diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc4240b04..7066dec08 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ jobs: name: NetBSD Build, Check, and Test runs-on: ubuntu-latest env: - PKGSRC_BRANCH: 2024Q3 + PKGSRC_BRANCH: 2025Q2 steps: - uses: actions/checkout@v4 - name: Build, Check, and Test @@ -30,13 +30,13 @@ jobs: gmake -C vendor/stb/src gmake -C vendor/cgltf/src gmake -C vendor/miniaudio/src - ./odin check examples/all -vet -strict-style -disallow-do -target:netbsd_amd64 - ./odin check examples/all -vet -strict-style -disallow-do -target:netbsd_arm64 - ./odin check vendor/sdl3 -vet -strict-style -disallow-do -target:netbsd_amd64 -no-entry-point - ./odin check vendor/sdl3 -vet -strict-style -disallow-do -target:netbsd_arm64 -no-entry-point - ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true - ./odin test tests/core/speed.odin -file -all-packages -vet -strict-style -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true - ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:netbsd_amd64 + ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:netbsd_arm64 + ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:netbsd_amd64 -no-entry-point + ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:netbsd_arm64 -no-entry-point + ./odin test tests/core/normal.odin -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + ./odin test tests/core/speed.odin -file -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + ./odin test tests/vendor -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true (cd tests/issues; ./run.sh) ./odin check tests/benchmark -vet -strict-style -no-entry-point @@ -52,7 +52,7 @@ jobs: usesh: true copyback: false prepare: | - pkg install -y gmake git bash python3 libxml2 llvm17 + pkg install -y gmake git bash python3 libxml2 llvm18 run: | # `set -e` is needed for test failures to register. https://github.com/vmactions/freebsd-vm/issues/72 set -e -x @@ -63,11 +63,11 @@ jobs: gmake -C vendor/stb/src gmake -C vendor/cgltf/src gmake -C vendor/miniaudio/src - ./odin check examples/all -vet -strict-style -disallow-do -target:freebsd_amd64 - ./odin check vendor/sdl3 -vet -strict-style -disallow-do -target:freebsd_amd64 -no-entry-point - ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true - ./odin test tests/core/speed.odin -file -all-packages -vet -strict-style -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true - ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_amd64 + ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_amd64 -no-entry-point + ./odin test tests/core/normal.odin -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + ./odin test tests/core/speed.odin -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + ./odin test tests/vendor -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true (cd tests/issues; ./run.sh) ./odin check tests/benchmark -vet -strict-style -no-entry-point ci: @@ -75,32 +75,35 @@ jobs: fail-fast: false matrix: # MacOS 13 runs on Intel, 14 runs on ARM - os: [ubuntu-latest, macos-13, macos-14] + os: [macos-14, ubuntu-latest] runs-on: ${{ matrix.os }} - name: ${{ matrix.os == 'macos-14' && 'MacOS ARM' || (matrix.os == 'macos-13' && 'MacOS Intel' || 'Ubuntu') }} Build, Check, and Test + name: ${{ matrix.os == 'macos-14' && 'MacOS ARM' || (matrix.os == 'macos-13' && 'MacOS Intel') || (matrix.os == 'ubuntu-latest' && 'Ubuntu') }} Build, Check, and Test timeout-minutes: 15 steps: - - uses: actions/checkout@v4 - - name: Download LLVM (Linux) - if: matrix.os == 'ubuntu-latest' - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 17 - echo "/usr/lib/llvm-17/bin" >> $GITHUB_PATH + - uses: actions/checkout@v4 - name: Download LLVM (MacOS Intel) if: matrix.os == 'macos-13' run: | - brew install llvm@17 lua@5.4 - echo "/usr/local/opt/llvm@17/bin" >> $GITHUB_PATH + brew update + brew install llvm@20 lua@5.4 lld + echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH - name: Download LLVM (MacOS ARM) if: matrix.os == 'macos-14' run: | - brew install llvm@17 wasmtime lua@5.4 - echo "/opt/homebrew/opt/llvm@17/bin" >> $GITHUB_PATH + brew update + brew install llvm@20 wasmtime lua@5.4 lld + echo "$(brew --prefix llvm@20)/bin" >> $GITHUB_PATH + + - name: Download LLVM (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 20 + echo "/usr/lib/llvm-20/bin" >> $GITHUB_PATH - name: Build Odin run: ./build_odin.sh release @@ -120,57 +123,62 @@ jobs: - name: Odin run -debug run: ./odin run examples/demo -debug - name: Odin check examples/all - run: ./odin check examples/all -strict-style -vet -disallow-do - - name: Odin check vendor/sdl3 - run: ./odin check vendor/sdl3 -strict-style -vet -disallow-do -no-entry-point + run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do + - name: Odin check examples/all/sdl3 + run: ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point - name: Normal Core library tests - run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + run: ./odin test tests/core/normal.odin -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Optimized Core library tests - run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Vendor library tests - run: ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + run: ./odin test tests/vendor -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Internals tests - run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + run: ./odin test tests/internal -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: GitHub Issue tests run: | cd tests/issues ./run.sh - - name: Check benchmarks - run: ./odin check tests/benchmark -vet -strict-style -no-entry-point - - name: Odin check examples/all for Linux i386 - run: ./odin check examples/all -vet -strict-style -disallow-do -target:linux_i386 - if: matrix.os == 'ubuntu-latest' - - name: Odin check examples/all for Linux arm64 - run: ./odin check examples/all -vet -strict-style -disallow-do -target:linux_arm64 - if: matrix.os == 'ubuntu-latest' - - name: Odin check examples/all for FreeBSD amd64 - run: ./odin check examples/all -vet -strict-style -disallow-do -target:freebsd_amd64 - if: matrix.os == 'ubuntu-latest' - - name: Odin check examples/all for OpenBSD amd64 - run: ./odin check examples/all -vet -strict-style -disallow-do -target:openbsd_amd64 - if: matrix.os == 'ubuntu-latest' - - - name: Odin check vendor/sdl3 for Linux i386 - run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:linux_i386 - if: matrix.os == 'ubuntu-latest' - - name: Odin check vendor/sdl3 for Linux arm64 - run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:linux_arm64 - if: matrix.os == 'ubuntu-latest' - - name: Odin check vendor/sdl3 for FreeBSD amd64 - run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:freebsd_amd64 - if: matrix.os == 'ubuntu-latest' - - name: Odin check vendor/sdl3 for OpenBSD amd64 - run: ./odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point -target:openbsd_amd64 - if: matrix.os == 'ubuntu-latest' - - - name: Run demo on WASI WASM32 run: | - ./odin build examples/demo -target:wasi_wasm32 -vet -strict-style -disallow-do -out:demo.wasm + ./odin build examples/demo -target:wasi_wasm32 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -out:demo wasmtime ./demo.wasm if: matrix.os == 'macos-14' + - name: Check benchmarks + run: ./odin check tests/benchmark -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point + - name: Odin check examples/all for Linux i386 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_i386 + - name: Odin check examples/all for Linux arm64 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_arm64 + - name: Odin check examples/all for FreeBSD amd64 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_amd64 + - name: Odin check examples/all for OpenBSD amd64 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:openbsd_amd64 + - name: Odin check examples/all for js_wasm32 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:js_wasm32 + - name: Odin check examples/all for js_wasm64p32 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:js_wasm64p32 + + - name: Odin check examples/all/sdl3 for Linux i386 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:linux_i386 + - name: Odin check examples/all/sdl3 for Linux arm64 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:linux_arm64 + - name: Odin check examples/all/sdl3 for FreeBSD amd64 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:freebsd_amd64 + - name: Odin check examples/all/sdl3 for OpenBSD amd64 + if: matrix.os == 'ubuntu-latest' + run: ./odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point -target:openbsd_amd64 + build_windows: name: Windows Build, Check, and Test runs-on: windows-2022 @@ -200,38 +208,38 @@ jobs: shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin run examples/demo -debug -vet -strict-style -disallow-do + odin run examples/demo -debug -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do - name: Odin check examples/all shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin check examples/all -vet -strict-style -disallow-do - - name: Odin check vendor/sdl3 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do + - name: Odin check examples/all/sdl3 shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin check vendor/sdl3 -vet -strict-style -disallow-do -no-entry-point + odin check examples/all/sdl3 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point - name: Core library tests shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + odin test tests/core/normal.odin -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Optimized core library tests shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + odin test tests/core/speed.odin -o:speed -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Vendor library tests shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat copy vendor\lua\5.4\windows\*.dll . - odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + odin test tests/vendor -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Odin internals tests shell: cmd run: | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat - odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true + odin test tests/internal -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -sanitize:address - name: Check issues shell: cmd run: | @@ -249,12 +257,6 @@ jobs: call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat cd tests\documentation call build.bat - - name: core:math/big tests - shell: cmd - run: | - call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat - cd tests\core\math\big - call build.bat - name: Odin check examples/all for Windows 32bits shell: cmd run: | @@ -291,25 +293,25 @@ jobs: make -C vendor/miniaudio/src - name: Odin check examples/all - run: ./odin check examples/all -target:linux_riscv64 -vet -strict-style -disallow-do + run: ./odin check examples/all -target:linux_riscv64 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do - - name: Odin check vendor/sdl3 - run: ./odin check vendor/sdl3 -target:linux_riscv64 -vet -strict-style -disallow-do -no-entry-point + - name: Odin check examples/all/sdl3 + run: ./odin check examples/all/sdl3 -target:linux_riscv64 -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -no-entry-point - name: Install riscv64 toolchain and qemu run: sudo apt-get install -y qemu-user qemu-user-static gcc-12-riscv64-linux-gnu libc6-riscv64-cross - name: Odin run - run: ./odin run examples/demo -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath + run: ./odin run examples/demo -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Odin run -debug - run: ./odin run examples/demo -debug -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath + run: ./odin run examples/demo -debug -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Normal Core library tests - run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath + run: ./odin test tests/core/normal.odin -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Optimized Core library tests - run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath + run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Internals tests - run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath + run: ./odin test tests/internal -all-packages -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath diff --git a/.github/workflows/cover.yml b/.github/workflows/cover.yml new file mode 100644 index 000000000..5d61296d5 --- /dev/null +++ b/.github/workflows/cover.yml @@ -0,0 +1,60 @@ +name: Test Coverage +on: [push, pull_request, workflow_dispatch] + +jobs: + build_linux_amd64: + runs-on: ubuntu-latest + name: Linux AMD64 Test Coverage + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + + - name: Download LLVM (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 20 + echo "/usr/lib/llvm-20/bin" >> $GITHUB_PATH + + - name: Install kcov + run: | + sudo apt-get update + sudo apt-get install binutils-dev build-essential cmake libssl-dev libcurl4-openssl-dev libelf-dev libstdc++-12-dev zlib1g-dev libdw-dev libiberty-dev + git clone https://github.com/SimonKagstrom/kcov.git + mkdir kcov/build + cd kcov/build + cmake .. + sudo make + sudo make install + cd ../.. + kcov --version + + - name: Build Odin + run: ./build_odin.sh release + + - name: Odin report + run: ./odin report + + - name: Normal Core library tests + run: | + ./odin build tests/core/normal.odin -build-mode:test -debug -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_amd64 + mkdir kcov-out + kcov --exclude-path=tests,/usr kcov-out ./normal.bin . + + - name: Optimized Core library tests + run: | + ./odin build tests/core/speed.odin -build-mode:test -debug -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_amd64 + kcov --exclude-path=tests,/usr kcov-out ./speed.bin . + + - name: Internals tests + run: | + ./odin build tests/internal -build-mode:test -debug -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_amd64 + kcov --exclude-path=tests,/usr kcov-out ./internal . + + - uses: codecov/codecov-action@v5 + with: + name: Ubuntu Coverage # optional + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true # optional (default = false + directory: kcov-out/kcov-merged \ No newline at end of file diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 314711efb..d3f14ca9e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -47,20 +47,15 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: jirutka/setup-alpine@v1 - with: - branch: v3.20 - - name: (Linux) Download LLVM + - name: (Linux) Download LLVM and Build Odin run: | - apk add --no-cache \ - musl-dev llvm18-dev clang18 git mold lz4 \ - libxml2-static llvm18-static zlib-static zstd-static \ - make - shell: alpine.sh --root {0} - - name: build odin - # NOTE: this build does slow compile times because of musl - run: ci/build_linux_static.sh - shell: alpine.sh {0} + docker run --rm -v "$PWD:/src" -w /src alpine sh -c ' + apk add --no-cache \ + musl-dev llvm20-dev clang20 git mold lz4 \ + libxml2-static llvm20-static zlib-static zstd-static \ + make && + ./ci/build_linux_static.sh + ' - name: Odin run run: ./odin run examples/demo - name: Copy artifacts @@ -74,6 +69,7 @@ jobs: cp -r core $FILE cp -r vendor $FILE cp -r examples $FILE + ./ci/remove_windows_binaries.sh $FILE # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38 tar -czvf dist.tar.gz $FILE - name: Odin run @@ -85,16 +81,57 @@ jobs: with: name: linux_artifacts path: dist.tar.gz + build_linux_arm: + name: Linux ARM Build + if: github.repository == 'odin-lang/Odin' + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@v4 + - name: (Linux ARM) Download LLVM and Build Odin + run: | + docker run --rm -v "$PWD:/src" -w /src arm64v8/alpine sh -c ' + apk add --no-cache \ + musl-dev llvm20-dev clang20 git mold lz4 \ + libxml2-static llvm20-static zlib-static zstd-static \ + make && + ./ci/build_linux_static.sh + ' + - name: Odin run + run: ./odin run examples/demo + - name: Copy artifacts + run: | + FILE="odin-linux-arm64-nightly+$(date -I)" + mkdir $FILE + cp odin $FILE + cp LICENSE $FILE + cp -r shared $FILE + cp -r base $FILE + cp -r core $FILE + cp -r vendor $FILE + cp -r examples $FILE + ./ci/remove_windows_binaries.sh $FILE + # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38 + tar -czvf dist.tar.gz $FILE + - name: Odin run + run: | + FILE="odin-linux-arm64-nightly+$(date -I)" + $FILE/odin run examples/demo + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: linux_arm_artifacts + path: dist.tar.gz build_macos: name: MacOS Build if: github.repository == 'odin-lang/Odin' - runs-on: macos-13 + runs-on: macos-14 # Intel machine steps: - uses: actions/checkout@v4 - name: Download LLVM and setup PATH run: | - brew install llvm@18 dylibbundler - echo "/usr/local/opt/llvm@18/bin" >> $GITHUB_PATH + brew update + brew install llvm@20 dylibbundler lld@20 + - name: build odin # These -L makes the linker prioritize system libraries over LLVM libraries, this is mainly to # not link with libunwind bundled with LLVM but link with libunwind on the system. @@ -110,6 +147,7 @@ jobs: cp -r core $FILE cp -r vendor $FILE cp -r examples $FILE + ./ci/remove_windows_binaries.sh $FILE dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38 tar -czvf dist.tar.gz $FILE @@ -130,8 +168,9 @@ jobs: - uses: actions/checkout@v4 - name: Download LLVM and setup PATH run: | - brew install llvm@18 dylibbundler - echo "/opt/homebrew/opt/llvm@18/bin" >> $GITHUB_PATH + brew update + brew install llvm@20 dylibbundler lld@20 + - name: build odin # These -L makes the linker prioritize system libraries over LLVM libraries, this is mainly to # not link with libunwind bundled with LLVM but link with libunwind on the system. @@ -147,6 +186,7 @@ jobs: cp -r core $FILE cp -r vendor $FILE cp -r examples $FILE + ./ci/remove_windows_binaries.sh $FILE dylibbundler -b -x $FILE/odin -d $FILE/libs -od -p @executable_path/libs # Creating a tarball so executable permissions are retained, see https://github.com/actions/upload-artifact/issues/38 tar -czvf dist.tar.gz $FILE @@ -161,7 +201,7 @@ jobs: path: dist.tar.gz upload_b2: runs-on: [ubuntu-latest] - needs: [build_windows, build_macos, build_macos_arm, build_linux] + needs: [build_windows, build_macos, build_macos_arm, build_linux, build_linux_arm] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 @@ -190,6 +230,12 @@ jobs: name: linux_artifacts path: linux_artifacts + - name: Download Ubuntu ARM artifacts + uses: actions/download-artifact@v4.1.7 + with: + name: linux_arm_artifacts + path: linux_arm_artifacts + - name: Download macOS artifacts uses: actions/download-artifact@v4.1.7 with: @@ -217,6 +263,7 @@ jobs: file linux_artifacts/dist.tar.gz python3 ci/nightly.py artifact windows-amd64 windows_artifacts/ python3 ci/nightly.py artifact linux-amd64 linux_artifacts/dist.tar.gz + python3 ci/nightly.py artifact linux-arm64 linux_arm_artifacts/dist.tar.gz python3 ci/nightly.py artifact macos-amd64 macos_artifacts/dist.tar.gz python3 ci/nightly.py artifact macos-arm64 macos_arm_artifacts/dist.tar.gz python3 ci/nightly.py prune diff --git a/.gitignore b/.gitignore index 32e5f5b0f..4efb5d73e 100644 --- a/.gitignore +++ b/.gitignore @@ -277,6 +277,7 @@ odin *.bin demo.bin libLLVM*.so* +*.a # shared collection shared/ @@ -293,5 +294,17 @@ build.sh # RAD debugger project file *.raddbg - +*.rdi +tests/issues/build/* misc/featuregen/featuregen + +# Clangd stuff +.cache/ +.clangd +compile_commands.json + +# Dev cmake helpers +build/ +cmake-build*/ +CMakeLists.txt +sandbox/ diff --git a/LLVM-C.dll b/LLVM-C.dll index ee03a2acd..b2f22ba8e 100644 Binary files a/LLVM-C.dll and b/LLVM-C.dll differ diff --git a/README.md b/README.md index cc40fb1ad..5e48f4168 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ - +

diff --git a/base/builtin/builtin.odin b/base/builtin/builtin.odin index 227ceeb49..2dd214321 100644 --- a/base/builtin/builtin.odin +++ b/base/builtin/builtin.odin @@ -7,13 +7,232 @@ nil :: nil false :: 0!=0 true :: 0==0 -ODIN_OS :: ODIN_OS -ODIN_ARCH :: ODIN_ARCH -ODIN_ENDIAN :: ODIN_ENDIAN -ODIN_VENDOR :: ODIN_VENDOR -ODIN_VERSION :: ODIN_VERSION -ODIN_ROOT :: ODIN_ROOT -ODIN_DEBUG :: ODIN_DEBUG +// The following constants are added in `checker.cpp`'s `init_universal` procedure. + +/* + An `enum` value indicating the target's CPU architecture. + Possible values are: `.amd64`, `.i386`, `.arm32`, `.arm64`, `.wasm32`, `.wasm64p32`, and `.riscv64`. +*/ +ODIN_ARCH :: ODIN_ARCH + +/* + A `string` indicating the target's CPU architecture. + Possible values are: "amd64", "i386", "arm32", "arm64", "wasm32", "wasm64p32", "riscv64". +*/ +ODIN_ARCH_STRING :: ODIN_ARCH_STRING + +/* + An `enum` value indicating the type of compiled output, chosen using `-build-mode`. + Possible values are: `.Executable`, `.Dynamic`, `.Static`, `.Object`, `.Assembly`, and `.LLVM_IR`. +*/ +ODIN_BUILD_MODE :: ODIN_BUILD_MODE + +/* + A `string` containing the name of the folder that contains the entry point, + e.g. for `%ODIN_ROOT%/examples/demo`, this would contain `demo`. +*/ +ODIN_BUILD_PROJECT_NAME :: ODIN_BUILD_PROJECT_NAME + +/* + An `i64` containing the time at which the executable was compiled, in nanoseconds. + This is compatible with the `time.Time` type, i.e. `time.Time{_nsec=ODIN_COMPILE_TIMESTAMP}` +*/ +ODIN_COMPILE_TIMESTAMP :: ODIN_COMPILE_TIMESTAMP + +/* + `true` if the `-debug` command line switch is passed, which enables debug info generation. +*/ +ODIN_DEBUG :: ODIN_DEBUG + +/* + `true` if the `-default-to-nil-allocator` command line switch is passed, + which sets the initial `context.allocator` to an allocator that does nothing. +*/ +ODIN_DEFAULT_TO_NIL_ALLOCATOR :: ODIN_DEFAULT_TO_NIL_ALLOCATOR + +/* + `true` if the `-default-to-panic-allocator` command line switch is passed, + which sets the initial `context.allocator` to an allocator that panics if allocated from. +*/ +ODIN_DEFAULT_TO_PANIC_ALLOCATOR :: ODIN_DEFAULT_TO_PANIC_ALLOCATOR + +/* + `true` if the `-disable-assert` command line switch is passed, + which removes all calls to `assert` from the program. +*/ +ODIN_DISABLE_ASSERT :: ODIN_DISABLE_ASSERT + +/* + An `enum` value indicating the endianness of the target. + Possible values are: `.Little` and `.Big`. +*/ +ODIN_ENDIAN :: ODIN_ENDIAN + +/* + An `string` indicating the endianness of the target. + Possible values are: "little" and "big". +*/ +ODIN_ENDIAN_STRING :: ODIN_ENDIAN_STRING + +/* + An `enum` value set using the `-error-pos-style` switch, indicating the source location style used for compile errors and warnings. + Possible values are: `.Default` (Odin-style) and `.Unix`. +*/ +ODIN_ERROR_POS_STYLE :: ODIN_ERROR_POS_STYLE + +/* + `true` if the `-foreign-error-procedures` command line switch is passed, + which inhibits generation of runtime error procedures, so that they can be in a separate compilation unit. +*/ +ODIN_FOREIGN_ERROR_PROCEDURES :: ODIN_FOREIGN_ERROR_PROCEDURES + +/* + A `string` describing the microarchitecture used for code generation. + If not set using the `-microarch` command line switch, the compiler will pick a default. + Possible values include, but are not limited to: "sandybridge", "x86-64-v2". +*/ +ODIN_MICROARCH_STRING :: ODIN_MICROARCH_STRING + +/* + An `int` value representing the minimum OS version given to the linker, calculated as `major * 10_000 + minor * 100 + revision`. + If not set using the `-minimum-os-version` command line switch, it defaults to `0`, except on Darwin, where it's `11_00_00`. +*/ +ODIN_MINIMUM_OS_VERSION :: ODIN_MINIMUM_OS_VERSION + +/* + `true` if the `-no-bounds-check` command line switch is passed, which disables bounds checking at runtime. +*/ +ODIN_NO_BOUNDS_CHECK :: ODIN_NO_BOUNDS_CHECK + +/* + `true` if the `-no-crt` command line switch is passed, which inhibits linking with the C Runtime Library, a.k.a. LibC. +*/ +ODIN_NO_CRT :: ODIN_NO_CRT + +/* + `true` if the `-no-entry-point` command line switch is passed, which makes the declaration of a `main` procedure optional. +*/ +ODIN_NO_ENTRY_POINT :: ODIN_NO_ENTRY_POINT + +/* + `true` if the `-no-rtti` command line switch is passed, which inhibits generation of full Runtime Type Information. +*/ +ODIN_NO_RTTI :: ODIN_NO_RTTI + +/* + `true` if the `-no-type-assert` command line switch is passed, which disables type assertion checking program wide. +*/ +ODIN_NO_TYPE_ASSERT :: ODIN_NO_TYPE_ASSERT + +/* + An `enum` value indicating the optimization level selected using the `-o` command line switch. + Possible values are: `.None`, `.Minimal`, `.Size`, `.Speed`, and `.Aggressive`. + + If `ODIN_OPTIMIZATION_MODE` is anything other than `.None` or `.Minimal`, the compiler will also perform a unity build, + and `ODIN_USE_SEPARATE_MODULES` will be set to `false` as a result. +*/ +ODIN_OPTIMIZATION_MODE :: ODIN_OPTIMIZATION_MODE + +/* + An `enum` value indicating what the target operating system is. +*/ +ODIN_OS :: ODIN_OS + +/* + A `string` indicating what the target operating system is. +*/ +ODIN_OS_STRING :: ODIN_OS_STRING + +/* + An `enum` value indicating the platform subtarget, chosen using the `-subtarget` switch. + Possible values are: `.Default` `.iPhone`, .iPhoneSimulator, and `.Android`. +*/ +ODIN_PLATFORM_SUBTARGET :: ODIN_PLATFORM_SUBTARGET + +/* + A `string` representing the path of the folder containing the Odin compiler, + relative to which we expect to find the `base` and `core` package collections. +*/ +ODIN_ROOT :: ODIN_ROOT + +/* + A `bit_set` indicating the sanitizer flags set using the `-sanitize` command line switch. + Supported flags are `.Address`, `.Memory`, and `.Thread`. +*/ +ODIN_SANITIZER_FLAGS :: ODIN_SANITIZER_FLAGS + +/* + `true` if the code is being compiled via an invocation of `odin test`. +*/ +ODIN_TEST :: ODIN_TEST + +/* + `true` if built using the experimental Tilde backend. +*/ +ODIN_TILDE :: ODIN_TILDE + +/* + `true` by default, meaning each each package is built into its own object file, and then linked together. + `false` if the `-use-single-module` command line switch to force a unity build is provided. + + If `ODIN_OPTIMIZATION_MODE` is anything other than `.None` or `.Minimal`, the compiler will also perform a unity build, + and this constant will also be set to `false`. +*/ +ODIN_USE_SEPARATE_MODULES :: ODIN_USE_SEPARATE_MODULES + +/* + `true` if Valgrind integration is supported on the target. +*/ +ODIN_VALGRIND_SUPPORT :: ODIN_VALGRIND_SUPPORT + +/* + A `string` which identifies the compiler being used. The official compiler sets this to `"odin"`. +*/ +ODIN_VENDOR :: ODIN_VENDOR + +/* + A `string` containing the version of the Odin compiler, typically in the format `dev-YYYY-MM`. +*/ +ODIN_VERSION :: ODIN_VERSION + +/* + A `string` containing the Git hash part of the Odin version. + Empty if `.git` could not be detected at the time the compiler was built. +*/ +ODIN_VERSION_HASH :: ODIN_VERSION_HASH + +/* + An `enum` set by the `-subsystem` flag, specifying which Windows subsystem the PE file was created for. + Possible values are: + `.Unknown` - Default and only value on non-Windows platforms + `.Console` - Default on Windows + `.Windows` - Can be used by graphical applications so Windows doesn't open an empty console + + There are some other possible values for e.g. EFI applications, but only Console and Windows are supported. + + See also: https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64 +*/ +ODIN_WINDOWS_SUBSYSTEM :: ODIN_WINDOWS_SUBSYSTEM + +/* + An `string` set by the `-subsystem` flag, specifying which Windows subsystem the PE file was created for. + Possible values are: + "UNKNOWN" - Default and only value on non-Windows platforms + "CONSOLE" - Default on Windows + "WINDOWS" - Can be used by graphical applications so Windows doesn't open an empty console + + There are some other possible values for e.g. EFI applications, but only Console and Windows are supported. + + See also: https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64 +*/ +ODIN_WINDOWS_SUBSYSTEM_STRING :: ODIN_WINDOWS_SUBSYSTEM_STRING + +/* + `true` if LLVM supports the f16 type. +*/ +__ODIN_LLVM_F16_SUPPORTED :: __ODIN_LLVM_F16_SUPPORTED + + byte :: u8 // alias @@ -119,7 +338,8 @@ jmag :: proc(value: Quaternion) -> Float --- kmag :: proc(value: Quaternion) -> Float --- conj :: proc(value: Complex_Or_Quaternion) -> Complex_Or_Quaternion --- -expand_values :: proc(value: Struct_Or_Array) -> (A, B, C, ...) --- +expand_values :: proc(value: Struct_Or_Array) -> (A, B, C, ...) --- +compress_values :: proc(values: ...) -> Struct_Or_Array_Like_Type --- min :: proc(values: ..T) -> T --- max :: proc(values: ..T) -> T --- @@ -130,3 +350,6 @@ soa_zip :: proc(slices: ...) -> #soa[]Struct --- soa_unzip :: proc(value: $S/#soa[]$E) -> (slices: ...) --- unreachable :: proc() -> ! --- + +// Where T is a string, slice, dynamic array, or pointer to an array type +raw_data :: proc(t: $T) -> rawptr \ No newline at end of file diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index bec452007..dd508180d 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -32,6 +32,7 @@ trap :: proc() -> ! --- alloca :: proc(size, align: int) -> [^]u8 --- cpu_relax :: proc() --- read_cycle_counter :: proc() -> i64 --- +read_cycle_counter_frequency :: proc() -> i64 --- count_ones :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- count_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) --- @@ -140,6 +141,7 @@ type_is_quaternion :: proc($T: typeid) -> bool --- type_is_string :: proc($T: typeid) -> bool --- type_is_typeid :: proc($T: typeid) -> bool --- type_is_any :: proc($T: typeid) -> bool --- +type_is_string16 :: proc($T: typeid) -> bool --- type_is_endian_platform :: proc($T: typeid) -> bool --- type_is_endian_little :: proc($T: typeid) -> bool --- @@ -169,6 +171,7 @@ type_is_union :: proc($T: typeid) -> bool --- type_is_enum :: proc($T: typeid) -> bool --- type_is_proc :: proc($T: typeid) -> bool --- type_is_bit_set :: proc($T: typeid) -> bool --- +type_is_bit_field :: proc($T: typeid) -> bool --- type_is_simd_vector :: proc($T: typeid) -> bool --- type_is_matrix :: proc($T: typeid) -> bool --- @@ -212,6 +215,10 @@ type_is_subtype_of :: proc($T, $U: typeid) -> bool --- type_field_index_of :: proc($T: typeid, $name: string) -> uintptr --- +// "Contiguous" means that the set of enum constants, when sorted, have a difference of either 0 or 1 between consecutive values. +// This is the exact opposite of "sparse". +type_enum_is_contiguous :: proc($T: typeid) -> bool where type_is_enum(T) --- + type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) where type_is_comparable(T) --- type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) --- @@ -221,8 +228,14 @@ type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info --- type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) --- type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) --- +type_integer_to_unsigned :: proc($T: typeid) -> type where type_is_integer(T), !type_is_unsigned(T) --- +type_integer_to_signed :: proc($T: typeid) -> type where type_is_integer(T), type_is_unsigned(T) --- + type_has_shared_fields :: proc($U, $V: typeid) -> bool where type_is_struct(U), type_is_struct(V) --- +// Returns the canonicalized name of the type, of which is used to produce the pseudo-unique 'typeid' +type_canonical_name :: proc($T: typeid) -> string --- + constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- constant_log2 :: proc($v: $T) -> T where type_is_integer(T) --- @@ -274,8 +287,12 @@ simd_lanes_ge :: proc(a, b: #simd[N]T) -> #simd[N]Integer --- simd_extract :: proc(a: #simd[N]T, idx: uint) -> T --- simd_replace :: proc(a: #simd[N]T, idx: uint, elem: T) -> #simd[N]T --- +simd_reduce_add_bisect :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_mul_bisect :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- simd_reduce_add_ordered :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- simd_reduce_mul_ordered :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_add_pairs :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- +simd_reduce_mul_pairs :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- simd_reduce_min :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- simd_reduce_max :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- simd_reduce_and :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)--- @@ -298,10 +315,11 @@ simd_masked_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) simd_masked_expand_load :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) --- simd_masked_compress_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) --- - +simd_indices :: proc($T: typeid/#simd[$N]$E) -> T where type_is_numeric(T) --- simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T --- simd_select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T --- +simd_runtime_swizzle :: proc(table: #simd[N]T, indices: #simd[N]T) -> #simd[N]T where type_is_integer(T) --- // Lane-wise operations simd_ceil :: proc(a: #simd[N]any_float) -> #simd[N]any_float --- @@ -349,19 +367,26 @@ x86_cpuid :: proc(ax, cx: u32) -> (eax, ebx, ecx, edx: u32) --- x86_xgetbv :: proc(cx: u32) -> (eax, edx: u32) --- + // Darwin targets only objc_object :: struct{} objc_selector :: struct{} objc_class :: struct{} -objc_id :: ^objc_object -objc_SEL :: ^objc_selector -objc_Class :: ^objc_class +objc_ivar :: struct{} + +objc_id :: ^objc_object +objc_SEL :: ^objc_selector +objc_Class :: ^objc_class +objc_Ivar :: ^objc_ivar +objc_instancetype :: distinct objc_id objc_find_selector :: proc($name: string) -> objc_SEL --- objc_register_selector :: proc($name: string) -> objc_SEL --- objc_find_class :: proc($name: string) -> objc_Class --- objc_register_class :: proc($name: string) -> objc_Class --- - +objc_ivar_get :: proc(self: ^$T) -> ^$U --- +objc_block :: proc(invoke: $T, ..any) -> ^Objc_Block(T) where type_is_proc(T) --- +objc_super :: proc(obj: ^$T) -> ^$U where type_is_subtype_of(T, objc_object) && type_is_subtype_of(U, objc_object) --- valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, a3, a4: uintptr) -> uintptr --- diff --git a/base/runtime/core.odin b/base/runtime/core.odin index db5e4d698..478a3d307 100644 --- a/base/runtime/core.odin +++ b/base/runtime/core.odin @@ -61,6 +61,11 @@ Type_Info_Struct_Soa_Kind :: enum u8 { Dynamic = 3, } +Type_Info_String_Encoding_Kind :: enum u8 { + UTF_8 = 0, + UTF_16 = 1, +} + // Variant Types Type_Info_Named :: struct { name: string, @@ -73,7 +78,7 @@ Type_Info_Rune :: struct {} Type_Info_Float :: struct {endianness: Platform_Endianness} Type_Info_Complex :: struct {} Type_Info_Quaternion :: struct {} -Type_Info_String :: struct {is_cstring: bool} +Type_Info_String :: struct {is_cstring: bool, encoding: Type_Info_String_Encoding_Kind} Type_Info_Boolean :: struct {} Type_Info_Any :: struct {} Type_Info_Type_Id :: struct {} @@ -110,13 +115,12 @@ Type_Info_Parameters :: struct { // Only used for procedures parameters and resu types: []^Type_Info, names: []string, } -Type_Info_Tuple :: Type_Info_Parameters // Will be removed eventually Type_Info_Struct_Flags :: distinct bit_set[Type_Info_Struct_Flag; u8] Type_Info_Struct_Flag :: enum u8 { packed = 0, raw_union = 1, - no_copy = 2, + _ = 2, align = 3, } @@ -398,6 +402,11 @@ Raw_String :: struct { len: int, } +Raw_String16 :: struct { + data: [^]u16, + len: int, +} + Raw_Slice :: struct { data: rawptr, len: int, @@ -442,13 +451,21 @@ Raw_Any :: struct { data: rawptr, id: typeid, } -#assert(size_of(Raw_Any) == size_of(any)) +when !ODIN_NO_RTTI { + #assert(size_of(Raw_Any) == size_of(any)) +} Raw_Cstring :: struct { data: [^]byte, } #assert(size_of(Raw_Cstring) == size_of(cstring)) +Raw_Cstring16 :: struct { + data: [^]u16, +} +#assert(size_of(Raw_Cstring16) == size_of(cstring16)) + + Raw_Soa_Pointer :: struct { data: rawptr, index: int, @@ -556,11 +573,18 @@ ALL_ODIN_OS_TYPES :: Odin_OS_Types{ // Defined internally by the compiler Odin_Platform_Subtarget_Type :: enum int { Default, - iOS, + iPhone, + iPhoneSimulator + Android, } */ Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET) +Odin_Platform_Subtarget_Types :: bit_set[Odin_Platform_Subtarget_Type] + +@(builtin) +ODIN_PLATFORM_SUBTARGET_IOS :: ODIN_PLATFORM_SUBTARGET == .iPhone || ODIN_PLATFORM_SUBTARGET == .iPhoneSimulator + /* // Defined internally by the compiler Odin_Sanitizer_Flag :: enum u32 { diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index cf379aacb..d63d9e72a 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -5,6 +5,11 @@ import "base:intrinsics" @builtin Maybe :: union($T: typeid) {T} +/* +Represents an Objective-C block with a given procedure signature T +*/ +@builtin +Objc_Block :: struct($T: typeid) where intrinsics.type_is_proc(T) { using _: intrinsics.objc_object } /* Recovers the containing/parent struct from a pointer to one of its fields. @@ -49,7 +54,12 @@ container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: type when !NO_DEFAULT_TEMP_ALLOCATOR { - @thread_local global_default_temp_allocator_data: Default_Temp_Allocator + when ODIN_ARCH == .i386 && ODIN_OS == .Windows { + // Thread-local storage is problematic on Windows i386 + global_default_temp_allocator_data: Default_Temp_Allocator + } else { + @thread_local global_default_temp_allocator_data: Default_Temp_Allocator + } } @(builtin, disabled=NO_DEFAULT_TEMP_ALLOCATOR) @@ -60,37 +70,50 @@ init_global_temporary_allocator :: proc(size: int, backup_allocator := context.a } +@(require_results) +copy_slice_raw :: proc "contextless" (dst, src: rawptr, dst_len, src_len, elem_size: int) -> int { + n := min(dst_len, src_len) + if n > 0 { + intrinsics.mem_copy(dst, src, n*elem_size) + } + return n +} + // `copy_slice` is a built-in procedure that copies elements from a source slice `src` to a destination slice `dst`. // The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum // of len(src) and len(dst). // // Prefer the procedure group `copy`. @builtin -copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int { - n := max(0, min(len(dst), len(src))) - if n > 0 { - intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(E)) - } - return n +copy_slice :: #force_inline proc "contextless" (dst, src: $T/[]$E) -> int { + return copy_slice_raw(raw_data(dst), raw_data(src), len(dst), len(src), size_of(E)) } + // `copy_from_string` is a built-in procedure that copies elements from a source string `src` to a destination slice `dst`. // The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum // of len(src) and len(dst). // // Prefer the procedure group `copy`. @builtin -copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int { - n := max(0, min(len(dst), len(src))) - if n > 0 { - intrinsics.mem_copy(raw_data(dst), raw_data(src), n) - } - return n +copy_from_string :: #force_inline proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int { + return copy_slice_raw(raw_data(dst), raw_data(src), len(dst), len(src), 1) } + +// `copy_from_string16` is a built-in procedure that copies elements from a source string `src` to a destination slice `dst`. +// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum +// of len(src) and len(dst). +// +// Prefer the procedure group `copy`. +@builtin +copy_from_string16 :: #force_inline proc "contextless" (dst: $T/[]$E/u16, src: $S/string16) -> int { + return copy_slice_raw(raw_data(dst), raw_data(src), len(dst), len(src), 2) +} + // `copy` is a built-in procedure that copies elements from a source slice/string `src` to a destination slice `dst`. // The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum // of len(src) and len(dst). @builtin -copy :: proc{copy_slice, copy_from_string} +copy :: proc{copy_slice, copy_from_string, copy_from_string16} @@ -146,11 +169,17 @@ remove_range :: proc(array: ^$D/[dynamic]$T, #any_int lo, hi: int, loc := #calle @builtin pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check { assert(len(array) > 0, loc=loc) - res = array[len(array)-1] - (^Raw_Dynamic_Array)(array).len -= 1 + _pop_type_erased(&res, (^Raw_Dynamic_Array)(array), size_of(E)) return res } +_pop_type_erased :: proc(res: rawptr, array: ^Raw_Dynamic_Array, elem_size: int, loc := #caller_location) { + end := rawptr(uintptr(array.data) + uintptr(elem_size*(array.len-1))) + intrinsics.mem_copy_non_overlapping(res, end, elem_size) + array.len -= 1 +} + + // `pop_safe` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1. // If the operation is not possible, it will return false. @@ -285,6 +314,15 @@ delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error } +@builtin +delete_string16 :: proc(str: string16, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { + return mem_free_with_size(raw_data(str), len(str)*size_of(u16), allocator, loc) +} +@builtin +delete_cstring16 :: proc(str: cstring16, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { + return mem_free((^u16)(str), allocator, loc) +} + // `delete` will try to free the underlying data of the passed built-in data structure (string, cstring, dynamic array, slice, or map), with the given `allocator` if the allocator supports this operation. // // Note: Prefer `delete` over the specific `delete_*` procedures where possible. @@ -297,26 +335,27 @@ delete :: proc{ delete_map, delete_soa_slice, delete_soa_dynamic_array, + delete_string16, + delete_cstring16, } // The new built-in procedure allocates memory. The first argument is a type, not a value, and the value // return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator @(builtin, require_results) -new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_allocator_error { - return new_aligned(T, align_of(T), allocator, loc) +new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error { + t = (^T)(raw_data(mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return)) + return } @(require_results) new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) { - data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return - t = (^T)(raw_data(data)) + t = (^T)(raw_data(mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return)) return } @(builtin, require_results) new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error { - t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return - t = (^T)(raw_data(t_data)) + t = (^T)(raw_data(mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return)) if t != nil { t^ = data } @@ -326,14 +365,21 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat DEFAULT_DYNAMIC_ARRAY_CAPACITY :: 8 @(require_results) -make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { +make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (res: T, err: Allocator_Error) #optional_allocator_error { + err = _make_aligned_type_erased(&res, size_of(E), len, alignment, allocator, loc) + return +} + +@(require_results) +_make_aligned_type_erased :: proc(slice: rawptr, elem_size: int, len: int, alignment: int, allocator: Allocator, loc := #caller_location) -> Allocator_Error { make_slice_error_loc(loc, len) - data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc) - if data == nil && size_of(E) != 0 { - return nil, err + data, err := mem_alloc_bytes(elem_size*len, alignment, allocator, loc) + if data == nil && elem_size != 0 { + return err } - s := Raw_Slice{raw_data(data), len} - return transmute(T)s, err + (^Raw_Slice)(slice).data = raw_data(data) + (^Raw_Slice)(slice).len = len + return err } // `make_slice` allocates and initializes a slice. Like `new`, the first argument is a type, not a value. @@ -341,24 +387,27 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat // // Note: Prefer using the procedure group `make`. @(builtin, require_results) -make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { - return make_aligned(T, len, align_of(E), allocator, loc) +make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (res: T, err: Allocator_Error) #optional_allocator_error { + err = _make_aligned_type_erased(&res, size_of(E), len, align_of(E), allocator, loc) + return } // `make_dynamic_array` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it. // // Note: Prefer using the procedure group `make`. @(builtin, require_results) -make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { - return make_dynamic_array_len_cap(T, 0, 0, allocator, loc) +make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error { + err = _make_dynamic_array_len_cap((^Raw_Dynamic_Array)(&array), size_of(E), align_of(E), 0, 0, allocator, loc) + return } // `make_dynamic_array_len` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it. // // Note: Prefer using the procedure group `make`. @(builtin, require_results) -make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error { - return make_dynamic_array_len_cap(T, len, len, allocator, loc) +make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error { + err = _make_dynamic_array_len_cap((^Raw_Dynamic_Array)(&array), size_of(E), align_of(E), len, len, allocator, loc) + return } // `make_dynamic_array_len_cap` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it. @@ -463,7 +512,7 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) { // Note: Prefer the procedure group `reserve` @builtin reserve_map :: proc(m: ^$T/map[$K]$V, #any_int capacity: int, loc := #caller_location) -> Allocator_Error { - return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil + return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) } // Shrinks the capacity of a map down to the current length. @@ -492,7 +541,7 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value: return } -_append_elem :: #force_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, arg_ptr: rawptr, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +_append_elem :: #force_no_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, arg_ptr: rawptr, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { if array == nil { return } @@ -537,7 +586,7 @@ non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc : } } -_append_elems :: #force_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, should_zero: bool, loc := #caller_location, args: rawptr, arg_len: int) -> (n: int, err: Allocator_Error) #optional_allocator_error { +_append_elems :: #force_no_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, should_zero: bool, loc := #caller_location, args: rawptr, arg_len: int) -> (n: int, err: Allocator_Error) #optional_allocator_error { if array == nil { return 0, nil } @@ -648,6 +697,9 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (n: i @builtin inject_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast arg: E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { + when !ODIN_NO_BOUNDS_CHECK { + ensure(index >= 0, "Index must be positive.", loc) + } if array == nil { return } @@ -666,6 +718,9 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcas @builtin inject_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { + when !ODIN_NO_BOUNDS_CHECK { + ensure(index >= 0, "Index must be positive.", loc) + } if array == nil { return } @@ -689,6 +744,9 @@ inject_at_elems :: proc(array: ^$T/[dynamic]$E, #any_int index: int, #no_broadca @builtin inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, #any_int index: int, arg: string, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { + when !ODIN_NO_BOUNDS_CHECK { + ensure(index >= 0, "Index must be positive.", loc) + } if array == nil { return } @@ -777,7 +835,7 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) { // `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`). // // Note: Prefer the procedure group `reserve`. -_reserve_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error { +_reserve_dynamic_array :: #force_no_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error { if a == nil { return nil } @@ -821,7 +879,7 @@ non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity } -_resize_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error { +_resize_dynamic_array :: #force_no_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error { if a == nil { return nil } diff --git a/base/runtime/core_builtin_soa.odin b/base/runtime/core_builtin_soa.odin index ff27a4559..331254ac7 100644 --- a/base/runtime/core_builtin_soa.odin +++ b/base/runtime/core_builtin_soa.odin @@ -178,8 +178,31 @@ resize_soa :: proc(array: ^$T/#soa[dynamic]$E, #any_int length: int, loc := #cal if array == nil { return nil } - reserve_soa(array, length, loc) or_return + footer := raw_soa_footer(array) + + if length > footer.cap { + reserve_soa(array, length, loc) or_return + } else if size_of(E) > 0 && length > footer.len { + ti := type_info_base(type_info_of(typeid_of(T))) + si := &ti.variant.(Type_Info_Struct) + + field_count := len(E) when intrinsics.type_is_array(E) else intrinsics.type_struct_field_count(E) + + data := (^rawptr)(array)^ + + soa_offset := 0 + for i in 0.. Allocator { +@(require_results) +nil_allocator :: proc "contextless" () -> Allocator { return Allocator{ procedure = nil_allocator_proc, data = nil, @@ -72,6 +73,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, return nil, nil } +@(require_results) panic_allocator :: proc() -> Allocator { return Allocator{ procedure = panic_allocator_proc, diff --git a/base/runtime/default_temp_allocator_arena.odin b/base/runtime/default_temp_allocator_arena.odin index 6e2900411..8f4821b4a 100644 --- a/base/runtime/default_temp_allocator_arena.odin +++ b/base/runtime/default_temp_allocator_arena.odin @@ -1,6 +1,7 @@ package runtime import "base:intrinsics" +// import "base:sanitizer" DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: uint(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE) @@ -43,15 +44,21 @@ memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint block.base = ([^]byte)(uintptr(block) + base_offset) block.capacity = uint(end - uintptr(block.base)) + // sanitizer.address_poison(block.base, block.capacity) + // Should be zeroed assert(block.used == 0) assert(block.prev == nil) return } -memory_block_dealloc :: proc(block_to_free: ^Memory_Block, loc := #caller_location) { +memory_block_dealloc :: proc "contextless" (block_to_free: ^Memory_Block, loc := #caller_location) { if block_to_free != nil { + allocator := block_to_free.allocator + // sanitizer.address_unpoison(block_to_free.base, block_to_free.capacity) + context = default_context() + context.allocator = allocator mem_free(block_to_free, allocator, loc) } } @@ -83,6 +90,7 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) return } data = block.base[block.used+alignment_offset:][:min_size] + // sanitizer.address_unpoison(block.base[block.used:block.used+size]) block.used += size return } @@ -104,13 +112,15 @@ arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_locatio if size == 0 { return } - - needed := align_forward_uint(size, alignment) - if arena.curr_block == nil || (safe_add(arena.curr_block.used, needed) or_else 0) > arena.curr_block.capacity { + + prev_used := 0 if arena.curr_block == nil else arena.curr_block.used + data, err = alloc_from_memory_block(arena.curr_block, size, alignment) + if err == .Out_Of_Memory { if arena.minimum_block_size == 0 { arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE } + needed := align_forward_uint(size, alignment) block_size := max(needed, arena.minimum_block_size) if arena.backing_allocator.procedure == nil { @@ -121,10 +131,9 @@ arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_locatio new_block.prev = arena.curr_block arena.curr_block = new_block arena.total_capacity += new_block.capacity + prev_used = 0 + data, err = alloc_from_memory_block(arena.curr_block, size, alignment) } - - prev_used := arena.curr_block.used - data, err = alloc_from_memory_block(arena.curr_block, size, alignment) arena.total_used += arena.curr_block.used - prev_used return } @@ -161,11 +170,12 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { if arena.curr_block != nil { intrinsics.mem_zero(arena.curr_block.base, arena.curr_block.used) arena.curr_block.used = 0 + // sanitizer.address_poison(arena.curr_block.base, arena.curr_block.capacity) } arena.total_used = 0 } -arena_destroy :: proc(arena: ^Arena, loc := #caller_location) { +arena_destroy :: proc "contextless" (arena: ^Arena, loc := #caller_location) { for arena.curr_block != nil { free_block := arena.curr_block arena.curr_block = free_block.prev @@ -177,6 +187,7 @@ arena_destroy :: proc(arena: ^Arena, loc := #caller_location) { arena.total_capacity = 0 } +@(require_results) arena_allocator :: proc(arena: ^Arena) -> Allocator { return Allocator{arena_allocator_proc, arena} } @@ -225,6 +236,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, // grow data in-place, adjusting next allocation block.used = uint(new_end) data = block.base[start:new_end] + // sanitizer.address_unpoison(data) return } } @@ -298,6 +310,7 @@ arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) { assert(block.used >= temp.used, "out of order use of arena_temp_end", loc) amount_to_zero := block.used-temp.used intrinsics.mem_zero(block.base[temp.used:], amount_to_zero) + // sanitizer.address_poison(block.base[temp.used:block.capacity]) block.used = temp.used arena.total_used -= amount_to_zero } diff --git a/base/runtime/default_temporary_allocator.odin b/base/runtime/default_temporary_allocator.odin index b355ded70..ec3c6ad8c 100644 --- a/base/runtime/default_temporary_allocator.odin +++ b/base/runtime/default_temporary_allocator.odin @@ -8,7 +8,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR { default_temp_allocator_init :: proc(s: ^Default_Temp_Allocator, size: int, backing_allocator := context.allocator) {} - default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) {} + default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) {} default_temp_allocator_proc :: nil_allocator_proc @@ -28,7 +28,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR { _ = arena_init(&s.arena, uint(size), backing_allocator) } - default_temp_allocator_destroy :: proc(s: ^Default_Temp_Allocator) { + default_temp_allocator_destroy :: proc "contextless" (s: ^Default_Temp_Allocator) { if s != nil { arena_destroy(&s.arena) s^ = {} @@ -56,7 +56,7 @@ when NO_DEFAULT_TEMP_ALLOCATOR { } @(fini, private) - _destroy_temp_allocator_fini :: proc() { + _destroy_temp_allocator_fini :: proc "contextless" () { default_temp_allocator_destroy(&global_default_temp_allocator_data) } } @@ -70,7 +70,7 @@ DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD :: #force_inline proc(ignore := false, loc := } } - +@(require_results) default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator { return Allocator{ procedure = default_temp_allocator_proc, diff --git a/base/runtime/doc.odin b/base/runtime/doc.odin new file mode 100644 index 000000000..7369e36b5 --- /dev/null +++ b/base/runtime/doc.odin @@ -0,0 +1,244 @@ + +/* +Declarations which are required by the compiler + +## Descriptions of files + +There are a lot of files in this package and below is described roughly what +kind of functionality is placed in different files: + +| File pattern | Description +|----------------------|------------------------------------------------------| +| `core.odin` | Contains the declarations that compiler will require to be present. Contains context-related declarations, `Type_Info` declarations and some other types used to implement the runtime and other packages. | +| `core_builtin*.odin` | Contain `@(builtin)` declarations that can be used without importing the package. Most of them aren't required by the compiler | +| `default_*.odin` | Contain default implementations for context allocators | +| `entry_*.odin` | Contain OS-specific entry points | +| `os_specific_*.odin` | Contain OS-specific utility procedures | +| `*internal*.odin` | Contain implementations for internal procedures that can be called by the compiler | + +## Implementing custom runtime + +For embedded and kernel development it might be required to re-implement parts +of the `base:runtime` package. This can include changing the default printing +procedures that handle console output when the program panics, custom +entry-points, tailored for a specific platform or execution environment, or +simply switching up implementations of some procedures. + +In case this is required, the following is suggested: + +1. Define `$ODIN_ROOT` environment variable to point to a directory within your + project that contains the following directories: `base/`, `core/` and `vendor/`. +2. Inside the `$ODIN_ROOT/base` subdirectory, implement the *necessary + declarations*. + +What constitutes the necessary definitions is described below. + +### Context-related + +The compiler will require these declarations as they concern the `context` +variable. + +* `Maybe` +* `Source_Code_Location` +* `Context` +* `Allocator` +* `Random_Generator` +* `Logger` +* `__init_context` + +### Runtime initialization/cleanup + +These are not strictly required for compilation, but if global variables or +`@(init)`/`@(fini)` blocks are used, these procedures need to be called inside +the entry point. + +* `_startup_runtime` +* `_cleanup_runtime` + +### Type assertion check + +These procedures are called every time `.(Type)` expressions are used in order +to check the union tag or the underlying type of `any` before returning the +value of the underlying type. These are not required if `-no-type-assert` is +specified. + +* `type_assertion_check` +* `type_assertion_check2` (takes in typeid) + +### Bounds checking procedures + +These procedures are called every time index or slicing expression are used in +order to perform bounds-checking before the actual operation. These are not +required if the `-no-bounds-check` option is specified. + +* `bounds_check_error` +* `matrix_bounds_check_error` +* `slice_expr_error_hi` +* `slice_expr_error_lo_hi` +* `multi_pointer_slice_expr_error` + +### cstring calls + +If `cstring` or `cstring16` types are used, these procedures are required. + +* `cstring_to_string` +* `cstring_len` +* `cstring16_to_string16` +* `cstring16_len` + +### Comparison + +These procedures are required for comparison operators between strings and other +compound types to function properly. If strings, structs nor unions are compared, +only `string_eq` procedure is required. + +* `memory_equal` +* `memory_compare` +* `memory_compare_zero` +* `cstring_eq` +* `cstring16_eq` +* `cstring_ne` +* `cstring16_ne` +* `cstring_lt` +* `cstring16_lt` +* `cstring_gt` +* `cstring16_gt` +* `cstring_le` +* `cstring16_le` +* `cstring_ge` +* `cstring16_ge` +* `string_eq` +* `string16_eq` +* `string_ne` +* `string16_ne` +* `string_lt` +* `string16_lt` +* `string_gt` +* `string16_gt` +* `string_le` +* `string16_le` +* `string_ge` +* `string16_ge` +* `complex32_eq` +* `complex32_ne` +* `complex64_eq` +* `complex64_ne` +* `complex128_eq` +* `complex128_ne` +* `quaternion64_eq` +* `quaternion64_ne` +* `quaternion128_eq` +* `quaternion128_ne` +* `quaternion256_eq` +* `quaternion256_ne` + +### for-in `string` type + +These procedures are required to iterate strings using `for ... in` loop. If this +kind of loop isn't used, these procedures aren't required. + +* `string_decode_rune` +* `string_decode_last_rune` (for `#reverse for`) + +### Required when RTTI is enabled (the vast majority of targets) + +These declarations are required unless the `-no-rtti` compiler option is +specified. Note that in order to be useful, some other procedures need to be +implemented. Those procedures aren't mentioned here as the compiler won't +complain if they're missing. + +* `Type_Info` +* `type_table` +* `__type_info_of` + +### Hashing + +Required if maps are used + +* `default_hasher` +* `default_hasher_cstring` +* `default_hasher_string` + +### Pseudo-CRT required procedured due to LLVM but useful in general + +* `memset` +* `memcpy` +* `memove` + +### Procedures required by the LLVM backend if u128/i128 is used + +* `umodti3` +* `udivti3` +* `modti3` +* `divti3` +* `fixdfti` +* `fixunsdfti` +* `fixunsdfdi` +* `floattidf` +* `floattidf_unsigned` +* `truncsfhf2` +* `truncdfhf2` +* `gnu_h2f_ieee` +* `gnu_f2h_ieee` +* `extendhfsf2` + +### Procedures required by the LLVM backend if f16 is used (WASM only) + +* `__ashlti3` +* `__multi3` + +### When -no-crt is defined (windows only) + +* `_tls_index` +* `_fltused` + +### Arithmetic + +* `quo_complex32` +* `quo_complex64` +* `quo_complex128` + +* `mul_quaternion64` +* `mul_quaternion128` +* `mul_quaternion256` + +* `quo_quaternion64` +* `quo_quaternion128` +* `quo_quaternion256` + +* `abs_complex32` +* `abs_complex64` +* `abs_complex128` + +* `abs_quaternion64` +* `abs_quaternion128` +* `abs_quaternion256` + +## Map specific calls + +* `map_seed_from_map_data` +* `__dynamic_map_check_grow` (for static map calls) +* `map_insert_hash_dynamic` (for static map calls) +* `__dynamic_map_get` (for dynamic map calls) +* `__dynamic_map_set` (for dynamic map calls) + +## Dynamic literals (`[dynamic]T` and `map[K]V`) (can be disabled with `-no-dynamic-literals`) + +* `__dynamic_array_reserve` +* `__dynamic_array_append` +* `__dynamic_map_reserve` + +### Objective-C specific + +* `objc_lookUpClass` +* `sel_registerName` +* `objc_allocateClassPair` + +### Other required declarations + +This is required without conditions. + +* `Load_Directory_File` + +*/ +package runtime diff --git a/base/runtime/docs.odin b/base/runtime/docs.odin deleted file mode 100644 index f6b439aa0..000000000 --- a/base/runtime/docs.odin +++ /dev/null @@ -1,180 +0,0 @@ -package runtime - -/* - -package runtime has numerous entities (declarations) which are required by the compiler to function. - - -## Basic types and calls (and anything they rely on) - -Source_Code_Location -Context -Allocator -Logger - -__init_context -_cleanup_runtime - - -## cstring calls - -cstring_to_string -cstring_len - - - -## Required when RTTI is enabled (the vast majority of targets) - -Type_Info - -type_table -__type_info_of - - -## Hashing - -default_hasher -default_hasher_cstring -default_hasher_string - - -## Pseudo-CRT required procedured due to LLVM but useful in general -memset -memcpy -memove - - -## Procedures required by the LLVM backend if u128/i128 is used -umodti3 -udivti3 -modti3 -divti3 -fixdfti -fixunsdfti -fixunsdfdi -floattidf -floattidf_unsigned -truncsfhf2 -truncdfhf2 -gnu_h2f_ieee -gnu_f2h_ieee -extendhfsf2 - -## Procedures required by the LLVM backend if f16 is used -__ashlti3 // wasm specific -__multi3 // wasm specific - - -## Required an entry point is defined (i.e. 'main') - -args__ - - -## When -no-crt is defined (and not a wasm target) (mostly due to LLVM) -_tls_index -_fltused - - -## Bounds checking procedures (when not disabled with -no-bounds-check) - -bounds_check_error -matrix_bounds_check_error -slice_expr_error_hi -slice_expr_error_lo_hi -multi_pointer_slice_expr_error - - -## Type assertion check - -type_assertion_check -type_assertion_check2 // takes in typeid - - -## Arithmetic - -quo_complex32 -quo_complex64 -quo_complex128 - -mul_quaternion64 -mul_quaternion128 -mul_quaternion256 - -quo_quaternion64 -quo_quaternion128 -quo_quaternion256 - -abs_complex32 -abs_complex64 -abs_complex128 - -abs_quaternion64 -abs_quaternion128 -abs_quaternion256 - - -## Comparison - -memory_equal -memory_compare -memory_compare_zero - -cstring_eq -cstring_ne -cstring_lt -cstring_gt -cstring_le -cstring_gt - -string_eq -string_ne -string_lt -string_gt -string_le -string_gt - -complex32_eq -complex32_ne -complex64_eq -complex64_ne -complex128_eq -complex128_ne - -quaternion64_eq -quaternion64_ne -quaternion128_eq -quaternion128_ne -quaternion256_eq -quaternion256_ne - - -## Map specific calls - -map_seed_from_map_data -__dynamic_map_check_grow // static map calls -map_insert_hash_dynamic // static map calls -__dynamic_map_get // dynamic map calls -__dynamic_map_set // dynamic map calls - - -## Dynamic literals ([dynamic]T and map[K]V) (can be disabled with -no-dynamic-literals) - -__dynamic_array_reserve -__dynamic_array_append - -__dynamic_map_reserve - - -## Objective-C specific - -objc_lookUpClass -sel_registerName -objc_allocateClassPair - - -## for-in `string` type - -string_decode_rune -string_decode_last_rune // #reverse for - -*/ \ No newline at end of file diff --git a/base/runtime/dynamic_map_internal.odin b/base/runtime/dynamic_map_internal.odin index 96ae9c73c..e288d1f53 100644 --- a/base/runtime/dynamic_map_internal.odin +++ b/base/runtime/dynamic_map_internal.odin @@ -985,6 +985,9 @@ __dynamic_map_entry :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_ // IMPORTANT: USED WITHIN THE COMPILER @(private) __dynamic_map_reserve :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uint, loc := #caller_location) -> Allocator_Error { + if m == nil { + return nil + } return map_reserve_dynamic(m, info, uintptr(new_capacity), loc) } @@ -1029,3 +1032,32 @@ default_hasher_cstring :: proc "contextless" (data: rawptr, seed: uintptr) -> ui h &= HASH_MASK return uintptr(h) | uintptr(uintptr(h) == 0) } + +default_hasher_f64 :: proc "contextless" (f: f64, seed: uintptr) -> uintptr { + f := f + buf: [size_of(f)]u8 + if f == 0 { + return default_hasher(&buf, seed, size_of(buf)) + } + if f != f { + // TODO(bill): What should the logic be for NaNs? + return default_hasher(&f, seed, size_of(f)) + } + return default_hasher(&f, seed, size_of(f)) +} + +default_hasher_complex128 :: proc "contextless" (x, y: f64, seed: uintptr) -> uintptr { + seed := seed + seed = default_hasher_f64(x, seed) + seed = default_hasher_f64(y, seed) + return seed +} + +default_hasher_quaternion256 :: proc "contextless" (x, y, z, w: f64, seed: uintptr) -> uintptr { + seed := seed + seed = default_hasher_f64(x, seed) + seed = default_hasher_f64(y, seed) + seed = default_hasher_f64(z, seed) + seed = default_hasher_f64(w, seed) + return seed +} \ No newline at end of file diff --git a/base/runtime/entry_unix_no_crt_amd64.asm b/base/runtime/entry_unix_no_crt_amd64.asm index f0bdce8d7..225356a2f 100644 --- a/base/runtime/entry_unix_no_crt_amd64.asm +++ b/base/runtime/entry_unix_no_crt_amd64.asm @@ -3,6 +3,7 @@ bits 64 extern _start_odin global _start +section .note.GNU-stack section .text ;; Entry point for programs that specify -no-crt option @@ -35,7 +36,7 @@ _start: xor rbp, rbp ;; Load argc into 1st param reg, argv into 2nd param reg pop rdi - mov rdx, rsi + mov rsi, rsp ;; Align stack pointer down to 16-bytes (sysv calling convention) and rsp, -16 ;; Call into odin entry point diff --git a/base/runtime/entry_windows.odin b/base/runtime/entry_windows.odin index 8eb4cc7d1..dc8e9b82c 100644 --- a/base/runtime/entry_windows.odin +++ b/base/runtime/entry_windows.odin @@ -28,7 +28,19 @@ when ODIN_BUILD_MODE == .Dynamic { return true } } else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT { - when ODIN_ARCH == .i386 || ODIN_NO_CRT { + when ODIN_ARCH == .i386 && !ODIN_NO_CRT { + // Windows i386 with CRT: libcmt provides mainCRTStartup which calls _main + // Note: "c" calling convention adds underscore prefix automatically on i386 + @(link_name="main", linkage="strong", require) + main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 { + args__ = argv[:argc] + context = default_context() + #force_no_inline _startup_runtime() + intrinsics.__entry_point() + #force_no_inline _cleanup_runtime() + return 0 + } + } else when ODIN_NO_CRT { @(link_name="mainCRTStartup", linkage="strong", require) mainCRTStartup :: proc "system" () -> i32 { context = default_context() diff --git a/base/runtime/heap_allocator.odin b/base/runtime/heap_allocator.odin index 4b04dffef..e2667a78c 100644 --- a/base/runtime/heap_allocator.odin +++ b/base/runtime/heap_allocator.odin @@ -2,6 +2,7 @@ package runtime import "base:intrinsics" +@(require_results) heap_allocator :: proc() -> Allocator { return Allocator{ procedure = heap_allocator_proc, @@ -70,10 +71,12 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, new_memory = aligned_alloc(new_size, new_alignment, p, old_size, zero_memory) or_return - // NOTE: heap_resize does not zero the new memory, so we do it - if zero_memory && new_size > old_size { - new_region := raw_data(new_memory[old_size:]) - intrinsics.mem_zero(new_region, new_size - old_size) + when ODIN_OS != .Windows { + // NOTE: heap_resize does not zero the new memory, so we do it + if zero_memory && new_size > old_size { + new_region := raw_data(new_memory[old_size:]) + conditional_mem_zero(new_region, new_size - old_size) + } } return } diff --git a/base/runtime/heap_allocator_unix.odin b/base/runtime/heap_allocator_unix.odin index d4590d2dd..f6e7ce39e 100644 --- a/base/runtime/heap_allocator_unix.odin +++ b/base/runtime/heap_allocator_unix.odin @@ -3,7 +3,7 @@ package runtime when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/base/runtime/heap_allocator_windows.odin b/base/runtime/heap_allocator_windows.odin index e07df7559..04a6f149b 100644 --- a/base/runtime/heap_allocator_windows.odin +++ b/base/runtime/heap_allocator_windows.odin @@ -1,5 +1,7 @@ package runtime +import "../sanitizer" + foreign import kernel32 "system:Kernel32.lib" @(private="file") @@ -16,7 +18,10 @@ foreign kernel32 { _heap_alloc :: proc "contextless" (size: int, zero_memory := true) -> rawptr { HEAP_ZERO_MEMORY :: 0x00000008 - return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY if zero_memory else 0, uint(size)) + ptr := HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY if zero_memory else 0, uint(size)) + // NOTE(lucas): asan not guarunteed to unpoison win32 heap out of the box, do it ourselves + sanitizer.address_unpoison(ptr, size) + return ptr } _heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr { if new_size == 0 { @@ -28,7 +33,10 @@ _heap_resize :: proc "contextless" (ptr: rawptr, new_size: int) -> rawptr { } HEAP_ZERO_MEMORY :: 0x00000008 - return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, uint(new_size)) + new_ptr := HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ptr, uint(new_size)) + // NOTE(lucas): asan not guarunteed to unpoison win32 heap out of the box, do it ourselves + sanitizer.address_unpoison(new_ptr, new_size) + return new_ptr } _heap_free :: proc "contextless" (ptr: rawptr) { if ptr == nil { diff --git a/base/runtime/internal.odin b/base/runtime/internal.odin index 59811a525..0e674aca8 100644 --- a/base/runtime/internal.odin +++ b/base/runtime/internal.odin @@ -16,6 +16,12 @@ RUNTIME_REQUIRE :: false // !ODIN_TILDE @(private) __float16 :: f16 when __ODIN_LLVM_F16_SUPPORTED else u16 +HAS_HARDWARE_SIMD :: false when (ODIN_ARCH == .amd64 || ODIN_ARCH == .i386) && !intrinsics.has_target_feature("sse2") else + false when (ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32) && !intrinsics.has_target_feature("neon") else + false when (ODIN_ARCH == .wasm64p32 || ODIN_ARCH == .wasm32) && !intrinsics.has_target_feature("simd128") else + false when (ODIN_ARCH == .riscv64) && !intrinsics.has_target_feature("v") else + true + @(private) byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check { @@ -117,7 +123,7 @@ mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> r DEFAULT_ALIGNMENT :: 2*align_of(rawptr) -mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { +mem_alloc_bytes :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc) if size == 0 || allocator.procedure == nil{ return nil, nil @@ -125,7 +131,7 @@ mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNM return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) } -mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { +mem_alloc :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc) if size == 0 || allocator.procedure == nil { return nil, nil @@ -133,7 +139,7 @@ mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, a return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) } -mem_alloc_non_zeroed :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { +mem_alloc_non_zeroed :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc) if size == 0 || allocator.procedure == nil { return nil, nil @@ -141,7 +147,7 @@ mem_alloc_non_zeroed :: #force_inline proc(size: int, alignment: int = DEFAULT_A return allocator.procedure(allocator.data, .Alloc_Non_Zeroed, size, alignment, nil, 0, loc) } -mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { +mem_free :: #force_no_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { if ptr == nil || allocator.procedure == nil { return nil } @@ -149,7 +155,7 @@ mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc return err } -mem_free_with_size :: #force_inline proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { +mem_free_with_size :: #force_no_inline proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { if ptr == nil || allocator.procedure == nil { return nil } @@ -157,7 +163,7 @@ mem_free_with_size :: #force_inline proc(ptr: rawptr, byte_count: int, allocator return err } -mem_free_bytes :: #force_inline proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { +mem_free_bytes :: #force_no_inline proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { if bytes == nil || allocator.procedure == nil { return nil } @@ -166,14 +172,14 @@ mem_free_bytes :: #force_inline proc(bytes: []byte, allocator := context.allocat } -mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) { +mem_free_all :: #force_no_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) { if allocator.procedure != nil { _, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc) } return } -_mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { +_mem_resize :: #force_no_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc) if allocator.procedure == nil { return nil, nil @@ -224,156 +230,296 @@ non_zero_mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int return _mem_resize(ptr, old_size, new_size, alignment, allocator, false, loc) } +conditional_mem_zero :: proc "contextless" (data: rawptr, n_: int) #no_bounds_check { + // When acquiring memory from the OS for the first time it's likely that the + // OS already gives the zero page mapped multiple times for the request. The + // actual allocation does not have physical pages allocated to it until those + // pages are written to which causes a page-fault. This is often called COW + // (Copy on Write) + // + // You do not want to actually zero out memory in this case because it would + // cause a bunch of page faults decreasing the speed of allocations and + // increase the amount of actual resident physical memory used. + // + // Instead a better technique is to check if memory is zerored before zeroing + // it. This turns out to be an important optimization in practice, saving + // nearly half (or more) the amount of physical memory used by an application. + // This is why every implementation of calloc in libc does this optimization. + // + // It may seem counter-intuitive but most allocations in an application are + // wasted and never used. When you consider something like a [dynamic]T which + // always doubles in capacity on resize but you rarely ever actually use the + // full capacity of a dynamic array it means you have a lot of resident waste + // if you actually zeroed the remainder of the memory. + // + // Keep in mind the OS is already guaranteed to give you zeroed memory by + // mapping in this zero page multiple times so in the best case there is no + // need to actually zero anything. As for testing all this memory for a zero + // value, it costs nothing because the the same zero page is used for the + // whole allocation and will exist in L1 cache for the entire zero checking + // process. + + if n_ <= 0 { + return + } + n := uint(n_) + + n_words := n / size_of(uintptr) + p_words := ([^]uintptr)(data)[:n_words] + p_bytes := ([^]byte)(data)[size_of(uintptr) * n_words:n] + for &p_word in p_words { + if p_word != 0 { + p_word = 0 + } + } + for &p_byte in p_bytes { + if p_byte != 0 { + p_byte = 0 + } + } +} + memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { switch { case n == 0: return true case x == y: return true } - a, b := ([^]byte)(x), ([^]byte)(y) - length := uint(n) + a, b := cast([^]byte)x, cast([^]byte)y - for i := uint(0); i < length; i += 1 { + n := uint(n) + i := uint(0) + m := uint(0) + + if n >= 8 { + when HAS_HARDWARE_SIMD { + // Avoid using 256-bit SIMD on platforms where its emulation is + // likely to be less than ideal. + when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") { + m = n / 32 * 32 + for /**/; i < m; i += 32 { + load_a := intrinsics.unaligned_load(cast(^#simd[32]u8)&a[i]) + load_b := intrinsics.unaligned_load(cast(^#simd[32]u8)&b[i]) + ne := intrinsics.simd_lanes_ne(load_a, load_b) + if intrinsics.simd_reduce_or(ne) != 0 { + return false + } + } + } + } + + m = (n-i) / 16 * 16 + for /**/; i < m; i += 16 { + load_a := intrinsics.unaligned_load(cast(^#simd[16]u8)&a[i]) + load_b := intrinsics.unaligned_load(cast(^#simd[16]u8)&b[i]) + ne := intrinsics.simd_lanes_ne(load_a, load_b) + if intrinsics.simd_reduce_or(ne) != 0 { + return false + } + } + + m = (n-i) / size_of(uintptr) * size_of(uintptr) + for /**/; i < m; i += size_of(uintptr) { + if intrinsics.unaligned_load(cast(^uintptr)&a[i]) != intrinsics.unaligned_load(cast(^uintptr)&b[i]) { + return false + } + } + } + + for /**/; i < n; i += 1 { if a[i] != b[i] { return false } } return true - -/* - - when size_of(uint) == 8 { - if word_length := length >> 3; word_length != 0 { - for _ in 0..> 2; word_length != 0 { - for _ in 0.. int #no_bounds_check { + +memory_compare :: proc "contextless" (x, y: rawptr, n: int) -> int #no_bounds_check { switch { - case a == b: return 0 - case a == nil: return -1 - case b == nil: return +1 + case x == y: return 0 + case x == nil: return -1 + case y == nil: return +1 } + a, b := cast([^]byte)x, cast([^]byte)y + + n := uint(n) + i := uint(0) + m := uint(0) - x := uintptr(a) - y := uintptr(b) - n := uintptr(n) - - SU :: size_of(uintptr) - fast := n/SU + 1 - offset := (fast-1)*SU - curr_block := uintptr(0) - if n < SU { - fast = 0 - } - - for /**/; curr_block < fast; curr_block += 1 { - va := (^uintptr)(x + curr_block * size_of(uintptr))^ - vb := (^uintptr)(y + curr_block * size_of(uintptr))^ - if va ~ vb != 0 { - for pos := curr_block*SU; pos < n; pos += 1 { - a := (^byte)(x+pos)^ - b := (^byte)(y+pos)^ - if a ~ b != 0 { - return -1 if (int(a) - int(b)) < 0 else +1 + when HAS_HARDWARE_SIMD { + when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") { + m = n / 32 * 32 + for /**/; i < m; i += 32 { + load_a := intrinsics.unaligned_load(cast(^#simd[32]u8)&a[i]) + load_b := intrinsics.unaligned_load(cast(^#simd[32]u8)&b[i]) + comparison := intrinsics.simd_lanes_ne(load_a, load_b) + if intrinsics.simd_reduce_or(comparison) != 0 { + sentinel: #simd[32]u8 = u8(0xFF) + indices := intrinsics.simd_indices(#simd[32]u8) + index_select := intrinsics.simd_select(comparison, indices, sentinel) + index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select) + return -1 if a[i+index_reduce] < b[i+index_reduce] else +1 } } } } - for /**/; offset < n; offset += 1 { - a := (^byte)(x+offset)^ - b := (^byte)(y+offset)^ - if a ~ b != 0 { - return -1 if (int(a) - int(b)) < 0 else +1 + m = (n-i) / 16 * 16 + for /**/; i < m; i += 16 { + load_a := intrinsics.unaligned_load(cast(^#simd[16]u8)&a[i]) + load_b := intrinsics.unaligned_load(cast(^#simd[16]u8)&b[i]) + comparison := intrinsics.simd_lanes_ne(load_a, load_b) + if intrinsics.simd_reduce_or(comparison) != 0 { + sentinel: #simd[16]u8 = u8(0xFF) + indices := intrinsics.simd_indices(#simd[16]u8) + index_select := intrinsics.simd_select(comparison, indices, sentinel) + index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select) + return -1 if a[i+index_reduce] < b[i+index_reduce] else +1 } } + // 64-bit SIMD is faster than using a `uintptr` to detect a difference then + // re-iterating with the byte-by-byte loop, at least on AMD64. + m = (n-i) / 8 * 8 + for /**/; i < m; i += 8 { + load_a := intrinsics.unaligned_load(cast(^#simd[8]u8)&a[i]) + load_b := intrinsics.unaligned_load(cast(^#simd[8]u8)&b[i]) + comparison := intrinsics.simd_lanes_ne(load_a, load_b) + if intrinsics.simd_reduce_or(comparison) != 0 { + sentinel: #simd[8]u8 = u8(0xFF) + indices := intrinsics.simd_indices(#simd[8]u8) + index_select := intrinsics.simd_select(comparison, indices, sentinel) + index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select) + return -1 if a[i+index_reduce] < b[i+index_reduce] else +1 + } + } + + for /**/; i < n; i += 1 { + if a[i] ~ b[i] != 0 { + return -1 if int(a[i]) - int(b[i]) < 0 else +1 + } + } return 0 } memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check { - x := uintptr(a) - n := uintptr(n) + n := uint(n) + i := uint(0) + m := uint(0) - SU :: size_of(uintptr) - fast := n/SU + 1 - offset := (fast-1)*SU - curr_block := uintptr(0) - if n < SU { - fast = 0 + // Because we're comparing against zero, we never return -1, as that would + // indicate the compared value is less than zero. + // + // Note that a zero return value here means equality. + + bytes := ([^]u8)(a) + + if n >= 8 { + when HAS_HARDWARE_SIMD { + when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") { + scanner32: #simd[32]u8 + m = n / 32 * 32 + for /**/; i < m; i += 32 { + load := intrinsics.unaligned_load(cast(^#simd[32]u8)&bytes[i]) + ne := intrinsics.simd_lanes_ne(scanner32, load) + if intrinsics.simd_reduce_or(ne) > 0 { + return 1 + } + } + } + } + + scanner16: #simd[16]u8 + m = (n-i) / 16 * 16 + for /**/; i < m; i += 16 { + load := intrinsics.unaligned_load(cast(^#simd[16]u8)&bytes[i]) + ne := intrinsics.simd_lanes_ne(scanner16, load) + if intrinsics.simd_reduce_or(ne) != 0 { + return 1 + } + } + + m = (n-i) / size_of(uintptr) * size_of(uintptr) + for /**/; i < m; i += size_of(uintptr) { + if intrinsics.unaligned_load(cast(^uintptr)&bytes[i]) != 0 { + return 1 + } + } } - for /**/; curr_block < fast; curr_block += 1 { - va := (^uintptr)(x + curr_block * size_of(uintptr))^ - if va ~ 0 != 0 { - for pos := curr_block*SU; pos < n; pos += 1 { - a := (^byte)(x+pos)^ - if a ~ 0 != 0 { - return -1 if int(a) < 0 else +1 + for /**/; i < n; i += 1 { + if bytes[i] != 0 { + return 1 + } + } + return 0 +} + +memory_prefix_length :: proc "contextless" (x, y: rawptr, n: int) -> (idx: int) #no_bounds_check { + switch { + case x == y: return n + case x == nil: return 0 + case y == nil: return 0 + } + a, b := cast([^]byte)x, cast([^]byte)y + + n := uint(n) + i := uint(0) + m := uint(0) + + when HAS_HARDWARE_SIMD { + when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") { + m = n / 32 * 32 + for /**/; i < m; i += 32 { + load_a := intrinsics.unaligned_load(cast(^#simd[32]u8)&a[i]) + load_b := intrinsics.unaligned_load(cast(^#simd[32]u8)&b[i]) + comparison := intrinsics.simd_lanes_ne(load_a, load_b) + if intrinsics.simd_reduce_or(comparison) != 0 { + sentinel: #simd[32]u8 = u8(0xFF) + indices := intrinsics.simd_indices(#simd[32]u8) + index_select := intrinsics.simd_select(comparison, indices, sentinel) + index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select) + return int(i + index_reduce) } } } } - for /**/; offset < n; offset += 1 { - a := (^byte)(x+offset)^ - if a ~ 0 != 0 { - return -1 if int(a) < 0 else +1 + m = (n-i) / 16 * 16 + for /**/; i < m; i += 16 { + load_a := intrinsics.unaligned_load(cast(^#simd[16]u8)&a[i]) + load_b := intrinsics.unaligned_load(cast(^#simd[16]u8)&b[i]) + comparison := intrinsics.simd_lanes_ne(load_a, load_b) + if intrinsics.simd_reduce_or(comparison) != 0 { + sentinel: #simd[16]u8 = u8(0xFF) + indices := intrinsics.simd_indices(#simd[16]u8) + index_select := intrinsics.simd_select(comparison, indices, sentinel) + index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select) + return int(i + index_reduce) } } - return 0 + // 64-bit SIMD is faster than using a `uintptr` to detect a difference then + // re-iterating with the byte-by-byte loop, at least on AMD64. + m = (n-i) / 8 * 8 + for /**/; i < m; i += 8 { + load_a := intrinsics.unaligned_load(cast(^#simd[8]u8)&a[i]) + load_b := intrinsics.unaligned_load(cast(^#simd[8]u8)&b[i]) + comparison := intrinsics.simd_lanes_ne(load_a, load_b) + if intrinsics.simd_reduce_or(comparison) != 0 { + sentinel: #simd[8]u8 = u8(0xFF) + indices := intrinsics.simd_indices(#simd[8]u8) + index_select := intrinsics.simd_select(comparison, indices, sentinel) + index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select) + return int(i + index_reduce) + } + } + + for /**/; i < n; i += 1 { + if a[i] ~ b[i] != 0 { + return int(i) + } + } + return int(n) } string_eq :: proc "contextless" (lhs, rhs: string) -> bool { @@ -396,12 +542,40 @@ string_cmp :: proc "contextless" (a, b: string) -> int { return ret } + +string16_eq :: proc "contextless" (lhs, rhs: string16) -> bool { + x := transmute(Raw_String16)lhs + y := transmute(Raw_String16)rhs + if x.len != y.len { + return false + } + return #force_inline memory_equal(x.data, y.data, x.len*size_of(u16)) +} + +string16_cmp :: proc "contextless" (a, b: string16) -> int { + x := transmute(Raw_String16)a + y := transmute(Raw_String16)b + + ret := memory_compare(x.data, y.data, min(x.len, y.len)*size_of(u16)) + if ret == 0 && x.len != y.len { + return -1 if x.len < y.len else +1 + } + return ret +} + string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b) } string_lt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) < 0 } string_gt :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) > 0 } string_le :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) <= 0 } string_ge :: #force_inline proc "contextless" (a, b: string) -> bool { return string_cmp(a, b) >= 0 } +string16_ne :: #force_inline proc "contextless" (a, b: string16) -> bool { return !string16_eq(a, b) } +string16_lt :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) < 0 } +string16_gt :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) > 0 } +string16_le :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) <= 0 } +string16_ge :: #force_inline proc "contextless" (a, b: string16) -> bool { return string16_cmp(a, b) >= 0 } + + cstring_len :: proc "contextless" (s: cstring) -> int { p0 := uintptr((^byte)(s)) p := p0 @@ -411,6 +585,16 @@ cstring_len :: proc "contextless" (s: cstring) -> int { return int(p - p0) } +cstring16_len :: proc "contextless" (s: cstring16) -> int { + p := ([^]u16)(s) + n := 0 + for p != nil && p[0] != 0 { + p = p[1:] + n += 1 + } + return n +} + cstring_to_string :: proc "contextless" (s: cstring) -> string { if s == nil { return "" @@ -420,6 +604,15 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string { return transmute(string)Raw_String{ptr, n} } +cstring16_to_string16 :: proc "contextless" (s: cstring16) -> string16 { + if s == nil { + return "" + } + ptr := (^u16)(s) + n := cstring16_len(s) + return transmute(string16)Raw_String16{ptr, n} +} + cstring_eq :: proc "contextless" (lhs, rhs: cstring) -> bool { x := ([^]byte)(lhs) @@ -462,6 +655,46 @@ cstring_gt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_le :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) <= 0 } cstring_ge :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) >= 0 } +cstring16_eq :: proc "contextless" (lhs, rhs: cstring16) -> bool { + x := ([^]u16)(lhs) + y := ([^]u16)(rhs) + if x == y { + return true + } + if (x == nil) ~ (y == nil) { + return false + } + xn := cstring16_len(lhs) + yn := cstring16_len(rhs) + if xn != yn { + return false + } + return #force_inline memory_equal(x, y, xn*size_of(u16)) +} + +cstring16_cmp :: proc "contextless" (lhs, rhs: cstring16) -> int { + x := ([^]u16)(lhs) + y := ([^]u16)(rhs) + if x == y { + return 0 + } + if (x == nil) ~ (y == nil) { + return -1 if x == nil else +1 + } + xn := cstring16_len(lhs) + yn := cstring16_len(rhs) + ret := memory_compare(x, y, min(xn, yn)*size_of(u16)) + if ret == 0 && xn != yn { + return -1 if xn < yn else +1 + } + return ret +} + +cstring16_ne :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return !cstring16_eq(a, b) } +cstring16_lt :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) < 0 } +cstring16_gt :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) > 0 } +cstring16_le :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) <= 0 } +cstring16_ge :: #force_inline proc "contextless" (a, b: cstring16) -> bool { return cstring16_cmp(a, b) >= 0 } complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) } complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) } @@ -483,7 +716,7 @@ quaternion256_eq :: #force_inline proc "contextless" (a, b: quaternion256) -> bo quaternion256_ne :: #force_inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b) } -string_decode_rune :: #force_inline proc "contextless" (s: string) -> (rune, int) { +string_decode_rune :: proc "contextless" (s: string) -> (rune, int) { // NOTE(bill): Duplicated here to remove dependency on package unicode/utf8 @(static, rodata) accept_sizes := [256]u8{ @@ -597,6 +830,68 @@ string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) { return r, size } + +string16_decode_rune :: proc "contextless" (s: string16) -> (rune, int) { + REPLACEMENT_CHAR :: '\ufffd' + _surr1 :: 0xd800 + _surr2 :: 0xdc00 + _surr3 :: 0xe000 + _surr_self :: 0x10000 + + r := rune(REPLACEMENT_CHAR) + + if len(s) < 1 { + return r, 0 + } + + w := 1 + switch c := s[0]; { + case c < _surr1, _surr3 <= c: + r = rune(c) + case _surr1 <= c && c < _surr2 && 1 < len(s) && + _surr2 <= s[1] && s[1] < _surr3: + r1, r2 := rune(c), rune(s[1]) + if _surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3 { + r = (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self + } + w += 1 + } + return r, w +} + +string16_decode_last_rune :: proc "contextless" (s: string16) -> (rune, int) { + REPLACEMENT_CHAR :: '\ufffd' + _surr1 :: 0xd800 + _surr2 :: 0xdc00 + _surr3 :: 0xe000 + _surr_self :: 0x10000 + + r := rune(REPLACEMENT_CHAR) + + if len(s) < 1 { + return r, 0 + } + + n := len(s)-1 + c := s[n] + w := 1 + if _surr2 <= c && c < _surr3 { + if n >= 1 { + r1 := rune(s[n-1]) + r2 := rune(c) + if _surr1 <= r1 && r1 < _surr2 { + r = (r1-_surr1)<<10 | (r2 - _surr2) + _surr_self + } + w = 2 + } + } else if c < _surr1 || _surr3 <= c { + r = rune(c) + } + return r, w +} + + + abs_complex32 :: #force_inline proc "contextless" (x: complex32) -> f16 { p, q := abs(real(x)), abs(imag(x)) if p < q { @@ -1106,3 +1401,11 @@ __read_bits :: proc "contextless" (dst, src: [^]byte, offset: uintptr, size: uin dst[j>>3] |= the_bit<<(j&7) } } + +when .Address in ODIN_SANITIZER_FLAGS { + foreign { + @(require) + __asan_unpoison_memory_region :: proc "system" (address: rawptr, size: uint) --- + } +} + diff --git a/base/runtime/os_specific_bsd.odin b/base/runtime/os_specific_bsd.odin index 5d198484b..466001ada 100644 --- a/base/runtime/os_specific_bsd.odin +++ b/base/runtime/os_specific_bsd.odin @@ -9,7 +9,7 @@ foreign libc { @(link_name="write") _unix_write :: proc(fd: i32, buf: rawptr, size: int) -> int --- - when ODIN_OS == .NetBSD { + when ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { @(link_name="__errno") __error :: proc() -> ^i32 --- } else { __error :: proc() -> ^i32 --- diff --git a/base/runtime/print.odin b/base/runtime/print.odin index c28fd593d..2cfb6661b 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -293,7 +293,14 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_string("quaternion") print_u64(u64(8*ti.size)) case Type_Info_String: + if info.is_cstring { + print_byte('c') + } print_string("string") + switch info.encoding { + case .UTF_8: /**/ + case .UTF_16: print_string("16") + } case Type_Info_Boolean: switch ti.id { case bool: print_string("bool") @@ -403,7 +410,7 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) { print_string("struct ") if .packed in info.flags { print_string("#packed ") } if .raw_union in info.flags { print_string("#raw_union ") } - if .no_copy in info.flags { print_string("#no_copy ") } + // if .no_copy in info.flags { print_string("#no_copy ") } if .align in info.flags { print_string("#align(") print_u64(u64(ti.align)) diff --git a/base/runtime/procs_darwin.odin b/base/runtime/procs_darwin.odin index c3fc46af1..0ffe68e49 100644 --- a/base/runtime/procs_darwin.odin +++ b/base/runtime/procs_darwin.odin @@ -1,22 +1,56 @@ #+private package runtime +@(priority_index=-1e5) +foreign import ObjC "system:objc" + @(priority_index=-1e6) -foreign import "system:Foundation.framework" +foreign import libSystem "system:System" import "base:intrinsics" -objc_id :: ^intrinsics.objc_object +objc_id :: ^intrinsics.objc_object objc_Class :: ^intrinsics.objc_class -objc_SEL :: ^intrinsics.objc_selector +objc_SEL :: ^intrinsics.objc_selector +objc_Ivar :: ^intrinsics.objc_ivar +objc_BOOL :: bool -foreign Foundation { - objc_lookUpClass :: proc "c" (name: cstring) -> objc_Class --- - sel_registerName :: proc "c" (name: cstring) -> objc_SEL --- - objc_allocateClassPair :: proc "c" (superclass: objc_Class, name: cstring, extraBytes: uint) -> objc_Class --- - - objc_msgSend :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) --- - objc_msgSend_fpret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> f64 --- - objc_msgSend_fp2ret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> complex128 --- - objc_msgSend_stret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) --- +objc_super :: struct { + receiver: objc_id, + super_class: objc_Class, +} + +objc_IMP :: proc "c" (object: objc_id, sel: objc_SEL, #c_vararg args: ..any) -> objc_id + +foreign ObjC { + sel_registerName :: proc "c" (name: cstring) -> objc_SEL --- + + objc_msgSend :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) --- + objc_msgSend_fpret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> f64 --- + objc_msgSend_fp2ret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) -> complex128 --- + objc_msgSend_stret :: proc "c" (self: objc_id, op: objc_SEL, #c_vararg args: ..any) --- + + // See: https://github.com/opensource-apple/objc4/blob/cd5e62a5597ea7a31dccef089317abb3a661c154/runtime/objc-abi.h#L111 + objc_msgSendSuper2 :: proc "c" (super: rawptr, op: objc_SEL, #c_vararg args: ..any) -> objc_id --- + objc_msgSendSuper2_stret :: proc "c" (super: ^objc_super, op: objc_SEL, #c_vararg args: ..any) --- + + + objc_lookUpClass :: proc "c" (name: cstring) -> objc_Class --- + objc_allocateClassPair :: proc "c" (superclass: objc_Class, name: cstring, extraBytes: uint) -> objc_Class --- + objc_registerClassPair :: proc "c" (cls : objc_Class) --- + class_addMethod :: proc "c" (cls: objc_Class, name: objc_SEL, imp: objc_IMP, types: cstring) -> objc_BOOL --- + class_addIvar :: proc "c" (cls: objc_Class, name: cstring, size: uint, alignment: u8, types: cstring) -> objc_BOOL --- + class_getInstanceVariable :: proc "c" (cls : objc_Class, name: cstring) -> objc_Ivar --- + class_getInstanceSize :: proc "c" (cls : objc_Class) -> uint --- + class_getSuperclass :: proc "c" (cls : objc_Class) -> objc_Class --- + ivar_getOffset :: proc "c" (v: objc_Ivar) -> uintptr --- + object_getClass :: proc "c" (obj: objc_id) -> objc_Class --- +} + +foreign libSystem { + _NSConcreteGlobalBlock: intrinsics.objc_class + _NSConcreteStackBlock: intrinsics.objc_class + + _Block_object_assign :: proc "c" (rawptr, rawptr, i32) --- + _Block_object_dispose :: proc "c" (rawptr, i32) --- } diff --git a/base/runtime/procs_js.odin b/base/runtime/procs_js.odin index 58bed808d..3690f9436 100644 --- a/base/runtime/procs_js.odin +++ b/base/runtime/procs_js.odin @@ -3,8 +3,8 @@ package runtime init_default_context_for_js: Context @(init, private="file") -init_default_context :: proc() { - init_default_context_for_js = context +init_default_context :: proc "contextless" () { + __init_context(&init_default_context_for_js) } @(export) diff --git a/base/runtime/random_generator.odin b/base/runtime/random_generator.odin index 81432b330..ca5c008d0 100644 --- a/base/runtime/random_generator.odin +++ b/base/runtime/random_generator.odin @@ -97,7 +97,7 @@ default_random_generator_proc :: proc(data: rawptr, mode: Random_Generator_Mode, for &v in p { if pos == 0 { val = read_u64(r) - pos = 7 + pos = 8 } v = byte(val) val >>= 8 diff --git a/base/runtime/thread_management.odin b/base/runtime/thread_management.odin index cabd4691c..97dcbc8f5 100644 --- a/base/runtime/thread_management.odin +++ b/base/runtime/thread_management.odin @@ -1,10 +1,14 @@ package runtime -Thread_Local_Cleaner :: #type proc "odin" () +Thread_Local_Cleaner_Odin :: #type proc "odin" () +Thread_Local_Cleaner_Contextless :: #type proc "contextless" () + +Thread_Local_Cleaner :: union #shared_nil {Thread_Local_Cleaner_Odin, Thread_Local_Cleaner_Contextless} @(private="file") thread_local_cleaners: [8]Thread_Local_Cleaner + // Add a procedure that will be run at the end of a thread for the purpose of // deallocating state marked as `thread_local`. // @@ -29,6 +33,9 @@ run_thread_local_cleaners :: proc "odin" () { if p == nil { break } - p() + switch v in p { + case Thread_Local_Cleaner_Odin: v() + case Thread_Local_Cleaner_Contextless: v() + } } } diff --git a/base/runtime/wasm_allocator.odin b/base/runtime/wasm_allocator.odin index 574f3dd06..325b1d4fa 100644 --- a/base/runtime/wasm_allocator.odin +++ b/base/runtime/wasm_allocator.odin @@ -89,10 +89,12 @@ wasm_allocator_init :: proc(a: ^WASM_Allocator, alignment: uint = 8) { global_default_wasm_allocator_data: WASM_Allocator +@(require_results) default_wasm_allocator :: proc() -> Allocator { return wasm_allocator(&global_default_wasm_allocator_data) } +@(require_results) wasm_allocator :: proc(a: ^WASM_Allocator) -> Allocator { return { data = a, diff --git a/base/sanitizer/address.odin b/base/sanitizer/address.odin new file mode 100644 index 000000000..edfdfc172 --- /dev/null +++ b/base/sanitizer/address.odin @@ -0,0 +1,601 @@ +#+no-instrumentation +package sanitizer + +Address_Death_Callback :: #type proc "c" (pc: rawptr, bp: rawptr, sp: rawptr, addr: rawptr, is_write: i32, access_size: uint) + +@(private="file") +ASAN_ENABLED :: .Address in ODIN_SANITIZER_FLAGS + +@(private="file") +@(default_calling_convention="system") +foreign { + __asan_poison_memory_region :: proc(address: rawptr, size: uint) --- + __asan_unpoison_memory_region :: proc(address: rawptr, size: uint) --- + __sanitizer_set_death_callback :: proc(callback: Address_Death_Callback) --- + __asan_region_is_poisoned :: proc(begin: rawptr, size: uint) -> rawptr --- + __asan_address_is_poisoned :: proc(addr: rawptr) -> i32 --- + __asan_describe_address :: proc(addr: rawptr) --- + __asan_report_present :: proc() -> i32 --- + __asan_get_report_pc :: proc() -> rawptr --- + __asan_get_report_bp :: proc() -> rawptr --- + __asan_get_report_sp :: proc() -> rawptr --- + __asan_get_report_address :: proc() -> rawptr --- + __asan_get_report_access_type :: proc() -> i32 --- + __asan_get_report_access_size :: proc() -> uint --- + __asan_get_report_description :: proc() -> cstring --- + __asan_locate_address :: proc(addr: rawptr, name: rawptr, name_size: uint, region_address: ^rawptr, region_size: ^uint) -> cstring --- + __asan_get_alloc_stack :: proc(addr: rawptr, trace: rawptr, size: uint, thread_id: ^i32) -> uint --- + __asan_get_free_stack :: proc(addr: rawptr, trace: rawptr, size: uint, thread_id: ^i32) -> uint --- + __asan_get_shadow_mapping :: proc(shadow_scale: ^uint, shadow_offset: ^uint) --- + __asan_print_accumulated_stats :: proc() --- + __asan_get_current_fake_stack :: proc() -> rawptr --- + __asan_addr_is_in_fake_stack :: proc(fake_stack: rawptr, addr: rawptr, beg: ^rawptr, end: ^rawptr) -> rawptr --- + __asan_handle_no_return :: proc() --- + __asan_update_allocation_context :: proc(addr: rawptr) -> i32 --- +} + +Address_Access_Type :: enum { + none, + read, + write, +} + +Address_Located_Address :: struct { + category: string, + name: string, + region: []byte, +} + +Address_Shadow_Mapping :: struct { + scale: uint, + offset: uint, +} + +/* +Marks a slice as unaddressable + +Code instrumented with `-sanitize:address` is forbidden from accessing any address +within the slice. This procedure is not thread-safe because no two threads can +poison or unpoison memory in the same memory region region simultaneously. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_poison_slice :: proc "contextless" (region: $T/[]$E) { + when ASAN_ENABLED { + __asan_poison_memory_region(raw_data(region), size_of(E) * len(region)) + } +} + +/* +Marks a slice as addressable + +Code instrumented with `-sanitize:address` is allowed to access any address +within the slice again. This procedure is not thread-safe because no two threads +can poison or unpoison memory in the same memory region region simultaneously. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_unpoison_slice :: proc "contextless" (region: $T/[]$E) { + when ASAN_ENABLED { + __asan_unpoison_memory_region(raw_data(region), size_of(E) * len(region)) + } +} + +/* +Marks a pointer as unaddressable + +Code instrumented with `-sanitize:address` is forbidden from accessing any address +within the region the pointer points to. This procedure is not thread-safe because no +two threads can poison or unpoison memory in the same memory region region simultaneously. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_poison_ptr :: proc "contextless" (ptr: ^$T) { + when ASAN_ENABLED { + __asan_poison_memory_region(ptr, size_of(T)) + } +} + +/* +Marks a pointer as addressable + +Code instrumented with `-sanitize:address` is allowed to access any address +within the region the pointer points to again. This procedure is not thread-safe +because no two threads can poison or unpoison memory in the same memory region +region simultaneously. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_unpoison_ptr :: proc "contextless" (ptr: ^$T) { + when ASAN_ENABLED { + __asan_unpoison_memory_region(ptr, size_of(T)) + } +} + +/* +Marks the region covering `[ptr, ptr+len)` as unaddressable + +Code instrumented with `-sanitize:address` is forbidden from accessing any address +within the region. This procedure is not thread-safe because no two threads can +poison or unpoison memory in the same memory region region simultaneously. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_poison_rawptr :: proc "contextless" (ptr: rawptr, len: int) { + when ASAN_ENABLED { + assert_contextless(len >= 0) + __asan_poison_memory_region(ptr, uint(len)) + } +} + +/* +Marks the region covering `[ptr, ptr+len)` as unaddressable + +Code instrumented with `-sanitize:address` is forbidden from accessing any address +within the region. This procedure is not thread-safe because no two threads can +poison or unpoison memory in the same memory region region simultaneously. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_poison_rawptr_uint :: proc "contextless" (ptr: rawptr, len: uint) { + when ASAN_ENABLED { + __asan_poison_memory_region(ptr, len) + } +} + +/* +Marks the region covering `[ptr, ptr+len)` as addressable + +Code instrumented with `-sanitize:address` is allowed to access any address +within the region again. This procedure is not thread-safe because no two +threads can poison or unpoison memory in the same memory region region simultaneously. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_unpoison_rawptr :: proc "contextless" (ptr: rawptr, len: int) { + when ASAN_ENABLED { + assert_contextless(len >= 0) + __asan_unpoison_memory_region(ptr, uint(len)) + } +} + +/* +Marks the region covering `[ptr, ptr+len)` as addressable + +Code instrumented with `-sanitize:address` is allowed to access any address +within the region again. This procedure is not thread-safe because no two +threads can poison or unpoison memory in the same memory region region simultaneously. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_unpoison_rawptr_uint :: proc "contextless" (ptr: rawptr, len: uint) { + when ASAN_ENABLED { + __asan_unpoison_memory_region(ptr, len) + } +} + +address_poison :: proc { + address_poison_slice, + address_poison_ptr, + address_poison_rawptr, + address_poison_rawptr_uint, +} + +address_unpoison :: proc { + address_unpoison_slice, + address_unpoison_ptr, + address_unpoison_rawptr, + address_unpoison_rawptr_uint, +} + +/* +Registers a callback to be run when asan detects a memory error right before terminating +the process. + +This can be used for logging and/or debugging purposes. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_set_death_callback :: proc "contextless" (callback: Address_Death_Callback) { + when ASAN_ENABLED { + __sanitizer_set_death_callback(callback) + } +} + +/* +Checks if the memory region covered by the slice is poisoned. + +If it is poisoned this procedure returns the address which would result +in an asan error. + +When asan is not enabled this procedure returns `nil`. +*/ +@(no_sanitize_address) +address_region_is_poisoned_slice :: proc "contextless" (region: $T/[]$E) -> rawptr { + when ASAN_ENABLED { + return __asan_region_is_poisoned(raw_data(region), size_of(E) * len(region)) + } else { + return nil + } +} + +/* +Checks if the memory region pointed to by the pointer is poisoned. + +If it is poisoned this procedure returns the address which would result +in an asan error. + +When asan is not enabled this procedure returns `nil`. +*/ +@(no_sanitize_address) +address_region_is_poisoned_ptr :: proc "contextless" (ptr: ^$T) -> rawptr { + when ASAN_ENABLED { + return __asan_region_is_poisoned(ptr, size_of(T)) + } else { + return nil + } +} + +/* +Checks if the memory region covered by `[ptr, ptr+len)` is poisoned. + +If it is poisoned this procedure returns the address which would result +in an asan error. + +When asan is not enabled this procedure returns `nil`. +*/ +@(no_sanitize_address) +address_region_is_poisoned_rawptr :: proc "contextless" (region: rawptr, len: int) -> rawptr { + when ASAN_ENABLED { + assert_contextless(len >= 0) + return __asan_region_is_poisoned(region, uint(len)) + } else { + return nil + } +} + +/* +Checks if the memory region covered by `[ptr, ptr+len)` is poisoned. + +If it is poisoned this procedure returns the address which would result +in an asan error. + +When asan is not enabled this procedure returns `nil`. +*/ +@(no_sanitize_address) +address_region_is_poisoned_rawptr_uint :: proc "contextless" (region: rawptr, len: uint) -> rawptr { + when ASAN_ENABLED { + return __asan_region_is_poisoned(region, len) + } else { + return nil + } +} + + +address_region_is_poisoned :: proc { + address_region_is_poisoned_slice, + address_region_is_poisoned_ptr, + address_region_is_poisoned_rawptr, + address_region_is_poisoned_rawptr_uint, +} + +/* +Checks if the address is poisoned. + +If it is poisoned this procedure returns `true`, otherwise it returns +`false`. + +When asan is not enabled this procedure returns `false`. +*/ +@(no_sanitize_address) +address_is_poisoned :: proc "contextless" (address: rawptr) -> bool { + when ASAN_ENABLED { + return __asan_address_is_poisoned(address) != 0 + } else { + return false + } +} + +/* +Describes the sanitizer state for an address. + +This procedure prints the description out to `stdout`. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_describe_address :: proc "contextless" (address: rawptr) { + when ASAN_ENABLED { + __asan_describe_address(address) + } +} + +/* +Returns `true` if an asan error has occured, otherwise it returns +`false`. + +When asan is not enabled this procedure returns `false`. +*/ +@(no_sanitize_address) +address_report_present :: proc "contextless" () -> bool { + when ASAN_ENABLED { + return __asan_report_present() != 0 + } else { + return false + } +} + +/* +Returns the program counter register value of an asan error. + +If no asan error has occurd `nil` is returned. + +When asan is not enabled this procedure returns `nil`. +*/ +@(no_sanitize_address) +address_get_report_pc :: proc "contextless" () -> rawptr { + when ASAN_ENABLED { + return __asan_get_report_pc() + } else { + return nil + } +} + +/* +Returns the base pointer register value of an asan error. + +If no asan error has occurd `nil` is returned. + +When asan is not enabled this procedure returns `nil`. +*/ +@(no_sanitize_address) +address_get_report_bp :: proc "contextless" () -> rawptr { + when ASAN_ENABLED { + return __asan_get_report_bp() + } else { + return nil + } +} + +/* +Returns the stack pointer register value of an asan error. + +If no asan error has occurd `nil` is returned. + +When asan is not enabled this procedure returns `nil`. +*/ +@(no_sanitize_address) +address_get_report_sp :: proc "contextless" () -> rawptr { + when ASAN_ENABLED { + return __asan_get_report_sp() + } else { + return nil + } +} + +/* +Returns the report buffer address of an asan error. + +If no asan error has occurd `nil` is returned. + +When asan is not enabled this procedure returns `nil`. +*/ +@(no_sanitize_address) +address_get_report_address :: proc "contextless" () -> rawptr { + when ASAN_ENABLED { + return __asan_get_report_address() + } else { + return nil + } +} + +/* +Returns the address access type of an asan error. + +If no asan error has occurd `.none` is returned. + +When asan is not enabled this procedure returns `.none`. +*/ +@(no_sanitize_address) +address_get_report_access_type :: proc "contextless" () -> Address_Access_Type { + when ASAN_ENABLED { + if ! address_report_present() { + return .none + } + return __asan_get_report_access_type() == 0 ? .read : .write + } else { + return .none + } +} + +/* +Returns the access size of an asan error. + +If no asan error has occurd `0` is returned. + +When asan is not enabled this procedure returns `0`. +*/ +@(no_sanitize_address) +address_get_report_access_size :: proc "contextless" () -> uint { + when ASAN_ENABLED { + return __asan_get_report_access_size() + } else { + return 0 + } +} + +/* +Returns the bug description of an asan error. + +If no asan error has occurd an empty string is returned. + +When asan is not enabled this procedure returns an empty string. +*/ +@(no_sanitize_address) +address_get_report_description :: proc "contextless" () -> string { + when ASAN_ENABLED { + return string(__asan_get_report_description()) + } else { + return "" + } +} + +/* +Returns asan information about the address provided, writing the category into `data`. + +The information provided include: +* The category of the address, i.e. stack, global, heap, etc. +* The name of the variable this address belongs to +* The memory region of the address + +When asan is not enabled this procedure returns zero initialised values. +*/ +@(no_sanitize_address) +address_locate_address :: proc "contextless" (addr: rawptr, data: []byte) -> Address_Located_Address { + when ASAN_ENABLED { + out_addr: rawptr + out_size: uint + str := __asan_locate_address(addr, raw_data(data), len(data), &out_addr, &out_size) + return { string(str), string(cstring(raw_data(data))), (cast([^]byte)out_addr)[:out_size] }, + } else { + return { "", "", {} } + } +} + +/* +Returns the allocation stack trace and thread id for a heap address. + +The stack trace is filled into the `data` slice. + +When asan is not enabled this procedure returns a zero initialised value. +*/ +@(no_sanitize_address) +address_get_alloc_stack_trace :: proc "contextless" (addr: rawptr, data: []rawptr) -> ([]rawptr, int) { + when ASAN_ENABLED { + out_thread: i32 + __asan_get_alloc_stack(addr, raw_data(data), len(data), &out_thread) + return data, int(out_thread) + } else { + return {}, 0 + } +} + +/* +Returns the free stack trace and thread id for a heap address. + +The stack trace is filled into the `data` slice. + +When asan is not enabled this procedure returns zero initialised values. +*/ +@(no_sanitize_address) +address_get_free_stack_trace :: proc "contextless" (addr: rawptr, data: []rawptr) -> ([]rawptr, int) { + when ASAN_ENABLED { + out_thread: i32 + __asan_get_free_stack(addr, raw_data(data), len(data), &out_thread) + return data, int(out_thread) + } else { + return {}, 0 + } +} + +/* +Returns the current asan shadow memory mapping. + +When asan is not enabled this procedure returns a zero initialised value. +*/ +@(no_sanitize_address) +address_get_shadow_mapping :: proc "contextless" () -> Address_Shadow_Mapping { + when ASAN_ENABLED { + result: Address_Shadow_Mapping + __asan_get_shadow_mapping(&result.scale, &result.offset) + return result + } else { + return {} + } +} + +/* +Prints asan statistics to `stderr` + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_print_accumulated_stats :: proc "contextless" () { + when ASAN_ENABLED { + __asan_print_accumulated_stats() + } +} + +/* +Returns the address of the current fake stack used by asan. + +This pointer can be then used for `address_is_in_fake_stack`. + +When asan is not enabled this procedure returns `nil`. +*/ +@(no_sanitize_address) +address_get_current_fake_stack :: proc "contextless" () -> rawptr { + when ASAN_ENABLED { + return __asan_get_current_fake_stack() + } else { + return nil + } +} + +/* +Returns if an address belongs to a given fake stack and if so the region of the fake frame. + +When asan is not enabled this procedure returns zero initialised values. +*/ +@(no_sanitize_address) +address_is_in_fake_stack :: proc "contextless" (fake_stack: rawptr, addr: rawptr) -> ([]byte, bool) { + when ASAN_ENABLED { + begin: rawptr + end: rawptr + if __asan_addr_is_in_fake_stack(fake_stack, addr, &begin, &end) == nil { + return {}, false + } + return ((cast([^]byte)begin)[:uintptr(end)-uintptr(begin)]), true + } else { + return {}, false + } +} + +/* +Performs shadow memory cleanup for the current thread before a procedure with no return is called +i.e. a procedure such as `panic` and `os.exit`. + +When asan is not enabled this procedure does nothing. +*/ +@(no_sanitize_address) +address_handle_no_return :: proc "contextless" () { + when ASAN_ENABLED { + __asan_handle_no_return() + } +} + +/* +Updates the allocation stack trace for the given address. + +Returns `true` if successful, otherwise it returns `false`. + +When asan is not enabled this procedure returns `false`. +*/ +@(no_sanitize_address) +address_update_allocation_context :: proc "contextless" (addr: rawptr) -> bool { + when ASAN_ENABLED { + return __asan_update_allocation_context(addr) != 0 + } else { + return false + } +} + diff --git a/base/sanitizer/doc.odin b/base/sanitizer/doc.odin new file mode 100644 index 000000000..707f41ce0 --- /dev/null +++ b/base/sanitizer/doc.odin @@ -0,0 +1,38 @@ +/* +The `sanitizer` package implements various procedures for interacting with sanitizers +from user code. + +An odin project can be linked with various sanitizers to help identify various different +bugs. These sanitizers are: + +## Address + +Enabled with `-sanitize:address` when building an odin project. + +The address sanitizer (asan) is a runtime memory error detector used to help find common memory +related bugs. Typically asan interacts with libc but Odin code can be marked up to interact +with the asan runtime to extend the memory error detection outside of libc using this package. +For more information about asan see: https://clang.llvm.org/docs/AddressSanitizer.html + +Procedures can be made exempt from asan when marked up with @(no_sanitize_address) + +## Memory + +Enabled with `-sanitize:memory` when building an odin project. + +The memory sanitizer is another runtime memory error detector with the sole purpose to catch the +use of uninitialized memory. This is not a very common bug in Odin as by default everything is +set to zero when initialised (ZII). +For more information about the memory sanitizer see: https://clang.llvm.org/docs/MemorySanitizer.html + +## Thread + +Enabled with `-sanitize:thread` when building an odin project. + +The thread sanitizer is a runtime data race detector. It can be used to detect if multiple threads +are concurrently writing and accessing a memory location without proper syncronisation. +For more information about the thread sanitizer see: https://clang.llvm.org/docs/ThreadSanitizer.html + +*/ +package sanitizer + diff --git a/base/sanitizer/memory.odin b/base/sanitizer/memory.odin new file mode 100644 index 000000000..b16309a49 --- /dev/null +++ b/base/sanitizer/memory.odin @@ -0,0 +1,74 @@ +#+no-instrumentation +package sanitizer + +@(private="file") +MSAN_ENABLED :: .Memory in ODIN_SANITIZER_FLAGS + +@(private="file") +@(default_calling_convention="system") +foreign { + __msan_unpoison :: proc(addr: rawptr, size: uint) --- +} + +/* +Marks a slice as fully initialized. + +Code instrumented with `-sanitize:memory` will be permitted to access any +address within the slice as if it had already been initialized. + +When msan is not enabled this procedure does nothing. +*/ +memory_unpoison_slice :: proc "contextless" (region: $T/[]$E) { + when MSAN_ENABLED { + __msan_unpoison(raw_data(region), size_of(E) * len(region)) + } +} + +/* +Marks a pointer as fully initialized. + +Code instrumented with `-sanitize:memory` will be permitted to access memory +within the region the pointer points to as if it had already been initialized. + +When msan is not enabled this procedure does nothing. +*/ +memory_unpoison_ptr :: proc "contextless" (ptr: ^$T) { + when MSAN_ENABLED { + __msan_unpoison(ptr, size_of(T)) + } +} + +/* +Marks the region covering `[ptr, ptr+len)` as fully initialized. + +Code instrumented with `-sanitize:memory` will be permitted to access memory +within this range as if it had already been initialized. + +When msan is not enabled this procedure does nothing. +*/ +memory_unpoison_rawptr :: proc "contextless" (ptr: rawptr, len: int) { + when MSAN_ENABLED { + __msan_unpoison(ptr, uint(len)) + } +} + +/* +Marks the region covering `[ptr, ptr+len)` as fully initialized. + +Code instrumented with `-sanitize:memory` will be permitted to access memory +within this range as if it had already been initialized. + +When msan is not enabled this procedure does nothing. +*/ +memory_unpoison_rawptr_uint :: proc "contextless" (ptr: rawptr, len: uint) { + when MSAN_ENABLED { + __msan_unpoison(ptr, len) + } +} + +memory_unpoison :: proc { + memory_unpoison_slice, + memory_unpoison_ptr, + memory_unpoison_rawptr, + memory_unpoison_rawptr_uint, +} diff --git a/bin/lld-link.exe b/bin/lld-link.exe index da6527264..ec739e0fd 100644 Binary files a/bin/lld-link.exe and b/bin/lld-link.exe differ diff --git a/bin/llvm/windows/LLVM-C.lib b/bin/llvm/windows/LLVM-C.lib index 0e5b6c624..6230de057 100644 Binary files a/bin/llvm/windows/LLVM-C.lib and b/bin/llvm/windows/LLVM-C.lib differ diff --git a/bin/wasm-ld.exe b/bin/wasm-ld.exe index da6527264..ec739e0fd 100644 Binary files a/bin/wasm-ld.exe and b/bin/wasm-ld.exe differ diff --git a/build.bat b/build.bat index a788a8c04..b1ff9b173 100644 --- a/build.bat +++ b/build.bat @@ -4,12 +4,12 @@ setlocal EnableDelayedExpansion where /Q cl.exe || ( set __VSCMD_ARG_NO_LOGO=1 - for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -requires Microsoft.VisualStudio.Workload.NativeDesktop -property installationPath') do set VS=%%i + for /f "tokens=*" %%i in ('"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath') do set VS=%%i if "!VS!" equ "" ( - echo ERROR: Visual Studio installation not found + echo ERROR: MSVC installation not found exit /b 1 ) - call "!VS!\VC\Auxiliary\Build\vcvarsall.bat" amd64 || exit /b 1 + call "!VS!\Common7\Tools\vsdevcmd.bat" -arch=x64 -host_arch=x64 || exit /b 1 ) if "%VSCMD_ARG_TGT_ARCH%" neq "x64" ( @@ -19,16 +19,27 @@ if "%VSCMD_ARG_TGT_ARCH%" neq "x64" ( ) ) +where /Q git.exe || goto skip_git_hash +if not exist .git\ goto skip_git_hash +for /f "tokens=1,2" %%i IN ('git show "--pretty=%%cd %%h" "--date=format:%%Y-%%m-%%d" --no-patch --no-notes HEAD') do ( + set CURR_DATE_TIME=%%i + set GIT_SHA=%%j +) +if %ERRORLEVEL% equ 0 ( + goto have_git_hash_and_date +) +:skip_git_hash pushd misc cl /nologo get-date.c -popd - -for /f %%i in ('misc\get-date') do ( +for /f %%i in ('get-date') do ( set CURR_DATE_TIME=%%i + rem Don't set GIT_SHA ) +popd +:have_git_hash_and_date set curr_year=%CURR_DATE_TIME:~0,4% -set curr_month=%CURR_DATE_TIME:~4,2% -set curr_day=%CURR_DATE_TIME:~6,2% +set curr_month=%CURR_DATE_TIME:~5,2% +set curr_day=%CURR_DATE_TIME:~8,2% :: Make sure this is a decent name and not generic set exe_name=odin.exe @@ -61,31 +72,14 @@ if %release_mode% equ 0 ( set V4=0 set odin_version_full="%V1%.%V2%.%V3%.%V4%" set odin_version_raw="dev-%V1%-%V2%" - set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF rem Parse source code as utf-8 even on shift-jis and other codepages rem See https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170 set compiler_flags= %compiler_flags% /utf-8 -set compiler_defines= -DODIN_VERSION_RAW=\"%odin_version_raw%\" +set compiler_defines= -DODIN_VERSION_RAW=\"%odin_version_raw%\" -DGIT_SHA=\"%GIT_SHA%\" rem fileversion is defined as {Major,Minor,Build,Private: u16} so a bit limited -set rc_flags=-nologo ^ --DV1=%V1% -DV2=%V2% -DV3=%V3% -DV4=%V4% ^ --DVF=%odin_version_full% -DNIGHTLY=%nightly% - -where /Q git.exe || goto skip_git_hash -if not exist .git\ goto skip_git_hash -for /f "tokens=1,2" %%i IN ('git show "--pretty=%%cd %%h" "--date=format:%%Y-%%m" --no-patch --no-notes HEAD') do ( - set odin_version_raw=dev-%%i - set GIT_SHA=%%j -) -if %ERRORLEVEL% equ 0 ( - set compiler_defines=%compiler_defines% -DGIT_SHA=\"%GIT_SHA%\" - set rc_flags=%rc_flags% -DGIT_SHA=%GIT_SHA% -DVP=%odin_version_raw%:%GIT_SHA% -) else ( - set rc_flags=%rc_flags% -DVP=%odin_version_raw% -) -:skip_git_hash +set rc_flags="-DGIT_SHA=%GIT_SHA% -DVP=dev-%V1%-%V2%:%GIT_SHA% nologo -DV1=%V1% -DV2=%V2% -DV3=%V3% -DV4=%V4% -DVF=%odin_version_full% -DNIGHTLY=%nightly%" if %nightly% equ 1 set compiler_defines=%compiler_defines% -DNIGHTLY @@ -138,6 +132,7 @@ del *.ilk > NUL 2> NUL rc %rc_flags% %odin_rc% cl %compiler_settings% "src\main.cpp" "src\libtommath.cpp" /link %linker_settings% -OUT:%exe_name% +if %errorlevel% neq 0 goto end_of_build mt -nologo -inputresource:%exe_name%;#1 -manifest misc\odin.manifest -outputresource:%exe_name%;#1 -validate_manifest -identity:"odin, processorArchitecture=amd64, version=%odin_version_full%, type=win32" if %errorlevel% neq 0 goto end_of_build diff --git a/build_odin.sh b/build_odin.sh index c7d5c9288..0d7e8a26e 100755 --- a/build_odin.sh +++ b/build_odin.sh @@ -6,7 +6,6 @@ set -eu : ${LDFLAGS=} : ${LLVM_CONFIG=} -CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\"" CXXFLAGS="$CXXFLAGS -std=c++14" DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value" LDFLAGS="$LDFLAGS -pthread -lm" @@ -15,8 +14,12 @@ OS_NAME="$(uname -s)" if [ -d ".git" ] && [ -n "$(command -v git)" ]; then GIT_SHA=$(git show --pretty='%h' --no-patch --no-notes HEAD) + GIT_DATE=$(git show "--pretty=%cd" "--date=format:%Y-%m" --no-patch --no-notes HEAD) CPPFLAGS="$CPPFLAGS -DGIT_SHA=\"$GIT_SHA\"" +else + GIT_DATE=$(date +"%Y-%m") fi +CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"dev-$GIT_DATE\"" error() { printf "ERROR: %s\n" "$1" @@ -25,7 +28,8 @@ error() { # Brew advises people not to add llvm to their $PATH, so try and use brew to find it. if [ -z "$LLVM_CONFIG" ] && [ -n "$(command -v brew)" ]; then - if [ -n "$(command -v $(brew --prefix llvm@19)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@19)/bin/llvm-config" + if [ -n "$(command -v $(brew --prefix llvm@20)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@20)/bin/llvm-config" + elif [ -n "$(command -v $(brew --prefix llvm@19)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@19)/bin/llvm-config" elif [ -n "$(command -v $(brew --prefix llvm@18)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@18)/bin/llvm-config" elif [ -n "$(command -v $(brew --prefix llvm@17)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@17)/bin/llvm-config" elif [ -n "$(command -v $(brew --prefix llvm@14)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@14)/bin/llvm-config" @@ -34,7 +38,8 @@ fi if [ -z "$LLVM_CONFIG" ]; then # darwin, linux, openbsd - if [ -n "$(command -v llvm-config-19)" ]; then LLVM_CONFIG="llvm-config-19" + if [ -n "$(command -v llvm-config-20)" ]; then LLVM_CONFIG="llvm-config-20" + elif [ -n "$(command -v llvm-config-19)" ]; then LLVM_CONFIG="llvm-config-19" elif [ -n "$(command -v llvm-config-18)" ]; then LLVM_CONFIG="llvm-config-18" elif [ -n "$(command -v llvm-config-17)" ]; then LLVM_CONFIG="llvm-config-17" elif [ -n "$(command -v llvm-config-14)" ]; then LLVM_CONFIG="llvm-config-14" @@ -42,6 +47,7 @@ if [ -z "$LLVM_CONFIG" ]; then elif [ -n "$(command -v llvm-config-12)" ]; then LLVM_CONFIG="llvm-config-12" elif [ -n "$(command -v llvm-config-11)" ]; then LLVM_CONFIG="llvm-config-11" # freebsd + elif [ -n "$(command -v llvm-config20)" ]; then LLVM_CONFIG="llvm-config20" elif [ -n "$(command -v llvm-config19)" ]; then LLVM_CONFIG="llvm-config19" elif [ -n "$(command -v llvm-config18)" ]; then LLVM_CONFIG="llvm-config18" elif [ -n "$(command -v llvm-config17)" ]; then LLVM_CONFIG="llvm-config17" @@ -69,15 +75,15 @@ LLVM_VERSION_MAJOR="$(echo $LLVM_VERSION | awk -F. '{print $1}')" LLVM_VERSION_MINOR="$(echo $LLVM_VERSION | awk -F. '{print $2}')" LLVM_VERSION_PATCH="$(echo $LLVM_VERSION | awk -F. '{print $3}')" -if [ $LLVM_VERSION_MAJOR -lt 11 ] || ([ $LLVM_VERSION_MAJOR -gt 14 ] && [ $LLVM_VERSION_MAJOR -lt 17 ]) || [ $LLVM_VERSION_MAJOR -gt 19 ]; then - error "Invalid LLVM version $LLVM_VERSION: must be 11, 12, 13, 14, 17, 18 or 19" +if [ $LLVM_VERSION_MAJOR -lt 11 ] || ([ $LLVM_VERSION_MAJOR -gt 14 ] && [ $LLVM_VERSION_MAJOR -lt 17 ]) || [ $LLVM_VERSION_MAJOR -gt 20 ]; then + error "Invalid LLVM version $LLVM_VERSION: must be 11, 12, 13, 14, 17, 18, 19 or 20" fi case "$OS_NAME" in Darwin) if [ "$OS_ARCH" = "arm64" ]; then if [ $LLVM_VERSION_MAJOR -lt 13 ]; then - error "Invalid LLVM version $LLVM_VERSION: Darwin Arm64 requires LLVM 13, 14, 17, 18 or 19" + error "Invalid LLVM version $LLVM_VERSION: Darwin Arm64 requires LLVM 13, 14, 17, 18, 19 or 20" fi fi diff --git a/check_all.bat b/check_all.bat new file mode 100644 index 000000000..c5f7ee399 --- /dev/null +++ b/check_all.bat @@ -0,0 +1,75 @@ +@echo off + +if "%1" == "" ( + echo Checking darwin_amd64 - expect vendor:cgltf panic + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:darwin_amd64 + echo Checking darwin_arm64 - expect vendor:cgltf panic + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:darwin_arm64 + echo Checking linux_i386 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_i386 + echo Checking linux_amd64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_amd64 + echo Checking linux_arm64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_arm64 + echo Checking linux_arm32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_arm32 + echo Checking linux_riscv64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_riscv64 + echo Checking windows_i386 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:windows_i386 + echo Checking windows_amd64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:windows_amd64 + echo Checking freebsd_amd64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_amd64 + echo Checking freebsd_arm64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_arm64 + echo Checking netbsd_amd64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:netbsd_amd64 + echo Checking netbsd_arm64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:netbsd_arm64 + echo Checking openbsd_amd64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:openbsd_amd64 +) + +if "%1" == "freestanding" ( + echo Checking freestanding_wasm32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_wasm32 + echo Checking freestanding_wasm64p32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_wasm64p32 + echo Checking freestanding_amd64_sysv + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_amd64_sysv + echo Checking freestanding_amd64_win64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_amd64_win64 + echo Checking freestanding_arm64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_arm64 + echo Checking freestanding_arm32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_arm32 + echo Checking freestanding_riscv64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_riscv64 +) + +if "%1" == "rare" ( + echo Checking essence_amd64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:essence_amd64 + echo Checking freebsd_i386 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_i386 + echo Checking haiku_amd64 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:haiku_amd64 +) + +if "%1" == "wasm" ( + echo Checking freestanding_wasm32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_wasm32 + echo Checking freestanding_wasm64p32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_wasm64p32 + echo Checking wasi_wasm64p32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:wasi_wasm64p32 + echo Checking wasi_wasm32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:wasi_wasm32 + echo Checking js_wasm32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:js_wasm32 + echo Checking orca_wasm32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:orca_wasm32 + echo Checking js_wasm64p32 + odin check examples\all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:js_wasm64p32 +) \ No newline at end of file diff --git a/check_all.sh b/check_all.sh new file mode 100755 index 000000000..568ac55ba --- /dev/null +++ b/check_all.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +case $1 in +freestanding) + echo Checking freestanding_wasm32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_wasm32 + echo Checking freestanding_wasm64p32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_wasm64p32 + echo Checking freestanding_amd64_sysv + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_amd64_sysv + echo Checking freestanding_amd64_win64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_amd64_win64 + echo Checking freestanding_arm64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_arm64 + echo Checking freestanding_arm32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_arm32 + echo Checking freestanding_riscv64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_riscv64 + ;; + +rare) + echo Checking essence_amd64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:essence_amd64 + echo Checking freebsd_i386 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_i386 + echo Checking haiku_amd64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:haiku_amd64 + ;; + +wasm) + echo Checking freestanding_wasm32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_wasm32 + echo Checking freestanding_wasm64p32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freestanding_wasm64p32 + echo Checking wasi_wasm64p32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:wasi_wasm64p32 + echo Checking wasi_wasm32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:wasi_wasm32 + echo Checking js_wasm32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:js_wasm32 + echo Checking orca_wasm32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:orca_wasm32 + echo Checking js_wasm64p32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:js_wasm64p32 + ;; + +*) + echo Checking darwin_amd64 - expect vendor:cgltf panic + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:darwin_amd64 + echo Checking darwin_arm64 - expect vendor:cgltf panic + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:darwin_arm64 + echo Checking linux_i386 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_i386 + echo Checking linux_amd64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_amd64 + echo Checking linux_arm64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_arm64 + echo Checking linux_arm32 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_arm32 + echo Checking linux_riscv64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:linux_riscv64 + echo Checking windows_i386 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:windows_i386 + echo Checking windows_amd64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:windows_amd64 + echo Checking freebsd_amd64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_amd64 + echo Checking freebsd_arm64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:freebsd_arm64 + echo Checking netbsd_amd64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:netbsd_amd64 + echo Checking netbsd_arm64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:netbsd_arm64 + echo Checking openbsd_amd64 + odin check examples/all -vet -vet-tabs -strict-style -vet-style -warnings-as-errors -disallow-do -target:openbsd_amd64 + ;; + +esac \ No newline at end of file diff --git a/ci/build_linux_static.sh b/ci/build_linux_static.sh index f821cbb59..2eb99116e 100755 --- a/ci/build_linux_static.sh +++ b/ci/build_linux_static.sh @@ -1,8 +1,8 @@ #!/usr/bin/env sh # Intended for use in Alpine containers, see the "nightly" Github action for a list of dependencies -CXX="clang++-18" -LLVM_CONFIG="llvm-config-18" +CXX="clang++-20" +LLVM_CONFIG="llvm-config-20" DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value" diff --git a/ci/remove_windows_binaries.sh b/ci/remove_windows_binaries.sh new file mode 100755 index 000000000..0722fc455 --- /dev/null +++ b/ci/remove_windows_binaries.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env sh + +find "$1" -type f \(\ + -iname "*.exe" \ + -o -iname "*.dll" \ + -o -iname "*.lib" \ + -o -iname "*.pdb" \ + \) -delete diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..da629b510 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,6 @@ +comment: false +coverage: + status: + project: + default: + threshold: 1% \ No newline at end of file diff --git a/core/bufio/reader.odin b/core/bufio/reader.odin index a875c732d..b78cac6e1 100644 --- a/core/bufio/reader.odin +++ b/core/bufio/reader.odin @@ -257,7 +257,7 @@ reader_read_rune :: proc(b: ^Reader) -> (r: rune, size: int, err: io.Error) { for b.r+utf8.UTF_MAX > b.w && !utf8.full_rune(b.buf[b.r:b.w]) && b.err == nil && - b.w-b.w < len(b.buf) { + b.w-b.r < len(b.buf) { _reader_read_new_chunk(b) or_return } diff --git a/core/bytes/bytes.odin b/core/bytes/bytes.odin index c0d25bcce..71b6ef70c 100644 --- a/core/bytes/bytes.odin +++ b/core/bytes/bytes.odin @@ -350,7 +350,7 @@ index_byte :: proc "contextless" (s: []byte, c: byte) -> (index: int) #no_bounds } c_vec: simd.u8x16 = c - when !simd.IS_EMULATED { + when simd.HAS_HARDWARE_SIMD { // Note: While this is something that could also logically take // advantage of AVX512, the various downclocking and power // consumption related woes make premature to have a dedicated @@ -485,7 +485,7 @@ last_index_byte :: proc "contextless" (s: []byte, c: byte) -> int #no_bounds_che } c_vec: simd.u8x16 = c - when !simd.IS_EMULATED { + when simd.HAS_HARDWARE_SIMD { // Note: While this is something that could also logically take // advantage of AVX512, the various downclocking and power // consumption related woes make premature to have a dedicated diff --git a/core/c/libc/complex.odin b/core/c/libc/complex.odin index 98fd7b1bb..7b6ac6417 100644 --- a/core/c/libc/complex.odin +++ b/core/c/libc/complex.odin @@ -5,7 +5,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/ctype.odin b/core/c/libc/ctype.odin index 185385a5e..d156f1ed7 100644 --- a/core/c/libc/ctype.odin +++ b/core/c/libc/ctype.odin @@ -3,7 +3,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/errno.odin b/core/c/libc/errno.odin index 5d1ca8248..138d70a80 100644 --- a/core/c/libc/errno.odin +++ b/core/c/libc/errno.odin @@ -5,7 +5,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/locale.odin b/core/c/libc/locale.odin index d95f5c164..3216e0f90 100644 --- a/core/c/libc/locale.odin +++ b/core/c/libc/locale.odin @@ -5,7 +5,7 @@ import "core:c" when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } @@ -72,14 +72,14 @@ when ODIN_OS == .Windows { n_sep_by_space: c.char, p_sign_posn: c.char, n_sign_posn: c.char, - _W_decimal_point: [^]u16 `fmt:"s,0"`, - _W_thousands_sep: [^]u16 `fmt:"s,0"`, - _W_int_curr_symbol: [^]u16 `fmt:"s,0"`, - _W_currency_symbol: [^]u16 `fmt:"s,0"`, - _W_mon_decimal_point: [^]u16 `fmt:"s,0"`, - _W_mon_thousands_sep: [^]u16 `fmt:"s,0"`, - _W_positive_sign: [^]u16 `fmt:"s,0"`, - _W_negative_sign: [^]u16 `fmt:"s,0"`, + _W_decimal_point: cstring16, + _W_thousands_sep: cstring16, + _W_int_curr_symbol: cstring16, + _W_currency_symbol: cstring16, + _W_mon_decimal_point: cstring16, + _W_mon_thousands_sep: cstring16, + _W_positive_sign: cstring16, + _W_negative_sign: cstring16, } } else { lconv :: struct { diff --git a/core/c/libc/math.odin b/core/c/libc/math.odin index 81d51728d..d0a015c70 100644 --- a/core/c/libc/math.odin +++ b/core/c/libc/math.odin @@ -7,7 +7,7 @@ import "base:intrinsics" when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/setjmp.odin b/core/c/libc/setjmp.odin index 101b614b3..4f5319316 100644 --- a/core/c/libc/setjmp.odin +++ b/core/c/libc/setjmp.odin @@ -5,7 +5,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/signal.odin b/core/c/libc/signal.odin index c447e3cc3..cddf06916 100644 --- a/core/c/libc/signal.odin +++ b/core/c/libc/signal.odin @@ -5,7 +5,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin index 56e4e8f66..aa92e4a6b 100644 --- a/core/c/libc/stdio.odin +++ b/core/c/libc/stdio.odin @@ -9,7 +9,7 @@ when ODIN_OS == .Windows { "system:legacy_stdio_definitions.lib", } } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } @@ -275,7 +275,7 @@ foreign libc { // 7.21.7 Character input/output functions fgetc :: proc(stream: ^FILE) -> int --- fgets :: proc(s: [^]char, n: int, stream: ^FILE) -> [^]char --- - fputc :: proc(s: cstring, stream: ^FILE) -> int --- + fputc :: proc(s: c.int, stream: ^FILE) -> int --- getc :: proc(stream: ^FILE) -> int --- getchar :: proc() -> int --- putc :: proc(c: int, stream: ^FILE) -> int --- diff --git a/core/c/libc/stdlib.odin b/core/c/libc/stdlib.odin index c0e273872..ca906a5f0 100644 --- a/core/c/libc/stdlib.odin +++ b/core/c/libc/stdlib.odin @@ -5,7 +5,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/string.odin b/core/c/libc/string.odin index 4ec4f3a7a..2ea54579c 100644 --- a/core/c/libc/string.odin +++ b/core/c/libc/string.odin @@ -7,7 +7,7 @@ import "base:runtime" when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/time.odin b/core/c/libc/time.odin index 33f8dc3af..6106923f5 100644 --- a/core/c/libc/time.odin +++ b/core/c/libc/time.odin @@ -5,7 +5,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/uchar.odin b/core/c/libc/uchar.odin index a10969ceb..997b99b46 100644 --- a/core/c/libc/uchar.odin +++ b/core/c/libc/uchar.odin @@ -5,7 +5,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/wchar.odin b/core/c/libc/wchar.odin index f0dae720e..248611409 100644 --- a/core/c/libc/wchar.odin +++ b/core/c/libc/wchar.odin @@ -5,7 +5,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/c/libc/wctype.odin b/core/c/libc/wctype.odin index b96410b4c..6526a14e2 100644 --- a/core/c/libc/wctype.odin +++ b/core/c/libc/wctype.odin @@ -5,7 +5,7 @@ package libc when ODIN_OS == .Windows { foreign import libc "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/compress/common.odin b/core/compress/common.odin index 242538e78..f4429b667 100644 --- a/core/compress/common.odin +++ b/core/compress/common.odin @@ -139,9 +139,6 @@ Context_Memory_Input :: struct #packed { } when size_of(rawptr) == 8 { #assert(size_of(Context_Memory_Input) == 64) -} else { - // e.g. `-target:windows_i386` - #assert(size_of(Context_Memory_Input) == 52) } Context_Stream_Input :: struct #packed { diff --git a/core/container/intrusive/list/intrusive_list.odin b/core/container/intrusive/list/intrusive_list.odin index 5b29efb22..1e116ef18 100644 --- a/core/container/intrusive/list/intrusive_list.odin +++ b/core/container/intrusive/list/intrusive_list.odin @@ -278,19 +278,19 @@ Example: iterate_next_example :: proc() { l: list.List - one := My_Struct{value=1} - two := My_Struct{value=2} + one := My_Next_Struct{value=1} + two := My_Next_Struct{value=2} list.push_back(&l, &one.node) list.push_back(&l, &two.node) - it := list.iterator_head(l, My_Struct, "node") + it := list.iterator_head(l, My_Next_Struct, "node") for num in list.iterate_next(&it) { fmt.println(num.value) } } - My_Struct :: struct { + My_Next_Struct :: struct { node : list.Node, value: int, } @@ -325,22 +325,22 @@ Example: import "core:fmt" import "core:container/intrusive/list" - iterate_next_example :: proc() { + iterate_prev_example :: proc() { l: list.List - one := My_Struct{value=1} - two := My_Struct{value=2} + one := My_Prev_Struct{value=1} + two := My_Prev_Struct{value=2} list.push_back(&l, &one.node) list.push_back(&l, &two.node) - it := list.iterator_tail(l, My_Struct, "node") + it := list.iterator_tail(l, My_Prev_Struct, "node") for num in list.iterate_prev(&it) { fmt.println(num.value) } } - My_Struct :: struct { + My_Prev_Struct :: struct { node : list.Node, value: int, } diff --git a/core/container/lru/lru_cache.odin b/core/container/lru/lru_cache.odin index f8aa55dc2..d95e8e1d2 100644 --- a/core/container/lru/lru_cache.odin +++ b/core/container/lru/lru_cache.odin @@ -129,7 +129,7 @@ remove :: proc(c: ^$C/Cache($Key, $Value), key: Key) -> bool { return false } _remove_node(c, e) - free(node, c.node_allocator) + free(e, c.node_allocator) c.count -= 1 return true } diff --git a/core/container/priority_queue/priority_queue.odin b/core/container/priority_queue/priority_queue.odin index 8a6d77288..c62a821f4 100644 --- a/core/container/priority_queue/priority_queue.odin +++ b/core/container/priority_queue/priority_queue.odin @@ -1,6 +1,7 @@ package container_priority_queue import "base:builtin" +import "base:runtime" Priority_Queue :: struct($T: typeid) { queue: [dynamic]T, @@ -17,13 +18,14 @@ default_swap_proc :: proc($T: typeid) -> proc(q: []T, i, j: int) { } } -init :: proc(pq: ^$Q/Priority_Queue($T), less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int), capacity := DEFAULT_CAPACITY, allocator := context.allocator) { +init :: proc(pq: ^$Q/Priority_Queue($T), less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> (err: runtime.Allocator_Error) { if pq.queue.allocator.procedure == nil { pq.queue.allocator = allocator } - reserve(pq, capacity) + reserve(pq, capacity) or_return pq.less = less pq.swap = swap + return .None } init_from_dynamic_array :: proc(pq: ^$Q/Priority_Queue($T), queue: [dynamic]T, less: proc(a, b: T) -> bool, swap: proc(q: []T, i, j: int)) { @@ -41,8 +43,8 @@ destroy :: proc(pq: ^$Q/Priority_Queue($T)) { delete(pq.queue) } -reserve :: proc(pq: ^$Q/Priority_Queue($T), capacity: int) { - builtin.reserve(&pq.queue, capacity) +reserve :: proc(pq: ^$Q/Priority_Queue($T), capacity: int) -> (err: runtime.Allocator_Error) { + return builtin.reserve(&pq.queue, capacity) } clear :: proc(pq: ^$Q/Priority_Queue($T)) { builtin.clear(&pq.queue) @@ -103,9 +105,10 @@ fix :: proc(pq: ^$Q/Priority_Queue($T), i: int) { } } -push :: proc(pq: ^$Q/Priority_Queue($T), value: T) { - append(&pq.queue, value) +push :: proc(pq: ^$Q/Priority_Queue($T), value: T) -> (err: runtime.Allocator_Error) { + append(&pq.queue, value) or_return _shift_up(pq, builtin.len(pq.queue)-1) + return .None } pop :: proc(pq: ^$Q/Priority_Queue($T), loc := #caller_location) -> (value: T) { @@ -130,12 +133,10 @@ pop_safe :: proc(pq: ^$Q/Priority_Queue($T), loc := #caller_location) -> (value: remove :: proc(pq: ^$Q/Priority_Queue($T), i: int) -> (value: T, ok: bool) { n := builtin.len(pq.queue) if 0 <= i && i < n { - if n != i { - pq.swap(pq.queue[:], i, n) - _shift_down(pq, i, n) - _shift_up(pq, i) - } - value, ok = builtin.pop_safe(&pq.queue) + pq.swap(pq.queue[:], i, n-1) + _shift_down(pq, i, n-1) + _shift_up(pq, i) + value, ok = builtin.pop(&pq.queue), true } return } diff --git a/core/container/queue/queue.odin b/core/container/queue/queue.odin index d1040a7c9..8de8d55c0 100644 --- a/core/container/queue/queue.odin +++ b/core/container/queue/queue.odin @@ -4,7 +4,13 @@ import "base:builtin" import "base:runtime" _ :: runtime -// Dynamically resizable double-ended queue/ring-buffer +/* +`Queue` is a dynamically resizable double-ended queue/ring-buffer. + +Being double-ended means that either end may be pushed onto or popped from +across the same block of memory, in any order, thus providing both stack and +queue-like behaviors in the same data structure. +*/ Queue :: struct($T: typeid) { data: [dynamic]T, len: uint, @@ -13,18 +19,31 @@ Queue :: struct($T: typeid) { DEFAULT_CAPACITY :: 16 -// Procedure to initialize a queue -init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator) -> runtime.Allocator_Error { - if q.data.allocator.procedure == nil { - q.data.allocator = allocator - } +/* +Initialize a `Queue` with a starting `capacity` and an `allocator`. +*/ +init :: proc(q: ^$Q/Queue($T), capacity := DEFAULT_CAPACITY, allocator := context.allocator, loc := #caller_location) -> runtime.Allocator_Error { clear(q) - return reserve(q, capacity) + q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{ + data = nil, + len = 0, + cap = 0, + allocator = allocator, + } + return reserve(q, capacity, loc) } -// Procedure to initialize a queue from a fixed backing slice. -// The contents of the `backing` will be overwritten as items are pushed onto the `Queue`. -// Any previous contents are not available. +/* +Initialize a `Queue` from a fixed `backing` slice into which modifications are +made directly. + +The contents of the `backing` will be overwritten as items are pushed onto the +`Queue`. Any previous contents will not be available through the API but are +not explicitly zeroed either. + +Note that procedures which need space to work (`push_back`, ...) will fail if +the backing slice runs out of space. +*/ init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool { clear(q) q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{ @@ -36,8 +55,14 @@ init_from_slice :: proc(q: ^$Q/Queue($T), backing: []T) -> bool { return true } -// Procedure to initialize a queue from a fixed backing slice. -// Existing contents are preserved and available on the queue. +/* +Initialize a `Queue` from a fixed `backing` slice into which modifications are +made directly. + +The contents of the queue will start out with all of the elements in `backing`, +effectively creating a full queue from the slice. As such, no procedures will +be able to add more elements to the queue until some are taken off. +*/ init_with_contents :: proc(q: ^$Q/Queue($T), backing: []T) -> bool { clear(q) q.data = transmute([dynamic]T)runtime.Raw_Dynamic_Array{ @@ -50,87 +75,203 @@ init_with_contents :: proc(q: ^$Q/Queue($T), backing: []T) -> bool { return true } -// Procedure to destroy a queue +/* +Delete memory that has been dynamically allocated from a `Queue` that was setup with `init`. + +Note that this procedure should not be used on queues setup with +`init_from_slice` or `init_with_contents`, as neither of those procedures keep +track of the allocator state of the underlying `backing` slice. +*/ destroy :: proc(q: ^$Q/Queue($T)) { delete(q.data) } -// The length of the queue +/* +Return the length of the queue. +*/ len :: proc(q: $Q/Queue($T)) -> int { return int(q.len) } -// The current capacity of the queue +/* +Return the capacity of the queue. +*/ cap :: proc(q: $Q/Queue($T)) -> int { return builtin.len(q.data) } -// Remaining space in the queue (cap-len) +/* +Return the remaining space in the queue. + +This will be `cap() - len()`. +*/ space :: proc(q: $Q/Queue($T)) -> int { return builtin.len(q.data) - int(q.len) } -// Reserve enough space for at least the specified capacity -reserve :: proc(q: ^$Q/Queue($T), capacity: int) -> runtime.Allocator_Error { +/* +Reserve enough space in the queue for at least the specified capacity. + +This may return an error if allocation failed. +*/ +reserve :: proc(q: ^$Q/Queue($T), capacity: int, loc := #caller_location) -> runtime.Allocator_Error { if capacity > space(q^) { - return _grow(q, uint(capacity)) + return _grow(q, uint(capacity), loc) } return nil } +/* +Shrink a queue's dynamically allocated array. +This has no effect if the queue was initialized with a backing slice. +*/ +shrink :: proc(q: ^$Q/Queue($T), temp_allocator := context.temp_allocator, loc := #caller_location) { + if q.data.allocator.procedure == runtime.nil_allocator_proc { + return + } + + if q.len > 0 && q.offset > 0 { + // Make the array contiguous again. + buffer := make([]T, q.len, temp_allocator) + defer delete(buffer, temp_allocator) + + right := uint(builtin.len(q.data)) - q.offset + copy(buffer[:], q.data[q.offset:]) + copy(buffer[right:], q.data[:q.offset]) + + copy(q.data[:], buffer[:]) + + q.offset = 0 + } + + builtin.shrink(&q.data, q.len, loc) +} + +/* +Get the element at index `i`. + +This will raise a bounds checking error if `i` is an invalid index. +*/ get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T { - runtime.bounds_check_error_loc(loc, i, builtin.len(q.data)) + runtime.bounds_check_error_loc(loc, i, int(q.len)) idx := (uint(i)+q.offset)%builtin.len(q.data) return q.data[idx] } -front :: proc(q: ^$Q/Queue($T)) -> T { - return q.data[q.offset] -} -front_ptr :: proc(q: ^$Q/Queue($T)) -> ^T { - return &q.data[q.offset] -} +/* +Get a pointer to the element at index `i`. -back :: proc(q: ^$Q/Queue($T)) -> T { - idx := (q.offset+uint(q.len - 1))%builtin.len(q.data) - return q.data[idx] -} -back_ptr :: proc(q: ^$Q/Queue($T)) -> ^T { - idx := (q.offset+uint(q.len - 1))%builtin.len(q.data) +This will raise a bounds checking error if `i` is an invalid index. +*/ +get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^T { + runtime.bounds_check_error_loc(loc, i, int(q.len)) + + idx := (uint(i)+q.offset)%builtin.len(q.data) return &q.data[idx] } +/* +Set the element at index `i` to `val`. + +This will raise a bounds checking error if `i` is an invalid index. +*/ set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) { - runtime.bounds_check_error_loc(loc, i, builtin.len(q.data)) - + runtime.bounds_check_error_loc(loc, i, int(q.len)) + idx := (uint(i)+q.offset)%builtin.len(q.data) q.data[idx] = val } -get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^T { - runtime.bounds_check_error_loc(loc, i, builtin.len(q.data)) - - idx := (uint(i)+q.offset)%builtin.len(q.data) + +/* +Get the element at the front of the queue. + +This will raise a bounds checking error if the queue is empty. +*/ +front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> T { + when !ODIN_NO_BOUNDS_CHECK { + ensure(q.len > 0, "Queue is empty.", loc) + } + return q.data[q.offset] +} + +/* +Get a pointer to the element at the front of the queue. + +This will raise a bounds checking error if the queue is empty. +*/ +front_ptr :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T { + when !ODIN_NO_BOUNDS_CHECK { + ensure(q.len > 0, "Queue is empty.", loc) + } + return &q.data[q.offset] +} + +/* +Get the element at the back of the queue. + +This will raise a bounds checking error if the queue is empty. +*/ +back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> T { + when !ODIN_NO_BOUNDS_CHECK { + ensure(q.len > 0, "Queue is empty.", loc) + } + idx := (q.offset+uint(q.len - 1))%builtin.len(q.data) + return q.data[idx] +} + +/* +Get a pointer to the element at the back of the queue. + +This will raise a bounds checking error if the queue is empty. +*/ +back_ptr :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T { + when !ODIN_NO_BOUNDS_CHECK { + ensure(q.len > 0, "Queue is empty.", loc) + } + idx := (q.offset+uint(q.len - 1))%builtin.len(q.data) return &q.data[idx] } + +@(deprecated="Use `front_ptr` instead") peek_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T { - runtime.bounds_check_error_loc(loc, 0, builtin.len(q.data)) - idx := q.offset%builtin.len(q.data) - return &q.data[idx] + return front_ptr(q, loc) } +@(deprecated="Use `back_ptr` instead") peek_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T { - runtime.bounds_check_error_loc(loc, int(q.len - 1), builtin.len(q.data)) - idx := (uint(q.len - 1)+q.offset)%builtin.len(q.data) - return &q.data[idx] + return back_ptr(q, loc) } -// Push an element to the back of the queue -push_back :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) { +/* +Push an element to the back of the queue. + +If there is no more space left and allocation fails to get more, this will +return false with an `Allocator_Error`. + +Example: + + import "base:runtime" + import "core:container/queue" + + // This demonstrates typical queue behavior (First-In First-Out). + main :: proc() { + q: queue.Queue(int) + queue.init(&q) + queue.push_back(&q, 1) + queue.push_back(&q, 2) + queue.push_back(&q, 3) + // q.data is now [1, 2, 3, ...] + assert(queue.pop_front(&q) == 1) + assert(queue.pop_front(&q) == 2) + assert(queue.pop_front(&q) == 3) + } +*/ +push_back :: proc(q: ^$Q/Queue($T), elem: T, loc := #caller_location) -> (ok: bool, err: runtime.Allocator_Error) { if space(q^) == 0 { - _grow(q) or_return + _grow(q, loc = loc) or_return } idx := (q.offset+uint(q.len))%builtin.len(q.data) q.data[idx] = elem @@ -138,27 +279,78 @@ push_back :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocato return true, nil } -// Push an element to the front of the queue -push_front :: proc(q: ^$Q/Queue($T), elem: T) -> (ok: bool, err: runtime.Allocator_Error) { +/* +Push an element to the front of the queue. + +If there is no more space left and allocation fails to get more, this will +return false with an `Allocator_Error`. + +Example: + + import "base:runtime" + import "core:container/queue" + + // This demonstrates stack behavior (First-In Last-Out). + main :: proc() { + q: queue.Queue(int) + queue.init(&q) + queue.push_back(&q, 1) + queue.push_back(&q, 2) + queue.push_back(&q, 3) + // q.data is now [1, 2, 3, ...] + assert(queue.pop_back(&q) == 3) + assert(queue.pop_back(&q) == 2) + assert(queue.pop_back(&q) == 1) + } +*/ +push_front :: proc(q: ^$Q/Queue($T), elem: T, loc := #caller_location) -> (ok: bool, err: runtime.Allocator_Error) { if space(q^) == 0 { - _grow(q) or_return - } + _grow(q, loc = loc) or_return + } q.offset = uint(q.offset - 1 + builtin.len(q.data)) % builtin.len(q.data) q.len += 1 q.data[q.offset] = elem return true, nil } +/* +Pop an element from the back of the queue. -// Pop an element from the back of the queue +This will raise a bounds checking error if the queue is empty. + +Example: + + import "base:runtime" + import "core:container/queue" + + // This demonstrates stack behavior (First-In Last-Out) at the far end of the data array. + main :: proc() { + q: queue.Queue(int) + queue.init(&q) + queue.push_front(&q, 1) + queue.push_front(&q, 2) + queue.push_front(&q, 3) + // q.data is now [..., 3, 2, 1] + log.infof("%#v", q) + assert(queue.pop_front(&q) == 3) + assert(queue.pop_front(&q) == 2) + assert(queue.pop_front(&q) == 1) + } +*/ pop_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) { - assert(condition=q.len > 0, loc=loc) + when !ODIN_NO_BOUNDS_CHECK { + ensure(q.len > 0, "Queue is empty.", loc) + } q.len -= 1 idx := (q.offset+uint(q.len))%builtin.len(q.data) elem = q.data[idx] return } -// Safely pop an element from the back of the queue + +/* +Pop an element from the back of the queue if one exists and return true. +Otherwise, return a nil element and false. +*/ pop_back_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) { if q.len > 0 { q.len -= 1 @@ -169,15 +361,25 @@ pop_back_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) { return } -// Pop an element from the front of the queue +/* +Pop an element from the front of the queue + +This will raise a bounds checking error if the queue is empty. +*/ pop_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> (elem: T) { - assert(condition=q.len > 0, loc=loc) + when !ODIN_NO_BOUNDS_CHECK { + ensure(q.len > 0, "Queue is empty.", loc) + } elem = q.data[q.offset] q.offset = (q.offset+1)%builtin.len(q.data) q.len -= 1 return } -// Safely pop an element from the front of the queue + +/* +Pop an element from the front of the queue if one exists and return true. +Otherwise, return a nil element and false. +*/ pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) { if q.len > 0 { elem = q.data[q.offset] @@ -188,13 +390,18 @@ pop_front_safe :: proc(q: ^$Q/Queue($T)) -> (elem: T, ok: bool) { return } -// Push multiple elements to the back of the queue -push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> (ok: bool, err: runtime.Allocator_Error) { +/* +Push many elements at once to the back of the queue. + +If there is not enough space left and allocation fails to get more, this will +return false with an `Allocator_Error`. +*/ +push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T, loc := #caller_location) -> (ok: bool, err: runtime.Allocator_Error) { n := uint(builtin.len(elems)) if space(q^) < int(n) { - _grow(q, q.len + n) or_return + _grow(q, q.len + n, loc) or_return } - + sz := uint(builtin.len(q.data)) insert_from := (q.offset + q.len) % sz insert_to := n @@ -207,19 +414,31 @@ push_back_elems :: proc(q: ^$Q/Queue($T), elems: ..T) -> (ok: bool, err: runtime return true, nil } -// Consume `n` elements from the front of the queue +/* +Consume `n` elements from the back of the queue. + +This will raise a bounds checking error if the queue does not have enough elements. +*/ consume_front :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) { - assert(condition=int(q.len) >= n, loc=loc) + when !ODIN_NO_BOUNDS_CHECK { + ensure(q.len >= uint(n), "Queue does not have enough elements to consume.", loc) + } if n > 0 { nu := uint(n) q.offset = (q.offset + nu) % builtin.len(q.data) - q.len -= nu + q.len -= nu } } -// Consume `n` elements from the back of the queue +/* +Consume `n` elements from the back of the queue. + +This will raise a bounds checking error if the queue does not have enough elements. +*/ consume_back :: proc(q: ^$Q/Queue($T), n: int, loc := #caller_location) { - assert(condition=int(q.len) >= n, loc=loc) + when !ODIN_NO_BOUNDS_CHECK { + ensure(q.len >= uint(n), "Queue does not have enough elements to consume.", loc) + } if n > 0 { q.len -= uint(n) } @@ -231,9 +450,14 @@ append_elem :: push_back append_elems :: push_back_elems push :: proc{push_back, push_back_elems} append :: proc{push_back, push_back_elems} +enqueue :: push_back +dequeue :: pop_front -// Clear the contents of the queue +/* +Reset the queue's length and offset to zero, letting it write new elements over +old memory, in effect clearing the accessible contents. +*/ clear :: proc(q: ^$Q/Queue($T)) { q.len = 0 q.offset = 0 @@ -241,10 +465,10 @@ clear :: proc(q: ^$Q/Queue($T)) { // Internal growing procedure -_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0) -> runtime.Allocator_Error { +_grow :: proc(q: ^$Q/Queue($T), min_capacity: uint = 0, loc := #caller_location) -> runtime.Allocator_Error { new_capacity := max(min_capacity, uint(8), uint(builtin.len(q.data))*2) n := uint(builtin.len(q.data)) - builtin.resize(&q.data, int(new_capacity)) or_return + builtin.resize(&q.data, int(new_capacity), loc) or_return if q.offset + q.len > n { diff := n - q.offset copy(q.data[new_capacity-diff:], q.data[q.offset:][:diff]) diff --git a/core/container/small_array/doc.odin b/core/container/small_array/doc.odin new file mode 100644 index 000000000..f3e9acd57 --- /dev/null +++ b/core/container/small_array/doc.odin @@ -0,0 +1,55 @@ +/* +Package small_array implements a dynamic array like +interface on a stack-allocated, fixed-size array. + +The Small_Array type is optimal for scenarios where you need +a container for a fixed number of elements of a specific type, +with the total number known at compile time but the exact +number to be used determined at runtime. + +Example: + import "core:fmt" + import "core:container/small_array" + + create :: proc() -> (result: small_array.Small_Array(10, rune)) { + // appending single elements + small_array.push(&result, 'e') + // pushing a bunch of elements at once + small_array.push(&result, 'l', 'i', 'x', '-', 'e') + // pre-pending + small_array.push_front(&result, 'H') + // removing elements + small_array.ordered_remove(&result, 4) + // resizing to the desired length (the capacity will stay unchanged) + small_array.resize(&result, 7) + // inserting elements + small_array.inject_at(&result, 'p', 5) + // updating elements + small_array.set(&result, 3, 'l') + // getting pointers to elements + o := small_array.get_ptr(&result, 4) + o^ = 'o' + // and much more .... + return + } + + // the Small_Array can be an ordinary parameter 'generic' over + // the actual length to be usable with different sizes + print_elements :: proc(arr: ^small_array.Small_Array($N, rune)) { + for r in small_array.slice(arr) { + fmt.print(r) + } + } + + main :: proc() { + arr := create() + // ... + print_elements(&arr) + } + +Output: + + Hellope + +*/ +package container_small_array diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin index 77bb21cbc..1d9795db8 100644 --- a/core/container/small_array/small_array.odin +++ b/core/container/small_array/small_array.odin @@ -1,62 +1,367 @@ package container_small_array import "base:builtin" -import "base:runtime" -_ :: runtime +@require import "base:intrinsics" +@require import "base:runtime" +/* +A fixed-size stack-allocated array operated on in a dynamic fashion. + +Fields: +- `data`: The underlying array +- `len`: Amount of items that the `Small_Array` currently holds + +Example: + + import "core:container/small_array" + + example :: proc() { + a: small_array.Small_Array(100, int) + small_array.push_back(&a, 10) + } +*/ Small_Array :: struct($N: int, $T: typeid) where N >= 0 { data: [N]T, len: int, } +/* +Returns the amount of items in the small-array. +**Inputs** +- `a`: The small-array + +**Returns** +- the amount of items in the array +*/ len :: proc "contextless" (a: $A/Small_Array) -> int { return a.len } +/* +Returns the capacity of the small-array. + +**Inputs** +- `a`: The small-array + +**Returns** the capacity +*/ cap :: proc "contextless" (a: $A/Small_Array) -> int { return builtin.len(a.data) } +/* +Returns how many more items the small-array could fit. + +**Inputs** +- `a`: The small-array + +**Returns** +- the number of unused slots +*/ space :: proc "contextless" (a: $A/Small_Array) -> int { return builtin.len(a.data) - a.len } +/* +Returns a slice of the data. + +**Inputs** +- `a`: The pointer to the small-array + +**Returns** +- the slice + +Example: + + import "core:container/small_array" + import "core:fmt" + + slice_example :: proc() { + print :: proc(a: ^small_array.Small_Array($N, int)) { + for item in small_array.slice(a) { + fmt.println(item) + } + } + + a: small_array.Small_Array(5, int) + small_array.push_back(&a, 1) + small_array.push_back(&a, 2) + print(&a) + } + +Output: + + 1 + 2 +*/ slice :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> []T { return a.data[:a.len] } +/* +Get a copy of the item at the specified position. +This operation assumes that the small-array is large enough. +This will result in: + - the value if 0 <= index < len + - the zero value of the type if len < index < capacity + - 'crash' if capacity < index or index < 0 + +**Inputs** +- `a`: The small-array +- `index`: The position of the item to get + +**Returns** +- the element at the specified position +*/ get :: proc "contextless" (a: $A/Small_Array($N, $T), index: int) -> T { return a.data[index] } + +/* +Get a pointer to the item at the specified position. +This operation assumes that the small-array is large enough. + +This will result in: + - the pointer if 0 <= index < len + - the pointer to the zero value if len < index < capacity + - 'crash' if capacity < index or index < 0 + +**Inputs** +- `a`: A pointer to the small-array +- `index`: The position of the item to get + +**Returns** +- the pointer to the element at the specified position +*/ get_ptr :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int) -> ^T { return &a.data[index] } -get_safe :: proc(a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check { +/* +Attempt to get a copy of the item at the specified position. + +**Inputs** +- `a`: The small-array +- `index`: The position of the item to get + +**Returns** +- the element at the specified position +- true if element exists, false otherwise + +Example: + + import "core:container/small_array" + import "core:fmt" + + get_safe_example :: proc() { + a: small_array.Small_Array(5, rune) + small_array.push_back(&a, 'A') + + fmt.println(small_array.get_safe(a, 0) or_else 'x') + fmt.println(small_array.get_safe(a, 1) or_else 'x') + } + +Output: + + A + x + +*/ +get_safe :: proc "contextless" (a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check { if index < 0 || index >= a.len { return {}, false } return a.data[index], true } -get_ptr_safe :: proc(a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check { +/* +Get a pointer to the item at the specified position. + +**Inputs** +- `a`: A pointer to the small-array +- `index`: The position of the item to get + +**Returns** +- the pointer to the element at the specified position +- true if element exists, false otherwise +*/ +get_ptr_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check { if index < 0 || index >= a.len { return {}, false } return &a.data[index], true } +/* +Set the element at the specified position to the given value. +This operation assumes that the small-array is large enough. + +This will result in: + - the value being set if 0 <= index < capacity + - 'crash' otherwise + +**Inputs** +- `a`: A pointer to the small-array +- `index`: The position of the item to set +- `value`: The value to set the element to + +Example: + + import "core:container/small_array" + import "core:fmt" + + set_example :: proc() { + a: small_array.Small_Array(5, rune) + small_array.push_back(&a, 'A') + small_array.push_back(&a, 'B') + fmt.println(small_array.slice(&a)) + + // updates index 0 + small_array.set(&a, 0, 'Z') + fmt.println(small_array.slice(&a)) + + // updates to a position x, where + // len <= x < cap are not visible since + // the length of the small-array remains unchanged + small_array.set(&a, 2, 'X') + small_array.set(&a, 3, 'Y') + small_array.set(&a, 4, 'Z') + fmt.println(small_array.slice(&a)) + + // resizing makes the change visible + small_array.non_zero_resize(&a, 100) + fmt.println(small_array.slice(&a)) + } + +Output: + + [A, B] + [Z, B] + [Z, B] + [Z, B, X, Y, Z] + +*/ set :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, item: T) { a.data[index] = item } -resize :: proc "contextless" (a: ^$A/Small_Array, length: int) { +/* +Tries to resize the small-array to the specified length. + +The memory of added elements will be zeroed out. + +The new length will be: + - `length` if `length` <= capacity + - capacity if length > capacity + +**Inputs** +- `a`: A pointer to the small-array +- `length`: The new desired length + +Example: + + import "core:container/small_array" + import "core:fmt" + + resize_example :: proc() { + a: small_array.Small_Array(5, int) + + small_array.push_back(&a, 1) + small_array.push_back(&a, 2) + fmt.println(small_array.slice(&a)) + + small_array.resize(&a, 1) + fmt.println(small_array.slice(&a)) + + small_array.resize(&a, 100) + fmt.println(small_array.slice(&a)) + } + +Output: + + [1, 2] + [1] + [1, 0, 0, 0, 0] +*/ +resize :: proc "contextless" (a: ^$A/Small_Array($N, $T), length: int) { + prev_len := a.len + a.len = min(length, builtin.len(a.data)) + if prev_len < a.len { + intrinsics.mem_zero(&a.data[prev_len], size_of(T)*(a.len-prev_len)) + } +} + +/* +Tries to resize the small-array to the specified length. + +The new length will be: + - `length` if `length` <= capacity + - capacity if length > capacity + +**Inputs** +- `a`: A pointer to the small-array +- `length`: The new desired length + +Example: + + import "core:container/small_array" + import "core:fmt" + + non_zero_resize :: proc() { + a: small_array.Small_Array(5, int) + + small_array.push_back(&a, 1) + small_array.push_back(&a, 2) + fmt.println(small_array.slice(&a)) + + small_array.non_zero_resize(&a, 1) + fmt.println(small_array.slice(&a)) + + small_array.non_zero_resize(&a, 100) + fmt.println(small_array.slice(&a)) + } + +Output: + + [1, 2] + [1] + [1, 2, 0, 0, 0] +*/ +non_zero_resize :: proc "contextless" (a: ^$A/Small_Array, length: int) { a.len = min(length, builtin.len(a.data)) } +/* +Attempts to add the given element to the end. +**Inputs** +- `a`: A pointer to the small-array +- `item`: The item to append + +**Returns** +- true if there was enough space to fit the element, false otherwise + +Example: + + import "core:container/small_array" + import "core:fmt" + + push_back_example :: proc() { + a: small_array.Small_Array(2, int) + + assert(small_array.push_back(&a, 1), "this should fit") + assert(small_array.push_back(&a, 2), "this should fit") + assert(!small_array.push_back(&a, 3), "this should not fit") + + fmt.println(small_array.slice(&a)) + } + +Output: + + [1, 2] +*/ push_back :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T) -> bool { if a.len < cap(a^) { a.data[a.len] = item @@ -66,6 +371,39 @@ push_back :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T) -> bool { return false } +/* +Attempts to add the given element at the beginning. +This operation assumes that the small-array is not empty. + +Note: Performing this operation will cause pointers obtained +through get_ptr(_save) to reference incorrect elements. + +**Inputs** +- `a`: A pointer to the small-array +- `item`: The item to append + +**Returns** +- true if there was enough space to fit the element, false otherwise + +Example: + + import "core:container/small_array" + import "core:fmt" + + push_front_example :: proc() { + a: small_array.Small_Array(2, int) + + assert(small_array.push_front(&a, 2), "this should fit") + assert(small_array.push_front(&a, 1), "this should fit") + assert(!small_array.push_back(&a, 0), "this should not fit") + + fmt.println(small_array.slice(&a)) + } + +Output: + + [1, 2] +*/ push_front :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T) -> bool { if a.len < cap(a^) { a.len += 1 @@ -77,6 +415,35 @@ push_front :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T) -> bool { return false } +/* +Removes and returns the last element of the small-array. +This operation assumes that the small-array is not empty. + +**Inputs** +- `a`: A pointer to the small-array + +**Returns** +- a copy of the element removed from the end of the small-array + +Example: + + import "core:container/small_array" + import "core:fmt" + + pop_back_example :: proc() { + a: small_array.Small_Array(5, int) + small_array.push(&a, 0, 1, 2) + + fmt.println("BEFORE:", small_array.slice(&a)) + small_array.pop_back(&a) + fmt.println("AFTER: ", small_array.slice(&a)) + } + +Output: + + BEFORE: [0, 1, 2] + AFTER: [0, 1] +*/ pop_back :: proc "odin" (a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T { assert(condition=(N > 0 && a.len > 0), loc=loc) item := a.data[a.len-1] @@ -84,6 +451,38 @@ pop_back :: proc "odin" (a: ^$A/Small_Array($N, $T), loc := #caller_location) -> return item } +/* +Removes and returns the first element of the small-array. +This operation assumes that the small-array is not empty. + +Note: Performing this operation will cause pointers obtained +through get_ptr(_save) to reference incorrect elements. + +**Inputs** +- `a`: A pointer to the small-array + +**Returns** +- a copy of the element removed from the beginning of the small-array + +Example: + + import "core:container/small_array" + import "core:fmt" + + pop_front_example :: proc() { + a: small_array.Small_Array(5, int) + small_array.push(&a, 0, 1, 2) + + fmt.println("BEFORE:", small_array.slice(&a)) + small_array.pop_front(&a) + fmt.println("AFTER: ", small_array.slice(&a)) + } + +Output: + + BEFORE: [0, 1, 2] + AFTER: [1, 2] +*/ pop_front :: proc "odin" (a: ^$A/Small_Array($N, $T), loc := #caller_location) -> T { assert(condition=(N > 0 && a.len > 0), loc=loc) item := a.data[0] @@ -93,6 +492,32 @@ pop_front :: proc "odin" (a: ^$A/Small_Array($N, $T), loc := #caller_location) - return item } +/* +Attempts to remove and return the last element of the small array. +Unlike `pop_back`, it does not assume that the array is non-empty. + +**Inputs** +- `a`: A pointer to the small-array + +**Returns** +- a copy of the element removed from the end of the small-array +- true if the small-array was not empty, false otherwise + +Example: + + import "core:container/small_array" + + pop_back_safe_example :: proc() { + a: small_array.Small_Array(3, int) + small_array.push(&a, 1) + + el, ok := small_array.pop_back_safe(&a) + assert(ok, "there was an element in the array") + + el, ok = small_array.pop_back_safe(&a) + assert(!ok, "there was NO element in the array") + } +*/ pop_back_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) { if N > 0 && a.len > 0 { item = a.data[a.len-1] @@ -102,6 +527,35 @@ pop_back_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> (item: T, ok return } +/* +Attempts to remove and return the first element of the small array. +Unlike `pop_front`, it does not assume that the array is non-empty. + +Note: Performing this operation will cause pointers obtained +through get_ptr(_save) to reference incorrect elements. + +**Inputs** +- `a`: A pointer to the small-array + +**Returns** +- a copy of the element removed from the beginning of the small-array +- true if the small-array was not empty, false otherwise + +Example: + + import "core:container/small_array" + + pop_front_safe_example :: proc() { + a: small_array.Small_Array(3, int) + small_array.push(&a, 1) + + el, ok := small_array.pop_front_safe(&a) + assert(ok, "there was an element in the array") + + el, ok = small_array.pop_front_(&a) + assert(!ok, "there was NO element in the array") + } +*/ pop_front_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> (item: T, ok: bool) { if N > 0 && a.len > 0 { item = a.data[0] @@ -113,11 +567,70 @@ pop_front_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> (item: T, o return } +/* +Decreases the length of the small-array by the given amount. +The elements are therefore not really removed and can be +recovered by calling `resize`. + +Note: This procedure assumes that the array has a sufficient length. + +**Inputs** +- `a`: A pointer to the small-array +- `count`: The amount the length should be reduced by + +Example: + + import "core:container/small_array" + import "core:fmt" + + consume_example :: proc() { + a: small_array.Small_Array(3, int) + small_array.push(&a, 0, 1, 2) + + fmt.println("BEFORE:", small_array.slice(&a)) + small_array.consume(&a, 2) + fmt.println("AFTER :", small_array.slice(&a)) + } + +Output: + + BEFORE: [0, 1, 2] + AFTER : [0] +*/ consume :: proc "odin" (a: ^$A/Small_Array($N, $T), count: int, loc := #caller_location) { assert(condition=a.len >= count, loc=loc) a.len -= count } +/* +Removes the element at the specified index while retaining order. + +Note: Performing this operation will cause pointers obtained +through get_ptr(_save) to reference incorrect elements. + +**Inputs** +- `a`: A pointer to the small-array +- `index`: The position of the element to remove + +Example: + + import "core:container/small_array" + import "core:fmt" + + ordered_remove_example :: proc() { + a: small_array.Small_Array(4, int) + small_array.push(&a, 0, 1, 2, 3) + + fmt.println("BEFORE:", small_array.slice(&a)) + small_array.ordered_remove(&a, 1) + fmt.println("AFTER :", small_array.slice(&a)) + } + +Output: + + BEFORE: [0, 1, 2, 3] + AFTER : [0, 2, 3] +*/ ordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check { runtime.bounds_check_error_loc(loc, index, a.len) if index+1 < a.len { @@ -126,6 +639,32 @@ ordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, lo a.len -= 1 } +/* +Removes the element at the specified index without retaining order. + +**Inputs** +- `a`: A pointer to the small-array +- `index`: The position of the element to remove + +Example: + + import "core:container/small_array" + import "core:fmt" + + unordered_remove_example :: proc() { + a: small_array.Small_Array(4, int) + small_array.push(&a, 0, 1, 2, 3) + + fmt.println("BEFORE:", small_array.slice(&a)) + small_array.unordered_remove(&a, 1) + fmt.println("AFTER :", small_array.slice(&a)) + } + +Output: + + BEFORE: [0, 1, 2, 3] + AFTER : [0, 3, 2] +*/ unordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check { runtime.bounds_check_error_loc(loc, index, a.len) n := a.len-1 @@ -135,10 +674,63 @@ unordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, a.len -= 1 } +/* +Sets the length of the small-array to 0. + +**Inputs** +- `a`: A pointer to the small-array + +Example: + + import "core:container/small_array" + import "core:fmt" + + clear_example :: proc() { + a: small_array.Small_Array(4, int) + small_array.push(&a, 0, 1, 2, 3) + + fmt.println("BEFORE:", small_array.slice(&a)) + small_array.clear(&a) + fmt.println("AFTER :", small_array.slice(&a)) + } + +Output: + + BEFORE: [0, 1, 2, 3] + AFTER : [] + +*/ clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) { resize(a, 0) } +/* +Attempts to append all elements to the small-array returning +false if there is not enough space to fit all of them. + +**Inputs** +- `a`: A pointer to the small-array +- `item`: The item to append +- ..: + +**Returns** +- true if there was enough space to fit the element, false otherwise + +Example: + + import "core:container/small_array" + import "core:fmt" + + push_back_elems_example :: proc() { + a: small_array.Small_Array(100, int) + small_array.push_back_elems(&a, 0, 1, 2, 3, 4) + fmt.println(small_array.slice(&a)) + } + +Output: + + [0, 1, 2, 3, 4] +*/ push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) -> bool { if a.len + builtin.len(items) <= cap(a^) { n := copy(a.data[a.len:], items[:]) @@ -148,6 +740,36 @@ push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) - return false } +/* +Tries to insert an element at the specified position. + +Note: Performing this operation will cause pointers obtained +through get_ptr(_save) to reference incorrect elements. + +**Inputs** +- `a`: A pointer to the small-array +- `item`: The item to insert +- `index`: The index to insert the item at + +**Returns** +- true if there was enough space to fit the element, false otherwise + +Example: + + import "core:container/small_array" + import "core:fmt" + + inject_at_example :: proc() { + arr: small_array.Small_Array(100, rune) + small_array.push(&arr, 'A', 'C', 'D') + small_array.inject_at(&arr, 'B', 1) + fmt.println(small_array.slice(&arr)) + } + +Output: + + [A, B, C, D] +*/ inject_at :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T, index: int) -> bool #no_bounds_check { if a.len < cap(a^) && index >= 0 && index <= len(a^) { a.len += 1 @@ -160,7 +782,38 @@ inject_at :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T, index: int return false } +// Alias for `push_back` append_elem :: push_back +// Alias for `push_back_elems` append_elems :: push_back_elems + +/* +Tries to append the element(s) to the small-array. + +**Inputs** +- `a`: A pointer to the small-array +- `item`: The item to append +- ..: + +**Returns** +- true if there was enough space to fit the element, false otherwise + +Example: + + import "core:container/small_array" + import "core:fmt" + + push_example :: proc() { + a: small_array.Small_Array(100, int) + small_array.push(&a, 0) + small_array.push(&a, 1, 2, 3, 4) + fmt.println(small_array.slice(&a)) + } + +Output: + + [0, 1, 2, 3, 4] +*/ push :: proc{push_back, push_back_elems} +// Alias for `push` append :: proc{push_back, push_back_elems} diff --git a/core/crypto/_aes/aes.odin b/core/crypto/_aes/aes.odin index 4f52485d2..f458a12fb 100644 --- a/core/crypto/_aes/aes.odin +++ b/core/crypto/_aes/aes.odin @@ -25,4 +25,5 @@ GHASH_BLOCK_SIZE :: 16 GHASH_TAG_SIZE :: 16 // RCON is the AES keyschedule round constants. +@(rodata) RCON := [10]byte{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36} diff --git a/core/crypto/_aes/ct64/ct64.odin b/core/crypto/_aes/ct64/ct64.odin index f198cab81..af2b42c1e 100644 --- a/core/crypto/_aes/ct64/ct64.odin +++ b/core/crypto/_aes/ct64/ct64.odin @@ -22,8 +22,6 @@ package aes_ct64 -import "base:intrinsics" - // Bitsliced AES for 64-bit general purpose (integer) registers. Each // invocation will process up to 4 blocks at a time. This implementation // is derived from the BearSSL ct64 code, and distributed under a 1-clause @@ -212,11 +210,8 @@ orthogonalize :: proc "contextless" (q: ^[8]u64) { } @(require_results) -interleave_in :: proc "contextless" (w: []u32) -> (q0, q1: u64) #no_bounds_check { - if len(w) < 4 { - intrinsics.trap() - } - x0, x1, x2, x3 := u64(w[0]), u64(w[1]), u64(w[2]), u64(w[3]) +interleave_in :: proc "contextless" (w0, w1, w2, w3: u32) -> (q0, q1: u64) #no_bounds_check { + x0, x1, x2, x3 := u64(w0), u64(w1), u64(w2), u64(w3) x0 |= (x0 << 16) x1 |= (x1 << 16) x2 |= (x2 << 16) diff --git a/core/crypto/_aes/ct64/ct64_enc.odin b/core/crypto/_aes/ct64/ct64_enc.odin index 36d4aebc8..bee6de722 100644 --- a/core/crypto/_aes/ct64/ct64_enc.odin +++ b/core/crypto/_aes/ct64/ct64_enc.odin @@ -22,12 +22,8 @@ package aes_ct64 -import "base:intrinsics" - add_round_key :: proc "contextless" (q: ^[8]u64, sk: []u64) #no_bounds_check { - if len(sk) < 8 { - intrinsics.trap() - } + ensure_contextless(len(sk) >= 8, "aes/ct64: invalid round key size") q[0] ~= sk[0] q[1] ~= sk[1] diff --git a/core/crypto/_aes/ct64/ct64_keysched.odin b/core/crypto/_aes/ct64/ct64_keysched.odin index 060a2c03e..0f00bba57 100644 --- a/core/crypto/_aes/ct64/ct64_keysched.odin +++ b/core/crypto/_aes/ct64/ct64_keysched.odin @@ -22,7 +22,6 @@ package aes_ct64 -import "base:intrinsics" import "core:crypto/_aes" import "core:encoding/endian" import "core:mem" @@ -42,7 +41,7 @@ sub_word :: proc "contextless" (x: u32) -> u32 { } @(private, require_results) -keysched :: proc(comp_skey: []u64, key: []byte) -> int { +keysched :: proc "contextless" (comp_skey: []u64, key: []byte) -> int { num_rounds, key_len := 0, len(key) switch key_len { case _aes.KEY_SIZE_128: @@ -52,7 +51,7 @@ keysched :: proc(comp_skey: []u64, key: []byte) -> int { case _aes.KEY_SIZE_256: num_rounds = _aes.ROUNDS_256 case: - panic("crypto/aes: invalid AES key size") + panic_contextless("crypto/aes: invalid AES key size") } skey: [60]u32 = --- @@ -78,7 +77,7 @@ keysched :: proc(comp_skey: []u64, key: []byte) -> int { q: [8]u64 = --- for i, j := 0, 0; i < nkf; i, j = i + 4, j + 2 { - q[0], q[4] = interleave_in(skey[i:]) + q[0], q[4] = interleave_in(skey[i], skey[i+1], skey[i+2], skey[i+3]) q[1] = q[0] q[2] = q[0] q[3] = q[0] @@ -123,57 +122,3 @@ skey_expand :: proc "contextless" (skey, comp_skey: []u64, num_rounds: int) { skey[v + 3] = (x3 << 4) - x3 } } - -orthogonalize_roundkey :: proc "contextless" (qq: []u64, key: []byte) { - if len(qq) < 8 || len(key) != 16 { - intrinsics.trap() - } - - skey: [4]u32 = --- - skey[0] = endian.unchecked_get_u32le(key[0:]) - skey[1] = endian.unchecked_get_u32le(key[4:]) - skey[2] = endian.unchecked_get_u32le(key[8:]) - skey[3] = endian.unchecked_get_u32le(key[12:]) - - q: [8]u64 = --- - q[0], q[4] = interleave_in(skey[:]) - q[1] = q[0] - q[2] = q[0] - q[3] = q[0] - q[5] = q[4] - q[6] = q[4] - q[7] = q[4] - orthogonalize(&q) - - comp_skey: [2]u64 = --- - comp_skey[0] = - (q[0] & 0x1111111111111111) | - (q[1] & 0x2222222222222222) | - (q[2] & 0x4444444444444444) | - (q[3] & 0x8888888888888888) - comp_skey[1] = - (q[4] & 0x1111111111111111) | - (q[5] & 0x2222222222222222) | - (q[6] & 0x4444444444444444) | - (q[7] & 0x8888888888888888) - - for x, u in comp_skey { - x0 := x - x1, x2, x3 := x0, x0, x0 - x0 &= 0x1111111111111111 - x1 &= 0x2222222222222222 - x2 &= 0x4444444444444444 - x3 &= 0x8888888888888888 - x1 >>= 1 - x2 >>= 2 - x3 >>= 3 - qq[u * 4 + 0] = (x0 << 4) - x0 - qq[u * 4 + 1] = (x1 << 4) - x1 - qq[u * 4 + 2] = (x2 << 4) - x2 - qq[u * 4 + 3] = (x3 << 4) - x3 - } - - mem.zero_explicit(&skey, size_of(skey)) - mem.zero_explicit(&q, size_of(q)) - mem.zero_explicit(&comp_skey, size_of(comp_skey)) -} diff --git a/core/crypto/_aes/ct64/ghash.odin b/core/crypto/_aes/ct64/ghash.odin index a522a481a..0c885d8ba 100644 --- a/core/crypto/_aes/ct64/ghash.odin +++ b/core/crypto/_aes/ct64/ghash.odin @@ -22,7 +22,6 @@ package aes_ct64 -import "base:intrinsics" import "core:crypto/_aes" import "core:encoding/endian" @@ -64,9 +63,8 @@ rev64 :: proc "contextless" (x: u64) -> u64 { // Note: `dst` is both an input and an output, to support easy implementation // of GCM. ghash :: proc "contextless" (dst, key, data: []byte) { - if len(dst) != _aes.GHASH_BLOCK_SIZE || len(key) != _aes.GHASH_BLOCK_SIZE { - intrinsics.trap() - } + ensure_contextless(len(dst) == _aes.GHASH_BLOCK_SIZE) + ensure_contextless(len(key) == _aes.GHASH_BLOCK_SIZE) buf := data l := len(buf) diff --git a/core/crypto/_aes/ct64/helpers.odin b/core/crypto/_aes/ct64/helpers.odin index 169271f6d..7eec5bdc4 100644 --- a/core/crypto/_aes/ct64/helpers.odin +++ b/core/crypto/_aes/ct64/helpers.odin @@ -1,60 +1,61 @@ package aes_ct64 -import "base:intrinsics" import "core:crypto/_aes" import "core:encoding/endian" -load_blockx1 :: proc "contextless" (q: ^[8]u64, src: []byte) { - if len(src) != _aes.BLOCK_SIZE { - intrinsics.trap() - } - - w: [4]u32 = --- - w[0] = endian.unchecked_get_u32le(src[0:]) - w[1] = endian.unchecked_get_u32le(src[4:]) - w[2] = endian.unchecked_get_u32le(src[8:]) - w[3] = endian.unchecked_get_u32le(src[12:]) - q[0], q[4] = interleave_in(w[:]) - orthogonalize(q) +@(require_results) +load_interleaved :: proc "contextless" (src: []byte) -> (u64, u64) #no_bounds_check { + w0 := endian.unchecked_get_u32le(src[0:]) + w1 := endian.unchecked_get_u32le(src[4:]) + w2 := endian.unchecked_get_u32le(src[8:]) + w3 := endian.unchecked_get_u32le(src[12:]) + return interleave_in(w0, w1, w2, w3) } -store_blockx1 :: proc "contextless" (dst: []byte, q: ^[8]u64) { - if len(dst) != _aes.BLOCK_SIZE { - intrinsics.trap() - } - - orthogonalize(q) - w0, w1, w2, w3 := interleave_out(q[0], q[4]) +store_interleaved :: proc "contextless" (dst: []byte, a0, a1: u64) #no_bounds_check { + w0, w1, w2, w3 := interleave_out(a0, a1) endian.unchecked_put_u32le(dst[0:], w0) endian.unchecked_put_u32le(dst[4:], w1) endian.unchecked_put_u32le(dst[8:], w2) endian.unchecked_put_u32le(dst[12:], w3) } +@(require_results) +xor_interleaved :: #force_inline proc "contextless" (a0, a1, b0, b1: u64) -> (u64, u64) { + return a0 ~ b0, a1 ~ b1 +} + +@(require_results) +and_interleaved :: #force_inline proc "contextless" (a0, a1, b0, b1: u64) -> (u64, u64) { + return a0 & b0, a1 & b1 +} + +load_blockx1 :: proc "contextless" (q: ^[8]u64, src: []byte) { + ensure_contextless(len(src) == _aes.BLOCK_SIZE, "aes/ct64: invalid block size") + + q[0], q[4] = #force_inline load_interleaved(src) + orthogonalize(q) +} + +store_blockx1 :: proc "contextless" (dst: []byte, q: ^[8]u64) { + ensure_contextless(len(dst) == _aes.BLOCK_SIZE, "aes/ct64: invalid block size") + + orthogonalize(q) + #force_inline store_interleaved(dst, q[0], q[4]) +} + load_blocks :: proc "contextless" (q: ^[8]u64, src: [][]byte) { - if n := len(src); n > STRIDE || n == 0 { - intrinsics.trap() - } + ensure_contextless(len(src) == 0 || len(src) <= STRIDE, "aes/ct64: invalid block(s) size") - w: [4]u32 = --- for s, i in src { - if len(s) != _aes.BLOCK_SIZE { - intrinsics.trap() - } - - w[0] = endian.unchecked_get_u32le(s[0:]) - w[1] = endian.unchecked_get_u32le(s[4:]) - w[2] = endian.unchecked_get_u32le(s[8:]) - w[3] = endian.unchecked_get_u32le(s[12:]) - q[i], q[i + 4] = interleave_in(w[:]) + ensure_contextless(len(s) == _aes.BLOCK_SIZE, "aes/ct64: invalid block size") + q[i], q[i + 4] = #force_inline load_interleaved(s) } orthogonalize(q) } store_blocks :: proc "contextless" (dst: [][]byte, q: ^[8]u64) { - if n := len(dst); n > STRIDE || n == 0 { - intrinsics.trap() - } + ensure_contextless(len(dst) == 0 || len(dst) <= STRIDE, "aes/ct64: invalid block(s) size") orthogonalize(q) for d, i in dst { @@ -62,14 +63,7 @@ store_blocks :: proc "contextless" (dst: [][]byte, q: ^[8]u64) { if d == nil { break } - if len(d) != _aes.BLOCK_SIZE { - intrinsics.trap() - } - - w0, w1, w2, w3 := interleave_out(q[i], q[i + 4]) - endian.unchecked_put_u32le(d[0:], w0) - endian.unchecked_put_u32le(d[4:], w1) - endian.unchecked_put_u32le(d[8:], w2) - endian.unchecked_put_u32le(d[12:], w3) + ensure_contextless(len(d) == _aes.BLOCK_SIZE, "aes/ct64: invalid block size") + #force_inline store_interleaved(d, q[i], q[i + 4]) } } diff --git a/core/crypto/_aes/hw_intel/api.odin b/core/crypto/_aes/hw_intel/api.odin index 52669cb35..502d56213 100644 --- a/core/crypto/_aes/hw_intel/api.odin +++ b/core/crypto/_aes/hw_intel/api.odin @@ -6,7 +6,7 @@ import "core:sys/info" // is_supported returns true iff hardware accelerated AES // is supported. is_supported :: proc "contextless" () -> bool { - features, ok := info.cpu_features.? + features, ok := info.cpu.features.? if !ok { return false } diff --git a/core/crypto/_aes/hw_intel/ghash.odin b/core/crypto/_aes/hw_intel/ghash.odin index 4320dd59b..5f51b614b 100644 --- a/core/crypto/_aes/hw_intel/ghash.odin +++ b/core/crypto/_aes/hw_intel/ghash.odin @@ -52,7 +52,7 @@ GHASH_STRIDE_BYTES_HW :: GHASH_STRIDE_HW * _aes.GHASH_BLOCK_SIZE // that it is right-shifted by 1 bit. The left-shift is relatively // inexpensive, and it can be mutualised. // -// Since SSE2 opcodes do not have facilities for shitfting full 128-bit +// Since SSE2 opcodes do not have facilities for shifting full 128-bit // values with bit precision, we have to break down values into 64-bit // chunks. We number chunks from 0 to 3 in left to right order. @@ -155,7 +155,7 @@ square_f128 :: #force_inline proc "contextless" (kw: x86.__m128i) -> (x86.__m128 @(enable_target_feature = "sse2,ssse3,pclmul") ghash :: proc "contextless" (dst, key, data: []byte) #no_bounds_check { if len(dst) != _aes.GHASH_BLOCK_SIZE || len(key) != _aes.GHASH_BLOCK_SIZE { - intrinsics.trap() + panic_contextless("aes/ghash: invalid dst or key size") } // Note: BearSSL opts to copy the remainder into a zero-filled diff --git a/core/crypto/_blake2/blake2.odin b/core/crypto/_blake2/blake2.odin index 2ad74843b..89fbe3a7a 100644 --- a/core/crypto/_blake2/blake2.odin +++ b/core/crypto/_blake2/blake2.odin @@ -18,6 +18,8 @@ BLAKE2S_SIZE :: 32 BLAKE2B_BLOCK_SIZE :: 128 BLAKE2B_SIZE :: 64 +MAX_SIZE :: 255 + Blake2s_Context :: struct { h: [8]u32, t: [2]u32, @@ -68,13 +70,13 @@ Blake2_Tree :: struct { is_last_node: bool, } -@(private) +@(private, rodata) BLAKE2S_IV := [8]u32 { 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, } -@(private) +@(private, rodata) BLAKE2B_IV := [8]u64 { 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, @@ -82,16 +84,13 @@ BLAKE2B_IV := [8]u64 { 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, } -init :: proc(ctx: ^$T, cfg: ^Blake2_Config) { +init :: proc "contextless" (ctx: ^$T, cfg: ^Blake2_Config) { when T == Blake2s_Context { max_size :: BLAKE2S_SIZE } else when T == Blake2b_Context { max_size :: BLAKE2B_SIZE } - - if cfg.size > max_size { - panic("blake2: requested output size exceeeds algorithm max") - } + ensure_contextless(cfg.size <= max_size, "blake2: requested output size exceeeds algorithm max") // To save having to allocate a scratch buffer, use the internal // data buffer (`ctx.x`), as it is exactly the correct size. @@ -167,8 +166,8 @@ init :: proc(ctx: ^$T, cfg: ^Blake2_Config) { ctx.is_initialized = true } -update :: proc(ctx: ^$T, p: []byte) { - assert(ctx.is_initialized) +update :: proc "contextless" (ctx: ^$T, p: []byte) { + ensure_contextless(ctx.is_initialized) p := p when T == Blake2s_Context { @@ -195,8 +194,8 @@ update :: proc(ctx: ^$T, p: []byte) { ctx.nx += copy(ctx.x[ctx.nx:], p) } -final :: proc(ctx: ^$T, hash: []byte, finalize_clone: bool = false) { - assert(ctx.is_initialized) +final :: proc "contextless" (ctx: ^$T, hash: []byte, finalize_clone: bool = false) { + ensure_contextless(ctx.is_initialized) ctx := ctx if finalize_clone { @@ -206,24 +205,19 @@ final :: proc(ctx: ^$T, hash: []byte, finalize_clone: bool = false) { } defer(reset(ctx)) + ensure_contextless(len(hash) >= int(ctx.size), "crypto/blake2: invalid destination digest size") when T == Blake2s_Context { - if len(hash) < int(ctx.size) { - panic("crypto/blake2s: invalid destination digest size") - } blake2s_final(ctx, hash) } else when T == Blake2b_Context { - if len(hash) < int(ctx.size) { - panic("crypto/blake2b: invalid destination digest size") - } blake2b_final(ctx, hash) } } -clone :: proc(ctx, other: ^$T) { +clone :: proc "contextless" (ctx, other: ^$T) { ctx^ = other^ } -reset :: proc(ctx: ^$T) { +reset :: proc "contextless" (ctx: ^$T) { if !ctx.is_initialized { return } diff --git a/core/crypto/_chacha20/chacha20.odin b/core/crypto/_chacha20/chacha20.odin index a907209de..1a4b5a507 100644 --- a/core/crypto/_chacha20/chacha20.odin +++ b/core/crypto/_chacha20/chacha20.odin @@ -1,6 +1,5 @@ package _chacha20 -import "base:intrinsics" import "core:encoding/endian" import "core:math/bits" import "core:mem" @@ -46,9 +45,8 @@ Context :: struct { // derivation is expected to be handled by the caller, so that the // HChaCha call can be suitably accelerated. init :: proc "contextless" (ctx: ^Context, key, iv: []byte, is_xchacha: bool) { - if len(key) != KEY_SIZE || len(iv) != IV_SIZE { - intrinsics.trap() - } + ensure_contextless(len(key) == KEY_SIZE, "chacha20: invalid key size") + ensure_contextless(len(iv) == IV_SIZE, "chacha20: invalid key size") k, n := key, iv @@ -76,12 +74,10 @@ init :: proc "contextless" (ctx: ^Context, key, iv: []byte, is_xchacha: bool) { // seek seeks the (X)ChaCha20 stream counter to the specified block. seek :: proc(ctx: ^Context, block_nr: u64) { - assert(ctx._is_initialized) + ensure(ctx._is_initialized) if ctx._is_ietf_flavor { - if block_nr > MAX_CTR_IETF { - panic("crypto/chacha20: attempted to seek past maximum counter") - } + ensure(block_nr <= MAX_CTR_IETF, "crypto/chacha20: attempted to seek past maximum counter") } else { ctx._s[13] = u32(block_nr >> 32) } @@ -102,7 +98,7 @@ check_counter_limit :: proc(ctx: ^Context, nr_blocks: int) { // Enforce the maximum consumed keystream per IV. // // While all modern "standard" definitions of ChaCha20 use - // the IETF 32-bit counter, for XChaCha20 most common + // the IETF 32-bit counter, for XChaCha20 historical // implementations allow for a 64-bit counter. // // Honestly, the answer here is "use a MRAE primitive", but @@ -110,14 +106,14 @@ check_counter_limit :: proc(ctx: ^Context, nr_blocks: int) { ERR_CTR_EXHAUSTED :: "crypto/chacha20: maximum (X)ChaCha20 keystream per IV reached" + ctr_ok: bool if ctx._is_ietf_flavor { - if u64(ctx._s[12]) + u64(nr_blocks) > MAX_CTR_IETF { - panic(ERR_CTR_EXHAUSTED) - } + ctr_ok = u64(ctx._s[12]) + u64(nr_blocks) <= MAX_CTR_IETF } else { ctr := (u64(ctx._s[13]) << 32) | u64(ctx._s[12]) - if _, carry := bits.add_u64(ctr, u64(nr_blocks), 0); carry != 0 { - panic(ERR_CTR_EXHAUSTED) - } + _, carry := bits.add_u64(ctr, u64(nr_blocks), 0) + ctr_ok = carry == 0 } + + ensure(ctr_ok, "crypto/chacha20: maximum (X)ChaCha20 keystream per IV reached") } diff --git a/core/crypto/_chacha20/simd128/chacha20_simd128.odin b/core/crypto/_chacha20/simd128/chacha20_simd128.odin index fe0d0d518..4bf40e240 100644 --- a/core/crypto/_chacha20/simd128/chacha20_simd128.odin +++ b/core/crypto/_chacha20/simd128/chacha20_simd128.odin @@ -29,11 +29,24 @@ when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 { // explicitly using simd.u8x16 shuffles. @(private = "file") TARGET_SIMD_FEATURES :: "sse2,ssse3" +} else when ODIN_ARCH == .riscv64 { + @(private = "file") + TARGET_SIMD_FEATURES :: "v" } else { @(private = "file") TARGET_SIMD_FEATURES :: "" } +// Some targets lack runtime feature detection, and will flat out refuse +// to load binaries that have unknown instructions. This is distinct from +// `simd.HAS_HARDWARE_SIMD` as actually good designs support runtime feature +// detection and that constant establishes a baseline. +// +// See: +// - https://github.com/WebAssembly/design/issues/1161 +@(private = "file") +TARGET_IS_DESIGNED_BY_IDIOTS :: (ODIN_ARCH == .wasm64p32 || ODIN_ARCH == .wasm32) && !intrinsics.has_target_feature("simd128") + @(private = "file") _ROT_7L: simd.u32x4 : {7, 7, 7, 7} @(private = "file") @@ -205,14 +218,16 @@ _store_simd128 :: #force_inline proc "contextless" ( // is_performant returns true iff the target and current host both support // "enough" 128-bit SIMD to make this implementation performant. is_performant :: proc "contextless" () -> bool { - when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 || ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 || ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .riscv64 { when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 { req_features :: info.CPU_Features{.asimd} } else when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 { req_features :: info.CPU_Features{.sse2, .ssse3} + } else when ODIN_ARCH == .riscv64 { + req_features :: info.CPU_Features{.V} } - features, ok := info.cpu_features.? + features, ok := info.cpu.features.? if !ok { return false } @@ -245,8 +260,17 @@ stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) // 8 blocks at a time. // - // Note: This is only worth it on Aarch64. - when ODIN_ARCH == .arm64 { + // Note: + // This uses a ton of registers so it is only worth it on targets + // that have something like 32 128-bit registers. This is currently + // all ARMv8 targets, and RISC-V Zvl128b (`V` application profile) + // targets. + // + // While our current definition of `.arm32` is 32-bit ARMv8, this + // may change in the future (ARMv7 is still relevant), and things + // like Cortex-A8/A9 does "pretend" 128-bit SIMD 64-bits at a time + // thus needs bemchmarking. + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { for ; n >= 8; n = n - 8 { v0, v1, v2, v3 := s0, s1, s2, s3 @@ -354,9 +378,11 @@ stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) // 4 blocks at a time. // - // Note: The i386 target lacks the required number of registers - // for this to be performant, so it is skipped. - when ODIN_ARCH != .i386 { + // Note: This is skipped on several targets for various reasons. + // - i386 lacks the required number of registers + // - Generating code when runtime "hardware" SIMD support is impossible + // to detect is pointless, since this will be emulated using GP regs. + when ODIN_ARCH != .i386 && !TARGET_IS_DESIGNED_BY_IDIOTS { for ; n >= 4; n = n - 4 { v0, v1, v2, v3 := s0, s1, s2, s3 diff --git a/core/crypto/_chacha20/simd256/chacha20_simd256.odin b/core/crypto/_chacha20/simd256/chacha20_simd256.odin index ccb02a947..12fffeb2f 100644 --- a/core/crypto/_chacha20/simd256/chacha20_simd256.odin +++ b/core/crypto/_chacha20/simd256/chacha20_simd256.odin @@ -41,7 +41,7 @@ _VEC_TWO: simd.u64x4 : {2, 0, 2, 0} is_performant :: proc "contextless" () -> bool { req_features :: info.CPU_Features{.avx, .avx2} - features, ok := info.cpu_features.? + features, ok := info.cpu.features.? if !ok { return false } diff --git a/core/crypto/_chacha20/simd256/chacha20_simd256_stub.odin b/core/crypto/_chacha20/simd256/chacha20_simd256_stub.odin index ce673b42b..287ddd885 100644 --- a/core/crypto/_chacha20/simd256/chacha20_simd256_stub.odin +++ b/core/crypto/_chacha20/simd256/chacha20_simd256_stub.odin @@ -13,5 +13,5 @@ stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) } hchacha20 :: proc "contextless" (dst, key, iv: []byte) { - intrinsics.trap() + panic_contextless("crypto/chacha20: simd256 implementation unsupported") } \ No newline at end of file diff --git a/core/crypto/_edwards25519/edwards25519.odin b/core/crypto/_edwards25519/edwards25519.odin index 6495f7a3a..d6f01d497 100644 --- a/core/crypto/_edwards25519/edwards25519.odin +++ b/core/crypto/_edwards25519/edwards25519.odin @@ -11,7 +11,6 @@ See: - https://www.hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html */ -import "base:intrinsics" import "core:crypto" import field "core:crypto/_fiat/field_curve25519" import "core:mem" @@ -32,6 +31,7 @@ import "core:mem" // - The group element decoding routine takes the opinionated stance of // rejecting non-canonical encodings. +@(rodata) FE_D := field.Tight_Field_Element { 929955233495203, 466365720129213, @@ -39,7 +39,7 @@ FE_D := field.Tight_Field_Element { 2033849074728123, 1442794654840575, } -@(private) +@(private, rodata) FE_A := field.Tight_Field_Element { 2251799813685228, 2251799813685247, @@ -47,7 +47,7 @@ FE_A := field.Tight_Field_Element { 2251799813685247, 2251799813685247, } -@(private) +@(private, rodata) FE_D2 := field.Tight_Field_Element { 1859910466990425, 932731440258426, @@ -55,7 +55,7 @@ FE_D2 := field.Tight_Field_Element { 1815898335770999, 633789495995903, } -@(private) +@(private, rodata) GE_BASEPOINT := Group_Element { field.Tight_Field_Element { 1738742601995546, @@ -80,6 +80,7 @@ GE_BASEPOINT := Group_Element { 1821297809914039, }, } +@(rodata) GE_IDENTITY := Group_Element { field.Tight_Field_Element{0, 0, 0, 0, 0}, field.Tight_Field_Element{1, 0, 0, 0, 0}, @@ -107,9 +108,7 @@ ge_set :: proc "contextless" (ge, a: ^Group_Element) { @(require_results) ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool { - if len(b) != 32 { - intrinsics.trap() - } + ensure_contextless(len(b) == 32, "edwards25519: invalid group element size") b_ := (^[32]byte)(raw_data(b)) // Do the work in a scratch element, so that ge is unchanged on @@ -166,9 +165,7 @@ ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool { } ge_bytes :: proc "contextless" (ge: ^Group_Element, dst: []byte) { - if len(dst) != 32 { - intrinsics.trap() - } + ensure_contextless(len(dst) == 32, "edwards25519: invalid group element size") dst_ := (^[32]byte)(raw_data(dst)) // Convert the element to affine (x, y) representation. diff --git a/core/crypto/_edwards25519/edwards25519_scalar.odin b/core/crypto/_edwards25519/edwards25519_scalar.odin index e21fa3755..68c79a6e8 100644 --- a/core/crypto/_edwards25519/edwards25519_scalar.odin +++ b/core/crypto/_edwards25519/edwards25519_scalar.odin @@ -1,6 +1,5 @@ package _edwards25519 -import "base:intrinsics" import field "core:crypto/_fiat/field_scalar25519" import "core:mem" @@ -8,7 +7,7 @@ Scalar :: field.Montgomery_Domain_Field_Element // WARNING: This is non-canonical and only to be used when checking if // a group element is on the prime-order subgroup. -@(private) +@(private, rodata) SC_ELL := field.Non_Montgomery_Domain_Field_Element { field.ELL[0], field.ELL[1], @@ -25,17 +24,13 @@ sc_set_u64 :: proc "contextless" (sc: ^Scalar, i: u64) { @(require_results) sc_set_bytes :: proc "contextless" (sc: ^Scalar, b: []byte) -> bool { - if len(b) != 32 { - intrinsics.trap() - } + ensure_contextless(len(b) == 32, "edwards25519: invalid scalar size") b_ := (^[32]byte)(raw_data(b)) return field.fe_from_bytes(sc, b_) } sc_set_bytes_rfc8032 :: proc "contextless" (sc: ^Scalar, b: []byte) { - if len(b) != 32 { - intrinsics.trap() - } + ensure_contextless(len(b) == 32, "edwards25519: invalid scalar size") b_ := (^[32]byte)(raw_data(b)) field.fe_from_bytes_rfc8032(sc, b_) } diff --git a/core/crypto/_fiat/field_curve25519/field51.odin b/core/crypto/_fiat/field_curve25519/field51.odin index d039bd411..6716fa158 100644 --- a/core/crypto/_fiat/field_curve25519/field51.odin +++ b/core/crypto/_fiat/field_curve25519/field51.odin @@ -42,9 +42,12 @@ import "core:math/bits" Loose_Field_Element :: distinct [5]u64 Tight_Field_Element :: distinct [5]u64 +@(rodata) FE_ZERO := Tight_Field_Element{0, 0, 0, 0, 0} +@(rodata) FE_ONE := Tight_Field_Element{1, 0, 0, 0, 0} +@(rodata) FE_SQRT_M1 := Tight_Field_Element { 1718705420411056, 234908883556509, diff --git a/core/crypto/_fiat/field_curve448/field.odin b/core/crypto/_fiat/field_curve448/field.odin new file mode 100644 index 000000000..540d88f28 --- /dev/null +++ b/core/crypto/_fiat/field_curve448/field.odin @@ -0,0 +1,235 @@ +package field_curve448 + +import "core:mem" + +fe_relax_cast :: #force_inline proc "contextless" ( + arg1: ^Tight_Field_Element, +) -> ^Loose_Field_Element { + return (^Loose_Field_Element)(arg1) +} + +fe_tighten_cast :: #force_inline proc "contextless" ( + arg1: ^Loose_Field_Element, +) -> ^Tight_Field_Element { + return (^Tight_Field_Element)(arg1) +} + +fe_clear :: proc "contextless" ( + arg1: $T, +) where T == ^Tight_Field_Element || T == ^Loose_Field_Element { + mem.zero_explicit(arg1, size_of(arg1^)) +} + +fe_clear_vec :: proc "contextless" ( + arg1: $T, +) where T == []^Tight_Field_Element || T == []^Loose_Field_Element { + for fe in arg1 { + fe_clear(fe) + } +} + +fe_carry_mul_small :: proc "contextless" ( + out1: ^Tight_Field_Element, + arg1: ^Loose_Field_Element, + arg2: u64, +) { + arg2_ := Loose_Field_Element{arg2, 0, 0, 0, 0, 0, 0, 0} + fe_carry_mul(out1, arg1, &arg2_) +} + +fe_carry_pow2k :: proc "contextless" ( + out1: ^Tight_Field_Element, + arg1: ^Loose_Field_Element, + arg2: uint, +) { + // Special case: `arg1^(2 * 0) = 1`, though this should never happen. + if arg2 == 0 { + fe_one(out1) + return + } + + fe_carry_square(out1, arg1) + for _ in 1 ..< arg2 { + fe_carry_square(out1, fe_relax_cast(out1)) + } +} + +fe_carry_inv :: proc "contextless" ( + out1: ^Tight_Field_Element, + arg1: ^Loose_Field_Element, +) { + // Inversion computation is derived from the addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _110 = 2*_11 + // _111 = 1 + _110 + // _111000 = _111 << 3 + // _111111 = _111 + _111000 + // x12 = _111111 << 6 + _111111 + // x24 = x12 << 12 + x12 + // i34 = x24 << 6 + // x30 = _111111 + i34 + // x48 = i34 << 18 + x24 + // x96 = x48 << 48 + x48 + // x192 = x96 << 96 + x96 + // x222 = x192 << 30 + x30 + // x223 = 2*x222 + 1 + // return (x223 << 223 + x222) << 2 + 1 + // + // Operations: 447 squares 13 multiplies + // + // Generated by github.com/mmcloughlin/addchain v0.4.0. + + t0, t1, t2: Tight_Field_Element = ---, ---, --- + + // Step 1: t0 = x^0x2 + fe_carry_square(&t0, arg1) + + // Step 2: t0 = x^0x3 + fe_carry_mul(&t0, arg1, fe_relax_cast(&t0)) + + // t0.Sqr(t0) + fe_carry_square(&t0, fe_relax_cast(&t0)) + + // Step 4: t0 = x^0x7 + fe_carry_mul(&t0, arg1, fe_relax_cast(&t0)) + + // Step 7: t1 = x^0x38 + fe_carry_pow2k(&t1, fe_relax_cast(&t0), 3) + + // Step 8: t0 = x^0x3f + fe_carry_mul(&t0, fe_relax_cast(&t0), fe_relax_cast(&t1)) + + // Step 14: t1 = x^0xfc0 + fe_carry_pow2k(&t1, fe_relax_cast(&t0), 6) + + // Step 15: t1 = x^0xfff + fe_carry_mul(&t1, fe_relax_cast(&t0), fe_relax_cast(&t1)) + + // Step 27: t2 = x^0xfff000 + fe_carry_pow2k(&t2, fe_relax_cast(&t1), 12) + + // Step 28: t1 = x^0xffffff + fe_carry_mul(&t1, fe_relax_cast(&t1), fe_relax_cast(&t2)) + + // Step 34: t2 = x^0x3fffffc0 + fe_carry_pow2k(&t2, fe_relax_cast(&t1), 6) + + // Step 35: t0 = x^0x3fffffff + fe_carry_mul(&t0, fe_relax_cast(&t0), fe_relax_cast(&t2)) + + // Step 53: t2 = x^0xffffff000000 + fe_carry_pow2k(&t2, fe_relax_cast(&t2), 18) + + // Step 54: t1 = x^0xffffffffffff + fe_carry_mul(&t1, fe_relax_cast(&t1), fe_relax_cast(&t2)) + + // Step 102: t2 = x^0xffffffffffff000000000000 + fe_carry_pow2k(&t2, fe_relax_cast(&t1), 48) + + // Step 103: t1 = x^0xffffffffffffffffffffffff + fe_carry_mul(&t1, fe_relax_cast(&t1), fe_relax_cast(&t2)) + + // Step 199: t2 = x^0xffffffffffffffffffffffff000000000000000000000000 + fe_carry_pow2k(&t2, fe_relax_cast(&t1), 96) + + // Step 200: t1 = x^0xffffffffffffffffffffffffffffffffffffffffffffffff + fe_carry_mul(&t1, fe_relax_cast(&t1), fe_relax_cast(&t2)) + + // Step 230: t1 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffc0000000 + fe_carry_pow2k(&t1, fe_relax_cast(&t1), 30) + + // Step 231: t0 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff + fe_carry_mul(&t0, fe_relax_cast(&t0), fe_relax_cast(&t1)) + + // Step 232: t1 = x^0x7ffffffffffffffffffffffffffffffffffffffffffffffffffffffe + fe_carry_square(&t1, fe_relax_cast(&t0)) + + // Step 233: t1 = x^0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffff + fe_carry_mul(&t1, arg1, fe_relax_cast(&t1)) + + // Step 456: t1 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000000000000000000000000000000000000000000000000000 + fe_carry_pow2k(&t1, fe_relax_cast(&t1), 223) + + // Step 457: t0 = x^0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffff + fe_carry_mul(&t0, fe_relax_cast(&t0), fe_relax_cast(&t1)) + + // Step 459: t0 = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffc + fe_carry_pow2k(&t0, fe_relax_cast(&t0), 2) + + // Step 460: z = x^0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffd + fe_carry_mul(out1, arg1, fe_relax_cast(&t0)) + + fe_clear_vec([]^Tight_Field_Element{&t0, &t1, &t2}) +} + +fe_zero :: proc "contextless" (out1: ^Tight_Field_Element) { + out1[0] = 0 + out1[1] = 0 + out1[2] = 0 + out1[3] = 0 + out1[4] = 0 + out1[5] = 0 + out1[6] = 0 + out1[7] = 0 +} + +fe_one :: proc "contextless" (out1: ^Tight_Field_Element) { + out1[0] = 1 + out1[1] = 0 + out1[2] = 0 + out1[3] = 0 + out1[4] = 0 + out1[5] = 0 + out1[6] = 0 + out1[7] = 0 +} + +fe_set :: proc "contextless" (out1, arg1: ^Tight_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + x4 := arg1[3] + x5 := arg1[4] + x6 := arg1[5] + x7 := arg1[6] + x8 := arg1[7] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 + out1[6] = x7 + out1[7] = x8 +} + +@(optimization_mode = "none") +fe_cond_swap :: #force_no_inline proc "contextless" (out1, out2: ^Tight_Field_Element, arg1: int) { + mask := (u64(arg1) * 0xffffffffffffffff) + x := (out1[0] ~ out2[0]) & mask + x1, y1 := out1[0] ~ x, out2[0] ~ x + x = (out1[1] ~ out2[1]) & mask + x2, y2 := out1[1] ~ x, out2[1] ~ x + x = (out1[2] ~ out2[2]) & mask + x3, y3 := out1[2] ~ x, out2[2] ~ x + x = (out1[3] ~ out2[3]) & mask + x4, y4 := out1[3] ~ x, out2[3] ~ x + x = (out1[4] ~ out2[4]) & mask + x5, y5 := out1[4] ~ x, out2[4] ~ x + x = (out1[5] ~ out2[5]) & mask + x6, y6 := out1[5] ~ x, out2[5] ~ x + x = (out1[6] ~ out2[6]) & mask + x7, y7 := out1[6] ~ x, out2[6] ~ x + x = (out1[7] ~ out2[7]) & mask + x8, y8 := out1[7] ~ x, out2[7] ~ x + out1[0], out2[0] = x1, y1 + out1[1], out2[1] = x2, y2 + out1[2], out2[2] = x3, y3 + out1[3], out2[3] = x4, y4 + out1[4], out2[4] = x5, y5 + out1[5], out2[5] = x6, y6 + out1[6], out2[6] = x7, y7 + out1[7], out2[7] = x8, y8 +} \ No newline at end of file diff --git a/core/crypto/_fiat/field_curve448/field51.odin b/core/crypto/_fiat/field_curve448/field51.odin new file mode 100644 index 000000000..d8e49e04d --- /dev/null +++ b/core/crypto/_fiat/field_curve448/field51.odin @@ -0,0 +1,1060 @@ +// The BSD 1-Clause License (BSD-1-Clause) +// +// Copyright (c) 2015-2020 the fiat-crypto authors (see the AUTHORS file) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, +// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +package field_curve448 + +// The file provides arithmetic on the field Z/(2^448 - 2^224 - 1) using +// unsaturated 64-bit integer arithmetic. It is derived primarily +// from the machine generated Golang output from the fiat-crypto project. +// +// While the base implementation is provably correct, this implementation +// makes no such claims as the port and optimizations were done by hand. +// +// TODO: +// * When fiat-crypto supports it, using a saturated 64-bit limbs +// instead of 56-bit limbs will be faster, though the gains are +// minimal unless adcx/adox/mulx are used. + +import fiat "core:crypto/_fiat" +import "core:math/bits" + +Loose_Field_Element :: distinct [8]u64 +Tight_Field_Element :: distinct [8]u64 + +@(rodata) +FE_ZERO := Tight_Field_Element{0, 0, 0, 0, 0, 0, 0, 0} +@(rodata) +FE_ONE := Tight_Field_Element{1, 0, 0, 0, 0, 0, 0, 0} + +_addcarryx_u56 :: #force_inline proc "contextless" ( + arg1: fiat.u1, + arg2, arg3: u64, +) -> ( + out1: u64, + out2: fiat.u1, +) { + x1 := ((u64(arg1) + arg2) + arg3) + x2 := (x1 & 0xffffffffffffff) + x3 := fiat.u1((x1 >> 56)) + out1 = x2 + out2 = x3 + return +} + +_subborrowx_u56 :: #force_inline proc "contextless" ( + arg1: fiat.u1, + arg2, arg3: u64, +) -> ( + out1: u64, + out2: fiat.u1, +) { + x1 := ((i64(arg2) - i64(arg1)) - i64(arg3)) + x2 := fiat.u1((x1 >> 56)) + x3 := (u64(x1) & 0xffffffffffffff) + out1 = x3 + out2 = (0x0 - fiat.u1(x2)) + return +} + +fe_carry_mul :: proc "contextless" (out1: ^Tight_Field_Element, arg1, arg2: ^Loose_Field_Element) { + x2, x1 := bits.mul_u64(arg1[7], arg2[7]) + x4, x3 := bits.mul_u64(arg1[7], arg2[6]) + x6, x5 := bits.mul_u64(arg1[7], arg2[5]) + x8, x7 := bits.mul_u64(arg1[6], arg2[7]) + x10, x9 := bits.mul_u64(arg1[6], arg2[6]) + x12, x11 := bits.mul_u64(arg1[5], arg2[7]) + x14, x13 := bits.mul_u64(arg1[7], arg2[7]) + x16, x15 := bits.mul_u64(arg1[7], arg2[6]) + x18, x17 := bits.mul_u64(arg1[7], arg2[5]) + x20, x19 := bits.mul_u64(arg1[6], arg2[7]) + x22, x21 := bits.mul_u64(arg1[6], arg2[6]) + x24, x23 := bits.mul_u64(arg1[5], arg2[7]) + x26, x25 := bits.mul_u64(arg1[7], arg2[7]) + x28, x27 := bits.mul_u64(arg1[7], arg2[6]) + x30, x29 := bits.mul_u64(arg1[7], arg2[5]) + x32, x31 := bits.mul_u64(arg1[7], arg2[4]) + x34, x33 := bits.mul_u64(arg1[7], arg2[3]) + x36, x35 := bits.mul_u64(arg1[7], arg2[2]) + x38, x37 := bits.mul_u64(arg1[7], arg2[1]) + x40, x39 := bits.mul_u64(arg1[6], arg2[7]) + x42, x41 := bits.mul_u64(arg1[6], arg2[6]) + x44, x43 := bits.mul_u64(arg1[6], arg2[5]) + x46, x45 := bits.mul_u64(arg1[6], arg2[4]) + x48, x47 := bits.mul_u64(arg1[6], arg2[3]) + x50, x49 := bits.mul_u64(arg1[6], arg2[2]) + x52, x51 := bits.mul_u64(arg1[5], arg2[7]) + x54, x53 := bits.mul_u64(arg1[5], arg2[6]) + x56, x55 := bits.mul_u64(arg1[5], arg2[5]) + x58, x57 := bits.mul_u64(arg1[5], arg2[4]) + x60, x59 := bits.mul_u64(arg1[5], arg2[3]) + x62, x61 := bits.mul_u64(arg1[4], arg2[7]) + x64, x63 := bits.mul_u64(arg1[4], arg2[6]) + x66, x65 := bits.mul_u64(arg1[4], arg2[5]) + x68, x67 := bits.mul_u64(arg1[4], arg2[4]) + x70, x69 := bits.mul_u64(arg1[3], arg2[7]) + x72, x71 := bits.mul_u64(arg1[3], arg2[6]) + x74, x73 := bits.mul_u64(arg1[3], arg2[5]) + x76, x75 := bits.mul_u64(arg1[2], arg2[7]) + x78, x77 := bits.mul_u64(arg1[2], arg2[6]) + x80, x79 := bits.mul_u64(arg1[1], arg2[7]) + x82, x81 := bits.mul_u64(arg1[7], arg2[4]) + x84, x83 := bits.mul_u64(arg1[7], arg2[3]) + x86, x85 := bits.mul_u64(arg1[7], arg2[2]) + x88, x87 := bits.mul_u64(arg1[7], arg2[1]) + x90, x89 := bits.mul_u64(arg1[6], arg2[5]) + x92, x91 := bits.mul_u64(arg1[6], arg2[4]) + x94, x93 := bits.mul_u64(arg1[6], arg2[3]) + x96, x95 := bits.mul_u64(arg1[6], arg2[2]) + x98, x97 := bits.mul_u64(arg1[5], arg2[6]) + x100, x99 := bits.mul_u64(arg1[5], arg2[5]) + x102, x101 := bits.mul_u64(arg1[5], arg2[4]) + x104, x103 := bits.mul_u64(arg1[5], arg2[3]) + x106, x105 := bits.mul_u64(arg1[4], arg2[7]) + x108, x107 := bits.mul_u64(arg1[4], arg2[6]) + x110, x109 := bits.mul_u64(arg1[4], arg2[5]) + x112, x111 := bits.mul_u64(arg1[4], arg2[4]) + x114, x113 := bits.mul_u64(arg1[3], arg2[7]) + x116, x115 := bits.mul_u64(arg1[3], arg2[6]) + x118, x117 := bits.mul_u64(arg1[3], arg2[5]) + x120, x119 := bits.mul_u64(arg1[2], arg2[7]) + x122, x121 := bits.mul_u64(arg1[2], arg2[6]) + x124, x123 := bits.mul_u64(arg1[1], arg2[7]) + x126, x125 := bits.mul_u64(arg1[7], arg2[0]) + x128, x127 := bits.mul_u64(arg1[6], arg2[1]) + x130, x129 := bits.mul_u64(arg1[6], arg2[0]) + x132, x131 := bits.mul_u64(arg1[5], arg2[2]) + x134, x133 := bits.mul_u64(arg1[5], arg2[1]) + x136, x135 := bits.mul_u64(arg1[5], arg2[0]) + x138, x137 := bits.mul_u64(arg1[4], arg2[3]) + x140, x139 := bits.mul_u64(arg1[4], arg2[2]) + x142, x141 := bits.mul_u64(arg1[4], arg2[1]) + x144, x143 := bits.mul_u64(arg1[4], arg2[0]) + x146, x145 := bits.mul_u64(arg1[3], arg2[4]) + x148, x147 := bits.mul_u64(arg1[3], arg2[3]) + x150, x149 := bits.mul_u64(arg1[3], arg2[2]) + x152, x151 := bits.mul_u64(arg1[3], arg2[1]) + x154, x153 := bits.mul_u64(arg1[3], arg2[0]) + x156, x155 := bits.mul_u64(arg1[2], arg2[5]) + x158, x157 := bits.mul_u64(arg1[2], arg2[4]) + x160, x159 := bits.mul_u64(arg1[2], arg2[3]) + x162, x161 := bits.mul_u64(arg1[2], arg2[2]) + x164, x163 := bits.mul_u64(arg1[2], arg2[1]) + x166, x165 := bits.mul_u64(arg1[2], arg2[0]) + x168, x167 := bits.mul_u64(arg1[1], arg2[6]) + x170, x169 := bits.mul_u64(arg1[1], arg2[5]) + x172, x171 := bits.mul_u64(arg1[1], arg2[4]) + x174, x173 := bits.mul_u64(arg1[1], arg2[3]) + x176, x175 := bits.mul_u64(arg1[1], arg2[2]) + x178, x177 := bits.mul_u64(arg1[1], arg2[1]) + x180, x179 := bits.mul_u64(arg1[1], arg2[0]) + x182, x181 := bits.mul_u64(arg1[0], arg2[7]) + x184, x183 := bits.mul_u64(arg1[0], arg2[6]) + x186, x185 := bits.mul_u64(arg1[0], arg2[5]) + x188, x187 := bits.mul_u64(arg1[0], arg2[4]) + x190, x189 := bits.mul_u64(arg1[0], arg2[3]) + x192, x191 := bits.mul_u64(arg1[0], arg2[2]) + x194, x193 := bits.mul_u64(arg1[0], arg2[1]) + x196, x195 := bits.mul_u64(arg1[0], arg2[0]) + x197, x198 := bits.add_u64(x43, x31, u64(0x0)) + x199, _ := bits.add_u64(x44, x32, u64(fiat.u1(x198))) + x201, x202 := bits.add_u64(x53, x197, u64(0x0)) + x203, _ := bits.add_u64(x54, x199, u64(fiat.u1(x202))) + x205, x206 := bits.add_u64(x61, x201, u64(0x0)) + x207, _ := bits.add_u64(x62, x203, u64(fiat.u1(x206))) + x209, x210 := bits.add_u64(x153, x205, u64(0x0)) + x211, _ := bits.add_u64(x154, x207, u64(fiat.u1(x210))) + x213, x214 := bits.add_u64(x163, x209, u64(0x0)) + x215, _ := bits.add_u64(x164, x211, u64(fiat.u1(x214))) + x217, x218 := bits.add_u64(x175, x213, u64(0x0)) + x219, _ := bits.add_u64(x176, x215, u64(fiat.u1(x218))) + x221, x222 := bits.add_u64(x189, x217, u64(0x0)) + x223, _ := bits.add_u64(x190, x219, u64(fiat.u1(x222))) + x225 := ((x221 >> 56) | ((x223 << 8) & 0xffffffffffffffff)) + x226 := (x221 & 0xffffffffffffff) + x227, x228 := bits.add_u64(x89, x81, u64(0x0)) + x229, _ := bits.add_u64(x90, x82, u64(fiat.u1(x228))) + x231, x232 := bits.add_u64(x97, x227, u64(0x0)) + x233, _ := bits.add_u64(x98, x229, u64(fiat.u1(x232))) + x235, x236 := bits.add_u64(x105, x231, u64(0x0)) + x237, _ := bits.add_u64(x106, x233, u64(fiat.u1(x236))) + x239, x240 := bits.add_u64(x125, x235, u64(0x0)) + x241, _ := bits.add_u64(x126, x237, u64(fiat.u1(x240))) + x243, x244 := bits.add_u64(x127, x239, u64(0x0)) + x245, _ := bits.add_u64(x128, x241, u64(fiat.u1(x244))) + x247, x248 := bits.add_u64(x131, x243, u64(0x0)) + x249, _ := bits.add_u64(x132, x245, u64(fiat.u1(x248))) + x251, x252 := bits.add_u64(x137, x247, u64(0x0)) + x253, _ := bits.add_u64(x138, x249, u64(fiat.u1(x252))) + x255, x256 := bits.add_u64(x145, x251, u64(0x0)) + x257, _ := bits.add_u64(x146, x253, u64(fiat.u1(x256))) + x259, x260 := bits.add_u64(x155, x255, u64(0x0)) + x261, _ := bits.add_u64(x156, x257, u64(fiat.u1(x260))) + x263, x264 := bits.add_u64(x167, x259, u64(0x0)) + x265, _ := bits.add_u64(x168, x261, u64(fiat.u1(x264))) + x267, x268 := bits.add_u64(x181, x263, u64(0x0)) + x269, _ := bits.add_u64(x182, x265, u64(fiat.u1(x268))) + x271, x272 := bits.add_u64(x25, x13, u64(0x0)) + x273, _ := bits.add_u64(x26, x14, u64(fiat.u1(x272))) + x275, x276 := bits.add_u64(x83, x271, u64(0x0)) + x277, _ := bits.add_u64(x84, x273, u64(fiat.u1(x276))) + x279, x280 := bits.add_u64(x91, x275, u64(0x0)) + x281, _ := bits.add_u64(x92, x277, u64(fiat.u1(x280))) + x283, x284 := bits.add_u64(x99, x279, u64(0x0)) + x285, _ := bits.add_u64(x100, x281, u64(fiat.u1(x284))) + x287, x288 := bits.add_u64(x107, x283, u64(0x0)) + x289, _ := bits.add_u64(x108, x285, u64(fiat.u1(x288))) + x291, x292 := bits.add_u64(x113, x287, u64(0x0)) + x293, _ := bits.add_u64(x114, x289, u64(fiat.u1(x292))) + x295, x296 := bits.add_u64(x129, x291, u64(0x0)) + x297, _ := bits.add_u64(x130, x293, u64(fiat.u1(x296))) + x299, x300 := bits.add_u64(x133, x295, u64(0x0)) + x301, _ := bits.add_u64(x134, x297, u64(fiat.u1(x300))) + x303, x304 := bits.add_u64(x139, x299, u64(0x0)) + x305, _ := bits.add_u64(x140, x301, u64(fiat.u1(x304))) + x307, x308 := bits.add_u64(x147, x303, u64(0x0)) + x309, _ := bits.add_u64(x148, x305, u64(fiat.u1(x308))) + x311, x312 := bits.add_u64(x157, x307, u64(0x0)) + x313, _ := bits.add_u64(x158, x309, u64(fiat.u1(x312))) + x315, x316 := bits.add_u64(x169, x311, u64(0x0)) + x317, _ := bits.add_u64(x170, x313, u64(fiat.u1(x316))) + x319, x320 := bits.add_u64(x183, x315, u64(0x0)) + x321, _ := bits.add_u64(x184, x317, u64(fiat.u1(x320))) + x323, x324 := bits.add_u64(x19, x15, u64(0x0)) + x325, _ := bits.add_u64(x20, x16, u64(fiat.u1(x324))) + x327, x328 := bits.add_u64(x27, x323, u64(0x0)) + x329, _ := bits.add_u64(x28, x325, u64(fiat.u1(x328))) + x331, x332 := bits.add_u64(x39, x327, u64(0x0)) + x333, _ := bits.add_u64(x40, x329, u64(fiat.u1(x332))) + x335, x336 := bits.add_u64(x85, x331, u64(0x0)) + x337, _ := bits.add_u64(x86, x333, u64(fiat.u1(x336))) + x339, x340 := bits.add_u64(x93, x335, u64(0x0)) + x341, _ := bits.add_u64(x94, x337, u64(fiat.u1(x340))) + x343, x344 := bits.add_u64(x101, x339, u64(0x0)) + x345, _ := bits.add_u64(x102, x341, u64(fiat.u1(x344))) + x347, x348 := bits.add_u64(x109, x343, u64(0x0)) + x349, _ := bits.add_u64(x110, x345, u64(fiat.u1(x348))) + x351, x352 := bits.add_u64(x115, x347, u64(0x0)) + x353, _ := bits.add_u64(x116, x349, u64(fiat.u1(x352))) + x355, x356 := bits.add_u64(x119, x351, u64(0x0)) + x357, _ := bits.add_u64(x120, x353, u64(fiat.u1(x356))) + x359, x360 := bits.add_u64(x135, x355, u64(0x0)) + x361, _ := bits.add_u64(x136, x357, u64(fiat.u1(x360))) + x363, x364 := bits.add_u64(x141, x359, u64(0x0)) + x365, _ := bits.add_u64(x142, x361, u64(fiat.u1(x364))) + x367, x368 := bits.add_u64(x149, x363, u64(0x0)) + x369, _ := bits.add_u64(x150, x365, u64(fiat.u1(x368))) + x371, x372 := bits.add_u64(x159, x367, u64(0x0)) + x373, _ := bits.add_u64(x160, x369, u64(fiat.u1(x372))) + x375, x376 := bits.add_u64(x171, x371, u64(0x0)) + x377, _ := bits.add_u64(x172, x373, u64(fiat.u1(x376))) + x379, x380 := bits.add_u64(x185, x375, u64(0x0)) + x381, _ := bits.add_u64(x186, x377, u64(fiat.u1(x380))) + x383, x384 := bits.add_u64(x21, x17, u64(0x0)) + x385, _ := bits.add_u64(x22, x18, u64(fiat.u1(x384))) + x387, x388 := bits.add_u64(x23, x383, u64(0x0)) + x389, _ := bits.add_u64(x24, x385, u64(fiat.u1(x388))) + x391, x392 := bits.add_u64(x29, x387, u64(0x0)) + x393, _ := bits.add_u64(x30, x389, u64(fiat.u1(x392))) + x395, x396 := bits.add_u64(x41, x391, u64(0x0)) + x397, _ := bits.add_u64(x42, x393, u64(fiat.u1(x396))) + x399, x400 := bits.add_u64(x51, x395, u64(0x0)) + x401, _ := bits.add_u64(x52, x397, u64(fiat.u1(x400))) + x403, x404 := bits.add_u64(x87, x399, u64(0x0)) + x405, _ := bits.add_u64(x88, x401, u64(fiat.u1(x404))) + x407, x408 := bits.add_u64(x95, x403, u64(0x0)) + x409, _ := bits.add_u64(x96, x405, u64(fiat.u1(x408))) + x411, x412 := bits.add_u64(x103, x407, u64(0x0)) + x413, _ := bits.add_u64(x104, x409, u64(fiat.u1(x412))) + x415, x416 := bits.add_u64(x111, x411, u64(0x0)) + x417, _ := bits.add_u64(x112, x413, u64(fiat.u1(x416))) + x419, x420 := bits.add_u64(x117, x415, u64(0x0)) + x421, _ := bits.add_u64(x118, x417, u64(fiat.u1(x420))) + x423, x424 := bits.add_u64(x121, x419, u64(0x0)) + x425, _ := bits.add_u64(x122, x421, u64(fiat.u1(x424))) + x427, x428 := bits.add_u64(x123, x423, u64(0x0)) + x429, _ := bits.add_u64(x124, x425, u64(fiat.u1(x428))) + x431, x432 := bits.add_u64(x143, x427, u64(0x0)) + x433, _ := bits.add_u64(x144, x429, u64(fiat.u1(x432))) + x435, x436 := bits.add_u64(x151, x431, u64(0x0)) + x437, _ := bits.add_u64(x152, x433, u64(fiat.u1(x436))) + x439, x440 := bits.add_u64(x161, x435, u64(0x0)) + x441, _ := bits.add_u64(x162, x437, u64(fiat.u1(x440))) + x443, x444 := bits.add_u64(x173, x439, u64(0x0)) + x445, _ := bits.add_u64(x174, x441, u64(fiat.u1(x444))) + x447, x448 := bits.add_u64(x187, x443, u64(0x0)) + x449, _ := bits.add_u64(x188, x445, u64(fiat.u1(x448))) + x451, x452 := bits.add_u64(x33, x1, u64(0x0)) + x453, _ := bits.add_u64(x34, x2, u64(fiat.u1(x452))) + x455, x456 := bits.add_u64(x45, x451, u64(0x0)) + x457, _ := bits.add_u64(x46, x453, u64(fiat.u1(x456))) + x459, x460 := bits.add_u64(x55, x455, u64(0x0)) + x461, _ := bits.add_u64(x56, x457, u64(fiat.u1(x460))) + x463, x464 := bits.add_u64(x63, x459, u64(0x0)) + x465, _ := bits.add_u64(x64, x461, u64(fiat.u1(x464))) + x467, x468 := bits.add_u64(x69, x463, u64(0x0)) + x469, _ := bits.add_u64(x70, x465, u64(fiat.u1(x468))) + x471, x472 := bits.add_u64(x165, x467, u64(0x0)) + x473, _ := bits.add_u64(x166, x469, u64(fiat.u1(x472))) + x475, x476 := bits.add_u64(x177, x471, u64(0x0)) + x477, _ := bits.add_u64(x178, x473, u64(fiat.u1(x476))) + x479, x480 := bits.add_u64(x191, x475, u64(0x0)) + x481, _ := bits.add_u64(x192, x477, u64(fiat.u1(x480))) + x483, x484 := bits.add_u64(x7, x3, u64(0x0)) + x485, _ := bits.add_u64(x8, x4, u64(fiat.u1(x484))) + x487, x488 := bits.add_u64(x35, x483, u64(0x0)) + x489, _ := bits.add_u64(x36, x485, u64(fiat.u1(x488))) + x491, x492 := bits.add_u64(x47, x487, u64(0x0)) + x493, _ := bits.add_u64(x48, x489, u64(fiat.u1(x492))) + x495, x496 := bits.add_u64(x57, x491, u64(0x0)) + x497, _ := bits.add_u64(x58, x493, u64(fiat.u1(x496))) + x499, x500 := bits.add_u64(x65, x495, u64(0x0)) + x501, _ := bits.add_u64(x66, x497, u64(fiat.u1(x500))) + x503, x504 := bits.add_u64(x71, x499, u64(0x0)) + x505, _ := bits.add_u64(x72, x501, u64(fiat.u1(x504))) + x507, x508 := bits.add_u64(x75, x503, u64(0x0)) + x509, _ := bits.add_u64(x76, x505, u64(fiat.u1(x508))) + x511, x512 := bits.add_u64(x179, x507, u64(0x0)) + x513, _ := bits.add_u64(x180, x509, u64(fiat.u1(x512))) + x515, x516 := bits.add_u64(x193, x511, u64(0x0)) + x517, _ := bits.add_u64(x194, x513, u64(fiat.u1(x516))) + x519, x520 := bits.add_u64(x9, x5, u64(0x0)) + x521, _ := bits.add_u64(x10, x6, u64(fiat.u1(x520))) + x523, x524 := bits.add_u64(x11, x519, u64(0x0)) + x525, _ := bits.add_u64(x12, x521, u64(fiat.u1(x524))) + x527, x528 := bits.add_u64(x37, x523, u64(0x0)) + x529, _ := bits.add_u64(x38, x525, u64(fiat.u1(x528))) + x531, x532 := bits.add_u64(x49, x527, u64(0x0)) + x533, _ := bits.add_u64(x50, x529, u64(fiat.u1(x532))) + x535, x536 := bits.add_u64(x59, x531, u64(0x0)) + x537, _ := bits.add_u64(x60, x533, u64(fiat.u1(x536))) + x539, x540 := bits.add_u64(x67, x535, u64(0x0)) + x541, _ := bits.add_u64(x68, x537, u64(fiat.u1(x540))) + x543, x544 := bits.add_u64(x73, x539, u64(0x0)) + x545, _ := bits.add_u64(x74, x541, u64(fiat.u1(x544))) + x547, x548 := bits.add_u64(x77, x543, u64(0x0)) + x549, _ := bits.add_u64(x78, x545, u64(fiat.u1(x548))) + x551, x552 := bits.add_u64(x79, x547, u64(0x0)) + x553, _ := bits.add_u64(x80, x549, u64(fiat.u1(x552))) + x555, x556 := bits.add_u64(x195, x551, u64(0x0)) + x557, _ := bits.add_u64(x196, x553, u64(fiat.u1(x556))) + x559, x560 := bits.add_u64(x225, x447, u64(0x0)) + x561 := (u64(fiat.u1(x560)) + x449) + x562 := ((x267 >> 56) | ((x269 << 8) & 0xffffffffffffffff)) + x563 := (x267 & 0xffffffffffffff) + x564, x565 := bits.add_u64(x559, x562, u64(0x0)) + x566 := (u64(fiat.u1(x565)) + x561) + x567 := ((x564 >> 56) | ((x566 << 8) & 0xffffffffffffffff)) + x568 := (x564 & 0xffffffffffffff) + x569, x570 := bits.add_u64(x555, x562, u64(0x0)) + x571 := (u64(fiat.u1(x570)) + x557) + x572, x573 := bits.add_u64(x567, x379, u64(0x0)) + x574 := (u64(fiat.u1(x573)) + x381) + x575 := ((x569 >> 56) | ((x571 << 8) & 0xffffffffffffffff)) + x576 := (x569 & 0xffffffffffffff) + x577, x578 := bits.add_u64(x575, x515, u64(0x0)) + x579 := (u64(fiat.u1(x578)) + x517) + x580 := ((x572 >> 56) | ((x574 << 8) & 0xffffffffffffffff)) + x581 := (x572 & 0xffffffffffffff) + x582, x583 := bits.add_u64(x580, x319, u64(0x0)) + x584 := (u64(fiat.u1(x583)) + x321) + x585 := ((x577 >> 56) | ((x579 << 8) & 0xffffffffffffffff)) + x586 := (x577 & 0xffffffffffffff) + x587, x588 := bits.add_u64(x585, x479, u64(0x0)) + x589 := (u64(fiat.u1(x588)) + x481) + x590 := ((x582 >> 56) | ((x584 << 8) & 0xffffffffffffffff)) + x591 := (x582 & 0xffffffffffffff) + x592 := (x590 + x563) + x593 := ((x587 >> 56) | ((x589 << 8) & 0xffffffffffffffff)) + x594 := (x587 & 0xffffffffffffff) + x595 := (x593 + x226) + x596 := (x592 >> 56) + x597 := (x592 & 0xffffffffffffff) + x598 := (x595 >> 56) + x599 := (x595 & 0xffffffffffffff) + x600 := (x568 + x596) + x601 := (x576 + x596) + x602 := (x598 + x600) + x603 := fiat.u1((x602 >> 56)) + x604 := (x602 & 0xffffffffffffff) + x605 := (u64(x603) + x581) + x606 := fiat.u1((x601 >> 56)) + x607 := (x601 & 0xffffffffffffff) + x608 := (u64(x606) + x586) + out1[0] = x607 + out1[1] = x608 + out1[2] = x594 + out1[3] = x599 + out1[4] = x604 + out1[5] = x605 + out1[6] = x591 + out1[7] = x597 +} + +fe_carry_square :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { + x1 := arg1[7] + x2 := arg1[7] + x3 := (x1 * 0x2) + x4 := (x2 * 0x2) + x5 := (arg1[7] * 0x2) + x6 := arg1[6] + x7 := arg1[6] + x8 := (x6 * 0x2) + x9 := (x7 * 0x2) + x10 := (arg1[6] * 0x2) + x11 := arg1[5] + x12 := arg1[5] + x13 := (x11 * 0x2) + x14 := (x12 * 0x2) + x15 := (arg1[5] * 0x2) + x16 := arg1[4] + x17 := arg1[4] + x18 := (arg1[4] * 0x2) + x19 := (arg1[3] * 0x2) + x20 := (arg1[2] * 0x2) + x21 := (arg1[1] * 0x2) + x23, x22 := bits.mul_u64(arg1[7], x1) + x25, x24 := bits.mul_u64(arg1[6], x3) + x27, x26 := bits.mul_u64(arg1[6], x6) + x29, x28 := bits.mul_u64(arg1[5], x3) + x31, x30 := bits.mul_u64(arg1[7], x1) + x33, x32 := bits.mul_u64(arg1[6], x3) + x35, x34 := bits.mul_u64(arg1[6], x6) + x37, x36 := bits.mul_u64(arg1[5], x3) + x39, x38 := bits.mul_u64(arg1[7], x2) + x41, x40 := bits.mul_u64(arg1[6], x4) + x43, x42 := bits.mul_u64(arg1[6], x7) + x45, x44 := bits.mul_u64(arg1[5], x4) + x47, x46 := bits.mul_u64(arg1[5], x9) + x49, x48 := bits.mul_u64(arg1[5], x8) + x51, x50 := bits.mul_u64(arg1[5], x12) + x53, x52 := bits.mul_u64(arg1[5], x11) + x55, x54 := bits.mul_u64(arg1[4], x4) + x57, x56 := bits.mul_u64(arg1[4], x3) + x59, x58 := bits.mul_u64(arg1[4], x9) + x61, x60 := bits.mul_u64(arg1[4], x8) + x63, x62 := bits.mul_u64(arg1[4], x14) + x65, x64 := bits.mul_u64(arg1[4], x13) + x67, x66 := bits.mul_u64(arg1[4], x17) + x69, x68 := bits.mul_u64(arg1[4], x16) + x71, x70 := bits.mul_u64(arg1[3], x4) + x73, x72 := bits.mul_u64(arg1[3], x3) + x75, x74 := bits.mul_u64(arg1[3], x9) + x77, x76 := bits.mul_u64(arg1[3], x8) + x79, x78 := bits.mul_u64(arg1[3], x14) + x81, x80 := bits.mul_u64(arg1[3], x13) + x83, x82 := bits.mul_u64(arg1[3], x18) + x85, x84 := bits.mul_u64(arg1[3], arg1[3]) + x87, x86 := bits.mul_u64(arg1[2], x4) + x89, x88 := bits.mul_u64(arg1[2], x3) + x91, x90 := bits.mul_u64(arg1[2], x9) + x93, x92 := bits.mul_u64(arg1[2], x8) + x95, x94 := bits.mul_u64(arg1[2], x15) + x97, x96 := bits.mul_u64(arg1[2], x18) + x99, x98 := bits.mul_u64(arg1[2], x19) + x101, x100 := bits.mul_u64(arg1[2], arg1[2]) + x103, x102 := bits.mul_u64(arg1[1], x4) + x105, x104 := bits.mul_u64(arg1[1], x3) + x107, x106 := bits.mul_u64(arg1[1], x10) + x109, x108 := bits.mul_u64(arg1[1], x15) + x111, x110 := bits.mul_u64(arg1[1], x18) + x113, x112 := bits.mul_u64(arg1[1], x19) + x115, x114 := bits.mul_u64(arg1[1], x20) + x117, x116 := bits.mul_u64(arg1[1], arg1[1]) + x119, x118 := bits.mul_u64(arg1[0], x5) + x121, x120 := bits.mul_u64(arg1[0], x10) + x123, x122 := bits.mul_u64(arg1[0], x15) + x125, x124 := bits.mul_u64(arg1[0], x18) + x127, x126 := bits.mul_u64(arg1[0], x19) + x129, x128 := bits.mul_u64(arg1[0], x20) + x131, x130 := bits.mul_u64(arg1[0], x21) + x133, x132 := bits.mul_u64(arg1[0], arg1[0]) + x134, x135 := bits.add_u64(x54, x46, u64(0x0)) + x136, _ := bits.add_u64(x55, x47, u64(fiat.u1(x135))) + x138, x139 := bits.add_u64(x114, x134, u64(0x0)) + x140, _ := bits.add_u64(x115, x136, u64(fiat.u1(x139))) + x142, x143 := bits.add_u64(x126, x138, u64(0x0)) + x144, _ := bits.add_u64(x127, x140, u64(fiat.u1(x143))) + x146 := ((x142 >> 56) | ((x144 << 8) & 0xffffffffffffffff)) + x147 := (x142 & 0xffffffffffffff) + x148, x149 := bits.add_u64(x56, x48, u64(0x0)) + x150, _ := bits.add_u64(x57, x49, u64(fiat.u1(x149))) + x152, x153 := bits.add_u64(x82, x148, u64(0x0)) + x154, _ := bits.add_u64(x83, x150, u64(fiat.u1(x153))) + x156, x157 := bits.add_u64(x94, x152, u64(0x0)) + x158, _ := bits.add_u64(x95, x154, u64(fiat.u1(x157))) + x160, x161 := bits.add_u64(x106, x156, u64(0x0)) + x162, _ := bits.add_u64(x107, x158, u64(fiat.u1(x161))) + x164, x165 := bits.add_u64(x118, x160, u64(0x0)) + x166, _ := bits.add_u64(x119, x162, u64(fiat.u1(x165))) + x168, x169 := bits.add_u64(x38, x30, u64(0x0)) + x170, _ := bits.add_u64(x39, x31, u64(fiat.u1(x169))) + x172, x173 := bits.add_u64(x52, x168, u64(0x0)) + x174, _ := bits.add_u64(x53, x170, u64(fiat.u1(x173))) + x176, x177 := bits.add_u64(x60, x172, u64(0x0)) + x178, _ := bits.add_u64(x61, x174, u64(fiat.u1(x177))) + x180, x181 := bits.add_u64(x72, x176, u64(0x0)) + x182, _ := bits.add_u64(x73, x178, u64(fiat.u1(x181))) + x184, x185 := bits.add_u64(x84, x180, u64(0x0)) + x186, _ := bits.add_u64(x85, x182, u64(fiat.u1(x185))) + x188, x189 := bits.add_u64(x96, x184, u64(0x0)) + x190, _ := bits.add_u64(x97, x186, u64(fiat.u1(x189))) + x192, x193 := bits.add_u64(x108, x188, u64(0x0)) + x194, _ := bits.add_u64(x109, x190, u64(fiat.u1(x193))) + x196, x197 := bits.add_u64(x120, x192, u64(0x0)) + x198, _ := bits.add_u64(x121, x194, u64(fiat.u1(x197))) + x200, x201 := bits.add_u64(x40, x32, u64(0x0)) + x202, _ := bits.add_u64(x41, x33, u64(fiat.u1(x201))) + x204, x205 := bits.add_u64(x64, x200, u64(0x0)) + x206, _ := bits.add_u64(x65, x202, u64(fiat.u1(x205))) + x208, x209 := bits.add_u64(x76, x204, u64(0x0)) + x210, _ := bits.add_u64(x77, x206, u64(fiat.u1(x209))) + x212, x213 := bits.add_u64(x88, x208, u64(0x0)) + x214, _ := bits.add_u64(x89, x210, u64(fiat.u1(x213))) + x216, x217 := bits.add_u64(x98, x212, u64(0x0)) + x218, _ := bits.add_u64(x99, x214, u64(fiat.u1(x217))) + x220, x221 := bits.add_u64(x110, x216, u64(0x0)) + x222, _ := bits.add_u64(x111, x218, u64(fiat.u1(x221))) + x224, x225 := bits.add_u64(x122, x220, u64(0x0)) + x226, _ := bits.add_u64(x123, x222, u64(fiat.u1(x225))) + x228, x229 := bits.add_u64(x36, x34, u64(0x0)) + x230, _ := bits.add_u64(x37, x35, u64(fiat.u1(x229))) + x232, x233 := bits.add_u64(x42, x228, u64(0x0)) + x234, _ := bits.add_u64(x43, x230, u64(fiat.u1(x233))) + x236, x237 := bits.add_u64(x44, x232, u64(0x0)) + x238, _ := bits.add_u64(x45, x234, u64(fiat.u1(x237))) + x240, x241 := bits.add_u64(x68, x236, u64(0x0)) + x242, _ := bits.add_u64(x69, x238, u64(fiat.u1(x241))) + x244, x245 := bits.add_u64(x80, x240, u64(0x0)) + x246, _ := bits.add_u64(x81, x242, u64(fiat.u1(x245))) + x248, x249 := bits.add_u64(x92, x244, u64(0x0)) + x250, _ := bits.add_u64(x93, x246, u64(fiat.u1(x249))) + x252, x253 := bits.add_u64(x100, x248, u64(0x0)) + x254, _ := bits.add_u64(x101, x250, u64(fiat.u1(x253))) + x256, x257 := bits.add_u64(x104, x252, u64(0x0)) + x258, _ := bits.add_u64(x105, x254, u64(fiat.u1(x257))) + x260, x261 := bits.add_u64(x112, x256, u64(0x0)) + x262, _ := bits.add_u64(x113, x258, u64(fiat.u1(x261))) + x264, x265 := bits.add_u64(x124, x260, u64(0x0)) + x266, _ := bits.add_u64(x125, x262, u64(fiat.u1(x265))) + x268, x269 := bits.add_u64(x50, x22, u64(0x0)) + x270, _ := bits.add_u64(x51, x23, u64(fiat.u1(x269))) + x272, x273 := bits.add_u64(x58, x268, u64(0x0)) + x274, _ := bits.add_u64(x59, x270, u64(fiat.u1(x273))) + x276, x277 := bits.add_u64(x70, x272, u64(0x0)) + x278, _ := bits.add_u64(x71, x274, u64(fiat.u1(x277))) + x280, x281 := bits.add_u64(x116, x276, u64(0x0)) + x282, _ := bits.add_u64(x117, x278, u64(fiat.u1(x281))) + x284, x285 := bits.add_u64(x128, x280, u64(0x0)) + x286, _ := bits.add_u64(x129, x282, u64(fiat.u1(x285))) + x288, x289 := bits.add_u64(x62, x24, u64(0x0)) + x290, _ := bits.add_u64(x63, x25, u64(fiat.u1(x289))) + x292, x293 := bits.add_u64(x74, x288, u64(0x0)) + x294, _ := bits.add_u64(x75, x290, u64(fiat.u1(x293))) + x296, x297 := bits.add_u64(x86, x292, u64(0x0)) + x298, _ := bits.add_u64(x87, x294, u64(fiat.u1(x297))) + x300, x301 := bits.add_u64(x130, x296, u64(0x0)) + x302, _ := bits.add_u64(x131, x298, u64(fiat.u1(x301))) + x304, x305 := bits.add_u64(x28, x26, u64(0x0)) + x306, _ := bits.add_u64(x29, x27, u64(fiat.u1(x305))) + x308, x309 := bits.add_u64(x66, x304, u64(0x0)) + x310, _ := bits.add_u64(x67, x306, u64(fiat.u1(x309))) + x312, x313 := bits.add_u64(x78, x308, u64(0x0)) + x314, _ := bits.add_u64(x79, x310, u64(fiat.u1(x313))) + x316, x317 := bits.add_u64(x90, x312, u64(0x0)) + x318, _ := bits.add_u64(x91, x314, u64(fiat.u1(x317))) + x320, x321 := bits.add_u64(x102, x316, u64(0x0)) + x322, _ := bits.add_u64(x103, x318, u64(fiat.u1(x321))) + x324, x325 := bits.add_u64(x132, x320, u64(0x0)) + x326, _ := bits.add_u64(x133, x322, u64(fiat.u1(x325))) + x328, x329 := bits.add_u64(x146, x264, u64(0x0)) + x330 := (u64(fiat.u1(x329)) + x266) + x331 := ((x164 >> 56) | ((x166 << 8) & 0xffffffffffffffff)) + x332 := (x164 & 0xffffffffffffff) + x333, x334 := bits.add_u64(x328, x331, u64(0x0)) + x335 := (u64(fiat.u1(x334)) + x330) + x336 := ((x333 >> 56) | ((x335 << 8) & 0xffffffffffffffff)) + x337 := (x333 & 0xffffffffffffff) + x338, x339 := bits.add_u64(x324, x331, u64(0x0)) + x340 := (u64(fiat.u1(x339)) + x326) + x341, x342 := bits.add_u64(x336, x224, u64(0x0)) + x343 := (u64(fiat.u1(x342)) + x226) + x344 := ((x338 >> 56) | ((x340 << 8) & 0xffffffffffffffff)) + x345 := (x338 & 0xffffffffffffff) + x346, x347 := bits.add_u64(x344, x300, u64(0x0)) + x348 := (u64(fiat.u1(x347)) + x302) + x349 := ((x341 >> 56) | ((x343 << 8) & 0xffffffffffffffff)) + x350 := (x341 & 0xffffffffffffff) + x351, x352 := bits.add_u64(x349, x196, u64(0x0)) + x353 := (u64(fiat.u1(x352)) + x198) + x354 := ((x346 >> 56) | ((x348 << 8) & 0xffffffffffffffff)) + x355 := (x346 & 0xffffffffffffff) + x356, x357 := bits.add_u64(x354, x284, u64(0x0)) + x358 := (u64(fiat.u1(x357)) + x286) + x359 := ((x351 >> 56) | ((x353 << 8) & 0xffffffffffffffff)) + x360 := (x351 & 0xffffffffffffff) + x361 := (x359 + x332) + x362 := ((x356 >> 56) | ((x358 << 8) & 0xffffffffffffffff)) + x363 := (x356 & 0xffffffffffffff) + x364 := (x362 + x147) + x365 := (x361 >> 56) + x366 := (x361 & 0xffffffffffffff) + x367 := (x364 >> 56) + x368 := (x364 & 0xffffffffffffff) + x369 := (x337 + x365) + x370 := (x345 + x365) + x371 := (x367 + x369) + x372 := fiat.u1((x371 >> 56)) + x373 := (x371 & 0xffffffffffffff) + x374 := (u64(x372) + x350) + x375 := fiat.u1((x370 >> 56)) + x376 := (x370 & 0xffffffffffffff) + x377 := (u64(x375) + x355) + out1[0] = x376 + out1[1] = x377 + out1[2] = x363 + out1[3] = x368 + out1[4] = x373 + out1[5] = x374 + out1[6] = x360 + out1[7] = x366 +} + +fe_carry :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^Loose_Field_Element) { + x1 := arg1[3] + x2 := arg1[7] + x3 := (x2 >> 56) + x4 := (((x1 >> 56) + arg1[4]) + x3) + x5 := (arg1[0] + x3) + x6 := ((x4 >> 56) + arg1[5]) + x7 := ((x5 >> 56) + arg1[1]) + x8 := ((x6 >> 56) + arg1[6]) + x9 := ((x7 >> 56) + arg1[2]) + x10 := ((x8 >> 56) + (x2 & 0xffffffffffffff)) + x11 := ((x9 >> 56) + (x1 & 0xffffffffffffff)) + x12 := fiat.u1((x10 >> 56)) + x13 := ((x5 & 0xffffffffffffff) + u64(x12)) + x14 := (u64(fiat.u1((x11 >> 56))) + ((x4 & 0xffffffffffffff) + u64(x12))) + x15 := (x13 & 0xffffffffffffff) + x16 := (u64(fiat.u1((x13 >> 56))) + (x7 & 0xffffffffffffff)) + x17 := (x9 & 0xffffffffffffff) + x18 := (x11 & 0xffffffffffffff) + x19 := (x14 & 0xffffffffffffff) + x20 := (u64(fiat.u1((x14 >> 56))) + (x6 & 0xffffffffffffff)) + x21 := (x8 & 0xffffffffffffff) + x22 := (x10 & 0xffffffffffffff) + out1[0] = x15 + out1[1] = x16 + out1[2] = x17 + out1[3] = x18 + out1[4] = x19 + out1[5] = x20 + out1[6] = x21 + out1[7] = x22 +} + +fe_add :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) { + x1 := (arg1[0] + arg2[0]) + x2 := (arg1[1] + arg2[1]) + x3 := (arg1[2] + arg2[2]) + x4 := (arg1[3] + arg2[3]) + x5 := (arg1[4] + arg2[4]) + x6 := (arg1[5] + arg2[5]) + x7 := (arg1[6] + arg2[6]) + x8 := (arg1[7] + arg2[7]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 + out1[6] = x7 + out1[7] = x8 +} + +fe_sub :: proc "contextless" (out1: ^Loose_Field_Element, arg1, arg2: ^Tight_Field_Element) { + x1 := ((0x1fffffffffffffe + arg1[0]) - arg2[0]) + x2 := ((0x1fffffffffffffe + arg1[1]) - arg2[1]) + x3 := ((0x1fffffffffffffe + arg1[2]) - arg2[2]) + x4 := ((0x1fffffffffffffe + arg1[3]) - arg2[3]) + x5 := ((0x1fffffffffffffc + arg1[4]) - arg2[4]) + x6 := ((0x1fffffffffffffe + arg1[5]) - arg2[5]) + x7 := ((0x1fffffffffffffe + arg1[6]) - arg2[6]) + x8 := ((0x1fffffffffffffe + arg1[7]) - arg2[7]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 + out1[6] = x7 + out1[7] = x8 +} + +fe_opp :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) { + x1 := (0x1fffffffffffffe - arg1[0]) + x2 := (0x1fffffffffffffe - arg1[1]) + x3 := (0x1fffffffffffffe - arg1[2]) + x4 := (0x1fffffffffffffe - arg1[3]) + x5 := (0x1fffffffffffffc - arg1[4]) + x6 := (0x1fffffffffffffe - arg1[5]) + x7 := (0x1fffffffffffffe - arg1[6]) + x8 := (0x1fffffffffffffe - arg1[7]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 + out1[6] = x7 + out1[7] = x8 +} + +@(optimization_mode = "none") +fe_cond_assign :: #force_no_inline proc "contextless" ( + out1, arg1: ^Tight_Field_Element, + arg2: int, +) { + x1 := fiat.cmovznz_u64(fiat.u1(arg2), out1[0], arg1[0]) + x2 := fiat.cmovznz_u64(fiat.u1(arg2), out1[1], arg1[1]) + x3 := fiat.cmovznz_u64(fiat.u1(arg2), out1[2], arg1[2]) + x4 := fiat.cmovznz_u64(fiat.u1(arg2), out1[3], arg1[3]) + x5 := fiat.cmovznz_u64(fiat.u1(arg2), out1[4], arg1[4]) + x6 := fiat.cmovznz_u64(fiat.u1(arg2), out1[5], arg1[5]) + x7 := fiat.cmovznz_u64(fiat.u1(arg2), out1[6], arg1[6]) + x8 := fiat.cmovznz_u64(fiat.u1(arg2), out1[7], arg1[7]) + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 + out1[6] = x7 + out1[7] = x8 +} + +fe_to_bytes :: proc "contextless" (out1: ^[56]byte, arg1: ^Tight_Field_Element) { + x1, x2 := _subborrowx_u56(0x0, arg1[0], 0xffffffffffffff) + x3, x4 := _subborrowx_u56(x2, arg1[1], 0xffffffffffffff) + x5, x6 := _subborrowx_u56(x4, arg1[2], 0xffffffffffffff) + x7, x8 := _subborrowx_u56(x6, arg1[3], 0xffffffffffffff) + x9, x10 := _subborrowx_u56(x8, arg1[4], 0xfffffffffffffe) + x11, x12 := _subborrowx_u56(x10, arg1[5], 0xffffffffffffff) + x13, x14 := _subborrowx_u56(x12, arg1[6], 0xffffffffffffff) + x15, x16 := _subborrowx_u56(x14, arg1[7], 0xffffffffffffff) + x17 := fiat.cmovznz_u64(x16, u64(0x0), 0xffffffffffffffff) + x18, x19 := _addcarryx_u56(0x0, x1, (x17 & 0xffffffffffffff)) + x20, x21 := _addcarryx_u56(x19, x3, (x17 & 0xffffffffffffff)) + x22, x23 := _addcarryx_u56(x21, x5, (x17 & 0xffffffffffffff)) + x24, x25 := _addcarryx_u56(x23, x7, (x17 & 0xffffffffffffff)) + x26, x27 := _addcarryx_u56(x25, x9, (x17 & 0xfffffffffffffe)) + x28, x29 := _addcarryx_u56(x27, x11, (x17 & 0xffffffffffffff)) + x30, x31 := _addcarryx_u56(x29, x13, (x17 & 0xffffffffffffff)) + x32, _ := _addcarryx_u56(x31, x15, (x17 & 0xffffffffffffff)) + x34 := (u8(x18) & 0xff) + x35 := (x18 >> 8) + x36 := (u8(x35) & 0xff) + x37 := (x35 >> 8) + x38 := (u8(x37) & 0xff) + x39 := (x37 >> 8) + x40 := (u8(x39) & 0xff) + x41 := (x39 >> 8) + x42 := (u8(x41) & 0xff) + x43 := (x41 >> 8) + x44 := (u8(x43) & 0xff) + x45 := u8((x43 >> 8)) + x46 := (u8(x20) & 0xff) + x47 := (x20 >> 8) + x48 := (u8(x47) & 0xff) + x49 := (x47 >> 8) + x50 := (u8(x49) & 0xff) + x51 := (x49 >> 8) + x52 := (u8(x51) & 0xff) + x53 := (x51 >> 8) + x54 := (u8(x53) & 0xff) + x55 := (x53 >> 8) + x56 := (u8(x55) & 0xff) + x57 := u8((x55 >> 8)) + x58 := (u8(x22) & 0xff) + x59 := (x22 >> 8) + x60 := (u8(x59) & 0xff) + x61 := (x59 >> 8) + x62 := (u8(x61) & 0xff) + x63 := (x61 >> 8) + x64 := (u8(x63) & 0xff) + x65 := (x63 >> 8) + x66 := (u8(x65) & 0xff) + x67 := (x65 >> 8) + x68 := (u8(x67) & 0xff) + x69 := u8((x67 >> 8)) + x70 := (u8(x24) & 0xff) + x71 := (x24 >> 8) + x72 := (u8(x71) & 0xff) + x73 := (x71 >> 8) + x74 := (u8(x73) & 0xff) + x75 := (x73 >> 8) + x76 := (u8(x75) & 0xff) + x77 := (x75 >> 8) + x78 := (u8(x77) & 0xff) + x79 := (x77 >> 8) + x80 := (u8(x79) & 0xff) + x81 := u8((x79 >> 8)) + x82 := (u8(x26) & 0xff) + x83 := (x26 >> 8) + x84 := (u8(x83) & 0xff) + x85 := (x83 >> 8) + x86 := (u8(x85) & 0xff) + x87 := (x85 >> 8) + x88 := (u8(x87) & 0xff) + x89 := (x87 >> 8) + x90 := (u8(x89) & 0xff) + x91 := (x89 >> 8) + x92 := (u8(x91) & 0xff) + x93 := u8((x91 >> 8)) + x94 := (u8(x28) & 0xff) + x95 := (x28 >> 8) + x96 := (u8(x95) & 0xff) + x97 := (x95 >> 8) + x98 := (u8(x97) & 0xff) + x99 := (x97 >> 8) + x100 := (u8(x99) & 0xff) + x101 := (x99 >> 8) + x102 := (u8(x101) & 0xff) + x103 := (x101 >> 8) + x104 := (u8(x103) & 0xff) + x105 := u8((x103 >> 8)) + x106 := (u8(x30) & 0xff) + x107 := (x30 >> 8) + x108 := (u8(x107) & 0xff) + x109 := (x107 >> 8) + x110 := (u8(x109) & 0xff) + x111 := (x109 >> 8) + x112 := (u8(x111) & 0xff) + x113 := (x111 >> 8) + x114 := (u8(x113) & 0xff) + x115 := (x113 >> 8) + x116 := (u8(x115) & 0xff) + x117 := u8((x115 >> 8)) + x118 := (u8(x32) & 0xff) + x119 := (x32 >> 8) + x120 := (u8(x119) & 0xff) + x121 := (x119 >> 8) + x122 := (u8(x121) & 0xff) + x123 := (x121 >> 8) + x124 := (u8(x123) & 0xff) + x125 := (x123 >> 8) + x126 := (u8(x125) & 0xff) + x127 := (x125 >> 8) + x128 := (u8(x127) & 0xff) + x129 := u8((x127 >> 8)) + out1[0] = x34 + out1[1] = x36 + out1[2] = x38 + out1[3] = x40 + out1[4] = x42 + out1[5] = x44 + out1[6] = x45 + out1[7] = x46 + out1[8] = x48 + out1[9] = x50 + out1[10] = x52 + out1[11] = x54 + out1[12] = x56 + out1[13] = x57 + out1[14] = x58 + out1[15] = x60 + out1[16] = x62 + out1[17] = x64 + out1[18] = x66 + out1[19] = x68 + out1[20] = x69 + out1[21] = x70 + out1[22] = x72 + out1[23] = x74 + out1[24] = x76 + out1[25] = x78 + out1[26] = x80 + out1[27] = x81 + out1[28] = x82 + out1[29] = x84 + out1[30] = x86 + out1[31] = x88 + out1[32] = x90 + out1[33] = x92 + out1[34] = x93 + out1[35] = x94 + out1[36] = x96 + out1[37] = x98 + out1[38] = x100 + out1[39] = x102 + out1[40] = x104 + out1[41] = x105 + out1[42] = x106 + out1[43] = x108 + out1[44] = x110 + out1[45] = x112 + out1[46] = x114 + out1[47] = x116 + out1[48] = x117 + out1[49] = x118 + out1[50] = x120 + out1[51] = x122 + out1[52] = x124 + out1[53] = x126 + out1[54] = x128 + out1[55] = x129 +} + +fe_from_bytes :: proc "contextless" (out1: ^Tight_Field_Element, arg1: ^[56]byte) { + x1 := (u64(arg1[55]) << 48) + x2 := (u64(arg1[54]) << 40) + x3 := (u64(arg1[53]) << 32) + x4 := (u64(arg1[52]) << 24) + x5 := (u64(arg1[51]) << 16) + x6 := (u64(arg1[50]) << 8) + x7 := arg1[49] + x8 := (u64(arg1[48]) << 48) + x9 := (u64(arg1[47]) << 40) + x10 := (u64(arg1[46]) << 32) + x11 := (u64(arg1[45]) << 24) + x12 := (u64(arg1[44]) << 16) + x13 := (u64(arg1[43]) << 8) + x14 := arg1[42] + x15 := (u64(arg1[41]) << 48) + x16 := (u64(arg1[40]) << 40) + x17 := (u64(arg1[39]) << 32) + x18 := (u64(arg1[38]) << 24) + x19 := (u64(arg1[37]) << 16) + x20 := (u64(arg1[36]) << 8) + x21 := arg1[35] + x22 := (u64(arg1[34]) << 48) + x23 := (u64(arg1[33]) << 40) + x24 := (u64(arg1[32]) << 32) + x25 := (u64(arg1[31]) << 24) + x26 := (u64(arg1[30]) << 16) + x27 := (u64(arg1[29]) << 8) + x28 := arg1[28] + x29 := (u64(arg1[27]) << 48) + x30 := (u64(arg1[26]) << 40) + x31 := (u64(arg1[25]) << 32) + x32 := (u64(arg1[24]) << 24) + x33 := (u64(arg1[23]) << 16) + x34 := (u64(arg1[22]) << 8) + x35 := arg1[21] + x36 := (u64(arg1[20]) << 48) + x37 := (u64(arg1[19]) << 40) + x38 := (u64(arg1[18]) << 32) + x39 := (u64(arg1[17]) << 24) + x40 := (u64(arg1[16]) << 16) + x41 := (u64(arg1[15]) << 8) + x42 := arg1[14] + x43 := (u64(arg1[13]) << 48) + x44 := (u64(arg1[12]) << 40) + x45 := (u64(arg1[11]) << 32) + x46 := (u64(arg1[10]) << 24) + x47 := (u64(arg1[9]) << 16) + x48 := (u64(arg1[8]) << 8) + x49 := arg1[7] + x50 := (u64(arg1[6]) << 48) + x51 := (u64(arg1[5]) << 40) + x52 := (u64(arg1[4]) << 32) + x53 := (u64(arg1[3]) << 24) + x54 := (u64(arg1[2]) << 16) + x55 := (u64(arg1[1]) << 8) + x56 := arg1[0] + x57 := (x55 + u64(x56)) + x58 := (x54 + x57) + x59 := (x53 + x58) + x60 := (x52 + x59) + x61 := (x51 + x60) + x62 := (x50 + x61) + x63 := (x48 + u64(x49)) + x64 := (x47 + x63) + x65 := (x46 + x64) + x66 := (x45 + x65) + x67 := (x44 + x66) + x68 := (x43 + x67) + x69 := (x41 + u64(x42)) + x70 := (x40 + x69) + x71 := (x39 + x70) + x72 := (x38 + x71) + x73 := (x37 + x72) + x74 := (x36 + x73) + x75 := (x34 + u64(x35)) + x76 := (x33 + x75) + x77 := (x32 + x76) + x78 := (x31 + x77) + x79 := (x30 + x78) + x80 := (x29 + x79) + x81 := (x27 + u64(x28)) + x82 := (x26 + x81) + x83 := (x25 + x82) + x84 := (x24 + x83) + x85 := (x23 + x84) + x86 := (x22 + x85) + x87 := (x20 + u64(x21)) + x88 := (x19 + x87) + x89 := (x18 + x88) + x90 := (x17 + x89) + x91 := (x16 + x90) + x92 := (x15 + x91) + x93 := (x13 + u64(x14)) + x94 := (x12 + x93) + x95 := (x11 + x94) + x96 := (x10 + x95) + x97 := (x9 + x96) + x98 := (x8 + x97) + x99 := (x6 + u64(x7)) + x100 := (x5 + x99) + x101 := (x4 + x100) + x102 := (x3 + x101) + x103 := (x2 + x102) + x104 := (x1 + x103) + out1[0] = x62 + out1[1] = x68 + out1[2] = x74 + out1[3] = x80 + out1[4] = x86 + out1[5] = x92 + out1[6] = x98 + out1[7] = x104 +} + +fe_relax :: proc "contextless" (out1: ^Loose_Field_Element, arg1: ^Tight_Field_Element) { + x1 := arg1[0] + x2 := arg1[1] + x3 := arg1[2] + x4 := arg1[3] + x5 := arg1[4] + x6 := arg1[5] + x7 := arg1[6] + x8 := arg1[7] + out1[0] = x1 + out1[1] = x2 + out1[2] = x3 + out1[3] = x4 + out1[4] = x5 + out1[5] = x6 + out1[6] = x7 + out1[7] = x8 +} diff --git a/core/crypto/_fiat/field_poly1305/field.odin b/core/crypto/_fiat/field_poly1305/field.odin index b12046858..caaece98e 100644 --- a/core/crypto/_fiat/field_poly1305/field.odin +++ b/core/crypto/_fiat/field_poly1305/field.odin @@ -1,6 +1,5 @@ package field_poly1305 -import "base:intrinsics" import "core:encoding/endian" import "core:mem" @@ -29,9 +28,7 @@ fe_from_bytes :: #force_inline proc "contextless" ( // makes implementing the actual MAC block processing considerably // neater. - if len(arg1) != 16 { - intrinsics.trap() - } + ensure_contextless(len(arg1) == 16, "poly1305: invalid field element size") // While it may be unwise to do deserialization here on our // own when fiat-crypto provides equivalent functionality, diff --git a/core/crypto/_fiat/field_scalar25519/field.odin b/core/crypto/_fiat/field_scalar25519/field.odin index 9b40661b7..933637c54 100644 --- a/core/crypto/_fiat/field_scalar25519/field.odin +++ b/core/crypto/_fiat/field_scalar25519/field.odin @@ -1,18 +1,17 @@ package field_scalar25519 -import "base:intrinsics" import "core:encoding/endian" import "core:math/bits" import "core:mem" -@(private) +@(private, rodata) _TWO_168 := Montgomery_Domain_Field_Element { 0x5b8ab432eac74798, 0x38afddd6de59d5d7, 0xa2c131b399411b7c, 0x6329a7ed9ce5a30, } -@(private) +@(private, rodata) _TWO_336 := Montgomery_Domain_Field_Element { 0xbd3d108e2b35ecc5, 0x5c3a3718bdf9c90b, @@ -95,9 +94,8 @@ fe_from_bytes_wide :: proc "contextless" ( @(private) _fe_from_bytes_short :: proc "contextless" (out1: ^Montgomery_Domain_Field_Element, arg1: []byte) { // INVARIANT: len(arg1) < 32. - if len(arg1) >= 32 { - intrinsics.trap() - } + ensure_contextless(len(arg1) < 32, "edwards25519: oversized short scalar") + tmp: [32]byte copy(tmp[:], arg1) @@ -106,9 +104,7 @@ _fe_from_bytes_short :: proc "contextless" (out1: ^Montgomery_Domain_Field_Eleme } fe_to_bytes :: proc "contextless" (out1: []byte, arg1: ^Montgomery_Domain_Field_Element) { - if len(out1) != 32 { - intrinsics.trap() - } + ensure_contextless(len(out1) == 32, "edwards25519: oversized scalar output buffer") tmp: Non_Montgomery_Domain_Field_Element fe_from_montgomery(&tmp, arg1) diff --git a/core/crypto/_sha3/sha3.odin b/core/crypto/_sha3/sha3.odin index 2db76fce0..52b3fbda9 100644 --- a/core/crypto/_sha3/sha3.odin +++ b/core/crypto/_sha3/sha3.odin @@ -44,7 +44,7 @@ Context :: struct { is_finalized: bool, // For SHAKE (unlimited squeeze is allowed) } -@(private) +@(private, rodata) keccakf_rndc := [?]u64 { 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, @@ -56,13 +56,13 @@ keccakf_rndc := [?]u64 { 0x8000000000008080, 0x0000000080000001, 0x8000000080008008, } -@(private) +@(private, rodata) keccakf_rotc := [?]int { 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, } -@(private) +@(private, rodata) keccakf_piln := [?]i32 { 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1, @@ -122,7 +122,7 @@ keccakf :: proc "contextless" (st: ^[25]u64) { } } -init :: proc(ctx: ^Context) { +init :: proc "contextless" (ctx: ^Context) { for i := 0; i < 25; i += 1 { ctx.st.q[i] = 0 } @@ -133,9 +133,9 @@ init :: proc(ctx: ^Context) { ctx.is_finalized = false } -update :: proc(ctx: ^Context, data: []byte) { - assert(ctx.is_initialized) - assert(!ctx.is_finalized) +update :: proc "contextless" (ctx: ^Context, data: []byte) { + ensure_contextless(ctx.is_initialized) + ensure_contextless(!ctx.is_finalized) j := ctx.pt for i := 0; i < len(data); i += 1 { @@ -149,12 +149,9 @@ update :: proc(ctx: ^Context, data: []byte) { ctx.pt = j } -final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - assert(ctx.is_initialized) - - if len(hash) < ctx.mdlen { - panic("crypto/sha3: invalid destination digest size") - } +final :: proc "contextless" (ctx: ^Context, hash: []byte, finalize_clone: bool = false) { + ensure_contextless(ctx.is_initialized) + ensure_contextless(len(hash) >= ctx.mdlen, "crypto/sha3: invalid destination digest size") ctx := ctx if finalize_clone { @@ -173,11 +170,11 @@ final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { } } -clone :: proc(ctx, other: ^Context) { +clone :: proc "contextless" (ctx, other: ^Context) { ctx^ = other^ } -reset :: proc(ctx: ^Context) { +reset :: proc "contextless" (ctx: ^Context) { if !ctx.is_initialized { return } @@ -185,9 +182,9 @@ reset :: proc(ctx: ^Context) { mem.zero_explicit(ctx, size_of(ctx^)) } -shake_xof :: proc(ctx: ^Context) { - assert(ctx.is_initialized) - assert(!ctx.is_finalized) +shake_xof :: proc "contextless" (ctx: ^Context) { + ensure_contextless(ctx.is_initialized) + ensure_contextless(!ctx.is_finalized) ctx.st.b[ctx.pt] ~= ctx.dsbyte ctx.st.b[ctx.rsiz - 1] ~= 0x80 @@ -197,9 +194,9 @@ shake_xof :: proc(ctx: ^Context) { ctx.is_finalized = true // No more absorb, unlimited squeeze. } -shake_out :: proc(ctx: ^Context, hash: []byte) { - assert(ctx.is_initialized) - assert(ctx.is_finalized) +shake_out :: proc "contextless" (ctx: ^Context, hash: []byte) { + ensure_contextless(ctx.is_initialized) + ensure_contextless(ctx.is_finalized) j := ctx.pt for i := 0; i < len(hash); i += 1 { diff --git a/core/crypto/_sha3/sp800_185.odin b/core/crypto/_sha3/sp800_185.odin index a96f78cc1..8390d8490 100644 --- a/core/crypto/_sha3/sp800_185.odin +++ b/core/crypto/_sha3/sp800_185.odin @@ -3,7 +3,7 @@ package _sha3 import "core:encoding/endian" import "core:math/bits" -init_cshake :: proc(ctx: ^Context, n, s: []byte, sec_strength: int) { +init_cshake :: proc "contextless" (ctx: ^Context, n, s: []byte, sec_strength: int) { ctx.mdlen = sec_strength / 8 // No domain separator is equivalent to vanilla SHAKE. @@ -18,7 +18,7 @@ init_cshake :: proc(ctx: ^Context, n, s: []byte, sec_strength: int) { bytepad(ctx, [][]byte{n, s}, rate_cshake(sec_strength)) } -final_cshake :: proc(ctx: ^Context, dst: []byte, finalize_clone: bool = false) { +final_cshake :: proc "contextless" (ctx: ^Context, dst: []byte, finalize_clone: bool = false) { ctx := ctx if finalize_clone { tmp_ctx: Context @@ -32,7 +32,7 @@ final_cshake :: proc(ctx: ^Context, dst: []byte, finalize_clone: bool = false) { shake_out(ctx, dst) } -rate_cshake :: #force_inline proc(sec_strength: int) -> int { +rate_cshake :: #force_inline proc "contextless" (sec_strength: int) -> int { switch sec_strength { case 128: return RATE_128 @@ -40,7 +40,7 @@ rate_cshake :: #force_inline proc(sec_strength: int) -> int { return RATE_256 } - panic("crypto/sha3: invalid security strength") + panic_contextless("crypto/sha3: invalid security strength") } // right_encode and left_encode are defined to support 0 <= x < 2^2040 @@ -52,10 +52,10 @@ rate_cshake :: #force_inline proc(sec_strength: int) -> int { // // Thus we support 0 <= x < 2^128. -@(private) +@(private, rodata) _PAD: [RATE_128]byte // Biggest possible value of w per spec. -bytepad :: proc(ctx: ^Context, x_strings: [][]byte, w: int) { +bytepad :: proc "contextless" (ctx: ^Context, x_strings: [][]byte, w: int) { // 1. z = left_encode(w) || X. z_hi: u64 z_lo := left_right_encode(ctx, 0, u64(w), true) @@ -70,9 +70,7 @@ bytepad :: proc(ctx: ^Context, x_strings: [][]byte, w: int) { // This isn't actually possible, at least with the currently // defined SP 800-185 routines. - if carry != 0 { - panic("crypto/sha3: bytepad input length overflow") - } + ensure_contextless(carry == 0, "crypto/sha3: bytepad input length overflow") } // We skip this step as we are doing a byte-oriented implementation @@ -95,7 +93,7 @@ bytepad :: proc(ctx: ^Context, x_strings: [][]byte, w: int) { } } -encode_string :: #force_inline proc(ctx: ^Context, s: []byte) -> (u64, u64) { +encode_string :: #force_inline proc "contextless" (ctx: ^Context, s: []byte) -> (u64, u64) { l := encode_byte_len(ctx, len(s), true) // left_encode update(ctx, s) @@ -104,13 +102,13 @@ encode_string :: #force_inline proc(ctx: ^Context, s: []byte) -> (u64, u64) { return hi, lo } -encode_byte_len :: #force_inline proc(ctx: ^Context, l: int, is_left: bool) -> u64 { +encode_byte_len :: #force_inline proc "contextless" (ctx: ^Context, l: int, is_left: bool) -> u64 { hi, lo := bits.mul_u64(u64(l), 8) return left_right_encode(ctx, hi, lo, is_left) } @(private) -left_right_encode :: proc(ctx: ^Context, hi, lo: u64, is_left: bool) -> u64 { +left_right_encode :: proc "contextless" (ctx: ^Context, hi, lo: u64, is_left: bool) -> u64 { HI_OFFSET :: 1 LO_OFFSET :: HI_OFFSET + 8 RIGHT_OFFSET :: LO_OFFSET + 8 diff --git a/core/crypto/aead/aead.odin b/core/crypto/aead/aead.odin index 9b7d810e4..c8f324929 100644 --- a/core/crypto/aead/aead.odin +++ b/core/crypto/aead/aead.odin @@ -16,7 +16,7 @@ seal_oneshot :: proc(algo: Algorithm, dst, tag, key, iv, aad, plaintext: []byte, // returning true iff the authentication was successful. If authentication // fails, the destination buffer will be zeroed. // -// dst and plaintext MUST alias exactly or not at all. +// dst and ciphertext MUST alias exactly or not at all. @(require_results) open_oneshot :: proc(algo: Algorithm, dst, key, iv, aad, ciphertext, tag: []byte, impl: Implementation = nil) -> bool { ctx: Context diff --git a/core/crypto/aead/low_level.odin b/core/crypto/aead/low_level.odin index 38a0c84ba..c80574a0d 100644 --- a/core/crypto/aead/low_level.odin +++ b/core/crypto/aead/low_level.odin @@ -1,8 +1,10 @@ package aead +import "core:crypto/aegis" import "core:crypto/aes" import "core:crypto/chacha20" import "core:crypto/chacha20poly1305" +import "core:crypto/deoxysii" import "core:reflect" // Implementation is an AEAD implementation. Most callers will not need @@ -15,7 +17,7 @@ Implementation :: union { // MAX_TAG_SIZE is the maximum size tag that can be returned by any of the // Algorithms supported via this package. -MAX_TAG_SIZE :: 16 +MAX_TAG_SIZE :: 32 // Algorithm is the algorithm identifier associated with a given Context. Algorithm :: enum { @@ -25,9 +27,14 @@ Algorithm :: enum { AES_GCM_256, CHACHA20POLY1305, XCHACHA20POLY1305, + AEGIS_128L, + AEGIS_128L_256, // AEGIS-128L (256-bit tag) + AEGIS_256, + AEGIS_256_256, // AEGIS-256 (256-bit tag) + DEOXYS_II_256, } -// ALGORITM_NAMES is the Agorithm to algorithm name string. +// ALGORITM_NAMES is the Algorithm to algorithm name string. ALGORITHM_NAMES := [Algorithm]string { .Invalid = "Invalid", .AES_GCM_128 = "AES-GCM-128", @@ -35,6 +42,11 @@ ALGORITHM_NAMES := [Algorithm]string { .AES_GCM_256 = "AES-GCM-256", .CHACHA20POLY1305 = "chacha20poly1305", .XCHACHA20POLY1305 = "xchacha20poly1305", + .AEGIS_128L = "AEGIS-128L", + .AEGIS_128L_256 = "AEGIS-128L-256", + .AEGIS_256 = "AEGIS-256", + .AEGIS_256_256 = "AEGIS-256-256", + .DEOXYS_II_256 = "Deoxys-II-256", } // TAG_SIZES is the Algorithm to tag size in bytes. @@ -45,6 +57,11 @@ TAG_SIZES := [Algorithm]int { .AES_GCM_256 = aes.GCM_TAG_SIZE, .CHACHA20POLY1305 = chacha20poly1305.TAG_SIZE, .XCHACHA20POLY1305 = chacha20poly1305.TAG_SIZE, + .AEGIS_128L = aegis.TAG_SIZE_128, + .AEGIS_128L_256 = aegis.TAG_SIZE_256, + .AEGIS_256 = aegis.TAG_SIZE_128, + .AEGIS_256_256 = aegis.TAG_SIZE_256, + .DEOXYS_II_256 = deoxysii.TAG_SIZE, } // KEY_SIZES is the Algorithm to key size in bytes. @@ -55,6 +72,11 @@ KEY_SIZES := [Algorithm]int { .AES_GCM_256 = aes.KEY_SIZE_256, .CHACHA20POLY1305 = chacha20poly1305.KEY_SIZE, .XCHACHA20POLY1305 = chacha20poly1305.KEY_SIZE, + .AEGIS_128L = aegis.KEY_SIZE_128L, + .AEGIS_128L_256 = aegis.KEY_SIZE_128L, + .AEGIS_256 = aegis.KEY_SIZE_256, + .AEGIS_256_256 = aegis.KEY_SIZE_256, + .DEOXYS_II_256 = deoxysii.KEY_SIZE, } // IV_SIZES is the Algorithm to initialization vector size in bytes. @@ -67,6 +89,11 @@ IV_SIZES := [Algorithm]int { .AES_GCM_256 = aes.GCM_IV_SIZE, .CHACHA20POLY1305 = chacha20poly1305.IV_SIZE, .XCHACHA20POLY1305 = chacha20poly1305.XIV_SIZE, + .AEGIS_128L = aegis.IV_SIZE_128L, + .AEGIS_128L_256 = aegis.IV_SIZE_128L, + .AEGIS_256 = aegis.IV_SIZE_256, + .AEGIS_256_256 = aegis.IV_SIZE_256, + .DEOXYS_II_256 = deoxysii.IV_SIZE, } // Context is a concrete instantiation of a specific AEAD algorithm. @@ -75,6 +102,8 @@ Context :: struct { _impl: union { aes.Context_GCM, chacha20poly1305.Context, + aegis.Context, + deoxysii.Context, }, } @@ -86,6 +115,11 @@ _IMPL_IDS := [Algorithm]typeid { .AES_GCM_256 = typeid_of(aes.Context_GCM), .CHACHA20POLY1305 = typeid_of(chacha20poly1305.Context), .XCHACHA20POLY1305 = typeid_of(chacha20poly1305.Context), + .AEGIS_128L = typeid_of(aegis.Context), + .AEGIS_128L_256 = typeid_of(aegis.Context), + .AEGIS_256 = typeid_of(aegis.Context), + .AEGIS_256_256 = typeid_of(aegis.Context), + .DEOXYS_II_256 = typeid_of(deoxysii.Context), } // init initializes a Context with a specific AEAD Algorithm. @@ -94,9 +128,7 @@ init :: proc(ctx: ^Context, algorithm: Algorithm, key: []byte, impl: Implementat reset(ctx) } - if len(key) != KEY_SIZES[algorithm] { - panic("crypto/aead: invalid key size") - } + ensure(len(key) == KEY_SIZES[algorithm], "crypto/aead: invalid key size") // Directly specialize the union by setting the type ID (save a copy). reflect.set_union_variant_typeid( @@ -113,6 +145,12 @@ init :: proc(ctx: ^Context, algorithm: Algorithm, key: []byte, impl: Implementat case .XCHACHA20POLY1305: impl_ := impl != nil ? impl.(chacha20.Implementation) : chacha20.DEFAULT_IMPLEMENTATION chacha20poly1305.init_xchacha(&ctx._impl.(chacha20poly1305.Context), key, impl_) + case .AEGIS_128L, .AEGIS_128L_256, .AEGIS_256, .AEGIS_256_256: + impl_ := impl != nil ? impl.(aes.Implementation) : aes.DEFAULT_IMPLEMENTATION + aegis.init(&ctx._impl.(aegis.Context), key, impl_) + case .DEOXYS_II_256: + impl_ := impl != nil ? impl.(aes.Implementation) : aes.DEFAULT_IMPLEMENTATION + deoxysii.init(&ctx._impl.(deoxysii.Context), key, impl_) case .Invalid: panic("crypto/aead: uninitialized algorithm") case: @@ -127,11 +165,17 @@ init :: proc(ctx: ^Context, algorithm: Algorithm, key: []byte, impl: Implementat // // dst and plaintext MUST alias exactly or not at all. seal_ctx :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) { + ensure(len(tag) == TAG_SIZES[ctx._algo], "crypto/aead: invalid tag size") + switch &impl in ctx._impl { case aes.Context_GCM: aes.seal_gcm(&impl, dst, tag, iv, aad, plaintext) case chacha20poly1305.Context: chacha20poly1305.seal(&impl, dst, tag, iv, aad, plaintext) + case aegis.Context: + aegis.seal(&impl, dst, tag, iv, aad, plaintext) + case deoxysii.Context: + deoxysii.seal(&impl, dst, tag, iv, aad, plaintext) case: panic("crypto/aead: uninitialized algorithm") } @@ -145,11 +189,17 @@ seal_ctx :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) { // dst and plaintext MUST alias exactly or not at all. @(require_results) open_ctx :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { + ensure(len(tag) == TAG_SIZES[ctx._algo], "crypto/aead: invalid tag size") + switch &impl in ctx._impl { case aes.Context_GCM: return aes.open_gcm(&impl, dst, iv, aad, ciphertext, tag) case chacha20poly1305.Context: return chacha20poly1305.open(&impl, dst, iv, aad, ciphertext, tag) + case aegis.Context: + return aegis.open(&impl, dst, iv, aad, ciphertext, tag) + case deoxysii.Context: + return deoxysii.open(&impl, dst, iv, aad, ciphertext, tag) case: panic("crypto/aead: uninitialized algorithm") } @@ -163,6 +213,10 @@ reset :: proc(ctx: ^Context) { aes.reset_gcm(&impl) case chacha20poly1305.Context: chacha20poly1305.reset(&impl) + case aegis.Context: + aegis.reset(&impl) + case deoxysii.Context: + deoxysii.reset(&impl) case: // Calling reset repeatedly is fine. } diff --git a/core/crypto/aegis/aegis.odin b/core/crypto/aegis/aegis.odin new file mode 100644 index 000000000..adecce91f --- /dev/null +++ b/core/crypto/aegis/aegis.odin @@ -0,0 +1,213 @@ +/* +package aegis implements the AEGIS-128L and AEGIS-256 Authenticated +Encryption with Additional Data algorithms. + +See: +- [[ https://www.ietf.org/archive/id/draft-irtf-cfrg-aegis-aead-12.txt ]] +*/ +package aegis + +import "core:bytes" +import "core:crypto" +import "core:crypto/aes" +import "core:mem" + +// KEY_SIZE_128L is the AEGIS-128L key size in bytes. +KEY_SIZE_128L :: 16 +// KEY_SIZE_256 is the AEGIS-256 key size in bytes. +KEY_SIZE_256 :: 32 +// IV_SIZE_128L is the AEGIS-128L IV size in bytes. +IV_SIZE_128L :: 16 +// IV_SIZE_256 is the AEGIS-256 IV size in bytes. +IV_SIZE_256 :: 32 +// TAG_SIZE_128 is the AEGIS-128L or AEGIS-256 128-bit tag size in bytes. +TAG_SIZE_128 :: 16 +// TAG_SIZE_256 is the AEGIS-128L or AEGIS-256 256-bit tag size in bytes. +TAG_SIZE_256 :: 32 + +@(private) +_RATE_128L :: 32 +@(private) +_RATE_256 :: 16 +@(private) +_RATE_MAX :: _RATE_128L + +@(private, rodata) +_C0 := [16]byte{ + 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, + 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62, +} + +@(private, rodata) +_C1 := [16]byte { + 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, + 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd, +} + +// Context is a keyed AEGIS-128L or AEGIS-256 instance. +Context :: struct { + _key: [KEY_SIZE_256]byte, + _key_len: int, + _impl: aes.Implementation, + _is_initialized: bool, +} + +@(private) +_validate_common_slice_sizes :: proc (ctx: ^Context, tag, iv, aad, text: []byte) { + switch len(tag) { + case TAG_SIZE_128, TAG_SIZE_256: + case: + panic("crypto/aegis: invalid tag size") + } + + iv_ok: bool + switch ctx._key_len { + case KEY_SIZE_128L: + iv_ok = len(iv) == IV_SIZE_128L + case KEY_SIZE_256: + iv_ok = len(iv) == IV_SIZE_256 + } + ensure(iv_ok,"crypto/aegis: invalid IV size") + + #assert(size_of(int) == 8 || size_of(int) <= 4) + // As A_MAX and P_MAX are both defined to be 2^61 - 1 bytes, and + // the maximum length of a slice is bound by `size_of(int)`, where + // `int` is register sized, there is no need to check AAD/text + // lengths. +} + +// init initializes a Context with the provided key, for AEGIS-128L or AEGIS-256. +init :: proc(ctx: ^Context, key: []byte, impl := aes.DEFAULT_IMPLEMENTATION) { + switch len(key) { + case KEY_SIZE_128L, KEY_SIZE_256: + case: + panic("crypto/aegis: invalid key size") + } + + copy(ctx._key[:], key) + ctx._key_len = len(key) + ctx._impl = impl + if ctx._impl == .Hardware && !is_hardware_accelerated() { + ctx._impl = .Portable + } + ctx._is_initialized = true +} + +// seal encrypts the plaintext and authenticates the aad and ciphertext, +// with the provided Context and iv, stores the output in dst and tag. +// +// dst and plaintext MUST alias exactly or not at all. +seal :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) { + ensure(ctx._is_initialized) + + _validate_common_slice_sizes(ctx, tag, iv, aad, plaintext) + ensure(len(dst) == len(plaintext), "crypto/aegis: invalid destination ciphertext size") + ensure(!bytes.alias_inexactly(dst, plaintext), "crypto/aegis: dst and plaintext alias inexactly") + + switch ctx._impl { + case .Hardware: + st: State_HW + defer reset_state_hw(&st) + + init_hw(ctx, &st, iv) + + aad_len, pt_len := len(aad), len(plaintext) + if aad_len > 0 { + absorb_hw(&st, aad) + } + + if pt_len > 0 { + enc_hw(&st, dst, plaintext) + } + + finalize_hw(&st, tag, aad_len, pt_len) + case .Portable: + st: State_SW + defer reset_state_sw(&st) + + init_sw(ctx, &st, iv) + + aad_len, pt_len := len(aad), len(plaintext) + if aad_len > 0 { + absorb_sw(&st, aad) + } + + if pt_len > 0 { + enc_sw(&st, dst, plaintext) + } + + finalize_sw(&st, tag, aad_len, pt_len) + case: + panic("core/crypto/aegis: not implemented") + } +} + +// open authenticates the aad and ciphertext, and decrypts the ciphertext, +// with the provided Context, iv, and tag, and stores the output in dst, +// returning true iff the authentication was successful. If authentication +// fails, the destination buffer will be zeroed. +// +// dst and plaintext MUST alias exactly or not at all. +@(require_results) +open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { + ensure(ctx._is_initialized) + + _validate_common_slice_sizes(ctx, tag, iv, aad, ciphertext) + ensure(len(dst) == len(ciphertext), "crypto/aegis: invalid destination plaintext size") + ensure(!bytes.alias_inexactly(dst, ciphertext), "crypto/aegis: dst and ciphertext alias inexactly") + + tmp: [TAG_SIZE_256]byte + derived_tag := tmp[:len(tag)] + aad_len, ct_len := len(aad), len(ciphertext) + + switch ctx._impl { + case .Hardware: + st: State_HW + defer reset_state_hw(&st) + + init_hw(ctx, &st, iv) + + if aad_len > 0 { + absorb_hw(&st, aad) + } + + if ct_len > 0 { + dec_hw(&st, dst, ciphertext) + } + + finalize_hw(&st, derived_tag, aad_len, ct_len) + case .Portable: + st: State_SW + defer reset_state_sw(&st) + + init_sw(ctx, &st, iv) + + if aad_len > 0 { + absorb_sw(&st, aad) + } + + if ct_len > 0 { + dec_sw(&st, dst, ciphertext) + } + + finalize_sw(&st, derived_tag, aad_len, ct_len) + case: + panic("core/crypto/aegis: not implemented") + } + + if crypto.compare_constant_time(tag, derived_tag) != 1 { + mem.zero_explicit(raw_data(derived_tag), len(derived_tag)) + mem.zero_explicit(raw_data(dst), ct_len) + return false + } + + return true +} + +// reset sanitizes the Context. The Context must be +// re-initialized to be used again. +reset :: proc "contextless" (ctx: ^Context) { + mem.zero_explicit(&ctx._key, len(ctx._key)) + ctx._key_len = 0 + ctx._is_initialized = false +} diff --git a/core/crypto/aegis/aegis_impl_ct64.odin b/core/crypto/aegis/aegis_impl_ct64.odin new file mode 100644 index 000000000..4813b37ec --- /dev/null +++ b/core/crypto/aegis/aegis_impl_ct64.odin @@ -0,0 +1,452 @@ +package aegis + +import aes "core:crypto/_aes/ct64" +import "core:encoding/endian" +import "core:mem" + +// This uses the bitlsiced 64-bit general purpose register SWAR AES +// round function. The intermediate state is stored in interleaved +// but NOT orthogonalized form, as leaving things in the orthgonalized +// format would overly complicate the update implementation. +// +// Note/perf: Per Frank Denis and a review of the specification, it is +// possible to gain slightly more performance by leaving the state in +// orthogonalized form while doing initialization, finalization, and +// absorbing AAD. This implementation opts out of those optimizations +// for the sake of simplicity. +// +// The update function leverages the paralleism (4xblocks) at once. + +@(private) +State_SW :: struct { + s0_0, s0_1: u64, + s1_0, s1_1: u64, + s2_0, s2_1: u64, + s3_0, s3_1: u64, + s4_0, s4_1: u64, + s5_0, s5_1: u64, + s6_0, s6_1: u64, + s7_0, s7_1: u64, + q_k, q_b: [8]u64, + rate: int, +} + +@(private) +init_sw :: proc "contextless" (ctx: ^Context, st: ^State_SW, iv: []byte) { + switch ctx._key_len { + case KEY_SIZE_128L: + key_0, key_1 := aes.load_interleaved(ctx._key[:16]) + iv_0, iv_1 := aes.load_interleaved(iv) + + st.s0_0, st.s0_1 = aes.xor_interleaved(key_0, key_1, iv_0, iv_1) + st.s1_0, st.s1_1 = aes.load_interleaved(_C1[:]) + st.s2_0, st.s2_1 = aes.load_interleaved(_C0[:]) + st.s3_0, st.s3_1 = st.s1_0, st.s1_1 + st.s4_0, st.s4_1 = st.s0_0, st.s0_1 + st.s5_0, st.s5_1 = aes.xor_interleaved(key_0, key_1, st.s2_0, st.s2_1) + st.s6_0, st.s6_1 = aes.xor_interleaved(key_0, key_1, st.s1_0, st.s1_1) + st.s7_0, st.s7_1 = st.s5_0, st.s5_1 + st.rate = _RATE_128L + + for _ in 0 ..< 10 { + update_sw_128l(st, iv_0, iv_1, key_0, key_1) + } + case KEY_SIZE_256: + k0_0, k0_1 := aes.load_interleaved(ctx._key[:16]) + k1_0, k1_1 := aes.load_interleaved(ctx._key[16:]) + n0_0, n0_1 := aes.load_interleaved(iv[:16]) + n1_0, n1_1 := aes.load_interleaved(iv[16:]) + + st.s0_0, st.s0_1 = aes.xor_interleaved(k0_0, k0_1, n0_0, n0_1) + st.s1_0, st.s1_1 = aes.xor_interleaved(k1_0, k1_1, n1_0, n1_1) + st.s2_0, st.s2_1 = aes.load_interleaved(_C1[:]) + st.s3_0, st.s3_1 = aes.load_interleaved(_C0[:]) + st.s4_0, st.s4_1 = aes.xor_interleaved(k0_0, k0_1, st.s3_0, st.s3_1) + st.s5_0, st.s5_1 = aes.xor_interleaved(k1_0, k1_1, st.s2_0, st.s2_1) + st.rate = _RATE_256 + + u0_0, u0_1, u1_0, u1_1 := st.s0_0, st.s0_1, st.s1_0, st.s1_1 + for _ in 0 ..< 4 { + update_sw_256(st, k0_0, k0_1) + update_sw_256(st, k1_0, k1_1) + update_sw_256(st, u0_0, u0_1) + update_sw_256(st, u1_0, u1_1) + } + } +} + +@(private = "file") +update_sw_128l :: proc "contextless" (st: ^State_SW, m0_0, m0_1, m1_0, m1_1: u64) { + st.q_k[0], st.q_k[4] = aes.xor_interleaved(st.s0_0, st.s0_1, m0_0, m0_1) + st.q_k[1], st.q_k[5] = st.s1_0, st.s1_1 + st.q_k[2], st.q_k[6] = st.s2_0, st.s2_1 + st.q_k[3], st.q_k[7] = st.s3_0, st.s3_1 + aes.orthogonalize(&st.q_k) + + st.q_b[0], st.q_b[4] = st.s7_0, st.s7_1 + st.q_b[1], st.q_b[5] = st.s0_0, st.s0_1 + st.q_b[2], st.q_b[6] = st.s1_0, st.s1_1 + st.q_b[3], st.q_b[7] = st.s2_0, st.s2_1 + aes.orthogonalize(&st.q_b) + + aes.sub_bytes(&st.q_b) + aes.shift_rows(&st.q_b) + aes.mix_columns(&st.q_b) + aes.add_round_key(&st.q_b, st.q_k[:]) + aes.orthogonalize(&st.q_b) + + st.s0_0, st.s0_1 = st.q_b[0], st.q_b[4] + st.s1_0, st.s1_1 = st.q_b[1], st.q_b[5] + st.s2_0, st.s2_1 = st.q_b[2], st.q_b[6] + s3_0, s3_1 := st.q_b[3], st.q_b[7] + + st.q_k[0], st.q_k[4] = aes.xor_interleaved(st.s4_0, st.s4_1, m1_0, m1_1) + st.q_k[1], st.q_k[5] = st.s5_0, st.s5_1 + st.q_k[2], st.q_k[6] = st.s6_0, st.s6_1 + st.q_k[3], st.q_k[7] = st.s7_0, st.s7_1 + aes.orthogonalize(&st.q_k) + + st.q_b[0], st.q_b[4] = st.s3_0, st.s3_1 + st.q_b[1], st.q_b[5] = st.s4_0, st.s4_1 + st.q_b[2], st.q_b[6] = st.s5_0, st.s5_1 + st.q_b[3], st.q_b[7] = st.s6_0, st.s6_1 + aes.orthogonalize(&st.q_b) + + aes.sub_bytes(&st.q_b) + aes.shift_rows(&st.q_b) + aes.mix_columns(&st.q_b) + aes.add_round_key(&st.q_b, st.q_k[:]) + aes.orthogonalize(&st.q_b) + + st.s3_0, st.s3_1 = s3_0, s3_1 + st.s4_0, st.s4_1 = st.q_b[0], st.q_b[4] + st.s5_0, st.s5_1 = st.q_b[1], st.q_b[5] + st.s6_0, st.s6_1 = st.q_b[2], st.q_b[6] + st.s7_0, st.s7_1 = st.q_b[3], st.q_b[7] +} + +@(private = "file") +update_sw_256 :: proc "contextless" (st: ^State_SW, m_0, m_1: u64) { + st.q_k[0], st.q_k[4] = aes.xor_interleaved(st.s0_0, st.s0_1, m_0, m_1) + st.q_k[1], st.q_k[5] = st.s1_0, st.s1_1 + st.q_k[2], st.q_k[6] = st.s2_0, st.s2_1 + st.q_k[3], st.q_k[7] = st.s3_0, st.s3_1 + aes.orthogonalize(&st.q_k) + + st.q_b[0], st.q_b[4] = st.s5_0, st.s5_1 + st.q_b[1], st.q_b[5] = st.s0_0, st.s0_1 + st.q_b[2], st.q_b[6] = st.s1_0, st.s1_1 + st.q_b[3], st.q_b[7] = st.s2_0, st.s2_1 + aes.orthogonalize(&st.q_b) + + aes.sub_bytes(&st.q_b) + aes.shift_rows(&st.q_b) + aes.mix_columns(&st.q_b) + aes.add_round_key(&st.q_b, st.q_k[:]) + aes.orthogonalize(&st.q_b) + + st.s0_0, st.s0_1 = st.q_b[0], st.q_b[4] + st.s1_0, st.s1_1 = st.q_b[1], st.q_b[5] + st.s2_0, st.s2_1 = st.q_b[2], st.q_b[6] + s3_0, s3_1 := st.q_b[3], st.q_b[7] + + st.q_k[0], st.q_k[4] = st.s4_0, st.s4_1 + st.q_k[1], st.q_k[5] = st.s5_0, st.s5_1 + aes.orthogonalize(&st.q_k) + + st.q_b[0], st.q_b[4] = st.s3_0, st.s3_1 + st.q_b[1], st.q_b[5] = st.s4_0, st.s4_1 + aes.orthogonalize(&st.q_b) + + aes.sub_bytes(&st.q_b) + aes.shift_rows(&st.q_b) + aes.mix_columns(&st.q_b) + aes.add_round_key(&st.q_b, st.q_k[:]) + aes.orthogonalize(&st.q_b) + + st.s3_0, st.s3_1 = s3_0, s3_1 + st.s4_0, st.s4_1 = st.q_b[0], st.q_b[4] + st.s5_0, st.s5_1 = st.q_b[1], st.q_b[5] +} + +@(private = "file") +absorb_sw_128l :: #force_inline proc "contextless" (st: ^State_SW, ai: []byte) #no_bounds_check { + t0_0, t0_1 := aes.load_interleaved(ai[:16]) + t1_0, t1_1 := aes.load_interleaved(ai[16:]) + update_sw_128l(st, t0_0, t0_1, t1_0, t1_1) +} + +@(private = "file") +absorb_sw_256 :: #force_inline proc "contextless" (st: ^State_SW, ai: []byte) { + m_0, m_1 := aes.load_interleaved(ai) + update_sw_256(st, m_0, m_1) +} + +@(private) +absorb_sw :: proc "contextless" (st: ^State_SW, aad: []byte) #no_bounds_check { + ai, l := aad, len(aad) + + switch st.rate { + case _RATE_128L: + for l >= _RATE_128L { + absorb_sw_128l(st, ai) + ai = ai[_RATE_128L:] + l -= _RATE_128L + } + case _RATE_256: + for l >= _RATE_256 { + absorb_sw_256(st, ai) + + ai = ai[_RATE_256:] + l -= _RATE_256 + } + } + + // Pad out the remainder with `0`s till it is rate sized. + if l > 0 { + tmp: [_RATE_MAX]byte // AAD is not confidential. + copy(tmp[:], ai) + switch st.rate { + case _RATE_128L: + absorb_sw_128l(st, tmp[:]) + case _RATE_256: + absorb_sw_256(st, tmp[:]) + } + } +} + +@(private = "file", require_results) +z_sw_128l :: proc "contextless" (st: ^State_SW) -> (u64, u64, u64, u64) { + z0_0, z0_1 := aes.and_interleaved(st.s2_0, st.s2_1, st.s3_0, st.s3_1) + z0_0, z0_1 = aes.xor_interleaved(st.s1_0, st.s1_1, z0_0, z0_1) + z0_0, z0_1 = aes.xor_interleaved(st.s6_0, st.s6_1, z0_0, z0_1) + + z1_0, z1_1 := aes.and_interleaved(st.s6_0, st.s6_1, st.s7_0, st.s7_1) + z1_0, z1_1 = aes.xor_interleaved(st.s5_0, st.s5_1, z1_0, z1_1) + z1_0, z1_1 = aes.xor_interleaved(st.s2_0, st.s2_1, z1_0, z1_1) + + return z0_0, z0_1, z1_0, z1_1 +} + +@(private = "file", require_results) +z_sw_256 :: proc "contextless" (st: ^State_SW) -> (u64, u64) { + z_0, z_1 := aes.and_interleaved(st.s2_0, st.s2_1, st.s3_0, st.s3_1) + z_0, z_1 = aes.xor_interleaved(st.s5_0, st.s5_1, z_0, z_1) + z_0, z_1 = aes.xor_interleaved(st.s4_0, st.s4_1, z_0, z_1) + return aes.xor_interleaved(st.s1_0, st.s1_1, z_0, z_1) +} + +@(private = "file") +enc_sw_128l :: #force_inline proc "contextless" (st: ^State_SW, ci, xi: []byte) #no_bounds_check { + z0_0, z0_1, z1_0, z1_1 := z_sw_128l(st) + + t0_0, t0_1 := aes.load_interleaved(xi[:16]) + t1_0, t1_1 := aes.load_interleaved(xi[16:]) + update_sw_128l(st, t0_0, t0_1, t1_0, t1_1) + + out0_0, out0_1 := aes.xor_interleaved(t0_0, t0_1, z0_0, z0_1) + out1_0, out1_1 := aes.xor_interleaved(t1_0, t1_1, z1_0, z1_1) + aes.store_interleaved(ci[:16], out0_0, out0_1) + aes.store_interleaved(ci[16:], out1_0, out1_1) +} + +@(private = "file") +enc_sw_256 :: #force_inline proc "contextless" (st: ^State_SW, ci, xi: []byte) #no_bounds_check { + z_0, z_1 := z_sw_256(st) + + xi_0, xi_1 := aes.load_interleaved(xi) + update_sw_256(st, xi_0, xi_1) + + ci_0, ci_1 := aes.xor_interleaved(xi_0, xi_1, z_0, z_1) + aes.store_interleaved(ci, ci_0, ci_1) +} + +@(private) +enc_sw :: proc "contextless" (st: ^State_SW, dst, src: []byte) #no_bounds_check { + ci, xi, l := dst, src, len(src) + + switch st.rate { + case _RATE_128L: + for l >= _RATE_128L { + enc_sw_128l(st, ci, xi) + ci = ci[_RATE_128L:] + xi = xi[_RATE_128L:] + l -= _RATE_128L + } + case _RATE_256: + for l >= _RATE_256 { + enc_sw_256(st, ci, xi) + ci = ci[_RATE_256:] + xi = xi[_RATE_256:] + l -= _RATE_256 + } + } + + // Pad out the remainder with `0`s till it is rate sized. + if l > 0 { + tmp: [_RATE_MAX]byte // Ciphertext is not confidential. + copy(tmp[:], xi) + switch st.rate { + case _RATE_128L: + enc_sw_128l(st, tmp[:], tmp[:]) + case _RATE_256: + enc_sw_256(st, tmp[:], tmp[:]) + } + copy(ci, tmp[:l]) + } +} + +@(private = "file") +dec_sw_128l :: #force_inline proc "contextless" (st: ^State_SW, xi, ci: []byte) #no_bounds_check { + z0_0, z0_1, z1_0, z1_1 := z_sw_128l(st) + + t0_0, t0_1 := aes.load_interleaved(ci[:16]) + t1_0, t1_1 := aes.load_interleaved(ci[16:]) + out0_0, out0_1 := aes.xor_interleaved(t0_0, t0_1, z0_0, z0_1) + out1_0, out1_1 := aes.xor_interleaved(t1_0, t1_1, z1_0, z1_1) + + update_sw_128l(st, out0_0, out0_1, out1_0, out1_1) + aes.store_interleaved(xi[:16], out0_0, out0_1) + aes.store_interleaved(xi[16:], out1_0, out1_1) +} + +@(private = "file") +dec_sw_256 :: #force_inline proc "contextless" (st: ^State_SW, xi, ci: []byte) #no_bounds_check { + z_0, z_1 := z_sw_256(st) + + ci_0, ci_1 := aes.load_interleaved(ci) + xi_0, xi_1 := aes.xor_interleaved(ci_0, ci_1, z_0, z_1) + + update_sw_256(st, xi_0, xi_1) + aes.store_interleaved(xi, xi_0, xi_1) +} + +@(private = "file") +dec_partial_sw_128l :: proc "contextless" (st: ^State_SW, xn, cn: []byte) #no_bounds_check { + tmp: [_RATE_128L]byte + defer mem.zero_explicit(&tmp, size_of(tmp)) + + z0_0, z0_1, z1_0, z1_1 := z_sw_128l(st) + copy(tmp[:], cn) + + t0_0, t0_1 := aes.load_interleaved(tmp[:16]) + t1_0, t1_1 := aes.load_interleaved(tmp[16:]) + out0_0, out0_1 := aes.xor_interleaved(t0_0, t0_1, z0_0, z0_1) + out1_0, out1_1 := aes.xor_interleaved(t1_0, t1_1, z1_0, z1_1) + + aes.store_interleaved(tmp[:16], out0_0, out0_1) + aes.store_interleaved(tmp[16:], out1_0, out1_1) + copy(xn, tmp[:]) + + for off := len(xn); off < _RATE_128L; off += 1 { + tmp[off] = 0 + } + out0_0, out0_1 = aes.load_interleaved(tmp[:16]) + out1_0, out1_1 = aes.load_interleaved(tmp[16:]) + update_sw_128l(st, out0_0, out0_1, out1_0, out1_1) +} + +@(private = "file") +dec_partial_sw_256 :: proc "contextless" (st: ^State_SW, xn, cn: []byte) #no_bounds_check { + tmp: [_RATE_256]byte + defer mem.zero_explicit(&tmp, size_of(tmp)) + + z_0, z_1 := z_sw_256(st) + copy(tmp[:], cn) + + cn_0, cn_1 := aes.load_interleaved(tmp[:]) + xn_0, xn_1 := aes.xor_interleaved(cn_0, cn_1, z_0, z_1) + + aes.store_interleaved(tmp[:], xn_0, xn_1) + copy(xn, tmp[:]) + + for off := len(xn); off < _RATE_256; off += 1 { + tmp[off] = 0 + } + xn_0, xn_1 = aes.load_interleaved(tmp[:]) + update_sw_256(st, xn_0, xn_1) +} + +@(private) +dec_sw :: proc "contextless" (st: ^State_SW, dst, src: []byte) #no_bounds_check { + xi, ci, l := dst, src, len(src) + + switch st.rate { + case _RATE_128L: + for l >= _RATE_128L { + dec_sw_128l(st, xi, ci) + xi = xi[_RATE_128L:] + ci = ci[_RATE_128L:] + l -= _RATE_128L + } + case _RATE_256: + for l >= _RATE_256 { + dec_sw_256(st, xi, ci) + xi = xi[_RATE_256:] + ci = ci[_RATE_256:] + l -= _RATE_256 + } + } + + // Process the remainder. + if l > 0 { + switch st.rate { + case _RATE_128L: + dec_partial_sw_128l(st, xi, ci) + case _RATE_256: + dec_partial_sw_256(st, xi, ci) + } + } +} + +@(private) +finalize_sw :: proc "contextless" (st: ^State_SW, tag: []byte, ad_len, msg_len: int) { + tmp: [16]byte + endian.unchecked_put_u64le(tmp[0:], u64(ad_len) * 8) + endian.unchecked_put_u64le(tmp[8:], u64(msg_len) * 8) + + t_0, t_1 := aes.load_interleaved(tmp[:]) + + t0_0, t0_1, t1_0, t1_1: u64 = ---, ---, ---, --- + switch st.rate { + case _RATE_128L: + t_0, t_1 = aes.xor_interleaved(st.s2_0, st.s2_1, t_0, t_1) + for _ in 0 ..< 7 { + update_sw_128l(st, t_0, t_1, t_0, t_1) + } + + t0_0, t0_1 = aes.xor_interleaved(st.s0_0, st.s0_1, st.s1_0, st.s1_1) + t0_0, t0_1 = aes.xor_interleaved(t0_0, t0_1, st.s2_0, st.s2_1) + t0_0, t0_1 = aes.xor_interleaved(t0_0, t0_1, st.s3_0, st.s3_1) + + t1_0, t1_1 = aes.xor_interleaved(st.s4_0, st.s4_1, st.s5_0, st.s5_1) + t1_0, t1_1 = aes.xor_interleaved(t1_0, t1_1, st.s6_0, st.s6_1) + if len(tag) == TAG_SIZE_256 { + t1_0, t1_1 = aes.xor_interleaved(t1_0, t1_1, st.s7_0, st.s7_1) + } + case _RATE_256: + t_0, t_1 = aes.xor_interleaved(st.s3_0, st.s3_1, t_0, t_1) + for _ in 0 ..< 7 { + update_sw_256(st, t_0, t_1) + } + + t0_0, t0_1 = aes.xor_interleaved(st.s0_0, st.s0_1, st.s1_0, st.s1_1) + t0_0, t0_1 = aes.xor_interleaved(t0_0, t0_1, st.s2_0, st.s2_1) + + t1_0, t1_1 = aes.xor_interleaved(st.s3_0, st.s3_1, st.s4_0, st.s4_1) + t1_0, t1_1 = aes.xor_interleaved(t1_0, t1_1, st.s5_0, st.s5_1) + } + switch len(tag) { + case TAG_SIZE_128: + t0_0, t0_1 = aes.xor_interleaved(t0_0, t0_1, t1_0, t1_1) + aes.store_interleaved(tag, t0_0, t0_1) + case TAG_SIZE_256: + aes.store_interleaved(tag[:16], t0_0, t0_1) + aes.store_interleaved(tag[16:], t1_0, t1_1) + } +} + +@(private) +reset_state_sw :: proc "contextless" (st: ^State_SW) { + mem.zero_explicit(st, size_of(st^)) +} diff --git a/core/crypto/aegis/aegis_impl_hw_gen.odin b/core/crypto/aegis/aegis_impl_hw_gen.odin new file mode 100644 index 000000000..5ec2f3d6e --- /dev/null +++ b/core/crypto/aegis/aegis_impl_hw_gen.odin @@ -0,0 +1,44 @@ +#+build !amd64 +package aegis + +@(private = "file") +ERR_HW_NOT_SUPPORTED :: "crypto/aegis: hardware implementation unsupported" + +@(private) +State_HW :: struct {} + +// is_hardware_accelerated returns true iff hardware accelerated AEGIS +// is supported. +is_hardware_accelerated :: proc "contextless" () -> bool { + return false +} + +@(private) +init_hw :: proc "contextless" (ctx: ^Context, st: ^State_HW, iv: []byte) { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} + +@(private) +absorb_hw :: proc "contextless" (st: ^State_HW, aad: []byte) { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} + +@(private) +enc_hw :: proc "contextless" (st: ^State_HW, dst, src: []byte) { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} + +@(private) +dec_hw :: proc "contextless" (st: ^State_HW, dst, src: []byte) { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} + +@(private) +finalize_hw :: proc "contextless" (st: ^State_HW, tag: []byte, ad_len, msg_len: int) { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} + +@(private) +reset_state_hw :: proc "contextless" (st: ^State_HW) { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} diff --git a/core/crypto/aegis/aegis_impl_hw_intel.odin b/core/crypto/aegis/aegis_impl_hw_intel.odin new file mode 100644 index 000000000..5334f3258 --- /dev/null +++ b/core/crypto/aegis/aegis_impl_hw_intel.odin @@ -0,0 +1,389 @@ +#+build amd64 +package aegis + +import "base:intrinsics" +import "core:crypto/aes" +import "core:encoding/endian" +import "core:mem" +import "core:simd/x86" + +@(private) +State_HW :: struct { + s0: x86.__m128i, + s1: x86.__m128i, + s2: x86.__m128i, + s3: x86.__m128i, + s4: x86.__m128i, + s5: x86.__m128i, + s6: x86.__m128i, + s7: x86.__m128i, + rate: int, +} + +// is_hardware_accelerated returns true iff hardware accelerated AEGIS +// is supported. +is_hardware_accelerated :: proc "contextless" () -> bool { + return aes.is_hardware_accelerated() +} + +@(private, enable_target_feature = "sse2,aes") +init_hw :: proc "contextless" (ctx: ^Context, st: ^State_HW, iv: []byte) { + switch ctx._key_len { + case KEY_SIZE_128L: + key := intrinsics.unaligned_load((^x86.__m128i)(&ctx._key[0])) + iv := intrinsics.unaligned_load((^x86.__m128i)(raw_data(iv))) + + st.s0 = x86._mm_xor_si128(key, iv) + st.s1 = intrinsics.unaligned_load((^x86.__m128i)(&_C1[0])) + st.s2 = intrinsics.unaligned_load((^x86.__m128i)(&_C0[0])) + st.s3 = st.s1 + st.s4 = st.s0 + st.s5 = x86._mm_xor_si128(key, st.s2) // key ^ C0 + st.s6 = x86._mm_xor_si128(key, st.s1) // key ^ C1 + st.s7 = st.s5 + st.rate = _RATE_128L + + for _ in 0 ..< 10 { + update_hw_128l(st, iv, key) + } + case KEY_SIZE_256: + k0 := intrinsics.unaligned_load((^x86.__m128i)(&ctx._key[0])) + k1 := intrinsics.unaligned_load((^x86.__m128i)(&ctx._key[16])) + n0 := intrinsics.unaligned_load((^x86.__m128i)(&iv[0])) + n1 := intrinsics.unaligned_load((^x86.__m128i)(&iv[16])) + + st.s0 = x86._mm_xor_si128(k0, n0) + st.s1 = x86._mm_xor_si128(k1, n1) + st.s2 = intrinsics.unaligned_load((^x86.__m128i)(&_C1[0])) + st.s3 = intrinsics.unaligned_load((^x86.__m128i)(&_C0[0])) + st.s4 = x86._mm_xor_si128(k0, st.s3) // k0 ^ C0 + st.s5 = x86._mm_xor_si128(k1, st.s2) // k1 ^ C1 + st.rate = _RATE_256 + + u0, u1 := st.s0, st.s1 + for _ in 0 ..< 4 { + update_hw_256(st, k0) + update_hw_256(st, k1) + update_hw_256(st, u0) + update_hw_256(st, u1) + } + } +} + +@(private = "file", enable_target_feature = "sse2,aes") +update_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, m0, m1: x86.__m128i) { + s0_ := x86._mm_aesenc_si128(st.s7, x86._mm_xor_si128(st.s0, m0)) + s1_ := x86._mm_aesenc_si128(st.s0, st.s1) + s2_ := x86._mm_aesenc_si128(st.s1, st.s2) + s3_ := x86._mm_aesenc_si128(st.s2, st.s3) + s4_ := x86._mm_aesenc_si128(st.s3, x86._mm_xor_si128(st.s4, m1)) + s5_ := x86._mm_aesenc_si128(st.s4, st.s5) + s6_ := x86._mm_aesenc_si128(st.s5, st.s6) + s7_ := x86._mm_aesenc_si128(st.s6, st.s7) + st.s0, st.s1, st.s2, st.s3, st.s4, st.s5, st.s6, st.s7 = s0_, s1_, s2_, s3_, s4_, s5_, s6_, s7_ +} + +@(private = "file", enable_target_feature = "sse2,aes") +update_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, m: x86.__m128i) { + s0_ := x86._mm_aesenc_si128(st.s5, x86._mm_xor_si128(st.s0, m)) + s1_ := x86._mm_aesenc_si128(st.s0, st.s1) + s2_ := x86._mm_aesenc_si128(st.s1, st.s2) + s3_ := x86._mm_aesenc_si128(st.s2, st.s3) + s4_ := x86._mm_aesenc_si128(st.s3, st.s4) + s5_ := x86._mm_aesenc_si128(st.s4, st.s5) + st.s0, st.s1, st.s2, st.s3, st.s4, st.s5 = s0_, s1_, s2_, s3_, s4_, s5_ +} + +@(private = "file", enable_target_feature = "sse2,aes") +absorb_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, ai: []byte) { + t0 := intrinsics.unaligned_load((^x86.__m128i)(&ai[0])) + t1 := intrinsics.unaligned_load((^x86.__m128i)(&ai[16])) + update_hw_128l(st, t0, t1) +} + +@(private = "file", enable_target_feature = "sse2,aes") +absorb_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, ai: []byte) { + m := intrinsics.unaligned_load((^x86.__m128i)(&ai[0])) + update_hw_256(st, m) +} + +@(private, enable_target_feature = "sse2,aes") +absorb_hw :: proc "contextless" (st: ^State_HW, aad: []byte) #no_bounds_check { + ai, l := aad, len(aad) + + switch st.rate { + case _RATE_128L: + for l >= _RATE_128L { + absorb_hw_128l(st, ai) + ai = ai[_RATE_128L:] + l -= _RATE_128L + } + case _RATE_256: + for l >= _RATE_256 { + absorb_hw_256(st, ai) + + ai = ai[_RATE_256:] + l -= _RATE_256 + } + } + + // Pad out the remainder with `0`s till it is rate sized. + if l > 0 { + tmp: [_RATE_MAX]byte // AAD is not confidential. + copy(tmp[:], ai) + switch st.rate { + case _RATE_128L: + absorb_hw_128l(st, tmp[:]) + case _RATE_256: + absorb_hw_256(st, tmp[:]) + } + } +} + +@(private = "file", enable_target_feature = "sse2", require_results) +z_hw_128l :: #force_inline proc "contextless" (st: ^State_HW) -> (x86.__m128i, x86.__m128i) { + z0 := x86._mm_xor_si128( + st.s6, + x86._mm_xor_si128( + st.s1, + x86._mm_and_si128(st.s2, st.s3), + ), + ) + z1 := x86._mm_xor_si128( + st.s2, + x86._mm_xor_si128( + st.s5, + x86._mm_and_si128(st.s6, st.s7), + ), + ) + return z0, z1 +} + +@(private = "file", enable_target_feature = "sse2", require_results) +z_hw_256 :: #force_inline proc "contextless" (st: ^State_HW) -> x86.__m128i { + return x86._mm_xor_si128( + st.s1, + x86._mm_xor_si128( + st.s4, + x86._mm_xor_si128( + st.s5, + x86._mm_and_si128(st.s2, st.s3), + ), + ), + ) +} + +@(private = "file", enable_target_feature = "sse2,aes") +enc_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, ci, xi: []byte) #no_bounds_check { + z0, z1 := z_hw_128l(st) + + t0 := intrinsics.unaligned_load((^x86.__m128i)(&xi[0])) + t1 := intrinsics.unaligned_load((^x86.__m128i)(&xi[16])) + update_hw_128l(st, t0, t1) + + out0 := x86._mm_xor_si128(t0, z0) + out1 := x86._mm_xor_si128(t1, z1) + intrinsics.unaligned_store((^x86.__m128i)(&ci[0]), out0) + intrinsics.unaligned_store((^x86.__m128i)(&ci[16]), out1) +} + +@(private = "file", enable_target_feature = "sse2,aes") +enc_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, ci, xi: []byte) #no_bounds_check { + z := z_hw_256(st) + + xi_ := intrinsics.unaligned_load((^x86.__m128i)(raw_data(xi))) + update_hw_256(st, xi_) + + ci_ := x86._mm_xor_si128(xi_, z) + intrinsics.unaligned_store((^x86.__m128i)(raw_data(ci)), ci_) +} + +@(private, enable_target_feature = "sse2,aes") +enc_hw :: proc "contextless" (st: ^State_HW, dst, src: []byte) #no_bounds_check { + ci, xi, l := dst, src, len(src) + + switch st.rate { + case _RATE_128L: + for l >= _RATE_128L { + enc_hw_128l(st, ci, xi) + ci = ci[_RATE_128L:] + xi = xi[_RATE_128L:] + l -= _RATE_128L + } + case _RATE_256: + for l >= _RATE_256 { + enc_hw_256(st, ci, xi) + ci = ci[_RATE_256:] + xi = xi[_RATE_256:] + l -= _RATE_256 + } + } + + // Pad out the remainder with `0`s till it is rate sized. + if l > 0 { + tmp: [_RATE_MAX]byte // Ciphertext is not confidential. + copy(tmp[:], xi) + switch st.rate { + case _RATE_128L: + enc_hw_128l(st, tmp[:], tmp[:]) + case _RATE_256: + enc_hw_256(st, tmp[:], tmp[:]) + } + copy(ci, tmp[:l]) + } +} + +@(private = "file", enable_target_feature = "sse2,aes") +dec_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, xi, ci: []byte) #no_bounds_check { + z0, z1 := z_hw_128l(st) + + t0 := intrinsics.unaligned_load((^x86.__m128i)(&ci[0])) + t1 := intrinsics.unaligned_load((^x86.__m128i)(&ci[16])) + out0 := x86._mm_xor_si128(t0, z0) + out1 := x86._mm_xor_si128(t1, z1) + + update_hw_128l(st, out0, out1) + intrinsics.unaligned_store((^x86.__m128i)(&xi[0]), out0) + intrinsics.unaligned_store((^x86.__m128i)(&xi[16]), out1) +} + +@(private = "file", enable_target_feature = "sse2,aes") +dec_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, xi, ci: []byte) #no_bounds_check { + z := z_hw_256(st) + + ci_ := intrinsics.unaligned_load((^x86.__m128i)(raw_data(ci))) + xi_ := x86._mm_xor_si128(ci_, z) + + update_hw_256(st, xi_) + intrinsics.unaligned_store((^x86.__m128i)(raw_data(xi)), xi_) +} + +@(private = "file", enable_target_feature = "sse2,aes") +dec_partial_hw_128l :: #force_inline proc "contextless" (st: ^State_HW, xn, cn: []byte) #no_bounds_check { + tmp: [_RATE_128L]byte + defer mem.zero_explicit(&tmp, size_of(tmp)) + + z0, z1 := z_hw_128l(st) + copy(tmp[:], cn) + + t0 := intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) + t1 := intrinsics.unaligned_load((^x86.__m128i)(&tmp[16])) + out0 := x86._mm_xor_si128(t0, z0) + out1 := x86._mm_xor_si128(t1, z1) + + intrinsics.unaligned_store((^x86.__m128i)(&tmp[0]), out0) + intrinsics.unaligned_store((^x86.__m128i)(&tmp[16]), out1) + copy(xn, tmp[:]) + + for off := len(xn); off < _RATE_128L; off += 1 { + tmp[off] = 0 + } + out0 = intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) // v0 + out1 = intrinsics.unaligned_load((^x86.__m128i)(&tmp[16])) // v1 + update_hw_128l(st, out0, out1) +} + +@(private = "file", enable_target_feature = "sse2,aes") +dec_partial_hw_256 :: #force_inline proc "contextless" (st: ^State_HW, xn, cn: []byte) #no_bounds_check { + tmp: [_RATE_256]byte + defer mem.zero_explicit(&tmp, size_of(tmp)) + + z := z_hw_256(st) + copy(tmp[:], cn) + + cn_ := intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) + xn_ := x86._mm_xor_si128(cn_, z) + + intrinsics.unaligned_store((^x86.__m128i)(&tmp[0]), xn_) + copy(xn, tmp[:]) + + for off := len(xn); off < _RATE_256; off += 1 { + tmp[off] = 0 + } + xn_ = intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) + update_hw_256(st, xn_) +} + +@(private, enable_target_feature = "sse2,aes") +dec_hw :: proc "contextless" (st: ^State_HW, dst, src: []byte) #no_bounds_check { + xi, ci, l := dst, src, len(src) + + switch st.rate { + case _RATE_128L: + for l >= _RATE_128L { + dec_hw_128l(st, xi, ci) + xi = xi[_RATE_128L:] + ci = ci[_RATE_128L:] + l -= _RATE_128L + } + case _RATE_256: + for l >= _RATE_256 { + dec_hw_256(st, xi, ci) + xi = xi[_RATE_256:] + ci = ci[_RATE_256:] + l -= _RATE_256 + } + } + + // Process the remainder. + if l > 0 { + switch st.rate { + case _RATE_128L: + dec_partial_hw_128l(st, xi, ci) + case _RATE_256: + dec_partial_hw_256(st, xi, ci) + } + } +} + +@(private, enable_target_feature = "sse2,aes") +finalize_hw :: proc "contextless" (st: ^State_HW, tag: []byte, ad_len, msg_len: int) { + tmp: [16]byte + endian.unchecked_put_u64le(tmp[0:], u64(ad_len) * 8) + endian.unchecked_put_u64le(tmp[8:], u64(msg_len) * 8) + + t := intrinsics.unaligned_load((^x86.__m128i)(&tmp[0])) + + t0, t1: x86.__m128i = ---, --- + switch st.rate { + case _RATE_128L: + t = x86._mm_xor_si128(st.s2, t) + for _ in 0 ..< 7 { + update_hw_128l(st, t, t) + } + + t0 = x86._mm_xor_si128(st.s0, st.s1) + t0 = x86._mm_xor_si128(t0, st.s2) + t0 = x86._mm_xor_si128(t0, st.s3) + + t1 = x86._mm_xor_si128(st.s4, st.s5) + t1 = x86._mm_xor_si128(t1, st.s6) + if len(tag) == TAG_SIZE_256 { + t1 = x86._mm_xor_si128(t1, st.s7) + } + case _RATE_256: + t = x86._mm_xor_si128(st.s3, t) + for _ in 0 ..< 7 { + update_hw_256(st, t) + } + + t0 = x86._mm_xor_si128(st.s0, st.s1) + t0 = x86._mm_xor_si128(t0, st.s2) + + t1 = x86._mm_xor_si128(st.s3, st.s4) + t1 = x86._mm_xor_si128(t1, st.s5) + } + switch len(tag) { + case TAG_SIZE_128: + t0 = x86._mm_xor_si128(t0, t1) + intrinsics.unaligned_store((^x86.__m128i)(&tag[0]), t0) + case TAG_SIZE_256: + intrinsics.unaligned_store((^x86.__m128i)(&tag[0]), t0) + intrinsics.unaligned_store((^x86.__m128i)(&tag[16]), t1) + } +} + +@(private) +reset_state_hw :: proc "contextless" (st: ^State_HW) { + mem.zero_explicit(st, size_of(st^)) +} diff --git a/core/crypto/aes/aes_ctr.odin b/core/crypto/aes/aes_ctr.odin index 20b75e57f..a74133235 100644 --- a/core/crypto/aes/aes_ctr.odin +++ b/core/crypto/aes/aes_ctr.odin @@ -21,9 +21,7 @@ Context_CTR :: struct { // init_ctr initializes a Context_CTR with the provided key and IV. init_ctr :: proc(ctx: ^Context_CTR, key, iv: []byte, impl := DEFAULT_IMPLEMENTATION) { - if len(iv) != CTR_IV_SIZE { - panic("crypto/aes: invalid CTR IV size") - } + ensure(len(iv) == CTR_IV_SIZE, "crypto/aes: invalid CTR IV size") init_impl(&ctx._impl, key, impl) ctx._off = BLOCK_SIZE @@ -36,16 +34,14 @@ init_ctr :: proc(ctx: ^Context_CTR, key, iv: []byte, impl := DEFAULT_IMPLEMENTAT // keystream, and writes the resulting output to dst. dst and src MUST // alias exactly or not at all. xor_bytes_ctr :: proc(ctx: ^Context_CTR, dst, src: []byte) { - assert(ctx._is_initialized) + ensure(ctx._is_initialized) src, dst := src, dst if dst_len := len(dst); dst_len < len(src) { src = src[:dst_len] } - if bytes.alias_inexactly(dst, src) { - panic("crypto/aes: dst and src alias inexactly") - } + ensure(!bytes.alias_inexactly(dst, src), "crypto/aes: dst and src alias inexactly") #no_bounds_check for remaining := len(src); remaining > 0; { // Process multiple blocks at once @@ -82,7 +78,7 @@ xor_bytes_ctr :: proc(ctx: ^Context_CTR, dst, src: []byte) { // keystream_bytes_ctr fills dst with the raw AES-CTR keystream output. keystream_bytes_ctr :: proc(ctx: ^Context_CTR, dst: []byte) { - assert(ctx._is_initialized) + ensure(ctx._is_initialized) dst := dst #no_bounds_check for remaining := len(dst); remaining > 0; { diff --git a/core/crypto/aes/aes_ecb.odin b/core/crypto/aes/aes_ecb.odin index 32476006c..cac62de5d 100644 --- a/core/crypto/aes/aes_ecb.odin +++ b/core/crypto/aes/aes_ecb.odin @@ -19,11 +19,9 @@ init_ecb :: proc(ctx: ^Context_ECB, key: []byte, impl := DEFAULT_IMPLEMENTATION) // encrypt_ecb encrypts the BLOCK_SIZE buffer src, and writes the result to dst. encrypt_ecb :: proc(ctx: ^Context_ECB, dst, src: []byte) { - assert(ctx._is_initialized) - - if len(dst) != BLOCK_SIZE || len(src) != BLOCK_SIZE { - panic("crypto/aes: invalid buffer size(s)") - } + ensure(ctx._is_initialized) + ensure(len(dst) == BLOCK_SIZE, "crypto/aes: invalid dst size") + ensure(len(dst) == BLOCK_SIZE, "crypto/aes: invalid src size") switch &impl in ctx._impl { case ct64.Context: @@ -35,11 +33,9 @@ encrypt_ecb :: proc(ctx: ^Context_ECB, dst, src: []byte) { // decrypt_ecb decrypts the BLOCK_SIZE buffer src, and writes the result to dst. decrypt_ecb :: proc(ctx: ^Context_ECB, dst, src: []byte) { - assert(ctx._is_initialized) - - if len(dst) != BLOCK_SIZE || len(src) != BLOCK_SIZE { - panic("crypto/aes: invalid buffer size(s)") - } + ensure(ctx._is_initialized) + ensure(len(dst) == BLOCK_SIZE, "crypto/aes: invalid dst size") + ensure(len(dst) == BLOCK_SIZE, "crypto/aes: invalid src size") switch &impl in ctx._impl { case ct64.Context: diff --git a/core/crypto/aes/aes_gcm.odin b/core/crypto/aes/aes_gcm.odin index 8616821ce..d349aa353 100644 --- a/core/crypto/aes/aes_gcm.odin +++ b/core/crypto/aes/aes_gcm.odin @@ -36,15 +36,11 @@ init_gcm :: proc(ctx: ^Context_GCM, key: []byte, impl := DEFAULT_IMPLEMENTATION) // // dst and plaintext MUST alias exactly or not at all. seal_gcm :: proc(ctx: ^Context_GCM, dst, tag, iv, aad, plaintext: []byte) { - assert(ctx._is_initialized) + ensure(ctx._is_initialized) gcm_validate_common_slice_sizes(tag, iv, aad, plaintext) - if len(dst) != len(plaintext) { - panic("crypto/aes: invalid destination ciphertext size") - } - if bytes.alias_inexactly(dst, plaintext) { - panic("crypto/aes: dst and plaintext alias inexactly") - } + ensure(len(dst) == len(plaintext), "crypto/aes: invalid destination ciphertext size") + ensure(!bytes.alias_inexactly(dst, plaintext), "crypto/aes: dst and plaintext alias inexactly") if impl, is_hw := ctx._impl.(Context_Impl_Hardware); is_hw { gcm_seal_hw(&impl, dst, tag, iv, aad, plaintext) @@ -76,15 +72,11 @@ seal_gcm :: proc(ctx: ^Context_GCM, dst, tag, iv, aad, plaintext: []byte) { // dst and plaintext MUST alias exactly or not at all. @(require_results) open_gcm :: proc(ctx: ^Context_GCM, dst, iv, aad, ciphertext, tag: []byte) -> bool { - assert(ctx._is_initialized) + ensure(ctx._is_initialized) gcm_validate_common_slice_sizes(tag, iv, aad, ciphertext) - if len(dst) != len(ciphertext) { - panic("crypto/aes: invalid destination plaintext size") - } - if bytes.alias_inexactly(dst, ciphertext) { - panic("crypto/aes: dst and ciphertext alias inexactly") - } + ensure(len(dst) == len(ciphertext), "crypto/aes: invalid destination plaintext size") + ensure(!bytes.alias_inexactly(dst, ciphertext), "crypto/aes: dst and ciphertext alias inexactly") if impl, is_hw := ctx._impl.(Context_Impl_Hardware); is_hw { return gcm_open_hw(&impl, dst, iv, aad, ciphertext, tag) @@ -122,21 +114,13 @@ reset_gcm :: proc "contextless" (ctx: ^Context_GCM) { @(private = "file") gcm_validate_common_slice_sizes :: proc(tag, iv, aad, text: []byte) { - if len(tag) != GCM_TAG_SIZE { - panic("crypto/aes: invalid GCM tag size") - } + ensure(len(tag) == GCM_TAG_SIZE, "crypto/aes: invalid GCM tag size") // The specification supports IVs in the range [1, 2^64) bits. - if l := len(iv); l == 0 || u64(l) >= GCM_IV_SIZE_MAX { - panic("crypto/aes: invalid GCM IV size") - } + ensure(len(iv) == 0 || u64(len(iv)) <= GCM_IV_SIZE_MAX, "crypto/aes: invalid GCM IV size") - if aad_len := u64(len(aad)); aad_len > GCM_A_MAX { - panic("crypto/aes: oversized GCM aad") - } - if text_len := u64(len(text)); text_len > GCM_P_MAX { - panic("crypto/aes: oversized GCM src data") - } + ensure(u64(len(aad)) <= GCM_A_MAX, "crypto/aes: oversized GCM aad") + ensure(u64(len(text)) <= GCM_P_MAX, "crypto/aes: oversized GCM data") } @(private = "file") diff --git a/core/crypto/aes/aes_gcm_hw_intel.odin b/core/crypto/aes/aes_gcm_hw_intel.odin index 4cb5ab3b2..3982d1452 100644 --- a/core/crypto/aes/aes_gcm_hw_intel.odin +++ b/core/crypto/aes/aes_gcm_hw_intel.odin @@ -235,7 +235,7 @@ gctr_hw :: proc( // BUG: Sticking this in gctr_hw (like the other implementations) crashes // the compiler. // -// src/check_expr.cpp(7892): Assertion Failure: `c->curr_proc_decl->entity` +// src/check_expr.cpp(8104): Assertion Failure: `c->curr_proc_decl->entity` @(private = "file", enable_target_feature = "sse4.1") hw_inc_ctr32 :: #force_inline proc "contextless" (src: ^x86.__m128i, ctr: u32) -> (x86.__m128i, u32) { ret := x86._mm_insert_epi32(src^, i32(intrinsics.byte_swap(ctr)), 3) diff --git a/core/crypto/blake2b/blake2b.odin b/core/crypto/blake2b/blake2b.odin index 74396b103..3b3fc6649 100644 --- a/core/crypto/blake2b/blake2b.odin +++ b/core/crypto/blake2b/blake2b.odin @@ -18,7 +18,7 @@ package blake2b import "../_blake2" // DIGEST_SIZE is the BLAKE2b digest size in bytes. -DIGEST_SIZE :: 64 +DIGEST_SIZE :: _blake2.BLAKE2B_SIZE // BLOCK_SIZE is the BLAKE2b block size in bytes. BLOCK_SIZE :: _blake2.BLAKE2B_BLOCK_SIZE @@ -27,9 +27,11 @@ BLOCK_SIZE :: _blake2.BLAKE2B_BLOCK_SIZE Context :: _blake2.Blake2b_Context // init initializes a Context with the default BLAKE2b config. -init :: proc(ctx: ^Context) { +init :: proc(ctx: ^Context, digest_size := DIGEST_SIZE) { + ensure(digest_size <= _blake2.MAX_SIZE, "crypto/blake2b: invalid digest size") + cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2B_SIZE + cfg.size = u8(digest_size) _blake2.init(ctx, &cfg) } diff --git a/core/crypto/blake2s/blake2s.odin b/core/crypto/blake2s/blake2s.odin index 339ddf027..9bbd44541 100644 --- a/core/crypto/blake2s/blake2s.odin +++ b/core/crypto/blake2s/blake2s.odin @@ -18,7 +18,7 @@ package blake2s import "../_blake2" // DIGEST_SIZE is the BLAKE2s digest size in bytes. -DIGEST_SIZE :: 32 +DIGEST_SIZE :: _blake2.BLAKE2S_SIZE // BLOCK_SIZE is the BLAKE2s block size in bytes. BLOCK_SIZE :: _blake2.BLAKE2S_BLOCK_SIZE @@ -27,9 +27,11 @@ BLOCK_SIZE :: _blake2.BLAKE2S_BLOCK_SIZE Context :: _blake2.Blake2s_Context // init initializes a Context with the default BLAKE2s config. -init :: proc(ctx: ^Context) { +init :: proc(ctx: ^Context, digest_size := DIGEST_SIZE) { + ensure(digest_size <= _blake2.MAX_SIZE, "crypto/blake2s: invalid digest size") + cfg: _blake2.Blake2_Config - cfg.size = _blake2.BLAKE2S_SIZE + cfg.size = u8(digest_size) _blake2.init(ctx, &cfg) } diff --git a/core/crypto/chacha20/chacha20.odin b/core/crypto/chacha20/chacha20.odin index dfab2bc65..e8d67eb3e 100644 --- a/core/crypto/chacha20/chacha20.odin +++ b/core/crypto/chacha20/chacha20.odin @@ -27,12 +27,8 @@ Context :: struct { // init inititializes a Context for ChaCha20 or XChaCha20 with the provided // key and iv. init :: proc(ctx: ^Context, key, iv: []byte, impl := DEFAULT_IMPLEMENTATION) { - if len(key) != KEY_SIZE { - panic("crypto/chacha20: invalid (X)ChaCha20 key size") - } - if l := len(iv); l != IV_SIZE && l != XIV_SIZE { - panic("crypto/chacha20: invalid (X)ChaCha20 IV size") - } + ensure(len(key) == KEY_SIZE, "crypto/chacha20: invalid (X)ChaCha20 key size") + ensure(len(iv) == IV_SIZE || len(iv) == XIV_SIZE, "crypto/chacha20: invalid (X)ChaCha20 IV size") k, n := key, iv @@ -67,16 +63,14 @@ seek :: proc(ctx: ^Context, block_nr: u64) { // keystream, and writes the resulting output to dst. Dst and src MUST // alias exactly or not at all. xor_bytes :: proc(ctx: ^Context, dst, src: []byte) { - assert(ctx._state._is_initialized) + ensure(ctx._state._is_initialized) src, dst := src, dst if dst_len := len(dst); dst_len < len(src) { src = src[:dst_len] } - if bytes.alias_inexactly(dst, src) { - panic("crypto/chacha20: dst and src alias inexactly") - } + ensure(!bytes.alias_inexactly(dst, src), "crypto/chacha20: dst and src alias inexactly") st := &ctx._state #no_bounds_check for remaining := len(src); remaining > 0; { @@ -114,7 +108,7 @@ xor_bytes :: proc(ctx: ^Context, dst, src: []byte) { // keystream_bytes fills dst with the raw (X)ChaCha20 keystream output. keystream_bytes :: proc(ctx: ^Context, dst: []byte) { - assert(ctx._state._is_initialized) + ensure(ctx._state._is_initialized) dst, st := dst, &ctx._state #no_bounds_check for remaining := len(dst); remaining > 0; { diff --git a/core/crypto/chacha20poly1305/chacha20poly1305.odin b/core/crypto/chacha20poly1305/chacha20poly1305.odin index 3de2532dd..6706b3820 100644 --- a/core/crypto/chacha20poly1305/chacha20poly1305.odin +++ b/core/crypto/chacha20poly1305/chacha20poly1305.odin @@ -29,13 +29,9 @@ _P_MAX :: 64 * 0xffffffff // 64 * (2^32-1) @(private) _validate_common_slice_sizes :: proc (tag, iv, aad, text: []byte, is_xchacha: bool) { - if len(tag) != TAG_SIZE { - panic("crypto/chacha20poly1305: invalid destination tag size") - } expected_iv_len := is_xchacha ? XIV_SIZE : IV_SIZE - if len(iv) != expected_iv_len { - panic("crypto/chacha20poly1305: invalid IV size") - } + ensure(len(tag) == TAG_SIZE, "crypto/chacha20poly1305: invalid destination tag size") + ensure(len(iv) == expected_iv_len, "crypto/chacha20poly1305: invalid IV size") #assert(size_of(int) == 8 || size_of(int) <= 4) when size_of(int) == 8 { @@ -45,13 +41,11 @@ _validate_common_slice_sizes :: proc (tag, iv, aad, text: []byte, is_xchacha: bo // A_MAX is limited by size_of(int), so there is no need to // enforce it. P_MAX only needs to be checked on 64-bit targets, // for reasons that should be obvious. - if text_len := len(text); text_len > _P_MAX { - panic("crypto/chacha20poly1305: oversized src data") - } + ensure(len(text) <= _P_MAX, "crypto/chacha20poly1305: oversized src data") } } -@(private) +@(private, rodata) _PAD: [16]byte @(private) @@ -71,9 +65,7 @@ Context :: struct { // init initializes a Context with the provided key, for AEAD_CHACHA20_POLY1305. init :: proc(ctx: ^Context, key: []byte, impl := chacha20.DEFAULT_IMPLEMENTATION) { - if len(key) != KEY_SIZE { - panic("crypto/chacha20poly1305: invalid key size") - } + ensure(len(key) == KEY_SIZE, "crypto/chacha20poly1305: invalid key size") copy(ctx._key[:], key) ctx._impl = impl @@ -96,11 +88,11 @@ init_xchacha :: proc(ctx: ^Context, key: []byte, impl := chacha20.DEFAULT_IMPLEM // // dst and plaintext MUST alias exactly or not at all. seal :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) { + ensure(ctx._is_initialized) + ciphertext := dst _validate_common_slice_sizes(tag, iv, aad, plaintext, ctx._is_xchacha) - if len(ciphertext) != len(plaintext) { - panic("crypto/chacha20poly1305: invalid destination ciphertext size") - } + ensure(len(ciphertext) == len(plaintext), "crypto/chacha20poly1305: invalid destination ciphertext size") stream_ctx: chacha20.Context = --- chacha20.init(&stream_ctx, ctx._key[:],iv, ctx._impl) @@ -151,11 +143,11 @@ seal :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) { // dst and plaintext MUST alias exactly or not at all. @(require_results) open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { + ensure(ctx._is_initialized) + plaintext := dst _validate_common_slice_sizes(tag, iv, aad, ciphertext, ctx._is_xchacha) - if len(ciphertext) != len(plaintext) { - panic("crypto/chacha20poly1305: invalid destination plaintext size") - } + ensure(len(ciphertext) == len(plaintext), "crypto/chacha20poly1305: invalid destination plaintext size") // Note: Unlike encrypt, this can fail early, so use defer for // sanitization rather than assuming control flow reaches certain diff --git a/core/crypto/deoxysii/deoxysii.odin b/core/crypto/deoxysii/deoxysii.odin new file mode 100644 index 000000000..cead770e2 --- /dev/null +++ b/core/crypto/deoxysii/deoxysii.odin @@ -0,0 +1,280 @@ +/* +package deoxysii implements the Deoxys-II-256 Authenticated Encryption +with Additional Data algorithm. + +- [[ https://sites.google.com/view/deoxyscipher ]] +- [[ https://thomaspeyrin.github.io/web/assets/docs/papers/Jean-etal-JoC2021.pdf ]] +*/ +package deoxysii + +import "base:intrinsics" +import "core:bytes" +import "core:crypto/aes" +import "core:mem" +import "core:simd" + +// KEY_SIZE is the Deoxys-II-256 key size in bytes. +KEY_SIZE :: 32 +// IV_SIZE iss the Deoxys-II-256 IV size in bytes. +IV_SIZE :: 15 // 120-bits +// TAG_SIZE is the Deoxys-II-256 tag size in bytes. +TAG_SIZE :: 16 + +@(private) +PREFIX_AD_BLOCK :: 0b0010 +@(private) +PREFIX_AD_FINAL :: 0b0110 +@(private) +PREFIX_MSG_BLOCK :: 0b0000 +@(private) +PREFIX_MSG_FINAL :: 0b0100 +@(private) +PREFIX_TAG :: 0b0001 +@(private) +PREFIX_SHIFT :: 4 + +@(private) +BC_ROUNDS :: 16 +@(private) +BLOCK_SIZE :: aes.BLOCK_SIZE + +@(private = "file") +_LFSR2_MASK :: simd.u8x16{ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +} +@(private = "file") +_LFSR3_MASK :: simd.u8x16{ + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +} +@(private = "file") +_LFSR_SH1 :: _LFSR2_MASK +@(private = "file") +_LFSR_SH5 :: simd.u8x16{ + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, +} +@(private = "file") +_LFSR_SH7 :: simd.u8x16{ + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, +} +@(private = "file", rodata) +_RCONS := []byte { + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, + 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, + 0x72, +} + +// Context is a keyed Deoxys-II-256 instance. +Context :: struct { + _subkeys: [BC_ROUNDS+1][16]byte, + _impl: aes.Implementation, + _is_initialized: bool, +} + +@(private) +_validate_common_slice_sizes :: proc (ctx: ^Context, tag, iv, aad, text: []byte) { + ensure(len(tag) == TAG_SIZE, "crypto/deoxysii: invalid tag size") + ensure(len(iv) == IV_SIZE, "crypto/deoxysii: invalid IV size") + + #assert(size_of(int) == 8 || size_of(int) <= 4) + // For the nonce-misuse resistant mode, the total size of the + // associated data and the total size of the message do not exceed + // `16 * 2^max_l * 2^max_m bytes`, thus 2^128 bytes for all variants + // of Deoxys-II. Moreover, the maximum number of messages that can + // be handled for a same key is 2^max_m, that is 2^64 for all variants + // of Deoxys. +} + +// init initializes a Context with the provided key. +init :: proc(ctx: ^Context, key: []byte, impl := aes.DEFAULT_IMPLEMENTATION) { + ensure(len(key) == KEY_SIZE, "crypto/deoxysii: invalid key size") + + ctx._impl = impl + if ctx._impl == .Hardware && !is_hardware_accelerated() { + ctx._impl = .Portable + } + + derive_ks(ctx, key) + + ctx._is_initialized = true +} + +// seal encrypts the plaintext and authenticates the aad and ciphertext, +// with the provided Context and iv, stores the output in dst and tag. +// +// dst and plaintext MUST alias exactly or not at all. +seal :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) { + ensure(ctx._is_initialized) + + _validate_common_slice_sizes(ctx, tag, iv, aad, plaintext) + ensure(len(dst) == len(plaintext), "crypto/deoxysii: invalid destination ciphertext size") + ensure(!bytes.alias_inexactly(dst, plaintext), "crypto/deoxysii: dst and plaintext alias inexactly") + + switch ctx._impl { + case .Hardware: + e_hw(ctx, dst, tag, iv, aad, plaintext) + case .Portable: + e_ref(ctx, dst, tag, iv, aad, plaintext) + } +} + +// open authenticates the aad and ciphertext, and decrypts the ciphertext, +// with the provided Context, iv, and tag, and stores the output in dst, +// returning true iff the authentication was successful. If authentication +// fails, the destination buffer will be zeroed. +// +// dst and plaintext MUST alias exactly or not at all. +@(require_results) +open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { + ensure(ctx._is_initialized) + + _validate_common_slice_sizes(ctx, tag, iv, aad, ciphertext) + ensure(len(dst) == len(ciphertext), "crypto/deoxysii: invalid destination plaintext size") + ensure(!bytes.alias_inexactly(dst, ciphertext), "crypto/deoxysii: dst and ciphertext alias inexactly") + + ok: bool + switch ctx._impl { + case .Hardware: + ok = d_hw(ctx, dst, iv, aad, ciphertext, tag) + case .Portable: + ok = d_ref(ctx, dst, iv, aad, ciphertext, tag) + } + if !ok { + mem.zero_explicit(raw_data(dst), len(ciphertext)) + } + + return ok +} + +// reset sanitizes the Context. The Context must be +// re-initialized to be used again. +reset :: proc "contextless" (ctx: ^Context) { + mem.zero_explicit(&ctx._subkeys, len(ctx._subkeys)) + ctx._is_initialized = false +} + +@(private = "file") +derive_ks :: proc "contextless" (ctx: ^Context, key: []byte) { + // Derive the constant component of each subtweakkey. + // + // The key schedule is as thus: + // + // STK_i = TK1_i ^ TK2_i ^ TK3_i ^ RC_i + // + // TK1_i = h(TK1_(i-1)) + // TK2_i = h(LFSR2(TK2_(i-1))) + // TK3_i = h(LFSR3(TK2_(i-1))) + // + // where: + // + // KT = K || T + // W3 = KT[:16] + // W2 = KT[16:32] + // W1 = KT[32:] + // + // TK1_0 = W1 + // TK2_0 = W2 + // TK3_0 = W3 + // + // As `K` is fixed per Context, the XORs of `TK3_0 .. TK3_n`, + // `TK2_0 .. TK2_n` and RC_i can be precomputed in advance like + // thus: + // + // subkey_i = TK3_i ^ TK2_i ^ RC_i + // + // When it is time to actually call Deoxys-BC-384, it is then + // a simple matter of deriving each round subtweakkey via: + // + // TK1_0 = T (Tweak) + // STK_0 = subkey_0 ^ TK1_0 + // STK_i = subkey_i (precomputed) ^ H(TK1_(i-1)) + // + // We opt to use SIMD here and for the subtweakkey deriviation + // as `H()` is typically a single vector instruction. + + tk2 := intrinsics.unaligned_load((^simd.u8x16)(raw_data(key[16:]))) + tk3 := intrinsics.unaligned_load((^simd.u8x16)(raw_data(key))) + + // subkey_0 does not apply LFSR2/3 or H. + intrinsics.unaligned_store( + (^simd.u8x16)(&ctx._subkeys[0]), + simd.bit_xor( + tk2, + simd.bit_xor( + tk3, + rcon(0), + ), + ), + ) + + // Precompute k_1 .. k_16. + for i in 1 ..< BC_ROUNDS+1 { + tk2 = h(lfsr2(tk2)) + tk3 = h(lfsr3(tk3)) + intrinsics.unaligned_store( + (^simd.u8x16)(&ctx._subkeys[i]), + simd.bit_xor( + tk2, + simd.bit_xor( + tk3, + rcon(i), + ), + ), + ) + } +} + +@(private = "file") +lfsr2 :: #force_inline proc "contextless" (tk: simd.u8x16) -> simd.u8x16 { + // LFSR2 is a application of the following LFSR to each byte of input. + // (x7||x6||x5||x4||x3||x2||x1||x0) -> (x6||x5||x4||x3||x2||x1||x0||x7 ^ x5) + return simd.bit_or( + simd.shl(tk, _LFSR_SH1), + simd.bit_and( + simd.bit_xor( + simd.shr(tk, _LFSR_SH7), // x7 + simd.shr(tk, _LFSR_SH5), // x5 + ), + _LFSR2_MASK, + ), + ) +} + +@(private = "file") +lfsr3 :: #force_inline proc "contextless" (tk: simd.u8x16) -> simd.u8x16 { + // LFSR3 is a application of the following LFSR to each byte of input. + // (x7||x6||x5||x4||x3||x2||x1||x0) -> (x0 ^ x6||x7||x6||x5||x4||x3||x2||x1) + return simd.bit_or( + simd.shr(tk, _LFSR_SH1), + simd.bit_and( + simd.bit_xor( + simd.shl(tk, _LFSR_SH7), // x0 + simd.shl(tk, _LFSR_SH1), // x6 + ), + _LFSR3_MASK, + ), + ) +} + +@(private) +h :: #force_inline proc "contextless" (tk: simd.u8x16) -> simd.u8x16 { + return simd.swizzle( + tk, + 0x01, 0x06, 0x0b, 0x0c, 0x05, 0x0a, 0x0f, 0x00, + 0x09, 0x0e, 0x03, 0x04, 0x0d, 0x02, 0x07, 0x08, + ) +} + +@(private = "file") +rcon :: #force_inline proc "contextless" (rd: int) -> simd.u8x16 #no_bounds_check { + rc := _RCONS[rd] + return simd.u8x16{ + 1, 2, 4, 8, + rc, rc, rc, rc, + 0, 0, 0, 0, + 0, 0, 0, 0, + } +} \ No newline at end of file diff --git a/core/crypto/deoxysii/deoxysii_impl_ct64.odin b/core/crypto/deoxysii/deoxysii_impl_ct64.odin new file mode 100644 index 000000000..c4d0edb03 --- /dev/null +++ b/core/crypto/deoxysii/deoxysii_impl_ct64.odin @@ -0,0 +1,399 @@ +package deoxysii + +import "base:intrinsics" +import "core:crypto" +import aes "core:crypto/_aes/ct64" +import "core:encoding/endian" +import "core:mem" +import "core:simd" + +// This uses the bitlsiced 64-bit general purpose register SWAR AES +// round function. The encryption pass skips orthogonalizing the +// AES round function input as it is aways going to be the leading 0 +// padded IV, and doing a 64-byte copy is faster. + +@(private = "file") +TWEAK_SIZE :: 16 + +@(private = "file") +State_SW :: struct { + ctx: ^Context, + q_stk, q_b: [8]u64, +} + +@(private = "file") +auth_tweak :: #force_inline proc "contextless" ( + dst: ^[TWEAK_SIZE]byte, + prefix: byte, + block_nr: int, +) { + endian.unchecked_put_u64be(dst[8:], u64(block_nr)) + endian.unchecked_put_u64le(dst[0:], u64(prefix) << PREFIX_SHIFT) // dst[0] = prefix << PREFIX_SHIFT +} + +@(private = "file") +enc_tweak :: #force_inline proc "contextless" ( + dst: ^[TWEAK_SIZE]byte, + tag: ^[TAG_SIZE]byte, + block_nr: int, +) { + tmp: [8]byte + endian.unchecked_put_u64be(tmp[:], u64(block_nr)) + + copy(dst[:], tag[:]) + dst[0] |= 0x80 + for i in 0 ..< 8 { + dst[i+8] ~= tmp[i] + } +} + +@(private = "file") +enc_plaintext :: #force_inline proc "contextless" ( + dst: ^[8]u64, + iv: []byte, +) { + tmp: [BLOCK_SIZE]byte = --- + tmp[0] = 0 + copy(tmp[1:], iv[:]) + + q_0, q_1 := aes.load_interleaved(tmp[:]) + for i in 0 ..< 4 { + dst[i], dst[i+4] = q_0, q_1 + } + aes.orthogonalize(dst) +} + +@(private = "file") +bc_x4 :: proc "contextless" ( + ctx: ^Context, + dst: []byte, + tweaks: ^[4][TWEAK_SIZE]byte, + q_stk: ^[8]u64, + q_b: ^[8]u64, // Orthogonalized + n: int, +) { + tk1s: [4]simd.u8x16 + for j in 0 ..< n { + tk1s[j] = intrinsics.unaligned_load((^simd.u8x16)(&tweaks[j])) + } + + // Deoxys-BC-384 + for i in 0 ..= BC_ROUNDS { + // Derive the round's subtweakkey + sk := intrinsics.unaligned_load((^simd.u8x16)(&ctx._subkeys[i])) + for j in 0 ..< n { + if i != 0 { + tk1s[j] = h(tk1s[j]) + } + intrinsics.unaligned_store( + (^simd.u8x16)(raw_data(dst)), + simd.bit_xor(sk, tk1s[j]), + ) + q_stk[j], q_stk[j+4] = aes.load_interleaved(dst[:]) + } + aes.orthogonalize(q_stk) + + if i != 0 { + aes.sub_bytes(q_b) + aes.shift_rows(q_b) + aes.mix_columns(q_b) + } + aes.add_round_key(q_b, q_stk[:]) + } + + aes.orthogonalize(q_b) + for i in 0 ..< n { + aes.store_interleaved(dst[i*BLOCK_SIZE:], q_b[i], q_b[i+4]) + } +} + +@(private = "file", require_results) +bc_absorb :: proc "contextless" ( + st: ^State_SW, + dst: []byte, + src: []byte, + tweak_prefix: byte, + stk_block_nr: int, +) -> int { + tweaks: [4][TWEAK_SIZE]byte = --- + tmp: [BLOCK_SIZE*4]byte = --- + + src, stk_block_nr := src, stk_block_nr + dst_ := intrinsics.unaligned_load((^simd.u8x16)(raw_data(dst))) + + nr_blocks := len(src) / BLOCK_SIZE + for nr_blocks > 0 { + // Derive the tweak(s), orthogonalize the plaintext + n := min(nr_blocks, 4) + for i in 0 ..< n { + auth_tweak(&tweaks[i], tweak_prefix, stk_block_nr + i) + st.q_b[i], st.q_b[i + 4] = aes.load_interleaved(src) + src = src[BLOCK_SIZE:] + } + aes.orthogonalize(&st.q_b) + + // Deoxys-BC-384 + bc_x4(st.ctx, tmp[:], &tweaks, &st.q_stk, &st.q_b, n) + + // XOR in the existing Auth/tag + for i in 0 ..< n { + dst_ = simd.bit_xor( + dst_, + intrinsics.unaligned_load((^simd.u8x16)(raw_data(tmp[i*BLOCK_SIZE:]))), + ) + } + + stk_block_nr += n + nr_blocks -= n + } + + intrinsics.unaligned_store((^simd.u8x16)(raw_data(dst)), dst_) + + mem.zero_explicit(&tweaks, size_of(tweaks)) + mem.zero_explicit(&tmp, size_of(tmp)) + + return stk_block_nr +} + +@(private = "file") +bc_final :: proc "contextless" ( + st: ^State_SW, + dst: []byte, + iv: []byte, +) { + tweaks: [4][TWEAK_SIZE]byte = --- + + tweaks[0][0] = PREFIX_TAG << PREFIX_SHIFT + copy(tweaks[0][1:], iv) + + st.q_b[0], st.q_b[4] = aes.load_interleaved(dst) + aes.orthogonalize(&st.q_b) + + bc_x4(st.ctx, dst, &tweaks, &st.q_stk, &st.q_b, 1) +} + +@(private = "file", require_results) +bc_encrypt :: proc "contextless" ( + st: ^State_SW, + dst: []byte, + src: []byte, + q_n: ^[8]u64, // Orthogonalized + tweak_tag: ^[TAG_SIZE]byte, + stk_block_nr: int, +) -> int { + tweaks: [4][TWEAK_SIZE]byte = --- + tmp: [BLOCK_SIZE*4]byte = --- + + dst, src, stk_block_nr := dst, src, stk_block_nr + + nr_blocks := len(src) / BLOCK_SIZE + for nr_blocks > 0 { + // Derive the tweak(s) + n := min(nr_blocks, 4) + for i in 0 ..< n { + enc_tweak(&tweaks[i], tweak_tag, stk_block_nr + i) + } + st.q_b = q_n^ // The plaintext is always `0^8 || N` + + // Deoxys-BC-384 + bc_x4(st.ctx, tmp[:], &tweaks, &st.q_stk, &st.q_b, n) + + // XOR the ciphertext + for i in 0 ..< n { + intrinsics.unaligned_store( + (^simd.u8x16)(raw_data(dst[i*BLOCK_SIZE:])), + simd.bit_xor( + intrinsics.unaligned_load((^simd.u8x16)(raw_data(src[i*BLOCK_SIZE:]))), + intrinsics.unaligned_load((^simd.u8x16)(raw_data(tmp[i*BLOCK_SIZE:]))), + ), + ) + } + + dst, src = dst[n*BLOCK_SIZE:], src[n*BLOCK_SIZE:] + stk_block_nr += n + nr_blocks -= n + } + + mem.zero_explicit(&tweaks, size_of(tweaks)) + mem.zero_explicit(&tmp, size_of(tmp)) + + return stk_block_nr +} + +@(private) +e_ref :: proc "contextless" (ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) #no_bounds_check { + st: State_SW = --- + st.ctx = ctx + + // Algorithm 3 + // + // Associated data + // A_1 || ... || A_la || A_∗ <- A where each |A_i| = n and |A_∗| < n + // Auth <- 0^n + // for i = 0 to la − 1 do + // Auth <- Auth ^ EK(0010 || i, A_i+1) + // end + // if A_∗ != nil then + // Auth <- Auth ^ EK(0110 || la, pad10∗(A_∗)) + // end + auth: [TAG_SIZE]byte + aad := aad + n := bc_absorb(&st, auth[:], aad, PREFIX_AD_BLOCK, 0) + aad = aad[n*BLOCK_SIZE:] + if l := len(aad); l > 0 { + a_star: [BLOCK_SIZE]byte + + copy(a_star[:], aad) + a_star[l] = 0x80 + + _ = bc_absorb(&st, auth[:], a_star[:], PREFIX_AD_FINAL, n) + } + + // Message authentication and tag generation + // M_1 || ... || M_l || M_∗ <- M where each |M_j| = n and |M_∗| < n + // tag <- Auth + // for j = 0 to l − 1 do + // tag <- tag ^ EK(0000 || j, M_j+1) + // end + // if M_∗ != nil then + // tag <- tag ^ EK(0100 || l, pad10∗(M_∗)) + // end + // tag <- EK(0001 || 0^4 || N, tag) + m := plaintext + n = bc_absorb(&st, auth[:], m, PREFIX_MSG_BLOCK, 0) + m = m[n*BLOCK_SIZE:] + if l := len(m); l > 0 { + m_star: [BLOCK_SIZE]byte + + copy(m_star[:], m) + m_star[l] = 0x80 + + _ = bc_absorb(&st, auth[:], m_star[:], PREFIX_MSG_FINAL, n) + } + bc_final(&st, auth[:], iv) + + // Message encryption + // for j = 0 to l − 1 do + // C_j <- M_j ^ EK(1 || tag ^ j, 0^8 || N) + // end + // if M_∗ != nil then + // C_∗ <- M_* ^ EK(1 || tag ^ l, 0^8 || N) + // end + // + // return (C_1 || ... || C_l || C_∗, tag) + q_iv: [8]u64 = --- + enc_plaintext(&q_iv, iv) + + m = plaintext + n = bc_encrypt(&st, dst, m, &q_iv, &auth, 0) + m = m[n*BLOCK_SIZE:] + if l := len(m); l > 0 { + m_star: [BLOCK_SIZE]byte + + copy(m_star[:], m) + _ = bc_encrypt(&st, m_star[:], m_star[:], &q_iv, &auth, n) + + copy(dst[n*BLOCK_SIZE:], m_star[:]) + + mem.zero_explicit(&m_star, size_of(m_star)) + } + + copy(tag, auth[:]) + + mem.zero_explicit(&st.q_stk, size_of(st.q_stk)) + mem.zero_explicit(&st.q_b, size_of(st.q_b)) +} + +@(private, require_results) +d_ref :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { + st: State_SW = --- + st.ctx = ctx + + // Algorithm 4 + // + // Message decryption + // C_1 || ... || C_l || C_∗ <- C where each |C_j| = n and |C_∗| < n + // for j = 0 to l − 1 do + // M_j <- C_j ^ EK(1 || tag ^ j, 0^8 || N) + // end + // if C_∗ != nil then + // M_∗ <- C_∗ ^ EK(1 || tag ^ l, 0^8 || N) + // end + q_iv: [8]u64 = --- + enc_plaintext(&q_iv, iv) + + auth: [TAG_SIZE]byte + copy(auth[:], tag) + + m := ciphertext + n := bc_encrypt(&st, dst, m, &q_iv, &auth, 0) + m = m[n*BLOCK_SIZE:] + if l := len(m); l > 0 { + m_star: [BLOCK_SIZE]byte + + copy(m_star[:], m) + _ = bc_encrypt(&st, m_star[:], m_star[:], &q_iv, &auth, n) + + copy(dst[n*BLOCK_SIZE:], m_star[:]) + + mem.zero_explicit(&m_star, size_of(m_star)) + } + + // Associated data + // A_1 || ... || Al_a || A_∗ <- A where each |Ai_| = n and |A_∗| < n + // Auth <- 0 + // for i = 0 to la − 1 do + // Auth <- Auth ^ EK(0010 || i, A_i+1) + // end + // if A∗ != nil then + // Auth <- Auth ^ EK(0110| | l_a, pad10∗(A_∗)) + // end + auth = 0 + aad := aad + n = bc_absorb(&st, auth[:], aad, PREFIX_AD_BLOCK, 0) + aad = aad[n*BLOCK_SIZE:] + if l := len(aad); l > 0 { + a_star: [BLOCK_SIZE]byte + + copy(a_star[:], aad) + a_star[l] = 0x80 + + _ = bc_absorb(&st, auth[:], a_star[:], PREFIX_AD_FINAL, n) + } + + // Message authentication and tag generation + // M_1 || ... || M_l || M_∗ <- M where each |M_j| = n and |M_∗| < n + // tag0 <- Auth + // for j = 0 to l − 1 do + // tag0 <- tag0 ^ EK(0000 || j, M_j+1) + // end + // if M_∗ != nil then + // tag0 <- tag0 ^ EK(0100 || l, pad10∗(M_∗)) + // end + // tag0 <- EK(0001 || 0^4 || N, tag0) + m = dst[:len(ciphertext)] + n = bc_absorb(&st, auth[:], m, PREFIX_MSG_BLOCK, 0) + m = m[n*BLOCK_SIZE:] + if l := len(m); l > 0 { + m_star: [BLOCK_SIZE]byte + + copy(m_star[:], m) + m_star[l] = 0x80 + + _ = bc_absorb(&st, auth[:], m_star[:], PREFIX_MSG_FINAL, n) + + mem.zero_explicit(&m_star, size_of(m_star)) + } + bc_final(&st, auth[:], iv) + + // Tag verification + // if tag0 = tag then return (M_1 || ... || M_l || M_∗) + // else return false + ok := crypto.compare_constant_time(auth[:], tag) == 1 + + mem.zero_explicit(&auth, size_of(auth)) + mem.zero_explicit(&st.q_stk, size_of(st.q_stk)) + mem.zero_explicit(&st.q_b, size_of(st.q_b)) + + return ok +} diff --git a/core/crypto/deoxysii/deoxysii_impl_hw_gen.odin b/core/crypto/deoxysii/deoxysii_impl_hw_gen.odin new file mode 100644 index 000000000..b0705ca62 --- /dev/null +++ b/core/crypto/deoxysii/deoxysii_impl_hw_gen.odin @@ -0,0 +1,21 @@ +#+build !amd64 +package deoxysii + +@(private = "file") +ERR_HW_NOT_SUPPORTED :: "crypto/deoxysii: hardware implementation unsupported" + +// is_hardware_accelerated returns true iff hardware accelerated Deoxys-II +// is supported. +is_hardware_accelerated :: proc "contextless" () -> bool { + return false +} + +@(private) +e_hw :: proc "contextless" (ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) #no_bounds_check { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} + +@(private, require_results) +d_hw :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} diff --git a/core/crypto/deoxysii/deoxysii_impl_hw_intel.odin b/core/crypto/deoxysii/deoxysii_impl_hw_intel.odin new file mode 100644 index 000000000..d268009a2 --- /dev/null +++ b/core/crypto/deoxysii/deoxysii_impl_hw_intel.odin @@ -0,0 +1,434 @@ +#+build amd64 +package deoxysii + +import "base:intrinsics" +import "core:crypto" +import "core:crypto/aes" +import "core:mem" +import "core:simd" +import "core:simd/x86" + +// This processes a maximum of 4 blocks at a time, as that is suitable +// for most current hardware that doesn't say "Xeon". + +@(private = "file") +_BIT_ENC :: x86.__m128i{0x80, 0} +@(private = "file") +_PREFIX_AD_BLOCK :: x86.__m128i{PREFIX_AD_BLOCK << PREFIX_SHIFT, 0} +@(private = "file") +_PREFIX_AD_FINAL :: x86.__m128i{PREFIX_AD_FINAL << PREFIX_SHIFT, 0} +@(private = "file") +_PREFIX_MSG_BLOCK :: x86.__m128i{PREFIX_MSG_BLOCK << PREFIX_SHIFT, 0} +@(private = "file") +_PREFIX_MSG_FINAL :: x86.__m128i{PREFIX_MSG_FINAL << PREFIX_SHIFT, 0} + +// is_hardware_accelerated returns true iff hardware accelerated Deoxys-II +// is supported. +is_hardware_accelerated :: proc "contextless" () -> bool { + return aes.is_hardware_accelerated() +} + +@(private = "file", enable_target_feature = "sse4.1", require_results) +auth_tweak :: #force_inline proc "contextless" ( + prefix: x86.__m128i, + block_nr: int, +) -> x86.__m128i { + return x86._mm_insert_epi64(prefix, i64(intrinsics.byte_swap(u64(block_nr))), 1) +} + +@(private = "file", enable_target_feature = "sse2", require_results) +enc_tweak :: #force_inline proc "contextless" ( + tag: x86.__m128i, + block_nr: int, +) -> x86.__m128i { + return x86._mm_xor_si128( + x86._mm_or_si128(tag, _BIT_ENC), + x86.__m128i{0, i64(intrinsics.byte_swap(u64(block_nr)))}, + ) +} + +@(private = "file", enable_target_feature = "ssse3", require_results) +h_ :: #force_inline proc "contextless" (tk1: x86.__m128i) -> x86.__m128i { + return transmute(x86.__m128i)h(transmute(simd.u8x16)tk1) +} + +@(private = "file", enable_target_feature = "sse2,ssse3,aes", require_results) +bc_x4 :: #force_inline proc "contextless" ( + ctx: ^Context, + s_0, s_1, s_2, s_3: x86.__m128i, + tweak_0, tweak_1, tweak_2, tweak_3: x86.__m128i, +) -> (x86.__m128i, x86.__m128i, x86.__m128i, x86.__m128i) #no_bounds_check { + s_0, s_1, s_2, s_3 := s_0, s_1, s_2, s_3 + tk1_0, tk1_1, tk1_2, tk1_3 := tweak_0, tweak_1, tweak_2, tweak_3 + + sk := intrinsics.unaligned_load((^x86.__m128i)(&ctx._subkeys[0])) + stk_0 := x86._mm_xor_si128(tk1_0, sk) + stk_1 := x86._mm_xor_si128(tk1_1, sk) + stk_2 := x86._mm_xor_si128(tk1_2, sk) + stk_3 := x86._mm_xor_si128(tk1_3, sk) + + s_0 = x86._mm_xor_si128(s_0, stk_0) + s_1 = x86._mm_xor_si128(s_1, stk_1) + s_2 = x86._mm_xor_si128(s_2, stk_2) + s_3 = x86._mm_xor_si128(s_3, stk_3) + + for i in 1 ..= BC_ROUNDS { + sk = intrinsics.unaligned_load((^x86.__m128i)(&ctx._subkeys[i])) + + tk1_0 = h_(tk1_0) + tk1_1 = h_(tk1_1) + tk1_2 = h_(tk1_2) + tk1_3 = h_(tk1_3) + + stk_0 = x86._mm_xor_si128(tk1_0, sk) + stk_1 = x86._mm_xor_si128(tk1_1, sk) + stk_2 = x86._mm_xor_si128(tk1_2, sk) + stk_3 = x86._mm_xor_si128(tk1_3, sk) + + s_0 = x86._mm_aesenc_si128(s_0, stk_0) + s_1 = x86._mm_aesenc_si128(s_1, stk_1) + s_2 = x86._mm_aesenc_si128(s_2, stk_2) + s_3 = x86._mm_aesenc_si128(s_3, stk_3) + } + + return s_0, s_1, s_2, s_3 +} + +@(private = "file", enable_target_feature = "sse2,ssse3,aes", require_results) +bc_x1 :: #force_inline proc "contextless" ( + ctx: ^Context, + s: x86.__m128i, + tweak: x86.__m128i, +) -> x86.__m128i #no_bounds_check { + s, tk1 := s, tweak + + sk := intrinsics.unaligned_load((^x86.__m128i)(&ctx._subkeys[0])) + stk := x86._mm_xor_si128(tk1, sk) + + s = x86._mm_xor_si128(s, stk) + + for i in 1 ..= BC_ROUNDS { + sk = intrinsics.unaligned_load((^x86.__m128i)(&ctx._subkeys[i])) + + tk1 = h_(tk1) + + stk = x86._mm_xor_si128(tk1, sk) + + s = x86._mm_aesenc_si128(s, stk) + } + + return s +} + +@(private = "file", enable_target_feature = "sse2,ssse3,sse4.1,aes", require_results) +bc_absorb :: proc "contextless" ( + ctx: ^Context, + tag: x86.__m128i, + src: []byte, + tweak_prefix: x86.__m128i, + stk_block_nr: int, +) -> (x86.__m128i, int) #no_bounds_check { + src, stk_block_nr, tag := src, stk_block_nr, tag + + nr_blocks := len(src) / BLOCK_SIZE + for nr_blocks >= 4 { + d_0, d_1, d_2, d_3 := bc_x4( + ctx, + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))), + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[BLOCK_SIZE:]))), + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[2*BLOCK_SIZE:]))), + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[3*BLOCK_SIZE:]))), + auth_tweak(tweak_prefix, stk_block_nr), + auth_tweak(tweak_prefix, stk_block_nr + 1), + auth_tweak(tweak_prefix, stk_block_nr + 2), + auth_tweak(tweak_prefix, stk_block_nr + 3), + ) + + tag = x86._mm_xor_si128(tag, d_0) + tag = x86._mm_xor_si128(tag, d_1) + tag = x86._mm_xor_si128(tag, d_2) + tag = x86._mm_xor_si128(tag, d_3) + + src = src[4*BLOCK_SIZE:] + stk_block_nr += 4 + nr_blocks -= 4 + } + + for nr_blocks > 0 { + d := bc_x1( + ctx, + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))), + auth_tweak(tweak_prefix, stk_block_nr), + ) + + tag = x86._mm_xor_si128(tag, d) + + src = src[BLOCK_SIZE:] + stk_block_nr += 1 + nr_blocks -= 1 + } + + return tag, stk_block_nr +} + +@(private = "file", enable_target_feature = "sse2,ssse3,aes", require_results) +bc_final :: proc "contextless" ( + ctx: ^Context, + tag: x86.__m128i, + iv: []byte, +) -> x86.__m128i { + tmp: [BLOCK_SIZE]byte + + tmp[0] = PREFIX_TAG << PREFIX_SHIFT + copy(tmp[1:], iv) + + tweak := intrinsics.unaligned_load((^x86.__m128i)(&tmp)) + + return bc_x1(ctx, tag, tweak) +} + +@(private = "file", enable_target_feature = "sse2,ssse3,aes", require_results) +bc_encrypt :: proc "contextless" ( + ctx: ^Context, + dst: []byte, + src: []byte, + iv: x86.__m128i, + tweak_tag: x86.__m128i, + stk_block_nr: int, +) -> int { + dst, src, stk_block_nr := dst, src, stk_block_nr + + nr_blocks := len(src) / BLOCK_SIZE + for nr_blocks >= 4 { + d_0, d_1, d_2, d_3 := bc_x4( + ctx, + iv, iv, iv, iv, + enc_tweak(tweak_tag, stk_block_nr), + enc_tweak(tweak_tag, stk_block_nr + 1), + enc_tweak(tweak_tag, stk_block_nr + 2), + enc_tweak(tweak_tag, stk_block_nr + 3), + ) + + intrinsics.unaligned_store( + (^x86.__m128i)(raw_data(dst)), + x86._mm_xor_si128( + d_0, + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))), + ), + ) + intrinsics.unaligned_store( + (^x86.__m128i)(raw_data(dst[BLOCK_SIZE:])), + x86._mm_xor_si128( + d_1, + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[BLOCK_SIZE:]))), + ), + ) + intrinsics.unaligned_store( + (^x86.__m128i)(raw_data(dst[2*BLOCK_SIZE:])), + x86._mm_xor_si128( + d_2, + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[2*BLOCK_SIZE:]))), + ), + ) + intrinsics.unaligned_store( + (^x86.__m128i)(raw_data(dst[3*BLOCK_SIZE:])), + x86._mm_xor_si128( + d_3, + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[3*BLOCK_SIZE:]))), + ), + ) + + src, dst = src[4*BLOCK_SIZE:], dst[4*BLOCK_SIZE:] + stk_block_nr += 4 + nr_blocks -= 4 + } + + for nr_blocks > 0 { + d := bc_x1( + ctx, + iv, + enc_tweak(tweak_tag, stk_block_nr), + ) + + intrinsics.unaligned_store( + (^x86.__m128i)(raw_data(dst)), + x86._mm_xor_si128( + d, + intrinsics.unaligned_load((^x86.__m128i)(raw_data(src))), + ), + ) + + src, dst = src[BLOCK_SIZE:], dst[BLOCK_SIZE:] + stk_block_nr += 1 + nr_blocks -= 1 + } + + return stk_block_nr +} + +@(private) +e_hw :: proc "contextless" (ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) #no_bounds_check { + tmp: [BLOCK_SIZE]byte + copy(tmp[1:], iv) + iv_ := intrinsics.unaligned_load((^x86.__m128i)(raw_data(&tmp))) + + // Algorithm 3 + // + // Associated data + // A_1 || ... || A_la || A_∗ <- A where each |A_i| = n and |A_∗| < n + // Auth <- 0^n + // for i = 0 to la − 1 do + // Auth <- Auth ^ EK(0010 || i, A_i+1) + // end + // if A_∗ != nil then + // Auth <- Auth ^ EK(0110 || la, pad10∗(A_∗)) + // end + auth: x86.__m128i + n: int + + aad := aad + auth, n = bc_absorb(ctx, auth, aad, _PREFIX_AD_BLOCK, 0) + aad = aad[n*BLOCK_SIZE:] + if l := len(aad); l > 0 { + a_star: [BLOCK_SIZE]byte + + copy(a_star[:], aad) + a_star[l] = 0x80 + + auth, _ = bc_absorb(ctx, auth, a_star[:], _PREFIX_AD_FINAL, n) + } + + // Message authentication and tag generation + // M_1 || ... || M_l || M_∗ <- M where each |M_j| = n and |M_∗| < n + // tag <- Auth + // for j = 0 to l − 1 do + // tag <- tag ^ EK(0000 || j, M_j+1) + // end + // if M_∗ != nil then + // tag <- tag ^ EK(0100 || l, pad10∗(M_∗)) + // end + // tag <- EK(0001 || 0^4 ||N, tag) + m := plaintext + auth, n = bc_absorb(ctx, auth, m, _PREFIX_MSG_BLOCK, 0) + m = m[n*BLOCK_SIZE:] + if l := len(m); l > 0 { + m_star: [BLOCK_SIZE]byte + + copy(m_star[:], m) + m_star[l] = 0x80 + + auth, _ = bc_absorb(ctx, auth, m_star[:], _PREFIX_MSG_FINAL, n) + } + auth = bc_final(ctx, auth, iv) + + // Message encryption + // for j = 0 to l − 1 do + // C_j <- M_j ^ EK(1 || tag ^ j, 0^8 || N) + // end + // if M_∗ != nil then + // C_∗ <- M_* ^ EK(1 || tag ^ l, 0^8 || N) + // end + // + // return (C_1 || ... || C_l || C_∗, tag) + m = plaintext + n = bc_encrypt(ctx, dst, m, iv_, auth, 0) + m = m[n*BLOCK_SIZE:] + if l := len(m); l > 0 { + m_star: [BLOCK_SIZE]byte + + copy(m_star[:], m) + _ = bc_encrypt(ctx, m_star[:], m_star[:], iv_, auth, n) + + copy(dst[n*BLOCK_SIZE:], m_star[:]) + } + + intrinsics.unaligned_store((^x86.__m128i)(raw_data(tag)), auth) +} + +@(private, require_results) +d_hw :: proc "contextless" (ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool { + tmp: [BLOCK_SIZE]byte + copy(tmp[1:], iv) + iv_ := intrinsics.unaligned_load((^x86.__m128i)(raw_data(&tmp))) + + // Algorithm 4 + // + // Message decryption + // C_1 || ... || C_l || C_∗ <- C where each |C_j| = n and |C_∗| < n + // for j = 0 to l − 1 do + // M_j <- C_j ^ EK(1 || tag ^ j, 0^8 || N) + // end + // if C_∗ != nil then + // M_∗ <- C_∗ ^ EK(1 || tag ^ l, 0^8 || N) + // end + auth := intrinsics.unaligned_load((^x86.__m128i)(raw_data(tag))) + + m := ciphertext + n := bc_encrypt(ctx, dst, m, iv_, auth, 0) + m = m[n*BLOCK_SIZE:] + if l := len(m); l > 0 { + m_star: [BLOCK_SIZE]byte + + copy(m_star[:], m) + _ = bc_encrypt(ctx, m_star[:], m_star[:], iv_, auth, n) + + copy(dst[n*BLOCK_SIZE:], m_star[:]) + + mem.zero_explicit(&m_star, size_of(m_star)) + } + + // Associated data + // A_1 || ... || Al_a || A_∗ <- A where each |Ai_| = n and |A_∗| < n + // Auth <- 0 + // for i = 0 to la − 1 do + // Auth <- Auth ^ EK(0010 || i, A_i+1) + // end + // if A∗ != nil then + // Auth <- Auth ^ EK(0110| | l_a, pad10∗(A_∗)) + // end + auth = x86.__m128i{0, 0} + aad := aad + auth, n = bc_absorb(ctx, auth, aad, _PREFIX_AD_BLOCK, 0) + aad = aad[BLOCK_SIZE*n:] + if l := len(aad); l > 0 { + a_star: [BLOCK_SIZE]byte + + copy(a_star[:], aad) + a_star[l] = 0x80 + + auth, _ = bc_absorb(ctx, auth, a_star[:], _PREFIX_AD_FINAL, n) + } + + // Message authentication and tag generation + // M_1 || ... || M_l || M_∗ <- M where each |M_j| = n and |M_∗| < n + // tag0 <- Auth + // for j = 0 to l − 1 do + // tag0 <- tag0 ^ EK(0000 || j, M_j+1) + // end + // if M_∗ != nil then + // tag0 <- tag0 ^ EK(0100 || l, pad10∗(M_∗)) + // end + // tag0 <- EK(0001 || 0^4 || N, tag0) + m = dst[:len(ciphertext)] + auth, n = bc_absorb(ctx, auth, m, _PREFIX_MSG_BLOCK, 0) + m = m[n*BLOCK_SIZE:] + if l := len(m); l > 0 { + m_star: [BLOCK_SIZE]byte + + copy(m_star[:], m) + m_star[l] = 0x80 + + auth, _ = bc_absorb(ctx, auth, m_star[:], _PREFIX_MSG_FINAL, n) + } + auth = bc_final(ctx, auth, iv) + + // Tag verification + // if tag0 = tag then return (M_1 || ... || M_l || M_∗) + // else return false + intrinsics.unaligned_store((^x86.__m128i)(raw_data(&tmp)), auth) + ok := crypto.compare_constant_time(tmp[:], tag) == 1 + + mem.zero_explicit(&tmp, size_of(tmp)) + + return ok +} diff --git a/core/crypto/ed25519/ed25519.odin b/core/crypto/ed25519/ed25519.odin index 460a19563..deeb80685 100644 --- a/core/crypto/ed25519/ed25519.odin +++ b/core/crypto/ed25519/ed25519.odin @@ -81,12 +81,8 @@ private_key_set_bytes :: proc(priv_key: ^Private_Key, b: []byte) -> bool { // private_key_bytes sets dst to byte-encoding of priv_key. private_key_bytes :: proc(priv_key: ^Private_Key, dst: []byte) { - if !priv_key._is_initialized { - panic("crypto/ed25519: uninitialized private key") - } - if len(dst) != PRIVATE_KEY_SIZE { - panic("crypto/ed25519: invalid destination size") - } + ensure(priv_key._is_initialized, "crypto/ed25519: uninitialized private key") + ensure(len(dst) == PRIVATE_KEY_SIZE, "crypto/ed25519: invalid destination size") copy(dst, priv_key._b[:]) } @@ -98,12 +94,8 @@ private_key_clear :: proc "contextless" (priv_key: ^Private_Key) { // sign writes the signature by priv_key over msg to sig. sign :: proc(priv_key: ^Private_Key, msg, sig: []byte) { - if !priv_key._is_initialized { - panic("crypto/ed25519: uninitialized private key") - } - if len(sig) != SIGNATURE_SIZE { - panic("crypto/ed25519: invalid destination size") - } + ensure(priv_key._is_initialized, "crypto/ed25519: uninitialized private key") + ensure(len(sig) == SIGNATURE_SIZE, "crypto/ed25519: invalid destination size") // 1. Compute the hash of the private key d, H(d) = (h_0, h_1, ..., h_2b-1) // using SHA-512 for Ed25519. H(d) may be precomputed. @@ -178,9 +170,7 @@ public_key_set_bytes :: proc "contextless" (pub_key: ^Public_Key, b: []byte) -> // public_key_set_priv sets pub_key to the public component of priv_key. public_key_set_priv :: proc(pub_key: ^Public_Key, priv_key: ^Private_Key) { - if !priv_key._is_initialized { - panic("crypto/ed25519: uninitialized public key") - } + ensure(priv_key._is_initialized, "crypto/ed25519: uninitialized public key") src := &priv_key._pub_key copy(pub_key._b[:], src._b[:]) @@ -191,21 +181,15 @@ public_key_set_priv :: proc(pub_key: ^Public_Key, priv_key: ^Private_Key) { // public_key_bytes sets dst to byte-encoding of pub_key. public_key_bytes :: proc(pub_key: ^Public_Key, dst: []byte) { - if !pub_key._is_initialized { - panic("crypto/ed25519: uninitialized public key") - } - if len(dst) != PUBLIC_KEY_SIZE { - panic("crypto/ed25519: invalid destination size") - } + ensure(pub_key._is_initialized, "crypto/ed25519: uninitialized public key") + ensure(len(dst) == PUBLIC_KEY_SIZE, "crypto/ed25519: invalid destination size") copy(dst, pub_key._b[:]) } // public_key_equal returns true iff pub_key is equal to other. public_key_equal :: proc(pub_key, other: ^Public_Key) -> bool { - if !pub_key._is_initialized || !other._is_initialized { - panic("crypto/ed25519: uninitialized public key") - } + ensure(pub_key._is_initialized && other._is_initialized, "crypto/ed25519: uninitialized public key") return crypto.compare_constant_time(pub_key._b[:], other._b[:]) == 1 } diff --git a/core/crypto/hash/hash.odin b/core/crypto/hash/hash.odin index d47f0ab46..66d9201cd 100644 --- a/core/crypto/hash/hash.odin +++ b/core/crypto/hash/hash.odin @@ -21,8 +21,7 @@ hash_string :: proc(algorithm: Algorithm, data: string, allocator := context.all // in a newly allocated slice. hash_bytes :: proc(algorithm: Algorithm, data: []byte, allocator := context.allocator) -> []byte { dst := make([]byte, DIGEST_SIZES[algorithm], allocator) - hash_bytes_to_buffer(algorithm, data, dst) - return dst + return hash_bytes_to_buffer(algorithm, data, dst) } // hash_string_to_buffer will hash the given input and assign the @@ -46,7 +45,7 @@ hash_bytes_to_buffer :: proc(algorithm: Algorithm, data, hash: []byte) -> []byte update(&ctx, data) final(&ctx, hash) - return hash + return hash[:DIGEST_SIZES[algorithm]] } // hash_stream will incrementally fully consume a stream, and return the diff --git a/core/crypto/hmac/hmac.odin b/core/crypto/hmac/hmac.odin index 4813a9938..f74d6492f 100644 --- a/core/crypto/hmac/hmac.odin +++ b/core/crypto/hmac/hmac.odin @@ -56,7 +56,7 @@ init :: proc(ctx: ^Context, algorithm: hash.Algorithm, key: []byte) { // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - assert(ctx._is_initialized) + ensure(ctx._is_initialized) hash.update(&ctx._i_hash, data) } @@ -64,13 +64,10 @@ update :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the tag to dst, and calls // reset on the Context. final :: proc(ctx: ^Context, dst: []byte) { - assert(ctx._is_initialized) - defer (reset(ctx)) - if len(dst) != ctx._tag_sz { - panic("crypto/hmac: invalid destination tag size") - } + ensure(ctx._is_initialized) + ensure(len(dst) == ctx._tag_sz, "crypto/hmac: invalid destination tag size") hash.final(&ctx._i_hash, dst) // H((k ^ ipad) || text) @@ -105,14 +102,14 @@ reset :: proc(ctx: ^Context) { // algorithm returns the Algorithm used by a Context instance. algorithm :: proc(ctx: ^Context) -> hash.Algorithm { - assert(ctx._is_initialized) + ensure(ctx._is_initialized) return hash.algorithm(&ctx._i_hash) } // tag_size returns the tag size of a Context instance in bytes. tag_size :: proc(ctx: ^Context) -> int { - assert(ctx._is_initialized) + ensure(ctx._is_initialized) return ctx._tag_sz } diff --git a/core/crypto/kmac/kmac.odin b/core/crypto/kmac/kmac.odin index e8bf42946..6f58e20a7 100644 --- a/core/crypto/kmac/kmac.odin +++ b/core/crypto/kmac/kmac.odin @@ -36,6 +36,7 @@ sum :: proc(sec_strength: int, dst, msg, key, domain_sep: []byte) { // tag is valid. verify :: proc(sec_strength: int, tag, msg, key, domain_sep: []byte, allocator := context.temp_allocator) -> bool { derived_tag := make([]byte, len(tag), allocator) + defer(delete(derived_tag)) sum(sec_strength, derived_tag, msg, key, domain_sep) @@ -59,8 +60,6 @@ init_256 :: proc(ctx: ^Context, key, domain_sep: []byte) { // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - assert(ctx.is_initialized) - shake.write((^shake.Context)(ctx), data) } @@ -68,12 +67,9 @@ update :: proc(ctx: ^Context, data: []byte) { // on the Context. This routine will panic if the dst length is less than // MIN_TAG_SIZE. final :: proc(ctx: ^Context, dst: []byte) { - assert(ctx.is_initialized) defer reset(ctx) - if len(dst) < MIN_TAG_SIZE { - panic("crypto/kmac: invalid KMAC tag_size, too short") - } + ensure(len(dst) >= MIN_TAG_SIZE, "crypto/kmac: invalid KMAC tag_size, too short") _sha3.final_cshake((^_sha3.Context)(ctx), dst) } @@ -103,14 +99,12 @@ _init_kmac :: proc(ctx: ^Context, key, s: []byte, sec_strength: int) { reset(ctx) } - if len(key) < sec_strength / 8 { - panic("crypto/kmac: invalid KMAC key, too short") - } + ensure(len(key) >= sec_strength / 8, "crypto/kmac: invalid KMAC key, too short") ctx_ := (^_sha3.Context)(ctx) _sha3.init_cshake(ctx_, N_KMAC, s, sec_strength) _sha3.bytepad(ctx_, [][]byte{key}, _sha3.rate_cshake(sec_strength)) } -@(private) +@(private, rodata) N_KMAC := []byte{'K', 'M', 'A', 'C'} diff --git a/core/crypto/legacy/keccak/keccak.odin b/core/crypto/legacy/keccak/keccak.odin index 6ca66b7ca..40fc2729f 100644 --- a/core/crypto/legacy/keccak/keccak.odin +++ b/core/crypto/legacy/keccak/keccak.odin @@ -40,37 +40,37 @@ BLOCK_SIZE_512 :: _sha3.RATE_512 Context :: distinct _sha3.Context // init_224 initializes a Context for Keccak-224. -init_224 :: proc(ctx: ^Context) { +init_224 :: proc "contextless" (ctx: ^Context) { ctx.mdlen = DIGEST_SIZE_224 _init(ctx) } // init_256 initializes a Context for Keccak-256. -init_256 :: proc(ctx: ^Context) { +init_256 :: proc "contextless" (ctx: ^Context) { ctx.mdlen = DIGEST_SIZE_256 _init(ctx) } // init_384 initializes a Context for Keccak-384. -init_384 :: proc(ctx: ^Context) { +init_384 :: proc "contextless" (ctx: ^Context) { ctx.mdlen = DIGEST_SIZE_384 _init(ctx) } // init_512 initializes a Context for Keccak-512. -init_512 :: proc(ctx: ^Context) { +init_512 :: proc "contextless" (ctx: ^Context) { ctx.mdlen = DIGEST_SIZE_512 _init(ctx) } @(private) -_init :: proc(ctx: ^Context) { +_init :: proc "contextless" (ctx: ^Context) { ctx.dsbyte = _sha3.DS_KECCAK _sha3.init((^_sha3.Context)(ctx)) } // update adds more data to the Context. -update :: proc(ctx: ^Context, data: []byte) { +update :: proc "contextless" (ctx: ^Context, data: []byte) { _sha3.update((^_sha3.Context)(ctx), data) } @@ -79,17 +79,17 @@ update :: proc(ctx: ^Context, data: []byte) { // // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. -final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { +final :: proc "contextless" (ctx: ^Context, hash: []byte, finalize_clone: bool = false) { _sha3.final((^_sha3.Context)(ctx), hash, finalize_clone) } // clone clones the Context other into ctx. -clone :: proc(ctx, other: ^Context) { +clone :: proc "contextless" (ctx, other: ^Context) { _sha3.clone((^_sha3.Context)(ctx), (^_sha3.Context)(other)) } // reset sanitizes the Context. The Context must be re-initialized to // be used again. -reset :: proc(ctx: ^Context) { +reset :: proc "contextless" (ctx: ^Context) { _sha3.reset((^_sha3.Context)(ctx)) } diff --git a/core/crypto/legacy/md5/md5.odin b/core/crypto/legacy/md5/md5.odin index 28b47e0b3..050501d98 100644 --- a/core/crypto/legacy/md5/md5.odin +++ b/core/crypto/legacy/md5/md5.odin @@ -53,7 +53,7 @@ init :: proc(ctx: ^Context) { // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - assert(ctx.is_initialized) + ensure(ctx.is_initialized) for i := 0; i < len(data); i += 1 { ctx.data[ctx.datalen] = data[i] @@ -72,11 +72,8 @@ update :: proc(ctx: ^Context, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - assert(ctx.is_initialized) - - if len(hash) < DIGEST_SIZE { - panic("crypto/md5: invalid destination digest size") - } + ensure(ctx.is_initialized) + ensure(len(hash) >= DIGEST_SIZE, "crypto/md5: invalid destination digest size") ctx := ctx if finalize_clone { diff --git a/core/crypto/legacy/sha1/sha1.odin b/core/crypto/legacy/sha1/sha1.odin index 1025ecb5b..5a2b57005 100644 --- a/core/crypto/legacy/sha1/sha1.odin +++ b/core/crypto/legacy/sha1/sha1.odin @@ -60,7 +60,7 @@ init :: proc(ctx: ^Context) { // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - assert(ctx.is_initialized) + ensure(ctx.is_initialized) for i := 0; i < len(data); i += 1 { ctx.data[ctx.datalen] = data[i] @@ -79,11 +79,8 @@ update :: proc(ctx: ^Context, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - assert(ctx.is_initialized) - - if len(hash) < DIGEST_SIZE { - panic("crypto/sha1: invalid destination digest size") - } + ensure(ctx.is_initialized) + ensure(len(hash) >= DIGEST_SIZE, "crypto/sha1: invalid destination digest size") ctx := ctx if finalize_clone { diff --git a/core/crypto/poly1305/poly1305.odin b/core/crypto/poly1305/poly1305.odin index ea0e6c907..3dd915da7 100644 --- a/core/crypto/poly1305/poly1305.odin +++ b/core/crypto/poly1305/poly1305.odin @@ -60,9 +60,7 @@ Context :: struct { // init initializes a Context with the specified key. The key SHOULD be // unique and MUST be unpredictable for each invocation. init :: proc(ctx: ^Context, key: []byte) { - if len(key) != KEY_SIZE { - panic("crypto/poly1305: invalid key size") - } + ensure(len(key) == KEY_SIZE, "crypto/poly1305: invalid key size") // r = le_bytes_to_num(key[0..15]) // r = clamp(r) (r &= 0xffffffc0ffffffc0ffffffc0fffffff) @@ -85,7 +83,7 @@ init :: proc(ctx: ^Context, key: []byte) { // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - assert(ctx._is_initialized) + ensure(ctx._is_initialized) msg := data msg_len := len(data) @@ -124,12 +122,10 @@ update :: proc(ctx: ^Context, data: []byte) { // final finalizes the Context, writes the tag to dst, and calls // reset on the Context. final :: proc(ctx: ^Context, dst: []byte) { - assert(ctx._is_initialized) defer reset(ctx) - if len(dst) != TAG_SIZE { - panic("poly1305: invalid destination tag size") - } + ensure(ctx._is_initialized) + ensure(len(dst) == TAG_SIZE, "poly1305: invalid destination tag size") // Process remaining block if ctx._leftover > 0 { diff --git a/core/crypto/ristretto255/ristretto255.odin b/core/crypto/ristretto255/ristretto255.odin index 7b0944e33..20a002900 100644 --- a/core/crypto/ristretto255/ristretto255.odin +++ b/core/crypto/ristretto255/ristretto255.odin @@ -16,7 +16,7 @@ ELEMENT_SIZE :: 32 // group element. WIDE_ELEMENT_SIZE :: 64 -@(private) +@(private, rodata) FE_NEG_ONE := field.Tight_Field_Element { 2251799813685228, 2251799813685247, @@ -24,7 +24,7 @@ FE_NEG_ONE := field.Tight_Field_Element { 2251799813685247, 2251799813685247, } -@(private) +@(private, rodata) FE_INVSQRT_A_MINUS_D := field.Tight_Field_Element { 278908739862762, 821645201101625, @@ -32,7 +32,7 @@ FE_INVSQRT_A_MINUS_D := field.Tight_Field_Element { 1777959178193151, 2118520810568447, } -@(private) +@(private, rodata) FE_ONE_MINUS_D_SQ := field.Tight_Field_Element { 1136626929484150, 1998550399581263, @@ -40,7 +40,7 @@ FE_ONE_MINUS_D_SQ := field.Tight_Field_Element { 118527312129759, 45110755273534, } -@(private) +@(private, rodata) FE_D_MINUS_ONE_SQUARED := field.Tight_Field_Element { 1507062230895904, 1572317787530805, @@ -48,7 +48,7 @@ FE_D_MINUS_ONE_SQUARED := field.Tight_Field_Element { 317374165784489, 1572899562415810, } -@(private) +@(private, rodata) FE_SQRT_AD_MINUS_ONE := field.Tight_Field_Element { 2241493124984347, 425987919032274, @@ -76,7 +76,7 @@ ge_clear :: proc "contextless" (ge: ^Group_Element) { // ge_set sets `ge = a`. ge_set :: proc(ge, a: ^Group_Element) { - _ge_assert_initialized([]^Group_Element{a}) + _ge_ensure_initialized([]^Group_Element{a}) grp.ge_set(&ge._p, &a._p) ge._is_initialized = true @@ -199,9 +199,7 @@ ge_set_bytes :: proc "contextless" (ge: ^Group_Element, b: []byte) -> bool { // ge_set_wide_bytes sets ge to the result of deriving a ristretto255 // group element, from a wide (512-bit) byte string. ge_set_wide_bytes :: proc(ge: ^Group_Element, b: []byte) { - if len(b) != WIDE_ELEMENT_SIZE { - panic("crypto/ristretto255: invalid wide input size") - } + ensure(len(b) == WIDE_ELEMENT_SIZE, "crypto/ristretto255: invalid wide input size") // The element derivation function on an input string b proceeds as // follows: @@ -222,10 +220,8 @@ ge_set_wide_bytes :: proc(ge: ^Group_Element, b: []byte) { // ge_bytes sets dst to the canonical encoding of ge. ge_bytes :: proc(ge: ^Group_Element, dst: []byte) { - _ge_assert_initialized([]^Group_Element{ge}) - if len(dst) != ELEMENT_SIZE { - panic("crypto/ristretto255: invalid destination size") - } + _ge_ensure_initialized([]^Group_Element{ge}) + ensure(len(dst) == ELEMENT_SIZE, "crypto/ristretto255: invalid destination size") x0, y0, z0, t0 := &ge._p.x, &ge._p.y, &ge._p.z, &ge._p.t @@ -306,7 +302,7 @@ ge_bytes :: proc(ge: ^Group_Element, dst: []byte) { // ge_add sets `ge = a + b`. ge_add :: proc(ge, a, b: ^Group_Element) { - _ge_assert_initialized([]^Group_Element{a, b}) + _ge_ensure_initialized([]^Group_Element{a, b}) grp.ge_add(&ge._p, &a._p, &b._p) ge._is_initialized = true @@ -314,7 +310,7 @@ ge_add :: proc(ge, a, b: ^Group_Element) { // ge_double sets `ge = a + a`. ge_double :: proc(ge, a: ^Group_Element) { - _ge_assert_initialized([]^Group_Element{a}) + _ge_ensure_initialized([]^Group_Element{a}) grp.ge_double(&ge._p, &a._p) ge._is_initialized = true @@ -322,7 +318,7 @@ ge_double :: proc(ge, a: ^Group_Element) { // ge_negate sets `ge = -a`. ge_negate :: proc(ge, a: ^Group_Element) { - _ge_assert_initialized([]^Group_Element{a}) + _ge_ensure_initialized([]^Group_Element{a}) grp.ge_negate(&ge._p, &a._p) ge._is_initialized = true @@ -330,7 +326,7 @@ ge_negate :: proc(ge, a: ^Group_Element) { // ge_scalarmult sets `ge = A * sc`. ge_scalarmult :: proc(ge, A: ^Group_Element, sc: ^Scalar) { - _ge_assert_initialized([]^Group_Element{A}) + _ge_ensure_initialized([]^Group_Element{A}) grp.ge_scalarmult(&ge._p, &A._p, sc) ge._is_initialized = true @@ -344,7 +340,7 @@ ge_scalarmult_generator :: proc "contextless" (ge: ^Group_Element, sc: ^Scalar) // ge_scalarmult_vartime sets `ge = A * sc` in variable time. ge_scalarmult_vartime :: proc(ge, A: ^Group_Element, sc: ^Scalar) { - _ge_assert_initialized([]^Group_Element{A}) + _ge_ensure_initialized([]^Group_Element{A}) grp.ge_scalarmult_vartime(&ge._p, &A._p, sc) ge._is_initialized = true @@ -358,7 +354,7 @@ ge_double_scalarmult_generator_vartime :: proc( A: ^Group_Element, b: ^Scalar, ) { - _ge_assert_initialized([]^Group_Element{A}) + _ge_ensure_initialized([]^Group_Element{A}) grp.ge_double_scalarmult_basepoint_vartime(&ge._p, a, &A._p, b) ge._is_initialized = true @@ -367,7 +363,7 @@ ge_double_scalarmult_generator_vartime :: proc( // ge_cond_negate sets `ge = a` iff `ctrl == 0` and `ge = -a` iff `ctrl == 1`. // Behavior for all other values of ctrl are undefined, ge_cond_negate :: proc(ge, a: ^Group_Element, ctrl: int) { - _ge_assert_initialized([]^Group_Element{a}) + _ge_ensure_initialized([]^Group_Element{a}) grp.ge_cond_negate(&ge._p, &a._p, ctrl) ge._is_initialized = true @@ -376,7 +372,7 @@ ge_cond_negate :: proc(ge, a: ^Group_Element, ctrl: int) { // ge_cond_assign sets `ge = ge` iff `ctrl == 0` and `ge = a` iff `ctrl == 1`. // Behavior for all other values of ctrl are undefined, ge_cond_assign :: proc(ge, a: ^Group_Element, ctrl: int) { - _ge_assert_initialized([]^Group_Element{ge, a}) + _ge_ensure_initialized([]^Group_Element{ge, a}) grp.ge_cond_assign(&ge._p, &a._p, ctrl) } @@ -384,7 +380,7 @@ ge_cond_assign :: proc(ge, a: ^Group_Element, ctrl: int) { // ge_cond_select sets `ge = a` iff `ctrl == 0` and `ge = b` iff `ctrl == 1`. // Behavior for all other values of ctrl are undefined, ge_cond_select :: proc(ge, a, b: ^Group_Element, ctrl: int) { - _ge_assert_initialized([]^Group_Element{a, b}) + _ge_ensure_initialized([]^Group_Element{a, b}) grp.ge_cond_select(&ge._p, &a._p, &b._p, ctrl) ge._is_initialized = true @@ -393,7 +389,7 @@ ge_cond_select :: proc(ge, a, b: ^Group_Element, ctrl: int) { // ge_equal returns 1 iff `a == b`, and 0 otherwise. @(require_results) ge_equal :: proc(a, b: ^Group_Element) -> int { - _ge_assert_initialized([]^Group_Element{a, b}) + _ge_ensure_initialized([]^Group_Element{a, b}) // CT_EQ(x1 * y2, y1 * x2) | CT_EQ(y1 * y2, x1 * x2) ax_by, ay_bx, ay_by, ax_bx: field.Tight_Field_Element = ---, ---, ---, --- @@ -501,10 +497,8 @@ ge_map :: proc "contextless" (ge: ^Group_Element, b: []byte) { } @(private) -_ge_assert_initialized :: proc(ges: []^Group_Element) { +_ge_ensure_initialized :: proc(ges: []^Group_Element) { for ge in ges { - if !ge._is_initialized { - panic("crypto/ristretto255: uninitialized group element") - } + ensure(ge._is_initialized, "crypto/ristretto255: uninitialized group element") } } diff --git a/core/crypto/ristretto255/ristretto255_scalar.odin b/core/crypto/ristretto255/ristretto255_scalar.odin index 1ecb490e0..75844b3f4 100644 --- a/core/crypto/ristretto255/ristretto255_scalar.odin +++ b/core/crypto/ristretto255/ristretto255_scalar.odin @@ -42,9 +42,7 @@ sc_set_bytes :: proc(sc: ^Scalar, b: []byte) -> bool { // scalar, from a wide (512-bit) byte string by interpreting b as a // little-endian value, and reducing it mod the group order. sc_set_bytes_wide :: proc(sc: ^Scalar, b: []byte) { - if len(b) != WIDE_SCALAR_SIZE { - panic("crypto/ristretto255: invalid wide input size") - } + ensure(len(b) == WIDE_SCALAR_SIZE, "crypto/ristretto255: invalid wide input size") b_ := (^[WIDE_SCALAR_SIZE]byte)(raw_data(b)) grp.sc_set_bytes_wide(sc, b_) @@ -52,9 +50,7 @@ sc_set_bytes_wide :: proc(sc: ^Scalar, b: []byte) { // sc_bytes sets dst to the canonical encoding of sc. sc_bytes :: proc(sc: ^Scalar, dst: []byte) { - if len(dst) != SCALAR_SIZE { - panic("crypto/ristretto255: invalid destination size") - } + ensure(len(dst) == SCALAR_SIZE, "crypto/ristretto255: invalid destination size") grp.sc_bytes(dst, sc) } diff --git a/core/crypto/sha2/sha2.odin b/core/crypto/sha2/sha2.odin index 4230851ab..bf9b81601 100644 --- a/core/crypto/sha2/sha2.odin +++ b/core/crypto/sha2/sha2.odin @@ -15,9 +15,9 @@ package sha2 zhibog, dotbmp: Initial implementation. */ -import "core:encoding/endian" +@(require) import "core:encoding/endian" import "core:math/bits" -import "core:mem" +@(require) import "core:mem" // DIGEST_SIZE_224 is the SHA-224 digest size in bytes. DIGEST_SIZE_224 :: 28 @@ -158,7 +158,7 @@ _init :: proc(ctx: ^$T) { // update adds more data to the Context. update :: proc(ctx: ^$T, data: []byte) { - assert(ctx.is_initialized) + ensure(ctx.is_initialized) when T == Context_256 { CURR_BLOCK_SIZE :: BLOCK_SIZE_256 @@ -194,11 +194,8 @@ update :: proc(ctx: ^$T, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^$T, hash: []byte, finalize_clone: bool = false) { - assert(ctx.is_initialized) - - if len(hash) * 8 < ctx.md_bits { - panic("crypto/sha2: invalid destination digest size") - } + ensure(ctx.is_initialized) + ensure(len(hash) * 8 >= ctx.md_bits, "crypto/sha2: invalid destination digest size") ctx := ctx if finalize_clone { @@ -238,7 +235,7 @@ final :: proc(ctx: ^$T, hash: []byte, finalize_clone: bool = false) { endian.unchecked_put_u64be(pad[8:], length_lo) update(ctx, pad[0:16]) } - assert(ctx.bitlength == 0) + assert(ctx.bitlength == 0) // Check for bugs when T == Context_256 { for i := 0; i < ctx.md_bits / 32; i += 1 { @@ -270,8 +267,8 @@ reset :: proc(ctx: ^$T) { SHA2 implementation */ -@(private) -sha256_k := [64]u32 { +@(private, rodata) +SHA256_K := [64]u32 { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, @@ -290,8 +287,8 @@ sha256_k := [64]u32 { 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, } -@(private) -sha512_k := [80]u64 { +@(private, rodata) +SHA512_K := [80]u64 { 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, @@ -334,6 +331,11 @@ sha512_k := [80]u64 { 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, } +@(private) +SHA256_ROUNDS :: 64 +@(private) +SHA512_ROUNDS :: 80 + @(private) SHA256_CH :: #force_inline proc "contextless" (x, y, z: u32) -> u32 { return (x & y) ~ (~x & z) @@ -395,22 +397,29 @@ SHA512_F4 :: #force_inline proc "contextless" (x: u64) -> u64 { } @(private) -sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) { +sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) #no_bounds_check { when T == Context_256 { - w: [64]u32 + if is_hardware_accelerated_256() { + sha256_transf_hw(ctx, data) + return + } + + w: [SHA256_ROUNDS]u32 wv: [8]u32 t1, t2: u32 + CURR_BLOCK_SIZE :: BLOCK_SIZE_256 } else when T == Context_512 { - w: [80]u64 + w: [SHA512_ROUNDS]u64 wv: [8]u64 t1, t2: u64 + CURR_BLOCK_SIZE :: BLOCK_SIZE_512 } data := data for len(data) >= CURR_BLOCK_SIZE { - for i := 0; i < 16; i += 1 { + for i in 0 ..< 16 { when T == Context_256 { w[i] = endian.unchecked_get_u32be(data[i * 4:]) } else when T == Context_512 { @@ -419,22 +428,22 @@ sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) { } when T == Context_256 { - for i := 16; i < 64; i += 1 { + for i in 16 ..< SHA256_ROUNDS { w[i] = SHA256_F4(w[i - 2]) + w[i - 7] + SHA256_F3(w[i - 15]) + w[i - 16] } } else when T == Context_512 { - for i := 16; i < 80; i += 1 { + for i in 16 ..< SHA512_ROUNDS { w[i] = SHA512_F4(w[i - 2]) + w[i - 7] + SHA512_F3(w[i - 15]) + w[i - 16] } } - for i := 0; i < 8; i += 1 { + for i in 0 ..< 8 { wv[i] = ctx.h[i] } when T == Context_256 { - for i := 0; i < 64; i += 1 { - t1 = wv[7] + SHA256_F2(wv[4]) + SHA256_CH(wv[4], wv[5], wv[6]) + sha256_k[i] + w[i] + for i in 0 ..< SHA256_ROUNDS { + t1 = wv[7] + SHA256_F2(wv[4]) + SHA256_CH(wv[4], wv[5], wv[6]) + SHA256_K[i] + w[i] t2 = SHA256_F1(wv[0]) + SHA256_MAJ(wv[0], wv[1], wv[2]) wv[7] = wv[6] wv[6] = wv[5] @@ -446,8 +455,8 @@ sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) { wv[0] = t1 + t2 } } else when T == Context_512 { - for i := 0; i < 80; i += 1 { - t1 = wv[7] + SHA512_F2(wv[4]) + SHA512_CH(wv[4], wv[5], wv[6]) + sha512_k[i] + w[i] + for i in 0 ..< SHA512_ROUNDS { + t1 = wv[7] + SHA512_F2(wv[4]) + SHA512_CH(wv[4], wv[5], wv[6]) + SHA512_K[i] + w[i] t2 = SHA512_F1(wv[0]) + SHA512_MAJ(wv[0], wv[1], wv[2]) wv[7] = wv[6] wv[6] = wv[5] @@ -460,7 +469,7 @@ sha2_transf :: proc "contextless" (ctx: ^$T, data: []byte) { } } - for i := 0; i < 8; i += 1 { + for i in 0 ..< 8 { ctx.h[i] += wv[i] } diff --git a/core/crypto/sha2/sha2_impl_hw_gen.odin b/core/crypto/sha2/sha2_impl_hw_gen.odin new file mode 100644 index 000000000..85c7f8b28 --- /dev/null +++ b/core/crypto/sha2/sha2_impl_hw_gen.odin @@ -0,0 +1,15 @@ +#+build !amd64 +package sha2 + +@(private = "file") +ERR_HW_NOT_SUPPORTED :: "crypto/sha2: hardware implementation unsupported" + +// is_hardware_accelerated_256 returns true iff hardware accelerated +// SHA-224/SHA-256 is supported. +is_hardware_accelerated_256 :: proc "contextless" () -> bool { + return false +} + +sha256_transf_hw :: proc "contextless" (ctx: ^Context_256, data: []byte) { + panic_contextless(ERR_HW_NOT_SUPPORTED) +} diff --git a/core/crypto/sha2/sha2_impl_hw_intel.odin b/core/crypto/sha2/sha2_impl_hw_intel.odin new file mode 100644 index 000000000..cb29a3a20 --- /dev/null +++ b/core/crypto/sha2/sha2_impl_hw_intel.odin @@ -0,0 +1,260 @@ +#+build amd64 +package sha2 + +// Based on the public domain code by Jeffrey Walton, though +// realistically, there only is one sensible way to write this +// and Intel's whitepaper covers it. +// +// See: https://github.com/noloader/SHA-Intrinsics + +import "base:intrinsics" +import "core:simd" +import "core:simd/x86" +import "core:sys/info" + +@(private = "file") +MASK :: x86.__m128i{0x0405060700010203, 0x0c0d0e0f08090a0b} + +@(private = "file") +K_0 :: simd.u64x2{0x71374491428a2f98, 0xe9b5dba5b5c0fbcf} +@(private = "file") +K_1 :: simd.u64x2{0x59f111f13956c25b, 0xab1c5ed5923f82a4} +@(private = "file") +K_2 :: simd.u64x2{0x12835b01d807aa98, 0x550c7dc3243185be} +@(private = "file") +K_3 :: simd.u64x2{0x80deb1fe72be5d74, 0xc19bf1749bdc06a7} +@(private = "file") +K_4 :: simd.u64x2{0xefbe4786e49b69c1, 0x240ca1cc0fc19dc6} +@(private = "file") +K_5 :: simd.u64x2{0x4a7484aa2de92c6f, 0x76f988da5cb0a9dc} +@(private = "file") +K_6 :: simd.u64x2{0xa831c66d983e5152, 0xbf597fc7b00327c8} +@(private = "file") +K_7 :: simd.u64x2{0xd5a79147c6e00bf3, 0x1429296706ca6351} +@(private = "file") +K_8 :: simd.u64x2{0x2e1b213827b70a85, 0x53380d134d2c6dfc} +@(private = "file") +K_9 :: simd.u64x2{0x766a0abb650a7354, 0x92722c8581c2c92e} +@(private = "file") +K_10 :: simd.u64x2{0xa81a664ba2bfe8a1, 0xc76c51a3c24b8b70} +@(private = "file") +K_11 :: simd.u64x2{0xd6990624d192e819, 0x106aa070f40e3585} +@(private = "file") +K_12 :: simd.u64x2{0x1e376c0819a4c116, 0x34b0bcb52748774c} +@(private = "file") +K_13 :: simd.u64x2{0x4ed8aa4a391c0cb3, 0x682e6ff35b9cca4f} +@(private = "file") +K_14 :: simd.u64x2{0x78a5636f748f82ee, 0x8cc7020884c87814} +@(private = "file") +K_15 :: simd.u64x2{0xa4506ceb90befffa, 0xc67178f2bef9a3f7} + + +// is_hardware_accelerated_256 returns true iff hardware accelerated +// SHA-224/SHA-256 is supported. +is_hardware_accelerated_256 :: proc "contextless" () -> bool { + features, ok := info.cpu.features.? + if !ok { + return false + } + + req_features :: info.CPU_Features{ + .sse2, + .ssse3, + .sse41, + .sha, + } + return features >= req_features +} + +@(private, enable_target_feature="sse2,ssse3,sse4.1,sha") +sha256_transf_hw :: proc "contextless" (ctx: ^Context_256, data: []byte) #no_bounds_check { + // Load the state + tmp := intrinsics.unaligned_load((^x86.__m128i)(&ctx.h[0])) + state_1 := intrinsics.unaligned_load((^x86.__m128i)(&ctx.h[4])) + + tmp = x86._mm_shuffle_epi32(tmp, 0xb1) // CDAB + state_1 = x86._mm_shuffle_epi32(state_1, 0x1b) // EFGH + state_0 := x86._mm_alignr_epi8(tmp, state_1, 8) // ABEF + // state_1 = x86._mm_blend_epi16(state_1, tmp, 0xf0) // CDGH + state_1 = kludge_mm_blend_epi16_0xf0(state_1, tmp) + + data := data + for len(data) >= BLOCK_SIZE_256 { + state_0_save, state_1_save := state_0, state_1 + + // Rounds 0-3 + msg := intrinsics.unaligned_load((^x86.__m128i)(raw_data(data))) + msg_0 := x86._mm_shuffle_epi8(msg, MASK) + msg = x86._mm_add_epi32(msg_0, x86.__m128i(K_0)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + msg = x86._mm_shuffle_epi32(msg, 0xe) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + + // Rounds 4-7 + msg_1 := intrinsics.unaligned_load((^x86.__m128i)(raw_data(data[16:]))) + msg_1 = x86._mm_shuffle_epi8(msg_1, MASK) + msg = x86._mm_add_epi32(msg_1, x86.__m128i(K_1)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + msg = x86._mm_shuffle_epi32(msg, 0xe) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_0 = x86._mm_sha256msg1_epu32(msg_0, msg_1) + + // Rounds 8-11 + msg_2 := intrinsics.unaligned_load((^x86.__m128i)(raw_data(data[32:]))) + msg_2 = x86._mm_shuffle_epi8(msg_2, MASK) + msg = x86._mm_add_epi32(msg_2, x86.__m128i(K_2)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + msg = x86._mm_shuffle_epi32(msg, 0xe) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_1 = x86._mm_sha256msg1_epu32(msg_1, msg_2) + + // Rounds 12-15 + msg_3 := intrinsics.unaligned_load((^x86.__m128i)(raw_data(data[48:]))) + msg_3 = x86._mm_shuffle_epi8(msg_3, MASK) + msg = x86._mm_add_epi32(msg_3, x86.__m128i(K_3)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_3, msg_2, 4) + msg_0 = x86._mm_add_epi32(msg_0, tmp) + msg_0 = x86._mm_sha256msg2_epu32(msg_0, msg_3) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_2 = x86._mm_sha256msg1_epu32(msg_2, msg_3) + + // Rounds 16-19 + msg = x86._mm_add_epi32(msg_0, x86.__m128i(K_4)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_0, msg_3, 4) + msg_1 = x86._mm_add_epi32(msg_1, tmp) + msg_1 = x86._mm_sha256msg2_epu32(msg_1, msg_0) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_3 = x86._mm_sha256msg1_epu32(msg_3, msg_0) + + // Rounds 20-23 + msg = x86._mm_add_epi32(msg_1, x86.__m128i(K_5)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_1, msg_0, 4) + msg_2 = x86._mm_add_epi32(msg_2, tmp) + msg_2 = x86._mm_sha256msg2_epu32(msg_2, msg_1) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_0 = x86._mm_sha256msg1_epu32(msg_0, msg_1) + + // Rounds 24-27 + msg = x86._mm_add_epi32(msg_2, x86.__m128i(K_6)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_2, msg_1, 4) + msg_3 = x86._mm_add_epi32(msg_3, tmp) + msg_3 = x86._mm_sha256msg2_epu32(msg_3, msg_2) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_1 = x86._mm_sha256msg1_epu32(msg_1, msg_2) + + // Rounds 28-31 + msg = x86._mm_add_epi32(msg_3, x86.__m128i(K_7)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_3, msg_2, 4) + msg_0 = x86._mm_add_epi32(msg_0, tmp) + msg_0 = x86._mm_sha256msg2_epu32(msg_0, msg_3) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_2 = x86._mm_sha256msg1_epu32(msg_2, msg_3) + + // Rounds 32-35 + msg = x86._mm_add_epi32(msg_0, x86.__m128i(K_8)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_0, msg_3, 4) + msg_1 = x86._mm_add_epi32(msg_1, tmp) + msg_1 = x86._mm_sha256msg2_epu32(msg_1, msg_0) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_3 = x86._mm_sha256msg1_epu32(msg_3, msg_0) + + // Rounds 36-39 + msg = x86._mm_add_epi32(msg_1, x86.__m128i(K_9)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_1, msg_0, 4) + msg_2 = x86._mm_add_epi32(msg_2, tmp) + msg_2 = x86._mm_sha256msg2_epu32(msg_2, msg_1) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_0 = x86._mm_sha256msg1_epu32(msg_0, msg_1) + + // Rounds 40-43 + msg = x86._mm_add_epi32(msg_2, x86.__m128i(K_10)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_2, msg_1, 4) + msg_3 = x86._mm_add_epi32(msg_3, tmp) + msg_3 = x86._mm_sha256msg2_epu32(msg_3, msg_2) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_1 = x86._mm_sha256msg1_epu32(msg_1, msg_2) + + // Rounds 44-47 + msg = x86._mm_add_epi32(msg_3, x86.__m128i(K_11)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_3, msg_2, 4) + msg_0 = x86._mm_add_epi32(msg_0, tmp) + msg_0 = x86._mm_sha256msg2_epu32(msg_0, msg_3) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_2 = x86._mm_sha256msg1_epu32(msg_2, msg_3) + + // Rounds 48-51 + msg = x86._mm_add_epi32(msg_0, x86.__m128i(K_12)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_0, msg_3, 4) + msg_1 = x86._mm_add_epi32(msg_1, tmp) + msg_1 = x86._mm_sha256msg2_epu32(msg_1, msg_0) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + msg_3 = x86._mm_sha256msg1_epu32(msg_3, msg_0) + + // Rounds 52-55 + msg = x86._mm_add_epi32(msg_1, x86.__m128i(K_13)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_1, msg_0, 4) + msg_2 = x86._mm_add_epi32(msg_2, tmp) + msg_2 = x86._mm_sha256msg2_epu32(msg_2, msg_1) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + + /* Rounds 56-59 */ + msg = x86._mm_add_epi32(msg_2, x86.__m128i(K_14)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + tmp = x86._mm_alignr_epi8(msg_2, msg_1, 4) + msg_3 = x86._mm_add_epi32(msg_3, tmp) + msg_3 = x86._mm_sha256msg2_epu32(msg_3, msg_2) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + + // Rounds 60-63 + msg = x86._mm_add_epi32(msg_3, x86.__m128i(K_15)) + state_1 = x86._mm_sha256rnds2_epu32(state_1, state_0, msg) + msg = x86._mm_shuffle_epi32(msg, 0x0e) + state_0 = x86._mm_sha256rnds2_epu32(state_0, state_1, msg) + + state_0 = x86._mm_add_epi32(state_0, state_0_save) + state_1 = x86._mm_add_epi32(state_1, state_1_save) + + data = data[BLOCK_SIZE_256:] + } + + // Write back the updated state + tmp = x86._mm_shuffle_epi32(state_0, 0x1b) // FEBA + state_1 = x86._mm_shuffle_epi32(state_1, 0xb1) // DCHG + // state_0 = x86._mm_blend_epi16(tmp, state_1, 0xf0) // DCBA + state_0 = kludge_mm_blend_epi16_0xf0(tmp, state_1) + state_1 = x86._mm_alignr_epi8(state_1, tmp, 8) // ABEF + + intrinsics.unaligned_store((^x86.__m128i)(&ctx.h[0]), state_0) + intrinsics.unaligned_store((^x86.__m128i)(&ctx.h[4]), state_1) +} + +@(private = "file") +kludge_mm_blend_epi16_0xf0 :: #force_inline proc "contextless"(a, b: x86.__m128i) -> x86.__m128i { + // HACK HACK HACK: LLVM got rid of `llvm.x86.sse41.pblendw`. + a_ := simd.to_array(a) + b_ := simd.to_array(b) + return x86.__m128i{a_[0], b_[1]} +} diff --git a/core/crypto/siphash/siphash.odin b/core/crypto/siphash/siphash.odin index c145ab3f0..f9fe50cb0 100644 --- a/core/crypto/siphash/siphash.odin +++ b/core/crypto/siphash/siphash.odin @@ -219,18 +219,14 @@ verify_4_8 :: proc { */ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) { - if len(key) != KEY_SIZE { - panic("crypto/siphash; invalid key size") - } + ensure(len(key) == KEY_SIZE,"crypto/siphash; invalid key size") ctx.c_rounds = c_rounds ctx.d_rounds = d_rounds is_valid_setting := (ctx.c_rounds == 1 && ctx.d_rounds == 3) || (ctx.c_rounds == 2 && ctx.d_rounds == 4) || (ctx.c_rounds == 4 && ctx.d_rounds == 8) - if !is_valid_setting { - panic("crypto/siphash: incorrect rounds set up") - } + ensure(is_valid_setting, "crypto/siphash: incorrect rounds set up") ctx.k0 = endian.unchecked_get_u64le(key[:8]) ctx.k1 = endian.unchecked_get_u64le(key[8:]) ctx.v0 = 0x736f6d6570736575 ~ ctx.k0 @@ -245,7 +241,7 @@ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) { } update :: proc(ctx: ^Context, data: []byte) { - assert(ctx.is_initialized, "crypto/siphash: context is not initialized") + ensure(ctx.is_initialized) data := data ctx.total_length += len(data) @@ -269,7 +265,7 @@ update :: proc(ctx: ^Context, data: []byte) { } final :: proc(ctx: ^Context, dst: ^u64) { - assert(ctx.is_initialized, "crypto/siphash: context is not initialized") + ensure(ctx.is_initialized) tmp: [BLOCK_SIZE]byte copy(tmp[:], ctx.buf[:ctx.last_block]) @@ -336,9 +332,8 @@ _get_byte :: #force_inline proc "contextless" (byte_num: byte, into: u64) -> byt @(private) _collect_output :: #force_inline proc(dst: []byte, hash: u64) { - if len(dst) < DIGEST_SIZE { - panic("crypto/siphash: invalid tag size") - } + ensure(len(dst) >= DIGEST_SIZE, "crypto/siphash: invalid tag size") + dst[0] = _get_byte(7, hash) dst[1] = _get_byte(6, hash) dst[2] = _get_byte(5, hash) diff --git a/core/crypto/sm3/sm3.odin b/core/crypto/sm3/sm3.odin index f910d735b..6487c5e8c 100644 --- a/core/crypto/sm3/sm3.odin +++ b/core/crypto/sm3/sm3.odin @@ -53,7 +53,7 @@ init :: proc(ctx: ^Context) { // update adds more data to the Context. update :: proc(ctx: ^Context, data: []byte) { - assert(ctx.is_initialized) + ensure(ctx.is_initialized) data := data ctx.length += u64(len(data)) @@ -83,11 +83,8 @@ update :: proc(ctx: ^Context, data: []byte) { // Iff finalize_clone is set, final will work on a copy of the Context, // which is useful for for calculating rolling digests. final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { - assert(ctx.is_initialized) - - if len(hash) < DIGEST_SIZE { - panic("crypto/sm3: invalid destination digest size") - } + ensure(ctx.is_initialized) + ensure(len(hash) >= DIGEST_SIZE, "crypto/sm3: invalid destination digest size") ctx := ctx if finalize_clone { @@ -110,7 +107,7 @@ final :: proc(ctx: ^Context, hash: []byte, finalize_clone: bool = false) { length <<= 3 endian.unchecked_put_u64be(pad[:], length) update(ctx, pad[0:8]) - assert(ctx.bitlength == 0) + assert(ctx.bitlength == 0) // Check for bugs for i := 0; i < DIGEST_SIZE / 4; i += 1 { endian.unchecked_put_u32be(hash[i * 4:], ctx.state[i]) @@ -136,7 +133,7 @@ reset :: proc(ctx: ^Context) { SM3 implementation */ -@(private) +@(private, rodata) IV := [8]u32 { 0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e, diff --git a/core/crypto/x25519/x25519.odin b/core/crypto/x25519/x25519.odin index 412a767b8..6805c3ff8 100644 --- a/core/crypto/x25519/x25519.odin +++ b/core/crypto/x25519/x25519.odin @@ -15,7 +15,7 @@ SCALAR_SIZE :: 32 // POINT_SIZE is the size of a X25519 point (public key/shared secret) in bytes. POINT_SIZE :: 32 -@(private) +@(private, rodata) _BASE_POINT: [32]byte = {9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @(private) @@ -101,15 +101,9 @@ _scalarmult :: proc "contextless" (out, scalar, point: ^[32]byte) { // scalarmult "multiplies" the provided scalar and point, and writes the // resulting point to dst. scalarmult :: proc(dst, scalar, point: []byte) { - if len(scalar) != SCALAR_SIZE { - panic("crypto/x25519: invalid scalar size") - } - if len(point) != POINT_SIZE { - panic("crypto/x25519: invalid point size") - } - if len(dst) != POINT_SIZE { - panic("crypto/x25519: invalid destination point size") - } + ensure(len(scalar) == SCALAR_SIZE, "crypto/x25519: invalid scalar size") + ensure(len(point) == POINT_SIZE, "crypto/x25519: invalid point size") + ensure(len(dst) == POINT_SIZE, "crypto/x25519: invalid destination point size") // "clamp" the scalar e: [32]byte = --- diff --git a/core/crypto/x448/x448.odin b/core/crypto/x448/x448.odin new file mode 100644 index 000000000..43c5d25e0 --- /dev/null +++ b/core/crypto/x448/x448.odin @@ -0,0 +1,155 @@ +/* +package x448 implements the X448 (aka curve448) Elliptic-Curve +Diffie-Hellman key exchange protocol. + +See: +- [[ https://www.rfc-editor.org/rfc/rfc7748 ]] +*/ +package x448 + +import field "core:crypto/_fiat/field_curve448" +import "core:mem" + +// SCALAR_SIZE is the size of a X448 scalar (private key) in bytes. +SCALAR_SIZE :: 56 +// POINT_SIZE is the size of a X448 point (public key/shared secret) in bytes. +POINT_SIZE :: 56 + +@(private, rodata) +_BASE_POINT: [56]byte = { + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +} + +@(private) +_scalar_bit :: #force_inline proc "contextless" (s: ^[56]byte, i: int) -> u8 { + if i < 0 { + return 0 + } + return (s[i >> 3] >> uint(i & 7)) & 1 +} + +@(private) +_scalarmult :: proc "contextless" (out, scalar, point: ^[56]byte) { + // Montgomery pseudo-multiplication, using the RFC 7748 formula. + t1, t2: field.Loose_Field_Element = ---, --- + + // x_1 = u + // x_2 = 1 + // z_2 = 0 + // x_3 = u + // z_3 = 1 + x1: field.Tight_Field_Element = --- + field.fe_from_bytes(&x1, point) + + x2, x3, z2, z3: field.Tight_Field_Element = ---, ---, ---, --- + field.fe_one(&x2) + field.fe_zero(&z2) + field.fe_set(&x3, &x1) + field.fe_one(&z3) + + // swap = 0 + swap: int + + // For t = bits-1 down to 0:a + for t := 448 - 1; t >= 0; t -= 1 { + // k_t = (k >> t) & 1 + k_t := int(_scalar_bit(scalar, t)) + // swap ^= k_t + swap ~= k_t + // Conditional swap; see text below. + // (x_2, x_3) = cswap(swap, x_2, x_3) + field.fe_cond_swap(&x2, &x3, swap) + // (z_2, z_3) = cswap(swap, z_2, z_3) + field.fe_cond_swap(&z2, &z3, swap) + // swap = k_t + swap = k_t + + // Note: This deliberately omits reductions after add/sub operations + // if the result is only ever used as the input to a mul/square since + // the implementations of those can deal with non-reduced inputs. + // + // fe_tighten_cast is only used to store a fully reduced + // output in a Loose_Field_Element, or to provide such a + // Loose_Field_Element as a Tight_Field_Element argument. + + // A = x_2 + z_2 + field.fe_add(&t1, &x2, &z2) + // B = x_2 - z_2 + field.fe_sub(&t2, &x2, &z2) + // D = x_3 - z_3 + field.fe_sub(field.fe_relax_cast(&z2), &x3, &z3) // (z2 unreduced) + // DA = D * A + field.fe_carry_mul(&x2, field.fe_relax_cast(&z2), &t1) + // C = x_3 + z_3 + field.fe_add(field.fe_relax_cast(&z3), &x3, &z3) // (z3 unreduced) + // CB = C * B + field.fe_carry_mul(&x3, &t2, field.fe_relax_cast(&z3)) + // z_3 = x_1 * (DA - CB)^2 + field.fe_sub(field.fe_relax_cast(&z3), &x2, &x3) // (z3 unreduced) + field.fe_carry_square(&z3, field.fe_relax_cast(&z3)) + field.fe_carry_mul(&z3, field.fe_relax_cast(&x1), field.fe_relax_cast(&z3)) + // x_3 = (DA + CB)^2 + field.fe_add(field.fe_relax_cast(&z2), &x2, &x3) // (z2 unreduced) + field.fe_carry_square(&x3, field.fe_relax_cast(&z2)) + + // AA = A^2 + field.fe_carry_square(&z2, &t1) + // BB = B^2 + field.fe_carry_square(field.fe_tighten_cast(&t1), &t2) // (t1 reduced) + // x_2 = AA * BB + field.fe_carry_mul(&x2, field.fe_relax_cast(&z2), &t1) + // E = AA - BB + field.fe_sub(&t2, &z2, field.fe_tighten_cast(&t1)) // (t1 (input) is reduced) + // z_2 = E * (AA + a24 * E) + field.fe_carry_mul_small(field.fe_tighten_cast(&t1), &t2, 39081) // (t1 reduced) + field.fe_add(&t1, &z2, field.fe_tighten_cast(&t1)) // (t1 (input) is reduced) + field.fe_carry_mul(&z2, &t2, &t1) + } + + // Conditional swap; see text below. + // (x_2, x_3) = cswap(swap, x_2, x_3) + field.fe_cond_swap(&x2, &x3, swap) + // (z_2, z_3) = cswap(swap, z_2, z_3) + field.fe_cond_swap(&z2, &z3, swap) + + // Return x_2 * (z_2^(p - 2)) + field.fe_carry_inv(&z2, field.fe_relax_cast(&z2)) + field.fe_carry_mul(&x2, field.fe_relax_cast(&x2), field.fe_relax_cast(&z2)) + field.fe_to_bytes(out, &x2) + + field.fe_clear_vec([]^field.Tight_Field_Element{&x1, &x2, &x3, &z2, &z3}) + field.fe_clear_vec([]^field.Loose_Field_Element{&t1, &t2}) +} + +// scalarmult "multiplies" the provided scalar and point, and writes the +// resulting point to dst. +scalarmult :: proc(dst, scalar, point: []byte) { + ensure(len(scalar) == SCALAR_SIZE, "crypto/x448: invalid scalar size") + ensure(len(point) == POINT_SIZE, "crypto/x448: invalid point size") + ensure(len(dst) == POINT_SIZE, "crypto/x448: invalid destination point size") + + // "clamp" the scalar + e: [56]byte = --- + copy_slice(e[:], scalar) + e[0] &= 252 + e[55] |= 128 + + p: [56]byte = --- + copy_slice(p[:], point) + + d: [56]byte = --- + _scalarmult(&d, &e, &p) + copy_slice(dst, d[:]) + + mem.zero_explicit(&e, size_of(e)) + mem.zero_explicit(&d, size_of(d)) +} + +// scalarmult_basepoint "multiplies" the provided scalar with the X448 +// base point and writes the resulting point to dst. +scalarmult_basepoint :: proc(dst, scalar: []byte) { + scalarmult(dst, scalar, _BASE_POINT[:]) +} diff --git a/core/debug/trace/trace_windows.odin b/core/debug/trace/trace_windows.odin index c9868e338..04e92f125 100644 --- a/core/debug/trace/trace_windows.odin +++ b/core/debug/trace/trace_windows.odin @@ -49,10 +49,12 @@ _resolve :: proc(ctx: ^Context, frame: Frame, allocator: runtime.Allocator) -> ( data: [size_of(win32.SYMBOL_INFOW) + size_of([256]win32.WCHAR)]byte symbol := (^win32.SYMBOL_INFOW)(&data[0]) - symbol.SizeOfStruct = size_of(symbol) + // The value of SizeOfStruct must be the size of the whole struct, + // not just the size of the pointer + symbol.SizeOfStruct = size_of(symbol^) symbol.MaxNameLen = 255 if win32.SymFromAddrW(ctx.impl.hProcess, win32.DWORD64(frame), &{}, symbol) { - fl.procedure, _ = win32.wstring_to_utf8(&symbol.Name[0], -1, allocator) + fl.procedure, _ = win32.wstring_to_utf8(cstring16(&symbol.Name[0]), -1, allocator) } else { fl.procedure = fmt.aprintf("(procedure: 0x%x)", frame, allocator=allocator) } diff --git a/core/dynlib/lb_haiku.odin b/core/dynlib/lb_haiku.odin new file mode 100644 index 000000000..79e05505a --- /dev/null +++ b/core/dynlib/lb_haiku.odin @@ -0,0 +1,23 @@ +#+build haiku +#+private +package dynlib + +import "base:runtime" + +_LIBRARY_FILE_EXTENSION :: "" + +_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) { + return nil, false +} + +_unload_library :: proc(library: Library) -> bool { + return false +} + +_symbol_address :: proc(library: Library, symbol: string, allocator: runtime.Allocator) -> (ptr: rawptr, found: bool) { + return nil, false +} + +_last_error :: proc() -> string { + return "" +} diff --git a/core/dynlib/lib.odin b/core/dynlib/lib.odin index cd9eed5f8..e6b39be4b 100644 --- a/core/dynlib/lib.odin +++ b/core/dynlib/lib.odin @@ -145,6 +145,11 @@ initialize_symbols :: proc( } } + // No field for it in the struct. + if handle == nil { + handle = load_library(library_path) or_return + } + // Buffer to concatenate the prefix + symbol name. prefixed_symbol_buf: [2048]u8 = --- diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin index 05cd2cb3c..95372dac6 100644 --- a/core/dynlib/lib_windows.odin +++ b/core/dynlib/lib_windows.odin @@ -13,7 +13,7 @@ _LIBRARY_FILE_EXTENSION :: "dll" _load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) { // NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL wide_path := win32.utf8_to_wstring(path, allocator) - defer free(wide_path, allocator) + defer free(rawptr(wide_path), allocator) handle := cast(Library)win32.LoadLibraryW(wide_path) return handle, handle != nil } diff --git a/core/encoding/base32/base32_test.odin b/core/encoding/base32/base32_test.odin index ea41ae36f..07d5c8080 100644 --- a/core/encoding/base32/base32_test.odin +++ b/core/encoding/base32/base32_test.odin @@ -1,3 +1,4 @@ +#+test package encoding_base32 import "core:testing" diff --git a/core/encoding/cbor/cbor.odin b/core/encoding/cbor/cbor.odin index 8eb829ed3..1fb7c34ab 100644 --- a/core/encoding/cbor/cbor.odin +++ b/core/encoding/cbor/cbor.odin @@ -385,17 +385,17 @@ to_diagnostic_format_writer :: proc(w: io.Writer, val: Value, padding := 0) -> i // which we want for the diagnostic format. case f16: buf: [64]byte - str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f16), 8*size_of(f16)) + str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f16), 8*size_of(f16)) if str[0] == '+' && str != "+Inf" { str = str[1:] } io.write_string(w, str) or_return case f32: buf: [128]byte - str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f32), 8*size_of(f32)) + str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f32), 8*size_of(f32)) if str[0] == '+' && str != "+Inf" { str = str[1:] } io.write_string(w, str) or_return case f64: buf: [256]byte - str := strconv.append_float(buf[:], f64(v), 'f', 2*size_of(f64), 8*size_of(f64)) + str := strconv.write_float(buf[:], f64(v), 'f', 2*size_of(f64), 8*size_of(f64)) if str[0] == '+' && str != "+Inf" { str = str[1:] } io.write_string(w, str) or_return diff --git a/core/encoding/cbor/marshal.odin b/core/encoding/cbor/marshal.odin index aca71deb2..b23087c90 100644 --- a/core/encoding/cbor/marshal.odin +++ b/core/encoding/cbor/marshal.odin @@ -612,6 +612,42 @@ _marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (er case: panic("unknown bit_size size") } + case runtime.Type_Info_Matrix: + count := info.column_count * info.elem_stride + err_conv(_encode_u64(e, u64(count), .Array)) or_return + + if impl, ok := _tag_implementations_type[info.elem.id]; ok { + for i in 0..marshal(e, any{rawptr(data), info.elem.id}) or_return + } + return + } + + elem_ti := runtime.type_info_core(type_info_of(info.elem.id)) + for i in 0..marshal(e, any{rawptr(data), info.elem.id}) or_return + } + return + } + + elem_ti := runtime.type_info_core(type_info_of(info.elem.id)) + for i in 0.. (err: Unmarshal_Error) { @@ -51,6 +52,11 @@ unmarshal_from_string :: proc(s: string, ptr: ^$T, flags := Decoder_Flags{}, all return } +// Unmarshals from a slice of bytes, see docs on the proc group `Unmarshal` for more info. +unmarshal_from_bytes :: proc(bytes: []byte, ptr: ^$T, flags := Decoder_Flags{}, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { + return unmarshal_from_string(string(bytes), ptr, flags, allocator, temp_allocator, loc) +} + unmarshal_from_decoder :: proc(d: Decoder, ptr: ^$T, allocator := context.allocator, temp_allocator := context.temp_allocator, loc := #caller_location) -> (err: Unmarshal_Error) { d := d @@ -329,6 +335,8 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.a _unmarshal_bytes :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header, add: Add, allocator := context.allocator, loc := #caller_location) -> (err: Unmarshal_Error) { #partial switch t in ti.variant { case reflect.Type_Info_String: + assert(t.encoding == .UTF_8) + bytes := err_conv(_decode_bytes(d, add, allocator=allocator, loc=loc)) or_return if t.is_cstring { @@ -487,7 +495,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header data := mem.alloc_bytes_non_zeroed(t.elem.size * scap, t.elem.align, allocator=allocator, loc=loc) or_return defer if err != nil { mem.free_bytes(data, allocator=allocator, loc=loc) } - da := mem.Raw_Dynamic_Array{raw_data(data), 0, length, context.allocator } + da := mem.Raw_Dynamic_Array{raw_data(data), 0, scap, context.allocator } assign_array(d, &da, t.elem, length) or_return @@ -585,6 +593,31 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header if out_of_space { return _unsupported(v, hdr) } return + case reflect.Type_Info_Matrix: + count := t.column_count * t.elem_stride + length, _ := err_conv(_decode_len_container(d, add)) or_return + if length > count { + return _unsupported(v, hdr) + } + + da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator } + + out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return + if out_of_space { return _unsupported(v, hdr) } + return + + case reflect.Type_Info_Simd_Vector: + length, _ := err_conv(_decode_len_container(d, add)) or_return + if length > t.count { + return _unsupported(v, hdr) + } + + da := mem.Raw_Dynamic_Array{rawptr(v.data), 0, length, allocator } + + out_of_space := assign_array(d, &da, t.elem, length, growable=false) or_return + if out_of_space { return _unsupported(v, hdr) } + return + case: return _unsupported(v, hdr) } } diff --git a/core/encoding/csv/doc.odin b/core/encoding/csv/doc.odin index bfeadafd6..7abe2be49 100644 --- a/core/encoding/csv/doc.odin +++ b/core/encoding/csv/doc.odin @@ -63,8 +63,6 @@ Example: read_csv_from_string :: proc(filename: string) { r: csv.Reader r.trim_leading_space = true - r.reuse_record = true // Without it you have to delete(record) - r.reuse_record_buffer = true // Without it you have to each of the fields within it defer csv.reader_destroy(&r) csv_data, ok := os.read_entire_file(filename) diff --git a/core/encoding/csv/reader.odin b/core/encoding/csv/reader.odin index 5348624d5..577ef219d 100644 --- a/core/encoding/csv/reader.odin +++ b/core/encoding/csv/reader.odin @@ -130,7 +130,7 @@ reader_destroy :: proc(r: ^Reader) { for record, row_idx in csv.iterator_next(&r) { ... } TIP: If you process the results within the loop and don't need to own the results, - you can set the Reader's `reuse_record` and `reuse_record_reuse_record_buffer` to true; + you can set the Reader's `reuse_record` and `reuse_record_buffer` to true; you won't need to delete the record or its fields. */ iterator_next :: proc(r: ^Reader) -> (record: []string, idx: int, err: Error, more: bool) { diff --git a/core/encoding/entity/entity.odin b/core/encoding/entity/entity.odin index d2f1d46b2..cb8fa8611 100644 --- a/core/encoding/entity/entity.odin +++ b/core/encoding/entity/entity.odin @@ -108,7 +108,7 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := it couldn't have been part of an XML tag body to be decoded here. Keep in mind that we could already *be* inside a CDATA tag. - If so, write `>` as a literal and continue. + If so, write `<` as a literal and continue. */ if in_data { write_rune(&builder, '<') @@ -119,11 +119,9 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator := case ']': // If we're unboxing _and_ decoding CDATA, we'll have to check for the end tag. if in_data { - if t.read_offset + len(CDATA_END) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { - in_data = false - t.read_offset += len(CDATA_END) - 1 - } + if strings.has_prefix(t.src[t.offset:], CDATA_END) { + in_data = false + t.read_offset += len(CDATA_END) - 1 } continue } else { @@ -297,40 +295,40 @@ _handle_xml_special :: proc(t: ^Tokenizer, builder: ^strings.Builder, options: X assert(t != nil && t.r == '<') if t.read_offset + len(CDATA_START) >= len(t.src) { return false, .None } - if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { - t.read_offset += len(CDATA_START) - 1 - + s := string(t.src[t.offset:]) + if strings.has_prefix(s, CDATA_START) { if .Unbox_CDATA in options && .Decode_CDATA in options { // We're unboxing _and_ decoding CDATA + t.read_offset += len(CDATA_START) - 1 return true, .None } - // CDATA is passed through. - offset := t.offset - - // Scan until end of CDATA. + // CDATA is passed through. Scan until end of CDATA. + start_offset := t.offset + t.read_offset += len(CDATA_START) for { - advance(t) or_return - if t.r < 0 { return true, .CDATA_Not_Terminated } + advance(t) + if t.r < 0 { + // error(t, offset, "[scan_string] CDATA was not terminated\n") + return true, .CDATA_Not_Terminated + } - if t.read_offset + len(CDATA_END) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { - t.read_offset += len(CDATA_END) - 1 + // Scan until the end of a CDATA tag. + if s = string(t.src[t.read_offset:]); strings.has_prefix(s, CDATA_END) { + t.read_offset += len(CDATA_END) + cdata := string(t.src[start_offset:t.read_offset]) - cdata := string(t.src[offset : t.read_offset]) - - if .Unbox_CDATA in options { - cdata = cdata[len(CDATA_START):] - cdata = cdata[:len(cdata) - len(CDATA_END)] - } - - write_string(builder, cdata) - return false, .None + if .Unbox_CDATA in options { + cdata = cdata[len(CDATA_START):] + cdata = cdata[:len(cdata) - len(CDATA_END)] } + write_string(builder, cdata) + return false, .None } } - } else if string(t.src[t.offset:][:len(COMMENT_START)]) == COMMENT_START { + + } else if strings.has_prefix(s, COMMENT_START) { t.read_offset += len(COMMENT_START) // Comment is passed through by default. offset := t.offset diff --git a/core/encoding/hxa/read.odin b/core/encoding/hxa/read.odin index a679946f8..6dde16848 100644 --- a/core/encoding/hxa/read.odin +++ b/core/encoding/hxa/read.odin @@ -79,7 +79,6 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato read_meta :: proc(r: ^Reader, capacity: u32le, allocator := context.allocator, loc := #caller_location) -> (meta_data: []Meta, err: Read_Error) { meta_data = make([]Meta, int(capacity), allocator=allocator) count := 0 - defer meta_data = meta_data[:count] for &m in meta_data { m.name = read_name(r) or_return @@ -105,6 +104,7 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato count += 1 } + meta_data = meta_data[:count] return } @@ -112,7 +112,6 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato stack_count := read_value(r, u32le) or_return layer_count := 0 layers = make(Layer_Stack, stack_count, allocator=allocator, loc=loc) - defer layers = layers[:layer_count] for &layer in layers { layer.name = read_name(r) or_return layer.components = read_value(r, u8) or_return @@ -136,6 +135,7 @@ read :: proc(data: []byte, filename := "", print_error := false, allocato layer_count += 1 } + layers = layers[:layer_count] return } diff --git a/core/encoding/json/marshal.odin b/core/encoding/json/marshal.odin index ed6de2f52..2fb507edf 100644 --- a/core/encoding/json/marshal.odin +++ b/core/encoding/json/marshal.odin @@ -108,13 +108,13 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) { switch i in a { case u8, u16, u32, u64, u128: - s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix }) + s = strconv.write_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix }) case: - s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) + s = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) } } else { - s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) + s = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil) } io.write_string(w, s) or_return @@ -292,7 +292,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: case runtime.Type_Info_Integer: buf: [40]byte u := cast_any_int_to_u128(ka) - name = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*kti.size, "0123456789", nil) + name = strconv.write_bits_128(buf[:], u, 10, info.signed, 8*kti.size, "0123456789", nil) opt_write_key(w, opt, name) or_return case: return .Unsupported_Type @@ -359,10 +359,10 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: #partial switch info in ti.variant { case runtime.Type_Info_String: switch x in v { - case string: - return x == "" - case cstring: - return x == nil || x == "" + case string: return x == "" + case cstring: return x == nil || x == "" + case string16: return x == "" + case cstring16: return x == nil || x == "" } case runtime.Type_Info_Any: return v.(any) == nil diff --git a/core/encoding/json/tokenizer.odin b/core/encoding/json/tokenizer.odin index e46d879a7..ad928b7d9 100644 --- a/core/encoding/json/tokenizer.odin +++ b/core/encoding/json/tokenizer.odin @@ -101,7 +101,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { } } - scan_espace :: proc(t: ^Tokenizer) -> bool { + scan_escape :: proc(t: ^Tokenizer) -> bool { switch t.r { case '"', '\'', '\\', '/', 'b', 'n', 'r', 't', 'f': next_rune(t) @@ -310,7 +310,7 @@ get_token :: proc(t: ^Tokenizer) -> (token: Token, err: Error) { break } if r == '\\' { - scan_espace(t) + scan_escape(t) } } diff --git a/core/encoding/json/unmarshal.odin b/core/encoding/json/unmarshal.odin index 57371e360..0b65adaac 100644 --- a/core/encoding/json/unmarshal.odin +++ b/core/encoding/json/unmarshal.odin @@ -117,9 +117,25 @@ assign_int :: proc(val: any, i: $T) -> bool { case uint: dst = uint (i) case uintptr: dst = uintptr(i) case: + is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool { + if ti == nil { + return false + } + t := runtime.type_info_base(ti) + #partial switch info in t.variant { + case runtime.Type_Info_Integer: + switch info.endianness { + case .Platform: return false + case .Little: return ODIN_ENDIAN != .Little + case .Big: return ODIN_ENDIAN != .Big + } + } + return false + } + ti := type_info_of(v.id) - if _, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok { - do_byte_swap := !reflect.bit_set_is_big_endian(v) + if info, ok := ti.variant.(runtime.Type_Info_Bit_Set); ok { + do_byte_swap := is_bit_set_different_endian_to_platform(info.underlying) switch ti.size * 8 { case 0: // no-op. case 8: @@ -390,6 +406,9 @@ unmarshal_expect_token :: proc(p: ^Parser, kind: Token_Kind, loc := #caller_loca return prev } +// Struct tags can include not only the name of the JSON key, but also a tag such as `omitempty`. +// Example: `json:"key_name,omitempty"` +// This returns the first field as `json_name`, and the rest are returned as `extra`. @(private) json_name_from_tag_value :: proc(value: string) -> (json_name, extra: string) { json_name = value @@ -425,12 +444,6 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm defer delete(key, p.allocator) unmarshal_expect_token(p, .Colon) - - field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool { - prev_set := field_used[offset/8] & byte(offset&7) != 0 - field_used[offset/8] |= byte(offset&7) - return prev_set - } field_used_bytes := (reflect.size_of_typeid(ti.id)+7)/8 field_used := intrinsics.alloca(field_used_bytes + 1, 1) // + 1 to not overflow on size_of 0 types. @@ -449,7 +462,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm if use_field_idx < 0 { for field, field_idx in fields { - if key == field.name { + tag_value := reflect.struct_tag_get(field.tag, "json") + json_name, _ := json_name_from_tag_value(tag_value) + if json_name == "" && key == field.name { use_field_idx = field_idx break } @@ -470,7 +485,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm } } - if field.name == key || (field.tag != "" && reflect.struct_tag_get(field.tag, "json") == key) { + tag_value := reflect.struct_tag_get(field.tag, "json") + json_name, _ := json_name_from_tag_value(tag_value) + if (json_name == "" && field.name == key) || json_name == key { offset = field.offset type = field.type found = true @@ -492,6 +509,11 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm } if field_found { + field_test :: #force_inline proc "contextless" (field_used: [^]byte, offset: uintptr) -> bool { + prev_set := field_used[offset/8] & byte(offset&7) != 0 + field_used[offset/8] |= byte(offset&7) + return prev_set + } if field_test(field_used, offset) { return .Multiple_Use_Field } @@ -548,7 +570,9 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm key_ptr: rawptr #partial switch tk in t.key.variant { - case runtime.Type_Info_String: + case runtime.Type_Info_String: + assert(tk.encoding == .UTF_8) + key_ptr = rawptr(&key) key_cstr: cstring if reflect.is_cstring(t.key) { diff --git a/core/encoding/uuid/generation.odin b/core/encoding/uuid/generation.odin index 7c9d4b80c..b210f6a52 100644 --- a/core/encoding/uuid/generation.odin +++ b/core/encoding/uuid/generation.odin @@ -240,7 +240,7 @@ Example: import "core:encoding/uuid" import "core:fmt" - main :: proc() { + generate_v8_hash_bytes_example :: proc() { my_uuid := uuid.generate_v8_hash(uuid.Namespace_DNS, "www.odin-lang.org", .SHA256) my_uuid_string := uuid.to_string(my_uuid, context.temp_allocator) fmt.println(my_uuid_string) @@ -306,7 +306,7 @@ Example: import "core:encoding/uuid" import "core:fmt" - main :: proc() { + generate_v8_hash_string_example :: proc() { my_uuid := uuid.generate_v8_hash(uuid.Namespace_DNS, "www.odin-lang.org", .SHA256) my_uuid_string := uuid.to_string(my_uuid, context.temp_allocator) fmt.println(my_uuid_string) diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index a2bbaf28e..3ef9a6388 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -16,6 +16,7 @@ package encoding_xml import "core:fmt" import "core:unicode" import "core:unicode/utf8" +import "core:strings" Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any) @@ -121,7 +122,7 @@ default_error_handler :: proc(pos: Pos, msg: string, args: ..any) { error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { pos := offset_to_pos(t, offset) if t.err != nil { - t.err(pos, msg, ..args) + t.err(pos=pos, fmt=msg, args=args) } t.error_count += 1 } @@ -268,32 +269,27 @@ scan_comment :: proc(t: ^Tokenizer) -> (comment: string, err: Error) { // Skip CDATA skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) { - if t.read_offset + len(CDATA_START) >= len(t.src) { - // Can't be the start of a CDATA tag. + if s := string(t.src[t.offset:]); !strings.has_prefix(s, CDATA_START) { return .None } - if string(t.src[t.offset:][:len(CDATA_START)]) == CDATA_START { - t.read_offset += len(CDATA_START) - offset := t.offset + t.read_offset += len(CDATA_START) + offset := t.offset - cdata_scan: for { - advance_rune(t) - if t.ch < 0 { - error(t, offset, "[scan_string] CDATA was not terminated\n") - return .Premature_EOF - } + cdata_scan: for { + advance_rune(t) + if t.ch < 0 { + error(t, offset, "[scan_string] CDATA was not terminated\n") + return .Premature_EOF + } - // Scan until the end of a CDATA tag. - if t.read_offset + len(CDATA_END) < len(t.src) { - if string(t.src[t.offset:][:len(CDATA_END)]) == CDATA_END { - t.read_offset += len(CDATA_END) - break cdata_scan - } - } + // Scan until the end of a CDATA tag. + if s := string(t.src[t.read_offset:]); strings.has_prefix(s, CDATA_END) { + t.read_offset += len(CDATA_END) + break cdata_scan } } - return + return .None } @(optimization_mode="favor_size") @@ -393,6 +389,8 @@ scan :: proc(t: ^Tokenizer, multiline_string := false) -> Token { case '/': kind = .Slash case '-': kind = .Dash case ':': kind = .Colon + case '[': kind = .Open_Bracket + case ']': kind = .Close_Bracket case '"', '\'': kind = .Invalid diff --git a/core/encoding/xml/xml_reader.odin b/core/encoding/xml/xml_reader.odin index b8c8b13a4..707d2b3f3 100644 --- a/core/encoding/xml/xml_reader.odin +++ b/core/encoding/xml/xml_reader.odin @@ -56,7 +56,7 @@ Option_Flag :: enum { Option_Flags :: bit_set[Option_Flag; u16] Document :: struct { - elements: [dynamic]Element, + elements: [dynamic]Element `fmt:"v,element_count"`, element_count: Element_ID, prologue: Attributes, @@ -70,15 +70,15 @@ Document :: struct { // If we encounter comments before the root node, and the option to intern comments is given, this is where they'll live. // Otherwise they'll be in the element tree. - comments: [dynamic]string, + comments: [dynamic]string `fmt:"-"`, // Internal - tokenizer: ^Tokenizer, - allocator: mem.Allocator, + tokenizer: ^Tokenizer `fmt:"-"`, + allocator: mem.Allocator `fmt:"-"`, // Input. Either the original buffer, or a copy if `.Input_May_Be_Modified` isn't specified. - input: []u8, - strings_to_free: [dynamic]string, + input: []u8 `fmt:"-"`, + strings_to_free: [dynamic]string `fmt:"-"`, } Element :: struct { @@ -175,7 +175,7 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha data = bytes.clone(data) } - t := &Tokenizer{} + t := new(Tokenizer) init(t, string(data), path, error_handler) doc = new(Document) @@ -195,7 +195,6 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha loop: for { skip_whitespace(t) - // NOTE(Jeroen): This is faster as a switch. switch t.ch { case '<': // Consume peeked `<` @@ -306,9 +305,17 @@ parse_bytes :: proc(data: []u8, options := DEFAULT_OPTIONS, path := "", error_ha } } + case .Open_Bracket: + // This could be a CDATA tag part of a tag's body. Unread the ` (attr: Attribute, offset: int, err: E t := doc.tokenizer key := expect(t, .Ident) or_return - offset = t.offset - len(key.text) - _ = expect(t, .Eq) or_return value := expect(t, .String, multiline_string=true) or_return @@ -591,6 +566,47 @@ parse_doctype :: proc(doc: ^Document) -> (err: Error) { return .None } +parse_body :: proc(doc: ^Document, element: Element_ID, opts: Options) -> (err: Error) { + assert(doc != nil) + context.allocator = doc.allocator + t := doc.tokenizer + + body_text := scan_string(t, t.offset) or_return + needs_processing := .Unbox_CDATA in opts.flags + needs_processing |= .Decode_SGML_Entities in opts.flags + + if !needs_processing { + append(&doc.elements[element].value, body_text) + return + } + + decode_opts := entity.XML_Decode_Options{} + if .Keep_Tag_Body_Comments not_in opts.flags { + decode_opts += { .Comment_Strip } + } + + if .Decode_SGML_Entities not_in opts.flags { + decode_opts += { .No_Entity_Decode } + } + + if .Unbox_CDATA in opts.flags { + decode_opts += { .Unbox_CDATA } + if .Decode_SGML_Entities in opts.flags { + decode_opts += { .Decode_CDATA } + } + } + + decoded, decode_err := entity.decode_xml(body_text, decode_opts) + if decode_err == .None { + append(&doc.elements[element].value, decoded) + append(&doc.strings_to_free, decoded) + } else { + append(&doc.elements[element].value, body_text) + } + + return +} + Element_ID :: u32 new_element :: proc(doc: ^Document) -> (id: Element_ID) { @@ -609,4 +625,4 @@ new_element :: proc(doc: ^Document) -> (id: Element_ID) { cur := doc.element_count doc.element_count += 1 return cur -} +} \ No newline at end of file diff --git a/core/flags/constants.odin b/core/flags/constants.odin index 6f5281928..dc2663e2a 100644 --- a/core/flags/constants.odin +++ b/core/flags/constants.odin @@ -19,7 +19,7 @@ SUBTAG_NAME :: "name" SUBTAG_POS :: "pos" SUBTAG_REQUIRED :: "required" SUBTAG_HIDDEN :: "hidden" -SUBTAG_VARIADIC :: "variadic" +SUBTAG_MANIFOLD :: "manifold" SUBTAG_FILE :: "file" SUBTAG_PERMS :: "perms" SUBTAG_INDISTINCT :: "indistinct" @@ -28,7 +28,7 @@ TAG_USAGE :: "usage" UNDOCUMENTED_FLAG :: "" -INTERNAL_VARIADIC_FLAG :: "varg" +INTERNAL_OVERFLOW_FLAG :: #config(ODIN_CORE_FLAGS_OVERFLOW_FLAG, "overflow") RESERVED_HELP_FLAG :: "help" RESERVED_HELP_FLAG_SHORT :: "h" diff --git a/core/flags/doc.odin b/core/flags/doc.odin index b97547806..440acd52c 100644 --- a/core/flags/doc.odin +++ b/core/flags/doc.odin @@ -20,6 +20,17 @@ The format is similar to the Odin binary's way of handling compiler flags. -:= set map[key] to value +Unhandled Arguments: + +All unhandled positional arguments are placed into the `overflow` field on a +struct, if it exists. In UNIX-style parsing, the existence of a `--` on the +command line will also pass all arguments afterwards into this field. + +If desired, the name of the field may be changed from `overflow` to any string +by setting the `ODIN_CORE_FLAGS_OVERFLOW_FLAG` compile-time config option with +`-define:ODIN_CORE_FLAGS_OVERFLOW_FLAG=`. + + Struct Tags: Users of the `core:encoding/json` package may be familiar with using tags to @@ -32,7 +43,7 @@ Under the `args` tag, there are the following subtags: - `pos=N`: place positional argument `N` into this flag. - `hidden`: hide this flag from the usage documentation. - `required`: cause verification to fail if this argument is not set. -- `variadic`: take all remaining arguments when set, UNIX-style only. +- `manifold=N`: take several arguments at once, UNIX-style only. - `file`: for `os.Handle` types, file open mode. - `perms`: for `os.Handle` types, file open permissions. - `indistinct`: allow the setting of distinct types by their base type. @@ -47,8 +58,9 @@ you want to require 3 and only 3 arguments in a dynamic array, you would specify `required=3<4`. -`variadic` may be given a number (`variadic=N`) above 1 to limit how many extra -arguments it consumes. +`manifold` may be given a number (`manifold=N`) above 1 to limit how many extra +arguments it consumes at once. If this number is not specified, it will take as +many arguments as can be converted to the underlying element type. `file` determines the file open mode for an `os.Handle`. @@ -160,7 +172,7 @@ at parse time. --flag --flag=argument --flag argument - --flag argument repeating-argument + --flag argument (manifold-argument) `-flag` may also be substituted for `--flag`. diff --git a/core/flags/errors.odin b/core/flags/errors.odin index 6e48f6ccf..3d34a95d3 100644 --- a/core/flags/errors.odin +++ b/core/flags/errors.odin @@ -4,7 +4,7 @@ import "core:os" Parse_Error_Reason :: enum { None, - // An extra positional argument was given, and there is no `varg` field. + // An extra positional argument was given, and there is no `overflow` field. Extra_Positional, // The underlying type does not support the string value it is being set to. Bad_Value, diff --git a/core/flags/example/example.odin b/core/flags/example/example.odin index b1d7b58d6..a3af44790 100644 --- a/core/flags/example/example.odin +++ b/core/flags/example/example.odin @@ -107,14 +107,14 @@ main :: proc() { // assignments: map[string]u8 `args:"name=assign" usage:"Number of jobs per worker."`, - // (Variadic) Only available in UNIX style: + // (Manifold) Only available in UNIX style: - // bots: [dynamic]string `args:"variadic=2,required"`, + // bots: [dynamic]string `args:"manifold=2,required"`, verbose: bool `usage:"Show verbose output."`, debug: bool `args:"hidden" usage:"print debug info"`, - varg: [dynamic]string `usage:"Any extra arguments go here."`, + overflow: [dynamic]string `usage:"Any extra arguments go here."`, } opt: Options diff --git a/core/flags/internal_assignment.odin b/core/flags/internal_assignment.odin index 12ddb876f..5999dbf2d 100644 --- a/core/flags/internal_assignment.odin +++ b/core/flags/internal_assignment.odin @@ -33,9 +33,9 @@ push_positional :: #force_no_inline proc (model: ^$T, parser: ^Parser, arg: stri field, index, has_pos_assigned := get_field_by_pos(model, pos) if !has_pos_assigned { - when intrinsics.type_has_field(T, INTERNAL_VARIADIC_FLAG) { + when intrinsics.type_has_field(T, INTERNAL_OVERFLOW_FLAG) { // Add it to the fallback array. - field = reflect.struct_field_by_name(T, INTERNAL_VARIADIC_FLAG) + field = reflect.struct_field_by_name(T, INTERNAL_OVERFLOW_FLAG) } else { return Parse_Error { .Extra_Positional, @@ -117,8 +117,8 @@ set_unix_flag :: proc(model: ^$T, parser: ^Parser, name: string) -> (future_args case runtime.Type_Info_Dynamic_Array: future_args = 1 if tag, ok := reflect.struct_tag_lookup(field.tag, TAG_ARGS); ok { - if length, is_variadic := get_struct_subtag(tag, SUBTAG_VARIADIC); is_variadic { - // Variadic arrays may specify how many arguments they consume at once. + if length, is_manifold := get_struct_subtag(tag, SUBTAG_MANIFOLD); is_manifold { + // Manifold arrays may specify how many arguments they consume at once. // Otherwise, they take everything that's left. if value, value_ok := strconv.parse_u64_of_base(length, 10); value_ok { future_args = cast(int)value diff --git a/core/flags/internal_parsing.odin b/core/flags/internal_parsing.odin index 4e49f45b0..6d544e5af 100644 --- a/core/flags/internal_parsing.odin +++ b/core/flags/internal_parsing.odin @@ -95,7 +95,7 @@ parse_one_unix_arg :: proc(model: ^$T, parser: ^Parser, arg: string) -> ( // `--`, and only `--`. // Everything from now on will be treated as an argument. future_args = max(int) - current_flag = INTERNAL_VARIADIC_FLAG + current_flag = INTERNAL_OVERFLOW_FLAG return } } diff --git a/core/flags/internal_rtti.odin b/core/flags/internal_rtti.odin index 1c559ca55..a1b050597 100644 --- a/core/flags/internal_rtti.odin +++ b/core/flags/internal_rtti.odin @@ -127,6 +127,8 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info: } case runtime.Type_Info_String: + assert(specific_type_info.encoding == .UTF_8) + if specific_type_info.is_cstring { cstr_ptr := (^cstring)(ptr) if cstr_ptr != nil { diff --git a/core/flags/internal_validation.odin b/core/flags/internal_validation.odin index afd05331c..cd903c3e5 100644 --- a/core/flags/internal_validation.odin +++ b/core/flags/internal_validation.odin @@ -59,7 +59,8 @@ validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_ } } - if pos_str, has_pos := get_struct_subtag(args_tag, SUBTAG_POS); has_pos { + pos_str, has_pos := get_struct_subtag(args_tag, SUBTAG_POS) + if has_pos { #partial switch specific_type_info in field.type.variant { case runtime.Type_Info_Map: fmt.panicf("%T.%s has `%s` defined, and this does not make sense on a map type.", @@ -79,7 +80,7 @@ validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_ fmt.assertf(!reflect.is_boolean(field.type), "%T.%s is a required boolean. This is disallowed.", model_type, field.name, loc = loc) - fmt.assertf(field.name != INTERNAL_VARIADIC_FLAG, "%T.%s is defined as required. This is disallowed.", + fmt.assertf(field.name != INTERNAL_OVERFLOW_FLAG, "%T.%s is defined as required. This is disallowed.", model_type, field.name, loc = loc) if len(requirement) > 0 { @@ -109,24 +110,28 @@ validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_ } } - if length, is_variadic := get_struct_subtag(args_tag, SUBTAG_VARIADIC); is_variadic { + if length, is_manifold := get_struct_subtag(args_tag, SUBTAG_MANIFOLD); is_manifold { + fmt.assertf(!has_pos, + "%T.%s has both `%s` and `%s` defined. This is disallowed.\n\tSuggestion: Use a dynamic array field named `%s` to accept unspecified positional arguments.", + model_type, field.name, SUBTAG_POS, SUBTAG_MANIFOLD, INTERNAL_OVERFLOW_FLAG, loc = loc) + if value, parse_ok := strconv.parse_u64_of_base(length, 10); parse_ok { fmt.assertf(value > 0, "%T.%s has `%s` set to %i. It must be greater than zero.", - model_type, field.name, value, SUBTAG_VARIADIC, loc = loc) + model_type, field.name, value, SUBTAG_MANIFOLD, loc = loc) fmt.assertf(value != 1, - "%T.%s has `%s` set to 1. This has no effect.", - model_type, field.name, SUBTAG_VARIADIC, loc = loc) + "%T.%s has `%s` set to 1. This is equivalent to not defining `%s`.", + model_type, field.name, SUBTAG_MANIFOLD, SUBTAG_MANIFOLD, loc = loc) } #partial switch specific_type_info in field.type.variant { case runtime.Type_Info_Dynamic_Array: fmt.assertf(style != .Odin, "%T.%s has `%s` defined, but this only makes sense in UNIX-style parsing mode.", - model_type, field.name, SUBTAG_VARIADIC, loc = loc) + model_type, field.name, SUBTAG_MANIFOLD, loc = loc) case: fmt.panicf("%T.%s has `%s` defined, but this only makes sense on dynamic arrays.", - model_type, field.name, SUBTAG_VARIADIC, loc = loc) + model_type, field.name, SUBTAG_MANIFOLD, loc = loc) } } diff --git a/core/flags/parsing.odin b/core/flags/parsing.odin index 2d8ce34eb..989a9a1a6 100644 --- a/core/flags/parsing.odin +++ b/core/flags/parsing.odin @@ -6,7 +6,7 @@ package flags Parsing_Style :: enum { // Odin-style: `-flag`, `-flag:option`, `-map:key=value` Odin, - // UNIX-style: `-flag` or `--flag`, `--flag=argument`, `--flag argument repeating-argument` + // UNIX-style: `-flag` or `--flag`, `--flag=argument`, `--flag argument (manifold-argument)` Unix, } @@ -61,7 +61,7 @@ parse :: proc( } case .Unix: - // Support for `-flag argument (repeating-argument ...)` + // Support for `-flag argument (manifold-argument ...)` future_args: int current_flag: string diff --git a/core/flags/rtti.odin b/core/flags/rtti.odin index ce7a23773..058292698 100644 --- a/core/flags/rtti.odin +++ b/core/flags/rtti.odin @@ -38,6 +38,6 @@ Note that only one can be active at a time. Inputs: - setter: The type setter. Pass `nil` to disable any previously set setter. */ -register_type_setter :: proc(setter: Custom_Type_Setter) { +register_type_setter :: proc "contextless" (setter: Custom_Type_Setter) { global_custom_type_setter = setter } diff --git a/core/flags/usage.odin b/core/flags/usage.odin index c42df7576..a44baec81 100644 --- a/core/flags/usage.odin +++ b/core/flags/usage.odin @@ -30,18 +30,18 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty is_positional: bool, is_required: bool, is_boolean: bool, - is_variadic: bool, - variadic_length: int, + is_manifold: bool, + manifold_length: int, } // // POSITIONAL+REQUIRED, POSITIONAL, REQUIRED, NON_REQUIRED+NON_POSITIONAL, ... // sort_flags :: proc(i, j: Flag) -> slice.Ordering { - // `varg` goes to the end. - if i.name == INTERNAL_VARIADIC_FLAG { + // `overflow` goes to the end. + if i.name == INTERNAL_OVERFLOW_FLAG { return .Greater - } else if j.name == INTERNAL_VARIADIC_FLAG { + } else if j.name == INTERNAL_OVERFLOW_FLAG { return .Less } @@ -120,10 +120,10 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty flag.is_required = true flag.required_min, flag.required_max, _ = parse_requirements(requirement) } - if length_str, is_variadic := get_struct_subtag(args_tag, SUBTAG_VARIADIC); is_variadic { - flag.is_variadic = true + if length_str, is_manifold := get_struct_subtag(args_tag, SUBTAG_MANIFOLD); is_manifold { + flag.is_manifold = true if length, parse_ok := strconv.parse_u64_of_base(length_str, 10); parse_ok { - flag.variadic_length = cast(int)length + flag.manifold_length = cast(int)length } } } @@ -147,15 +147,15 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty case runtime.Type_Info_Dynamic_Array: requirement_spec := describe_array_requirements(flag) - if flag.is_variadic || flag.name == INTERNAL_VARIADIC_FLAG { - if flag.variadic_length == 0 { + if flag.is_manifold || flag.name == INTERNAL_OVERFLOW_FLAG { + if flag.manifold_length == 0 { flag.type_description = fmt.tprintf("<%v, ...>%s", specific_type_info.elem.id, requirement_spec) } else { flag.type_description = fmt.tprintf("<%v, %i at once>%s", specific_type_info.elem.id, - flag.variadic_length, + flag.manifold_length, requirement_spec) } } else { @@ -177,7 +177,7 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty } } - if flag.name == INTERNAL_VARIADIC_FLAG { + if flag.name == INTERNAL_OVERFLOW_FLAG { flag.full_length = len(flag.type_description) } else if flag.is_boolean { flag.full_length = len(flag_prefix) + len(flag.name) + len(flag.type_description) @@ -201,13 +201,13 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty strings.write_string(&builder, program) for flag in visible_flags { - if keep_it_short && !(flag.is_required || flag.is_positional || flag.name == INTERNAL_VARIADIC_FLAG) { + if keep_it_short && !(flag.is_required || flag.is_positional || flag.name == INTERNAL_OVERFLOW_FLAG) { continue } strings.write_byte(&builder, ' ') - if flag.name == INTERNAL_VARIADIC_FLAG { + if flag.name == INTERNAL_OVERFLOW_FLAG { strings.write_string(&builder, "...") continue } @@ -252,7 +252,7 @@ write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", sty strings.write_byte(&builder, '\t') - if flag.name == INTERNAL_VARIADIC_FLAG { + if flag.name == INTERNAL_OVERFLOW_FLAG { strings.write_string(&builder, flag.type_description) } else { strings.write_string(&builder, flag_prefix) diff --git a/core/flags/util.odin b/core/flags/util.odin index c182289be..ce7e2e36c 100644 --- a/core/flags/util.odin +++ b/core/flags/util.odin @@ -95,7 +95,7 @@ Example: import "core:flags" import "core:fmt" - subtag_example :: proc() { + get_subtag_example :: proc() { args_tag := "precision=3,signed" precision, has_precision := flags.get_subtag(args_tag, "precision") diff --git a/core/fmt/doc.odin b/core/fmt/doc.odin index d45e6c796..eeebd33f7 100644 --- a/core/fmt/doc.odin +++ b/core/fmt/doc.odin @@ -29,6 +29,8 @@ Integer: %x base 16, with lower-case letters for a-f %X base 16, with upper-case letters for A-F %U Unicode format: U+1234; same as "U+%04X" + %m number of bytes in the best unit of measurement, e.g. 123.45mib + %M number of bytes in the best unit of measurement, e.g. 123.45MiB Floating-point, complex numbers, and quaternions: %e scientific notation, e.g. -1.23456e+78 %E scientific notation, e.g. -1.23456E+78 @@ -38,8 +40,6 @@ Floating-point, complex numbers, and quaternions: %G synonym for %g %h hexadecimal (lower-case) representation with 0h prefix (0h01234abcd) %H hexadecimal (upper-case) representation with 0H prefix (0h01234ABCD) - %m number of bytes in the best unit of measurement, e.g. 123.45mib - %M number of bytes in the best unit of measurement, e.g. 123.45MiB String and slice of bytes %s the uninterpreted bytes of the string or slice %q a double-quoted string safely escaped with Odin syntax diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index b7b42ffa4..9c245de94 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -116,11 +116,12 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist } // Creates a formatted string // -// *Allocates Using Context's Allocator* +// *Allocates Using Provided Allocator* // // Inputs: // - args: A variadic list of arguments to be formatted. // - sep: An optional separator string (default is a single space). +// - allocator: (default: context.allocator) // // Returns: A formatted string. // @@ -132,11 +133,12 @@ aprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> strin } // Creates a formatted string with a newline character at the end // -// *Allocates Using Context's Allocator* +// *Allocates Using Provided Allocator* // // Inputs: // - args: A variadic list of arguments to be formatted. // - sep: An optional separator string (default is a single space). +// - allocator: (default: context.allocator) // // Returns: A formatted string with a newline character at the end. // @@ -148,11 +150,12 @@ aprintln :: proc(args: ..any, sep := " ", allocator := context.allocator) -> str } // Creates a formatted string using a format string and arguments // -// *Allocates Using Context's Allocator* +// *Allocates Using Provided Allocator* // // Inputs: // - fmt: A format string with placeholders for the provided arguments. // - args: A variadic list of arguments to be formatted. +// - allocator: (default: context.allocator) // - newline: Whether the string should end with a newline. (See `aprintfln`.) // // Returns: A formatted string. The returned string must be freed accordingly. @@ -165,11 +168,12 @@ aprintf :: proc(fmt: string, args: ..any, allocator := context.allocator, newlin } // Creates a formatted string using a format string and arguments, followed by a newline. // -// *Allocates Using Context's Allocator* +// *Allocates Using Provided Allocator* // // Inputs: // - fmt: A format string with placeholders for the provided arguments. // - args: A variadic list of arguments to be formatted. +// - allocator: (default: context.allocator) // // Returns: A formatted string. The returned string must be freed accordingly. // @@ -359,11 +363,12 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! { // Creates a formatted C string // -// *Allocates Using Context's Allocator* +// *Allocates Using Provided Allocator* // // Inputs: // - args: A variadic list of arguments to be formatted. // - sep: An optional separator string (default is a single space). +// - allocator: (default: context.allocator) // // Returns: A formatted C string. // @@ -379,11 +384,12 @@ caprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> cstr // Creates a formatted C string // -// *Allocates Using Context's Allocator* +// *Allocates Using Provided Allocator* // // Inputs: // - format: A format string with placeholders for the provided arguments // - args: A variadic list of arguments to be formatted +// - allocator: (default: context.allocator) // - newline: Whether the string should end with a newline. (See `caprintfln`.) // // Returns: A formatted C string @@ -399,11 +405,12 @@ caprintf :: proc(format: string, args: ..any, allocator := context.allocator, ne } // Creates a formatted C string, followed by a newline. // -// *Allocates Using Context's Allocator* +// *Allocates Using Provided Allocator* // // Inputs: // - format: A format string with placeholders for the provided arguments // - args: A variadic list of arguments to be formatted +// - allocator: (default: context.allocator) // // Returns: A formatted C string // @@ -1115,7 +1122,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d flags: strconv.Int_Flags if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} } if fi.plus { flags += {.Plus} } - s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags) + s := strconv.write_bits(buf[start:], u, base, is_signed, bit_size, digits, flags) prev_zero := fi.zero defer fi.zero = prev_zero fi.zero = false @@ -1200,7 +1207,7 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i flags: strconv.Int_Flags if fi.hash && !fi.zero && start == 0 { flags += {.Prefix} } if fi.plus { flags += {.Plus} } - s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags) + s := strconv.write_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags) if fi.hash && fi.zero && fi.indent == 0 { c: byte = 0 @@ -1265,7 +1272,7 @@ _fmt_memory :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, units: st } buf: [256]byte - str := strconv.append_float(buf[:], amt, 'f', prec, 64) + str := strconv.write_float(buf[:], amt, 'f', prec, 64) // Add the unit at the end. copy(buf[len(str):], units[off:off+unit_len]) @@ -1417,7 +1424,7 @@ _fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: b buf: [386]byte // Can return "NaN", "+Inf", "-Inf", "+", "-". - str := strconv.append_float(buf[:], v, float_fmt, prec, bit_size) + str := strconv.write_float(buf[:], v, float_fmt, prec, bit_size) if !fi.plus { // Strip sign from "+" but not "+Inf". @@ -1442,9 +1449,12 @@ fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) { _fmt_float_as(fi, v, bit_size, verb, 'g', -1) case 'f', 'F': _fmt_float_as(fi, v, bit_size, verb, 'f', 3) - case 'e', 'E': + case 'e': // BUG(): "%.3e" returns "3.000e+00" _fmt_float_as(fi, v, bit_size, verb, 'e', 6) + case 'E': + // BUG(): "%.3E" returns "3.000E+00" + _fmt_float_as(fi, v, bit_size, verb, 'E', 6) case 'h', 'H': prev_fi := fi^ @@ -1541,6 +1551,79 @@ fmt_string :: proc(fi: ^Info, s: string, verb: rune) { fmt_cstring :: proc(fi: ^Info, s: cstring, verb: rune) { fmt_string(fi, string(s), verb) } + +// Formats a string UTF-16 with a specific format. +// +// Inputs: +// - fi: Pointer to the Info struct containing format settings. +// - s: The string to format. +// - verb: The format specifier character (e.g. 's', 'v', 'q', 'x', 'X'). +// +fmt_string16 :: proc(fi: ^Info, s: string16, verb: rune) { + s, verb := s, verb + if ol, ok := fi.optional_len.?; ok { + s = s[:clamp(ol, 0, len(s))] + } + if !fi.in_bad && fi.record_level > 0 && verb == 'v' { + verb = 'q' + } + + switch verb { + case 's', 'v': + if fi.width_set { + if fi.width > len(s) { + if fi.minus { + io.write_string16(fi.writer, s, &fi.n) + } + + for _ in 0.. 0 && space { + io.write_byte(fi.writer, ' ', &fi.n) + } + char_set := __DIGITS_UPPER + if verb == 'x' { + char_set = __DIGITS_LOWER + } + _fmt_int(fi, u64(s[i]), 16, false, bit_size=16, digits=char_set) + } + + case: + fmt_bad_verb(fi, verb) + } +} +// Formats a C-style UTF-16 string with a specific format. +// +// Inputs: +// - fi: Pointer to the Info struct containing format settings. +// - s: The C-style string to format. +// - verb: The format specifier character (Ref fmt_string). +// +fmt_cstring16 :: proc(fi: ^Info, s: cstring16, verb: rune) { + fmt_string16(fi, string16(s), verb) +} + // Formats a raw pointer with a specific format. // // Inputs: @@ -1795,11 +1878,8 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') { e, is_enum := et.variant.(runtime.Type_Info_Enum) commas := 0 - loop: for i in 0 ..< bit_size { - if bits & (1< 0 { io.write_string(fi.writer, ", ", &fi.n) } @@ -1822,8 +1902,7 @@ fmt_bit_set :: proc(fi: ^Info, v: any, name: string = "", verb: rune = 'v') { } } } - v := i64(i) + info.lower - io.write_i64(fi.writer, v, 10, &fi.n) + io.write_i64(fi.writer, i, 10, &fi.n) commas += 1 } } @@ -2267,14 +2346,14 @@ fmt_array :: proc(fi: ^Info, data: rawptr, n: int, elem_size: int, elem: ^reflec } switch reflect.type_info_base(elem).id { - case byte: fmt_string(fi, string(([^]byte)(data)[:n]), verb); return - case u16: print_utf16(fi, ([^]u16)(data)[:n]); return - case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return - case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return - case u32: print_utf32(fi, ([^]u32)(data)[:n]); return - case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return - case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return - case rune: print_utf32(fi, ([^]rune)(data)[:n]); return + case byte: fmt_string(fi, string (([^]byte)(data)[:n]), verb); return + case u16: fmt_string16(fi, string16(([^]u16) (data)[:n]), verb); return + case u16le: print_utf16(fi, ([^]u16le)(data)[:n]); return + case u16be: print_utf16(fi, ([^]u16be)(data)[:n]); return + case u32: print_utf32(fi, ([^]u32)(data)[:n]); return + case u32le: print_utf32(fi, ([^]u32le)(data)[:n]); return + case u32be: print_utf32(fi, ([^]u32be)(data)[:n]); return + case rune: print_utf32(fi, ([^]rune)(data)[:n]); return } } if verb == 'p' { @@ -3204,6 +3283,9 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { case string: fmt_string(fi, a, verb) case cstring: fmt_cstring(fi, a, verb) + case string16: fmt_string16(fi, a, verb) + case cstring16: fmt_cstring16(fi, a, verb) + case typeid: reflect.write_typeid(fi.writer, a, &fi.n) case i16le: fmt_int(fi, u64(a), true, 16, verb) diff --git a/core/hash/crc32.odin b/core/hash/crc32.odin index a7f68207e..0a4617f6d 100644 --- a/core/hash/crc32.odin +++ b/core/hash/crc32.odin @@ -317,85 +317,4 @@ crc32_table := [8][256]u32{ 0xff6b144a, 0x33c114d4, 0xbd4e1337, 0x71e413a9, 0x7b211ab0, 0xb78b1a2e, 0x39041dcd, 0xf5ae1d53, 0x2c8e0fff, 0xe0240f61, 0x6eab0882, 0xa201081c, 0xa8c40105, 0x646e019b, 0xeae10678, 0x264b06e6, }, -} - - - -/* -@(optimization_mode="speed") -crc32 :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 { - result := ~u32(seed); - #no_bounds_check for b in data { - result = result>>8 ~ _crc32_table[(result ~ u32(b)) & 0xff]; - } - return ~result; -} - - -@private _crc32_table := [256]u32{ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -}; -*/ +} \ No newline at end of file diff --git a/core/hash/hash.odin b/core/hash/hash.odin index 45f524d8a..6c048c05b 100644 --- a/core/hash/hash.odin +++ b/core/hash/hash.odin @@ -127,7 +127,7 @@ jenkins :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 { } @(optimization_mode="favor_size") -murmur32 :: proc "contextless" (data: []byte, seed := u32(0)) -> u32 { +murmur32 :: proc "contextless" (data: []byte, seed := u32(0x9747b28c)) -> u32 { c1_32: u32 : 0xcc9e2d51 c2_32: u32 : 0x1b873593 diff --git a/core/hash/xxhash/common.odin b/core/hash/xxhash/common.odin index adfc1bac2..636393b52 100644 --- a/core/hash/xxhash/common.odin +++ b/core/hash/xxhash/common.odin @@ -101,3 +101,35 @@ XXH64_read64 :: #force_inline proc(buf: []u8, alignment := Alignment.Unaligned) return u64(b) } } + +XXH64_read64_simd :: #force_inline proc(buf: []$E, $W: uint, alignment := Alignment.Unaligned) -> (res: #simd[W]u64) { + if alignment == .Aligned { + res = (^#simd[W]u64)(raw_data(buf))^ + } else { + res = intrinsics.unaligned_load((^#simd[W]u64)(raw_data(buf))) + } + + when ODIN_ENDIAN == .Big { + bytes := transmute(#simd[W*8]u8)res + bytes = intrinsics.simd_lanes_reverse(bytes) + res = transmute(#simd[W]u64)bytes + res = intrinsics.simd_lanes_reverse(res) + } + return +} + +XXH64_write64_simd :: #force_inline proc(buf: []$E, value: $V/#simd[$W]u64, alignment := Alignment.Unaligned) { + value := value + when ODIN_ENDIAN == .Big { + bytes := transmute(#simd[W*8]u8)value + bytes = intrinsics.simd_lanes_reverse(bytes) + value = transmute(#simd[W]u64)bytes + value = intrinsics.simd_lanes_reverse(value) + } + + if alignment == .Aligned { + (^V)(raw_data(buf))^ = value + } else { + intrinsics.unaligned_store((^V)(raw_data(buf)), value) + } +} diff --git a/core/hash/xxhash/xxhash_3.odin b/core/hash/xxhash/xxhash_3.odin index 293e98528..fe92f16d9 100644 --- a/core/hash/xxhash/xxhash_3.odin +++ b/core/hash/xxhash/xxhash_3.odin @@ -52,6 +52,7 @@ XXH3_SECRET_SIZE_MIN :: 136 #assert(len(XXH3_kSecret) == 192 && len(XXH3_kSecret) > XXH3_SECRET_SIZE_MIN) XXH_ACC_ALIGN :: 8 /* scalar */ +XXH_MAX_WIDTH :: #config(XXH_MAX_WIDTH, 512) / 64 /* This is the optimal update size for incremental hashing. @@ -62,10 +63,11 @@ XXH3_INTERNAL_BUFFER_SIZE :: 256 Streaming state. IMPORTANT: This structure has a strict alignment requirement of 64 bytes!! ** - Do not allocate this with `make()` or `new`, it will not be sufficiently aligned. - Use`XXH3_create_state` and `XXH3_destroy_state, or stack allocation. + Default allocators will align it correctly if created via `new`, as will + placing this struct on the stack, but if using a custom allocator make sure + that it handles the alignment correctly! */ -XXH3_state :: struct { +XXH3_state :: struct #align(64) { acc: [8]u64, custom_secret: [XXH_SECRET_DEFAULT_SIZE]u8, buffer: [XXH3_INTERNAL_BUFFER_SIZE]u8, @@ -380,7 +382,6 @@ XXH3_INIT_ACC :: [XXH_ACC_NB]xxh_u64{ XXH_SECRET_MERGEACCS_START :: 11 -@(optimization_mode="favor_size") XXH3_hashLong_128b_internal :: #force_inline proc( input: []u8, secret: []u8, @@ -408,7 +409,6 @@ XXH3_hashLong_128b_internal :: #force_inline proc( /* * It's important for performance that XXH3_hashLong is not inlined. */ -@(optimization_mode="favor_size") XXH3_hashLong_128b_default :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) { return XXH3_hashLong_128b_internal(input, XXH3_kSecret[:], XXH3_accumulate_512, XXH3_scramble_accumulator) } @@ -416,12 +416,10 @@ XXH3_hashLong_128b_default :: #force_no_inline proc(input: []u8, seed: xxh_u64, /* * It's important for performance that XXH3_hashLong is not inlined. */ -@(optimization_mode="favor_size") XXH3_hashLong_128b_withSecret :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) { return XXH3_hashLong_128b_internal(input, secret, XXH3_accumulate_512, XXH3_scramble_accumulator) } -@(optimization_mode="favor_size") XXH3_hashLong_128b_withSeed_internal :: #force_inline proc( input: []u8, seed: xxh_u64, secret: []u8, f_acc512: XXH3_accumulate_512_f, @@ -442,7 +440,6 @@ XXH3_hashLong_128b_withSeed_internal :: #force_inline proc( /* * It's important for performance that XXH3_hashLong is not inlined. */ - @(optimization_mode="favor_size") XXH3_hashLong_128b_withSeed :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: XXH3_128_hash) { return XXH3_hashLong_128b_withSeed_internal(input, seed, secret, XXH3_accumulate_512, XXH3_scramble_accumulator , XXH3_init_custom_secret) } @@ -477,7 +474,7 @@ XXH3_128bits_internal :: #force_inline proc( /* === Public XXH128 API === */ @(optimization_mode="favor_size") XXH3_128_default :: proc(input: []u8) -> (hash: XXH3_128_hash) { - return XXH3_128bits_internal(input, 0, XXH3_kSecret[:], XXH3_hashLong_128b_withSeed) + return XXH3_128bits_internal(input, 0, XXH3_kSecret[:], XXH3_hashLong_128b_default) } @(optimization_mode="favor_size") @@ -733,10 +730,6 @@ XXH3_accumulate_512_f :: #type proc(acc: []xxh_u64, input: []u8, secret: XXH3_scramble_accumulator_f :: #type proc(acc: []xxh_u64, secret: []u8) XXH3_init_custom_secret_f :: #type proc(custom_secret: []u8, seed64: xxh_u64) -XXH3_accumulate_512 : XXH3_accumulate_512_f = XXH3_accumulate_512_scalar -XXH3_scramble_accumulator : XXH3_scramble_accumulator_f = XXH3_scramble_accumulator_scalar -XXH3_init_custom_secret : XXH3_init_custom_secret_f = XXH3_init_custom_secret_scalar - /* scalar variants - universal */ @(optimization_mode="favor_size") XXH3_accumulate_512_scalar :: #force_inline proc(acc: []xxh_u64, input: []u8, secret: []u8) { @@ -751,7 +744,7 @@ XXH3_accumulate_512_scalar :: #force_inline proc(acc: []xxh_u64, input: []u8, se sec := XXH64_read64(xsecret[8 * i:]) data_key := data_val ~ sec xacc[i ~ 1] += data_val /* swap adjacent lanes */ - xacc[i ] += u64(u128(u32(data_key)) * u128(u64(data_key >> 32))) + xacc[i ] += u64(u32(data_key)) * u64(data_key >> 32) } } @@ -785,6 +778,87 @@ XXH3_init_custom_secret_scalar :: #force_inline proc(custom_secret: []u8, seed64 } } +/* generalized SIMD variants */ +XXH3_accumulate_512_simd_generic :: #force_inline proc(acc: []xxh_u64, input: []u8, secret: []u8, $W: uint) { + u32xW :: #simd[W]u32 + u64xW :: #simd[W]u64 + + #no_bounds_check for i in uint(0).. 1 { + XXH3_accumulate_512_simd_generic(acc, input, secret, XXH_NATIVE_WIDTH) + } else { + XXH3_accumulate_512_scalar(acc, input, secret) + } +} + +XXH3_scramble_accumulator :: #force_inline proc(acc: []xxh_u64, secret: []u8) { + when XXH_NATIVE_WIDTH > 1 { + XXH3_scramble_accumulator_simd_generic(acc, secret, XXH_NATIVE_WIDTH) + } else { + XXH3_scramble_accumulator_scalar(acc, secret) + } +} + +XXH3_init_custom_secret :: #force_inline proc(custom_secret: []u8, seed64: xxh_u64) { + when XXH_NATIVE_WIDTH > 1 { + XXH3_init_custom_secret_simd_generic(custom_secret, seed64, XXH_NATIVE_WIDTH) + } else { + XXH3_init_custom_secret_scalar(custom_secret, seed64) + } +} + XXH_PREFETCH_DIST :: 320 /* @@ -796,7 +870,7 @@ XXH_PREFETCH_DIST :: 320 XXH3_accumulate :: #force_inline proc( acc: []xxh_u64, input: []u8, secret: []u8, nbStripes: uint, f_acc512: XXH3_accumulate_512_f) { - for n := uint(0); n < nbStripes; n += 1 { + #no_bounds_check for n := uint(0); n < nbStripes; n += 1 { when !XXH_DISABLE_PREFETCH { in_ptr := &input[n * XXH_STRIPE_LEN] prefetch(in_ptr, XXH_PREFETCH_DIST) @@ -869,7 +943,6 @@ XXH3_hashLong_64b_internal :: #force_inline proc(input: []u8, secret: []u8, /* It's important for performance that XXH3_hashLong is not inlined. */ -@(optimization_mode="favor_size") XXH3_hashLong_64b_withSecret :: #force_no_inline proc(input: []u8, seed64: xxh_u64, secret: []u8) -> (hash: xxh_u64) { return XXH3_hashLong_64b_internal(input, secret, XXH3_accumulate_512, XXH3_scramble_accumulator) } @@ -881,24 +954,11 @@ XXH3_hashLong_64b_withSecret :: #force_no_inline proc(input: []u8, seed64: xxh_u This variant enforces that the compiler can detect that, and uses this opportunity to streamline the generated code for better performance. */ -@(optimization_mode="favor_size") XXH3_hashLong_64b_default :: #force_no_inline proc(input: []u8, seed64: xxh_u64, secret: []u8) -> (hash: xxh_u64) { return XXH3_hashLong_64b_internal(input, XXH3_kSecret[:], XXH3_accumulate_512, XXH3_scramble_accumulator) } -/* - XXH3_hashLong_64b_withSeed(): - Generate a custom key based on alteration of default XXH3_kSecret with the seed, - and then use this key for long mode hashing. - - This operation is decently fast but nonetheless costs a little bit of time. - Try to avoid it whenever possible (typically when seed==0). - - It's important for performance that XXH3_hashLong is not inlined. Not sure - why (uop cache maybe?), but the difference is large and easily measurable. -*/ -@(optimization_mode="favor_size") -XXH3_hashLong_64b_withSeed_internal :: #force_no_inline proc( +XXH3_hashLong_64b_withSeed_internal :: #force_inline proc( input: []u8, seed: xxh_u64, f_acc512: XXH3_accumulate_512_f, @@ -915,9 +975,16 @@ XXH3_hashLong_64b_withSeed_internal :: #force_no_inline proc( } /* - It's important for performance that XXH3_hashLong is not inlined. + XXH3_hashLong_64b_withSeed(): + Generate a custom key based on alteration of default XXH3_kSecret with the seed, + and then use this key for long mode hashing. + + This operation is decently fast but nonetheless costs a little bit of time. + Try to avoid it whenever possible (typically when seed==0). + + It's important for performance that XXH3_hashLong is not inlined. Not sure + why (uop cache maybe?), but the difference is large and easily measurable. */ -@(optimization_mode="favor_size") XXH3_hashLong_64b_withSeed :: #force_no_inline proc(input: []u8, seed: xxh_u64, secret: []u8) -> (hash: xxh_u64) { return XXH3_hashLong_64b_withSeed_internal(input, seed, XXH3_accumulate_512, XXH3_scramble_accumulator, XXH3_init_custom_secret) } @@ -926,7 +993,7 @@ XXH3_hashLong_64b_withSeed :: #force_no_inline proc(input: []u8, seed: xxh_u64, XXH3_hashLong64_f :: #type proc(input: []u8, seed: xxh_u64, secret: []u8) -> (res: xxh_u64) @(optimization_mode="favor_size") -XXH3_64bits_internal :: proc(input: []u8, seed: xxh_u64, secret: []u8, f_hashLong: XXH3_hashLong64_f) -> (hash: xxh_u64) { +XXH3_64bits_internal :: #force_inline proc(input: []u8, seed: xxh_u64, secret: []u8, f_hashLong: XXH3_hashLong64_f) -> (hash: xxh_u64) { assert(len(secret) >= XXH3_SECRET_SIZE_MIN) /* If an action is to be taken if len(secret) condition is not respected, it should be done here. diff --git a/core/hash/xxhash/xxhash_3_intel.odin b/core/hash/xxhash/xxhash_3_intel.odin new file mode 100644 index 000000000..3397fcef5 --- /dev/null +++ b/core/hash/xxhash/xxhash_3_intel.odin @@ -0,0 +1,13 @@ +#+build amd64, i386 +package xxhash + +import "base:intrinsics" + +@(private="file") SSE2_FEATURES :: "sse2" +@(private="file") AVX2_FEATURES :: "avx2" +@(private="file") AVX512_FEATURES :: "avx512dq,evex512" + +XXH_NATIVE_WIDTH :: min(XXH_MAX_WIDTH, + 8 when intrinsics.has_target_feature(AVX512_FEATURES) else + 4 when intrinsics.has_target_feature(AVX2_FEATURES) else + 2 when intrinsics.has_target_feature(SSE2_FEATURES) else 1) diff --git a/core/hash/xxhash/xxhash_3_other.odin b/core/hash/xxhash/xxhash_3_other.odin new file mode 100644 index 000000000..e1a5d0474 --- /dev/null +++ b/core/hash/xxhash/xxhash_3_other.odin @@ -0,0 +1,8 @@ +#+build !amd64 +#+build !i386 +package xxhash + +import "base:runtime" + +XXH_NATIVE_WIDTH :: min(XXH_MAX_WIDTH, + 2 when runtime.HAS_HARDWARE_SIMD else 1) diff --git a/core/image/bmp/bmp.odin b/core/image/bmp/bmp.odin index 057c2ffa0..d5a094e83 100644 --- a/core/image/bmp/bmp.odin +++ b/core/image/bmp/bmp.odin @@ -741,6 +741,6 @@ destroy :: proc(img: ^Image) { } @(init, private) -_register :: proc() { +_register :: proc "contextless" () { image.register(.BMP, load_from_bytes, destroy) } diff --git a/core/image/common.odin b/core/image/common.odin index 690ebc045..4014e2ae6 100644 --- a/core/image/common.odin +++ b/core/image/common.odin @@ -64,8 +64,16 @@ Image_Metadata :: union #shared_nil { ^QOI_Info, ^TGA_Info, ^BMP_Info, + ^JPEG_Info, } +Exif :: struct { + byte_order: enum { + little_endian, + big_endian, + }, + data: []u8 `fmt:"-"`, +} /* @@ -112,8 +120,7 @@ Image_Option: `.alpha_drop_if_present` If the image has an alpha channel, drop it. - You may want to use `.alpha_ - tiply` in this case. + You may want to use `.alpha_premultiply` in this case. NOTE: For PNG, this also skips handling of the tRNS chunk, if present, unless you select `alpha_premultiply`. @@ -163,6 +170,7 @@ Error :: union #shared_nil { PNG_Error, QOI_Error, BMP_Error, + JPEG_Error, compress.Error, compress.General_Error, @@ -575,6 +583,140 @@ TGA_Info :: struct { extension: Maybe(TGA_Extension), } + +/* + JPEG-specific +*/ +JFIF_Magic := [?]byte{0x4A, 0x46, 0x49, 0x46} // "JFIF" +JFXX_Magic := [?]byte{0x4A, 0x46, 0x58, 0x58} // "JFXX" +Exif_Magic := [?]byte{0x45, 0x78, 0x69, 0x66} // "Exif" + +JPEG_Error :: enum { + None = 0, + Duplicate_SOI_Marker, + Invalid_JFXX_Extension_Code, + Encountered_SOS_Before_SOF, + Invalid_Quantization_Table_Precision, + Invalid_Quantization_Table_Index, + Invalid_Huffman_Coefficient_Type, + Invalid_Huffman_Table_Index, + Unsupported_Frame_Type, + Invalid_Frame_Bit_Depth_Combo, + Invalid_Sampling_Factor, + Unsupported_12_Bit_Depth, + Multiple_SOS_Markers, + Encountered_RST_Marker_Outside_ECS, + Extra_Data_After_SOS, // Image seemed to have decoded okay, but there's more data after SOS + Invalid_Thumbnail_Size, + Huffman_Symbols_Exceeds_Max, +} + +JFIF_Unit :: enum byte { + None = 0, + Dots_Per_Inch = 1, + Dots_Per_Centimeter = 2, +} + +JFIF_APP0 :: struct { + version: u16be, + x_density: u16be, + y_density: u16be, + units: JFIF_Unit, + x_thumbnail: u8, + y_thumbnail: u8, + greyscale_thumbnail: bool, + thumbnail: []RGB_Pixel `fmt:"-"`, +} + +JFXX_APP0 :: struct { + extension_code: JFXX_Extension_Code, + x_thumbnail: u8, + y_thumbnail: u8, + thumbnail: []byte `fmt:"-"`, +} + +JFXX_Extension_Code :: enum u8 { + Thumbnail_JPEG = 0x10, + Thumbnail_1_Byte_Palette = 0x11, + Thumbnail_3_Byte_RGB = 0x13, +} + +JPEG_Marker :: enum u8 { + SOF0 = 0xC0, // Baseline sequential DCT + SOF1 = 0xC1, // Extended sequential DCT + SOF2 = 0xC2, // Progressive DCT + SOF3 = 0xC3, // Lossless (sequential) + SOF5 = 0xC5, // Differential sequential DCT + SOF6 = 0xC6, // Differential progressive DCT + SOF7 = 0xC7, // Differential lossless (sequential) + SOF9 = 0xC9, // Extended sequential DCT, Arithmetic coding + SOF10 = 0xCA, // Progressive DCT, Arithmetic coding + SOF11 = 0xCB, // Lossless (sequential), Arithmetic coding + SOF13 = 0xCD, // Differential sequential DCT, Arithmetic coding + SOF14 = 0xCE, // Differential progressive DCT, Arithmetic coding + SOF15 = 0xCF, // Differential lossless (sequential), Arithmetic coding + + DHT = 0xC4, + JPG = 0xC8, + DAC = 0xCC, + RST0 = 0xD0, + RST1 = 0xD1, + RST2 = 0xD2, + RST3 = 0xD3, + RST4 = 0xD4, + RST5 = 0xD5, + RST6 = 0xD6, + RST7 = 0xD7, + SOI = 0xD8, + EOI = 0xD9, + SOS = 0xDA, + DQT = 0xDB, + DNL = 0xDC, + DRI = 0xDD, + DHP = 0xDE, + EXP = 0xDF, + APP0 = 0xE0, + APP1 = 0xE1, + APP2 = 0xE2, + APP3 = 0xE3, + APP4 = 0xE4, + APP5 = 0xE5, + APP6 = 0xE6, + APP7 = 0xE7, + APP8 = 0xE8, + APP9 = 0xE9, + APP10 = 0xEA, + APP11 = 0xEB, + APP12 = 0xEC, + APP13 = 0xED, + APP14 = 0xEE, + APP15 = 0xEF, + JPG0 = 0xF0, + JPG1 = 0xF1, + JPG2 = 0xF2, + JPG3 = 0xF3, + JPG4 = 0xF4, + JPG5 = 0xF5, + JPG6 = 0xF6, + JPG7 = 0xF7, + JPG8 = 0xF8, + JPG9 = 0xF9, + JPG10 = 0xFA, + JPG11 = 0xFB, + JPG12 = 0xFC, + JPG13 = 0xFD, + COM = 0xFE, + TEM = 0x01, +} + +JPEG_Info :: struct { + jfif_app0: Maybe(JFIF_APP0), + jfxx_app0: Maybe(JFXX_APP0), + comments: [dynamic]string, + exif: [dynamic]Exif, + frame_type: JPEG_Marker, +} + // Function to help with image buffer calculations compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) { size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height diff --git a/core/image/general.odin b/core/image/general.odin index e92b54f18..1662cf14e 100644 --- a/core/image/general.odin +++ b/core/image/general.odin @@ -10,13 +10,13 @@ Destroy_Proc :: #type proc(img: ^Image) _internal_loaders: [Which_File_Type]Loader_Proc _internal_destroyers: [Which_File_Type]Destroy_Proc -register :: proc(kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) { - assert(loader != nil) - assert(destroyer != nil) - assert(_internal_loaders[kind] == nil) +register :: proc "contextless" (kind: Which_File_Type, loader: Loader_Proc, destroyer: Destroy_Proc) { + assert_contextless(loader != nil) + assert_contextless(destroyer != nil) + assert_contextless(_internal_loaders[kind] == nil) _internal_loaders[kind] = loader - assert(_internal_destroyers[kind] == nil) + assert_contextless(_internal_destroyers[kind] == nil) _internal_destroyers[kind] = destroyer } @@ -147,7 +147,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type { return .JPEG case s[:3] == "\xff\xd8\xff": switch s[3] { - case 0xdb, 0xee, 0xe1, 0xe0: + case 0xdb, 0xee, 0xe1, 0xe0, 0xfe, 0xed: return .JPEG } switch { diff --git a/core/image/jpeg/jpeg.odin b/core/image/jpeg/jpeg.odin new file mode 100644 index 000000000..818bd13d5 --- /dev/null +++ b/core/image/jpeg/jpeg.odin @@ -0,0 +1,1106 @@ +package jpeg + +import "core:bytes" +import "core:compress" +import "core:math" +import "core:mem" +import "core:image" +import "core:slice" +import "core:strings" + +Image :: image.Image +Error :: image.Error +Options :: image.Options + +HUFFMAN_MAX_SYMBOLS :: 176 +HUFFMAN_MAX_BITS :: 16 +// 768 bytes of 24-bit RGB values. +THUMBNAIL_PALETTE_SIZE :: 768 +BLOCK_SIZE :: 8 +COEFFICIENT_COUNT :: BLOCK_SIZE * BLOCK_SIZE +SEGMENT_MAX_SIZE :: 65533 + +Coefficient :: enum u8 { + DC, + AC, +} + +Component :: enum u8 { + Y = 1, + Cb = 2, + Cr = 3, +} + +Huffman_Table :: struct { + symbols: [HUFFMAN_MAX_SYMBOLS]byte, + codes: [HUFFMAN_MAX_SYMBOLS]u32, + offsets: [HUFFMAN_MAX_BITS + 1]byte, +} + +Quantization_Table :: [COEFFICIENT_COUNT]u16be + +Color_Component :: struct { + dc_table_idx: u8, + ac_table_idx: u8, + quantization_table_idx: u8, + v_sampling_factor: int, + h_sampling_factor: int, +} + +// 8x8 block of pixels +Block :: [Component][COEFFICIENT_COUNT]i16 + +@(private="file") +zigzag := [?]byte{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, +} + +@(optimization_mode="favor_size", private="file") +refill_msb :: #force_inline proc(z: ^compress.Context_Memory_Input, width := i8(48)) { + refill := u64(width) + b := u64(0) + + if z.num_bits > refill { + return + } + + for { + if len(z.input_data) != 0 { + b = u64(z.input_data[0]) + + if len(z.input_data) > 1 && b == 0xFF { + next := u64(z.input_data[1]) + + if next == 0x00 { + // 0x00 is used as a stuffing to indicate that the 0xFF is part of the data and not + // the beginning of a marker + z.input_data = z.input_data[2:] + } else if next >= cast(u64)image.JPEG_Marker.RST0 && next <= cast(u64)image.JPEG_Marker.RST7 { + // Skip any RSTn markers if we encounter them + if len(z.input_data) > 2 { + b = u64(z.input_data[2]) + z.input_data = z.input_data[3:] + } else { + b = 0 + } + } + } else { + z.input_data = z.input_data[1:] + } + } else { + b = 0 + } + + z.code_buffer |= ((b << 56) >> u8(z.num_bits)) + z.num_bits += 8 + if z.num_bits > refill { + break + } + } +} + +@(optimization_mode="favor_size", private="file") +consume_bits_msb :: #force_inline proc(z: ^compress.Context_Memory_Input, width: u8) { + z.code_buffer <<= width + z.num_bits -= u64(width) +} + +@(private="file") +byte_align :: #force_inline proc(z: ^compress.Context_Memory_Input) { + skip := z.num_bits % 8 + consume_bits_msb(z, cast(u8)skip) +} + +@(optimization_mode="favor_size", private="file") +peek_bits_msb :: #force_inline proc(z: ^compress.Context_Memory_Input, width: u8) -> u32 { + if z.num_bits < u64(width) { + refill_msb(z) + } + return u32((z.code_buffer &~ (max(u64) >> width)) >> (64 - width)) +} + +@(optimization_mode="favor_size", private="file") +read_bits_msb :: #force_inline proc(z: ^compress.Context_Memory_Input, width: u8) -> u32 { + k := #force_inline peek_bits_msb(z, width) + #force_inline consume_bits_msb(z, width) + return k +} + +load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) { + ctx := &compress.Context_Memory_Input{ + input_data = data, + } + + img, err = load_from_context(ctx, options, allocator) + return img, err +} + +@(private="file") +get_symbol :: proc(ctx: ^$C, huffman_table: Huffman_Table) -> byte { + possible_code: u32 = 0 + + for i in 0.. (img: ^Image, err: Error) { + context.allocator = allocator + options := options + + // Precalculate IDCT scaling factors + m0 := 2.0 * math.cos_f32(1.0 / 16.0 * 2.0 * math.PI) + m1 := 2.0 * math.cos_f32(2.0 / 16.0 * 2.0 * math.PI) + m3 := 2.0 * math.cos_f32(2.0 / 16.0 * 2.0 * math.PI) + m5 := 2.0 * math.cos_f32(3.0 / 16.0 * 2.0 * math.PI) + m2 := m0 - m5 + m4 := m0 + m5 + + s0 := math.cos_f32(0.0 / 16.0 * math.PI) / math.sqrt_f32(8.0) + s1 := math.cos_f32(1.0 / 16.0 * math.PI) / 2.0 + s2 := math.cos_f32(2.0 / 16.0 * math.PI) / 2.0 + s3 := math.cos_f32(3.0 / 16.0 * math.PI) / 2.0 + s4 := math.cos_f32(4.0 / 16.0 * math.PI) / 2.0 + s5 := math.cos_f32(5.0 / 16.0 * math.PI) / 2.0 + s6 := math.cos_f32(6.0 / 16.0 * math.PI) / 2.0 + s7 := math.cos_f32(7.0 / 16.0 * math.PI) / 2.0 + + if .info in options { + options += {.return_metadata, .do_not_decompress_image} + options -= {.info} + } + + if .return_header in options && .return_metadata in options { + options -= {.return_header} + } + + if .do_not_expand_channels in options || .do_not_expand_grayscale in options { + return img, .Unsupported_Option + } + + first := compress.read_u8(ctx) or_return + soi := cast(image.JPEG_Marker)compress.read_u8(ctx) or_return + if first != 0xFF && soi != .SOI { + return img, .Invalid_Signature + } + + img = new(Image) or_return + img.which = .JPEG + + expect_EOI := false + zero_based_components := false + huffman: [Coefficient][4]Huffman_Table + quantization: [4]Quantization_Table + color_components: [Component]Color_Component + restart_interval: int + // Image width and height in MCUs + mcu_width: int + mcu_height: int + // Image width and height in blocks + block_width: int + block_height: int + blocks: []Block + defer delete(blocks) + + loop: for { + // Loop until we find 0xFF. + first = compress.read_u8(ctx) or_return + (first == 0xFF) or_continue + + marker := cast(image.JPEG_Marker)compress.read_u8(ctx) or_return + if expect_EOI && marker != .EOI { + return img, .Extra_Data_After_SOS + } + #partial switch marker { + case cast(image.JPEG_Marker)0xFF: + // If we encounter multiple FF bytes then just skip them + continue + case .SOI: + return img, .Duplicate_SOI_Marker + case .APP0: + ident := make([dynamic]byte, 0, 16, context.temp_allocator) or_return + length := cast(int)((compress.read_data(ctx, u16be) or_return) - 2) + for { + b := compress.read_u8(ctx) or_return + if b == 0x00 { + break + } + append(&ident, b) or_return + } + if slice.equal(ident[:], image.JFIF_Magic[:]) { + if length != 14 { + // Malformed APP0. Skip it + compress.read_slice(ctx, length - len(ident) - 1) or_return + continue + } + + version := compress.read_data(ctx, u16be) or_return + units := cast(image.JFIF_Unit)(compress.read_u8(ctx) or_return) + x_density := compress.read_data(ctx, u16be) or_return + y_density := compress.read_data(ctx, u16be) or_return + x_thumbnail := cast(int)compress.read_u8(ctx) or_return + y_thumbnail := cast(int)compress.read_u8(ctx) or_return + thumbnail: []image.RGB_Pixel + + if x_thumbnail * y_thumbnail != 0 { + greyscale_thumbnail := false + thumbnail_size := x_thumbnail * y_thumbnail * 3 + // According to the JFIF spec, the thumbnail should always be made of RGB pixels. + // But some jpegs encode single-channel thumbnails. + if thumbnail_size != length - 14 && thumbnail_size / 3 == length - 14 { + thumbnail_size = x_thumbnail * y_thumbnail + greyscale_thumbnail = true + } else { + return img, .Invalid_Thumbnail_Size + } + thumb_pixels := slice.reinterpret([]image.RGB_Pixel, compress.read_slice_from_memory(ctx, x_thumbnail * y_thumbnail) or_return) + + if .return_metadata in options { + thumbnail = make([]image.RGB_Pixel, x_thumbnail * y_thumbnail) or_return + copy(thumbnail, thumb_pixels) + + info: ^image.JPEG_Info + if img.metadata == nil { + info = new(image.JPEG_Info) or_return + } else { + info = img.metadata.(^image.JPEG_Info) + } + info.jfif_app0 = image.JFIF_APP0{ + version, + x_density, + y_density, + units, + cast(u8)x_thumbnail, + cast(u8)y_thumbnail, + greyscale_thumbnail, + thumbnail, + } + img.metadata = info + } + } + } else if slice.equal(ident[:], image.JFXX_Magic[:]) { + extension_code := cast(image.JFXX_Extension_Code)compress.read_u8(ctx) or_return + thumbnail: []byte + + switch extension_code { + // We return the JPEG-compressed bytes for this type of thumbnail. + // It's up to the user if they want to decode it by checking the extension code + // and calling image.load() on the thumbnail. + // Not sure where to document that though, maybe it's better if the thumbnail is always raw pixel data. + case .Thumbnail_JPEG: + // +1 for the NUL byte + thumbnail_len := length - (size_of(image.JFXX_Magic) + 1 + size_of(image.JFXX_Extension_Code)) + thumbnail_jpeg := compress.read_slice(ctx, thumbnail_len) or_return + + if .return_metadata in options { + thumbnail = make([]byte, thumbnail_len) or_return + copy(thumbnail, thumbnail_jpeg) + + info: ^image.JPEG_Info + if img.metadata == nil { + info = new(image.JPEG_Info) or_return + } else { + info = img.metadata.(^image.JPEG_Info) + } + info.jfxx_app0 = image.JFXX_APP0{ + extension_code, + 0, + 0, + thumbnail, + } + img.metadata = info + } + case .Thumbnail_3_Byte_RGB: + x_thumbnail := cast(int)compress.read_u8(ctx) or_return + y_thumbnail := cast(int)compress.read_u8(ctx) or_return + pixels := compress.read_slice(ctx, x_thumbnail * y_thumbnail * 3) or_return + + if .return_metadata in options { + thumbnail = make([]byte, x_thumbnail * y_thumbnail * 3) or_return + copy(thumbnail, pixels) + + info: ^image.JPEG_Info + if img.metadata == nil { + info = new(image.JPEG_Info) or_return + } else { + info = img.metadata.(^image.JPEG_Info) + } + info.jfxx_app0 = image.JFXX_APP0{ + extension_code, + cast(u8)x_thumbnail, + cast(u8)y_thumbnail, + thumbnail, + } + img.metadata = info + } + case .Thumbnail_1_Byte_Palette: // NOTE(illusionman1212): NOT TESTED. Couldn't find a jpeg to test this with. + x_thumbnail := cast(int)compress.read_u8(ctx) or_return + y_thumbnail := cast(int)compress.read_u8(ctx) or_return + palette := slice.reinterpret([]image.RGB_Pixel, compress.read_slice(ctx, THUMBNAIL_PALETTE_SIZE / 3) or_return) + old_pixels := compress.read_slice(ctx, x_thumbnail * y_thumbnail) or_return + + if .return_metadata in options { + pixels := make([]byte, x_thumbnail * y_thumbnail * 3) or_return + for i in 0.. 0 && len(info.exif[len(info.exif) - 1].data) == SEGMENT_MAX_SIZE - len(ident) - 2 { + exif.byte_order = info.exif[len(info.exif) - 1].byte_order + } else { + compress.read_slice(ctx, length - len(ident) - 2) or_return + continue + } + } + + // - 2 for the NUL byte and padding byte + data := compress.read_slice(ctx, length - len(ident) - 2) or_return + exif.data = make([]byte, len(data)) or_return + copy(exif.data, data) + + append(&info.exif, exif) or_return + img.metadata = info + } else { + // - 1 for the NUL byte + compress.read_slice(ctx, length - len(ident) - 1) or_return + continue + } + case .COM: + length := (compress.read_data(ctx, u16be) or_return) - 2 + comment := string(compress.read_slice(ctx, cast(int)length) or_return) + if .return_metadata in options { + if info, ok := img.metadata.(^image.JPEG_Info); ok { + append(&info.comments, strings.clone(comment)) or_return + } + } + case .DQT: + length := cast(int)(compress.read_data(ctx, u16be) or_return) - 2 + + for length > 0 { + precision_and_index := compress.read_u8(ctx) or_return + precision := precision_and_index >> 4 + index := precision_and_index & 0xF + + if precision != 0 && precision != 1 { + return img, .Invalid_Quantization_Table_Precision + } + + if index < 0 || index > 3 { + return img, .Invalid_Quantization_Table_Index + } + + // When precision is 0, we read 64 u8s. + // when it's 1, we read 64 u16s. + table_bytes := 64 + if precision == 1 { + table_bytes = 128 + table := compress.read_slice(ctx, table_bytes) or_return + for v, i in slice.reinterpret([]u16be, table) { + quantization[index][i] = v + } + } else { + table := compress.read_slice(ctx, table_bytes) or_return + for v, i in table { + quantization[index][i] = cast(u16be)v + } + } + + length -= table_bytes + 1 + } + case .DHT: + length := (compress.read_data(ctx, u16be) or_return) - 2 + + for length > 0 { + type_index := compress.read_u8(ctx) or_return + type := cast(Coefficient)((type_index >> 4) & 0xF) + index := type_index & 0xF + + if type != .DC && type != .AC { + return img, .Invalid_Huffman_Coefficient_Type + } + + if index < 0 || index > 3 { + return img, .Invalid_Huffman_Table_Index + } + + lengths := compress.read_slice(ctx, HUFFMAN_MAX_BITS) or_return + num_symbols: u8 = 0 + for length, i in lengths { + num_symbols += length + huffman[type][index].offsets[i + 1] = num_symbols + } + + if num_symbols > HUFFMAN_MAX_SYMBOLS { + return img, .Huffman_Symbols_Exceeds_Max + } + + symbols := compress.read_slice(ctx, cast(int)num_symbols) or_return + copy(huffman[type][index].symbols[:], symbols) + + length -= cast(u16be)(1 + HUFFMAN_MAX_BITS + num_symbols) + + code: u32 = 0 + for i in 0.. image.MAX_DIMENSIONS { + return img, .Image_Dimensions_Too_Large + } + + // TODO: Some JPEGs use CMYK as the color model which means there will be 4 components + if components != 1 && components != 3 { + return img, .Invalid_Number_Of_Channels + } + + if img.metadata != nil { + info := img.metadata.(^image.JPEG_Info) + info.frame_type = marker + } + + mcu_width = (img.width + 7) / BLOCK_SIZE + mcu_height = (img.height + 7) / BLOCK_SIZE + block_width = mcu_width + block_height = mcu_height + + for _ in 0.. .Cr { + return img, .Image_Does_Not_Adhere_to_Spec + } + + h_v_factors := compress.read_u8(ctx) or_return + horizontal_sampling := h_v_factors >> 4 + vertical_sampling := h_v_factors & 0xF + + // TODO: spec says the range for the sampling factors is 1-4 + // We only support 1,2 for now. + if horizontal_sampling < 1 || horizontal_sampling > 2 { + return img, .Invalid_Sampling_Factor + } + if vertical_sampling < 1 || vertical_sampling > 2 { + return img, .Invalid_Sampling_Factor + } + + if id == .Y { + if horizontal_sampling == 2 && mcu_width % 2 == 1 { + block_width += 1 + } + if vertical_sampling == 2 && mcu_height % 2 == 1 { + block_height += 1 + } + } else { + if horizontal_sampling != 1 && vertical_sampling != 1 { + return img, .Invalid_Sampling_Factor + } + } + + quantization_table_idx := compress.read_u8(ctx) or_return + + if quantization_table_idx < 0 || quantization_table_idx > 3 { + return img, .Invalid_Quantization_Table_Index + } + + color_components[id].quantization_table_idx = quantization_table_idx + color_components[id].v_sampling_factor = cast(int)vertical_sampling + color_components[id].h_sampling_factor = cast(int)horizontal_sampling + } + case .SOF2: // Progressive DCT + fallthrough + case .SOF3: // Lossless (sequential) + fallthrough + case .SOF5: // Differential sequential DCT + fallthrough + case .SOF6: // Differential progressive DCT + fallthrough + case .SOF7: // Differential lossless (sequential) + fallthrough + case .SOF9: // Extended sequential DCT, Arithmetic coding + fallthrough + case .SOF10: // Progressive DCT, Arithmetic coding + fallthrough + case .SOF11: // Lossless (sequential), Arithmetic coding + fallthrough + case .SOF13: // Differential sequential DCT, Arithmetic coding + fallthrough + case .SOF14: // Differential progressive DCT, Arithmetic coding + fallthrough + case .SOF15: // Differential lossless (sequential), Arithmetic coding + if img.metadata != nil { + info := img.metadata.(^image.JPEG_Info) + info.frame_type = marker + } + return img, .Unsupported_Frame_Type + case .SOS: + if img.channels == 0 && img.depth == 0 && img.width == 0 && img.height == 0 { + return img, .Encountered_SOS_Before_SOF + } + + if .do_not_decompress_image in options { + return img, nil + } + + // Length + compress.read_data(ctx, u16be) or_return + num_components := compress.read_u8(ctx) or_return + if num_components != 1 && num_components != 3 { + return img, .Invalid_Number_Of_Channels + } + + for _ in 0.. .Cr { + return img, .Image_Does_Not_Adhere_to_Spec + } + + // high 4 is DC, low 4 is AC + coefficient_indices := compress.read_u8(ctx) or_return + dc_table_idx := coefficient_indices >> 4 + ac_table_idx := coefficient_indices & 0xF + + if (dc_table_idx < 0 || dc_table_idx > 3) || (ac_table_idx < 0 || ac_table_idx > 3) { + return img, .Invalid_Huffman_Table_Index + } + + color_components[component_id].dc_table_idx = dc_table_idx + color_components[component_id].ac_table_idx = ac_table_idx + } + // TODO: These aren't used for sequential DCT, only progressive and lossless. + Ss := compress.read_u8(ctx) or_return + _ = Ss + Se := compress.read_u8(ctx) or_return + _ = Se + Ah_Al := compress.read_u8(ctx) or_return + _ = Ah_Al + + blocks = make([]Block, block_height * block_width) or_return + + previous_dc: [Component]i16 + + luma_v_sampling_factor := color_components[.Y].v_sampling_factor + luma_h_sampling_factor := color_components[.Y].h_sampling_factor + + restart_interval *= luma_v_sampling_factor * luma_h_sampling_factor + #no_bounds_check for y := 0; y < mcu_height; y += luma_v_sampling_factor { + for x := 0; x < mcu_width; x += luma_h_sampling_factor { + blk := y * block_width + x + + if restart_interval != 0 && blk % restart_interval == 0 { + previous_dc[.Y] = 0 + previous_dc[.Cb] = 0 + previous_dc[.Cr] = 0 + byte_align(ctx) + } + for c in 1..=img.channels { + c := cast(Component)c + for v in 0.. 11 { + return img, .Corrupt + } + + dc_coeff := cast(i16)read_bits_msb(ctx, length) + + if length != 0 && dc_coeff < (1 << (length - 1)) { + dc_coeff -= (1 << length) - 1 + } + mcu[0] = (dc_coeff + previous_dc[c]) * cast(i16)quantization_table[0] + previous_dc[c] = dc_coeff + previous_dc[c] + + for i := 1; i < COEFFICIENT_COUNT; i += 1 { + // High nibble is amount of 0s to skip. + // Low nibble is length of coeff. + symbol := get_symbol(ctx, ac_table) + + // Special symbol used to indicate + // that the rest of the MCU is filled with 0s + if symbol == 0x00 { + continue h_loop + } + + amnt_zeros := int(symbol >> 4) + ac_coeff_len := symbol & 0xF + ac_coeff: i16 = 0 + + if i + amnt_zeros >= COEFFICIENT_COUNT || ac_coeff_len > 10 { + return img, .Corrupt + } + + i += amnt_zeros + + ac_coeff = cast(i16)read_bits_msb(ctx, ac_coeff_len) + if ac_coeff < (1 << (ac_coeff_len - 1)) { + ac_coeff -= (1 << ac_coeff_len) - 1 + } + + mcu[zigzag[i]] = ac_coeff * cast(i16)quantization_table[i] + } + } + } + } + + for c in 1..=img.channels { + c := cast(Component)c + + for v in 0..= 0; v -= 1 { + for h := luma_h_sampling_factor - 1; h >= 0; h -= 1 { + y_blk := &blocks[(y + v) * block_width + (x + h)] + + for j := BLOCK_SIZE - 1; j >= 0; j -= 1 { + for k := BLOCK_SIZE - 1; k >= 0; k -= 1 { + i := j * BLOCK_SIZE + k + cbcr_pixel_row := j / luma_v_sampling_factor + 4 * v + cbcr_pixel_column := k / luma_h_sampling_factor + 4 * h + cbcr_pixel := cbcr_pixel_row * BLOCK_SIZE + cbcr_pixel_column + + r := cast(i16)clamp(cast(f32)y_blk[.Y][i] + 1.402 * cast(f32)cbcr_blk[.Cr][cbcr_pixel] + 128, 0, 255) + g := cast(i16)clamp(cast(f32)y_blk[.Y][i] - 0.344 * cast(f32)cbcr_blk[.Cb][cbcr_pixel] - 0.714 * cast(f32)cbcr_blk[.Cr][cbcr_pixel] + 128, 0, 255) + b := cast(i16)clamp(cast(f32)y_blk[.Y][i] + 1.772 * cast(f32)cbcr_blk[.Cb][cbcr_pixel] + 128, 0, 255) + + y_blk[.Y][i] = r + y_blk[.Cb][i] = g + y_blk[.Cr][i] = b + } + } + } + } + } + } + + orig_channels := img.channels + + // We automatically expand grayscale images to RGB + if img.channels == 1 { + img.channels += 2 + } + + if .alpha_add_if_missing in options { + img.channels += 1 + orig_channels += 1 + } + + if resize(&img.pixels.buf, img.width * img.height * img.channels) != nil { + return img, .Unable_To_Allocate_Or_Resize + } + + switch orig_channels { + case 1: // Grayscale JPEG expanded to RGB + out := mem.slice_data_cast([]image.RGB_Pixel, img.pixels.buf[:]) + out_idx := 0 + for y in 0.. (img: ^Image, err: Error) { + context.allocator = allocator + + data, ok := os.read_entire_file(filename) + defer delete(data) + + if ok { + return load_from_bytes(data, options) + } else { + return nil, .Unable_To_Read_File + } +} diff --git a/core/image/netpbm/netpbm.odin b/core/image/netpbm/netpbm.odin index a9dc6599a..25e0228b5 100644 --- a/core/image/netpbm/netpbm.odin +++ b/core/image/netpbm/netpbm.odin @@ -720,7 +720,7 @@ autoselect_pbm_format_from_image :: proc(img: ^Image, prefer_binary := true, for } @(init, private) -_register :: proc() { +_register :: proc "contextless" () { loader :: proc(data: []byte, options: image.Options, allocator: mem.Allocator) -> (img: ^Image, err: Error) { return load_from_bytes(data, allocator) } diff --git a/core/image/png/helpers.odin b/core/image/png/helpers.odin index a9495ed4d..97e70226c 100644 --- a/core/image/png/helpers.odin +++ b/core/image/png/helpers.odin @@ -366,7 +366,7 @@ chrm :: proc(c: image.PNG_Chunk) -> (res: cHRM, ok: bool) { return } -exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) { +exif :: proc(c: image.PNG_Chunk) -> (res: image.Exif, ok: bool) { ok = true @@ -396,4 +396,4 @@ exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) { General helper functions */ -compute_buffer_size :: image.compute_buffer_size \ No newline at end of file +compute_buffer_size :: image.compute_buffer_size diff --git a/core/image/png/png.odin b/core/image/png/png.odin index 2d3665e94..3516fc8d3 100644 --- a/core/image/png/png.odin +++ b/core/image/png/png.odin @@ -138,14 +138,6 @@ Text :: struct { text: string, } -Exif :: struct { - byte_order: enum { - little_endian, - big_endian, - }, - data: []u8, -} - iCCP :: struct { name: string, profile: []u8, @@ -250,10 +242,14 @@ read_header :: proc(ctx: ^$C) -> (image.PNG_IHDR, Error) { header := (^image.PNG_IHDR)(raw_data(c.data))^ // Validate IHDR using header - if width == 0 || height == 0 || u128(width) * u128(height) > image.MAX_DIMENSIONS { + if width == 0 || height == 0 { return {}, .Invalid_Image_Dimensions } + if u128(width) * u128(height) > image.MAX_DIMENSIONS { + return {}, .Image_Dimensions_Too_Large + } + if compression_method != 0 { return {}, compress.General_Error.Unknown_Compression_Method } @@ -1212,7 +1208,6 @@ Filter_Params :: struct #packed { depth_scale_table :: []u8{0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01} -// @(optimization_mode="speed") defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) { using params @@ -1273,7 +1268,6 @@ defilter_8 :: proc(params: ^Filter_Params) -> (ok: bool) { return } -// @(optimization_mode="speed") defilter_less_than_8 :: proc(params: ^Filter_Params) -> bool #no_bounds_check { using params @@ -1436,7 +1430,6 @@ defilter_less_than_8 :: proc(params: ^Filter_Params) -> bool #no_bounds_check { return true } -// @(optimization_mode="speed") defilter_16 :: proc(params: ^Filter_Params) -> bool { using params @@ -1614,6 +1607,6 @@ defilter :: proc(img: ^Image, filter_bytes: ^bytes.Buffer, header: ^image.PNG_IH } @(init, private) -_register :: proc() { +_register :: proc "contextless" () { image.register(.PNG, load_from_bytes, destroy) } diff --git a/core/image/qoi/qoi.odin b/core/image/qoi/qoi.odin index 6b6149e60..ded8d7971 100644 --- a/core/image/qoi/qoi.odin +++ b/core/image/qoi/qoi.odin @@ -371,6 +371,6 @@ qoi_hash :: #force_inline proc(pixel: RGBA_Pixel) -> (index: u8) { } @(init, private) -_register :: proc() { +_register :: proc "contextless" () { image.register(.QOI, load_from_bytes, destroy) } diff --git a/core/image/tga/tga.odin b/core/image/tga/tga.odin index 46e37a0cf..5fda803c5 100644 --- a/core/image/tga/tga.odin +++ b/core/image/tga/tga.odin @@ -406,6 +406,6 @@ IMAGE_DESCRIPTOR_RIGHT_MASK :: 1<<4 IMAGE_DESCRIPTOR_TOP_MASK :: 1<<5 @(init, private) -_register :: proc() { +_register :: proc "contextless" () { image.register(.TGA, load_from_bytes, destroy) } \ No newline at end of file diff --git a/core/io/io.odin b/core/io/io.odin index c2b44cbdb..c4eb6a073 100644 --- a/core/io/io.odin +++ b/core/io/io.odin @@ -5,6 +5,7 @@ package io import "base:intrinsics" import "core:unicode/utf8" +import "core:unicode/utf16" // Seek whence values Seek_From :: enum { @@ -314,6 +315,29 @@ write_string :: proc(s: Writer, str: string, n_written: ^int = nil) -> (n: int, return write(s, transmute([]byte)str, n_written) } +// write_string16 writes the contents of the string16 s to w reencoded as utf-8 +write_string16 :: proc(s: Writer, str: string16, n_written: ^int = nil) -> (n: int, err: Error) { + for i := 0; i < len(str); i += 1 { + r := rune(utf16.REPLACEMENT_CHAR) + switch c := str[i]; { + case c < utf16._surr1, utf16._surr3 <= c: + r = rune(c) + case utf16._surr1 <= c && c < utf16._surr2 && i+1 < len(str) && + utf16._surr2 <= str[i+1] && str[i+1] < utf16._surr3: + r = utf16.decode_surrogate_pair(rune(c), rune(str[i+1])) + i += 1 + } + + w: int + w, err = write_rune(s, r, n_written) + n += w + if err != nil { + return + } + } + return +} + // write_rune writes a UTF-8 encoded rune to w. write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err: Error) { defer if err == nil && n_written != nil { diff --git a/core/io/util.odin b/core/io/util.odin index fdbbd5b9f..a956a5975 100644 --- a/core/io/util.odin +++ b/core/io/util.odin @@ -22,12 +22,12 @@ write_ptr_at :: proc(w: Writer_At, p: rawptr, byte_size: int, offset: i64, n_wri write_u64 :: proc(w: Writer, i: u64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { buf: [32]byte - s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], i, base, false, 64, strconv.digits, nil) return write_string(w, s, n_written) } write_i64 :: proc(w: Writer, i: i64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { buf: [32]byte - s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) return write_string(w, s, n_written) } @@ -40,18 +40,18 @@ write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> ( write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { buf: [39]byte - s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil) + s := strconv.write_bits_128(buf[:], i, base, false, 128, strconv.digits, nil) return write_string(w, s, n_written) } write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) { buf: [40]byte - s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil) + s := strconv.write_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil) return write_string(w, s, n_written) } write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: Error) { buf: [386]byte - str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) + str := strconv.write_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) s := buf[:len(str)+1] if s[1] == '+' || s[1] == '-' { s = s[1:] @@ -67,7 +67,7 @@ write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: E write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: Error) { buf: [386]byte - str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) + str := strconv.write_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val)) s := buf[:len(str)+1] if s[1] == '+' || s[1] == '-' { s = s[1:] @@ -83,7 +83,7 @@ write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: E write_f64 :: proc(w: Writer, val: f64, n_written: ^int = nil) -> (n: int, err: Error) { buf: [386]byte - str := strconv.append_float(buf[1:], val, 'f', 2*size_of(val), 8*size_of(val)) + str := strconv.write_float(buf[1:], val, 'f', 2*size_of(val), 8*size_of(val)) s := buf[:len(str)+1] if s[1] == '+' || s[1] == '-' { s = s[1:] @@ -130,7 +130,7 @@ write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^ write_string(w, `\x`, &n) or_return buf: [2]byte - s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil) switch len(s) { case 0: write_string(w, "00", &n) or_return @@ -189,6 +189,23 @@ write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false, write_encoded_rune(w, r, false, &n) or_return return } + if r < 32 && for_json { + switch r { + case '\b': write_string(w, `\b`, &n) or_return + case '\f': write_string(w, `\f`, &n) or_return + case '\n': write_string(w, `\n`, &n) or_return + case '\r': write_string(w, `\r`, &n) or_return + case '\t': write_string(w, `\t`, &n) or_return + case: + write_byte(w, '\\', &n) or_return + write_byte(w, 'u', &n) or_return + write_byte(w, '0', &n) or_return + write_byte(w, '0', &n) or_return + write_byte(w, DIGITS_LOWER[r>>4 & 0xf], &n) or_return + write_byte(w, DIGITS_LOWER[r & 0xf], &n) or_return + } + return + } switch r { case '\a': write_string(w, `\a`, &n) or_return case '\b': write_string(w, `\b`, &n) or_return @@ -264,6 +281,33 @@ write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written return } +write_quoted_string16 :: proc(w: Writer, str: string16, quote: byte = '"', n_written: ^int = nil, for_json := false) -> (n: int, err: Error) { + defer if n_written != nil { + n_written^ += n + } + write_byte(w, quote, &n) or_return + for width, s := 0, str; len(s) > 0; s = s[width:] { + r := rune(s[0]) + width = 1 + if r >= utf8.RUNE_SELF { + r, width = utf16.decode_rune_in_string(s) + } + if width == 1 && r == utf8.RUNE_ERROR { + write_byte(w, '\\', &n) or_return + write_byte(w, 'x', &n) or_return + write_byte(w, DIGITS_LOWER[s[0]>>4], &n) or_return + write_byte(w, DIGITS_LOWER[s[0]&0xf], &n) or_return + continue + } + + n_wrapper(write_escaped_rune(w, r, quote, false, nil, for_json), &n) or_return + + } + write_byte(w, quote, &n) or_return + return +} + + // writer append a quoted rune into the byte buffer, return the written size write_quoted_rune :: proc(w: Writer, r: rune) -> (n: int) { _write_byte :: #force_inline proc(w: Writer, c: byte) -> int { diff --git a/core/log/file_console_logger.odin b/core/log/file_console_logger.odin index 6d93fb879..f0acc8a22 100644 --- a/core/log/file_console_logger.odin +++ b/core/log/file_console_logger.odin @@ -2,10 +2,12 @@ #+build !orca package log -import "core:encoding/ansi" +import "base:runtime" import "core:fmt" import "core:strings" import "core:os" +import "core:terminal" +import "core:terminal/ansi" import "core:time" Level_Headers := [?]string{ @@ -37,11 +39,38 @@ File_Console_Logger_Data :: struct { ident: string, } +@(private) global_subtract_stdout_options: Options +@(private) global_subtract_stderr_options: Options + +@(init, private) +init_standard_stream_status :: proc "contextless" () { + // NOTE(Feoramund): While it is technically possible for these streams to + // be redirected during the runtime of the program, the cost of checking on + // every single log message is not worth it to support such an + // uncommonly-used feature. + if terminal.color_enabled { + context = runtime.default_context() + + // This is done this way because it's possible that only one of these + // streams could be redirected to a file. + if !terminal.is_terminal(os.stdout) { + global_subtract_stdout_options = {.Terminal_Color} + } + if !terminal.is_terminal(os.stderr) { + global_subtract_stderr_options = {.Terminal_Color} + } + } else { + // Override any terminal coloring. + global_subtract_stdout_options = {.Terminal_Color} + global_subtract_stderr_options = {.Terminal_Color} + } +} + create_file_logger :: proc(h: os.Handle, lowest := Level.Debug, opt := Default_File_Logger_Opts, ident := "", allocator := context.allocator) -> Logger { data := new(File_Console_Logger_Data, allocator) data.file_handle = h data.ident = ident - return Logger{file_console_logger_proc, data, lowest, opt} + return Logger{file_logger_proc, data, lowest, opt} } destroy_file_logger :: proc(log: Logger, allocator := context.allocator) { @@ -56,19 +85,15 @@ create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logg data := new(File_Console_Logger_Data, allocator) data.file_handle = os.INVALID_HANDLE data.ident = ident - return Logger{file_console_logger_proc, data, lowest, opt} + return Logger{console_logger_proc, data, lowest, opt} } destroy_console_logger :: proc(log: Logger, allocator := context.allocator) { free(log.data, allocator) } -file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { - data := cast(^File_Console_Logger_Data)logger_data - h: os.Handle = os.stdout if level <= Level.Error else os.stderr - if data.file_handle != os.INVALID_HANDLE { - h = data.file_handle - } +@(private) +_file_console_logger_proc :: proc(h: os.Handle, ident: string, level: Level, text: string, options: Options, location: runtime.Source_Code_Location) { backing: [1024]byte //NOTE(Hoej): 1024 might be too much for a header backing, unless somebody has really long paths. buf := strings.builder_from_bytes(backing[:]) @@ -86,13 +111,32 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string fmt.sbprintf(&buf, "[{}] ", os.current_thread_id()) } - if data.ident != "" { - fmt.sbprintf(&buf, "[%s] ", data.ident) + if ident != "" { + fmt.sbprintf(&buf, "[%s] ", ident) } //TODO(Hoej): When we have better atomics and such, make this thread-safe fmt.fprintf(h, "%s%s\n", strings.to_string(buf), text) } +file_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { + data := cast(^File_Console_Logger_Data)logger_data + _file_console_logger_proc(data.file_handle, data.ident, level, text, options, location) +} + +console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { + options := options + data := cast(^File_Console_Logger_Data)logger_data + h: os.Handle = --- + if level < Level.Error { + h = os.stdout + options -= global_subtract_stdout_options + } else { + h = os.stderr + options -= global_subtract_stderr_options + } + _file_console_logger_proc(h, data.ident, level, text, options, location) +} + do_level_header :: proc(opts: Options, str: ^strings.Builder, level: Level) { RESET :: ansi.CSI + ansi.RESET + ansi.SGR diff --git a/core/log/log.odin b/core/log/log.odin index 2b6317060..b2efe8beb 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -193,7 +193,7 @@ log :: proc(level: Level, args: ..any, sep := " ", location := #caller_location) return } runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - str := fmt.tprint(..args, sep=sep) //NOTE(Hoej): While tprint isn't thread-safe, no logging is. + str := fmt.tprint(..args, sep=sep) logger.procedure(logger.data, level, str, logger.options, location) } diff --git a/core/math/big/api.odin b/core/math/big/api.odin index bf19e83b6..70e134a90 100644 --- a/core/math/big/api.odin +++ b/core/math/big/api.odin @@ -160,6 +160,5 @@ destroy :: proc { int_destroy :: proc(integers: ..^Int) */ int_destroy, -} - - + internal_rat_destroy, +} \ No newline at end of file diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 5428b00ee..22655293f 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -14,23 +14,12 @@ import "base:intrinsics" This allows to benchmark and/or setting optimized values for a certain CPU without recompiling. */ -/* - ========================== TUNABLES ========================== - - `initialize_constants` returns `#config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF)` - and we initialize this cutoff that way so that the procedure is used and called, - because it handles initializing the constants ONE, ZERO, MINUS_ONE, NAN and INF. - - `initialize_constants` also replaces the other `_DEFAULT_*` cutoffs with custom compile-time values if so `#config`ured. - -*/ - /* There is a bug with DLL globals. They don't get set. To allow tests to run we add `-define:MATH_BIG_EXE=false` to hardcode the cutoffs for now. */ when #config(MATH_BIG_EXE, true) { - MUL_KARATSUBA_CUTOFF := initialize_constants() + MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index ee09bb2c7..9ee35c45a 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -7,6 +7,7 @@ package math_big import "base:intrinsics" +import "base:runtime" import rnd "core:math/rand" /* @@ -777,32 +778,36 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca */ INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{} -@(init, private) -_init_constants :: proc() { - initialize_constants() -} +@(private) +constant_allocator: runtime.Allocator -initialize_constants :: proc() -> (res: int) { - internal_set( INT_ZERO, 0); INT_ZERO.flags = {.Immutable} - internal_set( INT_ONE, 1); INT_ONE.flags = {.Immutable} - internal_set(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable} +@(init, private) +initialize_constants :: proc "contextless" () { + context = runtime.default_context() + constant_allocator = context.allocator + + internal_int_set_from_integer( INT_ZERO, 0); INT_ZERO.flags = {.Immutable} + internal_int_set_from_integer( INT_ONE, 1); INT_ONE.flags = {.Immutable} + internal_int_set_from_integer(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable} /* We set these special values to -1 or 1 so they don't get mistake for zero accidentally. This allows for shortcut tests of is_zero as .used == 0. */ - internal_set( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN} - internal_set( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf} - internal_set(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf} - - return _DEFAULT_MUL_KARATSUBA_CUTOFF + internal_int_set_from_integer( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN} + internal_int_set_from_integer( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf} + internal_int_set_from_integer(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf} } /* Destroy constants. Optional for an EXE, as this would be called at the very end of a process. */ -destroy_constants :: proc() { +@(fini, private) +destroy_constants :: proc "contextless" () { + context = runtime.default_context() + context.allocator = constant_allocator + internal_destroy(INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN) } diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index c9b331e55..e0bc1ae06 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -27,10 +27,10 @@ package math_big -import "core:mem" -import "base:intrinsics" -import rnd "core:math/rand" import "base:builtin" +import "base:intrinsics" +import "core:mem" +import rnd "core:math/rand" /* Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7. @@ -1660,13 +1660,13 @@ internal_int_sqrt :: proc(dest, src: ^Int, allocator := context.allocator) -> (e if internal_gte(y, x) { internal_swap(dest, x) - return nil + return internal_clamp(dest) } internal_swap(x, y) } internal_swap(dest, x) - return err + return internal_clamp(dest) } internal_sqrt :: proc { internal_int_sqrt, } @@ -2885,12 +2885,12 @@ internal_clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context } internal_clear_if_uninitialized :: proc {internal_clear_if_uninitialized_single, internal_clear_if_uninitialized_multi, } -internal_error_if_immutable_single :: proc(arg: ^Int) -> (err: Error) { +internal_error_if_immutable_single :: proc "contextless" (arg: ^Int) -> (err: Error) { if arg != nil && .Immutable in arg.flags { return .Assignment_To_Immutable } return nil } -internal_error_if_immutable_multi :: proc(args: ..^Int) -> (err: Error) { +internal_error_if_immutable_multi :: proc "contextless" (args: ..^Int) -> (err: Error) { for i in args { if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable } } diff --git a/core/math/big/private.odin b/core/math/big/private.odin index bb6b9497c..c42bad0c6 100644 --- a/core/math/big/private.odin +++ b/core/math/big/private.odin @@ -1370,8 +1370,8 @@ _private_int_div_recursive :: proc(quotient, remainder, a, b: ^Int, allocator := /* Slower bit-bang division... also smaller. + Prefer `_int_div_school` for speed. */ -@(deprecated="Use `_int_div_school`, it's 3.5x faster.") _private_int_div_small :: proc(quotient, remainder, numerator, denominator: ^Int) -> (err: Error) { ta, tb, tq, q := &Int{}, &Int{}, &Int{}, &Int{} diff --git a/core/math/big/radix.odin b/core/math/big/radix.odin index a5100e478..73c4452ac 100644 --- a/core/math/big/radix.odin +++ b/core/math/big/radix.odin @@ -280,7 +280,7 @@ int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context } pos := ch - '+' - if RADIX_TABLE_REVERSE_SIZE <= pos { + if RADIX_TABLE_REVERSE_SIZE <= u32(pos) { break } y := RADIX_TABLE_REVERSE[pos] @@ -310,7 +310,7 @@ int_atoi :: proc(res: ^Int, input: string, radix := i8(10), allocator := context res.sign = sign } - return nil + return internal_clamp(res) } diff --git a/core/math/big/rat.odin b/core/math/big/rat.odin index e0e58b80f..3c32d45cb 100644 --- a/core/math/big/rat.odin +++ b/core/math/big/rat.odin @@ -157,6 +157,8 @@ internal_rat_norm :: proc(z: ^Rat, allocator := context.allocator) -> (err: Erro z.b.sign = .Zero_or_Positive f := &Int{} + defer internal_int_destroy(f) + internal_int_gcd(f, &z.a, &z.b) or_return if !internal_int_equals_digit(f, 1) { f.sign = .Zero_or_Positive @@ -378,9 +380,6 @@ internal_rat_to_float :: proc($T: typeid, z: ^Rat, allocator := context.allocato } has_sign := a.sign != b.sign - defer if has_sign { - f = -builtin.abs(f) - } exp := alen - blen a2, b2 := &Int{}, &Int{} @@ -440,6 +439,9 @@ internal_rat_to_float :: proc($T: typeid, z: ^Rat, allocator := context.allocato if math.is_inf(f, 0) { exact = false } + if has_sign { + f = -builtin.abs(f) + } return } diff --git a/core/math/fixed/fixed.odin b/core/math/fixed/fixed.odin index b23090307..9af6d7599 100644 --- a/core/math/fixed/fixed.odin +++ b/core/math/fixed/fixed.odin @@ -103,7 +103,7 @@ round :: proc(x: $T/Fixed($Backing, $Fraction_Width)) -> Backing { } @(require_results) -append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string { +write :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string { Integer_Width :: 8*size_of(Backing) - Fraction_Width x := x @@ -124,16 +124,16 @@ append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string { when size_of(Backing) < 16 { T :: u64 - append_uint :: strconv.append_uint + write_uint :: strconv.write_uint } else { T :: u128 - append_uint :: strconv.append_u128 + write_uint :: strconv.write_u128 } integer := T(x.i) >> Fraction_Width fraction := T(x.i) & (1< string { @(require_results) to_string :: proc(x: $T/Fixed($Backing, $Fraction_Width), allocator := context.allocator) -> string { buf: [48]byte - s := append(buf[:], x) + s := write(buf[:], x) str := make([]byte, len(s), allocator) copy(str, s) return string(str) @@ -294,3 +294,8 @@ _power_of_two_table := [129]string{ "85070591730234615865843651857942052864", "170141183460469231731687303715884105728", } + +@(deprecated="Use write instead") +append :: proc(dst: []byte, x: $T/Fixed($Backing, $Fraction_Width)) -> string { + return write(dst, x) +} diff --git a/core/math/math.odin b/core/math/math.odin index 934842318..b99a97bc1 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -2296,7 +2296,7 @@ nextafter_f16 :: proc "contextless" (x, y: f16) -> (r: f16) { case x == y: r = x case x == 0: - r = copy_sign_f16(1, y) + r = copy_sign_f16(transmute(f16)u16(1), y) case (y > x) == (x > 0): r = transmute(f16)(transmute(u16)x + 1) case: @@ -2312,7 +2312,7 @@ nextafter_f32 :: proc "contextless" (x, y: f32) -> (r: f32) { case x == y: r = x case x == 0: - r = copy_sign_f32(1, y) + r = copy_sign_f32(transmute(f32)u32(1), y) case (y > x) == (x > 0): r = transmute(f32)(transmute(u32)x + 1) case: @@ -2328,7 +2328,7 @@ nextafter_f64 :: proc "contextless" (x, y: f64) -> (r: f64) { case x == y: r = x case x == 0: - r = copy_sign_f64(1, y) + r = copy_sign_f64(transmute(f64)u64(1), y) case (y > x) == (x > 0): r = transmute(f64)(transmute(u64)x + 1) case: @@ -2349,32 +2349,6 @@ nextafter :: proc{ nextafter_f64, nextafter_f64le, nextafter_f64be, } -@(require_results) -signbit_f16 :: proc "contextless" (x: f16) -> bool { - return (transmute(u16)x)&(1<<15) != 0 -} -@(require_results) -signbit_f32 :: proc "contextless" (x: f32) -> bool { - return (transmute(u32)x)&(1<<31) != 0 -} -@(require_results) -signbit_f64 :: proc "contextless" (x: f64) -> bool { - return (transmute(u64)x)&(1<<63) != 0 -} -@(require_results) signbit_f16le :: proc "contextless" (x: f16le) -> bool { return signbit_f16(f16(x)) } -@(require_results) signbit_f32le :: proc "contextless" (x: f32le) -> bool { return signbit_f32(f32(x)) } -@(require_results) signbit_f64le :: proc "contextless" (x: f64le) -> bool { return signbit_f64(f64(x)) } -@(require_results) signbit_f16be :: proc "contextless" (x: f16be) -> bool { return signbit_f16(f16(x)) } -@(require_results) signbit_f32be :: proc "contextless" (x: f32be) -> bool { return signbit_f32(f32(x)) } -@(require_results) signbit_f64be :: proc "contextless" (x: f64be) -> bool { return signbit_f64(f64(x)) } - -signbit :: proc{ - signbit_f16, signbit_f16le, signbit_f16be, - signbit_f32, signbit_f32le, signbit_f32be, - signbit_f64, signbit_f64le, signbit_f64be, -} - - @(require_results) hypot_f16 :: proc "contextless" (x, y: f16) -> (r: f16) { p, q := abs(x), abs(y) diff --git a/core/math/math_gamma.odin b/core/math/math_gamma.odin index 9f5a364d3..9e8c2a909 100644 --- a/core/math/math_gamma.odin +++ b/core/math/math_gamma.odin @@ -132,7 +132,7 @@ gamma_f64 :: proc "contextless" (x: f64) -> f64 { case is_inf(x, 1): return inf_f64(1) case x == 0: - if signbit(x) { + if sign_bit(x) { return inf_f64(-1) } return inf_f64(1) diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index 537256d32..6b9a73395 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -33,7 +33,7 @@ Example: import "core:math/rand" import "core:fmt" - set_global_seed_example :: proc() { + reset_example :: proc() { rand.reset(1) fmt.println(rand.uint64()) } @@ -56,13 +56,6 @@ query_info :: proc(gen := context.random_generator) -> Generator_Query_Info { } -@(private) -_random_u64 :: proc(gen := context.random_generator) -> (res: u64) { - ok := runtime.random_generator_read_ptr(gen, &res, size_of(res)) - assert(ok, "uninitialized gen/context.random_generator") - return -} - /* Generates a random 32 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. @@ -84,7 +77,7 @@ Possible Output: */ @(require_results) -uint32 :: proc(gen := context.random_generator) -> (val: u32) { return u32(_random_u64(gen)) } +uint32 :: proc(gen := context.random_generator) -> (val: u32) {return u32(uint64(gen))} /* Generates a random 64 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. @@ -107,7 +100,11 @@ Possible Output: */ @(require_results) -uint64 :: proc(gen := context.random_generator) -> (val: u64) { return _random_u64(gen) } +uint64 :: proc(gen := context.random_generator) -> (val: u64) { + ok := runtime.random_generator_read_ptr(gen, &val, size_of(val)) + assert(ok, "uninitialized gen/context.random_generator") + return +} /* Generates a random 128 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. @@ -131,13 +128,13 @@ Possible Output: */ @(require_results) uint128 :: proc(gen := context.random_generator) -> (val: u128) { - a := u128(_random_u64(gen)) - b := u128(_random_u64(gen)) + a := u128(uint64(gen)) + b := u128(uint64(gen)) return (a<<64) | b } /* -Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. +Generates a random 31 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. The sign bit will always be set to 0, thus all generated numbers will be positive. Returns: @@ -160,7 +157,7 @@ Possible Output: @(require_results) int31 :: proc(gen := context.random_generator) -> (val: i32) { return i32(uint32(gen) << 1 >> 1) } /* -Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. +Generates a random 63 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. The sign bit will always be set to 0, thus all generated numbers will be positive. Returns: @@ -183,7 +180,7 @@ Possible Output: @(require_results) int63 :: proc(gen := context.random_generator) -> (val: i64) { return i64(uint64(gen) << 1 >> 1) } /* -Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. +Generates a random 127 bit value using the provided random number generator. If no generator is provided the global random number generator will be used. The sign bit will always be set to 0, thus all generated numbers will be positive. Returns: @@ -350,7 +347,7 @@ Example: Possible Output: 6 - 500 + 13 */ @(require_results) @@ -432,7 +429,7 @@ Example: Possible Output: 15.312 - 673.130 + 273.15 */ @(require_results) float64_range :: proc(low, high: f64, gen := context.random_generator) -> (val: f64) { @@ -467,7 +464,7 @@ Example: Possible Output: 15.312 - 273.130 + 273.15 */ @(require_results) float32_range :: proc(low, high: f32, gen := context.random_generator) -> (val: f32) { @@ -480,8 +477,8 @@ Possible Output: } /* -Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used. -Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value. +Fills a byte slice with random values using the provided random number generator. If no generator is provided the global random number generator will be used. +Due to floating point precision there is no guarantee if the upper and lower bounds are inclusive/exclusive with the exact floating point value. Inputs: - p: The byte slice to fill @@ -508,22 +505,12 @@ Possible Output: */ @(require_results) read :: proc(p: []byte, gen := context.random_generator) -> (n: int) { - pos := i8(0) - val := i64(0) - for n = 0; n < len(p); n += 1 { - if pos == 0 { - val = int63(gen) - pos = 7 - } - p[n] = byte(val) - val >>= 8 - pos -= 1 - } - return + if !runtime.random_generator_read_bytes(gen, p) {return 0} + return len(p) } /* -Creates a slice of `int` filled with random values using the provided random number generator. If no generator is provided the global random number generator will be used. +Creates a slice of `int` filled with random values using the provided random number generator. If no generator is provided the global random number generator will be used. *Allocates Using Provided Allocator* @@ -566,7 +553,7 @@ perm :: proc(n: int, allocator := context.allocator, gen := context.random_gener } /* -Randomizes the ordering of elements for the provided slice. If no generator is provided the global random number generator will be used. +Randomizes the ordering of elements for the provided slice. If no generator is provided the global random number generator will be used. Inputs: - array: The slice to randomize @@ -607,7 +594,7 @@ shuffle :: proc(array: $T/[]$E, gen := context.random_generator) { } /* -Returns a random element from the provided slice. If no generator is provided the global random number generator will be used. +Returns a random element from the provided slice. If no generator is provided the global random number generator will be used. Inputs: - array: The slice to choose an element from diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index 1094e7381..48cc39245 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -888,6 +888,34 @@ make_aligned :: proc( return runtime.make_aligned(T, len, alignment, allocator, loc) } + +/* +Allocate a new slice with alignment for allocators that might not support the +specified alignment requirement. + +This procedure allocates a new slice of type `T` with length `len`, aligned +on a boundary specified by `alignment` from an allocator specified by +`allocator`, and returns the allocated slice. + +The user should `delete` the return `original_data` slice not the typed `slice`. +*/ +@(require_results) +make_over_aligned :: proc( + $T: typeid/[]$E, + #any_int len: int, + alignment: int, + allocator: runtime.Allocator, + loc := #caller_location, +) -> (slice: T, original_data: []byte, err: Allocator_Error) { + size := size_of(E)*len + alignment-1 + original_data, err = runtime.make([]byte, size, allocator, loc) + if err == nil { + ptr := align_forward(raw_data(original_data), uintptr(alignment)) + slice = ([^]E)(ptr)[:len] + } + return +} + /* Allocate a new slice. @@ -953,6 +981,22 @@ make_dynamic_array_len_cap :: proc( return runtime.make_dynamic_array_len_cap(T, len, cap, allocator, loc) } +/* +Create a map with no initial allocation. + +This procedure creates a map of type `T` with no initial allocation, which will +use the allocator specified by `allocator` as its backing allocator when it +allocates. +*/ +@(require_results) +make_map :: proc( + $T: typeid/map[$K]$E, + allocator := context.allocator, + loc := #caller_location, +) -> (m: T) { + return runtime.make_map(T, allocator, loc) +} + /* Allocate a map. @@ -961,13 +1005,13 @@ This procedure creates a map of type `T` with initial capacity specified by allocator. */ @(require_results) -make_map :: proc( +make_map_cap :: proc( $T: typeid/map[$K]$E, - #any_int cap: int = 1< (m: T, err: Allocator_Error) { - return runtime.make_map(T, cap, allocator, loc) + return runtime.make_map_cap(T, cap, allocator, loc) } /* @@ -1060,6 +1104,7 @@ make :: proc{ make_dynamic_array_len, make_dynamic_array_len_cap, make_map, + make_map_cap, make_multi_pointer, make_soa_slice, make_soa_dynamic_array, diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 028be58e3..5b0b178f8 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -3,6 +3,57 @@ package mem import "base:intrinsics" import "base:runtime" +// NOTE(Feoramund): Sanitizer usage in this package has been temporarily +// disabled pending a thorough review per allocator, as ASan is particular +// about the addresses and ranges it receives. +// +// In short, it keeps track only of 8-byte blocks. This can cause issues if an +// allocator poisons an entire range but an allocation for less than 8 bytes is +// desired or if the next allocation address would not be 8-byte aligned. +// +// This must be handled carefully on a per-allocator basis and some allocators +// may not be able to participate. +// +// Please see the following link for more information: +// +// https://github.com/google/sanitizers/wiki/AddressSanitizerAlgorithm#mapping +// +// import "base:sanitizer" + + +/* +This procedure checks if a byte slice `range` is poisoned and makes sure the +root address of the poison range is the base pointer of `range`. + +This can help guard against buggy allocators returning memory that they already returned. + +This has no effect if `-sanitize:address` is not enabled. +*/ +// @(disabled=.Address not_in ODIN_SANITIZER_FLAGS, private) +// ensure_poisoned :: proc(range: []u8, loc := #caller_location) { +// cond := sanitizer.address_region_is_poisoned(range) == raw_data(range) +// // If this fails, we've overlapped an allocation and it's our fault. +// ensure(cond, `This allocator has sliced a block of memory of which some part is not poisoned before returning. +// This is a bug in the core library and should be reported to the Odin developers with a stack trace and minimal example code if possible.`, loc) +// } + +/* +This procedure checks if a byte slice `range` is not poisoned. + +This can help guard against buggy allocators resizing memory that they should not. + +This has no effect if `-sanitize:address` is not enabled. +*/ +// @(disabled=.Address not_in ODIN_SANITIZER_FLAGS, private) +// ensure_not_poisoned :: proc(range: []u8, loc := #caller_location) { +// cond := sanitizer.address_region_is_poisoned(range) == nil +// // If this fails, we've tried to resize memory that is poisoned, which +// // could be user error caused by an incorrect `old_memory` pointer. +// ensure(cond, `This allocator has sliced a block of memory of which some part is poisoned before returning. +// This may be a bug in the core library, or it could be user error due to an invalid pointer passed to a resize operation. +// If after ensuring your own code is not responsible, report the problem to the Odin developers with a stack trace and minimal example code if possible.`, loc) +// } + /* Nil allocator. @@ -107,11 +158,10 @@ The arena allocator (also known as a linear allocator, bump allocator, region allocator) is an allocator that uses a single backing buffer for allocations. -The buffer is being used contiguously, from start by end. Each subsequent -allocation occupies the next adjacent region of memory in the buffer. Since -arena allocator does not keep track of any metadata associated with the -allocations and their locations, it is impossible to free individual -allocations. +The buffer is used contiguously, from start to end. Each subsequent allocation +occupies the next adjacent region of memory in the buffer. Since the arena +allocator does not keep track of any metadata associated with the allocations +and their locations, it is impossible to free individual allocations. The arena allocator can be used for temporary allocations in frame-based memory management. Games are one example of such applications. A global arena can be @@ -130,7 +180,7 @@ arena_allocator :: proc(arena: ^Arena) -> Allocator { /* Initialize an arena. -This procedure initializes the arena `a` with memory region `data` as it's +This procedure initializes the arena `a` with memory region `data` as its backing buffer. */ arena_init :: proc(a: ^Arena, data: []byte) { @@ -138,6 +188,7 @@ arena_init :: proc(a: ^Arena, data: []byte) { a.offset = 0 a.peak_used = 0 a.temp_count = 0 + // sanitizer.address_poison(a.data) } /* @@ -214,7 +265,7 @@ arena_alloc_bytes_non_zeroed :: proc( loc := #caller_location ) -> ([]byte, Allocator_Error) { if a.data == nil { - panic("Arena is not initialized", loc) + panic("Allocation on uninitialized Arena allocator.", loc) } #no_bounds_check end := &a.data[a.offset] ptr := align_forward(end, uintptr(alignment)) @@ -224,14 +275,18 @@ arena_alloc_bytes_non_zeroed :: proc( } a.offset += total_size a.peak_used = max(a.peak_used, a.offset) - return byte_slice(ptr, size), nil + result := byte_slice(ptr, size) + // ensure_poisoned(result) + // sanitizer.address_unpoison(result) + return result, nil } /* -Free all memory to an arena. +Free all memory back to the arena allocator. */ arena_free_all :: proc(a: ^Arena) { a.offset = 0 + // sanitizer.address_poison(a.data) } arena_allocator_proc :: proc( @@ -270,12 +325,12 @@ arena_allocator_proc :: proc( } /* -Temporary memory region of arena. +Temporary memory region of an `Arena` allocator. -Temporary memory regions of arena act as "savepoints" for arena. When one is -created, the subsequent allocations are done inside the temporary memory -region. When `end_arena_temp_memory` is called, the arena is rolled back, and -all of the memory that was allocated from the arena will be freed. +Temporary memory regions of an arena act as "save-points" for the allocator. +When one is created, the subsequent allocations are done inside the temporary +memory region. When `end_arena_temp_memory` is called, the arena is rolled +back, and all of the memory that was allocated from the arena will be freed. Multiple temporary memory regions can exist at the same time for an arena. */ @@ -309,6 +364,7 @@ allocations *inside* the temporary memory region will be freed to the arena. end_arena_temp_memory :: proc(tmp: Arena_Temp_Memory) { assert(tmp.arena.offset >= tmp.prev_offset) assert(tmp.arena.temp_count > 0) + // sanitizer.address_poison(tmp.arena.data[tmp.prev_offset:tmp.arena.offset]) tmp.arena.offset = tmp.prev_offset tmp.arena.temp_count -= 1 } @@ -322,29 +378,37 @@ scratch_allocator_destroy :: scratch_destroy Scratch allocator data. */ Scratch :: struct { - data: []byte, - curr_offset: int, - prev_allocation: rawptr, - backup_allocator: Allocator, - leaked_allocations: [dynamic][]byte, + data: []byte, + curr_offset: int, + prev_allocation: rawptr, + prev_allocation_root: rawptr, + backup_allocator: Allocator, + leaked_allocations: [dynamic][]byte, } /* Scratch allocator. The scratch allocator works in a similar way to the `Arena` allocator. The -scratch allocator has a backing buffer, that is being allocated in -contiguous regions, from start to end. +scratch allocator has a backing buffer that is allocated in contiguous regions, +from start to end. Each subsequent allocation will be the next adjacent region of memory in the backing buffer. If the allocation doesn't fit into the remaining space of the backing buffer, this allocation is put at the start of the buffer, and all -previous allocations will become invalidated. If the allocation doesn't fit -into the backing buffer as a whole, it will be allocated using a backing -allocator, and pointer to the allocated memory region will be put into the -`leaked_allocations` array. +previous allocations will become invalidated. -The `leaked_allocations` array is managed by the `context` allocator. +If the allocation doesn't fit into the backing buffer as a whole, it will be +allocated using a backing allocator, and the pointer to the allocated memory +region will be put into the `leaked_allocations` array. A `Warning`-level log +message will be sent as well. + +Allocations which are resized will be resized in-place if they were the last +allocation. Otherwise, they are re-allocated to avoid overwriting previous +allocations. + +The `leaked_allocations` array is managed by the `context` allocator if no +`backup_allocator` is specified in `scratch_init`. */ @(require_results) scratch_allocator :: proc(allocator: ^Scratch) -> Allocator { @@ -355,19 +419,24 @@ scratch_allocator :: proc(allocator: ^Scratch) -> Allocator { } /* -Initialize scratch allocator. +Initialize a scratch allocator. */ scratch_init :: proc(s: ^Scratch, size: int, backup_allocator := context.allocator) -> Allocator_Error { s.data = make_aligned([]byte, size, 2*align_of(rawptr), backup_allocator) or_return s.curr_offset = 0 s.prev_allocation = nil + s.prev_allocation_root = nil s.backup_allocator = backup_allocator s.leaked_allocations.allocator = backup_allocator + // sanitizer.address_poison(s.data) return nil } /* Free all data associated with a scratch allocator. + +This is distinct from `scratch_free_all` in that it deallocates all memory used +to setup the allocator, as opposed to all allocations made from that space. */ scratch_destroy :: proc(s: ^Scratch) { if s == nil { @@ -377,12 +446,13 @@ scratch_destroy :: proc(s: ^Scratch) { free_bytes(ptr, s.backup_allocator) } delete(s.leaked_allocations) + // sanitizer.address_unpoison(s.data) delete(s.data, s.backup_allocator) s^ = {} } /* -Allocate memory from scratch allocator. +Allocate memory from a scratch allocator. This procedure allocates `size` bytes of memory aligned on a boundary specified by `alignment`. The allocated memory region is zero-initialized. This procedure @@ -400,7 +470,7 @@ scratch_alloc :: proc( } /* -Allocate memory from scratch allocator. +Allocate memory from a scratch allocator. This procedure allocates `size` bytes of memory aligned on a boundary specified by `alignment`. The allocated memory region is zero-initialized. This procedure @@ -421,7 +491,7 @@ scratch_alloc_bytes :: proc( } /* -Allocate non-initialized memory from scratch allocator. +Allocate non-initialized memory from a scratch allocator. This procedure allocates `size` bytes of memory aligned on a boundary specified by `alignment`. The allocated memory region is not explicitly zero-initialized. @@ -439,7 +509,7 @@ scratch_alloc_non_zeroed :: proc( } /* -Allocate non-initialized memory from scratch allocator. +Allocate non-initialized memory from a scratch allocator. This procedure allocates `size` bytes of memory aligned on a boundary specified by `alignment`. The allocated memory region is not explicitly zero-initialized. @@ -455,37 +525,47 @@ scratch_alloc_bytes_non_zeroed :: proc( if s.data == nil { DEFAULT_BACKING_SIZE :: 4 * Megabyte if !(context.allocator.procedure != scratch_allocator_proc && context.allocator.data != s) { - panic("cyclic initialization of the scratch allocator with itself", loc) + panic("Cyclic initialization of the scratch allocator with itself.", loc) } scratch_init(s, DEFAULT_BACKING_SIZE) } - size := size - size = align_forward_int(size, alignment) - if size <= len(s.data) { + aligned_size := size + if alignment > 1 { + // It is possible to do this with less bytes, but this is the + // mathematically simpler solution, and this being a Scratch allocator, + // we don't need to be so strict about every byte. + aligned_size += alignment - 1 + } + if aligned_size <= len(s.data) { offset := uintptr(0) - if s.curr_offset+size <= len(s.data) { + if s.curr_offset+aligned_size <= len(s.data) { offset = uintptr(s.curr_offset) } else { + // The allocation will cause an overflow past the boundary of the + // space available, so reset to the starting offset. offset = 0 } start := uintptr(raw_data(s.data)) - ptr := align_forward_uintptr(offset+start, uintptr(alignment)) - s.prev_allocation = rawptr(ptr) - s.curr_offset = int(offset) + size - return byte_slice(rawptr(ptr), size), nil - } else { - a := s.backup_allocator - if a.procedure == nil { - a = context.allocator - s.backup_allocator = a + ptr := rawptr(offset+start) + // We keep track of the original base pointer without extra alignment + // in order to later allow the free operation to work from that point. + s.prev_allocation_root = ptr + if !is_aligned(ptr, alignment) { + ptr = align_forward(ptr, uintptr(alignment)) } + s.prev_allocation = ptr + s.curr_offset = int(offset) + aligned_size + result := byte_slice(ptr, size) + // ensure_poisoned(result) + // sanitizer.address_unpoison(result) + return result, nil + } else { + // NOTE: No need to use `aligned_size` here, as the backup allocator will handle alignment for us. + a := s.backup_allocator ptr, err := alloc_bytes_non_zeroed(size, alignment, a, loc) if err != nil { return ptr, err } - if s.leaked_allocations == nil { - s.leaked_allocations, err = make([dynamic][]byte, a) - } append(&s.leaked_allocations, ptr) if logger := context.logger; logger.lowest_level <= .Warning { if logger.procedure != nil { @@ -497,7 +577,7 @@ scratch_alloc_bytes_non_zeroed :: proc( } /* -Free memory to the scratch allocator. +Free memory back to the scratch allocator. This procedure frees the memory region allocated at pointer `ptr`. @@ -506,7 +586,7 @@ operation is a no-op. */ scratch_free :: proc(s: ^Scratch, ptr: rawptr, loc := #caller_location) -> Allocator_Error { if s.data == nil { - panic("Free on an uninitialized scratch allocator", loc) + panic("Free on an uninitialized Scratch allocator.", loc) } if ptr == nil { return nil @@ -515,8 +595,10 @@ scratch_free :: proc(s: ^Scratch, ptr: rawptr, loc := #caller_location) -> Alloc end := start + uintptr(len(s.data)) old_ptr := uintptr(ptr) if s.prev_allocation == ptr { - s.curr_offset = int(uintptr(s.prev_allocation) - start) + s.curr_offset = int(uintptr(s.prev_allocation_root) - start) + // sanitizer.address_poison(s.data[s.curr_offset:]) s.prev_allocation = nil + s.prev_allocation_root = nil return nil } if start <= old_ptr && old_ptr < end { @@ -537,7 +619,7 @@ scratch_free :: proc(s: ^Scratch, ptr: rawptr, loc := #caller_location) -> Alloc } /* -Free all memory to the scratch allocator. +Free all memory back to the scratch allocator. */ scratch_free_all :: proc(s: ^Scratch, loc := #caller_location) { s.curr_offset = 0 @@ -546,14 +628,15 @@ scratch_free_all :: proc(s: ^Scratch, loc := #caller_location) { free_bytes(ptr, s.backup_allocator, loc) } clear(&s.leaked_allocations) + // sanitizer.address_poison(s.data) } /* -Resize an allocation. +Resize an allocation owned by a scratch allocator. -This procedure resizes a memory region, defined by its location, `old_memory`, -and its size, `old_size` to have a size `size` and alignment `alignment`. The -newly allocated memory, if any is zero-initialized. +This procedure resizes a memory region defined by its location `old_memory` +and its size `old_size` to have a size `size` and alignment `alignment`. The +newly allocated memory, if any, is zero-initialized. If `old_memory` is `nil`, this procedure acts just like `scratch_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -578,10 +661,10 @@ scratch_resize :: proc( } /* -Resize an allocation. +Resize an allocation owned by a scratch allocator. -This procedure resizes a memory region, specified by `old_data`, to have a size -`size` and alignment `alignment`. The newly allocated memory, if any is +This procedure resizes a memory region specified by `old_data` to have a size +`size` and alignment `alignment`. The newly allocated memory, if any, is zero-initialized. If `old_memory` is `nil`, this procedure acts just like `scratch_alloc()`, @@ -609,11 +692,11 @@ scratch_resize_bytes :: proc( } /* -Resize an allocation without zero-initialization. +Resize an allocation owned by a scratch allocator, without zero-initialization. -This procedure resizes a memory region, defined by its location, `old_memory`, -and its size, `old_size` to have a size `size` and alignment `alignment`. The -newly allocated memory, if any is not explicitly zero-initialized. +This procedure resizes a memory region defined by its location `old_memory` +and its size `old_size` to have a size `size` and alignment `alignment`. The +newly allocated memory, if any, is not explicitly zero-initialized. If `old_memory` is `nil`, this procedure acts just like `scratch_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -638,10 +721,10 @@ scratch_resize_non_zeroed :: proc( } /* -Resize an allocation. +Resize an allocation owned by a scratch allocator. -This procedure resizes a memory region, specified by `old_data`, to have a size -`size` and alignment `alignment`. The newly allocated memory, if any is not +This procedure resizes a memory region specified by `old_data` to have a size +`size` and alignment `alignment`. The newly allocated memory, if any, is not explicitly zero-initialized. If `old_memory` is `nil`, this procedure acts just like `scratch_alloc()`, @@ -666,16 +749,25 @@ scratch_resize_bytes_non_zeroed :: proc( if s.data == nil { DEFAULT_BACKING_SIZE :: 4 * Megabyte if !(context.allocator.procedure != scratch_allocator_proc && context.allocator.data != s) { - panic("cyclic initialization of the scratch allocator with itself", loc) + panic("Cyclic initialization of the scratch allocator with itself.", loc) } scratch_init(s, DEFAULT_BACKING_SIZE) } begin := uintptr(raw_data(s.data)) end := begin + uintptr(len(s.data)) old_ptr := uintptr(old_memory) - if begin <= old_ptr && old_ptr < end && old_ptr+uintptr(size) < end { + // We can only sanely resize the last allocation; to do otherwise may + // overwrite memory that could very well just have been allocated. + // + // Also, the alignments must match, otherwise we must re-allocate to + // guarantee the user's request. + if s.prev_allocation == old_memory && is_aligned(old_memory, alignment) && old_ptr+uintptr(size) < end { + // ensure_not_poisoned(old_data) + // sanitizer.address_poison(old_memory) s.curr_offset = int(old_ptr-begin)+size - return byte_slice(old_memory, size), nil + result := byte_slice(old_memory, size) + // sanitizer.address_unpoison(result) + return result, nil } data, err := scratch_alloc_bytes_non_zeroed(s, size, alignment, loc) if err != nil { @@ -766,7 +858,7 @@ stack_allocator :: proc(stack: ^Stack) -> Allocator { } /* -Initialize the stack allocator. +Initialize a stack allocator. This procedure initializes the stack allocator with a backing buffer specified by `data` parameter. @@ -776,10 +868,11 @@ stack_init :: proc(s: ^Stack, data: []byte) { s.prev_offset = 0 s.curr_offset = 0 s.peak_used = 0 + // sanitizer.address_poison(data) } /* -Allocate memory from stack. +Allocate memory from a stack allocator. This procedure allocates `size` bytes of memory, aligned to the boundary specified by `alignment`. The allocated memory is zero-initialized. This @@ -797,7 +890,7 @@ stack_alloc :: proc( } /* -Allocate memory from stack. +Allocate memory from a stack allocator. This procedure allocates `size` bytes of memory, aligned to the boundary specified by `alignment`. The allocated memory is zero-initialized. This @@ -818,7 +911,7 @@ stack_alloc_bytes :: proc( } /* -Allocate memory from stack. +Allocate memory from a stack allocator. This procedure allocates `size` bytes of memory, aligned to the boundary specified by `alignment`. The allocated memory is not explicitly @@ -836,13 +929,13 @@ stack_alloc_non_zeroed :: proc( } /* -Allocate memory from stack. +Allocate memory from a stack allocator. This procedure allocates `size` bytes of memory, aligned to the boundary specified by `alignment`. The allocated memory is not explicitly zero-initialized. This procedure returns the slice of the allocated memory. */ -@(require_results) +@(require_results, no_sanitize_address) stack_alloc_bytes_non_zeroed :: proc( s: ^Stack, size: int, @@ -850,7 +943,7 @@ stack_alloc_bytes_non_zeroed :: proc( loc := #caller_location ) -> ([]byte, Allocator_Error) { if s.data == nil { - panic("Stack allocation on an uninitialized stack allocator", loc) + panic("Allocation on an uninitialized Stack allocator.", loc) } curr_addr := uintptr(raw_data(s.data)) + uintptr(s.curr_offset) padding := calc_padding_with_header( @@ -861,22 +954,26 @@ stack_alloc_bytes_non_zeroed :: proc( if s.curr_offset + padding + size > len(s.data) { return nil, .Out_Of_Memory } + old_offset := s.prev_offset s.prev_offset = s.curr_offset s.curr_offset += padding next_addr := curr_addr + uintptr(padding) header := (^Stack_Allocation_Header)(next_addr - size_of(Stack_Allocation_Header)) header.padding = padding - header.prev_offset = s.prev_offset + header.prev_offset = old_offset s.curr_offset += size s.peak_used = max(s.peak_used, s.curr_offset) - return byte_slice(rawptr(next_addr), size), nil + result := byte_slice(rawptr(next_addr), size) + // ensure_poisoned(result) + // sanitizer.address_unpoison(result) + return result, nil } /* -Free memory to the stack. +Free memory back to the stack allocator. This procedure frees the memory region starting at `old_memory` to the stack. -If the freeing does is an out of order freeing, the `.Invalid_Pointer` error +If the freeing is an out of order freeing, the `.Invalid_Pointer` error is returned. */ stack_free :: proc( @@ -885,7 +982,7 @@ stack_free :: proc( loc := #caller_location, ) -> (Allocator_Error) { if s.data == nil { - panic("Stack free on an uninitialized stack allocator", loc) + panic("Free on an uninitialized Stack allocator.", loc) } if old_memory == nil { return nil @@ -894,7 +991,7 @@ stack_free :: proc( end := start + uintptr(len(s.data)) curr_addr := uintptr(old_memory) if !(start <= curr_addr && curr_addr < end) { - panic("Out of bounds memory address passed to stack allocator (free)", loc) + panic("Out of bounds memory address passed to Stack allocator. (free)", loc) } if curr_addr >= start+uintptr(s.curr_offset) { // NOTE(bill): Allow double frees @@ -902,29 +999,32 @@ stack_free :: proc( } header := (^Stack_Allocation_Header)(curr_addr - size_of(Stack_Allocation_Header)) old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data))) - if old_offset != header.prev_offset { - // panic("Out of order stack allocator free"); + if old_offset != s.prev_offset { return .Invalid_Pointer } - s.curr_offset = old_offset + s.prev_offset = header.prev_offset + // sanitizer.address_poison(s.data[old_offset:s.curr_offset]) + s.curr_offset = old_offset + return nil } /* -Free all allocations to the stack. +Free all memory back to the stack allocator. */ stack_free_all :: proc(s: ^Stack, loc := #caller_location) { s.prev_offset = 0 s.curr_offset = 0 + // sanitizer.address_poison(s.data) } /* -Resize an allocation. +Resize an allocation owned by a stack allocator. -This procedure resizes a memory region, defined by its location, `old_memory`, -and its size, `old_size` to have a size `size` and alignment `alignment`. The -newly allocated memory, if any is zero-initialized. +This procedure resizes a memory region defined by its location `old_memory` +and its size `old_size` to have a size `size` and alignment `alignment`. The +newly allocated memory, if any, is zero-initialized. If `old_memory` is `nil`, this procedure acts just like `stack_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -949,11 +1049,11 @@ stack_resize :: proc( } /* -Resize an allocation. +Resize an allocation owned by a stack allocator. -This procedure resizes a memory region, specified by the `old_data` parameter -to have a size `size` and alignment `alignment`. The newly allocated memory, -if any is zero-initialized. +This procedure resizes a memory region specified by `old_data` to have a size +`size` and alignment `alignment`. The newly allocated memory, if any, is +zero-initialized. If `old_memory` is `nil`, this procedure acts just like `stack_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -972,8 +1072,8 @@ stack_resize_bytes :: proc( alignment := DEFAULT_ALIGNMENT, loc := #caller_location, ) -> ([]byte, Allocator_Error) { - bytes, err := stack_alloc_bytes_non_zeroed(s, size, alignment, loc) - if bytes != nil { + bytes, err := stack_resize_bytes_non_zeroed(s, old_data, size, alignment, loc) + if err == nil { if old_data == nil { zero_slice(bytes) } else if size > len(old_data) { @@ -984,11 +1084,11 @@ stack_resize_bytes :: proc( } /* -Resize an allocation without zero-initialization. +Resize an allocation owned by a stack allocator, without zero-initialization. -This procedure resizes a memory region, defined by its location, `old_memory`, -and its size, `old_size` to have a size `size` and alignment `alignment`. The -newly allocated memory, if any is not explicitly zero-initialized. +This procedure resizes a memory region defined by its location `old_memory` +and its size `old_size` to have a size `size` and alignment `alignment`. The +newly allocated memory, if any, is not explicitly zero-initialized. If `old_memory` is `nil`, this procedure acts just like `stack_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -1013,11 +1113,11 @@ stack_resize_non_zeroed :: proc( } /* -Resize an allocation without zero-initialization. +Resize an allocation owned by a stack allocator, without zero-initialization. -This procedure resizes a memory region, specified by the `old_data` parameter -to have a size `size` and alignment `alignment`. The newly allocated memory, -if any is not explicitly zero-initialized. +This procedure resizes a memory region specified by `old_data` to have a size +`size` and alignment `alignment`. The newly allocated memory, if any, is not +explicitly zero-initialized. If `old_memory` is `nil`, this procedure acts just like `stack_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -1039,24 +1139,34 @@ stack_resize_bytes_non_zeroed :: proc( old_memory := raw_data(old_data) old_size := len(old_data) if s.data == nil { - panic("Stack free all on an uninitialized stack allocator", loc) + panic("Resize on an uninitialized Stack allocator.", loc) } if old_memory == nil { return stack_alloc_bytes_non_zeroed(s, size, alignment, loc) } if size == 0 { - return nil, nil + return nil, stack_free(s, old_memory, loc) } start := uintptr(raw_data(s.data)) end := start + uintptr(len(s.data)) curr_addr := uintptr(old_memory) if !(start <= curr_addr && curr_addr < end) { - panic("Out of bounds memory address passed to stack allocator (resize)") + panic("Out of bounds memory address passed to Stack allocator. (resize)") } if curr_addr >= start+uintptr(s.curr_offset) { // NOTE(bill): Allow double frees return nil, nil } + if uintptr(old_memory) & uintptr(alignment-1) != 0 { + // A different alignment has been requested and the current address + // does not satisfy it. + data, err := stack_alloc_bytes_non_zeroed(s, size, alignment, loc) + if err == nil { + runtime.copy(data, byte_slice(old_memory, old_size)) + // sanitizer.address_poison(old_memory) + } + return data, err + } if old_size == size { return byte_slice(old_memory, size), nil } @@ -1066,6 +1176,7 @@ stack_resize_bytes_non_zeroed :: proc( data, err := stack_alloc_bytes_non_zeroed(s, size, alignment, loc) if err == nil { runtime.copy(data, byte_slice(old_memory, old_size)) + // sanitizer.address_poison(old_memory) } return data, err } @@ -1075,8 +1186,13 @@ stack_resize_bytes_non_zeroed :: proc( s.curr_offset += diff // works for smaller sizes too if diff > 0 { zero(rawptr(curr_addr + uintptr(diff)), diff) + } else { + // sanitizer.address_poison(old_data[size:]) } - return byte_slice(old_memory, size), nil + result := byte_slice(old_memory, size) + // ensure_poisoned(result) + // sanitizer.address_unpoison(result) + return result, nil } stack_allocator_proc :: proc( @@ -1135,7 +1251,7 @@ Small_Stack :: struct { } /* -Initialize small stack. +Initialize a small stack allocator. This procedure initializes the small stack allocator with `data` as its backing buffer. @@ -1144,14 +1260,18 @@ small_stack_init :: proc(s: ^Small_Stack, data: []byte) { s.data = data s.offset = 0 s.peak_used = 0 + // sanitizer.address_poison(data) } /* Small stack allocator. -The small stack allocator is just like a stack allocator, with the only +The small stack allocator is just like a `Stack` allocator, with the only difference being an extremely small header size. Unlike the stack allocator, -small stack allows out-of order freeing of memory. +the small stack allows out-of order freeing of memory, with the stipulation +that all allocations made after the freed allocation will become invalidated +upon following allocations as they will begin to overwrite the memory formerly +used by the freed allocation. The memory is allocated in the backing buffer linearly, from start to end. Each subsequent allocation will get the next adjacent memory region. @@ -1169,7 +1289,7 @@ small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator { } /* -Allocate memory from small stack. +Allocate memory from a small stack allocator. This procedure allocates `size` bytes of memory aligned to a boundary specified by `alignment`. The allocated memory is zero-initialized. This procedure @@ -1187,7 +1307,7 @@ small_stack_alloc :: proc( } /* -Allocate memory from small stack. +Allocate memory from a small stack allocator. This procedure allocates `size` bytes of memory aligned to a boundary specified by `alignment`. The allocated memory is zero-initialized. This procedure @@ -1208,7 +1328,7 @@ small_stack_alloc_bytes :: proc( } /* -Allocate memory from small stack. +Allocate memory from a small stack allocator. This procedure allocates `size` bytes of memory aligned to a boundary specified by `alignment`. The allocated memory is not explicitly zero-initialized. This @@ -1226,13 +1346,13 @@ small_stack_alloc_non_zeroed :: proc( } /* -Allocate memory from small stack. +Allocate memory from a small stack allocator. This procedure allocates `size` bytes of memory aligned to a boundary specified by `alignment`. The allocated memory is not explicitly zero-initialized. This procedure returns a slice of the allocated memory region. */ -@(require_results) +@(require_results, no_sanitize_address) small_stack_alloc_bytes_non_zeroed :: proc( s: ^Small_Stack, size: int, @@ -1240,7 +1360,7 @@ small_stack_alloc_bytes_non_zeroed :: proc( loc := #caller_location, ) -> ([]byte, Allocator_Error) { if s.data == nil { - panic("Small stack is not initialized", loc) + panic("Allocation on an uninitialized Small Stack allocator.", loc) } alignment := alignment alignment = clamp(alignment, 1, 8*size_of(Stack_Allocation_Header{}.padding)/2) @@ -1252,14 +1372,21 @@ small_stack_alloc_bytes_non_zeroed :: proc( s.offset += padding next_addr := curr_addr + uintptr(padding) header := (^Small_Stack_Allocation_Header)(next_addr - size_of(Small_Stack_Allocation_Header)) - header.padding = auto_cast padding + header.padding = cast(u8)padding + // We must poison the header, no matter what its state is, because there + // may have been an out-of-order free before this point. + // sanitizer.address_poison(header) s.offset += size s.peak_used = max(s.peak_used, s.offset) - return byte_slice(rawptr(next_addr), size), nil + result := byte_slice(rawptr(next_addr), size) + // NOTE: We cannot ensure the poison state of this allocation, because this + // allocator allows out-of-order frees with overwriting. + // sanitizer.address_unpoison(result) + return result, nil } /* -Allocate memory from small stack. +Allocate memory from a small stack allocator. This procedure allocates `size` bytes of memory aligned to a boundary specified by `alignment`. The allocated memory is not explicitly zero-initialized. This @@ -1271,7 +1398,7 @@ small_stack_free :: proc( loc := #caller_location, ) -> Allocator_Error { if s.data == nil { - panic("Small stack is not initialized", loc) + panic("Free on an uninitialized Small Stack allocator.", loc) } if old_memory == nil { return nil @@ -1280,8 +1407,7 @@ small_stack_free :: proc( end := start + uintptr(len(s.data)) curr_addr := uintptr(old_memory) if !(start <= curr_addr && curr_addr < end) { - // panic("Out of bounds memory address passed to stack allocator (free)"); - return .Invalid_Pointer + panic("Out of bounds memory address passed to Small Stack allocator. (free)", loc) } if curr_addr >= start+uintptr(s.offset) { // NOTE(bill): Allow double frees @@ -1289,23 +1415,25 @@ small_stack_free :: proc( } header := (^Small_Stack_Allocation_Header)(curr_addr - size_of(Small_Stack_Allocation_Header)) old_offset := int(curr_addr - uintptr(header.padding) - uintptr(raw_data(s.data))) + // sanitizer.address_poison(s.data[old_offset:s.offset]) s.offset = old_offset return nil } /* -Free all memory to small stack. +Free all memory back to the small stack allocator. */ small_stack_free_all :: proc(s: ^Small_Stack) { s.offset = 0 + // sanitizer.address_poison(s.data) } /* -Resize an allocation. +Resize an allocation owned by a small stack allocator. -This procedure resizes a memory region, defined by its location, `old_memory`, -and its size, `old_size` to have a size `size` and alignment `alignment`. The -newly allocated memory, if any is zero-initialized. +This procedure resizes a memory region defined by its location `old_memory` +and its size `old_size` to have a size `size` and alignment `alignment`. The +newly allocated memory, if any, is zero-initialized. If `old_memory` is `nil`, this procedure acts just like `small_stack_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -1330,11 +1458,11 @@ small_stack_resize :: proc( } /* -Resize an allocation. +Resize an allocation owned by a small stack allocator. -This procedure resizes a memory region, specified by the `old_data` parameter -to have a size `size` and alignment `alignment`. The newly allocated memory, -if any is zero-initialized. +This procedure resizes a memory region specified by `old_data` to have a size +`size` and alignment `alignment`. The newly allocated memory, if any, is +zero-initialized. If `old_memory` is `nil`, this procedure acts just like `small_stack_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -1365,11 +1493,11 @@ small_stack_resize_bytes :: proc( } /* -Resize an allocation without zero-initialization. +Resize an allocation owned by a small stack allocator, without zero-initialization. -This procedure resizes a memory region, defined by its location, `old_memory`, -and its size, `old_size` to have a size `size` and alignment `alignment`. The -newly allocated memory, if any is not explicitly zero-initialized. +This procedure resizes a memory region defined by its location `old_memory` +and its size `old_size` to have a size `size` and alignment `alignment`. The +newly allocated memory, if any, is not explicitly zero-initialized. If `old_memory` is `nil`, this procedure acts just like `small_stack_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -1394,11 +1522,11 @@ small_stack_resize_non_zeroed :: proc( } /* -Resize an allocation without zero-initialization. +Resize an allocation owned by a small stack allocator, without zero-initialization. -This procedure resizes a memory region, specified by the `old_data` parameter -to have a size `size` and alignment `alignment`. The newly allocated memory, -if any is not explicitly zero-initialized. +This procedure resizes a memory region specified by `old_data` to have a size +`size` and alignment `alignment`. The newly allocated memory, if any, is not +explicitly zero-initialized. If `old_memory` is `nil`, this procedure acts just like `small_stack_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified @@ -1418,7 +1546,7 @@ small_stack_resize_bytes_non_zeroed :: proc( loc := #caller_location, ) -> ([]byte, Allocator_Error) { if s.data == nil { - panic("Small stack is not initialized", loc) + panic("Resize on an uninitialized Small Stack allocator.", loc) } old_memory := raw_data(old_data) old_size := len(old_data) @@ -1428,21 +1556,32 @@ small_stack_resize_bytes_non_zeroed :: proc( return small_stack_alloc_bytes_non_zeroed(s, size, alignment, loc) } if size == 0 { - return nil, nil + return nil, small_stack_free(s, old_memory, loc) } start := uintptr(raw_data(s.data)) end := start + uintptr(len(s.data)) curr_addr := uintptr(old_memory) if !(start <= curr_addr && curr_addr < end) { - // panic("Out of bounds memory address passed to stack allocator (resize)"); - return nil, .Invalid_Pointer + panic("Out of bounds memory address passed to Small Stack allocator. (resize)", loc) } if curr_addr >= start+uintptr(s.offset) { // NOTE(bill): Treat as a double free return nil, nil } + if uintptr(old_memory) & uintptr(alignment-1) != 0 { + // A different alignment has been requested and the current address + // does not satisfy it. + data, err := small_stack_alloc_bytes_non_zeroed(s, size, alignment, loc) + if err == nil { + runtime.copy(data, byte_slice(old_memory, old_size)) + // sanitizer.address_poison(old_memory) + } + return data, err + } if old_size == size { - return byte_slice(old_memory, size), nil + result := byte_slice(old_memory, size) + // sanitizer.address_unpoison(result) + return result, nil } data, err := small_stack_alloc_bytes_non_zeroed(s, size, alignment, loc) if err == nil { @@ -1559,18 +1698,18 @@ dynamic_arena_init :: proc( Dynamic arena allocator. The dynamic arena allocator uses blocks of a specific size, allocated on-demand -using the block allocator. This allocator acts similarly to arena. All +using the block allocator. This allocator acts similarly to `Arena`. All allocations in a block happen contiguously, from start to end. If an allocation -does not fit into the remaining space of the block, and its size is smaller +does not fit into the remaining space of the block and its size is smaller than the specified out-band size, a new block is allocated using the `block_allocator` and the allocation is performed from a newly-allocated block. -If an allocation has bigger size than the specified out-band size, a new block +If an allocation is larger than the specified out-band size, a new block is allocated such that the allocation fits into this new block. This is referred to as an *out-band allocation*. The out-band blocks are kept separately from normal blocks. -Just like arena, the dynamic arena does not support freeing of individual +Just like `Arena`, the dynamic arena does not support freeing of individual objects. */ @(require_results) @@ -1584,7 +1723,7 @@ dynamic_arena_allocator :: proc(a: ^Dynamic_Arena) -> Allocator { /* Destroy a dynamic arena. -This procedure frees all allocations, made on a dynamic arena, including the +This procedure frees all allocations made on a dynamic arena, including the unused blocks, as well as the arrays for storing blocks. */ dynamic_arena_destroy :: proc(a: ^Dynamic_Arena) { @@ -1598,7 +1737,7 @@ dynamic_arena_destroy :: proc(a: ^Dynamic_Arena) { @(private="file") _dynamic_arena_cycle_new_block :: proc(a: ^Dynamic_Arena, loc := #caller_location) -> (err: Allocator_Error) { if a.block_allocator.procedure == nil { - panic("You must call arena_init on a Pool before using it", loc) + panic("You must call `dynamic_arena_init` on a Dynamic Arena before using it.", loc) } if a.current_block != nil { append(&a.used_blocks, a.current_block, loc=loc) @@ -1616,6 +1755,7 @@ _dynamic_arena_cycle_new_block :: proc(a: ^Dynamic_Arena, loc := #caller_locatio nil, 0, ) + // sanitizer.address_poison(data) new_block = raw_data(data) } a.bytes_left = a.block_size @@ -1632,7 +1772,7 @@ by `alignment` from a dynamic arena `a`. The allocated memory is zero-initialized. This procedure returns a pointer to the newly allocated memory region. */ -@(private, require_results) +@(require_results) dynamic_arena_alloc :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> (rawptr, Allocator_Error) { data, err := dynamic_arena_alloc_bytes(a, size, loc) return raw_data(data), err @@ -1679,18 +1819,18 @@ memory region. */ @(require_results) dynamic_arena_alloc_bytes_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> ([]byte, Allocator_Error) { - n := align_formula(size, a.alignment) - if n > a.block_size { - return nil, .Invalid_Argument - } - if n >= a.out_band_size { - assert(a.block_allocator.procedure != nil, "Backing block allocator must be initialized", loc=loc) - memory, err := alloc_bytes_non_zeroed(a.block_size, a.alignment, a.block_allocator, loc) + if size >= a.out_band_size { + assert(a.out_band_allocations.allocator.procedure != nil, "Backing array allocator must be initialized", loc=loc) + memory, err := alloc_bytes_non_zeroed(size, a.alignment, a.out_band_allocations.allocator, loc) if memory != nil { append(&a.out_band_allocations, raw_data(memory), loc = loc) } return memory, err } + n := align_formula(size, a.alignment) + if n > a.block_size { + return nil, .Invalid_Argument + } if a.bytes_left < n { err := _dynamic_arena_cycle_new_block(a, loc) if err != nil { @@ -1703,59 +1843,62 @@ dynamic_arena_alloc_bytes_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, loc : memory := a.current_pos a.current_pos = ([^]byte)(a.current_pos)[n:] a.bytes_left -= n - return ([^]byte)(memory)[:size], nil + result := ([^]byte)(memory)[:size] + // ensure_poisoned(result) + // sanitizer.address_unpoison(result) + return result, nil } /* -Reset the dynamic arena. +Reset a dynamic arena allocator. -This procedure frees all the allocations, owned by the dynamic arena, excluding +This procedure frees all the allocations owned by the dynamic arena, excluding the unused blocks. */ dynamic_arena_reset :: proc(a: ^Dynamic_Arena, loc := #caller_location) { if a.current_block != nil { + // sanitizer.address_poison(a.current_block, a.block_size) append(&a.unused_blocks, a.current_block, loc=loc) a.current_block = nil } for block in a.used_blocks { + // sanitizer.address_poison(block, a.block_size) append(&a.unused_blocks, block, loc=loc) } clear(&a.used_blocks) for allocation in a.out_band_allocations { - free(allocation, a.block_allocator, loc=loc) + free(allocation, a.out_band_allocations.allocator, loc=loc) } clear(&a.out_band_allocations) a.bytes_left = 0 // Make new allocations call `_dynamic_arena_cycle_new_block` again. } /* -Free all memory from a dynamic arena. +Free all memory back to the dynamic arena allocator. -This procedure frees all the allocations, owned by the dynamic arena, including +This procedure frees all the allocations owned by the dynamic arena, including the unused blocks. */ dynamic_arena_free_all :: proc(a: ^Dynamic_Arena, loc := #caller_location) { dynamic_arena_reset(a) for block in a.unused_blocks { + // sanitizer.address_unpoison(block, a.block_size) free(block, a.block_allocator, loc) } clear(&a.unused_blocks) } /* -Resize an allocation. +Resize an allocation owned by a dynamic arena allocator. -This procedure resizes a memory region, defined by its location, `old_memory`, -and its size, `old_size` to have a size `size` and alignment `alignment`. The -newly allocated memory, if any is zero-initialized. +This procedure resizes a memory region defined by its location `old_memory` +and its size `old_size` to have a size `size` and alignment `alignment`. The +newly allocated memory, if any, is zero-initialized. If `old_memory` is `nil`, this procedure acts just like `dynamic_arena_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified by `alignment`. -If `size` is 0, this procedure acts just like `dynamic_arena_free()`, freeing -the memory region located at an address specified by `old_memory`. - This procedure returns the pointer to the resized memory region. */ @(require_results) @@ -1771,19 +1914,16 @@ dynamic_arena_resize :: proc( } /* -Resize an allocation. +Resize an allocation owned by a dynamic arena allocator. -This procedure resizes a memory region, specified by `old_data`, to have a size -`size` and alignment `alignment`. The newly allocated memory, if any is +This procedure resizes a memory region specified by `old_data` to have a size +`size` and alignment `alignment`. The newly allocated memory, if any, is zero-initialized. If `old_memory` is `nil`, this procedure acts just like `dynamic_arena_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified by `alignment`. -If `size` is 0, this procedure acts just like `dynamic_arena_free()`, freeing the -memory region located at an address specified by `old_memory`. - This procedure returns the slice of the resized memory region. */ @(require_results) @@ -1793,6 +1933,10 @@ dynamic_arena_resize_bytes :: proc( size: int, loc := #caller_location, ) -> ([]byte, Allocator_Error) { + if size == 0 { + // NOTE: This allocator has no Free mode. + return nil, nil + } bytes, err := dynamic_arena_resize_bytes_non_zeroed(a, old_data, size, loc) if bytes != nil { if old_data == nil { @@ -1805,19 +1949,16 @@ dynamic_arena_resize_bytes :: proc( } /* -Resize an allocation without zero-initialization. +Resize an allocation owned by a dynamic arena allocator, without zero-initialization. -This procedure resizes a memory region, defined by its location, `old_memory`, -and its size, `old_size` to have a size `size` and alignment `alignment`. The -newly allocated memory, if any is not explicitly zero-initialized. +This procedure resizes a memory region defined by its location `old_memory` +and its size `old_size` to have a size `size` and alignment `alignment`. The +newly allocated memory, if any, is not explicitly zero-initialized. If `old_memory` is `nil`, this procedure acts just like `dynamic_arena_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified by `alignment`. -If `size` is 0, this procedure acts just like `dynamic_arena_free()`, freeing the -memory region located at an address specified by `old_memory`. - This procedure returns the pointer to the resized memory region. */ @(require_results) @@ -1833,19 +1974,16 @@ dynamic_arena_resize_non_zeroed :: proc( } /* -Resize an allocation. +Resize an allocation owned by a dynamic arena allocator, without zero-initialization. -This procedure resizes a memory region, specified by `old_data`, to have a size -`size` and alignment `alignment`. The newly allocated memory, if any is not +This procedure resizes a memory region specified by `old_data` to have a size +`size` and alignment `alignment`. The newly allocated memory, if any, is not explicitly zero-initialized. If `old_memory` is `nil`, this procedure acts just like `dynamic_arena_alloc()`, allocating a memory region `size` bytes in size, aligned on a boundary specified by `alignment`. -If `size` is 0, this procedure acts just like `dynamic_arena_free()`, freeing -the memory region located at an address specified by `old_memory`. - This procedure returns the slice of the resized memory region. */ @(require_results) @@ -1855,11 +1993,18 @@ dynamic_arena_resize_bytes_non_zeroed :: proc( size: int, loc := #caller_location, ) -> ([]byte, Allocator_Error) { + if size == 0 { + // NOTE: This allocator has no Free mode. + return nil, nil + } old_memory := raw_data(old_data) old_size := len(old_data) if old_size >= size { + // sanitizer.address_poison(old_data[size:]) return byte_slice(old_memory, size), nil } + // No information is kept about allocations in this allocator, thus we + // cannot truly resize anything and must reallocate. data, err := dynamic_arena_alloc_bytes_non_zeroed(a, size, loc) if err == nil { runtime.copy(data, byte_slice(old_memory, old_size)) @@ -1920,7 +2065,7 @@ Buddy_Block :: struct #align(align_of(uint)) { /* Obtain the next buddy block. */ -@(require_results) +@(require_results, no_sanitize_address) buddy_block_next :: proc(block: ^Buddy_Block) -> ^Buddy_Block { return (^Buddy_Block)(([^]byte)(block)[block.size:]) } @@ -1928,7 +2073,7 @@ buddy_block_next :: proc(block: ^Buddy_Block) -> ^Buddy_Block { /* Split the block into two, by truncating the given block to a given size. */ -@(require_results) +@(require_results, no_sanitize_address) buddy_block_split :: proc(block: ^Buddy_Block, size: uint) -> ^Buddy_Block { block := block if block != nil && size != 0 { @@ -1951,6 +2096,7 @@ buddy_block_split :: proc(block: ^Buddy_Block, size: uint) -> ^Buddy_Block { /* Coalesce contiguous blocks in a range of blocks into one. */ +@(no_sanitize_address) buddy_block_coalescence :: proc(head, tail: ^Buddy_Block) { for { // Keep looping until there are no more buddies to coalesce @@ -1987,7 +2133,7 @@ buddy_block_coalescence :: proc(head, tail: ^Buddy_Block) { /* Find the best block for storing a given size in a range of blocks. */ -@(require_results) +@(require_results, no_sanitize_address) buddy_block_find_best :: proc(head, tail: ^Buddy_Block, size: uint) -> ^Buddy_Block { assert(size != 0) best_block: ^Buddy_Block @@ -2050,7 +2196,7 @@ The buddy allocator data. */ Buddy_Allocator :: struct { head: ^Buddy_Block, - tail: ^Buddy_Block, + tail: ^Buddy_Block `fmt:"-"`, alignment: uint, } @@ -2073,10 +2219,13 @@ buddy_allocator :: proc(b: ^Buddy_Allocator) -> Allocator { } /* -Initialize the buddy allocator. +Initialize a buddy allocator. This procedure initializes the buddy allocator `b` with a backing buffer `data` and block alignment specified by `alignment`. + +`alignment` may be any power of two, but the backing buffer must be aligned to +at least `size_of(Buddy_Block)`. */ buddy_allocator_init :: proc(b: ^Buddy_Allocator, data: []byte, alignment: uint, loc := #caller_location) { assert(data != nil) @@ -2087,12 +2236,14 @@ buddy_allocator_init :: proc(b: ^Buddy_Allocator, data: []byte, alignment: uint, alignment = size_of(Buddy_Block) } ptr := raw_data(data) - assert(uintptr(ptr) % uintptr(alignment) == 0, "data is not aligned to minimum alignment", loc) + assert(uintptr(ptr) % uintptr(alignment) == 0, "The data is not aligned to the minimum alignment, which must be at least `size_of(Buddy_Block)`.", loc) b.head = (^Buddy_Block)(ptr) b.head.size = len(data) b.head.is_free = true b.tail = buddy_block_next(b.head) b.alignment = alignment + assert(uint(len(data)) >= 2 * buddy_block_size_required(b, 1), "The size of the backing buffer must be large enough to hold at least two 1-byte allocations given the alignment requirements, otherwise it cannot split.", loc) + // sanitizer.address_poison(data) } /* @@ -2100,12 +2251,14 @@ Get required block size to fit in the allocation as well as the alignment paddin */ @(require_results) buddy_block_size_required :: proc(b: ^Buddy_Allocator, size: uint) -> uint { - size := size - actual_size := b.alignment - size += size_of(Buddy_Block) - size = align_forward_uint(size, b.alignment) - for size > actual_size { - actual_size <<= 1 + assert(size > 0) + // NOTE: `size_of(Buddy_Block)` will be accounted for in `b.alignment`. + // This calculation is also previously guarded against being given a `size` + // 0 by `buddy_allocator_alloc_bytes_non_zeroed` checking for that. + actual_size := b.alignment + size + if intrinsics.count_ones(actual_size) != 1 { + // We're not a power of two. Let's fix that. + actual_size = 1 << (size_of(uint) * 8 - intrinsics.count_leading_zeros(actual_size)) } return actual_size } @@ -2113,11 +2266,12 @@ buddy_block_size_required :: proc(b: ^Buddy_Allocator, size: uint) -> uint { /* Allocate memory from a buddy allocator. -This procedure allocates `size` bytes of memory aligned on a boundary specified -by `alignment`. The allocated memory region is zero-initialized. This procedure -returns a pointer to the allocated memory region. +This procedure allocates `size` bytes of memory. The allocation's alignment is +fixed to the `alignment` specified at initialization. The allocated memory +region is zero-initialized. This procedure returns a pointer to the allocated +memory region. */ -@(require_results) +@(require_results, no_sanitize_address) buddy_allocator_alloc :: proc(b: ^Buddy_Allocator, size: uint) -> (rawptr, Allocator_Error) { bytes, err := buddy_allocator_alloc_bytes(b, size) return raw_data(bytes), err @@ -2126,11 +2280,12 @@ buddy_allocator_alloc :: proc(b: ^Buddy_Allocator, size: uint) -> (rawptr, Alloc /* Allocate memory from a buddy allocator. -This procedure allocates `size` bytes of memory aligned on a boundary specified -by `alignment`. The allocated memory region is zero-initialized. This procedure -returns a slice of the allocated memory region. +This procedure allocates `size` bytes of memory. The allocation's alignment is +fixed to the `alignment` specified at initialization. The allocated memory +region is zero-initialized. This procedure returns a slice of the allocated +memory region. */ -@(require_results) +@(require_results, no_sanitize_address) buddy_allocator_alloc_bytes :: proc(b: ^Buddy_Allocator, size: uint) -> ([]byte, Allocator_Error) { bytes, err := buddy_allocator_alloc_bytes_non_zeroed(b, size) if bytes != nil { @@ -2142,11 +2297,12 @@ buddy_allocator_alloc_bytes :: proc(b: ^Buddy_Allocator, size: uint) -> ([]byte, /* Allocate non-initialized memory from a buddy allocator. -This procedure allocates `size` bytes of memory aligned on a boundary specified -by `alignment`. The allocated memory region is not explicitly zero-initialized. -This procedure returns a pointer to the allocated memory region. +This procedure allocates `size` bytes of memory. The allocation's alignment is +fixed to the `alignment` specified at initialization. The allocated memory +region is not explicitly zero-initialized. This procedure returns a pointer to +the allocated memory region. */ -@(require_results) +@(require_results, no_sanitize_address) buddy_allocator_alloc_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint) -> (rawptr, Allocator_Error) { bytes, err := buddy_allocator_alloc_bytes_non_zeroed(b, size) return raw_data(bytes), err @@ -2155,16 +2311,17 @@ buddy_allocator_alloc_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint) -> (ra /* Allocate non-initialized memory from a buddy allocator. -This procedure allocates `size` bytes of memory aligned on a boundary specified -by `alignment`. The allocated memory region is not explicitly zero-initialized. -This procedure returns a slice of the allocated memory region. +This procedure allocates `size` bytes of memory. The allocation's alignment is +fixed to the `alignment` specified at initialization. The allocated memory +region is not explicitly zero-initialized. This procedure returns a slice of +the allocated memory region. */ -@(require_results) +@(require_results, no_sanitize_address) buddy_allocator_alloc_bytes_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint) -> ([]byte, Allocator_Error) { if size != 0 { actual_size := buddy_block_size_required(b, size) found := buddy_block_find_best(b.head, b.tail, actual_size) - if found != nil { + if found == nil { // Try to coalesce all the free buddy blocks and then search again buddy_block_coalescence(b.head, b.tail) found = buddy_block_find_best(b.head, b.tail, actual_size) @@ -2174,25 +2331,30 @@ buddy_allocator_alloc_bytes_non_zeroed :: proc(b: ^Buddy_Allocator, size: uint) } found.is_free = false data := ([^]byte)(found)[b.alignment:][:size] + assert(cast(uintptr)raw_data(data)+cast(uintptr)(size-1) < cast(uintptr)buddy_block_next(found), "Buddy_Allocator has made an allocation which overlaps a block header.") + // ensure_poisoned(data) + // sanitizer.address_unpoison(data) return data, nil } return nil, nil } /* -Free memory to the buddy allocator. +Free memory back to the buddy allocator. This procedure frees the memory region allocated at pointer `ptr`. If `ptr` is not the latest allocation and is not a leaked allocation, this operation is a no-op. */ +@(no_sanitize_address) buddy_allocator_free :: proc(b: ^Buddy_Allocator, ptr: rawptr) -> Allocator_Error { if ptr != nil { if !(b.head <= ptr && ptr <= b.tail) { return .Invalid_Pointer } block := (^Buddy_Block)(([^]byte)(ptr)[-b.alignment:]) + // sanitizer.address_poison(ptr, block.size) block.is_free = true buddy_block_coalescence(b.head, b.tail) } @@ -2200,16 +2362,18 @@ buddy_allocator_free :: proc(b: ^Buddy_Allocator, ptr: rawptr) -> Allocator_Erro } /* -Free all memory to the buddy allocator. +Free all memory back to the buddy allocator. */ +@(no_sanitize_address) buddy_allocator_free_all :: proc(b: ^Buddy_Allocator) { alignment := b.alignment head := ([^]byte)(b.head) tail := ([^]byte)(b.tail) data := head[:ptr_sub(tail, head)] - buddy_allocator_init(b, data, alignment) + buddy_allocator_init(b, data, alignment) } +@(no_sanitize_address) buddy_allocator_proc :: proc( allocator_data: rawptr, mode: Allocator_Mode, @@ -2263,7 +2427,7 @@ buddy_allocator_proc :: proc( // on the old size to work. // // The overhead of this allocator is an extra max(alignment, size_of(Header)) bytes allocated for each allocation, these bytes are -// used to store the size and original pointer. +// used to store the size and alignment. Compat_Allocator :: struct { parent: Allocator, } @@ -2272,6 +2436,7 @@ compat_allocator_init :: proc(rra: ^Compat_Allocator, allocator := context.alloc rra.parent = allocator } +@(require_results) compat_allocator :: proc(rra: ^Compat_Allocator) -> Allocator { return Allocator{ data = rra, @@ -2283,51 +2448,87 @@ compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, location := #caller_location) -> (data: []byte, err: Allocator_Error) { - size, old_size := size, old_size - Header :: struct { - size: int, - ptr: rawptr, + size: int, + alignment: int, + } + + @(no_sanitize_address) + get_unpoisoned_header :: #force_inline proc(ptr: rawptr) -> Header { + header := ([^]Header)(ptr)[-1] + // a := max(header.alignment, size_of(Header)) + // sanitizer.address_unpoison(rawptr(uintptr(ptr)-uintptr(a)), a) + return header } rra := (^Compat_Allocator)(allocator_data) switch mode { case .Alloc, .Alloc_Non_Zeroed: - a := max(alignment, size_of(Header)) - size += a - assert(size >= 0, "overflow") + a := max(alignment, size_of(Header)) + req_size := size + a + assert(req_size >= 0, "overflow") - allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) or_return + allocation := rra.parent.procedure(rra.parent.data, mode, req_size, alignment, old_memory, old_size, location) or_return #no_bounds_check data = allocation[a:] ([^]Header)(raw_data(data))[-1] = { - size = size, - ptr = raw_data(allocation), + size = size, + alignment = alignment, } + + // sanitizer.address_poison(raw_data(allocation), a) return case .Free: - header := ([^]Header)(old_memory)[-1] - return rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location) + header := get_unpoisoned_header(old_memory) + a := max(header.alignment, size_of(Header)) + orig_ptr := rawptr(uintptr(old_memory)-uintptr(a)) + orig_size := header.size + a + + return rra.parent.procedure(rra.parent.data, mode, orig_size, header.alignment, orig_ptr, orig_size, location) case .Resize, .Resize_Non_Zeroed: - header := ([^]Header)(old_memory)[-1] + header := get_unpoisoned_header(old_memory) + orig_a := max(header.alignment, size_of(Header)) + orig_ptr := rawptr(uintptr(old_memory)-uintptr(orig_a)) + orig_size := header.size + orig_a - a := max(alignment, size_of(header)) - size += a + new_alignment := max(header.alignment, alignment) + + a := max(new_alignment, size_of(header)) + req_size := size + a assert(size >= 0, "overflow") - allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location) or_return + allocation := rra.parent.procedure(rra.parent.data, mode, req_size, new_alignment, orig_ptr, orig_size, location) or_return #no_bounds_check data = allocation[a:] ([^]Header)(raw_data(data))[-1] = { - size = size, - ptr = raw_data(allocation), + size = size, + alignment = new_alignment, + } + + // sanitizer.address_poison(raw_data(allocation), a) + return + + case .Free_All: + return rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) + + case .Query_Info: + info := (^Allocator_Query_Info)(old_memory) + if info != nil && info.pointer != nil { + header := get_unpoisoned_header(info.pointer) + info.size = header.size + info.alignment = header.alignment } return - case .Free_All, .Query_Info, .Query_Features: - return rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) + case .Query_Features: + data, err = rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) + if err != nil { + set := (^Allocator_Mode_Set)(old_memory) + set^ += {.Query_Info} + } + return case: unreachable() } diff --git a/core/mem/mem.odin b/core/mem/mem.odin index b2a7158a1..96ec1990a 100644 --- a/core/mem/mem.odin +++ b/core/mem/mem.odin @@ -171,16 +171,15 @@ If the return value is: The comparison is performed as follows: 1. Each byte, upto `min(len(a), len(b))` bytes is compared between `a` and `b`. - - If the byte in slice `a` is smaller than a byte in slice `b`, then comparison - stops and this procedure returns `-1`. - - If the byte in slice `a` is bigger than a byte in slice `b`, then comparison - stops and this procedure returns `+1`. - - Otherwise the comparison continues until `min(len(a), len(b))` are compared. -2. If all the bytes in the range are equal, then the lengths of the slices are - compared. - - If the length of slice `a` is smaller than the length of slice `b`, then `-1` is returned. - - If the length of slice `b` is smaller than the length of slice `b`, then `+1` is returned. - - Otherwise `0` is returned. + - If the byte in slice `a` is smaller than a byte in slice `b`, then comparison + stops and this procedure returns `-1`. + - If the byte in slice `a` is bigger than a byte in slice `b`, then comparison + stops and this procedure returns `+1`. + - Otherwise the comparison continues until `min(len(a), len(b))` are compared. +2. If all the bytes in the range are equal, then the lengths of the slices are compared. + - If the length of slice `a` is smaller than the length of slice `b`, then `-1` is returned. + - If the length of slice `b` is smaller than the length of slice `b`, then `+1` is returned. + - Otherwise `0` is returned. */ @(require_results) compare :: proc "contextless" (a, b: []byte) -> int { @@ -207,11 +206,11 @@ If the return value is: The comparison is performed as follows: 1. Each byte, upto `n` bytes is compared between `a` and `b`. - - If the byte in `a` is smaller than a byte in `b`, then comparison stops - and this procedure returns `-1`. - - If the byte in `a` is bigger than a byte in `b`, then comparison stops - and this procedure returns `+1`. - - Otherwise the comparison continues until `n` bytes are compared. + - If the byte in `a` is smaller than a byte in `b`, then comparison stops + and this procedure returns `-1`. + - If the byte in `a` is bigger than a byte in `b`, then comparison stops + and this procedure returns `+1`. + - Otherwise the comparison continues until `n` bytes are compared. 2. If all the bytes in the range are equal, this procedure returns `0`. */ @(require_results) @@ -233,11 +232,11 @@ If the return value is: The comparison is performed as follows: 1. Each byte, upto `n` bytes is compared between `a` and `b`. - - If the byte in `a` is smaller than a byte in `b`, then comparison stops - and this procedure returns `-1`. - - If the byte in `a` is bigger than a byte in `b`, then comparison stops - and this procedure returns `+1`. - - Otherwise the comparison continues until `n` bytes are compared. + - If the byte in `a` is smaller than a byte in `b`, then comparison stops + and this procedure returns `-1`. + - If the byte in `a` is bigger than a byte in `b`, then comparison stops + and this procedure returns `+1`. + - Otherwise the comparison continues until `n` bytes are compared. 2. If all the bytes in the range are equal, this procedure returns `0`. */ @(require_results) @@ -316,18 +315,38 @@ check_zero_ptr :: proc(ptr: rawptr, len: int) -> bool { Offset a given pointer by a given amount. This procedure offsets the pointer `ptr` to an object of type `T`, by the amount -of bytes specified by `offset*size_of(T)`, and returns the pointer `ptr`. +of bytes specified by `offset * size_of(T)`, and returns the pointer `ptr`. **Note**: Prefer to use multipointer types, if possible. */ ptr_offset :: intrinsics.ptr_offset /* -Offset a given pointer by a given amount backwards. +Subtract two pointers of the same type, and return the number of `T` between them. -This procedure offsets the pointer `ptr` to an object of type `T`, by the amount -of bytes specified by `offset*size_of(T)` in the negative direction, and -returns the pointer `ptr`. +This procedure subtracts pointer `b` from pointer `a`, both of type `^T`, +and returns an integer count of the `T` between them. + +**Inputs** +- `a`: A pointer to a type T +- `b`: A pointer to a type T + +**Returns** +- `b` - `a` in items of T as an `int`. + +Example: + + import "core:mem" + import "core:fmt" + + ptr_sub_example :: proc() { + arr: [2]int + fmt.println(mem.ptr_sub(&arr[1], &arr[0])) + } + +Output: + + 1 */ ptr_sub :: intrinsics.ptr_sub diff --git a/core/mem/rollback_stack_allocator.odin b/core/mem/rollback_stack_allocator.odin index 43ef10fe9..3f16a2897 100644 --- a/core/mem/rollback_stack_allocator.odin +++ b/core/mem/rollback_stack_allocator.odin @@ -1,6 +1,7 @@ package mem import "base:runtime" +// import "base:sanitizer" /* Rollback stack default block size. @@ -47,14 +48,14 @@ Rollback_Stack :: struct { block_allocator: Allocator, } -@(private="file", require_results) +@(private="file", require_results, no_sanitize_address) rb_ptr_in_bounds :: proc(block: ^Rollback_Stack_Block, ptr: rawptr) -> bool { start := raw_data(block.buffer) end := start[block.offset:] return start < ptr && ptr <= end } -@(private="file", require_results) +@(private="file", require_results, no_sanitize_address) rb_find_ptr :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> ( parent: ^Rollback_Stack_Block, block: ^Rollback_Stack_Block, @@ -71,7 +72,7 @@ rb_find_ptr :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> ( return nil, nil, nil, .Invalid_Pointer } -@(private="file", require_results) +@(private="file", require_results, no_sanitize_address) rb_find_last_alloc :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> ( block: ^Rollback_Stack_Block, header: ^Rollback_Stack_Header, @@ -86,9 +87,10 @@ rb_find_last_alloc :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> ( return nil, nil, false } -@(private="file") +@(private="file", no_sanitize_address) rb_rollback_block :: proc(block: ^Rollback_Stack_Block, header: ^Rollback_Stack_Header) { header := header + for block.offset > 0 && header.is_free { block.offset = header.prev_offset block.last_alloc = raw_data(block.buffer)[header.prev_ptr:] @@ -99,9 +101,10 @@ rb_rollback_block :: proc(block: ^Rollback_Stack_Block, header: ^Rollback_Stack_ /* Free memory to a rollback stack allocator. */ -@(private="file", require_results) +@(private="file", require_results, no_sanitize_address) rb_free :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> Allocator_Error { parent, block, header := rb_find_ptr(stack, ptr) or_return + if header.is_free { return .Invalid_Pointer } @@ -120,7 +123,7 @@ rb_free :: proc(stack: ^Rollback_Stack, ptr: rawptr) -> Allocator_Error { /* Free all memory owned by the rollback stack allocator. */ -@(private="file") +@(private="file", no_sanitize_address) rb_free_all :: proc(stack: ^Rollback_Stack) { for block := stack.head.next_block; block != nil; /**/ { next_block := block.next_block @@ -131,12 +134,13 @@ rb_free_all :: proc(stack: ^Rollback_Stack) { stack.head.next_block = nil stack.head.last_alloc = nil stack.head.offset = 0 + // sanitizer.address_poison(stack.head.buffer) } /* Allocate memory using the rollback stack allocator. */ -@(require_results) +@(require_results, no_sanitize_address) rb_alloc :: proc( stack: ^Rollback_Stack, size: int, @@ -153,7 +157,7 @@ rb_alloc :: proc( /* Allocate memory using the rollback stack allocator. */ -@(require_results) +@(require_results, no_sanitize_address) rb_alloc_bytes :: proc( stack: ^Rollback_Stack, size: int, @@ -170,7 +174,7 @@ rb_alloc_bytes :: proc( /* Allocate non-initialized memory using the rollback stack allocator. */ -@(require_results) +@(require_results, no_sanitize_address) rb_alloc_non_zeroed :: proc( stack: ^Rollback_Stack, size: int, @@ -184,7 +188,7 @@ rb_alloc_non_zeroed :: proc( /* Allocate non-initialized memory using the rollback stack allocator. */ -@(require_results) +@(require_results, no_sanitize_address) rb_alloc_bytes_non_zeroed :: proc( stack: ^Rollback_Stack, size: int, @@ -194,6 +198,7 @@ rb_alloc_bytes_non_zeroed :: proc( assert(size >= 0, "Size must be positive or zero.", loc) assert(is_power_of_two(cast(uintptr)alignment), "Alignment must be a power of two.", loc) parent: ^Rollback_Stack_Block + for block := stack.head; /**/; block = block.next_block { when !ODIN_DISABLE_ASSERT { allocated_new_block: bool @@ -235,7 +240,9 @@ rb_alloc_bytes_non_zeroed :: proc( // Prevent any further allocations on it. block.offset = cast(uintptr)len(block.buffer) } - #no_bounds_check return ptr[:size], nil + res := ptr[:size] + // sanitizer.address_unpoison(res) + return res, nil } return nil, .Out_Of_Memory } @@ -243,7 +250,7 @@ rb_alloc_bytes_non_zeroed :: proc( /* Resize an allocation owned by rollback stack allocator. */ -@(require_results) +@(require_results, no_sanitize_address) rb_resize :: proc( stack: ^Rollback_Stack, old_ptr: rawptr, @@ -266,7 +273,7 @@ rb_resize :: proc( /* Resize an allocation owned by rollback stack allocator. */ -@(require_results) +@(require_results, no_sanitize_address) rb_resize_bytes :: proc( stack: ^Rollback_Stack, old_memory: []byte, @@ -289,7 +296,7 @@ rb_resize_bytes :: proc( Resize an allocation owned by rollback stack allocator without explicit zero-initialization. */ -@(require_results) +@(require_results, no_sanitize_address) rb_resize_non_zeroed :: proc( stack: ^Rollback_Stack, old_ptr: rawptr, @@ -306,7 +313,7 @@ rb_resize_non_zeroed :: proc( Resize an allocation owned by rollback stack allocator without explicit zero-initialization. */ -@(require_results) +@(require_results, no_sanitize_address) rb_resize_bytes_non_zeroed :: proc( stack: ^Rollback_Stack, old_memory: []byte, @@ -330,7 +337,9 @@ rb_resize_bytes_non_zeroed :: proc( if len(block.buffer) <= stack.block_size { block.offset += cast(uintptr)size - cast(uintptr)old_size } - #no_bounds_check return (ptr)[:size], nil + res := (ptr)[:size] + // sanitizer.address_unpoison(res) + #no_bounds_check return res, nil } } } @@ -340,7 +349,7 @@ rb_resize_bytes_non_zeroed :: proc( return } -@(private="file", require_results) +@(private="file", require_results, no_sanitize_address) rb_make_block :: proc(size: int, allocator: Allocator) -> (block: ^Rollback_Stack_Block, err: Allocator_Error) { buffer := runtime.mem_alloc(size_of(Rollback_Stack_Block) + size, align_of(Rollback_Stack_Block), allocator) or_return block = cast(^Rollback_Stack_Block)raw_data(buffer) @@ -351,6 +360,7 @@ rb_make_block :: proc(size: int, allocator: Allocator) -> (block: ^Rollback_Stac /* Initialize the rollback stack allocator using a fixed backing buffer. */ +@(no_sanitize_address) rollback_stack_init_buffered :: proc(stack: ^Rollback_Stack, buffer: []byte, location := #caller_location) { MIN_SIZE :: size_of(Rollback_Stack_Block) + size_of(Rollback_Stack_Header) + size_of(rawptr) assert(len(buffer) >= MIN_SIZE, "User-provided buffer to Rollback Stack Allocator is too small.", location) @@ -365,6 +375,7 @@ rollback_stack_init_buffered :: proc(stack: ^Rollback_Stack, buffer: []byte, loc /* Initialize the rollback stack alocator using a backing block allocator. */ +@(no_sanitize_address) rollback_stack_init_dynamic :: proc( stack: ^Rollback_Stack, block_size : int = ROLLBACK_STACK_DEFAULT_BLOCK_SIZE, @@ -396,6 +407,7 @@ rollback_stack_init :: proc { /* Destroy a rollback stack. */ +@(no_sanitize_address) rollback_stack_destroy :: proc(stack: ^Rollback_Stack) { if stack.block_allocator.procedure != nil { rb_free_all(stack) @@ -435,7 +447,7 @@ from the last allocation backwards. Each allocation has an overhead of 8 bytes and any extra bytes to satisfy the requested alignment. */ -@(require_results) +@(require_results, no_sanitize_address) rollback_stack_allocator :: proc(stack: ^Rollback_Stack) -> Allocator { return Allocator { data = stack, @@ -443,7 +455,7 @@ rollback_stack_allocator :: proc(stack: ^Rollback_Stack) -> Allocator { } } -@(require_results) +@(require_results, no_sanitize_address) rollback_stack_allocator_proc :: proc( allocator_data: rawptr, mode: Allocator_Mode, diff --git a/core/mem/tlsf/tlsf.odin b/core/mem/tlsf/tlsf.odin index 8ec5f52b7..0ae8c28e0 100644 --- a/core/mem/tlsf/tlsf.odin +++ b/core/mem/tlsf/tlsf.odin @@ -10,6 +10,7 @@ // package mem_tlsf implements a Two Level Segregated Fit memory allocator. package mem_tlsf +import "base:intrinsics" import "base:runtime" Error :: enum byte { @@ -21,7 +22,6 @@ Error :: enum byte { Backing_Allocator_Error = 5, } - Allocator :: struct { // Empty lists point at this block to indicate they are free. block_null: Block_Header, @@ -39,12 +39,13 @@ Allocator :: struct { // statistics like how much memory is still available, // fragmentation, etc. pool: Pool, + + // If we're expected to grow when we run out of memory, + // how much should we ask the backing allocator for? + new_pool_size: uint, } #assert(size_of(Allocator) % ALIGN_SIZE == 0) - - - @(require_results) allocator :: proc(t: ^Allocator) -> runtime.Allocator { return runtime.Allocator{ @@ -53,6 +54,21 @@ allocator :: proc(t: ^Allocator) -> runtime.Allocator { } } +// Tries to estimate a pool size sufficient for `count` allocations, each of `size` and with `alignment`. +estimate_pool_from_size_alignment :: proc(count: int, size: int, alignment: int) -> (pool_size: int) { + per_allocation := align_up(uint(size + alignment) + BLOCK_HEADER_OVERHEAD, ALIGN_SIZE) + return count * int(per_allocation) + int(INITIAL_POOL_OVERHEAD) +} + +// Tries to estimate a pool size sufficient for `count` allocations of `type`. +estimate_pool_from_typeid :: proc(count: int, type: typeid) -> (pool_size: int) { + ti := type_info_of(type) + return estimate_pool_size(count, ti.size, ti.align) +} + +estimate_pool_size :: proc{estimate_pool_from_size_alignment, estimate_pool_from_typeid} + + @(require_results) init_from_buffer :: proc(control: ^Allocator, buf: []byte) -> Error { assert(control != nil) @@ -60,21 +76,25 @@ init_from_buffer :: proc(control: ^Allocator, buf: []byte) -> Error { return .Invalid_Alignment } - pool_bytes := align_down(len(buf) - POOL_OVERHEAD, ALIGN_SIZE) + pool_bytes := align_down(len(buf) - INITIAL_POOL_OVERHEAD, ALIGN_SIZE) if pool_bytes < BLOCK_SIZE_MIN { return .Backing_Buffer_Too_Small } else if pool_bytes > BLOCK_SIZE_MAX { return .Backing_Buffer_Too_Large } - clear(control) - return pool_add(control, buf[:]) + control.pool = Pool{ + data = buf, + allocator = {}, + } + + return free_all(control) } @(require_results) init_from_allocator :: proc(control: ^Allocator, backing: runtime.Allocator, initial_pool_size: int, new_pool_size := 0) -> Error { assert(control != nil) - pool_bytes := align_up(uint(initial_pool_size) + POOL_OVERHEAD, ALIGN_SIZE) + pool_bytes := uint(estimate_pool_size(1, initial_pool_size, ALIGN_SIZE)) if pool_bytes < BLOCK_SIZE_MIN { return .Backing_Buffer_Too_Small } else if pool_bytes > BLOCK_SIZE_MAX { @@ -85,12 +105,15 @@ init_from_allocator :: proc(control: ^Allocator, backing: runtime.Allocator, ini if backing_err != nil { return .Backing_Allocator_Error } - err := init_from_buffer(control, buf) + control.pool = Pool{ data = buf, allocator = backing, } - return err + + control.new_pool_size = uint(new_pool_size) + + return free_all(control) } init :: proc{init_from_buffer, init_from_allocator} @@ -103,8 +126,6 @@ destroy :: proc(control: ^Allocator) { // No need to call `pool_remove` or anything, as they're they're embedded in the backing memory. // We do however need to free the `Pool` tracking entities and the backing memory itself. - // As `Allocator` is embedded in the first backing slice, the `control` pointer will be - // invalid after this call. for p := control.pool.next; p != nil; { next := p.next @@ -136,9 +157,8 @@ allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, return nil, nil case .Free_All: - // NOTE: this doesn't work right at the moment, Jeroen has it on his to-do list :) - // clear(control) - return nil, .Mode_Not_Implemented + free_all(control) + return nil, nil case .Resize: return resize(control, old_memory, uint(old_size), uint(size), uint(alignment)) @@ -159,3 +179,23 @@ allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode, return nil, nil } + +// Exported solely to facilitate testing +@(require_results) +ffs :: proc "contextless" (word: u32) -> (bit: i32) { + return -1 if word == 0 else i32(intrinsics.count_trailing_zeros(word)) +} + +// Exported solely to facilitate testing +@(require_results) +fls :: proc "contextless" (word: u32) -> (bit: i32) { + N :: (size_of(u32) * 8) - 1 + return i32(N - intrinsics.count_leading_zeros(word)) +} + +// Exported solely to facilitate testing +@(require_results) +fls_uint :: proc "contextless" (size: uint) -> (bit: i32) { + N :: (size_of(uint) * 8) - 1 + return i32(N - intrinsics.count_leading_zeros(size)) +} diff --git a/core/mem/tlsf/tlsf_internal.odin b/core/mem/tlsf/tlsf_internal.odin index 66141fcbb..e53d76d61 100644 --- a/core/mem/tlsf/tlsf_internal.odin +++ b/core/mem/tlsf/tlsf_internal.odin @@ -7,12 +7,11 @@ Jeroen van Rijn: Source port */ - package mem_tlsf import "base:intrinsics" +// import "base:sanitizer" import "base:runtime" -// import "core:fmt" // log2 of number of linear subdivisions of block sizes. // Larger values require more memory in the control structure. @@ -58,7 +57,6 @@ Pool :: struct { next: ^Pool, } - /* Block header structure. @@ -95,6 +93,7 @@ The `prev_phys_block` field is stored *inside* the previous free block. BLOCK_HEADER_OVERHEAD :: uint(size_of(uint)) POOL_OVERHEAD :: 2 * BLOCK_HEADER_OVERHEAD +INITIAL_POOL_OVERHEAD :: 48 // User data starts directly after the size field in a used block. BLOCK_START_OFFSET :: offset_of(Block_Header, size) + size_of(Block_Header{}.size) @@ -107,436 +106,12 @@ bits for `FL_INDEX`. BLOCK_SIZE_MIN :: uint(size_of(Block_Header) - size_of(^Block_Header)) BLOCK_SIZE_MAX :: uint(1) << FL_INDEX_MAX -/* - TLSF achieves O(1) cost for `alloc` and `free` operations by limiting - the search for a free block to a free list of guaranteed size - adequate to fulfill the request, combined with efficient free list - queries using bitmasks and architecture-specific bit-manipulation - routines. - - NOTE: TLSF spec relies on ffs/fls returning value 0..31. -*/ - -@(require_results) -ffs :: proc "contextless" (word: u32) -> (bit: i32) { - return -1 if word == 0 else i32(intrinsics.count_trailing_zeros(word)) -} - -@(require_results) -fls :: proc "contextless" (word: u32) -> (bit: i32) { - N :: (size_of(u32) * 8) - 1 - return i32(N - intrinsics.count_leading_zeros(word)) -} - -@(require_results) -fls_uint :: proc "contextless" (size: uint) -> (bit: i32) { - N :: (size_of(uint) * 8) - 1 - return i32(N - intrinsics.count_leading_zeros(size)) -} - -@(require_results) -block_size :: proc "contextless" (block: ^Block_Header) -> (size: uint) { - return block.size &~ (BLOCK_HEADER_FREE | BLOCK_HEADER_PREV_FREE) -} - -block_set_size :: proc "contextless" (block: ^Block_Header, size: uint) { - old_size := block.size - block.size = size | (old_size & (BLOCK_HEADER_FREE | BLOCK_HEADER_PREV_FREE)) -} - -@(require_results) -block_is_last :: proc "contextless" (block: ^Block_Header) -> (is_last: bool) { - return block_size(block) == 0 -} - -@(require_results) -block_is_free :: proc "contextless" (block: ^Block_Header) -> (is_free: bool) { - return (block.size & BLOCK_HEADER_FREE) == BLOCK_HEADER_FREE -} - -block_set_free :: proc "contextless" (block: ^Block_Header) { - block.size |= BLOCK_HEADER_FREE -} - -block_set_used :: proc "contextless" (block: ^Block_Header) { - block.size &~= BLOCK_HEADER_FREE -} - -@(require_results) -block_is_prev_free :: proc "contextless" (block: ^Block_Header) -> (is_prev_free: bool) { - return (block.size & BLOCK_HEADER_PREV_FREE) == BLOCK_HEADER_PREV_FREE -} - -block_set_prev_free :: proc "contextless" (block: ^Block_Header) { - block.size |= BLOCK_HEADER_PREV_FREE -} - -block_set_prev_used :: proc "contextless" (block: ^Block_Header) { - block.size &~= BLOCK_HEADER_PREV_FREE -} - -@(require_results) -block_from_ptr :: proc(ptr: rawptr) -> (block_ptr: ^Block_Header) { - return (^Block_Header)(uintptr(ptr) - BLOCK_START_OFFSET) -} - -@(require_results) -block_to_ptr :: proc(block: ^Block_Header) -> (ptr: rawptr) { - return rawptr(uintptr(block) + BLOCK_START_OFFSET) -} - -// Return location of next block after block of given size. -@(require_results) -offset_to_block :: proc(ptr: rawptr, size: uint) -> (block: ^Block_Header) { - return (^Block_Header)(uintptr(ptr) + uintptr(size)) -} - -@(require_results) -offset_to_block_backwards :: proc(ptr: rawptr, size: uint) -> (block: ^Block_Header) { - return (^Block_Header)(uintptr(ptr) - uintptr(size)) -} - -// Return location of previous block. -@(require_results) -block_prev :: proc(block: ^Block_Header) -> (prev: ^Block_Header) { - assert(block_is_prev_free(block), "previous block must be free") - return block.prev_phys_block -} - -// Return location of next existing block. -@(require_results) -block_next :: proc(block: ^Block_Header) -> (next: ^Block_Header) { - return offset_to_block(block_to_ptr(block), block_size(block) - BLOCK_HEADER_OVERHEAD) -} - -// Link a new block with its physical neighbor, return the neighbor. -@(require_results) -block_link_next :: proc(block: ^Block_Header) -> (next: ^Block_Header) { - next = block_next(block) - next.prev_phys_block = block - return -} - -block_mark_as_free :: proc(block: ^Block_Header) { - // Link the block to the next block, first. - next := block_link_next(block) - block_set_prev_free(next) - block_set_free(block) -} - -block_mark_as_used :: proc(block: ^Block_Header) { - next := block_next(block) - block_set_prev_used(next) - block_set_used(block) -} - -@(require_results) -align_up :: proc(x, align: uint) -> (aligned: uint) { - assert(0 == (align & (align - 1)), "must align to a power of two") - return (x + (align - 1)) &~ (align - 1) -} - -@(require_results) -align_down :: proc(x, align: uint) -> (aligned: uint) { - assert(0 == (align & (align - 1)), "must align to a power of two") - return x - (x & (align - 1)) -} - -@(require_results) -align_ptr :: proc(ptr: rawptr, align: uint) -> (aligned: rawptr) { - assert(0 == (align & (align - 1)), "must align to a power of two") - align_mask := uintptr(align) - 1 - _ptr := uintptr(ptr) - _aligned := (_ptr + align_mask) &~ (align_mask) - return rawptr(_aligned) -} - -// Adjust an allocation size to be aligned to word size, and no smaller than internal minimum. -@(require_results) -adjust_request_size :: proc(size, align: uint) -> (adjusted: uint) { - if size == 0 { - return 0 - } - - // aligned size must not exceed `BLOCK_SIZE_MAX`, or we'll go out of bounds on `sl_bitmap`. - if aligned := align_up(size, align); aligned < BLOCK_SIZE_MAX { - adjusted = max(aligned, BLOCK_SIZE_MIN) - } - return -} - -// Adjust an allocation size to be aligned to word size, and no smaller than internal minimum. -@(require_results) -adjust_request_size_with_err :: proc(size, align: uint) -> (adjusted: uint, err: runtime.Allocator_Error) { - if size == 0 { - return 0, nil - } - - // aligned size must not exceed `BLOCK_SIZE_MAX`, or we'll go out of bounds on `sl_bitmap`. - if aligned := align_up(size, align); aligned < BLOCK_SIZE_MAX { - adjusted = min(aligned, BLOCK_SIZE_MAX) - } else { - err = .Out_Of_Memory - } - return -} - -// TLSF utility functions. In most cases these are direct translations of -// the documentation in the research paper. - -@(optimization_mode="favor_size", require_results) -mapping_insert :: proc(size: uint) -> (fl, sl: i32) { - if size < SMALL_BLOCK_SIZE { - // Store small blocks in first list. - sl = i32(size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT) - } else { - fl = fls_uint(size) - sl = i32(size >> (uint(fl) - TLSF_SL_INDEX_COUNT_LOG2)) ~ (1 << TLSF_SL_INDEX_COUNT_LOG2) - fl -= (FL_INDEX_SHIFT - 1) - } - return -} - -@(optimization_mode="favor_size", require_results) -mapping_round :: #force_inline proc(size: uint) -> (rounded: uint) { - rounded = size - if size >= SMALL_BLOCK_SIZE { - round := uint(1 << (uint(fls_uint(size) - TLSF_SL_INDEX_COUNT_LOG2))) - 1 - rounded += round - } - return -} - -// This version rounds up to the next block size (for allocations) -@(optimization_mode="favor_size", require_results) -mapping_search :: proc(size: uint) -> (fl, sl: i32) { - return mapping_insert(mapping_round(size)) -} - -@(require_results) -search_suitable_block :: proc(control: ^Allocator, fli, sli: ^i32) -> (block: ^Block_Header) { - // First, search for a block in the list associated with the given fl/sl index. - fl := fli^; sl := sli^ - - sl_map := control.sl_bitmap[fli^] & (~u32(0) << uint(sl)) - if sl_map == 0 { - // No block exists. Search in the next largest first-level list. - fl_map := control.fl_bitmap & (~u32(0) << uint(fl + 1)) - if fl_map == 0 { - // No free blocks available, memory has been exhausted. - return {} - } - - fl = ffs(fl_map) - fli^ = fl - sl_map = control.sl_bitmap[fl] - } - assert(sl_map != 0, "internal error - second level bitmap is null") - sl = ffs(sl_map) - sli^ = sl - - // Return the first block in the free list. - return control.blocks[fl][sl] -} - -// Remove a free block from the free list. -remove_free_block :: proc(control: ^Allocator, block: ^Block_Header, fl: i32, sl: i32) { - prev := block.prev_free - next := block.next_free - assert(prev != nil, "prev_free can not be nil") - assert(next != nil, "next_free can not be nil") - next.prev_free = prev - prev.next_free = next - - // If this block is the head of the free list, set new head. - if control.blocks[fl][sl] == block { - control.blocks[fl][sl] = next - - // If the new head is nil, clear the bitmap - if next == &control.block_null { - control.sl_bitmap[fl] &~= (u32(1) << uint(sl)) - - // If the second bitmap is now empty, clear the fl bitmap - if control.sl_bitmap[fl] == 0 { - control.fl_bitmap &~= (u32(1) << uint(fl)) - } - } - } -} - -// Insert a free block into the free block list. -insert_free_block :: proc(control: ^Allocator, block: ^Block_Header, fl: i32, sl: i32) { - current := control.blocks[fl][sl] - assert(current != nil, "free lists cannot have a nil entry") - assert(block != nil, "cannot insert a nil entry into the free list") - block.next_free = current - block.prev_free = &control.block_null - current.prev_free = block - - assert(block_to_ptr(block) == align_ptr(block_to_ptr(block), ALIGN_SIZE), "block not properly aligned") - - // Insert the new block at the head of the list, and mark the first- and second-level bitmaps appropriately. - control.blocks[fl][sl] = block - control.fl_bitmap |= (u32(1) << uint(fl)) - control.sl_bitmap[fl] |= (u32(1) << uint(sl)) -} - -// Remove a given block from the free list. -block_remove :: proc(control: ^Allocator, block: ^Block_Header) { - fl, sl := mapping_insert(block_size(block)) - remove_free_block(control, block, fl, sl) -} - -// Insert a given block into the free list. -block_insert :: proc(control: ^Allocator, block: ^Block_Header) { - fl, sl := mapping_insert(block_size(block)) - insert_free_block(control, block, fl, sl) -} - -@(require_results) -block_can_split :: proc(block: ^Block_Header, size: uint) -> (can_split: bool) { - return block_size(block) >= size_of(Block_Header) + size -} - -// Split a block into two, the second of which is free. -@(require_results) -block_split :: proc(block: ^Block_Header, size: uint) -> (remaining: ^Block_Header) { - // Calculate the amount of space left in the remaining block. - remaining = offset_to_block(block_to_ptr(block), size - BLOCK_HEADER_OVERHEAD) - - remain_size := block_size(block) - (size + BLOCK_HEADER_OVERHEAD) - - assert(block_to_ptr(remaining) == align_ptr(block_to_ptr(remaining), ALIGN_SIZE), - "remaining block not aligned properly") - - assert(block_size(block) == remain_size + size + BLOCK_HEADER_OVERHEAD) - block_set_size(remaining, remain_size) - assert(block_size(remaining) >= BLOCK_SIZE_MIN, "block split with invalid size") - - block_set_size(block, size) - block_mark_as_free(remaining) - - return remaining -} - -// Absorb a free block's storage into an adjacent previous free block. -@(require_results) -block_absorb :: proc(prev: ^Block_Header, block: ^Block_Header) -> (absorbed: ^Block_Header) { - assert(!block_is_last(prev), "previous block can't be last") - // Note: Leaves flags untouched. - prev.size += block_size(block) + BLOCK_HEADER_OVERHEAD - _ = block_link_next(prev) - return prev -} - -// Merge a just-freed block with an adjacent previous free block. -@(require_results) -block_merge_prev :: proc(control: ^Allocator, block: ^Block_Header) -> (merged: ^Block_Header) { - merged = block - if (block_is_prev_free(block)) { - prev := block_prev(block) - assert(prev != nil, "prev physical block can't be nil") - assert(block_is_free(prev), "prev block is not free though marked as such") - block_remove(control, prev) - merged = block_absorb(prev, block) - } - return merged -} - -// Merge a just-freed block with an adjacent free block. -@(require_results) -block_merge_next :: proc(control: ^Allocator, block: ^Block_Header) -> (merged: ^Block_Header) { - merged = block - next := block_next(block) - assert(next != nil, "next physical block can't be nil") - - if (block_is_free(next)) { - assert(!block_is_last(block), "previous block can't be last") - block_remove(control, next) - merged = block_absorb(block, next) - } - return merged -} - -// Trim any trailing block space off the end of a free block, return to pool. -block_trim_free :: proc(control: ^Allocator, block: ^Block_Header, size: uint) { - assert(block_is_free(block), "block must be free") - if (block_can_split(block, size)) { - remaining_block := block_split(block, size) - _ = block_link_next(block) - block_set_prev_free(remaining_block) - block_insert(control, remaining_block) - } -} - -// Trim any trailing block space off the end of a used block, return to pool. -block_trim_used :: proc(control: ^Allocator, block: ^Block_Header, size: uint) { - assert(!block_is_free(block), "Block must be used") - if (block_can_split(block, size)) { - // If the next block is free, we must coalesce. - remaining_block := block_split(block, size) - block_set_prev_used(remaining_block) - - remaining_block = block_merge_next(control, remaining_block) - block_insert(control, remaining_block) - } -} - -// Trim leading block space, return to pool. -@(require_results) -block_trim_free_leading :: proc(control: ^Allocator, block: ^Block_Header, size: uint) -> (remaining: ^Block_Header) { - remaining = block - if block_can_split(block, size) { - // We want the 2nd block. - remaining = block_split(block, size - BLOCK_HEADER_OVERHEAD) - block_set_prev_free(remaining) - - _ = block_link_next(block) - block_insert(control, block) - } - return remaining -} - -@(require_results) -block_locate_free :: proc(control: ^Allocator, size: uint) -> (block: ^Block_Header) { - fl, sl: i32 - if size != 0 { - fl, sl = mapping_search(size) - - /* - `mapping_search` can futz with the size, so for excessively large sizes it can sometimes wind up - with indices that are off the end of the block array. So, we protect against that here, - since this is the only call site of `mapping_search`. Note that we don't need to check `sl`, - as it comes from a modulo operation that guarantees it's always in range. - */ - if fl < FL_INDEX_COUNT { - block = search_suitable_block(control, &fl, &sl) - } - } - - if block != nil { - assert(block_size(block) >= size) - remove_free_block(control, block, fl, sl) - } - return block -} - -@(require_results) -block_prepare_used :: proc(control: ^Allocator, block: ^Block_Header, size: uint) -> (res: []byte, err: runtime.Allocator_Error) { - if block != nil { - assert(size != 0, "Size must be non-zero") - block_trim_free(control, block, size) - block_mark_as_used(block) - res = ([^]byte)(block_to_ptr(block))[:size] - } - return -} - // Clear control structure and point all empty lists at the null block -clear :: proc(control: ^Allocator) { +@(private) +free_all :: proc(control: ^Allocator) -> (err: Error) { + // Clear internal structures control.block_null.next_free = &control.block_null control.block_null.prev_free = &control.block_null - control.fl_bitmap = 0 for i in 0.. (err: Error) { assert(uintptr(raw_data(pool)) % ALIGN_SIZE == 0, "Added memory must be aligned") @@ -574,9 +155,11 @@ pool_add :: proc(control: ^Allocator, pool: []u8) -> (err: Error) { block_set_size(next, 0) block_set_used(next) block_set_prev_free(next) + return } +@(private) pool_remove :: proc(control: ^Allocator, pool: []u8) { block := offset_to_block_backwards(raw_data(pool), BLOCK_HEADER_OVERHEAD) @@ -588,7 +171,7 @@ pool_remove :: proc(control: ^Allocator, pool: []u8) { remove_free_block(control, block, fl, sl) } -@(require_results) +@(private, require_results) alloc_bytes_non_zeroed :: proc(control: ^Allocator, size: uint, align: uint) -> (res: []byte, err: runtime.Allocator_Error) { assert(control != nil) adjust := adjust_request_size(size, ALIGN_SIZE) @@ -601,9 +184,56 @@ alloc_bytes_non_zeroed :: proc(control: ^Allocator, size: uint, align: uint) -> return nil, .Out_Of_Memory } - block := block_locate_free(control, aligned_size) + block := block_locate_free(control, aligned_size) if block == nil { - return nil, .Out_Of_Memory + // OOM: Couldn't find block of `aligned_size` bytes. + if control.new_pool_size > 0 && control.pool.allocator.procedure != nil { + // TLSF is configured to grow. + + /* + This implementation doesn't allow for out-of-band allocations to be passed through, as it's not designed to + track those. Nor is it able to signal those allocations then need to be freed on the backing allocator, + as opposed to regular allocations handled for you when you `destroy` the TLSF instance. + + So if we're asked for more than we're configured to grow by, we can fail with an OOM error early, without adding a new pool. + */ + if aligned_size > control.new_pool_size { + return nil, .Out_Of_Memory + } + + // Trying to allocate a new pool of `control.new_pool_size` bytes. + new_pool_buf := runtime.make_aligned([]byte, control.new_pool_size, ALIGN_SIZE, control.pool.allocator) or_return + + // Add new pool to control structure + if pool_add_err := pool_add(control, new_pool_buf); pool_add_err != .None { + delete(new_pool_buf, control.pool.allocator) + return nil, .Out_Of_Memory + } + + // sanitizer.address_poison(new_pool_buf) + + // Allocate a new link in the `control.pool` tracking structure. + new_pool := new_clone(Pool{ + data = new_pool_buf, + allocator = control.pool.allocator, + next = nil, + }, control.pool.allocator) or_return + + p := &control.pool + for p.next != nil { + p = p.next + } + p.next = new_pool + + // Try again to find free block + block = block_locate_free(control, aligned_size) + if block == nil { + return nil, .Out_Of_Memory + } + } else { + // TLSF is non-growing. We're done. + return nil, .Out_Of_Memory + } } ptr := block_to_ptr(block) aligned := align_ptr(ptr, align) @@ -627,7 +257,7 @@ alloc_bytes_non_zeroed :: proc(control: ^Allocator, size: uint, align: uint) -> return block_prepare_used(control, block, adjust) } -@(require_results) +@(private, require_results) alloc_bytes :: proc(control: ^Allocator, size: uint, align: uint) -> (res: []byte, err: runtime.Allocator_Error) { res, err = alloc_bytes_non_zeroed(control, size, align) if err == nil { @@ -637,6 +267,7 @@ alloc_bytes :: proc(control: ^Allocator, size: uint, align: uint) -> (res: []byt } +@(no_sanitize_address) free_with_size :: proc(control: ^Allocator, ptr: rawptr, size: uint) { assert(control != nil) // `size` is currently ignored @@ -646,6 +277,7 @@ free_with_size :: proc(control: ^Allocator, ptr: rawptr, size: uint) { block := block_from_ptr(ptr) assert(!block_is_free(block), "block already marked as free") // double free + // sanitizer.address_poison(ptr, block.size) block_mark_as_free(block) block = block_merge_prev(control, block) block = block_merge_next(control, block) @@ -653,7 +285,7 @@ free_with_size :: proc(control: ^Allocator, ptr: rawptr, size: uint) { } -@(require_results) +@(private, require_results) resize :: proc(control: ^Allocator, ptr: rawptr, old_size, new_size: uint, alignment: uint) -> (res: []byte, err: runtime.Allocator_Error) { assert(control != nil) if ptr != nil && new_size == 0 { @@ -689,6 +321,7 @@ resize :: proc(control: ^Allocator, ptr: rawptr, old_size, new_size: uint, align block_trim_used(control, block, adjust) res = ([^]byte)(ptr)[:new_size] + // sanitizer.address_unpoison(res) if min_size < new_size { to_zero := ([^]byte)(ptr)[min_size:new_size] @@ -697,7 +330,7 @@ resize :: proc(control: ^Allocator, ptr: rawptr, old_size, new_size: uint, align return } -@(require_results) +@(private, require_results) resize_non_zeroed :: proc(control: ^Allocator, ptr: rawptr, old_size, new_size: uint, alignment: uint) -> (res: []byte, err: runtime.Allocator_Error) { assert(control != nil) if ptr != nil && new_size == 0 { @@ -736,3 +369,427 @@ resize_non_zeroed :: proc(control: ^Allocator, ptr: rawptr, old_size, new_size: res = ([^]byte)(ptr)[:new_size] return } + +/* + TLSF achieves O(1) cost for `alloc` and `free` operations by limiting + the search for a free block to a free list of guaranteed size + adequate to fulfill the request, combined with efficient free list + queries using bitmasks and architecture-specific bit-manipulation + routines. + + NOTE: TLSF spec relies on ffs/fls returning a value in the range 0..31. +*/ + +@(private, require_results, no_sanitize_address) +block_size :: proc "contextless" (block: ^Block_Header) -> (size: uint) { + return block.size &~ (BLOCK_HEADER_FREE | BLOCK_HEADER_PREV_FREE) +} + +@(private, no_sanitize_address) +block_set_size :: proc "contextless" (block: ^Block_Header, size: uint) { + old_size := block.size + block.size = size | (old_size & (BLOCK_HEADER_FREE | BLOCK_HEADER_PREV_FREE)) +} + +@(private, require_results, no_sanitize_address) +block_is_last :: proc "contextless" (block: ^Block_Header) -> (is_last: bool) { + return block_size(block) == 0 +} + +@(private, require_results, no_sanitize_address) +block_is_free :: proc "contextless" (block: ^Block_Header) -> (is_free: bool) { + return (block.size & BLOCK_HEADER_FREE) == BLOCK_HEADER_FREE +} + +@(private, no_sanitize_address) +block_set_free :: proc "contextless" (block: ^Block_Header) { + block.size |= BLOCK_HEADER_FREE +} + +@(private, no_sanitize_address) +block_set_used :: proc "contextless" (block: ^Block_Header) { + block.size &~= BLOCK_HEADER_FREE +} + +@(private, require_results, no_sanitize_address) +block_is_prev_free :: proc "contextless" (block: ^Block_Header) -> (is_prev_free: bool) { + return (block.size & BLOCK_HEADER_PREV_FREE) == BLOCK_HEADER_PREV_FREE +} + +@(private, no_sanitize_address) +block_set_prev_free :: proc "contextless" (block: ^Block_Header) { + block.size |= BLOCK_HEADER_PREV_FREE +} + +@(private, no_sanitize_address) +block_set_prev_used :: proc "contextless" (block: ^Block_Header) { + block.size &~= BLOCK_HEADER_PREV_FREE +} + +@(private, require_results, no_sanitize_address) +block_from_ptr :: proc(ptr: rawptr) -> (block_ptr: ^Block_Header) { + return (^Block_Header)(uintptr(ptr) - BLOCK_START_OFFSET) +} + +@(private, require_results, no_sanitize_address) +block_to_ptr :: proc(block: ^Block_Header) -> (ptr: rawptr) { + return rawptr(uintptr(block) + BLOCK_START_OFFSET) +} + +// Return location of next block after block of given size. +@(private, require_results, no_sanitize_address) +offset_to_block :: proc(ptr: rawptr, size: uint) -> (block: ^Block_Header) { + return (^Block_Header)(uintptr(ptr) + uintptr(size)) +} + +@(private, require_results, no_sanitize_address) +offset_to_block_backwards :: proc(ptr: rawptr, size: uint) -> (block: ^Block_Header) { + return (^Block_Header)(uintptr(ptr) - uintptr(size)) +} + +// Return location of previous block. +@(private, require_results, no_sanitize_address) +block_prev :: proc(block: ^Block_Header) -> (prev: ^Block_Header) { + assert(block_is_prev_free(block), "previous block must be free") + + return block.prev_phys_block +} + +// Return location of next existing block. +@(private, require_results, no_sanitize_address) +block_next :: proc(block: ^Block_Header) -> (next: ^Block_Header) { + return offset_to_block(block_to_ptr(block), block_size(block) - BLOCK_HEADER_OVERHEAD) +} + +// Link a new block with its physical neighbor, return the neighbor. +@(private, require_results, no_sanitize_address) +block_link_next :: proc(block: ^Block_Header) -> (next: ^Block_Header) { + next = block_next(block) + next.prev_phys_block = block + return +} + +@(private, no_sanitize_address) +block_mark_as_free :: proc(block: ^Block_Header) { + // Link the block to the next block, first. + next := block_link_next(block) + block_set_prev_free(next) + block_set_free(block) +} + +@(private, no_sanitize_address) +block_mark_as_used :: proc(block: ^Block_Header) { + next := block_next(block) + block_set_prev_used(next) + block_set_used(block) +} + +@(private, require_results) +align_up :: proc(x, align: uint) -> (aligned: uint) { + assert(0 == (align & (align - 1)), "must align to a power of two") + return (x + (align - 1)) &~ (align - 1) +} + +@(private, require_results) +align_down :: proc(x, align: uint) -> (aligned: uint) { + assert(0 == (align & (align - 1)), "must align to a power of two") + return x - (x & (align - 1)) +} + +@(private, require_results) +align_ptr :: proc(ptr: rawptr, align: uint) -> (aligned: rawptr) { + assert(0 == (align & (align - 1)), "must align to a power of two") + align_mask := uintptr(align) - 1 + _ptr := uintptr(ptr) + _aligned := (_ptr + align_mask) &~ (align_mask) + return rawptr(_aligned) +} + +// Adjust an allocation size to be aligned to word size, and no smaller than internal minimum. +@(private, require_results) +adjust_request_size :: proc(size, align: uint) -> (adjusted: uint) { + if size == 0 { + return 0 + } + + // aligned size must not exceed `BLOCK_SIZE_MAX`, or we'll go out of bounds on `sl_bitmap`. + if aligned := align_up(size, align); aligned < BLOCK_SIZE_MAX { + adjusted = max(aligned, BLOCK_SIZE_MIN) + } + return +} + +// Adjust an allocation size to be aligned to word size, and no smaller than internal minimum. +@(private, require_results) +adjust_request_size_with_err :: proc(size, align: uint) -> (adjusted: uint, err: runtime.Allocator_Error) { + if size == 0 { + return 0, nil + } + + // aligned size must not exceed `BLOCK_SIZE_MAX`, or we'll go out of bounds on `sl_bitmap`. + if aligned := align_up(size, align); aligned < BLOCK_SIZE_MAX { + adjusted = min(aligned, BLOCK_SIZE_MAX) + } else { + err = .Out_Of_Memory + } + return +} + +// TLSF utility functions. In most cases these are direct translations of +// the documentation in the research paper. + +@(optimization_mode="favor_size", private, require_results) +mapping_insert :: proc(size: uint) -> (fl, sl: i32) { + if size < SMALL_BLOCK_SIZE { + // Store small blocks in first list. + sl = i32(size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT) + } else { + fl = fls_uint(size) + sl = i32(size >> (uint(fl) - TLSF_SL_INDEX_COUNT_LOG2)) ~ (1 << TLSF_SL_INDEX_COUNT_LOG2) + fl -= (FL_INDEX_SHIFT - 1) + } + return +} + +@(optimization_mode="favor_size", private, require_results) +mapping_round :: #force_inline proc(size: uint) -> (rounded: uint) { + rounded = size + if size >= SMALL_BLOCK_SIZE { + round := uint(1 << (uint(fls_uint(size) - TLSF_SL_INDEX_COUNT_LOG2))) - 1 + rounded += round + } + return +} + +// This version rounds up to the next block size (for allocations) +@(optimization_mode="favor_size", private, require_results) +mapping_search :: proc(size: uint) -> (fl, sl: i32) { + return mapping_insert(mapping_round(size)) +} + +@(private, require_results, no_sanitize_address) +search_suitable_block :: proc(control: ^Allocator, fli, sli: ^i32) -> (block: ^Block_Header) { + // First, search for a block in the list associated with the given fl/sl index. + fl := fli^; sl := sli^ + + sl_map := control.sl_bitmap[fli^] & (~u32(0) << uint(sl)) + if sl_map == 0 { + // No block exists. Search in the next largest first-level list. + fl_map := control.fl_bitmap & (~u32(0) << uint(fl + 1)) + if fl_map == 0 { + // No free blocks available, memory has been exhausted. + return {} + } + + fl = ffs(fl_map) + fli^ = fl + sl_map = control.sl_bitmap[fl] + } + assert(sl_map != 0, "internal error - second level bitmap is null") + sl = ffs(sl_map) + sli^ = sl + + // Return the first block in the free list. + return control.blocks[fl][sl] +} + +// Remove a free block from the free list. +@(private, no_sanitize_address) +remove_free_block :: proc(control: ^Allocator, block: ^Block_Header, fl: i32, sl: i32) { + prev := block.prev_free + next := block.next_free + assert(prev != nil, "prev_free can not be nil") + assert(next != nil, "next_free can not be nil") + next.prev_free = prev + prev.next_free = next + + // If this block is the head of the free list, set new head. + if control.blocks[fl][sl] == block { + control.blocks[fl][sl] = next + + // If the new head is nil, clear the bitmap + if next == &control.block_null { + control.sl_bitmap[fl] &~= (u32(1) << uint(sl)) + + // If the second bitmap is now empty, clear the fl bitmap + if control.sl_bitmap[fl] == 0 { + control.fl_bitmap &~= (u32(1) << uint(fl)) + } + } + } +} + +// Insert a free block into the free block list. +@(private, no_sanitize_address) +insert_free_block :: proc(control: ^Allocator, block: ^Block_Header, fl: i32, sl: i32) { + current := control.blocks[fl][sl] + assert(current != nil, "free lists cannot have a nil entry") + assert(block != nil, "cannot insert a nil entry into the free list") + block.next_free = current + block.prev_free = &control.block_null + current.prev_free = block + + assert(block_to_ptr(block) == align_ptr(block_to_ptr(block), ALIGN_SIZE), "block not properly aligned") + + // Insert the new block at the head of the list, and mark the first- and second-level bitmaps appropriately. + control.blocks[fl][sl] = block + control.fl_bitmap |= (u32(1) << uint(fl)) + control.sl_bitmap[fl] |= (u32(1) << uint(sl)) +} + +// Remove a given block from the free list. +@(private, no_sanitize_address) +block_remove :: proc(control: ^Allocator, block: ^Block_Header) { + fl, sl := mapping_insert(block_size(block)) + remove_free_block(control, block, fl, sl) +} + +// Insert a given block into the free list. +@(private, no_sanitize_address) +block_insert :: proc(control: ^Allocator, block: ^Block_Header) { + fl, sl := mapping_insert(block_size(block)) + insert_free_block(control, block, fl, sl) +} + +@(private, require_results, no_sanitize_address) +block_can_split :: proc(block: ^Block_Header, size: uint) -> (can_split: bool) { + return block_size(block) >= size_of(Block_Header) + size +} + +// Split a block into two, the second of which is free. +@(private, require_results, no_sanitize_address) +block_split :: proc(block: ^Block_Header, size: uint) -> (remaining: ^Block_Header) { + // Calculate the amount of space left in the remaining block. + remaining = offset_to_block(block_to_ptr(block), size - BLOCK_HEADER_OVERHEAD) + + remain_size := block_size(block) - (size + BLOCK_HEADER_OVERHEAD) + + assert(block_to_ptr(remaining) == align_ptr(block_to_ptr(remaining), ALIGN_SIZE), + "remaining block not aligned properly") + + assert(block_size(block) == remain_size + size + BLOCK_HEADER_OVERHEAD) + block_set_size(remaining, remain_size) + assert(block_size(remaining) >= BLOCK_SIZE_MIN, "block split with invalid size") + + block_set_size(block, size) + block_mark_as_free(remaining) + + return remaining +} + +// Absorb a free block's storage into an adjacent previous free block. +@(private, require_results, no_sanitize_address) +block_absorb :: proc(prev: ^Block_Header, block: ^Block_Header) -> (absorbed: ^Block_Header) { + assert(!block_is_last(prev), "previous block can't be last") + + // Note: Leaves flags untouched. + prev.size += block_size(block) + BLOCK_HEADER_OVERHEAD + _ = block_link_next(prev) + return prev +} + +// Merge a just-freed block with an adjacent previous free block. +@(private, require_results, no_sanitize_address) +block_merge_prev :: proc(control: ^Allocator, block: ^Block_Header) -> (merged: ^Block_Header) { + merged = block + if (block_is_prev_free(block)) { + prev := block_prev(block) + assert(prev != nil, "prev physical block can't be nil") + assert(block_is_free(prev), "prev block is not free though marked as such") + block_remove(control, prev) + merged = block_absorb(prev, block) + } + return merged +} + +// Merge a just-freed block with an adjacent free block. +@(private, require_results, no_sanitize_address) +block_merge_next :: proc(control: ^Allocator, block: ^Block_Header) -> (merged: ^Block_Header) { + merged = block + next := block_next(block) + assert(next != nil, "next physical block can't be nil") + + if (block_is_free(next)) { + assert(!block_is_last(block), "previous block can't be last") + block_remove(control, next) + merged = block_absorb(block, next) + } + return merged +} + +// Trim any trailing block space off the end of a free block, return to pool. +@(private, no_sanitize_address) +block_trim_free :: proc(control: ^Allocator, block: ^Block_Header, size: uint) { + assert(block_is_free(block), "block must be free") + if (block_can_split(block, size)) { + remaining_block := block_split(block, size) + _ = block_link_next(block) + block_set_prev_free(remaining_block) + block_insert(control, remaining_block) + } +} + +// Trim any trailing block space off the end of a used block, return to pool. +@(private, no_sanitize_address) +block_trim_used :: proc(control: ^Allocator, block: ^Block_Header, size: uint) { + assert(!block_is_free(block), "Block must be used") + if (block_can_split(block, size)) { + // If the next block is free, we must coalesce. + remaining_block := block_split(block, size) + block_set_prev_used(remaining_block) + + remaining_block = block_merge_next(control, remaining_block) + block_insert(control, remaining_block) + } +} + +// Trim leading block space, return to pool. +@(private, require_results, no_sanitize_address) +block_trim_free_leading :: proc(control: ^Allocator, block: ^Block_Header, size: uint) -> (remaining: ^Block_Header) { + remaining = block + if block_can_split(block, size) { + // We want the 2nd block. + remaining = block_split(block, size - BLOCK_HEADER_OVERHEAD) + block_set_prev_free(remaining) + + _ = block_link_next(block) + block_insert(control, block) + } + return remaining +} + +@(private, require_results, no_sanitize_address) +block_locate_free :: proc(control: ^Allocator, size: uint) -> (block: ^Block_Header) { + fl, sl: i32 + if size != 0 { + fl, sl = mapping_search(size) + + /* + `mapping_search` can futz with the size, so for excessively large sizes it can sometimes wind up + with indices that are off the end of the block array. So, we protect against that here, + since this is the only call site of `mapping_search`. Note that we don't need to check `sl`, + as it comes from a modulo operation that guarantees it's always in range. + */ + if fl < FL_INDEX_COUNT { + block = search_suitable_block(control, &fl, &sl) + } + } + + if block != nil { + assert(block_size(block) >= size) + remove_free_block(control, block, fl, sl) + } + return block +} + +@(private, require_results, no_sanitize_address) +block_prepare_used :: proc(control: ^Allocator, block: ^Block_Header, size: uint) -> (res: []byte, err: runtime.Allocator_Error) { + if block != nil { + assert(size != 0, "Size must be non-zero") + block_trim_free(control, block, size) + block_mark_as_used(block) + res = ([^]byte)(block_to_ptr(block))[:size] + // sanitizer.address_unpoison(res) + } + return +} diff --git a/core/mem/tracking_allocator.odin b/core/mem/tracking_allocator.odin index 25c547471..01080075e 100644 --- a/core/mem/tracking_allocator.odin +++ b/core/mem/tracking_allocator.odin @@ -64,6 +64,7 @@ This procedure initializes the tracking allocator `t` with a backing allocator specified with `backing_allocator`. The `internals_allocator` will used to allocate the tracked data. */ +@(no_sanitize_address) tracking_allocator_init :: proc(t: ^Tracking_Allocator, backing_allocator: Allocator, internals_allocator := context.allocator) { t.backing = backing_allocator t.allocation_map.allocator = internals_allocator @@ -77,6 +78,7 @@ tracking_allocator_init :: proc(t: ^Tracking_Allocator, backing_allocator: Alloc /* Destroy the tracking allocator. */ +@(no_sanitize_address) tracking_allocator_destroy :: proc(t: ^Tracking_Allocator) { delete(t.allocation_map) delete(t.bad_free_array) @@ -90,6 +92,7 @@ This procedure clears the tracked data from a tracking allocator. **Note**: This procedure clears only the current allocation data while keeping the totals intact. */ +@(no_sanitize_address) tracking_allocator_clear :: proc(t: ^Tracking_Allocator) { sync.mutex_lock(&t.mutex) clear(&t.allocation_map) @@ -103,6 +106,7 @@ Reset the tracking allocator. Reset all of a Tracking Allocator's allocation data back to zero. */ +@(no_sanitize_address) tracking_allocator_reset :: proc(t: ^Tracking_Allocator) { sync.mutex_lock(&t.mutex) clear(&t.allocation_map) @@ -124,6 +128,7 @@ Override Tracking_Allocator.bad_free_callback to have something else happen. For example, you can use tracking_allocator_bad_free_callback_add_to_array to return the tracking allocator to the old behavior, where the bad_free_array was used. */ +@(no_sanitize_address) tracking_allocator_bad_free_callback_panic :: proc(t: ^Tracking_Allocator, memory: rawptr, location: runtime.Source_Code_Location) { runtime.print_caller_location(location) runtime.print_string(" Tracking allocator error: Bad free of pointer ") @@ -136,6 +141,7 @@ tracking_allocator_bad_free_callback_panic :: proc(t: ^Tracking_Allocator, memor Alternative behavior for a bad free: Store in `bad_free_array`. If you use this, then you must make sure to check Tracking_Allocator.bad_free_array at some point. */ +@(no_sanitize_address) tracking_allocator_bad_free_callback_add_to_array :: proc(t: ^Tracking_Allocator, memory: rawptr, location: runtime.Source_Code_Location) { append(&t.bad_free_array, Tracking_Allocator_Bad_Free_Entry { memory = memory, @@ -175,7 +181,7 @@ Example: } } */ -@(require_results) +@(require_results, no_sanitize_address) tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator { return Allocator{ data = data, @@ -183,6 +189,7 @@ tracking_allocator :: proc(data: ^Tracking_Allocator) -> Allocator { } } +@(no_sanitize_address) tracking_allocator_proc :: proc( allocator_data: rawptr, mode: Allocator_Mode, @@ -191,6 +198,7 @@ tracking_allocator_proc :: proc( old_size: int, loc := #caller_location, ) -> (result: []byte, err: Allocator_Error) { + @(no_sanitize_address) track_alloc :: proc(data: ^Tracking_Allocator, entry: ^Tracking_Allocator_Entry) { data.total_memory_allocated += i64(entry.size) data.total_allocation_count += 1 @@ -200,6 +208,7 @@ tracking_allocator_proc :: proc( } } + @(no_sanitize_address) track_free :: proc(data: ^Tracking_Allocator, entry: ^Tracking_Allocator_Entry) { data.total_memory_freed += i64(entry.size) data.total_free_count += 1 diff --git a/core/mem/virtual/arena.odin b/core/mem/virtual/arena.odin index 5191505cf..b515aa3cf 100644 --- a/core/mem/virtual/arena.odin +++ b/core/mem/virtual/arena.odin @@ -3,6 +3,8 @@ package mem_virtual import "core:mem" import "core:sync" +// import "base:sanitizer" + Arena_Kind :: enum uint { Growing = 0, // Chained memory blocks (singly linked list). Static = 1, // Fixed reservation sized. @@ -43,7 +45,7 @@ DEFAULT_ARENA_STATIC_RESERVE_SIZE :: mem.Gigabyte when size_of(uintptr) == 8 els // Initialization of an `Arena` to be a `.Growing` variant. // A growing arena is a linked list of `Memory_Block`s allocated with virtual memory. -@(require_results) +@(require_results, no_sanitize_address) arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) { arena.kind = .Growing arena.curr_block = memory_block_alloc(0, reserved, {}) or_return @@ -53,24 +55,26 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING if arena.minimum_block_size == 0 { arena.minimum_block_size = reserved } + // sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed]) return } // Initialization of an `Arena` to be a `.Static` variant. // A static arena contains a single `Memory_Block` allocated with virtual memory. -@(require_results) +@(require_results, no_sanitize_address) arena_init_static :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_STATIC_RESERVE_SIZE, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) { arena.kind = .Static arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return arena.total_used = 0 arena.total_reserved = arena.curr_block.reserved + // sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed]) return } // Initialization of an `Arena` to be a `.Buffer` variant. // A buffer arena contains single `Memory_Block` created from a user provided []byte. -@(require_results) +@(require_results, no_sanitize_address) arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Error) { if len(buffer) < size_of(Memory_Block) { return .Out_Of_Memory @@ -78,7 +82,7 @@ arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Erro arena.kind = .Buffer - mem.zero_slice(buffer) + // sanitizer.address_poison(buffer[:]) block_base := raw_data(buffer) block := (^Memory_Block)(block_base) @@ -94,7 +98,7 @@ arena_init_buffer :: proc(arena: ^Arena, buffer: []byte) -> (err: Allocator_Erro } // Allocates memory from the provided arena. -@(require_results) +@(require_results, no_sanitize_address) arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { assert(alignment & (alignment-1) == 0, "non-power of two alignment", loc) @@ -104,11 +108,22 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l } sync.mutex_guard(&arena.mutex) + return arena_alloc_unguarded(arena, size, alignment, loc) +} + +// Allocates memory from the provided arena. +@(require_results, no_sanitize_address, private) +arena_alloc_unguarded :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { + size := size + if size == 0 { + return nil, nil + } switch arena.kind { case .Growing: - needed := mem.align_forward_uint(size, alignment) - if arena.curr_block == nil || (safe_add(arena.curr_block.used, needed) or_else 0) > arena.curr_block.reserved { + prev_used := 0 if arena.curr_block == nil else arena.curr_block.used + data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=arena.default_commit_size) + if err == .Out_Of_Memory { if arena.minimum_block_size == 0 { arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE arena.minimum_block_size = mem.align_forward_uint(arena.minimum_block_size, DEFAULT_PAGE_SIZE) @@ -124,6 +139,7 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l max(arena.default_commit_size, arena.minimum_block_size) } + needed := mem.align_forward_uint(size, alignment) needed = max(needed, arena.default_commit_size) block_size := max(needed, arena.minimum_block_size) @@ -131,10 +147,10 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l new_block.prev = arena.curr_block arena.curr_block = new_block arena.total_reserved += new_block.reserved - } - prev_used := arena.curr_block.used - data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=arena.default_commit_size) + prev_used = 0 + data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=arena.default_commit_size) + } arena.total_used += arena.curr_block.used - prev_used case .Static: if arena.curr_block == nil { @@ -156,10 +172,13 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l data, err = alloc_from_memory_block(arena.curr_block, size, alignment, default_commit_size=0) arena.total_used = arena.curr_block.used } + + // sanitizer.address_unpoison(data) return } // Resets the memory of a Static or Buffer arena to a specific `position` (offset) and zeroes the previously used memory. +@(no_sanitize_address) arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool { sync.mutex_guard(&arena.mutex) @@ -173,6 +192,7 @@ arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) mem.zero_slice(arena.curr_block.base[arena.curr_block.used:][:prev_pos-pos]) } arena.total_used = arena.curr_block.used + // sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed]) return true } else if pos == 0 { arena.total_used = 0 @@ -182,6 +202,7 @@ arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) } // Frees the last memory block of a Growing Arena +@(no_sanitize_address) arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) { if free_block := arena.curr_block; free_block != nil { assert(arena.kind == .Growing, "expected a .Growing arena", loc) @@ -189,11 +210,13 @@ arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_locat arena.total_reserved -= free_block.reserved arena.curr_block = free_block.prev + // sanitizer.address_poison(free_block.base[:free_block.committed]) memory_block_dealloc(free_block) } } // Deallocates all but the first memory block of the arena and resets the allocator's usage to 0. +@(no_sanitize_address) arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { switch arena.kind { case .Growing: @@ -206,7 +229,9 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { if arena.curr_block != nil { curr_block_used := int(arena.curr_block.used) arena.curr_block.used = 0 + // sanitizer.address_unpoison(arena.curr_block.base[:curr_block_used]) mem.zero(arena.curr_block.base, curr_block_used) + // sanitizer.address_poison(arena.curr_block.base[:arena.curr_block.committed]) } arena.total_used = 0 case .Static, .Buffer: @@ -217,6 +242,7 @@ arena_free_all :: proc(arena: ^Arena, loc := #caller_location) { // Frees all of the memory allocated by the arena and zeros all of the values of an arena. // A buffer based arena does not `delete` the provided `[]byte` bufffer. +@(no_sanitize_address) arena_destroy :: proc(arena: ^Arena, loc := #caller_location) { sync.mutex_guard(&arena.mutex) switch arena.kind { @@ -248,7 +274,7 @@ arena_static_bootstrap_new :: proc{ } // Ability to bootstrap allocate a struct with an arena within the struct itself using the growing variant strategy. -@(require_results) +@(require_results, no_sanitize_address) arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { bootstrap: Arena bootstrap.kind = .Growing @@ -264,13 +290,13 @@ arena_growing_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintp } // Ability to bootstrap allocate a struct with an arena within the struct itself using the growing variant strategy. -@(require_results) +@(require_results, no_sanitize_address) arena_growing_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, minimum_block_size: uint = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE) -> (ptr: ^T, err: Allocator_Error) { return arena_growing_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), minimum_block_size) } // Ability to bootstrap allocate a struct with an arena within the struct itself using the static variant strategy. -@(require_results) +@(require_results, no_sanitize_address) arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintptr, reserved: uint) -> (ptr: ^T, err: Allocator_Error) { bootstrap: Arena bootstrap.kind = .Static @@ -286,19 +312,20 @@ arena_static_bootstrap_new_by_offset :: proc($T: typeid, offset_to_arena: uintpt } // Ability to bootstrap allocate a struct with an arena within the struct itself using the static variant strategy. -@(require_results) +@(require_results, no_sanitize_address) arena_static_bootstrap_new_by_name :: proc($T: typeid, $field_name: string, reserved: uint) -> (ptr: ^T, err: Allocator_Error) { return arena_static_bootstrap_new_by_offset(T, offset_of_by_string(T, field_name), reserved) } // Create an `Allocator` from the provided `Arena` -@(require_results) +@(require_results, no_sanitize_address) arena_allocator :: proc(arena: ^Arena) -> mem.Allocator { return mem.Allocator{arena_allocator_proc, arena} } // The allocator procedure used by an `Allocator` produced by `arena_allocator` +@(no_sanitize_address) arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, @@ -328,10 +355,15 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, case size == 0: err = .Mode_Not_Implemented return - case uintptr(old_data) & uintptr(alignment-1) == 0: + } + + sync.mutex_guard(&arena.mutex) + + if uintptr(old_data) & uintptr(alignment-1) == 0 { if size < old_size { // shrink data in-place data = old_data[:size] + // sanitizer.address_poison(old_data[size:old_size]) return } @@ -341,18 +373,22 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, new_end := start + size if start < old_end && old_end == block.used && new_end <= block.reserved { // grow data in-place, adjusting next allocation + prev_used := block.used _ = alloc_from_memory_block(block, new_end - old_end, 1, default_commit_size=arena.default_commit_size) or_return + arena.total_used += block.used - prev_used data = block.base[start:new_end] + // sanitizer.address_unpoison(data) return } } } - new_memory := arena_alloc(arena, size, alignment, location) or_return + new_memory := arena_alloc_unguarded(arena, size, alignment, location) or_return if new_memory == nil { return } copy(new_memory, old_data[:old_size]) + // sanitizer.address_poison(old_data[:old_size]) return new_memory, nil case .Query_Features: set := (^mem.Allocator_Mode_Set)(old_memory) @@ -378,7 +414,7 @@ Arena_Temp :: struct { } // Begins the section of temporary arena memory. -@(require_results) +@(require_results, no_sanitize_address) arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) { assert(arena != nil, "nil arena", loc) sync.mutex_guard(&arena.mutex) @@ -393,6 +429,7 @@ arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena } // Ends the section of temporary arena memory by resetting the memory to the stored position. +@(no_sanitize_address) arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) { assert(temp.arena != nil, "nil arena", loc) arena := temp.arena @@ -428,6 +465,7 @@ arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) { } // Ignore the use of a `arena_temp_begin` entirely by __not__ resetting to the stored position. +@(no_sanitize_address) arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) { assert(temp.arena != nil, "nil arena", loc) arena := temp.arena @@ -438,6 +476,7 @@ arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) { } // Asserts that all uses of `Arena_Temp` has been used by an `Arena` +@(no_sanitize_address) arena_check_temp :: proc(arena: ^Arena, loc := #caller_location) { assert(arena.temp_count == 0, "Arena_Temp not been ended", loc) } diff --git a/core/mem/virtual/arena_util.odin b/core/mem/virtual/arena_util.odin index 4e28c17d6..fb778687b 100644 --- a/core/mem/virtual/arena_util.odin +++ b/core/mem/virtual/arena_util.odin @@ -20,6 +20,17 @@ new_aligned :: proc(arena: ^Arena, $T: typeid, alignment: uint, loc := #caller_l return } +// The `new_clone` procedure allocates memory for a type `T` from a `virtual.Arena`. The second argument is a value that +// is to be copied to the allocated data. The value returned is a pointer to a newly allocated value of that type using the specified allocator. +@(require_results) +new_clone :: proc(arena: ^Arena, data: $T, loc := #caller_location) -> (ptr: ^T, err: Allocator_Error) { + ptr, err = new_aligned(arena, T, align_of(T), loc) + if ptr != nil && err == nil { + ptr^ = data + } + return +} + // `make_slice` allocates and initializes a slice. Like `new`, the second argument is a type, not a value. // Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it. // diff --git a/core/mem/virtual/virtual.odin b/core/mem/virtual/virtual.odin index 4afc33813..3f388acf3 100644 --- a/core/mem/virtual/virtual.odin +++ b/core/mem/virtual/virtual.odin @@ -2,39 +2,46 @@ package mem_virtual import "core:mem" import "base:intrinsics" +// import "base:sanitizer" import "base:runtime" _ :: runtime DEFAULT_PAGE_SIZE := uint(4096) @(init, private) -platform_memory_init :: proc() { +platform_memory_init :: proc "contextless" () { _platform_memory_init() } Allocator_Error :: mem.Allocator_Error -@(require_results) +@(require_results, no_sanitize_address) reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { return _reserve(size) } +@(no_sanitize_address) commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { + // sanitizer.address_unpoison(data, size) return _commit(data, size) } -@(require_results) +@(require_results, no_sanitize_address) reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { data = reserve(size) or_return commit(raw_data(data), size) or_return return } +@(no_sanitize_address) decommit :: proc "contextless" (data: rawptr, size: uint) { + // sanitizer.address_poison(data, size) _decommit(data, size) } +@(no_sanitize_address) release :: proc "contextless" (data: rawptr, size: uint) { + // sanitizer.address_unpoison(data, size) _release(data, size) } @@ -46,13 +53,11 @@ Protect_Flag :: enum u32 { Protect_Flags :: distinct bit_set[Protect_Flag; u32] Protect_No_Access :: Protect_Flags{} +@(no_sanitize_address) protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool { return _protect(data, size, flags) } - - - Memory_Block :: struct { prev: ^Memory_Block, base: [^]byte, @@ -66,13 +71,13 @@ Memory_Block_Flag :: enum u32 { Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32] -@(private="file", require_results) +@(private="file", require_results, no_sanitize_address) align_formula :: #force_inline proc "contextless" (size, align: uint) -> uint { result := size + align-1 return result - result%align } -@(require_results) +@(require_results, no_sanitize_address) memory_block_alloc :: proc(committed, reserved: uint, alignment: uint = 0, flags: Memory_Block_Flags = {}) -> (block: ^Memory_Block, err: Allocator_Error) { page_size := DEFAULT_PAGE_SIZE assert(mem.is_power_of_two(uintptr(page_size))) @@ -84,8 +89,8 @@ memory_block_alloc :: proc(committed, reserved: uint, alignment: uint = 0, flags reserved = align_formula(reserved, page_size) committed = clamp(committed, 0, reserved) - total_size := uint(reserved + max(alignment, size_of(Platform_Memory_Block))) - base_offset := uintptr(max(alignment, size_of(Platform_Memory_Block))) + total_size := reserved + alignment + size_of(Platform_Memory_Block) + base_offset := mem.align_forward_uintptr(size_of(Platform_Memory_Block), max(uintptr(alignment), align_of(Platform_Memory_Block))) protect_offset := uintptr(0) do_protection := false @@ -116,8 +121,9 @@ memory_block_alloc :: proc(committed, reserved: uint, alignment: uint = 0, flags return &pmblock.block, nil } -@(require_results) +@(require_results, no_sanitize_address) alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint, default_commit_size: uint = 0) -> (data: []byte, err: Allocator_Error) { + @(no_sanitize_address) calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint { alignment_offset := uint(0) ptr := uintptr(block.base[block.used:]) @@ -128,6 +134,7 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint, return alignment_offset } + @(no_sanitize_address) do_commit_if_necessary :: proc(block: ^Memory_Block, size: uint, default_commit_size: uint) -> (err: Allocator_Error) { if block.committed - block.used < size { pmblock := (^Platform_Memory_Block)(block) @@ -172,10 +179,12 @@ alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint, data = block.base[block.used+alignment_offset:][:min_size] block.used += size + // sanitizer.address_unpoison(data) return } +@(no_sanitize_address) memory_block_dealloc :: proc(block_to_free: ^Memory_Block) { if block := (^Platform_Memory_Block)(block_to_free); block != nil { platform_memory_free(block) diff --git a/core/mem/virtual/virtual_darwin.odin b/core/mem/virtual/virtual_darwin.odin new file mode 100644 index 000000000..0635c83d4 --- /dev/null +++ b/core/mem/virtual/virtual_darwin.odin @@ -0,0 +1,20 @@ +package mem_virtual + +import "core:sys/posix" + +_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { + result := posix.mmap(nil, size, {}, {.ANONYMOUS, .PRIVATE}) + if result == posix.MAP_FAILED { + assert_contextless(posix.errno() == .ENOMEM) + return nil, .Out_Of_Memory + } + + return ([^]byte)(uintptr(result))[:size], nil +} + +_decommit :: proc "contextless" (data: rawptr, size: uint) { + MADV_FREE :: 5 + + posix.mprotect(data, size, {}) + posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE)) +} diff --git a/core/mem/virtual/virtual_freebsd.odin b/core/mem/virtual/virtual_freebsd.odin new file mode 100644 index 000000000..af0f31733 --- /dev/null +++ b/core/mem/virtual/virtual_freebsd.odin @@ -0,0 +1,26 @@ +package mem_virtual + +import "core:sys/posix" + +_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { + + PROT_MAX :: proc "contextless" (flags: posix.Prot_Flags) -> posix.Prot_Flags { + _PROT_MAX_SHIFT :: 16 + return transmute(posix.Prot_Flags)(transmute(i32)flags << _PROT_MAX_SHIFT) + } + + result := posix.mmap(nil, size, PROT_MAX({.READ, .WRITE, .EXEC}), {.ANONYMOUS, .PRIVATE}) + if result == posix.MAP_FAILED { + assert_contextless(posix.errno() == .ENOMEM) + return nil, .Out_Of_Memory + } + + return ([^]byte)(uintptr(result))[:size], nil +} + +_decommit :: proc "contextless" (data: rawptr, size: uint) { + MADV_FREE :: 5 + + posix.mprotect(data, size, {}) + posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE)) +} diff --git a/core/mem/virtual/virtual_linux.odin b/core/mem/virtual/virtual_linux.odin index 3e0d7668b..f819fbf86 100644 --- a/core/mem/virtual/virtual_linux.odin +++ b/core/mem/virtual/virtual_linux.odin @@ -43,10 +43,10 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) return errno == .NONE } -_platform_memory_init :: proc() { +_platform_memory_init :: proc "contextless" () { DEFAULT_PAGE_SIZE = 4096 // is power of two - assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) + assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) } diff --git a/core/mem/virtual/virtual_netbsd.odin b/core/mem/virtual/virtual_netbsd.odin new file mode 100644 index 000000000..588625cc7 --- /dev/null +++ b/core/mem/virtual/virtual_netbsd.odin @@ -0,0 +1,25 @@ +package mem_virtual + +import "core:sys/posix" + +_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { + + PROT_MPROTECT :: proc "contextless" (flags: posix.Prot_Flags) -> posix.Prot_Flags { + return transmute(posix.Prot_Flags)(transmute(i32)flags << 3) + } + + result := posix.mmap(nil, size, PROT_MPROTECT({.READ, .WRITE, .EXEC}), {.ANONYMOUS, .PRIVATE}) + if result == posix.MAP_FAILED { + assert_contextless(posix.errno() == .ENOMEM) + return nil, .Out_Of_Memory + } + + return ([^]byte)(uintptr(result))[:size], nil +} + +_decommit :: proc "contextless" (data: rawptr, size: uint) { + MADV_FREE :: 6 + + posix.mprotect(data, size, {}) + posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE)) +} diff --git a/core/mem/virtual/virtual_openbsd.odin b/core/mem/virtual/virtual_openbsd.odin new file mode 100644 index 000000000..83f7ca9ca --- /dev/null +++ b/core/mem/virtual/virtual_openbsd.odin @@ -0,0 +1,20 @@ +package mem_virtual + +import "core:sys/posix" + +_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { + result := posix.mmap(nil, size, {}, {.ANONYMOUS, .PRIVATE}) + if result == posix.MAP_FAILED { + assert_contextless(posix.errno() == .ENOMEM) + return nil, .Out_Of_Memory + } + + return ([^]byte)(uintptr(result))[:size], nil +} + +_decommit :: proc "contextless" (data: rawptr, size: uint) { + MADV_FREE :: 6 + + posix.mprotect(data, size, {}) + posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE)) +} diff --git a/core/mem/virtual/virtual_other.odin b/core/mem/virtual/virtual_other.odin index a57856975..c6386e842 100644 --- a/core/mem/virtual/virtual_other.odin +++ b/core/mem/virtual/virtual_other.odin @@ -25,7 +25,7 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) return false } -_platform_memory_init :: proc() { +_platform_memory_init :: proc "contextless" () { } _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { diff --git a/core/mem/virtual/virtual_platform.odin b/core/mem/virtual/virtual_platform.odin index 54c42ce4b..c9dde4e9d 100644 --- a/core/mem/virtual/virtual_platform.odin +++ b/core/mem/virtual/virtual_platform.odin @@ -7,6 +7,7 @@ Platform_Memory_Block :: struct { reserved: uint, } +@(no_sanitize_address) platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (block: ^Platform_Memory_Block, err: Allocator_Error) { to_commit, to_reserve := to_commit, to_reserve to_reserve = max(to_commit, to_reserve) @@ -15,7 +16,9 @@ platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (bl to_commit = clamp(to_commit, size_of(Platform_Memory_Block), total_to_reserved) data := reserve(total_to_reserved) or_return - commit(raw_data(data), to_commit) + + commit_err := commit(raw_data(data), to_commit) + assert_contextless(commit_err == nil) block = (^Platform_Memory_Block)(raw_data(data)) block.committed = to_commit @@ -24,12 +27,14 @@ platform_memory_alloc :: proc "contextless" (to_commit, to_reserve: uint) -> (bl } +@(no_sanitize_address) platform_memory_free :: proc "contextless" (block: ^Platform_Memory_Block) { if block != nil { release(block, block.reserved) } } +@(no_sanitize_address) platform_memory_commit :: proc "contextless" (block: ^Platform_Memory_Block, to_commit: uint) -> (err: Allocator_Error) { if to_commit < block.committed { return nil diff --git a/core/mem/virtual/virtual_posix.odin b/core/mem/virtual/virtual_posix.odin index c3d6a9095..4bb161770 100644 --- a/core/mem/virtual/virtual_posix.odin +++ b/core/mem/virtual/virtual_posix.odin @@ -4,36 +4,18 @@ package mem_virtual import "core:sys/posix" -// Define non-posix needed flags: -when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD { - MADV_FREE :: 5 /* pages unneeded, discard contents */ -} else when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { - MADV_FREE :: 6 -} - -_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { - flags := posix.Map_Flags{ .ANONYMOUS, .PRIVATE } - result := posix.mmap(nil, size, {}, flags) - if result == posix.MAP_FAILED { - return nil, .Out_Of_Memory - } - - return ([^]byte)(uintptr(result))[:size], nil -} - _commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { if posix.mprotect(data, size, { .READ, .WRITE }) != .OK { - return .Out_Of_Memory + #partial switch posix.errno() { + case .EACCES, .EPERM: return .Invalid_Pointer + case .ENOTSUP, .EINVAL: return .Invalid_Argument + case: return .Out_Of_Memory + } } return nil } -_decommit :: proc "contextless" (data: rawptr, size: uint) { - posix.mprotect(data, size, {}) - posix.posix_madvise(data, size, transmute(posix.MAdvice)i32(MADV_FREE)) -} - _release :: proc "contextless" (data: rawptr, size: uint) { posix.munmap(data, size) } @@ -46,13 +28,13 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) return posix.mprotect(data, size, transmute(posix.Prot_Flags)flags) == .OK } -_platform_memory_init :: proc() { +_platform_memory_init :: proc "contextless" () { // NOTE: `posix.PAGESIZE` due to legacy reasons could be wrong so we use `sysconf`. size := posix.sysconf(._PAGESIZE) DEFAULT_PAGE_SIZE = uint(max(size, posix.PAGESIZE)) // is power of two - assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) + assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) } _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { diff --git a/core/mem/virtual/virtual_windows.odin b/core/mem/virtual/virtual_windows.odin index acd30ae33..1d777af17 100644 --- a/core/mem/virtual/virtual_windows.odin +++ b/core/mem/virtual/virtual_windows.odin @@ -72,7 +72,7 @@ foreign Kernel32 { flProtect: u32, dwMaximumSizeHigh: u32, dwMaximumSizeLow: u32, - lpName: [^]u16, + lpName: cstring16, ) -> rawptr --- MapViewOfFile :: proc( @@ -83,6 +83,8 @@ foreign Kernel32 { dwNumberOfBytesToMap: uint, ) -> rawptr --- } + +@(no_sanitize_address) _reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) { result := VirtualAlloc(nil, size, MEM_RESERVE, PAGE_READWRITE) if result == nil { @@ -93,6 +95,7 @@ _reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Err return } +@(no_sanitize_address) _commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { result := VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE) if result == nil { @@ -107,12 +110,18 @@ _commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error { } return nil } + +@(no_sanitize_address) _decommit :: proc "contextless" (data: rawptr, size: uint) { VirtualFree(data, size, MEM_DECOMMIT) } + +@(no_sanitize_address) _release :: proc "contextless" (data: rawptr, size: uint) { VirtualFree(data, 0, MEM_RELEASE) } + +@(no_sanitize_address) _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool { pflags: u32 pflags = PAGE_NOACCESS @@ -136,17 +145,18 @@ _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) } - -_platform_memory_init :: proc() { +@(no_sanitize_address) +_platform_memory_init :: proc "contextless" () { sys_info: SYSTEM_INFO GetSystemInfo(&sys_info) DEFAULT_PAGE_SIZE = max(DEFAULT_PAGE_SIZE, uint(sys_info.dwPageSize)) // is power of two - assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) + assert_contextless(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0) } +@(no_sanitize_address) _map_file :: proc "contextless" (fd: uintptr, size: i64, flags: Map_File_Flags) -> (data: []byte, error: Map_File_Error) { page_flags: u32 if flags == {.Read} { diff --git a/core/net/common.odin b/core/net/common.odin index 12add8225..7b33350c0 100644 --- a/core/net/common.odin +++ b/core/net/common.odin @@ -53,8 +53,6 @@ ODIN_NET_TCP_NODELAY_DEFAULT :: #config(ODIN_NET_TCP_NODELAY_DEFAULT, true) Maybe :: runtime.Maybe Network_Error :: union #shared_nil { - General_Error, - Platform_Error, Create_Socket_Error, Dial_Error, Listen_Error, @@ -65,6 +63,8 @@ Network_Error :: union #shared_nil { TCP_Recv_Error, UDP_Recv_Error, Shutdown_Error, + Interfaces_Error, + Socket_Info_Error, Socket_Option_Error, Set_Blocking_Error, Parse_Endpoint_Error, @@ -74,14 +74,13 @@ Network_Error :: union #shared_nil { #assert(size_of(Network_Error) == 8) -General_Error :: enum u32 { - None = 0, - Unable_To_Enumerate_Network_Interfaces = 1, +Interfaces_Error :: enum u32 { + None, + Unable_To_Enumerate_Network_Interfaces, + Allocation_Failure, + Unknown, } -// `Platform_Error` is used to wrap errors returned by the different platforms that don't fit a common error. -Platform_Error :: enum u32 {} - Parse_Endpoint_Error :: enum u32 { None = 0, Bad_Port = 1, @@ -109,7 +108,7 @@ TCP_Options :: struct { no_delay: bool, } -default_tcp_options := TCP_Options { +DEFAULT_TCP_OPTIONS :: TCP_Options { no_delay = ODIN_NET_TCP_NODELAY_DEFAULT, } @@ -262,6 +261,9 @@ DNS_Configuration :: struct { resolv_conf: string, hosts_file: string, + resolv_conf_buf: [128]u8, + hosts_file_buf: [128]u8, + // TODO: Allow loading these up with `reload_configuration()` call or the like, // so we don't have to do it each call. name_servers: []Endpoint, diff --git a/core/net/dns.odin b/core/net/dns.odin index 7eb543db3..ed8c00d6a 100644 --- a/core/net/dns.odin +++ b/core/net/dns.odin @@ -22,69 +22,43 @@ package net Haesbaert: Security fixes */ +@(require) import "base:runtime" import "core:mem" import "core:strings" import "core:time" import "core:os" import "core:math/rand" -/* - Default configuration for DNS resolution. -*/ +@(require) import "core:sync" + +dns_config_initialized: sync.Once when ODIN_OS == .Windows { - DEFAULT_DNS_CONFIGURATION :: DNS_Configuration{ - resolv_conf = "", - hosts_file = "%WINDIR%\\system32\\drivers\\etc\\hosts", + dns_configuration := DNS_Configuration{ + resolv_conf = "", + hosts_file = "%WINDIR%\\system32\\drivers\\etc\\hosts", } } else when ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { - DEFAULT_DNS_CONFIGURATION :: DNS_Configuration{ - resolv_conf = "/etc/resolv.conf", - hosts_file = "/etc/hosts", + dns_configuration := DNS_Configuration{ + resolv_conf = "/etc/resolv.conf", + hosts_file = "/etc/hosts", } } else { #panic("Please add a configuration for this OS.") } -@(init) +/* + Replaces environment placeholders in `dns_configuration`. Only necessary on Windows. + Is automatically called, once, by `get_dns_records_*`. +*/ +@(private) init_dns_configuration :: proc() { - /* - Resolve %ENVIRONMENT% placeholders in their paths. - */ - dns_configuration.resolv_conf, _ = replace_environment_path(dns_configuration.resolv_conf) - dns_configuration.hosts_file, _ = replace_environment_path(dns_configuration.hosts_file) -} - -@(fini, private) -destroy_dns_configuration :: proc() { - delete(dns_configuration.resolv_conf) - dns_configuration.resolv_conf = "" - delete(dns_configuration.hosts_file) - dns_configuration.hosts_file = "" -} - -dns_configuration := DEFAULT_DNS_CONFIGURATION - -// Always allocates for consistency. -replace_environment_path :: proc(path: string, allocator := context.allocator) -> (res: string, ok: bool) { - // Nothing to replace. Return a clone of the original. - if strings.count(path, "%") != 2 { - return strings.clone(path, allocator), true + when ODIN_OS == .Windows { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + val := os.replace_environment_placeholders(dns_configuration.hosts_file, context.temp_allocator) + copy(dns_configuration.hosts_file_buf[:], val) + dns_configuration.hosts_file = string(dns_configuration.hosts_file_buf[:len(val)]) } - - left := strings.index(path, "%") + 1 - assert(left > 0 && left <= len(path)) // should be covered by there being two % - - right := strings.index(path[left:], "%") + 1 - assert(right > 0 && right <= len(path)) // should be covered by there being two % - - env_key := path[left: right] - env_val := os.get_env(env_key, allocator) - defer delete(env_val) - - res, _ = strings.replace(path, path[left - 1: right + 1], env_val, 1, allocator) - return res, true } - /* Resolves a hostname to exactly one IP4 and IP6 endpoint. It's then up to you which one you use. @@ -204,6 +178,9 @@ resolve_ip6 :: proc(hostname_and_maybe_port: string) -> (ep6: Endpoint, err: Net See `destroy_records`. */ get_dns_records_from_os :: proc(hostname: string, type: DNS_Record_Type, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) { + when ODIN_OS == .Windows { + sync.once_do(&dns_config_initialized, init_dns_configuration) + } return _get_dns_records_os(hostname, type, allocator) } @@ -219,6 +196,9 @@ get_dns_records_from_os :: proc(hostname: string, type: DNS_Record_Type, allocat See `destroy_records`. */ get_dns_records_from_nameservers :: proc(hostname: string, type: DNS_Record_Type, name_servers: []Endpoint, host_overrides: []DNS_Record, allocator := context.allocator) -> (records: []DNS_Record, err: DNS_Error) { + when ODIN_OS == .Windows { + sync.once_do(&dns_config_initialized, init_dns_configuration) + } context.allocator = allocator if type != .SRV { @@ -440,6 +420,8 @@ load_hosts :: proc(hosts_file_path: string, allocator := context.allocator) -> ( splits := strings.fields(line) defer delete(splits) + (len(splits) >= 2) or_continue + ip_str := splits[0] addr := parse_address(ip_str) if addr == nil { @@ -886,4 +868,4 @@ parse_response :: proc(response: []u8, filter: DNS_Record_Type = nil, allocator xid = hdr.id return _records[:], xid, true -} +} \ No newline at end of file diff --git a/core/net/dns_unix.odin b/core/net/dns_unix.odin index e4336e410..351d26dbc 100644 --- a/core/net/dns_unix.odin +++ b/core/net/dns_unix.odin @@ -79,4 +79,4 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator : } return get_dns_records_from_nameservers(hostname, type, name_servers, host_overrides[:]) -} +} \ No newline at end of file diff --git a/core/net/errors.odin b/core/net/errors.odin new file mode 100644 index 000000000..4853327b0 --- /dev/null +++ b/core/net/errors.odin @@ -0,0 +1,292 @@ +package net + +/* +Retrieve a platform specific error code, for when the categorized cross-platform errors are not enough. + +Platforms specific returns: +- Darwin: `posix.Errno` (`core:sys/posix`) +- Linux: `linux.Errno` (`core:sys/linux`) +- FreeBSD: `freebsd.Errno` (`core:sys/freebsd`) +- Windows: `windows.System_Error` (`core:sys/windows`) +*/ +@(require_results) +last_platform_error :: proc() -> i32 { + return _last_platform_error() +} + +/* +Retrieve a stringified version of the last platform error. +*/ +@(require_results) +last_platform_error_string :: proc() -> string { + return _last_platform_error_string() +} + +set_last_platform_error :: proc(err: i32) { + _set_last_platform_error(err) +} + +Create_Socket_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Invalid/unsupported family or protocol. + Invalid_Argument, + // The user has no permission to create a socket of this type and/or protocol. + Insufficient_Permissions, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +Dial_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Invalid endpoint and/or options. + Invalid_Argument, + // An attempt was made to connect to a broadcast socket on a socket that doesn't support it. + Broadcast_Not_Supported, + // The socket is already connected. + Already_Connected, + // The socket is already in the progress of making a connection. + Already_Connecting, + // The address is already in use. + Address_In_Use, + // Could not reach the remote host. + Host_Unreachable, + // The remote host refused the connection or isn't listening. + Refused, + // The connection was reset by the remote host. + Reset, + // Timed out before making a connection. + Timeout, + // Non-blocking socket that would need to block waiting to connect. + Would_Block, + // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. + Interrupted, + // Endpoint given without a port, which is required. + Port_Required, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +Bind_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Invalid socket or endpoint, or invalid combination of the two. + Invalid_Argument, + // The socket is already bound to an address. + Already_Bound, + // The address is protected and the current user has insufficient permissions to access it. + Insufficient_Permissions_For_Address, + // The address is already in use. + Address_In_Use, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +Listen_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // The socket or backlog is invalid. + Invalid_Argument, + // The socket is valid, but does not support listening. + Unsupported_Socket, + // The socket is already connected. + Already_Connected, + // The address is already in use. + Address_In_Use, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +Accept_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Invalid socket, or options. + Invalid_Argument, + // The given socket does not support accepting connections. + Unsupported_Socket, + // accept called on a socket which is not listening. + Not_Listening, + // A connection arrived but was closed while in the listen queue. + Aborted, + // Timed out before being able to accept a connection. + Timeout, + // Non-blocking socket that would need to block waiting for a connection. + Would_Block, + // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. + Interrupted, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +TCP_Recv_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Invalid socket or buffer given. + Invalid_Argument, + // The socket is not connected. + Not_Connected, + // Connection was closed/broken/shutdown while receiving data. + Connection_Closed, + // Timed out before being able to receive any data. + Timeout, + // Non-blocking socket that would need to block waiting on data. + Would_Block, + // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. + Interrupted, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +UDP_Recv_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Invalid socket or buffer given. + Invalid_Argument, + // "Connection" was refused by remote, or closed/broken/shutdown while receiving data. + Connection_Refused, + // Timed out before being able to receive any data. + Timeout, + // Non-blocking socket that would need to block waiting on data. + Would_Block, + // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. + Interrupted, + // Linux and UDP only: indicates the buffer was too small to receive all data, and the excess is truncated and discarded. + Excess_Truncated, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +TCP_Send_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Invalid socket or buffer given. + Invalid_Argument, + // Connection was closed/broken/shutdown while receiving data. + Connection_Closed, + // The socket is not connected. + Not_Connected, + // Could not reach the remote host. + Host_Unreachable, + // Timed out before being able to send any data. + Timeout, + // Non-blocking socket that would need to block waiting on the remote to be able to receive the data. + Would_Block, + // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. + Interrupted, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +UDP_Send_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Invalid socket or buffer given. + Invalid_Argument, + // Could not reach the remote host. + Host_Unreachable, + // "Connection" was refused by remote, or closed/broken/shutdown while sending data. + Connection_Refused, + // Timed out before being able to send any data. + Timeout, + // Non-blocking socket that would need to block waiting on the remote to be able to receive the data. + Would_Block, + // Interrupted by a signal or other method of cancellation like WSACancelBlockingCall on Windows. + Interrupted, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +Shutdown_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Socket is invalid or not connected, or the manner given is invalid. + Invalid_Argument, + // Connection was closed/aborted/shutdown. + Connection_Closed, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +Socket_Info_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Socket is invalid or not connected, or the manner given is invalid. + Invalid_Argument, + // The socket is valid, but unsupported by this opperation. + Unsupported_Socket, + // Connection was closed/aborted/shutdown. + Connection_Closed, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +Socket_Option_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Not enough space in internal tables/buffers to create a new socket, or an unsupported protocol is given. + Insufficient_Resources, + // Socket is invalid, not connected, or the connection has been closed/reset/shutdown. + Invalid_Socket, + // Unknown or unsupported option for the socket. + Invalid_Option, + // Invalid level or value. + Invalid_Value, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} + +Set_Blocking_Error :: enum i32 { + None, + // No network connection, or the network stack is not initialized. + Network_Unreachable, + // Socket is invalid. + Invalid_Argument, + + // An error unable to be categorized in above categories, `last_platform_error` may have more info. + Unknown, +} diff --git a/core/net/errors_darwin.odin b/core/net/errors_darwin.odin index 2905b44bc..255bd351f 100644 --- a/core/net/errors_darwin.odin +++ b/core/net/errors_darwin.odin @@ -20,189 +20,249 @@ package net Feoramund: FreeBSD platform code */ -import "core:c" -import "core:os" +import "core:reflect" +import "core:sys/posix" -Create_Socket_Error :: enum c.int { - None = 0, - Family_Not_Supported_For_This_Socket = c.int(os.EAFNOSUPPORT), - No_Socket_Descriptors_Available = c.int(os.EMFILE), - No_Buffer_Space_Available = c.int(os.ENOBUFS), - No_Memory_Available_Available = c.int(os.ENOMEM), - Protocol_Unsupported_By_System = c.int(os.EPROTONOSUPPORT), - Wrong_Protocol_For_Socket = c.int(os.EPROTONOSUPPORT), - Family_And_Socket_Type_Mismatch = c.int(os.EPROTONOSUPPORT), +_last_platform_error :: proc() -> i32 { + return i32(posix.errno()) } -Dial_Error :: enum c.int { - None = 0, - Port_Required = -1, // Attempted to dial an endpointing without a port being set. - - Address_In_Use = c.int(os.EADDRINUSE), - In_Progress = c.int(os.EINPROGRESS), - Cannot_Use_Any_Address = c.int(os.EADDRNOTAVAIL), - Wrong_Family_For_Socket = c.int(os.EAFNOSUPPORT), - Refused = c.int(os.ECONNREFUSED), - Is_Listening_Socket = c.int(os.EACCES), - Already_Connected = c.int(os.EISCONN), - Network_Unreachable = c.int(os.ENETUNREACH), // Device is offline - Host_Unreachable = c.int(os.EHOSTUNREACH), // Remote host cannot be reached - No_Buffer_Space_Available = c.int(os.ENOBUFS), - Not_Socket = c.int(os.ENOTSOCK), - Timeout = c.int(os.ETIMEDOUT), - - // TODO: we may need special handling for this; maybe make a socket a struct with metadata? - Would_Block = c.int(os.EWOULDBLOCK), +_last_platform_error_string :: proc() -> string { + description, _ := reflect.enum_name_from_value(posix.errno()) + return description } -Bind_Error :: enum c.int { - None = 0, - Privileged_Port_Without_Root = -1, // Attempted to bind to a port less than 1024 without root access. - - Address_In_Use = c.int(os.EADDRINUSE), // Another application is currently bound to this endpoint. - Given_Nonlocal_Address = c.int(os.EADDRNOTAVAIL), // The address is not a local address on this machine. - Broadcast_Disabled = c.int(os.EACCES), // To bind a UDP socket to the broadcast address, the appropriate socket option must be set. - Address_Family_Mismatch = c.int(os.EFAULT), // The address family of the address does not match that of the socket. - Already_Bound = c.int(os.EINVAL), // The socket is already bound to an address. - No_Ports_Available = c.int(os.ENOBUFS), // There are not enough ephemeral ports available. +_set_last_platform_error :: proc(err: i32) { + posix.errno(posix.Errno(err)) } -Listen_Error :: enum c.int { - None = 0, - Address_In_Use = c.int(os.EADDRINUSE), - Already_Connected = c.int(os.EISCONN), - No_Socket_Descriptors_Available = c.int(os.EMFILE), - No_Buffer_Space_Available = c.int(os.ENOBUFS), - Nonlocal_Address = c.int(os.EADDRNOTAVAIL), - Not_Socket = c.int(os.ENOTSOCK), - Listening_Not_Supported_For_This_Socket = c.int(os.EOPNOTSUPP), +_create_socket_error :: proc() -> Create_Socket_Error { + #partial switch posix.errno() { + case .EMFILE, .ENOBUFS, .ENOMEM, .EPROTONOSUPPORT, .EISCONN, .ENFILE: + return .Insufficient_Resources + case .EAFNOSUPPORT, .EPROTOTYPE: + return .Invalid_Argument + case .EACCES: + return .Insufficient_Permissions + case: + return .Unknown + } } -Accept_Error :: enum c.int { - None = 0, - // TODO(tetra): Is this error actually possible here? Or is like Linux, in which case we can remove it. - Reset = c.int(os.ECONNRESET), - Not_Listening = c.int(os.EINVAL), - No_Socket_Descriptors_Available_For_Client_Socket = c.int(os.EMFILE), - No_Buffer_Space_Available = c.int(os.ENOBUFS), - Not_Socket = c.int(os.ENOTSOCK), - Not_Connection_Oriented_Socket = c.int(os.EOPNOTSUPP), - - // TODO: we may need special handling for this; maybe make a socket a struct with metadata? - Would_Block = c.int(os.EWOULDBLOCK), +_dial_error :: proc() -> Dial_Error { + #partial switch posix.errno() { + case .ENOBUFS: + return .Insufficient_Resources + case .EAFNOSUPPORT, .EBADF, .EFAULT, .EINVAL, .ENOTSOCK, .EPROTOTYPE, .EADDRNOTAVAIL: + return .Invalid_Argument + case .EISCONN: + return .Already_Connected + case .EALREADY: + return .Already_Connecting + case .EADDRINUSE: + return .Address_In_Use + case .ENETDOWN: + return .Network_Unreachable + case .EHOSTUNREACH: + return .Host_Unreachable + case .ECONNREFUSED: + return .Refused + case .ECONNRESET: + return .Reset + case .ETIMEDOUT: + return .Timeout + case .EINPROGRESS: + return .Would_Block + case .EINTR: + return .Interrupted + case .EACCES: + return .Broadcast_Not_Supported + case: + return .Unknown + } } -TCP_Recv_Error :: enum c.int { - None = 0, - Shutdown = c.int(os.ESHUTDOWN), - Not_Connected = c.int(os.ENOTCONN), - - // TODO(tetra): Is this error actually possible here? - Connection_Broken = c.int(os.ENETRESET), - Not_Socket = c.int(os.ENOTSOCK), - Aborted = c.int(os.ECONNABORTED), - - // TODO(tetra): Determine when this is different from the syscall returning n=0 and maybe normalize them? - Connection_Closed = c.int(os.ECONNRESET), - Offline = c.int(os.ENETDOWN), - Host_Unreachable = c.int(os.EHOSTUNREACH), - Interrupted = c.int(os.EINTR), - - // NOTE: No, really. Presumably this means something different for nonblocking sockets... - Timeout = c.int(os.EWOULDBLOCK), +_bind_error :: proc() -> Bind_Error { + #partial switch posix.errno() { + case .EADDRNOTAVAIL, .EAFNOSUPPORT, .EBADF, .EDESTADDRREQ, .EFAULT, .ENOTSOCK, .EOPNOTSUPP: + return .Invalid_Argument + case .EINVAL: + return .Already_Bound + case .EACCES: + return .Insufficient_Permissions_For_Address + case .EADDRINUSE: + return .Address_In_Use + case: + return .Unknown + } } -UDP_Recv_Error :: enum c.int { - None = 0, - Buffer_Too_Small = c.int(os.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost. - Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket. - Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor. - Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory. - Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7). - - // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. - // NOTE: No, really. Presumably this means something different for nonblocking sockets... - Timeout = c.int(os.EWOULDBLOCK), - Socket_Not_Bound = c.int(os.EINVAL), // The socket must be bound for this operation, but isn't. +_listen_error :: proc() -> Listen_Error { + #partial switch posix.errno() { + case .EBADF, .ENOTSOCK: + return .Invalid_Argument + case .EDESTADDRREQ, .EOPNOTSUPP: + return .Unsupported_Socket + case .EINVAL: + return .Already_Connected + case: + return .Unknown + } } -TCP_Send_Error :: enum c.int { - None = 0, - - Aborted = c.int(os.ECONNABORTED), - Connection_Closed = c.int(os.ECONNRESET), - Not_Connected = c.int(os.ENOTCONN), - Shutdown = c.int(os.ESHUTDOWN), - - // The send queue was full. - // This is usually a transient issue. - // - // This also shouldn't normally happen on Linux, as data is dropped if it - // doesn't fit in the send queue. - No_Buffer_Space_Available = c.int(os.ENOBUFS), - Offline = c.int(os.ENETDOWN), - Host_Unreachable = c.int(os.EHOSTUNREACH), - Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7). - - // NOTE: No, really. Presumably this means something different for nonblocking sockets... - // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. - Timeout = c.int(os.EWOULDBLOCK), - Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket. +_accept_error :: proc() -> Accept_Error { + #partial switch posix.errno() { + case .EMFILE, .ENFILE, .ENOMEM: + return .Insufficient_Resources + case .EBADF, .ENOTSOCK, .EFAULT: + return .Invalid_Argument + case .EOPNOTSUPP: + return .Unsupported_Socket + case .ECONNABORTED: + return .Aborted + case .EWOULDBLOCK: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -// TODO -UDP_Send_Error :: enum c.int { - None = 0, - Message_Too_Long = c.int(os.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent. - - // TODO: not sure what the exact circumstances for this is yet - Network_Unreachable = c.int(os.ENETUNREACH), - No_Outbound_Ports_Available = c.int(os.EAGAIN), // There are no more emphemeral outbound ports available to bind the socket to, in order to send. - - // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. - // NOTE: No, really. Presumably this means something different for nonblocking sockets... - Timeout = c.int(os.EWOULDBLOCK), - Not_Socket = c.int(os.ENOTSOCK), // The so-called socket is not an open socket. - Not_Descriptor = c.int(os.EBADF), // The so-called socket is, in fact, not even a valid descriptor. - Bad_Buffer = c.int(os.EFAULT), // The buffer did not point to a valid location in memory. - Interrupted = c.int(os.EINTR), // A signal occurred before any data was transmitted. See signal(7). - - // The send queue was full. - // This is usually a transient issue. - // - // This also shouldn't normally happen on Linux, as data is dropped if it - // doesn't fit in the send queue. - No_Buffer_Space_Available = c.int(os.ENOBUFS), - No_Memory_Available = c.int(os.ENOMEM), // No memory was available to properly manage the send queue. +_tcp_recv_error :: proc() -> TCP_Recv_Error { + #partial switch posix.errno() { + case .EBADF, .EFAULT, .EINVAL, .ENOTSOCK, .EOPNOTSUPP: + return .Invalid_Argument + case .ENOBUFS: + return .Insufficient_Resources + case .ENOTCONN: + return .Not_Connected + case .ECONNRESET: + return .Connection_Closed + case .ETIMEDOUT: + return .Timeout + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Shutdown_Manner :: enum c.int { - Receive = c.int(os.SHUT_RD), - Send = c.int(os.SHUT_WR), - Both = c.int(os.SHUT_RDWR), +_udp_recv_error :: proc() -> UDP_Recv_Error { + #partial switch posix.errno() { + case .EBADF, .EFAULT, .EINVAL, .ENOTSOCK, .EOPNOTSUPP, .EMSGSIZE: + return .Invalid_Argument + case .ENOBUFS, .ENOMEM: + return .Insufficient_Resources + case .ECONNRESET, .ENOTCONN: + return .Connection_Refused + case .ETIMEDOUT: + return .Timeout + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Shutdown_Error :: enum c.int { - None = 0, - Aborted = c.int(os.ECONNABORTED), - Reset = c.int(os.ECONNRESET), - Offline = c.int(os.ENETDOWN), - Not_Connected = c.int(os.ENOTCONN), - Not_Socket = c.int(os.ENOTSOCK), - Invalid_Manner = c.int(os.EINVAL), +_tcp_send_error :: proc() -> TCP_Send_Error { + #partial switch posix.errno() { + case .EACCES, .EBADF, .EFAULT, .EMSGSIZE, .ENOTSOCK, .EOPNOTSUPP: + return .Invalid_Argument + case .ENOBUFS: + return .Insufficient_Resources + case .ECONNRESET, .EPIPE: + return .Connection_Closed + case .ENOTCONN: + return .Not_Connected + case .EHOSTUNREACH: + return .Host_Unreachable + case .ENETDOWN, .ENETUNREACH: + return .Network_Unreachable + case .ETIMEDOUT: + return .Timeout + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Socket_Option_Error :: enum c.int { - None = 0, - Offline = c.int(os.ENETDOWN), - Timeout_When_Keepalive_Set = c.int(os.ENETRESET), - Invalid_Option_For_Socket = c.int(os.ENOPROTOOPT), - Reset_When_Keepalive_Set = c.int(os.ENOTCONN), - Not_Socket = c.int(os.ENOTSOCK), +_udp_send_error :: proc() -> UDP_Send_Error { + #partial switch posix.errno() { + case .EACCES, .EBADF, .EFAULT, .EMSGSIZE, .ENOTSOCK, .EOPNOTSUPP, .EAFNOSUPPORT, .EDESTADDRREQ: + return .Invalid_Argument + case .ENOBUFS, .ENOMEM: + return .Insufficient_Resources + case .ECONNRESET, .EPIPE: + return .Connection_Refused + case .EHOSTUNREACH: + return .Host_Unreachable + case .ENETDOWN, .ENETUNREACH: + return .Network_Unreachable + case .ETIMEDOUT: + return .Timeout + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Set_Blocking_Error :: enum c.int { - None = 0, +_shutdown_error :: proc() -> Shutdown_Error { + #partial switch posix.errno() { + case .EBADF, .EINVAL, .ENOTSOCK, .ENOTCONN: + return .Invalid_Argument + case: + return .Unknown + } +} - // TODO: Add errors for `set_blocking` -} \ No newline at end of file +_socket_info_error :: proc() -> Socket_Info_Error { + #partial switch posix.errno() { + case .EBADF, .ENOTSOCK: + return .Invalid_Argument + case .ENOTCONN: + return .Network_Unreachable + case .EOPNOTSUPP: + return .Unsupported_Socket + case .EINVAL: + return .Connection_Closed + case .ENOBUFS: + return .Insufficient_Resources + case: + return .Unknown + } +} + +_socket_option_error :: proc() -> Socket_Option_Error { + #partial switch posix.errno() { + case .ENOBUFS: + return .Insufficient_Resources + case .EBADF, .ENOTSOCK, .EISCONN: + return .Invalid_Socket + case .EINVAL, .ENOPROTOOPT: + return .Invalid_Option + case .EFAULT, .EDOM: + return .Invalid_Value + case: + return .Unknown + } +} + +_set_blocking_error :: proc() -> Set_Blocking_Error { + #partial switch posix.errno() { + case .EBADF: + return .Invalid_Argument + case: + return .Unknown + } +} diff --git a/core/net/errors_freebsd.odin b/core/net/errors_freebsd.odin index 486732a95..05de41746 100644 --- a/core/net/errors_freebsd.odin +++ b/core/net/errors_freebsd.odin @@ -20,198 +20,285 @@ package net Feoramund: FreeBSD platform code */ -import "core:c" +import "core:reflect" import "core:sys/freebsd" -Create_Socket_Error :: enum c.int { - None = 0, - Access_Denied = cast(c.int)freebsd.Errno.EACCES, - Family_Not_Supported_For_This_Socket = cast(c.int)freebsd.Errno.EAFNOSUPPORT, - Full_Per_Process_Descriptor_Table = cast(c.int)freebsd.Errno.EMFILE, - Full_System_File_Table = cast(c.int)freebsd.Errno.ENFILE, - No_Buffer_Space_Available = cast(c.int)freebsd.Errno.ENOBUFS, - Insufficient_Permission = cast(c.int)freebsd.Errno.EPERM, - Protocol_Unsupported_In_Family = cast(c.int)freebsd.Errno.EPROTONOSUPPORT, - Socket_Type_Unsupported_By_Protocol = cast(c.int)freebsd.Errno.EPROTOTYPE, +@(private="file", thread_local) +_last_error: freebsd.Errno + +_last_platform_error :: proc() -> i32 { + return i32(_last_error) } -Dial_Error :: enum c.int { - None = 0, - Port_Required = -1, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - Invalid_Namelen = cast(c.int)freebsd.Errno.EINVAL, - Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, - Address_Unavailable = cast(c.int)freebsd.Errno.EADDRNOTAVAIL, - Wrong_Family_For_Socket = cast(c.int)freebsd.Errno.EAFNOSUPPORT, - Already_Connected = cast(c.int)freebsd.Errno.EISCONN, - Timeout = cast(c.int)freebsd.Errno.ETIMEDOUT, - Refused_By_Remote_Host = cast(c.int)freebsd.Errno.ECONNREFUSED, - // `Refused` alias for `core:net` tests. - // The above default name `Refused_By_Remote_Host` is more explicit. - Refused = Refused_By_Remote_Host, - Reset_By_Remote_Host = cast(c.int)freebsd.Errno.ECONNRESET, - Network_Unreachable = cast(c.int)freebsd.Errno.ENETUNREACH, - Host_Unreachable = cast(c.int)freebsd.Errno.EHOSTUNREACH, - Address_In_Use = cast(c.int)freebsd.Errno.EADDRINUSE, - Invalid_Address_Space = cast(c.int)freebsd.Errno.EFAULT, - In_Progress = cast(c.int)freebsd.Errno.EINPROGRESS, - Interrupted_By_Signal = cast(c.int)freebsd.Errno.EINTR, - Previous_Attempt_Incomplete = cast(c.int)freebsd.Errno.EALREADY, - Broadcast_Unavailable = cast(c.int)freebsd.Errno.EACCES, - Auto_Port_Unavailable = cast(c.int)freebsd.Errno.EAGAIN, - - // NOTE: There are additional connect() error possibilities, but they are - // strictly for addresses in the UNIX domain. +_last_platform_error_string :: proc() -> string { + description, _ := reflect.enum_name_from_value(_last_error) + return description } -Bind_Error :: enum c.int { - None = 0, - Kernel_Resources_Unavailable = cast(c.int)freebsd.Errno.EAGAIN, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - - // NOTE: bind() can also return EINVAL if the underlying `addrlen` is an - // invalid length for the address family. This shouldn't happen for the net - // package, but it's worth noting. - Already_Bound = cast(c.int)freebsd.Errno.EINVAL, - Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, - Given_Nonlocal_Address = cast(c.int)freebsd.Errno.EADDRNOTAVAIL, - Address_In_Use = cast(c.int)freebsd.Errno.EADDRINUSE, - Address_Family_Mismatch = cast(c.int)freebsd.Errno.EAFNOSUPPORT, - Protected_Address = cast(c.int)freebsd.Errno.EACCES, - Invalid_Address_Space = cast(c.int)freebsd.Errno.EFAULT, - - // NOTE: There are additional bind() error possibilities, but they are - // strictly for addresses in the UNIX domain. +_set_last_platform_error :: proc(err: i32) { + _last_error = freebsd.Errno(err) } -Listen_Error :: enum c.int { - None = 0, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - Socket_Not_Bound = cast(c.int)freebsd.Errno.EDESTADDRREQ, - Already_Connected = cast(c.int)freebsd.Errno.EINVAL, - Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, - Listening_Not_Supported_For_This_Socket = cast(c.int)freebsd.Errno.EOPNOTSUPP, +_create_socket_error :: proc(errno: freebsd.Errno) -> Create_Socket_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EMFILE, .ENFILE, .ENOBUFS, .EPROTONOSUPPORT: + return .Insufficient_Resources + case .EAFNOSUPPORT, .EPROTOTYPE: + return .Invalid_Argument + case .EACCES, .EPERM: + return .Insufficient_Permissions + case: + return .Unknown + } } -Accept_Error :: enum c.int { - None = 0, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - Interrupted = cast(c.int)freebsd.Errno.EINTR, - Full_Per_Process_Descriptor_Table = cast(c.int)freebsd.Errno.EMFILE, - Full_System_File_Table = cast(c.int)freebsd.Errno.ENFILE, - Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, - Listen_Not_Called_On_Socket_Yet = cast(c.int)freebsd.Errno.EINVAL, - Address_Not_Writable = cast(c.int)freebsd.Errno.EFAULT, +_dial_error :: proc(errno: freebsd.Errno) -> Dial_Error { + assert(errno != nil) + _last_error = errno - // NOTE: This is the same as EWOULDBLOCK. - No_Connections_Available = cast(c.int)freebsd.Errno.EAGAIN, - // `Would_Block` alias for `core:net` tests. - Would_Block = cast(c.int)freebsd.Errno.EAGAIN, - - New_Connection_Aborted = cast(c.int)freebsd.Errno.ECONNABORTED, + #partial switch errno { + case .EBADF, .EINVAL, .ENOTSOCK, .EADDRNOTAVAIL, .EAFNOSUPPORT, .EFAULT, .EAGAIN: + return .Invalid_Argument + case .EISCONN: + return .Already_Connected + case .EALREADY: + return .Already_Connecting + case .EADDRINUSE: + return .Address_In_Use + case .ENETUNREACH: + return .Network_Unreachable + case .EHOSTUNREACH: + return .Host_Unreachable + case .ECONNREFUSED: + return .Refused + case .ECONNRESET: + return .Reset + case .ETIMEDOUT: + return .Timeout + case .EINPROGRESS: + return .Would_Block + case .EINTR: + return .Interrupted + case .EACCES: + return .Broadcast_Not_Supported + case: + return .Unknown + } } -TCP_Recv_Error :: enum c.int { - None = 0, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - Connection_Closed = cast(c.int)freebsd.Errno.ECONNRESET, - Not_Connected = cast(c.int)freebsd.Errno.ENOTCONN, - Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, +_bind_error :: proc(errno: freebsd.Errno) -> Bind_Error { + assert(errno != nil) + _last_error = errno - // NOTE(Feoramund): The next two errors are only relevant for recvmsg(), - // but I'm including them for completeness's sake. - Full_Table_And_Pending_Data = cast(c.int)freebsd.Errno.EMFILE, - Invalid_Message_Size = cast(c.int)freebsd.Errno.EMSGSIZE, - - Timeout = cast(c.int)freebsd.Errno.EAGAIN, - Interrupted_By_Signal = cast(c.int)freebsd.Errno.EINTR, - Buffer_Pointer_Outside_Address_Space = cast(c.int)freebsd.Errno.EFAULT, + #partial switch errno { + case .EAGAIN, .ENOTSOCK, .EADDRNOTAVAIL, .EAFNOSUPPORT, .EFAULT: + return .Insufficient_Resources + case .EBADF: + return .Invalid_Argument + case .EINVAL: + return .Already_Bound + case .EACCES: + return .Insufficient_Permissions_For_Address + case .EADDRINUSE: + return .Address_In_Use + case: + return .Unknown + } } -UDP_Recv_Error :: enum c.int { - None = 0, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - Connection_Closed = cast(c.int)freebsd.Errno.ECONNRESET, - Not_Connected = cast(c.int)freebsd.Errno.ENOTCONN, - Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, +_listen_error :: proc(errno: freebsd.Errno) -> Listen_Error { + assert(errno != nil) + _last_error = errno - // NOTE(Feoramund): The next two errors are only relevant for recvmsg(), - // but I'm including them for completeness's sake. - Full_Table_And_Data_Discarded = cast(c.int)freebsd.Errno.EMFILE, - Invalid_Message_Size = cast(c.int)freebsd.Errno.EMSGSIZE, - - Timeout = cast(c.int)freebsd.Errno.EAGAIN, - Interrupted_By_Signal = cast(c.int)freebsd.Errno.EINTR, - Buffer_Pointer_Outside_Address_Space = cast(c.int)freebsd.Errno.EFAULT, + #partial switch errno { + case .EBADF, .ENOTSOCK: + return .Invalid_Argument + case .EDESTADDRREQ, .EOPNOTSUPP: + return .Unsupported_Socket + case .EINVAL: + return .Already_Connected + case: + return .Unknown + } } -TCP_Send_Error :: enum c.int { - None = 0, - Connection_Closed = cast(c.int)freebsd.Errno.ECONNRESET, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - Broadcast_Status_Mismatch = cast(c.int)freebsd.Errno.EACCES, - Not_Connected = cast(c.int)freebsd.Errno.ENOTCONN, - Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, - Argument_In_Invalid_Address_Space = cast(c.int)freebsd.Errno.EFAULT, +_accept_error :: proc(errno: freebsd.Errno) -> Accept_Error { + assert(errno != nil) + _last_error = errno - Message_Size_Breaks_Atomicity = cast(c.int)freebsd.Errno.EMSGSIZE, - - /* The socket is marked non-blocking, or MSG_DONTWAIT is - specified, and the requested operation would block. */ - Would_Block = cast(c.int)freebsd.Errno.EAGAIN, - - /* NOTE: This error arises for two distinct reasons: - - 1. The system was unable to allocate an internal buffer. - The operation may succeed when buffers become available. - - 2. The output queue for a network interface was full. - This generally indicates that the interface has stopped - sending, but may be caused by transient congestion. - */ - No_Buffer_Space_Available = cast(c.int)freebsd.Errno.ENOBUFS, - - Host_Unreachable = cast(c.int)freebsd.Errno.EHOSTUNREACH, - Already_Connected = cast(c.int)freebsd.Errno.EISCONN, - ICMP_Unreachable = cast(c.int)freebsd.Errno.ECONNREFUSED, - Host_Down = cast(c.int)freebsd.Errno.EHOSTDOWN, - Network_Down = cast(c.int)freebsd.Errno.ENETDOWN, - Jailed_Socket_Tried_To_Escape = cast(c.int)freebsd.Errno.EADDRNOTAVAIL, - Cannot_Send_More_Data = cast(c.int)freebsd.Errno.EPIPE, + #partial switch errno { + case .EMFILE, .ENFILE: + return .Insufficient_Resources + case .EBADF, .ENOTSOCK, .EFAULT: + return .Invalid_Argument + case .EINVAL: + return .Not_Listening + case .ECONNABORTED: + return .Aborted + case .EWOULDBLOCK: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -// NOTE(Feoramund): The same as TCP errors go, as far as I'm aware. -UDP_Send_Error :: distinct TCP_Send_Error +_tcp_recv_error :: proc(errno: freebsd.Errno) -> TCP_Recv_Error { + assert(errno != nil) + _last_error = errno -Shutdown_Manner :: enum c.int { - Receive = cast(c.int)freebsd.Shutdown_Method.RD, - Send = cast(c.int)freebsd.Shutdown_Method.WR, - Both = cast(c.int)freebsd.Shutdown_Method.RDWR, + #partial switch errno { + case .EBADF, .ENOTSOCK, .EFAULT: + return .Invalid_Argument + case .ENOTCONN: + return .Not_Connected + case .ECONNRESET: + return .Connection_Closed + case .ETIMEDOUT: + return .Timeout + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Shutdown_Error :: enum c.int { - None = 0, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - Invalid_Manner = cast(c.int)freebsd.Errno.EINVAL, - Not_Connected = cast(c.int)freebsd.Errno.ENOTCONN, - Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, +_udp_recv_error :: proc(errno: freebsd.Errno) -> UDP_Recv_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .ENOTSOCK, .EFAULT: + return .Invalid_Argument + case .ECONNRESET, .ENOTCONN: + return .Connection_Refused + case .ETIMEDOUT: + return .Timeout + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Socket_Option_Error :: enum c.int { - None = 0, - Value_Out_Of_Range = -1, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - Not_Socket = cast(c.int)freebsd.Errno.ENOTSOCK, - Unknown_Option_For_Level = cast(c.int)freebsd.Errno.ENOPROTOOPT, - Argument_In_Invalid_Address_Space = cast(c.int)freebsd.Errno.EFAULT, - // This error can arise for many different reasons. - Invalid_Value = cast(c.int)freebsd.Errno.EINVAL, - System_Memory_Allocation_Failed = cast(c.int)freebsd.Errno.ENOMEM, - Insufficient_System_Resources = cast(c.int)freebsd.Errno.ENOBUFS, +_tcp_send_error :: proc(errno: freebsd.Errno) -> TCP_Send_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .EACCES, .ENOTSOCK, .EFAULT, .EMSGSIZE: + return .Invalid_Argument + case .ENOBUFS: + return .Insufficient_Resources + case .ECONNRESET, .EPIPE: + return .Connection_Closed + case .ENOTCONN: + return .Not_Connected + case .EHOSTUNREACH: + return .Host_Unreachable + case .EHOSTDOWN: + return .Host_Unreachable + case .ENETDOWN: + return .Network_Unreachable + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Set_Blocking_Error :: enum c.int { - None = 0, - Not_Descriptor = cast(c.int)freebsd.Errno.EBADF, - Wrong_Descriptor = cast(c.int)freebsd.Errno.ENOTTY, +_udp_send_error :: proc(errno: freebsd.Errno) -> UDP_Send_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .EACCES, .ENOTSOCK, .EFAULT, .EMSGSIZE: + return .Invalid_Argument + case .ENOBUFS: + return .Insufficient_Resources + case .ECONNRESET, .EPIPE: + return .Connection_Refused + case .EHOSTUNREACH: + return .Host_Unreachable + case .EHOSTDOWN: + return .Host_Unreachable + case .ENETDOWN: + return .Network_Unreachable + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } +} + +_shutdown_error :: proc(errno: freebsd.Errno) -> Shutdown_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .EINVAL, .ENOTSOCK, .ENOTCONN: + return .Invalid_Argument + case: + return .Unknown + } +} + +_socket_info_error :: proc(errno: freebsd.Errno) -> Socket_Info_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .ENOTSOCK, .EINVAL, .EFAULT: + return .Invalid_Argument + case .ENOTCONN: + return .Network_Unreachable + case .ECONNRESET: + return .Connection_Closed + case .ENOBUFS: + return .Insufficient_Resources + case: + return .Unknown + } +} + +_socket_option_error :: proc(errno: freebsd.Errno) -> Socket_Option_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .ENOMEM, .ENOBUFS: + return .Insufficient_Resources + case .EBADF, .ENOTSOCK: + return .Invalid_Socket + case .ENOPROTOOPT: + return .Invalid_Option + case .EINVAL, .EFAULT: + return .Invalid_Value + case: + return .Unknown + } +} + +_set_blocking_error :: proc(errno: freebsd.Errno) -> Set_Blocking_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .ENOTTY: + return .Invalid_Argument + case: + return .Unknown + } } diff --git a/core/net/errors_linux.odin b/core/net/errors_linux.odin index 3cd51e6fd..258560595 100644 --- a/core/net/errors_linux.odin +++ b/core/net/errors_linux.odin @@ -21,181 +21,285 @@ package net Feoramund: FreeBSD platform code */ -import "core:c" +import "core:reflect" import "core:sys/linux" -Create_Socket_Error :: enum c.int { - None = 0, - Family_Not_Supported_For_This_Socket = c.int(linux.Errno.EAFNOSUPPORT), - No_Socket_Descriptors_Available = c.int(linux.Errno.EMFILE), - No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), - No_Memory_Available_Available = c.int(linux.Errno.ENOMEM), - Protocol_Unsupported_By_System = c.int(linux.Errno.EPROTONOSUPPORT), - Wrong_Protocol_For_Socket = c.int(linux.Errno.EPROTONOSUPPORT), - Family_And_Socket_Type_Mismatch = c.int(linux.Errno.EPROTONOSUPPORT), +@(private="file", thread_local) +_last_error: linux.Errno + +_last_platform_error :: proc() -> i32 { + return i32(_last_error) } -Dial_Error :: enum c.int { - None = 0, - Port_Required = -1, - - Address_In_Use = c.int(linux.Errno.EADDRINUSE), - In_Progress = c.int(linux.Errno.EINPROGRESS), - Cannot_Use_Any_Address = c.int(linux.Errno.EADDRNOTAVAIL), - Wrong_Family_For_Socket = c.int(linux.Errno.EAFNOSUPPORT), - Refused = c.int(linux.Errno.ECONNREFUSED), - Is_Listening_Socket = c.int(linux.Errno.EACCES), - Already_Connected = c.int(linux.Errno.EISCONN), - Network_Unreachable = c.int(linux.Errno.ENETUNREACH), // Device is offline - Host_Unreachable = c.int(linux.Errno.EHOSTUNREACH), // Remote host cannot be reached - No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), - Not_Socket = c.int(linux.Errno.ENOTSOCK), - Timeout = c.int(linux.Errno.ETIMEDOUT), - - // TODO: we may need special handling for this; maybe make a socket a struct with metadata? - Would_Block = c.int(linux.Errno.EWOULDBLOCK), +_last_platform_error_string :: proc() -> string { + description, _ := reflect.enum_name_from_value(_last_error) + return description } -Bind_Error :: enum c.int { - None = 0, - Address_In_Use = c.int(linux.Errno.EADDRINUSE), // Another application is currently bound to this endpoint. - Given_Nonlocal_Address = c.int(linux.Errno.EADDRNOTAVAIL), // The address is not a local address on this machine. - Broadcast_Disabled = c.int(linux.Errno.EACCES), // To bind a UDP socket to the broadcast address, the appropriate socket option must be set. - Address_Family_Mismatch = c.int(linux.Errno.EFAULT), // The address family of the address does not match that of the socket. - Already_Bound = c.int(linux.Errno.EINVAL), // The socket is already bound to an address. - No_Ports_Available = c.int(linux.Errno.ENOBUFS), // There are not enough ephemeral ports available. +_set_last_platform_error :: proc(err: i32) { + _last_error = linux.Errno(err) } -Listen_Error :: enum c.int { - None = 0, - Address_In_Use = c.int(linux.Errno.EADDRINUSE), - Already_Connected = c.int(linux.Errno.EISCONN), - No_Socket_Descriptors_Available = c.int(linux.Errno.EMFILE), - No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), - Nonlocal_Address = c.int(linux.Errno.EADDRNOTAVAIL), - Not_Socket = c.int(linux.Errno.ENOTSOCK), - Listening_Not_Supported_For_This_Socket = c.int(linux.Errno.EOPNOTSUPP), +_create_socket_error :: proc(errno: linux.Errno) -> Create_Socket_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EMFILE, .ENFILE, .ENOBUFS, .EPROTONOSUPPORT: + return .Insufficient_Resources + case .EAFNOSUPPORT, .EPROTOTYPE: + return .Invalid_Argument + case .EACCES, .EPERM: + return .Insufficient_Permissions + case: + return .Unknown + } } -Accept_Error :: enum c.int { - None = 0, - Not_Listening = c.int(linux.Errno.EINVAL), - No_Socket_Descriptors_Available_For_Client_Socket = c.int(linux.Errno.EMFILE), - No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), - Not_Socket = c.int(linux.Errno.ENOTSOCK), - Not_Connection_Oriented_Socket = c.int(linux.Errno.EOPNOTSUPP), +_dial_error :: proc(errno: linux.Errno) -> Dial_Error { + assert(errno != nil) + _last_error = errno - // TODO: we may need special handling for this; maybe make a socket a struct with metadata? - Would_Block = c.int(linux.Errno.EWOULDBLOCK), + #partial switch errno { + case .EAGAIN: + return .Insufficient_Resources + case .EBADF, .EINVAL, .ENOTSOCK, .EADDRNOTAVAIL, .EAFNOSUPPORT, .EFAULT: + return .Invalid_Argument + case .EISCONN: + return .Already_Connected + case .EALREADY: + return .Already_Connecting + case .EADDRINUSE: + return .Address_In_Use + case .ENETUNREACH: + return .Network_Unreachable + case .EHOSTUNREACH: + return .Host_Unreachable + case .ECONNREFUSED: + return .Refused + case .ECONNRESET: + return .Reset + case .ETIMEDOUT: + return .Timeout + case .EINPROGRESS: + return .Would_Block + case .EINTR: + return .Interrupted + case .EACCES: + return .Broadcast_Not_Supported + case: + return .Unknown + } } -TCP_Recv_Error :: enum c.int { - None = 0, - Shutdown = c.int(linux.Errno.ESHUTDOWN), - Not_Connected = c.int(linux.Errno.ENOTCONN), - Connection_Broken = c.int(linux.Errno.ENETRESET), - Not_Socket = c.int(linux.Errno.ENOTSOCK), - Aborted = c.int(linux.Errno.ECONNABORTED), +_bind_error :: proc(errno: linux.Errno) -> Bind_Error { + assert(errno != nil) + _last_error = errno - // TODO(tetra): Determine when this is different from the syscall returning n=0 and maybe normalize them? - Connection_Closed = c.int(linux.Errno.ECONNRESET), - Offline = c.int(linux.Errno.ENETDOWN), - Host_Unreachable = c.int(linux.Errno.EHOSTUNREACH), - Interrupted = c.int(linux.Errno.EINTR), - Timeout = c.int(linux.Errno.EWOULDBLOCK), // NOTE: No, really. Presumably this means something different for nonblocking sockets... + #partial switch errno { + case .EAGAIN, .ENOTSOCK, .EADDRNOTAVAIL, .EAFNOSUPPORT, .EFAULT: + return .Insufficient_Resources + case .EINVAL: + return .Already_Bound + case .EBADF: + return .Invalid_Argument + case .EACCES: + return .Insufficient_Permissions_For_Address + case .EADDRINUSE: + return .Address_In_Use + case: + return .Unknown + } } -UDP_Recv_Error :: enum c.int { - None = 0, +_listen_error :: proc(errno: linux.Errno) -> Listen_Error { + assert(errno != nil) + _last_error = errno - Buffer_Too_Small = c.int(linux.Errno.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost. - Not_Socket = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket. - Not_Descriptor = c.int(linux.Errno.EBADF), // The so-called socket is, in fact, not even a valid descriptor. - Bad_Buffer = c.int(linux.Errno.EFAULT), // The buffer did not point to a valid location in memory. - Interrupted = c.int(linux.Errno.EINTR), // A signal occurred before any data was transmitted. See signal(7). - - // The send timeout duration passed before all data was received. See Socket_Option.Receive_Timeout. - // NOTE: No, really. Presumably this means something different for nonblocking sockets... - Timeout = c.int(linux.Errno.EWOULDBLOCK), - Socket_Not_Bound = c.int(linux.Errno.EINVAL), // The socket must be bound for this operation, but isn't. + #partial switch errno { + case .EBADF, .ENOTSOCK: + return .Invalid_Argument + case .EDESTADDRREQ, .EOPNOTSUPP: + return .Unsupported_Socket + case .EINVAL: + return .Already_Connected + case: + return .Unknown + } } -TCP_Send_Error :: enum c.int { - None = 0, - Aborted = c.int(linux.Errno.ECONNABORTED), - Connection_Closed = c.int(linux.Errno.ECONNRESET), - Not_Connected = c.int(linux.Errno.ENOTCONN), - Shutdown = c.int(linux.Errno.ESHUTDOWN), +_accept_error :: proc(errno: linux.Errno) -> Accept_Error { + assert(errno != nil) + _last_error = errno - // The send queue was full. - // This is usually a transient issue. - // - // This also shouldn't normally happen on Linux, as data is dropped if it - // doesn't fit in the send queue. - No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), - Offline = c.int(linux.Errno.ENETDOWN), - Host_Unreachable = c.int(linux.Errno.EHOSTUNREACH), - Interrupted = c.int(linux.Errno.EINTR), // A signal occurred before any data was transmitted. See signal(7). - Timeout = c.int(linux.Errno.EWOULDBLOCK), // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. - Not_Socket = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket. + #partial switch errno { + case .EMFILE, .ENFILE, .ENOBUFS, .ENOMEM: + return .Insufficient_Resources + case .EBADF, .ENOTSOCK, .EFAULT: + return .Invalid_Argument + case .EINVAL: + return .Not_Listening + case .ECONNABORTED: + return .Aborted + case .EWOULDBLOCK: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -// TODO -UDP_Send_Error :: enum c.int { - None = 0, - Message_Too_Long = c.int(linux.Errno.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent. +_tcp_recv_error :: proc(errno: linux.Errno) -> TCP_Recv_Error { + assert(errno != nil) + _last_error = errno - // TODO: not sure what the exact circumstances for this is yet - Network_Unreachable = c.int(linux.Errno.ENETUNREACH), - No_Outbound_Ports_Available = c.int(linux.Errno.EAGAIN), // There are no more emphemeral outbound ports available to bind the socket to, in order to send. - - // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout. - // NOTE: No, really. Presumably this means something different for nonblocking sockets... - Timeout = c.int(linux.Errno.EWOULDBLOCK), - Not_Socket = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket. - Not_Descriptor = c.int(linux.Errno.EBADF), // The so-called socket is, in fact, not even a valid descriptor. - Bad_Buffer = c.int(linux.Errno.EFAULT), // The buffer did not point to a valid location in memory. - Interrupted = c.int(linux.Errno.EINTR), // A signal occurred before any data was transmitted. See signal(7). - - // The send queue was full. - // This is usually a transient issue. - // - // This also shouldn't normally happen on Linux, as data is dropped if it - // doesn't fit in the send queue. - No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS), - No_Memory_Available = c.int(linux.Errno.ENOMEM), // No memory was available to properly manage the send queue. + #partial switch errno { + case .EBADF, .ENOTSOCK, .EFAULT: + return .Invalid_Argument + case .ENOTCONN: + return .Not_Connected + case .ECONNREFUSED, .ECONNRESET: + return .Connection_Closed + case .ETIMEDOUT: + return .Timeout + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -// TODO(flysand): slight regression -Shutdown_Manner :: enum c.int { - Receive = c.int(linux.Shutdown_How.RD), - Send = c.int(linux.Shutdown_How.WR), - Both = c.int(linux.Shutdown_How.RDWR), +_udp_recv_error :: proc(errno: linux.Errno) -> UDP_Recv_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .ENOTSOCK, .EFAULT: + return .Invalid_Argument + case .ECONNREFUSED, .ENOTCONN, .ECONNRESET: + return .Connection_Refused + case .ETIMEDOUT: + return .Timeout + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Shutdown_Error :: enum c.int { - None = 0, - Aborted = c.int(linux.Errno.ECONNABORTED), - Reset = c.int(linux.Errno.ECONNRESET), - Offline = c.int(linux.Errno.ENETDOWN), - Not_Connected = c.int(linux.Errno.ENOTCONN), - Not_Socket = c.int(linux.Errno.ENOTSOCK), - Invalid_Manner = c.int(linux.Errno.EINVAL), +_tcp_send_error :: proc(errno: linux.Errno) -> TCP_Send_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .EACCES, .ENOTSOCK, .EFAULT, .EMSGSIZE, .EDESTADDRREQ, .EINVAL, .EISCONN, .EOPNOTSUPP: + return .Invalid_Argument + case .ENOBUFS, .ENOMEM: + return .Insufficient_Resources + case .ECONNRESET, .EPIPE: + return .Connection_Closed + case .ENOTCONN: + return .Not_Connected + case .EHOSTUNREACH: + return .Host_Unreachable + case .EHOSTDOWN: + return .Host_Unreachable + case .ENETDOWN: + return .Network_Unreachable + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Socket_Option_Error :: enum c.int { - None = 0, - Offline = c.int(linux.Errno.ENETDOWN), - Timeout_When_Keepalive_Set = c.int(linux.Errno.ENETRESET), - Invalid_Option_For_Socket = c.int(linux.Errno.ENOPROTOOPT), - Reset_When_Keepalive_Set = c.int(linux.Errno.ENOTCONN), - Not_Socket = c.int(linux.Errno.ENOTSOCK), +_udp_send_error :: proc(errno: linux.Errno) -> UDP_Send_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .EACCES, .ENOTSOCK, .EFAULT, .EMSGSIZE, .EDESTADDRREQ, .EINVAL, .EISCONN, .EOPNOTSUPP: + return .Invalid_Argument + case .ENOBUFS, .ENOMEM: + return .Insufficient_Resources + case .ECONNRESET, .EPIPE: + return .Connection_Refused + case .EHOSTUNREACH: + return .Host_Unreachable + case .EHOSTDOWN: + return .Host_Unreachable + case .ENETDOWN: + return .Network_Unreachable + case .EAGAIN: + return .Would_Block + case .EINTR: + return .Interrupted + case: + return .Unknown + } } -Set_Blocking_Error :: enum c.int { - None = 0, +_shutdown_error :: proc(errno: linux.Errno) -> Shutdown_Error { + assert(errno != nil) + _last_error = errno - // TODO: add errors occuring on followig calls: - // flags, _ := linux.Errno.fcntl(sd, linux.Errno.F_GETFL, 0) - // linux.Errno.fcntl(sd, linux.Errno.F_SETFL, flags | int(linux.Errno.O_NONBLOCK)) -} \ No newline at end of file + #partial switch errno { + case .EBADF, .EINVAL, .ENOTSOCK, .ENOTCONN: + return .Invalid_Argument + case: + return .Unknown + } +} + +_socket_info_error :: proc(errno: linux.Errno) -> Socket_Info_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF, .ENOTSOCK, .EFAULT, .EINVAL: + return .Invalid_Argument + case .ENOTCONN: + return .Network_Unreachable + case .ENOBUFS: + return .Insufficient_Resources + case: + return .Unknown + } +} + +_socket_option_error :: proc(errno: linux.Errno) -> Socket_Option_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .ENOMEM, .ENOBUFS: + return .Insufficient_Resources + case .EBADF, .ENOTSOCK: + return .Invalid_Socket + case .ENOPROTOOPT, .EINVAL: + return .Invalid_Option + case .EFAULT, .EDOM: + return .Invalid_Value + case: + return .Unknown + } +} + +_set_blocking_error :: proc(errno: linux.Errno) -> Set_Blocking_Error { + assert(errno != nil) + _last_error = errno + + #partial switch errno { + case .EBADF: + return .Invalid_Argument + case: + return .Unknown + } +} diff --git a/core/net/errors_others.odin b/core/net/errors_others.odin new file mode 100644 index 000000000..b80ead79c --- /dev/null +++ b/core/net/errors_others.odin @@ -0,0 +1,27 @@ +#+build !darwin +#+build !linux +#+build !freebsd +#+build !windows +package net + +@(private="file", thread_local) +_last_error: i32 + +_last_platform_error :: proc() -> i32 { + return _last_error +} + +_last_platform_error_string :: proc() -> string { + return "" +} + +_set_last_platform_error :: proc(err: i32) { + _last_error = err +} + +Parse_Endpoint_Error :: enum u32 { + None = 0, + Bad_Port = 1, + Bad_Address, + Bad_Hostname, +} \ No newline at end of file diff --git a/core/net/errors_windows.odin b/core/net/errors_windows.odin index f41bcf888..8e0e4cda3 100644 --- a/core/net/errors_windows.odin +++ b/core/net/errors_windows.odin @@ -20,250 +20,253 @@ package net Feoramund: FreeBSD platform code */ -import "core:c" +import "core:reflect" import win "core:sys/windows" -Create_Socket_Error :: enum c.int { - None = 0, - Network_Subsystem_Failure = win.WSAENETDOWN, - Family_Not_Supported_For_This_Socket = win.WSAEAFNOSUPPORT, - No_Socket_Descriptors_Available = win.WSAEMFILE, - No_Buffer_Space_Available = win.WSAENOBUFS, - Protocol_Unsupported_By_System = win.WSAEPROTONOSUPPORT, - Wrong_Protocol_For_Socket = win.WSAEPROTOTYPE, - Family_And_Socket_Type_Mismatch = win.WSAESOCKTNOSUPPORT, +_last_platform_error :: proc() -> i32 { + return i32(win.WSAGetLastError()) } -Dial_Error :: enum c.int { - None = 0, - Port_Required = -1, - Address_In_Use = win.WSAEADDRINUSE, - In_Progress = win.WSAEALREADY, - Cannot_Use_Any_Address = win.WSAEADDRNOTAVAIL, - Wrong_Family_For_Socket = win.WSAEAFNOSUPPORT, - Refused = win.WSAECONNREFUSED, - Is_Listening_Socket = win.WSAEINVAL, - Already_Connected = win.WSAEISCONN, - Network_Unreachable = win.WSAENETUNREACH, // Device is offline - Host_Unreachable = win.WSAEHOSTUNREACH, // Remote host cannot be reached - No_Buffer_Space_Available = win.WSAENOBUFS, - Not_Socket = win.WSAENOTSOCK, - Timeout = win.WSAETIMEDOUT, - Would_Block = win.WSAEWOULDBLOCK, // TODO: we may need special handling for this; maybe make a socket a struct with metadata? +_last_platform_error_string :: proc() -> string { + description, _ := reflect.enum_name_from_value(win.System_Error(win.WSAGetLastError())) + return description } -Bind_Error :: enum c.int { - None = 0, - Address_In_Use = win.WSAEADDRINUSE, // Another application is currently bound to this endpoint. - Given_Nonlocal_Address = win.WSAEADDRNOTAVAIL, // The address is not a local address on this machine. - Broadcast_Disabled = win.WSAEACCES, // To bind a UDP socket to the broadcast address, the appropriate socket option must be set. - Address_Family_Mismatch = win.WSAEFAULT, // The address family of the address does not match that of the socket. - Already_Bound = win.WSAEINVAL, // The socket is already bound to an address. - No_Ports_Available = win.WSAENOBUFS, // There are not enough ephemeral ports available. +_set_last_platform_error :: proc(err: i32) { + win.WSASetLastError(err) } -Listen_Error :: enum c.int { - None = 0, - Address_In_Use = win.WSAEADDRINUSE, - Already_Connected = win.WSAEISCONN, - No_Socket_Descriptors_Available = win.WSAEMFILE, - No_Buffer_Space_Available = win.WSAENOBUFS, - Nonlocal_Address = win.WSAEADDRNOTAVAIL, - Not_Socket = win.WSAENOTSOCK, - Listening_Not_Supported_For_This_Socket = win.WSAEOPNOTSUPP, +_create_socket_error :: proc() -> Create_Socket_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSANOTINITIALISED, .WSAENETDOWN, .WSAEINVALIDPROVIDER, .WSAEINVALIDPROCTABLE, .WSAEPROVIDERFAILEDINIT: + return .Network_Unreachable + case .WSAEAFNOSUPPORT, .WSAEINPROGRESS, .WSAEINVAL, .WSAEPROTOTYPE, .WSAESOCKTNOSUPPORT: + return .Invalid_Argument + case .WSAEMFILE, .WSAENOBUFS, .WSAEPROTONOSUPPORT: + return .Insufficient_Resources + case: + return .Unknown + } } -Accept_Error :: enum c.int { - None = 0, - Not_Listening = win.WSAEINVAL, - No_Socket_Descriptors_Available_For_Client_Socket = win.WSAEMFILE, - No_Buffer_Space_Available = win.WSAENOBUFS, - Not_Socket = win.WSAENOTSOCK, - Not_Connection_Oriented_Socket = win.WSAEOPNOTSUPP, - - // TODO: we may need special handling for this; maybe make a socket a struct with metadata? - Would_Block = win.WSAEWOULDBLOCK, +_dial_error :: proc() -> Dial_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSANOTINITIALISED, .WSAENETDOWN: + return .Network_Unreachable + case .WSAEADDRINUSE: + return .Address_In_Use + case .WSAEINTR: + return .Interrupted + case .WSAEWOULDBLOCK: + return .Would_Block + case .WSAEALREADY: + return .Already_Connecting + case .WSAEADDRNOTAVAIL, .WSAEAFNOSUPPORT, .WSAEFAULT, .WSAENOTSOCK, .WSAEINPROGRESS, .WSAEINVAL: + return .Invalid_Argument + case .WSAECONNREFUSED: + return .Refused + case .WSAEISCONN: + return .Already_Connected + case .WSAEHOSTUNREACH: + return .Host_Unreachable + case .WSAENOBUFS: + return .Insufficient_Resources + case .WSAETIMEDOUT: + return .Timeout + case .WSAEACCES: + return .Broadcast_Not_Supported + case: + return .Unknown + } } -TCP_Recv_Error :: enum c.int { - None = 0, - Network_Subsystem_Failure = win.WSAENETDOWN, - Not_Connected = win.WSAENOTCONN, - Bad_Buffer = win.WSAEFAULT, - Keepalive_Failure = win.WSAENETRESET, - Not_Socket = win.WSAENOTSOCK, - Shutdown = win.WSAESHUTDOWN, - Would_Block = win.WSAEWOULDBLOCK, - Aborted = win.WSAECONNABORTED, - Timeout = win.WSAETIMEDOUT, - - // TODO(tetra): Determine when this is different from the syscall returning n=0 and maybe normalize them? - Connection_Closed = win.WSAECONNRESET, - - // TODO: verify can actually happen - Host_Unreachable = win.WSAEHOSTUNREACH, +_bind_error :: proc() -> Bind_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSANOTINITIALISED, .WSAENETDOWN: + return .Network_Unreachable + case .WSAEADDRINUSE: + return .Address_In_Use + case .WSAEADDRNOTAVAIL, .WSAEFAULT, .WSAEINPROGRESS, .WSAEACCES, .WSAEINVAL, .WSAENOTSOCK: + return .Invalid_Argument + case: + return .Unknown + } } -UDP_Recv_Error :: enum c.int { - None = 0, - Network_Subsystem_Failure = win.WSAENETDOWN, - Aborted = win.WSAECONNABORTED, - Buffer_Too_Small = win.WSAEMSGSIZE, // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost. - Remote_Not_Listening = win.WSAECONNRESET, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data. - Shutdown = win.WSAESHUTDOWN, - Broadcast_Disabled = win.WSAEACCES, // A broadcast address was specified, but the .Broadcast socket option isn't set. - Bad_Buffer = win.WSAEFAULT, - No_Buffer_Space_Available = win.WSAENOBUFS, - Not_Socket = win.WSAENOTSOCK, // The socket is not valid socket handle. - Would_Block = win.WSAEWOULDBLOCK, - Host_Unreachable = win.WSAEHOSTUNREACH, // The remote host cannot be reached from this host at this time. - Offline = win.WSAENETUNREACH, // The network cannot be reached from this host at this time. - Timeout = win.WSAETIMEDOUT, - - // TODO: can this actually happen? The socket isn't bound; an unknown flag specified; or MSG_OOB specified with SO_OOBINLINE enabled. - Incorrectly_Configured = win.WSAEINVAL, - TTL_Expired = win.WSAENETRESET, // The message took more hops than was allowed (the Time To Live) to reach the remote endpoint. +_listen_error :: proc() -> Listen_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSANOTINITIALISED, .WSAENETDOWN: + return .Network_Unreachable + case .WSAEMFILE, .WSAENOBUFS: + return .Insufficient_Resources + case .WSAEADDRINUSE: + return .Address_In_Use + case .WSAEINPROGRESS, .WSAENOTSOCK: + return .Invalid_Argument + case .WSAEISCONN: + return .Already_Connected + case .WSAEOPNOTSUPP, .WSAEINVAL: + return .Unsupported_Socket + case: + return .Unknown + } } -// TODO: consider merging some errors to make handling them easier -// TODO: verify once more what errors to actually expose -TCP_Send_Error :: enum c.int { - None = 0, - - Aborted = win.WSAECONNABORTED, - Not_Connected = win.WSAENOTCONN, - Shutdown = win.WSAESHUTDOWN, - Connection_Closed = win.WSAECONNRESET, - No_Buffer_Space_Available = win.WSAENOBUFS, - Network_Subsystem_Failure = win.WSAENETDOWN, - Host_Unreachable = win.WSAEHOSTUNREACH, - Would_Block = win.WSAEWOULDBLOCK, - - // TODO: verify possible, as not mentioned in docs - Offline = win.WSAENETUNREACH, - Timeout = win.WSAETIMEDOUT, - - // A broadcast address was specified, but the .Broadcast socket option isn't set. - Broadcast_Disabled = win.WSAEACCES, - Bad_Buffer = win.WSAEFAULT, - - // Connection is broken due to keepalive activity detecting a failure during the operation. - Keepalive_Failure = win.WSAENETRESET, // TODO: not functionally different from Reset; merge? - Not_Socket = win.WSAENOTSOCK, // The so-called socket is not an open socket. +_accept_error :: proc() -> Accept_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSANOTINITIALISED, .WSAENETDOWN: + return .Network_Unreachable + case .WSAEMFILE, .WSAENOBUFS: + return .Insufficient_Resources + case .WSAECONNRESET: + return .Aborted + case .WSAEFAULT, .WSAEINPROGRESS, .WSAENOTSOCK: + return .Invalid_Argument + case .WSAEINTR: + return .Interrupted + case .WSAEINVAL: + return .Not_Listening + case .WSAEWOULDBLOCK: + return .Would_Block + case .WSAEOPNOTSUPP: + return .Unsupported_Socket + case: + return .Unknown + } } -UDP_Send_Error :: enum c.int { - None = 0, - Network_Subsystem_Failure = win.WSAENETDOWN, - - Aborted = win.WSAECONNABORTED, - Message_Too_Long = win.WSAEMSGSIZE, // The message is larger than the maximum UDP packet size. - Remote_Not_Listening = win.WSAECONNRESET, // The machine at the remote endpoint doesn't have the given port open to receiving UDP data. - Shutdown = win.WSAESHUTDOWN, // A broadcast address was specified, but the .Broadcast socket option isn't set. - Broadcast_Disabled = win.WSAEACCES, - Bad_Buffer = win.WSAEFAULT, // Connection is broken due to keepalive activity detecting a failure during the operation. - - // TODO: not functionally different from Reset; merge? - Keepalive_Failure = win.WSAENETRESET, - No_Buffer_Space_Available = win.WSAENOBUFS, - Not_Socket = win.WSAENOTSOCK, // The socket is not valid socket handle. - - // This socket is unidirectional and cannot be used to send any data. - // TODO: verify possible; decide whether to keep if not - Receive_Only = win.WSAEOPNOTSUPP, - Would_Block = win.WSAEWOULDBLOCK, - Host_Unreachable = win.WSAEHOSTUNREACH, // The remote host cannot be reached from this host at this time. - Cannot_Use_Any_Address = win.WSAEADDRNOTAVAIL, // Attempt to send to the Any address. - Family_Not_Supported_For_This_Socket = win.WSAEAFNOSUPPORT, // The address is of an incorrect address family for this socket. - Offline = win.WSAENETUNREACH, // The network cannot be reached from this host at this time. - Timeout = win.WSAETIMEDOUT, +_tcp_recv_error :: proc() -> TCP_Recv_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSANOTINITIALISED, .WSAENETDOWN: + return .Network_Unreachable + case .WSAEFAULT, .WSAEINPROGRESS, .WSAENOTSOCK, .WSAEMSGSIZE, .WSAEINVAL, .WSAEOPNOTSUPP: + return .Invalid_Argument + case .WSAENOTCONN: + return .Not_Connected + case .WSAEINTR: + return .Interrupted + case .WSAENETRESET, .WSAESHUTDOWN, .WSAECONNABORTED, .WSAECONNRESET: + return .Connection_Closed + case .WSAEWOULDBLOCK: + return .Would_Block + case .WSAETIMEDOUT: + return .Timeout + case: + return .Unknown + } } -Shutdown_Manner :: enum c.int { - Receive = win.SD_RECEIVE, - Send = win.SD_SEND, - Both = win.SD_BOTH, +_udp_recv_error :: proc() -> UDP_Recv_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSANOTINITIALISED, .WSAENETDOWN: + return .Network_Unreachable + case .WSAEFAULT, .WSAEINPROGRESS, .WSAEINVAL, .WSAEISCONN, .WSAENOTSOCK, .WSAEOPNOTSUPP, .WSAEMSGSIZE: + return .Invalid_Argument + case .WSAEINTR: + return .Interrupted + case .WSAENETRESET, .WSAESHUTDOWN, .WSAECONNRESET: + return .Connection_Refused + case .WSAEWOULDBLOCK: + return .Would_Block + case .WSAETIMEDOUT: + return .Timeout + case: + return .Unknown + } } -Shutdown_Error :: enum c.int { - None = 0, - Aborted = win.WSAECONNABORTED, - Reset = win.WSAECONNRESET, - Offline = win.WSAENETDOWN, - Not_Connected = win.WSAENOTCONN, - Not_Socket = win.WSAENOTSOCK, - Invalid_Manner = win.WSAEINVAL, +_tcp_send_error :: proc() -> TCP_Send_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSANOTINITIALISED, .WSAENETDOWN: + return .Network_Unreachable + case .WSAENOBUFS: + return .Insufficient_Resources + case .WSAEACCES, .WSAEINPROGRESS, .WSAEFAULT, .WSAENOTSOCK, .WSAEOPNOTSUPP, .WSAEMSGSIZE, .WSAEINVAL: + return .Invalid_Argument + case .WSAEINTR: + return .Interrupted + case .WSAENETRESET, .WSAESHUTDOWN, .WSAECONNABORTED, .WSAECONNRESET: + return .Connection_Closed + case .WSAENOTCONN: + return .Not_Connected + case .WSAEWOULDBLOCK: + return .Would_Block + case .WSAETIMEDOUT: + return .Timeout + case .WSAEHOSTUNREACH: + return .Host_Unreachable + case: + return .Unknown + } } -Socket_Option :: enum c.int { - // bool: Whether the address that this socket is bound to can be reused by other sockets. - // This allows you to bypass the cooldown period if a program dies while the socket is bound. - Reuse_Address = win.SO_REUSEADDR, - - // bool: Whether other programs will be inhibited from binding the same endpoint as this socket. - Exclusive_Addr_Use = win.SO_EXCLUSIVEADDRUSE, - - // bool: When true, keepalive packets will be automatically be sent for this connection. TODO: verify this understanding - Keep_Alive = win.SO_KEEPALIVE, - - // bool: When true, client connections will immediately be sent a TCP/IP RST response, rather than being accepted. - Conditional_Accept = win.SO_CONDITIONAL_ACCEPT, - - // bool: If true, when the socket is closed, but data is still waiting to be sent, discard that data. - Dont_Linger = win.SO_DONTLINGER, - - // bool: When true, 'out-of-band' data sent over the socket will be read by a normal net.recv() call, the same as normal 'in-band' data. - Out_Of_Bounds_Data_Inline = win.SO_OOBINLINE, - - // bool: When true, disables send-coalescing, therefore reducing latency. - TCP_Nodelay = win.TCP_NODELAY, - - // win.LINGER: Customizes how long (if at all) the socket will remain open when there - // is some remaining data waiting to be sent, and net.close() is called. - Linger = win.SO_LINGER, - - // win.DWORD: The size, in bytes, of the OS-managed receive-buffer for this socket. - Receive_Buffer_Size = win.SO_RCVBUF, - - // win.DWORD: The size, in bytes, of the OS-managed send-buffer for this socket. - Send_Buffer_Size = win.SO_SNDBUF, - - // win.DWORD: For blocking sockets, the time in milliseconds to wait for incoming data to be received, before giving up and returning .Timeout. - // For non-blocking sockets, ignored. - // Use a value of zero to potentially wait forever. - Receive_Timeout = win.SO_RCVTIMEO, - - // win.DWORD: For blocking sockets, the time in milliseconds to wait for outgoing data to be sent, before giving up and returning .Timeout. - // For non-blocking sockets, ignored. - // Use a value of zero to potentially wait forever. - Send_Timeout = win.SO_SNDTIMEO, - - // bool: Allow sending to, receiving from, and binding to, a broadcast address. - Broadcast = win.SO_BROADCAST, +_udp_send_error :: proc() -> UDP_Send_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSANOTINITIALISED, .WSAENETDOWN, .WSAENETUNREACH: + return .Network_Unreachable + case .WSAENOBUFS: + return .Insufficient_Resources + case .WSAEACCES, .WSAEINVAL, .WSAEINPROGRESS, .WSAEFAULT, .WSAENOTCONN, .WSAENOTSOCK, .WSAEOPNOTSUPP, .WSAEADDRNOTAVAIL, .WSAEAFNOSUPPORT, .WSAEDESTADDRREQ: + return .Invalid_Argument + case .WSAEINTR: + return .Interrupted + case .WSAENETRESET, .WSAESHUTDOWN, .WSAECONNRESET: + return .Connection_Refused + case .WSAEWOULDBLOCK: + return .Would_Block + case .WSAETIMEDOUT: + return .Timeout + case: + return .Unknown + } } -Socket_Option_Error :: enum c.int { - None = 0, - Linger_Only_Supports_Whole_Seconds = 1, - - // The given value is too big or small to be given to the OS. - Value_Out_Of_Range, - - Network_Subsystem_Failure = win.WSAENETDOWN, - Timeout_When_Keepalive_Set = win.WSAENETRESET, - Invalid_Option_For_Socket = win.WSAENOPROTOOPT, - Reset_When_Keepalive_Set = win.WSAENOTCONN, - Not_Socket = win.WSAENOTSOCK, +_shutdown_error :: proc() -> Shutdown_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSAENETDOWN, .WSANOTINITIALISED: + return .Network_Unreachable + case .WSAECONNABORTED, .WSAECONNRESET: + return .Connection_Closed + case .WSAEINPROGRESS, .WSAEINVAL, .WSAENOTCONN, .WSAENOTSOCK: + return .Invalid_Argument + case: + return .Unknown + } } -Set_Blocking_Error :: enum c.int { - None = 0, +_socket_info_error :: proc() -> Socket_Info_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSAEFAULT, .WSAEINPROGRESS, .WSAENOTSOCK, .WSAEINVAL: + return .Invalid_Argument + case .WSANOTINITIALISED, .WSAENETDOWN, .WSAENOTCONN: + return .Network_Unreachable + case: + return .Unknown + } +} - Network_Subsystem_Failure = win.WSAENETDOWN, - Blocking_Call_In_Progress = win.WSAEINPROGRESS, - Not_Socket = win.WSAENOTSOCK, +_socket_option_error :: proc() -> Socket_Option_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSAENETDOWN, .WSANOTINITIALISED: + return .Network_Unreachable + case .WSAEFAULT, .WSAEINVAL: + return .Invalid_Value + case .WSAENETRESET, .WSAENOTCONN, .WSAENOTSOCK: + return .Invalid_Socket + case .WSAENOPROTOOPT: + return .Invalid_Option + case: + return .Unknown + } +} - // TODO: are those errors possible? - Network_Subsystem_Not_Initialized = win.WSAENOTINITIALISED, - Invalid_Argument_Pointer = win.WSAEFAULT, -} \ No newline at end of file +_set_blocking_error :: proc() -> Set_Blocking_Error { + #partial switch win.System_Error(win.WSAGetLastError()) { + case .WSAENETDOWN, .WSANOTINITIALISED: + return .Network_Unreachable + case .WSAEINPROGRESS, .WSAENOTSOCK, .WSAEFAULT: + return .Invalid_Argument + case: + return .Unknown + } +} diff --git a/core/net/interface.odin b/core/net/interface.odin index 775a812f3..4d499a008 100644 --- a/core/net/interface.odin +++ b/core/net/interface.odin @@ -27,7 +27,7 @@ MAX_INTERFACE_ENUMERATION_TRIES :: 3 /* `enumerate_interfaces` retrieves a list of network interfaces with their associated properties. */ -enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) { +enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) { return _enumerate_interfaces(allocator) } diff --git a/core/net/interface_darwin.odin b/core/net/interface_darwin.odin index 4921bc3fe..9883c10af 100644 --- a/core/net/interface_darwin.odin +++ b/core/net/interface_darwin.odin @@ -20,60 +20,57 @@ package net Feoramund: FreeBSD platform code */ -import "core:os" import "core:strings" +import "core:sys/posix" + +foreign import lib "system:System" @(private) -_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) { +_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) { context.allocator = allocator - head: ^os.ifaddrs - - if res := os._getifaddrs(&head); res < 0 { + head: ^ifaddrs + if getifaddrs(&head) != .OK { return {}, .Unable_To_Enumerate_Network_Interfaces } + defer freeifaddrs(head) - /* - Unlike Windows, *nix regrettably doesn't return all it knows about an interface in one big struct. - We're going to have to iterate over a list and coalesce information as we go. - */ - ifaces: map[string]^Network_Interface + ifaces: map[string]Network_Interface defer delete(ifaces) for ifaddr := head; ifaddr != nil; ifaddr = ifaddr.next { adapter_name := string(ifaddr.name) - /* - Check if we have seen this interface name before so we can reuse the `Network_Interface`. - Else, create a new one. - */ - if adapter_name not_in ifaces { - ifaces[adapter_name] = new(Network_Interface) - ifaces[adapter_name].adapter_name = strings.clone(adapter_name) + key_ptr, iface, inserted, mem_err := map_entry(&ifaces, adapter_name) + if mem_err == nil && inserted { + key_ptr^, mem_err = strings.clone(adapter_name) + iface.adapter_name = key_ptr^ + } + if mem_err != nil { + return {}, .Allocation_Failure } - iface := ifaces[adapter_name] address: Address netmask: Netmask - if ifaddr.address != nil { - switch int(ifaddr.address.family) { - case os.AF_INET, os.AF_INET6: - address = _sockaddr_basic_to_endpoint(ifaddr.address).address + if ifaddr.addr != nil { + #partial switch ifaddr.addr.sa_family { + case .INET, .INET6: + address = _sockaddr_basic_to_endpoint(ifaddr.addr).address } } if ifaddr.netmask != nil { - switch int(ifaddr.netmask.family) { - case os.AF_INET, os.AF_INET6: + #partial switch ifaddr.netmask.sa_family { + case .INET, .INET6: netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address) } } - if ifaddr.broadcast_or_dest != nil && .BROADCAST in ifaddr.flags { - switch int(ifaddr.broadcast_or_dest.family) { - case os.AF_INET, os.AF_INET6: - broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address + if ifaddr.dstaddr != nil && .BROADCAST in ifaddr.flags { + #partial switch ifaddr.dstaddr.sa_family { + case .INET, .INET6: + broadcast := _sockaddr_basic_to_endpoint(ifaddr.dstaddr).address append(&iface.multicast, broadcast) } } @@ -105,18 +102,51 @@ _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: [] iface.link.state = state } - /* - Free the OS structures. - */ - os._freeifaddrs(head) - - /* - Turn the map into a slice to return. - */ - _interfaces := make([dynamic]Network_Interface, 0, allocator) + interfaces = make([]Network_Interface, len(ifaces)) + i: int for _, iface in ifaces { - append(&_interfaces, iface^) - free(iface) + interfaces[i] = iface + i += 1 } - return _interfaces[:], {} + return interfaces, nil +} + +@(private) +IF_Flag :: enum u32 { + UP, + BROADCAST, + DEBUG, + LOOPBACK, + POINTTOPOINT, + NOTRAILERS, + RUNNING, + NOARP, + PROMISC, + ALLMULTI, + OACTIVE, + SIMPLEX, + LINK0, + LINK1, + LINK2, + MULTICAST, +} + +@(private) +IF_Flags :: bit_set[IF_Flag; u32] + +@(private) +ifaddrs :: struct { + next: ^ifaddrs, + name: cstring, + flags: IF_Flags, + addr: ^posix.sockaddr, + netmask: ^posix.sockaddr, + dstaddr: ^posix.sockaddr, + data: rawptr, +} + +@(private) +foreign lib { + getifaddrs :: proc(ifap: ^^ifaddrs) -> posix.result --- + freeifaddrs :: proc(ifp: ^ifaddrs) --- } diff --git a/core/net/interface_freebsd.odin b/core/net/interface_freebsd.odin index 50e2d1a96..90a538a04 100644 --- a/core/net/interface_freebsd.odin +++ b/core/net/interface_freebsd.odin @@ -25,7 +25,7 @@ import "core:strings" import "core:sys/freebsd" @(private) -_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) { +_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) { // This is a simplified implementation of `getifaddrs` from the FreeBSD // libc using only Odin and syscalls. context.allocator = allocator @@ -50,7 +50,7 @@ _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: [] // Allocate and get the entries. buf, alloc_err := make([]byte, needed) if alloc_err != nil { - return nil, .Unable_To_Enumerate_Network_Interfaces + return nil, .Allocation_Failure } defer delete(buf) diff --git a/core/net/interface_linux.odin b/core/net/interface_linux.odin index 28724735b..e329803c5 100644 --- a/core/net/interface_linux.odin +++ b/core/net/interface_linux.odin @@ -30,7 +30,7 @@ package net // NOTE(flysand): https://man7.org/linux/man-pages/man7/netlink.7.html // apparently musl libc uses this to enumerate network interfaces @(private) -_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) { +_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) { context.allocator = allocator // head: ^os.ifaddrs @@ -143,4 +143,4 @@ _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: [] // } // return _interfaces[:], {} return nil, {} -} \ No newline at end of file +} diff --git a/core/net/interface_windows.odin b/core/net/interface_windows.odin index a6eb72846..571fb322f 100644 --- a/core/net/interface_windows.odin +++ b/core/net/interface_windows.odin @@ -23,7 +23,7 @@ package net import sys "core:sys/windows" import strings "core:strings" -_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) { +_enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Interfaces_Error) { context.allocator = allocator buf: []u8 @@ -52,7 +52,8 @@ _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: [] case 0: break gaa case: - return {}, Platform_Error(res) + set_last_platform_error(i32(res)) + return {}, .Unknown } } @@ -63,13 +64,13 @@ _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: [] _interfaces := make([dynamic]Network_Interface, 0, allocator) for adapter := (^sys.IP_Adapter_Addresses)(raw_data(buf)); adapter != nil; adapter = adapter.Next { friendly_name, err1 := sys.wstring_to_utf8(sys.wstring(adapter.FriendlyName), 256, allocator) - if err1 != nil { return {}, Platform_Error(err1) } + if err1 != nil { return {}, .Allocation_Failure } description, err2 := sys.wstring_to_utf8(sys.wstring(adapter.Description), 256, allocator) - if err2 != nil { return {}, Platform_Error(err2) } + if err2 != nil { return {}, .Allocation_Failure } dns_suffix, err3 := sys.wstring_to_utf8(sys.wstring(adapter.DnsSuffix), 256, allocator) - if err3 != nil { return {}, Platform_Error(err3) } + if err3 != nil { return {}, .Allocation_Failure } interface := Network_Interface{ adapter_name = strings.clone(string(adapter.AdapterName)), @@ -176,4 +177,4 @@ parse_socket_address :: proc(addr_in: sys.SOCKET_ADDRESS) -> (addr: Endpoint) { case: return // Empty or invalid address type } unreachable() -} \ No newline at end of file +} diff --git a/core/net/socket.odin b/core/net/socket.odin index c5ea11e11..f68508169 100644 --- a/core/net/socket.odin +++ b/core/net/socket.odin @@ -35,8 +35,10 @@ any_socket_to_socket :: proc "contextless" (socket: Any_Socket) -> Socket { `a.host.name:9999`, or as `1.2.3.4:9999`, or IP6 equivalent. Calls `parse_hostname_or_endpoint` and `dial_tcp_from_host_or_endpoint`. + + Errors that can be returned: `Parse_Endpoint_Error`, `Resolve_Error`, `DNS_Error`, `Create_Socket_Error`, or `Dial_Error` */ -dial_tcp_from_hostname_and_port_string :: proc(hostname_and_port: string, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) { +dial_tcp_from_hostname_and_port_string :: proc(hostname_and_port: string, options := DEFAULT_TCP_OPTIONS) -> (socket: TCP_Socket, err: Network_Error) { target := parse_hostname_or_endpoint(hostname_and_port) or_return return dial_tcp_from_host_or_endpoint(target, options) @@ -47,8 +49,10 @@ dial_tcp_from_hostname_and_port_string :: proc(hostname_and_port: string, option `parse_hostname_or_endpoint` is called and the `hostname` will be resolved into an IP. If a `hostname` of form `a.host.name:9999` is given, the port will be ignored in favor of the explicit `port` param. + + Errors that can be returned: `Parse_Endpoint_Error`, `Resolve_Error`, `DNS_Error`, `Create_Socket_Error`, or `Dial_Error` */ -dial_tcp_from_hostname_with_port_override :: proc(hostname: string, port: int, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) { +dial_tcp_from_hostname_with_port_override :: proc(hostname: string, port: int, options := DEFAULT_TCP_OPTIONS) -> (socket: TCP_Socket, err: Network_Error) { target := parse_hostname_or_endpoint(hostname) or_return switch &t in target { case Endpoint: @@ -62,8 +66,10 @@ dial_tcp_from_hostname_with_port_override :: proc(hostname: string, port: int, o /* Expects the `host` as Host. + + Errors that can be returned: `Resolve_Error`, `DNS_Error`, `Create_Socket_Error`, or `Dial_Error` */ -dial_tcp_from_host :: proc(host: Host, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) { +dial_tcp_from_host :: proc(host: Host, options := DEFAULT_TCP_OPTIONS) -> (socket: TCP_Socket, err: Network_Error) { if host.port == 0 { return 0, .Port_Required } @@ -76,8 +82,10 @@ dial_tcp_from_host :: proc(host: Host, options := default_tcp_options) -> (socke /* Expects the `target` as a Host_OrEndpoint. Unwraps the underlying type and calls `dial_tcp_from_host` or `dial_tcp_from_endpoint`. + + Errors that can be returned: `Parse_Endpoint_Error`, `Resolve_Error`, `DNS_Error`, `Create_Socket_Error`, or `Dial_Error` */ -dial_tcp_from_host_or_endpoint :: proc(target: Host_Or_Endpoint, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) { +dial_tcp_from_host_or_endpoint :: proc(target: Host_Or_Endpoint, options := DEFAULT_TCP_OPTIONS) -> (socket: TCP_Socket, err: Network_Error) { switch t in target { case Endpoint: return dial_tcp_from_endpoint(t, options) @@ -87,12 +95,21 @@ dial_tcp_from_host_or_endpoint :: proc(target: Host_Or_Endpoint, options := defa unreachable() } -// Dial from an Address -dial_tcp_from_address_and_port :: proc(address: Address, port: int, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) { +/* + Dial from an Address. + + Errors that can be returned: `Create_Socket_Error`, or `Dial_Error` +*/ +dial_tcp_from_address_and_port :: proc(address: Address, port: int, options := DEFAULT_TCP_OPTIONS) -> (socket: TCP_Socket, err: Network_Error) { return dial_tcp_from_endpoint({address, port}, options) } -dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) { +/* + Dial from an Endpoint. + + Errors that can be returned: `Create_Socket_Error`, or `Dial_Error` +*/ +dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := DEFAULT_TCP_OPTIONS) -> (socket: TCP_Socket, err: Network_Error) { return _dial_tcp_from_endpoint(endpoint, options) } @@ -105,11 +122,11 @@ dial_tcp :: proc{ dial_tcp_from_host_or_endpoint, } -create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) { +create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) { return _create_socket(family, protocol) } -bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Network_Error) { +bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Bind_Error) { return _bind(socket, ep) } @@ -119,7 +136,7 @@ bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Network_Error) { This is like a client TCP socket, except that it can send data to any remote endpoint without needing to establish a connection first. */ -make_unbound_udp_socket :: proc(family: Address_Family) -> (socket: UDP_Socket, err: Network_Error) { +make_unbound_udp_socket :: proc(family: Address_Family) -> (socket: UDP_Socket, err: Create_Socket_Error) { sock := create_socket(family, .UDP) or_return socket = sock.(UDP_Socket) return @@ -131,6 +148,8 @@ make_unbound_udp_socket :: proc(family: Address_Family) -> (socket: UDP_Socket, This is like a listening TCP socket, except that data packets can be sent and received without needing to establish a connection first. The `bound_address` is the address of the network interface that you want to use, or a loopback address if you don't care which to use. + + Errors that can be returned: `Parse_Endpoint_Error`, `Create_Socket_Error`, or `Bind_Error` */ make_bound_udp_socket :: proc(bound_address: Address, port: int) -> (socket: UDP_Socket, err: Network_Error) { if bound_address == nil { @@ -141,6 +160,11 @@ make_bound_udp_socket :: proc(bound_address: Address, port: int) -> (socket: UDP return } +/* + Creates a TCP socket and starts listening on the given endpoint. + + Errors that can be returned: `Create_Socket_Error`, `Bind_Error`, or `Listen_Error` +*/ listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: TCP_Socket, err: Network_Error) { assert(backlog > 0 && backlog < int(max(i32))) @@ -150,11 +174,18 @@ listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: TC /* Returns the endpoint that the given socket is listening / bound on. */ -bound_endpoint :: proc(socket: Any_Socket) -> (endpoint: Endpoint, err: Network_Error) { +bound_endpoint :: proc(socket: Any_Socket) -> (endpoint: Endpoint, err: Socket_Info_Error) { return _bound_endpoint(socket) } -accept_tcp :: proc(socket: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) { +/* + Returns the endpoint that the given socket is connected to. (Peer's endpoint) +*/ +peer_endpoint :: proc(socket: Any_Socket) -> (endpoint: Endpoint, err: Socket_Info_Error) { + return _peer_endpoint(socket) +} + +accept_tcp :: proc(socket: TCP_Socket, options := DEFAULT_TCP_OPTIONS) -> (client: TCP_Socket, source: Endpoint, err: Accept_Error) { return _accept_tcp(socket, options) } @@ -162,11 +193,11 @@ close :: proc(socket: Any_Socket) { _close(socket) } -recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: Network_Error) { +recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: TCP_Recv_Error) { return _recv_tcp(socket, buf) } -recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: Network_Error) { +recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: UDP_Recv_Error) { return _recv_udp(socket, buf) } @@ -175,6 +206,8 @@ recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_en Note: `remote_endpoint` parameter is non-nil only if the socket type is UDP. On TCP sockets it will always return `nil`. + + Errors that can be returned: `TCP_Recv_Error`, or `UDP_Recv_Error` */ recv_any :: proc(socket: Any_Socket, buf: []byte) -> ( bytes_read: int, @@ -197,7 +230,7 @@ recv :: proc{recv_tcp, recv_udp, recv_any} Repeatedly sends data until the entire buffer is sent. If a send fails before all data is sent, returns the amount sent up to that point. */ -send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Network_Error) { +send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: TCP_Send_Error) { return _send_tcp(socket, buf) } @@ -207,10 +240,15 @@ send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: N Datagrams are limited in size; attempting to send more than this limit at once will result in a Message_Too_Long error. UDP packets are not guarenteed to be received in order. */ -send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: Network_Error) { +send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: UDP_Send_Error) { return _send_udp(socket, buf, to) } +/* + Sends data over the socket. + + Errors that can be returned: `TCP_Send_Error`, or `UDP_Send_Error` +*/ send_any :: proc(socket: Any_Socket, buf: []byte, to: Maybe(Endpoint) = nil) -> ( bytes_written: int, err: Network_Error, @@ -226,14 +264,14 @@ send_any :: proc(socket: Any_Socket, buf: []byte, to: Maybe(Endpoint) = nil) -> send :: proc{send_tcp, send_udp, send_any} -shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { +shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Shutdown_Error) { return _shutdown(socket, manner) } -set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error { +set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Socket_Option_Error { return _set_option(socket, option, value, loc) } -set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) { +set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Set_Blocking_Error) { return _set_blocking(socket, should_block) } diff --git a/core/net/socket_darwin.odin b/core/net/socket_darwin.odin index 27927e973..fe4b4c3b5 100644 --- a/core/net/socket_darwin.odin +++ b/core/net/socket_darwin.odin @@ -21,44 +21,51 @@ package net */ import "core:c" -import "core:os" import "core:sys/posix" import "core:time" Socket_Option :: enum c.int { - Broadcast = c.int(os.SO_BROADCAST), - Reuse_Address = c.int(os.SO_REUSEADDR), - Keep_Alive = c.int(os.SO_KEEPALIVE), - Out_Of_Bounds_Data_Inline = c.int(os.SO_OOBINLINE), - TCP_Nodelay = c.int(os.TCP_NODELAY), - Linger = c.int(os.SO_LINGER), - Receive_Buffer_Size = c.int(os.SO_RCVBUF), - Send_Buffer_Size = c.int(os.SO_SNDBUF), - Receive_Timeout = c.int(os.SO_RCVTIMEO), - Send_Timeout = c.int(os.SO_SNDTIMEO), + Broadcast = c.int(posix.Sock_Option.BROADCAST), + Reuse_Address = c.int(posix.Sock_Option.REUSEADDR), + Keep_Alive = c.int(posix.Sock_Option.KEEPALIVE), + Out_Of_Bounds_Data_Inline = c.int(posix.Sock_Option.OOBINLINE), + TCP_Nodelay = c.int(posix.TCP_NODELAY), + Linger = c.int(posix.Sock_Option.LINGER), + Receive_Buffer_Size = c.int(posix.Sock_Option.RCVBUF), + Send_Buffer_Size = c.int(posix.Sock_Option.SNDBUF), + Receive_Timeout = c.int(posix.Sock_Option.RCVTIMEO), + Send_Timeout = c.int(posix.Sock_Option.SNDTIMEO), +} + +Shutdown_Manner :: enum c.int { + Receive = c.int(posix.SHUT_RD), + Send = c.int(posix.SHUT_WR), + Both = c.int(posix.SHUT_RDWR), } @(private) -_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) { - c_type, c_protocol, c_family: int +_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) { + c_type: posix.Sock + c_protocol: posix.Protocol + c_family: posix.AF switch family { - case .IP4: c_family = os.AF_INET - case .IP6: c_family = os.AF_INET6 + case .IP4: c_family = .INET + case .IP6: c_family = .INET6 case: unreachable() } switch protocol { - case .TCP: c_type = os.SOCK_STREAM; c_protocol = os.IPPROTO_TCP - case .UDP: c_type = os.SOCK_DGRAM; c_protocol = os.IPPROTO_UDP + case .TCP: c_type = .STREAM; c_protocol = .TCP + case .UDP: c_type = .DGRAM; c_protocol = .UDP case: unreachable() } - sock, sock_err := os.socket(c_family, c_type, c_protocol) - if sock_err != nil { - err = Create_Socket_Error(os.is_platform_error(sock_err) or_else -1) + sock := posix.socket(c_family, c_type, c_protocol) + if sock < 0 { + err = _create_socket_error() return } @@ -71,7 +78,7 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (so } @(private) -_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (skt: TCP_Socket, err: Network_Error) { +_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := DEFAULT_TCP_OPTIONS) -> (skt: TCP_Socket, err: Network_Error) { if endpoint.port == 0 { return 0, .Port_Required } @@ -86,30 +93,22 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio _ = set_option(skt, .Reuse_Address, true) sockaddr := _endpoint_to_sockaddr(endpoint) - res := os.connect(os.Socket(skt), (^os.SOCKADDR)(&sockaddr), i32(sockaddr.len)) - if res != nil { + if posix.connect(posix.FD(skt), (^posix.sockaddr)(&sockaddr), posix.socklen_t(sockaddr.ss_len)) != .OK { + err = _dial_error() close(skt) - return {}, Dial_Error(os.is_platform_error(res) or_else -1) } return } -// On Darwin, any port below 1024 is 'privileged' - which means that you need root access in order to use it. -MAX_PRIVILEGED_PORT :: 1023 - @(private) -_bind :: proc(skt: Any_Socket, ep: Endpoint) -> (err: Network_Error) { +_bind :: proc(skt: Any_Socket, ep: Endpoint) -> (err: Bind_Error) { sockaddr := _endpoint_to_sockaddr(ep) s := any_socket_to_socket(skt) - res := os.bind(os.Socket(s), (^os.SOCKADDR)(&sockaddr), i32(sockaddr.len)) - if res != nil { - if res == os.EACCES && ep.port <= MAX_PRIVILEGED_PORT { - err = .Privileged_Port_Without_Root - } else { - err = Bind_Error(os.is_platform_error(res) or_else -1) - } + if posix.bind(posix.FD(s), (^posix.sockaddr)(&sockaddr), posix.socklen_t(sockaddr.ss_len)) != .OK { + err = _bind_error() } + return } @@ -126,78 +125,90 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (skt: TCP_ // bypass the cooldown period, and allow the next run of the program to // use the same address immediately. // - // TODO(tetra, 2022-02-15): Confirm that this doesn't mean other processes can hijack the address! - set_option(sock, .Reuse_Address, true) or_return + _ = set_option(sock, .Reuse_Address, true) bind(sock, interface_endpoint) or_return - res := os.listen(os.Socket(skt), backlog) - if res != nil { - err = Listen_Error(os.is_platform_error(res) or_else -1) - return + if posix.listen(posix.FD(skt), i32(backlog)) != .OK { + err = _listen_error() } return } @(private) -_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) { +_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { addr: posix.sockaddr_storage addr_len := posix.socklen_t(size_of(addr)) - res := posix.getsockname(posix.FD(any_socket_to_socket(sock)), (^posix.sockaddr)(&addr), &addr_len) - if res != .OK { - err = Listen_Error(posix.errno()) + if posix.getsockname(posix.FD(any_socket_to_socket(sock)), (^posix.sockaddr)(&addr), &addr_len) != .OK { + err = _socket_info_error() return } - ep = _sockaddr_to_endpoint((^os.SOCKADDR_STORAGE_LH)(&addr)) + + ep = _sockaddr_to_endpoint(&addr) return } @(private) -_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) { - sockaddr: os.SOCKADDR_STORAGE_LH - sockaddrlen := c.int(size_of(sockaddr)) - - client_sock, client_sock_err := os.accept(os.Socket(sock), cast(^os.SOCKADDR) &sockaddr, &sockaddrlen) - if client_sock_err != nil { - err = Accept_Error(os.is_platform_error(client_sock_err) or_else -1) +_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { + addr: posix.sockaddr_storage + addr_len := posix.socklen_t(size_of(addr)) + if posix.getpeername(posix.FD(any_socket_to_socket(sock)), (^posix.sockaddr)(&addr), &addr_len) != .OK { + err = _socket_info_error() return } + + ep = _sockaddr_to_endpoint(&addr) + return +} + +@(private) +_accept_tcp :: proc(sock: TCP_Socket, options := DEFAULT_TCP_OPTIONS) -> (client: TCP_Socket, source: Endpoint, err: Accept_Error) { + addr: posix.sockaddr_storage + addr_len := posix.socklen_t(size_of(addr)) + client_sock := posix.accept(posix.FD(sock), (^posix.sockaddr)(&addr), &addr_len) + if client_sock < 0 { + err = _accept_error() + return + } + client = TCP_Socket(client_sock) - source = _sockaddr_to_endpoint(&sockaddr) + source = _sockaddr_to_endpoint(&addr) return } @(private) _close :: proc(skt: Any_Socket) { s := any_socket_to_socket(skt) - os.close(os.Handle(os.Socket(s))) + posix.close(posix.FD(s)) } @(private) -_recv_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_read: int, err: Network_Error) { +_recv_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_read: int, err: TCP_Recv_Error) { if len(buf) <= 0 { return } - res, res_err := os.recv(os.Socket(skt), buf, 0) - if res_err != nil { - err = TCP_Recv_Error(os.is_platform_error(res_err) or_else -1) + + res := posix.recv(posix.FD(skt), raw_data(buf), len(buf), {}) + if res < 0 { + err = _tcp_recv_error() return } + return int(res), nil } @(private) -_recv_udp :: proc(skt: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: Network_Error) { +_recv_udp :: proc(skt: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: UDP_Recv_Error) { if len(buf) <= 0 { return } - from: os.SOCKADDR_STORAGE_LH - fromsize := c.int(size_of(from)) - res, res_err := os.recvfrom(os.Socket(skt), buf, 0, cast(^os.SOCKADDR) &from, &fromsize) - if res_err != nil { - err = UDP_Recv_Error(os.is_platform_error(res_err) or_else -1) + from: posix.sockaddr_storage + fromsize := posix.socklen_t(size_of(from)) + res := posix.recvfrom(posix.FD(skt), raw_data(buf), len(buf), {}, (^posix.sockaddr)(&from), &fromsize) + if res < 0 { + err = _udp_recv_error() return } @@ -207,67 +218,60 @@ _recv_udp :: proc(skt: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endp } @(private) -_send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Network_Error) { +_send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: TCP_Send_Error) { for bytes_written < len(buf) { limit := min(int(max(i32)), len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - res, res_err := os.send(os.Socket(skt), remaining, os.MSG_NOSIGNAL) - if res_err == os.EPIPE { - // EPIPE arises if the socket has been closed remotely. - err = TCP_Send_Error.Connection_Closed - return - } else if res_err != nil { - err = TCP_Send_Error(os.is_platform_error(res_err) or_else -1) + res := posix.send(posix.FD(skt), raw_data(remaining), len(remaining), {.NOSIGNAL}) + if res < 0 { + err = _tcp_send_error() return } + bytes_written += int(res) } return } @(private) -_send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: Network_Error) { +_send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: UDP_Send_Error) { toaddr := _endpoint_to_sockaddr(to) for bytes_written < len(buf) { limit := min(1<<31, len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - res, res_err := os.sendto(os.Socket(skt), remaining, os.MSG_NOSIGNAL, cast(^os.SOCKADDR)&toaddr, i32(toaddr.len)) - if res_err == os.EPIPE { - // EPIPE arises if the socket has been closed remotely. - err = UDP_Send_Error.Not_Socket - return - } else if res_err != nil { - err = UDP_Send_Error(os.is_platform_error(res_err) or_else -1) + res := posix.sendto(posix.FD(skt), raw_data(remaining), len(remaining), {.NOSIGNAL}, (^posix.sockaddr)(&toaddr), posix.socklen_t(toaddr.ss_len)) + if res < 0 { + err = _udp_send_error() return } + bytes_written += int(res) } return } @(private) -_shutdown :: proc(skt: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { +_shutdown :: proc(skt: Any_Socket, manner: Shutdown_Manner) -> (err: Shutdown_Error) { s := any_socket_to_socket(skt) - res := os.shutdown(os.Socket(s), int(manner)) - if res != nil { - return Shutdown_Error(os.is_platform_error(res) or_else -1) + if posix.shutdown(posix.FD(s), posix.Shut(manner)) != .OK { + err = _shutdown_error() } return } @(private) -_set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error { - level := os.SOL_SOCKET if option != .TCP_Nodelay else os.IPPROTO_TCP +_set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Socket_Option_Error { + level := posix.SOL_SOCKET if option != .TCP_Nodelay else posix.IPPROTO_TCP // NOTE(tetra, 2022-02-15): On Linux, you cannot merely give a single byte for a bool; // it _has_ to be a b32. // I haven't tested if you can give more than that. bool_value: b32 - int_value: i32 - timeval_value: os.Timeval + int_value: posix.socklen_t + timeval_value: posix.timeval ptr: rawptr - len: os.socklen_t + len: posix.socklen_t switch option { case @@ -302,8 +306,8 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca t := value.(time.Duration) or_else panic("set_option() value must be a time.Duration here", loc) micros := i64(time.duration_microseconds(t)) - timeval_value.microseconds = int(micros % 1e6) - timeval_value.seconds = (micros - i64(timeval_value.microseconds)) / 1e6 + timeval_value.tv_usec = posix.suseconds_t(micros % 1e6) + timeval_value.tv_sec = posix.time_t(micros - i64(timeval_value.tv_usec)) / 1e6 ptr = &timeval_value len = size_of(timeval_value) @@ -312,12 +316,12 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca .Send_Buffer_Size: // TODO: check for out of range values and return .Value_Out_Of_Range? switch i in value { - case i8, u8: i2 := i; int_value = os.socklen_t((^u8)(&i2)^) - case i16, u16: i2 := i; int_value = os.socklen_t((^u16)(&i2)^) - case i32, u32: i2 := i; int_value = os.socklen_t((^u32)(&i2)^) - case i64, u64: i2 := i; int_value = os.socklen_t((^u64)(&i2)^) - case i128, u128: i2 := i; int_value = os.socklen_t((^u128)(&i2)^) - case int, uint: i2 := i; int_value = os.socklen_t((^uint)(&i2)^) + case i8, u8: i2 := i; int_value = posix.socklen_t((^u8)(&i2)^) + case i16, u16: i2 := i; int_value = posix.socklen_t((^u16)(&i2)^) + case i32, u32: i2 := i; int_value = posix.socklen_t((^u32)(&i2)^) + case i64, u64: i2 := i; int_value = posix.socklen_t((^u64)(&i2)^) + case i128, u128: i2 := i; int_value = posix.socklen_t((^u128)(&i2)^) + case int, uint: i2 := i; int_value = posix.socklen_t((^uint)(&i2)^) case: panic("set_option() value must be an integer here", loc) } @@ -326,54 +330,53 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca } skt := any_socket_to_socket(s) - res := os.setsockopt(os.Socket(skt), int(level), int(option), ptr, len) - if res != nil { - return Socket_Option_Error(os.is_platform_error(res) or_else -1) + if posix.setsockopt(posix.FD(skt), i32(level), posix.Sock_Option(option), ptr, len) != .OK { + return _socket_option_error() } return nil } @(private) -_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) { +_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Set_Blocking_Error) { socket := any_socket_to_socket(socket) - flags, getfl_err := os.fcntl(int(socket), os.F_GETFL, 0) - if getfl_err != nil { - return Set_Blocking_Error(os.is_platform_error(getfl_err) or_else -1) + flags_ := posix.fcntl(posix.FD(socket), .GETFL, 0) + if flags_ < 0 { + return _set_blocking_error() } + flags := transmute(posix.O_Flags)flags_ if should_block { - flags &~= int(os.O_NONBLOCK) + flags -= {.NONBLOCK} } else { - flags |= int(os.O_NONBLOCK) + flags += {.NONBLOCK} } - _, setfl_err := os.fcntl(int(socket), os.F_SETFL, flags) - if setfl_err != nil { - return Set_Blocking_Error(os.is_platform_error(setfl_err) or_else -1) + if posix.fcntl(posix.FD(socket), .SETFL, flags) < 0 { + return _set_blocking_error() } return nil } @private -_endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: os.SOCKADDR_STORAGE_LH) { +_endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: posix.sockaddr_storage) { switch a in ep.address { case IP4_Address: - (^os.sockaddr_in)(&sockaddr)^ = os.sockaddr_in { + (^posix.sockaddr_in)(&sockaddr)^ = posix.sockaddr_in { sin_port = u16be(ep.port), - sin_addr = transmute(os.in_addr) a, - sin_family = u8(os.AF_INET), - sin_len = size_of(os.sockaddr_in), + sin_addr = transmute(posix.in_addr)a, + sin_family = .INET, + sin_len = size_of(posix.sockaddr_in), } return case IP6_Address: - (^os.sockaddr_in6)(&sockaddr)^ = os.sockaddr_in6 { + (^posix.sockaddr_in6)(&sockaddr)^ = posix.sockaddr_in6 { sin6_port = u16be(ep.port), - sin6_addr = transmute(os.in6_addr) a, - sin6_family = u8(os.AF_INET6), - sin6_len = size_of(os.sockaddr_in6), + sin6_addr = transmute(posix.in6_addr)a, + sin6_family = .INET6, + sin6_len = size_of(posix.sockaddr_in6), } return } @@ -381,21 +384,21 @@ _endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: os.SOCKADDR_STORAGE_LH } @private -_sockaddr_to_endpoint :: proc(native_addr: ^os.SOCKADDR_STORAGE_LH) -> (ep: Endpoint) { - switch native_addr.family { - case u8(os.AF_INET): - addr := cast(^os.sockaddr_in) native_addr +_sockaddr_to_endpoint :: proc(native_addr: ^posix.sockaddr_storage) -> (ep: Endpoint) { + #partial switch native_addr.ss_family { + case .INET: + addr := cast(^posix.sockaddr_in)native_addr port := int(addr.sin_port) ep = Endpoint { - address = IP4_Address(transmute([4]byte) addr.sin_addr), - port = port, + address = IP4_Address(transmute([4]byte)addr.sin_addr), + port = port, } - case u8(os.AF_INET6): - addr := cast(^os.sockaddr_in6) native_addr + case .INET6: + addr := cast(^posix.sockaddr_in6)native_addr port := int(addr.sin6_port) ep = Endpoint { - address = IP6_Address(transmute([8]u16be) addr.sin6_addr), - port = port, + address = IP6_Address(transmute([8]u16be)addr.sin6_addr), + port = port, } case: panic("native_addr is neither IP4 or IP6 address") @@ -404,21 +407,21 @@ _sockaddr_to_endpoint :: proc(native_addr: ^os.SOCKADDR_STORAGE_LH) -> (ep: Endp } @(private) -_sockaddr_basic_to_endpoint :: proc(native_addr: ^os.SOCKADDR) -> (ep: Endpoint) { - switch u16(native_addr.family) { - case u16(os.AF_INET): - addr := cast(^os.sockaddr_in) native_addr +_sockaddr_basic_to_endpoint :: proc(native_addr: ^posix.sockaddr) -> (ep: Endpoint) { + #partial switch native_addr.sa_family { + case .INET: + addr := cast(^posix.sockaddr_in)native_addr port := int(addr.sin_port) ep = Endpoint { - address = IP4_Address(transmute([4]byte) addr.sin_addr), - port = port, + address = IP4_Address(transmute([4]byte)addr.sin_addr), + port = port, } - case u16(os.AF_INET6): - addr := cast(^os.sockaddr_in6) native_addr + case .INET6: + addr := cast(^posix.sockaddr_in6)native_addr port := int(addr.sin6_port) ep = Endpoint { - address = IP6_Address(transmute([8]u16be) addr.sin6_addr), - port = port, + address = IP6_Address(transmute([8]u16be)addr.sin6_addr), + port = port, } case: panic("native_addr is neither IP4 or IP6 address") diff --git a/core/net/socket_freebsd.odin b/core/net/socket_freebsd.odin index 3a3774007..78bd1cdae 100644 --- a/core/net/socket_freebsd.odin +++ b/core/net/socket_freebsd.odin @@ -54,8 +54,14 @@ Socket_Option :: enum c.int { Receive_Timeout = cast(c.int)freebsd.Socket_Option.RCVTIMEO, } +Shutdown_Manner :: enum c.int { + Receive = cast(c.int)freebsd.Shutdown_Method.RD, + Send = cast(c.int)freebsd.Shutdown_Method.WR, + Both = cast(c.int)freebsd.Shutdown_Method.RDWR, +} + @(private) -_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) { +_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) { sys_family: freebsd.Protocol_Family = --- sys_protocol: freebsd.Protocol = --- sys_socket_type: freebsd.Socket_Type = --- @@ -72,24 +78,7 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (so new_socket, errno := freebsd.socket(sys_family, sys_socket_type, sys_protocol) if errno != nil { - err = cast(Create_Socket_Error)errno - return - } - - // NOTE(Feoramund): By default, FreeBSD will generate SIGPIPE if an EPIPE - // error is raised during the writing of a socket that may be closed. - // This behavior is unlikely to be expected by general users. - // - // There are two workarounds. One is to apply the .NOSIGNAL flag when using - // the `sendto` syscall. However, that would prevent users of this library - // from re-enabling the SIGPIPE-raising functionality, if they really - // wanted it. - // - // So I have disabled it here with this socket option for all sockets. - truth: b32 = true - errno = freebsd.setsockopt(new_socket, .SOCKET, .NOSIGPIPE, &truth, size_of(truth)) - if errno != nil { - err = cast(Socket_Option_Error)errno + err = _create_socket_error(errno) return } @@ -102,7 +91,7 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (so } @(private) -_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) { +_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := DEFAULT_TCP_OPTIONS) -> (socket: TCP_Socket, err: Network_Error) { if endpoint.port == 0 { return 0, .Port_Required } @@ -115,19 +104,19 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio errno := freebsd.connect(cast(Fd)socket, &sockaddr, cast(freebsd.socklen_t)sockaddr.len) if errno != nil { close(socket) - return {}, cast(Dial_Error)errno + return {}, _dial_error(errno) } return } @(private) -_bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Network_Error) { +_bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Bind_Error) { sockaddr := _endpoint_to_sockaddr(ep) real_socket := any_socket_to_socket(socket) errno := freebsd.bind(cast(Fd)real_socket, &sockaddr, cast(freebsd.socklen_t)sockaddr.len) if errno != nil { - err = cast(Bind_Error)errno + err = _bind_error(errno) } return } @@ -143,7 +132,7 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: T errno := freebsd.listen(cast(Fd)socket, backlog) if errno != nil { - err = cast(Listen_Error)errno + err = _listen_error(errno) return } @@ -151,12 +140,12 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: T } @(private) -_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) { +_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { sockaddr: freebsd.Socket_Address_Storage errno := freebsd.getsockname(cast(Fd)any_socket_to_socket(sock), &sockaddr) if errno != nil { - err = cast(Listen_Error)errno + err = _socket_info_error(errno) return } @@ -165,12 +154,26 @@ _bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) } @(private) -_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) { +_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { + sockaddr: freebsd.Socket_Address_Storage + + errno := freebsd.getpeername(cast(Fd)any_socket_to_socket(sock), &sockaddr) + if errno != nil { + err = _socket_info_error(errno) + return + } + + ep = _sockaddr_to_endpoint(&sockaddr) + return +} + +@(private) +_accept_tcp :: proc(sock: TCP_Socket, options := DEFAULT_TCP_OPTIONS) -> (client: TCP_Socket, source: Endpoint, err: Accept_Error) { sockaddr: freebsd.Socket_Address_Storage result, errno := freebsd.accept(cast(Fd)sock, &sockaddr) if errno != nil { - err = cast(Accept_Error)errno + err = _accept_error(errno) return } @@ -187,20 +190,20 @@ _close :: proc(socket: Any_Socket) { } @(private) -_recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: Network_Error) { +_recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: TCP_Recv_Error) { if len(buf) == 0 { return } result, errno := freebsd.recv(cast(Fd)socket, buf, .NONE) if errno != nil { - err = cast(TCP_Recv_Error)errno + err = _tcp_recv_error(errno) return } return result, nil } @(private) -_recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: Network_Error) { +_recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: UDP_Recv_Error) { if len(buf) == 0 { return } @@ -208,21 +211,21 @@ _recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_e result, errno := freebsd.recvfrom(cast(Fd)socket, buf, .NONE, &from) if errno != nil { - err = cast(UDP_Recv_Error)errno + err = _udp_recv_error(errno) return } return result, _sockaddr_to_endpoint(&from), nil } @(private) -_send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Network_Error) { +_send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: TCP_Send_Error) { for bytes_written < len(buf) { limit := min(int(max(i32)), len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - result, errno := freebsd.send(cast(Fd)socket, remaining, .NONE) + result, errno := freebsd.send(cast(Fd)socket, remaining, .NOSIGNAL) if errno != nil { - err = cast(TCP_Send_Error)errno + err = _tcp_send_error(errno) return } bytes_written += result @@ -231,15 +234,15 @@ _send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: } @(private) -_send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: Network_Error) { +_send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: UDP_Send_Error) { toaddr := _endpoint_to_sockaddr(to) for bytes_written < len(buf) { limit := min(int(max(i32)), len(buf) - bytes_written) remaining := buf[bytes_written:][:limit] - result, errno := freebsd.sendto(cast(Fd)socket, remaining, .NONE, &toaddr) + result, errno := freebsd.sendto(cast(Fd)socket, remaining, .NOSIGNAL, &toaddr) if errno != nil { - err = cast(UDP_Send_Error)errno + err = _udp_send_error(errno) return } bytes_written += result @@ -248,17 +251,17 @@ _send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_writt } @(private) -_shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { +_shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Shutdown_Error) { real_socket := cast(Fd)any_socket_to_socket(socket) errno := freebsd.shutdown(real_socket, cast(freebsd.Shutdown_Method)manner) if errno != nil { - return cast(Shutdown_Error)errno + return _shutdown_error(errno) } return } @(private) -_set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error { +_set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Socket_Option_Error { // NOTE(Feoramund): I found that FreeBSD, like Linux, requires at least 32 // bits for a boolean socket option value. Nothing less will work. bool_value: b32 @@ -315,25 +318,25 @@ _set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc : case u16: int_value = cast(i32)real case i32: int_value = real case u32: - if real > u32(max(i32)) { return .Value_Out_Of_Range } + if real > u32(max(i32)) { return .Invalid_Value } int_value = cast(i32)real case i64: - if real > i64(max(i32)) || real < i64(min(i32)) { return .Value_Out_Of_Range } + if real > i64(max(i32)) || real < i64(min(i32)) { return .Invalid_Value } int_value = cast(i32)real case u64: - if real > u64(max(i32)) { return .Value_Out_Of_Range } + if real > u64(max(i32)) { return .Invalid_Value } int_value = cast(i32)real case i128: - if real > i128(max(i32)) || real < i128(min(i32)) { return .Value_Out_Of_Range } + if real > i128(max(i32)) || real < i128(min(i32)) { return .Invalid_Value } int_value = cast(i32)real case u128: - if real > u128(max(i32)) { return .Value_Out_Of_Range } + if real > u128(max(i32)) { return .Invalid_Value } int_value = cast(i32)real case int: - if real > int(max(i32)) || real < int(min(i32)) { return .Value_Out_Of_Range } + if real > int(max(i32)) || real < int(min(i32)) { return .Invalid_Value } int_value = cast(i32)real case uint: - if real > uint(max(i32)) { return .Value_Out_Of_Range } + if real > uint(max(i32)) { return .Invalid_Value } int_value = cast(i32)real case: panic("set_option() value must be an integer here", loc) @@ -347,19 +350,19 @@ _set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc : real_socket := any_socket_to_socket(socket) errno := freebsd.setsockopt(cast(Fd)real_socket, .SOCKET, cast(freebsd.Socket_Option)option, ptr, len) if errno != nil { - return cast(Socket_Option_Error)errno + return _socket_option_error(errno) } return nil } @(private) -_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) { +_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Set_Blocking_Error) { real_socket := any_socket_to_socket(socket) flags, errno := freebsd.fcntl_getfl(cast(freebsd.Fd)real_socket) if errno != nil { - return cast(Set_Blocking_Error)errno + return _set_blocking_error(errno) } if should_block { @@ -370,7 +373,7 @@ _set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_E errno = freebsd.fcntl_setfl(cast(freebsd.Fd)real_socket, flags) if errno != nil { - return cast(Set_Blocking_Error)errno + return _set_blocking_error(errno) } return diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin index cafec747d..bdb48fce8 100644 --- a/core/net/socket_linux.odin +++ b/core/net/socket_linux.odin @@ -38,15 +38,21 @@ Socket_Option :: enum c.int { Broadcast = c.int(linux.Socket_Option.BROADCAST), } +Shutdown_Manner :: enum c.int { + Receive = c.int(linux.Shutdown_How.RD), + Send = c.int(linux.Shutdown_How.WR), + Both = c.int(linux.Shutdown_How.RDWR), +} + // Wrappers and unwrappers for system-native types @(private="file") -_unwrap_os_socket :: proc "contextless" (sock: Any_Socket)->linux.Fd { +_unwrap_os_socket :: proc "contextless" (sock: Any_Socket) -> linux.Fd { return linux.Fd(any_socket_to_socket(sock)) } @(private="file") -_wrap_os_socket :: proc "contextless" (sock: linux.Fd, protocol: Socket_Protocol)->Any_Socket { +_wrap_os_socket :: proc "contextless" (sock: linux.Fd, protocol: Socket_Protocol) -> Any_Socket { switch protocol { case .TCP: return TCP_Socket(Socket(sock)) case .UDP: return UDP_Socket(Socket(sock)) @@ -56,7 +62,7 @@ _wrap_os_socket :: proc "contextless" (sock: linux.Fd, protocol: Socket_Protocol } @(private="file") -_unwrap_os_family :: proc "contextless" (family: Address_Family)->linux.Address_Family { +_unwrap_os_family :: proc "contextless" (family: Address_Family) -> linux.Address_Family { switch family { case .IP4: return .INET case .IP6: return .INET6 @@ -66,7 +72,7 @@ _unwrap_os_family :: proc "contextless" (family: Address_Family)->linux.Address_ } @(private="file") -_unwrap_os_proto_socktype :: proc "contextless" (protocol: Socket_Protocol)->(linux.Protocol, linux.Socket_Type) { +_unwrap_os_proto_socktype :: proc "contextless" (protocol: Socket_Protocol) -> (linux.Protocol, linux.Socket_Type) { switch protocol { case .TCP: return .TCP, .STREAM case .UDP: return .UDP, .DGRAM @@ -76,7 +82,7 @@ _unwrap_os_proto_socktype :: proc "contextless" (protocol: Socket_Protocol)->(li } @(private="file") -_unwrap_os_addr :: proc "contextless" (endpoint: Endpoint)->(linux.Sock_Addr_Any) { +_unwrap_os_addr :: proc "contextless" (endpoint: Endpoint) -> linux.Sock_Addr_Any { switch address in endpoint.address { case IP4_Address: return { @@ -100,7 +106,7 @@ _unwrap_os_addr :: proc "contextless" (endpoint: Endpoint)->(linux.Sock_Addr_Any } @(private="file") -_wrap_os_addr :: proc "contextless" (addr: linux.Sock_Addr_Any)->(Endpoint) { +_wrap_os_addr :: proc "contextless" (addr: linux.Sock_Addr_Any) -> Endpoint { #partial switch addr.family { case .INET: return { @@ -117,18 +123,18 @@ _wrap_os_addr :: proc "contextless" (addr: linux.Sock_Addr_Any)->(Endpoint) { } } -_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (Any_Socket, Network_Error) { +_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (Any_Socket, Create_Socket_Error) { family := _unwrap_os_family(family) proto, socktype := _unwrap_os_proto_socktype(protocol) sock, errno := linux.socket(family, socktype, {.CLOEXEC}, proto) if errno != .NONE { - return {}, Create_Socket_Error(errno) + return {}, _create_socket_error(errno) } return _wrap_os_socket(sock, protocol), nil } @(private) -_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (TCP_Socket, Network_Error) { +_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := DEFAULT_TCP_OPTIONS) -> (TCP_Socket, Network_Error) { errno: linux.Errno if endpoint.port == 0 { return 0, .Port_Required @@ -138,7 +144,7 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio os_sock, errno = linux.socket(_unwrap_os_family(family_from_endpoint(endpoint)), .STREAM, {.CLOEXEC}, .TCP) if errno != .NONE { // TODO(flysand): should return invalid file descriptor here casted as TCP_Socket - return {}, Create_Socket_Error(errno) + return {}, _create_socket_error(errno) } // NOTE(tetra): This is so that if we crash while the socket is open, we can // bypass the cooldown period, and allow the next run of the program to @@ -149,7 +155,7 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio errno = linux.connect(linux.Fd(os_sock), &addr) if errno != .NONE { close(cast(TCP_Socket) os_sock) - return {}, Dial_Error(errno) + return {}, _dial_error(errno) } // NOTE(tetra): Not vital to succeed; error ignored no_delay: b32 = cast(b32) options.no_delay @@ -158,11 +164,11 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio } @(private) -_bind :: proc(sock: Any_Socket, endpoint: Endpoint) -> (Network_Error) { +_bind :: proc(sock: Any_Socket, endpoint: Endpoint) -> (Bind_Error) { addr := _unwrap_os_addr(endpoint) errno := linux.bind(_unwrap_os_socket(sock), &addr) if errno != .NONE { - return Bind_Error(errno) + return _bind_error(errno) } return nil } @@ -180,7 +186,7 @@ _listen_tcp :: proc(endpoint: Endpoint, backlog := 1000) -> (socket: TCP_Socket, os_sock: linux.Fd os_sock, errno = linux.socket(ep_family, .STREAM, {.CLOEXEC}, .TCP) if errno != .NONE { - err = Create_Socket_Error(errno) + err = _create_socket_error(errno) return } socket = cast(TCP_Socket)os_sock @@ -193,31 +199,30 @@ _listen_tcp :: proc(endpoint: Endpoint, backlog := 1000) -> (socket: TCP_Socket, // TODO(tetra, 2022-02-15): Confirm that this doesn't mean other processes can hijack the address! do_reuse_addr: b32 = true if errno = linux.setsockopt(os_sock, linux.SOL_SOCKET, linux.Socket_Option.REUSEADDR, &do_reuse_addr); errno != .NONE { - err = Listen_Error(errno) + err = _listen_error(errno) return } // Bind the socket to endpoint address if errno = linux.bind(os_sock, &ep_address); errno != .NONE { - err = Bind_Error(errno) + err = _bind_error(errno) return } // Listen on bound socket if errno = linux.listen(os_sock, cast(i32) backlog); errno != .NONE { - err = Listen_Error(errno) - return + err = _listen_error(errno) } return } @(private) -_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) { +_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { addr: linux.Sock_Addr_Any errno := linux.getsockname(_unwrap_os_socket(sock), &addr) if errno != .NONE { - err = Listen_Error(errno) + err = _socket_info_error(errno) return } @@ -226,11 +231,24 @@ _bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) } @(private) -_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (tcp_client: TCP_Socket, endpoint: Endpoint, err: Network_Error) { +_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { + addr: linux.Sock_Addr_Any + errno := linux.getpeername(_unwrap_os_socket(sock), &addr) + if errno != .NONE { + err = _socket_info_error(errno) + return + } + + ep = _wrap_os_addr(addr) + return +} + +@(private) +_accept_tcp :: proc(sock: TCP_Socket, options := DEFAULT_TCP_OPTIONS) -> (tcp_client: TCP_Socket, endpoint: Endpoint, err: Accept_Error) { addr: linux.Sock_Addr_Any client_sock, errno := linux.accept(linux.Fd(sock), &addr) if errno != .NONE { - return {}, {}, Accept_Error(errno) + return {}, {}, _accept_error(errno) } // NOTE(tetra): Not vital to succeed; error ignored val: b32 = cast(b32) options.no_delay @@ -244,19 +262,19 @@ _close :: proc(sock: Any_Socket) { } @(private) -_recv_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) { +_recv_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, TCP_Recv_Error) { if len(buf) <= 0 { return 0, nil } bytes_read, errno := linux.recv(linux.Fd(tcp_sock), buf, {}) if errno != .NONE { - return 0, TCP_Recv_Error(errno) + return 0, _tcp_recv_error(errno) } return int(bytes_read), nil } @(private) -_recv_udp :: proc(udp_sock: UDP_Socket, buf: []byte) -> (int, Endpoint, Network_Error) { +_recv_udp :: proc(udp_sock: UDP_Socket, buf: []byte) -> (int, Endpoint, UDP_Recv_Error) { if len(buf) <= 0 { // NOTE(flysand): It was returning no error, I didn't change anything return 0, {}, {} @@ -268,28 +286,24 @@ _recv_udp :: proc(udp_sock: UDP_Socket, buf: []byte) -> (int, Endpoint, Network_ from_addr: linux.Sock_Addr_Any bytes_read, errno := linux.recvfrom(linux.Fd(udp_sock), buf, {.TRUNC}, &from_addr) if errno != .NONE { - return 0, {}, UDP_Recv_Error(errno) + return 0, {}, _udp_recv_error(errno) } if bytes_read > len(buf) { // NOTE(tetra): The buffer has been filled, with a partial message. - return len(buf), {}, .Buffer_Too_Small + return len(buf), {}, .Excess_Truncated } return bytes_read, _wrap_os_addr(from_addr), nil } @(private) -_send_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) { +_send_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, TCP_Send_Error) { total_written := 0 for total_written < len(buf) { limit := min(int(max(i32)), len(buf) - total_written) remaining := buf[total_written:][:limit] res, errno := linux.send(linux.Fd(tcp_sock), remaining, {.NOSIGNAL}) - if errno == .EPIPE { - // If the peer is disconnected when we are trying to send we will get an `EPIPE` error, - // so we turn that into a clearer error - return total_written, TCP_Send_Error.Connection_Closed - } else if errno != .NONE { - return total_written, TCP_Send_Error(errno) + if errno != .NONE { + return total_written, _tcp_send_error(errno) } total_written += int(res) } @@ -297,28 +311,28 @@ _send_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) { } @(private) -_send_udp :: proc(udp_sock: UDP_Socket, buf: []byte, to: Endpoint) -> (int, Network_Error) { +_send_udp :: proc(udp_sock: UDP_Socket, buf: []byte, to: Endpoint) -> (int, UDP_Send_Error) { to_addr := _unwrap_os_addr(to) bytes_written, errno := linux.sendto(linux.Fd(udp_sock), buf, {}, &to_addr) if errno != .NONE { - return bytes_written, UDP_Send_Error(errno) + return bytes_written, _udp_send_error(errno) } return int(bytes_written), nil } @(private) -_shutdown :: proc(sock: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { +_shutdown :: proc(sock: Any_Socket, manner: Shutdown_Manner) -> (err: Shutdown_Error) { os_sock := _unwrap_os_socket(sock) errno := linux.shutdown(os_sock, cast(linux.Shutdown_How) manner) if errno != .NONE { - return Shutdown_Error(errno) + return _shutdown_error(errno) } return nil } // TODO(flysand): Figure out what we want to do with this on core:sys/ level. @(private) -_set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error { +_set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Socket_Option_Error { level: int if option == .TCP_Nodelay { level = int(linux.SOL_TCP) @@ -388,19 +402,19 @@ _set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc := errno = linux.setsockopt(os_sock, level, int(option), &int_value) } if errno != .NONE { - return Socket_Option_Error(errno) + return _socket_option_error(errno) } return nil } @(private) -_set_blocking :: proc(sock: Any_Socket, should_block: bool) -> (err: Network_Error) { +_set_blocking :: proc(sock: Any_Socket, should_block: bool) -> (err: Set_Blocking_Error) { errno: linux.Errno flags: linux.Open_Flags os_sock := _unwrap_os_socket(sock) flags, errno = linux.fcntl(os_sock, linux.F_GETFL) if errno != .NONE { - return Set_Blocking_Error(errno) + return _set_blocking_error(errno) } if should_block { flags -= {.NONBLOCK} @@ -409,7 +423,7 @@ _set_blocking :: proc(sock: Any_Socket, should_block: bool) -> (err: Network_Err } errno = linux.fcntl(os_sock, linux.F_SETFL, flags) if errno != .NONE { - return Set_Blocking_Error(errno) + return _set_blocking_error(errno) } return nil } diff --git a/core/net/socket_windows.odin b/core/net/socket_windows.odin index f19be536a..9127874de 100644 --- a/core/net/socket_windows.odin +++ b/core/net/socket_windows.odin @@ -24,13 +24,67 @@ import "core:c" import win "core:sys/windows" import "core:time" +Socket_Option :: enum c.int { + // bool: Whether the address that this socket is bound to can be reused by other sockets. + // This allows you to bypass the cooldown period if a program dies while the socket is bound. + Reuse_Address = win.SO_REUSEADDR, + + // bool: Whether other programs will be inhibited from binding the same endpoint as this socket. + Exclusive_Addr_Use = win.SO_EXCLUSIVEADDRUSE, + + // bool: When true, keepalive packets will be automatically be sent for this connection. TODO: verify this understanding + Keep_Alive = win.SO_KEEPALIVE, + + // bool: When true, client connections will immediately be sent a TCP/IP RST response, rather than being accepted. + Conditional_Accept = win.SO_CONDITIONAL_ACCEPT, + + // bool: If true, when the socket is closed, but data is still waiting to be sent, discard that data. + Dont_Linger = win.SO_DONTLINGER, + + // bool: When true, 'out-of-band' data sent over the socket will be read by a normal net.recv() call, the same as normal 'in-band' data. + Out_Of_Bounds_Data_Inline = win.SO_OOBINLINE, + + // bool: When true, disables send-coalescing, therefore reducing latency. + TCP_Nodelay = win.TCP_NODELAY, + + // win.LINGER: Customizes how long (if at all) the socket will remain open when there + // is some remaining data waiting to be sent, and net.close() is called. + Linger = win.SO_LINGER, + + // win.DWORD: The size, in bytes, of the OS-managed receive-buffer for this socket. + Receive_Buffer_Size = win.SO_RCVBUF, + + // win.DWORD: The size, in bytes, of the OS-managed send-buffer for this socket. + Send_Buffer_Size = win.SO_SNDBUF, + + // win.DWORD: For blocking sockets, the time in milliseconds to wait for incoming data to be received, before giving up and returning .Timeout. + // For non-blocking sockets, ignored. + // Use a value of zero to potentially wait forever. + Receive_Timeout = win.SO_RCVTIMEO, + + // win.DWORD: For blocking sockets, the time in milliseconds to wait for outgoing data to be sent, before giving up and returning .Timeout. + // For non-blocking sockets, ignored. + // Use a value of zero to potentially wait forever. + Send_Timeout = win.SO_SNDTIMEO, + + // bool: Allow sending to, receiving from, and binding to, a broadcast address. + Broadcast = win.SO_BROADCAST, +} + + +Shutdown_Manner :: enum c.int { + Receive = win.SD_RECEIVE, + Send = win.SD_SEND, + Both = win.SD_BOTH, +} + @(init, private) -ensure_winsock_initialized :: proc() { +ensure_winsock_initialized :: proc "contextless" () { win.ensure_winsock_initialized() } @(private) -_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) { +_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Create_Socket_Error) { c_type, c_protocol, c_family: c.int switch family { @@ -49,7 +103,7 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (so sock := win.socket(c_family, c_type, c_protocol) if sock == win.INVALID_SOCKET { - err = Create_Socket_Error(win.WSAGetLastError()) + err = _create_socket_error() return } @@ -62,7 +116,7 @@ _create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (so } @(private) -_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (socket: TCP_Socket, err: Network_Error) { +_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := DEFAULT_TCP_OPTIONS) -> (socket: TCP_Socket, err: Network_Error) { if endpoint.port == 0 { err = .Port_Required return @@ -80,7 +134,7 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio sockaddr := _endpoint_to_sockaddr(endpoint) res := win.connect(win.SOCKET(socket), &sockaddr, size_of(sockaddr)) if res < 0 { - err = Dial_Error(win.WSAGetLastError()) + err = _dial_error() close(socket) return {}, err } @@ -93,12 +147,12 @@ _dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_optio } @(private) -_bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Network_Error) { +_bind :: proc(socket: Any_Socket, ep: Endpoint) -> (err: Bind_Error) { sockaddr := _endpoint_to_sockaddr(ep) sock := any_socket_to_socket(socket) res := win.bind(win.SOCKET(sock), &sockaddr, size_of(sockaddr)) if res < 0 { - err = Bind_Error(win.WSAGetLastError()) + err = _bind_error() } return } @@ -117,17 +171,17 @@ _listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (socket: T bind(sock, interface_endpoint) or_return if res := win.listen(win.SOCKET(socket), i32(backlog)); res == win.SOCKET_ERROR { - err = Listen_Error(win.WSAGetLastError()) + err = _listen_error() } return } @(private) -_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) { +_bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { sockaddr: win.SOCKADDR_STORAGE_LH sockaddrlen := c.int(size_of(sockaddr)) if win.getsockname(win.SOCKET(any_socket_to_socket(sock)), &sockaddr, &sockaddrlen) == win.SOCKET_ERROR { - err = Listen_Error(win.WSAGetLastError()) + err = _socket_info_error() return } @@ -136,7 +190,21 @@ _bound_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Network_Error) } @(private) -_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) { +_peer_endpoint :: proc(sock: Any_Socket) -> (ep: Endpoint, err: Socket_Info_Error) { + sockaddr: win.SOCKADDR_STORAGE_LH + sockaddrlen := c.int(size_of(sockaddr)) + res := win.getpeername(win.SOCKET(any_socket_to_socket(sock)), &sockaddr, &sockaddrlen) + if res < 0 { + err = _socket_info_error() + return + } + + ep = _sockaddr_to_endpoint(&sockaddr) + return +} + +@(private) +_accept_tcp :: proc(sock: TCP_Socket, options := DEFAULT_TCP_OPTIONS) -> (client: TCP_Socket, source: Endpoint, err: Accept_Error) { for { sockaddr: win.SOCKADDR_STORAGE_LH sockaddrlen := c.int(size_of(sockaddr)) @@ -150,7 +218,7 @@ _accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client // can do this to match the behaviour. continue } - err = Accept_Error(e) + err = _accept_error() return } client = TCP_Socket(client_sock) @@ -170,20 +238,20 @@ _close :: proc(socket: Any_Socket) { } @(private) -_recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: Network_Error) { +_recv_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_read: int, err: TCP_Recv_Error) { if len(buf) <= 0 { return } res := win.recv(win.SOCKET(socket), raw_data(buf), c.int(len(buf)), 0) if res < 0 { - err = TCP_Recv_Error(win.WSAGetLastError()) + err = _tcp_recv_error() return } return int(res), nil } @(private) -_recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: Network_Error) { +_recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: UDP_Recv_Error) { if len(buf) <= 0 { return } @@ -192,7 +260,7 @@ _recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_e fromsize := c.int(size_of(from)) res := win.recvfrom(win.SOCKET(socket), raw_data(buf), c.int(len(buf)), 0, &from, &fromsize) if res < 0 { - err = UDP_Recv_Error(win.WSAGetLastError()) + err = _udp_recv_error() return } @@ -202,13 +270,13 @@ _recv_udp :: proc(socket: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_e } @(private) -_send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Network_Error) { +_send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: TCP_Send_Error) { for bytes_written < len(buf) { limit := min(int(max(i32)), len(buf) - bytes_written) remaining := buf[bytes_written:] res := win.send(win.SOCKET(socket), raw_data(remaining), c.int(limit), 0) if res < 0 { - err = TCP_Send_Error(win.WSAGetLastError()) + err = _tcp_send_error() return } bytes_written += int(res) @@ -217,34 +285,34 @@ _send_tcp :: proc(socket: TCP_Socket, buf: []byte) -> (bytes_written: int, err: } @(private) -_send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: Network_Error) { - if len(buf) > int(max(c.int)) { - // NOTE(tetra): If we don't guard this, we'll return (0, nil) instead, which is misleading. - err = .Message_Too_Long - return - } +_send_udp :: proc(socket: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: UDP_Send_Error) { toaddr := _endpoint_to_sockaddr(to) - res := win.sendto(win.SOCKET(socket), raw_data(buf), c.int(len(buf)), 0, &toaddr, size_of(toaddr)) - if res < 0 { - err = UDP_Send_Error(win.WSAGetLastError()) - return + for bytes_written < len(buf) { + limit := min(int(max(i32)), len(buf) - bytes_written) + remaining := buf[bytes_written:] + res := win.sendto(win.SOCKET(socket), raw_data(remaining), c.int(limit), 0, &toaddr, size_of(toaddr)) + if res < 0 { + err = _udp_send_error() + return + } + + bytes_written += int(res) } - bytes_written = int(res) return } @(private) -_shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) { +_shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Shutdown_Error) { s := any_socket_to_socket(socket) res := win.shutdown(win.SOCKET(s), c.int(manner)) if res < 0 { - return Shutdown_Error(win.WSAGetLastError()) + return _shutdown_error() } return } @(private) -_set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error { +_set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Socket_Option_Error { level := win.SOL_SOCKET if option != .TCP_Nodelay else win.IPPROTO_TCP bool_value: b32 @@ -283,11 +351,8 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca t := value.(time.Duration) or_else panic("set_option() value must be a time.Duration here", loc) num_secs := i64(time.duration_seconds(t)) - if time.Duration(num_secs * 1e9) != t { - return .Linger_Only_Supports_Whole_Seconds - } if num_secs > i64(max(u16)) { - return .Value_Out_Of_Range + return .Invalid_Value } linger_value.l_onoff = 1 linger_value.l_linger = c.ushort(num_secs) @@ -323,19 +388,19 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca socket := any_socket_to_socket(s) res := win.setsockopt(win.SOCKET(socket), c.int(level), c.int(option), ptr, len) if res < 0 { - return Socket_Option_Error(win.WSAGetLastError()) + return _socket_option_error() } return nil } @(private) -_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) { +_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Set_Blocking_Error) { socket := any_socket_to_socket(socket) arg: win.DWORD = 0 if should_block else 1 res := win.ioctlsocket(win.SOCKET(socket), transmute(win.c_long)win.FIONBIO, &arg) if res == win.SOCKET_ERROR { - return Set_Blocking_Error(win.WSAGetLastError()) + return _set_blocking_error() } return nil diff --git a/core/net/url.odin b/core/net/url.odin index aadcf5e48..41c315585 100644 --- a/core/net/url.odin +++ b/core/net/url.odin @@ -125,7 +125,7 @@ percent_encode :: proc(s: string, allocator := context.allocator) -> string { bytes, n := utf8.encode_rune(ch) for byte in bytes[:n] { buf: [2]u8 = --- - t := strconv.append_int(buf[:], i64(byte), 16) + t := strconv.write_int(buf[:], i64(byte), 16) strings.write_rune(&b, '%') strings.write_string(&b, t) } diff --git a/core/odin/doc-format/doc_format.odin b/core/odin/doc-format/doc_format.odin index c2d86a0ba..e6804c981 100644 --- a/core/odin/doc-format/doc_format.odin +++ b/core/odin/doc-format/doc_format.odin @@ -180,7 +180,7 @@ Type_Kind :: enum u32le { Struct = 10, Union = 11, Enum = 12, - Tuple = 13, + Parameters = 13, Proc = 14, Bit_Set = 15, Simd_Vector = 16, @@ -256,10 +256,10 @@ Type :: struct { types: Array(Type_Index), // Used by: - // .Named - 1 field for the definition - // .Struct - fields - // .Enum - fields - // .Tuple - parameters (procedures only) + // .Named - 1 field for the definition + // .Struct - fields + // .Enum - fields + // .Parameters - parameters (procedures only) entities: Array(Entity_Index), // Used By: .Struct, .Union diff --git a/core/odin/parser/file_tags.odin b/core/odin/parser/file_tags.odin index c5c6637c3..24aea3b9e 100644 --- a/core/odin/parser/file_tags.odin +++ b/core/odin/parser/file_tags.odin @@ -30,14 +30,27 @@ File_Tags :: struct { } @require_results -get_build_os_from_string :: proc(str: string) -> runtime.Odin_OS_Type { +get_build_os_from_string :: proc(str: string) -> (found_os: runtime.Odin_OS_Type, found_subtarget: runtime.Odin_Platform_Subtarget_Type) { + str_os, _, str_subtarget := strings.partition(str, ":") + fields := reflect.enum_fields_zipped(runtime.Odin_OS_Type) for os in fields { - if strings.equal_fold(os.name, str) { - return runtime.Odin_OS_Type(os.value) + if strings.equal_fold(os.name, str_os) { + found_os = runtime.Odin_OS_Type(os.value) + break } } - return .Unknown + if str_subtarget != "" { + st_fields := reflect.enum_fields_zipped(runtime.Odin_Platform_Subtarget_Type) + for subtarget in st_fields { + if strings.equal_fold(subtarget.name, str_subtarget) { + found_subtarget = runtime.Odin_Platform_Subtarget_Type(subtarget.value) + break + } + } + } + + return } @require_results get_build_arch_from_string :: proc(str: string) -> runtime.Odin_Arch_Type { @@ -187,7 +200,8 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags if value == "ignore" { tags.ignore = true - } else if os := get_build_os_from_string(value); os != .Unknown { + } else if os, subtarget := get_build_os_from_string(value); os != .Unknown { + _ = subtarget // TODO(bill): figure out how to handle the subtarget logic if is_notted { os_negative += {os} } else { diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 63c7e388f..dab2d5d6a 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -348,27 +348,30 @@ consume_comment_group :: proc(p: ^Parser, n: int) -> (comments: ^ast.Comment_Gro } consume_comment_groups :: proc(p: ^Parser, prev: tokenizer.Token) { - if p.curr_tok.kind == .Comment { - comment: ^ast.Comment_Group - end_line := 0 - - if p.curr_tok.pos.line == prev.pos.line { - comment, end_line = consume_comment_group(p, 0) - if p.curr_tok.pos.line != end_line || p.curr_tok.kind == .EOF { - p.line_comment = comment - } - } - - end_line = -1 - for p.curr_tok.kind == .Comment { - comment, end_line = consume_comment_group(p, 1) - } - if end_line+1 >= p.curr_tok.pos.line || end_line < 0 { - p.lead_comment = comment - } - - assert(p.curr_tok.kind != .Comment) + if p.curr_tok.kind != .Comment { + return } + comment: ^ast.Comment_Group + end_line := 0 + + if p.curr_tok.pos.line == prev.pos.line { + comment, end_line = consume_comment_group(p, 0) + if p.curr_tok.pos.line != end_line || + p.curr_tok.pos.line == prev.pos.line+1 || + p.curr_tok.kind == .EOF { + p.line_comment = comment + } + } + + end_line = -1 + for p.curr_tok.kind == .Comment { + comment, end_line = consume_comment_group(p, 1) + } + if end_line+1 >= p.curr_tok.pos.line || end_line < 0 { + p.lead_comment = comment + } + + assert(p.curr_tok.kind != .Comment) } advance_token :: proc(p: ^Parser) -> tokenizer.Token { @@ -1276,28 +1279,28 @@ parse_unrolled_for_loop :: proc(p: ^Parser, inline_tok: tokenizer.Token) -> ^ast args = make([dynamic]^ast.Expr) for p.curr_tok.kind != .Close_Paren && p.curr_tok.kind != .EOF { - arg := parse_value(p) + arg := parse_value(p) - if p.curr_tok.kind == .Eq { - eq := expect_token(p, .Eq) - if arg != nil { - if _, ok := arg.derived.(^ast.Ident); !ok { - error(p, arg.pos, "expected an identifier for 'key=value'") - } - } - value := parse_value(p) - fv := ast.new(ast.Field_Value, arg.pos, value) - fv.field = arg - fv.sep = eq.pos - fv.value = value + if p.curr_tok.kind == .Eq { + eq := expect_token(p, .Eq) + if arg != nil { + if _, ok := arg.derived.(^ast.Ident); !ok { + error(p, arg.pos, "expected an identifier for 'key=value'") + } + } + value := parse_value(p) + fv := ast.new(ast.Field_Value, arg.pos, value) + fv.field = arg + fv.sep = eq.pos + fv.value = value - arg = fv - } + arg = fv + } - append(&args, arg) + append(&args, arg) allow_token(p, .Comma) or_break - } + } } p.expr_level -= 1 @@ -2307,6 +2310,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { open := expect_token(p, .Open_Paren) p.expr_level += 1 expr := parse_expr(p, false) + skip_possible_newline(p) p.expr_level -= 1 close := expect_token(p, .Close_Paren) @@ -2481,7 +2485,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { allow_token(p, .Comma) or_break } - close := expect_token(p, .Close_Brace) + close := expect_closing_brace_of_field_list(p) if len(args) == 0 { error(p, tok.pos, "expected at least 1 argument in procedure group") @@ -2922,6 +2926,8 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { fields: [dynamic]^ast.Bit_Field_Field for p.curr_tok.kind != .Close_Brace && p.curr_tok.kind != .EOF { + docs := p.lead_comment + name := parse_ident(p) expect_token(p, .Colon) type := parse_type(p) @@ -2932,6 +2938,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { if p.curr_tok.kind == .String { tag = expect_token(p, .String) } + ok := allow_token(p, .Comma) field := ast.new(ast.Bit_Field_Field, name.pos, bit_size) @@ -2939,10 +2946,14 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { field.type = type field.bit_size = bit_size field.tag = tag + field.docs = docs + field.comments = p.line_comment append(&fields, field) - allow_token(p, .Comma) or_break + if !ok { + break + } } close := expect_closing_brace_of_field_list(p) @@ -3526,6 +3537,7 @@ parse_binary_expr :: proc(p: ^Parser, lhs: bool, prec_in: int) -> ^ast.Expr { case .When: x := expr cond := parse_expr(p, lhs) + skip_possible_newline(p) else_tok := expect_token(p, .Else) y := parse_expr(p, lhs) te := ast.new(ast.Ternary_When_Expr, expr.pos, end_pos(p.prev_tok)) @@ -3780,10 +3792,6 @@ parse_import_decl :: proc(p: ^Parser, kind := Import_Decl_Kind.Standard) -> ^ast import_name.pos = p.curr_tok.pos } - if !is_using && is_blank_ident(import_name) { - error(p, import_name.pos, "illegal import name: '_'") - } - path := expect_token_after(p, .String, "import") decl := ast.new(ast.Import_Decl, tok.pos, end_pos(path)) diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin index d4da82c56..a9d367a4d 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -209,14 +209,14 @@ scan_comment :: proc(t: ^Tokenizer) -> string { scan_file_tag :: proc(t: ^Tokenizer) -> string { offset := t.offset - 1 - for t.ch != '\n' { + for t.ch != '\n' && t.ch != utf8.RUNE_EOF { if t.ch == '/' { next := peek_byte(t, 0) if next == '/' || next == '*' { break } - } + } advance_rune(t) } diff --git a/core/os/dir_unix.odin b/core/os/dir_unix.odin index f06bf8b37..c3dd844ef 100644 --- a/core/os/dir_unix.odin +++ b/core/os/dir_unix.odin @@ -5,9 +5,10 @@ import "core:strings" @(require_results) read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Error) { - dupfd := _dup(fd) or_return + context.allocator = allocator - dirp := _fdopendir(dupfd) or_return + dupfd := _dup(fd) or_return + dirp := _fdopendir(dupfd) or_return defer _closedir(dirp) dirpath := absolute_path_from_handle(dupfd) or_return diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index ae3e6922c..40f4b9e9b 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -87,7 +87,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F defer delete(path) find_data := &win32.WIN32_FIND_DATAW{} - find_handle := win32.FindFirstFileW(raw_data(wpath_search), find_data) + find_handle := win32.FindFirstFileW(cstring16(raw_data(wpath_search)), find_data) if find_handle == win32.INVALID_HANDLE_VALUE { err = get_last_error() return dfi[:], err diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index efd002342..ef658b0a1 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -8,7 +8,7 @@ import "base:runtime" // Otherwise the returned value will be empty and the boolean will be false // NOTE: the value will be allocated with the supplied allocator @(require_results) -lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { if key == "" { return } @@ -29,17 +29,54 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin return } +// This version of `lookup_env` doesn't allocate and instead requires the user to provide a buffer. +// Note that it is limited to environment names and values of 512 utf-16 values each +// due to the necessary utf-8 <> utf-16 conversion. +@(require_results) +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + key_buf: [513]u16 + wkey := win32.utf8_to_wstring(key_buf[:], key) + if wkey == nil { + return "", .Buffer_Full + } + + n2 := win32.GetEnvironmentVariableW(wkey, nil, 0) + if n2 == 0 { + return "", .Env_Var_Not_Found + } + + val_buf: [513]u16 + n2 = win32.GetEnvironmentVariableW(wkey, raw_data(val_buf[:]), u32(len(val_buf[:]))) + if n2 == 0 { + return "", .Env_Var_Not_Found + } else if int(n2) > len(buf) { + return "", .Buffer_Full + } + + value = win32.utf16_to_utf8(buf, val_buf[:n2]) + + return value, nil +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} // get_env retrieves the value of the environment variable named by the key // It returns the value, which will be empty if the variable is not present // To distinguish between an empty value and an unset value, use lookup_env // NOTE: the value will be allocated with the supplied allocator @(require_results) -get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} + + // set_env sets the value of the environment variable named by the key set_env :: proc(key, value: string) -> Error { k := win32.utf8_to_wstring(key) diff --git a/core/os/errors.odin b/core/os/errors.odin index 691397f4b..bf4cf27ff 100644 --- a/core/os/errors.odin +++ b/core/os/errors.odin @@ -35,6 +35,9 @@ General_Error :: enum u32 { File_Is_Pipe, Not_Dir, + + // Environment variable not found. + Env_Var_Not_Found, } @@ -82,6 +85,7 @@ error_string :: proc "contextless" (ferr: Error) -> string { case .Pattern_Has_Separator: return "pattern has separator" case .File_Is_Pipe: return "file is pipe" case .Not_Dir: return "file is not directory" + case .Env_Var_Not_Found: return "environment variable not found" } case io.Error: switch e { diff --git a/core/os/os.odin b/core/os/os.odin index 30b86d4cd..fe08edff4 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -4,6 +4,7 @@ import "base:intrinsics" import "base:runtime" import "core:io" import "core:strconv" +import "core:strings" import "core:unicode/utf8" @@ -57,7 +58,7 @@ write_encoded_rune :: proc(f: Handle, r: rune) -> (n: int, err: Error) { if r < 32 { if wrap(write_string(f, "\\x"), &n, &err) { return } b: [2]byte - s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) + s := strconv.write_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) switch len(s) { case 0: if wrap(write_string(f, "00"), &n, &err) { return } case 1: if wrap(write_rune(f, '0'), &n, &err) { return } @@ -210,3 +211,55 @@ heap_free :: runtime.heap_free processor_core_count :: proc() -> int { return _processor_core_count() } + +// Always allocates for consistency. +replace_environment_placeholders :: proc(path: string, allocator := context.allocator) -> (res: string) { + path := path + + sb: strings.Builder + strings.builder_init_none(&sb, allocator) + for len(path) > 0 { + switch path[0] { + case '%': // Windows + when ODIN_OS == .Windows { + for r, i in path[1:] { + if r == '%' { + env_key := path[1:i+1] + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[i+1:] // % is part of key, so skip 1 character extra + } + } + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case '$': // Posix + when ODIN_OS != .Windows { + env_key := "" + dollar_loop: for r, i in path[1:] { + switch r { + case 'A'..='Z', 'a'..='z', '0'..='9', '_': // Part of key ident + case: + env_key = path[1:i+1] + break dollar_loop + } + } + if len(env_key) > 0 { + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[len(env_key):] + } + + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case: + strings.write_rune(&sb, rune(path[0])) + } + + path = path[1:] + } + return strings.to_string(sb) +} \ No newline at end of file diff --git a/core/os/os2/allocators.odin b/core/os/os2/allocators.odin index 864532850..36a7d72be 100644 --- a/core/os/os2/allocators.odin +++ b/core/os/os2/allocators.odin @@ -8,66 +8,67 @@ file_allocator :: proc() -> runtime.Allocator { return heap_allocator() } -temp_allocator_proc :: runtime.arena_allocator_proc - @(private="file") MAX_TEMP_ARENA_COUNT :: 2 - +@(private="file") +MAX_TEMP_ARENA_COLLISIONS :: MAX_TEMP_ARENA_COUNT - 1 @(private="file", thread_local) global_default_temp_allocator_arenas: [MAX_TEMP_ARENA_COUNT]runtime.Arena -@(private="file", thread_local) -global_default_temp_allocator_index: uint - - -@(require_results) -temp_allocator :: proc() -> runtime.Allocator { - arena := &global_default_temp_allocator_arenas[global_default_temp_allocator_index] - if arena.backing_allocator.procedure == nil { - arena.backing_allocator = heap_allocator() - } - - return runtime.Allocator{ - procedure = temp_allocator_proc, - data = arena, - } -} - - - -@(require_results) -temp_allocator_temp_begin :: proc(loc := #caller_location) -> (temp: runtime.Arena_Temp) { - temp = runtime.arena_temp_begin(&global_default_temp_allocator_arenas[global_default_temp_allocator_index], loc) - return -} - -temp_allocator_temp_end :: proc(temp: runtime.Arena_Temp, loc := #caller_location) { - runtime.arena_temp_end(temp, loc) -} - @(fini, private) -temp_allocator_fini :: proc() { +temp_allocator_fini :: proc "contextless" () { for &arena in global_default_temp_allocator_arenas { runtime.arena_destroy(&arena) } global_default_temp_allocator_arenas = {} } -TEMP_ALLOCATOR_GUARD_END :: proc(temp: runtime.Arena_Temp, loc := #caller_location) { - runtime.arena_temp_end(temp, loc) - if temp.arena != nil { - global_default_temp_allocator_index = (global_default_temp_allocator_index-1)%MAX_TEMP_ARENA_COUNT - } +Temp_Allocator :: struct { + using arena: ^runtime.Arena, + using allocator: runtime.Allocator, + tmp: runtime.Arena_Temp, + loc: runtime.Source_Code_Location, +} + +TEMP_ALLOCATOR_GUARD_END :: proc(temp: Temp_Allocator) { + runtime.arena_temp_end(temp.tmp, temp.loc) } @(deferred_out=TEMP_ALLOCATOR_GUARD_END) -TEMP_ALLOCATOR_GUARD :: #force_inline proc(loc := #caller_location) -> (runtime.Arena_Temp, runtime.Source_Code_Location) { - global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT - tmp := temp_allocator_temp_begin(loc) - return tmp, loc +TEMP_ALLOCATOR_GUARD :: #force_inline proc(collisions: []runtime.Allocator, loc := #caller_location) -> Temp_Allocator { + assert(len(collisions) <= MAX_TEMP_ARENA_COLLISIONS, "Maximum collision count exceeded. MAX_TEMP_ARENA_COUNT must be increased!") + good_arena: ^runtime.Arena + for i in 0.. (runtime.Arena_Temp) { + return temp_allocator_begin(tmp.arena) +} +@(private="file") +_temp_allocator_end :: proc(tmp: runtime.Arena_Temp) { + temp_allocator_end(tmp) } @(init, private) -init_thread_local_cleaner :: proc() { +init_thread_local_cleaner :: proc "contextless" () { runtime.add_thread_local_cleaner(temp_allocator_fini) } diff --git a/core/os/os2/dir.odin b/core/os/os2/dir.odin index 4a7762ded..10b06a8ce 100644 --- a/core/os/os2/dir.odin +++ b/core/os/os2/dir.odin @@ -2,6 +2,7 @@ package os2 import "base:runtime" import "core:slice" +import "core:strings" read_dir :: read_directory @@ -18,12 +19,12 @@ read_directory :: proc(f: ^File, n: int, allocator: runtime.Allocator) -> (files size = 100 } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) it := read_directory_iterator_create(f) defer _read_directory_iterator_destroy(&it) - dfi := make([dynamic]File_Info, 0, size, temp_allocator()) + dfi := make([dynamic]File_Info, 0, size, temp_allocator) defer if err != nil { for fi in dfi { file_info_delete(fi, allocator) @@ -192,3 +193,56 @@ read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, return _read_directory_iterator(it) } + +// Recursively copies a directory to `dst` from `src` +copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error { + when #defined(_copy_directory_all_native) { + return _copy_directory_all_native(dst, src, dst_perm) + } else { + return _copy_directory_all(dst, src, dst_perm) + } +} + +@(private) +_copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error { + err := make_directory(dst, dst_perm) + if err != nil && err != .Exist { + return err + } + + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + + abs_src := get_absolute_path(src, temp_allocator) or_return + abs_dst := get_absolute_path(dst, temp_allocator) or_return + + dst_buf := make([dynamic]byte, 0, len(abs_dst) + 256, temp_allocator) or_return + + w: Walker + walker_init_path(&w, src) + defer walker_destroy(&w) + + for info in walker_walk(&w) { + _ = walker_error(&w) or_break + + rel := strings.trim_prefix(info.fullpath, abs_src) + + non_zero_resize(&dst_buf, 0) + reserve(&dst_buf, len(abs_dst) + len(Path_Separator_String) + len(rel)) or_return + append(&dst_buf, abs_dst) + append(&dst_buf, Path_Separator_String) + append(&dst_buf, rel) + + if info.type == .Directory { + err = make_directory(string(dst_buf[:]), dst_perm) + if err != nil && err != .Exist { + return err + } + } else { + copy_file(string(dst_buf[:]), info.fullpath) or_return + } + } + + _ = walker_error(&w) or_return + + return nil +} diff --git a/core/os/os2/dir_linux.odin b/core/os/os2/dir_linux.odin index a868a02c4..34346c02f 100644 --- a/core/os/os2/dir_linux.odin +++ b/core/os/os2/dir_linux.odin @@ -78,7 +78,8 @@ _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info it.impl.prev_fi = fi if err != nil { - path, _ := _get_full_path(entry_fd, temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + path, _ := _get_full_path(entry_fd, temp_allocator) read_directory_iterator_set_error(it, path, err) } diff --git a/core/os/os2/dir_posix_darwin.odin b/core/os/os2/dir_posix_darwin.odin new file mode 100644 index 000000000..3cae50d25 --- /dev/null +++ b/core/os/os2/dir_posix_darwin.odin @@ -0,0 +1,17 @@ +#+private +package os2 + +import "core:sys/darwin" + +_copy_directory_all_native :: proc(dst, src: string, dst_perm := 0o755) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + + csrc := clone_to_cstring(src, temp_allocator) or_return + cdst := clone_to_cstring(dst, temp_allocator) or_return + + if darwin.copyfile(csrc, cdst, nil, darwin.COPYFILE_ALL + {.RECURSIVE}) < 0 { + err = _get_platform_error() + } + + return +} diff --git a/core/os/os2/dir_windows.odin b/core/os/os2/dir_windows.odin index d592e8036..6c754a677 100644 --- a/core/os/os2/dir_windows.odin +++ b/core/os/os2/dir_windows.odin @@ -14,7 +14,9 @@ find_data_to_file_info :: proc(base_path: string, d: ^win32.WIN32_FIND_DATAW, al if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 { return } - path := concatenate({base_path, `\`, win32_utf16_to_utf8(d.cFileName[:], temp_allocator()) or_else ""}, allocator) or_return + + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + path := concatenate({base_path, `\`, win32_wstring_to_utf8(cstring16(raw_data(d.cFileName[:])), temp_allocator) or_else ""}, allocator) or_return handle := win32.HANDLE(_open_internal(path, {.Read}, 0o666) or_else 0) defer win32.CloseHandle(handle) @@ -49,8 +51,6 @@ Read_Directory_Iterator_Impl :: struct { @(require_results) _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) { - TEMP_ALLOCATOR_GUARD() - for !it.impl.no_more_files { err: Error file_info_delete(it.impl.prev_fi, file_allocator()) @@ -107,24 +107,16 @@ _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) { return } - wpath: []u16 - { - i := 0 - for impl.wname[i] != 0 { - i += 1 - } - wpath = impl.wname[:i] - } + wpath := string16(impl.wname) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) - TEMP_ALLOCATOR_GUARD() - - wpath_search := make([]u16, len(wpath)+3, temp_allocator()) + wpath_search := make([]u16, len(wpath)+3, temp_allocator) copy(wpath_search, wpath) wpath_search[len(wpath)+0] = '\\' wpath_search[len(wpath)+1] = '*' wpath_search[len(wpath)+2] = 0 - it.impl.find_handle = win32.FindFirstFileW(raw_data(wpath_search), &it.impl.find_data) + it.impl.find_handle = win32.FindFirstFileW(cstring16(raw_data(wpath_search)), &it.impl.find_data) if it.impl.find_handle == win32.INVALID_HANDLE_VALUE { read_directory_iterator_set_error(it, impl.name, _get_platform_error()) return diff --git a/core/os/os2/env.odin b/core/os/os2/env.odin index 13c107f3c..310d45af1 100644 --- a/core/os/os2/env.odin +++ b/core/os/os2/env.odin @@ -1,26 +1,49 @@ package os2 import "base:runtime" +import "core:strings" -// get_env retrieves the value of the environment variable named by the key +// `get_env` retrieves the value of the environment variable named by the key // It returns the value, which will be empty if the variable is not present // To distinguish between an empty value and an unset value, use lookup_env // NOTE: the value will be allocated with the supplied allocator @(require_results) -get_env :: proc(key: string, allocator: runtime.Allocator) -> string { +get_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> string { value, _ := lookup_env(key, allocator) return value } -// lookup_env gets the value of the environment variable named by the key +// `get_env` retrieves the value of the environment variable named by the key +// It returns the value, which will be empty if the variable is not present +// To distinguish between an empty value and an unset value, use lookup_env +// NOTE: this version takes a backing buffer for the string value +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> string { + value, _ := lookup_env(buf, key) + return value +} + +get_env :: proc{get_env_alloc, get_env_buf} + +// `lookup_env` gets the value of the environment variable named by the key // If the variable is found in the environment the value (which can be empty) is returned and the boolean is true // Otherwise the returned value will be empty and the boolean will be false // NOTE: the value will be allocated with the supplied allocator @(require_results) -lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { - return _lookup_env(key, allocator) +lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { + return _lookup_env_alloc(key, allocator) } +// This version of `lookup_env` doesn't allocate and instead requires the user to provide a buffer. +// Note that it is limited to environment names and values of 512 utf-16 values each +// due to the necessary utf-8 <> utf-16 conversion. +@(require_results) +lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + return _lookup_env_buf(buf, key) +} + +lookup_env :: proc{lookup_env_alloc, lookup_env_buf} + // set_env sets the value of the environment variable named by the key // Returns Error on failure set_env :: proc(key, value: string) -> Error { @@ -45,4 +68,55 @@ environ :: proc(allocator: runtime.Allocator) -> ([]string, Error) { return _environ(allocator) } +// Always allocates for consistency. +replace_environment_placeholders :: proc(path: string, allocator: runtime.Allocator) -> (res: string) { + path := path + sb: strings.Builder + strings.builder_init_none(&sb, allocator) + + for len(path) > 0 { + switch path[0] { + case '%': // Windows + when ODIN_OS == .Windows { + for r, i in path[1:] { + if r == '%' { + env_key := path[1:i+1] + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[i+1:] // % is part of key, so skip 1 character extra + } + } + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case '$': // Posix + when ODIN_OS != .Windows { + env_key := "" + dollar_loop: for r, i in path[1:] { + switch r { + case 'A'..='Z', 'a'..='z', '0'..='9', '_': // Part of key ident + case: + env_key = path[1:i+1] + break dollar_loop + } + } + if len(env_key) > 0 { + env_val := get_env(env_key, context.temp_allocator) + strings.write_string(&sb, env_val) + path = path[len(env_key):] + } + + } else { + strings.write_rune(&sb, rune(path[0])) + } + + case: + strings.write_rune(&sb, rune(path[0])) + } + + path = path[1:] + } + return strings.to_string(sb) +} \ No newline at end of file diff --git a/core/os/os2/env_linux.odin b/core/os/os2/env_linux.odin index f24bd8d84..e003b0717 100644 --- a/core/os/os2/env_linux.odin +++ b/core/os/os2/env_linux.odin @@ -20,19 +20,18 @@ NOT_FOUND :: -1 // the environment is a 0 delimited list of = strings _env: [dynamic]string -_env_mutex: sync.Mutex +_env_mutex: sync.Recursive_Mutex // We need to be able to figure out if the environment variable // is contained in the original environment or not. This also // serves as a flag to determine if we have built _env. -_org_env_begin: uintptr -_org_env_end: uintptr +_org_env_begin: uintptr // atomic +_org_env_end: uintptr // guarded by _env_mutex // Returns value + index location into _env // or -1 if not found _lookup :: proc(key: string) -> (value: string, idx: int) { - sync.mutex_lock(&_env_mutex) - defer sync.mutex_unlock(&_env_mutex) + sync.guard(&_env_mutex) for entry, i in _env { if k, v := _kv_from_entry(entry); k == key { @@ -42,8 +41,8 @@ _lookup :: proc(key: string) -> (value: string, idx: int) { return "", -1 } -_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { - if _org_env_begin == 0 { +_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { + if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) == 0 { _build_env() } @@ -54,19 +53,35 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string return } -_set_env :: proc(key, v_new: string) -> Error { - if _org_env_begin == 0 { +_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) == 0 { _build_env() } + if v, idx := _lookup(key); idx != -1 { + if len(buf) >= len(v) { + copy(buf, v) + return string(buf[:len(v)]), nil + } + return "", .Buffer_Full + } + return "", .Env_Var_Not_Found +} + +_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf} + +_set_env :: proc(key, v_new: string) -> Error { + if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) == 0 { + _build_env() + } + sync.guard(&_env_mutex) + // all key values are stored as "key=value\x00" kv_size := len(key) + len(v_new) + 2 if v_curr, idx := _lookup(key); idx != NOT_FOUND { if v_curr == v_new { return nil } - sync.mutex_lock(&_env_mutex) - defer sync.mutex_unlock(&_env_mutex) unordered_remove(&_env, idx) @@ -101,16 +116,15 @@ _set_env :: proc(key, v_new: string) -> Error { intrinsics.mem_copy_non_overlapping(&val_slice[0], raw_data(v_new), len(v_new)) val_slice[len(v_new)] = 0 - sync.mutex_lock(&_env_mutex) append(&_env, string(k_addr[:kv_size - 1])) - sync.mutex_unlock(&_env_mutex) return nil } _unset_env :: proc(key: string) -> bool { - if _org_env_begin == 0 { + if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) == 0 { _build_env() } + sync.guard(&_env_mutex) v: string i: int @@ -118,15 +132,13 @@ _unset_env :: proc(key: string) -> bool { return false } - sync.mutex_lock(&_env_mutex) unordered_remove(&_env, i) - sync.mutex_unlock(&_env_mutex) if _is_in_org_env(v) { return true } - // if we got this far, the envrionment variable + // if we got this far, the environment variable // existed AND was allocated by us. k_addr, _ := _kv_addr_from_val(v, key) runtime.heap_free(k_addr) @@ -134,8 +146,7 @@ _unset_env :: proc(key: string) -> bool { } _clear_env :: proc() { - sync.mutex_lock(&_env_mutex) - defer sync.mutex_unlock(&_env_mutex) + sync.guard(&_env_mutex) for kv in _env { if !_is_in_org_env(kv) { @@ -145,14 +156,16 @@ _clear_env :: proc() { clear(&_env) // nothing resides in the original environment either - _org_env_begin = ~uintptr(0) + intrinsics.atomic_store_explicit(&_org_env_begin, ~uintptr(0), .Release) _org_env_end = ~uintptr(0) } _environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error) { - if _org_env_begin == 0 { + if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) == 0 { _build_env() } + sync.guard(&_env_mutex) + env := make([dynamic]string, 0, len(_env), allocator) or_return defer if err != nil { for e in env { @@ -161,8 +174,6 @@ _environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error delete(env) } - sync.mutex_lock(&_env_mutex) - defer sync.mutex_unlock(&_env_mutex) for entry in _env { s := clone_string(entry, allocator) or_return append(&env, s) @@ -174,7 +185,7 @@ _environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error // The entire environment is stored as 0 terminated strings, // so there is no need to clone/free individual variables export_cstring_environment :: proc(allocator: runtime.Allocator) -> []cstring { - if _org_env_begin == 0 { + if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) == 0 { // The environment has not been modified, so we can just // send the original environment org_env := _get_original_env() @@ -182,12 +193,11 @@ export_cstring_environment :: proc(allocator: runtime.Allocator) -> []cstring { for ; org_env[n] != nil; n += 1 {} return slice.clone(org_env[:n + 1], allocator) } + sync.guard(&_env_mutex) // NOTE: already terminated by nil pointer via + 1 env := make([]cstring, len(_env) + 1, allocator) - sync.mutex_lock(&_env_mutex) - defer sync.mutex_unlock(&_env_mutex) for entry, i in _env { env[i] = cstring(raw_data(entry)) } @@ -195,15 +205,14 @@ export_cstring_environment :: proc(allocator: runtime.Allocator) -> []cstring { } _build_env :: proc() { - sync.mutex_lock(&_env_mutex) - defer sync.mutex_unlock(&_env_mutex) - if _org_env_begin != 0 { + sync.guard(&_env_mutex) + if intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) != 0 { return } _env = make(type_of(_env), runtime.heap_allocator()) cstring_env := _get_original_env() - _org_env_begin = uintptr(rawptr(cstring_env[0])) + intrinsics.atomic_store_explicit(&_org_env_begin, uintptr(rawptr(cstring_env[0])), .Release) for i := 0; cstring_env[i] != nil; i += 1 { bytes := ([^]u8)(cstring_env[i]) n := len(cstring_env[i]) @@ -235,5 +244,5 @@ _kv_addr_from_val :: #force_inline proc(val: string, key: string) -> ([^]u8, [^] _is_in_org_env :: #force_inline proc(env_data: string) -> bool { addr := uintptr(raw_data(env_data)) - return addr >= _org_env_begin && addr < _org_env_end + return addr >= intrinsics.atomic_load_explicit(&_org_env_begin, .Acquire) && addr < _org_env_end } diff --git a/core/os/os2/env_posix.odin b/core/os/os2/env_posix.odin index 3db8d817a..84500d139 100644 --- a/core/os/os2/env_posix.odin +++ b/core/os/os2/env_posix.odin @@ -7,14 +7,14 @@ import "base:runtime" import "core:strings" import "core:sys/posix" -_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { +_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { if key == "" { return } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - ckey := strings.clone_to_cstring(key, temp_allocator()) + ckey := strings.clone_to_cstring(key, temp_allocator) cval := posix.getenv(ckey) if cval == nil { return @@ -26,11 +26,41 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string return } -_set_env :: proc(key, value: string) -> (err: Error) { - TEMP_ALLOCATOR_GUARD() +_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, error: Error) { + if key == "" { + return + } - ckey := strings.clone_to_cstring(key, temp_allocator()) or_return - cval := strings.clone_to_cstring(key, temp_allocator()) or_return + if len(key) + 1 > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, key) + } + + cval := posix.getenv(cstring(raw_data(buf))) + if cval == nil { + return + } + + if value = string(cval); value == "" { + return "", .Env_Var_Not_Found + } else { + if len(value) > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, value) + return string(buf[:len(value)]), nil + } + } +} + +_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf} + +_set_env :: proc(key, value: string) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + + ckey := strings.clone_to_cstring(key, temp_allocator) or_return + cval := strings.clone_to_cstring(value, temp_allocator) or_return if posix.setenv(ckey, cval, true) != nil { err = _get_platform_error_from_errno() @@ -39,9 +69,9 @@ _set_env :: proc(key, value: string) -> (err: Error) { } _unset_env :: proc(key: string) -> (ok: bool) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) - ckey := strings.clone_to_cstring(key, temp_allocator()) + ckey := strings.clone_to_cstring(key, temp_allocator) ok = posix.unsetenv(ckey) == .OK return @@ -57,7 +87,7 @@ _clear_env :: proc() { } _environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error) { - n := 0 + n := 0 for entry := posix.environ[0]; entry != nil; n, entry = n+1, posix.environ[n] {} r := make([dynamic]string, 0, n, allocator) or_return diff --git a/core/os/os2/env_wasi.odin b/core/os/os2/env_wasi.odin index 305192c92..b126d014e 100644 --- a/core/os/os2/env_wasi.odin +++ b/core/os/os2/env_wasi.odin @@ -39,9 +39,9 @@ build_env :: proc() -> (err: Error) { g_env_buf = make([]byte, size_of_envs, file_allocator()) or_return defer if err != nil { delete(g_env_buf, file_allocator()) } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) - envs := make([]cstring, num_envs, temp_allocator()) or_return + envs := make([]cstring, num_envs, temp_allocator) or_return _err = wasi.environ_get(raw_data(envs), raw_data(g_env_buf)) if _err != nil { @@ -67,7 +67,7 @@ delete_string_if_not_original :: proc(str: string) { } @(require_results) -_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { +_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { if err := build_env(); err != nil { return } @@ -79,6 +79,34 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string return } +_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, error: Error) { + if key == "" { + return + } + + if len(key) + 1 > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, key) + } + + sync.shared_guard(&g_env_mutex) + + val, ok := g_env[key] + + if !ok { + return "", .Env_Var_Not_Found + } else { + if len(val) > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, val) + return string(buf[:len(val)]), nil + } + } +} +_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf} + @(require_results) _set_env :: proc(key, value: string) -> (err: Error) { build_env() or_return diff --git a/core/os/os2/env_windows.odin b/core/os/os2/env_windows.odin index 3ac26a261..d389f8860 100644 --- a/core/os/os2/env_windows.odin +++ b/core/os/os2/env_windows.odin @@ -4,12 +4,12 @@ package os2 import win32 "core:sys/windows" import "base:runtime" -_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { +_lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) { if key == "" { return } - TEMP_ALLOCATOR_GUARD() - wkey, _ := win32_utf8_to_wstring(key, temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + wkey, _ := win32_utf8_to_wstring(key, temp_allocator) n := win32.GetEnvironmentVariableW(wkey, nil, 0) if n == 0 { @@ -20,7 +20,7 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string return "", true } - b := make([]u16, n+1, temp_allocator()) + b := make([]u16, n+1, temp_allocator) n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b))) if n == 0 { @@ -31,15 +31,45 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string return "", false } - value = win32_utf16_to_utf8(b[:n], allocator) or_else "" + value = win32_utf16_to_utf8(string16(b[:n]), allocator) or_else "" found = true return } +// This version of `lookup_env` doesn't allocate and instead requires the user to provide a buffer. +// Note that it is limited to environment names and values of 512 utf-16 values each +// due to the necessary utf-8 <> utf-16 conversion. +@(require_results) +_lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + key_buf: [513]u16 + wkey := win32.utf8_to_wstring(key_buf[:], key) + if wkey == nil { + return "", .Buffer_Full + } + + n2 := win32.GetEnvironmentVariableW(wkey, nil, 0) + if n2 == 0 { + return "", .Env_Var_Not_Found + } + + val_buf: [513]u16 + n2 = win32.GetEnvironmentVariableW(wkey, raw_data(val_buf[:]), u32(len(val_buf[:]))) + if n2 == 0 { + return "", .Env_Var_Not_Found + } else if int(n2) > len(buf) { + return "", .Buffer_Full + } + + value = win32.utf16_to_utf8(buf, val_buf[:n2]) + + return value, nil +} +_lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf} + _set_env :: proc(key, value: string) -> Error { - TEMP_ALLOCATOR_GUARD() - k := win32_utf8_to_wstring(key, temp_allocator()) or_return - v := win32_utf8_to_wstring(value, temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + k := win32_utf8_to_wstring(key, temp_allocator) or_return + v := win32_utf8_to_wstring(value, temp_allocator) or_return if !win32.SetEnvironmentVariableW(k, v) { return _get_platform_error() @@ -48,14 +78,14 @@ _set_env :: proc(key, value: string) -> Error { } _unset_env :: proc(key: string) -> bool { - TEMP_ALLOCATOR_GUARD() - k, _ := win32_utf8_to_wstring(key, temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + k, _ := win32_utf8_to_wstring(key, temp_allocator) return bool(win32.SetEnvironmentVariableW(k, nil)) } _clear_env :: proc() { - TEMP_ALLOCATOR_GUARD() - envs, _ := environ(temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + envs, _ := environ(temp_allocator) for env in envs { for j in 1.. bool { @(require_results) is_file :: proc(path: string) -> bool { - TEMP_ALLOCATOR_GUARD() - fi, err := stat(path, temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + fi, err := stat(path, temp_allocator) if err != nil { return false } @@ -303,8 +303,8 @@ is_dir :: is_directory @(require_results) is_directory :: proc(path: string) -> bool { - TEMP_ALLOCATOR_GUARD() - fi, err := stat(path, temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + fi, err := stat(path, temp_allocator) if err != nil { return false } @@ -313,6 +313,15 @@ is_directory :: proc(path: string) -> bool { copy_file :: proc(dst_path, src_path: string) -> Error { + when #defined(_copy_file_native) { + return _copy_file_native(dst_path, src_path) + } else { + return _copy_file(dst_path, src_path) + } +} + +@(private) +_copy_file :: proc(dst_path, src_path: string) -> Error { src := open(src_path) or_return defer close(src) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 811ee7055..92f0c1541 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -45,8 +45,8 @@ _stderr := File{ } @init -_standard_stream_init :: proc() { - new_std :: proc(impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File { +_standard_stream_init :: proc "contextless" () { + new_std :: proc "contextless" (impl: ^File_Impl, fd: linux.Fd, name: string) -> ^File { impl.file.impl = impl impl.fd = linux.Fd(fd) impl.allocator = runtime.nil_allocator() @@ -66,8 +66,8 @@ _standard_stream_init :: proc() { } _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + name_cstr := clone_to_cstring(name, temp_allocator) or_return // Just default to using O_NOCTTY because needing to open a controlling // terminal would be incredibly rare. This has no effect on files while @@ -269,6 +269,7 @@ _write_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (nt: i64, err: Error return } +@(no_sanitize_memory) _file_size :: proc(f: ^File_Impl) -> (n: i64, err: Error) { // TODO: Identify 0-sized "pseudo" files and return No_Size. This would // eliminate the need for the _read_entire_pseudo_file procs. @@ -299,8 +300,8 @@ _truncate :: proc(f: ^File, size: i64) -> Error { } _remove :: proc(name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + name_cstr := clone_to_cstring(name, temp_allocator) or_return if fd, errno := linux.open(name_cstr, _OPENDIR_FLAGS + {.NOFOLLOW}); errno == .NONE { linux.close(fd) @@ -311,25 +312,25 @@ _remove :: proc(name: string) -> Error { } _rename :: proc(old_name, new_name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - old_name_cstr := temp_cstring(old_name) or_return - new_name_cstr := temp_cstring(new_name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + old_name_cstr := clone_to_cstring(old_name, temp_allocator) or_return + new_name_cstr := clone_to_cstring(new_name, temp_allocator) or_return return _get_platform_error(linux.rename(old_name_cstr, new_name_cstr)) } _link :: proc(old_name, new_name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - old_name_cstr := temp_cstring(old_name) or_return - new_name_cstr := temp_cstring(new_name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + old_name_cstr := clone_to_cstring(old_name, temp_allocator) or_return + new_name_cstr := clone_to_cstring(new_name, temp_allocator) or_return return _get_platform_error(linux.link(old_name_cstr, new_name_cstr)) } _symlink :: proc(old_name, new_name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - old_name_cstr := temp_cstring(old_name) or_return - new_name_cstr := temp_cstring(new_name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + old_name_cstr := clone_to_cstring(old_name, temp_allocator) or_return + new_name_cstr := clone_to_cstring(new_name, temp_allocator) or_return return _get_platform_error(linux.symlink(old_name_cstr, new_name_cstr)) } @@ -352,14 +353,14 @@ _read_link_cstr :: proc(name_cstr: cstring, allocator: runtime.Allocator) -> (st } _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, e: Error) { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + name_cstr := clone_to_cstring(name, temp_allocator) or_return return _read_link_cstr(name_cstr, allocator) } _chdir :: proc(name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + name_cstr := clone_to_cstring(name, temp_allocator) or_return return _get_platform_error(linux.chdir(name_cstr)) } @@ -369,8 +370,8 @@ _fchdir :: proc(f: ^File) -> Error { } _chmod :: proc(name: string, mode: int) -> Error { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + name_cstr := clone_to_cstring(name, temp_allocator) or_return return _get_platform_error(linux.chmod(name_cstr, transmute(linux.Mode)(u32(mode)))) } @@ -381,15 +382,15 @@ _fchmod :: proc(f: ^File, mode: int) -> Error { // NOTE: will throw error without super user priviledges _chown :: proc(name: string, uid, gid: int) -> Error { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + name_cstr := clone_to_cstring(name, temp_allocator) or_return return _get_platform_error(linux.chown(name_cstr, linux.Uid(uid), linux.Gid(gid))) } // NOTE: will throw error without super user priviledges _lchown :: proc(name: string, uid, gid: int) -> Error { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + name_cstr := clone_to_cstring(name, temp_allocator) or_return return _get_platform_error(linux.lchown(name_cstr, linux.Uid(uid), linux.Gid(gid))) } @@ -400,8 +401,8 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error { } _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + name_cstr := clone_to_cstring(name, temp_allocator) or_return times := [2]linux.Time_Spec { { uint(atime._nsec) / uint(time.Second), @@ -431,8 +432,8 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error { } _exists :: proc(name: string) -> bool { - TEMP_ALLOCATOR_GUARD() - name_cstr, _ := temp_cstring(name) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + name_cstr, _ := clone_to_cstring(name, temp_allocator) return linux.access(name_cstr, linux.F_OK) == .NONE } @@ -440,8 +441,8 @@ _exists :: proc(name: string) -> bool { _read_entire_pseudo_file :: proc { _read_entire_pseudo_file_string, _read_entire_pseudo_file_cstring } _read_entire_pseudo_file_string :: proc(name: string, allocator: runtime.Allocator) -> (b: []u8, e: Error) { - TEMP_ALLOCATOR_GUARD() - name_cstr := clone_to_cstring(name, temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + name_cstr := clone_to_cstring(name, temp_allocator) or_return return _read_entire_pseudo_file_cstring(name_cstr, allocator) } diff --git a/core/os/os2/file_posix.odin b/core/os/os2/file_posix.odin index 43d5866b1..fed8d766c 100644 --- a/core/os/os2/file_posix.odin +++ b/core/os/os2/file_posix.odin @@ -25,8 +25,8 @@ File_Impl :: struct { } @(init) -init_std_files :: proc() { - new_std :: proc(impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File { +init_std_files :: proc "contextless" () { + new_std :: proc "contextless" (impl: ^File_Impl, fd: posix.FD, name: cstring) -> ^File { impl.file.impl = impl impl.fd = fd impl.allocator = runtime.nil_allocator() @@ -69,8 +69,8 @@ _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Err if .Trunc in flags { sys_flags += {.TRUNC} } if .Inheritable in flags { sys_flags -= {.CLOEXEC} } - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cname := clone_to_cstring(name, temp_allocator) or_return fd := posix.open(cname, sys_flags, transmute(posix.mode_t)posix._mode_t(perm)) if fd < 0 { @@ -183,39 +183,39 @@ _truncate :: proc(f: ^File, size: i64) -> Error { return nil } -_remove :: proc(name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) +_remove :: proc(name: string) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cname := clone_to_cstring(name, temp_allocator) or_return if posix.remove(cname) != 0 { return _get_platform_error() } return nil } -_rename :: proc(old_path, new_path: string) -> Error { - TEMP_ALLOCATOR_GUARD() - cold := temp_cstring(old_path) - cnew := temp_cstring(new_path) +_rename :: proc(old_path, new_path: string) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cold := clone_to_cstring(old_path, temp_allocator) or_return + cnew := clone_to_cstring(new_path, temp_allocator) or_return if posix.rename(cold, cnew) != 0 { return _get_platform_error() } return nil } -_link :: proc(old_name, new_name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - cold := temp_cstring(old_name) - cnew := temp_cstring(new_name) +_link :: proc(old_name, new_name: string) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cold := clone_to_cstring(old_name, temp_allocator) or_return + cnew := clone_to_cstring(new_name, temp_allocator) or_return if posix.link(cold, cnew) != .OK { return _get_platform_error() } return nil } -_symlink :: proc(old_name, new_name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - cold := temp_cstring(old_name) - cnew := temp_cstring(new_name) +_symlink :: proc(old_name, new_name: string) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cold := clone_to_cstring(old_name, temp_allocator) or_return + cnew := clone_to_cstring(new_name, temp_allocator) or_return if posix.symlink(cold, cnew) != .OK { return _get_platform_error() } @@ -223,8 +223,8 @@ _symlink :: proc(old_name, new_name: string) -> Error { } _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, err: Error) { - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + cname := clone_to_cstring(name, temp_allocator) or_return buf: [dynamic]byte buf.allocator = allocator @@ -268,9 +268,9 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er } } -_chdir :: proc(name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) +_chdir :: proc(name: string) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cname := clone_to_cstring(name, temp_allocator) or_return if posix.chdir(cname) != .OK { return _get_platform_error() } @@ -291,9 +291,9 @@ _fchmod :: proc(f: ^File, mode: int) -> Error { return nil } -_chmod :: proc(name: string, mode: int) -> Error { - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) +_chmod :: proc(name: string, mode: int) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cname := clone_to_cstring(name, temp_allocator) or_return if posix.chmod(cname, transmute(posix.mode_t)posix._mode_t(mode)) != .OK { return _get_platform_error() } @@ -307,9 +307,9 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error { return nil } -_chown :: proc(name: string, uid, gid: int) -> Error { - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) +_chown :: proc(name: string, uid, gid: int) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cname := clone_to_cstring(name, temp_allocator) or_return if posix.chown(cname, posix.uid_t(uid), posix.gid_t(gid)) != .OK { return _get_platform_error() } @@ -317,15 +317,15 @@ _chown :: proc(name: string, uid, gid: int) -> Error { } _lchown :: proc(name: string, uid, gid: int) -> Error { - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cname := clone_to_cstring(name, temp_allocator) or_return if posix.lchown(cname, posix.uid_t(uid), posix.gid_t(gid)) != .OK { return _get_platform_error() } return nil } -_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { +_chtimes :: proc(name: string, atime, mtime: time.Time) -> (err: Error) { times := [2]posix.timeval{ { tv_sec = posix.time_t(atime._nsec/1e9), /* seconds */ @@ -337,8 +337,8 @@ _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { }, } - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cname := clone_to_cstring(name, temp_allocator) or_return if posix.utimes(cname, ×) != .OK { return _get_platform_error() @@ -365,8 +365,9 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error { } _exists :: proc(path: string) -> bool { - TEMP_ALLOCATOR_GUARD() - cpath := temp_cstring(path) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cpath, err := clone_to_cstring(path, temp_allocator) + if err != nil { return false } return posix.access(cpath) == .OK } diff --git a/core/os/os2/file_posix_darwin.odin b/core/os/os2/file_posix_darwin.odin index 920a63a71..aed3e56f5 100644 --- a/core/os/os2/file_posix_darwin.odin +++ b/core/os/os2/file_posix_darwin.odin @@ -3,6 +3,7 @@ package os2 import "base:runtime" +import "core:sys/darwin" import "core:sys/posix" _posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) { @@ -16,3 +17,30 @@ _posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allo return clone_to_cstring(string(cstring(&buf[0])), allocator) } + +_copy_file_native :: proc(dst_path, src_path: string) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + + csrc := clone_to_cstring(src_path, temp_allocator) or_return + cdst := clone_to_cstring(dst_path, temp_allocator) or_return + + // Disallow directories, as specified by the generic implementation. + + stat: posix.stat_t + if posix.stat(csrc, &stat) != .OK { + err = _get_platform_error() + return + } + + if posix.S_ISDIR(stat.st_mode) { + err = .Invalid_File + return + } + + ret := darwin.copyfile(csrc, cdst, nil, darwin.COPYFILE_ALL) + if ret < 0 { + err = _get_platform_error() + } + + return +} diff --git a/core/os/os2/file_posix_other.odin b/core/os/os2/file_posix_other.odin index 74b6374ec..d2946098b 100644 --- a/core/os/os2/file_posix_other.odin +++ b/core/os/os2/file_posix_other.odin @@ -7,8 +7,8 @@ import "base:runtime" import "core:sys/posix" _posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) { - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + cname := clone_to_cstring(name, temp_allocator) buf: [posix.PATH_MAX]byte path = posix.realpath(cname, raw_data(buf[:])) diff --git a/core/os/os2/file_util.odin b/core/os/os2/file_util.odin index 8af46fab3..13d6db661 100644 --- a/core/os/os2/file_util.odin +++ b/core/os/os2/file_util.odin @@ -59,7 +59,7 @@ write_encoded_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) { if r < 32 { if wrap(write_string(f, "\\x"), &n, &err) { return } b: [2]byte - s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) + s := strconv.write_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil) switch len(s) { case 0: if wrap(write_string(f, "00"), &n, &err) { return } case 1: if wrap(write_rune(f, '0'), &n, &err) { return } @@ -151,7 +151,7 @@ read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (d n: int n, err = read(f, buffer[:]) total += n - append_elems(&out_buffer, ..buffer[:n]) + append_elems(&out_buffer, ..buffer[:n]) or_return if err != nil { if err == .EOF || err == .Broken_Pipe { err = nil diff --git a/core/os/os2/file_wasi.odin b/core/os/os2/file_wasi.odin index 0245841e3..1d417ffb1 100644 --- a/core/os/os2/file_wasi.odin +++ b/core/os/os2/file_wasi.odin @@ -30,8 +30,8 @@ Preopen :: struct { preopens: []Preopen @(init) -init_std_files :: proc() { - new_std :: proc(impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File { +init_std_files :: proc "contextless" () { + new_std :: proc "contextless" (impl: ^File_Impl, fd: wasi.fd_t, name: string) -> ^File { impl.file.impl = impl impl.allocator = runtime.nil_allocator() impl.fd = fd diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index b123330e0..b39e65fe2 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -43,8 +43,8 @@ File_Impl :: struct { } @(init) -init_std_files :: proc() { - new_std :: proc(impl: ^File_Impl, code: u32, name: string) -> ^File { +init_std_files :: proc "contextless" () { + new_std :: proc "contextless" (impl: ^File_Impl, code: u32, name: string) -> ^File { impl.file.impl = impl impl.allocator = runtime.nil_allocator() @@ -77,7 +77,7 @@ init_std_files :: proc() { stderr = new_std(&files[2], win32.STD_ERROR_HANDLE, "") } -_handle :: proc(f: ^File) -> win32.HANDLE { +_handle :: proc "contextless" (f: ^File) -> win32.HANDLE { return win32.HANDLE(_fd(f)) } @@ -86,9 +86,9 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: int) -> (handle: u err = .Not_Exist return } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) - path := _fix_long_path(name, temp_allocator()) or_return + path := _fix_long_path(name, temp_allocator) or_return access: u32 switch flags & {.Read, .Write} { case {.Read}: access = win32.FILE_GENERIC_READ @@ -234,7 +234,7 @@ _clone :: proc(f: ^File) -> (clone: ^File, err: Error) { return _new_file(uintptr(clonefd), name(f), file_allocator()) } -_fd :: proc(f: ^File) -> uintptr { +_fd :: proc "contextless" (f: ^File) -> uintptr { if f == nil || f.impl == nil { return INVALID_HANDLE } @@ -247,11 +247,11 @@ _destroy :: proc(f: ^File_Impl) -> Error { } a := f.allocator - err0 := free(f.wname, a) + err0 := free(rawptr(f.wname), a) err1 := delete(f.name, a) - err2 := free(f, a) - err3 := delete(f.r_buf, a) - err4 := delete(f.w_buf, a) + err2 := delete(f.r_buf, a) + err3 := delete(f.w_buf, a) + err4 := free(f, a) err0 or_return err1 or_return err2 or_return @@ -506,10 +506,16 @@ _write_at :: proc(f: ^File_Impl, p: []byte, offset: i64) -> (n: i64, err: Error) _file_size :: proc(f: ^File_Impl) -> (n: i64, err: Error) { length: win32.LARGE_INTEGER - if f.kind == .Pipe { - return 0, .No_Size - } handle := _handle(&f.file) + if f.kind == .Pipe { + bytes_available: u32 + if win32.PeekNamedPipe(handle, nil, 0, nil, &bytes_available, nil) { + return i64(bytes_available), nil + } else { + err = _get_platform_error() + return + } + } if !win32.GetFileSizeEx(handle, &length) { err = _get_platform_error() } @@ -551,8 +557,8 @@ _truncate :: proc(f: ^File, size: i64) -> Error { } _remove :: proc(name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - p := _fix_long_path(name, temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + p := _fix_long_path(name, temp_allocator) or_return err, err1: Error if !win32.DeleteFileW(p) { err = _get_platform_error() @@ -589,9 +595,9 @@ _remove :: proc(name: string) -> Error { } _rename :: proc(old_path, new_path: string) -> Error { - TEMP_ALLOCATOR_GUARD() - from := _fix_long_path(old_path, temp_allocator()) or_return - to := _fix_long_path(new_path, temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + from := _fix_long_path(old_path, temp_allocator) or_return + to := _fix_long_path(new_path, temp_allocator) or_return if win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) { return nil } @@ -600,9 +606,9 @@ _rename :: proc(old_path, new_path: string) -> Error { } _link :: proc(old_name, new_name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - o := _fix_long_path(old_name, temp_allocator()) or_return - n := _fix_long_path(new_name, temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + o := _fix_long_path(old_name, temp_allocator) or_return + n := _fix_long_path(new_name, temp_allocator) or_return if win32.CreateHardLinkW(n, o, nil) { return nil } @@ -613,7 +619,7 @@ _symlink :: proc(old_name, new_name: string) -> Error { return .Unsupported } -_open_sym_link :: proc(p: [^]u16) -> (handle: win32.HANDLE, err: Error) { +_open_sym_link :: proc(p: cstring16) -> (handle: win32.HANDLE, err: Error) { attrs := u32(win32.FILE_FLAG_BACKUP_SEMANTICS) attrs |= win32.FILE_FLAG_OPEN_REPARSE_POINT handle = win32.CreateFileW(p, 0, 0, nil, win32.OPEN_EXISTING, attrs, nil) @@ -655,7 +661,7 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st } - handle := _open_sym_link(raw_data(p)) or_return + handle := _open_sym_link(cstring16(raw_data(p))) or_return defer win32.CloseHandle(handle) n := win32.GetFinalPathNameByHandleW(handle, nil, 0, win32.VOLUME_NAME_DOS) @@ -663,10 +669,10 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st return "", _get_platform_error() } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - buf := make([]u16, n+1, temp_allocator()) - n = win32.GetFinalPathNameByHandleW(handle, raw_data(buf), u32(len(buf)), win32.VOLUME_NAME_DOS) + buf := make([]u16, n+1, temp_allocator) + n = win32.GetFinalPathNameByHandleW(handle, cstring16(raw_data(buf)), u32(len(buf)), win32.VOLUME_NAME_DOS) if n == 0 { return "", _get_platform_error() } @@ -689,9 +695,9 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er @thread_local rdb_buf: [MAXIMUM_REPARSE_DATA_BUFFER_SIZE]byte - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - p := _fix_long_path(name, temp_allocator()) or_return + p := _fix_long_path(name, temp_allocator) or_return handle := _open_sym_link(p) or_return defer win32.CloseHandle(handle) @@ -707,7 +713,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er switch rdb.ReparseTag { case win32.IO_REPARSE_TAG_SYMLINK: rb := (^win32.SYMBOLIC_LINK_REPARSE_BUFFER)(&rdb.rest) - pb := win32.wstring(&rb.PathBuffer) + pb := ([^]u16)(&rb.PathBuffer) pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0 p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength] if rb.Flags & win32.SYMLINK_FLAG_RELATIVE != 0 { @@ -717,7 +723,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er case win32.IO_REPARSE_TAG_MOUNT_POINT: rb := (^win32.MOUNT_POINT_REPARSE_BUFFER)(&rdb.rest) - pb := win32.wstring(&rb.PathBuffer) + pb := ([^]u16)(&rb.PathBuffer) pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0 p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength] return _normalize_link_path(p, allocator) @@ -766,8 +772,8 @@ _fchown :: proc(f: ^File, uid, gid: int) -> Error { } _chdir :: proc(name: string) -> Error { - TEMP_ALLOCATOR_GUARD() - p := _fix_long_path(name, temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + p := _fix_long_path(name, temp_allocator) or_return if !win32.SetCurrentDirectoryW(p) { return _get_platform_error() } @@ -794,19 +800,11 @@ _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { defer close(f) return _fchtimes(f, atime, mtime) } + _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error { if f == nil || f.impl == nil { return nil } - d: win32.BY_HANDLE_FILE_INFORMATION - if !win32.GetFileInformationByHandle(_handle(f), &d) { - return _get_platform_error() - } - - to_windows_time :: #force_inline proc(t: time.Time) -> win32.LARGE_INTEGER { - // a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC) - return win32.LARGE_INTEGER(time.time_to_unix_nano(t) * 100 + 116444736000000000) - } atime, mtime := atime, mtime if time.time_to_unix_nano(atime) < time.time_to_unix_nano(mtime) { @@ -814,17 +812,17 @@ _fchtimes :: proc(f: ^File, atime, mtime: time.Time) -> Error { } info: win32.FILE_BASIC_INFO - info.LastAccessTime = to_windows_time(atime) - info.LastWriteTime = to_windows_time(mtime) - if !win32.SetFileInformationByHandle(_handle(f), .FileBasicInfo, &info, size_of(d)) { + info.LastAccessTime = time_as_filetime(atime) + info.LastWriteTime = time_as_filetime(mtime) + if !win32.SetFileInformationByHandle(_handle(f), .FileBasicInfo, &info, size_of(info)) { return _get_platform_error() } return nil } _exists :: proc(path: string) -> bool { - TEMP_ALLOCATOR_GUARD() - wpath, _ := _fix_long_path(path, temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + wpath, _ := _fix_long_path(path, temp_allocator) attribs := win32.GetFileAttributesW(wpath) return attribs != win32.INVALID_FILE_ATTRIBUTES } @@ -876,8 +874,8 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, @(private="package", require_results) -win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: [^]u16, err: runtime.Allocator_Error) { - ws = raw_data(win32_utf8_to_utf16(s, allocator) or_return) +win32_utf8_to_wstring :: proc(s: string, allocator: runtime.Allocator) -> (ws: cstring16, err: runtime.Allocator_Error) { + ws = cstring16(raw_data(win32_utf8_to_utf16(s, allocator) or_return)) return } @@ -911,24 +909,26 @@ win32_utf8_to_utf16 :: proc(s: string, allocator: runtime.Allocator) -> (ws: []u } @(private="package", require_results) -win32_wstring_to_utf8 :: proc(s: [^]u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) { - if s == nil || s[0] == 0 { +win32_wstring_to_utf8 :: proc(s: cstring16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) { + if s == nil || s == "" { return "", nil } - n := 0 - for s[n] != 0 { - n += 1 - } - return win32_utf16_to_utf8(s[:n], allocator) + return win32_utf16_to_utf8(string16(s), allocator) +} + +@(private="package") +win32_utf16_to_utf8 :: proc{ + win32_utf16_string16_to_utf8, + win32_utf16_u16_to_utf8, } @(private="package", require_results) -win32_utf16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) { +win32_utf16_string16_to_utf8 :: proc(s: string16, allocator: runtime.Allocator) -> (res: string, err: runtime.Allocator_Error) { if len(s) == 0 { return } - n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), nil, 0, nil, nil) + n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), nil, 0, nil, nil) if n == 0 { return } @@ -940,7 +940,41 @@ win32_utf16_to_utf8 :: proc(s: []u16, allocator: runtime.Allocator) -> (res: str // will not be null terminated. text := make([]byte, n, allocator) or_return - n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), raw_data(text), n, nil, nil) + n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), raw_data(text), n, nil, nil) + if n1 == 0 { + delete(text, allocator) + return + } + + for i in 0.. (res: string, err: runtime.Allocator_Error) { + if len(s) == 0 { + return + } + + n := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), nil, 0, nil, nil) + if n == 0 { + return + } + + // If N < 0 the call to WideCharToMultiByte assume the wide string is null terminated + // and will scan it to find the first null terminated character. The resulting string will + // also be null terminated. + // If N > 0 it assumes the wide string is not null terminated and the resulting string + // will not be null terminated. + text := make([]byte, n, allocator) or_return + + n1 := win32.WideCharToMultiByte(win32.CP_UTF8, win32.WC_ERR_INVALID_CHARS, cstring16(raw_data(s)), i32(len(s)), raw_data(text), n, nil, nil) if n1 == 0 { delete(text, allocator) return diff --git a/core/os/os2/internal_util.odin b/core/os/os2/internal_util.odin index 164e1e1be..9616af8b0 100644 --- a/core/os/os2/internal_util.odin +++ b/core/os/os2/internal_util.odin @@ -3,6 +3,7 @@ package os2 import "base:intrinsics" import "base:runtime" +import "core:math/rand" // Splits pattern by the last wildcard "*", if it exists, and returns the prefix and suffix @@ -42,11 +43,6 @@ clone_to_cstring :: proc(s: string, allocator: runtime.Allocator) -> (res: cstri return cstring(&buf[0]), nil } -@(require_results) -temp_cstring :: proc(s: string) -> (cstring, runtime.Allocator_Error) #optional_allocator_error { - return clone_to_cstring(s, temp_allocator()) -} - @(require_results) string_from_null_terminated_bytes :: proc(b: []byte) -> (res: string) { s := string(b) @@ -84,45 +80,15 @@ concatenate :: proc(strings: []string, allocator: runtime.Allocator) -> (res: st return string(buf), nil } - - -@(private="file") -random_string_seed: [2]u64 - -@(init, private="file") -init_random_string_seed :: proc() { - seed := u64(intrinsics.read_cycle_counter()) - s := &random_string_seed - s[0] = 0 - s[1] = (seed << 1) | 1 - _ = next_random(s) - s[1] += seed - _ = next_random(s) -} - -@(require_results) -next_random :: proc(r: ^[2]u64) -> u64 { - old_state := r[0] - r[0] = old_state * 6364136223846793005 + (r[1]|1) - xor_shifted := (((old_state >> 59) + 5) ~ old_state) * 12605985483714917081 - rot := (old_state >> 59) - return (xor_shifted >> rot) | (xor_shifted << ((-rot) & 63)) -} - @(require_results) random_string :: proc(buf: []byte) -> string { - @(static, rodata) digits := "0123456789" - - u := next_random(&random_string_seed) - - b :: 10 - i := len(buf) - for u >= b { - i -= 1 - buf[i] = digits[u % b] - u /= b + for i := 0; i < len(buf); i += 16 { + n := rand.uint64() + end := min(i + 16, len(buf)) + for j := i; j < end; j += 1 { + buf[j] = '0' + u8(n) % 10 + n >>= 4 + } } - i -= 1 - buf[i] = digits[u % b] - return string(buf[i:]) + return string(buf) } diff --git a/core/os/os2/path.odin b/core/os/os2/path.odin index 9231307f5..e12aa3c9c 100644 --- a/core/os/os2/path.odin +++ b/core/os/os2/path.odin @@ -2,12 +2,18 @@ package os2 import "base:runtime" -import "core:path/filepath" +import "core:strings" Path_Separator :: _Path_Separator // OS-Specific Path_Separator_String :: _Path_Separator_String // OS-Specific Path_List_Separator :: _Path_List_Separator // OS-Specific +#assert(_Path_Separator <= rune(0x7F), "The system-specific path separator rune is expected to be within the 7-bit ASCII character set.") + +/* +Return true if `c` is a character used to separate paths into directory and +file hierarchies on the current system. +*/ @(require_results) is_path_separator :: proc(c: byte) -> bool { return _is_path_separator(c) @@ -15,22 +21,42 @@ is_path_separator :: proc(c: byte) -> bool { mkdir :: make_directory +/* +Make a new directory. + +If `path` is relative, it will be relative to the process's current working directory. +*/ make_directory :: proc(name: string, perm: int = 0o755) -> Error { return _mkdir(name, perm) } mkdir_all :: make_directory_all +/* +Make a new directory, creating new intervening directories when needed. + +If `path` is relative, it will be relative to the process's current working directory. +*/ make_directory_all :: proc(path: string, perm: int = 0o755) -> Error { return _mkdir_all(path, perm) } +/* +Delete `path` and all files and directories inside of `path` if it is a directory. + +If `path` is relative, it will be relative to the process's current working directory. +*/ remove_all :: proc(path: string) -> Error { return _remove_all(path) } getwd :: get_working_directory +/* +Get the working directory of the current process. + +*Allocates Using Provided Allocator* +*/ @(require_results) get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { return _get_working_directory(allocator) @@ -38,16 +64,399 @@ get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err setwd :: set_working_directory +/* +Change the working directory of the current process. + +*Allocates Using Provided Allocator* +*/ set_working_directory :: proc(dir: string) -> (err: Error) { return _set_working_directory(dir) } +/* +Get the path for the currently running executable. + +*Allocates Using Provided Allocator* +*/ +@(require_results) get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) { return _get_executable_path(allocator) } +/* +Get the directory for the currently running executable. + +*Allocates Using Provided Allocator* +*/ +@(require_results) get_executable_directory :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) { path = _get_executable_path(allocator) or_return - path, _ = filepath.split(path) + path, _ = split_path(path) return } + +/* +Compare two paths for exactness without normalization. + +This procedure takes into account case-sensitivity on differing systems. +*/ +@(require_results) +are_paths_identical :: proc(a, b: string) -> (identical: bool) { + return _are_paths_identical(a, b) +} + +/* +Normalize a path. + +*Allocates Using Provided Allocator* + +This will remove duplicate separators and unneeded references to the current or +parent directory. +*/ +@(require_results) +clean_path :: proc(path: string, allocator: runtime.Allocator) -> (cleaned: string, err: Error) { + if path == "" || path == "." { + return strings.clone(".", allocator) + } + + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + + // The extra byte is to simplify appending path elements by letting the + // loop to end each with a separator. We'll trim the last one when we're done. + buffer := make([]u8, len(path) + 1, temp_allocator) or_return + + // This is the only point where Windows and POSIX differ, as Windows has + // alphabet-based volumes for root paths. + rooted, start := _clean_path_handle_start(path, buffer) + + head, buffer_i := start, start + for i, j := start, start; i <= len(path); i += 1 { + if i == len(path) || _is_path_separator(path[i]) { + elem := path[j:i] + j = i + 1 + + switch elem { + case "", ".": + // Skip duplicate path separators and current directory references. + case "..": + if !rooted && buffer_i == head { + // Only allow accessing further parent directories when the path is relative. + buffer[buffer_i] = '.' + buffer[buffer_i+1] = '.' + buffer[buffer_i+2] = _Path_Separator + buffer_i += 3 + head = buffer_i + } else { + // Roll back to the last separator or the head of the buffer. + back_to := head + // `buffer_i` will be equal to 1 + the last set byte, so + // skipping two bytes avoids the final separator we just + // added. + for k := buffer_i-2; k >= head; k -= 1 { + if _is_path_separator(buffer[k]) { + back_to = k + 1 + break + } + } + buffer_i = back_to + } + case: + // Copy the path element verbatim and add a separator. + copy(buffer[buffer_i:], elem) + buffer_i += len(elem) + buffer[buffer_i] = _Path_Separator + buffer_i += 1 + } + } + } + + // Trim the final separator. + // NOTE: No need to check if the last byte is a separator, as we always add it. + if buffer_i > start { + buffer_i -= 1 + } + + if buffer_i == 0 { + return strings.clone(".", allocator) + } + + compact := make([]u8, buffer_i, allocator) or_return + copy(compact, buffer) // NOTE(bill): buffer[:buffer_i] is redundant here + return string(compact), nil +} + +/* +Return true if `path` is an absolute path as opposed to a relative one. +*/ +@(require_results) +is_absolute_path :: proc(path: string) -> bool { + return _is_absolute_path(path) +} + +/* +Get the absolute path to `path` with respect to the process's current directory. + +*Allocates Using Provided Allocator* +*/ +@(require_results) +get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) { + return _get_absolute_path(path, allocator) +} + +/* +Get the relative path needed to change directories from `base` to `target`. + +*Allocates Using Provided Allocator* + +The result is such that `join_path(base, get_relative_path(base, target))` is equivalent to `target`. + +NOTE: This procedure expects both `base` and `target` to be normalized first, +which can be done by calling `clean_path` on them if needed. + +This procedure will return an `Invalid_Path` error if `base` begins with a +reference to the parent directory (`".."`). Use `get_working_directory` with +`join_path` to construct absolute paths for both arguments instead. +*/ +@(require_results) +get_relative_path :: proc(base, target: string, allocator: runtime.Allocator) -> (path: string, err: Error) { + if _are_paths_identical(base, target) { + return strings.clone(".", allocator) + } + if base == "." { + return strings.clone(target, allocator) + } + + // This is the first point where Windows and POSIX differ, as Windows has + // alphabet-based volumes for root paths. + if !_get_relative_path_handle_start(base, target) { + return "", .Invalid_Path + } + if strings.has_prefix(base, "..") && (len(base) == 2 || _is_path_separator(base[2])) { + // We could do the work for the user of getting absolute paths for both + // arguments, but that could make something costly (repeatedly + // normalizing paths) convenient, when it would be better for the user + // to store already-finalized paths and operate on those instead. + return "", .Invalid_Path + } + + // This is the other point where Windows and POSIX differ, as Windows is + // case-insensitive. + common := _get_common_path_len(base, target) + + // Get the result of splitting `base` and `target` on _Path_Separator, + // comparing them up to their most common elements, then count how many + // unshared parts are in the split `base`. + seps := 0 + size := 0 + if len(base)-common > 0 { + seps = 1 + size = 2 + } + // This range skips separators on the ends of the string. + for i in common+1.. 0 { + // Account for leading separators on the target after cutting the common part. + // (i.e. base == `/home`, target == `/home/a`) + if _is_path_separator(trailing[0]) { + trailing = trailing[1:] + } + size += len(trailing) + if seps > 0 { + size += 1 + } + } + if trailing == "." { + trailing = "" + size -= 2 + } + + // Build the string. + buf := make([]u8, size, allocator) or_return + n := 0 + if seps > 0 { + buf[0] = '.' + buf[1] = '.' + n = 2 + } + for _ in 1.. 0 { + if seps > 0 { + buf[n] = _Path_Separator + n += 1 + } + copy(buf[n:], trailing) + } + + path = string(buf) + + return +} + +/* +Split a path into a directory hierarchy and a filename. + +For example, `split_path("/home/foo/bar.tar.gz")` will return `"/home/foo"` and `"bar.tar.gz"`. +*/ +@(require_results) +split_path :: proc(path: string) -> (dir, filename: string) { + return _split_path(path) +} + +/* +Join all `elems` with the system's path separator and normalize the result. + +*Allocates Using Provided Allocator* + +For example, `join_path({"/home", "foo", "bar.txt"})` will result in `"/home/foo/bar.txt"`. +*/ +@(require_results) +join_path :: proc(elems: []string, allocator: runtime.Allocator) -> (joined: string, err: Error) { + for e, i in elems { + if e != "" { + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + p := strings.join(elems[i:], Path_Separator_String, temp_allocator) or_return + return clean_path(p, allocator) + } + } + return "", nil +} + +/* +Split a filename from its extension. + +This procedure splits on the last separator. + +If the filename begins with a separator, such as `".readme.txt"`, the separator +will be included in the filename, resulting in `".readme"` and `"txt"`. + +For example, `split_filename("foo.tar.gz")` will return `"foo.tar"` and `"gz"`. +*/ +@(require_results) +split_filename :: proc(filename: string) -> (base, ext: string) { + i := strings.last_index_byte(filename, '.') + if i <= 0 { + return filename, "" + } + return filename[:i], filename[i+1:] +} + +/* +Split a filename from its extension. + +This procedure splits on the first separator. + +If the filename begins with a separator, such as `".readme.txt.gz"`, the separator +will be included in the filename, resulting in `".readme"` and `"txt.gz"`. + +For example, `split_filename_all("foo.tar.gz")` will return `"foo"` and `"tar.gz"`. +*/ +@(require_results) +split_filename_all :: proc(filename: string) -> (base, ext: string) { + i := strings.index_byte(filename, '.') + if i == 0 { + j := strings.index_byte(filename[1:], '.') + if j != -1 { + j += 1 + } + i = j + } + if i == -1 { + return filename, "" + } + return filename[:i], filename[i+1:] +} + +/* +Join `base` and `ext` with the system's filename extension separator. + +*Allocates Using Provided Allocator* + +For example, `join_filename("foo", "tar.gz")` will result in `"foo.tar.gz"`. +*/ +@(require_results) +join_filename :: proc(base: string, ext: string, allocator: runtime.Allocator) -> (joined: string, err: Error) { + if len(base) == 0 { + return strings.clone(ext, allocator) + } else if len(ext) == 0 { + return strings.clone(base, allocator) + } + + buf := make([]u8, len(base) + 1 + len(ext), allocator) or_return + copy(buf, base) + buf[len(base)] = '.' + copy(buf[1+len(base):], ext) + + return string(buf), nil +} + +/* +Split a string that is separated by a system-specific separator, typically used +for environment variables specifying multiple directories. + +*Allocates Using Provided Allocator* + +For example, there is the "PATH" environment variable on POSIX systems which +this procedure can split into separate entries. +*/ +@(require_results) +split_path_list :: proc(path: string, allocator: runtime.Allocator) -> (list: []string, err: Error) { + if path == "" { + return nil, nil + } + + start: int + quote: bool + + start, quote = 0, false + count := 0 + + for i := 0; i < len(path); i += 1 { + c := path[i] + switch { + case c == '"': + quote = !quote + case c == Path_List_Separator && !quote: + count += 1 + } + } + + start, quote = 0, false + list = make([]string, count + 1, allocator) or_return + index := 0 + for i := 0; i < len(path); i += 1 { + c := path[i] + switch { + case c == '"': + quote = !quote + case c == Path_List_Separator && !quote: + list[index] = path[start:i] + index += 1 + start = i + 1 + } + } + assert(index == count) + list[index] = path[start:] + + for s0, i in list { + s, new := strings.replace_all(s0, `"`, ``, allocator) + if !new { + s = strings.clone(s, allocator) or_return + } + list[i] = s + } + + return list, nil +} diff --git a/core/os/os2/path_freebsd.odin b/core/os/os2/path_freebsd.odin index 577108eca..e7e4f63c9 100644 --- a/core/os/os2/path_freebsd.odin +++ b/core/os/os2/path_freebsd.odin @@ -25,5 +25,5 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err return } - return string(buf[:size]), nil + return string(buf[:size-1]), nil } diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index e3e7f8a7c..1c9927843 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -14,12 +14,12 @@ _Path_List_Separator :: ':' _OPENDIR_FLAGS : linux.Open_Flags : {.NONBLOCK, .DIRECTORY, .LARGEFILE, .CLOEXEC} _is_path_separator :: proc(c: byte) -> bool { - return c == '/' + return c == _Path_Separator } _mkdir :: proc(path: string, perm: int) -> Error { - TEMP_ALLOCATOR_GUARD() - path_cstr := temp_cstring(path) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + path_cstr := clone_to_cstring(path, temp_allocator) or_return return _get_platform_error(linux.mkdir(path_cstr, transmute(linux.Mode)u32(perm))) } @@ -52,9 +52,9 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { } return _get_platform_error(errno) } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) // need something we can edit, and use to generate cstrings - path_bytes := make([]u8, len(path) + 1, temp_allocator()) + path_bytes := make([]u8, len(path) + 1, temp_allocator) // zero terminate the byte slice to make it a valid cstring copy(path_bytes, path) @@ -129,8 +129,8 @@ _remove_all :: proc(path: string) -> Error { return nil } - TEMP_ALLOCATOR_GUARD() - path_cstr := temp_cstring(path) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + path_cstr := clone_to_cstring(path, temp_allocator) or_return fd, errno := linux.open(path_cstr, _OPENDIR_FLAGS) #partial switch errno { @@ -168,14 +168,16 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (string, Error) } _set_working_directory :: proc(dir: string) -> Error { - dir_cstr := temp_cstring(dir) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + + dir_cstr := clone_to_cstring(dir, temp_allocator) or_return return _get_platform_error(linux.chdir(dir_cstr)) } _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - buf := make([dynamic]byte, 1024, temp_allocator()) or_return + buf := make([dynamic]byte, 1024, temp_allocator) or_return for { n, errno := linux.readlink("/proc/self/exe", buf[:]) if errno != .NONE { @@ -197,7 +199,7 @@ _get_full_path :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (fullpath: buf: [32]u8 copy(buf[:], PROC_FD_PATH) - strconv.itoa(buf[len(PROC_FD_PATH):], int(fd)) + strconv.write_int(buf[len(PROC_FD_PATH):], i64(fd), 10) if fullpath, err = _read_link_cstr(cstring(&buf[0]), allocator); err != nil || fullpath[0] != '/' { delete(fullpath, allocator) @@ -205,3 +207,21 @@ _get_full_path :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (fullpath: } return } + +_get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) { + rel := path + if rel == "" { + rel = "." + } + + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + + fd, errno := linux.open(clone_to_cstring(path, temp_allocator) or_return, {}) + if errno != nil { + err = _get_platform_error(errno) + return + } + defer linux.close(fd) + + return _get_full_path(fd, allocator) +} diff --git a/core/os/os2/path_netbsd.odin b/core/os/os2/path_netbsd.odin index f56a91fd6..815102dea 100644 --- a/core/os/os2/path_netbsd.odin +++ b/core/os/os2/path_netbsd.odin @@ -5,9 +5,9 @@ import "base:runtime" import "core:sys/posix" _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - buf := make([dynamic]byte, 1024, temp_allocator()) or_return + buf := make([dynamic]byte, 1024, temp_allocator) or_return for { n := posix.readlink("/proc/curproc/exe", raw_data(buf), len(buf)) if n < 0 { diff --git a/core/os/os2/path_openbsd.odin b/core/os/os2/path_openbsd.odin index 37b5de927..cbc0346d4 100644 --- a/core/os/os2/path_openbsd.odin +++ b/core/os/os2/path_openbsd.odin @@ -35,11 +35,11 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err return real(arg, allocator) } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - buf := strings.builder_make(temp_allocator()) + buf := strings.builder_make(temp_allocator) - paths := get_env("PATH", temp_allocator()) + paths := get_env("PATH", temp_allocator) for dir in strings.split_iterator(&paths, ":") { strings.builder_reset(&buf) strings.write_string(&buf, dir) diff --git a/core/os/os2/path_posix.odin b/core/os/os2/path_posix.odin index e6b95c0d4..f22cd446b 100644 --- a/core/os/os2/path_posix.odin +++ b/core/os/os2/path_posix.odin @@ -3,7 +3,6 @@ package os2 import "base:runtime" -import "core:path/filepath" import "core:sys/posix" @@ -15,9 +14,9 @@ _is_path_separator :: proc(c: byte) -> bool { return c == _Path_Separator } -_mkdir :: proc(name: string, perm: int) -> Error { - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) +_mkdir :: proc(name: string, perm: int) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cname := clone_to_cstring(name, temp_allocator) or_return if posix.mkdir(cname, transmute(posix.mode_t)posix._mode_t(perm)) != .OK { return _get_platform_error() } @@ -29,17 +28,17 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { return .Invalid_Path } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) if exists(path) { return .Exist } - clean_path := filepath.clean(path, temp_allocator()) + clean_path := clean_path(path, temp_allocator) or_return return internal_mkdir_all(clean_path, perm) internal_mkdir_all :: proc(path: string, perm: int) -> Error { - dir, file := filepath.split(path) + dir, file := split_path(path) if file != path && dir != "/" { if len(dir) > 1 && dir[len(dir) - 1] == '/' { dir = dir[:len(dir) - 1] @@ -53,9 +52,9 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { } } -_remove_all :: proc(path: string) -> Error { - TEMP_ALLOCATOR_GUARD() - cpath := temp_cstring(path) +_remove_all :: proc(path: string) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cpath := clone_to_cstring(path, temp_allocator) or_return dir := posix.opendir(cpath) if dir == nil { @@ -79,7 +78,7 @@ _remove_all :: proc(path: string) -> Error { continue } - fullpath, _ := concatenate({path, "/", string(cname), "\x00"}, temp_allocator()) + fullpath, _ := concatenate({path, "/", string(cname), "\x00"}, temp_allocator) if entry.d_type == .DIR { _remove_all(fullpath[:len(fullpath)-1]) or_return } else { @@ -96,10 +95,10 @@ _remove_all :: proc(path: string) -> Error { } _get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) buf: [dynamic]byte - buf.allocator = temp_allocator() + buf.allocator = temp_allocator size := uint(posix.PATH_MAX) cwd: cstring @@ -117,10 +116,27 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, er } _set_working_directory :: proc(dir: string) -> (err: Error) { - TEMP_ALLOCATOR_GUARD() - cdir := temp_cstring(dir) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + cdir := clone_to_cstring(dir, temp_allocator) or_return if posix.chdir(cdir) != .OK { err = _get_platform_error() } return } + +_get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) { + rel := path + if rel == "" { + rel = "." + } + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + rel_cstr := clone_to_cstring(rel, temp_allocator) or_return + path_ptr := posix.realpath(rel_cstr, nil) + if path_ptr == nil { + return "", Platform_Error(posix.errno()) + } + defer posix.free(path_ptr) + + path_str := clone_string(string(path_ptr), allocator) or_return + return path_str, nil +} diff --git a/core/os/os2/path_posixfs.odin b/core/os/os2/path_posixfs.odin new file mode 100644 index 000000000..0736e73d1 --- /dev/null +++ b/core/os/os2/path_posixfs.odin @@ -0,0 +1,57 @@ +#+private +#+build linux, darwin, netbsd, freebsd, openbsd, wasi +package os2 + +// This implementation is for all systems that have POSIX-compliant filesystem paths. + +_are_paths_identical :: proc(a, b: string) -> (identical: bool) { + return a == b +} + +_clean_path_handle_start :: proc(path: string, buffer: []u8) -> (rooted: bool, start: int) { + // Preserve rooted paths. + if _is_path_separator(path[0]) { + rooted = true + buffer[0] = _Path_Separator + start = 1 + } + return +} + +_is_absolute_path :: proc(path: string) -> bool { + return len(path) > 0 && _is_path_separator(path[0]) +} + +_get_relative_path_handle_start :: proc(base, target: string) -> bool { + base_rooted := len(base) > 0 && _is_path_separator(base[0]) + target_rooted := len(target) > 0 && _is_path_separator(target[0]) + return base_rooted == target_rooted +} + +_get_common_path_len :: proc(base, target: string) -> int { + i := 0 + end := min(len(base), len(target)) + for j in 0..=end { + if j == end || _is_path_separator(base[j]) { + if base[i:j] == target[i:j] { + i = j + } else { + break + } + } + } + return i +} + +_split_path :: proc(path: string) -> (dir, file: string) { + i := len(path) - 1 + for i >= 0 && !_is_path_separator(path[i]) { + i -= 1 + } + if i == 0 { + return path[:i+1], path[i+1:] + } else if i > 0 { + return path[:i], path[i+1:] + } + return "", path +} diff --git a/core/os/os2/path_wasi.odin b/core/os/os2/path_wasi.odin index 1c4fafa17..b8240e188 100644 --- a/core/os/os2/path_wasi.odin +++ b/core/os/os2/path_wasi.odin @@ -3,7 +3,6 @@ package os2 import "base:runtime" -import "core:path/filepath" import "core:sync" import "core:sys/wasm/wasi" @@ -29,17 +28,17 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { return .Invalid_Path } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) if exists(path) { return .Exist } - clean_path := filepath.clean(path, temp_allocator()) + clean_path := clean_path(path, temp_allocator) return internal_mkdir_all(clean_path) internal_mkdir_all :: proc(path: string) -> Error { - dir, file := filepath.split(path) + dir, file := split_path(path) if file != path && dir != "/" { if len(dir) > 1 && dir[len(dir) - 1] == '/' { dir = dir[:len(dir) - 1] diff --git a/core/os/os2/path_windows.odin b/core/os/os2/path_windows.odin index 041a4d1e3..e5a1545ec 100644 --- a/core/os/os2/path_windows.odin +++ b/core/os/os2/path_windows.odin @@ -1,8 +1,9 @@ #+private package os2 -import win32 "core:sys/windows" import "base:runtime" +import "core:strings" +import win32 "core:sys/windows" _Path_Separator :: '\\' _Path_Separator_String :: "\\" @@ -13,8 +14,8 @@ _is_path_separator :: proc(c: byte) -> bool { } _mkdir :: proc(name: string, perm: int) -> Error { - TEMP_ALLOCATOR_GUARD() - if !win32.CreateDirectoryW(_fix_long_path(name, temp_allocator()) or_return, nil) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + if !win32.CreateDirectoryW(_fix_long_path(name, temp_allocator) or_return, nil) { return _get_platform_error() } return nil @@ -32,9 +33,9 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { return p, false, nil } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) - dir_stat, err := stat(path, temp_allocator()) + dir_stat, err := stat(path, temp_allocator) if err == nil { if dir_stat.type == .Directory { return nil @@ -62,7 +63,7 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { err = mkdir(path, perm) if err != nil { - new_dir_stat, err1 := lstat(path, temp_allocator()) + new_dir_stat, err1 := lstat(path, temp_allocator) if err1 == nil && new_dir_stat.type == .Directory { return nil } @@ -81,8 +82,8 @@ _remove_all :: proc(path: string) -> Error { return nil } - TEMP_ALLOCATOR_GUARD() - dir := win32_utf8_to_wstring(path, temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + dir := win32_utf8_to_wstring(path, temp_allocator) or_return empty: [1]u16 @@ -90,11 +91,11 @@ _remove_all :: proc(path: string) -> Error { nil, win32.FO_DELETE, dir, - &empty[0], + cstring16(&empty[0]), win32.FOF_NOCONFIRMATION | win32.FOF_NOERRORUI | win32.FOF_SILENT, false, nil, - &empty[0], + cstring16(&empty[0]), } res := win32.SHFileOperationW(&file_op) if res != 0 { @@ -108,10 +109,10 @@ _remove_all :: proc(path: string) -> Error { _get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { win32.AcquireSRWLockExclusive(&cwd_lock) - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) sz_utf16 := win32.GetCurrentDirectoryW(0, nil) - dir_buf_wstr := make([]u16, sz_utf16, temp_allocator()) or_return + dir_buf_wstr := make([]u16, sz_utf16, temp_allocator) or_return sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), raw_data(dir_buf_wstr)) assert(int(sz_utf16)+1 == len(dir_buf_wstr)) // the second time, it _excludes_ the NUL. @@ -122,8 +123,8 @@ _get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, er } _set_working_directory :: proc(dir: string) -> (err: Error) { - TEMP_ALLOCATOR_GUARD() - wstr := win32_utf8_to_wstring(dir, temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + wstr := win32_utf8_to_wstring(dir, temp_allocator) or_return win32.AcquireSRWLockExclusive(&cwd_lock) @@ -137,9 +138,9 @@ _set_working_directory :: proc(dir: string) -> (err: Error) { } _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err: Error) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - buf := make([dynamic]u16, 512, temp_allocator()) or_return + buf := make([dynamic]u16, 512, temp_allocator) or_return for { ret := win32.GetModuleFileNameW(nil, raw_data(buf), win32.DWORD(len(buf))) if ret == 0 { @@ -159,7 +160,7 @@ _get_executable_path :: proc(allocator: runtime.Allocator) -> (path: string, err can_use_long_paths: bool @(init) -init_long_path_support :: proc() { +init_long_path_support :: proc "contextless" () { can_use_long_paths = false key: win32.HKEY @@ -186,7 +187,6 @@ init_long_path_support :: proc() { if value == 1 { can_use_long_paths = true } - } @(require_results) @@ -217,14 +217,14 @@ _fix_long_path_internal :: proc(path: string) -> string { return path } - if !_is_abs(path) { // relative path + if !_is_absolute_path(path) { // relative path return path } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) PREFIX :: `\\?` - path_buf := make([]byte, len(PREFIX)+len(path)+1, temp_allocator()) + path_buf := make([]byte, len(PREFIX)+len(path)+1, temp_allocator) copy(path_buf, PREFIX) n := len(path) r, w := 0, len(PREFIX) @@ -257,3 +257,98 @@ _fix_long_path_internal :: proc(path: string) -> string { return string(path_buf[:w]) } + +_are_paths_identical :: strings.equal_fold + +_clean_path_handle_start :: proc(path: string, buffer: []u8) -> (rooted: bool, start: int) { + // Preserve rooted paths. + start = _volume_name_len(path) + if start > 0 { + rooted = true + if len(path) > start && _is_path_separator(path[start]) { + // Take `C:` to `C:\`. + start += 1 + } + copy(buffer, path[:start]) + for n in 0.. bool { + if _is_reserved_name(path) { + return true + } + l := _volume_name_len(path) + if l == 0 { + return false + } + + path := path + path = path[l:] + if path == "" { + return false + } + return _is_path_separator(path[0]) +} + +_get_absolute_path :: proc(path: string, allocator: runtime.Allocator) -> (absolute_path: string, err: Error) { + rel := path + if rel == "" { + rel = "." + } + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + rel_utf16 := win32.utf8_to_utf16(rel, temp_allocator) + n := win32.GetFullPathNameW(cstring16(raw_data(rel_utf16)), 0, nil, nil) + if n == 0 { + return "", Platform_Error(win32.GetLastError()) + } + + buf := make([]u16, n, temp_allocator) or_return + n = win32.GetFullPathNameW(cstring16(raw_data(rel_utf16)), u32(n), cstring16(raw_data(buf)), nil) + if n == 0 { + return "", Platform_Error(win32.GetLastError()) + } + + return win32.utf16_to_utf8(buf, allocator) +} + +_get_relative_path_handle_start :: proc(base, target: string) -> bool { + base_root := base[:_volume_name_len(base)] + target_root := target[:_volume_name_len(target)] + return strings.equal_fold(base_root, target_root) +} + +_get_common_path_len :: proc(base, target: string) -> int { + i := 0 + end := min(len(base), len(target)) + for j in 0..=end { + if j == end || _is_path_separator(base[j]) { + if strings.equal_fold(base[i:j], target[i:j]) { + i = j + } else { + break + } + } + } + return i +} + +_split_path :: proc(path: string) -> (dir, file: string) { + vol_len := _volume_name_len(path) + + i := len(path) - 1 + for i >= vol_len && !_is_path_separator(path[i]) { + i -= 1 + } + if i == vol_len { + return path[:i+1], path[i+1:] + } else if i > vol_len { + return path[:i], path[i+1:] + } + return "", path +} diff --git a/core/os/os2/process.odin b/core/os/os2/process.odin index c90e3add2..635befc64 100644 --- a/core/os/os2/process.odin +++ b/core/os/os2/process.odin @@ -16,7 +16,8 @@ Arguments to the current process. args := get_args() @(private="file") -get_args :: proc() -> []string { +get_args :: proc "contextless" () -> []string { + context = runtime.default_context() result := make([]string, len(runtime.args__), heap_allocator()) for rt_arg, i in runtime.args__ { result[i] = string(rt_arg) @@ -24,6 +25,12 @@ get_args :: proc() -> []string { return result } +@(fini, private="file") +delete_args :: proc "contextless" () { + context = runtime.default_context() + delete(args, heap_allocator()) +} + /* Exit the current process. */ @@ -264,7 +271,7 @@ specific process, even after it has died. **Note(linux)**: The `handle` will be referring to pidfd. */ Process :: struct { - pid: int, + pid: int, handle: uintptr, } @@ -290,21 +297,10 @@ process_open :: proc(pid: int, flags := Process_Open_Flags {}) -> (Process, Erro return _process_open(pid, flags) } - -/* -OS-specific process attributes. -*/ -Process_Attributes :: struct { - sys_attr: _Sys_Process_Attributes, -} - /* The description of how a process should be created. */ Process_Desc :: struct { - // OS-specific attributes. - sys_attr: Process_Attributes, - // The working directory of the process. If the string has length 0, the // working directory is assumed to be the current working directory of the // current process. @@ -407,11 +403,9 @@ process_exec :: proc( { stdout_b: [dynamic]byte stdout_b.allocator = allocator - defer stdout = stdout_b[:] stderr_b: [dynamic]byte stderr_b.allocator = allocator - defer stderr = stderr_b[:] buf: [1024]u8 = --- @@ -450,6 +444,9 @@ process_exec :: proc( } } } + + stdout = stdout_b[:] + stderr = stderr_b[:] } if err != nil { diff --git a/core/os/os2/process_linux.odin b/core/os/os2/process_linux.odin index 632bde6ba..170f0ea1a 100644 --- a/core/os/os2/process_linux.odin +++ b/core/os/os2/process_linux.odin @@ -10,7 +10,6 @@ import "core:slice" import "core:strings" import "core:strconv" import "core:sys/linux" -import "core:path/filepath" PIDFD_UNASSIGNED :: ~uintptr(0) @@ -51,7 +50,7 @@ _get_ppid :: proc() -> int { @(private="package") _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) dir_fd, errno := linux.open("/proc/", _OPENDIR_FLAGS) #partial switch errno { @@ -69,9 +68,9 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) } defer linux.close(dir_fd) - dynamic_list := make([dynamic]int, temp_allocator()) or_return + dynamic_list := make([dynamic]int, temp_allocator) or_return - buf := make([dynamic]u8, 128, 128, temp_allocator()) or_return + buf := make([dynamic]u8, 128, 128, temp_allocator) or_return loop: for { buflen: int buflen, errno = linux.getdents(dir_fd, buf[:]) @@ -101,7 +100,7 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) @(private="package") _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator: runtime.Allocator) -> (info: Process_Info, err: Error) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) info.pid = pid @@ -127,7 +126,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator passwd_bytes: []u8 passwd_err: Error - passwd_bytes, passwd_err = _read_entire_pseudo_file_cstring("/etc/passwd", temp_allocator()) + passwd_bytes, passwd_err = _read_entire_pseudo_file_cstring("/etc/passwd", temp_allocator) if passwd_err != nil { err = passwd_err break username_if @@ -163,13 +162,13 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator } } - cmdline_if: if selection & {.Working_Dir, .Command_Line, .Command_Args, .Executable_Path} != {} { + cmdline_if: if selection & {.Working_Dir, .Command_Line, .Command_Args} != {} { strings.builder_reset(&path_builder) strings.write_string(&path_builder, "/proc/") strings.write_int(&path_builder, pid) strings.write_string(&path_builder, "/cmdline") - cmdline_bytes, cmdline_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator()) + cmdline_bytes, cmdline_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator) if cmdline_err != nil || len(cmdline_bytes) == 0 { err = cmdline_err break cmdline_if @@ -179,18 +178,18 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator terminator := strings.index_byte(cmdline, 0) assert(terminator > 0) - command_line_exec := cmdline[:terminator] + // command_line_exec := cmdline[:terminator] // Still need cwd if the execution on the command line is relative. cwd: string cwd_err: Error - if .Working_Dir in selection || (.Executable_Path in selection && command_line_exec[0] != '/') { + if .Working_Dir in selection { strings.builder_reset(&path_builder) strings.write_string(&path_builder, "/proc/") strings.write_int(&path_builder, pid) strings.write_string(&path_builder, "/cwd") - cwd, cwd_err = _read_link_cstr(strings.to_cstring(&path_builder) or_return, temp_allocator()) // allowed to fail + cwd, cwd_err = _read_link_cstr(strings.to_cstring(&path_builder) or_return, temp_allocator) // allowed to fail if cwd_err == nil && .Working_Dir in selection { info.working_dir = strings.clone(cwd, allocator) or_return info.fields += {.Working_Dir} @@ -200,18 +199,6 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator } } - if .Executable_Path in selection { - if cmdline[0] == '/' { - info.executable_path = strings.clone(cmdline[:terminator], allocator) or_return - info.fields += {.Executable_Path} - } else if cwd_err == nil { - info.executable_path = filepath.join({ cwd, cmdline[:terminator] }, allocator) or_return - info.fields += {.Executable_Path} - } else { - break cmdline_if - } - } - if selection & {.Command_Line, .Command_Args} != {} { // skip to first arg //cmdline = cmdline[terminator + 1:] @@ -258,7 +245,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator strings.write_int(&path_builder, pid) strings.write_string(&path_builder, "/stat") - proc_stat_bytes, stat_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator()) + proc_stat_bytes, stat_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator) if stat_err != nil { err = stat_err break stat_if @@ -297,7 +284,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator Nice, //... etc, } - stat_fields := strings.split(stats, " ", temp_allocator()) or_return + stat_fields := strings.split(stats, " ", temp_allocator) or_return if len(stat_fields) <= int(Fields.Nice) { break stat_if @@ -324,13 +311,37 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator } } + if .Executable_Path in selection { + /* + NOTE(Jeroen): + + The old version returned the wrong executable path for things like `bash` or `sh`, + for whom `/proc//cmdline` will just report "bash" or "sh", + resulting in misleading paths like `$PWD/sh`, even though that executable doesn't exist there. + + Thanks to Yawning for suggesting `/proc/self/exe`. + */ + + strings.builder_reset(&path_builder) + strings.write_string(&path_builder, "/proc/") + strings.write_int(&path_builder, pid) + strings.write_string(&path_builder, "/exe") + + if exe_bytes, exe_err := _read_link(strings.to_string(path_builder), temp_allocator); exe_err == nil { + info.executable_path = strings.clone(string(exe_bytes), allocator) or_return + info.fields += {.Executable_Path} + } else { + err = exe_err + } + } + if .Environment in selection { strings.builder_reset(&path_builder) strings.write_string(&path_builder, "/proc/") strings.write_int(&path_builder, pid) strings.write_string(&path_builder, "/environ") - if env_bytes, env_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator()); env_err == nil { + if env_bytes, env_err := _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator); env_err == nil { env := string(env_bytes) env_list := make([dynamic]string, allocator) or_return @@ -379,12 +390,9 @@ _process_open :: proc(pid: int, _: Process_Open_Flags) -> (process: Process, err return } -@(private="package") -_Sys_Process_Attributes :: struct {} - @(private="package") _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) if len(desc.command) == 0 { return process, .Invalid_Command @@ -393,7 +401,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { dir_fd := linux.AT_FDCWD errno: linux.Errno if desc.working_dir != "" { - dir_cstr := temp_cstring(desc.working_dir) or_return + dir_cstr := clone_to_cstring(desc.working_dir, temp_allocator) or_return if dir_fd, errno = linux.open(dir_cstr, _OPENDIR_FLAGS); errno != .NONE { return process, _get_platform_error(errno) } @@ -406,10 +414,10 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { exe_path: cstring executable_name := desc.command[0] if strings.index_byte(executable_name, '/') < 0 { - path_env := get_env("PATH", temp_allocator()) - path_dirs := filepath.split_list(path_env, temp_allocator()) or_return + path_env := get_env("PATH", temp_allocator) + path_dirs := split_path_list(path_env, temp_allocator) or_return - exe_builder := strings.builder_make(temp_allocator()) or_return + exe_builder := strings.builder_make(temp_allocator) or_return found: bool for dir in path_dirs { @@ -436,7 +444,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { } } } else { - exe_path = temp_cstring(executable_name) or_return + exe_path = clone_to_cstring(executable_name, temp_allocator) or_return if linux.access(exe_path, linux.X_OK) != .NONE { return process, .Not_Exist } @@ -444,20 +452,20 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { // args and environment need to be a list of cstrings // that are terminated by a nil pointer. - cargs := make([]cstring, len(desc.command) + 1, temp_allocator()) or_return + cargs := make([]cstring, len(desc.command) + 1, temp_allocator) or_return for command, i in desc.command { - cargs[i] = temp_cstring(command) or_return + cargs[i] = clone_to_cstring(command, temp_allocator) or_return } // Use current process' environment if description didn't provide it. env: [^]cstring if desc.env == nil { // take this process's current environment - env = raw_data(export_cstring_environment(temp_allocator())) + env = raw_data(export_cstring_environment(temp_allocator)) } else { - cenv := make([]cstring, len(desc.env) + 1, temp_allocator()) or_return + cenv := make([]cstring, len(desc.env) + 1, temp_allocator) or_return for env, i in desc.env { - cenv[i] = temp_cstring(env) or_return + cenv[i] = clone_to_cstring(env, temp_allocator) or_return } env = &cenv[0] } @@ -585,7 +593,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { } _process_state_update_times :: proc(state: ^Process_State) -> (err: Error) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) stat_path_buf: [48]u8 path_builder := strings.builder_from_bytes(stat_path_buf[:]) @@ -594,7 +602,7 @@ _process_state_update_times :: proc(state: ^Process_State) -> (err: Error) { strings.write_string(&path_builder, "/stat") stat_buf: []u8 - stat_buf, err = _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator()) + stat_buf, err = _read_entire_pseudo_file(strings.to_cstring(&path_builder) or_return, temp_allocator) if err != nil { return } diff --git a/core/os/os2/process_posix.odin b/core/os/os2/process_posix.odin index 3fa429cbe..fcacdf654 100644 --- a/core/os/os2/process_posix.odin +++ b/core/os/os2/process_posix.odin @@ -6,7 +6,6 @@ import "base:runtime" import "core:time" import "core:strings" -import "core:path/filepath" import kq "core:sys/kqueue" import "core:sys/posix" @@ -47,22 +46,20 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime return _process_info_by_pid(_get_pid(), selection, allocator) } -_Sys_Process_Attributes :: struct {} - _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { if len(desc.command) == 0 { err = .Invalid_Path return } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) // search PATH if just a plain name is provided. - exe_builder := strings.builder_make(temp_allocator()) + exe_builder := strings.builder_make(temp_allocator) exe_name := desc.command[0] if strings.index_byte(exe_name, '/') < 0 { - path_env := get_env("PATH", temp_allocator()) - path_dirs := filepath.split_list(path_env, temp_allocator()) + path_env := get_env("PATH", temp_allocator) + path_dirs := split_path_list(path_env, temp_allocator) or_return found: bool for dir in path_dirs { @@ -111,12 +108,12 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { } cwd: cstring; if desc.working_dir != "" { - cwd = temp_cstring(desc.working_dir) + cwd = clone_to_cstring(desc.working_dir, temp_allocator) or_return } - cmd := make([]cstring, len(desc.command) + 1, temp_allocator()) + cmd := make([]cstring, len(desc.command) + 1, temp_allocator) for part, i in desc.command { - cmd[i] = temp_cstring(part) + cmd[i] = clone_to_cstring(part, temp_allocator) or_return } env: [^]cstring @@ -124,9 +121,9 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { // take this process's current environment env = posix.environ } else { - cenv := make([]cstring, len(desc.env) + 1, temp_allocator()) + cenv := make([]cstring, len(desc.env) + 1, temp_allocator) for env, i in desc.env { - cenv[i] = temp_cstring(env) + cenv[i] = clone_to_cstring(env, temp_allocator) or_return } env = raw_data(cenv) } diff --git a/core/os/os2/process_posix_darwin.odin b/core/os/os2/process_posix_darwin.odin index 0ea1f643c..f655d42a9 100644 --- a/core/os/os2/process_posix_darwin.odin +++ b/core/os/os2/process_posix_darwin.odin @@ -10,10 +10,10 @@ import "core:sys/posix" import "core:sys/unix" import "core:time" -foreign import lib "system:System.framework" +foreign import lib "system:System" foreign lib { - sysctl :: proc( + sysctl :: proc "c" ( name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^uint, newp: rawptr, newlen: uint, @@ -50,6 +50,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator } + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) info.pid = pid // Thought on errors is: allocation failures return immediately (also why the non-allocation stuff is done first), @@ -127,7 +128,7 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator break args } - buf := runtime.make_aligned([]byte, length, 4, temp_allocator()) + buf := runtime.make_aligned([]byte, length, 4, temp_allocator) if sysctl(raw_data(mib), 3, raw_data(buf), &length, nil, 0) != .OK { if err == nil { err = _get_platform_error() @@ -239,9 +240,9 @@ _process_list :: proc(allocator: runtime.Allocator) -> (list: []int, err: Error) return } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - buffer := make([]i32, ret, temp_allocator()) + buffer := make([]i32, ret, temp_allocator) ret = darwin.proc_listallpids(raw_data(buffer), ret*size_of(i32)) if ret < 0 { err = _get_platform_error() diff --git a/core/os/os2/process_wasi.odin b/core/os/os2/process_wasi.odin index 6ebfe3788..9f4d61649 100644 --- a/core/os/os2/process_wasi.odin +++ b/core/os/os2/process_wasi.odin @@ -44,8 +44,6 @@ _current_process_info :: proc(selection: Process_Info_Fields, allocator: runtime return } -_Sys_Process_Attributes :: struct {} - _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { err = .Unsupported return diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin index 536930ee1..990da6616 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/os2/process_windows.odin @@ -162,9 +162,10 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator if err != nil { break read_peb } + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) if selection >= {.Command_Line, .Command_Args} { - TEMP_ALLOCATOR_GUARD() - cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return + temp_allocator_scope(temp_allocator) + cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator) or_return _, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) if err != nil { break read_peb @@ -174,14 +175,14 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator info.fields += {.Command_Line} } if .Command_Args in selection { - info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return + info.command_args = _parse_command_line(cstring16(raw_data(cmdline_w)), allocator) or_return info.fields += {.Command_Args} } } if .Environment in selection { - TEMP_ALLOCATOR_GUARD() + temp_allocator_scope(temp_allocator) env_len := process_params.EnvironmentSize / 2 - envs_w := make([]u16, env_len, temp_allocator()) or_return + envs_w := make([]u16, env_len, temp_allocator) or_return _, err = read_memory_as_slice(ph, process_params.Environment, envs_w) if err != nil { break read_peb @@ -190,8 +191,8 @@ _process_info_by_pid :: proc(pid: int, selection: Process_Info_Fields, allocator info.fields += {.Environment} } if .Working_Dir in selection { - TEMP_ALLOCATOR_GUARD() - cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return + temp_allocator_scope(temp_allocator) + cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator) or_return _, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) if err != nil { break read_peb @@ -272,9 +273,10 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields if err != nil { break read_peb } + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) if selection >= {.Command_Line, .Command_Args} { - TEMP_ALLOCATOR_GUARD() - cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator()) or_return + temp_allocator_scope(temp_allocator) + cmdline_w := make([]u16, process_params.CommandLine.Length, temp_allocator) or_return _, err = read_memory_as_slice(ph, process_params.CommandLine.Buffer, cmdline_w) if err != nil { break read_peb @@ -284,14 +286,14 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields info.fields += {.Command_Line} } if .Command_Args in selection { - info.command_args = _parse_command_line(raw_data(cmdline_w), allocator) or_return + info.command_args = _parse_command_line(cstring16(raw_data(cmdline_w)), allocator) or_return info.fields += {.Command_Args} } } if .Environment in selection { - TEMP_ALLOCATOR_GUARD() + temp_allocator_scope(temp_allocator) env_len := process_params.EnvironmentSize / 2 - envs_w := make([]u16, env_len, temp_allocator()) or_return + envs_w := make([]u16, env_len, temp_allocator) or_return _, err = read_memory_as_slice(ph, process_params.Environment, envs_w) if err != nil { break read_peb @@ -300,8 +302,8 @@ _process_info_by_handle :: proc(process: Process, selection: Process_Info_Fields info.fields += {.Environment} } if .Working_Dir in selection { - TEMP_ALLOCATOR_GUARD() - cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator()) or_return + temp_allocator_scope(temp_allocator) + cwd_w := make([]u16, process_params.CurrentDirectoryPath.Length, temp_allocator) or_return _, err = read_memory_as_slice(ph, process_params.CurrentDirectoryPath.Buffer, cwd_w) if err != nil { break read_peb @@ -417,35 +419,64 @@ _process_open :: proc(pid: int, flags: Process_Open_Flags) -> (process: Process, return } -@(private="package") -_Sys_Process_Attributes :: struct {} - @(private="package") _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { - TEMP_ALLOCATOR_GUARD() - command_line := _build_command_line(desc.command, temp_allocator()) - command_line_w := win32_utf8_to_wstring(command_line, temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + command_line := _build_command_line(desc.command, temp_allocator) + command_line_w := win32_utf8_to_wstring(command_line, temp_allocator) or_return environment := desc.env if desc.env == nil { - environment = environ(temp_allocator()) or_return + environment = environ(temp_allocator) or_return } - environment_block := _build_environment_block(environment, temp_allocator()) - environment_block_w := win32_utf8_to_utf16(environment_block, temp_allocator()) or_return - stderr_handle := win32.GetStdHandle(win32.STD_ERROR_HANDLE) - stdout_handle := win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) - stdin_handle := win32.GetStdHandle(win32.STD_INPUT_HANDLE) + environment_block := _build_environment_block(environment, temp_allocator) + environment_block_w := win32_utf8_to_utf16(environment_block, temp_allocator) or_return - if desc.stdout != nil { + stderr_handle: win32.HANDLE + stdout_handle: win32.HANDLE + stdin_handle: win32.HANDLE + + null_handle: win32.HANDLE + if desc.stdout == nil || desc.stderr == nil || desc.stdin == nil { + null_handle = win32.CreateFileW( + win32.L("NUL"), + win32.GENERIC_READ|win32.GENERIC_WRITE, + win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE, + &win32.SECURITY_ATTRIBUTES{ + nLength = size_of(win32.SECURITY_ATTRIBUTES), + bInheritHandle = true, + }, + win32.OPEN_EXISTING, + win32.FILE_ATTRIBUTE_NORMAL, + nil, + ) + // Opening NUL should always succeed. + assert(null_handle != nil) + } + // NOTE(laytan): I believe it is fine to close this handle right after CreateProcess, + // and we don't have to hold onto this until the process exits. + defer if null_handle != nil { + win32.CloseHandle(null_handle) + } + + if desc.stdout == nil { + stdout_handle = null_handle + } else { stdout_handle = win32.HANDLE((^File_Impl)(desc.stdout.impl).fd) } - if desc.stderr != nil { + + if desc.stderr == nil { + stderr_handle = null_handle + } else { stderr_handle = win32.HANDLE((^File_Impl)(desc.stderr.impl).fd) } - if desc.stdin != nil { + + if desc.stdin == nil { + stdin_handle = null_handle + } else { stdin_handle = win32.HANDLE((^File_Impl)(desc.stdin.impl).fd) } - working_dir_w := (win32_utf8_to_wstring(desc.working_dir, temp_allocator()) or_else nil) if len(desc.working_dir) > 0 else nil + working_dir_w := (win32_utf8_to_wstring(desc.working_dir, temp_allocator) or_else nil) if len(desc.working_dir) > 0 else nil process_info: win32.PROCESS_INFORMATION ok := win32.CreateProcessW( nil, @@ -579,11 +610,11 @@ _process_exe_by_pid :: proc(pid: int, allocator: runtime.Allocator) -> (exe_path err =_get_platform_error() return } - return win32_wstring_to_utf8(raw_data(entry.szExePath[:]), allocator) + return win32_wstring_to_utf8(cstring16(raw_data(entry.szExePath[:])), allocator) } _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Allocator) -> (full_username: string, err: Error) { - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) token_handle: win32.HANDLE if !win32.OpenProcessToken(process_handle, win32.TOKEN_QUERY, &token_handle) { err = _get_platform_error() @@ -598,7 +629,7 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc } err = nil } - token_user := (^win32.TOKEN_USER)(raw_data(make([]u8, token_user_size, temp_allocator()) or_return)) + token_user := (^win32.TOKEN_USER)(raw_data(make([]u8, token_user_size, temp_allocator) or_return)) if !win32.GetTokenInformation(token_handle, .TokenUser, token_user, token_user_size, &token_user_size) { err = _get_platform_error() return @@ -614,12 +645,12 @@ _get_process_user :: proc(process_handle: win32.HANDLE, allocator: runtime.Alloc err = _get_platform_error() return } - username := win32_utf16_to_utf8(username_w[:username_chrs], temp_allocator()) or_return - domain := win32_utf16_to_utf8(domain_w[:domain_chrs], temp_allocator()) or_return + username := win32_utf16_to_utf8(username_w[:username_chrs], temp_allocator) or_return + domain := win32_utf16_to_utf8(domain_w[:domain_chrs], temp_allocator) or_return return strings.concatenate({domain, "\\", username}, allocator) } -_parse_command_line :: proc(cmd_line_w: [^]u16, allocator: runtime.Allocator) -> (argv: []string, err: Error) { +_parse_command_line :: proc(cmd_line_w: cstring16, allocator: runtime.Allocator) -> (argv: []string, err: Error) { argc: i32 argv_w := win32.CommandLineToArgvW(cmd_line_w, &argc) if argv_w == nil { diff --git a/core/os/os2/stat.odin b/core/os/os2/stat.odin index b53ebb3ab..d6b524684 100644 --- a/core/os/os2/stat.odin +++ b/core/os/os2/stat.odin @@ -1,7 +1,6 @@ package os2 import "base:runtime" -import "core:path/filepath" import "core:strings" import "core:time" @@ -24,8 +23,8 @@ File_Info :: struct { @(require_results) file_info_clone :: proc(fi: File_Info, allocator: runtime.Allocator) -> (cloned: File_Info, err: runtime.Allocator_Error) { cloned = fi - cloned.fullpath = strings.clone(fi.fullpath) or_return - cloned.name = filepath.base(cloned.fullpath) + cloned.fullpath = strings.clone(fi.fullpath, allocator) or_return + _, cloned.name = split_path(cloned.fullpath) return } @@ -74,14 +73,14 @@ last_write_time_by_name :: modification_time_by_path @(require_results) modification_time :: proc(f: ^File) -> (time.Time, Error) { - TEMP_ALLOCATOR_GUARD() - fi, err := fstat(f, temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + fi, err := fstat(f, temp_allocator) return fi.modification_time, err } @(require_results) modification_time_by_path :: proc(path: string) -> (time.Time, Error) { - TEMP_ALLOCATOR_GUARD() - fi, err := stat(path, temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + fi, err := stat(path, temp_allocator) return fi.modification_time, err } diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin index 0433c1a61..373765be5 100644 --- a/core/os/os2/stat_linux.odin +++ b/core/os/os2/stat_linux.odin @@ -4,7 +4,6 @@ package os2 import "core:time" import "base:runtime" import "core:sys/linux" -import "core:path/filepath" _fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) { impl := (^File_Impl)(f.impl) @@ -42,14 +41,14 @@ _fstat_internal :: proc(fd: linux.Fd, allocator: runtime.Allocator) -> (fi: File creation_time = time.Time{i64(s.ctime.time_sec) * i64(time.Second) + i64(s.ctime.time_nsec)}, // regular stat does not provide this } fi.creation_time = fi.modification_time - fi.name = filepath.base(fi.fullpath) + _, fi.name = split_path(fi.fullpath) return } // NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + name_cstr := clone_to_cstring(name, temp_allocator) or_return fd, errno := linux.open(name_cstr, {}) if errno != .NONE { @@ -60,8 +59,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err } _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { - TEMP_ALLOCATOR_GUARD() - name_cstr := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + name_cstr := clone_to_cstring(name, temp_allocator) or_return fd, errno := linux.open(name_cstr, {.PATH, .NOFOLLOW}) if errno != .NONE { diff --git a/core/os/os2/stat_posix.odin b/core/os/os2/stat_posix.odin index 88029c1f5..6ffbdf1da 100644 --- a/core/os/os2/stat_posix.odin +++ b/core/os/os2/stat_posix.odin @@ -4,13 +4,12 @@ package os2 import "base:runtime" -import "core:path/filepath" import "core:sys/posix" import "core:time" internal_stat :: proc(stat: posix.stat_t, fullpath: string) -> (fi: File_Info) { fi.fullpath = fullpath - fi.name = filepath.base(fi.fullpath) + _, fi.name = split_path(fi.fullpath) fi.inode = u128(stat.st_ino) fi.size = i64(stat.st_size) @@ -70,8 +69,8 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err return } - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + cname := clone_to_cstring(name, temp_allocator) or_return fd := posix.open(cname, {}) if fd == -1 { @@ -97,33 +96,34 @@ _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, er return } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) // NOTE: can't use realpath or open (+ fcntl F_GETPATH) here because it tries to resolve symlinks. // NOTE: This might not be correct when given "/symlink/foo.txt", // you would want that to resolve "/symlink", but not resolve "foo.txt". - fullpath := filepath.clean(name, temp_allocator()) + fullpath := clean_path(name, temp_allocator) or_return assert(len(fullpath) > 0) switch { case fullpath[0] == '/': // nothing. case fullpath == ".": - fullpath = getwd(temp_allocator()) or_return + fullpath = getwd(temp_allocator) or_return case len(fullpath) > 1 && fullpath[0] == '.' && fullpath[1] == '/': fullpath = fullpath[2:] fallthrough case: fullpath = concatenate({ - getwd(temp_allocator()) or_return, + getwd(temp_allocator) or_return, "/", fullpath, - }, temp_allocator()) or_return + }, temp_allocator) or_return } stat: posix.stat_t - if posix.lstat(temp_cstring(fullpath), &stat) != .OK { + c_fullpath := clone_to_cstring(fullpath, temp_allocator) or_return + if posix.lstat(c_fullpath, &stat) != .OK { err = _get_platform_error() return } diff --git a/core/os/os2/stat_wasi.odin b/core/os/os2/stat_wasi.odin index 2992c6267..bf18d8273 100644 --- a/core/os/os2/stat_wasi.odin +++ b/core/os/os2/stat_wasi.odin @@ -3,13 +3,12 @@ package os2 import "base:runtime" -import "core:path/filepath" import "core:sys/wasm/wasi" import "core:time" internal_stat :: proc(stat: wasi.filestat_t, fullpath: string) -> (fi: File_Info) { fi.fullpath = fullpath - fi.name = filepath.base(fi.fullpath) + _, fi.name = split_path(fi.fullpath) fi.inode = u128(stat.ino) fi.size = i64(stat.size) diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin index 31f5d9e88..3dee42be6 100644 --- a/core/os/os2/stat_windows.odin +++ b/core/os/os2/stat_windows.odin @@ -45,16 +45,16 @@ full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path name = "." } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - p := win32_utf8_to_utf16(name, temp_allocator()) or_return + p := win32_utf8_to_utf16(name, temp_allocator) or_return - n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil) + n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil) if n == 0 { return "", _get_platform_error() } - buf := make([]u16, n+1, temp_allocator()) - n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) + buf := make([]u16, n+1, temp_allocator) + n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil) if n == 0 { return "", _get_platform_error() } @@ -65,9 +65,9 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runt if len(name) == 0 { return {}, .Not_Exist } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - wname := _fix_long_path(name, temp_allocator()) or_return + wname := _fix_long_path(name, temp_allocator) or_return fa: win32.WIN32_FILE_ATTRIBUTE_DATA ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa) if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { @@ -137,11 +137,11 @@ _cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (strin return "", _get_platform_error() } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - buf := make([]u16, max(n, 260)+1, temp_allocator()) - n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0) - return _cleanpath_from_buf(buf[:n], allocator) + buf := make([]u16, max(n, 260)+1, temp_allocator) + n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0) + return _cleanpath_from_buf(string16(buf[:n]), allocator) } _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) { @@ -155,15 +155,15 @@ _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) { return nil, _get_platform_error() } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({}) - buf := make([]u16, max(n, 260)+1, temp_allocator()) - n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0) + buf := make([]u16, max(n, 260)+1, temp_allocator) + n = win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), u32(len(buf)), 0) return _cleanpath_strip_prefix(buf[:n]), nil } -_cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { - buf := buf +_cleanpath_from_buf :: proc(buf: string16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { + buf := transmute([]u16)buf buf = _cleanpath_strip_prefix(buf) return win32_utf16_to_utf8(buf, allocator) } @@ -236,14 +236,30 @@ _file_type_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: wi return } +// a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC) +time_as_filetime :: #force_inline proc(t: time.Time) -> (ft: win32.LARGE_INTEGER) { + win := u64(t._nsec / 100) + 116444736000000000 + return win32.LARGE_INTEGER(win) +} + +filetime_as_time_li :: #force_inline proc(ft: win32.LARGE_INTEGER) -> (t: time.Time) { + return {_nsec=(i64(ft) - 116444736000000000) * 100} +} + +filetime_as_time_ft :: #force_inline proc(ft: win32.FILETIME) -> (t: time.Time) { + return filetime_as_time_li(win32.LARGE_INTEGER(ft.dwLowDateTime) + win32.LARGE_INTEGER(ft.dwHighDateTime) << 32) +} + +filetime_as_time :: proc{filetime_as_time_ft, filetime_as_time_li} + _file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) { fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0) fi.type = type fi.mode |= mode - fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime)) - fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime)) - fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime)) + fi.creation_time = filetime_as_time(d.ftCreationTime) + fi.modification_time = filetime_as_time(d.ftLastWriteTime) + fi.access_time = filetime_as_time(d.ftLastAccessTime) fi.fullpath, e = full_path_from_name(name, allocator) fi.name = basename(fi.fullpath) return @@ -254,9 +270,9 @@ _file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, nil, 0) fi.type = type fi.mode |= mode - fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime)) - fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime)) - fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime)) + fi.creation_time = filetime_as_time(d.ftCreationTime) + fi.modification_time = filetime_as_time(d.ftLastWriteTime) + fi.access_time = filetime_as_time(d.ftLastAccessTime) fi.fullpath, e = full_path_from_name(name, allocator) fi.name = basename(fi.fullpath) return @@ -286,9 +302,9 @@ _file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HA type, mode := _file_type_mode_from_file_attributes(d.dwFileAttributes, h, 0) fi.type = type fi.mode |= mode - fi.creation_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftCreationTime)) - fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime)) - fi.access_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime)) + fi.creation_time = filetime_as_time(d.ftCreationTime) + fi.modification_time = filetime_as_time(d.ftLastWriteTime) + fi.access_time = filetime_as_time(d.ftLastAccessTime) return fi, nil } @@ -310,62 +326,68 @@ _is_reserved_name :: proc(path: string) -> bool { return false } -_is_UNC :: proc(path: string) -> bool { - return _volume_name_len(path) > 2 -} +_volume_name_len :: proc(path: string) -> (length: int) { + if len(path) < 2 { + return 0 + } -_volume_name_len :: proc(path: string) -> int { - if ODIN_OS == .Windows { - if len(path) < 2 { - return 0 + if path[1] == ':' { + switch path[0] { + case 'a'..='z', 'A'..='Z': + return 2 } - c := path[0] - if path[1] == ':' { - switch c { + } + + /* + See: URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx + Further allowed paths can be of the form of: + - \\server\share or \\server\share\more\path + - \\?\C:\... + - \\.\PhysicalDriveX + */ + // Any remaining kind of path has to start with two slashes. + if !_is_path_separator(path[0]) || !_is_path_separator(path[1]) { + return 0 + } + + // Device path. The volume name is the whole string + if len(path) >= 5 && path[2] == '.' && _is_path_separator(path[3]) { + return len(path) + } + + // We're a UNC share `\\host\share`, file namespace `\\?\C:` or UNC in file namespace `\\?\\host\share` + prefix := 2 + + // File namespace. + if len(path) >= 5 && path[2] == '?' && _is_path_separator(path[3]) { + if _is_path_separator(path[4]) { + // `\\?\\` UNC path in file namespace + prefix = 5 + } + + if len(path) >= 6 && path[5] == ':' { + switch path[4] { case 'a'..='z', 'A'..='Z': - return 2 - } - } - - // URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx - if l := len(path); l >= 5 && _is_path_separator(path[0]) && _is_path_separator(path[1]) && - !_is_path_separator(path[2]) && path[2] != '.' { - for n := 3; n < l-1; n += 1 { - if _is_path_separator(path[n]) { - n += 1 - if !_is_path_separator(path[n]) { - if path[n] == '.' { - break - } - } - for ; n < l; n += 1 { - if _is_path_separator(path[n]) { - break - } - } - return n - } - break + return 6 + case: + return 0 } } } - return 0 -} -_is_abs :: proc(path: string) -> bool { - if _is_reserved_name(path) { - return true - } - l := _volume_name_len(path) - if l == 0 { - return false + // UNC path, minimum version of the volume is `\\h\s` for host, share. + // Can also contain an IP address in the host position. + slash_count := 0 + for i in prefix.. 0 { + slash_count += 1 + + if slash_count == 2 { + return i + } + } } - path := path - path = path[l:] - if path == "" { - return false - } - return is_path_separator(path[0]) -} - + return len(path) +} \ No newline at end of file diff --git a/core/os/os2/temp_file.odin b/core/os/os2/temp_file.odin index 5ca4e1453..e3e74bd11 100644 --- a/core/os/os2/temp_file.odin +++ b/core/os/os2/temp_file.odin @@ -15,13 +15,13 @@ MAX_ATTEMPTS :: 1<<13 // Should be enough for everyone, right? // The caller must `close` the file once finished with. @(require_results) create_temp_file :: proc(dir, pattern: string) -> (f: ^File, err: Error) { - TEMP_ALLOCATOR_GUARD() - dir := dir if dir != "" else temp_directory(temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + dir := dir if dir != "" else temp_directory(temp_allocator) or_return prefix, suffix := _prefix_and_suffix(pattern) or_return - prefix = temp_join_path(dir, prefix) or_return + prefix = temp_join_path(dir, prefix, temp_allocator) or_return - rand_buf: [32]byte - name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator()) + rand_buf: [10]byte + name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator) attempts := 0 for { @@ -47,13 +47,13 @@ mkdir_temp :: make_directory_temp // If `dir` is an empty tring, `temp_directory()` will be used. @(require_results) make_directory_temp :: proc(dir, pattern: string, allocator: runtime.Allocator) -> (temp_path: string, err: Error) { - TEMP_ALLOCATOR_GUARD() - dir := dir if dir != "" else temp_directory(temp_allocator()) or_return + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + dir := dir if dir != "" else temp_directory(temp_allocator) or_return prefix, suffix := _prefix_and_suffix(pattern) or_return - prefix = temp_join_path(dir, prefix) or_return + prefix = temp_join_path(dir, prefix, temp_allocator) or_return - rand_buf: [32]byte - name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator()) + rand_buf: [10]byte + name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator) attempts := 0 for { @@ -70,7 +70,7 @@ make_directory_temp :: proc(dir, pattern: string, allocator: runtime.Allocator) return "", err } if err == .Not_Exist { - if _, serr := stat(dir, temp_allocator()); serr == .Not_Exist { + if _, serr := stat(dir, temp_allocator); serr == .Not_Exist { return "", serr } } @@ -88,10 +88,10 @@ temp_directory :: proc(allocator: runtime.Allocator) -> (string, Error) { @(private="file") -temp_join_path :: proc(dir, name: string) -> (string, runtime.Allocator_Error) { +temp_join_path :: proc(dir, name: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { if len(dir) > 0 && is_path_separator(dir[len(dir)-1]) { - return concatenate({dir, name}, temp_allocator(),) + return concatenate({dir, name}, allocator) } - return concatenate({dir, Path_Separator_String, name}, temp_allocator()) + return concatenate({dir, Path_Separator_String, name}, allocator) } diff --git a/core/os/os2/temp_file_linux.odin b/core/os/os2/temp_file_linux.odin index 4eacbc54a..310720cbe 100644 --- a/core/os/os2/temp_file_linux.odin +++ b/core/os/os2/temp_file_linux.odin @@ -4,8 +4,8 @@ package os2 import "base:runtime" _temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { - TEMP_ALLOCATOR_GUARD() - tmpdir := get_env("TMPDIR", temp_allocator()) + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + tmpdir := get_env("TMPDIR", temp_allocator) if tmpdir == "" { tmpdir = "/tmp" } diff --git a/core/os/os2/temp_file_windows.odin b/core/os/os2/temp_file_windows.odin index 3e3e1285c..91ea284a1 100644 --- a/core/os/os2/temp_file_windows.odin +++ b/core/os/os2/temp_file_windows.odin @@ -9,15 +9,15 @@ _temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Er if n == 0 { return "", nil } - TEMP_ALLOCATOR_GUARD() + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) - b := make([]u16, max(win32.MAX_PATH, n), temp_allocator()) - n = win32.GetTempPathW(u32(len(b)), raw_data(b)) + b := make([]u16, max(win32.MAX_PATH, n), temp_allocator) + n = win32.GetTempPathW(u32(len(b)), cstring16(raw_data(b))) if n == 3 && b[1] == ':' && b[2] == '\\' { } else if n > 0 && b[n-1] == '\\' { n -= 1 } - return win32_utf16_to_utf8(b[:n], allocator) + return win32_utf16_to_utf8(string16(b[:n]), allocator) } diff --git a/core/os/os2/user.odin b/core/os/os2/user.odin index a0a7a839d..e2a4ec4d0 100644 --- a/core/os/os2/user.odin +++ b/core/os/os2/user.odin @@ -2,78 +2,148 @@ package os2 import "base:runtime" -@(require_results) -user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { - TEMP_ALLOCATOR_GUARD() - - #partial switch ODIN_OS { - case .Windows: - dir = get_env("LocalAppData", temp_allocator()) - if dir != "" { - dir = clone_string(dir, allocator) or_return - } - case .Darwin: - dir = get_env("HOME", temp_allocator()) - if dir != "" { - dir = concatenate({dir, "/Library/Caches"}, allocator) or_return - } - case: // All other UNIX systems - dir = get_env("XDG_CACHE_HOME", allocator) - if dir == "" { - dir = get_env("HOME", temp_allocator()) - if dir == "" { - return - } - dir = concatenate({dir, "/.cache"}, allocator) or_return - } - } - if dir == "" { - err = .Invalid_Path - } - return -} - -@(require_results) -user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { - TEMP_ALLOCATOR_GUARD() - - #partial switch ODIN_OS { - case .Windows: - dir = get_env("AppData", temp_allocator()) - if dir != "" { - dir = clone_string(dir, allocator) or_return - } - case .Darwin: - dir = get_env("HOME", temp_allocator()) - if dir != "" { - dir = concatenate({dir, "/.config"}, allocator) or_return - } - case: // All other UNIX systems - dir = get_env("XDG_CACHE_HOME", allocator) - if dir == "" { - dir = get_env("HOME", temp_allocator()) - if dir == "" { - return - } - dir = concatenate({dir, "/.config"}, allocator) or_return - } - } - if dir == "" { - err = .Invalid_Path - } - return -} - +// ``` +// Windows: C:\Users\Alice +// macOS: /Users/Alice +// Linux: /home/alice +// ``` @(require_results) user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { - env := "HOME" - #partial switch ODIN_OS { - case .Windows: - env = "USERPROFILE" - } - if v := get_env(env, allocator); v != "" { - return v, nil - } - return "", .Invalid_Path + return _user_home_dir(allocator) } +// Files that applications can regenerate/refetch at a loss of speed, e.g. shader caches +// +// Sometimes deleted for system maintenance +// +// ``` +// Windows: C:\Users\Alice\AppData\Local +// macOS: /Users/Alice/Library/Caches +// Linux: /home/alice/.cache +// ``` +@(require_results) +user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_cache_dir(allocator) +} + +// User-hidden application data +// +// ``` +// Windows: C:\Users\Alice\AppData\Local ("C:\Users\Alice\AppData\Roaming" if `roaming`) +// macOS: /Users/Alice/Library/Application Support +// Linux: /home/alice/.local/share +// ``` +// +// NOTE: (Windows only) `roaming` is for syncing across multiple devices within a *domain network* +@(require_results) +user_data_dir :: proc(allocator: runtime.Allocator, roaming := false) -> (dir: string, err: Error) { + return _user_data_dir(allocator, roaming) +} + +// Non-essential application data, e.g. history, ui layout state +// +// ``` +// Windows: C:\Users\Alice\AppData\Local +// macOS: /Users/Alice/Library/Application Support +// Linux: /home/alice/.local/state +// ``` +@(require_results) +user_state_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_state_dir(allocator) +} + +// Application log files +// +// ``` +// Windows: C:\Users\Alice\AppData\Local +// macOS: /Users/Alice/Library/Logs +// Linux: /home/alice/.local/state +// ``` +@(require_results) +user_log_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_log_dir(allocator) +} + +// Application settings/preferences +// +// ``` +// Windows: C:\Users\Alice\AppData\Local ("C:\Users\Alice\AppData\Roaming" if `roaming`) +// macOS: /Users/Alice/Library/Application Support +// Linux: /home/alice/.config +// ``` +// +// NOTE: (Windows only) `roaming` is for syncing across multiple devices within a *domain network* +@(require_results) +user_config_dir :: proc(allocator: runtime.Allocator, roaming := false) -> (dir: string, err: Error) { + return _user_config_dir(allocator, roaming) +} + +// ``` +// Windows: C:\Users\Alice\Music +// macOS: /Users/Alice/Music +// Linux: /home/alice/Music +// ``` +@(require_results) +user_music_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_music_dir(allocator) +} + +// ``` +// Windows: C:\Users\Alice\Desktop +// macOS: /Users/Alice/Desktop +// Linux: /home/alice/Desktop +// ``` +@(require_results) +user_desktop_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_desktop_dir(allocator) +} + +// ``` +// Windows: C:\Users\Alice\Documents +// macOS: /Users/Alice/Documents +// Linux: /home/alice/Documents +// ``` +@(require_results) +user_documents_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_documents_dir(allocator) +} + +// ``` +// Windows: C:\Users\Alice\Downloads +// macOS: /Users/Alice/Downloads +// Linux: /home/alice/Downloads +// ``` +@(require_results) +user_downloads_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_downloads_dir(allocator) +} + +// ``` +// Windows: C:\Users\Alice\Pictures +// macOS: /Users/Alice/Pictures +// Linux: /home/alice/Pictures +// ``` +@(require_results) +user_pictures_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_pictures_dir(allocator) +} + +// ``` +// Windows: C:\Users\Alice\Public +// macOS: /Users/Alice/Public +// Linux: /home/alice/Public +// ``` +@(require_results) +user_public_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_public_dir(allocator) +} + +// ``` +// Windows: C:\Users\Alice\Videos +// macOS: /Users/Alice/Movies +// Linux: /home/alice/Videos +// ``` +@(require_results) +user_videos_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + return _user_videos_dir(allocator) +} \ No newline at end of file diff --git a/core/os/os2/user_posix.odin b/core/os/os2/user_posix.odin new file mode 100644 index 000000000..691745b7a --- /dev/null +++ b/core/os/os2/user_posix.odin @@ -0,0 +1,175 @@ +#+build !windows +package os2 + +import "base:runtime" +import "core:encoding/ini" +import "core:strings" + +_user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Library/Caches", allocator) + case: // Unix + return _xdg_lookup("XDG_CACHE_HOME", "/.cache", allocator) + } +} + +_user_config_dir :: proc(allocator: runtime.Allocator, _roaming: bool) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Library/Application Support", allocator) + case: // Unix + return _xdg_lookup("XDG_CONFIG_HOME", "/.config", allocator) + } +} + +_user_state_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Library/Application Support", allocator) + case: // Unix + return _xdg_lookup("XDG_STATE_HOME", "/.local/state", allocator) + } +} + +_user_log_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Library/Logs", allocator) + case: // Unix + return _xdg_lookup("XDG_STATE_HOME", "/.local/state", allocator) + } +} + +_user_data_dir :: proc(allocator: runtime.Allocator, _roaming: bool) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Library/Application Support", allocator) + case: // Unix + return _xdg_lookup("XDG_DATA_HOME", "/.local/share", allocator) + } +} + +_user_music_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Music", allocator) + case: // Unix + return _xdg_lookup("XDG_MUSIC_DIR", "/Music", allocator) + } +} + +_user_desktop_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Desktop", allocator) + case: // Unix + return _xdg_lookup("XDG_DESKTOP_DIR", "/Desktop", allocator) + } +} + +_user_documents_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Documents", allocator) + case: // Unix + return _xdg_lookup("XDG_DOCUMENTS_DIR", "/Documents", allocator) + } +} + +_user_downloads_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Downloads", allocator) + case: // Unix + return _xdg_lookup("XDG_DOWNLOAD_DIR", "/Downloads", allocator) + } +} + +_user_pictures_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Pictures", allocator) + case: // Unix + return _xdg_lookup("XDG_PICTURES_DIR", "/Pictures", allocator) + } +} + +_user_public_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Public", allocator) + case: // Unix + return _xdg_lookup("XDG_PUBLICSHARE_DIR", "/Public", allocator) + } +} + +_user_videos_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + #partial switch ODIN_OS { + case .Darwin: + return _xdg_lookup("", "/Movies", allocator) + case: // Unix + return _xdg_lookup("XDG_VIDEOS_DIR", "/Videos", allocator) + } +} + +_user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + if v := get_env("HOME", allocator); v != "" { + return v, nil + } + err = .No_HOME_Variable + return +} + +_xdg_lookup :: proc(xdg_key: string, fallback_suffix: string, allocator: runtime.Allocator) -> (dir: string, err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + + if xdg_key == "" { // Darwin doesn't have XDG paths. + dir = get_env("HOME", temp_allocator) + if dir == "" { + err = .No_HOME_Variable + return + } + return concatenate({dir, fallback_suffix}, allocator) + } else { + if strings.ends_with(xdg_key, "_DIR") { + dir = _xdg_user_dirs_lookup(xdg_key, allocator) or_return + } else { + dir = get_env(xdg_key, allocator) + } + + if dir == "" { + dir = get_env("HOME", temp_allocator) + if dir == "" { + err = .No_HOME_Variable + return + } + dir = concatenate({dir, fallback_suffix}, allocator) or_return + } + return + } +} + +// If `/user-dirs.dirs` doesn't exist, or `xdg_key` can't be found there: returns `""` +_xdg_user_dirs_lookup :: proc(xdg_key: string, allocator: runtime.Allocator) -> (dir: string, err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator }) + config_dir := user_config_dir(temp_allocator) or_return + user_dirs_path := concatenate({config_dir, "/user-dirs.dirs"}, temp_allocator) or_return + content := read_entire_file(user_dirs_path, temp_allocator) or_return + + it := ini.Iterator{ + section = "", + _src = string(content), + options = ini.Options{ + comment = "#", + key_lower_case = false, + }, + } + + for k, v in ini.iterate(&it) { + if k == xdg_key { + return replace_environment_placeholders(v, allocator), nil + } + } + return +} \ No newline at end of file diff --git a/core/os/os2/user_windows.odin b/core/os/os2/user_windows.odin new file mode 100644 index 000000000..75d0ba6ac --- /dev/null +++ b/core/os/os2/user_windows.odin @@ -0,0 +1,78 @@ +package os2 + +import "base:runtime" +@(require) import win32 "core:sys/windows" + +_local_appdata :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + guid := win32.FOLDERID_LocalAppData + return _get_known_folder_path(&guid, allocator) +} + +_local_appdata_or_roaming :: proc(allocator: runtime.Allocator, roaming: bool) -> (dir: string, err: Error) { + guid := win32.FOLDERID_LocalAppData + if roaming { + guid = win32.FOLDERID_RoamingAppData + } + return _get_known_folder_path(&guid, allocator) +} + +_user_config_dir :: _local_appdata_or_roaming +_user_data_dir :: _local_appdata_or_roaming + +_user_state_dir :: _local_appdata +_user_log_dir :: _local_appdata +_user_cache_dir :: _local_appdata + +_user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + guid := win32.FOLDERID_Profile + return _get_known_folder_path(&guid, allocator) +} + +_user_music_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + guid := win32.FOLDERID_Music + return _get_known_folder_path(&guid, allocator) +} + +_user_desktop_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + guid := win32.FOLDERID_Desktop + return _get_known_folder_path(&guid, allocator) +} + +_user_documents_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + guid := win32.FOLDERID_Documents + return _get_known_folder_path(&guid, allocator) +} + +_user_downloads_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + guid := win32.FOLDERID_Downloads + return _get_known_folder_path(&guid, allocator) +} + +_user_pictures_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + guid := win32.FOLDERID_Pictures + return _get_known_folder_path(&guid, allocator) +} + +_user_public_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + guid := win32.FOLDERID_Public + return _get_known_folder_path(&guid, allocator) +} + +_user_videos_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + guid := win32.FOLDERID_Videos + return _get_known_folder_path(&guid, allocator) +} + +_get_known_folder_path :: proc(rfid: win32.REFKNOWNFOLDERID, allocator: runtime.Allocator) -> (dir: string, err: Error) { + // https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath + // See also `known_folders.odin` in `core:sys/windows` for the GUIDs. + path_w: win32.LPWSTR + res := win32.SHGetKnownFolderPath(rfid, 0, nil, &path_w) + defer win32.CoTaskMemFree(path_w) + + if res != 0 { + return "", .Invalid_Path + } + + return win32_wstring_to_utf8(cstring16(path_w), allocator) +} \ No newline at end of file diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index bbffc46d7..77b5825dd 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -1,8 +1,8 @@ package os foreign import dl "system:dl" -foreign import libc "system:System.framework" -foreign import pthread "system:System.framework" +foreign import libc "system:System" +foreign import pthread "system:System" import "base:runtime" import "core:strings" @@ -1055,9 +1055,10 @@ flush :: proc(fd: Handle) -> Error { } @(require_results) -lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) + // NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults. cstr := _unix_getenv(path_str) if cstr == nil { return "", false @@ -1066,11 +1067,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin } @(require_results) -get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + if len(key) + 1 > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, key) + } + + if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { + return "", .Env_Var_Not_Found + } else { + if len(value) > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, value) + return string(buf[:len(value)]), nil + } + } +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} + +@(require_results) +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} + set_env :: proc(key, value: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() key_cstring := strings.clone_to_cstring(key, context.temp_allocator) @@ -1196,8 +1225,9 @@ _processor_core_count :: proc() -> int { return 1 } -@(require_results) -_alloc_command_line_arguments :: proc() -> []string { +@(private, require_results) +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) for _, i in res { res[i] = string(runtime.args__[i]) @@ -1205,6 +1235,12 @@ _alloc_command_line_arguments :: proc() -> []string { return res } +@(private, fini) +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() + delete(args) +} + socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { result := _unix_socket(c.int(domain), c.int(type), c.int(protocol)) if result < 0 { diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 87a56b057..0542e10dc 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -662,7 +662,7 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Error) { return File_Time(modified), nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -674,7 +674,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -688,7 +688,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_fstat(fd, &s) @@ -827,10 +827,10 @@ access :: proc(path: string, mask: int) -> (bool, Error) { } @(require_results) -lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - path_str := strings.clone_to_cstring(key, context.temp_allocator) + // NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults. cstr := _unix_getenv(path_str) if cstr == nil { return "", false @@ -839,11 +839,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin } @(require_results) -get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + if len(key) + 1 > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, key) + } + + if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { + return "", .Env_Var_Not_Found + } else { + if len(value) > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, value) + return string(buf[:len(value)]), nil + } + } +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} + +@(require_results) +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} + @(require_results) get_current_directory :: proc(allocator := context.allocator) -> string { context.allocator = allocator @@ -936,11 +964,18 @@ _processor_core_count :: proc() -> int { } -@(require_results) -_alloc_command_line_arguments :: proc() -> []string { +@(private, require_results) +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) - for arg, i in runtime.args__ { - res[i] = string(arg) + for _, i in res { + res[i] = string(runtime.args__[i]) } return res } + +@(private, fini) +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() + delete(args) +} diff --git a/core/os/os_haiku.odin b/core/os/os_haiku.odin index 4a57afb87..e7c71338b 100644 --- a/core/os/os_haiku.odin +++ b/core/os/os_haiku.odin @@ -316,8 +316,9 @@ file_size :: proc(fd: Handle) -> (i64, Error) { // "Argv" arguments converted to Odin strings args := _alloc_command_line_arguments() -@(require_results) -_alloc_command_line_arguments :: proc() -> []string { +@(private, require_results) +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) for arg, i in runtime.args__ { res[i] = string(arg) @@ -325,7 +326,13 @@ _alloc_command_line_arguments :: proc() -> []string { return res } -@(private, require_results) +@(private, fini) +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() + delete(args) +} + +@(private, require_results, no_sanitize_memory) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -339,7 +346,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -353,7 +360,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { // deliberately uninitialized s: OS_Stat = --- @@ -463,9 +470,10 @@ access :: proc(path: string, mask: int) -> (bool, Error) { } @(require_results) -lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) + // NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults. cstr := _unix_getenv(path_str) if cstr == nil { return "", false @@ -474,11 +482,40 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin } @(require_results) -get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + if len(key) + 1 > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, key) + } + + if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { + return "", .Env_Var_Not_Found + } else { + if len(value) > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, value) + return string(buf[:len(value)]), nil + } + } +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} + +@(require_results) +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} + + @(private, require_results) _processor_core_count :: proc() -> int { info: haiku.system_info diff --git a/core/os/os_js.odin b/core/os/os_js.odin index 348554728..1870218d3 100644 --- a/core/os/os_js.odin +++ b/core/os/os_js.odin @@ -249,3 +249,27 @@ exit :: proc "contextless" (code: int) -> ! { current_thread_id :: proc "contextless" () -> int { return 0 } + +@(require_results) +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + return "", false +} + +@(require_results) +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + return "", .Env_Var_Not_Found +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} + +@(require_results) +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { + value, _ = lookup_env(key, allocator) + return +} + +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} \ No newline at end of file diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 2281e6a82..f0f9b401c 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -674,7 +674,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { return i64(res), nil } -@(require_results) +@(require_results, no_sanitize_memory) file_size :: proc(fd: Handle) -> (i64, Error) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- @@ -794,7 +794,7 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { return File_Time(modified), nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -808,7 +808,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -822,7 +822,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- @@ -908,7 +908,7 @@ _dup :: proc(fd: Handle) -> (Handle, Error) { @(require_results) absolute_path_from_handle :: proc(fd: Handle) -> (string, Error) { buf : [256]byte - fd_str := strconv.itoa( buf[:], cast(int)fd ) + fd_str := strconv.write_int( buf[:], cast(i64)fd, 10 ) procfs_path := strings.concatenate( []string{ "/proc/self/fd/", fd_str } ) defer delete(procfs_path) @@ -946,7 +946,7 @@ access :: proc(path: string, mask: int) -> (bool, Error) { } @(require_results) -lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) // NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults. @@ -958,11 +958,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin } @(require_results) -get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + if len(key) + 1 > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, key) + } + + if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { + return "", .Env_Var_Not_Found + } else { + if len(value) > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, value) + return string(buf[:len(value)]), nil + } + } +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} + +@(require_results) +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} + set_env :: proc(key, value: string) -> Error { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() key_cstring := strings.clone_to_cstring(key, context.temp_allocator) @@ -1069,15 +1097,22 @@ _processor_core_count :: proc() -> int { return int(_unix_get_nprocs()) } -@(require_results) -_alloc_command_line_arguments :: proc() -> []string { +@(private, require_results) +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) - for arg, i in runtime.args__ { - res[i] = string(arg) + for _, i in res { + res[i] = string(runtime.args__[i]) } return res } +@(private, fini) +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() + delete(args) +} + @(require_results) socket :: proc(domain: int, type: int, protocol: int) -> (Socket, Error) { result := unix.sys_socket(domain, type, protocol) diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index e3ba760a4..30511012f 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -724,7 +724,7 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { return File_Time(modified), nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -736,7 +736,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -750,7 +750,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { s: OS_Stat = --- result := _unix_fstat(fd, &s) @@ -874,10 +874,10 @@ access :: proc(path: string, mask: int) -> (bool, Error) { } @(require_results) -lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) - path_str := strings.clone_to_cstring(key, context.temp_allocator) + // NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults. cstr := _unix_getenv(path_str) if cstr == nil { return "", false @@ -886,11 +886,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin } @(require_results) -get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + if len(key) + 1 > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, key) + } + + if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { + return "", .Env_Var_Not_Found + } else { + if len(value) > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, value) + return string(buf[:len(value)]), nil + } + } +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} + +@(require_results) +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} + @(require_results) get_current_directory :: proc(allocator := context.allocator) -> string { context.allocator = allocator @@ -986,11 +1014,18 @@ _processor_core_count :: proc() -> int { return 1 } -@(require_results) -_alloc_command_line_arguments :: proc() -> []string { +@(private, require_results) +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) - for arg, i in runtime.args__ { - res[i] = string(arg) + for _, i in res { + res[i] = string(runtime.args__[i]) } return res } + +@(private, fini) +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() + delete(args) +} diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin index 3c377968c..50ee37dff 100644 --- a/core/os/os_openbsd.odin +++ b/core/os/os_openbsd.odin @@ -343,7 +343,7 @@ AT_REMOVEDIR :: 0x08 @(default_calling_convention="c") foreign libc { - @(link_name="__error") __error :: proc() -> ^c.int --- + @(link_name="__errno") __error :: proc() -> ^c.int --- @(link_name="fork") _unix_fork :: proc() -> pid_t --- @(link_name="getthrid") _unix_getthrid :: proc() -> int --- @@ -639,7 +639,7 @@ last_write_time_by_name :: proc(name: string) -> (time: File_Time, err: Error) { return File_Time(modified), nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _stat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -653,7 +653,7 @@ _stat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _lstat :: proc(path: string) -> (OS_Stat, Error) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) @@ -667,7 +667,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Error) { return s, nil } -@(private, require_results) +@(private, require_results, no_sanitize_memory) _fstat :: proc(fd: Handle) -> (OS_Stat, Error) { // deliberately uninitialized s: OS_Stat = --- @@ -787,9 +787,10 @@ access :: proc(path: string, mask: int) -> (bool, Error) { } @(require_results) -lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) path_str := strings.clone_to_cstring(key, context.temp_allocator) + // NOTE(tetra): Lifetime of 'cstr' is unclear, but _unix_free(cstr) segfaults. cstr := _unix_getenv(path_str) if cstr == nil { return "", false @@ -798,11 +799,39 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin } @(require_results) -get_env :: proc(key: string, allocator := context.allocator) -> (value: string) { +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + if len(key) + 1 > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, key) + } + + if value = string(_unix_getenv(cstring(raw_data(buf)))); value == "" { + return "", .Env_Var_Not_Found + } else { + if len(value) > len(buf) { + return "", .Buffer_Full + } else { + copy(buf, value) + return string(buf[:len(value)]), nil + } + } +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} + +@(require_results) +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { value, _ = lookup_env(key, allocator) return } +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} + @(require_results) get_current_directory :: proc(allocator := context.allocator) -> string { context.allocator = allocator @@ -885,11 +914,18 @@ _processor_core_count :: proc() -> int { return int(_sysconf(_SC_NPROCESSORS_ONLN)) } -@(require_results) -_alloc_command_line_arguments :: proc() -> []string { +@(private, require_results) +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() res := make([]string, len(runtime.args__)) - for arg, i in runtime.args__ { - res[i] = string(arg) + for _, i in res { + res[i] = string(runtime.args__[i]) } return res } + +@(private, fini) +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() + delete(args) +} diff --git a/core/os/os_wasi.odin b/core/os/os_wasi.odin index 28f470357..fe0a1fb3e 100644 --- a/core/os/os_wasi.odin +++ b/core/os/os_wasi.odin @@ -27,13 +27,20 @@ stderr: Handle = 2 args := _alloc_command_line_arguments() -@(require_results) -_alloc_command_line_arguments :: proc() -> (args: []string) { - args = make([]string, len(runtime.args__)) - for &arg, i in args { +@(private, require_results) +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() + cmd_args := make([]string, len(runtime.args__)) + for &arg, i in cmd_args { arg = string(runtime.args__[i]) } - return + return cmd_args +} + +@(private, fini) +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() + delete(args) } // WASI works with "preopened" directories, the environment retrieves directories @@ -52,9 +59,8 @@ Preopen :: struct { preopens: []Preopen @(init, private) -init_preopens :: proc() { - - strip_prefixes :: proc(path: string) -> string { +init_preopens :: proc "contextless" () { + strip_prefixes :: proc "contextless"(path: string) -> string { path := path loop: for len(path) > 0 { switch { @@ -71,6 +77,8 @@ init_preopens :: proc() { return path } + context = runtime.default_context() + dyn_preopens: [dynamic]Preopen loop: for fd := wasi.fd_t(3); ; fd += 1 { desc, err := wasi.fd_prestat_get(fd) @@ -239,3 +247,27 @@ exit :: proc "contextless" (code: int) -> ! { runtime._cleanup_runtime_contextless() wasi.proc_exit(wasi.exitcode_t(code)) } + +@(require_results) +lookup_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + return "", false +} + +@(require_results) +lookup_env_buffer :: proc(buf: []u8, key: string) -> (value: string, err: Error) { + return "", .Env_Var_Not_Found +} +lookup_env :: proc{lookup_env_alloc, lookup_env_buffer} + +@(require_results) +get_env_alloc :: proc(key: string, allocator := context.allocator) -> (value: string) { + value, _ = lookup_env(key, allocator) + return +} + +@(require_results) +get_env_buf :: proc(buf: []u8, key: string) -> (value: string) { + value, _ = lookup_env(buf, key) + return +} +get_env :: proc{get_env_alloc, get_env_buf} \ No newline at end of file diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index 0c532bf14..03c194596 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -193,8 +193,9 @@ current_thread_id :: proc "contextless" () -> int { -@(require_results) -_alloc_command_line_arguments :: proc() -> []string { +@(private, require_results) +_alloc_command_line_arguments :: proc "contextless" () -> []string { + context = runtime.default_context() arg_count: i32 arg_list_ptr := win32.CommandLineToArgvW(win32.GetCommandLineW(), &arg_count) arg_list := make([]string, int(arg_count)) @@ -215,6 +216,15 @@ _alloc_command_line_arguments :: proc() -> []string { return arg_list } +@(private, fini) +_delete_command_line_arguments :: proc "contextless" () { + context = runtime.default_context() + for s in args { + delete(s) + } + delete(args) +} + /* Windows 11 (preview) has the same major and minor version numbers as Windows 10: 10 and 0 respectively. diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index ca4f87668..662c9f9e6 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -17,7 +17,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa buf := make([dynamic]u16, 100) defer delete(buf) for { - n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) + n := win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil) if n == 0 { return "", get_last_error() } @@ -154,7 +154,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle, allocator: runtime.Allocator) -> ( return nil, get_last_error() } buf := make([]u16, max(n, win32.DWORD(260))+1, allocator) - buf_len := win32.GetFinalPathNameByHandleW(h, raw_data(buf), n, 0) + buf_len := win32.GetFinalPathNameByHandleW(h, cstring16(raw_data(buf)), n, 0) return buf[:buf_len], nil } @(private, require_results) diff --git a/core/path/filepath/match.odin b/core/path/filepath/match.odin index 1f0ac9287..3eaa7c6fe 100644 --- a/core/path/filepath/match.odin +++ b/core/path/filepath/match.odin @@ -1,4 +1,5 @@ #+build !wasi +#+build !js package filepath import "core:os" diff --git a/core/path/filepath/path_js.odin b/core/path/filepath/path_js.odin new file mode 100644 index 000000000..3b5ac04f5 --- /dev/null +++ b/core/path/filepath/path_js.odin @@ -0,0 +1,36 @@ +package filepath + +import "base:runtime" + +import "core:strings" + +SEPARATOR :: '/' +SEPARATOR_STRING :: `/` +LIST_SEPARATOR :: ':' + +is_reserved_name :: proc(path: string) -> bool { + return false +} + +is_abs :: proc(path: string) -> bool { + return strings.has_prefix(path, "/") +} + +abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { + if is_abs(path) { + return strings.clone(string(path), allocator), true + } + + return path, false +} + +join :: proc(elems: []string, allocator := context.allocator) -> (joined: string, err: runtime.Allocator_Error) #optional_allocator_error { + for e, i in elems { + if e != "" { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator) + p := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) or_return + return clean(p, allocator) + } + } + return "", nil +} \ No newline at end of file diff --git a/core/path/filepath/path_windows.odin b/core/path/filepath/path_windows.odin index 0dcb28cf8..b3f4eee9e 100644 --- a/core/path/filepath/path_windows.odin +++ b/core/path/filepath/path_windows.odin @@ -32,7 +32,6 @@ is_UNC :: proc(path: string) -> bool { return volume_name_len(path) > 2 } - is_abs :: proc(path: string) -> bool { if is_reserved_name(path) { return true @@ -50,7 +49,6 @@ is_abs :: proc(path: string) -> bool { return is_slash(path[0]) } - @(private) temp_full_path :: proc(name: string) -> (path: string, err: os.Error) { ta := context.temp_allocator @@ -61,13 +59,13 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) { } p := win32.utf8_to_utf16(name, ta) - n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil) + n := win32.GetFullPathNameW(cstring16(raw_data(p)), 0, nil, nil) if n == 0 { return "", os.get_last_error() } buf := make([]u16, n, ta) - n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil) + n = win32.GetFullPathNameW(cstring16(raw_data(p)), u32(len(buf)), cstring16(raw_data(buf)), nil) if n == 0 { delete(buf) return "", os.get_last_error() @@ -76,8 +74,6 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) { return win32.utf16_to_utf8(buf[:n], ta) } - - abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator) full_path, err := temp_full_path(path) @@ -88,17 +84,16 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { return p, true } - -join :: proc(elems: []string, allocator := context.allocator) -> string { +join :: proc(elems: []string, allocator := context.allocator) -> (string, runtime.Allocator_Error) #optional_allocator_error { for e, i in elems { if e != "" { return join_non_empty(elems[i:], allocator) } } - return "" + return "", nil } -join_non_empty :: proc(elems: []string, allocator := context.allocator) -> string { +join_non_empty :: proc(elems: []string, allocator := context.allocator) -> (joined: string, err: runtime.Allocator_Error) { context.allocator = allocator runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator) @@ -110,23 +105,25 @@ join_non_empty :: proc(elems: []string, allocator := context.allocator) -> strin break } } - s := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) - s = strings.concatenate({elems[0], s}, context.temp_allocator) + s := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) or_return + s = strings.concatenate({elems[0], s}, context.temp_allocator) or_return return clean(s) } - p := clean(strings.join(elems, SEPARATOR_STRING, context.temp_allocator)) + p := strings.join(elems, SEPARATOR_STRING, context.temp_allocator) or_return + p = clean(p) or_return if !is_UNC(p) { - return p + return p, nil } - - head := clean(elems[0], context.temp_allocator) + + head := clean(elems[0], context.temp_allocator) or_return if is_UNC(head) { - return p + return p, nil } delete(p) // It is not needed now - tail := clean(strings.join(elems[1:], SEPARATOR_STRING, context.temp_allocator), context.temp_allocator) + tail := strings.join(elems[1:], SEPARATOR_STRING, context.temp_allocator) or_return + tail = clean(tail, context.temp_allocator) or_return if head[len(head)-1] == SEPARATOR { return strings.concatenate({head, tail}) } diff --git a/core/path/filepath/walk.odin b/core/path/filepath/walk.odin index 53b10eed7..05d67daf0 100644 --- a/core/path/filepath/walk.odin +++ b/core/path/filepath/walk.odin @@ -1,4 +1,5 @@ #+build !wasi +#+build !js package filepath import "core:os" diff --git a/core/prof/spall/spall.odin b/core/prof/spall/spall.odin index 12f082b2c..dc53dc3dc 100644 --- a/core/prof/spall/spall.odin +++ b/core/prof/spall/spall.odin @@ -8,29 +8,36 @@ import "base:intrinsics" MANUAL_MAGIC :: u64le(0x0BADF00D) -Manual_Header :: struct #packed { +Manual_Stream_Header :: struct #packed { magic: u64le, version: u64le, timestamp_scale: f64le, reserved: u64le, } +Manual_Buffer_Header :: struct #packed { + size: u32le, + tid: u32le, + pid: u32le, + first_ts: u64le, +} + Manual_Event_Type :: enum u8 { - Invalid = 0, + Invalid = 0, - Begin = 3, - End = 4, - Instant = 5, + Begin = 3, + End = 4, + Instant = 5, - Pad_Skip = 7, + Pad_Skip = 7, + + Name_Process = 8, + Name_Thread = 9, } Begin_Event :: struct #packed { type: Manual_Event_Type, - category: u8, - pid: u32le, - tid: u32le, - ts: f64le, + ts: u64le, name_len: u8, args_len: u8, } @@ -38,9 +45,7 @@ BEGIN_EVENT_MAX :: size_of(Begin_Event) + 255 + 255 End_Event :: struct #packed { type: Manual_Event_Type, - pid: u32le, - tid: u32le, - ts: f64le, + ts: u64le, } Pad_Skip :: struct #packed { @@ -48,6 +53,12 @@ Pad_Skip :: struct #packed { size: u32le, } +Name_Event :: struct #packed { + type: Manual_Event_Type, + name_len: u8, +} +NAME_EVENT_MAX :: size_of(Name_Event) + 255 + // User Interface Context :: struct { @@ -61,6 +72,7 @@ Buffer :: struct { head: int, tid: u32, pid: u32, + first_ts: u64, } BUFFER_DEFAULT_SIZE :: 0x10_0000 @@ -76,8 +88,8 @@ context_create_with_scale :: proc(filename: string, precise_time: bool, timestam ctx.precise_time = precise_time ctx.timestamp_scale = timestamp_scale - temp := [size_of(Manual_Header)]u8{} - _build_header(temp[:], ctx.timestamp_scale) + temp := [size_of(Manual_Stream_Header)]u8{} + _build_stream_header(temp[:], ctx.timestamp_scale) os.write(ctx.fd, temp[:]) ok = true return @@ -85,12 +97,13 @@ context_create_with_scale :: proc(filename: string, precise_time: bool, timestam context_create_with_sleep :: proc(filename: string, sleep := 2 * time.Second) -> (ctx: Context, ok: bool) #optional_ok { freq, freq_ok := time.tsc_frequency(sleep) - timestamp_scale: f64 = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1 + timestamp_scale: f64 = ((1 / f64(freq)) * 1_000_000_000) if freq_ok else 1 return context_create_with_scale(filename, freq_ok, timestamp_scale) } context_create :: proc{context_create_with_scale, context_create_with_sleep} +@(no_instrumentation) context_destroy :: proc(ctx: ^Context) { if ctx == nil { return @@ -102,25 +115,39 @@ context_destroy :: proc(ctx: ^Context) { buffer_create :: proc(data: []byte, tid: u32 = 0, pid: u32 = 0) -> (buffer: Buffer, ok: bool) #optional_ok { assert(len(data) >= 1024) - buffer.data = data - buffer.tid = tid - buffer.pid = pid - buffer.head = 0 + buffer.data = data + buffer.tid = tid + buffer.pid = pid + buffer.first_ts = 0 + buffer.head = size_of(Manual_Buffer_Header) ok = true return } @(no_instrumentation) buffer_flush :: proc "contextless" (ctx: ^Context, buffer: ^Buffer) #no_bounds_check /* bounds check would segfault instrumentation */ { + if len(buffer.data) == 0 { + return + } + + buffer_size := buffer.head - size_of(Manual_Buffer_Header) + hdr := (^Manual_Buffer_Header)(raw_data(buffer.data)) + hdr.size = u32le(buffer_size) + hdr.pid = u32le(buffer.pid) + hdr.tid = u32le(buffer.tid) + hdr.first_ts = u64le(buffer.first_ts) + start := _trace_now(ctx) write(ctx.fd, buffer.data[:buffer.head]) - buffer.head = 0 + buffer.head = size_of(Manual_Buffer_Header) end := _trace_now(ctx) - buffer.head += _build_begin(buffer.data[buffer.head:], "Spall Trace Buffer Flush", "", start, buffer.tid, buffer.pid) - buffer.head += _build_end(buffer.data[buffer.head:], end, buffer.tid, buffer.pid) + buffer.head += _build_begin(buffer.data[buffer.head:], "Spall Trace Buffer Flush", "", start) + buffer.head += _build_end(buffer.data[buffer.head:], end) + buffer.first_ts = end } +@(no_instrumentation) buffer_destroy :: proc(ctx: ^Context, buffer: ^Buffer) { buffer_flush(ctx, buffer) @@ -130,35 +157,37 @@ buffer_destroy :: proc(ctx: ^Context, buffer: ^Buffer) { @(deferred_in=_scoped_buffer_end) +@(no_instrumentation) SCOPED_EVENT :: proc(ctx: ^Context, buffer: ^Buffer, name: string, args: string = "", location := #caller_location) -> bool { _buffer_begin(ctx, buffer, name, args, location) return true } @(private) +@(no_instrumentation) _scoped_buffer_end :: proc(ctx: ^Context, buffer: ^Buffer, _, _: string, _ := #caller_location) { _buffer_end(ctx, buffer) } @(no_instrumentation) -_trace_now :: proc "contextless" (ctx: ^Context) -> f64 { +_trace_now :: proc "contextless" (ctx: ^Context) -> u64 { if !ctx.precise_time { - return f64(tick_now()) / 1_000 + return u64(tick_now()) } - return f64(intrinsics.read_cycle_counter()) + return u64(intrinsics.read_cycle_counter()) } @(no_instrumentation) -_build_header :: proc "contextless" (buffer: []u8, timestamp_scale: f64) -> (header_size: int, ok: bool) #optional_ok { - header_size = size_of(Manual_Header) +_build_stream_header :: proc "contextless" (buffer: []u8, timestamp_scale: f64) -> (header_size: int, ok: bool) #optional_ok { + header_size = size_of(Manual_Stream_Header) if header_size > len(buffer) { return 0, false } - hdr := (^Manual_Header)(raw_data(buffer)) + hdr := (^Manual_Stream_Header)(raw_data(buffer)) hdr.magic = MANUAL_MAGIC - hdr.version = 1 + hdr.version = 3 hdr.timestamp_scale = f64le(timestamp_scale) hdr.reserved = 0 ok = true @@ -166,7 +195,7 @@ _build_header :: proc "contextless" (buffer: []u8, timestamp_scale: f64) -> (hea } @(no_instrumentation) -_build_begin :: #force_inline proc "contextless" (buffer: []u8, name: string, args: string, ts: f64, tid: u32, pid: u32) -> (event_size: int, ok: bool) #optional_ok #no_bounds_check /* bounds check would segfault instrumentation */ { +_build_begin :: #force_inline proc "contextless" (buffer: []u8, name: string, args: string, ts: u64) -> (event_size: int, ok: bool) #optional_ok #no_bounds_check /* bounds check would segfault instrumentation */ { ev := (^Begin_Event)(raw_data(buffer)) name_len := min(len(name), 255) args_len := min(len(args), 255) @@ -177,9 +206,7 @@ _build_begin :: #force_inline proc "contextless" (buffer: []u8, name: string, ar } ev.type = .Begin - ev.pid = u32le(pid) - ev.tid = u32le(tid) - ev.ts = f64le(ts) + ev.ts = u64le(ts) ev.name_len = u8(name_len) ev.args_len = u8(args_len) intrinsics.mem_copy_non_overlapping(raw_data(buffer[size_of(Begin_Event):]), raw_data(name), name_len) @@ -190,7 +217,7 @@ _build_begin :: #force_inline proc "contextless" (buffer: []u8, name: string, ar } @(no_instrumentation) -_build_end :: proc "contextless" (buffer: []u8, ts: f64, tid: u32, pid: u32) -> (event_size: int, ok: bool) #optional_ok { +_build_end :: proc "contextless" (buffer: []u8, ts: u64) -> (event_size: int, ok: bool) #optional_ok { ev := (^End_Event)(raw_data(buffer)) event_size = size_of(End_Event) if event_size > len(buffer) { @@ -198,9 +225,28 @@ _build_end :: proc "contextless" (buffer: []u8, ts: f64, tid: u32, pid: u32) -> } ev.type = .End - ev.pid = u32le(pid) - ev.tid = u32le(tid) - ev.ts = f64le(ts) + ev.ts = u64le(ts) + ok = true + + return +} + +@(no_instrumentation) +_build_name_event :: #force_inline proc "contextless" (buffer: []u8, name: string, type: Manual_Event_Type) -> (event_size: int, ok: bool) #optional_ok #no_bounds_check /* bounds check would segfault instrumentation */ { + ev := (^Name_Event)(raw_data(buffer)) + name_len := min(len(name), 255) + + event_size = size_of(Name_Event) + name_len + if event_size > len(buffer) { + return 0, false + } + if type != .Name_Process && type != .Name_Thread { + return 0, false + } + + ev.type = type + ev.name_len = u8(name_len) + intrinsics.mem_copy_non_overlapping(raw_data(buffer[size_of(Name_Event):]), raw_data(name), name_len) ok = true return @@ -212,7 +258,7 @@ _buffer_begin :: proc "contextless" (ctx: ^Context, buffer: ^Buffer, name: strin buffer_flush(ctx, buffer) } name := location.procedure if name == "" else name - buffer.head += _build_begin(buffer.data[buffer.head:], name, args, _trace_now(ctx), buffer.tid, buffer.pid) + buffer.head += _build_begin(buffer.data[buffer.head:], name, args, _trace_now(ctx)) } @(no_instrumentation) @@ -223,7 +269,23 @@ _buffer_end :: proc "contextless" (ctx: ^Context, buffer: ^Buffer) #no_bounds_ch buffer_flush(ctx, buffer) } - buffer.head += _build_end(buffer.data[buffer.head:], ts, buffer.tid, buffer.pid) + buffer.head += _build_end(buffer.data[buffer.head:], ts) +} + +@(no_instrumentation) +_buffer_name_thread :: proc "contextless" (ctx: ^Context, buffer: ^Buffer, name: string, location := #caller_location) #no_bounds_check /* bounds check would segfault instrumentation */ { + if buffer.head + NAME_EVENT_MAX > len(buffer.data) { + buffer_flush(ctx, buffer) + } + buffer.head += _build_name_event(buffer.data[buffer.head:], name, .Name_Thread) +} + +@(no_instrumentation) +_buffer_name_process :: proc "contextless" (ctx: ^Context, buffer: ^Buffer, name: string, location := #caller_location) #no_bounds_check /* bounds check would segfault instrumentation */ { + if buffer.head + NAME_EVENT_MAX > len(buffer.data) { + buffer_flush(ctx, buffer) + } + buffer.head += _build_name_event(buffer.data[buffer.head:], name, .Name_Process) } @(no_instrumentation) diff --git a/core/reflect/reflect.odin b/core/reflect/reflect.odin index 7f79acb77..b3315a0c3 100644 --- a/core/reflect/reflect.odin +++ b/core/reflect/reflect.odin @@ -24,7 +24,6 @@ Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array Type_Info_Dynamic_Array :: runtime.Type_Info_Dynamic_Array Type_Info_Slice :: runtime.Type_Info_Slice Type_Info_Parameters :: runtime.Type_Info_Parameters -Type_Info_Tuple :: runtime.Type_Info_Parameters Type_Info_Struct :: runtime.Type_Info_Struct Type_Info_Union :: runtime.Type_Info_Union Type_Info_Enum :: runtime.Type_Info_Enum @@ -58,7 +57,7 @@ Type_Kind :: enum { Enumerated_Array, Dynamic_Array, Slice, - Tuple, + Parameters, Struct, Union, Enum, @@ -93,7 +92,7 @@ type_kind :: proc(T: typeid) -> Type_Kind { case Type_Info_Enumerated_Array: return .Enumerated_Array case Type_Info_Dynamic_Array: return .Dynamic_Array case Type_Info_Slice: return .Slice - case Type_Info_Parameters: return .Tuple + case Type_Info_Parameters: return .Parameters case Type_Info_Struct: return .Struct case Type_Info_Union: return .Union case Type_Info_Enum: return .Enum @@ -176,6 +175,7 @@ typeid_elem :: proc(id: typeid) -> typeid { case Type_Info_Enumerated_Array: return v.elem.id case Type_Info_Slice: return v.elem.id case Type_Info_Dynamic_Array: return v.elem.id + case Type_Info_Simd_Vector: return v.elem.id } return id } @@ -260,7 +260,11 @@ length :: proc(val: any) -> int { } else { return (^runtime.Raw_String)(val.data).len } + + case Type_Info_Simd_Vector: + return a.count } + return 0 } @@ -286,7 +290,11 @@ capacity :: proc(val: any) -> int { case Type_Info_Map: return runtime.map_cap((^runtime.Raw_Map)(val.data)^) + + case Type_Info_Simd_Vector: + return a.count } + return 0 } @@ -1431,6 +1439,11 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) { case Type_Info_Complex: switch v in a { + case complex32: + if imag(v) == 0 { + value = f64(real(v)) + valid = true + } case complex64: if imag(v) == 0 { value = f64(real(v)) @@ -1445,6 +1458,11 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) { case Type_Info_Quaternion: switch v in a { + case quaternion64: + if imag(v) == 0 && jmag(v) == 0 && kmag(v) == 0 { + value = f64(real(v)) + valid = true + } case quaternion128: if imag(v) == 0 && jmag(v) == 0 && kmag(v) == 0 { value = f64(real(v)) @@ -1638,13 +1656,40 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_ return equal(va, vb, including_indirect_array_recursion, recursion_level+1) case Type_Info_Map: return false + case Type_Info_Float: + x, _ := as_f64(a) + y, _ := as_f64(b) + return x == y + case Type_Info_Complex: + switch x in a { + case complex32: + #no_type_assert y := b.(complex32) + return x == y + case complex64: + #no_type_assert y := b.(complex64) + return x == y + case complex128: + #no_type_assert y := b.(complex128) + return x == y + } + return false + case Type_Info_Quaternion: + switch x in a { + case quaternion64: + #no_type_assert y := b.(quaternion64) + return x == y + case quaternion128: + #no_type_assert y := b.(quaternion128) + return x == y + case quaternion256: + #no_type_assert y := b.(quaternion256) + return x == y + } + return false case Type_Info_Boolean, Type_Info_Integer, Type_Info_Rune, - Type_Info_Float, - Type_Info_Complex, - Type_Info_Quaternion, Type_Info_Type_Id, Type_Info_Pointer, Type_Info_Multi_Pointer, diff --git a/core/reflect/types.odin b/core/reflect/types.odin index cb31a27e2..98b7b368f 100644 --- a/core/reflect/types.odin +++ b/core/reflect/types.odin @@ -348,12 +348,6 @@ is_parameters :: proc(info: ^Type_Info) -> bool { _, ok := type_info_base(info).variant.(Type_Info_Parameters) return ok } -@(require_results, deprecated="prefer is_parameters") -is_tuple :: proc(info: ^Type_Info) -> bool { - if info == nil { return false } - _, ok := type_info_base(info).variant.(Type_Info_Parameters) - return ok -} @(require_results) is_struct :: proc(info: ^Type_Info) -> bool { if info == nil { return false } @@ -517,9 +511,12 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt io.write_i64(w, i64(8*ti.size), 10, &n) or_return case Type_Info_String: if info.is_cstring { - io.write_string(w, "cstring", &n) or_return - } else { - io.write_string(w, "string", &n) or_return + io.write_byte(w, 'c', &n) or_return + } + io.write_string(w, "string", &n) or_return + switch info.encoding { + case .UTF_8: /**/ + case .UTF_16: io.write_string(w, "16", &n) or_return } case Type_Info_Boolean: switch ti.id { @@ -636,7 +633,7 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt io.write_string(w, "struct ", &n) or_return if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return } if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return } - if .no_copy in info.flags { io.write_string(w, "#no_copy ", &n) or_return } + // if .no_copy in info.flags { io.write_string(w, "#no_copy ", &n) or_return } if .align in info.flags { io.write_string(w, "#align(", &n) or_return io.write_i64(w, i64(ti.align), 10, &n) or_return diff --git a/core/simd/simd.odin b/core/simd/simd.odin index 0bce4e16a..303eceb97 100644 --- a/core/simd/simd.odin +++ b/core/simd/simd.odin @@ -21,20 +21,17 @@ package simd import "base:builtin" import "base:intrinsics" +import "base:runtime" /* Check if SIMD is software-emulated on a target platform. -This value is `false`, when the compile-time target has the hardware support for -at 128-bit (or wider) SIMD. If the compile-time target lacks the hardware support -for 128-bit SIMD, this value is `true`, and all SIMD operations will likely be +This value is `true`, when the compile-time target has the hardware support for +at least 128-bit (or wider) SIMD. If the compile-time target lacks the hardware support +for 128-bit SIMD, this value is `false`, and all SIMD operations will likely be emulated. */ -IS_EMULATED :: true when (ODIN_ARCH == .amd64 || ODIN_ARCH == .i386) && !intrinsics.has_target_feature("sse2") else - true when (ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32) && !intrinsics.has_target_feature("neon") else - true when (ODIN_ARCH == .wasm64p32 || ODIN_ARCH == .wasm32) && !intrinsics.has_target_feature("simd128") else - true when (ODIN_ARCH == .riscv64) && !intrinsics.has_target_feature("v") else - false +HAS_HARDWARE_SIMD :: runtime.HAS_HARDWARE_SIMD /* Vector of 16 `u8` lanes (128 bits). @@ -1328,13 +1325,18 @@ Example: // to load valid positions of the `ptrs` array, and the array of defaults which // will have `127` in each position as the default value. - v1 := [4] f32 {1, 2, 3, 4}; - v2 := [4] f32 {9, 10,11,12}; - ptrs := #simd [4]rawptr { &v1[1], nil, &v2[1], nil } - mask := #simd [4]bool { true, false, true, false } - defaults := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } - res := simd.gather(ptrs, defaults, mask) - fmt.println(res) + import "core:fmt" + import "core:simd" + + simd_gather_example :: proc() { + v1 := [4] f32 {1, 2, 3, 4}; + v2 := [4] f32 {9, 10,11,12}; + ptrs := #simd [4]rawptr { &v1[1], nil, &v2[1], nil } + mask := #simd [4]bool { true, false, true, false } + defaults := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } + res := simd.gather(ptrs, defaults, mask) + fmt.println(res) + } Output: @@ -1396,14 +1398,19 @@ Example: // vectors. The addresses of store destinations are written to the first and the // third argument of the `ptr` vector, and the `mask` is set accordingly. - v1 := [4] f32 {1, 2, 3, 4}; - v2 := [4] f32 {5, 6, 7, 8}; - ptrs := #simd [4]rawptr { &v1[1], nil, &v2[1], nil } - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } - simd.scatter(ptrs, vals, mask) - fmt.println(v1) - fmt.println(v2) + import "core:fmt" + import "core:simd" + + simd_scatter_example :: proc() { + v1 := [4] f32 {1, 2, 3, 4}; + v2 := [4] f32 {5, 6, 7, 8}; + ptrs := #simd [4]rawptr { &v1[1], nil, &v2[1], nil } + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } + simd.scatter(ptrs, vals, mask) + fmt.println(v1) + fmt.println(v2) + } Output: @@ -1467,11 +1474,16 @@ Example: // third value (selected by the mask). The masked-off values are given the value // of 127 (`0x7f`). - src := [4] f32 {1, 2, 3, 4}; - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } - res := simd.masked_load(&src, vals, mask) - fmt.println(res) + import "core:fmt" + import "core:simd" + + simd_masked_load_example :: proc() { + src := [4] f32 {1, 2, 3, 4}; + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } + res := simd.masked_load(&src, vals, mask) + fmt.println(res) + } Output: @@ -1526,11 +1538,16 @@ Example: // Example below stores the value 127 into the first and the third slot of the // vector `v`. - v := [4] f32 {1, 2, 3, 4}; - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } - simd.masked_store(&v, vals, mask) - fmt.println(v) + import "core:fmt" + import "core:simd" + + simd_masked_store_example :: proc() { + v := [4] f32 {1, 2, 3, 4}; + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f32 { 0x7f, 0x7f, 0x7f, 0x7f } + simd.masked_store(&v, vals, mask) + fmt.println(v) + } Output: @@ -1600,11 +1617,16 @@ Example: // the third lane of the result vector. All the other lanes of the result vector // will be initialized to the default value `127`. - v := [2] f64 {1, 2}; - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f64 { 0x7f, 0x7f, 0x7f, 0x7f } - res := simd.masked_expand_load(&v, vals, mask) - fmt.println(res) + import "core:fmt" + import "core:simd" + + simd_masked_expand_load_example :: proc() { + v := [2] f64 {1, 2}; + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f64 { 0x7f, 0x7f, 0x7f, 0x7f } + res := simd.masked_expand_load(&v, vals, mask) + fmt.println(res) + } Output: @@ -1661,11 +1683,16 @@ Example: // vector, the first and the third value. The items in the mask are set to `true` // in those lanes. - v := [2] f64 { }; - mask := #simd [4]bool { true, false, true, false } - vals := #simd [4]f64 { 1, 2, 3, 4 } - simd.masked_compress_store(&v, vals, mask) - fmt.println(v) + import "core:fmt" + import "core:simd" + + simd_masked_compress_store_example :: proc() { + v := [2] f64 { }; + mask := #simd [4]bool { true, false, true, false } + vals := #simd [4]f64 { 1, 2, 3, 4 } + simd.masked_compress_store(&v, vals, mask) + fmt.println(v) + } Output: @@ -1729,7 +1756,103 @@ Returns: replace :: intrinsics.simd_replace /* -Reduce a vector to a scalar by adding up all the lanes. +Reduce a vector to a scalar by adding up all the lanes in a bisecting fashion. + +This procedure returns a scalar that is the sum of all lanes, calculated by +bisecting the vector into two parts, where the first contains lanes [0, N/2) +and the second contains lanes [N/2, N), and adding the two halves element-wise +to produce N/2 values. This is repeated until only a single element remains. +This order may be faster to compute than the ordered sum for floats, as it can +often be better parallelized. + +The order of the sum may be important for accounting for precision errors in +floating-point computation, as floating-point addition is not associative, that +is `(a+b)+c` may not be equal to `a+(b+c)`. + +Inputs: +- `v`: The vector to reduce. + +Result: +- Sum of all lanes, as a scalar. + +**Operation**: + + for n > 1 { + n = n / 2 + for i in 0 ..< n { + a[i] += a[i+n] + } + } + res := a[0] + +Graphical representation of the operation for N=4: + + +-----------------------+ + | v0 | v1 | v2 | v3 | + +-----------------------+ + | | | | + [+]<-- | ---' | + | [+]<--------' + | | + `>[+]<' + | + v + +-----+ + result: | y0 | + +-----+ +*/ +reduce_add_bisect :: intrinsics.simd_reduce_add_bisect + +/* +Reduce a vector to a scalar by multiplying up all the lanes in a bisecting fashion. + +This procedure returns a scalar that is the product of all lanes, calculated by +bisecting the vector into two parts, where the first contains indices [0, N/2) +and the second contains indices [N/2, N), and multiplying the two halves +together element-wise to produce N/2 values. This is repeated until only a +single element remains. This order may be faster to compute than the ordered +product for floats, as it can often be better parallelized. + +The order of the product may be important for accounting for precision errors +in floating-point computation, as floating-point multiplication is not +associative, that is `(a*b)*c` may not be equal to `a*(b*c)`. + +Inputs: +- `v`: The vector to reduce. + +Result: +- Product of all lanes, as a scalar. + +**Operation**: + + for n > 1 { + n = n / 2 + for i in 0 ..< n { + a[i] *= a[i+n] + } + } + res := a[0] + +Graphical representation of the operation for N=4: + + +-----------------------+ + | v0 | v1 | v2 | v3 | + +-----------------------+ + | | | | + [x]<-- | ---' | + | [x]<--------' + | | + `>[x]<' + | + v + +-----+ + result: | y0 | + +-----+ +*/ +reduce_mul_bisect :: intrinsics.simd_reduce_mul_bisect + +/* +Reduce a vector to a scalar by adding up all the lanes in an ordered fashion. This procedure returns a scalar that is the ordered sum of all lanes. The ordered sum may be important for accounting for precision errors in @@ -1752,7 +1875,7 @@ Result: reduce_add_ordered :: intrinsics.simd_reduce_add_ordered /* -Reduce a vector to a scalar by multiplying all the lanes. +Reduce a vector to a scalar by multiplying all the lanes in an ordered fashion. This procedure returns a scalar that is the ordered product of all lanes. The ordered product may be important for accounting for precision errors in @@ -1774,6 +1897,100 @@ Result: */ reduce_mul_ordered :: intrinsics.simd_reduce_mul_ordered +/* +Reduce a vector to a scalar by adding up all the lanes in a pairwise fashion. + +This procedure returns a scalar that is the sum of all lanes, calculated by +adding each even-indexed element with the following odd-indexed element to +produce N/2 values. This is repeated until only a single element remains. This +order is supported by hardware instructions for some types/architectures (e.g. +i16/i32/f32/f64 on x86 SSE, i8/i16/i32/f32 on ARM NEON). + +The order of the sum may be important for accounting for precision errors in +floating-point computation, as floating-point addition is not associative, that +is `(a+b)+c` may not be equal to `a+(b+c)`. + +Inputs: +- `v`: The vector to reduce. + +Result: +- Sum of all lanes, as a scalar. + +**Operation**: + + for n > 1 { + n = n / 2 + for i in 0 ..< n { + a[i] = a[2*i+0] + a[2*i+1] + } + } + res := a[0] + +Graphical representation of the operation for N=4: + + +-----------------------+ + v: | v0 | v1 | v2 | v3 | + +-----------------------+ + | | | | + `>[+]<' `>[+]<' + | | + `--->[+]<--' + | + v + +-----+ + result: | y0 | + +-----+ +*/ +reduce_add_pairs :: intrinsics.simd_reduce_add_pairs + +/* +Reduce a vector to a scalar by multiplying all the lanes in a pairwise fashion. + +This procedure returns a scalar that is the product of all lanes, calculated by +bisecting the vector into two parts, where the first contains lanes [0, N/2) +and the second contains lanes [N/2, N), and multiplying the two halves together +multiplying each even-indexed element with the following odd-indexed element to +produce N/2 values. This is repeated until only a single element remains. This +order may be faster to compute than the ordered product for floats, as it can +often be better parallelized. + +The order of the product may be important for accounting for precision errors +in floating-point computation, as floating-point multiplication is not +associative, that is `(a*b)*c` may not be equal to `a*(b*c)`. + +Inputs: +- `v`: The vector to reduce. + +Result: +- Product of all lanes, as a scalar. + +**Operation**: + + for n > 1 { + n = n / 2 + for i in 0 ..< n { + a[i] = a[2*i+0] * a[2*i+1] + } + } + res := a[0] + +Graphical representation of the operation for N=4: + + +-----------------------+ + v: | v0 | v1 | v2 | v3 | + +-----------------------+ + | | | | + `>[x]<' `>[x]<' + | | + `--->[x]<--' + | + v + +-----+ + result: | y0 | + +-----+ +*/ +reduce_mul_pairs :: intrinsics.simd_reduce_mul_pairs + /* Reduce a vector to a scalar by finding the minimum value between all of the lanes. @@ -1949,14 +2166,19 @@ Example: // The example below shows how the indices are used to determine which lanes of the // input vector get written into the result vector. - - x := #simd [4]f32 { 1.5, 2.5, 3.5, 4.5 } - res := simd.swizzle(x, 0, 3, 1, 1) - fmt.println("res") + + import "core:fmt" + import "core:simd" + + swizzle_example :: proc() { + x := #simd [4]f32 { 1.5, 2.5, 3.5, 4.5 } + res := simd.swizzle(x, 0, 3, 1, 1) + fmt.println(res) + } Output: - [ 1.5, 3.5, 2.5, 2.5 ] + <1.5, 4.5, 2.5, 2.5> The graphical representation of the operation is as follows. The `idx` vector in the picture represents the `indices` parameter: @@ -2013,8 +2235,14 @@ Example: // Since lanes 0, 1, 4, 7 contain negative numbers, the most significant // bits for them will be set. - v := #simd [8]i32 { -1, -2, +3, +4, -5, +6, +7, -8 } - fmt.println(simd.extract_msbs(v)) + + import "core:fmt" + import "core:simd" + + simd_extract_msbs_example :: proc() { + v := #simd [8]i32 { -1, -2, +3, +4, -5, +6, +7, -8 } + fmt.println(simd.extract_msbs(v)) + } Output: @@ -2052,8 +2280,14 @@ Example: // Since lanes 0, 2, 4, 6 contain odd integers, the least significant bits // for these lanes are set. - v := #simd [8]i32 { -1, -2, +3, +4, -5, +6, +7, -8 } - fmt.println(simd.extract_lsbs(v)) + + import "core:fmt" + import "core:simd" + + simd_extract_lsbs_example :: proc() { + v := #simd [8]i32 { -1, -2, +3, +4, -5, +6, +7, -8 } + fmt.println(simd.extract_lsbs(v)) + } Output: @@ -2097,15 +2331,20 @@ Example: // The example below shows how the indices are used to determine lanes of the // input vector that are shuffled into the result vector. - - a := #simd [4]f32 { 1, 2, 3, 4 } - b := #simd [4]f32 { 5, 6, 7, 8 } - res := simd.shuffle(a, b, 0, 4, 2, 5) - fmt.println("res") + + import "core:fmt" + import "core:simd" + + simd_shuffle_example :: proc() { + a := #simd [4]f32 { 1, 2, 3, 4 } + b := #simd [4]f32 { 5, 6, 7, 8 } + res := simd.shuffle(a, b, 0, 4, 2, 5) + fmt.println(res) + } Output: - [ 1, 5, 3, 6 ] + <1, 5, 3, 6> The graphical representation of the operation is as follows. The `idx` vector in the picture represents the `indices` parameter: @@ -2163,14 +2402,20 @@ Example: // The following example selects values from the two input vectors, `a` and `b` // into a single vector. - a := #simd [4] f64 { 1,2,3,4 } - b := #simd [4] f64 { 5,6,7,8 } - cond := #simd[4] int { 1, 0, 1, 0 } - fmt.println(simd.select(cond,a,b)) + + import "core:fmt" + import "core:simd" + + simd_select_example :: proc() { + a := #simd [4] f64 { 1,2,3,4 } + b := #simd [4] f64 { 5,6,7,8 } + cond := #simd[4] int { 1, 0, 1, 0 } + fmt.println(simd.select(cond,a,b)) + } Output: - [ 1, 6, 3, 8 ] + <1, 6, 3, 8> Graphically, the operation looks as follows. The `t` and `f` represent the `true` and `false` vectors respectively: @@ -2195,6 +2440,57 @@ Graphically, the operation looks as follows. The `t` and `f` represent the */ select :: intrinsics.simd_select +/* +Runtime Equivalent to Shuffle. + +Performs element-wise table lookups using runtime indices. +Each element in the indices vector selects an element from the table vector. +The indices are automatically masked to prevent out-of-bounds access. + +This operation is hardware-accelerated on most platforms when using 8-bit +integer vectors. For other element types or unsupported vector sizes, it +falls back to software emulation. + +Inputs: +- `table`: The lookup table vector (should be power-of-2 size for correct masking). +- `indices`: The indices vector (automatically masked to valid range). + +Returns: +- A vector where `result[i] = table[indices[i] & (table_size-1)]`. + +Operation: + + for i in 0 ..< len(indices) { + masked_index := indices[i] & (len(table) - 1) + result[i] = table[masked_index] + } + return result + +Implementation: + + | Platform | Lane Size | Implementation | + |-------------|-------------------------------------------|---------------------| + | x86-64 | pshufb (16B), vpshufb (32B), AVX512 (64B) | Single vector | + | ARM64 | tbl1 (16B), tbl2 (32B), tbl4 (64B) | Automatic splitting | + | ARM32 | vtbl1 (8B), vtbl2 (16B), vtbl4 (32B) | Automatic splitting | + | WebAssembly | i8x16.swizzle (16B), Emulation (>16B) | Mixed | + | Other | Emulation | Software | + +Example: + + import "core:simd" + import "core:fmt" + + runtime_swizzle_example :: proc() { + table := simd.u8x16{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + indices := simd.u8x16{15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} + result := simd.runtime_swizzle(table, indices) + fmt.println(result) // Expected: {15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} + } + +*/ +runtime_swizzle :: intrinsics.simd_runtime_swizzle + /* Compute the square root of each lane in a SIMD vector. */ @@ -2452,3 +2748,17 @@ Example: recip :: #force_inline proc "contextless" (v: $T/#simd[$LANES]$E) -> T where intrinsics.type_is_float(E) { return T(1) / v } + + +/* +Create a vector where each lane contains the index of that lane. +Inputs: +- `V`: The type of the vector to create. +Result: +- A vector of the given type, where each lane contains the index of that lane. +**Operation**: + for i in 0 ..< N { + res[i] = i + } +*/ +indices :: intrinsics.simd_indices \ No newline at end of file diff --git a/core/simd/x86/bmi.odin b/core/simd/x86/bmi.odin new file mode 100644 index 000000000..661272dbf --- /dev/null +++ b/core/simd/x86/bmi.odin @@ -0,0 +1,79 @@ +#+build i386, amd64 +package simd_x86 + +import "base:intrinsics" + +@(require_results, enable_target_feature="bmi") +_andn_u32 :: #force_inline proc "c" (a, b: u32) -> u32 { + return a &~ b +} +@(require_results, enable_target_feature="bmi") +_andn_u64 :: #force_inline proc "c" (a, b: u64) -> u64 { + return a &~ b +} + +@(require_results, enable_target_feature="bmi") +_bextr_u32 :: #force_inline proc "c" (a, start, len: u32) -> u32 { + return bextr_u32(a, (start & 0xff) | (len << 8)) +} +@(require_results, enable_target_feature="bmi") +_bextr_u64 :: #force_inline proc "c" (a: u64, start, len: u32) -> u64 { + return bextr_u64(a, cast(u64)((start & 0xff) | (len << 8))) +} + +@(require_results, enable_target_feature="bmi") +_bextr2_u32 :: #force_inline proc "c" (a, control: u32) -> u32 { + return bextr_u32(a, control) +} +@(require_results, enable_target_feature="bmi") +_bextr2_u64 :: #force_inline proc "c" (a, control: u64) -> u64 { + return bextr_u64(a, control) +} + +@(require_results, enable_target_feature="bmi") +_blsi_u32 :: #force_inline proc "c" (a: u32) -> u32 { + return a & -a +} +@(require_results, enable_target_feature="bmi") +_blsi_u64 :: #force_inline proc "c" (a: u64) -> u64 { + return a & -a +} + +@(require_results, enable_target_feature="bmi") +_blsmsk_u32 :: #force_inline proc "c" (a: u32) -> u32 { + return a ~ (a-1) +} +@(require_results, enable_target_feature="bmi") +_blsmsk_u64 :: #force_inline proc "c" (a: u64) -> u64 { + return a ~ (a-1) +} + +@(require_results, enable_target_feature="bmi") +_blsr_u32 :: #force_inline proc "c" (a: u32) -> u32 { + return a & (a-1) +} +@(require_results, enable_target_feature="bmi") +_blsr_u64 :: #force_inline proc "c" (a: u64) -> u64 { + return a & (a-1) +} + +@(require_results, enable_target_feature = "bmi") +_tzcnt_u16 :: #force_inline proc "c" (a: u16) -> u16 { + return intrinsics.count_trailing_zeros(a) +} +@(require_results, enable_target_feature = "bmi") +_tzcnt_u32 :: #force_inline proc "c" (a: u32) -> u32 { + return intrinsics.count_trailing_zeros(a) +} +@(require_results, enable_target_feature = "bmi") +_tzcnt_u64 :: #force_inline proc "c" (a: u64) -> u64 { + return intrinsics.count_trailing_zeros(a) +} + +@(private, default_calling_convention = "none") +foreign _ { + @(link_name = "llvm.x86.bmi.bextr.32") + bextr_u32 :: proc(a, control: u32) -> u32 --- + @(link_name = "llvm.x86.bmi.bextr.64") + bextr_u64 :: proc(a, control: u64) -> u64 --- +} diff --git a/core/simd/x86/bmi2.odin b/core/simd/x86/bmi2.odin new file mode 100644 index 000000000..65ce7f77c --- /dev/null +++ b/core/simd/x86/bmi2.odin @@ -0,0 +1,46 @@ +#+build i386, amd64 +package simd_x86 + +@(require_results, enable_target_feature = "bmi2") +_bzhi_u32 :: #force_inline proc "c" (a, index: u32) -> u32 { + return bzhi_u32(a, index) +} +@(require_results, enable_target_feature = "bmi2") +_bzhi_u64 :: #force_inline proc "c" (a, index: u64) -> u64 { + return bzhi_u64(a, index) +} + +@(require_results, enable_target_feature = "bmi2") +_pdep_u32 :: #force_inline proc "c" (a, mask: u32) -> u32 { + return pdep_u32(a, mask) +} +@(require_results, enable_target_feature = "bmi2") +_pdep_u64 :: #force_inline proc "c" (a, mask: u64) -> u64 { + return pdep_u64(a, mask) +} + +@(require_results, enable_target_feature = "bmi2") +_pext_u32 :: #force_inline proc "c" (a, mask: u32) -> u32 { + return pext_u32(a, mask) +} +@(require_results, enable_target_feature = "bmi2") +_pext_u64 :: #force_inline proc "c" (a, mask: u64) -> u64 { + return pext_u64(a, mask) +} + + +@(private, default_calling_convention = "none") +foreign _ { + @(link_name = "llvm.x86.bmi.bzhi.32") + bzhi_u32 :: proc(a, index: u32) -> u32 --- + @(link_name = "llvm.x86.bmi.bzhi.64") + bzhi_u64 :: proc(a, index: u64) -> u64 --- + @(link_name = "llvm.x86.bmi.pdep.32") + pdep_u32 :: proc(a, mask: u32) -> u32 --- + @(link_name = "llvm.x86.bmi.pdep.64") + pdep_u64 :: proc(a, mask: u64) -> u64 --- + @(link_name = "llvm.x86.bmi.pext.32") + pext_u32 :: proc(a, mask: u32) -> u32 --- + @(link_name = "llvm.x86.bmi.pext.64") + pext_u64 :: proc(a, mask: u64) -> u64 --- +} diff --git a/core/simd/x86/ssse3.odin b/core/simd/x86/ssse3.odin index 07c846e7b..03ba5dcfb 100644 --- a/core/simd/x86/ssse3.odin +++ b/core/simd/x86/ssse3.odin @@ -21,7 +21,7 @@ _mm_abs_epi32 :: #force_inline proc "c" (a: __m128i) -> __m128i { _mm_shuffle_epi8 :: #force_inline proc "c" (a, b: __m128i) -> __m128i { return transmute(__m128i)pshufb128(transmute(u8x16)a, transmute(u8x16)b) } -@(require_results, enable_target_feature="ssse3") +@(require_results, enable_target_feature="sse2,ssse3") _mm_alignr_epi8 :: #force_inline proc "c" (a, b: __m128i, $IMM8: u32) -> __m128i { shift :: IMM8 diff --git a/core/slice/slice.odin b/core/slice/slice.odin index c328fd267..8337a9728 100644 --- a/core/slice/slice.odin +++ b/core/slice/slice.odin @@ -387,6 +387,25 @@ has_prefix :: proc(array: $T/[]$E, needle: T) -> bool where intrinsics.type_is_c return false } +/* + return the suffix length common between slices `a` and `b`. + + slice.suffix_length([]u8{1, 2, 3, 4}, []u8{1, 2, 3, 4}) -> 4 + slice.suffix_length([]u8{1, 2, 3, 4}, []u8{3, 4}) -> 2 + slice.suffix_length([]u8{1, 2, 3, 4}, []u8{1}) -> 0 + slice.suffix_length([]u8{1, 2, 3, 4}, []u8{1, 3, 5}) -> 0 + slice.suffix_length([]u8{3, 4, 5}, []u8{3, 5}) -> 1 +*/ +@(require_results) +suffix_length :: proc(a, b: $T/[]$E) -> (n: int) where intrinsics.type_is_comparable(E) { + len_a, len_b := len(a), len(b) + _len := builtin.min(len_a, len_b) + + #no_bounds_check for i := 1; i <= _len && a[len_a - i] == b[len_b - i]; i += 1 { + n += 1 + } + return +} @(require_results) has_suffix :: proc(array: $T/[]$E, needle: T) -> bool where intrinsics.type_is_comparable(E) { diff --git a/core/sort/sort.odin b/core/sort/sort.odin index 322613cc4..c4aca4188 100644 --- a/core/sort/sort.odin +++ b/core/sort/sort.odin @@ -30,14 +30,6 @@ sort :: proc(it: Interface) { _quick_sort(it, 0, n, max_depth(n)) } - -@(deprecated="use slice.sort") -slice :: proc(array: $T/[]$E) where ORD(E) { - _slice.sort(array) - // s := array; - // sort(slice_interface(&s)); -} - slice_interface :: proc(s: ^$T/[]$E) -> Interface where ORD(E) { return Interface{ collection = rawptr(s), @@ -80,31 +72,6 @@ reverse_sort :: proc(it: Interface) { sort(reverse_interface(&it)) } -@(deprecated="use slice.reverse") -reverse_slice :: proc(array: $T/[]$E) where ORD(E) { - _slice.reverse(array) - /* - s := array; - sort(Interface{ - collection = rawptr(&s), - len = proc(it: Interface) -> int { - s := (^T)(it.collection); - return len(s^); - }, - less = proc(it: Interface, i, j: int) -> bool { - s := (^T)(it.collection); - return s[j] < s[i]; // manual set up - }, - swap = proc(it: Interface, i, j: int) { - s := (^T)(it.collection); - s[i], s[j] = s[j], s[i]; - }, - }); - */ -} - - - is_sorted :: proc(it: Interface) -> bool { n := it->len() for i := n-1; i > 0; i -= 1 { @@ -294,11 +261,6 @@ _insertion_sort :: proc(it: Interface, a, b: int) { } } - - - - -// @(deprecated="use sort.sort or slice.sort_by") bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { assert(f != nil) count := len(array) @@ -327,7 +289,6 @@ bubble_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { } } -// @(deprecated="use sort.sort_slice or slice.sort") bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { count := len(array) @@ -355,7 +316,6 @@ bubble_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { } } -// @(deprecated="use sort.sort or slice.sort_by") quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { assert(f != nil) a := array @@ -384,7 +344,6 @@ quick_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { quick_sort_proc(a[i:n], f) } -// @(deprecated="use sort.sort_slice or slice.sort") quick_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { a := array n := len(a) @@ -420,7 +379,6 @@ _log2 :: proc(x: int) -> int { return res } -// @(deprecated="use sort.sort or slice.sort_by") merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { merge :: proc(a: A, start, mid, end: int, f: proc(T, T) -> int) { s, m := start, mid @@ -462,7 +420,6 @@ merge_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { internal_sort(array, 0, len(array)-1, f) } -// @(deprecated="use sort.sort_slice or slice.sort") merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { merge :: proc(a: A, start, mid, end: int) { s, m := start, mid @@ -504,8 +461,6 @@ merge_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { internal_sort(array, 0, len(array)-1) } - -// @(deprecated="use sort.sort or slice.sort_by") heap_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { sift_proc :: proc(a: A, pi: int, n: int, f: proc(T, T) -> int) #no_bounds_check { p := pi @@ -540,7 +495,6 @@ heap_sort_proc :: proc(array: $A/[]$T, f: proc(T, T) -> int) { } } -// @(deprecated="use sort.sort_slice or slice.sort") heap_sort :: proc(array: $A/[]$T) where intrinsics.type_is_ordered(T) { sift :: proc(a: A, pi: int, n: int) #no_bounds_check { p := pi diff --git a/core/strconv/decimal/decimal.odin b/core/strconv/decimal/decimal.odin index 06503d01a..5a878d0e1 100644 --- a/core/strconv/decimal/decimal.odin +++ b/core/strconv/decimal/decimal.odin @@ -12,11 +12,11 @@ Decimal :: struct { Sets a Decimal from a given string `s`. The string is expected to represent a float. Stores parsed number in the given Decimal structure. If parsing fails, the Decimal will be left in an undefined state. -**Inputs** +**Inputs** - d: Pointer to a Decimal struct where the parsed result will be stored - s: The input string representing the floating-point number -**Returns** +**Returns** - ok: A boolean indicating whether the parsing was successful */ set :: proc(d: ^Decimal, s: string) -> (ok: bool) { @@ -104,11 +104,11 @@ set :: proc(d: ^Decimal, s: string) -> (ok: bool) { /* Converts a Decimal to a string representation, using the provided buffer as storage. -**Inputs** +**Inputs** - buf: A byte slice buffer to hold the resulting string - a: The struct to be converted to a string -**Returns** +**Returns** - A string representation of the Decimal */ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string { @@ -150,7 +150,7 @@ decimal_to_string :: proc(buf: []byte, a: ^Decimal) -> string { /* Trims trailing zeros in the given Decimal, updating the count and decimal_point values as needed. -**Inputs** +**Inputs** - a: Pointer to the Decimal struct to be trimmed */ trim :: proc(a: ^Decimal) { @@ -166,7 +166,7 @@ Converts a given u64 integer `idx` to its Decimal representation in the provided **Used for internal Decimal Operations.** -**Inputs** +**Inputs** - a: Where the result will be stored - idx: The value to be assigned to the Decimal */ @@ -190,11 +190,11 @@ assign :: proc(a: ^Decimal, idx: u64) { trim(a) } /* -Shifts the Decimal value to the right by k positions. +Shifts the Decimal value to the right by k positions. **Used for internal Decimal Operations.** -**Inputs** +**Inputs** - a: The Decimal struct to be shifted - k: The number of positions to shift right */ @@ -344,7 +344,7 @@ Shifts the decimal of the input value to the left by `k` places WARNING: asserts `k < 61` -**Inputs** +**Inputs** - a: The Decimal to be modified - k: The number of places to shift the decimal to the left */ @@ -399,13 +399,13 @@ shift_left :: proc(a: ^Decimal, k: uint) #no_bounds_check { a.decimal_point += delta - a.count = clamp(a.count, 0, len(a.digits)) + a.count = clamp(a.count+delta, 0, len(a.digits)) trim(a) } /* Shifts the decimal of the input value by the specified number of places -**Inputs** +**Inputs** - a: The Decimal to be modified - i: The number of places to shift the decimal (positive for left shift, negative for right shift) */ @@ -435,7 +435,7 @@ shift :: proc(a: ^Decimal, i: int) { /* Determines if the Decimal can be rounded up at the given digit index -**Inputs** +**Inputs** - a: The Decimal to check - nd: The digit index to consider for rounding up @@ -455,7 +455,7 @@ can_round_up :: proc(a: ^Decimal, nd: int) -> bool { /* Rounds the Decimal at the given digit index -**Inputs** +**Inputs** - a: The Decimal to be modified - nd: The digit index to round */ @@ -470,7 +470,7 @@ round :: proc(a: ^Decimal, nd: int) { /* Rounds the Decimal up at the given digit index -**Inputs** +**Inputs** - a: The Decimal to be modified - nd: The digit index to round up */ @@ -493,7 +493,7 @@ round_up :: proc(a: ^Decimal, nd: int) { /* Rounds down the decimal value to the specified number of decimal places -**Inputs** +**Inputs** - a: The Decimal value to be rounded down - nd: The number of decimal places to round down to @@ -522,7 +522,7 @@ round_down :: proc(a: ^Decimal, nd: int) { /* Extracts the rounded integer part of a decimal value -**Inputs** +**Inputs** - a: A pointer to the Decimal value to extract the rounded integer part from WARNING: There are no guarantees about overflow. @@ -562,4 +562,3 @@ rounded_integer :: proc(a: ^Decimal) -> u64 { } return n } - diff --git a/core/strconv/deprecated.odin b/core/strconv/deprecated.odin new file mode 100644 index 000000000..c644d331e --- /dev/null +++ b/core/strconv/deprecated.odin @@ -0,0 +1,62 @@ +package strconv + +// (2025-06-05) These procedures are to be removed at a later release. + +@(deprecated="Use write_bits instead") +append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { + return write_bits(buf, x, base, is_signed, bit_size, digits, flags) +} + +@(deprecated="Use write_bits_128 instead") +append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { + return write_bits_128(buf, x, base, is_signed, bit_size, digits, flags) +} + +@(deprecated="Use write_bool instead") +append_bool :: proc(buf: []byte, b: bool) -> string { + return write_bool(buf, b) +} + +@(deprecated="Use write_uint instead") +append_uint :: proc(buf: []byte, u: u64, base: int) -> string { + return write_uint(buf, u, base) +} + +@(deprecated="Use write_int instead") +append_int :: proc(buf: []byte, i: i64, base: int) -> string { + return write_int(buf, i, base) +} + +@(deprecated="Use write_u128 instead") +append_u128 :: proc(buf: []byte, u: u128, base: int) -> string { + return write_u128(buf, u, base) +} + +@(deprecated="Use write_float instead") +append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { + return write_float(buf, f, fmt, prec, bit_size) +} + +// 2025-10-03 Deprecated C short names and implementations + +@(deprecated="Use strconv.write_int() instead") +itoa :: proc(buf: []byte, i: int) -> string { + return write_int(buf, i64(i), 10) +} + +@(deprecated="Use strconv.parse_int() instead") +atoi :: proc(s: string) -> int { + v, _ := parse_int(s) + return v +} + +@(deprecated="Use strconv.parse_f64() instead") +atof :: proc(s: string) -> f64 { + v, _ := parse_f64(s) + return v +} + +@(deprecated="Use strconv.write_float() instead") +ftoa :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { + return string(generic_ftoa(buf, f, fmt, prec, bit_size)) +} \ No newline at end of file diff --git a/core/strconv/generic_float.odin b/core/strconv/generic_float.odin index b049f0fe1..163148156 100644 --- a/core/strconv/generic_float.odin +++ b/core/strconv/generic_float.odin @@ -23,7 +23,7 @@ _f64_info := Float_Info{52, 11, -1023} /* Converts a floating-point number to a string with the specified format and precision. -**Inputs** +**Inputs** buf: A byte slice to store the resulting string val: The floating-point value to be converted @@ -40,7 +40,7 @@ Example: bit_size := 64 result := strconv.generic_ftoa(buf[:], val, fmt, precision, bit_size) -> "3.14" -**Returns** +**Returns** - A byte slice containing the formatted string */ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) -> []byte { @@ -122,7 +122,7 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int) /* Converts a decimal floating-point number into a byte buffer with the given format -**Inputs** +**Inputs** - buf: The byte buffer to store the formatted number - shortest: If true, generates the shortest representation of the number - neg: If true, the number is negative @@ -130,7 +130,7 @@ Converts a decimal floating-point number into a byte buffer with the given forma - precision: The number of digits after the decimal point - fmt: The format specifier (accepted values: 'f', 'F', 'e', 'E', 'g', 'G') -**Returns** +**Returns** - A byte slice containing the formatted decimal floating-point number */ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slice, precision: int, fmt: byte) -> []byte { @@ -256,7 +256,7 @@ format_digits :: proc(buf: []byte, shortest: bool, neg: bool, digs: Decimal_Slic /* Rounds the given decimal number to its shortest representation, considering the provided floating-point format -**Inputs** +**Inputs** - d: The decimal number to round - mant: The mantissa of the floating-point number - exp: The exponent of the floating-point number @@ -331,53 +331,45 @@ round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Inf /* Converts a decimal number to its floating-point representation with the given format and returns the resulting bits -**Inputs** +**Inputs** - d: Pointer to the decimal number to convert - info: Pointer to the Float_Info structure containing information about the floating-point format -**Returns** +**Returns** - b: The bits representing the floating-point number - overflow: A boolean indicating whether an overflow occurred during conversion */ -@(private) decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64, overflow: bool) { - end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (bits: u64) { + overflow_end :: proc "contextless" (d: ^decimal.Decimal, info: ^Float_Info) -> (u64, bool) { + mant: u64 = 0 + exp: int = 1< (bits: u64, overflow: bool) { bits = mant & (u64(1)< bool { - mant^ = 0 - exp^ = 1< 310 { - set_overflow(&mant, &exp, info) - b = end(d, mant, exp, info) - return + return overflow_end(d, info) } else if d.decimal_point < -330 { - mant = 0 - exp = info.bias - b = end(d, mant, exp, info) - return + return end(d, 0, info.bias, info, false) } @(static, rodata) power_table := [?]int{1, 3, 6, 9, 13, 16, 19, 23, 26} - exp = 0 + + exp := 0 for d.decimal_point > 0 { n := 27 if d.decimal_point >= len(power_table) else power_table[d.decimal_point] decimal.shift(d, -n) @@ -392,35 +384,34 @@ decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64 // go from [0.5, 1) to [1, 2) exp -= 1 + // Min rep exp is 1+bias if exp < info.bias + 1 { n := info.bias + 1 - exp - decimal.shift(d, n) + decimal.shift(d, -n) exp += n } if (exp-info.bias) >= (1<>= 1 exp += 1 if (exp-info.bias) >= (1< (u: u64, return } /* -Appends the string representation of an integer to a buffer with specified base, flags, and digit set. +Writes the string representation of an integer to a buffer with specified base, flags, and digit set. -**Inputs** +**Inputs** - buf: The buffer to append the integer representation to - x: The integer value to convert - base: The base for the integer representation (2 <= base <= MAX_BASE) @@ -59,12 +59,12 @@ Appends the string representation of an integer to a buffer with specified base, - digits: The digit set used for the integer representation - flags: The Int_Flags bit set to control integer formatting -**Returns** +**Returns** - The string containing the integer representation appended to the buffer */ -append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { +write_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { if base < 2 || base > MAX_BASE { - panic("strconv: illegal base passed to append_bits") + panic("strconv: illegal base passed to write_bits") } a: [129]byte @@ -106,12 +106,12 @@ append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: i /* Determines whether the given unsigned 128-bit integer is a negative value by interpreting it as a signed integer with the specified bit size. -**Inputs** +**Inputs** - x: The unsigned 128-bit integer to check for negativity - is_signed: A boolean indicating if the input should be treated as a signed integer - bit_size: The bit size of the signed integer representation (8, 16, 32, 64, or 128) -**Returns** +**Returns** - u: The absolute value of the input integer - neg: A boolean indicating whether the input integer is negative */ @@ -146,9 +146,9 @@ is_integer_negative_128 :: proc(x: u128, is_signed: bool, bit_size: int) -> (u: return } /* -Appends the string representation of a 128-bit integer to a buffer with specified base, flags, and digit set. +Writes the string representation of a 128-bit integer to a buffer with specified base, flags, and digit set. -**Inputs** +**Inputs** - buf: The buffer to append the integer representation to - x: The 128-bit integer value to convert - base: The base for the integer representation (2 <= base <= MAX_BASE) @@ -157,12 +157,12 @@ Appends the string representation of a 128-bit integer to a buffer with specifie - digits: The digit set used for the integer representation - flags: The Int_Flags bit set to control integer formatting -**Returns** -- The string containing the integer representation appended to the buffer +**Returns** +- The string containing the integer representation written to the buffer */ -append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { +write_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { if base < 2 || base > MAX_BASE { - panic("strconv: illegal base passed to append_bits") + panic("strconv: illegal base passed to write_bits") } a: [140]byte diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index 26a737bd1..7fcb578f7 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -5,8 +5,8 @@ import "decimal" /* Parses a boolean value from the input string -**Inputs** -- s: The input string +**Inputs** +- s: The input string - true: "1", "t", "T", "true", "TRUE", "True" - false: "0", "f", "F", "false", "FALSE", "False" - n: An optional pointer to an int to store the length of the parsed substring (default: nil) @@ -386,7 +386,7 @@ Parses an unsigned integer value from the input string, using the specified base - If base is not 0, it will be used for parsing regardless of any prefix in the input string Example: - + import "core:fmt" import "core:strconv" parse_uint_example :: proc() { @@ -399,14 +399,14 @@ Example: n, ok = strconv.parse_uint("0xffff") // with prefix and inferred base fmt.println(n,ok) } - + Output: 1234 true 65535 true 65535 true -**Returns** +**Returns** value: The parsed uint value ok: `false` if no appropriate value could be found; the value was negative; he input string contained more than just the number @@ -423,7 +423,7 @@ parse_uint :: proc(s: string, base := 0, n: ^int = nil) -> (value: uint, ok: boo /* Parses an integer value from a string in the given base, without any prefix -**Inputs** +**Inputs** - str: The input string containing the integer value - base: The base (radix) to use for parsing the integer (1-16) - n: An optional pointer to an int to store the length of the parsed substring (default: nil) @@ -436,12 +436,12 @@ Example: n, ok := strconv.parse_i128_of_base("-1234eeee", 10) fmt.println(n,ok) } - + Output: -1234 false -**Returns** +**Returns** - value: The parsed i128 value - ok: false if no numeric value of the appropriate base could be found, or if the input string contained more than just the number. */ @@ -491,7 +491,7 @@ parse_i128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i12 /* Parses an integer value from a string in base 10, unless there's a prefix -**Inputs** +**Inputs** - str: The input string containing the integer value - n: An optional pointer to an int to store the length of the parsed substring (default: nil) @@ -506,13 +506,13 @@ Example: n, ok = strconv.parse_i128_maybe_prefixed("0xeeee") fmt.println(n, ok) } - + Output: 1234 true 61166 true - -**Returns** + +**Returns** - value: The parsed i128 value - ok: `false` if a valid integer could not be found, or if the input string contained more than just the number. */ @@ -574,7 +574,7 @@ parse_i128 :: proc{parse_i128_maybe_prefixed, parse_i128_of_base} /* Parses an unsigned integer value from a string in the given base, without any prefix -**Inputs** +**Inputs** - str: The input string containing the integer value - base: The base (radix) to use for parsing the integer (1-16) - n: An optional pointer to an int to store the length of the parsed substring (default: nil) @@ -590,13 +590,13 @@ Example: n, ok = strconv.parse_u128_of_base("5678eeee", 16) fmt.println(n, ok) } - + Output: 1234 false 1450766062 true - -**Returns** + +**Returns** - value: The parsed u128 value - ok: `false` if no numeric value of the appropriate base could be found, or if the input string contained more than just the number. */ @@ -634,7 +634,7 @@ parse_u128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u12 /* Parses an unsigned integer value from a string in base 10, unless there's a prefix -**Inputs** +**Inputs** - str: The input string containing the integer value - n: An optional pointer to an int to store the length of the parsed substring (default: nil) @@ -649,13 +649,13 @@ Example: n, ok = strconv.parse_u128_maybe_prefixed("5678eeee") fmt.println(n, ok) } - + Output: 1234 true 5678 false - -**Returns** + +**Returns** - value: The parsed u128 value - ok: false if a valid integer could not be found, if the value was negative, or if the input string contained more than just the number. */ @@ -706,10 +706,10 @@ parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base} /* Converts a byte to lowercase -**Inputs** +**Inputs** - ch: A byte character to be converted to lowercase. -**Returns** +**Returns** - A lowercase byte character. */ @(private) @@ -717,7 +717,7 @@ lower :: #force_inline proc "contextless" (ch: byte) -> byte { return ('a' - 'A' /* Parses a 32-bit floating point number from a string -**Inputs** +**Inputs** - s: The input string containing a 32-bit floating point number. - n: An optional pointer to an int to store the length of the parsed substring (default: nil). @@ -732,13 +732,13 @@ Example: n, ok = strconv.parse_f32("5678e2") fmt.printfln("%.3f %v", n, ok) } - + Output: 0.000 false 567800.000 true - -**Returns** + +**Returns** - value: The parsed 32-bit floating point number. - ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number. */ @@ -750,7 +750,7 @@ parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) { /* Parses a 64-bit floating point number from a string -**Inputs** +**Inputs** - str: The input string containing a 64-bit floating point number. - n: An optional pointer to an int to store the length of the parsed substring (default: nil). @@ -765,13 +765,13 @@ Example: n, ok = strconv.parse_f64("5678e2") fmt.printfln("%.3f %v", n, ok) } - + Output: 0.000 false 567800.000 true - -**Returns** + +**Returns** - value: The parsed 64-bit floating point number. - ok: `false` if a base 10 float could not be found, or if the input string contained more than just the number. */ @@ -787,7 +787,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) { /* Parses a 32-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful -**Inputs** +**Inputs** - str: The input string containing a 32-bit floating point number. Example: @@ -801,14 +801,14 @@ Example: n, _, ok = strconv.parse_f32_prefix("5678e2") fmt.printfln("%.3f %v", n, ok) } - + Output: 0.000 false 567800.000 true - -**Returns** + +**Returns** - value: The parsed 32-bit floating point number. - nr: The length of the parsed substring. - ok: A boolean indicating whether the parsing was successful. @@ -822,7 +822,7 @@ parse_f32_prefix :: proc(str: string) -> (value: f32, nr: int, ok: bool) { /* Parses a 64-bit floating point number from a string and returns the parsed number, the length of the parsed substring, and a boolean indicating whether the parsing was successful -**Inputs** +**Inputs** - str: The input string containing a 64-bit floating point number. Example: @@ -846,7 +846,7 @@ Output: 1234.000 true 13.370 true -**Returns** +**Returns** - value: The parsed 64-bit floating point number. - nr: The length of the parsed substring. - ok: `false` if a base 10 float could not be found @@ -1095,6 +1095,39 @@ parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) { return transmute(f64)bits, ok } + if len(str) > 2 && str[0] == '0' && str[1] == 'h' { + nr = 2 + + as_int: u64 + digits: int + for r in str[2:] { + if r == '_' { + nr += 1 + continue + } + v := u64(_digit_value(r)) + if v >= 16 { + break + } + as_int *= 16 + as_int += v + digits += 1 + } + nr += digits + ok = len(str) == nr + + switch digits { + case 4: + value = cast(f64)transmute(f16)cast(u16)as_int + case 8: + value = cast(f64)transmute(f32)cast(u32)as_int + case 16: + value = transmute(f64)as_int + case: + ok = false + } + return + } if value, nr, ok = check_special(str); ok { return @@ -1151,7 +1184,7 @@ parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) { /* Parses a 128-bit complex number from a string -**Inputs** +**Inputs** - str: The input string containing a 128-bit complex number. - n: An optional pointer to an int to store the length of the parsed substring (default: nil). @@ -1167,13 +1200,13 @@ Example: c, ok = strconv.parse_complex128("5+7i hellope", &n) fmt.printfln("%v %i %t", c, n, ok) } - + Output: 3+1i 4 true 5+7i 4 false - -**Returns** + +**Returns** - value: The parsed 128-bit complex number. - ok: `false` if a complex number could not be found, or if the input string contained more than just the number. */ @@ -1199,12 +1232,12 @@ parse_complex128 :: proc(str: string, n: ^int = nil) -> (value: complex128, ok: } value = complex(real_value, imag_value) - return + return } /* Parses a 64-bit complex number from a string -**Inputs** +**Inputs** - str: The input string containing a 64-bit complex number. - n: An optional pointer to an int to store the length of the parsed substring (default: nil). @@ -1220,13 +1253,13 @@ Example: c, ok = strconv.parse_complex64("5+7i hellope", &n) fmt.printfln("%v %i %t", c, n, ok) } - + Output: 3+1i 4 true 5+7i 4 false - -**Returns** + +**Returns** - value: The parsed 64-bit complex number. - ok: `false` if a complex number could not be found, or if the input string contained more than just the number. */ @@ -1238,7 +1271,7 @@ parse_complex64 :: proc(str: string, n: ^int = nil) -> (value: complex64, ok: bo /* Parses a 32-bit complex number from a string -**Inputs** +**Inputs** - str: The input string containing a 32-bit complex number. - n: An optional pointer to an int to store the length of the parsed substring (default: nil). @@ -1254,13 +1287,13 @@ Example: c, ok = strconv.parse_complex32("5+7i hellope", &n) fmt.printfln("%v %i %t", c, n, ok) } - + Output: 3+1i 4 true 5+7i 4 false - -**Returns** + +**Returns** - value: The parsed 32-bit complex number. - ok: `false` if a complex number could not be found, or if the input string contained more than just the number. */ @@ -1272,7 +1305,7 @@ parse_complex32 :: proc(str: string, n: ^int = nil) -> (value: complex32, ok: bo /* Parses a 256-bit quaternion from a string -**Inputs** +**Inputs** - str: The input string containing a 256-bit quaternion. - n: An optional pointer to an int to store the length of the parsed substring (default: nil). @@ -1288,13 +1321,13 @@ Example: q, ok = strconv.parse_quaternion256("1+2i+3j+4k hellope", &n) fmt.printfln("%v %i %t", q, n, ok) } - + Output: 1+2i+3j+4k 10 true 1+2i+3j+4k 10 false - -**Returns** + +**Returns** - value: The parsed 256-bit quaternion. - ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion. */ @@ -1352,7 +1385,7 @@ parse_quaternion256 :: proc(str: string, n: ^int = nil) -> (value: quaternion256 /* Parses a 128-bit quaternion from a string -**Inputs** +**Inputs** - str: The input string containing a 128-bit quaternion. - n: An optional pointer to an int to store the length of the parsed substring (default: nil). @@ -1368,13 +1401,13 @@ Example: q, ok = strconv.parse_quaternion128("1+2i+3j+4k hellope", &n) fmt.printfln("%v %i %t", q, n, ok) } - + Output: 1+2i+3j+4k 10 true 1+2i+3j+4k 10 false - -**Returns** + +**Returns** - value: The parsed 128-bit quaternion. - ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion. */ @@ -1386,7 +1419,7 @@ parse_quaternion128 :: proc(str: string, n: ^int = nil) -> (value: quaternion128 /* Parses a 64-bit quaternion from a string -**Inputs** +**Inputs** - str: The input string containing a 64-bit quaternion. - n: An optional pointer to an int to store the length of the parsed substring (default: nil). @@ -1402,13 +1435,13 @@ Example: q, ok = strconv.parse_quaternion64("1+2i+3j+4k hellope", &n) fmt.printfln("%v %i %t", q, n, ok) } - + Output: 1+2i+3j+4k 10 true 1+2i+3j+4k 10 false - -**Returns** + +**Returns** - value: The parsed 64-bit quaternion. - ok: `false` if a quaternion could not be found, or if the input string contained more than just the quaternion. */ @@ -1417,20 +1450,20 @@ parse_quaternion64 :: proc(str: string, n: ^int = nil) -> (value: quaternion64, v, ok = parse_quaternion256(str, n) return cast(quaternion64)v, ok } -/* -Appends a boolean value as a string to the given buffer +/* +Writes a boolean value as a string to the given buffer -**Inputs** -- buf: The buffer to append the boolean value to -- b: The boolean value to be appended +**Inputs** +- buf: The buffer to write the boolean value to +- b: The boolean value to be written Example: import "core:fmt" import "core:strconv" - append_bool_example :: proc() { + write_bool_example :: proc() { buf: [6]byte - result := strconv.append_bool(buf[:], true) + result := strconv.write_bool(buf[:], true) fmt.println(result, buf) } @@ -1438,10 +1471,10 @@ Output: true [116, 114, 117, 101, 0, 0] -**Returns** -- The resulting string after appending the boolean value +**Returns** +- The resulting string after writing the boolean value */ -append_bool :: proc(buf: []byte, b: bool) -> string { +write_bool :: proc(buf: []byte, b: bool) -> string { n := 0 if b { n = copy(buf, "true") @@ -1450,21 +1483,21 @@ append_bool :: proc(buf: []byte, b: bool) -> string { } return string(buf[:n]) } -/* -Appends an unsigned integer value as a string to the given buffer with the specified base +/* +Writes an unsigned integer value as a string to the given buffer with the specified base -**Inputs** -- buf: The buffer to append the unsigned integer value to -- u: The unsigned integer value to be appended +**Inputs** +- buf: The buffer to write the unsigned integer value to +- u: The unsigned integer value to be written - base: The base to use for converting the integer value Example: import "core:fmt" import "core:strconv" - append_uint_example :: proc() { + write_uint_example :: proc() { buf: [4]byte - result := strconv.append_uint(buf[:], 42, 16) + result := strconv.write_uint(buf[:], 42, 16) fmt.println(result, buf) } @@ -1472,27 +1505,27 @@ Output: 2a [50, 97, 0, 0] -**Returns** -- The resulting string after appending the unsigned integer value +**Returns** +- The resulting string after writing the unsigned integer value */ -append_uint :: proc(buf: []byte, u: u64, base: int) -> string { - return append_bits(buf, u, base, false, 8*size_of(uint), digits, nil) +write_uint :: proc(buf: []byte, u: u64, base: int) -> string { + return write_bits(buf, u, base, false, 8*size_of(uint), digits, nil) } -/* -Appends a signed integer value as a string to the given buffer with the specified base +/* +Writes a signed integer value as a string to the given buffer with the specified base -**Inputs** -- buf: The buffer to append the signed integer value to -- i: The signed integer value to be appended +**Inputs** +- buf: The buffer to write the signed integer value to +- i: The signed integer value to be written - base: The base to use for converting the integer value Example: import "core:fmt" import "core:strconv" - append_int_example :: proc() { + write_int_example :: proc() { buf: [4]byte - result := strconv.append_int(buf[:], -42, 10) + result := strconv.write_int(buf[:], -42, 10) fmt.println(result, buf) } @@ -1500,104 +1533,27 @@ Output: -42 [45, 52, 50, 0] -**Returns** -- The resulting string after appending the signed integer value +**Returns** +- The resulting string after writing the signed integer value */ -append_int :: proc(buf: []byte, i: i64, base: int) -> string { - return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil) +write_int :: proc(buf: []byte, i: i64, base: int) -> string { + return write_bits(buf, u64(i), base, true, 8*size_of(int), digits, nil) } -append_u128 :: proc(buf: []byte, u: u128, base: int) -> string { - return append_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil) +write_u128 :: proc(buf: []byte, u: u128, base: int) -> string { + return write_bits_128(buf, u, base, false, 8*size_of(uint), digits, nil) } -/* -Converts an integer value to a string and stores it in the given buffer - -**Inputs** -- buf: The buffer to store the resulting string -- i: The integer value to be converted - -Example: - - import "core:fmt" - import "core:strconv" - itoa_example :: proc() { - buf: [4]byte - result := strconv.itoa(buf[:], 42) - fmt.println(result, buf) // "42" - } - -Output: - - 42 [52, 50, 0, 0] - -**Returns** -- The resulting string after converting the integer value -*/ -itoa :: proc(buf: []byte, i: int) -> string { - return append_int(buf, i64(i), 10) -} /* -Converts a string to an integer value +`ftoa` C name deprecated, use `write_float` instead (same procedure) -**Inputs** -- s: The string to be converted +Writes a float64 value as a string to the given buffer with the specified format and precision -Example: - - import "core:fmt" - import "core:strconv" - atoi_example :: proc() { - fmt.println(strconv.atoi("42")) - } - -Output: - - 42 - -**Returns** -- The resulting integer value -*/ -atoi :: proc(s: string) -> int { - v, _ := parse_int(s) - return v -} -/* -Converts a string to a float64 value - -**Inputs** -- s: The string to be converted - -Example: - - import "core:fmt" - import "core:strconv" - atof_example :: proc() { - fmt.printfln("%.3f", strconv.atof("3.14")) - } - -Output: - - 3.140 - -**Returns** -- The resulting float64 value after converting the string -*/ -atof :: proc(s: string) -> f64 { - v, _ := parse_f64(s) - return v -} -// Alias to `append_float` -ftoa :: append_float -/* -Appends a float64 value as a string to the given buffer with the specified format and precision - -**Inputs** -- buf: The buffer to append the float64 value to -- f: The float64 value to be appended +**Inputs** +- buf: The buffer to write the float64 value to +- f: The float64 value to be written - fmt: The byte specifying the format to use for the conversion - prec: The precision to use for the conversion - bit_size: The size of the float in bits (32 or 64) @@ -1606,9 +1562,9 @@ Example: import "core:fmt" import "core:strconv" - append_float_example :: proc() { + write_float_example :: proc() { buf: [8]byte - result := strconv.append_float(buf[:], 3.14159, 'f', 2, 64) + result := strconv.write_float(buf[:], 3.14159, 'f', 2, 64) fmt.println(result, buf) } @@ -1616,20 +1572,27 @@ Output: +3.14 [43, 51, 46, 49, 52, 0, 0, 0] -**Returns** -- The resulting string after appending the float +**Returns** +- The resulting string after writing the float */ -append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { +write_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string { return string(generic_ftoa(buf, f, fmt, prec, bit_size)) } +// Accepts '0'..='9', otherwise returns ok = false +digit_to_int :: proc(r: rune) -> (value: int, ok: bool) { + if '0' <= r && r <= '9' { + return int(r - '0'), true + } + return -1, false +} /* -Appends a quoted string representation of the input string to a given byte slice and returns the result as a string +Writes a quoted string representation of the input string to a given byte slice and returns the result as a string -**Inputs** -- buf: The byte slice to which the quoted string will be appended +**Inputs** +- buf: The byte slice to which the quoted string will be written - str: The input string to be quoted -!! ISSUE !! NOT EXPECTED -- "\"hello\"" was expected +!! ISSUE !! NOT EXPECTED -- "\"hello\"" was expected Example: @@ -1645,8 +1608,8 @@ Output: "'h''e''l''l''o'" [34, 39, 104, 39, 39, 101, 39, 39, 108, 39, 39, 108, 39, 39, 111, 39, 34, 0, 0, 0] -**Returns** -- The resulting string after appending the quoted string representation +**Returns** +- The resulting string after writing the quoted string representation */ quote :: proc(buf: []byte, str: string) -> string { write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) { @@ -1686,10 +1649,10 @@ quote :: proc(buf: []byte, str: string) -> string { return string(buf[:i]) } /* -Appends a quoted rune representation of the input rune to a given byte slice and returns the result as a string +Writes a quoted rune representation of the input rune to a given byte slice and returns the result as a string -**Inputs** -- buf: The byte slice to which the quoted rune will be appended +**Inputs** +- buf: The byte slice to which the quoted rune will be written - r: The input rune to be quoted Example: @@ -1706,8 +1669,8 @@ Output: 'A' [39, 65, 39, 0] -**Returns** -- The resulting string after appending the quoted rune representation +**Returns** +- The resulting string after writing the quoted rune representation */ quote_rune :: proc(buf: []byte, r: rune) -> string { write_byte :: proc(buf: []byte, i: ^int, bytes: ..byte) { @@ -1750,7 +1713,7 @@ quote_rune :: proc(buf: []byte, r: rune) -> string { if r < 32 { write_string(buf, &i, "\\x") b: [2]byte - s := append_bits(b[:], u64(r), 16, true, 64, digits, nil) + s := write_bits(b[:], u64(r), 16, true, 64, digits, nil) switch len(s) { case 0: write_string(buf, &i, "00") case 1: write_rune(buf, &i, '0') @@ -1767,11 +1730,11 @@ quote_rune :: proc(buf: []byte, r: rune) -> string { /* Unquotes a single character from the input string, considering the given quote character -**Inputs** +**Inputs** - str: The input string containing the character to unquote - quote: The quote character to consider (e.g., '"') -Example: +Example: import "core:fmt" import "core:strconv" @@ -1782,12 +1745,12 @@ Example: fmt.printf("r: <%v>, multiple_bytes:%v, tail_string:<%s>, success:%v\n",r, multiple_bytes, tail_string, success) } -Output: +Output: Source: 'The' raven r: <'>, multiple_bytes:false, tail_string:, success:true -**Returns** +**Returns** - r: The unquoted rune - multiple_bytes: A boolean indicating if the rune has multiple bytes - tail_string: The remaining portion of the input string after unquoting the character @@ -1890,13 +1853,13 @@ unquote_char :: proc(str: string, quote: byte) -> (r: rune, multiple_bytes: bool /* Unquotes the input string considering any type of quote character and returns the unquoted string -**Inputs** +**Inputs** - lit: The input string to unquote - allocator: (default: context.allocator) WARNING: This procedure gives unexpected results if the quotes are not the first and last characters. -Example: +Example: import "core:fmt" import "core:strconv" @@ -1914,10 +1877,10 @@ Example: src="The raven \'Huginn\' is black." s, allocated, ok = strconv.unquote_string(src) // Will produce undesireable results fmt.println(src) - fmt.printf("Unquoted: <%s>, alloc:%v, ok:%v\n", s, allocated, ok) + fmt.printf("Unquoted: <%s>, alloc:%v, ok:%v\n", s, allocated, ok) } -Output: +Output: "The raven Huginn is black." Unquoted: , alloc:false, ok:true @@ -1928,7 +1891,7 @@ Output: The raven 'Huginn' is black. Unquoted: , alloc:false, ok:true -**Returns** +**Returns** - res: The resulting unquoted string - allocated: A boolean indicating if the resulting string was allocated using the provided allocator - success: A boolean indicating whether the unquoting was successful @@ -1969,7 +1932,7 @@ unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: str return s, false, true } } - + context.allocator = allocator buf_len := 3*len(s) / 2 diff --git a/core/strings/builder.odin b/core/strings/builder.odin index e5a88527a..285ced9ce 100644 --- a/core/strings/builder.odin +++ b/core/strings/builder.odin @@ -296,8 +296,8 @@ Inputs: Returns: - res: A cstring of the Builder's buffer */ -unsafe_to_cstring :: proc(b: ^Builder) -> (res: cstring) { - append(&b.buf, 0) +unsafe_to_cstring :: proc(b: ^Builder, loc := #caller_location) -> (res: cstring) { + append(&b.buf, 0, loc) pop(&b.buf) return cstring(raw_data(b.buf)) } @@ -311,8 +311,8 @@ Returns: - res: A cstring of the Builder's buffer upon success - err: An optional allocator error if one occured, `nil` otherwise */ -to_cstring :: proc(b: ^Builder) -> (res: cstring, err: mem.Allocator_Error) { - n := append(&b.buf, 0) or_return +to_cstring :: proc(b: ^Builder, loc := #caller_location) -> (res: cstring, err: mem.Allocator_Error) #optional_allocator_error { + n := append(&b.buf, 0, loc) or_return if n != 1 { return nil, .Out_Of_Memory } @@ -518,9 +518,9 @@ Output: abc */ -write_string :: proc(b: ^Builder, s: string) -> (n: int) { +write_string :: proc(b: ^Builder, s: string, loc := #caller_location) -> (n: int) { n0 := len(b.buf) - append(&b.buf, s) + append(&b.buf, s, loc) n1 := len(b.buf) return n1-n0 } @@ -675,7 +675,7 @@ Returns: */ write_float :: proc(b: ^Builder, f: f64, fmt: byte, prec, bit_size: int, always_signed := false) -> (n: int) { buf: [384]byte - s := strconv.append_float(buf[:], f, fmt, prec, bit_size) + s := strconv.write_float(buf[:], f, fmt, prec, bit_size) // If the result starts with a `+` then unless we always want signed results, // we skip it unless it's followed by an `I` (because of +Inf). if !always_signed && (buf[0] == '+' && buf[1] != 'I') { @@ -699,7 +699,7 @@ Returns: */ write_f16 :: proc(b: ^Builder, f: f16, fmt: byte, always_signed := false) -> (n: int) { buf: [384]byte - s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) + s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) if !always_signed && (buf[0] == '+' && buf[1] != 'I') { s = s[1:] } @@ -739,7 +739,7 @@ Output: */ write_f32 :: proc(b: ^Builder, f: f32, fmt: byte, always_signed := false) -> (n: int) { buf: [384]byte - s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) + s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) if !always_signed && (buf[0] == '+' && buf[1] != 'I') { s = s[1:] } @@ -761,7 +761,7 @@ Returns: */ write_f64 :: proc(b: ^Builder, f: f64, fmt: byte, always_signed := false) -> (n: int) { buf: [384]byte - s := strconv.append_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) + s := strconv.write_float(buf[:], f64(f), fmt, 2*size_of(f), 8*size_of(f)) if !always_signed && (buf[0] == '+' && buf[1] != 'I') { s = s[1:] } @@ -782,7 +782,7 @@ Returns: */ write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) { buf: [32]byte - s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], i, base, false, 64, strconv.digits, nil) return write_string(b, s) } /* @@ -800,7 +800,7 @@ Returns: */ write_i64 :: proc(b: ^Builder, i: i64, base: int = 10) -> (n: int) { buf: [32]byte - s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) + s := strconv.write_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil) return write_string(b, s) } /* diff --git a/core/strings/strings.odin b/core/strings/strings.odin index e99a1bfb4..ffa11f219 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -2,6 +2,7 @@ package strings import "base:intrinsics" +import "base:runtime" import "core:bytes" import "core:io" import "core:mem" @@ -25,26 +26,9 @@ Returns: clone :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { c := make([]byte, len(s), allocator, loc) or_return copy(c, s) - return string(c[:len(s)]), nil + return string(c), nil } -/* -Clones a string safely (returns early with an allocation error on failure) -*Allocates Using Provided Allocator* - -Inputs: -- s: The string to be cloned -- allocator: (default: context.allocator) -- loc: The caller location for debugging purposes (default: #caller_location) - -Returns: -- res: The cloned string -- err: An allocator error if one occured, `nil` otherwise -*/ -@(deprecated="Prefer clone. It now returns an optional allocator error") -clone_safe :: proc(s: string, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) { - return clone(s, allocator, loc) -} /* Clones a string and appends a null-byte to make it a cstring @@ -65,6 +49,7 @@ clone_to_cstring :: proc(s: string, allocator := context.allocator, loc := #call c[len(s)] = 0 return cstring(&c[0]), nil } + /* Transmutes a raw pointer into a string. Non-allocating. @@ -80,6 +65,7 @@ Returns: string_from_ptr :: proc(ptr: ^byte, len: int) -> (res: string) { return transmute(string)mem.Raw_String{ptr, len} } + /* Transmutes a raw pointer (null-terminated) into a string. Non-allocating. Searches for a null-byte from `0.. (res: ^byte) { - d := transmute(mem.Raw_String)str - return d.data -} /* Converts a string `str` to a cstring @@ -127,6 +100,7 @@ unsafe_string_to_cstring :: proc(str: string) -> (res: cstring) { d := transmute(mem.Raw_String)str return cstring(d.data) } + /* Truncates a string `str` at the first occurrence of char/byte `b` @@ -146,6 +120,7 @@ truncate_to_byte :: proc "contextless" (str: string, b: byte) -> (res: string) { } return str[:n] } + /* Truncates a string `str` at the first occurrence of rune `r` as a slice of the original, entire string if not found @@ -163,6 +138,7 @@ truncate_to_rune :: proc(str: string, r: rune) -> (res: string) { } return str[:n] } + /* Clones a byte array `s` and appends a null-byte @@ -183,6 +159,7 @@ clone_from_bytes :: proc(s: []byte, allocator := context.allocator, loc := #call c[len(s)] = 0 return string(c[:len(s)]), nil } + /* Clones a cstring `s` as a string @@ -200,6 +177,7 @@ Returns: clone_from_cstring :: proc(s: cstring, allocator := context.allocator, loc := #caller_location) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { return clone(string(s), allocator, loc) } + /* Clones a string from a byte pointer `ptr` and a byte length `len` @@ -221,6 +199,7 @@ clone_from_ptr :: proc(ptr: ^byte, len: int, allocator := context.allocator, loc s := string_from_ptr(ptr, len) return clone(s, allocator, loc) } + // Overloaded procedure to clone from a string, `[]byte`, `cstring` or a `^byte` + length clone_from :: proc{ clone, @@ -228,6 +207,7 @@ clone_from :: proc{ clone_from_cstring, clone_from_ptr, } + /* Clones a string from a null-terminated cstring `ptr` and a byte length `len` @@ -250,6 +230,7 @@ clone_from_cstring_bounded :: proc(ptr: cstring, len: int, allocator := context. s = truncate_to_byte(s, 0) return clone(s, allocator, loc) } + /* Compares two strings, returning a value representing which one comes first lexicographically. -1 for `lhs`; 1 for `rhs`, or 0 if they are equal. @@ -264,6 +245,7 @@ Returns: compare :: proc "contextless" (lhs, rhs: string) -> (result: int) { return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs) } + /* Checks if rune `r` in the string `s` @@ -282,6 +264,7 @@ contains_rune :: proc(s: string, r: rune) -> (result: bool) { } return false } + /* Returns true when the string `substr` is contained inside the string `s` @@ -313,6 +296,7 @@ Output: contains :: proc(s, substr: string) -> (res: bool) { return index(s, substr) >= 0 } + /* Returns `true` when the string `s` contains any of the characters inside the string `chars` @@ -385,6 +369,7 @@ Output: rune_count :: proc(s: string) -> (res: int) { return utf8.rune_count_in_string(s) } + /* Returns whether the strings `u` and `v` are the same alpha characters, ignoring different casings Works with UTF-8 string content @@ -458,6 +443,7 @@ equal_fold :: proc(u, v: string) -> (res: bool) { return s == t } + /* Returns the prefix length common between strings `a` and `b` @@ -488,29 +474,58 @@ Output: 0 */ -prefix_length :: proc(a, b: string) -> (n: int) { - _len := min(len(a), len(b)) +prefix_length :: proc "contextless" (a, b: string) -> (n: int) { + RUNE_ERROR :: '\ufffd' + RUNE_SELF :: 0x80 + UTF_MAX :: 4 - // Scan for matches including partial codepoints. - #no_bounds_check for n < _len && a[n] == b[n] { - n += 1 - } - - // Now scan to ignore partial codepoints. - if n > 0 { - s := a[:n] - n = 0 - for { - r0, w := utf8.decode_rune(s[n:]) - if r0 != utf8.RUNE_ERROR { - n += w - } else { - break + n = runtime.memory_prefix_length(raw_data(a), raw_data(b), min(len(a), len(b))) + lim := max(n - UTF_MAX + 1, 0) + for l := n; l > lim; l -= 1 { + r, _ := runtime.string_decode_rune(a[l - 1:]) + if r != RUNE_ERROR { + if l > 0 && (a[l - 1] & 0xc0 == 0xc0) { + return l - 1 } + return l } } return } + +/* +Returns the common prefix between strings `a` and `b` + +Inputs: +- a: The first input string +- b: The second input string + +Returns: +- n: The string prefix common between strings `a` and `b` + +Example: + + import "core:fmt" + import "core:strings" + + common_prefix_example :: proc() { + fmt.println(strings.common_prefix("testing", "test")) + fmt.println(strings.common_prefix("testing", "te")) + fmt.println(strings.common_prefix("telephone", "te")) + } + +Output: + + test + te + te + + +*/ +common_prefix :: proc(a, b: string) -> string { + return a[:prefix_length(a, b)] +} + /* Determines if a string `s` starts with a given `prefix` @@ -632,24 +647,7 @@ join :: proc(a: []string, sep: string, allocator := context.allocator, loc := #c } return string(b), nil } -/* -Joins a slice of strings `a` with a `sep` string, returns an error on allocation failure -*Allocates Using Provided Allocator* - -Inputs: -- a: A slice of strings to join -- sep: The separator string -- allocator: (default is context.allocator) - -Returns: -- str: A combined string from the slice of strings `a` separated with the `sep` string -- err: An allocator error if one occured, `nil` otherwise -*/ -@(deprecated="Prefer join. It now returns an optional allocator error") -join_safe :: proc(a: []string, sep: string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) { - return join(a, sep, allocator) -} /* Returns a combined string from the slice of strings `a` without a separator @@ -694,22 +692,6 @@ concatenate :: proc(a: []string, allocator := context.allocator, loc := #caller_ } return string(b), nil } -/* -Returns a combined string from the slice of strings `a` without a separator, or an error if allocation fails - -*Allocates Using Provided Allocator* - -Inputs: -- a: A slice of strings to concatenate -- allocator: (default is context.allocator) - -Returns: -The concatenated string, and an error if allocation fails -*/ -@(deprecated="Prefer concatenate. It now returns an optional allocator error") -concatenate_safe :: proc(a: []string, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) { - return concatenate(a, allocator) -} /* Returns a substring of the input string `s` with the specified rune offset and length @@ -787,7 +769,7 @@ Example: import "core:fmt" import "core:strings" - cut_example :: proc() { + cut_clone_example :: proc() { fmt.println(strings.cut_clone("some example text", 0, 4)) // -> "some" fmt.println(strings.cut_clone("some example text", 2, 2)) // -> "me" fmt.println(strings.cut_clone("some example text", 5, 7)) // -> "example" @@ -872,6 +854,7 @@ _split :: proc(s_, sep: string, sep_save, n_: int, allocator := context.allocato return res[:i+1], nil } + /* Splits a string into parts based on a separator. @@ -907,6 +890,7 @@ Output: split :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { return _split(s, sep, 0, -1, allocator) } + /* Splits a string into parts based on a separator. If n < count of seperators, the remainder of the string is returned in the last entry. @@ -943,6 +927,7 @@ Output: split_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { return _split(s, sep, 0, n, allocator) } + /* Splits a string into parts after the separator, retaining it in the substrings. @@ -978,6 +963,7 @@ Output: split_after :: proc(s, sep: string, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { return _split(s, sep, len(sep), -1, allocator) } + /* Splits a string into a total of `n` parts after the separator. @@ -1014,6 +1000,7 @@ Output: split_after_n :: proc(s, sep: string, n: int, allocator := context.allocator) -> (res: []string, err: mem.Allocator_Error) #optional_allocator_error { return _split(s, sep, len(sep), n, allocator) } + /* Searches for the first occurrence of `sep` in the given string and returns the substring up to (but not including) the separator, as well as a boolean indicating success. @@ -1054,6 +1041,7 @@ _split_iterator :: proc(s: ^string, sep: string, sep_save: int) -> (res: string, } return } + /* Splits the input string by the byte separator in an iterator fashion. @@ -1100,6 +1088,7 @@ split_by_byte_iterator :: proc(s: ^string, sep: u8) -> (res: string, ok: bool) { } return } + /* Splits the input string by the separator string in an iterator fashion. @@ -1135,6 +1124,7 @@ Output: split_iterator :: proc(s: ^string, sep: string) -> (res: string, ok: bool) { return _split_iterator(s, sep, 0) } + /* Splits the input string after every separator string in an iterator fashion. @@ -1170,6 +1160,7 @@ Output: split_after_iterator :: proc(s: ^string, sep: string) -> (res: string, ok: bool) { return _split_iterator(s, sep, len(sep)) } + /* Trims the carriage return character from the end of the input string. @@ -1191,6 +1182,7 @@ _trim_cr :: proc(s: string) -> (res: string) { } return s } + /* Splits the input string at every line break `\n`. @@ -1228,6 +1220,7 @@ split_lines :: proc(s: string, allocator := context.allocator) -> (res: []string } return lines, nil } + /* Splits the input string at every line break `\n` for `n` parts. @@ -1268,6 +1261,7 @@ split_lines_n :: proc(s: string, n: int, allocator := context.allocator) -> (res } return lines, nil } + /* Splits the input string at every line break `\n` leaving the `\n` in the resulting strings. @@ -1307,6 +1301,7 @@ split_lines_after :: proc(s: string, allocator := context.allocator) -> (res: [] } return lines, nil } + /* Splits the input string at every line break `\n` leaving the `\n` in the resulting strings. Only runs for n parts. @@ -1348,6 +1343,7 @@ split_lines_after_n :: proc(s: string, n: int, allocator := context.allocator) - } return lines, nil } + /* Splits the input string at every line break `\n`. Returns the current split string every iteration until the string is consumed. @@ -1382,6 +1378,7 @@ split_lines_iterator :: proc(s: ^string) -> (line: string, ok: bool) { line = _split_iterator(s, sep, 0) or_return return _trim_cr(line), true } + /* Splits the input string at every line break `\n`. Returns the current split string with line breaks included every iteration until the string is consumed. @@ -1419,6 +1416,7 @@ split_lines_after_iterator :: proc(s: ^string) -> (line: string, ok: bool) { line = _split_iterator(s, sep, len(sep)) or_return return _trim_cr(line), true } + /* Returns the byte offset of the first byte `c` in the string s it finds, -1 when not found. NOTE: Can't find UTF-8 based runes. @@ -1453,6 +1451,7 @@ Output: index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) { return #force_inline bytes.index_byte(transmute([]u8)s, c) } + /* Returns the byte offset of the last byte `c` in the string `s`, -1 when not found. @@ -1488,6 +1487,7 @@ Output: last_index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) { return #force_inline bytes.last_index_byte(transmute([]u8)s, c) } + /* Returns the byte offset of the first rune `r` in the string `s` it finds, -1 when not found. Invalid runes return -1 @@ -1628,6 +1628,7 @@ index :: proc "contextless" (s, substr: string) -> (res: int) { } return -1 } + /* Returns the last byte offset of the string `substr` in the string `s`, -1 when not found. @@ -1705,6 +1706,7 @@ last_index :: proc(s, substr: string) -> (res: int) { } return -1 } + /* Returns the index of any first char of `chars` found in `s`, -1 if not found. @@ -1768,6 +1770,7 @@ index_any :: proc(s, chars: string) -> (res: int) { } return -1 } + /* Finds the last occurrence of any character in `chars` within `s`. Iterates in reverse. @@ -1849,6 +1852,7 @@ last_index_any :: proc(s, chars: string) -> (res: int) { } return -1 } + /* Finds the first occurrence of any substring in `substrs` within `s` @@ -1890,6 +1894,7 @@ index_multi :: proc(s: string, substrs: []string) -> (idx: int, width: int) { } return } + /* Counts the number of non-overlapping occurrences of `substr` in `s` @@ -1956,6 +1961,7 @@ count :: proc(s, substr: string) -> (res: int) { } return n } + /* Repeats the string `s` `count` times, concatenating the result @@ -2001,6 +2007,7 @@ repeat :: proc(s: string, count: int, allocator := context.allocator, loc := #ca } return string(b), nil } + /* Replaces all occurrences of `old` in `s` with `new` @@ -2034,9 +2041,11 @@ Output: zzzz true */ + replace_all :: proc(s, old, new: string, allocator := context.allocator) -> (output: string, was_allocation: bool) { return replace(s, old, new, -1, allocator) } + /* Replaces n instances of old in the string s with the new string @@ -2115,6 +2124,7 @@ replace :: proc(s, old, new: string, n: int, allocator := context.allocator, loc output = string(t[0:w]) return } + /* Removes the key string `n` times from the `s` string @@ -2153,6 +2163,7 @@ Output: remove :: proc(s, key: string, n: int, allocator := context.allocator) -> (output: string, was_allocation: bool) { return replace(s, key, "", n, allocator) } + /* Removes all the `key` string instances from the `s` string @@ -2188,6 +2199,7 @@ Output: remove_all :: proc(s, key: string, allocator := context.allocator) -> (output: string, was_allocation: bool) { return remove(s, key, -1, allocator) } + // Returns true if is an ASCII space character ('\t', '\n', '\v', '\f', '\r', ' ') @(private) _ascii_space := [256]bool{'\t' = true, '\n' = true, '\v' = true, '\f' = true, '\r' = true, ' ' = true} @@ -2291,6 +2303,7 @@ index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res: int } return -1 } + // Same as `index_proc`, but the procedure p takes a raw pointer for state index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> (res: int) { for r, i in s { @@ -2300,6 +2313,7 @@ index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: r } return -1 } + // Finds the index of the *last* rune in the string s for which the procedure p returns the same value as truth last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res: int) { // TODO(bill): Probably use Rabin-Karp Search @@ -2312,6 +2326,7 @@ last_index_proc :: proc(s: string, p: proc(rune) -> bool, truth := true) -> (res } return -1 } + // Same as `index_proc_with_state`, runs through the string in reverse last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, state: rawptr, truth := true) -> (res: int) { // TODO(bill): Probably use Rabin-Karp Search @@ -2324,6 +2339,7 @@ last_index_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, sta } return -1 } + /* Trims the input string `s` from the left until the procedure `p` returns false @@ -2358,6 +2374,7 @@ trim_left_proc :: proc(s: string, p: proc(rune) -> bool) -> (res: string) { } return s[i:] } + /* Trims the input string `s` from the left until the procedure `p` with state returns false @@ -2376,6 +2393,7 @@ trim_left_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, stat } return s[i:] } + /* Trims the input string `s` from the right until the procedure `p` returns `false` @@ -2413,6 +2431,7 @@ trim_right_proc :: proc(s: string, p: proc(rune) -> bool) -> (res: string) { } return s[0:i] } + /* Trims the input string `s` from the right until the procedure `p` with state returns `false` @@ -2434,6 +2453,7 @@ trim_right_proc_with_state :: proc(s: string, p: proc(rawptr, rune) -> bool, sta } return s[0:i] } + // Procedure for `trim_*_proc` variants, which has a string rawptr cast + rune comparison is_in_cutset :: proc(state: rawptr, r: rune) -> (res: bool) { cutset := (^string)(state)^ @@ -2444,6 +2464,7 @@ is_in_cutset :: proc(state: rawptr, r: rune) -> (res: bool) { } return false } + /* Trims the cutset string from the `s` string @@ -2461,6 +2482,7 @@ trim_left :: proc(s: string, cutset: string) -> (res: string) { state := cutset return trim_left_proc_with_state(s, is_in_cutset, &state) } + /* Trims the cutset string from the `s` string from the right @@ -2478,6 +2500,7 @@ trim_right :: proc(s: string, cutset: string) -> (res: string) { state := cutset return trim_right_proc_with_state(s, is_in_cutset, &state) } + /* Trims the cutset string from the `s` string, both from left and right @@ -2491,6 +2514,7 @@ Returns: trim :: proc(s: string, cutset: string) -> (res: string) { return trim_right(trim_left(s, cutset), cutset) } + /* Trims until a valid non-space rune from the left, "\t\txyz\t\t" -> "xyz\t\t" @@ -2503,6 +2527,7 @@ Returns: trim_left_space :: proc(s: string) -> (res: string) { return trim_left_proc(s, is_space) } + /* Trims from the right until a valid non-space rune, "\t\txyz\t\t" -> "\t\txyz" @@ -2515,6 +2540,7 @@ Returns: trim_right_space :: proc(s: string) -> (res: string) { return trim_right_proc(s, is_space) } + /* Trims from both sides until a valid non-space rune, "\t\txyz\t\t" -> "xyz" @@ -2527,6 +2553,7 @@ Returns: trim_space :: proc(s: string) -> (res: string) { return trim_right_space(trim_left_space(s)) } + /* Trims null runes from the left, "\x00\x00testing\x00\x00" -> "testing\x00\x00" @@ -2539,6 +2566,7 @@ Returns: trim_left_null :: proc(s: string) -> (res: string) { return trim_left_proc(s, is_null) } + /* Trims null runes from the right, "\x00\x00testing\x00\x00" -> "\x00\x00testing" @@ -2551,6 +2579,7 @@ Returns: trim_right_null :: proc(s: string) -> (res: string) { return trim_right_proc(s, is_null) } + /* Trims null runes from both sides, "\x00\x00testing\x00\x00" -> "testing" @@ -2562,6 +2591,7 @@ Returns: trim_null :: proc(s: string) -> (res: string) { return trim_right_null(trim_left_null(s)) } + /* Trims a `prefix` string from the start of the `s` string and returns the trimmed string @@ -2594,6 +2624,7 @@ trim_prefix :: proc(s, prefix: string) -> (res: string) { } return s } + /* Trims a `suffix` string from the end of the `s` string and returns the trimmed string @@ -2626,6 +2657,7 @@ trim_suffix :: proc(s, suffix: string) -> (res: string) { } return s } + /* Splits the input string `s` by all possible `substrs` and returns an allocated array of strings @@ -2698,6 +2730,7 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator assert(len(results) == n) return results[:], nil } + /* Splits the input string `s` by all possible `substrs` in an iterator fashion. The full string is returned if no match. @@ -2757,6 +2790,7 @@ split_multi_iterate :: proc(it: ^string, substrs: []string) -> (res: string, ok: ok = true return } + /* Replaces invalid UTF-8 characters in the input string with a specified replacement string. Adjacent invalid bytes are only replaced once. @@ -2817,6 +2851,7 @@ scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> return to_string(b), nil } + /* Reverses the input string `s` @@ -2860,6 +2895,7 @@ reverse :: proc(s: string, allocator := context.allocator, loc := #caller_locati } return string(buf), nil } + /* Expands the input string by replacing tab characters with spaces to align to a specified tab size @@ -2891,6 +2927,7 @@ Output: abc1 abc2 abc3 */ + expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> (res: string, err: mem.Allocator_Error) #optional_allocator_error { if tab_size <= 0 { panic("tab size must be positive") @@ -2932,6 +2969,7 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) -> return to_string(b), nil } + /* Splits the input string `str` by the separator `sep` string and returns 3 parts. The values are slices of the original string. @@ -2982,8 +3020,10 @@ partition :: proc(str, sep: string) -> (head, match, tail: string) { tail = str[i+len(sep):] return } + // Alias for centre_justify center_justify :: centre_justify // NOTE(bill): Because Americans exist + /* Centers the input string within a field of specified length by adding pad string on both sides, if its length is less than the target length. @@ -3019,6 +3059,7 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte return to_string(b), nil } + /* Left-justifies the input string within a field of specified length by adding pad string on the right side, if its length is less than the target length. @@ -3044,7 +3085,6 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context pad_len := rune_count(pad) b: Builder - builder_init(&b, allocator) builder_init(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator) or_return w := to_writer(&b) @@ -3054,6 +3094,7 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context return to_string(b), nil } + /* Right-justifies the input string within a field of specified length by adding pad string on the left side, if its length is less than the target length. @@ -3079,7 +3120,6 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex pad_len := rune_count(pad) b: Builder - builder_init(&b, allocator) builder_init(&b, 0, len(str) + (remains/pad_len + 1)*len(pad), allocator) or_return w := to_writer(&b) @@ -3089,6 +3129,7 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex return to_string(b), nil } + /* Writes a given pad string a specified number of times to an `io.Writer` @@ -3115,6 +3156,7 @@ write_pad_string :: proc(w: io.Writer, pad: string, pad_len, remains: int) { p = p[width:] } } + /* Splits a string into a slice of substrings at each instance of one or more consecutive white space characters, as defined by `unicode.is_space` @@ -3176,6 +3218,7 @@ fields :: proc(s: string, allocator := context.allocator, loc := #caller_locatio } return a, nil } + /* Splits a string into a slice of substrings at each run of unicode code points `r` satisfying the predicate `f(r)` @@ -3218,6 +3261,7 @@ fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.alloc return substrings[:], nil } + /* Retrieves the first non-space substring from a mutable string reference and advances the reference. `s` is advanced from any space after the substring, or be an empty string if the substring was the remaining characters @@ -3256,6 +3300,7 @@ fields_iterator :: proc(s: ^string) -> (field: string, ok: bool) { s^ = s[len(s):] return } + /* Computes the Levenshtein edit distance between two strings @@ -3433,4 +3478,4 @@ substring_to :: proc(s: string, rune_end: int) -> (sub: string, ok: bool) { } return internal_substring(s, -1, rune_end) -} +} \ No newline at end of file diff --git a/core/sync/chan/chan.odin b/core/sync/chan/chan.odin index c470d15f3..05312e5a2 100644 --- a/core/sync/chan/chan.odin +++ b/core/sync/chan/chan.odin @@ -7,16 +7,70 @@ import "core:mem" import "core:sync" import "core:math/rand" +when ODIN_TEST { +/* +Hook for testing _try_select_raw allowing the test harness to manipulate the +channels prior to the select actually operating on them. +*/ +__try_select_raw_pause : proc() = nil +} + +/* +Determines what operations `Chan` supports. +*/ Direction :: enum { Send = -1, Both = 0, Recv = +1, } +/* +A typed wrapper around `Raw_Chan` which should be used +preferably. + +Note: all procedures accepting `Raw_Chan` also accept `Chan`. + +**Inputs** +- `$T`: The type of the messages +- `Direction`: what `Direction` the channel supports + +Example: + + import "core:sync/chan" + + chan_example :: proc() { + // Create an unbuffered channel with messages of type int, + // supporting both sending and receiving. + // Creating unidirectional channels, although possible, is useless. + c, _ := chan.create(chan.Chan(int), context.allocator) + defer chan.destroy(c) + + // This channel can now only be used for receiving messages + recv_only_channel: chan.Chan(int, .Recv) = chan.as_recv(c) + // This channel can now only be used for sending messages + send_only_channel: chan.Chan(int, .Send) = chan.as_send(c) + } +*/ Chan :: struct($T: typeid, $D: Direction = Direction.Both) { #subtype impl: ^Raw_Chan `fmt:"-"`, } +/* +`Raw_Chan` allows for thread-safe communication using fixed-size messages. +This is the low-level implementation of `Chan`, which does not include +the concept of Direction. + +Example: + + import "core:sync/chan" + + raw_chan_example :: proc() { + // Create an unbuffered channel with messages of type int, + c, _ := chan.create_raw(size_of(int), align_of(int), context.allocator) + defer chan.destroy(c) + } + +*/ Raw_Chan :: struct { // Shared allocator: runtime.Allocator, @@ -29,6 +83,8 @@ Raw_Chan :: struct { r_waiting: int, // guarded by `mutex` w_waiting: int, // guarded by `mutex` + did_read: bool, // lets a sender know if the value was read + // Buffered queue: ^Raw_Queue, @@ -36,12 +92,66 @@ Raw_Chan :: struct { unbuffered_data: rawptr, } +/* +Creates a buffered or unbuffered `Chan` instance. +*Allocates Using Provided Allocator* + +**Inputs** +- `$C`: Type of `Chan` to create +- [`cap`: The capacity of the channel] omit for creating unbuffered channels +- `allocator`: The allocator to use + +**Returns**: +- The initialized `Chan` +- An `Allocator_Error` + +Example: + + import "core:sync/chan" + + create_example :: proc() { + unbuffered: chan.Chan(int) + buffered: chan.Chan(int) + err: runtime.Allocator_Error + + unbuffered, err = chan.create(chan.Chan(int), context.allocator) + assert(err == .None) + defer chan.destroy(unbuffered) + + buffered, err = chan.create(chan.Chan(int), 10, context.allocator) + assert(err == .None) + defer chan.destroy(buffered) + } +*/ create :: proc{ create_unbuffered, create_buffered, } +/* +Creates an unbuffered version of the specified `Chan` type. + +*Allocates Using Provided Allocator* + +**Inputs** +- `$C`: Type of `Chan` to create +- `allocator`: The allocator to use + +**Returns**: +- The initialized `Chan` +- An `Allocator_Error` + +Example: + + import "core:sync/chan" + + create_unbuffered_example :: proc() { + c, err := chan.create_unbuffered(chan.Chan(int), context.allocator) + assert(err == .None) + defer chan.destroy(c) + } +*/ @(require_results) create_unbuffered :: proc($C: typeid/Chan($T), allocator: runtime.Allocator) -> (c: C, err: runtime.Allocator_Error) where size_of(T) <= int(max(u16)) { @@ -49,6 +159,30 @@ create_unbuffered :: proc($C: typeid/Chan($T), allocator: runtime.Allocator) -> return } +/* +Creates a buffered version of the specified `Chan` type. + +*Allocates Using Provided Allocator* + +**Inputs** +- `$C`: Type of `Chan` to create +- `cap`: The capacity of the channel +- `allocator`: The allocator to use + +**Returns**: +- The initialized `Chan` +- An `Allocator_Error` + +Example: + + import "core:sync/chan" + + create_buffered_example :: proc() { + c, err := chan.create_buffered(chan.Chan(int), 10, context.allocator) + assert(err == .None) + defer chan.destroy(c) + } +*/ @(require_results) create_buffered :: proc($C: typeid/Chan($T), #any_int cap: int, allocator: runtime.Allocator) -> (c: C, err: runtime.Allocator_Error) where size_of(T) <= int(max(u16)) { @@ -56,11 +190,70 @@ create_buffered :: proc($C: typeid/Chan($T), #any_int cap: int, allocator: runti return } +/* +Creates a buffered or unbuffered `Raw_Chan` for messages of the specified +size and alignment. + +*Allocates Using Provided Allocator* + +**Inputs** +- `msg_size`: The size of the messages the messages being sent +- `msg_alignment`: The alignment of the messages being sent +- [`cap`: The capacity of the channel] omit for creating unbuffered channels +- `allocator`: The allocator to use + +**Returns**: +- The initialized `Raw_Chan` +- An `Allocator_Error` + +Example: + + import "core:sync/chan" + + create_raw_example :: proc() { + unbuffered: ^chan.Raw_Chan + buffered: ^chan.Raw_Chan + err: runtime.Allocator_Error + + unbuffered, err = chan.create_raw(size_of(int), align_of(int), context.allocator) + assert(err == .None) + defer chan.destroy(unbuffered) + + buffered, err = chan.create_raw(size_of(int), align_of(int), 10, context.allocator) + assert(err == .None) + defer chan.destroy(buffered) + } +*/ create_raw :: proc{ create_raw_unbuffered, create_raw_buffered, } +/* +Creates an unbuffered `Raw_Chan` for messages of the specified +size and alignment. + +*Allocates Using Provided Allocator* + +**Inputs** +- `msg_size`: The size of the messages the messages being sent +- `msg_alignment`: The alignment of the messages being sent +- `allocator`: The allocator to use + +**Returns**: +- The initialized `Raw_Chan` +- An `Allocator_Error` + +Example: + + import "core:sync/chan" + + create_raw_unbuffered_example :: proc() { + unbuffered, err := chan.create_raw(size_of(int), align_of(int), context.allocator) + assert(err == .None) + defer chan.destroy(unbuffered) + } +*/ @(require_results) create_raw_unbuffered :: proc(#any_int msg_size, msg_alignment: int, allocator: runtime.Allocator) -> (c: ^Raw_Chan, err: runtime.Allocator_Error) { assert(msg_size <= int(max(u16))) @@ -80,6 +273,32 @@ create_raw_unbuffered :: proc(#any_int msg_size, msg_alignment: int, allocator: return } +/* +Creates a buffered `Raw_Chan` for messages of the specified +size and alignment. + +*Allocates Using Provided Allocator* + +**Inputs** +- `msg_size`: The size of the messages the messages being sent +- `msg_alignment`: The alignment of the messages being sent +- `cap`: The capacity of the channel +- `allocator`: The allocator to use + +**Returns**: +- The initialized `Raw_Chan` +- An `Allocator_Error` + +Example: + + import "core:sync/chan" + + create_raw_unbuffered_example :: proc() { + c, err := chan.create_raw_buffered(size_of(int), align_of(int), 10, context.allocator) + assert(err == .None) + defer chan.destroy(c) + } +*/ @(require_results) create_raw_buffered :: proc(#any_int msg_size, msg_alignment: int, #any_int cap: int, allocator: runtime.Allocator) -> (c: ^Raw_Chan, err: runtime.Allocator_Error) { assert(msg_size <= int(max(u16))) @@ -110,6 +329,16 @@ create_raw_buffered :: proc(#any_int msg_size, msg_alignment: int, #any_int cap: return } + +/* +Destroys the Channel. + +**Inputs** +- `c`: The channel to destroy + +**Returns**: +- An `Allocator_Error` +*/ destroy :: proc(c: ^Raw_Chan) -> (err: runtime.Allocator_Error) { if c != nil { allocator := c.allocator @@ -118,22 +347,142 @@ destroy :: proc(c: ^Raw_Chan) -> (err: runtime.Allocator_Error) { return } +/* +Creates a version of a channel that can only be used for sending +not receiving. + +**Inputs** +- `c`: The channel + +**Returns**: +- An `Allocator_Error` + +Example: + + import "core:sync/chan" + + as_send_example :: proc() { + // this procedure takes a channel that can only + // be used for sending not receiving. + producer :: proc(c: chan.Chan(int, .Send)) { + chan.send(c, 112) + + // compile-time error: + // value, ok := chan.recv(c) + } + + c, err := chan.create(chan.Chan(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + producer(chan.as_send(c)) + } +*/ @(require_results) as_send :: #force_inline proc "contextless" (c: $C/Chan($T, $D)) -> (s: Chan(T, .Send)) where C.D <= .Both { return transmute(type_of(s))c } + +/* +Creates a version of a channel that can only be used for receiving +not sending. + +**Inputs** +- `c`: The channel + +**Returns**: +- An `Allocator_Error` + +Example: + + import "core:sync/chan" + + as_recv_example :: proc() { + consumer :: proc(c: chan.Chan(int, .Recv)) { + value, ok := chan.recv(c) + + // compile-time error: + // chan.send(c, 22) + } + + c, err := chan.create(chan.Chan(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + chan.send(c, 112) + consumer(chan.as_recv(c)) + } +*/ @(require_results) as_recv :: #force_inline proc "contextless" (c: $C/Chan($T, $D)) -> (r: Chan(T, .Recv)) where C.D >= .Both { return transmute(type_of(r))c } +/* +Sends the specified message, blocking the current thread if: +- the channel is unbuffered +- the channel's buffer is full +until the channel is being read from or the channel is closed. `send` will +return `false` when attempting to send on an already closed channel. +**Inputs** +- `c`: The channel +- `data`: The message to send + +**Returns** +- `true` if the message was sent, `false` when the channel was already closed + +Example: + + import "core:sync/chan" + + send_example :: proc() { + c, err := chan.create(chan.Chan(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + assert(chan.send(c, 2)) + + // this would block since the channel has a buffersize of 1 + // assert(chan.send(c, 2)) + + // sending on a closed channel returns false + chan.close(c) + assert(! chan.send(c, 2)) + } +*/ send :: proc "contextless" (c: $C/Chan($T, $D), data: T) -> (ok: bool) where C.D <= .Both { data := data ok = send_raw(c, &data) return } +/* +Tries sending the specified message which is: +- blocking: given the channel is unbuffered +- non-blocking: given the channel is buffered + +**Inputs** +- `c`: The channel +- `data`: The message to send + +**Returns** +- `true` if the message was sent, `false` when the channel was +already closed or the channel's buffer was full + +Example: + + import "core:sync/chan" + + try_send_example :: proc() { + c, err := chan.create(chan.Chan(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + assert(chan.try_send(c, 2), "there is enough space") + assert(!chan.try_send(c, 2), "the buffer is already full") + } +*/ @(require_results) try_send :: proc "contextless" (c: $C/Chan($T, $D), data: T) -> (ok: bool) where C.D <= .Both { data := data @@ -141,6 +490,44 @@ try_send :: proc "contextless" (c: $C/Chan($T, $D), data: T) -> (ok: bool) where return } +/* +Reads a message from the channel, blocking the current thread if: +- the channel is unbuffered +- the channel's buffer is empty +until the channel is being written to or the channel is closed. `recv` will +return `false` when attempting to receive a message on an already closed +channel. + +**Inputs** +- `c`: The channel + +**Returns** +- The message +- `true` if a message was received, `false` when the channel was already closed + +Example: + + import "core:sync/chan" + + recv_example :: proc() { + c, err := chan.create(chan.Chan(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + assert(chan.send(c, 2)) + + value, ok := chan.recv(c) + assert(ok, "the value was received") + + // this would block since the channel is now empty + // value, ok = chan.recv(c) + + // reading from a closed channel returns false + chan.close(c) + value, ok = chan.recv(c) + assert(!ok, "the channel is closed") + } +*/ @(require_results) recv :: proc "contextless" (c: $C/Chan($T)) -> (data: T, ok: bool) where C.D >= .Both { ok = recv_raw(c, &data) @@ -148,6 +535,29 @@ recv :: proc "contextless" (c: $C/Chan($T)) -> (data: T, ok: bool) where C.D >= } +/* +Tries reading a message from the channel in a non-blocking fashion. + +**Inputs** +- `c`: The channel + +**Returns** +- The message +- `true` if a message was received, `false` when the channel was already closed or no message was available + +Example: + + import "core:sync/chan" + + try_recv_example :: proc() { + c, err := chan.create(chan.Chan(int), context.allocator) + assert(err == .None) + defer chan.destroy(c) + + _, ok := chan.try_recv(c) + assert(!ok, "there is not value to read") + } +*/ @(require_results) try_recv :: proc "contextless" (c: $C/Chan($T)) -> (data: T, ok: bool) where C.D >= .Both { ok = try_recv_raw(c, &data) @@ -155,6 +565,43 @@ try_recv :: proc "contextless" (c: $C/Chan($T)) -> (data: T, ok: bool) where C.D } +/* +Sends the specified message, blocking the current thread if: +- the channel is unbuffered +- the channel's buffer is full +until the channel is being read from or the channel is closed. `send_raw` will +return `false` when attempting to send on an already closed channel. + +Note: The message referenced by `msg_out` must match the size +and alignment used when the `Raw_Chan` was created. + +**Inputs** +- `c`: The channel +- `msg_out`: Pointer to the data to send + +**Returns** +- `true` if the message was sent, `false` when the channel was already closed + +Example: + + import "core:sync/chan" + + send_raw_example :: proc() { + c, err := chan.create_raw(size_of(int), align_of(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + value := 2 + assert(chan.send_raw(c, &value)) + + // this would block since the channel has a buffersize of 1 + // assert(chan.send_raw(c, &value)) + + // sending on a closed channel returns false + chan.close(c) + assert(! chan.send_raw(c, &value)) + } +*/ @(require_results) send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool) { if c == nil { @@ -183,17 +630,68 @@ send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool) { return false } + c.did_read = false + defer c.did_read = false + mem.copy(c.unbuffered_data, msg_in, int(c.msg_size)) + c.w_waiting += 1 + if c.r_waiting > 0 { sync.signal(&c.r_cond) } + sync.wait(&c.w_cond, &c.mutex) + + if c.closed && !c.did_read { + return false + } + ok = true } return } +/* +Reads a message from the channel, blocking the current thread if: +- the channel is unbuffered +- the channel's buffer is empty +until the channel is being written to or the channel is closed. `recv_raw` +will return `false` when attempting to receive a message on an already closed +channel. + +Note: The location pointed to by `msg_out` must match the size +and alignment used when the `Raw_Chan` was created. + +**Inputs** +- `c`: The channel +- `msg_out`: Pointer to where the message should be stored + +**Returns** +- `true` if a message was received, `false` when the channel was already closed + +Example: + + import "core:sync/chan" + + recv_raw_example :: proc() { + c, err := chan.create_raw(size_of(int), align_of(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + value := 2 + assert(chan.send_raw(c, &value)) + + assert(chan.recv_raw(c, &value)) + + // this would block since the channel is now empty + // assert(chan.recv_raw(c, &value)) + + // reading from a closed channel returns false + chan.close(c) + assert(! chan.recv_raw(c, &value)) + } +*/ @(require_results) recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) { if c == nil { @@ -223,8 +721,7 @@ recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) { } else if c.unbuffered_data != nil { // unbuffered sync.guard(&c.mutex) - for !c.closed && - c.w_waiting == 0 { + for !c.closed && c.w_waiting == 0 { c.r_waiting += 1 sync.wait(&c.r_cond, &c.mutex) c.r_waiting -= 1 @@ -237,6 +734,7 @@ recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) { mem.copy(msg_out, c.unbuffered_data, int(c.msg_size)) c.w_waiting -= 1 + c.did_read = true sync.signal(&c.w_cond) ok = true } @@ -244,6 +742,36 @@ recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> (ok: bool) { } +/* +Tries sending the specified message which is: +- blocking: given the channel is unbuffered +- non-blocking: given the channel is buffered + +Note: The message referenced by `msg_out` must match the size +and alignment used when the `Raw_Chan` was created. + +**Inputs** +- `c`: the channel +- `msg_out`: pointer to the data to send + +**Returns** +- `true` if the message was sent, `false` when the channel was +already closed or the channel's buffer was full + +Example: + + import "core:sync/chan" + + try_send_raw_example :: proc() { + c, err := chan.create_raw(size_of(int), align_of(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + value := 2 + assert(chan.try_send_raw(c, &value), "there is enough space") + assert(!chan.try_send_raw(c, &value), "the buffer is already full") + } +*/ @(require_results) try_send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool) { if c == nil { @@ -266,7 +794,7 @@ try_send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool) } else if c.unbuffered_data != nil { // unbuffered sync.guard(&c.mutex) - if c.closed { + if c.closed || c.r_waiting - c.w_waiting <= 0 { return false } @@ -281,6 +809,32 @@ try_send_raw :: proc "contextless" (c: ^Raw_Chan, msg_in: rawptr) -> (ok: bool) return } +/* +Reads a message from the channel if one is available. + +Note: The location pointed to by `msg_out` must match the size +and alignment used when the `Raw_Chan` was created. + +**Inputs** +- `c`: The channel +- `msg_out`: Pointer to where the message should be stored + +**Returns** +- `true` if a message was received, `false` when the channel was already closed or no message was available + +Example: + + import "core:sync/chan" + + try_recv_raw_example :: proc() { + c, err := chan.create_raw(size_of(int), align_of(int), context.allocator) + assert(err == .None) + defer chan.destroy(c) + + value: int + assert(!chan.try_recv_raw(c, &value)) + } +*/ @(require_results) try_recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> bool { if c == nil { @@ -304,7 +858,7 @@ try_recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> bool { } else if c.unbuffered_data != nil { // unbuffered sync.guard(&c.mutex) - if c.closed || c.w_waiting == 0 { + if c.closed || c.w_waiting - c.r_waiting <= 0 { return false } @@ -319,16 +873,85 @@ try_recv_raw :: proc "contextless" (c: ^Raw_Chan, msg_out: rawptr) -> bool { +/* +Checks if the given channel is buffered. + +**Inputs** +- `c`: The channel + +**Returns**: +- `true` if the channel is buffered, `false` otherwise + +Example: + + import "core:sync/chan" + + is_buffered_example :: proc() { + c, _ := chan.create(chan.Chan(int), 1, context.allocator) + defer chan.destroy(c) + assert(chan.is_buffered(c)) + } +*/ @(require_results) is_buffered :: proc "contextless" (c: ^Raw_Chan) -> bool { return c != nil && c.queue != nil } +/* +Checks if the given channel is unbuffered. + +**Inputs** +- `c`: The channel + +**Returns**: +- `true` if the channel is unbuffered, `false` otherwise + +Example: + + import "core:sync/chan" + + is_buffered_example :: proc() { + c, _ := chan.create(chan.Chan(int), context.allocator) + defer chan.destroy(c) + assert(chan.is_unbuffered(c)) + } +*/ @(require_results) is_unbuffered :: proc "contextless" (c: ^Raw_Chan) -> bool { return c != nil && c.unbuffered_data != nil } +/* +Returns the number of elements currently in the channel. + +Note: Unbuffered channels will always return `0` +because they cannot hold elements. + +**Inputs** +- `c`: The channel + +**Returns**: +- Number of elements + +Example: + + import "core:sync/chan" + import "core:fmt" + + len_example :: proc() { + c, _ := chan.create(chan.Chan(int), 2, context.allocator) + defer chan.destroy(c) + + fmt.println(chan.len(c)) + assert(chan.send(c, 1)) // add an element + fmt.println(chan.len(c)) + } + +Output: + + 0 + 1 +*/ @(require_results) len :: proc "contextless" (c: ^Raw_Chan) -> int { if c != nil && c.queue != nil { @@ -338,6 +961,34 @@ len :: proc "contextless" (c: ^Raw_Chan) -> int { return 0 } +/* +Returns the number of elements the channel could hold. + +Note: Unbuffered channels will always return `0` +because they cannot hold elements. + +**Inputs** +- `c`: The channel + +**Returns**: +- Number of elements + +Example: + + import "core:sync/chan" + import "core:fmt" + + cap_example :: proc() { + c, _ := chan.create(chan.Chan(int), 2, context.allocator) + defer chan.destroy(c) + + fmt.println(chan.cap(c)) + } + +Output: + + 2 +*/ @(require_results) cap :: proc "contextless" (c: ^Raw_Chan) -> int { if c != nil && c.queue != nil { @@ -347,6 +998,36 @@ cap :: proc "contextless" (c: ^Raw_Chan) -> int { return 0 } +/* +Closes the channel, preventing new messages from being added. + +**Inputs** +- `c`: The channel + +**Returns**: +- `true` if the channel was closed by this operation, `false` if it was already closed + +Example: + + import "core:sync/chan" + + close_example :: proc() { + c, _ := chan.create(chan.Chan(int), 2, context.allocator) + defer chan.destroy(c) + + // Sending a message to an open channel + assert(chan.send(c, 1), "allowed to send") + + // Closing the channel successfully + assert(chan.close(c), "successfully closed") + + // Trying to send a message after the channel is closed (should fail) + assert(!chan.send(c, 1), "not allowed to send after close") + + // Trying to close the channel again (should fail since it's already closed) + assert(!chan.close(c), "was already closed") + } +*/ close :: proc "contextless" (c: ^Raw_Chan) -> bool { if c == nil { return false @@ -361,6 +1042,15 @@ close :: proc "contextless" (c: ^Raw_Chan) -> bool { return true } +/* +Returns if the channel is closed or not + +**Inputs** +- `c`: The channel + +**Returns**: +- `true` if the channel is closed, `false` otherwise +*/ @(require_results) is_closed :: proc "contextless" (c: ^Raw_Chan) -> bool { if c == nil { @@ -370,9 +1060,230 @@ is_closed :: proc "contextless" (c: ^Raw_Chan) -> bool { return bool(c.closed) } +/* +Returns whether a message can be read without blocking the current +thread. Specifically, it checks if the channel is buffered and not full, +or if there is already a writer attempting to send a message. + +**Inputs** +- `c`: The channel + +**Returns** +- `true` if a message can be read, `false` otherwise + +Example: + + import "core:sync/chan" + + can_recv_example :: proc() { + c, err := chan.create(chan.Chan(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + assert(!chan.can_recv(c), "the cannel is empty") + assert(chan.send(c, 2)) + assert(chan.can_recv(c), "there is message to read") + } +*/ +@(require_results) +can_recv :: proc "contextless" (c: ^Raw_Chan) -> bool { + sync.guard(&c.mutex) + if is_buffered(c) { + return c.queue.len > 0 + } + return c.w_waiting - c.r_waiting > 0 +} +/* +Returns whether a message can be sent without blocking the current +thread. Specifically, it checks if the channel is buffered and not full, +or if there is already a reader waiting for a message. +**Inputs** +- `c`: The channel + +**Returns** +- `true` if a message can be sent, `false` otherwise + +Example: + + import "core:sync/chan" + + can_send_example :: proc() { + c, err := chan.create(chan.Chan(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + assert(chan.can_send(c), "the channel's buffer is not full") + assert(chan.send(c, 2)) + assert(!chan.can_send(c), "the channel's buffer is full") + } +*/ +@(require_results) +can_send :: proc "contextless" (c: ^Raw_Chan) -> bool { + sync.guard(&c.mutex) + if is_buffered(c) { + return c.queue.len < c.queue.cap + } + return c.r_waiting - c.w_waiting > 0 +} + +/* +Specifies the direction of the selected channel. +*/ +Select_Status :: enum { + None, + Recv, + Send, +} + + +/* +Attempts to either send or receive messages on the specified channels without blocking. + +`try_select_raw` first identifies which channels have messages ready to be received +and which are available for sending. It then randomly selects one operation +(either a send or receive) to perform. + +If no channels have messages ready, the procedure is a noop. + +Note: Each message in `send_msgs` corresponds to the send channel at the same index in `sends`. +If the message is nil, corresponding send channel will be skipped. + +**Inputs** +- `recv`: A slice of channels to read from +- `sends`: A slice of channels to send messages on +- `send_msgs`: A slice of messages to send +- `recv_out`: A pointer to the location where, when receiving, the message should be stored + +**Returns** +- Position of the available channel which was used for receiving or sending +- `true` if sending/receiving was successfull, `false` if the channel was closed or no channel was available + +Example: + + import "core:sync/chan" + import "core:fmt" + + select_raw_example :: proc() { + c, err := chan.create(chan.Chan(int), 1, context.allocator) + assert(err == .None) + defer chan.destroy(c) + + // sending value '1' on the channel + value1 := 1 + msgs := [?]rawptr{&value1} + send_chans := [?]^chan.Raw_Chan{c} + + // for simplicity the same channel used for sending is also used for receiving + receive_chans := [?]^chan.Raw_Chan{c} + // where the value from the read should be stored + received_value: int + + idx, ok := chan.try_select_raw(receive_chans[:], send_chans[:], msgs[:], &received_value) + fmt.println("SELECT: ", idx, ok) + fmt.println("RECEIVED VALUE ", received_value) + + idx, ok = chan.try_select_raw(receive_chans[:], send_chans[:], msgs[:], &received_value) + fmt.println("SELECT: ", idx, ok) + fmt.println("RECEIVED VALUE ", received_value) + + // closing of a channel also affects the select operation + chan.close(c) + + idx, ok = chan.try_select_raw(receive_chans[:], send_chans[:], msgs[:], &received_value) + fmt.println("SELECT: ", idx, ok) + } + +Output: + + SELECT: 0 true + RECEIVED VALUE 0 + SELECT: 0 true + RECEIVED VALUE 1 + SELECT: 0 false + +*/ +@(require_results) +try_select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs: []rawptr, recv_out: rawptr) -> (select_idx: int, status: Select_Status) #no_bounds_check { + Select_Op :: struct { + idx: int, // local to the slice that was given + is_recv: bool, + } + + candidate_count := builtin.len(recvs)+builtin.len(sends) + candidates := ([^]Select_Op)(intrinsics.alloca(candidate_count*size_of(Select_Op), align_of(Select_Op))) + + try_loop: for { + count := 0 + + for c, i in recvs { + if can_recv(c) { + candidates[count] = { + is_recv = true, + idx = i, + } + count += 1 + } + } + + for c, i in sends { + if i > builtin.len(send_msgs)-1 || send_msgs[i] == nil { + continue + } + if can_send(c) { + candidates[count] = { + is_recv = false, + idx = i, + } + count += 1 + } + } + + if count == 0 { + return -1, .None + } + + when ODIN_TEST { + if __try_select_raw_pause != nil { + __try_select_raw_pause() + } + } + + candidate_idx := rand.int_max(count) if count > 0 else 0 + + sel := candidates[candidate_idx] + if sel.is_recv { + status = .Recv + if !try_recv_raw(recvs[sel.idx], recv_out) { + continue try_loop + } + } else { + status = .Send + if !try_send_raw(sends[sel.idx], send_msgs[sel.idx]) { + continue try_loop + } + } + + return sel.idx, status + } +} + +@(require_results, deprecated = "use try_select_raw") +select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs: []rawptr, recv_out: rawptr) -> (select_idx: int, status: Select_Status) #no_bounds_check { + return try_select_raw(recvs, sends, send_msgs, recv_out) +} + +/* +`Raw_Queue` is a non-thread-safe queue implementation designed to store messages +of fixed size and alignment. + +Note: For most use cases, it is recommended to use `core:container/queue` instead, +as `Raw_Queue` is used internally by `Raw_Chan` and may not provide the desired +level of convenience for typical applications. +*/ +@(private) Raw_Queue :: struct { data: [^]byte, len: int, @@ -381,6 +1292,28 @@ Raw_Queue :: struct { size: int, // element size } +/* +Initializes a `Raw_Queue` + +**Inputs** +- `q`: A pointert to the `Raw_Queue` to initialize +- `data`: The pointer to backing slice storing the messages +- `cap`: The capacity of the queue +- `size`: The size of a message + +Example: + + import "core:sync/chan" + + raw_queue_init_example :: proc() { + // use a stack allocated array as backing storage + storage: [100]int + + rq: chan.Raw_Queue + chan.raw_queue_init(&rq, &storage, cap(storage), size_of(int)) + } +*/ +@(private) raw_queue_init :: proc "contextless" (q: ^Raw_Queue, data: rawptr, cap: int, size: int) { q.data = ([^]byte)(data) q.len = 0 @@ -389,8 +1322,33 @@ raw_queue_init :: proc "contextless" (q: ^Raw_Queue, data: rawptr, cap: int, siz q.size = size } +/* +Add an element to the queue. -@(require_results) +Note: The message referenced by `data` must match the size +and alignment used when the `Raw_Queue` was initialized. + +**Inputs** +- `q`: A pointert to the `Raw_Queue` +- `data`: The pointer to message to add + +**Returns** +- `true` if the element was added, `false` when the queue is already full + +Example: + + import "core:sync/chan" + + raw_queue_push_example :: proc() { + storage: [100]int + rq: chan.Raw_Queue + chan.raw_queue_init(&rq, &storage, cap(storage), size_of(int)) + + value := 2 + assert(chan.raw_queue_push(&rq, &value), "there was enough space") + } +*/ +@(private, require_results) raw_queue_push :: proc "contextless" (q: ^Raw_Queue, data: rawptr) -> bool { if q.len == q.cap { return false @@ -406,7 +1364,38 @@ raw_queue_push :: proc "contextless" (q: ^Raw_Queue, data: rawptr) -> bool { return true } -@(require_results) +/* +Removes and returns the first element of the queue. + +Note: The returned element is only guaranteed to be valid until the next +`raw_queue_push` operation. Accessing it after that point may result in +undefined behavior. + +**Inputs** +- `c`: A pointer to the `Raw_Queue`. + +**Returns** +- A pointer to the first element in the queue, or `nil` if the queue is empty. + +Example: + + import "core:sync/chan" + + raw_queue_pop_example :: proc() { + storage: [100]int + rq: chan.Raw_Queue + chan.raw_queue_init(&rq, &storage, cap(storage), size_of(int)) + + assert(chan.raw_queue_pop(&rq) == nil, "queue was empty") + + // add an element to the queue + value := 2 + assert(chan.raw_queue_push(&rq, &value), "there was enough space") + + assert((cast(^int)chan.raw_queue_pop(&rq))^ == 2, "retrieved the element") + } +*/ +@(private, require_results) raw_queue_pop :: proc "contextless" (q: ^Raw_Queue) -> (data: rawptr) { if q.len > 0 { data = q.data[q.next*q.size:] @@ -418,71 +1407,3 @@ raw_queue_pop :: proc "contextless" (q: ^Raw_Queue) -> (data: rawptr) { } return } - - -@(require_results) -can_recv :: proc "contextless" (c: ^Raw_Chan) -> bool { - sync.guard(&c.mutex) - if is_buffered(c) { - return c.queue.len > 0 - } - return c.w_waiting > 0 -} - - -@(require_results) -can_send :: proc "contextless" (c: ^Raw_Chan) -> bool { - sync.guard(&c.mutex) - if is_buffered(c) { - return c.queue.len < c.queue.cap - } - return c.w_waiting == 0 -} - - - -@(require_results) -select_raw :: proc "odin" (recvs: []^Raw_Chan, sends: []^Raw_Chan, send_msgs: []rawptr, recv_out: rawptr) -> (select_idx: int, ok: bool) #no_bounds_check { - Select_Op :: struct { - idx: int, // local to the slice that was given - is_recv: bool, - } - - candidate_count := builtin.len(recvs)+builtin.len(sends) - candidates := ([^]Select_Op)(intrinsics.alloca(candidate_count*size_of(Select_Op), align_of(Select_Op))) - count := 0 - - for c, i in recvs { - if can_recv(c) { - candidates[count] = { - is_recv = true, - idx = i, - } - count += 1 - } - } - - for c, i in sends { - if can_send(c) { - candidates[count] = { - is_recv = false, - idx = i, - } - count += 1 - } - } - - if count == 0 { - return - } - - select_idx = rand.int_max(count) if count > 0 else 0 - - sel := candidates[select_idx] - if sel.is_recv { - ok = recv_raw(recvs[sel.idx], recv_out) - } else { - ok = send_raw(sends[sel.idx], send_msgs[sel.idx]) - } - return -} diff --git a/core/sync/chan/doc.odin b/core/sync/chan/doc.odin new file mode 100644 index 000000000..5d65d7410 --- /dev/null +++ b/core/sync/chan/doc.odin @@ -0,0 +1,69 @@ +/* +This package provides both high-level and low-level channel types +for thread-safe communication. + +While channels are essentially thread-safe queues under the hood, +their primary purpose is to facilitate safe communication between +multiple readers and multiple writers. +Although they can be used like queues, channels are designed with +synchronization and concurrent messaging patterns in mind. + +Provided types: +- `Chan` a high level channel +- `Raw_Chan` a low level channel +- `Raw_Queue` a low level non-threadsafe queue implementation used internally + +Example: + + import "core:sync/chan" + import "core:fmt" + import "core:thread" + + // The consumer reads from the channel until it's closed. + // Closing the channel acts as a signal to stop. + consumer :: proc(recv_chan: chan.Chan(int, .Recv)) { + for { + value, ok := chan.recv(recv_chan) + if !ok { + break // More idiomatic than return here + } + fmt.println("[CONSUMER] Received:", value) + } + fmt.println("[CONSUMER] Channel closed, stopping.") + } + + // The producer sends `count` number of messages. + producer :: proc(send_chan: chan.Chan(int, .Send), count: int) { + for i in 0.. bool { Atomic_RW_Mutex_State :: distinct uint -Atomic_RW_Mutex_State_Half_Width :: size_of(Atomic_RW_Mutex_State)*8/2 -Atomic_RW_Mutex_State_Is_Writing :: Atomic_RW_Mutex_State(1) -Atomic_RW_Mutex_State_Writer :: Atomic_RW_Mutex_State(1)<<1 -Atomic_RW_Mutex_State_Reader :: Atomic_RW_Mutex_State(1)< bool { if atomic_mutex_try_lock(&rw.mutex) { state := atomic_load(&rw.state) if state & Atomic_RW_Mutex_State_Reader_Mask == 0 { - _ = atomic_or(&rw.state, Atomic_RW_Mutex_State_Is_Writing) - return true + // Compare-and-exchange for absolute certainty that no one has come in to read. + _, ok := atomic_compare_exchange_strong(&rw.state, state, state | Atomic_RW_Mutex_State_Is_Writing) + if ok { + return true + } } + // A reader is active or came in while we have the lock, so we need to + // back out. atomic_mutex_unlock(&rw.mutex) } return false @@ -150,16 +157,22 @@ atomic_rw_mutex_try_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool { // atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers) atomic_rw_mutex_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) { state := atomic_load(&rw.state) - for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 { + for state & Atomic_RW_Mutex_State_Is_Writing == 0 { ok: bool state, ok = atomic_compare_exchange_weak(&rw.state, state, state + Atomic_RW_Mutex_State_Reader) if ok { + // We succesfully took the shared reader lock without any writers intervening. return } } + // A writer is active or came in while we were trying to get a shared + // reader lock, so now we must take the full lock in order to wait for the + // writer to give it up. atomic_mutex_lock(&rw.mutex) + // At this point, we have the lock, so we can add to the reader count. _ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Reader) + // Then we give up the lock to let other readers (or writers) come through. atomic_mutex_unlock(&rw.mutex) } @@ -169,6 +182,8 @@ atomic_rw_mutex_shared_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) { if (state & Atomic_RW_Mutex_State_Reader_Mask == Atomic_RW_Mutex_State_Reader) && (state & Atomic_RW_Mutex_State_Is_Writing != 0) { + // We were the last reader, so post to the writer with the lock who's + // waiting to continue. atomic_sema_post(&rw.sema) } } @@ -176,12 +191,21 @@ atomic_rw_mutex_shared_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) { // atomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers) atomic_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool { state := atomic_load(&rw.state) - if state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 { - _, ok := atomic_compare_exchange_strong(&rw.state, state, state + Atomic_RW_Mutex_State_Reader) + // NOTE: We need to check this in a for loop, because it is possible for + // another reader to change the underlying state which would cause our + // compare-and-exchange to fail. + for state & (Atomic_RW_Mutex_State_Is_Writing) == 0 { + ok: bool + state, ok = atomic_compare_exchange_weak(&rw.state, state, state + Atomic_RW_Mutex_State_Reader) if ok { return true } } + // A writer is active or came in during our lock attempt. + + // We try to take the full lock, and if that succeeds (perhaps because the + // writer finished during the time since we failed our CAS), we increment + // the reader count and head on. if atomic_mutex_try_lock(&rw.mutex) { _ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Reader) atomic_mutex_unlock(&rw.mutex) diff --git a/core/sync/primitives_darwin.odin b/core/sync/primitives_darwin.odin index 141cea744..4ae4b7789 100644 --- a/core/sync/primitives_darwin.odin +++ b/core/sync/primitives_darwin.odin @@ -5,7 +5,7 @@ package sync import "core:c" import "base:intrinsics" -foreign import pthread "system:System.framework" +foreign import pthread "system:System" _current_thread_id :: proc "contextless" () -> int { tid: u64 diff --git a/core/sys/darwin/CoreFoundation/CFString.odin b/core/sys/darwin/CoreFoundation/CFString.odin index 24485a494..d245ba793 100644 --- a/core/sys/darwin/CoreFoundation/CFString.odin +++ b/core/sys/darwin/CoreFoundation/CFString.odin @@ -1,10 +1,12 @@ package CoreFoundation +import "core:c" + foreign import CoreFoundation "system:CoreFoundation.framework" String :: distinct TypeRef // same as CFStringRef -StringEncoding :: distinct u32 +StringEncoding :: distinct c.long StringBuiltInEncodings :: enum StringEncoding { MacRoman = 0, @@ -171,7 +173,7 @@ foreign CoreFoundation { // Fetches a range of the characters from a string into a byte buffer after converting the characters to a specified encoding. StringGetBytes :: proc(thestring: String, range: Range, encoding: StringEncoding, lossByte: u8, isExternalRepresentation: b8, buffer: [^]byte, maxBufLen: Index, usedBufLen: ^Index) -> Index --- - StringIsEncodingAvailable :: proc(encoding: StringEncoding) -> bool --- + StringIsEncodingAvailable :: proc(encoding: StringEncoding) -> b8 --- @(link_name = "__CFStringMakeConstantString") StringMakeConstantString :: proc "c" (#const c: cstring) -> String --- diff --git a/core/sys/darwin/Foundation/NSApplication.odin b/core/sys/darwin/Foundation/NSApplication.odin index 254da75ad..a5e9f2e24 100644 --- a/core/sys/darwin/Foundation/NSApplication.odin +++ b/core/sys/darwin/Foundation/NSApplication.odin @@ -82,7 +82,6 @@ Application_setActivationPolicy :: proc "c" (self: ^Application, activationPolic // NOTE: this is technically deprecated but still actively used (Sokol, glfw, SDL, etc.) // and has no clear alternative although `activate` is what Apple tells you to use, // that does not work the same way. -// @(deprecated="Use NSApplication method activate instead.") @(objc_type=Application, objc_name="activateIgnoringOtherApps") Application_activateIgnoringOtherApps :: proc "c" (self: ^Application, ignoreOtherApps: BOOL) { msgSend(nil, self, "activateIgnoringOtherApps:", ignoreOtherApps) @@ -99,7 +98,7 @@ Application_setTitle :: proc "c" (self: ^Application, title: ^String) { } @(objc_type=Application, objc_name="mainMenu") -Window_mainMenu :: proc "c" (self: ^Application) -> ^Menu { +Application_mainMenu :: proc "c" (self: ^Application) -> ^Menu { return msgSend(^Menu, self, "mainMenu") } @@ -256,7 +255,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem return nil } if template.applicationWillFinishLaunching != nil { - applicationWillFinishLaunching :: proc "c" (self: id, notification: ^Notification) { + applicationWillFinishLaunching :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationWillFinishLaunching(notification) @@ -264,7 +263,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationWillFinishLaunching:"), auto_cast applicationWillFinishLaunching, "v@:@") } if template.applicationDidFinishLaunching != nil { - applicationDidFinishLaunching :: proc "c" (self: id, notification: ^Notification) { + applicationDidFinishLaunching :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidFinishLaunching(notification) @@ -272,7 +271,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationDidFinishLaunching:"), auto_cast applicationDidFinishLaunching, "v@:@") } if template.applicationWillBecomeActive != nil { - applicationWillBecomeActive :: proc "c" (self: id, notification: ^Notification) { + applicationWillBecomeActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationWillBecomeActive(notification) @@ -280,7 +279,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationWillBecomeActive:"), auto_cast applicationWillBecomeActive, "v@:@") } if template.applicationDidBecomeActive != nil { - applicationDidBecomeActive :: proc "c" (self: id, notification: ^Notification) { + applicationDidBecomeActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidBecomeActive(notification) @@ -288,7 +287,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationDidBecomeActive:"), auto_cast applicationDidBecomeActive, "v@:@") } if template.applicationWillResignActive != nil { - applicationWillResignActive :: proc "c" (self: id, notification: ^Notification) { + applicationWillResignActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationWillResignActive(notification) @@ -296,7 +295,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationWillResignActive:"), auto_cast applicationWillResignActive, "v@:@") } if template.applicationDidResignActive != nil { - applicationDidResignActive :: proc "c" (self: id, notification: ^Notification) { + applicationDidResignActive :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidResignActive(notification) @@ -304,7 +303,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationDidResignActive:"), auto_cast applicationDidResignActive, "v@:@") } if template.applicationShouldTerminate != nil { - applicationShouldTerminate :: proc "c" (self: id, sender: ^Application) -> ApplicationTerminateReply { + applicationShouldTerminate :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> ApplicationTerminateReply { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationShouldTerminate(sender) @@ -312,7 +311,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationShouldTerminate:"), auto_cast applicationShouldTerminate, _UINTEGER_ENCODING+"@:@") } if template.applicationShouldTerminateAfterLastWindowClosed != nil { - applicationShouldTerminateAfterLastWindowClosed :: proc "c" (self: id, sender: ^Application) -> BOOL { + applicationShouldTerminateAfterLastWindowClosed :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationShouldTerminateAfterLastWindowClosed(sender) @@ -320,7 +319,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationShouldTerminateAfterLastWindowClosed:"), auto_cast applicationShouldTerminateAfterLastWindowClosed, "B@:@") } if template.applicationWillTerminate != nil { - applicationWillTerminate :: proc "c" (self: id, notification: ^Notification) { + applicationWillTerminate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationWillTerminate(notification) @@ -328,7 +327,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationWillTerminate:"), auto_cast applicationWillTerminate, "v@:@") } if template.applicationWillHide != nil { - applicationWillHide :: proc "c" (self: id, notification: ^Notification) { + applicationWillHide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationWillHide(notification) @@ -336,7 +335,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationWillHide:"), auto_cast applicationWillHide, "v@:@") } if template.applicationDidHide != nil { - applicationDidHide :: proc "c" (self: id, notification: ^Notification) { + applicationDidHide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidHide(notification) @@ -344,7 +343,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationDidHide:"), auto_cast applicationDidHide, "v@:@") } if template.applicationWillUnhide != nil { - applicationWillUnhide :: proc "c" (self: id, notification: ^Notification) { + applicationWillUnhide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationWillUnhide(notification) @@ -352,7 +351,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationWillUnhide:"), auto_cast applicationWillUnhide, "v@:@") } if template.applicationDidUnhide != nil { - applicationDidUnhide :: proc "c" (self: id, notification: ^Notification) { + applicationDidUnhide :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidUnhide(notification) @@ -360,7 +359,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationDidUnhide:"), auto_cast applicationDidUnhide, "v@:@") } if template.applicationWillUpdate != nil { - applicationWillUpdate :: proc "c" (self: id, notification: ^Notification) { + applicationWillUpdate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationWillUpdate(notification) @@ -368,7 +367,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationWillUpdate:"), auto_cast applicationWillUpdate, "v@:@") } if template.applicationDidUpdate != nil { - applicationDidUpdate :: proc "c" (self: id, notification: ^Notification) { + applicationDidUpdate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidUpdate(notification) @@ -376,7 +375,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationDidUpdate:"), auto_cast applicationDidUpdate, "v@:@") } if template.applicationShouldHandleReopenHasVisibleWindows != nil { - applicationShouldHandleReopenHasVisibleWindows :: proc "c" (self: id, sender: ^Application, flag: BOOL) -> BOOL { + applicationShouldHandleReopenHasVisibleWindows :: proc "c" (self: id, cmd: SEL, sender: ^Application, flag: BOOL) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationShouldHandleReopenHasVisibleWindows(sender, flag) @@ -384,7 +383,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationShouldHandleReopen:hasVisibleWindows:"), auto_cast applicationShouldHandleReopenHasVisibleWindows, "B@:@B") } if template.applicationDockMenu != nil { - applicationDockMenu :: proc "c" (self: id, sender: ^Application) -> ^Menu { + applicationDockMenu :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> ^Menu { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationDockMenu(sender) @@ -392,7 +391,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationDockMenu:"), auto_cast applicationDockMenu, "@@:@") } if template.applicationShouldAutomaticallyLocalizeKeyEquivalents != nil { - applicationShouldAutomaticallyLocalizeKeyEquivalents :: proc "c" (self: id, application: ^Application) -> BOOL { + applicationShouldAutomaticallyLocalizeKeyEquivalents :: proc "c" (self: id, cmd: SEL, application: ^Application) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationShouldAutomaticallyLocalizeKeyEquivalents(application) @@ -400,7 +399,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationShouldAutomaticallyLocalizeKeyEquivalents:"), auto_cast applicationShouldAutomaticallyLocalizeKeyEquivalents, "B@:@") } if template.applicationWillPresentError != nil { - applicationWillPresentError :: proc "c" (self: id, application: ^Application, error: ^Error) -> ^Error { + applicationWillPresentError :: proc "c" (self: id, cmd: SEL, application: ^Application, error: ^Error) -> ^Error { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationWillPresentError(application, error) @@ -408,7 +407,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:willPresentError:"), auto_cast applicationWillPresentError, "@@:@@") } if template.applicationDidChangeScreenParameters != nil { - applicationDidChangeScreenParameters :: proc "c" (self: id, notification: ^Notification) { + applicationDidChangeScreenParameters :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidChangeScreenParameters(notification) @@ -416,7 +415,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationDidChangeScreenParameters:"), auto_cast applicationDidChangeScreenParameters, "v@:@") } if template.applicationWillContinueUserActivityWithType != nil { - applicationWillContinueUserActivityWithType :: proc "c" (self: id, application: ^Application, userActivityType: ^String) -> BOOL { + applicationWillContinueUserActivityWithType :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivityType: ^String) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationWillContinueUserActivityWithType(application, userActivityType) @@ -424,7 +423,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:willContinueUserActivityWithType:"), auto_cast applicationWillContinueUserActivityWithType, "B@:@@") } if template.applicationContinueUserActivityRestorationHandler != nil { - applicationContinueUserActivityRestorationHandler :: proc "c" (self: id, application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL { + applicationContinueUserActivityRestorationHandler :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivity: ^UserActivity, restorationHandler: ^Block) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationContinueUserActivityRestorationHandler(application, userActivity, restorationHandler) @@ -432,7 +431,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:continueUserActivity:restorationHandler:"), auto_cast applicationContinueUserActivityRestorationHandler, "B@:@@?") } if template.applicationDidFailToContinueUserActivityWithTypeError != nil { - applicationDidFailToContinueUserActivityWithTypeError :: proc "c" (self: id, application: ^Application, userActivityType: ^String, error: ^Error) { + applicationDidFailToContinueUserActivityWithTypeError :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivityType: ^String, error: ^Error) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidFailToContinueUserActivityWithTypeError(application, userActivityType, error) @@ -440,7 +439,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:didFailToContinueUserActivityWithType:error:"), auto_cast applicationDidFailToContinueUserActivityWithTypeError, "v@:@@@") } if template.applicationDidUpdateUserActivity != nil { - applicationDidUpdateUserActivity :: proc "c" (self: id, application: ^Application, userActivity: ^UserActivity) { + applicationDidUpdateUserActivity :: proc "c" (self: id, cmd: SEL, application: ^Application, userActivity: ^UserActivity) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidUpdateUserActivity(application, userActivity) @@ -448,7 +447,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:didUpdateUserActivity:"), auto_cast applicationDidUpdateUserActivity, "v@:@@") } if template.applicationDidRegisterForRemoteNotificationsWithDeviceToken != nil { - applicationDidRegisterForRemoteNotificationsWithDeviceToken :: proc "c" (self: id, application: ^Application, deviceToken: ^Data) { + applicationDidRegisterForRemoteNotificationsWithDeviceToken :: proc "c" (self: id, cmd: SEL, application: ^Application, deviceToken: ^Data) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidRegisterForRemoteNotificationsWithDeviceToken(application, deviceToken) @@ -456,7 +455,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:didRegisterForRemoteNotificationsWithDeviceToken:"), auto_cast applicationDidRegisterForRemoteNotificationsWithDeviceToken, "v@:@@") } if template.applicationDidFailToRegisterForRemoteNotificationsWithError != nil { - applicationDidFailToRegisterForRemoteNotificationsWithError :: proc "c" (self: id, application: ^Application, error: ^Error) { + applicationDidFailToRegisterForRemoteNotificationsWithError :: proc "c" (self: id, cmd: SEL, application: ^Application, error: ^Error) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidFailToRegisterForRemoteNotificationsWithError(application, error) @@ -464,7 +463,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:didFailToRegisterForRemoteNotificationsWithError:"), auto_cast applicationDidFailToRegisterForRemoteNotificationsWithError, "v@:@@") } if template.applicationDidReceiveRemoteNotification != nil { - applicationDidReceiveRemoteNotification :: proc "c" (self: id, application: ^Application, userInfo: ^Dictionary) { + applicationDidReceiveRemoteNotification :: proc "c" (self: id, cmd: SEL, application: ^Application, userInfo: ^Dictionary) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidReceiveRemoteNotification(application, userInfo) @@ -472,7 +471,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:didReceiveRemoteNotification:"), auto_cast applicationDidReceiveRemoteNotification, "v@:@@") } // if template.applicationUserDidAcceptCloudKitShareWithMetadata != nil { - // applicationUserDidAcceptCloudKitShareWithMetadata :: proc "c" (self: id, application: ^Application, metadata: ^CKShareMetadata) { + // applicationUserDidAcceptCloudKitShareWithMetadata :: proc "c" (self: id, cmd: SEL, application: ^Application, metadata: ^CKShareMetadata) { // del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) // context = del._context // del.applicationUserDidAcceptCloudKitShareWithMetadata(application, metadata) @@ -480,7 +479,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem // class_addMethod(class, intrinsics.objc_find_selector("application:userDidAcceptCloudKitShareWithMetadata:"), auto_cast applicationUserDidAcceptCloudKitShareWithMetadata, "v@:@@") // } // if template.applicationHandlerForIntent != nil { - // applicationHandlerForIntent :: proc "c" (self: id, application: ^Application, intent: ^INIntent) -> id { + // applicationHandlerForIntent :: proc "c" (self: id, cmd: SEL, application: ^Application, intent: ^INIntent) -> id { // del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) // context = del._context // return del.applicationHandlerForIntent(application, intent) @@ -488,7 +487,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem // class_addMethod(class, intrinsics.objc_find_selector("application:handlerForIntent:"), auto_cast applicationHandlerForIntent, "@@:@@") // } if template.applicationOpenURLs != nil { - applicationOpenURLs :: proc "c" (self: id, application: ^Application, urls: ^Array) { + applicationOpenURLs :: proc "c" (self: id, cmd: SEL, application: ^Application, urls: ^Array) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationOpenURLs(application, urls) @@ -496,7 +495,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:openURLs:"), auto_cast applicationOpenURLs, "v@:@@") } if template.applicationOpenFile != nil { - applicationOpenFile :: proc "c" (self: id, sender: ^Application, filename: ^String) -> BOOL { + applicationOpenFile :: proc "c" (self: id, cmd: SEL, sender: ^Application, filename: ^String) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationOpenFile(sender, filename) @@ -504,7 +503,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:openFile:"), auto_cast applicationOpenFile, "B@:@@") } if template.applicationOpenFileWithoutUI != nil { - applicationOpenFileWithoutUI :: proc "c" (self: id, sender: id, filename: ^String) -> BOOL { + applicationOpenFileWithoutUI :: proc "c" (self: id, cmd: SEL, sender: id, filename: ^String) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationOpenFileWithoutUI(sender, filename) @@ -512,7 +511,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:openFileWithoutUI:"), auto_cast applicationOpenFileWithoutUI, "B@:@@") } if template.applicationOpenTempFile != nil { - applicationOpenTempFile :: proc "c" (self: id, sender: ^Application, filename: ^String) -> BOOL { + applicationOpenTempFile :: proc "c" (self: id, cmd: SEL, sender: ^Application, filename: ^String) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationOpenTempFile(sender, filename) @@ -520,7 +519,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:openTempFile:"), auto_cast applicationOpenTempFile, "B@:@@") } if template.applicationOpenFiles != nil { - applicationOpenFiles :: proc "c" (self: id, sender: ^Application, filenames: ^Array) { + applicationOpenFiles :: proc "c" (self: id, cmd: SEL, sender: ^Application, filenames: ^Array) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationOpenFiles(sender, filenames) @@ -528,7 +527,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:openFiles:"), auto_cast applicationOpenFiles, "v@:@@") } if template.applicationShouldOpenUntitledFile != nil { - applicationShouldOpenUntitledFile :: proc "c" (self: id, sender: ^Application) -> BOOL { + applicationShouldOpenUntitledFile :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationShouldOpenUntitledFile(sender) @@ -536,7 +535,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationShouldOpenUntitledFile:"), auto_cast applicationShouldOpenUntitledFile, "B@:@") } if template.applicationOpenUntitledFile != nil { - applicationOpenUntitledFile :: proc "c" (self: id, sender: ^Application) -> BOOL { + applicationOpenUntitledFile :: proc "c" (self: id, cmd: SEL, sender: ^Application) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationOpenUntitledFile(sender) @@ -544,7 +543,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationOpenUntitledFile:"), auto_cast applicationOpenUntitledFile, "B@:@") } if template.applicationPrintFile != nil { - applicationPrintFile :: proc "c" (self: id, sender: ^Application, filename: ^String) -> BOOL { + applicationPrintFile :: proc "c" (self: id, cmd: SEL, sender: ^Application, filename: ^String) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationPrintFile(sender, filename) @@ -552,7 +551,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:printFile:"), auto_cast applicationPrintFile, "B@:@@") } if template.applicationPrintFilesWithSettingsShowPrintPanels != nil { - applicationPrintFilesWithSettingsShowPrintPanels :: proc "c" (self: id, application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply { + applicationPrintFilesWithSettingsShowPrintPanels :: proc "c" (self: id, cmd: SEL, application: ^Application, fileNames: ^Array, printSettings: ^Dictionary, showPrintPanels: BOOL) -> ApplicationPrintReply { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationPrintFilesWithSettingsShowPrintPanels(application, fileNames, printSettings, showPrintPanels) @@ -560,7 +559,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:printFiles:withSettings:showPrintPanels:"), auto_cast applicationPrintFilesWithSettingsShowPrintPanels, _UINTEGER_ENCODING+"@:@@@B") } if template.applicationSupportsSecureRestorableState != nil { - applicationSupportsSecureRestorableState :: proc "c" (self: id, app: ^Application) -> BOOL { + applicationSupportsSecureRestorableState :: proc "c" (self: id, cmd: SEL, app: ^Application) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationSupportsSecureRestorableState(app) @@ -568,7 +567,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationSupportsSecureRestorableState:"), auto_cast applicationSupportsSecureRestorableState, "B@:@") } if template.applicationProtectedDataDidBecomeAvailable != nil { - applicationProtectedDataDidBecomeAvailable :: proc "c" (self: id, notification: ^Notification) { + applicationProtectedDataDidBecomeAvailable :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationProtectedDataDidBecomeAvailable(notification) @@ -576,7 +575,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationProtectedDataDidBecomeAvailable:"), auto_cast applicationProtectedDataDidBecomeAvailable, "v@:@") } if template.applicationProtectedDataWillBecomeUnavailable != nil { - applicationProtectedDataWillBecomeUnavailable :: proc "c" (self: id, notification: ^Notification) { + applicationProtectedDataWillBecomeUnavailable :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationProtectedDataWillBecomeUnavailable(notification) @@ -584,7 +583,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationProtectedDataWillBecomeUnavailable:"), auto_cast applicationProtectedDataWillBecomeUnavailable, "v@:@") } if template.applicationWillEncodeRestorableState != nil { - applicationWillEncodeRestorableState :: proc "c" (self: id, app: ^Application, coder: ^Coder) { + applicationWillEncodeRestorableState :: proc "c" (self: id, cmd: SEL, app: ^Application, coder: ^Coder) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationWillEncodeRestorableState(app, coder) @@ -592,7 +591,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:willEncodeRestorableState:"), auto_cast applicationWillEncodeRestorableState, "v@:@@") } if template.applicationDidDecodeRestorableState != nil { - applicationDidDecodeRestorableState :: proc "c" (self: id, app: ^Application, coder: ^Coder) { + applicationDidDecodeRestorableState :: proc "c" (self: id, cmd: SEL, app: ^Application, coder: ^Coder) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidDecodeRestorableState(app, coder) @@ -600,7 +599,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("application:didDecodeRestorableState:"), auto_cast applicationDidDecodeRestorableState, "v@:@@") } if template.applicationDidChangeOcclusionState != nil { - applicationDidChangeOcclusionState :: proc "c" (self: id, notification: ^Notification) { + applicationDidChangeOcclusionState :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context del.applicationDidChangeOcclusionState(notification) @@ -608,7 +607,7 @@ application_delegate_register_and_alloc :: proc(template: ApplicationDelegateTem class_addMethod(class, intrinsics.objc_find_selector("applicationDidChangeOcclusionState:"), auto_cast applicationDidChangeOcclusionState, "v@:@") } if template.applicationDelegateHandlesKey != nil { - applicationDelegateHandlesKey :: proc "c" (self: id, sender: ^Application, key: ^String) -> BOOL { + applicationDelegateHandlesKey :: proc "c" (self: id, cmd: SEL, sender: ^Application, key: ^String) -> BOOL { del := cast(^_ApplicationDelegateInternal)object_getIndexedIvars(self) context = del._context return del.applicationDelegateHandlesKey(sender, key) diff --git a/core/sys/darwin/Foundation/NSArray.odin b/core/sys/darwin/Foundation/NSArray.odin index b238f63f8..0977c6469 100644 --- a/core/sys/darwin/Foundation/NSArray.odin +++ b/core/sys/darwin/Foundation/NSArray.odin @@ -40,3 +40,49 @@ Array_objectAs :: proc "c" (self: ^Array, index: UInteger, $T: typeid) -> T wher Array_count :: proc "c" (self: ^Array) -> UInteger { return msgSend(UInteger, self, "count") } + + +@(objc_class="NSMutableArray") +MutableArray :: struct { + using _: Copying(MutableArray), +} + +@(objc_type=MutableArray, objc_name="alloc", objc_is_class_method=true) +MutableArray_alloc :: proc "c" () -> ^MutableArray { + return msgSend(^MutableArray, MutableArray, "alloc") +} + +@(objc_type=MutableArray, objc_name="init") +MutableArray_init :: proc "c" (self: ^MutableArray) -> ^MutableArray { + return msgSend(^MutableArray, self, "init") +} + +@(objc_type=MutableArray, objc_name="initWithObjects") +MutableArray_initWithObjects :: proc "c" (self: ^MutableArray, objects: [^]^Object, count: UInteger) -> ^MutableArray { + return msgSend(^MutableArray, self, "initWithObjects:count:", objects, count) +} + +@(objc_type=MutableArray, objc_name="initWithCoder") +MutableArray_initWithCoder :: proc "c" (self: ^MutableArray, coder: ^Coder) -> ^MutableArray { + return msgSend(^MutableArray, self, "initWithCoder:", coder) +} + +@(objc_type=MutableArray, objc_name="object") +MutableArray_object :: proc "c" (self: ^MutableArray, index: UInteger) -> ^Object { + return msgSend(^Object, self, "objectAtIndex:", index) +} +@(objc_type=MutableArray, objc_name="objectAs") +MutableArray_objectAs :: proc "c" (self: ^MutableArray, index: UInteger, $T: typeid) -> T where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) { + return (T)(MutableArray_object(self, index)) +} + +@(objc_type=MutableArray, objc_name="count") +MutableArray_count :: proc "c" (self: ^MutableArray) -> UInteger { + return msgSend(UInteger, self, "count") +} + + +@(objc_type=MutableArray, objc_name="exchangeObjectAtIndex") +MutableArray_exchangeObjectAtIndex :: proc "c" (self: ^MutableArray, idx1, idx2: UInteger) { + msgSend(nil, self, "exchangeObjectAtIndex:withObjectAtIndex:", idx1, idx2) +} diff --git a/core/sys/darwin/Foundation/NSBitmapImageRep.odin b/core/sys/darwin/Foundation/NSBitmapImageRep.odin new file mode 100644 index 000000000..059a75e43 --- /dev/null +++ b/core/sys/darwin/Foundation/NSBitmapImageRep.odin @@ -0,0 +1,50 @@ +package objc_Foundation + +import "base:intrinsics" + +@(objc_class="NSBitmapImageRep") +BitmapImageRep :: struct { using _: Object } + +@(objc_type=BitmapImageRep, objc_name="alloc", objc_is_class_method=true) +BitmapImageRep_alloc :: proc "c" () -> ^BitmapImageRep { + return msgSend(^BitmapImageRep, BitmapImageRep, "alloc") +} + +@(objc_type=BitmapImageRep, objc_name="initWithBitmapDataPlanes") +BitmapImageRep_initWithBitmapDataPlanes :: proc "c" ( + self: ^BitmapImageRep, + bitmapDataPlanes: ^^u8, + pixelsWide: Integer, + pixelsHigh: Integer, + bitsPerSample: Integer, + samplesPerPixel: Integer, + hasAlpha: bool, + isPlanar: bool, + colorSpaceName: ^String, + bytesPerRow: Integer, + bitsPerPixel: Integer) -> ^BitmapImageRep { + + return msgSend(^BitmapImageRep, + self, + "initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bytesPerRow:bitsPerPixel:", + bitmapDataPlanes, + pixelsWide, + pixelsHigh, + bitsPerSample, + samplesPerPixel, + hasAlpha, + isPlanar, + colorSpaceName, + bytesPerRow, + bitsPerPixel) +} + +@(objc_type=BitmapImageRep, objc_name="bitmapData") +BitmapImageRep_bitmapData :: proc "c" (self: ^BitmapImageRep) -> rawptr { + return msgSend(rawptr, self, "bitmapData") +} + +@(objc_type=BitmapImageRep, objc_name="CGImage") +BitmapImageRep_CGImage :: proc "c" (self: ^BitmapImageRep) -> rawptr { + return msgSend(rawptr, self, "CGImage") +} diff --git a/core/sys/darwin/Foundation/NSBlock.odin b/core/sys/darwin/Foundation/NSBlock.odin index 1ef5e8a9b..8e65391f4 100644 --- a/core/sys/darwin/Foundation/NSBlock.odin +++ b/core/sys/darwin/Foundation/NSBlock.odin @@ -62,7 +62,7 @@ global_block_descriptor := Block_Descriptor{ size = size_of(Internal_Block_Literal), } -foreign import libSystem "system:System.framework" +foreign import libSystem "system:System" foreign libSystem { _NSConcreteGlobalBlock: intrinsics.objc_class _NSConcreteStackBlock: intrinsics.objc_class diff --git a/core/sys/darwin/Foundation/NSDictionary.odin b/core/sys/darwin/Foundation/NSDictionary.odin index 8af58cf62..ed98f3168 100644 --- a/core/sys/darwin/Foundation/NSDictionary.odin +++ b/core/sys/darwin/Foundation/NSDictionary.odin @@ -15,7 +15,7 @@ Dictionary_dictionaryWithObject :: proc "c" (object: ^Object, forKey: ^Object) - @(objc_type=Dictionary, objc_name="dictionaryWithObjects", objc_is_class_method=true) Dictionary_dictionaryWithObjects :: proc "c" (objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary { - return msgSend(^Dictionary, Dictionary, "dictionaryWithObjects:forKeys:count", objects, forKeys, count) + return msgSend(^Dictionary, Dictionary, "dictionaryWithObjects:forKeys:count:", objects, forKeys, count) } @@ -31,7 +31,7 @@ Dictionary_init :: proc "c" (self: ^Dictionary) -> ^Dictionary { @(objc_type=Dictionary, objc_name="initWithObjects") Dictionary_initWithObjects :: proc "c" (self: ^Dictionary, objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary { - return msgSend(^Dictionary, self, "initWithObjects:forKeys:count", objects, forKeys, count) + return msgSend(^Dictionary, self, "initWithObjects:forKeys:count:", objects, forKeys, count) } @(objc_type=Dictionary, objc_name="objectForKey") diff --git a/core/sys/darwin/Foundation/NSMenu.odin b/core/sys/darwin/Foundation/NSMenu.odin index 9a74151b0..747920ab7 100644 --- a/core/sys/darwin/Foundation/NSMenu.odin +++ b/core/sys/darwin/Foundation/NSMenu.odin @@ -2,127 +2,562 @@ package objc_Foundation import "base:builtin" import "base:intrinsics" - -KeyEquivalentModifierFlag :: enum UInteger { - CapsLock = 16, // Set if Caps Lock key is pressed. - Shift = 17, // Set if Shift key is pressed. - Control = 18, // Set if Control key is pressed. - Option = 19, // Set if Option or Alternate key is pressed. - Command = 20, // Set if Command key is pressed. - NumericPad = 21, // Set if any key in the numeric keypad is pressed. - Help = 22, // Set if the Help key is pressed. - Function = 23, // Set if any function key is pressed. -} -KeyEquivalentModifierMask :: distinct bit_set[KeyEquivalentModifierFlag; UInteger] - -// Used to retrieve only the device-independent modifier flags, allowing applications to mask off the device-dependent modifier flags, including event coalescing information. -KeyEventModifierFlagDeviceIndependentFlagsMask := transmute(KeyEquivalentModifierMask)_KeyEventModifierFlagDeviceIndependentFlagsMask -@(private) _KeyEventModifierFlagDeviceIndependentFlagsMask := UInteger(0xffff0000) +import "core:c" -MenuItemCallback :: proc "c" (unused: rawptr, name: SEL, sender: ^Object) - - -@(objc_class="NSMenuItem") -MenuItem :: struct {using _: Object} - -@(objc_type=MenuItem, objc_name="alloc", objc_is_class_method=true) -MenuItem_alloc :: proc "c" () -> ^MenuItem { - return msgSend(^MenuItem, MenuItem, "alloc") +MenuSelectionMode :: enum c.long { + Automatic = 0, + SelectOne = 1, + SelectAny = 2, } -@(objc_type=MenuItem, objc_name="registerActionCallback", objc_is_class_method=true) -MenuItem_registerActionCallback :: proc "c" (name: cstring, callback: MenuItemCallback) -> SEL { - s := string(name) - n := len(s) - sel: SEL - if n > 0 && s[n-1] != ':' { - col_name := intrinsics.alloca(n+2, 1) - builtin.copy(col_name[:n], s) - col_name[n] = ':' - col_name[n+1] = 0 - sel = sel_registerName(cstring(col_name)) - } else { - sel = sel_registerName(name) - } - if callback != nil { - class_addMethod(intrinsics.objc_find_class("NSObject"), sel, auto_cast callback, "v@:@") - } - return sel +MenuPresentationStyle :: enum c.long { + Regular = 0, + Palette = 1, } -@(objc_type=MenuItem, objc_name="separatorItem", objc_is_class_method=true) -MenuItem_separatorItem :: proc "c" () -> ^MenuItem { - return msgSend(^MenuItem, MenuItem, "separatorItem") +UserInterfaceLayoutDirection :: enum c.long { + LeftToRight = 0, + RightToLeft = 1, } -@(objc_type=MenuItem, objc_name="init") -MenuItem_init :: proc "c" (self: ^MenuItem) -> ^MenuItem { - return msgSend(^MenuItem, self, "init") +MenuPropertyItem :: enum c.ulong { + Title = 0, + AttributedTitle = 1, + KeyEquivalent = 2, + Image = 3, + Enabled = 4, + AccessibilityDescription = 5, } - -@(objc_type=MenuItem, objc_name="initWithTitle") -MenuItem_initWithTitle :: proc "c" (self: ^MenuItem, title: ^String, action: SEL, keyEquivalent: ^String) -> ^MenuItem { - return msgSend(^MenuItem, self, "initWithTitle:action:keyEquivalent:", title, action, keyEquivalent) -} - -@(objc_type=MenuItem, objc_name="setKeyEquivalentModifierMask") -MenuItem_setKeyEquivalentModifierMask :: proc "c" (self: ^MenuItem, modifierMask: KeyEquivalentModifierMask) { - msgSend(nil, self, "setKeyEquivalentModifierMask:", modifierMask) -} - -@(objc_type=MenuItem, objc_name="keyEquivalentModifierMask") -MenuItem_keyEquivalentModifierMask :: proc "c" (self: ^MenuItem) -> KeyEquivalentModifierMask { - return msgSend(KeyEquivalentModifierMask, self, "keyEquivalentModifierMask") -} - -@(objc_type=MenuItem, objc_name="setSubmenu") -MenuItem_setSubmenu :: proc "c" (self: ^MenuItem, submenu: ^Menu) { - msgSend(nil, self, "setSubmenu:", submenu) -} - -@(objc_type=MenuItem, objc_name="title") -MenuItem_title :: proc "c" (self: ^MenuItem) -> ^String { - return msgSend(^String, self, "title") -} - -@(objc_type=MenuItem, objc_name="setTitle") -MenuItem_setTitle :: proc "c" (self: ^MenuItem, title: ^String) -> ^String { - return msgSend(^String, self, "title:", title) -} - +MenuProperties :: distinct bit_set[MenuPropertyItem; c.ulong] @(objc_class="NSMenu") Menu :: struct {using _: Object} -@(objc_type=Menu, objc_name="alloc", objc_is_class_method=true) -Menu_alloc :: proc "c" () -> ^Menu { - return msgSend(^Menu, Menu, "alloc") -} - @(objc_type=Menu, objc_name="init") Menu_init :: proc "c" (self: ^Menu) -> ^Menu { return msgSend(^Menu, self, "init") } + @(objc_type=Menu, objc_name="initWithTitle") -Menu_initWithTitle :: proc "c" (self: ^Menu, title: ^String) -> ^Menu { +Menu_initWithTitle :: #force_inline proc "c" (self: ^Menu, title: ^String) -> ^Menu { return msgSend(^Menu, self, "initWithTitle:", title) } - - +@(objc_type=Menu, objc_name="initWithCoder") +Menu_initWithCoder :: #force_inline proc "c" (self: ^Menu, coder: ^Coder) -> ^Menu { + return msgSend(^Menu, self, "initWithCoder:", coder) +} +@(objc_type=Menu, objc_name="popUpContextMenu_withEvent_forView", objc_is_class_method=true) +Menu_popUpContextMenu_withEvent_forView :: #force_inline proc "c" (menu: ^Menu, event: ^Event, view: ^View) { + msgSend(nil, Menu, "popUpContextMenu:withEvent:forView:", menu, event, view) +} +// @(objc_type=Menu, objc_name="popUpContextMenu_withEvent_forView_withFont", objc_is_class_method=true) +// Menu_popUpContextMenu_withEvent_forView_withFont :: #force_inline proc "c" (menu: ^Menu, event: ^Event, view: ^View, font: ^Font) { +// msgSend(nil, Menu, "popUpContextMenu:withEvent:forView:withFont:", menu, event, view, font) +// } +@(objc_type=Menu, objc_name="popUpMenuPositioningItem") +Menu_popUpMenuPositioningItem :: #force_inline proc "c" (self: ^Menu, item: ^MenuItem, location: Point, view: ^View) -> bool { + return msgSend(bool, self, "popUpMenuPositioningItem:atLocation:inView:", item, location, view) +} +@(objc_type=Menu, objc_name="setMenuBarVisible", objc_is_class_method=true) +Menu_setMenuBarVisible :: #force_inline proc "c" (visible: bool) { + msgSend(nil, Menu, "setMenuBarVisible:", visible) +} +@(objc_type=Menu, objc_name="menuBarVisible", objc_is_class_method=true) +Menu_menuBarVisible :: #force_inline proc "c" () -> bool { + return msgSend(bool, Menu, "menuBarVisible") +} +@(objc_type=Menu, objc_name="insertItem") +Menu_insertItem :: #force_inline proc "c" (self: ^Menu, newItem: ^MenuItem, index: Integer) { + msgSend(nil, self, "insertItem:atIndex:", newItem, index) +} @(objc_type=Menu, objc_name="addItem") -Menu_addItem :: proc "c" (self: ^Menu, item: ^MenuItem) { - msgSend(nil, self, "addItem:", item) +Menu_addItem :: #force_inline proc "c" (self: ^Menu, newItem: ^MenuItem) { + msgSend(nil, self, "addItem:", newItem) +} +@(objc_type=Menu, objc_name="insertItemWithTitle") +Menu_insertItemWithTitle :: #force_inline proc "c" (self: ^Menu, string: ^String, selector: SEL, charCode: ^String, index: Integer) -> ^MenuItem { + return msgSend(^MenuItem, self, "insertItemWithTitle:action:keyEquivalent:atIndex:", string, selector, charCode, index) } - @(objc_type=Menu, objc_name="addItemWithTitle") -Menu_addItemWithTitle :: proc "c" (self: ^Menu, title: ^String, selector: SEL, keyEquivalent: ^String) -> ^MenuItem { - return msgSend(^MenuItem, self, "addItemWithTitle:action:keyEquivalent:", title, selector, keyEquivalent) +Menu_addItemWithTitle :: #force_inline proc "c" (self: ^Menu, string: ^String, selector: SEL, charCode: ^String) -> ^MenuItem { + return msgSend(^MenuItem, self, "addItemWithTitle:action:keyEquivalent:", string, selector, charCode) +} +@(objc_type=Menu, objc_name="removeItemAtIndex") +Menu_removeItemAtIndex :: #force_inline proc "c" (self: ^Menu, index: Integer) { + msgSend(nil, self, "removeItemAtIndex:", index) +} +@(objc_type=Menu, objc_name="removeItem") +Menu_removeItem :: #force_inline proc "c" (self: ^Menu, item: ^MenuItem) { + msgSend(nil, self, "removeItem:", item) +} +@(objc_type=Menu, objc_name="setSubmenu") +Menu_setSubmenu :: #force_inline proc "c" (self: ^Menu, menu: ^Menu, item: ^MenuItem) { + msgSend(nil, self, "setSubmenu:forItem:", menu, item) +} +@(objc_type=Menu, objc_name="removeAllItems") +Menu_removeAllItems :: #force_inline proc "c" (self: ^Menu) { + msgSend(nil, self, "removeAllItems") +} +@(objc_type=Menu, objc_name="itemAtIndex") +Menu_itemAtIndex :: #force_inline proc "c" (self: ^Menu, index: Integer) -> ^MenuItem { + return msgSend(^MenuItem, self, "itemAtIndex:", index) +} +@(objc_type=Menu, objc_name="indexOfItem") +Menu_indexOfItem :: #force_inline proc "c" (self: ^Menu, item: ^MenuItem) -> Integer { + return msgSend(Integer, self, "indexOfItem:", item) +} +@(objc_type=Menu, objc_name="indexOfItemWithTitle") +Menu_indexOfItemWithTitle :: #force_inline proc "c" (self: ^Menu, title: ^String) -> Integer { + return msgSend(Integer, self, "indexOfItemWithTitle:", title) +} +@(objc_type=Menu, objc_name="indexOfItemWithTag") +Menu_indexOfItemWithTag :: #force_inline proc "c" (self: ^Menu, tag: Integer) -> Integer { + return msgSend(Integer, self, "indexOfItemWithTag:", tag) +} +@(objc_type=Menu, objc_name="indexOfItemWithRepresentedObject") +Menu_indexOfItemWithRepresentedObject :: #force_inline proc "c" (self: ^Menu, object: id) -> Integer { + return msgSend(Integer, self, "indexOfItemWithRepresentedObject:", object) +} +@(objc_type=Menu, objc_name="indexOfItemWithSubmenu") +Menu_indexOfItemWithSubmenu :: #force_inline proc "c" (self: ^Menu, submenu: ^Menu) -> Integer { + return msgSend(Integer, self, "indexOfItemWithSubmenu:", submenu) +} +@(objc_type=Menu, objc_name="indexOfItemWithTarget") +Menu_indexOfItemWithTarget :: #force_inline proc "c" (self: ^Menu, target: id, actionSelector: SEL) -> Integer { + return msgSend(Integer, self, "indexOfItemWithTarget:andAction:", target, actionSelector) +} +@(objc_type=Menu, objc_name="itemWithTitle") +Menu_itemWithTitle :: #force_inline proc "c" (self: ^Menu, title: ^String) -> ^MenuItem { + return msgSend(^MenuItem, self, "itemWithTitle:", title) +} +@(objc_type=Menu, objc_name="itemWithTag") +Menu_itemWithTag :: #force_inline proc "c" (self: ^Menu, tag: Integer) -> ^MenuItem { + return msgSend(^MenuItem, self, "itemWithTag:", tag) +} +@(objc_type=Menu, objc_name="update") +Menu_update :: #force_inline proc "c" (self: ^Menu) { + msgSend(nil, self, "update") +} +@(objc_type=Menu, objc_name="performKeyEquivalent") +Menu_performKeyEquivalent :: #force_inline proc "c" (self: ^Menu, event: ^Event) -> bool { + return msgSend(bool, self, "performKeyEquivalent:", event) +} +@(objc_type=Menu, objc_name="itemChanged") +Menu_itemChanged :: #force_inline proc "c" (self: ^Menu, item: ^MenuItem) { + msgSend(nil, self, "itemChanged:", item) +} +@(objc_type=Menu, objc_name="performActionForItemAtIndex") +Menu_performActionForItemAtIndex :: #force_inline proc "c" (self: ^Menu, index: Integer) { + msgSend(nil, self, "performActionForItemAtIndex:", index) +} +@(objc_type=Menu, objc_name="cancelTracking") +Menu_cancelTracking :: #force_inline proc "c" (self: ^Menu) { + msgSend(nil, self, "cancelTracking") +} +@(objc_type=Menu, objc_name="cancelTrackingWithoutAnimation") +Menu_cancelTrackingWithoutAnimation :: #force_inline proc "c" (self: ^Menu) { + msgSend(nil, self, "cancelTrackingWithoutAnimation") +} +@(objc_type=Menu, objc_name="title") +Menu_title :: #force_inline proc "c" (self: ^Menu) -> ^String { + return msgSend(^String, self, "title") +} +@(objc_type=Menu, objc_name="setTitle") +Menu_setTitle :: #force_inline proc "c" (self: ^Menu, title: ^String) { + msgSend(nil, self, "setTitle:", title) +} +@(objc_type=Menu, objc_name="supermenu") +Menu_supermenu :: #force_inline proc "c" (self: ^Menu) -> ^Menu { + return msgSend(^Menu, self, "supermenu") +} +@(objc_type=Menu, objc_name="setSupermenu") +Menu_setSupermenu :: #force_inline proc "c" (self: ^Menu, supermenu: ^Menu) { + msgSend(nil, self, "setSupermenu:", supermenu) +} +@(objc_type=Menu, objc_name="itemArray") +Menu_itemArray :: #force_inline proc "c" (self: ^Menu) -> ^Array { + return msgSend(^Array, self, "itemArray") +} +@(objc_type=Menu, objc_name="setItemArray") +Menu_setItemArray :: #force_inline proc "c" (self: ^Menu, itemArray: ^Array) { + msgSend(nil, self, "setItemArray:", itemArray) +} +@(objc_type=Menu, objc_name="numberOfItems") +Menu_numberOfItems :: #force_inline proc "c" (self: ^Menu) -> Integer { + return msgSend(Integer, self, "numberOfItems") +} +@(objc_type=Menu, objc_name="autoenablesItems") +Menu_autoenablesItems :: #force_inline proc "c" (self: ^Menu) -> bool { + return msgSend(bool, self, "autoenablesItems") +} +@(objc_type=Menu, objc_name="setAutoenablesItems") +Menu_setAutoenablesItems :: #force_inline proc "c" (self: ^Menu, autoenablesItems: bool) { + msgSend(nil, self, "setAutoenablesItems:", autoenablesItems) +} +@(objc_type=Menu, objc_name="delegate") +Menu_delegate :: #force_inline proc "c" (self: ^Menu) -> ^MenuDelegate { + return msgSend(^MenuDelegate, self, "delegate") +} +@(objc_type=Menu, objc_name="setDelegate") +Menu_setDelegate :: #force_inline proc "c" (self: ^Menu, delegate: ^MenuDelegate) { + msgSend(nil, self, "setDelegate:", delegate) +} +@(objc_type=Menu, objc_name="menuBarHeight") +Menu_menuBarHeight :: #force_inline proc "c" (self: ^Menu) -> Float { + return msgSend(Float, self, "menuBarHeight") +} +@(objc_type=Menu, objc_name="highlightedItem") +Menu_highlightedItem :: #force_inline proc "c" (self: ^Menu) -> ^MenuItem { + return msgSend(^MenuItem, self, "highlightedItem") +} +@(objc_type=Menu, objc_name="minimumWidth") +Menu_minimumWidth :: #force_inline proc "c" (self: ^Menu) -> Float { + return msgSend(Float, self, "minimumWidth") +} +@(objc_type=Menu, objc_name="setMinimumWidth") +Menu_setMinimumWidth :: #force_inline proc "c" (self: ^Menu, minimumWidth: Float) { + msgSend(nil, self, "setMinimumWidth:", minimumWidth) +} +@(objc_type=Menu, objc_name="size") +Menu_size :: #force_inline proc "c" (self: ^Menu) -> Size { + return msgSend(Size, self, "size") +} +// @(objc_type=Menu, objc_name="font") +// Menu_font :: #force_inline proc "c" (self: ^Menu) -> ^Font { +// return msgSend(^Font, self, "font") +// } +// @(objc_type=Menu, objc_name="setFont") +// Menu_setFont :: #force_inline proc "c" (self: ^Menu, font: ^Font) { +// msgSend(nil, self, "setFont:", font) +// } +@(objc_type=Menu, objc_name="allowsContextMenuPlugIns") +Menu_allowsContextMenuPlugIns :: #force_inline proc "c" (self: ^Menu) -> bool { + return msgSend(bool, self, "allowsContextMenuPlugIns") +} +@(objc_type=Menu, objc_name="setAllowsContextMenuPlugIns") +Menu_setAllowsContextMenuPlugIns :: #force_inline proc "c" (self: ^Menu, allowsContextMenuPlugIns: bool) { + msgSend(nil, self, "setAllowsContextMenuPlugIns:", allowsContextMenuPlugIns) +} +@(objc_type=Menu, objc_name="showsStateColumn") +Menu_showsStateColumn :: #force_inline proc "c" (self: ^Menu) -> bool { + return msgSend(bool, self, "showsStateColumn") +} +@(objc_type=Menu, objc_name="setShowsStateColumn") +Menu_setShowsStateColumn :: #force_inline proc "c" (self: ^Menu, showsStateColumn: bool) { + msgSend(nil, self, "setShowsStateColumn:", showsStateColumn) +} +@(objc_type=Menu, objc_name="userInterfaceLayoutDirection") +Menu_userInterfaceLayoutDirection :: #force_inline proc "c" (self: ^Menu) -> UserInterfaceLayoutDirection { + return msgSend(UserInterfaceLayoutDirection, self, "userInterfaceLayoutDirection") +} +@(objc_type=Menu, objc_name="setUserInterfaceLayoutDirection") +Menu_setUserInterfaceLayoutDirection :: #force_inline proc "c" (self: ^Menu, userInterfaceLayoutDirection: UserInterfaceLayoutDirection) { + msgSend(nil, self, "setUserInterfaceLayoutDirection:", userInterfaceLayoutDirection) +} +@(objc_type=Menu, objc_name="paletteMenuWithColors_titles_selectionHandler", objc_is_class_method=true) +Menu_paletteMenuWithColors_titles_selectionHandler :: #force_inline proc "c" (colors: ^Array, itemTitles: ^Array, onSelectionChange: proc "c" (_arg_0: ^Menu)) -> ^Menu { + return msgSend(^Menu, Menu, "paletteMenuWithColors:titles:selectionHandler:", colors, itemTitles, onSelectionChange) +} +// @(objc_type=Menu, objc_name="paletteMenuWithColors_titles_templateImage_selectionHandler", objc_is_class_method=true) +// Menu_paletteMenuWithColors_titles_templateImage_selectionHandler :: #force_inline proc "c" (colors: ^Array, itemTitles: ^Array, image: ^Image, onSelectionChange: proc "c" (_arg_0: ^Menu)) -> ^Menu { +// return msgSend(^Menu, Menu, "paletteMenuWithColors:titles:templateImage:selectionHandler:", colors, itemTitles, image, onSelectionChange) +// } +@(objc_type=Menu, objc_name="presentationStyle") +Menu_presentationStyle :: #force_inline proc "c" (self: ^Menu) -> MenuPresentationStyle { + return msgSend(MenuPresentationStyle, self, "presentationStyle") +} +@(objc_type=Menu, objc_name="setPresentationStyle") +Menu_setPresentationStyle :: #force_inline proc "c" (self: ^Menu, presentationStyle: MenuPresentationStyle) { + msgSend(nil, self, "setPresentationStyle:", presentationStyle) +} +@(objc_type=Menu, objc_name="selectionMode") +Menu_selectionMode :: #force_inline proc "c" (self: ^Menu) -> MenuSelectionMode { + return msgSend(MenuSelectionMode, self, "selectionMode") +} +@(objc_type=Menu, objc_name="setSelectionMode") +Menu_setSelectionMode :: #force_inline proc "c" (self: ^Menu, selectionMode: MenuSelectionMode) { + msgSend(nil, self, "setSelectionMode:", selectionMode) +} +@(objc_type=Menu, objc_name="selectedItems") +Menu_selectedItems :: #force_inline proc "c" (self: ^Menu) -> ^Array { + return msgSend(^Array, self, "selectedItems") +} +@(objc_type=Menu, objc_name="setSelectedItems") +Menu_setSelectedItems :: #force_inline proc "c" (self: ^Menu, selectedItems: ^Array) { + msgSend(nil, self, "setSelectedItems:", selectedItems) +} +@(objc_type=Menu, objc_name="submenuAction") +Menu_submenuAction :: #force_inline proc "c" (self: ^Menu, sender: id) { + msgSend(nil, self, "submenuAction:", sender) +} +@(objc_type=Menu, objc_name="propertiesToUpdate") +Menu_propertiesToUpdate :: #force_inline proc "c" (self: ^Menu) -> MenuProperties { + return msgSend(MenuProperties, self, "propertiesToUpdate") +} +@(objc_type=Menu, objc_name="setMenuRepresentation") +Menu_setMenuRepresentation :: #force_inline proc "c" (self: ^Menu, menuRep: id) { + msgSend(nil, self, "setMenuRepresentation:", menuRep) +} +@(objc_type=Menu, objc_name="menuRepresentation") +Menu_menuRepresentation :: #force_inline proc "c" (self: ^Menu) -> id { + return msgSend(id, self, "menuRepresentation") +} +@(objc_type=Menu, objc_name="setContextMenuRepresentation") +Menu_setContextMenuRepresentation :: #force_inline proc "c" (self: ^Menu, menuRep: id) { + msgSend(nil, self, "setContextMenuRepresentation:", menuRep) +} +@(objc_type=Menu, objc_name="contextMenuRepresentation") +Menu_contextMenuRepresentation :: #force_inline proc "c" (self: ^Menu) -> id { + return msgSend(id, self, "contextMenuRepresentation") +} +@(objc_type=Menu, objc_name="setTearOffMenuRepresentation") +Menu_setTearOffMenuRepresentation :: #force_inline proc "c" (self: ^Menu, menuRep: id) { + msgSend(nil, self, "setTearOffMenuRepresentation:", menuRep) +} +@(objc_type=Menu, objc_name="tearOffMenuRepresentation") +Menu_tearOffMenuRepresentation :: #force_inline proc "c" (self: ^Menu) -> id { + return msgSend(id, self, "tearOffMenuRepresentation") +} +@(objc_type=Menu, objc_name="menuZone", objc_is_class_method=true) +Menu_menuZone :: #force_inline proc "c" () -> ^Zone { + return msgSend(^Zone, Menu, "menuZone") +} +@(objc_type=Menu, objc_name="setMenuZone", objc_is_class_method=true) +Menu_setMenuZone :: #force_inline proc "c" (zone: ^Zone) { + msgSend(nil, Menu, "setMenuZone:", zone) +} +@(objc_type=Menu, objc_name="attachedMenu") +Menu_attachedMenu :: #force_inline proc "c" (self: ^Menu) -> ^Menu { + return msgSend(^Menu, self, "attachedMenu") +} +@(objc_type=Menu, objc_name="isAttached") +Menu_isAttached :: #force_inline proc "c" (self: ^Menu) -> bool { + return msgSend(bool, self, "isAttached") +} +@(objc_type=Menu, objc_name="sizeToFit") +Menu_sizeToFit :: #force_inline proc "c" (self: ^Menu) { + msgSend(nil, self, "sizeToFit") +} +@(objc_type=Menu, objc_name="locationForSubmenu") +Menu_locationForSubmenu :: #force_inline proc "c" (self: ^Menu, submenu: ^Menu) -> Point { + return msgSend(Point, self, "locationForSubmenu:", submenu) +} +@(objc_type=Menu, objc_name="helpRequested") +Menu_helpRequested :: #force_inline proc "c" (self: ^Menu, eventPtr: ^Event) { + msgSend(nil, self, "helpRequested:", eventPtr) +} +@(objc_type=Menu, objc_name="menuChangedMessagesEnabled") +Menu_menuChangedMessagesEnabled :: #force_inline proc "c" (self: ^Menu) -> bool { + return msgSend(bool, self, "menuChangedMessagesEnabled") +} +@(objc_type=Menu, objc_name="setMenuChangedMessagesEnabled") +Menu_setMenuChangedMessagesEnabled :: #force_inline proc "c" (self: ^Menu, menuChangedMessagesEnabled: bool) { + msgSend(nil, self, "setMenuChangedMessagesEnabled:", menuChangedMessagesEnabled) +} +@(objc_type=Menu, objc_name="isTornOff") +Menu_isTornOff :: #force_inline proc "c" (self: ^Menu) -> bool { + return msgSend(bool, self, "isTornOff") +} +@(objc_type=Menu, objc_name="load", objc_is_class_method=true) +Menu_load :: #force_inline proc "c" () { + msgSend(nil, Menu, "load") +} +@(objc_type=Menu, objc_name="initialize", objc_is_class_method=true) +Menu_initialize :: #force_inline proc "c" () { + msgSend(nil, Menu, "initialize") +} +@(objc_type=Menu, objc_name="new", objc_is_class_method=true) +Menu_new :: #force_inline proc "c" () -> ^Menu { + return msgSend(^Menu, Menu, "new") +} +@(objc_type=Menu, objc_name="allocWithZone", objc_is_class_method=true) +Menu_allocWithZone :: #force_inline proc "c" (zone: ^Zone) -> ^Menu { + return msgSend(^Menu, Menu, "allocWithZone:", zone) +} +@(objc_type=Menu, objc_name="alloc", objc_is_class_method=true) +Menu_alloc :: #force_inline proc "c" () -> ^Menu { + return msgSend(^Menu, Menu, "alloc") +} +@(objc_type=Menu, objc_name="copyWithZone", objc_is_class_method=true) +Menu_copyWithZone :: #force_inline proc "c" (zone: ^Zone) -> id { + return msgSend(id, Menu, "copyWithZone:", zone) +} +@(objc_type=Menu, objc_name="mutableCopyWithZone", objc_is_class_method=true) +Menu_mutableCopyWithZone :: #force_inline proc "c" (zone: ^Zone) -> id { + return msgSend(id, Menu, "mutableCopyWithZone:", zone) +} +@(objc_type=Menu, objc_name="instancesRespondToSelector", objc_is_class_method=true) +Menu_instancesRespondToSelector :: #force_inline proc "c" (aSelector: SEL) -> bool { + return msgSend(bool, Menu, "instancesRespondToSelector:", aSelector) +} +@(objc_type=Menu, objc_name="conformsToProtocol", objc_is_class_method=true) +Menu_conformsToProtocol :: #force_inline proc "c" (protocol: ^Protocol) -> bool { + return msgSend(bool, Menu, "conformsToProtocol:", protocol) +} +@(objc_type=Menu, objc_name="instanceMethodForSelector", objc_is_class_method=true) +Menu_instanceMethodForSelector :: #force_inline proc "c" (aSelector: SEL) -> IMP { + return msgSend(IMP, Menu, "instanceMethodForSelector:", aSelector) +} +// @(objc_type=Menu, objc_name="instanceMethodSignatureForSelector", objc_is_class_method=true) +// Menu_instanceMethodSignatureForSelector :: #force_inline proc "c" (aSelector: SEL) -> ^MethodSignature { +// return msgSend(^MethodSignature, Menu, "instanceMethodSignatureForSelector:", aSelector) +// } +@(objc_type=Menu, objc_name="isSubclassOfClass", objc_is_class_method=true) +Menu_isSubclassOfClass :: #force_inline proc "c" (aClass: Class) -> bool { + return msgSend(bool, Menu, "isSubclassOfClass:", aClass) +} +@(objc_type=Menu, objc_name="resolveClassMethod", objc_is_class_method=true) +Menu_resolveClassMethod :: #force_inline proc "c" (sel: SEL) -> bool { + return msgSend(bool, Menu, "resolveClassMethod:", sel) +} +@(objc_type=Menu, objc_name="resolveInstanceMethod", objc_is_class_method=true) +Menu_resolveInstanceMethod :: #force_inline proc "c" (sel: SEL) -> bool { + return msgSend(bool, Menu, "resolveInstanceMethod:", sel) +} +@(objc_type=Menu, objc_name="hash", objc_is_class_method=true) +Menu_hash :: #force_inline proc "c" () -> UInteger { + return msgSend(UInteger, Menu, "hash") +} +@(objc_type=Menu, objc_name="superclass", objc_is_class_method=true) +Menu_superclass :: #force_inline proc "c" () -> Class { + return msgSend(Class, Menu, "superclass") +} +@(objc_type=Menu, objc_name="class", objc_is_class_method=true) +Menu_class :: #force_inline proc "c" () -> Class { + return msgSend(Class, Menu, "class") +} +@(objc_type=Menu, objc_name="description", objc_is_class_method=true) +Menu_description :: #force_inline proc "c" () -> ^String { + return msgSend(^String, Menu, "description") +} +@(objc_type=Menu, objc_name="debugDescription", objc_is_class_method=true) +Menu_debugDescription :: #force_inline proc "c" () -> ^String { + return msgSend(^String, Menu, "debugDescription") +} +@(objc_type=Menu, objc_name="version", objc_is_class_method=true) +Menu_version :: #force_inline proc "c" () -> Integer { + return msgSend(Integer, Menu, "version") +} +@(objc_type=Menu, objc_name="setVersion", objc_is_class_method=true) +Menu_setVersion :: #force_inline proc "c" (aVersion: Integer) { + msgSend(nil, Menu, "setVersion:", aVersion) +} +@(objc_type=Menu, objc_name="poseAsClass", objc_is_class_method=true) +Menu_poseAsClass :: #force_inline proc "c" (aClass: Class) { + msgSend(nil, Menu, "poseAsClass:", aClass) +} +@(objc_type=Menu, objc_name="cancelPreviousPerformRequestsWithTarget_selector_object", objc_is_class_method=true) +Menu_cancelPreviousPerformRequestsWithTarget_selector_object :: #force_inline proc "c" (aTarget: id, aSelector: SEL, anArgument: id) { + msgSend(nil, Menu, "cancelPreviousPerformRequestsWithTarget:selector:object:", aTarget, aSelector, anArgument) +} +@(objc_type=Menu, objc_name="cancelPreviousPerformRequestsWithTarget_", objc_is_class_method=true) +Menu_cancelPreviousPerformRequestsWithTarget_ :: #force_inline proc "c" (aTarget: id) { + msgSend(nil, Menu, "cancelPreviousPerformRequestsWithTarget:", aTarget) +} +@(objc_type=Menu, objc_name="accessInstanceVariablesDirectly", objc_is_class_method=true) +Menu_accessInstanceVariablesDirectly :: #force_inline proc "c" () -> bool { + return msgSend(bool, Menu, "accessInstanceVariablesDirectly") +} +@(objc_type=Menu, objc_name="useStoredAccessor", objc_is_class_method=true) +Menu_useStoredAccessor :: #force_inline proc "c" () -> bool { + return msgSend(bool, Menu, "useStoredAccessor") +} +@(objc_type=Menu, objc_name="keyPathsForValuesAffectingValueForKey", objc_is_class_method=true) +Menu_keyPathsForValuesAffectingValueForKey :: #force_inline proc "c" (key: ^String) -> ^Set { + return msgSend(^Set, Menu, "keyPathsForValuesAffectingValueForKey:", key) +} +@(objc_type=Menu, objc_name="automaticallyNotifiesObserversForKey", objc_is_class_method=true) +Menu_automaticallyNotifiesObserversForKey :: #force_inline proc "c" (key: ^String) -> bool { + return msgSend(bool, Menu, "automaticallyNotifiesObserversForKey:", key) +} +@(objc_type=Menu, objc_name="setKeys", objc_is_class_method=true) +Menu_setKeys :: #force_inline proc "c" (keys: ^Array, dependentKey: ^String) { + msgSend(nil, Menu, "setKeys:triggerChangeNotificationsForDependentKey:", keys, dependentKey) +} +@(objc_type=Menu, objc_name="classFallbacksForKeyedArchiver", objc_is_class_method=true) +Menu_classFallbacksForKeyedArchiver :: #force_inline proc "c" () -> ^Array { + return msgSend(^Array, Menu, "classFallbacksForKeyedArchiver") +} +@(objc_type=Menu, objc_name="classForKeyedUnarchiver", objc_is_class_method=true) +Menu_classForKeyedUnarchiver :: #force_inline proc "c" () -> Class { + return msgSend(Class, Menu, "classForKeyedUnarchiver") +} +@(objc_type=Menu, objc_name="exposeBinding", objc_is_class_method=true) +Menu_exposeBinding :: #force_inline proc "c" (binding: ^String) { + msgSend(nil, Menu, "exposeBinding:", binding) +} +@(objc_type=Menu, objc_name="setDefaultPlaceholder", objc_is_class_method=true) +Menu_setDefaultPlaceholder :: #force_inline proc "c" (placeholder: id, marker: id, binding: ^String) { + msgSend(nil, Menu, "setDefaultPlaceholder:forMarker:withBinding:", placeholder, marker, binding) +} +@(objc_type=Menu, objc_name="defaultPlaceholderForMarker", objc_is_class_method=true) +Menu_defaultPlaceholderForMarker :: #force_inline proc "c" (marker: id, binding: ^String) -> id { + return msgSend(id, Menu, "defaultPlaceholderForMarker:withBinding:", marker, binding) +} +@(objc_type=Menu, objc_name="popUpContextMenu") +Menu_popUpContextMenu :: proc { + Menu_popUpContextMenu_withEvent_forView, + // Menu_popUpContextMenu_withEvent_forView_withFont, } -@(objc_type=Menu, objc_name="itemArray") -Menu_itemArray :: proc "c" (self: ^Menu) -> ^Array { - return msgSend(^Array, self, "itemArray") -} \ No newline at end of file +@(objc_type=Menu, objc_name="paletteMenuWithColors") +Menu_paletteMenuWithColors :: proc { + Menu_paletteMenuWithColors_titles_selectionHandler, + // Menu_paletteMenuWithColors_titles_templateImage_selectionHandler, +} + +@(objc_type=Menu, objc_name="cancelPreviousPerformRequestsWithTarget") +Menu_cancelPreviousPerformRequestsWithTarget :: proc { + Menu_cancelPreviousPerformRequestsWithTarget_selector_object, + Menu_cancelPreviousPerformRequestsWithTarget_, +} + + + + + + + +@(objc_class="NSMenuDelegate") +MenuDelegate :: struct {using _: Object, using _: ObjectProtocol} + +@(objc_type=MenuDelegate, objc_name="menuNeedsUpdate") +MenuDelegate_menuNeedsUpdate :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu) { + msgSend(nil, self, "menuNeedsUpdate:", menu) +} +@(objc_type=MenuDelegate, objc_name="numberOfItemsInMenu") +MenuDelegate_numberOfItemsInMenu :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu) -> Integer { + return msgSend(Integer, self, "numberOfItemsInMenu:", menu) +} +@(objc_type=MenuDelegate, objc_name="menu_updateItem_atIndex_shouldCancel") +MenuDelegate_menu_updateItem_atIndex_shouldCancel :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu, item: ^MenuItem, index: Integer, shouldCancel: bool) -> bool { + return msgSend(bool, self, "menu:updateItem:atIndex:shouldCancel:", menu, item, index, shouldCancel) +} +@(objc_type=MenuDelegate, objc_name="menuHasKeyEquivalent") +MenuDelegate_menuHasKeyEquivalent :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu, event: ^Event, target: ^id, action: ^SEL) -> bool { + return msgSend(bool, self, "menuHasKeyEquivalent:forEvent:target:action:", menu, event, target, action) +} +@(objc_type=MenuDelegate, objc_name="menuWillOpen") +MenuDelegate_menuWillOpen :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu) { + msgSend(nil, self, "menuWillOpen:", menu) +} +@(objc_type=MenuDelegate, objc_name="menuDidClose") +MenuDelegate_menuDidClose :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu) { + msgSend(nil, self, "menuDidClose:", menu) +} +@(objc_type=MenuDelegate, objc_name="menu_willHighlightItem") +MenuDelegate_menu_willHighlightItem :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu, item: ^MenuItem) { + msgSend(nil, self, "menu:willHighlightItem:", menu, item) +} +@(objc_type=MenuDelegate, objc_name="confinementRectForMenu") +MenuDelegate_confinementRectForMenu :: #force_inline proc "c" (self: ^MenuDelegate, menu: ^Menu, screen: ^Screen) -> Rect { + return msgSend(Rect, self, "confinementRectForMenu:onScreen:", menu, screen) +} +@(objc_type=MenuDelegate, objc_name="menu") +MenuDelegate_menu :: proc { + MenuDelegate_menu_updateItem_atIndex_shouldCancel, + MenuDelegate_menu_willHighlightItem, +} diff --git a/core/sys/darwin/Foundation/NSMenuItem.odin b/core/sys/darwin/Foundation/NSMenuItem.odin new file mode 100644 index 000000000..248a0cf4f --- /dev/null +++ b/core/sys/darwin/Foundation/NSMenuItem.odin @@ -0,0 +1,460 @@ +package objc_Foundation + +import "base:builtin" +import "base:intrinsics" + +KeyEquivalentModifierFlag :: EventModifierFlag +KeyEquivalentModifierMask :: EventModifierFlags + +// Used to retrieve only the device-independent modifier flags, allowing applications to mask off the device-dependent modifier flags, including event coalescing information. +KeyEventModifierFlagDeviceIndependentFlagsMask := transmute(KeyEquivalentModifierMask)_KeyEventModifierFlagDeviceIndependentFlagsMask +@(private) _KeyEventModifierFlagDeviceIndependentFlagsMask := UInteger(0xffff0000) + +MenuItemCallback :: proc "c" (unused: rawptr, name: SEL, sender: ^Object) + +@(objc_class="NSMenuItem") +MenuItem :: struct {using _: Object} + +@(objc_type=MenuItem, objc_name="registerActionCallback", objc_is_class_method=true) +MenuItem_registerActionCallback :: proc "c" (name: cstring, callback: MenuItemCallback) -> SEL { + s := string(name) + n := len(s) + sel: SEL + if n > 0 && s[n-1] != ':' { + col_name := intrinsics.alloca(n+2, 1) + builtin.copy(col_name[:n], s) + col_name[n] = ':' + col_name[n+1] = 0 + sel = sel_registerName(cstring(col_name)) + } else { + sel = sel_registerName(name) + } + if callback != nil { + class_addMethod(intrinsics.objc_find_class("NSObject"), sel, auto_cast callback, "v@:@") + } + return sel +} + +@(objc_type=MenuItem, objc_name="init") +MenuItem_init :: proc "c" (self: ^MenuItem) -> ^MenuItem { + return msgSend(^MenuItem, self, "init") +} + + +@(objc_type=MenuItem, objc_name="separatorItem", objc_is_class_method=true) +MenuItem_separatorItem :: #force_inline proc "c" () -> ^MenuItem { + return msgSend(^MenuItem, MenuItem, "separatorItem") +} +@(objc_type=MenuItem, objc_name="sectionHeaderWithTitle", objc_is_class_method=true) +MenuItem_sectionHeaderWithTitle :: #force_inline proc "c" (title: ^String) -> ^MenuItem { + return msgSend(^MenuItem, MenuItem, "sectionHeaderWithTitle:", title) +} +@(objc_type=MenuItem, objc_name="initWithTitle") +MenuItem_initWithTitle :: #force_inline proc "c" (self: ^MenuItem, string: ^String, selector: SEL, charCode: ^String) -> ^MenuItem { + return msgSend(^MenuItem, self, "initWithTitle:action:keyEquivalent:", string, selector, charCode) +} +@(objc_type=MenuItem, objc_name="initWithCoder") +MenuItem_initWithCoder :: #force_inline proc "c" (self: ^MenuItem, coder: ^Coder) -> ^MenuItem { + return msgSend(^MenuItem, self, "initWithCoder:", coder) +} +@(objc_type=MenuItem, objc_name="usesUserKeyEquivalents", objc_is_class_method=true) +MenuItem_usesUserKeyEquivalents :: #force_inline proc "c" () -> bool { + return msgSend(bool, MenuItem, "usesUserKeyEquivalents") +} +@(objc_type=MenuItem, objc_name="setUsesUserKeyEquivalents", objc_is_class_method=true) +MenuItem_setUsesUserKeyEquivalents :: #force_inline proc "c" (usesUserKeyEquivalents: bool) { + msgSend(nil, MenuItem, "setUsesUserKeyEquivalents:", usesUserKeyEquivalents) +} +@(objc_type=MenuItem, objc_name="menu") +MenuItem_menu :: #force_inline proc "c" (self: ^MenuItem) -> ^Menu { + return msgSend(^Menu, self, "menu") +} +@(objc_type=MenuItem, objc_name="setMenu") +MenuItem_setMenu :: #force_inline proc "c" (self: ^MenuItem, menu: ^Menu) { + msgSend(nil, self, "setMenu:", menu) +} +@(objc_type=MenuItem, objc_name="hasSubmenu") +MenuItem_hasSubmenu :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "hasSubmenu") +} +@(objc_type=MenuItem, objc_name="submenu") +MenuItem_submenu :: #force_inline proc "c" (self: ^MenuItem) -> ^Menu { + return msgSend(^Menu, self, "submenu") +} +@(objc_type=MenuItem, objc_name="setSubmenu") +MenuItem_setSubmenu :: #force_inline proc "c" (self: ^MenuItem, submenu: ^Menu) { + msgSend(nil, self, "setSubmenu:", submenu) +} +@(objc_type=MenuItem, objc_name="parentItem") +MenuItem_parentItem :: #force_inline proc "c" (self: ^MenuItem) -> ^MenuItem { + return msgSend(^MenuItem, self, "parentItem") +} +@(objc_type=MenuItem, objc_name="title") +MenuItem_title :: #force_inline proc "c" (self: ^MenuItem) -> ^String { + return msgSend(^String, self, "title") +} +@(objc_type=MenuItem, objc_name="setTitle") +MenuItem_setTitle :: #force_inline proc "c" (self: ^MenuItem, title: ^String) { + msgSend(nil, self, "setTitle:", title) +} +// @(objc_type=MenuItem, objc_name="attributedTitle") +// MenuItem_attributedTitle :: #force_inline proc "c" (self: ^MenuItem) -> ^AttributedString { +// return msgSend(^AttributedString, self, "attributedTitle") +// } +// @(objc_type=MenuItem, objc_name="setAttributedTitle") +// MenuItem_setAttributedTitle :: #force_inline proc "c" (self: ^MenuItem, attributedTitle: ^AttributedString) { +// msgSend(nil, self, "setAttributedTitle:", attributedTitle) +// } +@(objc_type=MenuItem, objc_name="subtitle") +MenuItem_subtitle :: #force_inline proc "c" (self: ^MenuItem) -> ^String { + return msgSend(^String, self, "subtitle") +} +@(objc_type=MenuItem, objc_name="setSubtitle") +MenuItem_setSubtitle :: #force_inline proc "c" (self: ^MenuItem, subtitle: ^String) { + msgSend(nil, self, "setSubtitle:", subtitle) +} +@(objc_type=MenuItem, objc_name="isSeparatorItem") +MenuItem_isSeparatorItem :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "isSeparatorItem") +} +@(objc_type=MenuItem, objc_name="isSectionHeader") +MenuItem_isSectionHeader :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "isSectionHeader") +} +@(objc_type=MenuItem, objc_name="keyEquivalent") +MenuItem_keyEquivalent :: #force_inline proc "c" (self: ^MenuItem) -> ^String { + return msgSend(^String, self, "keyEquivalent") +} +@(objc_type=MenuItem, objc_name="setKeyEquivalent") +MenuItem_setKeyEquivalent :: #force_inline proc "c" (self: ^MenuItem, keyEquivalent: ^String) { + msgSend(nil, self, "setKeyEquivalent:", keyEquivalent) +} +@(objc_type=MenuItem, objc_name="keyEquivalentModifierMask") +MenuItem_keyEquivalentModifierMask :: #force_inline proc "c" (self: ^MenuItem) -> EventModifierFlags { + return msgSend(EventModifierFlags, self, "keyEquivalentModifierMask") +} +@(objc_type=MenuItem, objc_name="setKeyEquivalentModifierMask") +MenuItem_setKeyEquivalentModifierMask :: #force_inline proc "c" (self: ^MenuItem, keyEquivalentModifierMask: EventModifierFlags) { + msgSend(nil, self, "setKeyEquivalentModifierMask:", keyEquivalentModifierMask) +} +@(objc_type=MenuItem, objc_name="userKeyEquivalent") +MenuItem_userKeyEquivalent :: #force_inline proc "c" (self: ^MenuItem) -> ^String { + return msgSend(^String, self, "userKeyEquivalent") +} +@(objc_type=MenuItem, objc_name="allowsKeyEquivalentWhenHidden") +MenuItem_allowsKeyEquivalentWhenHidden :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "allowsKeyEquivalentWhenHidden") +} +@(objc_type=MenuItem, objc_name="setAllowsKeyEquivalentWhenHidden") +MenuItem_setAllowsKeyEquivalentWhenHidden :: #force_inline proc "c" (self: ^MenuItem, allowsKeyEquivalentWhenHidden: bool) { + msgSend(nil, self, "setAllowsKeyEquivalentWhenHidden:", allowsKeyEquivalentWhenHidden) +} +@(objc_type=MenuItem, objc_name="allowsAutomaticKeyEquivalentLocalization") +MenuItem_allowsAutomaticKeyEquivalentLocalization :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "allowsAutomaticKeyEquivalentLocalization") +} +@(objc_type=MenuItem, objc_name="setAllowsAutomaticKeyEquivalentLocalization") +MenuItem_setAllowsAutomaticKeyEquivalentLocalization :: #force_inline proc "c" (self: ^MenuItem, allowsAutomaticKeyEquivalentLocalization: bool) { + msgSend(nil, self, "setAllowsAutomaticKeyEquivalentLocalization:", allowsAutomaticKeyEquivalentLocalization) +} +@(objc_type=MenuItem, objc_name="allowsAutomaticKeyEquivalentMirroring") +MenuItem_allowsAutomaticKeyEquivalentMirroring :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "allowsAutomaticKeyEquivalentMirroring") +} +@(objc_type=MenuItem, objc_name="setAllowsAutomaticKeyEquivalentMirroring") +MenuItem_setAllowsAutomaticKeyEquivalentMirroring :: #force_inline proc "c" (self: ^MenuItem, allowsAutomaticKeyEquivalentMirroring: bool) { + msgSend(nil, self, "setAllowsAutomaticKeyEquivalentMirroring:", allowsAutomaticKeyEquivalentMirroring) +} +// @(objc_type=MenuItem, objc_name="image") +// MenuItem_image :: #force_inline proc "c" (self: ^MenuItem) -> ^Image { +// return msgSend(^Image, self, "image") +// } +// @(objc_type=MenuItem, objc_name="setImage") +// MenuItem_setImage :: #force_inline proc "c" (self: ^MenuItem, image: ^Image) { +// msgSend(nil, self, "setImage:", image) +// } +// @(objc_type=MenuItem, objc_name="state") +// MenuItem_state :: #force_inline proc "c" (self: ^MenuItem) -> ControlStateValue { +// return msgSend(ControlStateValue, self, "state") +// } +// @(objc_type=MenuItem, objc_name="setState") +// MenuItem_setState :: #force_inline proc "c" (self: ^MenuItem, state: ControlStateValue) { +// msgSend(nil, self, "setState:", state) +// } +// @(objc_type=MenuItem, objc_name="onStateImage") +// MenuItem_onStateImage :: #force_inline proc "c" (self: ^MenuItem) -> ^Image { +// return msgSend(^Image, self, "onStateImage") +// } +// @(objc_type=MenuItem, objc_name="setOnStateImage") +// MenuItem_setOnStateImage :: #force_inline proc "c" (self: ^MenuItem, onStateImage: ^Image) { +// msgSend(nil, self, "setOnStateImage:", onStateImage) +// } +// @(objc_type=MenuItem, objc_name="offStateImage") +// MenuItem_offStateImage :: #force_inline proc "c" (self: ^MenuItem) -> ^Image { +// return msgSend(^Image, self, "offStateImage") +// } +// @(objc_type=MenuItem, objc_name="setOffStateImage") +// MenuItem_setOffStateImage :: #force_inline proc "c" (self: ^MenuItem, offStateImage: ^Image) { +// msgSend(nil, self, "setOffStateImage:", offStateImage) +// } +// @(objc_type=MenuItem, objc_name="mixedStateImage") +// MenuItem_mixedStateImage :: #force_inline proc "c" (self: ^MenuItem) -> ^Image { +// return msgSend(^Image, self, "mixedStateImage") +// } +// @(objc_type=MenuItem, objc_name="setMixedStateImage") +// MenuItem_setMixedStateImage :: #force_inline proc "c" (self: ^MenuItem, mixedStateImage: ^Image) { +// msgSend(nil, self, "setMixedStateImage:", mixedStateImage) +// } +@(objc_type=MenuItem, objc_name="isEnabled") +MenuItem_isEnabled :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "isEnabled") +} +@(objc_type=MenuItem, objc_name="setEnabled") +MenuItem_setEnabled :: #force_inline proc "c" (self: ^MenuItem, enabled: bool) { + msgSend(nil, self, "setEnabled:", enabled) +} +@(objc_type=MenuItem, objc_name="isAlternate") +MenuItem_isAlternate :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "isAlternate") +} +@(objc_type=MenuItem, objc_name="setAlternate") +MenuItem_setAlternate :: #force_inline proc "c" (self: ^MenuItem, alternate: bool) { + msgSend(nil, self, "setAlternate:", alternate) +} +@(objc_type=MenuItem, objc_name="indentationLevel") +MenuItem_indentationLevel :: #force_inline proc "c" (self: ^MenuItem) -> Integer { + return msgSend(Integer, self, "indentationLevel") +} +@(objc_type=MenuItem, objc_name="setIndentationLevel") +MenuItem_setIndentationLevel :: #force_inline proc "c" (self: ^MenuItem, indentationLevel: Integer) { + msgSend(nil, self, "setIndentationLevel:", indentationLevel) +} +@(objc_type=MenuItem, objc_name="target") +MenuItem_target :: #force_inline proc "c" (self: ^MenuItem) -> id { + return msgSend(id, self, "target") +} +@(objc_type=MenuItem, objc_name="setTarget") +MenuItem_setTarget :: #force_inline proc "c" (self: ^MenuItem, target: id) { + msgSend(nil, self, "setTarget:", target) +} +@(objc_type=MenuItem, objc_name="action") +MenuItem_action :: #force_inline proc "c" (self: ^MenuItem) -> SEL { + return msgSend(SEL, self, "action") +} +@(objc_type=MenuItem, objc_name="setAction") +MenuItem_setAction :: #force_inline proc "c" (self: ^MenuItem, action: SEL) { + msgSend(nil, self, "setAction:", action) +} +@(objc_type=MenuItem, objc_name="tag") +MenuItem_tag :: #force_inline proc "c" (self: ^MenuItem) -> Integer { + return msgSend(Integer, self, "tag") +} +@(objc_type=MenuItem, objc_name="setTag") +MenuItem_setTag :: #force_inline proc "c" (self: ^MenuItem, tag: Integer) { + msgSend(nil, self, "setTag:", tag) +} +@(objc_type=MenuItem, objc_name="representedObject") +MenuItem_representedObject :: #force_inline proc "c" (self: ^MenuItem) -> id { + return msgSend(id, self, "representedObject") +} +@(objc_type=MenuItem, objc_name="setRepresentedObject") +MenuItem_setRepresentedObject :: #force_inline proc "c" (self: ^MenuItem, representedObject: id) { + msgSend(nil, self, "setRepresentedObject:", representedObject) +} +@(objc_type=MenuItem, objc_name="view") +MenuItem_view :: #force_inline proc "c" (self: ^MenuItem) -> ^View { + return msgSend(^View, self, "view") +} +@(objc_type=MenuItem, objc_name="setView") +MenuItem_setView :: #force_inline proc "c" (self: ^MenuItem, view: ^View) { + msgSend(nil, self, "setView:", view) +} +@(objc_type=MenuItem, objc_name="isHighlighted") +MenuItem_isHighlighted :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "isHighlighted") +} +@(objc_type=MenuItem, objc_name="isHidden") +MenuItem_isHidden :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "isHidden") +} +@(objc_type=MenuItem, objc_name="setHidden") +MenuItem_setHidden :: #force_inline proc "c" (self: ^MenuItem, hidden: bool) { + msgSend(nil, self, "setHidden:", hidden) +} +@(objc_type=MenuItem, objc_name="isHiddenOrHasHiddenAncestor") +MenuItem_isHiddenOrHasHiddenAncestor :: #force_inline proc "c" (self: ^MenuItem) -> bool { + return msgSend(bool, self, "isHiddenOrHasHiddenAncestor") +} +@(objc_type=MenuItem, objc_name="toolTip") +MenuItem_toolTip :: #force_inline proc "c" (self: ^MenuItem) -> ^String { + return msgSend(^String, self, "toolTip") +} +@(objc_type=MenuItem, objc_name="setToolTip") +MenuItem_setToolTip :: #force_inline proc "c" (self: ^MenuItem, toolTip: ^String) { + msgSend(nil, self, "setToolTip:", toolTip) +} +// @(objc_type=MenuItem, objc_name="badge") +// MenuItem_badge :: #force_inline proc "c" (self: ^MenuItem) -> ^MenuItemBadge { +// return msgSend(^MenuItemBadge, self, "badge") +// } +// @(objc_type=MenuItem, objc_name="setBadge") +// MenuItem_setBadge :: #force_inline proc "c" (self: ^MenuItem, badge: ^MenuItemBadge) { +// msgSend(nil, self, "setBadge:", badge) +// } +@(objc_type=MenuItem, objc_name="setMnemonicLocation") +MenuItem_setMnemonicLocation :: #force_inline proc "c" (self: ^MenuItem, location: UInteger) { + msgSend(nil, self, "setMnemonicLocation:", location) +} +@(objc_type=MenuItem, objc_name="mnemonicLocation") +MenuItem_mnemonicLocation :: #force_inline proc "c" (self: ^MenuItem) -> UInteger { + return msgSend(UInteger, self, "mnemonicLocation") +} +@(objc_type=MenuItem, objc_name="mnemonic") +MenuItem_mnemonic :: #force_inline proc "c" (self: ^MenuItem) -> ^String { + return msgSend(^String, self, "mnemonic") +} +@(objc_type=MenuItem, objc_name="setTitleWithMnemonic") +MenuItem_setTitleWithMnemonic :: #force_inline proc "c" (self: ^MenuItem, stringWithAmpersand: ^String) { + msgSend(nil, self, "setTitleWithMnemonic:", stringWithAmpersand) +} +@(objc_type=MenuItem, objc_name="load", objc_is_class_method=true) +MenuItem_load :: #force_inline proc "c" () { + msgSend(nil, MenuItem, "load") +} +@(objc_type=MenuItem, objc_name="initialize", objc_is_class_method=true) +MenuItem_initialize :: #force_inline proc "c" () { + msgSend(nil, MenuItem, "initialize") +} +@(objc_type=MenuItem, objc_name="new", objc_is_class_method=true) +MenuItem_new :: #force_inline proc "c" () -> ^MenuItem { + return msgSend(^MenuItem, MenuItem, "new") +} +@(objc_type=MenuItem, objc_name="allocWithZone", objc_is_class_method=true) +MenuItem_allocWithZone :: #force_inline proc "c" (zone: ^Zone) -> ^MenuItem { + return msgSend(^MenuItem, MenuItem, "allocWithZone:", zone) +} +@(objc_type=MenuItem, objc_name="alloc", objc_is_class_method=true) +MenuItem_alloc :: #force_inline proc "c" () -> ^MenuItem { + return msgSend(^MenuItem, MenuItem, "alloc") +} +@(objc_type=MenuItem, objc_name="copyWithZone", objc_is_class_method=true) +MenuItem_copyWithZone :: #force_inline proc "c" (zone: ^Zone) -> id { + return msgSend(id, MenuItem, "copyWithZone:", zone) +} +@(objc_type=MenuItem, objc_name="mutableCopyWithZone", objc_is_class_method=true) +MenuItem_mutableCopyWithZone :: #force_inline proc "c" (zone: ^Zone) -> id { + return msgSend(id, MenuItem, "mutableCopyWithZone:", zone) +} +@(objc_type=MenuItem, objc_name="instancesRespondToSelector", objc_is_class_method=true) +MenuItem_instancesRespondToSelector :: #force_inline proc "c" (aSelector: SEL) -> bool { + return msgSend(bool, MenuItem, "instancesRespondToSelector:", aSelector) +} +@(objc_type=MenuItem, objc_name="conformsToProtocol", objc_is_class_method=true) +MenuItem_conformsToProtocol :: #force_inline proc "c" (protocol: ^Protocol) -> bool { + return msgSend(bool, MenuItem, "conformsToProtocol:", protocol) +} +@(objc_type=MenuItem, objc_name="instanceMethodForSelector", objc_is_class_method=true) +MenuItem_instanceMethodForSelector :: #force_inline proc "c" (aSelector: SEL) -> IMP { + return msgSend(IMP, MenuItem, "instanceMethodForSelector:", aSelector) +} +// @(objc_type=MenuItem, objc_name="instanceMethodSignatureForSelector", objc_is_class_method=true) +// MenuItem_instanceMethodSignatureForSelector :: #force_inline proc "c" (aSelector: SEL) -> ^MethodSignature { +// return msgSend(^MethodSignature, MenuItem, "instanceMethodSignatureForSelector:", aSelector) +// } +@(objc_type=MenuItem, objc_name="isSubclassOfClass", objc_is_class_method=true) +MenuItem_isSubclassOfClass :: #force_inline proc "c" (aClass: Class) -> bool { + return msgSend(bool, MenuItem, "isSubclassOfClass:", aClass) +} +@(objc_type=MenuItem, objc_name="resolveClassMethod", objc_is_class_method=true) +MenuItem_resolveClassMethod :: #force_inline proc "c" (sel: SEL) -> bool { + return msgSend(bool, MenuItem, "resolveClassMethod:", sel) +} +@(objc_type=MenuItem, objc_name="resolveInstanceMethod", objc_is_class_method=true) +MenuItem_resolveInstanceMethod :: #force_inline proc "c" (sel: SEL) -> bool { + return msgSend(bool, MenuItem, "resolveInstanceMethod:", sel) +} +@(objc_type=MenuItem, objc_name="hash", objc_is_class_method=true) +MenuItem_hash :: #force_inline proc "c" () -> UInteger { + return msgSend(UInteger, MenuItem, "hash") +} +@(objc_type=MenuItem, objc_name="superclass", objc_is_class_method=true) +MenuItem_superclass :: #force_inline proc "c" () -> Class { + return msgSend(Class, MenuItem, "superclass") +} +@(objc_type=MenuItem, objc_name="class", objc_is_class_method=true) +MenuItem_class :: #force_inline proc "c" () -> Class { + return msgSend(Class, MenuItem, "class") +} +@(objc_type=MenuItem, objc_name="description", objc_is_class_method=true) +MenuItem_description :: #force_inline proc "c" () -> ^String { + return msgSend(^String, MenuItem, "description") +} +@(objc_type=MenuItem, objc_name="debugDescription", objc_is_class_method=true) +MenuItem_debugDescription :: #force_inline proc "c" () -> ^String { + return msgSend(^String, MenuItem, "debugDescription") +} +@(objc_type=MenuItem, objc_name="version", objc_is_class_method=true) +MenuItem_version :: #force_inline proc "c" () -> Integer { + return msgSend(Integer, MenuItem, "version") +} +@(objc_type=MenuItem, objc_name="setVersion", objc_is_class_method=true) +MenuItem_setVersion :: #force_inline proc "c" (aVersion: Integer) { + msgSend(nil, MenuItem, "setVersion:", aVersion) +} +@(objc_type=MenuItem, objc_name="poseAsClass", objc_is_class_method=true) +MenuItem_poseAsClass :: #force_inline proc "c" (aClass: Class) { + msgSend(nil, MenuItem, "poseAsClass:", aClass) +} +@(objc_type=MenuItem, objc_name="cancelPreviousPerformRequestsWithTarget_selector_object", objc_is_class_method=true) +MenuItem_cancelPreviousPerformRequestsWithTarget_selector_object :: #force_inline proc "c" (aTarget: id, aSelector: SEL, anArgument: id) { + msgSend(nil, MenuItem, "cancelPreviousPerformRequestsWithTarget:selector:object:", aTarget, aSelector, anArgument) +} +@(objc_type=MenuItem, objc_name="cancelPreviousPerformRequestsWithTarget_", objc_is_class_method=true) +MenuItem_cancelPreviousPerformRequestsWithTarget_ :: #force_inline proc "c" (aTarget: id) { + msgSend(nil, MenuItem, "cancelPreviousPerformRequestsWithTarget:", aTarget) +} +@(objc_type=MenuItem, objc_name="accessInstanceVariablesDirectly", objc_is_class_method=true) +MenuItem_accessInstanceVariablesDirectly :: #force_inline proc "c" () -> bool { + return msgSend(bool, MenuItem, "accessInstanceVariablesDirectly") +} +@(objc_type=MenuItem, objc_name="useStoredAccessor", objc_is_class_method=true) +MenuItem_useStoredAccessor :: #force_inline proc "c" () -> bool { + return msgSend(bool, MenuItem, "useStoredAccessor") +} +@(objc_type=MenuItem, objc_name="keyPathsForValuesAffectingValueForKey", objc_is_class_method=true) +MenuItem_keyPathsForValuesAffectingValueForKey :: #force_inline proc "c" (key: ^String) -> ^Set { + return msgSend(^Set, MenuItem, "keyPathsForValuesAffectingValueForKey:", key) +} +@(objc_type=MenuItem, objc_name="automaticallyNotifiesObserversForKey", objc_is_class_method=true) +MenuItem_automaticallyNotifiesObserversForKey :: #force_inline proc "c" (key: ^String) -> bool { + return msgSend(bool, MenuItem, "automaticallyNotifiesObserversForKey:", key) +} +@(objc_type=MenuItem, objc_name="setKeys", objc_is_class_method=true) +MenuItem_setKeys :: #force_inline proc "c" (keys: ^Array, dependentKey: ^String) { + msgSend(nil, MenuItem, "setKeys:triggerChangeNotificationsForDependentKey:", keys, dependentKey) +} +@(objc_type=MenuItem, objc_name="classFallbacksForKeyedArchiver", objc_is_class_method=true) +MenuItem_classFallbacksForKeyedArchiver :: #force_inline proc "c" () -> ^Array { + return msgSend(^Array, MenuItem, "classFallbacksForKeyedArchiver") +} +@(objc_type=MenuItem, objc_name="classForKeyedUnarchiver", objc_is_class_method=true) +MenuItem_classForKeyedUnarchiver :: #force_inline proc "c" () -> Class { + return msgSend(Class, MenuItem, "classForKeyedUnarchiver") +} +@(objc_type=MenuItem, objc_name="exposeBinding", objc_is_class_method=true) +MenuItem_exposeBinding :: #force_inline proc "c" (binding: ^String) { + msgSend(nil, MenuItem, "exposeBinding:", binding) +} +@(objc_type=MenuItem, objc_name="setDefaultPlaceholder", objc_is_class_method=true) +MenuItem_setDefaultPlaceholder :: #force_inline proc "c" (placeholder: id, marker: id, binding: ^String) { + msgSend(nil, MenuItem, "setDefaultPlaceholder:forMarker:withBinding:", placeholder, marker, binding) +} +@(objc_type=MenuItem, objc_name="defaultPlaceholderForMarker", objc_is_class_method=true) +MenuItem_defaultPlaceholderForMarker :: #force_inline proc "c" (marker: id, binding: ^String) -> id { + return msgSend(id, MenuItem, "defaultPlaceholderForMarker:withBinding:", marker, binding) +} +@(objc_type=MenuItem, objc_name="cancelPreviousPerformRequestsWithTarget") +MenuItem_cancelPreviousPerformRequestsWithTarget :: proc { + MenuItem_cancelPreviousPerformRequestsWithTarget_selector_object, + MenuItem_cancelPreviousPerformRequestsWithTarget_, +} \ No newline at end of file diff --git a/core/sys/darwin/Foundation/NSNotification.odin b/core/sys/darwin/Foundation/NSNotification.odin index f766d0cab..f2f4e819b 100644 --- a/core/sys/darwin/Foundation/NSNotification.odin +++ b/core/sys/darwin/Foundation/NSNotification.odin @@ -50,10 +50,22 @@ NotificationCenter_defaultCenter :: proc "c" () -> ^NotificationCenter { return msgSend(^NotificationCenter, NotificationCenter, "defaultCenter") } -@(objc_type=NotificationCenter, objc_name="addObserver") -NotificationCenter_addObserverName :: proc "c" (self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Block) -> ^Object { - return msgSend(^Object, self, "addObserverName:object:queue:block:", name, pObj, pQueue, block) +@(objc_type=NotificationCenter, objc_name="addObserverForName") +NotificationCenter_addObserverForName :: proc{NotificationCenter_addObserverForName_old, NotificationCenter_addObserverForName_new} + +NotificationCenter_addObserverForName_old :: proc "c" (self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Block) -> ^Object { + return msgSend(^Object, self, "addObserverForName:object:queue:usingBlock:", name, pObj, pQueue, block) } + +NotificationCenter_addObserverForName_new :: proc "c" (self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Objc_Block) -> ^Object { + return msgSend(^Object, self, "addObserverForName:object:queue:usingBlock:", name, pObj, pQueue, block) +} + +@(objc_type=NotificationCenter, objc_name="addObserver") +NotificationCenter_addObserver :: proc "c" (self: ^NotificationCenter, observer: ^Object, selector: SEL, name: NotificationName, object: ^Object) { + msgSend(nil, self, "addObserver:selector:name:object:", observer, selector, name, object) +} + @(objc_type=NotificationCenter, objc_name="removeObserver") NotificationCenter_removeObserver :: proc "c" (self: ^NotificationCenter, pObserver: ^Object) { msgSend(nil, self, "removeObserver:", pObserver) diff --git a/core/sys/darwin/Foundation/NSWindow.odin b/core/sys/darwin/Foundation/NSWindow.odin index 57ac2b6f6..e1b027a89 100644 --- a/core/sys/darwin/Foundation/NSWindow.odin +++ b/core/sys/darwin/Foundation/NSWindow.odin @@ -146,7 +146,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla return nil } if template.windowWillPositionSheetUsingRect != nil { - windowWillPositionSheetUsingRect :: proc "c" (self: id, window: ^Window, sheet: ^Window, rect: Rect) -> Rect { + windowWillPositionSheetUsingRect :: proc "c" (self: id, cmd: SEL, window: ^Window, sheet: ^Window, rect: Rect) -> Rect { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowWillPositionSheetUsingRect(window, sheet, rect) @@ -154,7 +154,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:willPositionSheet:usingRect:"), auto_cast windowWillPositionSheetUsingRect, _RECT_ENCODING+"@:@@"+_RECT_ENCODING) } if template.windowWillBeginSheet != nil { - windowWillBeginSheet :: proc "c" (self: id, notification: ^Notification) { + windowWillBeginSheet :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillBeginSheet(notification) @@ -162,7 +162,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillBeginSheet:"), auto_cast windowWillBeginSheet, "v@:@") } if template.windowDidEndSheet != nil { - windowDidEndSheet :: proc "c" (self: id, notification: ^Notification) { + windowDidEndSheet :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidEndSheet(notification) @@ -170,7 +170,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidEndSheet:"), auto_cast windowDidEndSheet, "v@:@") } if template.windowWillResizeToSize != nil { - windowWillResizeToSize :: proc "c" (self: id, sender: ^Window, frameSize: Size) -> Size { + windowWillResizeToSize :: proc "c" (self: id, cmd: SEL, sender: ^Window, frameSize: Size) -> Size { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowWillResizeToSize(sender, frameSize) @@ -178,7 +178,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillResize:toSize:"), auto_cast windowWillResizeToSize, _SIZE_ENCODING+"@:@"+_SIZE_ENCODING) } if template.windowDidResize != nil { - windowDidResize :: proc "c" (self: id, notification: ^Notification) { + windowDidResize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidResize(notification) @@ -186,7 +186,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidResize:"), auto_cast windowDidResize, "v@:@") } if template.windowWillStartLiveResize != nil { - windowWillStartLiveResize :: proc "c" (self: id, notification: ^Notification) { + windowWillStartLiveResize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillStartLiveResize(notification) @@ -194,7 +194,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillStartLiveResize:"), auto_cast windowWillStartLiveResize, "v@:@") } if template.windowDidEndLiveResize != nil { - windowDidEndLiveResize :: proc "c" (self: id, notification: ^Notification) { + windowDidEndLiveResize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidEndLiveResize(notification) @@ -202,7 +202,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidEndLiveResize:"), auto_cast windowDidEndLiveResize, "v@:@") } if template.windowWillMiniaturize != nil { - windowWillMiniaturize :: proc "c" (self: id, notification: ^Notification) { + windowWillMiniaturize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillMiniaturize(notification) @@ -210,7 +210,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillMiniaturize:"), auto_cast windowWillMiniaturize, "v@:@") } if template.windowDidMiniaturize != nil { - windowDidMiniaturize :: proc "c" (self: id, notification: ^Notification) { + windowDidMiniaturize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidMiniaturize(notification) @@ -218,7 +218,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidMiniaturize:"), auto_cast windowDidMiniaturize, "v@:@") } if template.windowDidDeminiaturize != nil { - windowDidDeminiaturize :: proc "c" (self: id, notification: ^Notification) { + windowDidDeminiaturize :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidDeminiaturize(notification) @@ -226,7 +226,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidDeminiaturize:"), auto_cast windowDidDeminiaturize, "v@:@") } if template.windowWillUseStandardFrameDefaultFrame != nil { - windowWillUseStandardFrameDefaultFrame :: proc(self: id, window: ^Window, newFrame: Rect) -> Rect { + windowWillUseStandardFrameDefaultFrame :: proc(self: id, cmd: SEL, window: ^Window, newFrame: Rect) -> Rect { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowWillUseStandardFrameDefaultFrame(window, newFrame) @@ -234,7 +234,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillUseStandardFrame:defaultFrame:"), auto_cast windowWillUseStandardFrameDefaultFrame, _RECT_ENCODING+"@:@"+_RECT_ENCODING) } if template.windowShouldZoomToFrame != nil { - windowShouldZoomToFrame :: proc "c" (self: id, window: ^Window, newFrame: Rect) -> BOOL { + windowShouldZoomToFrame :: proc "c" (self: id, cmd: SEL, window: ^Window, newFrame: Rect) -> BOOL { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowShouldZoomToFrame(window, newFrame) @@ -242,7 +242,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowShouldZoom:toFrame:"), auto_cast windowShouldZoomToFrame, "B@:@"+_RECT_ENCODING) } if template.windowWillUseFullScreenContentSize != nil { - windowWillUseFullScreenContentSize :: proc "c" (self: id, window: ^Window, proposedSize: Size) -> Size { + windowWillUseFullScreenContentSize :: proc "c" (self: id, cmd: SEL, window: ^Window, proposedSize: Size) -> Size { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowWillUseFullScreenContentSize(window, proposedSize) @@ -250,7 +250,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:willUseFullScreenContentSize:"), auto_cast windowWillUseFullScreenContentSize, _SIZE_ENCODING+"@:@"+_SIZE_ENCODING) } if template.windowWillUseFullScreenPresentationOptions != nil { - windowWillUseFullScreenPresentationOptions :: proc(self: id, window: ^Window, proposedOptions: ApplicationPresentationOptions) -> ApplicationPresentationOptions { + windowWillUseFullScreenPresentationOptions :: proc(self: id, cmd: SEL, window: ^Window, proposedOptions: ApplicationPresentationOptions) -> ApplicationPresentationOptions { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowWillUseFullScreenPresentationOptions(window, proposedOptions) @@ -258,7 +258,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:willUseFullScreenPresentationOptions:"), auto_cast windowWillUseFullScreenPresentationOptions, _UINTEGER_ENCODING+"@:@"+_UINTEGER_ENCODING) } if template.windowWillEnterFullScreen != nil { - windowWillEnterFullScreen :: proc "c" (self: id, notification: ^Notification) { + windowWillEnterFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillEnterFullScreen(notification) @@ -266,7 +266,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillEnterFullScreen:"), auto_cast windowWillEnterFullScreen, "v@:@") } if template.windowDidEnterFullScreen != nil { - windowDidEnterFullScreen :: proc "c" (self: id, notification: ^Notification) { + windowDidEnterFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidEnterFullScreen(notification) @@ -274,7 +274,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidEnterFullScreen:"), auto_cast windowDidEnterFullScreen, "v@:@") } if template.windowWillExitFullScreen != nil { - windowWillExitFullScreen :: proc "c" (self: id, notification: ^Notification) { + windowWillExitFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillExitFullScreen(notification) @@ -282,7 +282,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillExitFullScreen:"), auto_cast windowWillExitFullScreen, "v@:@") } if template.windowDidExitFullScreen != nil { - windowDidExitFullScreen :: proc "c" (self: id, notification: ^Notification) { + windowDidExitFullScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidExitFullScreen(notification) @@ -290,7 +290,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidExitFullScreen:"), auto_cast windowDidExitFullScreen, "v@:@") } if template.customWindowsToEnterFullScreenForWindow != nil { - customWindowsToEnterFullScreenForWindow :: proc "c" (self: id, window: ^Window) -> ^Array { + customWindowsToEnterFullScreenForWindow :: proc "c" (self: id, cmd: SEL, window: ^Window) -> ^Array { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.customWindowsToEnterFullScreenForWindow(window) @@ -298,7 +298,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("customWindowsToEnterFullScreenForWindow:"), auto_cast customWindowsToEnterFullScreenForWindow, "@@:@") } if template.customWindowsToEnterFullScreenForWindowOnScreen != nil { - customWindowsToEnterFullScreenForWindowOnScreen :: proc(self: id, window: ^Window, screen: ^Screen) -> ^Array { + customWindowsToEnterFullScreenForWindowOnScreen :: proc(self: id, cmd: SEL, window: ^Window, screen: ^Screen) -> ^Array { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.customWindowsToEnterFullScreenForWindowOnScreen(window, screen) @@ -306,7 +306,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("customWindowsToEnterFullScreenForWindow:onScreen:"), auto_cast customWindowsToEnterFullScreenForWindowOnScreen, "@@:@@") } if template.windowStartCustomAnimationToEnterFullScreenWithDuration != nil { - windowStartCustomAnimationToEnterFullScreenWithDuration :: proc "c" (self: id, window: ^Window, duration: TimeInterval) { + windowStartCustomAnimationToEnterFullScreenWithDuration :: proc "c" (self: id, cmd: SEL, window: ^Window, duration: TimeInterval) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowStartCustomAnimationToEnterFullScreenWithDuration(window, duration) @@ -314,7 +314,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:startCustomAnimationToEnterFullScreenWithDuration:"), auto_cast windowStartCustomAnimationToEnterFullScreenWithDuration, "v@:@@") } if template.windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration != nil { - windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration :: proc(self: id, window: ^Window, screen: ^Screen, duration: TimeInterval) { + windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration :: proc(self: id, cmd: SEL, window: ^Window, screen: ^Screen, duration: TimeInterval) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration(window, screen, duration) @@ -322,7 +322,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:startCustomAnimationToEnterFullScreenOnScreen:withDuration:"), auto_cast windowStartCustomAnimationToEnterFullScreenOnScreenWithDuration, "v@:@@d") } if template.windowDidFailToEnterFullScreen != nil { - windowDidFailToEnterFullScreen :: proc "c" (self: id, window: ^Window) { + windowDidFailToEnterFullScreen :: proc "c" (self: id, cmd: SEL, window: ^Window) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidFailToEnterFullScreen(window) @@ -330,7 +330,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidFailToEnterFullScreen:"), auto_cast windowDidFailToEnterFullScreen, "v@:@") } if template.customWindowsToExitFullScreenForWindow != nil { - customWindowsToExitFullScreenForWindow :: proc "c" (self: id, window: ^Window) -> ^Array { + customWindowsToExitFullScreenForWindow :: proc "c" (self: id, cmd: SEL, window: ^Window) -> ^Array { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.customWindowsToExitFullScreenForWindow(window) @@ -338,7 +338,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("customWindowsToExitFullScreenForWindow:"), auto_cast customWindowsToExitFullScreenForWindow, "@@:@") } if template.windowStartCustomAnimationToExitFullScreenWithDuration != nil { - windowStartCustomAnimationToExitFullScreenWithDuration :: proc "c" (self: id, window: ^Window, duration: TimeInterval) { + windowStartCustomAnimationToExitFullScreenWithDuration :: proc "c" (self: id, cmd: SEL, window: ^Window, duration: TimeInterval) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowStartCustomAnimationToExitFullScreenWithDuration(window, duration) @@ -346,7 +346,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:startCustomAnimationToExitFullScreenWithDuration:"), auto_cast windowStartCustomAnimationToExitFullScreenWithDuration, "v@:@d") } if template.windowDidFailToExitFullScreen != nil { - windowDidFailToExitFullScreen :: proc "c" (self: id, window: ^Window) { + windowDidFailToExitFullScreen :: proc "c" (self: id, cmd: SEL, window: ^Window) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidFailToExitFullScreen(window) @@ -354,7 +354,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidFailToExitFullScreen:"), auto_cast windowDidFailToExitFullScreen, "v@:@") } if template.windowWillMove != nil { - windowWillMove :: proc "c" (self: id, notification: ^Notification) { + windowWillMove :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillMove(notification) @@ -362,7 +362,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillMove:"), auto_cast windowWillMove, "v@:@") } if template.windowDidMove != nil { - windowDidMove :: proc "c" (self: id, notification: ^Notification) { + windowDidMove :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidMove(notification) @@ -370,7 +370,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidMove:"), auto_cast windowDidMove, "v@:@") } if template.windowDidChangeScreen != nil { - windowDidChangeScreen :: proc "c" (self: id, notification: ^Notification) { + windowDidChangeScreen :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidChangeScreen(notification) @@ -378,7 +378,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeScreen:"), auto_cast windowDidChangeScreen, "v@:@") } if template.windowDidChangeScreenProfile != nil { - windowDidChangeScreenProfile :: proc "c" (self: id, notification: ^Notification) { + windowDidChangeScreenProfile :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidChangeScreenProfile(notification) @@ -386,7 +386,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeScreenProfile:"), auto_cast windowDidChangeScreenProfile, "v@:@") } if template.windowDidChangeBackingProperties != nil { - windowDidChangeBackingProperties :: proc "c" (self: id, notification: ^Notification) { + windowDidChangeBackingProperties :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidChangeBackingProperties(notification) @@ -394,7 +394,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeBackingProperties:"), auto_cast windowDidChangeBackingProperties, "v@:@") } if template.windowShouldClose != nil { - windowShouldClose :: proc "c" (self:id, sender: ^Window) -> BOOL { + windowShouldClose :: proc "c" (self:id, cmd: SEL, sender: ^Window) -> BOOL { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowShouldClose(sender) @@ -402,7 +402,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowShouldClose:"), auto_cast windowShouldClose, "B@:@") } if template.windowWillClose != nil { - windowWillClose :: proc "c" (self:id, notification: ^Notification) { + windowWillClose :: proc "c" (self:id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillClose(notification) @@ -410,7 +410,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillClose:"), auto_cast windowWillClose, "v@:@") } if template.windowDidBecomeKey != nil { - windowDidBecomeKey :: proc "c" (self: id, notification: ^Notification) { + windowDidBecomeKey :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidBecomeKey(notification) @@ -418,7 +418,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidBecomeKey:"), auto_cast windowDidBecomeKey, "v@:@") } if template.windowDidResignKey != nil { - windowDidResignKey :: proc "c" (self: id, notification: ^Notification) { + windowDidResignKey :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidResignKey(notification) @@ -426,7 +426,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidResignKey:"), auto_cast windowDidResignKey, "v@:@") } if template.windowDidBecomeMain != nil { - windowDidBecomeMain :: proc "c" (self: id, notification: ^Notification) { + windowDidBecomeMain :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidBecomeMain(notification) @@ -434,7 +434,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidBecomeMain:"), auto_cast windowDidBecomeMain, "v@:@") } if template.windowDidResignMain != nil { - windowDidResignMain :: proc "c" (self: id, notification: ^Notification) { + windowDidResignMain :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidResignMain(notification) @@ -442,7 +442,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidResignMain:"), auto_cast windowDidResignMain, "v@:@") } if template.windowWillReturnFieldEditorToObject != nil { - windowWillReturnFieldEditorToObject :: proc "c" (self:id, sender: ^Window, client: id) -> id { + windowWillReturnFieldEditorToObject :: proc "c" (self:id, cmd: SEL, sender: ^Window, client: id) -> id { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowWillReturnFieldEditorToObject(sender, client) @@ -450,7 +450,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillReturnFieldEditor:toObject:"), auto_cast windowWillReturnFieldEditorToObject, "@@:@@") } if template.windowDidUpdate != nil { - windowDidUpdate :: proc "c" (self: id, notification: ^Notification) { + windowDidUpdate :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidUpdate(notification) @@ -458,7 +458,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidUpdate:"), auto_cast windowDidUpdate, "v@:@") } if template.windowDidExpose != nil { - windowDidExpose :: proc "c" (self: id, notification: ^Notification) { + windowDidExpose :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidExpose(notification) @@ -466,7 +466,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidExpose:"), auto_cast windowDidExpose, "v@:@") } if template.windowDidChangeOcclusionState != nil { - windowDidChangeOcclusionState :: proc "c" (self: id, notification: ^Notification) { + windowDidChangeOcclusionState :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidChangeOcclusionState(notification) @@ -474,7 +474,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidChangeOcclusionState:"), auto_cast windowDidChangeOcclusionState, "v@:@") } if template.windowShouldDragDocumentWithEventFromWithPasteboard != nil { - windowShouldDragDocumentWithEventFromWithPasteboard :: proc "c" (self: id, window: ^Window, event: ^Event, dragImageLocation: Point, pasteboard: ^Pasteboard) -> BOOL { + windowShouldDragDocumentWithEventFromWithPasteboard :: proc "c" (self: id, cmd: SEL, window: ^Window, event: ^Event, dragImageLocation: Point, pasteboard: ^Pasteboard) -> BOOL { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowShouldDragDocumentWithEventFromWithPasteboard(window, event, dragImageLocation, pasteboard) @@ -482,7 +482,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:shouldDragDocumentWithEvent:from:withPasteboard:"), auto_cast windowShouldDragDocumentWithEventFromWithPasteboard, "B@:@@"+_POINT_ENCODING+"@") } if template.windowWillReturnUndoManager != nil { - windowWillReturnUndoManager :: proc "c" (self: id, window: ^Window) -> ^UndoManager { + windowWillReturnUndoManager :: proc "c" (self: id, cmd: SEL, window: ^Window) -> ^UndoManager { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowWillReturnUndoManager(window) @@ -490,7 +490,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillReturnUndoManager:"), auto_cast windowWillReturnUndoManager, "@@:@") } if template.windowShouldPopUpDocumentPathMenu != nil { - windowShouldPopUpDocumentPathMenu :: proc "c" (self: id, window: ^Window, menu: ^Menu) -> BOOL { + windowShouldPopUpDocumentPathMenu :: proc "c" (self: id, cmd: SEL, window: ^Window, menu: ^Menu) -> BOOL { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowShouldPopUpDocumentPathMenu(window, menu) @@ -498,7 +498,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:shouldPopUpDocumentPathMenu:"), auto_cast windowShouldPopUpDocumentPathMenu, "B@:@@") } if template.windowWillEncodeRestorableState != nil { - windowWillEncodeRestorableState :: proc "c" (self: id, window: ^Window, state: ^Coder) { + windowWillEncodeRestorableState :: proc "c" (self: id, cmd: SEL, window: ^Window, state: ^Coder) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillEncodeRestorableState(window, state) @@ -506,7 +506,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:willEncodeRestorableState:"), auto_cast windowWillEncodeRestorableState, "v@:@@") } if template.windowDidEncodeRestorableState != nil { - windowDidEncodeRestorableState :: proc "c" (self: id, window: ^Window, state: ^Coder) { + windowDidEncodeRestorableState :: proc "c" (self: id, cmd: SEL, window: ^Window, state: ^Coder) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidEncodeRestorableState(window, state) @@ -514,7 +514,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:didDecodeRestorableState:"), auto_cast windowDidEncodeRestorableState, "v@:@@") } if template.windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize != nil { - windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize :: proc "c" (self: id, window: ^Window, maxPreferredFrameSize: Size, maxAllowedFrameSize: Size) -> Size { + windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize :: proc "c" (self: id, cmd: SEL, window: ^Window, maxPreferredFrameSize: Size, maxAllowedFrameSize: Size) -> Size { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context return del.windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize(window, maxPreferredFrameSize, maxPreferredFrameSize) @@ -522,7 +522,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("window:willResizeForVersionBrowserWithMaxPreferredSize:maxAllowedSize:"), auto_cast windowWillResizeForVersionBrowserWithMaxPreferredSizeMaxAllowedSize, _SIZE_ENCODING+"@:@"+_SIZE_ENCODING+_SIZE_ENCODING) } if template.windowWillEnterVersionBrowser != nil { - windowWillEnterVersionBrowser :: proc "c" (self: id, notification: ^Notification) { + windowWillEnterVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillEnterVersionBrowser(notification) @@ -530,7 +530,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillEnterVersionBrowser:"), auto_cast windowWillEnterVersionBrowser, "v@:@") } if template.windowDidEnterVersionBrowser != nil { - windowDidEnterVersionBrowser :: proc "c" (self: id, notification: ^Notification) { + windowDidEnterVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidEnterVersionBrowser(notification) @@ -538,7 +538,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowDidEnterVersionBrowser:"), auto_cast windowDidEnterVersionBrowser, "v@:@") } if template.windowWillExitVersionBrowser != nil { - windowWillExitVersionBrowser :: proc "c" (self: id, notification: ^Notification) { + windowWillExitVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowWillExitVersionBrowser(notification) @@ -546,7 +546,7 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla class_addMethod(class, intrinsics.objc_find_selector("windowWillExitVersionBrowser:"), auto_cast windowWillExitVersionBrowser, "v@:@") } if template.windowDidExitVersionBrowser != nil { - windowDidExitVersionBrowser :: proc "c" (self: id, notification: ^Notification) { + windowDidExitVersionBrowser :: proc "c" (self: id, cmd: SEL, notification: ^Notification) { del := cast(^_WindowDelegateInternal)object_getIndexedIvars(self) context = del._context del.windowDidExitVersionBrowser(notification) @@ -568,6 +568,15 @@ window_delegate_register_and_alloc :: proc(template: WindowDelegateTemplate, cla @(objc_class="CALayer") Layer :: struct { using _: Object } + +@(objc_type=Layer, objc_name="contents") +Layer_contents :: proc "c" (self: ^Layer) -> rawptr { + return msgSend(rawptr, self, "contents") +} +@(objc_type=Layer, objc_name="setContents") +Layer_setContents :: proc "c" (self: ^Layer, contents: rawptr) { + msgSend(nil, self, "setContents:", contents) +} @(objc_type=Layer, objc_name="contentsScale") Layer_contentsScale :: proc "c" (self: ^Layer) -> Float { return msgSend(Float, self, "contentsScale") @@ -654,8 +663,12 @@ Window_frame :: proc "c" (self: ^Window) -> Rect { return msgSend(Rect, self, "frame") } @(objc_type=Window, objc_name="setFrame") -Window_setFrame :: proc "c" (self: ^Window, frame: Rect) { - msgSend(nil, self, "setFrame:", frame) +Window_setFrame :: proc "c" (self: ^Window, frame: Rect, display: BOOL) { + msgSend(nil, self, "setFrame:display:", frame, display) +} +@(objc_type=Window, objc_name="setFrameOrigin") +Window_setFrameOrigin :: proc "c" (self: ^Window, origin: Point) { + msgSend(nil, self, "setFrameOrigin:", origin) } @(objc_type=Window, objc_name="opaque") Window_opaque :: proc "c" (self: ^Window) -> BOOL { @@ -693,6 +706,10 @@ Window_setMovable :: proc "c" (self: ^Window, ok: BOOL) { Window_setMovableByWindowBackground :: proc "c" (self: ^Window, ok: BOOL) { msgSend(nil, self, "setMovableByWindowBackground:", ok) } +@(objc_type=Window, objc_name="setAcceptsMouseMovedEvents") +Window_setAcceptsMouseMovedEvents :: proc "c" (self: ^Window, ok: BOOL) { + msgSend(nil, self, "setAcceptsMouseMovedEvents:", ok) +} @(objc_type=Window, objc_name="setStyleMask") Window_setStyleMask :: proc "c" (self: ^Window, style_mask: WindowStyleMask) { msgSend(nil, self, "setStyleMask:", style_mask) @@ -780,4 +797,4 @@ Window_performWindowDragWithEvent :: proc "c" (self: ^Window, event: ^Event) { @(objc_type=Window, objc_name="setToolbar") Window_setToolbar :: proc "c" (self: ^Window, toolbar: ^Toolbar) { msgSend(nil, self, "setToolbar:", toolbar) -} \ No newline at end of file +} diff --git a/core/sys/darwin/Foundation/objc_helper.odin b/core/sys/darwin/Foundation/objc_helper.odin new file mode 100644 index 000000000..0748d700b --- /dev/null +++ b/core/sys/darwin/Foundation/objc_helper.odin @@ -0,0 +1,136 @@ +package objc_Foundation + +import "base:runtime" +import "base:intrinsics" + +Subclasser_Proc :: proc(cls: Class, vtable: rawptr) + +Object_VTable_Info :: struct { + vtable: rawptr, + size: uint, + impl: Subclasser_Proc, +} + +Class_VTable_Info :: struct { + _context: runtime.Context, + super_vtable: rawptr, + protocol_vtable: rawptr, +} + +@(require_results) +class_get_metaclass :: #force_inline proc "contextless" (cls: Class) -> Class { + return (^Class)(cls)^ +} + +@(require_results) +object_get_vtable_info :: proc "contextless" (obj: id) -> ^Class_VTable_Info { + return (^Class_VTable_Info)(object_getIndexedIvars(obj)) +} + +@(require_results) +make_subclasser :: #force_inline proc(vtable: ^$T, impl: proc(cls: Class, vt: ^T)) -> Object_VTable_Info { + return Object_VTable_Info{ + vtable = vtable, + size = size_of(T), + impl = (Subclasser_Proc)(impl), + } +} + +@(require_results) +register_subclass :: proc( + class_name: cstring, + superclass: Class, + superclass_overrides: Maybe(Object_VTable_Info) = nil, + protocol: Maybe(Object_VTable_Info) = nil, + _context: Maybe(runtime.Context) = nil, +) -> Class { + assert(superclass != nil) + + super_size: uint + proto_size: uint + + if superclass_overrides != nil { + // Align to 8-byte boundary + super_size = (superclass_overrides.?.size + 7)/8 * 8 + } + + if protocol != nil { + // Align to 8-byte boundary + proto_size = (protocol.?.size + 7)/8 * 8 + } + + cls := objc_lookUpClass(class_name) + if cls != nil { + return cls + } + + extra_size := uint(size_of(Class_VTable_Info)) + 8 + super_size + proto_size + + cls = objc_allocateClassPair(superclass, class_name, extra_size) + assert(cls != nil) + + if s, ok := superclass_overrides.?; ok { + s.impl(cls, s.vtable) + } + + if p, ok := protocol.?; ok { + p.impl(cls, p.vtable) + } + + objc_registerClassPair(cls) + meta_cls := class_get_metaclass(cls) + meta_size := uint(class_getInstanceSize(meta_cls)) + + // Offsets are always aligned to 8-byte boundary + info_offset := (meta_size + 7) / 8 * 8 + super_vtable_offset := (info_offset + size_of(Class_VTable_Info) + 7) / 8 * 8 + ptoto_vtable_offset := super_vtable_offset + super_size + + + p_info := (^Class_VTable_Info)(([^]u8)(cls)[info_offset:]) + p_super_vtable := ([^]u8)(cls)[super_vtable_offset:] + p_proto_vtable := ([^]u8)(cls)[ptoto_vtable_offset:] + + intrinsics.mem_zero(p_info, size_of(Class_VTable_Info)) + + // Assign the context + p_info._context = _context.? or_else context + + if s, ok := superclass_overrides.?; ok { + p_info.super_vtable = p_super_vtable + intrinsics.mem_copy(p_super_vtable, s.vtable, super_size) + } + if p, ok := protocol.?; ok { + p_info.protocol_vtable = p_proto_vtable + intrinsics.mem_copy(p_proto_vtable, p.vtable, p.size) + } + + return cls +} + +@(require_results) +class_get_vtable_info :: proc "contextless" (cls: Class) -> ^Class_VTable_Info { + meta_cls := class_get_metaclass(cls) + meta_size := uint(class_getInstanceSize(meta_cls)) + + // Align to 8-byte boundary + info_offset := (meta_size+7) / 8 * 8 + + p_cls := ([^]u8)(cls)[info_offset:] + ctx := (^Class_VTable_Info)(p_cls) + return ctx +} + +@(require_results) +alloc_user_object :: proc "contextless" (cls: Class, _context: Maybe(runtime.Context) = nil) -> id { + info := class_get_vtable_info(cls) + + obj := class_createInstance(cls, size_of(Class_VTable_Info)) + obj_info := (^Class_VTable_Info)(object_getIndexedIvars(obj)) + obj_info^ = info^ + + if _context != nil { + obj_info._context = _context.? + } + return obj +} \ No newline at end of file diff --git a/core/sys/darwin/copyfile.odin b/core/sys/darwin/copyfile.odin new file mode 100644 index 000000000..6c58b8067 --- /dev/null +++ b/core/sys/darwin/copyfile.odin @@ -0,0 +1,67 @@ +package darwin + +import "core:sys/posix" + +copyfile_state_t :: distinct rawptr + +copyfile_flags :: bit_set[enum { + ACL, + STAT, + XATTR, + DATA, + + RECURSIVE = 15, + + CHECK, + EXCL, + NOFOLLOW_SRC, + NOFOLLOW_DST, + MOVE, + UNLINK, + PACK, + UNPACK, + + CLONE, + CLONE_FORCE, + RUN_IN_PLACE, + DATA_SPARSE, + PRESERVE_DST_TRACKED, + VERBOSE = 30, +}; u32] + +COPYFILE_SECURITY :: copyfile_flags{.STAT, .ACL} +COPYFILE_METADATA :: COPYFILE_SECURITY + copyfile_flags{.XATTR} +COPYFILE_ALL :: COPYFILE_METADATA + copyfile_flags{.DATA} + +COPYFILE_NOFOLLOW :: copyfile_flags{.NOFOLLOW_SRC, .NOFOLLOW_DST} + +copyfile_state_flag :: enum u32 { + SRC_FD = 1, + SRC_FILENAME, + DST_FD, + DST_FILENAME, + QUARANTINE, + STATUS_CB, + STATUS_CTX, + COPIED, + XATTRNAME, + WAS_CLONED, + SRC_BSIZE, + DST_BSIZE, + BSIZE, + FORBID_CROSS_MOUNT, + NOCPROTECT, + PRESERVE_SUID, + RECURSIVE_SRC_FTSENT, + FORBID_DST_EXISTING_SYMLINKS, +} + +foreign system { + copyfile :: proc(from, to: cstring, state: copyfile_state_t, flags: copyfile_flags) -> i32 --- + fcopyfile :: proc(from, to: posix.FD, state: copyfile_state_t, flags: copyfile_flags) -> i32 --- + + copyfile_state_alloc :: proc() -> copyfile_state_t --- + copyfile_state_free :: proc(state: copyfile_state_t) -> posix.result --- + copyfile_state_get :: proc(state: copyfile_state_t, flag: copyfile_state_flag, dst: rawptr) -> posix.result --- + copyfile_state_set :: proc(state: copyfile_state_t, flag: copyfile_state_flag, src: rawptr) -> posix.result --- +} diff --git a/core/sys/darwin/darwin.odin b/core/sys/darwin/darwin.odin index d109f5544..52297505a 100644 --- a/core/sys/darwin/darwin.odin +++ b/core/sys/darwin/darwin.odin @@ -3,7 +3,8 @@ package darwin import "core:c" -foreign import system "system:System.framework" +@(export) +foreign import system "system:System" Bool :: b8 diff --git a/core/sys/darwin/mach_darwin.odin b/core/sys/darwin/mach_darwin.odin index 2cc823e69..19515fe87 100644 --- a/core/sys/darwin/mach_darwin.odin +++ b/core/sys/darwin/mach_darwin.odin @@ -1,19 +1,38 @@ package darwin -foreign import mach "system:System.framework" +foreign import mach "system:System" import "core:c" import "base:intrinsics" -kern_return_t :: distinct c.int - mach_port_t :: distinct c.uint +task_t :: mach_port_t + +semaphore_t :: distinct u64 + +kern_return_t :: distinct c.int +thread_act_t :: distinct u64 +thread_state_t :: distinct ^u32 +thread_list_t :: [^]thread_act_t +vm_region_recurse_info_t :: distinct ^i32 +task_info_t :: distinct ^i32 + +MACH_PORT_NULL :: 0 +MACH_PORT_DEAD :: ~mach_port_t(0) + +MACH_MSG_PORT_DESCRIPTOR :: 0 + +X86_THREAD_STATE32 :: 1 +X86_THREAD_STATE64 :: 4 +ARM_THREAD_STATE64 :: 6 + +mach_msg_option_t :: distinct i32 +name_t :: distinct cstring + vm_map_t :: mach_port_t mem_entry_name_port_t :: mach_port_t ipc_space_t :: mach_port_t thread_t :: mach_port_t -task_t :: mach_port_t -semaphore_t :: mach_port_t vm_size_t :: distinct c.uintptr_t @@ -29,11 +48,279 @@ vm_inherit_t :: distinct c.uint mach_port_name_t :: distinct c.uint +mach_port_right_t :: distinct c.uint + sync_policy_t :: distinct c.int +mach_msg_port_descriptor_t :: struct { + name: mach_port_t, + _: u32, + using _: bit_field u32 { + _: u32 | 16, + disposition: u32 | 8, + type: u32 | 8, + }, +} + +Task_Port_Type :: enum u32 { + Kernel = 1, + Host, + Name, + Bootstrap, + Seatbelt = 7, + Access = 9, +} + +Bootstrap_Error :: enum u32 { + Success, + Not_Privileged = 1100, + Name_In_Use = 1101, + Unknown_Service = 1102, + Service_Active = 1103, + Bad_Count = 1104, + No_Memory = 1105, + No_Children = 1106, +} + +Msg_Type :: enum u32 { + Unstructured = 0, + Bit = 0, + Boolean = 0, + Integer_16 = 1, + Integer_32 = 2, + Char = 8, + Byte = 9, + Integer_8 = 9, + Real = 10, + Integer_64 = 11, + String = 12, + String_C = 12, + + Port_Name = 15, + + Move_Receive = 16, + Port_Receive = 16, + Move_Send = 17, + Port_Send = 17, + Move_Send_Once = 18, + Port_Send_Once = 18, + Copy_Send = 19, + Make_Send = 20, + Make_Send_Once = 21, +} + +Msg_Header_Bits :: enum u32 { + Zero = 0, + Remote_Mask = 0xff, + Local_Mask = 0xff00, + Migrated = 0x08000000, + Unused = 0x07ff0000, + Complex_Data = 0x10000000, + Complex_Ports = 0x20000000, + Circular = 0x40000000, + Complex = 0x80000000, +} + +mach_msg_type_t :: struct { + using _: bit_field u32 { + name: u32 | 8, + size: u32 | 8, + number: u32 | 12, + inline: u32 | 1, + longform: u32 | 1, + deallocate: u32 | 1, + unused: u32 | 1, + }, +} + +mach_msg_header_t :: struct { + msgh_bits: u32, + msgh_size: u32, + msgh_remote_port: mach_port_t, + msgh_local_port: mach_port_t, + msgh_voucher_port: u32, + msgh_id: i32, +} + +mach_msg_body_t :: struct { + msgh_descriptor_count: u32, +} + +mach_msg_trailer_t :: struct { + msgh_trailer_type: u32, + msgh_trailer_size: u32, +} + +x86_thread_state32_t :: struct { + eax: u32, + ebx: u32, + ecx: u32, + edx: u32, + edi: u32, + esi: u32, + ebp: u32, + esp: u32, + ss: u32, + eflags: u32, + eip: u32, + cs: u32, + ds: u32, + es: u32, + fs: u32, + gs: u32, +} +X86_THREAD_STATE32_COUNT :: size_of(x86_thread_state32_t) / size_of(u32) + +x86_thread_state64_t :: struct #packed { + rax: u64, + rbx: u64, + rcx: u64, + rdx: u64, + rdi: u64, + rsi: u64, + rbp: u64, + rsp: u64, + r8: u64, + r9: u64, + r10: u64, + r11: u64, + r12: u64, + r13: u64, + r14: u64, + r15: u64, + rip: u64, + rflags: u64, + cs: u64, + fs: u64, + gs: u64, +} +X86_THREAD_STATE64_COUNT :: size_of(x86_thread_state64_t) / size_of(u32) + +arm_thread_state64_t :: struct #packed { + x: [29]u64, + fp: u64, + lr: u64, + sp: u64, + pc: u64, + cpsr: u32, + pad: u32, +} +ARM_THREAD_STATE64_COUNT :: size_of(arm_thread_state64_t) / size_of(u32) + +THREAD_IDENTIFIER_INFO :: 4 +thread_identifier_info :: struct { + thread_id: u64, + thread_handler: u64, + dispatch_qaddr: u64, +} +THREAD_IDENTIFIER_INFO_COUNT :: size_of(thread_identifier_info) / size_of(u32) + +vm_region_submap_info_64 :: struct { + protection: u32, + max_protection: u32, + inheritance: u32, + offset: u64, + user_tag: u32, + pages_residept: u32, + pages_shared_now_private: u32, + pages_swapped_out: u32, + pages_dirtied: u32, + ref_count: u32, + shadow_depth: u16, + external_pager: u8, + share_mode: u8, + is_submap: b32, + behavior: i32, + object_id: u32, + user_wired_count: u16, + pages_reusable: u32, +} +VM_REGION_SUBMAP_INFO_COUNT_64 :: size_of(vm_region_submap_info_64) / size_of(u32) + +TASK_DYLD_INFO :: 17 +task_dyld_info :: struct { + all_image_info_addr: u64, + all_image_info_size: u64, + all_image_info_format: i32, +} +TASK_DYLD_INFO_COUNT :: size_of(task_dyld_info) / size_of(u32) + +dyld_image_info :: struct { + image_load_addr: u64, + image_file_path: cstring, + image_file_mod_date: u64, +} + +dyld_uuid_info :: struct { + image_load_addr: u64, + image_uuid: [16]u8, +} + +dyld_all_image_infos :: struct { + version: u32, + info_array_count: u32, + info_array: rawptr, + notification: rawptr, + process_detached_from_shared_region: b32, + libSystem_initialized: b32, + dyld_image_load_addr: u64, + jit_info: rawptr, + dyld_version: cstring, + error_message: cstring, + termination_flags: u64, + core_symbolication_shm_page: rawptr, + system_order_flag: u64, + uuid_array_count: u64, + uuid_array: rawptr, + dyld_all_image_infos_addr: u64, + initial_image_count: u64, + error_kind: u64, + error_client_of_dylib_path: cstring, + error_target_dylib_path: cstring, + error_symbol: cstring, + shared_cache_slide: u64, + shared_cache_uuid: [16]u8, + shared_cache_base_addr: u64, + info_array_change_timestamp: u64, + dyld_path: cstring, + notify_ports: [8]mach_port_t, + reserved: [7]u64, + shared_cache_fsid: u64, + shared_cache_fsobjid: u64, + compact_dyld_image_info_addr: u64, + compact_dyld_image_info_size: u64, + platform: u32, + aot_info_count: u32, + aot_info_array: rawptr, + aot_info_array_change_timestamp: u64, + aot_shared_cache_base_address: u64, + aot_shared_cache_uuid: [16]u8, +} + + @(default_calling_convention="c") foreign mach { - mach_task_self :: proc() -> mach_port_t --- + mach_task_self :: proc() -> mach_port_t --- + mach_msg :: proc(header: rawptr, option: Msg_Option_Flags, send_size: u32, receive_limit: u32, receive_name: mach_port_t, timeout: u32, notify: mach_port_t) -> Kern_Return --- + mach_msg_send :: proc(header: rawptr) -> Kern_Return --- + mach_vm_allocate :: proc(target_task: task_t, adddress: u64, size: u64, flags: i32) -> Kern_Return --- + mach_vm_deallocate :: proc(target_task: task_t, adddress: ^u64, size: u64) -> Kern_Return --- + mach_vm_remap :: proc(target_task: task_t, page: rawptr, size: u64, mask: u64, flags: i32, src_task: task_t, src_address: u64, copy: b32, cur_protection: ^i32, max_protection: ^i32, inheritance: VM_Inherit) -> Kern_Return --- + mach_vm_region_recurse :: proc(target_task: task_t, address: ^u64, size: ^u64, depth: ^u32, info: vm_region_recurse_info_t, count: ^u32) -> Kern_Return --- + vm_page_size: u64 + vm_page_mask: u64 + vm_page_shift: i32 + + mach_port_allocate :: proc(task: task_t, right: Port_Right, name: rawptr) -> Kern_Return --- + mach_port_deallocate :: proc(task: task_t, name: u32) -> Kern_Return --- + mach_port_extract_right :: proc(task: task_t, name: u32, msgt_name: u32, poly: ^mach_port_t, poly_poly: ^mach_port_t) -> Kern_Return --- + + task_get_special_port :: proc(task: task_t, port: i32, special_port: ^mach_port_t) -> Kern_Return --- + task_suspend :: proc(task: task_t) -> Kern_Return --- + task_resume :: proc(task: task_t) -> Kern_Return --- + task_threads :: proc(task: task_t, thread_list: ^thread_list_t, list_count: ^u32) -> Kern_Return --- + task_info :: proc(task: task_t, flavor: i32, info: task_info_t, count: ^u32) -> Kern_Return --- + task_terminate :: proc(task: task_t) -> Kern_Return --- semaphore_create :: proc(task: task_t, semaphore: ^semaphore_t, policy: Sync_Policy, value: c.int) -> Kern_Return --- semaphore_destroy :: proc(task: task_t, semaphore: semaphore_t) -> Kern_Return --- @@ -44,9 +331,11 @@ foreign mach { semaphore_wait :: proc(semaphore: semaphore_t) -> Kern_Return --- - vm_allocate :: proc (target_task : vm_map_t, address: ^vm_address_t, size: vm_size_t, flags: VM_Flags) -> Kern_Return --- + thread_get_state :: proc(thread: thread_act_t, flavor: i32, thread_state: thread_state_t, old_state_count: ^u32) -> Kern_Return --- + thread_info :: proc(thread: thread_act_t, flavor: u32, thread_info: ^thread_identifier_info, info_count: ^u32) -> Kern_Return --- - vm_deallocate :: proc(target_task: vm_map_t, address: vm_address_t, size: vm_size_t) -> Kern_Return --- + bootstrap_register2 :: proc(bp: mach_port_t, service_name: name_t, sp: mach_port_t, flags: u64) -> Kern_Return --- + bootstrap_look_up :: proc(bp: mach_port_t, service_name: name_t, sp: ^mach_port_t) -> Kern_Return --- vm_map :: proc( target_task: vm_map_t, @@ -70,15 +359,10 @@ foreign mach { object_handle: ^mem_entry_name_port_t, parent_entry: mem_entry_name_port_t, ) -> Kern_Return --- - - mach_port_deallocate :: proc( - task: ipc_space_t, - name: mach_port_name_t, - ) -> Kern_Return --- - - vm_page_size: vm_size_t } + + Kern_Return :: enum kern_return_t { Success, @@ -500,6 +784,39 @@ VM_PROT_NONE :: VM_Prot_Flags{} VM_PROT_DEFAULT :: VM_Prot_Flags{.Read, .Write} VM_PROT_ALL :: VM_Prot_Flags{.Read, .Write, .Execute} +/* + * Mach msg options, defined as bits within the mach_msg_option_t type + */ + +Msg_Option :: enum mach_msg_option_t { + Send_Msg, + Receive_Msg, + + Send_Timeout = LOG2(0x10), + Send_Notify = LOG2(0x20), + Send_Interrupt = LOG2(0x40), + Send_Cancel = LOG2(0x80), + Receive_Timeout = LOG2(0x100), + Receive_Notify = LOG2(0x200), + Receive_Interrupt = LOG2(0x400), + Receive_Large = LOG2(0x800), + Send_Always = LOG2(0x10000), +} + +Msg_Option_Flags :: distinct bit_set[Msg_Option; mach_msg_option_t] + +/* + * Enumeration of valid values for mach_port_right_t + */ + +Port_Right :: enum mach_port_right_t { + Send, + Receive, + Send_Once, + Port_Set, + Dead_Name, +} + /* * Enumeration of valid values for vm_inherit_t. */ @@ -522,3 +839,7 @@ Sync_Policy :: enum sync_policy_t { Lifo = Fifo | Reversed, } + +mach_vm_trunc_page :: proc(v: u64) -> u64 { + return v & ~vm_page_mask +} diff --git a/core/sys/darwin/proc.odin b/core/sys/darwin/proc.odin index fa5391f6f..ccd05f478 100644 --- a/core/sys/darwin/proc.odin +++ b/core/sys/darwin/proc.odin @@ -4,7 +4,7 @@ import "base:intrinsics" import "core:sys/posix" -foreign import lib "system:System.framework" +foreign import lib "system:System" // Incomplete bindings to the proc API on MacOS, add to when needed. diff --git a/core/sys/darwin/sync.odin b/core/sys/darwin/sync.odin index 58fc7c9e4..5f4f16fc3 100644 --- a/core/sys/darwin/sync.odin +++ b/core/sys/darwin/sync.odin @@ -1,27 +1,15 @@ package darwin -foreign import system "system:System.framework" - // #define OS_WAIT_ON_ADDR_AVAILABILITY \ // __API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4)) when ODIN_OS == .Darwin { - - when ODIN_PLATFORM_SUBTARGET == .iOS && ODIN_MINIMUM_OS_VERSION >= 17_04_00 { - WAIT_ON_ADDRESS_AVAILABLE :: true - } else when ODIN_MINIMUM_OS_VERSION >= 14_04_00 { - WAIT_ON_ADDRESS_AVAILABLE :: true + when ODIN_PLATFORM_SUBTARGET_IOS { + WAIT_ON_ADDRESS_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 17_04_00 + ULOCK_WAIT_2_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 14_00_00 } else { - WAIT_ON_ADDRESS_AVAILABLE :: false + WAIT_ON_ADDRESS_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 14_04_00 + ULOCK_WAIT_2_AVAILABLE :: ODIN_MINIMUM_OS_VERSION >= 11_00_00 } - - when ODIN_PLATFORM_SUBTARGET == .iOS && ODIN_MINIMUM_OS_VERSION >= 14_00_00 { - ULOCK_WAIT_2_AVAILABLE :: true - } else when ODIN_MINIMUM_OS_VERSION >= 11_00_00 { - ULOCK_WAIT_2_AVAILABLE :: true - } else { - ULOCK_WAIT_2_AVAILABLE :: false - } - } else { WAIT_ON_ADDRESS_AVAILABLE :: false ULOCK_WAIT_2_AVAILABLE :: false diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index 1188091a9..43bcb543b 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -19,16 +19,6 @@ X_OK :: c.int((1 << 0)) /* test for execute or search permission */ W_OK :: c.int((1 << 1)) /* test for write permission */ R_OK :: c.int((1 << 2)) /* test for read permission */ -/* copyfile flags */ -COPYFILE_ACL :: (1 << 0) -COPYFILE_STAT :: (1 << 1) -COPYFILE_XATTR :: (1 << 2) -COPYFILE_DATA :: (1 << 3) - -COPYFILE_SECURITY :: (COPYFILE_STAT | COPYFILE_ACL) -COPYFILE_METADATA :: (COPYFILE_SECURITY | COPYFILE_XATTR) -COPYFILE_ALL :: (COPYFILE_METADATA | COPYFILE_DATA) - /* syslimits.h */ PATH_MAX :: 1024 /* max bytes in pathname */ @@ -233,6 +223,11 @@ _Proc_Bsdinfo :: struct { /*--==========================================================================--*/ +/* Get window size */ +TIOCGWINSZ :: 0x40087468 + +/*--==========================================================================--*/ + syscall_fsync :: #force_inline proc "contextless" (fildes: c.int) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.fsync), uintptr(fildes))) } @@ -285,6 +280,10 @@ syscall_lseek :: #force_inline proc "contextless" (fd: c.int, offset: i64, whenc return cast(i64)intrinsics.syscall(unix_offset_syscall(.lseek), uintptr(fd), uintptr(offset), uintptr(whence)) } +syscall_ioctl :: #force_inline proc "contextless" (fd: c.int, request: u32, arg: rawptr) -> c.int { + return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.ioctl), uintptr(fd), uintptr(request), uintptr(arg))) +} + syscall_gettid :: #force_inline proc "contextless" () -> u64 { return cast(u64)intrinsics.syscall(unix_offset_syscall(.gettid)) } diff --git a/core/sys/es/api.odin b/core/sys/es/api.odin index 4cf64b748..ae1a1a8bb 100644 --- a/core/sys/es/api.odin +++ b/core/sys/es/api.odin @@ -8,564 +8,564 @@ ElementPublic :: struct { instance : ^INSTANCE_TYPE, flags : u64 , } -Generic :: rawptr; -INSTANCE_TYPE :: Instance; -Element :: ElementPublic; -Panel :: Element; -Window :: Element; -Scrollbar :: Element; -Button :: Element; -TextDisplay :: Element; -IconDisplay :: Element; -Textbox :: Element; -ListView :: Element; -Menu :: Element; -Choice :: Element; -ColorWell :: Element; -Splitter :: Element; -ImageDisplay :: Element; -TextPlan :: rawptr; -Store :: rawptr; -PaintTarget :: rawptr; -DirectoryMonitor :: rawptr; -NodeType :: u8 ; -Error :: int ; -Handle :: uint ; -Response :: i32; -FileOffset :: u64 ; -FileOffsetDifference :: i64 ; -AudioDeviceID :: u64 ; -SCANCODE_A :: (0x04); -SCANCODE_B :: (0x05); -SCANCODE_C :: (0x06); -SCANCODE_D :: (0x07); -SCANCODE_E :: (0x08); -SCANCODE_F :: (0x09); -SCANCODE_G :: (0x0A); -SCANCODE_H :: (0x0B); -SCANCODE_I :: (0x0C); -SCANCODE_J :: (0x0D); -SCANCODE_K :: (0x0E); -SCANCODE_L :: (0x0F); -SCANCODE_M :: (0x10); -SCANCODE_N :: (0x11); -SCANCODE_O :: (0x12); -SCANCODE_P :: (0x13); -SCANCODE_Q :: (0x14); -SCANCODE_R :: (0x15); -SCANCODE_S :: (0x16); -SCANCODE_T :: (0x17); -SCANCODE_U :: (0x18); -SCANCODE_V :: (0x19); -SCANCODE_W :: (0x1A); -SCANCODE_X :: (0x1B); -SCANCODE_Y :: (0x1C); -SCANCODE_Z :: (0x1D); -SCANCODE_1 :: (0x1E); -SCANCODE_2 :: (0x1F); -SCANCODE_3 :: (0x20); -SCANCODE_4 :: (0x21); -SCANCODE_5 :: (0x22); -SCANCODE_6 :: (0x23); -SCANCODE_7 :: (0x24); -SCANCODE_8 :: (0x25); -SCANCODE_9 :: (0x26); -SCANCODE_0 :: (0x27); -SCANCODE_ENTER :: (0x28); -SCANCODE_ESCAPE :: (0x29); -SCANCODE_BACKSPACE :: (0x2A); -SCANCODE_TAB :: (0x2B); -SCANCODE_SPACE :: (0x2C); -SCANCODE_HYPHEN :: (0x2D); -SCANCODE_EQUALS :: (0x2E); -SCANCODE_LEFT_BRACE :: (0x2F); -SCANCODE_RIGHT_BRACE :: (0x30); -SCANCODE_COMMA :: (0x36); -SCANCODE_PERIOD :: (0x37); -SCANCODE_SLASH :: (0x38); -SCANCODE_PUNCTUATION_1 :: (0x31) ; -SCANCODE_PUNCTUATION_2 :: (0x32) ; -SCANCODE_PUNCTUATION_3 :: (0x33) ; -SCANCODE_PUNCTUATION_4 :: (0x34) ; -SCANCODE_PUNCTUATION_5 :: (0x35) ; -SCANCODE_PUNCTUATION_6 :: (0x64) ; -SCANCODE_F1 :: (0x3A); -SCANCODE_F2 :: (0x3B); -SCANCODE_F3 :: (0x3C); -SCANCODE_F4 :: (0x3D); -SCANCODE_F5 :: (0x3E); -SCANCODE_F6 :: (0x3F); -SCANCODE_F7 :: (0x40); -SCANCODE_F8 :: (0x41); -SCANCODE_F9 :: (0x42); -SCANCODE_F10 :: (0x43); -SCANCODE_F11 :: (0x44); -SCANCODE_F12 :: (0x45); -SCANCODE_F13 :: (0x68); -SCANCODE_F14 :: (0x69); -SCANCODE_F15 :: (0x6A); -SCANCODE_F16 :: (0x6B); -SCANCODE_F17 :: (0x6C); -SCANCODE_F18 :: (0x6D); -SCANCODE_F19 :: (0x6E); -SCANCODE_F20 :: (0x6F); -SCANCODE_F21 :: (0x70); -SCANCODE_F22 :: (0x71); -SCANCODE_F23 :: (0x72); -SCANCODE_F24 :: (0x73); -SCANCODE_CAPS_LOCK :: (0x39); -SCANCODE_PRINT_SCREEN :: (0x46); -SCANCODE_SCROLL_LOCK :: (0x47); -SCANCODE_PAUSE :: (0x48); -SCANCODE_INSERT :: (0x49); -SCANCODE_HOME :: (0x4A); -SCANCODE_PAGE_UP :: (0x4B); -SCANCODE_DELETE :: (0x4C); -SCANCODE_END :: (0x4D); -SCANCODE_PAGE_DOWN :: (0x4E); -SCANCODE_RIGHT_ARROW :: (0x4F); -SCANCODE_LEFT_ARROW :: (0x50); -SCANCODE_DOWN_ARROW :: (0x51); -SCANCODE_UP_ARROW :: (0x52); -SCANCODE_NUM_LOCK :: (0x53); -SCANCODE_CONTEXT_MENU :: (0x65); -SCANCODE_SYSTEM_REQUEST :: (0x9A); -SCANCODE_ACTION_EXECUTE :: (0x74); -SCANCODE_ACTION_HELP :: (0x75); -SCANCODE_ACTION_MENU :: (0x76); -SCANCODE_ACTION_SELECT :: (0x77); -SCANCODE_ACTION_STOP :: (0x78); -SCANCODE_ACTION_AGAIN :: (0x79); -SCANCODE_ACTION_UNDO :: (0x7A); -SCANCODE_ACTION_CUT :: (0x7B); -SCANCODE_ACTION_COPY :: (0x7C); -SCANCODE_ACTION_PASTE :: (0x7D); -SCANCODE_ACTION_FIND :: (0x7E); -SCANCODE_ACTION_CANCEL :: (0x9B); -SCANCODE_ACTION_CLEAR :: (0x9C); -SCANCODE_ACTION_PRIOR :: (0x9D); -SCANCODE_ACTION_RETURN :: (0x9E); -SCANCODE_ACTION_SEPARATOR :: (0x9F); -SCANCODE_MM_MUTE :: (0x7F); -SCANCODE_MM_LOUDER :: (0x80); -SCANCODE_MM_QUIETER :: (0x81); -SCANCODE_MM_NEXT :: (0x103); -SCANCODE_MM_PREVIOUS :: (0x104); -SCANCODE_MM_STOP :: (0x105); -SCANCODE_MM_PAUSE :: (0x106); -SCANCODE_MM_SELECT :: (0x107); -SCANCODE_MM_EMAIL :: (0x108); -SCANCODE_MM_CALC :: (0x109); -SCANCODE_MM_FILES :: (0x10A); -SCANCODE_INTERNATIONAL_1 :: (0x87); -SCANCODE_INTERNATIONAL_2 :: (0x88); -SCANCODE_INTERNATIONAL_3 :: (0x89); -SCANCODE_INTERNATIONAL_4 :: (0x8A); -SCANCODE_INTERNATIONAL_5 :: (0x8B); -SCANCODE_INTERNATIONAL_6 :: (0x8C); -SCANCODE_INTERNATIONAL_7 :: (0x8D); -SCANCODE_INTERNATIONAL_8 :: (0x8E); -SCANCODE_INTERNATIONAL_9 :: (0x8F); -SCANCODE_HANGUL_ENGLISH_TOGGLE :: (0x90); -SCANCODE_HANJA_CONVERSION :: (0x91); -SCANCODE_KATAKANA :: (0x92); -SCANCODE_HIRAGANA :: (0x93); -SCANCODE_HANKAKU_ZENKAKU_TOGGLE :: (0x94); -SCANCODE_ALTERNATE_ERASE :: (0x99); -SCANCODE_THOUSANDS_SEPARATOR :: (0xB2); -SCANCODE_DECIMAL_SEPARATOR :: (0xB3); -SCANCODE_CURRENCY_UNIT :: (0xB4); -SCANCODE_CURRENCY_SUBUNIT :: (0xB5); -SCANCODE_NUM_DIVIDE :: (0x54); -SCANCODE_NUM_MULTIPLY :: (0x55); -SCANCODE_NUM_SUBTRACT :: (0x56); -SCANCODE_NUM_ADD :: (0x57); -SCANCODE_NUM_ENTER :: (0x58); -SCANCODE_NUM_1 :: (0x59); -SCANCODE_NUM_2 :: (0x5A); -SCANCODE_NUM_3 :: (0x5B); -SCANCODE_NUM_4 :: (0x5C); -SCANCODE_NUM_5 :: (0x5D); -SCANCODE_NUM_6 :: (0x5E); -SCANCODE_NUM_7 :: (0x5F); -SCANCODE_NUM_8 :: (0x60); -SCANCODE_NUM_9 :: (0x61); -SCANCODE_NUM_0 :: (0x62); -SCANCODE_NUM_POINT :: (0x63); -SCANCODE_NUM_EQUALS :: (0x67); -SCANCODE_NUM_COMMA :: (0x82); -SCANCODE_NUM_00 :: (0xB0); -SCANCODE_NUM_000 :: (0xB1); -SCANCODE_NUM_LEFT_PAREN :: (0xB6); -SCANCODE_NUM_RIGHT_PAREN :: (0xB7); -SCANCODE_NUM_LEFT_BRACE :: (0xB8); -SCANCODE_NUM_RIGHT_BRACE :: (0xB9); -SCANCODE_NUM_TAB :: (0xBA); -SCANCODE_NUM_BACKSPACE :: (0xBB); -SCANCODE_NUM_A :: (0xBC); -SCANCODE_NUM_B :: (0xBD); -SCANCODE_NUM_C :: (0xBE); -SCANCODE_NUM_D :: (0xBF); -SCANCODE_NUM_E :: (0xC0); -SCANCODE_NUM_F :: (0xC1); -SCANCODE_NUM_XOR :: (0xC2); -SCANCODE_NUM_CARET :: (0xC3); -SCANCODE_NUM_PERCENT :: (0xC4); -SCANCODE_NUM_LESS_THAN :: (0xC5); -SCANCODE_NUM_GREATER_THAN :: (0xC6); -SCANCODE_NUM_AMPERSAND :: (0xC7); -SCANCODE_NUM_DOUBLE_AMPERSAND :: (0xC8); -SCANCODE_NUM_BAR :: (0xC9); -SCANCODE_NUM_DOUBLE_BAR :: (0xCA); -SCANCODE_NUM_COLON :: (0xCB); -SCANCODE_NUM_HASH :: (0xCC); -SCANCODE_NUM_SPACE :: (0xCD); -SCANCODE_NUM_AT :: (0xCE); -SCANCODE_NUM_EXCLAMATION_MARK :: (0xCF); -SCANCODE_NUM_MEMORY_STORE :: (0xD0); -SCANCODE_NUM_MEMORY_RECALL :: (0xD1); -SCANCODE_NUM_MEMORY_CLEAR :: (0xD2); -SCANCODE_NUM_MEMORY_ADD :: (0xD3); -SCANCODE_NUM_MEMORY_SUBTRACT :: (0xD4); -SCANCODE_NUM_MEMORY_MULTIPLY :: (0xD5); -SCANCODE_NUM_MEMORY_DIVIDE :: (0xD6); -SCANCODE_NUM_NEGATE :: (0xD7); -SCANCODE_NUM_CLEAR_ALL :: (0xD8); -SCANCODE_NUM_CLEAR :: (0xD9); -SCANCODE_NUM_BINARY :: (0xDA); -SCANCODE_NUM_OCTAL :: (0xDB); -SCANCODE_NUM_DECIMAL :: (0xDC); -SCANCODE_NUM_HEXADECIMAL :: (0xDD); -SCANCODE_LEFT_CTRL :: (0xE0); -SCANCODE_LEFT_SHIFT :: (0xE1); -SCANCODE_LEFT_ALT :: (0xE2); -SCANCODE_LEFT_FLAG :: (0xE3); -SCANCODE_RIGHT_CTRL :: (0xE4); -SCANCODE_RIGHT_SHIFT :: (0xE5); -SCANCODE_RIGHT_ALT :: (0xE6); -SCANCODE_RIGHT_FLAG :: (0xE7); -SCANCODE_ACPI_POWER :: (0x100); -SCANCODE_ACPI_SLEEP :: (0x101); -SCANCODE_ACPI_WAKE :: (0x102); -SCANCODE_WWW_SEARCH :: (0x10B); -SCANCODE_WWW_HOME :: (0x10C); -SCANCODE_WWW_BACK :: (0x10D); -SCANCODE_WWW_FORWARD :: (0x10E); -SCANCODE_WWW_STOP :: (0x10F); -SCANCODE_WWW_REFRESH :: (0x110); -SCANCODE_WWW_STARRED :: (0x111); -PROCESS_STATE_ALL_THREADS_TERMINATED :: (1); -PROCESS_STATE_TERMINATING :: (2); -PROCESS_STATE_CRASHED :: (4); -PROCESS_STATE_PINGED :: (8); -FLAGS_DEFAULT :: (0); -SUCCESS :: (-1); -ERROR_BUFFER_TOO_SMALL :: (-2); -ERROR_UNKNOWN :: (-7); -ERROR_NO_MESSAGES_AVAILABLE :: (-9); -ERROR_MESSAGE_QUEUE_FULL :: (-10); -ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: (-14); -ERROR_PATH_NOT_TRAVERSABLE :: (-15); -ERROR_FILE_ALREADY_EXISTS :: (-19); -ERROR_FILE_DOES_NOT_EXIST :: (-20); -ERROR_DRIVE_ERROR_FILE_DAMAGED :: (-21) ; -ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: (-22) ; -ERROR_FILE_PERMISSION_NOT_GRANTED :: (-23); -ERROR_FILE_IN_EXCLUSIVE_USE :: (-24); -ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: (-25); -ERROR_INCORRECT_NODE_TYPE :: (-26); -ERROR_EVENT_NOT_SET :: (-27); -ERROR_FILE_HAS_WRITERS :: (-28); -ERROR_TIMEOUT_REACHED :: (-29); -ERROR_FILE_ON_READ_ONLY_VOLUME :: (-32); -ERROR_INVALID_DIMENSIONS :: (-34); -ERROR_DRIVE_CONTROLLER_REPORTED :: (-35); -ERROR_COULD_NOT_ISSUE_PACKET :: (-36); -ERROR_HANDLE_TABLE_FULL :: (-37); -ERROR_COULD_NOT_RESIZE_FILE :: (-38); -ERROR_DIRECTORY_NOT_EMPTY :: (-39); -ERROR_NODE_DELETED :: (-41); -ERROR_VOLUME_MISMATCH :: (-43); -ERROR_TARGET_WITHIN_SOURCE :: (-44); -ERROR_TARGET_INVALID_TYPE :: (-45); -ERROR_MALFORMED_NODE_PATH :: (-47); -ERROR_OUT_OF_CACHE_RESOURCES :: (-48); -ERROR_TARGET_IS_SOURCE :: (-49); -ERROR_INVALID_NAME :: (-50); -ERROR_CORRUPT_DATA :: (-51); -ERROR_INSUFFICIENT_RESOURCES :: (-52); -ERROR_UNSUPPORTED_FEATURE :: (-53); -ERROR_FILE_TOO_FRAGMENTED :: (-54); -ERROR_DRIVE_FULL :: (-55); -ERROR_COULD_NOT_RESOLVE_SYMBOL :: (-56); -ERROR_ALREADY_EMBEDDED :: (-57); -ERROR_EVENT_SINK_OVERFLOW :: (-58); -ERROR_EVENT_SINK_DUPLICATE :: (-59); -ERROR_UNSUPPORTED_CONVERSION :: (-60); -ERROR_SOURCE_EMPTY :: (-61); -ERROR_UNSUPPORTED_EXECUTABLE :: (-62); -ERROR_NO_ADDRESS_FOR_DOMAIN_NAME :: (-63); -ERROR_NO_CONNECTED_NETWORK_INTERFACES :: (-64); -ERROR_BAD_DOMAIN_NAME :: (-65); -ERROR_LOST_IP_ADDRESS :: (-66); -ERROR_CONNECTION_RESET :: (-67); -ERROR_CONNECTION_REFUSED :: (-68); -SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND :: (0); -SYSTEM_CONSTANT_NO_FANCY_GRAPHICS :: (1); -SYSTEM_CONSTANT_REPORTED_PROBLEMS :: (2); -SYSTEM_CONSTANT_RIGHT_TO_LEFT :: (3); -SYSTEM_CONSTANT_WINDOW_INSET :: (4); -SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT :: (5); -INVALID_HANDLE :: (( Handle) (0)); -CURRENT_THREAD :: (( Handle) (0x10)); -CURRENT_PROCESS :: (( Handle) (0x11)); -DRAW_ALPHA_OVERWRITE :: (0x100); -DRAW_ALPHA_FULL :: (0x200) ; -WAIT_NO_TIMEOUT :: (-1); -MAX_WAIT_COUNT :: (8); -MAX_EVENT_FORWARD_COUNT :: (4) ; -MAX_EVENT_SINK_BUFFER_SIZE :: (256) ; -MAX_DIRECTORY_CHILD_NAME_LENGTH :: (256); -PROCESS_EXECUTABLE_NOT_LOADED :: (0); -PROCESS_EXECUTABLE_FAILED_TO_LOAD :: (1); -PROCESS_EXECUTABLE_LOADED :: (2); -SNAPSHOT_MAX_PROCESS_NAME_LENGTH :: (80); -SYSTEM_SNAPSHOT_PROCESSES :: (1); -SYSTEM_SNAPSHOT_DRIVES :: (2); -HANDLED :: (0); -NOT_HANDLED :: (-1); -REJECTED :: (-2); -SHARED_MEMORY_NAME_MAX_LENGTH :: (32); -MAP_OBJECT_ALL :: (0); -TEXT_H_LEFT :: (1); -TEXT_H_RIGHT :: (2); -TEXT_H_CENTER :: (3); -TEXT_V_TOP :: (4); -TEXT_V_BOTTOM :: (8); -TEXT_V_CENTER :: (12); -TEXT_WRAP :: (16); -TEXT_ELLIPSIS :: (32); -NODE_ACCESS_READ_SHARED :: (0x1) ; -NODE_ACCESS_READ :: (0x2) ; -NODE_ACCESS_WRITE :: (0x4) ; -NODE_ACCESS_WRITE_EXCLUSIVE :: (0x8) ; -NODE_FILE :: (0); -NODE_DIRECTORY :: (0x10); -NODE_INVALID :: (0x20); -NODE_FAIL_IF_FOUND :: (0x1000); -NODE_FAIL_IF_NOT_FOUND :: (0x2000); -NODE_PREVENT_RESIZE :: (0x4000); -NODE_CREATE_DIRECTORIES :: (0x8000) ; -NODE_POSIX_NAMESPACE :: (0x10000) ; -_ES_NODE_FROM_WRITE_EXCLUSIVE :: (0x20000); -DIRECTORY_CHILDREN_UNKNOWN :: (( FileOffsetDifference) (-1)); -MEMORY_OPEN_FAIL_IF_FOUND :: (0x1000); -MEMORY_OPEN_FAIL_IF_NOT_FOUND :: (0x2000); -MAP_OBJECT_READ_WRITE :: (0); -MAP_OBJECT_READ_ONLY :: (1); -MAP_OBJECT_COPY_ON_WRITE :: (2); -STRING_FORMAT_ENOUGH_SPACE :: ( (-1)); -STRING_FORMAT_SIMPLE :: (1 << 0); -POSIX_SYSCALL_GET_POSIX_FD_PATH :: (0x10000); -PERMISSION_ACCESS_SYSTEM_FILES :: (1 << 0); -PERMISSION_ACCESS_USER_FILES :: (1 << 1); -PERMISSION_PROCESS_CREATE :: (1 << 2); -PERMISSION_PROCESS_OPEN :: (1 << 3); -PERMISSION_SCREEN_MODIFY :: (1 << 4) ; -PERMISSION_SHUTDOWN :: (1 << 5); -PERMISSION_TAKE_SYSTEM_SNAPSHOT :: (1 << 6); -PERMISSION_WINDOW_OPEN :: (1 << 7); -PERMISSION_ALL :: ( (-1)); -PERMISSION_INHERIT :: ( (1) << 63); -PANEL_STYLE_DEFAULT :: "Panel.Default"; -PANEL_STYLE_TRANSPARENT :: "Panel.Transparent"; -PANEL_STYLE_WINDOW_BACKGROUND :: "Panel.WindowBackground"; -PANEL_STYLE_WINDOW_DIVIDER :: "Panel.WindowDivider"; -PANEL_STYLE_SHEET :: "Panel.Sheet"; -PANEL_STYLE_GROUP_BOX :: "Panel.GroupBox"; -PANEL_STYLE_INDENT :: "Panel.Indent"; -PANEL_BAND_SIZE_DEFAULT :: (-1); -ELEMENT_FOCUSABLE :: ( (1) << 32); -ELEMENT_HIDDEN :: ( (1) << 33) ; -ELEMENT_DISABLED :: ( (1) << 34) ; -ELEMENT_DEBUG :: ( (1) << 35) ; -ELEMENT_SCROLL_X :: ( (1) << 36); -ELEMENT_SCROLL_Y :: ( (1) << 37); -ELEMENT_NO_HOVER :: ( (1) << 38) ; -ELEMENT_BLOCK_FOCUS :: ( (1) << 39) ; -ELEMENT_NOT_TAB_TRAVERSABLE :: ( (1) << 40) ; -ELEMENT_NO_INFORM_PARENT :: ( (1) << 41) ; -ELEMENT_CENTER_ACCESS_KEY_HINT :: ( (1) << 42) ; -ELEMENT_LAYOUT_HINT_HORIZONTAL :: ( (1) << 43) ; -ELEMENT_STICKY_ACCESS_KEY :: ( (1) << 44) ; -CELL_NEW_BAND :: ( (1) << 51); -CELL_COLLAPSABLE :: ( (1) << 51); -CELL_H_PUSH :: ( (1) << 54); -CELL_H_EXPAND :: ( (1) << 55); -CELL_H_SHRINK :: ( (1) << 56); -CELL_H_LEFT :: ( (1) << 57); -CELL_H_RIGHT :: ( (1) << 58); -CELL_V_PUSH :: ( (1) << 59); -CELL_V_EXPAND :: ( (1) << 60); -CELL_V_SHRINK :: ( (1) << 61); -CELL_V_TOP :: ( (1) << 62); -CELL_V_BOTTOM :: ( (1) << 63); -PANEL_VERTICAL :: (0x0001); -PANEL_WRAP :: (0x0002); -PANEL_TABLE :: (0x0004); -PANEL_Z_STACK :: (0x0008); -PANEL_H_LEFT :: (0x0010); -PANEL_H_RIGHT :: (0x0020); -PANEL_H_CENTER :: (0x0040); -PANEL_H_JUSTIFY :: (0x0080); -PANEL_V_TOP :: (0x0100); -PANEL_V_BOTTOM :: (0x0200); -PANEL_V_CENTER :: (0x0400); -PANEL_V_JUSTIFY :: (0x0800); -PANEL_H_SCROLL :: (0x1000); -PANEL_V_SCROLL :: (0x2000); -PANEL_SWITCHER :: (0x4000); -TEXTBOX_MULTILINE :: (1 << 0); -TEXTBOX_EDIT_BASED :: (1 << 1); -TEXTBOX_COMPACT :: (1 << 2); -TEXTBOX_NO_SMART_CONTEXT_MENUS :: (1 << 3); -TEXTBOX_FIND_BACKWARDS :: (1 << 0); -BUTTON_DEFAULT :: (1 << 0); -BUTTON_DANGEROUS :: (1 << 1); -BUTTON_MENU_ITEM :: (1 << 2); -BUTTON_NOT_FOCUSABLE :: (1 << 3); -BUTTON_TOOLBAR :: (1 << 4); -BUTTON_DROPDOWN :: (1 << 5); -BUTTON_COMPACT :: (1 << 6); -MENU_ITEM_HEADER :: (1 << 7); -BUTTON_CHECKBOX :: (1 << 8); -BUTTON_RADIOBOX :: (1 << 9); -BUTTON_CANCEL :: (1 << 10); -BUTTON_PUSH :: (1 << 11); -COLOR_WELL_HAS_OPACITY :: (1 << 0); -SCROLLBAR_VERTICAL :: (0 << 0); -SCROLLBAR_HORIZONTAL :: (1 << 0); -SPLITTER_VERTICAL :: (0 << 0); -SPLITTER_HORIZONTAL :: (1 << 0); -IMAGE_DISPLAY_LOAD_ASYNCHRONOUSLY :: (1 << 0); -IMAGE_DISPLAY_UNLOAD_WHEN_HIDDEN :: (1 << 1); -IMAGE_DISPLAY_UPSCALE_NEAREST :: (1 << 2); -IMAGE_DISPLAY_DOWNSCALE_NEAREST :: (1 << 3); -IMAGE_DISPLAY_OPAQUE :: (1 << 4); -LIST_VIEW_HORIZONTAL :: (1 << 0) ; -LIST_VIEW_VARIABLE_SIZE :: (1 << 1) ; -LIST_VIEW_TILED :: (1 << 2) ; -LIST_VIEW_NON_LINEAR :: (1 << 3) ; -LIST_VIEW_SINGLE_SELECT :: (1 << 4) ; -LIST_VIEW_MULTI_SELECT :: (1 << 5) ; -LIST_VIEW_COLUMNS :: (1 << 6) ; -LIST_VIEW_GROUP_HAS_HEADER :: (1 << 0) ; -LIST_VIEW_GROUP_HAS_FOOTER :: (1 << 1) ; -LIST_VIEW_GROUP_INDENT :: (1 << 2) ; -LIST_VIEW_GROUP_COLLAPSABLE :: (1 << 3) ; -LIST_VIEW_COLUMN_RIGHT_ALIGNED :: (1 << 0) ; -LIST_VIEW_COLUMN_ASCENDING :: (1 << 1) ; -LIST_VIEW_COLUMN_DESCENDING :: (1 << 2) ; -LIST_VIEW_COLUMN_HAS_MENU :: (1 << 3) ; -MENU_AT_CURSOR :: (1 << 0); -MENU_MAXIMUM_HEIGHT :: (1 << 1); -FONT_SANS :: (0xFFFF); -FONT_SERIF :: (0xFFFE); -FONT_MONOSPACED :: (0xFFFD); -FONT_REGULAR :: (4); -FONT_BOLD :: (7); -TEXT_FIGURE_DEFAULT :: (0); -TEXT_FIGURE_OLD :: (1); -TEXT_FIGURE_TABULAR :: (2); -TEXT_DISPLAY_CONTENT_MAX_VALUES :: (8); -DIRECTORY_MONITOR_SUBTREE :: (1 << 0) ; -DIRECTORY_MONITOR_CONTENTS :: (1 << 1) ; -DIRECTORY_MONITOR_MODIFY :: (1 << 2) ; -COMMAND_SYSTEM_START :: (0xF0000000); -COMMAND_DELETE :: (0xF0000001); -COMMAND_SELECT_ALL :: (0xF0000002); -COMMAND_CUT :: (0xF0000003); -COMMAND_COPY :: (0xF0000004); -COMMAND_PASTE :: (0xF0000005); -AUDIO_STREAM_OVERRUN :: (1 << 0); -AUDIO_STREAM_UNDERRUN :: (1 << 0); -AUDIO_STREAM_FORMAT_CHANGED :: (1 << 1); -AUDIO_STREAM_TERMINATED :: (1 << 2); -AUDIO_STREAM_RUNNING :: (1 << 0); -AUDIO_STREAM_MUTED :: (1 << 1); -AUDIO_STREAM_ONESHOT :: (1 << 2); -AUDIO_DEFAULT_OUTPUT :: (1); -SAMPLE_FORMAT_U8 :: (1); -SAMPLE_FORMAT_S16LE :: (2); -SAMPLE_FORMAT_S32LE :: (3); -SAMPLE_FORMAT_F32LE :: (4) ; -CELL_FILL :: ( CELL_H_FILL | CELL_V_FILL); -CELL_H_FILL :: ( CELL_H_PUSH | CELL_H_EXPAND | CELL_H_SHRINK); -CELL_V_FILL :: ( CELL_V_PUSH | CELL_V_EXPAND | CELL_V_SHRINK); -CELL_CENTER :: ( CELL_H_CENTER | CELL_V_CENTER); -CELL_PUSH :: ( CELL_H_PUSH | CELL_V_PUSH); -CELL_EXPAND :: ( CELL_H_EXPAND | CELL_V_EXPAND); -CELL_CORNER :: ( CELL_H_LEFT | CELL_V_TOP); -CELL_SHRINK :: ( CELL_H_SHRINK | CELL_V_SHRINK); -CELL_H_CENTER :: ( CELL_H_LEFT | CELL_H_RIGHT); -CELL_V_CENTER :: ( CELL_V_TOP | CELL_V_BOTTOM); -THEME_METRICS_INSETS :: (1 << 0); -THEME_METRICS_CLIP_INSETS :: (1 << 1); -THEME_METRICS_GLOBAL_OFFSET :: (1 << 2) ; -THEME_METRICS_CLIP_ENABLED :: (1 << 3); -THEME_METRICS_CURSOR :: (1 << 4); -THEME_METRICS_ENTRANCE_TRANSITION :: (1 << 5); -THEME_METRICS_EXIT_TRANSITION :: (1 << 6); -THEME_METRICS_ENTRANCE_DURATION :: (1 << 7); -THEME_METRICS_EXIT_DURATION :: (1 << 8); -THEME_METRICS_PREFERRED_WIDTH :: (1 << 9); -THEME_METRICS_PREFERRED_HEIGHT :: (1 << 10); -THEME_METRICS_MINIMUM_WIDTH :: (1 << 11); -THEME_METRICS_MINIMUM_HEIGHT :: (1 << 12); -THEME_METRICS_MAXIMUM_WIDTH :: (1 << 13); -THEME_METRICS_MAXIMUM_HEIGHT :: (1 << 14); -THEME_METRICS_GAP_MAJOR :: (1 << 15); -THEME_METRICS_GAP_MINOR :: (1 << 16); -THEME_METRICS_GAP_WRAP :: (1 << 17); -THEME_METRICS_GAP_ALL :: ( THEME_METRICS_GAP_MAJOR | THEME_METRICS_GAP_MINOR | THEME_METRICS_GAP_WRAP); -THEME_METRICS_TEXT_COLOR :: (1 << 18); -THEME_METRICS_SELECTED_BACKGROUND :: (1 << 19); -THEME_METRICS_SELECTED_TEXT :: (1 << 20); -THEME_METRICS_ICON_COLOR :: (1 << 21); -THEME_METRICS_TEXT_ALIGN :: (1 << 22); -THEME_METRICS_TEXT_SIZE :: (1 << 23); -THEME_METRICS_FONT_FAMILY :: (1 << 24); -THEME_METRICS_FONT_WEIGHT :: (1 << 25); -THEME_METRICS_ICON_SIZE :: (1 << 26); -THEME_METRICS_IS_ITALIC :: (1 << 27); -THEME_METRICS_ELLIPSIS :: (1 << 28); -THEME_METRICS_WRAP_TEXT :: (1 << 29); -MOVE_WINDOW_MAXIMISED :: (1 << 0); -MOVE_WINDOW_ADJUST_TO_FIT_SCREEN :: (1 << 1); -MOVE_WINDOW_HIDDEN :: (1 << 2); -MOVE_WINDOW_ALWAYS_ON_TOP :: (1 << 3); -MOVE_WINDOW_AT_BOTTOM :: (1 << 4); -MOVE_WINDOW_UPDATE_SCREEN :: (1 << 5); -WINDOW_SOLID_TRUE :: (1 << 0); -WINDOW_SOLID_NO_ACTIVATE :: (1 << 1); -THEME_BITMAP_WIDTH :: (400); -THEME_BITMAP_HEIGHT :: (200); -THEME_BITMAP_NAME :: "Desktop.ThemeBitmap"; -TEXTBOX_MOVE_CARET_SINGLE :: (2); -TEXTBOX_MOVE_CARET_WORD :: (3); -TEXTBOX_MOVE_CARET_LINE :: (4); -TEXTBOX_MOVE_CARET_VERTICAL :: (5); -TEXTBOX_MOVE_CARET_ALL :: (6); -TEXTBOX_MOVE_CARET_FIRST_ONLY :: (1 << 8); -TEXTBOX_MOVE_CARET_SECOND_ONLY :: (1 << 9); -TEXTBOX_MOVE_CARET_BACKWARDS :: (1 << 10); -TEXTBOX_MOVE_CARET_STRONG_WHITESPACE :: (1 << 11); -GAME_CONTROLLER_MAX_COUNT :: (16); -DOMAIN_NAME_MAX_LENGTH :: (255); -ECHO_REQUEST_MAX_LENGTH :: (48); -CONNECTION_OPEN_WAIT :: (1 << 0); -FILE_CONTROL_NOTIFY_MONITORS :: (1 << 0); -FILE_CONTROL_FLUSH :: (1 << 1); +Generic :: rawptr +INSTANCE_TYPE :: Instance +Element :: ElementPublic +Panel :: Element +Window :: Element +Scrollbar :: Element +Button :: Element +TextDisplay :: Element +IconDisplay :: Element +Textbox :: Element +ListView :: Element +Menu :: Element +Choice :: Element +ColorWell :: Element +Splitter :: Element +ImageDisplay :: Element +TextPlan :: rawptr +Store :: rawptr +PaintTarget :: rawptr +DirectoryMonitor :: rawptr +NodeType :: u8 +Error :: int +Handle :: uint +Response :: i32 +FileOffset :: u64 +FileOffsetDifference :: i64 +AudioDeviceID :: u64 +SCANCODE_A :: (0x04) +SCANCODE_B :: (0x05) +SCANCODE_C :: (0x06) +SCANCODE_D :: (0x07) +SCANCODE_E :: (0x08) +SCANCODE_F :: (0x09) +SCANCODE_G :: (0x0A) +SCANCODE_H :: (0x0B) +SCANCODE_I :: (0x0C) +SCANCODE_J :: (0x0D) +SCANCODE_K :: (0x0E) +SCANCODE_L :: (0x0F) +SCANCODE_M :: (0x10) +SCANCODE_N :: (0x11) +SCANCODE_O :: (0x12) +SCANCODE_P :: (0x13) +SCANCODE_Q :: (0x14) +SCANCODE_R :: (0x15) +SCANCODE_S :: (0x16) +SCANCODE_T :: (0x17) +SCANCODE_U :: (0x18) +SCANCODE_V :: (0x19) +SCANCODE_W :: (0x1A) +SCANCODE_X :: (0x1B) +SCANCODE_Y :: (0x1C) +SCANCODE_Z :: (0x1D) +SCANCODE_1 :: (0x1E) +SCANCODE_2 :: (0x1F) +SCANCODE_3 :: (0x20) +SCANCODE_4 :: (0x21) +SCANCODE_5 :: (0x22) +SCANCODE_6 :: (0x23) +SCANCODE_7 :: (0x24) +SCANCODE_8 :: (0x25) +SCANCODE_9 :: (0x26) +SCANCODE_0 :: (0x27) +SCANCODE_ENTER :: (0x28) +SCANCODE_ESCAPE :: (0x29) +SCANCODE_BACKSPACE :: (0x2A) +SCANCODE_TAB :: (0x2B) +SCANCODE_SPACE :: (0x2C) +SCANCODE_HYPHEN :: (0x2D) +SCANCODE_EQUALS :: (0x2E) +SCANCODE_LEFT_BRACE :: (0x2F) +SCANCODE_RIGHT_BRACE :: (0x30) +SCANCODE_COMMA :: (0x36) +SCANCODE_PERIOD :: (0x37) +SCANCODE_SLASH :: (0x38) +SCANCODE_PUNCTUATION_1 :: (0x31) +SCANCODE_PUNCTUATION_2 :: (0x32) +SCANCODE_PUNCTUATION_3 :: (0x33) +SCANCODE_PUNCTUATION_4 :: (0x34) +SCANCODE_PUNCTUATION_5 :: (0x35) +SCANCODE_PUNCTUATION_6 :: (0x64) +SCANCODE_F1 :: (0x3A) +SCANCODE_F2 :: (0x3B) +SCANCODE_F3 :: (0x3C) +SCANCODE_F4 :: (0x3D) +SCANCODE_F5 :: (0x3E) +SCANCODE_F6 :: (0x3F) +SCANCODE_F7 :: (0x40) +SCANCODE_F8 :: (0x41) +SCANCODE_F9 :: (0x42) +SCANCODE_F10 :: (0x43) +SCANCODE_F11 :: (0x44) +SCANCODE_F12 :: (0x45) +SCANCODE_F13 :: (0x68) +SCANCODE_F14 :: (0x69) +SCANCODE_F15 :: (0x6A) +SCANCODE_F16 :: (0x6B) +SCANCODE_F17 :: (0x6C) +SCANCODE_F18 :: (0x6D) +SCANCODE_F19 :: (0x6E) +SCANCODE_F20 :: (0x6F) +SCANCODE_F21 :: (0x70) +SCANCODE_F22 :: (0x71) +SCANCODE_F23 :: (0x72) +SCANCODE_F24 :: (0x73) +SCANCODE_CAPS_LOCK :: (0x39) +SCANCODE_PRINT_SCREEN :: (0x46) +SCANCODE_SCROLL_LOCK :: (0x47) +SCANCODE_PAUSE :: (0x48) +SCANCODE_INSERT :: (0x49) +SCANCODE_HOME :: (0x4A) +SCANCODE_PAGE_UP :: (0x4B) +SCANCODE_DELETE :: (0x4C) +SCANCODE_END :: (0x4D) +SCANCODE_PAGE_DOWN :: (0x4E) +SCANCODE_RIGHT_ARROW :: (0x4F) +SCANCODE_LEFT_ARROW :: (0x50) +SCANCODE_DOWN_ARROW :: (0x51) +SCANCODE_UP_ARROW :: (0x52) +SCANCODE_NUM_LOCK :: (0x53) +SCANCODE_CONTEXT_MENU :: (0x65) +SCANCODE_SYSTEM_REQUEST :: (0x9A) +SCANCODE_ACTION_EXECUTE :: (0x74) +SCANCODE_ACTION_HELP :: (0x75) +SCANCODE_ACTION_MENU :: (0x76) +SCANCODE_ACTION_SELECT :: (0x77) +SCANCODE_ACTION_STOP :: (0x78) +SCANCODE_ACTION_AGAIN :: (0x79) +SCANCODE_ACTION_UNDO :: (0x7A) +SCANCODE_ACTION_CUT :: (0x7B) +SCANCODE_ACTION_COPY :: (0x7C) +SCANCODE_ACTION_PASTE :: (0x7D) +SCANCODE_ACTION_FIND :: (0x7E) +SCANCODE_ACTION_CANCEL :: (0x9B) +SCANCODE_ACTION_CLEAR :: (0x9C) +SCANCODE_ACTION_PRIOR :: (0x9D) +SCANCODE_ACTION_RETURN :: (0x9E) +SCANCODE_ACTION_SEPARATOR :: (0x9F) +SCANCODE_MM_MUTE :: (0x7F) +SCANCODE_MM_LOUDER :: (0x80) +SCANCODE_MM_QUIETER :: (0x81) +SCANCODE_MM_NEXT :: (0x103) +SCANCODE_MM_PREVIOUS :: (0x104) +SCANCODE_MM_STOP :: (0x105) +SCANCODE_MM_PAUSE :: (0x106) +SCANCODE_MM_SELECT :: (0x107) +SCANCODE_MM_EMAIL :: (0x108) +SCANCODE_MM_CALC :: (0x109) +SCANCODE_MM_FILES :: (0x10A) +SCANCODE_INTERNATIONAL_1 :: (0x87) +SCANCODE_INTERNATIONAL_2 :: (0x88) +SCANCODE_INTERNATIONAL_3 :: (0x89) +SCANCODE_INTERNATIONAL_4 :: (0x8A) +SCANCODE_INTERNATIONAL_5 :: (0x8B) +SCANCODE_INTERNATIONAL_6 :: (0x8C) +SCANCODE_INTERNATIONAL_7 :: (0x8D) +SCANCODE_INTERNATIONAL_8 :: (0x8E) +SCANCODE_INTERNATIONAL_9 :: (0x8F) +SCANCODE_HANGUL_ENGLISH_TOGGLE :: (0x90) +SCANCODE_HANJA_CONVERSION :: (0x91) +SCANCODE_KATAKANA :: (0x92) +SCANCODE_HIRAGANA :: (0x93) +SCANCODE_HANKAKU_ZENKAKU_TOGGLE :: (0x94) +SCANCODE_ALTERNATE_ERASE :: (0x99) +SCANCODE_THOUSANDS_SEPARATOR :: (0xB2) +SCANCODE_DECIMAL_SEPARATOR :: (0xB3) +SCANCODE_CURRENCY_UNIT :: (0xB4) +SCANCODE_CURRENCY_SUBUNIT :: (0xB5) +SCANCODE_NUM_DIVIDE :: (0x54) +SCANCODE_NUM_MULTIPLY :: (0x55) +SCANCODE_NUM_SUBTRACT :: (0x56) +SCANCODE_NUM_ADD :: (0x57) +SCANCODE_NUM_ENTER :: (0x58) +SCANCODE_NUM_1 :: (0x59) +SCANCODE_NUM_2 :: (0x5A) +SCANCODE_NUM_3 :: (0x5B) +SCANCODE_NUM_4 :: (0x5C) +SCANCODE_NUM_5 :: (0x5D) +SCANCODE_NUM_6 :: (0x5E) +SCANCODE_NUM_7 :: (0x5F) +SCANCODE_NUM_8 :: (0x60) +SCANCODE_NUM_9 :: (0x61) +SCANCODE_NUM_0 :: (0x62) +SCANCODE_NUM_POINT :: (0x63) +SCANCODE_NUM_EQUALS :: (0x67) +SCANCODE_NUM_COMMA :: (0x82) +SCANCODE_NUM_00 :: (0xB0) +SCANCODE_NUM_000 :: (0xB1) +SCANCODE_NUM_LEFT_PAREN :: (0xB6) +SCANCODE_NUM_RIGHT_PAREN :: (0xB7) +SCANCODE_NUM_LEFT_BRACE :: (0xB8) +SCANCODE_NUM_RIGHT_BRACE :: (0xB9) +SCANCODE_NUM_TAB :: (0xBA) +SCANCODE_NUM_BACKSPACE :: (0xBB) +SCANCODE_NUM_A :: (0xBC) +SCANCODE_NUM_B :: (0xBD) +SCANCODE_NUM_C :: (0xBE) +SCANCODE_NUM_D :: (0xBF) +SCANCODE_NUM_E :: (0xC0) +SCANCODE_NUM_F :: (0xC1) +SCANCODE_NUM_XOR :: (0xC2) +SCANCODE_NUM_CARET :: (0xC3) +SCANCODE_NUM_PERCENT :: (0xC4) +SCANCODE_NUM_LESS_THAN :: (0xC5) +SCANCODE_NUM_GREATER_THAN :: (0xC6) +SCANCODE_NUM_AMPERSAND :: (0xC7) +SCANCODE_NUM_DOUBLE_AMPERSAND :: (0xC8) +SCANCODE_NUM_BAR :: (0xC9) +SCANCODE_NUM_DOUBLE_BAR :: (0xCA) +SCANCODE_NUM_COLON :: (0xCB) +SCANCODE_NUM_HASH :: (0xCC) +SCANCODE_NUM_SPACE :: (0xCD) +SCANCODE_NUM_AT :: (0xCE) +SCANCODE_NUM_EXCLAMATION_MARK :: (0xCF) +SCANCODE_NUM_MEMORY_STORE :: (0xD0) +SCANCODE_NUM_MEMORY_RECALL :: (0xD1) +SCANCODE_NUM_MEMORY_CLEAR :: (0xD2) +SCANCODE_NUM_MEMORY_ADD :: (0xD3) +SCANCODE_NUM_MEMORY_SUBTRACT :: (0xD4) +SCANCODE_NUM_MEMORY_MULTIPLY :: (0xD5) +SCANCODE_NUM_MEMORY_DIVIDE :: (0xD6) +SCANCODE_NUM_NEGATE :: (0xD7) +SCANCODE_NUM_CLEAR_ALL :: (0xD8) +SCANCODE_NUM_CLEAR :: (0xD9) +SCANCODE_NUM_BINARY :: (0xDA) +SCANCODE_NUM_OCTAL :: (0xDB) +SCANCODE_NUM_DECIMAL :: (0xDC) +SCANCODE_NUM_HEXADECIMAL :: (0xDD) +SCANCODE_LEFT_CTRL :: (0xE0) +SCANCODE_LEFT_SHIFT :: (0xE1) +SCANCODE_LEFT_ALT :: (0xE2) +SCANCODE_LEFT_FLAG :: (0xE3) +SCANCODE_RIGHT_CTRL :: (0xE4) +SCANCODE_RIGHT_SHIFT :: (0xE5) +SCANCODE_RIGHT_ALT :: (0xE6) +SCANCODE_RIGHT_FLAG :: (0xE7) +SCANCODE_ACPI_POWER :: (0x100) +SCANCODE_ACPI_SLEEP :: (0x101) +SCANCODE_ACPI_WAKE :: (0x102) +SCANCODE_WWW_SEARCH :: (0x10B) +SCANCODE_WWW_HOME :: (0x10C) +SCANCODE_WWW_BACK :: (0x10D) +SCANCODE_WWW_FORWARD :: (0x10E) +SCANCODE_WWW_STOP :: (0x10F) +SCANCODE_WWW_REFRESH :: (0x110) +SCANCODE_WWW_STARRED :: (0x111) +PROCESS_STATE_ALL_THREADS_TERMINATED :: (1) +PROCESS_STATE_TERMINATING :: (2) +PROCESS_STATE_CRASHED :: (4) +PROCESS_STATE_PINGED :: (8) +FLAGS_DEFAULT :: (0) +SUCCESS :: (-1) +ERROR_BUFFER_TOO_SMALL :: (-2) +ERROR_UNKNOWN :: (-7) +ERROR_NO_MESSAGES_AVAILABLE :: (-9) +ERROR_MESSAGE_QUEUE_FULL :: (-10) +ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME :: (-14) +ERROR_PATH_NOT_TRAVERSABLE :: (-15) +ERROR_FILE_ALREADY_EXISTS :: (-19) +ERROR_FILE_DOES_NOT_EXIST :: (-20) +ERROR_DRIVE_ERROR_FILE_DAMAGED :: (-21) +ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS :: (-22) +ERROR_FILE_PERMISSION_NOT_GRANTED :: (-23) +ERROR_FILE_IN_EXCLUSIVE_USE :: (-24) +ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE :: (-25) +ERROR_INCORRECT_NODE_TYPE :: (-26) +ERROR_EVENT_NOT_SET :: (-27) +ERROR_FILE_HAS_WRITERS :: (-28) +ERROR_TIMEOUT_REACHED :: (-29) +ERROR_FILE_ON_READ_ONLY_VOLUME :: (-32) +ERROR_INVALID_DIMENSIONS :: (-34) +ERROR_DRIVE_CONTROLLER_REPORTED :: (-35) +ERROR_COULD_NOT_ISSUE_PACKET :: (-36) +ERROR_HANDLE_TABLE_FULL :: (-37) +ERROR_COULD_NOT_RESIZE_FILE :: (-38) +ERROR_DIRECTORY_NOT_EMPTY :: (-39) +ERROR_NODE_DELETED :: (-41) +ERROR_VOLUME_MISMATCH :: (-43) +ERROR_TARGET_WITHIN_SOURCE :: (-44) +ERROR_TARGET_INVALID_TYPE :: (-45) +ERROR_MALFORMED_NODE_PATH :: (-47) +ERROR_OUT_OF_CACHE_RESOURCES :: (-48) +ERROR_TARGET_IS_SOURCE :: (-49) +ERROR_INVALID_NAME :: (-50) +ERROR_CORRUPT_DATA :: (-51) +ERROR_INSUFFICIENT_RESOURCES :: (-52) +ERROR_UNSUPPORTED_FEATURE :: (-53) +ERROR_FILE_TOO_FRAGMENTED :: (-54) +ERROR_DRIVE_FULL :: (-55) +ERROR_COULD_NOT_RESOLVE_SYMBOL :: (-56) +ERROR_ALREADY_EMBEDDED :: (-57) +ERROR_EVENT_SINK_OVERFLOW :: (-58) +ERROR_EVENT_SINK_DUPLICATE :: (-59) +ERROR_UNSUPPORTED_CONVERSION :: (-60) +ERROR_SOURCE_EMPTY :: (-61) +ERROR_UNSUPPORTED_EXECUTABLE :: (-62) +ERROR_NO_ADDRESS_FOR_DOMAIN_NAME :: (-63) +ERROR_NO_CONNECTED_NETWORK_INTERFACES :: (-64) +ERROR_BAD_DOMAIN_NAME :: (-65) +ERROR_LOST_IP_ADDRESS :: (-66) +ERROR_CONNECTION_RESET :: (-67) +ERROR_CONNECTION_REFUSED :: (-68) +SYSTEM_CONSTANT_TIME_STAMP_UNITS_PER_MICROSECOND :: (0) +SYSTEM_CONSTANT_NO_FANCY_GRAPHICS :: (1) +SYSTEM_CONSTANT_REPORTED_PROBLEMS :: (2) +SYSTEM_CONSTANT_RIGHT_TO_LEFT :: (3) +SYSTEM_CONSTANT_WINDOW_INSET :: (4) +SYSTEM_CONSTANT_CONTAINER_TAB_BAND_HEIGHT :: (5) +INVALID_HANDLE :: (( Handle) (0)) +CURRENT_THREAD :: (( Handle) (0x10)) +CURRENT_PROCESS :: (( Handle) (0x11)) +DRAW_ALPHA_OVERWRITE :: (0x100) +DRAW_ALPHA_FULL :: (0x200) +WAIT_NO_TIMEOUT :: (-1) +MAX_WAIT_COUNT :: (8) +MAX_EVENT_FORWARD_COUNT :: (4) +MAX_EVENT_SINK_BUFFER_SIZE :: (256) +MAX_DIRECTORY_CHILD_NAME_LENGTH :: (256) +PROCESS_EXECUTABLE_NOT_LOADED :: (0) +PROCESS_EXECUTABLE_FAILED_TO_LOAD :: (1) +PROCESS_EXECUTABLE_LOADED :: (2) +SNAPSHOT_MAX_PROCESS_NAME_LENGTH :: (80) +SYSTEM_SNAPSHOT_PROCESSES :: (1) +SYSTEM_SNAPSHOT_DRIVES :: (2) +HANDLED :: (0) +NOT_HANDLED :: (-1) +REJECTED :: (-2) +SHARED_MEMORY_NAME_MAX_LENGTH :: (32) +MAP_OBJECT_ALL :: (0) +TEXT_H_LEFT :: (1) +TEXT_H_RIGHT :: (2) +TEXT_H_CENTER :: (3) +TEXT_V_TOP :: (4) +TEXT_V_BOTTOM :: (8) +TEXT_V_CENTER :: (12) +TEXT_WRAP :: (16) +TEXT_ELLIPSIS :: (32) +NODE_ACCESS_READ_SHARED :: (0x1) +NODE_ACCESS_READ :: (0x2) +NODE_ACCESS_WRITE :: (0x4) +NODE_ACCESS_WRITE_EXCLUSIVE :: (0x8) +NODE_FILE :: (0) +NODE_DIRECTORY :: (0x10) +NODE_INVALID :: (0x20) +NODE_FAIL_IF_FOUND :: (0x1000) +NODE_FAIL_IF_NOT_FOUND :: (0x2000) +NODE_PREVENT_RESIZE :: (0x4000) +NODE_CREATE_DIRECTORIES :: (0x8000) +NODE_POSIX_NAMESPACE :: (0x10000) +_ES_NODE_FROM_WRITE_EXCLUSIVE :: (0x20000) +DIRECTORY_CHILDREN_UNKNOWN :: (( FileOffsetDifference) (-1)) +MEMORY_OPEN_FAIL_IF_FOUND :: (0x1000) +MEMORY_OPEN_FAIL_IF_NOT_FOUND :: (0x2000) +MAP_OBJECT_READ_WRITE :: (0) +MAP_OBJECT_READ_ONLY :: (1) +MAP_OBJECT_COPY_ON_WRITE :: (2) +STRING_FORMAT_ENOUGH_SPACE :: ( (-1)) +STRING_FORMAT_SIMPLE :: (1 << 0) +POSIX_SYSCALL_GET_POSIX_FD_PATH :: (0x10000) +PERMISSION_ACCESS_SYSTEM_FILES :: (1 << 0) +PERMISSION_ACCESS_USER_FILES :: (1 << 1) +PERMISSION_PROCESS_CREATE :: (1 << 2) +PERMISSION_PROCESS_OPEN :: (1 << 3) +PERMISSION_SCREEN_MODIFY :: (1 << 4) +PERMISSION_SHUTDOWN :: (1 << 5) +PERMISSION_TAKE_SYSTEM_SNAPSHOT :: (1 << 6) +PERMISSION_WINDOW_OPEN :: (1 << 7) +PERMISSION_ALL :: ( (-1)) +PERMISSION_INHERIT :: ( (1) << 63) +PANEL_STYLE_DEFAULT :: "Panel.Default" +PANEL_STYLE_TRANSPARENT :: "Panel.Transparent" +PANEL_STYLE_WINDOW_BACKGROUND :: "Panel.WindowBackground" +PANEL_STYLE_WINDOW_DIVIDER :: "Panel.WindowDivider" +PANEL_STYLE_SHEET :: "Panel.Sheet" +PANEL_STYLE_GROUP_BOX :: "Panel.GroupBox" +PANEL_STYLE_INDENT :: "Panel.Indent" +PANEL_BAND_SIZE_DEFAULT :: (-1) +ELEMENT_FOCUSABLE :: ( (1) << 32) +ELEMENT_HIDDEN :: ( (1) << 33) +ELEMENT_DISABLED :: ( (1) << 34) +ELEMENT_DEBUG :: ( (1) << 35) +ELEMENT_SCROLL_X :: ( (1) << 36) +ELEMENT_SCROLL_Y :: ( (1) << 37) +ELEMENT_NO_HOVER :: ( (1) << 38) +ELEMENT_BLOCK_FOCUS :: ( (1) << 39) +ELEMENT_NOT_TAB_TRAVERSABLE :: ( (1) << 40) +ELEMENT_NO_INFORM_PARENT :: ( (1) << 41) +ELEMENT_CENTER_ACCESS_KEY_HINT :: ( (1) << 42) +ELEMENT_LAYOUT_HINT_HORIZONTAL :: ( (1) << 43) +ELEMENT_STICKY_ACCESS_KEY :: ( (1) << 44) +CELL_NEW_BAND :: ( (1) << 51) +CELL_COLLAPSABLE :: ( (1) << 51) +CELL_H_PUSH :: ( (1) << 54) +CELL_H_EXPAND :: ( (1) << 55) +CELL_H_SHRINK :: ( (1) << 56) +CELL_H_LEFT :: ( (1) << 57) +CELL_H_RIGHT :: ( (1) << 58) +CELL_V_PUSH :: ( (1) << 59) +CELL_V_EXPAND :: ( (1) << 60) +CELL_V_SHRINK :: ( (1) << 61) +CELL_V_TOP :: ( (1) << 62) +CELL_V_BOTTOM :: ( (1) << 63) +PANEL_VERTICAL :: (0x0001) +PANEL_WRAP :: (0x0002) +PANEL_TABLE :: (0x0004) +PANEL_Z_STACK :: (0x0008) +PANEL_H_LEFT :: (0x0010) +PANEL_H_RIGHT :: (0x0020) +PANEL_H_CENTER :: (0x0040) +PANEL_H_JUSTIFY :: (0x0080) +PANEL_V_TOP :: (0x0100) +PANEL_V_BOTTOM :: (0x0200) +PANEL_V_CENTER :: (0x0400) +PANEL_V_JUSTIFY :: (0x0800) +PANEL_H_SCROLL :: (0x1000) +PANEL_V_SCROLL :: (0x2000) +PANEL_SWITCHER :: (0x4000) +TEXTBOX_MULTILINE :: (1 << 0) +TEXTBOX_EDIT_BASED :: (1 << 1) +TEXTBOX_COMPACT :: (1 << 2) +TEXTBOX_NO_SMART_CONTEXT_MENUS :: (1 << 3) +TEXTBOX_FIND_BACKWARDS :: (1 << 0) +BUTTON_DEFAULT :: (1 << 0) +BUTTON_DANGEROUS :: (1 << 1) +BUTTON_MENU_ITEM :: (1 << 2) +BUTTON_NOT_FOCUSABLE :: (1 << 3) +BUTTON_TOOLBAR :: (1 << 4) +BUTTON_DROPDOWN :: (1 << 5) +BUTTON_COMPACT :: (1 << 6) +MENU_ITEM_HEADER :: (1 << 7) +BUTTON_CHECKBOX :: (1 << 8) +BUTTON_RADIOBOX :: (1 << 9) +BUTTON_CANCEL :: (1 << 10) +BUTTON_PUSH :: (1 << 11) +COLOR_WELL_HAS_OPACITY :: (1 << 0) +SCROLLBAR_VERTICAL :: (0 << 0) +SCROLLBAR_HORIZONTAL :: (1 << 0) +SPLITTER_VERTICAL :: (0 << 0) +SPLITTER_HORIZONTAL :: (1 << 0) +IMAGE_DISPLAY_LOAD_ASYNCHRONOUSLY :: (1 << 0) +IMAGE_DISPLAY_UNLOAD_WHEN_HIDDEN :: (1 << 1) +IMAGE_DISPLAY_UPSCALE_NEAREST :: (1 << 2) +IMAGE_DISPLAY_DOWNSCALE_NEAREST :: (1 << 3) +IMAGE_DISPLAY_OPAQUE :: (1 << 4) +LIST_VIEW_HORIZONTAL :: (1 << 0) +LIST_VIEW_VARIABLE_SIZE :: (1 << 1) +LIST_VIEW_TILED :: (1 << 2) +LIST_VIEW_NON_LINEAR :: (1 << 3) +LIST_VIEW_SINGLE_SELECT :: (1 << 4) +LIST_VIEW_MULTI_SELECT :: (1 << 5) +LIST_VIEW_COLUMNS :: (1 << 6) +LIST_VIEW_GROUP_HAS_HEADER :: (1 << 0) +LIST_VIEW_GROUP_HAS_FOOTER :: (1 << 1) +LIST_VIEW_GROUP_INDENT :: (1 << 2) +LIST_VIEW_GROUP_COLLAPSABLE :: (1 << 3) +LIST_VIEW_COLUMN_RIGHT_ALIGNED :: (1 << 0) +LIST_VIEW_COLUMN_ASCENDING :: (1 << 1) +LIST_VIEW_COLUMN_DESCENDING :: (1 << 2) +LIST_VIEW_COLUMN_HAS_MENU :: (1 << 3) +MENU_AT_CURSOR :: (1 << 0) +MENU_MAXIMUM_HEIGHT :: (1 << 1) +FONT_SANS :: (0xFFFF) +FONT_SERIF :: (0xFFFE) +FONT_MONOSPACED :: (0xFFFD) +FONT_REGULAR :: (4) +FONT_BOLD :: (7) +TEXT_FIGURE_DEFAULT :: (0) +TEXT_FIGURE_OLD :: (1) +TEXT_FIGURE_TABULAR :: (2) +TEXT_DISPLAY_CONTENT_MAX_VALUES :: (8) +DIRECTORY_MONITOR_SUBTREE :: (1 << 0) +DIRECTORY_MONITOR_CONTENTS :: (1 << 1) +DIRECTORY_MONITOR_MODIFY :: (1 << 2) +COMMAND_SYSTEM_START :: (0xF0000000) +COMMAND_DELETE :: (0xF0000001) +COMMAND_SELECT_ALL :: (0xF0000002) +COMMAND_CUT :: (0xF0000003) +COMMAND_COPY :: (0xF0000004) +COMMAND_PASTE :: (0xF0000005) +AUDIO_STREAM_OVERRUN :: (1 << 0) +AUDIO_STREAM_UNDERRUN :: (1 << 0) +AUDIO_STREAM_FORMAT_CHANGED :: (1 << 1) +AUDIO_STREAM_TERMINATED :: (1 << 2) +AUDIO_STREAM_RUNNING :: (1 << 0) +AUDIO_STREAM_MUTED :: (1 << 1) +AUDIO_STREAM_ONESHOT :: (1 << 2) +AUDIO_DEFAULT_OUTPUT :: (1) +SAMPLE_FORMAT_U8 :: (1) +SAMPLE_FORMAT_S16LE :: (2) +SAMPLE_FORMAT_S32LE :: (3) +SAMPLE_FORMAT_F32LE :: (4) +CELL_FILL :: ( CELL_H_FILL | CELL_V_FILL) +CELL_H_FILL :: ( CELL_H_PUSH | CELL_H_EXPAND | CELL_H_SHRINK) +CELL_V_FILL :: ( CELL_V_PUSH | CELL_V_EXPAND | CELL_V_SHRINK) +CELL_CENTER :: ( CELL_H_CENTER | CELL_V_CENTER) +CELL_PUSH :: ( CELL_H_PUSH | CELL_V_PUSH) +CELL_EXPAND :: ( CELL_H_EXPAND | CELL_V_EXPAND) +CELL_CORNER :: ( CELL_H_LEFT | CELL_V_TOP) +CELL_SHRINK :: ( CELL_H_SHRINK | CELL_V_SHRINK) +CELL_H_CENTER :: ( CELL_H_LEFT | CELL_H_RIGHT) +CELL_V_CENTER :: ( CELL_V_TOP | CELL_V_BOTTOM) +THEME_METRICS_INSETS :: (1 << 0) +THEME_METRICS_CLIP_INSETS :: (1 << 1) +THEME_METRICS_GLOBAL_OFFSET :: (1 << 2) +THEME_METRICS_CLIP_ENABLED :: (1 << 3) +THEME_METRICS_CURSOR :: (1 << 4) +THEME_METRICS_ENTRANCE_TRANSITION :: (1 << 5) +THEME_METRICS_EXIT_TRANSITION :: (1 << 6) +THEME_METRICS_ENTRANCE_DURATION :: (1 << 7) +THEME_METRICS_EXIT_DURATION :: (1 << 8) +THEME_METRICS_PREFERRED_WIDTH :: (1 << 9) +THEME_METRICS_PREFERRED_HEIGHT :: (1 << 10) +THEME_METRICS_MINIMUM_WIDTH :: (1 << 11) +THEME_METRICS_MINIMUM_HEIGHT :: (1 << 12) +THEME_METRICS_MAXIMUM_WIDTH :: (1 << 13) +THEME_METRICS_MAXIMUM_HEIGHT :: (1 << 14) +THEME_METRICS_GAP_MAJOR :: (1 << 15) +THEME_METRICS_GAP_MINOR :: (1 << 16) +THEME_METRICS_GAP_WRAP :: (1 << 17) +THEME_METRICS_GAP_ALL :: ( THEME_METRICS_GAP_MAJOR | THEME_METRICS_GAP_MINOR | THEME_METRICS_GAP_WRAP) +THEME_METRICS_TEXT_COLOR :: (1 << 18) +THEME_METRICS_SELECTED_BACKGROUND :: (1 << 19) +THEME_METRICS_SELECTED_TEXT :: (1 << 20) +THEME_METRICS_ICON_COLOR :: (1 << 21) +THEME_METRICS_TEXT_ALIGN :: (1 << 22) +THEME_METRICS_TEXT_SIZE :: (1 << 23) +THEME_METRICS_FONT_FAMILY :: (1 << 24) +THEME_METRICS_FONT_WEIGHT :: (1 << 25) +THEME_METRICS_ICON_SIZE :: (1 << 26) +THEME_METRICS_IS_ITALIC :: (1 << 27) +THEME_METRICS_ELLIPSIS :: (1 << 28) +THEME_METRICS_WRAP_TEXT :: (1 << 29) +MOVE_WINDOW_MAXIMISED :: (1 << 0) +MOVE_WINDOW_ADJUST_TO_FIT_SCREEN :: (1 << 1) +MOVE_WINDOW_HIDDEN :: (1 << 2) +MOVE_WINDOW_ALWAYS_ON_TOP :: (1 << 3) +MOVE_WINDOW_AT_BOTTOM :: (1 << 4) +MOVE_WINDOW_UPDATE_SCREEN :: (1 << 5) +WINDOW_SOLID_TRUE :: (1 << 0) +WINDOW_SOLID_NO_ACTIVATE :: (1 << 1) +THEME_BITMAP_WIDTH :: (400) +THEME_BITMAP_HEIGHT :: (200) +THEME_BITMAP_NAME :: "Desktop.ThemeBitmap" +TEXTBOX_MOVE_CARET_SINGLE :: (2) +TEXTBOX_MOVE_CARET_WORD :: (3) +TEXTBOX_MOVE_CARET_LINE :: (4) +TEXTBOX_MOVE_CARET_VERTICAL :: (5) +TEXTBOX_MOVE_CARET_ALL :: (6) +TEXTBOX_MOVE_CARET_FIRST_ONLY :: (1 << 8) +TEXTBOX_MOVE_CARET_SECOND_ONLY :: (1 << 9) +TEXTBOX_MOVE_CARET_BACKWARDS :: (1 << 10) +TEXTBOX_MOVE_CARET_STRONG_WHITESPACE :: (1 << 11) +GAME_CONTROLLER_MAX_COUNT :: (16) +DOMAIN_NAME_MAX_LENGTH :: (255) +ECHO_REQUEST_MAX_LENGTH :: (48) +CONNECTION_OPEN_WAIT :: (1 << 0) +FILE_CONTROL_NOTIFY_MONITORS :: (1 << 0) +FILE_CONTROL_FLUSH :: (1 << 1) using StandardIcon :: enum i32 { ICON_NONE, ICON_ACTION_UNAVAILABLE_SYMBOLIC, @@ -1968,7 +1968,7 @@ using MemoryProtection :: enum i32 { MEMORY_PROTECTION_READ_WRITE, MEMORY_PROTECTION_EXECUTABLE, } -UICallbackFunction :: distinct #type proc "c" ( ^Element, ^Message, ^Response); +UICallbackFunction :: distinct #type proc "c" ( ^Element, ^Message, ^Response) BatchCall :: struct { index : SyscallType, stopBatchIfError : bool, @@ -2417,7 +2417,7 @@ FormatValue :: struct { time : u64 , }, } -FragmentShaderCallbackFunction :: distinct #type proc "c" ( i32, i32, ^StyledBox) -> u32 ; +FragmentShaderCallbackFunction :: distinct #type proc "c" ( i32, i32, ^StyledBox) -> u32 StyledBox :: struct { bounds : Rectangle, clip : Rectangle, @@ -2444,7 +2444,7 @@ CalculationValue :: struct { error : bool, number : f64 , } -CommandCallbackFunction :: distinct #type proc "c" ( ^INSTANCE_TYPE, ^Element, ^Command); +CommandCallbackFunction :: distinct #type proc "c" ( ^INSTANCE_TYPE, ^Element, ^Command) Command :: struct { elements : ^^Element, callback : CommandCallbackFunction, @@ -2569,332 +2569,332 @@ Connection :: struct { sendWritePointer : uint , handle : Handle, } -ThreadEntryFunction :: distinct #type proc "c" ( Generic); -ComparisonCallbackFunction :: distinct #type proc "c" ( rawptr, rawptr, Generic) -> i32; -SwapCallbackFunction :: distinct #type proc "c" ( rawptr, rawptr, Generic); -CRTComparisonCallback :: distinct #type proc "c" ( rawptr, rawptr) -> i32; -TimerCallbackFunction :: distinct #type proc "c" ( Generic); -MenuCallbackFunction :: distinct #type proc "c" ( ^Menu, Generic); -StorePullCallbackFunction :: distinct #type proc "c" ( ^Store, ^INSTANCE_TYPE, Generic, i32, Generic, ^FormatValue); -StoreCallbackFunction :: distinct #type proc "c" ( ^Store, ^INSTANCE_TYPE, Generic, Generic); -DirectoryMonitorCallbackFunction :: distinct #type proc "c" ( ^DirectoryMonitor, i32, ^i8 , int , ^i8 , int , Generic); -Batch :: #force_inline proc "c" (calls_ : ^BatchCall, count_ : int ){ addr := 0x1000 + 0 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^BatchCall, int )) (fp))(calls_, count_); } -GetCreationArgument :: #force_inline proc "c" (object_ : Handle) -> Generic{ addr := 0x1000 + 1 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> Generic) (fp))(object_); } -GetSystemInformation :: #force_inline proc "c" (systemInformation_ : ^SystemInformation){ addr := 0x1000 + 2 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^SystemInformation)) (fp))(systemInformation_); } -HandleClose :: #force_inline proc "c" (handle_ : Handle) -> Error{ addr := 0x1000 + 3 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> Error) (fp))(handle_); } -InitialiseCStandardLibrary :: #force_inline proc "c" (argc_ : ^i32, argv_ : ^^^i8 ){ addr := 0x1000 + 4 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^i32, ^^^i8 )) (fp))(argc_, argv_); } -MailslotSendData :: #force_inline proc "c" (mailslot_ : Handle, data_ : rawptr, bytes_ : int ) -> bool{ addr := 0x1000 + 5 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, rawptr, int ) -> bool) (fp))(mailslot_, data_, bytes_); } -MakeLinuxSystemCall2 :: #force_inline proc "c" (n_ : int , a1_ : int , a2_ : int , a3_ : int , a4_ : int , a5_ : int , a6_ : int ) -> int { addr := 0x1000 + 6 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , int , int , int , int , int , int ) -> int ) (fp))(n_, a1_, a2_, a3_, a4_, a5_, a6_); } -SystemGetConstant :: #force_inline proc "c" (index_ : uint ) -> u64 { addr := 0x1000 + 8 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( uint ) -> u64 ) (fp))(index_); } -TakeSystemSnapshot :: #force_inline proc "c" (type_ : i32, bufferSize_ : ^int ) -> Handle{ addr := 0x1000 + 9 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32, ^int ) -> Handle) (fp))(type_, bufferSize_); } -UserGetHomeFolder :: #force_inline proc "c" (buffer_ : ^i8 , bufferBytes_ : int ) -> int { addr := 0x1000 + 10 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int ) -> int ) (fp))(buffer_, bufferBytes_); } -_EsInstanceCreate :: #force_inline proc "c" (bytes_ : int , message_ : ^Message, cName_ : cstring ) -> ^Instance{ addr := 0x1000 + 11 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , ^Message, cstring ) -> ^Instance) (fp))(bytes_, message_, cName_); } -_EsSyscall :: #force_inline proc "c" (a_ : uint , b_ : uint , c_ : uint , d_ : uint , e_ : uint , f_ : uint ) -> uint { addr := 0x1000 + 12 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( uint , uint , uint , uint , uint , uint ) -> uint ) (fp))(a_, b_, c_, d_, e_, f_); } -ApplicationStart :: #force_inline proc "c" (information_ : ^ApplicationStartupInformation){ addr := 0x1000 + 124 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ApplicationStartupInformation)) (fp))(information_); } -SystemConfigurationReadAll :: #force_inline proc "c" (groupCount_ : ^int ) -> ^SystemConfigurationGroup{ addr := 0x1000 + 164 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^int ) -> ^SystemConfigurationGroup) (fp))(groupCount_); } -SystemConfigurationReadInteger :: #force_inline proc "c" (section_ : string, key_ : string, defaultValue_ : i64 = 0) -> i64 { addr := 0x1000 + 295 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int, i64 ) -> i64 ) (fp))(raw_data(section_), len(section_), raw_data(key_), len(key_), defaultValue_); } -SystemConfigurationGroupReadInteger :: #force_inline proc "c" (group_ : ^SystemConfigurationGroup, key_ : string, defaultValue_ : i64 = 0) -> i64 { addr := 0x1000 + 296 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^SystemConfigurationGroup, ^u8, int, i64 ) -> i64 ) (fp))(group_, raw_data(key_), len(key_), defaultValue_); } -SystemConfigurationReadString :: #force_inline proc "c" (section_ : string, key_ : string, valueBytes_ : ^int = nil) -> ^i8 { addr := 0x1000 + 297 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int, ^int ) -> ^i8 ) (fp))(raw_data(section_), len(section_), raw_data(key_), len(key_), valueBytes_); } -SystemConfigurationGroupReadString :: #force_inline proc "c" (group_ : ^SystemConfigurationGroup, key_ : string, valueBytes_ : ^int = nil) -> ^i8 { addr := 0x1000 + 298 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^SystemConfigurationGroup, ^u8, int, ^int ) -> ^i8 ) (fp))(group_, raw_data(key_), len(key_), valueBytes_); } -INIParse :: #force_inline proc "c" (s_ : ^INIState) -> bool{ addr := 0x1000 + 7 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^INIState) -> bool) (fp))(s_); } -INIPeek :: #force_inline proc "c" (s_ : ^INIState) -> bool{ addr := 0x1000 + 87 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^INIState) -> bool) (fp))(s_); } -INIFormat :: #force_inline proc "c" (s_ : ^INIState, buffer_ : ^i8 , bytes_ : int ) -> int { addr := 0x1000 + 125 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^INIState, ^i8 , int ) -> int ) (fp))(s_, buffer_, bytes_); } -INIZeroTerminate :: #force_inline proc "c" (s_ : ^INIState){ addr := 0x1000 + 126 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^INIState)) (fp))(s_); } -CommandAddButton :: #force_inline proc "c" (command_ : ^Command, button_ : ^Button){ addr := 0x1000 + 13 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Command, ^Button)) (fp))(command_, button_); } -CommandByID :: #force_inline proc "c" (instance_ : ^Instance, stableID_ : u32 ) -> ^Command{ addr := 0x1000 + 14 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Instance, u32 ) -> ^Command) (fp))(instance_, stableID_); } -CommandRegister :: #force_inline proc "c" (command_ : ^Command, instance_ : ^Instance, callback_ : CommandCallbackFunction, stableID_ : u32 , cDefaultKeyboardShortcut_ : cstring = nil, enabled_ : bool = false) -> ^Command{ addr := 0x1000 + 15 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Command, ^Instance, CommandCallbackFunction, u32 , cstring , bool) -> ^Command) (fp))(command_, instance_, callback_, stableID_, cDefaultKeyboardShortcut_, enabled_); } -CommandSetCallback :: #force_inline proc "c" (command_ : ^Command, callback_ : CommandCallbackFunction){ addr := 0x1000 + 16 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Command, CommandCallbackFunction)) (fp))(command_, callback_); } -CommandSetDisabled :: #force_inline proc "c" (command_ : ^Command, disabled_ : bool){ addr := 0x1000 + 17 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Command, bool)) (fp))(command_, disabled_); } -DialogClose :: #force_inline proc "c" (window_ : ^Window){ addr := 0x1000 + 18 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Window)) (fp))(window_); } -DialogShow :: #force_inline proc "c" (window_ : ^Window) -> ^Element{ addr := 0x1000 + 19 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Window) -> ^Element) (fp))(window_); } -DialogShowAlert :: #force_inline proc "c" (window_ : ^Window, title_ : string, content_ : string, iconID_ : u32 , addOKButton_ : bool = false) -> ^Element{ addr := 0x1000 + 20 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Window, ^u8, int, ^u8, int, u32 , bool) -> ^Element) (fp))(window_, raw_data(title_), len(title_), raw_data(content_), len(content_), iconID_, addOKButton_); } -InstanceDestroy :: #force_inline proc "c" (instance_ : ^INSTANCE_TYPE){ addr := 0x1000 + 300 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^INSTANCE_TYPE)) (fp))(instance_); } -KeyboardIsAltHeld :: #force_inline proc "c" () -> bool{ addr := 0x1000 + 21 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> bool) (fp))(); } -KeyboardIsCtrlHeld :: #force_inline proc "c" () -> bool{ addr := 0x1000 + 22 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> bool) (fp))(); } -KeyboardIsShiftHeld :: #force_inline proc "c" () -> bool{ addr := 0x1000 + 23 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> bool) (fp))(); } -MessageGetInputText :: #force_inline proc "c" (message_ : ^Message, buffer_ : ^i8 ) -> int { addr := 0x1000 + 24 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Message, ^i8 ) -> int ) (fp))(message_, buffer_); } -MessageMutexAcquire :: #force_inline proc "c" (){ addr := 0x1000 + 26 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))(); } -MessageMutexCheck :: #force_inline proc "c" (){ addr := 0x1000 + 27 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))(); } -MessageMutexRelease :: #force_inline proc "c" (){ addr := 0x1000 + 28 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))(); } -MessagePost :: #force_inline proc "c" (target_ : ^Element, message_ : ^Message) -> Error{ addr := 0x1000 + 29 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, ^Message) -> Error) (fp))(target_, message_); } -MessagePostRemote :: #force_inline proc "c" (process_ : Handle, message_ : ^Message) -> Error{ addr := 0x1000 + 30 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, ^Message) -> Error) (fp))(process_, message_); } -MessageSend :: #force_inline proc "c" (object_ : ^Element, message_ : ^Message) -> Response{ addr := 0x1000 + 31 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, ^Message) -> Response) (fp))(object_, message_); } -MessageReceive :: #force_inline proc "c" () -> ^Message{ addr := 0x1000 + 318 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> ^Message) (fp))(); } -MouseGetPosition :: #force_inline proc "c" (relativeElement_ : ^Element = nil) -> Point{ addr := 0x1000 + 32 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> Point) (fp))(relativeElement_); } -MouseSetPosition :: #force_inline proc "c" (relativeWindow_ : ^Window, x_ : i32, y_ : i32){ addr := 0x1000 + 33 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Window, i32, i32)) (fp))(relativeWindow_, x_, y_); } -StyleInheritRegister :: #force_inline proc "c" (cStyle_ : cstring , cParent_ : cstring , customMetrics_ : ^ThemeMetrics){ addr := 0x1000 + 239 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( cstring , cstring , ^ThemeMetrics)) (fp))(cStyle_, cParent_, customMetrics_); } -StyleRefreshAll :: #force_inline proc "c" (window_ : ^Element){ addr := 0x1000 + 37 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element)) (fp))(window_); } -UISetDPI :: #force_inline proc "c" (dpiScale_ : i32){ addr := 0x1000 + 38 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( i32)) (fp))(dpiScale_); } -DirectoryEnumerateChildren :: #force_inline proc "c" (path_ : string, buffer_ : ^^DirectoryChild) -> int { addr := 0x1000 + 39 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^^DirectoryChild) -> int ) (fp))(raw_data(path_), len(path_), buffer_); } -DirectoryEnumerateChildrenFromHandle :: #force_inline proc "c" (directory_ : Handle, buffer_ : ^DirectoryChild, bufferCount_ : int ) -> int { addr := 0x1000 + 40 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, ^DirectoryChild, int ) -> int ) (fp))(directory_, buffer_, bufferCount_); } -DirectoryMonitorCreate :: #force_inline proc "c" (path_ : string, flags_ : u32 , callback_ : DirectoryMonitorCallbackFunction, _context_ : Generic) -> ^DirectoryMonitor{ addr := 0x1000 + 41 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, u32 , DirectoryMonitorCallbackFunction, Generic) -> ^DirectoryMonitor) (fp))(raw_data(path_), len(path_), flags_, callback_, _context_); } -DirectoryMonitorCreateFromHandle :: #force_inline proc "c" (directory_ : Handle, flags_ : u32 , callback_ : DirectoryMonitorCallbackFunction, _context_ : Generic) -> ^DirectoryMonitor{ addr := 0x1000 + 42 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, u32 , DirectoryMonitorCallbackFunction, Generic) -> ^DirectoryMonitor) (fp))(directory_, flags_, callback_, _context_); } -DirectoryMonitorDestroy :: #force_inline proc "c" (monitor_ : ^DirectoryMonitor){ addr := 0x1000 + 43 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^DirectoryMonitor)) (fp))(monitor_); } -FileControl :: #force_inline proc "c" (file_ : Handle, flags_ : u32 ) -> Error{ addr := 0x1000 + 96 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, u32 ) -> Error) (fp))(file_, flags_); } -FileReadAll :: #force_inline proc "c" (filePath_ : string, fileSize_ : ^int ) -> rawptr{ addr := 0x1000 + 44 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^int ) -> rawptr) (fp))(raw_data(filePath_), len(filePath_), fileSize_); } -FileReadSync :: #force_inline proc "c" (file_ : Handle, offset_ : FileOffset, size_ : int , buffer_ : rawptr) -> int { addr := 0x1000 + 45 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, FileOffset, int , rawptr) -> int ) (fp))(file_, offset_, size_, buffer_); } -FileResize :: #force_inline proc "c" (file_ : Handle, newSize_ : FileOffset) -> Error{ addr := 0x1000 + 46 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, FileOffset) -> Error) (fp))(file_, newSize_); } -FileWriteAll :: #force_inline proc "c" (filePath_ : string, data_ : rawptr, fileSize_ : int ) -> Error{ addr := 0x1000 + 47 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, rawptr, int ) -> Error) (fp))(raw_data(filePath_), len(filePath_), data_, fileSize_); } -FileWriteAllGather :: #force_inline proc "c" (filePath_ : string, data_ : ^rawptr, fileSize_ : ^int , gatherCount_ : int ) -> Error{ addr := 0x1000 + 48 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^rawptr, ^int , int ) -> Error) (fp))(raw_data(filePath_), len(filePath_), data_, fileSize_, gatherCount_); } -FileWriteSync :: #force_inline proc "c" (file_ : Handle, offset_ : FileOffset, size_ : int , buffer_ : rawptr) -> int { addr := 0x1000 + 50 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, FileOffset, int , rawptr) -> int ) (fp))(file_, offset_, size_, buffer_); } -NodeDelete :: #force_inline proc "c" (node_ : Handle) -> Error{ addr := 0x1000 + 51 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> Error) (fp))(node_); } -NodeDeleteByPath :: #force_inline proc "c" (filePath_ : string) -> Error{ addr := 0x1000 + 52 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> Error) (fp))(raw_data(filePath_), len(filePath_)); } -NodeFindUniqueName :: #force_inline proc "c" (buffer_ : ^i8 , originalBytes_ : int , bufferBytes_ : int ) -> int { addr := 0x1000 + 53 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , int ) -> int ) (fp))(buffer_, originalBytes_, bufferBytes_); } -NodeMove :: #force_inline proc "c" (node_ : Handle, newDirectory_ : Handle, newName_ : string) -> Error{ addr := 0x1000 + 54 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, Handle, ^u8, int) -> Error) (fp))(node_, newDirectory_, raw_data(newName_), len(newName_)); } -NodeOpen :: #force_inline proc "c" (path_ : string, flags_ : u32 , information_ : ^NodeInformation) -> Error{ addr := 0x1000 + 55 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, u32 , ^NodeInformation) -> Error) (fp))(raw_data(path_), len(path_), flags_, information_); } -NodeOpenRelative :: #force_inline proc "c" (directory_ : Handle, path_ : string, flags_ : u32 , information_ : ^NodeInformation) -> Error{ addr := 0x1000 + 56 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, ^u8, int, u32 , ^NodeInformation) -> Error) (fp))(directory_, raw_data(path_), len(path_), flags_, information_); } -NodeRefreshInformation :: #force_inline proc "c" (information_ : ^NodeInformation){ addr := 0x1000 + 57 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^NodeInformation)) (fp))(information_); } -ProcessCrash :: #force_inline proc "c" (error_ : Error, message_ : string){ addr := 0x1000 + 58 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Error, ^u8, int)) (fp))(error_, raw_data(message_), len(message_)); } -ProcessCreate :: #force_inline proc "c" (executablePath_ : string, information_ : ^ProcessInformation, argument_ : Generic) -> Error{ addr := 0x1000 + 59 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^ProcessInformation, Generic) -> Error) (fp))(raw_data(executablePath_), len(executablePath_), information_, argument_); } -ProcessCreate2 :: #force_inline proc "c" (arguments_ : ^ProcessCreationArguments, information_ : ^ProcessInformation) -> Error{ addr := 0x1000 + 60 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^ProcessCreationArguments, ^ProcessInformation) -> Error) (fp))(arguments_, information_); } -ProcessGetExitStatus :: #force_inline proc "c" (process_ : Handle) -> i32{ addr := 0x1000 + 61 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> i32) (fp))(process_); } -ProcessGetID :: #force_inline proc "c" (process_ : Handle) -> uint { addr := 0x1000 + 62 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> uint ) (fp))(process_); } -ProcessGetState :: #force_inline proc "c" (process_ : Handle, state_ : ^ProcessState){ addr := 0x1000 + 63 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, ^ProcessState)) (fp))(process_, state_); } -ProcessOpen :: #force_inline proc "c" (pid_ : u64 ) -> Handle{ addr := 0x1000 + 64 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( u64 ) -> Handle) (fp))(pid_); } -ProcessPause :: #force_inline proc "c" (process_ : Handle, resume_ : bool){ addr := 0x1000 + 65 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, bool)) (fp))(process_, resume_); } -ProcessTerminate :: #force_inline proc "c" (process_ : Handle, status_ : i32){ addr := 0x1000 + 66 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, i32)) (fp))(process_, status_); } -ProcessTerminateCurrent :: #force_inline proc "c" (){ addr := 0x1000 + 67 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))(); } -ThreadCreate :: #force_inline proc "c" (entryFunction_ : ThreadEntryFunction, information_ : ^ThreadInformation, argument_ : Generic) -> Error{ addr := 0x1000 + 68 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ThreadEntryFunction, ^ThreadInformation, Generic) -> Error) (fp))(entryFunction_, information_, argument_); } -ThreadGetID :: #force_inline proc "c" (thread_ : Handle) -> uint { addr := 0x1000 + 69 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> uint ) (fp))(thread_); } -ThreadTerminate :: #force_inline proc "c" (thread_ : Handle){ addr := 0x1000 + 71 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle)) (fp))(thread_); } -ArenaAllocate :: #force_inline proc "c" (arena_ : ^Arena, zero_ : bool) -> rawptr{ addr := 0x1000 + 72 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Arena, bool) -> rawptr) (fp))(arena_, zero_); } -ArenaFree :: #force_inline proc "c" (arena_ : ^Arena, pointer_ : rawptr){ addr := 0x1000 + 73 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Arena, rawptr)) (fp))(arena_, pointer_); } -ArenaInitialise :: #force_inline proc "c" (arena_ : ^Arena, blockSize_ : int , itemSize_ : int ){ addr := 0x1000 + 74 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Arena, int , int )) (fp))(arena_, blockSize_, itemSize_); } -ConstantBufferCreate :: #force_inline proc "c" (data_ : rawptr, dataBytes_ : int , targetProcess_ : Handle) -> Handle{ addr := 0x1000 + 75 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int , Handle) -> Handle) (fp))(data_, dataBytes_, targetProcess_); } -ConstantBufferRead :: #force_inline proc "c" (constantBuffer_ : Handle, output_ : rawptr){ addr := 0x1000 + 76 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, rawptr)) (fp))(constantBuffer_, output_); } -ConstantBufferShare :: #force_inline proc "c" (constantBuffer_ : Handle, targetProcess_ : Handle) -> Handle{ addr := 0x1000 + 77 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, Handle) -> Handle) (fp))(constantBuffer_, targetProcess_); } -HeapAllocate :: #force_inline proc "c" (size_ : int , zeroMemory_ : bool) -> rawptr{ addr := 0x1000 + 78 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , bool) -> rawptr) (fp))(size_, zeroMemory_); } -HeapFree :: #force_inline proc "c" (address_ : rawptr){ addr := 0x1000 + 79 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr)) (fp))(address_); } -HeapReallocate :: #force_inline proc "c" (oldAddress_ : rawptr, newAllocationSize_ : int , zeroNewSpace_ : bool) -> rawptr{ addr := 0x1000 + 80 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int , bool) -> rawptr) (fp))(oldAddress_, newAllocationSize_, zeroNewSpace_); } -HeapValidate :: #force_inline proc "c" (){ addr := 0x1000 + 81 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))(); } -MemoryCommit :: #force_inline proc "c" (pointer_ : rawptr, bytes_ : int ) -> bool{ addr := 0x1000 + 82 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int ) -> bool) (fp))(pointer_, bytes_); } -MemoryCompare :: #force_inline proc "c" (a_ : rawptr, b_ : rawptr, bytes_ : int ) -> i32{ addr := 0x1000 + 83 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, rawptr, int ) -> i32) (fp))(a_, b_, bytes_); } -MemoryCopy :: #force_inline proc "c" (destination_ : rawptr, source_ : rawptr, bytes_ : int ){ addr := 0x1000 + 84 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, int )) (fp))(destination_, source_, bytes_); } -MemoryCopyReverse :: #force_inline proc "c" (_destination_ : rawptr, _source_ : rawptr, bytes_ : int ){ addr := 0x1000 + 85 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, int )) (fp))(_destination_, _source_, bytes_); } -MemoryDecommit :: #force_inline proc "c" (pointer_ : rawptr, bytes_ : int ) -> bool{ addr := 0x1000 + 320 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int ) -> bool) (fp))(pointer_, bytes_); } -MemoryFill :: #force_inline proc "c" (from_ : rawptr, to_ : rawptr, byte_ : u8 ){ addr := 0x1000 + 86 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, u8 )) (fp))(from_, to_, byte_); } -MemoryMove :: #force_inline proc "c" (_start_ : rawptr, _end_ : rawptr, amount_ : int , zeroEmptySpace_ : bool){ addr := 0x1000 + 88 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, int , bool)) (fp))(_start_, _end_, amount_, zeroEmptySpace_); } -MemoryOpen :: #force_inline proc "c" (size_ : int , name_ : string, flags_ : u32 ) -> Handle{ addr := 0x1000 + 89 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , ^u8, int, u32 ) -> Handle) (fp))(size_, raw_data(name_), len(name_), flags_); } -MemoryReserve :: #force_inline proc "c" (size_ : int , protection_ : MemoryProtection = MEMORY_PROTECTION_READ_WRITE, commitAll_ : bool = true) -> rawptr{ addr := 0x1000 + 25 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , MemoryProtection, bool) -> rawptr) (fp))(size_, protection_, commitAll_); } -MemoryShare :: #force_inline proc "c" (sharedMemoryRegion_ : Handle, targetProcess_ : Handle, readOnly_ : bool) -> Handle{ addr := 0x1000 + 90 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, Handle, bool) -> Handle) (fp))(sharedMemoryRegion_, targetProcess_, readOnly_); } -MemorySumBytes :: #force_inline proc "c" (data_ : ^u8 , bytes_ : int ) -> u8 { addr := 0x1000 + 91 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^u8 , int ) -> u8 ) (fp))(data_, bytes_); } -MemoryUnreserve :: #force_inline proc "c" (pointer_ : rawptr, size_ : int = 0){ addr := 0x1000 + 319 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int )) (fp))(pointer_, size_); } -MemoryZero :: #force_inline proc "c" (destination_ : rawptr, bytes_ : int ){ addr := 0x1000 + 92 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int )) (fp))(destination_, bytes_); } -ObjectMap :: #force_inline proc "c" (object_ : Handle, offset_ : uint , size_ : int , flags_ : u32 ) -> rawptr{ addr := 0x1000 + 93 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, uint , int , u32 ) -> rawptr) (fp))(object_, offset_, size_, flags_); } -AssertionFailure :: #force_inline proc "c" (cFile_ : cstring , line_ : i32){ addr := 0x1000 + 94 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( cstring , i32)) (fp))(cFile_, line_); } -DoubleParse :: #force_inline proc "c" (string_ : string, endptr_ : ^^i8 ) -> f64 { addr := 0x1000 + 97 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^^i8 ) -> f64 ) (fp))(raw_data(string_), len(string_), endptr_); } -ExtractArguments :: #force_inline proc "c" (string_ : ^i8 , bytes_ : int , delimiterByte_ : u8 , replacementDelimiter_ : u8 , argvAllocated_ : int , argv_ : ^^i8 , argc_ : ^int ) -> bool{ addr := 0x1000 + 98 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , u8 , u8 , int , ^^i8 , ^int ) -> bool) (fp))(string_, bytes_, delimiterByte_, replacementDelimiter_, argvAllocated_, argv_, argc_); } -RandomU8 :: #force_inline proc "c" () -> u8 { addr := 0x1000 + 301 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> u8 ) (fp))(); } -RandomU64 :: #force_inline proc "c" () -> u64 { addr := 0x1000 + 302 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> u64 ) (fp))(); } -IntegerParse :: #force_inline proc "c" (text_ : string) -> i64 { addr := 0x1000 + 101 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> i64 ) (fp))(raw_data(text_), len(text_)); } -Print :: #force_inline proc "c" (format_ : cstring , _varargs_ : ..any){ addr := 0x1000 + 102 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( cstring , ..any)) (fp))(format_, _varargs_); } -PrintDirect :: #force_inline proc "c" (string_ : string){ addr := 0x1000 + 103 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" (^u8, int)) (fp))(raw_data(string_), len(string_)); } -PrintHelloWorld :: #force_inline proc "c" (){ addr := 0x1000 + 104 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))(); } -RandomAddEntropy :: #force_inline proc "c" (x_ : u64 ){ addr := 0x1000 + 106 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( u64 )) (fp))(x_); } -RandomSeed :: #force_inline proc "c" (x_ : u64 ){ addr := 0x1000 + 107 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( u64 )) (fp))(x_); } -RectangleClip :: #force_inline proc "c" (parent_ : Rectangle, rectangle_ : Rectangle, output_ : ^Rectangle) -> bool{ addr := 0x1000 + 108 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Rectangle, Rectangle, ^Rectangle) -> bool) (fp))(parent_, rectangle_, output_); } -Sort :: #force_inline proc "c" (_base_ : rawptr, nmemb_ : int , size_ : int , compar_ : ComparisonCallbackFunction, argument_ : Generic){ addr := 0x1000 + 109 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int , int , ComparisonCallbackFunction, Generic)) (fp))(_base_, nmemb_, size_, compar_, argument_); } -SortWithSwapCallback :: #force_inline proc "c" (_base_ : rawptr, nmemb_ : int , size_ : int , compar_ : ComparisonCallbackFunction, argument_ : Generic, swap_ : SwapCallbackFunction){ addr := 0x1000 + 110 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int , int , ComparisonCallbackFunction, Generic, SwapCallbackFunction)) (fp))(_base_, nmemb_, size_, compar_, argument_, swap_); } -TimeStamp :: #force_inline proc "c" () -> u64 { addr := 0x1000 + 252 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> u64 ) (fp))(); } -TimeStampMs :: #force_inline proc "c" () -> f64 { addr := 0x1000 + 261 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> f64 ) (fp))(); } -ColorBlend :: #force_inline proc "c" (under_ : u32 , over_ : u32 , fullAlpha_ : bool) -> u32 { addr := 0x1000 + 111 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( u32 , u32 , bool) -> u32 ) (fp))(under_, over_, fullAlpha_); } -ColorConvertToRGB :: #force_inline proc "c" (h_ : f32 , s_ : f32 , v_ : f32 ) -> u32 { addr := 0x1000 + 112 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 , f32 , f32 ) -> u32 ) (fp))(h_, s_, v_); } -ColorConvertToHSV :: #force_inline proc "c" (color_ : u32 , h_ : ^f32 , s_ : ^f32 , v_ : ^f32 ) -> bool{ addr := 0x1000 + 113 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( u32 , ^f32 , ^f32 , ^f32 ) -> bool) (fp))(color_, h_, s_, v_); } -ColorParse :: #force_inline proc "c" (string_ : string) -> u32 { addr := 0x1000 + 114 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> u32 ) (fp))(raw_data(string_), len(string_)); } -DrawBitmap :: #force_inline proc "c" (painter_ : ^Painter, region_ : Rectangle, bits_ : ^u32 , stride_ : uint ){ addr := 0x1000 + 324 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, Rectangle, ^u32 , uint )) (fp))(painter_, region_, bits_, stride_); } -DrawInvert :: #force_inline proc "c" (painter_ : ^Painter, bounds_ : Rectangle){ addr := 0x1000 + 95 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, Rectangle)) (fp))(painter_, bounds_); } -DrawStandardIcon :: #force_inline proc "c" (painter_ : ^Painter, id_ : u32 , size_ : i32, region_ : Rectangle, color_ : u32 ) -> bool{ addr := 0x1000 + 115 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Painter, u32 , i32, Rectangle, u32 ) -> bool) (fp))(painter_, id_, size_, region_, color_); } -DrawStyledBox :: #force_inline proc "c" (painter_ : ^Painter, box_ : StyledBox){ addr := 0x1000 + 116 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, StyledBox)) (fp))(painter_, box_); } -DrawPaintTarget :: #force_inline proc "c" (painter_ : ^Painter, source_ : ^PaintTarget, destinationRegion_ : Rectangle, sourceRegion_ : Rectangle, borderRegion_ : Rectangle, mode_ : DrawMode, alpha_ : u16 , clipRegion_ : Rectangle){ addr := 0x1000 + 263 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, ^PaintTarget, Rectangle, Rectangle, Rectangle, DrawMode, u16 , Rectangle)) (fp))(painter_, source_, destinationRegion_, sourceRegion_, borderRegion_, mode_, alpha_, clipRegion_); } -DrawText :: #force_inline proc "c" (painter_ : ^Painter, plan_ : ^TextPlan, bounds_ : Rectangle, clip_ : ^Rectangle = nil, selectionProperties_ : ^TextSelection = nil){ addr := 0x1000 + 120 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, ^TextPlan, Rectangle, ^Rectangle, ^TextSelection)) (fp))(painter_, plan_, bounds_, clip_, selectionProperties_); } -FontGetName :: #force_inline proc "c" (family_ : u16 , buffer_ : ^i8 , bufferBytes_ : int ) -> int { addr := 0x1000 + 121 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( u16 , ^i8 , int ) -> int ) (fp))(family_, buffer_, bufferBytes_); } -IconIDFromString :: #force_inline proc "c" (string_ : string = "") -> u32 { addr := 0x1000 + 127 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> u32 ) (fp))(raw_data(string_), len(string_)); } -ImageLoad :: #force_inline proc "c" (file_ : ^u8 , fileSize_ : int , width_ : ^u32 , height_ : ^u32 , imageChannels_ : i32) -> ^u8 { addr := 0x1000 + 165 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^u8 , int , ^u32 , ^u32 , i32) -> ^u8 ) (fp))(file_, fileSize_, width_, height_, imageChannels_); } -PainterBoundsClient :: #force_inline proc "c" (painter_ : ^Painter) -> Rectangle{ addr := 0x1000 + 122 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Painter) -> Rectangle) (fp))(painter_); } -PainterBoundsInset :: #force_inline proc "c" (painter_ : ^Painter) -> Rectangle{ addr := 0x1000 + 123 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Painter) -> Rectangle) (fp))(painter_); } -PainterDrawStandardContent :: #force_inline proc "c" (painter_ : ^Painter, text_ : string, iconID_ : u32 ){ addr := 0x1000 + 117 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, ^u8, int, u32 )) (fp))(painter_, raw_data(text_), len(text_), iconID_); } -PaintTargetClear :: #force_inline proc "c" (target_ : ^PaintTarget){ addr := 0x1000 + 34 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^PaintTarget)) (fp))(target_); } -PaintTargetEndDirectAccess :: #force_inline proc "c" (target_ : ^PaintTarget){ addr := 0x1000 + 264 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^PaintTarget)) (fp))(target_); } -PaintTargetStartDirectAccess :: #force_inline proc "c" (target_ : ^PaintTarget, bits_ : ^^u32 , width_ : ^int , height_ : ^int , stride_ : ^int ){ addr := 0x1000 + 276 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^PaintTarget, ^^u32 , ^int , ^int , ^int )) (fp))(target_, bits_, width_, height_, stride_); } -PaintTargetTake :: #force_inline proc "c" (target_ : ^PaintTarget, width_ : int , height_ : int ) -> bool{ addr := 0x1000 + 35 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^PaintTarget, int , int ) -> bool) (fp))(target_, width_, height_); } -PaintTargetReturn :: #force_inline proc "c" (target_ : ^PaintTarget){ addr := 0x1000 + 36 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^PaintTarget)) (fp))(target_); } -TextGetLineHeight :: #force_inline proc "c" (font_ : Font, size_ : u16 ) -> i32{ addr := 0x1000 + 157 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Font, u16 ) -> i32) (fp))(font_, size_); } -TextGetPartialStringWidth :: #force_inline proc "c" (font_ : Font, size_ : u16 , fullString_ : ^i8 , fullStringBytes_ : int , measureOffset_ : uint , measureBytes_ : int ) -> i32{ addr := 0x1000 + 171 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Font, u16 , ^i8 , int , uint , int ) -> i32) (fp))(font_, size_, fullString_, fullStringBytes_, measureOffset_, measureBytes_); } -TextGetCharacterAtPoint :: #force_inline proc "c" (font_ : Font, size_ : u16 , fullString_ : ^i8 , fullStringBytes_ : int , measureOffset_ : uint , measureBytes_ : int , pointX_ : ^i32, reverse_ : bool, middle_ : bool) -> int { addr := 0x1000 + 237 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Font, u16 , ^i8 , int , uint , int , ^i32, bool, bool) -> int ) (fp))(font_, size_, fullString_, fullStringBytes_, measureOffset_, measureBytes_, pointX_, reverse_, middle_); } -AudioStreamClose :: #force_inline proc "c" (stream_ : ^AudioStream){ addr := 0x1000 + 128 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^AudioStream)) (fp))(stream_); } -AudioStreamOpen :: #force_inline proc "c" (device_ : AudioDeviceID, bufferLengthUs_ : int ) -> ^AudioStream{ addr := 0x1000 + 129 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( AudioDeviceID, int ) -> ^AudioStream) (fp))(device_, bufferLengthUs_); } -AudioStreamNotify :: #force_inline proc "c" (stream_ : ^AudioStream){ addr := 0x1000 + 130 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^AudioStream)) (fp))(stream_); } -AudioStreamSend :: #force_inline proc "c" (destination_ : ^AudioStream, source_ : ^AudioStream, time_ : ^f64 ) -> Error{ addr := 0x1000 + 131 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^AudioStream, ^AudioStream, ^f64 ) -> Error) (fp))(destination_, source_, time_); } -AddressResolve :: #force_inline proc "c" (domain_ : string, flags_ : u32 , address_ : ^Address) -> Error{ addr := 0x1000 + 99 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, u32 , ^Address) -> Error) (fp))(raw_data(domain_), len(domain_), flags_, address_); } -ConnectionClose :: #force_inline proc "c" (connection_ : ^Connection){ addr := 0x1000 + 321 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Connection)) (fp))(connection_); } -ConnectionNotify :: #force_inline proc "c" (connection_ : ^Connection){ addr := 0x1000 + 322 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Connection)) (fp))(connection_); } -ConnectionOpen :: #force_inline proc "c" (connection_ : ^Connection, flags_ : u32 ) -> Error{ addr := 0x1000 + 100 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Connection, u32 ) -> Error) (fp))(connection_, flags_); } -ConnectionPoll :: #force_inline proc "c" (connection_ : ^Connection){ addr := 0x1000 + 303 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Connection)) (fp))(connection_); } -ConnectionRead :: #force_inline proc "c" (connection_ : ^Connection, buffer_ : rawptr, bufferBytes_ : int , bytesRead_ : ^int ) -> Error{ addr := 0x1000 + 325 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Connection, rawptr, int , ^int ) -> Error) (fp))(connection_, buffer_, bufferBytes_, bytesRead_); } -ConnectionWriteSync :: #force_inline proc "c" (connection_ : ^Connection, data_ : rawptr, dataBytes_ : int ) -> Error{ addr := 0x1000 + 323 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Connection, rawptr, int ) -> Error) (fp))(connection_, data_, dataBytes_); } -GameControllerStatePoll :: #force_inline proc "c" (buffer_ : ^GameControllerState) -> int { addr := 0x1000 + 299 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^GameControllerState) -> int ) (fp))(buffer_); } -EventCreate :: #force_inline proc "c" (autoReset_ : bool) -> Handle{ addr := 0x1000 + 132 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( bool) -> Handle) (fp))(autoReset_); } -EventForward :: #force_inline proc "c" (event_ : Handle, eventSink_ : Handle, data_ : Generic){ addr := 0x1000 + 133 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, Handle, Generic)) (fp))(event_, eventSink_, data_); } -EventPoll :: #force_inline proc "c" (event_ : Handle) -> Error{ addr := 0x1000 + 134 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> Error) (fp))(event_); } -EventReset :: #force_inline proc "c" (event_ : Handle){ addr := 0x1000 + 135 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle)) (fp))(event_); } -EventSet :: #force_inline proc "c" (event_ : Handle){ addr := 0x1000 + 136 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle)) (fp))(event_); } -EventSinkCreate :: #force_inline proc "c" (ignoreDuplicates_ : bool) -> Handle{ addr := 0x1000 + 137 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( bool) -> Handle) (fp))(ignoreDuplicates_); } -EventSinkPop :: #force_inline proc "c" (eventSink_ : Handle, data_ : ^Generic) -> Error{ addr := 0x1000 + 138 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, ^Generic) -> Error) (fp))(eventSink_, data_); } -EventSinkPush :: #force_inline proc "c" (eventSink_ : Handle, data_ : Generic) -> Error{ addr := 0x1000 + 139 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, Generic) -> Error) (fp))(eventSink_, data_); } -MutexAcquire :: #force_inline proc "c" (mutex_ : ^Mutex){ addr := 0x1000 + 140 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Mutex)) (fp))(mutex_); } -MutexDestroy :: #force_inline proc "c" (mutex_ : ^Mutex){ addr := 0x1000 + 141 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Mutex)) (fp))(mutex_); } -MutexRelease :: #force_inline proc "c" (mutex_ : ^Mutex){ addr := 0x1000 + 142 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Mutex)) (fp))(mutex_); } -PerformanceTimerPush :: #force_inline proc "c" (){ addr := 0x1000 + 143 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))(); } -PerformanceTimerPop :: #force_inline proc "c" () -> f64 { addr := 0x1000 + 144 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> f64 ) (fp))(); } -SchedulerYield :: #force_inline proc "c" (){ addr := 0x1000 + 145 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))(); } -Sleep :: #force_inline proc "c" (milliseconds_ : u64 ){ addr := 0x1000 + 146 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( u64 )) (fp))(milliseconds_); } -SpinlockAcquire :: #force_inline proc "c" (spinlock_ : ^Spinlock){ addr := 0x1000 + 147 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Spinlock)) (fp))(spinlock_); } -SpinlockRelease :: #force_inline proc "c" (spinlock_ : ^Spinlock){ addr := 0x1000 + 148 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Spinlock)) (fp))(spinlock_); } -TimerCreate :: #force_inline proc "c" () -> Handle{ addr := 0x1000 + 149 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> Handle) (fp))(); } -TimerSet :: #force_inline proc "c" (handle_ : Handle, afterMs_ : u64 , callback_ : TimerCallbackFunction, argument_ : Generic){ addr := 0x1000 + 150 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, u64 , TimerCallbackFunction, Generic)) (fp))(handle_, afterMs_, callback_, argument_); } -Wait :: #force_inline proc "c" (objects_ : ^Handle, objectCount_ : int , timeoutMs_ : uint ) -> uint { addr := 0x1000 + 151 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Handle, int , uint ) -> uint ) (fp))(objects_, objectCount_, timeoutMs_); } -CStringLength :: #force_inline proc "c" (string_ : cstring ) -> int { addr := 0x1000 + 152 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( cstring ) -> int ) (fp))(string_); } -StringAllocateAndFormat :: #force_inline proc "c" (bytes_ : ^int , format_ : cstring , _varargs_ : ..any) -> ^i8 { addr := 0x1000 + 153 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^int , cstring , ..any) -> ^i8 ) (fp))(bytes_, format_, _varargs_); } -StringCompare :: #force_inline proc "c" (s1_ : string, s2_ : string) -> i32{ addr := 0x1000 + 155 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int) -> i32) (fp))(raw_data(s1_), len(s1_), raw_data(s2_), len(s2_)); } -StringCompareRaw :: #force_inline proc "c" (s1_ : string, s2_ : string) -> i32{ addr := 0x1000 + 156 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int) -> i32) (fp))(raw_data(s1_), len(s1_), raw_data(s2_), len(s2_)); } -StringFormat :: #force_inline proc "c" (buffer_ : ^i8 , bufferLength_ : int , format_ : cstring , _varargs_ : ..any) -> int { addr := 0x1000 + 158 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , cstring , ..any) -> int ) (fp))(buffer_, bufferLength_, format_, _varargs_); } -StringFormatTemporary :: #force_inline proc "c" (format_ : cstring , _varargs_ : ..any) -> ^i8 { addr := 0x1000 + 159 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( cstring , ..any) -> ^i8 ) (fp))(format_, _varargs_); } -StringFormatAppend :: #force_inline proc "c" (buffer_ : ^i8 , bufferLength_ : int , bufferPosition_ : ^int , format_ : cstring , _varargs_ : ..any) -> bool{ addr := 0x1000 + 161 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , ^int , cstring , ..any) -> bool) (fp))(buffer_, bufferLength_, bufferPosition_, format_, _varargs_); } -StringLength :: #force_inline proc "c" (string_ : ^i8 , end_ : u8 ) -> int { addr := 0x1000 + 163 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , u8 ) -> int ) (fp))(string_, end_); } -StringStartsWith :: #force_inline proc "c" (string_ : string, prefix_ : string, caseInsensitive_ : bool) -> bool{ addr := 0x1000 + 166 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int, bool) -> bool) (fp))(raw_data(string_), len(string_), raw_data(prefix_), len(prefix_), caseInsensitive_); } -StringZeroTerminate :: #force_inline proc "c" (string_ : string) -> ^i8 { addr := 0x1000 + 167 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> ^i8 ) (fp))(raw_data(string_), len(string_)); } -CRTabs :: #force_inline proc "c" (n_ : i32) -> i32{ addr := 0x1000 + 168 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(n_); } -CRTacosf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 169 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTasinf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 170 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTatan2f :: #force_inline proc "c" (y_ : f32 , x_ : f32 ) -> f32 { addr := 0x1000 + 172 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 , f32 ) -> f32 ) (fp))(y_, x_); } -CRTatanf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 173 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTatoi :: #force_inline proc "c" (string_ : ^i8 ) -> i32{ addr := 0x1000 + 174 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 ) -> i32) (fp))(string_); } -CRTcalloc :: #force_inline proc "c" (num_ : int , size_ : int ) -> rawptr{ addr := 0x1000 + 175 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , int ) -> rawptr) (fp))(num_, size_); } -CRTceil :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 176 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_); } -CRTceilf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 177 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTcosf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 178 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTexp :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 326 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_); } -CRTexp2f :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 327 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTfabs :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 179 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_); } -CRTfabsf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 344 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTfloor :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 181 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_); } -CRTfloorf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 182 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTfmodf :: #force_inline proc "c" (x_ : f32 , y_ : f32 ) -> f32 { addr := 0x1000 + 183 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 , f32 ) -> f32 ) (fp))(x_, y_); } -CRTfree :: #force_inline proc "c" (ptr_ : rawptr){ addr := 0x1000 + 184 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr)) (fp))(ptr_); } -CRTgetenv :: #force_inline proc "c" (name_ : ^i8 ) -> ^i8 { addr := 0x1000 + 185 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 ) -> ^i8 ) (fp))(name_); } -CRTisalpha :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 186 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_); } -CRTisdigit :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 187 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_); } -CRTisnanf :: #force_inline proc "c" (f_ : f32 ) -> bool{ addr := 0x1000 + 345 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> bool) (fp))(f_); } -CRTisspace :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 188 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_); } -CRTisupper :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 189 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_); } -CRTisxdigit :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 190 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_); } -CRTmalloc :: #force_inline proc "c" (size_ : int ) -> rawptr{ addr := 0x1000 + 191 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int ) -> rawptr) (fp))(size_); } -CRTmemchr :: #force_inline proc "c" (_s_ : rawptr, _c_ : i32, n_ : int ) -> rawptr{ addr := 0x1000 + 192 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, i32, int ) -> rawptr) (fp))(_s_, _c_, n_); } -CRTmemcmp :: #force_inline proc "c" (s1_ : rawptr, s2_ : rawptr, n_ : int ) -> i32{ addr := 0x1000 + 193 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, rawptr, int ) -> i32) (fp))(s1_, s2_, n_); } -CRTmemcpy :: #force_inline proc "c" (dest_ : rawptr, src_ : rawptr, n_ : int ) -> rawptr{ addr := 0x1000 + 194 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, rawptr, int ) -> rawptr) (fp))(dest_, src_, n_); } -CRTmemmove :: #force_inline proc "c" (dest_ : rawptr, src_ : rawptr, n_ : int ) -> rawptr{ addr := 0x1000 + 195 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, rawptr, int ) -> rawptr) (fp))(dest_, src_, n_); } -CRTmemset :: #force_inline proc "c" (s_ : rawptr, c_ : i32, n_ : int ) -> rawptr{ addr := 0x1000 + 196 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, i32, int ) -> rawptr) (fp))(s_, c_, n_); } -CRTpowf :: #force_inline proc "c" (x_ : f32 , y_ : f32 ) -> f32 { addr := 0x1000 + 328 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 , f32 ) -> f32 ) (fp))(x_, y_); } -CRTqsort :: #force_inline proc "c" (_base_ : rawptr, nmemb_ : int , size_ : int , compar_ : CRTComparisonCallback){ addr := 0x1000 + 197 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int , int , CRTComparisonCallback)) (fp))(_base_, nmemb_, size_, compar_); } -CRTrealloc :: #force_inline proc "c" (ptr_ : rawptr, size_ : int ) -> rawptr{ addr := 0x1000 + 198 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int ) -> rawptr) (fp))(ptr_, size_); } -CRTsinf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 199 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTsnprintf :: #force_inline proc "c" (buffer_ : ^i8 , bufferSize_ : int , format_ : ^i8 , _varargs_ : ..any) -> i32{ addr := 0x1000 + 200 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , ^i8 , ..any) -> i32) (fp))(buffer_, bufferSize_, format_, _varargs_); } -CRTsprintf :: #force_inline proc "c" (buffer_ : ^i8 , format_ : ^i8 , _varargs_ : ..any) -> i32{ addr := 0x1000 + 201 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 , ..any) -> i32) (fp))(buffer_, format_, _varargs_); } -CRTsqrt :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 202 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_); } -CRTsqrtf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 203 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_); } -CRTstrcat :: #force_inline proc "c" (dest_ : ^i8 , src_ : ^i8 ) -> ^i8 { addr := 0x1000 + 205 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 ) -> ^i8 ) (fp))(dest_, src_); } -CRTstrchr :: #force_inline proc "c" (s_ : ^i8 , c_ : i32) -> ^i8 { addr := 0x1000 + 206 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , i32) -> ^i8 ) (fp))(s_, c_); } -CRTstrcmp :: #force_inline proc "c" (s1_ : ^i8 , s2_ : ^i8 ) -> i32{ addr := 0x1000 + 207 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 ) -> i32) (fp))(s1_, s2_); } -CRTstrcpy :: #force_inline proc "c" (dest_ : ^i8 , src_ : ^i8 ) -> ^i8 { addr := 0x1000 + 208 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 ) -> ^i8 ) (fp))(dest_, src_); } -CRTstrdup :: #force_inline proc "c" (string_ : ^i8 ) -> ^i8 { addr := 0x1000 + 70 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 ) -> ^i8 ) (fp))(string_); } -CRTstrerror :: #force_inline proc "c" (errnum_ : i32) -> ^i8 { addr := 0x1000 + 209 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> ^i8 ) (fp))(errnum_); } -CRTstrlen :: #force_inline proc "c" (s_ : ^i8 ) -> int { addr := 0x1000 + 210 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 ) -> int ) (fp))(s_); } -CRTstrncmp :: #force_inline proc "c" (s1_ : ^i8 , s2_ : ^i8 , n_ : int ) -> i32{ addr := 0x1000 + 211 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 , int ) -> i32) (fp))(s1_, s2_, n_); } -CRTstrncpy :: #force_inline proc "c" (dest_ : ^i8 , src_ : ^i8 , n_ : int ) -> ^i8 { addr := 0x1000 + 212 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 , int ) -> ^i8 ) (fp))(dest_, src_, n_); } -CRTstrnlen :: #force_inline proc "c" (s_ : ^i8 , maxlen_ : int ) -> int { addr := 0x1000 + 213 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int ) -> int ) (fp))(s_, maxlen_); } -CRTstrstr :: #force_inline proc "c" (haystack_ : ^i8 , needle_ : ^i8 ) -> ^i8 { addr := 0x1000 + 214 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 ) -> ^i8 ) (fp))(haystack_, needle_); } -CRTstrtol :: #force_inline proc "c" (nptr_ : ^i8 , endptr_ : ^^i8 , base_ : i32) -> i64 { addr := 0x1000 + 215 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^^i8 , i32) -> i64 ) (fp))(nptr_, endptr_, base_); } -CRTstrtoul :: #force_inline proc "c" (nptr_ : ^i8 , endptr_ : ^^i8 , base_ : i32) -> u64 { addr := 0x1000 + 216 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^^i8 , i32) -> u64 ) (fp))(nptr_, endptr_, base_); } -CRTtolower :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 217 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_); } -NewPanel :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Panel{ addr := 0x1000 + 219 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Panel) (fp))(parent_, flags_, cStyle_); } -NewSplitter :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Splitter{ addr := 0x1000 + 220 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Splitter) (fp))(parent_, flags_, cStyle_); } -NewButton :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, label_ : string = "") -> ^Button{ addr := 0x1000 + 221 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , ^u8, int) -> ^Button) (fp))(parent_, flags_, cStyle_, raw_data(label_), len(label_)); } -NewChoice :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Choice{ addr := 0x1000 + 222 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Choice) (fp))(parent_, flags_, cStyle_); } -NewColorWell :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, colorRGB_ : u32 = 0) -> ^ColorWell{ addr := 0x1000 + 223 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , u32 ) -> ^ColorWell) (fp))(parent_, flags_, cStyle_, colorRGB_); } -NewTextDisplay :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, label_ : string = "") -> ^TextDisplay{ addr := 0x1000 + 224 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , ^u8, int) -> ^TextDisplay) (fp))(parent_, flags_, cStyle_, raw_data(label_), len(label_)); } -NewIconDisplay :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, iconID_ : u32 = 0) -> ^IconDisplay{ addr := 0x1000 + 225 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , u32 ) -> ^IconDisplay) (fp))(parent_, flags_, cStyle_, iconID_); } -NewImageDisplay :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^ImageDisplay{ addr := 0x1000 + 226 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^ImageDisplay) (fp))(parent_, flags_, cStyle_); } -NewListView :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, cItemStyle_ : cstring = nil, cHeaderItemStyle_ : cstring = nil, cFooterItemStyle_ : cstring = nil) -> ^ListView{ addr := 0x1000 + 227 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , cstring , cstring , cstring ) -> ^ListView) (fp))(parent_, flags_, cStyle_, cItemStyle_, cHeaderItemStyle_, cFooterItemStyle_); } -NewTextbox :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Textbox{ addr := 0x1000 + 228 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Textbox) (fp))(parent_, flags_, cStyle_); } -NewCustomElement :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Element{ addr := 0x1000 + 229 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Element) (fp))(parent_, flags_, cStyle_); } -NewWindow :: #force_inline proc "c" (instance_ : ^INSTANCE_TYPE, style_ : WindowStyle) -> ^Window{ addr := 0x1000 + 230 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^INSTANCE_TYPE, WindowStyle) -> ^Window) (fp))(instance_, style_); } -NewMenu :: #force_inline proc "c" (source_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, userCallback_ : MenuCallbackFunction = nil, _context_ : Generic = nil, fixedWidth_ : i32 = 0, fixedHeight_ : i32 = 0) -> ^Menu{ addr := 0x1000 + 231 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , MenuCallbackFunction, Generic, i32, i32) -> ^Menu) (fp))(source_, flags_, userCallback_, _context_, fixedWidth_, fixedHeight_); } -NewMenuItem :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 , label_ : string = "", callback_ : MenuCallbackFunction = nil, _context_ : Generic = nil){ addr := 0x1000 + 232 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, u64 , ^u8, int, MenuCallbackFunction, Generic)) (fp))(parent_, flags_, raw_data(label_), len(label_), callback_, _context_); } -NewMenuCommand :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 , label_ : string, command_ : ^Command){ addr := 0x1000 + 233 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, u64 , ^u8, int, ^Command)) (fp))(parent_, flags_, raw_data(label_), len(label_), command_); } -NewMenuColumn :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT) -> ^Element{ addr := 0x1000 + 234 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 ) -> ^Element) (fp))(parent_, flags_); } -NewMenuSeparator :: #force_inline proc "c" (parent_ : ^Element){ addr := 0x1000 + 235 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element)) (fp))(parent_); } -NewSpacer :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 ) -> ^Element{ addr := 0x1000 + 236 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 ) -> ^Element) (fp))(parent_, flags_); } -NewTextPlan :: #force_inline proc "c" (properties_ : ^TextDisplayProperties, bounds_ : Rectangle, string_ : ^i8 , textRuns_ : ^TextRun, textRunCount_ : int , singleUse_ : bool) -> ^TextPlan{ addr := 0x1000 + 238 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^TextDisplayProperties, Rectangle, ^i8 , ^TextRun, int , bool) -> ^TextPlan) (fp))(properties_, bounds_, string_, textRuns_, textRunCount_, singleUse_); } -ElementDraw :: #force_inline proc "c" (element_ : ^Element, painter_ : ^Painter){ addr := 0x1000 + 240 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, ^Painter)) (fp))(element_, painter_); } -ElementFocus :: #force_inline proc "c" (element_ : ^Element, ensureVisible_ : bool = false){ addr := 0x1000 + 243 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, bool)) (fp))(element_, ensureVisible_); } -ElementSetDisabled :: #force_inline proc "c" (element_ : ^Element, disabled_ : bool = true){ addr := 0x1000 + 244 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, bool)) (fp))(element_, disabled_); } -ElementSetHidden :: #force_inline proc "c" (element_ : ^Element, hidden_ : bool = true){ addr := 0x1000 + 245 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, bool)) (fp))(element_, hidden_); } -ElementSetCallback :: #force_inline proc "c" (element_ : ^Element, callback_ : UICallbackFunction){ addr := 0x1000 + 246 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, UICallbackFunction)) (fp))(element_, callback_); } -ElementGetSize :: #force_inline proc "c" (element_ : ^Element, width_ : ^i32, height_ : ^i32){ addr := 0x1000 + 247 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, ^i32, ^i32)) (fp))(element_, width_, height_); } -ElementRepaint :: #force_inline proc "c" (element_ : ^Element, all_ : bool, region_ : Rectangle){ addr := 0x1000 + 248 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, bool, Rectangle)) (fp))(element_, all_, region_); } -ElementSetCellRange :: #force_inline proc "c" (element_ : ^Element, xFrom_ : i32, yFrom_ : i32, xTo_ : i32 = -1, yTo_ : i32 = -1){ addr := 0x1000 + 251 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, i32, i32, i32, i32)) (fp))(element_, xFrom_, yFrom_, xTo_, yTo_); } -ElementGetInsets :: #force_inline proc "c" (element_ : ^Element) -> Rectangle{ addr := 0x1000 + 253 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> Rectangle) (fp))(element_); } -ElementGetInsetSize :: #force_inline proc "c" (element_ : ^Element) -> Rectangle{ addr := 0x1000 + 254 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> Rectangle) (fp))(element_); } -ElementGetMetrics :: #force_inline proc "c" (element_ : ^Element) -> ThemeMetrics{ addr := 0x1000 + 105 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> ThemeMetrics) (fp))(element_); } -ElementGetPreferredSize :: #force_inline proc "c" (element_ : ^Element) -> Rectangle{ addr := 0x1000 + 255 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> Rectangle) (fp))(element_); } -ElementMove :: #force_inline proc "c" (element_ : ^Element, x_ : i32, y_ : i32, width_ : i32, height_ : i32){ addr := 0x1000 + 256 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, i32, i32, i32, i32)) (fp))(element_, x_, y_, width_, height_); } -ElementGetLayoutParent :: #force_inline proc "c" (element_ : ^Element) -> ^Element{ addr := 0x1000 + 257 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> ^Element) (fp))(element_); } -ElementDestroy :: #force_inline proc "c" (element_ : ^Element){ addr := 0x1000 + 258 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element)) (fp))(element_); } -ElementDestroyContents :: #force_inline proc "c" (element_ : ^Element){ addr := 0x1000 + 259 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element)) (fp))(element_); } -ElementStartAnimating :: #force_inline proc "c" (element_ : ^Element) -> bool{ addr := 0x1000 + 260 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> bool) (fp))(element_); } -WindowGetBounds :: #force_inline proc "c" (window_ : ^Window) -> Rectangle{ addr := 0x1000 + 265 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Window) -> Rectangle) (fp))(window_); } -WindowGetToolbar :: #force_inline proc "c" (window_ : ^Window) -> ^Element{ addr := 0x1000 + 266 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Window) -> ^Element) (fp))(window_); } -WindowSetIcon :: #force_inline proc "c" (window_ : ^Window, iconID_ : u32 ){ addr := 0x1000 + 267 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Window, u32 )) (fp))(window_, iconID_); } -WindowSetTitle :: #force_inline proc "c" (window_ : ^Window, title_ : string = ""){ addr := 0x1000 + 268 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Window, ^u8, int)) (fp))(window_, raw_data(title_), len(title_)); } -MenuGetSource :: #force_inline proc "c" (menu_ : ^Menu) -> ^Element{ addr := 0x1000 + 269 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Menu) -> ^Element) (fp))(menu_); } -ButtonSetIcon :: #force_inline proc "c" (button_ : ^Button, iconID_ : u32 ){ addr := 0x1000 + 270 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, u32 )) (fp))(button_, iconID_); } -ButtonSetCheck :: #force_inline proc "c" (button_ : ^Button, checkState_ : CheckState = CHECK_CHECKED, sendUpdatedMessage_ : bool = true){ addr := 0x1000 + 271 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, CheckState, bool)) (fp))(button_, checkState_, sendUpdatedMessage_); } -ButtonGetCheck :: #force_inline proc "c" (button_ : ^Button) -> CheckState{ addr := 0x1000 + 272 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Button) -> CheckState) (fp))(button_); } -ButtonOnCommand :: #force_inline proc "c" (button_ : ^Button, callback_ : CommandCallbackFunction, command_ : ^Command = nil){ addr := 0x1000 + 273 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, CommandCallbackFunction, ^Command)) (fp))(button_, callback_, command_); } -ButtonSetCheckBuddy :: #force_inline proc "c" (button_ : ^Button, checkBuddy_ : ^Element){ addr := 0x1000 + 274 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, ^Element)) (fp))(button_, checkBuddy_); } -ButtonGetCheckBuddy :: #force_inline proc "c" (button_ : ^Button) -> ^Element{ addr := 0x1000 + 275 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Button) -> ^Element) (fp))(button_); } -TextboxFind :: #force_inline proc "c" (textbox_ : ^Textbox, string_ : string, line_ : ^i32 , byte_ : ^i32 , flags_ : u32 ) -> bool{ addr := 0x1000 + 277 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Textbox, ^u8, int, ^i32 , ^i32 , u32 ) -> bool) (fp))(textbox_, raw_data(string_), len(string_), line_, byte_, flags_); } -TextboxInsert :: #force_inline proc "c" (textbox_ : ^Textbox, string_ : string = "", sendUpdatedMessage_ : bool = true){ addr := 0x1000 + 278 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, ^u8, int, bool)) (fp))(textbox_, raw_data(string_), len(string_), sendUpdatedMessage_); } -TextboxGetContents :: #force_inline proc "c" (textbox_ : ^Textbox, bytes_ : ^int = nil) -> ^i8 { addr := 0x1000 + 279 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Textbox, ^int ) -> ^i8 ) (fp))(textbox_, bytes_); } -TextboxGetLineLength :: #force_inline proc "c" (textbox_ : ^Textbox, line_ : uint = 0) -> int { addr := 0x1000 + 280 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Textbox, uint ) -> int ) (fp))(textbox_, line_); } -TextboxGetSelection :: #force_inline proc "c" (textbox_ : ^Textbox, fromLine_ : ^i32 , fromByte_ : ^i32 , toLine_ : ^i32 , toByte_ : ^i32 ){ addr := 0x1000 + 281 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, ^i32 , ^i32 , ^i32 , ^i32 )) (fp))(textbox_, fromLine_, fromByte_, toLine_, toByte_); } -TextboxMoveCaret :: #force_inline proc "c" (textbox_ : ^Textbox, line_ : i32 , byte_ : i32 ){ addr := 0x1000 + 282 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, i32 , i32 )) (fp))(textbox_, line_, byte_); } -TextboxSetSelection :: #force_inline proc "c" (textbox_ : ^Textbox, fromLine_ : i32 , fromByte_ : i32 , toLine_ : i32 , toByte_ : i32 ){ addr := 0x1000 + 283 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, i32 , i32 , i32 , i32 )) (fp))(textbox_, fromLine_, fromByte_, toLine_, toByte_); } -TextboxSelectAll :: #force_inline proc "c" (textbox_ : ^Textbox){ addr := 0x1000 + 284 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox)) (fp))(textbox_); } -TextboxClear :: #force_inline proc "c" (textbox_ : ^Textbox, sendUpdatedMessage_ : bool){ addr := 0x1000 + 285 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, bool)) (fp))(textbox_, sendUpdatedMessage_); } -TextboxUseNumberOverlay :: #force_inline proc "c" (textbox_ : ^Textbox, defaultBehaviour_ : bool){ addr := 0x1000 + 286 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, bool)) (fp))(textbox_, defaultBehaviour_); } -TextboxUseBreadcrumbOverlay :: #force_inline proc "c" (textbox_ : ^Textbox){ addr := 0x1000 + 287 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox)) (fp))(textbox_); } -TextboxMoveCaretRelative :: #force_inline proc "c" (textbox_ : ^Textbox, flags_ : u32 ){ addr := 0x1000 + 118 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, u32 )) (fp))(textbox_, flags_); } -TextboxEnsureCaretVisible :: #force_inline proc "c" (textbox_ : ^Textbox){ addr := 0x1000 + 119 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox)) (fp))(textbox_); } -PanelSetBands :: #force_inline proc "c" (panel_ : ^Panel, columnCount_ : int , rowCount_ : int = 0, columns_ : ^PanelBand = nil, rows_ : ^PanelBand = nil){ addr := 0x1000 + 288 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Panel, int , int , ^PanelBand, ^PanelBand)) (fp))(panel_, columnCount_, rowCount_, columns_, rows_); } -PanelSwitchTo :: #force_inline proc "c" (panel_ : ^Panel, targetChild_ : ^Element, transitionType_ : TransitionType, destroyPreviousAfterTransitionCompletes_ : bool = false){ addr := 0x1000 + 289 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Panel, ^Element, TransitionType, bool)) (fp))(panel_, targetChild_, transitionType_, destroyPreviousAfterTransitionCompletes_); } -TextPlanGetWidth :: #force_inline proc "c" (plan_ : ^TextPlan) -> i32{ addr := 0x1000 + 290 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^TextPlan) -> i32) (fp))(plan_); } -TextPlanGetHeight :: #force_inline proc "c" (plan_ : ^TextPlan) -> i32{ addr := 0x1000 + 291 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^TextPlan) -> i32) (fp))(plan_); } -TextPlanGetLineCount :: #force_inline proc "c" (plan_ : ^TextPlan) -> int { addr := 0x1000 + 292 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^TextPlan) -> int ) (fp))(plan_); } -TextPlanDestroy :: #force_inline proc "c" (plan_ : ^TextPlan){ addr := 0x1000 + 293 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^TextPlan)) (fp))(plan_); } -TextDisplaySetContents :: #force_inline proc "c" (display_ : ^TextDisplay, contents_ : string = ""){ addr := 0x1000 + 294 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^TextDisplay, ^u8, int)) (fp))(display_, raw_data(contents_), len(contents_)); } -ColorWellGetRGB :: #force_inline proc "c" (well_ : ^ColorWell) -> u32 { addr := 0x1000 + 304 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^ColorWell) -> u32 ) (fp))(well_); } -ColorWellSetRGB :: #force_inline proc "c" (well_ : ^ColorWell, colorRGB_ : u32 , sendChangedMessage_ : bool){ addr := 0x1000 + 305 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ColorWell, u32 , bool)) (fp))(well_, colorRGB_, sendChangedMessage_); } -ColorWellSetIndeterminate :: #force_inline proc "c" (well_ : ^ColorWell){ addr := 0x1000 + 306 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ColorWell)) (fp))(well_); } -ChoiceAddMenuItem :: #force_inline proc "c" (choice_ : ^Choice, item_ : Generic){ addr := 0x1000 + 307 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Choice, Generic)) (fp))(choice_, item_); } -ChoiceSetItem :: #force_inline proc "c" (choice_ : ^Choice, item_ : Generic, sendUpdatedMessage_ : bool = true){ addr := 0x1000 + 308 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Choice, Generic, bool)) (fp))(choice_, item_, sendUpdatedMessage_); } -ChoiceGetItem :: #force_inline proc "c" (choice_ : ^Choice) -> Generic{ addr := 0x1000 + 309 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Choice) -> Generic) (fp))(choice_); } -ListViewInsertGroup :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 , flags_ : u32 = FLAGS_DEFAULT){ addr := 0x1000 + 310 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 , u32 )) (fp))(view_, group_, flags_); } -ListViewInsert :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 , firstIndex_ : Generic, lastIndex_ : Generic, count_ : i64 = -1){ addr := 0x1000 + 311 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 , Generic, Generic, i64 )) (fp))(view_, group_, firstIndex_, lastIndex_, count_); } -ListViewRemove :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 , firstIndex_ : Generic, lastIndex_ : Generic, count_ : i64 = -1){ addr := 0x1000 + 312 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 , Generic, Generic, i64 )) (fp))(view_, group_, firstIndex_, lastIndex_, count_); } -ListViewRemoveAll :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 ){ addr := 0x1000 + 313 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 )) (fp))(view_, group_); } -ListViewGetIndex :: #force_inline proc "c" (view_ : ^ListView, item_ : ^Element) -> Generic{ addr := 0x1000 + 314 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^ListView, ^Element) -> Generic) (fp))(view_, item_); } -ListViewSetColumns :: #force_inline proc "c" (view_ : ^ListView, columns_ : ^ListViewColumn, columnCount_ : int ){ addr := 0x1000 + 315 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, ^ListViewColumn, int )) (fp))(view_, columns_, columnCount_); } -ListViewSetEmptyMessage :: #force_inline proc "c" (view_ : ^ListView, message_ : string = ""){ addr := 0x1000 + 262 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, ^u8, int)) (fp))(view_, raw_data(message_), len(message_)); } -ListViewSelect :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 , index_ : Generic){ addr := 0x1000 + 316 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 , Generic)) (fp))(view_, group_, index_); } -ListViewResetSearchBuffer :: #force_inline proc "c" (view_ : ^ListView){ addr := 0x1000 + 317 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView)) (fp))(view_); } +ThreadEntryFunction :: distinct #type proc "c" ( Generic) +ComparisonCallbackFunction :: distinct #type proc "c" ( rawptr, rawptr, Generic) -> i32 +SwapCallbackFunction :: distinct #type proc "c" ( rawptr, rawptr, Generic) +CRTComparisonCallback :: distinct #type proc "c" ( rawptr, rawptr) -> i32 +TimerCallbackFunction :: distinct #type proc "c" ( Generic) +MenuCallbackFunction :: distinct #type proc "c" ( ^Menu, Generic) +StorePullCallbackFunction :: distinct #type proc "c" ( ^Store, ^INSTANCE_TYPE, Generic, i32, Generic, ^FormatValue) +StoreCallbackFunction :: distinct #type proc "c" ( ^Store, ^INSTANCE_TYPE, Generic, Generic) +DirectoryMonitorCallbackFunction :: distinct #type proc "c" ( ^DirectoryMonitor, i32, ^i8 , int , ^i8 , int , Generic) +Batch :: #force_inline proc "c" (calls_ : ^BatchCall, count_ : int ){ addr := 0x1000 + 0 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^BatchCall, int )) (fp))(calls_, count_)} +GetCreationArgument :: #force_inline proc "c" (object_ : Handle) -> Generic{ addr := 0x1000 + 1 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> Generic) (fp))(object_)} +GetSystemInformation :: #force_inline proc "c" (systemInformation_ : ^SystemInformation){ addr := 0x1000 + 2 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^SystemInformation)) (fp))(systemInformation_)} +HandleClose :: #force_inline proc "c" (handle_ : Handle) -> Error{ addr := 0x1000 + 3 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> Error) (fp))(handle_)} +InitialiseCStandardLibrary :: #force_inline proc "c" (argc_ : ^i32, argv_ : ^^^i8 ){ addr := 0x1000 + 4 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^i32, ^^^i8 )) (fp))(argc_, argv_)} +MailslotSendData :: #force_inline proc "c" (mailslot_ : Handle, data_ : rawptr, bytes_ : int ) -> bool{ addr := 0x1000 + 5 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, rawptr, int ) -> bool) (fp))(mailslot_, data_, bytes_)} +MakeLinuxSystemCall2 :: #force_inline proc "c" (n_ : int , a1_ : int , a2_ : int , a3_ : int , a4_ : int , a5_ : int , a6_ : int ) -> int { addr := 0x1000 + 6 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , int , int , int , int , int , int ) -> int ) (fp))(n_, a1_, a2_, a3_, a4_, a5_, a6_)} +SystemGetConstant :: #force_inline proc "c" (index_ : uint ) -> u64 { addr := 0x1000 + 8 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( uint ) -> u64 ) (fp))(index_)} +TakeSystemSnapshot :: #force_inline proc "c" (type_ : i32, bufferSize_ : ^int ) -> Handle{ addr := 0x1000 + 9 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32, ^int ) -> Handle) (fp))(type_, bufferSize_)} +UserGetHomeFolder :: #force_inline proc "c" (buffer_ : ^i8 , bufferBytes_ : int ) -> int { addr := 0x1000 + 10 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int ) -> int ) (fp))(buffer_, bufferBytes_)} +_EsInstanceCreate :: #force_inline proc "c" (bytes_ : int , message_ : ^Message, cName_ : cstring ) -> ^Instance{ addr := 0x1000 + 11 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , ^Message, cstring ) -> ^Instance) (fp))(bytes_, message_, cName_)} +_EsSyscall :: #force_inline proc "c" (a_ : uint , b_ : uint , c_ : uint , d_ : uint , e_ : uint , f_ : uint ) -> uint { addr := 0x1000 + 12 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( uint , uint , uint , uint , uint , uint ) -> uint ) (fp))(a_, b_, c_, d_, e_, f_)} +ApplicationStart :: #force_inline proc "c" (information_ : ^ApplicationStartupInformation){ addr := 0x1000 + 124 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ApplicationStartupInformation)) (fp))(information_)} +SystemConfigurationReadAll :: #force_inline proc "c" (groupCount_ : ^int ) -> ^SystemConfigurationGroup{ addr := 0x1000 + 164 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^int ) -> ^SystemConfigurationGroup) (fp))(groupCount_)} +SystemConfigurationReadInteger :: #force_inline proc "c" (section_ : string, key_ : string, defaultValue_ : i64 = 0) -> i64 { addr := 0x1000 + 295 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int, i64 ) -> i64 ) (fp))(raw_data(section_), len(section_), raw_data(key_), len(key_), defaultValue_)} +SystemConfigurationGroupReadInteger :: #force_inline proc "c" (group_ : ^SystemConfigurationGroup, key_ : string, defaultValue_ : i64 = 0) -> i64 { addr := 0x1000 + 296 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^SystemConfigurationGroup, ^u8, int, i64 ) -> i64 ) (fp))(group_, raw_data(key_), len(key_), defaultValue_)} +SystemConfigurationReadString :: #force_inline proc "c" (section_ : string, key_ : string, valueBytes_ : ^int = nil) -> ^i8 { addr := 0x1000 + 297 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int, ^int ) -> ^i8 ) (fp))(raw_data(section_), len(section_), raw_data(key_), len(key_), valueBytes_)} +SystemConfigurationGroupReadString :: #force_inline proc "c" (group_ : ^SystemConfigurationGroup, key_ : string, valueBytes_ : ^int = nil) -> ^i8 { addr := 0x1000 + 298 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^SystemConfigurationGroup, ^u8, int, ^int ) -> ^i8 ) (fp))(group_, raw_data(key_), len(key_), valueBytes_)} +INIParse :: #force_inline proc "c" (s_ : ^INIState) -> bool{ addr := 0x1000 + 7 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^INIState) -> bool) (fp))(s_)} +INIPeek :: #force_inline proc "c" (s_ : ^INIState) -> bool{ addr := 0x1000 + 87 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^INIState) -> bool) (fp))(s_)} +INIFormat :: #force_inline proc "c" (s_ : ^INIState, buffer_ : ^i8 , bytes_ : int ) -> int { addr := 0x1000 + 125 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^INIState, ^i8 , int ) -> int ) (fp))(s_, buffer_, bytes_)} +INIZeroTerminate :: #force_inline proc "c" (s_ : ^INIState){ addr := 0x1000 + 126 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^INIState)) (fp))(s_)} +CommandAddButton :: #force_inline proc "c" (command_ : ^Command, button_ : ^Button){ addr := 0x1000 + 13 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Command, ^Button)) (fp))(command_, button_)} +CommandByID :: #force_inline proc "c" (instance_ : ^Instance, stableID_ : u32 ) -> ^Command{ addr := 0x1000 + 14 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Instance, u32 ) -> ^Command) (fp))(instance_, stableID_)} +CommandRegister :: #force_inline proc "c" (command_ : ^Command, instance_ : ^Instance, callback_ : CommandCallbackFunction, stableID_ : u32 , cDefaultKeyboardShortcut_ : cstring = nil, enabled_ : bool = false) -> ^Command{ addr := 0x1000 + 15 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Command, ^Instance, CommandCallbackFunction, u32 , cstring , bool) -> ^Command) (fp))(command_, instance_, callback_, stableID_, cDefaultKeyboardShortcut_, enabled_)} +CommandSetCallback :: #force_inline proc "c" (command_ : ^Command, callback_ : CommandCallbackFunction){ addr := 0x1000 + 16 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Command, CommandCallbackFunction)) (fp))(command_, callback_)} +CommandSetDisabled :: #force_inline proc "c" (command_ : ^Command, disabled_ : bool){ addr := 0x1000 + 17 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Command, bool)) (fp))(command_, disabled_)} +DialogClose :: #force_inline proc "c" (window_ : ^Window){ addr := 0x1000 + 18 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Window)) (fp))(window_)} +DialogShow :: #force_inline proc "c" (window_ : ^Window) -> ^Element{ addr := 0x1000 + 19 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Window) -> ^Element) (fp))(window_)} +DialogShowAlert :: #force_inline proc "c" (window_ : ^Window, title_ : string, content_ : string, iconID_ : u32 , addOKButton_ : bool = false) -> ^Element{ addr := 0x1000 + 20 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Window, ^u8, int, ^u8, int, u32 , bool) -> ^Element) (fp))(window_, raw_data(title_), len(title_), raw_data(content_), len(content_), iconID_, addOKButton_)} +InstanceDestroy :: #force_inline proc "c" (instance_ : ^INSTANCE_TYPE){ addr := 0x1000 + 300 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^INSTANCE_TYPE)) (fp))(instance_)} +KeyboardIsAltHeld :: #force_inline proc "c" () -> bool{ addr := 0x1000 + 21 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> bool) (fp))()} +KeyboardIsCtrlHeld :: #force_inline proc "c" () -> bool{ addr := 0x1000 + 22 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> bool) (fp))()} +KeyboardIsShiftHeld :: #force_inline proc "c" () -> bool{ addr := 0x1000 + 23 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> bool) (fp))()} +MessageGetInputText :: #force_inline proc "c" (message_ : ^Message, buffer_ : ^i8 ) -> int { addr := 0x1000 + 24 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Message, ^i8 ) -> int ) (fp))(message_, buffer_)} +MessageMutexAcquire :: #force_inline proc "c" (){ addr := 0x1000 + 26 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))()} +MessageMutexCheck :: #force_inline proc "c" (){ addr := 0x1000 + 27 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))()} +MessageMutexRelease :: #force_inline proc "c" (){ addr := 0x1000 + 28 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))()} +MessagePost :: #force_inline proc "c" (target_ : ^Element, message_ : ^Message) -> Error{ addr := 0x1000 + 29 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, ^Message) -> Error) (fp))(target_, message_)} +MessagePostRemote :: #force_inline proc "c" (process_ : Handle, message_ : ^Message) -> Error{ addr := 0x1000 + 30 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, ^Message) -> Error) (fp))(process_, message_)} +MessageSend :: #force_inline proc "c" (object_ : ^Element, message_ : ^Message) -> Response{ addr := 0x1000 + 31 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, ^Message) -> Response) (fp))(object_, message_)} +MessageReceive :: #force_inline proc "c" () -> ^Message{ addr := 0x1000 + 318 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> ^Message) (fp))()} +MouseGetPosition :: #force_inline proc "c" (relativeElement_ : ^Element = nil) -> Point{ addr := 0x1000 + 32 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> Point) (fp))(relativeElement_)} +MouseSetPosition :: #force_inline proc "c" (relativeWindow_ : ^Window, x_ : i32, y_ : i32){ addr := 0x1000 + 33 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Window, i32, i32)) (fp))(relativeWindow_, x_, y_)} +StyleInheritRegister :: #force_inline proc "c" (cStyle_ : cstring , cParent_ : cstring , customMetrics_ : ^ThemeMetrics){ addr := 0x1000 + 239 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( cstring , cstring , ^ThemeMetrics)) (fp))(cStyle_, cParent_, customMetrics_)} +StyleRefreshAll :: #force_inline proc "c" (window_ : ^Element){ addr := 0x1000 + 37 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element)) (fp))(window_)} +UISetDPI :: #force_inline proc "c" (dpiScale_ : i32){ addr := 0x1000 + 38 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( i32)) (fp))(dpiScale_)} +DirectoryEnumerateChildren :: #force_inline proc "c" (path_ : string, buffer_ : ^^DirectoryChild) -> int { addr := 0x1000 + 39 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^^DirectoryChild) -> int ) (fp))(raw_data(path_), len(path_), buffer_)} +DirectoryEnumerateChildrenFromHandle :: #force_inline proc "c" (directory_ : Handle, buffer_ : ^DirectoryChild, bufferCount_ : int ) -> int { addr := 0x1000 + 40 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, ^DirectoryChild, int ) -> int ) (fp))(directory_, buffer_, bufferCount_)} +DirectoryMonitorCreate :: #force_inline proc "c" (path_ : string, flags_ : u32 , callback_ : DirectoryMonitorCallbackFunction, _context_ : Generic) -> ^DirectoryMonitor{ addr := 0x1000 + 41 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, u32 , DirectoryMonitorCallbackFunction, Generic) -> ^DirectoryMonitor) (fp))(raw_data(path_), len(path_), flags_, callback_, _context_)} +DirectoryMonitorCreateFromHandle :: #force_inline proc "c" (directory_ : Handle, flags_ : u32 , callback_ : DirectoryMonitorCallbackFunction, _context_ : Generic) -> ^DirectoryMonitor{ addr := 0x1000 + 42 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, u32 , DirectoryMonitorCallbackFunction, Generic) -> ^DirectoryMonitor) (fp))(directory_, flags_, callback_, _context_)} +DirectoryMonitorDestroy :: #force_inline proc "c" (monitor_ : ^DirectoryMonitor){ addr := 0x1000 + 43 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^DirectoryMonitor)) (fp))(monitor_)} +FileControl :: #force_inline proc "c" (file_ : Handle, flags_ : u32 ) -> Error{ addr := 0x1000 + 96 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, u32 ) -> Error) (fp))(file_, flags_)} +FileReadAll :: #force_inline proc "c" (filePath_ : string, fileSize_ : ^int ) -> rawptr{ addr := 0x1000 + 44 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^int ) -> rawptr) (fp))(raw_data(filePath_), len(filePath_), fileSize_)} +FileReadSync :: #force_inline proc "c" (file_ : Handle, offset_ : FileOffset, size_ : int , buffer_ : rawptr) -> int { addr := 0x1000 + 45 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, FileOffset, int , rawptr) -> int ) (fp))(file_, offset_, size_, buffer_)} +FileResize :: #force_inline proc "c" (file_ : Handle, newSize_ : FileOffset) -> Error{ addr := 0x1000 + 46 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, FileOffset) -> Error) (fp))(file_, newSize_)} +FileWriteAll :: #force_inline proc "c" (filePath_ : string, data_ : rawptr, fileSize_ : int ) -> Error{ addr := 0x1000 + 47 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, rawptr, int ) -> Error) (fp))(raw_data(filePath_), len(filePath_), data_, fileSize_)} +FileWriteAllGather :: #force_inline proc "c" (filePath_ : string, data_ : ^rawptr, fileSize_ : ^int , gatherCount_ : int ) -> Error{ addr := 0x1000 + 48 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^rawptr, ^int , int ) -> Error) (fp))(raw_data(filePath_), len(filePath_), data_, fileSize_, gatherCount_)} +FileWriteSync :: #force_inline proc "c" (file_ : Handle, offset_ : FileOffset, size_ : int , buffer_ : rawptr) -> int { addr := 0x1000 + 50 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, FileOffset, int , rawptr) -> int ) (fp))(file_, offset_, size_, buffer_)} +NodeDelete :: #force_inline proc "c" (node_ : Handle) -> Error{ addr := 0x1000 + 51 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> Error) (fp))(node_)} +NodeDeleteByPath :: #force_inline proc "c" (filePath_ : string) -> Error{ addr := 0x1000 + 52 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> Error) (fp))(raw_data(filePath_), len(filePath_))} +NodeFindUniqueName :: #force_inline proc "c" (buffer_ : ^i8 , originalBytes_ : int , bufferBytes_ : int ) -> int { addr := 0x1000 + 53 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , int ) -> int ) (fp))(buffer_, originalBytes_, bufferBytes_)} +NodeMove :: #force_inline proc "c" (node_ : Handle, newDirectory_ : Handle, newName_ : string) -> Error{ addr := 0x1000 + 54 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, Handle, ^u8, int) -> Error) (fp))(node_, newDirectory_, raw_data(newName_), len(newName_))} +NodeOpen :: #force_inline proc "c" (path_ : string, flags_ : u32 , information_ : ^NodeInformation) -> Error{ addr := 0x1000 + 55 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, u32 , ^NodeInformation) -> Error) (fp))(raw_data(path_), len(path_), flags_, information_)} +NodeOpenRelative :: #force_inline proc "c" (directory_ : Handle, path_ : string, flags_ : u32 , information_ : ^NodeInformation) -> Error{ addr := 0x1000 + 56 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, ^u8, int, u32 , ^NodeInformation) -> Error) (fp))(directory_, raw_data(path_), len(path_), flags_, information_)} +NodeRefreshInformation :: #force_inline proc "c" (information_ : ^NodeInformation){ addr := 0x1000 + 57 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^NodeInformation)) (fp))(information_)} +ProcessCrash :: #force_inline proc "c" (error_ : Error, message_ : string){ addr := 0x1000 + 58 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Error, ^u8, int)) (fp))(error_, raw_data(message_), len(message_))} +ProcessCreate :: #force_inline proc "c" (executablePath_ : string, information_ : ^ProcessInformation, argument_ : Generic) -> Error{ addr := 0x1000 + 59 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^ProcessInformation, Generic) -> Error) (fp))(raw_data(executablePath_), len(executablePath_), information_, argument_)} +ProcessCreate2 :: #force_inline proc "c" (arguments_ : ^ProcessCreationArguments, information_ : ^ProcessInformation) -> Error{ addr := 0x1000 + 60 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^ProcessCreationArguments, ^ProcessInformation) -> Error) (fp))(arguments_, information_)} +ProcessGetExitStatus :: #force_inline proc "c" (process_ : Handle) -> i32{ addr := 0x1000 + 61 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> i32) (fp))(process_)} +ProcessGetID :: #force_inline proc "c" (process_ : Handle) -> uint { addr := 0x1000 + 62 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> uint ) (fp))(process_)} +ProcessGetState :: #force_inline proc "c" (process_ : Handle, state_ : ^ProcessState){ addr := 0x1000 + 63 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, ^ProcessState)) (fp))(process_, state_)} +ProcessOpen :: #force_inline proc "c" (pid_ : u64 ) -> Handle{ addr := 0x1000 + 64 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( u64 ) -> Handle) (fp))(pid_)} +ProcessPause :: #force_inline proc "c" (process_ : Handle, resume_ : bool){ addr := 0x1000 + 65 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, bool)) (fp))(process_, resume_)} +ProcessTerminate :: #force_inline proc "c" (process_ : Handle, status_ : i32){ addr := 0x1000 + 66 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, i32)) (fp))(process_, status_)} +ProcessTerminateCurrent :: #force_inline proc "c" (){ addr := 0x1000 + 67 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))()} +ThreadCreate :: #force_inline proc "c" (entryFunction_ : ThreadEntryFunction, information_ : ^ThreadInformation, argument_ : Generic) -> Error{ addr := 0x1000 + 68 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ThreadEntryFunction, ^ThreadInformation, Generic) -> Error) (fp))(entryFunction_, information_, argument_)} +ThreadGetID :: #force_inline proc "c" (thread_ : Handle) -> uint { addr := 0x1000 + 69 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> uint ) (fp))(thread_)} +ThreadTerminate :: #force_inline proc "c" (thread_ : Handle){ addr := 0x1000 + 71 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle)) (fp))(thread_)} +ArenaAllocate :: #force_inline proc "c" (arena_ : ^Arena, zero_ : bool) -> rawptr{ addr := 0x1000 + 72 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Arena, bool) -> rawptr) (fp))(arena_, zero_)} +ArenaFree :: #force_inline proc "c" (arena_ : ^Arena, pointer_ : rawptr){ addr := 0x1000 + 73 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Arena, rawptr)) (fp))(arena_, pointer_)} +ArenaInitialise :: #force_inline proc "c" (arena_ : ^Arena, blockSize_ : int , itemSize_ : int ){ addr := 0x1000 + 74 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Arena, int , int )) (fp))(arena_, blockSize_, itemSize_)} +ConstantBufferCreate :: #force_inline proc "c" (data_ : rawptr, dataBytes_ : int , targetProcess_ : Handle) -> Handle{ addr := 0x1000 + 75 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int , Handle) -> Handle) (fp))(data_, dataBytes_, targetProcess_)} +ConstantBufferRead :: #force_inline proc "c" (constantBuffer_ : Handle, output_ : rawptr){ addr := 0x1000 + 76 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, rawptr)) (fp))(constantBuffer_, output_)} +ConstantBufferShare :: #force_inline proc "c" (constantBuffer_ : Handle, targetProcess_ : Handle) -> Handle{ addr := 0x1000 + 77 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, Handle) -> Handle) (fp))(constantBuffer_, targetProcess_)} +HeapAllocate :: #force_inline proc "c" (size_ : int , zeroMemory_ : bool) -> rawptr{ addr := 0x1000 + 78 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , bool) -> rawptr) (fp))(size_, zeroMemory_)} +HeapFree :: #force_inline proc "c" (address_ : rawptr){ addr := 0x1000 + 79 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr)) (fp))(address_)} +HeapReallocate :: #force_inline proc "c" (oldAddress_ : rawptr, newAllocationSize_ : int , zeroNewSpace_ : bool) -> rawptr{ addr := 0x1000 + 80 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int , bool) -> rawptr) (fp))(oldAddress_, newAllocationSize_, zeroNewSpace_)} +HeapValidate :: #force_inline proc "c" (){ addr := 0x1000 + 81 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))()} +MemoryCommit :: #force_inline proc "c" (pointer_ : rawptr, bytes_ : int ) -> bool{ addr := 0x1000 + 82 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int ) -> bool) (fp))(pointer_, bytes_)} +MemoryCompare :: #force_inline proc "c" (a_ : rawptr, b_ : rawptr, bytes_ : int ) -> i32{ addr := 0x1000 + 83 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, rawptr, int ) -> i32) (fp))(a_, b_, bytes_)} +MemoryCopy :: #force_inline proc "c" (destination_ : rawptr, source_ : rawptr, bytes_ : int ){ addr := 0x1000 + 84 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, int )) (fp))(destination_, source_, bytes_)} +MemoryCopyReverse :: #force_inline proc "c" (_destination_ : rawptr, _source_ : rawptr, bytes_ : int ){ addr := 0x1000 + 85 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, int )) (fp))(_destination_, _source_, bytes_)} +MemoryDecommit :: #force_inline proc "c" (pointer_ : rawptr, bytes_ : int ) -> bool{ addr := 0x1000 + 320 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int ) -> bool) (fp))(pointer_, bytes_)} +MemoryFill :: #force_inline proc "c" (from_ : rawptr, to_ : rawptr, byte_ : u8 ){ addr := 0x1000 + 86 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, u8 )) (fp))(from_, to_, byte_)} +MemoryMove :: #force_inline proc "c" (_start_ : rawptr, _end_ : rawptr, amount_ : int , zeroEmptySpace_ : bool){ addr := 0x1000 + 88 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, rawptr, int , bool)) (fp))(_start_, _end_, amount_, zeroEmptySpace_)} +MemoryOpen :: #force_inline proc "c" (size_ : int , name_ : string, flags_ : u32 ) -> Handle{ addr := 0x1000 + 89 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , ^u8, int, u32 ) -> Handle) (fp))(size_, raw_data(name_), len(name_), flags_)} +MemoryReserve :: #force_inline proc "c" (size_ : int , protection_ : MemoryProtection = MEMORY_PROTECTION_READ_WRITE, commitAll_ : bool = true) -> rawptr{ addr := 0x1000 + 25 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , MemoryProtection, bool) -> rawptr) (fp))(size_, protection_, commitAll_)} +MemoryShare :: #force_inline proc "c" (sharedMemoryRegion_ : Handle, targetProcess_ : Handle, readOnly_ : bool) -> Handle{ addr := 0x1000 + 90 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, Handle, bool) -> Handle) (fp))(sharedMemoryRegion_, targetProcess_, readOnly_)} +MemorySumBytes :: #force_inline proc "c" (data_ : ^u8 , bytes_ : int ) -> u8 { addr := 0x1000 + 91 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^u8 , int ) -> u8 ) (fp))(data_, bytes_)} +MemoryUnreserve :: #force_inline proc "c" (pointer_ : rawptr, size_ : int = 0){ addr := 0x1000 + 319 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int )) (fp))(pointer_, size_)} +MemoryZero :: #force_inline proc "c" (destination_ : rawptr, bytes_ : int ){ addr := 0x1000 + 92 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int )) (fp))(destination_, bytes_)} +ObjectMap :: #force_inline proc "c" (object_ : Handle, offset_ : uint , size_ : int , flags_ : u32 ) -> rawptr{ addr := 0x1000 + 93 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, uint , int , u32 ) -> rawptr) (fp))(object_, offset_, size_, flags_)} +AssertionFailure :: #force_inline proc "c" (cFile_ : cstring , line_ : i32){ addr := 0x1000 + 94 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( cstring , i32)) (fp))(cFile_, line_)} +DoubleParse :: #force_inline proc "c" (string_ : string, endptr_ : ^^i8 ) -> f64 { addr := 0x1000 + 97 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^^i8 ) -> f64 ) (fp))(raw_data(string_), len(string_), endptr_)} +ExtractArguments :: #force_inline proc "c" (string_ : ^i8 , bytes_ : int , delimiterByte_ : u8 , replacementDelimiter_ : u8 , argvAllocated_ : int , argv_ : ^^i8 , argc_ : ^int ) -> bool{ addr := 0x1000 + 98 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , u8 , u8 , int , ^^i8 , ^int ) -> bool) (fp))(string_, bytes_, delimiterByte_, replacementDelimiter_, argvAllocated_, argv_, argc_)} +RandomU8 :: #force_inline proc "c" () -> u8 { addr := 0x1000 + 301 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> u8 ) (fp))()} +RandomU64 :: #force_inline proc "c" () -> u64 { addr := 0x1000 + 302 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> u64 ) (fp))()} +IntegerParse :: #force_inline proc "c" (text_ : string) -> i64 { addr := 0x1000 + 101 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> i64 ) (fp))(raw_data(text_), len(text_))} +Print :: #force_inline proc "c" (format_ : cstring , _varargs_ : ..any){ addr := 0x1000 + 102 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( cstring , ..any)) (fp))(format_, _varargs_)} +PrintDirect :: #force_inline proc "c" (string_ : string){ addr := 0x1000 + 103 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" (^u8, int)) (fp))(raw_data(string_), len(string_))} +PrintHelloWorld :: #force_inline proc "c" (){ addr := 0x1000 + 104 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))()} +RandomAddEntropy :: #force_inline proc "c" (x_ : u64 ){ addr := 0x1000 + 106 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( u64 )) (fp))(x_)} +RandomSeed :: #force_inline proc "c" (x_ : u64 ){ addr := 0x1000 + 107 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( u64 )) (fp))(x_)} +RectangleClip :: #force_inline proc "c" (parent_ : Rectangle, rectangle_ : Rectangle, output_ : ^Rectangle) -> bool{ addr := 0x1000 + 108 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Rectangle, Rectangle, ^Rectangle) -> bool) (fp))(parent_, rectangle_, output_)} +Sort :: #force_inline proc "c" (_base_ : rawptr, nmemb_ : int , size_ : int , compar_ : ComparisonCallbackFunction, argument_ : Generic){ addr := 0x1000 + 109 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int , int , ComparisonCallbackFunction, Generic)) (fp))(_base_, nmemb_, size_, compar_, argument_)} +SortWithSwapCallback :: #force_inline proc "c" (_base_ : rawptr, nmemb_ : int , size_ : int , compar_ : ComparisonCallbackFunction, argument_ : Generic, swap_ : SwapCallbackFunction){ addr := 0x1000 + 110 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int , int , ComparisonCallbackFunction, Generic, SwapCallbackFunction)) (fp))(_base_, nmemb_, size_, compar_, argument_, swap_)} +TimeStamp :: #force_inline proc "c" () -> u64 { addr := 0x1000 + 252 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> u64 ) (fp))()} +TimeStampMs :: #force_inline proc "c" () -> f64 { addr := 0x1000 + 261 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> f64 ) (fp))()} +ColorBlend :: #force_inline proc "c" (under_ : u32 , over_ : u32 , fullAlpha_ : bool) -> u32 { addr := 0x1000 + 111 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( u32 , u32 , bool) -> u32 ) (fp))(under_, over_, fullAlpha_)} +ColorConvertToRGB :: #force_inline proc "c" (h_ : f32 , s_ : f32 , v_ : f32 ) -> u32 { addr := 0x1000 + 112 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 , f32 , f32 ) -> u32 ) (fp))(h_, s_, v_)} +ColorConvertToHSV :: #force_inline proc "c" (color_ : u32 , h_ : ^f32 , s_ : ^f32 , v_ : ^f32 ) -> bool{ addr := 0x1000 + 113 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( u32 , ^f32 , ^f32 , ^f32 ) -> bool) (fp))(color_, h_, s_, v_)} +ColorParse :: #force_inline proc "c" (string_ : string) -> u32 { addr := 0x1000 + 114 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> u32 ) (fp))(raw_data(string_), len(string_))} +DrawBitmap :: #force_inline proc "c" (painter_ : ^Painter, region_ : Rectangle, bits_ : ^u32 , stride_ : uint ){ addr := 0x1000 + 324 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, Rectangle, ^u32 , uint )) (fp))(painter_, region_, bits_, stride_)} +DrawInvert :: #force_inline proc "c" (painter_ : ^Painter, bounds_ : Rectangle){ addr := 0x1000 + 95 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, Rectangle)) (fp))(painter_, bounds_)} +DrawStandardIcon :: #force_inline proc "c" (painter_ : ^Painter, id_ : u32 , size_ : i32, region_ : Rectangle, color_ : u32 ) -> bool{ addr := 0x1000 + 115 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Painter, u32 , i32, Rectangle, u32 ) -> bool) (fp))(painter_, id_, size_, region_, color_)} +DrawStyledBox :: #force_inline proc "c" (painter_ : ^Painter, box_ : StyledBox){ addr := 0x1000 + 116 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, StyledBox)) (fp))(painter_, box_)} +DrawPaintTarget :: #force_inline proc "c" (painter_ : ^Painter, source_ : ^PaintTarget, destinationRegion_ : Rectangle, sourceRegion_ : Rectangle, borderRegion_ : Rectangle, mode_ : DrawMode, alpha_ : u16 , clipRegion_ : Rectangle){ addr := 0x1000 + 263 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, ^PaintTarget, Rectangle, Rectangle, Rectangle, DrawMode, u16 , Rectangle)) (fp))(painter_, source_, destinationRegion_, sourceRegion_, borderRegion_, mode_, alpha_, clipRegion_)} +DrawText :: #force_inline proc "c" (painter_ : ^Painter, plan_ : ^TextPlan, bounds_ : Rectangle, clip_ : ^Rectangle = nil, selectionProperties_ : ^TextSelection = nil){ addr := 0x1000 + 120 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, ^TextPlan, Rectangle, ^Rectangle, ^TextSelection)) (fp))(painter_, plan_, bounds_, clip_, selectionProperties_)} +FontGetName :: #force_inline proc "c" (family_ : u16 , buffer_ : ^i8 , bufferBytes_ : int ) -> int { addr := 0x1000 + 121 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( u16 , ^i8 , int ) -> int ) (fp))(family_, buffer_, bufferBytes_)} +IconIDFromString :: #force_inline proc "c" (string_ : string = "") -> u32 { addr := 0x1000 + 127 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> u32 ) (fp))(raw_data(string_), len(string_))} +ImageLoad :: #force_inline proc "c" (file_ : ^u8 , fileSize_ : int , width_ : ^u32 , height_ : ^u32 , imageChannels_ : i32) -> ^u8 { addr := 0x1000 + 165 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^u8 , int , ^u32 , ^u32 , i32) -> ^u8 ) (fp))(file_, fileSize_, width_, height_, imageChannels_)} +PainterBoundsClient :: #force_inline proc "c" (painter_ : ^Painter) -> Rectangle{ addr := 0x1000 + 122 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Painter) -> Rectangle) (fp))(painter_)} +PainterBoundsInset :: #force_inline proc "c" (painter_ : ^Painter) -> Rectangle{ addr := 0x1000 + 123 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Painter) -> Rectangle) (fp))(painter_)} +PainterDrawStandardContent :: #force_inline proc "c" (painter_ : ^Painter, text_ : string, iconID_ : u32 ){ addr := 0x1000 + 117 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Painter, ^u8, int, u32 )) (fp))(painter_, raw_data(text_), len(text_), iconID_)} +PaintTargetClear :: #force_inline proc "c" (target_ : ^PaintTarget){ addr := 0x1000 + 34 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^PaintTarget)) (fp))(target_)} +PaintTargetEndDirectAccess :: #force_inline proc "c" (target_ : ^PaintTarget){ addr := 0x1000 + 264 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^PaintTarget)) (fp))(target_)} +PaintTargetStartDirectAccess :: #force_inline proc "c" (target_ : ^PaintTarget, bits_ : ^^u32 , width_ : ^int , height_ : ^int , stride_ : ^int ){ addr := 0x1000 + 276 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^PaintTarget, ^^u32 , ^int , ^int , ^int )) (fp))(target_, bits_, width_, height_, stride_)} +PaintTargetTake :: #force_inline proc "c" (target_ : ^PaintTarget, width_ : int , height_ : int ) -> bool{ addr := 0x1000 + 35 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^PaintTarget, int , int ) -> bool) (fp))(target_, width_, height_)} +PaintTargetReturn :: #force_inline proc "c" (target_ : ^PaintTarget){ addr := 0x1000 + 36 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^PaintTarget)) (fp))(target_)} +TextGetLineHeight :: #force_inline proc "c" (font_ : Font, size_ : u16 ) -> i32{ addr := 0x1000 + 157 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Font, u16 ) -> i32) (fp))(font_, size_)} +TextGetPartialStringWidth :: #force_inline proc "c" (font_ : Font, size_ : u16 , fullString_ : ^i8 , fullStringBytes_ : int , measureOffset_ : uint , measureBytes_ : int ) -> i32{ addr := 0x1000 + 171 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Font, u16 , ^i8 , int , uint , int ) -> i32) (fp))(font_, size_, fullString_, fullStringBytes_, measureOffset_, measureBytes_)} +TextGetCharacterAtPoint :: #force_inline proc "c" (font_ : Font, size_ : u16 , fullString_ : ^i8 , fullStringBytes_ : int , measureOffset_ : uint , measureBytes_ : int , pointX_ : ^i32, reverse_ : bool, middle_ : bool) -> int { addr := 0x1000 + 237 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Font, u16 , ^i8 , int , uint , int , ^i32, bool, bool) -> int ) (fp))(font_, size_, fullString_, fullStringBytes_, measureOffset_, measureBytes_, pointX_, reverse_, middle_)} +AudioStreamClose :: #force_inline proc "c" (stream_ : ^AudioStream){ addr := 0x1000 + 128 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^AudioStream)) (fp))(stream_)} +AudioStreamOpen :: #force_inline proc "c" (device_ : AudioDeviceID, bufferLengthUs_ : int ) -> ^AudioStream{ addr := 0x1000 + 129 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( AudioDeviceID, int ) -> ^AudioStream) (fp))(device_, bufferLengthUs_)} +AudioStreamNotify :: #force_inline proc "c" (stream_ : ^AudioStream){ addr := 0x1000 + 130 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^AudioStream)) (fp))(stream_)} +AudioStreamSend :: #force_inline proc "c" (destination_ : ^AudioStream, source_ : ^AudioStream, time_ : ^f64 ) -> Error{ addr := 0x1000 + 131 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^AudioStream, ^AudioStream, ^f64 ) -> Error) (fp))(destination_, source_, time_)} +AddressResolve :: #force_inline proc "c" (domain_ : string, flags_ : u32 , address_ : ^Address) -> Error{ addr := 0x1000 + 99 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, u32 , ^Address) -> Error) (fp))(raw_data(domain_), len(domain_), flags_, address_)} +ConnectionClose :: #force_inline proc "c" (connection_ : ^Connection){ addr := 0x1000 + 321 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Connection)) (fp))(connection_)} +ConnectionNotify :: #force_inline proc "c" (connection_ : ^Connection){ addr := 0x1000 + 322 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Connection)) (fp))(connection_)} +ConnectionOpen :: #force_inline proc "c" (connection_ : ^Connection, flags_ : u32 ) -> Error{ addr := 0x1000 + 100 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Connection, u32 ) -> Error) (fp))(connection_, flags_)} +ConnectionPoll :: #force_inline proc "c" (connection_ : ^Connection){ addr := 0x1000 + 303 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Connection)) (fp))(connection_)} +ConnectionRead :: #force_inline proc "c" (connection_ : ^Connection, buffer_ : rawptr, bufferBytes_ : int , bytesRead_ : ^int ) -> Error{ addr := 0x1000 + 325 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Connection, rawptr, int , ^int ) -> Error) (fp))(connection_, buffer_, bufferBytes_, bytesRead_)} +ConnectionWriteSync :: #force_inline proc "c" (connection_ : ^Connection, data_ : rawptr, dataBytes_ : int ) -> Error{ addr := 0x1000 + 323 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Connection, rawptr, int ) -> Error) (fp))(connection_, data_, dataBytes_)} +GameControllerStatePoll :: #force_inline proc "c" (buffer_ : ^GameControllerState) -> int { addr := 0x1000 + 299 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^GameControllerState) -> int ) (fp))(buffer_)} +EventCreate :: #force_inline proc "c" (autoReset_ : bool) -> Handle{ addr := 0x1000 + 132 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( bool) -> Handle) (fp))(autoReset_)} +EventForward :: #force_inline proc "c" (event_ : Handle, eventSink_ : Handle, data_ : Generic){ addr := 0x1000 + 133 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, Handle, Generic)) (fp))(event_, eventSink_, data_)} +EventPoll :: #force_inline proc "c" (event_ : Handle) -> Error{ addr := 0x1000 + 134 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle) -> Error) (fp))(event_)} +EventReset :: #force_inline proc "c" (event_ : Handle){ addr := 0x1000 + 135 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle)) (fp))(event_)} +EventSet :: #force_inline proc "c" (event_ : Handle){ addr := 0x1000 + 136 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle)) (fp))(event_)} +EventSinkCreate :: #force_inline proc "c" (ignoreDuplicates_ : bool) -> Handle{ addr := 0x1000 + 137 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( bool) -> Handle) (fp))(ignoreDuplicates_)} +EventSinkPop :: #force_inline proc "c" (eventSink_ : Handle, data_ : ^Generic) -> Error{ addr := 0x1000 + 138 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, ^Generic) -> Error) (fp))(eventSink_, data_)} +EventSinkPush :: #force_inline proc "c" (eventSink_ : Handle, data_ : Generic) -> Error{ addr := 0x1000 + 139 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( Handle, Generic) -> Error) (fp))(eventSink_, data_)} +MutexAcquire :: #force_inline proc "c" (mutex_ : ^Mutex){ addr := 0x1000 + 140 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Mutex)) (fp))(mutex_)} +MutexDestroy :: #force_inline proc "c" (mutex_ : ^Mutex){ addr := 0x1000 + 141 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Mutex)) (fp))(mutex_)} +MutexRelease :: #force_inline proc "c" (mutex_ : ^Mutex){ addr := 0x1000 + 142 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Mutex)) (fp))(mutex_)} +PerformanceTimerPush :: #force_inline proc "c" (){ addr := 0x1000 + 143 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))()} +PerformanceTimerPop :: #force_inline proc "c" () -> f64 { addr := 0x1000 + 144 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> f64 ) (fp))()} +SchedulerYield :: #force_inline proc "c" (){ addr := 0x1000 + 145 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ()) (fp))()} +Sleep :: #force_inline proc "c" (milliseconds_ : u64 ){ addr := 0x1000 + 146 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( u64 )) (fp))(milliseconds_)} +SpinlockAcquire :: #force_inline proc "c" (spinlock_ : ^Spinlock){ addr := 0x1000 + 147 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Spinlock)) (fp))(spinlock_)} +SpinlockRelease :: #force_inline proc "c" (spinlock_ : ^Spinlock){ addr := 0x1000 + 148 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Spinlock)) (fp))(spinlock_)} +TimerCreate :: #force_inline proc "c" () -> Handle{ addr := 0x1000 + 149 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" () -> Handle) (fp))()} +TimerSet :: #force_inline proc "c" (handle_ : Handle, afterMs_ : u64 , callback_ : TimerCallbackFunction, argument_ : Generic){ addr := 0x1000 + 150 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( Handle, u64 , TimerCallbackFunction, Generic)) (fp))(handle_, afterMs_, callback_, argument_)} +Wait :: #force_inline proc "c" (objects_ : ^Handle, objectCount_ : int , timeoutMs_ : uint ) -> uint { addr := 0x1000 + 151 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Handle, int , uint ) -> uint ) (fp))(objects_, objectCount_, timeoutMs_)} +CStringLength :: #force_inline proc "c" (string_ : cstring ) -> int { addr := 0x1000 + 152 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( cstring ) -> int ) (fp))(string_)} +StringAllocateAndFormat :: #force_inline proc "c" (bytes_ : ^int , format_ : cstring , _varargs_ : ..any) -> ^i8 { addr := 0x1000 + 153 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^int , cstring , ..any) -> ^i8 ) (fp))(bytes_, format_, _varargs_)} +StringCompare :: #force_inline proc "c" (s1_ : string, s2_ : string) -> i32{ addr := 0x1000 + 155 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int) -> i32) (fp))(raw_data(s1_), len(s1_), raw_data(s2_), len(s2_))} +StringCompareRaw :: #force_inline proc "c" (s1_ : string, s2_ : string) -> i32{ addr := 0x1000 + 156 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int) -> i32) (fp))(raw_data(s1_), len(s1_), raw_data(s2_), len(s2_))} +StringFormat :: #force_inline proc "c" (buffer_ : ^i8 , bufferLength_ : int , format_ : cstring , _varargs_ : ..any) -> int { addr := 0x1000 + 158 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , cstring , ..any) -> int ) (fp))(buffer_, bufferLength_, format_, _varargs_)} +StringFormatTemporary :: #force_inline proc "c" (format_ : cstring , _varargs_ : ..any) -> ^i8 { addr := 0x1000 + 159 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( cstring , ..any) -> ^i8 ) (fp))(format_, _varargs_)} +StringFormatAppend :: #force_inline proc "c" (buffer_ : ^i8 , bufferLength_ : int , bufferPosition_ : ^int , format_ : cstring , _varargs_ : ..any) -> bool{ addr := 0x1000 + 161 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , ^int , cstring , ..any) -> bool) (fp))(buffer_, bufferLength_, bufferPosition_, format_, _varargs_)} +StringLength :: #force_inline proc "c" (string_ : ^i8 , end_ : u8 ) -> int { addr := 0x1000 + 163 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , u8 ) -> int ) (fp))(string_, end_)} +StringStartsWith :: #force_inline proc "c" (string_ : string, prefix_ : string, caseInsensitive_ : bool) -> bool{ addr := 0x1000 + 166 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int, ^u8, int, bool) -> bool) (fp))(raw_data(string_), len(string_), raw_data(prefix_), len(prefix_), caseInsensitive_)} +StringZeroTerminate :: #force_inline proc "c" (string_ : string) -> ^i8 { addr := 0x1000 + 167 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" (^u8, int) -> ^i8 ) (fp))(raw_data(string_), len(string_))} +CRTabs :: #force_inline proc "c" (n_ : i32) -> i32{ addr := 0x1000 + 168 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(n_)} +CRTacosf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 169 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTasinf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 170 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTatan2f :: #force_inline proc "c" (y_ : f32 , x_ : f32 ) -> f32 { addr := 0x1000 + 172 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 , f32 ) -> f32 ) (fp))(y_, x_)} +CRTatanf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 173 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTatoi :: #force_inline proc "c" (string_ : ^i8 ) -> i32{ addr := 0x1000 + 174 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 ) -> i32) (fp))(string_)} +CRTcalloc :: #force_inline proc "c" (num_ : int , size_ : int ) -> rawptr{ addr := 0x1000 + 175 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int , int ) -> rawptr) (fp))(num_, size_)} +CRTceil :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 176 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_)} +CRTceilf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 177 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTcosf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 178 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTexp :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 326 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_)} +CRTexp2f :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 327 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTfabs :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 179 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_)} +CRTfabsf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 344 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTfloor :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 181 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_)} +CRTfloorf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 182 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTfmodf :: #force_inline proc "c" (x_ : f32 , y_ : f32 ) -> f32 { addr := 0x1000 + 183 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 , f32 ) -> f32 ) (fp))(x_, y_)} +CRTfree :: #force_inline proc "c" (ptr_ : rawptr){ addr := 0x1000 + 184 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr)) (fp))(ptr_)} +CRTgetenv :: #force_inline proc "c" (name_ : ^i8 ) -> ^i8 { addr := 0x1000 + 185 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 ) -> ^i8 ) (fp))(name_)} +CRTisalpha :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 186 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_)} +CRTisdigit :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 187 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_)} +CRTisnanf :: #force_inline proc "c" (f_ : f32 ) -> bool{ addr := 0x1000 + 345 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> bool) (fp))(f_)} +CRTisspace :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 188 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_)} +CRTisupper :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 189 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_)} +CRTisxdigit :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 190 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_)} +CRTmalloc :: #force_inline proc "c" (size_ : int ) -> rawptr{ addr := 0x1000 + 191 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( int ) -> rawptr) (fp))(size_)} +CRTmemchr :: #force_inline proc "c" (_s_ : rawptr, _c_ : i32, n_ : int ) -> rawptr{ addr := 0x1000 + 192 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, i32, int ) -> rawptr) (fp))(_s_, _c_, n_)} +CRTmemcmp :: #force_inline proc "c" (s1_ : rawptr, s2_ : rawptr, n_ : int ) -> i32{ addr := 0x1000 + 193 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, rawptr, int ) -> i32) (fp))(s1_, s2_, n_)} +CRTmemcpy :: #force_inline proc "c" (dest_ : rawptr, src_ : rawptr, n_ : int ) -> rawptr{ addr := 0x1000 + 194 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, rawptr, int ) -> rawptr) (fp))(dest_, src_, n_)} +CRTmemmove :: #force_inline proc "c" (dest_ : rawptr, src_ : rawptr, n_ : int ) -> rawptr{ addr := 0x1000 + 195 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, rawptr, int ) -> rawptr) (fp))(dest_, src_, n_)} +CRTmemset :: #force_inline proc "c" (s_ : rawptr, c_ : i32, n_ : int ) -> rawptr{ addr := 0x1000 + 196 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, i32, int ) -> rawptr) (fp))(s_, c_, n_)} +CRTpowf :: #force_inline proc "c" (x_ : f32 , y_ : f32 ) -> f32 { addr := 0x1000 + 328 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 , f32 ) -> f32 ) (fp))(x_, y_)} +CRTqsort :: #force_inline proc "c" (_base_ : rawptr, nmemb_ : int , size_ : int , compar_ : CRTComparisonCallback){ addr := 0x1000 + 197 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( rawptr, int , int , CRTComparisonCallback)) (fp))(_base_, nmemb_, size_, compar_)} +CRTrealloc :: #force_inline proc "c" (ptr_ : rawptr, size_ : int ) -> rawptr{ addr := 0x1000 + 198 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( rawptr, int ) -> rawptr) (fp))(ptr_, size_)} +CRTsinf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 199 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTsnprintf :: #force_inline proc "c" (buffer_ : ^i8 , bufferSize_ : int , format_ : ^i8 , _varargs_ : ..any) -> i32{ addr := 0x1000 + 200 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int , ^i8 , ..any) -> i32) (fp))(buffer_, bufferSize_, format_, _varargs_)} +CRTsprintf :: #force_inline proc "c" (buffer_ : ^i8 , format_ : ^i8 , _varargs_ : ..any) -> i32{ addr := 0x1000 + 201 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 , ..any) -> i32) (fp))(buffer_, format_, _varargs_)} +CRTsqrt :: #force_inline proc "c" (x_ : f64 ) -> f64 { addr := 0x1000 + 202 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f64 ) -> f64 ) (fp))(x_)} +CRTsqrtf :: #force_inline proc "c" (x_ : f32 ) -> f32 { addr := 0x1000 + 203 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( f32 ) -> f32 ) (fp))(x_)} +CRTstrcat :: #force_inline proc "c" (dest_ : ^i8 , src_ : ^i8 ) -> ^i8 { addr := 0x1000 + 205 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 ) -> ^i8 ) (fp))(dest_, src_)} +CRTstrchr :: #force_inline proc "c" (s_ : ^i8 , c_ : i32) -> ^i8 { addr := 0x1000 + 206 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , i32) -> ^i8 ) (fp))(s_, c_)} +CRTstrcmp :: #force_inline proc "c" (s1_ : ^i8 , s2_ : ^i8 ) -> i32{ addr := 0x1000 + 207 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 ) -> i32) (fp))(s1_, s2_)} +CRTstrcpy :: #force_inline proc "c" (dest_ : ^i8 , src_ : ^i8 ) -> ^i8 { addr := 0x1000 + 208 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 ) -> ^i8 ) (fp))(dest_, src_)} +CRTstrdup :: #force_inline proc "c" (string_ : ^i8 ) -> ^i8 { addr := 0x1000 + 70 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 ) -> ^i8 ) (fp))(string_)} +CRTstrerror :: #force_inline proc "c" (errnum_ : i32) -> ^i8 { addr := 0x1000 + 209 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> ^i8 ) (fp))(errnum_)} +CRTstrlen :: #force_inline proc "c" (s_ : ^i8 ) -> int { addr := 0x1000 + 210 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 ) -> int ) (fp))(s_)} +CRTstrncmp :: #force_inline proc "c" (s1_ : ^i8 , s2_ : ^i8 , n_ : int ) -> i32{ addr := 0x1000 + 211 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 , int ) -> i32) (fp))(s1_, s2_, n_)} +CRTstrncpy :: #force_inline proc "c" (dest_ : ^i8 , src_ : ^i8 , n_ : int ) -> ^i8 { addr := 0x1000 + 212 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 , int ) -> ^i8 ) (fp))(dest_, src_, n_)} +CRTstrnlen :: #force_inline proc "c" (s_ : ^i8 , maxlen_ : int ) -> int { addr := 0x1000 + 213 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , int ) -> int ) (fp))(s_, maxlen_)} +CRTstrstr :: #force_inline proc "c" (haystack_ : ^i8 , needle_ : ^i8 ) -> ^i8 { addr := 0x1000 + 214 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^i8 ) -> ^i8 ) (fp))(haystack_, needle_)} +CRTstrtol :: #force_inline proc "c" (nptr_ : ^i8 , endptr_ : ^^i8 , base_ : i32) -> i64 { addr := 0x1000 + 215 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^^i8 , i32) -> i64 ) (fp))(nptr_, endptr_, base_)} +CRTstrtoul :: #force_inline proc "c" (nptr_ : ^i8 , endptr_ : ^^i8 , base_ : i32) -> u64 { addr := 0x1000 + 216 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^i8 , ^^i8 , i32) -> u64 ) (fp))(nptr_, endptr_, base_)} +CRTtolower :: #force_inline proc "c" (c_ : i32) -> i32{ addr := 0x1000 + 217 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( i32) -> i32) (fp))(c_)} +NewPanel :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Panel{ addr := 0x1000 + 219 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Panel) (fp))(parent_, flags_, cStyle_)} +NewSplitter :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Splitter{ addr := 0x1000 + 220 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Splitter) (fp))(parent_, flags_, cStyle_)} +NewButton :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, label_ : string = "") -> ^Button{ addr := 0x1000 + 221 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , ^u8, int) -> ^Button) (fp))(parent_, flags_, cStyle_, raw_data(label_), len(label_))} +NewChoice :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Choice{ addr := 0x1000 + 222 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Choice) (fp))(parent_, flags_, cStyle_)} +NewColorWell :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, colorRGB_ : u32 = 0) -> ^ColorWell{ addr := 0x1000 + 223 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , u32 ) -> ^ColorWell) (fp))(parent_, flags_, cStyle_, colorRGB_)} +NewTextDisplay :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, label_ : string = "") -> ^TextDisplay{ addr := 0x1000 + 224 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , ^u8, int) -> ^TextDisplay) (fp))(parent_, flags_, cStyle_, raw_data(label_), len(label_))} +NewIconDisplay :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, iconID_ : u32 = 0) -> ^IconDisplay{ addr := 0x1000 + 225 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , u32 ) -> ^IconDisplay) (fp))(parent_, flags_, cStyle_, iconID_)} +NewImageDisplay :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^ImageDisplay{ addr := 0x1000 + 226 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^ImageDisplay) (fp))(parent_, flags_, cStyle_)} +NewListView :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil, cItemStyle_ : cstring = nil, cHeaderItemStyle_ : cstring = nil, cFooterItemStyle_ : cstring = nil) -> ^ListView{ addr := 0x1000 + 227 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring , cstring , cstring , cstring ) -> ^ListView) (fp))(parent_, flags_, cStyle_, cItemStyle_, cHeaderItemStyle_, cFooterItemStyle_)} +NewTextbox :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Textbox{ addr := 0x1000 + 228 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Textbox) (fp))(parent_, flags_, cStyle_)} +NewCustomElement :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, cStyle_ : cstring = nil) -> ^Element{ addr := 0x1000 + 229 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , cstring ) -> ^Element) (fp))(parent_, flags_, cStyle_)} +NewWindow :: #force_inline proc "c" (instance_ : ^INSTANCE_TYPE, style_ : WindowStyle) -> ^Window{ addr := 0x1000 + 230 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^INSTANCE_TYPE, WindowStyle) -> ^Window) (fp))(instance_, style_)} +NewMenu :: #force_inline proc "c" (source_ : ^Element, flags_ : u64 = FLAGS_DEFAULT, userCallback_ : MenuCallbackFunction = nil, _context_ : Generic = nil, fixedWidth_ : i32 = 0, fixedHeight_ : i32 = 0) -> ^Menu{ addr := 0x1000 + 231 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 , MenuCallbackFunction, Generic, i32, i32) -> ^Menu) (fp))(source_, flags_, userCallback_, _context_, fixedWidth_, fixedHeight_)} +NewMenuItem :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 , label_ : string = "", callback_ : MenuCallbackFunction = nil, _context_ : Generic = nil){ addr := 0x1000 + 232 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, u64 , ^u8, int, MenuCallbackFunction, Generic)) (fp))(parent_, flags_, raw_data(label_), len(label_), callback_, _context_)} +NewMenuCommand :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 , label_ : string, command_ : ^Command){ addr := 0x1000 + 233 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, u64 , ^u8, int, ^Command)) (fp))(parent_, flags_, raw_data(label_), len(label_), command_)} +NewMenuColumn :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 = FLAGS_DEFAULT) -> ^Element{ addr := 0x1000 + 234 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 ) -> ^Element) (fp))(parent_, flags_)} +NewMenuSeparator :: #force_inline proc "c" (parent_ : ^Element){ addr := 0x1000 + 235 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element)) (fp))(parent_)} +NewSpacer :: #force_inline proc "c" (parent_ : ^Element, flags_ : u64 ) -> ^Element{ addr := 0x1000 + 236 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element, u64 ) -> ^Element) (fp))(parent_, flags_)} +NewTextPlan :: #force_inline proc "c" (properties_ : ^TextDisplayProperties, bounds_ : Rectangle, string_ : ^i8 , textRuns_ : ^TextRun, textRunCount_ : int , singleUse_ : bool) -> ^TextPlan{ addr := 0x1000 + 238 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^TextDisplayProperties, Rectangle, ^i8 , ^TextRun, int , bool) -> ^TextPlan) (fp))(properties_, bounds_, string_, textRuns_, textRunCount_, singleUse_)} +ElementDraw :: #force_inline proc "c" (element_ : ^Element, painter_ : ^Painter){ addr := 0x1000 + 240 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, ^Painter)) (fp))(element_, painter_)} +ElementFocus :: #force_inline proc "c" (element_ : ^Element, ensureVisible_ : bool = false){ addr := 0x1000 + 243 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, bool)) (fp))(element_, ensureVisible_)} +ElementSetDisabled :: #force_inline proc "c" (element_ : ^Element, disabled_ : bool = true){ addr := 0x1000 + 244 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, bool)) (fp))(element_, disabled_)} +ElementSetHidden :: #force_inline proc "c" (element_ : ^Element, hidden_ : bool = true){ addr := 0x1000 + 245 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, bool)) (fp))(element_, hidden_)} +ElementSetCallback :: #force_inline proc "c" (element_ : ^Element, callback_ : UICallbackFunction){ addr := 0x1000 + 246 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, UICallbackFunction)) (fp))(element_, callback_)} +ElementGetSize :: #force_inline proc "c" (element_ : ^Element, width_ : ^i32, height_ : ^i32){ addr := 0x1000 + 247 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, ^i32, ^i32)) (fp))(element_, width_, height_)} +ElementRepaint :: #force_inline proc "c" (element_ : ^Element, all_ : bool, region_ : Rectangle){ addr := 0x1000 + 248 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, bool, Rectangle)) (fp))(element_, all_, region_)} +ElementSetCellRange :: #force_inline proc "c" (element_ : ^Element, xFrom_ : i32, yFrom_ : i32, xTo_ : i32 = -1, yTo_ : i32 = -1){ addr := 0x1000 + 251 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, i32, i32, i32, i32)) (fp))(element_, xFrom_, yFrom_, xTo_, yTo_)} +ElementGetInsets :: #force_inline proc "c" (element_ : ^Element) -> Rectangle{ addr := 0x1000 + 253 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> Rectangle) (fp))(element_)} +ElementGetInsetSize :: #force_inline proc "c" (element_ : ^Element) -> Rectangle{ addr := 0x1000 + 254 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> Rectangle) (fp))(element_)} +ElementGetMetrics :: #force_inline proc "c" (element_ : ^Element) -> ThemeMetrics{ addr := 0x1000 + 105 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> ThemeMetrics) (fp))(element_)} +ElementGetPreferredSize :: #force_inline proc "c" (element_ : ^Element) -> Rectangle{ addr := 0x1000 + 255 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> Rectangle) (fp))(element_)} +ElementMove :: #force_inline proc "c" (element_ : ^Element, x_ : i32, y_ : i32, width_ : i32, height_ : i32){ addr := 0x1000 + 256 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element, i32, i32, i32, i32)) (fp))(element_, x_, y_, width_, height_)} +ElementGetLayoutParent :: #force_inline proc "c" (element_ : ^Element) -> ^Element{ addr := 0x1000 + 257 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> ^Element) (fp))(element_)} +ElementDestroy :: #force_inline proc "c" (element_ : ^Element){ addr := 0x1000 + 258 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element)) (fp))(element_)} +ElementDestroyContents :: #force_inline proc "c" (element_ : ^Element){ addr := 0x1000 + 259 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Element)) (fp))(element_)} +ElementStartAnimating :: #force_inline proc "c" (element_ : ^Element) -> bool{ addr := 0x1000 + 260 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Element) -> bool) (fp))(element_)} +WindowGetBounds :: #force_inline proc "c" (window_ : ^Window) -> Rectangle{ addr := 0x1000 + 265 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Window) -> Rectangle) (fp))(window_)} +WindowGetToolbar :: #force_inline proc "c" (window_ : ^Window) -> ^Element{ addr := 0x1000 + 266 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Window) -> ^Element) (fp))(window_)} +WindowSetIcon :: #force_inline proc "c" (window_ : ^Window, iconID_ : u32 ){ addr := 0x1000 + 267 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Window, u32 )) (fp))(window_, iconID_)} +WindowSetTitle :: #force_inline proc "c" (window_ : ^Window, title_ : string = ""){ addr := 0x1000 + 268 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Window, ^u8, int)) (fp))(window_, raw_data(title_), len(title_))} +MenuGetSource :: #force_inline proc "c" (menu_ : ^Menu) -> ^Element{ addr := 0x1000 + 269 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Menu) -> ^Element) (fp))(menu_)} +ButtonSetIcon :: #force_inline proc "c" (button_ : ^Button, iconID_ : u32 ){ addr := 0x1000 + 270 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, u32 )) (fp))(button_, iconID_)} +ButtonSetCheck :: #force_inline proc "c" (button_ : ^Button, checkState_ : CheckState = CHECK_CHECKED, sendUpdatedMessage_ : bool = true){ addr := 0x1000 + 271 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, CheckState, bool)) (fp))(button_, checkState_, sendUpdatedMessage_)} +ButtonGetCheck :: #force_inline proc "c" (button_ : ^Button) -> CheckState{ addr := 0x1000 + 272 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Button) -> CheckState) (fp))(button_)} +ButtonOnCommand :: #force_inline proc "c" (button_ : ^Button, callback_ : CommandCallbackFunction, command_ : ^Command = nil){ addr := 0x1000 + 273 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, CommandCallbackFunction, ^Command)) (fp))(button_, callback_, command_)} +ButtonSetCheckBuddy :: #force_inline proc "c" (button_ : ^Button, checkBuddy_ : ^Element){ addr := 0x1000 + 274 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Button, ^Element)) (fp))(button_, checkBuddy_)} +ButtonGetCheckBuddy :: #force_inline proc "c" (button_ : ^Button) -> ^Element{ addr := 0x1000 + 275 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Button) -> ^Element) (fp))(button_)} +TextboxFind :: #force_inline proc "c" (textbox_ : ^Textbox, string_ : string, line_ : ^i32 , byte_ : ^i32 , flags_ : u32 ) -> bool{ addr := 0x1000 + 277 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Textbox, ^u8, int, ^i32 , ^i32 , u32 ) -> bool) (fp))(textbox_, raw_data(string_), len(string_), line_, byte_, flags_)} +TextboxInsert :: #force_inline proc "c" (textbox_ : ^Textbox, string_ : string = "", sendUpdatedMessage_ : bool = true){ addr := 0x1000 + 278 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, ^u8, int, bool)) (fp))(textbox_, raw_data(string_), len(string_), sendUpdatedMessage_)} +TextboxGetContents :: #force_inline proc "c" (textbox_ : ^Textbox, bytes_ : ^int = nil) -> ^i8 { addr := 0x1000 + 279 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Textbox, ^int ) -> ^i8 ) (fp))(textbox_, bytes_)} +TextboxGetLineLength :: #force_inline proc "c" (textbox_ : ^Textbox, line_ : uint = 0) -> int { addr := 0x1000 + 280 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Textbox, uint ) -> int ) (fp))(textbox_, line_)} +TextboxGetSelection :: #force_inline proc "c" (textbox_ : ^Textbox, fromLine_ : ^i32 , fromByte_ : ^i32 , toLine_ : ^i32 , toByte_ : ^i32 ){ addr := 0x1000 + 281 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, ^i32 , ^i32 , ^i32 , ^i32 )) (fp))(textbox_, fromLine_, fromByte_, toLine_, toByte_)} +TextboxMoveCaret :: #force_inline proc "c" (textbox_ : ^Textbox, line_ : i32 , byte_ : i32 ){ addr := 0x1000 + 282 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, i32 , i32 )) (fp))(textbox_, line_, byte_)} +TextboxSetSelection :: #force_inline proc "c" (textbox_ : ^Textbox, fromLine_ : i32 , fromByte_ : i32 , toLine_ : i32 , toByte_ : i32 ){ addr := 0x1000 + 283 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, i32 , i32 , i32 , i32 )) (fp))(textbox_, fromLine_, fromByte_, toLine_, toByte_)} +TextboxSelectAll :: #force_inline proc "c" (textbox_ : ^Textbox){ addr := 0x1000 + 284 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox)) (fp))(textbox_)} +TextboxClear :: #force_inline proc "c" (textbox_ : ^Textbox, sendUpdatedMessage_ : bool){ addr := 0x1000 + 285 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, bool)) (fp))(textbox_, sendUpdatedMessage_)} +TextboxUseNumberOverlay :: #force_inline proc "c" (textbox_ : ^Textbox, defaultBehaviour_ : bool){ addr := 0x1000 + 286 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, bool)) (fp))(textbox_, defaultBehaviour_)} +TextboxUseBreadcrumbOverlay :: #force_inline proc "c" (textbox_ : ^Textbox){ addr := 0x1000 + 287 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox)) (fp))(textbox_)} +TextboxMoveCaretRelative :: #force_inline proc "c" (textbox_ : ^Textbox, flags_ : u32 ){ addr := 0x1000 + 118 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox, u32 )) (fp))(textbox_, flags_)} +TextboxEnsureCaretVisible :: #force_inline proc "c" (textbox_ : ^Textbox){ addr := 0x1000 + 119 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Textbox)) (fp))(textbox_)} +PanelSetBands :: #force_inline proc "c" (panel_ : ^Panel, columnCount_ : int , rowCount_ : int = 0, columns_ : ^PanelBand = nil, rows_ : ^PanelBand = nil){ addr := 0x1000 + 288 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Panel, int , int , ^PanelBand, ^PanelBand)) (fp))(panel_, columnCount_, rowCount_, columns_, rows_)} +PanelSwitchTo :: #force_inline proc "c" (panel_ : ^Panel, targetChild_ : ^Element, transitionType_ : TransitionType, destroyPreviousAfterTransitionCompletes_ : bool = false){ addr := 0x1000 + 289 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Panel, ^Element, TransitionType, bool)) (fp))(panel_, targetChild_, transitionType_, destroyPreviousAfterTransitionCompletes_)} +TextPlanGetWidth :: #force_inline proc "c" (plan_ : ^TextPlan) -> i32{ addr := 0x1000 + 290 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^TextPlan) -> i32) (fp))(plan_)} +TextPlanGetHeight :: #force_inline proc "c" (plan_ : ^TextPlan) -> i32{ addr := 0x1000 + 291 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^TextPlan) -> i32) (fp))(plan_)} +TextPlanGetLineCount :: #force_inline proc "c" (plan_ : ^TextPlan) -> int { addr := 0x1000 + 292 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^TextPlan) -> int ) (fp))(plan_)} +TextPlanDestroy :: #force_inline proc "c" (plan_ : ^TextPlan){ addr := 0x1000 + 293 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^TextPlan)) (fp))(plan_)} +TextDisplaySetContents :: #force_inline proc "c" (display_ : ^TextDisplay, contents_ : string = ""){ addr := 0x1000 + 294 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^TextDisplay, ^u8, int)) (fp))(display_, raw_data(contents_), len(contents_))} +ColorWellGetRGB :: #force_inline proc "c" (well_ : ^ColorWell) -> u32 { addr := 0x1000 + 304 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^ColorWell) -> u32 ) (fp))(well_)} +ColorWellSetRGB :: #force_inline proc "c" (well_ : ^ColorWell, colorRGB_ : u32 , sendChangedMessage_ : bool){ addr := 0x1000 + 305 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ColorWell, u32 , bool)) (fp))(well_, colorRGB_, sendChangedMessage_)} +ColorWellSetIndeterminate :: #force_inline proc "c" (well_ : ^ColorWell){ addr := 0x1000 + 306 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ColorWell)) (fp))(well_)} +ChoiceAddMenuItem :: #force_inline proc "c" (choice_ : ^Choice, item_ : Generic){ addr := 0x1000 + 307 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Choice, Generic)) (fp))(choice_, item_)} +ChoiceSetItem :: #force_inline proc "c" (choice_ : ^Choice, item_ : Generic, sendUpdatedMessage_ : bool = true){ addr := 0x1000 + 308 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^Choice, Generic, bool)) (fp))(choice_, item_, sendUpdatedMessage_)} +ChoiceGetItem :: #force_inline proc "c" (choice_ : ^Choice) -> Generic{ addr := 0x1000 + 309 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^Choice) -> Generic) (fp))(choice_)} +ListViewInsertGroup :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 , flags_ : u32 = FLAGS_DEFAULT){ addr := 0x1000 + 310 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 , u32 )) (fp))(view_, group_, flags_)} +ListViewInsert :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 , firstIndex_ : Generic, lastIndex_ : Generic, count_ : i64 = -1){ addr := 0x1000 + 311 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 , Generic, Generic, i64 )) (fp))(view_, group_, firstIndex_, lastIndex_, count_)} +ListViewRemove :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 , firstIndex_ : Generic, lastIndex_ : Generic, count_ : i64 = -1){ addr := 0x1000 + 312 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 , Generic, Generic, i64 )) (fp))(view_, group_, firstIndex_, lastIndex_, count_)} +ListViewRemoveAll :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 ){ addr := 0x1000 + 313 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 )) (fp))(view_, group_)} +ListViewGetIndex :: #force_inline proc "c" (view_ : ^ListView, item_ : ^Element) -> Generic{ addr := 0x1000 + 314 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); return ((proc "c" ( ^ListView, ^Element) -> Generic) (fp))(view_, item_)} +ListViewSetColumns :: #force_inline proc "c" (view_ : ^ListView, columns_ : ^ListViewColumn, columnCount_ : int ){ addr := 0x1000 + 315 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, ^ListViewColumn, int )) (fp))(view_, columns_, columnCount_)} +ListViewSetEmptyMessage :: #force_inline proc "c" (view_ : ^ListView, message_ : string = ""){ addr := 0x1000 + 262 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, ^u8, int)) (fp))(view_, raw_data(message_), len(message_))} +ListViewSelect :: #force_inline proc "c" (view_ : ^ListView, group_ : i32 , index_ : Generic){ addr := 0x1000 + 316 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView, i32 , Generic)) (fp))(view_, group_, index_)} +ListViewResetSearchBuffer :: #force_inline proc "c" (view_ : ^ListView){ addr := 0x1000 + 317 * size_of(int); fp := (rawptr(((^uintptr)(uintptr(addr)))^)); ((proc "c" ( ^ListView)) (fp))(view_)} diff --git a/core/sys/freebsd/constants.odin b/core/sys/freebsd/constants.odin new file mode 100644 index 000000000..3188b32d6 --- /dev/null +++ b/core/sys/freebsd/constants.odin @@ -0,0 +1,5 @@ +package sys_freebsd + +/* Get window size */ +TIOCGWINSZ :: 0x40087468 + diff --git a/core/sys/freebsd/syscalls.odin b/core/sys/freebsd/syscalls.odin index 83b51138a..96fd9ac3f 100644 --- a/core/sys/freebsd/syscalls.odin +++ b/core/sys/freebsd/syscalls.odin @@ -21,6 +21,7 @@ SYS_close : uintptr : 6 SYS_getpid : uintptr : 20 SYS_recvfrom : uintptr : 29 SYS_accept : uintptr : 30 +SYS_getpeername: uintptr : 31 SYS_getsockname: uintptr : 32 SYS_fcntl : uintptr : 92 SYS_fsync : uintptr : 95 @@ -202,26 +203,38 @@ accept_nil :: proc "contextless" (s: Fd) -> (Fd, Errno) { accept :: proc { accept_T, accept_nil } -// Get socket name. -// -// The getsockname() system call appeared in 4.2BSD. -getsockname :: proc "contextless" (s: Fd, sockaddr: ^$T) -> Errno { +getsockname_or_peername :: proc "contextless" (s: Fd, sockaddr: ^$T, is_peer: bool) -> Errno { // sockaddr must contain a valid pointer, or this will segfault because // we're telling the syscall that there's memory available to write to. addrlen: socklen_t = size_of(T) - result, ok := intrinsics.syscall_bsd(SYS_getsockname, + result, ok := intrinsics.syscall_bsd( + is_peer ? SYS_getpeername : SYS_getsockname, cast(uintptr)s, cast(uintptr)sockaddr, cast(uintptr)&addrlen) if !ok { - return cast(Errno)result + return cast(Errno)result } return nil } +// Get name of connected peer +// +// The getpeername() system call appeared in 4.2BSD. +getpeername :: proc "contextless" (s: Fd, sockaddr: ^$T) -> Errno { + return getsockname_or_peername(s, sockaddr, true) +} + +// Get socket name. +// +// The getsockname() system call appeared in 4.2BSD. +getsockname :: proc "contextless" (s: Fd, sockaddr: ^$T) -> Errno { + return getsockname_or_peername(s, sockaddr, false) +} + // Synchronize changes to a file. // // The fsync() system call appeared in 4.2BSD. diff --git a/core/sys/info/cpu_arm.odin b/core/sys/info/cpu_arm.odin index 960e55a56..8f5143394 100644 --- a/core/sys/info/cpu_arm.odin +++ b/core/sys/info/cpu_arm.odin @@ -40,9 +40,13 @@ CPU_Feature :: enum u64 { } CPU_Features :: distinct bit_set[CPU_Feature; u64] - -cpu_features: Maybe(CPU_Features) -cpu_name: Maybe(string) +CPU :: struct { + name: Maybe(string), + features: Maybe(CPU_Features), + physical_cores: int, + logical_cores: int, +} +cpu: CPU @(private) cpu_name_buf: [128]byte @@ -53,7 +57,7 @@ init_cpu_name :: proc "contextless" () { when ODIN_OS == .Darwin { if unix.sysctlbyname("machdep.cpu.brand_string", &cpu_name_buf) { - cpu_name = string(cstring(rawptr(&cpu_name_buf))) + cpu.name = string(cstring(rawptr(&cpu_name_buf))) generic = false } } @@ -61,10 +65,10 @@ init_cpu_name :: proc "contextless" () { if generic { when ODIN_ARCH == .arm64 { copy(cpu_name_buf[:], "ARM64") - cpu_name = string(cpu_name_buf[:len("ARM64")]) + cpu.name = string(cpu_name_buf[:len("ARM64")]) } else { copy(cpu_name_buf[:], "ARM") - cpu_name = string(cpu_name_buf[:len("ARM")]) + cpu.name = string(cpu_name_buf[:len("ARM")]) } } } diff --git a/core/sys/info/cpu_darwin.odin b/core/sys/info/cpu_darwin.odin new file mode 100644 index 000000000..c4a209f6d --- /dev/null +++ b/core/sys/info/cpu_darwin.odin @@ -0,0 +1,12 @@ +package sysinfo + +import "core:sys/unix" + +@(init, private) +init_cpu_core_count :: proc "contextless" () { + physical, logical: i64 + unix.sysctlbyname("hw.physicalcpu", &physical) + unix.sysctlbyname("hw.logicalcpu", &logical) + cpu.physical_cores = int(physical) + cpu.logical_cores = int(logical) +} diff --git a/core/sys/info/cpu_darwin_arm64.odin b/core/sys/info/cpu_darwin_arm64.odin index ffa60d1cb..aaeef9ad9 100644 --- a/core/sys/info/cpu_darwin_arm64.odin +++ b/core/sys/info/cpu_darwin_arm64.odin @@ -5,7 +5,7 @@ import "core:sys/unix" @(init, private) init_cpu_features :: proc "contextless" () { @(static) features: CPU_Features - defer cpu_features = features + defer cpu.features = features try_set :: proc "contextless" (name: cstring, feature: CPU_Feature) -> (ok: bool) { support: b32 diff --git a/core/sys/info/cpu_intel.odin b/core/sys/info/cpu_intel.odin index 95b53dda0..e8f07c732 100644 --- a/core/sys/info/cpu_intel.odin +++ b/core/sys/info/cpu_intel.odin @@ -3,12 +3,6 @@ package sysinfo import "base:intrinsics" -// cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) --- -cpuid :: intrinsics.x86_cpuid - -// xgetbv :: proc(cx: u32) -> (eax, edx: u32) --- -xgetbv :: intrinsics.x86_xgetbv - CPU_Feature :: enum u64 { aes, // AES hardware implementation (AES NI) adx, // Multi-precision add-carry instruction extensions @@ -23,6 +17,7 @@ CPU_Feature :: enum u64 { popcnt, // Hamming weight instruction POPCNT. rdrand, // RDRAND instruction (on-chip random number generator) rdseed, // RDSEED instruction (on-chip random number generator) + sha, // SHA Extensions (SHA-1, SHA-224, SHA-256) sse2, // Streaming SIMD extension 2 (always available on amd64) sse3, // Streaming SIMD extension 3 ssse3, // Supplemental streaming SIMD extension 3 @@ -48,12 +43,16 @@ CPU_Feature :: enum u64 { } CPU_Features :: distinct bit_set[CPU_Feature; u64] - -cpu_features: Maybe(CPU_Features) -cpu_name: Maybe(string) +CPU :: struct { + name: Maybe(string), + features: Maybe(CPU_Features), + physical_cores: int, // Initialized by cpu_.odin + logical_cores: int, // Initialized by cpu_.odin +} +cpu: CPU @(init, private) -init_cpu_features :: proc "c" () { +init_cpu_features :: proc "contextless" () { is_set :: #force_inline proc "c" (bit: u32, value: u32) -> bool { return (value>>bit) & 0x1 != 0 } @@ -87,7 +86,7 @@ init_cpu_features :: proc "c" () { when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { // xgetbv is an illegal instruction under FreeBSD 13, OpenBSD 7.1 and NetBSD 10 // return before probing further - cpu_features = set + cpu.features = set return } @@ -115,6 +114,7 @@ init_cpu_features :: proc "c" () { _, ebx7, ecx7, edx7 := cpuid(7, 0) try_set(&set, .bmi1, 3, ebx7) + try_set(&set, .sha, 29, ebx7) if os_supports_avx { try_set(&set, .avx2, 5, ebx7) } @@ -149,14 +149,14 @@ init_cpu_features :: proc "c" () { try_set(&set, .rdseed, 18, ebx7) try_set(&set, .adx, 19, ebx7) - cpu_features = set + cpu.features = set } @(private) _cpu_name_buf: [72]u8 @(init, private) -init_cpu_name :: proc "c" () { +init_cpu_name :: proc "contextless" () { number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0) if number_of_extended_ids < 0x8000_0004 { return @@ -177,5 +177,11 @@ init_cpu_name :: proc "c" () { for len(brand) > 0 && brand[len(brand) - 1] == 0 || brand[len(brand) - 1] == ' ' { brand = brand[:len(brand) - 1] } - cpu_name = brand + cpu.name = brand } + +// cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) --- +cpuid :: intrinsics.x86_cpuid + +// xgetbv :: proc(cx: u32) -> (eax, edx: u32) --- +xgetbv :: intrinsics.x86_xgetbv \ No newline at end of file diff --git a/core/sys/info/cpu_linux_arm.odin b/core/sys/info/cpu_linux_arm.odin index 6408decb7..6e8b1a634 100644 --- a/core/sys/info/cpu_linux_arm.odin +++ b/core/sys/info/cpu_linux_arm.odin @@ -2,11 +2,13 @@ #+build linux package sysinfo +import "base:runtime" import "core:sys/linux" import "core:strings" @(init, private) -init_cpu_features :: proc() { +init_cpu_features :: proc "contextless" () { + context = runtime.default_context() fd, err := linux.open("/proc/cpuinfo", {}) if err != .NONE { return } defer linux.close(fd) @@ -17,7 +19,7 @@ init_cpu_features :: proc() { if rerr != .NONE || n == 0 { return } features: CPU_Features - defer cpu_features = features + defer cpu.features = features str := string(buf[:n]) for line in strings.split_lines_iterator(&str) { diff --git a/core/sys/info/cpu_linux_intel.odin b/core/sys/info/cpu_linux_intel.odin new file mode 100644 index 000000000..af76a75e4 --- /dev/null +++ b/core/sys/info/cpu_linux_intel.odin @@ -0,0 +1,41 @@ +#+build i386, amd64 +#+build linux +package sysinfo + +import "base:runtime" +import "core:sys/linux" +import "core:strings" +import "core:strconv" + +@(init, private) +init_cpu_core_count :: proc "contextless" () { + context = runtime.default_context() + + fd, err := linux.open("/proc/cpuinfo", {}) + if err != .NONE { return } + defer linux.close(fd) + + // This is probably enough right? + buf: [4096]byte + n, rerr := linux.read(fd, buf[:]) + if rerr != .NONE || n == 0 { return } + + str := string(buf[:n]) + for line in strings.split_lines_iterator(&str) { + key, _, value := strings.partition(line, ":") + key = strings.trim_space(key) + value = strings.trim_space(value) + + if key == "cpu cores" { + if num_physical_cores, ok := strconv.parse_int(value); ok { + cpu.physical_cores = num_physical_cores + } + } + + if key == "siblings" { + if num_logical_cores, ok := strconv.parse_int(value); ok { + cpu.logical_cores = num_logical_cores + } + } + } +} \ No newline at end of file diff --git a/core/sys/info/cpu_linux_riscv64.odin b/core/sys/info/cpu_linux_riscv64.odin index 84f6134d4..e65e8a3d2 100644 --- a/core/sys/info/cpu_linux_riscv64.odin +++ b/core/sys/info/cpu_linux_riscv64.odin @@ -7,9 +7,9 @@ import "base:intrinsics" import "core:sys/linux" @(init, private) -init_cpu_features :: proc() { +init_cpu_features :: proc "contextless" () { _features: CPU_Features - defer cpu_features = _features + defer cpu.features = _features HWCAP_Bits :: enum u64 { I = 'I' - 'A', @@ -81,11 +81,11 @@ init_cpu_features :: proc() { } err := linux.riscv_hwprobe(raw_data(pairs), len(pairs), 0, nil, {}) if err != nil { - assert(err == .ENOSYS, "unexpected error from riscv_hwprobe()") + assert_contextless(err == .ENOSYS, "unexpected error from riscv_hwprobe()") return } - assert(pairs[0].key == .IMA_EXT_0) + assert_contextless(pairs[0].key == .IMA_EXT_0) exts := pairs[0].value.ima_ext_0 exts -= { .FD, .C, .V } _features += transmute(CPU_Features)exts @@ -97,7 +97,7 @@ init_cpu_features :: proc() { _features += { .Misaligned_Supported } } } else { - assert(pairs[1].key == .CPUPERF_0) + assert_contextless(pairs[1].key == .CPUPERF_0) if .FAST in pairs[1].value.cpu_perf_0 { _features += { .Misaligned_Supported, .Misaligned_Fast } } else if .UNSUPPORTED not_in pairs[1].value.cpu_perf_0 { @@ -108,6 +108,6 @@ init_cpu_features :: proc() { } @(init, private) -init_cpu_name :: proc() { - cpu_name = "RISCV64" +init_cpu_name :: proc "contextless" () { + cpu.name = "RISCV64" } diff --git a/core/sys/info/cpu_riscv64.odin b/core/sys/info/cpu_riscv64.odin index c3319c48c..64f2edfd3 100644 --- a/core/sys/info/cpu_riscv64.odin +++ b/core/sys/info/cpu_riscv64.odin @@ -95,6 +95,10 @@ CPU_Feature :: enum u64 { } CPU_Features :: distinct bit_set[CPU_Feature; u64] - -cpu_features: Maybe(CPU_Features) -cpu_name: Maybe(string) +CPU :: struct { + name: Maybe(string), + features: Maybe(CPU_Features), + physical_cores: int, + logical_cores: int, +} +cpu: CPU \ No newline at end of file diff --git a/core/sys/info/cpu_windows.odin b/core/sys/info/cpu_windows.odin new file mode 100644 index 000000000..72d79f9a7 --- /dev/null +++ b/core/sys/info/cpu_windows.odin @@ -0,0 +1,31 @@ +package sysinfo + +import sys "core:sys/windows" +import "base:intrinsics" +import "base:runtime" + +@(init, private) +init_cpu_core_count :: proc "contextless" () { + context = runtime.default_context() + + infos: []sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION + defer delete(infos) + + returned_length: sys.DWORD + // Query for the required buffer size. + if ok := sys.GetLogicalProcessorInformation(raw_data(infos), &returned_length); !ok { + infos = make([]sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returned_length / size_of(sys.SYSTEM_LOGICAL_PROCESSOR_INFORMATION)) + } + + // If it still doesn't work, return + if ok := sys.GetLogicalProcessorInformation(raw_data(infos), &returned_length); !ok { + return + } + + for info in infos { + #partial switch info.Relationship { + case .RelationProcessorCore: cpu.physical_cores += 1 + case .RelationNumaNode: cpu.logical_cores += int(intrinsics.count_ones(info.ProcessorMask)) + } + } +} \ No newline at end of file diff --git a/core/sys/info/doc.odin b/core/sys/info/doc.odin index 2fd34b864..2a4f71642 100644 --- a/core/sys/info/doc.odin +++ b/core/sys/info/doc.odin @@ -26,13 +26,14 @@ Example: import si "core:sys/info" main :: proc() { - fmt.printfln("Odin: %v", ODIN_VERSION) - fmt.printfln("OS: %v", si.os_version.as_string) - fmt.printfln("OS: %#v", si.os_version) - fmt.printfln("CPU: %v", si.cpu_name) - fmt.printfln("RAM: %#.1M", si.ram.total_ram) + fmt.printfln("Odin: %v", ODIN_VERSION) + fmt.printfln("OS: %v", si.os_version.as_string) + fmt.printfln("OS: %#v", si.os_version) + fmt.printfln("CPU: %v", si.cpu.name) + fmt.printfln("CPU cores: %vc/%vt", si.cpu.physical_cores, si.cpu.logical_cores) + fmt.printfln("RAM: %#.1M", si.ram.total_ram) - // fmt.printfln("Features: %v", si.cpu_features) + // fmt.printfln("Features: %v", si.cpu.features) // fmt.printfln("MacOS version: %v", si.macos_version) fmt.println() diff --git a/core/sys/info/platform_bsd.odin b/core/sys/info/platform_bsd.odin index 6bb32cd3d..2f8d7f5bb 100644 --- a/core/sys/info/platform_bsd.odin +++ b/core/sys/info/platform_bsd.odin @@ -10,7 +10,9 @@ import "base:runtime" version_string_buf: [1024]u8 @(init, private) -init_os_version :: proc () { +init_os_version :: proc "contextless" () { + context = runtime.default_context() + when ODIN_OS == .NetBSD { os_version.platform = .NetBSD } else { @@ -66,7 +68,7 @@ init_os_version :: proc () { } @(init, private) -init_ram :: proc() { +init_ram :: proc "contextless" () { // Retrieve RAM info using `sysctl` mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64} mem_size: u64 diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin index 7dc49bcd1..07c26ec28 100644 --- a/core/sys/info/platform_darwin.odin +++ b/core/sys/info/platform_darwin.odin @@ -1,5 +1,7 @@ package sysinfo +import "base:runtime" + import "core:strconv" import "core:strings" import "core:sys/unix" @@ -9,7 +11,8 @@ import NS "core:sys/darwin/Foundation" version_string_buf: [1024]u8 @(init, private) -init_platform :: proc() { +init_platform :: proc "contextless" () { + context = runtime.default_context() ws :: strings.write_string wi :: strings.write_int @@ -28,12 +31,13 @@ init_platform :: proc() { macos_version = {int(version.majorVersion), int(version.minorVersion), int(version.patchVersion)} - when ODIN_PLATFORM_SUBTARGET == .iOS { + when ODIN_PLATFORM_SUBTARGET_IOS { os_version.platform = .iOS ws(&b, "iOS") } else { os_version.platform = .MacOS switch version.majorVersion { + case 26: ws(&b, "macOS Tahoe") case 15: ws(&b, "macOS Sequoia") case 14: ws(&b, "macOS Sonoma") case 13: ws(&b, "macOS Ventura") diff --git a/core/sys/info/platform_freebsd.odin b/core/sys/info/platform_freebsd.odin index b26fb7875..eb39769de 100644 --- a/core/sys/info/platform_freebsd.odin +++ b/core/sys/info/platform_freebsd.odin @@ -9,7 +9,9 @@ import "base:runtime" version_string_buf: [1024]u8 @(init, private) -init_os_version :: proc () { +init_os_version :: proc "contextless" () { + context = runtime.default_context() + os_version.platform = .FreeBSD kernel_version_buf: [1024]u8 @@ -68,7 +70,7 @@ init_os_version :: proc () { } @(init, private) -init_ram :: proc() { +init_ram :: proc "contextless" () { // Retrieve RAM info using `sysctl` mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM} mem_size: u64 diff --git a/core/sys/info/platform_linux.odin b/core/sys/info/platform_linux.odin index 45efc3329..43cd580c1 100644 --- a/core/sys/info/platform_linux.odin +++ b/core/sys/info/platform_linux.odin @@ -1,6 +1,7 @@ package sysinfo import "base:intrinsics" +import "base:runtime" import "core:strconv" import "core:strings" @@ -10,15 +11,21 @@ import "core:sys/linux" version_string_buf: [1024]u8 @(init, private) -init_os_version :: proc () { +init_os_version :: proc "contextless" () { + context = runtime.default_context() + os_version.platform = .Linux b := strings.builder_from_bytes(version_string_buf[:]) // Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS` - { + pretty_parse: { fd, errno := linux.open("/etc/os-release", {}) - assert(errno == .NONE, "Failed to read /etc/os-release") + if errno != .NONE { + strings.write_string(&b, "Unknown Linux Distro") + break pretty_parse + } + defer { cerrno := linux.close(fd) assert(cerrno == .NONE, "Failed to close the file descriptor") @@ -26,7 +33,10 @@ init_os_version :: proc () { os_release_buf: [2048]u8 n, read_errno := linux.read(fd, os_release_buf[:]) - assert(read_errno == .NONE, "Failed to read data from /etc/os-release") + if read_errno != .NONE { + strings.write_string(&b, "Unknown Linux Distro") + break pretty_parse + } release := string(os_release_buf[:n]) // Search the line in the file until we find "PRETTY_NAME=" @@ -59,7 +69,7 @@ init_os_version :: proc () { os_version.as_string = strings.to_string(b) // Parse the Linux version out of the release string - { + version_loop: { version_num, _, version_suffix := strings.partition(release_str, "-") os_version.version = version_suffix @@ -72,11 +82,11 @@ init_os_version :: proc () { case 0: dst = &os_version.major case 1: dst = &os_version.minor case 2: dst = &os_version.patch - case: break + case: break version_loop } num, ok := strconv.parse_int(part) - if !ok { break } + if !ok { break version_loop } dst^ = num } @@ -84,11 +94,11 @@ init_os_version :: proc () { } @(init, private) -init_ram :: proc() { +init_ram :: proc "contextless" () { // Retrieve RAM info using `sysinfo` sys_info: linux.Sys_Info errno := linux.sysinfo(&sys_info) - assert(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!") + assert_contextless(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!") ram = RAM{ total_ram = int(sys_info.totalram) * int(sys_info.mem_unit), free_ram = int(sys_info.freeram) * int(sys_info.mem_unit), diff --git a/core/sys/info/platform_windows.odin b/core/sys/info/platform_windows.odin index 4c00ddadf..ff8ebe2ee 100644 --- a/core/sys/info/platform_windows.odin +++ b/core/sys/info/platform_windows.odin @@ -12,7 +12,9 @@ import "base:runtime" version_string_buf: [1024]u8 @(init, private) -init_os_version :: proc () { +init_os_version :: proc "contextless" () { + context = runtime.default_context() + /* NOTE(Jeroen): `GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10. @@ -43,6 +45,7 @@ init_os_version :: proc () { os_version.minor = int(osvi.dwMinorVersion) os_version.build[0] = int(osvi.dwBuildNumber) + b := strings.builder_from_bytes(version_string_buf[:]) strings.write_string(&b, "Windows ") @@ -259,7 +262,7 @@ init_os_version :: proc () { } @(init, private) -init_ram :: proc() { +init_ram :: proc "contextless" () { state: sys.MEMORYSTATUSEX state.dwLength = size_of(state) @@ -276,10 +279,11 @@ init_ram :: proc() { } @(init, private) -init_gpu_info :: proc() { - +init_gpu_info :: proc "contextless" () { GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\" + context = runtime.default_context() + gpu_list: [dynamic]GPU gpu_index: int @@ -324,8 +328,8 @@ read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok status := sys.RegGetValueW( hkey, - &key_name_wide[0], - &val_name_wide[0], + cstring16(&key_name_wide[0]), + cstring16(&val_name_wide[0]), sys.RRF_RT_REG_SZ, nil, raw_data(result_wide[:]), @@ -359,8 +363,8 @@ read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool result_size := sys.DWORD(size_of(i32)) status := sys.RegGetValueW( hkey, - &key_name_wide[0], - &val_name_wide[0], + cstring16(&key_name_wide[0]), + cstring16(&val_name_wide[0]), sys.RRF_RT_REG_DWORD, nil, &res, @@ -386,8 +390,8 @@ read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool result_size := sys.DWORD(size_of(i64)) status := sys.RegGetValueW( hkey, - &key_name_wide[0], - &val_name_wide[0], + cstring16(&key_name_wide[0]), + cstring16(&val_name_wide[0]), sys.RRF_RT_REG_QWORD, nil, &res, diff --git a/core/sys/info/sysinfo.odin b/core/sys/info/sysinfo.odin index f624a1718..75cc237c6 100644 --- a/core/sys/info/sysinfo.odin +++ b/core/sys/info/sysinfo.odin @@ -1,6 +1,6 @@ package sysinfo -when !(ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64) { +when !(ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 || ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32) { #assert(false, "This package is unsupported on this architecture.") } diff --git a/core/sys/kqueue/kqueue.odin b/core/sys/kqueue/kqueue.odin index 56be1cf7a..25ee9bdce 100644 --- a/core/sys/kqueue/kqueue.odin +++ b/core/sys/kqueue/kqueue.odin @@ -2,7 +2,7 @@ package kqueue when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin index 4493ea767..64cdd2208 100644 --- a/core/sys/linux/bits.odin +++ b/core/sys/linux/bits.odin @@ -1,5 +1,10 @@ package linux +import "base:intrinsics" + +@(private) +log2 :: intrinsics.constant_log2 + /* Represents an error returned by most of syscalls @@ -574,7 +579,7 @@ Inotify_Event_Bits :: enum u32 { /* Bits for Mem_Protection bitfield */ -Mem_Protection_Bits :: enum{ +Mem_Protection_Bits :: enum { READ = 0, WRITE = 1, EXEC = 2, @@ -589,11 +594,13 @@ Mem_Protection_Bits :: enum{ /* Bits for Map_Flags + + See `constants.odin` for `MAP_SHARED_VALIDATE` and `MAP_HUGE_16KB`, et al. */ Map_Flags_Bits :: enum { SHARED = 0, PRIVATE = 1, - SHARED_VALIDATE = 2, + DROPPABLE = 3, FIXED = 4, ANONYMOUS = 5, // platform-dependent section start @@ -1611,36 +1618,39 @@ PER_HPUX :: 0x0010 PER_MASK :: 0x00ff /* - Bits for access modes for shared memory + Bits for SystemV IPC flags. + + In this enum, access modes are common for any shared memory. Prefixed + entries (i.e. `IPC_` or `SHM_`) denote flags, where `IPC_` are common flags + for all SystemV IPC primitives, and `SHM_`, `SEM_` and `MSG_` are specific + to shared memory segments, semaphores and message queues respectively. + + These bits overlap, because they are meant to be used within the + context of specific procedures. Creation flags, used for `*get` procedures, + and usage flags used by all other IPC procedures. Do not mix creation and + usage flags, as well as flags prefixed differently (excluding `IPC_` + prefix). */ -IPC_Mode_Bits :: enum { +IPC_Flags_Bits :: enum { + // Access modes for shared memory. WROTH = 1, RDOTH = 2, WRGRP = 4, RDGRP = 5, WRUSR = 7, RDUSR = 8, - DEST = 9, - LOCKED = 10, -} - -/* - Shared memory flags bits -*/ -IPC_Flags_Bits :: enum { + // Creation flags for shared memory. IPC_CREAT = 9, IPC_EXCL = 10, - IPC_NOWAIT = 11, - // Semaphore - SEM_UNDO = 9, - // Shared memory SHM_HUGETLB = 11, SHM_NORESERVE = 12, + // Usage flags for shared memory. + IPC_NOWAIT = 11, + SEM_UNDO = 9, SHM_RDONLY = 12, SHM_RND = 13, SHM_REMAP = 14, SHM_EXEC = 15, - // Message queue MSG_NOERROR = 12, MSG_EXCEPT = 13, MSG_COPY = 14, @@ -1828,7 +1838,7 @@ Clock_Id :: enum { Bits for POSIX interval timer flags. */ ITimer_Flags_Bits :: enum { - ABSTIME = 1, + ABSTIME = 0, } /* @@ -1839,22 +1849,23 @@ EPoll_Flags_Bits :: enum { } EPoll_Event_Kind :: enum u32 { - IN = 0x001, - PRI = 0x002, - OUT = 0x004, - RDNORM = 0x040, - RDBAND = 0x080, - WRNORM = 0x100, - WRBAND = 0x200, - MSG = 0x400, - ERR = 0x008, - HUP = 0x010, - RDHUP = 0x2000, - EXCLUSIVE = 1<<28, - WAKEUP = 1<<29, - ONESHOT = 1<<30, - ET = 1<<31, + IN = log2(0x001), + PRI = log2(0x002), + OUT = log2(0x004), + RDNORM = log2(0x040), + RDBAND = log2(0x080), + WRNORM = log2(0x100), + WRBAND = log2(0x200), + MSG = log2(0x400), + ERR = log2(0x008), + HUP = log2(0x010), + RDHUP = log2(0x2000), + EXCLUSIVE = log2(1<<28), + WAKEUP = log2(1<<29), + ONESHOT = log2(1<<30), + ET = log2(1<<31), } +EPoll_Event_Set :: bit_set[EPoll_Event_Kind; u32] EPoll_Ctl_Opcode :: enum i32 { ADD = 1, diff --git a/core/sys/linux/constants.odin b/core/sys/linux/constants.odin index b3bbcafb3..ceab17f6d 100644 --- a/core/sys/linux/constants.odin +++ b/core/sys/linux/constants.odin @@ -373,3 +373,25 @@ PTRACE_SECCOMP_GET_FILTER :: PTrace_Seccomp_Get_Filter_Type(.SECCOMP_GET_FIL PTRACE_SECCOMP_GET_METADATA :: PTrace_Seccomp_Get_Metadata_Type(.SECCOMP_GET_METADATA) PTRACE_GET_SYSCALL_INFO :: PTrace_Get_Syscall_Info_Type(.GET_SYSCALL_INFO) PTRACE_GET_RSEQ_CONFIGURATION :: PTrace_Get_RSeq_Configuration_Type(.GET_RSEQ_CONFIGURATION) + +MAP_SHARED_VALIDATE :: Map_Flags{.SHARED, .PRIVATE} + +MAP_HUGE_SHIFT :: 26 +MAP_HUGE_MASK :: 63 + +MAP_HUGE_16KB :: transmute(Map_Flags)(u32(14) << MAP_HUGE_SHIFT) +MAP_HUGE_64KB :: transmute(Map_Flags)(u32(16) << MAP_HUGE_SHIFT) +MAP_HUGE_512KB :: transmute(Map_Flags)(u32(19) << MAP_HUGE_SHIFT) +MAP_HUGE_1MB :: transmute(Map_Flags)(u32(20) << MAP_HUGE_SHIFT) +MAP_HUGE_2MB :: transmute(Map_Flags)(u32(21) << MAP_HUGE_SHIFT) +MAP_HUGE_8MB :: transmute(Map_Flags)(u32(23) << MAP_HUGE_SHIFT) +MAP_HUGE_16MB :: transmute(Map_Flags)(u32(24) << MAP_HUGE_SHIFT) +MAP_HUGE_32MB :: transmute(Map_Flags)(u32(25) << MAP_HUGE_SHIFT) +MAP_HUGE_256MB :: transmute(Map_Flags)(u32(28) << MAP_HUGE_SHIFT) +MAP_HUGE_512MB :: transmute(Map_Flags)(u32(29) << MAP_HUGE_SHIFT) +MAP_HUGE_1GB :: transmute(Map_Flags)(u32(30) << MAP_HUGE_SHIFT) +MAP_HUGE_2GB :: transmute(Map_Flags)(u32(31) << MAP_HUGE_SHIFT) +MAP_HUGE_16GB :: transmute(Map_Flags)(u32(34) << MAP_HUGE_SHIFT) + +/* Get window size */ +TIOCGWINSZ :: 0x5413 diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin index 532c1ff5f..deb22726f 100644 --- a/core/sys/linux/sys.odin +++ b/core/sys/linux/sys.odin @@ -1,3 +1,4 @@ +#+build linux #+no-instrumentation package linux @@ -212,7 +213,7 @@ rt_sigreturn :: proc "c" () -> ! { /* Alter an action taken by a process. */ -rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action($T), old_sigaction: ^Sig_Action) -> Errno { +rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action($T), old_sigaction: ^Sig_Action($U)) -> Errno { // NOTE(jason): It appears that the restorer is required for i386 and amd64 when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 { sigaction.flags += {.RESTORER} @@ -1412,7 +1413,7 @@ umask :: proc "contextless" (mask: Mode) -> Mode { Available since Linux 1.0. */ gettimeofday :: proc "contextless" (tv: ^Time_Val) -> (Errno) { - ret := syscall(SYS_gettimeofday, tv) + ret := syscall(SYS_gettimeofday, tv, rawptr(nil)) return Errno(-ret) } diff --git a/core/sys/linux/syscall_arm64.odin b/core/sys/linux/syscall_arm64.odin index da8eb45da..6f1c93f83 100644 --- a/core/sys/linux/syscall_arm64.odin +++ b/core/sys/linux/syscall_arm64.odin @@ -317,5 +317,18 @@ SYS_futex_waitv :: uintptr(449) SYS_set_mempolicy_home_node :: uintptr(450) SYS_cachestat :: uintptr(451) SYS_fchmodat2 :: uintptr(452) - +SYS_map_shadow_stack :: uintptr(453) +SYS_futex_wake :: uintptr(454) +SYS_futex_wait :: uintptr(455) +SYS_futex_requeue :: uintptr(456) +SYS_statmount :: uintptr(457) +SYS_listmount :: uintptr(458) +SYS_lsm_get_self_attr :: uintptr(459) +SYS_lsm_set_self_attr :: uintptr(460) +SYS_lsm_list_modules :: uintptr(461) +SYS_mseal :: uintptr(462) +SYS_setxattrat :: uintptr(463) +SYS_getxattrat :: uintptr(464) +SYS_listxattrat :: uintptr(465) +SYS_removexattrat :: uintptr(466) diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin index dcc72f72b..c2948c36e 100644 --- a/core/sys/linux/types.odin +++ b/core/sys/linux/types.odin @@ -288,7 +288,7 @@ Rename_Flags :: bit_set[Rename_Flags_Bits; u32] /* Directory entry record. - Recommended iterate these with `dirent_iterator()`, + Recommended to iterate these with `dirent_iterate_buf()`, and obtain the name via `dirent_name()`. */ Dirent :: struct { @@ -368,6 +368,8 @@ Mem_Protection :: bit_set[Mem_Protection_Bits; i32] /* Flags for mmap. + + See `constants.odin` for `MAP_SHARED_VALIDATE` and `MAP_HUGE_16KB`, et al. */ Map_Flags :: bit_set[Map_Flags_Bits; i32] @@ -935,17 +937,12 @@ IO_Vec :: struct { } /* - Access mode for shared memory -*/ -IPC_Mode :: bit_set[IPC_Mode_Bits; u32] - -/* - Flags used by IPC objects + Access modes and flags used by SystemV IPC procedures. */ IPC_Flags :: bit_set[IPC_Flags_Bits; i16] /* - Permissions for IPC objects + Permissions for SystemV IPC primitives. */ IPC_Perm :: struct { key: Key, @@ -953,7 +950,7 @@ IPC_Perm :: struct { gid: u32, cuid: u32, cgid: u32, - mode: IPC_Mode, + mode: IPC_Flags, // Only contains mode flags. seq: u16, _: [2 + 2*size_of(int)]u8, } @@ -1450,7 +1447,7 @@ EPoll_Data :: struct #raw_union { } EPoll_Event :: struct #packed { - events: EPoll_Event_Kind, + events: EPoll_Event_Set, data: EPoll_Data, } diff --git a/core/sys/linux/wrappers.odin b/core/sys/linux/wrappers.odin index ab1992a57..53eb80f86 100644 --- a/core/sys/linux/wrappers.odin +++ b/core/sys/linux/wrappers.odin @@ -54,22 +54,45 @@ WCOREDUMP :: #force_inline proc "contextless" (s: u32) -> bool { // TODO: sigaddset etc -/// Iterate the results of getdents -/// Only iterates as much data as loaded in the buffer -/// In case you need to iterate *all* files in a directory -/// consider using dirent_get_iterate -/// -/// Example of using dirent_iterate_buf -/// // Get dirents into a buffer -/// buf: [128]u8 -/// sys.getdents(dirfd, buf[:]) -/// // Print the names of the files -/// for dir in sys.dirent_iterate_buf(buf[:], &offs) { -/// name := sys.dirent_name(dir) -/// fmt.println(name) -/// } -/// This function doesn't automatically make a request -/// for the buffer to be refilled +/* +Iterate the results of `getdents()`. + +This procedure extracts a directory entry from `buf` at the offset `offs`. +`offs` will be modified to store an offset to the possible next directory entry +in `buf`. The procedure only iterates as much data as loaded in the buffer and +does not automatically make a request for the buffer to be refilled. + +Inputs: +- buf: A byte buffer with data from `getdents()` +- offs: An offset to the next possible directory entry in `buf` + +Returns: +- A pointer to a directory entry in `buf`, or `nil` +- A bool value denoting if a valid directory entry is returned + +Example: + + import "core:fmt" + import "core:sys/linux" + + print_names :: proc(dirfd: linux.Fd) { + // Get dirents into a buffer. + buf: [128]u8 + // Loop until there are no more entries. + for { + written, err := linux.getdents(dirfd, buf[:]) + if err != .NONE || written == 0 { + break + } + // Print the names of the files. + offset : int + for dir in linux.dirent_iterate_buf(buf[:written], &offset) { + name := linux.dirent_name(dir) + fmt.println(name) + } + } + } +*/ dirent_iterate_buf :: proc "contextless" (buf: []u8, offs: ^int) -> (d: ^Dirent, cont: bool) { // Stopped iterating when there's no space left if offs^ >= len(buf) { @@ -82,8 +105,17 @@ dirent_iterate_buf :: proc "contextless" (buf: []u8, offs: ^int) -> (d: ^Dirent, return dirent, true } -/// Obtain the name of dirent as a string -/// The lifetime of the string is bound to the lifetime of the provided dirent structure +/* +Obtain the name of dirent as a string. + +The lifetime of the returned string is bound to the lifetime of the provided dirent structure. + +Inputs: +- dirent: A directory entry + +Returns: +- A name of the entry +*/ dirent_name :: proc "contextless" (dirent: ^Dirent) -> string #no_bounds_check { str := ([^]u8)(&dirent.name) // Dirents are aligned to 8 bytes, so there is guaranteed to be a null @@ -93,10 +125,10 @@ dirent_name :: proc "contextless" (dirent: ^Dirent) -> string #no_bounds_check { trunc := min(str_size, 8) str_size -= trunc for _ in 0.. pton_result --- } diff --git a/core/sys/posix/dirent.odin b/core/sys/posix/dirent.odin index 1394f6b9e..cf15dada4 100644 --- a/core/sys/posix/dirent.odin +++ b/core/sys/posix/dirent.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/dlfcn.odin b/core/sys/posix/dlfcn.odin index e84b29d79..6c96b0079 100644 --- a/core/sys/posix/dlfcn.odin +++ b/core/sys/posix/dlfcn.odin @@ -4,11 +4,14 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { foreign import lib "system:dl" } else { - foreign import lib "system:c" + foreign import lib { + "system:c", + "system:dl", + } } // dlfcn.h - dynamic linking diff --git a/core/sys/posix/fcntl.odin b/core/sys/posix/fcntl.odin index bc0b5b5ba..db095c418 100644 --- a/core/sys/posix/fcntl.odin +++ b/core/sys/posix/fcntl.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/fnmatch.odin b/core/sys/posix/fnmatch.odin index 04c3d2888..efe179324 100644 --- a/core/sys/posix/fnmatch.odin +++ b/core/sys/posix/fnmatch.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/glob.odin b/core/sys/posix/glob.odin index fb90b7546..530481587 100644 --- a/core/sys/posix/glob.odin +++ b/core/sys/posix/glob.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/grp.odin b/core/sys/posix/grp.odin index 3694308a0..8e8e69fc2 100644 --- a/core/sys/posix/grp.odin +++ b/core/sys/posix/grp.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/langinfo.odin b/core/sys/posix/langinfo.odin index 1fddfe280..195de650d 100644 --- a/core/sys/posix/langinfo.odin +++ b/core/sys/posix/langinfo.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/libgen.odin b/core/sys/posix/libgen.odin index 2354bf70d..aa2effd72 100644 --- a/core/sys/posix/libgen.odin +++ b/core/sys/posix/libgen.odin @@ -2,7 +2,7 @@ package posix when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/monetary.odin b/core/sys/posix/monetary.odin index a444bff09..2e4105881 100644 --- a/core/sys/posix/monetary.odin +++ b/core/sys/posix/monetary.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/net_if.odin b/core/sys/posix/net_if.odin index 774d11b72..182a049d1 100644 --- a/core/sys/posix/net_if.odin +++ b/core/sys/posix/net_if.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/netdb.odin b/core/sys/posix/netdb.odin index ff1cb9d4c..f2f83875f 100644 --- a/core/sys/posix/netdb.odin +++ b/core/sys/posix/netdb.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/netinet_in.odin b/core/sys/posix/netinet_in.odin index ec05915de..4b74b87f0 100644 --- a/core/sys/posix/netinet_in.odin +++ b/core/sys/posix/netinet_in.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/poll.odin b/core/sys/posix/poll.odin index 44ec767a6..a9e582b51 100644 --- a/core/sys/posix/poll.odin +++ b/core/sys/posix/poll.odin @@ -6,7 +6,7 @@ import "base:intrinsics" import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/posix.odin b/core/sys/posix/posix.odin index d56217407..3dcf36a5e 100644 --- a/core/sys/posix/posix.odin +++ b/core/sys/posix/posix.odin @@ -31,7 +31,7 @@ Unimplemented headers: - iso646.h | Impossible - math.h | See `core:c/libc` - mqueue.h | Targets don't seem to have implemented it -- regex.h | See `core:regex` +- regex.h | See `core:text/regex` - search.h | Not useful in Odin - spawn.h | Use `fork`, `execve`, etc. - stdarg.h | See `core:c/libc` @@ -53,6 +53,8 @@ import "base:intrinsics" import "core:c" +IS_SUPPORTED :: _IS_SUPPORTED + result :: enum c.int { // Use `errno` and `strerror` for more information. FAIL = -1, diff --git a/core/sys/posix/posix_other.odin b/core/sys/posix/posix_other.odin new file mode 100644 index 000000000..88542c56b --- /dev/null +++ b/core/sys/posix/posix_other.odin @@ -0,0 +1,10 @@ +#+build !linux +#+build !darwin +#+build !netbsd +#+build !openbsd +#+build !freebsd +#+build !haiku +package posix + +_IS_SUPPORTED :: false + diff --git a/core/sys/posix/posix_unix.odin b/core/sys/posix/posix_unix.odin new file mode 100644 index 000000000..51580a655 --- /dev/null +++ b/core/sys/posix/posix_unix.odin @@ -0,0 +1,5 @@ +#+build linux, darwin, netbsd, openbsd, freebsd, haiku +package posix + +_IS_SUPPORTED :: true + diff --git a/core/sys/posix/pthread.odin b/core/sys/posix/pthread.odin index 36a3cd7b3..733725e2c 100644 --- a/core/sys/posix/pthread.odin +++ b/core/sys/posix/pthread.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .Linux { foreign import lib "system:pthread" } else { @@ -124,7 +124,7 @@ foreign lib { [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getscope.html ]] */ - pthread_attr_setscope :: proc(attr: ^pthread_attr_t, contentionscope: ^Thread_Scope) -> Errno --- + pthread_attr_setscope :: proc(attr: ^pthread_attr_t, contentionscope: Thread_Scope) -> Errno --- /* Get the area of storage to be used for the created thread's stack. @@ -400,7 +400,7 @@ when ODIN_OS == .Darwin { PTHREAD_SCOPE_PROCESS :: 2 PTHREAD_SCOPE_SYSTEM :: 1 - pthread_t :: distinct u64 + pthread_t :: distinct rawptr pthread_attr_t :: struct { __sig: c.long, diff --git a/core/sys/posix/pwd.odin b/core/sys/posix/pwd.odin index 75d15c899..c3ee3c0f6 100644 --- a/core/sys/posix/pwd.odin +++ b/core/sys/posix/pwd.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sched.odin b/core/sys/posix/sched.odin index 82b335653..cc509ba8e 100644 --- a/core/sys/posix/sched.odin +++ b/core/sys/posix/sched.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/setjmp.odin b/core/sys/posix/setjmp.odin index 926dbd3ad..a26bdb93e 100644 --- a/core/sys/posix/setjmp.odin +++ b/core/sys/posix/setjmp.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/signal.odin b/core/sys/posix/signal.odin index c7e2cc09b..69b405c5d 100644 --- a/core/sys/posix/signal.odin +++ b/core/sys/posix/signal.odin @@ -6,7 +6,7 @@ import "base:intrinsics" import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } @@ -50,7 +50,7 @@ foreign lib { /* Send a signal to a thread. - + As with kill, if sig is 0, only validation (of the pthread_t given) is done and no signal is sent. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_kill.html ]] @@ -124,7 +124,7 @@ foreign lib { sigignore :: proc(sig: Signal) -> result --- /* - Removes sig from the signal mask of the calling process and suspend the calling process until + Removes sig from the signal mask of the calling process and suspend the calling process until a signal is received. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sighold.html ]] @@ -166,7 +166,7 @@ foreign lib { [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigpending.html ]] */ @(link_name=LSIGPENDING) - sigpending :: proc(set: ^sigset_t) -> result --- + sigpending :: proc(set: ^sigset_t) -> result --- /* Wait for one of the given signals. @@ -333,7 +333,7 @@ SS_Flag_Bits :: enum c.int { SS_Flags :: bit_set[SS_Flag_Bits; c.int] Sig :: enum c.int { - // Resulting set is the union of the current set and the signal set and the complement of + // Resulting set is the union of the current set and the signal set and the complement of // the signal set pointed to by the argument. BLOCK = SIG_BLOCK, // Resulting set is the intersection of the current set and the complement of the signal set @@ -395,6 +395,7 @@ when ODIN_OS == .Darwin { SIGXFSZ :: 25 SIGVTALRM :: 26 SIGPROF :: 27 + SIGWINCH :: 28 SIGUSR1 :: 30 SIGUSR2 :: 31 @@ -535,6 +536,7 @@ when ODIN_OS == .Darwin { SIGXFSZ :: 25 SIGVTALRM :: 26 SIGPROF :: 27 + SIGWINCH :: 28 SIGUSR1 :: 30 SIGUSR2 :: 31 @@ -565,7 +567,7 @@ when ODIN_OS == .Darwin { SS_ONSTACK :: 0x0001 SS_DISABLE :: 0x0004 - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm32 { + when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 { MINSIGSTKSZ :: 1024 * 4 } else when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 { MINSIGSTKSZ :: 512 * 4 @@ -699,6 +701,7 @@ when ODIN_OS == .Darwin { SIGXFSZ :: 25 SIGVTALRM :: 26 SIGPROF :: 27 + SIGWINCH :: 28 SIGUSR1 :: 30 SIGUSR2 :: 31 @@ -876,6 +879,7 @@ when ODIN_OS == .Darwin { SIGXFSZ :: 25 SIGVTALRM :: 26 SIGPROF :: 27 + SIGWINCH :: 28 SIGUSR1 :: 30 SIGUSR2 :: 31 @@ -1036,6 +1040,7 @@ when ODIN_OS == .Darwin { SIGXFSZ :: 25 SIGVTALRM :: 26 SIGPROF :: 27 + SIGWINCH :: 28 SIGPOLL :: 29 SIGSYS :: 31 @@ -1084,7 +1089,7 @@ when ODIN_OS == .Darwin { @(private) __SI_MAX_SIZE :: 128 - when size_of(int) == 8 { + when size_of(int) == 8 { @(private) _pad0 :: struct { _pad0: c.int, diff --git a/core/sys/posix/signal_libc.odin b/core/sys/posix/signal_libc.odin index 7a054ddd7..ba0fbf084 100644 --- a/core/sys/posix/signal_libc.odin +++ b/core/sys/posix/signal_libc.odin @@ -9,7 +9,7 @@ import "core:c/libc" when ODIN_OS == .Windows { foreign import lib "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/spawn.odin b/core/sys/posix/spawn.odin new file mode 100644 index 000000000..4eacb3b4b --- /dev/null +++ b/core/sys/posix/spawn.odin @@ -0,0 +1,21 @@ +#+build linux, darwin, openbsd, freebsd, netbsd, haiku +package posix + +when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +foreign lib { + /* + Creates a child process from a provided filepath + spawnp searches directories on the path for the file + + Returns: 0 on success, with the child pid returned in the pid argument, or error values on failure. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html ]] + */ + posix_spawn :: proc(pid: ^pid_t, path: cstring, file_actions: rawptr, attrp: rawptr, argv: [^]cstring, envp: [^]cstring) -> Errno --- + posix_spawnp :: proc(pid: ^pid_t, file: cstring, file_actions: rawptr, attrp: rawptr, argv: [^]cstring, envp: [^]cstring) -> Errno --- +} diff --git a/core/sys/posix/stdio.odin b/core/sys/posix/stdio.odin index 24464dfd8..69c8ad3cb 100644 --- a/core/sys/posix/stdio.odin +++ b/core/sys/posix/stdio.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/stdio_libc.odin b/core/sys/posix/stdio_libc.odin index 12706970d..8ccdcc37a 100644 --- a/core/sys/posix/stdio_libc.odin +++ b/core/sys/posix/stdio_libc.odin @@ -10,7 +10,7 @@ when ODIN_OS == .Windows { "system:legacy_stdio_definitions.lib", } } else when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/stdlib.odin b/core/sys/posix/stdlib.odin index 5f1ae1908..0a6e5403c 100644 --- a/core/sys/posix/stdlib.odin +++ b/core/sys/posix/stdlib.odin @@ -6,7 +6,7 @@ import "base:intrinsics" import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/stdlib_libc.odin b/core/sys/posix/stdlib_libc.odin index 6574026f4..966dc1d32 100644 --- a/core/sys/posix/stdlib_libc.odin +++ b/core/sys/posix/stdlib_libc.odin @@ -9,7 +9,7 @@ import "core:c/libc" when ODIN_OS == .Windows { foreign import lib "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } @@ -60,7 +60,7 @@ wctomb :: libc.wctomb mbstowcs :: libc.mbstowcs wcstombs :: libc.wcstombs -free :: #force_inline proc(ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring { +free :: #force_inline proc "c" (ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring { libc.free(rawptr(ptr)) } diff --git a/core/sys/posix/string.odin b/core/sys/posix/string.odin index 3f9dbb43e..3d0c5b7a2 100644 --- a/core/sys/posix/string.odin +++ b/core/sys/posix/string.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/string_libc.odin b/core/sys/posix/string_libc.odin index 72164cc4c..d689847ee 100644 --- a/core/sys/posix/string_libc.odin +++ b/core/sys/posix/string_libc.odin @@ -4,7 +4,7 @@ package posix when ODIN_OS == .Windows { foreign import lib "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_ipc.odin b/core/sys/posix/sys_ipc.odin index bf5938ce1..5814c7211 100644 --- a/core/sys/posix/sys_ipc.odin +++ b/core/sys/posix/sys_ipc.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_mman.odin b/core/sys/posix/sys_mman.odin index 0594672ae..1bf3615dc 100644 --- a/core/sys/posix/sys_mman.odin +++ b/core/sys/posix/sys_mman.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } @@ -92,7 +92,12 @@ foreign lib { [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html ]] */ - shm_open :: proc(name: cstring, oflag: O_Flags, mode: mode_t) -> FD --- + when ODIN_OS == .Darwin { + // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/shm_open.2.html + shm_open :: proc(name: cstring, oflag: O_Flags, #c_vararg args: ..any) -> FD --- + } else { + shm_open :: proc(name: cstring, oflag: O_Flags, mode: mode_t) -> FD --- + } /* Removes a shared memory object. diff --git a/core/sys/posix/sys_msg.odin b/core/sys/posix/sys_msg.odin index c578b1fc6..87d5089ea 100644 --- a/core/sys/posix/sys_msg.odin +++ b/core/sys/posix/sys_msg.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_resource.odin b/core/sys/posix/sys_resource.odin index ae478382a..a748c2bba 100644 --- a/core/sys/posix/sys_resource.odin +++ b/core/sys/posix/sys_resource.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_select.odin b/core/sys/posix/sys_select.odin index a75e58de6..117dee625 100644 --- a/core/sys/posix/sys_select.odin +++ b/core/sys/posix/sys_select.odin @@ -6,7 +6,7 @@ import "base:intrinsics" import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_sem.odin b/core/sys/posix/sys_sem.odin index 069315f87..e876cf74a 100644 --- a/core/sys/posix/sys_sem.odin +++ b/core/sys/posix/sys_sem.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_shm.odin b/core/sys/posix/sys_shm.odin index 8f3c56b9c..8ee16e5a3 100644 --- a/core/sys/posix/sys_shm.odin +++ b/core/sys/posix/sys_shm.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_socket.odin b/core/sys/posix/sys_socket.odin index 0645893d0..812451219 100644 --- a/core/sys/posix/sys_socket.odin +++ b/core/sys/posix/sys_socket.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/sys/posix/sys_stat.odin b/core/sys/posix/sys_stat.odin index 265356e54..df0bf2b49 100644 --- a/core/sys/posix/sys_stat.odin +++ b/core/sys/posix/sys_stat.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_statvfs.odin b/core/sys/posix/sys_statvfs.odin index 47c810135..1a332c5ce 100644 --- a/core/sys/posix/sys_statvfs.odin +++ b/core/sys/posix/sys_statvfs.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_time.odin b/core/sys/posix/sys_time.odin index 94eafec85..058166759 100644 --- a/core/sys/posix/sys_time.odin +++ b/core/sys/posix/sys_time.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_times.odin b/core/sys/posix/sys_times.odin index 73db489a7..636d3e153 100644 --- a/core/sys/posix/sys_times.odin +++ b/core/sys/posix/sys_times.odin @@ -2,7 +2,7 @@ package posix when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_uio.odin b/core/sys/posix/sys_uio.odin index 5770f8058..b4411851b 100644 --- a/core/sys/posix/sys_uio.odin +++ b/core/sys/posix/sys_uio.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" + foreign import libc "system:System" } else { foreign import libc "system:c" } diff --git a/core/sys/posix/sys_utsname.odin b/core/sys/posix/sys_utsname.odin index 5ea8807a7..61f88b584 100644 --- a/core/sys/posix/sys_utsname.odin +++ b/core/sys/posix/sys_utsname.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/sys_wait.odin b/core/sys/posix/sys_wait.odin index d3bcdfddd..e12fcd212 100644 --- a/core/sys/posix/sys_wait.odin +++ b/core/sys/posix/sys_wait.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/termios.odin b/core/sys/posix/termios.odin index 4ca884e87..b385b7097 100644 --- a/core/sys/posix/termios.odin +++ b/core/sys/posix/termios.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/time.odin b/core/sys/posix/time.odin index 88f0153f4..7d55cf15b 100644 --- a/core/sys/posix/time.odin +++ b/core/sys/posix/time.odin @@ -5,7 +5,7 @@ import "core:c" import "core:c/libc" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/ulimit.odin b/core/sys/posix/ulimit.odin index 0f87641fa..892f6dee4 100644 --- a/core/sys/posix/ulimit.odin +++ b/core/sys/posix/ulimit.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/unistd.odin b/core/sys/posix/unistd.odin index b8020317c..b05f1e4fa 100644 --- a/core/sys/posix/unistd.odin +++ b/core/sys/posix/unistd.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/unistd_libc.odin b/core/sys/posix/unistd_libc.odin index 74edb6862..85d019f21 100644 --- a/core/sys/posix/unistd_libc.odin +++ b/core/sys/posix/unistd_libc.odin @@ -6,7 +6,7 @@ import "core:c" when ODIN_OS == .Windows { foreign import lib "system:libucrt.lib" } else when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/utime.odin b/core/sys/posix/utime.odin index 98c8166d6..fca0dee59 100644 --- a/core/sys/posix/utime.odin +++ b/core/sys/posix/utime.odin @@ -2,7 +2,7 @@ package posix when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/posix/wordexp.odin b/core/sys/posix/wordexp.odin index a9e6f39a7..92d6aba40 100644 --- a/core/sys/posix/wordexp.odin +++ b/core/sys/posix/wordexp.odin @@ -4,7 +4,7 @@ package posix import "core:c" when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" + foreign import lib "system:System" } else { foreign import lib "system:c" } diff --git a/core/sys/unix/sysctl_freebsd.odin b/core/sys/unix/sysctl_freebsd.odin index f5fee6c6c..cdd591a5b 100644 --- a/core/sys/unix/sysctl_freebsd.odin +++ b/core/sys/unix/sysctl_freebsd.odin @@ -3,7 +3,7 @@ package unix import "base:intrinsics" -sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) { +sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) { mib := mib result_size := u64(size_of(T)) diff --git a/core/sys/unix/sysctl_netbsd.odin b/core/sys/unix/sysctl_netbsd.odin index ad89b9ad4..b70740721 100644 --- a/core/sys/unix/sysctl_netbsd.odin +++ b/core/sys/unix/sysctl_netbsd.odin @@ -8,7 +8,7 @@ foreign libc { @(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 --- } -sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) { +sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) { mib := mib result_size := c.size_t(size_of(T)) res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0) diff --git a/core/sys/unix/sysctl_openbsd.odin b/core/sys/unix/sysctl_openbsd.odin index 49c9b6336..e71b743f8 100644 --- a/core/sys/unix/sysctl_openbsd.odin +++ b/core/sys/unix/sysctl_openbsd.odin @@ -9,7 +9,7 @@ foreign libc { @(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 --- } -sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) { +sysctl :: proc "contextless" (mib: []i32, val: ^$T) -> (ok: bool) { mib := mib result_size := c.size_t(size_of(T)) res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0) diff --git a/core/sys/wasm/js/events.odin b/core/sys/wasm/js/events.odin index ffa3a1202..f5a47c06b 100644 --- a/core/sys/wasm/js/events.odin +++ b/core/sys/wasm/js/events.odin @@ -189,7 +189,7 @@ Key_Location :: enum u8 { KEYBOARD_MAX_KEY_SIZE :: 32 KEYBOARD_MAX_CODE_SIZE :: 32 -GAMEPAD_MAX_ID_SIZE :: 64 +GAMEPAD_MAX_ID_SIZE :: 96 GAMEPAD_MAX_MAPPING_SIZE :: 64 GAMEPAD_MAX_BUTTONS :: 64 @@ -239,6 +239,12 @@ Gamepad_State :: struct { _mapping_buf: [GAMEPAD_MAX_MAPPING_SIZE]byte `fmt:"-"`, } +Pointer_Type :: enum u8 { + Mouse, + Pen, + Touch, +} + Event :: struct { kind: Event_Kind, target_kind: Event_Target_Kind, @@ -275,6 +281,8 @@ Event :: struct { repeat: bool, + char: rune, + _key_len: int `fmt:"-"`, _code_len: int `fmt:"-"`, _key_buf: [KEYBOARD_MAX_KEY_SIZE]byte `fmt:"-"`, @@ -295,6 +303,21 @@ Event :: struct { button: i16, buttons: bit_set[0..<16; u16], + + pointer: struct { + altitude_angle: f64, + azimuth_angle: f64, + persistent_device_id: int, + pointer_id: int, + width: int, + height: int, + pressure: f64, + tangential_pressure: f64, + tilt: [2]f64, + twist: f64, + pointer_type: Pointer_Type, + is_primary: bool, + }, }, gamepad: Gamepad_State, @@ -323,13 +346,13 @@ add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, call return _add_event_listener(id, event_kind_string[kind], kind, user_data, callback, use_capture) } -remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool { +remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { @(default_calling_convention="contextless") foreign dom_lib { @(link_name="remove_event_listener") - _remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event)) -> bool --- + _remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool --- } - return _remove_event_listener(id, event_kind_string[kind], user_data, callback) + return _remove_event_listener(id, event_kind_string[kind], user_data, callback, use_capture) } add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { @@ -341,20 +364,46 @@ add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: return _add_window_event_listener(event_kind_string[kind], kind, user_data, callback, use_capture) } -remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool { +remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { @(default_calling_convention="contextless") foreign dom_lib { @(link_name="remove_window_event_listener") - _remove_window_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event)) -> bool --- + _remove_window_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool --- } - return _remove_window_event_listener(event_kind_string[kind], user_data, callback) + return _remove_window_event_listener(event_kind_string[kind], user_data, callback, use_capture) +} + +add_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { + @(default_calling_convention="contextless") + foreign dom_lib { + @(link_name="add_document_event_listener") + _add_document_event_listener :: proc(name: string, name_code: Event_Kind, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool --- + } + return _add_document_event_listener(event_kind_string[kind], kind, user_data, callback, use_capture) +} + +remove_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { + @(default_calling_convention="contextless") + foreign dom_lib { + @(link_name="remove_document_event_listener") + _remove_document_event_listener :: proc(name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool --- + } + return _remove_document_event_listener(event_kind_string[kind], user_data, callback, use_capture) } remove_event_listener_from_event :: proc(e: Event) -> bool { + from_use_capture_false: bool + from_use_capture_true: bool if e.id == "" { - return remove_window_event_listener(e.kind, e.user_data, e.callback) + from_use_capture_false = remove_window_event_listener(e.kind, e.user_data, e.callback, false) + from_use_capture_true = remove_window_event_listener(e.kind, e.user_data, e.callback, true) + from_use_capture_false |= remove_document_event_listener(e.kind, e.user_data, e.callback, false) + from_use_capture_true |= remove_document_event_listener(e.kind, e.user_data, e.callback, true) + } else { + from_use_capture_false = remove_event_listener(e.id, e.kind, e.user_data, e.callback, false) + from_use_capture_true = remove_event_listener(e.id, e.kind, e.user_data, e.callback, true) } - return remove_event_listener(e.id, e.kind, e.user_data, e.callback) + return from_use_capture_false || from_use_capture_true } add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { @@ -365,13 +414,13 @@ add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, c } return _add_event_listener(id, name, .Custom, user_data, callback, use_capture) } -remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event)) -> bool { +remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { @(default_calling_convention="contextless") foreign dom_lib { @(link_name="remove_event_listener") - _remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event)) -> bool --- + _remove_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc "odin" (Event), use_capture: bool) -> bool --- } - return _remove_event_listener(id, name, user_data, callback) + return _remove_event_listener(id, name, user_data, callback, use_capture) } get_gamepad_state :: proc "contextless" (index: int, s: ^Gamepad_State) -> bool { @@ -384,7 +433,14 @@ get_gamepad_state :: proc "contextless" (index: int, s: ^Gamepad_State) -> bool if s == nil { return false } - return _get_gamepad_state(index, s) + + if !_get_gamepad_state(index, s) { + return false + } + + s.id = string(s._id_buf[:s._id_len]) + s.mapping = string(s._mapping_buf[:s._mapping_len]) + return true } @@ -415,4 +471,4 @@ do_event_callback :: proc(user_data: rawptr, callback: proc(e: Event)) { callback(event) } -} \ No newline at end of file +} diff --git a/core/sys/wasm/js/events_all_targets.odin b/core/sys/wasm/js/events_all_targets.odin index b7e01ca10..903252c7a 100644 --- a/core/sys/wasm/js/events_all_targets.odin +++ b/core/sys/wasm/js/events_all_targets.odin @@ -263,7 +263,7 @@ add_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, call panic("vendor:wasm/js not supported on non JS targets") } -remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool { +remove_event_listener :: proc(id: string, kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { panic("vendor:wasm/js not supported on non JS targets") } @@ -271,7 +271,15 @@ add_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: panic("vendor:wasm/js not supported on non JS targets") } -remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event)) -> bool { +remove_window_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { + panic("vendor:wasm/js not supported on non JS targets") +} + +add_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { + panic("vendor:wasm/js not supported on non JS targets") +} + +remove_document_event_listener :: proc(kind: Event_Kind, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { panic("vendor:wasm/js not supported on non JS targets") } @@ -282,6 +290,6 @@ remove_event_listener_from_event :: proc(e: Event) -> bool { add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { panic("vendor:wasm/js not supported on non JS targets") } -remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event)) -> bool { +remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event), use_capture := false) -> bool { panic("vendor:wasm/js not supported on non JS targets") -} \ No newline at end of file +} diff --git a/core/sys/wasm/js/general.odin b/core/sys/wasm/js/general.odin index 4ed2ae298..22bb08e2b 100644 --- a/core/sys/wasm/js/general.odin +++ b/core/sys/wasm/js/general.odin @@ -9,4 +9,5 @@ foreign odin_env { abort :: proc() -> ! --- alert :: proc(msg: string) --- evaluate :: proc(str: string) --- -} \ No newline at end of file + open :: proc(url: string, name := "", specs := "") --- +} diff --git a/core/sys/wasm/js/odin.js b/core/sys/wasm/js/odin.js index 29227c526..f4f73a42a 100644 --- a/core/sys/wasm/js/odin.js +++ b/core/sys/wasm/js/odin.js @@ -17,7 +17,7 @@ class WasmMemoryInterface { constructor() { this.memory = null; this.exports = null; - this.listenerMap = {}; + this.listenerMap = new Map(); // Size (in bytes) of the integer type, should be 4 on `js_wasm32` and 8 on `js_wasm64p32` this.intSize = 4; @@ -110,16 +110,12 @@ class WasmMemoryInterface { } loadCstring(ptr) { - return this.loadCstringDirect(this.loadPtr(ptr)); - } - - loadCstringDirect(start) { - if (start == 0) { + if (ptr == 0) { return null; } let len = 0; - for (; this.mem.getUint8(start+len) != 0; len += 1) {} - return this.loadString(start, len); + for (; this.mem.getUint8(ptr+len) != 0; len += 1) {} + return this.loadString(ptr, len); } storeU8(addr, value) { this.mem.setUint8 (addr, value); } @@ -396,12 +392,18 @@ class WebGLInterface { BindTexture: (target, texture) => { this.ctx.bindTexture(target, texture ? this.textures[texture] : null) }, + BindRenderbuffer: (target, renderbuffer) => { + this.ctx.bindRenderbuffer(target, renderbuffer ? this.renderbuffers[renderbuffer] : null) + }, BlendColor: (red, green, blue, alpha) => { this.ctx.blendColor(red, green, blue, alpha); }, BlendEquation: (mode) => { this.ctx.blendEquation(mode); }, + BlendEquationSeparate: (modeRGB, modeAlpha) => { + this.ctx.blendEquationSeparate(modeRGB, modeAlpha); + }, BlendFunc: (sfactor, dfactor) => { this.ctx.blendFunc(sfactor, dfactor); }, @@ -633,6 +635,13 @@ class WebGLInterface { GetParameter: (pname) => { return this.ctx.getParameter(pname); }, + GetParameter4i: (pname, v0, v1, v2, v3) => { + const i4 = this.ctx.getParameter(pname); + this.mem.storeI32(v0, i4[0]); + this.mem.storeI32(v1, i4[1]); + this.mem.storeI32(v2, i4[2]); + this.mem.storeI32(v3, i4[3]); + }, GetProgramParameter: (program, pname) => { return this.ctx.getProgramParameter(this.programs[program], pname) }, @@ -803,6 +812,40 @@ class WebGLInterface { Uniform3i: (location, v0, v1, v2) => { this.ctx.uniform3i(this.uniforms[location], v0, v1, v2); }, Uniform4i: (location, v0, v1, v2, v3) => { this.ctx.uniform4i(this.uniforms[location], v0, v1, v2, v3); }, + Uniform1fv: (location, count, addr) => { + let array = this.mem.loadF32Array(addr, 1*count); + this.ctx.uniform1fv(this.uniforms[location], array); + }, + Uniform2fv: (location, count, addr) => { + let array = this.mem.loadF32Array(addr, 2*count); + this.ctx.uniform2fv(this.uniforms[location], array); + }, + Uniform3fv: (location, count, addr) => { + let array = this.mem.loadF32Array(addr, 3*count); + this.ctx.uniform3fv(this.uniforms[location], array); + }, + Uniform4fv: (location, count, addr) => { + let array = this.mem.loadF32Array(addr, 4*count); + this.ctx.uniform4fv(this.uniforms[location], array); + }, + + Uniform1iv: (location, count, addr) => { + let array = this.mem.loadI32Array(addr, 1*count); + this.ctx.uniform1iv(this.uniforms[location], array); + }, + Uniform2iv: (location, count, addr) => { + let array = this.mem.loadI32Array(addr, 2*count); + this.ctx.uniform2iv(this.uniforms[location], array); + }, + Uniform3iv: (location, count, addr) => { + let array = this.mem.loadI32Array(addr, 3*count); + this.ctx.uniform3iv(this.uniforms[location], array); + }, + Uniform4iv: (location, count, addr) => { + let array = this.mem.loadI32Array(addr, 4*count); + this.ctx.uniform4iv(this.uniforms[location], array); + }, + UniformMatrix2fv: (location, addr) => { let array = this.mem.loadF32Array(addr, 2*2); this.ctx.uniformMatrix2fv(this.uniforms[location], false, array); @@ -1315,18 +1358,20 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { } else if (!line.includes("\n")) { currentLine[isError] = currentLine[isError].concat(line); } else { - let lines = line.split("\n"); + let lines = line.trimEnd().split("\n"); let printLast = lines.length > 1 && line.endsWith("\n"); println(currentLine[isError].concat(lines[0])); currentLine[isError] = ""; for (let i = 1; i < lines.length-1; i++) { println(lines[i]); } - let last = lines[lines.length-1]; - if (printLast) { - println(last); - } else { - currentLine[isError] = last; + if (lines.length > 1) { + let last = lines[lines.length-1]; + if (printLast) { + println(last); + } else { + currentLine[isError] = last; + } } } @@ -1393,6 +1438,10 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { info.scrollTop = info.scrollHeight; }; + const listener_key = (id, name, data, callback, useCapture) => { + return `${id}-${name}-data:${data}-callback:${callback}-useCapture:${useCapture}`; + }; + let webglContext = new WebGLInterface(wasmMemoryInterface); const env = {}; @@ -1421,6 +1470,13 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { abort: () => { Module.abort() }, evaluate: (str_ptr, str_len) => { eval.call(null, wasmMemoryInterface.loadString(str_ptr, str_len)); }, + open: (url_ptr, url_len, name_ptr, name_len, specs_ptr, specs_len) => { + const url = wasmMemoryInterface.loadString(url_ptr, url_len); + const name = wasmMemoryInterface.loadString(name_ptr, name_len); + const specs = wasmMemoryInterface.loadString(specs_ptr, specs_len); + window.open(url, name, specs); + }, + // return a bigint to be converted to i64 time_now: () => BigInt(Date.now()), tick_now: () => performance.now(), @@ -1533,6 +1589,29 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { wmi.storeI16(off(2), e.button); wmi.storeU16(off(2), e.buttons); + + if (e instanceof PointerEvent) { + wmi.storeF64(off(8), e.altitudeAngle); + wmi.storeF64(off(8), e.azimuthAngle); + wmi.storeInt(off(W), e.persistentDeviceId); + wmi.storeInt(off(W), e.pointerId); + wmi.storeInt(off(W), e.width); + wmi.storeInt(off(W), e.height); + wmi.storeF64(off(8), e.pressure); + wmi.storeF64(off(8), e.tangentialPressure); + wmi.storeF64(off(8), e.tiltX); + wmi.storeF64(off(8), e.tiltY); + wmi.storeF64(off(8), e.twist); + if (e.pointerType == "pen") { + wmi.storeU8(off(1), 1); + } else if (e.pointerType == "touch") { + wmi.storeU8(off(1), 2); + } else { + wmi.storeU8(off(1), 0); + } + wmi.storeU8(off(1), !!e.isPrimary); + } + } else if (e instanceof KeyboardEvent) { // Note: those strings are constructed // on the native side from buffers that @@ -1549,6 +1628,8 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { wmi.storeU8(off(1), !!e.repeat); + wmi.storeI32(off(4), e.charCode); + wmi.storeInt(off(W, W), e.key.length) wmi.storeInt(off(W, W), e.code.length) wmi.storeString(off(32, 1), e.key); @@ -1588,10 +1669,24 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { } } - wmi.storeInt(off(W, W), e.gamepad.id.length) - wmi.storeInt(off(W, W), e.gamepad.mapping.length) - wmi.storeString(off(64, 1), e.gamepad.id); - wmi.storeString(off(64, 1), e.gamepad.mapping); + let idLength = e.gamepad.id.length; + let id = e.gamepad.id; + if (idLength > 96) { + idLength = 96; + id = id.slice(0, 93) + '...'; + } + + let mappingLength = e.gamepad.mapping.length; + let mapping = e.gamepad.mapping; + if (mappingLength > 64) { + mappingLength = 61; + mapping = mapping.slice(0, 61) + '...'; + } + + wmi.storeInt(off(W, W), idLength); + wmi.storeInt(off(W, W), mappingLength); + wmi.storeString(off(96, 1), id); + wmi.storeString(off(64, 1), mapping); } }, @@ -1602,6 +1697,10 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { if (element == undefined) { return false; } + let key = listener_key(id, name, data, callback, !!use_capture); + if (wasmMemoryInterface.listenerMap.has(key)) { + return false; + } let listener = (e) => { let event_data = {}; @@ -1612,7 +1711,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { onEventReceived(event_data, data, callback); }; - wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener; + wasmMemoryInterface.listenerMap.set(key, listener); element.addEventListener(name, listener, !!use_capture); return true; }, @@ -1620,6 +1719,11 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { add_window_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => { let name = wasmMemoryInterface.loadString(name_ptr, name_len); let element = window; + let key = listener_key('window', name, data, callback, !!use_capture); + if (wasmMemoryInterface.listenerMap.has(key)) { + return false; + } + let listener = (e) => { let event_data = {}; event_data.id_ptr = 0; @@ -1629,12 +1733,34 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { onEventReceived(event_data, data, callback); }; - wasmMemoryInterface.listenerMap[{data: data, callback: callback}] = listener; + wasmMemoryInterface.listenerMap.set(key, listener); element.addEventListener(name, listener, !!use_capture); return true; }, - remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback) => { + add_document_event_listener: (name_ptr, name_len, name_code, data, callback, use_capture) => { + let name = wasmMemoryInterface.loadString(name_ptr, name_len); + let element = document; + let key = listener_key('document', name, data, callback, !!use_capture); + if (wasmMemoryInterface.listenerMap.has(key)) { + return false; + } + + let listener = (e) => { + let event_data = {}; + event_data.id_ptr = 0; + event_data.id_len = 0; + event_data.event = e; + event_data.name_code = name_code; + + onEventReceived(event_data, data, callback); + }; + wasmMemoryInterface.listenerMap.set(key, listener); + element.addEventListener(name, listener, !!use_capture); + return true; + }, + + remove_event_listener: (id_ptr, id_len, name_ptr, name_len, data, callback, use_capture) => { let id = wasmMemoryInterface.loadString(id_ptr, id_len); let name = wasmMemoryInterface.loadString(name_ptr, name_len); let element = getElement(id); @@ -1642,24 +1768,42 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { return false; } - let listener = wasmMemoryInterface.listenerMap[{data: data, callback: callback}]; - if (listener == undefined) { + let key = listener_key(id, name, data, callback, !!use_capture); + let listener = wasmMemoryInterface.listenerMap.get(key); + if (listener === undefined) { return false; } - element.removeEventListener(name, listener); + wasmMemoryInterface.listenerMap.delete(key); + + element.removeEventListener(name, listener, !!use_capture); return true; }, - remove_window_event_listener: (name_ptr, name_len, data, callback) => { + remove_window_event_listener: (name_ptr, name_len, data, callback, use_capture) => { let name = wasmMemoryInterface.loadString(name_ptr, name_len); let element = window; - let key = {data: data, callback: callback}; - let listener = wasmMemoryInterface.listenerMap[key]; - if (!listener) { + + let key = listener_key('window', name, data, callback, !!use_capture); + let listener = wasmMemoryInterface.listenerMap.get(key); + if (listener === undefined) { return false; } - wasmMemoryInterface.listenerMap[key] = undefined; + wasmMemoryInterface.listenerMap.delete(key); - element.removeEventListener(name, listener); + element.removeEventListener(name, listener, !!use_capture); + return true; + }, + remove_document_event_listener: (name_ptr, name_len, data, callback, use_capture) => { + let name = wasmMemoryInterface.loadString(name_ptr, name_len); + let element = document; + + let key = listener_key('document', name, data, callback, !!use_capture); + let listener = wasmMemoryInterface.listenerMap.get(key); + if (listener === undefined) { + return false; + } + wasmMemoryInterface.listenerMap.delete(key); + + element.removeEventListener(name, listener, !!use_capture); return true; }, @@ -1756,10 +1900,24 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { } } - wmi.storeInt(off(W, W), gamepad.id.length) - wmi.storeInt(off(W, W), gamepad.mapping.length) - wmi.storeString(off(64, 1), gamepad.id); - wmi.storeString(off(64, 1), gamepad.mapping); + let idLength = gamepad.id.length; + let id = gamepad.id; + if (idLength > 96) { + idLength = 96; + id = id.slice(0, 93) + '...'; + } + + let mappingLength = gamepad.mapping.length; + let mapping = gamepad.mapping; + if (mappingLength > 64) { + mappingLength = 61; + mapping = mapping.slice(0, 61) + '...'; + } + + wmi.storeInt(off(W, W), idLength); + wmi.storeInt(off(W, W), mappingLength); + wmi.storeString(off(96, 1), id); + wmi.storeString(off(64, 1), mapping); return true; } @@ -1779,7 +1937,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { if (buf_len > 0 && buf_ptr) { let n = Math.min(buf_len, str.length); str = str.substring(0, n); - this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(str)) + wasmMemoryInterface.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(str)) return n; } } @@ -1843,7 +2001,7 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory) { if (buf_len > 0 && buf_ptr) { let n = Math.min(buf_len, str.length); str = str.substring(0, n); - this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(str)) + wasmMemoryInterface.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(str)) return n; } } diff --git a/core/sys/windows/comctl32.odin b/core/sys/windows/comctl32.odin index d954f952c..c7a166634 100644 --- a/core/sys/windows/comctl32.odin +++ b/core/sys/windows/comctl32.odin @@ -573,10 +573,10 @@ Button_GetTextMargin :: #force_inline proc "system" (hwnd: HWND, pmargin: ^RECT) return cast(BOOL)SendMessageW(hwnd, BCM_GETTEXTMARGIN, 0, cast(LPARAM)uintptr(pmargin)) } Button_SetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR) -> BOOL { - return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(psz)) + return cast(BOOL)SendMessageW(hwnd, BCM_SETNOTE, 0, cast(LPARAM)uintptr(rawptr(psz))) } Button_GetNote :: #force_inline proc "system" (hwnd: HWND, psz: LPCWSTR, pcc: ^c_int) -> BOOL { - return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(psz)) + return cast(BOOL)SendMessageW(hwnd, BCM_GETNOTE, uintptr(pcc), cast(LPARAM)uintptr(rawptr(psz))) } Button_GetNoteLength :: #force_inline proc "system" (hwnd: HWND) -> LRESULT { return SendMessageW(hwnd, BCM_GETNOTELENGTH, 0, 0) @@ -604,10 +604,10 @@ EDITBALLOONTIP :: struct { PEDITBALLOONTIP :: ^EDITBALLOONTIP Edit_SetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR) -> BOOL { - return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(lpcwText)) + return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, 0, cast(LPARAM)uintptr(rawptr(lpcwText))) } Edit_SetCueBannerTextFocused :: #force_inline proc "system" (hwnd: HWND, lpcwText: LPCWSTR, fDrawFocused: BOOL) -> BOOL { - return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(lpcwText)) + return cast(BOOL)SendMessageW(hwnd, EM_SETCUEBANNER, cast(WPARAM)fDrawFocused, cast(LPARAM)uintptr(rawptr(lpcwText))) } Edit_GetCueBannerText :: #force_inline proc "system" (hwnd: HWND, lpwText: LPWSTR, cchText: LONG) -> BOOL { return cast(BOOL)SendMessageW(hwnd, EM_GETCUEBANNER, uintptr(lpwText), cast(LPARAM)cchText) @@ -1197,7 +1197,7 @@ ListView_GetItemPosition :: #force_inline proc "system" (hwnd: HWND, i: c_int, p return cast(BOOL)SendMessageW(hwnd, LVM_GETITEMPOSITION, cast(WPARAM)i, cast(LPARAM)uintptr(ppt)) } ListView_GetStringWidth :: #force_inline proc "system" (hwndLV: HWND, psz: LPCWSTR) -> c_int { - return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(psz)) + return cast(c_int)SendMessageW(hwndLV, LVM_GETSTRINGWIDTHW, 0, cast(LPARAM)uintptr(rawptr(psz))) } ListView_HitTest :: #force_inline proc "system" (hwndLV: HWND, pinfo: ^LV_HITTESTINFO) -> c_int { return cast(c_int)SendMessageW(hwndLV, LVM_HITTEST, 0, cast(LPARAM)uintptr(pinfo)) diff --git a/core/sys/windows/dwmapi.odin b/core/sys/windows/dwmapi.odin index 11e91c704..e86730660 100644 --- a/core/sys/windows/dwmapi.odin +++ b/core/sys/windows/dwmapi.odin @@ -39,10 +39,10 @@ DWMNCRENDERINGPOLICY :: enum { } DWM_WINDOW_CORNER_PREFERENCE :: enum c_int { - DEFAULT, - DONOTROUND, - ROUND, - ROUNDSMALL, + DEFAULT, + DONOTROUND, + ROUND, + ROUNDSMALL, } @(default_calling_convention="system") diff --git a/core/sys/windows/gdi32.odin b/core/sys/windows/gdi32.odin index 1d7a93d85..141429483 100644 --- a/core/sys/windows/gdi32.odin +++ b/core/sys/windows/gdi32.odin @@ -22,7 +22,7 @@ foreign gdi32 { CreateDIBPatternBrush :: proc(h: HGLOBAL, iUsage: UINT) -> HBRUSH --- CreateDIBitmap :: proc(hdc: HDC, pbmih: ^BITMAPINFOHEADER, flInit: DWORD, pjBits: VOID, pbmi: ^BITMAPINFO, iUsage: UINT) -> HBITMAP --- - CreateDIBSection :: proc(hdc: HDC, pbmi: ^BITMAPINFO, usage: UINT, ppvBits: VOID, hSection: HANDLE, offset: DWORD) -> HBITMAP --- + CreateDIBSection :: proc(hdc: HDC, pbmi: ^BITMAPINFO, usage: UINT, ppvBits: ^^VOID, hSection: HANDLE, offset: DWORD) -> HBITMAP --- StretchDIBits :: proc(hdc: HDC, xDest, yDest, DestWidth, DestHeight, xSrc, ySrc, SrcWidth, SrcHeight: INT, lpBits: VOID, lpbmi: ^BITMAPINFO, iUsage: UINT, rop: DWORD) -> INT --- StretchBlt :: proc(hdcDest: HDC, xDest, yDest, wDest, hDest: INT, hdcSrc: HDC, xSrc, ySrc, wSrc, hSrc: INT, rop: DWORD) -> BOOL --- @@ -350,4 +350,4 @@ NEWTEXTMETRICW :: struct { ntmAvgWidth: UINT, } -FONTENUMPROCW :: #type proc(lpelf: ^ENUMLOGFONTW, lpntm: ^NEWTEXTMETRICW, FontType: DWORD, lParam: LPARAM) -> INT +FONTENUMPROCW :: #type proc "system" (lpelf: ^ENUMLOGFONTW, lpntm: ^NEWTEXTMETRICW, FontType: DWORD, lParam: LPARAM) -> INT diff --git a/core/sys/windows/ip_helper.odin b/core/sys/windows/ip_helper.odin index 7a6e545ac..d2e75d531 100644 --- a/core/sys/windows/ip_helper.odin +++ b/core/sys/windows/ip_helper.odin @@ -38,9 +38,9 @@ IP_Adapter_Addresses :: struct { FirstAnycastAddress: ^IP_ADAPTER_ANYCAST_ADDRESS_XP, FirstMulticastAddress: ^IP_ADAPTER_MULTICAST_ADDRESS_XP, FirstDnsServerAddress: ^IP_ADAPTER_DNS_SERVER_ADDRESS_XP, - DnsSuffix: ^u16, - Description: ^u16, - FriendlyName: ^u16, + DnsSuffix: cstring16, + Description: cstring16, + FriendlyName: cstring16, PhysicalAddress: [8]u8, PhysicalAddressLength: u32, Anonymous2: struct #raw_union { diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 266dcdbf4..ff27cf795 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -168,6 +168,7 @@ foreign kernel32 { ResumeThread :: proc(thread: HANDLE) -> DWORD --- GetThreadPriority :: proc(thread: HANDLE) -> c_int --- SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL --- + GetThreadDescription :: proc(hThread: HANDLE, ppszThreadDescription: ^PCWSTR) -> HRESULT --- SetThreadDescription :: proc(hThread: HANDLE, lpThreadDescription: PCWSTR) -> HRESULT --- GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL --- TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL --- @@ -257,7 +258,7 @@ foreign kernel32 { ) -> BOOL --- CreateProcessW :: proc( lpApplicationName: LPCWSTR, - lpCommandLine: LPWSTR, + lpCommandLine: LPCWSTR, lpProcessAttributes: LPSECURITY_ATTRIBUTES, lpThreadAttributes: LPSECURITY_ATTRIBUTES, bInheritHandles: BOOL, @@ -372,6 +373,12 @@ foreign kernel32 { bInitialState: BOOL, lpName: LPCWSTR, ) -> HANDLE --- + CreateEventExW :: proc( + lpEventAttributes: LPSECURITY_ATTRIBUTES, + lpName: LPCWSTR, + dwFlags: DWORD, + dwDesiredAccess: DWORD, + ) -> HANDLE --- ResetEvent :: proc(hEvent: HANDLE) -> BOOL --- SetEvent :: proc(hEvent: HANDLE) -> BOOL --- WaitForMultipleObjects :: proc( @@ -406,6 +413,7 @@ foreign kernel32 { lpBytesLeftThisMessage: ^u32, ) -> BOOL --- CancelIo :: proc(handle: HANDLE) -> BOOL --- + CancelIoEx :: proc(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL --- GetOverlappedResult :: proc( hFile: HANDLE, lpOverlapped: LPOVERLAPPED, @@ -547,6 +555,7 @@ foreign kernel32 { GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL --- RtlCaptureStackBackTrace :: proc(FramesToSkip: ULONG, FramesToCapture: ULONG, BackTrace: [^]PVOID, BackTraceHash: PULONG) -> USHORT --- + RtlNtStatusToDosError :: proc(status: NTSTATUS) -> ULONG --- GetSystemPowerStatus :: proc(lpSystemPowerStatus: ^SYSTEM_POWER_STATUS) -> BOOL --- } @@ -857,7 +866,6 @@ MEMORY_RESOURCE_NOTIFICATION_TYPE :: enum c_int { LowMemoryResourceNotification :: MEMORY_RESOURCE_NOTIFICATION_TYPE.LowMemoryResourceNotification HighMemoryResourceNotification :: MEMORY_RESOURCE_NOTIFICATION_TYPE.HighMemoryResourceNotification - @(default_calling_convention="system") foreign kernel32 { CreateMemoryResourceNotification :: proc( @@ -1194,7 +1202,7 @@ DUMMYUNIONNAME_u :: struct #raw_union { SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct { ProcessorMask: ULONG_PTR, Relationship: LOGICAL_PROCESSOR_RELATIONSHIP, - DummyUnion: DUMMYUNIONNAME_u, + using DummyUnion: DUMMYUNIONNAME_u, } SYSTEM_POWER_STATUS :: struct { diff --git a/core/sys/windows/ole32.odin b/core/sys/windows/ole32.odin index 8535a6f87..32cb6fd60 100644 --- a/core/sys/windows/ole32.odin +++ b/core/sys/windows/ole32.odin @@ -25,11 +25,12 @@ COINIT :: enum DWORD { SPEED_OVER_MEMORY = 0x8, } +IUnknown_UUID_STRING :: "00000000-0000-0000-C000-000000000046" +IUnknown_UUID := &IID{0x00000000, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}} +IUnknownVtbl :: IUnknown_VTable IUnknown :: struct { using _iunknown_vtable: ^IUnknown_VTable, } - -IUnknownVtbl :: IUnknown_VTable IUnknown_VTable :: struct { QueryInterface: proc "system" (This: ^IUnknown, riid: REFIID, ppvObject: ^rawptr) -> HRESULT, AddRef: proc "system" (This: ^IUnknown) -> ULONG, @@ -52,10 +53,12 @@ foreign Ole32 { ppv: ^LPVOID, ) -> HRESULT --- + CoTaskMemAlloc :: proc(cb: SIZE_T) -> rawptr --- + CoTaskMemRealloc :: proc(pv: rawptr, cb: SIZE_T) -> rawptr --- CoTaskMemFree :: proc(pv: rawptr) --- CLSIDFromProgID :: proc(lpszProgID: LPCOLESTR, lpclsid: LPCLSID) -> HRESULT --- - CLSIDFromProgIDEx :: proc(lpszProgID, LPCOLESTR, lpclsid: LPCLSID) -> HRESULT --- + CLSIDFromProgIDEx :: proc(lpszProgID: LPCOLESTR, lpclsid: LPCLSID) -> HRESULT --- CLSIDFromString :: proc(lpsz: LPOLESTR, pclsid: LPCLSID) -> HRESULT --- IIDFromString :: proc(lpsz: LPOLESTR, lpiid: LPIID) -> HRESULT --- ProgIDFromCLSID :: proc(clsid: REFCLSID, lplpszProgID: ^LPOLESTR) -> HRESULT --- diff --git a/core/sys/windows/scan_codes.odin b/core/sys/windows/scan_codes.odin new file mode 100644 index 000000000..54949c2f6 --- /dev/null +++ b/core/sys/windows/scan_codes.odin @@ -0,0 +1,172 @@ +#+build windows +package sys_windows + +// Win32 scan codes for QWERTY layout +// https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input#scan-codes + +KB_SYS_POWERDOWN :: 0xE05E +KB_SYS_SLEEP :: 0xE05F +KB_SYS_WAKEUP :: 0xE063 +KB_ERR_ROLLOVER :: 0x00FF + +KB_A :: 0x001E +KB_B :: 0x0030 +KB_C :: 0x002E +KB_D :: 0x0020 +KB_E :: 0x0012 +KB_F :: 0x0021 +KB_G :: 0x0022 +KB_H :: 0x0023 +KB_I :: 0x0017 +KB_J :: 0x0024 +KB_K :: 0x0025 +KB_L :: 0x0026 +KB_M :: 0x0032 +KB_N :: 0x0031 +KB_O :: 0x0018 +KB_P :: 0x0019 +KB_Q :: 0x0010 +KB_R :: 0x0013 +KB_S :: 0x001F +KB_T :: 0x0014 +KB_U :: 0x0016 +KB_V :: 0x002F +KB_W :: 0x0011 +KB_X :: 0x002D +KB_Y :: 0x0015 +KB_Z :: 0x002C + +KB_1_BANG :: 0x0002 +KB_2_AT :: 0x0003 +KB_3_HASH :: 0x0004 +KB_4_DOLLAR :: 0x0005 +KB_5_PERCENT :: 0x0006 +KB_6_CARET :: 0x0007 +KB_7_AMPERSAND :: 0x0008 +KB_8_STAR :: 0x0009 +KB_9_LEFTBRACKET :: 0x000A +KB_0_RIGHTBRACKET :: 0x000B + +KB_RETURN_ENTER :: 0x001C +KB_ESCAPE :: 0x0001 +KB_DELETE :: 0x000E +KB_TAB :: 0x000F +KB_SPACEBAR :: 0x0039 +KB_DASH_UNDERSCORE :: 0x000C +KB_EQUALS_PLUS :: 0x000D +KB_LEFTBRACE :: 0x001A +KB_RIGHTBRACE :: 0x001B +KB_PIPE_SLASH :: 0x002B +KB_NONUS :: 0x002B +KB_SEMICOLON_COLON :: 0x0027 +KB_APOSTR_DOUBLEQUOT :: 0x0028 +KB_GRAVEACC_TILDE :: 0x0029 +KB_COMMA :: 0x0033 +KB_PERIOD :: 0x0034 +KB_QUESTIONMARK :: 0x0035 +KB_CAPSLOCK :: 0x003A + +KB_F1 :: 0x003B +KB_F2 :: 0x003C +KB_F3 :: 0x003D +KB_F4 :: 0x003E +KB_F5 :: 0x003F +KB_F6 :: 0x0040 +KB_F7 :: 0x0041 +KB_F8 :: 0x0042 +KB_F9 :: 0x0043 +KB_F10 :: 0x0044 +KB_F11 :: 0x0057 +KB_F12 :: 0x0058 + +KB_PRINTSCREEN :: 0xE037 +KB_SCROLLLOCK :: 0x0046 +KB_PAUSE :: 0xE11D45 +KB_INSERT :: 0xE052 +KB_HOME :: 0xE047 +KB_PAGEUP :: 0xE049 +KB_DELETEFORWARD :: 0xE053 +KB_END :: 0xE04F +KB_PAGEDOWN :: 0xE051 +KB_RIGHTARROW :: 0xE04D +KB_LEFTARROW :: 0xE04B +KB_DOWNARROW :: 0xE050 +KB_UPARROW :: 0xE048 + +KP_NUMLOCK_CLEAR :: 0x0045 +KP_FORWARDSLASH :: 0xE035 +KP_STAR :: 0x0037 +KP_DASH :: 0x004A +KP_PLUS :: 0x004E +KP_ENTER :: 0xE01C +KP_1_END :: 0x004F +KP_2_DOWNARROW :: 0x0050 +KP_3_PAGEDN :: 0x0051 +KP_4_LEFTARROW :: 0x004B +KP_5 :: 0x004C +KP_6_RIGHTARROW :: 0x004D +KP_7_HOME :: 0x0047 +KP_8_UPARROW :: 0x0048 +KP_9_PAGEUP :: 0x0049 +KP_0_INSERT :: 0x0052 +KP_PERIOD :: 0x0053 + +KB_NONUS_SLASHBAR :: 0x0056 +KB_APPLICATION :: 0xE05D +KB_POWER :: 0xE05E +KB_EQUALS :: 0x0059 +KB_F13 :: 0x0064 +KB_F14 :: 0x0065 +KB_F15 :: 0x0066 +KB_F16 :: 0x0067 +KB_F17 :: 0x0068 +KB_F18 :: 0x0069 +KB_F19 :: 0x006A +KB_F20 :: 0x006B +KB_F21 :: 0x006C +KB_F22 :: 0x006D +KB_F23 :: 0x006E +KB_F24 :: 0x0076 + +KP_COMMA :: 0x007E + +KB_INTERNATIONAL1 :: 0x0073 +KB_INTERNATIONAL2 :: 0x0070 +KB_INTERNATIONAL3 :: 0x007D +KB_INTERNATIONAL4 :: 0x0079 +KB_INTERNATIONAL5 :: 0x007B +KB_INTERNATIONAL6 :: 0x005C + +KB_LANG1 :: 0x0072 +KB_LANG2 :: 0x0071 +KB_LANG3 :: 0x0078 +KB_LANG4 :: 0x0077 +KB_LANG5 :: 0x0076 + +KB_LEFTCONTROL :: 0x001D +KB_LEFTSHIFT :: 0x002A +KB_LEFTALT :: 0x0038 +KB_LEFTGUI :: 0xE05B +KB_RIGHTCONTROL :: 0xE01D +KB_RIGHTSHIFT :: 0x0036 +KB_RIGHTALT :: 0xE038 +KB_RIGHTGUI :: 0xE05C + +FN_SCANNEXTTRACK :: 0xE019 +FN_SCANPREVTRACK :: 0xE010 +FN_STOP :: 0xE024 +FN_PLAY_PAUSE :: 0xE022 +FN_MUTE :: 0xE020 +FN_VOLUMEINC :: 0xE030 +FN_VOLUMEDEC :: 0xE02E +FN_AL_CONSUMERCTRLCONFIG :: 0xE06D +FN_AL_EMAILREADER :: 0xE06C +FN_AL_CALCULATOR :: 0xE021 +FN_AL_LOCALMACHINEBROWSER :: 0xE06B +FN_AC_SEARCH :: 0xE065 +FN_AC_HOME :: 0xE032 +FN_AC_BACK :: 0xE06A +FN_AC_FORWARD :: 0xE069 +FN_AC_STOP :: 0xE068 +FN_AC_REFRESH :: 0xE067 +FN_AC_BOOKMARKS :: 0xE066 diff --git a/core/sys/windows/types.odin b/core/sys/windows/types.odin index f698b63d4..904970589 100644 --- a/core/sys/windows/types.odin +++ b/core/sys/windows/types.odin @@ -107,8 +107,8 @@ PDWORD64 :: ^DWORD64 PDWORD_PTR :: ^DWORD_PTR ATOM :: distinct WORD -wstring :: [^]WCHAR -PWSTR :: [^]WCHAR +wstring :: cstring16 +PWSTR :: cstring16 PBYTE :: ^BYTE LPBYTE :: ^BYTE @@ -145,7 +145,7 @@ LPSTR :: ^CHAR LPWSTR :: ^WCHAR OLECHAR :: WCHAR BSTR :: ^OLECHAR -LPOLESTR :: ^OLECHAR +LPOLESTR :: cstring16 LPCOLESTR :: LPCSTR LPFILETIME :: ^FILETIME LPWSABUF :: ^WSABUF @@ -1698,7 +1698,7 @@ NM_FONTCHANGED :: NM_OUTOFMEMORY-22 NM_CUSTOMTEXT :: NM_OUTOFMEMORY-23 // uses NMCUSTOMTEXT struct NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING struct, defined after HTREEITEM -PCZZWSTR :: ^WCHAR +PCZZWSTR :: cstring16 SHFILEOPSTRUCTW :: struct { hwnd: HWND, @@ -3385,6 +3385,19 @@ FILE_ATTRIBUTE_TAG_INFO :: struct { ReparseTag: DWORD, } +// getaddrinfo flags https://learn.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-addrinfoa +AI_PASSIVE :: 0x01 +AI_CANONNAME :: 0x02 +AI_NUMERICHOST :: 0x04 +AI_ALL :: 0x0100 +AI_ADDRCONFIG :: 0x0400 +AI_V4MAPPED :: 0x0800 +AI_NON_AUTHORITATIVE :: 0x04000 +AI_SECURE :: 0x08000 +AI_RETURN_PREFERRED_NAMES :: 0x010000 +AI_FQDN :: 0x00020000 +AI_FILESERVER :: 0x00040000 + PADDRINFOEXW :: ^ADDRINFOEXW LPADDRINFOEXW :: ^ADDRINFOEXW ADDRINFOEXW :: struct { @@ -4845,6 +4858,12 @@ SOMAXCONN :: 128 // The number of messages that can be queued in memory after SOCKET_ERROR :: -1 // Networking errors +WSA_INVALID_HANDLE :: 6 // Specified event object handle is invalid. +WSA_NOT_ENOUGH_MEMORY :: 8 // Insufficient memory available. +WSA_INVALID_PARAMETER :: 87 // One or more parameters are invalid. +WSA_OPERATION_ABORTED :: 995 // Overlapped operation aborted. +WSA_IO_INCOMPLETE :: 996 // Overlapped I/O event object not in signaled state. +WSA_IO_PENDING :: 997 // Overlapped operations will complete later. WSAEINTR :: 10004 // Call interrupted. CancelBlockingCall was called. (This is different on Linux.) WSAEACCES :: 10013 // If you try to bind a Udp socket to the broadcast address without the socket option set. WSAEFAULT :: 10014 // A pointer that was passed to a WSA function is invalid, such as a buffer size is smaller than you said it was diff --git a/core/sys/windows/user32.odin b/core/sys/windows/user32.odin index 94cd57811..49ebb49cb 100644 --- a/core/sys/windows/user32.odin +++ b/core/sys/windows/user32.odin @@ -47,6 +47,8 @@ foreign user32 { lpParam: LPVOID, ) -> HWND --- + GetWindowThreadProcessId :: proc(hwnd: HWND, lpdwProcessId: LPDWORD) -> DWORD --- + DestroyWindow :: proc(hWnd: HWND) -> BOOL --- ShowWindow :: proc(hWnd: HWND, nCmdShow: INT) -> BOOL --- diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin index b3eb800bc..125038ac4 100644 --- a/core/sys/windows/util.odin +++ b/core/sys/windows/util.odin @@ -75,15 +75,7 @@ LANGIDFROMLCID :: #force_inline proc "contextless" (lcid: LCID) -> LANGID { return LANGID(lcid) } -// this one gave me trouble as it do not mask the values. -// the _ in the name is also off comparing to the c code -// i can't find any usage in the odin repo -@(deprecated = "use MAKEWORD") -MAKE_WORD :: #force_inline proc "contextless" (x, y: WORD) -> WORD { - return x << 8 | y -} - -utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 { +utf8_to_utf16_alloc :: proc(s: string, allocator := context.temp_allocator) -> []u16 { if len(s) < 1 { return nil } @@ -109,14 +101,42 @@ utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 { } return text[:n] } -utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> wstring { + +utf8_to_utf16_buf :: proc(buf: []u16, s: string) -> []u16 { + n1 := MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), nil, 0) + if n1 == 0 { + return nil + } else if int(n1) > len(buf) { + return nil + } + + n1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, raw_data(s), i32(len(s)), raw_data(buf[:]), n1) + if n1 == 0 { + return nil + } else if int(n1) > len(buf) { + return nil + } + return buf[:n1] +} +utf8_to_utf16 :: proc{utf8_to_utf16_alloc, utf8_to_utf16_buf} + +utf8_to_wstring_alloc :: proc(s: string, allocator := context.temp_allocator) -> wstring { if res := utf8_to_utf16(s, allocator); len(res) > 0 { - return raw_data(res) + return wstring(raw_data(res)) } return nil } -wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) { +utf8_to_wstring_buf :: proc(buf: []u16, s: string) -> wstring { + if res := utf8_to_utf16(buf, s); len(res) > 0 { + return wstring(raw_data(res)) + } + return nil +} + +utf8_to_wstring :: proc{utf8_to_wstring_alloc, utf8_to_wstring_buf} + +wstring_to_utf8_alloc :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) { context.allocator = allocator if N == 0 { @@ -150,13 +170,78 @@ wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) return string(text[:n]), nil } -utf16_to_utf8 :: proc(s: []u16, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) { +wstring_to_utf8_buf :: proc(buf: []u8, s: wstring, N := -1) -> (res: string) { + n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), nil, 0, nil, nil) + if n == 0 { + return + } else if int(n) > len(buf) { + return + } + + n2 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), raw_data(buf), n, nil, nil) + if n2 == 0 { + return + } else if int(n2) > len(buf) { + return + } + + for i in 0.. (res: string, err: runtime.Allocator_Error) { if len(s) == 0 { return "", nil } - return wstring_to_utf8(raw_data(s), len(s), allocator) + return wstring_to_utf8(wstring(raw_data(s)), len(s), allocator) } +/* +Converts a UTF-16 string into a regular UTF-8 `string`, using `buf` as its backing. +If the input is null-terminated, only the part of the input string leading up +to it will be converted. + +*Uses `buf` for backing* + +Inputs: +- s: The string to be converted +- buf: Backing buffer for result string + +Returns: +- res: A converted string, backed byu `buf` +*/ +utf16_to_utf8_buf :: proc(buf: []u8, s: []u16) -> (res: string) { + if len(s) == 0 { + return + } + return wstring_to_utf8(buf, wstring(raw_data(s)), len(s)) +} + +utf16_to_utf8 :: proc{utf16_to_utf8_alloc, utf16_to_utf8_buf} + + // AdvAPI32, NetAPI32 and UserENV helpers. allowed_username :: proc(username: string) -> bool { @@ -213,7 +298,7 @@ _add_user :: proc(servername: string, username: string, password: string) -> (ok servername_w = nil } else { server := utf8_to_utf16(servername, context.temp_allocator) - servername_w = &server[0] + servername_w = wstring(&server[0]) } if len(username) == 0 || len(username) > LM20_UNLEN { @@ -263,7 +348,7 @@ get_computer_name_and_account_sid :: proc(username: string) -> (computer_name: s res := LookupAccountNameW( nil, // Look on this computer first - &username_w[0], + wstring(&username_w[0]), &sid, &cbsid, nil, @@ -279,10 +364,10 @@ get_computer_name_and_account_sid :: proc(username: string) -> (computer_name: s res = LookupAccountNameW( nil, - &username_w[0], + wstring(&username_w[0]), &sid, &cbsid, - &cname_w[0], + wstring(&cname_w[0]), &computer_name_size, &pe_use, ) @@ -305,7 +390,7 @@ get_sid :: proc(username: string, sid: ^SID) -> (ok: bool) { res := LookupAccountNameW( nil, // Look on this computer first - &username_w[0], + wstring(&username_w[0]), sid, &cbsid, nil, @@ -321,10 +406,10 @@ get_sid :: proc(username: string, sid: ^SID) -> (ok: bool) { res = LookupAccountNameW( nil, - &username_w[0], + wstring(&username_w[0]), sid, &cbsid, - &cname_w[0], + wstring(&cname_w[0]), &computer_name_size, &pe_use, ) @@ -343,7 +428,7 @@ add_user_to_group :: proc(sid: ^SID, group: string) -> (ok: NET_API_STATUS) { group_name := utf8_to_utf16(group, context.temp_allocator) ok = NetLocalGroupAddMembers( nil, - &group_name[0], + wstring(&group_name[0]), 0, &group_member, 1, @@ -358,7 +443,7 @@ add_del_from_group :: proc(sid: ^SID, group: string) -> (ok: NET_API_STATUS) { group_name := utf8_to_utf16(group, context.temp_allocator) ok = NetLocalGroupDelMembers( nil, - &group_name[0], + cstring16(&group_name[0]), 0, &group_member, 1, @@ -380,19 +465,19 @@ add_user_profile :: proc(username: string) -> (ok: bool, profile_path: string) { if res == false { return false, "" } - defer LocalFree(sb) + defer LocalFree(rawptr(sb)) pszProfilePath := make([]u16, 257, context.temp_allocator) res2 := CreateProfile( sb, - &username_w[0], - &pszProfilePath[0], + cstring16(&username_w[0]), + cstring16(&pszProfilePath[0]), 257, ) if res2 != 0 { return false, "" } - profile_path = wstring_to_utf8(&pszProfilePath[0], 257) or_else "" + profile_path = wstring_to_utf8(wstring(&pszProfilePath[0]), 257) or_else "" return true, profile_path } @@ -410,7 +495,7 @@ delete_user_profile :: proc(username: string) -> (ok: bool) { if res == false { return false } - defer LocalFree(sb) + defer LocalFree(rawptr(sb)) res2 := DeleteProfileW( sb, @@ -463,13 +548,13 @@ delete_user :: proc(servername: string, username: string) -> (ok: bool) { servername_w = nil } else { server := utf8_to_utf16(servername, context.temp_allocator) - servername_w = &server[0] + servername_w = wstring(&server[0]) } username_w := utf8_to_utf16(username) res := NetUserDel( servername_w, - &username_w[0], + wstring(&username_w[0]), ) if res != .Success { return false @@ -501,9 +586,9 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P user_token: HANDLE ok = bool(LogonUserW( - lpszUsername = &username_w[0], - lpszDomain = &domain_w[0], - lpszPassword = &password_w[0], + lpszUsername = wstring(&username_w[0]), + lpszDomain = wstring(&domain_w[0]), + lpszPassword = wstring(&password_w[0]), dwLogonType = .NEW_CREDENTIALS, dwLogonProvider = .WINNT50, phToken = &user_token, @@ -520,8 +605,8 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P ok = bool(CreateProcessAsUserW( user_token, - &app_w[0], - &commandline_w[0], + wstring(&app_w[0]), + wstring(&commandline_w[0]), nil, // lpProcessAttributes, nil, // lpThreadAttributes, false, // bInheritHandles, @@ -543,7 +628,7 @@ run_as_user :: proc(username, password, application, commandline: string, pi: ^P } } -ensure_winsock_initialized :: proc() { +ensure_winsock_initialized :: proc "contextless" () { @static gate := false @static initted := false @@ -559,7 +644,7 @@ ensure_winsock_initialized :: proc() { unused_info: WSADATA version_requested := WORD(2) << 8 | 2 res := WSAStartup(version_requested, &unused_info) - assert(res == 0, "unable to initialized Winsock2") + assert_contextless(res == 0, "unable to initialized Winsock2") initted = true } diff --git a/core/sys/windows/wgl.odin b/core/sys/windows/wgl.odin index 8fea55c3d..f50f06939 100644 --- a/core/sys/windows/wgl.odin +++ b/core/sys/windows/wgl.odin @@ -82,7 +82,8 @@ foreign Opengl32 { wglSetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: c.int, cr: ^COLORREF) -> c.int --- wglShareLists :: proc(HGLRC1, HGLRC2: HGLRC) -> BOOL --- wglSwapLayerBuffers :: proc(hdc: HDC, planes: DWORD) -> BOOL --- - wglUseFontBitmaps :: proc(hdc: HDC, first, count, list_base: DWORD) -> BOOL --- + wglUseFontBitmapsA :: proc(hdc: HDC, first, count, list_base: DWORD) -> BOOL --- + wglUseFontBitmapsW :: proc(hdc: HDC, first, count, list_base: DWORD) -> BOOL --- wglUseFontOutlines :: proc(hdc: HDC, first, count, list_base: DWORD, deviation, extrusion: f32, format: c.int, gmf: LPGLYPHMETRICSFLOAT) -> BOOL --- } diff --git a/core/sys/windows/winerror.odin b/core/sys/windows/winerror.odin index 61a7d9d86..23467761d 100644 --- a/core/sys/windows/winerror.odin +++ b/core/sys/windows/winerror.odin @@ -173,6 +173,9 @@ FACILITY :: enum DWORD { EAS = 85, WEB = 885, WEB_SOCKET = 886, + XAUDIO2 = 896, + XAPO = 897, + GAMEINPUT = 906, MOBILE = 1793, SQLITE = 1967, SERVICE_FABRIC = 1968, @@ -219,9 +222,11 @@ ERROR_LOCK_FAILED : DWORD : 167 ERROR_ALREADY_EXISTS : DWORD : 183 ERROR_NO_DATA : DWORD : 232 ERROR_ENVVAR_NOT_FOUND : DWORD : 203 +ERROR_MR_MID_NOT_FOUND : DWORD : 317 ERROR_OPERATION_ABORTED : DWORD : 995 ERROR_IO_PENDING : DWORD : 997 ERROR_NO_UNICODE_TRANSLATION : DWORD : 1113 +ERROR_NOT_FOUND : DWORD : 1168 ERROR_TIMEOUT : DWORD : 1460 ERROR_DATATYPE_MISMATCH : DWORD : 1629 ERROR_UNSUPPORTED_TYPE : DWORD : 1630 @@ -231,6 +236,7 @@ ERROR_PIPE_BUSY : DWORD : 231 // https://learn.microsoft.com/en-us/windows/win32/seccrypto/common-hresult-values S_OK :: 0x00000000 // Operation successful +S_FALSE :: 0x00000001 E_NOTIMPL :: 0x80004001 // Not implemented E_NOINTERFACE :: 0x80004002 // No such interface supported E_POINTER :: 0x80004003 // Pointer that is not valid @@ -270,6 +276,10 @@ MAKE_HRESULT :: #force_inline proc "contextless" (#any_int sev: int, #any_int fa return HRESULT((uint(sev)<<31) | (uint(fac)<<16) | (uint(code))) } +HRESULT_FROM_WIN32 :: #force_inline proc "contextless" (#any_int code: int) -> HRESULT { + return HRESULT(code) <= 0 ? HRESULT(code) : HRESULT(uint(code & 0x0000FFFF) | (uint(FACILITY.WIN32) << 16) | 0x80000000) +} + DECODE_HRESULT :: #force_inline proc "contextless" (#any_int hr: int) -> (SEVERITY, FACILITY, int) { return HRESULT_SEVERITY(hr), HRESULT_FACILITY(hr), HRESULT_CODE(hr) } diff --git a/core/sys/windows/winmm.odin b/core/sys/windows/winmm.odin index 3c7ec80e7..b85548b85 100644 --- a/core/sys/windows/winmm.odin +++ b/core/sys/windows/winmm.odin @@ -265,7 +265,7 @@ HWAVE :: distinct HANDLE HWAVEIN :: distinct HANDLE HWAVEOUT :: distinct HANDLE -LPHWAVEIN :: ^HWAVEIN +LPHWAVEIN :: ^HWAVEIN LPHWAVEOUT :: ^HWAVEOUT // https://learn.microsoft.com/en-us/windows/win32/multimedia/multimedia-timer-structures @@ -311,10 +311,285 @@ MAXPNAMELEN :: 32 MAXERRORLENGTH :: 256 MMVERSION :: UINT +// Input is four characters string +// Output is little-endian u32 representation +MAKEFOURCC :: #force_inline proc "contextless" (s: [4]byte) -> DWORD { + return (DWORD(s[0])) | (DWORD(s[1]) << 8) | (DWORD(s[2]) << 16) | (DWORD(s[3]) << 24 ) +} + /* flags for wFormatTag field of WAVEFORMAT */ WAVE_FORMAT_PCM :: 1 -WAVEFORMATEX :: struct { +WAVE_FORMAT_UNKNOWN :: 0x0000 /* Microsoft Corporation */ +WAVE_FORMAT_ADPCM :: 0x0002 /* Microsoft Corporation */ +WAVE_FORMAT_IEEE_FLOAT :: 0x0003 /* Microsoft Corporation */ +WAVE_FORMAT_VSELP :: 0x0004 /* Compaq Computer Corp. */ +WAVE_FORMAT_IBM_CVSD :: 0x0005 /* IBM Corporation */ +WAVE_FORMAT_ALAW :: 0x0006 /* Microsoft Corporation */ +WAVE_FORMAT_MULAW :: 0x0007 /* Microsoft Corporation */ +WAVE_FORMAT_DTS :: 0x0008 /* Microsoft Corporation */ +WAVE_FORMAT_DRM :: 0x0009 /* Microsoft Corporation */ +WAVE_FORMAT_WMAVOICE9 :: 0x000A /* Microsoft Corporation */ +WAVE_FORMAT_WMAVOICE10 :: 0x000B /* Microsoft Corporation */ +WAVE_FORMAT_OKI_ADPCM :: 0x0010 /* OKI */ +WAVE_FORMAT_DVI_ADPCM :: 0x0011 /* Intel Corporation */ +WAVE_FORMAT_IMA_ADPCM :: WAVE_FORMAT_DVI_ADPCM /* Intel Corporation */ +WAVE_FORMAT_MEDIASPACE_ADPCM :: 0x0012 /* Videologic */ +WAVE_FORMAT_SIERRA_ADPCM :: 0x0013 /* Sierra Semiconductor Corp */ +WAVE_FORMAT_G723_ADPCM :: 0x0014 /* Antex Electronics Corporation */ +WAVE_FORMAT_DIGISTD :: 0x0015 /* DSP Solutions, Inc. */ +WAVE_FORMAT_DIGIFIX :: 0x0016 /* DSP Solutions, Inc. */ +WAVE_FORMAT_DIALOGIC_OKI_ADPCM :: 0x0017 /* Dialogic Corporation */ +WAVE_FORMAT_MEDIAVISION_ADPCM :: 0x0018 /* Media Vision, Inc. */ +WAVE_FORMAT_CU_CODEC :: 0x0019 /* Hewlett-Packard Company */ +WAVE_FORMAT_HP_DYN_VOICE :: 0x001A /* Hewlett-Packard Company */ +WAVE_FORMAT_YAMAHA_ADPCM :: 0x0020 /* Yamaha Corporation of America */ +WAVE_FORMAT_SONARC :: 0x0021 /* Speech Compression */ +WAVE_FORMAT_DSPGROUP_TRUESPEECH :: 0x0022 /* DSP Group, Inc */ +WAVE_FORMAT_ECHOSC1 :: 0x0023 /* Echo Speech Corporation */ +WAVE_FORMAT_AUDIOFILE_AF36 :: 0x0024 /* Virtual Music, Inc. */ +WAVE_FORMAT_APTX :: 0x0025 /* Audio Processing Technology */ +WAVE_FORMAT_AUDIOFILE_AF10 :: 0x0026 /* Virtual Music, Inc. */ +WAVE_FORMAT_PROSODY_1612 :: 0x0027 /* Aculab plc */ +WAVE_FORMAT_LRC :: 0x0028 /* Merging Technologies S.A. */ +WAVE_FORMAT_DOLBY_AC2 :: 0x0030 /* Dolby Laboratories */ +WAVE_FORMAT_GSM610 :: 0x0031 /* Microsoft Corporation */ +WAVE_FORMAT_MSNAUDIO :: 0x0032 /* Microsoft Corporation */ +WAVE_FORMAT_ANTEX_ADPCME :: 0x0033 /* Antex Electronics Corporation */ +WAVE_FORMAT_CONTROL_RES_VQLPC :: 0x0034 /* Control Resources Limited */ +WAVE_FORMAT_DIGIREAL :: 0x0035 /* DSP Solutions, Inc. */ +WAVE_FORMAT_DIGIADPCM :: 0x0036 /* DSP Solutions, Inc. */ +WAVE_FORMAT_CONTROL_RES_CR10 :: 0x0037 /* Control Resources Limited */ +WAVE_FORMAT_NMS_VBXADPCM :: 0x0038 /* Natural MicroSystems */ +WAVE_FORMAT_CS_IMAADPCM :: 0x0039 /* Crystal Semiconductor IMA ADPCM */ +WAVE_FORMAT_ECHOSC3 :: 0x003A /* Echo Speech Corporation */ +WAVE_FORMAT_ROCKWELL_ADPCM :: 0x003B /* Rockwell International */ +WAVE_FORMAT_ROCKWELL_DIGITALK :: 0x003C /* Rockwell International */ +WAVE_FORMAT_XEBEC :: 0x003D /* Xebec Multimedia Solutions Limited */ +WAVE_FORMAT_G721_ADPCM :: 0x0040 /* Antex Electronics Corporation */ +WAVE_FORMAT_G728_CELP :: 0x0041 /* Antex Electronics Corporation */ +WAVE_FORMAT_MSG723 :: 0x0042 /* Microsoft Corporation */ +WAVE_FORMAT_INTEL_G723_1 :: 0x0043 /* Intel Corp. */ +WAVE_FORMAT_INTEL_G729 :: 0x0044 /* Intel Corp. */ +WAVE_FORMAT_SHARP_G726 :: 0x0045 /* Sharp */ +WAVE_FORMAT_MPEG :: 0x0050 /* Microsoft Corporation */ +WAVE_FORMAT_RT24 :: 0x0052 /* InSoft, Inc. */ +WAVE_FORMAT_PAC :: 0x0053 /* InSoft, Inc. */ +WAVE_FORMAT_MPEGLAYER3 :: 0x0055 /* ISO/MPEG Layer3 Format Tag */ +WAVE_FORMAT_LUCENT_G723 :: 0x0059 /* Lucent Technologies */ +WAVE_FORMAT_CIRRUS :: 0x0060 /* Cirrus Logic */ +WAVE_FORMAT_ESPCM :: 0x0061 /* ESS Technology */ +WAVE_FORMAT_VOXWARE :: 0x0062 /* Voxware Inc */ +WAVE_FORMAT_CANOPUS_ATRAC :: 0x0063 /* Canopus, co., Ltd. */ +WAVE_FORMAT_G726_ADPCM :: 0x0064 /* APICOM */ +WAVE_FORMAT_G722_ADPCM :: 0x0065 /* APICOM */ +WAVE_FORMAT_DSAT :: 0x0066 /* Microsoft Corporation */ +WAVE_FORMAT_DSAT_DISPLAY :: 0x0067 /* Microsoft Corporation */ +WAVE_FORMAT_VOXWARE_BYTE_ALIGNED :: 0x0069 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_AC8 :: 0x0070 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_AC10 :: 0x0071 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_AC16 :: 0x0072 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_AC20 :: 0x0073 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_RT24 :: 0x0074 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_RT29 :: 0x0075 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_RT29HW :: 0x0076 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_VR12 :: 0x0077 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_VR18 :: 0x0078 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_TQ40 :: 0x0079 /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_SC3 :: 0x007A /* Voxware Inc */ +WAVE_FORMAT_VOXWARE_SC3_1 :: 0x007B /* Voxware Inc */ +WAVE_FORMAT_SOFTSOUND :: 0x0080 /* Softsound, Ltd. */ +WAVE_FORMAT_VOXWARE_TQ60 :: 0x0081 /* Voxware Inc */ +WAVE_FORMAT_MSRT24 :: 0x0082 /* Microsoft Corporation */ +WAVE_FORMAT_G729A :: 0x0083 /* AT&T Labs, Inc. */ +WAVE_FORMAT_MVI_MVI2 :: 0x0084 /* Motion Pixels */ +WAVE_FORMAT_DF_G726 :: 0x0085 /* DataFusion Systems (Pty) (Ltd) */ +WAVE_FORMAT_DF_GSM610 :: 0x0086 /* DataFusion Systems (Pty) (Ltd) */ +WAVE_FORMAT_ISIAUDIO :: 0x0088 /* Iterated Systems, Inc. */ +WAVE_FORMAT_ONLIVE :: 0x0089 /* OnLive! Technologies, Inc. */ +WAVE_FORMAT_MULTITUDE_FT_SX20 :: 0x008A /* Multitude Inc. */ +WAVE_FORMAT_INFOCOM_ITS_G721_ADPCM :: 0x008B /* Infocom */ +WAVE_FORMAT_CONVEDIA_G729 :: 0x008C /* Convedia Corp. */ +WAVE_FORMAT_CONGRUENCY :: 0x008D /* Congruency Inc. */ +WAVE_FORMAT_SBC24 :: 0x0091 /* Siemens Business Communications Sys */ +WAVE_FORMAT_DOLBY_AC3_SPDIF :: 0x0092 /* Sonic Foundry */ +WAVE_FORMAT_MEDIASONIC_G723 :: 0x0093 /* MediaSonic */ +WAVE_FORMAT_PROSODY_8KBPS :: 0x0094 /* Aculab plc */ +WAVE_FORMAT_ZYXEL_ADPCM :: 0x0097 /* ZyXEL Communications, Inc. */ +WAVE_FORMAT_PHILIPS_LPCBB :: 0x0098 /* Philips Speech Processing */ +WAVE_FORMAT_PACKED :: 0x0099 /* Studer Professional Audio AG */ +WAVE_FORMAT_MALDEN_PHONYTALK :: 0x00A0 /* Malden Electronics Ltd. */ +WAVE_FORMAT_RACAL_RECORDER_GSM :: 0x00A1 /* Racal recorders */ +WAVE_FORMAT_RACAL_RECORDER_G720_A :: 0x00A2 /* Racal recorders */ +WAVE_FORMAT_RACAL_RECORDER_G723_1 :: 0x00A3 /* Racal recorders */ +WAVE_FORMAT_RACAL_RECORDER_TETRA_ACELP :: 0x00A4 /* Racal recorders */ +WAVE_FORMAT_NEC_AAC :: 0x00B0 /* NEC Corp. */ +WAVE_FORMAT_RAW_AAC1 :: 0x00FF /* For Raw AAC, with format block AudioSpecificConfig() (as defined by MPEG-4), that follows WAVEFORMATEX */ +WAVE_FORMAT_RHETOREX_ADPCM :: 0x0100 /* Rhetorex Inc. */ +WAVE_FORMAT_IRAT :: 0x0101 /* BeCubed Software Inc. */ +WAVE_FORMAT_VIVO_G723 :: 0x0111 /* Vivo Software */ +WAVE_FORMAT_VIVO_SIREN :: 0x0112 /* Vivo Software */ +WAVE_FORMAT_PHILIPS_CELP :: 0x0120 /* Philips Speech Processing */ +WAVE_FORMAT_PHILIPS_GRUNDIG :: 0x0121 /* Philips Speech Processing */ +WAVE_FORMAT_DIGITAL_G723 :: 0x0123 /* Digital Equipment Corporation */ +WAVE_FORMAT_SANYO_LD_ADPCM :: 0x0125 /* Sanyo Electric Co., Ltd. */ +WAVE_FORMAT_SIPROLAB_ACEPLNET :: 0x0130 /* Sipro Lab Telecom Inc. */ +WAVE_FORMAT_SIPROLAB_ACELP4800 :: 0x0131 /* Sipro Lab Telecom Inc. */ +WAVE_FORMAT_SIPROLAB_ACELP8V3 :: 0x0132 /* Sipro Lab Telecom Inc. */ +WAVE_FORMAT_SIPROLAB_G729 :: 0x0133 /* Sipro Lab Telecom Inc. */ +WAVE_FORMAT_SIPROLAB_G729A :: 0x0134 /* Sipro Lab Telecom Inc. */ +WAVE_FORMAT_SIPROLAB_KELVIN :: 0x0135 /* Sipro Lab Telecom Inc. */ +WAVE_FORMAT_VOICEAGE_AMR :: 0x0136 /* VoiceAge Corp. */ +WAVE_FORMAT_G726ADPCM :: 0x0140 /* Dictaphone Corporation */ +WAVE_FORMAT_DICTAPHONE_CELP68 :: 0x0141 /* Dictaphone Corporation */ +WAVE_FORMAT_DICTAPHONE_CELP54 :: 0x0142 /* Dictaphone Corporation */ +WAVE_FORMAT_QUALCOMM_PUREVOICE :: 0x0150 /* Qualcomm, Inc. */ +WAVE_FORMAT_QUALCOMM_HALFRATE :: 0x0151 /* Qualcomm, Inc. */ +WAVE_FORMAT_TUBGSM :: 0x0155 /* Ring Zero Systems, Inc. */ +WAVE_FORMAT_MSAUDIO1 :: 0x0160 /* Microsoft Corporation */ +WAVE_FORMAT_WMAUDIO2 :: 0x0161 /* Microsoft Corporation */ +WAVE_FORMAT_WMAUDIO3 :: 0x0162 /* Microsoft Corporation */ +WAVE_FORMAT_WMAUDIO_LOSSLESS :: 0x0163 /* Microsoft Corporation */ +WAVE_FORMAT_WMASPDIF :: 0x0164 /* Microsoft Corporation */ +WAVE_FORMAT_UNISYS_NAP_ADPCM :: 0x0170 /* Unisys Corp. */ +WAVE_FORMAT_UNISYS_NAP_ULAW :: 0x0171 /* Unisys Corp. */ +WAVE_FORMAT_UNISYS_NAP_ALAW :: 0x0172 /* Unisys Corp. */ +WAVE_FORMAT_UNISYS_NAP_16K :: 0x0173 /* Unisys Corp. */ +WAVE_FORMAT_SYCOM_ACM_SYC008 :: 0x0174 /* SyCom Technologies */ +WAVE_FORMAT_SYCOM_ACM_SYC701_G726L :: 0x0175 /* SyCom Technologies */ +WAVE_FORMAT_SYCOM_ACM_SYC701_CELP54 :: 0x0176 /* SyCom Technologies */ +WAVE_FORMAT_SYCOM_ACM_SYC701_CELP68 :: 0x0177 /* SyCom Technologies */ +WAVE_FORMAT_KNOWLEDGE_ADVENTURE_ADPCM :: 0x0178 /* Knowledge Adventure, Inc. */ +WAVE_FORMAT_FRAUNHOFER_IIS_MPEG2_AAC :: 0x0180 /* Fraunhofer IIS */ +WAVE_FORMAT_DTS_DS :: 0x0190 /* Digital Theatre Systems, Inc. */ +WAVE_FORMAT_CREATIVE_ADPCM :: 0x0200 /* Creative Labs, Inc */ +WAVE_FORMAT_CREATIVE_FASTSPEECH8 :: 0x0202 /* Creative Labs, Inc */ +WAVE_FORMAT_CREATIVE_FASTSPEECH10 :: 0x0203 /* Creative Labs, Inc */ +WAVE_FORMAT_UHER_ADPCM :: 0x0210 /* UHER informatic GmbH */ +WAVE_FORMAT_ULEAD_DV_AUDIO :: 0x0215 /* Ulead Systems, Inc. */ +WAVE_FORMAT_ULEAD_DV_AUDIO_1 :: 0x0216 /* Ulead Systems, Inc. */ +WAVE_FORMAT_QUARTERDECK :: 0x0220 /* Quarterdeck Corporation */ +WAVE_FORMAT_ILINK_VC :: 0x0230 /* I-link Worldwide */ +WAVE_FORMAT_RAW_SPORT :: 0x0240 /* Aureal Semiconductor */ +WAVE_FORMAT_ESST_AC3 :: 0x0241 /* ESS Technology, Inc. */ +WAVE_FORMAT_GENERIC_PASSTHRU :: 0x0249 +WAVE_FORMAT_IPI_HSX :: 0x0250 /* Interactive Products, Inc. */ +WAVE_FORMAT_IPI_RPELP :: 0x0251 /* Interactive Products, Inc. */ +WAVE_FORMAT_CS2 :: 0x0260 /* Consistent Software */ +WAVE_FORMAT_SONY_SCX :: 0x0270 /* Sony Corp. */ +WAVE_FORMAT_SONY_SCY :: 0x0271 /* Sony Corp. */ +WAVE_FORMAT_SONY_ATRAC3 :: 0x0272 /* Sony Corp. */ +WAVE_FORMAT_SONY_SPC :: 0x0273 /* Sony Corp. */ +WAVE_FORMAT_TELUM_AUDIO :: 0x0280 /* Telum Inc. */ +WAVE_FORMAT_TELUM_IA_AUDIO :: 0x0281 /* Telum Inc. */ +WAVE_FORMAT_NORCOM_VOICE_SYSTEMS_ADPCM :: 0x0285 /* Norcom Electronics Corp. */ +WAVE_FORMAT_FM_TOWNS_SND :: 0x0300 /* Fujitsu Corp. */ +WAVE_FORMAT_MICRONAS :: 0x0350 /* Micronas Semiconductors, Inc. */ +WAVE_FORMAT_MICRONAS_CELP833 :: 0x0351 /* Micronas Semiconductors, Inc. */ +WAVE_FORMAT_BTV_DIGITAL :: 0x0400 /* Brooktree Corporation */ +WAVE_FORMAT_INTEL_MUSIC_CODER :: 0x0401 /* Intel Corp. */ +WAVE_FORMAT_INDEO_AUDIO :: 0x0402 /* Ligos */ +WAVE_FORMAT_QDESIGN_MUSIC :: 0x0450 /* QDesign Corporation */ +WAVE_FORMAT_ON2_VP7_AUDIO :: 0x0500 /* On2 Technologies */ +WAVE_FORMAT_ON2_VP6_AUDIO :: 0x0501 /* On2 Technologies */ +WAVE_FORMAT_VME_VMPCM :: 0x0680 /* AT&T Labs, Inc. */ +WAVE_FORMAT_TPC :: 0x0681 /* AT&T Labs, Inc. */ +WAVE_FORMAT_LIGHTWAVE_LOSSLESS :: 0x08AE /* Clearjump */ +WAVE_FORMAT_OLIGSM :: 0x1000 /* Ing C. Olivetti & C., S.p.A. */ +WAVE_FORMAT_OLIADPCM :: 0x1001 /* Ing C. Olivetti & C., S.p.A. */ +WAVE_FORMAT_OLICELP :: 0x1002 /* Ing C. Olivetti & C., S.p.A. */ +WAVE_FORMAT_OLISBC :: 0x1003 /* Ing C. Olivetti & C., S.p.A. */ +WAVE_FORMAT_OLIOPR :: 0x1004 /* Ing C. Olivetti & C., S.p.A. */ +WAVE_FORMAT_LH_CODEC :: 0x1100 /* Lernout & Hauspie */ +WAVE_FORMAT_LH_CODEC_CELP :: 0x1101 /* Lernout & Hauspie */ +WAVE_FORMAT_LH_CODEC_SBC8 :: 0x1102 /* Lernout & Hauspie */ +WAVE_FORMAT_LH_CODEC_SBC12 :: 0x1103 /* Lernout & Hauspie */ +WAVE_FORMAT_LH_CODEC_SBC16 :: 0x1104 /* Lernout & Hauspie */ +WAVE_FORMAT_NORRIS :: 0x1400 /* Norris Communications, Inc. */ +WAVE_FORMAT_ISIAUDIO_2 :: 0x1401 /* ISIAudio */ +WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS :: 0x1500 /* AT&T Labs, Inc. */ +WAVE_FORMAT_MPEG_ADTS_AAC :: 0x1600 /* Microsoft Corporation */ +WAVE_FORMAT_MPEG_RAW_AAC :: 0x1601 /* Microsoft Corporation */ +WAVE_FORMAT_MPEG_LOAS :: 0x1602 /* Microsoft Corporation (MPEG-4 Audio Transport Streams (LOAS/LATM) */ +WAVE_FORMAT_NOKIA_MPEG_ADTS_AAC :: 0x1608 /* Microsoft Corporation */ +WAVE_FORMAT_NOKIA_MPEG_RAW_AAC :: 0x1609 /* Microsoft Corporation */ +WAVE_FORMAT_VODAFONE_MPEG_ADTS_AAC :: 0x160A /* Microsoft Corporation */ +WAVE_FORMAT_VODAFONE_MPEG_RAW_AAC :: 0x160B /* Microsoft Corporation */ +WAVE_FORMAT_MPEG_HEAAC :: 0x1610 /* Microsoft Corporation (MPEG-2 AAC or MPEG-4 HE-AAC v1/v2 streams with any payload (ADTS, ADIF, LOAS/LATM, RAW). Format block includes MP4 AudioSpecificConfig() -- see HEAACWAVEFORMAT below */ +WAVE_FORMAT_VOXWARE_RT24_SPEECH :: 0x181C /* Voxware Inc. */ +WAVE_FORMAT_SONICFOUNDRY_LOSSLESS :: 0x1971 /* Sonic Foundry */ +WAVE_FORMAT_INNINGS_TELECOM_ADPCM :: 0x1979 /* Innings Telecom Inc. */ +WAVE_FORMAT_LUCENT_SX8300P :: 0x1C07 /* Lucent Technologies */ +WAVE_FORMAT_LUCENT_SX5363S :: 0x1C0C /* Lucent Technologies */ +WAVE_FORMAT_CUSEEME :: 0x1F03 /* CUSeeMe */ +WAVE_FORMAT_NTCSOFT_ALF2CM_ACM :: 0x1FC4 /* NTCSoft */ +WAVE_FORMAT_DVM :: 0x2000 /* FAST Multimedia AG */ +WAVE_FORMAT_DTS2 :: 0x2001 +WAVE_FORMAT_MAKEAVIS :: 0x3313 +WAVE_FORMAT_DIVIO_MPEG4_AAC :: 0x4143 /* Divio, Inc. */ +WAVE_FORMAT_NOKIA_ADAPTIVE_MULTIRATE :: 0x4201 /* Nokia */ +WAVE_FORMAT_DIVIO_G726 :: 0x4243 /* Divio, Inc. */ +WAVE_FORMAT_LEAD_SPEECH :: 0x434C /* LEAD Technologies */ +WAVE_FORMAT_LEAD_VORBIS :: 0x564C /* LEAD Technologies */ +WAVE_FORMAT_WAVPACK_AUDIO :: 0x5756 /* xiph.org */ +WAVE_FORMAT_ALAC :: 0x6C61 /* Apple Lossless */ +WAVE_FORMAT_OGG_VORBIS_MODE_1 :: 0x674F /* Ogg Vorbis */ +WAVE_FORMAT_OGG_VORBIS_MODE_2 :: 0x6750 /* Ogg Vorbis */ +WAVE_FORMAT_OGG_VORBIS_MODE_3 :: 0x6751 /* Ogg Vorbis */ +WAVE_FORMAT_OGG_VORBIS_MODE_1_PLUS :: 0x676F /* Ogg Vorbis */ +WAVE_FORMAT_OGG_VORBIS_MODE_2_PLUS :: 0x6770 /* Ogg Vorbis */ +WAVE_FORMAT_OGG_VORBIS_MODE_3_PLUS :: 0x6771 /* Ogg Vorbis */ +WAVE_FORMAT_3COM_NBX :: 0x7000 /* 3COM Corp. */ +WAVE_FORMAT_OPUS :: 0x704F /* Opus */ +WAVE_FORMAT_FAAD_AAC :: 0x706D +WAVE_FORMAT_AMR_NB :: 0x7361 /* AMR Narrowband */ +WAVE_FORMAT_AMR_WB :: 0x7362 /* AMR Wideband */ +WAVE_FORMAT_AMR_WP :: 0x7363 /* AMR Wideband Plus */ +WAVE_FORMAT_GSM_AMR_CBR :: 0x7A21 /* GSMA/3GPP */ +WAVE_FORMAT_GSM_AMR_VBR_SID :: 0x7A22 /* GSMA/3GPP */ +WAVE_FORMAT_COMVERSE_INFOSYS_G723_1 :: 0xA100 /* Comverse Infosys */ +WAVE_FORMAT_COMVERSE_INFOSYS_AVQSBC :: 0xA101 /* Comverse Infosys */ +WAVE_FORMAT_COMVERSE_INFOSYS_SBC :: 0xA102 /* Comverse Infosys */ +WAVE_FORMAT_SYMBOL_G729_A :: 0xA103 /* Symbol Technologies */ +WAVE_FORMAT_VOICEAGE_AMR_WB :: 0xA104 /* VoiceAge Corp. */ +WAVE_FORMAT_INGENIENT_G726 :: 0xA105 /* Ingenient Technologies, Inc. */ +WAVE_FORMAT_MPEG4_AAC :: 0xA106 /* ISO/MPEG-4 */ +WAVE_FORMAT_ENCORE_G726 :: 0xA107 /* Encore Software */ +WAVE_FORMAT_ZOLL_ASAO :: 0xA108 /* ZOLL Medical Corp. */ +WAVE_FORMAT_SPEEX_VOICE :: 0xA109 /* xiph.org */ +WAVE_FORMAT_VIANIX_MASC :: 0xA10A /* Vianix LLC */ +WAVE_FORMAT_WM9_SPECTRUM_ANALYZER :: 0xA10B /* Microsoft */ +WAVE_FORMAT_WMF_SPECTRUM_ANAYZER :: 0xA10C /* Microsoft */ +WAVE_FORMAT_GSM_610 :: 0xA10D +WAVE_FORMAT_GSM_620 :: 0xA10E +WAVE_FORMAT_GSM_660 :: 0xA10F +WAVE_FORMAT_GSM_690 :: 0xA110 +WAVE_FORMAT_GSM_ADAPTIVE_MULTIRATE_WB :: 0xA111 +WAVE_FORMAT_POLYCOM_G722 :: 0xA112 /* Polycom */ +WAVE_FORMAT_POLYCOM_G728 :: 0xA113 /* Polycom */ +WAVE_FORMAT_POLYCOM_G729_A :: 0xA114 /* Polycom */ +WAVE_FORMAT_POLYCOM_SIREN :: 0xA115 /* Polycom */ +WAVE_FORMAT_GLOBAL_IP_ILBC :: 0xA116 /* Global IP */ +WAVE_FORMAT_RADIOTIME_TIME_SHIFT_RADIO :: 0xA117 /* RadioTime */ +WAVE_FORMAT_NICE_ACA :: 0xA118 /* Nice Systems */ +WAVE_FORMAT_NICE_ADPCM :: 0xA119 /* Nice Systems */ +WAVE_FORMAT_VOCORD_G721 :: 0xA11A /* Vocord Telecom */ +WAVE_FORMAT_VOCORD_G726 :: 0xA11B /* Vocord Telecom */ +WAVE_FORMAT_VOCORD_G722_1 :: 0xA11C /* Vocord Telecom */ +WAVE_FORMAT_VOCORD_G728 :: 0xA11D /* Vocord Telecom */ +WAVE_FORMAT_VOCORD_G729 :: 0xA11E /* Vocord Telecom */ +WAVE_FORMAT_VOCORD_G729_A :: 0xA11F /* Vocord Telecom */ +WAVE_FORMAT_VOCORD_G723_1 :: 0xA120 /* Vocord Telecom */ +WAVE_FORMAT_VOCORD_LBC :: 0xA121 /* Vocord Telecom */ +WAVE_FORMAT_NICE_G728 :: 0xA122 /* Nice Systems */ +WAVE_FORMAT_FRACE_TELECOM_G729 :: 0xA123 /* France Telecom */ +WAVE_FORMAT_CODIAN :: 0xA124 /* CODIAN */ +WAVE_FORMAT_DOLBY_AC4 :: 0xAC40 /* Dolby AC-4 */ +WAVE_FORMAT_FLAC :: 0xF1AC /* flac.sourceforge.net */ +WAVE_FORMAT_EXTENSIBLE :: 0xFFFE /* Microsoft */ + + +WAVEFORMATEX :: struct #packed { wFormatTag: WORD, nChannels: WORD, nSamplesPerSec: DWORD, @@ -325,6 +600,20 @@ WAVEFORMATEX :: struct { } LPCWAVEFORMATEX :: ^WAVEFORMATEX +// New wave format development should be based on the WAVEFORMATEXTENSIBLE structure. +// WAVEFORMATEXTENSIBLE allows you to avoid having to register a new format tag with Microsoft. +// Simply define a new GUID value for the WAVEFORMATEXTENSIBLE.SubFormat field and use WAVE_FORMAT_EXTENSIBLE in the WAVEFORMATEXTENSIBLE.Format.wFormatTag field. +WAVEFORMATEXTENSIBLE :: struct #packed { + using Format: WAVEFORMATEX, + Samples: struct #raw_union { + wValidBitsPerSample: WORD, /* bits of precision */ + wSamplesPerBlock: WORD, /* valid if wBitsPerSample==0 */ + wReserved: WORD, /* If neither applies, set to zero. */ + }, + dwChannelMask: SPEAKER_FLAGS, /* which channels are present in stream */ + SubFormat: GUID, +} + WAVEHDR :: struct { lpData: LPSTR, /* pointer to locked data buffer */ dwBufferLength: DWORD, /* length of data buffer */ @@ -360,26 +649,50 @@ WAVEOUTCAPSW :: struct { } LPWAVEOUTCAPSW :: ^WAVEOUTCAPSW +SPEAKER_FLAGS :: distinct bit_set[SPEAKER_FLAG; DWORD] +SPEAKER_FLAG :: enum DWORD { + FRONT_LEFT = 0, + FRONT_RIGHT = 1, + FRONT_CENTER = 2, + LOW_FREQUENCY = 3, + BACK_LEFT = 4, + BACK_RIGHT = 5, + FRONT_LEFT_OF_CENTER = 6, + FRONT_RIGHT_OF_CENTER = 7, + BACK_CENTER = 8, + SIDE_LEFT = 9, + SIDE_RIGHT = 10, + TOP_CENTER = 11, + TOP_FRONT_LEFT = 12, + TOP_FRONT_CENTER = 13, + TOP_FRONT_RIGHT = 14, + TOP_BACK_LEFT = 15, + TOP_BACK_CENTER = 16, + TOP_BACK_RIGHT = 17, + //RESERVED = 0x7FFC0000, // bit mask locations reserved for future use + ALL = 31, // used to specify that any possible permutation of speaker configurations +} + // flag values for PlaySound -SND_SYNC :: 0x0000 /* play synchronously (default) */ -SND_ASYNC :: 0x0001 /* play asynchronously */ -SND_NODEFAULT :: 0x0002 /* silence (!default) if sound not found */ -SND_MEMORY :: 0x0004 /* pszSound points to a memory file */ -SND_LOOP :: 0x0008 /* loop the sound until next sndPlaySound */ -SND_NOSTOP :: 0x0010 /* don't stop any currently playing sound */ +SND_SYNC :: 0x0000 /* play synchronously (default) */ +SND_ASYNC :: 0x0001 /* play asynchronously */ +SND_NODEFAULT :: 0x0002 /* silence (!default) if sound not found */ +SND_MEMORY :: 0x0004 /* pszSound points to a memory file */ +SND_LOOP :: 0x0008 /* loop the sound until next sndPlaySound */ +SND_NOSTOP :: 0x0010 /* don't stop any currently playing sound */ -SND_NOWAIT :: 0x00002000 /* don't wait if the driver is busy */ -SND_ALIAS :: 0x00010000 /* name is a registry alias */ -SND_ALIAS_ID :: 0x00110000 /* alias is a predefined ID */ -SND_FILENAME :: 0x00020000 /* name is file name */ -SND_RESOURCE :: 0x00040004 /* name is resource name or atom */ +SND_NOWAIT :: 0x00002000 /* don't wait if the driver is busy */ +SND_ALIAS :: 0x00010000 /* name is a registry alias */ +SND_ALIAS_ID :: 0x00110000 /* alias is a predefined ID */ +SND_FILENAME :: 0x00020000 /* name is file name */ +SND_RESOURCE :: 0x00040004 /* name is resource name or atom */ -SND_PURGE :: 0x0040 /* purge non-static events for task */ -SND_APPLICATION :: 0x0080 /* look for application specific association */ +SND_PURGE :: 0x0040 /* purge non-static events for task */ +SND_APPLICATION :: 0x0080 /* look for application specific association */ -SND_SENTRY :: 0x00080000 /* Generate a SoundSentry event with this sound */ -SND_RING :: 0x00100000 /* Treat this as a "ring" from a communications app - don't duck me */ -SND_SYSTEM :: 0x00200000 /* Treat this as a system sound */ +SND_SENTRY :: 0x00080000 /* Generate a SoundSentry event with this sound */ +SND_RING :: 0x00100000 /* Treat this as a "ring" from a communications app - don't duck me */ +SND_SYSTEM :: 0x00200000 /* Treat this as a system sound */ CALLBACK_TYPEMASK :: 0x00070000 /* callback type mask */ diff --git a/core/sys/windows/ws2_32.odin b/core/sys/windows/ws2_32.odin index 5b2952495..0d1f477c3 100644 --- a/core/sys/windows/ws2_32.odin +++ b/core/sys/windows/ws2_32.odin @@ -82,6 +82,17 @@ Example Load: } */ +LPFN_GETACCEPTEXSOCKADDRS :: #type proc "system" ( + lpOutputBuffer: PVOID, + dwReceiveDataLength: DWORD, + dwLocalAddressLength: DWORD, + dwRemoteAddressLength: DWORD, + LocalSockaddr: ^^sockaddr, + LocalSockaddrLength: LPINT, + RemoteSockaddr: ^^sockaddr, + RemoteSockaddrLength: LPINT, +) + foreign import ws2_32 "system:Ws2_32.lib" @(default_calling_convention="system") foreign ws2_32 { @@ -91,6 +102,7 @@ foreign ws2_32 { WSACleanup :: proc() -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsagetlasterror) WSAGetLastError :: proc() -> c_int --- + WSASetLastError :: proc(err: c_int) --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll) WSAPoll :: proc(fdArray: ^WSA_POLLFD, fds: c_ulong, timeout: c_int) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaduplicatesocketw) @@ -130,6 +142,10 @@ foreign ws2_32 { ) -> SOCKET --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaioctl) WSAIoctl :: proc(s: SOCKET, dwIoControlCode: DWORD, lpvInBuffer: rawptr, cbInBuffer: DWORD, lpvOutBuffer: rawptr, cbOutBuffer: DWORD, lpcbBytesReturned: ^DWORD, lpOverlapped: ^OVERLAPPED, lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> c_int --- + // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsacreateevent) + WSACreateEvent :: proc() -> WSAEVENT --- + // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsacloseevent) + WSACloseEvent :: proc(hEvent: WSAEVENT) -> bool --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsaeventselect) WSAEventSelect :: proc(s: SOCKET, hEventObject: WSAEVENT, lNetworkEvents: i32) -> c_int --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsawaitformultipleevents) @@ -238,9 +254,9 @@ foreign ws2_32 { // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-ntohs) ntohs :: proc(netshort: c_ushort) -> c_ushort --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htonl) - @(deprecated="Use endian specific integers instead, https://odin-lang.org/docs/overview/#basic-types") + // Prefer using endian-specific integers instead, https://odin-lang.org/docs/overview/#basic-types htonl :: proc(hostlong: c_ulong) -> c_ulong --- // [MS-Docs](https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-htons) - @(deprecated="Use endian specific integers instead, https://odin-lang.org/docs/overview/#basic-types") + // Prefer using endian-specific integers instead, https://odin-lang.org/docs/overview/#basic-types htons :: proc(hostshort: c_ushort) -> c_ushort --- } diff --git a/core/encoding/ansi/ansi.odin b/core/terminal/ansi/ansi.odin similarity index 100% rename from core/encoding/ansi/ansi.odin rename to core/terminal/ansi/ansi.odin diff --git a/core/encoding/ansi/doc.odin b/core/terminal/ansi/doc.odin similarity index 100% rename from core/encoding/ansi/doc.odin rename to core/terminal/ansi/doc.odin diff --git a/core/terminal/doc.odin b/core/terminal/doc.odin new file mode 100644 index 000000000..490e9d398 --- /dev/null +++ b/core/terminal/doc.odin @@ -0,0 +1,4 @@ +/* +This package is for interacting with the command line interface of the system. +*/ +package terminal diff --git a/core/terminal/internal.odin b/core/terminal/internal.odin new file mode 100644 index 000000000..9404ff833 --- /dev/null +++ b/core/terminal/internal.odin @@ -0,0 +1,89 @@ +#+private +package terminal + +import "base:runtime" +import "core:os" +import "core:strings" + +// Reference documentation: +// +// - [[ https://no-color.org/ ]] +// - [[ https://github.com/termstandard/colors ]] +// - [[ https://invisible-island.net/ncurses/terminfo.src.html ]] + +get_no_color :: proc() -> bool { + buf: [128]u8 + if no_color, err := os.lookup_env(buf[:], "NO_COLOR"); err == nil { + return no_color != "" + } + return false +} + +get_environment_color :: proc() -> Color_Depth { + buf: [128]u8 + // `COLORTERM` is non-standard but widespread and unambiguous. + if colorterm, err := os.lookup_env(buf[:], "COLORTERM"); err == nil { + // These are the only values that are typically advertised that have + // anything to do with color depth. + if colorterm == "truecolor" || colorterm == "24bit" { + return .True_Color + } + } + + if term, err := os.lookup_env(buf[:], "TERM"); err == nil { + if strings.contains(term, "-truecolor") { + return .True_Color + } + if strings.contains(term, "-256color") { + return .Eight_Bit + } + if strings.contains(term, "-16color") { + return .Four_Bit + } + + // The `terminfo` database, which is stored in binary on *nix + // platforms, has an undocumented format that is not guaranteed to be + // portable, so beyond this point, we can only make safe assumptions. + // + // This section should only be necessary for terminals that do not + // define any of the previous environment values. + // + // Only a small sampling of some common values are checked here. + switch term { + case "ansi": fallthrough + case "konsole": fallthrough + case "putty": fallthrough + case "rxvt": fallthrough + case "rxvt-color": fallthrough + case "screen": fallthrough + case "st": fallthrough + case "tmux": fallthrough + case "vte": fallthrough + case "xterm": fallthrough + case "xterm-color": + return .Three_Bit + } + } + + return .None +} + +@(init) +init_terminal :: proc "contextless" () { + _init_terminal() + + context = runtime.default_context() + + // We respect `NO_COLOR` specifically as a color-disabler but not as a + // blanket ban on any terminal manipulation codes, hence why this comes + // after `_init_terminal` which will allow Windows to enable Virtual + // Terminal Processing for non-color control sequences. + if !get_no_color() { + color_enabled = color_depth > .None + } +} + +@(fini) +fini_terminal :: proc "contextless" () { + _fini_terminal() +} diff --git a/core/terminal/terminal.odin b/core/terminal/terminal.odin new file mode 100644 index 000000000..1e5566295 --- /dev/null +++ b/core/terminal/terminal.odin @@ -0,0 +1,36 @@ +package terminal + +import "core:os" + +/* +This describes the range of colors that a terminal is capable of supporting. +*/ +Color_Depth :: enum { + None, // No color support + Three_Bit, // 8 colors + Four_Bit, // 16 colors + Eight_Bit, // 256 colors + True_Color, // 24-bit true color +} + +/* +Returns true if the file `handle` is attached to a terminal. + +This is normally true for `os.stdout` and `os.stderr` unless they are +redirected to a file. +*/ +@(require_results) +is_terminal :: proc(handle: os.Handle) -> bool { + return _is_terminal(handle) +} + +/* +This is true if the terminal is accepting any form of colored text output. +*/ +color_enabled: bool + +/* +This value reports the color depth support as reported by the terminal at the +start of the program. +*/ +color_depth: Color_Depth diff --git a/core/terminal/terminal_js.odin b/core/terminal/terminal_js.odin new file mode 100644 index 000000000..4dcd4465e --- /dev/null +++ b/core/terminal/terminal_js.odin @@ -0,0 +1,15 @@ +#+private +#+build js +package terminal + +import "core:os" + +_is_terminal :: proc "contextless" (handle: os.Handle) -> bool { + return true +} + +_init_terminal :: proc "contextless" () { + color_depth = .None +} + +_fini_terminal :: proc "contextless" () { } \ No newline at end of file diff --git a/core/terminal/terminal_posix.odin b/core/terminal/terminal_posix.odin new file mode 100644 index 000000000..8d96dd256 --- /dev/null +++ b/core/terminal/terminal_posix.odin @@ -0,0 +1,18 @@ +#+private +#+build linux, darwin, netbsd, openbsd, freebsd, haiku +package terminal + +import "base:runtime" +import "core:os" +import "core:sys/posix" + +_is_terminal :: proc "contextless" (handle: os.Handle) -> bool { + return bool(posix.isatty(posix.FD(handle))) +} + +_init_terminal :: proc "contextless" () { + context = runtime.default_context() + color_depth = get_environment_color() +} + +_fini_terminal :: proc "contextless" () { } diff --git a/core/terminal/terminal_windows.odin b/core/terminal/terminal_windows.odin new file mode 100644 index 000000000..6d5f98a1f --- /dev/null +++ b/core/terminal/terminal_windows.odin @@ -0,0 +1,63 @@ +#+private +package terminal + +import "base:runtime" +import "core:os" +import "core:sys/windows" + +_is_terminal :: proc "contextless" (handle: os.Handle) -> bool { + is_tty := windows.GetFileType(windows.HANDLE(handle)) == windows.FILE_TYPE_CHAR + return is_tty +} + +old_modes: [2]struct{ + handle: windows.DWORD, + mode: windows.DWORD, +} = { + {windows.STD_OUTPUT_HANDLE, 0}, + {windows.STD_ERROR_HANDLE, 0}, +} + +@(init) +_init_terminal :: proc "contextless" () { + vtp_enabled: bool + + for &v in old_modes { + handle := windows.GetStdHandle(v.handle) + if handle == windows.INVALID_HANDLE || handle == nil { + return + } + if windows.GetConsoleMode(handle, &v.mode) { + windows.SetConsoleMode(handle, v.mode | windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) + + new_mode: windows.DWORD + windows.GetConsoleMode(handle, &new_mode) + + if new_mode & (windows.ENABLE_PROCESSED_OUTPUT | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0 { + vtp_enabled = true + } + } + } + + if vtp_enabled { + // This color depth is available on Windows 10 since build 10586. + color_depth = .Four_Bit + } else { + context = runtime.default_context() + + // The user may be on a non-default terminal emulator. + color_depth = get_environment_color() + } +} + +@(fini) +_fini_terminal :: proc "contextless" () { + for v in old_modes { + handle := windows.GetStdHandle(v.handle) + if handle == windows.INVALID_HANDLE || handle == nil { + return + } + + windows.SetConsoleMode(handle, v.mode) + } +} diff --git a/core/testing/reporting.odin b/core/testing/reporting.odin index 6752cd79b..7c7eb7b2d 100644 --- a/core/testing/reporting.odin +++ b/core/testing/reporting.odin @@ -10,12 +10,12 @@ package testing */ import "base:runtime" -import "core:encoding/ansi" import "core:fmt" import "core:io" import "core:mem" import "core:path/filepath" import "core:strings" +import "core:terminal/ansi" // Definitions of colors for use in the test runner. SGR_RESET :: ansi.CSI + ansi.RESET + ansi.SGR diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 83a5ac4e7..b53bd8722 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -13,7 +13,6 @@ package testing import "base:intrinsics" import "base:runtime" import "core:bytes" -import "core:encoding/ansi" @require import "core:encoding/base64" @require import "core:encoding/json" import "core:fmt" @@ -25,6 +24,8 @@ import "core:os" import "core:slice" @require import "core:strings" import "core:sync/chan" +import "core:terminal" +import "core:terminal/ansi" import "core:thread" import "core:time" @@ -44,6 +45,7 @@ PER_THREAD_MEMORY : int : #config(ODIN_TEST_THREAD_MEMORY, mem.ROLLBACK_S // The format is: `package.test_name,test_name_only,...` TEST_NAMES : string : #config(ODIN_TEST_NAMES, "") // Show the fancy animated progress report. +// This requires terminal color support, as well as STDOUT to not be redirected to a file. FANCY_OUTPUT : bool : #config(ODIN_TEST_FANCY, true) // Copy failed tests to the clipboard when done. USE_CLIPBOARD : bool : #config(ODIN_TEST_CLIPBOARD, false) @@ -55,6 +57,8 @@ SHARED_RANDOM_SEED : u64 : #config(ODIN_TEST_RANDOM_SEED, 0) // Set the lowest log level for this test run. LOG_LEVEL_DEFAULT : string : "debug" when ODIN_DEBUG else "info" LOG_LEVEL : string : #config(ODIN_TEST_LOG_LEVEL, LOG_LEVEL_DEFAULT) +// Report a message at the info level when a test has changed its state. +LOG_STATE_CHANGES : bool : #config(ODIN_TEST_LOG_STATE_CHANGES, false) // Show only the most necessary logging information. USING_SHORT_LOGS : bool : #config(ODIN_TEST_SHORT_LOGS, false) // Output a report of the tests to the given path. @@ -70,6 +74,9 @@ get_log_level :: #force_inline proc() -> runtime.Logger_Level { } } +@(private) global_log_colors_disabled: bool +@(private) global_ansi_disabled: bool + JSON :: struct { total: int, success: int, @@ -129,11 +136,16 @@ run_test_task :: proc(task: thread.Task) { context.assertion_failure_proc = test_assertion_failure_proc + logger_options := Default_Test_Logger_Opts + if global_log_colors_disabled { + logger_options -= {.Terminal_Color} + } + context.logger = { procedure = test_logger_proc, data = &data.t, lowest_level = get_log_level(), - options = Default_Test_Logger_Opts, + options = logger_options, } random_generator_state: runtime.Default_Random_State @@ -204,13 +216,16 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } } - when ODIN_OS == .Windows { - console_ansi_init() - } - stdout := io.to_writer(os.stream_from_handle(os.stdout)) stderr := io.to_writer(os.stream_from_handle(os.stderr)) + // The animations are only ever shown through STDOUT; + // STDERR is used exclusively for logging regardless of error level. + global_log_colors_disabled = !terminal.color_enabled || !terminal.is_terminal(os.stderr) + global_ansi_disabled = !terminal.is_terminal(os.stdout) + + should_show_animations := FANCY_OUTPUT && terminal.color_enabled && !global_ansi_disabled + // -- Prepare test data. alloc_error: mem.Allocator_Error @@ -268,12 +283,12 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { total_done_count := 0 total_test_count := len(internal_tests) - when !FANCY_OUTPUT { - // This is strictly for updating the window title when the progress - // report is disabled. We're otherwise able to depend on the call to - // `needs_to_redraw`. - last_done_count := -1 - } + + // This is strictly for updating the window title when the progress + // report is disabled. We're otherwise able to depend on the call to + // `needs_to_redraw`. + last_done_count := -1 + if total_test_count == 0 { // Exit early. @@ -342,31 +357,31 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { fmt.assertf(alloc_error == nil, "Error allocating memory for test report: %v", alloc_error) defer destroy_report(&report) - when FANCY_OUTPUT { - // We cannot make use of the ANSI save/restore cursor codes, because they - // work by absolute screen coordinates. This will cause unnecessary - // scrollback if we print at the bottom of someone's terminal. - ansi_redraw_string := fmt.aprintf( - // ANSI for "go up N lines then erase the screen from the cursor forward." - ansi.CSI + "%i" + ansi.CPL + ansi.CSI + ansi.ED + - // We'll combine this with the window title format string, since it - // can be printed at the same time. - "%s", - // 1 extra line for the status bar. - 1 + len(report.packages), OSC_WINDOW_TITLE) - assert(len(ansi_redraw_string) > 0, "Error allocating ANSI redraw string.") - defer delete(ansi_redraw_string) - thread_count_status_string: string = --- - { - PADDING :: PROGRESS_COLUMN_SPACING + PROGRESS_WIDTH + // We cannot make use of the ANSI save/restore cursor codes, because they + // work by absolute screen coordinates. This will cause unnecessary + // scrollback if we print at the bottom of someone's terminal. + ansi_redraw_string := fmt.aprintf( + // ANSI for "go up N lines then erase the screen from the cursor forward." + ansi.CSI + "%i" + ansi.CPL + ansi.CSI + ansi.ED + + // We'll combine this with the window title format string, since it + // can be printed at the same time. + "%s", + // 1 extra line for the status bar. + 1 + len(report.packages), OSC_WINDOW_TITLE) + assert(len(ansi_redraw_string) > 0, "Error allocating ANSI redraw string.") + defer delete(ansi_redraw_string) - unpadded := fmt.tprintf("%i thread%s", thread_count, "" if thread_count == 1 else "s") - thread_count_status_string = fmt.aprintf("%- *[1]s", unpadded, report.pkg_column_len + PADDING) - assert(len(thread_count_status_string) > 0, "Error allocating thread count status string.") - } - defer delete(thread_count_status_string) + thread_count_status_string: string = --- + { + PADDING :: PROGRESS_COLUMN_SPACING + PROGRESS_WIDTH + + unpadded := fmt.tprintf("%i thread%s", thread_count, "" if thread_count == 1 else "s") + thread_count_status_string = fmt.aprintf("%- *[1]s", unpadded, report.pkg_column_len + PADDING) + assert(len(thread_count_status_string) > 0, "Error allocating thread count status string.") } + defer delete(thread_count_status_string) + task_data_slots: []Task_Data = --- task_data_slots, alloc_error = make([]Task_Data, thread_count) @@ -442,11 +457,16 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { // digging through the source to divine everywhere it is used for that. shared_log_allocator := context.allocator + logger_options := Default_Test_Logger_Opts - {.Short_File_Path, .Line, .Procedure} + if global_log_colors_disabled { + logger_options -= {.Terminal_Color} + } + context.logger = { procedure = runner_logger_proc, data = &log_messages, lowest_level = get_log_level(), - options = Default_Test_Logger_Opts - {.Short_File_Path, .Line, .Procedure}, + options = logger_options, } run_index: int @@ -481,11 +501,13 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { setup_signal_handler() - fmt.wprint(stdout, ansi.CSI + ansi.DECTCEM_HIDE) + if !global_ansi_disabled { + fmt.wprint(stdout, ansi.CSI + ansi.DECTCEM_HIDE) + } - when FANCY_OUTPUT { - signals_were_raised := false + signals_were_raised := false + if should_show_animations { redraw_report(stdout, report) draw_status_bar(stdout, thread_count_status_string, total_done_count, total_test_count) } @@ -611,8 +633,8 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { total_done_count += 1 } - when ODIN_DEBUG { - log.debugf("Test #%i %s.%s changed state to %v.", task_channel.test_index, it.pkg, it.name, event.new_state) + when LOG_STATE_CHANGES { + log.infof("Test #%i %s.%s changed state to %v.", task_channel.test_index, it.pkg, it.name, event.new_state) } pkg.last_change_state = event.new_state @@ -703,25 +725,26 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { break main_loop } - when FANCY_OUTPUT { - // Because the bounds checking procs send directly to STDERR with - // no way to redirect or handle them, we need to at least try to - // let the user see those messages when using the animated progress - // report. This flag may be set by the block of code below if a - // signal is raised. - // - // It'll be purely by luck if the output is interleaved properly, - // given the nature of non-thread-safe printing. - // - // At worst, if Odin did not print any error for this signal, we'll - // just re-display the progress report. The fatal log error message - // should be enough to clue the user in that something dire has - // occurred. - bypass_progress_overwrite := false - } + + // Because the bounds checking procs send directly to STDERR with + // no way to redirect or handle them, we need to at least try to + // let the user see those messages when using the animated progress + // report. This flag may be set by the block of code below if a + // signal is raised. + // + // It'll be purely by luck if the output is interleaved properly, + // given the nature of non-thread-safe printing. + // + // At worst, if Odin did not print any error for this signal, we'll + // just re-display the progress report. The fatal log error message + // should be enough to clue the user in that something dire has + // occurred. + bypass_progress_overwrite := false + if test_index, reason, ok := should_stop_test(); ok { - #no_bounds_check report.all_test_states[test_index] = .Failed + passed := reason == .Successful_Stop + #no_bounds_check report.all_test_states[test_index] = .Successful if passed else .Failed #no_bounds_check it := internal_tests[test_index] #no_bounds_check pkg := report.packages_by_name[it.pkg] pkg.frame_ready = false @@ -742,7 +765,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { fmt.assertf(task_data != nil, "A signal (%v) was raised to stop test #%i %s.%s, but its task data is missing.", reason, test_index, it.pkg, it.name) - if !task_data.t._fail_now_called { + if !passed && !task_data.t._fail_now_called { if test_index not_in failed_test_reason_map { // We only write a new error message here if there wasn't one // already, because the message we can provide based only on @@ -752,7 +775,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { log.fatalf("Caught signal to stop test #%i %s.%s for: %v.", test_index, it.pkg, it.name, reason) } - when FANCY_OUTPUT { + if should_show_animations { bypass_progress_overwrite = true signals_were_raised = true } @@ -760,13 +783,17 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { end_t(&task_data.t) - total_failure_count += 1 + if passed { + total_success_count += 1 + } else { + total_failure_count += 1 + } total_done_count += 1 } // -- Redraw. - when FANCY_OUTPUT { + if should_show_animations { if len(log_messages) == 0 && !needs_to_redraw(report) { continue main_loop } @@ -776,7 +803,9 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } } else { if total_done_count != last_done_count { - fmt.wprintf(stdout, OSC_WINDOW_TITLE, total_done_count, total_test_count) + if !global_ansi_disabled { + fmt.wprintf(stdout, OSC_WINDOW_TITLE, total_done_count, total_test_count) + } last_done_count = total_done_count } @@ -801,7 +830,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { clear(&log_messages) bytes.buffer_reset(&batch_buffer) - when FANCY_OUTPUT { + if should_show_animations { redraw_report(batch_writer, report) draw_status_bar(batch_writer, thread_count_status_string, total_done_count, total_test_count) fmt.wprint(stdout, bytes.buffer_to_string(&batch_buffer)) @@ -822,7 +851,7 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { finished_in := time.since(start_time) - when !FANCY_OUTPUT { + if !should_show_animations || !terminal.is_terminal(os.stderr) { // One line to space out the results, since we don't have the status // bar in plain mode. fmt.wprintln(batch_writer) @@ -836,24 +865,28 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { if total_done_count != total_test_count { not_run_count := total_test_count - total_done_count + message := " %i %s left undone." if global_log_colors_disabled else " " + SGR_READY + "%i" + SGR_RESET + " %s left undone." fmt.wprintf(batch_writer, - " " + SGR_READY + "%i" + SGR_RESET + " %s left undone.", + message, not_run_count, "test was" if not_run_count == 1 else "tests were") } if total_success_count == total_test_count { + message := " %s successful." if global_log_colors_disabled else " %s " + SGR_SUCCESS + "successful." + SGR_RESET fmt.wprintfln(batch_writer, - " %s " + SGR_SUCCESS + "successful." + SGR_RESET, + message, "The test was" if total_test_count == 1 else "All tests were") } else if total_failure_count > 0 { if total_failure_count == total_test_count { + message := " %s failed." if global_log_colors_disabled else " %s " + SGR_FAILED + "failed." + SGR_RESET fmt.wprintfln(batch_writer, - " %s " + SGR_FAILED + "failed." + SGR_RESET, + message, "The test" if total_test_count == 1 else "All tests") } else { + message := " %i test%s failed." if global_log_colors_disabled else " " + SGR_FAILED + "%i" + SGR_RESET + " test%s failed." fmt.wprintfln(batch_writer, - " " + SGR_FAILED + "%i" + SGR_RESET + " test%s failed.", + message, total_failure_count, "" if total_failure_count == 1 else "s") } @@ -907,9 +940,11 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { } } - fmt.wprint(stdout, ansi.CSI + ansi.DECTCEM_SHOW) + if !global_ansi_disabled { + fmt.wprint(stdout, ansi.CSI + ansi.DECTCEM_SHOW) + } - when FANCY_OUTPUT { + if should_show_animations { if signals_were_raised { fmt.wprintln(batch_writer, ` Signals were raised during this test run. Log messages are likely to have collided with each other. diff --git a/core/testing/runner_windows.odin b/core/testing/runner_windows.odin deleted file mode 100644 index 401804c71..000000000 --- a/core/testing/runner_windows.odin +++ /dev/null @@ -1,22 +0,0 @@ -#+private -package testing - -import win32 "core:sys/windows" - -console_ansi_init :: proc() { - stdout := win32.GetStdHandle(win32.STD_OUTPUT_HANDLE) - if stdout != win32.INVALID_HANDLE && stdout != nil { - old_console_mode: u32 - if win32.GetConsoleMode(stdout, &old_console_mode) { - win32.SetConsoleMode(stdout, old_console_mode | win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING) - } - } - - stderr := win32.GetStdHandle(win32.STD_ERROR_HANDLE) - if stderr != win32.INVALID_HANDLE && stderr != nil { - old_console_mode: u32 - if win32.GetConsoleMode(stderr, &old_console_mode) { - win32.SetConsoleMode(stderr, old_console_mode | win32.ENABLE_VIRTUAL_TERMINAL_PROCESSING) - } - } -} diff --git a/core/testing/signal_handler.odin b/core/testing/signal_handler.odin index 2f1f7c89a..73ed362f0 100644 --- a/core/testing/signal_handler.odin +++ b/core/testing/signal_handler.odin @@ -12,8 +12,26 @@ package testing import "base:runtime" import "core:log" +@(private, thread_local) +local_test_expected_failures: struct { + signal: i32, + + message_count: int, + messages: [MAX_EXPECTED_ASSERTIONS_PER_TEST]string, + + location_count: int, + locations: [MAX_EXPECTED_ASSERTIONS_PER_TEST]runtime.Source_Code_Location, +} + +@(private, thread_local) +local_test_assertion_raised: struct { + message: string, + location: runtime.Source_Code_Location, +} + Stop_Reason :: enum { Unknown, + Successful_Stop, Illegal_Instruction, Arithmetic_Error, Segmentation_Fault, @@ -21,7 +39,12 @@ Stop_Reason :: enum { } test_assertion_failure_proc :: proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! { - log.fatalf("%s: %s", prefix, message, location = loc) + if local_test_expected_failures.message_count + local_test_expected_failures.location_count > 0 { + local_test_assertion_raised = { message, loc } + log.debugf("%s\n\tmessage: %q\n\tlocation: %w", prefix, message, loc) + } else { + log.fatalf("%s: %s", prefix, message, location = loc) + } runtime.trap() } diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin index 281fbde40..961f5c7ce 100644 --- a/core/testing/signal_handler_libc.odin +++ b/core/testing/signal_handler_libc.odin @@ -12,21 +12,30 @@ package testing import "base:intrinsics" import "core:c/libc" -import "core:encoding/ansi" -import "core:sync" import "core:os" +import "core:sync" +import "core:terminal/ansi" @(private="file") stop_runner_flag: libc.sig_atomic_t @(private="file") stop_test_gate: sync.Mutex @(private="file") stop_test_index: libc.sig_atomic_t -@(private="file") stop_test_reason: libc.sig_atomic_t +@(private="file") stop_test_signal: libc.sig_atomic_t +@(private="file") stop_test_passed: libc.sig_atomic_t @(private="file") stop_test_alert: libc.sig_atomic_t -@(private="file", thread_local) -local_test_index: libc.sig_atomic_t -@(private="file", thread_local) -local_test_index_set: bool +when ODIN_ARCH == .i386 && ODIN_OS == .Windows { + // Thread-local storage is problematic on Windows i386 + @(private="file") + local_test_index: libc.sig_atomic_t + @(private="file") + local_test_index_set: bool +} else { + @(private="file", thread_local) + local_test_index: libc.sig_atomic_t + @(private="file", thread_local) + local_test_index_set: bool +} // Windows does not appear to have a SIGTRAP, so this is defined here, instead // of in the libc package, just so there's no confusion about it being @@ -63,9 +72,11 @@ stop_test_callback :: proc "c" (sig: libc.int) { // NOTE(Feoramund): Using these write calls in a signal handler is // undefined behavior in C99 but possibly tolerated in POSIX 2008. // Either way, we may as well try to salvage what we can. - show_cursor := ansi.CSI + ansi.DECTCEM_SHOW - libc.fwrite(raw_data(show_cursor), size_of(byte), len(show_cursor), libc.stdout) - libc.fflush(libc.stdout) + if !global_ansi_disabled { + show_cursor := ansi.CSI + ansi.DECTCEM_SHOW + libc.fwrite(raw_data(show_cursor), size_of(byte), len(show_cursor), libc.stdout) + libc.fflush(libc.stdout) + } // This is an attempt at being compliant by avoiding printf. sigbuf: [8]byte @@ -97,7 +108,30 @@ This is a dire bug and should be reported to the Odin developers. if sync.mutex_guard(&stop_test_gate) { intrinsics.atomic_store(&stop_test_index, local_test_index) - intrinsics.atomic_store(&stop_test_reason, cast(libc.sig_atomic_t)sig) + intrinsics.atomic_store(&stop_test_signal, cast(libc.sig_atomic_t)sig) + passed: bool + check_passing: { + if location := local_test_assertion_raised.location; location != {} { + for i in 0.. (test_index: int, reason: Stop_Reason, ok: bool) intrinsics.atomic_store(&stop_test_alert, 0) test_index = cast(int)intrinsics.atomic_load(&stop_test_index) - switch intrinsics.atomic_load(&stop_test_reason) { - case libc.SIGFPE: reason = .Arithmetic_Error - case libc.SIGILL: reason = .Illegal_Instruction - case libc.SIGSEGV: reason = .Segmentation_Fault - case SIGTRAP: reason = .Unhandled_Trap + if cast(bool)intrinsics.atomic_load(&stop_test_passed) { + reason = .Successful_Stop + } else { + switch intrinsics.atomic_load(&stop_test_signal) { + case libc.SIGFPE: reason = .Arithmetic_Error + case libc.SIGILL: reason = .Illegal_Instruction + case libc.SIGSEGV: reason = .Segmentation_Fault + case SIGTRAP: reason = .Unhandled_Trap + } } ok = true } diff --git a/core/testing/testing.odin b/core/testing/testing.odin index 09bf6dc0e..1357a4683 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -21,6 +21,8 @@ import "core:mem" _ :: reflect // alias reflect to nothing to force visibility for -vet _ :: mem // in case TRACKING_MEMORY is not enabled +MAX_EXPECTED_ASSERTIONS_PER_TEST :: 5 + // IMPORTANT NOTE: Compiler requires this layout Test_Signature :: proc(^T) @@ -155,3 +157,74 @@ set_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location location = loc, }) } + +/* +Let the test runner know that it should expect an assertion failure from a +specific location in the source code for this test. + +In the event that an assertion fails, a debug message will be logged with its +exact message and location in a copyable format to make it convenient to write +tests which use this API. + +This procedure may be called up to 5 times with different locations. + +This is a limitation for the sake of simplicity in the implementation, and you +should consider breaking up your tests into smaller procedures if you need to +check for asserts in more than 2 places. +*/ +expect_assert_from :: proc(t: ^T, expected_place: runtime.Source_Code_Location, caller_loc := #caller_location) { + count := local_test_expected_failures.location_count + if count == MAX_EXPECTED_ASSERTIONS_PER_TEST { + panic("This test cannot handle that many expected assertions based on matching the location.", caller_loc) + } + local_test_expected_failures.locations[count] = expected_place + local_test_expected_failures.location_count += 1 +} + +/* +Let the test runner know that it should expect an assertion failure with a +specific message for this test. + +In the event that an assertion fails, a debug message will be logged with its +exact message and location in a copyable format to make it convenient to write +tests which use this API. + +This procedure may be called up to 5 times with different messages. + +This is a limitation for the sake of simplicity in the implementation, and you +should consider breaking up your tests into smaller procedures if you need to +check for more than a couple different assertion messages. +*/ +expect_assert_message :: proc(t: ^T, expected_message: string, caller_loc := #caller_location) { + count := local_test_expected_failures.message_count + if count == MAX_EXPECTED_ASSERTIONS_PER_TEST { + panic("This test cannot handle that many expected assertions based on matching the message.", caller_loc) + } + local_test_expected_failures.messages[count] = expected_message + local_test_expected_failures.message_count += 1 +} + +expect_assert :: proc { + expect_assert_from, + expect_assert_message, +} + +/* +Let the test runner know that it should expect a signal to be raised within +this test. + +This API is for advanced users, as arbitrary signals will not be caught; only +the ones already handled by the test runner, such as + +- SIGINT, (interrupt) +- SIGTERM, (polite termination) +- SIGILL, (illegal instruction) +- SIGFPE, (arithmetic error) +- SIGSEGV, and (segmentation fault) +- SIGTRAP (only on POSIX systems). (trap / debug trap) + +Note that only one signal can be expected per test. +*/ +expect_signal :: proc(t: ^T, #any_int sig: i32) { + local_test_expected_failures.signal = sig +} diff --git a/core/text/regex/common/common.odin b/core/text/regex/common/common.odin index 4a303e0a3..e60bef58f 100644 --- a/core/text/regex/common/common.odin +++ b/core/text/regex/common/common.odin @@ -15,8 +15,6 @@ MAX_PROGRAM_SIZE :: int(max(i16)) MAX_CLASSES :: int(max(u8)) Flag :: enum u8 { - // Global: try to match the pattern anywhere in the string. - Global, // Multiline: treat `^` and `$` as if they also match newlines. Multiline, // Case Insensitive: treat `a-z` as if it was also `A-Z`. @@ -36,7 +34,6 @@ Flags :: bit_set[Flag; u8] @(rodata) Flag_To_Letter := #sparse[Flag]u8 { - .Global = 'g', .Multiline = 'm', .Case_Insensitive = 'i', .Ignore_Whitespace = 'x', diff --git a/core/text/regex/compiler/compiler.odin b/core/text/regex/compiler/compiler.odin index b3ded0104..2f0f183e9 100644 --- a/core/text/regex/compiler/compiler.odin +++ b/core/text/regex/compiler/compiler.odin @@ -195,8 +195,12 @@ generate_code :: proc(c: ^Compiler, node: Node) -> (code: Program) { case ^Node_Anchor: if .Multiline in c.flags { - append(&code, Opcode.Multiline_Open) - append(&code, Opcode.Multiline_Close) + if specific.start { + append(&code, Opcode.Assert_Start_Multiline) + } else { + append(&code, Opcode.Multiline_Open) + append(&code, Opcode.Multiline_Close) + } } else { if specific.start { append(&code, Opcode.Assert_Start) @@ -401,7 +405,7 @@ compile :: proc(tree: Node, flags: common.Flags) -> (code: Program, class_data: pc_open := 0 - add_global: if .Global in flags { + optimize_opening: { // Check if the opening to the pattern is predictable. // If so, use one of the optimized Wait opcodes. iter := virtual_machine.Opcode_Iterator{ code[:], 0 } @@ -412,7 +416,7 @@ compile :: proc(tree: Node, flags: common.Flags) -> (code: Program, class_data: pc_open += size_of(Opcode) inject_at(&code, pc_open, Opcode(code[pc + size_of(Opcode) + pc_open])) pc_open += size_of(u8) - break add_global + break optimize_opening case .Rune: operand := intrinsics.unaligned_load(cast(^rune)&code[pc+1]) @@ -420,24 +424,28 @@ compile :: proc(tree: Node, flags: common.Flags) -> (code: Program, class_data: pc_open += size_of(Opcode) inject_raw(&code, pc_open, operand) pc_open += size_of(rune) - break add_global + break optimize_opening case .Rune_Class: inject_at(&code, pc_open, Opcode.Wait_For_Rune_Class) pc_open += size_of(Opcode) inject_at(&code, pc_open, Opcode(code[pc + size_of(Opcode) + pc_open])) pc_open += size_of(u8) - break add_global + break optimize_opening case .Rune_Class_Negated: inject_at(&code, pc_open, Opcode.Wait_For_Rune_Class_Negated) pc_open += size_of(Opcode) inject_at(&code, pc_open, Opcode(code[pc + size_of(Opcode) + pc_open])) pc_open += size_of(u8) - break add_global + break optimize_opening case .Save: continue + + case .Assert_Start, .Assert_Start_Multiline: + break optimize_opening + case: break seek_loop } diff --git a/core/text/regex/regex.odin b/core/text/regex/regex.odin index 8f8efe252..bff82c407 100644 --- a/core/text/regex/regex.odin +++ b/core/text/regex/regex.odin @@ -8,6 +8,7 @@ package regex Feoramund: Initial implementation. */ +import "base:runtime" import "core:text/regex/common" import "core:text/regex/compiler" import "core:text/regex/optimizer" @@ -51,7 +52,7 @@ This struct corresponds to a set of string captures from a RegEx match. such that `str[pos[0][0]:pos[0][1]] == groups[0]`. */ Capture :: struct { - pos: [][2]int, + pos: [][2]int, groups: []string, } @@ -59,11 +60,23 @@ Capture :: struct { A compiled Regular Expression value, to be used with the `match_*` procedures. */ Regular_Expression :: struct { - flags: Flags `fmt:"-"`, + flags: Flags `fmt:"-"`, class_data: []virtual_machine.Rune_Class_Data `fmt:"-"`, - program: []virtual_machine.Opcode `fmt:"-"`, + program: []virtual_machine.Opcode `fmt:"-"`, } +/* +An iterator to repeatedly match a pattern against a string, to be used with `*_iterator` procedures. +*/ +Match_Iterator :: struct { + regex: Regular_Expression, + capture: Capture, + vm: virtual_machine.Machine, + idx: int, + temp: runtime.Allocator, + threads: int, + done: bool, +} /* Create a regular expression from a string pattern and a set of flags. @@ -87,7 +100,6 @@ create :: proc( permanent_allocator := context.allocator, temporary_allocator := context.temp_allocator, ) -> (result: Regular_Expression, err: Error) { - // For the sake of speed and simplicity, we first run all the intermediate // processes such as parsing and compilation through the temporary // allocator. @@ -152,7 +164,6 @@ to escape the delimiter if found in the middle of the string. All runes after the closing delimiter will be parsed as flags: -- 'g': Global - 'm': Multiline - 'i': Case_Insensitive - 'x': Ignore_Whitespace @@ -229,7 +240,6 @@ create_by_user :: proc( // to `end` here. for r in pattern[start + end:] { switch r { - case 'g': flags += { .Global } case 'm': flags += { .Multiline } case 'i': flags += { .Case_Insensitive } case 'x': flags += { .Ignore_Whitespace } @@ -245,6 +255,40 @@ create_by_user :: proc( return create(pattern[start:end], flags, permanent_allocator, temporary_allocator) } +/* +Create a `Match_Iterator` using a string to search, a regular expression to match against it, and a set of flags. + +*Allocates Using Provided Allocators* + +Inputs: +- str: The string to iterate over. +- pattern: The pattern to match. +- flags: A `bit_set` of RegEx flags. +- permanent_allocator: The allocator to use for the compiled regular expression. (default: context.allocator) +- temporary_allocator: The allocator to use for the intermediate compilation and iteration stages. (default: context.temp_allocator) + +Returns: +- result: The `Match_Iterator`. +- err: An error, if one occurred. +*/ +create_iterator :: proc( + str: string, + pattern: string, + flags: Flags = {}, + permanent_allocator := context.allocator, + temporary_allocator := context.temp_allocator, +) -> (result: Match_Iterator, err: Error) { + + result.regex = create(pattern, flags, permanent_allocator, temporary_allocator) or_return + result.capture = preallocate_capture() + result.temp = temporary_allocator + result.vm = virtual_machine.create(result.regex.program, str) + result.vm.class_data = result.regex.class_data + result.threads = max(1, virtual_machine.opcode_count(result.vm.code) - 1) + + return +} + /* Match a regular expression against a string and allocate the results into the returned `capture` structure. @@ -387,9 +431,127 @@ match_with_preallocated_capture :: proc( return } +/* +Iterate over a `Match_Iterator` and return successive captures. + +Inputs: +- it: Pointer to the `Match_Iterator` to iterate over. + +Returns: +- result: `Capture` for this iteration. +- ok: A bool indicating if there was a match, stopping the iteration on `false`. +*/ +match_iterator :: proc(it: ^Match_Iterator) -> (result: Capture, index: int, ok: bool) { + assert(len(it.capture.groups) >= common.MAX_CAPTURE_GROUPS, + "Pre-allocated RegEx capture `groups` must be at least 10 elements long.") + assert(len(it.capture.pos) >= common.MAX_CAPTURE_GROUPS, + "Pre-allocated RegEx capture `pos` must be at least 10 elements long.") + + // Guard against situations in which the iterator should finish. + if it.done { + return + } + + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + if it.idx > 0 { + // Reset the state needed to `virtual_machine.run` again. + it.vm.top_thread = 0 + it.vm.current_rune = rune(0) + it.vm.current_rune_size = 0 + for i in 0.. 0 { + result = {it.capture.pos[:num_groups], it.capture.groups[:num_groups]} + } + return result, it.idx, ok +} + match :: proc { match_and_allocate_capture, match_with_preallocated_capture, + match_iterator, +} + +/* +Reset an iterator, allowing it to be run again as if new. + +Inputs: +- it: The iterator to reset. +*/ +reset :: proc(it: ^Match_Iterator) { + it.done = false + it.idx = 0 + it.vm.string_pointer = 0 + + it.vm.top_thread = 0 + it.vm.current_rune = rune(0) + it.vm.current_rune_size = 0 + it.vm.last_rune = rune(0) + for i in 0.. (result: Capture) { context.allocator = allocator - result.pos = make([][2]int, common.MAX_CAPTURE_GROUPS) + result.pos = make([][2]int, common.MAX_CAPTURE_GROUPS) result.groups = make([]string, common.MAX_CAPTURE_GROUPS) return } @@ -436,7 +598,7 @@ Free all data allocated by the `match_and_allocate_capture` procedure. *Frees Using Provided Allocator* Inputs: -- capture: A Capture. +- capture: A `Capture`. - allocator: (default: context.allocator) */ destroy_capture :: proc(capture: Capture, allocator := context.allocator) { @@ -445,7 +607,24 @@ destroy_capture :: proc(capture: Capture, allocator := context.allocator) { delete(capture.pos) } +/* +Free all data allocated by the `create_iterator` procedure. + +*Frees Using Provided Allocator* + +Inputs: +- it: A `Match_Iterator` +- allocator: (default: context.allocator) +*/ +destroy_iterator :: proc(it: Match_Iterator, allocator := context.allocator) { + context.allocator = allocator + destroy(it.regex) + destroy(it.capture) + virtual_machine.destroy(it.vm) +} + destroy :: proc { destroy_regex, destroy_capture, + destroy_iterator, } diff --git a/core/text/regex/virtual_machine/doc.odin b/core/text/regex/virtual_machine/doc.odin index 1b0694565..d599dbb1c 100644 --- a/core/text/regex/virtual_machine/doc.odin +++ b/core/text/regex/virtual_machine/doc.odin @@ -109,34 +109,42 @@ For more information, see: https://swtch.com/~rsc/regexp/regexp2.html (0x0A) Assert_Start - Asserts that the thread is at the beginning of a string. + Asserts that the thread is at the beginning of the string. - (0x0B) Assert_End + (0x0B) Assert_Start_Multiline - Asserts that the thread is at the end of a string. + This opcode is compiled in only when the `Multiline` flag is present as a + replacement for the `^` text anchor. - (0x0C) Assert_Word_Boundary + Asserts that the thread is at the beginning of the string or previously + parsed either a "\n" or "\r". + + (0x0C) Assert_End + + Asserts that the thread is at the end of the string. + + (0x0D) Assert_Word_Boundary Asserts that the thread is on a word boundary, which can be the start or end of the text. This examines both the current rune and the next rune. - (0x0D) Assert_Non_Word_Boundary + (0x0E) Assert_Non_Word_Boundary A modified version of Assert_Word_Boundary that returns the opposite value. - (0x0E) Multiline_Open + (0x0F) Multiline_Open - This opcode is compiled in only when the `Multiline` flag is present, and - it replaces both `^` and `$` text anchors. + This opcode is compiled in only when the `Multiline` flag is present as a + replacement for the `$` text anchor. - It asserts that either the current thread is on one of the string - boundaries, or it consumes a `\n` or `\r` character. + It asserts that either the current thread is at the end of the string, + or it consumes a `\n` or `\r` character. If a `\r` character is consumed, the PC will be advanced to the sibling `Multiline_Close` opcode to optionally consume a `\n` character on the next frame. - (0x0F) Multiline_Close + (0x10) Multiline_Close This opcode is always present after `Multiline_Open`. @@ -144,10 +152,10 @@ For more information, see: https://swtch.com/~rsc/regexp/regexp2.html For example, Windows newlines are represented by the characters `\r\n`, whereas UNIX newlines are `\n` and Macintosh newlines are `\r`. - (0x10) Wait_For_Byte - (0x11) Wait_For_Rune - (0x12) Wait_For_Rune_Class - (0x13) Wait_For_Rune_Class_Negated + (0x11) Wait_For_Byte + (0x12) Wait_For_Rune + (0x13) Wait_For_Rune_Class + (0x14) Wait_For_Rune_Class_Negated These opcodes are an optimization around restarting threads on failed matches when the beginning to a pattern is predictable and the Global flag @@ -156,7 +164,7 @@ For more information, see: https://swtch.com/~rsc/regexp/regexp2.html They will cause the VM to wait for the next rune to match before splitting, as would happen in the un-optimized version. - (0x14) Match_All_And_Escape + (0x15) Match_All_And_Escape This opcode is an optimized version of `.*$` or `.+$` that causes the active thread to immediately work on escaping the program by following all diff --git a/core/text/regex/virtual_machine/util.odin b/core/text/regex/virtual_machine/util.odin index fa94a139f..79c781e4a 100644 --- a/core/text/regex/virtual_machine/util.odin +++ b/core/text/regex/virtual_machine/util.odin @@ -34,6 +34,7 @@ iterate_opcodes :: proc(iter: ^Opcode_Iterator) -> (opcode: Opcode, pc: int, ok: case .Split: iter.pc += size_of(Opcode) + 2 * size_of(u16) case .Save: iter.pc += size_of(Opcode) + size_of(u8) case .Assert_Start: iter.pc += size_of(Opcode) + case .Assert_Start_Multiline: iter.pc += size_of(Opcode) case .Assert_End: iter.pc += size_of(Opcode) case .Assert_Word_Boundary: iter.pc += size_of(Opcode) case .Assert_Non_Word_Boundary: iter.pc += size_of(Opcode) @@ -64,6 +65,7 @@ opcode_to_name :: proc(opcode: Opcode) -> (str: string) { case .Split: str = "Split" case .Save: str = "Save" case .Assert_Start: str = "Assert_Start" + case .Assert_Start_Multiline: str = "Assert_Start_Multiline" case .Assert_End: str = "Assert_End" case .Assert_Word_Boundary: str = "Assert_Word_Boundary" case .Assert_Non_Word_Boundary: str = "Assert_Non_Word_Boundary" diff --git a/core/text/regex/virtual_machine/virtual_machine.odin b/core/text/regex/virtual_machine/virtual_machine.odin index a4fca6c4d..c292b0e99 100644 --- a/core/text/regex/virtual_machine/virtual_machine.odin +++ b/core/text/regex/virtual_machine/virtual_machine.odin @@ -37,16 +37,17 @@ Opcode :: enum u8 { Split = 0x08, // | u16, u16 Save = 0x09, // | u8 Assert_Start = 0x0A, // | - Assert_End = 0x0B, // | - Assert_Word_Boundary = 0x0C, // | - Assert_Non_Word_Boundary = 0x0D, // | - Multiline_Open = 0x0E, // | - Multiline_Close = 0x0F, // | - Wait_For_Byte = 0x10, // | u8 - Wait_For_Rune = 0x11, // | i32 - Wait_For_Rune_Class = 0x12, // | u8 - Wait_For_Rune_Class_Negated = 0x13, // | u8 - Match_All_And_Escape = 0x14, // | + Assert_Start_Multiline = 0x0B, // | + Assert_End = 0x0C, // | + Assert_Word_Boundary = 0x0D, // | + Assert_Non_Word_Boundary = 0x0E, // | + Multiline_Open = 0x0F, // | + Multiline_Close = 0x10, // | + Wait_For_Byte = 0x11, // | u8 + Wait_For_Rune = 0x12, // | i32 + Wait_For_Rune_Class = 0x13, // | u8 + Wait_For_Rune_Class_Negated = 0x14, // | u8 + Match_All_And_Escape = 0x15, // | } Thread :: struct { @@ -77,6 +78,8 @@ Machine :: struct { current_rune_size: int, next_rune: rune, next_rune_size: int, + + last_rune: rune, } @@ -169,6 +172,12 @@ add_thread :: proc(vm: ^Machine, saved: ^[2 * common.MAX_CAPTURE_GROUPS]int, pc: pc += size_of(Opcode) continue } + case .Assert_Start_Multiline: + sp := vm.string_pointer+vm.current_rune_size + if sp == 0 || vm.last_rune == '\n' || vm.last_rune == '\r' { + pc += size_of(Opcode) + continue + } case .Assert_End: sp := vm.string_pointer+vm.current_rune_size if sp == len(vm.memory) { @@ -177,24 +186,12 @@ add_thread :: proc(vm: ^Machine, saved: ^[2 * common.MAX_CAPTURE_GROUPS]int, pc: } case .Multiline_Open: sp := vm.string_pointer+vm.current_rune_size - if sp == 0 || sp == len(vm.memory) { - if vm.next_rune == '\r' || vm.next_rune == '\n' { - // The VM is currently on a newline at the string boundary, - // so consume the newline next frame. - when common.ODIN_DEBUG_REGEX { - io.write_string(common.debug_stream, "*** New thread added [PC:") - common.write_padded_hex(common.debug_stream, pc, 4) - io.write_string(common.debug_stream, "]\n") - } - vm.next_threads[vm.top_thread] = Thread{ pc = pc, saved = saved } - vm.top_thread += 1 - } else { - // Skip the `Multiline_Close` opcode. - pc += 2 * size_of(Opcode) - continue - } + if sp == len(vm.memory) { + // Skip the `Multiline_Close` opcode. + pc += 2 * size_of(Opcode) + continue } else { - // Not on a string boundary. + // Not at the end of the string. // Try to consume a newline next frame in the other opcode loop. when common.ODIN_DEBUG_REGEX { io.write_string(common.debug_stream, "*** New thread added [PC:") @@ -329,10 +326,10 @@ add_thread :: proc(vm: ^Machine, saved: ^[2 * common.MAX_CAPTURE_GROUPS]int, pc: run :: proc(vm: ^Machine, $UNICODE_MODE: bool) -> (saved: ^[2 * common.MAX_CAPTURE_GROUPS]int, ok: bool) #no_bounds_check { when UNICODE_MODE { - vm.next_rune, vm.next_rune_size = utf8.decode_rune_in_string(vm.memory) + vm.next_rune, vm.next_rune_size = utf8.decode_rune_in_string(vm.memory[vm.string_pointer:]) } else { if len(vm.memory) > 0 { - vm.next_rune = cast(rune)vm.memory[0] + vm.next_rune = cast(rune)vm.memory[vm.string_pointer] vm.next_rune_size = 1 } } @@ -613,6 +610,7 @@ run :: proc(vm: ^Machine, $UNICODE_MODE: bool) -> (saved: ^[2 * common.MAX_CAPTU break } + vm.last_rune = vm.current_rune vm.string_pointer += vm.current_rune_size } @@ -627,8 +625,9 @@ opcode_count :: proc(code: Program) -> (opcodes: int) { return } -create :: proc(code: Program, str: string) -> (vm: Machine) { +create :: proc(code: Program, str: string, allocator := context.allocator) -> (vm: Machine) { assert(len(code) > 0, "RegEx VM has no instructions.") + context.allocator = allocator vm.memory = str vm.code = code @@ -644,3 +643,11 @@ create :: proc(code: Program, str: string) -> (vm: Machine) { return } + +destroy :: proc(vm: Machine, allocator := context.allocator) { + context.allocator = allocator + + delete(vm.busy_map) + free(vm.threads) + free(vm.next_threads) +} diff --git a/core/text/scanner/scanner.odin b/core/text/scanner/scanner.odin index 24dbcc8a4..96109f614 100644 --- a/core/text/scanner/scanner.odin +++ b/core/text/scanner/scanner.odin @@ -285,6 +285,7 @@ scan_number :: proc(s: ^Scanner, ch: rune, seen_dot: bool) -> (rune, rune) { case 'o': return "octal literal" case 'z': return "dozenal literal" case 'x': return "hexadecimal literal" + case 'h': return "hexadecimal literal" } return "decimal literal" } @@ -360,7 +361,8 @@ scan_number :: proc(s: ^Scanner, ch: rune, seen_dot: bool) -> (rune, rune) { base, prefix = 12, 'z' case 'h': tok = Float - fallthrough + ch = advance(s) + base, prefix = 16, 'h' case 'x': ch = advance(s) base, prefix = 16, 'x' @@ -447,7 +449,7 @@ scan_string :: proc(s: ^Scanner, quote: rune) -> (n: int) { ch := advance(s) for ch != quote { if ch == '\n' || ch < 0 { - error(s, "literal no terminated") + error(s, "literal not terminated") return } if ch == '\\' { diff --git a/core/thread/thread.odin b/core/thread/thread.odin index c1cbceb42..194c7bfef 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -39,7 +39,8 @@ Type representing a thread handle and the associated with that thread data. Thread :: struct { using specific: Thread_Os_Specific, flags: bit_set[Thread_State; u8], - // Thread ID. + // Thread ID. Depending on the platform, may start out as 0 (zero) until the thread + // has had a chance to run. id: int, // The thread procedure. procedure: Thread_Proc, @@ -257,19 +258,23 @@ to execute. The thread will have priority specified by the `priority` parameter. If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be -automatically freed. **Do not** dereference the `^Thread` pointer, if this -flag is specified. +automatically freed. + +**Do not** dereference the `^Thread` pointer, if this flag is specified. +That includes calling `join`, which needs to dereference ^Thread`. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread { +create_and_start :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) { thread_proc :: proc(t: ^Thread) { fn := cast(proc())t.data fn() } - t := create(thread_proc, priority) + if t = create(thread_proc, priority); t == nil { + return + } t.data = rawptr(fn) if self_cleanup { intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) @@ -288,21 +293,25 @@ to execute. The thread will have priority specified by the `priority` parameter. If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be -automatically freed. **Do not** dereference the `^Thread` pointer, if this -flag is specified. +automatically freed. + +**Do not** dereference the `^Thread` pointer, if this flag is specified. +That includes calling `join`, which needs to dereference ^Thread`. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread { +create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) { thread_proc :: proc(t: ^Thread) { fn := cast(proc(rawptr))t.data assert(t.user_index >= 1) data := t.user_args[0] fn(data) } - t := create(thread_proc, priority) + if t = create(thread_proc, priority); t == nil { + return + } t.data = rawptr(fn) t.user_index = 1 t.user_args[0] = data @@ -323,14 +332,16 @@ to execute. The thread will have priority specified by the `priority` parameter. If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be -automatically freed. **Do not** dereference the `^Thread` pointer, if this -flag is specified. +automatically freed. + +**Do not** dereference the `^Thread` pointer, if this flag is specified. +That includes calling `join`, which needs to dereference ^Thread`. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread +create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T))t.data @@ -338,7 +349,9 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex data := (^T)(&t.user_args[0])^ fn(data) } - t := create(thread_proc, priority) + if t = create(thread_proc, priority); t == nil { + return + } t.data = rawptr(fn) t.user_index = 1 @@ -364,14 +377,16 @@ to execute. The thread will have priority specified by the `priority` parameter. If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be -automatically freed. **Do not** dereference the `^Thread` pointer, if this -flag is specified. +automatically freed. + +**Do not** dereference the `^Thread` pointer, if this flag is specified. +That includes calling `join`, which needs to dereference ^Thread`. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread +create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T1, T2))t.data @@ -383,7 +398,9 @@ create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), fn(arg1, arg2) } - t := create(thread_proc, priority) + if t = create(thread_proc, priority); t == nil { + return + } t.data = rawptr(fn) t.user_index = 2 @@ -411,14 +428,16 @@ to execute. The thread will have priority specified by the `priority` parameter. If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be -automatically freed. **Do not** dereference the `^Thread` pointer, if this -flag is specified. +automatically freed. + +**Do not** dereference the `^Thread` pointer, if this flag is specified. +That includes calling `join`, which needs to dereference ^Thread`. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread +create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T1, T2, T3))t.data @@ -431,7 +450,9 @@ create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: pr fn(arg1, arg2, arg3) } - t := create(thread_proc, priority) + if t = create(thread_proc, priority); t == nil { + return + } t.data = rawptr(fn) t.user_index = 3 @@ -460,14 +481,16 @@ to execute. The thread will have priority specified by the `priority` parameter. If `self_cleanup` is specified, after the thread finishes the execution of the `fn` procedure, the resources associated with the thread are going to be -automatically freed. **Do not** dereference the `^Thread` pointer, if this -flag is specified. +automatically freed. + +**Do not** dereference the `^Thread` pointer, if this flag is specified. +That includes calling `join`, which needs to dereference ^Thread`. **IMPORTANT**: If `init_context` is specified and the default temporary allocator is used, the thread procedure needs to call `runtime.default_temp_allocator_destroy()` in order to free the resources associated with the temporary allocations. */ -create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread +create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> (t: ^Thread) where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS { thread_proc :: proc(t: ^Thread) { fn := cast(proc(T1, T2, T3, T4))t.data @@ -481,7 +504,9 @@ create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: fn(arg1, arg2, arg3, arg4) } - t := create(thread_proc, priority) + if t = create(thread_proc, priority); t == nil { + return + } t.data = rawptr(fn) t.user_index = 4 @@ -513,8 +538,10 @@ _select_context_for_thread :: proc(init_context: Maybe(runtime.Context)) -> runt Ensure that the temp allocator is thread-safe when the user provides a specific initial context to use. Without this, the thread will use the same temp allocator state as the parent thread, and thus, bork it up. */ - if ctx.temp_allocator.procedure == runtime.default_temp_allocator_proc { - ctx.temp_allocator.data = &runtime.global_default_temp_allocator_data + when !ODIN_DEFAULT_TO_NIL_ALLOCATOR { + if ctx.temp_allocator.procedure == runtime.default_temp_allocator_proc { + ctx.temp_allocator.data = &runtime.global_default_temp_allocator_data + } } return ctx } @@ -529,4 +556,4 @@ _maybe_destroy_default_temp_allocator :: proc(init_context: Maybe(runtime.Contex if context.temp_allocator.procedure == runtime.default_temp_allocator_proc { runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data) } -} +} \ No newline at end of file diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index 59bf90620..15b3a28d2 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -120,6 +120,20 @@ pool_join :: proc(pool: ^Pool) { yield() + unstarted_count: int + for t in pool.threads { + flags := intrinsics.atomic_load(&t.flags) + if .Started not_in flags { + unstarted_count += 1 + } + } + + // most likely the user forgot to call `pool_start` + // exit here, so we don't hang forever + if len(pool.threads) == unstarted_count { + return + } + started_count: int for started_count < len(pool.threads) { started_count = 0 diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index ff79cfcbc..1db32657e 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -29,14 +29,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { t.id = sync.current_thread_id() - if .Started not_in sync.atomic_load(&t.flags) { + for (.Started not_in sync.atomic_load(&t.flags)) { sync.wait(&t.start_ok) } - if .Joined in sync.atomic_load(&t.flags) { - return nil - } - // Enable thread's cancelability. // NOTE(laytan): Darwin does not correctly/fully support all of this, not doing this does // actually make pthread_cancel work in the capacity of my tests, while executing this would @@ -85,8 +81,13 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { } defer posix.pthread_attr_destroy(&attrs) - // NOTE(tetra, 2019-11-01): These only fail if their argument is invalid. + stacksize: posix.rlimit + if res := posix.getrlimit(.STACK, &stacksize); res == .OK && stacksize.rlim_cur > 0 { + _ = posix.pthread_attr_setstacksize(&attrs, uint(stacksize.rlim_cur)) + } + res: posix.Errno + // NOTE(tetra, 2019-11-01): These only fail if their argument is invalid. res = posix.pthread_attr_setdetachstate(&attrs, .CREATE_JOINABLE) assert(res == nil) when ODIN_OS != .Haiku && ODIN_OS != .NetBSD { @@ -124,7 +125,6 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { free(thread, thread.creation_allocator) return nil } - return thread } @@ -149,10 +149,13 @@ _join :: proc(t: ^Thread) { // Prevent non-started threads from blocking main thread with initial wait // condition. - if .Started not_in sync.atomic_load(&t.flags) { + for (.Started not_in sync.atomic_load(&t.flags)) { _start(t) } + posix.pthread_join(t.unix_thread, nil) + + t.flags += {.Joined} } _join_multiple :: proc(threads: ..^Thread) { diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index cc73a2d6a..358e3e7f1 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -13,6 +13,7 @@ Thread_Os_Specific :: struct { win32_thread: win32.HANDLE, win32_thread_id: win32.DWORD, mutex: sync.Mutex, + start_ok: sync.Sema, } _thread_priority_map := [Thread_Priority]i32{ @@ -27,12 +28,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { __windows_thread_entry_proc :: proc "system" (t_: rawptr) -> win32.DWORD { t := (^Thread)(t_) - if .Joined in sync.atomic_load(&t.flags) { - return 0 + for (.Started not_in sync.atomic_load(&t.flags)) { + sync.wait(&t.start_ok) } - t.id = sync.current_thread_id() - { init_context := t.init_context @@ -76,6 +75,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { thread.procedure = procedure thread.win32_thread = win32_thread thread.win32_thread_id = win32_thread_id + thread.id = int(win32_thread_id) ok := win32.SetThreadPriority(win32_thread, _thread_priority_map[priority]) assert(ok == true) @@ -103,16 +103,15 @@ _join :: proc(t: ^Thread) { return } - t.flags += {.Joined} - - if .Started not_in t.flags { - t.flags += {.Started} - win32.ResumeThread(t.win32_thread) + for (.Started not_in sync.atomic_load(&t.flags)) { + _start(t) } win32.WaitForSingleObject(t.win32_thread, win32.INFINITE) win32.CloseHandle(t.win32_thread) t.win32_thread = win32.INVALID_HANDLE + + t.flags += {.Joined} } _join_multiple :: proc(threads: ..^Thread) { @@ -136,6 +135,7 @@ _join_multiple :: proc(threads: ..^Thread) { for t in threads { win32.CloseHandle(t.win32_thread) t.win32_thread = win32.INVALID_HANDLE + t.flags += {.Joined} } } diff --git a/core/time/datetime/constants.odin b/core/time/datetime/constants.odin index e24709e49..b4fb4a15f 100644 --- a/core/time/datetime/constants.odin +++ b/core/time/datetime/constants.odin @@ -5,13 +5,11 @@ Type representing a mononotic day number corresponding to a date. Ordinal 1 = Midnight Monday, January 1, 1 A.D. (Gregorian) | Midnight Monday, January 3, 1 A.D. (Julian) + +Every other ordinal counts days forwards, starting from the above date. */ Ordinal :: i64 -/* -*/ -EPOCH :: Ordinal(1) - /* Minimum valid value for date. diff --git a/core/time/datetime/datetime.odin b/core/time/datetime/datetime.odin index 2cd90b0e7..f52bff9b6 100644 --- a/core/time/datetime/datetime.odin +++ b/core/time/datetime/datetime.odin @@ -98,7 +98,7 @@ This procedure takes the value of an ordinal and returns the day of week for that ordinal. */ day_of_week :: proc "contextless" (ordinal: Ordinal) -> (day: Weekday) { - return Weekday((ordinal - EPOCH + 1) %% 7) + return Weekday(ordinal %% 7) } /* @@ -349,8 +349,7 @@ the result is unspecified. unsafe_date_to_ordinal :: proc "contextless" (date: Date) -> (ordinal: Ordinal) { year_minus_one := date.year - 1 - // Day before epoch - ordinal = EPOCH - 1 + ordinal = 0 // Add non-leap days ordinal += 365 * year_minus_one @@ -382,17 +381,17 @@ This procedure returns the year and the day of the year of a given ordinal. Of the ordinal is outside of its valid range, the result is unspecified. */ unsafe_ordinal_to_year :: proc "contextless" (ordinal: Ordinal) -> (year: i64, day_ordinal: i64) { - // Days after epoch - d0 := ordinal - EPOCH + // Correct for leap year cycle starting at day 1. + d0 := ordinal - 1 // Number of 400-year cycles and remainder - n400, d1 := divmod(d0, 146097) + n400, d1 := divmod(d0, 365*400 + 100 - 3) // Number of 100-year cycles and remainder - n100, d2 := divmod(d1, 36524) + n100, d2 := divmod(d1, 365*100 + 25 - 1) // Number of 4-year cycles and remainder - n4, d3 := divmod(d2, 1461) + n4, d3 := divmod(d2, 365*4 + 1) // Number of remaining days n1, d4 := divmod(d3, 365) diff --git a/core/time/perf.odin b/core/time/perf.odin index 784d7acd6..f4e1b4aa8 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -17,6 +17,13 @@ tick_now :: proc "contextless" () -> Tick { return _tick_now() } +/* +Add duration to a tick. +*/ +tick_add :: proc "contextless" (t: Tick, d: Duration) -> Tick { + return Tick{t._nsec + i64(d)} +} + /* Obtain the difference between ticks. */ @@ -97,6 +104,8 @@ TSC at a fixed frequency, independent of ACPI state, and CPU frequency. has_invariant_tsc :: proc "contextless" () -> bool { when ODIN_ARCH == .amd64 { return x86_has_invariant_tsc() + } else when ODIN_ARCH == .arm64 { + return true } return false diff --git a/core/time/time_js.odin b/core/time/time_js.odin index 9175fbfe9..0e021dc88 100644 --- a/core/time/time_js.odin +++ b/core/time/time_js.odin @@ -24,7 +24,7 @@ _sleep :: proc "contextless" (d: Duration) { _tick_now :: proc "contextless" () -> Tick { foreign odin_env { - tick_now :: proc "contextless" () -> f32 --- + tick_now :: proc "contextless" () -> f64 --- } return Tick{i64(tick_now()*1e6)} } diff --git a/core/time/timezone/tz_js.odin b/core/time/timezone/tz_js.odin new file mode 100644 index 000000000..d63e40033 --- /dev/null +++ b/core/time/timezone/tz_js.odin @@ -0,0 +1,13 @@ +#+build js +#+private +package timezone + +import "core:time/datetime" + +local_tz_name :: proc(allocator := context.allocator) -> (name: string, success: bool) { + return +} + +_region_load :: proc(_reg_str: string, allocator := context.allocator) -> (out_reg: ^datetime.TZ_Region, success: bool) { + return nil, true +} \ No newline at end of file diff --git a/core/time/timezone/tz_windows.odin b/core/time/timezone/tz_windows.odin index 8dc5f533c..fe00719a2 100644 --- a/core/time/timezone/tz_windows.odin +++ b/core/time/timezone/tz_windows.odin @@ -159,9 +159,9 @@ iana_to_windows_tz :: proc(iana_name: string, allocator := context.allocator) -> status: windows.UError iana_name_wstr := windows.utf8_to_wstring(iana_name, allocator) - defer free(iana_name_wstr, allocator) + defer free(rawptr(iana_name_wstr), allocator) - wintz_name_len := windows.ucal_getWindowsTimeZoneID(iana_name_wstr, -1, raw_data(wintz_name_buffer[:]), len(wintz_name_buffer), &status) + wintz_name_len := windows.ucal_getWindowsTimeZoneID(iana_name_wstr, -1, cstring16(raw_data(wintz_name_buffer[:])), len(wintz_name_buffer), &status) if status != .U_ZERO_ERROR { return } @@ -178,7 +178,7 @@ local_tz_name :: proc(allocator := context.allocator) -> (name: string, success: iana_name_buffer: [128]u16 status: windows.UError - zone_str_len := windows.ucal_getDefaultTimeZone(raw_data(iana_name_buffer[:]), len(iana_name_buffer), &status) + zone_str_len := windows.ucal_getDefaultTimeZone(cstring16(raw_data(iana_name_buffer[:])), len(iana_name_buffer), &status) if status != .U_ZERO_ERROR { return } @@ -291,7 +291,7 @@ _region_load :: proc(reg_str: string, allocator := context.allocator) -> (out_re defer delete(tz_key, allocator) tz_key_wstr := windows.utf8_to_wstring(tz_key, allocator) - defer free(tz_key_wstr, allocator) + defer free(rawptr(tz_key_wstr), allocator) key: windows.HKEY res := windows.RegOpenKeyExW(windows.HKEY_LOCAL_MACHINE, tz_key_wstr, 0, windows.KEY_READ, &key) diff --git a/core/time/timezone/tzdate.odin b/core/time/timezone/tzdate.odin index e62400889..8e900ec11 100644 --- a/core/time/timezone/tzdate.odin +++ b/core/time/timezone/tzdate.odin @@ -224,7 +224,7 @@ datetime_to_tz :: proc(dt: datetime.DateTime, tz: ^datetime.TZ_Region) -> (out: record := region_get_nearest(tz, tm) or_return secs := time.time_to_unix(tm) - adj_time := time.unix(secs + record.utc_offset, 0) + adj_time := time.unix(secs + record.utc_offset, i64(dt.nano)) adj_dt := time.time_to_datetime(adj_time) or_return adj_dt.tz = tz diff --git a/core/time/timezone/tzif.odin b/core/time/timezone/tzif.odin index 3fec7be53..804211ef4 100644 --- a/core/time/timezone/tzif.odin +++ b/core/time/timezone/tzif.odin @@ -577,12 +577,7 @@ parse_tzif :: proc(_buffer: []u8, region_name: string, allocator := context.allo footer_str := string(buffer[:end_idx]) // UTC is a special case, we don't need to alloc - if len(local_time_types) == 1 { - name := cstring(raw_data(timezone_string_table[local_time_types[0].idx:])) - if name != "UTC" { - return - } - + if len(local_time_types) == 1 && local_time_types[0].utoff == 0 { return nil, true } diff --git a/core/time/tsc_darwin.odin b/core/time/tsc_darwin.odin index 3726cff49..2efd35f20 100644 --- a/core/time/tsc_darwin.odin +++ b/core/time/tsc_darwin.odin @@ -1,10 +1,17 @@ #+private package time -import "core:sys/unix" +import "base:intrinsics" +@require import "core:sys/unix" _get_tsc_frequency :: proc "contextless" () -> (freq: u64, ok: bool) { - unix.sysctlbyname("machdep.tsc.frequency", &freq) or_return + when ODIN_ARCH == .amd64 { + unix.sysctlbyname("machdep.tsc.frequency", &freq) or_return + } else when ODIN_ARCH == .arm64 { + freq = u64(intrinsics.read_cycle_counter_frequency()) + } else { + return + } ok = true return } diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin index a83634414..f59a0338b 100644 --- a/core/time/tsc_linux.odin +++ b/core/time/tsc_linux.odin @@ -2,32 +2,38 @@ #+build linux package time -import linux "core:sys/linux" +import "base:intrinsics" +@(require) import linux "core:sys/linux" _get_tsc_frequency :: proc "contextless" () -> (u64, bool) { - // Get the file descriptor for the perf mapping - perf_attr := linux.Perf_Event_Attr{} - perf_attr.size = size_of(perf_attr) - perf_attr.type = .HARDWARE - perf_attr.config.hw = .INSTRUCTIONS - perf_attr.flags = {.Disabled, .Exclude_Kernel, .Exclude_HV} - fd, perf_errno := linux.perf_event_open(&perf_attr, linux.Pid(0), -1, linux.Fd(-1), {}) - if perf_errno != nil { - return 0, false + when ODIN_ARCH == .arm64 { + frequency := u64(intrinsics.read_cycle_counter_frequency()) + return frequency, true + } else { + // Get the file descriptor for the perf mapping + perf_attr := linux.Perf_Event_Attr{} + perf_attr.size = size_of(perf_attr) + perf_attr.type = .HARDWARE + perf_attr.config.hw = .INSTRUCTIONS + perf_attr.flags = {.Disabled, .Exclude_Kernel, .Exclude_HV} + fd, perf_errno := linux.perf_event_open(&perf_attr, linux.Pid(0), -1, linux.Fd(-1), {}) + if perf_errno != nil { + return 0, false + } + defer linux.close(fd) + // Map it into the memory + page_size : uint = 4096 + addr, mmap_errno := linux.mmap(0, page_size, {.READ}, {.SHARED}, fd) + if mmap_errno != nil { + return 0, false + } + defer linux.munmap(addr, page_size) + // Get the frequency from the mapped page + event_page := cast(^linux.Perf_Event_Mmap_Page) addr + if .User_Time not_in event_page.cap.flags { + return 0, false + } + frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) + return frequency, true } - defer linux.close(fd) - // Map it into the memory - page_size : uint = 4096 - addr, mmap_errno := linux.mmap(0, page_size, {.READ}, {.SHARED}, fd) - if mmap_errno != nil { - return 0, false - } - defer linux.munmap(addr, page_size) - // Get the frequency from the mapped page - event_page := cast(^linux.Perf_Event_Mmap_Page) addr - if .User_Time not_in event_page.cap.flags { - return 0, false - } - frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) - return frequency, true } diff --git a/core/unicode/utf16/utf16.odin b/core/unicode/utf16/utf16.odin index e2bcf7f68..d3f98584b 100644 --- a/core/unicode/utf16/utf16.odin +++ b/core/unicode/utf16/utf16.odin @@ -106,7 +106,57 @@ decode :: proc(d: []rune, s: []u16) -> (n: int) { return } -rune_count :: proc(s: []u16) -> (n: int) { +decode_rune_in_string :: proc(s: string16) -> (r: rune, width: int) { + r = rune(REPLACEMENT_CHAR) + n := len(s) + if n < 1 { + return + } + width = 1 + + + switch c := s[0]; { + case c < _surr1, _surr3 <= c: + r = rune(c) + case _surr1 <= c && c < _surr2 && 1 < len(s) && + _surr2 <= s[1] && s[1] < _surr3: + r = decode_surrogate_pair(rune(c), rune(s[1])) + width += 1 + } + return +} + +string_to_runes :: proc "odin" (s: string16, allocator := context.allocator) -> (runes: []rune) { + n := rune_count(s) + + runes = make([]rune, n, allocator) + i := 0 + for r in s { + runes[i] = r + i += 1 + } + return +} + + +rune_count :: proc{ + rune_count_in_string, + rune_count_in_slice, +} +rune_count_in_string :: proc(s: string16) -> (n: int) { + for i := 0; i < len(s); i += 1 { + c := s[i] + if _surr1 <= c && c < _surr2 && i+1 < len(s) && + _surr2 <= s[i+1] && s[i+1] < _surr3 { + i += 1 + } + n += 1 + } + return +} + + +rune_count_in_slice :: proc(s: []u16) -> (n: int) { for i := 0; i < len(s); i += 1 { c := s[i] if _surr1 <= c && c < _surr2 && i+1 < len(s) && diff --git a/examples/all/all_js.odin b/examples/all/all_js.odin new file mode 100644 index 000000000..28b85f537 --- /dev/null +++ b/examples/all/all_js.odin @@ -0,0 +1,148 @@ +#+build js +package all + +// Imports "every" package +// This is useful for knowing what exists and producing documentation with `odin doc` + +@(require) import "core:bufio" +@(require) import "core:bytes" +@(require) import "core:c" + +@(require) import "core:compress" +@(require) import "core:compress/shoco" +@(require) import "core:compress/gzip" +@(require) import "core:compress/zlib" + +@(require) import "core:container/avl" +@(require) import "core:container/bit_array" +@(require) import "core:container/priority_queue" +@(require) import "core:container/queue" +@(require) import "core:container/small_array" +@(require) import "core:container/lru" +@(require) import "core:container/intrusive/list" +@(require) import "core:container/rbtree" +@(require) import "core:container/topological_sort" + +@(require) import "core:crypto" +@(require) import "core:crypto/aead" +@(require) import "core:crypto/aegis" +@(require) import "core:crypto/aes" +@(require) import "core:crypto/blake2b" +@(require) import "core:crypto/blake2s" +@(require) import "core:crypto/chacha20" +@(require) import "core:crypto/chacha20poly1305" +@(require) import chash "core:crypto/hash" +@(require) import "core:crypto/deoxysii" +@(require) import "core:crypto/ed25519" +@(require) import "core:crypto/hkdf" +@(require) import "core:crypto/hmac" +@(require) import "core:crypto/kmac" +@(require) import "core:crypto/legacy/keccak" +@(require) import "core:crypto/legacy/md5" +@(require) import "core:crypto/legacy/sha1" +@(require) import "core:crypto/pbkdf2" +@(require) import "core:crypto/poly1305" +@(require) import "core:crypto/ristretto255" +@(require) import "core:crypto/sha2" +@(require) import "core:crypto/sha3" +@(require) import "core:crypto/shake" +@(require) import "core:crypto/sm3" +@(require) import "core:crypto/tuplehash" +@(require) import "core:crypto/x25519" +@(require) import "core:crypto/x448" + +@(require) import "core:debug/pe" +@(require) import "core:debug/trace" + +@(require) import "core:dynlib" +@(require) import "core:net" + +@(require) import "core:encoding/base32" +@(require) import "core:encoding/base64" +@(require) import "core:encoding/cbor" +@(require) import "core:encoding/csv" +@(require) import "core:encoding/endian" +@(require) import "core:encoding/hxa" +@(require) import "core:encoding/ini" +@(require) import "core:encoding/json" +@(require) import "core:encoding/varint" +@(require) import "core:encoding/xml" +@(require) import "core:encoding/uuid" +@(require) import "core:encoding/uuid/legacy" + +@(require) import "core:fmt" +@(require) import "core:hash" +@(require) import "core:hash/xxhash" + +@(require) import "core:image" +@(require) import "core:image/bmp" +@(require) import "core:image/netpbm" +@(require) import "core:image/png" +@(require) import "core:image/qoi" +@(require) import "core:image/tga" + +@(require) import "core:io" +@(require) import "core:log" + +@(require) import "core:math" +@(require) import "core:math/big" +@(require) import "core:math/bits" +@(require) import "core:math/fixed" +@(require) import "core:math/linalg" +@(require) import "core:math/linalg/glsl" +@(require) import "core:math/linalg/hlsl" +@(require) import "core:math/noise" +@(require) import "core:math/rand" +@(require) import "core:math/ease" +@(require) import "core:math/cmplx" + +@(require) import "core:mem" +@(require) import "core:mem/tlsf" +@(require) import "core:mem/virtual" + +@(require) import "core:odin/ast" +@(require) import doc_format "core:odin/doc-format" + +@(require) import "core:odin/tokenizer" +@(require) import "core:os" +@(require) import "core:path/slashpath" + +@(require) import "core:relative" + +@(require) import "core:reflect" +@(require) import "base:runtime" +@(require) import "base:sanitizer" +@(require) import "core:simd" +@(require) import "core:simd/x86" +@(require) import "core:slice" +@(require) import "core:slice/heap" +@(require) import "core:sort" +@(require) import "core:strconv" +@(require) import "core:strings" +@(require) import "core:sync" + +@(require) import "core:terminal" +@(require) import "core:terminal/ansi" + +@(require) import "core:text/edit" +@(require) import "core:text/i18n" +@(require) import "core:text/match" +@(require) import "core:text/regex" +@(require) import "core:text/scanner" +@(require) import "core:text/table" + +@(require) import "core:thread" +@(require) import "core:time" +@(require) import "core:time/datetime" +@(require) import "core:time/timezone" + + +@(require) import "core:sys/orca" +@(require) import "core:sys/info" + +@(require) import "core:unicode" +@(require) import "core:unicode/utf8" +@(require) import "core:unicode/utf8/utf8string" +@(require) import "core:unicode/utf16" + +main :: proc() {} \ No newline at end of file diff --git a/examples/all/all_linux.odin b/examples/all/all_linux.odin index ca51d6562..2b70fa1e1 100644 --- a/examples/all/all_linux.odin +++ b/examples/all/all_linux.odin @@ -1,6 +1,5 @@ #+build linux package all -import linux "core:sys/linux" - -_ :: linux \ No newline at end of file +@(require) import "core:sys/linux" +@(require) import "vendor:x11/xlib" \ No newline at end of file diff --git a/examples/all/all_main.odin b/examples/all/all_main.odin index 4a8a198d3..205eb2a3c 100644 --- a/examples/all/all_main.odin +++ b/examples/all/all_main.odin @@ -1,271 +1,157 @@ +#+build !js package all // Imports every package // This is useful for knowing what exists and producing documentation with `odin doc` -import bufio "core:bufio" -import bytes "core:bytes" +@(require) import "core:bufio" +@(require) import "core:bytes" -import c "core:c" -import libc "core:c/libc" +@(require) import "core:c" +@(require) import "core:c/libc" -import compress "core:compress" -import shoco "core:compress/shoco" -import gzip "core:compress/gzip" -import zlib "core:compress/zlib" +@(require) import "core:compress" +@(require) import "core:compress/shoco" +@(require) import "core:compress/gzip" +@(require) import "core:compress/zlib" -import avl "core:container/avl" -import bit_array "core:container/bit_array" -import priority_queue "core:container/priority_queue" -import queue "core:container/queue" -import small_array "core:container/small_array" -import lru "core:container/lru" -import list "core:container/intrusive/list" -import rbtree "core:container/rbtree" -import topological_sort "core:container/topological_sort" +@(require) import "core:container/avl" +@(require) import "core:container/bit_array" +@(require) import "core:container/priority_queue" +@(require) import "core:container/queue" +@(require) import "core:container/small_array" +@(require) import "core:container/lru" +@(require) import "core:container/intrusive/list" +@(require) import "core:container/rbtree" +@(require) import "core:container/topological_sort" -import crypto "core:crypto" -import aead "core:crypto/aead" -import aes "core:crypto/aes" -import blake2b "core:crypto/blake2b" -import blake2s "core:crypto/blake2s" -import chacha20 "core:crypto/chacha20" -import chacha20poly1305 "core:crypto/chacha20poly1305" -import crypto_hash "core:crypto/hash" -import ed25519 "core:crypto/ed25519" -import hkdf "core:crypto/hkdf" -import hmac "core:crypto/hmac" -import kmac "core:crypto/kmac" -import keccak "core:crypto/legacy/keccak" -import md5 "core:crypto/legacy/md5" -import sha1 "core:crypto/legacy/sha1" -import pbkdf2 "core:crypto/pbkdf2" -import poly1305 "core:crypto/poly1305" -import ristretto255 "core:crypto/ristretto255" -import sha2 "core:crypto/sha2" -import sha3 "core:crypto/sha3" -import shake "core:crypto/shake" -import sm3 "core:crypto/sm3" -import tuplehash "core:crypto/tuplehash" -import x25519 "core:crypto/x25519" +@(require) import "core:crypto" +@(require) import "core:crypto/aead" +@(require) import "core:crypto/aegis" +@(require) import "core:crypto/aes" +@(require) import "core:crypto/blake2b" +@(require) import "core:crypto/blake2s" +@(require) import "core:crypto/chacha20" +@(require) import "core:crypto/chacha20poly1305" +@(require) import chash "core:crypto/hash" +@(require) import "core:crypto/deoxysii" +@(require) import "core:crypto/ed25519" +@(require) import "core:crypto/hkdf" +@(require) import "core:crypto/hmac" +@(require) import "core:crypto/kmac" +@(require) import "core:crypto/legacy/keccak" +@(require) import "core:crypto/legacy/md5" +@(require) import "core:crypto/legacy/sha1" +@(require) import "core:crypto/pbkdf2" +@(require) import "core:crypto/poly1305" +@(require) import "core:crypto/ristretto255" +@(require) import "core:crypto/sha2" +@(require) import "core:crypto/sha3" +@(require) import "core:crypto/shake" +@(require) import "core:crypto/sm3" +@(require) import "core:crypto/tuplehash" +@(require) import "core:crypto/x25519" +@(require) import "core:crypto/x448" -import pe "core:debug/pe" -import trace "core:debug/trace" +@(require) import "core:debug/pe" +@(require) import "core:debug/trace" -import dynlib "core:dynlib" -import net "core:net" +@(require) import "core:dynlib" +@(require) import "core:net" -import ansi "core:encoding/ansi" -import base32 "core:encoding/base32" -import base64 "core:encoding/base64" -import cbor "core:encoding/cbor" -import csv "core:encoding/csv" -import endian "core:encoding/endian" -import hxa "core:encoding/hxa" -import ini "core:encoding/ini" -import json "core:encoding/json" -import varint "core:encoding/varint" -import xml "core:encoding/xml" -import uuid "core:encoding/uuid" -import uuid_legacy "core:encoding/uuid/legacy" +@(require) import "core:encoding/base32" +@(require) import "core:encoding/base64" +@(require) import "core:encoding/cbor" +@(require) import "core:encoding/csv" +@(require) import "core:encoding/endian" +@(require) import "core:encoding/hxa" +@(require) import "core:encoding/ini" +@(require) import "core:encoding/json" +@(require) import "core:encoding/varint" +@(require) import "core:encoding/xml" +@(require) import "core:encoding/uuid" +@(require) import "core:encoding/uuid/legacy" -import fmt "core:fmt" -import hash "core:hash" -import xxhash "core:hash/xxhash" +@(require) import "core:fmt" +@(require) import "core:hash" +@(require) import "core:hash/xxhash" -import image "core:image" -import bmp "core:image/bmp" -import netpbm "core:image/netpbm" -import png "core:image/png" -import qoi "core:image/qoi" -import tga "core:image/tga" +@(require) import "core:image" +@(require) import "core:image/bmp" +@(require) import "core:image/netpbm" +@(require) import "core:image/png" +@(require) import "core:image/qoi" +@(require) import "core:image/tga" +@(require) import "core:image/jpeg" -import io "core:io" -import log "core:log" +@(require) import "core:io" +@(require) import "core:log" -import math "core:math" -import big "core:math/big" -import bits "core:math/bits" -import fixed "core:math/fixed" -import linalg "core:math/linalg" -import glm "core:math/linalg/glsl" -import hlm "core:math/linalg/hlsl" -import noise "core:math/noise" -import rand "core:math/rand" -import ease "core:math/ease" -import cmplx "core:math/cmplx" +@(require) import "core:math" +@(require) import "core:math/big" +@(require) import "core:math/bits" +@(require) import "core:math/fixed" +@(require) import "core:math/linalg" +@(require) import "core:math/linalg/glsl" +@(require) import "core:math/linalg/hlsl" +@(require) import "core:math/noise" +@(require) import "core:math/rand" +@(require) import "core:math/ease" +@(require) import "core:math/cmplx" -import mem "core:mem" -import tlsf "core:mem/tlsf" -import virtual "core:mem/virtual" +@(require) import "core:mem" +@(require) import "core:mem/tlsf" +@(require) import "core:mem/virtual" -import ast "core:odin/ast" -import doc_format "core:odin/doc-format" -import odin_parser "core:odin/parser" -import odin_tokenizer "core:odin/tokenizer" +@(require) import "core:odin/ast" +@(require) import doc_format "core:odin/doc-format" +@(require) import "core:odin/parser" +@(require) import "core:odin/tokenizer" -import spall "core:prof/spall" +@(require) import "core:prof/spall" -import os "core:os" +@(require) import "core:os" -import slashpath "core:path/slashpath" -import filepath "core:path/filepath" +@(require) import "core:path/slashpath" +@(require) import "core:path/filepath" -import relative "core:relative" +@(require) import "core:relative" -import reflect "core:reflect" -import runtime "base:runtime" -import simd "core:simd" -import x86 "core:simd/x86" -import slice "core:slice" -import slice_heap "core:slice/heap" -import sort "core:sort" -import strconv "core:strconv" -import strings "core:strings" -import sync "core:sync" -import testing "core:testing" +@(require) import "core:reflect" +@(require) import "base:runtime" +@(require) import "base:sanitizer" +@(require) import "core:simd" +@(require) import "core:simd/x86" +@(require) import "core:slice" +@(require) import "core:slice/heap" +@(require) import "core:sort" +@(require) import "core:strconv" +@(require) import "core:strings" +@(require) import "core:sync" +@(require) import "core:testing" -import edit "core:text/edit" -import i18n "core:text/i18n" -import match "core:text/match" -import regex "core:text/regex" -import scanner "core:text/scanner" -import table "core:text/table" +@(require) import "core:terminal" +@(require) import "core:terminal/ansi" -import thread "core:thread" -import time "core:time" -import datetime "core:time/datetime" -import timezone "core:time/timezone" -import flags "core:flags" +@(require) import "core:text/edit" +@(require) import "core:text/i18n" +@(require) import "core:text/match" +@(require) import "core:text/regex" +@(require) import "core:text/scanner" +@(require) import "core:text/table" -import orca "core:sys/orca" -import sysinfo "core:sys/info" +@(require) import "core:thread" +@(require) import "core:time" +@(require) import "core:time/datetime" +@(require) import "core:time/timezone" +@(require) import "core:flags" -import unicode "core:unicode" -import utf8 "core:unicode/utf8" -import utf8string "core:unicode/utf8/utf8string" -import utf16 "core:unicode/utf16" +@(require) import "core:sys/orca" +@(require) import "core:sys/info" -main :: proc(){} +@(require) import "core:unicode" +@(require) import "core:unicode/utf8" +@(require) import "core:unicode/utf8/utf8string" +@(require) import "core:unicode/utf16" - -_ :: bufio -_ :: bytes -_ :: c -_ :: libc -_ :: compress -_ :: shoco -_ :: gzip -_ :: zlib -_ :: avl -_ :: bit_array -_ :: priority_queue -_ :: queue -_ :: small_array -_ :: lru -_ :: list -_ :: rbtree -_ :: topological_sort -_ :: crypto -_ :: crypto_hash -_ :: aead -_ :: aes -_ :: blake2b -_ :: blake2s -_ :: chacha20 -_ :: chacha20poly1305 -_ :: ed25519 -_ :: hmac -_ :: hkdf -_ :: kmac -_ :: keccak -_ :: md5 -_ :: pbkdf2 -_ :: poly1305 -_ :: ristretto255 -_ :: sha1 -_ :: sha2 -_ :: sha3 -_ :: shake -_ :: sm3 -_ :: tuplehash -_ :: x25519 -_ :: pe -_ :: trace -_ :: dynlib -_ :: net -_ :: ansi -_ :: base32 -_ :: base64 -_ :: csv -_ :: hxa -_ :: ini -_ :: json -_ :: varint -_ :: xml -_ :: endian -_ :: cbor -_ :: fmt -_ :: hash -_ :: xxhash -_ :: image -_ :: bmp -_ :: netpbm -_ :: png -_ :: qoi -_ :: tga -_ :: io -_ :: log -_ :: math -_ :: big -_ :: bits -_ :: fixed -_ :: linalg -_ :: glm -_ :: hlm -_ :: noise -_ :: rand -_ :: ease -_ :: cmplx -_ :: mem -_ :: tlsf -_ :: virtual -_ :: ast -_ :: doc_format -_ :: odin_parser -_ :: odin_tokenizer -_ :: os -_ :: spall -_ :: slashpath -_ :: filepath -_ :: relative -_ :: reflect -_ :: runtime -_ :: simd -_ :: x86 -_ :: slice -_ :: slice_heap -_ :: sort -_ :: strconv -_ :: strings -_ :: sync -_ :: testing -_ :: scanner -_ :: i18n -_ :: match -_ :: regex -_ :: table -_ :: edit -_ :: thread -_ :: time -_ :: datetime -_ :: timezone -_ :: flags -_ :: orca -_ :: sysinfo -_ :: unicode -_ :: uuid -_ :: uuid_legacy -_ :: utf8 -_ :: utf8string -_ :: utf16 +main :: proc() {} \ No newline at end of file diff --git a/examples/all/all_posix.odin b/examples/all/all_posix.odin index 61b33a5c6..3e05f74ff 100644 --- a/examples/all/all_posix.odin +++ b/examples/all/all_posix.odin @@ -1,8 +1,5 @@ #+build darwin, openbsd, freebsd, netbsd package all -import posix "core:sys/posix" -import kqueue "core:sys/kqueue" - -_ :: posix -_ :: kqueue +@(require) import "core:sys/posix" +@(require) import "core:sys/kqueue" \ No newline at end of file diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin index b224a3bbe..71bb6ef86 100644 --- a/examples/all/all_vendor.odin +++ b/examples/all/all_vendor.odin @@ -1,106 +1,51 @@ +#+build !js package all -import cgltf "vendor:cgltf" -// import commonmark "vendor:commonmark" -import ENet "vendor:ENet" -import exr "vendor:OpenEXRCore" -import ggpo "vendor:ggpo" -import gl "vendor:OpenGL" -import glfw "vendor:glfw" -import microui "vendor:microui" -import miniaudio "vendor:miniaudio" -import PM "vendor:portmidi" -import rl "vendor:raylib" -import zlib "vendor:zlib" +@(require) import "vendor:cgltf" +@(require) import "vendor:ENet" +@(require) import "vendor:OpenEXRCore" +@(require) import "vendor:ggpo" +@(require) import "vendor:OpenGL" +@(require) import "vendor:glfw" +@(require) import "vendor:microui" +@(require) import "vendor:miniaudio" +@(require) import "vendor:portmidi" +@(require) import "vendor:raylib" +@(require) import "vendor:zlib" -import SDL "vendor:sdl2" -import SDLNet "vendor:sdl2/net" -import IMG "vendor:sdl2/image" -import MIX "vendor:sdl2/mixer" -import TTF "vendor:sdl2/ttf" +@(require) import "vendor:sdl2" +@(require) import "vendor:sdl2/net" +@(require) import "vendor:sdl2/image" +@(require) import "vendor:sdl2/mixer" +@(require) import "vendor:sdl2/ttf" -import vk "vendor:vulkan" +@(require) import "vendor:vulkan" // NOTE(bill): only one can be checked at a time -import lua_5_4 "vendor:lua/5.4" - -import nvg "vendor:nanovg" -import nvg_gl "vendor:nanovg/gl" -import fontstash "vendor:fontstash" - -import xlib "vendor:x11/xlib" - -_ :: cgltf -// _ :: commonmark -_ :: ENet -_ :: exr -_ :: ggpo -_ :: gl -_ :: glfw -_ :: microui -_ :: miniaudio -_ :: PM -_ :: rl -_ :: zlib - -_ :: SDL -_ :: SDLNet -_ :: IMG -_ :: MIX -_ :: TTF - -_ :: vk - -_ :: lua_5_4 - -_ :: nvg -_ :: nvg_gl -_ :: fontstash - -_ :: xlib - +@(require) import lua54 "vendor:lua/5.4" +@(require) import "vendor:nanovg" +@(require) import "vendor:nanovg/gl" +@(require) import "vendor:fontstash" // NOTE: needed for doc generator +@(require) import "core:sys/darwin/Foundation" +@(require) import "core:sys/darwin/CoreFoundation" +@(require) import "core:sys/darwin/Security" +@(require) import "vendor:darwin/Metal" +@(require) import "vendor:darwin/MetalKit" +@(require) import "vendor:darwin/QuartzCore" -import NS "core:sys/darwin/Foundation" -import CF "core:sys/darwin/CoreFoundation" -import SEC "core:sys/darwin/Security" -import MTL "vendor:darwin/Metal" -import MTK "vendor:darwin/MetalKit" -import CA "vendor:darwin/QuartzCore" +@(require) import "vendor:directx/dxc" +@(require) import "vendor:directx/d3d11" +@(require) import "vendor:directx/d3d12" +@(require) import "vendor:directx/dxgi" +@(require) import "vendor:commonmark" -_ :: NS -_ :: CF -_ :: SEC -_ :: MTL -_ :: MTK -_ :: CA +@(require) import "vendor:stb/easy_font" +@(require) import stbi "vendor:stb/image" +@(require) import "vendor:stb/rect_pack" +@(require) import "vendor:stb/truetype" +@(require) import "vendor:stb/vorbis" -import DXC "vendor:directx/dxc" -import D3D11 "vendor:directx/d3d11" -import D3D12 "vendor:directx/d3d12" -import DXGI "vendor:directx/dxgi" - -_ :: DXC -_ :: D3D11 -_ :: D3D12 -_ :: DXGI - - -import cm "vendor:commonmark" -_ :: cm - - -import stb_easy_font "vendor:stb/easy_font" -import stbi "vendor:stb/image" -import stbrp "vendor:stb/rect_pack" -import stbtt "vendor:stb/truetype" -import stb_vorbis "vendor:stb/vorbis" - -_ :: stb_easy_font -_ :: stbi -_ :: stbrp -_ :: stbtt -_ :: stb_vorbis - +@(require) import "vendor:kb_text_shape" diff --git a/examples/all/all_vendor_js.odin b/examples/all/all_vendor_js.odin new file mode 100644 index 000000000..d7975541d --- /dev/null +++ b/examples/all/all_vendor_js.odin @@ -0,0 +1,13 @@ +#+build js +package all + +@(require) import "vendor:box2d" +@(require) import "vendor:cgltf" +@(require) import "vendor:fontstash" +@(require) import "vendor:microui" +@(require) import "vendor:stb/easy_font" +@(require) import "vendor:stb/image" +@(require) import "vendor:stb/rect_pack" +@(require) import "vendor:stb/truetype" +@(require) import "vendor:wgpu" +@(require) import "vendor:wasm/WebGL" \ No newline at end of file diff --git a/examples/all/all_vendor_windows.odin b/examples/all/all_vendor_windows.odin index 5087bac07..b71b69a5a 100644 --- a/examples/all/all_vendor_windows.odin +++ b/examples/all/all_vendor_windows.odin @@ -1,10 +1,9 @@ +#+build windows package all -import wgpu "vendor:wgpu" -import b2 "vendor:box2d" -import game_input "vendor:windows/GameInput" - -_ :: wgpu -_ :: b2 -_ :: game_input - +@(require) import "vendor:wgpu/glfwglue" +@(require) import "vendor:wgpu/sdl2glue" +@(require) import "vendor:wgpu" +@(require) import "vendor:box2d" +@(require) import "vendor:windows/GameInput" +@(require) import "vendor:windows/XAudio2" \ No newline at end of file diff --git a/examples/all/sdl3/all_sdl3.odin b/examples/all/sdl3/all_sdl3.odin new file mode 100644 index 000000000..550275af0 --- /dev/null +++ b/examples/all/sdl3/all_sdl3.odin @@ -0,0 +1,13 @@ +/* +Imports all packages using SDL3, can't go in the parent directory +because SDL2 and SDL3 will have naming conflicts. +*/ +package all_sdl3 + +import SDL "vendor:sdl3" +import IMG "vendor:sdl3/image" +import TTF "vendor:sdl3/ttf" + +_ :: SDL +_ :: IMG +_ :: TTF diff --git a/examples/all/sdl3/all_sdl3_windows.odin b/examples/all/sdl3/all_sdl3_windows.odin new file mode 100644 index 000000000..28a0fec90 --- /dev/null +++ b/examples/all/sdl3/all_sdl3_windows.odin @@ -0,0 +1,5 @@ +package all_sdl3 + +import wgpu_sdl3_glue "vendor:wgpu/sdl3glue" + +_ :: wgpu_sdl3_glue diff --git a/misc/get-date.c b/misc/get-date.c index bf5b32738..b3eb1be78 100644 --- a/misc/get-date.c +++ b/misc/get-date.c @@ -9,5 +9,5 @@ int main(int arg_count, char const **arg_ptr) { time_t t = time(NULL); struct tm* now = localtime(&t); - printf("%04d%02d%02d", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday); + printf("%04d-%02d-%02d", now->tm_year + 1900, now->tm_mon + 1, now->tm_mday); } \ No newline at end of file diff --git a/shell.nix b/shell.nix index 040c7696e..33e90018c 100644 --- a/shell.nix +++ b/shell.nix @@ -4,9 +4,9 @@ pkgs.mkShell { nativeBuildInputs = with pkgs; [ git which - clang_17 - llvmPackages_17.llvm - llvmPackages_17.bintools + clang_20 + llvmPackages_20.llvm + llvmPackages_20.bintools ]; shellHook="CXX=clang++"; } diff --git a/src/bug_report.cpp b/src/bug_report.cpp index c44c4be33..98a376895 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -527,7 +527,7 @@ gb_internal void report_os_info() { #elif defined(GB_SYSTEM_OSX) gbString sw_vers = gb_string_make(heap_allocator(), ""); - if (!system_exec_command_line_app_output("sw_vers --productVersion", &sw_vers)) { + if (!system_exec_command_line_app_output("sw_vers -productVersion", &sw_vers)) { gb_printf("macOS Unknown\n"); return; } @@ -540,6 +540,7 @@ gb_internal void report_os_info() { } switch (major) { + case 26: gb_printf("macOS Tahoe"); break; case 15: gb_printf("macOS Sequoia"); break; case 14: gb_printf("macOS Sonoma"); break; case 13: gb_printf("macOS Ventura"); break; @@ -667,8 +668,14 @@ gb_internal void print_bug_report_help() { gb_printf("-nightly"); #endif + String version = {}; + #ifdef GIT_SHA - gb_printf(":%s", GIT_SHA); + version.text = cast(u8 *)GIT_SHA; + version.len = gb_strlen(GIT_SHA); + if (version != "") { + gb_printf(":%.*s", LIT(version)); + } #endif gb_printf("\n"); diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 08df34c57..53953600e 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -31,6 +31,24 @@ enum TargetOsKind : u16 { TargetOs_COUNT, }; +gb_global String target_os_names[TargetOs_COUNT] = { + str_lit(""), + str_lit("windows"), + str_lit("darwin"), + str_lit("linux"), + str_lit("essence"), + str_lit("freebsd"), + str_lit("openbsd"), + str_lit("netbsd"), + str_lit("haiku"), + + str_lit("wasi"), + str_lit("js"), + str_lit("orca"), + + str_lit("freestanding"), +}; + enum TargetArchKind : u16 { TargetArch_Invalid, @@ -45,6 +63,17 @@ enum TargetArchKind : u16 { TargetArch_COUNT, }; +gb_global String target_arch_names[TargetArch_COUNT] = { + str_lit(""), + str_lit("amd64"), + str_lit("i386"), + str_lit("arm32"), + str_lit("arm64"), + str_lit("wasm32"), + str_lit("wasm64p32"), + str_lit("riscv64"), +}; + enum TargetEndianKind : u8 { TargetEndian_Little, TargetEndian_Big, @@ -52,6 +81,11 @@ enum TargetEndianKind : u8 { TargetEndian_COUNT, }; +gb_global String target_endian_names[TargetEndian_COUNT] = { + str_lit("little"), + str_lit("big"), +}; + enum TargetABIKind : u16 { TargetABI_Default, @@ -61,7 +95,14 @@ enum TargetABIKind : u16 { TargetABI_COUNT, }; +gb_global String target_abi_names[TargetABI_COUNT] = { + str_lit(""), + str_lit("win64"), + str_lit("sysv"), +}; + enum Windows_Subsystem : u8 { + Windows_Subsystem_UNKNOWN, Windows_Subsystem_BOOT_APPLICATION, Windows_Subsystem_CONSOLE, // Default, Windows_Subsystem_EFI_APPLICATION, @@ -75,53 +116,32 @@ enum Windows_Subsystem : u8 { Windows_Subsystem_COUNT, }; +gb_global String windows_subsystem_names[Windows_Subsystem_COUNT] = { + str_lit(""), + str_lit("BOOT_APPLICATION"), + str_lit("CONSOLE"), // Default + str_lit("EFI_APPLICATION"), + str_lit("EFI_BOOT_SERVICE_DRIVER"), + str_lit("EFI_ROM"), + str_lit("EFI_RUNTIME_DRIVER"), + str_lit("NATIVE"), + str_lit("POSIX"), + str_lit("WINDOWS"), + str_lit("WINDOWSCE"), +}; + struct MicroarchFeatureList { String microarch; String features; }; -gb_global String target_os_names[TargetOs_COUNT] = { - str_lit(""), - str_lit("windows"), - str_lit("darwin"), - str_lit("linux"), - str_lit("essence"), - str_lit("freebsd"), - str_lit("openbsd"), - str_lit("netbsd"), - str_lit("haiku"), - - str_lit("wasi"), - str_lit("js"), - str_lit("orca"), - - str_lit("freestanding"), -}; - -gb_global String target_arch_names[TargetArch_COUNT] = { - str_lit(""), - str_lit("amd64"), - str_lit("i386"), - str_lit("arm32"), - str_lit("arm64"), - str_lit("wasm32"), - str_lit("wasm64p32"), - str_lit("riscv64"), -}; - +#if defined(GB_SYSTEM_WINDOWS) + #include +#else + #include +#endif #include "build_settings_microarch.cpp" -gb_global String target_endian_names[TargetEndian_COUNT] = { - str_lit("little"), - str_lit("big"), -}; - -gb_global String target_abi_names[TargetABI_COUNT] = { - str_lit(""), - str_lit("win64"), - str_lit("sysv"), -}; - gb_global TargetEndianKind target_endians[TargetArch_COUNT] = { TargetEndian_Little, TargetEndian_Little, @@ -132,19 +152,6 @@ gb_global TargetEndianKind target_endians[TargetArch_COUNT] = { TargetEndian_Little, }; -gb_global String windows_subsystem_names[Windows_Subsystem_COUNT] = { - str_lit("BOOT_APPLICATION"), - str_lit("CONSOLE"), // Default - str_lit("EFI_APPLICATION"), - str_lit("EFI_BOOT_SERVICE_DRIVER"), - str_lit("EFI_ROM"), - str_lit("EFI_RUNTIME_DRIVER"), - str_lit("NATIVE"), - str_lit("POSIX"), - str_lit("WINDOWS"), - str_lit("WINDOWSCE"), -}; - #ifndef ODIN_VERSION_RAW #define ODIN_VERSION_RAW "dev-unknown-unknown" #endif @@ -164,14 +171,19 @@ struct TargetMetrics { enum Subtarget : u32 { Subtarget_Default, - Subtarget_iOS, - + Subtarget_iPhone, + Subtarget_iPhoneSimulator, + Subtarget_Android, + Subtarget_COUNT, + Subtarget_Invalid, // NOTE(harold): Must appear after _COUNT as this is not a real subtarget }; gb_global String subtarget_strings[Subtarget_COUNT] = { str_lit(""), - str_lit("ios"), + str_lit("iphone"), + str_lit("iphonesimulator"), + str_lit("android"), }; @@ -198,20 +210,25 @@ enum BuildModeKind { BuildMode_COUNT, }; -enum CommandKind : u32 { +enum CommandKind : u64 { Command_run = 1<<0, Command_build = 1<<1, - Command_check = 1<<3, - Command_doc = 1<<5, - Command_version = 1<<6, - Command_test = 1<<7, + Command_check = 1<<2, + Command_doc = 1<<3, + Command_version = 1<<4, + Command_test = 1<<5, - Command_strip_semicolon = 1<<8, - Command_bug_report = 1<<9, + Command_strip_semicolon = 1<<6, + Command_bug_report = 1<<7, + + Command_bundle_android = 1<<8, + Command_bundle_macos = 1<<9, + Command_bundle_ios = 1<<10, + Command_bundle_orca = 1<<11, Command__does_check = Command_run|Command_build|Command_check|Command_doc|Command_test|Command_strip_semicolon, Command__does_build = Command_run|Command_build|Command_test, - Command_all = ~(u32)0, + Command_all = ~(CommandKind)0, }; gb_global char const *odin_command_strings[32] = { @@ -222,6 +239,11 @@ gb_global char const *odin_command_strings[32] = { "version", "test", "strip-semicolon", + "", + "bundle android", + "bundle macos", + "bundle ios", + "bundle orca", }; @@ -269,7 +291,7 @@ enum BuildPath : u8 { BuildPath_VS_LIB, // vs_library_path BuildPath_Output, // Output Path for .exe, .dll, .so, etc. Can be overridden with `-out:`. - BuildPath_PDB, // Output Path for .pdb file, can be overridden with `-pdb-name:`. + BuildPath_Symbols, // Output Path for .pdb or .dSym file, can be overridden with `-pdb-name:`. BuildPathCOUNT, }; @@ -287,6 +309,7 @@ enum VetFlags : u64 { VetFlag_Cast = 1u<<8, VetFlag_Tabs = 1u<<9, VetFlag_UnusedProcedures = 1u<<10, + VetFlag_ExplicitAllocators = 1u<<11, VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports, @@ -320,6 +343,8 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_Tabs; } else if (name == "unused-procedures") { return VetFlag_UnusedProcedures; + } else if (name == "explicit-allocators") { + return VetFlag_ExplicitAllocators; } return VetFlag_NONE; } @@ -327,12 +352,43 @@ u64 get_vet_flag_from_name(String const &name) { enum OptInFeatureFlags : u64 { OptInFeatureFlag_NONE = 0, OptInFeatureFlag_DynamicLiterals = 1u<<0, + + OptInFeatureFlag_GlobalContext = 1u<<1, + + OptInFeatureFlag_IntegerDivisionByZero_Trap = 1u<<2, + OptInFeatureFlag_IntegerDivisionByZero_Zero = 1u<<3, + OptInFeatureFlag_IntegerDivisionByZero_Self = 1u<<4, + OptInFeatureFlag_IntegerDivisionByZero_AllBits = 1u<<5, + + + OptInFeatureFlag_IntegerDivisionByZero_ALL = OptInFeatureFlag_IntegerDivisionByZero_Trap| + OptInFeatureFlag_IntegerDivisionByZero_Zero| + OptInFeatureFlag_IntegerDivisionByZero_Self| + OptInFeatureFlag_IntegerDivisionByZero_AllBits, + }; u64 get_feature_flag_from_name(String const &name) { if (name == "dynamic-literals") { return OptInFeatureFlag_DynamicLiterals; } + if (name == "integer-division-by-zero:trap") { + return OptInFeatureFlag_IntegerDivisionByZero_Trap; + } + if (name == "integer-division-by-zero:zero") { + return OptInFeatureFlag_IntegerDivisionByZero_Zero; + } + if (name == "integer-division-by-zero:self") { + return OptInFeatureFlag_IntegerDivisionByZero_Self; + } + if (name == "integer-division-by-zero:all-bits") { + return OptInFeatureFlag_IntegerDivisionByZero_AllBits; + } + + + if (name == "global-context") { + return OptInFeatureFlag_GlobalContext; + } return OptInFeatureFlag_NONE; } @@ -362,30 +418,46 @@ enum LinkerChoice : i32 { Linker_Default = 0, Linker_lld, Linker_radlink, + Linker_mold, Linker_COUNT, }; +enum SourceCodeLocationInfo : u8 { + SourceCodeLocationInfo_Normal = 0, + SourceCodeLocationInfo_Obfuscated = 1, + SourceCodeLocationInfo_Filename = 2, + SourceCodeLocationInfo_None = 3, +}; + String linker_choices[Linker_COUNT] = { str_lit("default"), str_lit("lld"), str_lit("radlink"), + str_lit("mold"), +}; + +enum IntegerDivisionByZeroKind : u8 { + IntegerDivisionByZero_Trap, + IntegerDivisionByZero_Zero, + IntegerDivisionByZero_Self, + IntegerDivisionByZero_AllBits, }; // This stores the information for the specify architecture of this build struct BuildContext { // Constants - String ODIN_OS; // Target operating system - String ODIN_ARCH; // Target architecture - String ODIN_VENDOR; // Compiler vendor - String ODIN_VERSION; // Compiler version - String ODIN_ROOT; // Odin ROOT - String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name - String ODIN_WINDOWS_SUBSYSTEM; // Empty string for non-Windows targets - bool ODIN_DEBUG; // Odin in debug mode - bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not - bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing) - bool ODIN_DEFAULT_TO_PANIC_ALLOCATOR; // Whether the default allocator is a "panic" allocator or not (i.e. panics on any call to it) + String ODIN_OS; // Target operating system + String ODIN_ARCH; // Target architecture + String ODIN_VENDOR; // Compiler vendor + String ODIN_VERSION; // Compiler version + String ODIN_ROOT; // Odin ROOT + String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name + Windows_Subsystem ODIN_WINDOWS_SUBSYSTEM; // .Console, .Windows + bool ODIN_DEBUG; // Odin in debug mode + bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not + bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing) + bool ODIN_DEFAULT_TO_PANIC_ALLOCATOR; // Whether the default allocator is a "panic" allocator or not (i.e. panics on any call to it) bool ODIN_FOREIGN_ERROR_PROCEDURES; bool ODIN_VALGRIND_SUPPORT; @@ -423,6 +495,7 @@ struct BuildContext { String extra_assembler_flags; String microarch; BuildModeKind build_mode; + bool keep_executable; bool generate_docs; bool custom_optimization_level; i32 optimization_level; @@ -441,6 +514,7 @@ struct BuildContext { bool ignore_unknown_attributes; bool no_bounds_check; bool no_type_assert; + bool dynamic_literals; // Opt-in to `#+feature dynamic-literals` project-wide. bool no_output_files; bool no_crt; bool no_rpath; @@ -451,6 +525,8 @@ struct BuildContext { bool keep_object_files; bool disallow_do; + IntegerDivisionByZeroKind integer_division_by_zero_behaviour; + LinkerChoice linker_choice; StringSet custom_attributes; @@ -472,6 +548,8 @@ struct BuildContext { bool ignore_microsoft_magic; bool linker_map_file; + bool build_diagnostics; + bool use_single_module; bool use_separate_modules; bool module_per_file; @@ -480,6 +558,8 @@ struct BuildContext { bool internal_no_inline; bool internal_by_value; + bool internal_weak_monomorphization; + bool internal_ignore_llvm_verification; bool no_threaded_checker; @@ -491,7 +571,7 @@ struct BuildContext { bool dynamic_map_calls; - bool obfuscate_source_code_locations; + SourceCodeLocationInfo source_code_location_info; bool min_link_libs; @@ -521,6 +601,21 @@ struct BuildContext { String minimum_os_version_string; bool minimum_os_version_string_given; + + + int ODIN_ANDROID_API_LEVEL; + + String ODIN_ANDROID_SDK; + + String ODIN_ANDROID_NDK; + String ODIN_ANDROID_NDK_TOOLCHAIN; + String ODIN_ANDROID_NDK_TOOLCHAIN_LIB; + String ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL; + String ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT; + + String android_keystore; + String android_keystore_alias; + String android_keystore_password; }; gb_global BuildContext build_context = {0}; @@ -544,12 +639,6 @@ gb_internal isize MAX_ERROR_COLLECTOR_COUNT(void) { return build_context.max_error_count; } -#if defined(GB_SYSTEM_WINDOWS) - #include -#else - #include -#endif - // NOTE: AMD64 targets had their alignment on 128 bit ints bumped from 8 to 16 (undocumented of course). #if LLVM_VERSION_MAJOR >= 18 #define AMD64_MAX_ALIGNMENT 16 @@ -820,13 +909,47 @@ gb_global NamedTargetMetrics *selected_target_metrics; gb_global Subtarget selected_subtarget; -gb_internal TargetOsKind get_target_os_from_string(String str) { +gb_internal TargetOsKind get_target_os_from_string(String str, Subtarget *subtarget_ = nullptr, String *subtarget_str = nullptr) { + String os_name = str; + String subtarget = {}; + auto part = string_partition(str, str_lit(":")); + if (part.match.len == 1) { + os_name = part.head; + subtarget = part.tail; + } + + TargetOsKind kind = TargetOs_Invalid; + for (isize i = 0; i < TargetOs_COUNT; i++) { - if (str_eq_ignore_case(target_os_names[i], str)) { - return cast(TargetOsKind)i; + if (str_eq_ignore_case(target_os_names[i], os_name)) { + kind = cast(TargetOsKind)i; + break; } } - return TargetOs_Invalid; + + if (subtarget_str) *subtarget_str = subtarget; + + if (subtarget_) { + if (subtarget.len != 0) { + *subtarget_ = Subtarget_Invalid; + + if (str_eq_ignore_case(subtarget, "generic") || str_eq_ignore_case(subtarget, "default")) { + *subtarget_ = Subtarget_Default; + + } else { + for (isize i = 1; i < Subtarget_COUNT; i++) { + if (str_eq_ignore_case(subtarget_strings[i], subtarget)) { + *subtarget_ = cast(Subtarget)i; + break; + } + } + } + } else { + *subtarget_ = Subtarget_Default; + } + } + + return kind; } gb_internal TargetArchKind get_target_arch_from_string(String str) { @@ -847,14 +970,6 @@ gb_internal bool is_excluded_target_filename(String name) { return true; } - if (build_context.command_kind != Command_test) { - String test_suffix = str_lit("_test"); - if (string_ends_with(name, test_suffix) && name != test_suffix) { - // Ignore *_test.odin files - return true; - } - } - String str1 = {}; String str2 = {}; isize n = 0; @@ -946,6 +1061,14 @@ gb_internal bool is_arch_x86(void) { gb_global String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1}; gb_global String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; +gb_global String const SEPARATOR_STRING = +#if defined(GB_SYSTEM_WINDOWS) + WIN32_SEPARATOR_STRING; +#else + NIX_SEPARATOR_STRING; +#endif + + gb_global String const WASM_MODULE_NAME_SEPARATOR = str_lit(".."); gb_internal String internal_odin_root_dir(void); @@ -1001,10 +1124,10 @@ gb_internal String internal_odin_root_dir(void) { mutex_lock(&string_buffer_mutex); defer (mutex_unlock(&string_buffer_mutex)); - text = gb_alloc_array(permanent_allocator(), wchar_t, len+1); + text = permanent_alloc_array(len+1); GetModuleFileNameW(nullptr, text, cast(int)len); - path = string16_to_string(heap_allocator(), make_string16(text, len)); + path = string16_to_string(heap_allocator(), make_string16(cast(u16 *)text, len)); for (i = path.len-1; i >= 0; i--) { u8 c = path[i]; @@ -1038,8 +1161,8 @@ gb_internal String internal_odin_root_dir(void) { return global_module_path; } - auto path_buf = array_make(heap_allocator(), 300); - defer (array_free(&path_buf)); + TEMPORARY_ALLOCATOR_GUARD(); + auto path_buf = array_make(temporary_allocator(), 300); len = 0; for (;;) { @@ -1056,7 +1179,7 @@ gb_internal String internal_odin_root_dir(void) { mutex_lock(&string_buffer_mutex); defer (mutex_unlock(&string_buffer_mutex)); - text = gb_alloc_array(permanent_allocator(), u8, len + 1); + text = permanent_alloc_array(len + 1); gb_memmove(text, &path_buf[0], len); path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr); @@ -1108,7 +1231,7 @@ gb_internal String internal_odin_root_dir(void) { mutex_lock(&string_buffer_mutex); defer (mutex_unlock(&string_buffer_mutex)); - text = gb_alloc_array(permanent_allocator(), u8, len + 1); + text = permanent_alloc_array(len + 1); gb_memmove(text, &path_buf[0], len); path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr); @@ -1269,7 +1392,7 @@ gb_internal String internal_odin_root_dir(void) { mutex_lock(&string_buffer_mutex); defer (mutex_unlock(&string_buffer_mutex)); - text = gb_alloc_array(permanent_allocator(), u8, len + 1); + text = permanent_alloc_array(len + 1); gb_memmove(text, &path_buf[0], len); @@ -1302,14 +1425,14 @@ gb_internal String path_to_fullpath(gbAllocator a, String s, bool *ok_) { mutex_lock(&fullpath_mutex); - len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr); + len = GetFullPathNameW(cast(wchar_t *)&string16[0], 0, nullptr, nullptr); if (len != 0) { - wchar_t *text = gb_alloc_array(permanent_allocator(), wchar_t, len+1); - GetFullPathNameW(&string16[0], len, text, nullptr); + wchar_t *text = permanent_alloc_array(len+1); + GetFullPathNameW(cast(wchar_t *)&string16[0], len, text, nullptr); mutex_unlock(&fullpath_mutex); text[len] = 0; - result = string16_to_string(a, make_string16(text, len)); + result = string16_to_string(a, make_string16(cast(u16 *)text, len)); result = string_trim_whitespace(result); // Replace Windows style separators @@ -1461,6 +1584,94 @@ gb_internal bool has_ansi_terminal_colours(void) { return build_context.has_ansi_terminal_colours && !json_errors(); } +gb_internal void init_android_values(bool with_sdk) { + auto *bc = &build_context; + { // Android SDK/API Level + String default_level = str_lit("34"); + if (!bc->minimum_os_version_string_given) { + bc->minimum_os_version_string = default_level; + } + BigInt level = {}; + bool success = false; + big_int_from_string(&level, bc->minimum_os_version_string, &success); + if (!success) { + gb_printf_err("Warning: Invalid -minimum-os-version:%.*s for -subtarget:Android, defaulting to %.*s\n", LIT(bc->minimum_os_version_string), LIT(default_level)); + bc->minimum_os_version_string = default_level; + big_int_from_string(&level, bc->minimum_os_version_string, &success); + GB_ASSERT(success); + } + + i64 new_level = big_int_to_i64(&level); + + if (new_level >= 21) { + bc->ODIN_ANDROID_API_LEVEL = cast(int)new_level; + } else { + gb_printf_err("Warning: Invalid -minimum-os-version:%.*s for -subtarget:Android, defaulting to %.*s\n", LIT(bc->minimum_os_version_string), LIT(default_level)); + bc->ODIN_ANDROID_API_LEVEL = atoi(cast(char const *)default_level.text); + } + } + bc->ODIN_ANDROID_NDK = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK", permanent_allocator())), NIX_SEPARATOR_STRING); + bc->ODIN_ANDROID_NDK_TOOLCHAIN = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_NDK_TOOLCHAIN", permanent_allocator())), NIX_SEPARATOR_STRING); + bc->ODIN_ANDROID_SDK = normalize_path(permanent_allocator(), make_string_c(gb_get_env("ODIN_ANDROID_SDK", permanent_allocator())), NIX_SEPARATOR_STRING); + + #if defined(GB_SYSTEM_WINDOWS) + if (bc->ODIN_ANDROID_SDK.len == 0) { + bc->ODIN_ANDROID_SDK = normalize_path(permanent_allocator(), + path_to_fullpath(permanent_allocator(), str_lit("%LocalAppData%/Android/Sdk"), nullptr), + NIX_SEPARATOR_STRING); + } + #endif + + if (bc->ODIN_ANDROID_NDK.len != 0 && bc->ODIN_ANDROID_NDK_TOOLCHAIN.len == 0) { + String arch = str_lit("x86_64"); + #if defined (GB_CPU_ARM) + // TODO(bill): this is a complete guess + arch = str_lit("aarch64"); + #endif + #if defined(GB_SYSTEM_WINDOWS) + bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("windows-"), arch); + #elif defined(GB_SYSTEM_OSX) + // TODO(bill): is this name even correct? + bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("darwin-"), arch); + #elif defined(GB_SYSTEM_LINUX) + bc->ODIN_ANDROID_NDK_TOOLCHAIN = concatenate4_strings(temporary_allocator(), bc->ODIN_ANDROID_NDK, str_lit("toolchains/llvm/prebuilt/"), str_lit("linux-"), arch); + #endif + + bc->ODIN_ANDROID_NDK_TOOLCHAIN = normalize_path(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, NIX_SEPARATOR_STRING); + } + + if (bc->ODIN_ANDROID_NDK.len == 0 && !with_sdk) { + gb_printf_err("Error: ODIN_ANDROID_NDK not set"); + gb_exit(1); + + } + + if (bc->ODIN_ANDROID_NDK_TOOLCHAIN.len == 0 && !with_sdk) { + gb_printf_err("Error: ODIN_ANDROID_NDK not set"); + gb_exit(1); + } + + bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/usr/lib/aarch64-linux-android/")); + + char buf[32] = {}; + gb_snprintf(buf, gb_size_of(buf), "%d/", bc->ODIN_ANDROID_API_LEVEL); + bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN_LIB, make_string_c(buf)); + + bc->ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT = concatenate_strings(permanent_allocator(), bc->ODIN_ANDROID_NDK_TOOLCHAIN, str_lit("sysroot/")); + + + if (with_sdk) { + if (bc->ODIN_ANDROID_SDK.len == 0) { + gb_printf_err("Error: ODIN_ANDROID_SDK not set, which is required for -build-mode:executable for -subtarget:android"); + gb_exit(1); + } + if (bc->android_keystore.len == 0) { + gb_printf_err("Error: -android-keystore: has not been set\n"); + gb_exit(1); + } + } +} + gb_internal bool has_asm_extension(String const &path) { String ext = path_extension(path); if (ext == ".asm") { @@ -1637,20 +1848,66 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta } // Default to subsystem:CONSOLE on Windows targets - if (bc->ODIN_WINDOWS_SUBSYSTEM == "" && bc->metrics.os == TargetOs_windows) { - bc->ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_CONSOLE]; + if (bc->ODIN_WINDOWS_SUBSYSTEM == Windows_Subsystem_UNKNOWN && bc->metrics.os == TargetOs_windows) { + bc->ODIN_WINDOWS_SUBSYSTEM = Windows_Subsystem_CONSOLE; } - if (metrics->os == TargetOs_darwin && subtarget == Subtarget_iOS) { - switch (metrics->arch) { - case TargetArch_arm64: - bc->metrics.target_triplet = str_lit("arm64-apple-ios"); - break; - case TargetArch_amd64: - bc->metrics.target_triplet = str_lit("x86_64-apple-ios"); + if (subtarget == Subtarget_Android) { + switch (build_context.build_mode) { + case BuildMode_DynamicLibrary: + case BuildMode_Object: + case BuildMode_Assembly: + case BuildMode_LLVM_IR: break; default: - GB_PANIC("Unknown architecture for darwin"); + case BuildMode_Executable: + case BuildMode_StaticLibrary: + if ((build_context.command_kind & Command__does_build) != 0) { + gb_printf_err("Unsupported -build-mode for -subtarget:android\n"); + gb_printf_err("\tCurrently only supporting: \n"); + // gb_printf_err("\t\texe\n"); + gb_printf_err("\t\tshared\n"); + gb_printf_err("\t\tobject\n"); + gb_printf_err("\t\tassembly\n"); + gb_printf_err("\t\tllvm-ir\n"); + gb_exit(1); + } + break; + } + } + + if (metrics->os == TargetOs_darwin) { + switch (subtarget) { + case Subtarget_iPhone: + switch (metrics->arch) { + case TargetArch_arm64: + bc->metrics.target_triplet = str_lit("arm64-apple-ios"); + break; + default: + GB_PANIC("Unknown architecture for -subtarget:iphone"); + } + break; + case Subtarget_iPhoneSimulator: + switch (metrics->arch) { + case TargetArch_arm64: + bc->metrics.target_triplet = str_lit("arm64-apple-ios-simulator"); + break; + case TargetArch_amd64: + bc->metrics.target_triplet = str_lit("x86_64-apple-ios-simulator"); + break; + default: + GB_PANIC("Unknown architecture for -subtarget:iphonesimulator"); + } + break; + } + } else if (metrics->os == TargetOs_linux && subtarget == Subtarget_Android) { + switch (metrics->arch) { + case TargetArch_arm64: + bc->metrics.target_triplet = str_lit("aarch64-none-linux-android"); + bc->reloc_mode = RelocMode_PIC; + break; + default: + GB_PANIC("Unknown architecture for -subtarget:android"); } } @@ -1668,6 +1925,13 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta str_lit("-target "), bc->metrics.target_triplet, str_lit(" ")); } else if (is_arch_wasm()) { gbString link_flags = gb_string_make(heap_allocator(), " "); + + // NOTE(laytan): Put the stack first in the memory, + // causing a stack overflow to error immediately instead of corrupting globals. + link_flags = gb_string_appendc(link_flags, "--stack-first "); + // NOTE(laytan): default stack size is 64KiB, up to a more reasonable 1MiB. + link_flags = gb_string_appendc(link_flags, "-z stack-size=1048576 "); + // link_flags = gb_string_appendc(link_flags, "--export-all "); // link_flags = gb_string_appendc(link_flags, "--export-table "); // if (bc->metrics.arch == TargetArch_wasm64) { @@ -1700,12 +1964,27 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta // does not annoy the user with version warnings. if (metrics->os == TargetOs_darwin) { if (!bc->minimum_os_version_string_given) { - bc->minimum_os_version_string = str_lit("11.0.0"); + if (subtarget == Subtarget_Default) { + bc->minimum_os_version_string = str_lit("11.0.0"); + } else if (subtarget == Subtarget_iPhone || subtarget == Subtarget_iPhoneSimulator) { + // NOTE(harold): We default to 17.4 on iOS because that's when os_sync_wait_on_address was added and + // we'd like to avoid any potential App Store issues by using the private ulock_* there. + bc->minimum_os_version_string = str_lit("17.4"); + } } - if (subtarget == Subtarget_Default) { + if (subtarget == Subtarget_iPhoneSimulator) { + // For the iPhoneSimulator subtarget, the version must be between 'ios' and '-simulator'. + String suffix = str_lit("-simulator"); + GB_ASSERT(string_ends_with(bc->metrics.target_triplet, suffix)); + + String prefix = substring(bc->metrics.target_triplet, 0, bc->metrics.target_triplet.len - suffix.len); + bc->metrics.target_triplet = concatenate3_strings(permanent_allocator(), prefix, bc->minimum_os_version_string, suffix); + } else { bc->metrics.target_triplet = concatenate_strings(permanent_allocator(), bc->metrics.target_triplet, bc->minimum_os_version_string); } + } else if (selected_subtarget == Subtarget_Android) { + init_android_values(bc->build_mode == BuildMode_Executable && (bc->command_kind & Command__does_build) != 0); } if (!bc->custom_optimization_level) { @@ -1731,12 +2010,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta } - // TODO: Static map calls are bugged on `amd64sysv` abi. - if (bc->metrics.os != TargetOs_windows && bc->metrics.arch == TargetArch_amd64) { - // ENFORCE DYNAMIC MAP CALLS - bc->dynamic_map_calls = true; - } - bc->ODIN_VALGRIND_SUPPORT = false; if (build_context.metrics.os != TargetOs_windows) { switch (bc->metrics.arch) { @@ -1842,6 +2115,39 @@ gb_internal bool check_target_feature_is_superset_of(String const &superset, Str return true; } +gb_internal String infer_object_extension_from_build_context() { + String output_extension = {}; + if (is_arch_wasm()) { + output_extension = STR_LIT("wasm.o"); + } else { + switch (build_context.metrics.os) { + case TargetOs_windows: + output_extension = STR_LIT("obj"); + break; + default: + case TargetOs_darwin: + case TargetOs_linux: + case TargetOs_essence: + output_extension = STR_LIT("o"); + break; + + case TargetOs_freestanding: + switch (build_context.metrics.abi) { + default: + case TargetABI_Default: + case TargetABI_SysV: + output_extension = STR_LIT("o"); + break; + case TargetABI_Win64: + output_extension = STR_LIT("obj"); + break; + } + break; + } + } + return output_extension; +} + // NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate. // We've previously called `parse_build_flags`, so `out_filepath` should be set. gb_internal bool init_build_paths(String init_filename) { @@ -1885,10 +2191,6 @@ gb_internal bool init_build_paths(String init_filename) { } } - if (bc->pdb_filepath.len > 0) { - bc->build_paths[BuildPath_PDB] = path_from_string(ha, bc->pdb_filepath); - } - if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) { // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. Find_Result find_result = find_visual_studio_and_windows_sdk(); @@ -1947,7 +2249,10 @@ gb_internal bool init_build_paths(String init_filename) { output_extension = make_string(nullptr, 0); String const single_file_extension = str_lit(".odin"); - if (build_context.metrics.os == TargetOs_windows) { + if (selected_subtarget == Subtarget_Android) { + // NOTE(bill): It's always shared! + output_extension = STR_LIT("so"); + } else if (build_context.metrics.os == TargetOs_windows) { output_extension = STR_LIT("exe"); } else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { // Do nothing: we don't want the .bin extension @@ -1975,13 +2280,8 @@ gb_internal bool init_build_paths(String init_filename) { if (build_context.metrics.os == TargetOs_windows) { output_extension = STR_LIT("lib"); } - }else if (build_context.build_mode == BuildMode_Object) { - // By default use a .o object extension. - output_extension = STR_LIT("o"); - - if (build_context.metrics.os == TargetOs_windows) { - output_extension = STR_LIT("obj"); - } + } else if (build_context.build_mode == BuildMode_Object) { + output_extension = infer_object_extension_from_build_context(); } else if (build_context.build_mode == BuildMode_Assembly) { // By default use a .S asm extension. output_extension = STR_LIT("S"); @@ -2001,7 +2301,7 @@ gb_internal bool init_build_paths(String init_filename) { return false; } else if (bc->build_paths[BuildPath_Output].ext.len == 0) { gb_printf_err("Output path %.*s must have an appropriate extension.\n", LIT(output_file)); - return false; + return false; } } } else { @@ -2027,11 +2327,34 @@ gb_internal bool init_build_paths(String init_filename) { while (output_name.len > 0 && (output_name[output_name.len-1] == '/' || output_name[output_name.len-1] == '\\')) { output_name.len -= 1; } + // Only trim the extension if it's an Odin source file. + // This lets people build folders with extensions or files beginning with dots. + if (path_extension(output_name) == ".odin" && !path_is_directory(output_name)) { + output_name = remove_extension_from_path(output_name); + } output_name = remove_directory_from_path(output_name); - output_name = remove_extension_from_path(output_name); output_name = copy_string(ha, string_trim_whitespace(output_name)); - output_path = path_from_string(ha, output_name); - + // This is `path_from_string` without the extension trimming. + Path res = {}; + if (output_name.len > 0) { + String fullpath = path_to_full_path(ha, output_name); + defer (gb_free(ha, fullpath.text)); + + res.basename = directory_from_path(fullpath); + res.basename = copy_string(ha, res.basename); + + if (path_is_directory(fullpath)) { + if (res.basename.len > 0 && res.basename.text[res.basename.len - 1] == '/') { + res.basename.len--; + } + } else { + isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len; + res.name = substring(fullpath, name_start, fullpath.len); + res.name = copy_string(ha, res.name); + } + } + output_path = res; + // Note(Dragos): This is a fix for empty filenames // Turn the trailing folder into the file name if (output_path.name.len == 0) { @@ -2061,6 +2384,26 @@ gb_internal bool init_build_paths(String init_filename) { bc->build_paths[BuildPath_Output] = output_path; } + if (build_context.ODIN_DEBUG) { + if (build_context.metrics.os == TargetOs_windows) { + if (bc->pdb_filepath.len > 0) { + bc->build_paths[BuildPath_Symbols] = path_from_string(ha, bc->pdb_filepath); + } else { + Path symbol_path; + symbol_path.basename = copy_string(ha, bc->build_paths[BuildPath_Output].basename); + symbol_path.name = copy_string(ha, bc->build_paths[BuildPath_Output].name); + symbol_path.ext = copy_string(ha, STR_LIT("pdb")); + bc->build_paths[BuildPath_Symbols] = symbol_path; + } + } else if (build_context.metrics.os == TargetOs_darwin) { + Path symbol_path; + symbol_path.basename = copy_string(ha, bc->build_paths[BuildPath_Output].basename); + symbol_path.name = copy_string(ha, bc->build_paths[BuildPath_Output].name); + symbol_path.ext = copy_string(ha, STR_LIT("dSYM")); + bc->build_paths[BuildPath_Symbols] = symbol_path; + } + } + // Do we have an extension? We might not if the output filename was supplied. if (bc->build_paths[BuildPath_Output].ext.len == 0) { if (build_context.metrics.os == TargetOs_windows || is_arch_wasm() || build_context.build_mode != BuildMode_Executable) { @@ -2096,9 +2439,10 @@ gb_internal bool init_build_paths(String init_filename) { case TargetOs_windows: case TargetOs_linux: case TargetOs_darwin: + case TargetOs_freebsd: break; default: - gb_printf_err("-sanitize:address is only supported on windows, linux, and darwin\n"); + gb_printf_err("-sanitize:address is only supported on Windows, Linux, Darwin, and FreeBSD\n"); return false; } } @@ -2106,12 +2450,10 @@ gb_internal bool init_build_paths(String init_filename) { if (build_context.sanitizer_flags & SanitizerFlag_Memory) { switch (build_context.metrics.os) { case TargetOs_linux: + case TargetOs_freebsd: break; default: - gb_printf_err("-sanitize:memory is only supported on linux\n"); - return false; - } - if (build_context.metrics.os != TargetOs_linux) { + gb_printf_err("-sanitize:memory is only supported on Linux and FreeBSD\n"); return false; } } @@ -2120,9 +2462,10 @@ gb_internal bool init_build_paths(String init_filename) { switch (build_context.metrics.os) { case TargetOs_linux: case TargetOs_darwin: + case TargetOs_freebsd: break; default: - gb_printf_err("-sanitize:thread is only supported on linux and darwin\n"); + gb_printf_err("-sanitize:thread is only supported on Linux, Darwin, and FreeBSD\n"); return false; } } diff --git a/src/build_settings_microarch.cpp b/src/build_settings_microarch.cpp index 8f64d4026..16fb2196f 100644 --- a/src/build_settings_microarch.cpp +++ b/src/build_settings_microarch.cpp @@ -1,3 +1,561 @@ +#ifndef LLVM_VERSION_MAJOR + #error "LLVM_VERSION_MAJOR is not defined!" +#endif + +#if LLVM_VERSION_MAJOR >= 20 +// Generated with the featuregen script in `misc/featuregen` +gb_global String target_microarch_list[TargetArch_COUNT] = { + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,diamondrapids,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,pantherlake,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4,znver5"), + // TargetArch_i386: + str_lit("alderlake,amdfam10,arrowlake,arrowlake-s,arrowlake_s,athlon,athlon-4,athlon-fx,athlon-mp,athlon-tbird,athlon-xp,athlon64,athlon64-sse3,atom,atom_sse4_2,atom_sse4_2_movbe,barcelona,bdver1,bdver2,bdver3,bdver4,bonnell,broadwell,btver1,btver2,c3,c3-2,cannonlake,cascadelake,clearwaterforest,cooperlake,core-avx-i,core-avx2,core2,core_2_duo_sse4_1,core_2_duo_ssse3,core_2nd_gen_avx,core_3rd_gen_avx,core_4th_gen_avx,core_4th_gen_avx_tsx,core_5th_gen_avx,core_5th_gen_avx_tsx,core_aes_pclmulqdq,core_i7_sse4_2,corei7,corei7-avx,diamondrapids,emeraldrapids,generic,geode,goldmont,goldmont-plus,goldmont_plus,gracemont,grandridge,graniterapids,graniterapids-d,graniterapids_d,haswell,i386,i486,i586,i686,icelake-client,icelake-server,icelake_client,icelake_server,ivybridge,k6,k6-2,k6-3,k8,k8-sse3,knl,knm,lakemont,lunarlake,meteorlake,mic_avx512,nehalem,nocona,opteron,opteron-sse3,pantherlake,penryn,pentium,pentium-m,pentium-mmx,pentium2,pentium3,pentium3m,pentium4,pentium4m,pentium_4,pentium_4_sse3,pentium_ii,pentium_iii,pentium_iii_no_xmm_regs,pentium_m,pentium_mmx,pentium_pro,pentiumpro,prescott,raptorlake,rocketlake,sandybridge,sapphirerapids,sierraforest,silvermont,skx,skylake,skylake-avx512,skylake_avx512,slm,tigerlake,tremont,westmere,winchip-c6,winchip2,x86-64,x86-64-v2,x86-64-v3,x86-64-v4,yonah,znver1,znver2,znver3,znver4,znver5"), + // TargetArch_arm32: + str_lit("arm1020e,arm1020t,arm1022e,arm10e,arm10tdmi,arm1136j-s,arm1136jf-s,arm1156t2-s,arm1156t2f-s,arm1176jz-s,arm1176jzf-s,arm710t,arm720t,arm7tdmi,arm7tdmi-s,arm8,arm810,arm9,arm920,arm920t,arm922t,arm926ej-s,arm940t,arm946e-s,arm966e-s,arm968e-s,arm9e,arm9tdmi,cortex-a12,cortex-a15,cortex-a17,cortex-a32,cortex-a35,cortex-a5,cortex-a510,cortex-a53,cortex-a55,cortex-a57,cortex-a7,cortex-a710,cortex-a72,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78ae,cortex-a78c,cortex-a8,cortex-a9,cortex-m0,cortex-m0plus,cortex-m1,cortex-m23,cortex-m3,cortex-m33,cortex-m35p,cortex-m4,cortex-m52,cortex-m55,cortex-m7,cortex-m85,cortex-r4,cortex-r4f,cortex-r5,cortex-r52,cortex-r52plus,cortex-r7,cortex-r8,cortex-x1,cortex-x1c,cyclone,ep9312,exynos-m3,exynos-m4,exynos-m5,generic,iwmmxt,krait,kryo,mpcore,mpcorenovfp,neoverse-n1,neoverse-n2,neoverse-v1,sc000,sc300,star-mc1,strongarm,strongarm110,strongarm1100,strongarm1110,swift,xscale"), + // TargetArch_arm64: + str_lit("a64fx,ampere1,ampere1a,ampere1b,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a7,apple-a8,apple-a9,apple-m1,apple-m2,apple-m3,apple-m4,apple-s4,apple-s5,carmel,cobalt-100,cortex-a34,cortex-a35,cortex-a510,cortex-a520,cortex-a520ae,cortex-a53,cortex-a55,cortex-a57,cortex-a65,cortex-a65ae,cortex-a710,cortex-a715,cortex-a72,cortex-a720,cortex-a720ae,cortex-a725,cortex-a73,cortex-a75,cortex-a76,cortex-a76ae,cortex-a77,cortex-a78,cortex-a78ae,cortex-a78c,cortex-r82,cortex-r82ae,cortex-x1,cortex-x1c,cortex-x2,cortex-x3,cortex-x4,cortex-x925,cyclone,exynos-m3,exynos-m4,exynos-m5,falkor,fujitsu-monaka,generic,grace,kryo,neoverse-512tvb,neoverse-e1,neoverse-n1,neoverse-n2,neoverse-n3,neoverse-v1,neoverse-v2,neoverse-v3,neoverse-v3ae,oryon-1,saphira,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tsv110"), + // TargetArch_wasm32: + str_lit("bleeding-edge,generic,lime1,mvp"), + // TargetArch_wasm64p32: + str_lit("bleeding-edge,generic,lime1,mvp"), + // TargetArch_riscv64: + str_lit("generic,generic-rv32,generic-rv64,mips-p8700,rocket,rocket-rv32,rocket-rv64,rp2350-hazard3,sifive-7-series,sifive-e20,sifive-e21,sifive-e24,sifive-e31,sifive-e34,sifive-e76,sifive-p450,sifive-p470,sifive-p550,sifive-p670,sifive-s21,sifive-s51,sifive-s54,sifive-s76,sifive-u54,sifive-u74,sifive-x280,spacemit-x60,syntacore-scr1-base,syntacore-scr1-max,syntacore-scr3-rv32,syntacore-scr3-rv64,syntacore-scr4-rv32,syntacore-scr4-rv64,syntacore-scr5-rv32,syntacore-scr5-rv64,syntacore-scr7,tt-ascalon-d8,veyron-v1,xiangshan-nanhu"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global String target_features_list[TargetArch_COUNT] = { + // TargetArch_Invalid: + str_lit(""), + // TargetArch_amd64: + str_lit("16bit-mode,32bit-mode,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-dpwssd,fast-gather,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,inline-asm-use-gpr32,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,mwaitx,ndd,nf,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves,zu"), + // TargetArch_i386: + str_lit("16bit-mode,32bit-mode,64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,branchfusion,ccmp,cf,cldemote,clflushopt,clwb,clzero,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-lzcnt-tzcnt,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-popcnt,false-deps-range,fast-11bytenop,fast-15bytenop,fast-7bytenop,fast-bextr,fast-dpwssd,fast-gather,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fast-vector-shift-masks,faster-shift-than-shuffle,fma,fma4,fsgsbase,fsrm,fxsr,gfni,harden-sls-ijmp,harden-sls-ret,hreset,idivl-to-divb,idivq-to-divl,inline-asm-use-gpr32,invpcid,kl,lea-sp,lea-uses-ag,lvi-cfi,lvi-load-hardening,lwp,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,mwaitx,ndd,nf,no-bypass-delay,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pad-short-functions,pclmul,pconfig,pku,popcnt,ppx,prefer-128-bit,prefer-256-bit,prefer-mask-registers,prefer-movmsk-over-vtest,prefer-no-gather,prefer-no-scatter,prefetchi,prfchw,ptwrite,push2pop2,raoint,rdpid,rdpru,rdrnd,rdseed,retpoline,retpoline-external-thunk,retpoline-indirect-branches,retpoline-indirect-calls,rtm,sahf,sbb-dep-breaking,serialize,seses,sgx,sha,sha512,shstk,slow-3ops-lea,slow-incdec,slow-lea,slow-pmaddwd,slow-pmulld,slow-shld,slow-two-mem-ops,slow-unaligned-mem-16,slow-unaligned-mem-32,sm3,sm4,soft-float,sse,sse-unaligned-mem,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tagged-globals,tbm,tsxldtrk,tuning-fast-imm-vector-shift,uintr,use-glm-div-sqrt-costs,use-slm-arith-costs,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,widekl,x87,xop,xsave,xsavec,xsaveopt,xsaves,zu"), + // TargetArch_arm32: + str_lit("32bit,8msecext,a12,a15,a17,a32,a35,a5,a53,a55,a57,a7,a72,a73,a75,a76,a77,a78c,a8,a9,aapcs-frame-chain,aclass,acquire-release,aes,armv4,armv4t,armv5t,armv5te,armv5tej,armv6,armv6-m,armv6j,armv6k,armv6kz,armv6s-m,armv6t2,armv7-a,armv7-m,armv7-r,armv7e-m,armv7k,armv7s,armv7ve,armv8-a,armv8-m.base,armv8-m.main,armv8-r,armv8.1-a,armv8.1-m.main,armv8.2-a,armv8.3-a,armv8.4-a,armv8.5-a,armv8.6-a,armv8.7-a,armv8.8-a,armv8.9-a,armv9-a,armv9.1-a,armv9.2-a,armv9.3-a,armv9.4-a,armv9.5-a,armv9.6-a,atomics-32,avoid-movs-shop,avoid-muls,avoid-partial-cpsr,bf16,big-endian-instructions,branch-align-64,cde,cdecp0,cdecp1,cdecp2,cdecp3,cdecp4,cdecp5,cdecp6,cdecp7,cheap-predicable-cpsr,clrbhb,cortex-a510,cortex-a710,cortex-a78,cortex-a78ae,cortex-x1,cortex-x1c,crc,crypto,d32,db,dfb,disable-postra-scheduler,dont-widen-vmovs,dotprod,dsp,execute-only,expand-fp-mlx,exynos,fix-cmse-cve-2021-35465,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpao,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hwdiv,hwdiv-arm,i8mm,iwmmxt,iwmmxt2,krait,kryo,lob,long-calls,loop-align,m3,m55,m7,m85,mclass,mp,muxed-units,mve,mve.fp,mve1beat,mve2beat,mve4beat,nacl-trap,neon,neon-fpmovs,neonfp,neoverse-v1,no-branch-predictor,no-bti-at-return-twice,no-movt,no-neg-immediates,noarm,nonpipelined-vfp,pacbti,perfmon,prefer-ishst,prefer-vmovsr,prof-unpr,r4,r5,r52,r52plus,r7,ras,rclass,read-tp-tpidrprw,read-tp-tpidruro,read-tp-tpidrurw,reserve-r9,ret-addr-stack,sb,sha2,slow-fp-brcc,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,soft-float,splat-vfp-neon,strict-align,swift,thumb-mode,thumb2,trustzone,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.1m.main,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8m,v8m.main,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9.6a,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align,vmlx-forwarding,vmlx-hazards,wide-stride-vfp,xscale,zcz"), + // TargetArch_arm64: + str_lit("CONTEXTIDREL2,a35,a510,a520,a520ae,a53,a55,a57,a64fx,a65,a710,a715,a72,a720,a720ae,a73,a75,a76,a77,a78,a78ae,a78c,addr-lsl-slow-14,aes,aggressive-fma,all,alternate-sextload-cvt-f32-pattern,altnzcv,alu-lsl-fast,am,ampere1,ampere1a,ampere1b,amvs,apple-a10,apple-a11,apple-a12,apple-a13,apple-a14,apple-a15,apple-a16,apple-a17,apple-a7,apple-m4,arith-bcc-fusion,arith-cbz-fusion,ascend-store-address,avoid-ldapur,balance-fp-ops,bf16,brbe,bti,call-saved-x10,call-saved-x11,call-saved-x12,call-saved-x13,call-saved-x14,call-saved-x15,call-saved-x18,call-saved-x8,call-saved-x9,carmel,ccdp,ccidx,ccpp,chk,clrbhb,cmp-bcc-fusion,cmpbr,complxnum,cortex-a725,cortex-r82,cortex-r82ae,cortex-x1,cortex-x2,cortex-x3,cortex-x4,cortex-x925,cpa,crc,crypto,cssc,d128,disable-latency-sched-heuristic,disable-ldp,disable-stp,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,exynos-cheap-as-move,exynosm3,exynosm4,f32mm,f64mm,f8f16mm,f8f32mm,falkor,faminmax,fgt,fix-cortex-a53-835769,flagm,fmv,force-32bit-jump-tables,fp-armv8,fp16fml,fp8,fp8dot2,fp8dot4,fp8fma,fpac,fprcvt,fptoint,fujitsu-monaka,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,gcs,harden-sls-blr,harden-sls-nocomdat,harden-sls-retbr,hbc,hcx,i8mm,ite,jsconv,kryo,ldp-aligned-only,lor,ls64,lse,lse128,lse2,lsfe,lsui,lut,mec,mops,mpam,mte,neon,neoverse512tvb,neoversee1,neoversen1,neoversen2,neoversen3,neoversev1,neoversev2,neoversev3,neoversev3AE,nmi,no-bti-at-return-twice,no-neg-immediates,no-sve-fp-ld1r,no-zcz-fp,nv,occmo,oryon-1,outline-atomics,pan,pan-rwv,pauth,pauth-lr,pcdphint,perfmon,pops,predictable-select-expensive,predres,prfm-slc-target,rand,ras,rasv2,rcpc,rcpc-immo,rcpc3,rdm,reserve-lr-for-ra,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x18,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x3,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x9,rme,saphira,sb,sel2,sha2,sha3,slow-misaligned-128store,slow-paired-128,slow-strqro-store,sm4,sme,sme-b16b16,sme-f16f16,sme-f64f64,sme-f8f16,sme-f8f32,sme-fa64,sme-i16i64,sme-lutv2,sme-mop4,sme-tmop,sme2,sme2p1,sme2p2,spe,spe-eef,specres2,specrestrict,ssbs,ssve-aes,ssve-bitperm,ssve-fp8dot2,ssve-fp8dot4,ssve-fp8fma,store-pair-suppress,stp-aligned-only,strict-align,sve,sve-aes,sve-aes2,sve-b16b16,sve-bfscale,sve-bitperm,sve-f16f32mm,sve2,sve2-aes,sve2-bitperm,sve2-sha3,sve2-sm4,sve2p1,sve2p2,tagged-globals,the,thunderx,thunderx2t99,thunderx3t110,thunderxt81,thunderxt83,thunderxt88,tlb-rmi,tlbiw,tme,tpidr-el1,tpidr-el2,tpidr-el3,tpidrro-el0,tracev8.4,trbe,tsv110,uaops,use-experimental-zeroing-pseudos,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,use-reciprocal-square-root,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8.9a,v8a,v8r,v9.1a,v9.2a,v9.3a,v9.4a,v9.5a,v9.6a,v9a,vh,wfxt,xs,zcm,zcz,zcz-fp-workaround,zcz-gp"), + // TargetArch_wasm32: + str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call,wide-arithmetic"), + // TargetArch_wasm64p32: + str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call,wide-arithmetic"), + // TargetArch_riscv64: + str_lit("32bit,64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,disable-latency-sched-heuristic,dlen-factor-2,e,experimental,experimental-rvm23u32,experimental-sdext,experimental-sdtrig,experimental-smctr,experimental-ssctr,experimental-svukte,experimental-xqcia,experimental-xqciac,experimental-xqcicli,experimental-xqcicm,experimental-xqcics,experimental-xqcicsr,experimental-xqciint,experimental-xqcilo,experimental-xqcilsm,experimental-xqcisls,experimental-zalasr,experimental-zicfilp,experimental-zicfiss,experimental-zvbc32e,experimental-zvkgs,f,forced-atomics,h,i,ld-add-fusion,lui-addi-fusion,m,mips-p8700,no-default-unroll,no-rvc-hints,no-sink-splat-operands,no-trailing-seq-cst-fence,optimized-nf2-segment-load-store,optimized-nf3-segment-load-store,optimized-nf4-segment-load-store,optimized-nf5-segment-load-store,optimized-nf6-segment-load-store,optimized-nf7-segment-load-store,optimized-nf8-segment-load-store,optimized-zero-stride-load,predictable-select-expensive,prefer-w-inst,relax,reserve-x1,reserve-x10,reserve-x11,reserve-x12,reserve-x13,reserve-x14,reserve-x15,reserve-x16,reserve-x17,reserve-x18,reserve-x19,reserve-x2,reserve-x20,reserve-x21,reserve-x22,reserve-x23,reserve-x24,reserve-x25,reserve-x26,reserve-x27,reserve-x28,reserve-x29,reserve-x3,reserve-x30,reserve-x31,reserve-x4,reserve-x5,reserve-x6,reserve-x7,reserve-x8,reserve-x9,rva20s64,rva20u64,rva22s64,rva22u64,rva23s64,rva23u64,rvb23s64,rvb23u64,rvi20u32,rvi20u64,save-restore,sha,shcounterenw,shgatpa,shifted-zextw-fusion,short-forward-branch-opt,shtvala,shvsatpa,shvstvala,shvstvecd,sifive7,smaia,smcdeleg,smcsrind,smdbltrp,smepmp,smmpm,smnpm,smrnmi,smstateen,ssaia,ssccfg,ssccptr,sscofpmf,sscounterenw,sscsrind,ssdbltrp,ssnpm,sspm,ssqosid,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svadu,svbare,svinval,svnapot,svpbmt,svvptc,tagged-globals,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,ventana-veyron,vxrm-pipeline-flush,xcvalu,xcvbi,xcvbitmanip,xcvelw,xcvmac,xcvmem,xcvsimd,xmipscmove,xmipslsp,xsfcease,xsfvcp,xsfvfnrclipxfqf,xsfvfwmaccqqq,xsfvqmaccdod,xsfvqmaccqoq,xsifivecdiscarddlone,xsifivecflushdlone,xtheadba,xtheadbb,xtheadbs,xtheadcmo,xtheadcondmov,xtheadfmemidx,xtheadmac,xtheadmemidx,xtheadmempair,xtheadsync,xtheadvdot,xventanacondops,xwchc,za128rs,za64rs,zaamo,zabha,zacas,zalrsc,zama16b,zawrs,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zca,zcb,zcd,zce,zcf,zcmop,zcmp,zcmt,zdinx,zexth-fusion,zextw-fusion,zfa,zfbfmin,zfh,zfhmin,zfinx,zhinx,zhinxmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zk,zkn,zknd,zkne,zknh,zkr,zks,zksed,zksh,zkt,zmmul,ztso,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknha,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl1024b,zvl128b,zvl16384b,zvl2048b,zvl256b,zvl32768b,zvl32b,zvl4096b,zvl512b,zvl64b,zvl65536b,zvl8192b"), +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global int target_microarch_counts[TargetArch_COUNT] = { + // TargetArch_Invalid: + 0, + // TargetArch_amd64: + 129, + // TargetArch_i386: + 129, + // TargetArch_arm32: + 95, + // TargetArch_arm64: + 82, + // TargetArch_wasm32: + 4, + // TargetArch_wasm64p32: + 4, + // TargetArch_riscv64: + 39, +}; + +// Generated with the featuregen script in `misc/featuregen` +gb_global MicroarchFeatureList microarch_features_list[] = { + // TargetArch_amd64: + { str_lit("alderlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("arrowlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake-s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake_s"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("athlon"), str_lit("64bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("64bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("64bit,64bit-mode,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("64bit,64bit-mode,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("64bit,64bit-mode,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-15bytenop,fast-imm16,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("64bit,64bit-mode,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("64bit-mode,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("clearwaterforest"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("64bit,64bit-mode,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("diamondrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,ccmp,cf,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-256-bit,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves,zu") }, + { str_lit("emeraldrapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("64bit,64bit-mode,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,sse,sse2,vzeroupper,x87") }, + { str_lit("geode"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("64bit,64bit-mode,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("gracemont"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i486"), str_lit("64bit-mode,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i586"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("i686"), str_lit("64bit-mode,cmov,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("64bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper") }, + { str_lit("lunarlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("meteorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("opteron"), str_lit("64bit,64bit-mode,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pantherlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("penryn"), str_lit("64bit,64bit-mode,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("64bit-mode,cx8,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("64bit-mode,cx8,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("64bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("64bit,64bit-mode,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("64bit,64bit-mode,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("64bit,64bit-mode,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("winchip-c6"), str_lit("64bit-mode,mmx,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("64bit-mode,mmx,prfchw,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("64bit,64bit-mode,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("64bit,64bit-mode,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("64bit,64bit-mode,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("64bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver5"), str_lit("64bit,64bit-mode,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxvnni,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,nopl,pclmul,pku,popcnt,prefetchi,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_i386: + { str_lit("alderlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("amdfam10"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("arrowlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake-s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("arrowlake_s"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("athlon"), str_lit("32bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-fx"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon-mp"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon-tbird"), str_lit("32bit-mode,cmov,cx8,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("athlon-xp"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,prfchw,slow-shld,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("athlon64"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("athlon64-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("atom"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("atom_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("atom_sse4_2_movbe"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fsgsbase,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("barcelona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,idivq-to-divl,lzcnt,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,vzeroupper,x87") }, + { str_lit("bdver1"), str_lit("32bit-mode,64bit,aes,avx,branchfusion,cmov,crc32,cx16,cx8,fast-11bytenop,fast-scalar-shift-masks,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave") }, + { str_lit("bdver3"), str_lit("32bit-mode,64bit,aes,avx,bmi,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bdver4"), str_lit("32bit-mode,64bit,aes,avx,avx2,bmi,bmi2,branchfusion,cmov,crc32,cx16,cx8,f16c,fast-11bytenop,fast-bextr,fast-movbe,fast-scalar-shift-masks,fma,fma4,fsgsbase,fxsr,idivq-to-divl,lwp,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,tbm,vzeroupper,x87,xop,xsave,xsaveopt") }, + { str_lit("bonnell"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-imm16,fxsr,idivl-to-divb,idivq-to-divl,lea-sp,lea-uses-ag,mmx,movbe,no-bypass-delay,nopl,pad-short-functions,sahf,slow-two-mem-ops,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("broadwell"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("btver1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-15bytenop,fast-imm16,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,nopl,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4a,ssse3,vzeroupper,x87") }, + { str_lit("btver2"), str_lit("32bit-mode,64bit,aes,avx,bmi,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-hops,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-shift-masks,fast-vector-shift-masks,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prfchw,sahf,sbb-dep-breaking,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,x87,xsave,xsaveopt") }, + { str_lit("c3"), str_lit("32bit-mode,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("c3-2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("cannonlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vl,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,sha,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cascadelake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("clearwaterforest"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("cooperlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,avx512vnni,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("core-avx-i"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core-avx2"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core2"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_sse4_1"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("core_2_duo_ssse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,ssse3,vzeroupper,x87") }, + { str_lit("core_2nd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_3rd_gen_avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_4th_gen_avx_tsx"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_5th_gen_avx_tsx"), str_lit("32bit-mode,64bit,adx,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("core_aes_pclmulqdq"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("core_i7_sse4_2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("corei7-avx"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("diamondrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-avx512,amx-bf16,amx-complex,amx-fp16,amx-fp8,amx-int8,amx-movrs,amx-tf32,amx-tile,amx-transpose,avx,avx10.1-256,avx10.1-512,avx10.2-256,avx10.2-512,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,branch-hint,ccmp,cf,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,egpr,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,movrs,ndd,nf,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,ppx,prefer-256-bit,prefetchi,prfchw,ptwrite,push2pop2,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,usermsr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves,zu") }, + { str_lit("emeraldrapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("generic"), str_lit("32bit-mode,64bit,cx8,fast-15bytenop,fast-scalar-fsqrt,idivq-to-divl,macrofusion,slow-3ops-lea,vzeroupper,x87") }, + { str_lit("geode"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("goldmont"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont-plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("goldmont_plus"), str_lit("32bit-mode,64bit,aes,clflushopt,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("gracemont"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("grandridge"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids-d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("graniterapids_d"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-complex,amx-fp16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,branch-hint,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("haswell"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("i386"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i486"), str_lit("32bit-mode,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i586"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("i686"), str_lit("32bit-mode,cmov,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("icelake-client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake-server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_client"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("icelake_server"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("ivybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fsgsbase,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,rdrnd,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("k6"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-2"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k6-3"), str_lit("32bit-mode,cx8,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("k8"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("k8-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("knl"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("knm"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,avx512vpopcntdq,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("lakemont"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper") }, + { str_lit("lunarlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("meteorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("mic_avx512"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avx512cd,avx512f,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,fast-gather,fast-imm16,fast-movbe,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,nopl,pclmul,popcnt,prefer-mask-registers,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,slow-incdec,slow-pmaddwd,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,x87,xsave,xsaveopt") }, + { str_lit("nehalem"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("nocona"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("opteron"), str_lit("32bit-mode,64bit,cmov,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("opteron-sse3"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fast-scalar-shift-masks,fxsr,mmx,nopl,prfchw,sbb-dep-breaking,slow-shld,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pantherlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint16,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prefetchi,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,sha512,shstk,slow-3ops-lea,sm3,sm4,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("penryn"), str_lit("32bit-mode,64bit,cmov,cx16,cx8,fxsr,macrofusion,mmx,nopl,sahf,slow-unaligned-mem-16,sse,sse2,sse3,sse4.1,ssse3,vzeroupper,x87") }, + { str_lit("pentium"), str_lit("32bit-mode,cx8,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium-m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium-mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium2"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium3m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium4m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_4_sse3"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("pentium_ii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_iii"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_iii_no_xmm_regs"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,vzeroupper,x87") }, + { str_lit("pentium_m"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,vzeroupper,x87") }, + { str_lit("pentium_mmx"), str_lit("32bit-mode,cx8,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentium_pro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("pentiumpro"), str_lit("32bit-mode,cmov,cx8,nopl,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("prescott"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("raptorlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,f16c,false-deps-perm,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,idivq-to-divl,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-movmsk-over-vtest,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("rocketlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sandybridge"), str_lit("32bit-mode,64bit,avx,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsaveopt") }, + { str_lit("sapphirerapids"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,amx-bf16,amx-int8,amx-tile,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512fp16,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,avxvnni,bmi,bmi2,cldemote,clflushopt,clwb,cmov,crc32,cx16,cx8,enqcmd,ermsb,evex512,f16c,false-deps-getmant,false-deps-mulc,false-deps-mullq,false-deps-perm,false-deps-range,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pconfig,pku,popcnt,prefer-256-bit,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tsxldtrk,tuning-fast-imm-vector-shift,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("sierraforest"), str_lit("32bit-mode,64bit,adx,aes,avx,avx2,avxifma,avxneconvert,avxvnni,avxvnniint8,bmi,bmi2,cldemote,clflushopt,clwb,cmov,cmpccxadd,crc32,cx16,cx8,enqcmd,f16c,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,gfni,hreset,invpcid,kl,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,nopl,pclmul,pconfig,pku,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,serialize,sha,shstk,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,uintr,vaes,vpclmulqdq,vzeroupper,waitpkg,widekl,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("silvermont"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("skx"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,clflushopt,cmov,crc32,cx16,cx8,ermsb,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake-avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("skylake_avx512"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,faster-shift-than-shuffle,fma,fsgsbase,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdrnd,rdseed,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("slm"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-7bytenop,fast-imm16,fast-movbe,fxsr,idivq-to-divl,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,rdrnd,sahf,slow-incdec,slow-lea,slow-pmulld,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-slm-arith-costs,vzeroupper,x87") }, + { str_lit("tigerlake"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,bmi,bmi2,clflushopt,clwb,cmov,crc32,cx16,cx8,ermsb,evex512,f16c,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,no-bypass-delay-blend,no-bypass-delay-mov,no-bypass-delay-shuffle,nopl,pclmul,pku,popcnt,prefer-256-bit,prfchw,rdpid,rdrnd,rdseed,sahf,sha,shstk,sse,sse2,sse3,sse4.1,sse4.2,ssse3,tuning-fast-imm-vector-shift,vaes,vpclmulqdq,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("tremont"), str_lit("32bit-mode,64bit,aes,clflushopt,clwb,cmov,crc32,cx16,cx8,fast-imm16,fast-movbe,fsgsbase,fxsr,gfni,mmx,movbe,no-bypass-delay,nopl,pclmul,popcnt,prfchw,ptwrite,rdpid,rdrnd,rdseed,sahf,sha,slow-incdec,slow-lea,slow-two-mem-ops,sse,sse2,sse3,sse4.1,sse4.2,ssse3,use-glm-div-sqrt-costs,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("westmere"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,fxsr,idivq-to-divl,macrofusion,mmx,no-bypass-delay-mov,nopl,pclmul,popcnt,sahf,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("winchip-c6"), str_lit("32bit-mode,mmx,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("winchip2"), str_lit("32bit-mode,mmx,prfchw,slow-unaligned-mem-16,vzeroupper,x87") }, + { str_lit("x86-64"), str_lit("32bit-mode,64bit,cmov,cx8,fxsr,idivq-to-divl,macrofusion,mmx,nopl,slow-3ops-lea,slow-incdec,sse,sse2,vzeroupper,x87") }, + { str_lit("x86-64-v2"), str_lit("32bit-mode,64bit,cmov,crc32,cx16,cx8,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fxsr,idivq-to-divl,macrofusion,mmx,nopl,popcnt,sahf,slow-3ops-lea,slow-unaligned-mem-32,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87") }, + { str_lit("x86-64-v3"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,bmi,bmi2,cmov,crc32,cx16,cx8,f16c,false-deps-lzcnt-tzcnt,false-deps-popcnt,fast-15bytenop,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("x86-64-v4"), str_lit("32bit-mode,64bit,allow-light-256-bit,avx,avx2,avx512bw,avx512cd,avx512dq,avx512f,avx512vl,bmi,bmi2,cmov,crc32,cx16,cx8,evex512,f16c,false-deps-popcnt,fast-15bytenop,fast-gather,fast-scalar-fsqrt,fast-shld-rotate,fast-variable-crosslane-shuffle,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fxsr,idivq-to-divl,lzcnt,macrofusion,mmx,movbe,nopl,popcnt,prefer-256-bit,sahf,slow-3ops-lea,sse,sse2,sse3,sse4.1,sse4.2,ssse3,vzeroupper,x87,xsave") }, + { str_lit("yonah"), str_lit("32bit-mode,cmov,cx8,fxsr,mmx,nopl,slow-unaligned-mem-16,sse,sse2,sse3,vzeroupper,x87") }, + { str_lit("znver1"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver2"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fxsr,idivq-to-divl,lzcnt,mmx,movbe,mwaitx,nopl,pclmul,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver3"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,f16c,fast-15bytenop,fast-bextr,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver4"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vpopcntdq,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,mwaitx,nopl,pclmul,pku,popcnt,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + { str_lit("znver5"), str_lit("32bit-mode,64bit,adx,aes,allow-light-256-bit,avx,avx2,avx512bf16,avx512bitalg,avx512bw,avx512cd,avx512dq,avx512f,avx512ifma,avx512vbmi,avx512vbmi2,avx512vl,avx512vnni,avx512vp2intersect,avx512vpopcntdq,avxvnni,bmi,bmi2,branchfusion,clflushopt,clwb,clzero,cmov,crc32,cx16,cx8,evex512,f16c,fast-15bytenop,fast-bextr,fast-dpwssd,fast-imm16,fast-lzcnt,fast-movbe,fast-scalar-fsqrt,fast-scalar-shift-masks,fast-variable-perlane-shuffle,fast-vector-fsqrt,fma,fsgsbase,fsrm,fxsr,gfni,idivq-to-divl,invpcid,lzcnt,macrofusion,mmx,movbe,movdir64b,movdiri,mwaitx,nopl,pclmul,pku,popcnt,prefetchi,prfchw,rdpid,rdpru,rdrnd,rdseed,sahf,sbb-dep-breaking,sha,shstk,slow-shld,sse,sse2,sse3,sse4.1,sse4.2,sse4a,ssse3,vaes,vpclmulqdq,vzeroupper,wbnoinvd,x87,xsave,xsavec,xsaveopt,xsaves") }, + // TargetArch_arm32: + { str_lit("arm1020e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm1020t"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1022e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm10tdmi"), str_lit("armv5t,v4t,v5t") }, + { str_lit("arm1136j-s"), str_lit("armv6,dsp,v4t,v5t,v5te,v6") }, + { str_lit("arm1136jf-s"), str_lit("armv6,dsp,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,vfp2,vfp2sp") }, + { str_lit("arm1156t2-s"), str_lit("armv6t2,dsp,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m") }, + { str_lit("arm1156t2f-s"), str_lit("armv6t2,dsp,fp64,fpregs,fpregs64,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v8m,vfp2,vfp2sp") }, + { str_lit("arm1176jz-s"), str_lit("armv6kz,trustzone,v4t,v5t,v5te,v6,v6k") }, + { str_lit("arm1176jzf-s"), str_lit("armv6kz,fp64,fpregs,fpregs64,slowfpvmlx,trustzone,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("arm710t"), str_lit("armv4t,v4t") }, + { str_lit("arm720t"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi"), str_lit("armv4t,v4t") }, + { str_lit("arm7tdmi-s"), str_lit("armv4t,v4t") }, + { str_lit("arm8"), str_lit("armv4") }, + { str_lit("arm810"), str_lit("armv4") }, + { str_lit("arm9"), str_lit("armv4t,v4t") }, + { str_lit("arm920"), str_lit("armv4t,v4t") }, + { str_lit("arm920t"), str_lit("armv4t,v4t") }, + { str_lit("arm922t"), str_lit("armv4t,v4t") }, + { str_lit("arm926ej-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm940t"), str_lit("armv4t,v4t") }, + { str_lit("arm946e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm966e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm968e-s"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9e"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("arm9tdmi"), str_lit("armv4t,v4t") }, + { str_lit("cortex-a12"), str_lit("a12,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a15"), str_lit("a15,aclass,armv7-a,avoid-partial-cpsr,d32,db,dont-widen-vmovs,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,muxed-units,neon,perfmon,ret-addr-stack,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vldn-align") }, + { str_lit("cortex-a17"), str_lit("a17,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding") }, + { str_lit("cortex-a32"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a35"), str_lit("a35,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a5"), str_lit("a5,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-forwarding") }, + { str_lit("cortex-a510"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a53"), str_lit("a53,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a55"), str_lit("a55,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a57"), str_lit("a57,aclass,acquire-release,aes,armv8-a,avoid-partial-cpsr,cheap-predicable-cpsr,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a7"), str_lit("a7,aclass,armv7-a,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a710"), str_lit("aclass,acquire-release,armv9-a,bf16,cortex-a710,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a72"), str_lit("a72,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fix-cortex-a57-aes-1742098,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a73"), str_lit("a73,aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a75"), str_lit("a75,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a76ae"), str_lit("a76,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a77"), str_lit("a77,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78ae"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-a78ae,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a78c"), str_lit("a78c,aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-a8"), str_lit("a8,aclass,armv7-a,d32,db,dsp,fp64,fpregs,fpregs64,neon,nonpipelined-vfp,perfmon,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-a9"), str_lit("a9,aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,expand-fp-mlx,fp16,fp64,fpregs,fpregs64,mp,muxed-units,neon,neon-fpmovs,perfmon,prefer-vmovsr,ret-addr-stack,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vldn-align,vmlx-forwarding,vmlx-hazards") }, + { str_lit("cortex-m0"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m0plus"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m1"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("cortex-m23"), str_lit("8msecext,acquire-release,armv8-m.base,db,hwdiv,mclass,no-branch-predictor,no-movt,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m,v7clrex,v8m") }, + { str_lit("cortex-m3"), str_lit("armv7-m,db,hwdiv,loop-align,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-m33"), str_lit("8msecext,acquire-release,armv8-m.main,avoid-muls,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m35p"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m4"), str_lit("armv7e-m,db,dsp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("cortex-m52"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,mclass,mve,mve.fp,mve1beat,no-branch-predictor,noarm,pacbti,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m55"), str_lit("8msecext,acquire-release,armv8.1-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,loop-align,m55,mclass,mve,mve.fp,no-branch-predictor,noarm,ras,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m7"), str_lit("armv7e-m,branch-align-64,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs64,hwdiv,m7,mclass,noarm,thumb-mode,thumb2,use-mipipeliner,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-m85"), str_lit("8msecext,acquire-release,armv8.1-m.main,branch-align-64,db,dsp,fp-armv8d16,fp-armv8d16sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,lob,m85,mclass,mve,mve.fp,noarm,pacbti,ras,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8.1m.main,v8m,v8m.main,vfp2,vfp2sp,vfp3d16,vfp3d16sp,vfp4d16,vfp4d16sp") }, + { str_lit("cortex-r4"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,hwdiv,perfmon,r4,rclass,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("cortex-r4f"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,perfmon,r4,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r5"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,perfmon,r5,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r52"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-r52plus"), str_lit("acquire-release,armv8-r,crc,d32,db,dfb,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpao,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,r52plus,rclass,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-r7"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,r7,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-r8"), str_lit("armv7-r,avoid-partial-cpsr,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,perfmon,rclass,ret-addr-stack,slow-fp-brcc,slowfpvfmx,slowfpvmlx,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3d16,vfp3d16sp") }, + { str_lit("cortex-x1"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cortex-x1c"), str_lit("aclass,acquire-release,aes,armv8.2-a,cortex-x1c,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("cyclone"), str_lit("aclass,acquire-release,aes,armv8-a,avoid-movs-shop,avoid-partial-cpsr,crc,crypto,d32,db,disable-postra-scheduler,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,ret-addr-stack,sha2,slowfpvfmx,slowfpvmlx,swift,thumb2,trustzone,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,zcz") }, + { str_lit("ep9312"), str_lit("armv4t,v4t") }, + { str_lit("exynos-m3"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dont-widen-vmovs,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m4"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("exynos-m5"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dont-widen-vmovs,dotprod,dsp,expand-fp-mlx,exynos,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,fuse-aes,fuse-literals,hwdiv,hwdiv-arm,mp,neon,perfmon,prof-unpr,ras,ret-addr-stack,sha2,slow-fp-brcc,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,splat-vfp-neon,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization,wide-stride-vfp,zcz") }, + { str_lit("generic"), str_lit("") }, + { str_lit("iwmmxt"), str_lit("armv5te,v4t,v5t,v5te") }, + { str_lit("krait"), str_lit("aclass,armv7-a,avoid-partial-cpsr,d32,db,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,krait,muxed-units,neon,perfmon,ret-addr-stack,thumb2,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vldn-align,vmlx-forwarding") }, + { str_lit("kryo"), str_lit("aclass,acquire-release,aes,armv8-a,crc,crypto,d32,db,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,kryo,mp,neon,perfmon,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("mpcore"), str_lit("armv6k,fp64,fpregs,fpregs64,slowfpvmlx,v4t,v5t,v5te,v6,v6k,vfp2,vfp2sp") }, + { str_lit("mpcorenovfp"), str_lit("armv6k,v4t,v5t,v5te,v6,v6k") }, + { str_lit("neoverse-n1"), str_lit("aclass,acquire-release,aes,armv8.2-a,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-n2"), str_lit("aclass,acquire-release,armv9-a,bf16,crc,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp16fml,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sb,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8m,v9a,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("neoverse-v1"), str_lit("aclass,acquire-release,aes,armv8.4-a,bf16,crc,crypto,d32,db,dotprod,dsp,fp-armv8,fp-armv8d16,fp-armv8d16sp,fp-armv8sp,fp16,fp64,fpregs,fpregs16,fpregs64,fullfp16,hwdiv,hwdiv-arm,i8mm,mp,neon,perfmon,ras,sha2,thumb2,trustzone,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8,v8.1a,v8.2a,v8.3a,v8.4a,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,virtualization") }, + { str_lit("sc000"), str_lit("armv6-m,db,mclass,no-branch-predictor,noarm,strict-align,thumb-mode,v4t,v5t,v5te,v6,v6m") }, + { str_lit("sc300"), str_lit("armv7-m,db,hwdiv,m3,mclass,no-branch-predictor,noarm,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m") }, + { str_lit("star-mc1"), str_lit("8msecext,acquire-release,armv8-m.main,db,dsp,fix-cmse-cve-2021-35465,fp-armv8d16sp,fp16,fpregs,hwdiv,loop-align,mclass,no-branch-predictor,noarm,slowfpvfmx,slowfpvmlx,thumb-mode,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,v8m.main,vfp2sp,vfp3d16sp,vfp4d16sp") }, + { str_lit("strongarm"), str_lit("armv4") }, + { str_lit("strongarm110"), str_lit("armv4") }, + { str_lit("strongarm1100"), str_lit("armv4") }, + { str_lit("strongarm1110"), str_lit("armv4") }, + { str_lit("swift"), str_lit("aclass,armv7-a,avoid-movs-shop,avoid-partial-cpsr,d32,db,disable-postra-scheduler,dsp,fp16,fp64,fpregs,fpregs64,hwdiv,hwdiv-arm,mp,neon,neonfp,perfmon,prefer-ishst,prof-unpr,ret-addr-stack,slow-load-D-subreg,slow-odd-reg,slow-vdup32,slow-vgetlni32,slowfpvfmx,slowfpvmlx,swift,thumb2,use-misched,v4t,v5t,v5te,v6,v6k,v6m,v6t2,v7,v7clrex,v8m,vfp2,vfp2sp,vfp3,vfp3d16,vfp3d16sp,vfp3sp,vfp4,vfp4d16,vfp4d16sp,vfp4sp,vmlx-hazards,wide-stride-vfp") }, + { str_lit("xscale"), str_lit("armv5te,v4t,v5t,v5te") }, + // TargetArch_arm64: + { str_lit("a64fx"), str_lit("CONTEXTIDREL2,a64fx,aes,aggressive-fma,arith-bcc-fusion,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rdm,sha2,store-pair-suppress,sve,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("ampere1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("ampere1a"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1a,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-addsub-2reg-const1,fuse-adrp-add,fuse-aes,fuse-literals,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("ampere1b"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,altnzcv,alu-lsl-fast,am,ampere1b,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,cssc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,fgt,flagm,fp-armv8,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,hcx,i8mm,jsconv,ldp-aligned-only,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,specrestrict,ssbs,store-pair-suppress,stp-aligned-only,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs") }, + { str_lit("apple-a10"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a10,arith-bcc-fusion,arith-cbz-fusion,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,lor,neon,pan,perfmon,rdm,sha2,store-pair-suppress,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a11"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a11,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a12"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a13"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,am,apple-a13,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a14"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a15"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a16"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a17"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a17,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-a7"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-a8"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-a9"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("apple-m1"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,alternate-sextload-cvt-f32-pattern,altnzcv,am,apple-a14,arith-bcc-fusion,arith-cbz-fusion,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-m2"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a15,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-m3"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-a16,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,specrestrict,ssbs,store-pair-suppress,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-m4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,altnzcv,am,amvs,apple-m4,arith-bcc-fusion,arith-cbz-fusion,bf16,bti,ccdp,ccpp,complxnum,crc,disable-latency-sched-heuristic,dit,dotprod,ecv,el2vmsa,el3,fgt,flagm,fp-armv8,fp16fml,fpac,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-crypto-eor,fuse-csel,fuse-literals,hcx,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sme,sme-f64f64,sme-i16i64,sme2,specrestrict,tlb-rmi,tracev8.4,uaops,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,vh,wfxt,xs,zcm,zcz,zcz-gp") }, + { str_lit("apple-s4"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("apple-s5"), str_lit("CONTEXTIDREL2,aes,alternate-sextload-cvt-f32-pattern,apple-a12,arith-bcc-fusion,arith-cbz-fusion,ccpp,complxnum,crc,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fullfp16,fuse-aes,fuse-crypto-eor,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,ras,rcpc,rdm,sha2,store-pair-suppress,uaops,v8.1a,v8.2a,v8.3a,v8a,vh,zcm,zcz,zcz-gp") }, + { str_lit("carmel"), str_lit("CONTEXTIDREL2,aes,carmel,ccpp,crc,el2vmsa,el3,fp-armv8,fullfp16,lor,lse,neon,pan,pan-rwv,ras,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cobalt-100"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a34"), str_lit("a35,aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a35"), str_lit("a35,aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,sha2,v8a") }, + { str_lit("cortex-a510"), str_lit("CONTEXTIDREL2,a510,altnzcv,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a520"), str_lit("CONTEXTIDREL2,a520,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a520ae"), str_lit("CONTEXTIDREL2,a520ae,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a53"), str_lit("a53,aes,balance-fp-ops,crc,el2vmsa,el3,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,sha2,use-postra-scheduler,v8a") }, + { str_lit("cortex-a55"), str_lit("CONTEXTIDREL2,a55,aes,ccpp,crc,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a57"), str_lit("a57,addr-lsl-slow-14,aes,balance-fp-ops,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,use-postra-scheduler,v8a") }, + { str_lit("cortex-a65"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a65ae"), str_lit("CONTEXTIDREL2,a65,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a710"), str_lit("CONTEXTIDREL2,a710,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a715"), str_lit("CONTEXTIDREL2,a715,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-a72"), str_lit("a72,addr-lsl-slow-14,aes,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a720"), str_lit("CONTEXTIDREL2,a720,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a720ae"), str_lit("CONTEXTIDREL2,a720ae,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a725"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-a725,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-a73"), str_lit("a73,addr-lsl-slow-14,aes,crc,el2vmsa,el3,enable-select-opt,fp-armv8,fuse-adrp-add,fuse-aes,neon,perfmon,predictable-select-expensive,sha2,v8a") }, + { str_lit("cortex-a75"), str_lit("CONTEXTIDREL2,a75,addr-lsl-slow-14,aes,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76"), str_lit("CONTEXTIDREL2,a76,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a76ae"), str_lit("CONTEXTIDREL2,a76,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a77"), str_lit("CONTEXTIDREL2,a77,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,ssbs,uaops,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78"), str_lit("CONTEXTIDREL2,a78,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78ae"), str_lit("CONTEXTIDREL2,a78ae,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-a78c"), str_lit("CONTEXTIDREL2,a78c,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,crc,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-r82"), str_lit("CONTEXTIDREL2,ccdp,ccpp,complxnum,cortex-r82,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") }, + { str_lit("cortex-r82ae"), str_lit("CONTEXTIDREL2,ccdp,ccpp,complxnum,cortex-r82ae,crc,dit,dotprod,flagm,fp-armv8,fp16fml,fullfp16,jsconv,lse,neon,pan,pan-rwv,pauth,perfmon,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8r") }, + { str_lit("cortex-x1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x1c"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,cmp-bcc-fusion,cortex-x1,crc,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,lse2,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("cortex-x2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,cortex-x2,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-x3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x3,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("cortex-x4"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x4,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cortex-x925"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,complxnum,cortex-x925,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("cyclone"), str_lit("aes,alternate-sextload-cvt-f32-pattern,apple-a7,arith-bcc-fusion,arith-cbz-fusion,disable-latency-sched-heuristic,el2vmsa,el3,fp-armv8,fuse-aes,fuse-crypto-eor,neon,perfmon,sha2,store-pair-suppress,v8a,zcm,zcz,zcz-fp-workaround,zcz-gp") }, + { str_lit("exynos-m3"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,exynos-cheap-as-move,exynosm3,force-32bit-jump-tables,fp-armv8,fuse-address,fuse-adrp-add,fuse-aes,fuse-csel,fuse-literals,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a") }, + { str_lit("exynos-m4"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, + { str_lit("exynos-m5"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,arith-bcc-fusion,arith-cbz-fusion,ccpp,crc,dotprod,el2vmsa,el3,exynos-cheap-as-move,exynosm4,force-32bit-jump-tables,fp-armv8,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-arith-logic,fuse-csel,fuse-literals,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,store-pair-suppress,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh,zcz,zcz-gp") }, + { str_lit("falkor"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,falkor,fp-armv8,neon,perfmon,predictable-select-expensive,rdm,sha2,slow-strqro-store,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, + { str_lit("fujitsu-monaka"), str_lit("CONTEXTIDREL2,aes,altnzcv,am,amvs,arith-bcc-fusion,bf16,bti,ccdp,ccidx,ccpp,clrbhb,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,faminmax,fgt,flagm,fp-armv8,fp16fml,fp8,fp8dot2,fpac,fptoint,fujitsu-monaka,fullfp16,hbc,hcx,i8mm,jsconv,lor,ls64,lse,lse2,lut,mec,mops,mpam,neon,nmi,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,sha2,sha3,sm4,specres2,specrestrict,ssbs,sve,sve-aes,sve-bitperm,sve2,sve2-sha3,sve2-sm4,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8.8a,v8a,v9.1a,v9.2a,v9.3a,v9a,vh,wfxt,xs") }, + { str_lit("generic"), str_lit("enable-select-opt,ete,fp-armv8,fuse-adrp-add,fuse-aes,neon,trbe,use-postra-scheduler") }, + { str_lit("grace"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("kryo"), str_lit("aes,alu-lsl-fast,crc,el2vmsa,el3,fp-armv8,kryo,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,use-postra-scheduler,v8a,zcz,zcz-gp") }, + { str_lit("neoverse-512tvb"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoverse512tvb,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,sm4,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-e1"), str_lit("CONTEXTIDREL2,aes,ccpp,crc,dotprod,el2vmsa,el3,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversee1,pan,pan-rwv,perfmon,ras,rcpc,rdm,sha2,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,ccpp,crc,dotprod,el2vmsa,el3,enable-select-opt,fp-armv8,fullfp16,fuse-adrp-add,fuse-aes,lor,lse,neon,neoversen1,pan,pan-rwv,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,spe,ssbs,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + { str_lit("neoverse-n2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,ras,rcpc,rcpc-immo,rdm,sb,sel2,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("neoverse-n3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversen3,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("neoverse-v1"), str_lit("CONTEXTIDREL2,addr-lsl-slow-14,aes,alu-lsl-fast,am,bf16,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,flagm,fp-armv8,fp16fml,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,neon,neoversev1,no-sve-fp-ld1r,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,rand,ras,rcpc,rcpc-immo,rdm,sel2,sha2,sha3,sm4,spe,ssbs,sve,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh") }, + { str_lit("neoverse-v2"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,avoid-ldapur,bf16,bti,ccdp,ccidx,ccpp,cmp-bcc-fusion,complxnum,crc,dit,dotprod,el2vmsa,el3,enable-select-opt,ete,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,i8mm,jsconv,lor,lse,lse2,mpam,mte,neon,neoversev2,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,spe,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-fixed-over-scalable-if-equal-cost,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8a,v9a,vh") }, + { str_lit("neoverse-v3"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,brbe,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,ls64,lse,lse2,mpam,mte,neon,neoversev3,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("neoverse-v3ae"), str_lit("CONTEXTIDREL2,altnzcv,alu-lsl-fast,am,amvs,avoid-ldapur,bf16,brbe,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,ete,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-adrp-add,fuse-aes,hcx,i8mm,jsconv,lor,ls64,lse,lse2,mpam,mte,neon,neoversev3AE,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,predres,rand,ras,rcpc,rcpc-immo,rdm,rme,sb,sel2,spe,spe-eef,specrestrict,ssbs,sve,sve-bitperm,sve2,tlb-rmi,tracev8.4,trbe,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8.7a,v8a,v9.1a,v9.2a,v9a,vh,wfxt,xs") }, + { str_lit("oryon-1"), str_lit("CONTEXTIDREL2,aes,altnzcv,am,amvs,bf16,bti,ccdp,ccidx,ccpp,complxnum,crc,dit,dotprod,ecv,el2vmsa,el3,enable-select-opt,fgt,flagm,fp-armv8,fp16fml,fptoint,fullfp16,fuse-address,fuse-adrp-add,fuse-aes,fuse-crypto-eor,i8mm,jsconv,lor,lse,lse2,mpam,neon,nv,oryon-1,pan,pan-rwv,pauth,perfmon,predres,rand,ras,rcpc,rcpc-immo,rdm,sb,sel2,sha2,sha3,sm4,spe,specrestrict,ssbs,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8.5a,v8.6a,v8a,vh") }, + { str_lit("saphira"), str_lit("CONTEXTIDREL2,aes,alu-lsl-fast,am,ccidx,ccpp,complxnum,crc,dit,dotprod,el2vmsa,el3,flagm,fp-armv8,jsconv,lor,lse,lse2,mpam,neon,nv,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rcpc-immo,rdm,saphira,sel2,sha2,spe,store-pair-suppress,tlb-rmi,tracev8.4,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8.4a,v8a,vh,zcz,zcz-gp") }, + { str_lit("thunderx"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderx,use-postra-scheduler,v8a") }, + { str_lit("thunderx2t99"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,crc,el2vmsa,el3,fp-armv8,lor,lse,neon,pan,predictable-select-expensive,rdm,sha2,store-pair-suppress,thunderx2t99,use-postra-scheduler,v8.1a,v8a,vh") }, + { str_lit("thunderx3t110"), str_lit("CONTEXTIDREL2,aes,aggressive-fma,arith-bcc-fusion,balance-fp-ops,ccidx,ccpp,complxnum,crc,el2vmsa,el3,fp-armv8,jsconv,lor,lse,neon,pan,pan-rwv,pauth,perfmon,predictable-select-expensive,ras,rcpc,rdm,sha2,store-pair-suppress,strict-align,thunderx3t110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8.3a,v8a,vh") }, + { str_lit("thunderxt81"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt81,use-postra-scheduler,v8a") }, + { str_lit("thunderxt83"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt83,use-postra-scheduler,v8a") }, + { str_lit("thunderxt88"), str_lit("aes,crc,el2vmsa,el3,fp-armv8,neon,perfmon,predictable-select-expensive,sha2,store-pair-suppress,thunderxt88,use-postra-scheduler,v8a") }, + { str_lit("tsv110"), str_lit("CONTEXTIDREL2,aes,ccpp,complxnum,crc,dotprod,el2vmsa,el3,fp-armv8,fp16fml,fullfp16,fuse-aes,jsconv,lor,lse,neon,pan,pan-rwv,perfmon,ras,rdm,sha2,spe,store-pair-suppress,tsv110,uaops,use-postra-scheduler,v8.1a,v8.2a,v8a,vh") }, + // TargetArch_wasm32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("bulk-memory,bulk-memory-opt,call-indirect-overlong,multivalue,mutable-globals,nontrapping-fptoint,reference-types,sign-ext") }, + { str_lit("lime1"), str_lit("bulk-memory-opt,call-indirect-overlong,extended-const,multivalue,mutable-globals,nontrapping-fptoint,sign-ext") }, + { str_lit("mvp"), str_lit("") }, + // TargetArch_wasm64p32: + { str_lit("bleeding-edge"), str_lit("atomics,bulk-memory,bulk-memory-opt,call-indirect-overlong,exception-handling,extended-const,fp16,multimemory,multivalue,mutable-globals,nontrapping-fptoint,reference-types,relaxed-simd,sign-ext,simd128,tail-call") }, + { str_lit("generic"), str_lit("bulk-memory,bulk-memory-opt,call-indirect-overlong,multivalue,mutable-globals,nontrapping-fptoint,reference-types,sign-ext") }, + { str_lit("lime1"), str_lit("bulk-memory-opt,call-indirect-overlong,extended-const,multivalue,mutable-globals,nontrapping-fptoint,sign-ext") }, + { str_lit("mvp"), str_lit("") }, + // TargetArch_riscv64: + { str_lit("generic"), str_lit("64bit,i,optimized-nf2-segment-load-store") }, + { str_lit("generic-rv32"), str_lit("32bit,i,optimized-nf2-segment-load-store") }, + { str_lit("generic-rv64"), str_lit("64bit,i,optimized-nf2-segment-load-store") }, + { str_lit("mips-p8700"), str_lit("64bit,a,c,d,f,i,m,mips-p8700,xmipscmove,xmipslsp,zaamo,zalrsc,zba,zbb,zicsr,zifencei,zmmul") }, + { str_lit("rocket"), str_lit("") }, + { str_lit("rocket-rv32"), str_lit("32bit,i,zicsr,zifencei") }, + { str_lit("rocket-rv64"), str_lit("64bit,i,zicsr,zifencei") }, + { str_lit("rp2350-hazard3"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zba,zbb,zbkb,zbs,zca,zcb,zcmp,zicsr,zifencei,zmmul") }, + { str_lit("sifive-7-series"), str_lit("no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler") }, + { str_lit("sifive-e20"), str_lit("32bit,c,i,m,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e21"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e24"), str_lit("32bit,a,c,f,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e31"), str_lit("32bit,a,c,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e34"), str_lit("32bit,a,c,f,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-e76"), str_lit("32bit,a,c,f,i,m,no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-p450"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,za64rs,zaamo,zalrsc,zba,zbb,zbs,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul") }, + { str_lit("sifive-p470"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,xsifivecdiscarddlone,xsifivecflushdlone,za64rs,zaamo,zalrsc,zba,zbb,zbs,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("sifive-p550"), str_lit("64bit,a,auipc-addi-fusion,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zba,zbb,zicsr,zifencei,zmmul") }, + { str_lit("sifive-p670"), str_lit("64bit,a,auipc-addi-fusion,b,c,conditional-cmv-fusion,d,f,i,lui-addi-fusion,m,no-default-unroll,no-sink-splat-operands,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,vxrm-pipeline-flush,za64rs,zaamo,zalrsc,zba,zbb,zbs,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicsr,zifencei,zihintntl,zihintpause,zihpm,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvkb,zvkg,zvkn,zvknc,zvkned,zvkng,zvknhb,zvks,zvksc,zvksed,zvksg,zvksh,zvkt,zvl128b,zvl32b,zvl64b") }, + { str_lit("sifive-s21"), str_lit("64bit,a,c,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-s51"), str_lit("64bit,a,c,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-s54"), str_lit("64bit,a,c,d,f,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-s76"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zihintpause,zmmul") }, + { str_lit("sifive-u54"), str_lit("64bit,a,c,d,f,i,m,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-u74"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,short-forward-branch-opt,sifive7,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("sifive-x280"), str_lit("64bit,a,c,d,dlen-factor-2,f,i,m,no-default-unroll,optimized-nf2-segment-load-store,optimized-zero-stride-load,short-forward-branch-opt,sifive7,use-postra-scheduler,v,zaamo,zalrsc,zba,zbb,zfh,zfhmin,zicsr,zifencei,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvl128b,zvl256b,zvl32b,zvl512b,zvl64b") }, + { str_lit("spacemit-x60"), str_lit("64bit,a,b,c,d,dlen-factor-2,f,i,m,optimized-nf2-segment-load-store,optimized-nf3-segment-load-store,optimized-nf4-segment-load-store,ssccptr,sscofpmf,sscounterenw,sstc,sstvala,sstvecd,svade,svbare,svinval,svnapot,svpbmt,unaligned-scalar-mem,v,vxrm-pipeline-flush,za64rs,zaamo,zalrsc,zba,zbb,zbc,zbkc,zbs,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintpause,zihpm,zkt,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvfh,zvfhmin,zvkt,zvl128b,zvl256b,zvl32b,zvl64b") }, + { str_lit("syntacore-scr1-base"), str_lit("32bit,c,i,no-default-unroll,zicsr,zifencei") }, + { str_lit("syntacore-scr1-max"), str_lit("32bit,c,i,m,no-default-unroll,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr3-rv32"), str_lit("32bit,c,i,m,no-default-unroll,use-postra-scheduler,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr3-rv64"), str_lit("64bit,a,c,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr4-rv32"), str_lit("32bit,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr4-rv64"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr5-rv32"), str_lit("32bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr5-rv64"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,zaamo,zalrsc,zicsr,zifencei,zmmul") }, + { str_lit("syntacore-scr7"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,use-postra-scheduler,v,zaamo,zalrsc,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zicsr,zifencei,zkn,zknd,zkne,zknh,zmmul,zve32f,zve32x,zve64d,zve64f,zve64x,zvl128b,zvl32b,zvl64b") }, + { str_lit("tt-ascalon-d8"), str_lit("64bit,a,b,c,d,f,h,i,m,no-default-unroll,optimized-zero-stride-load,sha,shcounterenw,shgatpa,shtvala,shvsatpa,shvstvala,shvstvecd,smaia,ssaia,ssccptr,sscofpmf,sscounterenw,ssnpm,ssstateen,ssstrict,sstc,sstvala,sstvecd,ssu64xl,supm,svade,svbare,svinval,svnapot,svpbmt,unaligned-scalar-mem,unaligned-vector-mem,use-postra-scheduler,v,za64rs,zaamo,zalrsc,zawrs,zba,zbb,zbs,zca,zcb,zcmop,zfa,zfbfmin,zfh,zfhmin,zic64b,zicbom,zicbop,zicboz,ziccamoa,ziccif,zicclsm,ziccrse,zicntr,zicond,zicsr,zifencei,zihintntl,zihintpause,zihpm,zimop,zkt,zmmul,zvbb,zvbc,zve32f,zve32x,zve64d,zve64f,zve64x,zvfbfmin,zvfbfwma,zvfh,zvfhmin,zvkb,zvkg,zvkn,zvkned,zvkng,zvknhb,zvkt,zvl128b,zvl256b,zvl32b,zvl64b") }, + { str_lit("veyron-v1"), str_lit("64bit,a,auipc-addi-fusion,c,d,f,i,ld-add-fusion,lui-addi-fusion,m,shifted-zextw-fusion,ventana-veyron,xventanacondops,zaamo,zalrsc,zba,zbb,zbc,zbs,zexth-fusion,zextw-fusion,zicbom,zicbop,zicboz,zicntr,zicsr,zifencei,zihintpause,zihpm,zmmul") }, + { str_lit("xiangshan-nanhu"), str_lit("64bit,a,c,d,f,i,m,no-default-unroll,shifted-zextw-fusion,svinval,zaamo,zalrsc,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zexth-fusion,zextw-fusion,zicbom,zicboz,zicsr,zifencei,zkn,zknd,zkne,zknh,zksed,zksh,zmmul") }, +}; +#else // Generated with the featuregen script in `misc/featuregen` gb_global String target_microarch_list[TargetArch_COUNT] = { // TargetArch_Invalid: @@ -514,3 +1072,4 @@ gb_global MicroarchFeatureList microarch_features_list[] = { { str_lit("veyron-v1"), str_lit("64bit,a,auipc-addi-fusion,c,d,f,ld-add-fusion,lui-addi-fusion,m,shifted-zextw-fusion,ventana-veyron,xventanacondops,zba,zbb,zbc,zbs,zexth-fusion,zextw-fusion,zicbom,zicbop,zicboz,zicntr,zicsr,zifencei,zihintpause,zihpm") }, { str_lit("xiangshan-nanhu"), str_lit("64bit,a,c,d,f,m,svinval,zba,zbb,zbc,zbkb,zbkc,zbkx,zbs,zicbom,zicboz,zicsr,zifencei,zkn,zknd,zkne,zknh,zksed,zksh") }, }; +#endif diff --git a/src/bundle_command.cpp b/src/bundle_command.cpp new file mode 100644 index 000000000..7abd48104 --- /dev/null +++ b/src/bundle_command.cpp @@ -0,0 +1,212 @@ +i32 bundle_android(String init_directory); + +i32 bundle(String init_directory) { + switch (build_context.command_kind) { + case Command_bundle_android: + return bundle_android(init_directory); + } + gb_printf_err("Unknown odin package \n"); + return 1; +} + + +i32 bundle_android(String original_init_directory) { + TEMPORARY_ALLOCATOR_GUARD(); + + i32 result = 0; + init_android_values(/*with_sdk*/true); + + bool init_directory_ok = false; + String init_directory = path_to_fullpath(temporary_allocator(), original_init_directory, &init_directory_ok); + if (!init_directory_ok) { + gb_printf_err("Error: '%.*s' is not a valid directory", LIT(original_init_directory)); + return 1; + } + init_directory = normalize_path(temporary_allocator(), init_directory, NIX_SEPARATOR_STRING); + + int const ODIN_ANDROID_API_LEVEL = build_context.ODIN_ANDROID_API_LEVEL; + + String android_sdk_build_tools = concatenate3_strings(temporary_allocator(), + build_context.ODIN_ANDROID_SDK, str_lit("build-tools"), NIX_SEPARATOR_STRING); + + Array list = {}; + ReadDirectoryError rd_err = read_directory(android_sdk_build_tools, &list); + defer (array_free(&list)); + + switch (rd_err) { + case ReadDirectory_InvalidPath: + gb_printf_err("Invalid path: %.*s\n", LIT(android_sdk_build_tools)); + return 1; + case ReadDirectory_NotExists: + gb_printf_err("Path does not exist: %.*s\n", LIT(android_sdk_build_tools)); + return 1; + case ReadDirectory_Permission: + gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools)); + return 1; + case ReadDirectory_NotDir: + gb_printf_err("Expected a directory for a package, got a file: %.*s\n", LIT(android_sdk_build_tools)); + return 1; + case ReadDirectory_Empty: + gb_printf_err("Empty directory: %.*s\n", LIT(android_sdk_build_tools)); + return 1; + case ReadDirectory_Unknown: + gb_printf_err("Unknown error whilst reading path %.*s\n", LIT(android_sdk_build_tools)); + return 1; + } + + auto possible_valid_dirs = array_make(heap_allocator(), 0, list.count); + defer (array_free(&possible_valid_dirs)); + + + for (FileInfo fi : list) if (fi.is_dir) { + bool all_numbers = true; + for (isize i = 0; i < fi.name.len; i++) { + u8 c = fi.name[i]; + if ('0' <= c && c <= '9') { + // true + } else if (i == 0) { + all_numbers = false; + } else if (c == '.') { + break; + } else { + all_numbers = false; + } + } + + if (all_numbers) { + array_add(&possible_valid_dirs, fi); + } + } + + if (possible_valid_dirs.count == 0) { + gb_printf_err("Unable to find any Android SDK/API Level in %.*s\n", LIT(android_sdk_build_tools)); + return 1; + } + + int *dir_numbers = temporary_alloc_array(possible_valid_dirs.count); + + char buf[1024] = {}; + for_array(i, possible_valid_dirs) { + FileInfo fi = possible_valid_dirs[i]; + isize n = gb_min(gb_size_of(buf)-1, fi.name.len); + memcpy(buf, fi.name.text, n); + buf[n] = 0; + + dir_numbers[i] = atoi(buf); + } + + isize closest_number_idx = -1; + for (isize i = 0; i < possible_valid_dirs.count; i++) { + if (dir_numbers[i] >= ODIN_ANDROID_API_LEVEL) { + if (closest_number_idx < 0) { + closest_number_idx = i; + } else if (dir_numbers[i] < dir_numbers[closest_number_idx]) { + closest_number_idx = i; + } + } + } + + if (closest_number_idx < 0) { + gb_printf_err("Unable to find any Android SDK/API Level in %.*s meeting the minimum API level of %d\n", LIT(android_sdk_build_tools), ODIN_ANDROID_API_LEVEL); + return 1; + } + + String api_number = possible_valid_dirs[closest_number_idx].name; + + android_sdk_build_tools = concatenate_strings(temporary_allocator(), android_sdk_build_tools, api_number); + String android_sdk_platforms = concatenate_strings(temporary_allocator(), + build_context.ODIN_ANDROID_SDK, + make_string_c(gb_bprintf("platforms/android-%d/", dir_numbers[closest_number_idx])) + ); + + android_sdk_build_tools = normalize_path(temporary_allocator(), android_sdk_build_tools, NIX_SEPARATOR_STRING); + android_sdk_platforms = normalize_path(temporary_allocator(), android_sdk_platforms, NIX_SEPARATOR_STRING); + + gbString cmd = gb_string_make(heap_allocator(), ""); + defer (gb_string_free(cmd)); + + + String output_filename = str_lit("test"); + String output_apk = path_remove_extension(output_filename); + + TIME_SECTION("Android aapt"); + { + TEMPORARY_ALLOCATOR_GUARD(); + gb_string_clear(cmd); + + String manifest = concatenate_strings(temporary_allocator(), init_directory, str_lit("AndroidManifest.xml")); + + cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len); + cmd = gb_string_appendc(cmd, "aapt"); + cmd = gb_string_appendc(cmd, " package -f"); + cmd = gb_string_append_fmt(cmd, " -M \"%.*s\"", LIT(manifest)); + cmd = gb_string_append_fmt(cmd, " -I \"%.*sandroid.jar\"", LIT(android_sdk_platforms)); + cmd = gb_string_append_fmt(cmd, " -F \"%.*s.apk-build\"", LIT(output_apk)); + + String resources_dir = concatenate_strings(temporary_allocator(), init_directory, str_lit("res")); + if (gb_file_exists((const char *)resources_dir.text)) { + cmd = gb_string_append_fmt(cmd, " -S \"%.*s\"", LIT(resources_dir)); + } + + String assets_dir = concatenate_strings(temporary_allocator(), init_directory, str_lit("assets")); + if (gb_file_exists((const char *)assets_dir.text)) { + cmd = gb_string_append_fmt(cmd, " -A \"%.*s\"", LIT(assets_dir)); + } + + String lib_dir = concatenate_strings(temporary_allocator(), init_directory, str_lit("lib")); + if (gb_file_exists((const char *)lib_dir.text)) { + cmd = gb_string_append_fmt(cmd, " \"%.*s\"", LIT(lib_dir)); + } + + result = system_exec_command_line_app("android-aapt", cmd); + if (result) { + return result; + } + } + + TIME_SECTION("Android zipalign"); + { + TEMPORARY_ALLOCATOR_GUARD(); + gb_string_clear(cmd); + + cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len); + cmd = gb_string_appendc(cmd, "zipalign"); + cmd = gb_string_appendc(cmd, " -f 4"); + cmd = gb_string_append_fmt(cmd, " \"%.*s.apk-build\" \"%.*s.apk\"", LIT(output_apk), LIT(output_apk)); + + result = system_exec_command_line_app("android-zipalign", cmd); + if (result) { + return result; + } + } + + TIME_SECTION("Android apksigner"); + { + TEMPORARY_ALLOCATOR_GUARD(); + gb_string_clear(cmd); + + cmd = gb_string_append_length(cmd, android_sdk_build_tools.text, android_sdk_build_tools.len); + cmd = gb_string_appendc(cmd, "apksigner"); + cmd = gb_string_appendc(cmd, " sign"); + + String keystore = normalize_path(temporary_allocator(), build_context.android_keystore, NIX_SEPARATOR_STRING); + keystore = substring(keystore, 0, keystore.len - 1); + cmd = gb_string_append_fmt(cmd, " --ks \"%.*s\"", LIT(keystore)); + + if (build_context.android_keystore_alias.len != 0) { + cmd = gb_string_append_fmt(cmd, " --ks-key-alias \"%.*s\"", LIT(build_context.android_keystore_alias)); + } + if (build_context.android_keystore_password.len != 0) { + cmd = gb_string_append_fmt(cmd, " --ks-pass pass:\"%.*s\"", LIT(build_context.android_keystore_password)); + } + + cmd = gb_string_append_fmt(cmd, " \"%.*s.apk\"", LIT(output_apk)); + + result = system_exec_command_line_app("android-apksigner", cmd); + if (result) { + return result; + } + } + + return 0; +} diff --git a/src/cached.cpp b/src/cached.cpp index efdadce7b..61b5d01b4 100644 --- a/src/cached.cpp +++ b/src/cached.cpp @@ -231,7 +231,7 @@ Array cache_gather_envs() { wchar_t *curr_string = strings; while (curr_string && *curr_string) { - String16 wstr = make_string16_c(curr_string); + String16 wstr = make_string16_c(cast(u16 *)curr_string); curr_string += wstr.len+1; String str = string16_to_string(temporary_allocator(), wstr); if (string_starts_with(str, str_lit("CURR_DATE_TIME="))) { diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 023aeff73..f142f04b7 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1,5 +1,14 @@ typedef bool (BuiltinTypeIsProc)(Type *t); +gb_internal int enum_constant_entity_cmp(void const* a, void const* b) { + Entity const *ea = *(cast(Entity const **)a); + Entity const *eb = *(cast(Entity const **)b); + GB_ASSERT(ea->kind == Entity_Constant && eb->kind == Entity_Constant); + GB_ASSERT(ea->Constant.value.kind == ExactValue_Integer && eb->Constant.value.kind == ExactValue_Integer); + + return big_int_cmp(&ea->Constant.value.value_integer, &eb->Constant.value.value_integer); +} + gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - BuiltinProc__type_simple_boolean_begin] = { nullptr, // BuiltinProc__type_simple_boolean_begin @@ -10,6 +19,7 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool is_type_complex, is_type_quaternion, is_type_string, + is_type_string16, is_type_typeid, is_type_any, is_type_endian_platform, @@ -23,6 +33,7 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool is_type_sliceable, is_type_comparable, is_type_simple_compare, + is_type_nearly_simple_compare, is_type_dereferenceable, is_type_valid_for_keys, is_type_valid_for_matrix_elems, @@ -41,6 +52,7 @@ gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_bool is_type_enum, is_type_proc, is_type_bit_set, + is_type_bit_field, is_type_simd_vector, is_type_matrix, @@ -147,6 +159,11 @@ gb_internal bool does_require_msgSend_stret(Type *return_type) { if (return_type == nullptr) { return false; } + + if (build_context.metrics.os != TargetOs_darwin) { + return false; + } + if (build_context.metrics.arch == TargetArch_i386 || build_context.metrics.arch == TargetArch_amd64) { i64 struct_limit = type_size_of(t_uintptr) << 1; return type_size_of(return_type) > struct_limit; @@ -193,7 +210,7 @@ gb_internal ObjcMsgKind get_objc_proc_kind(Type *return_type) { return ObjcMsg_normal; } -gb_internal void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice param_types) { +void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice param_types) { ObjcMsgKind kind = get_objc_proc_kind(return_type); Scope *scope = create_scope(c->info, nullptr); @@ -223,14 +240,20 @@ gb_internal void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_t data.kind = kind; data.proc_type = alloc_type_proc(scope, params, param_types.count, results, results->Tuple.variables.count, false, ProcCC_CDecl); - mutex_lock(&c->info->objc_types_mutex); + mutex_lock(&c->info->objc_objc_msgSend_mutex); map_set(&c->info->objc_msgSend_types, call, data); - mutex_unlock(&c->info->objc_types_mutex); + mutex_unlock(&c->info->objc_objc_msgSend_mutex); try_to_add_package_dependency(c, "runtime", "objc_msgSend"); try_to_add_package_dependency(c, "runtime", "objc_msgSend_fpret"); try_to_add_package_dependency(c, "runtime", "objc_msgSend_fp2ret"); try_to_add_package_dependency(c, "runtime", "objc_msgSend_stret"); + + Slice args = call->CallExpr.args; + if (args.count > 0 && args[0]->tav.objc_super_target) { + try_to_add_package_dependency(c, "runtime", "objc_msgSendSuper2"); + try_to_add_package_dependency(c, "runtime", "objc_msgSendSuper2_stret"); + } } gb_internal bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) { @@ -337,7 +360,7 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan } isize const arg_offset = 1; - auto param_types = slice_make(permanent_allocator(), ce->args.count-arg_offset); + auto param_types = permanent_slice_make(ce->args.count-arg_offset); param_types[0] = t_objc_id; param_types[1] = sel_type; @@ -387,6 +410,328 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan try_to_add_package_dependency(c, "runtime", "objc_allocateClassPair"); return true; } break; + + case BuiltinProc_objc_ivar_get: + { + Type *self_type = nullptr; + + Operand self = {}; + check_expr_or_type(c, &self, ce->args[0]); + + if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) { + gbString e = expr_to_string(self.expr); + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } else if (!is_type_pointer(self.type)) { + gbString e = expr_to_string(self.expr); + gbString t = type_to_string(self.type); + error(self.expr, "'%.*s' expected a pointer of a value derived from intrinsics.objc_object, got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + + self_type = type_deref(self.type); + + if (!(self_type->kind == Type_Named && + self_type->Named.type_name != nullptr && + self_type->Named.type_name->TypeName.objc_class_name != "")) { + gbString t = type_to_string(self_type); + error(self.expr, "'%.*s' expected a named type with the attribute @(objc_class=) , got type %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + Type *ivar_type = self_type->Named.type_name->TypeName.objc_ivar; + if (ivar_type == nullptr) { + gbString t = type_to_string(self_type); + error(self.expr, "'%.*s' requires that type %s have the attribute @(objc_ivar=).", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + if (type_hint != nullptr && type_hint->kind == Type_Pointer && type_hint->Pointer.elem == ivar_type) { + operand->type = type_hint; + } else { + operand->type = alloc_type_pointer(ivar_type); + } + + operand->mode = Addressing_Value; + return true; + + } break; + + case BuiltinProc_objc_block: + { + // NOTE(harold): The last argument specified in the call is the handler proc, + // any other arguments before it are capture by-copy arguments. + auto param_operands = permanent_slice_make(ce->args.count); + + isize capture_arg_count = ce->args.count - 1; + + // NOTE(harold): The first argument is already checked at check_builtin_procedure(). + // Checking again would invalidate the Entity -> Value map for direct arguments if it's the handler proc. + param_operands[0] = *operand; + + for (isize i = 0; i < ce->args.count-1; i++) { + Operand x = {}; + check_expr(c, &x, ce->args[i]); + + switch (x.mode) { + case Addressing_Value: + case Addressing_Context: + case Addressing_Variable: + case Addressing_Constant: + param_operands[i] = x; + break; + + default: + gbString e = expr_to_string(x.expr); + gbString t = type_to_string(x.type); + error(x.expr, "'%.*s' capture arguments must be values, but got %s of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + } + + // Validate handler proc + Operand handler = {}; + + if (capture_arg_count == 0) { + // It's already been checked and assigned + handler = param_operands[0]; + } else { + check_expr_or_type(c, &handler, ce->args[capture_arg_count]); + param_operands[capture_arg_count] = handler; + } + + if (!is_operand_value(handler) || handler.type->kind != Type_Proc) { + gbString e = expr_to_string(handler.expr); + gbString t = type_to_string(handler.type); + error(handler.expr, "'%.*s' expected a procedure, but got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + + Ast *handler_node = unparen_expr(handler.expr); + + // Only direct reference to procs are allowed + switch (handler_node->kind) { + case Ast_ProcLit: break; // ok + case Ast_Ident: { + auto& ident = handler_node->Ident; + + if (ident.entity == nullptr) { + error(handler.expr, "'%.*s' failed to resolve entity from expression", LIT(builtin_name)); + return false; + } + + if (ident.entity->kind != Entity_Procedure) { + gbString e = expr_to_string(handler_node); + + ERROR_BLOCK(); + error(handler.expr, "'%.*s' expected a direct reference to a procedure", LIT(builtin_name)); + if(ident.entity->kind == Entity_Variable) { + error_line("\tSuggestion: Variables referencing a procedure are not allowed, they are not a direct procedure reference."); + } else { + error_line("\tSuggestion: Ensure '%s' is not a runtime-evaluated expression.", e); // NOTE(harold): Is this case possible to hit? + } + error_line("\n\t Refer to a procedure directly by its name or declare it anonymously: %.*s(proc(){})", LIT(builtin_name)); + + gb_string_free(e); + return false; + } + } break; + + default: { + gbString e = expr_to_string(handler_node); + ERROR_BLOCK(); + error(handler.expr, "'%.*s' expected a direct reference to a procedure", LIT(builtin_name)); + if( handler_node->kind == Ast_CallExpr) { + error_line("\tSuggestion: Do not use a procedure returned from another procedure."); + } else { + error_line("\tSuggestion: Ensure '%s' is not a runtime-evaluated expression.", e); + } + error_line("\n\t Refer to a procedure directly by its name or declare it anonymously: %.*s(proc(){})", LIT(builtin_name)); + + gb_string_free(e); + } return false; + } // End switch + + auto& handler_type_proc = handler.type->Proc; + + if (capture_arg_count > handler_type_proc.param_count) { + error(handler.expr, "'%.*s' captured arguments exceeded the handler's parameter count", LIT(builtin_name)); + return false; + } + + // If the handler proc is odin calling convention, but there must be a context defined in this scope. + if (handler_type_proc.calling_convention == ProcCC_Odin) { + if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) { + ERROR_BLOCK(); + error(handler.expr, "The handler procedure for '%.*s' requires a context, but no context is defined in the current scope", LIT(builtin_name)); + error_line("\tSuggestion: 'context = runtime.default_context()', or use the \"c\" calling convention for the handler procedure"); + return false; + } + } + + // At most a single return value is supported + if (handler_type_proc.result_count > 1) { + error(handler_type_proc.node->ProcType.results, "Handler procedures for '%.*s' cannot have multiple return values", LIT(builtin_name)); + return false; + } + + // Ensure that captured args are assignable to the handler's corresponding capture params + if (handler_type_proc.param_count > 0) { + auto& handler_param_types = handler.type->Proc.params->Tuple.variables; + Slice handler_capture_param_types = slice(handler_param_types, handler_param_types.count - capture_arg_count, handler_param_types.count); + + for (isize i = 0; i < capture_arg_count; i++) { + Operand op = param_operands[i]; + if (!check_is_assignable_to(c, &op, handler_capture_param_types[i]->type)) { + gbString e = expr_to_string(op.expr); + gbString src = type_to_string(op.type); + gbString dst = type_to_string(handler_capture_param_types[i]->type); + error(op.expr, "'%.*s' captured value '%s' of type '%s' is not assignable to type '%s'", LIT(builtin_name), e, src, dst); + gb_string_free(e); + gb_string_free(src); + gb_string_free(dst); + return false; + } + } + } + + ProcCallingConvention cc = handler_type_proc.calling_convention; + switch (cc) { + case ProcCC_Odin: + case ProcCC_Contextless: + case ProcCC_CDecl: + break; // ok + default: + ERROR_BLOCK(); + + error(handler.expr, "'%.*s' Invalid calling convention for block procedure.", LIT(builtin_name)); + error_line("\tSuggestion: Do not specify a calling convention ot else use \"c\" or \"cotextless\""); + return false; + } + + if (handler_type_proc.is_polymorphic) { + error(handler.expr, "'%.*s' Unspecialized polymorphic procedures are not allowed.", LIT(builtin_name)); + return false; + } + + // Create the specialized Objc_Block type that this intrinsic will return + Token ident = {}; + ident.kind = Token_Ident; + ident.string = str_lit("Objc_Block"); + ident.pos = ast_token(call).pos; + + Token l_paren = {}; + l_paren.kind = Token_OpenParen; + l_paren.string = str_lit("("); + l_paren.pos = ident.pos; + + Token r_paren = {}; + r_paren.kind = Token_CloseParen; + l_paren.string = str_lit(")"); + r_paren.pos = ident.pos; + + // Remove the capture args from the resulting Objc_Block type signature + Ast* handler_proc_type_copy = clone_ast(handler_type_proc.node); + handler_proc_type_copy->ProcType.params->FieldList.list.count -= capture_arg_count; + + // Make sure the Objc_Block's specialized proc is always "c" calling conv, + // even if we have a context, as the invoker is always "c". + // This allows us to have compatibility with the target block types with either calling convention used. + handler_proc_type_copy->ProcType.calling_convention = ProcCC_CDecl; + + Array poly_args = {}; + array_init(&poly_args, permanent_allocator(), 1, 1); + poly_args[0] = handler_proc_type_copy; + + + Type *t_Objc_Block = find_core_type(c->checker, str_lit("Objc_Block")); + Operand poly_op = {}; + poly_op.type = t_Objc_Block; + poly_op.mode = Addressing_Type; + + Ast *poly_call = ast_call_expr(nullptr, ast_ident(nullptr, ident), poly_args, l_paren, r_paren, {}); + + auto err = check_polymorphic_record_type(c, &poly_op, poly_call); + + if (err != 0) { + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + error(handler.expr, "'%.*s' failed to determine resulting Objc_Block handler procedure", LIT(builtin_name)); + return false; + } + + GB_ASSERT(poly_op.type != t_Objc_Block); + GB_ASSERT(poly_op.mode == Addressing_Type); + + bool is_global_block = capture_arg_count == 0 && handler_type_proc.calling_convention != ProcCC_Odin; + if (is_global_block) { + try_to_add_package_dependency(c, "runtime", "_NSConcreteGlobalBlock"); + } else { + try_to_add_package_dependency(c, "runtime", "_NSConcreteStackBlock"); + } + + *operand = poly_op; + operand->type = alloc_type_pointer(operand->type); + operand->mode = Addressing_Value; + return true; + } break; + + case BuiltinProc_objc_super: + { + // Must be a pointer to an Objective-C object. + Type *objc_obj = operand->type; + if (!is_type_objc_ptr_to_object(objc_obj)) { + gbString e = expr_to_string(operand->expr); + gbString t = type_to_string(objc_obj); + error(operand->expr, "'%.*s' expected a pointer to an Objective-C object, but got '%s' of type %s", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + + if (operand->mode != Addressing_Value && operand->mode != Addressing_Variable) { + gbString e = expr_to_string(operand->expr); + gbString t = type_to_string(operand->type); + error(operand->expr, "'%.*s' expression '%s', of type %s, must be a value or variable.", LIT(builtin_name), e, t); + gb_string_free(t); + gb_string_free(e); + return false; + } + + Type *obj_type = type_deref(objc_obj); + GB_ASSERT(obj_type->kind == Type_Named); + + // NOTE(harold) Track original type before transforming it to the superclass. + // This is needed because objc_msgSendSuper2 must start its search on the subclass, not the superclass. + call->tav.objc_super_target = obj_type; + + // The superclass type must be known at compile time. We require this so that the selector method expressions + // methods are resolved to the superclass's methods instead of the subclass's. + Type *superclass = obj_type->Named.type_name->TypeName.objc_superclass; + if (superclass == nullptr) { + gbString t = type_to_string(obj_type); + error(operand->expr, "'%.*s' target object '%.*s' does not have an Objective-C superclass. One must be set via the @(objc_superclass) attribute", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + GB_ASSERT(superclass->Named.type_name->TypeName.objc_class_name.len > 0); + + operand->type = alloc_type_pointer(superclass); + return true; + + } break; } } @@ -645,6 +990,13 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan break; } + if (!are_types_identical(x.type, y.type)) { + gbString tx = type_to_string(x.type); + gbString ty = type_to_string(y.type); + error(call, "Mismatched types to '%.*s', '%s' vs '%s'", LIT(builtin_name), tx, ty); + gb_string_free(ty); + gb_string_free(tx); + } Type *vt = base_type(x.type); GB_ASSERT(vt->kind == Type_SimdVector); @@ -753,6 +1105,36 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return true; } + case BuiltinProc_simd_indices: + { + Operand x = {}; + check_expr_or_type(c, &x, ce->args[0], nullptr); + if (x.mode == Addressing_Invalid) return false; + if (x.mode != Addressing_Type) { + gbString s = expr_to_string(x.expr); + error(x.expr, "'%.*s' expected a simd vector type, got '%s'", LIT(builtin_name), s); + gb_string_free(s); + return false; + } + if (!is_type_simd_vector(x.type)) { + gbString s = type_to_string(x.type); + error(x.expr, "'%.*s' expected a simd vector type, got '%s'", LIT(builtin_name), s); + gb_string_free(s); + return false; + } + + Type *elem = base_array_type(x.type); + if (!is_type_numeric(elem)) { + gbString s = type_to_string(x.type); + error(x.expr, "'%.*s' expected a simd vector type with a numeric element type, got '%s'", LIT(builtin_name), s); + gb_string_free(s); + } + + operand->mode = Addressing_Value; + operand->type = x.type; + return true; + } + case BuiltinProc_simd_extract: { Operand x = {}; @@ -816,8 +1198,12 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan } break; + case BuiltinProc_simd_reduce_add_bisect: + case BuiltinProc_simd_reduce_mul_bisect: case BuiltinProc_simd_reduce_add_ordered: case BuiltinProc_simd_reduce_mul_ordered: + case BuiltinProc_simd_reduce_add_pairs: + case BuiltinProc_simd_reduce_mul_pairs: case BuiltinProc_simd_reduce_min: case BuiltinProc_simd_reduce_max: { @@ -1050,6 +1436,58 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan return true; } + case BuiltinProc_simd_runtime_swizzle: + { + if (ce->args.count != 2) { + error(call, "'%.*s' expected 2 arguments, got %td", LIT(builtin_name), ce->args.count); + return false; + } + + Operand src = {}; + Operand indices = {}; + check_expr(c, &src, ce->args[0]); if (src.mode == Addressing_Invalid) return false; + check_expr_with_type_hint(c, &indices, ce->args[1], src.type); if (indices.mode == Addressing_Invalid) return false; + + if (!is_type_simd_vector(src.type)) { + error(src.expr, "'%.*s' expected first argument to be a simd vector", LIT(builtin_name)); + return false; + } + if (!is_type_simd_vector(indices.type)) { + error(indices.expr, "'%.*s' expected second argument (indices) to be a simd vector", LIT(builtin_name)); + return false; + } + + Type *src_elem = base_array_type(src.type); + Type *indices_elem = base_array_type(indices.type); + + if (!is_type_integer(src_elem)) { + gbString src_str = type_to_string(src.type); + error(src.expr, "'%.*s' expected first argument to be a simd vector of integers, got '%s'", LIT(builtin_name), src_str); + gb_string_free(src_str); + return false; + } + + if (!is_type_integer(indices_elem)) { + gbString indices_str = type_to_string(indices.type); + error(indices.expr, "'%.*s' expected indices to be a simd vector of integers, got '%s'", LIT(builtin_name), indices_str); + gb_string_free(indices_str); + return false; + } + + if (!are_types_identical(src.type, indices.type)) { + gbString src_str = type_to_string(src.type); + gbString indices_str = type_to_string(indices.type); + error(indices.expr, "'%.*s' expected both arguments to have the same type, got '%s' vs '%s'", LIT(builtin_name), src_str, indices_str); + gb_string_free(indices_str); + gb_string_free(src_str); + return false; + } + + operand->mode = Addressing_Value; + operand->type = src.type; + return true; + } + case BuiltinProc_simd_ceil: case BuiltinProc_simd_floor: case BuiltinProc_simd_trunc: @@ -1675,12 +2113,16 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o } if (ce->args.count > 0) { Ast *arg = ce->args[0]; - Operand o = {}; - Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true); - if (e == nullptr || (e->flags & EntityFlag_Param) == 0) { - error(ce->args[0], "'#caller_expression' expected a valid earlier parameter name"); + if (arg->kind != Ast_Ident) { + error(arg, "'#caller_expression' expected an identifier"); + } else { + Operand o = {}; + Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true); + if (e == nullptr || (e->flags & EntityFlag_Param) == 0) { + error(arg, "'#caller_expression' expected a valid earlier parameter name"); + } + arg->Ident.entity = e; } - arg->Ident.entity = e; } operand->type = t_string; @@ -2048,6 +2490,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_atomic_type_is_lock_free: case BuiltinProc_has_target_feature: case BuiltinProc_procedure_of: + case BuiltinProc_simd_indices: // NOTE(bill): The first arg may be a Type, this will be checked case by case break; @@ -2121,7 +2564,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_objc_find_selector: case BuiltinProc_objc_find_class: case BuiltinProc_objc_register_selector: - case BuiltinProc_objc_register_class: + case BuiltinProc_objc_register_class: + case BuiltinProc_objc_ivar_get: + case BuiltinProc_objc_block: + case BuiltinProc_objc_super: return check_builtin_objc_procedure(c, operand, call, id, type_hint); case BuiltinProc___entry_point: @@ -2160,13 +2606,23 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (is_type_string(op_type) && id == BuiltinProc_len) { if (operand->mode == Addressing_Constant) { mode = Addressing_Constant; - String str = operand->value.value_string; - value = exact_value_i64(str.len); + + if (operand->value.kind == ExactValue_String) { + String str = operand->value.value_string; + value = exact_value_i64(str.len); + } else if (operand->value.kind == ExactValue_String16) { + String16 str = operand->value.value_string16; + value = exact_value_i64(str.len); + } else { + GB_PANIC("Unhandled value kind: %d", operand->value.kind); + } type = t_untyped_integer; } else { mode = Addressing_Value; if (is_type_cstring(op_type)) { add_package_dependency(c, "runtime", "cstring_len"); + } else if (is_type_cstring16(op_type)) { + add_package_dependency(c, "runtime", "cstring16_len"); } } } else if (is_type_array(op_type)) { @@ -2218,7 +2674,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (mode == Addressing_Invalid) { gbString t = type_to_string(operand->type); - error(call, "'%.*s' is not supported for '%s'", LIT(builtin_name), t); + if (is_type_bit_set(op_type) && id == BuiltinProc_len) { + error(call, "'%.*s' is not supported for '%s', did you mean 'card'?", LIT(builtin_name), t); + } else { + error(call, "'%.*s' is not supported for '%s'", LIT(builtin_name), t); + } return false; } @@ -2771,8 +3231,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // quaternion :: proc(imag, jmag, kmag, real: float_type) -> complex_type Operand xyzw[4] = {}; - u32 first_index = 0; - // NOTE(bill): Invalid will be the default till fixed operand->type = t_invalid; operand->mode = Addressing_Invalid; @@ -2817,6 +3275,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (fields_set[*index]) { error(field->field, "Previously assigned field: '%.*s'", LIT(name)); + return false; } fields_set[*index] = style; @@ -2833,7 +3292,6 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (!ok || index < 0) { return false; } - first_index = cast(u32)index; *refs[index] = o; } @@ -2858,12 +3316,17 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } - for (u32 i = 0; i < 4; i++ ){ - u32 j = (i + first_index) % 4; - if (j == first_index) { - convert_to_typed(c, &xyzw[j], xyzw[(first_index+1)%4].type); if (xyzw[j].mode == Addressing_Invalid) return false; - } else { - convert_to_typed(c, &xyzw[j], xyzw[first_index].type); if (xyzw[j].mode == Addressing_Invalid) return false; + // The first typed value found, if any exist, will dictate the type for all untyped values. + for (u32 i = 0; i < 4; i++) { + if (is_type_typed(xyzw[i].type)) { + for (u32 j = 0; j < 4; j++) { + // `convert_to_typed` should check if it is typed already. + convert_to_typed(c, &xyzw[j], xyzw[i].type); + if (xyzw[j].mode == Addressing_Invalid) { + return false; + } + } + break; } } if (xyzw[0].mode == Addressing_Constant && @@ -2887,7 +3350,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As gbString ty = type_to_string(xyzw[1].type); gbString tz = type_to_string(xyzw[2].type); gbString tw = type_to_string(xyzw[3].type); - error(call, "Mismatched types to 'quaternion', 'x=%s' vs 'y=%s' vs 'z=%s' vs 'w=%s'", tx, ty, tz, tw); + error(call, "Mismatched types to 'quaternion', 'w=%s' vs 'x=%s' vs 'y=%s' vs 'z=%s'", tw, tx, ty, tz); gb_string_free(tw); gb_string_free(tz); gb_string_free(ty); @@ -2923,7 +3386,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->mode = Addressing_Constant; } - BasicKind kind = core_type(xyzw[first_index].type)->Basic.kind; + BasicKind kind = core_type(xyzw[0].type)->Basic.kind; switch (kind) { case Basic_f16: operand->type = t_quaternion64; break; case Basic_f32: operand->type = t_quaternion128; break; @@ -3143,6 +3606,194 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } + case BuiltinProc_compress_values: { + Operand *ops = temporary_alloc_array(ce->args.count); + + isize value_count = 0; + + for_array(i, ce->args) { + Ast *arg = ce->args[i]; + Operand *op = &ops[i]; + check_multi_expr(c, op, arg); + if (op->mode == Addressing_Invalid) { + return false; + } + + if (op->type == nullptr || op->type == t_invalid) { + gbString s = expr_to_string(op->expr); + error(op->expr, "Invalid expression to '%.*s', got %s", LIT(builtin_name), s); + gb_string_free(s); + } + if (is_type_tuple(op->type)) { + value_count += op->type->Tuple.variables.count; + } else { + value_count += 1; + } + } + + GB_ASSERT(value_count >= 1); + + if (value_count == 1) { + *operand = ops[0]; + break; + } + + if (type_hint != nullptr) { + Type *th = base_type(type_hint); + if (th->kind == Type_Struct) { + if (value_count == th->Struct.fields.count) { + isize index = 0; + for_array(i, ce->args) { + Operand *op = &ops[i]; + if (is_type_tuple(op->type)) { + for (Entity *v : op->type->Tuple.variables) { + Operand x = {}; + x.mode = Addressing_Value; + x.type = v->type; + check_assignment(c, &x, th->Struct.fields[index++]->type, builtin_name); + if (x.mode == Addressing_Invalid) { + return false; + } + } + } else { + check_assignment(c, op, th->Struct.fields[index++]->type, builtin_name); + if (op->mode == Addressing_Invalid) { + return false; + } + } + } + + operand->type = type_hint; + operand->mode = Addressing_Value; + break; + } + } else if (is_type_array_like(th)) { + if (cast(i64)value_count == get_array_type_count(th)) { + Type *elem = base_array_type(th); + for_array(i, ce->args) { + Operand *op = &ops[i]; + if (is_type_tuple(op->type)) { + for (Entity *v : op->type->Tuple.variables) { + Operand x = {}; + x.mode = Addressing_Value; + x.type = v->type; + check_assignment(c, &x, elem, builtin_name); + if (x.mode == Addressing_Invalid) { + return false; + } + } + } else { + check_assignment(c, op, elem, builtin_name); + if (op->mode == Addressing_Invalid) { + return false; + } + } + } + + operand->type = type_hint; + operand->mode = Addressing_Value; + break; + } + } + } + + bool all_types_the_same = true; + Type *last_type = nullptr; + for_array(i, ce->args) { + Operand *op = &ops[i]; + if (is_type_tuple(op->type)) { + if (last_type == nullptr) { + op->type->Tuple.variables[0]->type; + } + for (Entity *v : op->type->Tuple.variables) { + if (!are_types_identical(last_type, v->type)) { + all_types_the_same = false; + break; + } + last_type = v->type; + } + } else { + if (last_type == nullptr) { + last_type = op->type; + } else { + if (!are_types_identical(last_type, op->type)) { + all_types_the_same = false; + break; + } + last_type = op->type; + } + } + } + + if (all_types_the_same) { + Type *elem_type = default_type(last_type); + if (is_type_untyped(elem_type)) { + gbString s = expr_to_string(call); + error(call, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name)); + gb_string_free(s); + return false; + } + + operand->type = alloc_type_array(elem_type, value_count); + operand->mode = Addressing_Value; + } else { + Type *st = alloc_type_struct_complete(); + st->Struct.fields = permanent_slice_make(value_count); + st->Struct.tags = permanent_alloc_array(value_count); + st->Struct.offsets = permanent_alloc_array(value_count); + + Scope *scope = create_scope(c->info, nullptr); + + Token token = {}; + token.kind = Token_Ident; + token.pos = ast_token(call).pos; + + isize index = 0; + for_array(i, ce->args) { + Operand *op = &ops[i]; + if (is_type_tuple(op->type)) { + for (Entity *v : op->type->Tuple.variables) { + Type *t = default_type(v->type); + if (is_type_untyped(t)) { + gbString s = expr_to_string(op->expr); + error(op->expr, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name)); + gb_string_free(s); + return false; + } + + gbString s = gb_string_make_reserve(permanent_allocator(), 32); + s = gb_string_append_fmt(s, "v%lld", cast(long long)index); + token.string = make_string_c(s); + Entity *e = alloc_entity_field(scope, token, t, false, cast(i32)index, EntityState_Resolved); + st->Struct.fields[index++] = e; + } + } else { + Type *t = default_type(op->type); + if (is_type_untyped(t)) { + gbString s = expr_to_string(op->expr); + error(op->expr, "Invalid use of '%s' in '%.*s'", s, LIT(builtin_name)); + gb_string_free(s); + return false; + } + + gbString s = gb_string_make_reserve(permanent_allocator(), 32); + s = gb_string_append_fmt(s, "v%lld", cast(long long)index); + token.string = make_string_c(s); + Entity *e = alloc_entity_field(scope, token, t, false, cast(i32)index, EntityState_Resolved); + st->Struct.fields[index++] = e; + } + } + + + gb_unused(type_size_of(st)); + + operand->type = st; + operand->mode = Addressing_Value; + } + break; + } + + case BuiltinProc_min: { // min :: proc($T: typeid) -> ordered // min :: proc(a: ..ordered) -> ordered @@ -3789,7 +4440,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As elem = alloc_type_struct(); elem->Struct.scope = s; elem->Struct.fields = slice_from_array(fields); - elem->Struct.tags = gb_alloc_array(permanent_allocator(), String, fields.count); + elem->Struct.tags = permanent_alloc_array(fields.count); elem->Struct.node = dummy_node_struct; type_set_offsets(elem); wait_signal_set(&elem->Struct.fields_wait_signal); @@ -3821,7 +4472,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As gb_string_free(s); return false; } - auto types = slice_make(permanent_allocator(), t->Struct.fields.count-1); + auto types = permanent_slice_make(t->Struct.fields.count-1); for_array(i, types) { Entity *f = t->Struct.fields[i]; GB_ASSERT(f->type->kind == Type_MultiPointer); @@ -4157,8 +4808,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (is_type_array(elem)) { Type *old_array = base_type(elem); soa_struct = alloc_type_struct(); - soa_struct->Struct.fields = slice_make(heap_allocator(), cast(isize)old_array->Array.count); - soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, cast(isize)old_array->Array.count); + soa_struct->Struct.fields = permanent_slice_make(cast(isize)old_array->Array.count); + soa_struct->Struct.tags = permanent_alloc_array(cast(isize)old_array->Array.count); soa_struct->Struct.node = operand->expr; soa_struct->Struct.soa_kind = StructSoa_Fixed; soa_struct->Struct.soa_elem = elem; @@ -4190,8 +4841,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Type *old_struct = base_type(elem); soa_struct = alloc_type_struct(); - soa_struct->Struct.fields = slice_make(heap_allocator(), old_struct->Struct.fields.count); - soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, old_struct->Struct.fields.count); + soa_struct->Struct.fields = permanent_slice_make(old_struct->Struct.fields.count); + soa_struct->Struct.tags = permanent_alloc_array(old_struct->Struct.fields.count); soa_struct->Struct.node = operand->expr; soa_struct->Struct.soa_kind = StructSoa_Fixed; soa_struct->Struct.soa_elem = elem; @@ -4321,7 +4972,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; case Type_Basic: if (t->Basic.kind == Basic_string) { - operand->type = alloc_type_multi_pointer(t_u8); + operand->type = t_u8_multi_ptr; + } else if (t->Basic.kind == Basic_string16) { + operand->type = t_u16_multi_ptr; } break; case Type_Pointer: @@ -4351,6 +5004,15 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } break; + case BuiltinProc_read_cycle_counter_frequency: + if (build_context.metrics.arch != TargetArch_arm64) { + error(call, "'%.*s' is only allowed on arm64 targets", LIT(builtin_name)); + return false; + } + operand->mode = Addressing_Value; + operand->type = t_i64; + break; + case BuiltinProc_read_cycle_counter: operand->mode = Addressing_Value; operand->type = t_i64; @@ -5301,7 +5963,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } if (sz >= 64) { - if (is_type_unsigned(x.type)) { + if (is_type_unsigned(x.type) || is_type_unsigned(y.type)) { add_package_dependency(c, "runtime", "umodti3", true); add_package_dependency(c, "runtime", "udivti3", true); } else { @@ -5539,6 +6201,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case Type_EnumeratedArray: operand->type = bt->EnumeratedArray.elem; break; case Type_Slice: operand->type = bt->Slice.elem; break; case Type_DynamicArray: operand->type = bt->DynamicArray.elem; break; + case Type_SimdVector: operand->type = bt->SimdVector.elem; break; } } operand->mode = Addressing_Type; @@ -5571,7 +6234,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } Type *new_type = alloc_type_union(); - auto variants = slice_make(permanent_allocator(), bt->Union.variants.count); + auto variants = permanent_slice_make(bt->Union.variants.count); for_array(i, bt->Union.variants) { variants[i] = alloc_type_pointer(bt->Union.variants[i]); } @@ -5588,6 +6251,87 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } operand->mode = Addressing_Type; break; + case BuiltinProc_type_integer_to_unsigned: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + + if (is_type_polymorphic(operand->type)) { + gbString t = type_to_string(operand->type); + error(operand->expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + { + Type *bt = base_type(operand->type); + + if (bt->kind != Type_Basic || + (bt->Basic.flags & BasicFlag_Unsigned) != 0 || + (bt->Basic.flags & BasicFlag_Integer) == 0) { + gbString t = type_to_string(operand->type); + error(operand->expr, "Expected a signed integer type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + if ((bt->Basic.flags & BasicFlag_Untyped) != 0) { + gbString t = type_to_string(operand->type); + error(operand->expr, "Expected a non-untyped integer type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + Type *u_type = &basic_types[bt->Basic.kind + 1]; + + operand->type = u_type; + } + break; + case BuiltinProc_type_integer_to_signed: + if (operand->mode != Addressing_Type) { + error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + + if (is_type_polymorphic(operand->type)) { + gbString t = type_to_string(operand->type); + error(operand->expr, "Expected a non-polymorphic type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + { + Type *bt = base_type(operand->type); + + if (bt->kind != Type_Basic || + (bt->Basic.flags & BasicFlag_Unsigned) == 0 || + (bt->Basic.flags & BasicFlag_Integer) == 0) { + gbString t = type_to_string(operand->type); + error(operand->expr, "Expected an unsigned integer type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + if ((bt->Basic.flags & BasicFlag_Untyped) != 0) { + gbString t = type_to_string(operand->type); + error(operand->expr, "Expected a non-untyped integer type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + if (bt->Basic.kind == Basic_uintptr) { + gbString t = type_to_string(operand->type); + error(operand->expr, "Type %s does not have a signed integer mapping for '%.*s'", t, LIT(builtin_name)); + gb_string_free(t); + return false; + } + + Type *u_type = &basic_types[bt->Basic.kind - 1]; + + operand->type = u_type; + } + break; case BuiltinProc_type_merge: { operand->mode = Addressing_Type; @@ -5679,6 +6423,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_type_is_complex: case BuiltinProc_type_is_quaternion: case BuiltinProc_type_is_string: + case BuiltinProc_type_is_string16: case BuiltinProc_type_is_typeid: case BuiltinProc_type_is_any: case BuiltinProc_type_is_endian_platform: @@ -5692,6 +6437,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_type_is_sliceable: case BuiltinProc_type_is_comparable: case BuiltinProc_type_is_simple_compare: + case BuiltinProc_type_is_nearly_simple_compare: case BuiltinProc_type_is_dereferenceable: case BuiltinProc_type_is_valid_map_key: case BuiltinProc_type_is_valid_matrix_elements: @@ -5708,6 +6454,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_type_is_enum: case BuiltinProc_type_is_proc: case BuiltinProc_type_is_bit_set: + case BuiltinProc_type_is_bit_field: case BuiltinProc_type_is_simd_vector: case BuiltinProc_type_is_matrix: case BuiltinProc_type_is_specialized_polymorphic_record: @@ -5989,12 +6736,13 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As // NOTE(jakubtomsu): forces calculation of variant_block_size type_size_of(u); - i64 tag_offset = u->Union.variant_block_size; - GB_ASSERT(tag_offset > 0); + // NOTE(Jeroen): A tag offset of zero is perfectly fine if all members of the union are empty structs. + // What matters is that the tag size is > 0. + GB_ASSERT(u->Union.tag_size > 0); operand->mode = Addressing_Constant; operand->type = t_untyped_integer; - operand->value = exact_value_i64(tag_offset); + operand->value = exact_value_i64(u->Union.variant_block_size); } break; @@ -6538,6 +7286,50 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } + case BuiltinProc_type_enum_is_contiguous: + { + Operand op = {}; + Type *bt = check_type(c, ce->args[0]); + Type *type = base_type(bt); + if (type == nullptr || type == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (!is_type_enum(type)) { + gbString t = type_to_string(type); + error(ce->args[0], "Expected an enum type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + auto enum_constants = array_make(temporary_allocator(), type->Enum.fields.count); + array_copy(&enum_constants, type->Enum.fields, 0); + array_sort(enum_constants, enum_constant_entity_cmp); + + BigInt minus_one = big_int_make_i64(-1); + defer (big_int_dealloc(&minus_one)); + BigInt diff = {}; + + bool contiguous = true; + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + + for (isize i = 0; i < enum_constants.count - 1; i++) { + BigInt curr = enum_constants[i]->Constant.value.value_integer; + BigInt next = enum_constants[i + 1]->Constant.value.value_integer; + big_int_sub(&diff, &curr, &next); + defer (big_int_dealloc(&diff)); + + if (!big_int_is_zero(&diff) && big_int_cmp(&diff, &minus_one) != 0) { + contiguous = false; + break; + } + } + + operand->value = exact_value_bool(contiguous); + break; + } + case BuiltinProc_type_equal_proc: { Operand op = {}; @@ -6619,6 +7411,22 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } + case BuiltinProc_type_canonical_name: + { + Operand op = {}; + Type *type = check_type(c, ce->args[0]); + Type *bt = base_type(type); + if (bt == nullptr || bt == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + + operand->mode = Addressing_Constant; + operand->type = t_untyped_string; + operand->value = exact_value_string(type_to_canonical_string(permanent_allocator(), type)); + break; + } + case BuiltinProc_procedure_of: { Ast *call_expr = unparen_expr(ce->args[0]); @@ -6671,7 +7479,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } operand->mode = Addressing_Value; - operand->type = alloc_type_multi_pointer(t_u16); + if (type_hint != nullptr && is_type_cstring16(type_hint)) { + operand->type = type_hint; + } else { + operand->type = alloc_type_multi_pointer(t_u16); + } operand->value = {}; break; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 5607ea725..fa4eade0f 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -145,13 +145,6 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l if (d != nullptr) { d->init_expr = o->expr; } - - if (o->type && is_type_no_copy(o->type)) { - ERROR_BLOCK(); - if (check_no_copy_assignment(*o, str_lit("initialization"))) { - error_line("\tInitialization of a #no_copy type must be either implicitly zero, a constant literal, or a return value from a call expression"); - } - } } if (rhs_count > 0 && lhs_count != rhs_count) { error(lhs[0]->token, "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count); @@ -169,8 +162,6 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e if (found_scope == nullptr) { return; } - rw_mutex_lock(&found_scope->mutex); - defer (rw_mutex_unlock(&found_scope->mutex)); // IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the // original entity was still used check checked, but the checking was only @@ -179,7 +170,9 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e // Therefore two things can be done: the type can be assigned to state that it // has been "evaluated" and the variant data can be copied across + rw_mutex_lock(&found_scope->mutex); string_map_set(&found_scope->elements, original_name, new_entity); + rw_mutex_unlock(&found_scope->mutex); original_entity->flags |= EntityFlag_Overridden; original_entity->type = new_entity->type; @@ -468,6 +461,10 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, } e->type = named; + if (!is_distinct) { + e->TypeName.is_type_alias = true; + } + check_type_path_push(ctx, e); Type *bt = check_type_expr(ctx, te, named); check_type_path_pop(ctx); @@ -502,9 +499,9 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, if (!is_distinct) { e->type = bt; named->Named.base = bt; - e->TypeName.is_type_alias = true; } + e->TypeName.is_type_alias = !is_distinct; if (decl->type_expr != nullptr) { Type *t = check_type(ctx, decl->type_expr); @@ -520,12 +517,95 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, if (decl != nullptr) { AttributeContext ac = {}; check_decl_attributes(ctx, decl->attributes, type_decl_attribute, &ac); + if (e->kind == Entity_TypeName && ac.objc_class != "") { + e->TypeName.objc_class_name = ac.objc_class; + if (ac.objc_is_implementation) { + e->TypeName.objc_is_implementation = ac.objc_is_implementation; + e->TypeName.objc_superclass = ac.objc_superclass; + e->TypeName.objc_ivar = ac.objc_ivar; + e->TypeName.objc_context_provider = ac.objc_context_provider; + + mutex_lock(&ctx->info->objc_class_name_mutex); + bool class_exists = string_set_update(&ctx->info->obcj_class_name_set, ac.objc_class); + mutex_unlock(&ctx->info->objc_class_name_mutex); + if (class_exists) { + error(e->token, "@(objc_class) name '%.*s' has already been used elsewhere", LIT(ac.objc_class)); + } + + mpsc_enqueue(&ctx->info->objc_class_implementations, e); + + GB_ASSERT(e->TypeName.objc_ivar == nullptr || e->TypeName.objc_ivar->kind == Type_Named); + + // Enqueue the contex_provider proc to be checked after it is resolved + if (e->TypeName.objc_context_provider != nullptr) { + mpsc_enqueue(&ctx->checker->procs_with_objc_context_provider_to_check, e); + } + + // TODO(harold): I think there's a Check elsewhere in the checker for checking cycles. + // See about moving this to the right location. + // Ensure superclass hierarchy are all Objective-C classes and does not cycle + + // NOTE(harold): We check for superclass unconditionally (before checking if super is null) + // because this should be the case 99.99% of the time. Not subclassing something that + // is, or is the child of, NSObject means the objc runtime messaging will not properly work on this type. + TypeSet super_set{}; + type_set_init(&super_set, 8); + defer (type_set_destroy(&super_set)); + + type_set_update(&super_set, e->type); + + Type *super = ac.objc_superclass; + while (super != nullptr) { + if (type_set_update(&super_set, super)) { + error(e->token, "@(objc_superclass) Superclass hierarchy cycle encountered"); + break; + } + + check_single_global_entity(ctx->checker, super->Named.type_name, super->Named.type_name->decl_info); + + if (super->kind != Type_Named) { + error(e->token, "@(objc_superclass) Referenced type must be a named struct"); + break; + } + + Type* named_type = base_named_type(super); + GB_ASSERT(named_type->kind == Type_Named); + + if (!is_type_objc_object(named_type)) { + error(e->token, "@(objc_superclass) Superclass '%.*s' must be an Objective-C class", LIT(named_type->Named.name)); + break; + } + + if (named_type->Named.type_name->TypeName.objc_class_name == "") { + error(e->token, "@(objc_superclass) Superclass '%.*s' must have a valid @(objc_class) attribute", LIT(named_type->Named.name)); + break; + } + + super = named_type->Named.type_name->TypeName.objc_superclass; + } + } else { + if (ac.objc_ivar != nullptr) { + error(e->token, "@(objc_ivar) may only be applied when the @(obj_implement) attribute is also applied"); + } else if (ac.objc_context_provider != nullptr) { + error(e->token, "@(objc_context_provider) may only be applied when the @(obj_implement) attribute is also applied"); + } + } + if (type_size_of(e->type) > 0) { error(e->token, "@(objc_class) marked type must be of zero size"); } + } else if (ac.objc_is_implementation) { + error(e->token, "@(objc_implement) may only be applied when the @(objc_class) attribute is also applied"); + } + + if (ac.raddbg_type_view) { + RaddbgTypeView type_view = {}; + type_view.type = e->type; + type_view.view = ac.raddbg_type_view_string; + mpsc_enqueue(&ctx->info->raddbg_type_views_queue, type_view); } } @@ -628,6 +708,10 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr Operand x = {}; x.type = entity->type; x.mode = Addressing_Variable; + if (entity->kind == Entity_Constant) { + x.mode = Addressing_Constant; + x.value = entity->Constant.value; + } if (!check_is_assignable_to(ctx, &x, e->type)) { gbString expr_str = expr_to_string(init); gbString op_type_str = type_to_string(entity->type); @@ -736,6 +820,12 @@ gb_internal bool signature_parameter_similar_enough(Type *x, Type *y) { if (sig_compare(is_type_cstring, is_type_u8_multi_ptr, x, y)) { return true; } + if (sig_compare(is_type_cstring16, is_type_u16_ptr, x, y)) { + return true; + } + if (sig_compare(is_type_cstring16, is_type_u16_multi_ptr, x, y)) { + return true; + } if (sig_compare(is_type_uintptr, is_type_rawptr, x, y)) { return true; @@ -759,6 +849,50 @@ gb_internal bool signature_parameter_similar_enough(Type *x, Type *y) { } } + Type *x_base = base_type(x); + Type *y_base = base_type(y); + + if (x_base == y_base) { + return true; + } + + if (x_base->kind == y_base->kind && + x_base->kind == Type_Struct) { + i64 xs = type_size_of(x_base); + i64 ys = type_size_of(y_base); + + i64 xa = type_align_of(x_base); + i64 ya = type_align_of(y_base); + + + if (x_base->Struct.is_raw_union == y_base->Struct.is_raw_union && + xs == ys && xa == ya) { + if (xs > 16) { + // @@ABI NOTE(bill): Just allow anything over 16-bytes to be allowed, because on all current ABIs + // it will be passed by point + // NOTE(bill): this must be changed when ABI changes + return true; + } + if (x_base->Struct.is_raw_union) { + return true; + } + if (x->Struct.fields.count == y->Struct.fields.count) { + for (isize i = 0; i < x->Struct.fields.count; i++) { + Entity *a = x->Struct.fields[i]; + Entity *b = y->Struct.fields[i]; + bool similar = signature_parameter_similar_enough(a->type, b->type); + if (!similar) { + // NOTE(bill): If the fields are not similar enough, then stop. + goto end; + } + } + } + // HACK NOTE(bill): Allow this for the time begin until it actually becomes a practical problem + return true; + } + } + +end:; return are_types_identical(x, y); } @@ -856,7 +990,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) error(ident, "foreign library names must be an identifier"); } else { String name = ident->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name); + Entity *found = scope_lookup(ctx->scope, name, ident->Ident.hash); if (found == nullptr) { if (is_blank_ident(name)) { @@ -914,61 +1048,167 @@ gb_internal String handle_link_name(CheckerContext *ctx, Token token, String lin } -gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeContext const &ac) { - if (!(ac.objc_name.len || ac.objc_is_class_method || ac.objc_type)) { +gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeContext &ac) { + if (!ac.objc_type) { return; } - if (ac.objc_name.len == 0 && ac.objc_is_class_method) { - error(e->token, "@(objc_name) is required with @(objc_is_class_method)"); - } else if (ac.objc_type == nullptr) { - error(e->token, "@(objc_name) requires that @(objc_type) to be set"); - } else if (ac.objc_name.len == 0 && ac.objc_type) { - error(e->token, "@(objc_name) is required with @(objc_type)"); + + Type *t = ac.objc_type; + GB_ASSERT(t->kind == Type_Named); // NOTE(harold): This is already checked for at the attribute resolution stage. + + // Attempt to infer th objc_name automatically if the proc name contains + // the type name objc_type's name, followed by an underscore, as a prefix. + if (ac.objc_name.len == 0) { + String proc_name = e->token.string; + String type_name = t->Named.name; + + if (proc_name.len > type_name.len + 1 && + proc_name[type_name.len] == '_' && + str_eq(type_name, substring(proc_name, 0, type_name.len)) + ) { + ac.objc_name = substring(proc_name, type_name.len+1, proc_name.len); + } else { + error(e->token, "@(objc_name) requires that @(objc_type) be set or inferred " + "by prefixing the proc name with the type and underscore: MyObjcType_myProcName :: proc()."); + } + } + + Entity *tn = t->Named.type_name; + GB_ASSERT(tn->kind == Entity_TypeName); + + if (tn->scope != e->scope) { + error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope"); } else { - Type *t = ac.objc_type; - if (t->kind == Type_Named) { - Entity *tn = t->Named.type_name; + // Enable implementation by default if the class is an implementer too and + // @objc_implement was not set to false explicitly in this proc. + bool implement = tn->TypeName.objc_is_implementation; + if( ac.objc_is_implementation && !tn->TypeName.objc_is_implementation ) { + error(e->token, "Cannot apply @(objc_is_implement) to a procedure whose type does not also have @(objc_is_implement) set"); + } - GB_ASSERT(tn->kind == Entity_TypeName); + if (ac.objc_is_disabled_implement) { + implement = false; + } - if (tn->scope != e->scope) { - error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope"); - } else { - mutex_lock(&global_type_name_objc_metadata_mutex); - defer (mutex_unlock(&global_type_name_objc_metadata_mutex)); + String objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name; - if (!tn->TypeName.objc_metadata) { - tn->TypeName.objc_metadata = create_type_name_obj_c_metadata(); - } - auto *md = tn->TypeName.objc_metadata; - mutex_lock(md->mutex); - defer (mutex_unlock(md->mutex)); + if (e->kind == Entity_Procedure) { + bool has_body = e->decl_info->proc_lit->ProcLit.body != nullptr; + e->Procedure.is_objc_impl_or_import = implement || !has_body; + e->Procedure.is_objc_class_method = ac.objc_is_class_method; + e->Procedure.objc_selector_name = objc_selector; + e->Procedure.objc_class = tn; - if (!ac.objc_is_class_method) { - bool ok = true; - for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { - if (entry.name == ac.objc_name) { - error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); - ok = false; - break; - } - } - if (ok) { - array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); - } + auto &proc = e->type->Proc; + Type *first_param = proc.param_count > 0 ? proc.params->Tuple.variables[0]->type : t_untyped_nil; + + if (implement) { + if( !has_body ) { + error(e->token, "Procedures with @(objc_is_implement) must have a body"); + } else if (!tn->TypeName.objc_is_implementation) { + error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied"); + } else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) { + error(e->token, "Objective-C instance methods implementations require the first parameter to be a pointer to the class type set by @(objc_type)"); + } else if (proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) { + error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set"); + } else if (ac.objc_is_class_method && proc.calling_convention != ProcCC_CDecl) { + error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention"); + } else if (proc.result_count > 1) { + error(e->token, "Objective-C method implementations may return at most 1 value"); } else { - bool ok = true; - for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { - if (entry.name == ac.objc_name) { - error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); - ok = false; - break; - } + // Always export unconditionally + // NOTE(harold): This means check_objc_methods() MUST be called before + // e->Procedure.is_export is set in check_proc_decl()! + if (ac.is_export) { + error(e->token, "Explicit export not allowed when @(objc_implement) is set. It set exported implicitly"); } - if (ok) { - array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); + if (ac.link_name != "") { + error(e->token, "Explicit linkage not allowed when @(objc_implement) is set. It set to \"strong\" implicitly"); + } + + ac.is_export = true; + ac.linkage = STR_LIT("strong"); + + auto method = ObjcMethodData{ ac, e }; + method.ac.objc_selector = objc_selector; + + CheckerInfo *info = ctx->info; + mutex_lock(&info->objc_method_mutex); + defer (mutex_unlock(&info->objc_method_mutex)); + + Array* method_list = map_get(&info->objc_method_implementations, t); + if (method_list) { + array_add(method_list, method); + } else { + auto list = array_make(permanent_allocator(), 1, 8); + list[0] = method; + + map_set(&info->objc_method_implementations, t, list); } } + } else if (!has_body) { + if (ac.objc_selector == "The @(objc_selector) attribute is required for imported Objective-C methods.") { + return; + } else if (proc.calling_convention != ProcCC_CDecl) { + error(e->token, "Imported Objective-C methods must use the \"c\" calling convention"); + return; + } else if (tn->TypeName.objc_context_provider) { + error(e->token, "Imported Objective-C class '%.*s' must not declare context providers.", tn->type->Named.name); + return; + } else if (tn->TypeName.objc_is_implementation) { + error(e->token, "Imported Objective-C methods used in a class with @(objc_implement) is not allowed."); + return; + } else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) { + error(e->token, "Objective-C instance methods require the first parameter to be a pointer to the class type set by @(objc_type)"); + return; + } + } + else if(ac.objc_selector != "") { + error(e->token, "@(objc_selector) may only be applied to procedures that are Objective-C method implementations or are imported."); + return; + } + } else { + GB_ASSERT(e->kind == Entity_ProcGroup); + if (tn->TypeName.objc_is_implementation) { + error(e->token, "Objective-C procedure groups cannot use the @(objc_implement) attribute."); + return; + } + } + + + mutex_lock(&global_type_name_objc_metadata_mutex); + defer (mutex_unlock(&global_type_name_objc_metadata_mutex)); + + if (!tn->TypeName.objc_metadata) { + tn->TypeName.objc_metadata = create_type_name_obj_c_metadata(); + } + auto *md = tn->TypeName.objc_metadata; + mutex_lock(md->mutex); + defer (mutex_unlock(md->mutex)); + + if (!ac.objc_is_class_method) { + bool ok = true; + for (TypeNameObjCMetadataEntry const &entry : md->value_entries) { + if (entry.name == ac.objc_name) { + error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); + ok = false; + break; + } + } + if (ok) { + array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); + } + } else { + bool ok = true; + for (TypeNameObjCMetadataEntry const &entry : md->type_entries) { + if (entry.name == ac.objc_name) { + error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name)); + ok = false; + break; + } + } + if (ok) { + array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e}); } } } @@ -1137,6 +1377,9 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { break; } + // NOTE(harold): For Objective-C method implementations, this must happen after + // check_objc_methods() is called as it re-sets ac.is_export to true unconditionally. + // The same is true for the linkage, set below. e->Procedure.entry_point_only = ac.entry_point_only; e->Procedure.is_export = ac.is_export; @@ -1186,12 +1429,16 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { has_instrumentation = false; e->flags |= EntityFlag_Require; } else if (ac.instrumentation_enter) { + init_core_source_code_location(ctx->checker); if (!is_valid_instrumentation_call(e->type)) { init_core_source_code_location(ctx->checker); gbString s = type_to_string(e->type); error(e->token, "@(instrumentation_enter) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s); gb_string_free(s); } + if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { + error(e->token, "@(instrumentation_enter) procedures must be declared at the file scope"); + } MUTEX_GUARD(&ctx->info->instrumentation_mutex); if (ctx->info->instrumentation_enter_entity != nullptr) { error(e->token, "@(instrumentation_enter) has already been set"); @@ -1208,6 +1455,9 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { error(e->token, "@(instrumentation_exit) procedures must have the type '%s', got %s", instrumentation_proc_type_str, s); gb_string_free(s); } + if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { + error(e->token, "@(instrumentation_exit) procedures must be declared at the file scope"); + } MUTEX_GUARD(&ctx->info->instrumentation_mutex); if (ctx->info->instrumentation_exit_entity != nullptr) { error(e->token, "@(instrumentation_exit) has already been set"); @@ -1221,6 +1471,8 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { e->Procedure.has_instrumentation = has_instrumentation; + e->Procedure.no_sanitize_address = ac.no_sanitize_address; + e->Procedure.no_sanitize_memory = ac.no_sanitize_memory; e->deprecated_message = ac.deprecated_message; e->warning_message = ac.warning_message; @@ -1236,6 +1488,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } } + // NOTE(harold): See export/linkage note above(where is_export is assigned) regarding Objective-C method implementations bool is_foreign = e->Procedure.is_foreign; bool is_export = e->Procedure.is_export; @@ -1307,7 +1560,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (!pt->is_polymorphic) { check_procedure_later(ctx->checker, ctx->file, e->token, d, proc_type, pl->body, pl->tags); } - } else if (!is_foreign) { + } else if (!is_foreign && !e->Procedure.is_objc_impl_or_import) { if (e->Procedure.is_export) { error(e->token, "Foreign export procedures must have a body"); } else { @@ -1355,6 +1608,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { // NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later mpsc_enqueue(&ctx->info->foreign_decls_to_check, e); } else { + // TODO(harold): Check if it's an objective-C foreign, if so, I don't think we need to check it. check_foreign_procedure(ctx, e, d); } } else { @@ -1377,7 +1631,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { "\tother at %s", LIT(name), token_pos_to_string(pos)); } else if (name == "main") { - if (d->entity->pkg->kind != Package_Runtime) { + if (d->entity.load()->pkg->kind != Package_Runtime) { error(d->proc_lit, "The link name 'main' is reserved for internal use"); } } else { @@ -1393,7 +1647,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { } } -gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) { +gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) { GB_ASSERT(e->type == nullptr); GB_ASSERT(e->kind == Entity_Variable); @@ -1514,7 +1768,28 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast check_expr_with_type_hint(ctx, &o, init_expr, e->type); check_init_variable(ctx, e, &o, str_lit("variable declaration")); if (e->Variable.is_rodata && o.mode != Addressing_Constant) { + ERROR_BLOCK(); error(o.expr, "Variables declared with @(rodata) must have constant initialization"); + Ast *expr = unparen_expr(o.expr); + if (is_type_struct(e->type) && expr && expr->kind == Ast_CompoundLit) { + ast_node(cl, CompoundLit, expr); + for (Ast *elem_ : cl->elems) { + Ast *elem = elem_; + if (elem->kind == Ast_FieldValue) { + elem = elem->FieldValue.value; + } + elem = unparen_expr(elem); + + Entity *e = entity_of_node(elem); + if (elem->tav.mode != Addressing_Constant && e == nullptr && elem->kind != Ast_ProcLit) { + Token tok = ast_token(elem); + TokenPos pos = tok.pos; + gbString s = type_to_string(type_of_expr(elem)); + error_line("%s Element is not constant, which is required for @(rodata), of type %s\n", token_pos_to_string(pos), s); + gb_string_free(s); + } + } + } } check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed"); @@ -1686,6 +1961,17 @@ gb_internal void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, c.scope = d->scope; c.decl = d; c.type_level = 0; + c.curr_proc_calling_convention = ProcCC_Contextless; + + auto prev_flags = c.scope->flags; + defer (c.scope->flags = prev_flags); + + if (check_feature_flags(ctx, d->decl_node) & OptInFeatureFlag_GlobalContext) { + c.scope->flags |= ScopeFlag_ContextDefined; + } else { + c.scope->flags &= ~ScopeFlag_ContextDefined; + } + e->parent_proc_decl = c.curr_proc_decl; e->state = EntityState_InProgress; @@ -1732,7 +2018,7 @@ gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) { rw_mutex_shared_lock(&decl->deps_mutex); rw_mutex_lock(&decl->parent->deps_mutex); - for (Entity *e : decl->deps) { + FOR_PTR_SET(e, decl->deps) { ptr_set_add(&decl->parent->deps, e); } @@ -1784,8 +2070,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de ctx->curr_proc_sig = type; ctx->curr_proc_calling_convention = type->Proc.calling_convention; - if (decl->parent && decl->entity && decl->parent->entity) { - decl->entity->parent_proc_decl = decl->parent; + if (decl->parent && decl->entity.load() && decl->parent->entity) { + decl->entity.load()->parent_proc_decl = decl->parent; } if (ctx->pkg->name != "runtime") { @@ -1798,9 +2084,9 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de ast_node(bs, BlockStmt, body); + TEMPORARY_ALLOCATOR_GUARD(); Array using_entities = {}; - using_entities.allocator = heap_allocator(); - defer (array_free(&using_entities)); + using_entities.allocator = temporary_allocator(); { if (type->Proc.param_count > 0) { @@ -1889,7 +2175,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de GB_ASSERT(decl->proc_checked_state != ProcCheckedState_Checked); if (decl->defer_use_checked) { GB_ASSERT(is_type_polymorphic(type, true)); - error(token, "Defer Use Checked: %.*s", LIT(decl->entity->token.string)); + error(token, "Defer Use Checked: %.*s", LIT(decl->entity.load()->token.string)); GB_ASSERT(decl->defer_use_checked == false); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index bd1c34044..251f196a5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -129,6 +129,8 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type gb_internal bool is_exact_value_zero(ExactValue const &v); +gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(CheckerContext *c, Ast *node); + enum LoadDirectiveResult { LoadDirective_Success = 0, LoadDirective_Error = 1, @@ -263,6 +265,9 @@ gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char gb_internal Entity *entity_from_expr(Ast *expr) { expr = unparen_expr(expr); + if (expr == nullptr) { + return nullptr; + } switch (expr->kind) { case Ast_Ident: return expr->Ident.entity; @@ -582,6 +587,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E d->proc_lit = proc_lit; d->proc_checked_state = ProcCheckedState_Unchecked; d->defer_use_checked = false; + d->para_poly_original = old_decl->entity; Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags); entity->state.store(EntityState_Resolved); @@ -603,7 +609,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E entity->flags |= EntityFlag_Disabled; } - d->entity = entity; + d->entity.store(entity); AstFile *file = nullptr; { @@ -643,7 +649,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E gb_internal bool check_polymorphic_procedure_assignment(CheckerContext *c, Operand *operand, Type *type, Ast *poly_def_node, PolyProcData *poly_proc_data) { if (operand->expr == nullptr) return false; - Entity *base_entity = entity_of_node(operand->expr); + Entity *base_entity = entity_from_expr(operand->expr); if (base_entity == nullptr) return false; return find_or_generate_polymorphic_procedure(c, base_entity, type, nullptr, poly_def_node, poly_proc_data); } @@ -816,9 +822,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand } } - if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) { - if (c->in_enum_type) { - return 3; + if (c != nullptr) { + if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) { + if (c->in_enum_type) { + return 3; + } } } @@ -863,6 +871,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand if (are_types_identical(vt, s)) { return 1; } + if (is_type_proc(vt)) { + if (are_types_identical(base_type(vt), src)) { + return 1; + } + } } if (dst->Union.variants.count == 1) { @@ -990,14 +1003,34 @@ gb_internal i64 assign_score_function(i64 distance, bool is_variadic=false) { gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *operand, Type *type, i64 *score_, bool is_variadic=false, bool allow_array_programming=true) { - i64 score = 0; - i64 distance = check_distance_between_types(c, operand, type, allow_array_programming); - bool ok = distance >= 0; - if (ok) { - score = assign_score_function(distance, is_variadic); + if (c == nullptr) { + GB_ASSERT(operand->mode == Addressing_Value); + GB_ASSERT(is_type_typed(operand->type)); } - if (score_) *score_ = score; - return ok; + if (operand->mode == Addressing_Invalid || type == t_invalid) { + if (score_) *score_ = 0; + return false; + } + + // Handle polymorphic procedure used as default parameter + if (operand->mode == Addressing_Value && is_type_proc(type) && is_type_proc(operand->type)) { + Entity *e = entity_from_expr(operand->expr); + if (e != nullptr && e->kind == Entity_Procedure && is_type_polymorphic(e->type) && !is_type_polymorphic(type)) { + // Special case: Allow a polymorphic procedure to be used as default value for concrete proc type + // during the initial check. It will be properly instantiated when actually used. + if (score_) *score_ = assign_score_function(1); + return true; + } + } + + i64 score = check_distance_between_types(c, operand, type, allow_array_programming); + if (score >= 0) { + if (score_) *score_ = assign_score_function(score, is_variadic); + return true; + } + + if (score_) *score_ = 0; + return false; } @@ -1708,7 +1741,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam o->expr = n; String name = n->Ident.token.string; - Entity *e = scope_lookup(c->scope, name); + Entity *e = scope_lookup(c->scope, name, n->Ident.hash); if (e == nullptr) { if (is_blank_ident(name)) { error(n, "'_' cannot be used as a value"); @@ -1849,7 +1882,10 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam o->type = t_invalid; } if (o->type != nullptr && o->type->kind == Type_Named && o->type->Named.type_name->TypeName.is_type_alias) { - o->type = base_type(o->type); + Type *bt = base_type(o->type); + if (bt != nullptr) { + o->type = bt; + } } break; @@ -2075,6 +2111,9 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i } else if (is_type_boolean(type)) { return in_value.kind == ExactValue_Bool; } else if (is_type_string(type)) { + if (in_value.kind == ExactValue_String16) { + return is_type_string16(type) || is_type_cstring16(type); + } return in_value.kind == ExactValue_String; } else if (is_type_integer(type) || is_type_rune(type)) { if (in_value.kind == ExactValue_Bool) { @@ -2289,11 +2328,28 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i if (in_value.kind == ExactValue_String) { return false; } + if (in_value.kind == ExactValue_String16) { + return false; + } if (out_value) *out_value = in_value; } else if (is_type_bit_set(type)) { if (in_value.kind == ExactValue_Integer) { return true; } + } else if (is_type_typeid(type)) { + + if (in_value.kind == ExactValue_Compound) { + ast_node(cl, CompoundLit, in_value.value_compound); + if (cl->elems.count == 0) { + in_value = exact_value_typeid(nullptr); + } else { + return false; + } + } + if (in_value.kind == ExactValue_Typeid) { + if (out_value) *out_value = in_value; + return true; + } } return false; @@ -2393,27 +2449,27 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o Type *s = src->Array.elem; Type *d = dst->Slice.elem; if (are_types_identical(s, d)) { - error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a); + error_line("\tSuggestion: The array expression may be sliced with %s[:]\n", a); } } else if (is_type_dynamic_array(src) && is_type_slice(dst)) { Type *s = src->DynamicArray.elem; Type *d = dst->Slice.elem; if (are_types_identical(s, d)) { - error_line("\tSuggestion: the dynamic array expression may be sliced with %s[:]\n", a); + error_line("\tSuggestion: The dynamic array expression may be sliced with %s[:]\n", a); } }else if (are_types_identical(src, dst) && !are_types_identical(o->type, type)) { - error_line("\tSuggestion: the expression may be directly casted to type %s\n", b); + error_line("\tSuggestion: The expression may be directly casted to type %s\n", b); } else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) { - error_line("\tSuggestion: a string may be transmuted to %s\n", b); - error_line("\t This is an UNSAFE operation as string data is assumed to be immutable, \n"); + error_line("\tSuggestion: A string may be transmuted to %s\n", b); + error_line("\t This is an UNSAFE operation as string data is assumed to be immutable,\n"); error_line("\t whereas slices in general are assumed to be mutable.\n"); } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { - error_line("\tSuggestion: the expression may be casted to %s\n", b); + error_line("\tSuggestion: The expression may be casted to %s\n", b); } else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) { return; } else if (is_expr_inferred_fixed_array(c->type_hint_expr) && is_type_array_like(type) && is_type_array_like(o->type)) { gbString s = expr_to_string(c->type_hint_expr); - error_line("\tSuggestion: make sure that `%s` is attached to the compound literal directly\n", s); + error_line("\tSuggestion: Make sure that `%s` is attached to the compound literal directly\n", s); gb_string_free(s); } else if (is_type_pointer(type) && o->mode == Addressing_Variable && @@ -2424,7 +2480,8 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o } else if (is_type_pointer(o->type) && are_types_identical(type_deref(o->type), type)) { gbString s = expr_to_string(o->expr); - error_line("\tSuggestion: Did you mean `%s^`\n", s); + if (s[0] == '&') error_line("\tSuggestion: Did you mean `%s`\n", &s[1]); + else error_line("\tSuggestion: Did you mean `%s^`\n", s); gb_string_free(s); } } @@ -2599,9 +2656,8 @@ gb_internal ExactValue exact_bit_set_all_set_mask(Type *type) { continue; } - BigInt shift_amount = f->Constant.value.value_integer; - big_int_sub_eq(&shift_amount, &b_lower_base); - + BigInt shift_amount = {}; + big_int_sub(&shift_amount, &f->Constant.value.value_integer, &b_lower_base); BigInt value = {}; big_int_shl(&value, &one, &shift_amount); @@ -2832,6 +2888,14 @@ gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t add_package_dependency(c, "runtime", "string_eq"); add_package_dependency(c, "runtime", "string_ne"); break; + case Basic_cstring16: + add_package_dependency(c, "runtime", "cstring16_eq"); + add_package_dependency(c, "runtime", "cstring16_ne"); + break; + case Basic_string16: + add_package_dependency(c, "runtime", "string16_eq"); + add_package_dependency(c, "runtime", "string16_ne"); + break; } break; case Type_Struct: @@ -2903,9 +2967,20 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper if (!defined) { gbString xs = type_to_string(x->type, temporary_allocator()); gbString ys = type_to_string(y->type, temporary_allocator()); - err_str = gb_string_make(temporary_allocator(), - gb_bprintf("operator '%.*s' not defined between the types '%s' and '%s'", LIT(token_strings[op]), xs, ys) - ); + + if (!is_type_comparable(x->type)) { + err_str = gb_string_make(temporary_allocator(), + gb_bprintf("Type '%s' is not simply comparable, so operator '%.*s' is not defined for it", xs, LIT(token_strings[op])) + ); + } else if (!is_type_comparable(y->type)) { + err_str = gb_string_make(temporary_allocator(), + gb_bprintf("Type '%s' is not simply comparable, so operator '%.*s' is not defined for it", ys, LIT(token_strings[op])) + ); + } else { + err_str = gb_string_make(temporary_allocator(), + gb_bprintf("Operator '%.*s' not defined between the types '%s' and '%s'", LIT(token_strings[op]), xs, ys) + ); + } } else { Type *comparison_type = x->type; if (x->type == err_type && is_operand_nil(*x)) { @@ -2926,11 +3001,11 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper } else { yt = type_to_string(y->type); } - err_str = gb_string_make(temporary_allocator(), gb_bprintf("mismatched types '%s' and '%s'", xt, yt)); + err_str = gb_string_make(temporary_allocator(), gb_bprintf("Mismatched types '%s' and '%s'", xt, yt)); } if (err_str != nullptr) { - error(node, "Cannot compare expression, %s", err_str); + error(node, "Cannot compare expression. %s.", err_str); x->type = t_untyped_bool; } else { if (x->mode == Addressing_Constant && @@ -2994,6 +3069,24 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper case Token_LtEq: add_package_dependency(c, "runtime", "cstring_le"); break; case Token_GtEq: add_package_dependency(c, "runtime", "cstring_gt"); break; } + } else if (is_type_cstring16(x->type) && is_type_cstring16(y->type)) { + switch (op) { + case Token_CmpEq: add_package_dependency(c, "runtime", "cstring16_eq"); break; + case Token_NotEq: add_package_dependency(c, "runtime", "cstring16_ne"); break; + case Token_Lt: add_package_dependency(c, "runtime", "cstring16_lt"); break; + case Token_Gt: add_package_dependency(c, "runtime", "cstring16_gt"); break; + case Token_LtEq: add_package_dependency(c, "runtime", "cstring16_le"); break; + case Token_GtEq: add_package_dependency(c, "runtime", "cstring16_gt"); break; + } + } else if (is_type_string16(x->type) || is_type_string16(y->type)) { + switch (op) { + case Token_CmpEq: add_package_dependency(c, "runtime", "string16_eq"); break; + case Token_NotEq: add_package_dependency(c, "runtime", "string16_ne"); break; + case Token_Lt: add_package_dependency(c, "runtime", "string16_lt"); break; + case Token_Gt: add_package_dependency(c, "runtime", "string16_gt"); break; + case Token_LtEq: add_package_dependency(c, "runtime", "string16_le"); break; + case Token_GtEq: add_package_dependency(c, "runtime", "string16_gt"); break; + } } else if (is_type_string(x->type) || is_type_string(y->type)) { switch (op) { case Token_CmpEq: add_package_dependency(c, "runtime", "string_eq"); break; @@ -3045,126 +3138,106 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod GB_ASSERT(node->kind == Ast_BinaryExpr); ast_node(be, BinaryExpr, node); - ExactValue x_val = {}; - if (x->mode == Addressing_Constant) { - x_val = exact_value_to_integer(x->value); - } - - bool x_is_untyped = is_type_untyped(x->type); - if (!(is_type_integer(x->type) || (x_is_untyped && x_val.kind == ExactValue_Integer))) { - gbString err_str = expr_to_string(x->expr); - error(node, "Shifted operand '%s' must be an integer", err_str); - gb_string_free(err_str); - x->mode = Addressing_Invalid; - return; - } - - if (is_type_unsigned(y->type)) { - - } else if (is_type_untyped(y->type)) { + bool y_is_untyped = is_type_untyped(y->type); + if (y_is_untyped) { convert_to_typed(c, y, t_untyped_integer); if (y->mode == Addressing_Invalid) { x->mode = Addressing_Invalid; return; } - } else { - gbString err_str = expr_to_string(y->expr); - error(node, "Shift amount '%s' must be an unsigned integer", err_str); - gb_string_free(err_str); + } else if (!is_type_unsigned(y->type)) { + gbString y_str = expr_to_string(y->expr); + error(y->expr, "Shift amount '%s' must be an unsigned integer", y_str); + gb_string_free(y_str); x->mode = Addressing_Invalid; return; } + bool x_is_untyped = is_type_untyped(x->type); + if (!(x_is_untyped || is_type_integer(x->type))) { + gbString x_str = expr_to_string(x->expr); + error(x->expr, "Shifted operand '%s' must be an integer", x_str); + gb_string_free(x_str); + x->mode = Addressing_Invalid; + return; + } + + if (y->mode == Addressing_Constant) { + if (big_int_is_neg(&y->value.value_integer)) { + gbString y_str = expr_to_string(y->expr); + error(y->expr, "Shift amount '%s' cannot be negative", y_str); + gb_string_free(y_str); + x->mode = Addressing_Invalid; + return; + } + + BigInt max_shift = {}; + big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT); + + if (big_int_cmp(&y->value.value_integer, &max_shift) > 0) { + gbString y_str = expr_to_string(y->expr); + error(y->expr, "Shift amount '%s' must be <= %u", y_str, MAX_BIG_INT_SHIFT); + gb_string_free(y_str); + x->mode = Addressing_Invalid; + return; + } + + if (x->mode == Addressing_Constant) { + if (x_is_untyped) { + convert_to_typed(c, x, t_untyped_integer); + if (x->mode == Addressing_Invalid) { + return; + } + + x->expr = node; + x->value = exact_value_shift(be->op.kind, exact_value_to_integer(x->value), exact_value_to_integer(y->value)); - if (x->mode == Addressing_Constant) { - if (y->mode == Addressing_Constant) { - ExactValue y_val = exact_value_to_integer(y->value); - if (y_val.kind != ExactValue_Integer) { - gbString err_str = expr_to_string(y->expr); - error(node, "Shift amount '%s' must be an unsigned integer", err_str); - gb_string_free(err_str); - x->mode = Addressing_Invalid; return; } - BigInt max_shift = {}; - big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT); - - if (big_int_cmp(&y_val.value_integer, &max_shift) > 0) { - gbString err_str = expr_to_string(y->expr); - error(node, "Shift amount too large: '%s'", err_str); - gb_string_free(err_str); - x->mode = Addressing_Invalid; - return; - } - - if (!is_type_integer(x->type)) { - // NOTE(bill): It could be an untyped float but still representable - // as an integer - x->type = t_untyped_integer; - } - x->expr = node; - x->value = exact_value_shift(be->op.kind, x_val, y_val); + x->value = exact_value_shift(be->op.kind, x->value, y->value); + check_is_expressible(c, x, x->type); - if (is_type_typed(x->type)) { - check_is_expressible(c, x, x->type); - } return; } - TokenPos pos = ast_token(x->expr).pos; - if (x_is_untyped) { - if (x->expr != nullptr) { - x->expr->tav.is_lhs = true; - } - x->mode = Addressing_Value; - if (type_hint) { - if (is_type_integer(type_hint)) { - convert_to_typed(c, x, type_hint); - } else { - gbString x_str = expr_to_string(x->expr); - gbString to_type = type_to_string(type_hint); - error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type); - gb_string_free(x_str); - gb_string_free(to_type); - x->mode = Addressing_Invalid; - } - } else if (!is_type_integer(x->type)) { - gbString x_str = expr_to_string(x->expr); - error(node, "Non-integer shifted operand '%s' is not allowed", x_str); - gb_string_free(x_str); - x->mode = Addressing_Invalid; - } - // x->value = x_val; - return; + if (y_is_untyped) { + convert_to_typed(c, y, t_uint); } - } - if (y->mode == Addressing_Constant && big_int_is_neg(&y->value.value_integer)) { - gbString err_str = expr_to_string(y->expr); - error(node, "Shift amount cannot be negative: '%s'", err_str); - gb_string_free(err_str); - } - - if (!is_type_integer(x->type)) { - gbString err_str = expr_to_string(x->expr); - error(node, "Shift operand '%s' must be an integer", err_str); - gb_string_free(err_str); - x->mode = Addressing_Invalid; return; } - if (is_type_untyped(y->type)) { - convert_to_typed(c, y, t_uint); + if (x->mode == Addressing_Constant) { + if (x_is_untyped) { + if (type_hint) { + if (is_type_integer(type_hint)) { + convert_to_typed(c, x, type_hint); + } else if (is_type_any(type_hint)) { + convert_to_typed(c, x, default_type(t_untyped_integer)); + } else { + gbString x_str = expr_to_string(x->expr); + gbString type_str = type_to_string(type_hint); + error(x->expr, "Shifted operand '%s' cannot convert to non-integer type '%s'", x_str, type_str); + gb_string_free(x_str); + gb_string_free(type_str); + x->mode = Addressing_Invalid; + return; + } + } else { + check_is_expressible(c, x, default_type(t_untyped_integer)); + } + if (x->mode == Addressing_Invalid) { + return; + } + } + + x->mode = Addressing_Value; } - - x->mode = Addressing_Value; } - - gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { if (check_is_assignable_to(c, operand, y)) { return true; @@ -3319,6 +3392,11 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type return true; } + // []u16 <-> string16 (not cstring16) + if (is_type_u16_slice(src) && (is_type_string16(dst) && !is_type_cstring16(dst))) { + return true; + } + // cstring -> string if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) { if (operand->mode != Addressing_Constant) { @@ -3326,6 +3404,14 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type } return true; } + // cstring16 -> string16 + if (are_types_identical(src, t_cstring16) && are_types_identical(dst, t_string16)) { + if (operand->mode != Addressing_Constant) { + add_package_dependency(c, "runtime", "cstring16_to_string16"); + } + return true; + } + // cstring -> ^u8 if (are_types_identical(src, t_cstring) && is_type_u8_ptr(dst)) { return !is_constant; @@ -3351,6 +3437,34 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type if (is_type_rawptr(src) && are_types_identical(dst, t_cstring)) { return !is_constant; } + + // cstring -> ^u16 + if (are_types_identical(src, t_cstring16) && is_type_u16_ptr(dst)) { + return !is_constant; + } + // cstring -> [^]u16 + if (are_types_identical(src, t_cstring16) && is_type_u16_multi_ptr(dst)) { + return !is_constant; + } + // cstring16 -> rawptr + if (are_types_identical(src, t_cstring16) && is_type_rawptr(dst)) { + return !is_constant; + } + + + // ^u16 -> cstring16 + if (is_type_u16_ptr(src) && are_types_identical(dst, t_cstring16)) { + return !is_constant; + } + // [^]u16 -> cstring + if (is_type_u16_multi_ptr(src) && are_types_identical(dst, t_cstring16)) { + return !is_constant; + } + // rawptr -> cstring16 + if (is_type_rawptr(src) && are_types_identical(dst, t_cstring16)) { + return !is_constant; + } + // proc <-> proc if (is_type_proc(src) && is_type_proc(dst)) { if (is_type_polymorphic(dst)) { @@ -3406,6 +3520,7 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) { bool is_const_expr = x->mode == Addressing_Constant; + Type *bt = base_type(type); if (is_const_expr && is_type_constant_type(bt)) { if (core_type(bt)->kind == Type_Basic) { @@ -3427,6 +3542,9 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) } else if (is_type_slice(type) && is_type_string(x->type)) { x->mode = Addressing_Value; } else if (is_type_union(type)) { + if (is_type_union_constantable(type)) { + return true; + } x->mode = Addressing_Value; } if (x->mode == Addressing_Value) { @@ -3666,6 +3784,11 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type } gb_internal bool check_binary_array_expr(CheckerContext *c, Token op, Operand *x, Operand *y) { + if (is_type_array_like(x->type) || is_type_array_like(y->type)) { + if (op.kind == Token_CmpAnd || op.kind == Token_CmpOr) { + error(op, "Array programming is not allowed with the operator '%.*s'", LIT(op.string)); + } + } if (is_type_array(x->type) && !is_type_array(y->type)) { if (check_is_assignable_to(c, y, x->type)) { if (check_binary_op(c, x, op)) { @@ -3841,6 +3964,59 @@ matrix_error: } +gb_internal void check_binary_expr_dependency(CheckerContext *c, Token op, Type *bt, bool REQUIRE) { + if (op.kind == Token_Mod || op.kind == Token_ModEq || + op.kind == Token_ModMod || op.kind == Token_ModModEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break; + case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break; + } + } else if (op.kind == Token_Quo || op.kind == Token_QuoEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break; + case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break; + case Basic_complex128: add_package_dependency(c, "runtime", "quo_complex128"); break; + case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break; + case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break; + case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break; + + case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break; + case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break; + } + } else if (op.kind == Token_Mul || op.kind == Token_MulEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break; + case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break; + case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break; + + + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__multi3", REQUIRE); + } + break; + } + } else if (op.kind == Token_Shl || op.kind == Token_ShlEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__ashlti3", REQUIRE); + } + break; + } + } else if (op.kind == Token_Shr || op.kind == Token_ShrEq) { + if (bt->kind == Type_Basic) switch (bt->Basic.kind) { + case Basic_u128: + case Basic_i128: + if (is_arch_wasm()) { + add_package_dependency(c, "runtime", "__lshrti3", REQUIRE); + } + break; + } + } +} gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint, bool use_lhs_as_type_hint=false) { GB_ASSERT(node->kind == Ast_BinaryExpr); @@ -4038,58 +4214,10 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ } bool REQUIRE = true; - Type *bt = base_type(x->type); - if (op.kind == Token_Mod || op.kind == Token_ModEq || - op.kind == Token_ModMod || op.kind == Token_ModModEq) { - if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_u128: add_package_dependency(c, "runtime", "umodti3", REQUIRE); break; - case Basic_i128: add_package_dependency(c, "runtime", "modti3", REQUIRE); break; - } - } else if (op.kind == Token_Quo || op.kind == Token_QuoEq) { - if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_complex32: add_package_dependency(c, "runtime", "quo_complex32"); break; - case Basic_complex64: add_package_dependency(c, "runtime", "quo_complex64"); break; - case Basic_complex128: add_package_dependency(c, "runtime", "quo_complex128"); break; - case Basic_quaternion64: add_package_dependency(c, "runtime", "quo_quaternion64"); break; - case Basic_quaternion128: add_package_dependency(c, "runtime", "quo_quaternion128"); break; - case Basic_quaternion256: add_package_dependency(c, "runtime", "quo_quaternion256"); break; - - case Basic_u128: add_package_dependency(c, "runtime", "udivti3", REQUIRE); break; - case Basic_i128: add_package_dependency(c, "runtime", "divti3", REQUIRE); break; - } - } else if (op.kind == Token_Mul || op.kind == Token_MulEq) { - if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_quaternion64: add_package_dependency(c, "runtime", "mul_quaternion64"); break; - case Basic_quaternion128: add_package_dependency(c, "runtime", "mul_quaternion128"); break; - case Basic_quaternion256: add_package_dependency(c, "runtime", "mul_quaternion256"); break; - - - case Basic_u128: - case Basic_i128: - if (is_arch_wasm()) { - add_package_dependency(c, "runtime", "__multi3", REQUIRE); - } - break; - } - } else if (op.kind == Token_Shl || op.kind == Token_ShlEq) { - if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_u128: - case Basic_i128: - if (is_arch_wasm()) { - add_package_dependency(c, "runtime", "__ashlti3", REQUIRE); - } - break; - } - } else if (op.kind == Token_Shr || op.kind == Token_ShrEq) { - if (bt->kind == Type_Basic) switch (bt->Basic.kind) { - case Basic_u128: - case Basic_i128: - if (is_arch_wasm()) { - add_package_dependency(c, "runtime", "__lshrti3", REQUIRE); - } - break; - } - } + Type *btx = base_type(x->type); + Type *bty = base_type(y->type); + check_binary_expr_dependency(c, op, btx, REQUIRE); + check_binary_expr_dependency(c, op, bty, REQUIRE); if (token_is_shift(op.kind)) { check_shift(c, x, y, node, type_hint); @@ -4204,7 +4332,25 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ } if (fail) { - error(y->expr, "Division by zero not allowed"); + if (is_type_integer(x->type) || (x->mode == Addressing_Constant && x->value.kind == ExactValue_Integer)) { + if (check_for_integer_division_by_zero(c, node) != IntegerDivisionByZero_Trap) { + // Okay + break; + } + } + + switch (op.kind) { + case Token_Mod: + case Token_ModMod: + case Token_ModEq: + case Token_ModModEq: + error(y->expr, "Division by zero through '%.*s' not allowed", LIT(token_strings[op.kind])); + break; + case Token_Quo: + case Token_QuoEq: + error(y->expr, "Division by zero not allowed"); + break; + } x->mode = Addressing_Invalid; return; } @@ -4244,7 +4390,59 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ } } - x->value = exact_binary_operator_value(op.kind, a, b); + match_exact_values(&a, &b); + + + IntegerDivisionByZeroKind zero_behaviour = check_for_integer_division_by_zero(c, node); + if (zero_behaviour != IntegerDivisionByZero_Trap && + b.kind == ExactValue_Integer && big_int_is_zero(&b.value_integer) && + (op.kind == Token_QuoEq || op.kind == Token_Mod || op.kind == Token_ModMod)) { + if (op.kind == Token_QuoEq) { + switch (zero_behaviour) { + case IntegerDivisionByZero_Zero: + // x/0 == 0 + x->value = b; + break; + case IntegerDivisionByZero_Self: + // x/0 == x + x->value = a; + break; + case IntegerDivisionByZero_AllBits: + // x/0 == 0b111...111 + if (is_type_untyped(x->type)) { + x->value = exact_value_i64(-1); + } else { + x->value = exact_unary_operator_value(Token_Xor, b, cast(i32)(8*type_size_of(x->type)), is_type_unsigned(x->type)); + } + break; + } + } else { + /* + NOTE(bill): @integer division by zero rules + + truncated: r = a - b*trunc(a/b) + floored: r = a - b*floor(a/b) + + IFF a/0 == 0, then (a%0 == a) or (a%%0 == a) + IFF a/0 == a, then (a%0 == 0) or (a%%0 == 0) + IFF a/0 == 0b111..., then (a%0 == a) or (a%%0 == a) + */ + + switch (zero_behaviour) { + case IntegerDivisionByZero_Zero: + case IntegerDivisionByZero_AllBits: + // x%0 == x + x->value = a; + break; + case IntegerDivisionByZero_Self: + // x%0 == 0 + x->value = b; + break; + } + } + } else { + x->value = exact_binary_operator_value(op.kind, a, b); + } if (is_type_typed(x->type)) { if (node != nullptr) { @@ -4462,7 +4660,6 @@ gb_internal ExactValue convert_exact_value_for_type(ExactValue v, Type *type) { } gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) { - // GB_ASSERT_NOT_NULL(target_type); if (target_type == nullptr || operand->mode == Addressing_Invalid || operand->mode == Addressing_Type || is_type_typed(operand->type) || @@ -4504,8 +4701,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar } else { switch (operand->type->Basic.kind) { case Basic_UntypedBool: - if (!is_type_boolean(target_type) && - !is_type_integer(target_type)) { + if (!is_type_boolean(target_type)) { operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); return; @@ -4528,6 +4724,8 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar // target_type = t_untyped_nil; } else if (is_type_cstring(target_type)) { // target_type = t_untyped_nil; + } else if (is_type_cstring16(target_type)) { + // target_type = t_untyped_nil; } else if (!type_has_nil(target_type)) { operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); @@ -4555,6 +4753,13 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar break; } } + } else if (operand->value.kind == ExactValue_String16) { + String16 s = operand->value.value_string16; + if (is_type_u16_array(t)) { + if (s.len == t->Array.count) { + break; + } + } } operand->mode = Addressing_Invalid; convert_untyped_error(c, operand, target_type); @@ -4625,7 +4830,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar TEMPORARY_ALLOCATOR_GUARD(); isize count = t->Union.variants.count; - ValidIndexAndScore *valids = gb_alloc_array(temporary_allocator(), ValidIndexAndScore, count); + ValidIndexAndScore *valids = temporary_alloc_array(count); isize valid_count = 0; isize first_success_index = -1; for_array(i, t->Union.variants) { @@ -4666,7 +4871,10 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar break; } operand->type = new_type; - operand->mode = Addressing_Value; + if (operand->mode != Addressing_Constant || + !elem_type_can_be_constant(operand->type)) { + operand->mode = Addressing_Value; + } break; } else if (valid_count > 1) { ERROR_BLOCK(); @@ -4884,6 +5092,12 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v if (success_) *success_ = true; if (finish_) *finish_ = true; return exact_value_u64(val); + } else if (value.kind == ExactValue_String16) { + GB_ASSERT(0 <= index && index < value.value_string.len); + u16 val = value.value_string16[index]; + if (success_) *success_ = true; + if (finish_) *finish_ = true; + return exact_value_u64(val); } if (value.kind != ExactValue_Compound) { if (success_) *success_ = true; @@ -4902,7 +5116,11 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v } if (cl->elems[0]->kind == Ast_FieldValue) { - if (is_type_struct(node->tav.type)) { + if (is_type_raw_union(node->tav.type)) { + if (success_) *success_ = false; + if (finish_) *finish_ = true; + return empty_exact_value; + } else if (is_type_struct(node->tav.type)) { bool found = false; for (Ast *elem : cl->elems) { if (elem->kind != Ast_FieldValue) { @@ -4911,7 +5129,6 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v ast_node(fv, FieldValue, elem); String name = fv->field->Ident.token.string; Selection sub_sel = lookup_field(node->tav.type, name, false); - defer (array_free(&sub_sel.index)); if (sub_sel.index.count > 0 && sub_sel.index[0] == index) { value = fv->value->tav.value; @@ -5172,7 +5389,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * } } else */if (node->kind == Ast_Ident) { String name = node->Ident.token.string; - return scope_lookup(c->scope, name); + return scope_lookup(c->scope, name, node->Ident.hash); } else if (!ident_only) if (node->kind == Ast_SelectorExpr) { ast_node(se, SelectorExpr, node); if (se->token.kind == Token_ArrowRight) { @@ -5194,7 +5411,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast * if (op_expr->kind == Ast_Ident) { String op_name = op_expr->Ident.token.string; - Entity *e = scope_lookup(c->scope, op_name); + Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash); if (e == nullptr) { return nullptr; } @@ -5291,7 +5508,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod if (op_expr->kind == Ast_Ident) { String op_name = op_expr->Ident.token.string; - Entity *e = scope_lookup(c->scope, op_name); + Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash); add_entity_use(c, op_expr, e); expr_entity = e; @@ -5331,16 +5548,6 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod return nullptr; } - check_entity_decl(c, entity, nullptr, nullptr); - if (entity->kind == Entity_ProcGroup) { - operand->mode = Addressing_ProcGroup; - operand->proc_group = entity; - - add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); - return entity; - } - GB_ASSERT_MSG(entity->type != nullptr, "%.*s (%.*s)", LIT(entity->token.string), LIT(entity_strings[entity->kind])); - if (!is_entity_exported(entity, allow_builtin)) { gbString sel_str = expr_to_string(selector); error(node, "'%s' is not exported by '%.*s'", sel_str, LIT(import_name)); @@ -5351,36 +5558,15 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod // return nullptr; } + check_entity_decl(c, entity, nullptr, nullptr); if (entity->kind == Entity_ProcGroup) { - Array procs = entity->ProcGroup.entities; - bool skip = false; - for (Entity *p : procs) { - Type *t = base_type(p->type); - if (t == t_invalid) { - continue; - } + operand->mode = Addressing_ProcGroup; + operand->proc_group = entity; - Operand x = {}; - x.mode = Addressing_Value; - x.type = t; - if (type_hint != nullptr) { - if (check_is_assignable_to(c, &x, type_hint)) { - entity = p; - skip = true; - break; - } - } - } - - if (!skip) { - GB_ASSERT(entity != nullptr); - operand->mode = Addressing_ProcGroup; - operand->type = t_invalid; - operand->expr = node; - operand->proc_group = entity; - return entity; - } + add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); + return entity; } + GB_ASSERT_MSG(entity->type != nullptr, "%.*s (%.*s)", LIT(entity->token.string), LIT(entity_strings[entity->kind])); } } @@ -5419,8 +5605,18 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } } + if (operand->type && is_type_simd_vector(type_deref(operand->type))) { + String field_name = selector->Ident.token.string; + if (field_name.len == 1) { + error(op_expr, "Extracting an element from a #simd array using .%.*s syntax is disallowed, prefer `simd.extract`", LIT(field_name)); + } else { + error(op_expr, "Extracting elements from a #simd array using .%.*s syntax is disallowed, prefer `swizzle`", LIT(field_name)); + } + return nullptr; + } + if (entity == nullptr && selector->kind == Ast_Ident && operand->type != nullptr && - (is_type_array(type_deref(operand->type)) || is_type_simd_vector(type_deref(operand->type)))) { + (is_type_array(type_deref(operand->type)))) { String field_name = selector->Ident.token.string; if (1 < field_name.len && field_name.len <= 4) { u8 swizzles_xyzw[4] = {'x', 'y', 'z', 'w'}; @@ -5475,7 +5671,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod Type *original_type = operand->type; Type *array_type = base_type(type_deref(original_type)); - GB_ASSERT(array_type->kind == Type_Array || array_type->kind == Type_SimdVector); + GB_ASSERT(array_type->kind == Type_Array); i64 array_count = get_array_type_count(array_type); @@ -5516,10 +5712,6 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod break; } - if (array_type->kind == Type_SimdVector) { - operand->mode = Addressing_Value; - } - Entity *swizzle_entity = alloc_entity_variable(nullptr, make_token_ident(field_name), operand->type, EntityState_Resolved); add_type_and_value(c, operand->expr, operand->mode, operand->type, operand->value); return swizzle_entity; @@ -5642,7 +5834,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod switch (entity->kind) { case Entity_Constant: - operand->value = entity->Constant.value; + operand->value = entity->Constant.value; operand->mode = Addressing_Constant; if (operand->value.kind == ExactValue_Procedure) { Entity *proc = strip_entity_wrapping(operand->value.value_procedure); @@ -5739,7 +5931,7 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals return true; } } else { - Entity *e = scope_lookup(s, name); + Entity *e = scope_lookup(s, name, i->hash); if (e != nullptr) { if (out_scope) *out_scope = e->scope; return true; @@ -5758,22 +5950,6 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals return false; } -gb_internal bool check_no_copy_assignment(Operand const &o, String const &context) { - if (o.type && is_type_no_copy(o.type)) { - Ast *expr = unparen_expr(o.expr); - if (expr && o.mode != Addressing_Constant && o.mode != Addressing_Type) { - if (expr->kind == Ast_CallExpr) { - // Okay - } else { - error(o.expr, "Invalid use of #no_copy value in %.*s", LIT(context)); - return true; - } - } - } - return false; -} - - gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array const &lhs, Array *operands, Slice const &rhs) { bool optional_ok = false; isize tuple_index = 0; @@ -5844,7 +6020,6 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array for (Entity *e : tuple->variables) { o.type = e->type; array_add(operands, o); - check_no_copy_assignment(o, str_lit("assignment")); } tuple_index += tuple->variables.count; @@ -5859,12 +6034,12 @@ typedef u32 UnpackFlags; enum UnpackFlag : u32 { UnpackFlag_None = 0, UnpackFlag_AllowOk = 1<<0, - UnpackFlag_IsVariadic = 1<<1, - UnpackFlag_AllowUndef = 1<<2, + UnpackFlag_AllowUndef = 1<<1, }; -gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs_arguments, UnpackFlags flags) { +gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs_arguments, UnpackFlags flags, + isize variadic_index = -1) { auto const &add_dependencies_from_unpacking = [](CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) -> isize { if (lhs == nullptr || c->decl == nullptr) { return tuple_count; @@ -5880,7 +6055,7 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize } rw_mutex_shared_lock(&decl->deps_mutex); rw_mutex_lock(&c->decl->deps_mutex); - for (Entity *dep : decl->deps) { + FOR_PTR_SET(dep, decl->deps) { ptr_set_add(&c->decl->deps, dep); } rw_mutex_unlock(&c->decl->deps_mutex); @@ -5889,11 +6064,14 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize return tuple_count; }; - bool allow_ok = (flags & UnpackFlag_AllowOk) != 0; - bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0; bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0; + bool is_variadic = variadic_index > -1; + if (!is_variadic) { + variadic_index = lhs_count; + } + bool optional_ok = false; isize tuple_index = 0; for (Ast *rhs : rhs_arguments) { @@ -5909,26 +6087,18 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize Type *type_hint = nullptr; - - if (lhs != nullptr && tuple_index < lhs_count) { - // NOTE(bill): override DeclInfo for dependency - Entity *e = lhs[tuple_index]; - if (e != nullptr) { - type_hint = e->type; - if (e->flags & EntityFlag_Ellipsis) { - GB_ASSERT(is_type_slice(e->type)); - GB_ASSERT(e->type->kind == Type_Slice); - type_hint = e->type->Slice.elem; + if (lhs != nullptr) { + if (tuple_index < variadic_index) { + // NOTE(bill): override DeclInfo for dependency + Entity *e = lhs[tuple_index]; + if (e != nullptr) { + type_hint = e->type; } - } - } else if (lhs != nullptr && tuple_index >= lhs_count && is_variadic) { - // NOTE(bill): override DeclInfo for dependency - Entity *e = lhs[lhs_count-1]; - if (e != nullptr) { - type_hint = e->type; - if (e->flags & EntityFlag_Ellipsis) { + } else if (is_variadic) { + Entity *e = lhs[variadic_index]; + if (e != nullptr) { + GB_ASSERT(e->flags & EntityFlag_Ellipsis); GB_ASSERT(is_type_slice(e->type)); - GB_ASSERT(e->type->kind == Type_Slice); type_hint = e->type->Slice.elem; } } @@ -6075,7 +6245,8 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A Entity *entity, Type *proc_type, Array positional_operands, Array const &named_operands, CallArgumentErrorMode show_error_mode, - CallArgumentData *data) { + CallArgumentData *data, + bool checking_proc_group) { TEMPORARY_ALLOCATOR_GUARD(); CallArgumentError err = CallArgumentError_None; @@ -6112,7 +6283,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } GB_ASSERT(ce->split_args); - auto visited = slice_make(temporary_allocator(), pt->param_count); + auto visited = temporary_slice_make(pt->param_count); auto ordered_operands = array_make(temporary_allocator(), pt->param_count); defer ({ for (Operand const &o : ordered_operands) { @@ -6236,29 +6407,46 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } - for (Operand const &o : ordered_operands) { - if (o.mode != Addressing_Invalid) { - check_no_copy_assignment(o, str_lit("procedure call expression")); - } - } - for (isize i = 0; i < pt->param_count; i++) { if (!visited[i]) { Entity *e = pt->params->Tuple.variables[i]; + bool context_allocator_error = false; if (e->kind == Entity_Variable) { if (e->Variable.param_value.kind != ParameterValue_Invalid) { - ordered_operands[i].mode = Addressing_Value; - ordered_operands[i].type = e->type; - ordered_operands[i].expr = e->Variable.param_value.original_ast_expr; + if (ast_file_vet_explicit_allocators(c->file) && !checking_proc_group) { + // NOTE(lucas): check if we are trying to default to context.allocator or context.temp_allocator + if (e->Variable.param_value.original_ast_expr->kind == Ast_SelectorExpr) { + auto& expr = e->Variable.param_value.original_ast_expr->SelectorExpr.expr; + auto& selector = e->Variable.param_value.original_ast_expr->SelectorExpr.selector; + if (expr->kind == Ast_Implicit && + expr->Implicit.string == STR_LIT("context") && + selector->kind == Ast_Ident && + (selector->Ident.token.string == STR_LIT("allocator") || + selector->Ident.token.string == STR_LIT("temp_allocator"))) { + context_allocator_error = true; + } + } + } - dummy_argument_count += 1; - score += assign_score_function(1); - continue; + if (!context_allocator_error) { + ordered_operands[i].mode = Addressing_Value; + ordered_operands[i].type = e->type; + ordered_operands[i].expr = e->Variable.param_value.original_ast_expr; + + dummy_argument_count += 1; + score += assign_score_function(1); + continue; + } } } if (show_error) { - if (e->kind == Entity_TypeName) { + if (context_allocator_error) { + gbString str = type_to_string(e->type); + error(call, "Parameter '%.*s' of type '%s' must be explicitly provided in procedure call", + LIT(e->token.string), str); + gb_string_free(str); + } else if (e->kind == Entity_TypeName) { error(call, "Type parameter '%.*s' is missing in procedure call", LIT(e->token.string)); } else if (e->kind == Entity_Constant && e->Constant.value.kind != ExactValue_Invalid) { @@ -6310,6 +6498,21 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } } + if (e && e->kind == Entity_Constant && is_type_proc(e->type)) { + bool ok = false; + if (o->mode == Addressing_Constant) { + ok = true; + } else if (o->value.kind == ExactValue_Procedure) { + ok = true; + } + + if (!ok) { + if (show_error) { + error(o->expr, "Expected a constant procedure value for the argument '%.*s'", LIT(e->token.string)); + } + err = CallArgumentError_NoneConstantParameter; + } + } if (!err && is_type_any(param_type)) { add_type_info_type(c, o->type); @@ -6468,17 +6671,16 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) { return ce->args[0]->kind == Ast_FieldValue; } -gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_, bool *is_variadic) { +gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_) { Entity **lhs = nullptr; isize lhs_count = -1; - if (proc_type == nullptr) { + if (proc_type == nullptr || proc_type == t_invalid) { return nullptr; } GB_ASSERT(is_type_proc(proc_type)); TypeProc *pt = &base_type(proc_type)->Proc; - *is_variadic = pt->variadic; if (!pt->is_polymorphic || pt->is_poly_specialized) { if (pt->params != nullptr) { @@ -6534,7 +6736,7 @@ gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Sco Entity *e = entry.value; switch (e->kind) { case Entity_TypeName: { - if (print_count == 0) error_line("\n\tWith the following definitions:\n"); + // if (print_count == 0) error_line("\n\tWith the following definitions:\n"); gbString str = type_to_string(e->type); error_line("\t\t%.*s :: %s;\n", LIT(e->token.string), str); @@ -6653,7 +6855,8 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera Entity *e, Type *proc_type, Array const &positional_operands, Array const &named_operands, CallArgumentErrorMode show_error_mode, - CallArgumentData *data) { + CallArgumentData *data, + bool checking_proc_group) { bool return_on_failure = show_error_mode == CallArgumentErrorMode::NoErrors; @@ -6672,9 +6875,12 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera GB_ASSERT(proc_type != nullptr); proc_type = base_type(proc_type); + if (proc_type == t_invalid) { + return false; + } GB_ASSERT(proc_type->kind == Type_Proc); - CallArgumentError err = check_call_arguments_internal(c, call, e, proc_type, positional_operands, named_operands, show_error_mode, data); + CallArgumentError err = check_call_arguments_internal(c, call, e, proc_type, positional_operands, named_operands, show_error_mode, data, checking_proc_group); if (return_on_failure && err != CallArgumentError_None) { return false; } @@ -6799,31 +7005,40 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, array_unordered_remove(&procs, proc_index); continue; } + if (!pt->Proc.variadic && max_arg_count != ISIZE_MAX && param_count < max_arg_count) { + array_unordered_remove(&procs, proc_index); + continue; + } proc_index++; } } Entity **lhs = nullptr; isize lhs_count = -1; - bool is_variadic = false; + i32 variadic_index = -1; - auto positional_operands = array_make(heap_allocator(), 0, 0); - auto named_operands = array_make(heap_allocator(), 0, 0); - defer (array_free(&positional_operands)); - defer (array_free(&named_operands)); + TEMPORARY_ALLOCATOR_GUARD(); + + auto positional_operands = array_make(temporary_allocator(), 0, 0); + auto named_operands = array_make(temporary_allocator(), 0, 0); if (procs.count == 1) { Entity *e = procs[0]; - - lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic); - check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + Type *pt = base_type(e->type); + if (pt != nullptr && is_type_proc(pt)) { + lhs = populate_proc_parameter_list(c, pt, &lhs_count); + if (pt->Proc.variadic) { + variadic_index = pt->Proc.variadic_index; + } + } + check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index); if (check_named_arguments(c, e->type, named_args, &named_operands, true)) { check_call_arguments_single(c, call, operand, e, e->type, positional_operands, named_operands, CallArgumentErrorMode::ShowErrors, - &data); + &data, false); } return data; } @@ -6846,7 +7061,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, if (proc_arg_count >= 0) { lhs_count = proc_arg_count; if (lhs_count > 0) { - lhs = gb_alloc_array(heap_allocator(), Entity *, lhs_count); + lhs = gb_alloc_array(temporary_allocator(), Entity *, lhs_count); for (isize param_index = 0; param_index < lhs_count; param_index++) { Entity *e = nullptr; for (Entity *p : procs) { @@ -6876,11 +7091,30 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } lhs[param_index] = e; } + + for (Entity *p : procs) { + Type *pt = base_type(p->type); + if (!(pt != nullptr && is_type_proc(pt))) { + continue; + } + + if (pt->Proc.is_polymorphic) { + if (variadic_index == -1) { + variadic_index = pt->Proc.variadic_index; + } else if (variadic_index != pt->Proc.variadic_index) { + variadic_index = -1; + break; + } + } else { + variadic_index = -1; + break; + } + } } } } - check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index); for_array(i, named_args) { Ast *arg = named_args[i]; @@ -6913,13 +7147,9 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, array_add(&named_operands, o); } - gb_free(heap_allocator(), lhs); + auto valids = array_make(temporary_allocator(), 0, procs.count); - auto valids = array_make(heap_allocator(), 0, procs.count); - defer (array_free(&valids)); - - auto proc_entities = array_make(heap_allocator(), 0, procs.count*2 + 1); - defer (array_free(&proc_entities)); + auto proc_entities = array_make(temporary_allocator(), 0, procs.count*2 + 1); for (Entity *proc : procs) { array_add(&proc_entities, proc); } @@ -6929,6 +7159,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, gbString expr_name = expr_to_string(operand->expr); defer (gb_string_free(expr_name)); + c->in_proc_group = true; for_array(i, procs) { Entity *p = procs[i]; if (p->flags & EntityFlag_Disabled) { @@ -6948,7 +7179,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, p, pt, positional_operands, named_operands, CallArgumentErrorMode::NoErrors, - &data); + &data, true); if (!is_a_candidate) { continue; } @@ -6971,6 +7202,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, array_add(&valids, item); } } + c->in_proc_group = false; if (max_matched_features > 0) { for_array(i, valids) { @@ -7048,7 +7280,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } // Try to reduce the list further for `$T: typeid` like parameters - bool *possibly_ignore = gb_alloc_array(temporary_allocator(), bool, procs.count); + bool *possibly_ignore = temporary_alloc_array(procs.count); isize possibly_ignore_set = 0; if (true) { @@ -7136,7 +7368,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } isize max_spaces = gb_max(max_name_length, max_type_length); - char *spaces = gb_alloc_array(temporary_allocator(), char, max_spaces+1); + char *spaces = temporary_alloc_array(max_spaces+1); for (isize i = 0; i < max_spaces; i++) { spaces[i] = ' '; } @@ -7257,7 +7489,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, e, e->type, positional_operands, named_operands, CallArgumentErrorMode::ShowErrors, - &data); + &data, false); return data; } @@ -7311,20 +7543,22 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op return check_call_arguments_proc_group(c, operand, call); } - auto positional_operands = array_make(heap_allocator(), 0, positional_args.count); - auto named_operands = array_make(heap_allocator(), 0, 0); + TEMPORARY_ALLOCATOR_GUARD(); - defer (array_free(&positional_operands)); - defer (array_free(&named_operands)); + auto positional_operands = array_make(temporary_allocator(), 0, positional_args.count); + auto named_operands = array_make(temporary_allocator(), 0, 0); if (positional_args.count > 0) { - isize lhs_count = -1; - bool is_variadic = false; Entity **lhs = nullptr; + isize lhs_count = -1; + i32 variadic_index = -1; if (pt != nullptr) { - lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); + lhs = populate_proc_parameter_list(c, proc_type, &lhs_count); + if (pt->variadic) { + variadic_index = pt->variadic_index; + } } - check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index); } if (named_args.count > 0) { @@ -7367,7 +7601,7 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op nullptr, proc_type, positional_operands, named_operands, CallArgumentErrorMode::ShowErrors, - &data); + &data, false); } else if (pt) { data.result_type = pt->results; } @@ -7399,6 +7633,8 @@ gb_internal isize lookup_polymorphic_record_parameter(Type *t, String parameter_ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *operand, Ast *call) { + TEMPORARY_ALLOCATOR_GUARD(); + ast_node(ce, CallExpr, call); Type *original_type = operand->type; @@ -7407,7 +7643,6 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O bool show_error = true; Array operands = {}; - defer (array_free(&operands)); CallArgumentError err = CallArgumentError_None; @@ -7415,15 +7650,14 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O { // NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves auto prev_type_path = c->type_path; - c->type_path = new_checker_type_path(); - defer ({ - destroy_checker_type_path(c->type_path); - c->type_path = prev_type_path; - }); + TEMPORARY_ALLOCATOR_GUARD(); + + c->type_path = new_checker_type_path(temporary_allocator()); + defer (c->type_path = prev_type_path); if (is_call_expr_field_value(ce)) { named_fields = true; - operands = array_make(heap_allocator(), ce->args.count); + operands = array_make(temporary_allocator(), ce->args.count); for_array(i, ce->args) { Ast *arg = ce->args[i]; ast_node(fv, FieldValue, arg); @@ -7455,7 +7689,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O } } else { - operands = array_make(heap_allocator(), 0, 2*ce->args.count); + operands = array_make(temporary_allocator(), 0, 2*ce->args.count); Entity **lhs = nullptr; isize lhs_count = -1; @@ -7497,7 +7731,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O } else { TEMPORARY_ALLOCATOR_GUARD(); - bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count); + bool *visited = temporary_alloc_array(param_count); // LEAK(bill) ordered_operands = array_make(permanent_allocator(), param_count); @@ -7681,11 +7915,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O { GenTypesData *found_gen_types = ensure_polymorphic_record_entity_has_gen_types(c, original_type); - mutex_lock(&found_gen_types->mutex); defer (mutex_unlock(&found_gen_types->mutex)); - Entity *found_entity = find_polymorphic_record_entity(found_gen_types, param_count, ordered_operands); + Entity *found_entity = find_polymorphic_record_entity(found_gen_types, param_count, ordered_operands); if (found_entity) { operand->mode = Addressing_Type; operand->type = found_entity->type; @@ -7745,7 +7978,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O s = gb_string_append_fmt(s, "$%.*s", LIT(name)); if (v->kind == Entity_TypeName) { - if (v->type->kind != Type_Generic) { + if (v->type != nullptr && v->type->kind != Type_Generic) { s = gb_string_append_fmt(s, "="); s = write_type_to_string(s, v->type, false); } @@ -7813,6 +8046,173 @@ gb_internal bool check_call_parameter_mixture(Slice const &args, char con return Expr_Stmt; \ } +gb_internal ExprKind check_call_expr_as_type_cast(CheckerContext *c, Operand *operand, Ast *call, Slice const &args, Type *type_hint) { + GB_ASSERT(operand->mode == Addressing_Type); + Type *t = operand->type; + if (is_type_polymorphic_record(t)) { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction"); + + if (!is_type_named(t)) { + gbString s = expr_to_string(operand->expr); + error(call, "Illegal use of an unnamed polymorphic record, %s", s); + gb_string_free(s); + operand->mode = Addressing_Invalid; + operand->type = t_invalid;; + return Expr_Expr; + } + auto err = check_polymorphic_record_type(c, operand, call); + if (err == 0) { + Ast *ident = operand->expr; + while (ident->kind == Ast_SelectorExpr) { + Ast *s = ident->SelectorExpr.selector; + ident = s; + } + Type *ot = operand->type; + GB_ASSERT(ot->kind == Type_Named); + Entity *e = ot->Named.type_name; + add_entity_use(c, ident, e); + add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value); + } else { + operand->mode = Addressing_Invalid; + operand->type = t_invalid; + } + } else { + CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion"); + + operand->mode = Addressing_Invalid; + isize arg_count = args.count; + switch (arg_count) { + case 0: + { + gbString str = type_to_string(t); + error(call, "Missing argument in conversion to '%s'", str); + gb_string_free(str); + } break; + default: + { + gbString str = type_to_string(t); + if (t->kind == Type_Basic) { + ERROR_BLOCK(); + switch (t->Basic.kind) { + case Basic_complex32: + case Basic_complex64: + case Basic_complex128: + error(call, "Too many arguments in conversion to '%s'", str); + error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str); + break; + case Basic_quaternion64: + case Basic_quaternion128: + case Basic_quaternion256: + error(call, "Too many arguments in conversion to '%s'", str); + error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str); + break; + default: + error(call, "Too many arguments in conversion to '%s'", str); + } + } else { + error(call, "Too many arguments in conversion to '%s'", str); + } + gb_string_free(str); + } break; + case 1: { + Ast *arg = args[0]; + if (arg->kind == Ast_FieldValue) { + error(call, "'field = value' cannot be used in a type conversion"); + arg = arg->FieldValue.value; + // NOTE(bill): Carry on the cast regardless + } + check_expr_with_type_hint(c, operand, arg, t); + if (operand->mode != Addressing_Invalid) { + if (is_type_polymorphic(t)) { + error(call, "A polymorphic type cannot be used in a type conversion"); + } else { + // NOTE(bill): Otherwise the compiler can override the polymorphic type + // as it assumes it is determining the type + check_cast(c, operand, t); + } + } + operand->type = t; + operand->expr = call; + + + if (operand->mode != Addressing_Invalid) { + update_untyped_expr_type(c, arg, t, false); + } + break; + } + } + } + return Expr_Expr; +} + + +void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice param_types); + +gb_internal void check_objc_call_expr(CheckerContext *c, Operand *operand, Ast *call, Entity *proc_entity, Type *proc_type) { + auto &proc = proc_type->Proc; + Slice params = proc.params ? proc.params->Tuple.variables : Slice{}; + + Type *self_type = nullptr; + isize params_start = 1; + + ast_node(ce, CallExpr, call); + + Type *return_type = proc.result_count == 0 ? nullptr : proc.results->Tuple.variables[0]->type; + bool is_return_instancetype = return_type != nullptr && return_type == t_objc_instancetype; + + if (params.count == 0 || !is_type_objc_ptr_to_object(params[0]->type)) { + if (!proc_entity->Procedure.is_objc_class_method) { + // Not a class method, invalid call + error(call, "Invalid Objective-C call: The Objective-C method is not a class method but this first parameter is not an Objective-C object pointer."); + return; + } + + if (is_return_instancetype) { + if (ce->proc->kind == Ast_SelectorExpr) { + ast_node(se, SelectorExpr, ce->proc); + + // NOTE(harold): These should have already been checked, right? + GB_ASSERT(se->expr->tav.mode == Addressing_Type && se->expr->tav.type->kind == Type_Named); + + return_type = alloc_type_pointer(se->expr->tav.type); + } else { + return_type = proc_entity->Procedure.objc_class->type; + } + } + + self_type = t_objc_Class; + params_start = 0; + } else if (ce->args.count > 0) { + GB_ASSERT(is_type_objc_ptr_to_object(params[0]->type)); + + if (ce->args[0]->tav.objc_super_target) { + self_type = t_objc_super_ptr; + } else { + self_type = ce->args[0]->tav.type; + } + + if (is_return_instancetype) { + // NOTE(harold): These should have already been checked, right? + GB_ASSERT(ce->args[0]->tav.type && ce->args[0]->tav.type->kind == Type_Pointer && ce->args[0]->tav.type->Pointer.elem->kind == Type_Named); + + return_type = ce->args[0]->tav.type; + } + } + + auto param_types = slice_make(permanent_allocator(), proc.param_count + 2 - params_start); + param_types[0] = self_type; + param_types[1] = t_objc_SEL; + + for (isize i = params_start; i < params.count; i++) { + param_types[i+2-params_start] = params[i]->type; + } + + if (is_return_instancetype) { + operand->type = return_type; + } + + add_objc_proc_type(c, call, return_type, param_types); +} gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice const &args, ProcInlining inlining, Type *type_hint) { if (proc != nullptr && @@ -7869,79 +8269,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } if (operand->mode == Addressing_Type) { - Type *t = operand->type; - if (is_type_polymorphic_record(t)) { - CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction"); - - if (!is_type_named(t)) { - gbString s = expr_to_string(operand->expr); - error(call, "Illegal use of an unnamed polymorphic record, %s", s); - gb_string_free(s); - operand->mode = Addressing_Invalid; - operand->type = t_invalid;; - return Expr_Expr; - } - auto err = check_polymorphic_record_type(c, operand, call); - if (err == 0) { - Ast *ident = operand->expr; - while (ident->kind == Ast_SelectorExpr) { - Ast *s = ident->SelectorExpr.selector; - ident = s; - } - Type *ot = operand->type; - GB_ASSERT(ot->kind == Type_Named); - Entity *e = ot->Named.type_name; - add_entity_use(c, ident, e); - add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value); - } else { - operand->mode = Addressing_Invalid; - operand->type = t_invalid; - } - } else { - CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion"); - - operand->mode = Addressing_Invalid; - isize arg_count = args.count; - switch (arg_count) { - case 0: - { - gbString str = type_to_string(t); - error(call, "Missing argument in conversion to '%s'", str); - gb_string_free(str); - } break; - default: - { - gbString str = type_to_string(t); - error(call, "Too many arguments in conversion to '%s'", str); - gb_string_free(str); - } break; - case 1: { - Ast *arg = args[0]; - if (arg->kind == Ast_FieldValue) { - error(call, "'field = value' cannot be used in a type conversion"); - arg = arg->FieldValue.value; - // NOTE(bill): Carry on the cast regardless - } - check_expr_with_type_hint(c, operand, arg, t); - if (operand->mode != Addressing_Invalid) { - if (is_type_polymorphic(t)) { - error(call, "A polymorphic type cannot be used in a type conversion"); - } else { - // NOTE(bill): Otherwise the compiler can override the polymorphic type - // as it assumes it is determining the type - check_cast(c, operand, t); - } - } - operand->type = t; - operand->expr = call; - if (operand->mode != Addressing_Invalid) { - update_untyped_expr_type(c, arg, t, false); - } - break; - } - } - } - return Expr_Expr; + return check_call_expr_as_type_cast(c, operand, call, args, type_hint); } if (operand->mode == Addressing_Builtin) { @@ -8028,7 +8356,13 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) { if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) { - error(call, "'context' has not been defined within this scope, but is required for this procedure call"); + ERROR_BLOCK(); + if (c->scope->flags & ScopeFlag_File) { + error(call, "Procedures requiring a 'context' cannot be called at the global scope"); + } else { + error(call, "'context' has not been defined within this scope, but is required for this procedure call"); + error_line("\tSuggestion: 'context = runtime.default_context()'"); + } } } @@ -8107,9 +8441,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c if (c->curr_proc_decl == nullptr) { error(call, "Calling a '#force_inline' procedure that enables target features is not allowed at file scope"); } else { - GB_ASSERT(c->curr_proc_decl->entity); - GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc); - String scope_features = c->curr_proc_decl->entity->type->Proc.enable_target_feature; + Entity *e = c->curr_proc_decl->entity.load(); + GB_ASSERT(e); + GB_ASSERT(e->type->kind == Type_Proc); + String scope_features = e->type->Proc.enable_target_feature; if (!check_target_feature_is_superset_of(scope_features, pt->Proc.enable_target_feature, &invalid)) { ERROR_BLOCK(); error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid)); @@ -8132,7 +8467,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c type = pt; } type = base_type(type); - if (type->kind == Type_Proc && type->Proc.optional_ok) { + if (type->kind == Type_Proc && type->Proc.optional_ok && type->Proc.result_count > 0) { operand->mode = Addressing_OptionalOk; operand->type = type->Proc.results->Tuple.variables[0]->type; if (operand->expr != nullptr && operand->expr->kind == Ast_CallExpr) { @@ -8141,6 +8476,12 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c } } + Entity *proc_entity = entity_from_expr(call->CallExpr.proc); + bool is_objc_call = proc_entity && proc_entity->kind == Entity_Procedure && proc_entity->Procedure.is_objc_impl_or_import; + if (is_objc_call) { + check_objc_call_expr(c, operand, call, proc_entity, pt); + } + return Expr_Expr; } @@ -8175,6 +8516,7 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 case Type_Basic: if (t->Basic.kind == Basic_string) { if (o->mode == Addressing_Constant) { + GB_ASSERT(o->value.kind == ExactValue_String); *max_count = o->value.value_string.len; } if (o->mode != Addressing_Constant) { @@ -8182,6 +8524,16 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 } o->type = t_u8; return true; + } else if (t->Basic.kind == Basic_string16) { + if (o->mode == Addressing_Constant) { + GB_ASSERT(o->value.kind == ExactValue_String16); + *max_count = o->value.value_string16.len; + } + if (o->mode != Addressing_Constant) { + o->mode = Addressing_Value; + } + o->type = t_u16; + return true; } else if (t->Basic.kind == Basic_UntypedString) { if (o->mode == Addressing_Constant) { *max_count = o->value.value_string.len; @@ -8391,7 +8743,7 @@ gb_internal bool check_range(CheckerContext *c, Ast *node, bool is_for_loop, Ope return true; } -gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o) { +gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o, Type *field_type) { if (is_operand_nil(*o)) { return true; } @@ -8406,6 +8758,13 @@ gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Opera return true; } } + if (field_type != nullptr && is_type_typeid(field_type) && o->mode == Addressing_Type) { + add_type_info_type(c, o->type); + return true; + } + if (is_type_any(field_type)) { + return false; + } return o->mode == Addressing_Constant; } @@ -8635,7 +8994,7 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op isize count = multi_map_count(seen, key); if (count) { TEMPORARY_ALLOCATOR_GUARD(); - TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count); + TypeAndToken *taps = temporary_alloc_array(count); multi_map_get_all(seen, key, taps); for (isize i = 0; i < count; i++) { @@ -8709,23 +9068,52 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A String name = bd->name.string; if (name == "file") { String file = get_file_path_string(bd->token.pos.file_id); - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: file = obfuscate_string(file, "F"); + break; + case SourceCodeLocationInfo_Filename: + file = last_path_element(file); + break; + case SourceCodeLocationInfo_None: + file = str_lit(""); + break; } o->type = t_untyped_string; o->value = exact_value_string(file); } else if (name == "directory") { String file = get_file_path_string(bd->token.pos.file_id); String path = dir_from_path(file); - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: path = obfuscate_string(path, "D"); + break; + case SourceCodeLocationInfo_Filename: + path = last_path_element(path); + break; + case SourceCodeLocationInfo_None: + path = str_lit(""); + break; } o->type = t_untyped_string; o->value = exact_value_string(path); } else if (name == "line") { i32 line = bd->token.pos.line; - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: line = obfuscate_i32(line); + break; + case SourceCodeLocationInfo_Filename: + break; + case SourceCodeLocationInfo_None: + line = 0; + break; } o->type = t_untyped_integer; o->value = exact_value_i64(line); @@ -8736,8 +9124,17 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A o->value = exact_value_string(str_lit("")); } else { String p = c->proc_name; - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: p = obfuscate_string(p, "P"); + break; + case SourceCodeLocationInfo_Filename: + break; + case SourceCodeLocationInfo_None: + p = str_lit(""); + break; } o->type = t_untyped_string; o->value = exact_value_string(p); @@ -8969,8 +9366,14 @@ gb_internal ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node o->expr = node; return Expr_Expr; } + + Type *left_type = nullptr; + Type *right_type = nullptr; + check_or_else_split_types(c, &x, name, &left_type, &right_type); + add_type_and_value(c, arg, x.mode, x.type, x.value); + bool y_is_diverging = false; - check_expr_base(c, &y, default_value, x.type); + check_expr_base(c, &y, default_value, left_type); switch (y.mode) { case Addressing_NoValue: if (is_diverging_expr(y.expr)) { @@ -8995,14 +9398,21 @@ gb_internal ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node return Expr_Expr; } - Type *left_type = nullptr; - Type *right_type = nullptr; - check_or_else_split_types(c, &x, name, &left_type, &right_type); - add_type_and_value(c, arg, x.mode, x.type, x.value); - if (left_type != nullptr) { if (!y_is_diverging) { - check_assignment(c, &y, left_type, name); + if (is_type_tuple(left_type)) { + if (!is_type_tuple(y.type)) { + error(y.expr, "Found a single value where a %td-valued expression was expected", left_type->Tuple.variables.count); + } else if (!are_types_identical(left_type, y.type)) { + gbString xt = type_to_string(left_type); + gbString yt = type_to_string(y.type); + error(y.expr, "Mismatched types, expected (%s), got (%s)", xt, yt); + gb_string_free(yt); + gb_string_free(xt); + } + } else { + check_assignment(c, &y, left_type, name); + } } } else { check_or_else_expr_no_value_error(c, name, x, type_hint); @@ -9305,8 +9715,7 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slicevalue, field->type); - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { + if (elem_cannot_be_constant(field->type)) { is_constant = false; } if (is_constant) { - is_constant = check_is_operand_compound_lit_constant(c, &o); + is_constant = check_is_operand_compound_lit_constant(c, &o, field->type); } u8 prev_bit_field_bit_size = c->bit_field_bit_size; @@ -9378,7 +9787,10 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) { } gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) { - if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0) { + if (cl->elems.count == 0) { + return false; + } + if ((check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) { ERROR_BLOCK(); error(node, "Compound literals of dynamic types are disabled by default"); error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n"); @@ -9389,9 +9801,31 @@ gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCom error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n"); } return false; + } else if (c->curr_proc_decl != nullptr && c->curr_proc_calling_convention != ProcCC_Odin) { + if (c->scope != nullptr && (c->scope->flags & ScopeFlag_ContextDefined) == 0) { + error(node, "Compound literals of dynamic types require a 'context' to defined"); + } } - return cl->elems.count > 0; + return true; +} + +gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(CheckerContext *c, Ast *node) { + // TODO(bill): per file `#+feature` flags + u64 flags = check_feature_flags(c, node); + if ((flags & OptInFeatureFlag_IntegerDivisionByZero_Trap) != 0) { + return IntegerDivisionByZero_Trap; + } + if ((flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) != 0) { + return IntegerDivisionByZero_Zero; + } + if ((flags & OptInFeatureFlag_IntegerDivisionByZero_Self) != 0) { + return IntegerDivisionByZero_Self; + } + if ((flags & OptInFeatureFlag_IntegerDivisionByZero_AllBits) != 0) { + return IntegerDivisionByZero_AllBits; + } + return build_context.integer_division_by_zero_behaviour; } gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { @@ -9404,6 +9838,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } bool is_to_be_determined_array_count = false; bool is_constant = true; + bool is_soa = false; Ast *type_expr = cl->type; @@ -9436,8 +9871,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * GB_ASSERT(tag->kind == Ast_BasicDirective); String name = tag->BasicDirective.name.string; if (name == "soa") { - error(node, "#soa arrays are not supported for compound literals"); - return kind; + is_soa = true; + if (count == nullptr) { + error(node, "#soa slices are not supported for compound literals"); + return kind; + } else if (count->kind == Ast_UnaryExpr && + count->UnaryExpr.op.kind == Token_Question) { + error(node, "#soa fixed length arrays must specify their length and cannot use ?"); + } } } } @@ -9447,7 +9888,8 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * GB_ASSERT(tag->kind == Ast_BasicDirective); String name = tag->BasicDirective.name.string; if (name == "soa") { - error(node, "#soa arrays are not supported for compound literals"); + is_soa = true; + error(node, "#soa dynamic arrays are not supported for compound literals"); return kind; } } @@ -9476,101 +9918,101 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * switch (t->kind) { - case Type_Struct: { + case Type_Struct: if (cl->elems.count == 0) { break; // NOTE(bill): No need to init } - if (t->Struct.soa_kind != StructSoa_None) { - error(node, "#soa arrays are not supported for compound literals"); - break; - } + if (t->Struct.soa_kind == StructSoa_None) { + if (t->Struct.is_raw_union) { + if (cl->elems.count > 0) { + // NOTE: unions cannot be constant + is_constant = elem_type_can_be_constant(t); - if (t->Struct.is_raw_union) { - if (cl->elems.count > 0) { - // NOTE: unions cannot be constant - is_constant = false; - - if (cl->elems[0]->kind != Ast_FieldValue) { - gbString type_str = type_to_string(type); - error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str); - gb_string_free(type_str); - } else { - if (cl->elems.count != 1) { + if (cl->elems[0]->kind != Ast_FieldValue) { gbString type_str = type_to_string(type); - error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count); + error(node, "%s ('struct #raw_union') compound literals are only allowed to contain 'field = value' elements", type_str); gb_string_free(type_str); } else { - check_compound_literal_field_values(c, cl->elems, o, type, is_constant); + if (cl->elems.count != 1) { + gbString type_str = type_to_string(type); + error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count); + gb_string_free(type_str); + } else { + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); + } + } + } + break; + } + + wait_signal_until_available(&t->Struct.fields_wait_signal); + isize field_count = t->Struct.fields.count; + isize min_field_count = t->Struct.fields.count; + for (isize i = min_field_count-1; i >= 0; i--) { + Entity *e = t->Struct.fields[i]; + GB_ASSERT(e->kind == Entity_Variable); + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + min_field_count--; + } else { + break; + } + } + + if (cl->elems[0]->kind == Ast_FieldValue) { + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); + } else { + bool seen_field_value = false; + + for_array(index, cl->elems) { + Entity *field = nullptr; + Ast *elem = cl->elems[index]; + if (elem->kind == Ast_FieldValue) { + seen_field_value = true; + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } else if (seen_field_value) { + error(elem, "Value elements cannot be used after a 'field = value'"); + continue; + } + if (index >= field_count) { + error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count); + break; + } + + if (field == nullptr) { + field = t->Struct.fields[index]; + } + + Operand o = {}; + check_expr_or_type(c, &o, elem, field->type); + + if (elem_cannot_be_constant(field->type)) { + is_constant = false; + } + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &o, field->type); + } + + check_assignment(c, &o, field->type, str_lit("structure literal")); + } + if (cl->elems.count < field_count) { + if (min_field_count < field_count) { + if (cl->elems.count < min_field_count) { + error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count); + } + } else { + error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count); } } } + + break; + } else if (t->Struct.soa_kind != StructSoa_Fixed) { + error(node, "#soa slices and dynamic arrays are not supported for compound literals"); break; } - - wait_signal_until_available(&t->Struct.fields_wait_signal); - isize field_count = t->Struct.fields.count; - isize min_field_count = t->Struct.fields.count; - for (isize i = min_field_count-1; i >= 0; i--) { - Entity *e = t->Struct.fields[i]; - GB_ASSERT(e->kind == Entity_Variable); - if (e->Variable.param_value.kind != ParameterValue_Invalid) { - min_field_count--; - } else { - break; - } - } - - if (cl->elems[0]->kind == Ast_FieldValue) { - check_compound_literal_field_values(c, cl->elems, o, type, is_constant); - } else { - bool seen_field_value = false; - - for_array(index, cl->elems) { - Entity *field = nullptr; - Ast *elem = cl->elems[index]; - if (elem->kind == Ast_FieldValue) { - seen_field_value = true; - error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } else if (seen_field_value) { - error(elem, "Value elements cannot be used after a 'field = value'"); - continue; - } - if (index >= field_count) { - error(elem, "Too many values in structure literal, expected %td, got %td", field_count, cl->elems.count); - break; - } - - if (field == nullptr) { - field = t->Struct.fields[index]; - } - - Operand o = {}; - check_expr_or_type(c, &o, elem, field->type); - - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { - is_constant = false; - } - if (is_constant) { - is_constant = check_is_operand_compound_lit_constant(c, &o); - } - - check_assignment(c, &o, field->type, str_lit("structure literal")); - } - if (cl->elems.count < field_count) { - if (min_field_count < field_count) { - if (cl->elems.count < min_field_count) { - error(cl->close, "Too few values in structure literal, expected at least %td, got %td", min_field_count, cl->elems.count); - } - } else { - error(cl->close, "Too few values in structure literal, expected %td, got %td", field_count, cl->elems.count); - } - } - } - - break; - } + /*fallthrough*/ case Type_Slice: case Type_Array: @@ -9581,7 +10023,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * Type *elem_type = nullptr; String context_name = {}; i64 max_type_count = -1; - if (t->kind == Type_Slice) { + if (t->kind == Type_Struct) { + GB_ASSERT(t->Struct.soa_kind == StructSoa_Fixed); + elem_type = t->Struct.soa_elem; + context_name = str_lit("#soa array literal"); + if (!is_to_be_determined_array_count) { + max_type_count = t->Struct.soa_count; + } + } else if (t->kind == Type_Slice) { elem_type = t->Slice.elem; context_name = str_lit("slice literal"); } else if (t->kind == Type_Array) { @@ -9590,6 +10039,12 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (!is_to_be_determined_array_count) { max_type_count = t->Array.count; } + } else if (t->kind == Type_Array) { + elem_type = t->Array.elem; + context_name = str_lit("array literal"); + if (!is_to_be_determined_array_count) { + max_type_count = t->Array.count; + } } else if (t->kind == Type_DynamicArray) { elem_type = t->DynamicArray.elem; context_name = str_lit("dynamic array literal"); @@ -9681,7 +10136,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, fv->value, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } } else { Operand op_index = {}; check_expr(c, &op_index, fv->field); @@ -9713,7 +10170,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, fv->value, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } } } @@ -9740,7 +10199,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, e, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } } if (max < index) { @@ -9757,6 +10218,15 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * error(node, "Expected %lld values for this array literal, got %lld", cast(long long)t->Array.count, cast(long long)max); } } + } else if (t->kind == Type_Struct) { + GB_ASSERT(t->Struct.soa_kind == StructSoa_Fixed); + if (is_to_be_determined_array_count) { + t->Struct.soa_count = cast(i32)max; + } else if (cl->elems.count > 0 && cl->elems[0]->kind != Ast_FieldValue) { + if (0 < max && max < t->Struct.soa_count) { + error(node, "Expected %lld values for this #soa array literal, got %lld", cast(long long)t->Struct.soa_count, cast(long long)max); + } + } } @@ -9905,7 +10375,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, fv->value, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } TokenKind upper_op = Token_LtEq; if (op.kind == Token_RangeHalf) { @@ -9946,7 +10418,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, fv->value, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } add_to_seen_map(c, &seen, op_index); } @@ -9976,7 +10450,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * check_expr_with_type_hint(c, &operand, e, elem_type); check_assignment(c, &operand, elem_type, context_name); - is_constant = is_constant && operand.mode == Addressing_Constant; + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type); + } } if (max < index) { @@ -10180,52 +10656,48 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * is_constant = false; } - if (cl->elems[0]->kind == Ast_FieldValue) { - error(cl->elems[0], "'field = value' in a bit_set a literal is not allowed"); - is_constant = false; - } else { - for (Ast *elem : cl->elems) { - if (elem->kind == Ast_FieldValue) { - error(elem, "'field = value' in a bit_set a literal is not allowed"); + for (Ast *elem : cl->elems) { + if (elem->kind == Ast_FieldValue) { + error(elem, "'field = value' in a bit_set literal is not allowed"); + is_constant = false; + continue; + } + + check_expr_with_type_hint(c, o, elem, et); + + if (is_constant) { + is_constant = o->mode == Addressing_Constant; + } + + if (elem->kind == Ast_BinaryExpr) { + switch (elem->BinaryExpr.op.kind) { + case Token_Or: + { + gbString x = expr_to_string(elem->BinaryExpr.left); + gbString y = expr_to_string(elem->BinaryExpr.right); + gbString e = expr_to_string(elem); + error(elem, "Was the following intended? '%s, %s'; if not, surround the expression with parentheses '(%s)'", x, y, e); + gb_string_free(e); + gb_string_free(y); + gb_string_free(x); + } + break; + } + } + + check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal")); + if (o->mode == Addressing_Constant) { + i64 lower = t->BitSet.lower; + i64 upper = t->BitSet.upper; + i64 v = exact_value_to_i64(o->value); + if (lower <= v && v <= upper) { + // okay + } else { + gbString s = expr_to_string(o->expr); + error(elem, "Bit field value out of bounds, %s (%lld) not in the range %lld .. %lld", s, v, lower, upper); + gb_string_free(s); continue; } - - check_expr_with_type_hint(c, o, elem, et); - - if (is_constant) { - is_constant = o->mode == Addressing_Constant; - } - - if (elem->kind == Ast_BinaryExpr) { - switch (elem->BinaryExpr.op.kind) { - case Token_Or: - { - gbString x = expr_to_string(elem->BinaryExpr.left); - gbString y = expr_to_string(elem->BinaryExpr.right); - gbString e = expr_to_string(elem); - error(elem, "Was the following intended? '%s, %s'; if not, surround the expression with parentheses '(%s)'", x, y, e); - gb_string_free(e); - gb_string_free(y); - gb_string_free(x); - } - break; - } - } - - check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal")); - if (o->mode == Addressing_Constant) { - i64 lower = t->BitSet.lower; - i64 upper = t->BitSet.upper; - i64 v = exact_value_to_i64(o->value); - if (lower <= v && v <= upper) { - // okay - } else { - gbString s = expr_to_string(o->expr); - error(elem, "Bit field value out of bounds, %s (%lld) not in the range %lld .. %lld", s, v, lower, upper); - gb_string_free(s); - continue; - } - } } } break; @@ -10586,7 +11058,7 @@ gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast } } - auto modified_args = slice_make(heap_allocator(), ce->args.count+1); + auto modified_args = permanent_slice_make(ce->args.count+1); modified_args[0] = first_arg; slice_copy(&modified_args, ce->args, 1); ce->args = modified_args; @@ -10751,9 +11223,17 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, if (t->Basic.kind == Basic_string || t->Basic.kind == Basic_UntypedString) { valid = true; if (o->mode == Addressing_Constant) { + GB_ASSERT(o->value.kind == ExactValue_String); max_count = o->value.value_string.len; } o->type = type_deref(o->type); + } else if (t->Basic.kind == Basic_string16) { + valid = true; + if (o->mode == Addressing_Constant) { + GB_ASSERT(o->value.kind == ExactValue_String16); + max_count = o->value.value_string16.len; + } + o->type = type_deref(o->type); } break; @@ -10908,15 +11388,21 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, o->expr = node; return kind; } - - String s = {}; - if (o->value.kind == ExactValue_String) { - s = o->value.value_string; - } - o->mode = Addressing_Constant; o->type = t; - o->value = exact_value_string(substring(s, cast(isize)indices[0], cast(isize)indices[1])); + + if (o->value.kind == ExactValue_String16) { + String16 s = o->value.value_string16; + + o->value = exact_value_string16(substring(s, cast(isize)indices[0], cast(isize)indices[1])); + } else { + String s = {}; + if (o->value.kind == ExactValue_String) { + s = o->value.value_string; + } + + o->value = exact_value_string(substring(s, cast(isize)indices[0], cast(isize)indices[1])); + } } return kind; } @@ -10961,7 +11447,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast return kind; case_end; - case_ast_node(i, Implicit, node) + case_ast_node(i, Implicit, node); switch (i->kind) { case Token_context: { @@ -10997,7 +11483,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case_ast_node(u, Uninit, node); o->mode = Addressing_Value; o->type = t_untyped_uninit; - error(node, "Use of --- outside of variable declaration"); + error(node, "Global variables will always be zeroed if left unassigned, --- is disallowed"); case_end; @@ -11005,6 +11491,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast Type *t = t_invalid; switch (node->tav.value.kind) { case ExactValue_String: t = t_untyped_string; break; + case ExactValue_String16: t = t_string16; break; // TODO(bill): determine this correctly case ExactValue_Float: t = t_untyped_float; break; case ExactValue_Complex: t = t_untyped_complex; break; case ExactValue_Quaternion: t = t_untyped_quaternion; break; @@ -11074,6 +11561,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast o->mode = Addressing_Value; o->type = type; + o->value = exact_value_procedure(node); case_end; case_ast_node(te, TernaryIfExpr, node); @@ -11229,6 +11717,13 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast node->viral_state_flags |= de->expr->viral_state_flags; if (o->mode == Addressing_Invalid) { + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } else if (o->mode == Addressing_Type) { + gbString str = expr_to_string(o->expr); + error(o->expr, "Cannot dereference '%s' because it is a type", str); + o->mode = Addressing_Invalid; o->expr = node; return kind; @@ -11434,6 +11929,8 @@ gb_internal bool is_exact_value_zero(ExactValue const &v) { return !v.value_bool; case ExactValue_String: return v.value_string.len == 0; + case ExactValue_String16: + return v.value_string16.len == 0; case ExactValue_Integer: return big_int_is_zero(&v.value_integer); case ExactValue_Float: diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index e81996566..5e7a8e323 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -418,7 +418,7 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) { -gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) { +gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs, String context_name) { if (rhs->mode == Addressing_Invalid) { return nullptr; } @@ -430,8 +430,6 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O Ast *node = unparen_expr(lhs->expr); - check_no_copy_assignment(*rhs, str_lit("assignment")); - // NOTE(bill): Ignore assignments to '_' if (is_blank_ident(node)) { check_assignment(ctx, rhs, nullptr, str_lit("assignment to '_' identifier")); @@ -486,7 +484,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O } if (ident_node != nullptr) { ast_node(i, Ident, ident_node); - e = scope_lookup(ctx->scope, i->token.string); + e = scope_lookup(ctx->scope, i->token.string, i->hash); if (e != nullptr && e->kind == Entity_Variable) { used = (e->flags & EntityFlag_Used) != 0; // NOTE(bill): Make backup just in case } @@ -630,7 +628,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O ctx->bit_field_bit_size = lhs_e->Variable.bit_field_bit_size; } - check_assignment(ctx, rhs, assignment_type, str_lit("assignment")); + check_assignment(ctx, rhs, assignment_type, context_name); ctx->bit_field_bit_size = prev_bit_field_bit_size; @@ -976,7 +974,14 @@ gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod Type *t = base_type(operand.type); switch (t->kind) { case Type_Basic: - if (is_type_string(t) && t->Basic.kind != Basic_cstring) { + if (is_type_string16(t) && t->Basic.kind != Basic_cstring) { + val0 = t_rune; + val1 = t_int; + inline_for_depth = exact_value_i64(operand.value.value_string.len); + if (unroll_count > 0) { + error(node, "#unroll(%lld) does not support strings", cast(long long)unroll_count); + } + } else if (is_type_string(t) && t->Basic.kind != Basic_cstring) { val0 = t_rune; val1 = t_int; inline_for_depth = exact_value_i64(operand.value.value_string.len); @@ -1238,7 +1243,11 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags add_to_seen_map(ctx, &seen, upper_op, x, lhs, rhs); - if (is_type_string(x.type)) { + if (is_type_string16(x.type)) { + // NOTE(bill): Force dependency for strings here + add_package_dependency(ctx, "runtime", "string16_le"); + add_package_dependency(ctx, "runtime", "string16_lt"); + } else if (is_type_string(x.type)) { // NOTE(bill): Force dependency for strings here add_package_dependency(ctx, "runtime", "string_le"); add_package_dependency(ctx, "runtime", "string_lt"); @@ -1593,6 +1602,20 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ error_line("\tSuggestion: Was '#partial switch' wanted?\n"); } } + + if (build_context.strict_style) { + Token stok = ss->token; + for_array(i, bs->stmts) { + Ast *stmt = bs->stmts[i]; + if (stmt->kind != Ast_CaseClause) { + continue; + } + Token ctok = stmt->CaseClause.token; + if (ctok.pos.column > stok.pos.column) { + error(ctok, "With '-strict-style', 'case' statements must share the same column as the 'switch' token"); + } + } + } } gb_internal void check_block_stmt_for_errors(CheckerContext *ctx, Ast *body) { @@ -1758,7 +1781,16 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) switch (t->kind) { case Type_Basic: - if (t->Basic.kind == Basic_string || t->Basic.kind == Basic_UntypedString) { + if (t->Basic.kind == Basic_string16) { + is_possibly_addressable = false; + array_add(&vals, t_rune); + array_add(&vals, t_int); + if (is_reverse) { + add_package_dependency(ctx, "runtime", "string16_decode_last_rune"); + } else { + add_package_dependency(ctx, "runtime", "string16_decode_rune"); + } + } else if (t->Basic.kind == Basic_string || t->Basic.kind == Basic_UntypedString) { is_possibly_addressable = false; array_add(&vals, t_rune); array_add(&vals, t_int); @@ -1780,8 +1812,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) error(node, "Iteration over a bit_set of an enum is not allowed runtime type information (RTTI) has been disallowed"); } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { - String name = rs->vals[0]->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name); + AstIdent *ident = &rs->vals[0]->Ident; + String name = ident->token.string; + Entity *found = scope_lookup(ctx->scope, name, ident->hash); if (found && are_types_identical(found->type, t->BitSet.elem)) { ERROR_BLOCK(); gbString s = expr_to_string(expr); @@ -1825,8 +1858,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) error(node, "#reverse for is not supported for map types, as maps are unordered"); } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { - String name = rs->vals[0]->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name); + AstIdent *ident = &rs->vals[0]->Ident; + String name = ident->token.string; + Entity *found = scope_lookup(ctx->scope, name, ident->hash); if (found && are_types_identical(found->type, t->Map.key)) { ERROR_BLOCK(); gbString s = expr_to_string(expr); @@ -1931,7 +1965,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } auto rhs = slice_from_array(vals); - auto lhs = slice_make(temporary_allocator(), rhs.count); + auto lhs = temporary_slice_make(rhs.count); slice_copy(&lhs, rs->vals); isize addressable_index = cast(isize)is_map; @@ -2108,10 +2142,12 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f if (init_type == nullptr) { init_type = t_invalid; } else if (is_type_polymorphic(base_type(init_type))) { + /* DISABLED: This error seems too aggressive for instantiated generic types. gbString str = type_to_string(init_type); error(vd->type, "Invalid use of a polymorphic type '%s' in variable declaration", str); gb_string_free(str); init_type = t_invalid; + */ } if (init_type == t_invalid && entity_count == 1 && (mod_flags & (Stmt_BreakAllowed|Stmt_FallthroughAllowed))) { Entity *e = entities[0]; @@ -2402,7 +2438,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) { isize lhs_count = as->lhs.count; if (lhs_count == 0) { - error(as->op, "Missing lhs in assignment statement"); + error(as->op, "Missing LHS in assignment statement"); return; } @@ -2435,7 +2471,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) { if (lhs_to_ignore[i]) { continue; } - check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i]); + check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i], str_lit("assignment")); } if (lhs_count != rhs_count) { error(as->lhs[0], "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count); @@ -2445,11 +2481,11 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) { // a += 1; // Single-sided Token op = as->op; if (as->lhs.count != 1 || as->rhs.count != 1) { - error(op, "Assignment operation '%.*s' requires single-valued expressions", LIT(op.string)); + error(op, "Assignment operator '%.*s' requires single-valued operands", LIT(op.string)); return; } if (!gb_is_between(op.kind, Token__AssignOpBegin+1, Token__AssignOpEnd-1)) { - error(op, "Unknown Assignment operation '%.*s'", LIT(op.string)); + error(op, "Unknown assignment operator '%.*s'", LIT(op.string)); return; } Operand lhs = {Addressing_Invalid}; @@ -2458,15 +2494,16 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) { ast_node(be, BinaryExpr, binary_expr); be->op = op; be->op.kind = cast(TokenKind)(cast(i32)be->op.kind - (Token_AddEq - Token_Add)); - // NOTE(bill): Only use the first one will be used + // NOTE(bill): Only use the first one will be used be->left = as->lhs[0]; be->right = as->rhs[0]; check_expr(ctx, &lhs, as->lhs[0]); check_binary_expr(ctx, &rhs, binary_expr, nullptr, true); if (rhs.mode != Addressing_Invalid) { - // NOTE(bill): Only use the first one will be used - check_assignment_variable(ctx, &lhs, &rhs); + be->op.string = substring(be->op.string, 0, be->op.string.len - 1); + rhs.expr = binary_expr; + check_assignment_variable(ctx, &lhs, &rhs, str_lit("assignment operation")); } } } @@ -2504,6 +2541,78 @@ gb_internal void check_if_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { check_close_scope(ctx); } +// NOTE(bill): This is very basic escape analysis +// This needs to be improved tremendously, and a lot of it done during the +// middle-end (or LLVM side) to improve checks and error messages +void check_unsafe_return(Operand const &o, Type *type, Ast *expr) { + auto const unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) { + gbString s = expr_to_string(o.expr); + if (extra_type) { + gbString t = type_to_string(extra_type); + error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t); + gb_string_free(t); + } else { + error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s); + } + gb_string_free(s); + }; + + if (type == nullptr || expr == nullptr) { + return; + } + + if (expr->kind == Ast_CompoundLit && is_type_slice(type)) { + ast_node(cl, CompoundLit, expr); + if (cl->elems.count == 0) { + return; + } + unsafe_return_error(o, "a compound literal of a slice"); + } else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) { + Ast *x = unparen_expr(expr->UnaryExpr.expr); + Entity *e = entity_of_node(x); + if (is_entity_local_variable(e)) { + unsafe_return_error(o, "the address of a local variable"); + } else if (x->kind == Ast_CompoundLit) { + unsafe_return_error(o, "the address of a compound literal"); + } else if (x->kind == Ast_IndexExpr) { + Entity *f = entity_of_node(x->IndexExpr.expr); + if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) { + if (is_entity_local_variable(f)) { + unsafe_return_error(o, "the address of an indexed variable", f->type); + } + } + } else if (x->kind == Ast_MatrixIndexExpr) { + Entity *f = entity_of_node(x->MatrixIndexExpr.expr); + if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) { + unsafe_return_error(o, "the address of an indexed variable", f->type); + } + } + } else if (expr->kind == Ast_SliceExpr) { + Ast *x = unparen_expr(expr->SliceExpr.expr); + Entity *e = entity_of_node(x); + if (is_entity_local_variable(e) && is_type_array(e->type)) { + unsafe_return_error(o, "a slice of a local variable"); + } else if (x->kind == Ast_CompoundLit) { + unsafe_return_error(o, "a slice of a compound literal"); + } + } else if (o.mode == Addressing_Constant && is_type_slice(type)) { + ERROR_BLOCK(); + unsafe_return_error(o, "a compound literal of a slice"); + error_line("\tNote: A constant slice value will use the memory of the current stack frame\n"); + } else if (expr->kind == Ast_CompoundLit) { + ast_node(cl, CompoundLit, expr); + for (Ast *elem : cl->elems) { + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + Entity *e = entity_of_node(fv->field); + if (e != nullptr) { + check_unsafe_return(o, e->type, fv->value); + } + } + } + } +} + gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { ast_node(rs, ReturnStmt, node); @@ -2532,8 +2641,9 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { result_count = proc_type->Proc.results->Tuple.variables.count; } - auto operands = array_make(heap_allocator(), 0, 2*rs->results.count); - defer (array_free(&operands)); + TEMPORARY_ALLOCATOR_GUARD(); + + auto operands = array_make(temporary_allocator(), 0, 2*rs->results.count); check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk); @@ -2579,61 +2689,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { expr = unparen_expr(arg); } - auto unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) { - gbString s = expr_to_string(o.expr); - if (extra_type) { - gbString t = type_to_string(extra_type); - error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t); - gb_string_free(t); - } else { - error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s); - } - gb_string_free(s); - }; - - - // NOTE(bill): This is very basic escape analysis - // This needs to be improved tremendously, and a lot of it done during the - // middle-end (or LLVM side) to improve checks and error messages - if (expr->kind == Ast_CompoundLit && is_type_slice(o.type)) { - ast_node(cl, CompoundLit, expr); - if (cl->elems.count == 0) { - continue; - } - unsafe_return_error(o, "a compound literal of a slice"); - } else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) { - Ast *x = unparen_expr(expr->UnaryExpr.expr); - Entity *e = entity_of_node(x); - if (is_entity_local_variable(e)) { - unsafe_return_error(o, "the address of a local variable"); - } else if (x->kind == Ast_CompoundLit) { - unsafe_return_error(o, "the address of a compound literal"); - } else if (x->kind == Ast_IndexExpr) { - Entity *f = entity_of_node(x->IndexExpr.expr); - if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) { - if (is_entity_local_variable(f)) { - unsafe_return_error(o, "the address of an indexed variable", f->type); - } - } - } else if (x->kind == Ast_MatrixIndexExpr) { - Entity *f = entity_of_node(x->MatrixIndexExpr.expr); - if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) { - unsafe_return_error(o, "the address of an indexed variable", f->type); - } - } - } else if (expr->kind == Ast_SliceExpr) { - Ast *x = unparen_expr(expr->SliceExpr.expr); - Entity *e = entity_of_node(x); - if (is_entity_local_variable(e) && is_type_array(e->type)) { - unsafe_return_error(o, "a slice of a local variable"); - } else if (x->kind == Ast_CompoundLit) { - unsafe_return_error(o, "a slice of a compound literal"); - } - } else if (o.mode == Addressing_Constant && is_type_slice(o.type)) { - ERROR_BLOCK(); - unsafe_return_error(o, "a compound literal of a slice"); - error_line("\tNote: A constant slice value will use the memory of the current stack frame\n"); - } + check_unsafe_return(o, o.type, expr); } } @@ -2755,6 +2811,51 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) if (ctx->decl) { ctx->decl->defer_used += 1; } + + // NOTE(bill): Handling errors/warnings + + Ast *stmt = ds->stmt; + Ast *original_stmt = stmt; + + if (stmt->kind == Ast_BlockStmt && stmt->BlockStmt.stmts.count == 0) { + break; // empty defer statement + } + + bool is_singular = true; + while (is_singular && stmt->kind == Ast_BlockStmt) { + Ast *inner_stmt = nullptr; + for (Ast *s : stmt->BlockStmt.stmts) { + if (s->kind == Ast_EmptyStmt) { + continue; + } + if (inner_stmt != nullptr) { + is_singular = false; + break; + } + inner_stmt = s; + } + + if (inner_stmt != nullptr) { + stmt = inner_stmt; + } + } + if (!is_singular) { + stmt = original_stmt; + } + + switch (stmt->kind) { + case_ast_node(as, AssignStmt, stmt); + if (as->op.kind != Token_Eq) { + break; + } + for (Ast *lhs : as->lhs) { + Entity *e = entity_of_node(lhs); + if (e && e->flags & EntityFlag_Result) { + error(lhs, "Assignments to named return values within 'defer' will not affect the value that is returned"); + } + } + case_end; + } } case_end; @@ -2812,6 +2913,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) case Ast_BlockStmt: case Ast_IfStmt: case Ast_SwitchStmt: + case Ast_TypeSwitchStmt: if (token.kind != Token_break) { error(bs->label, "Label '%.*s' can only be used with 'break'", LIT(e->token.string)); } diff --git a/src/check_type.cpp b/src/check_type.cpp index 9d4defbb2..0819de217 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -267,28 +267,39 @@ gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_, gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type) { - mutex_lock(&ctx->info->gen_types_mutex); // @@global - GenTypesData *found_gen_types = nullptr; - auto *found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type); - if (found_gen_types_ptr == nullptr) { + + GB_ASSERT(original_type->kind == Type_Named); + mutex_lock(&original_type->Named.gen_types_data_mutex); + if (original_type->Named.gen_types_data == nullptr) { GenTypesData *gen_types = gb_alloc_item(permanent_allocator(), GenTypesData); gen_types->types = array_make(heap_allocator()); - map_set(&ctx->info->gen_types, original_type, gen_types); - found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type); + original_type->Named.gen_types_data = gen_types; } - found_gen_types = *found_gen_types_ptr; - GB_ASSERT(found_gen_types != nullptr); - mutex_unlock(&ctx->info->gen_types_mutex); // @@global + found_gen_types = original_type->Named.gen_types_data; + + mutex_unlock(&original_type->Named.gen_types_data_mutex); + return found_gen_types; } gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_type, Type *original_type) { GB_ASSERT(is_type_named(named_type)); + GB_ASSERT(original_type->kind == Type_Named); gbAllocator a = heap_allocator(); Scope *s = ctx->scope->parent; + AstPackage *pkg = nullptr; + if (original_type->Named.type_name && original_type->Named.type_name->pkg) { + pkg = original_type->Named.type_name->pkg; + } + + if (pkg == nullptr) { + // NOTE(bill): if the `pkg` cannot be determined, default to the current context's pkg instead + pkg = ctx->pkg; + } + Entity *e = nullptr; { Token token = ast_token(node); @@ -300,12 +311,12 @@ gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, T e = alloc_entity_type_name(s, token, named_type); e->state = EntityState_Resolved; e->file = ctx->file; - e->pkg = ctx->pkg; + e->pkg = pkg; + e->TypeName.original_type_for_parapoly = original_type; add_entity_use(ctx, node, e); } named_type->Named.type_name = e; - GB_ASSERT(original_type->kind == Type_Named); e->TypeName.objc_class_name = original_type->Named.type_name->TypeName.objc_class_name; // TODO(bill): Is this even correct? Or should the metadata be copied? e->TypeName.objc_metadata = original_type->Named.type_name->TypeName.objc_metadata; @@ -646,7 +657,6 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * struct_type->Struct.node = node; struct_type->Struct.scope = ctx->scope; struct_type->Struct.is_packed = st->is_packed; - struct_type->Struct.is_no_copy = st->is_no_copy; struct_type->Struct.polymorphic_params = check_record_polymorphic_params( ctx, st->polymorphic_params, &struct_type->Struct.is_polymorphic, @@ -1097,7 +1107,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, GB_ASSERT(fields.count <= bf->fields.count); - auto bit_offsets = slice_make(permanent_allocator(), fields.count); + auto bit_offsets = permanent_slice_make(fields.count); i64 curr_offset = 0; for_array(i, bit_sizes) { bit_offsets[i] = curr_offset; @@ -1155,8 +1165,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, } } - - + #if 0 // Reconsider at a later date if (bit_sizes.count > 0 && is_type_integer(backing_type)) { bool all_booleans = is_type_boolean(fields[0]->type); bool all_ones = bit_sizes[0] == 1; @@ -1182,7 +1191,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, } } } - + #endif bit_field_type->BitField.fields = slice_from_array(fields); bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes); @@ -1911,9 +1920,18 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para case ParameterValue_Location: case ParameterValue_Expression: case ParameterValue_Value: + // Special case for polymorphic procedures as default values + if (param_value.ast_value != nullptr) { + Entity *e = entity_from_expr(param_value.ast_value); + if (e != nullptr && e->kind == Entity_Procedure && is_type_polymorphic(e->type)) { + // Allow polymorphic procedures as default parameter values + // The type will be correctly determined at call site + break; + } + } gbString str = type_to_string(type); error(params[i], "A default value for a parameter must not be a polymorphic constant type, got %s", str); - gb_string_free(str); + gb_string_free(str); break; } } @@ -2068,7 +2086,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (op.mode == Addressing_Constant) { poly_const = op.value; } else { - error(op.expr, "Expected a constant value for this polymorphic name parameter, got %s", expr_to_string(op.expr)); + if (!ctx->in_proc_group) { + error(op.expr, "Expected a constant value for this polymorphic name parameter, got %s", expr_to_string(op.expr)); + } success = false; } } @@ -2082,7 +2102,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (type != t_invalid && !check_is_assignable_to(ctx, &op, type, allow_array_programming)) { bool ok = true; if (p->flags&FieldFlag_any_int) { - if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) { + if (op.type == nullptr) { + ok = false; + } else if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) { ok = false; } else if (!check_is_castable_to(ctx, &op, type)) { ok = false; @@ -2686,7 +2708,7 @@ gb_internal Type *get_map_cell_type(Type *type) { // Padding exists Type *s = alloc_type_struct(); Scope *scope = create_scope(nullptr, nullptr); - s->Struct.fields = slice_make(permanent_allocator(), 2); + s->Struct.fields = permanent_slice_make(2); s->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("v"), alloc_type_array(type, len), false, 0, EntityState_Resolved); s->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("_"), alloc_type_array(t_u8, padding), false, 1, EntityState_Resolved); s->Struct.scope = scope; @@ -2711,7 +2733,7 @@ gb_internal void init_map_internal_debug_types(Type *type) { Type *metadata_type = alloc_type_struct(); Scope *metadata_scope = create_scope(nullptr, nullptr); - metadata_type->Struct.fields = slice_make(permanent_allocator(), 5); + metadata_type->Struct.fields = permanent_slice_make(5); metadata_type->Struct.fields[0] = alloc_entity_field(metadata_scope, make_token_ident("key"), key, false, 0, EntityState_Resolved); metadata_type->Struct.fields[1] = alloc_entity_field(metadata_scope, make_token_ident("value"), value, false, 1, EntityState_Resolved); metadata_type->Struct.fields[2] = alloc_entity_field(metadata_scope, make_token_ident("hash"), t_uintptr, false, 2, EntityState_Resolved); @@ -2729,7 +2751,7 @@ gb_internal void init_map_internal_debug_types(Type *type) { Scope *scope = create_scope(nullptr, nullptr); Type *debug_type = alloc_type_struct(); - debug_type->Struct.fields = slice_make(permanent_allocator(), 3); + debug_type->Struct.fields = permanent_slice_make(3); debug_type->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("data"), metadata_type, false, 0, EntityState_Resolved); debug_type->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("len"), t_int, false, 1, EntityState_Resolved); debug_type->Struct.fields[2] = alloc_entity_field(scope, make_token_ident("allocator"), t_allocator, false, 2, EntityState_Resolved); @@ -2773,6 +2795,21 @@ gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) { return; } + if (key->kind == Type_Basic) { + if (key->Basic.flags & BasicFlag_Quaternion) { + add_package_dependency(ctx, "runtime", "default_hasher_f64"); + add_package_dependency(ctx, "runtime", "default_hasher_quaternion256"); + return; + } else if (key->Basic.flags & BasicFlag_Complex) { + add_package_dependency(ctx, "runtime", "default_hasher_f64"); + add_package_dependency(ctx, "runtime", "default_hasher_complex128"); + return; + } else if (key->Basic.flags & BasicFlag_Float) { + add_package_dependency(ctx, "runtime", "default_hasher_f64"); + return; + } + } + if (key->kind == Type_Struct) { add_package_dependency(ctx, "runtime", "default_hasher"); for_array(i, key->Struct.fields) { @@ -2947,13 +2984,13 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis if (wait_to_finish) { wait_signal_until_available(&old_struct->Struct.fields_wait_signal); } else { - GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load()); + GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load() != 0); } field_count = old_struct->Struct.fields.count; - t->Struct.fields = slice_make(permanent_allocator(), field_count+extra_field_count); - t->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); + t->Struct.fields = permanent_slice_make(field_count+extra_field_count); + t->Struct.tags = permanent_alloc_array(field_count+extra_field_count); auto const &add_entity = [](Scope *scope, Entity *entity) { @@ -3071,7 +3108,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e if (is_polymorphic) { field_count = 0; - soa_struct->Struct.fields = slice_make(permanent_allocator(), field_count+extra_field_count); + soa_struct->Struct.fields = permanent_slice_make(field_count+extra_field_count); soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); soa_struct->Struct.soa_count = 0; @@ -3081,7 +3118,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e Type *old_array = base_type(elem); field_count = cast(isize)old_array->Array.count; - soa_struct->Struct.fields = slice_make(permanent_allocator(), field_count+extra_field_count); + soa_struct->Struct.fields = permanent_slice_make(field_count+extra_field_count); soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); string_map_init(&scope->elements, 8); @@ -3123,8 +3160,8 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e if (old_struct->Struct.fields_wait_signal.futex.load()) { field_count = old_struct->Struct.fields.count; - soa_struct->Struct.fields = slice_make(permanent_allocator(), field_count+extra_field_count); - soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count); + soa_struct->Struct.fields = permanent_slice_make(field_count+extra_field_count); + soa_struct->Struct.tags = permanent_alloc_array(field_count+extra_field_count); for_array(i, old_struct->Struct.fields) { Entity *old_field = old_struct->Struct.fields[i]; @@ -3259,7 +3296,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t } if (count < 0) { - error(at->count, "? can only be used in conjuction with compound literals"); + error(at->count, "? can only be used in conjunction with compound literals"); count = 0; } @@ -3281,8 +3318,11 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t if (generic_type != nullptr) { // Ignore } else if (count < 1 || !is_power_of_two(count)) { - error(at->count, "Invalid length for #simd, expected a power of two length, got '%lld'", cast(long long)count); *type = alloc_type_array(elem, count, generic_type); + if (ctx->disallow_polymorphic_return_types && count == 0) { + return; + } + error(at->count, "Invalid length for #simd, expected a power of two length, got '%lld'", cast(long long)count); return; } @@ -3316,7 +3356,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t } } gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) { - GB_ASSERT_NOT_NULL(type); + GB_ASSERT(type != nullptr); if (e == nullptr) { *type = t_invalid; return true; @@ -3473,8 +3513,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T case_ast_node(pt, PointerType, e); CheckerContext c = *ctx; - c.type_path = new_checker_type_path(); - defer (destroy_checker_type_path(c.type_path)); + + TEMPORARY_ALLOCATOR_GUARD(); + c.type_path = new_checker_type_path(temporary_allocator()); Type *elem = t_invalid; Operand o = {}; @@ -3502,6 +3543,17 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T elem = o.type; } + if (!ctx->in_polymorphic_specialization && ctx->disallow_polymorphic_return_types) { + Type *t = base_type(elem); + if (t != nullptr && + unparen_expr(pt->type)->kind == Ast_Ident && + is_type_polymorphic_record_unspecialized(t)) { + gbString err_str = expr_to_string(e); + error(e, "Invalid use of a non-specialized polymorphic type '%s'", err_str); + gb_string_free(err_str); + } + } + if (pt->tag != nullptr) { GB_ASSERT(pt->tag->kind == Ast_BasicDirective); @@ -3697,8 +3749,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T gb_internal Type *check_type(CheckerContext *ctx, Ast *e) { CheckerContext c = *ctx; - c.type_path = new_checker_type_path(); - defer (destroy_checker_type_path(c.type_path)); + TEMPORARY_ALLOCATOR_GUARD(); + c.type_path = new_checker_type_path(temporary_allocator()); return check_type_expr(&c, e, nullptr); } @@ -3766,7 +3818,11 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) #if 0 error(e, "Invalid type definition of '%.*s'", LIT(type->Named.name)); #endif - type->Named.base = t_invalid; + if (type->Named.type_name->TypeName.is_type_alias) { + // NOTE(laytan): keep it null, type declaration is a mini "cycle" to be filled later. + } else { + type->Named.base = t_invalid; + } } if (is_type_polymorphic(type)) { @@ -3784,7 +3840,7 @@ gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) } #endif - if (is_type_typed(type)) { + if (type->kind == Type_Named && type->Named.base == nullptr || is_type_typed(type)) { add_type_and_value(ctx, e, Addressing_Type, type, empty_exact_value); } else { gbString name = type_to_string(type); diff --git a/src/checker.cpp b/src/checker.cpp index bee3f1efe..0a8590570 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -380,16 +380,25 @@ gb_internal Entity *scope_lookup_current(Scope *s, String const &name) { } -gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_) { +gb_global std::atomic in_single_threaded_checker_stage; + +gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entity **entity_, u32 hash) { + bool is_single_threaded = in_single_threaded_checker_stage.load(std::memory_order_relaxed); if (scope != nullptr) { bool gone_thru_proc = false; bool gone_thru_package = false; - StringHashKey key = string_hash_string(name); + StringHashKey key = {}; + if (hash) { + key.hash = hash; + key.string = name; + } else { + key = string_hash_string(name); + } for (Scope *s = scope; s != nullptr; s = s->parent) { Entity **found = nullptr; - rw_mutex_shared_lock(&s->mutex); + if (!is_single_threaded) rw_mutex_shared_lock(&s->mutex); found = string_map_get(&s->elements, key); - rw_mutex_shared_unlock(&s->mutex); + if (!is_single_threaded) rw_mutex_shared_unlock(&s->mutex); if (found) { Entity *e = *found; if (gone_thru_proc) { @@ -424,9 +433,9 @@ gb_internal void scope_lookup_parent(Scope *scope, String const &name, Scope **s if (scope_) *scope_ = nullptr; } -gb_internal Entity *scope_lookup(Scope *s, String const &name) { +gb_internal Entity *scope_lookup(Scope *s, String const &name, u32 hash) { Entity *entity = nullptr; - scope_lookup_parent(s, name, nullptr, &entity); + scope_lookup_parent(s, name, nullptr, &entity, hash); return entity; } @@ -507,11 +516,9 @@ end:; return result; } -gb_global bool in_single_threaded_checker_stage = false; - gb_internal Entity *scope_insert(Scope *s, Entity *entity) { String name = entity->token.string; - if (in_single_threaded_checker_stage) { + if (in_single_threaded_checker_stage.load(std::memory_order_relaxed)) { return scope_insert_with_name_no_mutex(s, name, entity); } else { return scope_insert_with_name(s, name, entity); @@ -565,6 +572,26 @@ gb_internal u64 check_feature_flags(CheckerContext *c, Ast *node) { return 0; } +gb_internal u64 check_feature_flags(Entity *e) { + if (e == nullptr) { + return 0; + } + AstFile *file = nullptr; + if (e->file == nullptr) { + file = e->file; + } + if (file == nullptr) { + if (e->decl_info && e->decl_info->decl_node) { + file = e->decl_info->decl_node->file(); + } + } + if (file != nullptr && file->feature_flags_set) { + return file->feature_flags; + } + return 0; +} + + enum VettedEntityKind { VettedEntity_Invalid, @@ -702,9 +729,10 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) { gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_flags, bool per_entity) { u64 original_vet_flags = vet_flags; + + TEMPORARY_ALLOCATOR_GUARD(); Array vetted_entities = {}; - array_init(&vetted_entities, heap_allocator()); - defer (array_free(&vetted_entities)); + array_init(&vetted_entities, temporary_allocator()); rw_mutex_shared_lock(&scope->mutex); for (auto const &entry : scope->elements) { @@ -728,12 +756,17 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl bool is_unused = false; if (vet_unused && check_vet_unused(c, e, &ve_unused)) { is_unused = true; - } else if (vet_unused_procedures && - e->kind == Entity_Procedure) { + } else if (vet_unused_procedures && e->kind == Entity_Procedure) { if (e->flags&EntityFlag_Used) { is_unused = false; } else if (e->flags & EntityFlag_Require) { is_unused = false; + } else if (e->flags & EntityFlag_Init) { + is_unused = false; + } else if (e->flags & EntityFlag_Fini) { + is_unused = false; + } else if (e->Procedure.is_export) { + is_unused = false; } else if (e->pkg && e->pkg->kind == Package_Init && e->token.string == "main") { is_unused = false; } else { @@ -751,7 +784,7 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl array_add(&vetted_entities, ve_unused); } else if (is_shadowed) { array_add(&vetted_entities, ve_shadowed); - } else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using|EntityFlag_Static)) == 0 && !e->Variable.is_global) { + } else if (e->kind == Entity_Variable && (e->flags & (EntityFlag_Param|EntityFlag_Using|EntityFlag_Static|EntityFlag_Field)) == 0 && !e->Variable.is_global) { i64 sz = type_size_of(e->type); // TODO(bill): When is a good size warn? // Is >256 KiB good enough? @@ -827,9 +860,13 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { gb_internal void add_dependency(CheckerInfo *info, DeclInfo *d, Entity *e) { - rw_mutex_lock(&d->deps_mutex); - ptr_set_add(&d->deps, e); - rw_mutex_unlock(&d->deps_mutex); + if (in_single_threaded_checker_stage.load(std::memory_order_relaxed)) { + ptr_set_add(&d->deps, e); + } else { + rw_mutex_lock(&d->deps_mutex); + ptr_set_add(&d->deps, e); + rw_mutex_unlock(&d->deps_mutex); + } } gb_internal void add_type_info_dependency(CheckerInfo *info, DeclInfo *d, Type *type) { if (d == nullptr || type == nullptr) { @@ -1073,11 +1110,30 @@ gb_internal void init_universal(void) { add_global_bool_constant("true", true); add_global_bool_constant("false", false); - add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR); - add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION); - add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT); - add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME); - add_global_string_constant("ODIN_WINDOWS_SUBSYSTEM", bc->ODIN_WINDOWS_SUBSYSTEM); + add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR); + add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION); + add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT); + add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME); + + { + GlobalEnumValue values[Windows_Subsystem_COUNT] = { + {"Unknown", Windows_Subsystem_UNKNOWN}, + {"Boot_Application", Windows_Subsystem_BOOT_APPLICATION}, + {"Console", Windows_Subsystem_CONSOLE}, + {"EFI_Application", Windows_Subsystem_EFI_APPLICATION}, + {"EFI_Boot_Service_Driver", Windows_Subsystem_EFI_BOOT_SERVICE_DRIVER}, + {"EFI_Rom", Windows_Subsystem_EFI_ROM}, + {"EFI_Runtime_Driver", Windows_Subsystem_EFI_RUNTIME_DRIVER}, + {"Native", Windows_Subsystem_NATIVE}, + {"Posix", Windows_Subsystem_POSIX}, + {"Windows", Windows_Subsystem_WINDOWS}, + {"Windows_CE", Windows_Subsystem_WINDOWSCE}, + }; + + auto fields = add_global_enum_type(str_lit("Odin_Windows_Subsystem_Type"), values, gb_count_of(values)); + add_global_enum_constant(fields, "ODIN_WINDOWS_SUBSYSTEM", bc->ODIN_WINDOWS_SUBSYSTEM); + add_global_string_constant("ODIN_WINDOWS_SUBSYSTEM_STRING", windows_subsystem_names[bc->ODIN_WINDOWS_SUBSYSTEM]); + } { GlobalEnumValue values[TargetOs_COUNT] = { @@ -1097,7 +1153,7 @@ gb_internal void init_universal(void) { }; auto fields = add_global_enum_type(str_lit("Odin_OS_Type"), values, gb_count_of(values)); - add_global_enum_constant(fields, "ODIN_OS", bc->metrics.os); + add_global_enum_constant(fields, "ODIN_OS", bc->metrics.os); add_global_string_constant("ODIN_OS_STRING", target_os_names[bc->metrics.os]); } @@ -1147,8 +1203,10 @@ gb_internal void init_universal(void) { { GlobalEnumValue values[Subtarget_COUNT] = { - {"Default", Subtarget_Default}, - {"iOS", Subtarget_iOS}, + {"Default", Subtarget_Default}, + {"iPhone", Subtarget_iPhone}, + {"iPhoneSimulator", Subtarget_iPhoneSimulator}, + {"Android", Subtarget_Android}, }; auto fields = add_global_enum_type(str_lit("Odin_Platform_Subtarget_Type"), values, gb_count_of(values)); @@ -1337,23 +1395,29 @@ gb_internal void init_universal(void) { } - t_u8_ptr = alloc_type_pointer(t_u8); - t_u8_multi_ptr = alloc_type_multi_pointer(t_u8); - t_int_ptr = alloc_type_pointer(t_int); - t_i64_ptr = alloc_type_pointer(t_i64); - t_f64_ptr = alloc_type_pointer(t_f64); - t_u8_slice = alloc_type_slice(t_u8); - t_string_slice = alloc_type_slice(t_string); + t_u8_ptr = alloc_type_pointer(t_u8); + t_u8_multi_ptr = alloc_type_multi_pointer(t_u8); + t_u16_ptr = alloc_type_pointer(t_u16); + t_u16_multi_ptr = alloc_type_multi_pointer(t_u16); + t_int_ptr = alloc_type_pointer(t_int); + t_i64_ptr = alloc_type_pointer(t_i64); + t_f64_ptr = alloc_type_pointer(t_f64); + t_u8_slice = alloc_type_slice(t_u8); + t_string_slice = alloc_type_slice(t_string); // intrinsics types for objective-c stuff { t_objc_object = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_object"), alloc_type_struct_complete()); t_objc_selector = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_selector"), alloc_type_struct_complete()); t_objc_class = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_class"), alloc_type_struct_complete()); + t_objc_ivar = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_ivar"), alloc_type_struct_complete()); t_objc_id = alloc_type_pointer(t_objc_object); t_objc_SEL = alloc_type_pointer(t_objc_selector); t_objc_Class = alloc_type_pointer(t_objc_class); + t_objc_Ivar = alloc_type_pointer(t_objc_ivar); + + t_objc_instancetype = add_global_type_name(intrinsics_pkg->scope, str_lit("objc_instancetype"), t_objc_id); } } @@ -1369,13 +1433,10 @@ gb_internal void init_checker_info(CheckerInfo *i) { array_init(&i->entities, a); map_init(&i->global_untyped); string_map_init(&i->foreigns); - // map_init(&i->gen_procs); - map_init(&i->gen_types); type_set_init(&i->min_dep_type_info_set); map_init(&i->min_dep_type_info_index_map); - // map_init(&i->type_info_map); string_map_init(&i->files); string_map_init(&i->packages); array_init(&i->variable_init_order, a); @@ -1386,8 +1447,13 @@ gb_internal void init_checker_info(CheckerInfo *i) { array_init(&i->defineables, a); map_init(&i->objc_msgSend_types); + mpsc_init(&i->objc_class_implementations, a); + string_set_init(&i->obcj_class_name_set, 0); + map_init(&i->objc_method_implementations); + string_map_init(&i->load_file_cache); - array_init(&i->all_procedures, heap_allocator()); + array_init(&i->all_procedures, a); + mpsc_init(&i->all_procedures_queue, a); mpsc_init(&i->entity_queue, a); // 1<<20); mpsc_init(&i->definition_queue, a); //); // 1<<20); @@ -1397,6 +1463,9 @@ gb_internal void init_checker_info(CheckerInfo *i) { mpsc_init(&i->foreign_decls_to_check, a); // 1<<10); mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used + mpsc_init(&i->raddbg_type_views_queue, a); + array_init(&i->raddbg_type_views, a); + string_map_init(&i->load_directory_cache); map_init(&i->load_directory_map); } @@ -1406,8 +1475,6 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { array_free(&i->entities); map_destroy(&i->global_untyped); string_map_destroy(&i->foreigns); - // map_destroy(&i->gen_procs); - map_destroy(&i->gen_types); type_set_destroy(&i->min_dep_type_info_set); map_destroy(&i->min_dep_type_info_index_map); @@ -1418,6 +1485,10 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { array_free(&i->required_foreign_imports_through_force); array_free(&i->defineables); + array_free(&i->all_procedures); + + mpsc_destroy(&i->all_procedures_queue); + mpsc_destroy(&i->entity_queue); mpsc_destroy(&i->definition_queue); mpsc_destroy(&i->required_global_variable_queue); @@ -1425,7 +1496,14 @@ gb_internal void destroy_checker_info(CheckerInfo *i) { mpsc_destroy(&i->foreign_imports_to_check_fullpaths); mpsc_destroy(&i->foreign_decls_to_check); + mpsc_destroy(&i->raddbg_type_views_queue); + array_free(&i->raddbg_type_views); + map_destroy(&i->objc_msgSend_types); + string_set_destroy(&i->obcj_class_name_set); + mpsc_destroy(&i->objc_class_implementations); + map_destroy(&i->objc_method_implementations); + string_map_destroy(&i->load_file_cache); string_map_destroy(&i->load_directory_cache); map_destroy(&i->load_directory_map); @@ -1438,12 +1516,12 @@ gb_internal CheckerContext make_checker_context(Checker *c) { ctx.scope = builtin_pkg->scope; ctx.pkg = builtin_pkg; - ctx.type_path = new_checker_type_path(); + ctx.type_path = new_checker_type_path(heap_allocator()); ctx.type_level = 0; return ctx; } gb_internal void destroy_checker_context(CheckerContext *ctx) { - destroy_checker_type_path(ctx->type_path); + destroy_checker_type_path(ctx->type_path, heap_allocator()); } gb_internal bool add_curr_ast_file(CheckerContext *ctx, AstFile *file) { @@ -1496,6 +1574,8 @@ gb_internal void init_checker(Checker *c) { TIME_SECTION("init proc queues"); mpsc_init(&c->procs_with_deferred_to_check, a); //, 1<<10); + mpsc_init(&c->procs_with_objc_context_provider_to_check, a); + // NOTE(bill): 1 Mi elements should be enough on average array_init(&c->procs_to_check, heap_allocator(), 0, 1<<20); @@ -1646,7 +1726,7 @@ gb_internal void check_remove_expr_info(CheckerContext *c, Ast *e) { } gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool error_on_failure) { - mutex_lock(&info->minimum_dependency_type_info_mutex); + rw_mutex_shared_lock(&info->minimum_dependency_type_info_mutex); isize entry_index = -1; u64 hash = pair.hash; @@ -1654,7 +1734,7 @@ gb_internal isize type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err if (found_entry_index) { entry_index = *found_entry_index; } - mutex_unlock(&info->minimum_dependency_type_info_mutex); + rw_mutex_shared_unlock(&info->minimum_dependency_type_info_mutex); if (error_on_failure && entry_index < 0) { compiler_error("Type_Info for '%s' could not be found", type_to_string(pair.type)); @@ -1692,7 +1772,7 @@ gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, check_set_expr_info(c, expr, mode, type, value); } -gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) { +gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex) { if (expr == nullptr) { return; } @@ -1710,7 +1790,7 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo mutex = &ctx->pkg->type_and_value_mutex; } - mutex_lock(mutex); + if (use_mutex) mutex_lock(mutex); Ast *prev_expr = nullptr; while (prev_expr != expr) { prev_expr = expr; @@ -1731,8 +1811,11 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo } expr = unparen_expr(expr); + if (expr == nullptr) { + break; + }; } - mutex_unlock(mutex); + if (use_mutex) mutex_unlock(mutex); } gb_internal void add_entity_definition(CheckerInfo *i, Ast *identifier, Entity *entity) { @@ -1974,8 +2057,8 @@ gb_internal void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, En add_entity_definition(info, identifier, e); GB_ASSERT(e->decl_info == nullptr); e->decl_info = d; - d->entity = e; e->pkg = c->pkg; + d->entity.store(e); isize queue_count = -1; bool is_lazy = false; @@ -2021,7 +2104,7 @@ gb_internal void add_type_info_type(CheckerContext *c, Type *t) { } gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { - if (t == nullptr) { + if (t == nullptr || c == nullptr) { return; } @@ -2276,11 +2359,9 @@ gb_internal void check_procedure_later(Checker *c, ProcInfo *info) { } if (DEBUG_CHECK_ALL_PROCEDURES) { - MUTEX_GUARD_BLOCK(&c->info.all_procedures_mutex) { - GB_ASSERT(info != nullptr); - GB_ASSERT(info->decl != nullptr); - array_add(&c->info.all_procedures, info); - } + GB_ASSERT(info != nullptr); + GB_ASSERT(info->decl != nullptr); + mpsc_enqueue(&c->info.all_procedures_queue, info); } } @@ -2308,7 +2389,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { return; } - if (type_set_update(&c->info.min_dep_type_info_set, t)) { + if (type_set_update_with_mutex(&c->info.min_dep_type_info_set, t, &c->info.min_dep_type_info_set_mutex)) { return; } @@ -2483,15 +2564,15 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { } } +gb_internal void add_dependency_to_set_threaded(Checker *c, Entity *entity); + +gb_global std::atomic global_checker_ptr; gb_internal void add_dependency_to_set(Checker *c, Entity *entity) { if (entity == nullptr) { return; } - CheckerInfo *info = &c->info; - auto *set = &info->minimum_dependency_set; - if (entity->type != nullptr && is_type_polymorphic(entity->type)) { DeclInfo *decl = decl_info_of_entity(entity); @@ -2500,7 +2581,7 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) { } } - if (ptr_set_update(set, entity)) { + if (entity->min_dep_count.fetch_add(1, std::memory_order_relaxed) > 0) { return; } @@ -2511,28 +2592,107 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) { for (TypeInfoPair const tt : decl->type_info_deps) { add_min_dep_type_info(c, tt.type); } - - for (Entity *e : decl->deps) { - add_dependency_to_set(c, e); - if (e->kind == Entity_Procedure && e->Procedure.is_foreign) { - Entity *fl = e->Procedure.foreign_library; - if (fl != nullptr) { - GB_ASSERT_MSG(fl->kind == Entity_LibraryName && - (fl->flags&EntityFlag_Used), - "%.*s", LIT(entity->token.string)); - add_dependency_to_set(c, fl); + FOR_PTR_SET(e, decl->deps) { + switch (e->kind) { + case Entity_Procedure: + if (e->Procedure.is_foreign) { + Entity *fl = e->Procedure.foreign_library; + if (fl != nullptr) { + GB_ASSERT_MSG(fl->kind == Entity_LibraryName && + (fl->flags&EntityFlag_Used), + "%.*s", LIT(entity->token.string)); + add_dependency_to_set(c, fl); + } } - } else if (e->kind == Entity_Variable && e->Variable.is_foreign) { - Entity *fl = e->Variable.foreign_library; - if (fl != nullptr) { - GB_ASSERT_MSG(fl->kind == Entity_LibraryName && - (fl->flags&EntityFlag_Used), - "%.*s", LIT(entity->token.string)); - add_dependency_to_set(c, fl); + break; + case Entity_Variable: + if (e->Variable.is_foreign) { + Entity *fl = e->Variable.foreign_library; + if (fl != nullptr) { + GB_ASSERT_MSG(fl->kind == Entity_LibraryName && + (fl->flags&EntityFlag_Used), + "%.*s", LIT(entity->token.string)); + add_dependency_to_set(c, fl); + } } + break; } } + + FOR_PTR_SET(e, decl->deps) { + add_dependency_to_set(c, e); + } + } +gb_internal WORKER_TASK_PROC(add_dependency_to_set_worker) { + Checker *c = global_checker_ptr.load(std::memory_order_relaxed); + Entity *entity = cast(Entity *)data; + if (entity == nullptr) { + return 0; + } + + if (entity->type != nullptr && + is_type_polymorphic(entity->type)) { + DeclInfo *decl = decl_info_of_entity(entity); + if (decl != nullptr && decl->gen_proc_type == nullptr) { + return 0; + } + } + + if (entity->min_dep_count.fetch_add(1, std::memory_order_relaxed) > 0) { + return 0; + } + + DeclInfo *decl = decl_info_of_entity(entity); + if (decl == nullptr) { + return 0; + } + for (TypeInfoPair const tt : decl->type_info_deps) { + add_min_dep_type_info(c, tt.type); + } + + FOR_PTR_SET(e, decl->deps) { + switch (e->kind) { + case Entity_Procedure: + if (e->Procedure.is_foreign) { + Entity *fl = e->Procedure.foreign_library; + if (fl != nullptr) { + GB_ASSERT_MSG(fl->kind == Entity_LibraryName && + (fl->flags&EntityFlag_Used), + "%.*s", LIT(entity->token.string)); + add_dependency_to_set_threaded(c, fl); + } + } + break; + case Entity_Variable: + if (e->Variable.is_foreign) { + Entity *fl = e->Variable.foreign_library; + if (fl != nullptr) { + GB_ASSERT_MSG(fl->kind == Entity_LibraryName && + (fl->flags&EntityFlag_Used), + "%.*s", LIT(entity->token.string)); + add_dependency_to_set_threaded(c, fl); + } + } + break; + } + } + + FOR_PTR_SET(e, decl->deps) { + add_dependency_to_set_threaded(c, e); + } + + return 0; +} + + +gb_internal void add_dependency_to_set_threaded(Checker *c, Entity *entity) { + if (entity == nullptr) { + return; + } + thread_pool_add_task(add_dependency_to_set_worker, entity); +} + gb_internal void force_add_dependency_entity(Checker *c, Scope *scope, String const &name) { Entity *e = scope_lookup(scope, name); @@ -2583,27 +2743,35 @@ gb_internal void collect_testing_procedures_of_package(Checker *c, AstPackage *p } gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *start) { + // auto const &add_to_set = add_dependency_to_set; + auto const &add_to_set = add_dependency_to_set_threaded; + + Scope *builtin_scope = builtin_pkg->scope; for_array(i, c->info.definitions) { Entity *e = c->info.definitions[i]; - if (e->scope == builtin_pkg->scope) { + if (e->scope == builtin_scope) { if (e->type == nullptr) { - add_dependency_to_set(c, e); + add_to_set(c, e); + } + } else if (e->kind == Entity_Procedure) { + if (e->Procedure.is_export) { + add_to_set(c, e); + } + } else if (e->kind == Entity_Variable) { + if (e->Variable.is_export) { + add_to_set(c, e); } - } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { - add_dependency_to_set(c, e); - } else if (e->kind == Entity_Variable && e->Variable.is_export) { - add_dependency_to_set(c, e); } } for (Entity *e; mpsc_dequeue(&c->info.required_foreign_imports_through_force_queue, &e); /**/) { array_add(&c->info.required_foreign_imports_through_force, e); - add_dependency_to_set(c, e); + add_to_set(c, e); } for (Entity *e; mpsc_dequeue(&c->info.required_global_variable_queue, &e); /**/) { e->flags |= EntityFlag_Used; - add_dependency_to_set(c, e); + add_to_set(c, e); } for_array(i, c->info.entities) { @@ -2611,16 +2779,16 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st switch (e->kind) { case Entity_Variable: if (e->Variable.is_export) { - add_dependency_to_set(c, e); + add_to_set(c, e); } else if (e->flags & EntityFlag_Require) { - add_dependency_to_set(c, e); + add_to_set(c, e); } break; case Entity_Procedure: if (e->Procedure.is_export) { - add_dependency_to_set(c, e); + add_to_set(c, e); } else if (e->flags & EntityFlag_Require) { - add_dependency_to_set(c, e); + add_to_set(c, e); } if (e->flags & EntityFlag_Init) { Type *t = base_type(e->type); @@ -2635,6 +2803,15 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st is_init = false; } + u64 feature_flags = check_feature_flags(e); + if ((feature_flags & OptInFeatureFlag_GlobalContext) == 0) { + if (t->Proc.calling_convention != ProcCC_Contextless) { + ERROR_BLOCK(); + error(e->token, "@(init) procedures must be declared as \"contextless\""); + error_line("\tSuggestion: this can be bypassed, for the time being, with '#+feature global-context'"); + } + } + if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { error(e->token, "@(init) procedures must be declared at the file scope"); is_init = false; @@ -2645,8 +2822,13 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st is_init = false; } + if (is_blank_ident(e->token)) { + error(e->token, "An @(init) procedure must not use a blank identifier as its name"); + } + + if (is_init) { - add_dependency_to_set(c, e); + add_to_set(c, e); array_add(&c->info.init_procedures, e); } } else if (e->flags & EntityFlag_Fini) { @@ -2662,13 +2844,26 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st is_fini = false; } + u64 feature_flags = check_feature_flags(e); + if ((feature_flags & OptInFeatureFlag_GlobalContext) == 0) { + if (t->Proc.calling_convention != ProcCC_Contextless) { + ERROR_BLOCK(); + error(e->token, "@(fini) procedures must be declared as \"contextless\""); + error_line("\tSuggestion: this can be bypassed, for the time being, with '#+feature global-context'"); + } + } + if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { error(e->token, "@(fini) procedures must be declared at the file scope"); is_fini = false; } + if (is_blank_ident(e->token)) { + error(e->token, "An @(fini) procedure must not use a blank identifier as its name"); + } + if (is_fini) { - add_dependency_to_set(c, e); + add_to_set(c, e); array_add(&c->info.fini_procedures, e); } } @@ -2685,7 +2880,7 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st Entity *e = entry.value; if (e != nullptr) { e->flags |= EntityFlag_Used; - add_dependency_to_set(c, e); + add_to_set(c, e); } } @@ -2700,16 +2895,11 @@ gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *st } } else if (start != nullptr) { start->flags |= EntityFlag_Used; - add_dependency_to_set(c, start); + add_to_set(c, start); } } gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { - isize entity_count = c->info.entities.count; - isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor - - ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap); - #define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \ if (condition) { \ String entities[] = {__VA_ARGS__}; \ @@ -2808,12 +2998,13 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { generate_minimum_dependency_set_internal(c, start); + thread_pool_wait(); + #undef FORCE_ADD_RUNTIME_ENTITIES } -gb_internal bool is_entity_a_dependency(Entity *e) { - if (e == nullptr) return false; +gb_internal gb_inline bool is_entity_a_dependency(Entity *e) { switch (e->kind) { case Entity_Procedure: return true; @@ -2826,83 +3017,112 @@ gb_internal bool is_entity_a_dependency(Entity *e) { return false; } -gb_internal Array generate_entity_dependency_graph(CheckerInfo *info, gbAllocator allocator) { - PtrMap M = {}; - map_init(&M, info->entities.count); - defer (map_destroy(&M)); +gb_internal Array generate_entity_dependency_graph(CheckerInfo *info, Arena *arena) { + PtrMap M_procs = {}; + PtrMap M_vars = {}; + PtrMap M_other = {}; + + map_init(&M_procs, info->entities.count); + defer (map_destroy(&M_procs)); + + map_init(&M_vars, info->entities.count); + defer (map_destroy(&M_vars)); + + map_init(&M_other, info->entities.count); + defer (map_destroy(&M_other)); + for_array(i, info->entities) { Entity *e = info->entities[i]; - if (is_entity_a_dependency(e)) { - EntityGraphNode *n = gb_alloc_item(allocator, EntityGraphNode); - n->entity = e; - map_set(&M, e, n); + if (e == nullptr || !is_entity_a_dependency(e)) { + continue; + } + EntityGraphNode *n = arena_alloc_item(arena); + n->entity = e; + switch (e->kind) { + case Entity_Procedure: map_set(&M_procs, e, n); break; + case Entity_Variable: map_set(&M_vars, e, n); break; + default: map_set(&M_other, e, n); break; } } TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 1"); // Calculate edges for graph M - for (auto const &entry : M) { + for (auto const &entry : M_procs) { EntityGraphNode *n = entry.value; Entity *e = n->entity; DeclInfo *decl = decl_info_of_entity(e); GB_ASSERT(decl != nullptr); - for (Entity *dep : decl->deps) { + FOR_PTR_SET(dep, decl->deps) { + GB_ASSERT(dep != nullptr); if (dep->flags & EntityFlag_Field) { continue; } - GB_ASSERT(dep != nullptr); - if (is_entity_a_dependency(dep)) { - EntityGraphNode *m = map_must_get(&M, dep); - entity_graph_node_set_add(&n->succ, m); - entity_graph_node_set_add(&m->pred, n); + if (!is_entity_a_dependency(dep)) { + continue; } + EntityGraphNode *m = nullptr; + + switch (dep->kind) { + case Entity_Procedure: m = map_must_get(&M_procs, dep); break; + case Entity_Variable: m = map_must_get(&M_vars, dep); break; + default: m = map_must_get(&M_other, dep); break; + } + entity_graph_node_set_add(&n->succ, m); + entity_graph_node_set_add(&m->pred, n); } } - TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2"); - auto G = array_make(allocator, 0, M.count); + TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2a (init)"); - for (auto const &m_entry : M) { - auto *e = m_entry.key; + auto G = array_make(arena_allocator(arena), 0, M_procs.count + M_vars.count + M_other.count); + + TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2b (procs)"); + + for (auto const &m_entry : M_procs) { EntityGraphNode *n = m_entry.value; - if (e->kind == Entity_Procedure) { - // Connect each pred 'p' of 'n' with each succ 's' and from - // the procedure node - for (EntityGraphNode *p : n->pred) { - // Ignore self-cycles - if (p != n) { - // Each succ 's' of 'n' becomes a succ of 'p', and - // each pred 'p' of 'n' becomes a pred of 's' - for (EntityGraphNode *s : n->succ) { - // Ignore self-cycles - if (s != n) { - if (p->entity->kind == Entity_Procedure && - s->entity->kind == Entity_Procedure) { - // NOTE(bill, 2020-11-15): Only care about variable initialization ordering - // TODO(bill): This is probably wrong!!!! - continue; - } - // IMPORTANT NOTE/TODO(bill, 2020-11-15): These three calls take the majority of the - // the time to process - entity_graph_node_set_add(&p->succ, s); - entity_graph_node_set_add(&s->pred, p); - // Remove edge to 'n' - entity_graph_node_set_remove(&s->pred, n); - } - } - - // Remove edge to 'n' - entity_graph_node_set_remove(&p->succ, n); - } + // Connect each pred 'p' of 'n' with each succ 's' and from + // the procedure node + FOR_PTR_SET(p, n->pred) { + // Ignore self-cycles + if (p == n) { + continue; } - } else if (e->kind == Entity_Variable) { - array_add(&G, n); + // Each succ 's' of 'n' becomes a succ of 'p', and + // each pred 'p' of 'n' becomes a pred of 's' + FOR_PTR_SET(s, n->succ) { + // Ignore self-cycles + if (s == n) { + continue; + } + if (p->entity->kind == Entity_Procedure && + s->entity->kind == Entity_Procedure) { + // NOTE(bill, 2020-11-15): Only care about variable initialization ordering + // TODO(bill): This is probably wrong!!!! + continue; + } + // IMPORTANT NOTE/TODO(bill, 2020-11-15): These three calls take the majority of the + // the time to process + entity_graph_node_set_add(&p->succ, s); + entity_graph_node_set_add(&s->pred, p); + // Remove edge to 'n' + entity_graph_node_set_remove(&s->pred, n); + } + + // Remove edge to 'n' + entity_graph_node_set_remove(&p->succ, n); } } + TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2c (vars)"); + + for (auto const &m_entry : M_vars) { + EntityGraphNode *n = m_entry.value; + array_add(&G, n); + } + TIME_SECTION("generate_entity_dependency_graph: Dependency Count Checker"); for_array(i, G) { EntityGraphNode *n = G[i]; @@ -2986,19 +3206,17 @@ gb_internal Type *find_type_in_pkg(CheckerInfo *info, String const &pkg, String return e->type; } -gb_internal CheckerTypePath *new_checker_type_path() { - gbAllocator a = heap_allocator(); - auto *tp = gb_alloc_item(a, CheckerTypePath); - array_init(tp, a, 0, 16); +gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator) { + auto *tp = gb_alloc_item(allocator, CheckerTypePath); + array_init(tp, allocator, 0, 16); return tp; } -gb_internal void destroy_checker_type_path(CheckerTypePath *tp) { +gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator) { array_free(tp); - gb_free(heap_allocator(), tp); + gb_free(allocator, tp); } - gb_internal void check_type_path_push(CheckerContext *c, Entity *e) { GB_ASSERT(c->type_path != nullptr); GB_ASSERT(e != nullptr); @@ -3057,6 +3275,9 @@ gb_internal void init_core_type_info(Checker *c) { GB_ASSERT(tis->fields.count == 5); + Entity *type_info_string_encoding_kind = find_core_entity(c, str_lit("Type_Info_String_Encoding_Kind")); + t_type_info_string_encoding_kind = type_info_string_encoding_kind->type; + Entity *type_info_variant = tis->fields[4]; Type *tiv_type = type_info_variant->type; GB_ASSERT(is_type_union(tiv_type)); @@ -3167,12 +3388,20 @@ gb_internal void init_core_map_type(Checker *c) { t_raw_map_ptr = alloc_type_pointer(t_raw_map); } +gb_internal void init_core_objc_c(Checker *c) { + if (build_context.metrics.os == TargetOs_darwin) { + t_objc_super = find_core_type(c, str_lit("objc_super")); + t_objc_super_ptr = alloc_type_pointer(t_objc_super); + } +} + gb_internal void init_preload(Checker *c) { init_core_type_info(c); init_mem_allocator(c); init_core_context(c); init_core_source_code_location(c); init_core_map_type(c); + init_core_objc_c(c); } gb_internal ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) { @@ -3653,6 +3882,33 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } } return true; + } else if (name == "objc_implement") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_Bool) { + ac->objc_is_implementation = ev.value_bool; + + if (!ac->objc_is_implementation) { + ac->objc_is_disabled_implement = true; + } + } else if (ev.kind == ExactValue_Invalid) { + ac->objc_is_implementation = true; + } else { + error(elem, "Expected a boolean value, or no value, for '%.*s'", LIT(name)); + } + + return true; + } else if (name == "objc_selector") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_String) { + if (string_is_valid_identifier(ev.value_string)) { + ac->objc_selector = ev.value_string; + } else { + error(elem, "Invalid identifier for '%.*s', got '%.*s'", LIT(name), LIT(ev.value_string)); + } + } else { + error(elem, "Expected a string value for '%.*s'", LIT(name)); + } + return true; } else if (name == "require_target_feature") { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind == ExactValue_String) { @@ -3702,6 +3958,18 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } ac->instrumentation_exit = true; return true; + } else if (name == "no_sanitize_address") { + if (value != nullptr) { + error(value, "'%.*s' expects no parameter", LIT(name)); + } + ac->no_sanitize_address = true; + return true; + } else if (name == "no_sanitize_memory") { + if (value != nullptr) { + error(value, "'%.*s' expects no parameter", LIT(name)); + } + ac->no_sanitize_memory = true; + return true; } return false; } @@ -3892,6 +4160,66 @@ gb_internal DECL_ATTRIBUTE_PROC(type_decl_attribute) { ac->objc_class = ev.value_string; } return true; + } else if (name == "objc_implement") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_Bool) { + ac->objc_is_implementation = ev.value_bool; + } else if (ev.kind == ExactValue_Invalid) { + ac->objc_is_implementation = true; + } else { + error(elem, "Expected a boolean value, or no value, for '%.*s'", LIT(name)); + } + return true; + } else if (name == "objc_superclass") { + Type *objc_superclass = check_type(c, value); + + if (objc_superclass != nullptr) { + ac->objc_superclass = objc_superclass; + } else { + error(value, "'%.*s' expected a named type", LIT(name)); + } + return true; + } else if (name == "objc_ivar") { + Type *objc_ivar = check_type(c, value); + + if (objc_ivar != nullptr && objc_ivar->kind == Type_Named) { + ac->objc_ivar = objc_ivar; + } else { + error(value, "'%.*s' expected a named type", LIT(name)); + } + return true; + } else if (name == "objc_context_provider") { + Operand o = {}; + check_expr(c, &o, value); + Entity *e = entity_of_node(o.expr); + + if (e != nullptr) { + if (ac->objc_context_provider != nullptr) { + error(elem, "Previous usage of a 'objc_context_provider' attribute"); + } + if (e->kind != Entity_Procedure) { + error(elem, "'objc_context_provider' must refer to a procedure"); + } else { + ac->objc_context_provider = e; + } + + return true; + } + } else if (name == "raddbg_type_view") { + ExactValue ev = check_decl_attribute_value(c, value); + if (ev.kind == ExactValue_Invalid) { + ac->raddbg_type_view = true; + } else if (ev.kind == ExactValue_String) { + ac->raddbg_type_view = true; + ac->raddbg_type_view_string = ev.value_string; + + if (ev.value_string.len == 0) { + error(elem, "Expected a non-empty string for '%.*s'", LIT(name)); + } + } else { + error(elem, "Expected a string or no value for '%.*s'", LIT(name)); + } + return true; } return false; } @@ -4651,7 +4979,7 @@ gb_internal void check_single_global_entity(Checker *c, Entity *e, DeclInfo *d) } gb_internal void check_all_global_entities(Checker *c) { - in_single_threaded_checker_stage = true; + in_single_threaded_checker_stage.store(true, std::memory_order_relaxed); // NOTE(bill): This must be single threaded // Don't bother trying @@ -4673,7 +5001,7 @@ gb_internal void check_all_global_entities(Checker *c) { } } - in_single_threaded_checker_stage = false; + in_single_threaded_checker_stage.store(false, std::memory_order_relaxed); } @@ -4811,14 +5139,14 @@ gb_internal void add_import_dependency_node(Checker *c, Ast *decl, PtrMap generate_import_dependency_graph(Checker *c) { +gb_internal Array generate_import_dependency_graph(Checker *c, gbAllocator allocator) { PtrMap M = {}; map_init(&M, 2*c->parser->packages.count); defer (map_destroy(&M)); for_array(i, c->parser->packages) { AstPackage *pkg = c->parser->packages[i]; - ImportGraphNode *n = import_graph_node_create(heap_allocator(), pkg); + ImportGraphNode *n = import_graph_node_create(allocator, pkg); map_set(&M, pkg, n); } @@ -4835,7 +5163,7 @@ gb_internal Array generate_import_dependency_graph(Checker *c } Array G = {}; - array_init(&G, heap_allocator(), 0, M.count); + array_init(&G, allocator, 0, M.count); isize i = 0; for (auto const &entry : M) { @@ -4854,7 +5182,7 @@ struct ImportPathItem { Ast * decl; }; -gb_internal Array find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet *visited) { +gb_internal Array find_import_path(Checker *c, AstPackage *start, AstPackage *end, PtrSet *visited, gbAllocator allocator) { Array empty_path = {}; if (ptr_set_update(visited, start)) { @@ -4888,11 +5216,11 @@ gb_internal Array find_import_path(Checker *c, AstPackage *start ImportPathItem item = {pkg, decl}; if (pkg == end) { - auto path = array_make(heap_allocator()); + auto path = array_make(allocator); array_add(&path, item); return path; } - auto next_path = find_import_path(c, pkg, end, visited); + auto next_path = find_import_path(c, pkg, end, visited, allocator); if (next_path.count > 0) { array_add(&next_path, item); return next_path; @@ -4972,9 +5300,10 @@ gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) { GB_ASSERT(scope->flags&ScopeFlag_Pkg); - if (ptr_set_update(&parent_scope->imported, scope)) { - // error(token, "Multiple import of the same file within this scope"); - } + ptr_set_add(&parent_scope->imported, scope); + // if (ptr_set_update(&parent_scope->imported, scope)) { + // // error(token, "Multiple import of the same file within this scope"); + // } String import_name = path_to_entity_name(id->import_name.string, id->fullpath, false); if (is_blank_ident(import_name)) { @@ -5496,14 +5825,9 @@ gb_internal void check_export_entities(Checker *c) { } gb_internal void check_import_entities(Checker *c) { - Array dep_graph = generate_import_dependency_graph(c); - defer ({ - for_array(i, dep_graph) { - import_graph_node_destroy(dep_graph[i], heap_allocator()); - } - array_free(&dep_graph); - }); + TEMPORARY_ALLOCATOR_GUARD(); + Array dep_graph = generate_import_dependency_graph(c, temporary_allocator()); TIME_SECTION("check_import_entities - sort packages"); // NOTE(bill): Priority queue @@ -5513,8 +5837,7 @@ gb_internal void check_import_entities(Checker *c) { defer (ptr_set_destroy(&emitted)); Array package_order = {}; - array_init(&package_order, heap_allocator(), 0, c->parser->packages.count); - defer (array_free(&package_order)); + array_init(&package_order, temporary_allocator(), 0, c->parser->packages.count); while (pq.queue.count > 0) { ImportGraphNode *n = priority_queue_pop(&pq); @@ -5522,11 +5845,12 @@ gb_internal void check_import_entities(Checker *c) { AstPackage *pkg = n->pkg; if (n->dep_count > 0) { + TEMPORARY_ALLOCATOR_GUARD(); + PtrSet visited = {}; defer (ptr_set_destroy(&visited)); - auto path = find_import_path(c, pkg, pkg, &visited); - defer (array_free(&path)); + auto path = find_import_path(c, pkg, pkg, &visited, temporary_allocator()); if (path.count > 1) { ImportPathItem item = path[path.count-1]; @@ -5541,7 +5865,7 @@ gb_internal void check_import_entities(Checker *c) { } } - for (ImportGraphNode *p : n->pred) { + FOR_PTR_SET(p, n->pred) { p->dep_count = gb_max(p->dep_count-1, 0); priority_queue_fix(&pq, p->index); } @@ -5644,9 +5968,9 @@ gb_internal void check_import_entities(Checker *c) { } -gb_internal Array find_entity_path(Entity *start, Entity *end, PtrSet *visited = nullptr); +gb_internal Array find_entity_path(Entity *start, Entity *end, gbAllocator allocator, PtrSet *visited = nullptr); -gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet *visited, Array *path_) { +gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, gbAllocator allocator, PtrSet *visited, Array *path_) { GB_ASSERT(path_ != nullptr); if (tuple == nullptr) { return false; @@ -5658,14 +5982,15 @@ gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSetdeps) { + + FOR_PTR_SET(dep, var_decl->deps) { if (dep == end) { - auto path = array_make(heap_allocator()); + auto path = array_make(allocator); array_add(&path, dep); *path_ = path; return true; } - auto next_path = find_entity_path(dep, end, visited); + auto next_path = find_entity_path(dep, end, allocator, visited); if (next_path.count > 0) { array_add(&next_path, dep); *path_ = next_path; @@ -5677,7 +6002,7 @@ gb_internal bool find_entity_path_tuple(Type *tuple, Entity *end, PtrSet find_entity_path(Entity *start, Entity *end, PtrSet *visited) { +gb_internal Array find_entity_path(Entity *start, Entity *end, gbAllocator allocator, PtrSet *visited) { PtrSet visited_ = {}; bool made_visited = false; if (visited == nullptr) { @@ -5701,20 +6026,20 @@ gb_internal Array find_entity_path(Entity *start, Entity *end, PtrSet< GB_ASSERT(t->kind == Type_Proc); Array path = {}; - if (find_entity_path_tuple(t->Proc.params, end, visited, &path)) { + if (find_entity_path_tuple(t->Proc.params, end, allocator, visited, &path)) { return path; } - if (find_entity_path_tuple(t->Proc.results, end, visited, &path)) { + if (find_entity_path_tuple(t->Proc.results, end, allocator, visited, &path)) { return path; } } else { - for (Entity *dep : decl->deps) { + FOR_PTR_SET(dep, decl->deps) { if (dep == end) { - auto path = array_make(heap_allocator()); + auto path = array_make(allocator); array_add(&path, dep); return path; } - auto next_path = find_entity_path(dep, end, visited); + auto next_path = find_entity_path(dep, end, allocator, visited); if (next_path.count > 0) { array_add(&next_path, dep); return next_path; @@ -5730,13 +6055,10 @@ gb_internal void calculate_global_init_order(Checker *c) { CheckerInfo *info = &c->info; TIME_SECTION("calculate_global_init_order: generate entity dependency graph"); - Array dep_graph = generate_entity_dependency_graph(info, heap_allocator()); - defer ({ - for_array(i, dep_graph) { - entity_graph_node_destroy(dep_graph[i], heap_allocator()); - } - array_free(&dep_graph); - }); + Arena *temporary_arena = get_arena(ThreadArena_Temporary); + ArenaTempGuard temporary_arena_guard(temporary_arena); + + Array dep_graph = generate_entity_dependency_graph(info, temporary_arena); TIME_SECTION("calculate_global_init_order: priority queue create"); // NOTE(bill): Priority queue @@ -5751,8 +6073,8 @@ gb_internal void calculate_global_init_order(Checker *c) { Entity *e = n->entity; if (n->dep_count > 0) { - auto path = find_entity_path(e, e); - defer (array_free(&path)); + TEMPORARY_ALLOCATOR_GUARD(); + auto path = find_entity_path(e, e, temporary_allocator()); if (path.count > 0) { Entity *e = path[0]; @@ -5765,7 +6087,7 @@ gb_internal void calculate_global_init_order(Checker *c) { } } - for (EntityGraphNode *p : n->pred) { + FOR_PTR_SET(p, n->pred) { p->dep_count -= 1; p->dep_count = gb_max(p->dep_count, 0); priority_queue_fix(&pq, p->index); @@ -5869,7 +6191,7 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u switch (pi->decl->proc_checked_state.load()) { case ProcCheckedState_InProgress: if (e) { - GB_ASSERT(global_procedure_body_in_worker_queue.load()); + GB_ASSERT(global_procedure_body_in_worker_queue.load() != 0); } return false; case ProcCheckedState_Checked: @@ -5958,7 +6280,7 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u add_untyped_expressions(&c->info, ctx.untyped); rw_mutex_shared_lock(&ctx.decl->deps_mutex); - for (Entity *dep : ctx.decl->deps) { + FOR_PTR_SET(dep, ctx.decl->deps) { if (dep && dep->kind == Entity_Procedure && (dep->flags & EntityFlag_ProcBodyChecked) == 0) { check_procedure_later_from_entity(c, dep, NULL); @@ -5987,8 +6309,10 @@ gb_internal void check_unchecked_bodies(Checker *c) { // use the `procs_to_check` array global_procedure_body_in_worker_queue = false; - for (Entity *e : c->info.minimum_dependency_set) { - check_procedure_later_from_entity(c, e, "check_unchecked_bodies"); + for (Entity *e : c->info.entities) { + if (e->min_dep_count.load(std::memory_order_relaxed) > 0) { + check_procedure_later_from_entity(c, e, "check_unchecked_bodies"); + } } if (!global_procedure_body_in_worker_queue) { @@ -6011,8 +6335,9 @@ gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) { defer (map_destroy(&untyped)); - for_array(i, c->info.all_procedures) { - ProcInfo *pi = c->info.all_procedures[i]; + array_reserve(&c->info.all_procedures, c->info.all_procedures_queue.count.load()); + + for (ProcInfo *pi = nullptr; mpsc_dequeue(&c->info.all_procedures_queue, &pi); /**/) { GB_ASSERT(pi != nullptr); GB_ASSERT(pi->decl != nullptr); Entity *e = pi->decl->entity; @@ -6027,6 +6352,8 @@ gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) { consume_proc_info(c, pi, &untyped); } } + + array_add(&c->info.all_procedures, pi); } } @@ -6121,7 +6448,7 @@ gb_internal WORKER_TASK_PROC(check_proc_info_worker_proc) { gb_internal void check_init_worker_data(Checker *c) { u32 thread_count = cast(u32)global_thread_pool.threads.count; - check_procedure_bodies_worker_data = gb_alloc_array(permanent_allocator(), CheckProcedureBodyWorkerData, thread_count); + check_procedure_bodies_worker_data = permanent_alloc_array(thread_count); for (isize i = 0; i < thread_count; i++) { check_procedure_bodies_worker_data[i].c = c; @@ -6183,7 +6510,7 @@ gb_internal Type *tuple_to_pointers(Type *ot) { Type *t = alloc_type_tuple(); - t->Tuple.variables = slice_make(heap_allocator(), ot->Tuple.variables.count); + t->Tuple.variables = permanent_slice_make(ot->Tuple.variables.count); Scope *scope = nullptr; for_array(i, t->Tuple.variables) { @@ -6225,6 +6552,12 @@ gb_internal void check_deferred_procedures(Checker *c) { continue; } + if (dst->flags & EntityFlag_Disabled) { + // Prevent procedures that have been disabled from acting as deferrals. + src->Procedure.deferred_procedure = {}; + continue; + } + GB_ASSERT(is_type_proc(src->type)); GB_ASSERT(is_type_proc(dst->type)); Type *src_params = base_type(src->type)->Proc.params; @@ -6380,6 +6713,309 @@ gb_internal void check_deferred_procedures(Checker *c) { } +gb_internal void handle_raddbg_type_view(Checker *c, RaddbgTypeView const &type_view) { + auto const struct_tag_lookup = [](String tag, char const *key_c, String *value_) -> bool { + String t = tag; + String key = make_string_c(key_c); + while (t.len != 0) { + isize i = 0; + while (i < t.len && t[i] == ' ') { // Skip whitespace + i += 1; + } + t.text += i; + t.len -= i; + if (t.len == 0) { + break; + } + + i = 0; + + while (i < t.len) { + u8 c = t[i]; + if (c == ':' || c == '"') { + break; + } else if ((0 <= c && c < ' ') || (0x7f <= c && c <= 0x9f)) { + // break if control character is found + break; + } + i += 1; + } + + if (i == 0) { + break; + } + if (i+1 >= t.len) { + break; + } + if (t[i] != ':' || t[i+1] != '"') { + break; + } + String name = {t.text, i}; + t = {t.text+i+1, t.len-(i+1)}; + + i = 1; + while (i < t.len && t[i] != '"') { // find closing quote + if (t[i] == '\\') { + i += 1; // Skip escaped characters + } + i += 1; + } + if (i >= t.len) { + break; + } + + String value = {t.text, i+1}; + t = {t.text+i+1, t.len-(i+1)}; + + if (key == name) { + value = {value.text+1, i-1}; + value = string_trim_whitespace(value); + if (value_) *value_ = value; + return true; + } + } + return false; + }; + + auto const parse_int = [](String s, isize *offset_, u64 *result_) -> bool { + isize offset = *offset_; + isize new_offset = *offset_; + + u64 result = 0; + + while (new_offset < s.len) { + u8 c = s[new_offset]; + if (!('0' <= c && c <= '9')) { + break; + } + + new_offset += 1; + result *= 10; + result += u64(c)-'0'; + } + + *offset_ = new_offset; + *result_ = result; + return new_offset > offset; + }; + + Type *type = type_view.type; + if (type == nullptr || type == t_invalid) { + return; + } + String view = type_view.view; + if (view.len != 0) { + array_add(&c->info.raddbg_type_views, RaddbgTypeView{type, view}); + return; + } + + // NOTE(bill): Generate one automatically from the struct field tags if they exist + // If it cannot be generated, it'll be ignored/err + + Type *bt = base_type(type); + if (is_type_struct(type)) { + GB_ASSERT(bt->kind == Type_Struct); + if (bt->Struct.tags != nullptr) { + bool found_any = false; + + for (isize i = 0; i < bt->Struct.fields.count; i++) { + String tag = bt->Struct.tags[i]; + String value = {}; + if (struct_tag_lookup(tag, "raddbg", &value)) { + found_any = true; + } else if (struct_tag_lookup(tag, "fmt", &value)) { + found_any = true; + } + } + + if (!found_any) { + return; + } + + gbString s = gb_string_make(heap_allocator(), ""); + + s = gb_string_appendc(s, "rows($"); + + for (isize i = 0; i < bt->Struct.fields.count; i++) { + Entity *field = bt->Struct.fields[i]; + GB_ASSERT(field != nullptr); + String name = field->token.string; + String tag = bt->Struct.tags[i]; + String value = {}; + bool custom_rule = false; + + bool raddbg_seen = false; + if (struct_tag_lookup(tag, "raddbg", &value)) { + raddbg_seen = true; + if (value == "-") { + // Ignore this field entirely; + continue; + } + } + + s = gb_string_appendc(s, ", "); + + if (raddbg_seen) { + if (value == "") { + // ignore + } else { + s = gb_string_append_length(s, value.text, value.len); + custom_rule = true; + } + } else if (struct_tag_lookup(tag, "fmt", &value)) { + if (value == "" || value == "-") { + // ignore + } else { + auto p = string_partition(value, make_string_c(",")); + String head = p.head; + String tail = p.tail; + + isize i = 0; + + for (bool ok = true; ok && i < head.len; i += 1) { + switch (head[i]) { + case '+': + case '-': + case ' ': + case '#': + case '0': + break; + default: + i -= 1; + ok = false; + break; + } + } + + u64 prec = 0; + u64 width = 0; + bool width_ok = parse_int(head, &i, &width); + bool prec_ok = false; + if (i < head.len && head[i] == '.') { + i += 1; + prec_ok = parse_int(head, &i, &prec); + } + + + Rune verb = 0; + if (i >= head.len || head[i] == ' ') { + verb = 'v'; + } else { + utf8_decode(head.text+i, head.len-i, &verb); + } + + isize paren_count = 0; + + + if (width_ok) { + s = gb_string_appendc(s, "digits("); + custom_rule = true; + } + + switch (verb) { + case 'b': + s = gb_string_appendc(s, "bin("); + paren_count += 1; + break; + case 'd': + s = gb_string_appendc(s, "dec("); + paren_count += 1; + break; + case 'x': + case 'X': + s = gb_string_appendc(s, "hex("); + paren_count += 1; + break; + case 'o': + s = gb_string_appendc(s, "oct("); + paren_count += 1; + break; + } + + + if (tail.len != 0 && tail != "0") { + s = gb_string_appendc(s, "array("); + s = gb_string_append_length(s, name.text, name.len); + if (is_type_slice(field->type) || is_type_dynamic_array(field->type)) { + s = gb_string_appendc(s, ".data"); + } + s = gb_string_appendc(s, ", "); + s = gb_string_append_length(s, tail.text, tail.len); + s = gb_string_appendc(s, ")"); + custom_rule = true; + } else { + s = gb_string_append_length(s, name.text, name.len); + custom_rule = true; + } + + + for (isize j = 0; j < paren_count; j++) { + s = gb_string_appendc(s, ")"); + custom_rule = true; + } + if (width_ok) { + s = gb_string_append_fmt(s, ", %llu)", cast(unsigned long long)width); + } + } + } + + if (!custom_rule) { + s = gb_string_append_length(s, name.text, name.len); + } + } + + s = gb_string_appendc(s, ")"); + + view = make_string((u8 const *)s, gb_string_length(s)); + } + } + + if (view.len == 0) { + // Ignore the type, it didn't anything custom + return; + } + + array_add(&c->info.raddbg_type_views, RaddbgTypeView{type, view}); +} + +gb_internal void check_objc_context_provider_procedures(Checker *c) { + for (Entity *e = nullptr; mpsc_dequeue(&c->procs_with_objc_context_provider_to_check, &e); /**/) { + GB_ASSERT(e->kind == Entity_TypeName); + + Entity *proc_entity = e->TypeName.objc_context_provider; + GB_ASSERT(proc_entity->kind == Entity_Procedure); + + auto &proc = proc_entity->type->Proc; + + Type *return_type = proc.result_count != 1 ? t_untyped_nil : base_named_type(proc.results->Tuple.variables[0]->type); + if (return_type != t_context) { + error(proc_entity->token, "The @(objc_context_provider) procedure must only return a context."); + } + + const char *self_param_err = "The @(objc_context_provider) procedure must take as a parameter a single pointer to the @(objc_type) value."; + if (proc.param_count != 1) { + error(proc_entity->token, self_param_err); + } + + Type *self_param = base_type(proc.params->Tuple.variables[0]->type); + if (self_param->kind != Type_Pointer) { + error(proc_entity->token, self_param_err); + } + + Type *self_type = base_named_type(self_param->Pointer.elem); + if (!internal_check_is_assignable_to(self_type, e->type) && + !(e->TypeName.objc_ivar && internal_check_is_assignable_to(self_type, e->TypeName.objc_ivar))) { + error(proc_entity->token, self_param_err); + } + if (proc.calling_convention != ProcCC_CDecl && proc.calling_convention != ProcCC_Contextless) { + error(e->token, self_param_err); + } + if (proc.is_polymorphic) { + error(e->token, self_param_err); + } + } +} + gb_internal void check_unique_package_names(Checker *c) { ERROR_BLOCK(); @@ -6414,6 +7050,19 @@ gb_internal void check_unique_package_names(Checker *c) { "\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n" "\tA package name is required for link name prefixing to have a consistent ABI\n"); error_line("%s found at previous location\n", token_pos_to_string(ast_token(prev).pos)); + + // NOTE(Jeroen): Check if the conflicting imports are the same case-folded directory + // See https://github.com/odin-lang/Odin/issues/5080 + #if defined(GB_SYSTEM_WINDOWS) + String dir_a = pkg->files[0]->directory; + String dir_b = (*found)->files[0]->directory; + + if (str_eq_ignore_case(dir_a, dir_b)) { + error_line("\tRemember that Windows case-folds paths, and so %.*s and %.*s are the same directory.\n", LIT(dir_a), LIT(dir_b)); + // Could also perform a FS lookup to check which of the two is the actual directory and suggest it, but this should be enough. + } + #endif + end_error_block(); } } @@ -6440,6 +7089,7 @@ gb_internal void check_merge_queues_into_arrays(Checker *c) { } check_add_entities_from_queues(c); check_add_definitions_from_queues(c); + thread_pool_wait(); } gb_internal GB_COMPARE_PROC(init_procedures_cmp) { @@ -6494,17 +7144,23 @@ gb_internal void check_sort_init_and_fini_procedures(Checker *c) { } gb_internal void add_type_info_for_type_definitions(Checker *c) { - for_array(i, c->info.definitions) { - Entity *e = c->info.definitions[i]; - if (e->kind == Entity_TypeName && e->type != nullptr) { + for (Entity *e : c->info.definitions) { + if (e->kind == Entity_TypeName && e->type != nullptr && is_type_typed(e->type)) { + #if 0 i64 align = type_align_of(e->type); - if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) { + if (align > 0 && e->min_dep_count.load(std::memory_order_relaxed) > 0) { add_type_info_type(&c->builtin_ctx, e->type); } + #else + if (e->min_dep_count.load(std::memory_order_relaxed) > 0) { + add_type_info_type(&c->builtin_ctx, e->type); + } + #endif } } } +#if 0 gb_internal void check_walk_all_dependencies(DeclInfo *decl) { if (decl == nullptr) { return; @@ -6526,8 +7182,116 @@ gb_internal void check_update_dependency_tree_for_procedures(Checker *c) { check_walk_all_dependencies(decl); } } +#else +gb_internal void check_walk_all_dependencies(DeclInfo *decl); + +gb_internal WORKER_TASK_PROC(check_walk_all_dependencies_worker_proc) { + if (data == nullptr) { + return 0; + } + DeclInfo *decl = cast(DeclInfo *)data; + + for (DeclInfo *child = decl->next_child; child != nullptr; child = child->next_sibling) { + thread_pool_add_task(check_walk_all_dependencies_worker_proc, child); + check_walk_all_dependencies(child); + } + + add_deps_from_child_to_parent(decl); + return 0; +} + +gb_internal void check_walk_all_dependencies(DeclInfo *decl) { + if (decl != nullptr) { + thread_pool_add_task(check_walk_all_dependencies_worker_proc, decl); + } +} + +gb_internal void check_update_dependency_tree_for_procedures(Checker *c) { + mutex_lock(&c->nested_proc_lits_mutex); + for (DeclInfo *decl : c->nested_proc_lits) { + check_walk_all_dependencies(decl); + } + mutex_unlock(&c->nested_proc_lits_mutex); + for (Entity *e : c->info.entities) { + DeclInfo *decl = e->decl_info; + check_walk_all_dependencies(decl); + } + + thread_pool_wait(); +} +#endif + +gb_internal WORKER_TASK_PROC(check_scope_usage_file_worker) { + Checker *c = global_checker_ptr.load(std::memory_order_relaxed); + AstFile *f = cast(AstFile *)data; + u64 vet_flags = ast_file_vet_flags(f); + check_scope_usage(c, f->scope, vet_flags); + return 0; +} + +gb_internal WORKER_TASK_PROC(check_scope_usage_pkg_worker) { + Checker *c = global_checker_ptr.load(std::memory_order_relaxed); + AstPackage *pkg = cast(AstPackage *)data; + check_scope_usage_internal(c, pkg->scope, 0, true); + return 0; +} + + + +gb_internal void check_all_scope_usages(Checker *c) { + for (auto const &entry : c->info.files) { + AstFile *f = entry.value; + thread_pool_add_task(check_scope_usage_file_worker, f); + } + for (auto const &entry : c->info.packages) { + AstPackage *pkg = entry.value; + thread_pool_add_task(check_scope_usage_pkg_worker, pkg); + } + + thread_pool_wait(); +} + + +gb_internal void check_for_type_cycles(Checker *c) { + // NOTE(bill): Check for illegal cyclic type declarations + for_array(i, c->info.definitions) { + Entity *e = c->info.definitions[i]; + if (e->kind != Entity_TypeName) { + continue; + } + if (e->type != nullptr && is_type_typed(e->type)) { + if (e->TypeName.is_type_alias) { + // Ignore for the time being + } else { + (void)type_align_of(e->type); + } + } + } +} + +gb_internal void check_for_inline_cycles(Checker *c) { + for_array(i, c->info.definitions) { + Entity *e = c->info.definitions[i]; + if (e->kind != Entity_Procedure) { + continue; + } + DeclInfo *decl = e->decl_info; + ast_node(pl, ProcLit, decl->proc_lit); + if (pl->inlining == ProcInlining_inline) { + FOR_PTR_SET(dep, decl->deps) { + if (dep == e) { + error(e->token, "Cannot inline recursive procedure '%.*s'", LIT(e->token.string)); + break; + } + } + } + } +} + gb_internal void check_parsed_files(Checker *c) { + global_checker_ptr.store(c, std::memory_order_relaxed); + TIME_SECTION("map full filepaths to scope"); add_type_info_type(&c->builtin_ctx, t_invalid); @@ -6591,16 +7355,9 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("add entities from procedure bodies"); check_merge_queues_into_arrays(c); - TIME_SECTION("check scope usage"); - for (auto const &entry : c->info.files) { - AstFile *f = entry.value; - u64 vet_flags = ast_file_vet_flags(f); - check_scope_usage(c, f->scope, vet_flags); - } - for (auto const &entry : c->info.packages) { - AstPackage *pkg = entry.value; - check_scope_usage_internal(c, pkg->scope, 0, true); - } + TIME_SECTION("check all scope usages"); + check_all_scope_usages(c); + TIME_SECTION("add basic type information"); // Add "Basic" type information @@ -6613,29 +7370,18 @@ gb_internal void check_parsed_files(Checker *c) { } check_merge_queues_into_arrays(c); - TIME_SECTION("check for type cycles and inline cycles"); - // NOTE(bill): Check for illegal cyclic type declarations - for_array(i, c->info.definitions) { - Entity *e = c->info.definitions[i]; - if (e->kind == Entity_TypeName && e->type != nullptr) { - (void)type_align_of(e->type); - } else if (e->kind == Entity_Procedure) { - DeclInfo *decl = e->decl_info; - ast_node(pl, ProcLit, decl->proc_lit); - if (pl->inlining == ProcInlining_inline) { - for (Entity *dep : decl->deps) { - if (dep == e) { - error(e->token, "Cannot inline recursive procedure '%.*s'", LIT(e->token.string)); - break; - } - } - } - } - } + TIME_SECTION("check for type cycles"); + check_for_type_cycles(c); + + TIME_SECTION("check for inline cycles"); + check_for_inline_cycles(c); TIME_SECTION("check deferred procedures"); check_deferred_procedures(c); + TIME_SECTION("check objc context provider procedures"); + check_objc_context_provider_procedures(c); + TIME_SECTION("calculate global init order"); calculate_global_init_order(c); @@ -6653,11 +7399,9 @@ gb_internal void check_parsed_files(Checker *c) { check_unchecked_bodies(c); TIME_SECTION("check #soa types"); - check_merge_queues_into_arrays(c); - thread_pool_wait(); - TIME_SECTION("update minimum dependency set"); + TIME_SECTION("update minimum dependency set again"); generate_minimum_dependency_set_internal(c, c->info.entry_point); // NOTE(laytan): has to be ran after generate_minimum_dependency_set, @@ -6722,7 +7466,6 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("add untyped expression values"); - // Add untyped expression values for (UntypedExprInfo u = {}; mpsc_dequeue(&c->global_untyped_queue, &u); /**/) { GB_ASSERT(u.expr != nullptr && u.info != nullptr); if (is_type_typed(u.info->type)) { @@ -6733,9 +7476,10 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("initialize and check for collisions in type info array"); { + TEMPORARY_ALLOCATOR_GUARD(); + Array type_info_types; // sorted after filled - array_init(&type_info_types, heap_allocator()); - defer (array_free(&type_info_types)); + array_init(&type_info_types, temporary_allocator()); for (auto const &tt : c->info.min_dep_type_info_set) { array_add(&type_info_types, tt); @@ -6765,7 +7509,7 @@ gb_internal void check_parsed_files(Checker *c) { if (entry.key != tt.hash) { continue; } - auto const &other = type_info_types[entry.value]; + auto const &other = c->info.type_info_types_hash_map[entry.value]; if (are_types_identical_unique_tuples(tt.type, other.type)) { continue; } @@ -6798,6 +7542,11 @@ gb_internal void check_parsed_files(Checker *c) { } } + TIME_SECTION("collate type info stuff"); + for (RaddbgTypeView type_view; mpsc_dequeue(&c->info.raddbg_type_views_queue, &type_view); /**/) { + handle_raddbg_type_view(c, type_view); + } + TIME_SECTION("type check finish"); } diff --git a/src/checker.hpp b/src/checker.hpp index d3b2d7d89..bda7b2746 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -139,6 +139,8 @@ struct AttributeContext { bool entry_point_only : 1; bool instrumentation_enter : 1; bool instrumentation_exit : 1; + bool no_sanitize_address : 1; + bool no_sanitize_memory : 1; bool rodata : 1; bool ignore_duplicates : 1; u32 optimization_mode; // ProcedureOptimizationMode @@ -148,11 +150,20 @@ struct AttributeContext { String objc_class; String objc_name; - bool objc_is_class_method; + String objc_selector; Type * objc_type; + Type * objc_superclass; + Type * objc_ivar; + Entity *objc_context_provider; + bool objc_is_class_method; + bool objc_is_implementation; // This struct or proc provides a class/method implementation, not a binding to an existing type. + bool objc_is_disabled_implement; // This means the method explicitly set @objc_implement to false so it won't be inferred from the class' attribute. String require_target_feature; // required by the target micro-architecture String enable_target_feature; // will be enabled for the procedure only + + bool raddbg_type_view; + String raddbg_type_view_string; }; gb_internal gb_inline AttributeContext make_attribute_context(String link_prefix, String link_suffix) { @@ -198,7 +209,7 @@ struct DeclInfo { Scope * scope; - Entity *entity; + std::atomic entity; Ast * decl_node; Ast * type_expr; @@ -207,6 +218,8 @@ struct DeclInfo { Ast * proc_lit; // Ast_ProcLit Type * gen_proc_type; // Precalculated + Entity * para_poly_original; + bool is_using; bool where_clauses_evaluated; bool foreign_require_results; @@ -298,11 +311,12 @@ struct EntityGraphNode; typedef PtrSet EntityGraphNodeSet; struct EntityGraphNode { - Entity * entity; // Procedure, Variable, Constant + Entity *entity; // Procedure, Variable, Constant + EntityGraphNodeSet pred; EntityGraphNodeSet succ; - isize index; // Index in array/queue - isize dep_count; + isize index; // Index in array/queue + isize dep_count; }; @@ -365,6 +379,11 @@ struct ObjcMsgData { Type *proc_type; }; +struct ObjcMethodData { + AttributeContext ac; + Entity *proc_entity; +}; + enum LoadFileTier { LoadFileTier_Invalid, LoadFileTier_Exists, @@ -414,6 +433,11 @@ struct Defineable { String pos_str; }; +struct RaddbgTypeView { + Type * type; + String view; +}; + // CheckerInfo stores all the symbol information for a type-checked program struct CheckerInfo { Checker *checker; @@ -427,9 +451,11 @@ struct CheckerInfo { AstPackage * init_package; Scope * init_scope; Entity * entry_point; - PtrSet minimum_dependency_set; - BlockingMutex minimum_dependency_type_info_mutex; + + RwMutex minimum_dependency_type_info_mutex; PtrMap min_dep_type_info_index_map; + + RWSpinLock min_dep_type_info_set_mutex; TypeSet min_dep_type_info_set; Array type_info_types_hash_map; // 2 * type_info_types.count @@ -456,8 +482,6 @@ struct CheckerInfo { RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files - BlockingMutex gen_types_mutex; - PtrMap gen_types; // BlockingMutex type_info_mutex; // NOT recursive // Array type_info_types; @@ -474,15 +498,26 @@ struct CheckerInfo { MPSCQueue foreign_imports_to_check_fullpaths; MPSCQueue foreign_decls_to_check; + MPSCQueue raddbg_type_views_queue; + Array raddbg_type_views; + MPSCQueue intrinsics_entry_point_usage; - BlockingMutex objc_types_mutex; + BlockingMutex objc_objc_msgSend_mutex; PtrMap objc_msgSend_types; + BlockingMutex objc_class_name_mutex; + StringSet obcj_class_name_set; + MPSCQueue objc_class_implementations; + + BlockingMutex objc_method_mutex; + PtrMap> objc_method_implementations; + + BlockingMutex load_file_mutex; StringMap load_file_cache; - BlockingMutex all_procedures_mutex; + MPSCQueue all_procedures_queue; Array all_procedures; BlockingMutex instrumentation_mutex; @@ -531,6 +566,7 @@ struct CheckerContext { u32 stmt_flags; bool in_enum_type; + bool in_proc_group; bool collect_delayed_decls; bool allow_polymorphic_types; bool disallow_polymorphic_return_types; // NOTE(zen3ger): no poly type decl in return types @@ -555,6 +591,7 @@ struct Checker { CheckerContext builtin_ctx; MPSCQueue procs_with_deferred_to_check; + MPSCQueue procs_with_objc_context_provider_to_check; Array procs_to_check; BlockingMutex nested_proc_lits_mutex; @@ -588,12 +625,12 @@ gb_internal Entity *entity_of_node(Ast *expr); gb_internal Entity *scope_lookup_current(Scope *s, String const &name); -gb_internal Entity *scope_lookup (Scope *s, String const &name); -gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_); +gb_internal Entity *scope_lookup (Scope *s, String const &name, u32 hash=0); +gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_, u32 hash=0); gb_internal Entity *scope_insert (Scope *s, Entity *entity); -gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value); +gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex=true); gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr); gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue const &value); gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity); @@ -614,8 +651,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice const &n gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws); gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl); -gb_internal CheckerTypePath *new_checker_type_path(); -gb_internal void destroy_checker_type_path(CheckerTypePath *tp); +gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator); +gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator); gb_internal void check_type_path_push(CheckerContext *c, Entity *e); gb_internal Entity *check_type_path_pop (CheckerContext *c); @@ -629,4 +666,4 @@ gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type); -gb_internal void init_map_internal_types(Type *type); \ No newline at end of file +gb_internal void init_map_internal_types(Type *type); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 40dde8240..c2255a6ba 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -26,6 +26,7 @@ enum BuiltinProcId { BuiltinProc_conj, BuiltinProc_expand_values, + BuiltinProc_compress_values, BuiltinProc_min, BuiltinProc_max, @@ -60,6 +61,7 @@ enum BuiltinProcId { BuiltinProc_trap, BuiltinProc_debug_trap, BuiltinProc_read_cycle_counter, + BuiltinProc_read_cycle_counter_frequency, BuiltinProc_count_ones, BuiltinProc_count_zeros, @@ -170,8 +172,12 @@ BuiltinProc__simd_begin, BuiltinProc_simd_extract, BuiltinProc_simd_replace, + BuiltinProc_simd_reduce_add_bisect, + BuiltinProc_simd_reduce_mul_bisect, BuiltinProc_simd_reduce_add_ordered, BuiltinProc_simd_reduce_mul_ordered, + BuiltinProc_simd_reduce_add_pairs, + BuiltinProc_simd_reduce_mul_pairs, BuiltinProc_simd_reduce_min, BuiltinProc_simd_reduce_max, BuiltinProc_simd_reduce_and, @@ -186,6 +192,7 @@ BuiltinProc__simd_begin, BuiltinProc_simd_shuffle, BuiltinProc_simd_select, + BuiltinProc_simd_runtime_swizzle, BuiltinProc_simd_ceil, BuiltinProc_simd_floor, @@ -205,6 +212,9 @@ BuiltinProc__simd_begin, BuiltinProc_simd_masked_expand_load, BuiltinProc_simd_masked_compress_store, + BuiltinProc_simd_indices, + + // Platform specific SIMD intrinsics BuiltinProc_simd_x86__MM_SHUFFLE, BuiltinProc__simd_end, @@ -216,6 +226,7 @@ BuiltinProc__simd_end, BuiltinProc_x86_cpuid, BuiltinProc_x86_xgetbv, + // Constant type tests BuiltinProc__type_begin, @@ -227,14 +238,19 @@ BuiltinProc__type_begin, BuiltinProc_type_convert_variants_to_pointers, BuiltinProc_type_merge, + BuiltinProc_type_integer_to_unsigned, + BuiltinProc_type_integer_to_signed, + BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_boolean, + BuiltinProc_type_is_bit_field, BuiltinProc_type_is_integer, BuiltinProc_type_is_rune, BuiltinProc_type_is_float, BuiltinProc_type_is_complex, BuiltinProc_type_is_quaternion, BuiltinProc_type_is_string, + BuiltinProc_type_is_string16, BuiltinProc_type_is_typeid, BuiltinProc_type_is_any, @@ -249,6 +265,7 @@ BuiltinProc__type_simple_boolean_begin, BuiltinProc_type_is_sliceable, BuiltinProc_type_is_comparable, BuiltinProc_type_is_simple_compare, // easily compared using memcmp + BuiltinProc_type_is_nearly_simple_compare, // easily compared using memcmp (including floats) BuiltinProc_type_is_dereferenceable, BuiltinProc_type_is_valid_map_key, BuiltinProc_type_is_valid_matrix_elements, @@ -313,6 +330,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_bit_set_backing_type, + BuiltinProc_type_enum_is_contiguous, + BuiltinProc_type_equal_proc, BuiltinProc_type_hasher_proc, BuiltinProc_type_map_info, @@ -320,6 +339,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_has_shared_fields, + BuiltinProc_type_canonical_name, + BuiltinProc__type_end, BuiltinProc_procedure_of, @@ -331,6 +352,9 @@ BuiltinProc__type_end, BuiltinProc_objc_find_class, BuiltinProc_objc_register_selector, BuiltinProc_objc_register_class, + BuiltinProc_objc_ivar_get, + BuiltinProc_objc_block, + BuiltinProc_objc_super, BuiltinProc_constant_utf16_cstring, @@ -368,6 +392,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("conj"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("expand_values"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, + {STR_LIT("compress_values"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("min"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("max"), 1, true, Expr_Expr, BuiltinProcPkg_builtin}, @@ -404,6 +429,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("trap"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics, /*diverging*/true}, {STR_LIT("debug_trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/false}, {STR_LIT("read_cycle_counter"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("read_cycle_counter_frequency"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("count_ones"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("count_zeros"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -515,8 +541,12 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_extract"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_replace"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_reduce_add_bisect"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_reduce_mul_bisect"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_reduce_add_ordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_reduce_mul_ordered"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_reduce_add_pairs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_reduce_mul_pairs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_reduce_min"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_reduce_max"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_reduce_and"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -532,6 +562,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_shuffle"), 2, true, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_select"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_runtime_swizzle"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_ceil") , 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_floor"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -551,6 +582,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("simd_masked_expand_load"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_masked_compress_store"), 3, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_indices"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("simd_x86__MM_SHUFFLE"), 4, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, @@ -569,6 +602,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_merge"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_integer_to_unsigned"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_integer_to_signed"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_integer"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -577,6 +613,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_complex"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_quaternion"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_string"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_string16"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_typeid"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_any"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -591,6 +628,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_sliceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_comparable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_simple_compare"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_nearly_simple_compare"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_dereferenceable"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_valid_map_key"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_valid_matrix_elements"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -608,6 +646,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_is_enum"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_bit_set"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_bit_field"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_simd_vector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_matrix"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, @@ -654,12 +693,15 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_bit_set_backing_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_enum_is_contiguous"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics }, + {STR_LIT("type_equal_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_hasher_proc"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_map_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_map_cell_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_has_shared_fields"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_canonical_name"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, @@ -673,6 +715,9 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("objc_find_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("objc_register_selector"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("objc_register_class"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT("objc_ivar_get"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT("objc_block"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("objc_super"), 1, true, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("constant_utf16_cstring"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/common.cpp b/src/common.cpp index ad1e5a851..5b007bf2c 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -80,6 +80,13 @@ gb_internal gb_inline bool is_power_of_two(i64 x) { return !(x & (x-1)); } +gb_internal gb_inline bool is_power_of_two_u64(u64 x) { + if (x == 0) { + return false; + } + return !(x & (x-1)); +} + gb_internal int isize_cmp(isize x, isize y) { if (x < y) { return -1; @@ -350,6 +357,7 @@ gb_global bool global_module_path_set = false; #include "ptr_map.cpp" #include "ptr_set.cpp" #include "string_map.cpp" +#include "string16_map.cpp" #include "string_set.cpp" #include "priority_queue.cpp" #include "thread_pool.cpp" @@ -669,7 +677,7 @@ gb_internal gb_inline f64 gb_sqrt(f64 x) { gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) { u32 i, j; - u32 len = cast(u32)string16_len(cmd_line); + u32 len = cast(u32)string16_len(cast(u16 *)cmd_line); i = ((len+2)/2)*gb_size_of(void *) + gb_size_of(void *); wchar_t **argv = cast(wchar_t **)GlobalAlloc(GMEM_FIXED, i + (len+2)*gb_size_of(wchar_t)); diff --git a/src/common_memory.cpp b/src/common_memory.cpp index 47b2796a9..addd43687 100644 --- a/src/common_memory.cpp +++ b/src/common_memory.cpp @@ -113,6 +113,13 @@ gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) { return ptr; } + +template +gb_internal T *arena_alloc_item(Arena *arena) { + return cast(T *)arena_alloc(arena, gb_size_of(T), gb_align_of(T)); +} + + gb_internal void arena_free_all(Arena *arena) { while (arena->curr_block != nullptr) { MemoryBlock *free_block = arena->curr_block; @@ -346,7 +353,7 @@ gb_internal gbAllocator arena_allocator(Arena *arena) { gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc) { void *ptr = nullptr; Arena *arena = cast(Arena *)allocator_data; - GB_ASSERT_NOT_NULL(arena); + GB_ASSERT(arena != nullptr); switch (type) { case gbAllocation_Alloc: @@ -394,6 +401,48 @@ gb_internal Arena *get_arena(ThreadArenaKind kind) { } +template +gb_internal T *permanent_alloc_item() { + Arena *arena = get_arena(ThreadArena_Permanent); + return arena_alloc_item(arena); +} + +template +gb_internal T *permanent_alloc_array(isize count) { + Arena *arena = get_arena(ThreadArena_Permanent); + return cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T)); +} + +template +gb_internal Slice permanent_slice_make(isize count) { + Arena *arena = get_arena(ThreadArena_Permanent); + T *data = cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T)); + return {data, count}; +} + +template +gb_internal T *temporary_alloc_item() { + Arena *arena = get_arena(ThreadArena_Temporary); + return arena_alloc_item(arena); +} + +template +gb_internal T *temporary_alloc_array(isize count) { + Arena *arena = get_arena(ThreadArena_Temporary); + return cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T)); +} + +template +gb_internal Slice temporary_slice_make(isize count) { + Arena *arena = get_arena(ThreadArena_Temporary); + T *data = cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T)); + return {data, count}; +} + + + + + gb_internal GB_ALLOCATOR_PROC(thread_arena_allocator_proc) { void *ptr = nullptr; @@ -432,15 +481,16 @@ gb_internal gbAllocator permanent_allocator() { } gb_internal gbAllocator temporary_allocator() { - return {thread_arena_allocator_proc, cast(void *)cast(uintptr)ThreadArena_Permanent}; + // return {thread_arena_allocator_proc, cast(void *)cast(uintptr)ThreadArena_Temporary}; + return permanent_allocator(); } #define TEMP_ARENA_GUARD(arena) ArenaTempGuard GB_DEFER_3(_arena_guard_){arena} -// #define TEMPORARY_ALLOCATOR_GUARD() -#define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(get_arena(ThreadArena_Temporary)) +// #define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(get_arena(ThreadArena_Temporary)) +#define TEMPORARY_ALLOCATOR_GUARD() #define PERMANENT_ALLOCATOR_GUARD() diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index a92ffc7ad..1f2325980 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -43,7 +43,7 @@ struct OdinDocWriter { }; gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e); -gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type); +gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool cache); template gb_internal void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker *t, isize size) { @@ -467,8 +467,8 @@ gb_internal OdinDocArray odin_doc_where_clauses(OdinDocWriter *w, return odin_write_slice(w, clauses.data, clauses.count); } -gb_internal OdinDocArray odin_doc_type_as_slice(OdinDocWriter *w, Type *type) { - OdinDocTypeIndex index = odin_doc_type(w, type); +gb_internal OdinDocArray odin_doc_type_as_slice(OdinDocWriter *w, Type *type, bool cache=true) { + OdinDocTypeIndex index = odin_doc_type(w, type, cache); return odin_write_item_as_slice(w, index); } @@ -479,7 +479,7 @@ gb_internal OdinDocArray odin_doc_add_entity_as_slice(OdinDo -gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { +gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool cache=true) { if (type == nullptr) { return 0; } @@ -491,10 +491,13 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { } } - u64 type_hash = type_hash_canonical_type(type); - OdinDocTypeIndex *found = map_get(&w->type_cache, type_hash); - if (found) { - return *found; + u64 type_hash = {0}; + if (cache) { + type_hash = type_hash_canonical_type(type); + OdinDocTypeIndex *found = map_get(&w->type_cache, type_hash); + if (found) { + return *found; + } } @@ -502,7 +505,9 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { OdinDocType doc_type = {}; OdinDocTypeIndex type_index = 0; type_index = odin_doc_write_item(w, &w->types, &doc_type, &dst); - map_set(&w->type_cache, type_hash, type_index); + if (cache) { + map_set(&w->type_cache, type_hash, type_index); + } switch (type->kind) { case Type_Basic: @@ -527,7 +532,10 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) { doc_type.kind = OdinDocType_Generic; doc_type.name = odin_doc_write_string(w, name); if (type->Generic.specialized) { - doc_type.types = odin_doc_type_as_slice(w, type->Generic.specialized); + // NOTE(laytan): do not look at the cache for the specialization, it would resolve + // to the same entry as the type itself because `default_type` resolves to the + // specialization of a generic type. + doc_type.types = odin_doc_type_as_slice(w, type->Generic.specialized, cache=false); } } break; @@ -1163,4 +1171,4 @@ gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) { gb_internal bool is_in_doc_writer(void) { return g_in_doc_writer.load(); -} \ No newline at end of file +} diff --git a/src/entity.cpp b/src/entity.cpp index b2148aa7b..2b21fdcac 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -164,6 +164,7 @@ struct Entity { u64 id; std::atomic flags; std::atomic state; + std::atomic min_dep_count; Token token; Scope * scope; Type * type; @@ -233,8 +234,13 @@ struct Entity { } Variable; struct { Type * type_parameter_specialization; + Type * original_type_for_parapoly; String ir_mangled_name; bool is_type_alias; + bool objc_is_implementation; + Type* objc_superclass; + Type* objc_ivar; + Entity*objc_context_provider; String objc_class_name; TypeNameObjCMetadata *objc_metadata; } TypeName; @@ -245,6 +251,8 @@ struct Entity { String link_name; String link_prefix; String link_suffix; + String objc_selector_name; + Entity *objc_class; DeferredProcedure deferred_procedure; struct GenProcsData *gen_procs; @@ -258,6 +266,10 @@ struct Entity { bool is_memcpy_like : 1; bool uses_branch_location : 1; bool is_anonymous : 1; + bool no_sanitize_address : 1; + bool no_sanitize_memory : 1; + bool is_objc_impl_or_import : 1; + bool is_objc_class_method : 1; } Procedure; struct { Array entities; @@ -341,7 +353,7 @@ gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Typ entity->type = type; entity->id = 1 + global_entity_id.fetch_add(1); if (token.pos.file_id) { - entity->file = thread_safe_get_ast_file_from_id(token.pos.file_id); + entity->file = thread_unsafe_get_ast_file_from_id(token.pos.file_id); } return entity; } diff --git a/src/error.cpp b/src/error.cpp index 1492b00c7..53bc01654 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -86,7 +86,7 @@ gb_internal char *token_pos_to_string(TokenPos const &pos); gb_internal bool set_file_path_string(i32 index, String const &path) { bool ok = false; GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.path_mutex); + // mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_files_mutex); if (index >= global_file_path_strings.count) { @@ -99,14 +99,14 @@ gb_internal bool set_file_path_string(i32 index, String const &path) { } mutex_unlock(&global_files_mutex); - mutex_unlock(&global_error_collector.path_mutex); + // mutex_unlock(&global_error_collector.path_mutex); return ok; } gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) { bool ok = false; GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.path_mutex); + // mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_files_mutex); if (index >= global_files.count) { @@ -118,13 +118,13 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) { ok = true; } mutex_unlock(&global_files_mutex); - mutex_unlock(&global_error_collector.path_mutex); + // mutex_unlock(&global_error_collector.path_mutex); return ok; } gb_internal String get_file_path_string(i32 index) { GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.path_mutex); + // mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_files_mutex); String path = {}; @@ -133,13 +133,13 @@ gb_internal String get_file_path_string(i32 index) { } mutex_unlock(&global_files_mutex); - mutex_unlock(&global_error_collector.path_mutex); + // mutex_unlock(&global_error_collector.path_mutex); return path; } gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) { GB_ASSERT(index >= 0); - mutex_lock(&global_error_collector.path_mutex); + // mutex_lock(&global_error_collector.path_mutex); mutex_lock(&global_files_mutex); AstFile *file = nullptr; @@ -148,7 +148,18 @@ gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) { } mutex_unlock(&global_files_mutex); - mutex_unlock(&global_error_collector.path_mutex); + // mutex_unlock(&global_error_collector.path_mutex); + return file; +} + + +// use AFTER PARSER +gb_internal AstFile *thread_unsafe_get_ast_file_from_id(i32 index) { + GB_ASSERT(index >= 0); + AstFile *file = nullptr; + if (index < global_files.count) { + file = global_files[index]; + } return file; } @@ -823,7 +834,7 @@ gb_internal int error_value_cmp(void const *a, void const *b) { gb_global String error_article_table[][2] = { {str_lit("a "), str_lit("bit_set literal")}, {str_lit("a "), str_lit("constant declaration")}, - {str_lit("a "), str_lit("dynamiic array literal")}, + {str_lit("a "), str_lit("dynamic array literal")}, {str_lit("a "), str_lit("map index")}, {str_lit("a "), str_lit("map literal")}, {str_lit("a "), str_lit("matrix literal")}, diff --git a/src/exact_value.cpp b/src/exact_value.cpp index ceaed84c1..f2aed84c2 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -29,6 +29,7 @@ enum ExactValueKind { ExactValue_Compound = 8, ExactValue_Procedure = 9, ExactValue_Typeid = 10, + ExactValue_String16 = 11, ExactValue_Count, }; @@ -46,6 +47,7 @@ struct ExactValue { Ast * value_compound; Ast * value_procedure; Type * value_typeid; + String16 value_string16; }; }; @@ -66,6 +68,9 @@ gb_internal uintptr hash_exact_value(ExactValue v) { case ExactValue_String: res = gb_fnv32a(v.value_string.text, v.value_string.len); break; + case ExactValue_String16: + res = gb_fnv32a(v.value_string.text, v.value_string.len*gb_size_of(u16)); + break; case ExactValue_Integer: { u32 key = gb_fnv32a(v.value_integer.dp, gb_size_of(*v.value_integer.dp) * v.value_integer.used); @@ -118,6 +123,11 @@ gb_internal ExactValue exact_value_string(String string) { result.value_string = string; return result; } +gb_internal ExactValue exact_value_string16(String16 string) { + ExactValue result = {ExactValue_String16}; + result.value_string16 = string; + return result; +} gb_internal ExactValue exact_value_i64(i64 i) { ExactValue result = {ExactValue_Integer}; @@ -656,6 +666,7 @@ gb_internal i32 exact_value_order(ExactValue const &v) { return 0; case ExactValue_Bool: case ExactValue_String: + case ExactValue_String16: return 1; case ExactValue_Integer: return 2; @@ -689,6 +700,7 @@ gb_internal void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_Bool: case ExactValue_String: + case ExactValue_String16: case ExactValue_Quaternion: case ExactValue_Pointer: case ExactValue_Compound: @@ -891,7 +903,18 @@ gb_internal ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, E gb_memmove(data, sx.text, sx.len); gb_memmove(data+sx.len, sy.text, sy.len); return exact_value_string(make_string(data, len)); - break; + } + case ExactValue_String16: { + if (op != Token_Add) goto error; + + // NOTE(bill): How do you minimize this over allocation? + String sx = x.value_string; + String sy = y.value_string; + isize len = sx.len+sy.len; + u16 *data = gb_alloc_array(permanent_allocator(), u16, len); + gb_memmove(data, sx.text, sx.len*gb_size_of(u16)); + gb_memmove(data+sx.len, sy.text, sy.len*gb_size_of(u16)); + return exact_value_string16(make_string16(data, len)); } } @@ -954,6 +977,10 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) case ExactValue_Float: { f64 a = x.value_float; f64 b = y.value_float; + if (isnan(a) || isnan(b)) { + return op == Token_NotEq; + } + switch (op) { case Token_CmpEq: return cmp_f64(a, b) == 0; case Token_NotEq: return cmp_f64(a, b) != 0; @@ -990,6 +1017,19 @@ gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) } break; } + case ExactValue_String16: { + String16 a = x.value_string16; + String16 b = y.value_string16; + switch (op) { + case Token_CmpEq: return a == b; + case Token_NotEq: return a != b; + case Token_Lt: return a < b; + case Token_LtEq: return a <= b; + case Token_Gt: return a > b; + case Token_GtEq: return a >= b; + } + break; + } case ExactValue_Pointer: { switch (op) { @@ -1046,6 +1086,20 @@ gb_internal gbString write_exact_value_to_string(gbString str, ExactValue const gb_free(heap_allocator(), s.text); return str; } + case ExactValue_String16: { + String s = quote_to_ascii(heap_allocator(), v.value_string16); + string_limit = gb_max(string_limit, 36); + if (s.len <= string_limit) { + str = gb_string_append_length(str, s.text, s.len); + } else { + isize n = string_limit/5; + str = gb_string_append_length(str, s.text, n); + str = gb_string_append_fmt(str, "\"..%lld chars..\"", s.len-(2*n)); + str = gb_string_append_length(str, s.text+s.len-n, n); + } + gb_free(heap_allocator(), s.text); + return str; + } case ExactValue_Integer: { String s = big_int_to_string(heap_allocator(), &v.value_integer); str = gb_string_append_length(str, s.text, s.len); diff --git a/src/gb/gb.h b/src/gb/gb.h index 98c362e93..c52f63cec 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -497,7 +497,11 @@ typedef i32 b32; // NOTE(bill): Prefer this!!! #if !defined(gb_no_asan) #if defined(_MSC_VER) - #define gb_no_asan __declspec(no_sanitize_address) + #if _MSC_VER >= 1930 + #define gb_no_asan __declspec(no_sanitize_address) + #else + #define gb_no_asan + #endif #else #define gb_no_asan __attribute__((disable_sanitizer_instrumentation)) #endif @@ -710,13 +714,15 @@ extern "C++" { } while (0) #endif + +#if defined(DISABLE_ASSERT) +#define GB_ASSERT(cond) gb_unused(cond) +#endif + #ifndef GB_ASSERT #define GB_ASSERT(cond) GB_ASSERT_MSG(cond, NULL) #endif -#ifndef GB_ASSERT_NOT_NULL -#define GB_ASSERT_NOT_NULL(ptr) GB_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL") -#endif // NOTE(bill): Things that shouldn't happen with a message! #ifndef GB_PANIC @@ -3715,7 +3721,7 @@ gb_inline i32 gb_strcmp(char const *s1, char const *s2) { } gb_inline char *gb_strcpy(char *dest, char const *source) { - GB_ASSERT_NOT_NULL(dest); + GB_ASSERT(dest != NULL); if (source) { char *str = dest; while (*source) *str++ = *source++; @@ -3725,7 +3731,7 @@ gb_inline char *gb_strcpy(char *dest, char const *source) { gb_inline char *gb_strncpy(char *dest, char const *source, isize len) { - GB_ASSERT_NOT_NULL(dest); + GB_ASSERT(dest != NULL); if (source) { char *str = dest; while (len > 0 && *source) { @@ -3742,7 +3748,7 @@ gb_inline char *gb_strncpy(char *dest, char const *source, isize len) { gb_inline isize gb_strlcpy(char *dest, char const *source, isize len) { isize result = 0; - GB_ASSERT_NOT_NULL(dest); + GB_ASSERT(dest != NULL); if (source) { char const *source_start = source; char *str = dest; @@ -4865,8 +4871,8 @@ u64 gb_murmur64_seed(void const *data_, isize len, u64 seed) { u64 h = seed ^ (len * m); u64 const *data = cast(u64 const *)data_; - u8 const *data2 = cast(u8 const *)data_; u64 const* end = data + (len / 8); + u8 const *data2 = cast(u8 const *)end; while (data != end) { u64 k = *data++; @@ -5632,7 +5638,7 @@ gbFileContents gb_file_read_contents(gbAllocator a, b32 zero_terminate, char con void gb_file_free_contents(gbFileContents *fc) { if (fc == NULL || fc->size == 0) return; - GB_ASSERT_NOT_NULL(fc->data); + GB_ASSERT(fc->data != NULL); gb_free(fc->allocator, fc->data); fc->data = NULL; fc->size = 0; @@ -5644,7 +5650,7 @@ void gb_file_free_contents(gbFileContents *fc) { gb_inline b32 gb_path_is_absolute(char const *path) { b32 result = false; - GB_ASSERT_NOT_NULL(path); + GB_ASSERT(path != NULL); #if defined(GB_SYSTEM_WINDOWS) result == (gb_strlen(path) > 2) && gb_char_is_alpha(path[0]) && @@ -5659,7 +5665,7 @@ gb_inline b32 gb_path_is_relative(char const *path) { return !gb_path_is_absolut gb_inline b32 gb_path_is_root(char const *path) { b32 result = false; - GB_ASSERT_NOT_NULL(path); + GB_ASSERT(path != NULL); #if defined(GB_SYSTEM_WINDOWS) result = gb_path_is_absolute(path) && (gb_strlen(path) == 3); #else @@ -5670,14 +5676,14 @@ gb_inline b32 gb_path_is_root(char const *path) { gb_inline char const *gb_path_base_name(char const *path) { char const *ls; - GB_ASSERT_NOT_NULL(path); + GB_ASSERT(path != NULL); ls = gb_char_last_occurence(path, '/'); return (ls == NULL) ? path : ls+1; } gb_inline char const *gb_path_extension(char const *path) { char const *ld; - GB_ASSERT_NOT_NULL(path); + GB_ASSERT(path != NULL); ld = gb_char_last_occurence(path, '.'); return (ld == NULL) ? NULL : ld+1; } @@ -5838,18 +5844,25 @@ gb_inline isize gb_printf_err_va(char const *fmt, va_list va) { gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) { char buf[4096]; - isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va); + va_list va_save; + va_copy(va_save, va); + isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va_save); + va_end(va_save); char *new_buf = NULL; isize n = gb_size_of(buf); while (len < 0) { + va_copy(va_save, va); + defer (va_end(va_save)); n <<= 1; gb_free(gb_heap_allocator(), new_buf); new_buf = gb_alloc_array(gb_heap_allocator(), char, n);; - len = gb_snprintf_va(new_buf, n, fmt, va); + len = gb_snprintf_va(new_buf, n, fmt, va_save); } - gb_file_write(f, buf, len-1); // NOTE(bill): prevent extra whitespace if (new_buf != NULL) { + gb_file_write(f, new_buf, len-1); // NOTE(bill): prevent extra whitespace gb_free(gb_heap_allocator(), new_buf); + } else { + gb_file_write(f, buf, len-1); // NOTE(bill): prevent extra whitespace } return len; } @@ -5912,7 +5925,7 @@ gb_internal isize gb__print_string(char *text, isize max_len, gbprivFmtInfo *inf len = info->precision < len ? info->precision : len; } - res += gb_strlcpy(text, str, len); + res += gb_strlcpy(text, str, gb_min(len, remaining)); if (info->width > res) { isize padding = info->width - len; @@ -5930,7 +5943,7 @@ gb_internal isize gb__print_string(char *text, isize max_len, gbprivFmtInfo *inf } } - res += gb_strlcpy(text, str, len); + res += gb_strlcpy(text, str, gb_min(len, remaining)); } @@ -6066,15 +6079,16 @@ gb_internal isize gb__print_f64(char *text, isize max_len, gbprivFmtInfo *info, gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va_list va) { char const *text_begin = text; - isize remaining = max_len, res; + isize remaining = max_len - 1, res; - while (*fmt) { + while (*fmt && remaining > 0) { gbprivFmtInfo info = {0}; isize len = 0; info.precision = -1; - while (*fmt && *fmt != '%' && remaining) { + while (remaining > 0 && *fmt && *fmt != '%') { *text++ = *fmt++; + remaining--; } if (*fmt == '%') { @@ -6240,7 +6254,7 @@ gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va text += len; if (len >= remaining) { - remaining = gb_min(remaining, 1); + remaining = 0; } else { remaining -= len; } diff --git a/src/linker.cpp b/src/linker.cpp index cf2ef638d..f1e0335d5 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -7,19 +7,15 @@ struct LinkerData { Array output_temp_paths; String output_base; String output_name; -#if defined(GB_SYSTEM_OSX) - b8 needs_system_library_linked; -#endif + bool needs_system_library_linked; }; gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...); gb_internal bool system_exec_command_line_app_output(char const *command, gbString *output); -#if defined(GB_SYSTEM_OSX) gb_internal void linker_enable_system_library_linking(LinkerData *ld) { - ld->needs_system_library_linked = 1; + ld->needs_system_library_linked = true; } -#endif gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String const &init_fullpath) { gbAllocator ha = heap_allocator(); @@ -28,9 +24,7 @@ gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String cons array_init(&ld->foreign_libraries, ha, 0, 1024); ptr_set_init(&ld->foreign_libraries_set, 1024); -#if defined(GB_SYSTEM_OSX) - ld->needs_system_library_linked = 0; -#endif + ld->needs_system_library_linked = false; if (build_context.out_filepath.len == 0) { ld->output_name = remove_directory_from_path(init_fullpath); @@ -136,6 +130,9 @@ gb_internal i32 linker_stage(LinkerData *gen) { return result; } + bool is_cross_linking = false; + bool is_android = false; + if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { #if defined(GB_SYSTEM_UNIX) result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s", @@ -146,32 +143,50 @@ gb_internal i32 linker_stage(LinkerData *gen) { LIT(target_arch_names[build_context.metrics.arch]) ); #endif - } else if (build_context.cross_compiling && build_context.different_os) { - gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n", - LIT(target_os_names[build_context.metrics.os]), - LIT(target_arch_names[build_context.metrics.arch]) - ); - build_context.keep_object_files = true; + } else if (build_context.cross_compiling && (build_context.different_os || selected_subtarget != Subtarget_Default)) { + switch (selected_subtarget) { + case Subtarget_Android: + is_cross_linking = true; + is_android = true; + goto try_cross_linking; + default: + gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n", + LIT(target_os_names[build_context.metrics.os]), + LIT(target_arch_names[build_context.metrics.arch]) + ); + build_context.keep_object_files = true; + break; + } } else { +try_cross_linking:; + #if defined(GB_SYSTEM_WINDOWS) - bool is_windows = true; + String section_name = str_lit("msvc-link"); + bool is_windows = build_context.metrics.os == TargetOs_windows; #else + String section_name = str_lit("lld-link"); bool is_windows = false; #endif - #if defined(GB_SYSTEM_OSX) - bool is_osx = true; - #else - bool is_osx = false; + + bool is_osx = build_context.metrics.os == TargetOs_darwin; + + + switch (build_context.linker_choice) { + case Linker_Default: break; + case Linker_lld: section_name = str_lit("lld-link"); break; + #if defined(GB_SYSTEM_LINUX) + case Linker_mold: section_name = str_lit("mold-link"); break; #endif + #if defined(GB_SYSTEM_WINDOWS) + case Linker_radlink: section_name = str_lit("rad-link"); break; + #endif + default: + gb_printf_err("'%.*s' linker is not support for this platform\n", LIT(linker_choices[build_context.linker_choice])); + return 1; + } if (is_windows) { - String section_name = str_lit("msvc-link"); - switch (build_context.linker_choice) { - case Linker_Default: break; - case Linker_lld: section_name = str_lit("lld-link"); break; - case Linker_radlink: section_name = str_lit("rad-link"); break; - } timings_start_section(timings, section_name); gbString lib_str = gb_string_make(heap_allocator(), ""); @@ -273,13 +288,20 @@ gb_internal i32 linker_stage(LinkerData *gen) { if (build_context.build_mode == BuildMode_DynamicLibrary) { link_settings = gb_string_append_fmt(link_settings, " /DLL"); + if (build_context.no_entry_point) { + link_settings = gb_string_append_fmt(link_settings, " /NOENTRY"); + } } else { - link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup"); + // For i386 with CRT, libcmt provides the entry point + // For other cases or no_crt, we need to specify the entry point + if (!(build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt)) { + link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup"); + } } - if (build_context.pdb_filepath != "") { - String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]); - link_settings = gb_string_append_fmt(link_settings, " /PDB:\"%.*s\"", LIT(pdb_path)); + if (build_context.build_paths[BuildPath_Symbols].name != "") { + String symbol_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Symbols]); + link_settings = gb_string_append_fmt(link_settings, " /PDB:\"%.*s\"", LIT(symbol_path)); } if (build_context.build_mode != BuildMode_StaticLibrary) { @@ -317,7 +339,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { "", LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename), link_settings, - LIT(build_context.ODIN_WINDOWS_SUBSYSTEM), + LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags), lib_str @@ -337,7 +359,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { "", LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename), link_settings, - LIT(build_context.ODIN_WINDOWS_SUBSYSTEM), + LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags), lib_str @@ -400,7 +422,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { "", LIT(vs_exe_path), LIT(linker_name), object_files, LIT(res_path), LIT(output_filename), link_settings, - LIT(build_context.ODIN_WINDOWS_SUBSYSTEM), + LIT(windows_subsystem_names[build_context.ODIN_WINDOWS_SUBSYSTEM]), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags), lib_str @@ -412,25 +434,32 @@ gb_internal i32 linker_stage(LinkerData *gen) { } } } else { - timings_start_section(timings, str_lit("ld-link")); + + timings_start_section(timings, section_name); + + int const ODIN_ANDROID_API_LEVEL = build_context.ODIN_ANDROID_API_LEVEL; + + String ODIN_ANDROID_NDK = build_context.ODIN_ANDROID_NDK; + String ODIN_ANDROID_NDK_TOOLCHAIN = build_context.ODIN_ANDROID_NDK_TOOLCHAIN; + String ODIN_ANDROID_NDK_TOOLCHAIN_LIB = build_context.ODIN_ANDROID_NDK_TOOLCHAIN_LIB; + String ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL = build_context.ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL; + String ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT = build_context.ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT; // Link using `clang`, unless overridden by `ODIN_CLANG_PATH` environment variable. const char* clang_path = gb_get_env("ODIN_CLANG_PATH", permanent_allocator()); + bool has_odin_clang_path_env = true; if (clang_path == NULL) { clang_path = "clang"; + has_odin_clang_path_env = false; } - // NOTE(vassvik): get cwd, for used for local shared libs linking, since those have to be relative to the exe - char cwd[256]; - #if !defined(GB_SYSTEM_WINDOWS) - getcwd(&cwd[0], 256); - #endif - //printf("%s\n", cwd); - // NOTE(vassvik): needs to add the root to the library search paths, so that the full filenames of the library // files can be passed with -l: - gbString lib_str = gb_string_make(heap_allocator(), "-L/"); + gbString lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(lib_str)); + #if !defined(GB_SYSTEM_WINDOWS) + lib_str = gb_string_appendc(lib_str, "-L/ "); + #endif StringSet asm_files = {}; string_set_init(&asm_files, 64); @@ -496,19 +525,20 @@ gb_internal i32 linker_stage(LinkerData *gen) { } String obj_format; - #if defined(GB_ARCH_64_BIT) - if (is_osx) { - obj_format = str_lit("macho64"); + if (build_context.metrics.ptr_size == 8) { + if (is_osx) { + obj_format = str_lit("macho64"); + } else { + obj_format = str_lit("elf64"); + } } else { - obj_format = str_lit("elf64"); + GB_ASSERT(build_context.metrics.ptr_size == 4); + if (is_osx) { + obj_format = str_lit("macho32"); + } else { + obj_format = str_lit("elf32"); + } } - #elif defined(GB_ARCH_32_BIT) - if (is_osx) { - obj_format = str_lit("macho32"); - } else { - obj_format = str_lit("elf32"); - } - #endif // GB_ARCH_*_BIT if (build_context.metrics.arch == TargetArch_riscv64) { result = system_exec_command_line_app("clang", @@ -579,7 +609,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { // Do not add libc again, this is added later already, and omitted with // the `-no-crt` flag, not skipping here would cause duplicate library // warnings when linking on darwin and might link libc silently even with `-no-crt`. - if (lib == str_lit("System.framework") || lib == str_lit("c")) { + if (lib == str_lit("System.framework") || lib == str_lit("System") || lib == str_lit("c")) { continue; } @@ -594,7 +624,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { // object // dynamic lib // static libs, absolute full path relative to the file in which the lib was imported from - lib_str = gb_string_append_fmt(lib_str, " %.*s ", LIT(lib)); + lib_str = gb_string_append_fmt(lib_str, " \"%.*s\" ", LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); @@ -618,8 +648,86 @@ gb_internal i32 linker_stage(LinkerData *gen) { gbString object_files = gb_string_make(heap_allocator(), ""); defer (gb_string_free(object_files)); + + + if (is_android) { // NOTE(bill): glue code needed for Android + TIME_SECTION("Android Native App Glue Compile"); + + String android_glue_object = {}; + String android_glue_static_lib = {}; + + char hash_buf[64] = {}; + gb_snprintf(hash_buf, gb_size_of(hash_buf), "%p", &hash_buf); + String hash = make_string_c(hash_buf); + + String temp_dir = normalize_path(temporary_allocator(), temporary_directory(temporary_allocator()), NIX_SEPARATOR_STRING); + android_glue_object = concatenate4_strings(temporary_allocator(), temp_dir, str_lit("android_native_app_glue-"), hash, str_lit(".o")); + android_glue_static_lib = concatenate4_strings(permanent_allocator(), temp_dir, str_lit("libandroid_native_app_glue-"), hash, str_lit(".a")); + + gbString glue = gb_string_make_length(heap_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len); + defer (gb_string_free(glue)); + + glue = gb_string_append_fmt(glue, "bin/clang"); + glue = gb_string_append_fmt(glue, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL); + glue = gb_string_appendc(glue, "-c \""); + glue = gb_string_append_length(glue, ODIN_ANDROID_NDK.text, ODIN_ANDROID_NDK.len); + glue = gb_string_appendc(glue, "sources/android/native_app_glue/android_native_app_glue.c"); + glue = gb_string_appendc(glue, "\" "); + glue = gb_string_appendc(glue, "-o \""); + glue = gb_string_append_length(glue, android_glue_object.text, android_glue_object.len); + glue = gb_string_appendc(glue, "\" "); + + glue = gb_string_appendc(glue, "--sysroot \""); + glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len); + glue = gb_string_appendc(glue, "sysroot"); + glue = gb_string_appendc(glue, "\" "); + + glue = gb_string_appendc(glue, "\"-I"); + glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len); + glue = gb_string_appendc(glue, "sysroot/usr/include/"); + glue = gb_string_appendc(glue, "\" "); + + glue = gb_string_appendc(glue, "\"-I"); + glue = gb_string_append_length(glue, ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len); + glue = gb_string_appendc(glue, "sysroot/usr/include/aarch64-linux-android/"); + glue = gb_string_appendc(glue, "\" "); + + + glue = gb_string_appendc(glue, "-Wno-macro-redefined "); + + result = system_exec_command_line_app("android-native-app-glue-compile", glue); + if (result) { + return result; + } + + TIME_SECTION("Android Native App Glue ar"); + + gbString ar = gb_string_make_length(heap_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len); + defer (gb_string_free(ar)); + + ar = gb_string_appendc(ar, "bin/llvm-ar"); + + ar = gb_string_appendc(ar, " rcs "); + + ar = gb_string_appendc(ar, "\""); + ar = gb_string_append_length(ar, android_glue_static_lib.text, android_glue_static_lib.len); + ar = gb_string_appendc(ar, "\" "); + + ar = gb_string_appendc(ar, "\""); + ar = gb_string_append_length(ar, android_glue_object.text, android_glue_object.len); + ar = gb_string_appendc(ar, "\" "); + + result = system_exec_command_line_app("android-native-app-glue-ar", ar); + if (result) { + return result; + } + + object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(android_glue_static_lib)); + } + + for (String object_path : gen->output_object_paths) { - object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); + object_files = gb_string_append_fmt(object_files, "\'%.*s\' ", LIT(object_path)); } gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); @@ -661,7 +769,9 @@ gb_internal i32 linker_stage(LinkerData *gen) { link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); } - + } else if (is_android) { + // Always shared even in android! + link_settings = gb_string_appendc(link_settings, "-shared "); } if (build_context.build_mode == BuildMode_Executable && build_context.reloc_mode == RelocMode_PIC) { @@ -670,6 +780,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { if (build_context.metrics.os != TargetOs_openbsd && build_context.metrics.os != TargetOs_haiku && build_context.metrics.arch != TargetArch_riscv64 + && !is_android ) { // OpenBSD and Haiku default to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); @@ -679,7 +790,65 @@ gb_internal i32 linker_stage(LinkerData *gen) { gbString platform_lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(platform_lib_str)); if (build_context.metrics.os == TargetOs_darwin) { - platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib "); + // Get the SDK path. + gbString darwin_sdk_path = gb_string_make(temporary_allocator(), ""); + + char const* darwin_platform_name = "MacOSX"; + char const* darwin_xcrun_sdk_name = "macosx"; + char const* darwin_min_version_id = "macosx"; + + const char* original_clang_path = clang_path; + + // NOTE(harold): We set the clang_path to run through xcrun because otherwise it complaints about the the sysroot + // being set to 'MacOSX' even though we've set the sysroot to the correct SDK (-Wincompatible-sysroot). + // This is because it is likely not using the SDK's toolchain Apple Clang but another one installed in the system. + switch (selected_subtarget) { + case Subtarget_iPhone: + darwin_platform_name = "iPhoneOS"; + darwin_xcrun_sdk_name = "iphoneos"; + darwin_min_version_id = "ios"; + if (!has_odin_clang_path_env) { + clang_path = "xcrun --sdk iphoneos clang"; + } + break; + case Subtarget_iPhoneSimulator: + darwin_platform_name = "iPhoneSimulator"; + darwin_xcrun_sdk_name = "iphonesimulator"; + darwin_min_version_id = "ios-simulator"; + if (!has_odin_clang_path_env) { + clang_path = "xcrun --sdk iphonesimulator clang"; + } + break; + } + + gbString darwin_find_sdk_cmd = gb_string_make(temporary_allocator(), ""); + darwin_find_sdk_cmd = gb_string_append_fmt(darwin_find_sdk_cmd, "xcrun --sdk %s --show-sdk-path", darwin_xcrun_sdk_name); + + if (!system_exec_command_line_app_output(darwin_find_sdk_cmd, &darwin_sdk_path)) { + + // Fallback to default clang, since `xcrun --sdk` did not work. + clang_path = original_clang_path; + + // Best-effort fallback to known locations + gbString darwin_sdk_path = gb_string_make(temporary_allocator(), ""); + darwin_sdk_path = gb_string_append_fmt(darwin_sdk_path, "/Library/Developer/CommandLineTools/SDKs/%s.sdk", darwin_platform_name); + + if (!path_is_directory(make_string_c(darwin_sdk_path))) { + gb_string_clear(darwin_sdk_path); + darwin_sdk_path = gb_string_append_fmt(darwin_sdk_path, "/Applications/Xcode.app/Contents/Developer/Platforms/%s.platform/Developer/SDKs/%s.sdk", darwin_platform_name); + + if (!path_is_directory(make_string_c(darwin_sdk_path))) { + gb_printf_err("Failed to find %s SDK\n", darwin_platform_name); + return -1; + } + } + } else { + // Trim the trailing newline. + darwin_sdk_path = gb_string_trim_space(darwin_sdk_path); + } + platform_lib_str = gb_string_append_fmt(platform_lib_str, "--sysroot %s ", darwin_sdk_path); + + platform_lib_str = gb_string_appendc(platform_lib_str, "-L/usr/local/lib "); // Homebrew's default library path, checking if it exists to avoid linking warnings. if (gb_file_exists("/opt/homebrew/lib")) { @@ -693,14 +862,57 @@ gb_internal i32 linker_stage(LinkerData *gen) { // Only specify this flag if the user has given a minimum version to target. // This will cause warnings to show up for mismatched libraries. - if (build_context.minimum_os_version_string_given) { - link_settings = gb_string_append_fmt(link_settings, "-mmacosx-version-min=%.*s ", LIT(build_context.minimum_os_version_string)); + // NOTE(harold): For device subtargets we have to explicitly set the default version to + // avoid the same warning since we configure our own minimum version when compiling for devices. + if (build_context.minimum_os_version_string_given || selected_subtarget != Subtarget_Default) { + link_settings = gb_string_append_fmt(link_settings, "-m%s-version-min=%.*s ", darwin_min_version_id, LIT(build_context.minimum_os_version_string)); } if (build_context.build_mode != BuildMode_DynamicLibrary) { // This points the linker to where the entry point is link_settings = gb_string_appendc(link_settings, "-e _main "); } + } else if (build_context.metrics.os == TargetOs_freebsd) { + if (build_context.sanitizer_flags & (SanitizerFlag_Address | SanitizerFlag_Memory)) { + // It's imperative that `pthread` is linked before `libc`, + // otherwise ASan/MSan will be unable to call `pthread_key_create` + // because FreeBSD's `libthr` implementation of `pthread` + // needs to replace the relevant stubs first. + // + // (Presumably TSan implements its own `pthread` interface, + // which is why it isn't required.) + // + // See: https://reviews.llvm.org/D39254 + platform_lib_str = gb_string_appendc(platform_lib_str, "-lpthread "); + } + // FreeBSD pkg installs third-party shared libraries in /usr/local/lib. + platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-L/usr/local/lib "); + } else if (build_context.metrics.os == TargetOs_openbsd) { + // OpenBSD ports install shared libraries in /usr/local/lib. Also, we must explicitly link libpthread. + platform_lib_str = gb_string_appendc(platform_lib_str, "-lpthread -Wl,-L/usr/local/lib "); + // Until the LLVM back-end can be adapted to emit endbr64 instructions on amd64, we + // need to pass -z nobtcfi in order to allow the resulting program to run under + // OpenBSD 7.4 and newer. Once support is added at compile time, this can be dropped. + platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-z,nobtcfi "); + } + + if (is_android) { + GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_LIB.len != 0); + GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.len != 0); + GB_ASSERT(ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.len != 0); + + platform_lib_str = gb_string_appendc(platform_lib_str, "\"-L"); + platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.text, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.len); + platform_lib_str = gb_string_appendc(platform_lib_str, "\" "); + + platform_lib_str = gb_string_appendc(platform_lib_str, "-landroid "); + platform_lib_str = gb_string_appendc(platform_lib_str, "-llog "); + + platform_lib_str = gb_string_appendc(platform_lib_str, "\"--sysroot="); + platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.text, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.len); + platform_lib_str = gb_string_appendc(platform_lib_str, "\" "); + + link_settings = gb_string_appendc(link_settings, "-u ANativeActivity_onCreate "); } if (!build_context.no_rpath) { @@ -709,24 +921,36 @@ gb_internal i32 linker_stage(LinkerData *gen) { if (build_context.metrics.os == TargetOs_darwin) { link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,@loader_path "); } else { - link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + if (is_android) { + // ignore + } else { + link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + } } } if (!build_context.no_crt) { - platform_lib_str = gb_string_appendc(platform_lib_str, "-lm "); + lib_str = gb_string_appendc(lib_str, "-lm "); if (build_context.metrics.os == TargetOs_darwin) { // NOTE: adding this causes a warning about duplicate libraries, I think it is // automatically assumed/added by clang when you don't do `-nostdlib`. - // platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem "); + // lib_str = gb_string_appendc(lib_str, "-lSystem "); } else { - platform_lib_str = gb_string_appendc(platform_lib_str, "-lc "); + lib_str = gb_string_appendc(lib_str, "-lc "); } } - gbString link_command_line = gb_string_make(heap_allocator(), clang_path); + gbString link_command_line = gb_string_make(heap_allocator(), ""); defer (gb_string_free(link_command_line)); + if (is_android) { + gbString ndk_bin_directory = gb_string_make_length(temporary_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len); + link_command_line = gb_string_appendc(link_command_line, ndk_bin_directory); + link_command_line = gb_string_appendc(link_command_line, "bin/clang"); + link_command_line = gb_string_append_fmt(link_command_line, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL); + } else { + link_command_line = gb_string_appendc(link_command_line, clang_path); + } link_command_line = gb_string_appendc(link_command_line, " -Wno-unused-command-line-argument "); link_command_line = gb_string_appendc(link_command_line, object_files); link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename)); @@ -736,9 +960,17 @@ gb_internal i32 linker_stage(LinkerData *gen) { link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.extra_linker_flags)); link_command_line = gb_string_append_fmt(link_command_line, " %s ", link_settings); + + if (is_android) { + TIME_SECTION("Linking"); + } + if (build_context.linker_choice == Linker_lld) { link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=lld"); result = system_exec_command_line_app("lld-link", link_command_line); + } else if (build_context.linker_choice == Linker_mold) { + link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=mold"); + result = system_exec_command_line_app("mold-link", link_command_line); } else { result = system_exec_command_line_app("ld-link", link_command_line); } diff --git a/src/llvm-c/Analysis.h b/src/llvm-c/Analysis.h index 6b93b5c3d..270b145a4 100644 --- a/src/llvm-c/Analysis.h +++ b/src/llvm-c/Analysis.h @@ -19,8 +19,8 @@ #ifndef LLVM_C_ANALYSIS_H #define LLVM_C_ANALYSIS_H -#include "ExternC.h" -#include "Types.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/BitReader.h b/src/llvm-c/BitReader.h index 725f3fa84..088107468 100644 --- a/src/llvm-c/BitReader.h +++ b/src/llvm-c/BitReader.h @@ -19,8 +19,8 @@ #ifndef LLVM_C_BITREADER_H #define LLVM_C_BITREADER_H -#include "ExternC.h" -#include "Types.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/BitWriter.h b/src/llvm-c/BitWriter.h index ba4a61afc..ea84b6593 100644 --- a/src/llvm-c/BitWriter.h +++ b/src/llvm-c/BitWriter.h @@ -19,8 +19,8 @@ #ifndef LLVM_C_BITWRITER_H #define LLVM_C_BITWRITER_H -#include "ExternC.h" -#include "Types.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Comdat.h b/src/llvm-c/Comdat.h index 30df20799..8002bc058 100644 --- a/src/llvm-c/Comdat.h +++ b/src/llvm-c/Comdat.h @@ -14,8 +14,8 @@ #ifndef LLVM_C_COMDAT_H #define LLVM_C_COMDAT_H -#include "ExternC.h" -#include "Types.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Config/llvm-config.h b/src/llvm-c/Config/llvm-config.h index e4edb83c5..8b77597c9 100644 --- a/src/llvm-c/Config/llvm-config.h +++ b/src/llvm-c/Config/llvm-config.h @@ -142,16 +142,16 @@ #define LLVM_USE_PERF 0 /* Major version of the LLVM API */ -#define LLVM_VERSION_MAJOR 18 +#define LLVM_VERSION_MAJOR 20 /* Minor version of the LLVM API */ #define LLVM_VERSION_MINOR 1 /* Patch version of the LLVM API */ -#define LLVM_VERSION_PATCH 8 +#define LLVM_VERSION_PATCH 0 /* LLVM version string */ -#define LLVM_VERSION_STRING "18.1.8" +#define LLVM_VERSION_STRING "20.1.0" /* Whether LLVM records statistics for use with GetStatistics(), * PrintStatistics() or PrintStatisticsJSON() diff --git a/src/llvm-c/Core.h b/src/llvm-c/Core.h index 25b8248fd..dc8ecf4fb 100644 --- a/src/llvm-c/Core.h +++ b/src/llvm-c/Core.h @@ -15,11 +15,11 @@ #ifndef LLVM_C_CORE_H #define LLVM_C_CORE_H -#include "Deprecated.h" -#include "ErrorHandling.h" -#include "ExternC.h" +#include "llvm-c/Deprecated.h" +#include "llvm-c/ErrorHandling.h" +#include "llvm-c/ExternC.h" -#include "Types.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN @@ -146,27 +146,27 @@ typedef enum { } LLVMOpcode; typedef enum { - LLVMVoidTypeKind, /**< type with no size */ - LLVMHalfTypeKind, /**< 16 bit floating point type */ - LLVMFloatTypeKind, /**< 32 bit floating point type */ - LLVMDoubleTypeKind, /**< 64 bit floating point type */ - LLVMX86_FP80TypeKind, /**< 80 bit floating point type (X87) */ - LLVMFP128TypeKind, /**< 128 bit floating point type (112-bit mantissa)*/ - LLVMPPC_FP128TypeKind, /**< 128 bit floating point type (two 64-bits) */ - LLVMLabelTypeKind, /**< Labels */ - LLVMIntegerTypeKind, /**< Arbitrary bit width integers */ - LLVMFunctionTypeKind, /**< Functions */ - LLVMStructTypeKind, /**< Structures */ - LLVMArrayTypeKind, /**< Arrays */ - LLVMPointerTypeKind, /**< Pointers */ - LLVMVectorTypeKind, /**< Fixed width SIMD vector type */ - LLVMMetadataTypeKind, /**< Metadata */ - LLVMX86_MMXTypeKind, /**< X86 MMX */ - LLVMTokenTypeKind, /**< Tokens */ - LLVMScalableVectorTypeKind, /**< Scalable SIMD vector type */ - LLVMBFloatTypeKind, /**< 16 bit brain floating point type */ - LLVMX86_AMXTypeKind, /**< X86 AMX */ - LLVMTargetExtTypeKind, /**< Target extension type */ + LLVMVoidTypeKind = 0, /**< type with no size */ + LLVMHalfTypeKind = 1, /**< 16 bit floating point type */ + LLVMFloatTypeKind = 2, /**< 32 bit floating point type */ + LLVMDoubleTypeKind = 3, /**< 64 bit floating point type */ + LLVMX86_FP80TypeKind = 4, /**< 80 bit floating point type (X87) */ + LLVMFP128TypeKind = 5, /**< 128 bit floating point type (112-bit mantissa)*/ + LLVMPPC_FP128TypeKind = 6, /**< 128 bit floating point type (two 64-bits) */ + LLVMLabelTypeKind = 7, /**< Labels */ + LLVMIntegerTypeKind = 8, /**< Arbitrary bit width integers */ + LLVMFunctionTypeKind = 9, /**< Functions */ + LLVMStructTypeKind = 10, /**< Structures */ + LLVMArrayTypeKind = 11, /**< Arrays */ + LLVMPointerTypeKind = 12, /**< Pointers */ + LLVMVectorTypeKind = 13, /**< Fixed width SIMD vector type */ + LLVMMetadataTypeKind = 14, /**< Metadata */ + /* 15 previously used by LLVMX86_MMXTypeKind */ + LLVMTokenTypeKind = 16, /**< Tokens */ + LLVMScalableVectorTypeKind = 17, /**< Scalable SIMD vector type */ + LLVMBFloatTypeKind = 18, /**< 16 bit brain floating point type */ + LLVMX86_AMXTypeKind = 19, /**< X86 AMX */ + LLVMTargetExtTypeKind = 20, /**< Target extension type */ } LLVMTypeKind; typedef enum { @@ -286,6 +286,7 @@ typedef enum { LLVMInstructionValueKind, LLVMPoisonValueValueKind, LLVMConstantTargetNoneValueKind, + LLVMConstantPtrAuthValueKind, } LLVMValueKind; typedef enum { @@ -361,35 +362,42 @@ typedef enum { } LLVMAtomicOrdering; typedef enum { - LLVMAtomicRMWBinOpXchg, /**< Set the new value and return the one old */ - LLVMAtomicRMWBinOpAdd, /**< Add a value and return the old one */ - LLVMAtomicRMWBinOpSub, /**< Subtract a value and return the old one */ - LLVMAtomicRMWBinOpAnd, /**< And a value and return the old one */ - LLVMAtomicRMWBinOpNand, /**< Not-And a value and return the old one */ - LLVMAtomicRMWBinOpOr, /**< OR a value and return the old one */ - LLVMAtomicRMWBinOpXor, /**< Xor a value and return the old one */ - LLVMAtomicRMWBinOpMax, /**< Sets the value if it's greater than the - original using a signed comparison and return - the old one */ - LLVMAtomicRMWBinOpMin, /**< Sets the value if it's Smaller than the - original using a signed comparison and return - the old one */ - LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the - original using an unsigned comparison and return - the old one */ - LLVMAtomicRMWBinOpUMin, /**< Sets the value if it's greater than the - original using an unsigned comparison and return - the old one */ - LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the - old one */ - LLVMAtomicRMWBinOpFSub, /**< Subtract a floating point value and return the + LLVMAtomicRMWBinOpXchg, /**< Set the new value and return the one old */ + LLVMAtomicRMWBinOpAdd, /**< Add a value and return the old one */ + LLVMAtomicRMWBinOpSub, /**< Subtract a value and return the old one */ + LLVMAtomicRMWBinOpAnd, /**< And a value and return the old one */ + LLVMAtomicRMWBinOpNand, /**< Not-And a value and return the old one */ + LLVMAtomicRMWBinOpOr, /**< OR a value and return the old one */ + LLVMAtomicRMWBinOpXor, /**< Xor a value and return the old one */ + LLVMAtomicRMWBinOpMax, /**< Sets the value if it's greater than the + original using a signed comparison and return + the old one */ + LLVMAtomicRMWBinOpMin, /**< Sets the value if it's Smaller than the + original using a signed comparison and return + the old one */ + LLVMAtomicRMWBinOpUMax, /**< Sets the value if it's greater than the + original using an unsigned comparison and return + the old one */ + LLVMAtomicRMWBinOpUMin, /**< Sets the value if it's greater than the + original using an unsigned comparison and return + the old one */ + LLVMAtomicRMWBinOpFAdd, /**< Add a floating point value and return the old one */ - LLVMAtomicRMWBinOpFMax, /**< Sets the value if it's greater than the - original using an floating point comparison and - return the old one */ - LLVMAtomicRMWBinOpFMin, /**< Sets the value if it's smaller than the - original using an floating point comparison and - return the old one */ + LLVMAtomicRMWBinOpFSub, /**< Subtract a floating point value and return the + old one */ + LLVMAtomicRMWBinOpFMax, /**< Sets the value if it's greater than the + original using an floating point comparison and + return the old one */ + LLVMAtomicRMWBinOpFMin, /**< Sets the value if it's smaller than the + original using an floating point comparison and + return the old one */ + LLVMAtomicRMWBinOpUIncWrap, /**< Increments the value, wrapping back to zero + when incremented above input value */ + LLVMAtomicRMWBinOpUDecWrap, /**< Decrements the value, wrapping back to + the input value when decremented below zero */ + LLVMAtomicRMWBinOpUSubCond, /** #else diff --git a/src/llvm-c/Error.h b/src/llvm-c/Error.h index 00746c701..874bbcfe8 100644 --- a/src/llvm-c/Error.h +++ b/src/llvm-c/Error.h @@ -14,7 +14,7 @@ #ifndef LLVM_C_ERROR_H #define LLVM_C_ERROR_H -#include "ExternC.h" +#include "llvm-c/ExternC.h" LLVM_C_EXTERN_C_BEGIN @@ -51,6 +51,14 @@ LLVMErrorTypeId LLVMGetErrorTypeId(LLVMErrorRef Err); */ void LLVMConsumeError(LLVMErrorRef Err); +/** + * Report a fatal error if Err is a failure value. + * + * This function can be used to wrap calls to fallible functions ONLY when it is + * known that the Error will always be a success value. + */ +void LLVMCantFail(LLVMErrorRef Err); + /** * Returns the given string's error message. This operation consumes the error, * and the given LLVMErrorRef value is not usable once this call returns. diff --git a/src/llvm-c/ErrorHandling.h b/src/llvm-c/ErrorHandling.h index 7f9b50a95..d9b9f2275 100644 --- a/src/llvm-c/ErrorHandling.h +++ b/src/llvm-c/ErrorHandling.h @@ -14,7 +14,7 @@ #ifndef LLVM_C_ERRORHANDLING_H #define LLVM_C_ERRORHANDLING_H -#include "ExternC.h" +#include "llvm-c/ExternC.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/ExecutionEngine.h b/src/llvm-c/ExecutionEngine.h index 8e72faefd..c5fc9bdb4 100644 --- a/src/llvm-c/ExecutionEngine.h +++ b/src/llvm-c/ExecutionEngine.h @@ -19,10 +19,10 @@ #ifndef LLVM_C_EXECUTIONENGINE_H #define LLVM_C_EXECUTIONENGINE_H -#include "ExternC.h" -#include "Target.h" -#include "TargetMachine.h" -#include "Types.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Target.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/IRReader.h b/src/llvm-c/IRReader.h index ec1110c7a..905b84fa5 100644 --- a/src/llvm-c/IRReader.h +++ b/src/llvm-c/IRReader.h @@ -14,8 +14,8 @@ #ifndef LLVM_C_IRREADER_H #define LLVM_C_IRREADER_H -#include "ExternC.h" -#include "Types.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/LLJIT.h b/src/llvm-c/LLJIT.h index ee207e10e..a58c3b8bb 100644 --- a/src/llvm-c/LLJIT.h +++ b/src/llvm-c/LLJIT.h @@ -24,10 +24,10 @@ #ifndef LLVM_C_LLJIT_H #define LLVM_C_LLJIT_H -#include "Error.h" -#include "Orc.h" -#include "TargetMachine.h" -#include "Types.h" +#include "llvm-c/Error.h" +#include "llvm-c/Orc.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/LLJITUtils.h b/src/llvm-c/LLJITUtils.h index 57ffedff8..940097432 100644 --- a/src/llvm-c/LLJITUtils.h +++ b/src/llvm-c/LLJITUtils.h @@ -26,7 +26,7 @@ #ifndef LLVM_C_LLJITUTILS_H #define LLVM_C_LLJITUTILS_H -#include "LLJIT.h" +#include "llvm-c/LLJIT.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Linker.h b/src/llvm-c/Linker.h index 463a2cff9..acff5d5e2 100644 --- a/src/llvm-c/Linker.h +++ b/src/llvm-c/Linker.h @@ -14,8 +14,8 @@ #ifndef LLVM_C_LINKER_H #define LLVM_C_LINKER_H -#include "ExternC.h" -#include "Types.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Object.h b/src/llvm-c/Object.h index 1948c3c34..2f39179c1 100644 --- a/src/llvm-c/Object.h +++ b/src/llvm-c/Object.h @@ -19,9 +19,9 @@ #ifndef LLVM_C_OBJECT_H #define LLVM_C_OBJECT_H -#include "ExternC.h" -#include "Types.h" -#include "Config/llvm-config.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" +#include "llvm-c/Config/llvm-config.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Orc.h b/src/llvm-c/Orc.h index ecd110b4d..8609a8a6d 100644 --- a/src/llvm-c/Orc.h +++ b/src/llvm-c/Orc.h @@ -27,9 +27,9 @@ #ifndef LLVM_C_ORC_H #define LLVM_C_ORC_H -#include "Error.h" -#include "TargetMachine.h" -#include "Types.h" +#include "llvm-c/Error.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN @@ -181,6 +181,15 @@ typedef struct { */ typedef LLVMOrcCDependenceMapPair *LLVMOrcCDependenceMapPairs; +/** + * A set of symbols that share dependencies. + */ +typedef struct { + LLVMOrcCSymbolsList Symbols; + LLVMOrcCDependenceMapPairs Dependencies; + size_t NumDependencies; +} LLVMOrcCSymbolDependenceGroup; + /** * Lookup kind. This can be used by definition generators when deciding whether * to produce a definition for a requested symbol. @@ -808,6 +817,19 @@ LLVMErrorRef LLVMOrcMaterializationResponsibilityNotifyResolved( * that all symbols covered by this MaterializationResponsibility instance * have been emitted. * + * This function takes ownership of the symbols in the Dependencies struct. + * This allows the following pattern... + * + * LLVMOrcSymbolStringPoolEntryRef Names[] = {...}; + * LLVMOrcCDependenceMapPair Dependence = {JD, {Names, sizeof(Names)}} + * LLVMOrcMaterializationResponsibilityAddDependencies(JD, Name, &Dependence, + * 1); + * + * ... without requiring cleanup of the elements of the Names array afterwards. + * + * The client is still responsible for deleting the Dependencies.Names arrays, + * and the Dependencies array itself. + * * This method will return an error if any symbols being resolved have been * moved to the error state due to the failure of a dependency. If this * method returns an error then clients should log it and call @@ -817,7 +839,8 @@ LLVMErrorRef LLVMOrcMaterializationResponsibilityNotifyResolved( * LLVMErrorSuccess. */ LLVMErrorRef LLVMOrcMaterializationResponsibilityNotifyEmitted( - LLVMOrcMaterializationResponsibilityRef MR); + LLVMOrcMaterializationResponsibilityRef MR, + LLVMOrcCSymbolDependenceGroup *SymbolDepGroups, size_t NumSymbolDepGroups); /** * Attempt to claim responsibility for new definitions. This method can be @@ -870,38 +893,6 @@ LLVMErrorRef LLVMOrcMaterializationResponsibilityDelegate( LLVMOrcSymbolStringPoolEntryRef *Symbols, size_t NumSymbols, LLVMOrcMaterializationResponsibilityRef *Result); -/** - * Adds dependencies to a symbol that the MaterializationResponsibility is - * responsible for. - * - * This function takes ownership of Dependencies struct. The Names - * array have been retained for this function. This allows the following - * pattern... - * - * LLVMOrcSymbolStringPoolEntryRef Names[] = {...}; - * LLVMOrcCDependenceMapPair Dependence = {JD, {Names, sizeof(Names)}} - * LLVMOrcMaterializationResponsibilityAddDependencies(JD, Name, &Dependence, - * 1); - * - * ... without requiring cleanup of the elements of the Names array afterwards. - * - * The client is still responsible for deleting the Dependencies.Names array - * itself. - */ -void LLVMOrcMaterializationResponsibilityAddDependencies( - LLVMOrcMaterializationResponsibilityRef MR, - LLVMOrcSymbolStringPoolEntryRef Name, - LLVMOrcCDependenceMapPairs Dependencies, size_t NumPairs); - -/** - * Adds dependencies to all symbols that the MaterializationResponsibility is - * responsible for. See LLVMOrcMaterializationResponsibilityAddDependencies for - * notes about memory responsibility. - */ -void LLVMOrcMaterializationResponsibilityAddDependenciesForAll( - LLVMOrcMaterializationResponsibilityRef MR, - LLVMOrcCDependenceMapPairs Dependencies, size_t NumPairs); - /** * Create a "bare" JITDylib. * diff --git a/src/llvm-c/OrcEE.h b/src/llvm-c/OrcEE.h index aef24c7aa..d451187aa 100644 --- a/src/llvm-c/OrcEE.h +++ b/src/llvm-c/OrcEE.h @@ -24,11 +24,11 @@ #ifndef LLVM_C_ORCEE_H #define LLVM_C_ORCEE_H -#include "Error.h" -#include "ExecutionEngine.h" -#include "Orc.h" -#include "TargetMachine.h" -#include "Types.h" +#include "llvm-c/Error.h" +#include "llvm-c/ExecutionEngine.h" +#include "llvm-c/Orc.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Remarks.h b/src/llvm-c/Remarks.h index 548a4041a..ffe647a65 100644 --- a/src/llvm-c/Remarks.h +++ b/src/llvm-c/Remarks.h @@ -15,8 +15,8 @@ #ifndef LLVM_C_REMARKS_H #define LLVM_C_REMARKS_H -#include "ExternC.h" -#include "Types.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" #ifdef __cplusplus #include #else diff --git a/src/llvm-c/Support.h b/src/llvm-c/Support.h index 31a75354c..17657861b 100644 --- a/src/llvm-c/Support.h +++ b/src/llvm-c/Support.h @@ -14,9 +14,9 @@ #ifndef LLVM_C_SUPPORT_H #define LLVM_C_SUPPORT_H -#include "DataTypes.h" -#include "ExternC.h" -#include "Types.h" +#include "llvm-c/DataTypes.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Target.h b/src/llvm-c/Target.h index 4d03741c4..54367a41b 100644 --- a/src/llvm-c/Target.h +++ b/src/llvm-c/Target.h @@ -19,9 +19,9 @@ #ifndef LLVM_C_TARGET_H #define LLVM_C_TARGET_H -#include "ExternC.h" -#include "Types.h" -#include "Config/llvm-config.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Types.h" +#include "llvm-c/Config/llvm-config.h" LLVM_C_EXTERN_C_BEGIN @@ -40,34 +40,34 @@ typedef struct LLVMOpaqueTargetLibraryInfotData *LLVMTargetLibraryInfoRef; /* Declare all of the target-initialization functions that are available. */ #define LLVM_TARGET(TargetName) \ void LLVMInitialize##TargetName##TargetInfo(void); -#include "Config/Targets.def" +#include "llvm-c/Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ #define LLVM_TARGET(TargetName) void LLVMInitialize##TargetName##Target(void); -#include "Config/Targets.def" +#include "llvm-c/Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ #define LLVM_TARGET(TargetName) \ void LLVMInitialize##TargetName##TargetMC(void); -#include "Config/Targets.def" +#include "llvm-c/Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ /* Declare all of the available assembly printer initialization functions. */ #define LLVM_ASM_PRINTER(TargetName) \ void LLVMInitialize##TargetName##AsmPrinter(void); -#include "Config/AsmPrinters.def" +#include "llvm-c/Config/AsmPrinters.def" #undef LLVM_ASM_PRINTER /* Explicit undef to make SWIG happier */ /* Declare all of the available assembly parser initialization functions. */ #define LLVM_ASM_PARSER(TargetName) \ void LLVMInitialize##TargetName##AsmParser(void); -#include "Config/AsmParsers.def" +#include "llvm-c/Config/AsmParsers.def" #undef LLVM_ASM_PARSER /* Explicit undef to make SWIG happier */ /* Declare all of the available disassembler initialization functions. */ #define LLVM_DISASSEMBLER(TargetName) \ void LLVMInitialize##TargetName##Disassembler(void); -#include "Config/Disassemblers.def" +#include "llvm-c/Config/Disassemblers.def" #undef LLVM_DISASSEMBLER /* Explicit undef to make SWIG happier */ /** LLVMInitializeAllTargetInfos - The main program should call this function if @@ -75,7 +75,7 @@ typedef struct LLVMOpaqueTargetLibraryInfotData *LLVMTargetLibraryInfoRef; support. */ static inline void LLVMInitializeAllTargetInfos(void) { #define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##TargetInfo(); -#include "Config/Targets.def" +#include "llvm-c/Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ } @@ -84,7 +84,7 @@ static inline void LLVMInitializeAllTargetInfos(void) { support. */ static inline void LLVMInitializeAllTargets(void) { #define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##Target(); -#include "Config/Targets.def" +#include "llvm-c/Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ } @@ -93,7 +93,7 @@ static inline void LLVMInitializeAllTargets(void) { support. */ static inline void LLVMInitializeAllTargetMCs(void) { #define LLVM_TARGET(TargetName) LLVMInitialize##TargetName##TargetMC(); -#include "Config/Targets.def" +#include "llvm-c/Config/Targets.def" #undef LLVM_TARGET /* Explicit undef to make SWIG happier */ } @@ -102,7 +102,7 @@ static inline void LLVMInitializeAllTargetMCs(void) { available via the TargetRegistry. */ static inline void LLVMInitializeAllAsmPrinters(void) { #define LLVM_ASM_PRINTER(TargetName) LLVMInitialize##TargetName##AsmPrinter(); -#include "Config/AsmPrinters.def" +#include "llvm-c/Config/AsmPrinters.def" #undef LLVM_ASM_PRINTER /* Explicit undef to make SWIG happier */ } @@ -111,7 +111,7 @@ static inline void LLVMInitializeAllAsmPrinters(void) { available via the TargetRegistry. */ static inline void LLVMInitializeAllAsmParsers(void) { #define LLVM_ASM_PARSER(TargetName) LLVMInitialize##TargetName##AsmParser(); -#include "Config/AsmParsers.def" +#include "llvm-c/Config/AsmParsers.def" #undef LLVM_ASM_PARSER /* Explicit undef to make SWIG happier */ } @@ -121,7 +121,7 @@ static inline void LLVMInitializeAllAsmParsers(void) { static inline void LLVMInitializeAllDisassemblers(void) { #define LLVM_DISASSEMBLER(TargetName) \ LLVMInitialize##TargetName##Disassembler(); -#include "Config/Disassemblers.def" +#include "llvm-c/Config/Disassemblers.def" #undef LLVM_DISASSEMBLER /* Explicit undef to make SWIG happier */ } @@ -244,7 +244,7 @@ LLVMTypeRef LLVMIntPtrTypeInContext(LLVMContextRef C, LLVMTargetDataRef TD); LLVMTypeRef LLVMIntPtrTypeForASInContext(LLVMContextRef C, LLVMTargetDataRef TD, unsigned AS); -/** Computes the size of a type in bytes for a target. +/** Computes the size of a type in bits for a target. See the method llvm::DataLayout::getTypeSizeInBits. */ unsigned long long LLVMSizeOfTypeInBits(LLVMTargetDataRef TD, LLVMTypeRef Ty); diff --git a/src/llvm-c/TargetMachine.h b/src/llvm-c/TargetMachine.h index aa628e216..cbe891380 100644 --- a/src/llvm-c/TargetMachine.h +++ b/src/llvm-c/TargetMachine.h @@ -19,9 +19,9 @@ #ifndef LLVM_C_TARGETMACHINE_H #define LLVM_C_TARGETMACHINE_H -#include "ExternC.h" -#include "Target.h" -#include "Types.h" +#include "llvm-c/ExternC.h" +#include "llvm-c/Target.h" +#include "llvm-c/Types.h" LLVM_C_EXTERN_C_BEGIN diff --git a/src/llvm-c/Transforms/PassBuilder.h b/src/llvm-c/Transforms/PassBuilder.h index 8ad2a9982..d297b57ca 100644 --- a/src/llvm-c/Transforms/PassBuilder.h +++ b/src/llvm-c/Transforms/PassBuilder.h @@ -14,9 +14,9 @@ #ifndef LLVM_C_TRANSFORMS_PASSBUILDER_H #define LLVM_C_TRANSFORMS_PASSBUILDER_H -#include "../Error.h" -#include "../TargetMachine.h" -#include "../Types.h" +#include "llvm-c/Error.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Types.h" /** * @defgroup LLVMCCoreNewPM New Pass Manager @@ -50,6 +50,16 @@ LLVMErrorRef LLVMRunPasses(LLVMModuleRef M, const char *Passes, LLVMTargetMachineRef TM, LLVMPassBuilderOptionsRef Options); +/** + * Construct and run a set of passes over a function. + * + * This function behaves the same as LLVMRunPasses, but operates on a single + * function instead of an entire module. + */ +LLVMErrorRef LLVMRunPassesOnFunction(LLVMValueRef F, const char *Passes, + LLVMTargetMachineRef TM, + LLVMPassBuilderOptionsRef Options); + /** * Create a new set of options for a PassBuilder * @@ -72,6 +82,14 @@ void LLVMPassBuilderOptionsSetVerifyEach(LLVMPassBuilderOptionsRef Options, void LLVMPassBuilderOptionsSetDebugLogging(LLVMPassBuilderOptionsRef Options, LLVMBool DebugLogging); +/** + * Specify a custom alias analysis pipeline for the PassBuilder to be used + * instead of the default one. The string argument is not copied; the caller + * is responsible for ensuring it outlives the PassBuilderOptions instance. + */ +void LLVMPassBuilderOptionsSetAAPipeline(LLVMPassBuilderOptionsRef Options, + const char *AAPipeline); + void LLVMPassBuilderOptionsSetLoopInterleaving( LLVMPassBuilderOptionsRef Options, LLVMBool LoopInterleaving); diff --git a/src/llvm-c/Types.h b/src/llvm-c/Types.h index 77aa7c9b4..4681500ef 100644 --- a/src/llvm-c/Types.h +++ b/src/llvm-c/Types.h @@ -14,8 +14,8 @@ #ifndef LLVM_C_TYPES_H #define LLVM_C_TYPES_H -#include "DataTypes.h" -#include "ExternC.h" +#include "llvm-c/DataTypes.h" +#include "llvm-c/ExternC.h" LLVM_C_EXTERN_C_BEGIN @@ -169,6 +169,11 @@ typedef struct LLVMOpaqueJITEventListener *LLVMJITEventListenerRef; */ typedef struct LLVMOpaqueBinary *LLVMBinaryRef; +/** + * @see llvm::DbgRecord + */ +typedef struct LLVMOpaqueDbgRecord *LLVMDbgRecordRef; + /** * @} */ diff --git a/src/llvm-c/lto.h b/src/llvm-c/lto.h index 89f76c695..5ceb02224 100644 --- a/src/llvm-c/lto.h +++ b/src/llvm-c/lto.h @@ -16,7 +16,7 @@ #ifndef LLVM_C_LTO_H #define LLVM_C_LTO_H -#include "ExternC.h" +#include "llvm-c/ExternC.h" #ifdef __cplusplus #include diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 0b2bb7956..9f2faaa08 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -256,8 +256,10 @@ gb_internal i64 lb_sizeof(LLVMTypeRef type) { } break; +#if LLVM_VERSION_MAJOR < 20 case LLVMX86_MMXTypeKind: return 8; +#endif case LLVMVectorTypeKind: { LLVMTypeRef elem = OdinLLVMGetVectorElementType(type); @@ -310,8 +312,10 @@ gb_internal i64 lb_alignof(LLVMTypeRef type) { case LLVMArrayTypeKind: return lb_alignof(OdinLLVMGetArrayElementType(type)); +#if LLVM_VERSION_MAJOR < 20 case LLVMX86_MMXTypeKind: return 8; +#endif case LLVMVectorTypeKind: { // TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation @@ -518,11 +522,30 @@ namespace lbAbiAmd64Win64 { } }; + +gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) { + if (!lb_is_type_kind(type, LLVMStructTypeKind)) { + return false; + } + if (LLVMCountStructElementTypes(type) != 2) { + return false; + } + LLVMTypeRef fields[2] = {}; + LLVMGetStructElementTypes(type, fields); + if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) { + return false; + } + return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8; + +} + // NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything namespace lbAbiAmd64SysV { enum RegClass { RegClass_NoClass, RegClass_Int, + RegClass_SSEHs, + RegClass_SSEHv, RegClass_SSEFs, RegClass_SSEFv, RegClass_SSEDs, @@ -541,6 +564,8 @@ namespace lbAbiAmd64SysV { gb_internal bool is_sse(RegClass reg_class) { switch (reg_class) { + case RegClass_SSEHs: + case RegClass_SSEHv: case RegClass_SSEFs: case RegClass_SSEFv: case RegClass_SSEDs: @@ -569,7 +594,9 @@ namespace lbAbiAmd64SysV { gb_internal void classify_with(LLVMTypeRef t, Array *cls, i64 ix, i64 off); gb_internal void fixup(LLVMTypeRef t, Array *cls); - gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention); + gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention, + bool is_arg, + i32 *int_regs, i32 *sse_regs); gb_internal Array classify(LLVMTypeRef t); gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array const ®_classes, LLVMTypeRef type); @@ -579,7 +606,9 @@ namespace lbAbiAmd64SysV { } LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO(); - return amd64_type(c, return_type, Amd64TypeAttribute_StructRect, ft->calling_convention); + return amd64_type(c, return_type, Amd64TypeAttribute_StructRect, ft->calling_convention, + false, + nullptr, nullptr); } gb_internal LB_ABI_INFO(abi_info) { @@ -588,10 +617,16 @@ namespace lbAbiAmd64SysV { ft->ctx = c; ft->calling_convention = calling_convention; + i32 int_regs = 6; // rdi, rsi, rdx, rcx, r8, r9 + i32 sse_regs = 8; // xmm0-xmm7 + ft->args = array_make(lb_function_type_args_allocator(), arg_count); for (unsigned i = 0; i < arg_count; i++) { - ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention); + ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention, + true, + &int_regs, &sse_regs); } + ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple); return ft; @@ -634,33 +669,80 @@ namespace lbAbiAmd64SysV { return false; } - gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) { - if (!lb_is_type_kind(type, LLVMStructTypeKind)) { - return false; + gb_internal bool is_aggregate(LLVMTypeRef type) { + LLVMTypeKind kind = LLVMGetTypeKind(type); + switch (kind) { + case LLVMStructTypeKind: + if (LLVMCountStructElementTypes(type) == 1) { + return is_aggregate(LLVMStructGetTypeAtIndex(type, 0)); + } + return true; + case LLVMArrayTypeKind: + if (LLVMGetArrayLength(type) == 1) { + return is_aggregate(LLVMGetElementType(type)); + } + return true; } - if (LLVMCountStructElementTypes(type) != 2) { - return false; - } - LLVMTypeRef fields[2] = {}; - LLVMGetStructElementTypes(type, fields); - if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) { - return false; - } - return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8; + return false; + }; - } + gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention, + bool is_arg, + i32 *int_regs, i32 *sse_regs) { + auto cls = classify(type); + i32 needed_int = 0; + i32 needed_sse = 0; + for (auto c : cls) { + switch (c) { + case RegClass_Int: + needed_int += 1; + break; + case RegClass_SSEHs: + case RegClass_SSEHv: + case RegClass_SSEFs: + case RegClass_SSEFv: + case RegClass_SSEDs: + case RegClass_SSEDv: + case RegClass_SSEInt8: + case RegClass_SSEInt16: + case RegClass_SSEInt32: + case RegClass_SSEInt64: + case RegClass_SSEInt128: + case RegClass_SSEUp: + needed_sse += 1; + break; + } + } + + bool ran_out_of_regs = false; + if (int_regs && sse_regs) { + *int_regs -= needed_int; + *sse_regs -= needed_sse; + bool int_ok = *int_regs >= 0; + bool sse_ok = *sse_regs >= 0; + + *int_regs = gb_max(*int_regs, 0); + *sse_regs = gb_max(*sse_regs, 0); + + if ((!int_ok || !sse_ok) && is_aggregate(type)) { + ran_out_of_regs = true; + } + } - gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention) { if (is_register(type)) { LLVMAttributeRef attribute = nullptr; if (type == LLVMInt1TypeInContext(c)) { attribute = lb_create_enum_attribute(c, "zeroext"); } return lb_arg_type_direct(type, nullptr, nullptr, attribute); - } - - auto cls = classify(type); - if (is_mem_cls(cls, attribute_kind)) { + } else if (ran_out_of_regs) { + if (is_arg) { + return lb_arg_type_indirect_byval(c, type); + } else { + LLVMAttributeRef attribute = lb_create_enum_attribute_with_type(c, "sret", type); + return lb_arg_type_indirect(type, attribute); + } + } else if (is_mem_cls(cls, attribute_kind)) { LLVMAttributeRef attribute = nullptr; if (attribute_kind == Amd64TypeAttribute_ByVal) { if (is_calling_convention_odin(calling_convention)) { @@ -728,6 +810,8 @@ namespace lbAbiAmd64SysV { to_write = RegClass_Memory; } else if (newv == RegClass_SSEUp) { switch (oldv) { + case RegClass_SSEHv: + case RegClass_SSEHs: case RegClass_SSEFv: case RegClass_SSEFs: case RegClass_SSEDv: @@ -774,14 +858,18 @@ namespace lbAbiAmd64SysV { } else if (oldv == RegClass_SSEUp) { oldv = RegClass_SSEDv; } else if (is_sse(oldv)) { - i++; - while (i != e && oldv == RegClass_SSEUp) { - i++; + for (i++; i < e; i++) { + RegClass v = (*cls)[cast(isize)i]; + if (v != RegClass_SSEUp) { + break; + } } } else if (oldv == RegClass_X87) { - i++; - while (i != e && oldv == RegClass_X87Up) { - i++; + for (i++; i < e; i++) { + RegClass v = (*cls)[cast(isize)i]; + if (v != RegClass_X87Up) { + break; + } } } else { i++; @@ -838,6 +926,7 @@ namespace lbAbiAmd64SysV { sz -= rs; break; } + case RegClass_SSEHv: case RegClass_SSEFv: case RegClass_SSEDv: case RegClass_SSEInt8: @@ -848,6 +937,10 @@ namespace lbAbiAmd64SysV { unsigned elems_per_word = 0; LLVMTypeRef elem_type = nullptr; switch (reg_class) { + case RegClass_SSEHv: + elems_per_word = 4; + elem_type = LLVMHalfTypeInContext(c); + break; case RegClass_SSEFv: elems_per_word = 2; elem_type = LLVMFloatTypeInContext(c); @@ -882,6 +975,10 @@ namespace lbAbiAmd64SysV { continue; } break; + case RegClass_SSEHs: + array_add(&types, LLVMHalfTypeInContext(c)); + sz -= 2; + break; case RegClass_SSEFs: array_add(&types, LLVMFloatTypeInContext(c)); sz -= 4; @@ -901,7 +998,7 @@ namespace lbAbiAmd64SysV { return types[0]; } - return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, sz == 0); + return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false); } gb_internal void classify_with(LLVMTypeRef t, Array *cls, i64 ix, i64 off) { @@ -928,9 +1025,11 @@ namespace lbAbiAmd64SysV { break; } case LLVMPointerTypeKind: - case LLVMHalfTypeKind: unify(cls, ix + off/8, RegClass_Int); break; + case LLVMHalfTypeKind: + unify(cls, ix + off/8, (off%8 != 0) ? RegClass_SSEHv : RegClass_SSEHs); + break; case LLVMFloatTypeKind: unify(cls, ix + off/8, (off%8 == 4) ? RegClass_SSEFv : RegClass_SSEFs); break; @@ -970,10 +1069,9 @@ namespace lbAbiAmd64SysV { i64 elem_sz = lb_sizeof(elem); LLVMTypeKind elem_kind = LLVMGetTypeKind(elem); RegClass reg = RegClass_NoClass; - unsigned elem_width = LLVMGetIntTypeWidth(elem); switch (elem_kind) { - case LLVMIntegerTypeKind: - case LLVMHalfTypeKind: + case LLVMIntegerTypeKind: { + unsigned elem_width = LLVMGetIntTypeWidth(elem); switch (elem_width) { case 8: reg = RegClass_SSEInt8; break; case 16: reg = RegClass_SSEInt16; break; @@ -989,6 +1087,10 @@ namespace lbAbiAmd64SysV { GB_PANIC("Unhandled integer width for vector type %u", elem_width); } break; + }; + case LLVMHalfTypeKind: + reg = RegClass_SSEHv; + break; case LLVMFloatTypeKind: reg = RegClass_SSEFv; break; @@ -1155,38 +1257,24 @@ namespace lbAbiArm64 { } } else { i64 size = lb_sizeof(return_type); - if (size <= 16) { - LLVMTypeRef cast_type = nullptr; - - if (size == 0) { - cast_type = LLVMStructTypeInContext(c, nullptr, 0, false); - } else if (size <= 8) { - cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8)); - } else { - unsigned count = cast(unsigned)((size+7)/8); - - LLVMTypeRef llvm_i64 = LLVMIntTypeInContext(c, 64); - LLVMTypeRef *types = gb_alloc_array(temporary_allocator(), LLVMTypeRef, count); - - i64 size_copy = size; - for (unsigned i = 0; i < count; i++) { - if (size_copy >= 8) { - types[i] = llvm_i64; - } else { - types[i] = LLVMIntTypeInContext(c, 8*cast(unsigned)size_copy); - } - size_copy -= 8; - } - GB_ASSERT(size_copy <= 0); - cast_type = LLVMStructTypeInContext(c, types, count, true); - } - return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr); - } else { + if (size > 16) { LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO(); LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type); return lb_arg_type_indirect(return_type, attr); } + + GB_ASSERT(size <= 16); + LLVMTypeRef cast_type = nullptr; + if (size == 0) { + cast_type = LLVMStructTypeInContext(c, nullptr, 0, false); + } else if (size <= 8) { + cast_type = LLVMIntTypeInContext(c, cast(unsigned)(size*8)); + } else { + LLVMTypeRef llvm_i64 = LLVMIntTypeInContext(c, 64); + cast_type = llvm_array_type(llvm_i64, 2); + } + return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr); } } @@ -1251,7 +1339,7 @@ namespace lbAbiWasm { registers/arguments if possible rather than by pointer. */ gb_internal Array compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention, Type *original_type); - gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type); + gb_internal lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type); enum {MAX_DIRECT_STRUCT_SIZE = 32}; @@ -1261,7 +1349,9 @@ namespace lbAbiWasm { ft->ctx = c; ft->calling_convention = calling_convention; ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention, original_type); - ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple); + + GB_ASSERT(original_type->kind == Type_Proc); + ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple, original_type->Proc.results); return ft; } @@ -1297,7 +1387,7 @@ namespace lbAbiWasm { return false; } - gb_internal bool type_can_be_direct(LLVMTypeRef type, ProcCallingConvention calling_convention) { + gb_internal bool type_can_be_direct(LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) { LLVMTypeKind kind = LLVMGetTypeKind(type); i64 sz = lb_sizeof(type); if (sz == 0) { @@ -1310,9 +1400,21 @@ namespace lbAbiWasm { return false; } else if (kind == LLVMStructTypeKind) { unsigned count = LLVMCountStructElementTypes(type); - if (count == 1) { - return type_can_be_direct(LLVMStructGetTypeAtIndex(type, 0), calling_convention); + + // NOTE(laytan): raw unions are always structs with 1 field in LLVM, need to check our own def. + Type *bt = base_type(original_type); + if (bt->kind == Type_Struct && bt->Struct.is_raw_union) { + count = cast(unsigned)bt->Struct.fields.count; } + + if (count == 1) { + return type_can_be_direct( + LLVMStructGetTypeAtIndex(type, 0), + type_internal_index(original_type, 0), + calling_convention + ); + } + } else if (is_basic_register_type(type)) { return true; } @@ -1336,7 +1438,7 @@ namespace lbAbiWasm { return false; } - gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) { + gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) { LLVMTypeKind kind = LLVMGetTypeKind(type); GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind); @@ -1344,15 +1446,15 @@ namespace lbAbiWasm { if (sz == 0) { return lb_arg_type_ignore(type); } - if (type_can_be_direct(type, calling_convention)) { + if (type_can_be_direct(type, original_type, calling_convention)) { return lb_arg_type_direct(type); } return lb_arg_type_indirect(type, nullptr); } - gb_internal lbArgType pseudo_slice(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) { + gb_internal lbArgType pseudo_slice(LLVMContextRef c, LLVMTypeRef type, Type *original_type, ProcCallingConvention calling_convention) { if (build_context.metrics.ptr_size < build_context.metrics.int_size && - type_can_be_direct(type, calling_convention)) { + type_can_be_direct(type, original_type, calling_convention)) { LLVMTypeRef types[2] = { LLVMStructGetTypeAtIndex(type, 0), // ignore padding @@ -1361,7 +1463,7 @@ namespace lbAbiWasm { LLVMTypeRef new_type = LLVMStructTypeInContext(c, types, gb_count_of(types), false); return lb_arg_type_direct(type, new_type, nullptr, nullptr); } else { - return is_struct(c, type, calling_convention); + return is_struct(c, type, original_type, calling_convention); } } @@ -1382,9 +1484,9 @@ namespace lbAbiWasm { LLVMTypeKind kind = LLVMGetTypeKind(t); if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) { if (is_type_slice(ptype) || is_type_string(ptype)) { - args[i] = pseudo_slice(c, t, calling_convention); + args[i] = pseudo_slice(c, t, ptype, calling_convention); } else { - args[i] = is_struct(c, t, calling_convention); + args[i] = is_struct(c, t, ptype, calling_convention); } } else { args[i] = non_struct(c, t, false); @@ -1393,11 +1495,11 @@ namespace lbAbiWasm { return args; } - gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) { + gb_internal lbArgType compute_return_type(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, Type* original_type) { if (!return_is_defined) { return lb_arg_type_direct(LLVMVoidTypeInContext(c)); } else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) { - if (type_can_be_direct(return_type, ft->calling_convention)) { + if (type_can_be_direct(return_type, original_type, ft->calling_convention)) { return lb_arg_type_direct(return_type); } else if (ft->calling_convention != ProcCC_CDecl) { i64 sz = lb_sizeof(return_type); @@ -1409,7 +1511,35 @@ namespace lbAbiWasm { } } - LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO(); + // Multiple returns. + if (return_is_tuple) { \ + lbArgType return_arg = {}; + if (lb_is_type_kind(return_type, LLVMStructTypeKind)) { + unsigned field_count = LLVMCountStructElementTypes(return_type); + if (field_count > 1) { + ft->original_arg_count = ft->args.count; + ft->multiple_return_original_type = return_type; + + for (unsigned i = 0; i < field_count-1; i++) { + LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(return_type, i); + LLVMTypeRef field_pointer_type = LLVMPointerType(field_type, 0); + lbArgType ret_partial = lb_arg_type_direct(field_pointer_type); + array_add(&ft->args, ret_partial); + } + + return_arg = compute_return_type( + ft, + c, + LLVMStructGetTypeAtIndex(return_type, field_count-1), + true, false, + type_internal_index(original_type, field_count-1) + ); + } + } + if (return_arg.type != nullptr) { + return return_arg; + } + } LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type); return lb_arg_type_indirect(return_type, attr); @@ -1814,7 +1944,8 @@ gb_internal LB_ABI_INFO(lb_get_abi_info) { return_type, return_is_defined, ALLOW_SPLIT_MULTI_RETURNS && return_is_tuple && is_calling_convention_odin(calling_convention), calling_convention, - base_type(original_type)); + base_type(original_type) + ); // NOTE(bill): this is handled here rather than when developing the type in `lb_type_internal_for_procedures_raw` diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 88e099930..921084250 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -8,7 +8,11 @@ #endif #ifndef LLVM_IGNORE_VERIFICATION -#define LLVM_IGNORE_VERIFICATION 0 +#define LLVM_IGNORE_VERIFICATION build_context.internal_ignore_llvm_verification +#endif + +#ifndef LLVM_WEAK_MONOMORPHIZATION +#define LLVM_WEAK_MONOMORPHIZATION (USE_SEPARATE_MODULES && build_context.internal_weak_monomorphization) #endif @@ -242,26 +246,12 @@ gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type return proc_name; } - -gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { - type = base_type(type); - GB_ASSERT(is_type_comparable(type)); +gb_internal void lb_equal_proc_generate_body(lbModule *m, lbProcedure *p) { + Type *type = p->internal_gen_type; Type *pt = alloc_type_pointer(type); LLVMTypeRef ptr_type = lb_type(m, pt); - String proc_name = lb_internal_gen_name_from_type("__$equal", type); - lbProcedure **found = string_map_get(&m->gen_procs, proc_name); - lbProcedure *compare_proc = nullptr; - if (found) { - compare_proc = *found; - GB_ASSERT(compare_proc != nullptr); - return {compare_proc->value, compare_proc->type}; - } - - - lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); - string_map_set(&m->gen_procs, proc_name, p); lb_begin_procedure_body(p); LLVMSetLinkage(p->value, LLVMInternalLinkage); @@ -389,9 +379,29 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { } lb_end_procedure_body(p); +} - compare_proc = p; - return {compare_proc->value, compare_proc->type}; +gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) { + type = base_type(type); + GB_ASSERT(is_type_comparable(type)); + + String proc_name = lb_internal_gen_name_from_type("__$equal", type); + lbProcedure **found = string_map_get(&m->gen_procs, proc_name); + if (found) { + lbProcedure *p = *found; + GB_ASSERT(p != nullptr); + return {p->value, p->type}; + } + + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); + string_map_set(&m->gen_procs, proc_name, p); + p->internal_gen_type = type; + p->generate_body = lb_equal_proc_generate_body; + + // p->generate_body(m, p); + mpsc_enqueue(&m->procedures_to_generate, p); + + return {p->value, p->type}; } gb_internal lbValue lb_simple_compare_hash(lbProcedure *p, Type *type, lbValue data, lbValue seed) { @@ -563,6 +573,53 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) { lbValue res = lb_emit_runtime_call(p, "default_hasher_string", args); lb_add_callsite_force_inline(p, res); LLVMBuildRet(p->builder, res.value); + } else if (is_type_float(type)) { + lbValue ptr = lb_emit_conv(p, data, pt); + lbValue v = lb_emit_load(p, ptr); + v = lb_emit_conv(p, v, t_f64); + + auto args = array_make(temporary_allocator(), 2); + args[0] = v; + args[1] = seed; + lbValue res = lb_emit_runtime_call(p, "default_hasher_f64", args); + lb_add_callsite_force_inline(p, res); + LLVMBuildRet(p->builder, res.value); + } else if (is_type_complex(type)) { + lbValue ptr = lb_emit_conv(p, data, pt); + lbValue xp = lb_emit_struct_ep(p, ptr, 0); + lbValue yp = lb_emit_struct_ep(p, ptr, 1); + + lbValue x = lb_emit_conv(p, lb_emit_load(p, xp), t_f64); + lbValue y = lb_emit_conv(p, lb_emit_load(p, yp), t_f64); + + auto args = array_make(temporary_allocator(), 3); + args[0] = x; + args[1] = y; + args[2] = seed; + lbValue res = lb_emit_runtime_call(p, "default_hasher_complex128", args); + lb_add_callsite_force_inline(p, res); + LLVMBuildRet(p->builder, res.value); + } else if (is_type_quaternion(type)) { + lbValue ptr = lb_emit_conv(p, data, pt); + lbValue xp = lb_emit_struct_ep(p, ptr, 0); + lbValue yp = lb_emit_struct_ep(p, ptr, 1); + lbValue zp = lb_emit_struct_ep(p, ptr, 2); + lbValue wp = lb_emit_struct_ep(p, ptr, 3); + + lbValue x = lb_emit_conv(p, lb_emit_load(p, xp), t_f64); + lbValue y = lb_emit_conv(p, lb_emit_load(p, yp), t_f64); + lbValue z = lb_emit_conv(p, lb_emit_load(p, zp), t_f64); + lbValue w = lb_emit_conv(p, lb_emit_load(p, wp), t_f64); + + auto args = array_make(temporary_allocator(), 5); + args[0] = x; + args[1] = y; + args[2] = z; + args[3] = w; + args[4] = seed; + lbValue res = lb_emit_runtime_call(p, "default_hasher_quaternion256", args); + lb_add_callsite_force_inline(p, res); + LLVMBuildRet(p->builder, res.value); } else { GB_PANIC("Unhandled type for hasher: %s", type_to_string(type)); } @@ -573,6 +630,7 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) { #define LLVM_SET_VALUE_NAME(value, name) LLVMSetValueName2((value), (name), gb_count_of((name))-1); + gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { GB_ASSERT(!build_context.dynamic_map_calls); type = base_type(type); @@ -587,6 +645,9 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) { lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_get_proc); string_map_set(&m->gen_procs, proc_name, p); + + p->internal_gen_type = type; + lb_begin_procedure_body(p); defer (lb_end_procedure_body(p)); @@ -1106,15 +1167,6 @@ gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_pt return lb_emit_runtime_call(p, "__dynamic_map_reserve", args); } - -struct lbGlobalVariable { - lbValue var; - lbValue init; - DeclInfo *decl; - bool is_initialized; -}; - - gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) { if (build_context.metrics.os != TargetOs_darwin) { return nullptr; @@ -1126,30 +1178,763 @@ gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) { return p; } -gb_internal void lb_finalize_objc_names(lbProcedure *p) { +String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) { + // NOTE(harold): See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100 + + // NOTE(harold): Darwin targets are always 64-bit. Should we drop this and assume "q" always? + #define INT_SIZE_ENCODING (build_context.metrics.int_size == 4 ? "i" : "q") + switch (t->kind) { + case Type_Basic: { + switch (t->Basic.kind) { + case Basic_Invalid: + return str_lit("?"); + + case Basic_llvm_bool: + case Basic_bool: + case Basic_b8: + return str_lit("B"); + + case Basic_b16: + return str_lit("C"); + case Basic_b32: + return str_lit("I"); + case Basic_b64: + return str_lit("q"); + case Basic_i8: + return str_lit("c"); + case Basic_u8: + return str_lit("C"); + case Basic_i16: + case Basic_i16le: + case Basic_i16be: + return str_lit("s"); + case Basic_u16: + case Basic_u16le: + case Basic_u16be: + return str_lit("S"); + case Basic_i32: + case Basic_i32le: + case Basic_i32be: + return str_lit("i"); + case Basic_u32le: + case Basic_u32: + case Basic_u32be: + return str_lit("I"); + case Basic_i64: + case Basic_i64le: + case Basic_i64be: + return str_lit("q"); + case Basic_u64: + case Basic_u64le: + case Basic_u64be: + return str_lit("Q"); + case Basic_i128: + case Basic_i128le: + case Basic_i128be: + return str_lit("t"); + case Basic_u128: + case Basic_u128le: + case Basic_u128be: + return str_lit("T"); + case Basic_rune: + return str_lit("I"); + case Basic_f16: + case Basic_f16le: + case Basic_f16be: + return str_lit("s"); // @harold: Closest we've got? + case Basic_f32: + case Basic_f32le: + case Basic_f32be: + return str_lit("f"); + case Basic_f64: + case Basic_f64le: + case Basic_f64be: + return str_lit("d"); + + case Basic_complex32: return str_lit("{complex32=ss}"); // No f16 encoding, so fallback to i16, as above in Basic_f16* + case Basic_complex64: return str_lit("{complex64=ff}"); + case Basic_complex128: return str_lit("{complex128=dd}"); + case Basic_quaternion64: return str_lit("{quaternion64=ssss}"); + case Basic_quaternion128: return str_lit("{quaternion128=ffff}"); + case Basic_quaternion256: return str_lit("{quaternion256=dddd}"); + + case Basic_int: + return str_lit(INT_SIZE_ENCODING); + case Basic_uint: + return build_context.metrics.int_size == 4 ? str_lit("I") : str_lit("Q"); + case Basic_uintptr: + case Basic_rawptr: + return str_lit("^v"); + + case Basic_string: + return build_context.metrics.int_size == 4 ? str_lit("{string=*i}") : str_lit("{string=*q}"); + + case Basic_string16: + return build_context.metrics.int_size == 4 ? str_lit("{string16=*i}") : str_lit("{string16=*q}"); + + case Basic_cstring: return str_lit("*"); + case Basic_cstring16: return str_lit("*"); + + + case Basic_any: return str_lit("{any=^v^v}"); // rawptr + ^Type_Info + + case Basic_typeid: + GB_ASSERT(t->Basic.size == 8); + return str_lit("q"); + + // Untyped types + case Basic_UntypedBool: + case Basic_UntypedInteger: + case Basic_UntypedFloat: + case Basic_UntypedComplex: + case Basic_UntypedQuaternion: + case Basic_UntypedString: + case Basic_UntypedRune: + case Basic_UntypedNil: + case Basic_UntypedUninit: + GB_PANIC("Untyped types cannot be @encoded()"); + return str_lit("?"); + } + break; + } + + case Type_Named: + case Type_Struct: + case Type_Union: { + Type* base = t; + if (base->kind == Type_Named) { + base = base_type(base); + if(base->kind != Type_Struct && base->kind != Type_Union) { + return lb_get_objc_type_encoding(base, pointer_depth); + } + } + + const bool is_union = base->kind == Type_Union; + if (!is_union) { + // Treat struct as an Objective-C Class? + if (has_type_got_objc_class_attribute(t) && pointer_depth == 0) { + return str_lit("#"); + } + } + + if (is_type_objc_object(base)) { + return str_lit("@"); + } + + + gbString s = gb_string_make_reserve(temporary_allocator(), 16); + s = gb_string_append_length(s, is_union ? "(" :"{", 1); + if (t->kind == Type_Named) { + s = gb_string_append_length(s, t->Named.name.text, t->Named.name.len); + } + + // Write fields + if (pointer_depth < 2) { + s = gb_string_append_length(s, "=", 1); + + if (!is_union) { + for( auto& f : base->Struct.fields ) { + String field_type = lb_get_objc_type_encoding(f->type, pointer_depth); + s = gb_string_append_length(s, field_type.text, field_type.len); + } + } else { + for( auto& v : base->Union.variants ) { + String variant_type = lb_get_objc_type_encoding(v, pointer_depth); + s = gb_string_append_length(s, variant_type.text, variant_type.len); + } + } + } + + s = gb_string_append_length(s, is_union ? ")" :"}", 1); + + return make_string_c(s); + } + + case Type_Generic: + GB_PANIC("Generic types cannot be @encoded()"); + return str_lit("?"); + + case Type_Pointer: { + // NOTE: These types are pointers, so we must check here for special cases + // Check for objc_SEL + if (internal_check_is_assignable_to(t, t_objc_SEL)) { + return str_lit(":"); + } + + // Check for objc_Class + if (internal_check_is_assignable_to(t, t_objc_Class)) { + return str_lit("#"); + } + + String pointee = lb_get_objc_type_encoding(t->Pointer.elem, pointer_depth +1); + // Special case for Objective-C Objects + if (pointer_depth == 0 && pointee == "@") { + return pointee; + } + + return concatenate_strings(temporary_allocator(), str_lit("^"), pointee); + } + + case Type_MultiPointer: + return concatenate_strings(temporary_allocator(), str_lit("^"), lb_get_objc_type_encoding(t->Pointer.elem, pointer_depth +1)); + + case Type_Array: { + String type_str = lb_get_objc_type_encoding(t->Array.elem, pointer_depth); + + gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8); + s = gb_string_append_fmt(s, "[%lld%.*s]", t->Array.count, LIT(type_str)); + return make_string_c(s); + } + + case Type_EnumeratedArray: { + String type_str = lb_get_objc_type_encoding(t->EnumeratedArray.elem, pointer_depth); + + gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8); + s = gb_string_append_fmt(s, "[%lld%.*s]", t->EnumeratedArray.count, LIT(type_str)); + return make_string_c(s); + } + + case Type_Slice: { + String type_str = lb_get_objc_type_encoding(t->Slice.elem, pointer_depth); + gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8); + s = gb_string_append_fmt(s, "{slice=^%.*s%s}", LIT(type_str), INT_SIZE_ENCODING); + return make_string_c(s); + } + + case Type_DynamicArray: { + String type_str = lb_get_objc_type_encoding(t->DynamicArray.elem, pointer_depth); + gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 8); + s = gb_string_append_fmt(s, "{dynamic=^%.*s%s%sAllocator={?^v}}", LIT(type_str), INT_SIZE_ENCODING, INT_SIZE_ENCODING); + return make_string_c(s); + } + + case Type_Map: + return str_lit("{^v^v{Allocator=?^v}}"); + case Type_Enum: + return lb_get_objc_type_encoding(t->Enum.base_type, pointer_depth); + case Type_Tuple: + // NOTE(harold): Is this type allowed here? + return str_lit("?"); + case Type_Proc: + return str_lit("?"); + case Type_BitSet: { + Type *bitset_integer_type = t->BitSet.underlying; + if (!bitset_integer_type) { + switch (t->cached_size) { + case 1: bitset_integer_type = t_u8; break; + case 2: bitset_integer_type = t_u16; break; + case 4: bitset_integer_type = t_u32; break; + case 8: bitset_integer_type = t_u64; break; + case 16: bitset_integer_type = t_u128; break; + } + } + GB_ASSERT_MSG(bitset_integer_type, "Could not determine bit_set integer size for objc_type_encoding"); + + return lb_get_objc_type_encoding(bitset_integer_type, pointer_depth); + } + + case Type_SimdVector: { + String type_str = lb_get_objc_type_encoding(t->SimdVector.elem, pointer_depth); + gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 5); + gb_string_append_fmt(s, "[%lld%.*s]", t->SimdVector.count, LIT(type_str)); + return make_string_c(s); + } + + case Type_Matrix: { + String type_str = lb_get_objc_type_encoding(t->Matrix.elem, pointer_depth); + gbString s = gb_string_make_reserve(temporary_allocator(), type_str.len + 5); + i64 element_count = t->Matrix.column_count * t->Matrix.row_count; + gb_string_append_fmt(s, "[%lld%.*s]", element_count, LIT(type_str)); + return make_string_c(s); + } + + case Type_BitField: + return lb_get_objc_type_encoding(t->BitField.backing_type, pointer_depth); + case Type_SoaPointer: { + gbString s = gb_string_make_reserve(temporary_allocator(), 8); + s = gb_string_append_fmt(s, "{=^v%s}", INT_SIZE_ENCODING); + return make_string_c(s); + } + + } // End switch t->kind + #undef INT_SIZE_ENCODING + + GB_PANIC("Unreachable"); + return str_lit(""); +} + +struct lbObjCGlobalClass { + lbObjCGlobal g; + union { + lbValue class_value; // Local registered class value + lbAddr class_global; // Global class pointer. Placeholder for class implementations which are registered in order of definition. + }; +}; + +gb_internal void lb_register_objc_thing( + StringSet &handled, + lbModule *m, + Array &args, + Array &class_impls, + StringMap &class_map, + lbProcedure *p, + lbObjCGlobal const &g, + char const *call +) { + if (string_set_update(&handled, g.name)) { + return; + } + + lbAddr addr = {}; + lbValue *found = string_map_get(&m->members, g.global_name); + if (found) { + addr = lb_addr(*found); + } else { + lbValue v = {}; + LLVMTypeRef t = lb_type(m, g.type); + v.value = LLVMAddGlobal(m->mod, t, g.global_name); + v.type = alloc_type_pointer(g.type); + addr = lb_addr(v); + LLVMSetInitializer(v.value, LLVMConstNull(t)); + } + + // If this class requires an implementation, save it for registration below. + if (g.class_impl_type != nullptr) { + + // Make sure the superclass has been initialized before us + auto &tn = g.class_impl_type->Named.type_name->TypeName; + Type *superclass = tn.objc_superclass; + if (superclass != nullptr) { + auto& superclass_global = string_map_must_get(&class_map, superclass->Named.type_name->TypeName.objc_class_name); + lb_register_objc_thing(handled, m, args, class_impls, class_map, p, superclass_global.g, call); + GB_ASSERT(superclass_global.class_global.addr.value); + } + + lbObjCGlobalClass impl_global = {}; + impl_global.g = g; + impl_global.class_global = addr; + + array_add(&class_impls, impl_global); + + lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name); + if (class_global != nullptr) { + class_global->class_global = addr; + } + } + else { + lbValue class_ptr = {}; + lbValue class_name = lb_const_value(m, t_cstring, exact_value_string(g.name)); + + args.count = 1; + args[0] = class_name; + class_ptr = lb_emit_runtime_call(p, call, args); + + lb_addr_store(p, addr, class_ptr); + + lbObjCGlobalClass* class_global = string_map_get(&class_map, g.name); + if (class_global != nullptr) { + class_global->class_value = class_ptr; + } + } +} + +gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) { if (p == nullptr) { return; } lbModule *m = p->module; + GB_ASSERT(m == &p->module->gen->default_module); TEMPORARY_ALLOCATOR_GUARD(); - auto args = array_make(temporary_allocator(), 1); + StringSet handled = {}; + string_set_init(&handled); + defer (string_set_destroy(&handled)); + + auto args = array_make(temporary_allocator(), 3, 8); + auto class_impls = array_make(temporary_allocator(), 0, 16); + + // Register all class implementations unconditionally, even if not statically referenced + for (Entity *e = {}; mpsc_dequeue(&gen->info->objc_class_implementations, &e); /**/) { + GB_ASSERT(e->kind == Entity_TypeName && e->TypeName.objc_is_implementation); + lb_handle_objc_find_or_register_class(p, e->TypeName.objc_class_name, e->type); + } + + // Ensure classes that have been implicitly referenced through + // the objc_superclass attribute have a global variable available for them. + TypeSet class_set{}; + type_set_init(&class_set, gen->objc_classes.count+16); + defer (type_set_destroy(&class_set)); + + auto referenced_classes = array_make(temporary_allocator()); + for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) { + array_add(&referenced_classes, g); + + Type *cls = g.class_impl_type; + while (cls) { + if (type_set_update(&class_set, cls)) { + break; + } + GB_ASSERT(cls->kind == Type_Named); + + cls = cls->Named.type_name->TypeName.objc_superclass; + } + } + + for (auto pair : class_set) { + auto& tn = pair.type->Named.type_name->TypeName; + Type *class_impl = !tn.objc_is_implementation ? nullptr : pair.type; + lb_handle_objc_find_or_register_class(p, tn.objc_class_name, class_impl); + } + for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_classes, &g); /**/) { + array_add( &referenced_classes, g ); + } + + // Add all class globals to a map so that we can look them up dynamically + // in order to resolve out-of-order because classes that are being implemented + // require their superclasses to be registered before them. + StringMap global_class_map{}; + string_map_init(&global_class_map, (usize)gen->objc_classes.count); + defer (string_map_destroy(&global_class_map)); + + for (lbObjCGlobal g : referenced_classes) { + string_map_set(&global_class_map, g.name, lbObjCGlobalClass{g}); + } LLVMSetLinkage(p->value, LLVMInternalLinkage); lb_begin_procedure_body(p); - for (auto const &entry : m->objc_classes) { - String name = entry.key; - args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); - lbValue ptr = lb_emit_runtime_call(p, "objc_lookUpClass", args); - lb_addr_store(p, entry.value.local_module_addr, ptr); + + // Register class globals, gathering classes that must be implemented + for (auto& kv : global_class_map) { + lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, kv.value.g, "objc_lookUpClass"); } - for (auto const &entry : m->objc_selectors) { - String name = entry.key; - args[0] = lb_const_value(m, t_cstring, exact_value_string(name)); - lbValue ptr = lb_emit_runtime_call(p, "sel_registerName", args); - lb_addr_store(p, entry.value.local_module_addr, ptr); + // Prefetch selectors for implemented methods so that they can also be registered. + for (const auto& cd : class_impls) { + auto& g = cd.g; + Type *class_type = g.class_impl_type; + + Array* methods = map_get(&m->info->objc_method_implementations, class_type); + if (!methods) { + continue; + } + + for (const ObjcMethodData& md : *methods) { + lb_handle_objc_find_or_register_selector(p, md.ac.objc_selector); + } + } + + // Now we can register all referenced selectors + for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_selectors, &g); /**/) { + lb_register_objc_thing(handled, m, args, class_impls, global_class_map, p, g, "sel_registerName"); + } + + + // Emit method wrapper implementations and registration + auto wrapper_args = array_make(temporary_allocator(), 2, 8); + auto get_context_args = array_make(temporary_allocator(), 1); + + + PtrMap ivar_map{}; + map_init(&ivar_map, gen->objc_ivars.count); + + for (lbObjCGlobal g = {}; mpsc_dequeue(&gen->objc_ivars, &g); /**/) { + map_set(&ivar_map, g.class_impl_type, g); + } + + for (const auto &cd : class_impls) { + auto &g = cd.g; + + Type *class_type = g.class_impl_type; + Type *class_ptr_type = alloc_type_pointer(class_type); + + // Begin class registration: create class pair and update global reference + lbValue class_value = {}; + + { + lbValue superclass_value = lb_const_nil(m, t_objc_Class); + + auto& tn = class_type->Named.type_name->TypeName; + Type *superclass = tn.objc_superclass; + + if (superclass != nullptr) { + auto& superclass_global = string_map_must_get(&global_class_map, superclass->Named.type_name->TypeName.objc_class_name); + superclass_value = superclass_global.class_value; + } + + args.count = 3; + args[0] = superclass_value; + args[1] = lb_const_value(m, t_cstring, exact_value_string(g.name)); + args[2] = lb_const_int(m, t_uint, 0); + class_value = lb_emit_runtime_call(p, "objc_allocateClassPair", args); + + lbObjCGlobalClass &mapped_global = string_map_must_get(&global_class_map, tn.objc_class_name); + lb_addr_store(p, mapped_global.class_global, class_value); + + mapped_global.class_value = class_value; + } + + + Type *ivar_type = class_type->Named.type_name->TypeName.objc_ivar; + + Entity *context_provider = class_type->Named.type_name->TypeName.objc_context_provider; + Type *contex_provider_self_ptr_type = nullptr; + Type *contex_provider_self_named_type = nullptr; + bool is_context_provider_ivar = false; + lbValue context_provider_proc_value{}; + + if (context_provider) { + context_provider_proc_value = lb_find_procedure_value_from_entity(m, context_provider); + + contex_provider_self_ptr_type = base_type(context_provider->type->Proc.params->Tuple.variables[0]->type); + GB_ASSERT(contex_provider_self_ptr_type->kind == Type_Pointer); + contex_provider_self_named_type = base_named_type(type_deref(contex_provider_self_ptr_type)); + + is_context_provider_ivar = ivar_type != nullptr && internal_check_is_assignable_to(contex_provider_self_named_type, ivar_type); + } + + Array *methods = map_get(&m->info->objc_method_implementations, class_type); + if (!methods) { + continue; + } + + // Check if it has any class methods ahead of time so that we know to grab the meta_class + lbValue meta_class_value = {}; + for (const ObjcMethodData &md : *methods) { + if (!md.ac.objc_is_class_method) { + continue; + } + + // Get the meta_class + args.count = 1; + args[0] = class_value; + meta_class_value = lb_emit_runtime_call(p, "object_getClass", args); + + break; + } + + for (const ObjcMethodData &md : *methods) { + GB_ASSERT( md.proc_entity->kind == Entity_Procedure); + Type *method_type = md.proc_entity->type; + + String proc_name = make_string_c("__$objc_method::"); + proc_name = concatenate_strings(temporary_allocator(), proc_name, g.name); + proc_name = concatenate_strings(temporary_allocator(), proc_name, str_lit("::")); + proc_name = concatenate_strings( permanent_allocator(), proc_name, md.ac.objc_name); + + wrapper_args.count = 2; + wrapper_args[0] = md.ac.objc_is_class_method ? t_objc_Class : class_ptr_type; + wrapper_args[1] = t_objc_SEL; + + isize method_param_count = method_type->Proc.param_count; + isize method_param_offset = 0; + + if (!md.ac.objc_is_class_method) { + GB_ASSERT(method_param_count >= 1); + method_param_count -= 1; + method_param_offset = 1; + } + + for (isize i = 0; i < method_param_count; i++) { + array_add(&wrapper_args, method_type->Proc.params->Tuple.variables[method_param_offset+i]->type); + } + + Type *wrapper_args_tuple = alloc_type_tuple_from_field_types(wrapper_args.data, wrapper_args.count, false, true); + Type *wrapper_results_tuple = nullptr; + + if (method_type->Proc.result_count > 0) { + GB_ASSERT(method_type->Proc.result_count == 1); + wrapper_results_tuple = alloc_type_tuple_from_field_types(&method_type->Proc.results->Tuple.variables[0]->type, 1, false, true); + } + + Type *wrapper_proc_type = alloc_type_proc(nullptr, wrapper_args_tuple, wrapper_args_tuple->Tuple.variables.count, + wrapper_results_tuple, method_type->Proc.result_count, false, ProcCC_CDecl); + + lbProcedure *wrapper_proc = lb_create_dummy_procedure(m, proc_name, wrapper_proc_type); + + lb_add_function_type_attributes(wrapper_proc->value, lb_get_function_type(m, wrapper_proc_type), ProcCC_CDecl); + + // Emit the wrapper + // LLVMSetLinkage(wrapper_proc->value, LLVMInternalLinkage); + LLVMSetDLLStorageClass(wrapper_proc->value, LLVMDLLExportStorageClass); + lb_add_attribute_to_proc(wrapper_proc->module, wrapper_proc->value, "nounwind"); + + lb_begin_procedure_body(wrapper_proc); + { + LLVMValueRef context_addr = nullptr; + if (method_type->Proc.calling_convention == ProcCC_Odin) { + GB_ASSERT(context_provider); + + // Emit the get odin context call + get_context_args[0] = lbValue { + wrapper_proc->raw_input_parameters[0], + contex_provider_self_ptr_type, + }; + + if (is_context_provider_ivar) { + // The context provider takes the ivar's type. + // Emit an objc_ivar_get call and use that pointer for 'self' instead. + lbValue real_self { + wrapper_proc->raw_input_parameters[0], + class_ptr_type + }; + get_context_args[0] = lb_handle_objc_ivar_for_objc_object_pointer(wrapper_proc, real_self); + } + + lbValue context = lb_emit_call(wrapper_proc, context_provider_proc_value, get_context_args); + context_addr = lb_address_from_load(wrapper_proc, context).value;//lb_address_from_load_or_generate_local(wrapper_proc, context)); + // context_addr = LLVMGetOperand(context.value, 0); + } + + isize method_forward_arg_count = method_param_count + method_param_offset; + isize method_forward_return_arg_offset = 0; + auto raw_method_args = array_make(temporary_allocator(), 0, method_forward_arg_count+1); + + lbValue method_proc_value = lb_find_procedure_value_from_entity(m, md.proc_entity); + lbFunctionType* ft = lb_get_function_type(m, method_type); + bool has_return = false; + lbArgKind return_kind = {}; + + if (wrapper_results_tuple != nullptr) { + has_return = true; + return_kind = ft->ret.kind; + + if (return_kind == lbArg_Indirect) { + method_forward_return_arg_offset = 1; + array_add(&raw_method_args, wrapper_proc->return_ptr.addr.value); + } + } + + if (!md.ac.objc_is_class_method) { + array_add(&raw_method_args, wrapper_proc->raw_input_parameters[method_forward_return_arg_offset]); + } + + for (isize i = 0; i < method_param_count; i++) { + array_add(&raw_method_args, wrapper_proc->raw_input_parameters[i+2+method_forward_return_arg_offset]); + } + + if (method_type->Proc.calling_convention == ProcCC_Odin) { + array_add(&raw_method_args, context_addr); + } + + // Call real procedure for method from here, passing the parameters expected, if any. + LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(m, method_type); + LLVMValueRef ret_val_raw = LLVMBuildCall2(wrapper_proc->builder, fnp, method_proc_value.value, raw_method_args.data, (unsigned)raw_method_args.count, ""); + + if (has_return && return_kind != lbArg_Indirect) { + LLVMBuildRet(wrapper_proc->builder, ret_val_raw); + } + else { + LLVMBuildRetVoid(wrapper_proc->builder); + } + } + lb_end_procedure_body(wrapper_proc); + + // Add the method to the class + String method_encoding = str_lit("v"); + + GB_ASSERT(method_type->Proc.result_count <= 1); + if (method_type->Proc.result_count != 0) { + method_encoding = lb_get_objc_type_encoding(method_type->Proc.results->Tuple.variables[0]->type); + } + + if (!md.ac.objc_is_class_method) { + method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("@:")); + } else { + method_encoding = concatenate_strings(temporary_allocator(), method_encoding, str_lit("#:")); + } + + for (isize i = 0; i < method_param_count; i++) { + Type *param_type = method_type->Proc.params->Tuple.variables[i + method_param_offset]->type; + String param_encoding = lb_get_objc_type_encoding(param_type); + + method_encoding = concatenate_strings(temporary_allocator(), method_encoding, param_encoding); + } + + // Emit method registration + lbAddr* sel_address = string_map_get(&m->objc_selectors, md.ac.objc_selector); + GB_ASSERT(sel_address); + lbValue selector_value = lb_addr_load(p, *sel_address); + + lbValue target_class = !md.ac.objc_is_class_method ? class_value : meta_class_value; + + args.count = 4; + args[0] = target_class; // Class + args[1] = selector_value; // SEL + args[2] = lbValue { wrapper_proc->value, wrapper_proc->type }; + args[3] = lb_const_value(m, t_cstring, exact_value_string(method_encoding)); + + // TODO(harold): Emit check BOOL result and panic if false? + lb_emit_runtime_call(p, "class_addMethod", args); + + } // End methods + + // Add ivar if we have one + if (ivar_type != nullptr) { + // Register a single ivar for this class + Type *ivar_base = ivar_type->Named.base; + + // @note(harold): The alignment is supposed to be passed as log2(alignment): https://developer.apple.com/documentation/objectivec/class_addivar(_:_:_:_:_:)?language=objc + const i64 size = type_size_of(ivar_base); + const i64 alignment = (i64)floor_log2((u64)type_align_of(ivar_base)); + + // NOTE(harold): I've opted to not emit the type encoding for ivars in order to keep the data private. + // If there is desire in the future to emit the type encoding for introspection through the Obj-C runtime, + // then perhaps an option can be added for it then. + // Should we pass the actual type encoding? Might not be ideal for obfuscation. + String ivar_name = str_lit("__$ivar"); + String ivar_types = str_lit("{= }"); //lb_get_objc_type_encoding(ivar_type); + args.count = 5; + args[0] = class_value; + args[1] = lb_const_value(m, t_cstring, exact_value_string(ivar_name)); + args[2] = lb_const_value(m, t_uint, exact_value_u64((u64)size)); + args[3] = lb_const_value(m, t_u8, exact_value_u64((u64)alignment)); + args[4] = lb_const_value(m, t_cstring, exact_value_string(ivar_types)); + lb_emit_runtime_call(p, "class_addIvar", args); + } + + // Complete the class registration + args.count = 1; + args[0] = class_value; + lb_emit_runtime_call(p, "objc_registerClassPair", args); + } + + // Register ivar offsets for any `objc_ivar_get` expressions emitted. + for (auto const& kv : ivar_map) { + lbObjCGlobal const& g = kv.value; + lbAddr ivar_addr = {}; + lbValue *found = string_map_get(&m->members, g.global_name); + + if (found) { + ivar_addr = lb_addr(*found); + GB_ASSERT(ivar_addr.addr.type == t_int_ptr); + } else { + // Defined in an external package, define it now in the main package + LLVMTypeRef t = lb_type(m, t_int); + + lbValue global = {}; + global.value = LLVMAddGlobal(m->mod, t, g.global_name); + global.type = t_int_ptr; + + LLVMSetInitializer(global.value, LLVMConstInt(t, 0, true)); + + ivar_addr = lb_addr(global); + } + + String class_name = g.class_impl_type->Named.type_name->TypeName.objc_class_name; + lbValue class_value = string_map_must_get(&global_class_map, class_name).class_value; + + args.count = 2; + args[0] = class_value; + args[1] = lb_const_value(m, t_cstring, exact_value_string(str_lit("__$ivar"))); + lbValue ivar = lb_emit_runtime_call(p, "class_getInstanceVariable", args); + + args.count = 1; + args[0] = ivar; + lbValue ivar_offset = lb_emit_runtime_call(p, "ivar_getOffset", args); + lbValue ivar_offset_int = lb_emit_conv(p, ivar_offset, t_int); + + lb_addr_store(p, ivar_addr, ivar_offset_int); } lb_end_procedure_body(p); @@ -1179,12 +1964,16 @@ gb_internal void lb_verify_function(lbModule *m, lbProcedure *p, bool dump_ll=fa } gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) { + if (LLVM_IGNORE_VERIFICATION) { + return 0; + } + char *llvm_error = nullptr; defer (LLVMDisposeMessage(llvm_error)); lbModule *m = cast(lbModule *)data; if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) { - gb_printf_err("LLVM Error:\n%s\n", llvm_error); + gb_printf_err("LLVM Error in module %s:\n%s\n", m->module_name, llvm_error); if (build_context.keep_temp_files) { TIME_SECTION("LLVM Print Module to File"); String filepath_ll = lb_filepath_ll_for_module(m); @@ -1200,6 +1989,132 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) { return 0; } +gb_internal bool lb_init_global_var(lbModule *m, lbProcedure *p, Entity *e, Ast *init_expr, lbGlobalVariable &var) { + if (init_expr != nullptr) { + lbValue init = lb_build_expr(p, init_expr); + if (init.value == nullptr) { + LLVMTypeRef global_type = llvm_addr_type(p->module, var.var); + if (is_type_untyped_nil(init.type)) { + LLVMSetInitializer(var.var.value, LLVMConstNull(global_type)); + var.is_initialized = true; + + if (e->Variable.is_rodata) { + LLVMSetGlobalConstant(var.var.value, true); + } + return true; + } + GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr)); + } + + if (is_type_any(e->type)) { + var.init = init; + } else if (lb_is_const_or_global(init)) { + if (!var.is_initialized) { + if (is_type_proc(init.type)) { + init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type)); + } + LLVMSetInitializer(var.var.value, init.value); + var.is_initialized = true; + + if (e->Variable.is_rodata) { + LLVMSetGlobalConstant(var.var.value, true); + } + return true; + } + } else { + var.init = init; + } + } + + if (var.init.value != nullptr) { + GB_ASSERT(!var.is_initialized); + Type *t = type_deref(var.var.type); + + if (is_type_any(t)) { + // NOTE(bill): Edge case for 'any' type + Type *var_type = default_type(var.init.type); + gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::"); + gbString e_str = string_canonical_entity_name(temporary_allocator(), e); + var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str)); + lbAddr g = lb_add_global_generated_with_name(m, var_type, {}, make_string_c(var_name)); + lb_addr_store(p, g, var.init); + lbValue gp = lb_addr_get_ptr(p, g); + + lbValue data = lb_emit_struct_ep(p, var.var, 0); + lbValue ti = lb_emit_struct_ep(p, var.var, 1); + lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr)); + lb_emit_store(p, ti, lb_typeid(p->module, var_type)); + } else { + LLVMTypeRef vt = llvm_addr_type(p->module, var.var); + lbValue src0 = lb_emit_conv(p, var.init, t); + LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt); + LLVMValueRef dst = var.var.value; + LLVMBuildStore(p->builder, src, dst); + } + + var.is_initialized = true; + } + return false; +} + + +gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedure *p) { + lb_begin_procedure_body(p); + + lb_setup_type_info_data(m); + + if (p->objc_names) { + LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(m, p->objc_names->type), p->objc_names->value, nullptr, 0, ""); + } + Type *dummy_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); + LLVMTypeRef raw_dummy_type = lb_type_internal_for_procedures_raw(m, dummy_type); + + for (auto &var : *p->global_variables) { + if (var.is_initialized) { + continue; + } + + lbModule *entity_module = m; + + Entity *e = var.decl->entity; + GB_ASSERT(e->kind == Entity_Variable); + e->code_gen_module = entity_module; + Ast *init_expr = var.decl->init_expr; + + if (init_expr == nullptr && var.init.value == nullptr) { + continue; + } + + if (type_size_of(e->type) > 8) { + String ename = lb_get_entity_name(m, e); + gbString name = gb_string_make(permanent_allocator(), ""); + name = gb_string_appendc(name, "__$startup$"); + name = gb_string_append_length(name, ename.text, ename.len); + + lbProcedure *dummy = lb_create_dummy_procedure(m, make_string_c(name), dummy_type); + LLVMSetVisibility(dummy->value, LLVMHiddenVisibility); + LLVMSetLinkage(dummy->value, LLVMWeakAnyLinkage); + + lb_begin_procedure_body(dummy); + lb_init_global_var(m, dummy, e, init_expr, var); + lb_end_procedure_body(dummy); + + LLVMValueRef context_ptr = lb_find_or_generate_context_ptr(p).addr.value; + LLVMBuildCall2(p->builder, raw_dummy_type, dummy->value, &context_ptr, 1, ""); + } else { + lb_init_global_var(m, p, e, init_expr, var); + } + } + CheckerInfo *info = m->gen->info; + + for (Entity *e : info->init_procedures) { + lbValue value = lb_find_procedure_value_from_entity(m, e); + lb_emit_call(p, value, {}, ProcInlining_none); + } + + + lb_end_procedure_body(p); +} gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array &global_variables) { // Startup Runtime @@ -1210,104 +2125,15 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc lb_add_attribute_to_proc(p->module, p->value, "optnone"); lb_add_attribute_to_proc(p->module, p->value, "noinline"); - lb_begin_procedure_body(p); + // Make sure shared libraries call their own runtime startup on Linux. + LLVMSetVisibility(p->value, LLVMHiddenVisibility); + LLVMSetLinkage(p->value, LLVMWeakAnyLinkage); - lb_setup_type_info_data(main_module); + p->global_variables = &global_variables; + p->objc_names = objc_names; - if (objc_names) { - LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, ""); - } + lb_create_startup_runtime_generate_body(main_module, p); - for (auto &var : global_variables) { - if (var.is_initialized) { - continue; - } - - lbModule *entity_module = main_module; - - Entity *e = var.decl->entity; - GB_ASSERT(e->kind == Entity_Variable); - e->code_gen_module = entity_module; - - Ast *init_expr = var.decl->init_expr; - if (init_expr != nullptr) { - lbValue init = lb_build_expr(p, init_expr); - if (init.value == nullptr) { - LLVMTypeRef global_type = llvm_addr_type(p->module, var.var); - if (is_type_untyped_nil(init.type)) { - LLVMSetInitializer(var.var.value, LLVMConstNull(global_type)); - var.is_initialized = true; - - if (e->Variable.is_rodata) { - LLVMSetGlobalConstant(var.var.value, true); - } - continue; - } - GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr)); - } - - if (is_type_any(e->type) || is_type_union(e->type)) { - var.init = init; - } else if (lb_is_const_or_global(init)) { - if (!var.is_initialized) { - if (is_type_proc(init.type)) { - init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type)); - } - LLVMSetInitializer(var.var.value, init.value); - var.is_initialized = true; - - if (e->Variable.is_rodata) { - LLVMSetGlobalConstant(var.var.value, true); - } - continue; - } - } else { - var.init = init; - } - } - - if (var.init.value != nullptr) { - GB_ASSERT(!var.is_initialized); - Type *t = type_deref(var.var.type); - - if (is_type_any(t)) { - // NOTE(bill): Edge case for 'any' type - Type *var_type = default_type(var.init.type); - gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::"); - gbString e_str = string_canonical_entity_name(temporary_allocator(), e); - var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str)); - lbAddr g = lb_add_global_generated_with_name(main_module, var_type, var.init, make_string_c(var_name)); - lb_addr_store(p, g, var.init); - lbValue gp = lb_addr_get_ptr(p, g); - - lbValue data = lb_emit_struct_ep(p, var.var, 0); - lbValue ti = lb_emit_struct_ep(p, var.var, 1); - lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr)); - lb_emit_store(p, ti, lb_type_info(p, var_type)); - } else { - LLVMTypeRef vt = llvm_addr_type(p->module, var.var); - lbValue src0 = lb_emit_conv(p, var.init, t); - LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt); - LLVMValueRef dst = var.var.value; - LLVMBuildStore(p->builder, src, dst); - } - - var.is_initialized = true; - } - - - } - CheckerInfo *info = main_module->gen->info; - - for (Entity *e : info->init_procedures) { - lbValue value = lb_find_procedure_value_from_entity(main_module, e); - lb_emit_call(p, value, {}, ProcInlining_none); - } - - - lb_end_procedure_body(p); - - lb_verify_function(main_module, p); return p; } @@ -1319,6 +2145,10 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C lb_add_attribute_to_proc(p->module, p->value, "optnone"); lb_add_attribute_to_proc(p->module, p->value, "noinline"); + // Make sure shared libraries call their own runtime cleanup on Linux. + LLVMSetVisibility(p->value, LLVMHiddenVisibility); + LLVMSetLinkage(p->value, LLVMWeakAnyLinkage); + lb_begin_procedure_body(p); CheckerInfo *info = main_module->gen->info; @@ -1344,7 +2174,7 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) { for (Entity *e : m->global_procedures_to_create) { (void)lb_get_entity_name(m, e); - array_add(&m->procedures_to_generate, lb_create_procedure(m, e)); + mpsc_enqueue(&m->procedures_to_generate, lb_create_procedure(m, e)); } return 0; } @@ -1368,8 +2198,6 @@ gb_internal GB_COMPARE_PROC(llvm_global_entity_cmp) { } gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info, bool do_threading) { - auto *min_dep_set = &info->minimum_dependency_set; - for (Entity *e : info->entities) { String name = e->token.string; Scope * scope = e->scope; @@ -1393,7 +2221,7 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker break; case Entity_Constant: if (build_context.ODIN_DEBUG) { - add_debug_info_for_global_constant_from_entity(gen, e); + lb_add_debug_info_for_global_constant_from_entity(gen, e); } break; } @@ -1406,18 +2234,28 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker } } - if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + if (!polymorphic_struct && e->min_dep_count.load(std::memory_order_relaxed) == 0) { // NOTE(bill): Nothing depends upon it so doesn't need to be built continue; } + // if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + // // NOTE(bill): Nothing depends upon it so doesn't need to be built + // continue; + // } + lbModule *m = &gen->default_module; if (USE_SEPARATE_MODULES) { - m = lb_module_of_entity(gen, e); + m = lb_module_of_entity(gen, e, m); } GB_ASSERT(m != nullptr); if (e->kind == Entity_Procedure) { + if (e->Procedure.is_foreign && e->Procedure.is_objc_impl_or_import) { + // Do not generate declarations for foreign Objective-C methods. These are called indirectly through the Objective-C runtime. + continue; + } + array_add(&m->global_procedures_to_create, e); } else if (e->kind == Entity_TypeName) { array_add(&m->global_types_to_create, e); @@ -1529,7 +2367,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { lb_llvm_function_pass_per_function_internal(m, m->gen->objc_names); } - for (lbProcedure *p : m->procedures_to_generate) { + MUTEX_GUARD_BLOCK(&m->generated_procedures_mutex) for (lbProcedure *p : m->generated_procedures) { if (p->body != nullptr) { // Build Procedure lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default; if (p->flags & lbProcedureFlag_WithoutMemcpyPass) { @@ -1568,17 +2406,23 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { } +void lb_remove_unused_functions_and_globals(lbGenerator *gen) { + for (auto &entry : gen->modules) { + lbModule *m = entry.value; + lb_run_remove_unused_function_pass(m); + lb_run_remove_unused_globals_pass(m); + } +} + struct lbLLVMModulePassWorkerData { lbModule *m; LLVMTargetMachineRef target_machine; + bool do_threading; }; gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { auto wd = cast(lbLLVMModulePassWorkerData *)data; - lb_run_remove_unused_function_pass(wd->m); - lb_run_remove_unused_globals_pass(wd->m); - LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager(); lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level); LLVMRunPassManager(module_pass_manager, wd->m->mod); @@ -1591,797 +2435,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) { LLVMPassBuilderOptionsRef pb_options = LLVMCreatePassBuilderOptions(); defer (LLVMDisposePassBuilderOptions(pb_options)); - switch (build_context.optimization_level) { - case -1: - array_add(&passes, "function(annotation-remarks)"); - break; - case 0: - array_add(&passes, "always-inline"); - array_add(&passes, "function(annotation-remarks)"); - break; - case 1: -// default -// Passes removed: coro, openmp, sroa -#if LLVM_VERSION_MAJOR == 17 - array_add(&passes, u8R"( -annotation2metadata, -forceattrs, -inferattrs, -function( - lower-expect, - simplifycfg, - early-cse<> -), -ipsccp, -called-value-propagation, -globalopt, -function( - mem2reg, - instcombine, - simplifycfg -), -require, -function( - invalidate -), -require, -cgscc( - devirt<4>( - inline, - inline, - function-attrs, - function( - early-cse, - speculative-execution, - jump-threading, - correlated-propagation, - simplifycfg, - instcombine, - aggressive-instcombine, - constraint-elimination, - tailcallelim, - simplifycfg, - reassociate, - loop-mssa( - loop-instsimplify, - loop-simplifycfg, - licm, - loop-rotate, - licm, - simple-loop-unswitch - ), - simplifycfg, - instcombine, - loop( - loop-idiom, - indvars, - loop-deletion, - loop-unroll-full - ), - vector-combine, - mldst-motion, - gvn<>, - sccp, - bdce, - instcombine, - jump-threading, - correlated-propagation, - adce, - memcpyopt, - dse, - move-auto-init, - loop-mssa( - licm - ), - simplifycfg, - instcombine - ), - function-attrs, - function( - require - ) - ) -), -deadargelim, -globalopt, -globaldce, -elim-avail-extern, -rpo-function-attrs, -recompute-globalsaa, -function( - float2int, - lower-constant-intrinsics, - loop( - loop-rotate, - loop-deletion - ), - loop-distribute, - inject-tli-mappings, - loop-vectorize, - loop-load-elim, - instcombine, - simplifycfg, - slp-vectorizer, - vector-combine, - instcombine, - loop-unroll, - transform-warning, - instcombine, - loop-mssa( - licm - ), - alignment-from-assumptions, - loop-sink, - instsimplify, - div-rem-pairs, - tailcallelim, - simplifycfg -), -globaldce, -constmerge, -cg-profile, -rel-lookup-table-converter, -function( - annotation-remarks -), -verify -)"); -#else - array_add(&passes, u8R"( -annotation2metadata, -forceattrs, -inferattrs, -function( - lower-expect, - simplifycfg, - sroa, - early-cse<> -), -ipsccp, -called-value-propagation, -globalopt, -function( - mem2reg, - instcombine, - simplifycfg -), -always-inline, -require, -function( - invalidate -), -require, -cgscc( - devirt<4>( - inline, - function-attrs, - function( - sroa, - early-cse, - speculative-execution, - jump-threading, - correlated-propagation, - simplifycfg, - instcombine, - aggressive-instcombine, - tailcallelim, - simplifycfg, - reassociate, - constraint-elimination, - loop-mssa( - loop-instsimplify, - loop-simplifycfg, - licm, - loop-rotate, - licm, - simple-loop-unswitch - ), - simplifycfg, - instcombine, - loop( - loop-idiom, - indvars, - loop-deletion, - loop-unroll-full - ), - sroa, - vector-combine, - mldst-motion, - gvn<>, - sccp, - bdce, - instcombine, - jump-threading, - correlated-propagation, - adce, - memcpyopt, - dse, - move-auto-init, - loop-mssa( - licm - ), - simplifycfg, - instcombine - ), - function-attrs, - function( - require - ) - ) -), -deadargelim, -globalopt, -globaldce, -elim-avail-extern, -rpo-function-attrs, -recompute-globalsaa, -function( - float2int, - lower-constant-intrinsics, - loop( - loop-rotate, - loop-deletion - ), - loop-distribute, - inject-tli-mappings, - loop-vectorize, - infer-alignment, - loop-load-elim, - instcombine, - simplifycfg, - slp-vectorizer, - vector-combine, - instcombine, - loop-unroll, - transform-warning, - sroa, - infer-alignment, - instcombine, - loop-mssa( - licm - ), - alignment-from-assumptions, - loop-sink, - instsimplify, - div-rem-pairs, - tailcallelim, - simplifycfg -), -globaldce, -constmerge, -cg-profile, -rel-lookup-table-converter, -function( - annotation-remarks -), -verify -)"); -#endif - break; -// default -// Passes removed: coro, openmp, sroa - case 2: -#if LLVM_VERSION_MAJOR == 17 - array_add(&passes, u8R"( -annotation2metadata, -forceattrs, -inferattrs, -function( - lower-expect, - simplifycfg, - early-cse<> -), -ipsccp, -called-value-propagation, -globalopt, -function( - mem2reg, - instcombine, - simplifycfg -), -require, -function( - invalidate -), -require, -cgscc( - devirt<4>( - inline, - inline, - function-attrs, - function( - early-cse, - speculative-execution, - jump-threading, - correlated-propagation, - simplifycfg, - instcombine, - aggressive-instcombine, - constraint-elimination, - libcalls-shrinkwrap, - tailcallelim, - simplifycfg, - reassociate, - loop-mssa( - loop-instsimplify, - loop-simplifycfg, - licm, - loop-rotate, - licm, - simple-loop-unswitch - ), - simplifycfg, - instcombine, - loop( - loop-idiom, - indvars, - loop-deletion, - loop-unroll-full - ), - vector-combine, - mldst-motion, - gvn<>, - sccp, - bdce, - instcombine, - jump-threading, - correlated-propagation, - adce, - memcpyopt, - dse, - move-auto-init, - loop-mssa( - licm - ), - simplifycfg, - instcombine - ), - function-attrs, - function( - require - ) - ) -), -deadargelim, -globalopt, -globaldce, -elim-avail-extern, -rpo-function-attrs, -recompute-globalsaa, -function( - float2int, - lower-constant-intrinsics, - loop( - loop-rotate, - loop-deletion - ), - loop-distribute, - inject-tli-mappings, - loop-vectorize, - loop-load-elim, - instcombine, - simplifycfg, - slp-vectorizer, - vector-combine, - instcombine, - loop-unroll, - transform-warning, - instcombine, - loop-mssa( - licm - ), - alignment-from-assumptions, - loop-sink, - instsimplify, - div-rem-pairs, - tailcallelim, - simplifycfg -), -globaldce, -constmerge, -cg-profile, -rel-lookup-table-converter, -function( - annotation-remarks -), -verify -)"); -#else - array_add(&passes, u8R"( -annotation2metadata, -forceattrs, -inferattrs, -function( - lower-expect, - simplifycfg, - sroa, - early-cse<> -), -ipsccp, -called-value-propagation, -globalopt, -function( - mem2reg, - instcombine, - simplifycfg -), -always-inline, -require, -function( - invalidate -), -require, -cgscc( - devirt<4>( - inline, - function-attrs, - function( - sroa, - early-cse, - speculative-execution, - jump-threading, - correlated-propagation, - simplifycfg, - instcombine, - aggressive-instcombine, - libcalls-shrinkwrap, - tailcallelim, - simplifycfg, - reassociate, - constraint-elimination, - loop-mssa( - loop-instsimplify, - loop-simplifycfg, - licm, - loop-rotate, - licm, - simple-loop-unswitch - ), - simplifycfg, - instcombine, - loop( - loop-idiom, - indvars, - loop-deletion, - loop-unroll-full - ), - sroa, - vector-combine, - mldst-motion, - gvn<>, - sccp, - bdce, - instcombine, - jump-threading, - correlated-propagation, - adce, - memcpyopt, - dse, - move-auto-init, - loop-mssa( - licm - ), - simplifycfg, - instcombine - ), - function-attrs, - function( - require - ) - ) -), -deadargelim, -globalopt, -globaldce, -elim-avail-extern, -rpo-function-attrs, -recompute-globalsaa, -function( - float2int, - lower-constant-intrinsics, - loop( - loop-rotate, - loop-deletion - ), - loop-distribute, - inject-tli-mappings, - loop-vectorize, - infer-alignment, - loop-load-elim, - instcombine, - simplifycfg, - slp-vectorizer, - vector-combine, - instcombine, - loop-unroll, - transform-warning, - sroa, - infer-alignment, - instcombine, - loop-mssa( - licm - ), - alignment-from-assumptions, - loop-sink, - instsimplify, - div-rem-pairs, - tailcallelim, - simplifycfg -), -globaldce, -constmerge, -cg-profile, -rel-lookup-table-converter, -function( - annotation-remarks -), -verify -)"); -#endif - break; - - case 3: -// default -// Passes removed: coro, openmp, sroa -#if LLVM_VERSION_MAJOR == 17 - array_add(&passes, u8R"( -annotation2metadata, -forceattrs, -inferattrs, -function( - lower-expect, - simplifycfg, - early-cse<>, - callsite-splitting -), -ipsccp, -called-value-propagation, -globalopt, -function( - mem2reg, - instcombine, - simplifycfg -), -require, -function( - invalidate -), -require, -cgscc( - devirt<4>( - inline, - inline, - function-attrs, - argpromotion, - function( - early-cse, - speculative-execution, - jump-threading, - correlated-propagation, - simplifycfg, - instcombine, - aggressive-instcombine, - constraint-elimination, - libcalls-shrinkwrap, - tailcallelim, - simplifycfg, - reassociate, - loop-mssa( - loop-instsimplify, - loop-simplifycfg, - licm, - loop-rotate, - licm, - simple-loop-unswitch - ), - simplifycfg, - instcombine, - loop( - loop-idiom, - indvars, - loop-deletion, - loop-unroll-full - ), - vector-combine, - mldst-motion, - gvn<>, - sccp, - bdce, - instcombine, - jump-threading, - correlated-propagation, - adce, - memcpyopt, - dse, - move-auto-init, - loop-mssa( - licm - ), - simplifycfg, - instcombine - ), - function-attrs, - function( - require - ) - ) -), -deadargelim, -globalopt, -globaldce, -elim-avail-extern, -rpo-function-attrs, -recompute-globalsaa, -function( - float2int, - lower-constant-intrinsics, - chr, - loop( - loop-rotate, - loop-deletion - ), - loop-distribute, - inject-tli-mappings, - loop-vectorize, - loop-load-elim, - instcombine, - simplifycfg, - slp-vectorizer, - vector-combine, - instcombine, - loop-unroll, - transform-warning, - instcombine, - loop-mssa( - licm - ), - alignment-from-assumptions, - loop-sink, - instsimplify, - div-rem-pairs, - tailcallelim, - simplifycfg -), -globaldce, -constmerge, -cg-profile, -rel-lookup-table-converter, -function( - annotation-remarks -), -verify -)"); -#else - array_add(&passes, u8R"( -annotation2metadata, -forceattrs, -inferattrs, -function( - lower-expect, - simplifycfg, - sroa, - early-cse<>, - callsite-splitting -), -ipsccp, -called-value-propagation, -globalopt, -function( - mem2reg, - instcombine, - simplifycfg -), -always-inline, -require, -function(invalidate), -require, -cgscc( - devirt<4>( - inline, - function-attrs, - argpromotion, - function( - sroa, - early-cse, - speculative-execution, - jump-threading, - correlated-propagation, - simplifycfg, - instcombine, - aggressive-instcombine, - libcalls-shrinkwrap, - tailcallelim, - simplifycfg, - reassociate, - constraint-elimination, - loop-mssa( - loop-instsimplify, - loop-simplifycfg, - licm, - loop-rotate, - licm, - simple-loop-unswitch - ), - simplifycfg, - instcombine, - loop( - loop-idiom, - indvars, - loop-deletion, - loop-unroll-full - ), - sroa, - vector-combine, - mldst-motion, - gvn<>, - sccp, - bdce, - instcombine, - jump-threading, - correlated-propagation, - adce, - memcpyopt, - dse, - move-auto-init, - loop-mssa(licm), - simplifycfg, - instcombine - ), - function-attrs, - function( - require - ) - ) -), -deadargelim, -globalopt, -globaldce, -elim-avail-extern, -rpo-function-attrs, -recompute-globalsaa, -function( - float2int, - lower-constant-intrinsics, - chr, - loop( - loop-rotate, - loop-deletion - ), - loop-distribute, - inject-tli-mappings, - loop-vectorize, - infer-alignment, - loop-load-elim, - instcombine, - simplifycfg, - slp-vectorizer, - vector-combine, - instcombine, - loop-unroll, - transform-warning, - sroa, - infer-alignment, - instcombine, - loop-mssa(licm), - alignment-from-assumptions, - loop-sink, - instsimplify, - div-rem-pairs, - tailcallelim, - simplifycfg -), -globaldce, -constmerge, -cg-profile, -rel-lookup-table-converter, -function( - annotation-remarks -), -verify -)"); -#endif - break; - } + #include "llvm_backend_passes.cpp" // asan - Linux, Darwin, Windows // msan - linux @@ -2444,6 +2498,17 @@ verify return 1; } #endif + + if (LLVM_IGNORE_VERIFICATION) { + return 0; + } + + if (wd->do_threading) { + thread_pool_add_task(lb_llvm_module_verification_worker_proc, wd->m); + } else { + lb_llvm_module_verification_worker_proc(wd->m); + } + return 0; } @@ -2451,8 +2516,7 @@ verify gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) { lbModule *m = cast(lbModule *)data; - for (isize i = 0; i < m->procedures_to_generate.count; i++) { - lbProcedure *p = m->procedures_to_generate[i]; + for (lbProcedure *p = nullptr; mpsc_dequeue(&m->procedures_to_generate, &p); /**/) { lb_generate_procedure(p->module, p); } return 0; @@ -2476,10 +2540,15 @@ gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) { gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) { lbModule *m = cast(lbModule *)data; - for (isize i = 0; i < m->missing_procedures_to_check.count; i++) { - lbProcedure *p = m->missing_procedures_to_check[i]; - debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m); - lb_generate_procedure(m, p); + for (lbProcedure *p = nullptr; mpsc_dequeue(&m->missing_procedures_to_check, &p); /**/) { + if (!p->is_done.load(std::memory_order_relaxed)) { + debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m); + lb_generate_procedure(m, p); + } + + for (lbProcedure *nested = nullptr; mpsc_dequeue(&m->procedures_to_generate, &nested); /**/) { + mpsc_enqueue(&m->missing_procedures_to_check, nested); + } } return 0; } @@ -2499,6 +2568,12 @@ gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_thread lb_generate_missing_procedures_to_check_worker_proc(m); } } + + for (auto const &entry : gen->modules) { + lbModule *m = entry.value; + GB_ASSERT(m->missing_procedures_to_check.count == 0); + GB_ASSERT(m->procedures_to_generate.count == 0); + } } gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) { @@ -2526,19 +2601,16 @@ gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) { } -gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) { +gb_internal void lb_llvm_module_passes_and_verification(lbGenerator *gen, bool do_threading) { if (do_threading) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); wd->m = m; wd->target_machine = m->target_machine; + wd->do_threading = true; - if (do_threading) { - thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd); - } else { - lb_llvm_module_pass_worker_proc(wd); - } + thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd); } thread_pool_wait(); } else { @@ -2547,6 +2619,7 @@ gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) { auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData); wd->m = m; wd->target_machine = m->target_machine; + wd->do_threading = false; lb_llvm_module_pass_worker_proc(wd); } } @@ -2589,10 +2662,8 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) { gbString path = gb_string_make_length(heap_allocator(), basename.text, basename.len); path = gb_string_appendc(path, "/"); - path = gb_string_append_length(path, name.text, name.len); - - { + if (USE_SEPARATE_MODULES) { GB_ASSERT(m->module_name != nullptr); String s = make_string_c(m->module_name); String prefix = str_lit("odin_package"); @@ -2602,6 +2673,8 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) { } path = gb_string_append_length(path, s.text, s.len); + } else { + path = gb_string_append_length(path, name.text, name.len); } if (use_temporary_directory) { @@ -2612,69 +2685,21 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) { String ext = {}; if (build_context.build_mode == BuildMode_Assembly) { - ext = STR_LIT(".S"); + ext = STR_LIT("S"); + } else if (build_context.build_mode == BuildMode_Object) { + // Allow a user override for the object extension. + ext = build_context.build_paths[BuildPath_Output].ext; } else { - if (is_arch_wasm()) { - ext = STR_LIT(".wasm.o"); - } else { - switch (build_context.metrics.os) { - case TargetOs_windows: - ext = STR_LIT(".obj"); - break; - default: - case TargetOs_darwin: - case TargetOs_linux: - case TargetOs_essence: - ext = STR_LIT(".o"); - break; - - case TargetOs_freestanding: - switch (build_context.metrics.abi) { - default: - case TargetABI_Default: - case TargetABI_SysV: - ext = STR_LIT(".o"); - break; - case TargetABI_Win64: - ext = STR_LIT(".obj"); - break; - } - break; - } - } + ext = infer_object_extension_from_build_context(); } + path = gb_string_append_length(path, ".", 1); path = gb_string_append_length(path, ext.text, ext.len); return make_string(cast(u8 *)path, gb_string_length(path)); } - -gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) { - if (LLVM_IGNORE_VERIFICATION) { - return true; - } - - if (do_threading) { - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - thread_pool_add_task(lb_llvm_module_verification_worker_proc, m); - } - thread_pool_wait(); - - } else { - for (auto const &entry : gen->modules) { - lbModule *m = entry.value; - if (lb_llvm_module_verification_worker_proc(m)) { - return false; - } - } - } - - return true; -} - gb_internal void lb_add_foreign_library_paths(lbGenerator *gen) { for (auto const &entry : gen->modules) { lbModule *m = entry.value; @@ -2770,8 +2795,15 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"), t_u32, false, true); params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true); call_cleanup = false; - } else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) { + } else if (build_context.metrics.os == TargetOs_windows && build_context.no_crt) { name = str_lit("mainCRTStartup"); + } else if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt) { + // Windows i386 with CRT: libcmt expects _main (main with underscore prefix) + name = str_lit("main"); + has_args = true; + slice_init(¶ms->Tuple.variables, permanent_allocator(), 2); + params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true); + params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true); } else if (is_arch_wasm()) { name = str_lit("_start"); call_cleanup = false; @@ -2826,8 +2858,8 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star if (testing_proc->pkg != nullptr) { pkg_name = testing_proc->pkg->name; } - lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name); - lbValue v_name = lb_find_or_add_entity_string(m, name); + lbValue v_pkg = lb_find_or_add_entity_string(m, pkg_name, false); + lbValue v_name = lb_find_or_add_entity_string(m, name, false); lbValue v_proc = lb_find_procedure_value_from_entity(m, testing_proc); indices[1] = LLVMConstInt(lb_type(m, t_int), testing_proc_index++, false); @@ -2897,18 +2929,20 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star } gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) { - if (p->is_done) { + if (p->is_done.load(std::memory_order_relaxed)) { return; } + if (p->body != nullptr) { // Build Procedure m->curr_procedure = p; lb_begin_procedure_body(p); lb_build_stmt(p, p->body); lb_end_procedure_body(p); - p->is_done = true; + p->is_done.store(true, std::memory_order_relaxed); m->curr_procedure = nullptr; + } else if (p->generate_body != nullptr) { + p->generate_body(m, p); } - lb_end_procedure(p); // Add Flags if (p->entity && p->entity->kind == Entity_Procedure && p->entity->Procedure.is_memcpy_like) { @@ -2916,6 +2950,9 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) { } lb_verify_function(m, p, true); + + MUTEX_GUARD(&m->generated_procedures_mutex); + array_add(&m->generated_procedures, p); } @@ -2930,8 +2967,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lbModule *default_module = &gen->default_module; CheckerInfo *info = gen->info; - auto *min_dep_set = &info->minimum_dependency_set; - switch (build_context.metrics.arch) { case TargetArch_amd64: case TargetArch_i386: @@ -2959,13 +2994,24 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { LLVMInitializeWebAssemblyAsmParser(); LLVMInitializeWebAssemblyDisassembler(); break; + case TargetArch_riscv64: + LLVMInitializeRISCVTargetInfo(); + LLVMInitializeRISCVTarget(); + LLVMInitializeRISCVTargetMC(); + LLVMInitializeRISCVAsmPrinter(); + LLVMInitializeRISCVAsmParser(); + LLVMInitializeRISCVDisassembler(); + break; + case TargetArch_arm32: + LLVMInitializeARMTargetInfo(); + LLVMInitializeARMTarget(); + LLVMInitializeARMTargetMC(); + LLVMInitializeARMAsmPrinter(); + LLVMInitializeARMAsmParser(); + LLVMInitializeARMDisassembler(); + break; default: - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargets(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllAsmPrinters(); - LLVMInitializeAllAsmParsers(); - LLVMInitializeAllDisassemblers(); + GB_PANIC("Unimplemented LLVM target initialization"); break; } @@ -3206,6 +3252,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t))); LLVMSetLinkage(g, LLVMInternalLinkage); lb_make_global_private_const(g); + lb_set_odin_rtti_section(g); return lb_addr({g, alloc_type_pointer(t)}); }; @@ -3235,6 +3282,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { String link_name = e->Procedure.link_name; if (e->pkg->kind == Package_Runtime) { if (link_name == "main" || + link_name == "_main" || link_name == "DllMain" || link_name == "WinMain" || link_name == "wWinMain" || @@ -3257,7 +3305,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { continue; } - if (!ptr_set_exists(min_dep_set, e)) { + if (e->min_dep_count.load(std::memory_order_relaxed) == 0) { continue; } @@ -3267,69 +3315,49 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } GB_ASSERT(e->kind == Entity_Variable); + bool is_foreign = e->Variable.is_foreign; bool is_export = e->Variable.is_export; + lbModule *default_module = &gen->default_module; + + lbModule *m = default_module; + lbModule *e_module = lb_module_of_entity(gen, e, default_module); + + bool const split_globals_across_modules = false; + if (split_globals_across_modules) { + m = e_module; + } - lbModule *m = &gen->default_module; String name = lb_get_entity_name(m, e); - lbValue g = {}; - g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); - g.type = alloc_type_pointer(e->type); - if (e->Variable.thread_local_model != "") { - LLVMSetThreadLocal(g.value, true); - - String m = e->Variable.thread_local_model; - LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel; - if (m == "default") { - mode = LLVMGeneralDynamicTLSModel; - } else if (m == "localdynamic") { - mode = LLVMLocalDynamicTLSModel; - } else if (m == "initialexec") { - mode = LLVMInitialExecTLSModel; - } else if (m == "localexec") { - mode = LLVMLocalExecTLSModel; - } else { - GB_PANIC("Unhandled thread local mode %.*s", LIT(m)); - } - LLVMSetThreadLocalMode(g.value, mode); - } - if (is_foreign) { - LLVMSetLinkage(g.value, LLVMExternalLinkage); - LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass); - LLVMSetExternallyInitialized(g.value, true); - lb_add_foreign_library_path(m, e->Variable.foreign_library); - } else { - LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type))); - } - if (is_export) { - LLVMSetLinkage(g.value, LLVMDLLExportLinkage); - LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass); - } else if (!is_foreign) { - LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage); - } - lb_set_linkage_from_entity_flags(m, g.value, e->flags); - - if (e->Variable.link_section.len > 0) { - LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section)); - } - lbGlobalVariable var = {}; - var.var = g; var.decl = decl; + lbValue g = {}; + g.type = alloc_type_pointer(e->type); + g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); + if (decl->init_expr != nullptr) { TypeAndValue tav = type_and_value_of_expr(decl->init_expr); - if (!is_type_any(e->type) && !is_type_union(e->type)) { + if (!is_type_any(e->type)) { if (tav.mode != Addressing_Invalid) { if (tav.value.kind != ExactValue_Invalid) { - bool is_rodata = e->kind == Entity_Variable && e->Variable.is_rodata; + auto cc = LB_CONST_CONTEXT_DEFAULT; + cc.is_rodata = e->kind == Entity_Variable && e->Variable.is_rodata; + cc.allow_local = false; + cc.link_section = e->Variable.link_section; + ExactValue v = tav.value; - lbValue init = lb_const_value(m, tav.type, v, false, is_rodata); + lbValue init = lb_const_value(m, tav.type, v, cc); + + LLVMDeleteGlobal(g.value); + g.value = nullptr; + g.value = LLVMAddGlobal(m->mod, LLVMTypeOf(init.value), alloc_cstring(permanent_allocator(), name)); + LLVMSetInitializer(g.value, init.value); var.is_initialized = true; - if (is_rodata) { + if (cc.is_rodata) { LLVMSetGlobalConstant(g.value, true); } } @@ -3344,11 +3372,33 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } else if (e->kind == Entity_Variable && e->Variable.is_rodata) { LLVMSetGlobalConstant(g.value, true); } - array_add(&global_variables, var); - lb_add_entity(m, e, g); - lb_add_member(m, name, g); + lb_apply_thread_local_model(g.value, e->Variable.thread_local_model); + + if (is_foreign) { + LLVMSetLinkage(g.value, LLVMExternalLinkage); + LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass); + LLVMSetExternallyInitialized(g.value, true); + lb_add_foreign_library_path(m, e->Variable.foreign_library); + } else if (LLVMGetInitializer(g.value) == nullptr) { + LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type))); + } + if (is_export) { + LLVMSetLinkage(g.value, LLVMDLLExportLinkage); + LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass); + } else if (!is_foreign) { + LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage); + } + lb_set_linkage_from_entity_flags(m, g.value, e->flags); + LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type)); + + if (e->Variable.link_section.len > 0) { + LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section)); + } + if (e->flags & EntityFlag_Require) { + lb_append_to_compiler_used(m, g.value); + } if (m->debug_builder) { String global_name = e->token.string; @@ -3378,6 +3428,49 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { LLVMGlobalSetMetadata(g.value, 0, global_variable_metadata); } } + + if (default_module == m) { + g.value = LLVMConstPointerCast(g.value, lb_type(m, alloc_type_pointer(e->type))); + + var.var = g; + array_add(&global_variables, var); + } else { + lbValue local_g = {}; + local_g.type = alloc_type_pointer(e->type); + local_g.value = LLVMAddGlobal(default_module->mod, lb_type(default_module, e->type), alloc_cstring(permanent_allocator(), name)); + LLVMSetLinkage(local_g.value, LLVMExternalLinkage); + + var.var = local_g; + array_add(&global_variables, var); + + lb_add_entity(default_module, e, local_g); + lb_add_member(default_module, name, local_g); + } + + lb_add_entity(m, e, g); + lb_add_member(m, name, g); + } + + if (build_context.ODIN_DEBUG) { + // Custom `.raddbg` section for its debugger + if (build_context.metrics.os == TargetOs_windows) { + lbModule *m = default_module; + LLVMModuleRef mod = m->mod; + LLVMContextRef ctx = m->ctx; + + { + LLVMTypeRef type = LLVMArrayType(LLVMInt8TypeInContext(ctx), 1); + LLVMValueRef global = LLVMAddGlobal(mod, type, "raddbg_is_attached_byte_marker"); + LLVMSetInitializer(global, LLVMConstNull(type)); + LLVMSetSection(global, ".raddbg"); + } + + if (gen->info->entry_point) { + String mangled_name = lb_get_entity_name(m, gen->info->entry_point); + char const *str = alloc_cstring(temporary_allocator(), mangled_name); + lb_add_raddbg_string(m, "entry_point: \"", str, "\""); + } + } } TIME_SECTION("LLVM Runtime Objective-C Names Creation"); @@ -3393,7 +3486,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { if (build_context.ODIN_DEBUG) { for (auto const &entry : builtin_pkg->scope->elements) { Entity *e = entry.value; - add_debug_info_for_global_constant_from_entity(gen, e); + lb_add_debug_info_for_global_constant_from_entity(gen, e); } } @@ -3417,12 +3510,101 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { if (gen->objc_names) { TIME_SECTION("Finalize objc names"); - lb_finalize_objc_names(gen->objc_names); + lb_finalize_objc_names(gen, gen->objc_names); } if (build_context.ODIN_DEBUG) { TIME_SECTION("LLVM Debug Info Complete Types and Finalize"); lb_debug_info_complete_types_and_finalize(gen); + + // Custom `.raddbg` section for its debugger + if (build_context.metrics.os == TargetOs_windows) { + lbModule *m = default_module; + LLVMModuleRef mod = m->mod; + LLVMContextRef ctx = m->ctx; + + lb_add_raddbg_string(m, "type_view: {type: \"[]?\", expr: \"array(data, len)\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"string\", expr: \"array(data, len)\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"[dynamic]?\", expr: \"rows($, array(data, len), len, cap, allocator)\"}"); + + // column major matrices + lb_add_raddbg_string(m, "type_view: {type: \"matrix[1, ?]?\", expr: \"columns($.data, $[0])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[2, ?]?\", expr: \"columns($.data, $[0], $[1])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[3, ?]?\", expr: \"columns($.data, $[0], $[1], $[2])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[4, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[5, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[6, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[7, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[8, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[9, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[10, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[11, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[12, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[13, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[14, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[15, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"matrix[16, ?]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}"); + + // row major matrices + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 1]?\", expr: \"columns($.data, $[0])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 2]?\", expr: \"columns($.data, $[0], $[1])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 3]?\", expr: \"columns($.data, $[0], $[1], $[2])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 4]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 5]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 6]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 7]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 8]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 9]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 10]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 11]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 12]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 13]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 14]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 15]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14])\"}"); + lb_add_raddbg_string(m, "type_view: {type: \"#row_major matrix[?, 16]?\", expr: \"columns($.data, $[0], $[1], $[2], $[3], $[4], $[5], $[6], $[7], $[8], $[9], $[10], $[11], $[12], $[13], $[14], $[15])\"}"); + + + TEMPORARY_ALLOCATOR_GUARD(); + for (RaddbgTypeView const &type_view : gen->info->raddbg_type_views) { + if (type_view.type == nullptr) { + continue; + } + + if (type_view.view.len == 0) { + continue; + } + + String t_str = type_to_canonical_string(temporary_allocator(), type_view.type); + + gbString s = gb_string_make(temporary_allocator(), ""); + + s = gb_string_appendc(s, "type_view: {type: \""); + s = gb_string_append_length(s, t_str.text, t_str.len); + s = gb_string_appendc(s, "\", expr: \""); + s = gb_string_append_length(s, type_view.view.text, type_view.view.len); + s = gb_string_appendc(s, "\"}"); + + lb_add_raddbg_string(m, s); + } + + TEMPORARY_ALLOCATOR_GUARD(); + u32 global_name_index = 0; + for (String str = {}; mpsc_dequeue(&gen->raddebug_section_strings, &str); /**/) { + LLVMValueRef data = LLVMConstStringInContext(ctx, cast(char const *)str.text, cast(unsigned)str.len, false); + LLVMTypeRef type = LLVMTypeOf(data); + + gbString global_name = gb_string_make(temporary_allocator(), "raddbg_data__"); + global_name = gb_string_append_fmt(global_name, "%u", global_name_index); + global_name_index += 1; + + LLVMValueRef global = LLVMAddGlobal(mod, type, global_name); + + LLVMSetInitializer(global, data); + LLVMSetAlignment(global, 1); + + LLVMSetSection(global, ".raddbg"); + } + } } if (do_threading) { @@ -3438,15 +3620,23 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } + TIME_SECTION("LLVM Add Foreign Library Paths"); + lb_add_foreign_library_paths(gen); + TIME_SECTION("LLVM Function Pass"); lb_llvm_function_passes(gen, do_threading && !build_context.ODIN_DEBUG); - TIME_SECTION("LLVM Module Pass"); - lb_llvm_module_passes(gen, do_threading); + TIME_SECTION("LLVM Remove Unused Functions and Globals"); + lb_remove_unused_functions_and_globals(gen); - TIME_SECTION("LLVM Module Verification"); - if (!lb_llvm_module_verification(gen, do_threading)) { - return false; + TIME_SECTION("LLVM Module Pass and Verification"); + lb_llvm_module_passes_and_verification(gen, do_threading); + + TIME_SECTION("LLVM Correct Entity Linkage"); + lb_correct_entity_linkage(gen); + + if (build_context.build_diagnostics) { + lb_do_build_diagnostics(gen); } llvm_error = nullptr; @@ -3475,11 +3665,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { } } - TIME_SECTION("LLVM Add Foreign Library Paths"); - lb_add_foreign_library_paths(gen); - - TIME_SECTION("LLVM Correct Entity Linkage"); - lb_correct_entity_linkage(gen); //////////////////////////////////////////// for (auto const &entry: gen->modules) { @@ -3505,36 +3690,48 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { if (build_context.sanitizer_flags & SanitizerFlag_Address) { - if (build_context.metrics.os == TargetOs_windows) { + switch (build_context.metrics.os) { + case TargetOs_windows: { auto paths = array_make(heap_allocator(), 0, 1); String path = concatenate_strings(permanent_allocator(), build_context.ODIN_ROOT, str_lit("\\bin\\llvm\\windows\\clang_rt.asan-x86_64.lib")); array_add(&paths, path); Entity *lib = alloc_entity_library_name(nullptr, make_token_ident("asan_lib"), nullptr, slice_from_array(paths), str_lit("asan_lib")); array_add(&gen->foreign_libraries, lib); - } else if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) { + } break; + case TargetOs_darwin: + case TargetOs_linux: + case TargetOs_freebsd: if (!build_context.extra_linker_flags.text) { build_context.extra_linker_flags = str_lit("-fsanitize=address"); } else { build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=address")); } + break; } } if (build_context.sanitizer_flags & SanitizerFlag_Memory) { - if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) { + switch (build_context.metrics.os) { + case TargetOs_linux: + case TargetOs_freebsd: if (!build_context.extra_linker_flags.text) { build_context.extra_linker_flags = str_lit("-fsanitize=memory"); } else { build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=memory")); } + break; } } if (build_context.sanitizer_flags & SanitizerFlag_Thread) { - if (build_context.metrics.os == TargetOs_darwin || build_context.metrics.os == TargetOs_linux) { + switch (build_context.metrics.os) { + case TargetOs_darwin: + case TargetOs_linux: + case TargetOs_freebsd: if (!build_context.extra_linker_flags.text) { build_context.extra_linker_flags = str_lit("-fsanitize=thread"); } else { build_context.extra_linker_flags = concatenate_strings(permanent_allocator(), build_context.extra_linker_flags, str_lit(" -fsanitize=thread")); } + break; } } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 4fd1b8d1a..6870f6259 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -143,18 +143,17 @@ struct lbPadType { LLVMTypeRef type; }; -struct lbObjcRef { - Entity * entity; - lbAddr local_module_addr; -}; - struct lbModule { LLVMModuleRef mod; LLVMContextRef ctx; + Checker *checker; + struct lbGenerator *gen; LLVMTargetMachineRef target_machine; + lbModule *polymorphic_module; + CheckerInfo *info; AstPackage *pkg; // possibly associated AstFile *file; // possibly associated @@ -176,18 +175,23 @@ struct lbModule { StringMap members; StringMap procedures; PtrMap procedure_values; - Array missing_procedures_to_check; - StringMap const_strings; + MPSCQueue missing_procedures_to_check; + + StringMap const_strings; + String16Map const_string16s; PtrMap function_type_map; StringMap gen_procs; // key is the canonicalized name - Array procedures_to_generate; + MPSCQueue procedures_to_generate; Array global_procedures_to_create; Array global_types_to_create; + BlockingMutex generated_procedures_mutex; + Array generated_procedures; + lbProcedure *curr_procedure; LLVMBuilderRef const_dummy_builder; @@ -198,8 +202,11 @@ struct lbModule { RecursiveMutex debug_values_mutex; PtrMap debug_values; - StringMap objc_classes; - StringMap objc_selectors; + + StringMap objc_classes; + StringMap objc_selectors; + StringMap objc_ivars; + isize objc_next_block_id; // Used to name objective-c blocks, per module PtrMap map_cell_info_map; // address of runtime.Map_Info PtrMap map_info_map; // address of runtime.Map_Cell_Info @@ -218,6 +225,14 @@ struct lbEntityCorrection { char const *cname; }; +struct lbObjCGlobal { + lbModule *module; + gbString global_name; + String name; + Type * type; + Type * class_impl_type; // This is set when the class has the objc_implement attribute set to true. +}; + struct lbGenerator : LinkerData { CheckerInfo *info; @@ -225,8 +240,7 @@ struct lbGenerator : LinkerData { PtrMap modules_through_ctx; lbModule default_module; - RecursiveMutex anonymous_proc_lits_mutex; - PtrMap anonymous_proc_lits; + lbModule *equal_module; isize used_module_count; @@ -235,6 +249,10 @@ struct lbGenerator : LinkerData { lbProcedure *objc_names; MPSCQueue entities_to_correct_linkage; + MPSCQueue objc_selectors; + MPSCQueue objc_classes; + MPSCQueue objc_ivars; + MPSCQueue raddebug_section_strings; }; @@ -318,6 +336,14 @@ struct lbVariadicReuseSlices { lbAddr slice_addr; }; +struct lbGlobalVariable { + lbValue var; + lbValue init; + DeclInfo *decl; + bool is_initialized; +}; + + struct lbProcedure { u32 flags; u16 state_flags; @@ -340,9 +366,9 @@ struct lbProcedure { lbFunctionType *abi_function_type; - LLVMValueRef value; - LLVMBuilderRef builder; - bool is_done; + LLVMValueRef value; + LLVMBuilderRef builder; + std::atomic is_done; lbAddr return_ptr; Array defer_stmts; @@ -378,6 +404,14 @@ struct lbProcedure { PtrMap selector_values; PtrMap selector_addr; PtrMap tuple_fix_map; + + Array asan_stack_locals; + + void (*generate_body)(lbModule *m, lbProcedure *p); + Array *global_variables; + lbProcedure *objc_names; + + Type *internal_gen_type; // map_set, map_get, etc. }; @@ -402,7 +436,6 @@ gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef c gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value); gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name); gb_internal lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false); -gb_internal void lb_end_procedure(lbProcedure *p); gb_internal LLVMTypeRef lb_type(lbModule *m, Type *type); @@ -410,9 +443,19 @@ gb_internal LLVMTypeRef llvm_get_element_type(LLVMTypeRef type); gb_internal lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false); +struct lbConstContext { + bool allow_local; + bool is_rodata; + String link_section; +}; + +static lbConstContext const LB_CONST_CONTEXT_DEFAULT = {true, false, {}}; +static lbConstContext const LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL = {true, false, {}}; +static lbConstContext const LB_CONST_CONTEXT_DEFAULT_NO_LOCAL = {false, false, {}}; + gb_internal lbValue lb_const_nil(lbModule *m, Type *type); gb_internal lbValue lb_const_undef(lbModule *m, Type *type); -gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local=true, bool is_rodata=false); +gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT, Type *value_type=nullptr); gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value); gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value); @@ -462,7 +505,10 @@ gb_internal void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, l gb_internal void lb_start_block(lbProcedure *p, lbBlock *b); gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr); - +gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type); +gb_internal void lb_begin_procedure_body(lbProcedure *p); +gb_internal void lb_end_procedure_body(lbProcedure *p); +gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, ProcInlining inlining); gb_internal lbAddr lb_find_or_generate_context_ptr(lbProcedure *p); gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx); @@ -509,7 +555,7 @@ gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base gb_internal lbValue lb_type_info(lbProcedure *p, Type *type); -gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str); +gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str, bool custom_link_section); gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent = nullptr); gb_internal bool lb_is_const(lbValue value); @@ -558,7 +604,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As gb_internal lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block); gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_); -gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_); +gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeRef t, LLVMValueRef *values, isize value_count_); gb_internal void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name); gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index b916c0017..193bffe08 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -33,7 +33,7 @@ gb_internal bool lb_is_elem_const(Ast *elem, Type *elem_type) { gb_internal bool lb_is_const_nil(lbValue value) { LLVMValueRef v = value.value; - if (LLVMIsConstant(v)) { + if (v != nullptr && LLVMIsConstant(v)) { if (LLVMIsAConstantAggregateZero(v)) { return true; } else if (LLVMIsAConstantPointerNull(v)) { @@ -81,7 +81,7 @@ gb_internal String lb_get_const_string(lbModule *m, lbValue value) { } -gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) { +gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst, bool *failure_) { LLVMTypeRef src = LLVMTypeOf(val); if (src == dst) { return val; @@ -96,15 +96,12 @@ gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) { case LLVMPointerTypeKind: return LLVMConstPointerCast(val, dst); case LLVMStructTypeKind: - // GB_PANIC("%s -> %s", LLVMPrintValueToString(val), LLVMPrintTypeToString(dst)); - // NOTE(bill): It's not possible to do a bit cast on a struct, why was this code even here in the first place? - // It seems mostly to exist to get around the "anonymous -> named" struct assignments - // return LLVMConstBitCast(val, dst); + if (LLVMTypeOf(val) != dst) { + if (failure_) *failure_ = true; + } return val; - default: - GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst)); } - + if (failure_) *failure_ = true; return val; } @@ -122,19 +119,38 @@ gb_internal lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) { gb_internal LLVMValueRef llvm_const_string_internal(lbModule *m, Type *t, LLVMValueRef data, LLVMValueRef len) { + GB_ASSERT(!is_type_string16(t)); if (build_context.metrics.ptr_size < build_context.metrics.int_size) { LLVMValueRef values[3] = { data, LLVMConstNull(lb_type(m, t_i32)), len, }; - return llvm_const_named_struct_internal(lb_type(m, t), values, 3); + return llvm_const_named_struct_internal(m, lb_type(m, t), values, 3); } else { LLVMValueRef values[2] = { data, len, }; - return llvm_const_named_struct_internal(lb_type(m, t), values, 2); + return llvm_const_named_struct_internal(m, lb_type(m, t), values, 2); + } +} + +gb_internal LLVMValueRef llvm_const_string16_internal(lbModule *m, Type *t, LLVMValueRef data, LLVMValueRef len) { + GB_ASSERT(is_type_string16(t)); + if (build_context.metrics.ptr_size < build_context.metrics.int_size) { + LLVMValueRef values[3] = { + data, + LLVMConstNull(lb_type(m, t_i32)), + len, + }; + return llvm_const_named_struct_internal(m, lb_type(m, t), values, 3); + } else { + LLVMValueRef values[2] = { + data, + len, + }; + return llvm_const_named_struct_internal(m, lb_type(m, t), values, 2); } } @@ -146,10 +162,10 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue unsigned value_count = cast(unsigned)value_count_; unsigned elem_count = LLVMCountStructElementTypes(struct_type); if (elem_count == value_count) { - return llvm_const_named_struct_internal(struct_type, values, value_count_); + return llvm_const_named_struct_internal(m, struct_type, values, value_count_); } Type *bt = base_type(t); - GB_ASSERT(bt->kind == Type_Struct); + GB_ASSERT(bt->kind == Type_Struct || bt->kind == Type_Union); GB_ASSERT(value_count_ == bt->Struct.fields.count); @@ -166,25 +182,40 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue } } - return llvm_const_named_struct_internal(struct_type, values_with_padding, values_with_padding_count); + return llvm_const_named_struct_internal(m, struct_type, values_with_padding, values_with_padding_count); } -gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) { +gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeRef t, LLVMValueRef *values, isize value_count_) { unsigned value_count = cast(unsigned)value_count_; unsigned elem_count = LLVMCountStructElementTypes(t); GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count); + bool failure = false; for (unsigned i = 0; i < elem_count; i++) { LLVMTypeRef elem_type = LLVMStructGetTypeAtIndex(t, i); - values[i] = llvm_const_cast(values[i], elem_type); + values[i] = llvm_const_cast(values[i], elem_type, &failure); + } + + if (failure) { + return LLVMConstStructInContext(m->ctx, values, value_count, true); } return LLVMConstNamedStruct(t, values, value_count); } -gb_internal LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) { +gb_internal LLVMValueRef llvm_const_array(lbModule *m, LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) { unsigned value_count = cast(unsigned)value_count_; + bool failure = false; for (unsigned i = 0; i < value_count; i++) { - values[i] = llvm_const_cast(values[i], elem_type); + values[i] = llvm_const_cast(values[i], elem_type, &failure); } + if (failure) { + return LLVMConstStructInContext(m->ctx, values, value_count, false); + } + for (unsigned i = 0; i < value_count; i++) { + if (elem_type != LLVMTypeOf(values[i])) { + return LLVMConstStructInContext(m->ctx, values, value_count, false); + } + } + return LLVMConstArray(elem_type, values, value_count); } @@ -238,6 +269,10 @@ gb_internal lbValue lb_const_string(lbModule *m, String const &value) { return lb_const_value(m, t_string, exact_value_string(value)); } +gb_internal lbValue lb_const_string(lbModule *m, String16 const &value) { + return lb_const_value(m, t_string16, exact_value_string16(value)); +} + gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value) { lbValue res = {}; @@ -292,19 +327,33 @@ gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String cons i32 line = pos.line; i32 column = pos.column; - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: file = obfuscate_string(file, "F"); procedure = obfuscate_string(procedure, "P"); - line = obfuscate_i32(line); - column = obfuscate_i32(column); + line = obfuscate_i32(line); + column = obfuscate_i32(column); + break; + case SourceCodeLocationInfo_Filename: + file = last_path_element(file); + break; + case SourceCodeLocationInfo_None: + file = str_lit(""); + procedure = str_lit(""); + + line = 0; + column = 0; + break; } LLVMValueRef fields[4] = {}; - fields[0]/*file*/ = lb_find_or_add_entity_string(m, file).value; + fields[0]/*file*/ = lb_find_or_add_entity_string(m, file, false).value; fields[1]/*line*/ = lb_const_int(m, t_i32, line).value; fields[2]/*column*/ = lb_const_int(m, t_i32, column).value; - fields[3]/*procedure*/ = lb_find_or_add_entity_string(m, procedure).value; + fields[3]/*procedure*/ = lb_find_or_add_entity_string(m, procedure, false).value; lbValue res = {}; res.value = llvm_const_named_struct(m, t_source_code_location, fields, gb_count_of(fields)); @@ -391,12 +440,12 @@ gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, Ast * -gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, bool allow_local, bool is_rodata) { - if (allow_local) { - is_rodata = false; +gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, lbConstContext cc) { + if (cc.allow_local) { + cc.is_rodata = false; } - bool is_local = allow_local && m->curr_procedure != nullptr; + bool is_local = cc.allow_local && m->curr_procedure != nullptr; bool is_const = true; if (is_local) { for (isize i = 0; i < count; i++) { @@ -424,7 +473,7 @@ gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, return lb_addr_load(p, v).value; } - return llvm_const_array(lb_type(m, elem_type), values, cast(unsigned int)count); + return llvm_const_array(m, lb_type(m, elem_type), values, cast(unsigned int)count); } gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) { @@ -494,15 +543,15 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel, } - if (is_type_raw_union(ft) || is_type_typeid(ft)) { + if (is_type_raw_union(ft)) { return false; } return lb_is_elem_const(elem, ft); } -gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local, bool is_rodata) { - if (allow_local) { - is_rodata = false; +gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc, Type *value_type) { + if (cc.allow_local) { + cc.is_rodata = false; } LLVMContextRef ctx = m->ctx; @@ -515,12 +564,101 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo type = core_type(type); value = convert_exact_value_for_type(value, type); - if (value.kind == ExactValue_Typeid) { - return lb_typeid(m, value.value_typeid); - } + bool is_local = cc.allow_local && m->curr_procedure != nullptr; - if (value.kind == ExactValue_Invalid) { - return lb_const_nil(m, original_type); + if (is_type_union(type) && is_type_union_constantable(type)) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + if (bt->Union.variants.count == 0) { + return lb_const_nil(m, original_type); + } else if (bt->Union.variants.count == 1) { + Type *t = bt->Union.variants[0]; + lbValue cv = lb_const_value(m, t, value, cc); + GB_ASSERT(LLVMIsConstant(cv.value)); + + LLVMTypeRef llvm_type = lb_type(m, original_type); + + if (is_type_union_maybe_pointer(type)) { + LLVMValueRef values[1] = {cv.value}; + res.value = llvm_const_named_struct_internal(m, llvm_type, values, 1); + res.type = original_type; + return res; + } else { + + unsigned tag_value = 1; + if (bt->Union.kind == UnionType_no_nil) { + tag_value = 0; + } + LLVMValueRef tag = LLVMConstInt(LLVMStructGetTypeAtIndex(llvm_type, 1), tag_value, false); + LLVMValueRef padding = nullptr; + LLVMValueRef values[3] = {cv.value, tag, padding}; + + isize value_count = 2; + if (LLVMCountStructElementTypes(llvm_type) > 2) { + value_count = 3; + padding = LLVMConstNull(LLVMStructGetTypeAtIndex(llvm_type, 2)); + } + res.value = llvm_const_named_struct_internal(m, llvm_type, values, value_count); + res.type = original_type; + return res; + } + } else { + if (value_type == nullptr) { + if (value.kind == ExactValue_Compound) { + ast_node(cl, CompoundLit, value.value_compound); + if (cl->elems.count == 0) { + return lb_const_nil(m, original_type); + } + } else if (value.kind == ExactValue_Invalid) { + return lb_const_nil(m, original_type); + } + } + + GB_ASSERT_MSG(value_type != nullptr, "%s :: %s", type_to_string(original_type), exact_value_to_string(value)); + + i64 block_size = bt->Union.variant_block_size; + + if (are_types_identical(value_type, original_type)) { + if (value.kind == ExactValue_Compound) { + ast_node(cl, CompoundLit, value.value_compound); + if (cl->elems.count == 0) { + return lb_const_nil(m, original_type); + } + } else if (value.kind == ExactValue_Invalid) { + return lb_const_nil(m, original_type); + } + + GB_PANIC("%s vs %s", type_to_string(value_type), type_to_string(original_type)); + } + + lbValue cv = lb_const_value(m, value_type, value, cc, value_type); + Type *variant_type = cv.type; + + LLVMValueRef values[4] = {}; + unsigned value_count = 0; + + values[value_count++] = cv.value; + if (type_size_of(variant_type) != block_size) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, block_size - type_size_of(variant_type), 1); + values[value_count++] = LLVMConstNull(padding_type); + } + + Type *tag_type = union_tag_type(bt); + LLVMTypeRef llvm_tag_type = lb_type(m, tag_type); + i64 tag_index = union_variant_index(bt, variant_type); + GB_ASSERT(tag_index >= 0); + values[value_count++] = LLVMConstInt(llvm_tag_type, tag_index, false); + i64 used_size = block_size + type_size_of(tag_type); + i64 union_size = type_size_of(bt); + i64 padding = union_size - used_size; + if (padding > 0) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, 1); + values[value_count++] = LLVMConstNull(padding_type); + } + + res.value = LLVMConstStructInContext(m->ctx, values, value_count, true); + return res; + } } if (value.kind == ExactValue_Procedure) { @@ -533,7 +671,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo Entity *e = entity_from_expr(expr); res = lb_find_procedure_value_from_entity(m, e); } - GB_ASSERT(res.value != nullptr); + if (res.value == nullptr) { + // This is an unspecialized polymorphic procedure, return nil or dummy value + return lb_const_nil(m, original_type); + } GB_ASSERT(LLVMGetValueKind(res.value) == LLVMFunctionValueKind); if (LLVMGetIntrinsicID(res.value) == 0) { @@ -543,7 +684,23 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo return res; } - bool is_local = allow_local && m->curr_procedure != nullptr; + // NOTE(bill): This has to be done AFTER the union stuff + if (value.kind == ExactValue_Invalid) { + return lb_const_nil(m, original_type); + } + + + if (value.kind == ExactValue_Typeid) { + return lb_typeid(m, value.value_typeid); + } + + if (value.kind == ExactValue_Compound) { + ast_node(cl, CompoundLit, value.value_compound); + if (cl->elems.count == 0) { + return lb_const_nil(m, original_type); + } + } + // GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type)); @@ -552,6 +709,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT(is_type_slice(type)); res.value = lb_find_or_add_entity_string_byte_slice_with_type(m, value.value_string, original_type).value; return res; + } else if (value.kind == ExactValue_String16) { + GB_ASSERT(is_type_slice(type)); + res.value = lb_find_or_add_entity_string16_slice_with_type(m, value.value_string16, original_type).value; + return res; } else { ast_node(cl, CompoundLit, value.value_compound); @@ -562,19 +723,39 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo count = gb_max(cast(isize)cl->max_count, count); Type *elem = base_type(type)->Slice.elem; Type *t = alloc_type_array(elem, count); - lbValue backing_array = lb_const_value(m, t, value, allow_local, is_rodata); + lbValue backing_array = lb_const_value(m, t, value, cc, nullptr); LLVMValueRef array_data = nullptr; + if (is_local) { // NOTE(bill, 2020-06-08): This is a bit of a hack but a "constant" slice needs // its backing data on the stack lbProcedure *p = m->curr_procedure; LLVMTypeRef llvm_type = lb_type(m, t); - array_data = llvm_alloca(p, llvm_type, 16); + unsigned alignment = cast(unsigned)gb_max(type_align_of(t), 16); + + + bool do_local_copy = false; + if (do_local_copy) { + array_data = llvm_alloca(p, llvm_type, alignment); + + LLVMValueRef local_copy = llvm_alloca(p, LLVMTypeOf(backing_array.value), alignment); + LLVMBuildStore(p->builder, backing_array.value, local_copy); + + LLVMBuildMemCpy(p->builder, + array_data, alignment, + local_copy, alignment, + LLVMConstInt(lb_type(m, t_int), type_size_of(t), false) + ); + } else { + array_data = llvm_alloca(p, LLVMTypeOf(backing_array.value), alignment); + LLVMBuildStore(p->builder, backing_array.value, array_data); + + array_data = LLVMBuildPointerCast(p->builder, array_data, LLVMPointerType(llvm_type, 0), ""); + } - LLVMBuildStore(p->builder, backing_array.value, array_data); { LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; @@ -596,23 +777,25 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo String name = make_string(cast(u8 const *)str, gb_string_length(str)); Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value); - array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str); + array_data = LLVMAddGlobal(m->mod, LLVMTypeOf(backing_array.value), str); LLVMSetInitializer(array_data, backing_array.value); - if (is_rodata) { + if (cc.link_section.len > 0) { + LLVMSetSection(array_data, alloc_cstring(permanent_allocator(), cc.link_section)); + } + if (cc.is_rodata) { LLVMSetGlobalConstant(array_data, true); } lbValue g = {}; - g.value = array_data; + g.value = LLVMConstPointerCast(array_data, LLVMPointerType(lb_type(m, t), 0)); g.type = t; lb_add_entity(m, e, g); lb_add_member(m, name, g); { - LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; - LLVMValueRef ptr = LLVMConstInBoundsGEP2(lb_type(m, t), array_data, indices, 2); + LLVMValueRef ptr = g.value; LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); LLVMValueRef values[2] = {ptr, len}; @@ -645,12 +828,12 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } GB_ASSERT(offset == s.len); - res.value = llvm_const_array(et, elems, cast(unsigned)count); + res.value = llvm_const_array(m, et, elems, cast(unsigned)count); return res; } // NOTE(bill, 2021-10-07): Allow for array programming value constants Type *core_elem = core_array_type(type); - return lb_const_value(m, core_elem, value, allow_local, is_rodata); + return lb_const_value(m, core_elem, value, cc); } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { GB_ASSERT(type->Array.count == value.value_string.len); LLVMValueRef data = LLVMConstStringInContext(ctx, @@ -668,14 +851,14 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo Type *elem = type->Array.elem; - lbValue single_elem = lb_const_value(m, elem, value, allow_local, is_rodata); + lbValue single_elem = lb_const_value(m, elem, value, cc); LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)count); for (i64 i = 0; i < count; i++) { elems[i] = single_elem.value; } - res.value = llvm_const_array(lb_type(m, elem), elems, cast(unsigned)count); + res.value = llvm_const_array(m, lb_type(m, elem), elems, cast(unsigned)count); return res; } else if (is_type_matrix(type) && value.kind != ExactValue_Invalid && @@ -686,8 +869,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo Type *elem = type->Matrix.elem; - lbValue single_elem = lb_const_value(m, elem, value, allow_local, is_rodata); - single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem)); + lbValue single_elem = lb_const_value(m, elem, value, cc); + single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem), /*failure_*/nullptr); i64 total_elem_count = matrix_type_total_internal_elems(type); LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)total_elem_count); @@ -708,8 +891,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i64 count = type->SimdVector.count; Type *elem = type->SimdVector.elem; - lbValue single_elem = lb_const_value(m, elem, value, allow_local, is_rodata); - single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem)); + lbValue single_elem = lb_const_value(m, elem, value, cc); + single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem), /*failure_*/nullptr); LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count); for (i64 i = 0; i < count; i++) { @@ -729,24 +912,80 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo return res; case ExactValue_String: { - LLVMValueRef ptr = lb_find_or_add_entity_string_ptr(m, value.value_string); + bool custom_link_section = cc.link_section.len > 0; + + LLVMValueRef ptr = nullptr; lbValue res = {}; res.type = default_type(original_type); - if (is_type_cstring(res.type)) { + + isize len = value.value_string.len; + + if (is_type_string16(res.type) || is_type_cstring16(res.type)) { + TEMPORARY_ALLOCATOR_GUARD(); + String16 s16 = string_to_string16(temporary_allocator(), value.value_string); + len = s16.len; + ptr = lb_find_or_add_entity_string16_ptr(m, s16, custom_link_section); + } else { + ptr = lb_find_or_add_entity_string_ptr(m, value.value_string, custom_link_section); + } + + if (custom_link_section) { + LLVMSetSection(ptr, alloc_cstring(permanent_allocator(), cc.link_section)); + } + + if (is_type_cstring(res.type) || is_type_cstring16(res.type)) { res.value = ptr; } else { - if (value.value_string.len == 0) { - ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); + if (len == 0) { + if (is_type_string16(res.type)) { + ptr = LLVMConstNull(lb_type(m, t_u16_ptr)); + } else { + ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); + } } - LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), value.value_string.len, true); + LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), len, true); GB_ASSERT(is_type_string(original_type)); - res.value = llvm_const_string_internal(m, original_type, ptr, str_len); + if (is_type_string16(res.type)) { + res.value = llvm_const_string16_internal(m, original_type, ptr, str_len); + } else { + res.value = llvm_const_string_internal(m, original_type, ptr, str_len); + } } return res; } + case ExactValue_String16: + { + GB_ASSERT(is_type_string16(res.type) || is_type_cstring16(res.type)); + + bool custom_link_section = cc.link_section.len > 0; + + LLVMValueRef ptr = lb_find_or_add_entity_string16_ptr(m, value.value_string16, custom_link_section); + lbValue res = {}; + res.type = default_type(original_type); + + if (custom_link_section) { + LLVMSetSection(ptr, alloc_cstring(permanent_allocator(), cc.link_section)); + } + + if (is_type_cstring16(res.type)) { + res.value = ptr; + } else { + if (value.value_string16.len == 0) { + ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); + } + LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), value.value_string16.len, true); + GB_ASSERT(is_type_string(original_type)); + + res.value = llvm_const_string16_internal(m, original_type, ptr, str_len); + } + + return res; + } + + case ExactValue_Integer: if (is_type_pointer(type) || is_type_multi_pointer(type) || is_type_proc(type)) { LLVMTypeRef t = lb_type(m, original_type); @@ -837,7 +1076,149 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo case ExactValue_Compound: if (is_type_slice(type)) { - return lb_const_value(m, type, value, allow_local, is_rodata); + return lb_const_value(m, type, value, cc); + } else if (is_type_soa_struct(type)) { + GB_ASSERT(type->kind == Type_Struct); + GB_ASSERT(type->Struct.soa_kind == StructSoa_Fixed); + ast_node(cl, CompoundLit, value.value_compound); + Type *elem_type = type->Struct.soa_elem; + isize elem_count = cl->elems.count; + if (elem_count == 0 || !elem_type_can_be_constant(elem_type)) { + return lb_const_nil(m, original_type); + } + if (cl->elems[0]->kind == Ast_FieldValue) { + TEMPORARY_ALLOCATOR_GUARD(); + + // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand + + isize elem_count = cast(isize)type->Struct.soa_count; + + LLVMValueRef *aos_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count); + + isize value_index = 0; + for (i64 i = 0; i < elem_count; i++) { + bool found = false; + + for (isize j = 0; j < elem_count; j++) { + Ast *elem = cl->elems[j]; + ast_node(fv, FieldValue, elem); + if (is_ast_range(fv->field)) { + ast_node(ie, BinaryExpr, fv->field); + TypeAndValue lo_tav = ie->left->tav; + TypeAndValue hi_tav = ie->right->tav; + GB_ASSERT(lo_tav.mode == Addressing_Constant); + GB_ASSERT(hi_tav.mode == Addressing_Constant); + + TokenKind op = ie->op.kind; + i64 lo = exact_value_to_i64(lo_tav.value); + i64 hi = exact_value_to_i64(hi_tav.value); + if (op != Token_RangeHalf) { + hi += 1; + } + if (lo == i) { + TypeAndValue tav = fv->value->tav; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; + for (i64 k = lo; k < hi; k++) { + aos_values[value_index++] = val; + } + + found = true; + i += (hi-lo-1); + break; + } + } else { + TypeAndValue index_tav = fv->field->tav; + GB_ASSERT(index_tav.mode == Addressing_Constant); + i64 index = exact_value_to_i64(index_tav.value); + if (index == i) { + TypeAndValue tav = fv->value->tav; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; + aos_values[value_index++] = val; + found = true; + break; + } + } + } + + if (!found) { + aos_values[value_index++] = nullptr; + } + } + + + isize field_count = type->Struct.fields.count; + LLVMValueRef *soa_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, field_count); + + for (isize i = 0; i < field_count; i++) { + TEMPORARY_ALLOCATOR_GUARD(); + + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count); + + Entity *f = type->Struct.fields[i]; + Type *array_type = f->type; + GB_ASSERT(array_type->kind == Type_Array); + Type *field_type = array_type->Array.elem; + + for (isize j = 0; j < elem_count; j++) { + LLVMValueRef v = aos_values[j]; + if (v != nullptr) { + values[j] = llvm_const_extract_value(m, v, cast(unsigned)i); + } else { + values[j] = LLVMConstNull(lb_type(m, field_type)); + } + } + + soa_values[i] = lb_build_constant_array_values(m, array_type, field_type, elem_count, values, cc); + } + + res.value = llvm_const_named_struct(m, type, soa_values, field_count); + return res; + } else { + GB_ASSERT_MSG(elem_count == type->Struct.soa_count, "%td != %td", elem_count, type->Struct.soa_count); + + TEMPORARY_ALLOCATOR_GUARD(); + + isize elem_count = cast(isize)type->Struct.soa_count; + + LLVMValueRef *aos_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count); + + for (isize i = 0; i < elem_count; i++) { + TypeAndValue tav = cl->elems[i]->tav; + GB_ASSERT(tav.mode != Addressing_Invalid); + aos_values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; + } + for (isize i = elem_count; i < type->Struct.soa_count; i++) { + aos_values[i] = nullptr; + } + + isize field_count = type->Struct.fields.count; + LLVMValueRef *soa_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, field_count); + + for (isize i = 0; i < field_count; i++) { + TEMPORARY_ALLOCATOR_GUARD(); + + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, elem_count); + + Entity *f = type->Struct.fields[i]; + Type *array_type = f->type; + GB_ASSERT(array_type->kind == Type_Array); + Type *field_type = array_type->Array.elem; + + for (isize j = 0; j < elem_count; j++) { + LLVMValueRef v = aos_values[j]; + if (v != nullptr) { + values[j] = llvm_const_extract_value(m, v, cast(unsigned)i); + } else { + values[j] = LLVMConstNull(lb_type(m, field_type)); + } + } + + soa_values[i] = lb_build_constant_array_values(m, array_type, field_type, elem_count, values, cc); + } + + res.value = llvm_const_named_struct(m, type, soa_values, field_count); + return res; + } } else if (is_type_array(type)) { ast_node(cl, CompoundLit, value.value_compound); Type *elem_type = type->Array.elem; @@ -871,7 +1252,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -886,7 +1267,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; values[value_index++] = val; found = true; break; @@ -899,9 +1280,20 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); + return res; + } else if (are_types_identical(value.value_compound->tav.type, elem_type)) { + // Compound is of array item type; expand its value to all items in array. + LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); + + for (isize i = 0; i < type->Array.count; i++) { + values[i] = lb_const_value(m, elem_type, value, cc, elem_type).value; + } + + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); return res; } else { + // Assume that compound value is an array literal GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count); @@ -909,13 +1301,13 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = elem_count; i < type->Array.count; i++) { values[i] = LLVMConstNull(lb_type(m, elem_type)); } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc); return res; } } else if (is_type_enumerated_array(type)) { @@ -955,7 +1347,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -970,7 +1362,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; values[value_index++] = val; found = true; break; @@ -983,7 +1375,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, cc); return res; } else { GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count); @@ -993,13 +1385,13 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = elem_count; i < type->EnumeratedArray.count; i++) { values[i] = LLVMConstNull(lb_type(m, elem_type)); } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, cc); return res; } } else if (is_type_simd_vector(type)) { @@ -1038,7 +1430,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } if (lo == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { values[value_index++] = val; } @@ -1053,7 +1445,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i64 index = exact_value_to_i64(index_tav.value); if (index == i) { TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; values[value_index++] = val; found = true; break; @@ -1072,7 +1464,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; GB_ASSERT(tav.mode != Addressing_Invalid); - values[i] = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } LLVMTypeRef et = lb_type(m, elem_type); @@ -1080,7 +1472,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo values[i] = LLVMConstNull(et); } for (isize i = 0; i < total_elem_count; i++) { - values[i] = llvm_const_cast(values[i], et); + values[i] = llvm_const_cast(values[i], et, /*failure_*/nullptr); } res.value = LLVMConstVector(values, cast(unsigned)total_elem_count); @@ -1094,6 +1486,39 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } if (is_type_raw_union(type)) { + if (is_type_raw_union_constantable(type)) { + GB_ASSERT(cl->elems.count == 1); + GB_ASSERT(cl->elems[0]->kind == Ast_FieldValue); + ast_node(fv, FieldValue, cl->elems[0]); + Entity *f = entity_of_node(fv->field); + + TypeAndValue tav = fv->value->tav; + if (tav.value.kind != ExactValue_Invalid) { + lbValue value = lb_const_value(m, f->type, tav.value, cc, f->type); + + LLVMValueRef values[2]; + unsigned value_count = 0; + + values[value_count++] = value.value; + + i64 union_alignment = type_align_of(type); + i64 value_alignment = type_align_of(f->type); + i64 alignment = gb_max(gb_min(value_alignment, union_alignment), 1); + + i64 union_size = type_size_of(type); + i64 value_size = lb_sizeof(LLVMTypeOf(value.value)); + i64 padding = union_size-value_size; + if (padding > 0) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, alignment); + values[value_count++] = LLVMConstNull(padding_type); + } + + LLVMValueRef res = LLVMConstStructInContext(m->ctx, values, value_count, /*packed*/padding > 0); + + return {res, original_type}; + } + + } return lb_const_nil(m, original_type); } @@ -1121,14 +1546,20 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i32 index = field_remapping[f->Variable.field_index]; if (elem_type_can_be_constant(f->type)) { if (sel.index.count == 1) { - values[index] = lb_const_value(m, f->type, tav.value, allow_local, is_rodata).value; + lbValue value = lb_const_value(m, f->type, tav.value, cc, tav.type); + LLVMTypeRef value_type = LLVMTypeOf(value.value); + GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type)); + values[index] = value.value; visited[index] = true; } else { if (!visited[index]) { - values[index] = lb_const_value(m, f->type, {}, false).value; + auto new_cc = cc; + new_cc.allow_local = false; + values[index] = lb_const_value(m, f->type, {}, new_cc).value; visited[index] = true; } + unsigned idx_list_len = cast(unsigned)sel.index.count-1; unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len); @@ -1139,6 +1570,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i32 index = sel.index[j]; Type *cvt = base_type(cv_type); + if (cvt->kind == Type_Struct) { if (cvt->Struct.is_raw_union) { // sanity check which should have been caught by `lb_is_nested_possibly_constant` @@ -1163,9 +1595,41 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } if (is_constant) { - LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local, is_rodata).value; - if (LLVMIsConstant(elem_value)) { + LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc, tav.type).value; + if (LLVMIsConstant(elem_value) && LLVMIsConstant(values[index])) { values[index] = llvm_const_insert_value(m, values[index], elem_value, idx_list, idx_list_len); + } else if (is_local) { + #if 1 + lbProcedure *p = m->curr_procedure; + GB_ASSERT(p != nullptr); + if (LLVMIsConstant(values[index])) { + lbAddr addr = lb_add_local_generated(p, f->type, false); + lb_addr_store(p, addr, lbValue{values[index], f->type}); + values[index] = lb_addr_load(p, addr).value; + } + + GB_ASSERT(LLVMIsALoadInst(values[index])); + + LLVMValueRef ptr = LLVMGetOperand(values[index], 0); + + LLVMValueRef *indices = gb_alloc_array(temporary_allocator(), LLVMValueRef, idx_list_len); + LLVMTypeRef lt_u32 = lb_type(m, t_u32); + for (unsigned i = 0; i < idx_list_len; i++) { + indices[i] = LLVMConstInt(lt_u32, idx_list[i], false); + } + + ptr = LLVMBuildGEP2(p->builder, lb_type(m, f->type), ptr, indices, idx_list_len, ""); + ptr = LLVMBuildPointerCast(p->builder, ptr, lb_type(m, alloc_type_pointer(tav.type)), ""); + + if (LLVMIsALoadInst(elem_value)) { + i64 sz = type_size_of(tav.type); + LLVMValueRef src = LLVMGetOperand(elem_value, 0); + lb_mem_copy_non_overlapping(p, {ptr, t_rawptr}, {src, t_rawptr}, lb_const_int(m, t_int, sz), false); + } else { + LLVMBuildStore(p->builder, elem_value, ptr); + } + #endif + is_constant = false; } else { is_constant = false; } @@ -1185,7 +1649,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i32 index = field_remapping[f->Variable.field_index]; if (elem_type_can_be_constant(f->type)) { - values[index] = lb_const_value(m, f->type, val, allow_local, is_rodata).value; + lbValue value = lb_const_value(m, f->type, tav.value, cc, tav.type); + LLVMTypeRef value_type = LLVMTypeOf(value.value); + GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type)); + values[index] = value.value; visited[index] = true; } } @@ -1205,13 +1672,15 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef val = values[i]; if (!LLVMIsConstant(val)) { GB_ASSERT(is_local); - GB_ASSERT(LLVMGetInstructionOpcode(val) == LLVMLoad); + GB_ASSERT(LLVMIsALoadInst(val)); is_constant = false; } } if (is_constant) { - res.value = llvm_const_named_struct_internal(struct_type, values, cast(unsigned)value_count); + res.value = llvm_const_named_struct_internal(m, struct_type, values, cast(unsigned)value_count); + LLVMTypeRef res_type = LLVMTypeOf(res.value); + GB_ASSERT(lb_sizeof(res_type) == lb_sizeof(struct_type)); return res; } else { // TODO(bill): THIS IS HACK BUT IT WORKS FOR WHAT I NEED @@ -1225,7 +1694,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo new_values[i] = LLVMConstNull(LLVMTypeOf(old_value)); } } - LLVMValueRef constant_value = llvm_const_named_struct_internal(struct_type, new_values, cast(unsigned)value_count); + LLVMValueRef constant_value = llvm_const_named_struct_internal(m, struct_type, new_values, cast(unsigned)value_count); GB_ASSERT(is_local); lbProcedure *p = m->curr_procedure; @@ -1237,7 +1706,15 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo LLVMValueRef val = old_values[i]; if (!LLVMIsConstant(val)) { LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, ""); + // if (LLVMIsALoadInst(val)) { + // Type *ptr_type = v.addr.type; + // i64 sz = type_size_of(type_deref(ptr_type)); + + // LLVMValueRef src = LLVMGetOperand(val, 0); + // lb_mem_copy_non_overlapping(p, {dst, ptr_type}, {src, ptr_type}, lb_const_int(m, t_int, sz), false); + // } else { LLVMBuildStore(p->builder, val, dst); + // } } } return lb_addr_load(p, v); @@ -1311,7 +1788,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; for (i64 k = lo; k < hi; k++) { i64 offset = matrix_row_major_index_to_offset(type, k); GB_ASSERT(values[offset] == nullptr); @@ -1323,7 +1800,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo i64 index = exact_value_to_i64(index_tav.value); GB_ASSERT(index < max_count); TypeAndValue tav = fv->value->tav; - LLVMValueRef val = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; i64 offset = matrix_row_major_index_to_offset(type, index); GB_ASSERT(values[offset] == nullptr); values[offset] = val; @@ -1336,7 +1813,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, cc); return res; } else { GB_ASSERT_MSG(elem_count == max_count, "%td != %td", elem_count, max_count); @@ -1347,7 +1824,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT(tav.mode != Addressing_Invalid); i64 offset = 0; offset = matrix_row_major_index_to_offset(type, i); - values[offset] = lb_const_value(m, elem_type, tav.value, allow_local, is_rodata).value; + values[offset] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value; } for (isize i = 0; i < total_count; i++) { if (values[i] == nullptr) { @@ -1355,7 +1832,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } } - res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, allow_local, is_rodata); + res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)total_count, values, cc); return res; } } else { diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 067004bc1..3372165f2 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -18,6 +18,25 @@ gb_internal void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef va } } +gb_internal void lb_add_raddbg_string(lbModule *m, String const &str) { + mpsc_enqueue(&m->gen->raddebug_section_strings, copy_string(permanent_allocator(), str)); +} + +gb_internal void lb_add_raddbg_string(lbModule *m, char const *cstr) { + mpsc_enqueue(&m->gen->raddebug_section_strings, copy_string(permanent_allocator(), make_string_c(cstr))); +} + +gb_internal void lb_add_raddbg_string(lbModule *m, char const *a, char const *b) { + String str = concatenate_strings(permanent_allocator(), make_string_c(a), make_string_c(b)); + mpsc_enqueue(&m->gen->raddebug_section_strings, str); +} + +gb_internal void lb_add_raddbg_string(lbModule *m, char const *a, char const *b, char const *c) { + String str = concatenate3_strings(permanent_allocator(), make_string_c(a), make_string_c(b), make_string_c(c)); + mpsc_enqueue(&m->gen->raddebug_section_strings, str); +} + + gb_internal LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) { GB_ASSERT_MSG(p->debug_info != nullptr, "missing debug information for %.*s", LIT(p->name)); @@ -564,22 +583,21 @@ gb_internal LLVMMetadataRef lb_debug_bitfield(lbModule *m, Type *type, String na u64 size_in_bits = 8*type_size_of(bt); u32 align_in_bits = 8*cast(u32)type_align_of(bt); - unsigned element_count = cast(unsigned)bt->BitField.fields.count; - LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count); + unsigned element_count = cast(unsigned)bt->BitField.fields.count; + LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count); - u64 offset_in_bits = 0; - for (unsigned i = 0; i < element_count; i++) { - Entity *f = bt->BitField.fields[i]; - u8 bit_size = bt->BitField.bit_sizes[i]; - GB_ASSERT(f->kind == Entity_Variable); - String name = f->token.string; - elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, line, - bit_size, offset_in_bits, 0, - LLVMDIFlagZero, lb_debug_type(m, f->type) - ); - - offset_in_bits += bit_size; - } + u64 offset_in_bits = 0; + for (unsigned i = 0; i < element_count; i++) { + Entity *f = bt->BitField.fields[i]; + u8 bit_size = bt->BitField.bit_sizes[i]; + GB_ASSERT(f->kind == Entity_Variable); + String name = f->token.string; + elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, line, + bit_size, offset_in_bits, 0, + LLVMDIFlagZero, lb_debug_type(m, f->type) + ); + offset_in_bits += bit_size; + } LLVMMetadataRef final_decl = LLVMDIBuilderCreateStructType( m->debug_builder, scope, @@ -784,6 +802,20 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { LLVMMetadataRef char_type = lb_debug_type_basic_type(m, str_lit("char"), 8, LLVMDWARFTypeEncoding_Unsigned); return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, ptr_bits, ptr_bits, 0, "cstring", 7); } + + case Basic_string16: + { + LLVMMetadataRef elements[2] = {}; + elements[0] = lb_debug_struct_field(m, str_lit("data"), t_u16_ptr, 0); + elements[1] = lb_debug_struct_field(m, str_lit("len"), t_int, int_bits); + return lb_debug_basic_struct(m, str_lit("string16"), 2*int_bits, int_bits, elements, gb_count_of(elements)); + } + case Basic_cstring16: + { + LLVMMetadataRef char_type = lb_debug_type_basic_type(m, str_lit("wchar_t"), 16, LLVMDWARFTypeEncoding_Unsigned); + return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, ptr_bits, ptr_bits, 0, "cstring16", 7); + } + case Basic_any: { LLVMMetadataRef elements[2] = {}; @@ -924,6 +956,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { } case Type_Matrix: { + #if 0 LLVMMetadataRef subscripts[1] = {}; subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder, 0ll, @@ -935,6 +968,66 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { 8*cast(unsigned)type_align_of(type), lb_debug_type(m, type->Matrix.elem), subscripts, gb_count_of(subscripts)); + #else + LLVMMetadataRef subscripts[2] = {}; + subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder, 0ll, type->Matrix.row_count); + subscripts[1] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder, 0ll, type->Matrix.column_count); + + LLVMMetadataRef scope = nullptr; + LLVMMetadataRef array_type = nullptr; + + uint64_t size_in_bits = 8*cast(uint64_t)(type_size_of(type)); + unsigned align_in_bits = 8*cast(unsigned)(type_align_of(type)); + + if (type->Matrix.is_row_major) { + LLVMMetadataRef base = LLVMDIBuilderCreateArrayType(m->debug_builder, + 8*cast(uint64_t)(type_size_of(type->Matrix.elem) * type->Matrix.column_count), + 8*cast(unsigned)type_align_of(type->Matrix.elem), + lb_debug_type(m, type->Matrix.elem), + subscripts+1, 1); + array_type = LLVMDIBuilderCreateArrayType(m->debug_builder, + size_in_bits, + align_in_bits, + base, + subscripts+0, 1); + } else { + LLVMMetadataRef base = LLVMDIBuilderCreateArrayType(m->debug_builder, + 8*cast(uint64_t)(type_size_of(type->Matrix.elem) * type->Matrix.row_count), + 8*cast(unsigned)type_align_of(type->Matrix.elem), + lb_debug_type(m, type->Matrix.elem), + subscripts+0, 1); + array_type = LLVMDIBuilderCreateArrayType(m->debug_builder, + size_in_bits, + align_in_bits, + base, + subscripts+1, 1); + } + + LLVMMetadataRef elements[1] = {}; + elements[0] = LLVMDIBuilderCreateMemberType(m->debug_builder, scope, + "data", 4, + nullptr, 0, + size_in_bits, align_in_bits, 0, LLVMDIFlagZero, + array_type + ); + + gbString name = temp_canonical_string(type); + + LLVMMetadataRef final_decl = LLVMDIBuilderCreateStructType( + m->debug_builder, scope, + name, gb_string_length(name), + nullptr, 0, + size_in_bits, align_in_bits, + LLVMDIFlagZero, + nullptr, + elements, 1, + 0, + nullptr, + "", 0 + ); + + return final_decl; + #endif } } @@ -1085,7 +1178,12 @@ gb_internal void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, T LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); lb_set_llvm_metadata(m, ptr, llvm_expr); + +#if LLVM_VERSION_MAJOR <= 18 LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); +#else + LLVMDIBuilderInsertDeclareRecordAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block); +#endif } gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block) { @@ -1181,7 +1279,7 @@ gb_internal void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx } -gb_internal String debug_info_mangle_constant_name(Entity *e, gbAllocator const &allocator, bool *did_allocate_) { +gb_internal String lb_debug_info_mangle_constant_name(Entity *e, gbAllocator const &allocator, bool *did_allocate_) { String name = e->token.string; if (e->pkg && e->pkg->name.len > 0) { gbString s = string_canonical_entity_name(allocator, e); @@ -1191,7 +1289,7 @@ gb_internal String debug_info_mangle_constant_name(Entity *e, gbAllocator const return name; } -gb_internal void add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMetadataRef dtype, LLVMMetadataRef expr) { +gb_internal void lb_add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMetadataRef dtype, LLVMMetadataRef expr) { LLVMMetadataRef scope = nullptr; LLVMMetadataRef file = nullptr; unsigned line = 0; @@ -1207,20 +1305,20 @@ gb_internal void add_debug_info_global_variable_expr(lbModule *m, String const & expr, decl, 8/*AlignInBits*/); } -gb_internal void add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLVMMetadataRef dtype, i64 v) { +gb_internal void lb_add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLVMMetadataRef dtype, i64 v) { LLVMMetadataRef expr = LLVMDIBuilderCreateConstantValueExpression(m->debug_builder, v); TEMPORARY_ALLOCATOR_GUARD(); - String name = debug_info_mangle_constant_name(e, temporary_allocator(), nullptr); + String name = lb_debug_info_mangle_constant_name(e, temporary_allocator(), nullptr); - add_debug_info_global_variable_expr(m, name, dtype, expr); + lb_add_debug_info_global_variable_expr(m, name, dtype, expr); if ((e->pkg && e->pkg->kind == Package_Init) || (e->scope && (e->scope->flags & ScopeFlag_Global))) { - add_debug_info_global_variable_expr(m, e->token.string, dtype, expr); + lb_add_debug_info_global_variable_expr(m, e->token.string, dtype, expr); } } -gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e) { +gb_internal void lb_add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e) { if (e == nullptr || e->kind != Entity_Constant) { return; } @@ -1229,7 +1327,7 @@ gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen } lbModule *m = &gen->default_module; if (USE_SEPARATE_MODULES) { - m = lb_module_of_entity(gen, e); + m = lb_module_of_entity(gen, e, m); } GB_ASSERT(m != nullptr); @@ -1251,14 +1349,14 @@ gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen dtype = lb_debug_type(m, e->type); } - add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); + lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); } } else if (is_type_rune(e->type)) { ExactValue const &value = e->Constant.value; if (value.kind == ExactValue_Integer) { LLVMMetadataRef dtype = lb_debug_type(m, t_rune); i64 v = exact_value_to_i64(value); - add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); + lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); } } else if (is_type_boolean(e->type)) { ExactValue const &value = e->Constant.value; @@ -1266,7 +1364,7 @@ gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen LLVMMetadataRef dtype = lb_debug_type(m, default_type(e->type)); i64 v = cast(i64)value.value_bool; - add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); + lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); } } else if (is_type_enum(e->type)) { ExactValue const &value = e->Constant.value; @@ -1279,14 +1377,70 @@ gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen v = cast(i64)exact_value_to_u64(value); } - add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); + lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); } } else if (is_type_pointer(e->type)) { ExactValue const &value = e->Constant.value; if (value.kind == ExactValue_Integer) { LLVMMetadataRef dtype = lb_debug_type(m, default_type(e->type)); i64 v = cast(i64)exact_value_to_u64(value); - add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); + lb_add_debug_info_for_global_constant_internal_i64(m, e, dtype, v); } } } + +gb_internal void lb_add_debug_label(lbProcedure *p, Ast *label, lbBlock *target) { +// NOTE(tf2spi): LLVM-C DILabel API used only existed for major versions 20+ +#if LLVM_VERSION_MAJOR >= 20 + if (p == nullptr || p->debug_info == nullptr) { + return; + } + if (target == nullptr || label == nullptr || label->kind != Ast_Label) { + return; + } + Token label_token = label->Label.token; + if (is_blank_ident(label_token.string)) { + return; + } + lbModule *m = p->module; + if (m == nullptr) { + return; + } + + AstFile *file = label->file(); + LLVMMetadataRef llvm_file = lb_get_llvm_metadata(m, file); + if (llvm_file == nullptr) { + debugf("llvm file not found for label\n"); + return; + } + LLVMMetadataRef llvm_scope = p->debug_info; + if(llvm_scope == nullptr) { + debugf("llvm scope not found for label\n"); + return; + } + LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, label_token.pos); + LLVMBasicBlockRef llvm_block = target->block; + if (llvm_block == nullptr || llvm_debug_loc == nullptr) { + return; + } + LLVMMetadataRef llvm_label = LLVMDIBuilderCreateLabel( + m->debug_builder, + llvm_scope, + (const char *)label_token.string.text, + (size_t)label_token.string.len, + llvm_file, + label_token.pos.line, + + // NOTE(tf2spi): Defaults to false in LLVM API, but I'd rather not take chances + // Always preserve the label no matter what when debugging + true + ); + GB_ASSERT(llvm_label != nullptr); + (void)LLVMDIBuilderInsertLabelAtEnd( + m->debug_builder, + llvm_label, + llvm_debug_loc, + llvm_block + ); +#endif +} diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 56c7b45ec..187c34595 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -222,6 +222,7 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, return lb_emit_byte_swap(p, res, type); } + Type* bt = base_type(type); lbValue res = {}; switch (op) { @@ -233,6 +234,8 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, case Token_Sub: // Number negation if (is_type_integer(x.type)) { res.value = LLVMBuildNeg(p->builder, x.value, ""); + } else if (bt->kind == Type_Enum && is_type_integer(bt->Enum.base_type)) { + res.value = LLVMBuildNeg(p->builder, x.value, ""); } else if (is_type_float(x.type)) { res.value = LLVMBuildFNeg(p->builder, x.value, ""); } else if (is_type_complex(x.type)) { @@ -280,6 +283,36 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, return res; } +gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero_behaviour(lbProcedure *p) { + AstFile *file = nullptr; + + if (p->body && p->body->file()) { + file = p->body->file(); + } else if (p->type_expr && p->type_expr->file()) { + file = p->type_expr->file(); + } else if (p->entity && p->entity->file) { + file = p->entity->file; + } + + if (file != nullptr && file->feature_flags_set) { + u64 flags = file->feature_flags; + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Trap) { + return IntegerDivisionByZero_Trap; + } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) { + return IntegerDivisionByZero_Zero; + } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Self) { + return IntegerDivisionByZero_Self; + } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_AllBits) { + return IntegerDivisionByZero_AllBits; + } + } + return build_context.integer_division_by_zero_behaviour; +} + + gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, lbValue *res_) { GB_ASSERT(is_type_array_like(type)); Type *elem_type = base_array_type(type); @@ -351,7 +384,6 @@ gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValu } } else { - switch (op) { case Token_Add: z = LLVMBuildAdd(p->builder, x, y, ""); @@ -363,17 +395,15 @@ gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValu z = LLVMBuildMul(p->builder, x, y, ""); break; case Token_Quo: - if (is_type_unsigned(integral_type)) { - z = LLVMBuildUDiv(p->builder, x, y, ""); - } else { - z = LLVMBuildSDiv(p->builder, x, y, ""); + { + auto *call = is_type_unsigned(integral_type) ? LLVMBuildUDiv : LLVMBuildSDiv; + z = call(p->builder, x, y, ""); } break; case Token_Mod: - if (is_type_unsigned(integral_type)) { - z = LLVMBuildURem(p->builder, x, y, ""); - } else { - z = LLVMBuildSRem(p->builder, x, y, ""); + { + auto *call = is_type_unsigned(integral_type) ? LLVMBuildURem : LLVMBuildSRem; + z = call(p->builder, x, y, ""); } break; case Token_ModMod: @@ -1108,6 +1138,303 @@ gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue l return {}; } +gb_internal LLVMValueRef lb_integer_division(lbProcedure *p, LLVMValueRef lhs, LLVMValueRef rhs, bool is_signed) { + LLVMTypeRef type = LLVMTypeOf(rhs); + GB_ASSERT(LLVMTypeOf(lhs) == type); + + LLVMValueRef zero = LLVMConstNull(type); + LLVMValueRef all_bits = LLVMConstNot(zero); + auto behaviour = lb_check_for_integer_division_by_zero_behaviour(p); + + auto *call = is_signed ? LLVMBuildSDiv : LLVMBuildUDiv; + + if (LLVMIsConstant(rhs)) { + if (LLVMIsNull(rhs)) { + switch (behaviour) { + case IntegerDivisionByZero_Self: + return lhs; + case IntegerDivisionByZero_Zero: + return zero; + case IntegerDivisionByZero_AllBits: + // return all_bits; + break; + } + } else { + if (!is_signed && lb_sizeof(type) <= 8) { + u64 v = cast(u64)LLVMConstIntGetZExtValue(rhs); + if (v == 1) { + return lhs; + } else if (is_power_of_two_u64(v)) { + u64 n = floor_log2(v); + LLVMValueRef bits = LLVMConstInt(type, n, false); + return LLVMBuildLShr(p->builder, lhs, bits, ""); + } + } + + return call(p->builder, lhs, rhs, ""); + } + } + + LLVMValueRef incoming_values[2] = {}; + LLVMBasicBlockRef incoming_blocks[2] = {}; + + lbBlock *safe_block = lb_create_block(p, "div.safe"); + lbBlock *edge_case_block = lb_create_block(p, "div.edge"); + lbBlock *done_block = lb_create_block(p, "div.done"); + + LLVMValueRef dem_check = LLVMBuildICmp(p->builder, LLVMIntNE, rhs, zero, ""); + lbValue cond = {dem_check, t_untyped_bool}; + + lb_emit_if(p, cond, safe_block, edge_case_block); + + lb_start_block(p, safe_block); + incoming_values[0] = call(p->builder, lhs, rhs, ""); + lb_emit_jump(p, done_block); + + lb_start_block(p, edge_case_block); + + + switch (behaviour) { + case IntegerDivisionByZero_Trap: + lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0); + LLVMBuildUnreachable(p->builder); + break; + case IntegerDivisionByZero_Zero: + incoming_values[1] = zero; + break; + case IntegerDivisionByZero_Self: + incoming_values[1] = lhs; + break; + case IntegerDivisionByZero_AllBits: + incoming_values[1] = all_bits; + break; + } + + lb_emit_jump(p, done_block); + lb_start_block(p, done_block); + + LLVMValueRef res = incoming_values[0]; + + switch (behaviour) { + case IntegerDivisionByZero_Trap: + case IntegerDivisionByZero_Self: + res = incoming_values[0]; + break; + case IntegerDivisionByZero_Zero: + case IntegerDivisionByZero_AllBits: + res = LLVMBuildPhi(p->builder, type, ""); + + GB_ASSERT(p->curr_block->preds.count >= 2); + incoming_blocks[0] = p->curr_block->preds[0]->block; + incoming_blocks[1] = p->curr_block->preds[1]->block; + + LLVMAddIncoming(res, incoming_values, incoming_blocks, 2); + break; + } + + return res; +} + +gb_internal LLVMValueRef lb_integer_division_intrinsics(lbProcedure *p, LLVMValueRef lhs, LLVMValueRef rhs, LLVMValueRef scale, Type *platform_type, char const *name) { + LLVMTypeRef type = LLVMTypeOf(rhs); + GB_ASSERT(LLVMTypeOf(lhs) == type); + + LLVMValueRef zero = LLVMConstNull(type); + LLVMValueRef all_bits = LLVMConstNot(zero); + auto behaviour = lb_check_for_integer_division_by_zero_behaviour(p); + + auto const do_op = [&]() -> LLVMValueRef { + LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; + + LLVMValueRef args[3] = { + lhs, + rhs, + scale }; + + return lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + }; + + if (LLVMIsConstant(rhs)) { + if (LLVMIsNull(rhs)) { + switch (behaviour) { + case IntegerDivisionByZero_Self: + return lhs; + case IntegerDivisionByZero_Zero: + return zero; + } + } else { + return do_op(); + } + } + + LLVMValueRef incoming_values[2] = {}; + LLVMBasicBlockRef incoming_blocks[2] = {}; + + lbBlock *safe_block = lb_create_block(p, "div.safe"); + lbBlock *edge_case_block = lb_create_block(p, "div.edge"); + lbBlock *done_block = lb_create_block(p, "div.done"); + + LLVMValueRef dem_check = LLVMBuildICmp(p->builder, LLVMIntNE, rhs, zero, ""); + lbValue cond = {dem_check, t_untyped_bool}; + + lb_emit_if(p, cond, safe_block, edge_case_block); + + lb_start_block(p, safe_block); + incoming_values[0] = do_op(); + lb_emit_jump(p, done_block); + + lb_start_block(p, edge_case_block); + + + switch (behaviour) { + case IntegerDivisionByZero_Trap: + lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0); + LLVMBuildUnreachable(p->builder); + break; + case IntegerDivisionByZero_Zero: + incoming_values[1] = zero; + break; + case IntegerDivisionByZero_Self: + incoming_values[1] = lhs; + break; + case IntegerDivisionByZero_AllBits: + incoming_values[1] = all_bits; + break; + } + + lb_emit_jump(p, done_block); + lb_start_block(p, done_block); + + LLVMValueRef res = incoming_values[0]; + + switch (behaviour) { + case IntegerDivisionByZero_Trap: + case IntegerDivisionByZero_Self: + res = incoming_values[0]; + break; + case IntegerDivisionByZero_Zero: + case IntegerDivisionByZero_AllBits: + res = LLVMBuildPhi(p->builder, type, ""); + + GB_ASSERT(p->curr_block->preds.count >= 2); + incoming_blocks[0] = p->curr_block->preds[0]->block; + incoming_blocks[1] = p->curr_block->preds[1]->block; + + LLVMAddIncoming(res, incoming_values, incoming_blocks, 2); + break; + } + + return res; +} + + +gb_internal LLVMValueRef lb_integer_modulo(lbProcedure *p, LLVMValueRef lhs, LLVMValueRef rhs, bool is_unsigned, bool is_floored) { + LLVMTypeRef type = LLVMTypeOf(rhs); + GB_ASSERT(LLVMTypeOf(lhs) == type); + + LLVMValueRef zero = LLVMConstNull(type); + auto behaviour = lb_check_for_integer_division_by_zero_behaviour(p); + + auto const do_op = [&]() -> LLVMValueRef { + if (is_floored) { // %% + if (is_unsigned) { + return LLVMBuildURem(p->builder, lhs, rhs, ""); + } else { + LLVMValueRef a = LLVMBuildSRem(p->builder, lhs, rhs, ""); + LLVMValueRef b = LLVMBuildAdd(p->builder, a, rhs, ""); + LLVMValueRef c = LLVMBuildSRem(p->builder, b, rhs, ""); + return c; + } + } else { // % + if (is_unsigned) { + return LLVMBuildURem(p->builder, lhs, rhs, ""); + } else { + return LLVMBuildSRem(p->builder, lhs, rhs, ""); + } + } + }; + + if (LLVMIsConstant(rhs)) { + if (LLVMIsNull(rhs)) { + switch (behaviour) { + case IntegerDivisionByZero_Self: + return zero; + case IntegerDivisionByZero_Zero: + case IntegerDivisionByZero_AllBits: + return lhs; + } + } else { + return do_op(); + } + } + + + LLVMValueRef incoming_values[2] = {}; + LLVMBasicBlockRef incoming_blocks[2] = {}; + + lbBlock *safe_block = lb_create_block(p, "mod.safe"); + lbBlock *edge_case_block = lb_create_block(p, "mod.edge"); + lbBlock *done_block = lb_create_block(p, "mod.done"); + + LLVMValueRef dem_check = LLVMBuildICmp(p->builder, LLVMIntNE, rhs, zero, ""); + lbValue cond = {dem_check, t_untyped_bool}; + + lb_emit_if(p, cond, safe_block, edge_case_block); + + lb_start_block(p, safe_block); + incoming_values[0] = do_op(); + lb_emit_jump(p, done_block); + + lb_start_block(p, edge_case_block); + + /* + NOTE(bill): @integer division by zero rules + + truncated: r = a - b*trunc(a/b) + floored: r = a - b*floor(a/b) + + IFF a/0 == 0, then (a%0 == a) or (a%%0 == a) + IFF a/0 == a, then (a%0 == 0) or (a%%0 == 0) + */ + + switch (behaviour) { + case IntegerDivisionByZero_Trap: + lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0); + LLVMBuildUnreachable(p->builder); + break; + case IntegerDivisionByZero_Zero: + case IntegerDivisionByZero_AllBits: + incoming_values[1] = lhs; + break; + case IntegerDivisionByZero_Self: + incoming_values[1] = zero; + break; + } + + lb_emit_jump(p, done_block); + lb_start_block(p, done_block); + + LLVMValueRef res = incoming_values[0]; + + switch (behaviour) { + case IntegerDivisionByZero_Trap: + case IntegerDivisionByZero_Self: + res = incoming_values[0]; + break; + case IntegerDivisionByZero_Zero: + case IntegerDivisionByZero_AllBits: + res = LLVMBuildPhi(p->builder, type, ""); + + GB_ASSERT(p->curr_block->preds.count >= 2); + incoming_blocks[0] = p->curr_block->preds[0]->block; + incoming_blocks[1] = p->curr_block->preds[1]->block; + + LLVMAddIncoming(res, incoming_values, incoming_blocks, 2); + break; + } + + return res; +} gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) { @@ -1347,33 +1674,20 @@ handle_op:; if (is_type_float(integral_type)) { res.value = LLVMBuildFDiv(p->builder, lhs.value, rhs.value, ""); return res; - } else if (is_type_unsigned(integral_type)) { - res.value = LLVMBuildUDiv(p->builder, lhs.value, rhs.value, ""); + } else { + res.value = lb_integer_division(p, lhs.value, rhs.value, !is_type_unsigned(integral_type)); return res; } - res.value = LLVMBuildSDiv(p->builder, lhs.value, rhs.value, ""); - return res; case Token_Mod: if (is_type_float(integral_type)) { res.value = LLVMBuildFRem(p->builder, lhs.value, rhs.value, ""); return res; - } else if (is_type_unsigned(integral_type)) { - res.value = LLVMBuildURem(p->builder, lhs.value, rhs.value, ""); - return res; } - res.value = LLVMBuildSRem(p->builder, lhs.value, rhs.value, ""); + res.value = lb_integer_modulo(p, lhs.value, rhs.value, is_type_unsigned(integral_type), /*is_floored*/false); return res; case Token_ModMod: - if (is_type_unsigned(integral_type)) { - res.value = LLVMBuildURem(p->builder, lhs.value, rhs.value, ""); - return res; - } else { - LLVMValueRef a = LLVMBuildSRem(p->builder, lhs.value, rhs.value, ""); - LLVMValueRef b = LLVMBuildAdd(p->builder, a, rhs.value, ""); - LLVMValueRef c = LLVMBuildSRem(p->builder, b, rhs.value, ""); - res.value = c; - return res; - } + res.value = lb_integer_modulo(p, lhs.value, rhs.value, is_type_unsigned(integral_type), /*is_floored*/true); + return res; case Token_And: res.value = LLVMBuildAnd(p->builder, lhs.value, rhs.value, ""); @@ -1556,16 +1870,24 @@ gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { return lb_emit_conv(p, cmp, type); } else if (lb_is_empty_string_constant(be->right) && !is_type_union(be->left->tav.type)) { // `x == ""` or `x != ""` + Type *str_type = t_string; + if (is_type_string16(be->left->tav.type) || is_type_cstring16(be->left->tav.type)) { + str_type = t_string16; + } lbValue s = lb_build_expr(p, be->left); - s = lb_emit_conv(p, s, t_string); + s = lb_emit_conv(p, s, str_type); lbValue len = lb_string_len(p, s); lbValue cmp = lb_emit_comp(p, be->op.kind, len, lb_const_int(p->module, t_int, 0)); Type *type = default_type(tv.type); return lb_emit_conv(p, cmp, type); } else if (lb_is_empty_string_constant(be->left) && !is_type_union(be->right->tav.type)) { // `"" == x` or `"" != x` + Type *str_type = t_string; + if (is_type_string16(be->right->tav.type) || is_type_cstring16(be->right->tav.type)) { + str_type = t_string16; + } lbValue s = lb_build_expr(p, be->right); - s = lb_emit_conv(p, s, t_string); + s = lb_emit_conv(p, s, str_type); lbValue len = lb_string_len(p, s); lbValue cmp = lb_emit_comp(p, be->op.kind, len, lb_const_int(p->module, t_int, 0)); Type *type = default_type(tv.type); @@ -1653,6 +1975,8 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { res.type = t; res.value = llvm_cstring(m, str); return res; + } else if (src->kind == Type_Basic && src->Basic.kind == Basic_string16 && dst->Basic.kind == Basic_cstring16) { + GB_PANIC("TODO(bill): UTF-16 string"); } // if (is_type_float(dst)) { // return value; @@ -1792,6 +2116,38 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } + + if (is_type_cstring16(src) && is_type_u16_ptr(dst)) { + return lb_emit_transmute(p, value, dst); + } + if (is_type_u16_ptr(src) && is_type_cstring16(dst)) { + return lb_emit_transmute(p, value, dst); + } + if (is_type_cstring16(src) && is_type_u16_multi_ptr(dst)) { + return lb_emit_transmute(p, value, dst); + } + if (is_type_u8_multi_ptr(src) && is_type_cstring16(dst)) { + return lb_emit_transmute(p, value, dst); + } + if (is_type_cstring16(src) && is_type_rawptr(dst)) { + return lb_emit_transmute(p, value, dst); + } + if (is_type_rawptr(src) && is_type_cstring16(dst)) { + return lb_emit_transmute(p, value, dst); + } + + if (are_types_identical(src, t_cstring16) && are_types_identical(dst, t_string16)) { + TEMPORARY_ALLOCATOR_GUARD(); + + lbValue c = lb_emit_conv(p, value, t_cstring16); + auto args = array_make(temporary_allocator(), 1); + args[0] = c; + lbValue s = lb_emit_runtime_call(p, "cstring16_to_string16", args); + return lb_emit_conv(p, s, dst); + } + + + // integer -> boolean if (is_type_integer(src) && is_type_boolean(dst)) { lbValue res = {}; @@ -2145,6 +2501,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } } for (Type *vt : dst->Union.variants) { + if (src_type == t_llvm_bool && is_type_boolean(vt)) { + lbAddr parent = lb_add_local_generated(p, t, true); + lb_emit_store_union_variant(p, parent.addr, value, vt); + return lb_addr_load(p, parent); + } if (are_types_identical(src_type, vt)) { lbAddr parent = lb_add_local_generated(p, t, true); lb_emit_store_union_variant(p, parent.addr, value, vt); @@ -2201,10 +2562,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { Type *dt = t; + TEMPORARY_ALLOCATOR_GUARD(); + GB_ASSERT(is_type_struct(st) || is_type_raw_union(st)); Selection sel = {}; - sel.index.allocator = heap_allocator(); - defer (array_free(&sel.index)); + sel.index.allocator = temporary_allocator(); if (lookup_subtype_polymorphic_selection(t, src_type, &sel)) { if (sel.entity == nullptr) { GB_PANIC("invalid subtype cast %s -> ", type_to_string(src_type), type_to_string(t)); @@ -2287,6 +2649,29 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return res; } + // [^]u16 <-> cstring16 + if (is_type_u16_multi_ptr(src) && is_type_cstring16(dst)) { + return lb_emit_transmute(p, value, t); + } + if (is_type_cstring16(src) && is_type_u16_multi_ptr(dst)) { + return lb_emit_transmute(p, value, t); + } + if (is_type_u16_ptr(src) && is_type_cstring16(dst)) { + return lb_emit_transmute(p, value, t); + } + if (is_type_cstring16(src) && is_type_u16_ptr(dst)) { + return lb_emit_transmute(p, value, t); + } + + + // []u16 <-> string16 + if (is_type_u16_slice(src) && is_type_string16(dst)) { + return lb_emit_transmute(p, value, t); + } + if (is_type_string16(src) && is_type_u16_slice(dst)) { + return lb_emit_transmute(p, value, t); + } + // []byte/[]u8 <-> string if (is_type_u8_slice(src) && is_type_string(dst)) { return lb_emit_transmute(p, value, t); @@ -2295,6 +2680,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return lb_emit_transmute(p, value, t); } + if (is_type_array_like(dst)) { Type *elem = base_array_type(dst); isize index_count = cast(isize)get_array_type_count(dst); @@ -2346,7 +2732,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { Type *elem = base_array_type(dst); lbValue e = lb_emit_conv(p, value, elem); lbAddr v = lb_add_local_generated(p, t, false); - lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), true); + lbValue zero = lb_const_value(p->module, elem, exact_value_i64(0), LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL); for (i64 j = 0; j < dst->Matrix.column_count; j++) { for (i64 i = 0; i < dst->Matrix.row_count; i++) { lbValue ptr = lb_emit_matrix_epi(p, v.addr, i, j); @@ -2383,7 +2769,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { lb_emit_store(p, d, s); } else if (i == j) { lbValue d = lb_emit_matrix_epi(p, v.addr, i, j); - lbValue s = lb_const_value(p->module, dst->Matrix.elem, exact_value_i64(1), true); + lbValue s = lb_const_value(p->module, dst->Matrix.elem, exact_value_i64(1), LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL); lb_emit_store(p, d, s); } } @@ -2508,7 +2894,7 @@ gb_internal lbValue lb_emit_c_vararg(lbProcedure *p, lbValue arg, Type *type) { } gb_internal lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right, Type *type) { - GB_ASSERT((is_type_struct(type) || is_type_union(type)) && is_type_comparable(type)); + GB_ASSERT((is_type_struct(type) || is_type_soa_pointer(type) || is_type_union(type)) && is_type_comparable(type)); lbValue left_ptr = lb_address_from_load_or_generate_local(p, left); lbValue right_ptr = lb_address_from_load_or_generate_local(p, right); lbValue res = {}; @@ -2701,7 +3087,53 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left return lb_compare_records(p, op_kind, left, right, b); } + + if (is_type_string16(a) || is_type_cstring16(a)) { + if (is_type_cstring16(a) && is_type_cstring16(b)) { + left = lb_emit_conv(p, left, t_cstring16); + right = lb_emit_conv(p, right, t_cstring16); + char const *runtime_procedure = nullptr; + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "cstring16_eq"; break; + case Token_NotEq: runtime_procedure = "cstring16_ne"; break; + case Token_Lt: runtime_procedure = "cstring16_lt"; break; + case Token_Gt: runtime_procedure = "cstring16_gt"; break; + case Token_LtEq: runtime_procedure = "cstring16_le"; break; + case Token_GtEq: runtime_procedure = "cstring16_ge"; break; + } + GB_ASSERT(runtime_procedure != nullptr); + + auto args = array_make(permanent_allocator(), 2); + args[0] = left; + args[1] = right; + return lb_emit_runtime_call(p, runtime_procedure, args); + } + + + if (is_type_cstring16(a) ^ is_type_cstring16(b)) { + left = lb_emit_conv(p, left, t_string16); + right = lb_emit_conv(p, right, t_string16); + } + + char const *runtime_procedure = nullptr; + switch (op_kind) { + case Token_CmpEq: runtime_procedure = "string16_eq"; break; + case Token_NotEq: runtime_procedure = "string16_ne"; break; + case Token_Lt: runtime_procedure = "string16_lt"; break; + case Token_Gt: runtime_procedure = "string16_gt"; break; + case Token_LtEq: runtime_procedure = "string16_le"; break; + case Token_GtEq: runtime_procedure = "string16_ge"; break; + } + GB_ASSERT(runtime_procedure != nullptr); + + auto args = array_make(permanent_allocator(), 2); + args[0] = left; + args[1] = right; + return lb_emit_runtime_call(p, runtime_procedure, args); + } + if (is_type_string(a)) { + if (is_type_cstring(a) && is_type_cstring(b)) { left = lb_emit_conv(p, left, t_cstring); right = lb_emit_conv(p, right, t_cstring); @@ -2893,6 +3325,7 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left is_type_proc(a) || is_type_enum(a)) { LLVMIntPredicate pred = {}; + if (is_type_unsigned(left.type)) { switch (op_kind) { case Token_Gt: pred = LLVMIntUGT; break; @@ -2935,7 +3368,7 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left case Token_GtEq: pred = LLVMRealOGE; break; case Token_Lt: pred = LLVMRealOLT; break; case Token_LtEq: pred = LLVMRealOLE; break; - case Token_NotEq: pred = LLVMRealONE; break; + case Token_NotEq: pred = LLVMRealUNE; break; } if (is_type_different_to_arch_endianness(left.type)) { @@ -2963,7 +3396,7 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left LLVMRealPredicate pred = {}; switch (op_kind) { case Token_CmpEq: pred = LLVMRealOEQ; break; - case Token_NotEq: pred = LLVMRealONE; break; + case Token_NotEq: pred = LLVMRealUNE; break; } mask = LLVMBuildFCmp(p->builder, pred, left.value, right.value, ""); } else { @@ -3016,6 +3449,9 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left return res; + } else if (is_type_soa_pointer(a)) { + // NOTE(Jeroen): Compare data pointer and index tag as if it were a simple struct. + return lb_compare_records(p, op_kind, left, right, a); } else { GB_PANIC("Unhandled comparison kind %s (%s) %.*s %s (%s)", type_to_string(left.type), type_to_string(base_type(left.type)), LIT(token_strings[op_kind]), type_to_string(right.type), type_to_string(base_type(right.type))); } @@ -3043,6 +3479,13 @@ gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, res.value = LLVMBuildIsNotNull(p->builder, x.value, ""); } return res; + case Basic_cstring16: + if (op_kind == Token_CmpEq) { + res.value = LLVMBuildIsNull(p->builder, x.value, ""); + } else if (op_kind == Token_NotEq) { + res.value = LLVMBuildIsNotNull(p->builder, x.value, ""); + } + return res; case Basic_any: { // TODO(bill): is this correct behaviour for nil comparison for any? @@ -3137,6 +3580,18 @@ gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, } } break; + + case Type_SoaPointer: + { + // NOTE(bill): An SoaPointer is essentially just a pointer for nil comparison + lbValue ptr = lb_emit_struct_ev(p, x, 0); // Extract the base pointer component (field 0) + if (op_kind == Token_CmpEq) { + res.value = LLVMBuildIsNull(p->builder, ptr.value, ""); + } else if (op_kind == Token_NotEq) { + res.value = LLVMBuildIsNotNull(p->builder, ptr.value, ""); + } + return res; + } case Type_Union: { @@ -3474,6 +3929,20 @@ gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr) { return res; } +gb_internal Type *lb_build_expr_original_const_type(Ast *expr) { + expr = unparen_expr(expr); + Type *type = type_of_expr(expr); + if (is_type_union(type)) { + if (expr->kind == Ast_CallExpr) { + if (expr->CallExpr.proc->tav.mode == Addressing_Type) { + Type *res = lb_build_expr_original_const_type(expr->CallExpr.args[0]); + return res; + } + } + } + return type_of_expr(expr); +} + gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { lbModule *m = p->module; @@ -3485,9 +3954,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type)); + if (tv.value.kind != ExactValue_Invalid) { + Type *original_type = lb_build_expr_original_const_type(expr); // NOTE(bill): Short on constant values - return lb_const_value(p->module, type, tv.value); + return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, original_type); } else if (tv.mode == Addressing_Type) { // NOTE(bill, 2023-01-16): is this correct? I hope so at least return lb_typeid(m, tv.type); @@ -3568,7 +4039,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { TypeAndValue tav = type_and_value_of_expr(expr); GB_ASSERT(tav.mode == Addressing_Constant); - return lb_const_value(p->module, type, tv.value); + return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, tv.type); case_end; case_ast_node(se, SelectorCallExpr, expr); @@ -3849,7 +4320,7 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp GB_ASSERT(e != nullptr); if (e->kind == Entity_Constant) { Type *t = default_type(type_of_expr(expr)); - lbValue v = lb_const_value(p->module, t, e->Constant.value); + lbValue v = lb_const_value(p->module, t, e->Constant.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL, e->type); if (LLVMIsConstant(v.value)) { lbAddr g = lb_add_global_generated_from_procedure(p, t, v); return g; @@ -4273,12 +4744,13 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { } - case Type_Basic: { // Basic_string + case Type_Basic: { // Basic_string/Basic_string16 lbValue str; lbValue elem; lbValue len; lbValue index; + str = lb_build_expr(p, ie->expr); if (deref) { str = lb_emit_load(p, str); @@ -4407,6 +4879,22 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { } case Type_Basic: { + if (is_type_string16(type)) { + GB_ASSERT_MSG(are_types_identical(type, t_string16), "got %s", type_to_string(type)); + lbValue len = lb_string_len(p, base); + if (high.value == nullptr) high = len; + + if (!no_indices) { + lb_emit_slice_bounds_check(p, se->open, low, high, len, se->low != nullptr); + } + + lbValue elem = lb_emit_ptr_offset(p, lb_string_elem(p, base), low); + lbValue new_len = lb_emit_arith(p, Token_Sub, high, low, t_int); + + lbAddr str = lb_add_local_generated(p, t_string16, false); + lb_fill_string(p, str, elem, new_len); + return str; + } GB_ASSERT_MSG(are_types_identical(type, t_string), "got %s", type_to_string(type)); lbValue len = lb_string_len(p, base); if (high.value == nullptr) high = len; @@ -4819,7 +5307,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); gb_unused(err); @@ -4908,7 +5396,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); Type *et = bt->DynamicArray.elem; lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); @@ -5129,8 +5617,6 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { return lb_build_addr(p, unparen_expr(se->selector)); } - - Type *type = base_type(tav.type); if (tav.mode == Addressing_Type) { // Addressing_Type Selection sel = lookup_field(tav.type, selector, true); if (sel.pseudo_field) { @@ -5165,18 +5651,29 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { return lb_addr_swizzle(a, type, swizzle_count, swizzle_indices); } - Selection sel = lookup_field(type, selector, false); + Selection sel = lookup_field(tav.type, selector, false); GB_ASSERT(sel.entity != nullptr); - if (sel.pseudo_field) { - GB_ASSERT(sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup); + if (sel.pseudo_field && (sel.entity->kind == Entity_Procedure || sel.entity->kind == Entity_ProcGroup)) { Entity *e = entity_of_node(sel_node); GB_ASSERT(e->kind == Entity_Procedure); return lb_addr(lb_find_value_from_entity(p->module, e)); } - if (sel.is_bit_field) { - lbAddr addr = lb_build_addr(p, se->expr); + lbAddr addr = lb_build_addr(p, se->expr); + // NOTE(harold): Only allow ivar pseudo field access on indirect selectors. + // It is incoherent otherwise as Objective-C objects are zero-sized. + Type *deref_type = type_deref(tav.type); + if (tav.type->kind == Type_Pointer && deref_type->kind == Type_Named && deref_type->Named.type_name->TypeName.objc_ivar) { + // NOTE(harold): We need to load the ivar from the current address and + // replace addr with the loaded ivar addr to apply the selector load properly. + addr = lb_addr(lb_emit_load(p, addr.addr)); + + lbValue ivar_ptr = lb_handle_objc_ivar_for_objc_object_pointer(p, addr.addr); + addr = lb_addr(ivar_ptr); + } + + if (sel.is_bit_field) { Selection sub_sel = sel; sub_sel.index.count -= 1; @@ -5202,7 +5699,6 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { } { - lbAddr addr = lb_build_addr(p, se->expr); if (addr.kind == lbAddr_Map) { lbValue v = lb_addr_load(p, addr); lbValue a = lb_address_from_load_or_generate_local(p, v); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 0705e2e93..39cf70a6a 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -15,26 +15,47 @@ gb_global isize lb_global_type_info_member_offsets_index = 0; gb_global isize lb_global_type_info_member_usings_index = 0; gb_global isize lb_global_type_info_member_tags_index = 0; -gb_internal void lb_init_module(lbModule *m, Checker *c) { +gb_internal WORKER_TASK_PROC(lb_init_module_worker_proc) { + lbModule *m = cast(lbModule *)data; + Checker *c = m->checker; m->info = &c->info; - gbString module_name = gb_string_make(heap_allocator(), "odin_package"); - if (m->file) { - if (m->pkg) { + + String name = build_context.build_paths[BuildPath_Output].name; + gbString module_name = gb_string_make(heap_allocator(), ""); + module_name = gb_string_append_length(module_name, name.text, name.len); + + if (!USE_SEPARATE_MODULES) { + // ignore suffixes + } else if (m->file) { + if (gb_string_length(module_name)) { + module_name = gb_string_appendc(module_name, "-"); + } + if (m->pkg) { + module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len); module_name = gb_string_appendc(module_name, "-"); - module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len); } - module_name = gb_string_appendc(module_name, "-"); String filename = filename_from_path(m->file->filename); module_name = gb_string_append_length(module_name, filename.text, filename.len); } else if (m->pkg) { - module_name = gb_string_appendc(module_name, "-"); + if (gb_string_length(module_name)) { + module_name = gb_string_appendc(module_name, "-"); + } module_name = gb_string_append_length(module_name, m->pkg->name.text, m->pkg->name.len); - } else if (USE_SEPARATE_MODULES) { - module_name = gb_string_appendc(module_name, "-builtin"); + } else { + if (gb_string_length(module_name)) { + module_name = gb_string_appendc(module_name, "-"); + } + module_name = gb_string_appendc(module_name, "builtin"); + } + if (m->polymorphic_module == m) { + if (gb_string_length(module_name)) { + module_name = gb_string_appendc(module_name, "-"); + } + module_name = gb_string_appendc(module_name, "$parapoly"); } - m->module_name = module_name ? module_name : "odin_package"; + m->module_name = module_name; m->ctx = LLVMContextCreate(); m->mod = LLVMModuleCreateWithNameInContext(m->module_name, m->ctx); // m->debug_builder = nullptr; @@ -72,22 +93,28 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) { string_map_init(&m->members); string_map_init(&m->procedures); string_map_init(&m->const_strings); + string16_map_init(&m->const_string16s); map_init(&m->function_type_map); string_map_init(&m->gen_procs); if (USE_SEPARATE_MODULES) { - array_init(&m->procedures_to_generate, a, 0, 1<<10); + mpsc_init(&m->procedures_to_generate, a); map_init(&m->procedure_values, 1<<11); + array_init(&m->generated_procedures, a, 0, 1<<10); } else { - array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count); + mpsc_init(&m->procedures_to_generate, a); map_init(&m->procedure_values, c->info.all_procedures.count*2); + array_init(&m->generated_procedures, a, 0, c->info.all_procedures.count*2); } + + array_init(&m->global_procedures_to_create, a, 0, 1024); array_init(&m->global_types_to_create, a, 0, 1024); - array_init(&m->missing_procedures_to_check, a, 0, 16); + mpsc_init(&m->missing_procedures_to_check, a); map_init(&m->debug_values); string_map_init(&m->objc_classes); string_map_init(&m->objc_selectors); + string_map_init(&m->objc_ivars); map_init(&m->map_info_map, 0); map_init(&m->map_cell_info_map, 0); @@ -98,6 +125,15 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) { m->const_dummy_builder = LLVMCreateBuilderInContext(m->ctx); + return 0; +} + +gb_internal void lb_init_module(lbModule *m, bool do_threading) { + if (do_threading) { + thread_pool_add_task(lb_init_module_worker_proc, m); + } else { + lb_init_module_worker_proc(m); + } } gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { @@ -110,6 +146,10 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { return false; } + isize thread_count = gb_max(build_context.thread_count, 1); + isize worker_count = thread_count-1; + bool do_threading = !!(LLVMIsMultithreaded() && USE_SEPARATE_MODULES && MULTITHREAD_OBJECT_GENERATION && worker_count > 0); + String init_fullpath = c->parser->init_fullpath; linker_data_init(gen, &c->info, init_fullpath); @@ -121,7 +161,6 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { map_init(&gen->modules, gen->info->packages.count*2); map_init(&gen->modules_through_ctx, gen->info->packages.count*2); - map_init(&gen->anonymous_proc_lits, 1024); if (USE_SEPARATE_MODULES) { bool module_per_file = build_context.module_per_file && build_context.optimization_level <= 0; @@ -130,26 +169,94 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { auto m = gb_alloc_item(permanent_allocator(), lbModule); m->pkg = pkg; m->gen = gen; + m->checker = c; map_set(&gen->modules, cast(void *)pkg, m); - lb_init_module(m, c); - if (!module_per_file) { + lb_init_module(m, do_threading); + + if (LLVM_WEAK_MONOMORPHIZATION) { + auto pm = gb_alloc_item(permanent_allocator(), lbModule); + pm->pkg = pkg; + pm->gen = gen; + pm->checker = c; + m->polymorphic_module = pm; + pm->polymorphic_module = pm; + + map_set(&gen->modules, cast(void *)pm, pm); // point to itself just add it to the list + + lb_init_module(pm, do_threading); + } + + bool allow_for_per_file = pkg->kind == Package_Runtime || module_per_file; + + #if 0 + if (!allow_for_per_file) { + if (pkg->files.count >= 20) { + isize proc_count = 0; + for (Entity *e : gen->info->entities) { + if (e->kind != Entity_Procedure) { + continue; + } + if (e->Procedure.is_foreign) { + continue; + } + if (e->pkg == pkg) { + proc_count += 1; + } + } + + if (proc_count >= 300) { + allow_for_per_file = true; + } + } + } + #endif + + if (!allow_for_per_file) { continue; } // NOTE(bill): Probably per file is not a good idea, so leave this for later for (AstFile *file : pkg->files) { - auto m = gb_alloc_item(permanent_allocator(), lbModule); + auto m = gb_alloc_item(permanent_allocator(), lbModule); m->file = file; - m->pkg = pkg; - m->gen = gen; + m->pkg = pkg; + m->gen = gen; + m->checker = c; map_set(&gen->modules, cast(void *)file, m); - lb_init_module(m, c); + lb_init_module(m, do_threading); + + + if (LLVM_WEAK_MONOMORPHIZATION) { + auto pm = gb_alloc_item(permanent_allocator(), lbModule); + pm->file = file; + pm->pkg = pkg; + pm->gen = gen; + pm->checker = c; + m->polymorphic_module = pm; + pm->polymorphic_module = pm; + + map_set(&gen->modules, cast(void *)pm, pm); // point to itself just add it to the list + + lb_init_module(pm, do_threading); + } } } + + if (LLVM_WEAK_MONOMORPHIZATION) { + lbModule *m = gb_alloc_item(permanent_allocator(), lbModule); + gen->equal_module = m; + m->gen = gen; + m->checker = c; + map_set(&gen->modules, cast(void *)m, m); // point to itself just add it to the list + lb_init_module(m, do_threading); + } } gen->default_module.gen = gen; + gen->default_module.checker = c; map_set(&gen->modules, cast(void *)1, &gen->default_module); - lb_init_module(&gen->default_module, c); + lb_init_module(&gen->default_module, do_threading); + + thread_pool_wait(); for (auto const &entry : gen->modules) { lbModule *m = entry.value; @@ -158,6 +265,10 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) { } mpsc_init(&gen->entities_to_correct_linkage, heap_allocator()); + mpsc_init(&gen->objc_selectors, heap_allocator()); + mpsc_init(&gen->objc_classes, heap_allocator()); + mpsc_init(&gen->objc_ivars, heap_allocator()); + mpsc_init(&gen->raddebug_section_strings, heap_allocator()); return true; } @@ -341,7 +452,7 @@ gb_internal LLVMValueRef llvm_const_insert_value(lbModule *m, LLVMValueRef agg, gb_internal LLVMValueRef llvm_cstring(lbModule *m, String const &str) { - lbValue v = lb_find_or_add_entity_string(m, str); + lbValue v = lb_find_or_add_entity_string(m, str, false); unsigned indices[1] = {0}; return llvm_const_extract_value(m, v.value, indices, gb_count_of(indices)); } @@ -384,9 +495,9 @@ gb_internal lbModule *lb_module_of_expr(lbGenerator *gen, Ast *expr) { return &gen->default_module; } -gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) { - GB_ASSERT(e != nullptr); +gb_internal lbModule *lb_module_of_entity_internal(lbGenerator *gen, Entity *e, lbModule *curr_module) { lbModule **found = nullptr; + if (e->kind == Entity_Procedure && e->decl_info && e->decl_info->code_gen_module) { @@ -409,6 +520,22 @@ gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) { return &gen->default_module; } + +gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e, lbModule *curr_module) { + GB_ASSERT(e != nullptr); + GB_ASSERT(curr_module != nullptr); + lbModule *m = lb_module_of_entity_internal(gen, e, curr_module); + + if (USE_SEPARATE_MODULES) { + if (e->kind == Entity_Procedure && e->Procedure.generated_from_polymorphic) { + if (m->polymorphic_module) { + return m->polymorphic_module; + } + } + } + return m; +} + gb_internal lbAddr lb_addr(lbValue addr) { lbAddr v = {lbAddr_Default, addr}; return v; @@ -528,8 +655,11 @@ gb_internal lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { break; case lbAddr_Swizzle: + GB_PANIC("lbAddr_Swizzle should be handled elsewhere"); + break; + case lbAddr_SwizzleLarge: - // TOOD(bill): is this good enough logic? + GB_PANIC("lbAddr_SwizzleLarge should be handled elsewhere"); break; } @@ -547,13 +677,25 @@ gb_internal void lb_set_file_line_col(lbProcedure *p, Array arr, TokenP i32 line = pos.line; i32 col = pos.column; - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: file = obfuscate_string(file, "F"); line = obfuscate_i32(line); col = obfuscate_i32(col); + break; + case SourceCodeLocationInfo_Filename: + file = last_path_element(file); + break; + case SourceCodeLocationInfo_None: + file = str_lit(""); + line = 0; + col = 0; + break; } - arr[0] = lb_find_or_add_entity_string(p->module, file); + arr[0] = lb_find_or_add_entity_string(p->module, file, false); arr[1] = lb_const_int(p->module, t_i32, line); arr[2] = lb_const_int(p->module, t_i32, col); } @@ -870,8 +1012,8 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { Type *t = base_type(type_deref(addr.addr.type)); GB_ASSERT(t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None); lbValue len = lb_soa_struct_len(p, addr.addr); - if (addr.soa.index_expr != nullptr) { - lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), index, len); + if (addr.soa.index_expr != nullptr && (!lb_is_const(addr.soa.index) || t->Struct.soa_kind != StructSoa_Fixed)) { + lb_emit_bounds_check(p, ast_token(addr.soa.index_expr), addr.soa.index, len); } } @@ -904,7 +1046,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { GB_ASSERT(value.value != nullptr); value = lb_emit_conv(p, value, lb_addr_type(addr)); - lbValue dst = lb_addr_get_ptr(p, addr); + lbValue dst = addr.addr; lbValue src = lb_address_from_load_or_generate_local(p, value); { lbValue src_ptrs[4] = {}; @@ -930,7 +1072,7 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { GB_ASSERT(value.value != nullptr); value = lb_emit_conv(p, value, lb_addr_type(addr)); - lbValue dst = lb_addr_get_ptr(p, addr); + lbValue dst = addr.addr; lbValue src = lb_address_from_load_or_generate_local(p, value); for_array(i, addr.swizzle_large.indices) { lbValue src_ptr = lb_emit_array_epi(p, src, i); @@ -1374,8 +1516,11 @@ gb_internal lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { unsigned element_count = LLVMCountStructElementTypes(uvt); GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); + LLVMValueRef ptr = u.value; + ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(uvt, 0), ""); + lbValue tag_ptr = {}; - tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, ""); + tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, ptr, 1, ""); tag_ptr.type = alloc_type_pointer(tag_type); return tag_ptr; } @@ -1600,8 +1745,92 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t map_set(&m->func_raw_types, type, new_abi_fn_type); return new_abi_fn_type; - } + + +gb_internal LLVMTypeRef lb_type_internal_union_block_type(lbModule *m, Type *type) { + GB_ASSERT(type->kind == Type_Union); + + if (type->Union.variants.count <= 0) { + return nullptr; + } + if (type->Union.variants.count == 1) { + return lb_type(m, type->Union.variants[0]); + } + + i64 align = type_align_of(type); + + unsigned block_size = cast(unsigned)type->Union.variant_block_size; + if (block_size == 0) { + return lb_type_padding_filler(m, block_size, align); + } + + bool all_pointers = align == build_context.ptr_size; + for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) { + Type *t = type->Union.variants[i]; + if (!is_type_internally_pointer_like(t)) { + all_pointers = false; + } + } + if (all_pointers) { + return lb_type(m, t_rawptr); + } + + { + Type *pt = type->Union.variants[0]; + for (isize i = 1; i < type->Union.variants.count; i++) { + Type *t = type->Union.variants[i]; + if (!are_types_identical(pt, t)) { + goto end_check_for_all_the_same; + } + } + return lb_type(m, pt); + } end_check_for_all_the_same:; + + { + Type *first_different = nullptr; + for (isize i = 0; i < type->Union.variants.count; i++) { + Type *t = type->Union.variants[i]; + if (type_size_of(t) == 0) { + continue; + } + if (first_different == nullptr) { + first_different = t; + } else if (!are_types_identical(first_different, t)) { + goto end_rest_zero_except_one; + } + } + if (first_different != nullptr) { + return lb_type(m, first_different); + } + } end_rest_zero_except_one:; + + // { + // LLVMTypeRef first_different = nullptr; + // for (isize i = 0; i < type->Union.variants.count; i++) { + // Type *t = type->Union.variants[i]; + // if (type_size_of(t) == 0) { + // continue; + // } + // if (first_different == nullptr) { + // first_different = lb_type(m, base_type(t)); + // } else { + // LLVMTypeRef llvm_t = lb_type(m, base_type(t)); + // if (llvm_t != first_different) { + // goto end_rest_zero_except_one_llvm_like; + // } + // } + // } + // if (first_different != nullptr) { + // return first_different; + // } + // } end_rest_zero_except_one_llvm_like:; + + + return lb_type_padding_filler(m, block_size, align); +} + + gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { LLVMContextRef ctx = m->ctx; i64 size = type_size_of(type); // Check size @@ -1779,6 +2008,37 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return type; } case Basic_cstring: return LLVMPointerType(LLVMInt8TypeInContext(ctx), 0); + + + case Basic_string16: + { + char const *name = "..string16"; + LLVMTypeRef type = LLVMGetTypeByName(m->mod, name); + if (type != nullptr) { + return type; + } + type = LLVMStructCreateNamed(ctx, name); + + if (build_context.metrics.ptr_size < build_context.metrics.int_size) { + GB_ASSERT(build_context.metrics.ptr_size == 4); + GB_ASSERT(build_context.metrics.int_size == 8); + LLVMTypeRef fields[3] = { + LLVMPointerType(lb_type(m, t_u16), 0), + lb_type(m, t_i32), + lb_type(m, t_int), + }; + LLVMStructSetBody(type, fields, 3, false); + } else { + LLVMTypeRef fields[2] = { + LLVMPointerType(lb_type(m, t_u16), 0), + lb_type(m, t_int), + }; + LLVMStructSetBody(type, fields, 2, false); + } + return type; + } + case Basic_cstring16: return LLVMPointerType(LLVMInt16TypeInContext(ctx), 0); + case Basic_any: { char const *name = "..any"; @@ -1982,26 +2242,26 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_Struct: { type_set_offsets(type); - + i64 full_type_size = type_size_of(type); i64 full_type_align = type_align_of(type); GB_ASSERT(full_type_size % full_type_align == 0); - + if (type->Struct.is_raw_union) { - + lbStructFieldRemapping field_remapping = {}; slice_init(&field_remapping, permanent_allocator(), 1); - + LLVMTypeRef fields[1] = {}; fields[0] = lb_type_padding_filler(m, full_type_size, full_type_align); field_remapping[0] = 0; - + LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false); map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping); map_set(&m->struct_field_remapping, cast(void *)type, field_remapping); return struct_type; } - + lbStructFieldRemapping field_remapping = {}; slice_init(&field_remapping, permanent_allocator(), type->Struct.fields.count); @@ -2014,7 +2274,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { LLVMTypeRef padding_type = lb_type_padding_filler(m, 0, type_align_of(type)); array_add(&fields, padding_type); } - + i64 prev_offset = 0; bool requires_packing = type->Struct.is_packed; for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) { @@ -2045,7 +2305,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { prev_offset = offset + type_size_of(field->type); } - + i64 end_padding = full_type_size-prev_offset; if (end_padding > 0) { array_add(&fields, lb_type_padding_filler(m, end_padding, 1)); @@ -2054,14 +2314,14 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { for_array(i, fields) { GB_ASSERT(fields[i] != nullptr); } - + LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, requires_packing); map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping); - map_set(&m->struct_field_remapping, cast(void *)type, field_remapping); + map_set(&m->struct_field_remapping, cast(void *)type, field_remapping); #if 0 - GB_ASSERT_MSG(lb_sizeof(struct_type) == full_type_size, - "(%lld) %s vs (%lld) %s", - cast(long long)lb_sizeof(struct_type), LLVMPrintTypeToString(struct_type), + GB_ASSERT_MSG(lb_sizeof(struct_type) == full_type_size, + "(%lld) %s vs (%lld) %s", + cast(long long)lb_sizeof(struct_type), LLVMPrintTypeToString(struct_type), cast(long long)full_type_size, type_to_string(type)); #endif return struct_type; @@ -2083,15 +2343,26 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false); } - unsigned block_size = cast(unsigned)type->Union.variant_block_size; - auto fields = array_make(temporary_allocator(), 0, 3); if (is_type_union_maybe_pointer(type)) { LLVMTypeRef variant = lb_type(m, type->Union.variants[0]); array_add(&fields, variant); + } else if (type->Union.variants.count == 1) { + LLVMTypeRef block_type = lb_type(m, type->Union.variants[0]); + + LLVMTypeRef tag_type = lb_type(m, union_tag_type(type)); + array_add(&fields, block_type); + array_add(&fields, tag_type); + i64 used_size = lb_sizeof(block_type) + lb_sizeof(tag_type); + i64 padding = size - used_size; + if (padding > 0) { + LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, align); + array_add(&fields, padding_type); + } } else { - LLVMTypeRef block_type = lb_type_padding_filler(m, block_size, align); - LLVMTypeRef tag_type = lb_type(m, union_tag_type(type)); + LLVMTypeRef block_type = lb_type_internal_union_block_type(m, type); + + LLVMTypeRef tag_type = lb_type(m, union_tag_type(type)); array_add(&fields, block_type); array_add(&fields, tag_type); i64 used_size = lb_sizeof(block_type) + lb_sizeof(tag_type); @@ -2171,7 +2442,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { field_count = 3; } LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count); - fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0); + fields[0] = LLVMPointerType(lb_type(m, type->SoaPointer.elem), 0); if (bigger_int) { fields[1] = lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size); fields[2] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.int_size); @@ -2183,6 +2454,14 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_BitField: return lb_type_internal(m, type->BitField.backing_type); + + case Type_Generic: + if (type->Generic.specialized) { + return lb_type_internal(m, type->Generic.specialized); + } else { + // For unspecialized generics, use a pointer type as a placeholder + return LLVMPointerType(LLVMInt8TypeInContext(m->ctx), 0); + } } GB_PANIC("Invalid type %s", type_to_string(type)); @@ -2348,6 +2627,29 @@ gb_internal void lb_add_attribute_to_proc_with_string(lbModule *m, LLVMValueRef } +gb_internal bool lb_apply_thread_local_model(LLVMValueRef value, String model) { + if (model != "") { + LLVMSetThreadLocal(value, true); + + LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel; + if (model == "default") { + mode = LLVMGeneralDynamicTLSModel; + } else if (model == "localdynamic") { + mode = LLVMLocalDynamicTLSModel; + } else if (model == "initialexec") { + mode = LLVMInitialExecTLSModel; + } else if (model == "localexec") { + mode = LLVMLocalExecTLSModel; + } else { + GB_PANIC("Unhandled thread local mode %.*s", LIT(model)); + } + LLVMSetThreadLocalMode(value, mode); + return true; + } + + return false; +} + gb_internal void lb_add_edge(lbBlock *from, lbBlock *to) { LLVMValueRef instr = LLVMGetLastInstruction(from->block); @@ -2486,10 +2788,13 @@ general_end:; } } - src_size = align_formula(src_size, src_align); - dst_size = align_formula(dst_size, dst_align); + // NOTE(laytan): even though this logic seems sound, the Address Sanitizer does not + // want you to load/store the space of a value that is there for alignment. +#if 0 + i64 aligned_src_size = align_formula(src_size, src_align); + i64 aligned_dst_size = align_formula(dst_size, dst_align); - if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) { + if (LLVMIsALoadInst(val) && (aligned_src_size >= aligned_dst_size && src_align >= dst_align)) { LLVMValueRef val_ptr = LLVMGetOperand(val, 0); val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), ""); LLVMValueRef loaded_val = OdinLLVMBuildLoad(p, dst_type, val_ptr); @@ -2497,8 +2802,60 @@ general_end:; // LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align)); return loaded_val; + } +#endif + + if (src_size > dst_size) { + GB_ASSERT(p->decl_block != p->curr_block); + // NOTE(laytan): src is bigger than dst, need to memcpy the part of src we want. + + LLVMTypeRef llvm_src_type = LLVMPointerType(src_type, 0); + LLVMTypeRef llvm_dst_type = LLVMPointerType(dst_type, 0); + + LLVMValueRef val_ptr; + if (LLVMIsALoadInst(val)) { + val_ptr = LLVMGetOperand(val, 0); + } else if (LLVMIsAAllocaInst(val)) { + val_ptr = LLVMBuildPointerCast(p->builder, val, llvm_src_type, ""); + } else { + // NOTE(laytan): we need a pointer to memcpy from. + LLVMValueRef val_copy = llvm_alloca(p, src_type, src_align); + val_ptr = LLVMBuildPointerCast(p->builder, val_copy, llvm_src_type, ""); + LLVMBuildStore(p->builder, val, val_ptr); + } + + i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type)); + max_align = gb_max(max_align, 16); + + LLVMValueRef ptr = llvm_alloca(p, dst_type, max_align); + LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, llvm_dst_type, ""); + + LLVMTypeRef types[3] = { + llvm_dst_type, + llvm_src_type, + lb_type(p->module, t_int) + }; + + LLVMValueRef args[4] = { + nptr, + val_ptr, + LLVMConstInt(LLVMIntTypeInContext(p->module->ctx, 8*cast(unsigned)build_context.int_size), dst_size, 0), + LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, 0), + }; + + lb_call_intrinsic( + p, + "llvm.memcpy.inline", + args, + gb_count_of(args), + types, + gb_count_of(types) + ); + + return OdinLLVMBuildLoad(p, dst_type, ptr); } else { GB_ASSERT(p->decl_block != p->curr_block); + GB_ASSERT(dst_size >= src_size); i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type)); max_align = gb_max(max_align, 16); @@ -2514,9 +2871,14 @@ general_end:; -gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { - StringHashKey key = string_hash_string(str); - LLVMValueRef *found = string_map_get(&m->const_strings, key); +gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str, bool custom_link_section) { + StringHashKey key = {}; + LLVMValueRef *found = nullptr; + + if (!custom_link_section) { + key = string_hash_string(str); + found = string_map_get(&m->const_strings, key); + } if (found != nullptr) { return *found; } else { @@ -2539,15 +2901,68 @@ gb_internal LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String co LLVMSetAlignment(global_data, 1); LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); - string_map_set(&m->const_strings, key, ptr); + if (!custom_link_section) { + string_map_set(&m->const_strings, key, ptr); + } return ptr; } } -gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) { +gb_internal LLVMValueRef lb_find_or_add_entity_string16_ptr(lbModule *m, String16 const &str, bool custom_link_section) { + String16HashKey key = {}; + LLVMValueRef *found = nullptr; + + if (!custom_link_section) { + key = string_hash_string(str); + found = string16_map_get(&m->const_string16s, key); + } + if (found != nullptr) { + return *found; + } + + + + LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; + + LLVMValueRef data = nullptr; + { + LLVMTypeRef llvm_u16 = LLVMInt16TypeInContext(m->ctx); + + TEMPORARY_ALLOCATOR_GUARD(); + + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, str.len+1); + + for (isize i = 0; i < str.len; i++) { + values[i] = LLVMConstInt(llvm_u16, str.text[i], false); + } + values[str.len] = LLVMConstInt(llvm_u16, 0, false); + + data = LLVMConstArray(llvm_u16, values, cast(unsigned)(str.len+1)); + } + + + u32 id = m->global_array_index.fetch_add(1); + gbString name = gb_string_make(temporary_allocator(), "csbs$"); + name = gb_string_appendc(name, m->module_name); + name = gb_string_append_fmt(name, "$%x", id); + + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); + LLVMSetInitializer(global_data, data); + lb_make_global_private_const(global_data); + LLVMSetAlignment(global_data, 2); + + LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); + if (!custom_link_section) { + string16_map_set(&m->const_string16s, key, ptr); + } + return ptr; +} + +gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str, bool custom_link_section) { LLVMValueRef ptr = nullptr; if (str.len != 0) { - ptr = lb_find_or_add_entity_string_ptr(m, str); + ptr = lb_find_or_add_entity_string_ptr(m, str, custom_link_section); } else { ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); } @@ -2604,6 +3019,60 @@ gb_internal lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule * return res; } +gb_internal lbValue lb_find_or_add_entity_string16_slice_with_type(lbModule *m, String16 const &str, Type *slice_type) { + GB_ASSERT(is_type_slice(slice_type)); + LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; + LLVMValueRef data = nullptr; + { + LLVMTypeRef llvm_u16 = LLVMInt16TypeInContext(m->ctx); + + TEMPORARY_ALLOCATOR_GUARD(); + + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, str.len+1); + + for (isize i = 0; i < str.len; i++) { + values[i] = LLVMConstInt(llvm_u16, str.text[i], false); + } + values[str.len] = LLVMConstInt(llvm_u16, 0, false); + + data = LLVMConstArray(llvm_u16, values, cast(unsigned)(str.len+1)); + } + + u32 id = m->global_array_index.fetch_add(1); + gbString name = gb_string_make(temporary_allocator(), "csba$"); + name = gb_string_appendc(name, m->module_name); + name = gb_string_append_fmt(name, "$%x", id); + + LLVMTypeRef type = LLVMTypeOf(data); + LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name); + LLVMSetInitializer(global_data, data); + lb_make_global_private_const(global_data); + LLVMSetAlignment(global_data, 2); + + i64 data_len = str.len; + LLVMValueRef ptr = nullptr; + if (data_len != 0) { + ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2); + } else { + ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); + } + if (!is_type_u16_slice(slice_type)) { + Type *bt = base_type(slice_type); + Type *elem = bt->Slice.elem; + i64 sz = type_size_of(elem); + GB_ASSERT(sz > 0); + ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem))); + data_len /= sz; + } + + LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), data_len, true); + LLVMValueRef values[2] = {ptr, len}; + + lbValue res = {}; + res.value = llvm_const_named_struct(m, slice_type, values, 2); + res.type = slice_type; + return res; +} gb_internal lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *expr) { @@ -2637,7 +3106,7 @@ gb_internal lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *e return lb_find_procedure_value_from_entity(m, e); } if (USE_SEPARATE_MODULES) { - lbModule *other_module = lb_module_of_entity(m->gen, e); + lbModule *other_module = lb_module_of_entity(m->gen, e, m); if (other_module != m) { String name = lb_get_entity_name(other_module, e); @@ -2667,6 +3136,7 @@ gb_internal lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *e gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) { lbGenerator *gen = m->gen; + GB_ASSERT(e != nullptr); GB_ASSERT(is_type_proc(e->type)); e = strip_entity_wrapping(e); GB_ASSERT(e != nullptr); @@ -2684,7 +3154,7 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) lbModule *other_module = m; if (USE_SEPARATE_MODULES) { - other_module = lb_module_of_entity(gen, e); + other_module = lb_module_of_entity(gen, e, m); } if (other_module == m) { debugf("Missing Procedure (lb_find_procedure_value_from_entity): %.*s module %p\n", LIT(e->token.string), m); @@ -2692,10 +3162,15 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) ignore_body = other_module != m; lbProcedure *missing_proc = lb_create_procedure(m, e, ignore_body); - if (ignore_body) { - mutex_lock(&gen->anonymous_proc_lits_mutex); - defer (mutex_unlock(&gen->anonymous_proc_lits_mutex)); + if (missing_proc == nullptr) { + // This is an unspecialized polymorphic procedure, which should not be codegen'd + lbValue dummy = {}; + dummy.value = nullptr; + dummy.type = nullptr; + return dummy; + } + if (ignore_body) { GB_ASSERT(other_module != nullptr); rw_mutex_shared_lock(&other_module->values_mutex); auto *found = map_get(&other_module->values, e); @@ -2703,10 +3178,10 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) if (found == nullptr) { // THIS IS THE RACE CONDITION lbProcedure *missing_proc_in_other_module = lb_create_procedure(other_module, e, false); - array_add(&other_module->missing_procedures_to_check, missing_proc_in_other_module); + mpsc_enqueue(&other_module->missing_procedures_to_check, missing_proc_in_other_module); } } else { - array_add(&m->missing_procedures_to_check, missing_proc); + mpsc_enqueue(&m->missing_procedures_to_check, missing_proc); } rw_mutex_shared_lock(&m->values_mutex); @@ -2724,18 +3199,16 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent) { lbGenerator *gen = m->gen; - - mutex_lock(&gen->anonymous_proc_lits_mutex); - defer (mutex_unlock(&gen->anonymous_proc_lits_mutex)); - - TokenPos pos = ast_token(expr).pos; - lbProcedure **found = map_get(&gen->anonymous_proc_lits, expr); - if (found) { - return lb_find_procedure_value_from_entity(m, (*found)->entity); - } + gb_unused(gen); ast_node(pl, ProcLit, expr); + if (pl->decl->entity.load() != nullptr) { + return lb_find_procedure_value_from_entity(m, pl->decl->entity.load()); + } + + TokenPos pos = ast_token(expr).pos; + // NOTE(bill): Generate a new name // parent$count isize name_len = prefix_name.len + 6 + 11; @@ -2753,30 +3226,51 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr token.string = name; Entity *e = alloc_entity_procedure(nullptr, token, type, pl->tags); e->file = expr->file(); + e->scope = e->file->scope; + + lbModule *target_module = m; + GB_ASSERT(target_module != nullptr); // NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time - pl->decl->code_gen_module = m; + pl->decl->code_gen_module = target_module; e->decl_info = pl->decl; - pl->decl->entity = e; e->parent_proc_decl = pl->decl->parent; e->Procedure.is_anonymous = true; e->flags |= EntityFlag_ProcBodyChecked; - lbProcedure *p = lb_create_procedure(m, e); - GB_ASSERT(e->code_gen_module == m); + pl->decl->entity.store(e); - lbValue value = {}; - value.value = p->value; - value.type = p->type; - map_set(&gen->anonymous_proc_lits, expr, p); - array_add(&m->procedures_to_generate, p); - if (parent != nullptr) { - array_add(&parent->children, p); + if (target_module != m) { + rw_mutex_shared_lock(&target_module->values_mutex); + lbValue *found = map_get(&target_module->values, e); + rw_mutex_shared_unlock(&target_module->values_mutex); + if (found == nullptr) { + lbProcedure *missing_proc_in_target_module = lb_create_procedure(target_module, e, false); + mpsc_enqueue(&target_module->missing_procedures_to_check, missing_proc_in_target_module); + } + + lbProcedure *p = lb_create_procedure(m, e, true); + + lbValue value = {}; + value.value = p->value; + value.type = p->type; + return value; } else { - string_map_set(&m->members, name, value); + lbProcedure *p = lb_create_procedure(m, e); + + lbValue value = {}; + value.value = p->value; + value.type = p->type; + + mpsc_enqueue(&m->procedures_to_generate, p); + if (parent != nullptr) { + array_add(&parent->children, p); + } else { + string_map_set(&m->members, name, value); + } + return value; } - return value; } @@ -2785,15 +3279,18 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb GB_ASSERT(type != nullptr); type = default_type(type); - u8 *str = cast(u8 *)gb_alloc_array(temporary_allocator(), u8, name.len); - memcpy(str, name.text, name.len); - str[name.len] = 0; + LLVMTypeRef actual_type = lb_type(m, type); + if (value.value != nullptr) { + LLVMTypeRef value_type = LLVMTypeOf(value.value); + GB_ASSERT_MSG(lb_sizeof(actual_type) == lb_sizeof(value_type), "%s vs %s", LLVMPrintTypeToString(actual_type), LLVMPrintTypeToString(value_type)); + actual_type = value_type; + } Scope *scope = nullptr; Entity *e = alloc_entity_variable(scope, make_token_ident(name), type); lbValue g = {}; g.type = alloc_type_pointer(type); - g.value = LLVMAddGlobal(m->mod, lb_type(m, type), cast(char const *)str); + g.value = LLVMAddGlobal(m->mod, actual_type, alloc_cstring(temporary_allocator(), name)); if (value.value != nullptr) { GB_ASSERT_MSG(LLVMIsConstant(value.value), LLVMPrintValueToString(value.value)); LLVMSetInitializer(g.value, value.value); @@ -2801,6 +3298,8 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, type))); } + g.value = LLVMConstPointerCast(g.value, lb_type(m, g.type)); + lb_add_entity(m, e, g); lb_add_member(m, name, g); @@ -2863,7 +3362,7 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) { } if (USE_SEPARATE_MODULES) { - lbModule *other_module = lb_module_of_entity(m->gen, e); + lbModule *other_module = lb_module_of_entity(m->gen, e, m); bool is_external = other_module != m; if (!is_external) { @@ -2888,25 +3387,7 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) { lb_set_entity_from_other_modules_linkage_correctly(other_module, e, name); - if (e->Variable.thread_local_model != "") { - LLVMSetThreadLocal(g.value, true); - - String m = e->Variable.thread_local_model; - LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel; - if (m == "default") { - mode = LLVMGeneralDynamicTLSModel; - } else if (m == "localdynamic") { - mode = LLVMLocalDynamicTLSModel; - } else if (m == "initialexec") { - mode = LLVMInitialExecTLSModel; - } else if (m == "localexec") { - mode = LLVMLocalExecTLSModel; - } else { - GB_PANIC("Unhandled thread local mode %.*s", LIT(m)); - } - LLVMSetThreadLocalMode(g.value, mode); - } - + lb_apply_thread_local_model(g.value, e->Variable.thread_local_model); return g; } @@ -3038,6 +3519,13 @@ gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero if (e != nullptr) { lb_add_entity(p->module, e, val); lb_add_debug_local_variable(p, ptr, type, e->token); + + // NOTE(lucas): In LLVM 20 and below we do not have the option to have asan cleanup poisoned stack + // locals ourselves. So we need to manually track and unpoison these locals on proc return. + // LLVM 21 adds the 'use-after-scope' asan option which does this for us. + if (build_context.sanitizer_flags & SanitizerFlag_Address && !p->entity->Procedure.no_sanitize_address) { + array_add(&p->asan_stack_locals, val); + } } if (zero_init) { diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index 7fe1359b4..8d5cfcb70 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -516,7 +516,7 @@ gb_internal void llvm_delete_function(LLVMValueRef func) { LLVMDeleteFunction(func); } -gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) { +gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef value) { LLVMValueRef global = LLVMGetNamedGlobal(m->mod, "llvm.compiler.used"); LLVMValueRef *constants; @@ -544,7 +544,7 @@ gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) { LLVMTypeRef Int8PtrTy = LLVMPointerType(LLVMInt8TypeInContext(m->ctx), 0); LLVMTypeRef ATy = llvm_array_type(Int8PtrTy, operands); - constants[operands - 1] = LLVMConstBitCast(func, Int8PtrTy); + constants[operands - 1] = LLVMConstBitCast(value, Int8PtrTy); LLVMValueRef initializer = LLVMConstArray(Int8PtrTy, constants, operands); global = LLVMAddGlobal(m->mod, ATy, "llvm.compiler.used"); diff --git a/src/llvm_backend_passes.cpp b/src/llvm_backend_passes.cpp new file mode 100644 index 000000000..bea95ce8e --- /dev/null +++ b/src/llvm_backend_passes.cpp @@ -0,0 +1,1195 @@ + switch (build_context.optimization_level) { + case -1: + array_add(&passes, "function(annotation-remarks)"); + break; + case 0: + array_add(&passes, "always-inline"); + array_add(&passes, "function(annotation-remarks)"); + break; + case 1: +// default +// Passes removed: coro, openmp, sroa +#if LLVM_VERSION_MAJOR == 17 + array_add(&passes, u8R"( +annotation2metadata, +forceattrs, +inferattrs, +function( + lower-expect, + simplifycfg, + early-cse<> +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + inline, + function-attrs, + function( + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + constraint-elimination, + tailcallelim, + simplifycfg, + reassociate, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + loop-deletion, + loop-unroll-full + ), + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + float2int, + lower-constant-intrinsics, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); +#elif LLVM_VERSION_MAJOR < 20 + array_add(&passes, u8R"( +annotation2metadata, +forceattrs, +inferattrs, +function( + lower-expect, + simplifycfg, + sroa, + early-cse<> +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +always-inline, +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + function-attrs, + function( + sroa, + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + tailcallelim, + simplifycfg, + reassociate, + constraint-elimination, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + loop-deletion, + loop-unroll-full + ), + sroa, + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + float2int, + lower-constant-intrinsics, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + infer-alignment, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + sroa, + infer-alignment, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); +#else + array_add(&passes, u8R"( +annotation2metadata, +forceattrs, +inferattrs, +function( + ee-instrument<>, + lower-expect, + simplifycfg, + sroa, + early-cse<> +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +always-inline, +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + function-attrs, + function( + sroa, + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + tailcallelim, + simplifycfg, + reassociate, + constraint-elimination, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + extra-simple-loop-unswitch-passes, + loop-deletion,loop-unroll-full + ), + sroa, + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + float2int, + lower-constant-intrinsics, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + infer-alignment, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + sroa, + infer-alignment, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); + +#endif + break; +// default +// Passes removed: coro, openmp, sroa + case 2: +#if LLVM_VERSION_MAJOR == 17 + array_add(&passes, u8R"( +annotation2metadata, +forceattrs, +inferattrs, +function( + lower-expect, + simplifycfg, + early-cse<> +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + inline, + function-attrs, + function( + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + constraint-elimination, + libcalls-shrinkwrap, + tailcallelim, + simplifycfg, + reassociate, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + loop-deletion, + loop-unroll-full + ), + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + float2int, + lower-constant-intrinsics, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); +#elif LLVM_VERSION_MAJOR < 20 + array_add(&passes, u8R"( +annotation2metadata, +forceattrs, +inferattrs, +function( + lower-expect, + simplifycfg, + sroa, + early-cse<> +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +always-inline, +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + function-attrs, + function( + sroa, + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + libcalls-shrinkwrap, + tailcallelim, + simplifycfg, + reassociate, + constraint-elimination, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + loop-deletion, + loop-unroll-full + ), + sroa, + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + float2int, + lower-constant-intrinsics, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + infer-alignment, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + sroa, + infer-alignment, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); +#else + array_add(&passes, u8R"( +annotation2metadata, +forceattrs, +inferattrs, +function( + ee-instrument<>, + lower-expect, + simplifycfg, + sroa, + early-cse<> +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +always-inline, +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + function-attrs, + function( + sroa, + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + libcalls-shrinkwrap, + tailcallelim, + simplifycfg, + reassociate, + constraint-elimination, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + extra-simple-loop-unswitch-passes, + loop-deletion, + loop-unroll-full + ), + sroa, + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + float2int, + lower-constant-intrinsics, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + infer-alignment, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + sroa, + infer-alignment, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); +#endif + break; + + case 3: +// default +// Passes removed: coro, openmp, sroa +#if LLVM_VERSION_MAJOR == 17 + array_add(&passes, u8R"( +annotation2metadata, +forceattrs, +inferattrs, +function( + lower-expect, + simplifycfg, + early-cse<>, + callsite-splitting +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + inline, + function-attrs, + argpromotion, + function( + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + constraint-elimination, + libcalls-shrinkwrap, + tailcallelim, + simplifycfg, + reassociate, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + loop-deletion, + loop-unroll-full + ), + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + float2int, + lower-constant-intrinsics, + chr, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); + +#elif LLVM_VERSION_MAJOR < 20 + array_add(&passes, u8R"( +annotation2metadata, +forceattrs, +inferattrs, +function( + lower-expect, + simplifycfg, + sroa, + early-cse<>, + callsite-splitting +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +always-inline, +require, +function(invalidate), +require, +cgscc( + devirt<4>( + inline, + function-attrs, + argpromotion, + function( + sroa, + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + libcalls-shrinkwrap, + tailcallelim, + simplifycfg, + reassociate, + constraint-elimination, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + loop-deletion, + loop-unroll-full + ), + sroa, + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa(licm), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + float2int, + lower-constant-intrinsics, + chr, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + infer-alignment, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + sroa, + infer-alignment, + instcombine, + loop-mssa(licm), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify +)"); +#else + array_add(&passes, u8R"( +annotation2metadata, +forceattrs, +inferattrs, +function( + ee-instrument<>, + lower-expect, + simplifycfg, + sroa, + early-cse<>, + callsite-splitting +), +ipsccp, +called-value-propagation, +globalopt, +function( + mem2reg, + instcombine, + simplifycfg +), +always-inline, +require, +function( + invalidate +), +require, +cgscc( + devirt<4>( + inline, + function-attrs, + argpromotion, + function( + sroa, + early-cse, + speculative-execution, + jump-threading, + correlated-propagation, + simplifycfg, + instcombine, + aggressive-instcombine, + libcalls-shrinkwrap, + tailcallelim, + simplifycfg, + reassociate, + constraint-elimination, + loop-mssa( + loop-instsimplify, + loop-simplifycfg, + licm, + loop-rotate, + licm, + simple-loop-unswitch + ), + simplifycfg, + instcombine, + loop( + loop-idiom, + indvars, + extra-simple-loop-unswitch-passes, + loop-deletion, + loop-unroll-full + ), + sroa, + vector-combine, + mldst-motion, + gvn<>, + sccp, + bdce, + instcombine, + jump-threading, + correlated-propagation, + adce, + memcpyopt, + dse, + move-auto-init, + loop-mssa( + licm + ), + simplifycfg, + instcombine + ), + function-attrs, + function( + require + ) + ) +), +deadargelim, +globalopt, +globaldce, +elim-avail-extern, +rpo-function-attrs, +recompute-globalsaa, +function( + float2int, + lower-constant-intrinsics, + chr, + loop( + loop-rotate, + loop-deletion + ), + loop-distribute, + inject-tli-mappings, + loop-vectorize, + infer-alignment, + loop-load-elim, + instcombine, + simplifycfg, + slp-vectorizer, + vector-combine, + instcombine, + loop-unroll, + transform-warning, + sroa, + infer-alignment, + instcombine, + loop-mssa( + licm + ), + alignment-from-assumptions, + loop-sink, + instsimplify, + div-rem-pairs, + tailcallelim, + simplifycfg +), +globaldce, +constmerge, +cg-profile, +rel-lookup-table-converter, +function( + annotation-remarks +), +verify + +)"); + +#endif + break; + } \ No newline at end of file diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index a835ae2c8..08ef42f01 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -67,6 +67,14 @@ gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValu gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) { GB_ASSERT(entity != nullptr); GB_ASSERT(entity->kind == Entity_Procedure); + // Skip codegen for unspecialized polymorphic procedures + if (is_type_polymorphic(entity->type) && !entity->Procedure.is_foreign) { + Type *bt = base_type(entity->type); + if (bt->kind == Type_Proc && bt->Proc.is_polymorphic && !bt->Proc.is_poly_specialized) { + // Do not generate code for unspecialized polymorphic procedures + return nullptr; + } + } if (!entity->Procedure.is_foreign) { if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) { GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false)); @@ -76,7 +84,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i String link_name = {}; if (ignore_body) { - lbModule *other_module = lb_module_of_entity(m->gen, entity); + lbModule *other_module = lb_module_of_entity(m->gen, entity, m); link_name = lb_get_entity_name(other_module, entity); } else { link_name = lb_get_entity_name(m, entity); @@ -91,7 +99,6 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i } } - lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); p->module = m; @@ -115,12 +122,13 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i p->is_entry_point = false; gbAllocator a = heap_allocator(); - p->children.allocator = a; - p->defer_stmts.allocator = a; - p->blocks.allocator = a; - p->branch_blocks.allocator = a; - p->context_stack.allocator = a; - p->scope_stack.allocator = a; + p->children.allocator = a; + p->defer_stmts.allocator = a; + p->blocks.allocator = a; + p->branch_blocks.allocator = a; + p->context_stack.allocator = a; + p->scope_stack.allocator = a; + p->asan_stack_locals.allocator = a; // map_init(&p->selector_values, 0); // map_init(&p->selector_addr, 0); // map_init(&p->tuple_fix_map, 0); @@ -333,10 +341,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i } if (p->body && entity->pkg && ((entity->pkg->kind == Package_Normal) || (entity->pkg->kind == Package_Init))) { - if (build_context.sanitizer_flags & SanitizerFlag_Address) { + if (build_context.sanitizer_flags & SanitizerFlag_Address && !entity->Procedure.no_sanitize_address) { lb_add_attribute_to_proc(m, p->value, "sanitize_address"); } - if (build_context.sanitizer_flags & SanitizerFlag_Memory) { + if (build_context.sanitizer_flags & SanitizerFlag_Memory && !entity->Procedure.no_sanitize_memory) { lb_add_attribute_to_proc(m, p->value, "sanitize_memory"); } if (build_context.sanitizer_flags & SanitizerFlag_Thread) { @@ -385,11 +393,12 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name p->is_entry_point = false; gbAllocator a = permanent_allocator(); - p->children.allocator = a; - p->defer_stmts.allocator = a; - p->blocks.allocator = a; - p->branch_blocks.allocator = a; - p->context_stack.allocator = a; + p->children.allocator = a; + p->defer_stmts.allocator = a; + p->blocks.allocator = a; + p->branch_blocks.allocator = a; + p->context_stack.allocator = a; + p->asan_stack_locals.allocator = a; map_init(&p->tuple_fix_map, 0); @@ -536,6 +545,9 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { GB_ASSERT(p->type != nullptr); lb_ensure_abi_function_type(p->module, p); + if (p->type->Proc.calling_convention == ProcCC_Odin) { + lb_push_context_onto_stack_from_implicit_parameter(p); + } { lbFunctionType *ft = p->abi_function_type; @@ -733,9 +745,6 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { } } - if (p->type->Proc.calling_convention == ProcCC_Odin) { - lb_push_context_onto_stack_from_implicit_parameter(p); - } lb_set_debug_position_to_procedure_begin(p); if (p->debug_info != nullptr) { @@ -781,17 +790,15 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) { p->curr_block = nullptr; p->state_flags = 0; -} -gb_internal void lb_end_procedure(lbProcedure *p) { + LLVMDisposeBuilder(p->builder); } gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) { GB_ASSERT(pd->body != nullptr); lbModule *m = p->module; - auto *min_dep_set = &m->info->minimum_dependency_set; - if (ptr_set_exists(min_dep_set, e) == false) { + if (e->min_dep_count.load(std::memory_order_relaxed) == 0) { // NOTE(bill): Nothing depends upon it so doesn't need to be built return; } @@ -815,6 +822,10 @@ gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) e->Procedure.link_name = name; lbProcedure *nested_proc = lb_create_procedure(p->module, e); + if (nested_proc == nullptr) { + // This is an unspecialized polymorphic procedure, skip codegen + return; + } e->code_gen_procedure = nested_proc; lbValue value = {}; @@ -823,7 +834,7 @@ gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) lb_add_entity(m, e, value); array_add(&p->children, nested_proc); - array_add(&m->procedures_to_generate, nested_proc); + mpsc_enqueue(&m->procedures_to_generate, nested_proc); } @@ -910,13 +921,14 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue arg_type != param_type) { LLVMTypeKind arg_kind = LLVMGetTypeKind(arg_type); LLVMTypeKind param_kind = LLVMGetTypeKind(param_type); - if (arg_kind == param_kind && - arg_kind == LLVMPointerTypeKind) { - // NOTE(bill): LLVM's newer `ptr` only type system seems to fail at times - // I don't know why... - args[i] = LLVMBuildPointerCast(p->builder, args[i], param_type, ""); - arg_type = param_type; - continue; + if (arg_kind == param_kind) { + if (arg_kind == LLVMPointerTypeKind) { + // NOTE(bill): LLVM's newer `ptr` only type system seems to fail at times + // I don't know why... + args[i] = LLVMBuildPointerCast(p->builder, args[i], param_type, ""); + arg_type = param_type; + continue; + } } } @@ -972,6 +984,7 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue gb_internal lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) { AstPackage *pkg = m->info->runtime_package; Entity *e = scope_lookup_current(pkg->scope, name); + GB_ASSERT_MSG(e != nullptr, "Runtime procedure not found: %s", name); return lb_find_procedure_value_from_entity(m, e); } @@ -1060,6 +1073,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c lbValue result = {}; + isize ignored_args = 0; auto processed_args = array_make(permanent_allocator(), 0, args.count); { @@ -1082,6 +1096,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c lbArgType *arg = &ft->args[param_index]; if (arg->kind == lbArg_Ignore) { param_index += 1; + ignored_args += 1; continue; } @@ -1190,7 +1205,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c auto tuple_fix_values = slice_make(permanent_allocator(), ret_count); auto tuple_geps = slice_make(permanent_allocator(), ret_count); - isize offset = ft->original_arg_count; + isize offset = ft->original_arg_count - ignored_args; for (isize j = 0; j < ret_count-1; j++) { lbValue ret_arg_ptr = processed_args[offset + j]; lbValue ret_arg = lb_emit_load(p, ret_arg_ptr); @@ -1293,6 +1308,23 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn lbValue res = {}; res.type = tv.type; + switch (builtin_id) { + case BuiltinProc_simd_indices: { + Type *type = base_type(res.type); + GB_ASSERT(type->kind == Type_SimdVector); + Type *elem = type->SimdVector.elem; + + i64 count = type->SimdVector.count; + LLVMValueRef *scalars = gb_alloc_array(temporary_allocator(), LLVMValueRef, count); + for (i64 i = 0; i < count; i++) { + scalars[i] = lb_const_value(m, elem, exact_value_i64(i)).value; + } + + res.value = LLVMConstVector(scalars, cast(unsigned)count); + return res; + } + } + lbValue arg0 = {}; if (ce->args.count > 0) arg0 = lb_build_expr(p, ce->args[0]); lbValue arg1 = {}; if (ce->args.count > 1) arg1 = lb_build_expr(p, ce->args[1]); lbValue arg2 = {}; if (ce->args.count > 2) arg2 = lb_build_expr(p, ce->args[2]); @@ -1442,7 +1474,7 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn LLVMRealPredicate pred = cast(LLVMRealPredicate)0; switch (builtin_id) { case BuiltinProc_simd_lanes_eq: pred = LLVMRealOEQ; break; - case BuiltinProc_simd_lanes_ne: pred = LLVMRealONE; break; + case BuiltinProc_simd_lanes_ne: pred = LLVMRealUNE; break; case BuiltinProc_simd_lanes_lt: pred = LLVMRealOLT; break; case BuiltinProc_simd_lanes_le: pred = LLVMRealOLE; break; case BuiltinProc_simd_lanes_gt: pred = LLVMRealOGT; break; @@ -1478,6 +1510,38 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn res.value = LLVMBuildInsertElement(p->builder, arg0.value, arg2.value, arg1.value, ""); return res; + case BuiltinProc_simd_reduce_add_bisect: + case BuiltinProc_simd_reduce_mul_bisect: + { + GB_ASSERT(arg0.type->kind == Type_SimdVector); + i64 num_elems = arg0.type->SimdVector.count; + + LLVMValueRef *indices = gb_alloc_array(temporary_allocator(), LLVMValueRef, num_elems); + for (i64 i = 0; i < num_elems; i++) { + indices[i] = lb_const_int(m, t_uint, cast(u64)i).value; + } + + switch (builtin_id) { + case BuiltinProc_simd_reduce_add_bisect: op_code = is_float ? LLVMFAdd : LLVMAdd; break; + case BuiltinProc_simd_reduce_mul_bisect: op_code = is_float ? LLVMFMul : LLVMMul; break; + } + + LLVMValueRef remaining = arg0.value; + i64 num_remaining = num_elems; + + while (num_remaining > 1) { + num_remaining /= 2; + LLVMValueRef left_indices = LLVMConstVector(&indices[0], cast(unsigned)num_remaining); + LLVMValueRef left_value = LLVMBuildShuffleVector(p->builder, remaining, remaining, left_indices, ""); + LLVMValueRef right_indices = LLVMConstVector(&indices[num_remaining], cast(unsigned)num_remaining); + LLVMValueRef right_value = LLVMBuildShuffleVector(p->builder, remaining, remaining, right_indices, ""); + remaining = LLVMBuildBinOp(p->builder, op_code, left_value, right_value, ""); + } + + res.value = LLVMBuildExtractElement(p->builder, remaining, indices[0], ""); + return res; + } + case BuiltinProc_simd_reduce_add_ordered: case BuiltinProc_simd_reduce_mul_ordered: { @@ -1510,6 +1574,40 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn res.value = lb_call_intrinsic(p, name, args, cast(unsigned)args_count, types, gb_count_of(types)); return res; } + + case BuiltinProc_simd_reduce_add_pairs: + case BuiltinProc_simd_reduce_mul_pairs: + { + GB_ASSERT(arg0.type->kind == Type_SimdVector); + i64 num_elems = arg0.type->SimdVector.count; + + LLVMValueRef *indices = gb_alloc_array(temporary_allocator(), LLVMValueRef, num_elems); + for (i64 i = 0; i < num_elems/2; i++) { + indices[i] = lb_const_int(m, t_uint, cast(u64)(2*i)).value; + indices[i+num_elems/2] = lb_const_int(m, t_uint, cast(u64)(2*i+1)).value; + } + + switch (builtin_id) { + case BuiltinProc_simd_reduce_add_pairs: op_code = is_float ? LLVMFAdd : LLVMAdd; break; + case BuiltinProc_simd_reduce_mul_pairs: op_code = is_float ? LLVMFMul : LLVMMul; break; + } + + LLVMValueRef remaining = arg0.value; + i64 num_remaining = num_elems; + + while (num_remaining > 1) { + num_remaining /= 2; + LLVMValueRef left_indices = LLVMConstVector(&indices[0], cast(unsigned)num_remaining); + LLVMValueRef left_value = LLVMBuildShuffleVector(p->builder, remaining, remaining, left_indices, ""); + LLVMValueRef right_indices = LLVMConstVector(&indices[num_elems/2], cast(unsigned)num_remaining); + LLVMValueRef right_value = LLVMBuildShuffleVector(p->builder, remaining, remaining, right_indices, ""); + remaining = LLVMBuildBinOp(p->builder, op_code, left_value, right_value, ""); + } + + res.value = LLVMBuildExtractElement(p->builder, remaining, indices[0], ""); + return res; + } + case BuiltinProc_simd_reduce_min: case BuiltinProc_simd_reduce_max: case BuiltinProc_simd_reduce_and: @@ -1625,6 +1723,275 @@ gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAn return res; } + case BuiltinProc_simd_runtime_swizzle: + { + LLVMValueRef src = arg0.value; + LLVMValueRef indices = lb_build_expr(p, ce->args[1]).value; + + Type *vt = arg0.type; + GB_ASSERT(vt->kind == Type_SimdVector); + i64 count = vt->SimdVector.count; + Type *elem_type = vt->SimdVector.elem; + i64 elem_size = type_size_of(elem_type); + + // Determine strategy based on element size and target architecture + char const *intrinsic_name = nullptr; + bool use_hardware_runtime_swizzle = false; + + // 8-bit elements: Use dedicated table lookup instructions + if (elem_size == 1) { + use_hardware_runtime_swizzle = true; + + if (build_context.metrics.arch == TargetArch_amd64 || build_context.metrics.arch == TargetArch_i386) { + // x86/x86-64: Use pshufb intrinsics + switch (count) { + case 16: + intrinsic_name = "llvm.x86.ssse3.pshuf.b.128"; + break; + case 32: + intrinsic_name = "llvm.x86.avx2.pshuf.b"; + break; + case 64: + intrinsic_name = "llvm.x86.avx512.pshuf.b.512"; + break; + default: + use_hardware_runtime_swizzle = false; + break; + } + } else if (build_context.metrics.arch == TargetArch_arm64) { + // ARM64: Use NEON tbl intrinsics with automatic table splitting + switch (count) { + case 16: + intrinsic_name = "llvm.aarch64.neon.tbl1"; + break; + case 32: + intrinsic_name = "llvm.aarch64.neon.tbl2"; + break; + case 48: + intrinsic_name = "llvm.aarch64.neon.tbl3"; + break; + case 64: + intrinsic_name = "llvm.aarch64.neon.tbl4"; + break; + default: + use_hardware_runtime_swizzle = false; + break; + } + } else if (build_context.metrics.arch == TargetArch_arm32) { + // ARM32: Use NEON vtbl intrinsics with automatic table splitting + switch (count) { + case 8: + intrinsic_name = "llvm.arm.neon.vtbl1"; + break; + case 16: + intrinsic_name = "llvm.arm.neon.vtbl2"; + break; + case 24: + intrinsic_name = "llvm.arm.neon.vtbl3"; + break; + case 32: + intrinsic_name = "llvm.arm.neon.vtbl4"; + break; + default: + use_hardware_runtime_swizzle = false; + break; + } + } else if (build_context.metrics.arch == TargetArch_wasm32 || build_context.metrics.arch == TargetArch_wasm64p32) { + // WebAssembly: Use swizzle (only supports 16-byte vectors) + if (count == 16) { + intrinsic_name = "llvm.wasm.swizzle"; + } else { + use_hardware_runtime_swizzle = false; + } + } else { + use_hardware_runtime_swizzle = false; + } + } + + if (use_hardware_runtime_swizzle && intrinsic_name != nullptr) { + // Use dedicated hardware swizzle instruction + + // Check if required target features are enabled + bool features_enabled = true; + if (build_context.metrics.arch == TargetArch_amd64 || build_context.metrics.arch == TargetArch_i386) { + // x86/x86-64 feature checking + if (count == 16) { + // SSE/SSSE3 for 128-bit vectors + if (!check_target_feature_is_enabled(str_lit("ssse3"), nullptr)) { + features_enabled = false; + } + } else if (count == 32) { + // AVX2 requires ssse3 + avx2 features + if (!check_target_feature_is_enabled(str_lit("ssse3"), nullptr) || + !check_target_feature_is_enabled(str_lit("avx2"), nullptr)) { + features_enabled = false; + } + } else if (count == 64) { + // AVX512 requires ssse3 + avx2 + avx512f + avx512bw features + if (!check_target_feature_is_enabled(str_lit("ssse3"), nullptr) || + !check_target_feature_is_enabled(str_lit("avx2"), nullptr) || + !check_target_feature_is_enabled(str_lit("avx512f"), nullptr) || + !check_target_feature_is_enabled(str_lit("avx512bw"), nullptr)) { + features_enabled = false; + } + } + } else if (build_context.metrics.arch == TargetArch_arm64 || build_context.metrics.arch == TargetArch_arm32) { + // ARM/ARM64 feature checking - NEON is required for all table/swizzle ops + if (!check_target_feature_is_enabled(str_lit("neon"), nullptr)) { + features_enabled = false; + } + } + + if (features_enabled) { + // Add target features to function attributes for LLVM instruction selection + if (build_context.metrics.arch == TargetArch_amd64 || build_context.metrics.arch == TargetArch_i386) { + // x86/x86-64 function attributes + if (count == 16) { + // SSE/SSSE3 for 128-bit vectors + lb_add_attribute_to_proc_with_string(p->module, p->value, str_lit("target-features"), str_lit("+ssse3")); + lb_add_attribute_to_proc_with_string(p->module, p->value, str_lit("min-legal-vector-width"), str_lit("128")); + } else if (count == 32) { + lb_add_attribute_to_proc_with_string(p->module, p->value, str_lit("target-features"), str_lit("+avx,+avx2,+ssse3")); + lb_add_attribute_to_proc_with_string(p->module, p->value, str_lit("min-legal-vector-width"), str_lit("256")); + } else if (count == 64) { + lb_add_attribute_to_proc_with_string(p->module, p->value, str_lit("target-features"), str_lit("+avx,+avx2,+avx512f,+avx512bw,+ssse3")); + lb_add_attribute_to_proc_with_string(p->module, p->value, str_lit("min-legal-vector-width"), str_lit("512")); + } + } else if (build_context.metrics.arch == TargetArch_arm64) { + // ARM64 function attributes - enable NEON for swizzle instructions + lb_add_attribute_to_proc_with_string(p->module, p->value, str_lit("target-features"), str_lit("+neon")); + // Set appropriate vector width for multi-swizzle operations + if (count >= 32) { + lb_add_attribute_to_proc_with_string(p->module, p->value, str_lit("min-legal-vector-width"), str_lit("256")); + } + } else if (build_context.metrics.arch == TargetArch_arm32) { + // ARM32 function attributes - enable NEON for swizzle instructions + lb_add_attribute_to_proc_with_string(p->module, p->value, str_lit("target-features"), str_lit("+neon")); + } + + // Handle ARM's multi-swizzle intrinsics by splitting the src vector + if (build_context.metrics.arch == TargetArch_arm64 && count > 16) { + // ARM64 TBL2/TBL3/TBL4: Split src into multiple 16-byte vectors + int num_tables = cast(int)(count / 16); + GB_ASSERT_MSG(count % 16 == 0, "ARM64 src size must be multiple of 16 bytes, got %lld bytes", count); + GB_ASSERT_MSG(num_tables <= 4, "ARM64 NEON supports maximum 4 tables (tbl4), got %d tables for %lld-byte vector", num_tables, count); + + LLVMValueRef src_parts[4]; // Max 4 tables for tbl4 + for (int i = 0; i < num_tables; i++) { + // Extract 16-byte slice from the larger src + LLVMValueRef indices_for_extract[16]; + for (int j = 0; j < 16; j++) { + indices_for_extract[j] = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), i * 16 + j, false); + } + LLVMValueRef extract_mask = LLVMConstVector(indices_for_extract, 16); + src_parts[i] = LLVMBuildShuffleVector(p->builder, src, LLVMGetUndef(LLVMTypeOf(src)), extract_mask, ""); + } + + // Call appropriate ARM64 tbl intrinsic + if (count == 32) { + LLVMValueRef args[3] = { src_parts[0], src_parts[1], indices }; + res.value = lb_call_intrinsic(p, intrinsic_name, args, 3, nullptr, 0); + } else if (count == 48) { + LLVMValueRef args[4] = { src_parts[0], src_parts[1], src_parts[2], indices }; + res.value = lb_call_intrinsic(p, intrinsic_name, args, 4, nullptr, 0); + } else if (count == 64) { + LLVMValueRef args[5] = { src_parts[0], src_parts[1], src_parts[2], src_parts[3], indices }; + res.value = lb_call_intrinsic(p, intrinsic_name, args, 5, nullptr, 0); + } + } else if (build_context.metrics.arch == TargetArch_arm32 && count > 8) { + // ARM32 VTBL2/VTBL3/VTBL4: Split src into multiple 8-byte vectors + int num_tables = cast(int)count / 8; + GB_ASSERT_MSG(count % 8 == 0, "ARM32 src size must be multiple of 8 bytes, got %lld bytes", count); + GB_ASSERT_MSG(num_tables <= 4, "ARM32 NEON supports maximum 4 tables (vtbl4), got %d tables for %lld-byte vector", num_tables, count); + + LLVMValueRef src_parts[4]; // Max 4 tables for vtbl4 + for (int i = 0; i < num_tables; i++) { + // Extract 8-byte slice from the larger src + LLVMValueRef indices_for_extract[8]; + for (int j = 0; j < 8; j++) { + indices_for_extract[j] = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), i * 8 + j, false); + } + LLVMValueRef extract_mask = LLVMConstVector(indices_for_extract, 8); + src_parts[i] = LLVMBuildShuffleVector(p->builder, src, LLVMGetUndef(LLVMTypeOf(src)), extract_mask, ""); + } + + // Call appropriate ARM32 vtbl intrinsic + if (count == 16) { + LLVMValueRef args[3] = { src_parts[0], src_parts[1], indices }; + res.value = lb_call_intrinsic(p, intrinsic_name, args, 3, nullptr, 0); + } else if (count == 24) { + LLVMValueRef args[4] = { src_parts[0], src_parts[1], src_parts[2], indices }; + res.value = lb_call_intrinsic(p, intrinsic_name, args, 4, nullptr, 0); + } else if (count == 32) { + LLVMValueRef args[5] = { src_parts[0], src_parts[1], src_parts[2], src_parts[3], indices }; + res.value = lb_call_intrinsic(p, intrinsic_name, args, 5, nullptr, 0); + } + } else { + // Single runtime swizzle case (x86, WebAssembly, ARM single-table) + LLVMValueRef args[2] = { src, indices }; + res.value = lb_call_intrinsic(p, intrinsic_name, args, gb_count_of(args), nullptr, 0); + } + return res; + } else { + // Features not enabled, fall back to emulation + use_hardware_runtime_swizzle = false; + } + } + + // Fallback: Emulate with extracts and inserts for all element sizes + GB_ASSERT(count > 0 && count <= 64); // Sanity check + + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count); + LLVMTypeRef i32_type = LLVMInt32TypeInContext(p->module->ctx); + LLVMTypeRef elem_llvm_type = lb_type(p->module, elem_type); + + // Calculate mask based on element size and vector count + i64 max_index = count - 1; + LLVMValueRef index_mask; + + if (elem_size == 1) { + // 8-bit: mask to src size (like pshufb behavior) + index_mask = LLVMConstInt(elem_llvm_type, max_index, false); + } else if (elem_size == 2) { + // 16-bit: mask to src size + index_mask = LLVMConstInt(elem_llvm_type, max_index, false); + } else if (elem_size == 4) { + // 32-bit: mask to src size + index_mask = LLVMConstInt(elem_llvm_type, max_index, false); + } else { + // 64-bit: mask to src size + index_mask = LLVMConstInt(elem_llvm_type, max_index, false); + } + + for (i64 i = 0; i < count; i++) { + LLVMValueRef idx_i = LLVMConstInt(i32_type, cast(unsigned)i, false); + LLVMValueRef index_elem = LLVMBuildExtractElement(p->builder, indices, idx_i, ""); + + // Mask index to valid range + LLVMValueRef masked_index = LLVMBuildAnd(p->builder, index_elem, index_mask, ""); + + // Convert to i32 for extractelement + LLVMValueRef index_i32; + if (LLVMGetIntTypeWidth(LLVMTypeOf(masked_index)) < 32) { + index_i32 = LLVMBuildZExt(p->builder, masked_index, i32_type, ""); + } else if (LLVMGetIntTypeWidth(LLVMTypeOf(masked_index)) > 32) { + index_i32 = LLVMBuildTrunc(p->builder, masked_index, i32_type, ""); + } else { + index_i32 = masked_index; + } + + values[i] = LLVMBuildExtractElement(p->builder, src, index_i32, ""); + } + + // Build result vector + res.value = LLVMGetUndef(LLVMTypeOf(src)); + for (i64 i = 0; i < count; i++) { + LLVMValueRef idx_i = LLVMConstInt(i32_type, cast(unsigned)i, false); + res.value = LLVMBuildInsertElement(p->builder, res.value, values[i], idx_i, ""); + } + return res; + } + case BuiltinProc_simd_ceil: case BuiltinProc_simd_floor: case BuiltinProc_simd_trunc: @@ -1844,7 +2211,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu GB_ASSERT(e != nullptr); if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) { - procedure = e->parent_proc_decl->entity->token.string; + procedure = e->parent_proc_decl->entity.load()->token.string; } else { procedure = str_lit(""); } @@ -1866,12 +2233,12 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu LLVMValueRef values[2] = {}; values[0] = lb_const_string(m, file_name).value; - values[1] = lb_const_string(m, file->data).value; + values[1] = lb_const_value(m, t_u8_slice, exact_value_string(file->data)).value; LLVMValueRef element = llvm_const_named_struct(m, t_load_directory_file, values, gb_count_of(values)); elements[i] = element; } - LLVMValueRef backing_array = llvm_const_array(lb_type(m, t_load_directory_file), elements, count); + LLVMValueRef backing_array = llvm_const_array(m, lb_type(m, t_load_directory_file), elements, count); Type *array_type = alloc_type_array(t_load_directory_file, count); lbAddr backing_array_addr = lb_add_global_generated_from_procedure(p, array_type, {backing_array, array_type}); @@ -1922,6 +2289,10 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } if (is_type_cstring(t)) { return lb_cstring_len(p, v); + } else if (is_type_cstring16(t)) { + return lb_cstring16_len(p, v); + } else if (is_type_string16(t)) { + return lb_string_len(p, v); } else if (is_type_string(t)) { return lb_string_len(p, v); } else if (is_type_array(t)) { @@ -2150,6 +2521,68 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu return lb_emit_load(p, tuple); } + case BuiltinProc_compress_values: { + isize value_count = 0; + for (Ast *arg : ce->args) { + Type *t = arg->tav.type; + if (is_type_tuple(t)) { + value_count += t->Tuple.variables.count; + } else { + value_count += 1; + } + } + + if (value_count == 1) { + lbValue x = lb_build_expr(p, ce->args[0]); + x = lb_emit_conv(p, x, tv.type); + return x; + } + + Type *dt = base_type(tv.type); + lbAddr addr = lb_add_local_generated(p, tv.type, true); + if (is_type_struct(dt) || is_type_tuple(dt)) { + i32 index = 0; + for (Ast *arg : ce->args) { + lbValue x = lb_build_expr(p, arg); + if (is_type_tuple(x.type)) { + for (isize i = 0; i < x.type->Tuple.variables.count; i++) { + lbValue y = lb_emit_tuple_ev(p, x, cast(i32)i); + lbValue ptr = lb_emit_struct_ep(p, addr.addr, index++); + y = lb_emit_conv(p, y, type_deref(ptr.type)); + lb_emit_store(p, ptr, y); + } + } else { + lbValue ptr = lb_emit_struct_ep(p, addr.addr, index++); + x = lb_emit_conv(p, x, type_deref(ptr.type)); + lb_emit_store(p, ptr, x); + } + } + GB_ASSERT(index == value_count); + } else if (is_type_array_like(dt)) { + i32 index = 0; + for (Ast *arg : ce->args) { + lbValue x = lb_build_expr(p, arg); + if (is_type_tuple(x.type)) { + for (isize i = 0; i < x.type->Tuple.variables.count; i++) { + lbValue y = lb_emit_tuple_ev(p, x, cast(i32)i); + lbValue ptr = lb_emit_array_epi(p, addr.addr, index++); + y = lb_emit_conv(p, y, type_deref(ptr.type)); + lb_emit_store(p, ptr, y); + } + } else { + lbValue ptr = lb_emit_array_epi(p, addr.addr, index++); + x = lb_emit_conv(p, x, type_deref(ptr.type)); + lb_emit_store(p, ptr, x); + } + } + GB_ASSERT(index == value_count); + } else { + GB_PANIC("TODO(bill): compress_values -> %s", type_to_string(tv.type)); + } + + return lb_addr_load(p, addr); + } + case BuiltinProc_min: { Type *t = type_of_expr(expr); if (ce->args.count == 2) { @@ -2299,6 +2732,11 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu res = lb_emit_conv(p, res, tv.type); } else if (t->Basic.kind == Basic_cstring) { res = lb_emit_conv(p, x, tv.type); + } else if (t->Basic.kind == Basic_string16) { + res = lb_string_elem(p, x); + res = lb_emit_conv(p, res, tv.type); + } else if (t->Basic.kind == Basic_cstring16) { + res = lb_emit_conv(p, x, tv.type); } break; case Type_Pointer: @@ -2382,6 +2820,21 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } return res; } + case BuiltinProc_read_cycle_counter_frequency: + { + lbValue res = {}; + res.type = tv.type; + + if (build_context.metrics.arch == TargetArch_arm64) { + LLVMTypeRef func_type = LLVMFunctionType(LLVMInt64TypeInContext(p->module->ctx), nullptr, 0, false); + bool has_side_effects = false; + LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("mrs $0, cntfrq_el0"), str_lit("=r"), has_side_effects); + GB_ASSERT(the_asm != nullptr); + res.value = LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, ""); + } + + return res; + } case BuiltinProc_count_trailing_zeros: return lb_emit_count_trailing_zeros(p, lb_build_expr(p, ce->args[0]), tv.type); @@ -2616,15 +3069,18 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu LLVMSetMetadata(instr, kind_id, LLVMMetadataAsValue(p->module->ctx, node)); } break; - case BuiltinProc_volatile_store: LLVMSetVolatile(instr, true); break; - case BuiltinProc_atomic_store: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; + case BuiltinProc_volatile_store: + LLVMSetVolatile(instr, true); + break; + case BuiltinProc_atomic_store: + LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); + LLVMSetVolatile(instr, true); + break; case BuiltinProc_atomic_store_explicit: { auto ordering = llvm_atomic_ordering_from_odin(ce->args[2]); LLVMSetOrdering(instr, ordering); - if (ordering == LLVMAtomicOrderingUnordered) { - LLVMSetVolatile(instr, true); - } + LLVMSetVolatile(instr, true); } break; } @@ -2650,15 +3106,18 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } break; break; - case BuiltinProc_volatile_load: LLVMSetVolatile(instr, true); break; - case BuiltinProc_atomic_load: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; + case BuiltinProc_volatile_load: + LLVMSetVolatile(instr, true); + break; + case BuiltinProc_atomic_load: + LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); + LLVMSetVolatile(instr, true); + break; case BuiltinProc_atomic_load_explicit: { auto ordering = llvm_atomic_ordering_from_odin(ce->args[1]); LLVMSetOrdering(instr, ordering); - if (ordering == LLVMAtomicOrderingUnordered) { - LLVMSetVolatile(instr, true); - } + LLVMSetVolatile(instr, true); } break; } @@ -2743,9 +3202,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu lbValue res = {}; res.value = LLVMBuildAtomicRMW(p->builder, op, dst.value, val.value, ordering, false); res.type = tv.type; - if (ordering == LLVMAtomicOrderingUnordered) { - LLVMSetVolatile(res.value, true); - } + LLVMSetVolatile(res.value, true); return res; } @@ -2781,9 +3238,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu single_threaded ); LLVMSetWeak(value, weak); - if (success_ordering == LLVMAtomicOrderingUnordered || failure_ordering == LLVMAtomicOrderingUnordered) { - LLVMSetVolatile(value, true); - } + LLVMSetVolatile(value, true); if (is_type_tuple(tv.type)) { Type *fix_typed = alloc_type_tuple(); @@ -2846,16 +3301,22 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } GB_ASSERT(name != nullptr); - LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; lbValue res = {}; + res.type = platform_type; - LLVMValueRef args[3] = { + if (id == BuiltinProc_fixed_point_div || + id == BuiltinProc_fixed_point_div_sat) { + res.value = lb_integer_division_intrinsics(p, x.value, y.value, scale.value, platform_type, name); + } else { + LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; + + LLVMValueRef args[3] = { x.value, y.value, scale.value }; - res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); - res.type = platform_type; + res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types)); + } return lb_emit_conv(p, res, tv.type); } @@ -2972,6 +3433,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu constraints = gb_string_appendc(constraints, "}"); } + constraints = gb_string_appendc(constraints, ",~{memory}"); + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; @@ -3034,6 +3497,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu constraints = gb_string_appendc(constraints, "}"); } + constraints = gb_string_appendc(constraints, ",~{memory}"); + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; @@ -3059,6 +3524,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu constraints = gb_string_appendc(constraints, "}"); } + constraints = gb_string_appendc(constraints, ",~{memory}"); + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } else { char asm_string[] = "svc #0"; @@ -3078,6 +3545,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu constraints = gb_string_appendc(constraints, "}"); } + constraints = gb_string_appendc(constraints, ",~{memory}"); + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } } @@ -3104,6 +3573,8 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu constraints = gb_string_appendc(constraints, "}"); } + constraints = gb_string_appendc(constraints, ",~{memory}"); + inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; @@ -3216,11 +3687,28 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu { GB_ASSERT(arg_count <= 7); - char asm_string[] = "svc #0; cset x8, cc"; - gbString constraints = gb_string_make(heap_allocator(), "={x0},={x8}"); - for (unsigned i = 0; i < arg_count; i++) { - constraints = gb_string_appendc(constraints, ",{"); - static char const *regs[] = { + char const *asm_string; + char const **regs; + gbString constraints; + + if (build_context.metrics.os == TargetOs_netbsd) { + asm_string = "svc #0; cset x17, cc"; + constraints = gb_string_make(heap_allocator(), "={x0},={x17}"); + static char const *_regs[] = { + "x17", + "x0", + "x1", + "x2", + "x3", + "x4", + "x5", + }; + regs = _regs; + } else { + // FreeBSD (tested), OpenBSD (untested). + asm_string = "svc #0; cset x8, cc"; + constraints = gb_string_make(heap_allocator(), "={x0},={x8}"); + static char const *_regs[] = { "x8", "x0", "x1", @@ -3229,13 +3717,19 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu "x4", "x5", }; + regs = _regs; + + // FreeBSD clobbered x1 on a call to sysctl. + constraints = gb_string_appendc(constraints, ",~{x1}"); + } + + for (unsigned i = 0; i < arg_count; i++) { + constraints = gb_string_appendc(constraints, ",{"); constraints = gb_string_appendc(constraints, regs[i]); constraints = gb_string_appendc(constraints, "}"); } - // FreeBSD clobbered x1 on a call to sysctl. - constraints = gb_string_appendc(constraints, ",~{x1},~{cc},~{memory}"); - + constraints = gb_string_appendc(constraints, ",~{cc},~{memory}"); inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints)); } break; @@ -3257,6 +3751,9 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_objc_find_class: return lb_handle_objc_find_class(p, expr); case BuiltinProc_objc_register_selector: return lb_handle_objc_register_selector(p, expr); case BuiltinProc_objc_register_class: return lb_handle_objc_register_class(p, expr); + case BuiltinProc_objc_ivar_get: return lb_handle_objc_ivar_get(p, expr); + case BuiltinProc_objc_block: return lb_handle_objc_block(p, expr); + case BuiltinProc_objc_super: return lb_handle_objc_super(p, expr); case BuiltinProc_constant_utf16_cstring: @@ -3621,25 +4118,28 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(ce->args.count == 1); lbValue x = lb_build_expr(p, ce->args[0]); lbValue y = lb_emit_conv(p, x, tv.type); + y.type = tv.type; return y; } Ast *proc_expr = unparen_expr(ce->proc); + Entity *proc_entity = entity_of_node(proc_expr); + if (proc_mode == Addressing_Builtin) { - Entity *e = entity_of_node(proc_expr); BuiltinProcId id = BuiltinProc_Invalid; - if (e != nullptr) { - id = cast(BuiltinProcId)e->Builtin.id; + if (proc_entity != nullptr) { + id = cast(BuiltinProcId)proc_entity->Builtin.id; } else { id = BuiltinProc_DIRECTIVE; } return lb_build_builtin_proc(p, expr, tv, id); } + bool is_objc_call = proc_entity && proc_entity->Procedure.is_objc_impl_or_import; + // NOTE(bill): Regular call lbValue value = {}; - Entity *proc_entity = entity_of_node(proc_expr); if (proc_entity != nullptr) { if (proc_entity->flags & EntityFlag_Disabled) { GB_ASSERT(tv.type == nullptr); @@ -3673,11 +4173,13 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } } - if (value.value == nullptr) { + if (is_objc_call) { + value.type = proc_tv.type; + } else if (value.value == nullptr) { value = lb_build_expr(p, proc_expr); } - GB_ASSERT(value.value != nullptr); + GB_ASSERT(value.value != nullptr || is_objc_call); Type *proc_type_ = base_type(value.type); GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; @@ -3905,6 +4407,11 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { isize final_count = is_c_vararg ? args.count : pt->param_count; auto call_args = array_slice(args, 0, final_count); + + if (is_objc_call) { + return lb_handle_objc_auto_send(p, expr, slice(call_args, 0, call_args.count)); + } + return lb_emit_call(p, value, call_args, ce->inlining); } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 758cd353f..f247fa2a7 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -3,8 +3,6 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) return; } - auto *min_dep_set = &p->module->info->minimum_dependency_set; - for (Ast *ident : vd->names) { GB_ASSERT(ident->kind == Ast_Ident); Entity *e = entity_of_node(ident); @@ -21,7 +19,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) } } - if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) { + if (!polymorphic_struct && e->min_dep_count.load(std::memory_order_relaxed) == 0) { continue; } @@ -56,7 +54,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) if (gpd) { rw_mutex_shared_lock(&gpd->mutex); for (Entity *e : gpd->procs) { - if (!ptr_set_exists(min_dep_set, e)) { + if (e->min_dep_count.load(std::memory_order_relaxed) == 0) { continue; } DeclInfo *d = decl_info_of_entity(e); @@ -94,7 +92,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) value.value = nested_proc->value; value.type = nested_proc->type; - array_add(&p->module->procedures_to_generate, nested_proc); + mpsc_enqueue(&p->module->procedures_to_generate, nested_proc); array_add(&p->children, nested_proc); string_map_set(&p->module->members, name, value); } @@ -136,7 +134,6 @@ gb_internal lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) { return empty; } - gb_internal lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) { lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList); tl->prev = p->target_list; @@ -623,6 +620,121 @@ gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_t if (done_) *done_ = done; } +gb_internal void lb_build_range_string16(lbProcedure *p, lbValue expr, Type *val_type, + lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_, + bool is_reverse) { + + lbModule *m = p->module; + lbValue count = lb_const_int(m, t_int, 0); + Type *expr_type = base_type(expr.type); + switch (expr_type->kind) { + case Type_Basic: + count = lb_string_len(p, expr); + break; + default: + GB_PANIC("Cannot do range_string of %s", type_to_string(expr_type)); + break; + } + + lbValue val = {}; + lbValue idx = {}; + lbBlock *loop = nullptr; + lbBlock *done = nullptr; + lbBlock *body = nullptr; + + loop = lb_create_block(p, "for.string16.loop"); + body = lb_create_block(p, "for.string16.body"); + done = lb_create_block(p, "for.string16.done"); + + lbAddr offset_ = lb_add_local_generated(p, t_int, false); + lbValue offset = {}; + lbValue cond = {}; + + if (!is_reverse) { + /* + for c, offset in str { + ... + } + + offset := 0 + for offset < len(str) { + c, _w := string16_decode_rune(str[offset:]) + ... + offset += _w + } + */ + lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); + + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + + offset = lb_addr_load(p, offset_); + cond = lb_emit_comp(p, Token_Lt, offset, count); + } else { + // NOTE(bill): REVERSED LOGIC + /* + #reverse for c, offset in str { + ... + } + + offset := len(str) + for offset > 0 { + c, _w := string16_decode_last_rune(str[:offset]) + offset -= _w + ... + } + */ + lb_addr_store(p, offset_, count); + + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + offset = lb_addr_load(p, offset_); + cond = lb_emit_comp(p, Token_Gt, offset, lb_const_int(m, t_int, 0)); + } + lb_emit_if(p, cond, body, done); + lb_start_block(p, body); + + + lbValue rune_and_len = {}; + if (!is_reverse) { + lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset); + lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int); + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_emit_string16(p, str_elem, str_len); + + rune_and_len = lb_emit_runtime_call(p, "string16_decode_rune", args); + lbValue len = lb_emit_struct_ev(p, rune_and_len, 1); + lb_addr_store(p, offset_, lb_emit_arith(p, Token_Add, offset, len, t_int)); + + idx = offset; + } else { + // NOTE(bill): REVERSED LOGIC + lbValue str_elem = lb_string_elem(p, expr); + lbValue str_len = offset; + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_emit_string16(p, str_elem, str_len); + + rune_and_len = lb_emit_runtime_call(p, "string16_decode_last_rune", args); + lbValue len = lb_emit_struct_ev(p, rune_and_len, 1); + lb_addr_store(p, offset_, lb_emit_arith(p, Token_Sub, offset, len, t_int)); + + idx = lb_addr_load(p, offset_); + } + + + if (val_type != nullptr) { + val = lb_emit_struct_ev(p, rune_and_len, 0); + } + + if (val_) *val_ = val; + if (idx_) *idx_ = idx; + if (loop_) *loop_ = loop; + if (done_) *done_ = done; +} + + gb_internal Ast *lb_strip_and_prefix(Ast *ident) { if (ident != nullptr) { @@ -688,6 +800,18 @@ gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node, lbBlock *body = lb_create_block(p, "for.interval.body"); lbBlock *done = lb_create_block(p, "for.interval.done"); + // TODO(tf2spi): This is inlined in more than several places. + // Putting this in a function might be preferred. + // LLVMSetCurrentDebugLocation2 has side effects, + // so I didn't want to hide that before it got reviewed. + if (rs->label != nullptr && p->debug_info != nullptr) { + lbBlock *label = lb_create_block(p, "for.interval.label"); + lb_emit_jump(p, label); + lb_start_block(p, label); + + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, rs->label)); + lb_add_debug_label(p, rs->label, label); + } lb_emit_jump(p, loop); lb_start_block(p, loop); @@ -893,6 +1017,14 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lbAddr index = lb_add_local_generated(p, t_int, false); + if (rs->label != nullptr && p->debug_info != nullptr) { + lbBlock *label = lb_create_block(p, "for.soa.label"); + lb_emit_jump(p, label); + lb_start_block(p, label); + + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, rs->label)); + lb_add_debug_label(p, rs->label, label); + } if (!is_reverse) { /* for x, i in array { @@ -970,7 +1102,6 @@ gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs lb_store_range_stmt_val(p, val1, lb_addr_load(p, index)); } - lb_push_target_list(p, rs->label, done, loop, nullptr); lb_build_stmt(p, rs->body); @@ -1029,6 +1160,15 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc lbBlock *done = nullptr; bool is_map = false; + if (rs->label != nullptr && p->debug_info != nullptr) { + lbBlock *label = lb_create_block(p, "for.range.label"); + lb_emit_jump(p, label); + lb_start_block(p, label); + + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, rs->label)); + lb_add_debug_label(p, rs->label, label); + } + if (tav.mode == Addressing_Type) { lb_build_range_enum(p, type_deref(tav.type), val0_type, &val, &key, &loop, &done); } else { @@ -1045,10 +1185,22 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc break; } case Type_Array: { - lbValue array = lb_build_addr_ptr(p, expr); - if (is_type_pointer(type_deref(array.type))) { - array = lb_emit_load(p, array); + lbValue array; + lbAddr addr = lb_build_addr(p, expr); + switch (addr.kind) { + case lbAddr_Swizzle: + case lbAddr_SwizzleLarge: + // NOTE(laytan): apply the swizzle. + array = lb_address_from_load(p, lb_addr_load(p, addr)); + break; + default: + array = lb_addr_get_ptr(p, addr); + if (is_type_pointer(type_deref(array.type))) { + array = lb_emit_load(p, array); + } + break; } + lbAddr count_ptr = lb_add_local_generated(p, t_int, false); lb_addr_store(p, count_ptr, lb_const_int(p->module, t_int, et->Array.count)); lb_build_range_indexed(p, array, val0_type, count_ptr.addr, &val, &key, &loop, &done, rs->reverse); @@ -1099,7 +1251,11 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc } Type *t = base_type(string.type); GB_ASSERT(!is_type_cstring(t)); - lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done, rs->reverse); + if (is_type_string16(t)) { + lb_build_range_string16(p, string, val0_type, &val, &key, &loop, &done, rs->reverse); + } else { + lb_build_range_string(p, string, val0_type, &val, &key, &loop, &done, rs->reverse); + } break; } case Type_Tuple: @@ -1114,62 +1270,43 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc } Type *elem = et->BitSet.elem; - if (is_type_enum(elem)) { - i64 enum_count = 0; - lbValue values = lb_enum_values_slice(p, elem, &enum_count); - lbValue values_data = lb_slice_elem(p, values); - lbValue max_count = lb_const_int(m, t_int, enum_count); + Type *mask = bit_set_to_int(et); - lbAddr offset_ = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, offset_, lb_const_int(m, t_int, 0)); + lbValue all_mask = lb_const_value(p->module, mask, exact_bit_set_all_set_mask(et)); + lbValue initial_mask = lb_emit_arith(p, Token_And, the_set, all_mask, mask); - loop = lb_create_block(p, "for.bit_set.enum.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); - - lbBlock *body_check = lb_create_block(p, "for.bit_set.enum.body-check"); - lbBlock *body = lb_create_block(p, "for.bit_set.enum.body"); - done = lb_create_block(p, "for.bit_set.enum.done"); - - lbValue offset = lb_addr_load(p, offset_); - lbValue cond = lb_emit_comp(p, Token_Lt, offset, max_count); - lb_emit_if(p, cond, body_check, done); - lb_start_block(p, body_check); - - lbValue val_ptr = lb_emit_ptr_offset(p, values_data, offset); - lb_emit_increment(p, offset_.addr); - val = lb_emit_load(p, val_ptr); - val = lb_emit_conv(p, val, elem); - - lbValue check = lb_build_binary_in(p, val, the_set, Token_in); - lb_emit_if(p, check, body, loop); - lb_start_block(p, body); - } else { - lbAddr offset_ = lb_add_local_generated(p, t_int, false); - lb_addr_store(p, offset_, lb_const_int(m, t_int, et->BitSet.lower)); - - lbValue max_count = lb_const_int(m, t_int, et->BitSet.upper); - - loop = lb_create_block(p, "for.bit_set.range.loop"); - lb_emit_jump(p, loop); - lb_start_block(p, loop); - - lbBlock *body_check = lb_create_block(p, "for.bit_set.range.body-check"); - lbBlock *body = lb_create_block(p, "for.bit_set.range.body"); - done = lb_create_block(p, "for.bit_set.range.done"); - - lbValue offset = lb_addr_load(p, offset_); - lbValue cond = lb_emit_comp(p, Token_LtEq, offset, max_count); - lb_emit_if(p, cond, body_check, done); - lb_start_block(p, body_check); - - val = lb_emit_conv(p, offset, elem); - lb_emit_increment(p, offset_.addr); - - lbValue check = lb_build_binary_in(p, val, the_set, Token_in); - lb_emit_if(p, check, body, loop); - lb_start_block(p, body); + if (rs->reverse) { + initial_mask = lb_emit_reverse_bits(p, initial_mask, mask); } + + lbAddr remaining = lb_add_local_generated(p, mask, false); + lb_addr_store(p, remaining, initial_mask); + + loop = lb_create_block(p, "for.bit_set.loop"); + lbBlock *body = lb_create_block(p, "for.bit_set.body"); + done = lb_create_block(p, "for.bit_set.done"); + + lb_emit_jump(p, loop); + lb_start_block(p, loop); + + lbValue remaining_val = lb_addr_load(p, remaining); + lbValue cond = lb_emit_comp(p, Token_NotEq, remaining_val, lb_zero(m, mask)); + lb_emit_if(p, cond, body, done); + + lb_start_block(p, body); + val = lb_emit_count_trailing_zeros(p, remaining_val, mask); + val = lb_emit_conv(p, val, elem); + + if (rs->reverse) { + val = lb_emit_arith(p, Token_Sub, lb_const_int(m, elem, et->BitSet.lower + 8*type_size_of(mask) - 1), val, elem); + } else { + val = lb_emit_arith(p, Token_Add, val, lb_const_int(m, elem, et->BitSet.lower), elem); + } + + lbValue reduce_val = lb_emit_arith(p, Token_Sub, remaining_val, lb_const_int(m, mask, 1), mask); + remaining_val = lb_emit_arith(p, Token_And, remaining_val, reduce_val, mask); + lb_addr_store(p, remaining, remaining_val); + break; } default: @@ -1549,6 +1686,14 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) { lb_open_scope(p, scope); + if (ss->label != nullptr && p->debug_info != nullptr) { + lbBlock *label = lb_create_block(p, "switch.label"); + lb_emit_jump(p, label); + lb_start_block(p, label); + + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, ss->label)); + lb_add_debug_label(p, ss->label, label); + } if (ss->init != nullptr) { lb_build_stmt(p, ss->init); } @@ -1755,6 +1900,7 @@ gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValu gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) { ast_node(cc, CaseClause, clause); + // NOTE(tf2spi): Debug info for label not generated here on purpose lb_push_target_list(p, label, done, nullptr, nullptr); lb_build_stmt_list(p, cc->stmts); lb_close_scope(p, lbDeferExit_Default, body, clause); @@ -1957,7 +2103,11 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss lb_add_entity(p->module, case_entity, ptr); lb_add_debug_local_variable(p, ptr.value, case_entity->type, case_entity->token); } else { - lb_store_type_case_implicit(p, clause, parent_value, false); + if (by_reference) { + lb_store_type_case_implicit(p, clause, parent_ptr, false); + } else { + lb_store_type_case_implicit(p, clause, parent_value, false); + } } lb_type_case_body(p, ss->label, clause, body, done); @@ -1978,8 +2128,7 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { GB_ASSERT(ast_value->tav.mode == Addressing_Constant || ast_value->tav.mode == Addressing_Invalid); - bool allow_local = false; - value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, allow_local); + value = lb_const_value(p->module, ast_value->tav.type, ast_value->tav.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL); } Ast *ident = vd->names[i]; @@ -2000,34 +2149,45 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { char *c_name = alloc_cstring(permanent_allocator(), mangled_name); LLVMValueRef global = LLVMAddGlobal(p->module->mod, lb_type(p->module, e->type), c_name); + LLVMSetAlignment(global, cast(u32)type_align_of(e->type)); LLVMSetInitializer(global, LLVMConstNull(lb_type(p->module, e->type))); - if (value.value != nullptr) { - LLVMSetInitializer(global, value.value); - } + if (e->Variable.is_rodata) { LLVMSetGlobalConstant(global, true); } - if (e->Variable.thread_local_model != "") { - LLVMSetThreadLocal(global, true); - String m = e->Variable.thread_local_model; - LLVMThreadLocalMode mode = LLVMGeneralDynamicTLSModel; - if (m == "default") { - mode = LLVMGeneralDynamicTLSModel; - } else if (m == "localdynamic") { - mode = LLVMLocalDynamicTLSModel; - } else if (m == "initialexec") { - mode = LLVMInitialExecTLSModel; - } else if (m == "localexec") { - mode = LLVMLocalExecTLSModel; - } else { - GB_PANIC("Unhandled thread local mode %.*s", LIT(m)); - } - LLVMSetThreadLocalMode(global, mode); - } else { + if (!lb_apply_thread_local_model(global, e->Variable.thread_local_model)) { LLVMSetLinkage(global, LLVMInternalLinkage); } + if (value.value != nullptr) { + if (is_type_any(e->type)) { + Type *var_type = default_type(value.type); + + gbString var_name = gb_string_make(temporary_allocator(), "__$static_any::"); + var_name = gb_string_append_length(var_name, mangled_name.text, mangled_name.len); + + lbAddr var_global = lb_add_global_generated_with_name(p->module, var_type, value, make_string_c(var_name), nullptr); + LLVMValueRef var_global_ref = var_global.addr.value; + + if (e->Variable.is_rodata) { + LLVMSetGlobalConstant(var_global_ref, true); + } + + if (!lb_apply_thread_local_model(var_global_ref, e->Variable.thread_local_model)) { + LLVMSetLinkage(var_global_ref, LLVMInternalLinkage); + } + + LLVMValueRef vals[2] = { + lb_emit_conv(p, var_global.addr, t_rawptr).value, + lb_typeid(p->module, var_type).value, + }; + LLVMValueRef init = llvm_const_named_struct(p->module, e->type, vals, gb_count_of(vals)); + LLVMSetInitializer(global, init); + } else { + LLVMSetInitializer(global, value.value); + } + } lbValue global_val = {global, alloc_type_pointer(e->type)}; lb_add_entity(p->module, e, global_val); @@ -2322,6 +2482,14 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { else_ = lb_create_block(p, "if.else"); } if (is->label != nullptr) { + if (p->debug_info != nullptr) { + lbBlock *label = lb_create_block(p, "if.label"); + lb_emit_jump(p, label); + lb_start_block(p, label); + + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, is->label)); + lb_add_debug_label(p, is->label, label); + } lbTargetList *tl = lb_push_target_list(p, is->label, done, nullptr, nullptr); tl->is_block = true; } @@ -2414,12 +2582,19 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) { lb_push_target_list(p, fs->label, done, post, nullptr); + if (fs->label != nullptr && p->debug_info != nullptr) { + lbBlock *label = lb_create_block(p, "for.label"); + lb_emit_jump(p, label); + lb_start_block(p, label); + + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, fs->label)); + lb_add_debug_label(p, fs->label, label); + } if (fs->init != nullptr) { - #if 1 lbBlock *init = lb_create_block(p, "for.init"); lb_emit_jump(p, init); lb_start_block(p, init); - #endif + lb_build_stmt(p, fs->init); } @@ -2435,7 +2610,6 @@ gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) { lb_start_block(p, body); } - lb_build_stmt(p, fs->body); lb_pop_target_list(p); @@ -2709,9 +2883,21 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { case_ast_node(bs, BlockStmt, node); + lbBlock *body = nullptr; lbBlock *done = nullptr; if (bs->label != nullptr) { + if (p->debug_info != nullptr) { + lbBlock *label = lb_create_block(p, "block.label"); + lb_emit_jump(p, label); + lb_start_block(p, label); + + LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, bs->label)); + lb_add_debug_label(p, bs->label, label); + } + body = lb_create_block(p, "block.body"); done = lb_create_block(p, "block.done"); + lb_emit_jump(p, body); + lb_start_block(p, body); lbTargetList *tl = lb_push_target_list(p, bs->label, done, nullptr, nullptr); tl->is_block = true; } @@ -2932,6 +3118,18 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo } defer (p->branch_location_pos = prev_token_pos); + // TODO(lucas): In LLVM 21 use the 'use-after-scope' asan option which does this for us. + if (kind == lbDeferExit_Return) { + for_array(i, p->asan_stack_locals) { + lbValue local = p->asan_stack_locals[i]; + + auto args = array_make(temporary_allocator(), 2); + args[0] = lb_emit_conv(p, local, t_rawptr); + args[1] = lb_const_int(p->module, t_int, type_size_of(local.type->Pointer.elem)); + lb_emit_runtime_call(p, "__asan_unpoison_memory_region", args); + } + } + isize count = p->defer_stmts.count; isize i = count; while (i --> 0) { diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index ad4250f3c..7d412eb15 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -1,4 +1,10 @@ +gb_internal void lb_set_odin_rtti_section(LLVMValueRef value) { + if (build_context.metrics.os != TargetOs_darwin) { + LLVMSetSection(value, ".odinti"); + } +} + gb_internal isize lb_type_info_index(CheckerInfo *info, TypeInfoPair pair, bool err_on_not_found=true) { isize index = type_info_index(info, pair, err_on_not_found); if (index >= 0) { @@ -221,6 +227,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ gb_snprintf(name, 63, "__$ti-%lld", cast(long long)index); LLVMValueRef g = LLVMAddGlobal(m->mod, type, name); lb_make_global_private_const(g); + lb_set_odin_rtti_section(g); return g; }; @@ -295,7 +302,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ (name##_values)[i] = LLVMConstNull(elem); \ } \ } \ - LLVMSetInitializer(name.addr.value, llvm_const_array(elem, name##_values, at->Array.count)); \ + LLVMSetInitializer(name.addr.value, llvm_const_array(m, elem, name##_values, at->Array.count)); \ }) type_info_allocate_values(lb_global_type_info_member_types); @@ -387,8 +394,9 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ String proc_name = {}; if (t->Named.type_name->parent_proc_decl) { DeclInfo *decl = t->Named.type_name->parent_proc_decl; - if (decl->entity && decl->entity->kind == Entity_Procedure) { - proc_name = decl->entity->token.string; + Entity *e = decl->entity.load(); + if (e && e->kind == Entity_Procedure) { + proc_name = e->token.string; } } TokenPos pos = t->Named.type_name->token.pos; @@ -518,14 +526,48 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ break; case Basic_string: - tag_type = t_type_info_string; + { + tag_type = t_type_info_string; + LLVMValueRef vals[2] = { + lb_const_bool(m, t_bool, false).value, + lb_const_int(m, t_type_info_string_encoding_kind, 0).value, + }; + + variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); + } break; case Basic_cstring: { tag_type = t_type_info_string; - LLVMValueRef vals[1] = { + LLVMValueRef vals[2] = { lb_const_bool(m, t_bool, true).value, + lb_const_int(m, t_type_info_string_encoding_kind, 0).value, + }; + + variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); + } + break; + + case Basic_string16: + { + tag_type = t_type_info_string; + LLVMValueRef vals[2] = { + lb_const_bool(m, t_bool, false).value, + lb_const_int(m, t_type_info_string_encoding_kind, 1).value, + }; + + variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); + } + break; + + + case Basic_cstring16: + { + tag_type = t_type_info_string; + LLVMValueRef vals[2] = { + lb_const_bool(m, t_bool, true).value, + lb_const_int(m, t_type_info_string_encoding_kind, 1).value, }; variant_value = llvm_const_named_struct(m, tag_type, vals, gb_count_of(vals)); @@ -710,12 +752,14 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ value_values[i] = lb_const_value(m, t_i64, fields[i]->Constant.value).value; } - LLVMValueRef name_init = llvm_const_array(lb_type(m, t_string), name_values, cast(unsigned)fields.count); - LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count); + LLVMValueRef name_init = llvm_const_array(m, lb_type(m, t_string), name_values, cast(unsigned)fields.count); + LLVMValueRef value_init = llvm_const_array(m, lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count); LLVMSetInitializer(name_array.value, name_init); LLVMSetInitializer(value_array.value, value_init); LLVMSetGlobalConstant(name_array.value, true); LLVMSetGlobalConstant(value_array.value, true); + lb_set_odin_rtti_section(name_array.value); + lb_set_odin_rtti_section(value_array.value); lbValue v_count = lb_const_int(m, t_int, fields.count); @@ -788,7 +832,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ u8 flags = 0; if (t->Struct.is_packed) flags |= 1<<0; if (t->Struct.is_raw_union) flags |= 1<<1; - if (t->Struct.is_no_copy) flags |= 1<<2; + // if (t->Struct.custom_align) flags |= 1<<3; vals[6] = lb_const_int(m, t_u8, flags).value; @@ -1056,6 +1100,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ LLVMValueRef giant_array = lb_global_type_info_data_ptr(m).value; LLVMSetInitializer(giant_array, giant_const); lb_make_global_private_const(giant_array); + lb_set_odin_rtti_section(giant_array); } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index c876169f3..ca7bf34e3 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -6,6 +6,7 @@ gb_internal bool lb_is_type_aggregate(Type *t) { case Type_Basic: switch (t->Basic.kind) { case Basic_string: + case Basic_string16: case Basic_any: return true; @@ -190,6 +191,23 @@ gb_internal lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue mi return z; } +gb_internal lbValue lb_emit_string16(lbProcedure *p, lbValue str_elem, lbValue str_len) { + if (false && lb_is_const(str_elem) && lb_is_const(str_len)) { + LLVMValueRef values[2] = { + str_elem.value, + str_len.value, + }; + lbValue res = {}; + res.type = t_string16; + res.value = llvm_const_named_struct(p->module, t_string16, values, gb_count_of(values)); + return res; + } else { + lbAddr res = lb_add_local_generated(p, t_string16, false); + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), str_elem); + lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), str_len); + return lb_addr_load(p, res); + } +} gb_internal lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) { @@ -268,7 +286,14 @@ gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { } } + bool is_simd_vector_bitcastable = false; if (is_type_simd_vector(src) && is_type_simd_vector(dst)) { + if (!is_type_internally_pointer_like(src->SimdVector.elem) && !is_type_internally_pointer_like(dst->SimdVector.elem)) { + is_simd_vector_bitcastable = true; + } + } + + if (is_simd_vector_bitcastable) { res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), ""); return res; } else if (is_type_array_like(src) && (is_type_simd_vector(dst) || is_type_integer_128bit(dst))) { @@ -981,7 +1006,8 @@ gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) { } else if (build_context.ptr_size != build_context.int_size) { switch (t->kind) { case Type_Basic: - if (t->Basic.kind != Basic_string) { + if (t->Basic.kind != Basic_string && + t->Basic.kind != Basic_string16) { break; } /*fallthrough*/ @@ -1160,6 +1186,11 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { case 0: result_type = alloc_type_pointer(t->Slice.elem); break; case 1: result_type = t_int; break; } + } else if (is_type_string16(t)) { + switch (index) { + case 0: result_type = t_u16_ptr; break; + case 1: result_type = t_int; break; + } } else if (is_type_string(t)) { switch (index) { case 0: result_type = t_u8_ptr; break; @@ -1273,6 +1304,12 @@ gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { switch (t->kind) { case Type_Basic: switch (t->Basic.kind) { + case Basic_string16: + switch (index) { + case 0: result_type = t_u16_ptr; break; + case 1: result_type = t_int; break; + } + break; case Basic_string: switch (index) { case 0: result_type = t_u8_ptr; break; @@ -1440,6 +1477,10 @@ gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection e = lb_emit_struct_ep(p, e, index); break; + case Basic_string16: + e = lb_emit_struct_ep(p, e, index); + break; + default: GB_PANIC("un-gep-able type %s", type_to_string(type)); break; @@ -1626,11 +1667,17 @@ gb_internal void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue ba gb_internal lbValue lb_string_elem(lbProcedure *p, lbValue string) { Type *t = base_type(string.type); + if (t->kind == Type_Basic && t->Basic.kind == Basic_string16) { + return lb_emit_struct_ev(p, string, 0); + } GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string); return lb_emit_struct_ev(p, string, 0); } gb_internal lbValue lb_string_len(lbProcedure *p, lbValue string) { Type *t = base_type(string.type); + if (t->kind == Type_Basic && t->Basic.kind == Basic_string16) { + return lb_emit_struct_ev(p, string, 1); + } GB_ASSERT_MSG(t->kind == Type_Basic && t->Basic.kind == Basic_string, "%s", type_to_string(t)); return lb_emit_struct_ev(p, string, 1); } @@ -1641,6 +1688,12 @@ gb_internal lbValue lb_cstring_len(lbProcedure *p, lbValue value) { args[0] = lb_emit_conv(p, value, t_cstring); return lb_emit_runtime_call(p, "cstring_len", args); } +gb_internal lbValue lb_cstring16_len(lbProcedure *p, lbValue value) { + GB_ASSERT(is_type_cstring16(value.type)); + auto args = array_make(permanent_allocator(), 1); + args[0] = lb_emit_conv(p, value, t_cstring16); + return lb_emit_runtime_call(p, "cstring16_len", args); +} gb_internal lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr) { @@ -2094,42 +2147,553 @@ gb_internal void lb_set_wasm_export_attributes(LLVMValueRef value, String export } - gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) { - lbObjcRef *found = string_map_get(&p->module->objc_selectors, name); + lbModule *m = p->module; + lbAddr *found = string_map_get(&m->objc_selectors, name); if (found) { - return found->local_module_addr; + return *found; } lbModule *default_module = &p->module->gen->default_module; - Entity *entity = {}; - if (default_module != p->module) { - found = string_map_get(&default_module->objc_selectors, name); - if (found) { - entity = found->entity; + gbString global_name = gb_string_make(permanent_allocator(), "__$objc_SEL::"); + global_name = gb_string_append_length(global_name, name.text, name.len); + + LLVMTypeRef t = lb_type(m, t_objc_SEL); + lbValue g = {}; + g.value = LLVMAddGlobal(m->mod, t, global_name); + g.type = alloc_type_pointer(t_objc_SEL); + + if (default_module == m) { + LLVMSetInitializer(g.value, LLVMConstNull(t)); + lb_add_member(m, make_string_c(global_name), g); + } else { + LLVMSetLinkage(g.value, LLVMExternalLinkage); + } + + mpsc_enqueue(&m->gen->objc_selectors, lbObjCGlobal{m, global_name, name, t_objc_SEL}); + + lbAddr addr = lb_addr(g); + string_map_set(&m->objc_selectors, name, addr); + return addr; +} + +gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name, Type *class_impl_type) { + lbModule *m = p->module; + lbAddr *found = string_map_get(&m->objc_classes, name); + if (found) { + return *found; + } + + lbModule *default_module = &p->module->gen->default_module; + + gbString global_name = gb_string_make(permanent_allocator(), "__$objc_Class::"); + global_name = gb_string_append_length(global_name, name.text, name.len); + + LLVMTypeRef t = lb_type(m, t_objc_Class); + lbValue g = {}; + g.value = LLVMAddGlobal(m->mod, t, global_name); + g.type = alloc_type_pointer(t_objc_Class); + + if (default_module == m) { + LLVMSetInitializer(g.value, LLVMConstNull(t)); + lb_add_member(m, make_string_c(global_name), g); + } else { + LLVMSetLinkage(g.value, LLVMExternalLinkage); + } + mpsc_enqueue(&m->gen->objc_classes, lbObjCGlobal{m, global_name, name, t_objc_Class, class_impl_type}); + + lbAddr addr = lb_addr(g); + string_map_set(&m->objc_classes, name, addr); + return addr; +} + +gb_internal lbAddr lb_handle_objc_find_or_register_ivar(lbModule *m, Type *self_type) { + + String name = self_type->Named.type_name->TypeName.objc_class_name; + GB_ASSERT(name != ""); + + lbAddr *found = string_map_get(&m->objc_ivars, name); + if (found) { + return *found; + } + + lbModule *default_module = &m->gen->default_module; + + gbString global_name = gb_string_make(permanent_allocator(), "__$objc_ivar::"); + global_name = gb_string_append_length(global_name, name.text, name.len); + + // Create a global variable to store offset of the ivar in an instance of an object + LLVMTypeRef t = lb_type(m, t_int); + + lbValue g = {}; + g.value = LLVMAddGlobal(m->mod, t, global_name); + g.type = t_int_ptr; + + if (default_module == m) { + LLVMSetInitializer(g.value, LLVMConstInt(t, 0, true)); + lb_add_member(m, make_string_c(global_name), g); + } else { + LLVMSetLinkage(g.value, LLVMExternalLinkage); + } + + mpsc_enqueue(&m->gen->objc_ivars, lbObjCGlobal{m, global_name, name, t_int, self_type}); + + lbAddr addr = lb_addr(g); + string_map_set(&m->objc_ivars, name, addr); + return addr; +} + +gb_internal lbValue lb_handle_objc_ivar_for_objc_object_pointer(lbProcedure *p, lbValue self) { + GB_ASSERT(self.type->kind == Type_Pointer && self.type->Pointer.elem->kind == Type_Named); + + Type *self_type = self.type->Pointer.elem; + + lbValue self_uptr = lb_emit_conv(p, self, t_uintptr); + + lbValue ivar_offset = lb_addr_load(p, lb_handle_objc_find_or_register_ivar(p->module, self_type)); + lbValue ivar_offset_uptr = lb_emit_conv(p, ivar_offset, t_uintptr); + + + lbValue ivar_uptr = lb_emit_arith(p, Token_Add, self_uptr, ivar_offset_uptr, t_uintptr); + + Type *ivar_type = self_type->Named.type_name->TypeName.objc_ivar; + return lb_emit_conv(p, ivar_uptr, alloc_type_pointer(ivar_type)); +} + +gb_internal lbValue lb_handle_objc_ivar_get(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + + GB_ASSERT(ce->args[0]->tav.type->kind == Type_Pointer); + lbValue self = lb_build_expr(p, ce->args[0]); + + return lb_handle_objc_ivar_for_objc_object_pointer(p, self); +} + +gb_internal void lb_create_objc_block_helper_procs( + lbModule *m, LLVMTypeRef block_lit_type, isize capture_field_offset, + Slice capture_values, Slice objc_object_indices, + lbProcedure *&out_copy_helper, lbProcedure *&out_dispose_helper +) { + gbString copy_helper_name = gb_string_append_fmt(gb_string_make(temporary_allocator(), ""), "__$objc_block_copy_helper_%lld", m->objc_next_block_id); + gbString dispose_helper_name = gb_string_append_fmt(gb_string_make(temporary_allocator(), ""), "__$objc_block_dispose_helper_%lld", m->objc_next_block_id); + + // copy: Block_Literal *dst, Block_Literal *src, i32 field_apropos + // dispose: Block_Literal *src, i32 field_apropos + Type *types[3] = { t_rawptr, t_rawptr, t_i32 }; + + Type *copy_tuple = alloc_type_tuple_from_field_types(types, 3, false, true); + Type *dispose_tuple = alloc_type_tuple_from_field_types(&types[1], 2, false, true); + + Type *copy_proc_type = alloc_type_proc(nullptr, copy_tuple, 3, nullptr, 0, false, ProcCC_CDecl); + Type *dispose_proc_type = alloc_type_proc(nullptr, dispose_tuple, 2, nullptr, 0, false, ProcCC_CDecl); + + lbProcedure *copy_proc = lb_create_dummy_procedure(m, make_string((u8*)copy_helper_name, gb_string_length(copy_helper_name)), copy_proc_type); + lbProcedure *dispose_proc = lb_create_dummy_procedure(m, make_string((u8*)dispose_helper_name, gb_string_length(dispose_helper_name)), dispose_proc_type); + LLVMSetLinkage(copy_proc->value, LLVMPrivateLinkage); + LLVMSetLinkage(dispose_proc->value, LLVMPrivateLinkage); + + + const int BLOCK_FIELD_IS_OBJECT = 3; // id, NSObject, __attribute__((NSObject)), block, ... + const int BLOCK_FIELD_IS_BLOCK = 7; // a block variable + + Type *block_base_type = find_core_type(m->info->checker, str_lit("Objc_Block")); + + auto is_object_objc_block = [](Type *type, Type *block_base_type) -> bool { + + Type *base = base_type(type_deref(type)); + GB_ASSERT(base->kind == Type_Struct); + + while (is_type_polymorphic_record_specialized(base)) { + if (base->Struct.polymorphic_parent) { + base = base->Struct.polymorphic_parent; + + if (base == block_base_type) { + return true; + } + base = base_type(base); + GB_ASSERT(base->kind == Type_Struct); + } + } + + return false; + }; + + lb_begin_procedure_body(copy_proc); + lb_begin_procedure_body(dispose_proc); + { + for (isize object_index : objc_object_indices) { + const auto field_offset = unsigned(capture_field_offset+object_index); + + Type *field_type = capture_values[object_index].type; + LLVMTypeRef field_raw_type = lb_type(m, field_type); + + GB_ASSERT(is_type_objc_object(field_type)); + bool is_block_obj = is_object_objc_block(field_type, block_base_type); + + auto copy_args = array_make(temporary_allocator(), 3, 3); + auto dispose_args = array_make(temporary_allocator(), 2, 2); + + // Copy helper + { + LLVMValueRef dst_field = LLVMBuildStructGEP2(copy_proc->builder, block_lit_type, copy_proc->raw_input_parameters[0], field_offset, ""); + LLVMValueRef src_field = LLVMBuildStructGEP2(copy_proc->builder, block_lit_type, copy_proc->raw_input_parameters[1], field_offset, ""); + + lbValue dst_value = {}, src_value = {}; + dst_value.type = alloc_type_pointer(field_type); + dst_value.value = dst_field; + + src_value.type = field_type; + src_value.value = LLVMBuildLoad2(copy_proc->builder, field_raw_type, src_field, ""); + + copy_args[0] = dst_value; + copy_args[1] = src_value; + copy_args[2] = lb_const_int(m, t_i32, u64(is_block_obj ? BLOCK_FIELD_IS_BLOCK : BLOCK_FIELD_IS_OBJECT)); + + lb_emit_runtime_call(copy_proc, "_Block_object_assign", copy_args); + } + + // Dispose helper + { + LLVMValueRef src_field = LLVMBuildStructGEP2(dispose_proc->builder, block_lit_type, dispose_proc->raw_input_parameters[0], field_offset, ""); + lbValue src_value = {}; + src_value.type = field_type; + src_value.value = LLVMBuildLoad2(dispose_proc->builder, field_raw_type, src_field, ""); + + dispose_args[0] = src_value; + dispose_args[1] = lb_const_int(m, t_i32, u64(is_block_obj ? BLOCK_FIELD_IS_BLOCK : BLOCK_FIELD_IS_OBJECT)); + + lb_emit_runtime_call(dispose_proc, "_Block_object_dispose", dispose_args); + } + } + } + lb_end_procedure_body(copy_proc); + lb_end_procedure_body(dispose_proc); + + + out_copy_helper = copy_proc; + out_dispose_helper = dispose_proc; +} + +gb_internal lbValue lb_handle_objc_block(lbProcedure *p, Ast *expr) { + /// #See: https://clang.llvm.org/docs/Block-ABI-Apple.html + /// https://www.newosxbook.com/src.php?tree=xnu&file=/libkern/libkern/Block_private.h + /// https://github.com/llvm/llvm-project/blob/21f1f9558df3830ffa637def364e3c0cb0dbb3c0/compiler-rt/lib/BlocksRuntime/Block_private.h + /// https://github.com/apple-oss-distributions/libclosure/blob/3668b0837f47be3cc1c404fb5e360f4ff178ca13/runtime.cpp + ast_node(ce, CallExpr, expr); + GB_ASSERT(ce->args.count > 0); + + lbModule *m = p->module; + + m->objc_next_block_id += 1; + + const isize capture_arg_count = ce->args.count - 1; + + Type *block_result_type = type_of_expr(expr); + GB_ASSERT(block_result_type != nullptr && block_result_type->kind == Type_Pointer); + + LLVMTypeRef lb_type_rawptr = lb_type(m, t_rawptr); + LLVMTypeRef lb_type_i32 = lb_type(m, t_i32); + LLVMTypeRef lb_type_int = lb_type(m, t_int); + + // Build user proc + // Type * user_proc_type = type_of_expr(ce->args[capture_arg_count]); + lbValue user_proc_value = lb_build_expr(p, ce->args[capture_arg_count]); + auto& user_proc = user_proc_value.type->Proc; + GB_ASSERT(user_proc_value.type->kind == Type_Proc); + + const bool is_global = capture_arg_count == 0 && user_proc.calling_convention != ProcCC_Odin; + const isize block_forward_args = user_proc.param_count - capture_arg_count; + const isize capture_fields_offset = user_proc.calling_convention != ProcCC_Odin ? 5 : 6; + + Ast *proc_lit = unparen_expr(ce->args[capture_arg_count]); + if (proc_lit->kind == Ast_Ident) { + proc_lit = proc_lit->Ident.entity->decl_info->proc_lit; + } + GB_ASSERT(proc_lit->kind == Ast_ProcLit); + + lbProcedure *copy_helper = {}, *dispose_helper = {}; + + // Build captured arguments & collect the ones that are Objective-C objects + auto captured_values = array_make(temporary_allocator(), capture_arg_count, capture_arg_count); + auto objc_captures = array_make(temporary_allocator()); + + for (isize i = 0; i < capture_arg_count; i++) { + captured_values[i] = lb_build_expr(p, ce->args[i]); + + if (is_type_pointer(captured_values[i].type) && is_type_objc_object(captured_values[i].type)) { + array_add(&objc_captures, i); } } - if (!entity) { - gbString global_name = gb_string_make(temporary_allocator(), "__$objc_SEL$"); - global_name = gb_string_append_length(global_name, name.text, name.len); + const bool has_objc_fields = objc_captures.count > 0; - lbAddr default_addr = lb_add_global_generated_with_name( - default_module, t_objc_SEL, {}, - make_string(cast(u8 const *)global_name, gb_string_length(global_name)), - &entity); - string_map_set(&default_module->objc_selectors, name, lbObjcRef{entity, default_addr}); + + // Create proc with the block signature + // (takes a block literal pointer as the first parameter, followed by any expected ones from the user's proc) + gbString block_invoker_name = gb_string_append_fmt(gb_string_make(permanent_allocator(), ""), "__$objc_block_invoker_%lld", m->objc_next_block_id); + + // Add + 1 because the first parameter received is the block literal pointer itself + auto invoker_args = array_make(temporary_allocator(), block_forward_args + 1, block_forward_args + 1); + invoker_args[0] = t_rawptr; + + GB_ASSERT(block_forward_args <= user_proc.param_count); + if (user_proc.param_count > 0) { + Slice user_proc_param_types = user_proc.params->Tuple.variables; + for (isize i = 0; i < block_forward_args; i++) { + invoker_args[i+1] = user_proc_param_types[i]->type; + } } - lbValue ptr = lb_find_value_from_entity(p->module, entity); - lbAddr local_addr = lb_addr(ptr); + GB_ASSERT(user_proc.result_count <= 1); - if (default_module != p->module) { - string_map_set(&p->module->objc_selectors, name, lbObjcRef{entity, local_addr}); + Type *invoker_args_tuple = alloc_type_tuple_from_field_types(invoker_args.data, invoker_args.count, false, true); + Type *invoker_results_tuple = nullptr; + if (user_proc.result_count > 0) { + invoker_results_tuple = alloc_type_tuple_from_field_types(&user_proc.results->Tuple.variables[0]->type, 1, false, true); } - return local_addr; + Type *invoker_proc_type = alloc_type_proc(nullptr, invoker_args_tuple, invoker_args_tuple->Tuple.variables.count, + invoker_results_tuple, user_proc.result_count, false, ProcCC_CDecl); + + lbProcedure *invoker_proc = lb_create_dummy_procedure(m, make_string((u8*)block_invoker_name, + gb_string_length(block_invoker_name)), invoker_proc_type); + + LLVMSetLinkage(invoker_proc->value, LLVMPrivateLinkage); + lb_add_function_type_attributes(invoker_proc->value, lb_get_function_type(m, invoker_proc_type), ProcCC_CDecl); + + // Create the block descriptor and block literal + gbString block_lit_type_name = gb_string_make(temporary_allocator(), "__$ObjC_Block_Literal_"); + block_lit_type_name = gb_string_append_fmt(block_lit_type_name, "%lld", m->objc_next_block_id); + + gbString block_desc_type_name = gb_string_make(temporary_allocator(), "__$ObjC_Block_Descriptor_"); + block_desc_type_name = gb_string_append_fmt(block_desc_type_name, "%lld", m->objc_next_block_id); + + LLVMTypeRef block_lit_type = {}; + LLVMTypeRef block_desc_type = {}; + LLVMValueRef block_desc_initializer = {}; + + { + block_desc_type = LLVMStructCreateNamed(m->ctx, block_desc_type_name); + + LLVMTypeRef fields_types[4] = { + lb_type_int, // Reserved + lb_type_int, // Block size + lb_type_rawptr, // Copy helper func pointer + lb_type_rawptr, // Dispose helper func pointer + }; + + LLVMStructSetBody(block_desc_type, fields_types, has_objc_fields ? 4 : 2, false); + } + + { + block_lit_type = LLVMStructCreateNamed(m->ctx, block_lit_type_name); + + auto fields = array_make(temporary_allocator()); + + array_add(&fields, lb_type_rawptr); // isa + array_add(&fields, lb_type_i32); // flags + array_add(&fields, lb_type_i32); // reserved + array_add(&fields, lb_type_rawptr); // invoke + array_add(&fields, block_desc_type); // descriptor + + if (user_proc.calling_convention == ProcCC_Odin) { + array_add(&fields, lb_type(m, t_context)); // context + } + + // From here on, fields for the captured vars are added + for (lbValue cap_arg : captured_values) { + array_add(&fields, lb_type(m, cap_arg.type)); + } + + LLVMStructSetBody(block_lit_type, fields.data, (unsigned)fields.count, false); + } + + // Generate copy and dispose helper functions for captured params that are Objective-C objects (or a Block) + if (has_objc_fields) { + lb_create_objc_block_helper_procs(m, block_lit_type, capture_fields_offset, + slice(captured_values, 0, captured_values.count), + slice(objc_captures, 0, objc_captures.count), + copy_helper, dispose_helper); + } + + { + LLVMValueRef fields_values[4] = { + lb_const_int(m, t_int, 0).value, // Reserved + lb_const_int(m, t_int, u64(lb_sizeof(block_lit_type))).value, // Block size + has_objc_fields ? copy_helper->value : nullptr, // Copy helper + has_objc_fields ? dispose_helper->value : nullptr, // Dispose helper + }; + + block_desc_initializer = LLVMConstNamedStruct(block_desc_type, fields_values, has_objc_fields ? 4 : 2); + } + + // Create global block descriptor + gbString desc_global_name = gb_string_make(temporary_allocator(), "__$objc_block_desc_"); + desc_global_name = gb_string_append_fmt(desc_global_name, "%lld", m->objc_next_block_id); + + LLVMValueRef p_descriptor = LLVMAddGlobal(m->mod, block_desc_type, desc_global_name); + LLVMSetInitializer(p_descriptor, block_desc_initializer); + + + /// Invoker body + lb_begin_procedure_body(invoker_proc); + { + // Reserve 2 extra arguments for: Indirect return values and context. + auto call_args = array_make(temporary_allocator(), 0, user_proc.param_count + 2); + + isize block_literal_arg_index = 0; + + lbFunctionType* user_proc_ft = lb_get_function_type(m, user_proc_value.type); + + lbArgKind return_kind = {}; + + GB_ASSERT(user_proc.result_count <= 1); + if (user_proc.result_count > 0) { + return_kind = user_proc_ft->ret.kind; + + if (return_kind == lbArg_Indirect) { + // Forward indirect return value + array_add(&call_args, invoker_proc->raw_input_parameters[0]); + block_literal_arg_index = 1; + } + } + + // Forward raw arguments + for (isize i = block_literal_arg_index+1; i < invoker_proc->raw_input_parameters.count; i++) { + array_add(&call_args, invoker_proc->raw_input_parameters[i]); + } + + LLVMValueRef block_literal = invoker_proc->raw_input_parameters[block_literal_arg_index]; + + // Copy capture parameters from the block literal + isize capture_arg_in_user_proc_start_index = user_proc_ft->args.count - capture_arg_count; + if (user_proc.calling_convention == ProcCC_Odin) { + capture_arg_in_user_proc_start_index -= 1; + } + + for (isize i = 0; i < capture_arg_count; i++) { + LLVMValueRef cap_value = LLVMBuildStructGEP2(invoker_proc->builder, block_lit_type, block_literal, unsigned(capture_fields_offset + i), ""); + + // Don't emit load if indirect. Pass the pointer as-is + isize cap_arg_index_in_user_proc = capture_arg_in_user_proc_start_index + i; + + if (user_proc_ft->args[cap_arg_index_in_user_proc].kind != lbArg_Indirect) { + cap_value = OdinLLVMBuildLoad(invoker_proc, lb_type(invoker_proc->module, captured_values[i].type), cap_value); + } + + array_add(&call_args, cap_value); + } + + // Push context, if needed + if (user_proc.calling_convention == ProcCC_Odin) { + LLVMValueRef p_context = LLVMBuildStructGEP2(invoker_proc->builder, block_lit_type, block_literal, 5, "context"); + array_add(&call_args, p_context); + } + + LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(m, user_proc_value.type); + LLVMValueRef ret_val = LLVMBuildCall2(invoker_proc->builder, fnp, user_proc_value.value, call_args.data, (unsigned)call_args.count, ""); + + if (user_proc.result_count > 0 && return_kind != lbArg_Indirect) { + LLVMBuildRet(invoker_proc->builder, ret_val); + } + else { + LLVMBuildRetVoid(invoker_proc->builder); + } + } + lb_end_procedure_body(invoker_proc); + + + /// Create local block literal + const int BLOCK_HAS_COPY_DISPOSE = (1 << 25); + const int BLOCK_IS_GLOBAL = (1 << 28); + + int raw_flags = is_global ? BLOCK_IS_GLOBAL : 0; + if (has_objc_fields) { + raw_flags |= BLOCK_HAS_COPY_DISPOSE; + } + + gbString block_var_name = gb_string_make(temporary_allocator(), "__$objc_block_literal_"); + block_var_name = gb_string_append_fmt(block_var_name, "%lld", m->objc_next_block_id); + + lbValue block_result = {}; + block_result.type = block_result_type; + + lbValue isa_val = lb_find_runtime_value(m, is_global ? str_lit("_NSConcreteGlobalBlock") : str_lit("_NSConcreteStackBlock")); + lbValue flags_val = lb_const_int(m, t_i32, (u64)raw_flags); + lbValue reserved_val = lb_const_int(m, t_i32, 0); + + if (is_global) { + LLVMValueRef p_block_lit = LLVMAddGlobal(m->mod, block_lit_type, block_var_name); + block_result.value = p_block_lit; + + LLVMValueRef fields_values[5] = { + isa_val.value, // isa + flags_val.value, // flags + reserved_val.value, // reserved + invoker_proc->value, // invoke + p_descriptor // descriptor + }; + + LLVMValueRef g_block_lit_initializer = LLVMConstNamedStruct(block_lit_type, fields_values, gb_count_of(fields_values)); + LLVMSetInitializer(p_block_lit, g_block_lit_initializer); + + } else { + LLVMValueRef p_block_lit = llvm_alloca(p, block_lit_type, lb_alignof(block_lit_type), block_var_name); + block_result.value = p_block_lit; + + // Initialize it + LLVMValueRef f_isa = LLVMBuildStructGEP2(p->builder, block_lit_type, p_block_lit, 0, "isa"); + LLVMValueRef f_flags = LLVMBuildStructGEP2(p->builder, block_lit_type, p_block_lit, 1, "flags"); + LLVMValueRef f_reserved = LLVMBuildStructGEP2(p->builder, block_lit_type, p_block_lit, 2, "reserved"); + LLVMValueRef f_invoke = LLVMBuildStructGEP2(p->builder, block_lit_type, p_block_lit, 3, "invoke"); + LLVMValueRef f_descriptor = LLVMBuildStructGEP2(p->builder, block_lit_type, p_block_lit, 4, "descriptor"); + + LLVMBuildStore(p->builder, isa_val.value, f_isa); + LLVMBuildStore(p->builder, flags_val.value, f_flags); + LLVMBuildStore(p->builder, reserved_val.value, f_reserved); + LLVMBuildStore(p->builder, invoker_proc->value, f_invoke); + LLVMBuildStore(p->builder, p_descriptor, f_descriptor); + + // Store current context, if there is one + if (user_proc.calling_convention == ProcCC_Odin) { + LLVMValueRef f_context = LLVMBuildStructGEP2(p->builder, block_lit_type, p_block_lit, 5, "context"); + lbAddr p_current_context = lb_find_or_generate_context_ptr(p); + + LLVMValueRef context_size = LLVMConstInt(LLVMInt64TypeInContext(m->ctx), (u64)lb_sizeof(lb_type(m, t_context)), false); + LLVMBuildMemCpy(p->builder, f_context, lb_try_get_alignment(f_context, 1), + p_current_context.addr.value, lb_try_get_alignment(p_current_context.addr.value, 1), context_size); + } + + // Store captured args into the block + for (isize i = 0; i < captured_values.count; i++) { + lbValue capture_arg = captured_values[i]; + + unsigned field_index = unsigned(capture_fields_offset + i); + LLVMValueRef f_capture = LLVMBuildStructGEP2(p->builder, block_lit_type, p_block_lit, field_index, "capture_arg"); + + lbValue f_capture_val = {}; + f_capture_val.type = alloc_type_pointer(capture_arg.type); + f_capture_val.value = f_capture; + + lb_emit_store(p, f_capture_val, capture_arg); + } + } + + return block_result; +} + +gb_internal lbValue lb_handle_objc_block_invoke(lbProcedure *p, Ast *expr) { + return {}; +} + +gb_internal lbValue lb_handle_objc_super(lbProcedure *p, Ast *expr) { + ast_node(ce, CallExpr, expr); + GB_ASSERT(ce->args.count == 1); + + // NOTE(harold): This doesn't actually do anything by itself, + // it has an effect when used on the left side of a selector call expression. + return lb_build_expr(p, ce->args[0]); } gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) { @@ -2158,41 +2722,6 @@ gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) return lb_addr_load(p, dst); } -gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) { - lbObjcRef *found = string_map_get(&p->module->objc_classes, name); - if (found) { - return found->local_module_addr; - } - - lbModule *default_module = &p->module->gen->default_module; - Entity *entity = {}; - - if (default_module != p->module) { - found = string_map_get(&default_module->objc_classes, name); - if (found) { - entity = found->entity; - } - } - - if (!entity) { - gbString global_name = gb_string_make(temporary_allocator(), "__$objc_Class$"); - global_name = gb_string_append_length(global_name, name.text, name.len); - - lbAddr default_addr = lb_add_global_generated_with_name(default_module, t_objc_Class, {}, - make_string(cast(u8 const *)global_name, gb_string_length(global_name)), - &entity); - string_map_set(&default_module->objc_classes, name, lbObjcRef{entity, default_addr}); - } - - lbValue ptr = lb_find_value_from_entity(p->module, entity); - lbAddr local_addr = lb_addr(ptr); - - if (default_module != p->module) { - string_map_set(&p->module->objc_classes, name, lbObjcRef{entity, local_addr}); - } - - return local_addr; -} gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); @@ -2200,7 +2729,7 @@ gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) { auto tav = ce->args[0]->tav; GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; - return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name)); + return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name, nullptr)); } gb_internal lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) { @@ -2210,7 +2739,7 @@ gb_internal lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) { auto tav = ce->args[0]->tav; GB_ASSERT(tav.value.kind == ExactValue_String); String name = tav.value.value_string; - lbAddr dst = lb_handle_objc_find_or_register_class(p, name); + lbAddr dst = lb_handle_objc_find_or_register_class(p, name, nullptr); auto args = array_make(permanent_allocator(), 3); args[0] = lb_const_nil(m, t_objc_Class); @@ -2232,7 +2761,9 @@ gb_internal lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) { GB_ASSERT(e->kind == Entity_TypeName); String name = e->TypeName.objc_class_name; - return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name)); + Type *class_impl_type = e->TypeName.objc_is_implementation ? type : nullptr; + + return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name, class_impl_type)); } return lb_build_expr(p, expr); @@ -2278,7 +2809,118 @@ gb_internal lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) { return lb_emit_call(p, the_proc, args); } +gb_internal lbValue lb_handle_objc_auto_send(lbProcedure *p, Ast *expr, Slice const arg_values) { + ast_node(ce, CallExpr, expr); + lbModule *m = p->module; + CheckerInfo *info = m->info; + ObjcMsgData data = map_must_get(&info->objc_msgSend_types, expr); + + Type *proc_type = data.proc_type; + GB_ASSERT(proc_type != nullptr); + + Entity *objc_method_ent = entity_of_node(ce->proc); + GB_ASSERT(objc_method_ent != nullptr); + GB_ASSERT(objc_method_ent->kind == Entity_Procedure); + GB_ASSERT(objc_method_ent->Procedure.objc_selector_name.len > 0); + + auto &proc = proc_type->Proc; + GB_ASSERT(proc.param_count >= 2); + + Type *objc_super_orig_type = nullptr; + if (ce->args.count > 0) { + objc_super_orig_type = unparen_expr(ce->args[0])->tav.objc_super_target; + } + + isize arg_offset = 1; + lbValue id = {}; + if (!objc_method_ent->Procedure.is_objc_class_method) { + GB_ASSERT(ce->args.count > 0); + id = arg_values[0]; + + if (objc_super_orig_type) { + GB_ASSERT(objc_super_orig_type->kind == Type_Named); + + auto& tn = objc_super_orig_type->Named.type_name->TypeName; + lbAddr p_supercls = lb_handle_objc_find_or_register_class(p, tn.objc_class_name, tn.objc_is_implementation ? objc_super_orig_type : nullptr); + + lbValue supercls = lb_addr_load(p, p_supercls); + lbAddr p_objc_super = lb_add_local_generated(p, t_objc_super, false); + + lbValue f_id = lb_emit_struct_ep(p, p_objc_super.addr, 0); + lbValue f_superclass = lb_emit_struct_ep(p, p_objc_super.addr, 1); + + id = lb_emit_conv(p, id, t_objc_id); + lb_emit_store(p, f_id, id); + lb_emit_store(p, f_superclass, supercls); + + id = p_objc_super.addr; + } + } else { + Entity *objc_class = objc_method_ent->Procedure.objc_class; + if (ce->proc->kind == Ast_SelectorExpr) { + // NOTE (harold): If called via a selector expression (ex: Foo.alloc()), then we should use + // the lhs-side to determine the class. This allows for class methods to be called + // with the correct class as the target, even when the method is defined in a superclass. + ast_node(se, SelectorExpr, ce->proc); + GB_ASSERT(se->expr->tav.mode == Addressing_Type && se->expr->tav.type->kind == Type_Named); + + objc_class = entity_from_expr(se->expr); + + GB_ASSERT(objc_class); + GB_ASSERT(objc_class->kind == Entity_TypeName); + GB_ASSERT(objc_class->TypeName.objc_class_name != ""); + } + + Type *class_impl_type = objc_class->TypeName.objc_is_implementation ? objc_class->type : nullptr; + + id = lb_addr_load(p, lb_handle_objc_find_or_register_class(p, objc_class->TypeName.objc_class_name, class_impl_type)); + arg_offset = 0; + } + + lbValue sel = lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, objc_method_ent->Procedure.objc_selector_name)); + + auto args = array_make(permanent_allocator(), 0, arg_values.count + 2 - arg_offset); + + array_add(&args, id); + array_add(&args, sel); + + for (isize i = arg_offset; i < ce->args.count; i++) { + array_add(&args, arg_values[i]); + } + + lbValue the_proc = {}; + + if (!objc_super_orig_type) { + switch (data.kind) { + default: + GB_PANIC("unhandled ObjcMsgKind %u", data.kind); + break; + case ObjcMsg_normal: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend")); break; + case ObjcMsg_fpret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_fpret")); break; + case ObjcMsg_fp2ret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_fp2ret")); break; + case ObjcMsg_stret: the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSend_stret")); break; + } + } else { + switch (data.kind) { + default: + GB_PANIC("unhandled ObjcMsgKind %u", data.kind); + break; + case ObjcMsg_normal: + case ObjcMsg_fpret: + case ObjcMsg_fp2ret: + the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSendSuper2")); + break; + case ObjcMsg_stret: + the_proc = lb_lookup_runtime_procedure(m, str_lit("objc_msgSendSuper2_stret")); + break; + } + } + + the_proc = lb_emit_conv(p, the_proc, data.proc_type); + + return lb_emit_call(p, the_proc, args); +} gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) { @@ -2301,3 +2943,292 @@ gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) { ExactValue value = type_and_value_of_expr(expr).value; return llvm_atomic_ordering_from_odin(value); } + + + +struct lbDiagParaPolyEntry { + Entity *entity; + String canonical_name; + isize count; + isize total_code_size; +}; + +gb_internal isize lb_total_code_size(lbProcedure *p) { + isize instruction_count = 0; + + LLVMBasicBlockRef first = LLVMGetFirstBasicBlock(p->value); + + for (LLVMBasicBlockRef block = first; block != nullptr; block = LLVMGetNextBasicBlock(block)) { + for (LLVMValueRef instr = LLVMGetFirstInstruction(block); instr != nullptr; instr = LLVMGetNextInstruction(instr)) { + instruction_count += 1; + } + } + return instruction_count; + +} + +gb_internal void lb_do_para_poly_diagnostics(lbGenerator *gen) { + PtrMap procs = {}; + map_init(&procs); + defer (map_destroy(&procs)); + + for (auto &entry : gen->modules) { + lbModule *m = entry.value; + for (lbProcedure *p : m->generated_procedures) { + Entity *e = p->entity; + if (e == nullptr) { + continue; + } + if (p->builder == nullptr) { + continue; + } + + DeclInfo *d = e->decl_info; + Entity *para_poly_parent = d->para_poly_original; + if (para_poly_parent == nullptr) { + continue; + } + + lbDiagParaPolyEntry *entry = map_get(&procs, para_poly_parent); + if (entry == nullptr) { + lbDiagParaPolyEntry entry = {}; + entry.entity = para_poly_parent; + entry.count = 0; + + + gbString w = string_canonical_entity_name(permanent_allocator(), entry.entity); + String name = make_string_c(w); + + for (isize i = 0; i < name.len; i++) { + String s = substring(name, i, name.len); + if (string_starts_with(s, str_lit(":proc"))) { + name = substring(name, 0, i); + break; + } + } + + entry.canonical_name = name; + + map_set(&procs, para_poly_parent, entry); + } + entry = map_get(&procs, para_poly_parent); + GB_ASSERT(entry != nullptr); + entry->count += 1; + entry->total_code_size += lb_total_code_size(p); + } + } + + + auto entries = array_make(heap_allocator(), 0, procs.count); + defer (array_free(&entries)); + + for (auto &entry : procs) { + array_add(&entries, entry.value); + } + + array_sort(entries, [](void const *a, void const *b) -> int { + lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a; + lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b; + if (x->total_code_size > y->total_code_size) { + return -1; + } + if (x->total_code_size < y->total_code_size) { + return +1; + } + return string_compare(x->canonical_name, y->canonical_name); + }); + + + gb_printf("Parametric Polymorphic Procedure Diagnostics\n"); + gb_printf("------------------------------------------------------------------------------------------\n"); + + gb_printf("Sorted by Total Instruction Count Descending (Top 100)\n\n"); + gb_printf("Total Instruction Count | Instantiation Count | Average Instruction Count | Procedure Name\n"); + + isize max_count = 100; + for (auto &entry : entries) { + isize code_size = entry.total_code_size; + isize count = entry.count; + String name = entry.canonical_name; + + f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1); + + gb_printf("%23td | %19td | %25.2f | %.*s\n", code_size, count, average, LIT(name)); + if (max_count-- <= 0) { + break; + } + } + + gb_printf("------------------------------------------------------------------------------------------\n"); + + array_sort(entries, [](void const *a, void const *b) -> int { + lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a; + lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b; + if (x->count > y->count) { + return -1; + } + if (x->count < y->count) { + return +1; + } + + return string_compare(x->canonical_name, y->canonical_name); + }); + + gb_printf("Sorted by Total Instantiation Count Descending (Top 100)\n\n"); + gb_printf("Instantiation Count | Total Instruction Count | Average Instruction Count | Procedure Name\n"); + + max_count = 100; + for (auto &entry : entries) { + isize code_size = entry.total_code_size; + isize count = entry.count; + String name = entry.canonical_name; + + + f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1); + + gb_printf("%19td | %23td | %25.2f | %.*s\n", count, code_size, average, LIT(name)); + if (max_count-- <= 0) { + break; + } + } + + gb_printf("------------------------------------------------------------------------------------------\n"); + + + array_sort(entries, [](void const *a, void const *b) -> int { + lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a; + lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b; + if (x->count < y->count) { + return -1; + } + if (x->count > y->count) { + return +1; + } + + if (x->total_code_size > y->total_code_size) { + return -1; + } + if (x->total_code_size < y->total_code_size) { + return +1; + } + + return string_compare(x->canonical_name, y->canonical_name); + }); + + gb_printf("Single Instanced Parametric Polymorphic Procedures\n\n"); + gb_printf("Instruction Count | Procedure Name\n"); + for (auto &entry : entries) { + isize code_size = entry.total_code_size; + isize count = entry.count; + String name = entry.canonical_name; + if (count != 1) { + break; + } + + gb_printf("%17td | %.*s\n", code_size, LIT(name)); + } + +} + +struct lbDiagModuleEntry { + lbModule *m; + String name; + isize global_internal_count; + isize global_external_count; + isize proc_internal_count; + isize proc_external_count; + isize total_instruction_count; +}; + +gb_internal void lb_do_module_diagnostics(lbGenerator *gen) { + Array modules = {}; + array_init(&modules, heap_allocator()); + defer (array_free(&modules)); + + for (auto &em : gen->modules) { + lbModule *m = em.value; + + { + lbDiagModuleEntry entry = {}; + entry.m = m; + entry.name = make_string_c(m->module_name); + array_add(&modules, entry); + } + lbDiagModuleEntry &entry = modules[modules.count-1]; + + for (LLVMValueRef p = LLVMGetFirstFunction(m->mod); p != nullptr; p = LLVMGetNextFunction(p)) { + LLVMBasicBlockRef block = LLVMGetFirstBasicBlock(p); + if (block == nullptr) { + entry.proc_external_count += 1; + } else { + entry.proc_internal_count += 1; + + for (; block != nullptr; block = LLVMGetNextBasicBlock(block)) { + for (LLVMValueRef i = LLVMGetFirstInstruction(block); i != nullptr; i = LLVMGetNextInstruction(i)) { + entry.total_instruction_count += 1; + } + } + } + } + + for (LLVMValueRef g = LLVMGetFirstGlobal(m->mod); g != nullptr; g = LLVMGetNextGlobal(g)) { + LLVMLinkage linkage = LLVMGetLinkage(g); + if (linkage == LLVMExternalLinkage) { + entry.global_external_count += 1; + } else { + entry.global_internal_count += 1; + } + } + } + + array_sort(modules, [](void const *a, void const *b) -> int { + lbDiagModuleEntry *x = cast(lbDiagModuleEntry *)a; + lbDiagModuleEntry *y = cast(lbDiagModuleEntry *)b; + + if (x->total_instruction_count > y->total_instruction_count) { + return -1; + } + if (x->total_instruction_count < y->total_instruction_count) { + return +1; + } + + return string_compare(x->name, y->name); + }); + + gb_printf("Module Diagnostics\n\n"); + gb_printf("Total Instructions | Global Internals | Global Externals | Proc Internals | Proc Externals | Files | Instructions/File | Instructions/Proc | Module Name\n"); + gb_printf("-------------------+------------------+------------------+----------------+----------------+-------+-------------------+-------------------+------------\n"); + for (auto &entry : modules) { + isize file_count = 1; + if (entry.m->file != nullptr) { + file_count = 1; + } else if (entry.m->pkg) { + file_count = entry.m->pkg->files.count; + } + + f64 instructions_per_file = cast(f64)entry.total_instruction_count / gb_max(1.0, cast(f64)file_count); + f64 instructions_per_proc = cast(f64)entry.total_instruction_count / gb_max(1.0, cast(f64)entry.proc_internal_count); + + gb_printf("%18td | %16td | %16td | %14td | %14td | %5td | %17.1f | %17.1f | %s \n", + entry.total_instruction_count, + entry.global_internal_count, + entry.global_external_count, + entry.proc_internal_count, + entry.proc_external_count, + file_count, + instructions_per_file, + instructions_per_proc, + entry.m->module_name); + } + + +} + +gb_internal void lb_do_build_diagnostics(lbGenerator *gen) { + lb_do_para_poly_diagnostics(gen); + gb_printf("------------------------------------------------------------------------------------------\n"); + gb_printf("------------------------------------------------------------------------------------------\n\n"); + lb_do_module_diagnostics(gen); + gb_printf("------------------------------------------------------------------------------------------\n"); + gb_printf("------------------------------------------------------------------------------------------\n\n"); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 0a24d64a6..6ad20cf26 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,6 +74,7 @@ gb_global Timings global_timings = {0}; #include "cached.cpp" #include "linker.cpp" +#include "bundle_command.cpp" #if defined(GB_SYSTEM_WINDOWS) && defined(ODIN_TILDE_BACKEND) #define ALLOW_TILDE 1 @@ -87,13 +88,6 @@ gb_global Timings global_timings = {0}; #include "llvm_backend.cpp" -#if defined(GB_SYSTEM_OSX) - #include - #if LLVM_VERSION_MAJOR < 11 || (LLVM_VERSION_MAJOR > 14 && LLVM_VERSION_MAJOR < 17) || LLVM_VERSION_MAJOR > 19 - #error LLVM Version 11..=14 or 17..=19 is required => "brew install llvm@14" - #endif -#endif - #include "bug_report.cpp" // NOTE(bill): 'name' is used in debugging and profiling modes @@ -148,9 +142,9 @@ gb_internal i32 system_exec_command_line_app_internal(bool exit_on_err, char con } wcmd = string_to_string16(permanent_allocator(), make_string(cast(u8 *)cmd_line, cmd_len-1)); - if (CreateProcessW(nullptr, wcmd.text, - nullptr, nullptr, true, 0, nullptr, nullptr, - &start_info, &pi)) { + if (CreateProcessW(nullptr, cast(wchar_t *)wcmd.text, + nullptr, nullptr, true, 0, nullptr, nullptr, + &start_info, &pi)) { WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, cast(DWORD *)&exit_code); @@ -238,7 +232,7 @@ gb_internal Array setup_args(int argc, char const **argv) { wchar_t **wargv = command_line_to_wargv(GetCommandLineW(), &wargc); auto args = array_make(a, 0, wargc); for (isize i = 0; i < wargc; i++) { - wchar_t *warg = wargv[i]; + u16 *warg = cast(u16 *)wargv[i]; isize wlen = string16_len(warg); String16 wstr = make_string16(warg, wlen); String arg = string16_to_string(a, wstr); @@ -283,10 +277,11 @@ gb_internal void usage(String argv0, String argv1 = {}) { print_usage_line(1, "build Compiles directory of .odin files, as an executable."); print_usage_line(1, " One must contain the program's entry point, all must be in the same package."); print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable."); - print_usage_line(1, "check Parses, and type checks a directory of .odin files."); + print_usage_line(1, "bundle Bundles a directory in a specific layout for that platform."); + print_usage_line(1, "check Parses and type checks a directory of .odin files."); print_usage_line(1, "strip-semicolon Parses, type checks, and removes unneeded semicolons from the entire program."); print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package."); - print_usage_line(1, "doc Generates documentation on a directory of .odin files."); + print_usage_line(1, "doc Generates documentation from a directory of .odin files."); print_usage_line(1, "version Prints version."); print_usage_line(1, "report Prints information useful to reporting a bug."); print_usage_line(1, "root Prints the root path where Odin looks for the builtin collections."); @@ -317,6 +312,7 @@ enum BuildFlagKind { BuildFlag_Collection, BuildFlag_Define, BuildFlag_BuildMode, + BuildFlag_KeepExecutable, BuildFlag_Target, BuildFlag_Subtarget, BuildFlag_Debug, @@ -324,6 +320,7 @@ enum BuildFlagKind { BuildFlag_NoBoundsCheck, BuildFlag_NoTypeAssert, BuildFlag_NoDynamicLiterals, + BuildFlag_DynamicLiterals, BuildFlag_NoCRT, BuildFlag_NoRPath, BuildFlag_NoEntryPoint, @@ -373,6 +370,7 @@ enum BuildFlagKind { BuildFlag_NoRTTI, BuildFlag_DynamicMapCalls, BuildFlag_ObfuscateSourceCodeLocations, + BuildFlag_SourceCodeLocations, BuildFlag_Compact, BuildFlag_GlobalDefinitions, @@ -394,6 +392,10 @@ enum BuildFlagKind { BuildFlag_PrintLinkerFlags, + BuildFlag_IntegerDivisionByZero, + + BuildFlag_BuildDiagnostics, + // internal use only BuildFlag_InternalFastISel, BuildFlag_InternalIgnoreLazy, @@ -403,6 +405,8 @@ enum BuildFlagKind { BuildFlag_InternalCached, BuildFlag_InternalNoInline, BuildFlag_InternalByValue, + BuildFlag_InternalWeakMonomorphization, + BuildFlag_InternalLLVMVerification, BuildFlag_Tilde, @@ -415,6 +419,10 @@ enum BuildFlagKind { BuildFlag_Subsystem, #endif + BuildFlag_AndroidKeystore, + BuildFlag_AndroidKeystoreAlias, + BuildFlag_AndroidKeystorePassword, + BuildFlag_COUNT, }; @@ -433,12 +441,12 @@ struct BuildFlag { BuildFlagKind kind; String name; BuildFlagParamKind param_kind; - u32 command_support; + u64 command_support; bool allow_multiple; }; -gb_internal void add_flag(Array *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_multiple=false) { +gb_internal void add_flag(Array *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u64 command_support, bool allow_multiple=false) { BuildFlag flag = {kind, name, param_kind, command_support, allow_multiple}; array_add(build_flags, flag); } @@ -531,6 +539,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Collection, str_lit("collection"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_Define, str_lit("define"), BuildFlagParam_String, Command__does_check, true); add_flag(&build_flags, BuildFlag_BuildMode, str_lit("build-mode"), BuildFlagParam_String, Command__does_build); // Commands_build is not used to allow for a better error message + add_flag(&build_flags, BuildFlag_KeepExecutable, str_lit("keep-executable"), BuildFlagParam_None, Command__does_build | Command_test); add_flag(&build_flags, BuildFlag_Target, str_lit("target"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_Subtarget, str_lit("subtarget"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check); @@ -539,6 +548,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoTypeAssert, str_lit("no-type-assert"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_DynamicLiterals, str_lit("dynamic-literals"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoRPath, str_lit("no-rpath"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test); @@ -574,7 +584,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_TargetFeatures, str_lit("target-features"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_StrictTargetFeatures, str_lit("strict-target-features"), BuildFlagParam_None, Command__does_build); - add_flag(&build_flags, BuildFlag_MinimumOSVersion, str_lit("minimum-os-version"), BuildFlagParam_String, Command__does_build); + add_flag(&build_flags, BuildFlag_MinimumOSVersion, str_lit("minimum-os-version"), BuildFlagParam_String, Command__does_build | Command_bundle_android); add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build); @@ -591,9 +601,10 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_DynamicMapCalls, str_lit("dynamic-map-calls"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ObfuscateSourceCodeLocations, str_lit("obfuscate-source-code-locations"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_SourceCodeLocations, str_lit("source-code-locations"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc); - add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc | Command_test); + add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc | Command_test | Command_build); add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc); add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all); @@ -608,6 +619,10 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_PrintLinkerFlags, str_lit("print-linker-flags"), BuildFlagParam_None, Command_build); + add_flag(&build_flags, BuildFlag_IntegerDivisionByZero, str_lit("integer-division-by-zero"), BuildFlagParam_String, Command__does_check); + + add_flag(&build_flags, BuildFlag_BuildDiagnostics, str_lit("build-diagnostics"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all); @@ -616,6 +631,8 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalNoInline, str_lit("internal-no-inline"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalByValue, str_lit("internal-by-value"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalWeakMonomorphization, str_lit("internal-weak-monomorphization"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalLLVMVerification, str_lit("internal-ignore-llvm-verification"), BuildFlagParam_None, Command_all); #if ALLOW_TILDE add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); @@ -631,9 +648,20 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Subsystem, str_lit("subsystem"), BuildFlagParam_String, Command__does_build); #endif + add_flag(&build_flags, BuildFlag_AndroidKeystore, str_lit("android-keystore"), BuildFlagParam_String, Command_bundle_android); + add_flag(&build_flags, BuildFlag_AndroidKeystoreAlias, str_lit("android-keystore-alias"), BuildFlagParam_String, Command_bundle_android); + add_flag(&build_flags, BuildFlag_AndroidKeystorePassword, str_lit("android-keystore-password"), BuildFlagParam_String, Command_bundle_android); - GB_ASSERT(args.count >= 3); - Array flag_args = array_slice(args, 3, args.count); + + Array flag_args = {}; + + if (build_context.command_kind == Command_bundle_android) { + GB_ASSERT(args.count >= 4); + flag_args = array_slice(args, 4, args.count); + } else { + GB_ASSERT(args.count >= 3); + flag_args = array_slice(args, 3, args.count); + } bool set_flags[BuildFlag_COUNT] = {}; @@ -1112,8 +1140,9 @@ gb_internal bool parse_build_flags(Array args) { String str = value.value_string; bool found = false; - if (selected_target_metrics->metrics->os != TargetOs_darwin) { - gb_printf_err("-subtarget can only be used with darwin based targets at the moment\n"); + if (selected_target_metrics->metrics->os != TargetOs_darwin && + selected_target_metrics->metrics->os != TargetOs_linux ) { + gb_printf_err("-subtarget can only be used with darwin and linux based targets at the moment\n"); bad_flags = true; break; } @@ -1180,6 +1209,9 @@ gb_internal bool parse_build_flags(Array args) { break; } + case BuildFlag_KeepExecutable: + build_context.keep_executable = true; + break; case BuildFlag_Debug: build_context.ODIN_DEBUG = true; @@ -1196,6 +1228,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_NoDynamicLiterals: gb_printf_err("Warning: Use of -no-dynamic-literals is now redundant\n"); break; + case BuildFlag_DynamicLiterals: + build_context.dynamic_literals = true; + break; case BuildFlag_NoCRT: build_context.no_crt = true; break; @@ -1401,7 +1436,23 @@ gb_internal bool parse_build_flags(Array args) { break; case BuildFlag_ObfuscateSourceCodeLocations: - build_context.obfuscate_source_code_locations = true; + gb_printf_err("'-obfuscate-source-code-locations' is now deprecated in favor of '-source-code-locations:obfuscated'\n"); + build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated; + break; + + case BuildFlag_SourceCodeLocations: + if (str_eq_ignore_case(value.value_string, str_lit("normal"))) { + build_context.source_code_location_info = SourceCodeLocationInfo_Normal; + } else if (str_eq_ignore_case(value.value_string, str_lit("obfuscated"))) { + build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated; + } else if (str_eq_ignore_case(value.value_string, str_lit("filename"))) { + build_context.source_code_location_info = SourceCodeLocationInfo_Filename; + } else if (str_eq_ignore_case(value.value_string, str_lit("none"))) { + build_context.source_code_location_info = SourceCodeLocationInfo_None; + } else { + gb_printf_err("-source-code-locations: options are 'normal', 'obfuscated', 'filename', and 'none'\n"); + bad_flags = true; + } break; case BuildFlag_DefaultToNilAllocator: @@ -1476,7 +1527,7 @@ gb_internal bool parse_build_flags(Array args) { } else if (str_eq_ignore_case(value.value_string, str_lit("unix"))) { build_context.ODIN_ERROR_POS_STYLE = ErrorPosStyle_Unix; } else { - gb_printf_err("-error-pos-style options are 'unix', 'odin' and 'default' (odin)\n"); + gb_printf_err("-error-pos-style options are 'unix', 'odin', and 'default' (odin)\n"); bad_flags = true; } break; @@ -1500,6 +1551,24 @@ gb_internal bool parse_build_flags(Array args) { build_context.print_linker_flags = true; break; + case BuildFlag_IntegerDivisionByZero: + GB_ASSERT(value.kind == ExactValue_String); + if (str_eq_ignore_case(value.value_string, "trap")) { + build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Trap; + } else if (str_eq_ignore_case(value.value_string, "zero")) { + build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Zero; + } else if (str_eq_ignore_case(value.value_string, "self")) { + build_context.integer_division_by_zero_behaviour = IntegerDivisionByZero_Self; + }else { + gb_printf_err("-integer-division-by-zero options are 'trap', 'zero', and 'self'.\n"); + bad_flags = true; + } + break; + + case BuildFlag_BuildDiagnostics: + build_context.build_diagnostics = true; + break; + case BuildFlag_InternalFastISel: build_context.fast_isel = true; break; @@ -1526,6 +1595,13 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_InternalByValue: build_context.internal_by_value = true; break; + case BuildFlag_InternalWeakMonomorphization: + build_context.internal_weak_monomorphization = true; + break; + case BuildFlag_InternalLLVMVerification: + build_context.internal_ignore_llvm_verification = true; + break; + case BuildFlag_Tilde: build_context.tilde_backend = true; @@ -1534,6 +1610,11 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_Sanitize: GB_ASSERT(value.kind == ExactValue_String); + if (build_context.sanitizer_flags != 0) { + gb_printf_err("-sanitize: may only be used once\n"); + bad_flags = true; + } + if (str_eq_ignore_case(value.value_string, str_lit("address"))) { build_context.sanitizer_flags |= SanitizerFlag_Address; } else if (str_eq_ignore_case(value.value_string, str_lit("memory"))) { @@ -1606,9 +1687,9 @@ gb_internal bool parse_build_flags(Array args) { GB_ASSERT(value.kind == ExactValue_String); String subsystem = value.value_string; bool subsystem_found = false; - for (int i = 0; i < Windows_Subsystem_COUNT; i++) { + for (int i = 1; i < Windows_Subsystem_COUNT; i++) { if (str_eq_ignore_case(subsystem, windows_subsystem_names[i])) { - build_context.ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[i]; + build_context.ODIN_WINDOWS_SUBSYSTEM = Windows_Subsystem(i); subsystem_found = true; break; } @@ -1617,7 +1698,7 @@ gb_internal bool parse_build_flags(Array args) { // WINDOW is a hidden alias for WINDOWS. Check it. String subsystem_windows_alias = str_lit("WINDOW"); if (!subsystem_found && str_eq_ignore_case(subsystem, subsystem_windows_alias)) { - build_context.ODIN_WINDOWS_SUBSYSTEM = windows_subsystem_names[Windows_Subsystem_WINDOWS]; + build_context.ODIN_WINDOWS_SUBSYSTEM = Windows_Subsystem_WINDOWS; subsystem_found = true; break; } @@ -1625,8 +1706,8 @@ gb_internal bool parse_build_flags(Array args) { if (!subsystem_found) { gb_printf_err("Invalid -subsystem string, got %.*s. Expected one of:\n", LIT(subsystem)); gb_printf_err("\t"); - for (int i = 0; i < Windows_Subsystem_COUNT; i++) { - if (i > 0) { + for (int i = 1; i < Windows_Subsystem_COUNT; i++) { + if (i > 1) { gb_printf_err(", "); } gb_printf_err("%.*s", LIT(windows_subsystem_names[i])); @@ -1644,6 +1725,20 @@ gb_internal bool parse_build_flags(Array args) { } #endif + case BuildFlag_AndroidKeystore: + GB_ASSERT(value.kind == ExactValue_String); + build_context.android_keystore = value.value_string; + break; + + case BuildFlag_AndroidKeystoreAlias: + GB_ASSERT(value.kind == ExactValue_String); + build_context.android_keystore_alias = value.value_string; + break; + + case BuildFlag_AndroidKeystorePassword: + GB_ASSERT(value.kind == ExactValue_String); + build_context.android_keystore_password = value.value_string; + break; } } @@ -1659,8 +1754,8 @@ gb_internal bool parse_build_flags(Array args) { gb_printf_err("'%.*s' is supported with the following commands:\n", LIT(name)); gb_printf_err("\t"); i32 count = 0; - for (u32 i = 0; i < 32; i++) { - if (found_bf.command_support & (1< 0) { gb_printf_err(", "); } @@ -1698,6 +1793,12 @@ gb_internal bool parse_build_flags(Array args) { bad_flags = true; } + + if ((build_context.command_kind & (Command_doc | Command_test)) == 0 && build_context.test_all_packages) { + gb_printf_err("`-test-all-packages` can only be used with `odin build -build-mode:test`, `odin test`, or `odin doc`.\n"); + bad_flags = true; + } + return !bad_flags; } @@ -1950,39 +2051,39 @@ gb_internal void show_timings(Checker *c, Timings *t) { if (build_context.show_debug_messages && build_context.show_more_timings) { { - gb_printf("\n"); - gb_printf("Total Lines - %td\n", lines); - gb_printf("Total Tokens - %td\n", tokens); - gb_printf("Total Files - %td\n", files); - gb_printf("Total Packages - %td\n", packages); - gb_printf("Total File Size - %td\n", total_file_size); - gb_printf("\n"); + gb_printf_err("\n"); + gb_printf_err("Total Lines - %td\n", lines); + gb_printf_err("Total Tokens - %td\n", tokens); + gb_printf_err("Total Files - %td\n", files); + gb_printf_err("Total Packages - %td\n", packages); + gb_printf_err("Total File Size - %td\n", total_file_size); + gb_printf_err("\n"); } { f64 time = total_tokenizing_time; - gb_printf("Tokenization Only\n"); - gb_printf("LOC/s - %.3f\n", cast(f64)lines/time); - gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines); - gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time); - gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens); - gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time); - gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024)); - gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size); + gb_printf_err("Tokenization Only\n"); + gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time); + gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines); + gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time); + gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens); + gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time); + gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024)); + gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size); - gb_printf("\n"); + gb_printf_err("\n"); } { f64 time = total_parsing_time; - gb_printf("Parsing Only\n"); - gb_printf("LOC/s - %.3f\n", cast(f64)lines/time); - gb_printf("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines); - gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/time); - gb_printf("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens); - gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/time); - gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024)); - gb_printf("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size); + gb_printf_err("Parsing Only\n"); + gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time); + gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines); + gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time); + gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens); + gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time); + gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024)); + gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size); - gb_printf("\n"); + gb_printf_err("\n"); } { TimeStamp ts = {}; @@ -1995,16 +2096,16 @@ gb_internal void show_timings(Checker *c, Timings *t) { GB_ASSERT(ts.label == "parse files"); f64 parse_time = time_stamp_as_s(ts, t->freq); - gb_printf("Parse pass\n"); - gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time); - gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines); - gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time); - gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens); - gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time); - gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024)); - gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size); + gb_printf_err("Parse pass\n"); + gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/parse_time); + gb_printf_err("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines); + gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/parse_time); + gb_printf_err("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens); + gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time); + gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024)); + gb_printf_err("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size); - gb_printf("\n"); + gb_printf_err("\n"); } { TimeStamp ts = {}; @@ -2025,27 +2126,27 @@ gb_internal void show_timings(Checker *c, Timings *t) { ts.finish = ts_end.finish; f64 parse_time = time_stamp_as_s(ts, t->freq); - gb_printf("Checker pass\n"); - gb_printf("LOC/s - %.3f\n", cast(f64)lines/parse_time); - gb_printf("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines); - gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/parse_time); - gb_printf("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens); - gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time); - gb_printf("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024)); - gb_printf("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size); - gb_printf("\n"); + gb_printf_err("Checker pass\n"); + gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/parse_time); + gb_printf_err("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines); + gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/parse_time); + gb_printf_err("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens); + gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time); + gb_printf_err("MiB/s - %.3f\n", (cast(f64)total_file_size/parse_time)/(1024*1024)); + gb_printf_err("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size); + gb_printf_err("\n"); } { f64 total_time = t->total_time_seconds; - gb_printf("Total pass\n"); - gb_printf("LOC/s - %.3f\n", cast(f64)lines/total_time); - gb_printf("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines); - gb_printf("Tokens/s - %.3f\n", cast(f64)tokens/total_time); - gb_printf("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens); - gb_printf("bytes/s - %.3f\n", cast(f64)total_file_size/total_time); - gb_printf("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024)); - gb_printf("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size); - gb_printf("\n"); + gb_printf_err("Total pass\n"); + gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/total_time); + gb_printf_err("us/LOC - %.3f\n", 1.0e6*total_time/cast(f64)lines); + gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/total_time); + gb_printf_err("us/Token - %.3f\n", 1.0e6*total_time/cast(f64)tokens); + gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/total_time); + gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/total_time)/(1024*1024)); + gb_printf_err("us/bytes - %.3f\n", 1.0e6*total_time/cast(f64)total_file_size); + gb_printf_err("\n"); } } } @@ -2176,7 +2277,7 @@ gb_internal void remove_temp_files(lbGenerator *gen) { return; } - TIME_SECTION("remove keep temp files"); + TIME_SECTION("remove temp files"); for (String const &path : gen->output_temp_paths) { gb_file_remove(cast(char const *)path.text); @@ -2196,20 +2297,30 @@ gb_internal void remove_temp_files(lbGenerator *gen) { } -gb_internal void print_show_help(String const arg0, String command, String optional_flag = {}) { +gb_internal int print_show_help(String const arg0, String command, String optional_flag = {}) { + bool help_resolved = false; + bool printed_usage_header = false; + bool printed_flags_header = false; + if (command == "help" && optional_flag.len != 0 && optional_flag[0] != '-') { command = optional_flag; optional_flag = {}; } - print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0)); - print_usage_line(0, "Usage:"); - print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command)); - print_usage_line(0, ""); - defer (print_usage_line(0, "")); - + auto const print_usage_header_once = [&help_resolved, &printed_usage_header, arg0, command]() { + if (printed_usage_header) { + return; + } + print_usage_line(0, "%.*s is a tool for managing Odin source code.", LIT(arg0)); + print_usage_line(0, "Usage:"); + print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command)); + print_usage_line(0, ""); + help_resolved = true; + printed_usage_header = true; + }; if (command == "build") { + print_usage_header_once(); print_usage_line(1, "build Compiles directory of .odin files as an executable."); print_usage_line(2, "One must contain the program's entry point, all must be in the same package."); print_usage_line(2, "Use `-file` to build a single file instead."); @@ -2218,6 +2329,7 @@ gb_internal void print_show_help(String const arg0, String command, String optio print_usage_line(3, "odin build Builds package in ."); print_usage_line(3, "odin build filename.odin -file Builds single-file package, must contain entry point."); } else if (command == "run") { + print_usage_header_once(); print_usage_line(1, "run Same as 'build', but also then runs the newly compiled executable."); print_usage_line(2, "Append an empty flag and then the args, '-- ', to specify args for the output."); print_usage_line(2, "Examples:"); @@ -2225,24 +2337,40 @@ gb_internal void print_show_help(String const arg0, String command, String optio print_usage_line(3, "odin run Builds and runs package in ."); print_usage_line(3, "odin run filename.odin -file Builds and runs single-file package, must contain entry point."); } else if (command == "check") { + print_usage_header_once(); print_usage_line(1, "check Parses and type checks directory of .odin files."); print_usage_line(2, "Examples:"); print_usage_line(3, "odin check . Type checks package in current directory."); print_usage_line(3, "odin check Type checks package in ."); print_usage_line(3, "odin check filename.odin -file Type checks single-file package, must contain entry point."); } else if (command == "test") { + print_usage_header_once(); print_usage_line(1, "test Builds and runs procedures with the attribute @(test) in the initial package."); } else if (command == "doc") { + print_usage_header_once(); print_usage_line(1, "doc Generates documentation from a directory of .odin files."); print_usage_line(2, "Examples:"); print_usage_line(3, "odin doc . Generates documentation on package in current directory."); print_usage_line(3, "odin doc Generates documentation on package in ."); print_usage_line(3, "odin doc filename.odin -file Generates documentation on single-file package."); } else if (command == "version") { + print_usage_header_once(); print_usage_line(1, "version Prints version."); } else if (command == "strip-semicolon") { + print_usage_header_once(); print_usage_line(1, "strip-semicolon"); print_usage_line(2, "Parses and type checks .odin file(s) and then removes unneeded semicolons from the entire project."); + } else if (command == "bundle") { + print_usage_header_once(); + print_usage_line(1, "bundle Bundles a directory in a specific layout for that platform"); + print_usage_line(2, "Supported platforms:"); + print_usage_line(3, "android"); + } else if (command == "report") { + print_usage_header_once(); + print_usage_line(1, "report Prints information useful to reporting a bug."); + } else if (command == "root") { + print_usage_header_once(); + print_usage_line(1, "root Prints the root path where Odin looks for the builtin collections."); } bool doc = command == "doc"; @@ -2252,6 +2380,7 @@ gb_internal void print_show_help(String const arg0, String command, String optio bool strip_semicolon = command == "strip-semicolon"; bool check_only = command == "check" || strip_semicolon; bool check = run_or_build || check_only; + bool bundle = command == "bundle"; if (command == "help") { doc = true; @@ -2263,13 +2392,10 @@ gb_internal void print_show_help(String const arg0, String command, String optio check = true; } - print_usage_line(0, ""); - print_usage_line(1, "Flags"); - print_usage_line(0, ""); - auto const print_flag = [&optional_flag](char const *flag) -> bool { + auto const print_flag = [&optional_flag, &help_resolved, &printed_flags_header, print_usage_header_once](char const *flag) -> bool { if (optional_flag.len != 0) { String f = make_string_c(flag); isize i = string_index_byte(f, ':'); @@ -2280,6 +2406,14 @@ gb_internal void print_show_help(String const arg0, String command, String optio return false; } } + print_usage_header_once(); + if (!printed_flags_header) { + print_usage_line(0, ""); + print_usage_line(1, "Flags"); + print_usage_line(0, ""); + printed_flags_header = true; + } + help_resolved = true; print_usage_line(0, ""); print_usage_line(1, flag); return true; @@ -2301,20 +2435,20 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (print_flag("-build-mode:")) { print_usage_line(2, "Sets the build mode."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-build-mode:exe Builds as an executable."); - print_usage_line(3, "-build-mode:test Builds as an executable that executes tests."); - print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library."); - print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library."); - print_usage_line(3, "-build-mode:dynamic Builds as a dynamically linked library."); - print_usage_line(3, "-build-mode:lib Builds as a statically linked library."); - print_usage_line(3, "-build-mode:static Builds as a statically linked library."); - print_usage_line(3, "-build-mode:obj Builds as an object file."); - print_usage_line(3, "-build-mode:object Builds as an object file."); - print_usage_line(3, "-build-mode:assembly Builds as an assembly file."); - print_usage_line(3, "-build-mode:assembler Builds as an assembly file."); - print_usage_line(3, "-build-mode:asm Builds as an assembly file."); - print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file."); - print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file."); + print_usage_line(3, "-build-mode:exe Builds as an executable."); + print_usage_line(3, "-build-mode:test Builds as an executable that executes tests."); + print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library."); + print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library."); + print_usage_line(3, "-build-mode:dynamic Builds as a dynamically linked library."); + print_usage_line(3, "-build-mode:lib Builds as a statically linked library."); + print_usage_line(3, "-build-mode:static Builds as a statically linked library."); + print_usage_line(3, "-build-mode:obj Builds as an object file."); + print_usage_line(3, "-build-mode:object Builds as an object file."); + print_usage_line(3, "-build-mode:assembly Builds as an assembly file."); + print_usage_line(3, "-build-mode:assembler Builds as an assembly file."); + print_usage_line(3, "-build-mode:asm Builds as an assembly file."); + print_usage_line(3, "-build-mode:llvm-ir Builds as an LLVM IR file."); + print_usage_line(3, "-build-mode:llvm Builds as an LLVM IR file."); } } @@ -2323,16 +2457,16 @@ gb_internal void print_show_help(String const arg0, String command, String optio print_usage_line(2, "Defines a library collection used for imports."); print_usage_line(2, "Example: -collection:shared=dir/to/shared"); print_usage_line(2, "Usage in Code:"); - print_usage_line(3, "import \"shared:foo\""); + print_usage_line(3, "import \"shared:foo\""); } if (print_flag("-custom-attribute:")) { print_usage_line(2, "Add a custom attribute which will be ignored if it is unknown."); print_usage_line(2, "This can be used with metaprogramming tools."); print_usage_line(2, "Examples:"); - print_usage_line(3, "-custom-attribute:my_tag"); - print_usage_line(3, "-custom-attribute:my_tag,the_other_thing"); - print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing"); + print_usage_line(3, "-custom-attribute:my_tag"); + print_usage_line(3, "-custom-attribute:my_tag,the_other_thing"); + print_usage_line(3, "-custom-attribute:my_tag -custom-attribute:the_other_thing"); } } @@ -2355,7 +2489,7 @@ gb_internal void print_show_help(String const arg0, String command, String optio print_usage_line(2, "Defines a scalar boolean, integer or string as global constant."); print_usage_line(2, "Example: -define:SPAM=123"); print_usage_line(2, "Usage in code:"); - print_usage_line(3, "#config(SPAM, default_value)"); + print_usage_line(3, "#config(SPAM, default_value)"); } } @@ -2390,9 +2524,9 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (check) { if (print_flag("-error-pos-style:")) { print_usage_line(2, "Available options:"); - print_usage_line(3, "-error-pos-style:unix file/path:45:3:"); - print_usage_line(3, "-error-pos-style:odin file/path(45:3)"); - print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)"); + print_usage_line(3, "-error-pos-style:unix file/path:45:3:"); + print_usage_line(3, "-error-pos-style:odin file/path(45:3)"); + print_usage_line(3, "-error-pos-style:default (Defaults to 'odin'.)"); } if (print_flag("-export-defineables:")) { @@ -2403,8 +2537,8 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (print_flag("-export-dependencies:")) { print_usage_line(2, "Exports dependencies to one of a few formats. Requires `-export-dependencies-file`."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-export-dependencies:make Exports in Makefile format"); - print_usage_line(3, "-export-dependencies:json Exports in JSON format"); + print_usage_line(3, "-export-dependencies:make Exports in Makefile format"); + print_usage_line(3, "-export-dependencies:json Exports in JSON format"); } if (print_flag("-export-dependencies-file:")) { @@ -2415,8 +2549,8 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (print_flag("-export-timings:")) { print_usage_line(2, "Exports timings to one of a few formats. Requires `-show-timings` or `-show-more-timings`."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-export-timings:json Exports compile time stats to JSON."); - print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV."); + print_usage_line(3, "-export-timings:json Exports compile time stats to JSON."); + print_usage_line(3, "-export-timings:csv Exports compile time stats to CSV."); } if (print_flag("-export-timings-file:")) { @@ -2464,7 +2598,20 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (print_flag("-ignore-warnings")) { print_usage_line(2, "Ignores warning messages."); } + } + if (check) { + if (print_flag("-integer-division-by-zero:")) { + print_usage_line(2, "Specifies the default behaviour for integer division by zero."); + print_usage_line(2, "Available Options:"); + print_usage_line(3, "-integer-division-by-zero:trap Trap on division/modulo/remainder by zero"); + print_usage_line(3, "-integer-division-by-zero:zero x/0 == 0 and x%%0 == x and x%%%%0 == x"); + print_usage_line(3, "-integer-division-by-zero:self x/0 == x and x%%0 == 0 and x%%%%0 == 0"); + print_usage_line(3, "-integer-division-by-zero:all-bits x/0 == ~T(0) and x%%0 == x and x%%%%0 == x"); + } + } + + if (check) { if (print_flag("-json-errors")) { print_usage_line(2, "Prints the error messages as json to stderr."); } @@ -2480,6 +2627,14 @@ gb_internal void print_show_help(String const arg0, String command, String optio } } + if (test_only || run_or_build) { + if (print_flag("-keep-executable")) { + print_usage_line(2, "Keep the executable generated by `odin test` or `odin run` after running it. We clean it up by default."); + print_usage_line(2, "If you build your program or test using `odin build`, the compiler does not automatically execute"); + print_usage_line(2, "the resulting program, and this option is not applicable."); + } + } + if (run_or_build) { if (print_flag("-linker:")) { print_usage_line(2, "Specify the linker to use."); @@ -2506,9 +2661,9 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (print_flag("-microarch:")) { print_usage_line(2, "Specifies the specific micro-architecture for the build in a string."); print_usage_line(2, "Examples:"); - print_usage_line(3, "-microarch:sandybridge"); - print_usage_line(3, "-microarch:native"); - print_usage_line(3, "-microarch:\"?\" for a list"); + print_usage_line(3, "-microarch:sandybridge"); + print_usage_line(3, "-microarch:native"); + print_usage_line(3, "-microarch:\"?\" for a list"); } } @@ -2519,13 +2674,15 @@ gb_internal void print_show_help(String const arg0, String command, String optio } } - if (run_or_build) { + if (run_or_build || bundle) { if (print_flag("-minimum-os-version:")) { print_usage_line(2, "Sets the minimum OS version targeted by the application."); print_usage_line(2, "Default: -minimum-os-version:11.0.0"); - print_usage_line(2, "Only used when target is Darwin, if given, linking mismatched versions will emit a warning."); + print_usage_line(2, "Only used when target is Darwin or subtarget is Android, if given, linking mismatched versions will emit a warning."); } + } + if (run_or_build) { if (print_flag("-no-bounds-check")) { print_usage_line(2, "Disables bounds checking program wide."); } @@ -2563,10 +2720,10 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (print_flag("-o:")) { print_usage_line(2, "Sets the optimization mode for compilation."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-o:none"); - print_usage_line(3, "-o:minimal"); - print_usage_line(3, "-o:size"); - print_usage_line(3, "-o:speed"); + print_usage_line(3, "-o:none"); + print_usage_line(3, "-o:minimal"); + print_usage_line(3, "-o:size"); + print_usage_line(3, "-o:speed"); if (LB_USE_NEW_PASS_SYSTEM) { print_usage_line(3, "-o:aggressive (use this with caution)"); } @@ -2574,8 +2731,14 @@ gb_internal void print_show_help(String const arg0, String command, String optio } - if (print_flag("-obfuscate-source-code-locations")) { - print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value."); + if (print_flag("-source-code-locations:")) { + print_usage_line(2, "Processes the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value."); + print_usage_line(2, "Available options:"); + print_usage_line(3, "-source-code-locations:normal"); + print_usage_line(3, "-source-code-locations:obfuscated"); + print_usage_line(3, "-source-code-locations:filename"); + print_usage_line(3, "-source-code-locations:none"); + print_usage_line(2, "The default is -source-code-locations:normal."); } @@ -2587,7 +2750,7 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (doc) { if (print_flag("-out:")) { - print_usage_line(2, "Sets the base name of the resultig .odin-doc file."); + print_usage_line(2, "Sets the base name of the resulting .odin-doc file."); print_usage_line(2, "The extension can be optionally included; the resulting file will always have an extension of '.odin-doc'."); print_usage_line(2, "Example: -out:foo"); } @@ -2617,10 +2780,10 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (print_flag("-reloc-mode:")) { print_usage_line(2, "Specifies the reloc mode."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-reloc-mode:default"); - print_usage_line(3, "-reloc-mode:static"); - print_usage_line(3, "-reloc-mode:pic"); - print_usage_line(3, "-reloc-mode:dynamic-no-pic"); + print_usage_line(3, "-reloc-mode:default"); + print_usage_line(3, "-reloc-mode:static"); + print_usage_line(3, "-reloc-mode:pic"); + print_usage_line(3, "-reloc-mode:dynamic-no-pic"); } #if defined(GB_SYSTEM_WINDOWS) @@ -2635,10 +2798,9 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (print_flag("-sanitize:")) { print_usage_line(2, "Enables sanitization analysis."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-sanitize:address"); - print_usage_line(3, "-sanitize:memory"); - print_usage_line(3, "-sanitize:thread"); - print_usage_line(2, "NOTE: This flag can be used multiple times."); + print_usage_line(3, "-sanitize:address"); + print_usage_line(3, "-sanitize:memory"); + print_usage_line(3, "-sanitize:thread"); } } @@ -2682,7 +2844,7 @@ gb_internal void print_show_help(String const arg0, String command, String optio print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons."); print_usage_line(2, "Errs on missing trailing commas followed by a newline."); print_usage_line(2, "Errs on deprecated syntax."); - print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS)."); + print_usage_line(2, "Errs when the attached-brace style is not adhered to (also known as 1TBS)."); print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token."); } } @@ -2698,17 +2860,32 @@ gb_internal void print_show_help(String const arg0, String command, String optio print_usage_line(2, "[Windows only]"); print_usage_line(2, "Defines the subsystem for the application."); print_usage_line(2, "Available options:"); - print_usage_line(3, "-subsystem:console"); - print_usage_line(3, "-subsystem:windows"); + print_usage_line(3, "-subsystem:console"); + print_usage_line(3, "-subsystem:windows"); } #endif + } + if (build) { + if (print_flag("-subtarget:")) { + print_usage_line(2, "[Darwin and Linux only]"); + print_usage_line(2, "Available subtargets:"); + String prefix = str_lit("-subtarget:"); + for (u32 i = 1; i < Subtarget_COUNT; i++) { + String name = subtarget_strings[i]; + String help_string = concatenate_strings(temporary_allocator(), prefix, name); + print_usage_line(3, (const char *)help_string.text); + } + } + } + + if (run_or_build) { if (print_flag("-target-features:")) { print_usage_line(2, "Specifies CPU features to enable on top of the enabled features implied by -microarch."); print_usage_line(2, "Examples:"); - print_usage_line(3, "-target-features:atomics"); - print_usage_line(3, "-target-features:\"sse2,aes\""); - print_usage_line(3, "-target-features:\"?\" for a list"); + print_usage_line(3, "-target-features:atomics"); + print_usage_line(3, "-target-features:\"sse2,aes\""); + print_usage_line(3, "-target-features:\"?\" for a list"); } } @@ -2745,11 +2922,11 @@ gb_internal void print_show_help(String const arg0, String command, String optio if (print_flag("-vet")) { print_usage_line(2, "Does extra checks on the code."); print_usage_line(2, "Extra checks include:"); - print_usage_line(3, "-vet-unused"); - print_usage_line(3, "-vet-unused-variables"); - print_usage_line(3, "-vet-unused-imports"); - print_usage_line(3, "-vet-shadowing"); - print_usage_line(3, "-vet-using-stmt"); + print_usage_line(3, "-vet-unused"); + print_usage_line(3, "-vet-unused-variables"); + print_usage_line(3, "-vet-unused-imports"); + print_usage_line(3, "-vet-shadowing"); + print_usage_line(3, "-vet-using-stmt"); } if (print_flag("-vet-cast")) { @@ -2816,6 +2993,40 @@ gb_internal void print_show_help(String const arg0, String command, String optio print_usage_line(2, "Treats warning messages as error messages."); } } + + if (bundle) { + print_usage_line(0, ""); + print_usage_line(1, "Android-specific flags"); + print_usage_line(0, ""); + if (print_flag("-android-keystore:")) { + print_usage_line(2, "Specifies the keystore file to use to sign the apk."); + } + + if (print_flag("-android-keystore-alias:")) { + print_usage_line(2, "Specifies the key alias to use when signing the apk"); + print_usage_line(2, "Can be omitted if the keystore only contains one key"); + } + + if (print_flag("-android-keystore-password:")) { + print_usage_line(2, "Sets the password to use to unlock the keystore"); + print_usage_line(2, "If this is omitted, the terminal will prompt you to provide it."); + } + } + + if (!help_resolved) { + usage(arg0); + print_usage_line(0, ""); + if (command == "help") { + print_usage_line(0, "'%.*s' is not a recognized flag.", LIT(optional_flag)); + } else { + print_usage_line(0, "'%.*s' is not a recognized command.", LIT(command)); + } + return 1; + } + + print_usage_line(0, ""); + + return 0; } gb_internal void print_show_unused(Checker *c) { @@ -2857,7 +3068,8 @@ gb_internal void print_show_unused(Checker *c) { if (e->token.string == "_") { continue; } - if (ptr_set_exists(&info->minimum_dependency_set, e)) { + + if (e->min_dep_count.load(std::memory_order_relaxed) > 0) { continue; } array_add(&unused, e); @@ -3188,6 +3400,16 @@ int main(int arg_count, char const **arg_ptr) { String run_args_string = {}; isize last_non_run_arg = args.count; + for_array(i, args) { + if (args[i] == "--") { + break; + } + if (args[i] == "-help" || args[i] == "--help") { + build_context.show_help = true; + return print_show_help(args[0], command); + } + } + bool run_output = false; if (command == "run" || command == "test") { if (args.count < 3) { @@ -3281,6 +3503,10 @@ int main(int arg_count, char const **arg_ptr) { return 1; #endif } else if (command == "version") { + if (args.count != 2) { + usage(args[0]); + return 1; + } build_context.command_kind = Command_version; gb_printf("%.*s version %.*s", LIT(args[0]), LIT(ODIN_VERSION)); @@ -3295,6 +3521,10 @@ int main(int arg_count, char const **arg_ptr) { gb_printf("\n"); return 0; } else if (command == "report") { + if (args.count != 2) { + usage(args[0]); + return 1; + } build_context.command_kind = Command_bug_report; print_bug_report_help(); return 0; @@ -3303,10 +3533,26 @@ int main(int arg_count, char const **arg_ptr) { usage(args[0]); return 1; } else { - print_show_help(args[0], args[1], args[2]); - return 0; + return print_show_help(args[0], args[1], args[2]); } + } else if (command == "bundle") { + if (args.count < 4) { + usage(args[0]); + return 1; + } + if (args[2] == "android") { + build_context.command_kind = Command_bundle_android; + } else { + gb_printf_err("Unknown package command: '%.*s'\n", LIT(args[2])); + usage(args[0]); + return 1; + } + init_filename = args[3]; } else if (command == "root") { + if (args.count != 2) { + usage(args[0]); + return 1; + } gb_printf("%.*s", LIT(odin_root_dir())); return 0; } else if (command == "clear-cache") { @@ -3322,11 +3568,6 @@ int main(int arg_count, char const **arg_ptr) { init_filename = copy_string(permanent_allocator(), init_filename); - if (init_filename == "-help" || - init_filename == "--help") { - build_context.show_help = true; - } - if (init_filename.len > 0 && !build_context.show_help) { // The command must be build, run, test, check, or another that takes a directory or filename. if (!path_is_directory(init_filename)) { @@ -3340,10 +3581,14 @@ int main(int arg_count, char const **arg_ptr) { } if (!single_file_package) { - gb_printf_err("ERROR: `%.*s %.*s` takes a package as its first argument.\n", LIT(args[0]), LIT(command)); + gb_printf_err("ERROR: `%.*s %.*s` takes a package/directory as its first argument.\n", LIT(args[0]), LIT(command)); if (init_filename == "-file") { gb_printf_err("Did you mean `%.*s %.*s -file`?\n", LIT(args[0]), LIT(command)); } else { + if (!gb_file_exists(cast(const char*)init_filename.text)) { + gb_printf_err("The file '%.*s' was not found.\n", LIT(init_filename)); + return 1; + } gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename)); } @@ -3373,8 +3618,11 @@ int main(int arg_count, char const **arg_ptr) { } if (build_context.show_help) { - print_show_help(args[0], command); - return 0; + return print_show_help(args[0], command); + } + + if (command == "bundle") { + return bundle(init_filename); } // NOTE(bill): add 'shared' directory if it is not already set @@ -3388,6 +3636,11 @@ int main(int arg_count, char const **arg_ptr) { // print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0])); // return 1; // } + + // Warn about Windows i386 thread-local storage limitations + if (build_context.metrics.arch == TargetArch_i386 && build_context.metrics.os == TargetOs_windows) { + gb_printf_err("Warning: Thread-local storage is disabled on Windows i386.\n"); + } // Check chosen microarchitecture. If not found or ?, print list. bool print_microarch_list = true; @@ -3716,6 +3969,21 @@ end_of_code_gen:; defer (gb_free(heap_allocator(), exe_name.text)); system_must_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string)); + + if (!build_context.keep_executable) { + char const *filename = cast(char const *)exe_name.text; + gb_file_remove(filename); + + if (build_context.ODIN_DEBUG) { + if (build_context.metrics.os == TargetOs_windows || build_context.metrics.os == TargetOs_darwin) { + String symbol_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Symbols]); + defer (gb_free(heap_allocator(), symbol_path.text)); + + filename = cast(char const *)symbol_path.text; + gb_file_remove(filename); + } + } + } } return 0; } diff --git a/src/microsoft_craziness.h b/src/microsoft_craziness.h index b0fd22a23..933607a2a 100644 --- a/src/microsoft_craziness.h +++ b/src/microsoft_craziness.h @@ -59,7 +59,7 @@ struct Find_Result { }; gb_internal String mc_wstring_to_string(wchar_t const *str) { - return string16_to_string(mc_allocator, make_string16_c(str)); + return string16_to_string(mc_allocator, make_string16_c(cast(u16 *)str)); } gb_internal String16 mc_string_to_wstring(String str) { @@ -103,7 +103,7 @@ gb_internal HANDLE mc_find_first(String wildcard, MC_Find_Data *find_data) { String16 wildcard_wide = mc_string_to_wstring(wildcard); defer (mc_free(wildcard_wide)); - HANDLE handle = FindFirstFileW(wildcard_wide.text, &_find_data); + HANDLE handle = FindFirstFileW(cast(wchar_t *)wildcard_wide.text, &_find_data); if (handle == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; find_data->file_attributes = _find_data.dwFileAttributes; diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index a80dc1996..8bacfabc6 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -1,3 +1,5 @@ +gb_internal bool is_in_doc_writer(void); + gb_internal GB_COMPARE_PROC(type_info_pair_cmp) { TypeInfoPair *x = cast(TypeInfoPair *)a; TypeInfoPair *y = cast(TypeInfoPair *)b; @@ -55,10 +57,13 @@ gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) { usize mask = s->capacity-1; usize hash_index = cast(usize)hash & mask; for (usize i = 0; i < s->capacity; i++) { - Type *key = s->keys[hash_index].type; - if (are_types_identical_unique_tuples(key, pair.type)) { + auto *e = &s->keys[hash_index]; + u64 hash = e->hash; + Type *key = e->type; + if (hash == pair.hash && + are_types_identical_unique_tuples(key, pair.type)) { return hash_index; - } else if (key == 0) { + } else if (key == nullptr) { return -1; } hash_index = (hash_index+1)&mask; @@ -162,6 +167,48 @@ gb_internal bool type_set_update(TypeSet *s, Type *ptr) { // returns true if it return type_set_update(s, pair); } +gb_internal bool type_set_update_with_mutex(TypeSet *s, TypeInfoPair pair, RWSpinLock *m) { // returns true if it previously existsed + rwlock_acquire_upgrade(m); + if (type_set_exists(s, pair)) { + rwlock_release_upgrade(m); + return true; + } + + rwlock_release_upgrade_and_acquire_write(m); + defer (rwlock_release_write(m)); + + if (s->keys == nullptr) { + type_set_init(s); + } else if (type_set__full(s)) { + type_set_grow(s); + } + GB_ASSERT(s->count < s->capacity); + GB_ASSERT(s->capacity >= 0); + + usize mask = s->capacity-1; + usize hash = cast(usize)pair.hash; + usize hash_index = (cast(usize)hash) & mask; + GB_ASSERT(hash_index < s->capacity); + for (usize i = 0; i < s->capacity; i++) { + TypeInfoPair *key = &s->keys[hash_index]; + GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type)); + if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) { + *key = pair; + s->count++; + return false; + } + hash_index = (hash_index+1)&mask; + } + + GB_PANIC("ptr set out of memory"); + return false; +} + +gb_internal bool type_set_update_with_mutex(TypeSet *s, Type *ptr, RWSpinLock *m) { // returns true if it previously existsed + TypeInfoPair pair = {ptr, type_hash_canonical_type(ptr)}; + return type_set_update_with_mutex(s, pair, m); +} + gb_internal Type *type_set_add(TypeSet *s, Type *ptr) { type_set_update(s, ptr); @@ -284,6 +331,23 @@ gb_internal void write_canonical_params(TypeWriter *w, Type *params) { } else { write_type_to_canonical_string(w, v->type); } + if (is_in_doc_writer()) { + // NOTE(bill): This just exists to make sure the entities default values exist when + // writing to the odin doc format + Ast *expr = v->Variable.init_expr; + if (expr == nullptr) { + expr = v->Variable.param_value.original_ast_expr; + } + if (expr != nullptr) { + type_writer_appendc(w, "="); + gbString s = write_expr_to_string( // Minor leak + gb_string_make(temporary_allocator(), ""), + expr, + build_context.cmd_doc_flags & CmdDocFlag_Short + ); + type_writer_append(w, s, gb_string_length(s)); + } + } break; case Entity_TypeName: type_writer_appendc(w, CANONICAL_PARAM_TYPEID); @@ -309,12 +373,20 @@ gb_internal u64 type_hash_canonical_type(Type *type) { if (type == nullptr) { return 0; } + u64 prev_hash = type->canonical_hash.load(std::memory_order_relaxed); + if (prev_hash != 0) { + return prev_hash; + } + u64 hash = fnv64a(nullptr, 0); TypeWriter w = {}; type_writer_make_hasher(&w, &hash); write_type_to_canonical_string(&w, type); + hash = hash ? hash : 1; - return hash ? hash : 1; + type->canonical_hash.store(hash, std::memory_order_relaxed); + + return hash; } gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) { @@ -486,7 +558,13 @@ write_base_name: Type *params = nullptr; Entity *parent = type_get_polymorphic_parent(e->type, ¶ms); - if (parent && (parent->token.string == e->token.string)) { + if (parent && (e->token.string == parent->token.string)) { + // Check for `distinct` forms + type_writer_append(w, parent->token.string.text, parent->token.string.len); + write_canonical_params(w, params); + } else if (parent && string_starts_with(e->token.string, parent->token.string) && + string_contains_char(e->token.string, '(')) { + // Check for named specialization forms type_writer_append(w, parent->token.string.text, parent->token.string.len); write_canonical_params(w, params); } else { @@ -520,7 +598,6 @@ write_base_name: return; } -gb_internal bool is_in_doc_writer(void); // NOTE(bill): This exists so that we deterministically hash a type by serializing it to a canonical string gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { @@ -631,6 +708,10 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { case Type_Union: type_writer_appendc(w, "union"); + if (is_in_doc_writer() && type->Union.polymorphic_params) { + write_canonical_params(w, type->Union.polymorphic_params); + } + switch (type->Union.kind) { case UnionType_no_nil: type_writer_appendc(w, "#no_nil"); break; case UnionType_shared_nil: type_writer_appendc(w, "#shared_nil"); break; @@ -658,9 +739,13 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { } type_writer_appendc(w, "struct"); + + if (is_in_doc_writer() && type->Struct.polymorphic_params) { + write_canonical_params(w, type->Struct.polymorphic_params); + } + if (type->Struct.is_packed) type_writer_appendc(w, "#packed"); if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union"); - if (type->Struct.is_no_copy) type_writer_appendc(w, "#no_copy"); if (type->Struct.custom_min_field_align != 0) type_writer_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align); if (type->Struct.custom_max_field_align != 0) type_writer_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align); if (type->Struct.custom_align != 0) type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align); @@ -724,16 +809,23 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { if (is_in_doc_writer()) { type_writer_appendc(w, "$"); type_writer_append(w, type->Generic.name.text, type->Generic.name.len); - type_writer_append_fmt(w, "%lld", cast(long long)type->Generic.id); + type_writer_append_fmt(w, "-%lld", cast(long long)type->Generic.id); + if (type->Generic.specialized) { + type_writer_appendc(w, "/"); + write_type_to_canonical_string(w, type->Generic.specialized); + } + } else if (type->Generic.specialized) { + // If we have a specialized type, use that instead of panicking + write_type_to_canonical_string(w, type->Generic.specialized); } else { - GB_PANIC("Type_Generic should never be hit"); + // For unspecialized generics, use a generic placeholder string + type_writer_appendc(w, "rawptr"); } return; case Type_Named: if (type->Named.type_name != nullptr) { write_canonical_entity_name(w, type->Named.type_name); - return; } else { type_writer_append(w, type->Named.name.text, type->Named.name.len); } diff --git a/src/name_canonicalization.hpp b/src/name_canonicalization.hpp index 304aff42e..00b450fbe 100644 --- a/src/name_canonicalization.hpp +++ b/src/name_canonicalization.hpp @@ -102,6 +102,8 @@ gb_internal Type *type_set_add (TypeSet *s, Type *ptr); gb_internal Type *type_set_add (TypeSet *s, TypeInfoPair pair); gb_internal bool type_set_update (TypeSet *s, Type *ptr); // returns true if it previously existed gb_internal bool type_set_update (TypeSet *s, TypeInfoPair pair); // returns true if it previously existed +gb_internal bool type_set_update_with_mutex(TypeSet *s, TypeInfoPair pair, RWSpinLock *m); +gb_internal bool type_set_update_with_mutex(TypeSet *s, Type *ptr, RWSpinLock *m); gb_internal bool type_set_exists (TypeSet *s, Type *ptr); gb_internal void type_set_remove (TypeSet *s, Type *ptr); gb_internal void type_set_clear (TypeSet *s); diff --git a/src/parser.cpp b/src/parser.cpp index f38f79607..363eb0c55 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,5 +1,7 @@ #include "parser_pos.cpp" +gb_global std::atomic g_parsing_done; + gb_internal bool in_vet_packages(AstFile *file) { if (file == nullptr) { return true; @@ -33,6 +35,10 @@ gb_internal bool ast_file_vet_deprecated(AstFile *f) { return (ast_file_vet_flags(f) & VetFlag_Deprecated) != 0; } +gb_internal bool ast_file_vet_explicit_allocators(AstFile *f) { + return (ast_file_vet_flags(f) & VetFlag_ExplicitAllocators) != 0; +} + gb_internal bool file_allow_newline(AstFile *f) { bool is_strict = build_context.strict_style || ast_file_vet_style(f); return !is_strict; @@ -172,7 +178,11 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { return nullptr; } if (f == nullptr) { - f = node->thread_safe_file(); + if (g_parsing_done.load(std::memory_order_relaxed)) { + f = node->file(); + } else { + f = node->thread_safe_file(); + } } Ast *n = alloc_ast_node(f, node->kind); gb_memmove(n, node, ast_node_size(node->kind)); @@ -740,6 +750,7 @@ gb_internal Ast *ast_matrix_index_expr(AstFile *f, Ast *expr, Token open, Token gb_internal Ast *ast_ident(AstFile *f, Token token) { Ast *result = alloc_ast_node(f, Ast_Ident); result->Ident.token = token; + result->Ident.hash = string_hash(token.string); return result; } @@ -1436,27 +1447,30 @@ gb_internal CommentGroup *consume_comment_group(AstFile *f, isize n, isize *end_ } gb_internal void consume_comment_groups(AstFile *f, Token prev) { - if (f->curr_token.kind == Token_Comment) { - CommentGroup *comment = nullptr; - isize end_line = 0; - - if (f->curr_token.pos.line == prev.pos.line) { - comment = consume_comment_group(f, 0, &end_line); - if (f->curr_token.pos.line != end_line || f->curr_token.kind == Token_EOF) { - f->line_comment = comment; - } - } - - end_line = -1; - while (f->curr_token.kind == Token_Comment) { - comment = consume_comment_group(f, 1, &end_line); - } - if (end_line+1 == f->curr_token.pos.line || end_line < 0) { - f->lead_comment = comment; - } - - GB_ASSERT(f->curr_token.kind != Token_Comment); + if (f->curr_token.kind != Token_Comment) { + return; } + CommentGroup *comment = nullptr; + isize end_line = 0; + + if (f->curr_token.pos.line == prev.pos.line) { + comment = consume_comment_group(f, 0, &end_line); + if (f->curr_token.pos.line != end_line || + f->curr_token.pos.line == prev.pos.line+1 || + f->curr_token.kind == Token_EOF) { + f->line_comment = comment; + } + } + + end_line = -1; + while (f->curr_token.kind == Token_Comment) { + comment = consume_comment_group(f, 1, &end_line); + } + if (end_line+1 == f->curr_token.pos.line || end_line < 0) { + f->lead_comment = comment; + } + + GB_ASSERT(f->curr_token.kind != Token_Comment); } gb_internal gb_inline bool ignore_newlines(AstFile *f) { @@ -3274,6 +3288,8 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) { case Token_OpenBracket: { bool prev_allow_range = f->allow_range; f->allow_range = false; + defer (f->allow_range = prev_allow_range); + Token open = {}, close = {}, interval = {}; Ast *indices[2] = {}; @@ -3282,6 +3298,13 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) { f->expr_level++; open = expect_token(f, Token_OpenBracket); + if (f->curr_token.kind == Token_CloseBracket) { + error(f->curr_token, "Expected an operand, got ]"); + close = expect_token(f, Token_CloseBracket); + operand = ast_index_expr(f, operand, nullptr, open, close); + break; + } + switch (f->curr_token.kind) { case Token_Ellipsis: case Token_RangeFull: @@ -3331,7 +3354,6 @@ gb_internal Ast *parse_atom_expr(AstFile *f, Ast *operand, bool lhs) { operand = ast_index_expr(f, operand, indices[0], open, close); } - f->allow_range = prev_allow_range; } break; case Token_Pointer: // Deference @@ -5786,7 +5808,7 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const for (FileInfo fi : list) { String name = fi.name; String ext = path_extension(name); - if (ext == FILE_EXT) { + if (ext == FILE_EXT && !fi.is_dir) { files_with_ext += 1; } if (ext == FILE_EXT && !is_excluded_target_filename(name)) { @@ -5811,7 +5833,7 @@ gb_internal AstPackage *try_add_import_path(Parser *p, String path, String const for (FileInfo fi : list) { String name = fi.name; String ext = path_extension(name); - if (ext == FILE_EXT) { + if (ext == FILE_EXT && !fi.is_dir) { if (is_excluded_target_filename(name)) { continue; } @@ -6157,7 +6179,7 @@ gb_internal String build_tag_get_token(String s, String *out) { isize width = utf8_decode(&s[n], s.len-n, &rune); if (n == 0 && rune == '!') { - } else if (!rune_is_letter(rune) && !rune_is_digit(rune)) { + } else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != ':') { isize k = gb_max(gb_max(n, width), 1); *out = substring(s, k, s.len); return substring(s, 0, k); @@ -6209,7 +6231,10 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) { continue; } - TargetOsKind os = get_target_os_from_string(p); + Subtarget subtarget = Subtarget_Invalid; + String subtarget_str = {}; + + TargetOsKind os = get_target_os_from_string(p, &subtarget, &subtarget_str); TargetArchKind arch = get_target_arch_from_string(p); num_tokens += 1; @@ -6220,14 +6245,35 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) { break; } + bool is_ios_subtarget = false; + if (subtarget == Subtarget_Invalid) { + // Special case for pseudo subtarget + if (!str_eq_ignore_case(subtarget_str, "ios")) { + syntax_error(token_for_pos, "Invalid subtarget '%.*s'.", LIT(subtarget_str)); + break; + } + + is_ios_subtarget = true; + } + + if (os != TargetOs_Invalid) { this_kind_os_seen = true; + // NOTE: Only testing for 'default' and not 'generic' because the 'generic' nomenclature implies any subtarget. + bool is_explicit_default_subtarget = str_eq_ignore_case(subtarget_str, "default"); + bool same_subtarget = (subtarget == Subtarget_Default && !is_explicit_default_subtarget) || (subtarget == selected_subtarget); + + // Special case for iPhone or iPhoneSimulator + if (is_ios_subtarget && (selected_subtarget == Subtarget_iPhone || selected_subtarget == Subtarget_iPhoneSimulator)) { + same_subtarget = true; + } + GB_ASSERT(arch == TargetArch_Invalid); if (is_notted) { - this_kind_correct = this_kind_correct && (os != build_context.metrics.os); + this_kind_correct = this_kind_correct && (os != build_context.metrics.os || !same_subtarget); } else { - this_kind_correct = this_kind_correct && (os == build_context.metrics.os); + this_kind_correct = this_kind_correct && (os == build_context.metrics.os && same_subtarget); } } else if (arch != TargetArch_Invalid) { this_kind_arch_seen = true; @@ -6250,7 +6296,7 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) { return any_correct; } -gb_internal String vet_tag_get_token(String s, String *out) { +gb_internal String vet_tag_get_token(String s, String *out, bool allow_colon) { s = string_trim_whitespace(s); isize n = 0; while (n < s.len) { @@ -6258,7 +6304,7 @@ gb_internal String vet_tag_get_token(String s, String *out) { isize width = utf8_decode(&s[n], s.len-n, &rune); if (n == 0 && rune == '!') { - } else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != '-') { + } else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != '-' && !(allow_colon && rune == ':')) { isize k = gb_max(gb_max(n, width), 1); *out = substring(s, k, s.len); return substring(s, 0, k); @@ -6284,7 +6330,7 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { u64 vet_not_flags = 0; while (s.len > 0) { - String p = string_trim_whitespace(vet_tag_get_token(s, &s)); + String p = string_trim_whitespace(vet_tag_get_token(s, &s, /*allow_colon*/false)); if (p.len == 0) { break; } @@ -6321,6 +6367,7 @@ gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { error_line("\textra\n"); error_line("\tcast\n"); error_line("\ttabs\n"); + error_line("\texplicit-allocators\n"); return build_context.vet_flags; } } @@ -6351,7 +6398,7 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { u64 feature_not_flags = 0; while (s.len > 0) { - String p = string_trim_whitespace(vet_tag_get_token(s, &s)); + String p = string_trim_whitespace(vet_tag_get_token(s, &s, /*allow_colon*/true)); if (p.len == 0) { break; } @@ -6373,26 +6420,45 @@ gb_internal u64 parse_feature_tag(Token token_for_pos, String s) { } else { feature_flags |= flag; } + if (is_notted) { + switch (flag) { + case OptInFeatureFlag_IntegerDivisionByZero_Trap: + case OptInFeatureFlag_IntegerDivisionByZero_Zero: + syntax_error(token_for_pos, "Feature flag does not support notting with '!' - '%.*s'", LIT(p)); + break; + } + } } else { ERROR_BLOCK(); syntax_error(token_for_pos, "Invalid feature flag name: %.*s", LIT(p)); error_line("\tExpected one of the following\n"); error_line("\tdynamic-literals\n"); + error_line("\tinteger-division-by-zero:trap\n"); + error_line("\tinteger-division-by-zero:zero\n"); + error_line("\tinteger-division-by-zero:self\n"); return OptInFeatureFlag_NONE; } } + u64 res = OptInFeatureFlag_NONE; + if (feature_flags == 0 && feature_not_flags == 0) { - return OptInFeatureFlag_NONE; + res = OptInFeatureFlag_NONE; + } else if (feature_flags == 0 && feature_not_flags != 0) { + res = OptInFeatureFlag_NONE &~ feature_not_flags; + } else if (feature_flags != 0 && feature_not_flags == 0) { + res = feature_flags; + } else { + GB_ASSERT(feature_flags != 0 && feature_not_flags != 0); + res = feature_flags &~ feature_not_flags; } - if (feature_flags == 0 && feature_not_flags != 0) { - return OptInFeatureFlag_NONE &~ feature_not_flags; + + u64 idbz_count = gb_count_set_bits(res & OptInFeatureFlag_IntegerDivisionByZero_ALL); + if (idbz_count > 1) { + syntax_error(token_for_pos, "Only one integer-division-by-zero feature flag can be enabled"); } - if (feature_flags != 0 && feature_not_flags == 0) { - return feature_flags; - } - GB_ASSERT(feature_flags != 0 && feature_not_flags != 0); - return feature_flags &~ feature_not_flags; + + return res; } gb_internal String dir_from_path(String path) { @@ -6495,6 +6561,10 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) } else if (string_starts_with(lc, str_lit("vet"))) { f->vet_flags = parse_vet_tag(tok, lc); f->vet_flags_set = true; + } else if (string_starts_with(lc, str_lit("test"))) { + if ((build_context.command_kind & Command_test) == 0) { + return false; + } } else if (string_starts_with(lc, str_lit("ignore"))) { return false; } else if (string_starts_with(lc, str_lit("private"))) { @@ -6865,6 +6935,8 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) { } } + g_parsing_done.store(true, std::memory_order_relaxed); + return ParseFile_None; } diff --git a/src/parser.hpp b/src/parser.hpp index d2dd22667..6127468d4 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -27,10 +27,29 @@ enum AddressingMode : u8 { Addressing_SwizzleVariable = 14, // Swizzle indexed variable }; +gb_global String const addressing_mode_strings[] = { + str_lit("Invalid"), + str_lit("NoValue"), + str_lit("Value"), + str_lit("Context"), + str_lit("Variable"), + str_lit("Constant"), + str_lit("Type"), + str_lit("Builtin"), + str_lit("ProcGroup"), + str_lit("MapIndex"), + str_lit("OptionalOk"), + str_lit("OptionalOkPtr"), + str_lit("SoaVariable"), + str_lit("SwizzleValue"), + str_lit("SwizzleVariable"), +}; + struct TypeAndValue { Type * type; AddressingMode mode; - bool is_lhs; // Debug info + bool is_lhs; // Debug info + Type * objc_super_target; // Original type of the Obj-C object before being converted to the superclass' type by the objc_super() intrinsic. ExactValue value; }; @@ -396,6 +415,7 @@ struct AstSplitArgs { AST_KIND(Ident, "identifier", struct { \ Token token; \ Entity *entity; \ + u32 hash; \ }) \ AST_KIND(Implicit, "implicit", Token) \ AST_KIND(Uninit, "uninitialized value", Token) \ diff --git a/src/path.cpp b/src/path.cpp index 2c08ddd98..2b97a04df 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -30,28 +30,80 @@ gb_internal String remove_directory_from_path(String const &s) { } -// NOTE(Mark Naughton): getcwd as String -#if !defined(GB_SYSTEM_WINDOWS) -gb_internal String get_current_directory(void) { - char cwd[256]; - getcwd(cwd, 256); +#if defined(GB_SYSTEM_WINDOWS) +gb_global SRWLOCK cwd_lock; - return make_string_c(cwd); +String get_working_directory(gbAllocator allocator) { + AcquireSRWLockExclusive(&cwd_lock); + + TEMPORARY_ALLOCATOR_GUARD(); + + DWORD sz_utf16 = GetCurrentDirectoryW(0, nullptr); + wchar_t *dir_buf_wstr = gb_alloc_array(temporary_allocator(), wchar_t, sz_utf16); + if (dir_buf_wstr == nullptr) { + ReleaseSRWLockExclusive(&cwd_lock); + return {}; + } + + DWORD n = GetCurrentDirectoryW(sz_utf16, dir_buf_wstr); + GB_ASSERT(n+1 == sz_utf16); + ReleaseSRWLockExclusive(&cwd_lock); + + + isize buf_len = sz_utf16*4; + u8 *buf = gb_alloc_array(allocator, u8, buf_len); + gb_ucs2_to_utf8(buf, buf_len, cast(u16 *)dir_buf_wstr); + + return make_string_c(cast(char const *)buf); +} + +bool set_working_directory(String dir) { + bool ok = false; + TEMPORARY_ALLOCATOR_GUARD(); + + char const *cdir = alloc_cstring(temporary_allocator(), dir); + wchar_t *wstr = gb__alloc_utf8_to_ucs2(temporary_allocator(), cdir, nullptr); + + AcquireSRWLockExclusive(&cwd_lock); + + ok = SetCurrentDirectoryW(wstr); + + ReleaseSRWLockExclusive(&cwd_lock); + + return ok; } #else -gb_internal String get_current_directory(void) { - gbAllocator a = heap_allocator(); - wchar_t cwd[256]; - GetCurrentDirectoryW(256, cwd); +String get_working_directory(gbAllocator allocator) { + TEMPORARY_ALLOCATOR_GUARD(); - String16 wstr = make_string16_c(cwd); + auto buf = array_make(temporary_allocator()); + size_t size = PATH_MAX; - return string16_to_string(a, wstr); + char const *cwd = nullptr; + for (; cwd == nullptr; size *= 2) { + array_resize(&buf, size); + + cwd = getcwd(buf.data, buf.count); + if (cwd == nullptr && errno != ERANGE) { + return {}; + } + } + + return copy_string(allocator, make_string_c(cwd)); } + +bool set_working_directory(String dir) { + TEMPORARY_ALLOCATOR_GUARD(); + char const *cdir = alloc_cstring(temporary_allocator(), dir); + return !chdir(cdir); +} + #endif + + gb_internal bool path_is_directory(String path); gb_internal String directory_from_path(String const &s) { @@ -78,7 +130,7 @@ gb_internal String directory_from_path(String const &s) { String16 wstr = string_to_string16(a, path); defer (gb_free(a, wstr.text)); - i32 attribs = GetFileAttributesW(wstr.text); + i32 attribs = GetFileAttributesW(cast(wchar_t *)wstr.text); if (attribs < 0) return false; return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; @@ -308,7 +360,7 @@ gb_internal ReadDirectoryError read_directory(String path, Array *fi) defer (gb_free(a, wstr.text)); WIN32_FIND_DATAW file_data = {}; - HANDLE find_file = FindFirstFileW(wstr.text, &file_data); + HANDLE find_file = FindFirstFileW(cast(wchar_t *)wstr.text, &file_data); if (find_file == INVALID_HANDLE_VALUE) { return ReadDirectory_Unknown; } @@ -320,7 +372,7 @@ gb_internal ReadDirectoryError read_directory(String path, Array *fi) wchar_t *filename_w = file_data.cFileName; u64 size = cast(u64)file_data.nFileSizeLow; size |= (cast(u64)file_data.nFileSizeHigh) << 32; - String name = string16_to_string(a, make_string16_c(filename_w)); + String name = string16_to_string(a, make_string16_c(cast(u16 *)filename_w)); if (name == "." || name == "..") { gb_free(a, name.text); continue; @@ -442,7 +494,7 @@ gb_internal bool write_directory(String path) { #else gb_internal bool write_directory(String path) { String16 wstr = string_to_string16(heap_allocator(), path); - LPCWSTR wdirectory_name = wstr.text; + LPCWSTR wdirectory_name = cast(wchar_t *)wstr.text; HANDLE directory = CreateFileW(wdirectory_name, GENERIC_WRITE, diff --git a/src/ptr_map.cpp b/src/ptr_map.cpp index 1c157c386..61f703cf1 100644 --- a/src/ptr_map.cpp +++ b/src/ptr_map.cpp @@ -15,7 +15,7 @@ static void *const MAP_TOMBSTONE = (void *)~(uintptr)0; template struct PtrMapEntry { static_assert(sizeof(K) == sizeof(void *), "Key size must be pointer size"); - + K key; V value; }; @@ -374,7 +374,7 @@ struct PtrMapIterator { } bool operator==(PtrMapIterator const &other) const noexcept { - return this->map == other->map && this->index == other->index; + return this->map == other.map && this->index == other.index; } operator PtrMapEntry *() const { @@ -858,4 +858,4 @@ gb_internal OrderedInsertPtrMapEntry *end(OrderedInsertPtrMap &m) { template gb_internal OrderedInsertPtrMapEntry const *end(OrderedInsertPtrMap const &m) { return m.entries + m.count; -} \ No newline at end of file +} diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index 5097e2bb6..5b1d2cc19 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -16,6 +16,8 @@ template gb_internal bool ptr_set_exists (PtrSet *s, T ptr); template gb_internal void ptr_set_remove (PtrSet *s, T ptr); template gb_internal void ptr_set_clear (PtrSet *s); +#define FOR_PTR_SET(element, set_) for (auto *it = &(set_).keys[0], element = it ? *it : nullptr; (set_).keys != nullptr && it < &(set_).keys[(set_).capacity]; it++) if (element = *it, (*it != nullptr && *it != cast(void *)~(uintptr)(0ull))) + gb_internal gbAllocator ptr_set_allocator(void) { return heap_allocator(); } @@ -83,7 +85,7 @@ gb_internal gb_inline void ptr_set_grow(PtrSet *old_set) { PtrSet new_set = {}; ptr_set_init(&new_set, gb_max(old_set->capacity<<1, 16)); - for (T ptr : *old_set) { + FOR_PTR_SET(ptr, *old_set) { bool was_new = ptr_set_update(&new_set, ptr); GB_ASSERT(!was_new); } @@ -134,6 +136,44 @@ gb_internal bool ptr_set_update(PtrSet *s, T ptr) { // returns true if it pre return false; } +template +gb_internal bool ptr_set_update_with_mutex(PtrSet *s, T ptr, RWSpinLock *m) { // returns true if it previously existsed + rwlock_acquire_upgrade(m); + if (ptr_set_exists(s, ptr)) { + rwlock_release_upgrade(m); + return true; + } + + rwlock_release_upgrade_and_acquire_write(m); + defer (rwlock_release_write(m)); + + if (s->keys == nullptr) { + ptr_set_init(s); + } else if (ptr_set__full(s)) { + ptr_set_grow(s); + } + GB_ASSERT(s->count < s->capacity); + GB_ASSERT(s->capacity >= 0); + + usize mask = s->capacity-1; + u32 hash = ptr_map_hash_key(ptr); + usize hash_index = (cast(usize)hash) & mask; + GB_ASSERT(hash_index < s->capacity); + for (usize i = 0; i < s->capacity; i++) { + T *key = &s->keys[hash_index]; + GB_ASSERT(*key != ptr); + if (*key == (T)PtrSet::TOMBSTONE || *key == 0) { + *key = ptr; + s->count++; + return false; + } + hash_index = (hash_index+1)&mask; + } + + GB_PANIC("ptr set out of memory"); + return false; +} + template gb_internal T ptr_set_add(PtrSet *s, T ptr) { ptr_set_update(s, ptr); @@ -157,7 +197,7 @@ gb_internal gb_inline void ptr_set_clear(PtrSet *s) { gb_zero_size(s->keys, s->capacity*gb_size_of(T)); } -template +/*template struct PtrSetIterator { PtrSet *set; usize index; @@ -201,4 +241,6 @@ gb_internal PtrSetIterator begin(PtrSet &set) noexcept { template gb_internal PtrSetIterator end(PtrSet &set) noexcept { return PtrSetIterator{&set, set.capacity}; -} \ No newline at end of file +}*/ + + diff --git a/src/queue.cpp b/src/queue.cpp index dee9ad1f8..82f82f3e1 100644 --- a/src/queue.cpp +++ b/src/queue.cpp @@ -36,7 +36,8 @@ gb_internal void mpsc_destroy(MPSCQueue *q) { template gb_internal MPSCNode *mpsc_alloc_node(MPSCQueue *q, T const &value) { - auto new_node = gb_alloc_item(heap_allocator(), MPSCNode); + // auto new_node = gb_alloc_item(heap_allocator(), MPSCNode); + auto new_node = gb_alloc_item(permanent_allocator(), MPSCNode); new_node->value = value; return new_node; } diff --git a/src/string.cpp b/src/string.cpp index b001adf0e..9c08114a7 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -26,15 +26,14 @@ struct String_Iterator { // NOTE(bill): String16 is only used for Windows due to its file directories struct String16 { - wchar_t *text; - isize len; - wchar_t const &operator[](isize i) const { + u16 * text; + isize len; + u16 const &operator[](isize i) const { GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i); return text[i]; } }; - gb_internal gb_inline String make_string(u8 const *text, isize len) { String s; s.text = cast(u8 *)text; @@ -45,19 +44,19 @@ gb_internal gb_inline String make_string(u8 const *text, isize len) { return s; } - -gb_internal gb_inline String16 make_string16(wchar_t const *text, isize len) { +gb_internal gb_inline String16 make_string16(u16 const *text, isize len) { String16 s; - s.text = cast(wchar_t *)text; + s.text = cast(u16 *)text; s.len = len; return s; } -gb_internal isize string16_len(wchar_t const *s) { + +gb_internal isize string16_len(u16 const *s) { if (s == nullptr) { return 0; } - wchar_t const *p = s; + u16 const *p = s; while (*p) { p++; } @@ -69,7 +68,7 @@ gb_internal gb_inline String make_string_c(char const *text) { return make_string(cast(u8 *)cast(void *)text, gb_strlen(text)); } -gb_internal gb_inline String16 make_string16_c(wchar_t const *text) { +gb_internal gb_inline String16 make_string16_c(u16 const *text) { return make_string16(text, string16_len(text)); } @@ -80,6 +79,13 @@ gb_internal String substring(String const &s, isize lo, isize hi) { return make_string(s.text+lo, hi-lo); } +gb_internal String16 substring(String16 const &s, isize lo, isize hi) { + isize max = s.len; + GB_ASSERT_MSG(lo <= hi && hi <= max, "%td..%td..%td", lo, hi, max); + + return make_string16(s.text+lo, hi-lo); +} + gb_internal char *alloc_cstring(gbAllocator a, String s) { char *c_str = gb_alloc_array(a, char, s.len+1); @@ -145,6 +151,27 @@ gb_internal int string_compare(String const &a, String const &b) { return res; } + +gb_internal int string16_compare(String16 const &a, String16 const &b) { + if (a.text == b.text) { + return cast(int)(a.len - b.len); + } + if (a.text == nullptr) { + return -1; + } + if (b.text == nullptr) { + return +1; + } + + uintptr n = gb_min(a.len, b.len); + int res = memcmp(a.text, b.text, n*gb_size_of(u16)); + if (res == 0) { + res = cast(int)(a.len - b.len); + } + return res; +} + + gb_internal isize string_index_byte(String const &s, u8 x) { for (isize i = 0; i < s.len; i++) { if (s.text[i] == x) { @@ -182,6 +209,26 @@ template gb_internal bool operator >= (String const &a, char const (&b template <> bool operator == (String const &a, char const (&b)[1]) { return a.len == 0; } template <> bool operator != (String const &a, char const (&b)[1]) { return a.len != 0; } + +gb_internal gb_inline bool str_eq(String16 const &a, String16 const &b) { + if (a.len != b.len) return false; + if (a.len == 0) return true; + return memcmp(a.text, b.text, a.len) == 0; +} +gb_internal gb_inline bool str_ne(String16 const &a, String16 const &b) { return !str_eq(a, b); } +gb_internal gb_inline bool str_lt(String16 const &a, String16 const &b) { return string16_compare(a, b) < 0; } +gb_internal gb_inline bool str_gt(String16 const &a, String16 const &b) { return string16_compare(a, b) > 0; } +gb_internal gb_inline bool str_le(String16 const &a, String16 const &b) { return string16_compare(a, b) <= 0; } +gb_internal gb_inline bool str_ge(String16 const &a, String16 const &b) { return string16_compare(a, b) >= 0; } + +gb_internal gb_inline bool operator == (String16 const &a, String16 const &b) { return str_eq(a, b); } +gb_internal gb_inline bool operator != (String16 const &a, String16 const &b) { return str_ne(a, b); } +gb_internal gb_inline bool operator < (String16 const &a, String16 const &b) { return str_lt(a, b); } +gb_internal gb_inline bool operator > (String16 const &a, String16 const &b) { return str_gt(a, b); } +gb_internal gb_inline bool operator <= (String16 const &a, String16 const &b) { return str_le(a, b); } +gb_internal gb_inline bool operator >= (String16 const &a, String16 const &b) { return str_ge(a, b); } + + gb_internal gb_inline bool string_starts_with(String const &s, String const &prefix) { if (prefix.len > s.len) { return false; @@ -273,6 +320,15 @@ gb_internal String path_extension(String const &str, bool include_dot = true) { return substring(str, include_dot ? pos : pos + 1, str.len); } + +gb_internal String path_remove_extension(String const &str) { + isize pos = string_extension_position(str); + if (pos < 0) { + return str; + } + return substring(str, 0, pos); +} + gb_internal String string_trim_whitespace(String str) { while (str.len > 0 && rune_is_whitespace(str[str.len-1])) { str.len--; @@ -327,6 +383,83 @@ gb_internal Array split_lines_from_array(Array const &array, gbAlloc return lines; } +enum : u32 { PRIME_RABIN_KARP = 16777619u }; + +gb_internal u32 hash_str_rabin_karp(String const &s, u32 *pow_) { + u32 hash = 0; + u32 pow = 1; + for (isize i = 0; i < s.len; i++) { + hash = hash*PRIME_RABIN_KARP + cast(u32)s.text[i]; + } + u32 sq = PRIME_RABIN_KARP; + for (isize i = s.len; i > 0; i >>= 1) { + if ((i & 1) != 0) { + pow *= sq; + } + sq *= sq; + } + if (pow_) *pow_ = pow; + return hash; + +} + + +gb_internal isize string_index(String const &s, String const &substr) { + isize n = substr.len; + if (n == 0) { + return 0; + } else if (n == 1) { + return string_index_byte(s, substr[0]); + } else if (n == s.len) { + if (s == substr) { + return 0; + } + return -1; + } else if (n > s.len) { + return -1; + } + u32 pow = 1; + u32 hash = hash_str_rabin_karp(s, &pow); + u32 h = 0; + for (isize i = 0; i < n; i++) { + h = h*PRIME_RABIN_KARP + cast(u32)s.text[i]; + } + if (h == hash && substring(s, 0, n) == substr) { + return 0; + } + for (isize i = n; i < s.len; /**/) { + h *= PRIME_RABIN_KARP; + h += cast(u32)s.text[i]; + h -= pow * u32(s.text[i-n]); + i += 1; + if (h == hash && substring(s, i-n, i) == substr) { + return i - n; + } + } + return -1; +} + + +struct StringPartition { + String head; + String match; + String tail; +}; + +gb_internal StringPartition string_partition(String const &str, String const &sep) { + StringPartition res = {}; + isize i = string_index(str, sep); + if (i < 0) { + res.head = str; + return res; + } + + res.head = substring(str, 0, i); + res.match = substring(str, i, i+sep.len); + res.tail = substring(str, i+sep.len, str.len); + return res; +} + gb_internal bool string_contains_char(String const &s, u8 c) { isize i; for (i = 0; i < s.len; i++) { @@ -500,23 +633,28 @@ gb_internal String normalize_path(gbAllocator a, String const &path, String cons return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, nullptr, nullptr); } #elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX) - - #include + #include gb_internal int convert_multibyte_to_widechar(char const *multibyte_input, usize input_length, wchar_t *output, usize output_size) { - iconv_t conv = iconv_open("WCHAR_T", "UTF-8"); - size_t result = iconv(conv, cast(char **)&multibyte_input, &input_length, cast(char **)&output, &output_size); - iconv_close(conv); + String string = copy_string(heap_allocator(), make_string(cast(u8 const*)multibyte_input, input_length)); /* Guarantee NULL terminator */ + u8* input = string.text; - return cast(int)result; + mbstate_t ps = { 0 }; + size_t result = mbsrtowcs(output, cast(const char**)&input, output_size, &ps); + + gb_free(heap_allocator(), string.text); + return (result == (size_t)-1) ? -1 : (int)result; } gb_internal int convert_widechar_to_multibyte(wchar_t const *widechar_input, usize input_length, char* output, usize output_size) { - iconv_t conv = iconv_open("UTF-8", "WCHAR_T"); - size_t result = iconv(conv, cast(char**) &widechar_input, &input_length, cast(char **)&output, &output_size); - iconv_close(conv); + String string = copy_string(heap_allocator(), make_string(cast(u8 const*)widechar_input, input_length)); /* Guarantee NULL terminator */ + u8* input = string.text; - return cast(int)result; + mbstate_t ps = { 0 }; + size_t result = wcsrtombs(output, cast(const wchar_t**)&input, output_size, &ps); + + gb_free(heap_allocator(), string.text); + return (result == (size_t)-1) ? -1 : (int)result; } #else #error Implement system @@ -525,10 +663,9 @@ gb_internal String normalize_path(gbAllocator a, String const &path, String cons -// TODO(bill): Make this non-windows specific gb_internal String16 string_to_string16(gbAllocator a, String s) { int len, len1; - wchar_t *text; + u16 *text; if (s.len < 1) { return make_string16(nullptr, 0); @@ -539,15 +676,14 @@ gb_internal String16 string_to_string16(gbAllocator a, String s) { return make_string16(nullptr, 0); } - text = gb_alloc_array(a, wchar_t, len+1); + text = gb_alloc_array(a, u16, len+1); - len1 = convert_multibyte_to_widechar(cast(char *)s.text, cast(int)s.len, text, cast(int)len); + len1 = convert_multibyte_to_widechar(cast(char *)s.text, cast(int)s.len, cast(wchar_t *)text, cast(int)len); if (len1 == 0) { gb_free(a, text); return make_string16(nullptr, 0); } text[len] = 0; - return make_string16(text, len); } @@ -560,7 +696,7 @@ gb_internal String string16_to_string(gbAllocator a, String16 s) { return make_string(nullptr, 0); } - len = convert_widechar_to_multibyte(s.text, cast(int)s.len, nullptr, 0); + len = convert_widechar_to_multibyte(cast(wchar_t *)s.text, cast(int)s.len, nullptr, 0); if (len == 0) { return make_string(nullptr, 0); } @@ -568,7 +704,7 @@ gb_internal String string16_to_string(gbAllocator a, String16 s) { text = gb_alloc_array(a, u8, len+1); - len1 = convert_widechar_to_multibyte(s.text, cast(int)s.len, cast(char *)text, cast(int)len); + len1 = convert_widechar_to_multibyte(cast(wchar_t *)s.text, cast(int)s.len, cast(char *)text, cast(int)len); if (len1 == 0) { gb_free(a, text); return make_string(nullptr, 0); @@ -588,9 +724,9 @@ gb_internal String temporary_directory(gbAllocator allocator) { return String{0}; } DWORD len = gb_max(MAX_PATH, n); - wchar_t *b = gb_alloc_array(heap_allocator(), wchar_t, len+1); + u16 *b = gb_alloc_array(heap_allocator(), u16, len+1); defer (gb_free(heap_allocator(), b)); - n = GetTempPathW(len, b); + n = GetTempPathW(len, cast(wchar_t *)b); if (n == 3 && b[1] == ':' && b[2] == '\\') { } else if (n > 0 && b[n-1] == '\\') { @@ -705,6 +841,104 @@ gb_internal String quote_to_ascii(gbAllocator a, String str, u8 quote='"') { return res; } +gb_internal Rune decode_surrogate_pair(u16 r1, u16 r2) { + static Rune const _surr1 = 0xd800; + static Rune const _surr2 = 0xdc00; + static Rune const _surr3 = 0xe000; + static Rune const _surr_self = 0x10000; + + if (_surr1 <= r1 && r1 < _surr2 && _surr2 <= r2 && r2 < _surr3) { + return (((r1-_surr1)<<10) | (r2 - _surr2)) + _surr_self; + } + return GB_RUNE_INVALID; +} + +gb_internal String quote_to_ascii(gbAllocator a, String16 str, u8 quote='"') { + static Rune const _surr1 = 0xd800; + static Rune const _surr2 = 0xdc00; + static Rune const _surr3 = 0xe000; + static Rune const _surr_self = 0x10000; + + u16 *s = cast(u16 *)str.text; + isize n = str.len; + auto buf = array_make(a, 0, n*2); + array_add(&buf, quote); + for (isize width = 0; n > 0; s += width, n -= width) { + Rune r = cast(Rune)s[0]; + width = 1; + if (r < _surr1 || _surr3 <= r) { + r = cast(Rune)r; + } else if (_surr1 <= r && r < _surr2) { + if (n>1) { + r = decode_surrogate_pair(s[0], s[1]); + if (r != GB_RUNE_INVALID) { + width = 2; + } + } else { + r = GB_RUNE_INVALID; + } + } + if (width == 1 && r == GB_RUNE_INVALID) { + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'x'); + array_add(&buf, cast(u8)lower_hex[s[0]>>4]); + array_add(&buf, cast(u8)lower_hex[s[0]&0xf]); + continue; + } + + if (r == quote || r == '\\') { + array_add(&buf, cast(u8)'\\'); + array_add(&buf, u8(r)); + continue; + } + if (r < 0x80 && is_printable(r)) { + array_add(&buf, u8(r)); + continue; + } + switch (r) { + case '\a': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + default: + if (r < ' ') { + u8 b = cast(u8)r; + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'x'); + array_add(&buf, cast(u8)lower_hex[b>>4]); + array_add(&buf, cast(u8)lower_hex[b&0xf]); + } + if (r > GB_RUNE_MAX) { + r = 0XFFFD; + } + if (r < 0x10000) { + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'u'); + for (isize i = 12; i >= 0; i -= 4) { + array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]); + } + } else { + array_add(&buf, cast(u8)'\\'); + array_add(&buf, cast(u8)'U'); + for (isize i = 28; i >= 0; i -= 4) { + array_add(&buf, cast(u8)lower_hex[(r>>i)&0xf]); + } + } + } + } + + + + array_add(&buf, quote); + String res = {}; + res.text = buf.data; + res.len = buf.count; + return res; +} + diff --git a/src/string16_map.cpp b/src/string16_map.cpp new file mode 100644 index 000000000..c9e2eb817 --- /dev/null +++ b/src/string16_map.cpp @@ -0,0 +1,538 @@ +GB_STATIC_ASSERT(sizeof(MapIndex) == sizeof(u32)); + + +struct String16HashKey { + String16 string; + u32 hash; + + operator String16() const noexcept { + return this->string; + } + operator String16 const &() const noexcept { + return this->string; + } +}; +gb_internal gb_inline u32 string_hash(String16 const &s) { + u32 res = fnv32a(s.text, s.len*gb_size_of(u16)) & 0x7fffffff; + return res | (res == 0); +} + +gb_internal gb_inline String16HashKey string_hash_string(String16 const &s) { + String16HashKey hash_key = {}; + hash_key.hash = string_hash(s); + hash_key.string = s; + return hash_key; +} + + +#if 1 /* old string map */ + +template +struct String16MapEntry { + String16 key; + u32 hash; + MapIndex next; + T value; +}; + +template +struct String16Map { + MapIndex * hashes; + usize hashes_count; + String16MapEntry *entries; + u32 count; + u32 entries_capacity; +}; + + +template gb_internal void string16_map_init (String16Map *h, usize capacity = 16); +template gb_internal void string16_map_destroy (String16Map *h); + +template gb_internal T * string16_map_get (String16Map *h, String16HashKey const &key); +template gb_internal T & string16_map_must_get(String16Map *h, String16HashKey const &key); +template gb_internal void string16_map_set (String16Map *h, String16HashKey const &key, T const &value); + +// template gb_internal void string16_map_remove (String16Map *h, String16HashKey const &key); +template gb_internal void string16_map_clear (String16Map *h); +template gb_internal void string16_map_grow (String16Map *h); +template gb_internal void string16_map_reserve (String16Map *h, usize new_count); + +gb_internal gbAllocator string16_map_allocator(void) { + return heap_allocator(); +} + +template +gb_internal gb_inline void string16_map_init(String16Map *h, usize capacity) { + capacity = next_pow2_isize(capacity); + string16_map_reserve(h, capacity); +} + +template +gb_internal gb_inline void string16_map_destroy(String16Map *h) { + gb_free(string16_map_allocator(), h->hashes); + gb_free(string16_map_allocator(), h->entries); +} + + +template +gb_internal void string16_map__resize_hashes(String16Map *h, usize count) { + h->hashes_count = cast(u32)resize_array_raw(&h->hashes, string16_map_allocator(), h->hashes_count, count, MAP_CACHE_LINE_SIZE); +} + + +template +gb_internal void string16_map__reserve_entries(String16Map *h, usize capacity) { + h->entries_capacity = cast(u32)resize_array_raw(&h->entries, string16_map_allocator(), h->entries_capacity, capacity, MAP_CACHE_LINE_SIZE); +} + + +template +gb_internal MapIndex string16_map__add_entry(String16Map *h, u32 hash, String16 const &key) { + String16MapEntry e = {}; + e.key = key; + e.hash = hash; + e.next = MAP_SENTINEL; + if (h->count+1 >= h->entries_capacity) { + string16_map__reserve_entries(h, gb_max(h->entries_capacity*2, 4)); + } + h->entries[h->count++] = e; + return cast(MapIndex)(h->count-1); +} + +template +gb_internal MapFindResult string16_map__find(String16Map *h, u32 hash, String16 const &key) { + MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; + if (h->hashes_count != 0) { + fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1)); + fr.entry_index = h->hashes[fr.hash_index]; + while (fr.entry_index != MAP_SENTINEL) { + auto *entry = &h->entries[fr.entry_index]; + if (entry->hash == hash && entry->key == key) { + return fr; + } + fr.entry_prev = fr.entry_index; + fr.entry_index = entry->next; + } + } + return fr; +} + +template +gb_internal MapFindResult string16_map__find_from_entry(String16Map *h, String16MapEntry *e) { + MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; + if (h->hashes_count != 0) { + fr.hash_index = cast(MapIndex)(e->hash & (h->hashes_count-1)); + fr.entry_index = h->hashes[fr.hash_index]; + while (fr.entry_index != MAP_SENTINEL) { + auto *entry = &h->entries[fr.entry_index]; + if (entry == e) { + return fr; + } + fr.entry_prev = fr.entry_index; + fr.entry_index = entry->next; + } + } + return fr; +} + +template +gb_internal b32 string16_map__full(String16Map *h) { + return 0.75f * h->hashes_count <= h->count; +} + +template +gb_inline void string16_map_grow(String16Map *h) { + isize new_count = gb_max(h->hashes_count<<1, 16); + string16_map_reserve(h, new_count); +} + + +template +gb_internal void string16_map_reset_entries(String16Map *h) { + for (u32 i = 0; i < h->hashes_count; i++) { + h->hashes[i] = MAP_SENTINEL; + } + for (isize i = 0; i < h->count; i++) { + MapFindResult fr; + String16MapEntry *e = &h->entries[i]; + e->next = MAP_SENTINEL; + fr = string16_map__find_from_entry(h, e); + if (fr.entry_prev == MAP_SENTINEL) { + h->hashes[fr.hash_index] = cast(MapIndex)i; + } else { + h->entries[fr.entry_prev].next = cast(MapIndex)i; + } + } +} + +template +gb_internal void string16_map_reserve(String16Map *h, usize cap) { + if (h->count*2 < h->hashes_count) { + return; + } + string16_map__reserve_entries(h, cap); + string16_map__resize_hashes(h, cap*2); + string16_map_reset_entries(h); +} + +template +gb_internal T *string16_map_get(String16Map *h, u32 hash, String16 const &key) { + MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}; + if (h->hashes_count != 0) { + fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1)); + fr.entry_index = h->hashes[fr.hash_index]; + while (fr.entry_index != MAP_SENTINEL) { + auto *entry = &h->entries[fr.entry_index]; + if (entry->hash == hash && entry->key == key) { + return &entry->value; + } + fr.entry_prev = fr.entry_index; + fr.entry_index = entry->next; + } + } + return nullptr; +} + + +template +gb_internal gb_inline T *string16_map_get(String16Map *h, String16HashKey const &key) { + return string16_map_get(h, key.hash, key.string); +} +template +gb_internal T &string16_map_must_get(String16Map *h, u32 hash, String16 const &key) { + isize index = string16_map__find(h, hash, key).entry_index; + GB_ASSERT(index != MAP_SENTINEL); + return h->entries[index].value; +} + +template +gb_internal T &string16_map_must_get(String16Map *h, String16HashKey const &key) { + return string16_map_must_get(h, key.hash, key.string); +} + +template +gb_internal void string16_map_set(String16Map *h, u32 hash, String16 const &key, T const &value) { + MapIndex index; + MapFindResult fr; + if (h->hashes_count == 0) { + string16_map_grow(h); + } + fr = string16_map__find(h, hash, key); + if (fr.entry_index != MAP_SENTINEL) { + index = fr.entry_index; + } else { + index = string16_map__add_entry(h, hash, key); + if (fr.entry_prev != MAP_SENTINEL) { + h->entries[fr.entry_prev].next = index; + } else { + h->hashes[fr.hash_index] = index; + } + } + h->entries[index].value = value; + + if (string16_map__full(h)) { + string16_map_grow(h); + } +} + +template +gb_internal gb_inline void string16_map_set(String16Map *h, String16HashKey const &key, T const &value) { + string16_map_set(h, key.hash, key.string, value); +} + + +template +gb_internal gb_inline void string16_map_clear(String16Map *h) { + h->count = 0; + for (u32 i = 0; i < h->hashes_count; i++) { + h->hashes[i] = MAP_SENTINEL; + } +} + + + +template +gb_internal String16MapEntry *begin(String16Map &m) noexcept { + return m.entries; +} +template +gb_internal String16MapEntry const *begin(String16Map const &m) noexcept { + return m.entries; +} + + +template +gb_internal String16MapEntry *end(String16Map &m) noexcept { + return m.entries + m.count; +} + +template +gb_internal String16MapEntry const *end(String16Map const &m) noexcept { + return m.entries + m.count; +} + +#else /* new string map */ + +template +struct StringMapEntry { + String key; + u32 hash; + T value; +}; + +template +struct StringMap { + String16MapEntry *entries; + u32 count; + u32 capacity; +}; + + +template gb_internal void string16_map_init (String16Map *h, usize capacity = 16); +template gb_internal void string16_map_destroy (String16Map *h); + +template gb_internal T * string16_map_get (String16Map *h, String16 const &key); +template gb_internal T * string16_map_get (String16Map *h, String16HashKey const &key); + +template gb_internal T & string16_map_must_get(String16Map *h, String16 const &key); +template gb_internal T & string16_map_must_get(String16Map *h, String16HashKey const &key); + +template gb_internal void string16_map_set (String16Map *h, String16 const &key, T const &value); +template gb_internal void string16_map_set (String16Map *h, String16HashKey const &key, T const &value); + +// template gb_internal void string16_map_remove (String16Map *h, String16HashKey const &key); +template gb_internal void string16_map_clear (String16Map *h); +template gb_internal void string16_map_grow (String16Map *h); +template gb_internal void string16_map_reserve (String16Map *h, usize new_count); + +gb_internal gbAllocator string16_map_allocator(void) { + return heap_allocator(); +} + +template +gb_internal gb_inline void string16_map_init(String16Map *h, usize capacity) { + capacity = next_pow2_isize(capacity); + string16_map_reserve(h, capacity); +} + +template +gb_internal gb_inline void string16_map_destroy(String16Map *h) { + gb_free(string16_map_allocator(), h->entries); +} + + +template +gb_internal void string16_map__insert(String16Map *h, u32 hash, String16 const &key, T const &value) { + if (h->count+1 >= h->capacity) { + string16_map_grow(h); + } + GB_ASSERT(h->count+1 < h->capacity); + + u32 mask = h->capacity-1; + MapIndex index = hash & mask; + MapIndex original_index = index; + do { + auto *entry = h->entries+index; + if (entry->hash == 0) { + entry->key = key; + entry->hash = hash; + entry->value = value; + + h->count += 1; + return; + } + index = (index+1)&mask; + } while (index != original_index); + + GB_PANIC("Full map"); +} + +template +gb_internal b32 string16_map__full(String16Map *h) { + return 0.75f * h->count <= h->capacity; +} + +template +gb_inline void string16_map_grow(String16Map *h) { + isize new_capacity = gb_max(h->capacity<<1, 16); + string16_map_reserve(h, new_capacity); +} + + +template +gb_internal void string16_map_reserve(String16Map *h, usize cap) { + if (cap < h->capacity) { + return; + } + cap = next_pow2_isize(cap); + + String16Map new_h = {}; + new_h.count = 0; + new_h.capacity = cast(u32)cap; + new_h.entries = gb_alloc_array(string16_map_allocator(), String16MapEntry, new_h.capacity); + + if (h->count) { + for (u32 i = 0; i < h->capacity; i++) { + auto *entry = h->entries+i; + if (entry->hash) { + string16_map__insert(&new_h, entry->hash, entry->key, entry->value); + } + } + } + string16_map_destroy(h); + *h = new_h; +} + +template +gb_internal T *string16_map_get(String16Map *h, u32 hash, String16 const &key) { + if (h->count == 0) { + return nullptr; + } + u32 mask = (h->capacity-1); + u32 index = hash & mask; + u32 original_index = index; + do { + auto *entry = h->entries+index; + u32 curr_hash = entry->hash; + if (curr_hash == 0) { + // NOTE(bill): no found, but there isn't any key removal for this hash map + return nullptr; + } else if (curr_hash == hash && entry->key == key) { + return &entry->value; + } + index = (index+1) & mask; + } while (original_index != index); + return nullptr; +} + + +template +gb_internal gb_inline T *string16_map_get(String16Map *h, String16HashKey const &key) { + return string16_map_get(h, key.hash, key.string); +} + +template +gb_internal gb_inline T *string16_map_get(String16Map *h, String16 const &key) { + return string16_map_get(h, string_hash(key), key); +} + +template +gb_internal T &string16_map_must_get(String16Map *h, u32 hash, String16 const &key) { + T *found = string16_map_get(h, hash, key); + GB_ASSERT(found != nullptr); + return *found; +} + +template +gb_internal T &string16_map_must_get(String16Map *h, String16HashKey const &key) { + return string16_map_must_get(h, key.hash, key.string); +} + +template +gb_internal gb_inline T &string16_map_must_get(String16Map *h, String16 const &key) { + return string16_map_must_get(h, string_hash(key), key); +} + +template +gb_internal void string16_map_set(String16Map *h, u32 hash, String16 const &key, T const &value) { + if (h->count == 0) { + string16_map_grow(h); + } + auto *found = string16_map_get(h, hash, key); + if (found) { + *found = value; + return; + } + string16_map__insert(h, hash, key, value); +} + +template +gb_internal gb_inline void string16_map_set(String16Map *h, String16 const &key, T const &value) { + string16_map_set(h, string_hash_string(key), value); +} + +template +gb_internal gb_inline void string16_map_set(String16Map *h, String16HashKey const &key, T const &value) { + string16_map_set(h, key.hash, key.string, value); +} + + +template +gb_internal gb_inline void string16_map_clear(String16Map *h) { + h->count = 0; + gb_zero_array(h->entries, h->capacity); +} + + +template +struct StringMapIterator { + String16Map *map; + MapIndex index; + + StringMapIterator &operator++() noexcept { + for (;;) { + ++index; + if (map->capacity == index) { + return *this; + } + String16MapEntry *entry = map->entries+index; + if (entry->hash != 0) { + return *this; + } + } + } + + bool operator==(StringMapIterator const &other) const noexcept { + return this->map == other->map && this->index == other->index; + } + + operator String16MapEntry *() const { + return map->entries+index; + } +}; + + +template +gb_internal StringMapIterator end(String16Map &m) noexcept { + return StringMapIterator{&m, m.capacity}; +} + +template +gb_internal StringMapIterator const end(String16Map const &m) noexcept { + return StringMapIterator{&m, m.capacity}; +} + + + +template +gb_internal StringMapIterator begin(String16Map &m) noexcept { + if (m.count == 0) { + return end(m); + } + + MapIndex index = 0; + while (index < m.capacity) { + if (m.entries[index].hash) { + break; + } + index++; + } + return StringMapIterator{&m, index}; +} +template +gb_internal StringMapIterator const begin(String16Map const &m) noexcept { + if (m.count == 0) { + return end(m); + } + + MapIndex index = 0; + while (index < m.capacity) { + if (m.entries[index].hash) { + break; + } + index++; + } + return StringMapIterator{&m, index}; +} + +#endif \ No newline at end of file diff --git a/src/thread_pool.cpp b/src/thread_pool.cpp index 8363a4553..ca6483fd9 100644 --- a/src/thread_pool.cpp +++ b/src/thread_pool.cpp @@ -19,6 +19,11 @@ enum GrabState { Grab_Failed = 2, }; +enum BroadcastWaitState { + Nobody_Waiting = 0, + Someone_Waiting = 1, +}; + struct ThreadPool { gbAllocator threads_allocator; Slice threads; @@ -54,8 +59,8 @@ gb_internal void thread_pool_destroy(ThreadPool *pool) { for_array_off(i, 1, pool->threads) { Thread *t = &pool->threads[i]; - pool->tasks_available.fetch_add(1, std::memory_order_acquire); - futex_broadcast(&pool->tasks_available); + pool->tasks_available.store(Nobody_Waiting); + futex_broadcast(&t->pool->tasks_available); thread_join_and_destroy(t); } @@ -87,8 +92,10 @@ void thread_pool_queue_push(Thread *thread, WorkerTask task) { thread->queue.bottom.store(bot + 1, std::memory_order_relaxed); thread->pool->tasks_left.fetch_add(1, std::memory_order_release); - thread->pool->tasks_available.fetch_add(1, std::memory_order_relaxed); - futex_broadcast(&thread->pool->tasks_available); + i32 state = Someone_Waiting; + if (thread->pool->tasks_available.compare_exchange_strong(state, Nobody_Waiting)) { + futex_broadcast(&thread->pool->tasks_available); + } } GrabState thread_pool_queue_take(Thread *thread, WorkerTask *task) { @@ -230,12 +237,13 @@ gb_internal THREAD_PROC(thread_pool_thread_proc) { } // if we've done all our work, and there's nothing to steal, go to sleep - state = pool->tasks_available.load(std::memory_order_acquire); + pool->tasks_available.store(Someone_Waiting); if (!pool->running) { break; } - futex_wait(&pool->tasks_available, state); + futex_wait(&pool->tasks_available, Someone_Waiting); main_loop_continue:; } return 0; } + diff --git a/src/threading.cpp b/src/threading.cpp index af8fd803c..84f09912d 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -195,7 +195,13 @@ gb_internal void mutex_lock(RecursiveMutex *m) { // inside the lock return; } - futex_wait(&m->owner, prev_owner); + + // NOTE(lucas): we are doing spin lock since futex signal is expensive on OSX. The recursive locks are + // very short lived so we don't hit this mega often and I see no perform regression on windows (with + // a performance uplift on OSX). + + //futex_wait(&m->owner, prev_owner); + yield_thread(); } } gb_internal bool mutex_try_lock(RecursiveMutex *m) { @@ -216,7 +222,9 @@ gb_internal void mutex_unlock(RecursiveMutex *m) { return; } m->owner.exchange(0, std::memory_order_release); - futex_signal(&m->owner); + // NOTE(lucas): see comment about spin lock in mutex_lock above + + // futex_signal(&m->owner); // outside the lock } @@ -448,6 +456,44 @@ gb_internal void semaphore_wait(Semaphore *s) { } #endif +static const int RWLOCK_WRITER = 1<<0; +static const int RWLOCK_UPGRADED = 1<<1; +static const int RWLOCK_READER = 1<<2; +struct RWSpinLock { + Futex bits; +}; + +void rwlock_release_write(RWSpinLock *l) { + l->bits.fetch_and(~(RWLOCK_WRITER | RWLOCK_UPGRADED), std::memory_order_release); + futex_signal(&l->bits); +} + +bool rwlock_try_acquire_upgrade(RWSpinLock *l) { + int value = l->bits.fetch_or(RWLOCK_UPGRADED, std::memory_order_acquire); + return (value & (RWLOCK_UPGRADED | RWLOCK_WRITER)) == 0; +} + +void rwlock_acquire_upgrade(RWSpinLock *l) { + while (!rwlock_try_acquire_upgrade(l)) { + futex_wait(&l->bits, RWLOCK_UPGRADED | RWLOCK_WRITER); + } +} +void rwlock_release_upgrade(RWSpinLock *l) { + l->bits.fetch_add(-RWLOCK_UPGRADED, std::memory_order_acq_rel); +} + +bool rwlock_try_release_upgrade_and_acquire_write(RWSpinLock *l) { + int expect = RWLOCK_UPGRADED; + return l->bits.compare_exchange_strong(expect, RWLOCK_WRITER, std::memory_order_acq_rel); +} + +void rwlock_release_upgrade_and_acquire_write(RWSpinLock *l) { + while (!rwlock_try_release_upgrade_and_acquire_write(l)) { + futex_wait(&l->bits, RWLOCK_UPGRADED); + } +} + + struct Parker { Futex state; }; @@ -756,7 +802,7 @@ gb_internal void futex_signal(Futex *f) { perror("Futex wake"); GB_PANIC("futex wake fail"); - } else if (ret == 1) { + } else { return; } } @@ -773,7 +819,7 @@ gb_internal void futex_broadcast(Futex *f) { perror("Futex wake"); GB_PANIC("futex wake fail"); - } else if (ret == 1) { + } else { return; } } @@ -783,7 +829,7 @@ gb_internal void futex_wait(Futex *f, Footex val) { for (;;) { int ret = futex((volatile uint32_t *)f, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, NULL, NULL); if (ret == -1) { - if (*f != val) { + if (errno == EAGAIN) { return; } diff --git a/src/timings.cpp b/src/timings.cpp index 3f8402b36..f6e86867f 100644 --- a/src/timings.cpp +++ b/src/timings.cpp @@ -197,7 +197,7 @@ gb_internal void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Mill f64 total_time = time_stamp(t->total, t->freq, unit); - gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n", + gb_printf_err("%.*s%.*s - % 9.3f %s - %6.2f%%\n", LIT(t->total.label), cast(int)(max_len-t->total.label.len), SPACES, total_time, @@ -207,7 +207,7 @@ gb_internal void timings_print_all(Timings *t, TimingUnit unit = TimingUnit_Mill for_array(i, t->sections) { TimeStamp ts = t->sections[i]; f64 section_time = time_stamp(ts, t->freq, unit); - gb_printf("%.*s%.*s - % 9.3f %s - %6.2f%%\n", + gb_printf_err("%.*s%.*s - % 9.3f %s - %6.2f%%\n", LIT(ts.label), cast(int)(max_len-ts.label.len), SPACES, section_time, diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 53f6135d0..ffa53abb5 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -968,6 +968,7 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) { advance_to_next_rune(t); for (isize comment_scope = 1; comment_scope > 0; /**/) { if (t->curr_rune == GB_RUNE_EOF) { + tokenizer_err(t, "Multi-line comment not terminated"); break; } else if (t->curr_rune == '/') { advance_to_next_rune(t); diff --git a/src/types.cpp b/src/types.cpp index 43fe625f2..372c2e991 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -41,8 +41,13 @@ enum BasicKind { Basic_uint, Basic_uintptr, Basic_rawptr, - Basic_string, // ^u8 + int - Basic_cstring, // ^u8 + + Basic_string, // [^]u8 + int + Basic_cstring, // [^]u8 + + Basic_string16, // [^]u16 + int + Basic_cstring16, // [^]u16 + int + Basic_any, // rawptr + ^Type_Info Basic_typeid, @@ -111,7 +116,7 @@ enum BasicFlag { BasicFlag_Ordered = BasicFlag_Integer | BasicFlag_Float | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, BasicFlag_OrderedNumeric = BasicFlag_Integer | BasicFlag_Float | BasicFlag_Rune, BasicFlag_ConstantType = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_String | BasicFlag_Pointer | BasicFlag_Rune, - BasicFlag_SimpleCompare = BasicFlag_Boolean | BasicFlag_Numeric | BasicFlag_Pointer | BasicFlag_Rune, + BasicFlag_SimpleCompare = BasicFlag_Boolean | BasicFlag_Integer | BasicFlag_Pointer | BasicFlag_Rune, }; struct BasicType { @@ -152,11 +157,11 @@ struct TypeStruct { bool is_polymorphic; bool are_offsets_set : 1; - bool are_offsets_being_processed : 1; bool is_packed : 1; bool is_raw_union : 1; - bool is_no_copy : 1; bool is_poly_specialized : 1; + + std::atomic are_offsets_being_processed; }; struct TypeUnion { @@ -201,13 +206,18 @@ struct TypeProc { bool optional_ok; }; +struct TypeNamed { + String name; + Type * base; + Entity *type_name; /* Entity_TypeName */ + + BlockingMutex gen_types_data_mutex; + GenTypesData *gen_types_data; +}; + #define TYPE_KINDS \ TYPE_KIND(Basic, BasicType) \ - TYPE_KIND(Named, struct { \ - String name; \ - Type * base; \ - Entity *type_name; /* Entity_TypeName */ \ - }) \ + TYPE_KIND(Named, TypeNamed) \ TYPE_KIND(Generic, struct { \ i64 id; \ String name; \ @@ -255,7 +265,7 @@ struct TypeProc { Slice variables; /* Entity_Variable */ \ i64 * offsets; \ BlockingMutex mutex; /* for settings offsets */ \ - bool are_offsets_being_processed; \ + std::atomic are_offsets_being_processed; \ bool are_offsets_set; \ bool is_packed; \ }) \ @@ -329,6 +339,7 @@ struct Type { // NOTE(bill): These need to be at the end to not affect the unionized data std::atomic cached_size; std::atomic cached_align; + std::atomic canonical_hash; std::atomic flags; // TypeFlag bool failure; }; @@ -424,11 +435,8 @@ gb_internal Selection make_selection(Entity *entity, Array index, bool indi } gb_internal void selection_add_index(Selection *s, isize index) { - // IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form - // of heap allocation - // TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3 if (s->index.data == nullptr) { - array_init(&s->index, heap_allocator()); + array_init(&s->index, permanent_allocator()); } array_add(&s->index, cast(i32)index); } @@ -436,7 +444,7 @@ gb_internal void selection_add_index(Selection *s, isize index) { gb_internal Selection selection_combine(Selection const &lhs, Selection const &rhs) { Selection new_sel = lhs; new_sel.indirect = lhs.indirect || rhs.indirect; - new_sel.index = array_make(heap_allocator(), lhs.index.count+rhs.index.count); + new_sel.index = array_make(permanent_allocator(), lhs.index.count+rhs.index.count); array_copy(&new_sel.index, lhs.index, 0); array_copy(&new_sel.index, rhs.index, lhs.index.count); return new_sel; @@ -501,8 +509,14 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_uintptr, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uintptr")}}, {Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}}, + {Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}}, {Type_Basic, {Basic_cstring, BasicFlag_String, -1, STR_LIT("cstring")}}, + + {Type_Basic, {Basic_string16, BasicFlag_String, -1, STR_LIT("string16")}}, + {Type_Basic, {Basic_cstring16, BasicFlag_String, -1, STR_LIT("cstring16")}}, + + {Type_Basic, {Basic_any, 0, 16, STR_LIT("any")}}, {Type_Basic, {Basic_typeid, 0, 8, STR_LIT("typeid")}}, @@ -592,8 +606,12 @@ gb_global Type *t_uint = &basic_types[Basic_uint]; gb_global Type *t_uintptr = &basic_types[Basic_uintptr]; gb_global Type *t_rawptr = &basic_types[Basic_rawptr]; + gb_global Type *t_string = &basic_types[Basic_string]; gb_global Type *t_cstring = &basic_types[Basic_cstring]; +gb_global Type *t_string16 = &basic_types[Basic_string16]; +gb_global Type *t_cstring16 = &basic_types[Basic_cstring16]; + gb_global Type *t_any = &basic_types[Basic_any]; gb_global Type *t_typeid = &basic_types[Basic_typeid]; @@ -631,6 +649,8 @@ gb_global Type *t_untyped_uninit = &basic_types[Basic_UntypedUninit]; gb_global Type *t_u8_ptr = nullptr; gb_global Type *t_u8_multi_ptr = nullptr; +gb_global Type *t_u16_ptr = nullptr; +gb_global Type *t_u16_multi_ptr = nullptr; gb_global Type *t_int_ptr = nullptr; gb_global Type *t_i64_ptr = nullptr; gb_global Type *t_f64_ptr = nullptr; @@ -644,6 +664,8 @@ gb_global Type *t_type_info_enum_value = nullptr; gb_global Type *t_type_info_ptr = nullptr; gb_global Type *t_type_info_enum_value_ptr = nullptr; +gb_global Type *t_type_info_string_encoding_kind = nullptr; + gb_global Type *t_type_info_named = nullptr; gb_global Type *t_type_info_integer = nullptr; gb_global Type *t_type_info_rune = nullptr; @@ -729,10 +751,15 @@ gb_global Type *t_map_set_proc = nullptr; gb_global Type *t_objc_object = nullptr; gb_global Type *t_objc_selector = nullptr; gb_global Type *t_objc_class = nullptr; +gb_global Type *t_objc_ivar = nullptr; +gb_global Type *t_objc_super = nullptr; // Struct used in lieu of the 'self' instance when calling objc_msgSendSuper. +gb_global Type *t_objc_super_ptr = nullptr; gb_global Type *t_objc_id = nullptr; gb_global Type *t_objc_SEL = nullptr; gb_global Type *t_objc_Class = nullptr; +gb_global Type *t_objc_Ivar = nullptr; +gb_global Type *t_objc_instancetype = nullptr; // Special distinct variant of t_objc_id used mimic auto-typing of instancetype* in Objective-C enum OdinAtomicMemoryOrder : i32 { OdinAtomicMemoryOrder_relaxed = 0, // unordered @@ -872,6 +899,29 @@ gb_internal Type *base_type(Type *t) { return t; } +gb_internal Type *base_named_type(Type *t) { + if (t->kind != Type_Named) { + return t_invalid; + } + + Type *prev_named = t; + t = t->Named.base; + for (;;) { + if (t == nullptr) { + break; + } + if (t->kind != Type_Named) { + break; + } + if (t == t->Named.base) { + return t_invalid; + } + prev_named = t; + t = t->Named.base; + } + return prev_named; +} + gb_internal Type *base_enum_type(Type *t) { Type *bt = base_type(t); if (bt != nullptr && @@ -1178,6 +1228,7 @@ gb_internal Type *type_deref(Type *t, bool allow_multi_pointer) { } gb_internal bool is_type_named(Type *t) { + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return true; } @@ -1185,16 +1236,16 @@ gb_internal bool is_type_named(Type *t) { } gb_internal bool is_type_boolean(Type *t) { - // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Boolean) != 0; } return false; } gb_internal bool is_type_integer(Type *t) { - // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Integer) != 0; } @@ -1202,6 +1253,7 @@ gb_internal bool is_type_integer(Type *t) { } gb_internal bool is_type_integer_like(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Boolean)) != 0; } @@ -1216,31 +1268,34 @@ gb_internal bool is_type_integer_like(Type *t) { gb_internal bool is_type_unsigned(Type *t) { t = base_type(t); - // t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Unsigned) != 0; } + if (t->kind == Type_Enum) { + return (t->Enum.base_type->Basic.flags & BasicFlag_Unsigned) != 0; + } return false; } gb_internal bool is_type_integer_128bit(Type *t) { - // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Integer) != 0 && t->Basic.size == 16; } return false; } gb_internal bool is_type_rune(Type *t) { - // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Rune) != 0; } return false; } gb_internal bool is_type_numeric(Type *t) { - // t = core_type(t); t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Numeric) != 0; } else if (t->kind == Type_Enum) { @@ -1254,23 +1309,39 @@ gb_internal bool is_type_numeric(Type *t) { } gb_internal bool is_type_string(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_String) != 0; } return false; } +gb_internal bool is_type_string16(Type *t) { + t = base_type(t); + if (t == nullptr) { return false; } + if (t->kind == Type_Basic) { + return t->Basic.kind == Basic_string16; + } + return false; +} gb_internal bool is_type_cstring(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return t->Basic.kind == Basic_cstring; } return false; } +gb_internal bool is_type_cstring16(Type *t) { + t = base_type(t); + if (t == nullptr) { return false; } + if (t->kind == Type_Basic) { + return t->Basic.kind == Basic_cstring16; + } + return false; +} gb_internal bool is_type_typed(Type *t) { t = base_type(t); - if (t == nullptr) { - return false; - } + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Untyped) == 0; } @@ -1278,9 +1349,7 @@ gb_internal bool is_type_typed(Type *t) { } gb_internal bool is_type_untyped(Type *t) { t = base_type(t); - if (t == nullptr) { - return false; - } + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Untyped) != 0; } @@ -1288,6 +1357,7 @@ gb_internal bool is_type_untyped(Type *t) { } gb_internal bool is_type_ordered(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } switch (t->kind) { case Type_Basic: return (t->Basic.flags & BasicFlag_Ordered) != 0; @@ -1300,6 +1370,7 @@ gb_internal bool is_type_ordered(Type *t) { } gb_internal bool is_type_ordered_numeric(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } switch (t->kind) { case Type_Basic: return (t->Basic.flags & BasicFlag_OrderedNumeric) != 0; @@ -1308,19 +1379,27 @@ gb_internal bool is_type_ordered_numeric(Type *t) { } gb_internal bool is_type_constant_type(Type *t) { t = core_type(t); - if (t->kind == Type_Basic) { + if (t == nullptr) { return false; } + switch (t->kind) { + case Type_Basic: + if (t->Basic.kind == Basic_typeid) { + return true; + } return (t->Basic.flags & BasicFlag_ConstantType) != 0; - } - if (t->kind == Type_BitSet) { + case Type_BitSet: return true; - } - if (t->kind == Type_Proc) { + case Type_Proc: return true; + case Type_Array: + return is_type_constant_type(t->Array.elem); + case Type_EnumeratedArray: + return is_type_constant_type(t->EnumeratedArray.elem); } return false; } gb_internal bool is_type_float(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Float) != 0; } @@ -1328,6 +1407,7 @@ gb_internal bool is_type_float(Type *t) { } gb_internal bool is_type_complex(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Complex) != 0; } @@ -1335,6 +1415,7 @@ gb_internal bool is_type_complex(Type *t) { } gb_internal bool is_type_quaternion(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Quaternion) != 0; } @@ -1342,6 +1423,7 @@ gb_internal bool is_type_quaternion(Type *t) { } gb_internal bool is_type_complex_or_quaternion(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & (BasicFlag_Complex|BasicFlag_Quaternion)) != 0; } @@ -1349,6 +1431,7 @@ gb_internal bool is_type_complex_or_quaternion(Type *t) { } gb_internal bool is_type_pointer(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & BasicFlag_Pointer) != 0; } @@ -1356,10 +1439,12 @@ gb_internal bool is_type_pointer(Type *t) { } gb_internal bool is_type_soa_pointer(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_SoaPointer; } gb_internal bool is_type_multi_pointer(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_MultiPointer; } gb_internal bool is_type_internally_pointer_like(Type *t) { @@ -1368,36 +1453,50 @@ gb_internal bool is_type_internally_pointer_like(Type *t) { gb_internal bool is_type_tuple(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Tuple; } gb_internal bool is_type_uintptr(Type *t) { + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.kind == Basic_uintptr); } return false; } gb_internal bool is_type_rawptr(Type *t) { + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return t->Basic.kind == Basic_rawptr; } return false; } gb_internal bool is_type_u8(Type *t) { + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return t->Basic.kind == Basic_u8; } return false; } +gb_internal bool is_type_u16(Type *t) { + if (t == nullptr) { return false; } + if (t->kind == Type_Basic) { + return t->Basic.kind == Basic_u16; + } + return false; +} gb_internal bool is_type_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Array; } gb_internal bool is_type_enumerated_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_EnumeratedArray; } gb_internal bool is_type_matrix(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Matrix; } @@ -1526,6 +1625,7 @@ gb_internal bool is_matrix_square(Type *t) { gb_internal bool is_type_valid_for_matrix_elems(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (is_type_integer(t)) { return true; } else if (is_type_float(t)) { @@ -1541,22 +1641,27 @@ gb_internal bool is_type_valid_for_matrix_elems(Type *t) { gb_internal bool is_type_dynamic_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_DynamicArray; } gb_internal bool is_type_slice(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Slice; } gb_internal bool is_type_proc(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Proc; } gb_internal bool is_type_asm_proc(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Proc && t->Proc.calling_convention == ProcCC_InlineAsm; } gb_internal bool is_type_simd_vector(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_SimdVector; } @@ -1596,11 +1701,13 @@ gb_internal Type *base_any_array_type(Type *t) { gb_internal bool is_type_generic(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Generic; } gb_internal bool is_type_u8_slice(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Slice) { return is_type_u8(t->Slice.elem); } @@ -1608,6 +1715,7 @@ gb_internal bool is_type_u8_slice(Type *t) { } gb_internal bool is_type_u8_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Array) { return is_type_u8(t->Array.elem); } @@ -1615,6 +1723,7 @@ gb_internal bool is_type_u8_array(Type *t) { } gb_internal bool is_type_u8_ptr(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Pointer) { return is_type_u8(t->Slice.elem); } @@ -1622,6 +1731,7 @@ gb_internal bool is_type_u8_ptr(Type *t) { } gb_internal bool is_type_u8_multi_ptr(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_MultiPointer) { return is_type_u8(t->Slice.elem); } @@ -1629,12 +1739,46 @@ gb_internal bool is_type_u8_multi_ptr(Type *t) { } gb_internal bool is_type_rune_array(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Array) { return is_type_rune(t->Array.elem); } return false; } +gb_internal bool is_type_u16_slice(Type *t) { + t = base_type(t); + if (t == nullptr) { return false; } + if (t->kind == Type_Slice) { + return is_type_u16(t->Slice.elem); + } + return false; +} +gb_internal bool is_type_u16_array(Type *t) { + t = base_type(t); + if (t == nullptr) { return false; } + if (t->kind == Type_Array) { + return is_type_u16(t->Array.elem); + } + return false; +} +gb_internal bool is_type_u16_ptr(Type *t) { + t = base_type(t); + if (t == nullptr) { return false; } + if (t->kind == Type_Pointer) { + return is_type_u16(t->Slice.elem); + } + return false; +} +gb_internal bool is_type_u16_multi_ptr(Type *t) { + t = base_type(t); + if (t == nullptr) { return false; } + if (t->kind == Type_MultiPointer) { + return is_type_u16(t->Slice.elem); + } + return false; +} + gb_internal bool is_type_array_like(Type *t) { return is_type_array(t) || is_type_enumerated_array(t); @@ -1709,44 +1853,49 @@ gb_internal Type *base_complex_elem_type(Type *t) { gb_internal bool is_type_struct(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Struct; } gb_internal bool is_type_union(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Union; } gb_internal bool is_type_soa_struct(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None; } gb_internal bool is_type_raw_union(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_Struct && t->Struct.is_raw_union); } -gb_internal bool is_type_no_copy(Type *t) { - t = base_type(t); - return (t->kind == Type_Struct && t->Struct.is_no_copy); -} gb_internal bool is_type_enum(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_Enum); } gb_internal bool is_type_bit_set(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_BitSet); } gb_internal bool is_type_bit_field(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_BitField); } gb_internal bool is_type_map(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return t->kind == Type_Map; } gb_internal bool is_type_union_maybe_pointer(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Union && t->Union.variants.count == 1) { Type *v = t->Union.variants[0]; return is_type_internally_pointer_like(v); @@ -1757,6 +1906,7 @@ gb_internal bool is_type_union_maybe_pointer(Type *t) { gb_internal bool is_type_union_maybe_pointer_original_alignment(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Union && t->Union.variants.count == 1) { Type *v = t->Union.variants[0]; if (is_type_internally_pointer_like(v)) { @@ -1791,6 +1941,7 @@ gb_internal TypeEndianKind type_endian_kind_of(Type *t) { gb_internal bool is_type_endian_big(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { if (t->Basic.flags & BasicFlag_EndianBig) { return true; @@ -1807,6 +1958,7 @@ gb_internal bool is_type_endian_big(Type *t) { } gb_internal bool is_type_endian_little(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { if (t->Basic.flags & BasicFlag_EndianLittle) { return true; @@ -1824,6 +1976,7 @@ gb_internal bool is_type_endian_little(Type *t) { gb_internal bool is_type_endian_platform(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_Basic) { return (t->Basic.flags & (BasicFlag_EndianLittle|BasicFlag_EndianBig)) == 0; } else if (t->kind == Type_BitSet) { @@ -1839,6 +1992,7 @@ gb_internal bool types_have_same_internal_endian(Type *a, Type *b) { } gb_internal bool is_type_endian_specific(Type *t) { t = core_type(t); + if (t == nullptr) { return false; } if (t->kind == Type_BitSet) { t = bit_set_to_int(t); } @@ -1936,25 +2090,35 @@ gb_internal Type *integer_endian_type_to_platform_type(Type *t) { gb_internal bool is_type_any(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_Basic && t->Basic.kind == Basic_any); } gb_internal bool is_type_typeid(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } return (t->kind == Type_Basic && t->Basic.kind == Basic_typeid); } gb_internal bool is_type_untyped_nil(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } // NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling return (t->kind == Type_Basic && (t->Basic.kind == Basic_UntypedNil || t->Basic.kind == Basic_UntypedUninit)); } gb_internal bool is_type_untyped_uninit(Type *t) { t = base_type(t); + if (t == nullptr) { return false; } // NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUninit); } gb_internal bool is_type_empty_union(Type *t) { + if (t == nullptr) { + return false; + } t = base_type(t); + if (t == nullptr) { + return false; + } return t->kind == Type_Union && t->Union.variants.count == 0; } @@ -2052,7 +2216,7 @@ gb_internal bool is_type_indexable(Type *t) { Type *bt = base_type(t); switch (bt->kind) { case Type_Basic: - return bt->Basic.kind == Basic_string; + return bt->Basic.kind == Basic_string || bt->Basic.kind == Basic_string16; case Type_Array: case Type_Slice: case Type_DynamicArray: @@ -2072,7 +2236,7 @@ gb_internal bool is_type_sliceable(Type *t) { Type *bt = base_type(t); switch (bt->kind) { case Type_Basic: - return bt->Basic.kind == Basic_string; + return bt->Basic.kind == Basic_string || bt->Basic.kind == Basic_string16; case Type_Array: case Type_Slice: case Type_DynamicArray: @@ -2319,6 +2483,7 @@ gb_internal bool type_has_nil(Type *t) { case Basic_any: return true; case Basic_cstring: + case Basic_cstring16: return true; case Basic_typeid: return true; @@ -2351,18 +2516,70 @@ gb_internal bool type_has_nil(Type *t) { return false; } +gb_internal bool is_type_union_constantable(Type *type) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Union); + + if (bt->Union.variants.count == 0) { + return true; + } else if (bt->Union.variants.count == 1) { + return is_type_constant_type(bt->Union.variants[0]); + } + + for (Type *v : bt->Union.variants) { + if (!is_type_constant_type(v)) { + return false; + } + } + return true; +} + +gb_internal bool is_type_raw_union_constantable(Type *type) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_Struct); + GB_ASSERT(bt->Struct.is_raw_union); + + for (Entity *f : bt->Struct.fields) { + if (!is_type_constant_type(f->type)) { + return false; + } + } + // return true; + return false; // Disable raw union constants for the time being +} + gb_internal bool elem_type_can_be_constant(Type *t) { t = base_type(t); if (t == t_invalid) { return false; } - if (is_type_any(t) || is_type_union(t) || is_type_raw_union(t)) { + if (is_type_any(t)) { return false; } + if (is_type_raw_union(t)) { + return is_type_raw_union_constantable(t); + } + if (is_type_union(t)) { + return is_type_union_constantable(t); + } return true; } +gb_internal bool elem_cannot_be_constant(Type *t) { + if (is_type_any(t)) { + return true; + } + if (is_type_union(t)) { + return !is_type_union_constantable(t); + } + if (is_type_raw_union(t)) { + return !is_type_raw_union_constantable(t); + } + return false; +} + + gb_internal bool is_type_lock_free(Type *t) { t = core_type(t); if (t == t_invalid) { @@ -2386,8 +2603,9 @@ gb_internal bool is_type_comparable(Type *t) { case Basic_rune: return true; case Basic_string: - return true; case Basic_cstring: + case Basic_string16: + case Basic_cstring16: return true; case Basic_typeid: return true; @@ -2502,6 +2720,62 @@ gb_internal bool is_type_simple_compare(Type *t) { return false; } +// NOTE(bill): type can be easily compared using memcmp or contains a float +gb_internal bool is_type_nearly_simple_compare(Type *t) { + t = core_type(t); + switch (t->kind) { + case Type_Array: + return is_type_nearly_simple_compare(t->Array.elem); + + case Type_EnumeratedArray: + return is_type_nearly_simple_compare(t->EnumeratedArray.elem); + + case Type_Basic: + if (t->Basic.flags & (BasicFlag_SimpleCompare|BasicFlag_Numeric)) { + return true; + } + if (t->Basic.kind == Basic_typeid) { + return true; + } + return false; + + case Type_Pointer: + case Type_MultiPointer: + case Type_SoaPointer: + case Type_Proc: + case Type_BitSet: + return true; + + case Type_Matrix: + return is_type_nearly_simple_compare(t->Matrix.elem); + + case Type_Struct: + for_array(i, t->Struct.fields) { + Entity *f = t->Struct.fields[i]; + if (!is_type_nearly_simple_compare(f->type)) { + return false; + } + } + return true; + + case Type_Union: + for_array(i, t->Union.variants) { + Type *v = t->Union.variants[i]; + if (!is_type_nearly_simple_compare(v)) { + return false; + } + } + // make it dumb on purpose + return t->Union.variants.count == 1; + + case Type_SimdVector: + return is_type_nearly_simple_compare(t->SimdVector.elem); + + } + + return false; +} + gb_internal bool is_type_load_safe(Type *type) { GB_ASSERT(type != nullptr); type = core_type(core_array_type(type)); @@ -2643,10 +2917,11 @@ gb_internal bool are_types_identical(Type *x, Type *y) { y = y->Named.base; } } - if (x->kind != y->kind) { + if (x == nullptr || y == nullptr || x->kind != y->kind) { return false; } + // MUTEX_GUARD(&g_type_mutex); return are_types_identical_internal(x, y, false); } gb_internal bool are_types_identical_unique_tuples(Type *x, Type *y) { @@ -2674,6 +2949,7 @@ gb_internal bool are_types_identical_unique_tuples(Type *x, Type *y) { return false; } + // MUTEX_GUARD(&g_type_mutex); return are_types_identical_internal(x, y, true); } @@ -2797,7 +3073,6 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Struct: if (x->Struct.is_raw_union == y->Struct.is_raw_union && - x->Struct.is_no_copy == y->Struct.is_no_copy && x->Struct.fields.count == y->Struct.fields.count && x->Struct.is_packed == y->Struct.is_packed && x->Struct.soa_kind == y->Struct.soa_kind && @@ -2932,6 +3207,10 @@ gb_internal Type *default_type(Type *type) { case Basic_UntypedString: return t_string; case Basic_UntypedRune: return t_rune; } + } else if (type->kind == Type_Generic) { + if (type->Generic.specialized) { + return default_type(type->Generic.specialized); + } } return type; } @@ -3030,11 +3309,15 @@ gb_internal i64 union_tag_size(Type *u) { compiler_error("how many variants do you have?! %lld", cast(long long)u->Union.variants.count); } - for_array(i, u->Union.variants) { - Type *variant_type = u->Union.variants[i]; - i64 align = type_align_of(variant_type); - if (max_align < align) { - max_align = align; + if (u->Union.custom_align > 0) { + max_align = gb_max(max_align, u->Union.custom_align); + } else { + for_array(i, u->Union.variants) { + Type *variant_type = u->Union.variants[i]; + i64 align = type_align_of(variant_type); + if (max_align < align) { + max_align = align; + } } } @@ -3327,6 +3610,15 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name } } } + + Type *objc_ivar_type = e->TypeName.objc_ivar; + if (objc_ivar_type != nullptr) { + sel = lookup_field_with_selection(objc_ivar_type, field_name, false, sel, allow_blank_ident); + if (sel.entity != nullptr) { + sel.pseudo_field = true; + return sel; + } + } } if (is_type_polymorphic(type)) { @@ -3701,10 +3993,12 @@ gb_internal i64 type_size_of(Type *t) { if (t->kind == Type_Basic) { GB_ASSERT_MSG(is_type_typed(t), "%s", type_to_string(t)); switch (t->Basic.kind) { - case Basic_string: size = 2*build_context.int_size; break; - case Basic_cstring: size = build_context.ptr_size; break; - case Basic_any: size = 16; break; - case Basic_typeid: size = 8; break; + case Basic_string: size = 2*build_context.int_size; break; + case Basic_cstring: size = build_context.ptr_size; break; + case Basic_string16: size = 2*build_context.int_size; break; + case Basic_cstring16: size = build_context.ptr_size; break; + case Basic_any: size = 16; break; + case Basic_typeid: size = 8; break; case Basic_int: case Basic_uint: size = build_context.int_size; @@ -3724,7 +4018,7 @@ gb_internal i64 type_size_of(Type *t) { TypePath path{}; type_path_init(&path); { - MUTEX_GUARD(&g_type_mutex); + // MUTEX_GUARD(&g_type_mutex); size = type_size_of_internal(t, &path); t->cached_size.store(size); } @@ -3744,7 +4038,7 @@ gb_internal i64 type_align_of(Type *t) { TypePath path{}; type_path_init(&path); { - MUTEX_GUARD(&g_type_mutex); + // MUTEX_GUARD(&g_type_mutex); t->cached_align.store(type_align_of_internal(t, &path)); } type_path_free(&path); @@ -3764,10 +4058,12 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) { case Type_Basic: { GB_ASSERT(is_type_typed(t)); switch (t->Basic.kind) { - case Basic_string: return build_context.int_size; - case Basic_cstring: return build_context.ptr_size; - case Basic_any: return 8; - case Basic_typeid: return 8; + case Basic_string: return build_context.int_size; + case Basic_cstring: return build_context.ptr_size; + case Basic_string16: return build_context.int_size; + case Basic_cstring16: return build_context.ptr_size; + case Basic_any: return 8; + case Basic_typeid: return 8; case Basic_int: case Basic_uint: return build_context.int_size; @@ -3970,18 +4266,18 @@ gb_internal bool type_set_offsets(Type *t) { if (t->kind == Type_Struct) { MUTEX_GUARD(&t->Struct.offset_mutex); if (!t->Struct.are_offsets_set) { - t->Struct.are_offsets_being_processed = true; + t->Struct.are_offsets_being_processed.store(true); t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union, t->Struct.custom_min_field_align, t->Struct.custom_max_field_align); - t->Struct.are_offsets_being_processed = false; + t->Struct.are_offsets_being_processed.store(false); t->Struct.are_offsets_set = true; return true; } } else if (is_type_tuple(t)) { MUTEX_GUARD(&t->Tuple.mutex); if (!t->Tuple.are_offsets_set) { - t->Tuple.are_offsets_being_processed = true; + t->Tuple.are_offsets_being_processed.store(true); t->Tuple.offsets = type_set_offsets_of(t->Tuple.variables, t->Tuple.is_packed, false, 1, 0); - t->Tuple.are_offsets_being_processed = false; + t->Tuple.are_offsets_being_processed.store(false); t->Tuple.are_offsets_set = true; return true; } @@ -4015,10 +4311,12 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { return size; } switch (kind) { - case Basic_string: return 2*build_context.int_size; - case Basic_cstring: return build_context.ptr_size; - case Basic_any: return 16; - case Basic_typeid: return 8; + case Basic_string: return 2*build_context.int_size; + case Basic_cstring: return build_context.ptr_size; + case Basic_string16: return 2*build_context.int_size; + case Basic_cstring16: return build_context.ptr_size; + case Basic_any: return 16; + case Basic_typeid: return 8; case Basic_int: case Basic_uint: return build_context.int_size; @@ -4108,10 +4406,10 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { } i64 max = 0; - i64 field_size = 0; for_array(i, t->Union.variants) { Type *variant_type = t->Union.variants[i]; + i64 size = type_size_of_internal(variant_type, path); if (max < size) { max = size; @@ -4130,7 +4428,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { size = align_formula(max, tag_size); // NOTE(bill): Calculate the padding between the common fields and the tag t->Union.tag_size = cast(i16)tag_size; - t->Union.variant_block_size = size - field_size; + t->Union.variant_block_size = size; size += tag_size; } @@ -4164,9 +4462,12 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { if (path->failure) { return FAILURE_SIZE; } - if (t->Struct.are_offsets_being_processed && t->Struct.offsets == nullptr) { - type_path_print_illegal_cycle(path, path->path.count-1); - return FAILURE_SIZE; + { + MUTEX_GUARD(&t->Struct.offset_mutex); + if (t->Struct.are_offsets_being_processed.load() && t->Struct.offsets == nullptr) { + type_path_print_illegal_cycle(path, path->path.count-1); + return FAILURE_SIZE; + } } type_set_offsets(t); GB_ASSERT(t->Struct.fields.count == 0 || t->Struct.offsets != nullptr); @@ -4247,6 +4548,15 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) { if (field_type_) *field_type_ = t_int; return build_context.int_size; // len } + } else if (t->Basic.kind == Basic_string16) { + switch (index) { + case 0: + if (field_type_) *field_type_ = t_u16_ptr; + return 0; // data + case 1: + if (field_type_) *field_type_ = t_int; + return build_context.int_size; // len + } } else if (t->Basic.kind == Basic_any) { switch (index) { case 0: @@ -4323,6 +4633,11 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) { case 0: t = t_rawptr; break; case 1: t = t_int; break; } + } else if (t->Basic.kind == Basic_string16) { + switch (index) { + case 0: t = t_rawptr; break; + case 1: t = t_int; break; + } } else if (t->Basic.kind == Basic_any) { switch (index) { case 0: t = t_rawptr; break; @@ -4423,6 +4738,14 @@ gb_internal bool is_type_objc_object(Type *t) { return internal_check_is_assignable_to(t, t_objc_object); } +gb_internal bool is_type_objc_ptr_to_object(Type *t) { + // NOTE (harold): is_type_objc_object() returns true if it's a pointer to an object or the object itself. + // This returns true ONLY if Type is a shallow pointer to an Objective-C object. + + Type *elem = type_deref(t); + return elem != t && elem->kind == Type_Named && is_type_objc_object(elem); +} + gb_internal Type *get_struct_field_type(Type *t, isize index) { t = base_type(type_deref(t)); GB_ASSERT(t->kind == Type_Struct); @@ -4449,7 +4772,7 @@ gb_internal Type *alloc_type_tuple_from_field_types(Type **field_types, isize fi } Type *t = alloc_type_tuple(); - t->Tuple.variables = slice_make(heap_allocator(), field_count); + t->Tuple.variables = slice_make(permanent_allocator(), field_count); Scope *scope = nullptr; for_array(i, t->Tuple.variables) { @@ -4542,7 +4865,89 @@ gb_internal Type *alloc_type_proc_from_types(Type **param_types, unsigned param_ // return type; // } -gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) { +// Index a type that is internally a struct or array. +gb_internal Type *type_internal_index(Type *t, isize index) { + Type *bt = base_type(t); + if (bt == nullptr) { + return nullptr; + } + + switch (bt->kind) { + case Type_Basic: + { + switch (bt->Basic.kind) { + case Basic_complex32: return t_f16; + case Basic_complex64: return t_f32; + case Basic_complex128: return t_f64; + case Basic_quaternion64: return t_f16; + case Basic_quaternion128: return t_f32; + case Basic_quaternion256: return t_f64; + case Basic_string: + { + GB_ASSERT(index == 0 || index == 1); + return index == 0 ? t_u8_ptr : t_int; + } + case Basic_string16: + { + GB_ASSERT(index == 0 || index == 1); + return index == 0 ? t_u16_ptr : t_int; + } + case Basic_any: + { + GB_ASSERT(index == 0 || index == 1); + return index == 0 ? t_rawptr : t_typeid; + } + } + } + break; + + case Type_Array: return bt->Array.elem; + case Type_EnumeratedArray: return bt->EnumeratedArray.elem; + case Type_SimdVector: return bt->SimdVector.elem; + case Type_Slice: + { + GB_ASSERT(index == 0 || index == 1); + return index == 0 ? t_rawptr : t_typeid; + } + case Type_DynamicArray: + { + switch (index) { + case 0: return t_rawptr; + case 1: return t_int; + case 2: return t_int; + case 3: return t_allocator; + default: GB_PANIC("invalid raw dynamic array index"); + }; + } + case Type_Struct: + return get_struct_field_type(bt, index); + case Type_Union: + if (index < bt->Union.variants.count) { + return bt->Union.variants[index]; + } + return union_tag_type(bt); + case Type_Tuple: + return bt->Tuple.variables[index]->type; + case Type_Matrix: + return bt->Matrix.elem; + case Type_SoaPointer: + { + GB_ASSERT(index == 0 || index == 1); + return index == 0 ? t_rawptr : t_int; + } + case Type_Map: + return type_internal_index(bt->Map.debug_metadata_type, index); + case Type_BitField: + return type_internal_index(bt->BitField.backing_type, index); + case Type_Generic: + return type_internal_index(bt->Generic.specialized, index); + }; + + GB_PANIC("Unhandled type %s", type_to_string(bt)); + return nullptr; +}; + +gb_internal gbString write_type_to_string(gbString str, Type *type, bool shorthand=false, bool allow_polymorphic=false) { if (type == nullptr) { return gb_string_appendc(str, ""); } @@ -4567,24 +4972,24 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_append_length(str, name.text, name.len); if (type->Generic.specialized != nullptr) { str = gb_string_append_rune(str, '/'); - str = write_type_to_string(str, type->Generic.specialized); + str = write_type_to_string(str, type->Generic.specialized, shorthand, allow_polymorphic); } } break; case Type_Pointer: str = gb_string_append_rune(str, '^'); - str = write_type_to_string(str, type->Pointer.elem); + str = write_type_to_string(str, type->Pointer.elem, shorthand, allow_polymorphic); break; case Type_SoaPointer: str = gb_string_appendc(str, "#soa ^"); - str = write_type_to_string(str, type->SoaPointer.elem); + str = write_type_to_string(str, type->SoaPointer.elem, shorthand, allow_polymorphic); break; case Type_MultiPointer: str = gb_string_appendc(str, "[^]"); - str = write_type_to_string(str, type->Pointer.elem); + str = write_type_to_string(str, type->Pointer.elem, shorthand, allow_polymorphic); break; case Type_EnumeratedArray: @@ -4592,31 +4997,31 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_appendc(str, "#sparse"); } str = gb_string_append_rune(str, '['); - str = write_type_to_string(str, type->EnumeratedArray.index); + str = write_type_to_string(str, type->EnumeratedArray.index, shorthand, allow_polymorphic); str = gb_string_append_rune(str, ']'); - str = write_type_to_string(str, type->EnumeratedArray.elem); + str = write_type_to_string(str, type->EnumeratedArray.elem, shorthand, allow_polymorphic); break; case Type_Array: str = gb_string_appendc(str, gb_bprintf("[%lld]", cast(long long)type->Array.count)); - str = write_type_to_string(str, type->Array.elem); + str = write_type_to_string(str, type->Array.elem, shorthand, allow_polymorphic); break; case Type_Slice: str = gb_string_appendc(str, "[]"); - str = write_type_to_string(str, type->Array.elem); + str = write_type_to_string(str, type->Array.elem, shorthand, allow_polymorphic); break; case Type_DynamicArray: str = gb_string_appendc(str, "[dynamic]"); - str = write_type_to_string(str, type->DynamicArray.elem); + str = write_type_to_string(str, type->DynamicArray.elem, shorthand, allow_polymorphic); break; case Type_Enum: str = gb_string_appendc(str, "enum"); if (type->Enum.base_type != nullptr) { str = gb_string_appendc(str, " "); - str = write_type_to_string(str, type->Enum.base_type); + str = write_type_to_string(str, type->Enum.base_type, shorthand, allow_polymorphic); } str = gb_string_appendc(str, " {"); for_array(i, type->Enum.fields) { @@ -4633,6 +5038,13 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha case Type_Union: str = gb_string_appendc(str, "union"); + + if (allow_polymorphic && type->Struct.polymorphic_params) { + str = gb_string_appendc(str, "("); + str = write_type_to_string(str, type->Struct.polymorphic_params, shorthand, allow_polymorphic); + str = gb_string_appendc(str, ")"); + } + switch (type->Union.kind) { case UnionType_no_nil: str = gb_string_appendc(str, " #no_nil"); break; case UnionType_shared_nil: str = gb_string_appendc(str, " #shared_nil"); break; @@ -4642,7 +5054,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha for_array(i, type->Union.variants) { Type *t = type->Union.variants[i]; if (i > 0) str = gb_string_appendc(str, ", "); - str = write_type_to_string(str, t); + str = write_type_to_string(str, t, shorthand, allow_polymorphic); } str = gb_string_append_rune(str, '}'); break; @@ -4655,17 +5067,23 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha case StructSoa_Dynamic: str = gb_string_appendc(str, "#soa[dynamic]"); break; default: GB_PANIC("Unknown StructSoaKind"); break; } - str = write_type_to_string(str, type->Struct.soa_elem); + str = write_type_to_string(str, type->Struct.soa_elem, shorthand, allow_polymorphic); break; } str = gb_string_appendc(str, "struct"); + + if (allow_polymorphic && type->Struct.polymorphic_params) { + str = gb_string_appendc(str, "("); + str = write_type_to_string(str, type->Struct.polymorphic_params, shorthand, allow_polymorphic); + str = gb_string_appendc(str, ")"); + } + if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed"); if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union"); - if (type->Struct.is_no_copy) str = gb_string_appendc(str, " #no_copy"); if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align); - str = gb_string_appendc(str, " {"); + str = gb_string_appendc(str, " {"); if (shorthand && type->Struct.fields.count > 16) { str = gb_string_append_fmt(str, "%lld fields...", cast(long long)type->Struct.fields.count); @@ -4678,7 +5096,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha } str = gb_string_append_length(str, f->token.string.text, f->token.string.len); str = gb_string_appendc(str, ": "); - str = write_type_to_string(str, f->type); + str = write_type_to_string(str, f->type, shorthand, allow_polymorphic); } } str = gb_string_append_rune(str, '}'); @@ -4686,9 +5104,9 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha case Type_Map: { str = gb_string_appendc(str, "map["); - str = write_type_to_string(str, type->Map.key); + str = write_type_to_string(str, type->Map.key, shorthand, allow_polymorphic); str = gb_string_append_rune(str, ']'); - str = write_type_to_string(str, type->Map.value); + str = write_type_to_string(str, type->Map.value, shorthand, allow_polymorphic); } break; case Type_Named: @@ -4718,9 +5136,11 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_append_length(str, name.text, name.len); if (!is_type_untyped(var->type)) { str = gb_string_appendc(str, ": "); - str = write_type_to_string(str, var->type); - str = gb_string_appendc(str, " = "); - str = write_exact_value_to_string(str, var->Constant.value); + str = write_type_to_string(str, var->type, shorthand, allow_polymorphic); + if (var->Constant.value.kind) { + str = gb_string_appendc(str, " = "); + str = write_exact_value_to_string(str, var->Constant.value); + } } else { str = gb_string_appendc(str, " := "); str = write_exact_value_to_string(str, var->Constant.value); @@ -4736,20 +5156,31 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha Type *slice = base_type(var->type); str = gb_string_appendc(str, ".."); GB_ASSERT(var->type->kind == Type_Slice); - str = write_type_to_string(str, slice->Slice.elem); + str = write_type_to_string(str, slice->Slice.elem, shorthand, allow_polymorphic); } else { - str = write_type_to_string(str, var->type); + str = write_type_to_string(str, var->type, shorthand, allow_polymorphic); } } else { GB_ASSERT(var->kind == Entity_TypeName); if (var->type->kind == Type_Generic) { - str = gb_string_appendc(str, "typeid/"); - str = write_type_to_string(str, var->type); + if (var->token.string.len != 0) { + String name = var->token.string; + str = gb_string_appendc(str, "$"); + str = gb_string_append_length(str, name.text, name.len); + str = gb_string_appendc(str, ": typeid"); + if (var->type->Generic.specialized) { + str = gb_string_appendc(str, "/"); + str = write_type_to_string(str, var->type->Generic.specialized, shorthand, allow_polymorphic); + } + } else { + str = gb_string_appendc(str, "typeid/"); + str = write_type_to_string(str, var->type, shorthand, allow_polymorphic); + } } else { str = gb_string_appendc(str, "$"); str = gb_string_append_length(str, name.text, name.len); str = gb_string_appendc(str, "="); - str = write_type_to_string(str, var->type); + str = write_type_to_string(str, var->type, shorthand, allow_polymorphic); } } } @@ -4795,7 +5226,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha } str = gb_string_appendc(str, "("); if (type->Proc.params) { - str = write_type_to_string(str, type->Proc.params); + str = write_type_to_string(str, type->Proc.params, shorthand, allow_polymorphic); } str = gb_string_appendc(str, ")"); if (type->Proc.results) { @@ -4803,7 +5234,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha if (type->Proc.results->Tuple.variables.count > 1) { str = gb_string_appendc(str, "("); } - str = write_type_to_string(str, type->Proc.results); + str = write_type_to_string(str, type->Proc.results, shorthand, allow_polymorphic); if (type->Proc.results->Tuple.variables.count > 1) { str = gb_string_appendc(str, ")"); } @@ -4815,7 +5246,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha if (type->BitSet.elem == nullptr) { str = gb_string_appendc(str, ""); } else if (is_type_enum(type->BitSet.elem)) { - str = write_type_to_string(str, type->BitSet.elem); + str = write_type_to_string(str, type->BitSet.elem, shorthand, allow_polymorphic); } else { str = gb_string_append_fmt(str, "%lld", type->BitSet.lower); str = gb_string_append_fmt(str, "..="); @@ -4823,14 +5254,14 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha } if (type->BitSet.underlying != nullptr) { str = gb_string_appendc(str, "; "); - str = write_type_to_string(str, type->BitSet.underlying); + str = write_type_to_string(str, type->BitSet.underlying, shorthand, allow_polymorphic); } str = gb_string_appendc(str, "]"); break; case Type_SimdVector: str = gb_string_append_fmt(str, "#simd[%d]", cast(int)type->SimdVector.count); - str = write_type_to_string(str, type->SimdVector.elem); + str = write_type_to_string(str, type->SimdVector.elem, shorthand, allow_polymorphic); break; case Type_Matrix: @@ -4838,12 +5269,12 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_appendc(str, "#row_major "); } str = gb_string_appendc(str, gb_bprintf("matrix[%d, %d]", cast(int)type->Matrix.row_count, cast(int)type->Matrix.column_count)); - str = write_type_to_string(str, type->Matrix.elem); + str = write_type_to_string(str, type->Matrix.elem, shorthand, allow_polymorphic); break; case Type_BitField: str = gb_string_appendc(str, "bit_field "); - str = write_type_to_string(str, type->BitField.backing_type); + str = write_type_to_string(str, type->BitField.backing_type, shorthand, allow_polymorphic); str = gb_string_appendc(str, " {"); for (isize i = 0; i < type->BitField.fields.count; i++) { Entity *f = type->BitField.fields[i]; @@ -4852,7 +5283,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha } str = gb_string_append_length(str, f->token.string.text, f->token.string.len); str = gb_string_appendc(str, ": "); - str = write_type_to_string(str, f->type); + str = write_type_to_string(str, f->type, shorthand, allow_polymorphic); str = gb_string_append_fmt(str, " | %u", type->BitField.bit_sizes[i]); } str = gb_string_appendc(str, " }"); @@ -4870,6 +5301,11 @@ gb_internal gbString type_to_string(Type *type, bool shorthand) { return write_type_to_string(gb_string_make(heap_allocator(), ""), type, shorthand); } +gb_internal gbString type_to_string_polymorphic(Type *type) { + return write_type_to_string(gb_string_make(heap_allocator(), ""), type, false, true); +} + + gb_internal gbString type_to_string_shorthand(Type *type) { return type_to_string(type, true); } diff --git a/tests/benchmark/all.odin b/tests/benchmark/all.odin index a48872cc6..30640ac87 100644 --- a/tests/benchmark/all.odin +++ b/tests/benchmark/all.odin @@ -4,3 +4,4 @@ package benchmarks @(require) import "crypto" @(require) import "hash" @(require) import "text/regex" +@(require) import "strings" \ No newline at end of file diff --git a/tests/benchmark/bytes/benchmark_bytes.odin b/tests/benchmark/bytes/benchmark_bytes.odin index 13ef8f9a5..ee3a91d64 100644 --- a/tests/benchmark/bytes/benchmark_bytes.odin +++ b/tests/benchmark/bytes/benchmark_bytes.odin @@ -54,14 +54,15 @@ run_trial_size :: proc(p: proc "contextless" ([]u8, byte) -> int, size: int, idx accumulator: int - for _ in 0.. 1 { + table.row(&tbl) + } + + algo_name := aead.ALGORITHM_NAMES[algo] + key_sz := aead.KEY_SIZES[algo] + + key := make([]byte, key_sz, context.temp_allocator) + crypto.rand_bytes(key) + + // TODO: Benchmark all available imlementations? + ctx: aead.Context + aead.init(&ctx, algo, key) + + for sz, _ in SIZES { + options := &time.Benchmark_Options{ + rounds = ITERS, + bytes = aead.IV_SIZES[algo] + sz, + setup = setup_sized_buf, + bench = do_bench_aead, + teardown = teardown_sized_buf, + } + context.user_ptr = &ctx + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil) + + time_per_iter := options.duration / ITERS + table.aligned_row_of_values( + &tbl, + .Right, + algo_name, + table.format(&tbl, "%d", sz), + table.format(&tbl, "%8M", time_per_iter), + table.format(&tbl, "%5.3f MiB/s", options.megabytes_per_second), + ) + } + } + + log_table(&tbl) +} + +@(private = "file") +do_bench_aead :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + tag_: [aead.MAX_TAG_SIZE]byte + + ctx := (^aead.Context)(context.user_ptr) + iv_sz := aead.iv_size(ctx) + + iv := options.input[:iv_sz] + buf := options.input[iv_sz:] + tag := tag_[:aead.tag_size(ctx)] + + for _ in 0 ..= options.rounds { + aead.seal_ctx(ctx, buf, tag, iv, nil, buf) + } + options.count = options.rounds + options.processed = options.rounds * (options.bytes - iv_sz) + + return +} diff --git a/tests/benchmark/crypto/benchmark_crypto.odin b/tests/benchmark/crypto/benchmark_crypto.odin deleted file mode 100644 index b139ea669..000000000 --- a/tests/benchmark/crypto/benchmark_crypto.odin +++ /dev/null @@ -1,415 +0,0 @@ -package benchmark_core_crypto - -import "base:runtime" -import "core:encoding/hex" -import "core:fmt" -import "core:log" -import "core:strings" -import "core:testing" -import "core:time" - -import "core:crypto/aes" -import "core:crypto/chacha20" -import "core:crypto/chacha20poly1305" -import "core:crypto/ed25519" -import "core:crypto/poly1305" -import "core:crypto/x25519" - -// Cryptographic primitive benchmarks. - -@(test) -benchmark_crypto :: proc(t: ^testing.T) { - runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() - - str: strings.Builder - strings.builder_init(&str, context.allocator) - defer { - log.info(strings.to_string(str)) - strings.builder_destroy(&str) - } - - { - name := "AES256-CTR 64 bytes" - options := &time.Benchmark_Options { - rounds = 1_000, - bytes = 64, - setup = _setup_sized_buf, - bench = _benchmark_aes256_ctr, - teardown = _teardown_sized_buf, - } - - err := time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - - name = "AES256-CTR 1024 bytes" - options.bytes = 1024 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - - name = "AES256-CTR 65536 bytes" - options.bytes = 65536 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - } - { - name := "ChaCha20 64 bytes" - options := &time.Benchmark_Options { - rounds = 1_000, - bytes = 64, - setup = _setup_sized_buf, - bench = _benchmark_chacha20, - teardown = _teardown_sized_buf, - } - - err := time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - - name = "ChaCha20 1024 bytes" - options.bytes = 1024 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - - name = "ChaCha20 65536 bytes" - options.bytes = 65536 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - } - { - name := "Poly1305 64 zero bytes" - options := &time.Benchmark_Options { - rounds = 1_000, - bytes = 64, - setup = _setup_sized_buf, - bench = _benchmark_poly1305, - teardown = _teardown_sized_buf, - } - - err := time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - - name = "Poly1305 1024 zero bytes" - options.bytes = 1024 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - } - { - name := "chacha20poly1305 64 bytes" - options := &time.Benchmark_Options { - rounds = 1_000, - bytes = 64, - setup = _setup_sized_buf, - bench = _benchmark_chacha20poly1305, - teardown = _teardown_sized_buf, - } - - err := time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - - name = "chacha20poly1305 1024 bytes" - options.bytes = 1024 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - - name = "chacha20poly1305 65536 bytes" - options.bytes = 65536 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - } - { - name := "AES256-GCM 64 bytes" - options := &time.Benchmark_Options { - rounds = 1_000, - bytes = 64, - setup = _setup_sized_buf, - bench = _benchmark_aes256_gcm, - teardown = _teardown_sized_buf, - } - - key := [aes.KEY_SIZE_256]byte { - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - } - ctx: aes.Context_GCM - aes.init_gcm(&ctx, key[:]) - - context.user_ptr = &ctx - - err := time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - - name = "AES256-GCM 1024 bytes" - options.bytes = 1024 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - - name = "AES256-GCM 65536 bytes" - options.bytes = 65536 - err = time.benchmark(options, context.allocator) - testing.expect(t, err == nil, name) - benchmark_print(&str, name, options) - } - { - iters :: 10000 - - priv_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" - priv_bytes, _ := hex.decode(transmute([]byte)(priv_str), context.temp_allocator) - priv_key: ed25519.Private_Key - start := time.now() - for i := 0; i < iters; i = i + 1 { - ok := ed25519.private_key_set_bytes(&priv_key, priv_bytes) - assert(ok, "private key should deserialize") - } - elapsed := time.since(start) - fmt.sbprintfln(&str, - "ed25519.private_key_set_bytes: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) - - pub_bytes := priv_key._pub_key._b[:] // "I know what I am doing" - pub_key: ed25519.Public_Key - start = time.now() - for i := 0; i < iters; i = i + 1 { - ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes[:]) - assert(ok, "public key should deserialize") - } - elapsed = time.since(start) - fmt.sbprintfln(&str, - "ed25519.public_key_set_bytes: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) - - msg := "Got a job for you, 621." - sig_bytes: [ed25519.SIGNATURE_SIZE]byte - msg_bytes := transmute([]byte)(msg) - start = time.now() - for i := 0; i < iters; i = i + 1 { - ed25519.sign(&priv_key, msg_bytes, sig_bytes[:]) - } - elapsed = time.since(start) - fmt.sbprintfln(&str, - "ed25519.sign: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) - - start = time.now() - for i := 0; i < iters; i = i + 1 { - ok := ed25519.verify(&pub_key, msg_bytes, sig_bytes[:]) - assert(ok, "signature should validate") - } - elapsed = time.since(start) - fmt.sbprintfln(&str, - "ed25519.verify: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) - } - { - point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" - scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" - - point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator) - scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator) - out: [x25519.POINT_SIZE]byte = --- - - iters :: 10000 - start := time.now() - for i := 0; i < iters; i = i + 1 { - x25519.scalarmult(out[:], scalar[:], point[:]) - } - elapsed := time.since(start) - - fmt.sbprintfln(&str, - "x25519.scalarmult: ~%f us/op", - time.duration_microseconds(elapsed) / iters, - ) - } -} - -@(private) -_setup_sized_buf :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - assert(options != nil) - - options.input = make([]u8, options.bytes, allocator) - return nil if len(options.input) == options.bytes else .Allocation_Error -} - -@(private) -_teardown_sized_buf :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - assert(options != nil) - - delete(options.input) - return nil -} - -@(private) -_benchmark_chacha20 :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - buf := options.input - key := [chacha20.KEY_SIZE]byte { - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - } - iv := [chacha20.IV_SIZE]byte { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - } - - ctx: chacha20.Context = --- - chacha20.init(&ctx, key[:], iv[:]) - - for _ in 0 ..= options.rounds { - chacha20.xor_bytes(&ctx, buf, buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - return nil -} - -@(private) -_benchmark_poly1305 :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - buf := options.input - key := [poly1305.KEY_SIZE]byte { - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - } - - tag: [poly1305.TAG_SIZE]byte = --- - for _ in 0 ..= options.rounds { - poly1305.sum(tag[:], buf, key[:]) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - //options.hash = u128(h) - return nil -} - -@(private) -_benchmark_chacha20poly1305 :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - buf := options.input - key := [chacha20.KEY_SIZE]byte { - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - } - iv := [chacha20.IV_SIZE]byte { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - } - - ctx: chacha20poly1305.Context = --- - chacha20poly1305.init(&ctx, key[:]) // Basically 0 overhead. - - tag: [chacha20poly1305.TAG_SIZE]byte = --- - - for _ in 0 ..= options.rounds { - chacha20poly1305.seal(&ctx, buf, tag[:], iv[:], nil, buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - return nil -} - -@(private) -_benchmark_aes256_ctr :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - buf := options.input - key := [aes.KEY_SIZE_256]byte { - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, - } - iv := [aes.CTR_IV_SIZE]byte { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - } - - ctx: aes.Context_CTR = --- - aes.init_ctr(&ctx, key[:], iv[:]) - - for _ in 0 ..= options.rounds { - aes.xor_bytes_ctr(&ctx, buf, buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - return nil -} - -_benchmark_aes256_gcm :: proc( - options: ^time.Benchmark_Options, - allocator := context.allocator, -) -> ( - err: time.Benchmark_Error, -) { - buf := options.input - iv: [aes.GCM_IV_SIZE]byte - tag: [aes.GCM_TAG_SIZE]byte = --- - - ctx := (^aes.Context_GCM)(context.user_ptr) - - for _ in 0 ..= options.rounds { - aes.seal_gcm(ctx, buf, tag[:], iv[:], nil, buf) - } - options.count = options.rounds - options.processed = options.rounds * options.bytes - return nil -} - -@(private) -benchmark_print :: proc(str: ^strings.Builder, name: string, options: ^time.Benchmark_Options, loc := #caller_location) { - fmt.sbprintfln(str, "[%v] %v rounds, %v bytes processed in %v ns\n\t\t%5.3f rounds/s, %5.3f MiB/s\n", - name, - options.rounds, - options.processed, - time.duration_nanoseconds(options.duration), - options.rounds_per_second, - options.megabytes_per_second, - ) -} diff --git a/tests/benchmark/crypto/benchmark_ecc.odin b/tests/benchmark/crypto/benchmark_ecc.odin new file mode 100644 index 000000000..16ca798dc --- /dev/null +++ b/tests/benchmark/crypto/benchmark_ecc.odin @@ -0,0 +1,163 @@ +package benchmark_core_crypto + +import "base:runtime" +import "core:encoding/hex" +import "core:testing" +import "core:text/table" +import "core:time" + +import "core:crypto/ed25519" +import "core:crypto/x25519" +import "core:crypto/x448" + +@(private = "file") +ECDH_ITERS :: 10000 +@(private = "file") +DSA_ITERS :: 10000 + +@(test) +benchmark_crypto_ecc :: proc(t: ^testing.T) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + bench_ecdh() + bench_dsa() +} + +@(private = "file") +bench_ecdh :: proc() { + tbl: table.Table + table.init(&tbl) + defer table.destroy(&tbl) + + table.caption(&tbl, "ECDH") + table.aligned_header_of_values(&tbl, .Right, "Algorithm", "Scalar-Basepoint", "Scalar-Point") + + append_tbl := proc(tbl: ^table.Table, algo_name: string, bp, sc: time.Duration) { + table.aligned_row_of_values( + tbl, + .Right, + algo_name, + table.format(tbl, "%8M", bp), + table.format(tbl, "%8M", sc), + ) + } + + scalar_bp, scalar := bench_x25519() + append_tbl(&tbl, "X25519", scalar_bp, scalar) + + scalar_bp, scalar = bench_x448() + append_tbl(&tbl, "X448", scalar_bp, scalar) + + log_table(&tbl) +} + +@(private = "file") +bench_x25519 :: proc() -> (bp, sc: time.Duration) { + point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" + + point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator) + scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator) + out: [x25519.POINT_SIZE]byte = --- + + start := time.tick_now() + for _ in 0 ..< ECDH_ITERS { + x25519.scalarmult_basepoint(out[:], scalar[:]) + } + bp = time.tick_since(start) / ECDH_ITERS + + start = time.tick_now() + for _ in 0 ..< ECDH_ITERS { + x25519.scalarmult(out[:], scalar[:], point[:]) + } + sc = time.tick_since(start) / ECDH_ITERS + + return +} + +@(private = "file") +bench_x448 :: proc() -> (bp, sc: time.Duration) { + point_str := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + scalar_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" + + point, _ := hex.decode(transmute([]byte)(point_str), context.temp_allocator) + scalar, _ := hex.decode(transmute([]byte)(scalar_str), context.temp_allocator) + out: [x448.POINT_SIZE]byte = --- + + start := time.tick_now() + for _ in 0 ..< ECDH_ITERS { + x448.scalarmult_basepoint(out[:], scalar[:]) + } + bp = time.tick_since(start) / ECDH_ITERS + + start = time.tick_now() + for _ in 0 ..< ECDH_ITERS { + x448.scalarmult(out[:], scalar[:], point[:]) + } + sc = time.tick_since(start) / ECDH_ITERS + + return +} + +@(private = "file") +bench_dsa :: proc() { + tbl: table.Table + table.init(&tbl) + defer table.destroy(&tbl) + + table.caption(&tbl, "ECDSA/EdDSA") + table.aligned_header_of_values(&tbl, .Right, "Algorithm", "Op", "Time") + + append_tbl := proc(tbl: ^table.Table, algo_name, op: string, t: time.Duration) { + table.aligned_row_of_values( + tbl, + .Right, + algo_name, + op, + table.format(tbl, "%8M", t), + ) + } + + sk, sig, verif := bench_ed25519() + append_tbl(&tbl, "ed25519", "private_key_set_bytes", sk) + append_tbl(&tbl, "ed25519", "sign", sig) + append_tbl(&tbl, "ed25519", "verify", verif) + + log_table(&tbl) +} + +@(private = "file") +bench_ed25519 :: proc() -> (sk, sig, verif: time.Duration) { + priv_str := "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe" + priv_bytes, _ := hex.decode(transmute([]byte)(priv_str), context.temp_allocator) + priv_key: ed25519.Private_Key + start := time.tick_now() + for _ in 0 ..< DSA_ITERS { + ok := ed25519.private_key_set_bytes(&priv_key, priv_bytes) + assert(ok, "private key should deserialize") + } + sk = time.tick_since(start) / DSA_ITERS + + pub_bytes := priv_key._pub_key._b[:] // "I know what I am doing" + pub_key: ed25519.Public_Key + ok := ed25519.public_key_set_bytes(&pub_key, pub_bytes[:]) + assert(ok, "public key should deserialize") + + msg := "Got a job for you, 621." + sig_bytes: [ed25519.SIGNATURE_SIZE]byte + msg_bytes := transmute([]byte)(msg) + start = time.tick_now() + for _ in 0 ..< DSA_ITERS { + ed25519.sign(&priv_key, msg_bytes, sig_bytes[:]) + } + sig = time.tick_since(start) / DSA_ITERS + + start = time.tick_now() + for _ in 0 ..< DSA_ITERS { + ok = ed25519.verify(&pub_key, msg_bytes, sig_bytes[:]) + assert(ok, "signature should validate") + } + verif = time.tick_since(start) / DSA_ITERS + + return +} diff --git a/tests/benchmark/crypto/benchmark_hash.odin b/tests/benchmark/crypto/benchmark_hash.odin new file mode 100644 index 000000000..f9c560e6d --- /dev/null +++ b/tests/benchmark/crypto/benchmark_hash.odin @@ -0,0 +1,101 @@ +package benchmark_core_crypto + +import "base:runtime" +import "core:testing" +import "core:text/table" +import "core:time" + +import "core:crypto/hash" + +@(private = "file") +ITERS :: 10000 +@(private = "file") +SIZES := []int{64, 1024, 65536} + +@(test) +benchmark_crypto_hash :: proc(t: ^testing.T) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + tbl: table.Table + table.init(&tbl) + defer table.destroy(&tbl) + + table.caption(&tbl, "Hash") + table.aligned_header_of_values(&tbl, .Right, "Algorithm", "Size", "Time", "Throughput") + + for algo, i in hash.Algorithm { + // Skip the sentinel value, and uncommon algorithms + #partial switch algo { + case .Invalid: + continue + case .Legacy_KECCAK_224, .Legacy_KECCAK_256, .Legacy_KECCAK_384, .Legacy_KECCAK_512: + // Skip: Legacy and not worth using over SHA3 + continue + case .Insecure_MD5, .Insecure_SHA1: + // Skip: Legacy and not worth using at all + continue + case .SHA224, .SHA384, .SHA3_224, .SHA3_384: + // Skip: Uncommon SHA2/SHA3 variants + continue + case .SM3: + // Skip: Liberty Prime is online. All systems nominal. + // Weapons hot. Mission: the destruction of any and + // all Chinese communists. + continue + } + if i > 1 { + table.row(&tbl) + } + + algo_name := hash.ALGORITHM_NAMES[algo] + + for sz, _ in SIZES { + options := &time.Benchmark_Options{ + rounds = ITERS, + bytes = sz, + setup = setup_sized_buf, + bench = do_bench_hash, + teardown = teardown_sized_buf, + } + tmp := algo + context.user_ptr = &tmp + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil) + + time_per_iter := options.duration / ITERS + table.aligned_row_of_values( + &tbl, + .Right, + algo_name, + table.format(&tbl, "%d", sz), + table.format(&tbl, "%8M", time_per_iter), + table.format(&tbl, "%5.3f MiB/s", options.megabytes_per_second), + ) + } + } + + log_table(&tbl) +} + +@(private = "file") +do_bench_hash :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + digest_: [hash.MAX_DIGEST_SIZE]byte + + buf := options.input + algo := (^hash.Algorithm)(context.user_ptr)^ + digest := digest_[:hash.DIGEST_SIZES[algo]] + + for _ in 0 ..= options.rounds { + hash.hash_bytes_to_buffer(algo, buf, digest) + } + options.count = options.rounds + options.processed = options.rounds * (options.bytes) + + return +} diff --git a/tests/benchmark/crypto/benchmark_mac.odin b/tests/benchmark/crypto/benchmark_mac.odin new file mode 100644 index 000000000..a0d2cae90 --- /dev/null +++ b/tests/benchmark/crypto/benchmark_mac.odin @@ -0,0 +1,191 @@ +package benchmark_core_crypto + +import "base:runtime" +import "core:testing" +import "core:text/table" +import "core:time" + +import "core:crypto/hmac" +import "core:crypto/kmac" +import "core:crypto/poly1305" + +@(private = "file") +ITERS :: 10000 +@(private = "file") +SIZES := []int{64, 1024, 65536} +@(private = "file") +KMAC_KEY_SIZES := []int{128, 256} + +@(test) +benchmark_crypto_mac :: proc(t: ^testing.T) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + tbl: table.Table + table.init(&tbl) + defer table.destroy(&tbl) + + table.caption(&tbl, "MAC") + table.aligned_header_of_values(&tbl, .Right, "Algorithm", "Size", "Time", "Throughput") + + { + for sz, _ in SIZES { + options := &time.Benchmark_Options{ + rounds = ITERS, + bytes = sz, + setup = setup_sized_buf, + bench = do_bench_hmac_sha_256, + teardown = teardown_sized_buf, + } + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil) + + time_per_iter := options.duration / ITERS + table.aligned_row_of_values( + &tbl, + .Right, + "HMAC-SHA256", + table.format(&tbl, "%d", sz), + table.format(&tbl, "%8M", time_per_iter), + table.format(&tbl, "%5.3f MiB/s", options.megabytes_per_second), + ) + } + } + + table.row(&tbl) + + for key_sz, i in KMAC_KEY_SIZES { + if i > 0 { + table.row(&tbl) + } + + for sz, _ in SIZES { + options := &time.Benchmark_Options{ + rounds = ITERS, + bytes = sz, + processed = key_sz, // Pls ignore. + setup = setup_sized_buf, + bench = do_bench_kmac, + teardown = teardown_sized_buf, + } + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil) + + time_per_iter := options.duration / ITERS + table.aligned_row_of_values( + &tbl, + .Right, + table.format(&tbl, "KMAC%d", key_sz), + table.format(&tbl, "%d", sz), + table.format(&tbl, "%8M", time_per_iter), + table.format(&tbl, "%5.3f MiB/s", options.megabytes_per_second), + ) + } + } + + table.row(&tbl) + + { + for sz, _ in SIZES { + options := &time.Benchmark_Options{ + rounds = ITERS, + bytes = sz, + setup = setup_sized_buf, + bench = do_bench_poly1305, + teardown = teardown_sized_buf, + } + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil) + + time_per_iter := options.duration / ITERS + table.aligned_row_of_values( + &tbl, + .Right, + "poly1305", + table.format(&tbl, "%d", sz), + table.format(&tbl, "%8M", time_per_iter), + table.format(&tbl, "%5.3f MiB/s", options.megabytes_per_second), + ) + } + } + + log_table(&tbl) +} + +@(private = "file") +do_bench_hmac_sha_256 :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + buf := options.input + key := [32]byte { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + + tag: [32]byte = --- + for _ in 0 ..= options.rounds { + hmac.sum(.SHA256, tag[:], buf, key[:]) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + + return +} + +@(private = "file") +do_bench_kmac :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + buf := options.input + key := [kmac.MIN_KEY_SIZE_256]byte { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + sec_strength := options.processed + + tag: [32]byte = --- + for _ in 0 ..= options.rounds { + kmac.sum(sec_strength, tag[:sec_strength/8], buf, key[:], nil) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + + return +} + +@(private = "file") +do_bench_poly1305 :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + buf := options.input + key := [poly1305.KEY_SIZE]byte { + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + } + + tag: [poly1305.TAG_SIZE]byte = --- + for _ in 0 ..= options.rounds { + poly1305.sum(tag[:], buf, key[:]) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + + return +} diff --git a/tests/benchmark/crypto/benchmark_stream.odin b/tests/benchmark/crypto/benchmark_stream.odin new file mode 100644 index 000000000..38c5a87c6 --- /dev/null +++ b/tests/benchmark/crypto/benchmark_stream.odin @@ -0,0 +1,145 @@ +package benchmark_core_crypto + +import "base:runtime" +import "core:crypto" +import "core:testing" +import "core:text/table" +import "core:time" + +import "core:crypto/aes" +import "core:crypto/chacha20" + +@(private = "file") +ITERS :: 10000 +@(private = "file") +SIZES := []int{64, 1024, 65536} +@(private = "file") +AES_CTR_KEY_SIZES := []int{128, 192, 256} + +@(test) +benchmark_crypto_stream :: proc(t: ^testing.T) { + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + tbl: table.Table + table.init(&tbl) + defer table.destroy(&tbl) + + table.caption(&tbl, "Stream Cipher") + table.aligned_header_of_values(&tbl, .Right, "Algorithm", "Size", "Time", "Throughput") + + for key_sz, i in AES_CTR_KEY_SIZES { + if i > 0 { + table.row(&tbl) + } + + key := make([]byte, key_sz/8, context.temp_allocator) + iv := make([]byte, aes.CTR_IV_SIZE, context.temp_allocator) + crypto.rand_bytes(key) + crypto.rand_bytes(iv) + + ctx: aes.Context_CTR + aes.init_ctr(&ctx, key, iv) + + for sz, _ in SIZES { + options := &time.Benchmark_Options{ + rounds = ITERS, + bytes = sz, + setup = setup_sized_buf, + bench = do_bench_aes_ctr, + teardown = teardown_sized_buf, + } + context.user_ptr = &ctx + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil) + + time_per_iter := options.duration / ITERS + table.aligned_row_of_values( + &tbl, + .Right, + table.format(&tbl, "AES%d-CTR", key_sz), + table.format(&tbl, "%d", sz), + table.format(&tbl, "%8M", time_per_iter), + table.format(&tbl, "%5.3f MiB/s", options.megabytes_per_second), + ) + } + } + + table.row(&tbl) + + { + key := make([]byte, chacha20.KEY_SIZE, context.temp_allocator) + iv := make([]byte, chacha20.IV_SIZE, context.temp_allocator) + crypto.rand_bytes(key) + crypto.rand_bytes(iv) + + ctx: chacha20.Context + chacha20.init(&ctx, key, iv) + + for sz, _ in SIZES { + options := &time.Benchmark_Options{ + rounds = ITERS, + bytes = sz, + setup = setup_sized_buf, + bench = do_bench_chacha20, + teardown = teardown_sized_buf, + } + context.user_ptr = &ctx + + err := time.benchmark(options, context.allocator) + testing.expect(t, err == nil) + + time_per_iter := options.duration / ITERS + table.aligned_row_of_values( + &tbl, + .Right, + "chacha20", + table.format(&tbl, "%d", sz), + table.format(&tbl, "%8M", time_per_iter), + table.format(&tbl, "%5.3f MiB/s", options.megabytes_per_second), + ) + } + } + + log_table(&tbl) +} + +@(private = "file") +do_bench_aes_ctr :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + ctx := (^aes.Context_CTR)(context.user_ptr) + + buf := options.input + + for _ in 0 ..= options.rounds { + aes.xor_bytes_ctr(ctx, buf, buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + + return +} + +@(private = "file") +do_bench_chacha20 :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + ctx := (^chacha20.Context)(context.user_ptr) + + buf := options.input + + for _ in 0 ..= options.rounds { + chacha20.xor_bytes(ctx, buf, buf) + } + options.count = options.rounds + options.processed = options.rounds * options.bytes + + return +} diff --git a/tests/benchmark/crypto/benchmark_utils.odin b/tests/benchmark/crypto/benchmark_utils.odin new file mode 100644 index 000000000..6609adbf7 --- /dev/null +++ b/tests/benchmark/crypto/benchmark_utils.odin @@ -0,0 +1,50 @@ +package benchmark_core_crypto + +import "core:crypto" +import "core:fmt" +import "core:log" +import "core:strings" +import "core:text/table" +import "core:time" + +@(private) +log_table :: #force_inline proc(tbl: ^table.Table) { + sb := strings.builder_make() + defer strings.builder_destroy(&sb) + + wr := strings.to_writer(&sb) + + fmt.sbprintln(&sb) + table.write_plain_table(wr, tbl) + + log.info(strings.to_string(sb)) +} + +@(private) +setup_sized_buf :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + assert(options != nil) + + options.input = make([]u8, options.bytes, allocator) + if len(options.input) > 0 { + crypto.rand_bytes(options.input) + } + return nil if len(options.input) == options.bytes else .Allocation_Error +} + +@(private) +teardown_sized_buf :: proc( + options: ^time.Benchmark_Options, + allocator := context.allocator, +) -> ( + err: time.Benchmark_Error, +) { + assert(options != nil) + + delete(options.input) + return nil +} diff --git a/tests/benchmark/runtime/benchmark_runtime.odin b/tests/benchmark/runtime/benchmark_runtime.odin new file mode 100644 index 000000000..871fb05e6 --- /dev/null +++ b/tests/benchmark/runtime/benchmark_runtime.odin @@ -0,0 +1,227 @@ +package benchmark_runtime + +import "base:runtime" +import "core:fmt" +import "core:log" +import "core:testing" +import "core:strings" +import "core:text/table" +import "core:time" + +RUNS_PER_SIZE :: 2500 + +sizes := [?]int { + 7, 8, 9, + 15, 16, 17, + 31, 32, 33, + 63, 64, 65, + 95, 96, 97, + 128, + 256, + 512, + 1024, + 4096, + 1024 * 1024, +} + +// These are the normal, unoptimized algorithms. + +plain_memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { + switch { + case n == 0: return true + case x == y: return true + } + a, b := ([^]byte)(x), ([^]byte)(y) + length := uint(n) + + for i := uint(0); i < length; i += 1 { + if a[i] != b[i] { + return false + } + } + return true +} + +plain_memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check { + switch { + case a == b: return 0 + case a == nil: return -1 + case b == nil: return +1 + } + + x := uintptr(a) + y := uintptr(b) + n := uintptr(n) + + SU :: size_of(uintptr) + fast := n/SU + 1 + offset := (fast-1)*SU + curr_block := uintptr(0) + if n < SU { + fast = 0 + } + + for /**/; curr_block < fast; curr_block += 1 { + va := (^uintptr)(x + curr_block * size_of(uintptr))^ + vb := (^uintptr)(y + curr_block * size_of(uintptr))^ + if va ~ vb != 0 { + for pos := curr_block*SU; pos < n; pos += 1 { + a := (^byte)(x+pos)^ + b := (^byte)(y+pos)^ + if a ~ b != 0 { + return -1 if (int(a) - int(b)) < 0 else +1 + } + } + } + } + + for /**/; offset < n; offset += 1 { + a := (^byte)(x+offset)^ + b := (^byte)(y+offset)^ + if a ~ b != 0 { + return -1 if (int(a) - int(b)) < 0 else +1 + } + } + + return 0 +} + +plain_memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check { + x := uintptr(a) + n := uintptr(n) + + SU :: size_of(uintptr) + fast := n/SU + 1 + offset := (fast-1)*SU + curr_block := uintptr(0) + if n < SU { + fast = 0 + } + + for /**/; curr_block < fast; curr_block += 1 { + va := (^uintptr)(x + curr_block * size_of(uintptr))^ + if va ~ 0 != 0 { + for pos := curr_block*SU; pos < n; pos += 1 { + a := (^byte)(x+pos)^ + if a ~ 0 != 0 { + return -1 if int(a) < 0 else +1 + } + } + } + } + + for /**/; offset < n; offset += 1 { + a := (^byte)(x+offset)^ + if a ~ 0 != 0 { + return -1 if int(a) < 0 else +1 + } + } + + return 0 +} + +run_trial_size_cmp :: proc(p: proc "contextless" (rawptr, rawptr, int) -> $R, size: int, idx: int, runs: int, loc := #caller_location) -> (timing: time.Duration) { + left := make([]u8, size) + right := make([]u8, size) + defer { + delete(left) + delete(right) + } + + right[idx] = 0x01 + + accumulator: int + + watch: time.Stopwatch + + time.stopwatch_start(&watch) + for _ in 0.. int, size: int, idx: int, runs: int, loc := #caller_location) -> (timing: time.Duration) { + data := make([]u8, size) + defer delete(data) + + data[idx] = 0x01 + + accumulator: int + + watch: time.Stopwatch + + time.stopwatch_start(&watch) + for _ in 0.. (n: int) { + _len := min(len(a), len(b)) + + // Scan for matches including partial codepoints. + #no_bounds_check for n < _len && a[n] == b[n] { + n += 1 + } + + // Now scan to ignore partial codepoints. + if n > 0 { + s := a[:n] + n = 0 + for { + r0, w := utf8.decode_rune(s[n:]) + if r0 != utf8.RUNE_ERROR { + n += w + } else { + break + } + } + } + return +} + +run_trial_size_prefix :: proc(p: proc "contextless" (string, string) -> $R, suffix: string, size: int, idx: int, runs: int, loc := #caller_location) -> (timing: time.Duration) { + left := make([]u8, size) + right := make([]u8, size) + defer { + delete(left) + delete(right) + } + + if len(suffix) > 0 { + copy(left [idx:], suffix) + copy(right[idx:], suffix) + + } else { + right[idx] = 'A' + } + + accumulator: int + + watch: time.Stopwatch + + time.stopwatch_start(&watch) + for _ in 0.. | | | fj ` \ ® ϱ ∳ ⁏ +
HHellope!
+
HHellope!
+
HHellope!
+
HHellope!
+
HHellope!
\ No newline at end of file diff --git a/tests/core/container/queue.odin b/tests/core/container/queue.odin new file mode 100644 index 000000000..56d2e1dca --- /dev/null +++ b/tests/core/container/queue.odin @@ -0,0 +1,157 @@ +package test_core_container + +import "base:runtime" +import "core:container/queue" +import "core:testing" + +@test +test_queue :: proc(t: ^testing.T) { + buf := [?]int{99, 99, 99, 99, 99} + q: queue.Queue(int) + + testing.expect(t, queue.init_from_slice(&q, buf[:])) + testing.expect_value(t, queue.reserve(&q, len(buf)), nil) + + queue.push_back(&q, 1) + queue.push_back_elems(&q, 2, 3) + queue.push_front(&q, 0) + + // { + // data = [1, 2, 3, 99, 0], + // len = 4, + // offset = 4, + // } + + testing.expect_value(t, queue.back(&q), 3) + testing.expect_value(t, queue.back_ptr(&q), &buf[2]) + testing.expect_value(t, queue.front(&q), 0) + testing.expect_value(t, queue.front_ptr(&q), &buf[4]) + + queue.get(&q, 3) + + for i in 0..<4 { + testing.expect_value(t, queue.get(&q, i), i) + queue.set(&q, i, i) + } + testing.expect_value(t, queue.get_ptr(&q, 3), &buf[2]) + + queue.consume_back(&q, 1) + queue.consume_front(&q, 1) + testing.expect_value(t, queue.pop_back(&q), 2) + v, ok := queue.pop_back_safe(&q) + testing.expect_value(t, v, 1) + testing.expect_value(t, ok, true) + + + // Test `init_with_contents`. + buf2 := [?]int{99, 3, 5} + + queue.init_with_contents(&q, buf2[:]) + push_ok, push_err := queue.push_back(&q, 1) + testing.expect(t, !push_ok) + testing.expect_value(t, push_err, runtime.Allocator_Error.Out_Of_Memory) + push_ok, push_err = queue.push_front(&q, 2) + testing.expect(t, !push_ok) + testing.expect_value(t, push_err, runtime.Allocator_Error.Out_Of_Memory) + + pop_front_v, pop_front_ok := queue.pop_front_safe(&q) + testing.expect(t, pop_front_ok) + testing.expect_value(t, pop_front_v, 99) + + // Re-initialization. + queue.init(&q, 0) + defer queue.destroy(&q) + + queue.push_back_elems(&q, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) + testing.expect_value(t, queue.len(q), 18) + queue.push_back_elems(&q, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18) + testing.expect_value(t, queue.len(q), 36) + + for i in 1..=18 { + testing.expect_value(t, queue.pop_front(&q), i) + } + for i in 1..=18 { + testing.expect_value(t, queue.pop_front(&q), i) + } +} + +@test +test_queue_grow_edge_case :: proc(t: ^testing.T) { + // Create a situation in which we trigger `q.offset + q.len > n` inside + // `_grow` to evaluate the `copy` behavior. + qq: queue.Queue(int) + queue.init(&qq, 0) + defer queue.destroy(&qq) + + queue.push_back_elems(&qq, 1, 2, 3, 4, 5, 6, 7) + testing.expect_value(t, queue.pop_front(&qq), 1) + testing.expect_value(t, queue.pop_front(&qq), 2) + testing.expect_value(t, queue.pop_front(&qq), 3) + queue.push_back(&qq, 8) + queue.push_back(&qq, 9) + + testing.expect_value(t, qq.len, 6) + testing.expect_value(t, qq.offset, 3) + testing.expect_value(t, len(qq.data), 8) // value contingent on smallest dynamic array capacity on first allocation + + queue.reserve(&qq, 16) + + testing.expect_value(t, queue.len(qq), 6) + for i in 4..=9 { + testing.expect_value(t, queue.pop_front(&qq), i) + } + testing.expect_value(t, queue.len(qq), 0) + + // If we made it to this point without failure, the queue should have + // copied the data into the right place after resizing the backing array. +} + +@test +test_queue_grow_edge_case_2 :: proc(t: ^testing.T) { + // Create a situation in which we trigger `insert_from + insert_to > sz` inside `push_back_elems` + // to evaluate the modified `insert_to` behavior. + qq: queue.Queue(int) + queue.init(&qq, 8) + defer queue.destroy(&qq) + + queue.push_back_elems(&qq, -1, -2, -3, -4, -5, -6, -7) + queue.consume_front(&qq, 3) + queue.push_back_elems(&qq, -8, -9, -10) + + queue.push_back_elems(&qq, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + + testing.expect_value(t, queue.len(qq), 17) + for i in 4..=10 { + testing.expect_value(t, queue.pop_front(&qq), -i) + } + for i in 1..=10 { + testing.expect_value(t, queue.pop_front(&qq), i) + } + testing.expect_value(t, queue.len(qq), 0) +} + +@test +test_queue_shrink :: proc(t: ^testing.T) { + qq: queue.Queue(int) + queue.init(&qq, 8) + defer queue.destroy(&qq) + + queue.push_back_elems(&qq, -1, -2, -3, -4, -5, -6, -7) + queue.consume_front(&qq, 3) + queue.push_back_elems(&qq, -8, -9, -10) + + queue.push_back_elems(&qq, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + + queue.shrink(&qq) + queue.consume_front(&qq, 7) + queue.shrink(&qq) + + for i in 1..=10 { + testing.expect_value(t, queue.pop_front(&qq), i) + } + + buf: [1]int + qq_backed: queue.Queue(int) + queue.init_from_slice(&qq_backed, buf[:]) + queue.shrink(&qq_backed) +} diff --git a/tests/core/container/test_core_small_array.odin b/tests/core/container/test_core_small_array.odin index 21f35f112..86342c6a5 100644 --- a/tests/core/container/test_core_small_array.odin +++ b/tests/core/container/test_core_small_array.odin @@ -54,6 +54,28 @@ test_small_array_push_back_elems :: proc(t: ^testing.T) { testing.expect(t, slice_equal(small_array.slice(&array), []int { 1, 2 })) } +@(test) +test_small_array_resize :: proc(t: ^testing.T) { + + array: small_array.Small_Array(4, int) + + for i in 0..<4 { + small_array.append(&array, i+1) + } + testing.expect(t, slice_equal(small_array.slice(&array), []int{1, 2, 3, 4}), "Expected to initialize the array with 1, 2, 3, 4") + + small_array.clear(&array) + testing.expect(t, slice_equal(small_array.slice(&array), []int{}), "Expected to clear the array") + + small_array.non_zero_resize(&array, 4) + testing.expect(t, slice_equal(small_array.slice(&array), []int{1, 2, 3, 4}), "Expected non_zero_resize to set length 4 with previous values") + + small_array.clear(&array) + small_array.resize(&array, 4) + testing.expect(t, slice_equal(small_array.slice(&array), []int{0, 0, 0, 0}), "Expected resize to set length 4 with zeroed values") +} + + slice_equal :: proc(a, b: []int) -> bool { if len(a) != len(b) { return false diff --git a/tests/core/crypto/test_core_crypto_aead.odin b/tests/core/crypto/test_core_crypto_aead.odin index 90eedc0b2..961311cd6 100644 --- a/tests/core/crypto/test_core_crypto_aead.odin +++ b/tests/core/crypto/test_core_crypto_aead.odin @@ -1,7 +1,10 @@ package test_core_crypto import "base:runtime" +import "core:crypto/aes" +import "core:crypto/aegis" import "core:crypto/aead" +import "core:crypto/deoxysii" import "core:encoding/hex" import "core:testing" @@ -17,6 +20,14 @@ test_aead :: proc(t: ^testing.T) { for impl in supported_chacha_impls() { append(&chacha_impls, impl) } + aegis_impls := make([dynamic]aead.Implementation, context.temp_allocator) + for impl in supported_aegis_impls() { + append(&aegis_impls, impl) + } + deoxysii_impls := make([dynamic]aead.Implementation, context.temp_allocator) + for impl in supported_deoxysii_impls() { + append(&deoxysii_impls, impl) + } impls := [aead.Algorithm][dynamic]aead.Implementation{ .Invalid = nil, .AES_GCM_128 = aes_impls, @@ -24,6 +35,11 @@ test_aead :: proc(t: ^testing.T) { .AES_GCM_256 = aes_impls, .CHACHA20POLY1305 = chacha_impls, .XCHACHA20POLY1305 = chacha_impls, + .AEGIS_128L = aegis_impls, + .AEGIS_128L_256 = aegis_impls, + .AEGIS_256 = aegis_impls, + .AEGIS_256_256 = aegis_impls, + .DEOXYS_II_256 = deoxysii_impls, } test_vectors := []struct{ @@ -224,6 +240,263 @@ test_aead :: proc(t: ^testing.T) { "bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b4522f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff921f9664c97637da9768812f615c68b13b52e", "c0875924c1c7987947deafd8780acf49", }, + // AEGIS-128L + // https://www.ietf.org/archive/id/draft-irtf-cfrg-aegis-aead-11.txt + { + .AEGIS_128L, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "", + "00000000000000000000000000000000", + "c1c0e58bd913006feba00f4b3cc3594e", + "abe0ece80c24868a226a35d16bdae37a", + }, + { + .AEGIS_128L_256, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "", + "00000000000000000000000000000000", + "c1c0e58bd913006feba00f4b3cc3594e", + "25835bfbb21632176cf03840687cb968cace4617af1bd0f7d064c639a5c79ee4", + }, + { + .AEGIS_128L, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "", + "", + "", + "c2b879a67def9d74e6c14f708bbcc9b4", + }, + { + .AEGIS_128L_256, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "", + "", + "", + "1360dc9db8ae42455f6e5b6a9d488ea4f2184c4e12120249335c4ee84bafe25d", + }, + { + .AEGIS_128L, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "0001020304050607", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "79d94593d8c2119d7e8fd9b8fc77845c5c077a05b2528b6ac54b563aed8efe84", + "cc6f3372f6aa1bb82388d695c3962d9a", + }, + { + .AEGIS_128L_256, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "0001020304050607", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "79d94593d8c2119d7e8fd9b8fc77845c5c077a05b2528b6ac54b563aed8efe84", + "022cb796fe7e0ae1197525ff67e309484cfbab6528ddef89f17d74ef8ecd82b3", + }, + { + .AEGIS_128L, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "0001020304050607", + "000102030405060708090a0b0c0d", + "79d94593d8c2119d7e8fd9b8fc77", + "5c04b3dba849b2701effbe32c7f0fab7", + }, + { + .AEGIS_128L_256, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "0001020304050607", + "000102030405060708090a0b0c0d", + "79d94593d8c2119d7e8fd9b8fc77", + "86f1b80bfb463aba711d15405d094baf4a55a15dbfec81a76f35ed0b9c8b04ac", + }, + { + .AEGIS_128L, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", + "b31052ad1cca4e291abcf2df3502e6bdb1bfd6db36798be3607b1f94d34478aa7ede7f7a990fec10", + "7542a745733014f9474417b337399507", + }, + { + .AEGIS_128L_256, + "10010000000000000000000000000000", + "10000200000000000000000000000000", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", + "b31052ad1cca4e291abcf2df3502e6bdb1bfd6db36798be3607b1f94d34478aa7ede7f7a990fec10", + "b91e2947a33da8bee89b6794e647baf0fc835ff574aca3fc27c33be0db2aff98", + }, + // AEGIS-256 + // https://www.ietf.org/archive/id/draft-irtf-cfrg-aegis-aead-11.txt + { + .AEGIS_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "", + "00000000000000000000000000000000", + "754fc3d8c973246dcc6d741412a4b236", + "3fe91994768b332ed7f570a19ec5896e", + }, + { + .AEGIS_256_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "", + "00000000000000000000000000000000", + "754fc3d8c973246dcc6d741412a4b236", + "1181a1d18091082bf0266f66297d167d2e68b845f61a3b0527d31fc7b7b89f13", + }, + { + .AEGIS_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "", + "", + "", + "e3def978a0f054afd1e761d7553afba3", + }, + { + .AEGIS_256_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "", + "", + "", + "6a348c930adbd654896e1666aad67de989ea75ebaa2b82fb588977b1ffec864a", + }, + { + .AEGIS_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "0001020304050607", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f373079ed84b2709faee373584585d60accd191db310ef5d8b11833df9dec711", + "8d86f91ee606e9ff26a01b64ccbdd91d", + }, + { + .AEGIS_256_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "0001020304050607", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f373079ed84b2709faee373584585d60accd191db310ef5d8b11833df9dec711", + "b7d28d0c3c0ebd409fd22b44160503073a547412da0854bfb9723020dab8da1a", + }, + { + .AEGIS_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "0001020304050607", + "000102030405060708090a0b0c0d", + "f373079ed84b2709faee37358458", + "c60b9c2d33ceb058f96e6dd03c215652", + }, + { + .AEGIS_256_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "0001020304050607", + "000102030405060708090a0b0c0d", + "f373079ed84b2709faee37358458", + "8c1cc703c81281bee3f6d9966e14948b4a175b2efbdc31e61a98b4465235c2d9", + }, + { + .AEGIS_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", + "57754a7d09963e7c787583a2e7b859bb24fa1e04d49fd550b2511a358e3bca252a9b1b8b30cc4a67", + "ab8a7d53fd0e98d727accca94925e128", + }, + { + .AEGIS_256_256, + "1001000000000000000000000000000000000000000000000000000000000000", + "1000020000000000000000000000000000000000000000000000000000000000", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", + "57754a7d09963e7c787583a2e7b859bb24fa1e04d49fd550b2511a358e3bca252a9b1b8b30cc4a67", + "a3aca270c006094d71c20e6910b5161c0826df233d08919a566ec2c05990f734", + }, + // Deoxys-II-256 + { + .DEOXYS_II_256, + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "202122232425262728292a2b2c2d2e", + "", + "", + "", + "2b97bd77712f0cde975309959dfe1d7c", + }, + { + .DEOXYS_II_256, + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "202122232425262728292a2b2c2d2e", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "", + "", + "54708ae5565a71f147bdb94d7ba3aed7", + }, + { + .DEOXYS_II_256, + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "202122232425262728292a2b2c2d2e", + "f495c9c03d29989695d98ff5d430650125805c1e0576d06f26cbda42b1f82238b8", + "", + "", + "3277689dc4208cc1ff59d15434a1baf1", + }, + { + .DEOXYS_II_256, + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "202122232425262728292a2b2c2d2e", + "", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "9da20db1c2781f6669257d87e2a4d9be1970f7581bef2c995e1149331e5e8cc1", + "92ce3aec3a4b72ff9eab71c2a93492fa", + }, + { + .DEOXYS_II_256, + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "202122232425262728292a2b2c2d2e", + "", + "15cd77732f9d0c4c6e581ef400876ad9188c5b8850ebd38224da95d7cdc99f7acc", + "e5ffd2abc5b459a73667756eda6443ede86c0883fc51dd75d22bb14992c684618c", + "5fa78d57308f19d0252072ee39df5ecc", + }, + { + .DEOXYS_II_256, + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "202122232425262728292a2b2c2d2e", + "000102030405060708090a0b0c0d0e0f", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "109f8a168b36dfade02628a9e129d5257f03cc7912aefa79729b67b186a2b08f", + "6549f9bf10acba0a451dbb2484a60d90", + }, + { + .DEOXYS_II_256, + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "202122232425262728292a2b2c2d2e", + "000102030405060708090a0b0c0d0e0f10", + "422857fb165af0a35c03199fb895604dca9cea6d788954962c419e0d5c225c0327", + "7d772203fa38be296d8d20d805163130c69aba8cb16ed845c2296c61a8f34b394e", + "0b3f10e3933c78190b24b33008bf80e9", + }, + { + .DEOXYS_II_256, + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", + "202122232425262728292a2b2c2d2e", + "3290bb8441279dc6083a43e9048c3dc08966ab30d7a6b35759e7a13339f124918f3b5ab1affa65e6c0e3680eb33a6ec82424ab1ce5a40b8654e13d845c29b13896a1466a75fc875acba4527ded37ed00c600a357c9a6e586c74cf3d85cd3258c813218f319d12b82480e5124ff19ec00bda1fbb8bd25eeb3de9fcbf3296deba250caf7e9f4ef0be1918e24221dd0be888c59c166ad761d7b58462a1b1d44b04265b45827172c133dd5b6c870b9af7b21368d12a88f4efa1751047543d584382d9ec22e7550d50ecddba27d1f65453f1f3398de54ee8c1f4ac8e16f5523d89641e99a632380af0f0b1e6b0e192ec29bf1d8714978ff9fbfb93604142393e9a82c3aaebbbe15e3b4e5cfd18bdfe309315c9f9f830deebe2edcdc24f8eca90fda49f6646e789c5041fb5be933fa843278e95f3a54f8eb41f14777ea949d5ea442b01249e64816151a325769e264ed4acd5c3f21700ca755d5bc0c2c5f9453419510bc74f2d71621dcecb9efc9c24791b4bb560fb70a8231521d6560af89d8d50144d9c080863f043781153bcd59030e60bd17a6d7aa083211b67b581fa4f74cce4d030d1e8f9429fd725c110040d41eb6989ffb1595c72cbe3c9b78a8ab80d71a6a5283da77b89cae295bb13c14fbe466b617f4da8ad60b085e2ea153f6713ae0046aa31e0ba44e43ef36a111bf05c073a4e3624cd35f63a546f9142b35aa81b8826d", + "83dab23b1379e090755c99079cfe918cb737e989f2d720ccaff493a744927644fec3653211fa75306a83486e5c34ecfe63870c97251a73e4b9033ae374809711b211ed5d293a592e466a81170f1d85750b5ca025ccd4579947edbae9ec132bfb1a7233ad79fae30006a6699f143893861b975226ed9d3cfb8a240be232fbf4e83755d59d20bc2faa2ea5e5b0428427485cca5e76a89fe32bdd59ab4177ad7cb1899c101e3c4f7535129591390ebdf30140846078b13867bbb2efd6cf434afe356eb18d716b21fd664c26c908496534bf2cde6d6b897799016594fb6d9f830ae5f44ccec26d42ff0d1a21b80cdbe8c8c170a5f766fad884abcc781b5b8ebc0f559bfeaa4557b04d977d51411a7f47bf437d0280cf9f92bc4f9cd6226337a492320851955adae2cafea22a89c3132dd252e4728328eda05555dff3241404341b8aa502d45c456113af42a8e91a85e4b4e9555028982ec3d144722af0eb04a6d3b8127c3040629de53f5fd187048198e8f8e8cc857afcbae45c693fec12fc2149d5e7587d0121b1717d0147f6979f75e8f085293f705c3399a6cc8df7057bf481e6c374edf0a0af7479f858045357b7fe21021c3fabdaf012652bf2e5db257bd9490ce637a81477bd3f9814a2198fdb9afa9344321f2393798670e588c47a1924d592cda3eb5a96754dfd92d87ee1ffa9d4ee586c85d7518c5d2db57d0451c33de0", + "88294fcef65a1bdfd7baaa472816c64ef5bef2622b88c1ec5a739396157ef4935f3aa76449e391c32da28ee2857f399ac3dd95aed30cfb26cc0063cd4cd8f7431108176fbf370123856662b000a8348e5925fbb97c9ec0c737758330a7983f06b51590c1d2f5e5faaf0eb58e34e19e5fc85cec03d3926dd46a79ba7026e83dec24e07484c9103dd0cdb0edb505500caca5e1d5dbc71348cf00648821488ebaab7f9d84bbbf91b3c521dbef30110e7bd94f8dad5ab8e0cc5411ca9682d210d5d80c0c4bdbba8181789a4273d6deb80899fdcd976ca6f3a9770b54305f586a04256cfbeb4c11254e88559f294db3b9a94b80ab9f9a02cb4c0748de0af7818685521691dba5738be546dba13a56016fb8635af9dff50f25d1b17ad21707db2640a76a741e65e559b2afaaec0f37e18436bf02008f84dbd7b2698687a22376b65dc7524fca8a28709eee3f3caee3b28ed1173d1e08ee849e2ca63d2c90d555755c8fbafd5d2f4b37f06a1dbd6852ee2ffcfe79d510152e98fc4f3094f740a4aede9ee378b606d34576776bf5f1269f5385a84b3928433bfca177550ccfcd22cd0331bbc595e38c2758b2662476fa66354c4e84c7b360405aa3f5b2a48621bdca1a90c69b21789c91b5b8c568e3c741d99e22f6d7e26f2abed045f1d578b782ab4a5cf2af636d842b3012e180e4b045d8d15b057b69c92398a517053daf9be7c2935e", + "a616f0c218e18b526cf2a3f8c115e262", + }, } for v, _ in test_vectors { algo_name := aead.ALGORITHM_NAMES[v.algo] @@ -337,3 +610,23 @@ test_aead :: proc(t: ^testing.T) { } } } + +supported_aegis_impls :: proc() -> [dynamic]aes.Implementation { + impls := make([dynamic]aes.Implementation, 0, 2, context.temp_allocator) + append(&impls, aes.Implementation.Portable) + if aegis.is_hardware_accelerated() { + append(&impls, aes.Implementation.Hardware) + } + + return impls +} + +supported_deoxysii_impls :: proc() -> [dynamic]aes.Implementation { + impls := make([dynamic]aes.Implementation, 0, 2, context.temp_allocator) + append(&impls, aes.Implementation.Portable) + if deoxysii.is_hardware_accelerated() { + append(&impls, aes.Implementation.Hardware) + } + + return impls +} diff --git a/tests/core/crypto/test_core_crypto_ecc25519.odin b/tests/core/crypto/test_core_crypto_edwards.odin similarity index 91% rename from tests/core/crypto/test_core_crypto_ecc25519.odin rename to tests/core/crypto/test_core_crypto_edwards.odin index fec4fa38e..61933c00f 100644 --- a/tests/core/crypto/test_core_crypto_ecc25519.odin +++ b/tests/core/crypto/test_core_crypto_edwards.odin @@ -7,6 +7,7 @@ import field "core:crypto/_fiat/field_curve25519" import "core:crypto/ed25519" import "core:crypto/ristretto255" import "core:crypto/x25519" +import "core:crypto/x448" @(test) test_sqrt_ratio_m1 :: proc(t: ^testing.T) { @@ -684,6 +685,68 @@ test_x25519 :: proc(t: ^testing.T) { } } +@(test) +test_x448 :: proc(t: ^testing.T) { + // Local copy of this so that the base point doesn't need to be exported. + _BASE_POINT: [56]byte = { + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + } + + test_vectors := []struct { + scalar: string, + point: string, + product: string, + } { + // Test vectors from RFC 7748 + { + "3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3", + "06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086", + "ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f", + }, + { + "203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f", + "0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db", + "884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d", + }, + } + for v, _ in test_vectors { + scalar, _ := hex.decode(transmute([]byte)(v.scalar), context.temp_allocator) + point, _ := hex.decode(transmute([]byte)(v.point), context.temp_allocator) + + derived_point: [x448.POINT_SIZE]byte + x448.scalarmult(derived_point[:], scalar[:], point[:]) + derived_point_str := string(hex.encode(derived_point[:], context.temp_allocator)) + + testing.expectf( + t, + derived_point_str == v.product, + "Expected %s for %s * %s, but got %s instead", + v.product, + v.scalar, + v.point, + derived_point_str, + ) + + // Abuse the test vectors to sanity-check the scalar-basepoint multiply. + p1, p2: [x448.POINT_SIZE]byte + x448.scalarmult_basepoint(p1[:], scalar[:]) + x448.scalarmult(p2[:], scalar[:], _BASE_POINT[:]) + p1_str := string(hex.encode(p1[:], context.temp_allocator)) + p2_str := string(hex.encode(p2[:], context.temp_allocator)) + testing.expectf( + t, + p1_str == p2_str, + "Expected %s for %s * basepoint, but got %s instead", + p2_str, + v.scalar, + p1_str, + ) + } +} + @(private) ge_str :: proc(ge: ^ristretto255.Group_Element) -> string { b: [ristretto255.ELEMENT_SIZE]byte diff --git a/tests/core/download_assets.py b/tests/core/download_assets.py index fc4a71cdc..b39aa059e 100644 --- a/tests/core/download_assets.py +++ b/tests/core/download_assets.py @@ -7,280 +7,284 @@ import zipfile import hashlib import hmac -TEST_SUITES = ['PNG', 'XML', 'BMP'] +TEST_SUITES = ['PNG', 'XML', 'BMP', 'JPG'] DOWNLOAD_BASE_PATH = sys.argv[1] + "/{}" ASSETS_BASE_URL = "https://raw.githubusercontent.com/odin-lang/test-assets/master/{}/{}" HMAC_KEY = "https://odin-lang.org" HMAC_HASH = hashlib.sha3_512 HMAC_DIGESTS = { - 'basi0g01.png': "eb26159a783a4dcf27878754e34db6960e992072fc565b12360c894746bc6369101df579e3b9a5c478167f0435e89efb2ab5484056f66c7104f07267f043c82d", - 'basi0g02.png': "f0f74d33ee4b3d3c9f1f4aacf8b0620a33cf1d5c6e9f409e11b4a6e95f2ab1c9159c1bd0bcf6f9553397bf670f4c92712b703d496665d4c6e88fdaf6a0c98620", - 'basi0g04.png': "7b81665f353ff6347304b761d26b4f1baa6118daefc4790f4b0e690150a4e6306514f2aef87e2c39e83e56a0b704df987b10a5366244da58697cda4d5d2745c1", - 'basi0g08.png': "6c809574674494d10eb04c58191c4e0b35813c45962ecafe36a9fe5ba44e5d74ba098e0a524a30c1508eb2dad601f04d5230dceb61a307ef1120f07a8bcbc92f", - 'basi0g16.png': "dd439069fb704b8deff3de822314c012e91a0bd84984d2e79888c6394b78557a0ae6197a7b0a4d64eb4e16fc758946c4f1f13d0d06e512ed9743c4a355b02488", - 'basi2c08.png': "e851fb030f88ead2541a01591882dde5fd9f5dea6bb2b11b374394ed86abc7289e72c4c90808b261aceac13111d3c05b39033168b42ffd1c7ea367314b3a8dc5", - 'basi2c16.png': "e0f81dd459860f7eaf04a2c54932547f41cdc9903a1295a26cc4a2087fd79c98a2e5d5e74f22345dba08b1eb12f3f53c9b904c88b756cbae0c19f9d680e2f1e8", - 'basi3p01.png': "aa21cbcd5d64e6e88056af907509f3b98b00d105198ea2a669fcb25b6966f06d5e4e3afc160b2382935e8ab8e7ccf61733424dfb39b9e864306b82f8355bbb58", - 'basi3p02.png': "d6182370236630d42fd75eed7dc54079ddb7fa9bd601eba22a8dc3331dce31b9a9465027145c29bd56cf778ab0ac029df6aa6481ef65c9464a1ce1d89423faa5", - 'basi3p04.png': "2b35fb98884da370f25833d25f0ab4b188cc26440321e95519131c675818c128b2029d38b3477ef94d88052ec6e9f8b1f7410c5576ce0b47b2fb7a5ba771ce48", - 'basi3p08.png': "7415890831958ca34c73de3e33a9c88980e788d10c983c3a00967886f05053d359499bf0bad386af8ee1bfdb73f666e1d541b0ab682c6092ebdbad3d93e145b1", - 'basi4a08.png': "22ab23a3070d9f1316e8c65b333745e4abf6dcbe63d9d0ada7f6881604b498a92e5b49eb8c1e32f453f4319d94d3d0f48441bac2e79ea528fd7ace0dbbacea9f", - 'basi4a16.png': "2b1436a619f91cf4045e18acf03201b5e9c7774fc77e4c3f38d668984d98543fe64978e80854f30adfecd89b71632945250508bea9eb1ce8e9145e3e55bdeece", - 'basi6a08.png': "aea929866edc5e607d7dc90fcd871f4b6d548abb379b9427fce75a773705e0d8c3ed03bb64e530482b72973eb09844638db5db93666ca1605ff6bbaf194f70e8", - 'basi6a16.png': "29b6ce7c2469e24587b87559f85551334c51bd9d7867f4066c0f7dcb01d710e11e87ee8654c91dc986454cd70f8bd6021e2086ea40e48a28d68a9bdf2283573f", - 'basn0g01.png': "52da610af6f97b03fd8e9f8e52276227f57a97e2bc7e47ae9484b2a37472330f8f5ecef2d6de7fde8f7eb8f144f233bdcf8a3d716c5d193e44d9590af2709cea", - 'basn0g02.png': "676c727faf143af658ed6c6333b15e50387c566c1846a4dda636ed4a2dbb1c0d6d32f0db635479f6851047a32c6d9c52898cfda004ea986853f3ee13750ed90a", - 'basn0g04.png': "123a6652b56f5b858373836509f6b7433221e6ff4eb9ce8a68d0d12bfb27cad0c1bb0cb159523ef1ae5997cb07f994bfbfeabcf0a813aa83495f8269a7a6c4e5", - 'basn0g08.png': "ad5ff30613a462a9b61242d42bb7c854b8247d80a1d03a3919dfdfe8a91c8a962ff51932b2411f714f1be7b803cbd4605c1d4441882cad7e8f44dd8d927198a4", - 'basn0g16.png': "40a96ed10ad5cc58180701e0bb6d6f36c1752c8b8329a80be2960535ad9e168469efbd8f3dc825b57bf65e78a3b61835f19697f2a22511f79c06ce2c6a0034c0", - 'basn2c08.png': "fd92ba13d2038c632fd8bdd3e33971cc69f561bee1eb04ff7920625c6771e0cf7fdda29e48b8a6ca71702c0624ebbca232793f28bb2073b0247d30ce0c549ad5", - 'basn2c16.png': "f6b3cfbc70ae502edbeabde828823dc079dc4e9a586a7fc326c70caec3033124121e3ee2e6481e6ce966efcdef9376cb3ec3edb8e677e91563f510bd6f6e83e6", - 'basn3p01.png': "d262c97549cd1d43e36f5990dac051ead80f1456693c8b1e19a8a48796195831a6ddd5c4a0ac44d22fee51ce4d9392c1c40a0be05571b1b2a961691636d69cd3", - 'basn3p02.png': "a00e375e1fbcc23de38b3b11a0fda4d0204f55473f74e37e0bb5c5f391b37c019293ccddbb99196b9457cd0b7fe5b9e34a55dc6b8167b6909b38813e37a95e46", - 'basn3p04.png': "1a6ab4c567e75b20ee6cdb400dd1f7764a05679c35010e6144fede5a55767dd1861df8e6240e1e59d4166e25d972ff05a41cdfd527818b6ec960a0f9d57d0939", - 'basn3p08.png': "b8f99f6410cc1ac0ceb366e93fc1008f45fb2499e39c489fafa143e8e881f334735e118eec93dde687bf4ea524b4548741c520d770ba6d7071e8fdce576644de", - 'basn4a08.png': "4b7758d4fce3bba95ef3d09cff0ab28c21b8bf568156730fd4e3bcea1c1c2d3ff77f53fe3551f617bd01c8c96e929eb20bf04f5c1a84f37c3cd6bacd4730e6eb", - 'basn4a16.png': "aa0c411f8bb15fc801b072f1048de2fd08761fe245ad267e8503eef8ffe1c39be845e99c04245771afe9b102328129f6375869a4e6cec60eeca641b3e5df3a8b", - 'basn6a08.png': "78d7c811c5463ce53a50874baed840ba70c811513e0ff98fda15a08f01ac6a7c7139a9979cb3688451af6b7e2981699be3c27a386d77af5e60d1acc9e23cb103", - 'basn6a16.png': "e1ad0ed2bf5774b2733d23f2ea9570c6edc933298572933010144ef07bfe6a7878f7367a76f2affbf9845d5b69ea3c84b885f9415e18e752fb1bf21d0dd9d9a2", - 'bgai4a08.png': "22ab23a3070d9f1316e8c65b333745e4abf6dcbe63d9d0ada7f6881604b498a92e5b49eb8c1e32f453f4319d94d3d0f48441bac2e79ea528fd7ace0dbbacea9f", - 'bgai4a16.png': "2b1436a619f91cf4045e18acf03201b5e9c7774fc77e4c3f38d668984d98543fe64978e80854f30adfecd89b71632945250508bea9eb1ce8e9145e3e55bdeece", - 'bgan6a08.png': "78d7c811c5463ce53a50874baed840ba70c811513e0ff98fda15a08f01ac6a7c7139a9979cb3688451af6b7e2981699be3c27a386d77af5e60d1acc9e23cb103", - 'bgan6a16.png': "e1ad0ed2bf5774b2733d23f2ea9570c6edc933298572933010144ef07bfe6a7878f7367a76f2affbf9845d5b69ea3c84b885f9415e18e752fb1bf21d0dd9d9a2", - 'bgbn4a08.png': "4fb9b1023c8c7accb93cf42bd345846c787735df01f7db0df4233737f144e2d5348afaededcdd8c2bcf2e53ce00e2ff095c91de14d7818b4b41c396ab85c9137", - 'bggn4a16.png': "302d7c02ddb0be62aeffeeda46957102c13a2701b841a757486cb3eec7b5456cfabc6ee1954f334ad525badc7c607621a72559b01ce338a0f39e2426d0a03fce", - 'bgwn6a08.png': "d380c477775d102288b43c387dbd7b931f85520f2f6151e3ccc5a25764169312d98fcebf69fb86d3d12520edc3de9bfced559ddf73366f0679e52defb9116424", - 'bgyn6a16.png': "b688d395552eb2a8506fa539ee9159b40a57d02c81860bcf76176213504eb10bdd89de7ce9da452e43f2a46c15290755cdc4816738620b27aed45b3ea7f7ee84", - 'ccwn2c08.png': "c4d58269ef360e42870cce5fb0b1134bfe5706f172c5ff916a338978798fc541a463ab4fdb7c91c424fa385f0ac5d6f576967f178b858d7503f609b2daeacb64", - 'ccwn3p08.png': "d89becf7d24dc57c931a8af1b9dc03ae10302785cc67028cec7255e1aa0ffb0d508d894023a98c10a24cf145aa60b93f977acb8231c8fee9d3f0934484757c30", - 'cdfn2c08.png': "a5faf9cfd284d3750ce2c2f8e15d0ff1bca09da4a9d46b8797c7a1a9f2ebe79d7a7a552bad3c3c049d6186460e81e1e7f9b94e7bb98a3c79d2516f6fb7ac6aa6", - 'cdhn2c08.png': "396eec14e76c00d22ee153171243ac531dcf7adad830948dfd5d6f0a84155734b90407e74f8c1ab8cfb0af5084c03f511530739751f8da070379c826545d0237", - 'cdsn2c08.png': "051b0defa4363ceb3fbc44f460f99a10cdd7c15797ea6d8aa62513b8b6fc5000fe542899db464db30eac56d0c9cd2a5d3778c6962f3aaa85a20881951a7f963a", - 'cdun2c08.png': "946074446fb99f0b790146df0f6e362c68e79b46ec7cbc4ce3d3dc9f75f66e58715caac4b3d7aa8fe8360c32abd2702e7228f9c03b4ba2a0d7f2f970a7ba8f32", - 'ch1n3p04.png': "6680e895195295989850129bcf9d0d0c47efca1c3bc363e4ea822c688707955cdcd07ae92e6e213ee388a62e14b51e036f9a9e075ad7b0f736b0cbc5cc4a108d", - 'ch2n3p08.png': "778ba389d9d0bcbe188e2501c7c1d047f1287179b3760b43da0053f0853e77a0575c7179a02f2442b83efa6cc0951b32d09bd7ea3b6848f261f10b8127e4b0e0", - 'cm0n0g04.png': "9e7e94d201a1222383294bd60e2627207b7b99c0bd80aecd677a1b7d8b372de4981b781fb794811d29a4b2c4db4f5a40c953039c31084f8f3de9aff13fbd1dc9", - 'cm7n0g04.png': "33bb0ffdfe54d655683e4e1bd6d963b9a35a6500129b5dd574245e78971de8d19f27b86a76d42056716b90c2bfc950241bfdc6c4b52ee0e125571de36ba61904", - 'cm9n0g04.png': "fd59386d15a1a324c5ff32f574484c1209afe4ad99f7dc12dce45b2a9bfefd33311ec93211fea3a8e61d1ad2f98220b0c15d151be304bdaa7f88126d54299f68", - 'cs3n2c16.png': "93ca3eeba9aef67de15f943fb2383d208ad1a68518ab78c9fa5ea306ad077b789e873f9e453f0354535167aa4e3d3fec715df05e827bf510948bf0e6fa0dacad", - 'cs3n3p08.png': "e8ddabbf0b17db03bcd7ff0c61d08cc971b3b88e3b3ecd2d4a296da8cf7d7708fa5b42ff3d5813d936ab7f5b4bafbf5842fa4c0fcf0cff15258548d2d26882f3", - 'cs5n2c08.png': "4e3eae53e8c27d4c58d8ad8cdff2c06b00a61d1528a41f5566694f10ef33c4a66f40d3d9fc247731c3ba6dfb734c9f2f90ef031c64486fbdf8a825e354fd67b9", - 'cs5n3p08.png': "31ee0f7f789c1203a9b0e81da34960a47017f3fce37bf2b711738ebd535bb3003ef60c2b0b1fca16587a59955c1ae24b9d186d7ead1d3ece6ada2bbfbc5aee85", - 'cs8n2c08.png': "11bbc80c3168f632deb4453f9199c7994255a0f4f2d7d2d2b06a00931fda4c56985b5a2ca8e969893ff2d65bf330c3d3148b80cbf72aacfe0054b612e6ae05e6", - 'cs8n3p08.png': "49ae3a9050487f6cae826407d421f32a8c67977dd057a6e36f1b2e1ec6abdf5cd46c8929ef4d7b565921ed6c9ae0dde89e243714fdf1510503c7d7b8af6d66e3", - 'ct0n0g04.png': "b6a66fda9ad82cb3287a1ef54702926204bbd4186969cdc2e0741a28dae1869ed76939199f44fd7dd78332753cb8b20a53c4bf740e353f2cc4247870cf576848", - 'ct1n0g04.png': "7cdbaebb6be5d9165972b5fa24f2b64ab437f5337f0548f3d212be8aa95e5dee6ff9abd76ec232faafedc4a41ab8825221b6ced2ecab81c1b3ab20042ceb81a3", - 'cten0g04.png': "648769788c3eb4acd06784dc428bab9e7868328aa3cfe3718ee6656e13e40c4502ca5ac1fe6d4baccb666d4a4f6b3a5d3c97d489f9919ae0d26c2dcdc62e526c", - 'ctfn0g04.png': "c40768807f13dee8dd80ab012bf82b7e8551cb20bde3c7b5c4c45ed19c764cb981945ef036292bd9a2838d34b1b52284295133fea326aea9fc391708bf1d1fbe", - 'ctgn0g04.png': "e0cb7a2d983f1c1c38054b02aabeec657e3f85dba3a52b4878798664c8c6db77cef84d01f042368de6e77cd07b7c2cc6e324aa70bd44c2c8a3642f0cc8fc6a65", - 'cthn0g04.png': "b8614c14bc8c32bb3b29d3b0ac9f3d04c0fcaa40818ab86866e2a8ba1e0c6a87a989f499f208a776d47bff8ab09bfa09352d52089b3cd5bf599faf27627a630b", - 'ctjn0g04.png': "02e2e0a5fa8054e7c7e1c583945da06fb31eff9a3fdd1a7c9f76ba3333f20ce60aec8fafe07f608e9d65a6543e97bab0ff8ae66f3995e8035c05a7c53168ca9a", - 'ctzn0g04.png': "ac35974bd1182e339327245ffa1c0afde634b3a67ee9d6e4e22deee983d6d31054e7843cf1720087b88f6510ed70276e9b0bf43deaf861bd16ceb166140352f9", - 'emblem-1024.png': "5b2e174847274069fc8f4e30c32870ddc7c0e3616a3f04fd41583543aa99ac6d9b7d5a63ed1da672c551b4d193568bb58ddac5e87a101b73367c7c3b01e36fa9", - 'exif2c08.png': "e81b85aa36c9aab55754dd8b73d42497c38eddf9ff3c2981529eb62993d8c0ab33d1b5146a350dd8a1c528d42a967733b2f86248ac615e0254fed53d66d0d895", - 'f00n0g08.png': "fa362f0262ce522297ce52bd7d18b1dc28a2eee3e099b4104c2fb6bdc3fbce0b70303e6df31b709b4033b41e8acec29c81d456c67cde741243c9a54f1ba17f17", - 'f00n2c08.png': "040e95e05152c4bb30608556c828f453c46253c7e0ab18984076cde29b5b6afea7b6658cb019a2723af02a5aabadb1af3b1190655256f3477cd54b9ebdd4df91", - 'f01n0g08.png': "5c60761dc803de1509ef33b4e0ee350d15488d73f4b4e2f93311beb19667626f42d91af39873cd078617c5a2e7c46cceb831d53299c3ff2e7486b43a02ce4967", - 'f01n2c08.png': "a2762a0c4905d05469178176966e86ed4f14c3fcf5c88336209cb923d76e73acc94c619947be87b9183afc20bcd002ab2cc84d81897ec8fc0a4bdeb02a2b7863", - 'f02n0g08.png': "adf640a6f60662ad1b47b5666d2ce86489c685284e50d47344af7cda37f4a42697b5e249f5140413bb3c3e563cca09b2693dcea8bd9ad9adad1adf654ce00bb1", - 'f02n2c08.png': "5f70f19d318ff1d9de4c2f728d83952b12b59bfebac213766ef835dd19f8214f56fa92318041eff25e720503542d067bc9fdf91d86016713c68eb1c52870bad4", - 'f03n0g08.png': "742efed3d25ada0449ed60e4fe1dc94abbe494870536946810cc0eef5c3bfbebefd9bb6d1a482cd5e2c2ee0f34a74b2ea796772254d05accb6739c1ab4d19cdd", - 'f03n2c08.png': "adfac7d6dcc7354467cb3f65742e30ecd44a09b5913ffb656664c9c4730e9cfab9c5e0df2ff8995d412b1ea9cd30ec061eead939546bf795e50a2d49cd10bf92", - 'f04n0g08.png': "9f229c609e87e6c3b83fa82f4f59d7b6494b70c7f85cc807b3611a12d5c59953f11c163228f2bb8b2e7ce77ad204e0da099ab06f8fc480d3ab0ca99fef83c23d", - 'f04n2c08.png': "2dd8b926d1f370b3d3ebaa982491fbe446f3c22b89e635c76eeab60c9ccd3ee7cf39773108d2cec647e480d40de88c4173369b4a12a3fccfba9e4040752cfb4b", - 'f99n0g04.png': "b41996ddf1b770d01900c309cfd2f96d6e60df8313cfda3585a731f32166aa447bcf66ef4af907d6417528024961408d06ca0894fbd6a63fd47ee5a9ed541b51", - 'g03n0g16.png': "02a49b9735063a4d1888b550ed961251b150794422b00ca3800ebba09cd55bdcba15cc8dfe0c41e5a99b2f4d3976b32b1cd08aba92f3dfc3960c71e28ec6cb51", - 'g03n2c08.png': "70b3d643218e033959c51279439d80982f338016b4355aff12be51e7bc59a79f5a5d519c0fa5f13db072cc667fb9635654766af2a11ea25c1b6673f554ceb1f4", - 'g03n3p04.png': "7bfab2aef6f2c04063c438a8f5cda38f3221892ec22a83ab3d3441a900b97c0a7184336ffc2e0c6748e4d931fc80855eed5d6b208ba6ac0709ef02bfbab3e8f2", - 'g04n0g16.png': "9a1d60c89bd63e1f2c81adf1ce7025b7f465e00f0c5142d8a67b5a92e2b042d41a352704969f237883e376bf50c911db196d46f8c28c30ef5763e1e717710c8a", - 'g04n2c08.png': "8e482c99cbc90e6e4aa678e5dbdc39f5b432d740ff260ab1ec04ffa199d97ed2e06491cf88eb0bbbda2f4133f174cf3741474305d9645e0268916aaaab43299d", - 'g04n3p04.png': "d95a52bdc83db74dd19aaa56b40bcbcea268492498c7b2348882a4a5ea70c2b258462c3d5cef85e5372188f21001f719afeb2fac635006486c8fc84b96cc4622", - 'g05n0g16.png': "75954c2e19aa2ba43f7011adecded403035ecb21595a5d116896d2bfc1b71eac42c9b6f008a748cd21b70004921832b3e0dafa1fc0fda4c51ad44cd2b4d782c9", - 'g05n2c08.png': "272baa8dc73cbd63f4fb9545288cfdfcee544e266c9074b73b401895188a123960a6000959f9c034f7b5abe2bfa5e6185253447bac82e9fbfa9634d7e9981d95", - 'g05n3p04.png': "81105d25df2bbbdce60e90cb9a7d0784326bc3c2857fdca4f1f3ef7ab301627685057b97b8d0c0c725d92bc0b48aa1b156dadf5e302ca35917f0b407689ba054", - 'g07n0g16.png': "cb6babe4e25f4cc7e0c3602d9f0e9e538f46a4c4e40420c29521799c528da31afd07b614ae64fbc0e9d0904c9f3e7395b31452abdc69c6a03bf1b5817035b669", - 'g07n2c08.png': "c61e8f936afda939d6497687597d3381485b7cc00716101fc4d6f3abf44df63659b762c77ee252a8735f8e0be0809961db17abbd42c5deab5bad10d0b6b28a55", - 'g07n3p04.png': "8151fa9e9ccd1991a05ea129a7363e23de80688c65d0554c7f3142ed7099d01d82d8ef122986693718f221202657ff965b1b6387a237b36ae741e3d4ea693280", - 'g10n0g16.png': "28ad93f3bebed928c3b0bb4beecaa1b1b55e480c7922d2a36c8f92fc0de012adab523c42f22871b82c6683a7ae74864ed1c35a76cfad92dc6692be0b78c22f50", - 'g10n2c08.png': "4b922386b48c0dd51aee3852da4e52c5c4f3eabe3fcb000e4cfdf0c0e8b27d6a6f77fed944932726fe884f468ac24d89c5c46d65db99be1ae797bc4bbee4cd01", - 'g10n3p04.png': "9b106a0db8ea7e4bc3876beed0f13d83b6f3d6d7d7211441379dd8d18db080f5dc81c6d15312cc3c8ae569b991852ad48f167229dec033f1a974d2a95c83cb3c", - 'g25n0g16.png': "0910ee601a4c4cb546c3bf2b5e8a799d199e34e1434c58c75ddad17f2b295920cf3dde9fe05eee19689705f76b11474b4edc73f4ff346b6ab2d02ec40a13d3cb", - 'g25n2c08.png': "080ed57fd4185c00c6c70e48c27612621393a6ef3987aefd1481611f74d0aebc58d1a90386e4e7bb0321eca961e97cd403a7e727f7324196c5a3cf0e07bffce3", - 'g25n3p04.png': "1deb4281d9792af858e715c39ef7e6756f3004845d87f52054efc9f02c679b2b1b6c2a548a5e6a3f31604b115469ba4bb81510470a47ff9a22b133427375a8db", - 'logo-slim.png': "0104624a95b1b8a97bb5013927cb8fbe330a8c9e7197814147702702cd1d44cdde956404786bb0e69927c6b03ed8031bab566599b1291b995ce747f7cb2135eb", - 'oi1n0g16.png': "40a96ed10ad5cc58180701e0bb6d6f36c1752c8b8329a80be2960535ad9e168469efbd8f3dc825b57bf65e78a3b61835f19697f2a22511f79c06ce2c6a0034c0", - 'oi1n2c16.png': "f6b3cfbc70ae502edbeabde828823dc079dc4e9a586a7fc326c70caec3033124121e3ee2e6481e6ce966efcdef9376cb3ec3edb8e677e91563f510bd6f6e83e6", - 'oi2n0g16.png': "aab1bbfc7b711ba66260985bd8bda6ffaa1e09a0a546b2fe8869b508d823a9e5a412ba6337355a81d87f010e9db8c95eee5f5084b21ddd5cca5d7db7725603b0", - 'oi2n2c16.png': "8d1dd257f3b1bf44ef0bf38338a1e3f2ff78670ac779959751a56231109ca1ed82414f50a221aa45333263073e1e1a950ac8df8e5318e2ed695422d49400c540", - 'oi4n0g16.png': "7675dfa4cff547c3029b21cc892b90a8647199dc9290add932535b04b4eaadaedbc338704f98a075f4690b87815eec8cc0f90a3dbaa2a7809aa03f238ebc5815", - 'oi4n2c16.png': "66313c9d4731e2a9fa006ee9e43c6ac4a3034ce2826c6213f67bfa349bb8bb3cfd8acd2c4553fd1fcd4b2f43993a54539ec8b7fb7f07b3a406adfe919f17b065", - 'oi9n0g16.png': "5615cd4c277be96b21031827d08c8fb2971fda090a0031fd34594f77f7cc558bc68917542597a32bc39c0cd29f7759f0f0429203aa285c163bba8c8f78894e72", - 'oi9n2c16.png': "e2184c00b952a3aa53078a5f995715fa683718a9cbe42705fae3a7c77b236ee6ad706f6dbf2c243aeea17e2c53e84724907724634545e065dd16ff400f5677ab", - 'PngSuite.png': "af1d473e986b3f5cb1006340f8f99156e980e2f8c9f804f0e27c57a51d0dec332a81d99c6e50162f63792d89da44857a6072f8431aa735f1e8f86c06520eff4e", - 'pp0n2c16.png': "82ee5674861b5f9bdab6cf41910d980fc33b5188e191b8892b051dc3b3bbceb4c6d421cbed7bc9b71a9a14db43991c0458ed2cbe5166939f1cbb1e20e445e8b1", - 'pp0n6a08.png': "71c0d4c87b6b2644a4529cd240c8d583c25d45e79fd8bb71ca850dada37e46571052b2da28b926a8194169b82da505c9a3e3a701816d91ac968ad6ff41132b70", - 'ps1n0g08.png': "b273e94c2f826640b10b27b50c605be06541b397ea1289be6f4ea821dff6c7b4b209ec8817a315db442de04c975b7cfecba07b51c6cec965ab9062c05ba04edd", - 'ps1n2c16.png': "833993b81801432eb3a9dbca81f4fdd8ab720c76f8d99a2d298fa1dc4ebd19759c158dd10a68f690f999ea643f62fb7e779e916df86aeb05c43bc4db62aa520b", - 'ps2n0g08.png': "4abea03946d751f03e1438e5987ae691607e528c577db52e893051b54a5d147969dd965e44aaf5540fea75baad873327d76aa71a07c81de31f04f3b781d01e3c", - 'ps2n2c16.png': "bfea51d7be49c04293de034c7649472d34becb663169608490916795fe988df7b812ff8950a3f8d896ee27756effcf9fb525d8d455226cf3965595ee85188581", - 's01i3p01.png': "18b405c902977d2553aab1738a3c00e602e40d11c121a7007c9b7b4cc499aba1fab12fc12aecbdbd5b5cd2638ec5ca5157b5d8fce5dad3cdc3bea02b0904c9cf", - 's01n3p01.png': "8e3e1c9754ebde8c687355b80eee4bf0e0ee8e37b39b784f1997cd2eb60ece7f077b40c8027b0d7f4b7e8f242c22173a244f4e599db33985187439bd918d4486", - 's02i3p01.png': "3e26a8cf35e3df1650adc1656f2d3e7c9b5e1c7932826cf792cbe2cc538c1283ff145f66e4682d459bb0b4f2a2f9ce7209f1997e336e06ca49a83f75270ccad1", - 's02n3p01.png': "d34685ade19ee550ba52e81657627832cb9ba3655f6fe336ebb5fdc4d35c380e819efc1556e1bd1ca2b4e456727dbc5312eb513e7254dfd057a25963e57f0ff4", - 's03i3p01.png': "818a2c91d6c0f96b13806d945d1fc1b4c64f17a9b6a2ede2658c84e20269cd80289312a163761165f0d99e1824f283844f1b4696af314c05714fd349acf7609e", - 's03n3p01.png': "fe847a62eb64bf9db4d9751600b19333f057b626f2f2eb80ee78a3374ae562944c2ebc9c2712f3bbf862798ef9205f38297cad44e8df5dcd96c158ca2e9d9233", - 's04i3p01.png': "1c63332a0d2f31b3a6457038ec2b8c5b4bd3192320fb1c44873947375dcaa028ea07151853e53c6f3fff6878cf90adedea35ae819e5a1b2dbf92399b29464d56", - 's04n3p01.png': "1312d9f3e5bb07b6cbf0c6798c3ae9b0a6cebae465ae6d4ba115ef585616b3b1f7723c6481fcfaa00626d6c62e4fbff7023faf1e92eedeb5354b9805542d43b6", - 's05i3p02.png': "13225a16a79579c4040cdc03f11c71d8589ab322a4f3926e32d9499fe4ca8503a43870e532b2da2597a6c3dd89c3904428cf89c25a8637d40bb3a353017cad5e", - 's05n3p02.png': "d07f2ef30c06a29b9c5c6a52ce1485a3bb9dacb5f119c2829c4cfd69c8fa272d6065eab21a5acd016bdb4f4c724214e8a737c2b76e0f0151e6afcbe5586a37ad", - 's06i3p02.png': "b386f0387e8496849b6d325e710440f7937a403b123886a52af8327e69e411fd632db19daaecfe2e712d49279630515d7217533112acde73cb429e2cfa465b63", - 's06n3p02.png': "df0968c77975f350a86fc09c047d9e3a0a2b71890a0ae67bdfedb23e7f0ce303ff883a463668e10df1dcf2e57cea8cf1fc7c836f5d13a73c1ecd8d66284fc0c5", - 's07i3p02.png': "0f67816f188ce11f15d0f345d2695f1920a322d84be3f332d542c5d20d10a9cef2cebf1e8ae778b25677beeda229c06221eb3450b851ea0e8cd102e5cad14e66", - 's07n3p02.png': "0af60c935e2da2a8a3173edf614085ad0df095c882a140437bdf93ecd5494cfeb5c068dc7ea4d49e181c67d26dd9cf8c969bb2d95f2fbce212ddf5817dd7f642", - 's08i3p02.png': "3204dd0879b6b1284f197a0437e674c4280adad180d4a1d37dff1555be1924d6234dad5d02266aa575d782c53fa52fd4580d452482ba939c732c09709075306f", - 's08n3p02.png': "135039621ce2079465ef49c1b7e5a5aeab299993d2bac864d822ff0669843df1e733a729ca5226ec05c94ddfebdcb2f4b78699fb3adb741db993d9757b4ca71c", - 's09i3p02.png': "dc4d8ed06a81fcd604f949f43e7d5f482c3ad9efd113d220b709de38ca0ca1a340f4cce7e929ca6323390b4ea7c4399cf2f1f2e34c1ef1b38c8296b51d7e8f4b", - 's09n3p02.png': "96b8204f7008899993d8d277ff42c8eb7c85e7cd522cae2e9cf28b8e10e3904c7ec2e3227372f397f6c5a381875dd747a42409471a29ad5049240417ec1441f3", - 's32i3p04.png': "a4de495c70f54eeccd115492a0dfe1cbbcf7f308343eacf6a57515d7a248b356a2639f5e88246d630c8713724cfd7ab1d5d388c677f026a1c5c9b4270a837c67", - 's32n3p04.png': "757009a2fdf19d1187d85930eeb4e75c6831387348fd8e618d1ef971c27d2682b2464b4160a743a6c6d712553fd7fe1f0e5d78226e348f270093495297ec83bf", - 's33i3p04.png': "19259eaf76a42fec949a21c4c55715247a027c2b59ba4bd0f45fdea1f3406cb475c33213b662fd64089b697a6cd25700364f76923dc2531fa0b39546242b3356", - 's33n3p04.png': "3f42b5f3896c1a47fe5dff9921d56234b4326dcffb70a7c6b1f0e7193a6f8f898438635f3b1cfef92c59d7ab827e2a3f40671d97c8547c8e7063a0076c97fba9", - 's34i3p04.png': "db0f7fe138fd732eae4a5c1b8d013167eb3be4afa86141b3e6ad096eabec67644e3108189311b3ce2c78f891d1ea7f5dfa1c30be59509edf123696064eecd00c", - 's34n3p04.png': "e35d9338637ae4c7a1c74a0e73a5c4ba405c2b0d36efd92512b7572d418c25e7d06361be2a8d16323c2708ff3921da24b76be5a41bd3cccf09c27ad472078261", - 's35i3p04.png': "9f0602e1160b81c2e88fc30daf295ff29c4f6faa5a3391c69d895621e7ab76e2071ced6f5a798e294f69621bb32272070ff4ceeeb1436b1cf03640417961a9d1", - 's35n3p04.png': "f12e6a7364073b7a010db0cf952989f5f5da20c592b0256efabb5e82e96d928dce7695c2a0af0749ddfa2739e3ca985463eb0f4a7fb6b8ab0638d65079fc6265", - 's36i3p04.png': "a2d0374bba6fb665deda98b1bd0ef767243b7a974b9f00c78d54bdbfed2c00decf6faef95816ef711efdc359247142be08ce2b86f7860b7384948ba394b4dd21", - 's36n3p04.png': "e200a6869dba1fc9e2eeeff6e686e02313c366a990bfb5582f66dba486251392a465db03806092543008e1130624f1d16cde61613d0ae2a9589941f69a1608db", - 's37i3p04.png': "555f1f7ec2d8ddb58ced7162a4dec315780be13b7cb9ed6d8978046c7fbcb91b4ecf6fcc5c99bd5b8b8d348e4cd202d882a31dec1ecd25156af8968c4a06fbff", - 's37n3p04.png': "d28b3f442b481214774d543924ab07b75fee5916262e6404992962184ea0059ca34fb32d14076642ecd83a3063966ea80676e3165759632782ffd844702cb74e", - 's38i3p04.png': "d4fe0179effbf28f7d28c0192de614512870367cec14ca04d86eb9fff9d6864b1074a68144023244e46cb69ad601e81632c36eb2ed307a32a3c37b7683f882d5", - 's38n3p04.png': "19d23ca8b9b44d26bc9173a69d1d8332e4e7b2ce6e6422195e71dfd0701158023253b130a831a035b2fce0a1556004e8de74e893caeea3d12410909e6e649831", - 's39i3p04.png': "f0c783232707d288b086398565918079e510677742bb5dab09b4520687a06809ae328d24508ebd8f5c26cf85105300ba98e55c29e3773579929839ed9ddbf7fa", - 's39n3p04.png': "39763c31a17edf2751442cf45ae3cc315623ed5b04141bbced2ee8d233485b2d1a2cc0678d60a1c84e3d89a7513634bfd9c82b58754cdfe95885f7a54ff18e2c", - 's40i3p04.png': "d33b29e6669accf1325e8212c555a6cb1d8413c445140aecb62eb6b40912743ef7c6298ad4bc2e232bc448ddaba37f79fa4d25e0cc8e3d53a5ebc93f8f984555", - 's40n3p04.png': "463eb60a2f0884fc368ea0650c5b7b6469c1429e5f006a6537e4aac721094bbd57baa6bcfe4025939089e27b344d7077ff09618e9ce3a5bd40ee3fe5a0e33ce0", - 'tbbn0g04.png': "24fb55d9fed351946869552edb15bf20a2e7a050094ca4b51ebd135958f8b77401e0e9b18618de0cbd18f835e16df24dc57ef094d3b456f0eb9f73c31748ce2a", - 'tbbn2c16.png': "ee98ae3a1cb4a851830ee3e8f4112d08bd74c2a05b778ce51102780ba9d7170c5200c9cc4e1a5c0833618ebe137595eb8fc0591b8798bb6e4e94c234f8cbba3b", - 'tbbn3p08.png': "ed325815b8525d3a5fa37c968b7c85946add7c08abd1c66d86e0264951cfa5a377078b910a78cc664ec2c43d352093c2609b8d01c9572f4ba922d98264e55c04", - 'tbgn2c16.png': "e6da4190d4cea04b0002d598d68c0536448899dd8fca4931b44bc8ea6d47e6946c55ebc5d2049936db2f7f52caef124648d25a360e838571f5f7cb2795eb3657", - 'tbgn3p08.png': "865358d285a8d8682a16b050d9c1b7492042e1a217b0b5753ad28ae1a698dd77150f8cd6510f345157e1efa1411b4e4d5938a81024c150c9d5e76e423105d9c8", - 'tbrn2c08.png': "cc3cd3b8b6cc9920914e0184bdedcf9e59975db3f99c39b93ea1202cf6e11689eb966fc40ae2caca8ef224a8aac03723142b58b701ca2a02fd73a62e379f7a6b", - 'tbwn0g16.png': "fa8359bf8cdac3ab9ac54cd4f1e96b1469ff3e3494102be179b5c7394a4e37953ef54f5e1ccffe771b4f028225ec164b410b0d08f82224ed93a654433feb14fe", - 'tbwn3p08.png': "a0e10707fe9df085596a724561ba6c80662f87095ba479b2345c985f4beb2933f7767fe3d07b30002591259dc14012f4b26fa9b503cc75fd644def7c27c9f2e6", - 'tbyn3p08.png': "9920b40b016c4a05a094c28a989d06e108e2ebd5d72c2a6ddca359b68ad95238b0b6dca0f60b78c56b551a2e44f924d5a443071bda6f6e31669b0a78c09b18af", - 'tm3n3p02.png': "e9910a8ccb78a10980c55c6ca7115757b48075e42c14a83aece92a7f85eee538d5e1d9301efc443a867628993ceff1c13aebcc574641ad85eec48ae05df9997c", - 'tp0n0g08.png': "57fbf8a07060565c23918420952d1feb506ce5b1bdb25f22d41ee1de4ce9655c6dde04b9643d2491b59efba229b7e0cacd6799010a89005802c28a300a4e578e", - 'tp0n2c08.png': "eed3f6c18bd81d96870a47c737574746293c71c517b6a5ba88afdad5ef89fa30d975717f8a8f84ec16cb98390353934cbdd6e4b099e86f0ca3fe8d50fa07bb11", - 'tp0n3p08.png': "9650347d0f4a1a6596828f48766949947148952c93c4899541324a48289ea558c5d7bd1a076ac0e32f71d197e478ffc418e424c52b3fcacd2f94eaae98a566c3", - 'tp1n3p08.png': "fbd0f987d98d96f85679ec237c05925032e8d7783551b3f3cffb1b7db6ebdb3afb61214460386b2a3a011826bbda8340757ba22727325eea9fe518c136969f24", - 'xc1n0g08.png': "6aa3e16f11e82378fa7d3767a785840960f2c152338374e3f64f94eb0799e1f29637a1a66435b6dcdbffb9208efbff65a70e17e80f1e05b3038a837dcf79312c", - 'xc9n2c08.png': "7e0d4285bc67345e092656f04b235b4fc273c7892e26dea339dc2bb8df6348d8477f7e6573fe4f40ede1c94b49a60d46ef47ff4f7327fb12cd6de3737e8b5e4c", - 'xcrn0g04.png': "f971b781eb229ada882bb333bbcce956740f9761581d68ba95b49d998b89499bdd4598c4155e72240d6a5b74c04d7081fe284f78fd3f85f2550a3d2171f6efbb", - 'xcsn0g01.png': "9e1d234c3775920546ab9f9eeabdb75457bd823d48ed677fdfe61a95c02c65730182ba7e84209bfbf59de5d1bea533ca57c90ff6a49ea6d5749636f949bdc16a", - 'xd0n2c08.png': "6458d4b8f10a01ff86207496fbf38b25c35857cc537e9e11085fd5fa7befe956e707e6c1c61bdd76a393a816fdc916e2003fcecf5b33dfeb53c4bb071110eaf0", - 'xd3n2c08.png': "fdf261941945d1231ff3b8e91db063ac5a52e8e56f1fc80c5c51149ed255a4eebb4351194d76ae156bdff1eaf5180184c2aa2dd27e4129498279360e00d7db4e", - 'xd9n2c08.png': "b7a3a47c0863bde4ae8aa5ef5fe5d43f8e29abb413dc002553b63d6a4c1fb79eaee66011f1f45887c218aef3fcd63fda847a1b1bc1975252c3b4fcad553c7b70", - 'xdtn0g01.png': "788ed6f9e7ed64e5f4dfa8b62dd88f6f37f7abd1c8e3abf4db2d1c46f0344e7ba638f6721e69ebffa19cf6536f7685f485e9eb548a3cae55131963da05950acd", - 'xhdn0g08.png': "1f06044e4607902e7bd8ba291bf2b9bbb855a881b4a7dde6a21e9f5f9b74f0f43f55a8aa31fa6d1c225d0dc891744943c1544aa17836b3ecf900f041b1cca23c", - 'xlfn0g04.png': "bf3467f8aa9d35f7ae17cd59c3b2d5f6bf110b71afdb3a501ee88306647d669e8419e78b93b995651193a9ff99c849f82530a0bd410cec445feffe36c8df8dd1", - 'xs1n0g01.png': "d1bae1e471886f1661354f23b3564a34c9e1b076bd158ba129388aeb1f287d39ba647269b955bf3cc81f2b962ac6a3eb1a887a8c85243574e84778e48096cf88", - 'xs2n0g01.png': "abd509aa6253d8367980e4f6f4d96bb4b3732287601a7bd3dfb0fa4c70dc3908937c16e6459961421409c74f9952b4693ed1d352dc002bd120a57ba5407cac1f", - 'xs4n0g01.png': "015a1bdc1f878435c3de87feed442e467b3c96f3db3134d1e23653b6759a3a3d68f05325d15992ecce18ec5c00cab7e430c1965ccf36b434d8c9f9a4e8194bfe", - 'xs7n0g01.png': "03dab5037599a58f25dcbd1be556ff60dba08ed3e0e92e5791c53e98041b0ef174a9ebdf75fd997696521ca96a19ca1bb9a5eff929f1a7c0dc1a7d3598d07d04", - 'z00n2c08.png': "9a65f94ebb3614b65e093534a7763f55687144fc9a82e2680e7cad9863d72947a0de3dfe57468e11b578234b8460485e8ee895c681c391d140d84b15c7a40f41", - 'z03n2c08.png': "847fd249d190ccd8ec54afc910afaecf007db7ea5753c18eec8de654b159f4cdf99b70bdd55ec276ce5340fd2ede5290468fe4c6029b5e4c0825ca881a75bde3", - 'z06n2c08.png': "94268c1998de1f4304d24219e31175def7375cc26e2bbfc7d1ac20465a42fae49bcc8ff7626873138b537588e8bce21b6d5e1373efaade1f83cae455334074aa", - 'z09n2c08.png': "3cbb1bb58d78ecc9dd5568a8e9093ba020b63449ef3ab102f98fac4220fc9619feaa873336a25f3c1ad99cfb3e5d32bcfe52d966bc8640d1d5ba4e061741743e", + 'basi0g01.png': "eb26159a783a4dcf27878754e34db6960e992072fc565b12360c894746bc6369101df579e3b9a5c478167f0435e89efb2ab5484056f66c7104f07267f043c82d", + 'basi0g02.png': "f0f74d33ee4b3d3c9f1f4aacf8b0620a33cf1d5c6e9f409e11b4a6e95f2ab1c9159c1bd0bcf6f9553397bf670f4c92712b703d496665d4c6e88fdaf6a0c98620", + 'basi0g04.png': "7b81665f353ff6347304b761d26b4f1baa6118daefc4790f4b0e690150a4e6306514f2aef87e2c39e83e56a0b704df987b10a5366244da58697cda4d5d2745c1", + 'basi0g08.png': "6c809574674494d10eb04c58191c4e0b35813c45962ecafe36a9fe5ba44e5d74ba098e0a524a30c1508eb2dad601f04d5230dceb61a307ef1120f07a8bcbc92f", + 'basi0g16.png': "dd439069fb704b8deff3de822314c012e91a0bd84984d2e79888c6394b78557a0ae6197a7b0a4d64eb4e16fc758946c4f1f13d0d06e512ed9743c4a355b02488", + 'basi2c08.png': "e851fb030f88ead2541a01591882dde5fd9f5dea6bb2b11b374394ed86abc7289e72c4c90808b261aceac13111d3c05b39033168b42ffd1c7ea367314b3a8dc5", + 'basi2c16.png': "e0f81dd459860f7eaf04a2c54932547f41cdc9903a1295a26cc4a2087fd79c98a2e5d5e74f22345dba08b1eb12f3f53c9b904c88b756cbae0c19f9d680e2f1e8", + 'basi3p01.png': "aa21cbcd5d64e6e88056af907509f3b98b00d105198ea2a669fcb25b6966f06d5e4e3afc160b2382935e8ab8e7ccf61733424dfb39b9e864306b82f8355bbb58", + 'basi3p02.png': "d6182370236630d42fd75eed7dc54079ddb7fa9bd601eba22a8dc3331dce31b9a9465027145c29bd56cf778ab0ac029df6aa6481ef65c9464a1ce1d89423faa5", + 'basi3p04.png': "2b35fb98884da370f25833d25f0ab4b188cc26440321e95519131c675818c128b2029d38b3477ef94d88052ec6e9f8b1f7410c5576ce0b47b2fb7a5ba771ce48", + 'basi3p08.png': "7415890831958ca34c73de3e33a9c88980e788d10c983c3a00967886f05053d359499bf0bad386af8ee1bfdb73f666e1d541b0ab682c6092ebdbad3d93e145b1", + 'basi4a08.png': "22ab23a3070d9f1316e8c65b333745e4abf6dcbe63d9d0ada7f6881604b498a92e5b49eb8c1e32f453f4319d94d3d0f48441bac2e79ea528fd7ace0dbbacea9f", + 'basi4a16.png': "2b1436a619f91cf4045e18acf03201b5e9c7774fc77e4c3f38d668984d98543fe64978e80854f30adfecd89b71632945250508bea9eb1ce8e9145e3e55bdeece", + 'basi6a08.png': "aea929866edc5e607d7dc90fcd871f4b6d548abb379b9427fce75a773705e0d8c3ed03bb64e530482b72973eb09844638db5db93666ca1605ff6bbaf194f70e8", + 'basi6a16.png': "29b6ce7c2469e24587b87559f85551334c51bd9d7867f4066c0f7dcb01d710e11e87ee8654c91dc986454cd70f8bd6021e2086ea40e48a28d68a9bdf2283573f", + 'basn0g01.png': "52da610af6f97b03fd8e9f8e52276227f57a97e2bc7e47ae9484b2a37472330f8f5ecef2d6de7fde8f7eb8f144f233bdcf8a3d716c5d193e44d9590af2709cea", + 'basn0g02.png': "676c727faf143af658ed6c6333b15e50387c566c1846a4dda636ed4a2dbb1c0d6d32f0db635479f6851047a32c6d9c52898cfda004ea986853f3ee13750ed90a", + 'basn0g04.png': "123a6652b56f5b858373836509f6b7433221e6ff4eb9ce8a68d0d12bfb27cad0c1bb0cb159523ef1ae5997cb07f994bfbfeabcf0a813aa83495f8269a7a6c4e5", + 'basn0g08.png': "ad5ff30613a462a9b61242d42bb7c854b8247d80a1d03a3919dfdfe8a91c8a962ff51932b2411f714f1be7b803cbd4605c1d4441882cad7e8f44dd8d927198a4", + 'basn0g16.png': "40a96ed10ad5cc58180701e0bb6d6f36c1752c8b8329a80be2960535ad9e168469efbd8f3dc825b57bf65e78a3b61835f19697f2a22511f79c06ce2c6a0034c0", + 'basn2c08.png': "fd92ba13d2038c632fd8bdd3e33971cc69f561bee1eb04ff7920625c6771e0cf7fdda29e48b8a6ca71702c0624ebbca232793f28bb2073b0247d30ce0c549ad5", + 'basn2c16.png': "f6b3cfbc70ae502edbeabde828823dc079dc4e9a586a7fc326c70caec3033124121e3ee2e6481e6ce966efcdef9376cb3ec3edb8e677e91563f510bd6f6e83e6", + 'basn3p01.png': "d262c97549cd1d43e36f5990dac051ead80f1456693c8b1e19a8a48796195831a6ddd5c4a0ac44d22fee51ce4d9392c1c40a0be05571b1b2a961691636d69cd3", + 'basn3p02.png': "a00e375e1fbcc23de38b3b11a0fda4d0204f55473f74e37e0bb5c5f391b37c019293ccddbb99196b9457cd0b7fe5b9e34a55dc6b8167b6909b38813e37a95e46", + 'basn3p04.png': "1a6ab4c567e75b20ee6cdb400dd1f7764a05679c35010e6144fede5a55767dd1861df8e6240e1e59d4166e25d972ff05a41cdfd527818b6ec960a0f9d57d0939", + 'basn3p08.png': "b8f99f6410cc1ac0ceb366e93fc1008f45fb2499e39c489fafa143e8e881f334735e118eec93dde687bf4ea524b4548741c520d770ba6d7071e8fdce576644de", + 'basn4a08.png': "4b7758d4fce3bba95ef3d09cff0ab28c21b8bf568156730fd4e3bcea1c1c2d3ff77f53fe3551f617bd01c8c96e929eb20bf04f5c1a84f37c3cd6bacd4730e6eb", + 'basn4a16.png': "aa0c411f8bb15fc801b072f1048de2fd08761fe245ad267e8503eef8ffe1c39be845e99c04245771afe9b102328129f6375869a4e6cec60eeca641b3e5df3a8b", + 'basn6a08.png': "78d7c811c5463ce53a50874baed840ba70c811513e0ff98fda15a08f01ac6a7c7139a9979cb3688451af6b7e2981699be3c27a386d77af5e60d1acc9e23cb103", + 'basn6a16.png': "e1ad0ed2bf5774b2733d23f2ea9570c6edc933298572933010144ef07bfe6a7878f7367a76f2affbf9845d5b69ea3c84b885f9415e18e752fb1bf21d0dd9d9a2", + 'bgai4a08.png': "22ab23a3070d9f1316e8c65b333745e4abf6dcbe63d9d0ada7f6881604b498a92e5b49eb8c1e32f453f4319d94d3d0f48441bac2e79ea528fd7ace0dbbacea9f", + 'bgai4a16.png': "2b1436a619f91cf4045e18acf03201b5e9c7774fc77e4c3f38d668984d98543fe64978e80854f30adfecd89b71632945250508bea9eb1ce8e9145e3e55bdeece", + 'bgan6a08.png': "78d7c811c5463ce53a50874baed840ba70c811513e0ff98fda15a08f01ac6a7c7139a9979cb3688451af6b7e2981699be3c27a386d77af5e60d1acc9e23cb103", + 'bgan6a16.png': "e1ad0ed2bf5774b2733d23f2ea9570c6edc933298572933010144ef07bfe6a7878f7367a76f2affbf9845d5b69ea3c84b885f9415e18e752fb1bf21d0dd9d9a2", + 'bgbn4a08.png': "4fb9b1023c8c7accb93cf42bd345846c787735df01f7db0df4233737f144e2d5348afaededcdd8c2bcf2e53ce00e2ff095c91de14d7818b4b41c396ab85c9137", + 'bggn4a16.png': "302d7c02ddb0be62aeffeeda46957102c13a2701b841a757486cb3eec7b5456cfabc6ee1954f334ad525badc7c607621a72559b01ce338a0f39e2426d0a03fce", + 'bgwn6a08.png': "d380c477775d102288b43c387dbd7b931f85520f2f6151e3ccc5a25764169312d98fcebf69fb86d3d12520edc3de9bfced559ddf73366f0679e52defb9116424", + 'bgyn6a16.png': "b688d395552eb2a8506fa539ee9159b40a57d02c81860bcf76176213504eb10bdd89de7ce9da452e43f2a46c15290755cdc4816738620b27aed45b3ea7f7ee84", + 'ccwn2c08.png': "c4d58269ef360e42870cce5fb0b1134bfe5706f172c5ff916a338978798fc541a463ab4fdb7c91c424fa385f0ac5d6f576967f178b858d7503f609b2daeacb64", + 'ccwn3p08.png': "d89becf7d24dc57c931a8af1b9dc03ae10302785cc67028cec7255e1aa0ffb0d508d894023a98c10a24cf145aa60b93f977acb8231c8fee9d3f0934484757c30", + 'cdfn2c08.png': "a5faf9cfd284d3750ce2c2f8e15d0ff1bca09da4a9d46b8797c7a1a9f2ebe79d7a7a552bad3c3c049d6186460e81e1e7f9b94e7bb98a3c79d2516f6fb7ac6aa6", + 'cdhn2c08.png': "396eec14e76c00d22ee153171243ac531dcf7adad830948dfd5d6f0a84155734b90407e74f8c1ab8cfb0af5084c03f511530739751f8da070379c826545d0237", + 'cdsn2c08.png': "051b0defa4363ceb3fbc44f460f99a10cdd7c15797ea6d8aa62513b8b6fc5000fe542899db464db30eac56d0c9cd2a5d3778c6962f3aaa85a20881951a7f963a", + 'cdun2c08.png': "946074446fb99f0b790146df0f6e362c68e79b46ec7cbc4ce3d3dc9f75f66e58715caac4b3d7aa8fe8360c32abd2702e7228f9c03b4ba2a0d7f2f970a7ba8f32", + 'ch1n3p04.png': "6680e895195295989850129bcf9d0d0c47efca1c3bc363e4ea822c688707955cdcd07ae92e6e213ee388a62e14b51e036f9a9e075ad7b0f736b0cbc5cc4a108d", + 'ch2n3p08.png': "778ba389d9d0bcbe188e2501c7c1d047f1287179b3760b43da0053f0853e77a0575c7179a02f2442b83efa6cc0951b32d09bd7ea3b6848f261f10b8127e4b0e0", + 'cm0n0g04.png': "9e7e94d201a1222383294bd60e2627207b7b99c0bd80aecd677a1b7d8b372de4981b781fb794811d29a4b2c4db4f5a40c953039c31084f8f3de9aff13fbd1dc9", + 'cm7n0g04.png': "33bb0ffdfe54d655683e4e1bd6d963b9a35a6500129b5dd574245e78971de8d19f27b86a76d42056716b90c2bfc950241bfdc6c4b52ee0e125571de36ba61904", + 'cm9n0g04.png': "fd59386d15a1a324c5ff32f574484c1209afe4ad99f7dc12dce45b2a9bfefd33311ec93211fea3a8e61d1ad2f98220b0c15d151be304bdaa7f88126d54299f68", + 'cs3n2c16.png': "93ca3eeba9aef67de15f943fb2383d208ad1a68518ab78c9fa5ea306ad077b789e873f9e453f0354535167aa4e3d3fec715df05e827bf510948bf0e6fa0dacad", + 'cs3n3p08.png': "e8ddabbf0b17db03bcd7ff0c61d08cc971b3b88e3b3ecd2d4a296da8cf7d7708fa5b42ff3d5813d936ab7f5b4bafbf5842fa4c0fcf0cff15258548d2d26882f3", + 'cs5n2c08.png': "4e3eae53e8c27d4c58d8ad8cdff2c06b00a61d1528a41f5566694f10ef33c4a66f40d3d9fc247731c3ba6dfb734c9f2f90ef031c64486fbdf8a825e354fd67b9", + 'cs5n3p08.png': "31ee0f7f789c1203a9b0e81da34960a47017f3fce37bf2b711738ebd535bb3003ef60c2b0b1fca16587a59955c1ae24b9d186d7ead1d3ece6ada2bbfbc5aee85", + 'cs8n2c08.png': "11bbc80c3168f632deb4453f9199c7994255a0f4f2d7d2d2b06a00931fda4c56985b5a2ca8e969893ff2d65bf330c3d3148b80cbf72aacfe0054b612e6ae05e6", + 'cs8n3p08.png': "49ae3a9050487f6cae826407d421f32a8c67977dd057a6e36f1b2e1ec6abdf5cd46c8929ef4d7b565921ed6c9ae0dde89e243714fdf1510503c7d7b8af6d66e3", + 'ct0n0g04.png': "b6a66fda9ad82cb3287a1ef54702926204bbd4186969cdc2e0741a28dae1869ed76939199f44fd7dd78332753cb8b20a53c4bf740e353f2cc4247870cf576848", + 'ct1n0g04.png': "7cdbaebb6be5d9165972b5fa24f2b64ab437f5337f0548f3d212be8aa95e5dee6ff9abd76ec232faafedc4a41ab8825221b6ced2ecab81c1b3ab20042ceb81a3", + 'cten0g04.png': "648769788c3eb4acd06784dc428bab9e7868328aa3cfe3718ee6656e13e40c4502ca5ac1fe6d4baccb666d4a4f6b3a5d3c97d489f9919ae0d26c2dcdc62e526c", + 'ctfn0g04.png': "c40768807f13dee8dd80ab012bf82b7e8551cb20bde3c7b5c4c45ed19c764cb981945ef036292bd9a2838d34b1b52284295133fea326aea9fc391708bf1d1fbe", + 'ctgn0g04.png': "e0cb7a2d983f1c1c38054b02aabeec657e3f85dba3a52b4878798664c8c6db77cef84d01f042368de6e77cd07b7c2cc6e324aa70bd44c2c8a3642f0cc8fc6a65", + 'cthn0g04.png': "b8614c14bc8c32bb3b29d3b0ac9f3d04c0fcaa40818ab86866e2a8ba1e0c6a87a989f499f208a776d47bff8ab09bfa09352d52089b3cd5bf599faf27627a630b", + 'ctjn0g04.png': "02e2e0a5fa8054e7c7e1c583945da06fb31eff9a3fdd1a7c9f76ba3333f20ce60aec8fafe07f608e9d65a6543e97bab0ff8ae66f3995e8035c05a7c53168ca9a", + 'ctzn0g04.png': "ac35974bd1182e339327245ffa1c0afde634b3a67ee9d6e4e22deee983d6d31054e7843cf1720087b88f6510ed70276e9b0bf43deaf861bd16ceb166140352f9", + 'emblem-1024.png': "5b2e174847274069fc8f4e30c32870ddc7c0e3616a3f04fd41583543aa99ac6d9b7d5a63ed1da672c551b4d193568bb58ddac5e87a101b73367c7c3b01e36fa9", + 'exif2c08.png': "e81b85aa36c9aab55754dd8b73d42497c38eddf9ff3c2981529eb62993d8c0ab33d1b5146a350dd8a1c528d42a967733b2f86248ac615e0254fed53d66d0d895", + 'f00n0g08.png': "fa362f0262ce522297ce52bd7d18b1dc28a2eee3e099b4104c2fb6bdc3fbce0b70303e6df31b709b4033b41e8acec29c81d456c67cde741243c9a54f1ba17f17", + 'f00n2c08.png': "040e95e05152c4bb30608556c828f453c46253c7e0ab18984076cde29b5b6afea7b6658cb019a2723af02a5aabadb1af3b1190655256f3477cd54b9ebdd4df91", + 'f01n0g08.png': "5c60761dc803de1509ef33b4e0ee350d15488d73f4b4e2f93311beb19667626f42d91af39873cd078617c5a2e7c46cceb831d53299c3ff2e7486b43a02ce4967", + 'f01n2c08.png': "a2762a0c4905d05469178176966e86ed4f14c3fcf5c88336209cb923d76e73acc94c619947be87b9183afc20bcd002ab2cc84d81897ec8fc0a4bdeb02a2b7863", + 'f02n0g08.png': "adf640a6f60662ad1b47b5666d2ce86489c685284e50d47344af7cda37f4a42697b5e249f5140413bb3c3e563cca09b2693dcea8bd9ad9adad1adf654ce00bb1", + 'f02n2c08.png': "5f70f19d318ff1d9de4c2f728d83952b12b59bfebac213766ef835dd19f8214f56fa92318041eff25e720503542d067bc9fdf91d86016713c68eb1c52870bad4", + 'f03n0g08.png': "742efed3d25ada0449ed60e4fe1dc94abbe494870536946810cc0eef5c3bfbebefd9bb6d1a482cd5e2c2ee0f34a74b2ea796772254d05accb6739c1ab4d19cdd", + 'f03n2c08.png': "adfac7d6dcc7354467cb3f65742e30ecd44a09b5913ffb656664c9c4730e9cfab9c5e0df2ff8995d412b1ea9cd30ec061eead939546bf795e50a2d49cd10bf92", + 'f04n0g08.png': "9f229c609e87e6c3b83fa82f4f59d7b6494b70c7f85cc807b3611a12d5c59953f11c163228f2bb8b2e7ce77ad204e0da099ab06f8fc480d3ab0ca99fef83c23d", + 'f04n2c08.png': "2dd8b926d1f370b3d3ebaa982491fbe446f3c22b89e635c76eeab60c9ccd3ee7cf39773108d2cec647e480d40de88c4173369b4a12a3fccfba9e4040752cfb4b", + 'f99n0g04.png': "b41996ddf1b770d01900c309cfd2f96d6e60df8313cfda3585a731f32166aa447bcf66ef4af907d6417528024961408d06ca0894fbd6a63fd47ee5a9ed541b51", + 'g03n0g16.png': "02a49b9735063a4d1888b550ed961251b150794422b00ca3800ebba09cd55bdcba15cc8dfe0c41e5a99b2f4d3976b32b1cd08aba92f3dfc3960c71e28ec6cb51", + 'g03n2c08.png': "70b3d643218e033959c51279439d80982f338016b4355aff12be51e7bc59a79f5a5d519c0fa5f13db072cc667fb9635654766af2a11ea25c1b6673f554ceb1f4", + 'g03n3p04.png': "7bfab2aef6f2c04063c438a8f5cda38f3221892ec22a83ab3d3441a900b97c0a7184336ffc2e0c6748e4d931fc80855eed5d6b208ba6ac0709ef02bfbab3e8f2", + 'g04n0g16.png': "9a1d60c89bd63e1f2c81adf1ce7025b7f465e00f0c5142d8a67b5a92e2b042d41a352704969f237883e376bf50c911db196d46f8c28c30ef5763e1e717710c8a", + 'g04n2c08.png': "8e482c99cbc90e6e4aa678e5dbdc39f5b432d740ff260ab1ec04ffa199d97ed2e06491cf88eb0bbbda2f4133f174cf3741474305d9645e0268916aaaab43299d", + 'g04n3p04.png': "d95a52bdc83db74dd19aaa56b40bcbcea268492498c7b2348882a4a5ea70c2b258462c3d5cef85e5372188f21001f719afeb2fac635006486c8fc84b96cc4622", + 'g05n0g16.png': "75954c2e19aa2ba43f7011adecded403035ecb21595a5d116896d2bfc1b71eac42c9b6f008a748cd21b70004921832b3e0dafa1fc0fda4c51ad44cd2b4d782c9", + 'g05n2c08.png': "272baa8dc73cbd63f4fb9545288cfdfcee544e266c9074b73b401895188a123960a6000959f9c034f7b5abe2bfa5e6185253447bac82e9fbfa9634d7e9981d95", + 'g05n3p04.png': "81105d25df2bbbdce60e90cb9a7d0784326bc3c2857fdca4f1f3ef7ab301627685057b97b8d0c0c725d92bc0b48aa1b156dadf5e302ca35917f0b407689ba054", + 'g07n0g16.png': "cb6babe4e25f4cc7e0c3602d9f0e9e538f46a4c4e40420c29521799c528da31afd07b614ae64fbc0e9d0904c9f3e7395b31452abdc69c6a03bf1b5817035b669", + 'g07n2c08.png': "c61e8f936afda939d6497687597d3381485b7cc00716101fc4d6f3abf44df63659b762c77ee252a8735f8e0be0809961db17abbd42c5deab5bad10d0b6b28a55", + 'g07n3p04.png': "8151fa9e9ccd1991a05ea129a7363e23de80688c65d0554c7f3142ed7099d01d82d8ef122986693718f221202657ff965b1b6387a237b36ae741e3d4ea693280", + 'g10n0g16.png': "28ad93f3bebed928c3b0bb4beecaa1b1b55e480c7922d2a36c8f92fc0de012adab523c42f22871b82c6683a7ae74864ed1c35a76cfad92dc6692be0b78c22f50", + 'g10n2c08.png': "4b922386b48c0dd51aee3852da4e52c5c4f3eabe3fcb000e4cfdf0c0e8b27d6a6f77fed944932726fe884f468ac24d89c5c46d65db99be1ae797bc4bbee4cd01", + 'g10n3p04.png': "9b106a0db8ea7e4bc3876beed0f13d83b6f3d6d7d7211441379dd8d18db080f5dc81c6d15312cc3c8ae569b991852ad48f167229dec033f1a974d2a95c83cb3c", + 'g25n0g16.png': "0910ee601a4c4cb546c3bf2b5e8a799d199e34e1434c58c75ddad17f2b295920cf3dde9fe05eee19689705f76b11474b4edc73f4ff346b6ab2d02ec40a13d3cb", + 'g25n2c08.png': "080ed57fd4185c00c6c70e48c27612621393a6ef3987aefd1481611f74d0aebc58d1a90386e4e7bb0321eca961e97cd403a7e727f7324196c5a3cf0e07bffce3", + 'g25n3p04.png': "1deb4281d9792af858e715c39ef7e6756f3004845d87f52054efc9f02c679b2b1b6c2a548a5e6a3f31604b115469ba4bb81510470a47ff9a22b133427375a8db", + 'logo-slim.png': "0104624a95b1b8a97bb5013927cb8fbe330a8c9e7197814147702702cd1d44cdde956404786bb0e69927c6b03ed8031bab566599b1291b995ce747f7cb2135eb", + 'oi1n0g16.png': "40a96ed10ad5cc58180701e0bb6d6f36c1752c8b8329a80be2960535ad9e168469efbd8f3dc825b57bf65e78a3b61835f19697f2a22511f79c06ce2c6a0034c0", + 'oi1n2c16.png': "f6b3cfbc70ae502edbeabde828823dc079dc4e9a586a7fc326c70caec3033124121e3ee2e6481e6ce966efcdef9376cb3ec3edb8e677e91563f510bd6f6e83e6", + 'oi2n0g16.png': "aab1bbfc7b711ba66260985bd8bda6ffaa1e09a0a546b2fe8869b508d823a9e5a412ba6337355a81d87f010e9db8c95eee5f5084b21ddd5cca5d7db7725603b0", + 'oi2n2c16.png': "8d1dd257f3b1bf44ef0bf38338a1e3f2ff78670ac779959751a56231109ca1ed82414f50a221aa45333263073e1e1a950ac8df8e5318e2ed695422d49400c540", + 'oi4n0g16.png': "7675dfa4cff547c3029b21cc892b90a8647199dc9290add932535b04b4eaadaedbc338704f98a075f4690b87815eec8cc0f90a3dbaa2a7809aa03f238ebc5815", + 'oi4n2c16.png': "66313c9d4731e2a9fa006ee9e43c6ac4a3034ce2826c6213f67bfa349bb8bb3cfd8acd2c4553fd1fcd4b2f43993a54539ec8b7fb7f07b3a406adfe919f17b065", + 'oi9n0g16.png': "5615cd4c277be96b21031827d08c8fb2971fda090a0031fd34594f77f7cc558bc68917542597a32bc39c0cd29f7759f0f0429203aa285c163bba8c8f78894e72", + 'oi9n2c16.png': "e2184c00b952a3aa53078a5f995715fa683718a9cbe42705fae3a7c77b236ee6ad706f6dbf2c243aeea17e2c53e84724907724634545e065dd16ff400f5677ab", + 'PngSuite.png': "af1d473e986b3f5cb1006340f8f99156e980e2f8c9f804f0e27c57a51d0dec332a81d99c6e50162f63792d89da44857a6072f8431aa735f1e8f86c06520eff4e", + 'pp0n2c16.png': "82ee5674861b5f9bdab6cf41910d980fc33b5188e191b8892b051dc3b3bbceb4c6d421cbed7bc9b71a9a14db43991c0458ed2cbe5166939f1cbb1e20e445e8b1", + 'pp0n6a08.png': "71c0d4c87b6b2644a4529cd240c8d583c25d45e79fd8bb71ca850dada37e46571052b2da28b926a8194169b82da505c9a3e3a701816d91ac968ad6ff41132b70", + 'ps1n0g08.png': "b273e94c2f826640b10b27b50c605be06541b397ea1289be6f4ea821dff6c7b4b209ec8817a315db442de04c975b7cfecba07b51c6cec965ab9062c05ba04edd", + 'ps1n2c16.png': "833993b81801432eb3a9dbca81f4fdd8ab720c76f8d99a2d298fa1dc4ebd19759c158dd10a68f690f999ea643f62fb7e779e916df86aeb05c43bc4db62aa520b", + 'ps2n0g08.png': "4abea03946d751f03e1438e5987ae691607e528c577db52e893051b54a5d147969dd965e44aaf5540fea75baad873327d76aa71a07c81de31f04f3b781d01e3c", + 'ps2n2c16.png': "bfea51d7be49c04293de034c7649472d34becb663169608490916795fe988df7b812ff8950a3f8d896ee27756effcf9fb525d8d455226cf3965595ee85188581", + 's01i3p01.png': "18b405c902977d2553aab1738a3c00e602e40d11c121a7007c9b7b4cc499aba1fab12fc12aecbdbd5b5cd2638ec5ca5157b5d8fce5dad3cdc3bea02b0904c9cf", + 's01n3p01.png': "8e3e1c9754ebde8c687355b80eee4bf0e0ee8e37b39b784f1997cd2eb60ece7f077b40c8027b0d7f4b7e8f242c22173a244f4e599db33985187439bd918d4486", + 's02i3p01.png': "3e26a8cf35e3df1650adc1656f2d3e7c9b5e1c7932826cf792cbe2cc538c1283ff145f66e4682d459bb0b4f2a2f9ce7209f1997e336e06ca49a83f75270ccad1", + 's02n3p01.png': "d34685ade19ee550ba52e81657627832cb9ba3655f6fe336ebb5fdc4d35c380e819efc1556e1bd1ca2b4e456727dbc5312eb513e7254dfd057a25963e57f0ff4", + 's03i3p01.png': "818a2c91d6c0f96b13806d945d1fc1b4c64f17a9b6a2ede2658c84e20269cd80289312a163761165f0d99e1824f283844f1b4696af314c05714fd349acf7609e", + 's03n3p01.png': "fe847a62eb64bf9db4d9751600b19333f057b626f2f2eb80ee78a3374ae562944c2ebc9c2712f3bbf862798ef9205f38297cad44e8df5dcd96c158ca2e9d9233", + 's04i3p01.png': "1c63332a0d2f31b3a6457038ec2b8c5b4bd3192320fb1c44873947375dcaa028ea07151853e53c6f3fff6878cf90adedea35ae819e5a1b2dbf92399b29464d56", + 's04n3p01.png': "1312d9f3e5bb07b6cbf0c6798c3ae9b0a6cebae465ae6d4ba115ef585616b3b1f7723c6481fcfaa00626d6c62e4fbff7023faf1e92eedeb5354b9805542d43b6", + 's05i3p02.png': "13225a16a79579c4040cdc03f11c71d8589ab322a4f3926e32d9499fe4ca8503a43870e532b2da2597a6c3dd89c3904428cf89c25a8637d40bb3a353017cad5e", + 's05n3p02.png': "d07f2ef30c06a29b9c5c6a52ce1485a3bb9dacb5f119c2829c4cfd69c8fa272d6065eab21a5acd016bdb4f4c724214e8a737c2b76e0f0151e6afcbe5586a37ad", + 's06i3p02.png': "b386f0387e8496849b6d325e710440f7937a403b123886a52af8327e69e411fd632db19daaecfe2e712d49279630515d7217533112acde73cb429e2cfa465b63", + 's06n3p02.png': "df0968c77975f350a86fc09c047d9e3a0a2b71890a0ae67bdfedb23e7f0ce303ff883a463668e10df1dcf2e57cea8cf1fc7c836f5d13a73c1ecd8d66284fc0c5", + 's07i3p02.png': "0f67816f188ce11f15d0f345d2695f1920a322d84be3f332d542c5d20d10a9cef2cebf1e8ae778b25677beeda229c06221eb3450b851ea0e8cd102e5cad14e66", + 's07n3p02.png': "0af60c935e2da2a8a3173edf614085ad0df095c882a140437bdf93ecd5494cfeb5c068dc7ea4d49e181c67d26dd9cf8c969bb2d95f2fbce212ddf5817dd7f642", + 's08i3p02.png': "3204dd0879b6b1284f197a0437e674c4280adad180d4a1d37dff1555be1924d6234dad5d02266aa575d782c53fa52fd4580d452482ba939c732c09709075306f", + 's08n3p02.png': "135039621ce2079465ef49c1b7e5a5aeab299993d2bac864d822ff0669843df1e733a729ca5226ec05c94ddfebdcb2f4b78699fb3adb741db993d9757b4ca71c", + 's09i3p02.png': "dc4d8ed06a81fcd604f949f43e7d5f482c3ad9efd113d220b709de38ca0ca1a340f4cce7e929ca6323390b4ea7c4399cf2f1f2e34c1ef1b38c8296b51d7e8f4b", + 's09n3p02.png': "96b8204f7008899993d8d277ff42c8eb7c85e7cd522cae2e9cf28b8e10e3904c7ec2e3227372f397f6c5a381875dd747a42409471a29ad5049240417ec1441f3", + 's32i3p04.png': "a4de495c70f54eeccd115492a0dfe1cbbcf7f308343eacf6a57515d7a248b356a2639f5e88246d630c8713724cfd7ab1d5d388c677f026a1c5c9b4270a837c67", + 's32n3p04.png': "757009a2fdf19d1187d85930eeb4e75c6831387348fd8e618d1ef971c27d2682b2464b4160a743a6c6d712553fd7fe1f0e5d78226e348f270093495297ec83bf", + 's33i3p04.png': "19259eaf76a42fec949a21c4c55715247a027c2b59ba4bd0f45fdea1f3406cb475c33213b662fd64089b697a6cd25700364f76923dc2531fa0b39546242b3356", + 's33n3p04.png': "3f42b5f3896c1a47fe5dff9921d56234b4326dcffb70a7c6b1f0e7193a6f8f898438635f3b1cfef92c59d7ab827e2a3f40671d97c8547c8e7063a0076c97fba9", + 's34i3p04.png': "db0f7fe138fd732eae4a5c1b8d013167eb3be4afa86141b3e6ad096eabec67644e3108189311b3ce2c78f891d1ea7f5dfa1c30be59509edf123696064eecd00c", + 's34n3p04.png': "e35d9338637ae4c7a1c74a0e73a5c4ba405c2b0d36efd92512b7572d418c25e7d06361be2a8d16323c2708ff3921da24b76be5a41bd3cccf09c27ad472078261", + 's35i3p04.png': "9f0602e1160b81c2e88fc30daf295ff29c4f6faa5a3391c69d895621e7ab76e2071ced6f5a798e294f69621bb32272070ff4ceeeb1436b1cf03640417961a9d1", + 's35n3p04.png': "f12e6a7364073b7a010db0cf952989f5f5da20c592b0256efabb5e82e96d928dce7695c2a0af0749ddfa2739e3ca985463eb0f4a7fb6b8ab0638d65079fc6265", + 's36i3p04.png': "a2d0374bba6fb665deda98b1bd0ef767243b7a974b9f00c78d54bdbfed2c00decf6faef95816ef711efdc359247142be08ce2b86f7860b7384948ba394b4dd21", + 's36n3p04.png': "e200a6869dba1fc9e2eeeff6e686e02313c366a990bfb5582f66dba486251392a465db03806092543008e1130624f1d16cde61613d0ae2a9589941f69a1608db", + 's37i3p04.png': "555f1f7ec2d8ddb58ced7162a4dec315780be13b7cb9ed6d8978046c7fbcb91b4ecf6fcc5c99bd5b8b8d348e4cd202d882a31dec1ecd25156af8968c4a06fbff", + 's37n3p04.png': "d28b3f442b481214774d543924ab07b75fee5916262e6404992962184ea0059ca34fb32d14076642ecd83a3063966ea80676e3165759632782ffd844702cb74e", + 's38i3p04.png': "d4fe0179effbf28f7d28c0192de614512870367cec14ca04d86eb9fff9d6864b1074a68144023244e46cb69ad601e81632c36eb2ed307a32a3c37b7683f882d5", + 's38n3p04.png': "19d23ca8b9b44d26bc9173a69d1d8332e4e7b2ce6e6422195e71dfd0701158023253b130a831a035b2fce0a1556004e8de74e893caeea3d12410909e6e649831", + 's39i3p04.png': "f0c783232707d288b086398565918079e510677742bb5dab09b4520687a06809ae328d24508ebd8f5c26cf85105300ba98e55c29e3773579929839ed9ddbf7fa", + 's39n3p04.png': "39763c31a17edf2751442cf45ae3cc315623ed5b04141bbced2ee8d233485b2d1a2cc0678d60a1c84e3d89a7513634bfd9c82b58754cdfe95885f7a54ff18e2c", + 's40i3p04.png': "d33b29e6669accf1325e8212c555a6cb1d8413c445140aecb62eb6b40912743ef7c6298ad4bc2e232bc448ddaba37f79fa4d25e0cc8e3d53a5ebc93f8f984555", + 's40n3p04.png': "463eb60a2f0884fc368ea0650c5b7b6469c1429e5f006a6537e4aac721094bbd57baa6bcfe4025939089e27b344d7077ff09618e9ce3a5bd40ee3fe5a0e33ce0", + 'tbbn0g04.png': "24fb55d9fed351946869552edb15bf20a2e7a050094ca4b51ebd135958f8b77401e0e9b18618de0cbd18f835e16df24dc57ef094d3b456f0eb9f73c31748ce2a", + 'tbbn2c16.png': "ee98ae3a1cb4a851830ee3e8f4112d08bd74c2a05b778ce51102780ba9d7170c5200c9cc4e1a5c0833618ebe137595eb8fc0591b8798bb6e4e94c234f8cbba3b", + 'tbbn3p08.png': "ed325815b8525d3a5fa37c968b7c85946add7c08abd1c66d86e0264951cfa5a377078b910a78cc664ec2c43d352093c2609b8d01c9572f4ba922d98264e55c04", + 'tbgn2c16.png': "e6da4190d4cea04b0002d598d68c0536448899dd8fca4931b44bc8ea6d47e6946c55ebc5d2049936db2f7f52caef124648d25a360e838571f5f7cb2795eb3657", + 'tbgn3p08.png': "865358d285a8d8682a16b050d9c1b7492042e1a217b0b5753ad28ae1a698dd77150f8cd6510f345157e1efa1411b4e4d5938a81024c150c9d5e76e423105d9c8", + 'tbrn2c08.png': "cc3cd3b8b6cc9920914e0184bdedcf9e59975db3f99c39b93ea1202cf6e11689eb966fc40ae2caca8ef224a8aac03723142b58b701ca2a02fd73a62e379f7a6b", + 'tbwn0g16.png': "fa8359bf8cdac3ab9ac54cd4f1e96b1469ff3e3494102be179b5c7394a4e37953ef54f5e1ccffe771b4f028225ec164b410b0d08f82224ed93a654433feb14fe", + 'tbwn3p08.png': "a0e10707fe9df085596a724561ba6c80662f87095ba479b2345c985f4beb2933f7767fe3d07b30002591259dc14012f4b26fa9b503cc75fd644def7c27c9f2e6", + 'tbyn3p08.png': "9920b40b016c4a05a094c28a989d06e108e2ebd5d72c2a6ddca359b68ad95238b0b6dca0f60b78c56b551a2e44f924d5a443071bda6f6e31669b0a78c09b18af", + 'tm3n3p02.png': "e9910a8ccb78a10980c55c6ca7115757b48075e42c14a83aece92a7f85eee538d5e1d9301efc443a867628993ceff1c13aebcc574641ad85eec48ae05df9997c", + 'tp0n0g08.png': "57fbf8a07060565c23918420952d1feb506ce5b1bdb25f22d41ee1de4ce9655c6dde04b9643d2491b59efba229b7e0cacd6799010a89005802c28a300a4e578e", + 'tp0n2c08.png': "eed3f6c18bd81d96870a47c737574746293c71c517b6a5ba88afdad5ef89fa30d975717f8a8f84ec16cb98390353934cbdd6e4b099e86f0ca3fe8d50fa07bb11", + 'tp0n3p08.png': "9650347d0f4a1a6596828f48766949947148952c93c4899541324a48289ea558c5d7bd1a076ac0e32f71d197e478ffc418e424c52b3fcacd2f94eaae98a566c3", + 'tp1n3p08.png': "fbd0f987d98d96f85679ec237c05925032e8d7783551b3f3cffb1b7db6ebdb3afb61214460386b2a3a011826bbda8340757ba22727325eea9fe518c136969f24", + 'xc1n0g08.png': "6aa3e16f11e82378fa7d3767a785840960f2c152338374e3f64f94eb0799e1f29637a1a66435b6dcdbffb9208efbff65a70e17e80f1e05b3038a837dcf79312c", + 'xc9n2c08.png': "7e0d4285bc67345e092656f04b235b4fc273c7892e26dea339dc2bb8df6348d8477f7e6573fe4f40ede1c94b49a60d46ef47ff4f7327fb12cd6de3737e8b5e4c", + 'xcrn0g04.png': "f971b781eb229ada882bb333bbcce956740f9761581d68ba95b49d998b89499bdd4598c4155e72240d6a5b74c04d7081fe284f78fd3f85f2550a3d2171f6efbb", + 'xcsn0g01.png': "9e1d234c3775920546ab9f9eeabdb75457bd823d48ed677fdfe61a95c02c65730182ba7e84209bfbf59de5d1bea533ca57c90ff6a49ea6d5749636f949bdc16a", + 'xd0n2c08.png': "6458d4b8f10a01ff86207496fbf38b25c35857cc537e9e11085fd5fa7befe956e707e6c1c61bdd76a393a816fdc916e2003fcecf5b33dfeb53c4bb071110eaf0", + 'xd3n2c08.png': "fdf261941945d1231ff3b8e91db063ac5a52e8e56f1fc80c5c51149ed255a4eebb4351194d76ae156bdff1eaf5180184c2aa2dd27e4129498279360e00d7db4e", + 'xd9n2c08.png': "b7a3a47c0863bde4ae8aa5ef5fe5d43f8e29abb413dc002553b63d6a4c1fb79eaee66011f1f45887c218aef3fcd63fda847a1b1bc1975252c3b4fcad553c7b70", + 'xdtn0g01.png': "788ed6f9e7ed64e5f4dfa8b62dd88f6f37f7abd1c8e3abf4db2d1c46f0344e7ba638f6721e69ebffa19cf6536f7685f485e9eb548a3cae55131963da05950acd", + 'xhdn0g08.png': "1f06044e4607902e7bd8ba291bf2b9bbb855a881b4a7dde6a21e9f5f9b74f0f43f55a8aa31fa6d1c225d0dc891744943c1544aa17836b3ecf900f041b1cca23c", + 'xlfn0g04.png': "bf3467f8aa9d35f7ae17cd59c3b2d5f6bf110b71afdb3a501ee88306647d669e8419e78b93b995651193a9ff99c849f82530a0bd410cec445feffe36c8df8dd1", + 'xs1n0g01.png': "d1bae1e471886f1661354f23b3564a34c9e1b076bd158ba129388aeb1f287d39ba647269b955bf3cc81f2b962ac6a3eb1a887a8c85243574e84778e48096cf88", + 'xs2n0g01.png': "abd509aa6253d8367980e4f6f4d96bb4b3732287601a7bd3dfb0fa4c70dc3908937c16e6459961421409c74f9952b4693ed1d352dc002bd120a57ba5407cac1f", + 'xs4n0g01.png': "015a1bdc1f878435c3de87feed442e467b3c96f3db3134d1e23653b6759a3a3d68f05325d15992ecce18ec5c00cab7e430c1965ccf36b434d8c9f9a4e8194bfe", + 'xs7n0g01.png': "03dab5037599a58f25dcbd1be556ff60dba08ed3e0e92e5791c53e98041b0ef174a9ebdf75fd997696521ca96a19ca1bb9a5eff929f1a7c0dc1a7d3598d07d04", + 'z00n2c08.png': "9a65f94ebb3614b65e093534a7763f55687144fc9a82e2680e7cad9863d72947a0de3dfe57468e11b578234b8460485e8ee895c681c391d140d84b15c7a40f41", + 'z03n2c08.png': "847fd249d190ccd8ec54afc910afaecf007db7ea5753c18eec8de654b159f4cdf99b70bdd55ec276ce5340fd2ede5290468fe4c6029b5e4c0825ca881a75bde3", + 'z06n2c08.png': "94268c1998de1f4304d24219e31175def7375cc26e2bbfc7d1ac20465a42fae49bcc8ff7626873138b537588e8bce21b6d5e1373efaade1f83cae455334074aa", + 'z09n2c08.png': "3cbb1bb58d78ecc9dd5568a8e9093ba020b63449ef3ab102f98fac4220fc9619feaa873336a25f3c1ad99cfb3e5d32bcfe52d966bc8640d1d5ba4e061741743e", - 'ba-bm.bmp': "2f76d46b1b9bea62e08e7fc5306452a495616cb7af7a0cbb79237ed457b083418d5859c9e6cfd0d9fbf1fe24495319b6f206135f36f2bd19330de01a8eaf20c8", - 'badbitcount.bmp': "2d37e22aa2e659416c950815841e5a402f2e9c21eb677390fc026eefaeb5be64345a7ef0fac2965a2cae8abe78c1e12086a7d93d8e62cc8659b35168c82f6d5f", - 'badbitssize.bmp': "f59cc30827bcb56f7e946dcffcaab22a5e197f2e3884cf80a2e596f5653f5203b3927674d9d5190486239964e65228f4e3f359cdd2f7d061b09846f5f26bfaa9", - 'baddens1.bmp': "aa84bebc41b3d50329269da9ee61fd7e1518ffd0e8f733af6872323bc46ace6ed1c9931a65a367d97b8b2cb2aa772ccd94fd3def0a79fd1c0baf185d669c386f", - 'baddens2.bmp': "5c254a8cde716fae77ebf20294a404383fd6afc705d783c5418762e7c4138aa621625bc6d08a8946ee3f1e8c40c767681a39806735bb3b3026fee5eb91d8fadc", - 'badfilesize.bmp': "9019b6853a91f69bd246f9b28da47007aec871c0e46fea7cd6ab5c30460a6938a1b09da8fa7ba8895650e37ce14a79d4183e9f2401eb510f60455410e2266eb5", - 'badheadersize.bmp': "90412d7c3bff7336d5e0c7ae899d8a53b82235072034f00783fb2403479447cd2959644f7ec70ae0988f99cc49b63356c8710b808ddd2280e19dca484f34074e", - 'badpalettesize.bmp': "d914a89f7b78fcdd6ab4433c176355755687b65c3cfc23db57de9d04447c440fa31d993db184940c1dc09b37e8e044324d8237877d3d1b1ad5657c4929d8435a", - 'badplanes.bmp': "46f583d4a43ef0c9964765b9d8820369955f0568a4eae0bf215434f508e8e03457bd759b73c344c2f88de7f33fc5379517ce3cf5b2e5a16ebc20c05df73aa723", - 'badrle.bmp': "a64e1551fd60159ff469ce25e1f5b4575dc462684f4ff66c7ea69b2990c7c9d2547b72237020e2d001f69dfd31f1ac45e0a9630d0ddd11c77584881f3e25609e", - 'badrle4.bmp': "2bd22418010b1ac3eac50932ed06e578411ac2741bfa50a9edd1b360686efa28c74df8b14d92e05b711eeb88a5e826256c6a5cf5a0176a29369fb92b336efb93", - 'badrle4bis.bmp': "d7a24ab095e1ca5e888dd1bcb732b19bb1983f787c64c1eb5a273da0f58c4b8cd137197df9ac47572a74c3026aab5af1f08551a2121af37b8941cffa71df1951", - 'badrle4ter.bmp': "825cc5361378d44524205b117825f95228c4d093d39ac2fc2ab755be743df78784529f2019418deca31059f3e46889a66658e7424b4f896668ee4cfa281574bc", - 'badrlebis.bmp': "f41acfd4f989302bb5ec42a2e759a56f71a5ecac5a814842e32542742ca015464f8579ebeec0e7e9cea45e2aafe51456cfe18b48b509bc3704f992bcc9d321af", - 'badrleter.bmp': "a8f3e0b0668fc4f43353028d5fca87d6cac6ff0c917c4e7a61c624918360ff598ec9eaa32f5c6a070da9bf6e90c58426f5a901fdab9dfb0a4fdca0c72ba67de4", - 'badwidth.bmp': "68f192a55b8de66f8e13fe316647262a5e4641365eb77d4987c84ab1eae35b7cba20827277cd569583543819de70ec75f383367f72cd229e48743ad1e45bfa9e", - 'pal1.bmp': "0194c9b501ac7e043fab78746e6f142e0c880917d0fd6dbb7215765b8fc1ce4403ad85146c555665ba6e37d3b47edad5e687b9260e7a61a27d8a059bc81bb525", - 'pal1bg.bmp': "3aafc29122bd6e97d88d740be1f61cb9febe8373d19ae6d731f4af776c868dd489260287bf0cf1c960f9d9afcbc7448e83e45435d3e42e913823c0f5c2a80d9f", - 'pal1huffmsb.bmp': "4e122f602c3556f4f5ab45f9e13a617d8210d81f587d08cbd6c2110dc6231573aec92a6344aeb4734c00d3dcf380130f53a887002756811d8edd6bc5aabbafc0", - 'pal1p1.bmp': "33e2b2b1c1bed43ba64888d7739eb830c7789857352513de08b6e35718ac0e421afcdae0e7bab97c25d1ad972eb4f09e2c6556c416d4d7367c545330c4123df0", - 'pal1wb.bmp': "bc583ad4eaae40f5d2e3a6280aeb3c62ee11b2cf05ba7c8386f9578587e29b66819293992bdcd31c2750c21cd9bf97daa603ce1051fbfdd40fadbc1860156853", - 'pal2.bmp': "7b560ba972cf58ca1ed01910fa4f630ca74e657d46d134e2ac0df733eb5773d0a1788e745d5240efa18f182bd8dce22c7ac7cee6f99ddc946a27b65297762764", - 'pal2color.bmp': "b868a8aaa22fac3aa86bbd5270eb5ffee06959461be8177880829d838be0391d9617d11d73fab1643520a92364dc333c25c0510bb2628c8fb945719518d2675f", - 'pal4.bmp': "53a39fdb86630c828d9003a1e95dbd59c47524c4ec044d8ce72e1b643166b4c2b6ec06ab5191cb25d17be2fcb18bd7a9e0b7ec169722e6d89b725609a15b1df1", - 'pal4gs.bmp': "ab4c2078943afdf19bcc02b1ebbe5a69cfa93d1152f7882db6176c39b917191a2760fbb2127e5207b0bfb3dafd711593a6aed61d312807605913062aa1ce9c2f", - 'pal4rle.bmp': "c86c86280b75a252ccf484e4bba2df45d3747dc1e4879795e925613959a0c451e2fc4890532e8aef9911e38e45e7d6a8baf29d57e573d26c20923a5823700443", - 'pal4rlecut.bmp': "f38d485dbb8e67bdeaefba181f9a05556a986ed3f834edca723c088e813764bb2b42240d4fbb938a1775370b79b9ea2f14277ffe9c7247c1e0e77766fec27189", - 'pal4rletrns.bmp': "b81e7fed38854d201a3199ce50ca05e92ca287c860797142857ac20b4a2f28952b058e21687c0fae60712f5784cd2c950ce70148ba1316efe31d4f3fc4006817", - 'pal8-0.bmp': "f39a4f1827c52bb620d975f8c72f5e95f90ac6c65ae0a6776ff1ad95808c090de17cbd182188a85157396fd9649ea4b5d84bb7c9175ab49ce2845da214c16bff", - 'pal8.bmp': "be27e55a866cbb655fdd917435cd6a5b62c20ae0d6ef7c1533c5a01dd9a893f058cc4ba2d902ab9315380009808e06b7f180116c9b790587cf62aa770c7a4a07", - 'pal8badindex.bmp': "bd5fc036985ae705182915a560dee2e5dfb3bd8b50932337b9085e190259c66e6bae5fbc813a261d352a60dcb0755798bdc251d6c2a0b638a7e337ba58811811", - 'pal8gs.bmp': "228f944b3e45359f62a2839d4e7b94d7f3a1074ad9e25661fdb9e8fff4c15581c85a7bb0ac75c92b95c7537ececc9d80b835cfe55bc7560a513118224a9ed36f", - 'pal8nonsquare.bmp': "b8adc9b03880975b232849ea1e8f87705937929d743df3d35420902b32557065354ab71d0d8176646bf0ad72c583c884cfcd1511017260ffca8c41d5a358a3eb", - 'pal8offs.bmp': "c92f1e1835d753fd8484be5198b2b8a2660d5e54117f6c4fc6d2ebc8d1def72a8d09cd820b1b8dcee15740b47151d62b8b7aca0b843e696252e28226b51361cf", - 'pal8os2-hs.bmp': "477c04048787eb412f192e7fe47ae96f14d7995391e78b10cc4c365f8c762f60c54cad7ef9d1705a78bd490a578fb346ee0a383c3a3fdf790558a12589eb04eb", - 'pal8os2-sz.bmp': "fd0eeb733be9b39f492d0f67dd28fc67207149e41691c206d4de4c693b5dea9458b88699a781383e7050a3b343259659aae64fec0616c98f3f8555cbf5c9e46c", - 'pal8os2.bmp': "cdab3ed7bc9f38d89117332a21418b3c916a99a8d8fb6b7ce456d54288c96152af12c0380293b04e96594a7867b83be5c99913d224c9750c7d38295924e0735a", - 'pal8os2sp.bmp': "f6e595a6db992ab7d1f79442d31f39f648061e7de13e51b07933283df065ce405c0208e6101ac916e4eb0613e412116f008510021a2d17543aa7f0a32349c96f", - 'pal8os2v2-16.bmp': "f52877d434218aa6b772a7aa0aaba4c2ae6ce35ecfa6876943bb350fdf9554f1f763a8d5bb054362fb8f9848eb71ce14a371f4a76da4b9475cdcee4f286109a4", - 'pal8os2v2-40sz.bmp': "9481691ada527df1f529316d44b5857c6a840c5dafa7e9795c9cb92dac02c6cc35739d3f6ce33d4ab6ff6bcd6b949741e89dc8c42cf52ad4546ff58cd3b5b66a", - 'pal8os2v2-sz.bmp': "99cd2836f90591cd27b0c8696ecff1e7a1debcef284bbe5d21e68759270c1bfe1f32ee8f576c49f3e64d8f4e4d9096574f3c8c79bfdae0545689da18364de3e7", - 'pal8os2v2.bmp': "7859b265956c7d369db7a0a357ce09bcda74e98954de88f454cae5e7cb021222146687a7770ce0cc2c58f1439c7c21c45c0c27464944e73913e1c88afc836c8a", - 'pal8oversizepal.bmp': "e778864e0669a33fce27c0ccd5b6460b572a5db01975e8d56acec8a9447e1c58d6051ad3516cfa96a39f4eb7f2576154188ea62ec187bcf4ae323883499383c0", - 'pal8rle.bmp': "88942a1cd2e36d1e0f0e2748a888034057919c7ec0f8d9b2664deb1daf1a6e45ed3e722dff5d810f413d6fc182e700a16d6563dd25f67dc6d135d751cd736dea", - 'pal8rlecut.bmp': "cda9fa274cde590aeaca81516e0465684cfae84e934eb983301801e978e6e2e9c590d22af992d9912e51bb9c2761945276bdbe0b6c47f3a021514414e1f3f455", - 'pal8rletrns.bmp': "0b2d5618dc9c81caa72c070070a4245dd9cd3de5d344b76ce9c15d0eeb72e2675efc264201f8709dfcffd234df09e76d6f328f16f2ad873ba846f870cadfa486", - 'pal8topdown.bmp': "d470a2b7556fa88eac820427cb900f59a121732cdb4a7f3530ed457798139c946a884a34ab79d822feb84c2ca6f4d9a65f6e792994eafc3a189948b9e4543546", - 'pal8v4.bmp': "0382610e32c49d5091a096cb48a54ebbf44d9ba1def96e2f30826fd3ddf249f5aed70ca5b74c484b6cdc3924f4d4bfed2f5194ad0bcf1d99bfaa3a619e299d86", - 'pal8v5.bmp': "50fadaa93aac2a377b565c4dc852fd4602538863b913cb43155f5ad7cf79928127ca28b33e5a3b0230076ea4a6e339e3bf57f019333f42c4e9f003a8f2376325", - 'pal8w124.bmp': "e54a901b9badda655cad828d226b381831aea7e36aec8729147e9e95a9f2b21a9d74d93756e908e812902a01197f1379fe7e35498dbafed02e27c853a24097b7", - 'pal8w125.bmp': "d7a04d45ef5b3830da071ca598f1e2a413c46834968b2db7518985cf8d8c7380842145899e133e71355b6b7d040ee9e97adec1e928ce4739282e0533058467c0", - 'pal8w126.bmp': "4b93845a98797679423c669c541a248b4cdfee80736f01cec29d8b40584bf55a27835c80656a2bf5c7ad3ed211c1f7d3c7d5831a6726904b39f10043a76b658d", - 'reallybig.bmp': "babbf0335bac63fd2e95a89210c61ae6bbaaeeab5f07974034e76b4dc2a5c755f77501e3d056479357445aac442e2807d7170ec44067bab8fd35742f0e7b8440", - 'rgb16-231.bmp': "611a87cb5d29f16ef71971714a3b0e3863a6df51fff16ce4d4df8ee028442f9ce03669fb5d7a6a838a12a75d8a887b56b5a2e44a3ad62f4ef3fc2e238c33f6a1", - 'rgb16-3103.bmp': "7fdff66f4d94341da522b4e40586b3b8c327be9778e461bca1600e938bfbaa872b484192b35cd84d9430ca20aa922ec0301567a74fb777c808400819db90b09d", - 'rgb16-565.bmp': "777883f64b9ae80d77bf16c6d062082b7a4702f8260c183680afee6ec26e48681bcca75f0f81c470be1ac8fcb55620b3af5ce31d9e114b582dfd82300a3d6654", - 'rgb16-565pal.bmp': "57e9dcf159415b3574a1b343a484391b0859ab2f480e22157f2a84bc188fde141a48826f960c6f30b1d1f17ef6503ec3afc883a2f25ff09dd50c437244f9ae7f", - 'rgb16-880.bmp': "8d61183623002da4f7a0a66b42aa58a120e3a91578bb0c4a5e2c5ba7d08b875d43a22f2b5b3a449d3caf4cc303cb05111dd1d5169953f288493b7ea3c2423d24", - 'rgb16.bmp': "1c0fe56661d4998edd76efedda520a441171d42ae4dad95b350e3b61deda984c3a3255392481fe1903e5e751357da3f35164935e323377f015774280036ba39e", - 'rgb16bfdef.bmp': "ed55d086e27ba472076df418be0046b740944958afeb84d05aa2bbe578dec27ced122ffefb6d549e1d07e05eb608979b3ac9b1bd809f8237cf0984ffdaa24716", - 'rgb16faketrns.bmp': "9cd4a8e05fe125649e360715851ef912e78a56d30e0ea1b1cfb6eaafd386437d45de9c1e1a845dd8d63ff5a414832355b8ae0e2a96d72a42a7205e8a2742d37c", - 'rgb24.bmp': "4f0ce2978bbfea948798b2fdcc4bdbe8983a6c94d1b7326f39daa6059368e08ebf239260984b64eeb0948f7c8089a523e74b7fa6b0437f9205d8af8891340389", - 'rgb24largepal.bmp': "b377aee1594c5d9fc806a70bc62ee83cf8d1852b4a2b18fd3e9409a31aa3b5a4cf5e3b4af2cbdebcef2b5861b7985a248239684a72072437c50151adc524e9df", - 'rgb24pal.bmp': "f40bb6e01f6ecb3d55aa992bf1d1e2988ea5eb11e3e58a0c59a4fea2448de26f231f45e9f378b7ee1bdd529ec57a1de38ea536e397f5e1ac6998921e066ab427", - 'rgb24png.bmp': "c60890bbd79c12472205665959eb6e2dd2103671571f80117b9e963f897cffca103181374a4797f53c7768af01a705e830a0de4dd8fab7241d24c17bee4a4dbe", - 'rgb24rle24.bmp': "ea0ff3f512dd04176d14b43dfbee73ac7f1913aa1b77587e187e271781c7dacec880cec73850c4127ea9f8dd885f069e281f159bb5232e93cbb2d1ee9cb50438", - 'rgb32-111110.bmp': "732884e300d4edbcf31556a038947beefc0c5e749131a66d2d7aa1d4ec8c8eba07833133038a03bbe4c4fa61a805a5df1f797b5853339ee6a8140478f5f70a76", - 'rgb32-7187.bmp': "4c55aab2e4ecf63dc30b04e5685c5d9fba7354ca0e1327d7c4b15d6da10ac66ca1cea6f0303f9c5f046da3bcd2566275384e0e7bb14fcc5196ec39ca90fac194", - 'rgb32-xbgr.bmp': "1e9f240eaec6ac2833f8c719f1fb53cc7551809936620e871ccacfab26402e1afc6503b9f707e4ec25f15529e3ce6433c7f999d5714af31dfb856eb67e772f64", - 'rgb32.bmp': "32033dbf9462e5321b1182ba739624ed535aa4d33b775ffeeaf09d2d4cb663e4c3505e8c05489d940f754dde4b50a2e0b0688b21d06755e717e6e511b0947525", - 'rgb32bf.bmp': "7243c215827a9b4a1d7d52d67fb04ffb43b0b176518fbdab43d413e2a0c18883b106797f1acd85ba68d494ec939b0caab8789564670d058caf0e1175ce7983fb", - 'rgb32bfdef.bmp': "a81433babb67ce714285346a77bfccd19cf6203ac1d8245288855aff20cf38146a783f4a7eac221db63d1ee31345da1329e945b432f0e7bcf279ea88ff5bb302", - 'rgb32fakealpha.bmp': "abecaf1b5bfad322de7aec897efe7aa6525f2a77a0af86cc0a0a366ed1650da703cf4b7b117a7ba34f21d03a8a0045e5821248cdefa00b0c78e01d434b55e746", - 'rgb32h52.bmp': "707d734393c83384bc75720330075ec9ffefc69167343259ebf95f9393948364a40f33712619f962e7056483b73334584570962c16da212cd5291f764b3f2cd1", - 'rgba16-1924.bmp': "3e41a5d8d951bac580c780370ca21e0783de8154f4081106bc58d1185bb2815fc5b7f08f2a1c75cd205fc52c888e9d07c91856651603a2d756c9cfc392585598", - 'rgba16-4444.bmp': "a6662186b23bd434a7e019d2a71cd95f53a47b64a1afea4c27ae1120685d041a9ff98800a43a9d8f332682670585bdb2fa77ff77b6def65139fe725323f91561", - 'rgba16-5551.bmp': "a7d9f8ae7f8349cd6df651ab9d814411939fa2a235506ddfdd0df5a8f8abcf75552c32481ea035ff29e683bdcd34da68eb23730857e0716b79af51d69a60757b", - 'rgba32-1.bmp': "3958d18d2a7f32ada69cb11e0b4397821225a5c40acc7b6d36ff28ee4565e150cc508971278a2ddf8948aaff86f66ec6a0c24513db44962d81b79c4239b3e612", - 'rgba32-1010102.bmp': "59a28db5563caf954d31b20a1d1cc59366fcfd258b7ba2949f7281978460a3d94bedcc314c089243dd7463bb18d36a9473355158a7d903912cb25b98eab6b068", - 'rgba32-2.bmp': "9b7e5965ff9888f011540936ab6b3022edf9f6c5d7e541d6882cb81820cf1d68326d65695a6f0d01999ac10a496a504440906aa45e413da593405563c54c1a05", - 'rgba32-61754.bmp': "784ae0a32b19fa925e0c86dbff3bd38d80904d0fa7dc3b03e9d4f707d42b1604c1f54229e901ccc249cab8c2976d58b1e16980157d9bf3dbc4e035e2b2fd1779", - 'rgba32-81284.bmp': "fcfca645017c0d15d44b08598a90d238d063763fd06db665d9a8e36ef5099ce0bf4d440e615c6d6b1bf99f38230d4848318bfa1e6d9bfdd6dfd521cc633ba110", - 'rgba32abf.bmp': "2883d676966d298d235196f102e044e52ef18f3cb5bb0dd84738c679f0a1901181483ca2df1cccf6e4b3b4e98be39e81de69c9a58f0d70bc3ebb0fcea80daa0c", - 'rgba32h56.bmp': "507d0caf29ccb011c83c0c069c21105ea1d58e06b92204f9c612f26102123a7680eae53fef023c701952d903e11b61f8aa07618c381ea08f6808c523f5a84546", - 'rgba64.bmp': "d01f14f649c1c33e3809508cc6f089dd2ab0a538baf833a91042f2e54eca3f8e409908e15fa8763b059d7fa022cf5c074d9f5720eed5293a4c922e131c2eae68", - 'rletopdown.bmp': "37500893aad0b40656aa80fd5c7c5f9b35d033018b8070d8b1d7baeb34c90f90462288b13295204b90aa3e5c9be797d22a328e3714ab259334e879a09a3de175", - 'shortfile.bmp': "be3ffade7999304f00f9b7d152b5b27811ad1166d0fd43004392467a28f44b6a4ec02a23c0296bacd4f02f8041cd824b9ca6c9fc31fed27e36e572113bb47d73", + 'ba-bm.bmp': "2f76d46b1b9bea62e08e7fc5306452a495616cb7af7a0cbb79237ed457b083418d5859c9e6cfd0d9fbf1fe24495319b6f206135f36f2bd19330de01a8eaf20c8", + 'badbitcount.bmp': "2d37e22aa2e659416c950815841e5a402f2e9c21eb677390fc026eefaeb5be64345a7ef0fac2965a2cae8abe78c1e12086a7d93d8e62cc8659b35168c82f6d5f", + 'badbitssize.bmp': "f59cc30827bcb56f7e946dcffcaab22a5e197f2e3884cf80a2e596f5653f5203b3927674d9d5190486239964e65228f4e3f359cdd2f7d061b09846f5f26bfaa9", + 'baddens1.bmp': "aa84bebc41b3d50329269da9ee61fd7e1518ffd0e8f733af6872323bc46ace6ed1c9931a65a367d97b8b2cb2aa772ccd94fd3def0a79fd1c0baf185d669c386f", + 'baddens2.bmp': "5c254a8cde716fae77ebf20294a404383fd6afc705d783c5418762e7c4138aa621625bc6d08a8946ee3f1e8c40c767681a39806735bb3b3026fee5eb91d8fadc", + 'badfilesize.bmp': "9019b6853a91f69bd246f9b28da47007aec871c0e46fea7cd6ab5c30460a6938a1b09da8fa7ba8895650e37ce14a79d4183e9f2401eb510f60455410e2266eb5", + 'badheadersize.bmp': "90412d7c3bff7336d5e0c7ae899d8a53b82235072034f00783fb2403479447cd2959644f7ec70ae0988f99cc49b63356c8710b808ddd2280e19dca484f34074e", + 'badpalettesize.bmp': "d914a89f7b78fcdd6ab4433c176355755687b65c3cfc23db57de9d04447c440fa31d993db184940c1dc09b37e8e044324d8237877d3d1b1ad5657c4929d8435a", + 'badplanes.bmp': "46f583d4a43ef0c9964765b9d8820369955f0568a4eae0bf215434f508e8e03457bd759b73c344c2f88de7f33fc5379517ce3cf5b2e5a16ebc20c05df73aa723", + 'badrle.bmp': "a64e1551fd60159ff469ce25e1f5b4575dc462684f4ff66c7ea69b2990c7c9d2547b72237020e2d001f69dfd31f1ac45e0a9630d0ddd11c77584881f3e25609e", + 'badrle4.bmp': "2bd22418010b1ac3eac50932ed06e578411ac2741bfa50a9edd1b360686efa28c74df8b14d92e05b711eeb88a5e826256c6a5cf5a0176a29369fb92b336efb93", + 'badrle4bis.bmp': "d7a24ab095e1ca5e888dd1bcb732b19bb1983f787c64c1eb5a273da0f58c4b8cd137197df9ac47572a74c3026aab5af1f08551a2121af37b8941cffa71df1951", + 'badrle4ter.bmp': "825cc5361378d44524205b117825f95228c4d093d39ac2fc2ab755be743df78784529f2019418deca31059f3e46889a66658e7424b4f896668ee4cfa281574bc", + 'badrlebis.bmp': "f41acfd4f989302bb5ec42a2e759a56f71a5ecac5a814842e32542742ca015464f8579ebeec0e7e9cea45e2aafe51456cfe18b48b509bc3704f992bcc9d321af", + 'badrleter.bmp': "a8f3e0b0668fc4f43353028d5fca87d6cac6ff0c917c4e7a61c624918360ff598ec9eaa32f5c6a070da9bf6e90c58426f5a901fdab9dfb0a4fdca0c72ba67de4", + 'badwidth.bmp': "68f192a55b8de66f8e13fe316647262a5e4641365eb77d4987c84ab1eae35b7cba20827277cd569583543819de70ec75f383367f72cd229e48743ad1e45bfa9e", + 'pal1.bmp': "0194c9b501ac7e043fab78746e6f142e0c880917d0fd6dbb7215765b8fc1ce4403ad85146c555665ba6e37d3b47edad5e687b9260e7a61a27d8a059bc81bb525", + 'pal1bg.bmp': "3aafc29122bd6e97d88d740be1f61cb9febe8373d19ae6d731f4af776c868dd489260287bf0cf1c960f9d9afcbc7448e83e45435d3e42e913823c0f5c2a80d9f", + 'pal1huffmsb.bmp': "4e122f602c3556f4f5ab45f9e13a617d8210d81f587d08cbd6c2110dc6231573aec92a6344aeb4734c00d3dcf380130f53a887002756811d8edd6bc5aabbafc0", + 'pal1p1.bmp': "33e2b2b1c1bed43ba64888d7739eb830c7789857352513de08b6e35718ac0e421afcdae0e7bab97c25d1ad972eb4f09e2c6556c416d4d7367c545330c4123df0", + 'pal1wb.bmp': "bc583ad4eaae40f5d2e3a6280aeb3c62ee11b2cf05ba7c8386f9578587e29b66819293992bdcd31c2750c21cd9bf97daa603ce1051fbfdd40fadbc1860156853", + 'pal2.bmp': "7b560ba972cf58ca1ed01910fa4f630ca74e657d46d134e2ac0df733eb5773d0a1788e745d5240efa18f182bd8dce22c7ac7cee6f99ddc946a27b65297762764", + 'pal2color.bmp': "b868a8aaa22fac3aa86bbd5270eb5ffee06959461be8177880829d838be0391d9617d11d73fab1643520a92364dc333c25c0510bb2628c8fb945719518d2675f", + 'pal4.bmp': "53a39fdb86630c828d9003a1e95dbd59c47524c4ec044d8ce72e1b643166b4c2b6ec06ab5191cb25d17be2fcb18bd7a9e0b7ec169722e6d89b725609a15b1df1", + 'pal4gs.bmp': "ab4c2078943afdf19bcc02b1ebbe5a69cfa93d1152f7882db6176c39b917191a2760fbb2127e5207b0bfb3dafd711593a6aed61d312807605913062aa1ce9c2f", + 'pal4rle.bmp': "c86c86280b75a252ccf484e4bba2df45d3747dc1e4879795e925613959a0c451e2fc4890532e8aef9911e38e45e7d6a8baf29d57e573d26c20923a5823700443", + 'pal4rlecut.bmp': "f38d485dbb8e67bdeaefba181f9a05556a986ed3f834edca723c088e813764bb2b42240d4fbb938a1775370b79b9ea2f14277ffe9c7247c1e0e77766fec27189", + 'pal4rletrns.bmp': "b81e7fed38854d201a3199ce50ca05e92ca287c860797142857ac20b4a2f28952b058e21687c0fae60712f5784cd2c950ce70148ba1316efe31d4f3fc4006817", + 'pal8-0.bmp': "f39a4f1827c52bb620d975f8c72f5e95f90ac6c65ae0a6776ff1ad95808c090de17cbd182188a85157396fd9649ea4b5d84bb7c9175ab49ce2845da214c16bff", + 'pal8.bmp': "be27e55a866cbb655fdd917435cd6a5b62c20ae0d6ef7c1533c5a01dd9a893f058cc4ba2d902ab9315380009808e06b7f180116c9b790587cf62aa770c7a4a07", + 'pal8badindex.bmp': "bd5fc036985ae705182915a560dee2e5dfb3bd8b50932337b9085e190259c66e6bae5fbc813a261d352a60dcb0755798bdc251d6c2a0b638a7e337ba58811811", + 'pal8gs.bmp': "228f944b3e45359f62a2839d4e7b94d7f3a1074ad9e25661fdb9e8fff4c15581c85a7bb0ac75c92b95c7537ececc9d80b835cfe55bc7560a513118224a9ed36f", + 'pal8nonsquare.bmp': "b8adc9b03880975b232849ea1e8f87705937929d743df3d35420902b32557065354ab71d0d8176646bf0ad72c583c884cfcd1511017260ffca8c41d5a358a3eb", + 'pal8offs.bmp': "c92f1e1835d753fd8484be5198b2b8a2660d5e54117f6c4fc6d2ebc8d1def72a8d09cd820b1b8dcee15740b47151d62b8b7aca0b843e696252e28226b51361cf", + 'pal8os2-hs.bmp': "477c04048787eb412f192e7fe47ae96f14d7995391e78b10cc4c365f8c762f60c54cad7ef9d1705a78bd490a578fb346ee0a383c3a3fdf790558a12589eb04eb", + 'pal8os2-sz.bmp': "fd0eeb733be9b39f492d0f67dd28fc67207149e41691c206d4de4c693b5dea9458b88699a781383e7050a3b343259659aae64fec0616c98f3f8555cbf5c9e46c", + 'pal8os2.bmp': "cdab3ed7bc9f38d89117332a21418b3c916a99a8d8fb6b7ce456d54288c96152af12c0380293b04e96594a7867b83be5c99913d224c9750c7d38295924e0735a", + 'pal8os2sp.bmp': "f6e595a6db992ab7d1f79442d31f39f648061e7de13e51b07933283df065ce405c0208e6101ac916e4eb0613e412116f008510021a2d17543aa7f0a32349c96f", + 'pal8os2v2-16.bmp': "f52877d434218aa6b772a7aa0aaba4c2ae6ce35ecfa6876943bb350fdf9554f1f763a8d5bb054362fb8f9848eb71ce14a371f4a76da4b9475cdcee4f286109a4", + 'pal8os2v2-40sz.bmp': "9481691ada527df1f529316d44b5857c6a840c5dafa7e9795c9cb92dac02c6cc35739d3f6ce33d4ab6ff6bcd6b949741e89dc8c42cf52ad4546ff58cd3b5b66a", + 'pal8os2v2-sz.bmp': "99cd2836f90591cd27b0c8696ecff1e7a1debcef284bbe5d21e68759270c1bfe1f32ee8f576c49f3e64d8f4e4d9096574f3c8c79bfdae0545689da18364de3e7", + 'pal8os2v2.bmp': "7859b265956c7d369db7a0a357ce09bcda74e98954de88f454cae5e7cb021222146687a7770ce0cc2c58f1439c7c21c45c0c27464944e73913e1c88afc836c8a", + 'pal8oversizepal.bmp': "e778864e0669a33fce27c0ccd5b6460b572a5db01975e8d56acec8a9447e1c58d6051ad3516cfa96a39f4eb7f2576154188ea62ec187bcf4ae323883499383c0", + 'pal8rle.bmp': "88942a1cd2e36d1e0f0e2748a888034057919c7ec0f8d9b2664deb1daf1a6e45ed3e722dff5d810f413d6fc182e700a16d6563dd25f67dc6d135d751cd736dea", + 'pal8rlecut.bmp': "cda9fa274cde590aeaca81516e0465684cfae84e934eb983301801e978e6e2e9c590d22af992d9912e51bb9c2761945276bdbe0b6c47f3a021514414e1f3f455", + 'pal8rletrns.bmp': "0b2d5618dc9c81caa72c070070a4245dd9cd3de5d344b76ce9c15d0eeb72e2675efc264201f8709dfcffd234df09e76d6f328f16f2ad873ba846f870cadfa486", + 'pal8topdown.bmp': "d470a2b7556fa88eac820427cb900f59a121732cdb4a7f3530ed457798139c946a884a34ab79d822feb84c2ca6f4d9a65f6e792994eafc3a189948b9e4543546", + 'pal8v4.bmp': "0382610e32c49d5091a096cb48a54ebbf44d9ba1def96e2f30826fd3ddf249f5aed70ca5b74c484b6cdc3924f4d4bfed2f5194ad0bcf1d99bfaa3a619e299d86", + 'pal8v5.bmp': "50fadaa93aac2a377b565c4dc852fd4602538863b913cb43155f5ad7cf79928127ca28b33e5a3b0230076ea4a6e339e3bf57f019333f42c4e9f003a8f2376325", + 'pal8w124.bmp': "e54a901b9badda655cad828d226b381831aea7e36aec8729147e9e95a9f2b21a9d74d93756e908e812902a01197f1379fe7e35498dbafed02e27c853a24097b7", + 'pal8w125.bmp': "d7a04d45ef5b3830da071ca598f1e2a413c46834968b2db7518985cf8d8c7380842145899e133e71355b6b7d040ee9e97adec1e928ce4739282e0533058467c0", + 'pal8w126.bmp': "4b93845a98797679423c669c541a248b4cdfee80736f01cec29d8b40584bf55a27835c80656a2bf5c7ad3ed211c1f7d3c7d5831a6726904b39f10043a76b658d", + 'reallybig.bmp': "babbf0335bac63fd2e95a89210c61ae6bbaaeeab5f07974034e76b4dc2a5c755f77501e3d056479357445aac442e2807d7170ec44067bab8fd35742f0e7b8440", + 'rgb16-231.bmp': "611a87cb5d29f16ef71971714a3b0e3863a6df51fff16ce4d4df8ee028442f9ce03669fb5d7a6a838a12a75d8a887b56b5a2e44a3ad62f4ef3fc2e238c33f6a1", + 'rgb16-3103.bmp': "7fdff66f4d94341da522b4e40586b3b8c327be9778e461bca1600e938bfbaa872b484192b35cd84d9430ca20aa922ec0301567a74fb777c808400819db90b09d", + 'rgb16-565.bmp': "777883f64b9ae80d77bf16c6d062082b7a4702f8260c183680afee6ec26e48681bcca75f0f81c470be1ac8fcb55620b3af5ce31d9e114b582dfd82300a3d6654", + 'rgb16-565pal.bmp': "57e9dcf159415b3574a1b343a484391b0859ab2f480e22157f2a84bc188fde141a48826f960c6f30b1d1f17ef6503ec3afc883a2f25ff09dd50c437244f9ae7f", + 'rgb16-880.bmp': "8d61183623002da4f7a0a66b42aa58a120e3a91578bb0c4a5e2c5ba7d08b875d43a22f2b5b3a449d3caf4cc303cb05111dd1d5169953f288493b7ea3c2423d24", + 'rgb16.bmp': "1c0fe56661d4998edd76efedda520a441171d42ae4dad95b350e3b61deda984c3a3255392481fe1903e5e751357da3f35164935e323377f015774280036ba39e", + 'rgb16bfdef.bmp': "ed55d086e27ba472076df418be0046b740944958afeb84d05aa2bbe578dec27ced122ffefb6d549e1d07e05eb608979b3ac9b1bd809f8237cf0984ffdaa24716", + 'rgb16faketrns.bmp': "9cd4a8e05fe125649e360715851ef912e78a56d30e0ea1b1cfb6eaafd386437d45de9c1e1a845dd8d63ff5a414832355b8ae0e2a96d72a42a7205e8a2742d37c", + 'rgb24.bmp': "4f0ce2978bbfea948798b2fdcc4bdbe8983a6c94d1b7326f39daa6059368e08ebf239260984b64eeb0948f7c8089a523e74b7fa6b0437f9205d8af8891340389", + 'rgb24largepal.bmp': "b377aee1594c5d9fc806a70bc62ee83cf8d1852b4a2b18fd3e9409a31aa3b5a4cf5e3b4af2cbdebcef2b5861b7985a248239684a72072437c50151adc524e9df", + 'rgb24pal.bmp': "f40bb6e01f6ecb3d55aa992bf1d1e2988ea5eb11e3e58a0c59a4fea2448de26f231f45e9f378b7ee1bdd529ec57a1de38ea536e397f5e1ac6998921e066ab427", + 'rgb24png.bmp': "c60890bbd79c12472205665959eb6e2dd2103671571f80117b9e963f897cffca103181374a4797f53c7768af01a705e830a0de4dd8fab7241d24c17bee4a4dbe", + 'rgb24rle24.bmp': "ea0ff3f512dd04176d14b43dfbee73ac7f1913aa1b77587e187e271781c7dacec880cec73850c4127ea9f8dd885f069e281f159bb5232e93cbb2d1ee9cb50438", + 'rgb32-111110.bmp': "732884e300d4edbcf31556a038947beefc0c5e749131a66d2d7aa1d4ec8c8eba07833133038a03bbe4c4fa61a805a5df1f797b5853339ee6a8140478f5f70a76", + 'rgb32-7187.bmp': "4c55aab2e4ecf63dc30b04e5685c5d9fba7354ca0e1327d7c4b15d6da10ac66ca1cea6f0303f9c5f046da3bcd2566275384e0e7bb14fcc5196ec39ca90fac194", + 'rgb32-xbgr.bmp': "1e9f240eaec6ac2833f8c719f1fb53cc7551809936620e871ccacfab26402e1afc6503b9f707e4ec25f15529e3ce6433c7f999d5714af31dfb856eb67e772f64", + 'rgb32.bmp': "32033dbf9462e5321b1182ba739624ed535aa4d33b775ffeeaf09d2d4cb663e4c3505e8c05489d940f754dde4b50a2e0b0688b21d06755e717e6e511b0947525", + 'rgb32bf.bmp': "7243c215827a9b4a1d7d52d67fb04ffb43b0b176518fbdab43d413e2a0c18883b106797f1acd85ba68d494ec939b0caab8789564670d058caf0e1175ce7983fb", + 'rgb32bfdef.bmp': "a81433babb67ce714285346a77bfccd19cf6203ac1d8245288855aff20cf38146a783f4a7eac221db63d1ee31345da1329e945b432f0e7bcf279ea88ff5bb302", + 'rgb32fakealpha.bmp': "abecaf1b5bfad322de7aec897efe7aa6525f2a77a0af86cc0a0a366ed1650da703cf4b7b117a7ba34f21d03a8a0045e5821248cdefa00b0c78e01d434b55e746", + 'rgb32h52.bmp': "707d734393c83384bc75720330075ec9ffefc69167343259ebf95f9393948364a40f33712619f962e7056483b73334584570962c16da212cd5291f764b3f2cd1", + 'rgba16-1924.bmp': "3e41a5d8d951bac580c780370ca21e0783de8154f4081106bc58d1185bb2815fc5b7f08f2a1c75cd205fc52c888e9d07c91856651603a2d756c9cfc392585598", + 'rgba16-4444.bmp': "a6662186b23bd434a7e019d2a71cd95f53a47b64a1afea4c27ae1120685d041a9ff98800a43a9d8f332682670585bdb2fa77ff77b6def65139fe725323f91561", + 'rgba16-5551.bmp': "a7d9f8ae7f8349cd6df651ab9d814411939fa2a235506ddfdd0df5a8f8abcf75552c32481ea035ff29e683bdcd34da68eb23730857e0716b79af51d69a60757b", + 'rgba32-1.bmp': "3958d18d2a7f32ada69cb11e0b4397821225a5c40acc7b6d36ff28ee4565e150cc508971278a2ddf8948aaff86f66ec6a0c24513db44962d81b79c4239b3e612", + 'rgba32-1010102.bmp': "59a28db5563caf954d31b20a1d1cc59366fcfd258b7ba2949f7281978460a3d94bedcc314c089243dd7463bb18d36a9473355158a7d903912cb25b98eab6b068", + 'rgba32-2.bmp': "9b7e5965ff9888f011540936ab6b3022edf9f6c5d7e541d6882cb81820cf1d68326d65695a6f0d01999ac10a496a504440906aa45e413da593405563c54c1a05", + 'rgba32-61754.bmp': "784ae0a32b19fa925e0c86dbff3bd38d80904d0fa7dc3b03e9d4f707d42b1604c1f54229e901ccc249cab8c2976d58b1e16980157d9bf3dbc4e035e2b2fd1779", + 'rgba32-81284.bmp': "fcfca645017c0d15d44b08598a90d238d063763fd06db665d9a8e36ef5099ce0bf4d440e615c6d6b1bf99f38230d4848318bfa1e6d9bfdd6dfd521cc633ba110", + 'rgba32abf.bmp': "2883d676966d298d235196f102e044e52ef18f3cb5bb0dd84738c679f0a1901181483ca2df1cccf6e4b3b4e98be39e81de69c9a58f0d70bc3ebb0fcea80daa0c", + 'rgba32h56.bmp': "507d0caf29ccb011c83c0c069c21105ea1d58e06b92204f9c612f26102123a7680eae53fef023c701952d903e11b61f8aa07618c381ea08f6808c523f5a84546", + 'rgba64.bmp': "d01f14f649c1c33e3809508cc6f089dd2ab0a538baf833a91042f2e54eca3f8e409908e15fa8763b059d7fa022cf5c074d9f5720eed5293a4c922e131c2eae68", + 'rletopdown.bmp': "37500893aad0b40656aa80fd5c7c5f9b35d033018b8070d8b1d7baeb34c90f90462288b13295204b90aa3e5c9be797d22a328e3714ab259334e879a09a3de175", + 'shortfile.bmp': "be3ffade7999304f00f9b7d152b5b27811ad1166d0fd43004392467a28f44b6a4ec02a23c0296bacd4f02f8041cd824b9ca6c9fc31fed27e36e572113bb47d73", - 'unicode.xml': "e0cdc94f07fdbb15eea811ed2ae6dcf494a83d197dafe6580c740270feb0d8f5f7146d4a7d4c2d2ea25f8bd9678bc986123484b39399819a6b7262687959d1ae", + 'emblem-1024.jpg': "d7b7e3ffaa5cda04c667e3742752091d78e02aa2d3c7a63406af679ce810a0a86666b10fcab12cc7ead2fadf2f6c2e1237bc94f892a62a4c218e18a20f96dbe4", + 'emblem-1024-progressive.jpg': "7a6f4b112bd7189320c58dcddb9129968bcf268798c1e0c4f2243c10b3e3d9a6962c9f142d9fd65f8fb31e9a1e899008cae22b3ffde713250d315499b412e160", + 'emblem-1024-gray.jpg': "4c25aaab92451e0452cdb165833b2b5a51978c2571de9d053950944667847666ba198d3001291615acda098ebe45b7d2d53c210c492f077b04a6bfe386f8a5fd", + + 'unicode.xml': "e0cdc94f07fdbb15eea811ed2ae6dcf494a83d197dafe6580c740270feb0d8f5f7146d4a7d4c2d2ea25f8bd9678bc986123484b39399819a6b7262687959d1ae", } def try_download_file(url, out_file): diff --git a/tests/core/encoding/cbor/test_core_cbor.odin b/tests/core/encoding/cbor/test_core_cbor.odin index ee853ebac..7bea69d2e 100644 --- a/tests/core/encoding/cbor/test_core_cbor.odin +++ b/tests/core/encoding/cbor/test_core_cbor.odin @@ -43,6 +43,8 @@ Foo :: struct { biggest: big.Int, smallest: big.Int, ignore_this: ^Foo `cbor:"-"`, + mat: matrix[4, 4]f32, + vec: #simd [4]f64, } FooBar :: enum { @@ -95,6 +97,8 @@ test_marshalling :: proc(t: ^testing.T) { onetwenty = i128(12345), small_onetwenty = -i128(max(u64)), ignore_this = &Foo{}, + mat = 1, + vec = 2, } big.atoi(&f.biggest, "1234567891011121314151617181920") @@ -120,11 +124,35 @@ test_marshalling :: proc(t: ^testing.T) { defer delete(diagnosis) testing.expect_value(t, diagnosis, `{ "no": null, + "mat": [ + 1.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 1.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 1.0000, + 0.0000, + 0.0000, + 0.0000, + 0.0000, + 1.0000 + ], "neg": -69, "nos": undefined, "now": 1(1701117968), "pos": 1212, "str": "Hellope", + "vec": [ + 2.0000, + 2.0000, + 2.0000, + 2.0000 + ], "yes": true, "comp": [ 32.0000, diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index c0e4329bd..409a8c9c0 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -114,7 +114,7 @@ xml_test_entities :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x05373317, + crc32 = 0x48f41216, }) } @@ -128,7 +128,7 @@ xml_test_entities_unbox :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x350ca83e, + crc32 = 0xd0567818, }) } @@ -142,7 +142,7 @@ xml_test_entities_unbox_decode :: proc(t: ^testing.T) { }, expected_doctype = "html", }, - crc32 = 0x7f58db7d, + crc32 = 0x68d2571e, }) } @@ -191,7 +191,7 @@ xml_test_unicode :: proc(t: ^testing.T) { } @(private) -run_test :: proc(t: ^testing.T, test: TEST) { +run_test :: proc(t: ^testing.T, test: TEST, loc := #caller_location) { path := strings.concatenate({TEST_SUITE_PATH, test.filename}) defer delete(path) @@ -205,10 +205,10 @@ run_test :: proc(t: ^testing.T, test: TEST) { crc32 := hash.crc32(tree_bytes) failed := err != test.err - testing.expectf(t, err == test.err, "%v: Expected return value %v, got %v", test.filename, test.err, err) + testing.expectf(t, err == test.err, "%v: Expected return value %v, got %v", test.filename, test.err, err, loc=loc) failed |= crc32 != test.crc32 - testing.expectf(t, crc32 == test.crc32, "%v: Expected CRC 0x%08x, got 0x%08x, with options %v", test.filename, test.crc32, crc32, test.options) + testing.expectf(t, crc32 == test.crc32, "%v: Expected CRC 0x%08x, got 0x%08x, with options %v", test.filename, test.crc32, crc32, test.options, loc=loc) if failed { // Don't fully print big trees. diff --git a/tests/core/flags/test_core_flags.odin b/tests/core/flags/test_core_flags.odin index 8fcd6a8a7..0cfcf8e75 100644 --- a/tests/core/flags/test_core_flags.odin +++ b/tests/core/flags/test_core_flags.odin @@ -17,7 +17,7 @@ Custom_Data :: struct { } @(init) -init_custom_type_setter :: proc() { +init_custom_type_setter :: proc "contextless" () { // NOTE: This is done here so it can be out of the flow of the // multi-threaded test runner, to prevent any data races that could be // reported by using `-sanitize:thread`. @@ -454,44 +454,44 @@ test_arrays :: proc(t: ^testing.T) { @(test) test_varargs :: proc(t: ^testing.T) { S :: struct { - varg: [dynamic]string, + overflow: [dynamic]string, } s: S args := [?]string { "abc", "foo", "bar" } result := flags.parse(&s, args[:]) - defer delete(s.varg) + defer delete(s.overflow) testing.expect_value(t, result, nil) - testing.expect_value(t, len(s.varg), 3) + testing.expect_value(t, len(s.overflow), 3) - if len(s.varg) < 3 { + if len(s.overflow) < 3 { return } - testing.expect_value(t, s.varg[0], "abc") - testing.expect_value(t, s.varg[1], "foo") - testing.expect_value(t, s.varg[2], "bar") + testing.expect_value(t, s.overflow[0], "abc") + testing.expect_value(t, s.overflow[1], "foo") + testing.expect_value(t, s.overflow[2], "bar") } @(test) test_mixed_varargs :: proc(t: ^testing.T) { S :: struct { input: string `args:"pos=0"`, - varg: [dynamic]string, + overflow: [dynamic]string, } s: S args := [?]string { "abc", "foo", "bar" } result := flags.parse(&s, args[:]) - defer delete(s.varg) + defer delete(s.overflow) testing.expect_value(t, result, nil) - testing.expect_value(t, len(s.varg), 2) + testing.expect_value(t, len(s.overflow), 2) - if len(s.varg) < 2 { + if len(s.overflow) < 2 { return } testing.expect_value(t, s.input, "abc") - testing.expect_value(t, s.varg[0], "foo") - testing.expect_value(t, s.varg[1], "bar") + testing.expect_value(t, s.overflow[0], "foo") + testing.expect_value(t, s.overflow[1], "bar") } @(test) @@ -718,23 +718,23 @@ test_tags_required_limit_max :: proc(t: ^testing.T) { test_tags_pos_out_of_order :: proc(t: ^testing.T) { S :: struct { a: int `args:"pos=2"`, - varg: [dynamic]int, + overflow: [dynamic]int, } s: S args := [?]string { "1", "2", "3", "4" } result := flags.parse(&s, args[:]) - defer delete(s.varg) + defer delete(s.overflow) testing.expect_value(t, result, nil) - testing.expect_value(t, len(s.varg), 3) + testing.expect_value(t, len(s.overflow), 3) - if len(s.varg) < 3 { + if len(s.overflow) < 3 { return } testing.expect_value(t, s.a, 3) - testing.expect_value(t, s.varg[0], 1) - testing.expect_value(t, s.varg[1], 2) - testing.expect_value(t, s.varg[2], 4) + testing.expect_value(t, s.overflow[0], 1) + testing.expect_value(t, s.overflow[1], 2) + testing.expect_value(t, s.overflow[2], 4) } @(test) @@ -899,7 +899,7 @@ test_pos_nonoverlap :: proc(t: ^testing.T) { @(test) test_pos_many_args :: proc(t: ^testing.T) { S :: struct { - varg: [dynamic]int, + overflow: [dynamic]int, a: int `args:"pos=0,required"`, b: int `args:"pos=64,required"`, c: int `args:"pos=66,required"`, @@ -908,7 +908,7 @@ test_pos_many_args :: proc(t: ^testing.T) { s: S args: [dynamic]string - defer delete(s.varg) + defer delete(s.overflow) for i in 0 ..< 130 { append(&args, fmt.aprintf("%i", 1 + i)) } defer { @@ -922,14 +922,14 @@ test_pos_many_args :: proc(t: ^testing.T) { testing.expect_value(t, result, nil) testing.expect_value(t, s.a, 1) - for i in 1 ..< 63 { testing.expect_value(t, s.varg[i], 2 + i) } + for i in 1 ..< 63 { testing.expect_value(t, s.overflow[i], 2 + i) } testing.expect_value(t, s.b, 65) - testing.expect_value(t, s.varg[63], 66) + testing.expect_value(t, s.overflow[63], 66) testing.expect_value(t, s.c, 67) - testing.expect_value(t, s.varg[64], 68) - testing.expect_value(t, s.varg[65], 69) - testing.expect_value(t, s.varg[66], 70) - for i in 67 ..< 126 { testing.expect_value(t, s.varg[i], 4 + i) } + testing.expect_value(t, s.overflow[64], 68) + testing.expect_value(t, s.overflow[65], 69) + testing.expect_value(t, s.overflow[66], 70) + for i in 67 ..< 126 { testing.expect_value(t, s.overflow[i], 4 + i) } testing.expect_value(t, s.d, 130) } @@ -966,9 +966,9 @@ test_unix :: proc(t: ^testing.T) { } @(test) -test_unix_variadic :: proc(t: ^testing.T) { +test_unix_manifold :: proc(t: ^testing.T) { S :: struct { - a: [dynamic]int `args:"variadic"`, + a: [dynamic]int `args:"manifold"`, } s: S @@ -989,9 +989,9 @@ test_unix_variadic :: proc(t: ^testing.T) { } @(test) -test_unix_variadic_limited :: proc(t: ^testing.T) { +test_unix_manifold_limited :: proc(t: ^testing.T) { S :: struct { - a: [dynamic]int `args:"variadic=2"`, + a: [dynamic]int `args:"manifold=2"`, b: int, } s: S @@ -1012,6 +1012,110 @@ test_unix_variadic_limited :: proc(t: ^testing.T) { testing.expect_value(t, s.b, 3) } +@(test) +test_unix_two_manifold_limited :: proc(t: ^testing.T) { + S :: struct { + a: [dynamic]int `args:"manifold=2"`, + b: [dynamic]int `args:"manifold=2"`, + c: int, + } + s: S + + args := [?]string { "-a", "11", "101", "-b", "3", "7", "-c", "9" } + + result := flags.parse(&s, args[:], .Unix) + defer { + delete(s.a) + delete(s.b) + } + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.a), 2) + testing.expect_value(t, len(s.b), 2) + + if len(s.a) < 2 || len(s.b) < 2 { + return + } + + testing.expect_value(t, s.a[0], 11) + testing.expect_value(t, s.a[1], 101) + testing.expect_value(t, s.b[0], 3) + testing.expect_value(t, s.b[1], 7) + testing.expect_value(t, s.c, 9) +} + +@(test) +test_unix_two_manifold_string :: proc(t: ^testing.T) { + // The expected behavior of a manifold flag is to consume all arguments as + // fitting for the element type. + S :: struct { + a: [dynamic]string `args:"manifold"`, + b: [dynamic]string `args:"manifold"`, + c: int, + } + s: S + + args := [?]string { "-a", "11", "101", "-b", "3", "7", "-c", "9" } + + result := flags.parse(&s, args[:], .Unix) + defer { + delete(s.a) + delete(s.b) + } + + testing.expect_value(t, result, nil) + testing.expect_value(t, len(s.a), 7) + testing.expect_value(t, len(s.b), 0) + + if len(s.a) != 7 { + return + } + + testing.expect_value(t, s.a[0], "11") + testing.expect_value(t, s.a[1], "101") + testing.expect_value(t, s.a[2], "-b") + testing.expect_value(t, s.a[3], "3") + testing.expect_value(t, s.a[4], "7") + testing.expect_value(t, s.a[5], "-c") + testing.expect_value(t, s.a[6], "9") +} + +@(test) +test_unix_two_manifold_int :: proc(t: ^testing.T) { + // If a manifold flag encounters an argument that it cannot convert to the + // element type, then this is an error. + S :: struct { + a: [dynamic]int `args:"manifold"`, + b: [dynamic]int `args:"manifold"`, + c: int, + } + s: S + + args := [?]string { "-a", "11", "101", "-b", "3", "7", "-c", "9" } + + result := flags.parse(&s, args[:], .Unix) + defer { + delete(s.a) + delete(s.b) + } + + err, ok := result.(flags.Parse_Error) + testing.expectf(t, ok, "unexpected result: %v", result) + if ok { + testing.expect_value(t, err.reason, flags.Parse_Error_Reason.Bad_Value) + } + + // It is expected that arguments which pass will still be available. + testing.expect_value(t, len(s.a), 2) + testing.expect_value(t, len(s.b), 0) + + if len(s.a) != 2 { + return + } + + testing.expect_value(t, s.a[0], 11) + testing.expect_value(t, s.a[1], 101) +} + @(test) test_unix_positional :: proc(t: ^testing.T) { S :: struct { @@ -1029,10 +1133,10 @@ test_unix_positional :: proc(t: ^testing.T) { } @(test) -test_unix_positional_with_variadic :: proc(t: ^testing.T) { +test_unix_positional_with_manifold :: proc(t: ^testing.T) { S :: struct { - varg: [dynamic]int, - v: [dynamic]int `args:"variadic"`, + overflow: [dynamic]int, + v: [dynamic]int `args:"manifold"`, } s: S @@ -1040,18 +1144,18 @@ test_unix_positional_with_variadic :: proc(t: ^testing.T) { result := flags.parse(&s, args[:], .Unix) defer { - delete(s.varg) + delete(s.overflow) delete(s.v) } testing.expect_value(t, result, nil) - testing.expect_value(t, len(s.varg), 1) + testing.expect_value(t, len(s.overflow), 1) testing.expect_value(t, len(s.v), 2) } @(test) -test_unix_double_dash_variadic :: proc(t: ^testing.T) { +test_unix_double_dash_varargs :: proc(t: ^testing.T) { S :: struct { - varg: [dynamic]string, + overflow: [dynamic]string, i: int, } s: S @@ -1060,19 +1164,19 @@ test_unix_double_dash_variadic :: proc(t: ^testing.T) { result := flags.parse(&s, args[:], .Unix) defer { - delete(s.varg) + delete(s.overflow) } testing.expect_value(t, result, nil) - testing.expect_value(t, len(s.varg), 3) + testing.expect_value(t, len(s.overflow), 3) testing.expect_value(t, s.i, 3) - if len(s.varg) != 3 { + if len(s.overflow) != 3 { return } - testing.expect_value(t, s.varg[0], "hellope") - testing.expect_value(t, s.varg[1], "-i") - testing.expect_value(t, s.varg[2], "5") + testing.expect_value(t, s.overflow[0], "hellope") + testing.expect_value(t, s.overflow[1], "-i") + testing.expect_value(t, s.overflow[2], "5") } @(test) @@ -1096,17 +1200,17 @@ test_unix_no_value :: proc(t: ^testing.T) { @(test) test_if_dynamic_cstrings_get_freed :: proc(t: ^testing.T) { S :: struct { - varg: [dynamic]cstring, + overflow: [dynamic]cstring, } s: S args := [?]string { "Hellope", "world!" } result := flags.parse(&s, args[:]) defer { - for v in s.varg { + for v in s.overflow { delete(v) } - delete(s.varg) + delete(s.overflow) } testing.expect_value(t, result, nil) } @@ -1324,7 +1428,7 @@ very nicely. debug: bool `args:"hidden" usage:"print debug info"`, verbose: bool, - varg: [dynamic]string, + overflow: [dynamic]string, } builder := strings.builder_make() @@ -1337,7 +1441,7 @@ very nicely. @(test) test_usage_write_unix :: proc(t: ^testing.T) { Expected_Output :: `Usage: - varg required-number [number] [name] --bars --bots --foos --gadgets --variadic-flag --widgets [--array] [--count] [--greek] [--verbose] ... + overflow required-number [number] [name] --bars --bots --foos --gadgets --manifold-flag --widgets [--array] [--count] [--greek] [--verbose] ... Flags: --required-number , required | some number --number | some other number @@ -1349,7 +1453,7 @@ Flags: --bots , at least 1 | --foos , between 2 and 3 | --gadgets , at least 1 | - --variadic-flag , at least 2 | + --manifold-flag , at least 2 | --widgets , at most 2 | | --array , multiple | @@ -1378,7 +1482,7 @@ very nicely. greek: Custom_Enum, array: [dynamic]rune, - variadic_flag: [dynamic]int `args:"variadic,required=2"`, + manifold_flag: [dynamic]int `args:"manifold,required=2"`, gadgets: [dynamic]string `args:"required=1"`, widgets: [dynamic]string `args:"required=<3"`, @@ -1389,12 +1493,12 @@ very nicely. debug: bool `args:"hidden" usage:"print debug info"`, verbose: bool, - varg: [dynamic]string, + overflow: [dynamic]string, } builder := strings.builder_make() defer strings.builder_destroy(&builder) writer := strings.to_stream(&builder) - flags.write_usage(writer, S, "varg", .Unix) + flags.write_usage(writer, S, "overflow", .Unix) testing.expect_value(t, strings.to_string(builder), Expected_Output) } diff --git a/tests/core/hash/test_core_hash.odin b/tests/core/hash/test_core_hash.odin index adb55d2d8..8a951b186 100644 --- a/tests/core/hash/test_core_hash.odin +++ b/tests/core/hash/test_core_hash.odin @@ -1,140 +1,186 @@ #+feature dynamic-literals package test_core_hash -import "core:hash/xxhash" import "core:hash" import "core:testing" -import "core:math/rand" import "base:intrinsics" +/* + Built-in `#hash`es: + #hash("murmur32"), + #hash("murmur64"), + }; +*/ + +V32 :: struct{s: string, h: u32} +V64 :: struct{s: string, h: u64} + @test -test_xxhash_zero_fixed :: proc(t: ^testing.T) { - many_zeroes := make([]u8, 16 * 1024 * 1024) - defer delete(many_zeroes) - - // All at once. - for i, v in ZERO_VECTORS { - b := many_zeroes[:i] - - xxh32 := xxhash.XXH32(b) - xxh64 := xxhash.XXH64(b) - xxh3_64 := xxhash.XXH3_64(b) - xxh3_128 := xxhash.XXH3_128(b) - - testing.expectf(t, xxh32 == v.xxh_32, "[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) - testing.expectf(t, xxh64 == v.xxh_64, "[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) - testing.expectf(t, xxh3_64 == v.xxh3_64, "[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) - testing.expectf(t, xxh3_128 == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) +test_adler32_vectors :: proc(t: ^testing.T) { + vectors :: []V32{ + {"" , 0x00000001}, + {"a" , 0x00620062}, + {"abc" , 0x024d0127}, + {"Hello" , 0x058c01f5}, + {"world" , 0x06a60229}, + {"Hello, world!", 0x205e048a}, } + + for vector in vectors { + b := transmute([]u8)vector.s + adler := hash.adler32(b) + testing.expectf(t, adler == vector.h, "\n\t[ADLER-32(%v)] Expected: 0x%08x, got: 0x%08x", vector.s, vector.h, adler) + } + + testing.expect_value(t, #hash(vectors[0].s, "adler32"), int(vectors[0].h)) + testing.expect_value(t, #hash(vectors[1].s, "adler32"), int(vectors[1].h)) + testing.expect_value(t, #hash(vectors[2].s, "adler32"), int(vectors[2].h)) + testing.expect_value(t, #hash(vectors[3].s, "adler32"), int(vectors[3].h)) + testing.expect_value(t, #hash(vectors[4].s, "adler32"), int(vectors[4].h)) + testing.expect_value(t, #hash(vectors[5].s, "adler32"), int(vectors[5].h)) } -@(test) -test_xxhash_zero_streamed_random_updates :: proc(t: ^testing.T) { - many_zeroes := make([]u8, 16 * 1024 * 1024) - defer delete(many_zeroes) +@test +test_djb2_vectors :: proc(t: ^testing.T) { + vectors :: []V32{ + {"" , 5381}, // Initial seed + {"a" , 0x0002b606}, + {"abc" , 0x0b885c8b}, + {"Hello" , 0x0d4f2079}, + {"world" , 0x10a7356d}, + {"Hello, world!", 0xe18796ae}, + } - // Streamed - for i, v in ZERO_VECTORS { - b := many_zeroes[:i] - - xxh_32_state, xxh_32_err := xxhash.XXH32_create_state() - defer xxhash.XXH32_destroy_state(xxh_32_state) - testing.expect(t, xxh_32_err == nil, "Problem initializing XXH_32 state") - - xxh_64_state, xxh_64_err := xxhash.XXH64_create_state() - defer xxhash.XXH64_destroy_state(xxh_64_state) - testing.expect(t, xxh_64_err == nil, "Problem initializing XXH_64 state") - - xxh3_64_state, xxh3_64_err := xxhash.XXH3_create_state() - defer xxhash.XXH3_destroy_state(xxh3_64_state) - testing.expect(t, xxh3_64_err == nil, "Problem initializing XXH3_64 state") - - xxh3_128_state, xxh3_128_err := xxhash.XXH3_create_state() - defer xxhash.XXH3_destroy_state(xxh3_128_state) - testing.expect(t, xxh3_128_err == nil, "Problem initializing XXH3_128 state") - - // XXH3_128_update - rand.reset(t.seed) - for len(b) > 0 { - update_size := min(len(b), rand.int_max(8192)) - if update_size > 4096 { - update_size %= 73 - } - xxhash.XXH32_update (xxh_32_state, b[:update_size]) - xxhash.XXH64_update (xxh_64_state, b[:update_size]) - - xxhash.XXH3_64_update (xxh3_64_state, b[:update_size]) - xxhash.XXH3_128_update(xxh3_128_state, b[:update_size]) - - b = b[update_size:] - } - - // Now finalize - xxh32 := xxhash.XXH32_digest(xxh_32_state) - xxh64 := xxhash.XXH64_digest(xxh_64_state) - - xxh3_64 := xxhash.XXH3_64_digest(xxh3_64_state) - xxh3_128 := xxhash.XXH3_128_digest(xxh3_128_state) - - testing.expectf(t, xxh32 == v.xxh_32, "[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) - testing.expectf(t, xxh64 == v.xxh_64, "[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) - testing.expectf(t, xxh3_64 == v.xxh3_64, "[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) - testing.expectf(t, xxh3_128 == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) + for vector in vectors { + b := transmute([]u8)vector.s + djb2 := hash.djb2(b) + testing.expectf(t, djb2 == vector.h, "\n\t[DJB-2(%v)] Expected: 0x%08x, got: 0x%08x", vector.s, vector.h, djb2) } } @test -test_xxhash_seeded :: proc(t: ^testing.T) { - buf := make([]u8, 256) - defer delete(buf) - - for seed, table in XXHASH_TEST_VECTOR_SEEDED { - for v, i in table { - b := buf[:i] - - xxh32 := xxhash.XXH32(b, u32(seed)) - xxh64 := xxhash.XXH64(b, seed) - xxh3_64 := xxhash.XXH3_64(b, seed) - xxh3_128 := xxhash.XXH3_128(b, seed) - - testing.expectf(t, xxh32 == v.xxh_32, "[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) - testing.expectf(t, xxh64 == v.xxh_64, "[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) - testing.expectf(t, xxh3_64 == v.xxh3_64, "[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) - testing.expectf(t, xxh3_128 == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) - - if len(b) > xxhash.XXH3_MIDSIZE_MAX { - xxh3_state, _ := xxhash.XXH3_create_state() - xxhash.XXH3_64_reset_with_seed(xxh3_state, seed) - xxhash.XXH3_64_update(xxh3_state, b) - xxh3_64_streamed := xxhash.XXH3_64_digest(xxh3_state) - xxhash.XXH3_destroy_state(xxh3_state) - testing.expectf(t, xxh3_64_streamed == v.xxh3_64, "[XXH3_64s(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64_streamed) - - xxh3_state2, _ := xxhash.XXH3_create_state() - xxhash.XXH3_128_reset_with_seed(xxh3_state2, seed) - xxhash.XXH3_128_update(xxh3_state2, b) - xxh3_128_streamed := xxhash.XXH3_128_digest(xxh3_state2) - xxhash.XXH3_destroy_state(xxh3_state2) - testing.expectf(t, xxh3_128_streamed == v.xxh3_128, "[XXH3_128s(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128_streamed) - } - } +test_fnv32_vectors :: proc(t: ^testing.T) { + vectors :: []V32{ + {"" , 0x811c9dc5}, + {"a" , 0x050c5d7e}, + {"abc" , 0x439c2f4b}, + {"Hello" , 0x3726bd47}, + {"world" , 0x9b8e862f}, + {"Hello, world!", 0xe84ead66}, } + + for vector in vectors { + b := transmute([]u8)vector.s + fnv := hash.fnv32_no_a(b) + testing.expectf(t, fnv == vector.h, "\n\t[FNV-32(%v)] Expected: 0x%08x, got: 0x%08x", vector.s, vector.h, fnv) + } + + testing.expect_value(t, #hash(vectors[0].s, "fnv32"), int(vectors[0].h)) + testing.expect_value(t, #hash(vectors[1].s, "fnv32"), int(vectors[1].h)) + testing.expect_value(t, #hash(vectors[2].s, "fnv32"), int(vectors[2].h)) + testing.expect_value(t, #hash(vectors[3].s, "fnv32"), int(vectors[3].h)) + testing.expect_value(t, #hash(vectors[4].s, "fnv32"), int(vectors[4].h)) + testing.expect_value(t, #hash(vectors[5].s, "fnv32"), int(vectors[5].h)) } @test -test_xxhash_secret :: proc(t: ^testing.T) { - buf := make([]u8, 256) - defer delete(buf) - - for secret, table in XXHASH_TEST_VECTOR_SECRET { - secret_bytes := transmute([]u8)secret - for v, i in table { - b := buf[:i] - - xxh3_128 := xxhash.XXH3_128(b, secret_bytes) - testing.expectf(t, xxh3_128 == v.xxh3_128_secret, "[XXH3_128(%03d)] Expected: %32x, got: %32x", i, v.xxh3_128_secret, xxh3_128) - } +test_fnv64_vectors :: proc(t: ^testing.T) { + vectors :: []V64{ + {"" , 0xcbf29ce484222325}, + {"a" , 0xaf63bd4c8601b7be}, + {"abc" , 0xd8dcca186bafadcb}, + {"Hello" , 0xfa365282a44c0ba7}, + {"world" , 0x3ec0cf0cc4a6540f}, + {"Hello, world!", 0x6519bd6389aaa166}, } + + for vector in vectors { + b := transmute([]u8)vector.s + fnv := hash.fnv64_no_a(b) + testing.expectf(t, fnv == vector.h, "\n\t[FNV-64(%v)] Expected: 0x%16x, got: 0x%16x", vector.s, vector.h, fnv) + } + + testing.expect_value(t, i128(#hash(vectors[0].s, "fnv64")), i128(vectors[0].h)) + testing.expect_value(t, i128(#hash(vectors[1].s, "fnv64")), i128(vectors[1].h)) + testing.expect_value(t, i128(#hash(vectors[2].s, "fnv64")), i128(vectors[2].h)) + testing.expect_value(t, i128(#hash(vectors[3].s, "fnv64")), i128(vectors[3].h)) + testing.expect_value(t, i128(#hash(vectors[4].s, "fnv64")), i128(vectors[4].h)) + testing.expect_value(t, i128(#hash(vectors[5].s, "fnv64")), i128(vectors[5].h)) +} + +@test +test_fnv32a_vectors :: proc(t: ^testing.T) { + vectors :: []V32{ + {"" , 0x811c9dc5}, + {"a" , 0xe40c292c}, + {"abc" , 0x1a47e90b}, + {"Hello" , 0xf55c314b}, + {"world" , 0x37a3e893}, + {"Hello, world!", 0xed90f094}, + } + + for vector in vectors { + b := transmute([]u8)vector.s + fnv := hash.fnv32a(b) + testing.expectf(t, fnv == vector.h, "\n\t[FNV-32a(%v)] Expected: 0x%08x, got: 0x%08x", vector.s, vector.h, fnv) + } + + testing.expect_value(t, #hash(vectors[0].s, "fnv32a"), int(vectors[0].h)) + testing.expect_value(t, #hash(vectors[1].s, "fnv32a"), int(vectors[1].h)) + testing.expect_value(t, #hash(vectors[2].s, "fnv32a"), int(vectors[2].h)) + testing.expect_value(t, #hash(vectors[3].s, "fnv32a"), int(vectors[3].h)) + testing.expect_value(t, #hash(vectors[4].s, "fnv32a"), int(vectors[4].h)) + testing.expect_value(t, #hash(vectors[5].s, "fnv32a"), int(vectors[5].h)) +} + +@test +test_fnv64a_vectors :: proc(t: ^testing.T) { + vectors :: []V64{ + {"" , 0xcbf29ce484222325}, + {"a" , 0xaf63dc4c8601ec8c}, + {"abc" , 0xe71fa2190541574b}, + {"Hello" , 0x63f0bfacf2c00f6b}, + {"world" , 0x4f59ff5e730c8af3}, + {"Hello, world!", 0x38d1334144987bf4}, + } + + for vector in vectors { + b := transmute([]u8)vector.s + fnv := hash.fnv64a(b) + testing.expectf(t, fnv == vector.h, "\n\t[FNV-64a(%v)] Expected: 0x%16x, got: 0x%16x", vector.s, vector.h, fnv) + } + + testing.expect_value(t, i128(#hash(vectors[0].s, "fnv64a")), i128(vectors[0].h)) + testing.expect_value(t, i128(#hash(vectors[1].s, "fnv64a")), i128(vectors[1].h)) + testing.expect_value(t, i128(#hash(vectors[2].s, "fnv64a")), i128(vectors[2].h)) + testing.expect_value(t, i128(#hash(vectors[3].s, "fnv64a")), i128(vectors[3].h)) + testing.expect_value(t, i128(#hash(vectors[4].s, "fnv64a")), i128(vectors[4].h)) + testing.expect_value(t, i128(#hash(vectors[5].s, "fnv64a")), i128(vectors[5].h)) +} + +@test +test_crc32_vectors :: proc(t: ^testing.T) { + vectors :: []V32{ + {"" , 0x00000000}, + {"a" , 0xe8b7be43}, + {"abc" , 0x352441c2}, + {"Hello" , 0xf7d18982}, + {"world" , 0x3a771143}, + {"Hello, world!", 0xebe6c6e6}, + } + + for vector in vectors { + b := transmute([]u8)vector.s + crc := hash.crc32(b) + testing.expectf(t, crc == vector.h, "\n\t[CRC-32(%v)] Expected: 0x%08x, got: 0x%08x", vector.s, vector.h, crc) + } + + testing.expect_value(t, #hash(vectors[0].s, "crc32"), int(vectors[0].h)) + testing.expect_value(t, #hash(vectors[1].s, "crc32"), int(vectors[1].h)) + testing.expect_value(t, #hash(vectors[2].s, "crc32"), int(vectors[2].h)) + testing.expect_value(t, #hash(vectors[3].s, "crc32"), int(vectors[3].h)) + testing.expect_value(t, #hash(vectors[4].s, "crc32"), int(vectors[4].h)) + testing.expect_value(t, #hash(vectors[5].s, "crc32"), int(vectors[5].h)) } @test @@ -167,4 +213,54 @@ test_crc64_vectors :: proc(t: ^testing.T) { testing.expectf(t, iso == expected[2], "[ CRC-64 ISO 3306] Expected: %016x, got: %016x", expected[2], iso) testing.expectf(t, iso2 == expected[3], "[~CRC-64 ISO 3306] Expected: %016x, got: %016x", expected[3], iso2) } +} + +@test +test_murmur32_vectors :: proc(t: ^testing.T) { + vectors :: []V32{ + {"" , 0xebb6c228}, + {"a" , 0x7fa09ea6}, + {"abc" , 0xc84a62dd}, + {"Hello" , 0xec73fdbe}, + {"world" , 0xd7f8a5f2}, + {"Hello, world!", 0x24884cba}, + } + + for vector in vectors { + b := transmute([]u8)vector.s + murmur := hash.murmur32(b) + testing.expectf(t, murmur == vector.h, "\n\t[MURMUR-32(%v)] Expected: 0x%08x, got: 0x%08x", vector.s, vector.h, murmur) + } + + testing.expect_value(t, #hash(vectors[0].s, "murmur32"), int(vectors[0].h)) + testing.expect_value(t, #hash(vectors[1].s, "murmur32"), int(vectors[1].h)) + testing.expect_value(t, #hash(vectors[2].s, "murmur32"), int(vectors[2].h)) + testing.expect_value(t, #hash(vectors[3].s, "murmur32"), int(vectors[3].h)) + testing.expect_value(t, #hash(vectors[4].s, "murmur32"), int(vectors[4].h)) + testing.expect_value(t, #hash(vectors[5].s, "murmur32"), int(vectors[5].h)) +} + +@test +test_murmur64_vectors :: proc(t: ^testing.T) { + vectors :: []V64{ + {"" , 0x8397626cd6895052}, + {"a" , 0xe96b6245652273ae}, + {"abc" , 0xa9316c8740c81414}, + {"Hello" , 0x89cc3a85a7045a4f}, + {"world" , 0xf030e222b1f740f6}, + {"Hello, world!", 0x710583fa7f802a84}, + } + + for vector in vectors { + b := transmute([]u8)vector.s + murmur := hash.murmur64a(b) + testing.expectf(t, murmur == vector.h, "\n\t[MURMUR-64(%v)] Expected: 0x%16x, got: 0x%16x", vector.s, vector.h, murmur) + } + + testing.expect_value(t, i128(#hash(vectors[0].s, "murmur64")), i128(vectors[0].h)) + testing.expect_value(t, i128(#hash(vectors[1].s, "murmur64")), i128(vectors[1].h)) + testing.expect_value(t, i128(#hash(vectors[2].s, "murmur64")), i128(vectors[2].h)) + testing.expect_value(t, i128(#hash(vectors[3].s, "murmur64")), i128(vectors[3].h)) + testing.expect_value(t, i128(#hash(vectors[4].s, "murmur64")), i128(vectors[4].h)) + testing.expect_value(t, i128(#hash(vectors[5].s, "murmur64")), i128(vectors[5].h)) } \ No newline at end of file diff --git a/tests/core/hash/test_vectors_xxhash.odin b/tests/core/hash/test_core_xxhash.odin similarity index 98% rename from tests/core/hash/test_vectors_xxhash.odin rename to tests/core/hash/test_core_xxhash.odin index 04e2d4f1f..f544f6699 100644 --- a/tests/core/hash/test_vectors_xxhash.odin +++ b/tests/core/hash/test_core_xxhash.odin @@ -2,6 +2,140 @@ #+feature dynamic-literals package test_core_hash +import "core:hash/xxhash" +import "core:testing" +import "core:math/rand" + +@test +test_xxhash_zero_fixed :: proc(t: ^testing.T) { + many_zeroes := make([]u8, 16 * 1024 * 1024) + defer delete(many_zeroes) + + // All at once. + for i, v in ZERO_VECTORS { + b := many_zeroes[:i] + + xxh32 := xxhash.XXH32(b) + xxh64 := xxhash.XXH64(b) + xxh3_64 := xxhash.XXH3_64(b) + xxh3_128 := xxhash.XXH3_128(b) + + testing.expectf(t, xxh32 == v.xxh_32, "[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) + testing.expectf(t, xxh64 == v.xxh_64, "[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) + testing.expectf(t, xxh3_64 == v.xxh3_64, "[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) + testing.expectf(t, xxh3_128 == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) + } +} + +@(test) +test_xxhash_zero_streamed_random_updates :: proc(t: ^testing.T) { + many_zeroes := make([]u8, 16 * 1024 * 1024) + defer delete(many_zeroes) + + // Streamed + for i, v in ZERO_VECTORS { + b := many_zeroes[:i] + + xxh_32_state, xxh_32_err := xxhash.XXH32_create_state() + defer xxhash.XXH32_destroy_state(xxh_32_state) + testing.expect(t, xxh_32_err == nil, "Problem initializing XXH_32 state") + + xxh_64_state, xxh_64_err := xxhash.XXH64_create_state() + defer xxhash.XXH64_destroy_state(xxh_64_state) + testing.expect(t, xxh_64_err == nil, "Problem initializing XXH_64 state") + + xxh3_64_state, xxh3_64_err := xxhash.XXH3_create_state() + defer xxhash.XXH3_destroy_state(xxh3_64_state) + testing.expect(t, xxh3_64_err == nil, "Problem initializing XXH3_64 state") + + xxh3_128_state, xxh3_128_err := xxhash.XXH3_create_state() + defer xxhash.XXH3_destroy_state(xxh3_128_state) + testing.expect(t, xxh3_128_err == nil, "Problem initializing XXH3_128 state") + + // XXH3_128_update + rand.reset(t.seed) + for len(b) > 0 { + update_size := min(len(b), rand.int_max(8192)) + if update_size > 4096 { + update_size %= 73 + } + xxhash.XXH32_update (xxh_32_state, b[:update_size]) + xxhash.XXH64_update (xxh_64_state, b[:update_size]) + + xxhash.XXH3_64_update (xxh3_64_state, b[:update_size]) + xxhash.XXH3_128_update(xxh3_128_state, b[:update_size]) + + b = b[update_size:] + } + + // Now finalize + xxh32 := xxhash.XXH32_digest(xxh_32_state) + xxh64 := xxhash.XXH64_digest(xxh_64_state) + + xxh3_64 := xxhash.XXH3_64_digest(xxh3_64_state) + xxh3_128 := xxhash.XXH3_128_digest(xxh3_128_state) + + testing.expectf(t, xxh32 == v.xxh_32, "[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) + testing.expectf(t, xxh64 == v.xxh_64, "[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) + testing.expectf(t, xxh3_64 == v.xxh3_64, "[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) + testing.expectf(t, xxh3_128 == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) + } +} + +@test +test_xxhash_seeded :: proc(t: ^testing.T) { + buf := make([]u8, 256) + defer delete(buf) + + for seed, table in XXHASH_TEST_VECTOR_SEEDED { + for v, i in table { + b := buf[:i] + + xxh32 := xxhash.XXH32(b, u32(seed)) + xxh64 := xxhash.XXH64(b, seed) + xxh3_64 := xxhash.XXH3_64(b, seed) + xxh3_128 := xxhash.XXH3_128(b, seed) + + testing.expectf(t, xxh32 == v.xxh_32, "[ XXH32(%03d) ] Expected: %08x, got: %08x", i, v.xxh_32, xxh32) + testing.expectf(t, xxh64 == v.xxh_64, "[ XXH64(%03d) ] Expected: %16x, got: %16x", i, v.xxh_64, xxh64) + testing.expectf(t, xxh3_64 == v.xxh3_64, "[XXH3_64(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64) + testing.expectf(t, xxh3_128 == v.xxh3_128, "[XXH3_128(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128) + + if len(b) > xxhash.XXH3_MIDSIZE_MAX { + xxh3_state, _ := xxhash.XXH3_create_state() + xxhash.XXH3_64_reset_with_seed(xxh3_state, seed) + xxhash.XXH3_64_update(xxh3_state, b) + xxh3_64_streamed := xxhash.XXH3_64_digest(xxh3_state) + xxhash.XXH3_destroy_state(xxh3_state) + testing.expectf(t, xxh3_64_streamed == v.xxh3_64, "[XXH3_64s(%03d) ] Expected: %16x, got: %16x", i, v.xxh3_64, xxh3_64_streamed) + + xxh3_state2, _ := xxhash.XXH3_create_state() + xxhash.XXH3_128_reset_with_seed(xxh3_state2, seed) + xxhash.XXH3_128_update(xxh3_state2, b) + xxh3_128_streamed := xxhash.XXH3_128_digest(xxh3_state2) + xxhash.XXH3_destroy_state(xxh3_state2) + testing.expectf(t, xxh3_128_streamed == v.xxh3_128, "[XXH3_128s(%03d) ] Expected: %32x, got: %32x", i, v.xxh3_128, xxh3_128_streamed) + } + } + } +} + +@test +test_xxhash_secret :: proc(t: ^testing.T) { + buf := make([]u8, 256) + defer delete(buf) + + for secret, table in XXHASH_TEST_VECTOR_SECRET { + secret_bytes := transmute([]u8)secret + for v, i in table { + b := buf[:i] + + xxh3_128 := xxhash.XXH3_128(b, secret_bytes) + testing.expectf(t, xxh3_128 == v.xxh3_128_secret, "[XXH3_128(%03d)] Expected: %32x, got: %32x", i, v.xxh3_128_secret, xxh3_128) + } + } +} + XXHASH_Test_Vectors :: struct #packed { /* Old hashes diff --git a/tests/core/image/test_core_image.odin b/tests/core/image/test_core_image.odin index 8f6091481..3293b80fa 100644 --- a/tests/core/image/test_core_image.odin +++ b/tests/core/image/test_core_image.odin @@ -5,7 +5,7 @@ List of contributors: Jeroen van Rijn: Initial implementation. - A test suite for PNG, TGA, NetPBM, QOI and BMP. + A test suite for PNG, TGA, NetPBM, QOI, BMP, and JPEG. */ #+feature dynamic-literals package test_core_image @@ -19,6 +19,7 @@ import pbm "core:image/netpbm" import "core:image/png" import "core:image/qoi" import "core:image/tga" +import "core:image/jpeg" import "core:bytes" import "core:hash" @@ -28,6 +29,7 @@ import "core:time" TEST_SUITE_PATH_PNG :: ODIN_ROOT + "tests/core/assets/PNG" TEST_SUITE_PATH_BMP :: ODIN_ROOT + "tests/core/assets/BMP" +TEST_SUITE_PATH_JPG :: ODIN_ROOT + "tests/core/assets/JPG" I_Error :: image.Error @@ -49,6 +51,7 @@ Blend_BG_Keep :: image.Options{.blend_background, .alpha_add_if_missing} Return_Metadata :: image.Options{.return_metadata} No_Channel_Expansion :: image.Options{.do_not_expand_channels, .return_metadata} + Dims :: struct { width: int, height: int, @@ -2360,6 +2363,66 @@ run_bmp_suite :: proc(t: ^testing.T, suite: []Test) { return } +// JPG test image +Basic_JPG_Tests := []Test{ + { + "emblem-1024", { + {Default, nil, {1024, 1024, 3, 8}, 0x_46a29e0f}, + {Alpha_Add, nil, {1024, 1024, 4, 8}, 0x_cae2d532}, + }, + }, + { + "emblem-1024-progressive", { + {Default, .Unsupported_Frame_Type, {1024, 1024, 3, 8}, 0x_46a29e0f}, + }, + }, + { + "emblem-1024-gray", { + {Default, nil, {1024, 1024, 3, 8}, 0x_4115d669}, + {Alpha_Add, nil, {1024, 1024, 4, 8}, 0x_db496297}, + {No_Channel_Expansion, .Unsupported_Option, {1024, 1024, 1, 8}, 0}, + }, + }, +} + +@test +jpeg_test_basic :: proc(t: ^testing.T) { + run_jpg_suite(t, Basic_JPG_Tests) +} + +run_jpg_suite :: proc(t: ^testing.T, suite: []Test) { + for file in suite { + test_file := strings.concatenate({TEST_SUITE_PATH_JPG, "/", file.file, ".jpg"}, context.allocator) + defer delete(test_file) + + for test in file.tests { + img, err := jpeg.load(test_file, test.options) + defer jpeg.destroy(img) + + passed := (test.expected_error == nil && err == nil) || (test.expected_error == err) + testing.expectf(t, passed, "%q failed to load with error %v.", file.file, err) + + // No point in running the other tests if it didn't load. + (err == nil) or_continue + + pixels := bytes.buffer_to_bytes(&img.pixels) + dims := Dims{img.width, img.height, img.channels, img.depth} + testing.expectf(t, test.dims == dims, "%v has %v, expected: %v.", file.file, dims, test.dims) + + img_hash := hash.crc32(pixels) + testing.expectf(t, test.hash == img_hash, "%v test #1's hash is %08x, expected %08x with %v.", file.file, img_hash, test.hash, test.options) + + // Optionally save to QOI file to check file loaded properly during development + when false { + test_qoi := strings.concatenate({TEST_SUITE_PATH_JPG, "/", file.file, ".qoi"}, context.temp_allocator) + save_err := qoi.save(test_qoi, img) + testing.expectf(t, save_err == nil, "expected saving to QOI not to raise error, got %v", save_err) + } + } + } + return +} + @test will_it_blend :: proc(t: ^testing.T) { Pixel :: image.RGB_Pixel diff --git a/tests/core/math/big/build.bat b/tests/core/math/big/build.bat deleted file mode 100644 index ad199d775..000000000 --- a/tests/core/math/big/build.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off -rem math/big tests -set PATH_TO_ODIN==..\..\..\..\odin -set TEST_ARGS=-fast-tests -set TEST_ARGS=-no-random -set TEST_ARGS= -set OUT_NAME=math_big_test_library.dll -set COMMON=-build-mode:shared -show-timings -no-bounds-check -define:MATH_BIG_EXE=false -vet -strict-style -echo --- -echo Running core:math/big tests -echo --- - -%PATH_TO_ODIN% build . %COMMON% -o:speed -out:%OUT_NAME% -python3 test.py %TEST_ARGS% \ No newline at end of file diff --git a/tests/core/math/big/test.py b/tests/core/math/big/generate_tests.py similarity index 75% rename from tests/core/math/big/test.py rename to tests/core/math/big/generate_tests.py index c0e695848..a0c5a5b84 100644 --- a/tests/core/math/big/test.py +++ b/tests/core/math/big/generate_tests.py @@ -1,776 +1,648 @@ -# -# Copyright 2021 Jeroen van Rijn . -# Made available under Odin's BSD-3 license. -# -# A BigInt implementation in Odin. -# For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. -# The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. -# - -from ctypes import * -from random import * -import math -import os -import platform -import time -import gc -from enum import Enum -import argparse - -parser = argparse.ArgumentParser( - description = "Odin core:math/big test suite", - epilog = "By default we run regression and random tests with preset parameters.", - formatter_class = argparse.ArgumentDefaultsHelpFormatter, -) - -# -# Normally, we report the number of passes and fails. With this option set, we exit at first fail. -# -parser.add_argument( - "-exit-on-fail", - help = "Exit when a test fails", - action = "store_true", -) - -# -# We skip randomized tests altogether if this is set. -# -no_random = parser.add_mutually_exclusive_group() - -no_random.add_argument( - "-no-random", - help = "No random tests", - action = "store_true", -) - -# -# Normally we run a given number of cycles on each test. -# Timed tests budget 1 second per 20_000 bits instead. -# -# For timed tests we budget a second per `n` bits and iterate until we hit that time. -# -timed_or_fast = no_random.add_mutually_exclusive_group() - -timed_or_fast.add_argument( - "-timed", - type = bool, - default = False, - help = "Timed tests instead of a preset number of iterations.", -) -parser.add_argument( - "-timed-bits", - type = int, - metavar = "BITS", - default = 20_000, - help = "Timed tests. Every `BITS` worth of input is given a second of running time.", -) - -# -# For normal tests (non-timed), `-fast-tests` cuts down on the number of iterations. -# -timed_or_fast.add_argument( - "-fast-tests", - help = "Cut down on the number of iterations of each test", - action = "store_true", -) - -args = parser.parse_args() - -EXIT_ON_FAIL = args.exit_on_fail - -# -# How many iterations of each random test do we want to run? -# -BITS_AND_ITERATIONS = [ - ( 120, 10_000), - ( 1_200, 1_000), - ( 4_096, 100), - (12_000, 10), -] - -if args.fast_tests: - for k in range(len(BITS_AND_ITERATIONS)): - b, i = BITS_AND_ITERATIONS[k] - BITS_AND_ITERATIONS[k] = (b, i // 10 if i >= 100 else 5) - -if args.no_random: - BITS_AND_ITERATIONS = [] - -# -# Where is the DLL? If missing, build using: `odin build . -build-mode:shared` -# -if platform.system() == "Windows": - LIB_PATH = os.getcwd() + os.sep + "math_big_test_library.dll" -elif platform.system() == "Linux": - LIB_PATH = os.getcwd() + os.sep + "math_big_test_library.so" -elif platform.system() == "Darwin": - LIB_PATH = os.getcwd() + os.sep + "math_big_test_library.dylib" -else: - print("Platform is unsupported.") - exit(1) - - -TOTAL_TIME = 0 -UNTIL_TIME = 0 -UNTIL_ITERS = 0 - -def we_iterate(): - if args.timed: - return TOTAL_TIME < UNTIL_TIME - else: - global UNTIL_ITERS - UNTIL_ITERS -= 1 - return UNTIL_ITERS != -1 - -# -# Error enum values -# -class Error(Enum): - Okay = 0 - Out_Of_Memory = 1 - Invalid_Pointer = 2 - Invalid_Argument = 3 - Unknown_Error = 4 - Assignment_To_Immutable = 10 - Max_Iterations_Reached = 11 - Buffer_Overflow = 12 - Integer_Overflow = 13 - Integer_Underflow = 14 - Division_by_Zero = 30 - Math_Domain_Error = 31 - Cannot_Open_File = 50 - Cannot_Read_File = 51 - Cannot_Write_File = 52 - Unimplemented = 127 - -# -# Disable garbage collection -# -gc.disable() - -# -# Set up exported procedures -# -try: - l = cdll.LoadLibrary(LIB_PATH) -except: - print("Couldn't find or load " + LIB_PATH + ".") - exit(1) - -def load(export_name, args, res): - export_name.argtypes = args - export_name.restype = res - return export_name - - - -# -# Result values will be passed in a struct { res: cstring, err: Error } -# -class Res(Structure): - _fields_ = [("res", c_char_p), ("err", c_uint64)] - -initialize_constants = load(l.test_initialize_constants, [], c_uint64) - -NAILS = initialize_constants() -LEG_BITS = 64 - NAILS - -print("LEG BITS: ", LEG_BITS) - -error_string = load(l.test_error_string, [c_byte], c_char_p) - -add = load(l.test_add, [c_char_p, c_char_p ], Res) -sub = load(l.test_sub, [c_char_p, c_char_p ], Res) -mul = load(l.test_mul, [c_char_p, c_char_p ], Res) -sqr = load(l.test_sqr, [c_char_p ], Res) -div = load(l.test_div, [c_char_p, c_char_p ], Res) - -# Powers and such -int_log = load(l.test_log, [c_char_p, c_longlong], Res) -int_pow = load(l.test_pow, [c_char_p, c_longlong], Res) -int_sqrt = load(l.test_sqrt, [c_char_p ], Res) -int_root_n = load(l.test_root_n, [c_char_p, c_longlong], Res) - -# Logical operations -int_shl_leg = load(l.test_shl_leg, [c_char_p, c_longlong], Res) -int_shr_leg = load(l.test_shr_leg, [c_char_p, c_longlong], Res) -int_shl = load(l.test_shl, [c_char_p, c_longlong], Res) -int_shr = load(l.test_shr, [c_char_p, c_longlong], Res) -int_shr_signed = load(l.test_shr_signed, [c_char_p, c_longlong], Res) - -int_factorial = load(l.test_factorial, [c_uint64 ], Res) -int_gcd = load(l.test_gcd, [c_char_p, c_char_p ], Res) -int_lcm = load(l.test_lcm, [c_char_p, c_char_p ], Res) - -is_square = load(l.test_is_square, [c_char_p ], Res) - -def test(test_name: "", res: Res, param=[], expected_error = Error.Okay, expected_result = "", radix=16): - passed = True - r = None - err = Error(res.err) - - if err != expected_error: - error_loc = res.res.decode('utf-8') - error = "{}: {} in '{}'".format(test_name, err, error_loc) - - if len(param): - error += " with params {}".format(param) - - print(error, flush=True) - passed = False - elif err == Error.Okay: - r = None - try: - r = res.res.decode('utf-8') - r = int(res.res, radix) - except: - pass - - if r != expected_result: - error = "{}: Result was '{}', expected '{}'".format(test_name, r, expected_result) - if len(param): - error += " with params {}".format(param) - - print(error, flush=True) - passed = False - - if EXIT_ON_FAIL and not passed: exit(res.err) - - return passed - -def arg_to_odin(a): - if a >= 0: - s = hex(a)[2:] - else: - s = '-' + hex(a)[3:] - return s.encode('utf-8') - - -def big_integer_sqrt(src): - # The Python version on Github's CI doesn't offer math.isqrt. - # We implement our own - count = src.bit_length() - a, b = count >> 1, count & 1 - - x = 1 << (a + b) - - while True: - # y = (x + n // x) // 2 - t1 = src // x - t2 = t1 + x - y = t2 >> 1 - - if y >= x: - return x - - x, y = y, x - -def big_integer_lcm(a, b): - # Computes least common multiple as `|a*b|/gcd(a,b)` - # Divide the smallest by the GCD. - - if a == 0 or b == 0: - return 0 - - if abs(a) < abs(b): - # Store quotient in `t2` such that `t2 * b` is the LCM. - lcm = a // math.gcd(a, b) - return abs(b * lcm) - else: - # Store quotient in `t2` such that `t2 * a` is the LCM. - lcm = b // math.gcd(a, b) - return abs(a * lcm) - -def test_add(a = 0, b = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), arg_to_odin(b)] - res = add(*args) - expected_result = None - if expected_error == Error.Okay: - expected_result = a + b - return test("test_add", res, [a, b], expected_error, expected_result) - -def test_sub(a = 0, b = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), arg_to_odin(b)] - res = sub(*args) - expected_result = None - if expected_error == Error.Okay: - expected_result = a - b - return test("test_sub", res, [a, b], expected_error, expected_result) - -def test_mul(a = 0, b = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), arg_to_odin(b)] - try: - res = mul(*args) - except OSError as e: - print("{} while trying to multiply {} x {}.".format(e, a, b)) - if EXIT_ON_FAIL: exit(3) - return False - - expected_result = None - if expected_error == Error.Okay: - expected_result = a * b - return test("test_mul", res, [a, b], expected_error, expected_result) - -def test_sqr(a = 0, b = 0, expected_error = Error.Okay): - args = [arg_to_odin(a)] - try: - res = sqr(*args) - except OSError as e: - print("{} while trying to square {}.".format(e, a)) - if EXIT_ON_FAIL: exit(3) - return False - - expected_result = None - if expected_error == Error.Okay: - expected_result = a * a - return test("test_sqr", res, [a], expected_error, expected_result) - -def test_div(a = 0, b = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), arg_to_odin(b)] - try: - res = div(*args) - except OSError as e: - print("{} while trying divide to {} / {}.".format(e, a, b)) - if EXIT_ON_FAIL: exit(3) - return False - expected_result = None - if expected_error == Error.Okay: - # - # We don't round the division results, so if one component is negative, we're off by one. - # - if a < 0 and b > 0: - expected_result = int(-(abs(a) // b)) - elif b < 0 and a > 0: - expected_result = int(-(a // abs((b)))) - else: - expected_result = a // b if b != 0 else None - return test("test_div", res, [a, b], expected_error, expected_result) - - -def test_log(a = 0, base = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), base] - res = int_log(*args) - - expected_result = None - if expected_error == Error.Okay: - expected_result = int(math.log(a, base)) - return test("test_log", res, [a, base], expected_error, expected_result) - -def test_pow(base = 0, power = 0, expected_error = Error.Okay): - args = [arg_to_odin(base), power] - res = int_pow(*args) - - expected_result = None - if expected_error == Error.Okay: - if power < 0: - expected_result = 0 - else: - # NOTE(Jeroen): Don't use `math.pow`, it's a floating point approximation. - # Use built-in `pow` or `a**b` instead. - expected_result = pow(base, power) - return test("test_pow", res, [base, power], expected_error, expected_result) - -def test_sqrt(number = 0, expected_error = Error.Okay): - args = [arg_to_odin(number)] - try: - res = int_sqrt(*args) - except OSError as e: - print("{} while trying to sqrt {}.".format(e, number)) - if EXIT_ON_FAIL: exit(3) - return False - - expected_result = None - if expected_error == Error.Okay: - if number < 0: - expected_result = 0 - else: - expected_result = big_integer_sqrt(number) - return test("test_sqrt", res, [number], expected_error, expected_result) - -def root_n(number, root): - u, s = number, number + 1 - while u < s: - s = u - t = (root-1) * s + number // pow(s, root - 1) - u = t // root - return s - -def test_root_n(number = 0, root = 0, expected_error = Error.Okay): - args = [arg_to_odin(number), root] - res = int_root_n(*args) - expected_result = None - if expected_error == Error.Okay: - if number < 0: - expected_result = 0 - else: - expected_result = root_n(number, root) - - return test("test_root_n", res, [number, root], expected_error, expected_result) - -def test_shl_leg(a = 0, digits = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), digits] - res = int_shl_leg(*args) - expected_result = None - if expected_error == Error.Okay: - expected_result = a << (digits * LEG_BITS) - return test("test_shl_leg", res, [a, digits], expected_error, expected_result) - -def test_shr_leg(a = 0, digits = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), digits] - res = int_shr_leg(*args) - expected_result = None - if expected_error == Error.Okay: - if a < 0: - # Don't pass negative numbers. We have a shr_signed. - return False - else: - expected_result = a >> (digits * LEG_BITS) - - return test("test_shr_leg", res, [a, digits], expected_error, expected_result) - -def test_shl(a = 0, bits = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), bits] - res = int_shl(*args) - expected_result = None - if expected_error == Error.Okay: - expected_result = a << bits - return test("test_shl", res, [a, bits], expected_error, expected_result) - -def test_shr(a = 0, bits = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), bits] - res = int_shr(*args) - expected_result = None - if expected_error == Error.Okay: - if a < 0: - # Don't pass negative numbers. We have a shr_signed. - return False - else: - expected_result = a >> bits - - return test("test_shr", res, [a, bits], expected_error, expected_result) - -def test_shr_signed(a = 0, bits = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), bits] - res = int_shr_signed(*args) - expected_result = None - if expected_error == Error.Okay: - expected_result = a >> bits - - return test("test_shr_signed", res, [a, bits], expected_error, expected_result) - -def test_factorial(number = 0, expected_error = Error.Okay): - args = [number] - try: - res = int_factorial(*args) - except OSError as e: - print("{} while trying to factorial {}.".format(e, number)) - if EXIT_ON_FAIL: exit(3) - return False - - expected_result = None - if expected_error == Error.Okay: - expected_result = math.factorial(number) - - return test("test_factorial", res, [number], expected_error, expected_result) - -def test_gcd(a = 0, b = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), arg_to_odin(b)] - res = int_gcd(*args) - expected_result = None - if expected_error == Error.Okay: - expected_result = math.gcd(a, b) - - return test("test_gcd", res, [a, b], expected_error, expected_result) - -def test_lcm(a = 0, b = 0, expected_error = Error.Okay): - args = [arg_to_odin(a), arg_to_odin(b)] - res = int_lcm(*args) - expected_result = None - if expected_error == Error.Okay: - expected_result = big_integer_lcm(a, b) - - return test("test_lcm", res, [a, b], expected_error, expected_result) - -def test_is_square(a = 0, b = 0, expected_error = Error.Okay): - args = [arg_to_odin(a)] - res = is_square(*args) - expected_result = None - if expected_error == Error.Okay: - expected_result = str(big_integer_sqrt(a) ** 2 == a) if a > 0 else "False" - - return test("test_is_square", res, [a], expected_error, expected_result) - -# TODO(Jeroen): Make sure tests cover edge cases, fast paths, and so on. -# -# The last two arguments in tests are the expected error and expected result. -# -# The expected error defaults to None. -# By default the Odin implementation will be tested against the Python one. -# You can override that by supplying an expected result as the last argument instead. - -TESTS = { - test_add: [ - [ 1234, 5432], - ], - test_sub: [ - [ 1234, 5432], - ], - test_mul: [ - [ 1234, 5432], - [ 0xd3b4e926aaba3040e1c12b5ea553b5, 0x1a821e41257ed9281bee5bc7789ea7 ], - [ 1 << 21_105, 1 << 21_501 ], - [ - 0x200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, - 0x200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, - ] - ], - test_sqr: [ - [ 5432], - [ 0xd3b4e926aaba3040e1c12b5ea553b5 ], - ], - test_div: [ - [ 54321, 12345], - [ 55431, 0, Error.Division_by_Zero], - [ 12980742146337069150589594264770969721, 4611686018427387904 ], - [ 831956404029821402159719858789932422, 243087903122332132 ], - ], - test_log: [ - [ 3192, 1, Error.Invalid_Argument], - [ -1234, 2, Error.Math_Domain_Error], - [ 0, 2, Error.Math_Domain_Error], - [ 1024, 2], - ], - test_pow: [ - [ 0, -1, Error.Math_Domain_Error ], # Math - [ 0, 0 ], # 1 - [ 0, 2 ], # 0 - [ 42, -1,], # 0 - [ 42, 1 ], # 1 - [ 42, 0 ], # 42 - [ 42, 2 ], # 42*42 - [ 1023423462055631945665902260039819522, 6], - [ 2351415513563017480724958108064794964140712340951636081608226461329298597792428177392182921045756382154475969841516481766099091057155043079113409578271460350765774152509347176654430118446048617733844782454267084644777022821998489944144604889308377152515711394170267839394315842510152114743680838721625924309675796181595284284935359605488617487126635442626578631, 4], - ], - test_sqrt: [ - [ -1, Error.Invalid_Argument, ], - [ 42, Error.Okay, ], - [ 12345678901234567890, Error.Okay, ], - [ 1298074214633706907132624082305024, Error.Okay, ], - [ 0xa85e79177036820e9e63d14514884413c283db3dba2771f66ec888ae94fe253826ed3230efc1de0cbb4a2ba16fede5fe980d232472cca9e8f339714c56a9e64b5cff7538c33773f128898e8cad47234e8a086b4ce5b902231e2da75cc6cb510d892feb9c9c19ee5f5b7967cb7f081fb79099afe2d20203b0693ecc95c656e5515e0903a4ebc84d22fc2a176ba36dd795195535cfdf473e547930fbd6eae51ad11e974198b4733a10115f391c0fefd22654f5acd63c6415d4cbdaad6c1fc1812333d701b64bb230307fb37911561f5287efd67c2eec5a26a694931aec299c67874881bab0c42941cf0f4ef8ca3548e1adcc7f712eb714762184d656385ceacc7b9f75620dfa7ec62b70ee92a5998cee14ad2b9df3f0c861678bc3311c1fe78c5ce4ed30b90c56d18d50261a4f46fdbf6af94737920b50adf1229503edea8b32900000697f366eba632074a66dcd9999a1510ccefa6110bac2207602b16cd4ce42a36fbf276b5b14550faf75194256f175a867169ff30f8e4770d094b617e3df29612359e33d2a3e8f4e12acf243a22b2732e35a5039fea630886e80f49fb310cb34cd1ecb0dc3036761ac8eed5e2e3d6ea88c5b2f552405149fcb100f50368e969c7d1d45db10ea868838dddc3fbc54c9b658761522c31e46661f46205a6c8783d60638db10bc9515ece8509aa181332207c5a2753ee4a8297a65695fbd8184de, Error.Okay, ], - ], - test_root_n: [ - [ 1298074214633706907132624082305024, 2, Error.Okay, ], - ], - test_shl_leg: [ - [ 3192, 1 ], - [ 1298074214633706907132624082305024, 2 ], - [ 1024, 3 ], - ], - test_shr_leg: [ - [ 3680125442705055547392, 1 ], - [ 1725436586697640946858688965569256363112777243042596638790631055949824, 2 ], - [ 219504133884436710204395031992179571, 2 ], - ], - test_shl: [ - [ 3192, 1 ], - [ 1298074214633706907132624082305024, 2 ], - [ 1024, 3 ], - ], - test_shr: [ - [ 3680125442705055547392, 1 ], - [ 1725436586697640946858688965569256363112777243042596638790631055949824, 2 ], - [ 219504133884436710204395031992179571, 2 ], - ], - test_shr_signed: [ - [ -611105530635358368578155082258244262, 12 ], - [ -149195686190273039203651143129455, 12 ], - [ 611105530635358368578155082258244262, 12 ], - [ 149195686190273039203651143129455, 12 ], - ], - test_factorial: [ - [ 6_000 ], # Regular factorial, see cutoff in common.odin. - [ 12_345 ], # Binary split factorial - ], - test_gcd: [ - [ 23, 25, ], - [ 125, 25, ], - [ 125, 0, ], - [ 0, 0, ], - [ 0, 125,], - ], - test_lcm: [ - [ 23, 25,], - [ 125, 25, ], - [ 125, 0, ], - [ 0, 0, ], - [ 0, 125,], - ], - test_is_square: [ - [ 12, ], - [ 0x4fa3f9fe4edb58bfae7bab80b94ffce6e02cdd067c509f75a5918e510d002a8b41949dee96f482678b6e593ee2a984aa68809af5bdc3c0ee839c588b3b619e0f4a5267a7533765f8621dd20994a9a5bdd7faca4aab4f84a72f4f30d623a44cbc974d48e7ab63259d3141da5467e0a2225d90e6388f8d05e0bcdcb67f6d11c4e17d4c168b9fb23bf0932d6082ed82241b01d7d80bb43bf516fc650d86d62e13df218557df8b3f2e4eb295485e3f221c01130791c0b1b4c77fae4ae98e000e42d943a1dff9bfd960fdabe6a729913f99d74b1a7736c213b6c134bbc6914e0b5ae9d1909a32c2084af5a49a99a97a8c3856fdf1e4ff39306ede6234f85f0dca94382a118d97058d0be641c7b0cecead08450042a56dff16808115f78857d8844df61d8e930427d410ee33a63c79, ] - ], -} - -if not args.fast_tests: - TESTS[test_factorial].append( - # This one on its own takes around 800ms, so we exclude it for FAST_TESTS - [ 10_000 ], - ) - -total_passes = 0 -total_failures = 0 - -# -# test_shr_signed also tests shr, so we're not going to test shr randomly. -# -RANDOM_TESTS = [ - test_add, test_sub, test_mul, test_sqr, - test_log, test_pow, test_sqrt, test_root_n, - test_shl_leg, test_shr_leg, test_shl, test_shr_signed, - test_gcd, test_lcm, test_is_square, test_div, -] -SKIP_LARGE = [ - test_pow, test_root_n, # test_gcd, -] -SKIP_LARGEST = [] - -# Untimed warmup. -for test_proc in TESTS: - for t in TESTS[test_proc]: - res = test_proc(*t) - -if __name__ == '__main__': - print("\n---- math/big tests ----") - print() - - max_name = 0 - for test_proc in TESTS: - max_name = max(max_name, len(test_proc.__name__)) - - fmt_string = "{name:>{max_name}}: {count_pass:7,} passes and {count_fail:7,} failures in {timing:9.3f} ms." - fmt_string = fmt_string.replace("{max_name}", str(max_name)) - - for test_proc in TESTS: - count_pass = 0 - count_fail = 0 - TIMINGS = {} - for t in TESTS[test_proc]: - start = time.perf_counter() - res = test_proc(*t) - diff = time.perf_counter() - start - TOTAL_TIME += diff - - if test_proc not in TIMINGS: - TIMINGS[test_proc] = diff - else: - TIMINGS[test_proc] += diff - - if res: - count_pass += 1 - total_passes += 1 - else: - count_fail += 1 - total_failures += 1 - - print(fmt_string.format(name=test_proc.__name__, count_pass=count_pass, count_fail=count_fail, timing=TIMINGS[test_proc] * 1_000)) - - for BITS, ITERATIONS in BITS_AND_ITERATIONS: - print() - print("---- math/big with two random {bits:,} bit numbers ----".format(bits=BITS)) - print() - - # - # We've already tested up to the 10th root. - # - TEST_ROOT_N_PARAMS = [2, 3, 4, 5, 6] - - for test_proc in RANDOM_TESTS: - if BITS > 1_200 and test_proc in SKIP_LARGE: continue - if BITS > 4_096 and test_proc in SKIP_LARGEST: continue - - count_pass = 0 - count_fail = 0 - TIMINGS = {} - - UNTIL_ITERS = ITERATIONS - if test_proc == test_root_n and BITS == 1_200: - UNTIL_ITERS /= 10 - - UNTIL_TIME = TOTAL_TIME + BITS / args.timed_bits - # We run each test for a second per 20k bits - - index = 0 - - while we_iterate(): - a = randint(-(1 << BITS), 1 << BITS) - b = randint(-(1 << BITS), 1 << BITS) - - if test_proc == test_div: - # We've already tested division by zero above. - bits = int(BITS * 0.6) - b = randint(-(1 << bits), 1 << bits) - if b == 0: - b == 42 - elif test_proc == test_log: - # We've already tested log's domain errors. - a = randint(1, 1 << BITS) - b = randint(2, 1 << 60) - elif test_proc == test_pow: - b = randint(1, 10) - elif test_proc == test_sqrt: - a = randint(1, 1 << BITS) - b = Error.Okay - elif test_proc == test_root_n: - a = randint(1, 1 << BITS) - b = TEST_ROOT_N_PARAMS[index] - index = (index + 1) % len(TEST_ROOT_N_PARAMS) - elif test_proc == test_shl_leg: - b = randint(0, 10); - elif test_proc == test_shr_leg: - a = abs(a) - b = randint(0, 10); - elif test_proc == test_shl: - b = randint(0, min(BITS, 120)) - elif test_proc == test_shr_signed: - b = randint(0, min(BITS, 120)) - elif test_proc == test_is_square: - a = randint(0, 1 << BITS) - elif test_proc == test_lcm: - smallest = min(a, b) - biggest = max(a, b) - - # Randomly swap biggest and smallest - if randint(1, 11) % 2 == 0: - smallest, biggest = biggest, smallest - - a, b = smallest, biggest - else: - b = randint(0, 1 << BITS) - - res = None - - start = time.perf_counter() - res = test_proc(a, b) - diff = time.perf_counter() - start - - TOTAL_TIME += diff - - if test_proc not in TIMINGS: - TIMINGS[test_proc] = diff - else: - TIMINGS[test_proc] += diff - - if res: - count_pass += 1; total_passes += 1 - else: - count_fail += 1; total_failures += 1 - - print(fmt_string.format(name=test_proc.__name__, count_pass=count_pass, count_fail=count_fail, timing=TIMINGS[test_proc] * 1_000)) - - print() - print("---- THE END ----") - print() - print(fmt_string.format(name="total", count_pass=total_passes, count_fail=total_failures, timing=TOTAL_TIME * 1_000)) - - if total_failures: +# +# Copyright 2021 Jeroen van Rijn . +# Made available under Odin's BSD-3 license. +# +# A BigInt implementation in Odin. +# For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. +# The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. +# + +from random import * +import math +import os +import platform +import time +import gc +from enum import Enum +import argparse + +LEG_BITS = 60 + +vectors = open('../test_vectors.odin', 'w') +vectors.write("""package test_core_math_big + +import "core:math/big" + +// GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED +// +// This file is generated using `test_generator.py` +// +// GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED + +Big_Test_Operation :: enum { + Add, + Sub, + Mul, + Div, + Sqr, + Log, + Sqrt, + Pow, + Root, + Shl, + Shr, + Shr_Signed, + Factorial, + Gcd, + Lcm, + Is_Square, +} + +Big_Test_Vector :: struct { + op: Big_Test_Operation, + a: string, + b: string, + exp: string, + err: big.Error, +} + +big_test_vectors := []Big_Test_Vector{ +""") + +parser = argparse.ArgumentParser( + description = "Odin core:math/big test suite generator", + epilog = "By default we generate regression and random tests with preset parameters.", + formatter_class = argparse.ArgumentDefaultsHelpFormatter, +) + +# +# We skip randomized tests altogether if this is set. +# +no_random = parser.add_mutually_exclusive_group() + +no_random.add_argument( + "-no-random", + help = "Don't generate random tests", + action = "store_true", +) + +# +# Normally we run a given number of cycles on each test. +# Timed tests budget 1 second per 20_000 bits instead. +# +# For timed tests we budget a second per `n` bits and iterate until we hit that time. +# +timed_or_fast = no_random.add_mutually_exclusive_group() + +timed_or_fast.add_argument( + "-timed", + type = bool, + default = False, + help = "Timed tests instead of a preset number of iterations.", +) +parser.add_argument( + "-timed-bits", + type = int, + metavar = "BITS", + default = 20_000, + help = "Timed tests. Every `BITS` worth of input is given a second of running time.", +) + +# +# For normal tests (non-timed), `-fast-tests` cuts down on the number of iterations. +# +timed_or_fast.add_argument( + "-fast-tests", + help = "Cut down on the number of iterations of each test", + action = "store_true", +) + +args = parser.parse_args() + +# +# How many iterations of each random test do we want to run? +# +BITS_AND_ITERATIONS = [ + ( 120, 100), + ( 1_200, 100), + ( 4_096, 100), + (12_000, 10), +] + +if args.fast_tests: + for k in range(len(BITS_AND_ITERATIONS)): + b, i = BITS_AND_ITERATIONS[k] + BITS_AND_ITERATIONS[k] = (b, i // 10 if i >= 100 else 5) + +if args.no_random: + BITS_AND_ITERATIONS = [] + +TOTAL_TIME = 0 +UNTIL_TIME = 0 +UNTIL_ITERS = 0 + +def we_iterate(): + if args.timed: + return TOTAL_TIME < UNTIL_TIME + else: + global UNTIL_ITERS + UNTIL_ITERS -= 1 + return UNTIL_ITERS != -1 + +# +# Error enum values +# +class Error(Enum): + Okay = 0 + Out_Of_Memory = 1 + Invalid_Pointer = 2 + Invalid_Argument = 3 + Unknown_Error = 4 + Assignment_To_Immutable = 10 + Max_Iterations_Reached = 11 + Buffer_Overflow = 12 + Integer_Overflow = 13 + Integer_Underflow = 14 + Division_by_Zero = 30 + Math_Domain_Error = 31 + Cannot_Open_File = 50 + Cannot_Read_File = 51 + Cannot_Write_File = 52 + Unimplemented = 127 + +# +# Disable garbage collection +# +gc.disable() + +def arg_to_odin(a): + if a >= 0: + s = hex(a)[2:] + else: + s = '-' + hex(a)[3:] + return s.encode('utf-8') + + +def big_integer_sqrt(src): + # The Python version on Github's CI doesn't offer math.isqrt. + # We implement our own + count = src.bit_length() + a, b = count >> 1, count & 1 + + x = 1 << (a + b) + + while True: + # y = (x + n // x) // 2 + t1 = src // x + t2 = t1 + x + y = t2 >> 1 + + if y >= x: + return x + + x, y = y, x + +def big_integer_lcm(a, b): + # Computes least common multiple as `|a*b|/gcd(a,b)` + # Divide the smallest by the GCD. + + if a == 0 or b == 0: + return 0 + + if abs(a) < abs(b): + # Store quotient in `t2` such that `t2 * b` is the LCM. + lcm = a // math.gcd(a, b) + return abs(b * lcm) + else: + # Store quotient in `t2` such that `t2 * a` is the LCM. + lcm = b // math.gcd(a, b) + return abs(a * lcm) + +def write_test_case(op = "", a = 0, b = 0, expected_result = 0, expected_error = Error.Okay): + def test_arg_to_odin(a): + if a >= 0: + s = hex(a)[2:] + else: + s = '-' + hex(a)[3:] + return s + + vectors.write("\t{{{}, ".format(op)) + vectors.write("\"{}\", ".format(test_arg_to_odin(a))) + vectors.write("\"{}\", ".format(test_arg_to_odin(b))) + if expected_result == None: + vectors.write("\"0\", ") + else: + vectors.write("\"{}\", ".format(test_arg_to_odin(expected_result))) + + vectors.write("{}}},\n".format(expected_error)[5:]) + +def test_add(a = 0, b = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), arg_to_odin(b)] + expected_result = None + if expected_error == Error.Okay: + expected_result = a + b + + write_test_case(".Add", a, b, expected_result, expected_error) + +def test_sub(a = 0, b = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), arg_to_odin(b)] + expected_result = None + if expected_error == Error.Okay: + expected_result = a - b + + write_test_case(".Sub", a, b, expected_result, expected_error) + +def test_mul(a = 0, b = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), arg_to_odin(b)] + expected_result = None + if expected_error == Error.Okay: + expected_result = a * b + + write_test_case(".Mul", a, b, expected_result, expected_error) + +def test_sqr(a = 0, b = 0, expected_error = Error.Okay): + args = [arg_to_odin(a)] + expected_result = None + if expected_error == Error.Okay: + expected_result = a * a + + write_test_case(".Sqr", a, b, expected_result, expected_error) + +def test_div(a = 0, b = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), arg_to_odin(b)] + expected_result = None + if expected_error == Error.Okay: + # + # We don't round the division results, so if one component is negative, we're off by one. + # + if a < 0 and b > 0: + expected_result = int(-(abs(a) // b)) + elif b < 0 and a > 0: + expected_result = int(-(a // abs((b)))) + else: + expected_result = a // b if b != 0 else None + + write_test_case(".Div", a, b, expected_result, expected_error) + +def test_log(a = 0, base = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), base] + expected_result = None + if expected_error == Error.Okay: + expected_result = int(math.log(a, base)) + + write_test_case(".Log", a, base, expected_result, expected_error) + +def test_pow(base = 0, power = 0, expected_error = Error.Okay): + args = [arg_to_odin(base), power] + expected_result = None + if expected_error == Error.Okay: + if power < 0: + expected_result = 0 + else: + # NOTE(Jeroen): Don't use `math.pow`, it's a floating point approximation. + # Use built-in `pow` or `a**b` instead. + expected_result = pow(base, power) + + write_test_case(".Pow", base, power, expected_result, expected_error) + +def test_sqrt(number = 0, expected_error = Error.Okay): + args = [arg_to_odin(number)] + expected_result = None + if expected_error == Error.Okay: + if number < 0: + expected_result = 0 + else: + expected_result = big_integer_sqrt(number) + + write_test_case(".Sqrt", number, 0, expected_result, expected_error) + +def root_n(number, root): + u, s = number, number + 1 + while u < s: + s = u + t = (root-1) * s + number // pow(s, root - 1) + u = t // root + return s + +def test_root_n(number = 0, root = 0, expected_error = Error.Okay): + args = [arg_to_odin(number), root] + expected_result = None + if expected_error == Error.Okay: + if number < 0: + expected_result = 0 + else: + expected_result = root_n(number, root) + + write_test_case(".Root", number, root, expected_result, expected_error) + +def test_shl_leg(a = 0, digits = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), digits] + expected_result = None + if expected_error == Error.Okay: + expected_result = a << (digits * LEG_BITS) + + write_test_case(".Shl", a, (digits * LEG_BITS), expected_result, expected_error) + +def test_shr_leg(a = 0, digits = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), digits] + expected_result = None + if expected_error == Error.Okay: + if a < 0: + # Don't pass negative numbers. We have a shr_signed. + return False + else: + expected_result = a >> (digits * LEG_BITS) + + write_test_case(".Shr", a, (digits * LEG_BITS), expected_result, expected_error) + +def test_shl(a = 0, bits = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), bits] + expected_result = None + if expected_error == Error.Okay: + expected_result = a << bits + + write_test_case(".Shl", a, bits, expected_result, expected_error) + +def test_shr(a = 0, bits = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), bits] + expected_result = None + if expected_error == Error.Okay: + if a < 0: + # Don't pass negative numbers. We have a shr_signed. + return False + else: + expected_result = a >> bits + + write_test_case(".Shr", a, bits, expected_result, expected_error) + +def test_shr_signed(a = 0, bits = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), bits] + expected_result = None + if expected_error == Error.Okay: + expected_result = a >> bits + + write_test_case(".Shr_Signed", a, bits, expected_result, expected_error) + +def test_factorial(number = 0, expected_error = Error.Okay): + args = [number] + expected_result = None + if expected_error == Error.Okay: + expected_result = math.factorial(number) + + write_test_case(".Factorial", number, 0, expected_result, expected_error) + +def test_gcd(a = 0, b = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), arg_to_odin(b)] + expected_result = None + if expected_error == Error.Okay: + expected_result = math.gcd(a, b) + + write_test_case(".Gcd", a, b, expected_result, expected_error) + +def test_lcm(a = 0, b = 0, expected_error = Error.Okay): + args = [arg_to_odin(a), arg_to_odin(b)] + expected_result = None + if expected_error == Error.Okay: + expected_result = big_integer_lcm(a, b) + + write_test_case(".Lcm", a, b, expected_result, expected_error) + +def test_is_square(a = 0, b = 0, expected_error = Error.Okay): + args = [arg_to_odin(a)] + expected_result = False + if expected_error == Error.Okay and a > 0: + expected_result = big_integer_sqrt(a) ** 2 == a + + write_test_case(".Is_Square", a, 0, expected_result, expected_error) + +# TODO(Jeroen): Make sure tests cover edge cases, fast paths, and so on. +# +# The last two arguments in tests are the expected error and expected result. +# +# The expected error defaults to None. +# By default the Odin implementation will be tested against the Python one. +# You can override that by supplying an expected result as the last argument instead. + +TESTS = { + test_add: [ + [ 1234, 5432], + ], + test_sub: [ + [ 1234, 5432], + ], + test_mul: [ + [ 1234, 5432], + [ 0xd3b4e926aaba3040e1c12b5ea553b5, 0x1a821e41257ed9281bee5bc7789ea7 ], + [ 1 << 21_105, 1 << 21_501 ], + [ + 0x200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, + 0x200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000, + ] + ], + test_sqr: [ + [ 5432], + [ 0xd3b4e926aaba3040e1c12b5ea553b5 ], + ], + test_div: [ + [ 54321, 12345], + [ 55431, 0, Error.Division_by_Zero], + [ 12980742146337069150589594264770969721, 4611686018427387904 ], + [ 831956404029821402159719858789932422, 243087903122332132 ], + ], + test_log: [ + [ 3192, 1, Error.Invalid_Argument], + [ -1234, 2, Error.Math_Domain_Error], + [ 0, 2, Error.Math_Domain_Error], + [ 1024, 2], + ], + test_pow: [ + [ 0, -1, Error.Math_Domain_Error ], # Math + [ 0, 0 ], # 1 + [ 0, 2 ], # 0 + [ 42, -1,], # 0 + [ 42, 1 ], # 1 + [ 42, 0 ], # 42 + [ 42, 2 ], # 42*42 + [ 1023423462055631945665902260039819522, 6], + [ 2351415513563017480724958108064794964140712340951636081608226461329298597792428177392182921045756382154475969841516481766099091057155043079113409578271460350765774152509347176654430118446048617733844782454267084644777022821998489944144604889308377152515711394170267839394315842510152114743680838721625924309675796181595284284935359605488617487126635442626578631, 4], + ], + test_sqrt: [ + [ -1, Error.Invalid_Argument, ], + [ 42, Error.Okay, ], + [ 12345678901234567890, Error.Okay, ], + [ 1298074214633706907132624082305024, Error.Okay, ], + [ 0xa85e79177036820e9e63d14514884413c283db3dba2771f66ec888ae94fe253826ed3230efc1de0cbb4a2ba16fede5fe980d232472cca9e8f339714c56a9e64b5cff7538c33773f128898e8cad47234e8a086b4ce5b902231e2da75cc6cb510d892feb9c9c19ee5f5b7967cb7f081fb79099afe2d20203b0693ecc95c656e5515e0903a4ebc84d22fc2a176ba36dd795195535cfdf473e547930fbd6eae51ad11e974198b4733a10115f391c0fefd22654f5acd63c6415d4cbdaad6c1fc1812333d701b64bb230307fb37911561f5287efd67c2eec5a26a694931aec299c67874881bab0c42941cf0f4ef8ca3548e1adcc7f712eb714762184d656385ceacc7b9f75620dfa7ec62b70ee92a5998cee14ad2b9df3f0c861678bc3311c1fe78c5ce4ed30b90c56d18d50261a4f46fdbf6af94737920b50adf1229503edea8b32900000697f366eba632074a66dcd9999a1510ccefa6110bac2207602b16cd4ce42a36fbf276b5b14550faf75194256f175a867169ff30f8e4770d094b617e3df29612359e33d2a3e8f4e12acf243a22b2732e35a5039fea630886e80f49fb310cb34cd1ecb0dc3036761ac8eed5e2e3d6ea88c5b2f552405149fcb100f50368e969c7d1d45db10ea868838dddc3fbc54c9b658761522c31e46661f46205a6c8783d60638db10bc9515ece8509aa181332207c5a2753ee4a8297a65695fbd8184de, Error.Okay, ], + ], + test_root_n: [ + [ 1298074214633706907132624082305024, 2, Error.Okay, ], + ], + test_shl_leg: [ + [ 3192, 1 ], + [ 1298074214633706907132624082305024, 2 ], + [ 1024, 3 ], + ], + test_shr_leg: [ + [ 3680125442705055547392, 1 ], + [ 1725436586697640946858688965569256363112777243042596638790631055949824, 2 ], + [ 219504133884436710204395031992179571, 2 ], + ], + test_shl: [ + [ 3192, 1 ], + [ 1298074214633706907132624082305024, 2 ], + [ 1024, 3 ], + ], + test_shr: [ + [ 3680125442705055547392, 1 ], + [ 1725436586697640946858688965569256363112777243042596638790631055949824, 2 ], + [ 219504133884436710204395031992179571, 2 ], + ], + test_shr_signed: [ + [ -611105530635358368578155082258244262, 12 ], + [ -149195686190273039203651143129455, 12 ], + [ 611105530635358368578155082258244262, 12 ], + [ 149195686190273039203651143129455, 12 ], + ], + test_factorial: [ + [ 6_000 ], # Regular factorial, see cutoff in common.odin. + [ 12_345 ], # Binary split factorial + ], + test_gcd: [ + [ 23, 25, ], + [ 125, 25, ], + [ 125, 0, ], + [ 0, 0, ], + [ 0, 125,], + ], + test_lcm: [ + [ 23, 25,], + [ 125, 25, ], + [ 125, 0, ], + [ 0, 0, ], + [ 0, 125,], + ], + test_is_square: [ + [ 12, ], + [ 0x4fa3f9fe4edb58bfae7bab80b94ffce6e02cdd067c509f75a5918e510d002a8b41949dee96f482678b6e593ee2a984aa68809af5bdc3c0ee839c588b3b619e0f4a5267a7533765f8621dd20994a9a5bdd7faca4aab4f84a72f4f30d623a44cbc974d48e7ab63259d3141da5467e0a2225d90e6388f8d05e0bcdcb67f6d11c4e17d4c168b9fb23bf0932d6082ed82241b01d7d80bb43bf516fc650d86d62e13df218557df8b3f2e4eb295485e3f221c01130791c0b1b4c77fae4ae98e000e42d943a1dff9bfd960fdabe6a729913f99d74b1a7736c213b6c134bbc6914e0b5ae9d1909a32c2084af5a49a99a97a8c3856fdf1e4ff39306ede6234f85f0dca94382a118d97058d0be641c7b0cecead08450042a56dff16808115f78857d8844df61d8e930427d410ee33a63c79, ] + ], +} + +if not args.fast_tests: + TESTS[test_factorial].append( + # This one on its own takes around 800ms, so we exclude it for FAST_TESTS + [ 10_000 ], + ) + +total_passes = 0 +total_failures = 0 + +# +# test_shr_signed also tests shr, so we're not going to test shr randomly. +# +RANDOM_TESTS = [ + test_add, test_sub, test_mul, test_sqr, + test_log, test_pow, test_sqrt, test_root_n, + test_shl_leg, test_shr_leg, test_shl, test_shr_signed, + test_gcd, test_lcm, test_is_square, test_div, +] +SKIP_LARGE = [ + test_pow, test_root_n, # test_gcd, +] +SKIP_LARGEST = [] + +# Untimed warmup. +for test_proc in TESTS: + for t in TESTS[test_proc]: + res = test_proc(*t) + +if __name__ == '__main__': + print("\n---- math/big tests ----") + print() + + max_name = 0 + for test_proc in TESTS: + max_name = max(max_name, len(test_proc.__name__)) + + fmt_string = "{name:>{max_name}}, {test_count} tests" + fmt_string = fmt_string.replace("{max_name}", str(max_name)) + + for test_proc in TESTS: + count = 0 + for t in TESTS[test_proc]: + count += 1 + test_proc(*t) + + print(fmt_string.format(name=test_proc.__name__, test_count=count)) + + for BITS, ITERATIONS in BITS_AND_ITERATIONS: + print() + print("---- math/big with two random {bits:,} bit numbers ----".format(bits=BITS)) + print() + + # + # We've already tested up to the 10th root. + # + TEST_ROOT_N_PARAMS = [2, 3, 4, 5, 6] + + for test_proc in RANDOM_TESTS: + if BITS > 1_200 and test_proc in SKIP_LARGE: continue + if BITS > 4_096 and test_proc in SKIP_LARGEST: continue + + count = 0 + + UNTIL_ITERS = ITERATIONS + if test_proc == test_root_n and BITS == 1_200: + UNTIL_ITERS /= 10 + + UNTIL_TIME = TOTAL_TIME + BITS / args.timed_bits + # We run each test for a second per 20k bits + + index = 0 + + while we_iterate(): + a = randint(-(1 << BITS), 1 << BITS) + b = randint(-(1 << BITS), 1 << BITS) + + if test_proc == test_div: + # We've already tested division by zero above. + bits = int(BITS * 0.6) + b = randint(-(1 << bits), 1 << bits) + if b == 0: + b == 42 + elif test_proc == test_log: + # We've already tested log's domain errors. + a = randint(1, 1 << BITS) + b = randint(2, 1 << 60) + elif test_proc == test_pow: + b = randint(1, 10) + elif test_proc == test_sqrt: + a = randint(1, 1 << BITS) + b = Error.Okay + elif test_proc == test_root_n: + a = randint(1, 1 << BITS) + b = TEST_ROOT_N_PARAMS[index] + index = (index + 1) % len(TEST_ROOT_N_PARAMS) + elif test_proc == test_shl_leg: + b = randint(0, 10); + elif test_proc == test_shr_leg: + a = abs(a) + b = randint(0, 10); + elif test_proc == test_shl: + b = randint(0, min(BITS, 120)) + elif test_proc == test_shr_signed: + b = randint(0, min(BITS, 120)) + elif test_proc == test_is_square: + a = randint(0, 1 << BITS) + elif test_proc == test_lcm: + smallest = min(a, b) + biggest = max(a, b) + + # Randomly swap biggest and smallest + if randint(1, 11) % 2 == 0: + smallest, biggest = biggest, smallest + + a, b = smallest, biggest + else: + b = randint(0, 1 << BITS) + + count += 1 + test_proc(a, b) + + print(fmt_string.format(name=test_proc.__name__, test_count=count)) + + print() + print("---- THE END ----") + + vectors.write("}") + + if total_failures: exit(1) \ No newline at end of file diff --git a/tests/core/math/big/test.odin b/tests/core/math/big/test.odin deleted file mode 100644 index f35f0b72b..000000000 --- a/tests/core/math/big/test.odin +++ /dev/null @@ -1,362 +0,0 @@ -/* - Copyright 2021 Jeroen van Rijn . - Made available under Odin's BSD-3 license. - - An arbitrary precision mathematics implementation in Odin. - For the theoretical underpinnings, see Knuth's The Art of Computer Programming, Volume 2, section 4.3. - The code started out as an idiomatic source port of libTomMath, which is in the public domain, with thanks. - - This file exports procedures for use with the test.py test suite. -*/ -package test_core_math_big - -/* - TODO: Write tests for `internal_*` and test reusing parameters with the public implementations. -*/ - -import "base:runtime" -import "core:strings" -import "core:math/big" - -PyRes :: struct { - res: cstring, - err: big.Error, -} - -print_to_buffer :: proc(val: ^big.Int) -> cstring { - context = runtime.default_context() - r, _ := big.int_itoa_cstring(val, 16, context.allocator) - return r -} - -@export test_initialize_constants :: proc "c" () -> (res: u64) { - context = runtime.default_context() - _ = big.initialize_constants() - - return u64(big._DIGIT_NAILS) -} - -@export test_error_string :: proc "c" (err: big.Error) -> (res: cstring) { - context = runtime.default_context() - es := big.Error_String - return strings.clone_to_cstring(es[err], context.allocator) -} - -@export test_add :: proc "c" (a, b: cstring) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - aa, bb, sum := &big.Int{}, &big.Int{}, &big.Int{} - defer big.internal_destroy(aa, bb, sum) - - if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":add:atoi(a):", err=err} } - if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":add:atoi(b):", err=err} } - if bb.used == 1 { - if err = #force_inline big.internal_add(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err} } - } else { - if err = #force_inline big.internal_add(sum, aa, bb); err != nil { return PyRes{res=":add:add(sum,a,b):", err=err} } - } - - r := print_to_buffer(sum) - - return PyRes{res = r, err = nil} -} - -@export test_sub :: proc "c" (a, b: cstring) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - aa, bb, sum := &big.Int{}, &big.Int{}, &big.Int{} - defer big.internal_destroy(aa, bb, sum) - - if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":sub:atoi(a):", err=err} } - if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":sub:atoi(b):", err=err} } - if bb.used == 1 { - if err = #force_inline big.internal_sub(sum, aa, bb.digit[0]); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err} } - } else { - if err = #force_inline big.internal_sub(sum, aa, bb); err != nil { return PyRes{res=":sub:sub(sum,a,b):", err=err} } - } - - r := print_to_buffer(sum) - if err != nil { return PyRes{res=":sub:itoa(sum):", err=err} } - return PyRes{res = r, err = nil} -} - -@export test_mul :: proc "c" (a, b: cstring) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - aa, bb, product := &big.Int{}, &big.Int{}, &big.Int{} - defer big.internal_destroy(aa, bb, product) - - if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":mul:atoi(a):", err=err} } - if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":mul:atoi(b):", err=err} } - if err = #force_inline big.internal_mul(product, aa, bb); err != nil { return PyRes{res=":mul:mul(product,a,b):", err=err} } - - r := print_to_buffer(product) - return PyRes{res = r, err = nil} -} - -@export test_sqr :: proc "c" (a: cstring) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - aa, square := &big.Int{}, &big.Int{} - defer big.internal_destroy(aa, square) - - if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":sqr:atoi(a):", err=err} } - if err = #force_inline big.internal_sqr(square, aa); err != nil { return PyRes{res=":sqr:sqr(square,a):", err=err} } - - r := print_to_buffer(square) - return PyRes{res = r, err = nil} -} - -/* - NOTE(Jeroen): For simplicity, we don't return the quotient and the remainder, just the quotient. -*/ -@export test_div :: proc "c" (a, b: cstring) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - aa, bb, quotient := &big.Int{}, &big.Int{}, &big.Int{} - defer big.internal_destroy(aa, bb, quotient) - - if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":div:atoi(a):", err=err} } - if err = big.atoi(bb, string(b), 16); err != nil { return PyRes{res=":div:atoi(b):", err=err} } - if err = #force_inline big.internal_div(quotient, aa, bb); err != nil { return PyRes{res=":div:div(quotient,a,b):", err=err} } - - r := print_to_buffer(quotient) - return PyRes{res = r, err = nil} -} - -/* - res = log(a, base) -*/ -@export test_log :: proc "c" (a: cstring, base := big.DIGIT(2)) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - l: int - - aa := &big.Int{} - defer big.internal_destroy(aa) - - if err = big.atoi(aa, string(a), 16); err != nil { return PyRes{res=":log:atoi(a):", err=err} } - if l, err = #force_inline big.internal_log(aa, base); err != nil { return PyRes{res=":log:log(a, base):", err=err} } - - #force_inline big.internal_zero(aa) - aa.digit[0] = big.DIGIT(l) & big._MASK - aa.digit[1] = big.DIGIT(l) >> big._DIGIT_BITS - aa.used = 2 - big.clamp(aa) - - r := print_to_buffer(aa) - return PyRes{res = r, err = nil} -} - -/* - dest = base^power -*/ -@export test_pow :: proc "c" (base: cstring, power := int(2)) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - dest, bb := &big.Int{}, &big.Int{} - defer big.internal_destroy(dest, bb) - - if err = big.atoi(bb, string(base), 16); err != nil { return PyRes{res=":pow:atoi(base):", err=err} } - if err = #force_inline big.internal_pow(dest, bb, power); err != nil { return PyRes{res=":pow:pow(dest, base, power):", err=err} } - - r := print_to_buffer(dest) - return PyRes{res = r, err = nil} -} - -/* - dest = sqrt(src) -*/ -@export test_sqrt :: proc "c" (source: cstring) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - src := &big.Int{} - defer big.internal_destroy(src) - - if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":sqrt:atoi(src):", err=err} } - if err = #force_inline big.internal_sqrt(src, src); err != nil { return PyRes{res=":sqrt:sqrt(src):", err=err} } - - r := print_to_buffer(src) - return PyRes{res = r, err = nil} -} - -/* - dest = root_n(src, power) -*/ -@export test_root_n :: proc "c" (source: cstring, power: int) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - src := &big.Int{} - defer big.internal_destroy(src) - - if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":root_n:atoi(src):", err=err} } - if err = #force_inline big.internal_root_n(src, src, power); err != nil { return PyRes{res=":root_n:root_n(src):", err=err} } - - r := print_to_buffer(src) - return PyRes{res = r, err = nil} -} - -/* - dest = shr_digit(src, digits) -*/ -@export test_shr_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - src := &big.Int{} - defer big.internal_destroy(src) - - if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err} } - if err = #force_inline big._private_int_shr_leg(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} } - - r := print_to_buffer(src) - return PyRes{res = r, err = nil} -} - -/* - dest = shl_digit(src, digits) -*/ -@export test_shl_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - src := &big.Int{} - defer big.internal_destroy(src) - - if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err} } - if err = #force_inline big._private_int_shl_leg(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} } - - r := print_to_buffer(src) - return PyRes{res = r, err = nil} -} - -/* - dest = shr(src, bits) -*/ -@export test_shr :: proc "c" (source: cstring, bits: int) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - src := &big.Int{} - defer big.internal_destroy(src) - - if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr:atoi(src):", err=err} } - if err = #force_inline big.internal_shr(src, src, bits); err != nil { return PyRes{res=":shr:shr(src, bits):", err=err} } - - r := print_to_buffer(src) - return PyRes{res = r, err = nil} -} - -/* - dest = shr_signed(src, bits) -*/ -@export test_shr_signed :: proc "c" (source: cstring, bits: int) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - src := &big.Int{} - defer big.internal_destroy(src) - - if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_signed:atoi(src):", err=err} } - if err = #force_inline big.internal_shr_signed(src, src, bits); err != nil { return PyRes{res=":shr_signed:shr_signed(src, bits):", err=err} } - - r := print_to_buffer(src) - return PyRes{res = r, err = nil} -} - -/* - dest = shl(src, bits) -*/ -@export test_shl :: proc "c" (source: cstring, bits: int) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - src := &big.Int{} - defer big.internal_destroy(src) - - if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl:atoi(src):", err=err} } - if err = #force_inline big.internal_shl(src, src, bits); err != nil { return PyRes{res=":shl:shl(src, bits):", err=err} } - - r := print_to_buffer(src) - return PyRes{res = r, err = nil} -} - -/* - dest = factorial(n) -*/ -@export test_factorial :: proc "c" (n: int) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - dest := &big.Int{} - defer big.internal_destroy(dest) - - if err = #force_inline big.internal_int_factorial(dest, n); err != nil { return PyRes{res=":factorial:factorial(n):", err=err} } - - r := print_to_buffer(dest) - return PyRes{res = r, err = nil} -} - -/* - dest = gcd(a, b) -*/ -@export test_gcd :: proc "c" (a, b: cstring) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - ai, bi, dest := &big.Int{}, &big.Int{}, &big.Int{} - defer big.internal_destroy(ai, bi, dest) - - if err = big.atoi(ai, string(a), 16); err != nil { return PyRes{res=":gcd:atoi(a):", err=err} } - if err = big.atoi(bi, string(b), 16); err != nil { return PyRes{res=":gcd:atoi(b):", err=err} } - if err = #force_inline big.internal_int_gcd_lcm(dest, nil, ai, bi); err != nil { return PyRes{res=":gcd:gcd(a, b):", err=err} } - - r := print_to_buffer(dest) - return PyRes{res = r, err = nil} -} - -/* - dest = lcm(a, b) -*/ -@export test_lcm :: proc "c" (a, b: cstring) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - - ai, bi, dest := &big.Int{}, &big.Int{}, &big.Int{} - defer big.internal_destroy(ai, bi, dest) - - if err = big.atoi(ai, string(a), 16); err != nil { return PyRes{res=":lcm:atoi(a):", err=err} } - if err = big.atoi(bi, string(b), 16); err != nil { return PyRes{res=":lcm:atoi(b):", err=err} } - if err = #force_inline big.internal_int_gcd_lcm(nil, dest, ai, bi); err != nil { return PyRes{res=":lcm:lcm(a, b):", err=err} } - - r := print_to_buffer(dest) - return PyRes{res = r, err = nil} -} - -/* - dest = lcm(a, b) -*/ -@export test_is_square :: proc "c" (a: cstring) -> (res: PyRes) { - context = runtime.default_context() - err: big.Error - square: bool - - ai := &big.Int{} - defer big.internal_destroy(ai) - - if err = big.atoi(ai, string(a), 16); err != nil { return PyRes{res=":is_square:atoi(a):", err=err} } - if square, err = #force_inline big.internal_int_is_square(ai); err != nil { return PyRes{res=":is_square:is_square(a):", err=err} } - - if square { - return PyRes{"True", nil} - } - return PyRes{"False", nil} -} \ No newline at end of file diff --git a/tests/core/math/big/test_core_math_big.odin b/tests/core/math/big/test_core_math_big.odin index 9a1e7b01b..42df7154f 100644 --- a/tests/core/math/big/test_core_math_big.odin +++ b/tests/core/math/big/test_core_math_big.odin @@ -1,6 +1,7 @@ package test_core_math_big import "core:math/big" +import "core:strconv" import "core:testing" @(test) @@ -35,3 +36,234 @@ test_permutations_and_combinations :: proc(t: ^testing.T) { testing.expect_value(t, error, nil) } } + +Rational_Vectors :: struct { + numerator: int, + denominator: int, + expected_f64: f64, + expected_f32: f32, + expected_f16: f16, + exact_f64: bool, + exact_f32: bool, + exact_f16: bool, +} +rational_vectors := []Rational_Vectors{ + {-1, 1, -1.00, -1.00, -1.00, true, true, true}, + { 1, 4, 0.25, 0.25, 0.25, true, true, true}, + { 3, 4, 0.75, 0.75, 0.75, true, true, true}, + {-3, 4, -0.75, -0.75, -0.75, true, true, true}, +} + +@(test) +test_rational_to_float :: proc(t: ^testing.T) { + for vec in rational_vectors { + r: big.Rat + defer big.destroy(&r) + big.set(&r.a, vec.numerator) + big.set(&r.b, vec.denominator) + + { + float, exact, err := big.rat_to_f64(&r) + testing.expect_value(t, float, vec.expected_f64) + testing.expect(t, exact == vec.exact_f64) + testing.expect(t, err == nil) + } + + { + float, exact, err := big.rat_to_f32(&r) + testing.expect_value(t, float, vec.expected_f32) + testing.expect(t, exact == vec.exact_f32) + testing.expect(t, err == nil) + } + + { + float, exact, err := big.rat_to_f16(&r) + testing.expect_value(t, float, vec.expected_f16) + testing.expect(t, exact == vec.exact_f16) + testing.expect(t, err == nil) + } + } +} + +import "core:log" + +@(test) +test_big_math_vectors :: proc(t: ^testing.T) { + for vec in big_test_vectors { + a, b, res, expected := &big.Int{}, &big.Int{}, &big.Int{}, &big.Int{} + defer big.destroy(a, b, res, expected) + + atoi(t, a, vec.a) or_continue + atoi(t, b, vec.b) or_continue + atoi(t, expected, vec.exp) or_continue + + #partial switch vec.op { + case .Add: + err := big.add(res, a, b) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected add(%v, %v) to be %v, got %v", a, b, expected, res, err) + + case .Sub: + err := big.sub(res, a, b) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected sub(%v, %v) to be %v, got %v", a, b, expected, res, err) + + case .Mul: + err := big.mul(res, a, b) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected mul(%v, %v) to be %v, got %v", a, b, expected, res, err) + + case .Div: + err := big.div(res, a, b) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected div(%v, %v) to be %v, got %v", a, b, expected, res, err) + + case .Sqr: + err := big.sqr(res, a) + testing.expect(t, err == vec.err) + + expect_a(t, "Expected sqr(%v) to be %v, got %v", a, expected, res, err) + + case .Log: + base, base_ok := strconv.parse_i64_of_base(vec.b, 16) + testing.expect(t, base_ok == true) + + log_res, err := big.log(a, big.DIGIT(base)) + testing.expect(t, err == vec.err) + + big.set(res, log_res) + expect_ab(t, "Expected log(%v, %v) to be %v, got %v", a, b, expected, res, err) + + case .Sqrt: + err := big.sqrt(res, a) + testing.expect(t, err == vec.err) + + expect_a(t, "Expected sqrt(%v) to be %v, got %v", a, expected, res, err) + + case .Pow: + power, power_ok := strconv.parse_i64_of_base(vec.b, 16) + testing.expect(t, power_ok == true) + + err := big.pow(res, a, int(power)) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected pow(%v, %v) to be '%v', got %v", a, b, expected, res, err) + + case .Root: + n, n_ok := strconv.parse_i64_of_base(vec.b, 16) + testing.expect(t, n_ok == true) + + err := big.root_n(res, a, int(n)) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected root_n(%v, %v) to be '%v', got %v", a, b, expected, res, err) + + case .Shl: + bits, bits_ok := strconv.parse_i64_of_base(vec.b, 16) + testing.expect(t, bits_ok == true) + + err := big.internal_int_shl(res, a, int(bits)) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected internal_int_shl(%v, %v) to be '%v', got %v", a, b, expected, res, err) + + case .Shr: + bits, bits_ok := strconv.parse_i64_of_base(vec.b, 16) + testing.expect(t, bits_ok == true) + + err := big.internal_int_shr(res, a, int(bits)) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected internal_int_shr(%v, %v) to be '%v', got %v", a, b, expected, res, err) + + case .Shr_Signed: + bits, bits_ok := strconv.parse_i64_of_base(vec.b, 16) + testing.expect(t, bits_ok == true) + + big.set(res, a) + err := big.internal_int_shr_signed(res, res, int(bits)) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected internal_int_shr_signed(%v, %v) to be '%v', got %v", a, b, expected, res, err) + + case .Factorial: + n, n_ok := strconv.parse_i64_of_base(vec.a, 16) + testing.expect(t, n_ok == true) + + err := big.factorial(res, int(n)) + testing.expect(t, err == vec.err) + + expect_a(t, "Expected factorial(%v) to be '%v', got %v", a, expected, res, err) + + case .Gcd: + err := big.internal_int_gcd_lcm(res, nil, a, b) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected gcd(%v, %v) to be '%v', got %v", a, b, expected, res, err) + + case .Lcm: + err := big.internal_int_gcd_lcm(nil, res, a, b) + testing.expect(t, err == vec.err) + + expect_ab(t, "Expected lcm(%v, %v) to be '%v', got %v", a, b, expected, res, err) + + case .Is_Square: + square, err := big.internal_int_is_square(a) + testing.expect(t, err == vec.err) + + big.set(res, 1 if square else 0) + expect_a(t, "Expected is_square(%v) to be '%v', got %v", a, expected, res, err) + + case: + log.assertf(false, "Unhandled op: %v", vec.op) + } + } +} + +expect_a :: proc(t: ^testing.T, format: string, a, expected, res: ^big.Int, err: big.Error, loc := #caller_location) { + if err != .Okay { return } + + equal, _ := big.equals(res, expected) + if !equal { + as, _ := big.itoa(a) + rs, _ := big.itoa(res) + es, _ := big.itoa(expected) + + defer delete(as) + defer delete(rs) + defer delete(es) + + testing.expectf(t, equal, format, as, es, rs, loc=loc) + assert(equal) + } +} + +expect_ab :: proc(t: ^testing.T, format: string, a, b, expected, res: ^big.Int, err: big.Error, loc := #caller_location) { + if err != .Okay { return } + + equal, _ := big.equals(res, expected) + if !equal { + as, _ := big.itoa(a) + bs, _ := big.itoa(b) + rs, _ := big.itoa(res) + es, _ := big.itoa(expected) + + defer delete(as) + defer delete(bs) + defer delete(rs) + defer delete(es) + + testing.expectf(t, equal, format, as, bs, es, rs, loc=loc) + assert(equal) + } +} + +atoi :: proc(t: ^testing.T, i: ^big.Int, a: string, loc := #caller_location) -> bool { + err := big.atoi(i, a, 16) + testing.expect(t, err == .Okay, loc=loc) + return err == .Okay +} \ No newline at end of file diff --git a/tests/core/math/big/test_vectors.odin b/tests/core/math/big/test_vectors.odin new file mode 100644 index 000000000..222912698 --- /dev/null +++ b/tests/core/math/big/test_vectors.odin @@ -0,0 +1,4813 @@ +package test_core_math_big + +import "core:math/big" + +// GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED +// +// This file is generated using `test_generator.py` +// +// GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED -=- GENERATED + +Big_Test_Operation :: enum { + Add, + Sub, + Mul, + Div, + Sqr, + Log, + Sqrt, + Pow, + Root, + Shl, + Shr, + Shr_Signed, + Factorial, + Gcd, + Lcm, + Is_Square, +} + +Big_Test_Vector :: struct { + op: Big_Test_Operation, + a: string, + b: string, + exp: string, + err: big.Error, +} + +big_test_vectors := []Big_Test_Vector{ + {.Add, "4d2", "1538", "1a0a", .Okay}, + {.Sub, "4d2", "1538", "-1066", .Okay}, + {.Mul, "4d2", "1538", "6647f0", .Okay}, + {.Mul, "d3b4e926aaba3040e1c12b5ea553b5", "1a821e41257ed9281bee5bc7789ea7", "15ebfa91663d62991f82757b52c07a1f61e42109fbda6012b09cb75b5113", .Okay}, + {.Mul, "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Mul, "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Sqr, "1538", "0", "1c23c40", .Okay}, + {.Sqr, "d3b4e926aaba3040e1c12b5ea553b5", "0", "af13b82e702669fcdc5a22d7fb20a286cd5d7357dc65dae8dd0beeb0ddf9", .Okay}, + {.Div, "d431", "3039", "4", .Okay}, + {.Div, "d887", "0", "0", .Division_by_Zero}, + {.Div, "9c40000000000044c00000000000079", "4000000000000000", "2710000000000011", .Okay}, + {.Div, "a03a9e1c9ecd4600a73553b5e7dd86", "35f9f28f2cd19e4", "2f7efced80593f1d", .Okay}, + {.Log, "c78", "1", "0", .Invalid_Argument}, + {.Log, "-4d2", "2", "0", .Math_Domain_Error}, + {.Log, "0", "2", "0", .Math_Domain_Error}, + {.Log, "400", "2", "a", .Okay}, + {.Pow, "0", "-1", "0", .Math_Domain_Error}, + {.Pow, "0", "0", "1", .Okay}, + {.Pow, "0", "2", "0", .Okay}, + {.Pow, "2a", "-1", "0", .Okay}, + {.Pow, "2a", "1", "2a", .Okay}, + {.Pow, "2a", "0", "1", .Okay}, + {.Pow, "2a", "2", "6e4", .Okay}, + {.Pow, "c51aac23a451627370e2767c51a102", "6", "355498cbf9889c7102a7cc5d500db60ee1bc0779bd9ae18e4aa442a4924eb20a307dc73634be3ea4fce13da5358090f92533943d7dee9ae7dc573c770d10ef76adb6bb13be22c27d8835053840178dd55fafaaa406f8aa28c040", .Okay}, + {.Pow, "22f5d30a14315d48df4a328b2157657583ef58244138029542bbdb4658c8c4811b81d571ff0de06579eb3ed0c4802a84602ff832ce7854f60e3a3a5ae31323eb8a2a7d12a4bb29ee6db08086bbc22cfe6ac7cb201e21c790c328cc5f4be7040c614e68f6f49da2e5dd72a54adbba17eec5deb657d02c899dc911380dbffec0286a03ed9ea3ca6e11148dfb80c89ce4c0999d8c9748c7", "4", "16cb3bba77f95103473e405521a073b6d8a1b81af0bae0cfa44a593ab8c8ee7f78b34e4bfffebc16bd494fc711f01f75cf76331ffa347c54532c78b8abd905c5dcb5bdfb68402cbc6d4256845bf63bd54577fee63b1bbcc32a762b29b64b9d491039e56854ea4474698f4c9fccdc886a8174b247d711aca335361c3a2037889d1426956af6df38584a36674f5782a07887622c33f9bbddbf5633690223b0761f00d21078d8d34726784c35d21b42c404633b2dc1a00f741653b9aba1b7b2a5454ccf4e8e6c0e7faa698921c5793c2b84ade8bf4b99bcf93eb6c33c3b0b59c2e93e6cc388a1fb2529e79877bd2c8885b7509fa8de77fcaff2e7faa7ca0daf37aed817f084a2df013f517d05e8fed27e38e29e45fb67172cfbbe3db09fb033936bf301ef73ca020adf88f538872448b02bedbb0bb9620d0efea3be30e9a6ccee5908cd215e8ab16d1cf8bba202718556a404cc55f2efc42fbcc3e65f629b4abe81436b3ac002406e81e42e370a31e787789bab92dec3f14b765d4028405a15e92336939bbef80fdfb455615a068063553a486805e71d05643fa415f4dd4d8efa886536c5d3d6f00a0d78d8792a71b5af3283bd7b0f4653b90108c518bdcea241ccd604aeabec6c7d881df3892e9307e7651d35278f09a2c991eff47f84406b3c950e3bc0a36ce803185e196df0f8ed1f5991e5586da5336786fd8e140d7de14bdac58001ea1b707d3d9d4ed6447c4a7810c34e3208d322bbb22f031cb180002e009637eb17768ba1d008ad513c097ceb161767cadffc58130b4166a67cac830766e4f32703d4bfd4ac257e3fc96a9f0803d82f489ec74e61", .Okay}, + {.Sqrt, "-1", "0", "0", .Invalid_Argument}, + {.Sqrt, "2a", "0", "6", .Okay}, + {.Sqrt, "ab54a98ceb1f0ad2", "0", "d16deb64", .Okay}, + {.Sqrt, "4000000000000000000000000000", "0", "80000000000000", .Okay}, + {.Sqrt, "a85e79177036820e9e63d14514884413c283db3dba2771f66ec888ae94fe253826ed3230efc1de0cbb4a2ba16fede5fe980d232472cca9e8f339714c56a9e64b5cff7538c33773f128898e8cad47234e8a086b4ce5b902231e2da75cc6cb510d892feb9c9c19ee5f5b7967cb7f081fb79099afe2d20203b0693ecc95c656e5515e0903a4ebc84d22fc2a176ba36dd795195535cfdf473e547930fbd6eae51ad11e974198b4733a10115f391c0fefd22654f5acd63c6415d4cbdaad6c1fc1812333d701b64bb230307fb37911561f5287efd67c2eec5a26a694931aec299c67874881bab0c42941cf0f4ef8ca3548e1adcc7f712eb714762184d656385ceacc7b9f75620dfa7ec62b70ee92a5998cee14ad2b9df3f0c861678bc3311c1fe78c5ce4ed30b90c56d18d50261a4f46fdbf6af94737920b50adf1229503edea8b32900000697f366eba632074a66dcd9999a1510ccefa6110bac2207602b16cd4ce42a36fbf276b5b14550faf75194256f175a867169ff30f8e4770d094b617e3df29612359e33d2a3e8f4e12acf243a22b2732e35a5039fea630886e80f49fb310cb34cd1ecb0dc3036761ac8eed5e2e3d6ea88c5b2f552405149fcb100f50368e969c7d1d45db10ea868838dddc3fbc54c9b658761522c31e46661f46205a6c8783d60638db10bc9515ece8509aa181332207c5a2753ee4a8297a65695fbd8184de", "0", "cf9c817dc096c3ad7b725c9ac52b0969fac4ff38ce527bec81fc7ede5a3f4802879e1c4f3a834d254725bf5ca902904334b22971d34f21d64321c0d5ad190791bd5004a54bcd7e70f265c9ee5c1ea266b687fdad448013bddd2c01436026be89ea2bd2b5cac4ecca23df5f6b3a1794836dd5ed890ed11a19a5c30135f76d1811e77984e69dff031f2151b3707bcded26c8b34e96a74cf392b85495cb1d6aa85000c652fe295d952cc784e29244fe53e52e6b9f44533b11fbd1425bfb8ccf69932dc717e7f614c39596e3ea7dd338f10c34a58dfcfdfa79c4aa11239476d5c201de5fda26e7bf1af62b3cf07058fe82e1cfc00725cd9da6a621b785af6554a4b2", .Okay}, + {.Root, "4000000000000000000000000000", "2", "80000000000000", .Okay}, + {.Shl, "c78", "3c", "c78000000000000000", .Okay}, + {.Shl, "4000000000000000000000000000", "78", "4000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "400", "b4", "400000000000000000000000000000000000000000000000", .Okay}, + {.Shr, "c78000000000000000", "3c", "c78", .Okay}, + {.Shr, "4000000000000000000000000000000000000000000000000000000000", "78", "4000000000000000000000000000", .Okay}, + {.Shr, "2a4663ad14733d6c985e64bf979b73", "78", "0", .Okay}, + {.Shl, "c78", "1", "18f0", .Okay}, + {.Shl, "4000000000000000000000000000", "2", "10000000000000000000000000000", .Okay}, + {.Shl, "400", "3", "2000", .Okay}, + {.Shr, "c78000000000000000", "1", "63c000000000000000", .Okay}, + {.Shr, "4000000000000000000000000000000000000000000000000000000000", "2", "1000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shr, "2a4663ad14733d6c985e64bf979b73", "2", "a9198eb451ccf5b2617992fe5e6dc", .Okay}, + {.Shr_Signed, "-75b1d4317d7fae6627576acd96e2a6", "c", "-75b1d4317d7fae6627576acd96f", .Okay}, + {.Shr_Signed, "-75b1d4317d7fae6627576acd96f", "c", "-75b1d4317d7fae6627576ace", .Okay}, + {.Shr_Signed, "75b1d4317d7fae6627576acd96e2a6", "c", "75b1d4317d7fae6627576acd96e", .Okay}, + {.Shr_Signed, "75b1d4317d7fae6627576acd96f", "c", "75b1d4317d7fae6627576acd", .Okay}, + {.Factorial, "1770", "0", "f0c93f984a54cc898047e57386e7170240f087f83b708cc5c1e3a0ad90b4e49923d442417a3dfc63d84db68daa950fb6c614e914cd54a006182dffd0967443f778a2b47cc1018efd34894fc11f723707e7e166153b0e0c2b4d7372785c450b1dd0f3de4e0d7cafd21180823e6cf11ed0c3241eb2ada4cc01852be8e2955f49204f04ad9d122d796b23835c62d7f15fb97925af7017271bfcd6f133410859470febdac7f22664fa1ae053d03c87a13fc2707128560505863df4dc233af70ff2ed86489f30c34a691951b950c86761b2e456457172902c0c4d4370b7ebe83972f2dd01c6449c983a51c17853ff4eed4082a6e42a99b6179b54e87b189fa5c4ecd1d345c88e5fc66b09d38ae9c49aba18eae2efc8c3e2932ab9a1bcf78c341b7c4e13ec55d43d67e6b15da8f6c789b91f876fb25af1fb6f2af3b7ba4104a198bf4215b13f89b6352bd58d4acb8bb248a646db3806e309ff66229e48c25d7128bd64647bd50527071238cb1795b03b509480c060cd17b77f949b007bdb5277faac50770c10c4bb83674776ce8a4610b0be3ea1565e7ac09fda913b04d6eba6ccbc03e4a49ad123711bed73de938b70e7808fbc02f01ab1b614559ffba61381b80685f8218ee679c0423f3c5859624bd20d2371682c139b4c58b95e90de1af532066d33f57c4b34e6c493bf30b01353ab50cc224a15cec1701a455a58e1de7ac797f598bb3d433fa5ba4d0a9657c98c08ee99fa3d0d5acc50537f4769606bc52b4dbf0cb11c2fe76985ef922cf3021d5b1e1db231cdc6f8f083e9a02d7dafd0867b829b849d636946227850ccabea4aed8056051f15ecc2304687734e81902a4929eb751a725ccfefe90f3156c20669c1566af2d9acc9f9798fb24f601571181e0b182a65356172261a23104c873b6c5cae0228699cb9077de65028f8bb53b4db83af02e580bbd4f0ef6ba996d93e321a6e3bae37f27ef9e316ebb350d8700079b7e84a1e5afb5d75e325a10738fa3cc5342354f0357d5b1457820f07698a3315a08730e9b2f58a73e74b294b50653883a8cae6da1b700440060dc7d25fe9f3756db15418f6128594fde0f48f7a543f977ce62ff9bf750954dc507f4de9cc54a61c072cb4bed5bfb4a35645782e3ccd4d0c257e74ea7a88a2c4e39a2d0d181b6f96f93d05261451fa4f64a17607465cfdcd16a67b73c38a5a09edbddf0728769aed09d0d5e4b7464f7942ecab0ea88649a04a4f9470176d4550b175f9900f984769d23fa45259dfb5e859146accccda8757d0c0a4b5858936cd8c89a64dca5eb9b42331075d32c3017d9c1f16424edc5dffe5e37ec7f51a3e3b047e207d1ca4f7239e90b76bae580f307685107f5a03e0cf2dc7c3ffd14d3b1a85e3af277c3793037cf84520bd6ce8fe99fa5259495808341e9406dbcebd8480b3ceb74b052039241ba4d1add796075ec99a0ecc948bc87c6c72f88082c0153677cc70317d55dc155f9574785494b26f997f379fdd80031c1d8eb2f7d43a6ea7ec4954a7fa5a496fe4fdc70f4f8ae5b1b78363e4441a073b5fef4e86b787d7084bfa0f462198b1c28cab2fdc669a1b486c026cb288654c1f18c8d2c1bcdcc33bc62ada91a10f7fa219c8d8db7597c6dc50e5d4342d93c2da55e05d835fe7a106958c80837af5a79f0b4552179ff57289958391ba7e387cee50a501930d31651e3b53e1cf95be74115dd42fbdff68926c4631b95400ec05fcf03324770a56e07fe364c1c78061e866a66357f5745fa8eff1eb11e1d77b284fe717ead053f26ff428ee773da48a66a3607d2d29d184065467c52ea251a1b8557bdae491f87a2764911a56edd4426df2039cc48b1ccb97e3ef48595408b168a1432fdc2017c0be74d587affc0e9fbb7d11304259dfc134e04a9f4913a7dc10259c0c698103a18c07c2947153bd5c04a10f24216a8f79fdab9340fa6cbb2c8714a4f39adbf6d99541ee288dcf824198140426b97abe5793f8446ef2b663ff6206e99f8cb5d87b7a30656fdacdba9c3cdc9e8911d9b470ae2fe7b37f5825e2e2018b9c26d6da0c0bfb3f7c1134423ea34a51daae7475e893f854625daad3507fdf93becc8cfe789aa45dcd4665b9cd92acd987c82e9a42a941b63484972bcf276549165fad3779472cad25121b79708beb9317c6179528c1801aedd208a94891ed897434fb7fced1d9e0d103ee64733038ee82a4dbcb29a1424c7b9d7b39c5abb2dccd8926558ebc2c7bc7714c39aa177f00c883e546c18fd0056e310ce09fb11edce0171dcd32057cf75c3a52be45361a5ac9d5be3745e9dcaec928c8311b44efc660bac4efbee5996b6e8d40672d4c9bd4bb1d203bc158dfec1478f47010106927a77a72101e3419d693acb64c2812508559e5fa9fb9d1fdca914941bfa78c2b0cce0d6e45e52751f29d682ddc49b47e17f22ebeb777ebfb4df4be344814f120585b407d7a4c5b24b1416e4a3a45a9e7602ee353b960309bacc6cd8f1eea4f297838b9028528347394d4cc6a63ee15000ecf4f64ccd0367caf08bb421dfd4278aa81185e50f8bce64be925c5d422d62feb1162cefadd4d48d4c606222e1e4aead7c05e7a44c9a1bc3d7e010c4fd8b5e754962f30a2ac0641d4581ac55871b6bfb1604747db02bd7b19c9fbd4e0cee9bdf3edfc4cd1c42bd91f30e86950349174cb96675830553acbd744ac318ebfbada54c6e3373aceeff6a62aeb1a0aca442580e8e2637a98887f548b43730db3532a3641e7dfca75f0766db4251d435973c4304ee8c79394642727245d8b5adce9970f0a74df28c1a7ae46b9f1a7b20f5b7759a50c238c90ff2c9f75807bf59abf38be876d404869cbf5ac6ea34a527ee35fc15db1e61fa7fa42879bddf7292922a485b792ea9eeecb4f58a070316dd89251bf826370c4fdcc0e1590365ed972d5a14703e94f122b357313eaedea12d4027dc77f0f16e35d17a7500cb36711952655280042deeb5b252486f2c42a0dd1a23768c2be59aaec3c760b878b114fca7ac863878d1ddb6aaf1543350a8eefda4ac5539d40dcabbfcfdc172e94709361a84da76638009a9c1b2823a0f213dcf46cf73931677c0b9b312bbe40a1848c0dd9152d5a9b3a377697167e287f6d620dacd1044e0d5d3ae07ae9e564dc07bcc9d1b552b140ec822d6c8ee6679444d58f0ea5710097d7c3be4a5c751c58a610031905539a1f391d8a7c0169a4bd082a42294887bc16d89fbf06d8388e989cb35593f2092cbae11ddd47bffc9b86b70ca9b41816f0b1654757781873b54c36eac4886ca2af9526c8ce0a8f85b51528a368d08c7a3570112031a67ab623f763bc19aa7939d0fb119ac0286648ccc7a12f3befe175f8d09c90f35fa0dca68a649cdfc859aa016047339ae9bf328fc9a0eae3a5ad1214f5220446372292b9ec461c44cc466e201aa6590f4bfc213865679d3403d4c2ac8380874cee3f65d6335bba1573d7d20ab9e73be9af1ba405f028b8341615bb07218ada3c2d36d18376277bf9f94fc1ce9189552c864298962f3195c9ef146874232fbc42f1768be379f94fc4edd747dc5b613da50c5e3322507ed9931c9cc17a7de16f5c06f6b24a4285ebe21458741f3855aca1aff3a015b840e23b4bef69505857940aa34fee44b3c8f11add91db976ba5c0b55659d2dd1d322e784578dfc4101c7e68c579052b5ae9cc923e2fbebc62d103dd68a966b49118747b64ae8dc9269ac6aced716427b91a14f8e17c011ca79816528aa8cf6589ef47db181fc5d48a5ec5da3dc629b0058ab91a9832f19b1b54c19b986613e7bd3b09c07de25e41c26aa1ebda72e38f169930813bfbfe74cc39fedb2e91255b5dba52600f38580669170749d7f52d39d2aa493ad83bf4ebb492d05a20ba4d7829ea7fcad7ed4ac9d9b037826289f5799d65d6c4817160239ce1a0f45d872229449d7b50f0932cf5982de3ede587ef5252b03349f60525c8e59a87bfd10fada76fae0c73dbb73e0a6f5c5fa6927c1eda01e4142d356fc02741af9d9e87183428c9d3389d08e9bf2c6514c0dcb87cfdbc1fb60cfd2714fe6f21b7206fec61a5ec7cb2e7eac92eb21c3164564d0303bf06edbaee1e7fe60a1bf8c69513412263b7c5cdedb96e36b5676a040396201981435d906321d9d5740dbf59a9723db18c65b32d84b684ef1ecc0723239c5b534e562df86d81f7aafa879b6bf9e1ca9a10caab41d2b616c107165b6756bca480dcccbf2880f5e7bafd49c186b03719836afba6eeb4f861c5aa4e00b226e42e0bc02c0cd7b0715eabf8cd67c7f4c2102e7772708d5824ccc2457641377775f8359a23bc94e514c414453dc7c486137e89a9c191d6f21b324cc1e02ac88fe60cea1261c9470507d2190b4d672185711c29871d20c91a332976a3aeffdce84c6b4b1c216dd9daa1e7065a629beaf9f92329712caff6dff95d61e93e5a0155e236b972de03f808253f8690aacf505d32682daeeabcb28789eb43c9026c32e535a956ee9e71f283dcdb02bae5b1c34d7dfb07202af8b5e900bfb3240d0049ac8e85b17276f012913128b53e2116887260d6a1df9e6c935850efa3e813ea85a0c743108a2f56f36bdb0c1e5ff14a3fd76f25a5b5e58241ae3302dfef6c778b230ec4c37d194b8369e3a511d98bd953ba26d418c25d6e15d4a8006a6b430deb02b00fd41f709c73bd30fbdef6b8b1cb7ee518c50c46cc09ad40949ae6b69da642baaa2f06a0a3d0dc4915f61ebddf1ab91c48af5dc75947f257eed2dd3cedc33fd0ff8df54b627be63974368c819054a4b893bb00f54d7933876c1e7838951417429faebadf917c3e1eb5f2ab3beeb3efa9cc4833c62901df6fcdc5e1505e659daf6310ea0b5f52acd8b4216ab7ce6b3591086a92ba093caf874cab14b006f5434fc1a4414bd16ab63a5a022b0cb0ba36cb1ed7860a3142ec646e0171f73d22822b2156cdc1848ea90eea94225add5ccf33e13db42654238424ae67a46066084cb0359fe32d307532dccf32f5c11233f8d3bcb398ef07fda2a5e465c12049032503675c6d3ef3576fe1d1c15047cbb0ce29fb7f353e43a8458822c252f02355d3d14f1cc33494b77f0bf55b88cf57871c6fdd2257adeef7962a4c3d4b857707b4ce8b02468347b58bde0466aff3d6057363e9125eeabcbb7d5936ebd656704fc6b045d27b9fc8514031c9cd90a635fe68a9a080713b9cf1918584f7461829f6cc3a7483a43e76601622f285734e21b56feca35f2458d40f4be31cc2931bce61f0f79a5eab3e492df63840a0a97b40a27d4516b32eb4cb6b643c5b562b5977f6e1d41c38940e9fe13240ea92421a7aaf97a2f68456802da771432df3a5d46eec42a74e780941f690353ef75f42d97a2eccc5da14dfbc277fc635c2fdb9cab322a51d92d4cd0ff70d009fa57435636550f4bc95926e7ff28467529ad9bcbac85de4d5ce5de6597ffa8a71e8197c937fca44bd206908fb9feb9ecc50071b00ec09940bfbc5679a4587e1d511f331586940663b65546777b23396366f996b002aca4520c6a997e7a368fb8698939a546e74eb00a0c0e4dab5927afa7b88cce9d8f07ef7a74818ed7e35448bfad0b07296992e21b514a6ecbca930e6f0543223b8780aa7b65612e0b394f93d19c3cf2188678bd5a5e2ad327bcc2860bedbfebbf343f31db337c48b2e8275bf6643192b2d3034d5d2404ee4129bf387c9572a773669aaf16ab2fbed600bb5060a2125e89b15f075ea947137e8d8777ea9bf260dfdc16bce48adcbbb5895081e8f0e966d69479de7d4197e2652961bd19ed5d651e45484ef6ecfd0033b0a9873f4497129575f2afcca46f1c42e4ad5e7cf3a72497ed83dd2cab5ed36c3a1c4a9ea3cd835792fbf77ec37a8b69c4f38fe8a77319c6e4e1f00dab8fa5629568843dd671d8f3ae36fb69772b02af3c94434c3c6e1b2ce38ae23feed4971dce4de59cb5843ee10bf1585c73a3898fe5848d74273ba3a6f9242d267207bf4250064b27445aeff713123de18ece118f989520b1e45bb7e3bce9c40a4c82bb12970b877bfd24332e1efd856306d53d9a4706f6ac0546af464fb6f5d97dba6da4bab8fa7254c0e517cc5d7622371db8ffb9aa9b2c2ce4a3cf5508beb12704a12bf89eb9eaf7aa0e9d4a578c0c17a505673124a2a0d0c19dcc4271b5bc67e7f6e470af0b232a6fd236fd4063d3fc9bc0d0b46b73b789af4c0c1b0b53f1d50ec1c648483bb153808e7ac4a829ae5bfe44fb193aa48a6231fda4292824da37b646d44a2548af78093154cd0f6c5880ded57959c4204526ff7fb88f36b2e753b857b1a95bea6f4448c0cb1c1c92dff1f6353f93e326cde06e5c4fec88143fdc29ff21e54625845db53a160058c8f8a8ca9c45f30a72c5f3f3c0d60ca21c97d01eb7d3bbbd68f973cfc4b7aff7ba10045e1e9deb4cdce9b95aeaf00b9b9a35adec07c593a518611c8d744669b12a3e52a37e26f5161ab89d02d32036349918ac5446235a0e59781eb0810809a077f473dc928b207ff5c5e3bf3a1ceab0e30088baba22fbdd3cc4a617b2376f2ccd5467bd87887ad618857ebb71434375896ef164ae95550d6bcc3086ab70ecf6fc17f3d3eb677ccf81a7dfe2fc58b5eaeae41dc540690b12e8e1b584432f05bd0f06db46742672a9c1e3031cf17b1c93849d9adf7e190e035f4e7f23e786f3102a3f6378ebc8bd19b7e9d3c73852c398118ff24a2d9b0e512173133692cdb6732ac4c35e0689c499d30195fa1a22addf95c0012a5ca5e62161dd88dcd75aaa29f043f987abdc5e1d0fdf03a67c859b96b7d92b6ccb9ab42b20903b2510e0f93fc43d9a7930ddc26d7c9caf4f8234723d24c1fd1cc7272e76a575778497d077592720ce020fe85a8fd94cee7e227d63dc67ea82b44992209963bc9c57a537c60848d7c98a880384ff4caf6fc4614109254beb4e91df94edc52b632448c4dbdaf7165792d79e687b4d720c5a6894e7019df3ee266148c52c93bce66073de054bf2e9887f77f7ebad94c70dfa3b0d6aeb47313f46125975c6187d34ab471d1aa4387829fa7a15f7ca89625ac8eec953b722ad0fd7d5581c35b895a7ad5efd9e2f355bec54c84dc1c01d40923039cc393950083496d2b75b8388fb4c93061ab0b962541819791038bfaf614e4a5805a66a2be678bbff245f6c35b73171a6b394b9fd4c24f742ee444bd70c7f4d2761450fdda51e82c7fe65f7f49bf0f2412a1e1d171db69fde747623c43749053b372db8948812c23f9efbf1bd318d20ae5a488e897350122bbe5e3d34c0871c05ca7ef9e02585ba1cff6fcb1c92d1063ea04fd4c22f014de06c494e9418b5f5df9c8d30b25b7ef180c45c07804cbff18e980e8e8ac2e65a24f48666b4f6bfb7fdaf68327575e1f486b6b69e4a6ce921ff6bde3ff11752c7788bb5f62b5966f6e6b501347e7342e089bc4b3daae8aed81b86a60911f454037d0d2e977f8658c362fe19f6bae39ffc626248e08b19f8211ab85913ed9849abe785e26e1137c6642134025dcd1cd138b178fde95f6785db77a39ffa444aa1f6b7cc19fa3f1b41af6c777ddae4e3d95d9df69b72da35d35f7d303ca85e28cca1a78644bcc2f3f97be8c3cba1fc31aa2df6d96f92b25dc3af7891ba3bcf5c9f8561613a9ffcb056a65d98e2a4232e8150ac3a5b328d44793d66a491ca2809fe5eabee9ed8f9d4738201a84eb4825b495db74921f766edabd1b06d25ade0b7e52ebc95ebc21c80f1cbf476c27fd23505b78f67eb885b4ed8e7cde831fe4fb52226a2323213a10c2957b2330e8d5f0160ed936e81261cc30e79e6d1aaffe0ae553f5392075af9a82750ffdc61e574e31bbe39affcc2ee6b8c6a64a056b62516506f2b58077093318293b47dac025bd280ef05beebe7dc7dd1fd5831b53624c9adf1096064470356db08a604e588e674553398782ff7c66694a44455574c6da206ecbb2225343e47f6198ee9ccbe38083b0ce60f8f074afe3887241691f8081e709c3d9b79c7cfd04d43b8bf1f34285acae5ddb1df8d26a7d7665af94e5d83ea90b24ae986611b26b35ce70e25e80a98b05d21f0d65a0f12d8c5033592d00cb69dc2e643db190389eaae0e98747c430e766801c223a94d87c9d727aa0888d982108d9a2078265a242d2d193a79fe0ccb3307b9c78925201a0f6e1c514ab705a8c43dd8d18ab3dbaf2969ce1c9108a1c03634c907d0ed2a01242a035be228ab9c39674c09799a84e5fe64f7f583085962e9c3522743f16320f6df80b07e16dcceee6c9860ecb992946ba773c3b4e9359775ab2443935d0cfed8c0091e33b55c4ef722d611b7550beab45853ea6f32bc4c184f6efdc339dd8b101a852b33aaae8ac13bdc9a1f5c9290c13e3533a0ecf6f3bec41031e0c901656f8c22021e3f9f57c2dec915155688d364e559220d1bb467473afa48d4e91e9637488c7f0d6382002eeebd4984ecc553679aabafd70ab008429355d018425db8e6a88e778b922e939e85bcc16a043ac0ff6e4ba3fd74332c075bcd496abd44bb8f73226980aecc55f14d1899764a9c7ce9bea4a9b4b1073a6ec2015181eca06907175ffdb2705f6fd00e5a013d21fc66d7a308235cc786f6627dc5909302b5188c42bd7de5350e06c1865316cf96300a79184d8cec06771c1b6ed8bfe661284c3f44ef5b41d7e70ba10bc6f41328787e778d5538e9785e5f032bea564bb4815fa9f09f47c5f73d4fa678d2104d8e0380c722c4ed6cabcb41da71ddc570028b7abadcf2899ad8be648e5d9aaf40c3a5411d704a57343c534f90c724f7981842a51691b8bea457e38e448908b66d9aa481c3c0763ad1afe7176630e646e9e00897bb348105ce4dc9a4c37ae615dc1b70ec5b1847d1aa9fe982dd649036fa8f5ef0c23e588c07f11de24e1bcffbaebbdd3215234935a08d389d6bcb6aea5be84e4929cf18e79eb8e5a8be348032eabd5509ce786ccbdc3344c87861c1b38b8ac59d21b0281e286927361a0797bee2700f625d3a8f87adc373258f6a9f35e65d68f2ab6570a0ccc21bffcb344f5b7d061a8a20646777bcf245e00a1ccdaefe2891f3b0c7580e3801dc7a3880fe66a70c0f0a2c880f79f110829cc7681623f36e022ba219e516ea2a46fa4f0fce0c489f67ed3484d67cbebeb5b9b3d75d82132059d4d7ce062fcfdc5c131b08d1c966eb103241d4d3228cfd1018e53003076d631150724f4ba6a7d6cd8719cb61d51fd83f09ebc9d11105b97af876566d80da59e977a0f665b3c28c7ed40cd778bca8f1a908319a14c5d6ad390cc55e5aaee779cc3916ec0963aa262dd7062a9ffc94aa86e7da473a44c0dee5c7f6820f327ba6b36e64154f5435474d09e3f3593f63216a3d6e206d3c8210a9430facdcfadb5cd50ebede3fc02d6bc1c43b3ece4793d0032f1f9a12cc9577a4bed8157c407f93f2ddc9b91aa5eea506c0386b55517f7a96ae01aef1e42a9479fe41be7c644d018301dce9c3ecddff37b1641beaefd486baacbbd24187f76cb9f154a33e6543155d29176fea515eaeaa28a321cd41255a1abb7efeedbbc0982f09563909fd76762f5b178d9003d37e2565908095f44cd376a8147ff2319d7cca6a0135f7bdd1f30f79c70c6f799f39f9bb88eb511858d4eb34c7d20b574f46ac8236a29b714d6575e58562a363b7c6286eae49d42831a14653ee16045446385a7797b6bcf1823f8b1b52a2376c3be5dc0b6a8282203d98df652455402ffd6208a6596570d264c2311a01da0a5b119172ef6d473321ab354460918f53c3eadd764c937c674a9fe3179d5c9cd54348805af4f29ccb5715d8e129d918040e4ec47f2c99022e1e00034d87d157a572d0d969032f04983cd54b8d18612a4c2875894c48feab0c96141e9ba648ad6a2f1ef1c0d4e44761bb14107126ff157ffd5c27568c37bd28a44ca81140cfc0d2a6dd864c4e27521ab9a1078d48e497b8d2b2104f1e4c3ba4a2f95e401667fa5e388c6807fac08d8c4c71bb5a0d50366d39987426dfd9172ae535e1497b0119bbf4c15f79fbe496350dbbe7ba335d9aa66ced3271eddec663d16120b0b0176987d463c5e47fed463e2ef2a230c17a5417f535aa26dad59615d603ec118670f88efba66f392aa3ad7a5d483ccfd8c8eb69728d982399cbb42c5a90449027efc2eb0432b90801d74a9418469af89eb75352e4a3dc2d1c589373eb8a2352aaf853e1bbaf7e4fd8e9c95567987bf453a46e7cfcc31fd61e6c0f1a2c658aba4feff965be68d6b5e964e2872f25eab5323b3c326c34729acf20c71698c43bc10ea039c977d4d7ab3927512c9a13134b4c4d518bbaaf831299632244228f2088eb6cba674fb68852c7cc3a2c721c84e8db66d2c5b0e4d0a95f0e0d928e7e5ac0602cb4f84ca84f200f33e7f189220f6a945b538480e4ecc07aeae6adf89c3f7b65737c0c15bc7f8a4ae2a2553d4fad3dbaf438ee0ba7a0f085b0743e6db6e425c1186aef4d134af4491222400e21e054ec39004f35862c17661ac52820005ab99c257de614f5d078073e323933c533b0e4ffdcbe8aa81c816e0fb3cbcb7e19a9fc228c2206c663f8b7bd4a166d527839b8204f3ffaf11af7b181e2f18c310f25eb7ccfdd9af1b5b00720fb719f5ba905163308736bc7833e400cd56c32198c6bcd137447df307a67567c8429adbe05028c3386ad96249552ca630fc67d7bacb109cf5f60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Factorial, "3039", "0", "725bc54b19f7229a2368a8438d231aa6742a9bdffda109af918973d185bd1142da42abe786438fbfb3b6a1d6732b6a1fb468d8908f1cd36ffb7efc0669264f2b5f3f92abfa5e2adb4ca4d9e2750eaf98c210de9067729c35a08bab7b52a889aa4f7462af4d00f28a02a41c9c63cdb0633b8afc137bcf9d06b7308fcf3aaa5d6a6cd571ae149530e773c9ab20fb61de0a754b959f749ed22fadd2ff0753c623eb2b377d75d7a730e0ab4fb8ab8097108085b68b81df361751ab9543dc4d640128718f886cd2deab7ce07c032728489f9b4c2ef223b13260de9c5b5eb26d5d3e4ba9439bdc3061afc6083ac8a60ef74d770d15557742c93e03f6df30dd5010a76761026e3e93b48e439d4cf71e41cfdc00e6c559f3a0047a5bcb54acee326ea538297a91cefdcc9a3b05d5d0c05319635a817fbe6edf12fa501e2024cdcd86f1ca3a12bfd485a55b0cb9717e5c29b65fd7f6a45ffe75300aa09ee79b9a0ef022d4ab09eef62544bef7042ad3c0dddd7cf6eda293ccf9d9cfe38e96c7a29cb0b8ec360cad98f97826dbeb94e444928d64bd1b01d7d562cec000c84d5a4b4b00039a82307a3dbd32dd5047fbef8d5a11d177bc6f09aa580ebcc9cfc1f1b73df77e247e23222e58592a5eb496e7fde5fe202b09f43734e4ea1318052095c689d7ead46695c1213cb6987c6a3fb6da2c7c7802af9b7d6eb6938d3660c87ee7a76b11b9f964063c7bc3e161f0edae8433de09febfcd2e37bcb9a48e519529aab496382dbace40b8c75a831e8401804a13c3f567691f03d84ef70c345c42a3afe869e4e59cb240b50811856f3a8202d2975289ea2ebeffa878a1f29a7576609c57c27c015a411e75fb25333ca49e6a6edd6f668b86f4ee9a7f6208e1af9ccd3553c00902692f9db06357f399b90cdbb05912070619c448159a4227526054ce00c7ca069d595557fc5374528b6739e29c2b27f81034eaa3a3b0358641c5b699db45256519da785dca487d0f88b41bdf388e460fedeacda9c27934bf453b96d7f8ea2acf573b33346a0a6f39c10104cc6eab077cab4ff1843b6f1ba2439808523c3f7ad9ca9d411ce0bafe9aaa543b82c54964cd1e7bb0692d314570f35d1b51e7a1b81f2d259f4ebef59e018a2e8781258ea2bf4b0a1053a0114089b70aff5657bdf835d73828d00878a3a74c9beb017901a593127907e14a350b40c15ec821a1e502cb5e8ff7e807f9277d7c18cfd82648aa7a7fb9732d3f7574386eb49b66ca927eea6154098f45efae6b7e46c4a0c9d8e5e432d7f9bbac3f06635f1e7edce3088e5baa7edfa7cb5ba90198b97020878e727c1481ba9399846092d81cc0d2f6e85edc6d995885335264e8423a8922b251f98113a89a14bd729b1aa895a7b8fd1d92ac8f826f0e5e39b23a4939313345f6a4c055f819b2689b8bb9fbab5bea96a69df4ca93566d1bf9b106f7f7826dd7ed7d2b14a1172e754ccfaa9aae397593a83e9a222830792c1d630ef0bcfa1ac7737630f56d5e4daf8d678b40167b5333923c78e4a962aeea8785886e19fadc2aef83eb5feee8b7cfa4583ab9122b3d784bf8ae0a0085a9617a2728013fa15c5ee1cfece8d6f1ec2edea5c02e98b3257e135957cb427f6dbfc179fb94229dc7c6867d93ab740b75c41522aa26dbfbf786e9a24b417cffe0c0c6b8049877706bf9ba0f302b93ee248f5cea90f098bc557a19d6e93383c3549b8ea7c2cf478d2be3006445e133cc899b05f8ce12f35caaadde7431ebd6aca51bac7e1a8677af175aff8ae9bcd31bd284f9b8bf99556e8c679aa617f35d89817636c0e32b28939cd5590a75d587d83a72478c68f289056350ce93a652a7ae531110e6e23340b64311c584263f2425aef4fa73ef808455688cf111ea17ea9ff5eea3aaf22cefab591dcc10167d9031659e9510c580b7ba675e75addd4ac4ad92b337ecb2024d1398a8933285da3affa4ae82f2ecc1add5881e42a9327c42be0f6e575d4d7c31a9257a7982dceede1e3cbd39b2808b739269413e6e764619554ae0e069cd4c18b54ebc7146100d735afcdcfbc969488470c0e12ad4dd9806d12cff39d431e008658e5b10a1bd72106ee0042c3e738000f7d825e4d9f1addd2ed0c1cef0756a29ac3500ab0a6278252f00e8b6d9b40bbd9425ddc7602a1332e4540a637ab94cf245e0d7453fe6d0cb94cf2ca5a279a565827052d9bdfd0a0a99fdbaab8f7bcdb5b3a19d70c19f6d3a87b47d8414d9fc7d617e8c2b8644adfdd761784174f1e7248eb7f04b538dc35eca7afe3df9ee02b9c5758c2ff06eccb89a918f607609a944a72e8917118a1fe1cf16b8993589d89f99044a5eb68d2efdb1cfdb894a7af03e3a24a2f98ef9ff47ff5813d2a38e13b76d66e3075fb0944c71f5510dcc5224236a1d4530c5abd60d439eca82c788c2bd84ed5455c395bb14b18f90fb6e23c1eb4396319642cd0c13c6026942c62022fbb9c26f180cd283960466e5649a62bf965721fa5930e844aa151f96abb4ba1dae7ae1095cc42cde8badd8662a997d213b23044077d29093b8d0951808f3a7c9cc1d60459506717d6db29d6f85eba257d1a8a7c0fbf049722923f5c5eede2ae0c4a2e8bd8881dd0f08ddefe11cb645350d8fa807a97ccd21b61bb271998eeaf0b60be41036525dc97fc80d7a8c648caf700468ffe7720aa279d5c5c1403646dfb3b9e0f4326876bdc7a89ed3a54aaddd84242264c0f4cec48fca3cdf8f59b548b8eff1cb3f31405cf068e1e3bf9cf4e378adc0662fb447f73c008724e6f8e212f5e57311385247d07429659c71b7eb7d8f2311a5edf73e1498ebf216b2b1cdbc83a182726a5f086b82c1465bfb43b25104eb3c947072a884edf2b8cdfed8bc1546d6daa21c4907350924fe9b5454c5cc5da4349809faabc2920a2b5d39e8d7d4149b69b5731155edc00f1c0f9f227a5794e2d0e47f5da6247e12afc1bbb76e679d3fd5d92a8e94300eca12e75fbbd423aaf5187a37ebd0796d063bf58c9575cb380672d5acfa6c2bb242f7a78a67b785f8982d0ec337fa809becb0dd8534b36b1908c5f10adc3f988eeb43acae2e271ffef9811ced071aa3608b9f887594d44824137f3e26104a2f3c49728dba805d410dc64afdb4911b070e32d5bef14bc10520e354cc7fa2f35998dc82173229ee64606ecbc14a9bf3d614a4a773e492d27b2ee8d34a7a772eb53392161027ba1bdbf88760f3f427186ec53844a991f75fef3de31e2e041a485d7bd09c977bfc1b7cd20d356db265a4bf17edf03a1bae0bfedad9290eae53a4e8a67ef0b1cb03efc5f2f3077beef63ec1a03e7db55671f2d0231d24a41f523705fa9109514d9d807a197d09685327da1fa35234f68b8942fe991a1b8f2454fbd2e4e1196a0f37eba6d24729bb4b6d50442a978d4638288aac01ef36a8e7b8f6f7b199a953c8b4c4c497f8cd32f558b18c58f021fe5cfe61a19a47b5cc5eada8796f666387b4a978b46319fda2f768b1f6a107019ad7aa813253449c8e6a419d2fedf59db4b39d899bc948250944aa7a586263fc0c06956c9f205369bf85ea63dae27f04f8850cc399b7b8b232ba9dfc5b59fce0373789f3566fb8df2ad50bc2f975830b92851c01886b2e737ffcd5065fe439f18f0b251925a430b438b6f9497d93c6f5eca03f2ee720689e7a981f7e54ea0c62777a0129a4e71348561d9122048081f5ff8c4f076d16d386406ffa3af8f1c399c8535df945e9fe17caf64255d175fb109a978db8a63f825e312c318c6b0dc59c55044a80ca4ac0e1ca2a98b70d32101c9aad6f9ad52abd939cc387cd4e4cd775524c7a7bab8328ad2d8096ded7c278f71ae9fdb8ac00e265db358c3030cfda95b6967495ae6f6a2c35886964f83a042a9a2d549fecde7eb49b221a8cd0f34ef4691e186a63154e76c7b9f8d8a6e885a36f0cebb3250d3a0da49237eb6079e06c81f1a082ded2cedb36d505f27351031d6d9643e03b1b87b64766c5c8935f13aa1f795554f1b55b9295e7d2b3e18f1ee84595978b8d8abde40d32a8e81ca08cbe0b3b44c50d5198e76b09b82764feae609ac46129d222ff5b861a41137e88605953642183894d1b4ba6afa59d7c69592d0feee7a9a92348d5082de0c84336861a1f6bcb3ff7708aabaef25955fcedf1435aad33a83aa9d3bbfbdbc174d12141c51f7ca91e356c76c9870e4a32d41dd7915d6c21ce24f5f49c334591907561fa6bf6d47b5bb41c1a83d6eb1e823acef38833f0798599f693c6711c9f7adf2887a8d8a4c0e615968e3e2d86fb51e92277f674ab129415a9d5b11b20a51dff9598a25d8f4b5f4fe8e03895158269b154c0a169e3c90a655c92b8f6c48c763df4bd134a1d23293379d36c9513455db5395e684dc79c74907a02c9ddb0ae562e1a4e307399b965511e05fc7e88e3abc495fd42d6f61ac5d5937249f9a0380127db9cf8235afcbfa7e136f6ace515bb3041c9dc54fa9eab903862a2d5ae1c0a14d8466e58ee872b6e3c8e8e11d63d67308d001cccbd58601fb1fe7874b80b927e0e97122a9d8c62f193a110d1431b696d1fdbd2216f421bcaea463ba82c7c8d583ab9629868b962d3152136d420083abec0fbf4a0d16b9120ebea914dece3df525788b0a18b953434b5899b24a0c601254974c65fc1623fdf2c11c10991493eeca2e1a9da5d0ed107cbaaf0f71f6592588f31aecf8e98cf25ca746242439ce908752a49a20de527caac3c707eef57543f98cfcd692ac1d039e19d5a09b9ce03fb307f00229f96cc5316747e1eaf619304a6a502c4edc236e76138789fd75a9a993cb77e7df97f7f0b847c92e4be0380b6e94d02e641a1677198b4dddb79b3fff93401b5bb6b7514d15afa918aff2943276d98ad8c61af100629ee7c90abadf959677760cd866f8d6fb7528e93320ca0f99351c5f0fa3d589bd9185fb615d501aa22191a46ad0501f2cdf61c92ff4e549dccdc531b775589d39672a16a2884a1cae8fc12233264b60ee868b1fa550b5fd541ed37e970d9ad7347fb9e338960a40ad8211cea809ae3ce928b5a003a01c3e45e5397ed20c1560944660285edcd5d68f0f8c7590feb49a2516856fe0c2ee49c958f9e8b7ac0d03814dfab8477079cecab4310bf97fb0306efce6cd933fcf0543c72862848f7159ac74eb354ed6f747ff82b13e801d8a274e5e2bb4f327b4e0bfa72a1428bde3281e685b095bb7807904717fc5f86cb96b896c24fdd3062fdcfe9a94a4ec84289e44e0f51da86158ba8ef895054ef3e9b609c3174f0f40b50f122f7d1b0cb2a4d4f8e6d84d04d7ab363fb6638323cd11a48efec0efc47eb7bd6ab5e40bef4f4a7f7acef17d9b5eb47181f155428eda5738943900323f4640c2adaa231b0d290d3166cbef6ecefd78e4295c391f6e7c350ad0840dfe5842d66fe4ab9c251ed7aa6b93799f9c57dab554929f687e8315ac0d306d763457d04b0892e5fc5fca44a65dbd58225f2c8a778b22fb0b376e72114845cc32a6dcf5fe7bf08d522ec9012f4e6f2238b10f23276df884f9cc813b9591dbf51441f6938c695b1c529dcdd8673eac84a75df4c2818fc5b73c54ca30b1f6865fa434c2721571cc115f864525af71fa9a7435a7a2645bd1c1be9888de21b354f0809f2cc4fec623a9f5d9d552e32dd8b93ba66e8b62baf97302ab20b3489efde5ab2c204c5a7dcf9742132f9acaa5093b75d5d4b2148c873e72cc9838c6e79ebb909d9d8b07e93ed565f3ad13f4676df70cdb366cb6ad4ad9e180465b9bc207852592933870a4312f4be267cbeffa80709217e2914515d259ab3bc4554293dff34518ed301a964cbee5e0da5f38da3e8d734b79c89095f08d782e6dc376723c48f3d60893375210dcf810149ed90592eb20e954e862e93afa885194c35f845c47d56ce469f6ca72d0c3d2880d96da5979b5dd865384484acedb1bab199888fb8af337d4af221542e664c8ceae0c004bd4d3145270583b6b666f3f62f0a2c6b9381b1673e73b08ffc34a693e02ed21cf9250b12f1daa9f1ba541fef727606e24072118bf69287170b3a33dbcbdbc068b855a2e65fa2406b3314af6eadee0f3464cff2416b6529c684c93037e2a17d674a1b56e96cc03ff13dd75d1ef0cea3831f1509ba1fcc6c7729363e7594e19e486b49b737a40e603ab2ce28e0ed7f4616fb2e6105df369cdf5490db1f75b2445025b86db0fdb0cc22bf63b68967cb2bcf2a7b1132c461f058be9e59254e1b7f240d9fdb01a9408a9c5770deaf74ba74af642a506c1c958fc95d8ae2293c4c5134573de18693c8d16c3c5ce7023f921842672adcda4e5e3f926b40bf14808ad2bd8fa91b28b2a1dcd380e8f1e5a566c48d8293d90efadef5fb104294109c393373e77bee58a932ce30f7c7ec46f52ab228fdeb883765fbb61d98f1869768f244182d40a5eeca6eb32111b381c8c9c82495ecdd41d4a27ac29effc82562b41fa41b60294bab971853ee48da85ce2ba803ea6573d1047406964c3f8f79653adc8bef5c818ef50623f468720c9828ae7f8038aba74f77d65db2bcbed9e1f415ed8819689e37d050a57e624cb527792b8709a0c31f921aab8a6098c9d23a542574686b52cbb4ba7d0922f28d1816684cd2359351227b2ed1a9864db623d87036ba16abe2742b54bcb23ac4bf7a1ed529b8382b290e5b000cc0f9582fda44d7a389400a51c8ead0bfac541bf7c95263750184f5a78091a8248720d67213ea1aed2d5a08419ab31cdb8d8052ec04a3f6a11cd0f47f0cfed6e4fce7d6e56e0996d06c5739238a5a5d89908c4e66ebd9aad357220ef39032330b35d40b7a4ad7e6174865fe64636e9e6f15ef4d37b0f390c81df3999e0dd73f191f1088bbc74c6cb9a742276c9a7023147043c81d00b6d3b82845c45d267fac6121fbd77093f22eca95af3a364c7934da516f75605c1aeb92fe9c801c571a366843df64f2cd4ce30636b37295620b9f74ec966ab52bbe3cea589f3e95bc0161b3305753b8a0af49979cdc8ae2e50006377b81a0a9c4718025572675fcf68aae62cdc47c71b272cedeea9ccad80c1c705a43650492cba6aa50b3375fd578f3a822d051dca2030218c2a4cfb16065716be81f4d1613b8d006af780fa5de4c7248fcef3cad3a58f242d9f254fe5486abd2f4bac666c01e90e892ab937fe39c243776a3475ffac7f8f96d68d3ea093ca3c4646a6618c31bde5374bc64c7efc0995989ebcbe816be8b6a3b1a43cbb63be86ad279a7c30c57fba1c469ef65270f46440e7d5cece01381c735afcb544872dfa7c4e7216cefa56584797dfad0313e6574eb4e01acf34f8a6c4395db3dc1efec7cd7f2562b082203120ecb56d54910c91db6dccf41da71fa22e5a68f2ad2a946415747bd8f7c79b2a02c177f185c55f9c32cec441bc96b00c8d21e977c0206ae8aae2e4fc7f74a787d603e8468bc823d39f0d1851b5d10bdf5ba813e2e214517a10a00c7e34d372034c126876c94aba7d03ac13ac36de981ed0ed51b8710c02b9a3dd6423af828425307910e7d8a5133c0a21e2182cf37512710f31681d5007e879ad75f40ee9cc3a4c3a6fe33e933a652a72f023fcba97d7774d167ab4c04d4a4bbdb7e330d220d84f877d3f577c1d499bd1e6fb999799e5259ca39f39f2463d371c9b8083a26225abd7487dc2fb20e8cdeb37200de1b82002b39f0ff70bb078c919d6bde528b0eb785e35d884fdfeb5127aa2dfad66df8761e5faf2f7a07c597aa4c9ef901116d69d45cf3565159383c8dfdca0c320512ce612654351e4cc2c72e5dc148786b75230d6fd463ed2164cc7da95f32cd26dccf7df8d97983f93dfb0239ea736f32c65f6469b9877bca5c0b9882e7171ed41b1366a2a86988642ef1c0c47cac31ee6e9354d9757d3057c00157be6f98a3f9754cad44883946a6fad81a64bb5ac661b2280e49e9f95e09c5af94615fab511082b6465a73c021ccb64dd1ccda8fad72562fb6eb55f1eeb5b2dc0687375cad33bcd0d74daad4298b1c592b5a624b26c5e0dcab7d631e6b217fadc76cb8f2aaabd5e50f2b4a28bc2effe011374d32ad6f3f7674333803c9beb262b60b539fa190f7b477c07922d645baea18ccbb3c06b5690d38fb125fce9be0988104066c15c7ca93ecb52ab3e1f936c2454a2e26783f5e8175c101c921a546dd33adb20d9153bf6f1bf79c3c284331133c605320cf313db6d1274f093015941e70ce615f10458ba48a30544d6f44b62e2847045fdb51c784a37edbe4eaec58974d8768684285e49ac15a33fc0cacf23e5afaa2e04524b71b1bb8535e53872f59aa647d13297a2dfe305116e82f1c72d27036898d2b544d6bb7bcec44db12d45cc6ad030875b170e3266581e544b07c8893f7829ae448eb888458a1ab8314e38ea687ca817ae1a7f7b77267a5ba136b546d5440025a9269f16546077fe2bc158bc31c1f4f77c5cd0850338917c5683f67207840e80caf6fdbfda8ebe105dfbc37d868545a40b97882769791d39d5547277320448ceb05c8f3d91d2a437d92adad44b78cffb6e81263cc900d99f57a0f3520d8acc2d1ce4ebf8bd494e4c84cb17d87ecfbbd595296a00949979a509037ac20b694adea16ab8e095fe8a42b4d12a4ea677f5a9baf4ba7409710e55d723ee1220c75ccdccae4389e6b7899a59417fe746d3607a120f64e15a64a3b50ec4e53575d82d348f445f1d6c1bc4cb9a6d8994a44c400bea87891ac5da3aba7fcfed7bf78ac3e90ef91bf55dbb16691a30476a6382de3fde7b8e07458e3cb4c7ccf53a870677d17ffdaf4590444f2586eed1d1814ee03ea49b3825168ca030299681114e0b5fec1be8b5d4dba691911acf1cf1e494261514613dc9be675d9a53d7c8a9733b8895eb746a7707adad425776b2400e1cfae03dd9ce639d964782a7894372d58245ff37e49fc09f86ec157898a5c55cf7a1c3977da3490190c82d4d6a54ebaf006634234ff6ff8070a9a992298f2e3d9ea3a74df937ec5e7b8263484e9815d731ef0f5b2d6eaa8c8f6bd966e0828a34144799bd575c4b7e6d5aa057518f7689b19ba446691f7813608c49fb424e9d4bb040c2a72d015aec8e049a0f6c985cd89cd106959d1beabeddbdd4042d5933cbfdc035e9718c98a2b5eee9cf9350a7e71749f3100309d59c41153c435e7cc7391538fe549fb1ccac1cdf7ba1f4b03d62d883da32fad505b5e98bc6ceb89b447852fcf5b84d64046daf583f42f88df6c936300339a49d121cc6814f5268d30bf827da8e83ee4672877c9ada3417f3fd1acc1c2bcebc22d9623a27068b83719b71f86a242fef992894ee32f53d60ca000779145c5b9274027c39711b8b4c697e4bcaf7c588a9d688d25f6312b9ee9dacdd1a28d0bd45883bcd665810c19170d80a6517dfaa83e489e38f4e70d2e70e605d7ecbdb0fde1e34f4633cd67ce2a24d845b1fa063fa12e141b51521071b40f73f2422d93498a456554be6eddfe155bb50e145ad0e24173daa9ab3aa808e156056821804d4e9ddf501379cecd91a37de9e2822e8465fcfd3968039c9d7617f685d6b567e8331eb117bf05768196b4c1384744bdf11fb824ea241386b882aa5c2fea9ca93165d13539e080462e8dd7ed58ae577f7d109fa864bc958b80c62cd5446a0048193b63423028291dc40355e63030988af8298013205330e292108aab5b29a19a0b5aff56e8d71c55a604fccdbb78f0b16443f3a4ecf292c57d72a09786346c0def2d97b1968c7d8313da150becfc0fe7bc2777fde63b05da1eb7b7dbf07a6c88e94ba3a1f03025b8abe363733243480a63fc68e687cfbeae555da8767b127d7a2893aa1259b300edb46d53df4e7659418a556a52c5920109c9f320448afc6567ea2c496f7340876e99bccebcef40f7653a7f66e6a4c53b893fe5a2009406226d119f526a6fc15e1aea77e505f8d339e7c0cf4f5ccd1474be0b49b629e27b07d754a056ffa66d8392384854477622ec093c2d16a9f430048743763acc2235bca3dac5745ea0b5dc7990ec5225eaf13025aba88319b8917c00e7c965fda36716122173659fc954e104436f86d3acba2d0052edb0d3edb273f56ce0fc763da0dd818e066e461f39e33892c72ee57d709fa22610ff698985a1a1095bd2ddd7f106283bb1c3c063d3e75d52e487fb56a4e3f5b619db7cc165fda958e417e86fe04018d2fd5347addfe9495bc39c26ff88730aab36f53c95d93d99102d0462c1e2837c27a9b0f4a2c011c5ac55b63c5a70d55f257e1c00102c2026c1f92451dcf82fb3c512f01339ed129472b9eba077b35aeac2acba39df315ab46ad5ecfa8e5a658ec4d0691d2b1b9d8578a341de65e918ab7969246ed3e790fb3d7753bda3bb855f2a4d9eb42355d5c68fa928ee2f21690d384a72576cc5a6592e5ab629968deb8ae9299eef30e71f77d135e77053dc67166059d1dcae2e723c345ffa14e730cb6a18c1489d585e255e300374afb1e1e52f41fcf72b43152346770f28c5ca6c35aab04bddfdee2180b762a55182b18b7978ab942f989843305303722db875219f6b37360c5d5f4bca44bd8cd199f3248b9ee383105f82822af392fc5899b175e32c11e7cf8f1b29201940e26d9bb189dd8c46c7f37a3c2cdb94496cc166f86a4c8ce1f6a91f7b178571050cf74dab79250512f4a84eeefe96d85a97159602049f5ebbb8e5cbc15a89cfc241277ce10fd3e8ecfd8ff462c7c5ee7a7adf5ea57acbc3df8c80806661dd31927413f43cd8d84e6768d3b580be97e1137bdf79637c4e672684a73534c8752cda954e4d1ff352eb82409b14aa45b843399414aa2c8d3f5262565c59cc7fb26ffd88cfe82e764ade5f563db295962cc802ee3ecbae87d3266b915835ca38a00cf7d64e90b5103305b91ca9ac97a4e274327f7899540163db95952ecfd1e0fd8bb1969f52558327a93e48a5108ba76add9e94e20a5e2a69f19d192c2c6e840acbb4e3d84b4397759a7e6249e011316f76d9fe6a918bcb411d2b41b12df3e9e968f404c52385affe1025d32b530a0dd0d39c96fe17fb80a274ad549d2b69565352fe67a0e1cc3046c2f4799e360b554e519a2626fa29fd5b4e5613f0663a8f4b1a4286d80ec4838efda3cededb362de4b822a77eeb2f37b131a65e17a8b25e36343512286e864e68545746ce255cf4797d92658d67938f7484cd525fb4e5655692e70fd47088ab206cb071cb404460e22a611dd0a55501841daf09f2f7cc4fccc494029cb99ee54f78eb4d4489a6f098572b209f7bbd6a8698572b67b99626d5e081f1a2da858fc7003980a9b5fd2ec77f6c267d9c0dc23ff60f0aecf26751ef29cf65d8581206fcae001b5766c889e897218cd00b372d9bc00c66d5f2edc77bb1505b9050788d3f559107c4efca0f66b09b0c4410454668090aaa52e3a1a918457e0d465874789340c043b121f0adb07b02fbb6510f785b904758ae1e0c215fa40b9ba0f6ad7925dd69dd4c2a323374e9705cc28d65e968a18e04d2859ff82e759d782e80f600fa5afaa0ffe880b1484fe3d76fb75845eaae145eb57f633d5121d451b1728a69a9c5af05b439e133bb78f4b59304628102e95f05d6eb13d86660d4d92b2693ec518d4f24e69462116c39ed1caa37fb3ac88dbafc999ae7477069a755e2b1c00a00890b401b74619f5d114def3ab936b141edf19dab04b1f5e4a179ebfb9e20efe8cc679e0b9a499a20c06e366bd890a83673ebcd551b957ff936a7a3e36fa9cb1152fa10c1357a4bbe55b96f925949eaac849f515363155f6db5b68317ac83ebb0245891e936cb82a95a4ef75a1ecc0945829cd5ff654d7dbb97b583d92073890e82a1cee2e3ab77c1fbc14f6898c2e40b5e0d7b32f6cc28e51b5103d8c341c63a01b1ad6a431858ec1cc9d2c1fb93c541af46408be1ce1ca9eefb051ca708b3e9c54f8fa6a6bee5782043eabc72d5da51feb40c9a4a2cadb452fd0d36c93efa3538353cb11c35163e4f888300653ee9e65baee3842ca51a54d716c6000ea285175cc2d1710f7a7681c273c022aee162427bac6eab5a74b4e7a5629ecf42224c9618824ffbb6c05f61f534ce5e7e81db01ae6c6c6bde41f3afb0320eae94784d0c414738b8d34a43088115281d61cb62da069876980e31eba34442183578e00a47581ce3706640cff00322a8461865ce796d021b632265a879af27cc3a20c5ca908243521449643a78a41f721ceadddc731d7cf020e063898322769075ecd33a2c3154a701a5def543de939b43c9fae25880ed4aee9f37ca20e7382ad469b1e0981d4d44820ff8ba2569149d634b522c101630cb9ed80c17d8ba19804a392912f77d9b655cd5800dfe7c2c654cff4d85eb3f6ae3707cd52112cca670e1e44e5454ff71e865da547c91e50b317050aa0eecdf99bbd32cb97d6278d88a28af732aad02e31609bcc8ac93511f17f95070fc37aa7cfd3959769da931638300842cc5af97376faeedbb31b084d53401f55f64b7086531094b27c48ad0b115f0fc7d959b1aad516856f95dc56328609ad27542970e4af282a2f61f6c61ce69c545b471ed0eb041ae17e132f7565457e8498fbf38151296f96016682f0082e220ba5abb0ad8ca52b4766680915e205d1650fc50c6d49e221c0466fd643b42d8d6a953cc5e21d048171df599aaf542f542123b0876b620d46bab078e6a37f4b78efc621d578e20948cd20b3be2623bbbea0d23b141fa102beda7e8e9d0839d2f023bb9e1914c9d948d7ef0fc24ab504ff7477a34a96fc6e1537bc6ef55f27d16c6368ab5d5ee7baf994ecdff8dfe2bc37047131714e25544b864328dcbf92fbb02df76096290022fb461292d0f4d5a4366441e18e9a14663a3a7905d2bc41aecb4723a16ac95ee7d59a8e5fc27a1c5f4bb2ec455cd460fa4d66b969afd2f0b5f47a88bf03102a9a62c81f8ef1e566f76a371a29b8c37555e214107bc269e562a3be6a619a251e80aa37d1c38a98c3c37094dfa6abe3ec47a2bff90af5bd31f2ff3f09f3a511e9864419bf4e65b24ad192481e28cf5382561f7fa38bc4eb88277ce3c2ce13ca49203e6feae0f0bc5dce32e6f9d0830eb95a7e8f43921dd360bdb4ad3c9a3135c8ec7abca027bf3a81d9362d2636958dada1f680aa2f331ae60bd0ea70c47fad08269a001c0138a7c737736f6d922ee42f9a7e596f5dbcd2473e108515248ce9c145bdd5f9f0acbe52735eb53ab092b4cec5585736641df0a60c1cea49392ad29a34eafc2ee940c7d2188cae84bfe86dd965d2a679efafc4153d56135b01ccb9c6d9d30723b64d6a853e114f35a4fb3e000b33c11f7219c1bb869436d5af69da81f80814d76fe7f0c5fca346c39ac275a7fd31d298f32da0db543b302d4559eede2f7e60a5d2a423954af3c1dacc6a4f4e0954e37e1fd89fa101f722b4515fa9628415d97688ab1017788ece393ffbf7ffabd3f92db0ad9773d0ec3a4f0cbedc6e1513acf1743974cfa4fa90a9922249bb0b1bbb39c118b044454f3ad1d3a0ab774bf8c2b5a240b743e59534770ddab84191454f3a8fd320d7583b5732b4df32e06c216652613b62a1dcce0068adb139471c804184403b14984549e8f13e54a710924fe9374fbf158cbb00ff93b2a14085888873d3296731cd618930c83936ee610aefe6bd85601399d5b6d7f86bddc06b5b1fa10e785a01a2b8918aee9a6f582735754bd3d707c4946a153ab047e5e89ad969ee922fb55356dc9a04cda997c3b74f447cff8c1f5dbd52290c979ffbdcc58f61cb00dcba292582b3df0979d3a0de42b7417344ec426f4129538b0fd2585369a6c4c55a906501bf5ebf5881fcc9dced7da46b6e02cdd425b45b480ded9e024468136affe521a0054a6b2d2b729eead54be36f5b7ca2f417220ccf6a4f44d4a3fa2de432ec7d1036c7e2ee052852f6d6f3f96ff24189b95e2b75ba4559a2c5fc3ffa13a9c3669a9981a625e0dfb608c14e722d7261c07cf6954b81a91ca482a234746a74cd70511b825f1a0bdd9ea4a2542f2625b3a509c273d7b731e77874b1f13a8460e72a69faea0197d0d5d5ed5b438db26aa7d8733af50e39b2c70089b8a9eecb64ba2b43c03bac29bd06c38e5cb9cf68b7571beaf8dff317194f2fca4927c933a4edebeca13a04b7329c759a5cc1377e7433d9d9b9f146dc435e749141173c1c3151ba17c07ada58e81876332fd13d055eef69b415ac3044d8cd3477e8cb2462b356a890be8d8779228078e2c5a383db483dfd7c6d00f0ab56c09860b9742ba8432ce6136634034fa0cc8e0adac49a90dc65c2e65d2db22894480aaa79763da47d231b7db3d32b29253ca247fbc9e79ff5b4bcead3fe2dbb4a52f8fd8248801f300a4eb1e51fa0688d0ebdf256938b8e2a7d91a0fdb992a9040a2c44a01d1ab23778ef4adf57bb87e1e92160de955d63130ede951632bebe2c5b06547b1bdf19d3713592511d312c54644d8fc2ab932aab9520e231cf1cb27c3e89c7ae3e0c20710a3b714cfcaf95201c5fd098eab2f5614b29238da7ba800fa3497cb66ab5eb6b75b7c02ac2588850a45841f97f5a64b19a45760657ae049040296272bb09e23e87c140543f7b8a4d60a529a51220df11e91fdfc1af002b12efce7b9644376f81e4e94dbb4235d614fce00dc3fc299aef5b940b75290b37b44c34cd2da3738234fc0b20e854100fd1bef48cb9744699af523a2f5144d66d50af156d92384167ea8ffcd787e1ec1b6f5cf7df126fd91e1b4e585c12373fd325e03bbb7190e9ad4e0c72703a68b68271defcfd9677b23a166d8c5776b027e2d5ed02535c942be13dac3a7d47ea7c47bf3c3fd8b106c6bcca427d33e9f595117e0959e0d161270af9132dfef909ac73c13a8fb8bed47b81dd9f3f2d8e9f15d6a1b70654c5033a1c55ad6f5ef997994d3de619393491b6cccfe6ec2b57e9c2fb272aee196dd7f22e93b99c863df54403fbb3e27d37a690509b28035b554e648da7c33151fdb5438ffc63cea2bf246910eaf0e7b4cc88b49a99fbe00b195857ac0e129c530a377cc80ac974c74b83e3913da4066809261a5e299433f05dc1e7923093e7f8d29fee14f9006e489dfad5261986b6b25892ba0aa7312dc2b09415b5c4240cb05d620e36ed118ffbfb7c33191306a96d5771ba3c53b94d4408e44222f4a2987803e1f2e6f6e45af1b326f8d6ca77bed58f5f298fec58a7c95bc55b090f95fee694081fb536004b87eda39e5335896d8837f8134379cfeeab19b94d1da87f18d1fea951b53fa834e22e8cbf4788cd6a4480ead97250c9ff94e4dbe6d2989d3f7c9030f51beffb77dfc34691a41fff28718971eb11241795a55b4449a5eaac0f778191f7e6671662701284d9fb2d1b672a17adf8f0b325b78580f2444a84fb2229856a08f5dbf9322c554652c472af56186ad44d9f6f5b0c1359d1c6d58bec2ed66a590e9722af0e2eb8534fbb20027e48938b3b053aa5733d2f5e7e68286d5070e9b86ad911eaf8610df35c159332fefe83b18de39aed770859b1b86fcbe3bce19e14a480006b5611d98fefb5ef8f9e7d9b3521d382e375036b30ce9329529b2c011a9828f0e2b17ca5992706f440e076dfd2cc141e3ac2070ff416bbac3b64c39586f4ad65cd9d90329115c4857bdad488267b16e0420ee3c614be0b688236204bfae1a628ca70f5f278a9bdf1a781425f19c92cc873413f1db021648e1ec950a809c0cc8e58b1f22e5896145002e3e7490ac94dea751ed1fdc1ffe4d0d3bbdc5e5a63fae6762e9cbb2702ad62c5bcfbcd0275df23410bd8c5ffe5f2a4f97fe98b8f8e8856588097f04c792af45db8b253cf2cf06d2e33103aebcb893caf345c8b90d99278ebcc5f38ee0b03b8c78703db3054118db82421df9b57a950e57b930b058970c77a8769a0b6fe11b9aa72fe68a80f45f001e554070a4a93e57feb6a10df68fe0839b67d6a49a9005ca84d753a761d2b653e6b4aa93628be0af0019c71d4ea2a6aa5777e8dbfaf8c685c261c318c49b5a63ca5db3b10544371c4e6f26936de4e7c90487472b4c645903751f6ef8f6894c587da5d8fbf2b5a28946601feadbc986dd8a6b8bb6f7a66af8fcd635d717bf51c3118b59fb93081cb23f90ea6113e67a1862810e7faa88bb8adf9a3420800c52969d6eb0dace5bf08091ec91855500f6b2b4a0944e62db48ea660bcabac290163fe8783ec1d8b3bbafecaa9a3d1e701cffff9ba6f6218a13a5bf0a15834876bc7556cafb4a9d139d6e95ef58fef0397b9e0233098e9418ed85560bd6690a19483e2af3b3b7125a7b2287e790e05af50b42a4fcd8d9a12166d257af7c3abd6b2c68308c824df3eb9ba69e2da4e2eb0555af20f85be582d761778f92c40cdad161e89d0d682916b21bb305e5418e015f5cb6c06ed8edf466f5470c3e38ac21b9868ca9af622cfa6cb16818bd23cf28720d534255bf1eb29c43e3c81b61493299b73acb33d06c14be46e43ec8d2925fc44cbfb40cdf4d45d2a10cd6b9e889f8fcb13c045be5c9e3dfc11f0a2a465839ad7a0a415c2c30c3af27670b126e782f2b9dcb46880f27a43625cf87455c5698edf8bf31039354d86ba908a5ca151a6c52188dd9ef4133e3fff4f8edb473146ca5c67ac9985720115cf853d7b185b12da78335876a854fcabf7f233e740857349be3a8a39649e6640f3d7c7ce7b1cde3a1a27a98cfd91b37edecee14c058f4c0552aae300133b1c6642b1bc06ddb77cf77774104f0b1efb892f9ce0ca69510229708223dfe994edde5b792d5d960f8dce8e02eb7d6844d2dc51d157d5d63f751a97c519f3858d8cf1aa125b43e5d23c9607f1986187d7d583a97bdd28e1887d3d49abac8e2191ffeca0609aff1877514b905e7a8e6a989560abda529a4dc48e26faed7b2fef60fc823b92d9705fce99baad49ab95dfb85f1dd3474b3c92231cfbeb9bed3d780a42fbcfb222dccc7ed8bf02ee691fbe48d754a9f6bc1677feef36dfe184f8c68919ab728bcde8fefcdb441cb24ad1b54449513b6f87dc91cc3b0ed00ff2123d12a54c913d3fd02178e160f5ab56aee87b622ad99362d7a37672f319197bfcf45e97a20091ff72e19c0242992bce3ab55517c8fe94df26d1b16ac8dbc764bd9c0d5322cfebc20f2c375705c1e02c6337c09b6d032cbafeb30acf05b398ae1239ec192d8a3f49f3f48f0c7c64d032b6b7c49e6fd3cb01e0b0ad634cc35c729d59bd224f81cb342a6f58e6eeea903ca71b992bf38147814839034aa0290dc9bc5f9edfd8a42106ef7fab25cee24aa01d0ab9ecec620474c054247502f788913bead3d2559eaf79547205dec18e8050c01bab45c3fa01e8bbd94ee39e7e4111e10aa0f088b83a0530d78e9af5e7f897c8b75a87094692a798731dda56d6db32cc6437f717930b823c93b0bb54fa4eda11f68ac1c8511d85c3ab85025f800cf6f1b30bd6b0698d32e7953ccc8df96deee47eab0d973b75f6ee1dda4d12ca65bf577d64243aa96fa4a23b0aab424ccabf9181f8fc796477e1bf518361a705f44c0997423dc4178b3e5177e01b61ee934153e72843f90e0cb038841461ee0a9dd1c4b6a5865f994e0ed4e8ef17f3ae6dd81618362553ec4c82e79e9cd6a28dcc08b01c12021edb0de622ec517e3188759c009cf39c99dce9f198c97ecc5c178e831ed2bc14c42f5a4448b346538e38d3af1c63c717fed3abcde5249777ca524d63c555357a55306b83cbcf161ba9c8cc40c9e7c8c56cf37c86063f7701728f744764c9ac4a02c73daab6f9d778334fc7436853c51696c92493f69713518508d814c3e4b9031abfbf6f00db522e534e27bc70cc6e898d0d38b4576b94f000f4f150c1b8d947092d6c10f4d019e23f4a7e7650eadd991041e3363cd35890b8e22d72be8b3b9c038b4012197e9ef68df121242ba4c08cb824dfb28174d3e243ff0034eff232bf05c5426bb9f953a854acda19e99f33dfe5638d54b6b16670c19db4dccea85bdfcfb4b8687f81ce873ed64d3e3e1f4c2ea0df642f578abf6cc4e4cb4a71b5bbc11a7aea5257b05ed844d4977c643ea7723625079a5878c830f172e87ec0c4331966e6d4c59ef9815ddd9bbcd561f71a8f70ae4fd8daf4467cdc710911c30d4f1948e7076761699664e7eeec0431925cbd78c6cd170f33e022dcf147093e871f4a50bb234d800a2f27b7cc29df3a2ef92d4879d4697c567a0a9defa65f31baf3a7bf8207e436394dbcfe2ae6b76f741a2cba489fc5bd48427bbf6a24c4fef78ae5b3ddf9b425c529753e4ef7a9545b65af10b964fb6a9e7913f22ecd3cab772bdbe28c05e73acfecf73b000cada683b9615447a54839771794c42fe7c5d9964e4bedea74d2f64f2bb4b343a9df2bf9ad1c9f34e938e4aadfc9ef13cd39ead8555b5c998938d545fa9b7aa168beeca7a2ea41cc883bd110bfbff34276251b3503037a9fba98d8a633187a9ad00340ea3bb84e5663ddbe85a0dd588410148b3b9ba87cd0c744804d645735f884314b88f5beee86f9d8d371c20e293a8ab3b2d236309dad668ae4174392efb181e9bd5c6cfc5d7b53e73a0c687f0f76044cad80b030b324e7146f3e1bc792e609146482ae796976a4c1d67dcf3c354e07e31668584a9cf38f483780f1e99da5fc0b501e16b2f8a04c1abfea1dc92b3a9094c7591fe0cb277b6984c7832c6a875dcdb96a7355ed51946ee848673bb6fa3dee32b2b57de8460b0323fea9d4ec49d96da198df3bea137496f05dd5a0e4d37a9216e95b3df9e37285d6de053ce093034b68c1374bec1a879e090cd6c72efd345e411bbe56a6573df724334d264b267cc6aa09130034746351e4a303157ad80aad83e2bec2ac64c9f4b2c76f9d5eb00376b0804ff123d3f79549239dce5bd88b5eacf3c46633faa89815b7adc3a9735d62879d189062c5bb51b6570db95bace9ff871b12f5b9038a675a61b2205ecd2ffdbcda62e6d0a5f9010ca25747b0a3ae540ccfbe3d4dc2a0ab13ea6736c9243062afb210814cab29dd2ce929ce27bc5c0bd812549edd07ea62454b935974d4488c453f721cf700c08a10e37255f545529b0265ed388524fb7f86a4f1a2f8b8d110ff520da45642c54d7aefdadf14987d1479a95b11a528197bb7e3bfb137af6351d4baa30438e4dc9ed9dcf425488c108f4f0c4cb137e66fc18fa55f190785776a0b355f903669d96b4683b39093a6d9c77fd3917f5092734b6f1a9a561c9dcb0c7b9291f0a178d4164a5beec174378015a49b933614b2e8861e1e148d637a4f97195446a8f61972b67801e1adcf79cad37f21001ba5b31bc0e44fcfebdfa32ae9b7a7dec4ec3b8e5092afc64fc1563fef7adf69ca5805569c888a558336647ef32e7d4cfdc9a2336172bcce3a5230d6d02e11c82e3eefb274bf6fc7ba79767086f1a34a50856e8a7fb4e8f20c205c6cfbcbd0290a27ebaa76c8192bb28732725852f4e0b5e685ea9ce22b10620ffce58c2a6db3936fa59b54473b58c3eb1c373e0aa790b7d9f9f41abc80e3bc62b583bd29aa81efc7c30586709e6b9f38ebd5e03dd83c35814a2bec905e1354fe364ab8009f9568e75dbe58222af10f794ffde0458fdaa7ebb97354c6f02d5e8d5a8be02c9273b507727dbd04975897f9c8e234b13a70e22465db48d364404bdd4aef5d54f6cc6cffe2cf70663c747c75284b14b1516377b5a8d67e29d3139d24a5382134a962341d43230c66f608e934d6b284e8d3988b5f43437e7d329c40cd405c44e9048e003ff73d4aca4c9fe4c053e888dd38fcfa3d2d6a88f0397595f32c6e18b88ab8663857f5c41e93ad3a1df6e27e6d0292e478dc6f8e10187ba2262fcc156affdeb39d3c600b578656eb6ff5faa86e15fbaa91cf57ad561a9d0eba6337cc7e3c366e9092c36457a57926da1bdeb3b122708f19991feea6c13b147a451df681a071fbf2c41de91f865d4049fe3dd29c98c8e4d2ce9dfd3b294c8017acde5aa643979784e1566d7221ff7acae71d8667813013e6ac617d63bbc77872e2956c418f1a10ca7593238299f24bdb9fbb5c8ebe205641e75d0e8b85b11b6dc57e0be057ba8ace9e612844bff75d973e7c632e57b2283e4c7a6086ea31fb037c8369653c8513aa0830d9cab47fce14ee966b520bd5286425e161f6cc7fce0da2b1351118a13c394775af0aaa58483b14493728ddfaaee96f49804869a26cdbdcd23baac7f9ff820faf588f73a8857b938639023feabbb2aae1953c4909a64497fa1209801a498a51074c95cf77579df848a31865fc394f30bf68dff472284cfe2f0b043fc52fb9f0e927636e7b5fbce922a16b96983bd2b95d51017779fd6f31d44e77b0cf6b5a8f9ed5986e0efa3e961a6e9c91ef590e52afdc2e942f57b957fe40ef421d77d04765bbd795a703e0530f2f34020ef643365f6212fcfd112a29be6f9ae54d87d71960386f2baf4b91703eca61f74000f9d8518d7cecb80b95dfd0818923a5f256d3bc881fdc335f0a112bb7fd9f160fbd91c1536dc7b12a4ce77101398a31755da91f9a2b9871cc55759800d0aab556560ac3051c6a1e969704a12ac2072bebf0f115d10a3f825a8fc4dc700f3d998ab311e4a2f38402c2350910d9125b9e5833d1103ab53638393f15f3cfe00f92ed621d9b77bd9c026233649ce924c6aaa6bbc174626f84a0524a3380e9e2cd9c0f6cf8fb8a38f76affff10afea89d9746a6febebf70ad7aaac1cacebd33aa2d419863e22d4eb0cb7bf98738c40354ae8e187fab46ca5a2bb540a6c30b0bc1ad0670ed8f112740883d9ddc20407cfc560b5c49a43812a0615b8bd8f1aa79c7d9677a6823f8b8cc8e46ba08c158a5b826ee46406e21c2884b54938cc9dae1e6abd0d933681cb72a922c1945f434891e9529485d8a0f2d4a245be1888c635ed0041e0571c112edf7379657bd02edb3604623060b37d9be7499ed24f40e710cd742688987c3a629db429d739b36b503ba4c234e6d7769bcf11c6c1e3e0a0160b81b3972c6364a95722e381144980d1df9040c9f9e198cde30cc19023179edfbb21130e8d93d54a147cf245bb01b56bc9651ba14330f3d57fb26d727df6cc4c9dc492feee249ec295c7a04d8b1576846b29ea80d17e6afefd4c005a18746c5cc8a436ef3aed4700ad55045c396b585472f724970be262c4259935da85bfc40d60d0a93a89bb5e7946d342913d86c3b81390b944021e7d4a280bbd3ec45434fbc6da17c3f6f76c34e3360d536cd97a1e8bdebbac9d7b17c3f2aee0a2c0db0fed3dbda8281d5fbc48c31dbf3788c9284d11ce5c1c89849e01395d540bc5b3d899c68157c44456a1e34a57a87c2009724f149993187c1d7867081384777b2a32da95939e6f3d189f1c9d7152b269bda393c04c2063c268d29d8a7a957e1fbd80417cb85e38767a853527a998b913aae8e0411e16fec0a8faf4fe136e278edaa595f3534586911143fbdc4a5c040067d5b2ecab2542ee80896dd144126c904a1766822a02d6ac22c299c9bd292ca3aede53db7094e2cba2821684d0b5f4ae581b3f9badc13e7233c6210ee0c251e86f62db001a90749bf9c4580316a29caa3cc195423bcf0b4cafc8c4af0af6771ffd7513b31dd89ef8c772485dfb41686f92cd3941df273a293bd6010509fcffe3cee99c26744d2382fa0a9740aabc6635e31dd48bd440a968746e5f97b67c3f41c7e35283e520f1e50c4560d917089f4abe120f85417f1c602e1e4af8d1db73d23d691e2b1f93a14b3e2df815b906253b64ddf31262e823e752196ba2071ea22a448f9f8addd05db9fa0153c6c274fc4a485bc0e5796dd1e1e5fb82a2cd3c88c6ccc194ebf0ea867c88db2da0443a731e23fceb8eb084084bdf1b9785f0ca607bdef3b3c28f78e55e28efbc95b8693348c877427269fd7b6321730ac393dc95ecc23c9cc37175399d2d8602e6556b97e426d6da4f1bafdf7eb280813e01f968e9cee7cd9dcc389831d44289c22c4bbc2e04429a506564971111e9285b3edd0e102b1dd6d20e65c73d442677cd32c8a422fdc2407d27ee92398966981b5617e49029e992c0daff96202e163e19f38c19b5da56de7f2b3e855ffc1dde515b9722ada399274ede13d5a6956cf7837749de6a322a86a6e8cbccc5ecdb3adfacbea8d455907b87d466f6a6c2fead2fdbae7eac3490dfe78e7315f26cbf575dff2eca2bb9e6c40cf1bd93e682f5a4127abb1e825f1bb166ca80df9616d22406d28ef5bb20a833feca0bd92c3dcf8530178f8acded12f9754eb570f236ff7aeedf620b491052f6d4d9d2c61fdde387034f8baf80fdd985d57bdad5ae393c2114983992fe4de81a37cce1b5b6e5d03d850def948f068b4d27fe6767131bb60129922facad0ecbdc8e7df91954e7c30907b7503a8b35fe220c6ecea5e0f524e6bacf445ad4fef7a31a6921d211ad16639cbc34bb2a2c2e28bf82d40db44875563767f7feee50f5c16b0cc79fb9015b66d648bffb3fa72f62b940fa6ad888e9dcbe9e455fc614682cbacbd91aaf5fb95e4d0d76117c631d9b4a15ad28f1130b05a7a853fe2e64d4f4e51248d1d09685422cdf4e110fafd8732f2f809589696d7351615257051a60e0f9cf3f240eaa87bcd3a5b8a258b1b19eb4b568dfbba5e14018b120b0f01f0e786b93497d0ef674d1f2d5e5dcc32955ee85473ccac9e13dfd3fbca84926d48c984e9f41e5179add983d1a70653c5eefcb1b12612ef302e610cd4a637e946f6223fb2603f49e6bccf10fc47abe43842fa0ca449008abab34c897e74b49cb6cba57048601199537ada51a6a458693fefc5b75d58dbd4988bbd492f500f7d00bdfd342d820a1471f23ee14815d56b5d7c6239f0f0f70f1517c7a8b36de07f6c62427b04e059f9dfb65d626bc0a6ed58807b00b2241e1da33e855640f456082637153d49321cc2e6eb85560d357f4c42b62e88a1b281194a211bd11f331360349549fc9a3b1f36d58f8876ab841f8bc233b85c6c94214509fc2fd5d98a763c1c62eba0a87980a02f63f401a36fde197e3dfd08f62cace04f0287f06ee830a9424d6166d1d07992bfcfd4f91e02daf2869e95697b430d569575f9158b6bbbe1046a08e40e19fb1bdc9a70e5ddb5f3012b2b199598c84de4c3ebe60207afa6f2f500a15e3950ad5435c89adc8b3a2634f56b1458f1498cc9b811c4dcac8abe738f954f45b0016d7300d62dc1f2bec0817a05589e78e5f0b7b3d9c73094ed3205ec6ddeeed09596464328730795d7eaf102138e70ded3ab4ecada677ea7f6be7eccfe1fa37e0712ab605c0802745d5c2f61bd4f720bc12c5ecf3c680968c59b8abd8bbddba0cb6f0c52cd7bc28f5ffc813cfaedaf7f2b259783be66244cf89f40fabd80168de87e408f939d42c1f9afcb4e638bd751029eba4ae6e07621b196310ecad95189e7c7053314e2f2b433451a1d70ea7589a283f25830d373beca7378c43c30b38e40ba92e4bc101085a1496fa63e0226eefda58109c33f90624fb40fa34db777abad28eab975994d30c86e9ebcde7ea6c3febb66d5620564d6d8a88a2162de3dfd07d69bd993eb5cb5b65fe3f6e1344848728df60be3baf1b7638cee8e02642ad3ea8294eb166df35a09703cd8e1ca7103b1c59d9293ba7a9548eac974c833e2256cc5fe8af0b333c9db1c1f2d351bc8f280e4ab9fe42fd48ba1a9ee60009cb68190100604c2fe1015426666bc3aaf26f8e8d5922ca44c26d81af0f2a703455e52acd24a3f9bd93b912bd80b9238c9798ae9aeaa50f38858aa40840a4ed65cf9bf75b7d0d56c07a68781cf93e75baa5b5053cb5d03944778d9dd74eeb372d0a88fdcfb211c3447628518a1b4cc15968006ed432d1341c259f8976d6168d95bb9e4bc6f03efd198ae5b19419d4f65b43f8d3a914a7bdd2d55edd316772a7e00df0438e0b7710fdc747c023d389ec8a8fd280c9ee35921ff155763b0e6267be4ff5b94a0981705cc1d6580addd78e711e88eb37aeea20afe2cdb4801e2be2db3c999450e44d5b361c08fb76ca4aa7cd27e1cc1b81e354cfb99c53e064bb50ce337174350a54fb55ba7752f17908c2d2859e82b054376d4bcf95f10dc8fbd5ef316f8e04430ee50ed489ca8070d24cc9ea689e1c8b9a5c0ecbc5024940e5ef6b83994151b7c333779b80ffbe5268cdf5c159369ae3e8bbd6251b1f939cf45028ab2997253e1c5394048cee1d0be4eef1e6e1a0083312b8c157484591898ff201b87eb7811463f96b8bf4d5cfc835960db71ee61482ef550460c7eefba06cd3d6f445358719a4fe9d9d4f0fd036069afe2eb15979d59c8d54077ab7fe0158de7408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Factorial, "2710", "0", "46ab3ae48966202d0fde097bfa88fadc512ae8afc0ea1d1d376a4109f10105e9e21f1e907151e85f926b8d82737b9030d572715fa32690be8dd16867f348b981683cda4be4f9e259977e69c16905ecee567d26742c1ba1cdfdd1274a067c3b39020f8d500f1199aa73884607e93fe423a99f3646585b76278922e3583c349cd3368417a0e630a075839ec290393d2f669d948980b23bb114fac5d62ac52e9883c9e3b8e0cd6bf0df411911f40d9f968f8691630a6033e9972c3090ed2c0ecb3a3d8ace0be058877cbb7e2bb8e9065af1d1eed955881cfa5ab0a4e155f84311203ba7489fdf5d08cac67c97920e676fd54a972b0297285841d9ee665dfff40bf3f162cc2a4ac74be168d996eadc9fe38b406af8f23cad528527097e4247c49d52aea83abfd77472110ad2dca4c977e104e041386a942d62e362e968b12bfc2549a5a3cefe5bb6b799e97d12f047aab8e219751f940689c3278e3e64583fbc3ad07d44745bf43feb42a8b7a860906dd98a5eae125fe7f3a013383b23331796878a2936e276a021f2fae759567bc8a261a4f1b8967ca3dea6d54ff6f97c97c791dcaeb6dbf4bde55bfaa1ceb679941675d1863a9a730e380099157bc0887a09e4b3d255dea2ce3fcbdaab5a783d0c60dceb7be6194d9ae7dcc515c4394cfa8b0fc765ddca6c64a5fe82883d6d2340f71ee3ca84f60339742b3ba82b5f05ecb540fd7e9a97c0a78e30f26307137efaa9aff7d462bc617e6ed6b9a9ec63728d4cd5b1a7f6fea10db84925e948df375d23ef6f7d912bf9c9af213874975b528b10fe2b791b39d1bf875d01a65b3c17d97ad2fd2eb5adc8a8a4b9516024e92a37ed14d6f087c5b99ac523e7f1157817eae88373990d19998b0a412e8add60b47f61ffcd2336bc3c137857c698be679024789ce95c19199b13a783f56a7e15ac38e63155a08337a9d4305cf94548f6788ba19af84e2c25578a346282e907c3380200a1acf5c43ef3b974da2a962acca9caeb1bf88e1c4d91d1f38164a360cb6f5fb48b8d18d9316023f1bfa0590c4a68a4fc49d4a17ac7d96dee097b3dc5c9e960636fc9a8c6220e8f3d6d0d7a79dd8861263a876b4b16b749c4ac6b4dc708d08f20acf42cbf98b7f4b9ece0f979d35f2c1dda29a8c313e23dddad30013aab39b415a058a2043350ddc2fe9ae3c66171fc1e8c54f59e53f734388a013b449ee0dd9b5eeeb432ecf6e60c14cde94916e0154a2baf84a3165a28ccbbceb5017504673bc32da530e90c8d074dc6f2071c36042d41f8decac8968a61445097cacf98fae342ecfaf7f567eb7ed8d11486c5c5290da57b6058d1799ce94330dae1e672954e134fde55d5629aed6f499ef81aa7c8dbac75ce7a391f23a0ea37cfc1509090e5d67b3989a6d01535e083b499bb51b2338f598ce2ad3f3fa614c2ca084442230989f8b464af87bf519287198f75949eacd7c245eb00f1fb2b055932fe4bc6eb0f7d6520030d93ee1feb0ee237a1114e6e60a49f3bf5fdff37c3a136ea5f9237d194efa6a7d551a64325d4708e784755cbeb0326b906df2161b5438ff1f91db3a60318be09b6c19ce0b8bc2f5a8d11f5dbe8f4a8c8ff47beb5cf58ebdaa03b69d29d6ff0c68115b753faf65deb98d2568867b18081532da2159c817d0def17c0edf7194300dc14f751694964043934a350eb0821a42f8a651e4b66fd78dca89c89d1f8d1c12f30a87f4307c58da161dd92214ec84fc4b2846f6e8265497ebd458c19832584fbf09437df477fde4dab76e8a5e45b78a23961a305d5351e0a9335cb4473d8b8b4e4b08094e93063792cc1364272cf4df8953cb07302dd1bcea4b8da10fedb4e201fd24fe4d51df15f9681fa9138784167981b3ec1f2d1ddf31e441cb7706b553053348e79670de2a3f361c84aca5ca4c582d19ddc3431961929f21ca5d5dbfbce6004da1e1f43d44273bc5e9f7ef49048bca2752a37c586aa46f75c3556e40eb317671ddac982869d64f56b2d43e249f75a9a6d1cbc653fd797b3cc455e0ed6a9b50a8c9520390b14938a545bf5345d6ad4e1866ad9e97d054508a6e427f008549813a94d979f5f23ba1f7978569f16a65fed6be7acbe5c98ade564e6aa6cc142fd7b66298c9d4c336521d324d5f077935cc1399d886cc10abdc65534915cd91cbc2dfb0306bf73d81f4ef0443e619e40b031ab33c9960553ea696def99741c478a0ca7fc5803e47bdf766bbf3013ea912fd3b0aa35d223ea524ed2ab1925719d95b9dd9091b328a2333f50ff66f3320fc45a88855f82cafdcfab6d5a63249080e513974003149b5ec731740ce5b0479092eedb086fc3d31aba7ab3abaad48605e37d5e82ad82f3fb34d97be49437a7349671b730ce1c8be8b4b7ae36323c240efbbf98ec3a90e2ef496e4e1e1b028db99bfa5a8933499205543522715230a86afda04348d7e8b7702d15dd2bd96d7c379c507a0413d4e9f5878b55fea0b08aaddc25b4f42a76d3ae788f6ea6daa6bb7c3bdffede9016fecb1c11759f061784127c7da411a7da6515a8fc32d60a9bc91bba213bc7c6de230ca5ff5eb23a759fd2876817c42ac700b938fca3d0cf04537858c05552d15a90b8097f9dabfab959360f0b28e3709610060f4df935282a025b0d61c503220b69582beaeeab70843c2c59585d8b8c705975064c26d6540afd294b4b4a05a9053d0917b0fcdbbe6b85f70bfc801758222402f44303d562a841ea945c7bd52c464942738dff502183b9968fdee9c14f72f1143f2ddb48c372aaa8301e89ec506ca67b412548375a53844742fb70fca23796e3ddaf1b0472cf2addb4ef0abe6691e00bc11b637e5e819895deb4bd02431785ee0286f544578371e9829993524d558886c6607986e7b9f113ec7068998a173bf8b045b0585d065aca7d20d71b238215c7dff981310e21c6ebb4753b34b506776967a0234c1efdf988f4028e015c6260be9a69d8330f71081a36447faf7ea5ed5f9fab1255e4ac5b935ff77a58aacc24ea6a3881b75137377df9734ad197b9e4db8dfc6e4bb56ef57b13c196e064b34e4e53c0dd3986a2238965b1fbae3d2cbdd5f25f6060f48867b89e848bbe0f58a103c496697c07e6eb15cd1aa946ed19b79b178345db2b04150a73d0adec11c73675a7aba51582b460d89bc5a32aaed5694540ec894a9a574588dc97fa84bbdc03183b7172dd380ffef0d87fa96d1048d475f8008d8ae72484a9bfd04f8863844365d014ff0acda7af8f8ad80bdf7289abbddb4c7f6aa33063c758638afe3c0c92f4502c32b41c5b0dd556590cc4823805ca76f6a98c675bedcbe801ad0d8eda46a842235096235d29d11b2528e5f135cee19fc318889d0aa32985fd15c2fb32df392767fc3c50f2f793432a07ffee46fd84e98cb1b3ea2cfc39feab6f285429be0378694a3100cc79e3736bf815df3941133f752bb1f004dc2219c303301a2a8cf82c082563d4a93c9ddb1f9dc81d48020c8c012e9b1428e2b1df6086c2652801ed0df764ec439939843af56d9b57aaf5b3d271114be8625cc012196e0a212e84731f510fbc65709c29ec95271a562d8a0b29792e304558ca06875505c13413a6408fefebc8af202e1749abf62fecd8c7aa9fd2645e8b9a5984c42a99fade37e44f25e5fc8bf9642e1a87e0307ef779cb8e9e78459563e96feb51826391b1904277fe8f817ad0b01d6f8c76658843d4465bdb034ab84497ec0bc0e10ed700c01c51283fabcb3337f977035f5678dea02687ab0e6bc300111f788db415d4fca2d74aa8e5a1fbf7173cd4b6ff754a87cfaafeab973ecc0234bdeee4f15f8209f029d9e92d9040650c7c974e033c1a27c94e13bc7dcf16c9968b12ff921eb40124abdc99bdf9790eb802aaf89dafff148ec9d85d7ec90130bacf688e47bb631b69bb7a26fba906867cf665df8e8b0f4f5fb5f52607f07843a02ec44c88adc563724cf225e831169d7f1aacdb203faccbc589c3ee39235b246758319185a16c729bbceec30eac34c5b6c14b20d9ee7253c43c8925b5b04580a50ac16ece44329c369bbef09138186d0f5d866c93445e8fea018618ddff8024fac522a6e2aca986eb7c2a4fc9a7a76694ff136124eeae14c33413457063f7187fb4a95aad2b901aa5a37b08eb3d08e6404f27e04ca044d6ea1880a06596015213ab62eaead531c16a25b470f10f5bff2f5ceae0dc455d8d0b16a320b3fd1c43e4d23b77a1538e44f085293aed9bf9ee0f09a3a9dab49fd884760ac4838d644fdcaae3d43e3dac8cfe109d061052030c21eea94fdfda541af578bcd7177df332e2d6a5c24930548679a9b7991049d33249fa188e5d48b7aadb2081453f9cdfd633789f5f8508d0584c2d99876c913ead946c9c7f927b541e26ed87c9aaecbb147245e09062678eb4feab8913fe570b3b59fda8aae679129cedada0e258d697ba4a44676dc457998321f2e99bb24957433f4de842ebdc3b29c00691ff56c0293a15dc05e72c01dbbd1e836fa990e83820f4ab1800e0864fc430229baf0593c9690b935dd19958c1ec1372479dd89e738f553a994003c0d716d0cf6ee13bf24f9ebbfac05226105f210e230f75a60c919c0cd358b08ff280b85a259a68d916b507f0ac6c11b4f13e3bf70a2e0be9502030e308a12f3e42065e0d119fa7ad365df0d40240e04449f3618a64750d7be318122d0a58d943dddd57d1b95da2e6c42d955d0589d35a5c912718d79fc98e451b51271163026139d57b534d2f847e766999e69e0b5724b7ccb665d10c3cd8fdd3f56ba2adf83ad11cb7debbb8f699e432fe89b97abb7dbdc7877616d2a6dcadf6b5a1918479bb0bacf2717aab4ed45a77be27ae4d07d934a0e805f43b961c70545aba66e40b463104168d693f87418905ceab9b9433455564d4cc6eadb867cdc3008fb5554fcb9f254947b6b6fe2dd03a499eac56bb20275bef9b4e680a5fd9664a61177ab24588bdb131134cd3cc919614459796f2a387f903cff1a7cd91d31ad12deabd1081f116891dabc228a2cd7c2684aaedb49aa19cff2a68af4b08bdccc7417d44233884d68e47d27986c381b8fa4346906363e21e0e403e35f17b109b085b45c8ce32ca30f20d31c71050304b5be00617fdfce24d273a9b88e37fa9d2a30705387747fbf1e2ad21130ea10c652ec3a08b9414562b3b6aab2e2255e86d7125d063517441df00e4c2d44528ef32fca26c30a3743488691ee3a4ea4d3ff747c62a43d78912a13bc778943b31d154a4167b6b1cd0a826633ed39496d3d773b0c6869acd6384c4f31c531288ff5a46656bb33ea9122b269c4fcc9ca7b8cea33025f62703fe5cfe21a7f2c1e7346392d06e8562e8d119192a73f20fa7b458f30900f277c49ec0b0ffa82e158c5600a655b2863a74d24a245ac7c1be0bf0e3cc9ee15eef5ff6e4202fb837005cce72d678dc38d41cd04f5224ca9b7e15d640e2ddde831da01f70f79c38f865cfd1d0ec1fe9dba06085ef99f55571fd236a4d5a4021186a2d7c493d97ff957e2d006572f31932f324a4e49dbf63e306dcc8ac43aec139d505f3e0f815b9ef2be2340d3aad5e80ad1881fd1d28237cd2f40cc92106e607cfca4176543bd4bd5108e47bdf33383dc72f3c18e59fe5e6fa6a5d364a3d882b77deb70c8889fc9ae9f6c84bb6ecb1c2ee936c84b0785ac45d301b30cf5d4c438571a8d64849bbd99d934cf5b1561dc2bea6c2656eb3787f87ef872eaa59379faf661cffeb3988ea725eba5ad2433e43381eb052b20a1014a26aaf45d471722a632da82ce5f5063217353b6bb9b07aa657abf30f1557f2de74cc2916f4c44941942473afe31946d7f58999343e3a2661f2f22533b2deb5a1a04abd257c01038575dc79b29b7b7b8f265b0691fcb9bcbe1313206e0c95d22258d8f18bc01c9aa8c7f08cf3555ddeb3c06b30b9794d80a85518a84fe1a2d2845d66f0aec9c148dbcc2cf687b40e1abbb5d3edff42f4821fe73440f5412451c3f191ec8aea7953317cb4e0820322e5fc395abc83be3e85fae54ec77b1c7dc6278918c3bef9f9ebc4a46e1c5f68922044b50942eb00d981253a2eee3821954d534bb60dff4c7dfc6ea796ef28371db88303b23ae012eb85bd1fde4361782181cc57b18f95e841d87f31afed1ab5fd8562dfa2ddd54e0fd7344eb6120f767821decf414c8cf02293bd351d4f7b297a3b58c57bd8fb73705922bce5dd8d4c32fac0f06791c76d8a85e08d19bf3739cc6c62f77431b6f264d98c2a74a87f9c9519612ca28cedf14eabde3732b9fcb54befe49ded72691a9fe75e504f856441f7e55d4ff1f56d36774106acd0e7a7203704e4fe5ff1fb0b61ab765090001d92692884a41b3ec9d416f050e09ae9c277308ed872ad7fd6d13ac276c9c80ec92ca00fbeb3b8cbcb276224740bd1a49b456b6620eda9afd5f3c0d107377f5ad0dc2159796eb36480cf296bc6915c53d2d7dfd763e0ba0d24123e4093c7d5575c916cbb053356dd91229a378338d467e3f52a9a79ecf3aca1d0234cf654278e9e5add18651c08d6671ce942e16ff782db772f4f2660c583fd6409de2aefd2bacf1a9d69a5ccd45d747fd28159d26a09c017f3c5c17eb25d4b1d406eb8e57f63178fdadd5d5459cc27b7c79758fd9e0dacfa35b7bcdc1c131faeaef6e7a4773551ccdfdae6afa29eb62b2d5c13a004ab5332dd8aadd891a8ff858044caeda2010f08350391d65a5af5804d8686b233699fa59f5a8f8150d72a099cee5fba38fc1741c00867efad3676c2b10e86bc781b0adedb847d80704688787b67b91c17bd80a48b44634fbdbb448ad71592b525be28914fbf171ea3b21cc1c4dc9480f44c4c130625a781856c42825ccc186c689a2b0244c17f71d1173ebe9fcfe0b3cd02e567476294eaf606d85878a8e79ad6c784718528131e8c7407f6139cc413a7e8af3ade39e0d9b21051d4e9d9c96da56b6c19e3a9cb183b8d4276aba1e288072bddfd2cdfcdbfcc2d764c10e8eb246a5198aa32589b12ecfaabf19903976935437d546aa5948c1c99afb48c9fd137e325541a2388fdfe10eeef0326b6ff9df84f6ceaf0eeef036f7ac5b5937c4bccdcc836e63520b9db1d71e741c3574bda69e75455d3aae9a28166f4cf7aec8e2cbd39cee6cb8f83c7a4bac99ae51728da436fa3560d102a7cf77d56bb3fa361945d7760bcdb35bef5708e26708f847be6e1fd34aef155ba46eb8e3a99c759e11e03b4aef8be536affdfba72608a39cc825a5732ce170acfa863e801c41aaf911a1edb0ca460a0f609db69b797e669e45e3a7513349e8450bda1d725b2b7cd2cf97bb4dbc2691a2ab4ffeb8ff7a9b9b42d9d3d1f4b40f05c02979357029c93c706153ca19bfa5f2097ea71d695a08566e71802f6212a11b9a8273892494a6b4ba6562b1636187f019eadc23955eb84ac47d0832707a81a1cb73105cc592dd665d4877f93446849cf350a2f049c437160ef4fb3afac228c905e67dbd69c737de4082cef3af1508177ec57e6127526d19bc6231517f2a17d291309709406329b96f4fe13e3c8af3f299c1868063a6608d26315151a3c1c922fb4cc41641bd4935171c3fe5d08abe9344ad126e7eec9a7e13faa0283a6dde54be2fc6c7917ec029fafbf1e35e62563e6d02f6cd40cd4e207697ab39b915e2954440dcda72836b83340fea34b25791a22f5d92a89c5e144b8979be83ed9855e744c34286a8ca5cccfad486c2342e6cb5004061d7583097ddd88a0546f3afc76e585a556ce38d2c5226e35553e8521e60f68e09f946eea2c2ddddd3332e70bce5b7c363a725df279277b240dae99f045ecc96d96f34a2ea31c5724ba3515e5d3e12c5d1145a4b2a0b2d5c5267b9a0505acc2907d8f2053c579311410430695b863147fd89c148b1e6e874049e99dff17ffee22dc9d5ecae98f517165d57e84777fed0897346b2e2321749ecdae78ab111555796c0ec5fba8f1dca54176bc4e3caef6e1b8fe677f85ddea2763ddce431db9cff719515325d9b14dfe6bbd7dd58a39263a2583d1b96203e4a86b16af5be494c4557f88490150fe2863ae12df9366674b8e55ca91e37771a90587ebcfdcf518108501d241ce8af6cf2343f06ebe88692480fb24e8690886c6ebb9518578f6971c558f887b3860d58468d6a54c0d59b1a913a8714358c779bc9493cd66d814a431675c7fd3126fddcc2ed2bbd99c5a95555525b2e4aa7b147173e5325a6ac23788d71341c87c33dc14598896ee067c9e4f26b9e56d9a43d30599b1f0ae6d670f42f1e8246102e3ac3e66ee24ebed90700abae2003214fd3de924bb2cb0b5e5988cd91a784b425781463910e68ae15b9466d54b5458d9ce76216feac1ad86ee53a1d52896b4bb1f0457fc9fef894dfd6abdb671fcaf5f2d9085ace8909e9dd5445a0f59ef0cba872cfc0941f9a71d4ec9fb64b8cc626a4290d2d031e008012b5d6a25e0d5d4de574230c585859eacb962c9be39978c2ee7359b2b59ec08565f7cb398b5363327bfd0d78b8865fbca3898a5d1d52a4a6ee34448c452aea62d7da63d80f93ad6e45c3bfa928880e25c0689c50d9a58a1bed660aa59dccb8789606339efa899c6242fb69b5f27f9fd9d1c4d2923b3d6e99d40da26f6f0477ca514b41eb413633d5afa23b1fd20845fba729c14cf32b3dba9a08dfcea29ad11eec4a87f413b57729c398dd04b39c854b6140f4ac71602bce1f66ac270e323a23bd6e3c8555583d2e5609ca6a597ddfd9672c7fe843cd6b43734b895368306bae1951c94d8d9b811a4c34ef5e4663e3acf1723f82ecb4361473e960f8730a0b44df4f78b89c938e83a9b99914eca4fc89cc345d53366d040920dd3649a867e0503c586aa33f7751196621c62475c97dfcdbf66ed18a26937391f22c183a9046ae89330102ec8bd4d44b2c1f866184800acf6ec936d712469830cfd0e715fcb6047575c0fef744443f960005b8cf76d72eeb754f91798a4587aebd4632d4baef76b0765ca0467eb0a095a8a6584d09f467209cfc2d26fac23fd864f38e65babf829ade897b1b851da66c2a9911c2bd8854c4e986021d0cdb18e82c245d683b512579c872f169da25ce018fd782b640c71ab5879c563a7f94817f3dd4942705a5d7902b78d84ab1eb8c6f32999ae93693f93605d93128f0d50b23515caeb6779eb5e1bf2206c3a7b2ac1fb571d97a736cfa4c5ab51ff0103e858edeedc02d437dd7df13eab9ca65f18b5fb8db7b872e88bb33a5713f484943efce65254e148c1a73c07453d26969c4c57c94b949933458f33739a3d4900a5e0a04811c283fe95347f6a31635fcc6dc8d7af5f411f36849790526efb109928e62a6cc9f06322c656b43bf5cc5717ee8f642ef05093e965d3902ffdf6083b4202972a9479642bfe0ee385cfc41fe807061392b5965098702edf8b9c2c7f304fb98c2c72c655fe362ae9c4aaac92ee5ad6d2a801fa28e962bc5051ad8a7e96df5c9183dc90693a1a209a5c92b3cc1158c28e1050a2ebd4141a103292654f5966b3f5c2996a7d1a422687fa374c267db1a25a50d19c8e490eb4da70b935df48be33ff6b9246c6021eb060135a32a40c2bdc6ad52da78bc628a4bb4d4de626946b098dc4399d6c6ad26e15e15e1995f6a178d2806bf82df301d4592371e17d46ed0283ca752bf342ccd3efdf0addd78fdf6ccb25e78114ce0bb28fe4686322eb2437202b330e59b17c34e39c02d4dbbf78f1be15511406b52dacba7b6482dd68809ee6f44ed1c5718bd0607fd46c828dc24707e6d103058dbb0e6d86012430cfd4a6d8fd579186cc46e51fd551adf7f02c4fa1316eaa8a793e33c6ecb5761fa6c1e15da8fdee5c4ccc90fc0c305df18033b169dd4fbdabac0786ae1b088066c269c2137b4f189750ee1c7c84064b4aaff510a087e69d88c9c39e18ff75077c8971583b9cd81aaed88bfe7386b894e00db13a9413c6bcd769919a6d16a41de83973b49fe2fadebc6cd1848327c6312f9f88900c988030d153b3b9c6214a5e9e2d9700c844f6ea72f0eee53b4e3de6b1e9078a9cf29c503fe8d8f2fd9ba85793cb16fe33b5695202c397ec0fee7bac0cfd1d303ce6f8d424cb6082e54d81bb0f8ff0dd660eced0f8e0a5a09e5400fb5b1fc4d309fa9f05b63e5ebf7ff1f5061f3d5c3514fee1254794a29dab5112a9477bda6ff75e86c61216ab6d16ac2ea32b8042115b3249f8ca49ce0541e13c60ee7356cf60a6a70722b43b33073c656e27223be8e71e8725b6912ad5eb4cb9153c424828224d2a91ed8a6be78c2029465e3df9810451954768807ab4ffba41c5e4cc6257ccb862c0ab85369db0f3545eb681757eb88b6f9829283c9f95946c4a35d56f66a9e85d12c66f6d0049e5aa8adcbf66512a83779a14a6ab64ad18d39d158253e1e6214c68388924adc08bc2e09721136906e77c60f5ad675f466385f76c0e028587835279cd8eb5272a5ca98077809c1fd023aad238c9a3b452f1a73a677582f8c9d1143db75f879b1d3e9d007aadac05f7b64b5ca98d0cb0156b75b8e2bc30b58397584f0501a62429a654e58353af8315005b50192a54aa7f84fd233e09cb33322040c22fa31b97f1926661959cb7046aa905cc2e783ca7333b5dd1ebb2e48036e11a66327d154f8a8686d0b23863bac33e4cb2d8098423a440b17259824c4b24c04a27b9326afd94b718110072de3fa95a646aa051cb050829fae50f0cd3f9c00329a7f170f555a4e8b36640d01f6d443fe257b553af510928cd3ed5e5b61444f64a65800a322a3baecf41ac3ac8ee3e56dfcce208cf1cfa3c00cbc935f2e04c746c3212767b99da2333b949d621387524c6900dfb3c81a321f7bf364747484eed0492fa53ada6d83b5f808c8ef28ec1a86ab3d48ccfa27c65bd5c78bb61a2ba2c009911813b37464dbb780dff4bc70bf84497201ff9270b5360fe755954cccb6b3646b6d6c93d1f0abc524beef628c095ece27e48ec3f5bd948f1fdbc5dcded5879a34ae862279c5fb34f15ab3bc66d9d0c24a9b4ecebc1fc99d916ec64a153bfe0d97067af1e991d012a54c6ba830c7ebb95838f9eb4c866aafc7a816047c1729aab34a9a85fa7fc9952b676c85e468287810de1cb65fe554287580d9bb6e7b6c4b108113013ce0f21fafb4731601ee25b027bed5ba4ea9cd284cd5348fffa47fbc36e3ac17fa0ba2ace9740ef0bb9bbf687d151e2ef3bf8aa86b4888abfd0cb6b797a4788e11488f20c1d7a767e6d4c4b2f351bfd749ff85ab2f6d5eb913a925520bc7a81ff78d5a7f6397c78aa4fdf9d677429ae3ab7444680c5e7e928d36ee2cd639948b74b053149ae0f89f884adf95b2581cad66071b988af45beb92c556c8bf870b6b0c5f744ba31b4e4c5faac45b9aaf08beb8dda565b653ea6038d547f9e277492ce0596063234b1e0ba98a1f0cda3e5a450135b0d454918c8649d049965d79b17c246daa0eed1bb7f99726448f4c16692c9a3dd8aea1d55b34b796ef23d29cc004c4950dc79e2a038a360d78b1db2a314555d7b74f34d1a5c4096dc8283abb9a75430abc9113c3445c47c43013ba67625c2f857714b8c825cea5dcbd9b5ce33c73edcfd62d13b705eff0d51e653c00434e47e1c28da114033f0bbe03ffbc81f9db41a9513299342c3d2734c445ca43e15800c0e7b61ed765c3c94ed30ea94cf95f14ab58120052d7002717eccb528731857d73d4efac2a80bb2289b8b1020290ca0505b54f9e8aa6cffc10b52fc40548b279f7c187d520e17e0e9155afc33df4ffe034faa1a61abc6a6748c6f5f54da1e9ba3433ae470849793d4f2721ae0a8646042a4469fbeb22e801446d66fb878ec9cab4f3806d43b472331db1c6681ac64b3f1a06e501c9e9927c06ea064e7e8000d6fe954dca772ef9cba71c7319a15c7d8df920867527fe6686b733c59e72500f139cc82e52799018f7e8cb6f37b64ab87e66863ff12dc3bd3e00a3442e69c7d3f176e0a1d51fe697d221c8a499e0185fd2d342110da11e430605c6dab0239ed0ad399281e9864d8acff1f1f80d44d36cb3a7ff11b7d9d0564c8c3c0cffc7f2bbd036e3ee6316f7c063bbf8b90c8dd49dceafc6b06a4911ef8ac2be209d245d5288e80ad9b04532ba47ae888239b07a4ea1b39812c4304ca22e0cd13638022ccb02923b8c787169df3d54d177b81d87aacd518f118e9bdab589abe93113f03c31a5fd1c237258523e98e62d33aafbaee238b9fc6118d198a977169bb3894b8b9051283549f968eb983c440e0ac26e62e6aa4872e7ebdac7c6eef7440e75f94a857bea674419cc76f90a9f95a80df90a0ac14d03bddda89b052131a1bd8d29e2ef09424116c88db97db1c929a730c6ed0701130020389f558ba3328673f1f30e968bc36aa08ba10e82c441851d7a595f7c531094f072a61b70e84d4b51fc5354c3a6219c810982366481e4c4212047d09aae0aec1e0a22c3e826873c96bb54da8525e58cfdb465af9525eb90ca9091641b0dd30bfcc32ac2667a951861a0a48c974a8829fdb2b100c07f0aa9afd7b512b7604f4de407f7d0d9c1465ace055885a97eb9e9beaee9a5dae4acbe3c290098995fea4685bbb54a0d29ea15dbda44ae6b305994d121125cfb2cd33e2f2c99b90d24811c363f37b811b26c5f85ab1455a4591ce649d5186a775573fa2d466a4f59a28bc265bd7415e5a06c6473c6b5b9db901f7a7faffcf64ba002a9d3634439f5b710f674c3191a26e344ecfb8439135fe7d5f9da121e9d141ffee2ba498647a6c4dfe330cf9e16389149bcc478865dded2f5225ee2ac8eee78afce5b62f36d926e0d17d0b47a2a36235559b5e15625fd40284305878c4ea25e18ceb27bfbf24857fe13f29a996a4cbf6b384c06d88501f452cfbf3d807f96d08bbec387f8ddab442e80741492293915555ea52c44dc84b698b496bd80e977a8c69aad2d045c2f83668dc98d989e305c446a6e512037755d87312860fbfd48ee1acfc496320a749e3253c1629432ad905b7eb92aa6b41476ae60edd178cc56a7b63864642d38e3311e5d249ea23d1c3bd1743b02fccc34aa488495c5b2caf1408c42b7bbbf5e68dab9f74dce918a9e224338a1b403f07c26a1a1a5d43a30e387f7b3f68ccaf51fa2d52ec919c75419dd647ed947f7a76f5231e6764b05ae0477e50bab26c070aa2788ae5b2078ccd520a2b63c5e72374aab3793912e1ea906c472d831f4bdf71dee8fa2b545809264c101d62951e5728dc39b2d1e0dfa803b1dbb8a478786f35c825c6aa52c67ef7516c5278e1d43080ea59d77f4851a94d50b31b2160e95b60a6d8c53936202bbf580d48b1b1497244c9549fa0b5985b4809d8a50b0ebb314482b46f0f3de81d6be7ebb8aacc6e46d78a4a146f2ba79dead8757bc383e09bca5924709f3f834b20786a215fac852b20d6120bcf731852c2a459116689d5c1a863396adb2ccc368848954c3206bf2615cac62fcd95d27405f32eb6042a98e0ee87a1704284dbbc173b51f96b4264740fb1561f112893a5fc3477a161b634ceb8f4385c96d0839b4fad22c1dbdaeaad3405afbb13a4c6b63208f3018492f1f65c33922a824258998fe4ac671bc33676fa26bc9335027df743993f62702ae2943a2e5887e64802f8c1e425b9945c98c99843a8343cf705866fdccff6a42011df33acbe61d200598951d921f8c5377075876163372d558ff7e26e0c9c758fd62a7edb0743b55b864ce66ae124883eedeb54bf87dca99fe685e05f5cc18793044e5fbdc87ccbb6bccd9f3f6933b0898250704eacbd5bfbb2100b23bfec478741e9d345fa54b568d727854ed920e16e757a47c7c36816582d4b0b69eb28574eb167360988af8c549ae17b533368f035a37864c73664c94027949f4386228ffdfc03fd3775eb90249a10df5651795e63f2b934b109ffb48f8b4465e8f8b89bee2fd3db94c19c4d269f8dc8cf60acd897add04dc7e14e8eb4d8588795eb28787fd40681c4d26afb49116a713b7680d2c45825b58747e8ffbb7dd9456ad9721a17d13a84022c227b0cec4ad9bb15b5b30f786e0b0ffdef7babd2135e4791fa30df1c8504f9db232d9267396b82fd658558523002814f4fbe14eaf4d502b5167b2f1d5c7e0cd7b43938ee3a8de668bb7261c07140e6e300f9a7e782ad0822a5400132fdcb037d679527d00ddc416a699bfca0d1e1e75e458807a3d95ca7eaba0d6606791a9446806a052dfca2c16fb504296c52cdd30bbc376d2943ca3f30564a37923a4d66316b3ca97a34e7e898cc839f764b8bfa2a977f7d0e516c4e3d1e010f84c695d5ad3faa1bfe209a8067060e7d3f2df20abd6ca9d9bd945c26b6b19ceab7012634697937dfd47e6e0ed5d031773a1a2b48b12f020f5e529bea36a085f4c5174bfb2020d012573231cd849854180954896f021759a944a4138c53340a508e7f4bfe5db2fda6f8d7770df4a77e58358a646b33ae0a2567492a356c2d85f32d1397430170e05ed1f94534bfac858387d1dd489cdfe875854f9190e1f1d265461cbe9c489c02e2729509898abde3e9e33644fb828f1a577c357042dbccd3b7dfebf4ff5850c449f7580002e864fd5dbff42142485b52a77273672e5970eef51485080d09d7b8f18f53000e63b322463390030e31813ea611fc988f5d9ff17ef56c87834f7743b456ef634fa9ec9961dad80506bde195a7ff8e45b2bc97732487dfd8a2bcf7c0efb7c9d3a2f903a29ad0c25b4135a94efdba9cbd6db56d12371d2bdcd0798c76e51522a630e1bea9f0c6643d3d171dbb0136e2d142c870d41b59e588832e20db2cd33fe94870a1e06727122a8917676d7e9b9604351a6d5929c1228b87fbb6e702d1df7b70a0a106d142a686985ccb88cf7724a059967c60c7821c67095d99bb20620b83c44d85647e5ee87f440193ff2712d7a4f2fdd7167f036ed09496bcd75a5d80fad2420a1556f1b222548bbf623bcb248ebf0089b025b4e43e4cf6fa04adda2448b3c5f037107cdbb64b7a779e0eda16ff3e0752a6790c68b0662a4c2368a994aae2856988444e5fb641983f38764a4375c1e5f2d71472462b390a91815cbb361dd7a09e91ddefa283914c3db7a7b2d4d39722d6c8e7c0df25c0681ecdca053c7049f5513eec948aecbcb750f710b2f60363d8bdcd5ab89021a35621e8109a3a07ebc648add14475091a9e18730573e5b84f0696198cd4a331fb8898dca94ae293dd9dbcdd46fb4f83ddc9898c626f1384578d2026ad7aff3ec5291f502224aa9037a8d12f49db519d3ce2d08b844e824e2f49a6db73d8b926760c2197f28f8914e3435e9418173782a9c549299192609d7dd399ae5ccc0238defbc8479799fb0d2334e3aceba774599a5b305cea49d493da522cba400f7c0f360048718e2132c8de8a7d9af1d4e8bf320a4a1137f4b35743a676db799cff44d42f9f01f1f509580ad4f6e2e4e74d11480da66537773b0316a8161420a74b92d3c484b9aac6c8f627f555515a44e5a173d8d1578f4a4bd563f856162923bf16b2e30297b99e0a43b03f20be7cf3b042fd449cef279f31c0f17fb002ec9211d47dd4e3df4fa3920716f4f17141d0a7085ea652477eda5efe7f4079f4cd71e8c691f60b9c9aa9b0e5fb6d5367642c4c3bfaf6edaeb4bbc79294a4c9875b1ab6702f2b98e328be732a7709714ea30fc1914b80b220671e0d272b88d960793ba3c4bf59b83e00c67b19a9a648955f4a4391ab8f9f69dc425e1f2505d499b2e2452b15f12f8c2217e87e9bded9ec58d25490cf2298b347b64e8d937651b3197e17f82e867a9594c88df9d7cfc861cf3a1a5c7c263cf65765dd836061949077eb1cea0251a7ad46628ca46069f5438ec75278acb3d30fa0db064a8f4283477fae64863162979b5718de0585cb21bd0ec6cc8f6fd0dab37318b648df49f8f67579cdebea18d4a8aeb9050cbf0ddc5eb16ede21c9ed2608a1e5b4accefeeba463c5b198ac0ff49229b7eb039846473155f1005645894a39f6e1ab51b2e3b87f586d8d3c38ff395525a817c8ad8d59e066d66706ff5b6f09e273c9a598dab6032746819f0b9c6cb76b69d75c2a03f4c8745ebd5490898a0483f950b047384e2310ea72b899e9a3c5b00345c16721f64882187dac78dad0ca1705b0b423075847ef2a477e91323c4a6f0d33f359b8ffd4ffa2f56d1f33e8cdb84cf2feafe4c0d3fce79ec54b9e9dd7356a0faf12fa78e75006c10122fb44d3ed19d47c3051b8c4c445c623a78bd4edc30b378a8be503098414284c808818df9b1a5553ed49acf0302878dfc6a876cdee06af197cb766532b2554d5d2a78472f4a6b78490809d3ee9788e07efdbda1a6c37f3441f9e8c0da66cbaed367714e40649ab7ad376b0798a0cec386e84342f5a8a730e1472545eb8f4b58cb5b24eab5c9eff1ed72a9645a9adab96e1d4300dbacb0a2e3c95a0dfa7d301aca2c8bfb1f64ef2b65b28d6303f253da5edb3f789e0e759dce59332197e7c05416b6342c0502b4ff731b716a73d8e95d1fe0c8c4e13e57ed31c32f8b00ee79843c40337d8b03a1d7caa3ed25b35f7e1a50e8ffb7da2ef42f7923eeba5d085f422b490eb3ebd29751b9e3864e01ccec9a0f78b5383777d7abe50a79a788f93219cd9546b5b528b6da673175fba0c8f497bba25eed660743ad0cc76db8c4c587fcfd2282bb596a3dcddcd71a3597dc8109d946e5a275e69a595905c89457c57e18914c289fc71443e7aa69b7731a27fb51ce9ea73ea37143bec5416f5c2f004912ab5de9856970bc4160c56691b7a6ce9ba97a9723ed9e45daa2f2adf39bd3bc0ffb9bc890147a39aa982a5cdc496e34389cd5f57df6c397c28474dcf5b55b7a5a52e504efd312b6e5e93fa1dfe34cfa443814d2a93b9494e64e6f9b5ba984a32823d8b7a6d24e191e29cd7ce8b96c58ca7de52dc51083f898c7b00b4b8a791280c3d1c226520722e4287844c0d629632a5b1d8ed722d952ddc117887b5c96495124cf6cc26bddc282b7de876c1d0aa9046a7d447b9943ab068bc52ac2f39f6d80fd837e0d0bc7efd5fac76c0d235c0b4b5bcac3eb69ee1ceea2fa3e9ca45cbc30871d64c80f664f008c9a7808247343e9f88f44e135079166e7085bd2bb6b06bda132bd2f319363a9961984de3062d62c36792d4ab3ff170bcfa5fdb101cf5d65d62956c9ac0e80c8a62c3143bde74b271c042b347a6fdd64ee02bc90f3925afc993689cc40acaebc45c8784a148af4a4c18231d3d8202398e04f38f19fe10e836a706880c10b82b8a84920f1de969fcd2b24b2aa25c8c8fad01e8465e64c37a657e77b8cca9cfb49e8d8ee3d51df258a514d1364aeea79d5061430ff93a08c6ee102bed3b661865bc159edfb9d7d6bea574666b922c702111fc27a02d710fd9860e9e8b27f8db180fbb6e175e5e60fa273246884ec0591a353abac75eb28724244583d58cf8f1608a18c1afdf29b3eda92254e3fe22c726191f174e1a2c526de6d1b92299a41bb495b29c0f4e81eccaf87034a6a78c57e8e033fc994da026da623695ae39ad73e7e1bc247842fa6d06bcb2dbbaf11764368a041d338ac30553748dad4c62cbbfc6c032c064c2782d27bcdb44fa2e86b805bae549ef2a6bf8c68d6f2b3267d9b77f1b81d24b6ebee42cb35ff5f639ee4dc138d053b00f4ae71cfc998512dce05f03317996a6d4a787fcd619a52bdfff1446c0d8f96d7021f589a82c2860de4aeea62c661276dedaaace58538d278de51a8677a44a24b4d7c5487f80d3413f841b3d02b2f7c590ce4fe84c783404d6a587385f9a0f7cd57918db136766c4ee248b0006bbe94bc9d7f9c10b3df317e1a5e45f101a367d8543115388aef3efac2f49953df5b58b64746257cb3e8db2f8408f9e695e340dbc90458089c87b7a71635b1ab94cf061f3f540128a0b7bf0a1d0afa8a57030c3c41ce6db5902fa6cf4d16965f942c418ef4558c4ef98051420d3c8580699f3679770797cfc6ad7c2a17636c5ec201cf483aaa1196e42ff90d0f8516cee152a7b50fc19afb80ed0b03973bebb7ef3bc4d0b75613b31d60aa821e3be410ae1bb5329b5f98006aa6cb7d7e9856492c1d106e05989083f24471d480a09b0472fcc3a20d99865f53f1d56edaa4c2c38cfd457ad561ee229baadb3221cd27232909043eecb5698d4cba6695191d6af7918acfb929fbc14577bef688ab404df00c15b1965fd930277c2b959ec1c747456da64e6ba719d9b426c654142fe008dc7c86729a0e68189ca6548eaa29f9cfcb189ad0911da879b7a0995b3836a1b5778b185ed518ffe59f173530af0fd7a2522cf939a9b97e8b03a5376c1099d373b99fe8f9082c622cbcab33e5eec492558265857418b7a08f505ffebf77a5f4ea71621eb216b2c49ba85d9daaae490ba0181db4338d8d3753251395a683ea18fa2fc81441c3edd4c289c4a009b5404b41bd97ddbdf619da7a012495754cdcf5089c708fb8125e9a5fb306d9d192cf7ca80a1d0b373862df6f514f900de3259292d68c2c31311bec941fd933ba6803a1c258a453c5528d66e7300585abe75ecd65f33ec1c67118e03351b2d2de692d80edd4780bba8f9c477d4b2d1dc75dcadd5a21ffc40bd00f1cb424654f492f6cfc5b1c75dd83e3a5964243526e4acfd505f23a31ca8dd7e3605efb3ec4c8831535bbbccc8e3ceca3ca848ffd163fa25010cb787d4bcbae58cf904514b06329667d21ef42419fb49e009cb6574bb850540e1f848010134842cd09f6717dc4ece7b9d4ca09c1f9ad40ea3f212677e5f9b10e28ff870b597753426cd0743cacbe3e6e28718bf20f31d79ff1f08e374b19eaeae30a1ae97324f3efdbf550621fdc915b9ec409a30983bfef2b3e3b86b38d39a985b2b4bd98b19758760f80d74b0eae01ba8381ae29a8f8fa5dbd4ce3b16b56f6bc72000edeeae8c5d863b87b88f532deb8a2302625d05c6abc1b970da583253dd662669f21fcb77463cc6c9f30f85c3e73fe612885f791882f11abca9c6796fe1d39478cc83bdce0268e63f748cf34db669536b0d9e8fe93e2b5b869abe893d2f3c7491a3ee098ece52145b244474291e3a1d0c50bf2cd7b722f98e6fecfda6c0f4f7557996cd71ae3a6634aec3b221393ea234ba007a76ae86df800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Gcd, "17", "19", "1", .Okay}, + {.Gcd, "7d", "19", "19", .Okay}, + {.Gcd, "7d", "0", "7d", .Okay}, + {.Gcd, "0", "0", "0", .Okay}, + {.Gcd, "0", "7d", "7d", .Okay}, + {.Lcm, "17", "19", "23f", .Okay}, + {.Lcm, "7d", "19", "7d", .Okay}, + {.Lcm, "7d", "0", "0", .Okay}, + {.Lcm, "0", "0", "0", .Okay}, + {.Lcm, "0", "7d", "0", .Okay}, + {.Is_Square, "c", "0", "0", .Okay}, + {.Is_Square, "4fa3f9fe4edb58bfae7bab80b94ffce6e02cdd067c509f75a5918e510d002a8b41949dee96f482678b6e593ee2a984aa68809af5bdc3c0ee839c588b3b619e0f4a5267a7533765f8621dd20994a9a5bdd7faca4aab4f84a72f4f30d623a44cbc974d48e7ab63259d3141da5467e0a2225d90e6388f8d05e0bcdcb67f6d11c4e17d4c168b9fb23bf0932d6082ed82241b01d7d80bb43bf516fc650d86d62e13df218557df8b3f2e4eb295485e3f221c01130791c0b1b4c77fae4ae98e000e42d943a1dff9bfd960fdabe6a729913f99d74b1a7736c213b6c134bbc6914e0b5ae9d1909a32c2084af5a49a99a97a8c3856fdf1e4ff39306ede6234f85f0dca94382a118d97058d0be641c7b0cecead08450042a56dff16808115f78857d8844df61d8e930427d410ee33a63c79", "0", "1", .Okay}, + {.Add, "4d2", "1538", "1a0a", .Okay}, + {.Sub, "4d2", "1538", "-1066", .Okay}, + {.Mul, "4d2", "1538", "6647f0", .Okay}, + {.Mul, "d3b4e926aaba3040e1c12b5ea553b5", "1a821e41257ed9281bee5bc7789ea7", "15ebfa91663d62991f82757b52c07a1f61e42109fbda6012b09cb75b5113", .Okay}, + {.Mul, "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Mul, "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Sqr, "1538", "0", "1c23c40", .Okay}, + {.Sqr, "d3b4e926aaba3040e1c12b5ea553b5", "0", "af13b82e702669fcdc5a22d7fb20a286cd5d7357dc65dae8dd0beeb0ddf9", .Okay}, + {.Div, "d431", "3039", "4", .Okay}, + {.Div, "d887", "0", "0", .Division_by_Zero}, + {.Div, "9c40000000000044c00000000000079", "4000000000000000", "2710000000000011", .Okay}, + {.Div, "a03a9e1c9ecd4600a73553b5e7dd86", "35f9f28f2cd19e4", "2f7efced80593f1d", .Okay}, + {.Log, "c78", "1", "0", .Invalid_Argument}, + {.Log, "-4d2", "2", "0", .Math_Domain_Error}, + {.Log, "0", "2", "0", .Math_Domain_Error}, + {.Log, "400", "2", "a", .Okay}, + {.Pow, "0", "-1", "0", .Math_Domain_Error}, + {.Pow, "0", "0", "1", .Okay}, + {.Pow, "0", "2", "0", .Okay}, + {.Pow, "2a", "-1", "0", .Okay}, + {.Pow, "2a", "1", "2a", .Okay}, + {.Pow, "2a", "0", "1", .Okay}, + {.Pow, "2a", "2", "6e4", .Okay}, + {.Pow, "c51aac23a451627370e2767c51a102", "6", "355498cbf9889c7102a7cc5d500db60ee1bc0779bd9ae18e4aa442a4924eb20a307dc73634be3ea4fce13da5358090f92533943d7dee9ae7dc573c770d10ef76adb6bb13be22c27d8835053840178dd55fafaaa406f8aa28c040", .Okay}, + {.Pow, "22f5d30a14315d48df4a328b2157657583ef58244138029542bbdb4658c8c4811b81d571ff0de06579eb3ed0c4802a84602ff832ce7854f60e3a3a5ae31323eb8a2a7d12a4bb29ee6db08086bbc22cfe6ac7cb201e21c790c328cc5f4be7040c614e68f6f49da2e5dd72a54adbba17eec5deb657d02c899dc911380dbffec0286a03ed9ea3ca6e11148dfb80c89ce4c0999d8c9748c7", "4", "16cb3bba77f95103473e405521a073b6d8a1b81af0bae0cfa44a593ab8c8ee7f78b34e4bfffebc16bd494fc711f01f75cf76331ffa347c54532c78b8abd905c5dcb5bdfb68402cbc6d4256845bf63bd54577fee63b1bbcc32a762b29b64b9d491039e56854ea4474698f4c9fccdc886a8174b247d711aca335361c3a2037889d1426956af6df38584a36674f5782a07887622c33f9bbddbf5633690223b0761f00d21078d8d34726784c35d21b42c404633b2dc1a00f741653b9aba1b7b2a5454ccf4e8e6c0e7faa698921c5793c2b84ade8bf4b99bcf93eb6c33c3b0b59c2e93e6cc388a1fb2529e79877bd2c8885b7509fa8de77fcaff2e7faa7ca0daf37aed817f084a2df013f517d05e8fed27e38e29e45fb67172cfbbe3db09fb033936bf301ef73ca020adf88f538872448b02bedbb0bb9620d0efea3be30e9a6ccee5908cd215e8ab16d1cf8bba202718556a404cc55f2efc42fbcc3e65f629b4abe81436b3ac002406e81e42e370a31e787789bab92dec3f14b765d4028405a15e92336939bbef80fdfb455615a068063553a486805e71d05643fa415f4dd4d8efa886536c5d3d6f00a0d78d8792a71b5af3283bd7b0f4653b90108c518bdcea241ccd604aeabec6c7d881df3892e9307e7651d35278f09a2c991eff47f84406b3c950e3bc0a36ce803185e196df0f8ed1f5991e5586da5336786fd8e140d7de14bdac58001ea1b707d3d9d4ed6447c4a7810c34e3208d322bbb22f031cb180002e009637eb17768ba1d008ad513c097ceb161767cadffc58130b4166a67cac830766e4f32703d4bfd4ac257e3fc96a9f0803d82f489ec74e61", .Okay}, + {.Sqrt, "-1", "0", "0", .Invalid_Argument}, + {.Sqrt, "2a", "0", "6", .Okay}, + {.Sqrt, "ab54a98ceb1f0ad2", "0", "d16deb64", .Okay}, + {.Sqrt, "4000000000000000000000000000", "0", "80000000000000", .Okay}, + {.Sqrt, "a85e79177036820e9e63d14514884413c283db3dba2771f66ec888ae94fe253826ed3230efc1de0cbb4a2ba16fede5fe980d232472cca9e8f339714c56a9e64b5cff7538c33773f128898e8cad47234e8a086b4ce5b902231e2da75cc6cb510d892feb9c9c19ee5f5b7967cb7f081fb79099afe2d20203b0693ecc95c656e5515e0903a4ebc84d22fc2a176ba36dd795195535cfdf473e547930fbd6eae51ad11e974198b4733a10115f391c0fefd22654f5acd63c6415d4cbdaad6c1fc1812333d701b64bb230307fb37911561f5287efd67c2eec5a26a694931aec299c67874881bab0c42941cf0f4ef8ca3548e1adcc7f712eb714762184d656385ceacc7b9f75620dfa7ec62b70ee92a5998cee14ad2b9df3f0c861678bc3311c1fe78c5ce4ed30b90c56d18d50261a4f46fdbf6af94737920b50adf1229503edea8b32900000697f366eba632074a66dcd9999a1510ccefa6110bac2207602b16cd4ce42a36fbf276b5b14550faf75194256f175a867169ff30f8e4770d094b617e3df29612359e33d2a3e8f4e12acf243a22b2732e35a5039fea630886e80f49fb310cb34cd1ecb0dc3036761ac8eed5e2e3d6ea88c5b2f552405149fcb100f50368e969c7d1d45db10ea868838dddc3fbc54c9b658761522c31e46661f46205a6c8783d60638db10bc9515ece8509aa181332207c5a2753ee4a8297a65695fbd8184de", "0", "cf9c817dc096c3ad7b725c9ac52b0969fac4ff38ce527bec81fc7ede5a3f4802879e1c4f3a834d254725bf5ca902904334b22971d34f21d64321c0d5ad190791bd5004a54bcd7e70f265c9ee5c1ea266b687fdad448013bddd2c01436026be89ea2bd2b5cac4ecca23df5f6b3a1794836dd5ed890ed11a19a5c30135f76d1811e77984e69dff031f2151b3707bcded26c8b34e96a74cf392b85495cb1d6aa85000c652fe295d952cc784e29244fe53e52e6b9f44533b11fbd1425bfb8ccf69932dc717e7f614c39596e3ea7dd338f10c34a58dfcfdfa79c4aa11239476d5c201de5fda26e7bf1af62b3cf07058fe82e1cfc00725cd9da6a621b785af6554a4b2", .Okay}, + {.Root, "4000000000000000000000000000", "2", "80000000000000", .Okay}, + {.Shl, "c78", "3c", "c78000000000000000", .Okay}, + {.Shl, "4000000000000000000000000000", "78", "4000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "400", "b4", "400000000000000000000000000000000000000000000000", .Okay}, + {.Shr, "c78000000000000000", "3c", "c78", .Okay}, + {.Shr, "4000000000000000000000000000000000000000000000000000000000", "78", "4000000000000000000000000000", .Okay}, + {.Shr, "2a4663ad14733d6c985e64bf979b73", "78", "0", .Okay}, + {.Shl, "c78", "1", "18f0", .Okay}, + {.Shl, "4000000000000000000000000000", "2", "10000000000000000000000000000", .Okay}, + {.Shl, "400", "3", "2000", .Okay}, + {.Shr, "c78000000000000000", "1", "63c000000000000000", .Okay}, + {.Shr, "4000000000000000000000000000000000000000000000000000000000", "2", "1000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shr, "2a4663ad14733d6c985e64bf979b73", "2", "a9198eb451ccf5b2617992fe5e6dc", .Okay}, + {.Shr_Signed, "-75b1d4317d7fae6627576acd96e2a6", "c", "-75b1d4317d7fae6627576acd96f", .Okay}, + {.Shr_Signed, "-75b1d4317d7fae6627576acd96f", "c", "-75b1d4317d7fae6627576ace", .Okay}, + {.Shr_Signed, "75b1d4317d7fae6627576acd96e2a6", "c", "75b1d4317d7fae6627576acd96e", .Okay}, + {.Shr_Signed, "75b1d4317d7fae6627576acd96f", "c", "75b1d4317d7fae6627576acd", .Okay}, + {.Factorial, "1770", "0", "f0c93f984a54cc898047e57386e7170240f087f83b708cc5c1e3a0ad90b4e49923d442417a3dfc63d84db68daa950fb6c614e914cd54a006182dffd0967443f778a2b47cc1018efd34894fc11f723707e7e166153b0e0c2b4d7372785c450b1dd0f3de4e0d7cafd21180823e6cf11ed0c3241eb2ada4cc01852be8e2955f49204f04ad9d122d796b23835c62d7f15fb97925af7017271bfcd6f133410859470febdac7f22664fa1ae053d03c87a13fc2707128560505863df4dc233af70ff2ed86489f30c34a691951b950c86761b2e456457172902c0c4d4370b7ebe83972f2dd01c6449c983a51c17853ff4eed4082a6e42a99b6179b54e87b189fa5c4ecd1d345c88e5fc66b09d38ae9c49aba18eae2efc8c3e2932ab9a1bcf78c341b7c4e13ec55d43d67e6b15da8f6c789b91f876fb25af1fb6f2af3b7ba4104a198bf4215b13f89b6352bd58d4acb8bb248a646db3806e309ff66229e48c25d7128bd64647bd50527071238cb1795b03b509480c060cd17b77f949b007bdb5277faac50770c10c4bb83674776ce8a4610b0be3ea1565e7ac09fda913b04d6eba6ccbc03e4a49ad123711bed73de938b70e7808fbc02f01ab1b614559ffba61381b80685f8218ee679c0423f3c5859624bd20d2371682c139b4c58b95e90de1af532066d33f57c4b34e6c493bf30b01353ab50cc224a15cec1701a455a58e1de7ac797f598bb3d433fa5ba4d0a9657c98c08ee99fa3d0d5acc50537f4769606bc52b4dbf0cb11c2fe76985ef922cf3021d5b1e1db231cdc6f8f083e9a02d7dafd0867b829b849d636946227850ccabea4aed8056051f15ecc2304687734e81902a4929eb751a725ccfefe90f3156c20669c1566af2d9acc9f9798fb24f601571181e0b182a65356172261a23104c873b6c5cae0228699cb9077de65028f8bb53b4db83af02e580bbd4f0ef6ba996d93e321a6e3bae37f27ef9e316ebb350d8700079b7e84a1e5afb5d75e325a10738fa3cc5342354f0357d5b1457820f07698a3315a08730e9b2f58a73e74b294b50653883a8cae6da1b700440060dc7d25fe9f3756db15418f6128594fde0f48f7a543f977ce62ff9bf750954dc507f4de9cc54a61c072cb4bed5bfb4a35645782e3ccd4d0c257e74ea7a88a2c4e39a2d0d181b6f96f93d05261451fa4f64a17607465cfdcd16a67b73c38a5a09edbddf0728769aed09d0d5e4b7464f7942ecab0ea88649a04a4f9470176d4550b175f9900f984769d23fa45259dfb5e859146accccda8757d0c0a4b5858936cd8c89a64dca5eb9b42331075d32c3017d9c1f16424edc5dffe5e37ec7f51a3e3b047e207d1ca4f7239e90b76bae580f307685107f5a03e0cf2dc7c3ffd14d3b1a85e3af277c3793037cf84520bd6ce8fe99fa5259495808341e9406dbcebd8480b3ceb74b052039241ba4d1add796075ec99a0ecc948bc87c6c72f88082c0153677cc70317d55dc155f9574785494b26f997f379fdd80031c1d8eb2f7d43a6ea7ec4954a7fa5a496fe4fdc70f4f8ae5b1b78363e4441a073b5fef4e86b787d7084bfa0f462198b1c28cab2fdc669a1b486c026cb288654c1f18c8d2c1bcdcc33bc62ada91a10f7fa219c8d8db7597c6dc50e5d4342d93c2da55e05d835fe7a106958c80837af5a79f0b4552179ff57289958391ba7e387cee50a501930d31651e3b53e1cf95be74115dd42fbdff68926c4631b95400ec05fcf03324770a56e07fe364c1c78061e866a66357f5745fa8eff1eb11e1d77b284fe717ead053f26ff428ee773da48a66a3607d2d29d184065467c52ea251a1b8557bdae491f87a2764911a56edd4426df2039cc48b1ccb97e3ef48595408b168a1432fdc2017c0be74d587affc0e9fbb7d11304259dfc134e04a9f4913a7dc10259c0c698103a18c07c2947153bd5c04a10f24216a8f79fdab9340fa6cbb2c8714a4f39adbf6d99541ee288dcf824198140426b97abe5793f8446ef2b663ff6206e99f8cb5d87b7a30656fdacdba9c3cdc9e8911d9b470ae2fe7b37f5825e2e2018b9c26d6da0c0bfb3f7c1134423ea34a51daae7475e893f854625daad3507fdf93becc8cfe789aa45dcd4665b9cd92acd987c82e9a42a941b63484972bcf276549165fad3779472cad25121b79708beb9317c6179528c1801aedd208a94891ed897434fb7fced1d9e0d103ee64733038ee82a4dbcb29a1424c7b9d7b39c5abb2dccd8926558ebc2c7bc7714c39aa177f00c883e546c18fd0056e310ce09fb11edce0171dcd32057cf75c3a52be45361a5ac9d5be3745e9dcaec928c8311b44efc660bac4efbee5996b6e8d40672d4c9bd4bb1d203bc158dfec1478f47010106927a77a72101e3419d693acb64c2812508559e5fa9fb9d1fdca914941bfa78c2b0cce0d6e45e52751f29d682ddc49b47e17f22ebeb777ebfb4df4be344814f120585b407d7a4c5b24b1416e4a3a45a9e7602ee353b960309bacc6cd8f1eea4f297838b9028528347394d4cc6a63ee15000ecf4f64ccd0367caf08bb421dfd4278aa81185e50f8bce64be925c5d422d62feb1162cefadd4d48d4c606222e1e4aead7c05e7a44c9a1bc3d7e010c4fd8b5e754962f30a2ac0641d4581ac55871b6bfb1604747db02bd7b19c9fbd4e0cee9bdf3edfc4cd1c42bd91f30e86950349174cb96675830553acbd744ac318ebfbada54c6e3373aceeff6a62aeb1a0aca442580e8e2637a98887f548b43730db3532a3641e7dfca75f0766db4251d435973c4304ee8c79394642727245d8b5adce9970f0a74df28c1a7ae46b9f1a7b20f5b7759a50c238c90ff2c9f75807bf59abf38be876d404869cbf5ac6ea34a527ee35fc15db1e61fa7fa42879bddf7292922a485b792ea9eeecb4f58a070316dd89251bf826370c4fdcc0e1590365ed972d5a14703e94f122b357313eaedea12d4027dc77f0f16e35d17a7500cb36711952655280042deeb5b252486f2c42a0dd1a23768c2be59aaec3c760b878b114fca7ac863878d1ddb6aaf1543350a8eefda4ac5539d40dcabbfcfdc172e94709361a84da76638009a9c1b2823a0f213dcf46cf73931677c0b9b312bbe40a1848c0dd9152d5a9b3a377697167e287f6d620dacd1044e0d5d3ae07ae9e564dc07bcc9d1b552b140ec822d6c8ee6679444d58f0ea5710097d7c3be4a5c751c58a610031905539a1f391d8a7c0169a4bd082a42294887bc16d89fbf06d8388e989cb35593f2092cbae11ddd47bffc9b86b70ca9b41816f0b1654757781873b54c36eac4886ca2af9526c8ce0a8f85b51528a368d08c7a3570112031a67ab623f763bc19aa7939d0fb119ac0286648ccc7a12f3befe175f8d09c90f35fa0dca68a649cdfc859aa016047339ae9bf328fc9a0eae3a5ad1214f5220446372292b9ec461c44cc466e201aa6590f4bfc213865679d3403d4c2ac8380874cee3f65d6335bba1573d7d20ab9e73be9af1ba405f028b8341615bb07218ada3c2d36d18376277bf9f94fc1ce9189552c864298962f3195c9ef146874232fbc42f1768be379f94fc4edd747dc5b613da50c5e3322507ed9931c9cc17a7de16f5c06f6b24a4285ebe21458741f3855aca1aff3a015b840e23b4bef69505857940aa34fee44b3c8f11add91db976ba5c0b55659d2dd1d322e784578dfc4101c7e68c579052b5ae9cc923e2fbebc62d103dd68a966b49118747b64ae8dc9269ac6aced716427b91a14f8e17c011ca79816528aa8cf6589ef47db181fc5d48a5ec5da3dc629b0058ab91a9832f19b1b54c19b986613e7bd3b09c07de25e41c26aa1ebda72e38f169930813bfbfe74cc39fedb2e91255b5dba52600f38580669170749d7f52d39d2aa493ad83bf4ebb492d05a20ba4d7829ea7fcad7ed4ac9d9b037826289f5799d65d6c4817160239ce1a0f45d872229449d7b50f0932cf5982de3ede587ef5252b03349f60525c8e59a87bfd10fada76fae0c73dbb73e0a6f5c5fa6927c1eda01e4142d356fc02741af9d9e87183428c9d3389d08e9bf2c6514c0dcb87cfdbc1fb60cfd2714fe6f21b7206fec61a5ec7cb2e7eac92eb21c3164564d0303bf06edbaee1e7fe60a1bf8c69513412263b7c5cdedb96e36b5676a040396201981435d906321d9d5740dbf59a9723db18c65b32d84b684ef1ecc0723239c5b534e562df86d81f7aafa879b6bf9e1ca9a10caab41d2b616c107165b6756bca480dcccbf2880f5e7bafd49c186b03719836afba6eeb4f861c5aa4e00b226e42e0bc02c0cd7b0715eabf8cd67c7f4c2102e7772708d5824ccc2457641377775f8359a23bc94e514c414453dc7c486137e89a9c191d6f21b324cc1e02ac88fe60cea1261c9470507d2190b4d672185711c29871d20c91a332976a3aeffdce84c6b4b1c216dd9daa1e7065a629beaf9f92329712caff6dff95d61e93e5a0155e236b972de03f808253f8690aacf505d32682daeeabcb28789eb43c9026c32e535a956ee9e71f283dcdb02bae5b1c34d7dfb07202af8b5e900bfb3240d0049ac8e85b17276f012913128b53e2116887260d6a1df9e6c935850efa3e813ea85a0c743108a2f56f36bdb0c1e5ff14a3fd76f25a5b5e58241ae3302dfef6c778b230ec4c37d194b8369e3a511d98bd953ba26d418c25d6e15d4a8006a6b430deb02b00fd41f709c73bd30fbdef6b8b1cb7ee518c50c46cc09ad40949ae6b69da642baaa2f06a0a3d0dc4915f61ebddf1ab91c48af5dc75947f257eed2dd3cedc33fd0ff8df54b627be63974368c819054a4b893bb00f54d7933876c1e7838951417429faebadf917c3e1eb5f2ab3beeb3efa9cc4833c62901df6fcdc5e1505e659daf6310ea0b5f52acd8b4216ab7ce6b3591086a92ba093caf874cab14b006f5434fc1a4414bd16ab63a5a022b0cb0ba36cb1ed7860a3142ec646e0171f73d22822b2156cdc1848ea90eea94225add5ccf33e13db42654238424ae67a46066084cb0359fe32d307532dccf32f5c11233f8d3bcb398ef07fda2a5e465c12049032503675c6d3ef3576fe1d1c15047cbb0ce29fb7f353e43a8458822c252f02355d3d14f1cc33494b77f0bf55b88cf57871c6fdd2257adeef7962a4c3d4b857707b4ce8b02468347b58bde0466aff3d6057363e9125eeabcbb7d5936ebd656704fc6b045d27b9fc8514031c9cd90a635fe68a9a080713b9cf1918584f7461829f6cc3a7483a43e76601622f285734e21b56feca35f2458d40f4be31cc2931bce61f0f79a5eab3e492df63840a0a97b40a27d4516b32eb4cb6b643c5b562b5977f6e1d41c38940e9fe13240ea92421a7aaf97a2f68456802da771432df3a5d46eec42a74e780941f690353ef75f42d97a2eccc5da14dfbc277fc635c2fdb9cab322a51d92d4cd0ff70d009fa57435636550f4bc95926e7ff28467529ad9bcbac85de4d5ce5de6597ffa8a71e8197c937fca44bd206908fb9feb9ecc50071b00ec09940bfbc5679a4587e1d511f331586940663b65546777b23396366f996b002aca4520c6a997e7a368fb8698939a546e74eb00a0c0e4dab5927afa7b88cce9d8f07ef7a74818ed7e35448bfad0b07296992e21b514a6ecbca930e6f0543223b8780aa7b65612e0b394f93d19c3cf2188678bd5a5e2ad327bcc2860bedbfebbf343f31db337c48b2e8275bf6643192b2d3034d5d2404ee4129bf387c9572a773669aaf16ab2fbed600bb5060a2125e89b15f075ea947137e8d8777ea9bf260dfdc16bce48adcbbb5895081e8f0e966d69479de7d4197e2652961bd19ed5d651e45484ef6ecfd0033b0a9873f4497129575f2afcca46f1c42e4ad5e7cf3a72497ed83dd2cab5ed36c3a1c4a9ea3cd835792fbf77ec37a8b69c4f38fe8a77319c6e4e1f00dab8fa5629568843dd671d8f3ae36fb69772b02af3c94434c3c6e1b2ce38ae23feed4971dce4de59cb5843ee10bf1585c73a3898fe5848d74273ba3a6f9242d267207bf4250064b27445aeff713123de18ece118f989520b1e45bb7e3bce9c40a4c82bb12970b877bfd24332e1efd856306d53d9a4706f6ac0546af464fb6f5d97dba6da4bab8fa7254c0e517cc5d7622371db8ffb9aa9b2c2ce4a3cf5508beb12704a12bf89eb9eaf7aa0e9d4a578c0c17a505673124a2a0d0c19dcc4271b5bc67e7f6e470af0b232a6fd236fd4063d3fc9bc0d0b46b73b789af4c0c1b0b53f1d50ec1c648483bb153808e7ac4a829ae5bfe44fb193aa48a6231fda4292824da37b646d44a2548af78093154cd0f6c5880ded57959c4204526ff7fb88f36b2e753b857b1a95bea6f4448c0cb1c1c92dff1f6353f93e326cde06e5c4fec88143fdc29ff21e54625845db53a160058c8f8a8ca9c45f30a72c5f3f3c0d60ca21c97d01eb7d3bbbd68f973cfc4b7aff7ba10045e1e9deb4cdce9b95aeaf00b9b9a35adec07c593a518611c8d744669b12a3e52a37e26f5161ab89d02d32036349918ac5446235a0e59781eb0810809a077f473dc928b207ff5c5e3bf3a1ceab0e30088baba22fbdd3cc4a617b2376f2ccd5467bd87887ad618857ebb71434375896ef164ae95550d6bcc3086ab70ecf6fc17f3d3eb677ccf81a7dfe2fc58b5eaeae41dc540690b12e8e1b584432f05bd0f06db46742672a9c1e3031cf17b1c93849d9adf7e190e035f4e7f23e786f3102a3f6378ebc8bd19b7e9d3c73852c398118ff24a2d9b0e512173133692cdb6732ac4c35e0689c499d30195fa1a22addf95c0012a5ca5e62161dd88dcd75aaa29f043f987abdc5e1d0fdf03a67c859b96b7d92b6ccb9ab42b20903b2510e0f93fc43d9a7930ddc26d7c9caf4f8234723d24c1fd1cc7272e76a575778497d077592720ce020fe85a8fd94cee7e227d63dc67ea82b44992209963bc9c57a537c60848d7c98a880384ff4caf6fc4614109254beb4e91df94edc52b632448c4dbdaf7165792d79e687b4d720c5a6894e7019df3ee266148c52c93bce66073de054bf2e9887f77f7ebad94c70dfa3b0d6aeb47313f46125975c6187d34ab471d1aa4387829fa7a15f7ca89625ac8eec953b722ad0fd7d5581c35b895a7ad5efd9e2f355bec54c84dc1c01d40923039cc393950083496d2b75b8388fb4c93061ab0b962541819791038bfaf614e4a5805a66a2be678bbff245f6c35b73171a6b394b9fd4c24f742ee444bd70c7f4d2761450fdda51e82c7fe65f7f49bf0f2412a1e1d171db69fde747623c43749053b372db8948812c23f9efbf1bd318d20ae5a488e897350122bbe5e3d34c0871c05ca7ef9e02585ba1cff6fcb1c92d1063ea04fd4c22f014de06c494e9418b5f5df9c8d30b25b7ef180c45c07804cbff18e980e8e8ac2e65a24f48666b4f6bfb7fdaf68327575e1f486b6b69e4a6ce921ff6bde3ff11752c7788bb5f62b5966f6e6b501347e7342e089bc4b3daae8aed81b86a60911f454037d0d2e977f8658c362fe19f6bae39ffc626248e08b19f8211ab85913ed9849abe785e26e1137c6642134025dcd1cd138b178fde95f6785db77a39ffa444aa1f6b7cc19fa3f1b41af6c777ddae4e3d95d9df69b72da35d35f7d303ca85e28cca1a78644bcc2f3f97be8c3cba1fc31aa2df6d96f92b25dc3af7891ba3bcf5c9f8561613a9ffcb056a65d98e2a4232e8150ac3a5b328d44793d66a491ca2809fe5eabee9ed8f9d4738201a84eb4825b495db74921f766edabd1b06d25ade0b7e52ebc95ebc21c80f1cbf476c27fd23505b78f67eb885b4ed8e7cde831fe4fb52226a2323213a10c2957b2330e8d5f0160ed936e81261cc30e79e6d1aaffe0ae553f5392075af9a82750ffdc61e574e31bbe39affcc2ee6b8c6a64a056b62516506f2b58077093318293b47dac025bd280ef05beebe7dc7dd1fd5831b53624c9adf1096064470356db08a604e588e674553398782ff7c66694a44455574c6da206ecbb2225343e47f6198ee9ccbe38083b0ce60f8f074afe3887241691f8081e709c3d9b79c7cfd04d43b8bf1f34285acae5ddb1df8d26a7d7665af94e5d83ea90b24ae986611b26b35ce70e25e80a98b05d21f0d65a0f12d8c5033592d00cb69dc2e643db190389eaae0e98747c430e766801c223a94d87c9d727aa0888d982108d9a2078265a242d2d193a79fe0ccb3307b9c78925201a0f6e1c514ab705a8c43dd8d18ab3dbaf2969ce1c9108a1c03634c907d0ed2a01242a035be228ab9c39674c09799a84e5fe64f7f583085962e9c3522743f16320f6df80b07e16dcceee6c9860ecb992946ba773c3b4e9359775ab2443935d0cfed8c0091e33b55c4ef722d611b7550beab45853ea6f32bc4c184f6efdc339dd8b101a852b33aaae8ac13bdc9a1f5c9290c13e3533a0ecf6f3bec41031e0c901656f8c22021e3f9f57c2dec915155688d364e559220d1bb467473afa48d4e91e9637488c7f0d6382002eeebd4984ecc553679aabafd70ab008429355d018425db8e6a88e778b922e939e85bcc16a043ac0ff6e4ba3fd74332c075bcd496abd44bb8f73226980aecc55f14d1899764a9c7ce9bea4a9b4b1073a6ec2015181eca06907175ffdb2705f6fd00e5a013d21fc66d7a308235cc786f6627dc5909302b5188c42bd7de5350e06c1865316cf96300a79184d8cec06771c1b6ed8bfe661284c3f44ef5b41d7e70ba10bc6f41328787e778d5538e9785e5f032bea564bb4815fa9f09f47c5f73d4fa678d2104d8e0380c722c4ed6cabcb41da71ddc570028b7abadcf2899ad8be648e5d9aaf40c3a5411d704a57343c534f90c724f7981842a51691b8bea457e38e448908b66d9aa481c3c0763ad1afe7176630e646e9e00897bb348105ce4dc9a4c37ae615dc1b70ec5b1847d1aa9fe982dd649036fa8f5ef0c23e588c07f11de24e1bcffbaebbdd3215234935a08d389d6bcb6aea5be84e4929cf18e79eb8e5a8be348032eabd5509ce786ccbdc3344c87861c1b38b8ac59d21b0281e286927361a0797bee2700f625d3a8f87adc373258f6a9f35e65d68f2ab6570a0ccc21bffcb344f5b7d061a8a20646777bcf245e00a1ccdaefe2891f3b0c7580e3801dc7a3880fe66a70c0f0a2c880f79f110829cc7681623f36e022ba219e516ea2a46fa4f0fce0c489f67ed3484d67cbebeb5b9b3d75d82132059d4d7ce062fcfdc5c131b08d1c966eb103241d4d3228cfd1018e53003076d631150724f4ba6a7d6cd8719cb61d51fd83f09ebc9d11105b97af876566d80da59e977a0f665b3c28c7ed40cd778bca8f1a908319a14c5d6ad390cc55e5aaee779cc3916ec0963aa262dd7062a9ffc94aa86e7da473a44c0dee5c7f6820f327ba6b36e64154f5435474d09e3f3593f63216a3d6e206d3c8210a9430facdcfadb5cd50ebede3fc02d6bc1c43b3ece4793d0032f1f9a12cc9577a4bed8157c407f93f2ddc9b91aa5eea506c0386b55517f7a96ae01aef1e42a9479fe41be7c644d018301dce9c3ecddff37b1641beaefd486baacbbd24187f76cb9f154a33e6543155d29176fea515eaeaa28a321cd41255a1abb7efeedbbc0982f09563909fd76762f5b178d9003d37e2565908095f44cd376a8147ff2319d7cca6a0135f7bdd1f30f79c70c6f799f39f9bb88eb511858d4eb34c7d20b574f46ac8236a29b714d6575e58562a363b7c6286eae49d42831a14653ee16045446385a7797b6bcf1823f8b1b52a2376c3be5dc0b6a8282203d98df652455402ffd6208a6596570d264c2311a01da0a5b119172ef6d473321ab354460918f53c3eadd764c937c674a9fe3179d5c9cd54348805af4f29ccb5715d8e129d918040e4ec47f2c99022e1e00034d87d157a572d0d969032f04983cd54b8d18612a4c2875894c48feab0c96141e9ba648ad6a2f1ef1c0d4e44761bb14107126ff157ffd5c27568c37bd28a44ca81140cfc0d2a6dd864c4e27521ab9a1078d48e497b8d2b2104f1e4c3ba4a2f95e401667fa5e388c6807fac08d8c4c71bb5a0d50366d39987426dfd9172ae535e1497b0119bbf4c15f79fbe496350dbbe7ba335d9aa66ced3271eddec663d16120b0b0176987d463c5e47fed463e2ef2a230c17a5417f535aa26dad59615d603ec118670f88efba66f392aa3ad7a5d483ccfd8c8eb69728d982399cbb42c5a90449027efc2eb0432b90801d74a9418469af89eb75352e4a3dc2d1c589373eb8a2352aaf853e1bbaf7e4fd8e9c95567987bf453a46e7cfcc31fd61e6c0f1a2c658aba4feff965be68d6b5e964e2872f25eab5323b3c326c34729acf20c71698c43bc10ea039c977d4d7ab3927512c9a13134b4c4d518bbaaf831299632244228f2088eb6cba674fb68852c7cc3a2c721c84e8db66d2c5b0e4d0a95f0e0d928e7e5ac0602cb4f84ca84f200f33e7f189220f6a945b538480e4ecc07aeae6adf89c3f7b65737c0c15bc7f8a4ae2a2553d4fad3dbaf438ee0ba7a0f085b0743e6db6e425c1186aef4d134af4491222400e21e054ec39004f35862c17661ac52820005ab99c257de614f5d078073e323933c533b0e4ffdcbe8aa81c816e0fb3cbcb7e19a9fc228c2206c663f8b7bd4a166d527839b8204f3ffaf11af7b181e2f18c310f25eb7ccfdd9af1b5b00720fb719f5ba905163308736bc7833e400cd56c32198c6bcd137447df307a67567c8429adbe05028c3386ad96249552ca630fc67d7bacb109cf5f60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Factorial, "3039", "0", "725bc54b19f7229a2368a8438d231aa6742a9bdffda109af918973d185bd1142da42abe786438fbfb3b6a1d6732b6a1fb468d8908f1cd36ffb7efc0669264f2b5f3f92abfa5e2adb4ca4d9e2750eaf98c210de9067729c35a08bab7b52a889aa4f7462af4d00f28a02a41c9c63cdb0633b8afc137bcf9d06b7308fcf3aaa5d6a6cd571ae149530e773c9ab20fb61de0a754b959f749ed22fadd2ff0753c623eb2b377d75d7a730e0ab4fb8ab8097108085b68b81df361751ab9543dc4d640128718f886cd2deab7ce07c032728489f9b4c2ef223b13260de9c5b5eb26d5d3e4ba9439bdc3061afc6083ac8a60ef74d770d15557742c93e03f6df30dd5010a76761026e3e93b48e439d4cf71e41cfdc00e6c559f3a0047a5bcb54acee326ea538297a91cefdcc9a3b05d5d0c05319635a817fbe6edf12fa501e2024cdcd86f1ca3a12bfd485a55b0cb9717e5c29b65fd7f6a45ffe75300aa09ee79b9a0ef022d4ab09eef62544bef7042ad3c0dddd7cf6eda293ccf9d9cfe38e96c7a29cb0b8ec360cad98f97826dbeb94e444928d64bd1b01d7d562cec000c84d5a4b4b00039a82307a3dbd32dd5047fbef8d5a11d177bc6f09aa580ebcc9cfc1f1b73df77e247e23222e58592a5eb496e7fde5fe202b09f43734e4ea1318052095c689d7ead46695c1213cb6987c6a3fb6da2c7c7802af9b7d6eb6938d3660c87ee7a76b11b9f964063c7bc3e161f0edae8433de09febfcd2e37bcb9a48e519529aab496382dbace40b8c75a831e8401804a13c3f567691f03d84ef70c345c42a3afe869e4e59cb240b50811856f3a8202d2975289ea2ebeffa878a1f29a7576609c57c27c015a411e75fb25333ca49e6a6edd6f668b86f4ee9a7f6208e1af9ccd3553c00902692f9db06357f399b90cdbb05912070619c448159a4227526054ce00c7ca069d595557fc5374528b6739e29c2b27f81034eaa3a3b0358641c5b699db45256519da785dca487d0f88b41bdf388e460fedeacda9c27934bf453b96d7f8ea2acf573b33346a0a6f39c10104cc6eab077cab4ff1843b6f1ba2439808523c3f7ad9ca9d411ce0bafe9aaa543b82c54964cd1e7bb0692d314570f35d1b51e7a1b81f2d259f4ebef59e018a2e8781258ea2bf4b0a1053a0114089b70aff5657bdf835d73828d00878a3a74c9beb017901a593127907e14a350b40c15ec821a1e502cb5e8ff7e807f9277d7c18cfd82648aa7a7fb9732d3f7574386eb49b66ca927eea6154098f45efae6b7e46c4a0c9d8e5e432d7f9bbac3f06635f1e7edce3088e5baa7edfa7cb5ba90198b97020878e727c1481ba9399846092d81cc0d2f6e85edc6d995885335264e8423a8922b251f98113a89a14bd729b1aa895a7b8fd1d92ac8f826f0e5e39b23a4939313345f6a4c055f819b2689b8bb9fbab5bea96a69df4ca93566d1bf9b106f7f7826dd7ed7d2b14a1172e754ccfaa9aae397593a83e9a222830792c1d630ef0bcfa1ac7737630f56d5e4daf8d678b40167b5333923c78e4a962aeea8785886e19fadc2aef83eb5feee8b7cfa4583ab9122b3d784bf8ae0a0085a9617a2728013fa15c5ee1cfece8d6f1ec2edea5c02e98b3257e135957cb427f6dbfc179fb94229dc7c6867d93ab740b75c41522aa26dbfbf786e9a24b417cffe0c0c6b8049877706bf9ba0f302b93ee248f5cea90f098bc557a19d6e93383c3549b8ea7c2cf478d2be3006445e133cc899b05f8ce12f35caaadde7431ebd6aca51bac7e1a8677af175aff8ae9bcd31bd284f9b8bf99556e8c679aa617f35d89817636c0e32b28939cd5590a75d587d83a72478c68f289056350ce93a652a7ae531110e6e23340b64311c584263f2425aef4fa73ef808455688cf111ea17ea9ff5eea3aaf22cefab591dcc10167d9031659e9510c580b7ba675e75addd4ac4ad92b337ecb2024d1398a8933285da3affa4ae82f2ecc1add5881e42a9327c42be0f6e575d4d7c31a9257a7982dceede1e3cbd39b2808b739269413e6e764619554ae0e069cd4c18b54ebc7146100d735afcdcfbc969488470c0e12ad4dd9806d12cff39d431e008658e5b10a1bd72106ee0042c3e738000f7d825e4d9f1addd2ed0c1cef0756a29ac3500ab0a6278252f00e8b6d9b40bbd9425ddc7602a1332e4540a637ab94cf245e0d7453fe6d0cb94cf2ca5a279a565827052d9bdfd0a0a99fdbaab8f7bcdb5b3a19d70c19f6d3a87b47d8414d9fc7d617e8c2b8644adfdd761784174f1e7248eb7f04b538dc35eca7afe3df9ee02b9c5758c2ff06eccb89a918f607609a944a72e8917118a1fe1cf16b8993589d89f99044a5eb68d2efdb1cfdb894a7af03e3a24a2f98ef9ff47ff5813d2a38e13b76d66e3075fb0944c71f5510dcc5224236a1d4530c5abd60d439eca82c788c2bd84ed5455c395bb14b18f90fb6e23c1eb4396319642cd0c13c6026942c62022fbb9c26f180cd283960466e5649a62bf965721fa5930e844aa151f96abb4ba1dae7ae1095cc42cde8badd8662a997d213b23044077d29093b8d0951808f3a7c9cc1d60459506717d6db29d6f85eba257d1a8a7c0fbf049722923f5c5eede2ae0c4a2e8bd8881dd0f08ddefe11cb645350d8fa807a97ccd21b61bb271998eeaf0b60be41036525dc97fc80d7a8c648caf700468ffe7720aa279d5c5c1403646dfb3b9e0f4326876bdc7a89ed3a54aaddd84242264c0f4cec48fca3cdf8f59b548b8eff1cb3f31405cf068e1e3bf9cf4e378adc0662fb447f73c008724e6f8e212f5e57311385247d07429659c71b7eb7d8f2311a5edf73e1498ebf216b2b1cdbc83a182726a5f086b82c1465bfb43b25104eb3c947072a884edf2b8cdfed8bc1546d6daa21c4907350924fe9b5454c5cc5da4349809faabc2920a2b5d39e8d7d4149b69b5731155edc00f1c0f9f227a5794e2d0e47f5da6247e12afc1bbb76e679d3fd5d92a8e94300eca12e75fbbd423aaf5187a37ebd0796d063bf58c9575cb380672d5acfa6c2bb242f7a78a67b785f8982d0ec337fa809becb0dd8534b36b1908c5f10adc3f988eeb43acae2e271ffef9811ced071aa3608b9f887594d44824137f3e26104a2f3c49728dba805d410dc64afdb4911b070e32d5bef14bc10520e354cc7fa2f35998dc82173229ee64606ecbc14a9bf3d614a4a773e492d27b2ee8d34a7a772eb53392161027ba1bdbf88760f3f427186ec53844a991f75fef3de31e2e041a485d7bd09c977bfc1b7cd20d356db265a4bf17edf03a1bae0bfedad9290eae53a4e8a67ef0b1cb03efc5f2f3077beef63ec1a03e7db55671f2d0231d24a41f523705fa9109514d9d807a197d09685327da1fa35234f68b8942fe991a1b8f2454fbd2e4e1196a0f37eba6d24729bb4b6d50442a978d4638288aac01ef36a8e7b8f6f7b199a953c8b4c4c497f8cd32f558b18c58f021fe5cfe61a19a47b5cc5eada8796f666387b4a978b46319fda2f768b1f6a107019ad7aa813253449c8e6a419d2fedf59db4b39d899bc948250944aa7a586263fc0c06956c9f205369bf85ea63dae27f04f8850cc399b7b8b232ba9dfc5b59fce0373789f3566fb8df2ad50bc2f975830b92851c01886b2e737ffcd5065fe439f18f0b251925a430b438b6f9497d93c6f5eca03f2ee720689e7a981f7e54ea0c62777a0129a4e71348561d9122048081f5ff8c4f076d16d386406ffa3af8f1c399c8535df945e9fe17caf64255d175fb109a978db8a63f825e312c318c6b0dc59c55044a80ca4ac0e1ca2a98b70d32101c9aad6f9ad52abd939cc387cd4e4cd775524c7a7bab8328ad2d8096ded7c278f71ae9fdb8ac00e265db358c3030cfda95b6967495ae6f6a2c35886964f83a042a9a2d549fecde7eb49b221a8cd0f34ef4691e186a63154e76c7b9f8d8a6e885a36f0cebb3250d3a0da49237eb6079e06c81f1a082ded2cedb36d505f27351031d6d9643e03b1b87b64766c5c8935f13aa1f795554f1b55b9295e7d2b3e18f1ee84595978b8d8abde40d32a8e81ca08cbe0b3b44c50d5198e76b09b82764feae609ac46129d222ff5b861a41137e88605953642183894d1b4ba6afa59d7c69592d0feee7a9a92348d5082de0c84336861a1f6bcb3ff7708aabaef25955fcedf1435aad33a83aa9d3bbfbdbc174d12141c51f7ca91e356c76c9870e4a32d41dd7915d6c21ce24f5f49c334591907561fa6bf6d47b5bb41c1a83d6eb1e823acef38833f0798599f693c6711c9f7adf2887a8d8a4c0e615968e3e2d86fb51e92277f674ab129415a9d5b11b20a51dff9598a25d8f4b5f4fe8e03895158269b154c0a169e3c90a655c92b8f6c48c763df4bd134a1d23293379d36c9513455db5395e684dc79c74907a02c9ddb0ae562e1a4e307399b965511e05fc7e88e3abc495fd42d6f61ac5d5937249f9a0380127db9cf8235afcbfa7e136f6ace515bb3041c9dc54fa9eab903862a2d5ae1c0a14d8466e58ee872b6e3c8e8e11d63d67308d001cccbd58601fb1fe7874b80b927e0e97122a9d8c62f193a110d1431b696d1fdbd2216f421bcaea463ba82c7c8d583ab9629868b962d3152136d420083abec0fbf4a0d16b9120ebea914dece3df525788b0a18b953434b5899b24a0c601254974c65fc1623fdf2c11c10991493eeca2e1a9da5d0ed107cbaaf0f71f6592588f31aecf8e98cf25ca746242439ce908752a49a20de527caac3c707eef57543f98cfcd692ac1d039e19d5a09b9ce03fb307f00229f96cc5316747e1eaf619304a6a502c4edc236e76138789fd75a9a993cb77e7df97f7f0b847c92e4be0380b6e94d02e641a1677198b4dddb79b3fff93401b5bb6b7514d15afa918aff2943276d98ad8c61af100629ee7c90abadf959677760cd866f8d6fb7528e93320ca0f99351c5f0fa3d589bd9185fb615d501aa22191a46ad0501f2cdf61c92ff4e549dccdc531b775589d39672a16a2884a1cae8fc12233264b60ee868b1fa550b5fd541ed37e970d9ad7347fb9e338960a40ad8211cea809ae3ce928b5a003a01c3e45e5397ed20c1560944660285edcd5d68f0f8c7590feb49a2516856fe0c2ee49c958f9e8b7ac0d03814dfab8477079cecab4310bf97fb0306efce6cd933fcf0543c72862848f7159ac74eb354ed6f747ff82b13e801d8a274e5e2bb4f327b4e0bfa72a1428bde3281e685b095bb7807904717fc5f86cb96b896c24fdd3062fdcfe9a94a4ec84289e44e0f51da86158ba8ef895054ef3e9b609c3174f0f40b50f122f7d1b0cb2a4d4f8e6d84d04d7ab363fb6638323cd11a48efec0efc47eb7bd6ab5e40bef4f4a7f7acef17d9b5eb47181f155428eda5738943900323f4640c2adaa231b0d290d3166cbef6ecefd78e4295c391f6e7c350ad0840dfe5842d66fe4ab9c251ed7aa6b93799f9c57dab554929f687e8315ac0d306d763457d04b0892e5fc5fca44a65dbd58225f2c8a778b22fb0b376e72114845cc32a6dcf5fe7bf08d522ec9012f4e6f2238b10f23276df884f9cc813b9591dbf51441f6938c695b1c529dcdd8673eac84a75df4c2818fc5b73c54ca30b1f6865fa434c2721571cc115f864525af71fa9a7435a7a2645bd1c1be9888de21b354f0809f2cc4fec623a9f5d9d552e32dd8b93ba66e8b62baf97302ab20b3489efde5ab2c204c5a7dcf9742132f9acaa5093b75d5d4b2148c873e72cc9838c6e79ebb909d9d8b07e93ed565f3ad13f4676df70cdb366cb6ad4ad9e180465b9bc207852592933870a4312f4be267cbeffa80709217e2914515d259ab3bc4554293dff34518ed301a964cbee5e0da5f38da3e8d734b79c89095f08d782e6dc376723c48f3d60893375210dcf810149ed90592eb20e954e862e93afa885194c35f845c47d56ce469f6ca72d0c3d2880d96da5979b5dd865384484acedb1bab199888fb8af337d4af221542e664c8ceae0c004bd4d3145270583b6b666f3f62f0a2c6b9381b1673e73b08ffc34a693e02ed21cf9250b12f1daa9f1ba541fef727606e24072118bf69287170b3a33dbcbdbc068b855a2e65fa2406b3314af6eadee0f3464cff2416b6529c684c93037e2a17d674a1b56e96cc03ff13dd75d1ef0cea3831f1509ba1fcc6c7729363e7594e19e486b49b737a40e603ab2ce28e0ed7f4616fb2e6105df369cdf5490db1f75b2445025b86db0fdb0cc22bf63b68967cb2bcf2a7b1132c461f058be9e59254e1b7f240d9fdb01a9408a9c5770deaf74ba74af642a506c1c958fc95d8ae2293c4c5134573de18693c8d16c3c5ce7023f921842672adcda4e5e3f926b40bf14808ad2bd8fa91b28b2a1dcd380e8f1e5a566c48d8293d90efadef5fb104294109c393373e77bee58a932ce30f7c7ec46f52ab228fdeb883765fbb61d98f1869768f244182d40a5eeca6eb32111b381c8c9c82495ecdd41d4a27ac29effc82562b41fa41b60294bab971853ee48da85ce2ba803ea6573d1047406964c3f8f79653adc8bef5c818ef50623f468720c9828ae7f8038aba74f77d65db2bcbed9e1f415ed8819689e37d050a57e624cb527792b8709a0c31f921aab8a6098c9d23a542574686b52cbb4ba7d0922f28d1816684cd2359351227b2ed1a9864db623d87036ba16abe2742b54bcb23ac4bf7a1ed529b8382b290e5b000cc0f9582fda44d7a389400a51c8ead0bfac541bf7c95263750184f5a78091a8248720d67213ea1aed2d5a08419ab31cdb8d8052ec04a3f6a11cd0f47f0cfed6e4fce7d6e56e0996d06c5739238a5a5d89908c4e66ebd9aad357220ef39032330b35d40b7a4ad7e6174865fe64636e9e6f15ef4d37b0f390c81df3999e0dd73f191f1088bbc74c6cb9a742276c9a7023147043c81d00b6d3b82845c45d267fac6121fbd77093f22eca95af3a364c7934da516f75605c1aeb92fe9c801c571a366843df64f2cd4ce30636b37295620b9f74ec966ab52bbe3cea589f3e95bc0161b3305753b8a0af49979cdc8ae2e50006377b81a0a9c4718025572675fcf68aae62cdc47c71b272cedeea9ccad80c1c705a43650492cba6aa50b3375fd578f3a822d051dca2030218c2a4cfb16065716be81f4d1613b8d006af780fa5de4c7248fcef3cad3a58f242d9f254fe5486abd2f4bac666c01e90e892ab937fe39c243776a3475ffac7f8f96d68d3ea093ca3c4646a6618c31bde5374bc64c7efc0995989ebcbe816be8b6a3b1a43cbb63be86ad279a7c30c57fba1c469ef65270f46440e7d5cece01381c735afcb544872dfa7c4e7216cefa56584797dfad0313e6574eb4e01acf34f8a6c4395db3dc1efec7cd7f2562b082203120ecb56d54910c91db6dccf41da71fa22e5a68f2ad2a946415747bd8f7c79b2a02c177f185c55f9c32cec441bc96b00c8d21e977c0206ae8aae2e4fc7f74a787d603e8468bc823d39f0d1851b5d10bdf5ba813e2e214517a10a00c7e34d372034c126876c94aba7d03ac13ac36de981ed0ed51b8710c02b9a3dd6423af828425307910e7d8a5133c0a21e2182cf37512710f31681d5007e879ad75f40ee9cc3a4c3a6fe33e933a652a72f023fcba97d7774d167ab4c04d4a4bbdb7e330d220d84f877d3f577c1d499bd1e6fb999799e5259ca39f39f2463d371c9b8083a26225abd7487dc2fb20e8cdeb37200de1b82002b39f0ff70bb078c919d6bde528b0eb785e35d884fdfeb5127aa2dfad66df8761e5faf2f7a07c597aa4c9ef901116d69d45cf3565159383c8dfdca0c320512ce612654351e4cc2c72e5dc148786b75230d6fd463ed2164cc7da95f32cd26dccf7df8d97983f93dfb0239ea736f32c65f6469b9877bca5c0b9882e7171ed41b1366a2a86988642ef1c0c47cac31ee6e9354d9757d3057c00157be6f98a3f9754cad44883946a6fad81a64bb5ac661b2280e49e9f95e09c5af94615fab511082b6465a73c021ccb64dd1ccda8fad72562fb6eb55f1eeb5b2dc0687375cad33bcd0d74daad4298b1c592b5a624b26c5e0dcab7d631e6b217fadc76cb8f2aaabd5e50f2b4a28bc2effe011374d32ad6f3f7674333803c9beb262b60b539fa190f7b477c07922d645baea18ccbb3c06b5690d38fb125fce9be0988104066c15c7ca93ecb52ab3e1f936c2454a2e26783f5e8175c101c921a546dd33adb20d9153bf6f1bf79c3c284331133c605320cf313db6d1274f093015941e70ce615f10458ba48a30544d6f44b62e2847045fdb51c784a37edbe4eaec58974d8768684285e49ac15a33fc0cacf23e5afaa2e04524b71b1bb8535e53872f59aa647d13297a2dfe305116e82f1c72d27036898d2b544d6bb7bcec44db12d45cc6ad030875b170e3266581e544b07c8893f7829ae448eb888458a1ab8314e38ea687ca817ae1a7f7b77267a5ba136b546d5440025a9269f16546077fe2bc158bc31c1f4f77c5cd0850338917c5683f67207840e80caf6fdbfda8ebe105dfbc37d868545a40b97882769791d39d5547277320448ceb05c8f3d91d2a437d92adad44b78cffb6e81263cc900d99f57a0f3520d8acc2d1ce4ebf8bd494e4c84cb17d87ecfbbd595296a00949979a509037ac20b694adea16ab8e095fe8a42b4d12a4ea677f5a9baf4ba7409710e55d723ee1220c75ccdccae4389e6b7899a59417fe746d3607a120f64e15a64a3b50ec4e53575d82d348f445f1d6c1bc4cb9a6d8994a44c400bea87891ac5da3aba7fcfed7bf78ac3e90ef91bf55dbb16691a30476a6382de3fde7b8e07458e3cb4c7ccf53a870677d17ffdaf4590444f2586eed1d1814ee03ea49b3825168ca030299681114e0b5fec1be8b5d4dba691911acf1cf1e494261514613dc9be675d9a53d7c8a9733b8895eb746a7707adad425776b2400e1cfae03dd9ce639d964782a7894372d58245ff37e49fc09f86ec157898a5c55cf7a1c3977da3490190c82d4d6a54ebaf006634234ff6ff8070a9a992298f2e3d9ea3a74df937ec5e7b8263484e9815d731ef0f5b2d6eaa8c8f6bd966e0828a34144799bd575c4b7e6d5aa057518f7689b19ba446691f7813608c49fb424e9d4bb040c2a72d015aec8e049a0f6c985cd89cd106959d1beabeddbdd4042d5933cbfdc035e9718c98a2b5eee9cf9350a7e71749f3100309d59c41153c435e7cc7391538fe549fb1ccac1cdf7ba1f4b03d62d883da32fad505b5e98bc6ceb89b447852fcf5b84d64046daf583f42f88df6c936300339a49d121cc6814f5268d30bf827da8e83ee4672877c9ada3417f3fd1acc1c2bcebc22d9623a27068b83719b71f86a242fef992894ee32f53d60ca000779145c5b9274027c39711b8b4c697e4bcaf7c588a9d688d25f6312b9ee9dacdd1a28d0bd45883bcd665810c19170d80a6517dfaa83e489e38f4e70d2e70e605d7ecbdb0fde1e34f4633cd67ce2a24d845b1fa063fa12e141b51521071b40f73f2422d93498a456554be6eddfe155bb50e145ad0e24173daa9ab3aa808e156056821804d4e9ddf501379cecd91a37de9e2822e8465fcfd3968039c9d7617f685d6b567e8331eb117bf05768196b4c1384744bdf11fb824ea241386b882aa5c2fea9ca93165d13539e080462e8dd7ed58ae577f7d109fa864bc958b80c62cd5446a0048193b63423028291dc40355e63030988af8298013205330e292108aab5b29a19a0b5aff56e8d71c55a604fccdbb78f0b16443f3a4ecf292c57d72a09786346c0def2d97b1968c7d8313da150becfc0fe7bc2777fde63b05da1eb7b7dbf07a6c88e94ba3a1f03025b8abe363733243480a63fc68e687cfbeae555da8767b127d7a2893aa1259b300edb46d53df4e7659418a556a52c5920109c9f320448afc6567ea2c496f7340876e99bccebcef40f7653a7f66e6a4c53b893fe5a2009406226d119f526a6fc15e1aea77e505f8d339e7c0cf4f5ccd1474be0b49b629e27b07d754a056ffa66d8392384854477622ec093c2d16a9f430048743763acc2235bca3dac5745ea0b5dc7990ec5225eaf13025aba88319b8917c00e7c965fda36716122173659fc954e104436f86d3acba2d0052edb0d3edb273f56ce0fc763da0dd818e066e461f39e33892c72ee57d709fa22610ff698985a1a1095bd2ddd7f106283bb1c3c063d3e75d52e487fb56a4e3f5b619db7cc165fda958e417e86fe04018d2fd5347addfe9495bc39c26ff88730aab36f53c95d93d99102d0462c1e2837c27a9b0f4a2c011c5ac55b63c5a70d55f257e1c00102c2026c1f92451dcf82fb3c512f01339ed129472b9eba077b35aeac2acba39df315ab46ad5ecfa8e5a658ec4d0691d2b1b9d8578a341de65e918ab7969246ed3e790fb3d7753bda3bb855f2a4d9eb42355d5c68fa928ee2f21690d384a72576cc5a6592e5ab629968deb8ae9299eef30e71f77d135e77053dc67166059d1dcae2e723c345ffa14e730cb6a18c1489d585e255e300374afb1e1e52f41fcf72b43152346770f28c5ca6c35aab04bddfdee2180b762a55182b18b7978ab942f989843305303722db875219f6b37360c5d5f4bca44bd8cd199f3248b9ee383105f82822af392fc5899b175e32c11e7cf8f1b29201940e26d9bb189dd8c46c7f37a3c2cdb94496cc166f86a4c8ce1f6a91f7b178571050cf74dab79250512f4a84eeefe96d85a97159602049f5ebbb8e5cbc15a89cfc241277ce10fd3e8ecfd8ff462c7c5ee7a7adf5ea57acbc3df8c80806661dd31927413f43cd8d84e6768d3b580be97e1137bdf79637c4e672684a73534c8752cda954e4d1ff352eb82409b14aa45b843399414aa2c8d3f5262565c59cc7fb26ffd88cfe82e764ade5f563db295962cc802ee3ecbae87d3266b915835ca38a00cf7d64e90b5103305b91ca9ac97a4e274327f7899540163db95952ecfd1e0fd8bb1969f52558327a93e48a5108ba76add9e94e20a5e2a69f19d192c2c6e840acbb4e3d84b4397759a7e6249e011316f76d9fe6a918bcb411d2b41b12df3e9e968f404c52385affe1025d32b530a0dd0d39c96fe17fb80a274ad549d2b69565352fe67a0e1cc3046c2f4799e360b554e519a2626fa29fd5b4e5613f0663a8f4b1a4286d80ec4838efda3cededb362de4b822a77eeb2f37b131a65e17a8b25e36343512286e864e68545746ce255cf4797d92658d67938f7484cd525fb4e5655692e70fd47088ab206cb071cb404460e22a611dd0a55501841daf09f2f7cc4fccc494029cb99ee54f78eb4d4489a6f098572b209f7bbd6a8698572b67b99626d5e081f1a2da858fc7003980a9b5fd2ec77f6c267d9c0dc23ff60f0aecf26751ef29cf65d8581206fcae001b5766c889e897218cd00b372d9bc00c66d5f2edc77bb1505b9050788d3f559107c4efca0f66b09b0c4410454668090aaa52e3a1a918457e0d465874789340c043b121f0adb07b02fbb6510f785b904758ae1e0c215fa40b9ba0f6ad7925dd69dd4c2a323374e9705cc28d65e968a18e04d2859ff82e759d782e80f600fa5afaa0ffe880b1484fe3d76fb75845eaae145eb57f633d5121d451b1728a69a9c5af05b439e133bb78f4b59304628102e95f05d6eb13d86660d4d92b2693ec518d4f24e69462116c39ed1caa37fb3ac88dbafc999ae7477069a755e2b1c00a00890b401b74619f5d114def3ab936b141edf19dab04b1f5e4a179ebfb9e20efe8cc679e0b9a499a20c06e366bd890a83673ebcd551b957ff936a7a3e36fa9cb1152fa10c1357a4bbe55b96f925949eaac849f515363155f6db5b68317ac83ebb0245891e936cb82a95a4ef75a1ecc0945829cd5ff654d7dbb97b583d92073890e82a1cee2e3ab77c1fbc14f6898c2e40b5e0d7b32f6cc28e51b5103d8c341c63a01b1ad6a431858ec1cc9d2c1fb93c541af46408be1ce1ca9eefb051ca708b3e9c54f8fa6a6bee5782043eabc72d5da51feb40c9a4a2cadb452fd0d36c93efa3538353cb11c35163e4f888300653ee9e65baee3842ca51a54d716c6000ea285175cc2d1710f7a7681c273c022aee162427bac6eab5a74b4e7a5629ecf42224c9618824ffbb6c05f61f534ce5e7e81db01ae6c6c6bde41f3afb0320eae94784d0c414738b8d34a43088115281d61cb62da069876980e31eba34442183578e00a47581ce3706640cff00322a8461865ce796d021b632265a879af27cc3a20c5ca908243521449643a78a41f721ceadddc731d7cf020e063898322769075ecd33a2c3154a701a5def543de939b43c9fae25880ed4aee9f37ca20e7382ad469b1e0981d4d44820ff8ba2569149d634b522c101630cb9ed80c17d8ba19804a392912f77d9b655cd5800dfe7c2c654cff4d85eb3f6ae3707cd52112cca670e1e44e5454ff71e865da547c91e50b317050aa0eecdf99bbd32cb97d6278d88a28af732aad02e31609bcc8ac93511f17f95070fc37aa7cfd3959769da931638300842cc5af97376faeedbb31b084d53401f55f64b7086531094b27c48ad0b115f0fc7d959b1aad516856f95dc56328609ad27542970e4af282a2f61f6c61ce69c545b471ed0eb041ae17e132f7565457e8498fbf38151296f96016682f0082e220ba5abb0ad8ca52b4766680915e205d1650fc50c6d49e221c0466fd643b42d8d6a953cc5e21d048171df599aaf542f542123b0876b620d46bab078e6a37f4b78efc621d578e20948cd20b3be2623bbbea0d23b141fa102beda7e8e9d0839d2f023bb9e1914c9d948d7ef0fc24ab504ff7477a34a96fc6e1537bc6ef55f27d16c6368ab5d5ee7baf994ecdff8dfe2bc37047131714e25544b864328dcbf92fbb02df76096290022fb461292d0f4d5a4366441e18e9a14663a3a7905d2bc41aecb4723a16ac95ee7d59a8e5fc27a1c5f4bb2ec455cd460fa4d66b969afd2f0b5f47a88bf03102a9a62c81f8ef1e566f76a371a29b8c37555e214107bc269e562a3be6a619a251e80aa37d1c38a98c3c37094dfa6abe3ec47a2bff90af5bd31f2ff3f09f3a511e9864419bf4e65b24ad192481e28cf5382561f7fa38bc4eb88277ce3c2ce13ca49203e6feae0f0bc5dce32e6f9d0830eb95a7e8f43921dd360bdb4ad3c9a3135c8ec7abca027bf3a81d9362d2636958dada1f680aa2f331ae60bd0ea70c47fad08269a001c0138a7c737736f6d922ee42f9a7e596f5dbcd2473e108515248ce9c145bdd5f9f0acbe52735eb53ab092b4cec5585736641df0a60c1cea49392ad29a34eafc2ee940c7d2188cae84bfe86dd965d2a679efafc4153d56135b01ccb9c6d9d30723b64d6a853e114f35a4fb3e000b33c11f7219c1bb869436d5af69da81f80814d76fe7f0c5fca346c39ac275a7fd31d298f32da0db543b302d4559eede2f7e60a5d2a423954af3c1dacc6a4f4e0954e37e1fd89fa101f722b4515fa9628415d97688ab1017788ece393ffbf7ffabd3f92db0ad9773d0ec3a4f0cbedc6e1513acf1743974cfa4fa90a9922249bb0b1bbb39c118b044454f3ad1d3a0ab774bf8c2b5a240b743e59534770ddab84191454f3a8fd320d7583b5732b4df32e06c216652613b62a1dcce0068adb139471c804184403b14984549e8f13e54a710924fe9374fbf158cbb00ff93b2a14085888873d3296731cd618930c83936ee610aefe6bd85601399d5b6d7f86bddc06b5b1fa10e785a01a2b8918aee9a6f582735754bd3d707c4946a153ab047e5e89ad969ee922fb55356dc9a04cda997c3b74f447cff8c1f5dbd52290c979ffbdcc58f61cb00dcba292582b3df0979d3a0de42b7417344ec426f4129538b0fd2585369a6c4c55a906501bf5ebf5881fcc9dced7da46b6e02cdd425b45b480ded9e024468136affe521a0054a6b2d2b729eead54be36f5b7ca2f417220ccf6a4f44d4a3fa2de432ec7d1036c7e2ee052852f6d6f3f96ff24189b95e2b75ba4559a2c5fc3ffa13a9c3669a9981a625e0dfb608c14e722d7261c07cf6954b81a91ca482a234746a74cd70511b825f1a0bdd9ea4a2542f2625b3a509c273d7b731e77874b1f13a8460e72a69faea0197d0d5d5ed5b438db26aa7d8733af50e39b2c70089b8a9eecb64ba2b43c03bac29bd06c38e5cb9cf68b7571beaf8dff317194f2fca4927c933a4edebeca13a04b7329c759a5cc1377e7433d9d9b9f146dc435e749141173c1c3151ba17c07ada58e81876332fd13d055eef69b415ac3044d8cd3477e8cb2462b356a890be8d8779228078e2c5a383db483dfd7c6d00f0ab56c09860b9742ba8432ce6136634034fa0cc8e0adac49a90dc65c2e65d2db22894480aaa79763da47d231b7db3d32b29253ca247fbc9e79ff5b4bcead3fe2dbb4a52f8fd8248801f300a4eb1e51fa0688d0ebdf256938b8e2a7d91a0fdb992a9040a2c44a01d1ab23778ef4adf57bb87e1e92160de955d63130ede951632bebe2c5b06547b1bdf19d3713592511d312c54644d8fc2ab932aab9520e231cf1cb27c3e89c7ae3e0c20710a3b714cfcaf95201c5fd098eab2f5614b29238da7ba800fa3497cb66ab5eb6b75b7c02ac2588850a45841f97f5a64b19a45760657ae049040296272bb09e23e87c140543f7b8a4d60a529a51220df11e91fdfc1af002b12efce7b9644376f81e4e94dbb4235d614fce00dc3fc299aef5b940b75290b37b44c34cd2da3738234fc0b20e854100fd1bef48cb9744699af523a2f5144d66d50af156d92384167ea8ffcd787e1ec1b6f5cf7df126fd91e1b4e585c12373fd325e03bbb7190e9ad4e0c72703a68b68271defcfd9677b23a166d8c5776b027e2d5ed02535c942be13dac3a7d47ea7c47bf3c3fd8b106c6bcca427d33e9f595117e0959e0d161270af9132dfef909ac73c13a8fb8bed47b81dd9f3f2d8e9f15d6a1b70654c5033a1c55ad6f5ef997994d3de619393491b6cccfe6ec2b57e9c2fb272aee196dd7f22e93b99c863df54403fbb3e27d37a690509b28035b554e648da7c33151fdb5438ffc63cea2bf246910eaf0e7b4cc88b49a99fbe00b195857ac0e129c530a377cc80ac974c74b83e3913da4066809261a5e299433f05dc1e7923093e7f8d29fee14f9006e489dfad5261986b6b25892ba0aa7312dc2b09415b5c4240cb05d620e36ed118ffbfb7c33191306a96d5771ba3c53b94d4408e44222f4a2987803e1f2e6f6e45af1b326f8d6ca77bed58f5f298fec58a7c95bc55b090f95fee694081fb536004b87eda39e5335896d8837f8134379cfeeab19b94d1da87f18d1fea951b53fa834e22e8cbf4788cd6a4480ead97250c9ff94e4dbe6d2989d3f7c9030f51beffb77dfc34691a41fff28718971eb11241795a55b4449a5eaac0f778191f7e6671662701284d9fb2d1b672a17adf8f0b325b78580f2444a84fb2229856a08f5dbf9322c554652c472af56186ad44d9f6f5b0c1359d1c6d58bec2ed66a590e9722af0e2eb8534fbb20027e48938b3b053aa5733d2f5e7e68286d5070e9b86ad911eaf8610df35c159332fefe83b18de39aed770859b1b86fcbe3bce19e14a480006b5611d98fefb5ef8f9e7d9b3521d382e375036b30ce9329529b2c011a9828f0e2b17ca5992706f440e076dfd2cc141e3ac2070ff416bbac3b64c39586f4ad65cd9d90329115c4857bdad488267b16e0420ee3c614be0b688236204bfae1a628ca70f5f278a9bdf1a781425f19c92cc873413f1db021648e1ec950a809c0cc8e58b1f22e5896145002e3e7490ac94dea751ed1fdc1ffe4d0d3bbdc5e5a63fae6762e9cbb2702ad62c5bcfbcd0275df23410bd8c5ffe5f2a4f97fe98b8f8e8856588097f04c792af45db8b253cf2cf06d2e33103aebcb893caf345c8b90d99278ebcc5f38ee0b03b8c78703db3054118db82421df9b57a950e57b930b058970c77a8769a0b6fe11b9aa72fe68a80f45f001e554070a4a93e57feb6a10df68fe0839b67d6a49a9005ca84d753a761d2b653e6b4aa93628be0af0019c71d4ea2a6aa5777e8dbfaf8c685c261c318c49b5a63ca5db3b10544371c4e6f26936de4e7c90487472b4c645903751f6ef8f6894c587da5d8fbf2b5a28946601feadbc986dd8a6b8bb6f7a66af8fcd635d717bf51c3118b59fb93081cb23f90ea6113e67a1862810e7faa88bb8adf9a3420800c52969d6eb0dace5bf08091ec91855500f6b2b4a0944e62db48ea660bcabac290163fe8783ec1d8b3bbafecaa9a3d1e701cffff9ba6f6218a13a5bf0a15834876bc7556cafb4a9d139d6e95ef58fef0397b9e0233098e9418ed85560bd6690a19483e2af3b3b7125a7b2287e790e05af50b42a4fcd8d9a12166d257af7c3abd6b2c68308c824df3eb9ba69e2da4e2eb0555af20f85be582d761778f92c40cdad161e89d0d682916b21bb305e5418e015f5cb6c06ed8edf466f5470c3e38ac21b9868ca9af622cfa6cb16818bd23cf28720d534255bf1eb29c43e3c81b61493299b73acb33d06c14be46e43ec8d2925fc44cbfb40cdf4d45d2a10cd6b9e889f8fcb13c045be5c9e3dfc11f0a2a465839ad7a0a415c2c30c3af27670b126e782f2b9dcb46880f27a43625cf87455c5698edf8bf31039354d86ba908a5ca151a6c52188dd9ef4133e3fff4f8edb473146ca5c67ac9985720115cf853d7b185b12da78335876a854fcabf7f233e740857349be3a8a39649e6640f3d7c7ce7b1cde3a1a27a98cfd91b37edecee14c058f4c0552aae300133b1c6642b1bc06ddb77cf77774104f0b1efb892f9ce0ca69510229708223dfe994edde5b792d5d960f8dce8e02eb7d6844d2dc51d157d5d63f751a97c519f3858d8cf1aa125b43e5d23c9607f1986187d7d583a97bdd28e1887d3d49abac8e2191ffeca0609aff1877514b905e7a8e6a989560abda529a4dc48e26faed7b2fef60fc823b92d9705fce99baad49ab95dfb85f1dd3474b3c92231cfbeb9bed3d780a42fbcfb222dccc7ed8bf02ee691fbe48d754a9f6bc1677feef36dfe184f8c68919ab728bcde8fefcdb441cb24ad1b54449513b6f87dc91cc3b0ed00ff2123d12a54c913d3fd02178e160f5ab56aee87b622ad99362d7a37672f319197bfcf45e97a20091ff72e19c0242992bce3ab55517c8fe94df26d1b16ac8dbc764bd9c0d5322cfebc20f2c375705c1e02c6337c09b6d032cbafeb30acf05b398ae1239ec192d8a3f49f3f48f0c7c64d032b6b7c49e6fd3cb01e0b0ad634cc35c729d59bd224f81cb342a6f58e6eeea903ca71b992bf38147814839034aa0290dc9bc5f9edfd8a42106ef7fab25cee24aa01d0ab9ecec620474c054247502f788913bead3d2559eaf79547205dec18e8050c01bab45c3fa01e8bbd94ee39e7e4111e10aa0f088b83a0530d78e9af5e7f897c8b75a87094692a798731dda56d6db32cc6437f717930b823c93b0bb54fa4eda11f68ac1c8511d85c3ab85025f800cf6f1b30bd6b0698d32e7953ccc8df96deee47eab0d973b75f6ee1dda4d12ca65bf577d64243aa96fa4a23b0aab424ccabf9181f8fc796477e1bf518361a705f44c0997423dc4178b3e5177e01b61ee934153e72843f90e0cb038841461ee0a9dd1c4b6a5865f994e0ed4e8ef17f3ae6dd81618362553ec4c82e79e9cd6a28dcc08b01c12021edb0de622ec517e3188759c009cf39c99dce9f198c97ecc5c178e831ed2bc14c42f5a4448b346538e38d3af1c63c717fed3abcde5249777ca524d63c555357a55306b83cbcf161ba9c8cc40c9e7c8c56cf37c86063f7701728f744764c9ac4a02c73daab6f9d778334fc7436853c51696c92493f69713518508d814c3e4b9031abfbf6f00db522e534e27bc70cc6e898d0d38b4576b94f000f4f150c1b8d947092d6c10f4d019e23f4a7e7650eadd991041e3363cd35890b8e22d72be8b3b9c038b4012197e9ef68df121242ba4c08cb824dfb28174d3e243ff0034eff232bf05c5426bb9f953a854acda19e99f33dfe5638d54b6b16670c19db4dccea85bdfcfb4b8687f81ce873ed64d3e3e1f4c2ea0df642f578abf6cc4e4cb4a71b5bbc11a7aea5257b05ed844d4977c643ea7723625079a5878c830f172e87ec0c4331966e6d4c59ef9815ddd9bbcd561f71a8f70ae4fd8daf4467cdc710911c30d4f1948e7076761699664e7eeec0431925cbd78c6cd170f33e022dcf147093e871f4a50bb234d800a2f27b7cc29df3a2ef92d4879d4697c567a0a9defa65f31baf3a7bf8207e436394dbcfe2ae6b76f741a2cba489fc5bd48427bbf6a24c4fef78ae5b3ddf9b425c529753e4ef7a9545b65af10b964fb6a9e7913f22ecd3cab772bdbe28c05e73acfecf73b000cada683b9615447a54839771794c42fe7c5d9964e4bedea74d2f64f2bb4b343a9df2bf9ad1c9f34e938e4aadfc9ef13cd39ead8555b5c998938d545fa9b7aa168beeca7a2ea41cc883bd110bfbff34276251b3503037a9fba98d8a633187a9ad00340ea3bb84e5663ddbe85a0dd588410148b3b9ba87cd0c744804d645735f884314b88f5beee86f9d8d371c20e293a8ab3b2d236309dad668ae4174392efb181e9bd5c6cfc5d7b53e73a0c687f0f76044cad80b030b324e7146f3e1bc792e609146482ae796976a4c1d67dcf3c354e07e31668584a9cf38f483780f1e99da5fc0b501e16b2f8a04c1abfea1dc92b3a9094c7591fe0cb277b6984c7832c6a875dcdb96a7355ed51946ee848673bb6fa3dee32b2b57de8460b0323fea9d4ec49d96da198df3bea137496f05dd5a0e4d37a9216e95b3df9e37285d6de053ce093034b68c1374bec1a879e090cd6c72efd345e411bbe56a6573df724334d264b267cc6aa09130034746351e4a303157ad80aad83e2bec2ac64c9f4b2c76f9d5eb00376b0804ff123d3f79549239dce5bd88b5eacf3c46633faa89815b7adc3a9735d62879d189062c5bb51b6570db95bace9ff871b12f5b9038a675a61b2205ecd2ffdbcda62e6d0a5f9010ca25747b0a3ae540ccfbe3d4dc2a0ab13ea6736c9243062afb210814cab29dd2ce929ce27bc5c0bd812549edd07ea62454b935974d4488c453f721cf700c08a10e37255f545529b0265ed388524fb7f86a4f1a2f8b8d110ff520da45642c54d7aefdadf14987d1479a95b11a528197bb7e3bfb137af6351d4baa30438e4dc9ed9dcf425488c108f4f0c4cb137e66fc18fa55f190785776a0b355f903669d96b4683b39093a6d9c77fd3917f5092734b6f1a9a561c9dcb0c7b9291f0a178d4164a5beec174378015a49b933614b2e8861e1e148d637a4f97195446a8f61972b67801e1adcf79cad37f21001ba5b31bc0e44fcfebdfa32ae9b7a7dec4ec3b8e5092afc64fc1563fef7adf69ca5805569c888a558336647ef32e7d4cfdc9a2336172bcce3a5230d6d02e11c82e3eefb274bf6fc7ba79767086f1a34a50856e8a7fb4e8f20c205c6cfbcbd0290a27ebaa76c8192bb28732725852f4e0b5e685ea9ce22b10620ffce58c2a6db3936fa59b54473b58c3eb1c373e0aa790b7d9f9f41abc80e3bc62b583bd29aa81efc7c30586709e6b9f38ebd5e03dd83c35814a2bec905e1354fe364ab8009f9568e75dbe58222af10f794ffde0458fdaa7ebb97354c6f02d5e8d5a8be02c9273b507727dbd04975897f9c8e234b13a70e22465db48d364404bdd4aef5d54f6cc6cffe2cf70663c747c75284b14b1516377b5a8d67e29d3139d24a5382134a962341d43230c66f608e934d6b284e8d3988b5f43437e7d329c40cd405c44e9048e003ff73d4aca4c9fe4c053e888dd38fcfa3d2d6a88f0397595f32c6e18b88ab8663857f5c41e93ad3a1df6e27e6d0292e478dc6f8e10187ba2262fcc156affdeb39d3c600b578656eb6ff5faa86e15fbaa91cf57ad561a9d0eba6337cc7e3c366e9092c36457a57926da1bdeb3b122708f19991feea6c13b147a451df681a071fbf2c41de91f865d4049fe3dd29c98c8e4d2ce9dfd3b294c8017acde5aa643979784e1566d7221ff7acae71d8667813013e6ac617d63bbc77872e2956c418f1a10ca7593238299f24bdb9fbb5c8ebe205641e75d0e8b85b11b6dc57e0be057ba8ace9e612844bff75d973e7c632e57b2283e4c7a6086ea31fb037c8369653c8513aa0830d9cab47fce14ee966b520bd5286425e161f6cc7fce0da2b1351118a13c394775af0aaa58483b14493728ddfaaee96f49804869a26cdbdcd23baac7f9ff820faf588f73a8857b938639023feabbb2aae1953c4909a64497fa1209801a498a51074c95cf77579df848a31865fc394f30bf68dff472284cfe2f0b043fc52fb9f0e927636e7b5fbce922a16b96983bd2b95d51017779fd6f31d44e77b0cf6b5a8f9ed5986e0efa3e961a6e9c91ef590e52afdc2e942f57b957fe40ef421d77d04765bbd795a703e0530f2f34020ef643365f6212fcfd112a29be6f9ae54d87d71960386f2baf4b91703eca61f74000f9d8518d7cecb80b95dfd0818923a5f256d3bc881fdc335f0a112bb7fd9f160fbd91c1536dc7b12a4ce77101398a31755da91f9a2b9871cc55759800d0aab556560ac3051c6a1e969704a12ac2072bebf0f115d10a3f825a8fc4dc700f3d998ab311e4a2f38402c2350910d9125b9e5833d1103ab53638393f15f3cfe00f92ed621d9b77bd9c026233649ce924c6aaa6bbc174626f84a0524a3380e9e2cd9c0f6cf8fb8a38f76affff10afea89d9746a6febebf70ad7aaac1cacebd33aa2d419863e22d4eb0cb7bf98738c40354ae8e187fab46ca5a2bb540a6c30b0bc1ad0670ed8f112740883d9ddc20407cfc560b5c49a43812a0615b8bd8f1aa79c7d9677a6823f8b8cc8e46ba08c158a5b826ee46406e21c2884b54938cc9dae1e6abd0d933681cb72a922c1945f434891e9529485d8a0f2d4a245be1888c635ed0041e0571c112edf7379657bd02edb3604623060b37d9be7499ed24f40e710cd742688987c3a629db429d739b36b503ba4c234e6d7769bcf11c6c1e3e0a0160b81b3972c6364a95722e381144980d1df9040c9f9e198cde30cc19023179edfbb21130e8d93d54a147cf245bb01b56bc9651ba14330f3d57fb26d727df6cc4c9dc492feee249ec295c7a04d8b1576846b29ea80d17e6afefd4c005a18746c5cc8a436ef3aed4700ad55045c396b585472f724970be262c4259935da85bfc40d60d0a93a89bb5e7946d342913d86c3b81390b944021e7d4a280bbd3ec45434fbc6da17c3f6f76c34e3360d536cd97a1e8bdebbac9d7b17c3f2aee0a2c0db0fed3dbda8281d5fbc48c31dbf3788c9284d11ce5c1c89849e01395d540bc5b3d899c68157c44456a1e34a57a87c2009724f149993187c1d7867081384777b2a32da95939e6f3d189f1c9d7152b269bda393c04c2063c268d29d8a7a957e1fbd80417cb85e38767a853527a998b913aae8e0411e16fec0a8faf4fe136e278edaa595f3534586911143fbdc4a5c040067d5b2ecab2542ee80896dd144126c904a1766822a02d6ac22c299c9bd292ca3aede53db7094e2cba2821684d0b5f4ae581b3f9badc13e7233c6210ee0c251e86f62db001a90749bf9c4580316a29caa3cc195423bcf0b4cafc8c4af0af6771ffd7513b31dd89ef8c772485dfb41686f92cd3941df273a293bd6010509fcffe3cee99c26744d2382fa0a9740aabc6635e31dd48bd440a968746e5f97b67c3f41c7e35283e520f1e50c4560d917089f4abe120f85417f1c602e1e4af8d1db73d23d691e2b1f93a14b3e2df815b906253b64ddf31262e823e752196ba2071ea22a448f9f8addd05db9fa0153c6c274fc4a485bc0e5796dd1e1e5fb82a2cd3c88c6ccc194ebf0ea867c88db2da0443a731e23fceb8eb084084bdf1b9785f0ca607bdef3b3c28f78e55e28efbc95b8693348c877427269fd7b6321730ac393dc95ecc23c9cc37175399d2d8602e6556b97e426d6da4f1bafdf7eb280813e01f968e9cee7cd9dcc389831d44289c22c4bbc2e04429a506564971111e9285b3edd0e102b1dd6d20e65c73d442677cd32c8a422fdc2407d27ee92398966981b5617e49029e992c0daff96202e163e19f38c19b5da56de7f2b3e855ffc1dde515b9722ada399274ede13d5a6956cf7837749de6a322a86a6e8cbccc5ecdb3adfacbea8d455907b87d466f6a6c2fead2fdbae7eac3490dfe78e7315f26cbf575dff2eca2bb9e6c40cf1bd93e682f5a4127abb1e825f1bb166ca80df9616d22406d28ef5bb20a833feca0bd92c3dcf8530178f8acded12f9754eb570f236ff7aeedf620b491052f6d4d9d2c61fdde387034f8baf80fdd985d57bdad5ae393c2114983992fe4de81a37cce1b5b6e5d03d850def948f068b4d27fe6767131bb60129922facad0ecbdc8e7df91954e7c30907b7503a8b35fe220c6ecea5e0f524e6bacf445ad4fef7a31a6921d211ad16639cbc34bb2a2c2e28bf82d40db44875563767f7feee50f5c16b0cc79fb9015b66d648bffb3fa72f62b940fa6ad888e9dcbe9e455fc614682cbacbd91aaf5fb95e4d0d76117c631d9b4a15ad28f1130b05a7a853fe2e64d4f4e51248d1d09685422cdf4e110fafd8732f2f809589696d7351615257051a60e0f9cf3f240eaa87bcd3a5b8a258b1b19eb4b568dfbba5e14018b120b0f01f0e786b93497d0ef674d1f2d5e5dcc32955ee85473ccac9e13dfd3fbca84926d48c984e9f41e5179add983d1a70653c5eefcb1b12612ef302e610cd4a637e946f6223fb2603f49e6bccf10fc47abe43842fa0ca449008abab34c897e74b49cb6cba57048601199537ada51a6a458693fefc5b75d58dbd4988bbd492f500f7d00bdfd342d820a1471f23ee14815d56b5d7c6239f0f0f70f1517c7a8b36de07f6c62427b04e059f9dfb65d626bc0a6ed58807b00b2241e1da33e855640f456082637153d49321cc2e6eb85560d357f4c42b62e88a1b281194a211bd11f331360349549fc9a3b1f36d58f8876ab841f8bc233b85c6c94214509fc2fd5d98a763c1c62eba0a87980a02f63f401a36fde197e3dfd08f62cace04f0287f06ee830a9424d6166d1d07992bfcfd4f91e02daf2869e95697b430d569575f9158b6bbbe1046a08e40e19fb1bdc9a70e5ddb5f3012b2b199598c84de4c3ebe60207afa6f2f500a15e3950ad5435c89adc8b3a2634f56b1458f1498cc9b811c4dcac8abe738f954f45b0016d7300d62dc1f2bec0817a05589e78e5f0b7b3d9c73094ed3205ec6ddeeed09596464328730795d7eaf102138e70ded3ab4ecada677ea7f6be7eccfe1fa37e0712ab605c0802745d5c2f61bd4f720bc12c5ecf3c680968c59b8abd8bbddba0cb6f0c52cd7bc28f5ffc813cfaedaf7f2b259783be66244cf89f40fabd80168de87e408f939d42c1f9afcb4e638bd751029eba4ae6e07621b196310ecad95189e7c7053314e2f2b433451a1d70ea7589a283f25830d373beca7378c43c30b38e40ba92e4bc101085a1496fa63e0226eefda58109c33f90624fb40fa34db777abad28eab975994d30c86e9ebcde7ea6c3febb66d5620564d6d8a88a2162de3dfd07d69bd993eb5cb5b65fe3f6e1344848728df60be3baf1b7638cee8e02642ad3ea8294eb166df35a09703cd8e1ca7103b1c59d9293ba7a9548eac974c833e2256cc5fe8af0b333c9db1c1f2d351bc8f280e4ab9fe42fd48ba1a9ee60009cb68190100604c2fe1015426666bc3aaf26f8e8d5922ca44c26d81af0f2a703455e52acd24a3f9bd93b912bd80b9238c9798ae9aeaa50f38858aa40840a4ed65cf9bf75b7d0d56c07a68781cf93e75baa5b5053cb5d03944778d9dd74eeb372d0a88fdcfb211c3447628518a1b4cc15968006ed432d1341c259f8976d6168d95bb9e4bc6f03efd198ae5b19419d4f65b43f8d3a914a7bdd2d55edd316772a7e00df0438e0b7710fdc747c023d389ec8a8fd280c9ee35921ff155763b0e6267be4ff5b94a0981705cc1d6580addd78e711e88eb37aeea20afe2cdb4801e2be2db3c999450e44d5b361c08fb76ca4aa7cd27e1cc1b81e354cfb99c53e064bb50ce337174350a54fb55ba7752f17908c2d2859e82b054376d4bcf95f10dc8fbd5ef316f8e04430ee50ed489ca8070d24cc9ea689e1c8b9a5c0ecbc5024940e5ef6b83994151b7c333779b80ffbe5268cdf5c159369ae3e8bbd6251b1f939cf45028ab2997253e1c5394048cee1d0be4eef1e6e1a0083312b8c157484591898ff201b87eb7811463f96b8bf4d5cfc835960db71ee61482ef550460c7eefba06cd3d6f445358719a4fe9d9d4f0fd036069afe2eb15979d59c8d54077ab7fe0158de7408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Factorial, "2710", "0", "46ab3ae48966202d0fde097bfa88fadc512ae8afc0ea1d1d376a4109f10105e9e21f1e907151e85f926b8d82737b9030d572715fa32690be8dd16867f348b981683cda4be4f9e259977e69c16905ecee567d26742c1ba1cdfdd1274a067c3b39020f8d500f1199aa73884607e93fe423a99f3646585b76278922e3583c349cd3368417a0e630a075839ec290393d2f669d948980b23bb114fac5d62ac52e9883c9e3b8e0cd6bf0df411911f40d9f968f8691630a6033e9972c3090ed2c0ecb3a3d8ace0be058877cbb7e2bb8e9065af1d1eed955881cfa5ab0a4e155f84311203ba7489fdf5d08cac67c97920e676fd54a972b0297285841d9ee665dfff40bf3f162cc2a4ac74be168d996eadc9fe38b406af8f23cad528527097e4247c49d52aea83abfd77472110ad2dca4c977e104e041386a942d62e362e968b12bfc2549a5a3cefe5bb6b799e97d12f047aab8e219751f940689c3278e3e64583fbc3ad07d44745bf43feb42a8b7a860906dd98a5eae125fe7f3a013383b23331796878a2936e276a021f2fae759567bc8a261a4f1b8967ca3dea6d54ff6f97c97c791dcaeb6dbf4bde55bfaa1ceb679941675d1863a9a730e380099157bc0887a09e4b3d255dea2ce3fcbdaab5a783d0c60dceb7be6194d9ae7dcc515c4394cfa8b0fc765ddca6c64a5fe82883d6d2340f71ee3ca84f60339742b3ba82b5f05ecb540fd7e9a97c0a78e30f26307137efaa9aff7d462bc617e6ed6b9a9ec63728d4cd5b1a7f6fea10db84925e948df375d23ef6f7d912bf9c9af213874975b528b10fe2b791b39d1bf875d01a65b3c17d97ad2fd2eb5adc8a8a4b9516024e92a37ed14d6f087c5b99ac523e7f1157817eae88373990d19998b0a412e8add60b47f61ffcd2336bc3c137857c698be679024789ce95c19199b13a783f56a7e15ac38e63155a08337a9d4305cf94548f6788ba19af84e2c25578a346282e907c3380200a1acf5c43ef3b974da2a962acca9caeb1bf88e1c4d91d1f38164a360cb6f5fb48b8d18d9316023f1bfa0590c4a68a4fc49d4a17ac7d96dee097b3dc5c9e960636fc9a8c6220e8f3d6d0d7a79dd8861263a876b4b16b749c4ac6b4dc708d08f20acf42cbf98b7f4b9ece0f979d35f2c1dda29a8c313e23dddad30013aab39b415a058a2043350ddc2fe9ae3c66171fc1e8c54f59e53f734388a013b449ee0dd9b5eeeb432ecf6e60c14cde94916e0154a2baf84a3165a28ccbbceb5017504673bc32da530e90c8d074dc6f2071c36042d41f8decac8968a61445097cacf98fae342ecfaf7f567eb7ed8d11486c5c5290da57b6058d1799ce94330dae1e672954e134fde55d5629aed6f499ef81aa7c8dbac75ce7a391f23a0ea37cfc1509090e5d67b3989a6d01535e083b499bb51b2338f598ce2ad3f3fa614c2ca084442230989f8b464af87bf519287198f75949eacd7c245eb00f1fb2b055932fe4bc6eb0f7d6520030d93ee1feb0ee237a1114e6e60a49f3bf5fdff37c3a136ea5f9237d194efa6a7d551a64325d4708e784755cbeb0326b906df2161b5438ff1f91db3a60318be09b6c19ce0b8bc2f5a8d11f5dbe8f4a8c8ff47beb5cf58ebdaa03b69d29d6ff0c68115b753faf65deb98d2568867b18081532da2159c817d0def17c0edf7194300dc14f751694964043934a350eb0821a42f8a651e4b66fd78dca89c89d1f8d1c12f30a87f4307c58da161dd92214ec84fc4b2846f6e8265497ebd458c19832584fbf09437df477fde4dab76e8a5e45b78a23961a305d5351e0a9335cb4473d8b8b4e4b08094e93063792cc1364272cf4df8953cb07302dd1bcea4b8da10fedb4e201fd24fe4d51df15f9681fa9138784167981b3ec1f2d1ddf31e441cb7706b553053348e79670de2a3f361c84aca5ca4c582d19ddc3431961929f21ca5d5dbfbce6004da1e1f43d44273bc5e9f7ef49048bca2752a37c586aa46f75c3556e40eb317671ddac982869d64f56b2d43e249f75a9a6d1cbc653fd797b3cc455e0ed6a9b50a8c9520390b14938a545bf5345d6ad4e1866ad9e97d054508a6e427f008549813a94d979f5f23ba1f7978569f16a65fed6be7acbe5c98ade564e6aa6cc142fd7b66298c9d4c336521d324d5f077935cc1399d886cc10abdc65534915cd91cbc2dfb0306bf73d81f4ef0443e619e40b031ab33c9960553ea696def99741c478a0ca7fc5803e47bdf766bbf3013ea912fd3b0aa35d223ea524ed2ab1925719d95b9dd9091b328a2333f50ff66f3320fc45a88855f82cafdcfab6d5a63249080e513974003149b5ec731740ce5b0479092eedb086fc3d31aba7ab3abaad48605e37d5e82ad82f3fb34d97be49437a7349671b730ce1c8be8b4b7ae36323c240efbbf98ec3a90e2ef496e4e1e1b028db99bfa5a8933499205543522715230a86afda04348d7e8b7702d15dd2bd96d7c379c507a0413d4e9f5878b55fea0b08aaddc25b4f42a76d3ae788f6ea6daa6bb7c3bdffede9016fecb1c11759f061784127c7da411a7da6515a8fc32d60a9bc91bba213bc7c6de230ca5ff5eb23a759fd2876817c42ac700b938fca3d0cf04537858c05552d15a90b8097f9dabfab959360f0b28e3709610060f4df935282a025b0d61c503220b69582beaeeab70843c2c59585d8b8c705975064c26d6540afd294b4b4a05a9053d0917b0fcdbbe6b85f70bfc801758222402f44303d562a841ea945c7bd52c464942738dff502183b9968fdee9c14f72f1143f2ddb48c372aaa8301e89ec506ca67b412548375a53844742fb70fca23796e3ddaf1b0472cf2addb4ef0abe6691e00bc11b637e5e819895deb4bd02431785ee0286f544578371e9829993524d558886c6607986e7b9f113ec7068998a173bf8b045b0585d065aca7d20d71b238215c7dff981310e21c6ebb4753b34b506776967a0234c1efdf988f4028e015c6260be9a69d8330f71081a36447faf7ea5ed5f9fab1255e4ac5b935ff77a58aacc24ea6a3881b75137377df9734ad197b9e4db8dfc6e4bb56ef57b13c196e064b34e4e53c0dd3986a2238965b1fbae3d2cbdd5f25f6060f48867b89e848bbe0f58a103c496697c07e6eb15cd1aa946ed19b79b178345db2b04150a73d0adec11c73675a7aba51582b460d89bc5a32aaed5694540ec894a9a574588dc97fa84bbdc03183b7172dd380ffef0d87fa96d1048d475f8008d8ae72484a9bfd04f8863844365d014ff0acda7af8f8ad80bdf7289abbddb4c7f6aa33063c758638afe3c0c92f4502c32b41c5b0dd556590cc4823805ca76f6a98c675bedcbe801ad0d8eda46a842235096235d29d11b2528e5f135cee19fc318889d0aa32985fd15c2fb32df392767fc3c50f2f793432a07ffee46fd84e98cb1b3ea2cfc39feab6f285429be0378694a3100cc79e3736bf815df3941133f752bb1f004dc2219c303301a2a8cf82c082563d4a93c9ddb1f9dc81d48020c8c012e9b1428e2b1df6086c2652801ed0df764ec439939843af56d9b57aaf5b3d271114be8625cc012196e0a212e84731f510fbc65709c29ec95271a562d8a0b29792e304558ca06875505c13413a6408fefebc8af202e1749abf62fecd8c7aa9fd2645e8b9a5984c42a99fade37e44f25e5fc8bf9642e1a87e0307ef779cb8e9e78459563e96feb51826391b1904277fe8f817ad0b01d6f8c76658843d4465bdb034ab84497ec0bc0e10ed700c01c51283fabcb3337f977035f5678dea02687ab0e6bc300111f788db415d4fca2d74aa8e5a1fbf7173cd4b6ff754a87cfaafeab973ecc0234bdeee4f15f8209f029d9e92d9040650c7c974e033c1a27c94e13bc7dcf16c9968b12ff921eb40124abdc99bdf9790eb802aaf89dafff148ec9d85d7ec90130bacf688e47bb631b69bb7a26fba906867cf665df8e8b0f4f5fb5f52607f07843a02ec44c88adc563724cf225e831169d7f1aacdb203faccbc589c3ee39235b246758319185a16c729bbceec30eac34c5b6c14b20d9ee7253c43c8925b5b04580a50ac16ece44329c369bbef09138186d0f5d866c93445e8fea018618ddff8024fac522a6e2aca986eb7c2a4fc9a7a76694ff136124eeae14c33413457063f7187fb4a95aad2b901aa5a37b08eb3d08e6404f27e04ca044d6ea1880a06596015213ab62eaead531c16a25b470f10f5bff2f5ceae0dc455d8d0b16a320b3fd1c43e4d23b77a1538e44f085293aed9bf9ee0f09a3a9dab49fd884760ac4838d644fdcaae3d43e3dac8cfe109d061052030c21eea94fdfda541af578bcd7177df332e2d6a5c24930548679a9b7991049d33249fa188e5d48b7aadb2081453f9cdfd633789f5f8508d0584c2d99876c913ead946c9c7f927b541e26ed87c9aaecbb147245e09062678eb4feab8913fe570b3b59fda8aae679129cedada0e258d697ba4a44676dc457998321f2e99bb24957433f4de842ebdc3b29c00691ff56c0293a15dc05e72c01dbbd1e836fa990e83820f4ab1800e0864fc430229baf0593c9690b935dd19958c1ec1372479dd89e738f553a994003c0d716d0cf6ee13bf24f9ebbfac05226105f210e230f75a60c919c0cd358b08ff280b85a259a68d916b507f0ac6c11b4f13e3bf70a2e0be9502030e308a12f3e42065e0d119fa7ad365df0d40240e04449f3618a64750d7be318122d0a58d943dddd57d1b95da2e6c42d955d0589d35a5c912718d79fc98e451b51271163026139d57b534d2f847e766999e69e0b5724b7ccb665d10c3cd8fdd3f56ba2adf83ad11cb7debbb8f699e432fe89b97abb7dbdc7877616d2a6dcadf6b5a1918479bb0bacf2717aab4ed45a77be27ae4d07d934a0e805f43b961c70545aba66e40b463104168d693f87418905ceab9b9433455564d4cc6eadb867cdc3008fb5554fcb9f254947b6b6fe2dd03a499eac56bb20275bef9b4e680a5fd9664a61177ab24588bdb131134cd3cc919614459796f2a387f903cff1a7cd91d31ad12deabd1081f116891dabc228a2cd7c2684aaedb49aa19cff2a68af4b08bdccc7417d44233884d68e47d27986c381b8fa4346906363e21e0e403e35f17b109b085b45c8ce32ca30f20d31c71050304b5be00617fdfce24d273a9b88e37fa9d2a30705387747fbf1e2ad21130ea10c652ec3a08b9414562b3b6aab2e2255e86d7125d063517441df00e4c2d44528ef32fca26c30a3743488691ee3a4ea4d3ff747c62a43d78912a13bc778943b31d154a4167b6b1cd0a826633ed39496d3d773b0c6869acd6384c4f31c531288ff5a46656bb33ea9122b269c4fcc9ca7b8cea33025f62703fe5cfe21a7f2c1e7346392d06e8562e8d119192a73f20fa7b458f30900f277c49ec0b0ffa82e158c5600a655b2863a74d24a245ac7c1be0bf0e3cc9ee15eef5ff6e4202fb837005cce72d678dc38d41cd04f5224ca9b7e15d640e2ddde831da01f70f79c38f865cfd1d0ec1fe9dba06085ef99f55571fd236a4d5a4021186a2d7c493d97ff957e2d006572f31932f324a4e49dbf63e306dcc8ac43aec139d505f3e0f815b9ef2be2340d3aad5e80ad1881fd1d28237cd2f40cc92106e607cfca4176543bd4bd5108e47bdf33383dc72f3c18e59fe5e6fa6a5d364a3d882b77deb70c8889fc9ae9f6c84bb6ecb1c2ee936c84b0785ac45d301b30cf5d4c438571a8d64849bbd99d934cf5b1561dc2bea6c2656eb3787f87ef872eaa59379faf661cffeb3988ea725eba5ad2433e43381eb052b20a1014a26aaf45d471722a632da82ce5f5063217353b6bb9b07aa657abf30f1557f2de74cc2916f4c44941942473afe31946d7f58999343e3a2661f2f22533b2deb5a1a04abd257c01038575dc79b29b7b7b8f265b0691fcb9bcbe1313206e0c95d22258d8f18bc01c9aa8c7f08cf3555ddeb3c06b30b9794d80a85518a84fe1a2d2845d66f0aec9c148dbcc2cf687b40e1abbb5d3edff42f4821fe73440f5412451c3f191ec8aea7953317cb4e0820322e5fc395abc83be3e85fae54ec77b1c7dc6278918c3bef9f9ebc4a46e1c5f68922044b50942eb00d981253a2eee3821954d534bb60dff4c7dfc6ea796ef28371db88303b23ae012eb85bd1fde4361782181cc57b18f95e841d87f31afed1ab5fd8562dfa2ddd54e0fd7344eb6120f767821decf414c8cf02293bd351d4f7b297a3b58c57bd8fb73705922bce5dd8d4c32fac0f06791c76d8a85e08d19bf3739cc6c62f77431b6f264d98c2a74a87f9c9519612ca28cedf14eabde3732b9fcb54befe49ded72691a9fe75e504f856441f7e55d4ff1f56d36774106acd0e7a7203704e4fe5ff1fb0b61ab765090001d92692884a41b3ec9d416f050e09ae9c277308ed872ad7fd6d13ac276c9c80ec92ca00fbeb3b8cbcb276224740bd1a49b456b6620eda9afd5f3c0d107377f5ad0dc2159796eb36480cf296bc6915c53d2d7dfd763e0ba0d24123e4093c7d5575c916cbb053356dd91229a378338d467e3f52a9a79ecf3aca1d0234cf654278e9e5add18651c08d6671ce942e16ff782db772f4f2660c583fd6409de2aefd2bacf1a9d69a5ccd45d747fd28159d26a09c017f3c5c17eb25d4b1d406eb8e57f63178fdadd5d5459cc27b7c79758fd9e0dacfa35b7bcdc1c131faeaef6e7a4773551ccdfdae6afa29eb62b2d5c13a004ab5332dd8aadd891a8ff858044caeda2010f08350391d65a5af5804d8686b233699fa59f5a8f8150d72a099cee5fba38fc1741c00867efad3676c2b10e86bc781b0adedb847d80704688787b67b91c17bd80a48b44634fbdbb448ad71592b525be28914fbf171ea3b21cc1c4dc9480f44c4c130625a781856c42825ccc186c689a2b0244c17f71d1173ebe9fcfe0b3cd02e567476294eaf606d85878a8e79ad6c784718528131e8c7407f6139cc413a7e8af3ade39e0d9b21051d4e9d9c96da56b6c19e3a9cb183b8d4276aba1e288072bddfd2cdfcdbfcc2d764c10e8eb246a5198aa32589b12ecfaabf19903976935437d546aa5948c1c99afb48c9fd137e325541a2388fdfe10eeef0326b6ff9df84f6ceaf0eeef036f7ac5b5937c4bccdcc836e63520b9db1d71e741c3574bda69e75455d3aae9a28166f4cf7aec8e2cbd39cee6cb8f83c7a4bac99ae51728da436fa3560d102a7cf77d56bb3fa361945d7760bcdb35bef5708e26708f847be6e1fd34aef155ba46eb8e3a99c759e11e03b4aef8be536affdfba72608a39cc825a5732ce170acfa863e801c41aaf911a1edb0ca460a0f609db69b797e669e45e3a7513349e8450bda1d725b2b7cd2cf97bb4dbc2691a2ab4ffeb8ff7a9b9b42d9d3d1f4b40f05c02979357029c93c706153ca19bfa5f2097ea71d695a08566e71802f6212a11b9a8273892494a6b4ba6562b1636187f019eadc23955eb84ac47d0832707a81a1cb73105cc592dd665d4877f93446849cf350a2f049c437160ef4fb3afac228c905e67dbd69c737de4082cef3af1508177ec57e6127526d19bc6231517f2a17d291309709406329b96f4fe13e3c8af3f299c1868063a6608d26315151a3c1c922fb4cc41641bd4935171c3fe5d08abe9344ad126e7eec9a7e13faa0283a6dde54be2fc6c7917ec029fafbf1e35e62563e6d02f6cd40cd4e207697ab39b915e2954440dcda72836b83340fea34b25791a22f5d92a89c5e144b8979be83ed9855e744c34286a8ca5cccfad486c2342e6cb5004061d7583097ddd88a0546f3afc76e585a556ce38d2c5226e35553e8521e60f68e09f946eea2c2ddddd3332e70bce5b7c363a725df279277b240dae99f045ecc96d96f34a2ea31c5724ba3515e5d3e12c5d1145a4b2a0b2d5c5267b9a0505acc2907d8f2053c579311410430695b863147fd89c148b1e6e874049e99dff17ffee22dc9d5ecae98f517165d57e84777fed0897346b2e2321749ecdae78ab111555796c0ec5fba8f1dca54176bc4e3caef6e1b8fe677f85ddea2763ddce431db9cff719515325d9b14dfe6bbd7dd58a39263a2583d1b96203e4a86b16af5be494c4557f88490150fe2863ae12df9366674b8e55ca91e37771a90587ebcfdcf518108501d241ce8af6cf2343f06ebe88692480fb24e8690886c6ebb9518578f6971c558f887b3860d58468d6a54c0d59b1a913a8714358c779bc9493cd66d814a431675c7fd3126fddcc2ed2bbd99c5a95555525b2e4aa7b147173e5325a6ac23788d71341c87c33dc14598896ee067c9e4f26b9e56d9a43d30599b1f0ae6d670f42f1e8246102e3ac3e66ee24ebed90700abae2003214fd3de924bb2cb0b5e5988cd91a784b425781463910e68ae15b9466d54b5458d9ce76216feac1ad86ee53a1d52896b4bb1f0457fc9fef894dfd6abdb671fcaf5f2d9085ace8909e9dd5445a0f59ef0cba872cfc0941f9a71d4ec9fb64b8cc626a4290d2d031e008012b5d6a25e0d5d4de574230c585859eacb962c9be39978c2ee7359b2b59ec08565f7cb398b5363327bfd0d78b8865fbca3898a5d1d52a4a6ee34448c452aea62d7da63d80f93ad6e45c3bfa928880e25c0689c50d9a58a1bed660aa59dccb8789606339efa899c6242fb69b5f27f9fd9d1c4d2923b3d6e99d40da26f6f0477ca514b41eb413633d5afa23b1fd20845fba729c14cf32b3dba9a08dfcea29ad11eec4a87f413b57729c398dd04b39c854b6140f4ac71602bce1f66ac270e323a23bd6e3c8555583d2e5609ca6a597ddfd9672c7fe843cd6b43734b895368306bae1951c94d8d9b811a4c34ef5e4663e3acf1723f82ecb4361473e960f8730a0b44df4f78b89c938e83a9b99914eca4fc89cc345d53366d040920dd3649a867e0503c586aa33f7751196621c62475c97dfcdbf66ed18a26937391f22c183a9046ae89330102ec8bd4d44b2c1f866184800acf6ec936d712469830cfd0e715fcb6047575c0fef744443f960005b8cf76d72eeb754f91798a4587aebd4632d4baef76b0765ca0467eb0a095a8a6584d09f467209cfc2d26fac23fd864f38e65babf829ade897b1b851da66c2a9911c2bd8854c4e986021d0cdb18e82c245d683b512579c872f169da25ce018fd782b640c71ab5879c563a7f94817f3dd4942705a5d7902b78d84ab1eb8c6f32999ae93693f93605d93128f0d50b23515caeb6779eb5e1bf2206c3a7b2ac1fb571d97a736cfa4c5ab51ff0103e858edeedc02d437dd7df13eab9ca65f18b5fb8db7b872e88bb33a5713f484943efce65254e148c1a73c07453d26969c4c57c94b949933458f33739a3d4900a5e0a04811c283fe95347f6a31635fcc6dc8d7af5f411f36849790526efb109928e62a6cc9f06322c656b43bf5cc5717ee8f642ef05093e965d3902ffdf6083b4202972a9479642bfe0ee385cfc41fe807061392b5965098702edf8b9c2c7f304fb98c2c72c655fe362ae9c4aaac92ee5ad6d2a801fa28e962bc5051ad8a7e96df5c9183dc90693a1a209a5c92b3cc1158c28e1050a2ebd4141a103292654f5966b3f5c2996a7d1a422687fa374c267db1a25a50d19c8e490eb4da70b935df48be33ff6b9246c6021eb060135a32a40c2bdc6ad52da78bc628a4bb4d4de626946b098dc4399d6c6ad26e15e15e1995f6a178d2806bf82df301d4592371e17d46ed0283ca752bf342ccd3efdf0addd78fdf6ccb25e78114ce0bb28fe4686322eb2437202b330e59b17c34e39c02d4dbbf78f1be15511406b52dacba7b6482dd68809ee6f44ed1c5718bd0607fd46c828dc24707e6d103058dbb0e6d86012430cfd4a6d8fd579186cc46e51fd551adf7f02c4fa1316eaa8a793e33c6ecb5761fa6c1e15da8fdee5c4ccc90fc0c305df18033b169dd4fbdabac0786ae1b088066c269c2137b4f189750ee1c7c84064b4aaff510a087e69d88c9c39e18ff75077c8971583b9cd81aaed88bfe7386b894e00db13a9413c6bcd769919a6d16a41de83973b49fe2fadebc6cd1848327c6312f9f88900c988030d153b3b9c6214a5e9e2d9700c844f6ea72f0eee53b4e3de6b1e9078a9cf29c503fe8d8f2fd9ba85793cb16fe33b5695202c397ec0fee7bac0cfd1d303ce6f8d424cb6082e54d81bb0f8ff0dd660eced0f8e0a5a09e5400fb5b1fc4d309fa9f05b63e5ebf7ff1f5061f3d5c3514fee1254794a29dab5112a9477bda6ff75e86c61216ab6d16ac2ea32b8042115b3249f8ca49ce0541e13c60ee7356cf60a6a70722b43b33073c656e27223be8e71e8725b6912ad5eb4cb9153c424828224d2a91ed8a6be78c2029465e3df9810451954768807ab4ffba41c5e4cc6257ccb862c0ab85369db0f3545eb681757eb88b6f9829283c9f95946c4a35d56f66a9e85d12c66f6d0049e5aa8adcbf66512a83779a14a6ab64ad18d39d158253e1e6214c68388924adc08bc2e09721136906e77c60f5ad675f466385f76c0e028587835279cd8eb5272a5ca98077809c1fd023aad238c9a3b452f1a73a677582f8c9d1143db75f879b1d3e9d007aadac05f7b64b5ca98d0cb0156b75b8e2bc30b58397584f0501a62429a654e58353af8315005b50192a54aa7f84fd233e09cb33322040c22fa31b97f1926661959cb7046aa905cc2e783ca7333b5dd1ebb2e48036e11a66327d154f8a8686d0b23863bac33e4cb2d8098423a440b17259824c4b24c04a27b9326afd94b718110072de3fa95a646aa051cb050829fae50f0cd3f9c00329a7f170f555a4e8b36640d01f6d443fe257b553af510928cd3ed5e5b61444f64a65800a322a3baecf41ac3ac8ee3e56dfcce208cf1cfa3c00cbc935f2e04c746c3212767b99da2333b949d621387524c6900dfb3c81a321f7bf364747484eed0492fa53ada6d83b5f808c8ef28ec1a86ab3d48ccfa27c65bd5c78bb61a2ba2c009911813b37464dbb780dff4bc70bf84497201ff9270b5360fe755954cccb6b3646b6d6c93d1f0abc524beef628c095ece27e48ec3f5bd948f1fdbc5dcded5879a34ae862279c5fb34f15ab3bc66d9d0c24a9b4ecebc1fc99d916ec64a153bfe0d97067af1e991d012a54c6ba830c7ebb95838f9eb4c866aafc7a816047c1729aab34a9a85fa7fc9952b676c85e468287810de1cb65fe554287580d9bb6e7b6c4b108113013ce0f21fafb4731601ee25b027bed5ba4ea9cd284cd5348fffa47fbc36e3ac17fa0ba2ace9740ef0bb9bbf687d151e2ef3bf8aa86b4888abfd0cb6b797a4788e11488f20c1d7a767e6d4c4b2f351bfd749ff85ab2f6d5eb913a925520bc7a81ff78d5a7f6397c78aa4fdf9d677429ae3ab7444680c5e7e928d36ee2cd639948b74b053149ae0f89f884adf95b2581cad66071b988af45beb92c556c8bf870b6b0c5f744ba31b4e4c5faac45b9aaf08beb8dda565b653ea6038d547f9e277492ce0596063234b1e0ba98a1f0cda3e5a450135b0d454918c8649d049965d79b17c246daa0eed1bb7f99726448f4c16692c9a3dd8aea1d55b34b796ef23d29cc004c4950dc79e2a038a360d78b1db2a314555d7b74f34d1a5c4096dc8283abb9a75430abc9113c3445c47c43013ba67625c2f857714b8c825cea5dcbd9b5ce33c73edcfd62d13b705eff0d51e653c00434e47e1c28da114033f0bbe03ffbc81f9db41a9513299342c3d2734c445ca43e15800c0e7b61ed765c3c94ed30ea94cf95f14ab58120052d7002717eccb528731857d73d4efac2a80bb2289b8b1020290ca0505b54f9e8aa6cffc10b52fc40548b279f7c187d520e17e0e9155afc33df4ffe034faa1a61abc6a6748c6f5f54da1e9ba3433ae470849793d4f2721ae0a8646042a4469fbeb22e801446d66fb878ec9cab4f3806d43b472331db1c6681ac64b3f1a06e501c9e9927c06ea064e7e8000d6fe954dca772ef9cba71c7319a15c7d8df920867527fe6686b733c59e72500f139cc82e52799018f7e8cb6f37b64ab87e66863ff12dc3bd3e00a3442e69c7d3f176e0a1d51fe697d221c8a499e0185fd2d342110da11e430605c6dab0239ed0ad399281e9864d8acff1f1f80d44d36cb3a7ff11b7d9d0564c8c3c0cffc7f2bbd036e3ee6316f7c063bbf8b90c8dd49dceafc6b06a4911ef8ac2be209d245d5288e80ad9b04532ba47ae888239b07a4ea1b39812c4304ca22e0cd13638022ccb02923b8c787169df3d54d177b81d87aacd518f118e9bdab589abe93113f03c31a5fd1c237258523e98e62d33aafbaee238b9fc6118d198a977169bb3894b8b9051283549f968eb983c440e0ac26e62e6aa4872e7ebdac7c6eef7440e75f94a857bea674419cc76f90a9f95a80df90a0ac14d03bddda89b052131a1bd8d29e2ef09424116c88db97db1c929a730c6ed0701130020389f558ba3328673f1f30e968bc36aa08ba10e82c441851d7a595f7c531094f072a61b70e84d4b51fc5354c3a6219c810982366481e4c4212047d09aae0aec1e0a22c3e826873c96bb54da8525e58cfdb465af9525eb90ca9091641b0dd30bfcc32ac2667a951861a0a48c974a8829fdb2b100c07f0aa9afd7b512b7604f4de407f7d0d9c1465ace055885a97eb9e9beaee9a5dae4acbe3c290098995fea4685bbb54a0d29ea15dbda44ae6b305994d121125cfb2cd33e2f2c99b90d24811c363f37b811b26c5f85ab1455a4591ce649d5186a775573fa2d466a4f59a28bc265bd7415e5a06c6473c6b5b9db901f7a7faffcf64ba002a9d3634439f5b710f674c3191a26e344ecfb8439135fe7d5f9da121e9d141ffee2ba498647a6c4dfe330cf9e16389149bcc478865dded2f5225ee2ac8eee78afce5b62f36d926e0d17d0b47a2a36235559b5e15625fd40284305878c4ea25e18ceb27bfbf24857fe13f29a996a4cbf6b384c06d88501f452cfbf3d807f96d08bbec387f8ddab442e80741492293915555ea52c44dc84b698b496bd80e977a8c69aad2d045c2f83668dc98d989e305c446a6e512037755d87312860fbfd48ee1acfc496320a749e3253c1629432ad905b7eb92aa6b41476ae60edd178cc56a7b63864642d38e3311e5d249ea23d1c3bd1743b02fccc34aa488495c5b2caf1408c42b7bbbf5e68dab9f74dce918a9e224338a1b403f07c26a1a1a5d43a30e387f7b3f68ccaf51fa2d52ec919c75419dd647ed947f7a76f5231e6764b05ae0477e50bab26c070aa2788ae5b2078ccd520a2b63c5e72374aab3793912e1ea906c472d831f4bdf71dee8fa2b545809264c101d62951e5728dc39b2d1e0dfa803b1dbb8a478786f35c825c6aa52c67ef7516c5278e1d43080ea59d77f4851a94d50b31b2160e95b60a6d8c53936202bbf580d48b1b1497244c9549fa0b5985b4809d8a50b0ebb314482b46f0f3de81d6be7ebb8aacc6e46d78a4a146f2ba79dead8757bc383e09bca5924709f3f834b20786a215fac852b20d6120bcf731852c2a459116689d5c1a863396adb2ccc368848954c3206bf2615cac62fcd95d27405f32eb6042a98e0ee87a1704284dbbc173b51f96b4264740fb1561f112893a5fc3477a161b634ceb8f4385c96d0839b4fad22c1dbdaeaad3405afbb13a4c6b63208f3018492f1f65c33922a824258998fe4ac671bc33676fa26bc9335027df743993f62702ae2943a2e5887e64802f8c1e425b9945c98c99843a8343cf705866fdccff6a42011df33acbe61d200598951d921f8c5377075876163372d558ff7e26e0c9c758fd62a7edb0743b55b864ce66ae124883eedeb54bf87dca99fe685e05f5cc18793044e5fbdc87ccbb6bccd9f3f6933b0898250704eacbd5bfbb2100b23bfec478741e9d345fa54b568d727854ed920e16e757a47c7c36816582d4b0b69eb28574eb167360988af8c549ae17b533368f035a37864c73664c94027949f4386228ffdfc03fd3775eb90249a10df5651795e63f2b934b109ffb48f8b4465e8f8b89bee2fd3db94c19c4d269f8dc8cf60acd897add04dc7e14e8eb4d8588795eb28787fd40681c4d26afb49116a713b7680d2c45825b58747e8ffbb7dd9456ad9721a17d13a84022c227b0cec4ad9bb15b5b30f786e0b0ffdef7babd2135e4791fa30df1c8504f9db232d9267396b82fd658558523002814f4fbe14eaf4d502b5167b2f1d5c7e0cd7b43938ee3a8de668bb7261c07140e6e300f9a7e782ad0822a5400132fdcb037d679527d00ddc416a699bfca0d1e1e75e458807a3d95ca7eaba0d6606791a9446806a052dfca2c16fb504296c52cdd30bbc376d2943ca3f30564a37923a4d66316b3ca97a34e7e898cc839f764b8bfa2a977f7d0e516c4e3d1e010f84c695d5ad3faa1bfe209a8067060e7d3f2df20abd6ca9d9bd945c26b6b19ceab7012634697937dfd47e6e0ed5d031773a1a2b48b12f020f5e529bea36a085f4c5174bfb2020d012573231cd849854180954896f021759a944a4138c53340a508e7f4bfe5db2fda6f8d7770df4a77e58358a646b33ae0a2567492a356c2d85f32d1397430170e05ed1f94534bfac858387d1dd489cdfe875854f9190e1f1d265461cbe9c489c02e2729509898abde3e9e33644fb828f1a577c357042dbccd3b7dfebf4ff5850c449f7580002e864fd5dbff42142485b52a77273672e5970eef51485080d09d7b8f18f53000e63b322463390030e31813ea611fc988f5d9ff17ef56c87834f7743b456ef634fa9ec9961dad80506bde195a7ff8e45b2bc97732487dfd8a2bcf7c0efb7c9d3a2f903a29ad0c25b4135a94efdba9cbd6db56d12371d2bdcd0798c76e51522a630e1bea9f0c6643d3d171dbb0136e2d142c870d41b59e588832e20db2cd33fe94870a1e06727122a8917676d7e9b9604351a6d5929c1228b87fbb6e702d1df7b70a0a106d142a686985ccb88cf7724a059967c60c7821c67095d99bb20620b83c44d85647e5ee87f440193ff2712d7a4f2fdd7167f036ed09496bcd75a5d80fad2420a1556f1b222548bbf623bcb248ebf0089b025b4e43e4cf6fa04adda2448b3c5f037107cdbb64b7a779e0eda16ff3e0752a6790c68b0662a4c2368a994aae2856988444e5fb641983f38764a4375c1e5f2d71472462b390a91815cbb361dd7a09e91ddefa283914c3db7a7b2d4d39722d6c8e7c0df25c0681ecdca053c7049f5513eec948aecbcb750f710b2f60363d8bdcd5ab89021a35621e8109a3a07ebc648add14475091a9e18730573e5b84f0696198cd4a331fb8898dca94ae293dd9dbcdd46fb4f83ddc9898c626f1384578d2026ad7aff3ec5291f502224aa9037a8d12f49db519d3ce2d08b844e824e2f49a6db73d8b926760c2197f28f8914e3435e9418173782a9c549299192609d7dd399ae5ccc0238defbc8479799fb0d2334e3aceba774599a5b305cea49d493da522cba400f7c0f360048718e2132c8de8a7d9af1d4e8bf320a4a1137f4b35743a676db799cff44d42f9f01f1f509580ad4f6e2e4e74d11480da66537773b0316a8161420a74b92d3c484b9aac6c8f627f555515a44e5a173d8d1578f4a4bd563f856162923bf16b2e30297b99e0a43b03f20be7cf3b042fd449cef279f31c0f17fb002ec9211d47dd4e3df4fa3920716f4f17141d0a7085ea652477eda5efe7f4079f4cd71e8c691f60b9c9aa9b0e5fb6d5367642c4c3bfaf6edaeb4bbc79294a4c9875b1ab6702f2b98e328be732a7709714ea30fc1914b80b220671e0d272b88d960793ba3c4bf59b83e00c67b19a9a648955f4a4391ab8f9f69dc425e1f2505d499b2e2452b15f12f8c2217e87e9bded9ec58d25490cf2298b347b64e8d937651b3197e17f82e867a9594c88df9d7cfc861cf3a1a5c7c263cf65765dd836061949077eb1cea0251a7ad46628ca46069f5438ec75278acb3d30fa0db064a8f4283477fae64863162979b5718de0585cb21bd0ec6cc8f6fd0dab37318b648df49f8f67579cdebea18d4a8aeb9050cbf0ddc5eb16ede21c9ed2608a1e5b4accefeeba463c5b198ac0ff49229b7eb039846473155f1005645894a39f6e1ab51b2e3b87f586d8d3c38ff395525a817c8ad8d59e066d66706ff5b6f09e273c9a598dab6032746819f0b9c6cb76b69d75c2a03f4c8745ebd5490898a0483f950b047384e2310ea72b899e9a3c5b00345c16721f64882187dac78dad0ca1705b0b423075847ef2a477e91323c4a6f0d33f359b8ffd4ffa2f56d1f33e8cdb84cf2feafe4c0d3fce79ec54b9e9dd7356a0faf12fa78e75006c10122fb44d3ed19d47c3051b8c4c445c623a78bd4edc30b378a8be503098414284c808818df9b1a5553ed49acf0302878dfc6a876cdee06af197cb766532b2554d5d2a78472f4a6b78490809d3ee9788e07efdbda1a6c37f3441f9e8c0da66cbaed367714e40649ab7ad376b0798a0cec386e84342f5a8a730e1472545eb8f4b58cb5b24eab5c9eff1ed72a9645a9adab96e1d4300dbacb0a2e3c95a0dfa7d301aca2c8bfb1f64ef2b65b28d6303f253da5edb3f789e0e759dce59332197e7c05416b6342c0502b4ff731b716a73d8e95d1fe0c8c4e13e57ed31c32f8b00ee79843c40337d8b03a1d7caa3ed25b35f7e1a50e8ffb7da2ef42f7923eeba5d085f422b490eb3ebd29751b9e3864e01ccec9a0f78b5383777d7abe50a79a788f93219cd9546b5b528b6da673175fba0c8f497bba25eed660743ad0cc76db8c4c587fcfd2282bb596a3dcddcd71a3597dc8109d946e5a275e69a595905c89457c57e18914c289fc71443e7aa69b7731a27fb51ce9ea73ea37143bec5416f5c2f004912ab5de9856970bc4160c56691b7a6ce9ba97a9723ed9e45daa2f2adf39bd3bc0ffb9bc890147a39aa982a5cdc496e34389cd5f57df6c397c28474dcf5b55b7a5a52e504efd312b6e5e93fa1dfe34cfa443814d2a93b9494e64e6f9b5ba984a32823d8b7a6d24e191e29cd7ce8b96c58ca7de52dc51083f898c7b00b4b8a791280c3d1c226520722e4287844c0d629632a5b1d8ed722d952ddc117887b5c96495124cf6cc26bddc282b7de876c1d0aa9046a7d447b9943ab068bc52ac2f39f6d80fd837e0d0bc7efd5fac76c0d235c0b4b5bcac3eb69ee1ceea2fa3e9ca45cbc30871d64c80f664f008c9a7808247343e9f88f44e135079166e7085bd2bb6b06bda132bd2f319363a9961984de3062d62c36792d4ab3ff170bcfa5fdb101cf5d65d62956c9ac0e80c8a62c3143bde74b271c042b347a6fdd64ee02bc90f3925afc993689cc40acaebc45c8784a148af4a4c18231d3d8202398e04f38f19fe10e836a706880c10b82b8a84920f1de969fcd2b24b2aa25c8c8fad01e8465e64c37a657e77b8cca9cfb49e8d8ee3d51df258a514d1364aeea79d5061430ff93a08c6ee102bed3b661865bc159edfb9d7d6bea574666b922c702111fc27a02d710fd9860e9e8b27f8db180fbb6e175e5e60fa273246884ec0591a353abac75eb28724244583d58cf8f1608a18c1afdf29b3eda92254e3fe22c726191f174e1a2c526de6d1b92299a41bb495b29c0f4e81eccaf87034a6a78c57e8e033fc994da026da623695ae39ad73e7e1bc247842fa6d06bcb2dbbaf11764368a041d338ac30553748dad4c62cbbfc6c032c064c2782d27bcdb44fa2e86b805bae549ef2a6bf8c68d6f2b3267d9b77f1b81d24b6ebee42cb35ff5f639ee4dc138d053b00f4ae71cfc998512dce05f03317996a6d4a787fcd619a52bdfff1446c0d8f96d7021f589a82c2860de4aeea62c661276dedaaace58538d278de51a8677a44a24b4d7c5487f80d3413f841b3d02b2f7c590ce4fe84c783404d6a587385f9a0f7cd57918db136766c4ee248b0006bbe94bc9d7f9c10b3df317e1a5e45f101a367d8543115388aef3efac2f49953df5b58b64746257cb3e8db2f8408f9e695e340dbc90458089c87b7a71635b1ab94cf061f3f540128a0b7bf0a1d0afa8a57030c3c41ce6db5902fa6cf4d16965f942c418ef4558c4ef98051420d3c8580699f3679770797cfc6ad7c2a17636c5ec201cf483aaa1196e42ff90d0f8516cee152a7b50fc19afb80ed0b03973bebb7ef3bc4d0b75613b31d60aa821e3be410ae1bb5329b5f98006aa6cb7d7e9856492c1d106e05989083f24471d480a09b0472fcc3a20d99865f53f1d56edaa4c2c38cfd457ad561ee229baadb3221cd27232909043eecb5698d4cba6695191d6af7918acfb929fbc14577bef688ab404df00c15b1965fd930277c2b959ec1c747456da64e6ba719d9b426c654142fe008dc7c86729a0e68189ca6548eaa29f9cfcb189ad0911da879b7a0995b3836a1b5778b185ed518ffe59f173530af0fd7a2522cf939a9b97e8b03a5376c1099d373b99fe8f9082c622cbcab33e5eec492558265857418b7a08f505ffebf77a5f4ea71621eb216b2c49ba85d9daaae490ba0181db4338d8d3753251395a683ea18fa2fc81441c3edd4c289c4a009b5404b41bd97ddbdf619da7a012495754cdcf5089c708fb8125e9a5fb306d9d192cf7ca80a1d0b373862df6f514f900de3259292d68c2c31311bec941fd933ba6803a1c258a453c5528d66e7300585abe75ecd65f33ec1c67118e03351b2d2de692d80edd4780bba8f9c477d4b2d1dc75dcadd5a21ffc40bd00f1cb424654f492f6cfc5b1c75dd83e3a5964243526e4acfd505f23a31ca8dd7e3605efb3ec4c8831535bbbccc8e3ceca3ca848ffd163fa25010cb787d4bcbae58cf904514b06329667d21ef42419fb49e009cb6574bb850540e1f848010134842cd09f6717dc4ece7b9d4ca09c1f9ad40ea3f212677e5f9b10e28ff870b597753426cd0743cacbe3e6e28718bf20f31d79ff1f08e374b19eaeae30a1ae97324f3efdbf550621fdc915b9ec409a30983bfef2b3e3b86b38d39a985b2b4bd98b19758760f80d74b0eae01ba8381ae29a8f8fa5dbd4ce3b16b56f6bc72000edeeae8c5d863b87b88f532deb8a2302625d05c6abc1b970da583253dd662669f21fcb77463cc6c9f30f85c3e73fe612885f791882f11abca9c6796fe1d39478cc83bdce0268e63f748cf34db669536b0d9e8fe93e2b5b869abe893d2f3c7491a3ee098ece52145b244474291e3a1d0c50bf2cd7b722f98e6fecfda6c0f4f7557996cd71ae3a6634aec3b221393ea234ba007a76ae86df800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Gcd, "17", "19", "1", .Okay}, + {.Gcd, "7d", "19", "19", .Okay}, + {.Gcd, "7d", "0", "7d", .Okay}, + {.Gcd, "0", "0", "0", .Okay}, + {.Gcd, "0", "7d", "7d", .Okay}, + {.Lcm, "17", "19", "23f", .Okay}, + {.Lcm, "7d", "19", "7d", .Okay}, + {.Lcm, "7d", "0", "0", .Okay}, + {.Lcm, "0", "0", "0", .Okay}, + {.Lcm, "0", "7d", "0", .Okay}, + {.Is_Square, "c", "0", "0", .Okay}, + {.Is_Square, "4fa3f9fe4edb58bfae7bab80b94ffce6e02cdd067c509f75a5918e510d002a8b41949dee96f482678b6e593ee2a984aa68809af5bdc3c0ee839c588b3b619e0f4a5267a7533765f8621dd20994a9a5bdd7faca4aab4f84a72f4f30d623a44cbc974d48e7ab63259d3141da5467e0a2225d90e6388f8d05e0bcdcb67f6d11c4e17d4c168b9fb23bf0932d6082ed82241b01d7d80bb43bf516fc650d86d62e13df218557df8b3f2e4eb295485e3f221c01130791c0b1b4c77fae4ae98e000e42d943a1dff9bfd960fdabe6a729913f99d74b1a7736c213b6c134bbc6914e0b5ae9d1909a32c2084af5a49a99a97a8c3856fdf1e4ff39306ede6234f85f0dca94382a118d97058d0be641c7b0cecead08450042a56dff16808115f78857d8844df61d8e930427d410ee33a63c79", "0", "1", .Okay}, + {.Add, "-569ee5408deb61a6d9232b12cadb73", "3248bc748056a33eec0c55f2ec0a49", "-245628cc0d94be67ed16d51fded12a", .Okay}, + {.Add, "-934b3cd66484ad0da5da23aa2c09fe", "405747b2c6d4dc10a0a453e08abd35", "-52f3f5239dafd0fd0535cfc9a14cc9", .Okay}, + {.Add, "-a497c6ab621818982512350f6f6324", "2c4a22e64d274f3968fa38e0079790", "-784da3c514f0c95ebc17fc2f67cb94", .Okay}, + {.Add, "f496179976924a7e94882e7a2abdbf", "1afce56f84a129940ee36e73041806", "10f92fd08fb337412a36b9ced2ed5c5", .Okay}, + {.Add, "7b768f42ef9ea9bd96b25d89d079e2", "c5b99b425e03bc09c8fc8842caedf2", "141302a854da265c75faee5cc9b67d4", .Okay}, + {.Add, "69c9d904d101e10680ad9f458b55a3", "1ba939736eb74c0775c72df23d47e2", "857312783fb92d0df674cd37c89d85", .Okay}, + {.Add, "-a6c804d3a2e562e918ba02c8cd9116", "8315acbe2c92566e29055611058955", "-23b2581576530c7aefb4acb7c807c1", .Okay}, + {.Add, "62c6f756b8e2a2774093f051503a90", "969e656b3dbc84d57c14f158d4bec1", "f9655cc1f69f274cbca8e1aa24f951", .Okay}, + {.Add, "f9e0ed137b655090b9f85a18cede30", "4badaa4c2f22bb383630fd744d58d8", "1458e975faa880bc8f029578d1c3708", .Okay}, + {.Add, "-ca868ef03da0cf72601c0e4d6f1f7f", "9a640689f71ccbebe88196a9998f25", "-3022886646840386779a77a3d5905a", .Okay}, + {.Add, "20ff037e64dbdff86f503201229289", "356cc9355432086cd5902b568e6057", "566bccb3b90de86544e05d57b0f2e0", .Okay}, + {.Add, "99dd0ed8047ba4b1e094b29144315d", "d1ccf8d7f9f21f74d6ec4be0fb605a", "16baa07affe6dc426b780fe723f91b7", .Okay}, + {.Add, "b47f4644cc7d56b23ad893ef6efb93", "397da0aa1c9c589541e4dcf762901e", "edfce6eee919af477cbd70e6d18bb1", .Okay}, + {.Add, "1411c2281750f2194de2bf576d2a85", "c73e2167fd2c3f126b4eec1b9ae8ca", "db4fe390147d312bb931ab7308134f", .Okay}, + {.Add, "-96cfc8ea05fd378290d18e07baa946", "c51cef0192af4ab6929ad6ca95ef8c", "2e4d26178cb2133401c948c2db4646", .Okay}, + {.Add, "-99836225715db20973ab0a01852dbd", "717355a66e5488602b8581db11326b", "-28100c7f030929a94825882673fb52", .Okay}, + {.Add, "c3ad4cd4c01ed667d8dfe5d0504517", "d07f2730ceaa5378ff34db85749e8b", "1942c74058ec929e0d814c155c4e3a2", .Okay}, + {.Add, "258b124033eb1870bbe95dcdf89316", "28a13f0fdfe07c821c7e408d86cfa8", "4e2c515013cb94f2d8679e5b7f62be", .Okay}, + {.Add, "e9d73ff0911f351acfb6914571efe3", "55cc12ce275998f6641233ed5b6a1a", "13fa352beb878ce1133c8c532cd59fd", .Okay}, + {.Add, "-c41d4581d8f2bd0205aa850cf1b4f1", "9e542a92b2ecbba92a4f4fb6b823d8", "-25c91aef26060158db5b3556399119", .Okay}, + {.Add, "-134289fe593181a8668de701f28f0f", "dcd3ec76ee80a9c03423c1e9bd16a0", "c9916278954f2817cd95dae7ca8791", .Okay}, + {.Add, "ce14284fa075e6381fcfdb81b1b1ea", "af365890ceb276ec56c1cfc8163fc4", "17d4a80e06f285d247691ab49c7f1ae", .Okay}, + {.Add, "6f8ab2f7d5a6066bb5de568f909f4f", "6d6faace70938b4dfa99c6c3bbda3a", "dcfa5dc6463991b9b0781d534c7989", .Okay}, + {.Add, "3f6861ad6695b09d5e0cc5964eb29b", "cf71eb6962703657e54af0848277cf", "10eda4d16c905e6f54357b61ad12a6a", .Okay}, + {.Add, "-ea5b72bb50d9c1d013d1aa1ad184c4", "442751754613757893e60a4f46eb5a", "-a63421460ac64c577feb9fcb8a996a", .Okay}, + {.Add, "ebc80596c377f4f7effa0000061d23", "e76869ede6da873b4f64d49c08229d", "1d3306f84aa527c333f5ed49c0e3fc0", .Okay}, + {.Add, "-14e786d470e33c05576b433d81be28", "f0b0a56cfa41deb25bf59c4893d80d", "dbc91e98895ea2ad048a590b1219e5", .Okay}, + {.Add, "1e147d13b45d32d6d32a8ae5562b32", "8d54b2e690e312db7d01cb8f0686c4", "ab692ffa454045b2502c56745cb1f6", .Okay}, + {.Add, "-3eda367af1da871561770837dc2001", "409b11667fafb48507fad1a48a9646", "1c0daeb8dd52d6fa683c96cae7645", .Okay}, + {.Add, "10d0643aaa6788797ab686217c848a", "84f9a2976ca6bcf87c5f08e1d2823f", "95ca06d2170e4571f7158f034f06c9", .Okay}, + {.Add, "abd25b8960a741bbe04ef6307d9de3", "8c387767e9a86808a277aae46fb0c2", "1380ad2f14a4fa9c482c6a114ed4ea5", .Okay}, + {.Add, "-698649c629001ab737d1f535e173a2", "44595ae8bb7c45116f4cfa793f0549", "-252ceedd6d83d5a5c884fabca26e59", .Okay}, + {.Add, "385a6078aaab170d7e1dad26e2ac7d", "2b77c05e659e9c53048bb42203b4c1", "63d220d71049b36082a96148e6613e", .Okay}, + {.Add, "186534b60f4bb2dfb81a48ce3da520", "57706db7e4e5e016c3ed248e3046e", "1ddc3b918d9a10e124591b1720a98e", .Okay}, + {.Add, "c56bdabb9343b9f400bddb0e7c5092", "2cc7bea46ca0ba30f2eb7c80e0508d", "f233995fffe47424f3a9578f5ca11f", .Okay}, + {.Add, "-b02250ec97fe005840b59d59620470", "f35d3ce5fed4573e5657d0bca6c54c", "433aebf966d656e615a2336344c0dc", .Okay}, + {.Add, "b87e0b8ecefa8860ff4457b4dd8f6c", "43645d3e9560f8b9611ed3c17c8c81", "fbe268cd645b811a60632b765a1bed", .Okay}, + {.Add, "4347e862f7480f9ccd1e2cbadbe0a7", "2c3ff6ed7cd20ef15fb72eaf1c3553", "6f87df50741a1e8e2cd55b69f815fa", .Okay}, + {.Add, "fd90dfc8cda3a4511673b862afecc5", "aefbd925f02ea98d54df3d648eb684", "1ac8cb8eebdd24dde6b52f5c73ea349", .Okay}, + {.Add, "77ebeaeac60505e3c8ee2e589b057c", "e7a02280e43bc19c4e4066c1275ef3", "15f8c0d6baa40c780172e9519c2646f", .Okay}, + {.Add, "-d8c286454f185406aaf1b77257f8e8", "f91fbe9e55cc6904a375a5b6b70ed3", "205d385906b414fdf883ee445f15eb", .Okay}, + {.Add, "-2dcce9c3eeceb2f390ce258c57a694", "cb6192b7687efc28b92dd4cb3b99e3", "9d94a8f379b04935285faf3ee3f34f", .Okay}, + {.Add, "459fdcb6595ff5190cf0b3c30322bd", "f42e29cc0ee1b24cc70b08f6350bfc", "139ce06826841a765d3fbbcb9382eb9", .Okay}, + {.Add, "a060c184a981170349654d49ef60ee", "4c45fafe1325c6c76d13271a43d1a", "a52521348ab3736fc0367fbb939e08", .Okay}, + {.Add, "21141c50fc6166451a4e9c7a15def9", "581d083529a6015f77eaec04c95ee2", "79312486260767a49239887edf3ddb", .Okay}, + {.Add, "-47a2127a2f3d586b0a0cd6347c0371", "748e8df8963a3d8eedf760a3863b4c", "2cec7b7e66fce523e3ea8a6f0a37db", .Okay}, + {.Add, "-7f37105534a36143980d426034c74f", "e0b49225c493d585803025a802df15", "617d81d08ff07441e822e347ce17c6", .Okay}, + {.Add, "b139ada1f3c07ff1439d5c662ee73c", "8b84e9493052af2b6ae18e77cb34b6", "13cbe96eb24132f1cae7eeaddfa1bf2", .Okay}, + {.Add, "-8eda708e51a4e96a5e884867836549", "a61eb7547c7537173d68999ec89c88", "174446c62ad04dacdee0513745373f", .Okay}, + {.Add, "-eed1b8b90fa07e638ebe48b0f8e608", "9abcfc93ea37ea1f23d68554d0f9e4", "-5414bc25256894446ae7c35c27ec24", .Okay}, + {.Add, "-2917c4bb7c3fd0f2177bc2481824f1", "4538b1537786a1ecdbe4d3f5ce9603", "1c20ec97fb46d0fac46911adb67112", .Okay}, + {.Add, "48946ce6f1cfd14cc24f5e3ea14c28", "9f613f621204deb766216ca84510a4", "e7f5ac4903d4b0042870cae6e65ccc", .Okay}, + {.Add, "aa250cb306da11292bbb1f64cf79ac", "47e9cc0e24107f5022835bf1af1811", "f20ed8c12aea90794e3e7b567e91bd", .Okay}, + {.Add, "-c6e1fcb7289318d6c68abfc9c86611", "6766d236c9d50c8916acc8a7ecfca6", "-5f7b2a805ebe0c4dafddf721db696b", .Okay}, + {.Add, "-d0e49985afa421979c9e06215c044d", "d4a21370a03afebc31510e37271e2d", "3bd79eaf096dd2494b30815cb19e0", .Okay}, + {.Add, "-dfe730ed8f4b3b6067e17801e21bee", "8fd587c0180cc2406172c5e21ddfae", "-5011a92d773e7920066eb21fc43c40", .Okay}, + {.Add, "-bb0884fdd6cd56b677c1968773eec1", "fe4f24b30249e58264d9f63a4da13f", "43469fb52b7c8ecbed185fb2d9b27e", .Okay}, + {.Add, "5152430a62ad0458a990ab04133467", "be6faba007b6b06bc5081028a4d9c3", "10fc1eeaa6a63b4c46e98bb2cb80e2a", .Okay}, + {.Add, "b3c1bff207a1929bf122cfec5f1fc0", "bf6366a2eb3742fd07c9d031bc36a8", "173252694f2d8d598f8eca01e1b5668", .Okay}, + {.Add, "c2eee9181f615cabf6513385746a15", "b8721458a27b4a280767db6bde59a5", "17b60fd70c1dca6d3fdb90ef152c3ba", .Okay}, + {.Add, "186824d924fdeef31cae2795b27ba3", "be9600f1b0f652672106699748514a", "d6fe25cad5f4415a3db4912cfacced", .Okay}, + {.Add, "e4645b2c4e730338448eba62378dfb", "ab5031f7201c24451e96282d97cddf", "18fb48d236e8f277d6324e28fcf5bda", .Okay}, + {.Add, "-80a73f04c208bf8c64cb2f46734a82", "eb9971b6a3d8bc1f596ef65e1e6577", "6af232b1e1cffc92f4a3c717ab1af5", .Okay}, + {.Add, "-9a69ed1d2e211df986602de1de87ff", "de7036d55aec03b5360e3315854e6f", "440649b82ccae5bbafae0533a6c670", .Okay}, + {.Add, "3c6cd691cfc4ee80bbc5f4a31a18ef", "a7574bf8472f3d3217b8b3cd7ebea9", "e3c4228a16f42bb2d37ea87098d798", .Okay}, + {.Add, "-54c4efe8f5ffbc212a9b1bdaacc8b4", "d99d1460975bab75564e75874346bc", "84d82477a15bef542bb359ac967e08", .Okay}, + {.Add, "da5af996fe757b4c1dfb0873d1499f", "e8babc0e0422656e7dcbc267a65065", "1c315b5a50297e0ba9bc6cadb779a04", .Okay}, + {.Add, "c984a3fdfff0b399ce2092bb4a991f", "1c2b816ddde20959bd8da081324c9b", "e5b0256bddd2bcf38bae333c7ce5ba", .Okay}, + {.Add, "-3f3182cd7e2ee8b0866aef997e4951", "967f488fde697d9b863f00246ab26e", "574dc5c2603a94eaffd4108aec691d", .Okay}, + {.Add, "-7955a9e3a5e4ee025bb1416ed14f50", "bd3bce22aa50ab7947b2a9a333e8b7", "43e6243f046bbd76ec016834629967", .Okay}, + {.Add, "190ccd720f626b83e7da8156e929d9", "ce93743833bf4b262cf07e921f3e15", "e7a041aa4321b6aa14caffe90867ee", .Okay}, + {.Add, "1cd9d5af13016c2d26239594df7d85", "bd8ff99dfe35e34b83041deb2e3924", "da69cf4d11374f78a927b3800db6a9", .Okay}, + {.Add, "ecb4daeabb77fe0f45c2453f8027f8", "81aba6312a58837c2a859ff6214ab4", "16e60811be5d0818b7047e535a172ac", .Okay}, + {.Add, "f8c0dc0e239a640a74e2dd3461bb3c", "544c6edde5340509f7d16c3b1ca4c3", "14d0d4aec08ce69146cb4496f7e5fff", .Okay}, + {.Add, "-a7a10c857721aac8f31ae1867a5252", "2f249ee848dffa4318825ff09e7829", "-787c6d9d2e41b085da988195dbda29", .Okay}, + {.Add, "548baed9e9c89a8368ebfec0dce354", "e91df190e6c733a9b877b86bc6395e", "13da9a06ad08fce2d2163b72ca31cb2", .Okay}, + {.Add, "ba4be5b2c217db9e28643a753c83a1", "e236bc13cb5e41beaf2f8386da2c4d", "19c82a1c68d761d5cd793bdfc16afee", .Okay}, + {.Add, "94118dedc79c6ad0c84f07611215a8", "296c103df4ae5c41be532c0efeaa5", "96a84ef1a6e75094e4343a2202004d", .Okay}, + {.Add, "a4af0adc2874dbd6aedc75c28cb062", "63536d6c616339a1415c4e31b39ffd", "10802784889d81577f038c3f440505f", .Okay}, + {.Add, "ae830a122e9acfac3c901ea99c8f67", "cb0dc5f6e42eb56c8767eb2e8888d8", "17990d00912c98518c3f809d825183f", .Okay}, + {.Add, "2281b0b1e987e6babd77dd6c9a9bd7", "138d9abb628b8a9394c32f934f1b38", "360f4b6d4c13714e523b0cffe9b70f", .Okay}, + {.Add, "-a7a7dc01aa7081edf076d647644e33", "9cb6ba46c5fe4bdb1248aff4201e48", "-af121bae4723612de2e2653442feb", .Okay}, + {.Add, "4b67d6b571e5e9bb07f485a17103ba", "fa51d75ea20868f3c51c794bb3eccd", "145b9ae1413ee52aecd10feed24f087", .Okay}, + {.Add, "f2ad7c055ab51ad62ed2dbc8c45b1b", "ac4de4f7ed7d13d56258c56a0c7001", "19efb60fd48322eab912ba132d0cb1c", .Okay}, + {.Add, "-2477edb593e8cbc46228081170e285", "f5d4e4168071641281259444d58841", "d15cf660ec88984e1efd8c3364a5bc", .Okay}, + {.Add, "132990dfc782a0e3688becdcd59a98", "9702cf61d44d3a59d08b383996dbb1", "aa2c60419bcfdb3d391725166c7649", .Okay}, + {.Add, "-66c9535d19e0477d631d6979de39ff", "694197b141647da4901e25a48f70e2", "2784454278436272d00bc2ab136e3", .Okay}, + {.Add, "67f1b9c7a3146e07457bbbd69863be", "b3074fcb2fd5dece8fdd7603167fe2", "11af90992d2ea4cd5d55931d9aee3a0", .Okay}, + {.Add, "915103c5fc3203b759c1d0291654b4", "95ac376a339734060c7562e124b4dd", "126fd3b302fc937bd6637330a3b0991", .Okay}, + {.Add, "-5e0e7a2d1de15922e82ecae9d1e50c", "d32d25991d47cb3c2976456cf46f86", "751eab6bff66721941477a83228a7a", .Okay}, + {.Add, "fe3aa15d3dbf542bdcbce2d9761cd2", "d1417bb13741457f27f5153c636784", "1cf7c1d0e750099ab04b1f815d98456", .Okay}, + {.Add, "df171cbf141404439205e4a5c104c5", "e72068cf8c0e2a33a88d9f86802d8b", "1c637858ea0222e773a93842c413250", .Okay}, + {.Add, "-fe169c3c58fdf58028d99dcdb494b", "8a995d11bef25a0837ad8966589df1", "7ab7f34df9627ab0351fef897d54a6", .Okay}, + {.Add, "-108794d0b6d9a7a29acc0e5f85b882", "dbd71f5fbce1f14665348130808a8a", "cb4f8a8f060849a3ca6872d0fad208", .Okay}, + {.Add, "adc6d78b62fcc9ea6d66b5813af6ab", "639ffc0027a8e2154e42c3ff78935f", "11166d38b8aa5abffbba97980b38a0a", .Okay}, + {.Add, "-72c1bbbe1cfe00650cfe4f454519c6", "fb9d070e564c87e23103cd013efd4b", "88db4b50394e877d24057dbbf9e385", .Okay}, + {.Add, "-af7b7d0eb9fe8ae996a8c4c5b8e853", "638a00cbebadf31daa823dc34183a2", "-4bf17c42ce5097cbec2687027764b1", .Okay}, + {.Add, "-57a6ceb0081c5fb28d4ac11e204605", "458dcad55ca60994242b80f89cb382", "-121903daab76561e691f4025839283", .Okay}, + {.Add, "-8a1092197b0102b41a2f4f90857758", "888809d2ba016d63b74138199e197", "-8188117c4f60ebdddebb3c0eeb95c1", .Okay}, + {.Add, "-646aebad41e4e5244aa9cf37f63c6d", "518da42bc2e7ad33eb654ddd0e6bde", "-12dd47817efd37f05f44815ae7d08f", .Okay}, + {.Sub, "-9eece2f9574233b8b5cc1ac1532d52", "63742ac24e90bd70af412d12299766", "-102610dbba5d2f129650d47d37cc4b8", .Okay}, + {.Sub, "-9d822ab4ce4cbad725bf7daee4184", "d507b2b86042df114abd97a4c44a2f", "-dedfd563ad27aabebd198f7fb28bb3", .Okay}, + {.Sub, "-2fdb011980a2093da0971b3f95b33f", "bb345afaf9f204ca8ed17ee2bca1ff", "-eb0f5c147a940e082f689a2252553e", .Okay}, + {.Sub, "7946cb75589257eca4544394e4d647", "dd11ee8c0682782aac12f9ca590ad", "6b75ac8c982a3069f99313f83f459a", .Okay}, + {.Sub, "f39c7790cf765c2cb8b7ce5a6ff85", "e3d2b13ea956fe50445468d6536c12", "-d498e9c59c5f988d78c8ebf0ac6c8d", .Okay}, + {.Sub, "-8c8bf853bc5b263e9ab57ffe166907", "f19097f56dc22035124bb95d6a2e5e", "-17e1c90492a1d4673ad01395b809765", .Okay}, + {.Sub, "-b380c899b277ae1cd457f73dbcf0d", "f0c8c541a5e904b5a2cb74eaaffb98", "-fc00d1cb41107f977010f45e8bcaa5", .Okay}, + {.Sub, "-cb684d80b640b63e8101b5c9138488", "b0e553d184e96e7352d5f4ffd0d203", "-17c4da1523b2a24b1d3d7aac8e4568b", .Okay}, + {.Sub, "-2cf7e4ddbdcf880b30af8c8d2d1761", "c4127b7a2b5f89b535e37072f16538", "-f10a6057e92f11c06692fd001e7c99", .Okay}, + {.Sub, "592ebe97b11407a6911fa8496edd22", "5462bbbff43701e1a06fa5b3e559b9", "4cc02d7bcdd05c4f0b00295898369", .Okay}, + {.Sub, "-b295054ffc5a2cb3738b24924f6c86", "f67b3673ce86c4874c166d89f33532", "-1a9103bc3cae0f13abfa1921c42a1b8", .Okay}, + {.Sub, "-944843676aadeebf4127cd0e7aeef6", "8a6bb7fae6084b1ed47298250c1bc6", "-11eb3fb6250b639de159a6533870abc", .Okay}, + {.Sub, "60001b2e087568c426309be4281eb0", "7b8d3f0c5ecd22093c340476c848d8", "-1b8d23de5657b94516036892a02a28", .Okay}, + {.Sub, "9a2c1a9fdabadb6a2e5fb5c4f7a761", "3def959750b06c4d494505a2f469ab", "5c3c85088a0a6f1ce51ab022033db6", .Okay}, + {.Sub, "-788f377cf7e12a24c969a808d10b7a", "5386173351c66d3eb62a281296b115", "-cc154eb049a797637f93d01b67bc8f", .Okay}, + {.Sub, "-e1985ce1b20aed09e5eeee9a5a75c4", "3459f181a6d3b3ab1e07bad91f323", "-e4ddfbf9cc78284497cf6a47ec68e7", .Okay}, + {.Sub, "-78007faed211b9c9deb8060d7e36ce", "edd1e639149caa5c33c3c428dd98e0", "-165d265e7e6ae6426127bca365bcfae", .Okay}, + {.Sub, "-3a512137a2ce06f7fddfbb1737bbb4", "6fd30de597ee3925f2c2acd2d06946", "-aa242f1d3abc401df0a267ea0824fa", .Okay}, + {.Sub, "14d88a9302795ddef8e5d426ad792a", "494e1ec3f4b784bdd22c35268bf555", "-34759430f23e26ded94660ffde7c2b", .Okay}, + {.Sub, "-715b499d174129da58d327775d136f", "cab7b2010f537b329c17fb1d8c6691", "-13c12fb9e2694a50cf4eb2294e97a00", .Okay}, + {.Sub, "56e14835414c242920f7559cb98b7e", "69987f127eab5d62021fd36c9bff20", "-12b736dd3d5f3938e1287dcfe273a2", .Okay}, + {.Sub, "-aba455acc668443e3983a00e4a1714", "72711380b01a87796cf63d63afcae1", "-11e15692d7682cbb7a679dd71f9e1f5", .Okay}, + {.Sub, "-2d60dd157238001fb3708464b1f0e", "4b01f758f51fb8047db15ead1f5958", "-4dd8052a4c43380678e866f36a7866", .Okay}, + {.Sub, "9598f10e2f1ce544b54596d393fd07", "9e849db215bf5c598dc657ef5b9dec", "-8ebaca3e6a27714d880c11bc7a0e5", .Okay}, + {.Sub, "-ae4c06ac5859d736e2893f9be503a0", "9d722bb23feff5f3a01b698ac816a5", "-14bbe325e9849cd2a82a4a926ad1a45", .Okay}, + {.Sub, "616dd3b5715d070010c09fbf08cceb", "5a1de2a466df223678a7112ae5e940", "74ff1110a7de4c998198e9422e3ab", .Okay}, + {.Sub, "4c5d8a45e9e2c78072368c1926879f", "6ba08db40dee87aceb5076dc4d0e2c", "-1f43036e240bc02c7919eac326868d", .Okay}, + {.Sub, "98064099179083123ac9e85bf03692", "1e292653505407b4c88a146747eacc", "79dd1a45c73c7b5d723fd3f4a84bc6", .Okay}, + {.Sub, "63912aa9e23ce61d5d842e36d31ab0", "9607d75985a3332de34b40cc7a332e", "-3276acafa3664d1085c71295a7187e", .Okay}, + {.Sub, "f7c7dabd2c0aca183a8788711a203b", "4f0fcabd904feab88ca1e2a11d9f74", "a8b80fff9bbadf5fade5a5cffc80c7", .Okay}, + {.Sub, "47c975054ecad952075e58e399ebc1", "1d9dffb0e09d929202b05715873d32", "2a2b75546e2d46c004ae01ce12ae8f", .Okay}, + {.Sub, "d4c06b1a5b0a6a2b7d4e9e55efc25d", "d34d30179cad6c67f69631f8e4cd61", "1733b02be5cfdc386b86c5d0af4fc", .Okay}, + {.Sub, "-f1783608c4057e1cd70f595db6f5c5", "1a5a668b0f326ee287d5a4bf15ced3", "-10bd29c93d337ecff5ee4fe1cccc498", .Okay}, + {.Sub, "-4532f966c8e1723bef836b65eea07b", "eea3e1d4e0f498703bb898d573ac06", "-133d6db3ba9d60aac2b3c043b624c81", .Okay}, + {.Sub, "d5d4ad2922f46732bcecd3b7f8faa", "c728355644e63249e18978d92ac943", "-b9caea83b2b6ebd6b5baab9dab3999", .Okay}, + {.Sub, "ed1b919e00c96123f1fce3137f8be1", "f7c1ecaae302401526010ac214750f", "-aa65b0ce238def1340427ae94e92e", .Okay}, + {.Sub, "-b704fd3001229c3ac44794b29e7e88", "668a2e76deda5518b9b0f3fa87b284", "-11d8f2ba6dffcf1537df888ad26310c", .Okay}, + {.Sub, "-79972d8bb133971875b00bfccff221", "7568fa5b9d9bee507ed0796ace944d", "-ef0027e74ecf8568f48085679e866e", .Okay}, + {.Sub, "60f88bb68b29040b1e866cd8aff4ed", "8f8d1890aa6fdc9cfd06b32134bf3c", "-2e948cda1f46d891de80464884ca4f", .Okay}, + {.Sub, "-25b7b807a049bf5917a272008a2f76", "b5dfa68be94b92f7e98f109dbe2c12", "-db975e93899552510131829e485b88", .Okay}, + {.Sub, "-be0ec3af8b0ad1016a54e727b33cd2", "45e4764abe399e2d02c6ef618bb72b", "-103f339fa49446f2e6d1bd6893ef3fd", .Okay}, + {.Sub, "b69470a9e9d2e5bfb000bc33c31b2b", "fa6141c1f33e16568ae1e9ca23eaee", "-43ccd118096b3096dae12d9660cfc3", .Okay}, + {.Sub, "-13d695eeac6c814082d794baf7ad39", "d21e30897a92aefc6084b2a4e680a7", "-e5f4c67826ff303ce35c475fde2de0", .Okay}, + {.Sub, "-50542901e938b6b003a75ca39347ca", "64ff1946d1670544e9a6b9ed0198fc", "-b5534248ba9fbbf4ed4e169094e0c6", .Okay}, + {.Sub, "-18cdda83e2021ea9f3a107f67926c", "73c42092bcf1a6c19f8bdb639a9775", "-7550fe3afb11c8ac3ec5ebe30229e1", .Okay}, + {.Sub, "-fe09c9adbb90dc1a14eb42ab3032b8", "55491f219fd9580c251ae0c8e29a4", "-1035e5b9fd58e719ad73cf0b7be5c5c", .Okay}, + {.Sub, "-94c58bcd7fc07039c78c40a3b701f7", "63a456a516cc6d7e50f4378941e0bf", "-f869e272968cddb81880782cf8e2b6", .Okay}, + {.Sub, "-ef3ef8f65a420225562e90b0cedf29", "6dc0fc5510479d3e88b2c05a12d5a6", "-15cfff54b6a899f63dee1510ae1b4cf", .Okay}, + {.Sub, "-a0105bcabb38d6594b6eecc0718408", "28168d68cf805e299428207fc511ea", "-c826e9338ab93482df970d403695f2", .Okay}, + {.Sub, "989a1563e3a44412c8fbf6bb12dcc0", "9168abd0f7af5536c99d4b133a1f2c", "7316992ebf4eedbff5eaba7d8bd94", .Okay}, + {.Sub, "-a5e269d69e73bc5adcb5c01a8d54bd", "2e4a02f5510b42a2d059334a5620dc", "-d42c6ccbef7efefdad0ef364e37599", .Okay}, + {.Sub, "-48b18b8e4a210e436bd2a922c856aa", "fac8e29fa7a66a5b31a5421c461a26", "-1437a6e2df1c7789e9d77eb3f0e70d0", .Okay}, + {.Sub, "-39ca6fb330355b7a392b068bfd1d1b", "d7eb2415c0424e89cc29237bba7649", "-111b593c8f077aa0405542a07b79364", .Okay}, + {.Sub, "7947c07a46ddaf14c97a172065be1b", "416e17b0f89d76d1f82e0684b02c9", "7530deff3753d7a7a9f736b81abb52", .Okay}, + {.Sub, "7beec1f44641e40dae2b979ffabe15", "ac8e979a2708526ec564ae1564ea4f", "-309fd5a5e0c66e61173916756a2c3a", .Okay}, + {.Sub, "9d9812884485efde1183f29c26dc54", "912d1674da451f92fa3a9c85181dfb", "c6afc136a40d04b174956170ebe59", .Okay}, + {.Sub, "e7982e91f2f9bc9e95069be9445e5a", "e30c60d9bf323ed1cac0283322bced", "48bcdb833c77dccca4673b621a16d", .Okay}, + {.Sub, "6c531d2c8260e769cd6192e4060f7b", "e34297513c438b14c1d7c27fd98d96", "-76ef7a24b9e2a3aaf4762f9bd37e1b", .Okay}, + {.Sub, "-f28d5aff0d5328d41f18841f1b3709", "2c85901971b43c73148601c241769", "-f555b400a46e6c9b5060e43b3f4e72", .Okay}, + {.Sub, "-f59307200163e9b3dcad44a57c1cdf", "3c2b2d700820102d314bef424d6121", "-131be34900983f9e10df933e7c97e00", .Okay}, + {.Sub, "-cc30c975662c2c3d4ff9046fc62a9a", "a7fb32016f860a61b4cab360bd839a", "-1742bfb76d5b2369f04c3b7d083ae34", .Okay}, + {.Sub, "-2d644f2ffd67e479a4755c536cae2c", "eb3132b2f70baed631f038026b955b", "-1189581e2f473934fd6659455d84387", .Okay}, + {.Sub, "7a23538ebc4584e0238ec20afb67e6", "a9fe02d626652cf99d48c78e8aad7b", "-2fdaaf476a1fa81979ba05838f4595", .Okay}, + {.Sub, "-dafb46eb0e81ed169ce94d4ce5a75c", "9871d0c82923bc330262cbc8199fdc", "-1736d17b337a5a9499f4c1914ff4738", .Okay}, + {.Sub, "-425c29630560c018661c7ab4c6211", "f40b10c653e19949ddfb64f7e8bab6", "-f830d35c8437a54b645d2ca3351cc7", .Okay}, + {.Sub, "b005c0bb66c003bc1378b1ac77b2fb", "d0c47984ae59b1adbc31cd1e20a5d4", "-20beb8c94799adf1a8b91b71a8f2d9", .Okay}, + {.Sub, "-b3b976c04552c73064f7f5daa6742f", "cd5fc6be3926d75481c632f14639f7", "-181193d7e7e799e84e6be28cbecae26", .Okay}, + {.Sub, "-863013a1eb034793fb134f1cb40654", "38a7cf55c75f95576396629f3d2fcb", "-bed7e2f7b262dceb5ea9b1bbf1361f", .Okay}, + {.Sub, "f346e361377bce14a774836fbccb34", "10c2e5b89a4bd9cb7e2c8ad0076ccd", "e283fda89d2ff4492947f89fb55e67", .Okay}, + {.Sub, "-9094da74a66b31b6f7ca93dc894683", "cf4da785182e7ca5c78529324a8071", "-15fe281f9be99ae5cbf4fbd0ed3c6f4", .Okay}, + {.Sub, "-389df45566eda8f95db4f4614e82dd", "4b306eeeef4e577eec90b041049a97", "-83ce6344563c00784a45a4a2531d74", .Okay}, + {.Sub, "-45430c9807be85170b84a176db6719", "cbaf33754b8c184c6f889ff5f43ee6", "-110f2400d534a9d637b0d416ccfa5ff", .Okay}, + {.Sub, "-9d780698c87c24a0c812a1baf07805", "45a86b6129e9ee853bd834125dafc2", "-e32071f9f266132603ead5cd4e27c7", .Okay}, + {.Sub, "-91967effa2b47bbae28a0f4d55e502", "3429eb8f411db359c4e3fc9e64f8d5", "-c5c06a8ee3d22f14a76e0bebbaddd7", .Okay}, + {.Sub, "a5c679dddb5617bf2ed0161592ba61", "88350d447bc97d507b6047e5b1d7cf", "1d916c995f8c9a6eb36fce2fe0e292", .Okay}, + {.Sub, "5a2b871defe6ff506b39585cc172ab", "b3009fe5fd3f332ef238d8d1e4710b", "-58d518c80d5833de86ff807522fe60", .Okay}, + {.Sub, "3c4437628b5b3043e64b8d2df935c", "8d7efcfdc8135817ee1f1f8bd1ae84", "-89bab9879f5da513afba66b8f21b28", .Okay}, + {.Sub, "fe4e8ce5980acc37920104793c8c5b", "4aa73b2ff57534fdb29e4103acc011", "b3a751b5a2959739df62c3758fcc4a", .Okay}, + {.Sub, "8102058057d2695ab2be1f40e22857", "ecf8ede44e9c884527c70f78963187", "-6bf6e863f6ca1eea7508f037b40930", .Okay}, + {.Sub, "-58ad3c0ff2eac768af8a45689f0f0a", "c5ab15a2f119ee930c5006bae02077", "-11e5851b2e404b5fbbbda4c237f2f81", .Okay}, + {.Sub, "-1ccccbce8c01c7549f2e5582f2e4b1", "5220ed36a92ef5226623fb9b17dddf", "-6eedb9053530bc770552511e0ac290", .Okay}, + {.Sub, "-7f7f4bfcd79590bc748622e937c622", "cf9424b3c3f86da1f66624cdc4e1fa", "-14f1370b09b8dfe5e6aec47b6fca81c", .Okay}, + {.Sub, "-dbc54af5b66e44747e09d55a4775ae", "78728e3ca1f26724e1f7c1bbcb95af", "-15437d9325860ab9960019716130b5d", .Okay}, + {.Sub, "-fc98b6e9b4d4353c812242d963ff5a", "df0c0bb18a1b10d7ae593e7dcb0cb6", "-1dba4c29b3eef46142f7b81572f0c10", .Okay}, + {.Sub, "ed562ee66dfc6239f55e0b6f0b2cf", "1181a7213e7feaa99658e414b4d2a8", "-2ac4432d7a02485f703035dc41fd9", .Okay}, + {.Sub, "-9c23f0ecbbe97014c49ef97142e78a", "a7d3168d010431b7f487b57dc8c6f6", "-143f70779bceda1ccb926aeef0bae80", .Okay}, + {.Sub, "119f896fccdbfa4deed0ecbfbb8c99", "8fbad3985011f45f72b3d5cc6ee19a", "-7e1b4a288335fa1183e2e90cb35501", .Okay}, + {.Sub, "-cf03ffc878e147ad8321b126a884e6", "2ef865fd3c8cdc2540c28bd16fa0ac", "-fdfc65c5b56e23d2c3e43cf8182592", .Okay}, + {.Sub, "2829b210731c645aa71e80de2921fd", "94f456b06107331e0c8512180b0047", "-6ccaa49fedeacec365669139e1de4a", .Okay}, + {.Sub, "-87272340592e836388768a7fe6cb26", "768e939f7d540a14f70074ac6a2470", "-fdb5b6dfd6828d787f76ff2c50ef96", .Okay}, + {.Sub, "-4f0507156f8af50ebe5c74e9004d78", "21c8b862515e875d1155601e62f2dd", "-70cdbf77c0e97c6bcfb1d507634055", .Okay}, + {.Sub, "-6c9cc85902f4eb71670a925b55acf9", "c8914a4b7e48994af91a3642dee237", "-1352e12a4813d84bc6024c89e348f30", .Okay}, + {.Sub, "34f7f1bec7ac859ce0935b935eb52c", "a86b6c7174303ff8fbfb3ed90312c3", "-73737ab2ac83ba5c1b67e345a45d97", .Okay}, + {.Sub, "7cb7d2b29a6ecc131927a7180d951", "2a4f4fa3c00a3ff75b25cde6fe3860", "-2283d27896635336299353757d5f0f", .Okay}, + {.Sub, "ae8cbc3898c4b3d3548df0b2b144c8", "11efad9c98ab651398136b7da16b9", "ad6dc15ecf39fd821b0cb9fad72e0f", .Okay}, + {.Sub, "6a623bbf6d91d5d1d3f956641ee1a2", "510c7f29a4664da4b3beb6378a851f", "1955bc95c92b882d203aa02c945c83", .Okay}, + {.Sub, "3a4e2e93824f6f7aea2f20f20a338", "c2550cb346a7e1ea855c10400d47d8", "-beb029ca0e82eaf2d6b91e30eca4a0", .Okay}, + {.Sub, "-4bd7c098d75f9ab839bb618b9cf39d", "ff7d0dab8bafad2fda37c1e775edb9", "-14b54ce44630f47e813f3237312e156", .Okay}, + {.Sub, "d7561fd3874deeb8133051e18c2b0", "1fb2e2a3e9fcd337767bb91379b3dc", "-123d80a6b187f44bf548b3f560f12c", .Okay}, + {.Sub, "-892a192e9f534b79b9afdee0362cbe", "18ad6aae43adbedec0991798ba066e", "-a1d783dce3010a587a48f678f0332c", .Okay}, + {.Mul, "ba85edad8e2339e7e6bf7136dd450", "b80c5ccc86eb6a294be5ffefb166c0", "861944b908bd615ae37b8f46d00fecd4a900cb304dd2b8f6ee2d0471c00", .Okay}, + {.Mul, "-e8f09bb2f6aaaa2aea99e7891a03d3", "c07460c22b02f3a333ae0f25521ffd", "-af1e59d7adf3f8cd6363b33b5e6e1f2de355ef17786a68a073ac5dc25487", .Okay}, + {.Mul, "50c0259b61e9243dcdacf794fc2e18", "39865a087210c037f82f44396289a6", "122529597f56cfc51041a3a84088d97bd67d2dd601242a947c728d60bb90", .Okay}, + {.Mul, "44866ab7ec87112628bde0e9758a63", "b7d58a410dfc656ba4ee7febe6bf82", "31353f222482fab9a5e85e018f304e9aa760645919e7f51f912575e22346", .Okay}, + {.Mul, "575f46aebf14ea609353907230532d", "4637817bb446da1237bf290e1ea189", "17f6fefd32b6f601a83d38e4bf270921703a02b32fe168087b88b571d015", .Okay}, + {.Mul, "-d3cbdbd2f21ebd144454c334b93df4", "3ebfbbb5e8ecc2b92ea18cff4a1ebc", "-33e9ffa2827039fb21e40fbb6c9a06309be340b90049a12b373a61d41730", .Okay}, + {.Mul, "84a3cd15d34847a9758d3b11961af2", "433101297ccfde0cdaeb8ccad0acb3", "22d042a11a2d54bf4bff86726879ea291ea58a77a54e86db0daefeaf6f36", .Okay}, + {.Mul, "-64136a6266ed6abe87ed3706943fd8", "dbdcbffafafa73d199f7f4d7efcd1d", "-55f2e7be340fbb5d05f4191b01ad717f943b54052d56ea3ed76678933378", .Okay}, + {.Mul, "-5bfe6e7be4b0b0ca17f787a072688b", "41ce527e375b102dfbc78ade5d075", "-17a5be6f3745564b0b9477a2e1afd36db0b125777b34b4e3f7ebc91b787", .Okay}, + {.Mul, "-3b1b33854b020ecbb222f02ecdade", "6a516cf7da760278519b5a97701d14", "-188c101931a6f00282bf087e5727e05cab4a01ee8fe20d057c5c26c3f58", .Okay}, + {.Mul, "af79829a187f36fd50a0f0484732ff", "95ac06bcf623838446fa186d0d03ac", "6697a345cecd217a22949b3df9c0c6555d3612bd7be55b3cbc858f624054", .Okay}, + {.Mul, "-cf9b03bdaadbd17183b885e99361ff", "e9622ffa660477ce783a70e4dac206", "-bd43b6a794ea566fd47a3ae9b3008fc072ce5ad78a6c97329e7db8dd89fa", .Okay}, + {.Mul, "-b84e91c9541248b95281d6cb08dd4d", "148cb3bc780846dcbe55c27b63a9cb", "-ecb6fc214b907201c2fd78b4c8e2dc9fddc05dec14d0f19cd776de6510f", .Okay}, + {.Mul, "-7bad2a44ef9022693285de9e3f5eb", "8e92cffd58004640e88d8141cc1b97", "-44e0faafc206bf98aed665582e775f9679c816f785350915493a2a9d69d", .Okay}, + {.Mul, "e1f4ac61db7beff8e476d7dfdbe066", "b5bc67e0d168566895ec87eaf6889", "a068493fa852dd048be35a374d68527c16c1ce5451fdb0e4fe8b98e8696", .Okay}, + {.Mul, "-6b9a96470c99dcd170ffaeeb164756", "5482e2cdad6205a78faecf2ff36e04", "-2385bd248c8c9db7c5790d8772a00b32426b6572a387d25d8787bfa21158", .Okay}, + {.Mul, "85335af4a1e42c9667d2ed0fae777b", "f734f0113b13274395534c15dd4d61", "80a018199e4f3896f52378f8854609841de32fe2d314b4d76c78a73a449b", .Okay}, + {.Mul, "7166d3abae4e93b9be030e2ee66b4e", "b9a72bd1356bca84302312f0a3c45f", "523d5c7418202cf6cea7836cd205a28289d4d278b15dc95914f7445389f2", .Okay}, + {.Mul, "79f689cfe4875f5eb61e5e08aff7c5", "99e2700dcbd8c220cd4950c0994acb", "49503965580a5ed437bc7ea40a53509693d37af558a8594e08a295e56b37", .Okay}, + {.Mul, "-76442ae1ae81d078455b1a1327d6d9", "24fe3d11def7f411e59531e40f7e81", "-111709e0c835af6598eaecffe0e8f3263860eb806151c129c4c91d891159", .Okay}, + {.Mul, "-e800025b39a4c886bd83c9f84b9635", "4a8914a5e9e5c49964e8cf96776a75", "-438c3b65fda45cc57217122f10cc28d766bc212d31f546800e1ea7609839", .Okay}, + {.Mul, "522b38dbca9e077a790b6c77eaaa7", "12879eaefeafee973f31cc14e3efe5", "5f291b9485e9cd87a0b1ad522366849de9d2bda350ca5ad67a13b59063", .Okay}, + {.Mul, "-97ee3b756e79745435dc5da4631f5c", "26503f7f98938b4a9603246802c1a7", "-16bcfcf55d76f66f0864edc606f194220e6b32bf62828cff64789605d104", .Okay}, + {.Mul, "db1fd8b842eaa28a1da00f6e88c828", "35f5a9bae3eebbd35babf49224875f", "2e2fdea08c814dcdb5c1c1f3ad3c875ef99adb6664f505e594871bef5ed8", .Okay}, + {.Mul, "93013e0282d0b755f96ed81d9d7495", "348e54b9201d4af63b7bd7f8e3c9d", "1e2dfbef9ea691b04541320d68582d857179585f0a23eb9c0a8a6896b61", .Okay}, + {.Mul, "2f897b2233ad22b26904c7b448fe4d", "1df9947cede6533e06f81ae388c17e", "590eb3e521356be776e8e2d973d889a7255a0a8c1cf3cd1d54d238d36e6", .Okay}, + {.Mul, "-51009b6b8c43f3fee26550c60577d", "292546c83ec4f258e0892d36a5c619", "-d04e46036d7730ffc6423eba1e9345936158752150567618667aa43935", .Okay}, + {.Mul, "-a6ef5dd6d1f941412e7b8623841181", "edd510fbacb79ca621a2dcc62f0806", "-9b168a1c074f72dab2b3769447fb74715cbf7433ef5f683f6de5f2537106", .Okay}, + {.Mul, "8061ba53224c247556d7274cd34399", "5e6ef27960d04c52c6b7277191aa44", "2f5b8601d731755f0770b08814129c3f4325272b92240ff4af4385aa8ea4", .Okay}, + {.Mul, "-2d1c0f72bc893b2bc3cfbd949ce351", "dbc1bca671b3ed66a1620c6ca2873d", "-26b9249cbc5ce734974f8cf3fa5e7a36d164e84992bc63305e852a83e14d", .Okay}, + {.Mul, "-52a5c60b609ad56df65e2b990a6734", "e3bfa2b9faa4e03e43cce2a19c93aa", "-4986dcd3cb30ce1fac68ae4a2b541dd51c75264963e34b86eafb31db6488", .Okay}, + {.Mul, "8deafaeb613bcc1bfb4598383751a5", "fcd5a11357f0d58bb1dffbfe9a2f8e", "8c29bccdfa8dc93e601c84daaaf2e07123379cdc23a3e4f108d129ee9486", .Okay}, + {.Mul, "7f8f3f0656c91ea54faf15981c39c8", "2ded5174d142c3e7b06a040e476c6f", "16e26e47fe3e79e95f88505d6924c467eef03089a2e94a9678a5d3156db8", .Okay}, + {.Mul, "-b298e4e765fd328ccd189aed3baaa3", "d737f0e239ca51659ab6917bffd284", "-96256f24ae42c324ec65137b4926242997dbfe8fc0e18967483b8e1ab20c", .Okay}, + {.Mul, "-445e93872381bf7c34c713e89ec7ce", "2d7fa42d25a67f8dc1a864d1d8db50", "-c26b6b29679103e2921c0f94de536f53919108e998959f561c84a5baa60", .Okay}, + {.Mul, "-90a6fcee3eea8595fa63bb36793624", "a8afbea51a2f043e273554e84db607", "-5f50e3dc7a4c48fab6d2f2ec8101817989c93c8f00d1b4e4462e92a212fc", .Okay}, + {.Mul, "424d5f783f1d5988f6cb445a61fbe8", "1deb12f4664e3665f6bdbc3742fee4", "7bfa5bfff7ccbd5a74efd369ca6f7249e8a0359615640647b4f81048aa0", .Okay}, + {.Mul, "-32b66061bcc8dca1342b8f5c80b513", "c7f3690f21423cf2e57cd4ba1838fc", "-279bfcd94354b3d77dd1e1311e6b270999f935de454539d294b7fe1666b4", .Okay}, + {.Mul, "3eafdfe69c23f68c58d2aa3030f4ab", "80fc4c274bda04ba2bcea26e8bd6c4", "1f95b7b98aea2aaee55ee9f90b5959ab25720c525df871ce308224db44ec", .Okay}, + {.Mul, "-151b990d5024a131895aa46d4691d2", "e9555a7075ec61e16cea135eaccd44", "-133d27ebe8f7b155c5492b9bf0685c51ad6279b685a520c9dab99e9be5c8", .Okay}, + {.Mul, "db728ed1d46b208417ebdb4d85e6e7", "785434d6c806ed59f43c3e548fcf98", "6725e1d49aa95cab5bfdd463e3232d13e24ce624ace80692ab67143ee228", .Okay}, + {.Mul, "-e510bf187b74481b6d4c11acca819", "1a395e5bb0044925d244314cbfb350", "-17770891399b9056db54fe10f95cc386db1912322106f421377502502d0", .Okay}, + {.Mul, "65212dfc5a04472a2ce5d73d07d6a5", "c9cb69cad2343849c6bb27693df42c", "4fb7683554dd600214633837596b8692c47ff5142d222db4a334c83f285c", .Okay}, + {.Mul, "1a1a416297ab7d56bf1b7d676de207", "1d807e26eb39386fdaab38d3b2fc58", "3021365c08a6dd9a054e51117b0f6e6dbadc42fa9a3f32c7f26a6229668", .Okay}, + {.Mul, "39ca434489546ef160936326abb745", "c2b336423f3ca7594ec23230a01267", "2bf3bba6979a467c71f84367301ff876749adff2df521fe2b8c61d1996c3", .Okay}, + {.Mul, "-df5edbd9c635c583d77dd7e3882bec", "dd1b949aa17a6227709afe98ec7ca5", "-c0ecf475f323ebe46dc647d47bbeaa9b1c2531451f3a63bed620399a9f1c", .Okay}, + {.Mul, "-7e4b9aa40fff0ffc6ef342cce21f7a", "bc848f00f9e34c6d13cf2ab48419d6", "-5d00eb18ef00e0590e7a7f76b4aa23561d0609d0e24bfd9c52975d0139fc", .Okay}, + {.Mul, "-4831b33c1b288f9b29ec5949dcc16d", "a038f9e44c50189ef9fdaf626a9427", "-2d2f215d7f3dba4260c56056c05458498044889e97c4fd5baa44b1967b9b", .Okay}, + {.Mul, "-36b936b99eb9b33b656020f242b099", "2051e2b773bf7d92993e6b348ae5c7", "-6e8a7e83e068e96865760657a12b8cee6ae27bda75a93d93417404a23ef", .Okay}, + {.Mul, "-26fe93415bfb0ebdc93c075526c9e6", "74c8c08c38f185da5b3e4f594e2240", "-11c9eef0f313a5ce8da5aa0998f00e770155c319862b4fbe6b20ea970580", .Okay}, + {.Mul, "-ae362073dc0c468ca8b2b5a1d59fad", "a83756ea4c8673f95b521d119fd65b", "-72792e12a1c07ba61d30d166660ada8c7c80a7deebadddc18fbac3dd607f", .Okay}, + {.Mul, "-24110701a8d75f8c6116242fe92f4e", "a94c2f969941a10e4fd878a602df63", "-17d9f96284cf2330016bf721f58cb2aa9bdc33ef93569178a6c999fe3d2a", .Okay}, + {.Mul, "44420de61a79b74296fc1a97ebabf7", "3c1475021307f3f0aaacad72a7aae4", "1004ef9dc21fe43d162ddc17be032b6423f7a7d8d269a2b567cdfa382dfc", .Okay}, + {.Mul, "-110dea3ab5feb4de6bdb7e039405c3", "4b06753507078f16346e0d234ee8b6", "-4ff81c19518189bc050f47438af4e050861a299cc73b114a79f1aded0a2", .Okay}, + {.Mul, "-d64b33e9d82a0d913b6f4bb440f667", "99db8444aac20b03eb173eaab801db", "-80cab3146cebca57a596bc742d35f964d95da7328246a0d021baf491311d", .Okay}, + {.Mul, "-daa746dcf01f18a5ba49ed22f15bd5", "c28e6f9789da0fb68f61a9861b7c0", "-a62c6bccb2a71f26b0500ccf66bec76c7ea3ba0974fe6738371015f22c0", .Okay}, + {.Mul, "-95960b7095fccba3c7e24a6f33feaf", "b6ec572d13d8fc70f9a2ba4cfd7c2e", "-6ae2c564eb48308a2aa1c67ee8bd79986b1652d00d5bf742d661d1a78772", .Okay}, + {.Mul, "3b14b87809513ba75ee477d9da55cc", "dc41767bad609c0ea578b4c9f022c5", "32d4ea22167b6f4e339d14830c4fd08912ff335ace98aafe58a73fa91dfc", .Okay}, + {.Mul, "-b56e0ce822a4cbdee0fd898e06b3c1", "8eb0a145f1146cdd1fedb2deee74b0", "-6520391d6a71c6a3737d24343134a200dca6b04a85ba830e263b297d08b0", .Okay}, + {.Mul, "e454a1e4bed1213a3d57e882515522", "b8756cc542e5b9da9b79bac82cc41d", "a485900e0bc952330b34f2eea117223f3bbe7b81ee69f1f1d64e3a3cacda", .Okay}, + {.Mul, "-46aac845c5d8de07ac1090c89ab176", "562cccfd5318b64b97eede32ccfb8", "-17c9bd37e1c493bdc36b7dd6704324e360e321a3b0110a8fe7566f5f6d0", .Okay}, + {.Mul, "-3151fbbd6b9b6383ede98a2142f16b", "30b3d37ac0ab7116a833fc9da2f37c", "-9620444c24cfca072bbc99279a0393656361aca25b7eff04d3a0c4b80d4", .Okay}, + {.Mul, "335c84c9c64d828ed030660a0965d0", "aa53af88985931af7b92d1418b58bc", "222c3a64b198118e6252e38a5f683e75e5410d92f5414a273326b1d644c0", .Okay}, + {.Mul, "1e508dc9ea2bb670e8cdb2927abf6e", "4147ed828c29d40bc68e2079cecd61", "7baf877a039fb52e250d0d0e854276f545af4fb06ee5076c4f6d4519eae", .Okay}, + {.Mul, "d845cfefc2150ef4b79e700b34ae58", "f10f4174e330fe9d8624fcb8ef8316", "cba69c245e1f96ce7a0b163ff6766d70b6a127d9477e1af3457aefe60390", .Okay}, + {.Mul, "-a84892b7a41abf2f677eeae9ea1de9", "62a7477d3ef9dbee3a49e745cdc200", "-40d9be807824af83474a37f839af33ce67aa95371ddb9ae9de0c2b3f9200", .Okay}, + {.Mul, "6dd464ada799a21da3dc6692280d29", "66eaa64f07673fbebaf74d57927652", "2c274b9ad8832fd8affd595c7906853015def63d6fc52cc75bdeb7471d22", .Okay}, + {.Mul, "ba6f587aff239ec44869ead277eb4a", "ed9c631b8584d323810a5fdf3198c6", "ad0af8f0e359ed794ce7085aeb211e0d21af3b927b6a1a294bf57b9deb3c", .Okay}, + {.Mul, "9488439fcb0ca82ffef3b1e73c95cb", "58daf70289573fbb034abc9c781152", "338de29975de823a0df0f5a7a79ba0de875f161649a55051de1902827606", .Okay}, + {.Mul, "-f5ebce766834dfec83d9bedef2e76f", "dda4005977ad80a0433da5276713ec", "-d4ea1ca26dc2773c4762774c6fdabde704db36ba5412083a390995c39754", .Okay}, + {.Mul, "18a25b8fdb088f2d75f906a6d6bd13", "ec4f8d1df6a13df060d2d105e8ed1d", "16bd54172dde9e9f41e87fc3aae5d7310fd8c836abaf40bbb5056b960227", .Okay}, + {.Mul, "6bce9c86489e6e4121f9eaf16bbb9b", "6752dba265ee657ed07588aaa930f7", "2b8305a64dcdd6c96cd5548d683a8db85a4250dd89276cf89afee972128d", .Okay}, + {.Mul, "-389c9899726c8953a7980b2fb7aa50", "2c1f985315137474bbc2d84ca7e8f", "-9c1e6e034493e543c102ba30fe3f324dcf701e67c34ead7a89b08b82b0", .Okay}, + {.Mul, "-638156a2797b74bf1afe4a6a155829", "74e164b5144532b3c52a7de6e51b1e", "-2d6e3713ac036f12805ce36e7c3532d6b8f3fbdc2f43614b7e3a6179a7ce", .Okay}, + {.Mul, "17c56d621ec0bf9f4988c9ffb58a58", "96e2a0b903fecb43e9bfeb73b2536e", "e02b94ea10c6e9bba96d075905ebfd5b13fca1546fd433a44db750bf9d0", .Okay}, + {.Mul, "5434db36000e8bac5f54a265937cd7", "1ec75f704c2cc774c86cec4efeaa4d", "a1fc62b48831d1767efda6025693c1119798832ea556b8dcedfdd9552ab", .Okay}, + {.Mul, "b5ea69928f817ed539233771138671", "90ecda3eedca99db6bf31cc8143ae4", "66fc2a92197b7e74e5e988c776d8faafad1bc5965259ac84fae9eaad56a4", .Okay}, + {.Mul, "2eeb40708b583201f9e304583327b0", "abc439d3f6e56308f0e18ff0a6084a", "1f7b1ac1bdbddf3a804070e3814a666cb0d9b8aa4e969849c3b3d426f8e0", .Okay}, + {.Mul, "22bb60094453f07452cadfebc0cc1a", "4de319ec33a75def81f40d687f6b05", "a912b8d49e44f1473055080d09259a2f93135d41c0657b2facb00f8da82", .Okay}, + {.Mul, "-c622e25a31b2630787c2c3cc7f048d", "825ab77d8a98ef9b0a52b6ff1d6d89", "-64e3ed397b0e3abf0141ac94f6da8c0df799e8edc1a48cb9af047be27875", .Okay}, + {.Mul, "-78fa9f5871df4be60284a53506ace8", "555ebe5c004b5baa6333a5fdbaa33e", "-2857fce45cc1793c2ebbe5b63cdd3f5115b51b64c9ab63f91a0900459830", .Okay}, + {.Mul, "f9223a939918688ebd108b67b0dd13", "b47a0c09de8ae7284d2eea4ebdffd4", "afa2d736e781f5b8655d159cb164bdc3836417f112553eaa7e080bb400bc", .Okay}, + {.Mul, "-943737729352b29148a5ede873428", "7fca102a1b1f730192c073ff1bdc68", "-49fc616f6bb88ff6d3e82dff6f798b620f3f72781a0b39650f4eff79040", .Okay}, + {.Mul, "f678ab3edab18671450523dcecff60", "7f893b373234e50954d8a3de35a854", "7ac9fc8ac6dbe0130693fcb69c4b8e50e0e60dc3140d6de71566243acb80", .Okay}, + {.Mul, "b1c0078695f4151046315ab1eaecf7", "196cf07614b6c545ce901c306736d0", "11a764b5555fa5ba87584178e5b105c17044dac55306c109b82fc43da2b0", .Okay}, + {.Mul, "c07906a11538195b97aad3d600412e", "4c39beb28c41eb9174bfa488e0cfe9", "394f584a5cb04a3c7629b6025d5714d66d1cb146643be2da3b29732f84de", .Okay}, + {.Mul, "-f8df3efc9c22fbeec950e5948c1aff", "5c19a4554b1a0cc3ff59a493ce7772", "-59892831de444a641451cd1ad116e7a129fb1293ed6dd76face36d228e8e", .Okay}, + {.Mul, "-bce363aa51ffa47bc5b0e065ece971", "d7f2338955216fbc4e7c18ec2425b0", "-9f55adaee33aa7222ee77361d87450a061604a5246d9d3b5641e5081d2b0", .Okay}, + {.Mul, "-a0b4a8aeb0fb50d8af47f668a7af51", "16f6c674eb22c0402ece9dfa29824f", "-e6a70ae3b02de036e6a67f0339e092c57b0da09df5fe7c48ceca0bf3bff", .Okay}, + {.Mul, "a7b130f6922209b6c811bdafe63957", "8f5760cef0b54fc39b3ab1b67d50a8", "5de536fb600b6ca359009c61d7c41f8f7e04c28f2cb7c15bd6c83a7bd118", .Okay}, + {.Mul, "e70bee0106fab769314a0aefb7b703", "7e7961010c65032c60194b99c77d44", "72256b547755be26a0c20ae2bed50809885f592ff0a56ad60f056f7e13cc", .Okay}, + {.Mul, "a626ee3e55572e9a2755990517ed66", "5f4ab1e2de21c7dbe733f38a45ae26", "3dd8ed1e28f320dd0bf192ece649680fbada240fdbab400da56afd669124", .Okay}, + {.Mul, "f930583e6fe961405c62264fd0ac0", "d601e9ddec95bd88b4e34db2c5fc1d", "d05046998f22dbf1e2e172e159aed275fedd0853631a60571414cff37c0", .Okay}, + {.Mul, "2987f181680da944d99703f3bde7fd", "d90f796edb6c14b41c90cd746e33ca", "2336be6114f17160e00be5870112f4d3dd5c8fe5e120a028d0fe7bc674a2", .Okay}, + {.Mul, "b55e5cf9862622af4c42b2e401b4f", "7e35533a3115eaa5b766001cc1ecd6", "596a3942e1fc18c5439856a6ab71492dafc2b95ecb7266b260cfd52a80a", .Okay}, + {.Mul, "57418ba7b340d0a54fd0108bab5299", "372b8451c37dc28af9cc4031eab297", "12cdea1d270f7be4abbcffbaaba44e44492dc7ff64559c1242884a561a3f", .Okay}, + {.Mul, "4cbfd5c01bf90779f2f8712b25e2c5", "d19291e213df2ba484a436cc500f54", "3ed48ea62dc7eb9f91fa452601782d0f66e76d35feea92dfdcc33a47f3a4", .Okay}, + {.Mul, "e3772c48f879556b2742db96dbf7ab", "8a3e17a26c610dc22e4135c1c09909", "7ad569bc164eacfebdb42fce91eb4a9aa1cfbe230c8e18ea42fa7000e803", .Okay}, + {.Mul, "8acfc29a311cb6a71b172aaca92a9e", "b7b6c917925a82527064c1bc14c3a5", "639da0da7a8b8e15d2b03d324ead73a842c930f5a2a7fe8c01a780d6d1d6", .Okay}, + {.Mul, "84d4bcbf06db9f99c7a914cbc74a7c", "bb7dad92efe9ed05c14f8ac3a19234", "61489bcfb4a58038a7816a4cdfb7704ef14317ae5513352f955b58f1d930", .Okay}, + {.Sqr, "-96032b1863272aeabca0bf9c563edb", "bcf7f027360196e1ff31b7270971ca", "57e7b68a9e056cd7fcb704e0b9d9cab5d76c0900b6472464c4733292cf59", .Okay}, + {.Sqr, "65c210762a52b74725be8116ebe140", "c6850a990ce9bb13d7c3e25b9e6ec8", "2872b41a318c65d14dc69fc39dcc98a5258704545fbedaa1668e51b19000", .Okay}, + {.Sqr, "e144ec2dafbef25ad3b3700c27e2a3", "ddda1d7608e010982362e85a1c76fc", "c63a39b6a11747a3b9012a4ef9eecac033db69b267509f1c04161e4e33c9", .Okay}, + {.Sqr, "-ba5b5d0fd1c3a6228e2bbb0754af21", "68af15c533186ac5aea79f8a881669", "87a8e3d647e3ede4baac3d00fde0c1e44f108f68625d355eadcd33762241", .Okay}, + {.Sqr, "-18cba201d349bb0bf72980f8855d33", "763cbbf829ba9b5a5044ee117ad00d", "266d05aad09396d8902fe7b879e6204e9775d04d67268e4330cc8ec1829", .Okay}, + {.Sqr, "-9f58c789e4840488acbc20758a982", "7584cc11f734750f0c43ef65486d6", "632f66a71430c3f084dd34a5cf7f85cd8e1ba4f6a59f930d02159ce604", .Okay}, + {.Sqr, "a8cb4a1772191b050c5527a2b23526", "bd0e3b03699883aff445dad3e33a78", "6f4b72ad5c617763b12d77a2a0f5e10f1a4aee3630f9c88d74e60be0c1a4", .Okay}, + {.Sqr, "-ecec85c1509f63d696d351c22c27b3", "c69b2cf4f3330702672843a03817b5", "db44f1234ef4f5b40131384706c2be02ba0ac0384cc1066d250ef7b00729", .Okay}, + {.Sqr, "6e78c5e09ed2332c772bcafe2235f3", "46570392f186c3c0ba3764445c313f", "2fac030724050290053d7c7d88fd1e6a12fabfaa0381384ead1c93ea84a9", .Okay}, + {.Sqr, "a9fb6d596e151b2974e03a3eed2493", "2c91f1c6ae5e683057d72b95b78231", "70dded4faf6b023bb2bf92089a2109b5de3273b0cd01ce258bfff167ac69", .Okay}, + {.Sqr, "bc8bdf3efb952c1f7f2036aed630be", "10f49df8b775088db48d5d4137749d", "8addbc50b2971698e349777a06e1442499e34398fd062677ed9fceefcd04", .Okay}, + {.Sqr, "-d933f443efdd3bb7fad9614ce780e1", "370153cf234131f3ae7bb40fb37c4a", "b8491ea668c834a8daf546be84579332e2d7f7eb297b3c7b62616eefc5c1", .Okay}, + {.Sqr, "f4101d1231f1cb088c95aecd299126", "a835ee5b4488b864fb5e6d91f5e09a", "e8aeb86e54c849dd84cdd913cc7980d59cff8749aefb0d7324deac7811a4", .Okay}, + {.Sqr, "cb3917e1d3d9bf8b59ebccefba0204", "cbc58df3bc21c6ddf6c08b8a599db8", "a153989bcac6080581286a17e2dbb9ac58bfc3965bac2f6b654a65d41010", .Okay}, + {.Sqr, "-7f75582e48af0b22ffedbcb280adfb", "d3ee9198b10014cc03e55005e428cb", "3f75a347a4cbf763731ecf02ec4c6ea316bcf038d5bc31a379477d3d3419", .Okay}, + {.Sqr, "b02ca54b742092e9afc3b8ddb046ce", "dabf5009db86e960f23d423430b5db", "793d6b10fc570f230f2664407d96bcfb28057d616215c2e16fc11ad54dc4", .Okay}, + {.Sqr, "-a072035a521af3abb1ee2905679287", "dfcc7b8498c40898e390470b66ccf6", "648eb6f7e31e0e621a52cd385f7e7d139b5a1661bbe2486b28de82804331", .Okay}, + {.Sqr, "51d07c5e42ce3c83746fe0f73aa323", "1af6e06fdf02221a9d21934359c632", "1a25987dfbde84da70cec8d922da31be52bde5dfb89818900b7bddd196c9", .Okay}, + {.Sqr, "8794606f0ac40c6f56db89d5f276e4", "b3956272d660c8609e9b7d010c394", "47cdd3b4c212b0092e222a04bcbc82d1d96c1b0165a520eab7846646fb10", .Okay}, + {.Sqr, "-f34bdc4e02092c322babd4fff2c45a", "bd20405e84a72901fcc82b40856805", "e7391ab6eb28c68c25df1bb3937dc16347eb5788e2585a86fa731cc1efa4", .Okay}, + {.Sqr, "-42127fd5f7d57944f48ae1009b2a78", "bc028bb9a9ff29b7e5353acd311a37", "110d8b408db6eb48c345d8f2c485ebd6ea3cfb7cc6320f4a64fc745b9840", .Okay}, + {.Sqr, "4557b3659835cbb67aef9141111e9f", "93707b149c91f3d23fba0881503d5d", "12c864c030d1af8d84208e4081440c88c7d1d9cb4bee00a744cfd2c7a6c1", .Okay}, + {.Sqr, "-8b2de3edce3acb586810c048f5e0d3", "5ae0f63f75676df66f31319e0d5e91", "4baaddbe2a7df22141b4bdb445bd71eefa0370e31685fd26d71ec94fede9", .Okay}, + {.Sqr, "-2c3bac51f80aa01cafcc5991254f29", "10c5ad10b716e77b45cadaf3a329e1", "7a491250f0a3b7cd7dbbc058063a90776324795a03ce673ab9e6c545491", .Okay}, + {.Sqr, "248d700f3747480b070b40a1af4e50", "5bbfd64ed6faddc6afa67bac3c697a", "53815a8e95c420e5b74b8d51eb3218e73b46258f38776e0008cc954d900", .Okay}, + {.Sqr, "-8b55eecbc429730db7a985df0bbed8", "7904128c9f91f1fa733ccafb43bace", "4bd66e29b914c9650e878616a7f9d1e7cefa58bcc0bbcf52f37644d55640", .Okay}, + {.Sqr, "a1bdb894ef3e2fbdd7873ae8004eb6", "4f02f4304b8eb587f85ba11f021fac", "66302ec565ebe86e2b859b580547393f9058250261cf371c2d21f8336964", .Okay}, + {.Sqr, "eedf0d73d59ccdd4339daab88c782e", "2c127094537aabb8ecb30f8b1ecb4b", "dee37f5bd1b2ae00b1b1de9193b31fc9c24708c590e5fd5642edcabb2844", .Okay}, + {.Sqr, "214cbdc62577328fab7c04a41cbc43", "d84a5871925e2078bd9a30c8d75a08", "454dfee4ffd267f0a09d06506aacf997042fb3dabf3bbfd9e87911a7989", .Okay}, + {.Sqr, "b0ec53e6723d1bd57cb8354b3988c5", "d0ec3c7ef033cae001d7e3c1bd0427", "7a45cd87a975e475f5f02ac5a934e71d5120bc20001d416094a39ecbe799", .Okay}, + {.Sqr, "-38404a00734c5096468848dbebec40", "a1644a4836e092ad830ef045f8ce67", "c5c3085480f4c125c836bf265430d315637fb57e4474fa663a117861000", .Okay}, + {.Sqr, "-fcd241657f20427a6f26ee177c4ba9", "ce6b5a4a00fc192aca3160afbf2360", "f9ae9d6f2d80c69a0c0aa7b07f047254cad95175a57344486c2dc0147591", .Okay}, + {.Sqr, "-b5f088b23f4d364e7c7c3dbb80ef89", "2f30a66627b9de15ce55da24373215", "814e034ca4b7beeeefeb19ac5a42c84c9d354a478b33558c7e2c8f211751", .Okay}, + {.Sqr, "8a92aa874fb37a1c07c9b45525b96e", "2e3e3c282710161a6fd8834f264993", "4b0273e0d5dc65bd06a69f96e24855de3842789226354a9191622c1c2b44", .Okay}, + {.Sqr, "-9fa4bae36f6bdcc76a7eb1f8d3e024", "aee102fb155a58a4e085ff894780f5", "638e0a26803e066a1c63dab550c155aea0b6dbae78782d4a9368ff970510", .Okay}, + {.Sqr, "-c1f9d90198b3969115c916b7b76f41", "3ec6e76519fd14e6ce2824170f8be7", "92faad0c454d8b44aad47a48795fd2c9c214c787e4ce06bcf5ab2d476e81", .Okay}, + {.Sqr, "b119dcdabe5610fe04a3cc67202f59", "a68b6b550b1b75bf081f4593bbae4", "7a84c6035c74e25b3954cf666f9e1f5dab5783c6bc9d97e9b5fd7d01ccf1", .Okay}, + {.Sqr, "a844ac579705561ee0be91e36647ff", "bc4ad79ad7f7d5dd8e4c3f57a86caa", "6e9a349ef8c50cc571d2d769b3ebe9352d1f46d121e0f8fa9f69ad737001", .Okay}, + {.Sqr, "-8ced1e5e3e8f37a3a2fc430617e03e", "f4eda682bbcf282360f49f86db0cd9", "4d9434d85286b36390c095d40c361e00116307f9c1f5f4969130f7908f04", .Okay}, + {.Sqr, "-2eba35216dbcc884cbd8c80522aa4c", "7afb66b27fe2e8d671c1158377bd6c", "8877289430a2a30bef71b81065308939cd75717c04afa2cb618a5790690", .Okay}, + {.Sqr, "-a5e6949e50966c173b1ef81d88651c", "47ed84c8b1359007932c1b32e8f554", "6b830b4376a224b5abfacc760dd0154a9b9a627d560ed646a5d3edaf1b10", .Okay}, + {.Sqr, "680a7e1e171b20cdd710ee090575db", "abb926f6ecba4a8c8885e32802a957", "2a4886e68b417b0def8ec171ebb15e409d6294f82d22290de59b36cfe959", .Okay}, + {.Sqr, "395116aed9d21fa229faadfd618c99", "439ac2bc8ca604a1eaee182d0d5eea", "cd535c939a7edeb2bb8f7ddeb94ef7078ca358ff961a43ecfdc4329b371", .Okay}, + {.Sqr, "-1aee81a32e364dba31d14dfa1dbae9", "50441f54bd4a7b9ae95050c552a54d", "2d5508a7272d158f42755c7f846630c95c9fce6194b16a2f6acf5416811", .Okay}, + {.Sqr, "6eb5a368a85218a76731d6a2c1d5a5", "2035c67b087a775d70914057bb3861", "2fe0994e6af30268762bd10a359aaf6f233e56897de9e81a3f04a915fc59", .Okay}, + {.Sqr, "-b0f31a0264dd1143754d57f2a4fd4c", "3367f4d90096891e514b8233cfceb5", "7a4f2a9daddfefee2a0e7707a7db26469b25fd6309ab61f83ae133ff4e90", .Okay}, + {.Sqr, "6d15b89c35c34d91cc77a6ae2f7e9c", "67997e3fc9261b2a6ff03806c624a6", "2e7b810cd48a0eb332dc024c80bb3582c4b36aef9d6d0471d33bcbe5ef10", .Okay}, + {.Sqr, "1cfa83e5e9440eef4f6fff95b430a7", "22dc3a236081d52b713ee94f476a23", "347c2002c07976854603f603c5c2af04b36f9d0854fafc6fe28da170cf1", .Okay}, + {.Sqr, "-7b5ae7477513e82ee5b7d4aab8e0d9", "786a84452370385898b488b2f04c5a", "3b707a8619b17c586552cbf9eafb4999145398a75b9fc5beb58c316c77f1", .Okay}, + {.Sqr, "67ad65482b34d4b6bfa149cbacfa94", "98b3baa5d472a952a40ffd71a2aa97", "29fcfcf21e60ef02920d6dbd30cadefb9f960958ecfdb6b8dab064256590", .Okay}, + {.Sqr, "c2ca6c24bc7d45fc9efab97a33b534", "4eb5e4be10b10b376f34146489a019", "94376bf68556581494aff612a3912b06a472be4be3a8e32ac84f42fa9290", .Okay}, + {.Sqr, "-70c9e4c01c5725520cc45430ae7999", "24296b291c7008fc59afaa4d50d95", "31b147611adf84262659259bff91d2795eedb03280b6904bf8eae5bdfd71", .Okay}, + {.Sqr, "-31b628481c0cda61513161e16608f9", "405b4dfacdc6b39584747b967b93bd", "9a73d08e79b6af392006a370d165011762fef5d332804c8a322d8bc8231", .Okay}, + {.Sqr, "-4f2c45d269d7be9ff96d19f8b94941", "3aa585c94a0a1c10aa22d269d0cadd", "187c5abff0b2a3d06168bea3701be6033416d5610c5b8cab2cbae4e82281", .Okay}, + {.Sqr, "a8785b19af72d3e36d2b173d96bae3", "c74562d8a2773434b2c42936497c2c", "6ede30273ec6771083ce2a20e9b1c07bd6188d88d0c879fd0499b872a549", .Okay}, + {.Sqr, "98ec9821f78394afa1a0901c5ebcd5", "6cf823b54c8a4f3bd2af63a844b87b", "5b59cf512ef4f598b38cbcee27548cb3a3a97093fe3313ad8bfdcfb58939", .Okay}, + {.Sqr, "ed6216463744f4add0e26f802cb8d0", "2ee92b08ea59cc9be1178a1b77a181", "dc1ec2d3120822974989927b6de380cf6928b18495d4cf4445000ceba900", .Okay}, + {.Sqr, "-30b7f627a3be5a4567eea8a33c0b93", "568188220cacdcb6d81ea62daedd", "9458080b6c3b0d4386cefd527ea59b5e43a40c80e84dab409c29f6df669", .Okay}, + {.Sqr, "-5d47be6143bbfa9b1ce098466281d8", "6278930829ec6004371ff8115c4ade", "21fd346dd2beabd923634ad623e5ecbb260d54bcae6802ce3569cb3b6640", .Okay}, + {.Sqr, "63ac545335cb6ca9c939d1808db7c9", "17c884da5041ad1a01189df4381070", "26cebd39c73255bec24edc85300b8f9e2aea1c0bc97c3f6d9e6ef75afbd1", .Okay}, + {.Sqr, "bfa2b3d84303899e3aab1d299bbf87", "a18951c3f64c810d559b9f14ce86e", "8f742fc4d00c3c3c61c3f138a0fffdbb9a5e3acd3c63f31700b0bac4b931", .Okay}, + {.Sqr, "-2e23d45ad1358df4473159249f1abf", "f4ad96e434812035929ae48b3bc744", "850e554642afe61121e163045a380b9402a86f966b2520cd935f40d5a81", .Okay}, + {.Sqr, "54ca18250ebb51e6eaa9294c014ec5", "5f12ed18733a2af6fd592d9ba1da53", "1c153f626e6d257d2cc354d49cab363e3a15754c7f9b25201be0adc6a399", .Okay}, + {.Sqr, "-9f43be5f99e71daff219f3969bbe00", "26b61fb6edd9989030a5a1184848fd", "63153867f4c9b200bef43c41b17d2830049a67403368e7619567a1040000", .Okay}, + {.Sqr, "63d0f08280f1760d7a4c5086bf3716", "b8ce289c7d5efd0124dadb6546ae10", "26eb448ca5c13dfa360547175576c5939a86ad2df776c41c3a3e46ae75e4", .Okay}, + {.Sqr, "-a75543565266c3904d3af4c1404eeb", "a42cafef60a060f6c4dd002fd4e200", "6d605a40688b17a16485206447d1bb4833b7f79fe90bf198f31de3d40bb9", .Okay}, + {.Sqr, "a0457cd6d82d076cb183745024ade9", "f2b3abb6deaa0b63b78834598d7746", "6456eee916e9a7479f81bc64097c9edefae97a4b71115883031affacbe11", .Okay}, + {.Sqr, "9b54af2dc69edc92c8680a319114b2", "f30cc65c0e3c066a7a9a328d9da41a", "5e3fa824dc6e55171e85d9ff79f68bb5635138fe80e927df1a0c97504bc4", .Okay}, + {.Sqr, "3c2e31ba79c2be3ab6b58636d442ab", "de2145e27d83436b9f0aca16528ada", "e25afa551bff599987753614b6b45b769f8062955bddf5dd522a0949e39", .Okay}, + {.Sqr, "55412ebbf0948bf7cc22b37e3e2c1d", "ae1f8ccb372e3e518d2f1e9bdb7eda", "1c6459a191bae4d05ecd1ad4706496a4e411bf46c7169122a713f1a5fb49", .Okay}, + {.Sqr, "-212f13957bb75538fdd44c030d0a17", "67d2240fb3368c7e4136fb2a083805", "44d2bb4bc4838f0723748c166a81eedbd15b2d14d1569f3648e90bbce11", .Okay}, + {.Sqr, "-2e095600260357389361f3e1f56025", "f104e645e4fb954330192e78ab7b78", "8475b3f368ff91ebb30917e1eb9a84b6278366fca954c9fce7034edc559", .Okay}, + {.Sqr, "f629397893aa69fcd06fb12774e872", "3a27912177c98c89f7daccbbb7b9fa", "ecb341173151bad47bb4853cfff24b0ade45ebd377ed20911dda365ed2c4", .Okay}, + {.Sqr, "d98cc96f03e0d143d95f3972f751f2", "94f9cfe6a2d2ff5d0a66b8859e4471", "b8dffaeb247ee4e54e5a3e103eb644dc0e48f3e559898cd94daec33708c4", .Okay}, + {.Sqr, "81c2f149f5b2263c842e90b712ce47", "77dd4c5db29530d6dc6e8f2368404", "41c60b9f2122428268557cf7ec52954e6cf1b5dbe8c33b6d782b2a3257b1", .Okay}, + {.Sqr, "22515e3f0b57630710ccef95c4a77f", "3330c0292f00c6a8f1d4904b9eda7e", "499b6e5859abf754d2b9f7b3a6056ee4e03c30e0ee249a1a92cbe0ef101", .Okay}, + {.Sqr, "adb2e213127734d6c8b9734accd187", "18138247a31392360624d0f341dc14", "75db428cf1207935fe4bd4f106bfd8f154135a87c53567a46a4aa6a5b531", .Okay}, + {.Sqr, "dd40fcc9ff662e35e45b2ef1b389d4", "4c9f376eb9141520eec71c2d533362", "bf3944f421946d145f72ffb11ca8578d526966dfbf80ae55c79b30ac9790", .Okay}, + {.Sqr, "22fdda62d588f05897d9a55fa83aa2", "91ed60055f221cad7819a4af416f7", "4c869bba25eea57ffbe03c4e4835e7e9627df325784311c82e53e0dce84", .Okay}, + {.Sqr, "2803e9993e962fb08fe5f2f448dda1", "c6e75a51ef28d7e525628729ee2eb6", "641390f324eb6158cbcb9820f1a5de7f3d3a653b6e0193e099c526f5f41", .Okay}, + {.Sqr, "8794a88c92a6a36a4cbf83017d7cbd", "90b6890cef2a6b54356e359eca463b", "47ce2017942e1eb2809b7977ef3269909ffe656f81c05ac9e7ea8759a389", .Okay}, + {.Sqr, "7faaec48779bce8ad099180a967c65", "1873f1f30cbc89f9928cd9bb66b915", "3fab088e910122e6cfab48b6da7af58f0aa2c8c1b21ce578271de6cdffd9", .Okay}, + {.Sqr, "b391ac8612f741249a7119786e3d4", "92d90da7de72757d9bb29a99f2fdf8", "7df50a2862abb0e5173a338ed824909587eeeda7ff35c141ff64b1a790", .Okay}, + {.Sqr, "-bd660261f701f4e8e6bc82c7ddf4de", "18a8066918a33440e923ca443a2ad2", "8c1fc82a8ccf668833ee3a0a6345076c01d7cb7a4a33f8059499d583f084", .Okay}, + {.Sqr, "-7a6df80e66a29688607c9f149b6922", "84b4b991227c32190e30b2c5d8cf84", "3a8cffaae672459892af9ad2a78765821a7f10254eec220e2f01ca58e884", .Okay}, + {.Sqr, "b85fac04d66d7ab86d73cf7e0477dc", "b37dfaef2702e6cdc73322f6abdc82", "84c9ab08136b05e4b626970e43428fdbc331465f652f5e49e3d886fe4510", .Okay}, + {.Sqr, "651dc912c5f2f91a0288e6dfa2a856", "68f158c7787f8a20591d43871602b0", "27f0841ffc610dd2f04a52d20a466c9a36d30f48b5db87d6a3274f88fce4", .Okay}, + {.Sqr, "b74915a7cd300b974bcf07993d763a", "2be4259283cfafd6a061b0d7cdb9b2", "833991d342e2aba025b72658f34b7c193eff29297e82d444c93ee23d8524", .Okay}, + {.Sqr, "57f65bca8d169c6c937ce19b9ef1e5", "d16339db1a1c6eddf35102ae8d6297", "1e395f783616265775904bdbc34bfaea17add8de554feb52e824c93cf6d9", .Okay}, + {.Sqr, "2050cb3485a802bf47d620ee931f4b", "e65a13e8da82f761bde67e690154a1", "4144c4cc389e0708fe6e8d15cd5d7dd01d96cabde93c109197c67f53ff9", .Okay}, + {.Sqr, "69222037cb29258d77fea5e75bc25d", "3c034b2d755ddf5a8ac389e818e692", "2b2d02fa5787b6af3c4e8cb07cbf6dcfcb1bf6abc6e94785d18997af15c9", .Okay}, + {.Sqr, "-7fb7e2912d8a392918857405c2fc3", "72687e4a096916d55a2bd2cfd063c5", "3fb7f6e1bf42e7112ab0aa7d1f6b45282df446c359487bdf9ddd112e89", .Okay}, + {.Sqr, "daee27f327fbb4a51cb1201631ff4f", "6a7a7a576d2293d6bcf5de3e58847e", "bb3a79986e7304d0b700ecb5f0724c945c2d9b34a1da60bfb3654edc7a61", .Okay}, + {.Sqr, "-699862b24656dd10d71506811e94bf", "6c149fff90eb0dfd6c888bd64a7400", "2b8e5bab9773c27eb9ce96c35278526e191f91fbeb150bc82483b1316681", .Okay}, + {.Sqr, "f7960e959f85e4a210cc4b4779cfee", "f3f05a5fe39f62ed0684662fb1c46e", "ef72e819d20004fe649b5f32b851bdc39d68ab92d6604e77f0c03bdec144", .Okay}, + {.Sqr, "-df7b2873af17a43dd018c5eb5e9c2e", "b4af2f981f31f2669e8eb09ec7efff", "c317cbb97099cbd9ae4355ea6218e5d7f0e2025ba4418c0bd47f85101844", .Okay}, + {.Sqr, "8ca2d0bc8fc46c432ccc6759d808a0", "7a35024f72d4e86c60cdb7d8dd01cf", "4d427bdb1617bf85272d76dc06da58cf63a03dff1eb0701ddd0dce4a6400", .Okay}, + {.Sqr, "-2f4394d14cbd3264a2b9a3a9ef7c89", "c6fbe6d3d68699ba7c348b7de4a19", "8b9e27c163e4f627a9edd7b9c5ec4475942f94b10269f28aaeca6630151", .Okay}, + {.Sqr, "3e197e7056aac9cbf3d1951d275f1a", "b60190174cf1aa8f9a1c225d92ffba", "f105bc85a5e6db6455bab268eb1775478bcc08078db03cb19de01404ea4", .Okay}, + {.Sqr, "-8596662d7610ebd77034f35dd1c796", "ae62daef0f82f7f06edde669c0c776", "45b59e8722bc330a6f64b49d421b9e2e5dbe59db67a90ef7edae7a868be4", .Okay}, + {.Log, "cb3a39fc19ec020e1cfc863258eccb", "bd3da0743421e99", "2", .Okay}, + {.Log, "fae16beb299a5357f15f768746a97b", "d94c2b3644dc4c2", "2", .Okay}, + {.Log, "cdfc1c960b0a7dbbcc7712aed948ba", "fb3cd2e174eee34", "1", .Okay}, + {.Log, "a24e310c260dd862e8d77664524a94", "b6b6a51de02490a", "2", .Okay}, + {.Log, "69b2d0fca14bef60fa1f6a52c31194", "10d3db86455a713", "2", .Okay}, + {.Log, "d50c7d7625306fc5040061c739a1b0", "ae22cd2eb93ba96", "2", .Okay}, + {.Log, "49da58d5bcd586ce39e552a56a0ad9", "40228bb0adb8c86", "2", .Okay}, + {.Log, "d3f2d1b029221d5545cc44bbf904a2", "556f006ff86e617", "2", .Okay}, + {.Log, "5bfebdfae1b3e243a703ae1ed77b61", "9c9ce969a2387fa", "1", .Okay}, + {.Log, "703a3ff964275e2739799d6d53ff5a", "4aa2c9e71cbf1a3", "2", .Okay}, + {.Log, "a32c26c418cf4ce70d424e8fb86fde", "a00ef549af2b3e2", "2", .Okay}, + {.Log, "a34def4b294cb01cd502957a46d9da", "30fda2f84bcbc18", "2", .Okay}, + {.Log, "645c6f7d9334bae974b367ebbf87ab", "e57ec1f191e853c", "1", .Okay}, + {.Log, "eac99d848424ea1e2de7c72dffcd56", "d2f371e2f152226", "2", .Okay}, + {.Log, "1082c8483da1c096947915dc8c454", "bff5e2b08bef7da", "1", .Okay}, + {.Log, "e012b224160dabefd0faff6acab746", "259f7f571921f1", "2", .Okay}, + {.Log, "5096801b89c3283b8a77372529a9a0", "b828e3688c92943", "1", .Okay}, + {.Log, "1d08cf90d7a683f3ca234f41dc9ed8", "ae6e339254d9d90", "1", .Okay}, + {.Log, "845183d028d7827d5c69d2898563a8", "f524236e909b009", "1", .Okay}, + {.Log, "cebbc28e67d991e30b992d315a5317", "fbe3d82de57f52a", "1", .Okay}, + {.Log, "5f166836737adcb5f0e4ddeeea1bc7", "8c6051e2879023", "2", .Okay}, + {.Log, "5bb360eca0eb29340f044cee3c6294", "ba4019b9a9d95f2", "1", .Okay}, + {.Log, "3b9f4205b467515a78878f0702b0b7", "59eebd58e5f019a", "2", .Okay}, + {.Log, "de75ab6f5bc2d46b762f8d1c714402", "e34ebe203ee3250", "2", .Okay}, + {.Log, "a6ffafc0e9f3f2187767212bcfb18b", "8c8858493503d03", "2", .Okay}, + {.Log, "3bafa218c63dc62d102ad99605b139", "d1f79d8a882890", "2", .Okay}, + {.Log, "93c738e8636110a2e66e83e6ac1ae9", "478050e6175edf4", "2", .Okay}, + {.Log, "1c0e83b6ccc01563f6e4172f92a136", "cb55cfbc85b8db6", "1", .Okay}, + {.Log, "81d7846fdac3622ff78a5901fd1325", "d8918b77e0db47d", "1", .Okay}, + {.Log, "382d28fa74b6b86b24bdfccc551ce9", "2cba17e4b282f07", "2", .Okay}, + {.Log, "d4fc4fcf0994eae4b37fcdb3ef1612", "159a0919c9f3125", "2", .Okay}, + {.Log, "76f1d2c0fef9f815c41d60281e41de", "34932e42d095d77", "2", .Okay}, + {.Log, "d98ddacb7c4670c8df23d5944c4210", "d58ae09d3bd28e0", "2", .Okay}, + {.Log, "e07aa0eb95ff9d40f6295dde22416f", "d4f02a19e4ab493", "2", .Okay}, + {.Log, "b6d401a28cd04cd0c3072c9e8a8062", "8d7a4797da4e62c", "2", .Okay}, + {.Log, "8b2ce11d18e7ad9e07379e77f7f7a2", "1331d5635b2a6c0", "2", .Okay}, + {.Log, "9db731db5f3eb843195e29b1eb0b9", "2afc0341ce706c9", "2", .Okay}, + {.Log, "9bc7e1d8b9fd1ac549622f3aea83d", "b958e35adb913cd", "1", .Okay}, + {.Log, "cc631f2ff49b7eb1551db34d3fe220", "59080edbdefa980", "2", .Okay}, + {.Log, "283beeff4967a48f660a705d439fbd", "fb84b09fc46f22b", "1", .Okay}, + {.Log, "6aaf60954b6954cda37e1a4dc51adc", "787aa7527a54318", "2", .Okay}, + {.Log, "a69363adb74e9bf563aa95a45cea8f", "cbcf8d13ee65de1", "2", .Okay}, + {.Log, "ae62e1abc4e2b240609629e4a07d6", "7ecf16aceeb05fb", "1", .Okay}, + {.Log, "2723f000c76a7e0e5ec48cb659c6e9", "8dcc8f357fda2d8", "1", .Okay}, + {.Log, "f7e08f5a6953b02d24284a095aa41a", "48136a8d43d6ce1", "2", .Okay}, + {.Log, "c4e84985a8760f0f05f9c1e545ee84", "a671517d0ab9b06", "2", .Okay}, + {.Log, "e44c310f21c64ccfd0e4947ac424e8", "3a0fda19a01b1c7", "2", .Okay}, + {.Log, "a4000d8c479dc711e42a9ad787c4a2", "a3e45f7e1313448", "2", .Okay}, + {.Log, "88649c423067075b80dfedcab0adde", "1e69f0805ea2d2b", "2", .Okay}, + {.Log, "8505a1894ec708760ca925a828ba08", "9ae06a649ace934", "2", .Okay}, + {.Log, "8d3da583c668f8051c4a0dfd5ac64f", "56b60518bb6c3d9", "2", .Okay}, + {.Log, "375d588dacb3bd40acf7587c242502", "2d5ec2dd689f7ed", "2", .Okay}, + {.Log, "ca551431cc9663bb612c021f871b31", "bc31b240c621910", "2", .Okay}, + {.Log, "c2829899802afb2175401a8cd3a078", "93e88f300394765", "2", .Okay}, + {.Log, "7f907583581e65e9131b2a768341a6", "ae0d56342ba5ccb", "2", .Okay}, + {.Log, "c2c0b37b18c50edd66df6704867680", "24d7b5fbb8142d7", "2", .Okay}, + {.Log, "c677811ea6e0510c09cc3a207047a1", "c6a05c4d2008298", "2", .Okay}, + {.Log, "42c153a9186ba30130352630fe5e6c", "c9bf2854f84a9c3", "1", .Okay}, + {.Log, "89d130dd62d1dcdcd694e7fedac889", "268987cb09a0178", "2", .Okay}, + {.Log, "5c3e19434906d7e9265e4e8e0dc076", "f4a47a8bb587427", "1", .Okay}, + {.Log, "6d589034f29ceacd34c882059c831a", "4dace7536bf85ac", "2", .Okay}, + {.Log, "a8f42481d65b630b4e7bf84135214e", "a956fa60dc3aba", "2", .Okay}, + {.Log, "13ca01b34888158c2079ba0773d6c2", "df75ef7ad973a4", "2", .Okay}, + {.Log, "36b7ecb6d77cc9feb04bc0116bc370", "a55054e0601fd2e", "1", .Okay}, + {.Log, "51116a1f2d38e53dba54d3cc644af4", "e80318d395fab8c", "1", .Okay}, + {.Log, "b7312884cc700d1727619f190c2597", "fca8dd0a164204d", "1", .Okay}, + {.Log, "afd7b290db7ac38915685748e57609", "30df6155be32c78", "2", .Okay}, + {.Log, "dc69dd6a13f293817e85f9829a119d", "e8fbc13c6c0ecdc", "2", .Okay}, + {.Log, "4cd2168cb3bc339f38f8a4c0165234", "e7249f33de7121d", "1", .Okay}, + {.Log, "7dd63a7ff8368e635967f2f7ce00d0", "ea109319e6b5182", "1", .Okay}, + {.Log, "667dc16f839662472a1b2749eb440f", "5eeb67b4f768c89", "2", .Okay}, + {.Log, "65768d1c8bc8b5479e24aa2049e5ca", "edb52b127f93d1c", "1", .Okay}, + {.Log, "c7da20787846d0c3e12291fdddd7ff", "ea4eb1d8fa7e2cd", "1", .Okay}, + {.Log, "962b35feb594e6d0f50fc0631fbf38", "1b3543ab4c1789c", "2", .Okay}, + {.Log, "f1ef187e4609625f5c816fc335c132", "d78d7e8ec9b3a40", "2", .Okay}, + {.Log, "262e29cedde5e8e019063f7a6c57ef", "2f9bd7d9efe3611", "2", .Okay}, + {.Log, "88f381f2930f09c0d1ea262e3f8a04", "7f0adfa6eaa9ce4", "2", .Okay}, + {.Log, "fb6fb7370c668155598f2b2014dab", "35d39a1a9703767", "2", .Okay}, + {.Log, "5548cf40e313e36b97878e41fce9a1", "61732722b0f7cfd", "2", .Okay}, + {.Log, "415873e9b7622498cae35e11a07af", "fa76e055cc27872", "1", .Okay}, + {.Log, "773fdf08655056ce8cee24dffce307", "cf20cc36db9a469", "1", .Okay}, + {.Log, "33b952cff6b34348f344ffc074d9a0", "2857995ef0c4a60", "2", .Okay}, + {.Log, "61cad3b75752ed8a24d035f5688121", "3ccc4b3cbbcfb0", "2", .Okay}, + {.Log, "931a6cad328afca6f94881d700176f", "2b0afe2d2063f3", "2", .Okay}, + {.Log, "d7f39d01508fb6a7a0442af85f5d60", "9bbeec8551179ff", "2", .Okay}, + {.Log, "a7f89ee314afe38340e6d226aab5e0", "5fb10ca56f08a34", "2", .Okay}, + {.Log, "5d23fb88d58d7563523213dd3ab40f", "e8da5bfaf6c4179", "1", .Okay}, + {.Log, "430958e14a8b4b14ad4b4671bba0ab", "424a7f78d4d532", "2", .Okay}, + {.Log, "d84aa2bc4c9daddf9b7d5a9f801ac0", "7ce17503c85ab18", "2", .Okay}, + {.Log, "cc8fd14f948daabedf3354ad74e992", "ecc3e1db35d207d", "1", .Okay}, + {.Log, "c6d669ba28c06962b6df98ff4a23c0", "1915ef1bff87ea1", "2", .Okay}, + {.Log, "4b925f549d8a5e8f035441423f3057", "a1dd44bc0019787", "1", .Okay}, + {.Log, "20f5abbeccbac2cc2d2d6af8920b04", "efffb00f033f760", "1", .Okay}, + {.Log, "f2ad9665e51666c07c0370ee08a994", "4d8fb606233d34d", "2", .Okay}, + {.Log, "fc1679174e11bf9da2f51602465785", "25ab2a6e7fc6871", "2", .Okay}, + {.Log, "b169ce1f73c21c9953d2aa7eafb97", "918e4351aa87298", "1", .Okay}, + {.Log, "fc85619aece0b0444418992a09bb72", "913cd6c05ee588a", "2", .Okay}, + {.Log, "e6512b5c8d420b7fc6caf40af46d0b", "7048e4bec5550e5", "2", .Okay}, + {.Log, "f370bdbb7d96201924d5ccdf9de34d", "35c2260d0559ee3", "2", .Okay}, + {.Log, "301b8db1b7cf196e74bcb16021b2a5", "d7a68e9a0550d36", "1", .Okay}, + {.Pow, "2206d8f0b603917a901508864ee863", "1", "2206d8f0b603917a901508864ee863", .Okay}, + {.Pow, "-2c3bf60e93e9d4468a23539d58c617", "a", "65e49a5ebdbd374353556071d156a6ccff7c69a47d326c558b233cc991296f220ed6ff668917096e3cf03b71015f35aa60954b7ff6e499e61318f996a6256da4e60438a37c81d4a60408cd7ca914fb10ec0a027400d57eb9809d61daa8c9668ac85e6ad751183bd201ecc3988d00f409967eb3a4bcfcf76cb1863084e8dc67d19cb9f8a6b47bf4a20fae51d1628e7470831851", .Okay}, + {.Pow, "-9010aac0d5e163bf2fe4b8a007ccb2", "8", "293386a5eba6b3f9fcbbc0e98719e5975ba29039ad1eaf7ca8ab6fef603135f457c02706d316b20c66ac0d2ffc69ad623cb635062cad7cb4e244a562c1f2cbbf16cbf90eb246a6973b176053467967138b11af8b18eef9d563f052147684fff3501c61de4790786657ce640fd9b57272f5b6df9bab1c100", .Okay}, + {.Pow, "-376b2a21b6cb1302ab29c93923e39a", "3", "-298dae345418fdec0ef6d448afa4b4b830738b69c55edb37230b19bdc889c21f7a50cfe362afa1fa2faa9fea8", .Okay}, + {.Pow, "-58fff78e9dc0d43decf4a4a562796e", "a", "1b0ba1e90052b14ae4a16498fd08f086e9b4133c00e75aef862524eec4f8add7fc66fa9dcd062f17473056f8a96a882dea48f78671a74efc6e87beb17a920e9639ab1e5efb101d0431039b42b8210ac963298edca91a1969309799cf6b58e8bfc55ce31259504dd826d956671bcfb87551c06308d5b91acc57a851b7741820fd45f39e6f6c9d85e7eead130848a68fe55d2c04400", .Okay}, + {.Pow, "dd9b4a1aa8530eddaa6b685cbd64e3", "7", "5d3f7607988628638f4ed0e4e437c28a0dfaf3d6ba1da0cf78f3c84826bcb22a820149ad8d1aa6bc0124e3794fd1ded9c74c265b40d9ea42e748b40afdec88584eb996326ba7b067d37263ab916b8a62a7857c276ee8d94aa5e603219233342bd6885d0648f47c51ab", .Okay}, + {.Pow, "1236df56639b3dc67290c8d2a554e6", "6", "22d3008e8477eae31d0790fe7471b54932dd52b9c9fadb39d82f737ff9c0696ff50614ad025cb8ecd4bdf78fefd52528c9159422ea68af619e79c43d64d0f286a505ebd73a77d23ce3a94d1a25c386730167a394570ee40", .Okay}, + {.Pow, "8f8b001c39bf3be1d04947e2432c85", "6", "7f4b8c8699c34fec566020aa7c2d47a6fdd6ee21d7bfcb20a876056efc55155bbd8fc0202c3a7965027d2b7357abe7157b78ddcc73beb06a7f60c903c73e65f3b28e5fcb3af4006b4699625be23b0f1f10a0047ca321c614409", .Okay}, + {.Pow, "-46845f7ca064ad057fcf7732d01099", "4", "1794f2818483683547a1cffcd3ebcf49e7bae2c575870ad35583d90414b5689d1ceb7b2ce424be6f84d3b2506ce7c29590c9329ccb02b42b58bc7e1", .Okay}, + {.Pow, "f8647d9e3b234f2e5f56a1551b1288", "7", "cf44573b281256247f9d7dfc3c04dd47e9937f3a807d1e8ad1e02b478c774b369e7cd00dbe7562f3ae8005916f98c1ceed447f3bb71162c95176fa6b8426df15ff9bc2eb578f3c15af21d1e82f80b1ff44fe8fd466b1c44b52d23e66b938a6186fdbeecd4da6200000", .Okay}, + {.Pow, "-f611795a362c75b728447f9fa93d41", "3", "-e358838806a59a0582c1948476e64e7f1d08456dbc36eb2a9290594ab0158ea60749c544c7a3c08050eda667c1", .Okay}, + {.Pow, "6f6024aee0cd108386cf7d48da671c", "8", "541dbc3ebefc44b68c2566da7f213e20e0ca76fd89cd838b36f10fcc825fabf429390f7cdf29b1d426cecb57e061bb0b6b32d8abac4f1c1bb0e6f2f7d1cb2901f37d87175e78211e25b769e884b3779168c0165d8d7bbfbf109004ed127ebe1cca88c793e086587e0056f847e644dabe7f348c78c10000", .Okay}, + {.Pow, "-d0146255ec11de294f912267578be8", "4", "6fbcc26915f227d7407a7eff28f14cff25cb8d8594f61b2d562e082dd04e6b112d9e46bed7c5428c7a388a112136516fbfc03144f06d126bb9e51000", .Okay}, + {.Pow, "-f3130333e8f3e7a136c9df0812a99", "7", "-b220dd46ba721200e8e5e4e0ed3cfdf46720cc972857739d240f14fbde3dff1623c35acf5258919ba45bf04c0ccc8c9e83db5763cb980906a5bc6e4709a7b252fea4472e997baa75b3adf6f81ae1ae3f0a3b7b60fbcce8eadfd0db6d2405428d92897d1a369", .Okay}, + {.Pow, "-ae837330860700867afc3cb6abc00a", "3", "-5118efccb24ee7f4f829ab443a9970f2c2fd71991cae3b276b9a54bf009f626678cef829370e1389f3f14503e8", .Okay}, + {.Pow, "-62141e1e58e9836ebe5bac82acb876", "1", "-62141e1e58e9836ebe5bac82acb876", .Okay}, + {.Pow, "-77a7487373ca48384538cc78f75f69", "6", "2ab44c423fb02feeabef6db77734746c2009edc12f2f1028fad2d2cef5a7e4ddc82a52771aeb4ac9b4dbe21f6b7a38dfdaff24edb8f93bd536451c3532a2406a44a4506baff81f065b7e33f7472f29c0d6de8ca5f0d6c3ebe31", .Okay}, + {.Pow, "e5c8ec0a5137d13d79acb62de3842c", "8", "6bde2151a0cdce92d900015fa999ee54bdee4706d825a7ce2c809da506071d7eb850a6c0229b4bc240a703af9896045675c553673c1569e3824ab94e99447aa5d8a689a4c338c79ea39b2a7274463d85720a42bab71e6020ea61cdfd49e29ec0b44d98b555394d8dae15c4e48dc038744a0744a5f3610000", .Okay}, + {.Pow, "db0af5a085a0081dcf915a606b6374", "9", "3eed787efa26e3206e2e5d36d0b09577e77b5b906587d312418308ae9cad6ec1d966be667b395394b9634295a66131ccff9cf7a37d709082c526d66b64d9bb1562b4282d1464c240d70a31bf8d844a804e5a30e2b542d2ad4eb0bbe7527b753475c6c8b78b28132f1a19634c2437d7cfc46eb20ea377093fd883615f89a85d1d8d9e63bbf40000", .Okay}, + {.Pow, "-e4bb27ca5fc85817db7691d7ccb133", "3", "-b6990ab819c30774f9a2eb9e8fa11786a25d8e41a9e96efa6f79cb8d2159263db289b066e6950ea36d3912112b", .Okay}, + {.Pow, "be711e83e60b31038b3772e6f7fdd5", "3", "6964561a72ec69c3e9e83310aa4e12f90c773c193525f48df184c95f64357484c02b01cc1cf6c4b39e7577736d", .Okay}, + {.Pow, "-111e68b34d1b751c9afdf34dbb63fd", "6", "18005fecb2070ecf54e2e9bf32d548a8582d14e2d768d01d2d97a8512b0cad257edaedca81a37ef53a4edd241866eee264890a88ae4136a86453e70c9182416113f1beb43ccb87437b0fbc914678c80dd6249e897b07ad9", .Okay}, + {.Pow, "-695f82a5b2ffd43d03768ef61c0db1", "1", "-695f82a5b2ffd43d03768ef61c0db1", .Okay}, + {.Pow, "a05ee20c182fc37a3bdca4725ee04a", "8", "61262f65d164f16243dba86b94cc02ee59bb142962d8163d9f30f04e1ab9148d0bbc945ab3a64f914bf4954ef9f32b84ec6c1c927b64e0ddd1c14c45151fbbfc1c14ac7a345e37207d93c7952208f10e96b0c29f869f2f3c91ae0e01fcaace2de3a768f13948f22013d908fe130fe7247e61294dc92e100", .Okay}, + {.Pow, "89c65434b7cf7530bbb2611e6f9d9f", "3", "27e7b670283365609dc9138e84fff7215632abbc05913761bf1c25bb3cdc852693367b6eba6310579900006cdf", .Okay}, + {.Pow, "-6e1f3a892459a3cb311c56099898b5", "2", "2f5eda1d15d64468d4bcf5fceeab1fa9e2f94eb2ee1b5794474e6c076ff9", .Okay}, + {.Pow, "72a91be7bfc9c471e4e6ce8be767aa", "8", "6a237b1fcaa911ff5e8b43cd9ec5314a78deb453f047a1355a0d359480a16ee154e4fadc96627dc35751def8aac81f4c12f9c784f0565a8f8d28c8059ca08d4d8532ed2d9031045249718d74bb7d4bbb6cc7f13260108034952fafa284816ffd313dbc710f90c5719573823e12def7b73f614ec9ae6100", .Okay}, + {.Pow, "-393af93ec422b97f10a8b98c9c28a1", "6", "82e4d373338245ae81ba782992e815aa7e620c4dfe955a58c3be12ae619dc6329e1d236a457631ee36dfd1b6a1234e2ec6b0fa09f98b2e9bf28ec2ccac0454dbc76ae56d31fbad900677dcac6f452d0ad5d6ea50d9daecfc1", .Okay}, + {.Pow, "-71b4617c57af5fc9cfec9d90353a32", "a", "139509f0699fc2d86574dac9b466029791fe81a1f1c4882ecfb6cf4ed0dd6cebf8e1f0ee8b4df51a265648a287059a1147536e78623eaefbc81d40b23728c40e9d73ec128125aed0428b59ad2367a720ca5aed2bc90a80479251b2f8699de3ce497aa5768cc9b6f692146128b909b455e9747793e7f2b876feda234a5f8d79995deed328e8b2a9061abe571b724856033002a0c400", .Okay}, + {.Pow, "ee09d9c15973bca3fe7a31841443ba", "a", "7baefdc80ccc1d14d32d2ace03209b691546e4514c270e9ed6646a4be497342ba5ed4bb19a84d0fa70bbe1825dad309b400155d859747e30d44d4ec514e89c05f9a51dfa9b925dd59117574d7a7e31d041627ac6a109471e37a1f1f3666d46a220b6338793c8057d63b802295a965a3433cfc5da00ecb36b8a3274598050c278f2327a3cecb4650fe31e6eea59bd2cfddca2d8e9a400", .Okay}, + {.Pow, "-ec176c07681a36886be6f9077a3b78", "2", "d9bb31523edb494e4d3ca4254874f4f3594859a801ac652b390d4c308840", .Okay}, + {.Pow, "ffae3c1232dddfd78853db0e3c7586", "3", "ff0b0286f8915a41195006180fa77e1ba8dd5850334cea38393ff9cd236b18137ce07dbf68b13e6d870ea212d8", .Okay}, + {.Pow, "59efddfa5fefc15055cca67c357bb9", "3", "b19adb502a6353522466c7f920f6ea07c22cd798aae0372d9c3c615548282b8b1917873daf7a5874c1a36bde9", .Okay}, + {.Pow, "-69d68656c4c7c4b72bf7f9966f0415", "a", "98f932466803d334bec8bd08ab61c1a109cb2d5401fe40c6206bed871556ca1a13b4c977c146f8f70c879c972ff56c6840ac59833936d022f000fe7c32d0fc5558de4e57a9d8c121fb9a1e5200f500478eb4e1c174839b8f5937ff5d2dd21a5c7ebb7709d84783539632d9ec01ffd69d9870d1d18deccffbd32aa37187c55340ec4cb73f6c61ddbab8bfcfab96c0911c0eefdb719", .Okay}, + {.Pow, "33dd262c3d0d6d7e8e7e8da9600247", "9", "9a55b893daaf57d89651c26fe00bc0bc6301977523c5be78a48c86b9f26e2688e8ad9227da10633032e4f2e7c7e600065df0f3eb4e5fe982c99e797aa6a8a719c3044f7eed08c301aa9826cc585981c10b0fab27ab0b6b53919aadd5952b317e306b7326b612c2418434d3facfc969ba0d6d2e8a7535600aae17979bc7d36f1b6bbb44387", .Okay}, + {.Pow, "2e13bd778ab3cd0281b96a72362811", "9", "35377430096f6272ca59e68bac3fa972f1d3133cdf5d09b9a2d83bc3c41e09070f877acb5e2eb38cccaeff6aa451d3972584056dd67df9584858d8dc44874a322ae8df94e6ce9b2783fe1b3da7a2aa7ba52ffa20a9e984d11855ab1643985474068631de4292eae426ef339725a73f6aa02517787d8dc5d8af35fbf05d816eecd105ecc91", .Okay}, + {.Pow, "6efaafe68d89121f60e367f2c1d81c", "4", "90aa8e47b3760573607f2ab1fd7098ae39116f1afee38e45c449ee1816cec5f2958aa14f706d7f6a0c454e7edf3d05d3ce06b9940d8c4d890716100", .Okay}, + {.Pow, "a5bab2f361900861a99f5711972f9c", "9", "51cec037dda04d236c67a7382c0d283c9b2f9ed2947faf7e59c549f8e054da5010494c87324be0dec5d98fc28bc5d28c2953e48577047502da5fc0f4778a71c6fa4c1462edfda2f8a6cd3eb3def8ee97c568ec241410d83c5cd840f330ed851ae764597cf14af9c2ca59409e062efbdadd588e64c19217578d4da6d024235b9daa771089c0000", .Okay}, + {.Pow, "df43ef5af5547b7297ce47cfa8dabc", "4", "941a84ac9f13831f1673b8830a195a1201c38852e643d6a123f83cfd42b0b3a03593aaf031fd3e630bc3206646d37a0b829afac84e8135ce0bbb4100", .Okay}, + {.Pow, "-a571054669f962822c9da7a21f3a9b", "4", "2ca75b3ef918c4ba5046994f5f381e3ff96b51d68e8a176cae4d9e94954df096fc470ae87fe04afa13e9028503ab81ac5a91f52b20ee08f7561d19f1", .Okay}, + {.Pow, "ae4af940538070083cdaa6587a0e3c", "3", "50ca4d35ab2412f8e918eb3c3f33a7df5683b1af7d464bf19015131b3907f6db72e342d25dfefab929bf01ebc0", .Okay}, + {.Pow, "8ad17a592b8bb615b455c1890024eb", "7", "3877f30b83eae82ccdbb328c54822e9259378cf6727b585ae2b8d19f2057158d71623e8d55c4b5d8cdc7eed7d77aaadc0024e303310087ef0596a90d9996e8ff22bc30f7b4ccf9da8f856705ec69b73c9410c01b479dd3d4b94fa897820189256e21c49aec39d4ce3", .Okay}, + {.Pow, "-702a4bc625ac4a43c1cffdcaf51550", "9", "-26ff8760d6d71efe131a5f9ee7f82b7fc37d83287b3aec2bd351d07b4e2515644f771388e99ce3d17109d951d92e21544f7cdbdc7cedc3c2d7483ad698aca7dd82371481850879b275a429e3bbbd4b44ab5dcf44485bfaf3c7eca910acfe13fed7ab29ce8f87cff62b24110283ccce7bc365428e32968319e2f2b674f673b4d0335000000000", .Okay}, + {.Pow, "-59b0c77fdc41adcbeca5bf17907129", "6", "793472bec69061f3e138a719163d0a7179b15899c49bbe361768a818ed94a25f374b65b3c4cfe41cefb6b79c5bfdbb1ed950913e55a17ad480a7ec34ef9b06e02a6c82750accaec78675a7a10b864576ad61e4ad330d232cb1", .Okay}, + {.Pow, "-3d81665d47265ee471d69b7404eadb", "2", "ec6ec30c6d87493d9c04b72b535acaa83601c9cefdf5884fe20a64d1759", .Okay}, + {.Pow, "dc618027bf202c606ecc3a469320c8", "7", "59b266dc2017359869734db0a391184ca82069ae6c5fe84b6ba4cd348cd41dba2f8fde61f65638810488a050a3d50e3168bbe1ea53d2cf3e7221fc3a2435a7038c99e94aeee6dc1d2cadf58268e7c5ce0dfb1deadaf58addf485cc7dfa2d93f83ae9213df7bd200000", .Okay}, + {.Pow, "ab4bcf3f3aca33a12c63c8569a9f37", "2", "729e5d518f5de4248e419e52d948d6d9d5122c7b0d16eef1904ce5315dd1", .Okay}, + {.Pow, "-6d653d754112620b638d39d9e5c4bf", "1", "-6d653d754112620b638d39d9e5c4bf", .Okay}, + {.Pow, "-5d249eb9b0b3db88c4e45823d6151b", "9", "-7529fbf1092e45050d758571b1fbb11dd8ad9df727f927bb3553cab02fe30d76558721116112edcf1ed0e8b48be8a9ea412d8e9f4275c0f2385b1ca2e0e6b958964260d629ab1bb6b456c46d67b5cc0d4db4bd40c0d47943d4d6e9a0011ef7ea9970c7dc93a7aed9554b51076de5cc936b521a5f17dc2e65332702e0a9b23b3631bce179cbb", .Okay}, + {.Pow, "727859eb61909bfbb5163978b8b4dc", "9", "2ed52e5e5f4883f6544c8981e3147fdbea8ceb4ef96c4f47b19da1793aae499b9f0556684294f967ee8b20c6ddbb4b026bcb079db8127a63fe52dae53542aded342f50337c105f724b1c1919670333ae3e7de5d6628b1e5384c88ddea785bf8629895246fb6bcc475235be00e4feade974309acacdb8336d91d426f141cfe3d9acd957dc0000", .Okay}, + {.Pow, "17525ca439abdbca41673ca4de3a12", "7", "dfab26990b2262c724d33f3b849129df268cb9486912ed76237888e52bfad0e565aec44dfeab9b24dd7342d619349b5ddc399c5d1d468641f81526903f37a0f56a81c3fd35d2962546064ad09a555d7092242374cbaff399506ad40eb3f37c47ed08778b3c80", .Okay}, + {.Pow, "4e7bf97137853808c794051bb09458", "3", "76075fa58bd3590a0def8b99a3b3a86e4cdb6e66076d59c9be1507401fed64c0495c1c167bced15fc55016600", .Okay}, + {.Pow, "-7892bc6a187948e73c48bddb12a2ec", "6", "2cb649162559056c315b233092e749dbfb45e83bd59fe2bb9428308575c68cf282eae353d4a11c15a0367ae6a436c902a3f619dc0e4aee169f5daf52356eb3febd91489d6aac92422089201d54836f8390860215d76e0e89000", .Okay}, + {.Pow, "-f4a25a887646314f0c1ad399194d0c", "8", "b203f0087b28bb6ce79fbf5e440632afe549c6d7df354b8f6d7b3c240527154284badb422a8554e944d0ad9003438cc556eb7db957c19467631d4b482cdef7e4a6b1c18b2c580495d694bd8e2ee411a4011831de5dc27d04d8af4096679921f143390438c30f17d03db874175a1d3c88686cf57b77a10000", .Okay}, + {.Pow, "-af2c93264c3887dc4e6e152f32b0d3", "3", "-52059c3a1ce005846b5ef28e72bbd4fa4b5d8d75d4d7888b55b770ea041ba705b56e378b7242dcf82593c5e70b", .Okay}, + {.Pow, "1c9e31b496e9ad5b091e89f1b57faa", "8", "68bf9dab778450aa17c7512e93a194c9aa450e5ac8e2a7e92b486fb8657b5118a53730e88dd07a52f2f33b001386b5227aa55914db7130d820ae94a7a161d7169d2c5eba88fa5bbae06eb2f1a7e2f886f3fd22e5f4190da8f5bd1df355844ff3dd73e1a690e1dbdbc725efc401605a481ec48e6100", .Okay}, + {.Pow, "14f4267ddda71579c73a53a254ea", "5", "3da278a0f4dacf09d0bee2cff8d21c60e4980aa747e85a7fe5cc997bc9892ab76efb4956c05d2fdc33615c0d2dadc2ae8ed26dd7164fa38cbf8ecbad6fec61ed5b06eca0", .Okay}, + {.Pow, "1a26f1a2c23166df604cddeb652ff7", "1", "1a26f1a2c23166df604cddeb652ff7", .Okay}, + {.Pow, "fbcd1127908cfa432f2d658b7e5ba6", "6", "e7d12853c1e5ee98e3ee6f92c06a2afcfd436ad0039ecc3463cd806b4256119e46c100552bf2ee755f49563e7c1dc0b3377b8b8995184031f4df143febcd5c75b8678b803694f6bd9dba9f3eb6d703d74e78413ba58b66a91e40", .Okay}, + {.Pow, "98d9786272c2e66a717338decfec3a", "3", "367d49c043d9278d24abc2399490595f354f0636cc380eb903f3e17161cac297ab33894d593325e91a7c8e8a28", .Okay}, + {.Pow, "df918e587ba95c01fe95ab17291241", "1", "df918e587ba95c01fe95ab17291241", .Okay}, + {.Pow, "-410f52a08ab5d4a7745672f4dbe9c6", "1", "-410f52a08ab5d4a7745672f4dbe9c6", .Okay}, + {.Pow, "-fcf2eff9d40fda99c7c971a43fca7d", "a", "e3133a93e8fe1b893b5fdb35c14199889402872dfc7afa07e17c962c3d1028bb2e18f4d0c70207f440494effe828627372e04dc69316dd6e012f4aff4affee2de91b5f54b85a4e4e532fbe24f98c79ce20e51ec3fd4900eeccfece3ba27ed8b4bd4a856e9f6b97aa56791f25fce0ffb1a24524d6463b77abcb3b27e2daa3c6bc064f885d8da5044ada18420c5d166a2305c23b588ba9", .Okay}, + {.Pow, "9cd608e91590eb2b705ce0db353aca", "4", "24102c2bccb86e8084a211f6d56c8156cf9331658a227634c47db948ab01778d6fd59ee002170cb550deb5cb3f326923f34ae33ecb5c05e1e22f9f10", .Okay}, + {.Pow, "a8d0f16543e8abf6268dc6e44da213", "1", "a8d0f16543e8abf6268dc6e44da213", .Okay}, + {.Pow, "caf4f59c21d7ea2dc8dcebf04fa87a", "8", "27f3fd83c46a7c6f4b40b8e30c79dc8e9699332c1bd4e3a7bcacc749211ca3ad3b376a2a27b892cd5bf7f39fe03c1d7a865cb850f248ed0db859006251bfb7589f47f8a1c01e265e40a59a3bfa18fb43ffafd3fe201b603d63c0936610ca173cf7520240e52ce9fa62f4d3f4f83ea5bf88a5ae71e1e3a100", .Okay}, + {.Pow, "e19dfce60912bf65fcb94ac99ee7d7", "a", "485ed5255bebf6fc9d3d4cf8639d2d5377889590ae6a0806389b0fe095d5aca848e65237a308dd1e0c1afc210fa2c8106528f729a7b30467fac10b8004b848065040389f5a0c7c5aa8af976dc992f8acbf6b1b7011b0a5946c22f877ca8783397cf025a8b0be9dbc755d94120c46cfb9afb9cfbe8664e5ec95832cb6aee17c2d4e057872d543f731b2557de328a9e644b55148fbdad1", .Okay}, + {.Pow, "-b031e070844b907d1f5641a7275a67", "a", "61b30c54ebe9086ec96eee44154c9a5aa78ca8ca1842f7b35f0e3361a1dfdad4712c44d539e6451a976894a54b19cbe08ffaa8f0a29110e906dad939b8be7e64aef4cd99c0b422439424a37d443085861d25e3cd0718f95bc4bff91e02d495fbf4a85ff38753684ca944f9dea95fae5c9e140a24be095a4bb022aadd58f9fd776edcb55487a8cc4fde18a2628826a1423c6d3fdf531", .Okay}, + {.Pow, "3025d0ff86d0226b6d0aeef44347af", "7", "8ba8cfea60977a0cdddbda28bec3e924e114954a7722703a52ef1f1460a15ac6d344cc688a670eff60aeaea3f443718dae55254195189e87382a9059abc5bbaf73bfd5d443160caf56d29c9ab539d0cfcab08cd5b2b644eb128c11a932a063299dd99ff3d978cf", .Okay}, + {.Pow, "-d815dca658f229e7decd656b5724b", "2", "b664e636a7919369d9016a6069c4c370200084af85d0b1c6c93514e1f9", .Okay}, + {.Pow, "5583d2c3589576955bada9fb8c0578", "7", "1e6a5996c4f78c0e00d2e9cb89339920b3c520ab1dc28d9b9a2f9c2bd7f142d01e69933ff7265377288932ffadfa87f0c0b08662ff9306acab1cb949dbf09c8a65ac714f43738bc7b9a10689ea19a276a59c7cb33a8da6429e85758acab77087ab51cba4f9e00000", .Okay}, + {.Pow, "b876d85d6fd6e1a31c09c19a541962", "a", "9a8dff059172840f790246aa72061cc24ccf7f8c855453f4d4e7bf2a7f38e827076c32b112dc58cea48a2e4be00cdc5914993a5aa8261ee68103eecd1a8ffca53d4910a99dd49b5fbf8607cd5113c4e0c89c8606b2bfad1051439ca4cc3c839ac55f6d20c6efb48d6f2f9d7d87101cb830b9e76d023404f3b7ac77a56a6d3ad345aeaecf14a98950dc37eb399f671069a1c030f8400", .Okay}, + {.Pow, "-be578c7b3bc1024abd58f4b7b0934d", "6", "2b408d5ace1c333aefef31da14dbcc907c66c9d78a87ec3f1a3cc23ccf147aad828b9b8887153a653eff194132377a00f4cf29fa40c3086e7f4e8c4fc616253b0c1c34f4bcd69dedf1c09dfdc077370862355c176b56c7d30c39", .Okay}, + {.Pow, "5dbbf26d0e02a47165181718f501f9", "1", "5dbbf26d0e02a47165181718f501f9", .Okay}, + {.Pow, "-7735c196a06f2dc15f6ae8429c535f", "6", "29c36ee3913299c47bff1bf4793e49478be4bd81be857d558f0cf498ed9bbce6fa9e921a9cc275f7c39183fa52b40d430dea4df5abf9941d783bb30edc7eab6d2eca005687bbb619b6ff7ce1e6ec35a038cef9b0100f4b6e7c1", .Okay}, + {.Pow, "-8954f7a7eed3c106dabcdadbf837e5", "4", "153393334cfefca36abb5870b8df47d1fdf673b66389ba57220afeb4a5d3baeadaa56a0346e7b254df723dcd510ac4b36df0afa76ad7892156a17bf1", .Okay}, + {.Pow, "9b6a02e23c60f65ef176cde6f88e9d", "1", "9b6a02e23c60f65ef176cde6f88e9d", .Okay}, + {.Pow, "c5a882ac2a84add1595dfe06bc9ca5", "2", "989cc808be1b50a04031f233baa8726b5ae7febd12e2bcfe1bba2e318259", .Okay}, + {.Pow, "-32b5f8157905fea81641b5d08b9c9d", "1", "-32b5f8157905fea81641b5d08b9c9d", .Okay}, + {.Pow, "6d3f0cd7a5c65b68238865f2822223", "3", "13e5135aba88d5f1932619f6d4d1081de97823c39a12162e8804b7b0aee13e89128f816f25396b5c897c42bd7b", .Okay}, + {.Pow, "-4c18c3954aa272dc798a1238283e20", "2", "169eb685e5bb396be358abff9dbdf0bb1aa53d2dbb290f34de0179138400", .Okay}, + {.Pow, "-e347a70c585cdf7e48623ca3cd1239", "7", "-6f4c490497c80459cc4ba3e0ea7205eabd78e948b79818275cab00f5c311f638a063f6b65f942be54f47d56f27c7d663ee86777a4c0cdebee2c0e44cdc078660434e16b792a38acfd4def7535ef7cb2c80d1f2724b15e8d3fca1bda1feda41358ef5c14c029ebddac9", .Okay}, + {.Pow, "-cee64ed1f76e89cb3e76b29e1ede2d", "7", "-39a9161c6e6f9e7e3e45b365e3bfdba363e852bf21745e53e0be358ba0cc54f86cee0cfe1f882e983e6de66a4e7bf94bf98ecb316b45c2a6f661f1f8bde1b7eeb3376e8c97674cf9fa37915bc435310e443d3403086209a0eba3b3462e0497f1a30c5ae3f5b563df45", .Okay}, + {.Pow, "fda45f76db952b29c14fdcc0c2951b", "3", "f8fdbf318a7b22b5cd2f359de829db9266da323900989b7d39fadb37372d549b9c96c9f50787e0f545efd833e3", .Okay}, + {.Pow, "69e5bd72f3d269a2de3d246f4775ef", "7", "87d4a7b2beae31a2eb011505cce2f2b9e5b0b04584e6cdb1f77b765d4a925a69726ef9d663b34435ffd018702979e2394f142e516dd46e0f93378f07a0e5f75add218248fbef8cf8eec63c773a9d096e1cd00cade16528d9d5e08f46d67a672309816b8a6186b48f", .Okay}, + {.Pow, "-4e65e48942655032232741971297c8", "9", "-18d78b360935e7022e40e166748805faf6f054c750d38bf505712aba5e2e1fe686397548136937fa777a871da01744fee6d7585fd9287789d9c65c46435ecb0d6c5f386a03478dc8158ff9938add2736a7abe567e168281a9cdca9900fc28f8a23d0f7713ef1eac672a00c064aae2e2f064902d89edffc25c05015af073b0679b5dc8000000", .Okay}, + {.Pow, "7d7bddc5f64ad3514bc53cc2b48904", "5", "73e77c9ed8ec567caeeee003cb1d6d010f9df73bf7868e885eae5dc369af29ad69c74f8014b530a4c81cf78646e6b500da23be1b890c5d8258ec1325194db7448320777a774f4712d0400", .Okay}, + {.Pow, "-4af665b61c5943771348bcdcca165d", "a", "4dc2be4dc8ea54dadb8c528f01cc541bcd6719e623176193a7266d5920c33bdcf4ed0c407df6c1f0489b97dbe37675db07b8a4da978f7e38ec490b5d9997a2eace307590b3931fb49a4306bb26d4f40cf7c2b15ad5c1f420369d08943ab8ab6ad78eb568f9d3fb85762fae5a278a0227045019e608b5dbbfdeccea4f0962fbeac97803bb5c7fb47fbc0b9edb1545aaa1f79ed369", .Okay}, + {.Pow, "-399544502d77cca458b6a62e311b5c", "6", "87cf27724bb990d5d6ef8d314148c102c659aadd2f16e18354e1d380d54f54a1022fee8696a8ce6d6be3f98a9a13fb4f20de58db6c5c06b3404d75d7c864fdcc0968492ff1986ebf43fbde26b5dafdb7e4bad6dd405cb1000", .Okay}, + {.Pow, "-86e78ea52f96dfb87ace8bb5d05f83", "9", "-cd615aa9e3caf100df2529c91951a80b970cdac7da8e450d826af49c3b0bd3b85f3cd3c8fc3eb8cc310d17e270b1625a2396cd0b30192c9a25ea224dc4d6436d5001e167fbad9c385173fb702775769a8c9d8011e68328db8402a0bee960ba0ec31d4ac241cd4c5ccbe6378b0aaae989e77df977ac00e9b80c4a9ed7fcc9f292c35d7e3f5863", .Okay}, + {.Pow, "40a498dcb7507d15c7fa3edbf8e623", "7", "44a37e043e25e99101eb4134828b162239775d0c4ff3a0681c6f479cffaec14343ffd69f36d07d47256b36899bd5f1c2c71529b355421783c022edc257ac9a57cd6504123b2ba81a38f9a30b5056f5b1278d9d0f77b4a6fc3fc17e9915a4b8bb881d8cb4dfefc6b", .Okay}, + {.Pow, "-19379814ba1e94f347d02606d86f3f", "a", "5e926fcad1cc9fc2493d24ccbbf0582d760bba6268deedf5c5eb907a569506e3ff0ae20cc0934e0cd8d75e5f6de082a68089fbfcd499983486db2d3b0b3fd91edbb0374dc784aea10d1572f8363f30b98c81b11b2042880390bc73243694d08100b5e7549902f19d870b9a15ff3320e9a048985a8d58ffb52a6b81bbcfece5d75a3e96cb78fdf67b72c61fcd6f1653bcf781", .Okay}, + {.Pow, "-c25cb5ced1b8937e20a742a2855ea9", "1", "-c25cb5ced1b8937e20a742a2855ea9", .Okay}, + {.Pow, "-8a112a419a4ebe67628c46a89d11ea", "7", "-365d27f57e456d1dd5de22c9b361b4a675bcc004fcb5ca40f2010535af1946111a93f729cfbfc28d9e9cbcb81dcad5ba5d74901c7d2f11ed9f973133ba0a0c2a373e538f93c8db24cff771404891daf7e79dd72865b74220fba2421b8d1d330f000fb5cd0b99e9e80", .Okay}, + {.Pow, "7188150a4277a37d641d1f28a3283b", "1", "7188150a4277a37d641d1f28a3283b", .Okay}, + {.Pow, "-fbc110bac3fb830672a31ef62f7794", "8", "dff0e1d70627062e382b40fe165c80319be8452e3aa0a97e734749979c3661bee734a73762b641a984e5612aebaebfa0ed79c99cf5471e5fa6fadb37d4342ab95391a0228fdb20b691262b86d05ac381164b3e7c884b0538cc0b95e851a9def52f6b97e75075616662b89262d498bd73066050cae8e10000", .Okay}, + {.Pow, "ff4f128d55f28839be6e30a62c1392", "6", "fbe192e781f7a831cf000cb8f58878d62f167638ed75e0b4149e8eeffb45a8955c7e979720a1234ecfd017327c5d56a2c3217258144b74c6b0ad15b1774f16103a8c9f68e1596cee6c43cdb84710f068b5ea69644ba4b26a9c40", .Okay}, + {.Pow, "-8459d6cbd22cde71b9bce26a8ef292", "4", "1249f6e3c0c184b91d9e7acfa9face3458bb60dfaefa95d230f5ddad28c31f0227bf45ef3eef81a89e1ace2240f6b74bd45930cebadcfb1927096a10", .Okay}, + {.Pow, "-539a899c9ca8c21da5c0be7b6fbf9d", "5", "-f372befc775f46e9292833fa7c9626abd94458352e8b19b2c6a136d76186e2316b8a5dadd5881bf13c96a88423979eb319f4fe509fa8765f06e0e3a9a81627c00d4605148c2298552f2d", .Okay}, + {.Pow, "-9cb02dbdd6dfb2b9ab6486696bb60e", "7", "-83ce425a0184b2f64af523584f72c28fb8ff38ebeaef3f4a4900f0b61a164ef852f16ddca0ff074561e2ec0472fd2e94cf1bc149904421bf1cdf3f6ccfae772e954a448ac71bfb193f7624d55d6002f9060e72e8c32f4857a3f8b76ef71e760a631899f2776eefb80", .Okay}, + {.Sqrt, "62c2ab8db7b6932e55157d636aa211", "0", "9f0158303abb829", .Okay}, + {.Sqrt, "ee58ebb144e2c98f9f84e6af04745d", "0", "f7041ac0fefe786", .Okay}, + {.Sqrt, "41499cdf6a2d0250e9be5098546039", "0", "8147f8b22181cbd", .Okay}, + {.Sqrt, "40586bb3074ece191cfe4fcc0949d2", "0", "80584d3dd57dc64", .Okay}, + {.Sqrt, "f5afbe46a94c3385a2d07487edf4bb", "0", "faca4d029482b42", .Okay}, + {.Sqrt, "23ebce49ddcf3bd9fa8aa854c2a6cf", "0", "5fe50f4572101c0", .Okay}, + {.Sqrt, "a34da9d49b5191bb27ccccabb00ac0", "0", "cc76de84373a66c", .Okay}, + {.Sqrt, "ac0ae5c69f98410cd0289237d576bb", "0", "d1dd2ef54a64e47", .Okay}, + {.Sqrt, "d7cabeba065c7ec9f1c0f81e349ea0", "0", "eb09aa23328db66", .Okay}, + {.Sqrt, "6851a61a6922364578d8a428feb8cb", "0", "a36b2b60af162ab", .Okay}, + {.Sqrt, "d9676eb119b4c88ea78412589b8561", "0", "ebe9fe43b073095", .Okay}, + {.Sqrt, "29bc2958436cceb9ed758169768502", "0", "675d3d5f361a149", .Okay}, + {.Sqrt, "9b217456b160770a6bac21cc9910d4", "0", "c74847fec9d9277", .Okay}, + {.Sqrt, "2e6cb6899949b0af960dd65a7069fe", "0", "6d045c23ec09f3e", .Okay}, + {.Sqrt, "c8989b28efd9aefa6f26fea016ac7e", "0", "e29c7348a08580d", .Okay}, + {.Sqrt, "972f45ef7e78ce4b9c2a21b7927f2b", "0", "c4bb41ef16557b4", .Okay}, + {.Sqrt, "c949455b0af94d02e3c35ea9c90e68", "0", "e300271ba4167af", .Okay}, + {.Sqrt, "bd32e399983566a1a3a0a8a6b06e5f", "0", "dc144ba190a6d3b", .Okay}, + {.Sqrt, "676183e81b208998c701fbe72944ce", "0", "a2aea818a09c586", .Okay}, + {.Sqrt, "5307d5ce04b68fd9c1cfcac7335a5d", "0", "91cb3729eb1e93d", .Okay}, + {.Sqrt, "294a1889547731da1971d2b7f17ba6", "0", "66cf9bd2c73759c", .Okay}, + {.Sqrt, "7e5762fd15f2d911e06c086d6b8379", "0", "b3d7b95a43503b7", .Okay}, + {.Sqrt, "f679c13f0d059ae3ee1e6ff77d38d7", "0", "fb31527b9990866", .Okay}, + {.Sqrt, "94c6d3318e67bdd71fcfa3e199be95", "0", "c32890e9a64ed29", .Okay}, + {.Sqrt, "f5f93d9b086786181986696a367993", "0", "faefcd4cd42069d", .Okay}, + {.Sqrt, "b34102fbd4de585558a6327fcd7829", "0", "d6379adc111ffce", .Okay}, + {.Sqrt, "95fa3583fb180e53946f40ec5ff88d", "0", "c3f1c4642f21f8c", .Okay}, + {.Sqrt, "4dec057cad04042c7339581208d0f7", "0", "8d3cca7c7dbb5a3", .Okay}, + {.Sqrt, "fd65a69380b2f2a42130f0c9b7284b", "0", "feb1f95f1a57e00", .Okay}, + {.Sqrt, "6c1e9c59b396589fc169dd2339dd49", "0", "a65e7033bf8b12d", .Okay}, + {.Sqrt, "cfe7bcd4acc362fd0e619deda5db29", "0", "e6b3e4685413ed8", .Okay}, + {.Sqrt, "a21a9e762f680c767f56e190ea4d8c", "0", "cbb64c12df30dc1", .Okay}, + {.Sqrt, "cc3af5afd6524a11f616c5a30bdfdb", "0", "e4a798aec0b5442", .Okay}, + {.Sqrt, "677b6e93abdf54a263f36ad1e25f4d", "0", "a2c30b0af0c5fe4", .Okay}, + {.Sqrt, "1ac358809774879291b3a114453a9f", "0", "52c5d9e640f4234", .Okay}, + {.Sqrt, "e855b1013ac87b4f7bbf75543a82d9", "0", "f3e16786e4810c6", .Okay}, + {.Sqrt, "43cc18385569ecc68c37b198e36674", "0", "83be168b96b1c82", .Okay}, + {.Sqrt, "6ad681956385784bab44bdfabb8d6c", "0", "a561401bba88b76", .Okay}, + {.Sqrt, "413fba54478ea8cfba9881b9500083", "0", "813e2edbd4d6278", .Okay}, + {.Sqrt, "462e8d80effaa9018b6a0aff71283e", "0", "860a14296a2db97", .Okay}, + {.Sqrt, "5d1d08361c9a6593f2319faa00f28", "0", "26991e1595bb4f4", .Okay}, + {.Sqrt, "539ef39258bf7e9d808d94c72fc2bb", "0", "924fa7441b8cc41", .Okay}, + {.Sqrt, "5e58fee290a03951552daaebcf4a42", "0", "9b698f29235cae6", .Okay}, + {.Sqrt, "3f484e4a855f30d8751c4257ea746c", "0", "7f47c9bc78cc47a", .Okay}, + {.Sqrt, "3fae57824431bc21c79bfc05b30991", "0", "7fae3d658a84ecf", .Okay}, + {.Sqrt, "99945378f2fd79c8d617819de0a324", "0", "c648901995a5d27", .Okay}, + {.Sqrt, "3fc8e13b68a2479ada31c11d662283", "0", "7fc8d5580d5c7b8", .Okay}, + {.Sqrt, "d354c4c63d25616f4ac56dce132210", "0", "e898810fd8f8b0c", .Okay}, + {.Sqrt, "689428d43ae00c8a49e7e4adb25707", "0", "a39f3b83564c35f", .Okay}, + {.Sqrt, "4ab763edfefa5d963a0ad2e9415cd4", "0", "8a4d43596cf3d7c", .Okay}, + {.Sqrt, "54378f4583d1b20a7e6833d7491872", "0", "92d4ecdd3d92762", .Okay}, + {.Sqrt, "ccb53a34f927c2f89d2a5feda1304", "0", "393b00170f971bf", .Okay}, + {.Sqrt, "d5d00e90251c5a565cebe1f88456ab", "0", "e9f517072caa9cd", .Okay}, + {.Sqrt, "1ec8401f06c1188faf3ca1f965c89b", "0", "58c55180b56790f", .Okay}, + {.Sqrt, "43ebe83dd11c880daac81119413f94", "0", "83dcfb96e522a65", .Okay}, + {.Sqrt, "609214726db102cbbeb380c6cce48c", "0", "9d3b897538f306a", .Okay}, + {.Sqrt, "b3c27f7510065a4f02d84879a395ea", "0", "d684ebed67f01db", .Okay}, + {.Sqrt, "e2efd3576332b6b42511ec3dbb7fee", "0", "f107dfa782ff16c", .Okay}, + {.Sqrt, "89ed891a9a638c6a1b6b3143b4527a", "0", "bbe88774eaa576d", .Okay}, + {.Sqrt, "bfcfb7b6468dc02a6cde4fc06d0fa6", "0", "dd97f54ab582a17", .Okay}, + {.Sqrt, "ca8b28a610c37a037a7f8f36d51710", "0", "e3b55ff0ebc6230", .Okay}, + {.Sqrt, "daf6ecf36444ddfb9ba18490103b05", "0", "ecc25bdf77a672c", .Okay}, + {.Sqrt, "6668e1e1803352bce4205be66bb993", "0", "a1ea91737f88d9d", .Okay}, + {.Sqrt, "bcdac6f810da24c962ef4e29588b43", "0", "dbe106875b9e15a", .Okay}, + {.Sqrt, "36a5bafd6dd4c71f4d6111fa206d73", "0", "76473783e47bc5c", .Okay}, + {.Sqrt, "18fdc2674c90ebf224a47a7f5f9d29", "0", "4ffc6a2a4fc6f4f", .Okay}, + {.Sqrt, "fbe0ec5f63f281c8b56df996f11b62", "0", "fdee5237dc6bad1", .Okay}, + {.Sqrt, "b82e7d1b8939820009b616124e657c", "0", "d924420c530110b", .Okay}, + {.Sqrt, "2ba3edd8b22f225adada9fd4688dc0", "0", "69b2854f49c1ee4", .Okay}, + {.Sqrt, "794f616fbe7d3990ec7e9b278be6fb", "0", "b039b1c529a1c8c", .Okay}, + {.Sqrt, "390f2f3d572fa3395e55aa5ecc12a8", "0", "78dc3524397c99b", .Okay}, + {.Sqrt, "27741a7ee02570389925496ce3fbe1", "0", "647fd03ba86aac8", .Okay}, + {.Sqrt, "1733222348d968dbcac89bd1243606", "0", "4d10d67df503409", .Okay}, + {.Sqrt, "df96780f8ecafc5c8eff473cc1932d", "0", "ef3ee144601b67d", .Okay}, + {.Sqrt, "cc307b09640d4fa9221004ffaaa804", "0", "e4a1badec54cbab", .Okay}, + {.Sqrt, "c2a86946b21a5631468c5869ba1244", "0", "df3b538815e16bc", .Okay}, + {.Sqrt, "f83b52882a0a5c02e824c89eb0a1f5", "0", "fc1600535b4869d", .Okay}, + {.Sqrt, "e6f47093373592fbad981db8dbd881", "0", "f327b9a1c7cd27b", .Okay}, + {.Sqrt, "bb65083acf8607c9b4d1afc344bf86", "0", "db0708343aaf0f2", .Okay}, + {.Sqrt, "773cb6e586b49a71b4ff35caef6b24", "0", "aeb6968f85f27ea", .Okay}, + {.Sqrt, "fbddd611ffb5b01da993e685d73e41", "0", "fdecc3d7b12de49", .Okay}, + {.Sqrt, "7f63e2a2149b6f97cf549cb30b6bae", "0", "b4966dae7b2012a", .Okay}, + {.Sqrt, "a3515f5730cddcff6544052a9b9d49", "0", "cc7930ebdd2b9a0", .Okay}, + {.Sqrt, "b278c732affce7e9b1cf484118cd8a", "0", "d5bfd46764a43fe", .Okay}, + {.Sqrt, "b4b1a31b9f4831ba61e2585e0c21dc", "0", "d7136d5379926e4", .Okay}, + {.Sqrt, "9fcebce4aa6a1184399b4cf4e799fe", "0", "ca439779ae51247", .Okay}, + {.Sqrt, "fa720d99be8ea97ca1345e23038378", "0", "fd3520ab9c7fc07", .Okay}, + {.Sqrt, "3a8d3a84c96e3bb8f6d445dd6bfa4c", "0", "7a6e3595b61784c", .Okay}, + {.Sqrt, "6e3e8b29121a3a1f955fbed25b2cf5", "0", "a7fee3ed9787255", .Okay}, + {.Sqrt, "2cc4fe65ff1d85aec569158ed2a6b2", "0", "6b0e5809de378b4", .Okay}, + {.Sqrt, "65d7d3decb2feedcf2649cd228c5f7", "0", "a177bd1c2bf6d16", .Okay}, + {.Sqrt, "792f3453cf72659d342d52e826788c", "0", "b02251418bd0851", .Okay}, + {.Sqrt, "258e79a17b5d62fd12376d33e1d024", "0", "620dad956921374", .Okay}, + {.Sqrt, "36a542b61f778b9c4c410fd14086ed", "0", "7646b5596ebe42f", .Okay}, + {.Sqrt, "496fee91f65382a99bbb70b8692547", "0", "891ce35391ebb45", .Okay}, + {.Sqrt, "5af744259d784155c4dc69d9322e47", "0", "989a064bd29a4ce", .Okay}, + {.Sqrt, "599ce14acfa8c050db4b568adba434", "0", "9776647bc824b5a", .Okay}, + {.Sqrt, "24a4ce3955655f6f7e601adf90a3d7", "0", "60dac45dbed0f16", .Okay}, + {.Sqrt, "f43d1b8e08207c2d7fd0d89488beaa", "0", "fa0cda93df0bfac", .Okay}, + {.Sqrt, "72c7d23e1b522650631b59ac38eec0", "0", "ab6ac6e426d1cdf", .Okay}, + {.Root, "10a157217ea8f01c4e185d80f40062", "2", "413f90706a04225", .Okay}, + {.Root, "cf51f1c733afbd10a4b4e52cf9013", "3", "5eb24bc09a", .Okay}, + {.Root, "6bd2a7cc718bdc2c4b3d1f1aa1d32c", "4", "338ee5e3", .Okay}, + {.Root, "495b51e970c7bd88720679d0a11575", "5", "c76116", .Okay}, + {.Root, "8af38458a8c7e3ed2843d6a1250560", "6", "e7364", .Okay}, + {.Root, "4f0a1e036625a983f0fb34d944703", "2", "238fc9901fb44a1", .Okay}, + {.Root, "c8fe3d6ad535dd07fdbf4772479b34", "3", "ec2aea0484", .Okay}, + {.Root, "90676f1c38c055c1ba86a5d7c3dfaf", "4", "3776e717", .Okay}, + {.Root, "db69281cfb4849292ffdccf0f8bd76", "5", "f83950", .Okay}, + {.Root, "735a1d31617440d5fecc288cb49bb7", "6", "e0263", .Okay}, + {.Root, "8f113145acd8e518eb73de0d6289f", "2", "2fd82252d5907fd", .Okay}, + {.Root, "2b7dc9e2fe4b215d16f6231dde37d3", "3", "8dc8bd3c79", .Okay}, + {.Root, "3dfe2af5f83dc0fd613f74914126bc", "4", "2ce550d2", .Okay}, + {.Root, "fc88d07eaa28592bd07f6aecd08559", "5", "ff4d98", .Okay}, + {.Root, "ee6b1b9d99059e8ff52816b54420aa", "6", "fcfb7", .Okay}, + {.Root, "1199dd464a8544575a5be55afb7b77", "2", "43203032110fa4c", .Okay}, + {.Root, "7362b17a7315e07c0c404f04152eb5", "3", "c447cca711", .Okay}, + {.Root, "449863d201bfc9bfb160b7aa0a5cca", "4", "2e0bd1eb", .Okay}, + {.Root, "2cf343e670ef62aedc0614c31da82c", "5", "b4c667", .Okay}, + {.Root, "c5ec71f2f89bd6f08fb011ec7257f1", "6", "f5410", .Okay}, + {.Root, "1a25d415009c87207e226e75bfdf6c", "2", "51d0d998c94a5b6", .Okay}, + {.Root, "85dae3292186347dda43947d899a50", "3", "ce3d4655f9", .Okay}, + {.Root, "9a537b3b88d1341cfe29466d4428d", "4", "1c326184", .Okay}, + {.Root, "fc4b9d679e3d8612a2fd0006c4ef39", "5", "ff4137", .Okay}, + {.Root, "e93095f254a0cf57adc3ac6f984451", "6", "fc0c8", .Okay}, + {.Root, "c21c6ebfa92f7f321eeb922f11e883", "2", "deeb01bccfdf0ad", .Okay}, + {.Root, "b0159bb163ef09987bb98103c6e57b", "3", "e1fa78e4c0", .Okay}, + {.Root, "3711741cba9e63e2e89dace66e00b1", "4", "2b95f7e5", .Okay}, + {.Root, "3243911422bf5f4b6519d28ecfd20f", "5", "b8dc31", .Okay}, + {.Root, "2fabbd07ba0e7223d385e4657076", "6", "4cc59", .Okay}, + {.Root, "57b84cc1d65b846b13856fc91bc52a", "2", "95dab0e9b62bdf3", .Okay}, + {.Root, "f9617697bee20a0441fd78ce766d99", "3", "fdc63705c4", .Okay}, + {.Root, "393e4b220db0fec9d70e3331914dea", "4", "2c028e53", .Okay}, + {.Root, "eb5c9eef6f92bbe1e17d6a7323fb7c", "5", "fbbb80", .Okay}, + {.Root, "d681e149745e595444b1f26573708e", "6", "f890b", .Okay}, + {.Root, "76d921190f00462fd6167ad2a6ca1e", "2", "ae6d91cda9cd47f", .Okay}, + {.Root, "a257b74d69b81ee527efede4c760ec", "3", "dbf0a273ba", .Okay}, + {.Root, "2fdf81ab17e17a4e4be749c8ebdecc", "4", "2a1624d8", .Okay}, + {.Root, "a0a48d9d492db77b0b26141fc4f512", "5", "e9381a", .Okay}, + {.Root, "bbafe9b789fe88c2e094cd06a0487d", "6", "f317c", .Okay}, + {.Root, "a2edc69cd59bf1b5d47f874b2e7303", "2", "cc3ace7f218777f", .Okay}, + {.Root, "f2f872878cc11d132b0a22301faa1b", "3", "fb94bbddbc", .Okay}, + {.Root, "4c6b0e0843a9cc35400c27c14303f7", "4", "2f4e6af1", .Okay}, + {.Root, "52cb822bc4f33cad45caa98a3ae269", "5", "cc43b1", .Okay}, + {.Root, "d4e5eb898735c13739b889e18b5314", "6", "f840e", .Okay}, + {.Root, "4d318bee6eb48920ac5a49b7dc170e", "2", "8c93658b92691c2", .Okay}, + {.Root, "5be8e98e42e2048fd511d511a89013", "3", "b5f2afbf5f", .Okay}, + {.Root, "3151a74df49baf66d40c7e8a57a82", "4", "15334b84", .Okay}, + {.Root, "7576c7e01fd1dc093fc787d5db0216", "5", "db10a1", .Okay}, + {.Root, "63fa04245cdc853fc79790962bacd7", "6", "dade4", .Okay}, + {.Root, "8f80162d1b70f1d35b6bc298ce1ed2", "2", "bfaaa67b068e613", .Okay}, + {.Root, "8e138f06bc8de3ee191d843b9fef75", "3", "d260ce4299", .Okay}, + {.Root, "f91bdb74842b1e5f5c9ef197ac3c3c", "4", "3f909c3a", .Okay}, + {.Root, "39fd817b76548f3b04e8d5ff35285e", "5", "be3915", .Okay}, + {.Root, "4066a7bab77d18353efd2d46b0ff5a", "6", "cb662", .Okay}, + {.Root, "3b3709f390db0a44a7b5cdaf30c88f", "2", "7b1f3e952d316dc", .Okay}, + {.Root, "9e2694752de2474c213ca576450110", "3", "da07c7389c", .Okay}, + {.Root, "25d4a34d56e1bf1012fbd9be58fb5", "4", "13d725b5", .Okay}, + {.Root, "4ea15f090b9e4ba9f7c79f561d9a5b", "5", "ca2ab9", .Okay}, + {.Root, "fbaad1cb36dea7724678cf188a096a", "6", "ff45d", .Okay}, + {.Root, "22c036b8243f8588d740b98311d5e9", "2", "5e51da9e0cfceca", .Okay}, + {.Root, "9002f56d2b23b747a35f3613510968", "3", "d354392be5", .Okay}, + {.Root, "2e06a68e9dc4ae3ccd914ae676e71e", "4", "29acae30", .Okay}, + {.Root, "6745de62dc4bf78a9ef599fca04821", "5", "d57eea", .Okay}, + {.Root, "6b34af81f0095e1dbf26aba0af5183", "6", "dd6e1", .Okay}, + {.Root, "e34ead33d4706f11f22bda070089fc", "2", "f13a3956ff07f9c", .Okay}, + {.Root, "1324d40a92b6492b14925ce54905da", "3", "6bdaa37191", .Okay}, + {.Root, "58db01228b8318833a4a5eb69c72b9", "4", "311faa9c", .Okay}, + {.Root, "234184556dceba1da58da8c5f68ad8", "5", "ac33bb", .Okay}, + {.Root, "d1b3d3cecb45e816316806e7c5009c", "6", "f7a0e", .Okay}, + {.Root, "39397f780192fd4233223d0eb9b70a", "2", "7908fcfd0e8a786", .Okay}, + {.Root, "c27e00b8ca788ebff945160aba1587", "3", "e997ede82a", .Okay}, + {.Root, "e71c5d0e4cc7983f31ed0f5cb0cd0d", "4", "3e625efb", .Okay}, + {.Root, "7a57bebc13b5845221f72fe9042f59", "5", "dcdaee", .Okay}, + {.Root, "9ed13eb706eb814786e826697beec", "6", "94ef5", .Okay}, + {.Root, "de9040e209f486141923474d990c72", "2", "eeb26dfe54724ca", .Okay}, + {.Root, "c854161033296360bdad6d4501928a", "3", "ebe83260e5", .Okay}, + {.Root, "3e3516d2a0979e8ddf7bf80e2775a3", "4", "2cef3f17", .Okay}, + {.Root, "ad20ac49059848dec6df28fbfc69f7", "5", "ecbc8c", .Okay}, + {.Root, "837ce0850edf789b553158498fba4a", "6", "e5182", .Okay}, + {.Root, "3bdb6716894515e982b75ee0f4aa1b", "2", "7bc9a8d4475f6ea", .Okay}, + {.Root, "7b5c0a74a825b969eab0f8bda12dac", "3", "c8b39d8e98", .Okay}, + {.Root, "6883c1e90dd7d53610037aa934d018", "4", "33287873", .Okay}, + {.Root, "7fe952b2f16ac29a0b189432199c6f", "5", "ded480", .Okay}, + {.Root, "426db1f971f26d8b953192c44f675d", "6", "cc73d", .Okay}, + {.Root, "b83fb79ed83d2e31999aeeebe2477f", "2", "d92e69b4e6fa43c", .Okay}, + {.Root, "b590bf66580632da19e8939ba86481", "3", "e44c973d96", .Okay}, + {.Root, "4c5702ed0e9a8c64c54e7a9d421323", "4", "2f4b508a", .Okay}, + {.Root, "71d69da6bf4520dd2d3c87f1c64169", "5", "d9b213", .Okay}, + {.Root, "5d32f403622bd752b2c94610b27b67", "6", "d8529", .Okay}, + {.Root, "43fcb414b9d5e0978aeb10d5295f9b", "2", "83ed4872cfe0ec2", .Okay}, + {.Root, "80cad211d850368606fff486f234f3", "3", "cb9b0e63e2", .Okay}, + {.Root, "45f894372cc647d16f1db6c55f7fa5", "4", "2e467c00", .Okay}, + {.Root, "68f2eb764edf9148ea9bc08796b4ea", "5", "d62f2b", .Okay}, + {.Root, "fcb283e1a3d7bec0bc670b6d5250c4", "6", "ff725", .Okay}, + {.Root, "dadce8f6507f08f01d9373db6116e9", "2", "ecb44ad7502e275", .Okay}, + {.Root, "2e3a5b838a51430f403338bc5c2f88", "3", "90b29ac1eb", .Okay}, + {.Root, "3bf0444f1bf582301cd31be40203d2", "4", "2c84e4c0", .Okay}, + {.Root, "5ae6d8a4d99a8189ee2e511e4669b9", "5", "d01dcf", .Okay}, + {.Root, "f49c1d20d5ea28aaf157ab7b0f0cb3", "6", "fe10c", .Okay}, + {.Shl, "-658d3d08e731450523288b993bdfbf", "3c", "-658d3d08e731450523288b993bdfbf000000000000000", .Okay}, + {.Shl, "a189599945cd53f46acc6f4ac90488", "0", "a189599945cd53f46acc6f4ac90488", .Okay}, + {.Shl, "-e8084215bade34a2a832d43b9ea4fb", "78", "-e8084215bade34a2a832d43b9ea4fb000000000000000000000000000000", .Okay}, + {.Shl, "d28decc587a041d7e42a1f2fa28007", "258", "d28decc587a041d7e42a1f2fa28007000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "7569d5e1a75d7f73d14ce469835452", "3c", "7569d5e1a75d7f73d14ce469835452000000000000000", .Okay}, + {.Shl, "-24a51f36e5e302158e5a88ed5c3dd", "f0", "-24a51f36e5e302158e5a88ed5c3dd000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "2d90d15bee02bd7aca9a66777d005f", "78", "2d90d15bee02bd7aca9a66777d005f000000000000000000000000000000", .Okay}, + {.Shl, "238b064bb74cd5645e8e20f254e3c4", "f0", "238b064bb74cd5645e8e20f254e3c4000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "77097dd67669de087e31db3c4558d", "78", "77097dd67669de087e31db3c4558d000000000000000000000000000000", .Okay}, + {.Shl, "-b2e7b6eee99021b5b7b2b2d647481e", "21c", "-b2e7b6eee99021b5b7b2b2d647481e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "6309dd4d898be926a69106f85f1c46", "1a4", "6309dd4d898be926a69106f85f1c46000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-707d0b9a1b3126f26f990593636f1e", "b4", "-707d0b9a1b3126f26f990593636f1e000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "790a29c144992ce75eae07115982b1", "12c", "790a29c144992ce75eae07115982b1000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-772002671f998cea41950c33a295eb", "f0", "-772002671f998cea41950c33a295eb000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "c2c68423de26917271baa68db64a3f", "0", "c2c68423de26917271baa68db64a3f", .Okay}, + {.Shl, "-6600bbec432116ea389decd67fece3", "78", "-6600bbec432116ea389decd67fece3000000000000000000000000000000", .Okay}, + {.Shl, "-944c70dc7667fdab30117d2bbed4aa", "1e0", "-944c70dc7667fdab30117d2bbed4aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "6455f8815e82a4abec258b125155af", "3c", "6455f8815e82a4abec258b125155af000000000000000", .Okay}, + {.Shl, "-f78acd68f7afb295c1f349796650fd", "168", "-f78acd68f7afb295c1f349796650fd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "ea3c758da2e3bac2ef7f10699ce980", "258", "ea3c758da2e3bac2ef7f10699ce980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-121b346cd116d61944cbe39cf02e18", "f0", "-121b346cd116d61944cbe39cf02e18000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-f6bd7793cb62c5fe5a4cf4668022bf", "b4", "-f6bd7793cb62c5fe5a4cf4668022bf000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "e67adba938d4a5ba3ab9ffb717afe", "3c", "e67adba938d4a5ba3ab9ffb717afe000000000000000", .Okay}, + {.Shl, "f74e955ca1c5983e9da4100dcac037", "3c", "f74e955ca1c5983e9da4100dcac037000000000000000", .Okay}, + {.Shl, "-da6c4d25768161e4155f976e7fd32d", "1a4", "-da6c4d25768161e4155f976e7fd32d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-508805b06e0b273e7c0de2b4e42ce5", "168", "-508805b06e0b273e7c0de2b4e42ce5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "21cac804f76655bf3b63bb60c6b42", "b4", "21cac804f76655bf3b63bb60c6b42000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "fac290d4a58edb998777ce26332437", "1e0", "fac290d4a58edb998777ce26332437000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-d2f71eccbd401cf34b6f2772c33504", "3c", "-d2f71eccbd401cf34b6f2772c33504000000000000000", .Okay}, + {.Shl, "-983b3a02d754e76a2136bfe04538f7", "1e0", "-983b3a02d754e76a2136bfe04538f7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-b8bd8ce0cbb8684e6bba8214b9175a", "3c", "-b8bd8ce0cbb8684e6bba8214b9175a000000000000000", .Okay}, + {.Shl, "-ad9d1c5cb6e62e46626cf8ec3c636c", "1e0", "-ad9d1c5cb6e62e46626cf8ec3c636c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-54cb3bfa1944106d16b7dd1b8e9bc5", "3c", "-54cb3bfa1944106d16b7dd1b8e9bc5000000000000000", .Okay}, + {.Shl, "4c82756e3e83c0d4d856ba8f0d4472", "258", "4c82756e3e83c0d4d856ba8f0d4472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-8d87c19d6f8aecb713b722e2ca5847", "168", "-8d87c19d6f8aecb713b722e2ca5847000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "701f015c25c06c4f49b2af5c98cea0", "1a4", "701f015c25c06c4f49b2af5c98cea0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "60a4a494ca89cd11eaee20872fad25", "b4", "60a4a494ca89cd11eaee20872fad25000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-ddef18322467fa6d382c35d528cbaa", "0", "-ddef18322467fa6d382c35d528cbaa", .Okay}, + {.Shl, "52d7e1c5aeceea088584080e7bae34", "0", "52d7e1c5aeceea088584080e7bae34", .Okay}, + {.Shl, "698b2e8973088cc64a4c0faea21cdf", "21c", "698b2e8973088cc64a4c0faea21cdf000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-8c54f6339c4ae8bebb9dca6d59d655", "78", "-8c54f6339c4ae8bebb9dca6d59d655000000000000000000000000000000", .Okay}, + {.Shl, "-483bd7a66ae9bf14a8e0ffb5331444", "0", "-483bd7a66ae9bf14a8e0ffb5331444", .Okay}, + {.Shl, "463f8dd1512737e7878b61e912309a", "1e0", "463f8dd1512737e7878b61e912309a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "b0ff158395e9c5637ba2d608b0c8e0", "258", "b0ff158395e9c5637ba2d608b0c8e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-189dacac8d5275bf5db45590d69f14", "b4", "-189dacac8d5275bf5db45590d69f14000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-cf78ac49617f519b2907fe7d5f09b1", "1a4", "-cf78ac49617f519b2907fe7d5f09b1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-8e26ed632298e36e7ab270dff8a3a4", "21c", "-8e26ed632298e36e7ab270dff8a3a4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-d6d6ac0a5a03ed6aad82d3f4b50df9", "0", "-d6d6ac0a5a03ed6aad82d3f4b50df9", .Okay}, + {.Shl, "fe277a9f1bc8b294ed743528f9e14c", "0", "fe277a9f1bc8b294ed743528f9e14c", .Okay}, + {.Shl, "-886ef6cbd61932b7b9e1dfb6785399", "78", "-886ef6cbd61932b7b9e1dfb6785399000000000000000000000000000000", .Okay}, + {.Shl, "-bc2457a3ed4f9a8f1948338f874960", "b4", "-bc2457a3ed4f9a8f1948338f874960000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-426bd1f974dc0609b9c1050ff8324c", "12c", "-426bd1f974dc0609b9c1050ff8324c000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-3a8342f9e8dbe7756f244fbfad4dd4", "b4", "-3a8342f9e8dbe7756f244fbfad4dd4000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-8a428a37bf21ad928f1abe71e629b7", "78", "-8a428a37bf21ad928f1abe71e629b7000000000000000000000000000000", .Okay}, + {.Shl, "-e45a05bccf7e80c5d241d6f60d7c42", "12c", "-e45a05bccf7e80c5d241d6f60d7c42000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-200dc45c64f05bb129cc529e564f92", "168", "-200dc45c64f05bb129cc529e564f92000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-a5f1e2bc4e6e3a71434f8f0b227f3e", "12c", "-a5f1e2bc4e6e3a71434f8f0b227f3e000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-e0baf9fab9cf811a0052281f9c0e96", "1e0", "-e0baf9fab9cf811a0052281f9c0e96000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-864ffc64f0869ffb4fc65f37a6b999", "1a4", "-864ffc64f0869ffb4fc65f37a6b999000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "ded81eb544433c41895a4cab5a3e47", "1a4", "ded81eb544433c41895a4cab5a3e47000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "60d02474a900fa9e0658aa8635300a", "258", "60d02474a900fa9e0658aa8635300a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "10bdc62a35e240e2c2c816b41dd32f", "78", "10bdc62a35e240e2c2c816b41dd32f000000000000000000000000000000", .Okay}, + {.Shl, "39e71136e71e3a8e712ebd7ccd321b", "f0", "39e71136e71e3a8e712ebd7ccd321b000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-48bf1c52f962dbf26979a7e27c4f6f", "f0", "-48bf1c52f962dbf26979a7e27c4f6f000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-952b905ae68b83644a5085b4347303", "168", "-952b905ae68b83644a5085b4347303000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-87c58ff7391b413a7d9eb7a0bc138d", "258", "-87c58ff7391b413a7d9eb7a0bc138d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "58949fb5d92360f2acb4b46155a644", "f0", "58949fb5d92360f2acb4b46155a644000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "f6c75c94e711343bfa870f439310c", "1a4", "f6c75c94e711343bfa870f439310c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-62f1ab29771a502d3452b405e7d0fc", "168", "-62f1ab29771a502d3452b405e7d0fc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "66762e87d6815c8cac54c084ab1e6e", "168", "66762e87d6815c8cac54c084ab1e6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "dbecc16a2b12b89941f1b074e4eabb", "78", "dbecc16a2b12b89941f1b074e4eabb000000000000000000000000000000", .Okay}, + {.Shl, "53312830f014e38440efff2955d542", "3c", "53312830f014e38440efff2955d542000000000000000", .Okay}, + {.Shl, "-71a485b29edf13c7e9bbbe81f28d55", "3c", "-71a485b29edf13c7e9bbbe81f28d55000000000000000", .Okay}, + {.Shl, "-aeedc8bc4a2bc625e3395d61a54f3a", "1a4", "-aeedc8bc4a2bc625e3395d61a54f3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "1dae7091a8e5382590407fb85a3446", "3c", "1dae7091a8e5382590407fb85a3446000000000000000", .Okay}, + {.Shl, "-1f2848713247c481b19a7841ceec0b", "0", "-1f2848713247c481b19a7841ceec0b", .Okay}, + {.Shl, "-719cf5e1852efe103dbb8f9f56402", "1e0", "-719cf5e1852efe103dbb8f9f56402000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-4cbb612a8993dc0785468bea82b84a", "78", "-4cbb612a8993dc0785468bea82b84a000000000000000000000000000000", .Okay}, + {.Shl, "-c4323fe1e34002a86ca6550bc570d5", "3c", "-c4323fe1e34002a86ca6550bc570d5000000000000000", .Okay}, + {.Shl, "-4ff49bc6aa65580bc525d8f781d955", "0", "-4ff49bc6aa65580bc525d8f781d955", .Okay}, + {.Shl, "124597f9ee1db2a29c9155e0ba994e", "258", "124597f9ee1db2a29c9155e0ba994e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "54ee206493a1872cc8baf80cfa1154", "258", "54ee206493a1872cc8baf80cfa1154000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-8e0366464e9ebefe00df4765c47820", "258", "-8e0366464e9ebefe00df4765c47820000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-188fc9eafcd3751ba40609942f7890", "1a4", "-188fc9eafcd3751ba40609942f7890000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "dd0993224cab3cfc44f677abcf5977", "78", "dd0993224cab3cfc44f677abcf5977000000000000000000000000000000", .Okay}, + {.Shl, "-4cf88736b9569635174dc0e91d1af7", "168", "-4cf88736b9569635174dc0e91d1af7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-1b9dcf0cc32f13d88ec4687129ef8f", "1a4", "-1b9dcf0cc32f13d88ec4687129ef8f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "310b5680963f337bd2a1e8bd5f9f4d", "1a4", "310b5680963f337bd2a1e8bd5f9f4d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "2e5cca517cd419eb978ffe8f7d32f9", "12c", "2e5cca517cd419eb978ffe8f7d32f9000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "4cb82c43e0bdb2e83b2d577c95f200", "78", "4cb82c43e0bdb2e83b2d577c95f200000000000000000000000000000000", .Okay}, + {.Shl, "d7771c0fc5d53c6a091ba61713a54f", "1e0", "d7771c0fc5d53c6a091ba61713a54f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-e88fe006377fcaceb008967fcbb6ee", "78", "-e88fe006377fcaceb008967fcbb6ee000000000000000000000000000000", .Okay}, + {.Shl, "e0b5ab720e8bc8927ac2c62723d205", "78", "e0b5ab720e8bc8927ac2c62723d205000000000000000000000000000000", .Okay}, + {.Shl, "e441ad16143d98743ca2d247c0583e", "b4", "e441ad16143d98743ca2d247c0583e000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "6772b1de4cc1c1c1dff44cf3b65f29", "b4", "6772b1de4cc1c1c1dff44cf3b65f29000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-c7a908c675996a5c78776de01c42f3", "1e0", "-c7a908c675996a5c78776de01c42f3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-49e4164e8bd234d2b812ba40c75562", "b4", "-49e4164e8bd234d2b812ba40c75562000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "d8b7b4e05ae24f2cf37d546135f7cc", "3c", "d8b7b4e05ae24f2cf37d546135f7cc000000000000000", .Okay}, + {.Shl, "-89fae13d7439b1aeba0df993cc606c", "21c", "-89fae13d7439b1aeba0df993cc606c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "5ba139cacf39236cec672b7af31d9", "f0", "5ba139cacf39236cec672b7af31d9000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shr, "1fc44e1c8f5073aa85d4ab14a3391b", "f0", "0", .Okay}, + {.Shr, "7fa5e5f6f5ee17eaddee98f5ba5bc1", "12c", "0", .Okay}, + {.Shr, "ae3d7a618e61f43fb093b2f17d89be", "12c", "0", .Okay}, + {.Shr, "e5f51680ef93b5142492683eddce9", "78", "0", .Okay}, + {.Shr, "18488f8a42581b61c882d5dd9013fc", "1e0", "0", .Okay}, + {.Shr, "ea1d6461d9ed01cfb38243c6922b66", "b4", "0", .Okay}, + {.Shr, "d00631ebe3f98fa76c99a00954d443", "78", "0", .Okay}, + {.Shr, "ab84f35e0437fcaf6f24a33be80cac", "f0", "0", .Okay}, + {.Shr, "b18dadb89ed579ba28b89f7ed31596", "1e0", "0", .Okay}, + {.Shr, "3df6eeaf5cda3935f8f7d656412592", "78", "0", .Okay}, + {.Shr, "fac43c91e42fdb66eb43a554f1f527", "258", "0", .Okay}, + {.Shr, "bb30af0fc3ee4c10c70204c1afd4f2", "f0", "0", .Okay}, + {.Shr, "66670b671486f4e46fb39d09fd9c48", "21c", "0", .Okay}, + {.Shr, "c566deff1abe3cfe09f0fc9c5f6a34", "78", "0", .Okay}, + {.Shr, "84a522c9965455fa52a9d0b5b7775f", "168", "0", .Okay}, + {.Shr, "fcab1b67d1e92818b9b5be5d9ea048", "3c", "fcab1b67d1e9281", .Okay}, + {.Shr, "d1ee2ae5ddd7c69bc77d5d46fd33f7", "3c", "d1ee2ae5ddd7c69", .Okay}, + {.Shr, "ec84b92b427ad1d886d61d8679b48", "168", "0", .Okay}, + {.Shr, "7d6419fc5d66dc4e97d9c6eba31f65", "1a4", "0", .Okay}, + {.Shr, "7339383db5316b94cbfd2cb1e9a42b", "1e0", "0", .Okay}, + {.Shr, "200961abb4c0512f282bc6814f1648", "1e0", "0", .Okay}, + {.Shr, "6484bdee4978fcc629bfa6a24b9d", "f0", "0", .Okay}, + {.Shr, "10376509c1859dfd1ef57904fe0f6b", "12c", "0", .Okay}, + {.Shr, "40b7958ae4e99b9b61cd8f8017860e", "258", "0", .Okay}, + {.Shr, "a262e80d02aa62b7eddf40e0c1a333", "258", "0", .Okay}, + {.Shr, "6aa121a01cad630cbac92baebb43a7", "78", "0", .Okay}, + {.Shr, "ae96af31baf3a1559d9bea96e75568", "21c", "0", .Okay}, + {.Shr, "5606d35754ee4f9aa07018828b404b", "b4", "0", .Okay}, + {.Shr, "b02648545551476f92175d8f22af67", "168", "0", .Okay}, + {.Shr, "fa0b72077dc24bd279aab163583db7", "1e0", "0", .Okay}, + {.Shr, "32761894f68eba2ecdd4ac918ec8bf", "78", "0", .Okay}, + {.Shr, "caa5bed3ae8142c996cd68e80983df", "b4", "0", .Okay}, + {.Shr, "b203d7d210dfc5fe78a39be3d95429", "1a4", "0", .Okay}, + {.Shr, "40177f4578998bd04a6d2a718ab043", "258", "0", .Okay}, + {.Shr, "409102784539816b4010e899ff4649", "f0", "0", .Okay}, + {.Shr, "53eb0d31bc11ef199f78aad44a9e78", "12c", "0", .Okay}, + {.Shr, "42079a0a28c33ca7c4c164533eec65", "1e0", "0", .Okay}, + {.Shr, "825a5b2c2b787b07269d94675ff037", "3c", "825a5b2c2b787b0", .Okay}, + {.Shr, "de11733c4514f98ab148bda0167831", "12c", "0", .Okay}, + {.Shr, "9fbc7df64a215c3573a813e49a3ba5", "1a4", "0", .Okay}, + {.Shr, "f557b381b56f724c2379e0414230bc", "258", "0", .Okay}, + {.Shr, "76dfea4c3784bdf674db60d6769965", "21c", "0", .Okay}, + {.Shr, "b8c1a0975018862a0f060d94e8b078", "3c", "b8c1a0975018862", .Okay}, + {.Shr, "71f35af151cc6f3066ce5a80787e53", "12c", "0", .Okay}, + {.Shr, "65f3df82d52ac5b1bd025cc490b461", "b4", "0", .Okay}, + {.Shr, "9dac37375e68fb8489411801f1854c", "f0", "0", .Okay}, + {.Shr, "36e249e98eb6c592633609c102b0d1", "258", "0", .Okay}, + {.Shr, "d9682b71fb53408b8c5a5bb8e6b929", "78", "0", .Okay}, + {.Shr, "b59946cebfab79bce24daffe509296", "78", "0", .Okay}, + {.Shr, "8c1350ce18f3067931b2d7eeff31d6", "f0", "0", .Okay}, + {.Shr, "44056923bdde2078dad1208240e182", "1e0", "0", .Okay}, + {.Shr, "aa5cff9c7d280818558a06923e674d", "f0", "0", .Okay}, + {.Shr, "f96770c9f8edcee259c98fd04172d", "0", "f96770c9f8edcee259c98fd04172d", .Okay}, + {.Shr, "4fb74295e5fe2543ea85b9b320001d", "0", "4fb74295e5fe2543ea85b9b320001d", .Okay}, + {.Shr, "e5a349a39512b46d170a0ba8dbe03d", "78", "0", .Okay}, + {.Shr, "74d0d1bdfa5307be0f01d18f57a6e", "1e0", "0", .Okay}, + {.Shr, "ff1d71786ab7272f46baafb3fb009c", "78", "0", .Okay}, + {.Shr, "5bd31982ece463bf09e716d135d9d4", "1a4", "0", .Okay}, + {.Shr, "3fdf6d44dd2fa6cf6227e1f4b42e4d", "0", "3fdf6d44dd2fa6cf6227e1f4b42e4d", .Okay}, + {.Shr, "be0cc4fe8049b06e04a3f69616a585", "21c", "0", .Okay}, + {.Shr, "64b196c09ac9ed4a779e6893098ea4", "1a4", "0", .Okay}, + {.Shr, "baea13cae5aaa509893a70efceab3c", "0", "baea13cae5aaa509893a70efceab3c", .Okay}, + {.Shr, "86e4ea0a5abefd50810c95c06d6909", "78", "0", .Okay}, + {.Shr, "4840a41269268b23d1dc688fa6a272", "258", "0", .Okay}, + {.Shr, "8c191f2ff6afaeb886e88593344fe", "1e0", "0", .Okay}, + {.Shr, "91a583b4cf8d8ed12a4adb9ace912", "78", "0", .Okay}, + {.Shr, "fa04769e975833cd237fd0d6a59c62", "0", "fa04769e975833cd237fd0d6a59c62", .Okay}, + {.Shr, "37d566faa6d1c71f128f688a63a729", "12c", "0", .Okay}, + {.Shr, "379d16eaab9b9d4527b7127d9e3e85", "1e0", "0", .Okay}, + {.Shr, "c034b3da2c26916e2b2ebddb5019ec", "b4", "0", .Okay}, + {.Shr, "da529ef77b79ab0c67a2df06311c7b", "78", "0", .Okay}, + {.Shr, "dc7ec792a767a911c861fce1e23030", "21c", "0", .Okay}, + {.Shr, "41c423963b378beca1dc3d15ba90df", "168", "0", .Okay}, + {.Shr, "1a802e1ff08f2fd58c240b724c28e8", "b4", "0", .Okay}, + {.Shr, "5f5c74b071faabc15840802ec4209c", "258", "0", .Okay}, + {.Shr, "6007683b140fb1750495fd6000ccf2", "12c", "0", .Okay}, + {.Shr, "deb48a4b6513663d229f0d3d779287", "3c", "deb48a4b6513663", .Okay}, + {.Shr, "298084a29ef5084516a4a377791b05", "0", "298084a29ef5084516a4a377791b05", .Okay}, + {.Shr, "83ef35717378da10f1cf863019cb07", "78", "0", .Okay}, + {.Shr, "efe13f12aa5b8d75506de90220091f", "12c", "0", .Okay}, + {.Shr, "4bcce2d1e8104f5b6ffe5a2c625223", "0", "4bcce2d1e8104f5b6ffe5a2c625223", .Okay}, + {.Shr, "321a2b2ddb17162a0e358f9f7ec1c3", "0", "321a2b2ddb17162a0e358f9f7ec1c3", .Okay}, + {.Shr, "c517c313b12846964fc03f0e7c8f01", "0", "c517c313b12846964fc03f0e7c8f01", .Okay}, + {.Shr, "8779232c5bf4a8f63411fc0682b277", "168", "0", .Okay}, + {.Shr, "74589d16e3b619fe2f3816e0627fc2", "21c", "0", .Okay}, + {.Shr, "3d4bef779013adc7ea0901f5a6fbd3", "1e0", "0", .Okay}, + {.Shr, "99392ea73a0dde4125b39f9762018", "1e0", "0", .Okay}, + {.Shr, "8c3e168c8efb59c146f045aa8092d6", "78", "0", .Okay}, + {.Shr, "d18b630a8a7962fbbeb9baf54975e5", "168", "0", .Okay}, + {.Shr, "39a9550c2d5405fbc34a48940071f1", "3c", "39a9550c2d5405f", .Okay}, + {.Shr, "d207c731f09536a30daa7900d9c674", "f0", "0", .Okay}, + {.Shr, "3dcad14fab82254df4cf499619dfd0", "78", "0", .Okay}, + {.Shr, "fe7c24b1e99f76f4897068ebcbe6d6", "258", "0", .Okay}, + {.Shr, "4c8fa40ae81be73e9ad4e5bcacc280", "1a4", "0", .Okay}, + {.Shr, "97bad43211c08a2b98ad1867866309", "0", "97bad43211c08a2b98ad1867866309", .Okay}, + {.Shr, "41c2ef52c8aaa5f5bab2a4f69c8e32", "78", "0", .Okay}, + {.Shr, "39800dc581db76a0dc8daa73525b61", "258", "0", .Okay}, + {.Shr, "342b2b446280bac44a1f578f1269c6", "b4", "0", .Okay}, + {.Shr, "1bccc1a51e27e60e4cd4b91655fcf0", "12c", "0", .Okay}, + {.Shr, "df97403177c8d24caaf1523cff3eb8", "21c", "0", .Okay}, + {.Shl, "244570854e3f425c6bdad06ca8f2f3", "18", "244570854e3f425c6bdad06ca8f2f3000000", .Okay}, + {.Shl, "-66a05544c910528cea93f56197dad3", "62", "-19a81551324414a33aa4fd5865f6b4c000000000000000000000000", .Okay}, + {.Shl, "f54bf2eac9af50f6e1f0459be92da9", "12", "3d52fcbab26bd43db87c1166fa4b6a40000", .Okay}, + {.Shl, "-935ca9ea6a627d45c42180e0c78ec", "a", "-24d72a7a9a989f517108603831e3b000", .Okay}, + {.Shl, "be143b95d5da6eaa6133c9bdc2baec", "45", "17c28772babb4dd54c267937b8575d800000000000000000", .Okay}, + {.Shl, "-8694fdc2ecd05a80879ce81e71600", "3", "-434a7ee176682d4043ce740f38b000", .Okay}, + {.Shl, "39b904ded7c985278421fc3d9c50f7", "23", "1cdc826f6be4c293c210fe1ece287b800000000", .Okay}, + {.Shl, "-8eea96d025abb9ad01c44a62849f45", "8", "-8eea96d025abb9ad01c44a62849f4500", .Okay}, + {.Shl, "-ba1a2f83b32346bdbed5d1f6f98c71", "11", "-174345f0766468d7b7daba3edf318e20000", .Okay}, + {.Shl, "-f64d76d11266c9edd6cfa93d8d49f2", "45", "-1ec9aeda224cd93dbad9f527b1a93e400000000000000000", .Okay}, + {.Shl, "-ec06059c1af58d82cf8fbc0de61281", "33", "-760302ce0d7ac6c167c7de06f309408000000000000", .Okay}, + {.Shl, "1387237cf7fb303d1848680c7b9dad", "75", "270e46f9eff6607a3090d018f73b5a00000000000000000000000000000", .Okay}, + {.Shl, "-d08ae02ccbc6269bf89263033705ee", "3c", "-d08ae02ccbc6269bf89263033705ee000000000000000", .Okay}, + {.Shl, "-e4af23fe2a26607d2a51b1dc1d04ef", "34", "-e4af23fe2a26607d2a51b1dc1d04ef0000000000000", .Okay}, + {.Shl, "1eb19883ee0ce2c4e3e9c256eaf11c", "34", "1eb19883ee0ce2c4e3e9c256eaf11c0000000000000", .Okay}, + {.Shl, "6f1c4434a95a72391b216c8702bf1a", "56", "1bc7110d2a569c8e46c85b21c0afc68000000000000000000000", .Okay}, + {.Shl, "-c95ca0e6c5b096f182a8cbdc6b0f89", "28", "-c95ca0e6c5b096f182a8cbdc6b0f890000000000", .Okay}, + {.Shl, "8c6f9ac8a2a1b1164f93a3bc241ae", "6f", "4637cd645150d88b27c9d1de120d70000000000000000000000000000", .Okay}, + {.Shl, "-82eaac537f5e60c1b922c5ae5e2f28", "e", "-20baab14dfd798306e48b16b978bca0000", .Okay}, + {.Shl, "-8c4a436b9972479b498f8a682513d8", "2", "-231290dae65c91e6d263e29a0944f60", .Okay}, + {.Shl, "-bcb905712c7a9d993e0d13f23543d", "c", "-bcb905712c7a9d993e0d13f23543d000", .Okay}, + {.Shl, "c617550f4ed58032e97babcd732af9", "4d", "18c2eaa1e9dab0065d2f7579ae655f20000000000000000000", .Okay}, + {.Shl, "3553c9fcc27ab9402fda0bd1b1075f", "53", "1aa9e4fe613d5ca017ed05e8d883af800000000000000000000", .Okay}, + {.Shl, "-9446b6bb675c42d09a49ac3aa8d699", "24", "-9446b6bb675c42d09a49ac3aa8d699000000000", .Okay}, + {.Shl, "23498564192b548d10d26cd4ebf3ae", "60", "23498564192b548d10d26cd4ebf3ae000000000000000000000000", .Okay}, + {.Shl, "ec7d6d997639d51cab76d9c9bacd0f", "65", "1d8fadb32ec73aa3956edb393759a1e0000000000000000000000000", .Okay}, + {.Shl, "-bdc8dfff866ed8c12532d8600673cd", "37", "-5ee46fffc3376c6092996c300339e680000000000000", .Okay}, + {.Shl, "-81dc3af2096563a00cde5b3d72b229", "65", "-103b875e412cac74019bcb67ae564520000000000000000000000000", .Okay}, + {.Shl, "eadf5e9d96d6c76ae5dbee8432608", "3b", "756faf4ecb6b63b572edf74219304000000000000000", .Okay}, + {.Shl, "-883ce2770e168051da7384e9f61d96", "55", "-11079c4ee1c2d00a3b4e709d3ec3b2c000000000000000000000", .Okay}, + {.Shl, "-e78eeb075a4b4931db92d212e961bd", "1f", "-73c77583ad25a498edc9690974b0de80000000", .Okay}, + {.Shl, "-ed50a0dd5eff2fa4323ba52620656a", "3", "-76a8506eaf7f97d2191dd2931032b50", .Okay}, + {.Shl, "825c4932faaf58cdc0415c66520bab", "8", "825c4932faaf58cdc0415c66520bab00", .Okay}, + {.Shl, "d6a1029746a8b2a242830f64516b19", "3b", "6b50814ba3545951214187b228b58c800000000000000", .Okay}, + {.Shl, "-5bd92a0e142451bb71af4f3f2599c0", "36", "-16f64a838509146edc6bd3cfc9667000000000000000", .Okay}, + {.Shl, "c0be8cef6e800c0fcb3acc3c37a811", "f", "605f4677b7400607e59d661e1bd4088000", .Okay}, + {.Shl, "11c91e59c4dcdda9f7dd3ee8c81055", "3c", "11c91e59c4dcdda9f7dd3ee8c81055000000000000000", .Okay}, + {.Shl, "-88807cec625a9dc410424a598b5b1c", "62", "-22201f3b1896a7710410929662d6c70000000000000000000000000", .Okay}, + {.Shl, "e24c27a2fc9196b8d358cf20ec7e95", "3a", "389309e8bf2465ae34d633c83b1fa5400000000000000", .Okay}, + {.Shl, "95c9cb4b2ceae8365134ffd45d8050", "52", "257272d2cb3aba0d944d3ff5176014000000000000000000000", .Okay}, + {.Shl, "a60cf77f73d57dd05c0d5aebd48d5c", "5e", "29833ddfdcf55f74170356baf52357000000000000000000000000", .Okay}, + {.Shl, "-df6a832cea6d8480f5fd08e268f591", "77", "-6fb541967536c2407afe8471347ac8800000000000000000000000000000", .Okay}, + {.Shl, "-1bb9278c2e9db1551856ad6545dcd8", "42", "-6ee49e30ba76c554615ab5951773600000000000000000", .Okay}, + {.Shl, "-92e9b031cb6a42a79d5b485d40a0ff", "72", "-24ba6c0c72da90a9e756d21750283fc0000000000000000000000000000", .Okay}, + {.Shl, "-67944e9550a59b37ee41f0910783", "2c", "-67944e9550a59b37ee41f091078300000000000", .Okay}, + {.Shl, "e84086f2c4b36687acc2f22c3eed53", "15", "1d0810de58966cd0f5985e4587ddaa600000", .Okay}, + {.Shl, "-618644ced4c6207e950261bfba604e", "3f", "-30c322676a63103f4a8130dfdd30270000000000000000", .Okay}, + {.Shl, "-7643e6494e66c382a33093dfc24b23", "64", "-7643e6494e66c382a33093dfc24b230000000000000000000000000", .Okay}, + {.Shl, "775fd7aaf5f14307b2e1aa0612902f", "75", "eebfaf55ebe2860f65c3540c25205e00000000000000000000000000000", .Okay}, + {.Shl, "9817da610a78edaf89c9d78786dbfc", "1d", "1302fb4c214f1db5f1393af0f0db7f80000000", .Okay}, + {.Shl, "5e68236cc7b4ae21a91b225019d968", "73", "2f3411b663da5710d48d91280cecb400000000000000000000000000000", .Okay}, + {.Shl, "-47a958accdafbcd7685b305d006778", "44", "-47a958accdafbcd7685b305d00677800000000000000000", .Okay}, + {.Shl, "-32f28e6f786a56f6ce8b797d99fede", "4d", "-65e51cdef0d4aded9d16f2fb33fdbc0000000000000000000", .Okay}, + {.Shl, "6fad5bdf93a994295718ce9cebc16b", "45", "df5ab7bf27532852ae319d39d782d600000000000000000", .Okay}, + {.Shl, "-840bc2e57e624169065fff4db85c50", "41", "-1081785cafcc482d20cbffe9b70b8a00000000000000000", .Okay}, + {.Shl, "-42dd661ce9b320eca8c9cdfffde556", "19", "-85bacc39d36641d951939bfffbcaac000000", .Okay}, + {.Shl, "78c3350e4d391d5b4366a51394dd2e", "28", "78c3350e4d391d5b4366a51394dd2e0000000000", .Okay}, + {.Shl, "-fc0534e6c89b099c1a5ee98ac4aabb", "54", "-fc0534e6c89b099c1a5ee98ac4aabb000000000000000000000", .Okay}, + {.Shl, "a1b0fabe6e746fe0acdcc6179f810c", "30", "a1b0fabe6e746fe0acdcc6179f810c000000000000", .Okay}, + {.Shl, "7f293f74d8696367a09a5f7b3b6eed", "20", "7f293f74d8696367a09a5f7b3b6eed00000000", .Okay}, + {.Shl, "f51b619818c5e976f0fa2f35c052e5", "52", "3d46d86606317a5dbc3e8bcd7014b9400000000000000000000", .Okay}, + {.Shl, "-1fc572fa3b5cfc9f9cb3153813e202", "58", "-1fc572fa3b5cfc9f9cb3153813e2020000000000000000000000", .Okay}, + {.Shl, "74618b46ef3827013928e9e7eec321", "4d", "e8c3168dde704e027251d3cfdd86420000000000000000000", .Okay}, + {.Shl, "-1d01b3679444c49f80714aaf950b0a", "35", "-3a0366cf2889893f00e2955f2a16140000000000000", .Okay}, + {.Shl, "fb592627d64f0ef6899f8eadb7d31c", "4a", "3ed64989f593c3bda267e3ab6df4c70000000000000000000", .Okay}, + {.Shl, "-16cd3bbfd8116215c98f5f5b2321c9", "56", "-5b34eeff60458857263d7d6c8c8724000000000000000000000", .Okay}, + {.Shl, "-2372c4d05c394a1d388c80d4bcdc31", "1c", "-2372c4d05c394a1d388c80d4bcdc310000000", .Okay}, + {.Shl, "-82b806ec5dcf2e40086758419b574b", "18", "-82b806ec5dcf2e40086758419b574b000000", .Okay}, + {.Shl, "-b2001ee46f7a02309d77188809fd64", "17", "-59000f7237bd01184ebb8c4404feb2000000", .Okay}, + {.Shl, "d5a1b04966a6a032d3029fffb7f61e", "35", "1ab436092cd4d4065a6053fff6fec3c0000000000000", .Okay}, + {.Shl, "-9db1b796cff0efab2611fec89fb671", "5a", "-276c6de5b3fc3beac9847fb227ed9c40000000000000000000000", .Okay}, + {.Shl, "-f4fc439a0b43f15b82f6a70678e837", "10", "-f4fc439a0b43f15b82f6a70678e8370000", .Okay}, + {.Shl, "-a593b6c4d7051e50cacc5d102bb78f", "2d", "-14b276d89ae0a3ca19598ba20576f1e00000000000", .Okay}, + {.Shl, "-10328ca66a7d7830d20554fd8b3e57", "65", "-2065194cd4faf061a40aa9fb167cae0000000000000000000000000", .Okay}, + {.Shl, "-636a47aa3c0b7f6a1966512c843197", "15", "-c6d48f547816fed432cca25908632e00000", .Okay}, + {.Shl, "508d5929a86191f196509f54510661", "45", "a11ab25350c323e32ca13ea8a20cc200000000000000000", .Okay}, + {.Shl, "-33a5dc7ec7462562b32bb728ce6463", "13", "-19d2ee3f63a312b15995db9467323180000", .Okay}, + {.Shl, "-21bcfdadf613fce63e02967b582b64", "29", "-4379fb5bec27f9cc7c052cf6b056c80000000000", .Okay}, + {.Shl, "-b9695ab458487ebe9f67b8d804dcd0", "3b", "-5cb4ad5a2c243f5f4fb3dc6c026e68000000000000000", .Okay}, + {.Shl, "-87848efbc5f608a7579459c74550cc", "65", "-10f091df78bec114eaf28b38e8aa1980000000000000000000000000", .Okay}, + {.Shl, "-c456a0a074644f0f77962d104873cc", "1d", "-188ad4140e8c89e1eef2c5a2090e7980000000", .Okay}, + {.Shl, "-57632b4719085f32fab22e65795d60", "6b", "-2bb195a38c842f997d591732bcaeb0000000000000000000000000000", .Okay}, + {.Shl, "5af676fe65b250cf70589aa549cee3", "10", "5af676fe65b250cf70589aa549cee30000", .Okay}, + {.Shl, "4e24c612eb533fcecc515b53779a65", "22", "13893184bad4cff3b31456d4dde699400000000", .Okay}, + {.Shl, "4d628d616b733db8bc28563c3081da", "49", "9ac51ac2d6e67b717850ac786103b4000000000000000000", .Okay}, + {.Shl, "-e080cae50f00d7cfa30fb6da05a1da", "26", "-382032b943c035f3e8c3edb68168768000000000", .Okay}, + {.Shl, "9aca0d83271160de30418081df4084", "5", "135941b064e22c1bc60830103be81080", .Okay}, + {.Shl, "-247b2aec569d1449c0ceb2b7cb3ba6", "2e", "-91ecabb15a745127033acadf2cee9800000000000", .Okay}, + {.Shl, "-8f6586935566a2b9d065d2488a2cbf", "6c", "-8f6586935566a2b9d065d2488a2cbf000000000000000000000000000", .Okay}, + {.Shl, "89e6658a4d5ffe74917b51e107983f", "6f", "44f332c526afff3a48bda8f083cc1f8000000000000000000000000000", .Okay}, + {.Shl, "f053afb82928e9b1c0deeba4b01398", "70", "f053afb82928e9b1c0deeba4b013980000000000000000000000000000", .Okay}, + {.Shl, "9b3c28c07885a3cd6d3677aee77533", "5c", "9b3c28c07885a3cd6d3677aee7753300000000000000000000000", .Okay}, + {.Shl, "64f9333ac7d6605b4befee8da5184d", "14", "64f9333ac7d6605b4befee8da5184d00000", .Okay}, + {.Shl, "-a5052ce72ba9f201f3d05adc32666e", "b", "-5282967395d4f900f9e82d6e193337000", .Okay}, + {.Shl, "-abe5a5940f6341e6446857f10e65e9", "1b", "-55f2d2ca07b1a0f322342bf88732f48000000", .Okay}, + {.Shl, "-855064e0e247a0065f68e702edffc5", "45", "-10aa0c9c1c48f400cbed1ce05dbff8a00000000000000000", .Okay}, + {.Shl, "41c885d8586156b2f92d8cc6094f63", "29", "83910bb0b0c2ad65f25b198c129ec60000000000", .Okay}, + {.Shl, "-27f8b8a4de04b5d60cd1420ae15da2", "53", "-13fc5c526f025aeb0668a10570aed1000000000000000000000", .Okay}, + {.Shl, "a9d50a5148ecdc33ff283f8dbc4a31", "49", "153aa14a291d9b867fe507f1b789462000000000000000000", .Okay}, + {.Shl, "-7b5eed436d567cac26e6b5b1506b39", "59", "-f6bdda86daacf9584dcd6b62a0d6720000000000000000000000", .Okay}, + {.Shr_Signed, "f505a74110c962cf7b56b75335cb51", "3c", "f505a74110c962c", .Okay}, + {.Shr_Signed, "4851199e761aa96b72973d6b3ff0c1", "3e", "121446679d86aa5", .Okay}, + {.Shr_Signed, "-8fd2c7f5fb1aea06df586c491bde12", "4c", "-8fd2c7f5fb2", .Okay}, + {.Shr_Signed, "6507b0c2c98556e4e6048bd0fdfb7e", "e", "1941ec30b26155b9398122f43f7", .Okay}, + {.Shr_Signed, "243db5b47f31737b9e97e59f464ec1", "59", "121edada", .Okay}, + {.Shr_Signed, "4ffd272fb7253b7dafd6a18836064", "2a", "13ff49cbedc94edf6bf", .Okay}, + {.Shr_Signed, "-b474c729be9282346dfd22cf41b3f1", "5f", "-168e98f", .Okay}, + {.Shr_Signed, "a900b420f50a75ea2c893aa3aea05e", "44", "a900b420f50a7", .Okay}, + {.Shr_Signed, "b0524c91330420ecfd58873de19f0e", "6b", "160a", .Okay}, + {.Shr_Signed, "e99b440cc6414dbddc96d824183ed9", "31", "74cda2066320a6deee", .Okay}, + {.Shr_Signed, "80f1d6caaae98caa26bd2e301ca8bd", "6c", "80f", .Okay}, + {.Shr_Signed, "-ee920f7c84371690107fe2bd5ead6b", "71", "-78", .Okay}, + {.Shr_Signed, "13518b580b07f70e435577340cdbb6", "1b", "26a316b0160fee1c86aaee6", .Okay}, + {.Shr_Signed, "-9990b504a6ab3395a261d903e2bf71", "a", "-26642d4129aacce568987640f8b0", .Okay}, + {.Shr_Signed, "-7b396462fdebd4f301ba56cec2dc4", "78", "-1", .Okay}, + {.Shr_Signed, "-188f7ab283b57560e1e3ff9a41bdd8", "3e", "-623deaca0ed5d6", .Okay}, + {.Shr_Signed, "5410ab901a612cf84a9de47360b096", "6a", "1504", .Okay}, + {.Shr_Signed, "-ad87b77c53de7af48707ddd1afb04", "1", "-56c3dbbe29ef3d7a4383eee8d7d82", .Okay}, + {.Shr_Signed, "-ff4d3c26efd1cea754d892e56273bd", "3f", "-1fe9a784ddfa39e", .Okay}, + {.Shr_Signed, "-ffcd163a5ca59813aaa571a60006df", "3f", "-1ff9a2c74b94b31", .Okay}, + {.Shr_Signed, "c447786dace008544af6391f075260", "18", "c447786dace008544af6391f", .Okay}, + {.Shr_Signed, "8523557ac99a3e4ab203bf431fc8f9", "5d", "4291aab", .Okay}, + {.Shr_Signed, "ac278b96516cfcb52199d268779740", "37", "1584f172ca2d9f96a", .Okay}, + {.Shr_Signed, "f264e9661ef1b10ca8eda6a0e76810", "4b", "1e4c9d2cc3de", .Okay}, + {.Shr_Signed, "-917a7fcabb5cc8a27bdc445e7e6c03", "6", "-245e9ff2aed732289ef711179f9b1", .Okay}, + {.Shr_Signed, "995bd6c7b52f8a1237b623a2f7e6a5", "70", "99", .Okay}, + {.Shr_Signed, "-d9f8fdff4545c7368e20625b70001e", "3d", "-6cfc7effa2a2e3a", .Okay}, + {.Shr_Signed, "-dc01543982540e7decfa7faf245a65", "18", "-dc01543982540e7decfa7fb0", .Okay}, + {.Shr_Signed, "-1bb065907020b0d8c6af798490a5da", "6a", "-6ed", .Okay}, + {.Shr_Signed, "-df1b32415d5d017e58143442a683b5", "0", "-df1b32415d5d017e58143442a683b5", .Okay}, + {.Shr_Signed, "931dd9d87ae49ee72925a6e734f9d5", "4a", "24c776761eb9", .Okay}, + {.Shr_Signed, "cd780f4cd054a2962f3a3081aa5c53", "12", "335e03d3341528a58bce8c206a", .Okay}, + {.Shr_Signed, "-d85572c8fa834ca54e757b4746f81a", "21", "-6c2ab9647d41a652a73abe", .Okay}, + {.Shr_Signed, "e5758ceda2c303c267178cea759dff", "76", "3", .Okay}, + {.Shr_Signed, "-c9a365248e680fd9fe9596f613c2c0", "2e", "-3268d949239a03f67fb", .Okay}, + {.Shr_Signed, "-b7865656974ad1bc68ebac7766a1d3", "28", "-b7865656974ad1bc68ec", .Okay}, + {.Shr_Signed, "38186df888ed244e7571c30a6b1a6b", "51", "1c0c36fc44", .Okay}, + {.Shr_Signed, "613aa19e40ce5f51d5b0024c87d1d", "71", "3", .Okay}, + {.Shr_Signed, "a3b6542301fae9754a9d1e24ed88af", "2a", "28ed9508c07eba5d52a7", .Okay}, + {.Shr_Signed, "-1bb55b6f87c385d6352dc8f41ff99f", "55", "-ddaadb7d", .Okay}, + {.Shr_Signed, "-3093a78469c4b5b528ec784d6b3d18", "4", "-3093a78469c4b5b528ec784d6b3d2", .Okay}, + {.Shr_Signed, "cee91938fb5537ea2b7bbe6edd3eb0", "73", "19", .Okay}, + {.Shr_Signed, "-943cdb7c7a33c52bc9a6a65bacc6f1", "78", "-1", .Okay}, + {.Shr_Signed, "8b7880a8577a851d3375deca364335", "9", "45bc40542bbd428e99baef651b21", .Okay}, + {.Shr_Signed, "-188a684c20d96c816effdaa3708576", "22", "-6229a1308365b205bbff7", .Okay}, + {.Shr_Signed, "e2d76eaa2d351c33b23b21e9df7f50", "e", "38b5dbaa8b4d470cec8ec87a77d", .Okay}, + {.Shr_Signed, "61cd20dfdc10c190aef91627749ba4", "53", "c39a41bfb", .Okay}, + {.Shr_Signed, "724ea6e5c18e23fab7c6db4f15a620", "1f", "e49d4dcb831c47f56f8db6", .Okay}, + {.Shr_Signed, "-b797764a1b99d703ca96e1ac79d0df", "16", "-2de5dd9286e675c0f2a5b86b2", .Okay}, + {.Shr_Signed, "-6aafdd33ed0dc8518409eeda9bc1fb", "7", "-d55fba67da1b90a30813ddb53784", .Okay}, + {.Shr_Signed, "91f20f0c86fab55530f07239f9d02c", "75", "4", .Okay}, + {.Shr_Signed, "-e252360e796ed727062996e2d11f1a", "39", "-71291b073cb76b94", .Okay}, + {.Shr_Signed, "c1e3ebe78066b7980932d7b8cc132b", "42", "3078faf9e019ad", .Okay}, + {.Shr_Signed, "f69ac1092893d804a06bbd212a2a6b", "72", "3d", .Okay}, + {.Shr_Signed, "6e81a8337c70755772f0e3949cf9a4", "61", "3740d4", .Okay}, + {.Shr_Signed, "aaeb77fb8862c0ac6abccf46544c11", "3a", "2abaddfee218b02b", .Okay}, + {.Shr_Signed, "2ab104f087c35cfbad828d429b5645", "47", "556209e10f86", .Okay}, + {.Shr_Signed, "-5f3b4235d84aa3449fd542ee7b5448", "c", "-5f3b4235d84aa3449fd542ee7b6", .Okay}, + {.Shr_Signed, "-1d7a5737f0d5b6c659d7de8e48f6a4", "5d", "-ebd2ba", .Okay}, + {.Shr_Signed, "bfd6cf330eca8c286e5ddb9979e422", "5e", "2ff5b3c", .Okay}, + {.Shr_Signed, "1e7bed8f118e42b80b185e4a43479e", "42", "79efb63c46390", .Okay}, + {.Shr_Signed, "-eda1c10db1c3d20ed3ccbe5073b174", "65", "-76d0f", .Okay}, + {.Shr_Signed, "-813852d42d6156b667ecc5fb76486e", "74", "-9", .Okay}, + {.Shr_Signed, "3cc47d3e7bd2d845266bb431d59e30", "68", "3cc4", .Okay}, + {.Shr_Signed, "-b557e9f5baa60645541863b6838b9", "46", "-2d55fa7d6eaa", .Okay}, + {.Shr_Signed, "2dad05cedfa197a7e80602bb4d6523", "1f", "5b5a0b9dbf432f4fd00c05", .Okay}, + {.Shr_Signed, "44bc2a21d351e1e57f5d5beb400424", "60", "44bc2a", .Okay}, + {.Shr_Signed, "-911167d451df8e3bf5f106a5c2109a", "44", "-911167d451df9", .Okay}, + {.Shr_Signed, "-2e4b89b7cef88c3ff79683a9d773a", "59", "-1725c4e", .Okay}, + {.Shr_Signed, "-5aead6eb00db1009a88f20aeab851e", "48", "-5aead6eb00dc", .Okay}, + {.Shr_Signed, "-4ca6b848bfd975e9a47946d3a8c0a8", "76", "-2", .Okay}, + {.Shr_Signed, "d15699410818a32940e3bc484e0d07", "15", "68ab4ca0840c5194a071de242", .Okay}, + {.Shr_Signed, "-ad118f38d1d39c88be50c65761af69", "51", "-5688c79c69", .Okay}, + {.Shr_Signed, "3935dc66ea50694532d66f656e0e84", "3c", "3935dc66ea50694", .Okay}, + {.Shr_Signed, "-f20a74ce7836276118f8bd25cfc598", "2e", "-3c829d339e0d89d8464", .Okay}, + {.Shr_Signed, "7ff8c319a6ee6fa15d95d980ea325f", "65", "3ffc6", .Okay}, + {.Shr_Signed, "-a127d639b643aa9fdf662ed8d423c2", "9", "-5093eb1cdb21d54fefb3176c6a12", .Okay}, + {.Shr_Signed, "cf75f41b2395138bdbc3dffe1ad870", "61", "67bafa", .Okay}, + {.Shr_Signed, "-e25fb42c533dbbe15560e764fd5e8d", "5e", "-3897ed1", .Okay}, + {.Shr_Signed, "-b79c5224b07cf3da60331ef12fa4b5", "47", "-16f38a44960fa", .Okay}, + {.Shr_Signed, "9ff7848afe362c320fa75cdb760e27", "54", "9ff7848af", .Okay}, + {.Shr_Signed, "6853d26bc29f2145b85a05499093f", "31", "3429e935e14f90a2d", .Okay}, + {.Shr_Signed, "4bf09639b556660ff7a56707cc5557", "1e", "12fc258e6d559983fde959c", .Okay}, + {.Shr_Signed, "fc89fe25139751e80b1192cb3fc94", "53", "1f913fc4a", .Okay}, + {.Shr_Signed, "fb9e2faf97606c822ca65a81e5e4c3", "37", "1f73c5f5f2ec0d904", .Okay}, + {.Shr_Signed, "-fabedc7f33180ade07ed5ba438e175", "44", "-fabedc7f33181", .Okay}, + {.Shr_Signed, "-f4607949c424de1c173d39604cd1f8", "13", "-1e8c0f2938849bc382e7a72c0a", .Okay}, + {.Shr_Signed, "d2cd7805a291a96c3d5311fbbb4a7a", "48", "d2cd7805a291", .Okay}, + {.Shr_Signed, "4c44d6eb617ba09d5db2d428e6fe5a", "54", "4c44d6eb6", .Okay}, + {.Shr_Signed, "b9362fea06abe02a863ec54cc4a092", "e", "2e4d8bfa81aaf80aa18fb153312", .Okay}, + {.Shr_Signed, "-77b831009229e412861bcbda19775d", "63", "-ef707", .Okay}, + {.Shr_Signed, "76872f45874f717552b85c9726525", "1f", "ed0e5e8b0e9ee2eaa570b", .Okay}, + {.Shr_Signed, "-7ab1f10606483ebb2d314dde778cad", "60", "-7ab1f2", .Okay}, + {.Shr_Signed, "-e0047609aa7c793b194e173ad7d89", "3", "-1c008ec1354f8f276329c2e75afb2", .Okay}, + {.Shr_Signed, "-9fff37c79a2a8d8e97cefe8e8baf2e", "62", "-27ffce", .Okay}, + {.Shr_Signed, "874f29f822671e78612adef74c6b13", "6", "21d3ca7e0899c79e184ab7bdd31ac", .Okay}, + {.Shr_Signed, "74d3eff7aafd124da395a9fa7343d4", "3f", "e9a7dfef55fa24", .Okay}, + {.Shr_Signed, "-18210572b61d9fc4ad8eab130aba1d", "3", "-30420ae56c3b3f895b1d562615744", .Okay}, + {.Shr_Signed, "-56d0a199ff8af06e9196e936531394", "65", "-2b686", .Okay}, + {.Shr_Signed, "-126aa9639bcc77a94dd2f4e311fe3b", "1", "-93554b1cde63bd4a6e97a7188ff1e", .Okay}, + {.Gcd, "8fff185f6107d80881ff3363ef088d", "5371c850e6a36895f5c5d610a9db7c", "1", .Okay}, + {.Gcd, "-9acba82db6cd4a903b19679adcdcd3", "ef98270815e36957d9a046654ab7fe", "1", .Okay}, + {.Gcd, "-ffa4c58748eaeb76ba4cc598e07edc", "4c21bba4a4f89c359e56ab3a2a0bbb", "1", .Okay}, + {.Gcd, "8c3237e5f62d84dc89f9b095d77887", "3a0f690410b436c3fa3bc746260d0e", "1", .Okay}, + {.Gcd, "-4cf58721af510a2de14716c6f86450", "23eb39998a18f6a68d78fec8d43ef9", "1", .Okay}, + {.Gcd, "58c9e3d62b1c29115545ffd48474a4", "70374665c43668c65c22ffc494c159", "1", .Okay}, + {.Gcd, "cfb27c85faf89c538b831c6e1b3c21", "ea5a66ad684b3fb311b430fe650b3d", "1", .Okay}, + {.Gcd, "-5cee8770e63d97626fde1b3eddd466", "f0c6eed1552f27a86d596737c5218f", "1", .Okay}, + {.Gcd, "-dd451d361443d6c21787018b075234", "59062f7f888cb7af697ebb942e989c", "4", .Okay}, + {.Gcd, "79b1171a84e2d40b488b5917054a2c", "754cde4a9196b9c1c923eb0f158b35", "1", .Okay}, + {.Gcd, "-81ed095a0d8c99dab75edba285d79", "f630c098bf168b0620009fe3118228", "1", .Okay}, + {.Gcd, "-b0d592ba341ec9c92e7dbedd624a71", "dfb4ab3b8f0f45ba01e516c16f2cf1", "1", .Okay}, + {.Gcd, "-cd0ddb13a997b700ef45a4f3328920", "287677f46e212cdbb0e783d7532cf8", "18", .Okay}, + {.Gcd, "-c75632758cfa10de39779d7d023dbc", "4e7a7a3e793f6387d7332a8d0f36c4", "4", .Okay}, + {.Gcd, "807db04912cd9211518f877e0f1245", "993c9edd89480cc85e8050f5e2cecc", "1", .Okay}, + {.Gcd, "-a20bac5407d78a789fba2d4dfcf238", "721bbe9a756196b077adfc49c00446", "6", .Okay}, + {.Gcd, "-1a1a72ba37882b0d45d52d3c83e93b", "b5dc6d94ff76803daa9064f48254e0", "1", .Okay}, + {.Gcd, "-1170b57406809fee6642e0c1fb1afc", "77463f38b4d9c7cc65e9eb7f3695a9", "1", .Okay}, + {.Gcd, "-7832b08d05a3e46d7d4db79dcece43", "63b1045c955f391be8ddafd45a647e", "1", .Okay}, + {.Gcd, "679a79d2d1c275ea401cc916d516f1", "ec7ebdefe590317c41ba0c8e4c31c4", "1", .Okay}, + {.Gcd, "7d40599f86e41c74d78da6d740c5c", "f10cfb2bd8ce167f7ade361eb985c3", "1", .Okay}, + {.Gcd, "24e99808df24240a575b426407e258", "81a235608b5b719e43687958b05697", "1", .Okay}, + {.Gcd, "-8ec64c42c82e842f6e5b9cf4a4534e", "65505aabdbe46126ccdeae7fb9c770", "42", .Okay}, + {.Gcd, "28412d3e42806215afc23bc3f17e1", "27153011d37f4287f5c1cb0f9c1b8b", "1", .Okay}, + {.Gcd, "-bf54738920158140f0b432a0c3fdf0", "490727eb7b1a573e550c16c62eb0d0", "10", .Okay}, + {.Gcd, "97cd608287346c0d2bd688b49ce5cc", "90787853b6fdbc8161a65a6ba3a417", "1", .Okay}, + {.Gcd, "-f32ea8adc2139e7e36a2b49fc5eebf", "b90f8edcd61c10aec27f1720ffc4f1", "1", .Okay}, + {.Gcd, "f4ef41bbda6dd3c87027418bde074", "2b5a8b0684e2a387bcf316968658dc", "4", .Okay}, + {.Gcd, "-dd4dc8c6af5a57c572ac60f9544e5e", "5b58f200eb271e3319c220ba408c48", "2", .Okay}, + {.Gcd, "-199872febf7c89c3d9964fa579c45d", "170d208d0b1129c9c702a1d43a3ba", "1", .Okay}, + {.Gcd, "-2e3f9977cbcaa5733a961d51941c74", "d408c476d7c1d2d9bce208d4d985d5", "1", .Okay}, + {.Gcd, "-cdd3d857726af67237e9063890cc1b", "cec4456b4b1bb36ec7268904ecf2dc", "1", .Okay}, + {.Gcd, "-b75304ce57f6d3531505d26d00b782", "d278f3c0ac85fa26607c37bf992434", "2", .Okay}, + {.Gcd, "-534ff7eefaeb10877c78c5ad128377", "4a690bcea60798800026f8b9b55032", "d", .Okay}, + {.Gcd, "8c5ca76a1a3cb6bcd4811e0533f01d", "7d6cbebd45dff0ce2bf3dc6391cc3b", "1", .Okay}, + {.Gcd, "d05cc2b5639c740cf9241244cdfde8", "ace1a1fec830d6dba80d7270da6f7d", "1", .Okay}, + {.Gcd, "-c4bbcb45dd163fc8367b7eb9a0e3ed", "6752a4bc501d744f0df0b439461418", "1", .Okay}, + {.Gcd, "-e4816abad8651f00f264efdeee05c8", "97638db5ab0b5cff1869930e5961a3", "1", .Okay}, + {.Gcd, "-2ba5d511557eb142c220d190cef594", "5c7504e016abb9439c9c7822831ae2", "6", .Okay}, + {.Gcd, "bdc9610c5bf313f42979f904787fd6", "2983c41788ab37fa455a829ccbd393", "1", .Okay}, + {.Gcd, "7d7901fa8e74e75d80faf0c12ed9fd", "3354ff9dd960527f71209362bd3410", "3", .Okay}, + {.Gcd, "-aa384b6fb616a72cfc7e8755de373", "acc168d1ead5da29a0c70cbab41648", "5", .Okay}, + {.Gcd, "-82780bee2308594f88fc196c2f601f", "aafea75aeceb38f597f92f1d1b1889", "1", .Okay}, + {.Gcd, "c48489fe0cf469b770d7efb79ab333", "68d6cfdf8a0c39861590e7cde260e2", "1", .Okay}, + {.Gcd, "-b626981d540fa942b1d5b09cdcf9f2", "783e356236414870871f1d6b297a53", "1", .Okay}, + {.Gcd, "84a230dd4cce490040ed8028b9c5fb", "dbc3b6e1c8722c0800db55f215c540", "5", .Okay}, + {.Gcd, "-6d8a2c582d9b9c78826f2c0295183e", "9a8353fa4069b804c160f2dd81dd35", "3", .Okay}, + {.Gcd, "2eceea848654cebaf2c3532ee33eee", "754c1bc016df2b55728859dbe55f13", "1", .Okay}, + {.Gcd, "-f47af7c2b5e7d3016b33c1308c7267", "7b22d0faae3e007cb0a08140ca85c", "3", .Okay}, + {.Gcd, "-d95deaf3069dce7d3210b8bb39164a", "699104954b690bf5b37f80ebaf4095", "1", .Okay}, + {.Gcd, "1dced0c0adebd6e40899d393f0d1b9", "231746312e77b56885a48f5c7587ea", "1", .Okay}, + {.Gcd, "-1b55a6de342fc38f0ebd5a4ce26f40", "b224585169743f3b8138c6a60201ee", "2", .Okay}, + {.Gcd, "5fc42aa5d99e797add7f1e3c6a827f", "d178159dcc505db5b4d3ee98a27681", "1", .Okay}, + {.Gcd, "6d7caaa59766746628fecfe5ef11b0", "3e3af45e3471c711f736b3e80fe96d", "1", .Okay}, + {.Gcd, "5d0ebc5cf857f008f5346abe2bfb5", "62950fddb1b24c2017f32973fb29d5", "1", .Okay}, + {.Gcd, "-7a4936de4435fdb989f98d8c834e3a", "b4f4bc20511b730891d41b3c78bc4", "2", .Okay}, + {.Gcd, "6ce419c3ba5bee4fec1e2375bff1f4", "af4347ba9e307e98402a05295cfe37", "3", .Okay}, + {.Gcd, "ddf9a56ab36f4ff13026cb8e04ba7d", "a609e1111e074708b1f8572cadd44d", "3", .Okay}, + {.Gcd, "-9044df5cb6a3ed1c232732c7166302", "decbc1dc6b2372c72c94b7f4ab4dcf", "1", .Okay}, + {.Gcd, "602b182bd0181086856a91ef0cf2ed", "f0c1a77d8126abcfaeeec493f8a493", "1", .Okay}, + {.Gcd, "-3803d07c8f8fbd9a01d1640e022fbe", "e897a1368f6a09017175fe2efdfe2e", "2", .Okay}, + {.Gcd, "3b28caec5c52ae7e72f7d0effb2fdd", "67c8e2d766b144544ab04fcc15a5e", "1", .Okay}, + {.Gcd, "2e2c92823cd7afcf5355b8f4feddd", "804d7d72204534eac3df0e6222201d", "1", .Okay}, + {.Gcd, "-6cfae5008c0283168ce19a27c3440c", "a5b9bb2b6792c8f5cfb4e74db41ddf", "1", .Okay}, + {.Gcd, "af1ca49fb0e36f2109d83cb3a66ab5", "8579f32e9386ce39e2624705cd96f9", "1", .Okay}, + {.Gcd, "-4bc5915bc75c840626e8861636a44e", "353d5376d1f11f8fac99f2a5c25610", "2", .Okay}, + {.Gcd, "d744608b698478f74774517833b9b4", "566d3f9e729b0fb6656758c5ef23e4", "4", .Okay}, + {.Gcd, "29431bd9736f166e47082babc83dd8", "c77c4a14396f9f59e4f2b26fb09f5e", "2", .Okay}, + {.Gcd, "257529ca95ad3acc048cbea5782d64", "d2df3c7055f51aca346588fc56535d", "1", .Okay}, + {.Gcd, "-97950ade4fa835f7515243c7910b92", "a74b9953949f898a8c530ccefdf9b8", "2", .Okay}, + {.Gcd, "2b218cf429d534930bb0cf227ccd21", "a5534482723abc574fa731cd5e2c62", "1", .Okay}, + {.Gcd, "b0ec89f5d1f31fa28469777e6506ad", "d103f321040f7158a0a883534db44c", "1", .Okay}, + {.Gcd, "f666f06656d0731684705acd290746", "14a4925a6ea0182c8aa562555c2ea", "2", .Okay}, + {.Gcd, "9123848874f3b40fa1af3ce2bd7461", "2eccf53149bfdacf9230064438c27a", "1", .Okay}, + {.Gcd, "-df29a0ee74ca389c23c8d89d393c5e", "400e5acc9972660e4d48af01901543", "1", .Okay}, + {.Gcd, "10d54577ec9eb1e60e26f5cbe7f206", "bd1125e7cc92fcac0172b8ac9a4c6f", "1", .Okay}, + {.Gcd, "d6e858d998125cc94766c6d768df8c", "850c33954b7ebb5441bac7a9992859", "1", .Okay}, + {.Gcd, "c4cd3c88f617308cfc33a8c784561d", "ec66a37fe0a9da0d35633f97716a55", "1", .Okay}, + {.Gcd, "e650b984babd887084fb614b654067", "13712f7c5e98032650f0539e8351ee", "1", .Okay}, + {.Gcd, "-7e5c3b6d268a95ad3fc99fe8e1ad71", "d7bc1bb0b65e20d0f8bf2c986a020d", "1", .Okay}, + {.Gcd, "e04e63ffe3a0f4c1f606649f2798d7", "c6e35f19291e1ef8bd087213c9c25a", "1", .Okay}, + {.Gcd, "-1059d76aa4bd4ba59c5682dc0ada53", "fe6c28d5a13bebea29cca5770d539f", "1", .Okay}, + {.Gcd, "33ad8328efaccfc9db78ff693a14aa", "15cdd2e82f4e5b323fe9fe995fdf80", "2", .Okay}, + {.Gcd, "496a3672028205426ddae004b546ff", "d452a8f8bad06826d0ffd80afa550a", "3", .Okay}, + {.Gcd, "-68a3dd5fdf10663f268d4318062b1e", "a3e02abf776053a872f37eade7ff6c", "2", .Okay}, + {.Gcd, "-b95e8352367e477bdfe45b6d7b59c6", "6c175f9331affd06d843c7385120ac", "e", .Okay}, + {.Gcd, "27d43b0a5aa44da3b6002437e0257f", "3945033458244162bec43ead843c00", "1", .Okay}, + {.Gcd, "-73d4a90bbe33f2279f9945a554499e", "c13524c80ec69aea10bd7e9c555496", "2", .Okay}, + {.Gcd, "-695a8efba3e403a3c37bd78dc5c2e3", "20f8a05bcedf6b68f65f86e1d5a423", "1", .Okay}, + {.Gcd, "cb2249c6c7f6ac3b850838966fe392", "304465288fdb70cf3acde9fd752da2", "2", .Okay}, + {.Gcd, "bb2716aca4b0f71f81845cc3a57e82", "c9dceb3715d23766c0fec6bdde3960", "6", .Okay}, + {.Gcd, "d736eed3b6a31f7142b65cd4a49187", "45d986048d564f093cc3262c997d1", "1", .Okay}, + {.Gcd, "-7d5c01bff51874f85fed3e82e5988e", "f2f955ffce82e7e967a03e95bae6c3", "1", .Okay}, + {.Gcd, "b5d52913a1022662df85af07d1f65e", "312a995b3a30381e3e74be43611c78", "2", .Okay}, + {.Gcd, "4c8a89e780fbbc23bc71092299b68b", "a2f1afe4c48c5b7ecada9d05fce2b6", "1", .Okay}, + {.Gcd, "a70b96df3f876b3f3070d7b3dc80e4", "fbec75055b71dafacbc4582e1de4c", "4", .Okay}, + {.Gcd, "-3eb89d15c5beb79c7d8ab455ddf9ae", "60b3b80189f7089920d1642a2acc24", "2", .Okay}, + {.Gcd, "-ba4215cbdbba9eab09681e10acc358", "7e306f1f360e28b63408f978aefd00", "8", .Okay}, + {.Gcd, "cf7db37e850efef5a937ca0758c6fc", "91ec27caf6e3b4f99841363a4defa4", "4", .Okay}, + {.Gcd, "6e993447fad6138d69125cadcd5128", "fcef1427fc0c97bb23abe343c4d573", "1", .Okay}, + {.Lcm, "-330184adbbafb54d09634c8b077bdf", "ba7a01c6b710ab086b6faf63d6c565", "2527697a0e53cf95663e8ffed8c47edec517f491f59f40e68fc965b079fb", .Okay}, + {.Lcm, "-3f90fbe8db7fe9a27b95dea402cfc5", "-2915cf0d7521ef62d8531610f83290", "a33a2a68865427b8f43ee7fa217d7fa1458873b9a615c8b92e8650158d0", .Okay}, + {.Lcm, "dd3772aac4b58eeb0338659b1b1304", "-adca2d783ccfb18943c0c0c133ba82", "4b1696c443b012cbb3c409e00b66d7f3093c6a66200622b384829eae4804", .Okay}, + {.Lcm, "ed2f0e6bde667f6e6ff61de8ab784", "-48c00c40cb3f41e8cc1790935f2676", "21b39559b2199b17e11b83031588e152ff65fd8bd2cc918c8a00895176c", .Okay}, + {.Lcm, "22ab1f0c25e72e3e407c5d63ad6975", "316b3637044b9110581ecb4e8ab43b", "6b145ced93a3b5893265ac52d2765914b9db72aac4a1c1b3aff662f91f7", .Okay}, + {.Lcm, "de956b68f2806389a964cd51658259", "ca864b63cb80e139e2381a0008dcc3", "b016aa8393791115b2a9ee60dab7ae5049ec2ac34feef1777a8e4f1ec5cb", .Okay}, + {.Lcm, "2a092f45b7c2fa6b4d20f0c5adc0b7", "c74e66d05d11dc8dd977352d632343", "20ba036d78ab02ee5a9fab6c9f9624982a24824d174188397dff2f9774e5", .Okay}, + {.Lcm, "-3816677d5e16adfc4dc82781887a82", "-f3b1449de3999ebb0f5c058e0166d1", "35641ac21915dfa4575c4717a862ab98e6b3c596a9f0629077e3b7bdd022", .Okay}, + {.Lcm, "591337790d66ee4e6990831c4c037d", "-7f44b8f4095e0b8c961af1e99dbc5b", "2c4871fa833fe69952a0f09e4cfa344f4a93332a52af1df82bdaca3e096f", .Okay}, + {.Lcm, "-bc8e6c5343fbd659f567af16983a84", "-e0054651892d3ab50c4860e5eca257", "a500815bf8d542a87e16198d43023a7814a99754f52e6e5d1afb08736adc", .Okay}, + {.Lcm, "-5a2871f6ebcace46bdbd21774a5b07", "-a70981fea8f119a94b263571b325ad", "c394b8ad6240f75e9200453637478dc1bd57eaa1f9400f311588a3e727", .Okay}, + {.Lcm, "-34d3ab54942396cf8798b0200f8f9a", "-fe3683b6ca2cc5ae6ae886e314a0a0", "1a3aa1e90bd973b827fe9c0b18339e326a9dc56fa7dfc935452344c10020", .Okay}, + {.Lcm, "54127a249bef69c28b67774f3597f2", "74d6dab381744268da639174d611c8", "66527c4e5737c076905f88314876a8a676cdcc646a783eefbdd84e04bd8", .Okay}, + {.Lcm, "-2ebceedac57779fa1b18166bd03f90", "-aacf0368c2e668a656f79f8d8f512e", "f97a100e094ecd3ebe7e3676de2dc0931ab31c25e89f7b861750a7bfdf0", .Okay}, + {.Lcm, "-86430be2b1b1e5350ad12bfa406ecd", "11b920cfcca1d41680976dcda6db81", "94b8b7301a4792986c2e1900fa844a5073a4ab5203a6897fd093b2f344d", .Okay}, + {.Lcm, "8f4fe2fa409ffb60cf8438b576853f", "-6e1af14199b6608b74792c98fc9994", "3da368b383325e231a8088659ab74cc6b06d681f1a299c7502d9502baf6c", .Okay}, + {.Lcm, "-73b554777c40793c1156cc5fb365df", "-b8266bc4be938502b154908beeeb15", "be3f4e7bbc26101faaba1888f229644bd991ce29c0e0df0f0bc54ef949d", .Okay}, + {.Lcm, "-d3669fe660c1c45d6427b07ab0557e", "-b00597d384d6711a7aa7487b671f9f", "915b2c4fb59dc85fb3f8f27e4855e23e16510b548da3f86058ed7d915b42", .Okay}, + {.Lcm, "-dc0f946365f84cf59d001cc07dadb", "-c5748dda18bc0cd4ccd0d6075c42dd", "a9bc2e2fc9c47fec6b6aae58a9fc9a29a697b10311da8497507cce8650f", .Okay}, + {.Lcm, "-6770b7031960e7669f3570096fd33f", "8d4cf21ef996f349b1d8c713fad04f", "39182c181af5e8edd07a9a0180f7e7d65db4b75cdda43c626718bdab6071", .Okay}, + {.Lcm, "-20c93a9162317828ae93d2274bc2de", "432f18a81ebc67e65e3ee67e6832a9", "89ab26e32dfc0174c965f7ff925fc5c2900480b367d199cb98d2b43008e", .Okay}, + {.Lcm, "64e3cfa428b8ec87e7c0ccdf914339", "381a8886764284bfa86d4bf9c593de", "161c4a5d03bdb4d7817499091eeef82d865487735a1c8f6121e8756f066e", .Okay}, + {.Lcm, "46a2297aa7b80f105f4cc59dbf1b9c", "-debf057271690a8a5c8f5febd6b56c", "231e79680827876fa5bb460a19e8382dab5aa7b1c819d0822acb6699aec", .Okay}, + {.Lcm, "3bb7ae73b820bd1033c7e77de89d91", "-bc5ffee65afcb8d56c2d248557a8f0", "2bf148bcb38072e82f220fd7308c0f14623723e39f7916659cf492c1dff0", .Okay}, + {.Lcm, "-341f8aaa546353bfae7e3add83987", "-930eeb1d7978174abb388a506c24a3", "1df12638585e1359f13be9e95d1a8f5dbb5070da61c82801e628db79cf5", .Okay}, + {.Lcm, "5cc6f6f287ab1a22ed105a37830fc1", "d2e8f8a625c3d2a0622ba6d798c75a", "197a8c553c56b4422fbf20d7d01cbe8dadef0ee2b854914083b047a3859e", .Okay}, + {.Lcm, "b31fac9de33c82a3416df91efbf7ef", "-b4478bb616e491e86e5f7886ca7952", "7e2454e97ed3ab674e15d86cc0754c5069e11c9924cd8c8a3911c17b618e", .Okay}, + {.Lcm, "-55d0f404b4a8a53885c07322da2662", "-db8ec639407dcd1e0f18001bf91e49", "188889b36502f426cbd773b0f42d797650cf0a952cb7c4e627b7640224a6", .Okay}, + {.Lcm, "b338062e8df573ff2a15f913d5488", "e9463f7ede34774152c7e6a411e518", "1469e56cb552e0f8944165dd057b69e1180f13d3e7ed7dba6e966ecb298", .Okay}, + {.Lcm, "27a7931112811f6adc8777d205f896", "-daa3760893508eba11d104988b4bd", "21de0537bf78e7f4a266c4a02b14d886f3719d18108ec7a119116e1febe", .Okay}, + {.Lcm, "2f6450fd63599e1b6b54efd102773c", "-c3332e976698a3f1d3d222f42f22ff", "2422e34d32df95c7c6be2092c1a14d40b7c9a4a6bd9447063bb4994ebcc4", .Okay}, + {.Lcm, "12540fcc28299f68ce8494fe47d4de", "-65dd21cec756555174266315d63e97", "74aff38d30aa5e965f5d8c1b1702961961f18114de5954d03d3898052f2", .Okay}, + {.Lcm, "-562cd68a75809b227fec9dbcd4c906", "2a7e707f4cbe351632267ef101783a", "726f59163aea3d7d4b805b864e64844c294b49244284082b7a3fabb2dae", .Okay}, + {.Lcm, "-defa9a061783c589a101c88f1ceb89", "-5456fca55338dfb84abe2555bd4fd6", "187caa42cf2110979fee781fc94df9b69c1ba523dcc072c61f0efaab0e82", .Okay}, + {.Lcm, "-be3fe938d990740ac37cadae00360b", "-fa121fb4ed4a9efdd9d401799fd259", "252b2d299f65c577db3943cbaa3310d512af74af68bbd54942f77c728ff7", .Okay}, + {.Lcm, "215ad800bfeffd32da262e490badeb", "-85b5ed25e7aa93434801403ac8992c", "116be65926887f7267436f130a9a0333960fb6d2f99728b755e3a68b5764", .Okay}, + {.Lcm, "-a466d5aa18cac96f484087936ccd6a", "8d97c0677d1f08d28bf404dd1d4a4f", "5aee17e64cf5ff0986b6d111a66f9f90ccb71c5e91bf119df8c3b8f607b6", .Okay}, + {.Lcm, "-5a74ef547f4c461e78c47ce039d8e", "20683bccea3d2e9322e44b9927e1b", "b73728d2558f181946361da64fbc5bdfb8599fd02924c9b9bfae981fa", .Okay}, + {.Lcm, "11e8f38cad060e8f097d50abb82063", "-4a97d828a9539dea5b9473488917dd", "537f5edb7bb311b2be0f72dfb9c810d72a2350efd06ad8be52ff5d7da77", .Okay}, + {.Lcm, "434dae6dc9f4fc57b099d1fe2f999d", "11f2e850db01668dac4e4c3995acad", "4b80517d62002294ba57177ef498de66a6871bbec69d7ee05351ec14b19", .Okay}, + {.Lcm, "fc57811500b2ff76e2d63967a790f", "83abdc9b723839a7bf5f8ac0acfa57", "81ca2ef564e2a81026c631b6a0b990f722fed0f58368aac75f653ebca19", .Okay}, + {.Lcm, "6a668bcdd1d256fab6564b591f7863", "3531e395c74d6f9df95c18d13b2e9", "75ea7b88470d3acc8d0c5fbd1fb67af30acd1233d4d8e3c0f1273b7809", .Okay}, + {.Lcm, "b57475e61fd7ea25e8c1cb2b4bf0d", "4f32a7889e2f1a01a1d33f57c3a5d7", "9a86734728657bf75a0e96f8a145fa9e6b7f03d8365ae98a2a69c75e7", .Okay}, + {.Lcm, "f26d207d1ed04ad4b37cbd9a2e7a89", "-e40e2a7fa94bd911ea463c9a92f7f9", "47fcde6200b0e70c30e9507a1d90fe173e06a602b9eb6725c780b3db1f6b", .Okay}, + {.Lcm, "-3cdfc9746afbecc929b017d525dbd8", "-426f1b8b35492d5c7a5bf4c0642140", "a8813ae0ba87cb8b60188405a532f4b5c45534ab8a78e4eb6a75cc9340", .Okay}, + {.Lcm, "-9efe4f7f7f6b6886d75bc4500e3752", "b30ba7eb1931642b6c00eabdcfa1d6", "37998766bcc39e41e46d9ce150c2e9e771b9ac3372ea4a957bdf10fd6846", .Okay}, + {.Lcm, "-70a3120da6c7297a43bc847ead33fa", "98a0f99d0f2ecbcc1ddb0b2512e392", "2193d33b8d66fddc56df2993d7a16a16d819df62da35f55285294eb9294a", .Okay}, + {.Lcm, "-dfbfdae3e824fdbed779efb98c59d5", "d290b87c0ae6028083cb633b097bea", "3d589f92cc23186fe65a7ec79da17e4d4d3543d22e2f0214b76d6da57be6", .Okay}, + {.Lcm, "179ce4be5322f0ca2dfa0d087fbaaa", "-d7d3b59ba0316cdc37dd29375bb992", "9f4259654984609c543ae955ef3853eb80bb2f1ee3f854092278395a77a", .Okay}, + {.Lcm, "-b4c08cfb0b30ec40e1a08f0dbb8817", "46ddecda5ddee4498e9c028884ac11", "3209580209fed94f3516e71aaa9650619fa5a828f8b71e118fe64cbf7d87", .Okay}, + {.Lcm, "-4c71ec3a4592aa84faa29dd49decf9", "3d47d0746e7c96fa92051600205884", "124c9721bb49c902b4ff9e1b6b8bef37038b3846dd10b811e89b8a03c864", .Okay}, + {.Lcm, "-b9a3c5e36188f402fcefa584a01fa9", "fcdc4ebaa7d035265bde0f2a5c35db", "b75cf8a12464828411acbfe05f9b1590dc3b3c419ae52b259eb1b6451293", .Okay}, + {.Lcm, "-e8840b401312818acf5dd042ee8b37", "-10ea1f867bf2c73eb4c05c4c9afdc8", "f5ce6086cd1300e53d8096420eddaed1092834f8038cfae79721d081df8", .Okay}, + {.Lcm, "88161dd30ded3067163347a10d3455", "501ed3849f0aa61c7416ae7791d8c4", "2a974c5a2d9d7bea47939b7278272d6a9b768217d4cc9bafee4e9968c914", .Okay}, + {.Lcm, "-693310b64b281b48daf6ae18e491ac", "-9d2dab439f056d6d6827ece9d47757", "4097159aa202e50a2fb6d7bb94042b34b2fd59d8af6376b0e72ae3d47574", .Okay}, + {.Lcm, "15528023bb4e970bca935db9f8a0f3", "-9cb187d311c622e36a3d637b9f3392", "d0d0f7074e5d5d4d31f4eed78d25d5ee2aa01c4ad9ceb92d33a4fc93396", .Okay}, + {.Lcm, "-841907fe87cd16be5ccff76ecb85dd", "99d76edf8a24ec1fffce6595fbcc7d", "4f622002f0738094362a8ce1cb822d67eb002843934a6a4774c228bb78e9", .Okay}, + {.Lcm, "-e647b772d9b07e9d0418fdc776c724", "-4f2fe75f3e4862cf70f82f8b7af42c", "11cece39e09be8008d2c81f802666e7cb394d7ad0ae2210f8a84bc58228c", .Okay}, + {.Lcm, "-8ea035af47b3325ddea769a714a816", "-e081344b8504e79c6a3082a568fe5", "7d142ad70a0339b78812f710c5223fe38a1726e1390b1468d0b12c2a5ae", .Okay}, + {.Lcm, "3aac26076a5688a3433363b945d7dc", "4cda98ce179f9b77e762682f16587f", "119d34e808674b53c4fa3f96d86e64ad1006836b4d1ede1c6e2adcc1b624", .Okay}, + {.Lcm, "87bf57ab73069588273b3a50cfaf0e", "-e9876339555819e001456614ff37e8", "3dea78a7d66edc6a3b4b2280c1b8e68be339f770856b3d55392b28e25358", .Okay}, + {.Lcm, "-c9f51b6bd08d28bc5224120bd36822", "5c63c9e49315985406192384d3548d", "48e2ceea1e813c04fb2a9f6cee3a71ffeb652381a47691eb19683da182ba", .Okay}, + {.Lcm, "f18fbe8aa837eedbca0ea3638186af", "dc6dcb7d96f238c7c261bbb0c51b1d", "cfff21f6c7507749606beb91004b86383c9a7e5f29faaad7341ae38bb6d3", .Okay}, + {.Lcm, "39834d43d4c5ada8c6b8ce099847d1", "94a3c058400c6487c674a5f1f67f16", "2164b27bb6abcd36eaed0af1ddf602130fd8ec747306961eaa1d228cdaf6", .Okay}, + {.Lcm, "fd88810809e233cc58e9cd44535b23", "-90a18320f59a23e714a4b6c8384dd7", "1476642f4f226d5fc3442cc37f3319c26ecb5aac5b9da66132773f707033", .Okay}, + {.Lcm, "-dfd07e9f3ce81dec27507402bddc24", "8b6ac16cf011e6d42508f82ccbb68f", "1860b53cdd0ff790286ad5e20c5482847271c263766ef6b9ec00da38b66c", .Okay}, + {.Lcm, "-a5fe411c99b6cb54946924c2870e3d", "-66dfb2adbfb91b56af0cb775f3bfc6", "42b45a478f91577f35dacb97b9cb65f3997dd979033b5cf128e09cfb862e", .Okay}, + {.Lcm, "-c9e67c9ecf20deeb21e41f0fd307f1", "25589535416d2058842ff22b18013f", "9d1644e507597148b2e80fc1ad8c67d3b0b519b736714abfb36fb2fa1c5", .Okay}, + {.Lcm, "-535e402a56607f2b61164c57f81b7e", "b02f56621d7e2987f259907361828b", "3960368c8065bf8d65e5bc539511a98dc20c9609859fc5b5ee5bc66ae96a", .Okay}, + {.Lcm, "1e1847fa3fd6671296b048d658a133", "-eac07e0f5e4bf8f5180f3d54d76562", "1b98d2d27bf916e8df86266d67db82f57f2f27b41717b515b7ee235bd486", .Okay}, + {.Lcm, "72a242ebfd565118679e31b0169a4f", "43413b69f777c4505f9bf53de6bb01", "1e1dad519a02f038cd4b49084244a5dd0e4bc962f231e8f00380a8c84f4f", .Okay}, + {.Lcm, "-153cac3e309375bffaeeacd86f2648", "89f473422f592afdaf30c2a4a1ce1f", "b71bf91323717b3087967c94e7fc6deb1c80b4f7da62f6dd214d98b92b8", .Okay}, + {.Lcm, "-1fd66bd2e661d43697568edc60002d", "-f17355b20f7a5c644e8953db60e218", "1e07337c51705ddaaac1fed7d9d9beb79f5e7f771fa1d9a123aef907be38", .Okay}, + {.Lcm, "-72f454b3515d4f39bcbf6cc0db2fca", "84b77bf88f34293ef94fcdf43a6793", "3b98600003d563d2d69e7c77e06e19bac4bd2898a3a89999e30249dab6fe", .Okay}, + {.Lcm, "30605ef273552589af9d60016358dc", "-ad24b526d848aee16ca4f68aabc67e", "105c07f9562ba911823e288c5538ed777889df2d3de5a59e427f3c49f224", .Okay}, + {.Lcm, "6c8db5570ed34c30a2d204fcf9eaec", "-cf56e099912517a48b252e12473263", "57eb6c796d2561cfb10022660ac7d93a2e3cfb03aabe87283f9363fbf144", .Okay}, + {.Lcm, "7857eef7b43537052b5b9d1d7393eb", "d99ea37ffae08314c743fc894557ff", "664d1cb19b59030961ed643e759d13b1deafed56d84c3d978d263ebc3415", .Okay}, + {.Lcm, "-6691b1fc834f628c0f0ec30a4c47e8", "e4397dfe346b3bf9d61ff933e5f9be", "2db865b841d1b2170b9bcbd3c5a25b53d10ef67d307456728d7eb08b0318", .Okay}, + {.Lcm, "-3bf5c27d5e3f7117998b1cc9cda76", "8a6eb2dc872aee82babce310afe3f3", "206c6855aec3a93d8aaf99a36ae596c696e5817c2352c66a4b705440002", .Okay}, + {.Lcm, "-db035191cd04b83adb8bbe0eb368a2", "96f1813ede02d18d671563269339c0", "4091473ed69d24865ac8901981ef4a9d2ca30d857f6e9a9df9820cf045c0", .Okay}, + {.Lcm, "-76627d9b78901dad6097d62b28ecde", "-92f53e36f424eaba036c9bf52e0849", "43f594aa24a5aaf582555a474e6ca665d2654edcdfee2d62fbe09bf67b4e", .Okay}, + {.Lcm, "-ddfca22285baaab71b17ca0483f3e9", "-ca42c1a6aa5c813a8880bf6de2575", "af633afd0632e88d30d87fcca23aebd79c82093a3a602800bcd8c9d267d", .Okay}, + {.Lcm, "91f56ca66b1ab7376dc68d089910d2", "9f8374bf64f97d5c740c8d9fce12ab", "5af261a24a97fcca6e9e966f90778959a662a42cdaf51c5da31778690046", .Okay}, + {.Lcm, "67cda88d6e76b68aa39415c22fa9e9", "-39dcd1af7d846a68002ce22874f137", "ab9c02202d8c24b2f181493db1d8743fcbebf6b749baf19f52d405a725", .Okay}, + {.Lcm, "-28c164ad59426352bdb11dbd745579", "9f4684b1301ea81f5fa93425a94d1d", "195b57891f1fc606b452c638e1402e7416b8ad16b5004dbc22155dc413b5", .Okay}, + {.Lcm, "-9fc7e634b1964a0ca0302593449768", "e2faa6e33e7367aecd089fdc52758b", "8daaea9ac8bdd748162b165684ed57ec5e1471a96a485230b8632ec0bd78", .Okay}, + {.Lcm, "-5ec40c173b860d6e787e730f6af4ef", "60a38aea758fa9b90d6a598a877c1", "23c60ec8e2598693f219e1a178bb869711be692cf8a6c681892fc55c12f", .Okay}, + {.Lcm, "1f1491ad91247d8b9f0df00ae255ed", "ffa85442fd893984fb4456a104b3a8", "2d25b594e7cd3aabbf537f83839e1661d678d629c86a8b9077c127bbc98", .Okay}, + {.Lcm, "45f348e76b76a6f50942008019187c", "50a951673704e93c33425076445c28", "58292a86815cbf3d3937a8fe9181fcde858e727d173b44ced342c6a18d8", .Okay}, + {.Lcm, "ec7a9a817bd2e11d29a149740de4ce", "-e8655ad718f0ffd7efb9586c3a2200", "6b565e270cd02e1f7a6595df26f968b31dec537052654e3bb6f34b87ae00", .Okay}, + {.Lcm, "bc24036774cb05e6b48d3486ef1475", "1d5e0588a6c5ea6cf987bc250d2e32", "15952dad19fb84aa062c3dec55dfd31ee9bd3c26c308b0f82586435004da", .Okay}, + {.Lcm, "71a40eb75cefaa78a8ebcffaa54890", "-9d495d281748fc8ff4b23b021b53e8", "8ba45c52173311c26a1a43dee5d3b5361030b00f3e97cc756bdd0700e50", .Okay}, + {.Lcm, "3bf71262a17726672a3bc76c4cf670", "-f051d0a85a921b0f68ce7e7208fb9e", "1c2565a4bb700a2a3bce500725c49afddc2818f43ece55693fc4f04ff490", .Okay}, + {.Lcm, "-712173914a62c5b0a9831a7bbb2ce8", "df21960cca03bed67366fc478c1987", "629afb4ab6153a4054079f1d060873154ec788eab8be3e5af13d6df75658", .Okay}, + {.Lcm, "6697d34958812c422fe876f0c5038a", "63b108d857fb221c3d81b950224348", "13f9d49cf27379b4bcfc0fd3444e4d9e1084779da5dbb3b2133b6fd50e68", .Okay}, + {.Lcm, "d2681f7784d4b4dab217787c360e10", "5341b42f1c667687d1f5283cf221ce", "2236e15dd5ff8daa80ce16cb97b23dfd829faaf9d919362781edfb37b070", .Okay}, + {.Lcm, "258a965e27d9a8324489e42c142206", "cdb935440e46310254f7ee2207a939", "1e2b235fbbfd668b9518dcf57679b9ab942dd94c188020e5a18cd51b8956", .Okay}, + {.Lcm, "451fb8f37173247c01f16187dcd456", "-4ee984c22379d46438d3592ac261a4", "aa75c09248fa0c32f000fc31dd6cbbe145071a9d3e531c03d855d8c4e8c", .Okay}, + {.Lcm, "8ecd862c25fbe4a574db42a0a47fe", "-8086625a795671f297a8aaa00100a8", "23d8dcc3b9b3a1a116817caf9322f05fa60a0c2921ff71509f84f5e9f58", .Okay}, + {.Lcm, "-8abc80418a7fd6579c49e84fb5d463", "-d7cc0c04ca8f1b0e0d996cadf20bef", "74f2e470ae47198f6537f37eaa0076e63918c4d0b57edd3afa7ce777896d", .Okay}, + {.Is_Square, "6d3046d98a8d28cf933e46d39212dd", "0", "0", .Okay}, + {.Is_Square, "c2f6029a7a373a61d38bab37a0cf33", "0", "0", .Okay}, + {.Is_Square, "b438507b2aebcd537da462c9738a7e", "0", "0", .Okay}, + {.Is_Square, "afb51078ef643c89896dd49f269a92", "0", "0", .Okay}, + {.Is_Square, "6b2fe00100db2a03faa424bdb902e", "0", "0", .Okay}, + {.Is_Square, "5e7b12801899449cc59434d48cb448", "0", "0", .Okay}, + {.Is_Square, "48d469eec9f46e95e071bd8bbe8830", "0", "0", .Okay}, + {.Is_Square, "3f510b5a40c14dde50a668fd4bc0fa", "0", "0", .Okay}, + {.Is_Square, "37e0de8e5805b7d67e0a7f1d6daa18", "0", "0", .Okay}, + {.Is_Square, "bfe90ccdcab17921ac8f19da45f7ef", "0", "0", .Okay}, + {.Is_Square, "d2ef3d6ba9584cbf0dbfbf0e3ee5b8", "0", "0", .Okay}, + {.Is_Square, "3f27e59f09a9ab2f68b111374f1750", "0", "0", .Okay}, + {.Is_Square, "ddf4c77ffa69ff1b495b7d4756fec2", "0", "0", .Okay}, + {.Is_Square, "56d46a7ccf8f10d642aa0581e133ce", "0", "0", .Okay}, + {.Is_Square, "1b6d755880ae9a3cb7504459727ace", "0", "0", .Okay}, + {.Is_Square, "e943782ae1b2b0a49dab0e80fab7ce", "0", "0", .Okay}, + {.Is_Square, "f455f1e9c88c9b4f186e348cb15506", "0", "0", .Okay}, + {.Is_Square, "4f5e31dcef20ec10f9507267377bb0", "0", "0", .Okay}, + {.Is_Square, "153c3be5e4086cd7480604492a07bc", "0", "0", .Okay}, + {.Is_Square, "ab7976ce5f96ade9ccd9041a8e7452", "0", "0", .Okay}, + {.Is_Square, "34b2c47592b418819900d9b372a72", "0", "0", .Okay}, + {.Is_Square, "5bc9164f87031189c168de3604473b", "0", "0", .Okay}, + {.Is_Square, "32f66f05c0db98ab6f4fe8ac7aad98", "0", "0", .Okay}, + {.Is_Square, "6fc69cf14b7b1860b62e1e1eb83529", "0", "0", .Okay}, + {.Is_Square, "e42c2c9489f0dfd61e1fa1f3ec7d9a", "0", "0", .Okay}, + {.Is_Square, "33d223e4784bb2fa8f6de8d0a8caac", "0", "0", .Okay}, + {.Is_Square, "5e87bbd59aa99e3ba022beee39e604", "0", "0", .Okay}, + {.Is_Square, "5a49bfc95e7990f54db9df1fd09a5e", "0", "0", .Okay}, + {.Is_Square, "95f6b7ff48e35fb7e078ee45227027", "0", "0", .Okay}, + {.Is_Square, "8521fdf36e9a24ce200ac191082d5e", "0", "0", .Okay}, + {.Is_Square, "e0a9902892b1c6ca9f2e95ec4e6096", "0", "0", .Okay}, + {.Is_Square, "14fdc6139eb81592c20da4875c7079", "0", "0", .Okay}, + {.Is_Square, "7aa8e84d7491946c45e35aee36bbbb", "0", "0", .Okay}, + {.Is_Square, "d6cae90b8b4cf48120c059965cd266", "0", "0", .Okay}, + {.Is_Square, "ae00f8ea9ba5aaefc5837c8b838162", "0", "0", .Okay}, + {.Is_Square, "7e749b05b2549bf342e7c1f47f88eb", "0", "0", .Okay}, + {.Is_Square, "a742de3bdac2d6c114518d6850fb88", "0", "0", .Okay}, + {.Is_Square, "b4fbe2a7fe8a3e106d32a0d91c2474", "0", "0", .Okay}, + {.Is_Square, "14026afb8521fc56ad14e657fb4ae6", "0", "0", .Okay}, + {.Is_Square, "25c682acffa20087dea3bd578ee576", "0", "0", .Okay}, + {.Is_Square, "65e028dcc1ba992876427779ed6e42", "0", "0", .Okay}, + {.Is_Square, "bcc380bd2880c3a03a6e034020065b", "0", "0", .Okay}, + {.Is_Square, "d496e79f18b65e98f8c755701bbfa2", "0", "0", .Okay}, + {.Is_Square, "397824267f568501059bd5b8611b52", "0", "0", .Okay}, + {.Is_Square, "d6a77fd4ef7e7f4d06571ac1f90d12", "0", "0", .Okay}, + {.Is_Square, "4a6dc60430e896267f4bd69fa9b52e", "0", "0", .Okay}, + {.Is_Square, "5f694dbdbfaf8f97ef462ae7058f", "0", "0", .Okay}, + {.Is_Square, "596869c1c9ef1a86441a38ee5ae26f", "0", "0", .Okay}, + {.Is_Square, "1a3f595a1ba479cece3d484360d4d2", "0", "0", .Okay}, + {.Is_Square, "3206661323c6d78a2caa43bba9676a", "0", "0", .Okay}, + {.Is_Square, "bb03c411e27766db73e817745b7b0c", "0", "0", .Okay}, + {.Is_Square, "7d54645c18548916209ac483bf1b35", "0", "0", .Okay}, + {.Is_Square, "731a37b1dea24db3bd29b584ef63fa", "0", "0", .Okay}, + {.Is_Square, "d9258d206838300239a1cc2f3d18c", "0", "0", .Okay}, + {.Is_Square, "682b6e7d09f02dcc5004224a9db2e0", "0", "0", .Okay}, + {.Is_Square, "11c8dc8af64134ff07063e79161ae1", "0", "0", .Okay}, + {.Is_Square, "e78279bf2b5b6710c743899bca5917", "0", "0", .Okay}, + {.Is_Square, "2146d3dbd109e624aaee4dc5c49f7d", "0", "0", .Okay}, + {.Is_Square, "f74d194701bbf25083dbf59f3de975", "0", "0", .Okay}, + {.Is_Square, "bc308fc6d4724dab89652bb10a431d", "0", "0", .Okay}, + {.Is_Square, "7d90797aed10014f94aba06d7c0202", "0", "0", .Okay}, + {.Is_Square, "7c93f7b1c99fb871e85e267f7432eb", "0", "0", .Okay}, + {.Is_Square, "67b33305601e1cda0b760008542389", "0", "0", .Okay}, + {.Is_Square, "45997273027c600d9d3fde11a6c56c", "0", "0", .Okay}, + {.Is_Square, "4ea259ab283528cfff9bef38f22a72", "0", "0", .Okay}, + {.Is_Square, "e91f774af12652a77b5f41a4e48e6d", "0", "0", .Okay}, + {.Is_Square, "4f3e7d0398d2cf219a7c67965ee9bd", "0", "0", .Okay}, + {.Is_Square, "60e5c5c574c075fe85db43bf4d40a5", "0", "0", .Okay}, + {.Is_Square, "8edbfae7991889ddf39d5f9f5be3aa", "0", "0", .Okay}, + {.Is_Square, "5ece7bd90913eeef1f4c289d25c381", "0", "0", .Okay}, + {.Is_Square, "12d69ab32fb3a0efcc0f6ad4a0db8c", "0", "0", .Okay}, + {.Is_Square, "95a57109dae44481110322bb342a01", "0", "0", .Okay}, + {.Is_Square, "3674b08179c8ada49ac8865815a99f", "0", "0", .Okay}, + {.Is_Square, "f0a78e0a8adbf25f0befe5ac438eb7", "0", "0", .Okay}, + {.Is_Square, "84f94c4e355d9c5cb03f72b16f256", "0", "0", .Okay}, + {.Is_Square, "e0ed88c2f29700a0a35e5158227135", "0", "0", .Okay}, + {.Is_Square, "3e615275b690a7941c4b56278e4bb8", "0", "0", .Okay}, + {.Is_Square, "82441c43604597c29e451a5620cc2e", "0", "0", .Okay}, + {.Is_Square, "e4696fd25bf1effbd13985701d9907", "0", "0", .Okay}, + {.Is_Square, "a9a32b9fde70b7320ea0aa633ec1ef", "0", "0", .Okay}, + {.Is_Square, "38d6c2278f48ecba67573ef33906d1", "0", "0", .Okay}, + {.Is_Square, "debee9a269b91f1aa66cef63cc2f08", "0", "0", .Okay}, + {.Is_Square, "d9ce4324030e62d134b6792b922c4a", "0", "0", .Okay}, + {.Is_Square, "5184051a7c16d22221a72a1810e23a", "0", "0", .Okay}, + {.Is_Square, "8529ec56e586cb52afd87302c77a26", "0", "0", .Okay}, + {.Is_Square, "4b7ba70f16a19089c5ef1b4ffebad1", "0", "0", .Okay}, + {.Is_Square, "a2c3f472012281e66d3079e37cc17e", "0", "0", .Okay}, + {.Is_Square, "b029aa8a89e90655da40be95361bdf", "0", "0", .Okay}, + {.Is_Square, "dd7330f0c4301f7f3ece00800d7d9c", "0", "0", .Okay}, + {.Is_Square, "337abbc3805819eab96fe8b228fecd", "0", "0", .Okay}, + {.Is_Square, "b7d8b1f08eda91a558466b03a94517", "0", "0", .Okay}, + {.Is_Square, "f8008ddb221b6f30f921eca33b360a", "0", "0", .Okay}, + {.Is_Square, "5f1a18d80a8a4f88c618cebd060f10", "0", "0", .Okay}, + {.Is_Square, "5e627cdaf40009f025d0a9739125d8", "0", "0", .Okay}, + {.Is_Square, "7500e127b2b59fec01ce91cffbeb37", "0", "0", .Okay}, + {.Is_Square, "5d056faa631d856e3bb352c3a07060", "0", "0", .Okay}, + {.Is_Square, "bfce7fd6ff6b49f42ce986e59fc16c", "0", "0", .Okay}, + {.Is_Square, "7501a470da2baf705c80f43db42c3a", "0", "0", .Okay}, + {.Is_Square, "bbe51f989a8ed695328d5af15aa9fd", "0", "0", .Okay}, + {.Is_Square, "3d170c8fef5aa8f7fd1448ad8e67a6", "0", "0", .Okay}, + {.Div, "-959faea2d7c966a8e60cd491fe3d1d", "c4e990ed395a84d680", "-c2857eb5c666", .Okay}, + {.Div, "36758d1217f555c66454c587c1478b", "73cb91e3472d06e1bf", "7865faa40b27", .Okay}, + {.Div, "-fe6fb2d49ba1f07c6612c49986911", "409f8ef42d9b81cdeb", "-3efedecdc8bb", .Okay}, + {.Div, "-f00632476eb2d3be116b0ebb75abef", "6b3bf3d3c0dfaaef78", "-23d0266ca25ea", .Okay}, + {.Div, "-144a2754e6951339ef181e32088402", "85f8c7132b5783e324", "-26c53fb4d6f0", .Okay}, + {.Div, "59b44a61370f82fde4e86e55c3f78", "7b17e2784d32e606ee", "ba8f5e9d16c", .Okay}, + {.Div, "-a45e78b5a62d01628421bce4c45472", "-5faa60a47d64c00733", "1b7d98f543fc1", .Okay}, + {.Div, "-73e99d4daf3e95d918f8ca3f39b6de", "809f2cc2ef2d36c7c2", "-e6b455eb4e40", .Okay}, + {.Div, "-8f519805f2146ba217ada057f7dc37", "-b31a8708893ec8dd64", "ccd9e8e2c082", .Okay}, + {.Div, "89955d955e5a16c3e72a8a7fb3f24e", "5268046fb7e1bc2680", "1ab69366d8da5", .Okay}, + {.Div, "e9dbc687ab18a4961a0867ccf2f1d1", "629d7864989d9c918e", "25f15cd77db05", .Okay}, + {.Div, "-6bb2d97f52ac297a2890e6cee3e185", "588d8032d19813125b", "-13759782792a9", .Okay}, + {.Div, "-d32a59db3e4ec0aefddaf6a6e2e7de", "-a057287d539c2b554", "15125b4599d0a4", .Okay}, + {.Div, "20f1ca44fa54328e2f1b644088500a", "61477050d8177ee424", "56b26647bd5e", .Okay}, + {.Div, "-19fd0d2c78844e9d990f0da9476bc7", "c06777974a547b834d", "-229419e905c2", .Okay}, + {.Div, "3c1c8ef5d72c135ed117d6ea1a633f", "109b04f878b2164dd8", "39eb6498fe640", .Okay}, + {.Div, "2864cd5ffe09f9369cfcff31aed472", "-f3eac027e808fe7b98", "-2a650ef02134", .Okay}, + {.Div, "d98aa0af0f7b582831c0bd6d682dbd", "-339599962404d76baa", "-4379a473367f7", .Okay}, + {.Div, "-2525dc8eb7da93b701028d44f0e978", "24426a20349573f690", "-10645d41d545b", .Okay}, + {.Div, "de25961d2719f78033ff6c7f1891fa", "-45cccb8f79f6db426f", "-32ec030a0e8f8", .Okay}, + {.Div, "b196a9d67861c2ba4e497b69634d55", "3123727c8ffedbfcc1", "39d31ec6c5c74", .Okay}, + {.Div, "39766c20db13678177b3e6dd97cdd2", "-a6164c40e4f4fc8d4b", "-58920e2dfebe", .Okay}, + {.Div, "11e17cb55a818d26e09e745426fda1", "71277419ec43f34c3b", "28741cb5d9c1", .Okay}, + {.Div, "777db5e2c55b6a552b5d048ad12025", "-5763496f485d62f0dd", "-15e0b9ed66a64", .Okay}, + {.Div, "fa28a6ae21b24a01fdd1120e517f35", "-28c38b5b0175abe9b", "-623041599776de", .Okay}, + {.Div, "138c1961c0dd614de4eea73513fbc", "2783aaf67f7bbfc044", "7ea3deded40", .Okay}, + {.Div, "-ebf032d7eceda2c87fc2ab5cbe1881", "-85762d70a79b31baba", "1c490e671b774", .Okay}, + {.Div, "fcbb08d5443f9a811191bcfa6db04c", "a741eaf11132320c7b", "182d2ac353735", .Okay}, + {.Div, "ead26daa53e4822f8ad33297ce81e1", "-57e1c3ac744d075517", "-2ac095cf6427b", .Okay}, + {.Div, "3c8ff056397a3c48ccec5b46f7debb", "-aab15a4158b2ec42df", "-5ad4599740c6", .Okay}, + {.Div, "-49ff6fe0be655905e054fcc42de420", "fbf0fdf81da3082fb8", "-4b309abd7762", .Okay}, + {.Div, "-9f4d831160768627b760de18b1dde0", "44ce49f6434e6afb78", "-250b45583b0e4", .Okay}, + {.Div, "8a391b9eed29172c0e11575f71cb5a", "b723ee62751b1d1b48", "c1368ad5ee9e", .Okay}, + {.Div, "-532b70424f9de54b65624c7d104707", "48a7b153b0a693b660", "-1250c5d2b50c6", .Okay}, + {.Div, "-fd642b62b8f5afb33eb5b56112ecde", "9fc6a5315cd9f2133f", "-195fe9b573f63", .Okay}, + {.Div, "bffd3c988ba4b2e49bde67eb835d2e", "-32cce6f7c66148750c", "-3c77f3efe05b8", .Okay}, + {.Div, "90e2b6fe5efed809a09e400b80624f", "b215cbc10cfaea5de2", "d04672424401", .Okay}, + {.Div, "5d56442b98353e733c9133426aae87", "5b0096da0a202219d7", "1069155a83d87", .Okay}, + {.Div, "-7ebb6961e588370580213fd77cff91", "-b298d5ba28dd8224d", "b5a8366e0dedd", .Okay}, + {.Div, "-183789c84eb554f254437be43ba7b5", "36e267999a272ee40", "-70f4d055dda17", .Okay}, + {.Div, "-3835be1eb909f882080a7f8012d582", "-38b21bba4cf9905bf8", "fdce72ab7d3a", .Okay}, + {.Div, "-1ed6f73074ab3b85ab3341ea4cfcb0", "d12b41b3507f6b88c6", "-25be93967691", .Okay}, + {.Div, "8e10c7e5aaf956b020acc3cdbdd7a4", "dfb951bdb6a36ea4d9", "a28f9d82cac0", .Okay}, + {.Div, "-f906ede6cdbcf2c3f6de9c42462b5c", "ee3ea1ee37ef6b904d", "-10b96027c9f42", .Okay}, + {.Div, "-7becb056d38400f66d2823d60067d4", "-bff6fa99aacd654a00", "a54359972337", .Okay}, + {.Div, "cdfd0443b381208ff383bfc4b44162", "-92b3d0fb9bfdf32917", "-16774a8c735c6", .Okay}, + {.Div, "-4d235d4c7696d0fca8980847e50f32", "4b9bc5e9ecaadab582", "-1052ddfeea926", .Okay}, + {.Div, "-86a7b82ee7a5c9f11cdf768e27ccb8", "e6d30488cdefe8d8c2", "-95578192d900", .Okay}, + {.Div, "-5a0f6bb21c2be0d01b9db89b30b589", "-c26a14860940f46c7d", "7696cd857646", .Okay}, + {.Div, "-8b9bb689c9309bd3bec30aeeb49092", "-df11308d3d37e5fa3e", "a03832fe3d64", .Okay}, + {.Div, "-b62e2800fb88a5a231d0bfbbc1974", "-5029243fb4b289a25b", "245cee4c17f5", .Okay}, + {.Div, "507e3895e8f53b7a2105ebe4357b76", "461a9b9356367a0221", "125f02a4941e5", .Okay}, + {.Div, "-8d4d026b8eaf0271dc8895433920ea", "-c2049fd3326c2d4111", "ba7102fa128d", .Okay}, + {.Div, "-e26de8b66e47c98545d14e109da5c7", "-329dbbfb329c08fbd6", "47934b07fe09a", .Okay}, + {.Div, "-22d5d925d04892ab547cc2fcab2c21", "c5c3a98d7a36ee735a", "-2d17e3859b74", .Okay}, + {.Div, "-27fde827fc4147549c3991d12737f3", "f891d93f60b4df3f96", "-292ff091701b", .Okay}, + {.Div, "7a876b20ac79c1576d3252d9a5de04", "-3cff4e7b4886a603bf", "-2023e28ca7ae6", .Okay}, + {.Div, "ec302d60143291ae0e1c916f657bef", "3688b02ca6634fed94", "454be775702a6", .Okay}, + {.Div, "9f92e07e9818e03f5128192e97030", "-e08045a8dadd322b6c", "-b5f68441252", .Okay}, + {.Div, "-228889ba132e960b245bda5d960ca3", "4c070aa5a393534229", "-7447e16eb4f3", .Okay}, + {.Div, "-ec03c3e82ef5492c552ae98ea896df", "be86445f5720ccc715", "-13d1f951fd79d", .Okay}, + {.Div, "-6a9607d27da99b586747d7b55d37bb", "c20444029f6b527a6d", "-8ca3374da22f", .Okay}, + {.Div, "a8b5d1b9fd852f372814d3487c3eeb", "-92f66b3ec2ed472b9a", "-125e213ed3cd5", .Okay}, + {.Div, "-4cc84441824c11bd88aebca9737ac3", "-6a6018da01f6c78e74", "b8c8381dcabd", .Okay}, + {.Div, "-921ec2b89238285f7e25797638fda4", "-d1d6132dbcca243da2", "b24436512711", .Okay}, + {.Div, "9339605a172d9b44a80fe28c91893b", "5b2d2888066a9248b4", "19d5e1ff51894", .Okay}, + {.Div, "-5ce94d61e7ca8c6e4fa3cc1318d92e", "-72b2476c0a10e30081", "cf604d9ec809", .Okay}, + {.Div, "-7960c3eb6cf4ed52a39e32da13a5e5", "-938eaa59a7df3a04a6", "d294be526dcc", .Okay}, + {.Div, "-ed596674efff9ef2418f5916b95d25", "c3f1fc5dca1c21d6f4", "-1361800391995", .Okay}, + {.Div, "4a43a13a0fd492e5961e762c5869fe", "-2f0ad46aa16149564e", "-1942395cbc063", .Okay}, + {.Div, "9fb2d8cb6a4ed522bab540bb4503bb", "54e030678f5190886d", "1e1adc81b13d9", .Okay}, + {.Div, "-55cb78264ce23b89c3a61caf8048a", "-9d69a083117bf194e3", "8b872c63bfa", .Okay}, + {.Div, "22bae741b7f11b1b4a76521e784535", "be78890ea9d1fd8198", "2eadb5adb450", .Okay}, + {.Div, "-803f0644c7bf99a1c67b522f8b0946", "cbcaaf8f955f332d95", "-a119d1dce9fe", .Okay}, + {.Div, "74ba9e1b43a828907a97c425847063", "-66df6a4386fe3173a0", "-1227b41a92ed5", .Okay}, + {.Div, "-a59fd5947d424452f7f2c8c7e072b7", "518de4ca9431717ebe", "-207e5ac0f0e5b", .Okay}, + {.Div, "5b46363f0fb7b426c6997201561a1b", "1255a75ee4f4cf2993", "4fa6f0277b5fb", .Okay}, + {.Div, "152936acf622ee87038b45ded441e8", "c3745f83a68bdcb8c5", "1bb749e364e5", .Okay}, + {.Div, "-7822b122a8eb122d342d0103ef7740", "e198f4879d0e894d6", "-885354b252c0c", .Okay}, + {.Div, "-68274052b3d416620fb4711a96caca", "4495a557c402727cef", "-184c3c11d8eef", .Okay}, + {.Div, "264c9467a7c006a2a2b9d99ee7b3ae", "-5f2a280d7c9e6d40fb", "-67070b2125e4", .Okay}, + {.Div, "d2f432544fbea5b166eec2eaa1070e", "64e7aa2c5e64f88721", "21732e0649432", .Okay}, + {.Div, "-337abe80f0aa39251233cbc8233b89", "308fb99e9857d79421", "-10f620a7b413f", .Okay}, + {.Div, "3ac389f2f715f9260cb753d0b7c9d2", "e9f22cc15b501c0e40", "404db0169e24", .Okay}, + {.Div, "5ff703bbc664ecfa07ec8eb8f30f50", "-8c617aa791be367fe7", "-af00b0af7287", .Okay}, + {.Div, "c37f709d5ef7b9e5685abb96894c22", "a9cff0277708fffe02", "126b8e129ba37", .Okay}, + {.Div, "-532d77996335f4235ecd6bdf01f4cd", "-308d82ee78554ab62a", "1b69034a3617e", .Okay}, + {.Div, "f842828c9f3ee5348747794ee5534d", "-d0d77acbd275985516", "-13051ac497e1e", .Okay}, + {.Div, "-27bf89ae13d69f3405cb540a19fcdb", "-d2670cda0611757985", "305cbba97e74", .Okay}, + {.Div, "-fe0baef3541584889a3582ae1645ec", "38a21e37607906d0a9", "-47c5d8113910c", .Okay}, + {.Div, "-24def4c31f9b96ff841a52512159cf", "18acc9c2f245af21c4", "-17e88287cf1d0", .Okay}, + {.Div, "8f7d571c5e2573e3336786ec27438", "-b698ab6a6216741b43", "-c92c1f3d88f", .Okay}, + {.Div, "-ef59f33b27bf3d9e0dbc71bed16f1c", "-f80e88399ae56ac27e", "f7040e00ac4a", .Okay}, + {.Div, "a10c4226406262fea77cc4ea5ea7f3", "-2c3800d71f6c29e7b6", "-3a45ec7e31b1e", .Okay}, + {.Div, "-e5532bb498073824d1f2263996df34", "3e16e4d316380aa159", "-3b186a93387a3", .Okay}, + {.Div, "-4747eed6ab898355a05652c2318049", "-fd6ada4bf2bdddca7", "4801e6595b9ea", .Okay}, + {.Div, "-dbccc726b60d381c6ee323575d8825", "-6a4006ca7d4ce59c89", "2119685f845b4", .Okay}, + {.Div, "-41d891e51db76ec5be466efd590246", "-ef45e40a127827b315", "4672f8aa3ab0", .Okay}, + {.Div, "-a2116f7d3446286ba0bbe236d2e521", "-6a2668707adf2fed19", "186db4734b2b2", .Okay}, + {.Div, "-8f614b0ca9fc87cdf009652d9c47f6", "4052e15cd6f50f6a5b", "-23aa233034aa2", .Okay}, + {.Add, "-6d0d2e3e64a4fdecc1fc23bccb64c7d8c44f3319bffde7fb1a1ba34af5b6aa5b34fd2c26e8a9ca7f1426b8d72a98685743f288f432e0c8d45de8cd91424f632b330086de9f68a811ec457bb5a474736cd7b0784275ded3fca8224211cb9f453c5b7bf4dd3fe1c868e0f3e7c45080ecdfd9fb1aaf0dfcc817c8caa1c0daabea3a006922d2312a0db92f0ff37f3a9277ac24dc8f4db1da", "67b98907a6b254a38fa65e33b93c664b867a7f1395f5617efa827844c53a3cb3306f95b7f2cf146111c9d42edd93fc301472463f7ca845339f8c65c2f42a798b22808d98e04b17777123b0d824b615cb6f8927603f152f530dc8c8e8eb65bea5ec0318fc0ddfaf6914b2dad9dcf16157b2fed975e35e8c92333d19c35b0788236ffee6db6bc145c3f46498c19a98cc4f4370f876755d", "-553a536bdf2a9493255c5891228618d3dd4b4062a08867c1f992b06307c6da8048d966ef5dab61e025ce4a84d046c272f8042b4b63883a0be5c67ce4e24e9a0107ff945bf1d909a7b21cadd7fbe5da1682750e236c9a4a99a597928e03986966f78dbe1320218ffcc410cea738f8b8826fc41392a9e3b85958d87fd7fa46216906a3bf6c568c7f53aab5abd9ff9ab5ce16b96d73c7d", .Okay}, + {.Add, "e54c2803657181c71480b480d2023c62ffe1ae25a538b1273ba7da988b4e0000704404ac8d536da8c8f317b192fe1f03cc6cdd817e2f19d67fea0fe55f8a6a525ac9c75ea14c3469e0b18aecd05afc76c0d384cc10f1f8aab1a587d92c91dace8b1bfe141a4f623a852408a76da04a6ba981bc0a09e0e6e17d9c9d63fd7a92c1700faea006b1ad9521935853088988351f80fd7dfd9b", "6a88cacb1abb581d2e17ef7e5d99d864c86f26d9a3d111e212948c14ecfe090a7d42b636429451da2369159ef64c499642fa2c4c697f9f5dfc09b2c8229aab7145540514f3103411afabf142df4ac4742b56ce99ce2b52168e92fae6cc897e20dcc2bb8d52e782d43ba04cf3a5b37a13e52c61022be2aa21f89812d5114726978b37e480441370e125629c2ba57c5b4726d5c33b5cac", "14fd4f2ce802cd9e44298a3ff2f9c14c7c850d4ff4909c3094e3c66ad784c090aed86bae2cfe7bf82ec5c2d50894a689a0f6709cde7aeb9347bf3c2ad822515c3a01dcc73945c687b905d7c2fafa5c0eaec2a5365df1d4ac1403882bff91b58ef67deb9a16d36e50ec0c4559b1353c47f8eae1d0c35c391037634b0390ec1b958fb4793204ac51e7646f5f47eae05e37c4656c0b95a47", .Okay}, + {.Add, "f6d614431a4c862c35d0c6d0c8b41d830c11324f3729f205330e62ac5bebaf10bb1198028e5f782ec8663683a1dee6872ac86acb38f61b8d659b9e615a606eb425e3728c6b21812edf8c65096e2c4e3a23f22610c5bfc0d3e28a6480ed1c7de8cd9c0207644d170e06500d21dd5ade8e86ac993c5f277a17aa5ee68893108bd3291da3e0557610b28215706b9ee895f26a63b8a65a7", "e9289d183e029e15585b3214d0f57df40e76e5154b511ae4016e141d865432e7a86987c56f680f8901b7c6161fe62222971684b821414b4f9dc20bb8ede5a1a723aebf3925ff7a1c8508a66e0906940694934d0b593baddfadb35dc0dff7ac280b3c34d5418a6e466dc242c4f9c957f80fbfbe864119991789053cae856235623b386498e94b1eea89e5521c228f7267534a246bd987", "f895fe5c6fa766781bb83e81dd80bfcc3f37f83a3ec3ba04549efa484c12edd8b41aa145984e070bee3e297e5a04108b09c30b64d4d0ad08741bc59f038ba892660cf661ecb1922f73016cbe9fe958ea36d26f6c6597a9ecebdc0408eec974069815f4f5b7cf3fb74e274397179f05e0f82a881a070c10b903ab2b170e933e1f6dca3ed6eea27ff5b206a922dc7dfbc679f05ff63f2e", .Okay}, + {.Add, "e103a19a541d096806269492b75c12b39d5d9d77aa0e6ad8ee91a8d438afbfb29fbb7a349d999c446fa890d56959fde4cb24e0398b820f438f64349cde36c6135f235721962c512c3e6993ee9d69fbeda001279b56ac43ef6da9dc7088cec3cfdc487e06f1dedd859375e64a5cdeb9592de6f315d8eb92c5f5d3e1b076039d8f1abd59750b6ff18280b18c019fb5c58d482bb84353ee", "177ea39946dab028ac6d5f5cb09e5fde2bc3fe03c62794d53deef31853da98450513b08fb9d6f8871af3c46b8ecc913905e333a106a2b65689e2ce6b51832da6121b5faf2cac723744e572224f2ae296c4839cbbdaf747db20775533c548efa2d104e9a395b3dcf2a4897fb4b24448d03c7fc40c83ffdebef2082fdee835be6f4b0563b3ddbe1a25b6abf62a9754a00e49302d89d1ff", "f88245339af7b990b293f3ef67fa7291c9219b7b7035ffae2c809bec8c8a57f7a4cf2ac4577094cb8a9c5540f8268f1dd10813da9224c59a194703082fb9f3b9713eb6d0c2d8c363834f0610ec94de846484c45731a38bca8e2131a44e17b372ad4d67aa8792ba7837ff65ff0f2302296a66b7225ceb7184e7dc118f5e395bfe65c2bd28e92e0ba8375d822c370a659b915be5cd25ed", .Okay}, + {.Add, "40e0f92b34a7b3ebb3fc5b0d5289effa5c84cd889afb6f8fceb4887ff4893a9a23f6a762c3c6d8d55ee70578918c5c8751d5120dc8b5ca3a041c2d787f44b8c01d664f250b1ae08c6267eac3da33927d2f0a5607fe467a662d5b1633695c34fe6f26cfc868a1099c8977cdf8e43d6f49d7e94738d6a9a35c7e19a6b2cabcf000ddd91abb369e212d19e1be8b6823b0e9541755130df4", "458ccd95d51f42e915514a7a6b06ff826681dda4b9800517eccbc4cf949d6351e44a021f275d5e7f417fcb1fd1ab0ba38b3260d937754a7d88a7967a787b418cf340095a2a39743492dcb570deb458f269169e46cc18c0203c4624af4cb73a8d8675b7aadb3d64c39d015c8aa81c4f3f77a9ea25c58fcdc7b4a62ffe963c21aba454c035248a89930cd700cc1791e96d8c9f183679d8", "866dc6c109c6f6d4c94da587bd90ef7cc306ab2d547b74a7bb804d4f89269dec0840a981eb243754a066d0986337682add0772e7002b14b78cc3c3f2f7bffa4d10a6587f355454c0f544a034b8e7eb6f9820f44eca5f3a8669a13ae2b6136f8bf59c877343de6e6026792a838c59be894f93315e9c39712432bfd6b160f911ac822ddaf05b28aac026b8bf577fb59a56e0b66d4987cc", .Okay}, + {.Add, "b01df46bcb1cbca4ade0d8aebeb2768e61984f5e87a05dcca93c301429c2d26438e4c04904078d8684b21313664aa9a0c30e5d66c635013241048218935e8880c4e54f1a6a22fe9bbc443afd236f525238e1570aa29532f5b586bdec2d7b2371bff7e0b7b398dccfd469c9b3affa64e112bccd486e3b16f282fa1c14445decdb2912ffbd55ce7be1384e48537c180d5a3aebbdcaee19", "82a30021418501d19686096c0c294f0d34876626144ab7e30cb19dd54e809969a1d4db5a410b6a7daae402814ddb310d5ffd909c63ecf39f70638a2559f1baaed4a5d8ef388b66e20d91a4a78f8fed546dca0d06588dba52425da3eddadb778581a5b0bc00c7f0e3c47ae453df843c6328f603ee5b0dbe06a2c20afe6cda715cadb83b89e8dcb408400f5c36e24342e76a76414653bc", "132c0f48d0ca1be764466e21acadbc59b961fb5849beb15afb5edcde978436bcddab99ba34512f8042f961594b425daae230bee032a21f4d1b1680c3ded50432f998b2809a2ae657dc9d5dfa4b2ff3fa6a6ab6410fb22ed47f7e461da08569af7419d9173b460cdb398e4ae078f7ea1443bb2d136c948d4f925bc2712b1385e37d6cb3b473eab2fe9785da48a5e5b5041a561ff1141d5", .Okay}, + {.Add, "-6e05b38860799917814d5d5c2e4ae6e5531f83e2a13339bf8b46cc96726d1467144b64ed3f86bd7be5e6b83013df6103e812eba8b3214a131895bb6419872539f428aa18b4f2d166deb307f96e65810b4150c4e62543b1dcb6a20779a42257f2186de141dbaefd9ca8b70b307ef65ef73b71f99de33ae9d9eaa022532cc1ce0e91679ec74aa9ce794103a04c2cc9301b0810a8ed3503", "18976f48959735273df3d5ad443facc99a35a4206129e6490b7d9c79549c2bc1bffadc4ac99d06f3f0fe28b84a2083130f37db8cef5f524160e3fc3d2e082eb466ff29ed84884b8679e96be86a5226fd20cddfdcee5e168e74697b74e73bdaa22c506798f6fbb78b13255f173fe697580134553ba6c3c974009eb6b6f43b5d0ab6c012d20cf314412a4ce92e90ff42d4058b02553915", "-556e443fcae263f0435987aeea0b3a1bb8e9dfc2400953767fc9301d1dd0e8a5545088a275e9b687f4e88f77c9beddf0d8db101bc3c1f7d1b7b1bf26eb7ef6858d29802b306a85e064c99c1104135a0e2082e50936e59b4e42388c04bce67d4fec1d79a8e4b346119591ac193f0fc79f3a3da4623c772065ea016b9c38867103daa78bf53db6ba3816b6b71d9bc9ed470285a697fbee", .Okay}, + {.Add, "ff39673de5efff39be2b92e67c6b46c455dc452f808b8e2416058e585b0ad88b240dec7e7dba6d7b19b67f688701325642963845975dcd205cfd70d57465f0a82a2d66efd65743882c5d6fa3ec190e2ff93cc945c249a477cc9f78529f7c99eb23bb633949636ca8b1a3f8af1f1684789a0b6e9f1d1b80e661a0e08bf5471a9e209559b9ca8f50bb692a9c6ea6700d22b0c11e7c1005", "ece6aaf16e29e2c6ede298bdf3c89ada55df04ee96dabf258dd786884f522bd6bac2f934d437fa9a4a10457c9a3608b2bcebebc18ebbfbbec9c6a25750330659b32477d68c54ef64d8b1b3d3ede543bc912fa812c92bdc6ce72e419c63cacd5d975818f814b611331907140727c54b63a33cfab79ea520edc172eb8fe24b4a98c557d724cf3089aeb3057e795c56a58d752997d0acd", "10e07d1ecfcd29d662d09bc725ba7d071fb3a357e69f93a166ee306c0dffffb488fba1c11cafded24be5783c050a492e16e64f701b0498cdc4999dafae969210dc55fae6d3f1c927e79e88ae12af7626bc24fc3c6eedc623e9b125c6c65b946c0fd30e4c8caaecdbbe33469ef9192d92ed43f3e4a9705d2f53db80f44f36bcf47acead72c17825956545af4563c35777b8813b7f91ad2", .Okay}, + {.Add, "-fc7f3d93fd925d25b9b8818eeca384d6d0e138135d32c62502d7092599733b045268dc762c025b7e1628ac692ba79a1696a52fabcc6f599f97246e2be41c7483498e0138632ac53fc6b6d0b8a2a8bdaea316c6316f662352f8a30cc98264f148400d114a6b8c37aac5c8f23679470e8087be8b469be4ba0349e6effd9a05b1100ef4f7d31f40718b17e4fddb0eb89c248e27ea3b4d4d", "7c36cc101540d88a5b92731a87b7eb29bda23e18ccdd0e824dd7558bc158931f78c7548b6c8f19edafb6409322654b14d6812c386cad70d46dc71e77649b9024b19d93f6cddee3bb9644c8d224c0c43a9c747f84959b1c3b8938856fd7d1be590795f93e14aabc3b982c42ddee58f9301348de2158bef0581ac3545504cde59fc4452be6b7f27399ac20e3bea17d2c0966f368c51fcb", "-80487183e851849b5e260e7464eb99ad133ef9fa9055b7a2b4ffb399d81aa7e4d9a187eabf73419066726bd609424f01c02403735fc1e8cb295d4fb47f80e45e97f06d41954be184307207e67de7f97406a246acd9cb07176f6a8759aa9332ef3877180c56e17b6f2d9caf588aee15507475ad254325c9ab2f239ba89537cb704aafcbec674dfdf16bc41a1c6d3b701b273481762d82", .Okay}, + {.Add, "-cce914f3e45dd0a34952ab73592d87340615ebe3b0327c57be92dfbb1393fc4ccc71e5052fc914cadbc0be479241de12269e8cbd023efd447e5d895ee1f79e5e72858983179c841b14b3060f3abd4551e207582d47551762321ef617527b3ea63f3177ee1cc828629e36304c36031590f59e372260c9ef9bd2d3b2c72591007e9818708add97e95c36e1d33345a1eb3b0debdea5afd2", "815a9c56beea0cc65f92efa255a70d3a810f79f9faab35c7a5c24ac7491f4f62eb4691f6a40fefca757ab1a017a8851c0ce9f2d1ea8c7f069ce84a9981d367ae9169efb625739120252b0f5c3d1d2954acc4943962e331b0416ae527c67c5f130a75b11ae3583d39e43849afd862e140ecdcd3826688b7c37f746714debc3504922827f8fc8ecb6029f9d9dc7b832487759232187e03", "-4b8e789d2573c3dce9bfbbd1038679f9850671e9b587469018d094f3ca74ace9e12b530e8bb9250066460ca77a9958f619b499eb17b27e3de1753ec5602436afe11b99ccf228f2faef87f6b2fda01bfd3542c3f3e471e5b1f0b410ef8bfedf9334bbc6d3396feb28b9fde69c5da0345008c1639ffa4137d8535f4bb246d4cb7a05f04891e1091dfc0ce7f956ca1ec6b39859ac8d31cf", .Okay}, + {.Add, "-5dc0ecb20fc0fcbee05e1c2eee9abfc5b86d3c92095713d0616235d8d00ca6455ef4d5e0065ef6c1d467d4681ea68dbc8a4d5fa254442da5633955325fa04cd9864d7aa80d36eea5438918f99da74eeeb334aec8461b66e60336bf6f3206cc6e5d3201c9552ecc6940b1d0dc29a98774d8a459fe92ab9aa8d094ed25a65dd3d10d5d51500154d0478df5f5c9e7c7a9f0e745d27290f6", "cf839a6d27b0661bb0ba7a0937df9f8880a7bf1af2a436158687beb202bc58e175e7c24f4bef44aab16646a2f0d8f985a17d82428483df605917c4d99ed34eec614ecff1525e2f363f191f0f065d531a68ed6ec7e0b3875f76f9f7a0a73f9adbaa1182c4499b231b04553afe41e7ee2bac33a9d3b4016f417ad6816f7cf0102132734084f1523e8f56bb71dd0249cbcd1e38a5f4718b", "71c2adbb17ef695cd05c5dda4944dfc2c83a8288e94d2245252588d932afb29c16f2ec6f45904de8dcfe723ad2326bc9173022a0303fb1baf5de6fa73f330212db01554945274090fb90061568b6042bb5b8bfff9a98207973c338317538ce6d4cdf80faf46c56b1c3a36a22183e66b6d38f4fd52155d498aa419449d6923c502515ef34effd6e47c8c57c131a8221dc36f2d381e095", .Okay}, + {.Add, "-d89034f1803a97bc005fde03e08cee79b80cf58ab9fcc76b7323d182e5328ddbd8ea03e9cd379e7a2b09378d36ff9239c781574d6c81136e6768af8cde84e5217d57e4e3b1ef77b1ce5ecd6a7d510f98149b67feadd1195571749f0b6e56e9d005cf6c066aca563fbf7841f4ea107b34c7bd53aedc759d0e9ef9e9a951225e83248f9316237d94242d1626392a8f00a92c23fbbc9ec2", "13986998cd3198b83b6d0d5197724d4ecb195185858758461e416296c7d4a53b65415f05feb8a6f22714ac6e98dc7a77ac0fcaba4a7c65fd13c3ed30e93d9a970c45fb4611205aa4abf3120973db13fb5a545b2b41f95b82d2213f84c5c832c17397a039488b9cd96cd85ac76d384e3cd5436c1c439b546264c9b9c894e69f0c0c31791283ecf4746f06dfb4d9f4037b97a59cf40d98", "-c4f7cb58b308ff03c4f2d0b2491aa12aecf3a40534756f2554e26eec1d5de8a073a8a4e3ce7ef78803f48b1e9e2317c21b718c932204ad7153a4c25bf5474a8a7111e99da0cf1d0d226bbb610975fb9cba470cd36bd7bdd29f535f86a88eb70e9237cbcd223eb966529fe72d7cd82cf7f279e79298da48ac3a302fe0bc3bbf77185e1a039f909fafbe0f4684509afd2d947e5ec8912a", .Okay}, + {.Add, "be7713598b24aa192fe285fb2b0c0689858782f853b75e9fdf6d996d2cb2254ac9fceab67aa2cbed1012dfc0fb203405a918224f9fab60ca57be38414c6687713c6408ecbe1f20990e08ac50ccc5eac9a3465720aacfcb00905c63a64ec61b0c1c25553c3d68f20ff12fd56d352f421414bfcd1db08ad5f9ce5f9d49e9732c2702ad6af41e06c23af7a0feeab30c4094672faafa43c4", "f1b0785ae963946cbaf948165676c2ac2e5de45a1a62bedd3e1ba79db47886a85ebaf8cd01eac99184246e893dc44bfdae6b691988290ba8d1312ab77ff6dde75db7457033d96cfa169cbb8f20bb6a548d6fb5e5536d81857115d1e734b999d02830681aea49ebfd326e8600dfcd4c9aa9d1a06a334eb931b962d53e540c353f5dc1d073b0e9f7a29d783ea14c6bfad08027b6e5344", "cd921adf39bae35ffb921a7c907372b4486d613df55d8a8db34f53e707f9adb54fe89a434ac17886285526a98efc78c583fed8e1382df184e4d14aecc465f54fb23f7d43c15cb768af727809bed1a16eec1d527f0006a318e76dc0c4c211b4a91ea85bbdec0d90cfc456bdcd432c16ddbf5ce72453bfc18ce9f5ca9dceb3ef7af88987fb591561b5217882d4c7d300416f3226689708", .Okay}, + {.Add, "f09b50443e7bde0d9fd9146cbe5f3523c17f7b6c8c2c644741c48bcb0b4e42405eb6df126a362a372d60f2d9592d3940c354f3259c96491e13e8f595867b61dcc7dac003db99d35a4d021eeb6a339b34194c7cbbbb8b40bb9c1ec5c76efe023eae10de147a6d938714f2430116b0a689b9b65cf0a7b096a81a31cf4068a9467d06ddccdd27483e1c9748d8d7e6d46a15a7b58e0374ea", "e5ed8258bf8b688bf366f9c549e9ae20a3d4d5df7a96765f706e39590730293eede15584806a22b5cca7c7e99288ef5b72b9b19546d85b3877cbc3df4d049df0983d21ef1c9bc7553875efaef4f2054143c9802c5809f8504b3721f84a3ada4efe2845c428f4ab245887490e7b81e2d8f8025d2aa2076f6b1036facf1e9dbb17bd6b25244d586564ddcedbcc9a245952dbf00977862", "fefa2869ca7494965f0f840912fdd005cbbcc8ca83d5cbad38cb6f609bc144d44d94f46ab23ccc628a2b6f57f255c8367a808e3ef103ced19b65b1d37b4babbbd15e9222cd638fcfa0897de65982bb882d8914be810be040a0d237e6f3a1afe39df36270bcfcde395a7ab791fe68c4b7493682c351d10d9ecb353eed5a93222e82b47f2f6c1dc472e525c694b076afaad5748e9aed4c", .Okay}, + {.Add, "8a4304e315a744898113e411ec641728edbf65ae25b53c31b819ddde4067105e41ddb4a695edb16b343bf388dff94d924a24bc28da08cb44a12c2c696431f42d72140b6b3dc3cfdeb3b3bbcda34dd0def161685994cc2ae05182a5754e0e7a8517f52c914842a1151862cc05da61def5606779c46787104a070d5fee846033761368bd4ebe4c3da4eff18601c7fd106b2943e72dca69", "82118a3a9e48e83e6986e6ed4ffb564afb15f81009559adab59250d2d1d83277ad42da5fce59114e802e491d0b44d32b5064663b1ac04edaf0fbc83b5e474dcb714e2dc5c4df174c440aa54dbf27a3fd5b0b79741fef449f853ee2206bdee641f81cb8285058e43d9b66e3b74fd0f6fd6177bd51d80b7c0c0aa9bd983b297c74fd76dfe288d6c1abfdae900d690a9444918f8a821928", "10c548f1db3f02cc7ea9acaff3c5f6d73e8d55dbe2f0ad70c6dac2eb1123f42d5ef208f066446c2b9b46a3ca5eb3e20bd9a892263f4c91a1f9227f4a4c27941f8e362393102a2e72af7be611b627574dc4c6ce1cdb4bb6f7fd6c18795b9ed60c71011e4b9989b8552b3c9afbd2a32d5f2c1df37163f928c5611b71d86bf89afeb10df9d314722ff50eda0160f3107a4afbad371afe391", .Okay}, + {.Add, "b4e6ef5cd10b421a116fa9f0148909e56d10ba22f5a8322bfd7565bcd684e01fa173c31e9e9b57c1d7143607f3d425c514dbb4901ad5c53d74ae6962d2ede7508b1cc0d1423dca8dd4a7fe605378b1d3a4788ac2508ea653a145ecd9bb77efbc35726de707fe7995c0217edc0eb316938a6a4ee51a37abbd85479e23edd9d3492c636359957592b844220ea43215927dd7a48d7bdee1", "6439aa8c3b1716c0ccbcc2ba58e996a701752030909be060adef3df671e8adc7fca6a7b8b5da6f8067b009b51db3a8882fb14a68638c284a1a3d8d154b3dcd04656b6408bbde38538e91a5d79dc48daaef7e9d8d5cda5c47f88579ce4c1e44ffeb81c767e6fa5e445c214dca86ca9336d8f981ecf01dc10207b6dd1956e373816417f7ade7fcb32e5f082230a8b1c1a48440981451f2", "1192099e90c2258dade2c6caa6d72a08c6e85da538644128cab64a3b3486d8de79e1a6ad75475c7423ec43fbd1187ce4d448cfef87e61ed878eebf6781e2bb454f08824d9fe1c02e16339a437f13d3f7e93f7284fad69029b99cb66a8079634bc20f4354eeef8d7da1c42cca6957da9ca6363d0d20a556cbf8cfe7b3d44bd46ca907b5b077d7245e6a32a30d4dac754225be5259030d3", .Okay}, + {.Add, "-162f4d4d660510b6b57e39c370e782ddc79e2efc28c18c71f34b52d996740f9f344b2a2b0947a0cb85327dd99153897bfab1b34ee9313b54611945207ef8c80f5c8a644b32f9384cd9d187b2bb87302bb59952302d5c754bcf9667ede59336f99316088698be90798519592b4a868874ae233ec8d297264fe48254ca8fd9692fc0f863ea4d24433dc9d071dccfcb46e7f1707199d7bc", "3cdab4366d2d0e492c4bedd3cfb1a9196ff33c2c5bc6a00f91e7e4d6f9d3da0af1129d6e91afeb8c0d7f585651d314f46d317380e4c5f065051da50c86f3b25bc891b93551d3a40ffeb9d439b45f06063f3afde639ed7144c644a8a25fea69118fc83c98f34d228764dd098dbbb218d8919f401e40a61ac212ec5aece2b0a6bc60b1638b1983a944159a5702de4132756ba99d5528f9", "26ab66e90727fd9276cdb4105eca263ba8550d303305139d9e9c91fd635fca6bbcc7734388684ac0884cda7cc07f8b78727fc031fb94b510a4045fec07faea4c6c0754ea1eda6bc324e84c86f8d7d5da89a1abb60c90fbf8f6ae40b47a573217fcb234125a8e920ddfc3b062712b9063e37c01556e0ef4722e6a062252d73d8c9fb8ffa0cc5f66064bc9e5260e75eb8d7a392bbb513d", .Okay}, + {.Add, "-d1805aecc70f15e9f46cf28bdee5bf768e5d38336a3eeb18aa79349ee3ba5bcb917d7c9eed54021be98f82834e9171715bc2ebc40d3aef5cbb74dff529acdbacec32a35562e6e26d66186bf5a5f9e8df6b96f215ccec8e1f7c59e701aa96260e5c24705ff6238444b0ff3f8472f7b98aec4ba4b603f0d1b6695a59f7efacd983783fc2fedc3ba94a5c33f9afb1b0ec58de306c9c696c", "47df3a1bdabe17783aeb771b244756f6bd8387afc5b7a58ea6f9ff1fcb93798bff09f4efd2576f032985643317b5c2d37d8c67f2f0f49fdb47038a3472180823afe1cc9b97cd36e6be2f948b1c2d4a223d3603c4eed7cf1d740032fa30998c57781638bb27f885c3eebcdc571f0d0fbca4e2657da1395f5453849d0d8683b3ff376b0504140092e27db386560ddb978f8fa30f20ab19", "-89a120d0ec50fe71b9817b70ba9e687fd0d9b083a487458a037f357f1826e23f927387af1afc9318c00a1e5036dbae9dde3683d11c464f81747155c0b794d3893c50d6b9cb19ab86a7e8d76a89cc9ebd2e60ee50de14bf020859b40779fc99b6e40e37a4ce2afe80c242632d53eaa9ce47693f3862b7726215d5bcea6929258440d4bdfac83b1667de807359a3d554c94e8d5d7bbe53", .Okay}, + {.Add, "-9f9bc83773f8655406eaa8df5ba51978f005c5929d361214bf14baf306353cefa2455a75350c254e3d03db7cb1d56c814f53f6939c887740291aa3c770b49bc3c77bca2b45e8b1cc82fdb7c8b482187ac6d5b5a3cfd99d48db6e1922422f848f6b20f1b9998aa378f21ed92a13c5461c577f8abf017b3492a2353ed0b9493345ab97718575dddddfbd787eecd9204f3799b27000bc52", "1f8d5e5c74b9c6abb9fa152e1fe93befac2b6aff1e76f6097f8573d79572dff1c3d7cacb10fcb2bd11b87436bc174a71d7f398009791b29c0452e9d9c7af267758510b14fe5f481581957e10e9523a41a382f79f300804a933ccc16c625451a5346bec648f227bf3dab46e77e52a0f7116c30833e87cd4aa4c288d41515004f9c56259509615df635c77057d1436ef409865badc3bdf", "-800e69daff3e9ea84cf093b13bbbdd8943da5a937ebf1c0b3f8f471b70c25cfdde6d8faa240f72912b4b6745f5be220f77605e9304f6c4a424c7b9eda905754c6f2abf16478969b7016839b7cb2fde392352be049fd1989fa7a157b5dfdb32ea36b505550a682785176a6ab22e9b36ab40bc828b18fe5fe8560cb18f67f92e4be6351834dfc7fe7c6101796fc4e95ff7014cb5248073", .Okay}, + {.Add, "-4a3d3a1d157a78430431d06d0769cb33dd6ad2a21a5553b6a78e49f73d5d72446b8ec23337e2619ea70550861c64df7d27ec00f6a622b4bb7566cd11e87c0363e25cd7ddee4b620d43e874562f22cd78416b14308a4fff9ce17f429552113c523303db10420a7ce82cc27ecbb04479fc1467763d97492dd02a37b75daebb76689bff26afb29211ad93d54c14e01891135bd501008150", "4ede342339474be61c8e9f2c4aeacba46ac9708472cb7ae9dcace7942b7c733977b2c48daec738c1a7a9d1407862a8647941d728ae2fc445f80975a8b7f8af2a219a90b53d822f598284c12eccf8200fc1c50092044990c2f189e831530a548ebf47993bbb5b6deac332fe61b6d185664407e5b5f22eb1c96b2369a4f104e1e6b3afc4b943b0d40d4d6f52091448272900ee29ba1b6c", "4a0fa0623ccd3a3185ccebf438100708d5e9de258762733351e9d9cee1f00f50c24025a76e4d72300a480ba5bfdc8e75155d632080d0f8a82a2a896cf7cabc63f3db8d74f36cd4c3e9c4cd89dd552978059ec6179f99126100aa59c00f9183c8c43be2b7950f10296707f96068d0b6a2fa06f785ae583f940ebb24742496b7e17b09e09911ec25fb99a05f4342f9615a51928b99a1c", .Okay}, + {.Add, "-54439616ede259c214b82c0a5c7a1def22ea2e0de7310f7881bbc247bbe67c6981a8ac1d994ae3dc54d09e5321700ae1c2a99abdb4d8b2863c82f8c493bf972fbf8ab156ce88998e246653181fb8a9ec8fa7e600440912cdb954712680194a9495da78da04cef56a05a95c91028cb052c686488fa28e71543e207847c71b1f2fcfb06210d49a44f12cc5ab6a9a41e0f944acd0e64bf", "9ea9d5c049449b0394e3d24de0858749d1da2d2ac7421aa820c1443887533c58686a28de984f929065c4701e933ef0fcf06ec96224686d913cf253e156150bc7d5b862d23df695a2cff457014c71738e8e5cbaaee2d5ef3225f39d25cc3be98c378057d644d3a3e09578cfe1443f5e0afc197d80199893c34c50dfe259c89cd51558902e2675226f34ff63c5eb85d260f63689902c30", "99659c5eda66756773984f8d3abde56adfab8a49e8cf09b098a588140b94d491d04f9e1cbebae452a07766396127f04ed4442fb6491ae268d92a24550cd91254d9bfb7bcd10e0c09edadf1cfca75e8efc5623c4ede955e054a5e5613643a54e2ee22b048a486b489f51e3a1834169305cfb118f71f6facae086ed85ddd56eae2185d8a0d192b7e202233090f41e1b45161ebbc81c771", .Okay}, + {.Add, "289668854d82ef0ec228b59f5770a1d38ec15395b20ceed6e71985402c774fe1b38702e8e5e5271df77e074ea58ce1788cf72f007ce69d89f5873445cc5b948dbd921c45bc9ab55c743088ffe185e261fe633f57cd6d28f93fbd465363a09b38a0a0e93751f0d982d4ef0963500e63c9d5211dd763e2eb04b844e7ac266c654fa4861c61b9618e05b3ef7dc47022f1ccf45b2e902f7d", "9fa4e3bf50bb6049157c4487904bb045cda4879d155bab2e865cc064990f25b70c8d6a732a62eaa6a92b29cbd3a62aa25c6c57954e0304384a59f0914789866a8c99655ba3802cd5c0de6416bc7574512c5a43531ffca2ae6dee2d98ee85cd69a824b259d71fc9b5d987b3e5cff97fbcf30129b7985c7a1dcb8157a663539a462ad2305b062494d36dd2380f9609e6a6f390df05ef71", "c83b4c449e3e4f57d7a4fa26e7bc52195c65db32c7689a056d7645a4c5867598c0146d5c104811c4a0a9311a79330c1ae9638695cae9a1c23fe124d713e51af84a2b81a1601ae232350eed169dfb56b32abd82aaed69cba7adab73ec522668a248c59b912910a338ae76bd492007e386c822478efc3f652283c63f5289bfff95cf584cbcbf8622d921c1b5d4062cd873e7ec0d961eee", .Okay}, + {.Add, "4504fbd7ec2c1abcb92ec40e5470403812aad380252c4ec20fd58b8a6485d0773796a29da0cd49224fd07c5d0c209a05faaaeb9232cbb9f3e8bf45747160e7499e4df7a7d0c083c49e3512ae14df62dc4f900afe1142df353fb7ce737f9e8cb713f79ec200b184b036a96b6ae9e3eb1303d36800f9ac914d770e567f1c949a2a775d0e4812c02045364bfbb18b6cfb5908df0df8db76", "58099286ed236f9a9588a5bc1b4182de74245dfbfb444cc6d43e3a39ab2ec7af1a71069606b3807a756dc70b9aa83601fdcf9b7fc806a51928f57f0cace7cd7812b9dda7d8c550be7641188bb8f0bb00099c221b434b41e00b64183985932a0a4e4602e408eb8cd3a36e517ee46f81d861a06fa0ead9cc1ea7a98c5981bbffa300136266eac7e175989f12b88ea3d7fe815ab7fbe096", "9d0e8e5ed94f8a574eb769ca6fb1c31686cf317c20709b88e413c5c40fb498265207a933a780c99cc53e4368a6c8d007f87a8711fad25f0d11b4c4811e48b4c1b107d54fa985d48314762b39cdd01ddc592c2d19548e21154b1be6ad0531b6c1623da1a6099d1183da17bce9ce536ceb6573d7a1e4865d6c1eb7e2d89e5099cd777070aefd8801baceeb0e6a1a10d3578a39c5f4bc0c", .Okay}, + {.Add, "38d9b1b3ccd6c0ec2b03b75dc1d084c60bc0b6ddb8e34ebd98a3bd463720cc7d08574c35a5bbc480f8d01a2f10f86cc22448a6973b236d4e3afc0300a227127a8a4d7033a952db66579f6533434a41cc56cf736035c6d5b49e3e241b64fef0972200b868bf805225510b61b0dc79dfb01ca309cc66fc99ecd009968249c24d348f9b6c04ce7825ef5ac1a2769ce51acfa3840f0675f0", "fa0d6e16dee75b40c59f11cc9c774996752bf180c64924553bc5722f6afeefbd14bb2853c421a07ecc3c9a2d5a6cb08c82b9dfbfe413c3148d7adcef7d73312611e55dd4d5f26ec210ca13bd64cebba487df539fba0d3de5b44ea84c4015d7d03e5be1b23978ade9135e41716e44d8bd376f9861c6d31b083f16f49bf28f0741dae1ca336ee5bb27dd3648c74d5f0c57403a967afba6", "132e71fcaabbe1c2cf0a2c92a5e47ce5c80eca85e7f2c7312d4692f75a21fbc3a1d12748969dd64ffc50cb45c6b651d4ea70286571f373062c876dff01f9a43a09c32ce087f454a28686978f0a818fd70deaec6ffefd4139a528ccc67a514c867605c9a1af8f9000e6469a3224abeb86d5412a22e2dcfb4f50f208b1e3c5154766a7d36383d5de11737f7eb3dea442726e3bea5817196", .Okay}, + {.Add, "-716dd5b720ed39cd662b8d798c2caa84839399d377f5ce48bdaba074b83ff062eaa82a3b48b4dc2d1c1133070e95cf21f0ae1887e788e36a37fe8de52868c975a60dd7bf17291dd27266f8c16ca4f5b7d64f9655b3be6391b961580008bc299f7d313488e5f9a7ce4b0064874694f2dd31052ba48f5cf572d892d9cf46a8cb1f67209aaa0d8005977a6d9c0b468edfe111dfd0ae2e7", "e515e3ef9b21c45dd18f313edfa6ce7ea698873215d510d29972e13efa34cfd0bcb17be061ee65d8341f737fb63c7afbefdff42e09843f4fb9c7a411df5ae7b4b08b0616a2bfa3e1d491a00b72405c6a9c5cdeda6219206a9ad3dc2c0b3bc5fa5e2293386d1defd0784bed5f91e65ce8d4947e6eaa1fdbd7fb211809d90a62a368acf6044088f1e3d0fab74f11c228cf38223f7fafb9", "ddff06942912f0c0fb2c786746e403d65e5f4d94de55b3ee0d982737aeb0d0ca8e06f93cad631815625e604f45531e09d0d512a58b0bb1191647bb338cd45b1d562a289ab14d1204ad6b307f5b760d0f1ef7e57506dd3a317f3dc6ac0ab00360664f7fefdebe5553939be7171d7d0dbb01842bb4612a0c80cd97ea6ce49fd5f1723aec599fb0f18a5953dd8e5d593ad127044274ccd2", .Okay}, + {.Add, "-d994df8ab6c3bdc16ded508afece30675886cd72de50f4570e94405a35c8ade6818bc27acf63832735c37e62e0b753c0cdff586c4cfa13c0672cf5dc875194b74091d27ec25592d4ee7bbe54f299a48565a386403b5218a5fa310f784976825950488255adc61b708215343f0898c214331d7f637b72831fc8d2b6c0f2277cb70fcfd74c1fb34147d4e9b0005266af619ba15eeda5ad", "dfa1da364d904f4fd80d1a35c4ff3a761bd8dad8c2c7427613b106c478be33816166e9bbf64546983187e24db87e3a6b422e0c781924ce3340a48c314d3b8f17e1d12794232822566f391a29a912c5f2aa3103f97ac794c7f76449efef3fe08b70aba44de9bcac8f04214c350a986ffaf6a393f01acb2b9af9f78fc3e60c645fd8e7dadcb6a758ee86a2b2546c1112cefbcfddc073ae", "60cfaab96cc918e6a1fc9aac6310a0ec3520d65e4764e1f051cc66a42f5859adfdb274126e1c370fbc463ead7c6e6aa742eb40bcc2aba72d9779654c5e9fa60a13f551560d28f8180bd5bd4b679216d448d7db93f757c21fd333a77a5c95e32206321f83bf6911e820c17f601ffade6c386148c9f58a87b3124d902f3e4e7a8c918039096f417a6b1b9025419aa636d602e7ed2ce01", .Okay}, + {.Add, "372ad1abc567667457fa276eef90459c43b0b49d98c021a281f12cc62d7658866b6b65cdc30581620420782cf77960358da7031a31e45969f1470092d236b604de2cd890e76577bbdcdc8fc049320679f04eac70697227e730fc90453e447dec35866561cce1fc7da3a7a81e07aff0c359693227ef6d2603131718537385bf45289e8d0cca21b34ec9abacf4e068aeb85decc62608ef", "8d9cdbd9abc3973e7424195865393354560d646ec4dce621d3e05b1f07f9dbc28de2153745121595f16b845a613a26b0c7f519e2c03e8c9388372674cc09cf4130b96f57bb0208c389bd7631e5f36a207c19c9fc862419026d5c7c1480554313ee1faaa3549ae701a1913ec56929851f45115c611c54d4741b06ca6aa53b7b0b071b7adf6e778182cb6bbe0c83d92307687a027f5487", "c4c7ad85712afdb2cc1e40c754c978f099be190c5d9d07c455d187e535703448f94d7b05081796f7f58bfc8758b386e6559c1cfcf222e5fd797e27079e4085460ee647e8a267807f669a05f22f25709a6c68766cef9640e99e590c59be99c10023a61005217ce37f4538e6e370d975e29e7a8e890bc1fa772e1de2be18c13a502fba07ec389934d195176b016441d1bfc666c8a55d76", .Okay}, + {.Add, "f0b7cf82bc313132005fcc4b290328eee5adbb2f9bfe6b46fe5b2426cd07e25ff6937247fdb2db580011df7a7695cd80b685cd9c9d5f454f4694ea703323fa15550dca66b28fe80d4a262e0431a5f0d797377705933c3164c584f99aa248a4bf90dbae99d3119e6203b8aeff486bfe8b45b4cff5cb6af4f3c07a9c339c818085ba39d374794a5249f788db69cef00976b27e83fb84cf", "2d803250ef80e4bfe4c84a4246e4c519e51d35ae0a1f05978cdf81ea3737cc90e33659261e1310dca95b584e989e13b6c2aa83eb4ae7a203ca1d0cbffcd21f6ed135be9d86aee76f8e5557915059a244fc4229bf293ba887e12a7095c4b34519d1be350d0677ff8b5d1da0c1594eb9dfc43caa313bf5b28c941372785308cafbd35dcb6ec58937a30514530ffd840490d344bd7755a8", "11e3801d3abb215f1e528168d6fe7ee08cacaf0dda61d70de8b3aa611043faef0d9c9cb6e1bc5ec34a96d37c90f33e13779305187e846e75310b1f7302ff6198426438904393ecf7cd87b859581ff931c9379a0c4bc77d9eca6af6a3066fbe9d96299e3a6d9899ded60d64fc0a1bab86b09f17a270760a780548e0eabef8a4b818d979ee33ed389ecfc9d2e79cc740e0785c34172da77", .Okay}, + {.Add, "c7a79b0b1f42a46dbbd79e7738b3bf035d397d38e4fb592c1520486c7afc38a90d756435b5a72c3a4f4d635a97472353908756b5981f9f3ab234e8bc2b4bacd9584451ddc6fdce66ed4b77a16e4555a2404d3b24188307cc93f4c533f2e2280d7ca9a8eaa2a579ffe5d7969a186054232234ef3a9958ec10225e092a2f45744e4b93509a2efa731cfee23da0ead3545e6d68fe5ceba0", "c7ea6381cadd647f69062bfc04de4fbf9e5caa352f0350eaad281fb04c05b8be5d6cd8c0f493c82161b5e6fa0b07b0ac59d33a0b6e8c92498e2c4a1b5447d0a20e64fb5397d2f3869c6cb4e87810d7044e0b0efa58c613a9ddd13989054e75716123043ed6227091ccadc65978547d2a0048bdafab09b00edd7f6a3e82c43562f2bc13e01225773bd9ec874dd33300b9ac7e742869f0", "18f91fe8cea2008ed24ddca733d920ec2fb96276e13feaa16c248681cc701f1676ae23cf6aa3af45bb1034a54a24ed3ffea5a90c106ac3184406132d77f937d7b66a94d315ed0c1ed89b82c89e6562ca68e584a1e71491b7671c5febcf8309d7eddccad2978c7ea91b2855cf390b4d14d227dacea44629c1effdd7368b209a9b13e4f647a411fea58d8cec4eebe06551819e772855590", .Okay}, + {.Add, "761b64692affd01b05a902ffa9cbafe12aa6bf0671c244861b8810302deae23b8611c62bc2a4a479d092506924b92494e7e975bbb70dc5a6f93cf170682e564e6e8f00a663110fcf062e578f8e760ca2e82943a85c28d535350fdae1aa802fdce6ebd9676d20d773b7478693379200f374a4804a9cc1da31775a547770efa78210163da8fe930c833e5eab4c645173adf2c34bc9c347", "2c1f9121d6625cc7ed1195719a53101e5de5cb2ea50eecdc7e91521976ecabff5e0782cad8b1d6918705dd938e756ed74475a5001112646c12fa657f5c6e5b3635f839c17e2c7a5455c395ffadb9e00b9d8addd508c2f9e33561bfc43650e94307f0ed4559e18fdb02a0bbb3dae2dd2048a7f59e2269f5bfcdd189521495841cfac7ed40c069ca1ce577eb1fb734c0c429030c927478", "a23af58b01622ce2f2ba9871441ebfff888c8a3516d131629a196249a4d78e3ae41948f69b567b0b57982dfcb32e936c2c5f1abbc8202a130c3756efc49cb184a4873a67e13d8a235bf1ed8f3c2fecae85b4217d64ebcf186a719aa5e0d1191feedcc6acc702674eb9e842471274de13bd4c75e8bf2bcff1452bddc985852b9f0ade2ae9befcd6a023d6966c1b8634721bc6585c37bf", .Okay}, + {.Add, "-d68d4e65052c350ce980e154551dcff180dce4f717c0843fac7e6def983e4813db6821814c0bdbda303a7f75903e56d41727e4b7422a6065058a79a6bf550266d4b636f3da913821a3c4fea9b0bafdbd42dfb2967a9c4620e8fee2faeb897c4e605d0765ebf3321ac0e4a1476ee6374b7af459a7e5243fb0ea6e9770c41983a570abef34af0f6606327f9ab7d74b4351ce4c7047064c", "4463ee651423e22ca0f45fbc9511c7f2214caadd9ed5bd5368178e378f8a0cdb5c870dab18eb57aa452e540c86ff0a8d625011e9f32d34efd14a29d64ae8cdf6817fd3d4f146ca477332e3678a7df0904e83d2925df266739345e9b0a579888611754fbd8e957c10f581113d4fc575fdf432ccd6190ed5ab73270d7424954315146aeaa4e6dfce2fc934b185531dcd9e44a32c124b2a", "-92295ffff10852e0488c8197c00c07ff5f903a1978eac6ec4466dfb808b43b387ee113d63320842feb0c2b69093f4c46b4d7d2cd4efd2b7534404fd0746c34705336631ee94a6dda30921b42263d0d2cf45be0041ca9dfad55b8f94a460ff3c84ee7b7a85d5db609cb63900a1f20c14d86c18cd1cc156a05774789fc9f8440905c41048fc82f97d6694ae932842d75b389a94434bb22", .Okay}, + {.Add, "be6ffe4f3ad0a80ec2f503350d27ce704b80c736f91398c703750f9ef0519b5560f7d2b16f72ecb81d98d104df2f4fe3036b50899b7f86f569ab8a7df0c5dd792003bc7adfdb22fef2d659f408a78829d50aaac5e1d79d2c55e15b59cfd9f938f819bf312bdec4e2bbbc251d022fdd26bf7de5fa2cc95db1b00e6bd8cbf317080ea7674b020f6b0c196d43a5e4007972caa58a3c2f60", "2f1b04b7a63e1601e1e99a42f845f9ea762880ff5893043d3bbe53c37e41eb8feb5a5a936f9e3247a9b5f40d398a97a2ba40b296548925bda76349c2d2849ef406a242a082e4dca388d2adaa0378a83cad2fe24772a616c2d17cef9a878547a23301dabe772158bae84d9def24ee1e7ed6089d8b88ed3b4d6a50ec221179746d9f65bcf04cf1e051db4d62e26ea57f9b93dee9b0d7ee", "ed8b0306e10ebe10a4de9d78056dc85ac1a9483651a69d043f3363626e9386e54c522d44df111effc74ec51218b9e785bdac031ff008acb3110ed440c34a7c6d26a5ff1b62bfffa27ba9079e0c203066823a8d0d547db3ef275e4af4575f40db2b1b99efa3001d9da409c30c271dfba595868385b5b698ff1a5f57fadd6c8b75ae0d243b4f014b5df4baa68852a5f90e5e8473ed074e", .Okay}, + {.Add, "4381eb2bb7f24280687f7dd3f56520ea5813358360bcad80f55fff158a2074c82c98618c6dcfaf1374af3a5238e6908049d516368b52176ac02e3b1746f1d5aa29493d4f7975c7b2e5957ce7f326e0a7f47b5252c9c901abbbdfa710f6c03e8c17bc367636088db671d82b6cd26c2ad1916b4693c4bfda04fceddf8ecde771355c2150100c2e9a7d7d53a6ef7397820c9212e799234f", "579c18f2f2d188a00c9e29c633efccee44acb1d30357c729f0ce26a68dbe9c5463899c292933a26a739ef2501f0102ec4c472a7eed751c58ccfcd3ec4749016b56c25490fad2e233c37d6be53a0e3825c16c2c1c2ffae0c3653d7e7a25501c95e74ac4811918aa4e20d1e6e1c4de9a5fb25dbf39db8c59c220739c61fb66da14872ebabb36733caf8f210d79b793917a1aefd68a7572", "9b1e041eaac3cb20751da79a2954edd89cbfe756641474aae62e25bc17df111c9021fdb59703517de84e2ca257e7936c961c40b578c733c38d2b0f038e3ad715800b91e07448a9e6a912e8cd2d3518cdb5e77e6ef9c3e26f211d258b1c105b21ff06faf74f21380492aa124e974ac53143c905cda04c33c71d617bf0c94e4b49e3500acb42a1d72d0c74b4692b2b1386ad02be2398c1", .Okay}, + {.Add, "-d34554b584a81432bd07a82a57b7d2aac43068e1e9232ea7895589db2f06c3ea736c1cee90328028b5f4b6ee4ddcd39c4c9f9117be6114837be161410ab377ebc37a5cf3b1c22875cc0bb66e12ecd6d3f5dc1e2d22ad1a6214884fb5c8b5ce8806d80790c0d61c31c815fe9606b451d1f1382ebbb0a5fd85e4097f5e2fa6b5e481aeb295e764c717ed0ea7165a2abb02bad390b8cac8", "15f8b121d4a4b37e0bb13efd5fac6cb141155f3c3f68831d1b8525d3abf6ca4c7bfff77f512d1ff4d6b9bb1de1a46dc2a2b0a1895b403e55c7dff15ecef2898f74d9a4ca83a8fdfa03dea3085c55908a98a73c00bb155d0f4e6c9628e035975749e57ab73516bd0700f9563d19893457478c93cec79af93dce7fca34c920976c96ac3318ec4f0929c387a649eaa60780388f644b5f76", "-bd4ca393b00360b4b156692cf80b65f9831b09a5a9baab8a6dd06407830ff99df76c256f3f056033df3afbd06c3865d9a9eeef8e6320d62db4016fe23bc0ee5c4ea0b8292e192a7bc82d1365b69746495d34e22c6797bd52c61bb98ce8803730bcf28cd98bbf5f2ac71ca858ed2b1d7aa9ab9aece90b04481589b52966861e77eb027f7cfb15bdee298700cc6f84b38282442c6d6b52", .Okay}, + {.Add, "-2dd3c016cafb9720f1575d6db270ac98b91eb1f84acf64a3558d0c984a0a8e693c8db761ca2e8d005a606a6315cf083ae12702fb0dd161d3394aca3cc0da9facc3ac09d5107cbccf385c5aaa6eeaa7d772060253ffd82f9ce5ee3b855a5b41c9c32020579a0b271060c6b250893cae5f0838c85acc40f399753395009b8aaf641a1a06a5037248ab0ce2cc8605ce31e068c80d4697e", "b07ddb83555e8c44751d636dd833b43738f87f2838cd28a55916ea1768e5bc8d82ca85367dd5eed57886eaf612a59b1d36d9e88aaee7e406972e7539b4ab694df3391f7f1d6ca6ee7a36cc3eca0f24f215d73166b9702f5a74d3a0a681cf43d175b9cd9e4a1298f8dddb06f25804f8b935b9654436709e893c0a99a06922eedd68b7a102640be01cc91544cb3b286c291926641160ea", "ada09f81e8aed2d26607ed96fd0ca96dad669408b420325b23be194de44513a6ef01a9c06133060572e0e44fe148aa9988c7785afe0acde96399c895e89dbf5326fe5ee1cc64db2186b1069423207a749eb6d1417972ac60a674bcee2c298fb4d987cb98d071e687d7ce9bcd4f712dd34535d8be89ac8f4fa4b760505f6a43e72716009813d4bb9218471802dacb890b1299e33cf76c", .Okay}, + {.Add, "-aabf8d8b4ad4fbbccbc4171cd8991e6cfbcf0954debce0b8b245c7379c8770cffdbe307b3cda1519a72a15b78500f6dd6b985152629cb6d393f5aebe84707647cf15ae24a696cacd7fb8645d182087ef299fe90ce2c182d9981a57feaff7ed0a2f995765bbe8174afce1c1cfae1acdffbb572dde200b358a31c3982d4d20d4ec344511f466bc729a179c99ce7b13c4f01e3d3141c592", "f192145011e794c2de8411b7463138acce2e0c22c069b007f12d92b35d000a0c9ea1dc86269183111f94ac31fb0bb38baaf599f16d6271c82c8df0542b30d0c17ff2d088d4c7aa40bd7bf917dc2c5aa52c7b7494e124e01482fb75edfd56c7a16bf642ce886098277b3895a44822bd97eb4ecdc12f106058d6ff438ad95ae38d24a92dc73092681e2a2a1440e560d25149a04cf899ae", "46d286c4c712990612bffa9a6d981a3fd25f02cde1accf4f3ee7cb7bc078993ca0e3ac0ae9b76df7786a967a760abcae3f5d489f0ac5baf498984195a6c05a79b0dd22642e30df733dc394bac40bd2b602db8b87fe635d3aeae11def4d5eda973c5ceb68cc7880dc7e56d3d49a07ef982ff79fe30f052acea53bab5d8c3a0ea0f0641bd2c9d5f584128d7a726a4d0d612b631bb6d41c", .Okay}, + {.Add, "f3f6c3aa8116caed10008fb4c595c55ecb110ceeac3a43c1a0608d7e058b5311a016e0d8daae24cf40b41950d5706f1eb730c2bee2efda6cf55944eb8384ed8f58bc3d8a346380851df98271bca77533936f0763a9a91431f76b23d326e305d659f140fec195e8c301a97117c9cd6bf26ce546ba01457f70bc7044e02e714d5c9c56632d219d8b287cfaa542829fc3b2bdde3a2df6af", "116bc9b9fa743f1a30df81abf24884e76a485dcb9b3e18e85166bdbfeb489bd41640adaef48b598cb4ef6d49d79e96349c78b74f06397d451c65134539c6800d829ae850460bfbdbf9a04637ee27d7046071ff97a20273b202c538d7038f9e16be4d668239f5033dbfbd390f647294642a2fde78dc0e157c80b4b425b23c562a745d4cf6dad18cf6c7f760b06f1a5561fb3dc9c2c2df", "105628d647b8b0a0740e01160b7de4a4635596aba47785ca9f1c74b3df0d3eee5b6578e87cf397e5bf5a3869aad0f055353a97a0de92957b211be5830bd4b6d9cdb5725da7a6f7c611799c8a9aacf4c37f3e106fb4bab87e3fa305caa2a72a3ed183ea780fb8aec00c166aa272e40005697152532dd5394ed3d24f905e0ada38710b3b023fc6f181f44f205f2f1ba1914b91c03f0b98e", .Okay}, + {.Add, "-f0c224aba19d92d3a00d5c8383cc5d8d46f64d3274d0fffc9a543b038e2484b6da0153eea8a859db71839fa6aa093ee7484e2995d81a65a3a77f1477b4327468c2d43a4d153199bef37cc46fefd9f4c220feec4594c6d745b293d1e919c288651c426f3477cb06e5b1ff204845abe228aa816a6403c615d14d667543d3620ca257c5a978322e42ef572296c1d1e70973b698b1495b", "64ee5a41521d1b26db1ae59121dfaaddadde1408b7d19ef232a38db94a95074cb179776cff4f421250ef84d61911bd152396203ffdcede34701ab9feeed537c3b522397bac061492beb40c1f25fd9860269ccda909ef4b1cac5470dedb356d80403fcd13c95b03db03d4c836fab2881a023ce12bbe167a92e599054be381822151d61097fd0a7955e7eec6088961adc22abf173e4796", "63fd981ca67b7d94077ad8349e5bde8020971dbb855ccdf23609397e4706e2c7fa9f761910a699b8757e01367267b3d63c4dd21667f6c3cecc733aea7721054f4c5f65415ef0e2f8ffc08f5ab60dbe6b647bcebcc45a844566a1dd0cf21baaf7db238aa494e338d41e22c916b26cdc37d9925fc15a12b47d144b9ed69fae2014af7e4aee84d84b12f897a371c78fc6b8b7087e8cfe3b", .Okay}, + {.Add, "-9928fa0a3635c0bd71b050764fd7a14b11219a3575bd87504ca483d93deff2e74e569957ea2a69ff5be14de1f508d79acb5c037aaca1a6f899b375c561fb2deb549babad83adab8e95764009343e94d157db3b97b1ddfc0db7fb7fe4fba9bbf4d47766647103f8f1eb891d7030fa5e6f88da1e232a3341fb00046aee9c584866ffcf5a573c47b3b1b0bb9b490d8621e68578ce40d1b", "7c4199ea1019f61c103899d93dd9f52d39cd57f13b7cf060d08b79a76b893b66be74ca5cfffb1ccdbd0e3c8f8d903f4e71924fa100a79bdd450676022523fab5f6dbb5d8de48cb7255b5d0936babb89cb1ac1e57f48b54549b91ecec758caba10c06364cd56c3993985f0624cdd184aee20899fda7166e5eef41ef6f7a5401089179fb3afc28179ef0780879b88f740ca4deb479e16c", "72af0a496cb69a10391d94d1d8dc7b1888bb3e4de42117ebcbc13169d7aa3c38498f60c78158762dc75027b16e3fb1d4c4dc8f6955dd816dbb6b3ea5cf0447d74191fb1e060df0b96c5e6c92d867cf4f9c2e6a9e796d7493c01234ee25d20fe1bebebfe68e5bfa0479a6744dcac1dec7e97af81b74733a3f3f41a8c0908e7c82217d059588639c63d56c4ec527b711ee3c872795d451", .Okay}, + {.Add, "-a24095719c0cb134e6e4f5e395b15adf124b29bc0135cdf7df92f1b236390cb55dfd186e7dc46e0f89be1790f040a2edce0e9b806deb5a896e859c133ffafb9332379660e64246fa765e2cd543bbacb28d1d2ec9cc3413d7c2bc3f06e3b6424ce3ddfdaa3d6533c51c890e4aee9383564f6356a4d6fbc6c7d674420d00bea8b9275c8256357305dbd7f896d1fef846b097a9b679c7d0", "699cbe1fd7adcdcdebbd66481e62e240d384162c29b100957b70a188262a31273f0fa29048739f52615a4672fcea721ba969fee4f8420a0fdc77833d726e8b5cf59cafea575543521e6361d76152427775d144380392d5133fe8fafe5d583a10bcfc2fb2207e2bc79cab8fe326a9ba0cd7205068ab93a9cd80d29e858590094fefb6f778ae77b030dd6b2c89df0b47a9dc96f257d60e", "-38a3d751c45ee366fb278f9b774e789e3ec7138fd784cd626422502a100edb8e1eed75de3550cebd2863d11df35630d224a49c9b75a95079920e18d5cd8c70363c9ae6768eed03a857facafde2696a3b174bea91c8a13ec482d34408865e083c26e1cdf81ce707fd7fdd7e67c7e9c9497843063c2b681cfa55a1a3877b2e9f6937a58add86fb55aafa8d6a481fecff06bb12c421f1c2", .Okay}, + {.Add, "60a4de167f9611d237771b12be26038cefee10400020e15534684e71adcce76898e08f65aeb83963e27024cbbc49968205e83ae237bd1ee0ea2ccf4f92016232c98a284352f31054c3206c22e6a9178837a92fed828797c5db0b9f44df1abb60d039ed53a9685b3b1332d5c47bd88c05e4b944d425298e2e8cddae28405ce4844acfae6eefd8e97ab462d5180cd0866ffe043faa348a", "18aa129e27987d3dbc076bea5b4fa54ecfd25cdf83de871819a37bd9d34360ca3b1a1f6af6dee6d828a1a71c6b02be65437ccd96889acc817b09f48b76e19ec5af7d4598cddedb0b39b326422effb12de31071ab356c7c3592d3afadcafa851c9b048bdb0db34c09827faf4bbc908a5a60d7bbe8bf78b5252f9f4a63ae9c66cea20e923b31df61b3f1a82dbab0f7d037b40aff48189e", "794ef0b4a72e8f0ff37e86fd1975a8dbbfc06d1f83ff686d4e0bca4b81104832d3faaed0a597203c0b11cbe8274c54e749650878c057eb626536c3db08e300f879076ddc20d1eb5ffcd3926515a8c8b61ab9a198b7f413fb6ddf4ef2aa15407d6b3e792eb71ba74495b2851038691660459100bce4a24353bc7cf88beef94b52ecde40aa21b84b2ea60b02d2bdc856a7b20f3ef24d28", .Okay}, + {.Add, "f2f1cd1f31c0a1e00df1df1f76b938ab881f7f873b301f2368dbf347936f238ab591a8db0efd2cfb20e2e5be64a37e0f19ea5a8025559fd9cbddd70e4412aa2b2088616e5e4ffdd234560e4c0d2bc3fcb82e7fd4e39a8e1acb13e64b1f472e29a5a8f5d81343b14e753f0e1d8fda53e8159949b1a76b5ae4aeabe15e767a1c9e2a6af77ceaf66f4eb80e5a8a66a610af856d706de428", "227d6661058da56c3d578deb1aa957ea29fabc32c477c748a89578eff022a822e7f11234f746f0d556fb269115922935505a2ad3e8c52a8150e31f00b9cc34206fe529f0c03aa637f1cbe4a135111387bfdbce806f60ff0208418801daaccd2bc55b1c92ab7d6f9accdb77c8c345e80a2bfb367dea9628df957ce73b6a39bdf52ad577c138704b1d7a5c8ed71d5d4f734171ea336ae3", "1156f3380374e474c4b496d0a91629095b21a3bb9ffa7e66c11716c378391cbad9d82bb1006441dd077de0c4f7a35a7446a4485540e1aca5b1cc0f60efddede4b906d8b5f1e8aa40a2621f2ed423cd784780a4e5552fb8d1cd3556e4cf9f3fb556b04126abec120e9421a85e653203bf24194802f920183c44428c899e0b3da9355406f3e2366ba6c326ae96184036022c6df5aa14f0b", .Okay}, + {.Add, "469399830b30878f43d2fea8f6b720f6d63be396cdac2b6037ee61af1099c58c42c6df7d6b65d720239db219a15674b1fc1b000a01ff76fa211a8b300c286d3d48c387b7e23c8f659f68c37008b09fad2a6e9e4a8a7b7bf98d17c459a7b4da4751e4321570fe7e62ec8e8ba0130753824764815da4553f5b45026944cb91330d38d2b386c922659790ab3c22203d4e3524530c0cf29c", "b041205baecbad6ee1f7a5861b35cd467301ea42ff51944e3dfb073a486dc36243b58f51889b824581ddf83113d3a04aa43a813c7c6cb7fb2fc0d4ea9a38120fa82ce45975219a6706d09badc92684fe6a8e0f326a1ea68b639cdec69ad6aeb82d4c7bb222c954d2ee5ebb92ddaa3d21810417bb5e9e67a9255164257569a7aeaac1fe06738b0fbc337e1f19a4a373030a143e2fdb54", "f6d4b9deb9fc34fe25caa42f11ecee3d493dcdd9ccfdbfae75e968e9590788ee867c6ecef4015965a57baa4ab52a14fca05581467e6c2ef550db601aa6607f4cf0f06c11575e29cca6395f1dd1d724ab94fcad7cf49a2284f0b4a320428b88ff7f30adc793c7d335daed4732f0b190a3c868991902f3a7046a53cd6a40fadabbe394b18d3cad7553c4295b3bc4e0c1382e674a3ccdf0", .Okay}, + {.Add, "-56118f754b60faf0b274b80744248e042d0cc110cc8b968548971d0c617f37a21903b28a8ea4dfe51821891dd40ea3d0d8ed786b129212602ebc0c3a622e651e17ca348c4ea9dee68af04259e147e456b76379e45a9f180bceebf4111587a9c2281c0ac2c14ed9e580a14fe9e4a10158b0555c19be78f423106766bf286c32e326f5d87f9864559e1129c3f0586efe88e33a671e1df1", "d2bb1332aec63d38521b9a25891c9c029f900391a0635be65eb6552dc9cc3fa274e74739b32dbb0c8a4e6c07478155ebeef1628b8c2db7c90d14c81b764a3df27e15cd86313928b96a05b99b8bf3e83602d84bc5fa695fe53f85d706edcfaba8070eadffaa50aee0eaa234adcd5253f5619bc97e6f5abd501b32979a3b24c93f09c32ffbbd7321721bb006b45f01407cf7c08e123ecc", "7ca983bd636542479fa6e21e44f80dfe72834280d3d7c561161f3821684d08005be394af2488db27722ce2e97372b21b1603ea20799ba568de58bbe1141bd8d4664b98f9e28f49d2df157741aaac03df4b74d1e19fca47d97099e2f5d84801e5def2a33ce901d4fb6a00e4c3e8b1529cb1466d64b0e1c92d0acb30db12b8965be2cd577c250ecbd40a8642c4069241f4148626f420db", .Okay}, + {.Add, "-9810aef14a3cb9d45ecfa2dab27731d7682a156cdf454af9a059765210e778993690bb28853e668d7ddd2bcf1c5b9da9f06077c046d68d2b61d95fbc4c4844900ee3e11b739c630fdefb24217192aa359b6d94cff5baee9c9d862e909f3562d0291ffcdd624873e550c166bda37401a4a5dcb6f44bb2893c3a82d4284089aace8c5eb3dd3f41b40643ccf5717d4e606a3806204c1354", "bd00f5bcbe0b5292f5698ad39e7ca4531ca322a1bbce0a5a0f214d9e1745934c9043ad06ed241dbc265f3fb39340b3676a40cdc05e46caf49d37a01b9d8014a827590e100bc03d1279c0eecb04d9a1dc824e43edcb4390b1a793fe2ff417847b51df5ee12c2030d3a9088fffbe15377946b879483afc9e99ee698f834d67845f7fce9ac4b958207a877a843324e580437c7f7dc7d0c8", "24f046cb73ce98be9699e7f8ec05727bb4790d34dc88bf606ec7d74c065e1ab359b2f1de67e5b72ea88213e476e515bd79e0560017703dc93b5e405f5137d01818752cf49823da029ac5caa99346f7a6e6e0af1dd588a2150a0dcf9f54e221ab28bf6203c9d7bcee584729421aa135d4a0dbc253ef4a155db3e6bb5b0cddd990f36fe6e77a166c7443ad8ec1a7971fd944795d7bbd74", .Okay}, + {.Add, "1826a049ea719a24d599f48d23373807941eb5f3aaf4430ff4159d48b75d6358722a23766b7857525a4612ecdd487d6161e7987a920754335ce9d1c453e612fd5dcbd69bed698d2aed77778cb3fd1a19d0b4d93e28d79cfe1b9030fffea856a8ff8357f3082a8db1a90dfdd0f141e0e2b27cc176037ffc1170a79758150afc93764d8099456460113e01c549cb68354ebca65e95567d", "5c79d602f5032f553d7bb2c8ffb9587ca600fbe52894a1e18fdb9428ba0040998438151df2d9bb0888953b2168aecceae1ce611e6723d8fd15dad79e02dd1bb1c327b20a3f9ed34aec7999acf9c511a8ea706aab2adc46ee486956b38d2702833d8ae7c8c8b27fca8b255a088ab4c87a01258de3475fe5f06324e30cc8a8cb887b6c2e1e7adedce8437d20cbe33dccc9ba18c57ba760", "74a0764cdf74c97a1315a75622f090843a1fb1d8d388e4f183f13171715da3f1f66238945e52125ae2db4e0e45f74a4c43b5f998f92b2d3072c4a96256c32eaf20f388a62d086075d9f11139adc22bc2bb2543e953b3e3ec63f987b38bcf592c3d0e3fbbd0dd0d7c343357d97bf6a95cb3a24f594adfe201d3cc7a64ddb3c81bf1b9aeb7c0433cf9817ee615aea6021876bf2410fddd", .Okay}, + {.Add, "c85420e76df8b3eff8c0bf8183d15e3489982b6e48b5561c49eb43ebf4ad0a5ec9ee389473dbeab896fe18f25ae126235a65ffcb1a06ee860372eb4465ecae4ea0d57700c61b569fc8eb776db2ccd11ecc7f98fd5f7ff9391ab6286612c383f5c3f16318533082f94429b48ef562b51982e5e7510442015f9d2837ab72817f9fbdbc3ef0f8d116b5e1bdc4d93074f54ce8615ddbfee4", "b8da68939477441dad319c36f66023cfcc0d7afcaf27ccb5c5afab7964013ae52f779ea0226ff0e5112a1dafa2d8672c7a598ee8e414ebe6dda2e0d87e241329351ad67fd5b781217f66ffdd640293a9f089485232d7d2ae0257d585b5add3fe10341ed2a90b47b7390c3413ca9824c2760c579d6a44870f9c2f86aa16b018c42db76a1bec5ab6f3e6c7f0f8f94b18c5204c3e131772", "1812e897b026ff80da5f25bb87a31820455a5a66af7dd22d20f9aef6558ae4543f965d734964bdb9da82836a1fdb98d4fd4bf8eb3fe1bda6ce115cc1ce410c177d5f04d809bd2d7c14852774b16cf64c8bd08e14f9257cbe71d0dfdebc87157f3d42581eafc3bcab07d35e8a2bffad9dbf8f23eee6e86886f3957be5589319863eb73a90ce52bcda9c885b5d229c00e1208ad9bef1656", .Okay}, + {.Add, "-fbede47381280c4d281d6896500ff39f15c15a3a00ce36b53405f56faeb4442cc9d39ec1677b9f192d3f0ccdf8f9ad4ec204b6ada77a6f4f75b2c8d3af127b8e02f538c05191f5f3aca9a84233ac659dd569a3838df2ee4fd67087b5e5fca659fc96ad7dc14559a692fff4b34c4230f16fc1ae406096743723f6c8e429353dc2b068e68a74b6a346d81d8d4027849e75c1cd46b5d70a", "3f597d96a127f1eacf71ab586eb64c99427310b21b868f5b2dea99b8a0c3b3774487a6a7593df9b526670bff01fcc8a6d6a5f5f79eaf824b30f834ba8ec53d1ef088195471143d40689a62d9933061688ff95a53c6a212ed9f75525c8a7054eb87d2647aacdda4838ed24635e101a791e410f656aee2de3cf4bbac69bf62d4f41109a4a9299fd669fa7d64e75f30cc034713ad19f3a2", "-bc9466dce0001a6258abbd3de159a705d34e4987e547a75a061b5bb70df090b5854bf81a0e3da56406d800cef6fce4a7eb5ec0b608caed0444ba9419204d3e6f126d1f6be07db8b3440f4568a07c04354570492fc750db6236fb35595b8c516e74c449031467b523042dae7d6b40895f8bb0b7e9b1b395fa2f3b1c7a69d268ce9f5f41e14b16ccdcdda02858c853d2727ab9999be368", .Okay}, + {.Add, "d42675195a747be77ee83026b5adee6bc0cdd3fe8a24227ef6924dd6a458fb67ab6e7d600b50c90bd73495fdc35e243ce92bd9f0edcad66871157c71b6a60447dde35d58ed42cf75f48e121a4f2117e1c9004e13933e09d7119f53a0b6d6dbdc794a3c96fc9ee42369f68611e1a4ebd3340dab9e4105636de2270a3f3b9f34d6822be02233bac021fc0c7d4516cb642be5568ad75b1d", "8198a6a1249f9dfc3ad7efa2dbeb3aae10c8476a84275a59adc036bd0d80628a6cf2224b55f2bc3d8713c7d38884a1215fbad0ce3209ecd0b411942b5f8b641c3e18e3c172a6f760447afb90d3d3b8a2322324ddfb476ed5098c66a69162f04cb32cb734f48954c40e3b4b0f22d1063da9246732d3631b4d112dcf756bc563ba06c03313de8e3d4782914129fc65e58857a5a70b9a5f", "155bf1bba7f1419e3b9c01fc991992919d1961b690e4b7cd8a4528493b1d95df218609fab614385495e485dd14be2c55e48e6aabf1fd4c3392527109d163168641bfc411a5fe9c6d639090dab22f4d083fb2372f18e8578ac1b2bba474839cc292c76f3cbf12838e77831d1210475f210dd3212d114687ebaf354d9b4a764989088ec13361248fd697e9dbe6f133149b43cfc31e2f57c", .Okay}, + {.Add, "-d20633d961418c0d3f3db3e1edae405e170d6e5f06929a1510d254989b5817362ad29ccb52159a74de788b99d3c19dbae9d9acdf9bf90f35dd0cab496f61531f0cdb0bcb914e3d5a84b1e1a39743928ff65dbc8ac976babe6c6fe70dbea58b2b34fee8a4df7990b832305817e2f290bcd6a85587ea52a2e9fa21349f68c4ba7cd9d8cdb88bf8f682476b986af063d8e2b7daacaba836", "f4577c0c24f7ff21aa499e844938a009d3715e0db2e423253ad63fa0ec2983cdbcb16b2b9be16837cd11bf667527b956096917d9cbf268609a4281dcb99a0389c9598fb400894b8d18c3151f375d95009f56792144ddff6a79b7ae8d337a0cb14c827c1abf079c9052bdfaf4b6ff5b654511e609507c8c4641d5720e2c2a52640feeb2cdfbb7639eaf22065092818c94a96febbb2083", "22514832c3b673146b0beaa25b8a5fabbc63efaeac5189102a03eb0850d16c9791dece6049cbcdc2ee9933cca1661b9b1f8f6afa2ff9592abd35d6934a38b06abc7e83e86f3b0e329411337ba01a0270a8f8bc967b6744ac0d47c77f74d4818617839375df8e0bd8208da2dcd40ccaa86e6990816629e95c47b43d6ec36597e73615e5156fbe6d1c67b66de5a21db3b1f1953f0f784d", .Okay}, + {.Add, "7278e6d2c66dc76361b7bd2a9c426283d3fafec0616d0d4c6522b10045db4470f9ac3c636a2b9305eac291ae39f47e84037a82eed18af7aad156bc7eadd0a19484bdadf4adf2d4c80dc6b6a8f04422fdf724f885978683a2783942a4b7b0b77f69831461d0b050e0674d618c5aef73a6517b8dd4d8ca9e619fd9ea62ee764e223b00110c6754e1f15cb3e3f929169685859bf5dd53d9", "2b7792570620919886eff316c58058e61871fae36514b4176d5fe87e315e2347c28d21da0fc3716ab239000717d1e776496b1ab290dac18fc758a50edf00274b22d3ca408aa6cf2fb0de07c823d301514c91ec7ba16bbf333ee4a89168698aa89ddf7828e995547e9f7a751f55e90abaea1b48414ec071cac70eceec9c75696e2da9d7e1d4f11e5412702d228705d0df443320c41fd", "75305ff836cfd07cea26bc5c089a681235821e6e97be588ddbf8af8828f126a575d50e810b27ca1c95e621aeab719cfb68113499fa98a3c3cdcc46cf9bc0a40936eaea98b69d41bb08d49725728153130bee174d519d3f95ac278d2dce375029f3610be45f49a628514508de504e0452001d4258edb6a57e4c4ad751b83da4b91ddaae8a84a3f3d69ddae6cb5186f39379df27e995d6", .Okay}, + {.Add, "f98c1158aa0bc610a31222fad535c2f2356bd842d8b3581efe964bbeba6383bec9dc024b41107632953c3f92c1581d8c97452ce4b4d3cd94742b8b92b9bca0ba18eb14c60e7d184e2fb622efa3cbbf7e05d9c9fb1fafe9cc5d7c76fd63849d5c1ae9d302ebf1e72c98db491d8e0c95b6b5a8b1790316fafd774561709ab54ae69db3b4a37dcff3f41c42e97b4411aec3fef401b8a3eb", "7802a17fcf876b34b4241846ed9738faca15b88a625c2801d9edb4c3f2198f0b9ef6cfe2413842d255cc227699e0cc38fd7572929b3ac58ed049cc333a0ef67b88e0cb1c00c49ffc0d49889c89b247be1dde3fde86431fbb444799f0f91f21373dbaa8e633c1974268b716a48f6ccaa80728b23cb2b7ac88e9b4d0913a07109041fd03b83f685d36744d85698057a3c85a18d5d18ea8", "1718eb2d87993314557363b41c2ccfbecff8190cd3b0f8020d8840082ac7d12ca68d2d22d8248b904eb0862095b38e9c594ba9f77500e9323447557c5f3cb9735a1cbdfe20f41b84a3cffab8c2d7e073c23b809d9a5f30987a1c410ee5ca3be9358a47be91fb37e6f01925fc21d79605ebcd163b5b5cea78660fa3201d4bc5b76dfb0b85bbd38512a90906ee4c469528c590cd78a3293", .Okay}, + {.Add, "110048ba5b4ab8faf2b0289944ccddc0edad73f04d6dfdbf416789ed033fd41b395ee621a12fb2dacd3ce07cf221426d6311990f866d117b7725fa1783c36abe43d26a2ecd3a2545e0b30aeef1a157e592e41b6390db44367aaffaaf2eab5f3cd14510019ee0e473bafde61485b09c49a9ca671dc6df5d11833d9326796cd02b4613af70786fbf4656fa4870a084aa9af1260892217f", "60ae114227ca5bfa924d8f2f6eb1f3455cbfe30a0798d10496070b60abeb15d4f7c2845297cf06c0733756513aa6894678129bc949bfe442cbfe4a5a05d047991d59129cbb0ffd71effc4c3bb40d211dcadb9e8ce3c2e5bd6656013ce7be5a4728bf37321d8b418ab1a61d3ede0ead96536aba67f9f7b94c91935434a157f8dddcd723e007b7d6d49c79af54ccef5555df9780d4be02", "71ae59fc831514f584fdb7c8b37ed1064a6d56fa5506cec3d76e954daf2ae9f031216a7438feb99b407436ce2cc7cbb3db2434d8d02cf5be432444718993b257612b7ccb884a22b7d0af572aa5ae79035dbfb9f0749e29f3e105fbec1669b983fa044733bc6c25fe6ca4035363bf49dffd352185c0d7165e14d0e75b1ac4c90922ead3508027961af373f7c56d73fff0d0bd8966df81", .Okay}, + {.Add, "dc75961619f86ff8bf340e00cc94f6797c9e1a7413b78721d42fe4a4a27be3c3b3123313ff0fe6d9f43f7f9488ba540df79b4ce2aa208e707ef49e20def0883ca205095319d5446e37de113c0b7138c7ae47098df8af52c4b5869d8d191e59779988a105f696f12bbf29198259ba6fa006c975e800e01ed91bf4eb3a85a508cb7c2322eec51822ead9be98b58e4346eb8d18ba6d372b", "774b7df9b190ebbb32d24d0b9c7a27db1fdd94f79187072197f48fcc1a2fa878d36af8166ef9dcbe7a615dec832978a7b1afe8ab454c911b6102a25d63de2d725ae986180ec35c0b9f31ab2ee5f79daf576df1b98e5309142d6afac8c042555beead2cdb53b9c104ee61e3832af8b3bc8175ad5de713da5082181d776ffe4d195fa710c9562ea3a94d79f945c9d5f759d3ac40d20b2d", "153c1140fcb895bb3f2065b0c690f1e549c7baf6ba53e8e436c247470bcab8c3c867d2b2a6e09c3986ea0dd810be3ccb5a94b358def6d1f8bdff7407e42ceb5aefcee8f6b2898a079d70fbc6af168d67705b4fb4787025bd8e2f19855d960aed38835cde14a50b230ad8afd0584b3235c883f2345e7f3f9299e0d08b1f5a355e4dbca33b81b46c694273891fb58193e4560c4fb3f4258", .Okay}, + {.Add, "-2831d5fb3411f0f90146b11b5363d730dd40b2ae043583392b58c09f8bcf7b0a1cf56def649aa0769c767d95f7bbd1c7c3dd26d6348c56b9a840965d726a793af6db36a817b83ca57376dc909a4231952f357300d8f2691bb82a77f109340cabc44aae6cbcf33ea721f57ed199ae0d8f6fb54e29bbecc73ad7d6180a76b9461f5414ba294b419807d2fcfc66da4a06c11f27445e45e7", "31b4d18aeb44c2b1743961923f781d1d07fa3039345ab46e3f12c39828fb589266ba1e4d6688203da0b959d54356ea983e60ff03be430bc0cbb3e9c46d20f39e63454974d46eca9f886584f646f8131c3278da6dfba8a219a04755ab47da7c7e4686867872378f24d0fcfd882abd173466cd80a83c29a327ead0b9b0d68d233b9b6a25126e96a06dd9da52ded25f68a9190080622dd3", "982fb8fb732d1b872f2b076ec1445ec2ab97d8b3025313513ba02f89d2bdd8849c4b05e01ed7fc70442dc3f4b9b18d07a83d82d89b6b50723735366fab67a636c6a12ccbcb68dfa14eea865acb5e1870343676d22b638fde81cddba3ea66fd2823bd80bb544507daf077eb6910f09a4f718327e803cdbed12faa1a65fd3dd1c47556ae92355086606dd5677f81561e7f9d93c03e7ec", .Okay}, + {.Add, "-6ca20a67b9a5403eafa8dfc6cd0e782996bf0dfdf83ccc1961bc68315455337f1c88d6689b2a4361dc396fe66f8c72ba0c47e09dc30d5959eda89e3e74e95cbd8358e2589997036148302b2c8dcb74a9756f020efde93d14c19eb1058494d0a455ac59054af1a8ba9232bfcb7d50130d1cbde06c146e4870576aec1a7ccce170d203a191803dec4f85c1acf9176be916ccb965214729", "47687cc33971af6b92788ce999cd85787889828fbe85d58e8cfd0ee11fc3d5a0bf2c89ebfd146aab17c6436d7198161c17de2e0c542ce6117a1e593697316a6a82290b09da7840c2c0d2be9d073eec1b3d7f194037fbb53641eb4dbd7badcec767cb69352ea369da8cc0d34ec660f4160c573311042e8ecd28044491a1b37c1d45cb84cdffce4694a6277b1d2441e0209c52d6096d25", "-25398da4803390d31d3052dd3340f2b11e358b6e39b6f68ad4bf595034915dde5d5c4c7c9e15d8b6c4732c78fdf45c9df469b2916ee07348738a4507ddb7f253012fd74ebf1ec29e875d6c8f868c888e37efe8cec5ed87de7fb3634808e701dcede0efd01c4e3ee00571ec7cb6ef1ef71066ad5b103fb9a32f66a788db1965538c381cc3806fa5badf9a31dbf32a08f630668f17da04", .Okay}, + {.Add, "e40c9d22691161d7c55002dc34d36e04d1ffeb42a77534c441e36467ca9c7121115ad6301cd8fd8ded4778c8865ec274a8a3ebc5aa902f4f07eaa3c982853993bcd106fc3f90ae4fc9b590c6624f1f89a87111e6335b513993e0fbe9e6f507d75e8b18b498e873332f1d60ac47e11688967aadc6a12f868eb567134f77ebb6685053ee1a05b6151ed543da6418f082090eee5c79c27f", "724af0b972ab0e6254f09ed21453cec11c79c4a5baf88b179a034ffc37216b2efaf19bf22053ff1c6ab47d0e3ddb7f4a5a99d5fa4b655cf150ad4084b579cbc573429d6be0b3374ed121a84ae52d95338ae8ee23777aa5ff89603e06879ed2bb3b07cf66cbc3d40aa3a92ef5abd144e95e14194b50c7a5fce09e22ac6e93ab18fbd2b8b263212e89891af862672aa7456df7ba1db96a", "156578ddbdbbc703a1a40a1ae49273cc5ee79afe8626dbfdbdbe6b46401bddc500c4c72223d2cfcaa57fbf5d6c43a41bf033dc1bff5f58c405897e44e37ff05593013a4682043e59e9ad73911477cb4bd335a0009aad5f7391d4139f06e93da929992e81b64ac473dd2c68fa1f3b25b71f48ec711f1f72c8b960535fbe67f61814c26a6cc68d743a85e5ed2c6801b294e7ce616977be9", .Okay}, + {.Add, "8b70ba4cd073518709bf123a93f0bc8eea0b90d8d500b97434091c3febe24133082456fb64d42f09c8f5b6b99316e454006cadc5c9d543ffdcf7449f519fb5880295f263039668410256c5364fac9770f81ef6847e59d791b40be8f60ae7a10e7c841ce77aa99ee7b6b20f8eb988b57e26ed7e91462ce806e93a0ded3afd2595be6ced9782bb5f73ea23c6c35a83bfe066b937f4915a", "62c924d07922ad4090ffd0b3fa3c12a8c67b794c23692bd97c3aaa555e711c19f574fdb2d70b08dd25a26043e807fb441dbd4aaeb014bc572e7f4c7f357dd5961f7d0a2313b592df3df5846b0b54fa449f5b69c14e06530acb20481c706f56bf6a4be8c768e835a7f10ec961a5efe4092fa6743a5fba42b3eab68694569346a75d1e8f6645a1dbf545f61d5dc7ba2db106c338b098e5", "ee39df1d4995fec79abee2ee8e2ccf37b0870a24f869e54db043c6954a535d4cfd9954ae3bdf37e6ee9816fd7b1edf981e29f87479ea00570b76911e871d8b1e2212fc86174bfb20404c49a15b0191b5977a6045cc602a9c7f2c31127b56f7cde6d005aee391d48fa7c0d8f05f7899875693f2cba5e72abad3f0948191906c3d1b8b7cfdc85d3b693019e421223ded916d7c70a52a3f", .Okay}, + {.Add, "d5066ab19085e91c49dcddf0e3acfe43834f0c4c9efa0232838d5ef7f04066843b3dace3480d9375f83bbd4c448c03c06c4def1a861f796eddbf661bf0cfe005bf67e68f0dbe4e4fee09cc6f4ec4a0470a0a8aa48a4d6f56ed822b47c13e015bba9a7250d3686c519e1355b62fc224490d5ab30392081bffa8120025471f6bfcd1af8b84848a4d3644ff075785a44a89c309266ff032", "be39e68d025cac807aa8acb19b2b5a63a15a84cbd752ac80c149b78da3b0c918f1600228466ea1cb14e24790b8a70e32bafaaa3e125a3fb40e2b0a25fe5f0b3eb68a61dbb7fd279231b85e78c710260149c3c6375f8694c3128b249081fb7be2455c87986bb607f240e5e6d0156fbb7fb4249e8e10a1dd1fe098b55605205b3279fc4bd8b3847ab1db8654a4905dde6c2652b239abb0", "19340513e92e2959cc4858aa27ed858a724a99118764caeb344d7168593f12f9d2c9daf0b8e7c35410d1e04dcfd3311f3274899589879b922ebea7041ef2eeb4475f2486ac5bb75e21fc22ae815d4c64853ce50dbe9d4041a000d4fd843397d3dfff6f9e93f1e7443def93c864531dfc8c17f5191a2a9f91f88aab57b4c3fc72f4babd75d380ec7e820855bfc160228f5e95bd8a99be2", .Okay}, + {.Add, "-40b97d0835fe8bc602175c80190d26f822f5b23c94db9c1f07929b78b411208478fab07b5b621b7568347b1e49801e93a4fd497c5319b22f4eac07148ef1297118ef4f31d852b902292d4a296ca6cac69a92db6748874a8569d3ce40ce3231145e6e494da5820cc80bd258bb175a18cf865c5a9190caf5f0754389d84ae65df168c46f9669cc9877f9ed4c3dbb5ce7a12fb07ac72be4", "ca0c5bc91d3b2efbb309bea3eeb43719772f323d1efb944a14e3c31967b97416db3f14b9bbaaae8de11b9f41eacbbefdd81659f78dd7a912dee0f3a868186d89be841f6d7656fa6f73f68e82b0ead71c4f595dafce8c8ca25cdfbdda1a6410ac544c2ed43980259c40a188257af91c6aadcd60523a4589d280788a33c69725f585af895aab088b8bdb13ecdb6440fe5a9053bbd3f979", "8952dec0e73ca335b0f26223d5a71021543980008a1ff82b0d5127a0b3a853926244643e6048931878e72423a14ba06a3319107b3abdf6e39034ec93d9274418a594d03b9e04416d4ac9445944440c55b4c682488605421cf30bef994c31df97f5dde58693fe18d434cf2f6a639f039b277105c0a97a93e20b35005b7bb0c8041ceb19c4413bf313e126a09da8e416b960a3410ccd95", .Okay}, + {.Add, "f0eba78931bd29e8c51348c310cbade0befae08bbfdbe9e3ac7ae7130abc1d1006fac87a2b077643ff88b69e7b1abbd7bc18b831692e1a09bca97d466c13c7308e6ce8a5d0cfb86d65a38c5d9523b54a0954039c442e7164cfaad6818d367c47f3964325af0a6d91bf69880aa53c6762cb11af2fa82402b9fbe6c8904f50bec65447e1f8ff0e5f099b26200e092dae296f0eed05ad77", "6577c6125f23358e7b1e95e0f07b448658ba402c15b5d538fab74420f875f4a48b96ee7bb72da50f03c22d7af0ba51dd2464837f9fe66d84498e3cb7f200518e6e74ba743faec038766c3760195235e38f68af45759ec9f95a06a0631dccc6c2bfbd62ad1c1baabca89397a80ecc6fe7eec9567debd158efd7b52d45d5723f6f28c52f7cf2128335cf6617aeb5a5ae9c0476fdb4cf70", "156636d9b90e05f774031dea40146f26717b520b7d591bf1ca7322b34033211b49291b6f5e2351b53034ae4196bd50db4e07d3bb10914878e0637b9fe5e1418befce1a31a107e78a5dc0fc3bdae75eb2d98bcb2e1b9cd3b5e29b176e4ab03430ab353a5d2cb26184e67fd1fb2b408d74ab9db05ad93f55ba9d39bf5d624c2fe357d0d1175f120e23f6a8c37bcbed35cc57385eaba7ce7", .Okay}, + {.Add, "5f28931047e52bccb44958c19d623fc78a74143e5f62716223b1cd05b12817cf1e6b70c90008bd732d1381385af48c45ee6c6bb4df28ea073fb8f745aa23db6e9d41aaa1cefb1719814a2cee876bf441a8028435ec8130116ce8088b4c22cb436dcf467f6419c3831500d30f4e3fd0f0679269f449467a6d3760e18b26b16ede6d748f959fbeb7e9f826fdebf33971fc744caf56f056", "4efb56a18a132486a478a6b77c32cb8b660fea3633de0e3f1b9002b89795853ee466299dea0c77976b5445522f3c369eb3e92999543598c08eecdcf164c858c3953a2ba98696bba1355af29704e56ced78af4d469d32b37c463f891a35d32a37a76df7b04ce621939b2da67026f03240bdd76708867ffc9f4f219244f7cabb329c835f0203376742fac1456049ce5d21ca057615fd2b", "ae23e9b1d1f8505358c1ff7919950b52f083fe7493407fa13f41cfbe48bd9d0e02d19a66ea15350a9867c68a8a30c2e4a255954e335e82c7cea5d4370eec3432327bd64b5591d2bab6a51f858c51612f20b1d17c89b3e38db32791a581f5f57b153d3e2fb0ffe516b02e797f753003312569d0fccfc6770c868273d01e7c2a1109f7ee97a2f61f2cf2e8434c3d07cf1e3e52256ced81", .Okay}, + {.Add, "-1672f2d2f6b05ed51374c5a891160806d53a010da16ed6986f04808b3318dcf239b544dc8243853844639cab102ef0e6c393b7917abae9412bacaacd72b76b8d25b486b585aba3fd43e5a4600e63d8b6af4b6b2534d9c499f78aef4600d12636456b2f9e5ff2ef91b7b0ed3121228b89671e0860c486e18e095d840bf2af2574c7401921568c91b7bdcc09b76cfc589aed51d215e4c4", "49489c93f617cc585af66f9cd7a106d1c4337a2d6372e474ae88c7c1c54d44ddf1a1c8f38040aa3a356177e4271cd8285146bb8f30f053c2885157e270c263d7957b89d1f238d00ff790b222313c704d0f05e3ed4c02b4c59f68159b5469ef729d40d606e00b5d38ce40421ff5344187981526f8ba581fc3f5055a8b1fe69e345b67e20061d331a49fc8acba78cf282485ddd2427af8", "32d5a9c0ff676d834781a9f4468afecaeef9791fc2040ddc3f844736923467ebb7ec8416fdfd2501f0fddb3916ede7418db303fdb6356a815ca4ad14fe0af84a6fc7031c6c8d2c12b3ab0dc222d897965fba78c81728f02ba7dd26555398c93c57d5a66880186da7168f54eed411b5fe30f71e97f5d13e35eba7d67f2d3778bf9427c8df0b469fece1fca3030bd2cf89988c002c9634", .Okay}, + {.Add, "-b8c70e4d9951d5f1d5f806a51e68270f79782903b420eaba63a53172a19d6879123ceeae5962b9d6fae5a563053dedc887ac87d46120fcd26f0a96459b5c6aff84966cd95a2e04793c68b75ba095d0bf0f1ef984fe6a63cd3fa66e4b557d921e37a70c06b73573497513802aa7b9ba172c8790aae00c146b39889f08cc1e536cc754b82311d4515e393c0b5bb4531e8ad3dc3907ab4d", "2596291a567428567c58263e39bc3f2475cc4036fb4bf3c9464714245bef4a463ad8899a4df4396e3efa7d91ce63ec090684310507baf79d71381df2096a6866dad84c153a1b75a57cf6c18614b6b16c76b92cefa4ca32553d807ad25c8e3d957321bfb4f9eb785ccb4740e2b4fbbd8ed56efcec17122004c9eed9d72b3a70110a4698a62fc3f14dd73d21dfdeeb74cc4736c3628d13", "-9330e53342ddad9b599fe066e4abe7eb03abe8ccb8d4f6f11d5e1d4e45ae1e32d76465140b6e8068bbeb27d136da01bf812856cf59660534fdd2785391f20298a9be20c420128ed3bf71f5d58bdf1f529865cc9559a031780225f378f8ef5488c4854c51bd49faeca9cc3f47f2bdfc88571893bec8f9f4666f99c531a0e3e35bbd0e1f7ce210601061fee97bd567a9be8ca575a51e3a", .Okay}, + {.Add, "-aa882c038295c0aba09d9911e02f9c014b005fb4204bdb50babdf6ebdc2868c52b0d386dddc55391928d01fee8a68e18ff6aa5e1ac8c111576a34c0314269794975b91bfd7c9269fbec67dab4f454b4cff7ed7121b8e4bf9a03098f492c6acc4c64f0b0b494e8b3eabdb049cf4d36a5bf825d2c083ce2e8cf466239c8c8fefcb4d8fba08eb82bec29622a1814f5aeba56519ceac5fc0", "c7ec16efb1db6706550c1f2ff9f6cadcf6c8a398ebf3c6d8af204d28ef88225d2e3956a74a8282bb5f1e2d35046fb4fb6df33a9ec39b7ac6f4288f71e9078c02b36f720ad14248ef954af13d0a28f0d0a4c7b71364d623f007a1e6dc5a7b781efabbe0d242b8897111793199d4573844aad6bfbed7ec34273709f61be9a9f7afcf41da0252749d4eb57a2f38a2f3e74de586563831c6", "1d63eaec2f45a65ab46e861e19c72edbabc843e4cba7eb87f462563d135fb998032c1e396cbd2f29cc912b361bc926e26e8894bd170f69b17d85436ed4e0f46e1c13e04af979224fd6847391bae3a583a548e0014947d7f667714de7c7b4cb5a346cd5c6f969fe32659e2cfcdf83cde8b2b0ecfe541e059a42a3d27f5d1a07e481b21ff966f1de8c1f578db75398fba8806c878bd206", .Okay}, + {.Add, "6538d0b912cd1b3865c44e573a9e3f18fbb405cf32e0e87d487b78f4441a3730342bb3be3f4af441634e87049f6ea2ae10f090eeab838828da89dc97c21139379240ea91ef4e913fe97a16acd8b14063d3cf8c9680e698425ba354ee9f38adcfc8b929f2915be799859a2af27dea48aa845e95b70065d3cf39133a605e8a06a8619b67fea4d947bbf07ed074f780bc5b6c2f86c93ac1", "ce1fcd591c6d27a191e7eaddd37371898185bf28f2f778c5ae51888e51d98cbbc3e21a71567c21f3885be2c3bf4ee3e689c22608453c4bb3ffa31d2ddca1f720f7f8c672a706fe44aa3821358eac4dd854a19add8cae14a8730c3e68a1b6348c5208b72dd1b38a08da19f8ae67860cf622bc654effe3a493393825095d6d490135d9352aa592647e017f0bf5a02d7c92409108eb275c", "133589e122f3a42d9f7ac39350e11b0a27d39c4f825d86142f6cd018295f3c3ebf80dce2f95c71634ebaa69c85ebd86949ab2b6f6f0bfd3dcda2cf9c59eb330588a39b10496558f8493b237e2675d8e3c287127740d94aceaceaf935740eee25c1ac1e120630f71a25fb423a0e57055a0a71afb0600497862724b5f69bbf74fa997749d294a6bac39f1fddc6a97ae38edacc08fb4621d", .Okay}, + {.Add, "-de427833df540079e271116c51232db8b40486fed15caadd79e155a174af2a0d1b5a6090951a4737a03b07f04e4bc8fa76c1c74a7d4175650c3b4a5370deca33321fe360acd27f10d5894bf291bcdc3010142ff44adcfb1c0ec2d5aa4e426ae0638cf40d83576706e1b5831558b34a32176346ed332d0fa2775abf7972c5e8cbc338e7f29dbd1fe52f7b3ed9c6eac30f5ea7129b8828", "c7d3281efcdf64c9261976ae3b9f292b692a705679a0595a645aff9e0a746a30504ded17cf689b26b1cb3a9c6f5a744e7bff7f6db25b5aac7bdb8d03c274c1c35f03803e9846fd6eeb514b9898cd6fe25773df1c7a65f7b2bc43f878add685ac7897e22e6dc617791836cf91d73d56d9bd716c258a922737f98e6ab5fb9c082a056c6081fae04714e5176b01fde3948e8b8770bc257c", "-166f5014e2749bb0bc579abe1584048d4ada16a857bc5183158656036a3abfdccb0c7378c5b1ac10ee6fcd53def154abfac247dccae61ab8905fbd4fae6a086fd31c6322148b81a1ea380059f8ef6c4db8a050d7d0770369527edd31a06be533eaf511df15914f8dc97eb3838175f35859f1dac7a89ae86a7dcc54c37729e0a1bdcc8770a2dcd8d04a63d3d7c9072e80d31fa1df62ac", .Okay}, + {.Add, "4aca8e0ec98f92c4ec3cf59ac6a4d4245a7a4a9180bdd2247c9b1117c642e2a7c1565285bca4da967322ab5722e372742e157a6055d48322eb62607d1a3b05bfcfe0c4acf154e10e19fa61bacb5a2473e6167277bb6e297fd36f67de4a09313422d1aa12011ba84c432274b34080972db325f62e29f235c7b3ea3170c0d83c1e1258c01099a42c4e1d7480461ce75fa43ce4143df099", "66f9b4bddb0af6d6c8f0041fe06bb15347a6231f3552db59891711dba42c2dca1c96eb9bdae349bc2c1a78482495f1e88c82f8039329f20897a688aa4497f6290d8163f05429b55a2d354c437198eeecdbe70a70772bcb7b7ef3377fb01ac519929cf1969091210e670c85454369a98f7c4d2f94b0790a41cef94f793843ed5ef2fbfcb2eaad5e18b6b05f9c09b0dcc783d57e79b7ad", "b1c442cca49a899bb52cf9baa7108577a2206db0b610ad7e05b222f36a6f1071dded3e21978824529f3d239f4779645cba987263e8fe752b8308e9275ed2fbe8dd62289d457e9668472fadfe3cf31360c1fd7ce83299f4fb52629f5dfa23f64db56e9ba891acc95aaa2ef9f883ea40bd2f7325c2da6b400982e380e9f91c297d0554bcc384518a66d424dfe226983c6bc0b992b7a846", .Okay}, + {.Add, "-285a239a72ff96724846e07610eca7e5dae351657790f8f2be68910ae79f3b348dd80cb97f3731bee1d0f647c3f734fb26a68f641a64dd66f69e8379e7591e7ae91578b9d144bec7302a4aadc99b0f671aedb07ad075cfd4fe4293314db543ab4ef89c1812726d40757502c8cc8059763aacfc00d574144510c5aff4e259ff9de97761704ddff59d1b0773b2a375a808aebee4b2a998", "4d0c0db5146959f62380517ef6fbea3d6a9f7c64be78d9eb71e3d8f9c7405a42f3789696aab95d49066914abdbffd7ecd58a8bf84e72047348884b40e35452844ad002ca9185b6a3caa2977558fbb262d07df4d8bba7c038670b5ac0e18975914547dfd44b46fb70cde02844472a92184539face1ccf9d48299b4666d59727c1d3324cbeca093d18d898f80b1307f9880e58af3dc74c", "24b1ea1aa169c383db397108e60f42578fbc2aff46e7e0f8b37b47eedfa11f0e65a089dd2b822b8a24981e641808a2f1aee3fc94340d270c51e9c7c6fbfb340961ba8a10c040f7dc9a784cc78f60a2fbb590445deb31f06368c8c78f93d431e5f64f43bc38d48e30586b257b7aaa38a20a8cfecd475b890318d59671f33d2823e9baeb4e7c29477bbd9184586f92517f5f99ca8b1db4", .Okay}, + {.Add, "d2888a595c4519c8d00fad553943be37aaa9ff192a59a576c4c58b156b863fd135cd2b3a1825004f32a511500a566964c213e72b17f176cd6803dc7d2b700a674c8f4d5967ee4d910827dd697361042554216644bef7118d5061c27b22d6217e556abf104fe0aa74615fe89da84d1b25dc0f58b0447e9ad98e1dcf13e3c32f131a9c85746a047f0370fa8659cbafd2a7bf0f8eb7d5c4", "da75d70a06c273fd180f35c529fa57a8b762ce1d17b0dea154c99258c7cf565a1b1a5905c61150e4ddcb95fcfb28baa355d67a5ce20b2c6e03be7ab56bb225c8dc70e44f3780b7b730eaaf4e8b0a440c22869a6fafc0708a4b773bae71d85e87f4d52a2612e38810f0e2f03766d033e3335ce0243a37c2f9975dcb7310b4a037f52f77d38740a8b0f15c1fc037cb9e74178e722b210a", "1acfe616363078dc5e81ee31a633e15e0620ccd36420a8418198f1d6e3355962b50e7843fde3651341070a74d057f240817ea6187f9fca33b6bc2573297223030290031a89f6f054839128cb7fe6b483176a800b46eb782179bd8fe2994ae80064a3fe93662c432855242d8d50f1d4f090f6c38d47eb65dd3257b9a86f477cf4b0fcbfd47f14527b46256a61a037b711bd69e00e2f6ce", .Okay}, + {.Add, "8189b27ad95dbe331aeee12438505c490f018980e3b268c5bac503c43d2051abc2e1a4fc5ea4e9311038536a1129d8ba8d7aa3f65709a1072a6c2cafc85e4b26095bbe147c00337caca0c00309285ddd9723a0533e368e1bc8c772dabd3fa0509b13390f36702417644034280db1b67e87f01ef628bbfb457909b2c2f06dea621fdd63a96ab10418c3c4c809647c937aba41b1fcaa8c", "c201d73bbc5c7920df5fa86537fe1b9f3c362953aa837ac188a56487955cde3137b8ab1b18ee8cb2d60b911c1ee83c6e24abb64e217f52ee2a56862a2e9710611de3f96d68a850e8464e3fa346a672ba8e2e1d33cf7916e56f08021061d4ddf369297dbef1b1514b8ebb2b6f6fe429597a5ab062d678e6c4cf46f76a8a53ea9322dcb66a69feedfae1fb98a1b78372fe15f4d0cdc9b0", "1438b89b695ba3753fa4e8989704e77e84b37b2d48e35e387436a684bd27d2fdcfa9a5017779375e3e643e48630121528b2265a447888f3f554c2b2d9f6f55b87273fb781e4a88464f2eeffa64fced0982551bd870dafa50137cf74eb1f147e44043cb6ce28217562f2fb5f977d95dfd8024acf58ff34e20a4850aa2d7ac1d4f542ba1a13d4aff213a5c060ab1c000678d03682ca743c", .Okay}, + {.Add, "-e3fb78863c6d172b9c03fc2921c1f47142a318fa5e4642afa4bfc0d6d5621713eaf0a92e385d3a11772cfd62cdd333cfc5f6691d136c768ae705d20cd863c2e0bd4bbbfa2b9caa8270f938905cf6f36e74a0dabc3c0e947f9d2ee256aae8080cc6b307772cc05d1a159e537b1892e2c9f49bd938d57f66fcc433e256af8da67eb90a5bda7b2a4587d9745097b39f8c236feacc246b9e", "d0f5d1dcb2ea55cfe13244e9769243f24902b5f0faec267028e0ac7ee1af6a577fd922644966922e7c5fd58c626aa5c39bf9fb87a30eed09f098ed53d63ca331bdcff59f1b0d2343322662b8cc4d0814ef9208cee47673c5f139e342e5ad689af46fb60e30f68b65468bbd7001b5b703522448323a477869cb5e3cb8f8ea65ac5e25f4b46b3040781ccc091cb988c5c81d3bc745aba3", "-1305a6a98982c15bbad1b73fab2fb07ef9a06309635a1c3f7bdf1457f3b2acbc6b1786c9eef6a7e2facd27d66b688e0c29fc6d95705d8980f66ce4b902271faeff7bc65b108f873f3ed2d5d790a9eb59850ed1ed579820b9abf4ff13c53a9f71d2435168fbc9d1b4cf12960b16dd2bc6a27791069b37ee92f8d5a59db6a340d25ae467260ffa050fbca8477afa16c65b52af04debffb", .Okay}, + {.Add, "-e915d954afe8a771955ce495bc3beb1c83b8df0a12d765aabe4916f0b1dd50905a43b8a163c6babb713af749b5a6168e550163d7da07e07cfee69e56596a76951c8ee45bf2974f49166b2f2b69364eaec30c4d9585572dce7c83cb533ef057fe95ec377407f5a8e1f4f25384cd7ca492dbd99547979e88cd0fe52be62389e87b1e934a6b92ccbf824b56c765675f0489adf5e1ae553f", "51b763232804eb492114812b40106f1f69510ae4213276d3d244e57ade303ad7ed356724643b773dc5bcb7c35bbead5e690c00dfbeec016a20c61c9d16b2b131b573cda5e8c3ffeef7fe3ec4e9ef86abb7f35e7cb19e1471bd93a5441b9c4864bafe20eac2d4128704cafaa232585b50c9667e3d7f5c07f7e5b04f060810887592dda633aeb8832c0c2c73e0c444fb9b0485f2cecfe1", "-975e763187e3bc287448636a7c2b7bfd1a67d425f1a4eed6ec043175d3ad15b86d0e517cff8b437dab7e3f8659e7692febf562f81b1bdf12de2081b942b7c563671b16b609d34f5a1e6cf0667f46c8030b18ef18d3b9195cbef0260f23540f99daee16894521965af02758e29b2449421273170a184280d52a34dce01b7960058bb5a437e4143c563f2a5384a31a08eea96feedf855e", .Okay}, + {.Add, "e8af14f5b4dbbc6af684b4751c1cea09c39ebe19a13a1e836a770ad7a823c91c44fbe6038ac1e18ec263c4294bd767098789dbb01c05e4c090abaec88709d7caa366e84007e69f8f1958c66a67709e6dc8d5d700027fc571fc09e181d969159be19da9761dc64f1bdac6328d9bfc2b92b3d032eaf2cfe37faef75b342ed2a4727168bda71103d6452983f3fa8c69b85863d1b40b514e", "8101f4b7fc4099b7565019bb94c137617372e4bfdf7b7c510482245aca5d49c0f94192bb4047a1d1a7e13b846eef027c1c46ff815fece5a474a034362a4409ecbcf8c8dae3a363b79ea888cb138bcc41cc950115e27ee2b9a28864c8b3618904154473af63eb0ffb2e66b31379a52b9b6b3537b0ed110675e92cc1af3c4ad8738de290f7d0414350d172e7c2f32c0195aad524d8db82", "169b109adb11c56224cd4ce30b0de216b3711a2d980b59ad46ef92f32728112dd3e3d78becb0983606a44ffadbac66985a3d0db317bf2ca65054be2feb14de1b7605fb11aeb8a0346b8014f357afc6aaf956ad815e4fea82b9e92464a8cca9e9ff6e21d2581b15f17092ce5a115a1572e1f056a9bdfe0e9f598241ce36b1d7ce5ff4b4e9ee1451995faf6dbbd7f95b9ee0ea6d8e42cd0", .Okay}, + {.Add, "-8e3fb2b8f8d2fcc9c88f70df2a69a1522e11b6b6fb6ce030535d5c5c48024a2429ab6daed2ac4973c945bbacfc6e8b43f46b44e25e2453fe2b75535676db8d5a602414a6957e131d808f9f632dd66e786f6c8fec89b89b76e8271875c97aed16411ad2758cb383c55ebbb60837ad54392573839dbff21834908d353fa4e830d641437e142bff520d7975e0950df63da77e1266bf425b", "5495ffeeb8beb9d27394e3f025b5412819923ae75dcac04fac6350556cef56232fa5d801cf3729901adeab33ca6f10ffa890a12759547bf48802f36e7bcd686d0c51d8497f8d6178c8bb0a4e873527d17d1fbc4d7b33479059c20afb8b4e961599da53323564b9e57040c90a28b4ccf117c7b7b774976f21c8226cf30ac63cab54b531e4bf47722f90afe5f04cd4ebbbec8b0db2cc12", "-39a9b2ca401442f754fa8cef04b4602a147f7bcf9da21fe0a6fa0c06db12f400fa0595ad03751fe3ae67107931ff7a444bdaa3bb04cfd809a3725fe7fb0e24ed53d23c5d15f0b1a4b7d49514a6a146a6f24cd39f0e8553e68e650d7a3e2c5700a7407f43574ec9dfee7aecfe0ef887480dabcbe64b5aa912c86ac84c9a21f42aec8e4c2f6cb7dfdde8c5faa4c12151eb9187590c7649", .Okay}, + {.Add, "b233b87798a8018c7bcd20b80085eaaeb4e49e20b82a50cd63180030121509d66c28eb3dfd96fe076cb68ccf96c4feed6ba3c2bd46a7067fde2e4881f26a6b5d6a438e124e9994f3e999c7618a18f7c7c5031e737e962291ae4987920e6f642b58eddc25fb95710c5f50e6d96b6ab13bd52d16bcff018beb3b8a10aeed7fa497900c5f61c90ec5cdc59915d3fbdad9fe7fde514052a4", "664e6a4ce68c0f176c878a60bd7a99197f9234b139b02aa0febf33d8ac53fc84ae5544d7d56d1d99a2750a6b14db583ec2da8c8a4ff533756747c2d25ce4b9e62c4f2d00555376607dc99ab8ec83f95cb62ffcc01ee4f67057e07184e948324c863eb5bb90d3bbd88de8da1c87f9b7c809eaa12210bde0af57ca9ea780a53638112925e529517e79869f7f6227adaea7793bda47ca1c", "1188222c47f3410a3e854ab18be0083c83476d2d1f1da7b6e61d73408be69065b1a7e3015d3041ba10f2b973aaba0572c2e7e4f47969c39f545760b544f4f25439692bb12a3ed0b546763621a769cf1247b331b339d7b19020629f916f7b79677df2c91e18c692ce4ed39c0f5f3646903df17b7df0fbf6c9a9354af566e24dacfa1358546f26044474c389536238888a5f91a2b881cc0", .Okay}, + {.Add, "-1d16a793a86d839c9003bfdd05fa1878b1c87416a3872bc38d640daaac86b3e6e7b9e837b75bcf939faf0e7b781b295e8e1e312525f3aeb97eeb47c08efafb212d1c510ea71f3cd30bc0c697b494b73d7aedba84d77d145d2bcb7b61240361abd6249e17af578939bac7cebbe8f5a3ee9c2c195b66ce0e1b2757b95cfd3677acfd40c2ce0714f1a562e016f16dfb90cab07c041784be", "a7db0b4a3378c896695d40c140ece8a0315a3d78a73a8b81f8cf5fd6a3cf7d66b1212dfdfa5972d3e61827ecc672ff60c340683cbd9b3853974279ca0c7c6091bbf2d9ad0cbe7cbbf041ab90e931004459845e46abb8f55948961dfb55d857908ddb1cb46501e7a364b6e557d2dcc813173116ec5385c011fcd855b920f6374f42f6a5f4dd98954ea90b0647e197f42af2d3d0df968e", "8ac463b68b0b44f9d95980e43af2d0277f91c96203b35fbe6b6b522bf748c97fc96745c642fda340466919714e57d6023522371797a7899a185732097d8165708ed6889e659f3fe8e480e4f9349c4906de96a3c1d43be0fc1ccaa29a31d4f5e4b7b67e9cb5aa5e69a9ef169be9e724247b04fd90ecb7b1f6d5809c5c23bfbfa245b5e326d683a3a9462aef56739c63604257ccc811d0", .Okay}, + {.Add, "-94511fb1d18c9a0821e2a756065422132824a3bbbb4219e0cb5b644288105583057c05d118e1ec3685fa6c3f53370250976d1b7de578a899bd42ad8ba0bd6a6260001b9749e8c141434b4fe6ca99e4f7bfde524d1a89d4b2815bd38a2871d961bb81ba60996188d6abbb45986d282f78921329d8f5c737c7c278ed4cf569cf5cb361391f3d691dabb369fc047673e73d432ea4cf7620", "6c410cfb62a9ccf087f2d26dabdbefe53669aa4dd6436bc383dc7e8f42986b0eff39b361be59737328e99df77bcbb111967ac928347d27290a79729bfb4655f807e6769a4b7d7466d5166acb2bf7c2efc7e5ce431d9608f82740bb4e47a67aba8a5fc8a731904a4df40256995edfea6a66efd0fa7699e4500b4d6b94e38ecae9c6fe6555936411bccba7ed9af1e1566f3ffde0047af2", "-281012b66ee2cd1799efd4e85a78322df1baf96de4feae1d477ee5b34577ea740642526f5a8878c35d10ce47d76b513f00f25255b0fb8170b2c93aefa577146a5819a4fcfe6b4cda6e34e51b9ea22207f7f88409fcf3cbba5a1b183be0cb5ea73121f1b967d13e88b7b8eeff0e48450e2b2358de7f2d5377b72b81b811db0472ec62d3c9aa050beee7c20e69849290ce0330c4cafb2e", .Okay}, + {.Add, "81be11440f7c6fde6f814e89e3983b5258e0636bd767f8b6668556551a83781c80177299912f44c6b5b753fb2bef4f73ea3f61add919579105f9d181d82ae4b34784585fb0336fe6445133da8ff6938ad2a95956ee8b01aa5126aab75d15592dca6b5e56bdc2ca41b284000884b61cad86a5bfb1805bfd9ee5025176cd3bc3f126016b6036fd7c59509376cceec13f6a193eec61f0c5", "4c77d42c340566363a368d335452822080fdc0ce682d907c01f3d70242442fb22c26d71acb359bbddff50e04fd56bad4bcaf4567362be3ad8c84466137d1b2aa2aa73ee981bfd1f81b7bbc292f63a6edebb3d9ba7adacfc784b87a05f68657544af23856262aa0e95ba157172326c879f52fa664e57c8acad72e54ccad1ec6a37f2418f637c97660af2dfb7e0956a16418cace030a94", "ce35e5704381d614a9b7dbbd37eabd72d9de243a3f95893268792d575cc7a7ceac3e49b45c64e08495ac620029460a48a6eea7150f453b3e927e17e30ffc975d722b974931f341de5fccf003bf5a3a78be5d33116965d171d5df24bd539bb082155d96ace3ed6b2b0e25571fa7dce5277bd5661665d88869bc30a6437a5a8a94a52584566ec6f2b9ffc1724af817e0ce3209ba64fb59", .Okay}, + {.Add, "-22a6224d381b36a3a7468e0f0efaddd3e987984bc2ea99e2a8b312109b99e157e20b6534f251e73812bce7af93dd5b6e3108df39641d2abd6e2f61c367baec407dd6cd99a80f35e03bb280923a876d890e4b0dbc2427b97e34b3eb894b72824678651d1adec7e9f0888112ab0b7d6d1ffd3c64ad33914e049da5f7298e6493c13313a1eabd118c9e2a92d129edff6d252edc49d4e354", "918e944f55c6bc10b04110ae28fd79edb227827384eb873effbe197c56391991df271ba62523f9297878846a2ec73b75ca30a5f8928572bd54acd9f3a0e86bd26479207ac28eb66bb424aad3345bf6040ba7a598db0028104528f8d2a3e9f0631f6eadb29cf374d46c04ee192c6740211dcf8eef3223cdd95a94b93b2ba0572e9118a2f3eddd7bb80d7abef1e013bef10fb1a576bab9", "6ee872021dab856d08fa829f1a029c19c89fea27c200ed5c570b076bba9f3839fd1bb67132d211f165bb9cba9ae9e0079927c6bf2e6847ffe67d7830392d7f91e6a252e11a7f808b78722a40f9d4887afd5c97dcb6d86e9210750d4958776e1ca7099097be2b8ae3e383db6e20e9d30120932a41fe927fd4bceec2119d3bc36d5e05010930cbef19e2e7edc7f21451cbe0d55ba1d765", .Okay}, + {.Add, "5b3b4bd41b68d9d49b9e03eae4630a25db5ad23943f76bba9d0bec99bf0db1fbf3b0331777444e8000aaed56fe41d769ea689292e9e4157a655bbb45593ff543a91fd20ca9de8b12cfd6991e82a10b20fca17a6a2d56ea37d590140467c65f1e9814dc372a6d89d2bfdf54f48cb6f654bda110a2acd8c13e72065202302fc27e97899a4796c3c7018e22fea19d6dd501e25c801f8a17", "5a8b283d511100cd06f5e5120632d23804de28974d5a51caffad56f6ebfee9f9bcc0f1c0d0e73054c2368712228d01d87f7191f18fc0ce92b1b675162932ff0d7d1ee101ef78c23847c8860d2a13fd9b6bf01a24ca92b64daef1272ba2df901b66833e37ebb9cd23b1882689a388ed4bbdf837160867da235c25ace2b2457725252fe1522818fcccd9f3eb7980ea66ff40e870f10639", "b5c674116c79daa1a293e8fcea95dc5de038fad09151bd859cb94390ab0c9bf5b07124d8482b7ed4c2e1746920ced94269da248479a4e40d1712305b8272f451263eb30e99574d4b179f1f2bacb508bc6891948ef7e9a08584813b300aa5ef39fe981a6f162756f671677b7e303fe3a07b9947b8b5409b61ce2bfee4e27539a3bcb97b99bedcc3ce6816ea1b1e583c012344f1109050", .Okay}, + {.Add, "c974f852f8164ce5d4c0d5bf07e6dd1bbdee1bc76448e3bf5c86f812ed0c779bd2ccc5d333f64f145a0893831e5d9e3f5297f281c6734e5f1c725e641c4d4bdc8ef839a8492d1a934d4c6fd40425f8f03aec87eeb976e694f0f49a86f5b920e2bf89a6392d3980a5acf908c4798f50be653ed49a81f37c5e183a10e9d6593aa04f41ff6b1af3baae8b75d98d923ecb884224fead2cca", "cf660b93282bbd389228eb8fa4dca8c4e9c47ff8a7a66c53c485a11e7dc81f33e1d56091554953fc14e4ff06a7f11640481bc605c1f09e88c1cde706e9994fc17ca9b7d3638788a970f289b2c02e0786144f9971a163e879066aadc52b380af0ab9fc1912c1db1b225d2d842d3a0b19f5d4d4a3a48b8db277298e4beb06419542e2ad07f9f5885790e6125e74fd73273e5f23b2bde2a", "198db03e620420a1e66e9c14eacc385e0a7b29bc00bef5013210c99316ad496cfb4a22664893fa3106eed9289c64eb47f9ab3b8878863ece7de40456b05e69b9e0ba1f17bacb4a33cbe3ef986c45400764f3c21605adacf0df75f484c20f12bd36b2967ca59573257d2cbe1074d30025dc28c1ed4caac57858ad2f5a886bd53f47d6ccfeaba4c402799d6ff74e215fdfc281739d90af4", .Okay}, + {.Add, "-896381848fb26af670f495bddb71cd6489c1eb20f2feeb950245576d486236d2e24bc1257f21c00cddc1b3cd95995777bbf8e9c3a51e4e10e39feb052f939fb08a0ce1689e8dfe2bbf66b7895a71a0d74fdad816653287aa6e4c2055a4ccdc48ae882d95e7f501aa7586c33ac7316acbdf92cb6fbdcaba35c466d8a0997dab5a82bdd8690560e14003ebff4a8b3d0e236789d7990e9f", "dd7672963d0e9df5928e101d8ad068a6bedeef303199af58bb6c18cb2c31e985f8d8df9807a9d742fcfa853c4434b1ad621aa2b1be23d6656ed97167bc12f805dc349b5b4790e85063b9df8042e021587bbfa688611a198fedf58fec1193f918aa0d13639d99eebcadaf667cc67145662e2fbfec2d2b137505fca8b3e734c3042a278e73ff2a59dc16753ec898f67112a6a96cfb9a7", "-7b8c1a5b2be1811717cbb4bc02c4c6da1dd3fc2defe5509f768e95e0959f183a82be332bfea72298adf20b79d1560c5ce5d73f98893c10aa8cb253eeb3d270302c4997b2ea14efa6b92b199156439ec1c81eddaddf20e6116f6cc756e3b39cb723e75c5fae1b62beaaabccd2faca56757cafcf70faf808fe74070e155b0a5f2a401b5f81c56e3ba24284ab5e01ada7123d1f40c954f8", .Okay}, + {.Add, "-987a011fac158cf32c8966f33757a8a282359f95a5ce1c10e890d0ac9671b8d5e89aa2269cff50d679b7bb747627dcc2013b619a9b8d4b70bbfa7078f6abe5dc16860223cf17f173631c338e3ad56b7f3b4728e8c963ce7a2835a2b4b561a76d471f8cc17022ecd219fabe28d70258000558aea8feab8b922e3a14cdb59558f963682dadccc84dc478f4c89acc791a6badedd9b75b72", "23b3e4daf2355c3c18259c3ab9ad7836a61d84a03f385cdf946d63b18785d487a4f890dc5a2b071d7081c3792ccd05023a999d8cd2f04a6a76f5f4eb61f093cfecb98367603ce3bb0632394a1ba757430a3672abc66de20089571c4ff54253df15b65946ddbd4f49d6a80fe1025a30d43123b28cb8ec3d02544cc4339aa255596e88a011e0aba4edc41a61ae2038e607b2ced04c0b8a", "-74c61c44b9e030b71463cab87daa306bdc181af56695bf3154236cfb0eebe44e43a2114a42d449b90935f7fb495ad7bfc6a1c40dc89d010645047b8d94bb520c29cc7ebc6edb0db85ce9fa441f2e143c3110b63d02f5ec799ede8664c01f538e3169337a92659d884352ae47d4a8272bd434fc1c45bf4e8fd9ed509a1af3039ff4df8d9bec1ca8d6b4da66ecac403463fb1f096b4fe8", .Okay}, + {.Add, "-ef3a8aafea9f1b6a1b5cc765f8a5adceea56ffc2cf3d4b70a8b43ddb2e058459d37cebdb02df70a080366615f53e321d2a0cc398dfd443305ebc9fa4d702feb8451dbb9e1d3763f5b286181c80fd4a9421ef9ac56dad506b159aeb420b3407a23635ff8301185b840c50319fdbd45203d72a9b47f0150d9fe9c09f3268f42dbd298a1518764355092f393841b00919ca6fe92997729c", "a2812823079dd4c12807d5bed97501837ba58779f2af80105779cca8f1d49006dc46371f885c700520dbf4b5955dfeb741d03d46eb557e6ff3870aa857a13a4fa6f7a8c08e551392b9421f1ebdf52c6ede6f4439e727ce7a4572b9e8f078574df428bcbdd6857c5c97718bd853c6d505b01a81946fc4082595ef809508045c6e8a24b9c6cc61ffe3066a768f413270910be85dbbd8d2", "-4cb9628ce30146a8f354f1a71f30ac4b6eb17848dc8dcb60513a71323c30f452f736b4bb7a83009b5f5a71605fe03365e83c8651f47ec4c06b3594fc7f61c4689e2612dd8ee25062f943f8fdc3081e254380568b868581f0d02831591abbb054420d42c52a92df2774dea5c7880d7cfe271019b38051057a53d11e9d60efd14e9f655b51a9e1552628cec1b26ed6a9396400cbdb99ca", .Okay}, + {.Add, "1aa80c9044d5273c2b88fa817a679ef19e4c8c626abc3761eedeb52f727ac6cd14b30cdfe0a6afaad548c076388502ca8751a6b76573eb06dc4621a6305aa6f4f682aedfa5a80a3352929e2011b573fb6dbb70ab45ccb538f1ff74a2e4085902c409de95293b4be1fb6723d726276b5375893c0523a0bc44f2539c80979ef6cb3e20121b1bf98acab6ec9146712d7a581a6ac87adc05", "8d6912eff4febe26afea21453229f59771fc7089394fef6a88cb7951e7e3319c08a5d1ec2ea8300142bf8ede60f485a5189e19bd90cdbfade872a2ee70710d0e61a8aa50c32a1ead6a9f3839b962bd23338cbfcd1dbd52f47a31f302e85f98920cc097bb2b8e5585cbdfd2aaa7f0f192ba65813ff18b606743a973803f13e60a90b44db7f1227b7cba1ab2e4701f4d62e52fb3c79283", "a8111f8039d3e562db731bc6ac9194891048fceba40c26cc77aa2e815a5df8691d58decc0f4edfac18084f549979886f9fefc074f641aab4c4b8c494a0cbb403582b593068d228e0bd31d659cb18311ea1483078638a082d6c3167a5cc67f194d0ca765054c9a167c746f681ce185ce62feebd45152c1cac35fd1000d6b2dcd5ced45fd30d1c06477107442ae14cc7baff9a7c426e88", .Okay}, + {.Add, "db2906c9441d86504eba0da43f3a805643b838a9f048bcf01bf601b09c2fcb86df17d978cf5051c34ac369c4e4ff1e2f54afc891fce7548f82a3042127a55cd594e57ffe48529ebf3ad859c6b17610336da6cfd577fa2764756061c9e4f5c23f54e5491e0262d45f735cb3ff4d472df543e18dba1c93e976f50b6c0a0f2437d28dc44d74c3b7e93b73c6f90cf8b5156b223f57296691", "ca31f41ea469b0524a33fde9e954968d1f5f696f8716e39fba110df673f780110775f9870022912c9903cd6d0a6b2ecc70166a045737117abc641ea3559b7c295b47ee9b7304e450290b4690120a9a93f665f25b745ea50d8ae6a01e0c661ed667134e27e96871b51f4b96e85ae82e8f54b7ea707855480e2b58277d7647fbde11fab24c70673e71055185d5971ba12b76d05251b9c", "e7cc260b2e642155735d4d82ddcfc9bf15ae2f40e8ba2b2a17971290036f4387ef8f39113f527ad61453a69bb5a5d11c1bb12f32425ac5a72e69460b5cff14982a99fee7ff82ed043d690e2fb296b9dcad0d2efb2f4011b54e0ecbcbc5bc242cbb567e0080f95b7ac5516d6dd2f5b0de392d0c6124193df7d7c0ee81e688b7906ee3f8998abe5d22841c116a5226cf7dd9ac5c4e822d", .Okay}, + {.Add, "-a195876bdc4adb3677d20816f1f364f5a9dae0f388225f587ba3518e82a56378ee58bf870c8946a1c376f5c8d27f626c13ff4f21c5e07c46405a8e90966d99dd1e0ccb8bedf6ad7978c85677037cb8fae5ff1f31f61f9867195365789f9ee950947792cf037eec14d1647b80e004124bffd82fa99d2956a41e4302f9157c05207267b00188058ad708ee5b1a2bf47b1521dcd335598", "31229f0988db88d8b945b698a9fddba810bd9e4f50d16f258e2d13ad6432c0c9e80ac185ed6727c4be286f689a648e0e60e425fd080744bd525917695b96ad88a5bb077a7e6d1f5b6b5fb725c85c82ddd4ae5ddea7e75c8f4c6ae382e22f131b39ce3456b58ca55a76f0fb4f26d563449b3b5a281a6842eeb8b4126911472431088796f356519413242d7a7f379296754a4dc1975e04", "27094692cb16db2551c896173adea558b61ff040184f49300672de947c086a925925358d7c9e935aa1f1000c0d3c97e79fa4310aeba93cf8ee536e80522fd3ead3da3ac1bf8db483d3d331be5824b74e264e6beb88856308dad5ad2b583524863086bb29c554b69929dab39718d5221fdb3dd72d8095ad8476cfe2397fef63df01611bf33dd13b65b39e94cd94d34ec3f82ff464086c", .Okay}, + {.Add, "ac101d8be1369910b586cd3161829ca1aebcf83995dfcd58a1bf292a4405b5c8c8b2fc4ea683b5d25ec8cd79c22af468d9eda047078757a96fd0829400a1e74045f7912a9166d3f354c835a4b629f3edd96879b5e304c78730f6058ebb82149e5b606f7273af77f9efcb19733572db41b8dabd0da62ba4ee37560be065f4677ce71c75408a7a0512e0c2b9967f66688802de4f704dfc", "98c216258db4d3f74b72a699b6439d172d1a845e706f4f753aee2ae03721622d000e7441065654425436ba59ab2e4093608670c477f4b3d509b25a13ff72b0876d26b0ecb081aea06308e8075daefb28d8ff07a1f2bdd2adf5c76f56834b8ab5206839aa3f6532919772a6c66b0363ac1f0d161beaa838892c4ac5326785a9ffbead0612e24680a8a5ff13e5024d7fe5a2bee09f6276", "144d233b16eeb6d0800f973cb17c639b8dbd77c98064f1ccddcad540a7b2717f5c8c1708facda0a14b2ff87d36d5934fc3a74110b7f7c0b7e7982dca8001497c7b31e421741e88293b7d11dac13d8ef16b2678157d5c29a3526bd74e53ecd9f537bc8a91cb314aa8b873dc039a0763eedd7e7d32990d3dd7763a0d112cd7a117ca5c97b536cc085bb86c1cd7b81b3e86da59d300fb072", .Okay}, + {.Add, "-49a1871a31f230685359a05c2a84fca188c4f5f8c66b326a48d525bdafa244f0542a944d8667913b3484e27fa8a3a8615c542ca6d1cc4092e0d93464504b3cbe937945a8e3bbeb3cb4979d94115d16d9abc36e7d50a620514016357b9447f5d5c7d80fab837d35b8341711e5f482022b74658e6b1d8d3b6f081e374e22412e19717e7b6c2507116b68dce57e94c218c16de4d9e17887", "886038b13212a844003c4762d98694801253b29aacbf436d2bd085007b2679289252bb2f5b5647b37eb5e9ec3cc6de7a4f839b0fff2772225a91d1b7958d2e918548a6e448df05ff9ba16e4b39667786c6479bee9feb808375a5e2dadfd8773a3f42d78ad1d951d9f0c066c4e6df612860dae4489a3709edfe5cfa2bc1bc605401609a94006b3a50bb932b2d714779d75eb6a673ca8d", "3ebeb197002077dbace2a706af0197de898ebca1e6541102e2fb5f42cb8434383e2826e1d4eeb6784a31076c94233618f32f6e692d5b318f79b89d534541f1d2f1cf613b65231ac2e709d0b7280960ad1a842d714f456032358fad5f4b908164776ac7df4e5c1c21bca954def25d5efcec7555dd7ca9ce7ef63ec2dd9f7b323a8fe21f27db6428e552b645aedc856115f0d1cc925206", .Okay}, + {.Add, "-d89a36d154d908c7b0b4d492c0770b4b4c0094683952fe156f7ae236be0dacdaed9943af899fd850676c866407251ad100326139a77fbe3db4b51fa2c8396a1348dc29da3c68bc4355c3b6e02a436421c78e09e3ecbc1beba74b51f5776e4b0e44932f87a4990e46a4dade0cb03f2f4e6322082fd33ff5948f7380e4c95ce8802060f2df167d689ce41c4be79813c22c59136cd5ae8d", "e724928bc87d938c3cd2ddd2f5cd71a8386c263031e7735f6749faf7b377c99fe604e40ef2edf6075b3b4a4ea2014fbd307e54987041ef6464ee07a83b87020697cdd1120bfb9c5849805581a568c5c532e550022bff7ea86c2d7816c8a7ecd28d9ed23325a9e3402df03a3ec3dcbb2b184545e0daf71b39b3300ba79369a79e39d681a5d9a988b9b289cc57dd00ef8909808acbf29b", "e8a5bba73a48ac48c1e09403556665cec6b91c7f8947549f7cf18c0f56a1cc4f86ba05f694e1db6f3cec3ea9adc34ec304bf35ec8c23126b038e805734d97f34ef1a737cf92e014f3bc9ea17b2561a36b57461e3f4362bcc4e226215139a1c4490ba2ab8110d4f989155c32139d8bdcb5233db107b725a523bc8ac2ca0cbf1e19758ec6c32c201cce6d807044ed2d5cb06d1df6440e", .Okay}, + {.Add, "-8f90ac9f1ddbca465358b73bcd28ada444fd274e148c4a6ddee117292869aa2755cd257c3d40d2335ea38802632f18d69a535c87526f769409e7225355ea437e60e3e40d2558ccb80e38ad652f0a3217954e033fae8627c02122a0e8cd57835de193008a0e867b1b7753136181a46abe71204de42f9495e150ba5efe297823faca49bee7a212597d80625359db239099b8a88b3dc6d9", "ec89a787375fa466a466791f215ac4e84f953b2eaefbfc13f52d7fb7e0c32116aac41e846eb10be95d03abf13c87065e2a0f55ac22d1617dc4801416c90349287f60ec87be44be40db44b886d2a20214ac3d937a6ad3fcfa9dcd537a473fc69e3d8b014821cfb0b14a35db49d6f1e8871a4b0c9c2b9e011cee1a9a2682af6371db155e0e49d59510fa722a2c4fddb468b8caf26c9932", "5cf8fae81983da20510dc1e3543217440a9813e09a6fb1a6164c688eb85976ef54f6f908317039b5fe6023eed957ed878fbbf924d061eae9ba98f1c3731905aa1e7d087a98ebf188cd0c0b21a397cffd16ef903abc4dd53a7caab29179e843405bf800be13493595d2e2c7e8554d7dc8a92abeb7fc096b3b9d603b2859373f7710cb9f26a7c33b937a0fd6d274ba23cf0022672ed259", .Okay}, + {.Add, "-72e98c819c38e5f6da612cf2faf273d65eafb11324d03f1a26a16459bb82b295fcfe7ba867c145111bd0b8ba55277ce159947704fdc8ef5d94e0505a3c8a4f469a51324f7bcb1db50eb75ae8c02cc6283e52defd7dbaba4bbfe37d1549be607e72e91745c7ae8fea09637b6962e5b1f11b26f8f55ee5ae6043790cf95761290bd49d387d2a098f781cdd8ad9174d6c0f7c4676d6f35b", "b7aa52413199ca4a2a04647e15a847aa2af7da88f3f5c64b2d7d04d75a0c59db5f35ccf77eb2ffe24271bffe78dc323ee0af94a977829a83059f95827a07c163831fdd4997b42f0f190024d02fb5278d9083feb8856f573b9f724089dfeb759ff7859f10d0ae1346e90004c75c442910d4b1125d34c8284c0c8ed84583722ca6f7958aa991e7c3a0ea3565b415a66b1966927455c49b", "44c0c5bf9560e4534fa3378b1ab5d3d3cc482975cf25873106dba07d9e89a7456237514f16f1bad126a1074423b4b55d871b1da479b9ab2570bf45283d7d721ce8ceaafa1be9115a0a48c9e76f88616552311fbb07b49cefdf8ec374962d1521849c87cb08ff835cdf9c895df95e771fb98a1967d5e279ebc915cb4c2c11039b22f8522c67de3428cd57dadafe58ff09ea4bfd7ed140", .Okay}, + {.Add, "-e044950bbabc4a6c3459d2c72dff3348a54cf96568b3692f63e83c8f20666bfd355ee82141d0b8c73ffc4391db5d92bcea439cc3c7b603ae15f8235adf2754465689d0e7da834b57dd821cbc162c26cdf625b13b850c1c7dfa040bc64226a51847f8dd68036bb7b7fcc7f65603236ea9e9bdf0ea98459701e01f8f49cf24bb7c72eca4e65f619c4a52e8cb1e863a543140381d37cd08", "a9674312f7d121d1d337dfd63b3d08d9018e5cefb9a13781f05f392435c1af9838927707d5f8eeb7b0d8150df177a2db96eb0a99d4742b5968895fe52bab9938be456359c244a792a344e5284e534c1bd32d7f4b708bff6b346be71dd4faa5b820d79f7264364a4519895ed0c02354fd15254a02076f569d704f0f23dba666b26c8d5612978ca0a8cfcf5929b88a1ee40c9363c15e86", "-36dd51f8c2eb289a6121f2f0f2c22a6fa3be9c75af1231ad7389036aeaa4bc64fccc71196bd7ca0f8f242e83e9e5efe153589229f341d854ad6ec375b37bbb0d98446d8e183ea3c53a3d3793c7d8dab222f831f014801d12c59824a86d2bff6027213df59f356d72e33e9785430019acd498a6e890d640646fd08025f37e54ca065f4ed3c7d4fba1831971f4cdb0354d33a4b9766e82", .Okay}, + {.Add, "-a650f3c6d0886da42ef39e05e15bf46b11462bcd9ddfa7041eeeb1b20b86f88f295888bc5c2e7163768ee5b7682b8898d90ef9b2078baf9bd962d242f054cfa06c55ecf3a74fc7d58b5cf72a246cd10486f33423c12ee1f5e0185bc0631d05c348c7a7bc83a9c7fc2f6616944ff7ef073ddb3a7fdf9ea31be688c87cfa20e9894587e653acb63ed1d5ae6a0762a6ca093827623c8b34", "7e396bdd3fe62a8ef5604a8d24cf3716c809e9c4fb724e660f67a32ced45a875fe5783bf2fef0f262d821aaaa63c2749ebe3f8266485f81baff3f00ddb193e84e7312581c7180f571fc8d85f297adb2beb2d85bb07555a274056598e27377749008575742516282736e9040db194f7c2d90547802dd7b76e6c8a070a594078b42943c0241778320d34a5876df0e21ba76b9c121d8d71", "-281787e990a2431539935378bc8cbd54493c4208a26d589e0f870e851e4150192b0104fd2c3f623d490ccb0cc1ef614eed2b018ba305b780296ee235153b911b8524c771e037b87e6b941ecafaf1f5d89bc5ae68b9d987ce9fc202323be58e7a484232485e939fd4f87d12869e62f74464d5f2ffb1c6ebad79fec172a0e070d51c44262f953e0cc4a108e29971c4ae61cc8b501efdc3", .Okay}, + {.Add, "329b7b6f7052956df5a62bcb38c5c16e681cfa31fc7a8d284abd6c8e406e7cfbd402f5c8fede55a05d39c9443b0d2fc9138dcfe274a4c7bbd09cee494c2af394cab3bffef79a4e0c7060a728053607cc223751ec03e1e866c53d1017c7be7e3bb7805c3f83a89caacc4b789a1b34a993f7bae6b6f3bc5988c9d8068ba5f21d9c429e2a1e6e90fa37c52415d7e97a85653715b1563044", "4621cf46f772122ad9d80416210e3fb0ec87cdc7e05adbacaaee00aec11cccb83b4aa701a1f8c738c511e6903ca9dd8174e894a2ae5863338002b345a47c714c57bd73a56bb6637666409fa67a19a39e5291791a026dfd3248793789bbdfa32ccbd4952e990e19b4af3c7249561581799a8539da603a7b05f8bfa7e60da6975b6e3104e912f876d4a2e53e2b104f2252d1ac1db6bae2", "78bd4ab667c4a798cf7e2fe159d4011f54a4c7f9dcd568d4f5ab6d3d018b49b40f4d9ccaa0d71cd9224bafd477b70d4a8876648522fd2aef509fa18ef0a764e1227133a46350b182d6a146ce7f4fab6a74c8cb06064fe5990db647a1839e21688354f16e1cb6b65f7b87eae3714a2b0d9240209153f6d48ec297ae71b398b4f7b0cf2f078189710c68095402f9c9a7b808c1cf0ceb26", .Okay}, + {.Add, "9a9e982b619334bc0695a6cf89abc158faff5e6f105e89d3906f63dcb9f3bc797b1a758341debb8552c031bc370a747d26449b80cb928b8cb969dd95872501d8d6ecdc6a870b818b77e4842dfc5994e75f48b94d4c1df233e2406dd2a6c4eee6c4076802042b658f4d339472f1dfa5e0ba2c73bf09916daa4fdd09d8671bcb53c13b03532db1117e4335289a8da4192b89bce00e72fd", "77d62f3c465e63d72da3033f567bab73f12cdc4d42ec457c5dc56bcc8c98043e3caf48782280a7b343d3757051f1f8fb36675d9bea2293e8ea6d7abdbca4c1606bbbc141a7fd4748425b8e3c2a8789c052403145449bb3d8bb642133f38891b058a9b1a3ec8f54123ebecd1df1370203ca8f25e026fc5df026f7f89be2263db95d252ffb07f88277a04e2478900841bc29bdee410739", "11274c767a7f198933438aa0ee0276cccec2c3abc534acf4fee34cfa9468bc0b7b7c9bdfb645f63389693a72c88fc6d785cabf91cb5b51f75a3d7585343c9c33942a89dac2f08c8d3ba40126a26e11ea7b188ea9290b9a60c9da48f069a4d80971cb119a5f0bab9a18bf26190e316a7e484bb999f308dcb9a76d502744942090d1e60334e35a993f5e3834d131dac5ae7b37ace4f7a36", .Okay}, + {.Add, "30db468ec0c99a0c41bd1a7e2191980fa415dc0e9758778ab6028a63dcce09326943b5a05a3f3f9395b4f78ee11bbe975e5ca597d6dd82c666b63e8631eb233338a65980152adfe40cc0f3fe63b5b7a31064f65c85d7e7319a12e248a530b77a5d5d4452baad8d156312e07290ec9ea1063545d77f9013892d9d32bcb487e2b93c33cd910f3cf8ce258925a825efcba38b5047a19322", "788eeda70478608f7ee7b446c7293861f3530743a512786f3f616fec260bea35037e0434b531d98a9833c4219795312b2ee6f142e3978e8cf307ae111fcdc52aa39b28e4d07076a7126de2ea445a388bf520b6039d8b9d320a57d8b8ff888f3b196e4351e9c4bbda506168811f84bac9303226bab38cb69401156859c7b3d8320086dc496db6cb4658236e359e1edf960c81dce20be0", "a96a3435c541fa9bc0a4cec4e8bad0719768e3523c6aeff9f563fa5002d9f3676cc1b9d50f71191e2de8bbb078b0efc28d4396daba75115359bdec9751b8e85ddc418264e59b568b1f2ed6e8a80ff02f0585ac6023638463a46abb01a4b946b576cb87a4a47248efb37448f3b071596a36676c92331cca1d2eb29b167c3bbaeb3cbaa9da7cf3c4147dac93ddc40eab3997d224839f02", .Okay}, + {.Add, "-4853b8173958dff0ba4509803da828f735e6e23dbf7b4c46c6a7db99118bf81b2b919d199202a7879699ea48cbf13998b0690e10e5c40b00f5a58f053829b839dd111b7ff98a9a13cb89b1477ddb3cdd7e112dfe7dcc690c28d18106f59c825ebebc48fe4e3cfe0352bcb31ca0dfbdac1eaa8df3061c64030f0e3e65a87c455c34cc89e878e7c49a77f72e87797e51effe5abe6d9fd8", "39ae45525eb8c45717403e4fa932156cc596646c823ac2dc3a025bff147432e0164c8cd266a456bae34c32a9a8450dcbb29be955bc774ca5b341ff5f3e2b777af68b27b9469c0081d84d603daf5491f1476c399bec903586792336622330c3a35a17bb3f88f2ca4f013a0ab6bd97f555b6cd82c6ea4b3c37fe209946efaf16edc4244991e99fe599141ca93049ad11f684795296a95a", "-ea572c4daa01b99a304cb309476138a70507dd13d40896a8ca57f99fd17c53b154510472b5e50ccb34db79f23ac2bccfdcd24bb294cbe5b42638fa5f9fe40bee685f3c6b2ee9991f33c5109ce86aaec36a4f462913c3385afae4aa4d26bbebb64a48dbec54a33b45182a865e347c85667dd0b2c1bd127cb10eda51eb8cd2e6e70a840568f47df0163da85572fd13ff979e16bd6f67e", .Okay}, + {.Add, "174a9c04b50453ad00401437039d6416830d64a37b069fc229775fd068cbc0a3b3c381027704e191d08ddbc1c3aa32647c211f6470fa003145b7d130375894d4c5c70f7299ab54e83b24569f421825fcbabec220c9b84aebe863b4741745337256816cb421c67a32b6cd3cca69c77ef5b81f95b7171a2100129399c856b69acb8e193275b3fdb49b808bb583f2c13d590362b6a72e22", "fac9b00db005ac8a2ca601cf309b10c30f9eb00120bef31cfd1bfc79d63c1ff656498421772cd928fa730322cc452c452a4c29ff4405576ff60dde234bd646aef83be7d9f563d05eb2203a737de439fb27a25d0098dabf0fe25a8d170625361f8c0590bfaec5413e4e6ad5d479de0ba68f05aa560ea0c778647d25e406d3845331790fd6cb569dfbc263a8806c2ab932862349bbf748", "112144c12650a00372ce61606343874d992ac14a49bc592df26935c4a3f07e09a0a0d0523ee31babacb00dee48fef5ea9a66d4963b4ff57a13bc5af53832edb83be02f74c8f0f2546ed449112bffc5ff7e2611f21629309fbcabe418b1d6a6991e286fd73d08bbb710538129ee3a58a9c4725400d25bae8787710bfac5d8a1f1ebf92424c7f54529742ef5e045eebf68b89860063256a", .Okay}, + {.Sub, "-28ca54039072a6db84452b44c65e1313b9dd0fb1b1e2bd98d4d8a62eb2bbcfbfdd32484e2d795d4494e923f1716d7e58fbdf76279b873ea2ef471418ef26ec791114d86673509cafdfe1e1e38db8ed56cd18b40e85b72086688d792ce177bb8de0bbeec65d432f43af32af177dfc3937075ae29b789eacce1d77520bc126fd4a0598294307aa7634e291da7f7223b207e77dd6cb920b", "20df9e35cf331ac3e23c53af2ba989f63c4b6ce9675586765f0feee2212f68bda42501c4cf86f996650a476afe3d6ced7e9275dcd86d266b43e7cfc7534d6ebd30fd6b488b0b638a57221dd71a60d562a1837502f7063043ec40bab0bbd7e7ffc5d7a7c401ed29200253fbc629ed38658261a85b2be260669844eef874b503b2a8975505cf9dcb7d194cd24e52b32252105a43aa8934", "-49a9f2395fa5c19f66817ef3f2079d09f6287c9b1938440f33e89510d3eb387d81574a12fd0056daf9f36b5c6faaeb467a71ec0473f4650e332ee3e042745b36421243aefe5c003a3703ffbaa819c2b96e9c29117cbd50ca54ce33dd9d4fa38da693968a5f305863b186aadda7e9719c89bc8af6a4810d34b5bc410435dc00fcae2f7e48d74841b1fbdeaccdc4d6d459f7d81a761b3f", .Okay}, + {.Sub, "-54c29f918703304790dbe6422a9c76f584e9df4faa3cd588c68db774df1d738182b2db6bd3a34cda103457dbde9143a4fc9d3840342eaf4684875fd0ae8951e968140eca9625eb9f0bb21985898fcd9e2bb0c0a3d65da72974f15d61c71460f4f9b7a6ac5d6f7467ea80173fe84097d3f50b10621e1674eb5c98179a5fa2c74571af8dd64ca788481d95043d92433f15a6d30c02970e", "443927c0201574bdb072b432dd5c3e1ea5c1c46df2db0d139cff3ce042b74563c5d7460fd1da9d2dafe32278b7da938cf94feef0b075f1ddf0c38b4a657023a71c729209b8fddffbd6eedda59b44de5db2bbb658a4575891eb7723b9a9e12a22bfb86506ba0917cd568d65d84d95c092bb439020f621ce302a9ed17e96a433cef1284aaf270e9963411db84e7d7550076d11566da0b0", "-98fbc751a718a505414e9a7507f8b5142aaba3bd9d17e29c638cf45521d4b8e5488a217ba57dea07c0177a54966bd731f5ed2730e4a4a124754aeb1b13f975908486a0d44f23cb9ae2a0f72b24d4abfbde6c76fc7ab4ffbb6068811b70f58b17b9700bb317788c35410d7d1835d65866b04ea0831438431b8736e918f646fb1462d7d88573b621ab5eb2bc8c0fb88f1d13e4627037be", .Okay}, + {.Sub, "-20d50e2e5bc3050b94be91ace5cd5d8cf0ae3af5b936c2df391a7a2abd3b57d4d8623ed56a202fbfca820a612e34fb7b8b3136d21486ccfc3057bc5494db84b34c774d9f02adc66ee586d85ffc90d826908c5449daeaef28eab4f2b2e25ae9cc53c0bf7441bbfa573903c450c29a0fd7f427690e1f1934b681338f7117af5e96d5abbdd440a94c0001be2b3300fee1deeafd341a8661", "eec3305d80723a0dcead0338c5fc5698779f760aba6acdd4441a4c705b11c0f8d67ae3e18c6c7f893edf8887e3dc8d1747d980a96bbe323f9442471339af31b374385404575ff90da921d3cacadd14b285686df70569cf90a8fae672df599f3e961d039ca4a9481226e92d714bba64bc07b6bd7d3263d1a10312ccc8521089a4e2e486367fc5919b46351eb2833f9a756ac6f5eabd75", "-10f983e8bdc353f19636b94e5abc9b425684db10073a190b37d34c69b184d18cdaedd22b6f68caf49096192e912118892d30ab77b8044ff3bc49a0367ce8ab666c0afa1a35a0dbf7c8ea8ac2ac76decd915f4c240e054beb993afd925c1b4890ae9ddc310e66542695fecf1c20e547493fbde268b517d065784465c3969bfe83bb890440ac06edd9b47f349e5843e7c5455c42a0543d6", .Okay}, + {.Sub, "-dfdfa5ba6a972e199a2b9b64e4c5d54fca7684664d30ef183da7a2dd107bb2996c23ef990065763869157979fffeb990990f3e67604a4c4af7dae67a4f9857fd3c3d819425c3ae1ae2224fb616f9867f0541f9637073cb43c447de10238407376772eb0a9055fed3c928cda7df5811f7eb56eb51bc4738ca6a0f8ddd568ef1a70193de4b6a6e61f2527a04f78f3286969921115d41c1", "adb4378d631b7e2ea71d720b7ba91e673e5c92acc5375167ac75e3ed126350a4542ce16203446ddbd5b42b64838b133de134baa1fe7dc2b114f92c9d90c489ede2e2b561b89976fe8c19ba9315e9788bd9700158e84949c51a39c776e8f362563a36908602c86783f3a2298fa1d904b137d7ddbca66ea0869795daac019886f2e30aef5bb3e10211ca4635b2b93dd606af32a4534203", "-18d93dd47cdb2ac4841490d70606ef3b708d317131268407fea1d86ca22df033dc050d0fb03a9e4143ec9a4de8389ccce7a43f9095ec80efc0cd41317e05ce1eb1f2036f5de5d25196e3c0a492ce2ff0adeb1fabc58bd1508de81a5870c77698da1a97b90931e6657bccaf737813116a9232ec90e62b5d95101a5688958277899e49ecda71e4f64041cc03aaa48705c9d4853b5b083c4", .Okay}, + {.Sub, "b35512d4bba7631d7488939f232673f48f6e26d6be224287f7771f60025d383c1e4010593932628cb52e501ae5e57c041f14cbbddf8ed0e2efe70bc6e55de84fdc44f1dc7e12d8059ba59229c0c004ca32186291059ff07f8de7d8ffe3b91c512c064cdf637eab973ab02ac12ef7121fb5c841b137fb78b407facaa3adcee3748d929fa6e56da8fabbc5d5c1dfbca6eadd461cb72bc", "464a7f97c438e458a69415ce184373606698452e2aa80ea8974ba720e3a24876731e9107916907d8cd7c0d2591a2bd70ac4e7bec6c0d5c06065d56be39da7e42b55a9ec8cf3a84d76e9e26ddd1084be340e123a010134f3ff57d0c71e8b8d96aa6990013aaca39556ff33210a25529fd3b20ab949228ea42c04857e9740981082403c5ce1644954108bcdd22df2e4ffc62a1ff9b8520", "-3b152e6a787e6e26cf4b8c9426110c211da162c0bec5ea8017d4352ae37c74f2b13a9001fdd5e1b002292823e34465b06a5d2f308e146ef7d75ee601cb849fbdb7964fab0759575714e3cdbb34fc4b969dbf9d76ffb95037fc9e8ee1ea7d47a593d89b45b4924e9bfc482f648f65b8db3fc427797ea932b77fc8ab3f392c92d0db2a9bd3a7edbab15d007fc6c132858db4cd9dd01264", .Okay}, + {.Sub, "-fdbc1ef4cf1f7825845e163fee28506530aca768813d8f27885f57a0b082852d7cb8698763449d3a9ff5678c14175c42c7b1b725d6772ee7d8f2b6da0ede67c9ef49b2d14d2b6c80a48cef973ae3dcf98afa3f9f4f11d7a37c30c77ab9b95722181b084480dc9622d344332d0d32b8e4841c7996c9214fb8a3d93ffeb2163d5c2e4df059cb7933de5871c949b18aabe5aee162e72f46", "6ade2f5c4cfb2a6f13bc22a9be733be5a460e9f2fce014b8cac4d5d6c11ec3dff4419d69ea0220233bcd72e478649282cc4946ea0a9de23b421319a48f7c57fe0c791a7fb1d50183bae7210f6525160e4a113db88e1ee93f9bc16334087fe08ab3e50ea655c552092289a3b2d185557320ed1dfa781869c83e372f913df0727d5b098704c70b87f69975da9934ad6e77988968e92e7f", "-1689a4e511c1aa294981a38e9ac9b8c4ad50d915b7e1da3e053242d7771a1490d70fa06f14d46bd5ddbc2da708c7beec593fafe0fe11511231b05d07e9e5abfc7fbc2cd50ff006e045f7410a6a008f307d50b7d57dd30c0e317f22aaec23937accc0016ead6a1e82bf5cdd6dfdeb80e57a50997914139b980e2106f8ff006afd98957775e9284bbd4f1e7a3e2e6381a5d476acbd05dc5", .Okay}, + {.Sub, "-f20702d999a0fa193c113de38874795756af7a44368da2165c4c6f47ae6eaa43ac44b4aea4c8cf7f69f703e46773c1e6026c776755a49db7916428e16d2907a50c258f139f8bf613faaa5b23c54f1d7caa7c06d4efb2c5481a6e821b5ce05e963ad69d4f6a57c64f08e08d3cef991b93233318b8cb53d5266a081984a4735c461646e762dbf6e9a39df21a4fa207e096c66442a52fad", "401d6bd7124b904d72f790813e67094409b961896f9aa14c880c83179bff801ec57ddf1328c5a11ac03d266543f196e1638a73f7c1df022a95dcf8e25471b7648bd9d13701f39f50ffb54b6eeb29b3c4842a80eed038798152e598fe628947782ab27a721347f83a695fe0f3292fdc1fcc333844a15f33a5272faedc29939204639109a67de7429e5eac9b7733a095e092772d3731e4", "-132246eb0abec8a66af08ce64c6db829b6068dbcda6284362e458f25f4a6e2a6271c293c1cd8e709a2a342a49ab6558c765f6eb5f17839fe2274121c3c19abf0997ff604aa17f9564fa5fa692b078d1412ea687c3bfeb3ec96d541b19bf69a60e658917c17d9fbe8972406e3018c8f7b2ef6650fd6cb308cb9137c860ce06ee4a79d7f10959de2c41fc9eb5c6d5a8767758db6fdc6191", .Okay}, + {.Sub, "-41930f6dd645f896d431202caf963d1aaf4af9de0a44f3d3abc9e13429ae0489626ddb7354fecd695d4afdf918437349df96231cf8c11577dd2ea1b295d886f30644f1bad3518c7b062e774e4bde3d5c4e526d7b7b978c168b5a9701892df74aa3e4a47652ce02f06a58bd5b39e59280e7490e098772c60c400b1106ef12504ee8ec089bb6c36b8d40d0a1876332b290677087229874", "76d6657760711ffed878bf2a17d9ce6f24a670fe6fff2a12ddfc018402be95424e2f9d4b9473b1ba1ec7d8fa1ff9a830b2b5405ccb736d5b8ad0c1de1e18f3cca2f517d051e409865ef0a436d6e420c458ec8397347cd1d781bd773d9efbc05e80a6e70d495c34baa2207da5a9d2ea7f40191b12bc47f7ab9b62235921ca70c90d9687f9d4b1c97309c382efadd40ed4022361454c3c", "-b86974e536b71895aca9df56c7700b89d3f16adc7a441de689c5e2b82c6c99cbb09d78bee9727f237c12d6f3383d1b7a924b6379c43482d367ff6390b3f17abfa93a098b25359601651f1b8522c25e20a73ef112b0145dee0d180e3f2829b7a9248b8b839c2a37ab0c793b00e3b87d002762291c43babdb7db6d346010dcc117f68290958b7535004a9424771106c1646993e867e4b0", .Okay}, + {.Sub, "-58f84d3440b1481e1d5477993e03eced47c6c58be306608c64f59859a8117953551f114b2b870a6dbd6d9c882b16f100393db0b409b00e008bae0a5fc4c9418ed16108e8c1cda08b2cf229ae2abd2c0dd55815fd472f22bc8ebfdba2aac231bae164b7c66a2b312d60203fe5ecb278cd166f11fa92c7bc11669c19ec66320e086ebcf7d68993f95dcd05fd40a2bb26f08c697b0cefa0", "bb942fe12fd015d03a0d5ec11eec514164a29c02015cecf3ce64dc2cb374ac77a60b60aada09540ca86a2eac142452e62f18743ad1b742046930887d9508826f0e64326bae0b207f3a3fbe18e4de24d787e0addd77b9e49777a723a734f7c7416012838fb455fe256b265f56bb112aab5cdec632796ebb05e4c99f4907902d599ca84d2c9dc3a004e3f5294cf857f596cda1901736fb", "-1148c7d1570815dee5761d65a5cf03e2eac69618de4634d80335a74865b8625cafb2a71f605905e7a65d7cb343f3b43e6685624eedb675004f4de92dd59d1c3fddfc53b546fd8c10a6731e7c70f9b50e55d38c3dabee907540666ff49dfb9f8fc41773b561e812f52cb469f3ca7c3a378734dd82d0c3677174b65b9356dc23b620b65450327579962b0fb268d9b131c875a0b0b24269b", .Okay}, + {.Sub, "487ad545a973559d76ca5de766289f4f7d3a2e1bf15f0568c117f9dcc08b26462c344788c8a79bb4f4b091a072a2adb9f4200480f897547a9d62660642c26413c4bd55a0c6d49cf83bd2a987cfebfabeab8776fa4746a6e6f5300676474de21942a9a0b5d3206e0e0c9a09c9a78e39d57dfda659f54ad61f59f2258387570c02dfd6b3bf27b3d2f83e55bc3fd3f1e971d4d87cdd72d", "758583d7f4018fc0c4191741523c3b9e83351e02c7a14b2377cc707ba6abadf40047ba3b4c88b1a8eb90c816815f960a668370beb9064325b880ce2db54c06df1173e9ce79409c08ae6e77f9704ae44cc41f17def42a9297696874985a38437e0ce8aa1fe39c6045b35c9bcd711946c2d8e8f97779b24dd5eacd57371b52b3d6f0816b58f4a217387e9d20a638bf71ae0076ed5f4c51", "-70fdd683996a5a66ecac7162dbd9b1a98b617b21088b5accebbaf0dddaa2fb8f9d8475c2bffe37ed9c45befc7a356b2ec7417076a97ccdde0eaaa7cd511fe09dd52814746cd352392ab14d60f34c24a0d966a06f4fb62828fa157430f5c3655c78be1014866a5964d292fb30d6a0632581091f11da5da073f52e34dee2dd4316c284001d0226da08fab7c4e23b805316e32965917524", .Okay}, + {.Sub, "7726389aa316a95172438de543cd5b9df03242c6518d3223f3b6ff79d3ece6d1707d9b27859911ee76c2c4b8795703538cd542c95f1fdc26e95ff613849e73bf2563e459272b8efe0e16cacba4b75bff11cf32178a57f6032af422d276fd1daf7aa32ef0709132b98236ea5511a6924737b0381346321ff61f6368904bd408eaf41487125b9ebd607de77f908a19373b9547f235f9e7", "bc0482cfcbec41531c7e0e908622aea8b58f793db0c9ae9d3523c4a7135a503e2a602199a966dfdd9d85d8a9f18e0f6528f3085655bf0f9fccf9396c66ce8d7e368c12b988359ee1beb83c934aa54c14ecc243a08a2c6e631c43f67a1ef67059d356a9cd97a9b210a35affda71666763e4cf04c86bef9c4c1e803fe780e7162455c27a8cf2853a27523c7c33c96dff3cbbc5aa14ed31", "-44de4a3528d59801aa3a80ab4255530ac55d36775f3c7c79416cc52d3f6d696cb9e2867223cdcdef26c313f178370c119c1dc58cf69f3378e3994358e23019bf11282e60610a0fe3b0a171c7a5edf015daf31188ffd4785ff14fd3a7a7f952aa58b37add27187f57212415855fbfd51cad1eccb525bd7c55ff1cd75735130d3961adf37a96e67cc6d454fca33f54c801267db7def34a", .Okay}, + {.Sub, "54844dc3a3f2f627bf25dc8bd3c119115021bd866a243b67e4e6cfa7bfece30a363ca9b71e33b05d7ad818c4bc295b1f039995f5c8d833511922ec9ec3de46df8202f47b68b6cd614e1d4e460927cfbb95825ad6049bdade21367a40b6bffd7b548a1dde5c63b9521c2aaa75f63801c8bead98d1271174befc6dbea32c75f867759f6bbd487b264e2ac4e537154db95e2ddb3933239", "179990d4a28711eca27d59ebd2af30dc8722f1bd9dcc3ad058d530f230578bb66691dbc1fe0d05702011e45be2cbef272f1802ba1b28348b75f6ece4b1b2bb8f11b0de2a5163a422cfa92633d9e58fa28eebf35ce85e6241ad1efe16a7f6241f8c31e2371e7053fd4f64f310ce1d0ebcfecbf018674dae34c3814a8688f3c81d9d135df95ef90c3852d1c108f3779eb88f4e8aef8518", "-12514bf86847e28a268afc2315731f4b7220d5e53729f719da86c3f7b458bd85c32e11268c29ca6a486462cf970959753ede695abe9ab1566464be1ac574d7211990aee29ad8374cbac7514f795312a6d593cdaf8814a493cb0b96729c8a2447d6e9405938aa18682da248696eb98ea072e1168b54dc96e8d3ba6e9c562c689725b9673d8a7159d3702572b58222c322ac70d75c52df", .Okay}, + {.Sub, "-57387ec90c2f238f94fc3e40e12ed3ebb4f68e8ae815986fa4efedc54368ba7954735aba88a5f0803efac9b8c84e4d9894d752f5e03891e9e27208590fcf71c5ba4f6a81bc453d788ee0e47b071cefdeb9e23284738a9d3834597f4d9e4186352475ca4f86d3a8a3f56f257bd410b666054a22eb90d517c831fa830053c9a3d15c4aa97e40d3cda3176cca89a81e5fd45aa8c4c2c16d", "670c15bf78ffbdda169f8222572224477b73cb8ec043357ebabe6e5f87c7909ca7d2be973f34a0b557a649328c3a07b9077c840f19571ce0f0ff471974b423e884889085e9976593f54d708bd80b94fc8d367555ce00cbe863bdaa2ef4ad294f90ae25b68d3898d2b927be8a4b9fca56b5f36cd1edfa6e6db415278bdda084f8b7cde9ece4a3b8d5208ef522c2cf75bc2b86d0f2e8bb", "-be449488852ee169ab9bc0633850f833306a5a19a858cdee5fae5c24cb304b15fc461951c7da913596a112eb548855519c53d704f98faecad3714f72848395ae3ed7fb07a5dca30c842e5506df2884db4718a7da418b69209817297c92eeaf84b523f006140c4176ae96e4061fb080bcbb3d8fbd7ecf8635e60faa8c316a28ca1418936b2577867837fbbfac6aedd590862f95b5aa28", .Okay}, + {.Sub, "82298924850fbb61e8bc9ed1f9def5c048cc4bf4a278451f633924a10fda3fa736510cd6ce95146562983e665d9e6ec387b57991e484e4f20c71f7d60e36d025cc488fc5524fe0d992dbe9dae8e4465ab3a0f615d8541558223fdbdf158b1be5b04b53cbda94550558279f6a8dc3730f3b95f82ef4c7fc5662467052d0344aaa48517b08413d685b19d3905350f0f819a6e1408c1a3c", "5d361f8afb7e9c84129dd1f2faa5f0bcde8a49df2486571e91b67b38f6114a2d011fd7a8165d171b3475c8a17880877021a4b3ef87b5fdf9a944573a41b8341675281c0d3254ed387f74471f4507bec41c80044ec24a90f45b923b517d3a1a78b5475fb64d49fc4b551a8116f19c166f4bf2babab9c78c96f055e8f3c7f0853e992c94374db5f66a6e13a1288a61c521e4d0d1cc871", "7c56272bd557d199a792c1b2ca3496b47ae3a756b02fdfad7a1dbced80792b04663f0f5c4d2f42f3af50e1dc4616664c859b2e52ec09851271ddb2626a1b4ce464f60e047f2a92060ae4a568f493ca6e71d8f5d0ec2f6c48dc86b829fdb77a3e24f6ddd075bfb540a2d5f7591ea9b1a846d6cc83492b838cf34111c393b542565ebeb1c4cc6208f472f25640c84adbc78894336f51cb", .Okay}, + {.Sub, "-d99e7dd93bc09610a749c5863caecdf411c86cd7534c3d701487dda260dce42276a1ea6ce6c66135855383a05ff74d1e7422cf10536f35ed75e62a979bd8f6333f3ee29ad04851730f8ebc35aa8ad436d74e52b23e0e1a013bddfdf9c55cdce264608f9b066823917ff71c591106d325bec7c48b7936b6dff97f020237c8bab2b2571d2658a54dec343bcc7cc3bce2676152ff03a615", "2453090144b44ae7b704aebb3aeab5ae9d3f56f8b6d54da0252d6b342f4822c9cdce2f9f8451223cb2e46d309df4ff761f155214ae09a33e3d3aa2ea908fab9a09c8d9bb96d095aa81b7264e13d0ac9e68ce76e3b3d8fb229a1c773f978b44424dea19042ac37b497989bd061bb80a6dc58b1c47ab41597383da1f83eba98a2248eec3cc98b106317abed829077642c980d7de7e08a5", "-fdf186da8074e0f85e4e7441779983a2af07c3d00a218b1039b548d6902506ec44701a0c6b1783723837f0d0fdec4c94933821250178d92bb320cd822c68a1cd4907bc566718e71d9145e283be5b80d5401cc995f1e71523d5fa75395ce82124b24aa89f312b9edaf980d95f2cbedd938452e0d3247810537d592186237244d4fb45e0f2f156541daefaa4a5cb332530e22add81aeba", .Okay}, + {.Sub, "9f18bebfac40db9840e0069d7a320ec6fc7d758766461c100f2dec0d0a988ff74fdb2c898054e32de360111181d3ea4397a4c27da72072750f0a052029ea26ce3183522f1f1557dd6f515ae60684654853c7479cc57fed2d51ec0868b1ef33c88bef66768a3816fe59a603649921c22762435c0a250fd5461a36121c2fa6eb0ea352dad60e2adfdcd1e5855aa9d67dc70344b67d17b4", "4d2cd1d3a589a42d593fd3c6e386581a2b886d9c508eaec18b0de919dcd37508841ffa2ba91ec0878fe519ffa4b866766f0f21f0714407a9f56f1304addb1fc55c88329dbd32cbb5bed67c8128ff42076be3e27cb62420ff0ef636a5773da60b59408f46ac1b86bb6098d9ee76f5feecceac553072a33f95cffef23d508650ee251be2c350130813fac5522c959f450ee4df03982907", "51ebecec06b7376ae7a032d696abb6acd0f507eb15b76d4e842002f32dc51aeecbbb325dd73622a6537af711dd1b83cd2895a08d35dc6acb199af21b7c0f0708d4fb1f9161e28c27b07ade64dd852340e7e365200f5bcc2e42f5d1c33ab18dbd32aed72fde1c9042f90d2976222bc33a939706d9b26c95b04a371fdedf209a207e36f812be17d7c8d720332e143738b81e65b2e4eead", .Okay}, + {.Sub, "306815455c975c6fcffafeaf44b5f41f3326140fb66f20514b14ecd34c8b9c618b950b2f93f2bb1266a7eb300bc76e9e35c65a076d5a5e2b3592dba6716d1bca2d7ba5fceb6f1530557d84e36fe98bf45d770879c9ccaf94da2f30d4d1ba0e167393e922db757f5963c9af4334175864d13bdb1e6f4711f2dde8a0908f762a82371da0d83c3b679b85e65f057cb4166b7fd062207870", "1b2ec3d946216d34a45627417306c2e3ecf209ceed1218edf8561ad6376e28d31e516c7bef71103fb5f57458902cb8c2e13986776111ed724c9bd299a81e08f55d0a0088e005cd997789e55d9ce80cf532c2095e0f3e3fddc516d0d2c2a684e2b033ebf8374f75e9b695e30281b3927b2128ac464c389fcb5df71fac4d51eb3c461ecdaa9101523a552405f205b746c51553bedfbf1f", "1539516c1675ef3b2ba4d76dd1af313b46340a40c95d076352bed1fd151d738e6d439eb3a481aad2b0b276d77b9ab5db548cd3900c4870b8e8f7090cc94f12d4d071a5740b694796ddf39f85d3017eff2ab4ff1bba8e6fb7151860020f138933c35ffd2aa426096fad33cc40b263c5e9b0132ed8230e72277ff180e442243f45f0fed32dab3a156130c2591376fccfa66a7ca340b951", .Okay}, + {.Sub, "e8e335097057b90ac0cf5268f75c81ea8d05105c57a2da574ef821c75c69bc7259a26e62b132dee6d6d9dc98821f4aee949851520f38ee93383153d5cfbffd96faa15a6b4856901a42849c3f086004f74610ecef3cf0c108ffa33963ce56200a35929616a024b62d55fc35a91b00c81f2344d28fe71c83af5c86ca19aec209fa94547e9281576006fa19f0bc085c2e255f9cf166d978", "56eb5c41737b1e0b50d8149a7abfed76e3bea47084196c2a5650121dffa8d4292cffc0ff8398a5f142da7df11bb09e1b5157d54716aca5f03a2415751c5126c08b4536d4f1a38964f43dd670fbd119c3ebbc0986c1e6a35dce8806e5bb02d4cfa909e37c29b275ecf003edad04967daccebf464782472f81050ad6f61926960c5cac878881dd924c7af338046040783ddbcddd74bdf6", "91f7d8c7fcdc9aff6ff73dce7c9c9473a9466bebd3896e2cf8a80fa95cc0e8492ca2ad632d9a38f593ff5ea7666eacd343407c0af88c48a2fe0d3e60b36ed6d66f5c239656b306b54e46c5ce0c8eeb335a54e3687b0a1dab311b327e13534b3a8c88b29a7672404065f847fc166a4a7254858c4864d5542e577bf323959b73ee37a7f709ff79cdba7f26b8b7a81bb5e783cf13f21b82", .Okay}, + {.Sub, "-f7b79297871fe6ff8388d1e1b027435b27129c6e3ea5935faa4cf1ea941483c781b71fb114c94a32408a42386049d5e7c041bae2168a5b63f82f9cdc2effb7172d20da164a62ff5244ba4fb9d060e1a0622e51fdc8defcbc92a9953456ae11936be87093f727a5d2f3015a9af9a170d3f98bfc1d6b85515e52ff55109513cf6cb6dec1d0210a5b18befc25e38f1bdb6ec3921851ec25", "5a46310ef7517a0ae7633ea7b22e1bb7b75b4230f817d600d3188862292f0160633d7d5b5b0b9019758d507992a343e715f2ce085818dcae7ee196c9276e336983920fa804c65c475796f468d2179e43ec572f5e2c9c47ff4b81bf2f0724fdaf6247dfdfaeb4f621f8732ea8dba6fbb9298fdb46b3fdf51857a1fb7a10e0790dfe855568cf133550a5ebbc4ef2ee7b54f728e22f42e1", "-151fdc3a67e71610a6aec108962555f12de6dde9f36bd69607d657a4cbd438527e4f49d0c6fd4da4bb61792b1f2ed19ced63488ea6ea33812771133a5566dea80b0b2e9be4f295b999c514422a2787fe44e85815bf57b44bbde2b54635dd30f42ce305073a5dc9bf4eb748943d5486c8d231bd7641f834676aaa1508aa5f4487ab5641738f01d906964e7e232820a56c3babafa812f06", .Okay}, + {.Sub, "-872506b51b6934a92a28b8e7834a73389f2d3a00d6f5ab9ed812982224c268ecbed5ad3552d00b48ee559c481278b665121038e6e78eeebe965d51703827fecdda71cc6677855a59ec7dd5b1067587b1b99fe18dd5a48f99aeefaeba57b7455305c5e831db974de5388dd5950ae8c955066635b7cf48e0dbdfbe625a2f43599395f0351624a026e4bb98ae2e6d30513330f6ebc98a11", "a4c944fec1e0fe078fbcc6780ef7d16b67aaff4d44b3a438c7f9a10924236fbd24162ed3121985d86fbb9f40f7a0c5ed247330af2408439adf63caf2fc00c47139abdaeb2f2e51b095b0b2f01937b3f53040e2cba9767845238af1c7804cb6217e85624b7ef3278fcd025da22c36b07226a90e7307c248560e5d7de0c6ed0ea6ee607b598f249d2af71ef30c46f12bdc564c058b57f5", "-12bee4bb3dd4a32b0b9e57f5f924244a406d8394e1ba94fd7a00c392b48e5d8a9e2ebdc0864e991215e113b890a197c52368369960b97325975c11c633428c33f141da751a6b3ac0a822e88a11fad3ba6e9e0c4597f1b07ded27aa081d803fb74844b4a7d5a8a757505903337371f79c72d0f442ad70b2931ee1be03af630683a8450b06fb3c4c40fb2b7a13ab4217d0f8742f154e206", .Okay}, + {.Sub, "-83bfd9ced00afc9d21887e67fb2bac51a06b4116a7a1efc9f8b4edc48bdd812102fbed6219756784d7b0d11e2f925a785cb521fc88fea0881bbaa332cf2bd7baff782ddb222502f014347ac78c9902e5b09e946d6c75f923b2de25cb7bc7a9abb91eda67863a22bc704c70d3edae80dc899c1d760edfc8aa846939a3504c5ed41d61d9db24d83f21d416e1559aaeec74acc87b290252", "8d0e98ec7c5de4dcdeb4115e92d71c1d36eeae7606fd5ab4a6eb29fba613c9e6a5e5d4297802d2787317f6ca1a78e6560259fd79325e8ad154a25546c7f1d46f0efcb1b135474ee1686296b7194c60c7d542c38e9d65dc94d2d2e410dc612984ced1de27e328fc3eba50dfff65f7a3196a1c186ed713caff174616f714dbceead57354243e92504bf032251b5903b7d469dcbf4af2d8", "-110ce72bb4c68e17a003c8fc68e02c86ed759ef8cae9f4a7e9fa017c031f14b07a8e1c18b917839fd4ac8c7e84a0b40ce5f0f1f75bb5d2b59705cf879971dac2a0e74df8c576c51d17c97117ea5e563ad85e157fc09dbd5b885b109dc5828d33087f0b88f69631efb2a9d50d353a623f5f3b835e4e5f393a99baf509a65282dbef2d52dff636a8f6dc4490670f3b2a44916a53a73f52a", .Okay}, + {.Sub, "-3d80758b3708c7856fed4c70f79ee801d4253e19394fab9f29e101dd6cee76f94389dbc6a3a3e778842447c06dcb40f9bdebd207df2377034ad7bbd9c39a370afafee7795d7c0762ace37c19d220a4f90ef31d1f7b6551bbf8b7589c58ee404ad5ecd831e44d1d0d95a085581e79dde385f23fcfaf1ffc6a3bec1fe53636eef2177062dd1fba38ebb88a3cf09c6b4b5084d5f04cff26", "bbf81a362bdd701e3a28984b0b73713362dcd3f93c867c0208295b20ab3a8fe37128d11a19ba1b25c5e3bd25f47d67ceb230a15c94592a51cd81b68c4c39c174382c8e2d06309654eb167b6f6f791dade2d9cc61a470f1c87c2d80081b5067f01ddf91a5c56384450089db6d366457ee9e0c9015fb3c6e8cd4c05015bfb80ea8793db65ee4dcf950b184cec76cca242fa346e6b9f35b", "-f9788fc162e637a3aa15e4bc031259353702121275d627a1320a5cfe182906dcb4b2ace0bd5e029e4a0804e66248a8c8701c7364737ca155185972660fd3f87f332b75a663ac9db797f9f7894199c2a6f1cce9811fd6438474e4d8a4743ea83af3cc69d7a9b0a152962a60c554de35d223fecfe5aa5c6af710ac6ffaf5eefd9a90ae193c0497323c6a0f0bb809356f80281cd706f281", .Okay}, + {.Sub, "-3a6d3e85991d88d3e2c7512c5a3087483d019fa662e3a3101cbd21ab500d4a4c0f65148786ad7a07d3dd9fd92fe466ddbffb3907a9c3f01ea17dfc669c74319026ac67b30b2fd6eaa5b948426da54a7df35993f884fd98971e7ff3747643f059052c67c607d11ee13793ccc1d8dd17b51acba688b4f62ca01572f660c54c2d43b0d2fb13b539fe9800ac4c117fb8f1af61a5982820c0", "393c342ea44859bb10459b325fddd5a0492c40638f5dcf3893ac51de438e65b3019d8f6392da062dbb3c42910a6565ad14a7ef4a39540d87b1251bbc85e7702f40396429352913ae4dda96b45551759c9122fe20705cde2fa9faf6f91829be14f0b2409be6f378b40c1cb7e7341da40cbd6ba013d3a8f0b4713fd0a5e6688b2c93aec1c0f83bca0888f3f0a03f10ebb7a5d44c0bd95b", "-73a972b43d65e28ef30cec5eba0e5ce8862de009f2417248b0697389939bafff1102a3eb198780358f19e26a3a49cc8ad4a32851e317fda652a31823225ba1bf66e5cbdc4058ea98f393def6c2f6c01a847c9218f55a76c6c87aea6d8e6dae6df5dea861eec4979543b084a90cfabbc1d837469c889f1d5486b2c706abb4b8704481bcd4ad75c8a089a03cb1bec9dd670779e433fa1b", .Okay}, + {.Sub, "21ebbcdef2f4b1b2237360811c98753ec21feac8e43e52953ff24887b27a771c2131065cace5b18543c6b3f490e35a727224dd4e920beef7823b375ba1da82b865050f3240ee04d5a712aa7aa8b8457e160be503c7e42d6cd7198c5d504a1621c6477395fba0f8b7215a7d1bc74ca1ac8280dd2e869eb21069220f4ade42098689355dcdcb29448b673cc87814929e75908a4d1ca0de", "3d1ceaecc84e06a63638c1de96f040916f167b929257eeda4ca630d967e8e6872a2552b1e5d899e9437cb2ad4f4795a51cba4e2ad37d2c9dbc6ddf941c2d89fbf20c13746d229cc7f10658f7cd607e331c33fed7137d162c44b46ce3e0c95d52b4dcab3703e34b6c9eed3b75b4449040bdf4181c55bdd8f80b00ccb7cd2f8f31cde6df0141cca7caa70db2ae3ce1f2ae8748da050847", "-1b312e0dd55954f412c5615d7a57cb52acf690c9ae199c450cb3e851b56e6f6b08f44c5538f2e863ffb5feb8be643b32aa9570dc41713da63a32a8387a5307438d0704422c3497f249f3ae7d24a838b5062819d34b98e8bf6d9ae086907f4730ee9537a1084252b57d92be59ecf7ee943b733aedcf1f26e7a1debd6ceeed85ab44b1813376a3633f3fd0ea36284f5438f6be8ce86769", .Okay}, + {.Sub, "-ed70aef606e646e18c0af8c52de232651e6700e212cb717c305cac81a395c13edc1bfabde9bc6d3a1d77620f735658d96e9470c462a2da0200193927c3a9decad32751889efd058106bdf87ba2effbc062ea7a8db817309b39fb6f2db4a8522b53f3e83008e5f04efed0d1cb9f0139c1f13e7bf3db6cb27a9e4c002da006757170024cad9faf054417202ace20b92460319d1824cb88", "b56cc6b37179eabd180805229d183f8b1e90b92b2d379e5646fde57eb28844eabb5b33455aeab6adb61d38dc84a2b0634fc735d4b5527b9bc69246763274e20203d7b9eb074e7e760ba22bb4aa247e81aa16ff6c78221be1140c5d18277db509dbc288d1cc6a58a05cdf6eea2fe7027bc56fb70500fc11ee1b60cf916e399a849af5a278aca4590d36880a4b4ee0e244db6ece5fa650", "-1a2dd75a97860319ea412fde7cafa71f03cf7ba0d40030fd2775a9200561e062997772e0344a723e7d3949aebf7f9093cbe5ba69917f5559dc6ab7f9df61ec0ccd6ff0b73a64b83f7126024304d147a420d0179fa30394c7c4e07cc45dc2607352fb67101d55048ef5bb040b5cee83c3db6ae32f8dc68c468b9accfbf0e400ff60af7ef264c535e514da835196f9a06a50d0be68471d8", .Okay}, + {.Sub, "-53e3717614f4451790f6bbb4eed7e58b6d62e6ca9f6655b64216c4be7581fa1356fe438c19e39f04c28b39c28dd530acfe01cb0f6c72f0e0b9013c53c2206f577f5f5ffeae2becc9c9136ec8a36a548c27c5e82c8c3fe66ca47c701954b67e2f2709586abefd6b101394c57168d722393bc198cf6fe0213defa6e92715f3da17fd76ce93f7ef1a9ffff05469064a630b6d4f936d9a95", "8d50598fd78439477a5c7018f14a7f392d0de50bd487512fb05e99936998e0554665f8edf6ed2eb01814a163c32dcfca08bd1e780bad896aac79c73603709b438aba3b80bc0a7e06715aa68b78bb67ff5fc8506f93f23a86b1133d31a1d9a124d836b2f73214610898c85fc9ed4c488d724138393c64f9e4a99aa68d16798542eb501467398fb8f58c5122eef348b04f01e2b42e36fe", "-e133cb05ec787e5f0b532bcde02264c49a70cbd673eda6e5f2755e51df1ada689d643c7a10d0cdb4da9fdb265103007706bee98778207a4b657b0389c5910a9b0a199b7f6a366ad03a6e15541c25bc8b878e389c203220f3558fad4af6901f53ff400b61f111cc18ac5d253b56236ac6ae02d108ac451b2299418fb42c6d5f5ae8c6e2fb317ed3958c417757f993135a6f32479bd193", .Okay}, + {.Sub, "-3f8bb0d4a755003f61b71c0c7c63c4ff6cdf8026f7ea5dc867f4cf7a1a04649591659c5aff4b31f052d70d881453692aa023cfaf593dd615669eb11e376476e70f0cbfa48e80ba6e6de2515958f845c59befa2cba41fb0a687913dc7960fccfc5feeadbd6d712c7dfb30a844d92ae0640a39c5c54a8f3203e7a636ddaf2f2ee1694a7fd1d1d58e66afbb137a0a6fa13d1bdc2269b536", "de145d35494c97b8bea82c8b698cff476e636063d433584d581e39d92a6f22d9ce7021331a7b4b08599c94e1dcd1a7fe94a633c7c40c05230a3aaf5cd0f0364cbb04e3cdfd6157607b74e3dd5c98036572a60ef3ed6db7449a5652d69629989935189b953c764c84b9f859a62b72caef453ae8cf1d90719b1474432e2fccc2c36bd81d2d1df9423836a78708ffa643faa0fbbe12063b", "-11da00e09f0a197f8205f4897e5f0c446db42e08acc1db615c01309534473876f5fd5bd8e19c67cf8ac73a269f125112934ca03771d49db3870d9607b0854ad33ca11a3728be211cee9573536b590492b0e95b1bf918d67eb21e7909e2c39659595074952a9e77902b52901eb049dab534f74ae94681fa39efc1a7a0bdefbf1a4d5229cfeefced09ee6629a830a15e537bcd7e07bbb71", .Okay}, + {.Sub, "10350085f26436b307f5465f19e929c1379956aae3c846fcc07e1a207ba9ef53e3eb37ca4eb155b3aa8ae092625abb1ff559a90a90745fa9c53ba9245eab71226999b1a7d4d594f140110445755b554c7ebddccbb7079ec4e7fa7ecda47b9f758e79273653ffc1a38b45050463de3c074a88846b93bfa41b3227a5c2bce2ce53df8f0af174ff55ab491931f5f6ea7a8b04282d972e49", "e233ab87d3cf770ffe31c167f123ac0978791a27ad85a34d7f1ad1d7ebd833b74b45ec4863252f37b347d5114683641c0da7c01e51a4d043f4038dbed6f270b36203c3a123587d420a8e2d7eb6743b62ff3554dd59c43bf8548c6cb47416a1e0e92ab68bc4f3e74a25e945b468e52c3452ff300d5757bef152071119cc11a31542966426196ec79d68f28602ecb15e13e6b9a81b6826", "-d1feab01e16b405cf63c7b08d73a824840dfc37cc9bd5c50be9cb7b7702e4463675ab47e1473d98408bcf47ee428a8fc184e1713c130709a2ec7e49a7846ff90f86a11f94e82e850ca7d29394118e61680777811a2bc9d336c91ede6cf9b026b5ab18f5570f425a69aa440b00506f02d0876aba1c3981ad61fdf6b570f2ed4c163075934a46f71f21fd9540cf5c6e388e2917a8439dd", .Okay}, + {.Sub, "7ee79f46a3fb768a5b5b30d1f089980937f91dfbb44ce88282bfe561dbc0e528432893336c45af1bef918cf8295429a65581ce0940adb6561616708c088acd14accab6393d5f89f4b443a035505f65e44c0a2fcdaaa540e415ff8d04a26efa0d3057b558667589821eb8c2e87abc9afa3d27ae5ffe10a3eff8760fbdd2e9e6fd17fbd35d6a172e6a1135fe01ebcf329b81f4caa8f640", "103ea738455e03d8c4d5ef168bd29b8db15eab8d8f3b3e9a8258f5978854d1f40d452b119b589caa49064dfbc52f2cdaef4ec8547ab03106b0d588032d0e032ac268de4e158cc470b8731d93eb50aeb549fe9d8422c950f522cae1b60ee7d5de644b592226280b42598c8206a074656ba2197f789ad7c9a80692dbe4e7e1c6ea8ccd207c3576c6ec2bc27eaeb28e9033e1ce86e7d400", "6ea8f80e5e9d72b1968541bb64b6fc7b869a726e2511a9e80066efca536c133435e36821d0ed1271a68b3efc6424fccb663305b4c5fd854f6540e888db7cc9e9ea61d7eb27d2c583fbd082a1650eb72f020b924987dbefeef334ab4e9387242ecc0c5c36404d7e3fc52c40e1da48358e9b0e2ee76338da47f1e333d8eb0820128b2eb2e134a0677de5737f533940a267a02643c12240", .Okay}, + {.Sub, "-bb06e305207438f2dd14bf5a8fe983870e743d7bf376db742f74a6e9eddf2010b53de002c9a5cde5f70bce2747456273043a6d7e99f87a9733e369ae77641043b76d7cc6f5f0c98e25931072006f11e759669f0d5e49e1ebcd4064c789fbb4f2aed1f5a0e01cd8fbe1305922d31f4ea6ad33b02667a922d7cd7f48d0411afae9087771f7cd288e46dd9bbdd652b71223bdbdbbcba133", "48f09777ef84df9441c36301aa10fe7faf833667eed02bb16ea8f41d58d7a0b898677a839f09617cb8a813f89bdca7bd4f85d08a463afa17c810e1fe2d118618873c69d05695492af393f0e3df83b7067fbd5ceee1a6a316deee0d1340758c4a08b3c411d154a1c281affb88a30a3fabecae019256ce0b6ad103867101f2aac1aac91de01c7cf075e4827cac8d1dd9531ea371fb2494", "-103f77a7d0ff918871ed8225c39fa8206bdf773e3e24707259e1d9b0746b6c0c94da55a8668af2f62afb3e21fe3220a3053c03e08e03374aefbf44baca475965c3ea9e6974c8612b919270155dff2c8edd923fbfc3ff08502ac2e71daca71413cb785b9b2b1717abe62e054ab76298e5299e1b1b8be772e429e82cf41430da5aab3408fd7e9a57ebcc21e3a82dfd4eb76dc612dc6c5c7", .Okay}, + {.Sub, "44c835d29f2ee0221c458446c61267dd014aadf471bdba16288fb60af8d8c6c57064074d721edf698d1aad07a6c3bea17c4160c0821c6acc3e9620956de0b8e7b94829196dcea2038d550ce0b5cdda9b8e67a7524459d7be9f4fc9818868e2eebc06b31e8f6f524438f9694df25aacdc0a35b3043f14aae5d6694e08ba24f6e15d0406f2d7b286edf1854c60fb08f8d4a6812eda02df", "bb9ee61ad9dcfd30140b0e80d438f7a9385ff41e70669096e9115ef43c911e0d7757be29b90c999c234b010dd2f695a78eadd4340b412c384403b37c3dec23891868c37d39b5849dcf3206f1d54a05ce126ea749828cbd8fca003de0ad06ecfc75e38bb1ab3826633d7d0a249cab306f179e9ba55ec2c2688efd43b162f75c54c521f36851643d61644cd0cbc289e7eb0b7ec9a4ed0", "390e4770f191104f1b04d35eb8ced8626dc4aeb28ab7510cb9fea01bb50fb4e498ee8b6ad68e15cfcae5fcf6c99455470356837d41685808ba55e55daa01f6af27c19ce19a3349b9b061ec7198793a3ead40bcddac310be5a2afc5a37d98741ef4a87a6374bbcfde052198aba88ff9d518bbc949e9287ebf4d7979cda3f5811c10b1e7bc529c4317db407f543ee05a55f5c9423fb40f", .Okay}, + {.Sub, "-a653f3d70bd0b50b6f663ed0d473cd9b4c4db7b6b1494310a38f5aaab1297fcb152cd91dc9fba4ac785de42e7d50dd5fdf335696a025578a2d1d97336317c442278c8f520cc2a3245aca0ce458f460a2c7edab5395283a4b0a470eebb1a16dd76a5a856fdcc28d3fa1cd06cf33cdb8eec2e89178cc7ca4c4824ab0722ca89ad0f736081ece4a2e51e3d9a625c49e7723ab00cfec3ea2", "175fc6a62f5239055e32cb570b92b84df1a7581b2fb59e0193739cda20554c4d6960dd9b0fef9c413159f0632915f4991433931f36e72876c6568622adb0baa88eb595f886039e1cd038df25dd8c2b471729902c2094b1770a0c3cf0e3d9e2c9506e0008e8819d7aebe57f59bc52f86874613242943ad068674deb9baf19b9b9e1e171b3f5044ec959f44a2e0f5a6f158c541f51ad01", "-bdb3ba7d3b22ee10cd990a27e00685e93df50fd1e0fee1123702f784d17ecc187e8db6b8d9eb40eda9b7d491a666d1f8f366e9b5d70c8000f3741d5610c87eeab642254a92c641412b02ec0a36808be9df173b7fb5bcebc214534bdc957b50a0bac88578c5442aba8db28628f020b1573749c3bb60b7752ce9989c0ddbc2548ad91779d2c34e7d1b3dcdf053d3f8e6393754ef3deba3", .Okay}, + {.Sub, "-5d7bab5e3916e9a193f41eb0d4e4bd9cd50de5596d257670329ee4eb30fb4fa43b5ca1edef1e4823fa22d46852a7e4cc015bfc352e33bc5d5da0c1a472b8bcdfb3127a1d4e83188bacc46b9d11dc777fd36339b4d444a0b344b3007b60458ac527dad5b36e8f44170a69ada5f1e0a5710f439febb9f5f0211f120073f2e369693ed87da7748cafbbae417cb51b7383d340a6bf91aa41", "dff0877ebc262e6d6b2b3dd0ba518246a272ff9ec3306e7063382a9ffea249a6ecc5135980fc756ff51074399a48fb33482fee054d1d2f9f04d96aaaa962e2474edbb32881d58f694510895e44306ae32b68f3b700d4efae23340f6c405e6a2ef081056761b7bca49b0dfab80a2dbc9a8eb50930bf9e6dd5bf017f96bc3986f495b71d271f815bba915e83fbe4e0beabf384efdd82b4", "-13d6c32dcf53d180eff1f5c818f363fe37780e4f83055e4e095d70f8b2f9d994b2821b547701abd93ef3348a1ecf0dfff498bea3a7b50ebfc627a2c4f1c1b9f2701ee2d45d058a7f4f1d4f4fb560ce262fecc2d6bd519906167e70fe7a0a3f4f4185bdb1ad04700bba577a85dfc0e620b9df8a91c79945df6de13800aaf1cf05dd48f9ace940e0b763fa000b10054427f342baf6f2cf5", .Okay}, + {.Sub, "-3b894802b78bce65c246994ff817464ae37a83fbb200ebb6498766f4e547483d4d0892e167541d230c6c41f4efc20f3986abb9f08000469aeeb70006a07e0ec2c55548fa3e9dac38a06ff12fe3f0eca92e17ff8deae366580cae55c3634f62a25ca28053efea28e0baf05463bbb57010a6abbacb02ce4bde8d2f21c402f827c85e90a534f92f2f7731bdb4c427769c614fde4625145d", "cf1391ac35fd20344336fd7aed1727977f4a91bf068c6cdc2330ea03aa011edf55d74c5663dda915bdbe4e2c72163785a5a5fafff8accc734f5bb2da030577fe1d49fbe6f9727c9c4daabfe72ed19c7749eae4031f120a47e6e464f878dd975ece882b2e56517b3a287d0b42be9f520fccddb23aa04720ba6eaefc26bcc4035d215097ead4382f2299a9642deb2c974f06d2b80af2a7", "-10a9cd9aeed88ee9a057d96cae52e6de262c515bab88d58926cb850f88f48671ca2dfdf37cb31c638ca2a902161d846bf2c51b4f078ad130e3e12b2e0a38386c0e29f44e1381028d4ee1ab11712c289207802e39109f5709ff392babbdc2cfa012b2aab82463ba41ae36d5fa67a54c22073896d05a3156c98fbde1deabfbc2b257fe13d1fcd675e99cb6718f212a333b056b0fe300704", .Okay}, + {.Sub, "aef4fd633eaeae20ae20748a136a0ece33b878a60405a436d52df47c2567453e395f6146e952535a74f141cf334054ac3d4dbc5a8b3ed8f1f15d39a2aa6e9c6c0b6ad7de88a7a4bb44edadd1ee7a61040c4fe02b87f175f8b334ee063cc71836010dd656adc814cb08a6b5f461573266e9fb4b369d2820299f3f1a4fe656034f18ca60f1866f721ef28be08e253329040be82fe08725", "12f032c500e1cab5f7dc2ee41f984546e5879bd229e869260b6a2a3170e268cc4a7811f79569bf6f88d0b721ccc51f5f0416fac0ba969a7f802995b38aed4ddb890ad42e6eef6488f9b0b7cff54cd0ec14b7a5001d80b6e14c7960ef058493355a196aa3c0b3ec357002aa7dcb7f6458d9a611b39b22c972173f86d046c564de29d65808d9cd07a6f32475b2fa4cc902ae0c9d0f5e9d", "9c04ca9e3dcce36ab64445a5f3d1c9874e30dcd3da1d3b10c9c3ca4ab484dc71eee74f4f53e893eaec208aad667b354d3936c199d0a83e727133a3ef1f814e90826003b019b840324b3cf601f92d9017f7983b2b6a70bf1766bb8d1737428500a6f46bb2ed14289598a40b7695d7ce0e10553983020556b787ff937f9f909e70eef408e8aca26a77ff676adb2ae660015ddb92d12888", .Okay}, + {.Sub, "-531b9b70d466bd795816c9e902fea79c047448c3459f949078c5842f0aa6c615c743c6f22c071c8feb133086c5240b8a9072586c76e5016bea0ce11bfa664bdf05ee11a1a3f827a857a839e13cb9f8a07af4aa0aa7a3c32a212cf5089692c120d7dc3c2f8b2b6d9cd112108d77b40609200e443ae53d6f13f7ea75776e9be610a354036bfeb4d910baa5774cdc9260486560b6b6b453", "8992169d388b562da51391034721c29b7d0aaa4d70bda61936b261ec502a3fa09fb33f7d164b0dc97ce84a27cb4107cc2aa19487029c64574942c10235e0cc43e22adfe85aa559dd06b5c85013aa3ec5b4259d61cb718733cfd7641a1b89bca38e6674db229a26c519c494e84ea5dcedab22497effd4d22349657c6fac34dc3415903ec0e283408f72c98bfcc2a6b30b9516806de53a", "-dcadb20e0cf213a6fd2a5aec4a206a37817ef310b65d3aa9af77e61b5ad105b666f7066f42522a5967fb7aae90651356bb13ecf3798165c3334fa21e30471822e818f189fe9d81855e5e0231506437662f1a476c73154a5df1045922b21c7dc46642b10aadc59461ead6a575c659e2f6cb308db9e5124137414ff1e71ad0c244b8e4422ce13819a02d6f03499f391353fa773724998d", .Okay}, + {.Sub, "-981ff1794fa33437d46f40876fd0a8e759a0c892186980e5e85faaffd1c2a3dba0cda44cc819425b7752893f935256e437e3d38612e6d556ebdcf7550c6f7203eeed0a2486a19c93c54ca249c6a9879fc7c55fbc36d0f0e553fb0be6baf925d6a77099deec78053358ad25c19ec9642f529f2d678174f518e23e70839f308e7a9c9cceb47fe560885080223d7aab6a914c37e411bcda", "41cd1b8330d720b7a6d575b0bfb5339b5eb00e540fe033f65bceca8435fccff432ddd640aa452a99ba2dc570f8eb030375754db8002f3d14032f7f06d245eb9525c9cad46e1eea1cbda1e65de43c976c4d7766768c57af5eb24658b01d7c1bd1b3e6dc4d2f8667add9342345dc3a7e877a53bddccd6e27d761a12a7e3846703a150b24521747699ce96dd0a0e733e4493ca4ec5e5c6b", "-d9ed0cfc807a54ef7b44b6382f85dc82b850d6e62849b4dc442e758407bf73cfd3ab7a8d725e6cf531804eb08c3d59e7ad59213e1316126aef0c765bdeb55d9914b6d4f8f4c086b082ee88a7aae61f0c153cc632c328a04406416496d87541a85b57762c1bfe6ce131e149077b03e2b6ccf2eb444ee31cf043df9b01d776feb4b1a7f306972cca2539edf2de61df4eda88dcd0701945", .Okay}, + {.Sub, "-71fa04094a3f0d160fb207cdf60e48b2b33e8fff58c7f554bf6337956d97655cb7504f7020929cbc4b6dd1679bc6f94877c1d6cb3758e2d283ce68b4d4c8c3dade60f0cddc6b5a4baf16db1e2003e993408307dbd8d26cf5ac8a6ee1f23da7719502eb926675368914fe9cb652ebf78d2c70e2750153e9cbd160cb948a7ee68d4d79a2f21e05c60e6199b9867b7a601265cc0856a669", "89f1e175dfe782acf5c44bd1fbd0ee307a4d478517ed29bb4fa4334245fc92fe0fd1f7ce8e06ea1f91ba9cadd4a943685bcc86bcdbdf92eb9eaa1881871a9f6e6a01aa64f086f29e97d02e9f9e52acf1a69fbe74b221ff253be4c5dd9d2f88b1c7c3632dd102ebf13561e1bf2c52d44aa8ff6757dba662ef05e8e783937f65680532a7f95bf998ff3039ea5e44a3a84727fc18b74069", "-fbebe57f2a268fc30576539ff1df36e32d8bd78470b51f100f076ad7b393f85ac722473eae9986dbdd286e1570703cb0d38e5d88133875be227881365be3634948629b32ccf24cea46e709bdbe569684e722c6508af46c1ae86f34bf8f6d30235cc64ec03778227a4a607e757f3ecbd7d57049ccdcfa4cbad749b3181dfe4bf552ac4aeb79ff5f0d91d3a3e4c01e08598dc8210de6d2", .Okay}, + {.Sub, "dc5f6775b8adffbebcd2962eeb08caff11481263e823b3f3c32689fe88eef93f9b047eee5e875c07f44f4f5613ad2901c5c09f448197663e7e368b2273042e5c572623f675bfe9a8c47c8c4499b7579f3d1d95a23807ce1c0e4276535472066a0815544c8904d8db321a2243079971306c3032137ea53bbb29d60fe4c209e9603402762f1a8a6ac398079e3c95ac664e1416dfa7afb4", "3dcc9a827aa51b2cf8b685c6e9e567674deebf690c75e79267beccf8edddc880784501c73076dd8f1f96eadaa1a73adad4a99e11e37fd30348af96af9c4b4fcededd6f51fdeb6b3edddd46ebb199469f977079e127cdd1b34e0cb1030022075d50f7aa95de6a94ac22d4373231ebfb6377e5d5f640f208b6d1d8f6b75089d1cb68c114ae13c392b2489cf769d573373d07db3abd2491", "9e92ccf33e08e491c41c106801236397c35952fadbadcc615b67bd059b1130bf22bf7d272e107e78d4b8647b7205ee26f11701329e17933b3586f472d6b8de8d7848b4a477d47e69e69f4558e81e10ffa5ad1bc11039fc68c035c550544fff0cb71da9b6aa9a442f0f45eb10d5ad75ccf44a5c1d3db3330457fd192d71801794cb41618106c6d8114f6aa6d2c0392f110c3ba4ea8b23", .Okay}, + {.Sub, "-5bddb8f1bbd13829b4d8405f0639cb1b25323e53f9d68ba587461bcafb46ab142128e7adb569f7713bec40ce51d271fce4fdb22b94a70bb31b94c79e1959450bea56f441328decd7bc29c39a989d1956a77a998cdda66a445102e19071702407df6716e0bfd3b6ce1d365f214fca4326568f5cd5d9a74d82f90c2cd73356362b5c60475e06f91c0ae25257ddc4e47d7bb284ece247f", "43cbea3ed31b81db8071caddbe6463d8f1e918d063e885586830945b030a681ffeb69a4ccabbb798fb7d0a7f76da0656483137dd165c40fb5e3e12ec61788995b0a6281be6158c439a719488232e8095a9cb5f46b2db914293cd3d220f556d22c0aff9df161dc761b45101b418998cc1da6272c08035c15ee2e2fe2db0a42f8656b5cc2822436a43e6afb43acd0fc8c2eb518a9c9ce8", "-4989c5cdeed8955e1bbf4ee3aec8008aa43c3cb5a385ee12c0a4f617b2bed2d140c928c7a61257100f3bce8c5bf72d76168112ffcfa6b1b68ff75f66430e1de66f4b975ff93e6b11163430c1ccb8522b144308df80b5f7e6d8dd6b3b166c6f633ea66b4d221b02ce962467a62d9630f43fcb688dddd036371273c0fb23d992e90c7bd09e02b2fc0494d4d9b8a95e109aa679d96ac167", .Okay}, + {.Sub, "538d6ba80c020e70cd8580f33af8afd6c3099a44e3342d15b67367c9d7c05b6fcfe843fa7c015e003d14284131f362e98b6a671675b3082532ea4a9968eebd6967510423bd6f2c9c1afbf7abfc12f5e34a3bec6007363e9d8310489aebab2c6da418bc727906e34daa59478b8241bfa70c5aa5f2e2417ffa1cb0a142472fff15a6e91099b1bd686d12720103bd8f6ed1a20c977784fc", "fd8d29234d9d04f4752f5a639ee4a41f326e92e243b65e6a84d1c64406e8279bedd60f164c43fa57b35020471c0440a2167a86f87fac4992d43675cd7c53417d705a65239dbf33ae783bab62cc73ad381f587b15489d8a8c358b06294441607a4e801fd7cbdfeb0c98ddfecd2ea4e19d592f88d797d794acf56d0c4a179c837c7b82d272955d103348f6c4928319d91faec9f7cb0de5", "-a9ffbd7b419af683a7a9d97063ebf4486f64f89d60823154ce5e5e7a2f27cc2c1dedcb1bd0429c57763bf805ea10ddb88b101fe209f9416da14c2b3413648414090960ffe05007125d3fb3b6d060b754d51c8eb541674beeb27abd8e5896340caa67636552d907beee84b741ac6321f64cd4e2e4b59614b2d8bc6b07d06c8466d499c1d8e39fa7c63684c38ec58a6a4e0cbd605388e9", .Okay}, + {.Sub, "f20b467e474b38e8a27ee22a200f4ffbaaf8b89e3a94ebe177ec410f65fe6ba94e5611ee43190808a58142d7dce92b7a4a5163a24f6f00c90d8e48f39a5a557c4027aed95cdd13b07dcbb8488a02dd6ca9558ce084d1fc604603749ce235c6d6a17cbdd1dc29aa38fdd69d1f8645dfbceed8bdcde6c25d40babc0b485de6ebe441c3c4280cc424514ebb70e59d0a3b7c856c82d5814b", "7ca6b8aaa264b49e8f57458f592bf62bf42f28ed3b3c4932808050b97de1390b5f742944092fdcd708e6917386963b7a763e74f167b954520f8a998570ff967ff22361d9e160ead086cd6a7a0eae9f0ea74d0ba4c4e953dd42703e1e571fdee4e3e6b1150850335ae75f44e5861fcd5ffb0ce4f248266d61fdd58239b0cad30a39e3f13f8418c0ce0697d2cf58b0346a4574aaa85e1a", "75648dd3a4e6844a13279c9ac6e359cfb6c98fb0ff58a2aef76bf055e81d329deee1e8aa39e92b319c9ab1645652efffd412eeb0e7b5ac76fe03af6e295abefc4e044cff7b7c28dff6fe4dce7b543e5e0208813bbfe8a8830393367e8b15e7f1bd960cbcd3d976de1677583a0026125cf3cbd8db9e9befdebce6890ead1c18da07dfd2e888ab638348239e16445a07123ff7d82d2331", .Okay}, + {.Sub, "-4917dcf7c52cb06a68078a1b3f7b5490cfa74b15d6b46ab509520ba5443a596b53e0718369a6433c1b184fd823b823c535d7f7931542663ec10a309370cb2961ec693b40354be0b522eb6d1ea4f63995ef7c11cf9bc4f32235c6c9cde7c154f105f9e6594987ecbad1cf65e5cf5f3300683b530cad05f3c87e8ec4710b18aeba5eb9c851f9ce71a32d7329450ae34d731717e08657c1", "d90a9b9c3dc5b65dae2fa3d5c46c07a3a2cbdf2e51b68d27822bcefc2051d0b4e1e3b74d0be556524641fc0cea1a6accfdbc0d7bb354ae090829b60391d7f5f706f92506b81f26a490b9b107e7edb1a57ba552cfd254f9c0c09e0b01919dae65953c656d5b0100404d2e4fa96454444978ef0b2d8cc2d060ae9b9aa79534b13397b7e73504a680755d7b5fa69ca54b0c80326118d099", "-12222789402f266c816372df103e75c3472732a44286af7dc8b7ddaa1648c2a2035c428d0758b998e615a4be50dd28e923394050ec8971447c933e69702a31f58f3626046ed6b0759b3a51e268ce3eb3b6b21649f6e19ece2f664d4cf795f03569b364bc6a488ecfb1efdb58f33b37749e12a5e3a39c8c4292d2a5f18a04d5fedf671af86fe74f2188aee88eba788987f974a419f285a", .Okay}, + {.Sub, "be6f45343f010c9a3c679eeddfbbbd2ace092889a8673f03b3adbf64044fbbdf4f690898b322e3b3e1b47f0807c28c5036f423a5e0ca111f5d7d92659c741af694f4793374beaf4fe487823fbd14064a15cef2f191a747406a7706555b2d9321411d52c603c25ae01946037323e28afc8ca07e9e3306fdd95d6fab0088a15fa7c736f2df3c2aa35ece51d4d63253a4d1a194ea0d32e3", "abe9d611f8791741e45a62f4234d54c065a1025da370d655af16e53ffaad12d95a698c62bb8b6f1fe8c5a37a93629141295e16d31d59eaef9eaa79517751b80e128caf9acba36eacff947994db509bcaf14d89eb5fe24d4a9826f39a60d9705e5ce3aecc0a858f44b9848b3f973cc846b12258d9942e66371bba0cf2950bc53c7f8c606d4b329aef6884de7bdbd4470ea4c6e42283f9", "12856f224687f558580d3bf9bc6e686a6868262c04f668ae0496da2409a2a905f4ff7c35f7977493f8eedb8d745ffb0f0d960cd2c370262fbed31914252262e88267c998a91b40a2e4f308aae1c36a7f2481690631c4f9f5d25012bafa5422c2e439a3f9f93ccb9b5fc178338ca5c2b5db7e25c49ed897a241b59e0df3959a6b47aa9271f0f8086f65ccf65a567f5dc2fcce05eaaeea", .Okay}, + {.Sub, "-d43e1bee188939668bb23ebf0827252e8291538277249343bf8ea607c1143709f0253c3cd6418cda24f0227647a4ce428518d87c816a5b23c8e317cfa458034b5e441cdf190f9c51953ae66f4f3ba64efe3cf9baa8a6ca0341ea205f58c933cc879451fd737cdf952cd9ee3b36d7f1659e739715240e89487d8ceae0f1c47e6f441aba8cd35a644e0baf66fba7552dd2e2518ae3eee3", "40488723b6e92aa00c1a4f9e66b1dbd39831ad9b17a01d15e7b4400cf330c28ad616fc8e28dd4684fae1a005fc14d49dae119b8071f232704a3b653e0dac6d3e1190756d1853207c5fc7ec399bac06abe847bc58ab5b8511097d1de208e8d12fdb1fa4767b21a169930888c069e0bbec1e36c60bbac1dec7fbbf58385825705bd4921c6ba1c24f98cbc6ad0ce7188bd1a57850451f25", "-11486a311cf72640697cc8e5d6ed901021ac3011d8ec4b059a742e614b444f994c63c38caff1ed35f1fd1c27c43b9a2e0332a73fcf35c8d94131e7d0db20470896fd4924c3162bccdf502d2a8eae7acfae684b61354024f144b673e4161b204fc62b3f673ee9e80febfe276fba0b8ad51bcaa5d20ded06810794c431949e9eecb18acd6f8751cb3e6d77614088e6db9a487c9db290e08", .Okay}, + {.Sub, "-341727b90dd65e137419d7bfc4539b65071a028e50321d6385ea7f2de9c0f71693b17ae8a683de51d5c2b27f33142cfd451a3db62909e72a1a1ffd600fbbb4146239a80925bebe41555fc71672f349974e3ddd3bc9e38142a6a8eb58305a1c957e80606ba9a411b947ee659a83b534cbe77f7a18ad30b1babbc466a07404d8db060676db3adb936e37abdba88100be846c062bd206d", "40dd68ce2e9c812d1f0b31fe92c611019956c7355453bfde6de9cf0d0e1d18beed21877ba7dbaff7f6b0384ef8bfe68a9ae211c5792944c26ea37f4a886c2f99f691e011029fb0a811b781f1f17da4a49547965c9ffe66196ec2847cccf2a84499d679e1ce027abd99b4ac0eba13354469d7f789b030870cf3fa51e6a84c11f8cb2641821e869883951fe8d945f1c9f589d2b7d99c98", "-441edb49bf79e70e564ccf7a8f0b4ab7e9c8675e3956e1b4a64876ffecb92830565c9f2a3243eddd140c6376ebf1295a6f33b5a0dbb9e33510457f208967eadb3cb57a9194fb9c8c270d7e6358acd93e0a2b74305c9c9e2d992d13324ff84a0df1be7fe8889cbbd92e339268624e8891284fef2b3b0392289fb69850af8c5f867b86a8efd23451ba789aa693ce01d5ddd0931a96bd05", .Okay}, + {.Sub, "289c5af9776135933591dd5adb5d7905da6a2f0542827c0b1735be52bf7243189b6649f3d2a26d00b80f75b1522d772cc87ddda59682d18791015546edb4d202b8ba368e044ae8a6a40764df9e670d7fb065013ddbeaa75df950afd356e748dad39fede3333f08274eee3b66c1c20e5067783bc4dc9008baace9a510315304867dad7d2f891bdf8627e886795f185f55a9433426e76e", "609fb91ac674537d7d30159f5012c28a3b3a9bb33443d568fbd39494b385729fcb4676f6711422ed82e1b1594c30217362c815c3f62783e89b4b5c9cc71a808223fc0538d7ea6fe434efcab2b504ae8b64d3fdfbf7ee2c7a225f4a35f488699925125ef409843b01130035f132e269f9ef32db726360e24529735281c1aa7fdf0f056313daf4c8039503c2c31f89ecb3cdaa2b1a216", "22925f67caf9f05b5dbedc00e65c4cdd36b6854a0f3e3eb4877885097439ebee9eb1e2846b912ad1dfe15a9bbd6a751592515c4957205949074c9f7d214329fa967a763a76cc41a860b868347316c296fa17c15e1c6bc496572abb2ff79ec241414ec7f3f2a6c4773dbe3807ae93e7b0c8850e0db659fa965a526fe815385c888cbd26fe4b6c9305ee984a4d2d1fc08a6c6891754558", .Okay}, + {.Sub, "94c945ad02e3a770f61aeb1771e2bcd1ea517b2b8ef93ce0f0e921bd773a2433c817e1db8f4a8b2e9d1bf2fbd05b842146603bd7e808f0c2e0f4dee74a934fa497de1e9e0fa37421bb7ae44802e2506b1c459d5d0ee2d6737ee63e3c9991dc7f3a7f385ebe452c9839eb069b91a5fa7623dbc9f83cc0b7d328604ad2b857e93877269bca8a3790f3247451d5f49185a29d3586a02bce", "fcd5a95ea22f7a1640729e02d3b7d0327ab32b196e84b8133403294644eade503c77a85b417b3e91180cc2a430316cfe3db4661eddb3632527d05fe49497df0c6e5122d6340e206c2ed105a0dd63af52b9fa26ee446deb4e459e9cade03b9b448f2f4e2fe4ef3c799ba8ec956763813f5c32f964deb8bc457d11ee93f499eed39f37dbbacea3f0a8263df055c4f85c94e8c7e2e5cb74", "-680c63b19f4bd2a54a57b2eb61d513609061afeddf8b7b32431a0788cdb0ba1c745fc67fb230b3627af0cfa85fd5e8dcf7542a46f5aa726246db80fd4a048f67d6730438246aac4a73562158da815ee79db48991358b14dac6b85e7146a9bec554b015d126aa0fe161bde5f9d5bd86c938572f6ca1f8047254b1a3c13c42059b28113ff0446c5fb501c99e7fd066d6f24b925c459fa6", .Okay}, + {.Sub, "-1a4f39ecc7024e4c9fec68c628d0bc9edbf348de82cbba2ebf629e3a13e6c4305ccad90608192d2f0771d07d4144aaef2d76d39fc764a6949d6bd5b06aef4f516d88a27b64f2022801fd14deb1caa6d2df04eb37120b326a117142f0d1ed63d0e72968068330f016c10961e2f3e80d3cc6d1509e584169ab86b95cb510e56439d542cec2c3e90512f3b459d80ce5a6fea58056085c18", "e17a3704c63a82e6c35e0e2e1a3a6713dadfcb9a3e17f3a0919ef69dc4672ba776c240a7701ff3261265ead4c0038ff69f10da1cc957cf74b33a59af484456a592dc292963373699516cb93d293c4c5b54c9cd3f75f8c85dc6075eb51fcbcb945592623cff5de4571288ee3b5f9dc9baf50389390684511d6f5471dddcf164893a56d22a0ce1376ae2f18ad53104ade44c29529ea38b", "-fbc970f18d3cd133634a76f4430b23b2b6d31478c0e3adcf510194d7d84defd7d38d19ad7839205519d7bb5201483ae5cc87adbc90bc760950a62f5fb333a5f70064cba4c82938c15369ce1bdb06f32e33ceb8768803fac7d778a1a5f1b92f653cbbca43828ed46dd392501e5385d6f7bbd4d9d75ec5bac8f60dce92edd6c8c30f99a0ecd0ca3c7dd6a5e4ad3dea54e2f1a9a8a6ffa3", .Okay}, + {.Sub, "bbe35b87c5cd81a4f6fcef911f3558d29dec06dad4e5402e8140d1aecdebde13fbb629c5313acd68e53ea2801f7dfbd5d64d77bd8b6450ebb499e88fa944ef216cd0b2aa60af8aa13a6fbc81190b413cc24d866c8a6ffbeacaa0c28fe3f7ed58f9b9b4d7527ee1b456b051968ae9501839eadac55c4a8279489de8b755730f7705aae4aa75bde25edc5de834819e373b29a167d9622", "71a7c184d5f7a83f4bae70f6bff261b7f8fe536b03449344f0e6da71a6addd9c2a0d863a17c2dc7f98ed1abd4a0df436b49517f260f1d94186bf9af4f6445be6d7cac4d38cbe5c47786f809d02c4c77d1c9cdfa92c84d228209d5c1ee13c5ff9c31349f5e860ec969cd879685f15dc6a241a9eb3f3f5a9c04cdf27fba56f311d3e932f7732129a4630c143e71cf42940d1c5e7c0e17d", "-65e98bcc599ad024fc3ea1fdadff0c2acf1f92fd55f63f4208d2cd56b9cf1fbaea52239dc4af2fa90a9930954816147957304076883b9432cb75fc6bfbb00cf4c0fdb9a8e6b3639d64c884d4f13413695078074263ddd26973f34ff5e2fce1243377aea87338fe7b576d744ef6674768a07bf1079e310198b855497030180025ce38812c8ab6bc2042fb6563d4da45cd1f2bd1434b5b", .Okay}, + {.Sub, "-c493bb16fcfc3113aadf8d32a7494f3b70d820dbffcbd90247c923835aa19b7f75934a88c012679e5a737828586876228cc96fc6b9a2c302c77c101e2f849ca191f38624607cb59a0fb904f6415e9681abcc06cfa7f030f0ac0d40507a7c34dce5faee61f81d0d2feff585c54a5e4006bcb57253d3e9f26b9c3c681065648bb5f2b252ce906c59c9550c4a6409ae1b71897d5a669687", "a184080e79ba79fad73d7bab56272d3f37ef6a710c15f9ac178292c09321c4fdc31806331fc595b4e822679e64c1d486ca6646b5c303bb3776552593c34e37a65df236a1ce5e2e74028e9265ed6e6a9f93e1d98ff3041ad358c2a6a5a2a6c3dcf323a2c0efa5b3cb282eec98facc5c4c124cc31fa56ad18bf356a4873cb31e7a5ca7191a1cdf2d5ca2a81754b74dd45020ebf00a23f0", "-16617c32576b6ab0e821d08ddfd707c7aa8c78b4d0be1d2ae5f4bb643edc3607d38ab50bbdfd7fd534295dfc6bd2a4aa9572fb67c7ca67e3a3dd135b1f2d2d447efe5bcc62edae40e1247975c2ecd01213fade05f9af44bc404cfe6f61d22f8b9d91e9122e7c2c0fb1824725e452a9c52cf0235737954c3f78f930c97a217aa304f596be8ad4b8725f7b461b8c0fbefc1aa694a70ba77", .Okay}, + {.Sub, "-f42076fe0d01a39e7e3b76812e9b5cfaca2c1ecc837757ed516797b16b6e5e15f11fc7e5afb3165a015e142b38be4510cdee746afd6ba57889a8fb133cc3016e30f4a1ee0bb685fe0e900e46eb98d473384a9c31dbf44c5658686108e359bd489e4d6c0956190c0d7e1b13ca789dfa13bdecd3f8a1e823480da3d43f0ae39333f6aa153d875fe995c74bfc778b379520f3fcd4c70128", "259c23997f38313caa42eef25dff94dcfb6033571baf31eedcd5a6478bb3eb503f546db052350d70fe7a6f78181625fb91067940e058cae52aa87fb017e9e51180212e68f57676a125466847e9bc957cda01fabaa64b087f3cae4c3ac24551d6003494e0fde80210eaaf02d37737c24718c95be37210a45f7edf8871754859b980258580b23ca87db2d43275f7271346344ad30e574c", "-119bc9a978c39d4db287e65738c9af1d7c58c52239f2689dc2e3d3df8f72249663074359601e823caffd883a350d46b0c5ef4edabddc4705db4517ac354ace67fb115d057012cfc9f33d6768ed55569f0124c96ec823f54d59516ad43a59f0f1e9e8200ea54010e1e68ca169defd5bc5ad6b62fdc13f8c7a78c835cb0802beced76cf9abe399c92137a202eed825ea8672847a7d55874", .Okay}, + {.Sub, "b251cdd5b99ba223e3df60e1eff6e8ddadfc24c3f1bd17923a9ac7af8751abc33aace8fe7fb157116121772c62db4630159f4a45ea76ad7c33e0a31b5cafbe826d80282299886f92f6f404cd361589aadde8f288206b87c867edd46d5ea82d32de1e507524e75a71b3ae451d7af3069181318ecc643008299bc47f4872d564cb15f1aade697d0c2dfbba2729cec8d4a456c769f85d9", "10e48db686d83d7664b6af1236c5a890dbc478b7bfc21423fa4733f3bb622ebf9bb1807a30592644ad6e23b004f9cf7aff198554daea34b852f52d0511807cbb87480e3c3dc808efa54b3dc36c012878abbaa24aad0a5068deca994cf0066c07ea7b531374a3620857675d7d53a6db06dfb848fc6e7b9b6a83c7d8a580a5868eec4c483aea1b4653f8cf8185402b815c76b8e82eca54", "-5bf70d92b3e83542678b90417c63a0300e4b66b80a642aad69d8778c2ed14036806b1ea485e10d3975c0c3d3ecc1b17fdbf90b07c42c9e08fb722d35bb580d360700bba142f81f675dbfd76989fcfddfddc13222b0397ec584bbc061a1be934bc996e0c2254ec613c2c792b7bf7aa9dc7a5300fa8389ae7ea0b90b0f97830423aed2d8d038375911913df12a33ef412314c718f447b", .Okay}, + {.Sub, "-e98b3b6c91fe9af1e1ba605b3262fd76a712b2967cf2b72a8f2e2c8ecc94511b652aaf4c5e844ef67e6a67ab74b7720e89c19fbee2a75e021b980b27fb5ae2db47b33682554fe9065a691b900630dcc047793edce325c29a98db0b805f7cd94e7cd2e7bdf88a444213466070491efd67477caae974f2cf6d72be207eee1b816d9d7e8ef192ca4d9e9fef7db92c57c68bf66afc962f04", "662362c9856d844ee25e3efddcdd7cbd9908508390bf2b7d4f8c56bda8b2cfbf0d0157dd824a4fa202cc2b52b53ba12e2b3ca06680ad75265dabc7a599d96bf9ba6ca772f4cefcaced07a431c3cc09c6610928491793ba380b62994e1842174b07564d9d5b216ba0c393412e5b358258f05c6d920dcb3dce398ac266ff086e96b69c8dff97eb8951e2b19269194cbf4030ae7cf44b35", "-14fae9e36176c1f40c4189f590f407a34401b031a0db1e2a7deba834c754720da722c0729e0ce9e98813692fe29f3133cb4fe40256354d3287943d2cd95344ed5021fddf54a1ee5b34770bfc1c9fce686a8826725fab97cd2a43da4ce77bef0998429355b53abafe2d6d9a19ea4547fc037d9187b82be0d3bac48e2e5ed23f004541b1cf12ab5d6f082a1102245a485cc2719798a7a39", .Okay}, + {.Sub, "-4b3914a3467f48f2bc3ef8301da96bddf8d3e5bc0e1e40cc52dfafb1181d9a900367cb4cede6244e58859d363aef67a675a393d16a86c0ca8436a085716537dbe73f1be0ca0aa263415b683ccccd8523aaa91849a234a9914d21ec088606cf482487a833cd13d1459ceb0faf02edf894664d0f82ae347490ba55b37abaff3a813a68db55301667ab0d6e66ac3802314c261f0da53f99", "158bc0e8ad71a7badd87c4718cab8376d5e7f09f487e3a7367c7d98a686da7ea37d7cb181471c357d15ef15c540a020be201f4e2d9d7a8c34d237988e7e2fc5dbbb2b2254fa1f77da78a3df7313d5806f9311841883424640eff0521206c1fd612927ae69b73a66053fae3b0287baa226f873486173dcead846bcf022f8ed9f653638b61508c1d486e1647b13c7a82d4466b16f7ca89", "-60c4d58bf3f0f0ad99c6bca1aa54ef54cebbd65b569c7b3fbaa7893b808b427a3b3f96650257e7a629e48e928ef969b257a588b4445e698dd15a1a0e59483439a2f1ce0619ac99e0e8e5a633fe0add2aa3da308b2a68cdf55c20f129a672ef1e371a231a688777a5f0e5f35f2b69a2b6d5d44408c572433e3ec1827cea8e14778dcc66b680a284f37b84ae5d747cb4206c8a249d0a22", .Okay}, + {.Sub, "7559a2b9b2a2e3cf75b32871a62a750ae49adcae99d7b5604012c3a8a8523249d6c1776403ca628881b7f316ab6366f07ba8e77101c4698f8ef770aeef64d65417249a8516f6e88f3fef85a078a0da9f1f28d94e724c602c1b0e65d893f5f13cdf39d6801f546fb25b0e1467f2edec2574064a2382ae4a7cfa6a689c4b7505f7ed00e3437752e40d1f7c7e36a907a2dcb17916c59bed", "e7f3e84add00c449bda4a8b8916ec2a17717c5125e8fc5342029557fa48400a6f67301f1650537e788cc5e3243a336f4996373114b47b1b5170c56de5ff123e827bb632a84a7816a8f90244c0c283a0528c85f08f4e340907f6fb73c47de54124eef31c1629cae82bba942875f53e84ab225e0dabf9b084aaba3d889ae513a66ef3a92fa92f30c0d9c276a8d1c14a1a817b1f9950b99", "-729a45912a5de07a47f18046eb444d96927ce863c4b80fd3e01691d6fc31ce5d1fb18a8d613ad55f07146b1b983fd0041dba8ba0498348258814e62f708c4d941096c8a56db098db4fa09eab93875f66099f85ba8296e06464615163b3e862d56fb55b4143483ed0609b2e1f6c65fc253e1f96b73cecbdcdb1396fed62dc346f0239afb71ba028007caaec56730cfecb6638e2cf6fac", .Okay}, + {.Sub, "-2e6c95f78518e9c755b845e6e41563ed78105eeb1f636774d0feda7b03e75bbfe1b28c717a24b7f0221f5a12ef7d5bfec7e19c69831583ba8f0e7abbeb68f76acd136aa3fec7b9d9c063a80dedcdb6ad0a568c4e8a3467f7e5f52e2c9f30a3d378d70f8cbc1ebd4a2809a9fa7dca94fdfc0e3a916d0d58d00719c81975c85fcba411f2c35ea7bf46e6adf293fbf58fd7d322c142d82b", "7c6a9a0250a81ee2c53b78d554ce30719181771d1f0754df94201134f05cde659599daaa875e4a0156777e35f78cce2f2b7add097bcc4c6f950a68bb2c218924646a7d482274f97ca4e14b4967fa3c8d48af3d7b9111e24c289b1df8976971e2a6ff35bc956e2a06bafdacf99191291a2dae45b7ddd5c54fc9a933793a29bbf5e51072856fd63a6f72b7c0ae6f5f45a93bd45f6ed36b", "-aad72ff9d5c108aa1af3bebc38e3945f0991d6083e6abc54651eebaff4443a25774c671c018301f17896d848e70a2a2df35c7972fee1d02a2418e377178a808f317de7ec213cb3566544f35755c7f33a5305c9ca1b464a440e904c25369a15b61fd64549518ce750e30756f40f5bbe1829bc80494ae31e1fd0c2fb92aff21bc189226548ce7df9b65965b3426b54d5810ef720b1ab96", .Okay}, + {.Sub, "-8b7b7233ca1967b8938201a00fb756f425b17d05c75fafe5eda031c67bed76ddc6cfd2ab63b5ce7b0a4c384e118dffcd6b7cc79ab81d7b49b84a2766744ca91efc092d9fc172a3c933d7d9fff411b8d9d7da174a7010ceb365c67cb03249d96f4e4779b783d9d0484d2bf563a561d0c28f76c626eb30c6359ca1eacaa3ea04a10e3cf4ffb1caf7a287855d5bb868960448d2d4ab2f4f", "d435648ff58e26d33390c65ca41bb8ecc59fd8cbff311cd58021296c7c5312479866473d3c175a7a86d381457b3c52687c29e1fb08e8c3fa5abde15076be79f7d99a6cd6b182de8ff7517a90eda918cce605b463ce9c19d7cb6582d4ddd01da6903056304220d21ed3e8a12ce465b9e1afac42b53a66306f0ed189170f7532554c55cc30bb3f54582661df9501d074a388f9f3357e4e", "-15fb0d6c3bfa78e8bc712c7fcb3d30fe0eb5155d1c690ccbb6dc15b32f84089255f3619e89fcd28f5911fb9938cca5235e7a6a995c1063f44130808b6eb0b2316d5a39a7672f582592b295490e1bad1a6bddfcbae3eace88b312bff851019f715de77cfe7c5faa2672114969089c78aa43f2308dc2596f6a4ab7373e1b35f36f65a92c1306d0a4bfaade73cf0ba390aa7d1ccc7e0ad9d", .Okay}, + {.Sub, "-76420af5b40797a747964ae2ef76aeeaefbcfe0c21ca8d67fde4fd38a08c2da17806174a64a462e11ab38097d9dbe855fb5d7a9acb7fef0b4b11dfae7128d2823511ece72afd73fd015ef9c9b050ab07fcaa3446f7849578dc9cf7f34ed6c0951cfb139c7c6aa338b8ce1ab08c45631e063372708f35c38de64f6ff31ea6da49ad142a425b9505885d8dbed966cf3dc6f3c07a9c704", "35b8e99824095188dbd1081677a19bd1fba3fc6aef8838239fe7e9267fa536326b5187e2ce054c026969841d79f578dd9f251063baa7bca7d2ae75bb7a49a75b2832d902bf49f5e4f0f6e86f8ec3641ebad4460f59b670673d5f6711667ea7466985b6e3cf7887771e22f6ff45d9929a6070da290e455886d16f8cf6c8e16b7cff13a447d809127482e94c43395d71089e3f11daea32", "-3d1d0a477f49cb03504a6cc4a69906c0aa9fcc4bb1a4e0fa1fc638fa09adf90c82d1e957744f92307b14bc26f7933762fedae80d675fbb98875f93b6615c34834b83f7d131f9cd24c10cd80c29c86ecf3a9ee953c92eb9becb2936909b6c134fbb55681d973f31aaa9afd8aa4e9de8cc40d411501738b4bfafd483f5facbd92199e4e6ebfdc262cd08c22830cfca64e50d7b1984b136", .Okay}, + {.Sub, "8fd68a7af4a3019fdfc37ab5850ec0e0f89b0d977614200b7dabf52125b690c2a4006af162f981cb0aa48fabdfb8548eaebfe7767c8ecd9b0e3563a6e64dd36103c03dbccf55afe7b32d7475481aa760b0abc6c39b8f223c31ecb63186c15fd93a4af088447917739071bcdb39a55c83625f227fdbfe137c0892e4de2e150a630c09640068bd60ae26e2fde2c7e28131226dc17dfb9", "2ce3737f5b8a491baa0990908c969157ee36b5a910917fdf012f00fa5af9dce3f732b5dc2de9fb8d327879cc21dd903fd492ed30ef91028c5e6d215734145fec4f18dbba1b61d7ebdc519175fe669da9fb50d6143405cc5de9a031722b24481673ca29473a164416559b76f003f98d0c22fdc6c00c25d478fbe125b2de0752d18340939c1ac56aabf115c029693860f344c9210c90fc", "-23e60ad7ac401901ac0d58e53445a549dead04cf99303dde495441a8489e73d7ccf2af2d17ba637081ce30d163e20af6e9a6eeb987c815b2ad89cb1cc5af82b63edcd7de4e6c7ced611eba2ea9e4f333f04619a7fa4cda3a2681660f12b83218e0257a3eb5ceb29f1c945b22505f3743ecd7d4980e65f3413b57f764fb26022b527ffd5c143994a10ea7904b3cba38e032a244f4b143", .Okay}, + {.Sub, "3528065a240495671812be950bff304c014a8f7c32f03b229148ec8b9aa1f764fe41b77cc9a8d854e09954c39552dd0545512160f28eb6311f20e39cc0ebbb94a9b777fb292b212e45eae514f5d73eb704f9e2a06ce24911fe298141bf9381864e79618ae9da05fa45ef79e629da413eecd25faaf16970eaafbabb01eac5ffa2e9d200bce1aac75088b1657b1fde63372f1128958506", "6cdec2d3baccb013558e5564dd6c99e159e96b10b3f927c3f63ce0556f0a3d0df4382f6bfb32614a024b7458385d5adae88f28c3200f8bc3528d71912f3c8eb6033f02181e90c496f5e62b49d9aa14e7f712c0f54a8ae626bf7c2aef105ef56b35d0bc242fbd2238446b2248deab72d1adca32539dfc58abee61914b5bb81dab44fe4fdfb554e9f136352c857dc9e57f61153f914d9a", "-37b6bc7996c81aac3d7b96cfd16d6995589edb948108eca164f3f3c9d46845a8f5f677ef318988f521b21f94a30a7dd5a33e07622d80d592336c8df46e50d32159878a1cf565a368affb4634e3d2d630f218de54dda89d14c152a9ad50cb73e4e7575a9945e31c3dfe7ba862b4d13192c0f7d2a8ac92e7c13ea6d64970f21e085b2c4f22d3aa22a0ad83c70a5deb8248320416fbc894", .Okay}, + {.Sub, "6e58eb2f7480dce811af72eb71dd10cb491506228ab9fbce30119b04b230c9a661096479664c23d5c8c0a07b668805c33ec7445dc069872528187dc136f67c201a2ac047a118e68137ed0f32829118a039ab825f56493e047a4397dc2b6c6eb1a92800f7e2b201779f2302da7a899be24ed0a56a065a52a3a3196ed8432387df67ff3f586f32f667b1622b7054ce27328f05810ea1ad", "645820c387e9f4961d63e78fce313a1141c0d6020f20464bf89a38b78598666dbb0f903346ff17363783fc506d6445dea84aefc6f73c7c337f9ab37b71be925647a19d2ffb2714ad987637223db74a34d3866a43b5b9f3ae91e4d07d4a8c9164243d3d0594ca573e58a97a24b8bda4cf07aed4e05b370431d195b5b3b43966a48a3072541fcbdb26b55b7f923fc23d8b0bb023d4cceb", "a00ca6bec96e851f44b8b5ba3abd6ba075430207b99b5823777624d2c986338a5f9d4461f4d0c9f913ca42af923bfe4967c5496c92d0af1a87dca45c537e9c9d2892317a5f1d1d39f76d81044d9ce6b6625181ba08f4a55e85ec75ee0dfdd4d84eac3f24de7aa39467988b5c1cbf7134721d089ab234e71d183b9248eea213addcecd044f671b40fc06abde150be9a783555d39d4c2", .Okay}, + {.Sub, "26749906f4306325de45d63b6def89cd9f7eb2717c7dbe285bdacd5973702baccc92d71a813548cf5dc5f9cd3e42fe344dc4fda371fce720cecea071fd43c453d1d6f231fdeea079c23dbc14ef3c49a4fdee718c2ecfe4e22a59b668a6b64ed61a8aae056e7e6f34e3b375386ac49519230949618c550410ba906509ffadc64215b936862ba5052f44dde9caa6f1cb32de1ae9d90036", "78d54d5105d7b8ca5433c2de9ae39e6bd0edf404a07d030e4d4f037a6c2ac64171a17bfada3e35f8170808f1749bf65c68911d3c4e5e04b2da264e5e273eb1f4a23f2eb32344b7e275de9b2a0744191ed75f418d516fe69eaacdac91f628779d2ea6bf882b33ddd6702510607589dec5bb8b459359a81239adf76187e6b843b07f9c4a228018b1cf6faedf7765088842495a4acfc858", "-5260b44a11a755a475edeca32cf4149e316f419323ff44e5f1743620f8ba9a94a50ea4e05908ed28b9420f243658f8281acc1f98dc611d920b57adec29faeda0d0683c8125561768b3a0df151807cf79d970d00122a001bc8073f6294f7228c7141c1182bcb56ea18c719b280ac549ac9881fc31cd530e28f366fc7de70a7d6e69e3139c5473aca02ad0f5acbe16bd0f6b3f60f6c822", .Okay}, + {.Sub, "9a1a57f8120924f2806ada27acb696a3d77e3c9fbe1709defd812090126a7938e4259e1d9da6e314cb12d2462177f28e94f331907f297678195033e60712ea5e5ac1f3c06ac2915a42741da3a267b8b6c1e1b83db2a5f0dc57dbf1945523fd69ac058b0e85a330f041ffe6ff0739f60cb861eb51a29b4f159a61ffc3c00709eab505fe7f51fbfbc1c3d6c8f5f151a44d842588d206ef", "9dbc18c2bcf848f7880db048bb791273fac685438e596800012dcecafb0497fde9376bac4f18fc6d6fc04ac09a3867f87636e8d697bdf7acab4734eef5fff4449b328ec0bd76ca6b7fcf59f9a9ed7fabefaa2c0d4584431e186e1df5b15ff159c601328bcdf4489962be3e344b6343b3f2e991de15c65c577108b2523347d9677de27b2dd95c39cf677db350772cf0fc3c75e1af3be5", "-3a1c0caaaef240507a2d6210ec27bd0234848a3d0425e2103acae3ae89a1ec50511cd8eb1721958a4ad787a78c07569e143b7461894813491f70108eeed09e640709b0052b439113d5b3c560785c6f52dc873cf92de5241c0922c615c3bf3f019fba77d485117a920be573544294da73a87a68c732b0d41d6a6b28e7340cf7cc8dc7cae87603e0da3a6ea5a85db4caeb85058dd34f6", .Okay}, + {.Sub, "-fc4fa78b992cd2b3e0afc9c5062999e15420063fab875b30f76bbb7c9c945349ac4484e1ee391ed14b45df61369366f21a45fd93ad35eda851fafa5a96018420cbf549dbf583b9c6ed415e101a2336974ab4833e9d80bec3524013dfb5ca5f56a147eeba784306588279b30fcffef8215abe63563634986f6c5b0d49abce614a340028ebfcd57677fea9b61cd8b2be0e3568556df64f", "a6d8fbbf17c942d2e009c2825289ec282cf6da2d34d6781f018a554d6cacc21c4886640606c6dc1079fb576209b8590e486c688455ef05d585a9fd513fa1e9b24b1e20f1c131783d6702aa935746a1f62b99080fd2d7208cbbf3bb9f0b6579cac5e4364f1d271b1fade9776be31c172444ee7ed70217a4f9457a3d3c002232797fab599650ceb041d99d80e5d39076b0c976380f15c", "-106bd37478aa966e10eb065ed2b5238a3d6ef73e27ed4c2b2e78460d1735f1f6b70cceb224ea58c9252e594d7572eec82feccc41bf294de05aa559a2fa9fba2bbf0a72beb1196d14ac3b188b94f97a0b6ad6e13bf9aae30cc1dff4f99a680b6f34da6321f6a15780a7d584a868e30b9939f0d4b43a65612bf00b2b11d6bd08471cbfade8561e2617c1c438e2b35ebc57941ffb8eee7ab", .Okay}, + {.Sub, "382d0a0dbf5e21aaccb9bab50fe300f86dd6ee85e888a275502276d3a1fbfdd10e037bc874ed2be54a15e948893de0e7e9d1674b2b53706f3b6735c7fdca9f099927d1dce120550bfc8e262a8517534842f8eea053424feaa2fca7b93ee5f76d1e55d7cee871370e502606c25a6852af5f88aecebbf5f68b262996c82de861c1b32d9879741814e2b9f610d30b1819dd7193807c0838", "a04ef06e3011e04ba2c76b05da7ad1c0663d4e049e6a82ee7b2e15ab56750599ac5b17844beb3319ef3d7a06b617f92393866fd745c7b48f89f06064764997010dc32e4230730869ab9295a4afa00f42a4cb47f78d30bd419ceaabdc31a480fc3e8ee44c5f96d4793403889f4c3bb5296671f066e2733948cd93dd13838670e72377f02d2fe9e61abafe67aa1661029e3022190645b5", "-6821e66070b3bea0d60db050ca97d0c7f8665f7eb5e1e0792b0b9ed7b47907c89e579bbbd6fe0734a52790be2cda183ba9b5088c1a7444204e892a9c787ef7f7749b5c654f52b35daf046f7a2a88bbfa61d2595739ee6d56f9ee0422f2be898f20390c7d77259d6ae3dd81dcf1d3627a06e94198267d42bda76a464b559e0f25704a57b3bbd1d138010856d70b48e8c0be8e988a3d7d", .Okay}, + {.Sub, "-d623564c831b411fcad4077315d0db1462c0534802983add2440025a98353c012702267c54783d79cc22ff229f1d82ceca5651cc232b6d64a5264ba56ae45f21fa28aa7e2bde531941a34310527954400af484ce11c6fe246a750248a6bf204fb2b9d9c9aee7d2352a32289a7f2bc743c5d54005ba9613e40b4b2c3105913c29b03984486727dd26b4c7c1e7779a01685027b4c1119", "475428c868a4b9e0aa13dbcb451e6da057c203b0b2c025ddfdd40a7314d9f5064a939dc7cccbd26479cc12ec99cd087607600572a5df27c83e624c0cba4e3e5a8df4b33a44a529e049736d0b77a5b4b3b9a1c5d27ef3754011d057f219ba7da0d961cab60b6fb473d7bc3a9530431f6add62577c33834dc885363cf3ac7b46a4c58392a118fa6f11414e64cbb3c9a74bc4e61a67fff8", "-54b65e2d30d66df2a6c11c42767b7b519dee08e532e9a98bd0180a98be5d48c65d03c02f9213563c168e42dec3bee0a2f4056a8f6811de9e88b4b0c710fc844cad973de227630f11dd8da13c7ccd49f7ba510e1f600fe5225877a816a4266fa5d48d6852a65e31972a5f5d1ed835dbdf19bfab7c8f2caf06c5eaefb6bcd45a6760872ae59f6cece3ac9ae0ea2b43476249e895b41111", .Okay}, + {.Sub, "bcf0687e22f4d1f21756f3878179968188ff520f8d3bf15e40cd47efe9ffe57e7ecdb1859696dace056d24286d7211af595e171d0740c5420a342823eede71ba8c488e9bcd9258b4c4192b1dee34d01b214cae030f3127265452d5fb43259f591cc77662fb5a45fb8dcf9de0762ae47db84af36069e3b011a9c3c9b3dc821248e547eaec50f69244678105f015cfbaaada2906639b3f", "fd65908645f5ca5eb8c385dd5bf9e380eeadbbe230d8feb42dbcafd51e56cbbe75307e78bd89f200bcebef42fc0835d28841fd6005612a7ebb79dbcf62b9efe22abcb81bd210c92c949517ba1178cc7cc787dd9b19f7102d9695b02e277fb64444b15f2b11c25e6666528e245a3f6f570df87abf81da2f0cf78b2924a08eefa9381f5c51b79cffb52a74f0edacc4860ab36fcbbd24a7", "-407528082300f86ca16c9255da804cff65ae69d2a39d0d55ecef67e53456e63ff662ccf326f31732b77ecb1a8e9624232ee3e642fe20653cb145b3ab73db7e279e742980047e7077d07bec9c2343fc61a63b2f980ac5e9074242da32e45a16eb27e9e8c81668186ad882f043e4148ad955ad875f17f67efb4dc75f70c40cdd6052d7716566a66d70c2f3eafd96f4cb5fd946c5598968", .Okay}, + {.Sub, "-10f0bbb6d01a355b5d85339b0c96ff7fc8432783941b23571601a9b1da2d6986ef333a37983f63ebb96a933ef9987441a6e7fbe89237b7017e288ed3f94988cd02de71234d7ed1e01a6219093d77e5daa6400daf49509745e01abe99e4cac69bacd3f6799983c1ee052c99d3756023d8d05a49d738f21ccabafdcc3a94b3133fdb43b22aa6fed84b665a9719a3fcbae59c342642c085", "6d52150290e1086679acea555a8fc57d6dd8c4b59fe31797f2bf8c2729be46449a853b5625ed4ad947facf342dfcbf280f482289bd36af4db2dbed5e7e19e825131afd05449974c61832179a19cd05c6979a9cabfe9ba8bb15bf228f13d0dfa03b5804579a609e920b0f451e9dce765799e21b5f23a661150820ec8fe3fce3fbabc5bdb1416b8bdad32c543766f3171245de6f126cf6", "-7e42d0b960fb3dc1d7321df06726c4fd361bec3933fe3aef08c135d903ebafcb89b8758dbe2caec50165627327953369b6301e724f6e664f31047c32776370f215f96e28921846a6329430a35744eba13ddaaa5b47ec4000f5d9e128f89ba63be82bfad133e46080103bdef2132e9a306a3c65365c987ddfc31eb8ca78aff73b87096fdbe86a64263986eb510aefd1f7e21295552d7b", .Okay}, + {.Sub, "2a695155f3ea5d1af348064d4538076e3e8ba68d584a48756490804c0e3148ea155becf116617b32579dbc1350ce1940f4ddb80d7f7ed84f6963e62a675a2b699a8fdbf6e4f6d0788c27f15b79b43f1eaee2ebd7129a3fc0ba24a66f619eed24c18951dfa28603c332399bdfd1c2d9b04ede4f52675ef4342da2f466e9f36291212688f3f5588f17246c6e71749c756e32ea128d048e", "eb28982ecf3d508a002a0937884ddec326085abf00ace79f1910b6df7af3ded1e3e0a5b080759eee23db8e989d40abbe5c88f4a5c68dd9249e02981880f70bb745d4667196f74a4ee9a7186bf2102203f7dfb73fbfe830bacc09d48ed058b26b83912bb8621cab85cf337465b813194f0b49a6ff7ecc90b42c343ff680c151273700bda0b912d8e9c72504b272fcde8a0eb9be67ae6", "1bb6c7d306f68812534565b9ccb329820c2b20e1683f79fb72ff74de16820afcf71de2960e5a214375600329c6fa0e850f1528c32315fabd1f83bca8df4abaae2632958fcb875bd39d8d7fd4ba933cfe6f64f063169bbcb50d640926749961fe09503f241c64390ad54664997641a81b5e29b4e26f722b28eadfb06781e74d7eadb67d19e9c7618887fa1e264d6ca78591fe76a689a8", .Okay}, + {.Sub, "c884450ef0decd497a60a7018c566afd54547830b9af664dc457e94dd164742e72f5c3a9caedd8571b157989c73a64ccd8138008e90c5c0a2c2fbaa0c7435fd23f3f9cda272416408b9796162f2864e12b714d6a94008cd3048e70687d9095523a92b606ad6d800201b973a5932d5d873b34af896011f013e47726465ebdd89dfb0a6c61e44c38b94e15778a2fe248d0e149403814a6", "3cfc2b6146ac72f99cc8e63520cba7e7f9ff3d5dc092040ea05dc6deb363b990339ab43238192cd3bb694ccdc4e27256ee130dce2373435fcfa38afcca9a7038aa9436c3779adec2d4dfe7532a76056e5abc34786ed8669d6b4c43fa0be453f529e51d9ed650523a0e95fab88de403b719dedd1e90acfa7d551cec2ee7c03c69f039fce1944d34624a761639dcade1972d93b7fe60fd", "8b8819adaa325a4fdd97c0cc6b8ac3155a553ad2f91d623f23fa226f1e00ba9e3f5b0f7792d4ab835fac2cbc0257f275ea00723ac59918aa5c8c2fa3fca8ef9994ab6616af89377db6b7aec304b25f72d0b518f22528263599422c6e71ac415d10ad9867d71d2dc7f32378ed054959d02155d26acf64f5968f5a3a1776fd9c340ad06f804fff0457039f615053346739b3b58839b3a9", .Okay}, + {.Sub, "-8a5aabfce8aa134a984deffa272624d207c62763d3e191bed600570d3e921277f20b111c21aa7c83d7f9455a5a6b315a1f6197fb455e696bf6c6ddb55a1b3abf66bea966b17032b76899e86ff67d1af6bc412fa43870a19f7aa95ce25e9c8b488f7582018ddc7c3300e3680d4b341eb7c87c0ff250ddbb94c3e48bb53a094532bb3ad52f11e4f836939fb278c1f9adea143010eb570f", "b36b4f462f828c065af00803f8a2c0b6c023838529d25021f14243c0f569674fd4f896574907a1dd072776c570252264926b3b03c7d9600a5d6428f49d4c27530a1896e5451357f0e0f92e1ba15b93d819cfe4471a5f5002e5a997c82ed23219bdd61f96933c094657b6a44c38b1680255c7c526a4addcf6ca2c5689e2c02d9a334a61f3711ee21b2cf0292517260ffec5ce0b3b042a", "-13dc5fb43182c9f50f33df7fe1fc8e588c7e9aae8fdb3e1e0c7429ace33fb79c7c703a7736ab21e60df20bc1fca9053beb1ccd2ff0d37c976542b06a9f767621270d7404bf6838aa84993168b97d8aeced61113eb52cff1a26052f4aa8d6ebd624d4ba19821188579589a0c5983e586ba1e43d518f58b988b8e10e23f1cc972ccee8537228303da51c08fdb9dd91fbde8d9fe1c265b39", .Okay}, + {.Sub, "de3708357ef2429d26bc698a8f7df5b73ee74298c945ab5690e417ccb5df6c931ba88b7421bf09d7b80df2b51976a4586588be445b78d210bcdca247e1a4db8f5bcccff478471a3a973221481ac7ff14d88621f736aa2aece879e2df95fa30b32da7a25df99aa737278ac2e0f49e6542eb5f02e5c8b612456b345b548ee5fe62ae21d5d933d031e200bc01c11b50fc9311ab532eb6fe", "fd3c9d7fa222070833ec30284f9b27dffa80b10829bfda55ea0b831ca52348c0c6c8a3b7d6c99954834c9c67e54e094f14e7cad26151d8a26067dce5ffb19205e1a198a3dafd9f00076f2744bfcd767c9b9e86d9204ba06626c00a493cccc13d320b3908e260245d9acd49d8bb547e454bfac7bebc65c4d76c5efe1ee3ecb1ba74f76a0c93edca98ddd1facccd7aa68a08003f879f6b", "-1f05954a232fc46b0d2fc69dc01d3228bb996e6f607a2eff59276b4fef43dc2dab201843b50a8f7ccb3ea9b2cbd764f6af5f0c8e05d90691a38b3a9e1e0cb67685d4c8af62b684c5703d05fca5057767c31864e1e9a175793e462769a6d2908a046396aae8c57d26734286f7c6b61902609bc4d8f3afb292012aa2ca5506b357c6d59433601d98b6dd15f90bb229a9f6f654ec58e86d", .Okay}, + {.Sub, "-f2df752352d603e97131d44a11cf8f639f345e41267d94d2d057eaba0d72385ca0854aa2d05b44fe47db490fd19a3237f250167d1897d4ee4e5bb1a01b61395849cd9801f830b260d2276915a9324169c3140fb110c166b3f1b31baf394bbbc1d5384489235f1a8721659f50542c920b21ab9b0b1934f4e0fe7af997887d82cc830f876f8a2210361a88062461de52da5074964e4e0a", "bf89386867f8de20db9d54c606da324fbe7ba97e292ecfd9268bbb9f5ce2219c1dc787739cf71b73d641c4fb60de0f2ecf0851d57b9a6b5a761fd13dd43dbc3a35859a40f52ee804674a55b9fd3182b47ef2e07134b2a419ce0ff97e46d82477a0259987dd1311ef62f62447ddd2d8f956d6d531fb5c40572d4482a3b9e83c7609f030113ac039a9cd50a891f7e77754269faf4d0cb3", "-1b268ad8bbacee20a4ccf291018a9c1b35db007bf4fac64abf6e3a6596a5459f8be4cd2166d5260721e1d0e0b32784166c158685294324048c47b82ddef9ef5927f533242ed5f9a653971becfa663c41e4206f02245740acdbfc3152d8023e039755dde1100722c76845bc39831ff6b047882703d149135382bbf7c3b4265bf428cffb780c4e249dfe7d8aeb659c5ca2e7714459b5abd", .Okay}, + {.Sub, "1ea5621dbbb390ebd94447836c7e748674b6460feec2341240971487cac430829850b046533059ad0ec74d74c6c1863164d0b091bbf6774083817d70724b53dbb0d0a92b151a5402cd9d6dffab3ab27787d8b438871ebef4e7c4d8cc68482821d52af15cbe7b294670ab8746b3be773a659a49d9e6e27c096f13afdb12e4c072b57e0e572812ac0a133e8f113bebda18f6261bac85d5", "1ef6246bda7db653749d4f1d38edf29d1399ec143e50e7e6abd3dcc4423b958d15d86b075a808f7b738665c7913dc7c9dd77233660d50bdf12a16cdf8c6602da00c9bb668de24ee778b0d0b322f1adb653cb5b616bcde06ef3130c222cebdfa0ff28cd868b78287cace1973e5acd56734d474470e1c213aadfa71ada847b7ac4281130228edfa31c6056149a645c6896499b4d79dad6", "-50c24e1eca25679b590799cc6f7e169ee3a6044f8eb3d46b3cc83c7777650a7d87bac1075035ce64bf1852ca7c419878a672a4a4de949e8f1fef6f1a1aaefe4ff9123b78c7fae4ab1362b377b6fb3ecbf2a728e4af217a0b4e3355c4a3b77f29fddc29ccfcff363c360ff7a70edf38e7acfa96fadf97a170936aff7196ba51729321cb66ccf7124d17858928708e7d537531cd5501", .Okay}, + {.Sub, "52dfb418cb86ac4213ba118dbebe1216e65ea5d4d17a122b72b30eaedb62f30f03e89169ae51d893fb2a757dcae15c22090176bc63eaeec4464afb3269cf33add41a3744ab36f70bb83138855ce4fc60c3374acfcd7906c4c180995836066fa6083b22ddf9dc1073e2f7261a8a166a7129cb9d7a8021eb75191ee2d4e83542fa2703e2933797453d991e3e8eaa0b220c0e0916f71b90", "54d7d211c915b59343c2acad571e30aca97373edabb8b120d77ea71ce6d52ad185c4517d8376e3592d1daedbbc9509d6b0703283bf4ca004e2a31140fc119f8f6ea4afd09be063bbf30eef2644d9d5dd33e2777be9e56a850062fe663e993dc004243559bdfa673d9b0a50eb926a97517e29681922e5e90123eb07a328b3731ef5c8df04258b86758ddbda435a5a0ea689d744cc41d2", "-1f81df8fd8f095130089b1f98601e95c314ce18da3e9ef564cb986e0b7237c281dbc013d5250ac531f3395df1b3adb4a76ebbc75b61b1409c58160e92426be19a8a788bf0a96cb03addb6a0e7f4d97c70ab2cac1c6c63c03ee2650e0892ce19fbe9127bc41e56c9b8132ad108542ce0545dca9ea2c3fd8c0acc24ce407e3024cec4fc70edf44137f4bd9bb4b04eec9a7bce2dd52642", .Okay}, + {.Sub, "eaff7c24402b425e36cdb7ec8491a87e1d558d0a827c3204de86dca10579d878958f4b096fd48b01d14d06d0793c47adf7e8811d6ff1d8d52e6f0df05f608967c40bc6fc7b2db9b25388c98253a3b15bfbd1cb28616d9086efcc5c3cd54c57b6b3fb707cd125eac36719b4b6a06514892573ef8f0cd17b644d030cdbbc57f61ff3740e5f630e1c12f2743668315352fa906dfb2a6dea", "2095596d8b2cbb1491a99c7288d1adecb56c0d6face9a67757e90557a7e561431545339e74f534b333742825eb37008561c51ef51f162a27fefe2d15d4044802171722173d6b8197210cfe94a838a9e32d781743a1c1a9524f9cc44df012534db852ff0c07cab45d943e5bc2f71498c05d717b89918b9138d926e2ec6a0c9fe0a8512a07d01b54544027506b25e990e2f8348d72fc2a", "ca6a22b6b4fe8749a5241b79fbbffa9167e97f9ad5928b8d869dd7495d947735804a176afadf564e9dd8deaa8e0547289623622850dbaead2f70e0da8b5c4165acf4a4e53dc2381b327bcaedab6b0778ce59b3e4bfabe734a02f97eee53a0468fba87170c95b3665d2db58f3a9507bc8c80274057b45ea2b73dc29ef524b563f4b22e45792f2c7beb24ce5fd0b69c21798396db771c0", .Okay}, + {.Sub, "-c2908c701ee67d5877befd1dc3f307df291a2c2b28f3ad1520297ccb1e423db7fbc67416c77ee2e23f44aa35f96746f65be859195036bc4e4716562347bc5e9e437838122fc1d0f18977dbdb3e47e9b21f20184c5d6151d1b4357cb1f369f9e8a0a344c3d419c4ade75ebf1f162cd8e4f49128165d144e3f8f46d27ef17d791ae3bef60d9626a31787925be0d426d314a22c7104f6b4", "19cf33278b2a6d977c1728d1299b25776a3f8ccec345e42b226f6a8e9a263dbb1f5f6a55955e5a16396c1e053f615e163cac1bb437152f41d9df2be34cd02f3d71c16a6e06b8661603e5010ff0fa84d7effe46f8c4aa50a0c8aa931af8f3880ca558a37554953a0a95987ff08c560443301332a78fba95ba8d05336e45d4d93d8c55a53ab8c3c3c6160ecf2102d3bc9008bd7a0a3635", "-dc5fbf97aa10eaeff3d625eeed8e2d569359b8f9ec3991404298e759b8687b731b25de6c5cdd3cf878b0c83b38c8a50c989474cd874beb9020f58206948c8ddbb539a280367a37078d5cdceb2f426e8a0f1e5f45220ba2727ce00fccec5d81f545fbe83928aefeb87cf73f0fa282dd2824a45abdeccee3fa1c4c05ed3752525870149b484eea66dd9da12b01d6fa8fa4aae9eb0f2ce9", .Okay}, + {.Sub, "-8434216e66c80baf1a3e99b0e5160fdac1ea6383843d3444c57ad2fa01eb094b12515e8c61eedef56ad2915ec9cc6cf90cc4f002b4adc80636c61cf8ec2ffbf58944bb412041671cf6edc66bb295bcee0bf55b743e9fff2cd84be90bc40c172d61841a555379226a89b2fbc545f32d150ade33d7381599e2a70d8a8b0467dcded348d3d32e4961efec915d2a8d07e5c9495f35e56a46", "d0293c89c3616542f73061e2d2a44431e4384e2b908416ad3fce51686ea0027f5588f53360b9b40342d30ac2301116841aa1f060c7a638b77fc0361168c1d22f78415ddb1acae72d762e482000a3c1f7437bd334af6d930736a1a69b8a698afd9e8cba1366bf15f37683dd01ce17275b4a215324e9e4348ec57bb2ceaa1a524196e1f9355185e93991860ba3c6689295f49976dd58d8", "-1545d5df82a2970f2116efb93b7ba540ca622b1af14c14af205492462708b0bca67da53bfc2a892f8ada59c20f9dd837d2766e0637c5400bdb686530a54f1ce250186191c3b0c4e4a6d1c0e8bb3397ee54f712ea8ee0d92340eed8fa74e75a22b0010d468ba38385e0036d8c7140a547054ff86fc21f9ce716c893d59ae822f206a2acd087fcf4b297e1768ce5370785f3df8acc2c31e", .Okay}, + {.Sub, "-234fa1df97b2f8d3a4773556465e40c107d4b43e4158dab69fb0beb6141a75cab3d167b67cb08b11b7e27015cc1a924583e985ef00da8896387e7e7f9a40ef14095ae5342ec3a1e1a8be5b15d6a700f5d5ca540daa21a7dde24987344367970e5239dd24a6e42ebaeb22634586dac6c72bc2157fddee83427861a4e11f2df23a2944a3462cd5d9c490d902b7e6284b5a8a2910bded45", "5e5204a51dbe99246506bfacc63f46efd99539ba0536db2d4c1bea0469221c6e5908a21e2ab94f5eaa766704b16ee9e482a51fa173c0028dacb8fea5355cf6e216c26b80f7398480eb41027a5d64bf420b81222122be24e354d9506cf7f4b83c43dfc841d9105d78f21ca6db8cd9cab1fb7293def80102c0e70a84580c3994572c869ab635ce4360c3fedb26e2cdf4fcf9de6b98e641", "-81a1a684b57191f8097df5030c9d87b0e169edf8468fb5e3ebcca8ba7d3c92390cda09d4a769da706258d71a7d897c2a068ea590749a8b23e5377d24cf9de5f6201d50b525fd266293ff5d90340bc037e14b762eccdfccc13722d7a13b5c4f4a9619a5667ff48c33dd3f0a2113b491792734a95ed5ef86035f6c29392b67869155cb3dfc62a41d2554d7dddec8f6405784077c56d386", .Okay}, + {.Sub, "434a180317b9bf7ab4998ed663085db690916fd95a13dd10b716007c713830ee2e3822e0be30f790381b3cb622dcbbdf2fc1dc5d6a304403eb2acfb9faa9a34e7436b2f2d3d26a7ac83714e6eff56f4b12596ae375b0a04f2fcf2fbd91ffd093065e75e9277ba20999cc912a8c93fc3dc0da02e16a4dc8fe31109a1e396478573f271fc7e6cdf0aa71072629e007f88903617d45d1fc", "8eddd0becada60daf23034767ecd147f5bd07b88c64889263109e37b429bb3a03fe38c88dad0ee7dd352697802e4d5d2dd3e575730675c2b69a9d79092d1fa4465b3d964d407399e2dbd90d8ee2c95e858863db05d0422fc7aa0189f580b6e287ba798c620946921918791c910344cd118721e4813c992975ccb5f0545666db71d9d19bb65af28732dad833667fb942a55f6449cd6cc", "-4b93b8bbb320a1603d96a5a01bc4b6c8cb3f0baf6c34ac1579f3e2fed16382b211ab69a81c9ff6ed9b372cc1e00819f3ad7c7af9c63718277e7f07d6982856f5f17d26720034cf2365867bf1fe37269d462cd2cce75382ad4ad0e8e1c60b9d95754922dcf918c717f7bb009e83a0509357981b66a97bc9992bbac4e70c01f55fde75f9f37ee137c8bca65d0c87f39ba15294c75704d0", .Okay}, + {.Sub, "-94bf80941c773ba26910763699df63350d7efc1f6e55ef0e8bce4e36a01f23bab76e6e899a46eac4aa8654bd384496290033e61e09f5792114564d6821c3a572977072e3faeb6493931d756af84f4fe7701aef815674dbb4877b2d5abe9c0a9904f9f75233c2988418632fe8b6c70fa0bac22dfad478f9bfab69e2142d7021e8b904ca1c5a893f4df844cd31bbfa76e9daf5facab592", "2229a50d2868a645ea4af705b7a4ee6fe9230214bfa7b482e05fe56435d5ce066eea0b28312afa10f8a954f89fc0185f838a93eac290a8687dc38360c636c8014084dda3bac636eee057ee7962249aee093f31128184ef86b44ed160b0b5526fce56a71e125d7bcd8d6d0dbadee96d15d7cc712e0be33c0658da242b406e06092d4dd60f586e859fc33ab5ad85ac8308b19b335ecfd8", "-b6e925a144dfe1e8535b6d3c518451a4f6a1fe342dfda3916c2e339ad5f4f1c1265879b1cb71e4d5a32fa9b5d804ae8883be7a08cc8621899219d0c8e7fa6d73d7f55087b5b19b82737563e45a73ead5795a2093d7f9cb3b3bc9febb6f515d08d3509e7046201451a5d03da395b07cb6928e9f28e05c35c60444063f6dde27f1e652a02bb2f7c4edbb7f82df41a6f9f28c912e29856a", .Okay}, + {.Sub, "e9e6d5fa55b2ce6a11a291e1fc1ea12334e190ceb0785f44bd75759966c6d71325ef445a3571ff215cd4cd7bb37a45ffc2edcfd81e4759d2bf90eac7b6efb456e0514d101cc6eced0186372eeb77e41758f959edfcf40d02ee90638ac7daf5d9a00b1e6b256b8b7ae8d8787a75585893339ff5f0219fbf275dc3b47a7bb377feefd7290c04ddee25f93b118266ddc2a600a02ea9cf61", "3257ffacea6065acbca634a4d28cc1c7861727f63ddbcb57fb1bd37f353221b4b8a385bab79e0c974650386c73acfb2c8cd2c581d21a123d39f2d9c19a16b0ba01e1b38f04ba0c826b4f0f5e9ececc20e0f60b799da3e0fbe50e59fa9c42e8af245bcc374c887e1b8611fa131a400e6f71c42222a8f7644964bc59cc50979e73bc6f129085890ad2ade2a6e24037fb6357130b277993", "b78ed64d6b5268bd54fc5d3d2991df5baeca68d8729c93ecc259a21a3194b55e6d4bbe9f7dd3f28a1684950f3fcd4ad3361b0a564c2d4795859e11061cd9039cde6f9981180ce06a963727d04ca917f678034e745f502c07098209902b980d2a7baf5233d8e30d5f62c67e675b184a23c1dbd3cd78a85addf9075aae2b1bd98b3368167b7f54e3534b586aa026a5c742a98d238255ce", .Okay}, + {.Sub, "-bd8421cfa13e6c43266cc1554a14897bd68432b3ff3719c5929c088d1c3416d421df2c3d57c754fa2a37ddc4cb47dd7a98aefb7d4548b51b5876e378493f076af52a9811535e57f4f637f5c683277065103a737cb67e272fb7f909b3ec0f1aa3a7537911cd96fbeae3fe94ee215b9ea577188cfa0864d5c72f26dcfc3bc12160dc78a204cc2bd27bbb4813bea9cba250010ea932c264", "ad3c44791d61bd6f8e3399bfe1d2ccd7daf09bd5013a85edc5bb27e47d1f5c42436c82902f74ffd54264795bab6c7b0386ccff123c397ff09343a1a917edf72530c5c26eff3df09ceccdf4dd2ea9ea5003d8f6401d8331fc0178f26b6e6fa40c0852410a4ac925b17d3e67bb1f71036970f24a71b3014f2ba805852d54cd01c8662381da7052f1af614e1a54924f59dfc804365fb07c", "-16ac06648bea029b2b4a05b152be75653b174ce8900719fb35857307199537316654baecd873c54cf6c9c572076b4587e1f7bfa8f8182350bebba8521612cfe9025f05a80529c4891e305eaa3b1d15ab5141369bcd401592bb971fc1f5a7ebeafafa5ba1c1860219c613cfca940cca20ee80ad76bbb6624f2d72c6229908e2329429c23df3c7ec42b1c962e133c1afc2fc912df9272e0", .Okay}, + {.Sub, "-acb798cbf50532c8ade6e014770e41948b5b43018af8d9b604e470593260220c1a9c75939210858d0f844e107e4d9797df13603cd3882d086071a1a4512b6774a41a62308c3f6ee174193c44ef7e8453f58869dc5075a0c104f0911b6a55ecfc418575dd275ad1d1b15abb99c6268ab5a9af0c38ad56bc92dfc9928727bd1801fb99d9b3926692c52311d3ea4e43b53a4dc217d70a99", "2947eaaac8732df4c98acf14cf381b64b80dafc4fe39eef06e79c89e58474d052b3dd9df5a26454db70b19a6ce4fe6066b4ef8d2c1420a868a568b6830a05f1a3bd3a3d8207794b242087553f4a45ce692091568da72904b667669d27919f31ebcc4ee6e225bf40cb4ba0dbf0c76c78b84d21a75b166912b2aa6f5b8c36e9c4ce60ea638835411fb357900c82f60377827df9a4178f5", "-d5ff8376bd7860bd7771af2946465cf94368f2c68932c8a6735e38f78aa76f1145da4f72ec36cadac68f67b74c9d7d9e4a62590f94ca378eeac82d0c81cbc68edfee0608acb70393b621b198e422e13a87917f452ae8310c6b66faede36fe01afe4a644b49b6c5de6614c958d29d52412e8126ae5ebd4dbe0a70883feb2bb44ee1a87fec15baa4c0588ad4b27da3ecb275a1b218838e", .Okay}, + {.Sub, "9a57bf4e62ac450fb44e231a2195729ac200194fa3107ef4a7889e9a5d6050e1cf8136f3354ef551a6b6a70ccde850e5a2677fa492ebdcf2acdc92d0af8aa856ca06b42a0a297c47db0d77e2d1bae7c8b130f3761ef56fbb9d5a65edd5cc633ef43f281459f43ea9d3c280dc3e6d4c2bed8fcd7442f5231fd7dbf3e5bd9dcb7750ada7bedb8b72564a1bee1465dbe7be838ca54d96b3", "caf18626e0ae28d3c7fd0a9a5e2efbca7ad4b74f52c35e5158d0757d8507619c046836bc3daa109e7c476c055bbda4d74a537b087a5d42458821eea6c29b2fc28abade6a01a10ba6387dd4f8e0dd79558528e48c22e9ce98f5f62006ea43437cb643b890c1852e32e95c882da94068f489322b3890d10ce8cb4959dd27e99516a573ee3d842ab798be0a4798466f88ee082c33e54440", "-3099c6d87e01e3c413aee7803c99892fb8d49dffafb2df5cb147d6e327a710ba34e6ffc9085b1b4cd590c4f88dd553f1a7ebfb63e7716552db455bd61310876bc0b42a3ff7778f5e5d705d160f22918cd3f7f11603f45edd589bba191476e03dc204907c6790ef89159a07516ad31cc89ba25dc44ddbe9c8f36d65f76a4bc99f54c6467ea89f454273ee5983e093a12f849f8e97ad8d", .Okay}, + {.Sub, "ef2bc60446645de651fb8cb6c423a940e17f1cb6d5f07792f546391085e8502c2885e55bb0a4aecc553142b803c70c7e5326dff3eb3f21d80d5992783987c386ec13d3ca5b0c54a294ed01b3ef54b8f3de7ce0f31a13e06530d2511c8bd2765454fdf3c1bf552eb8e1b5bb99b0a5bd1ae685a574dc4325f4b279ed3f890d516e486ad915fdebc671e85d5cce8e31577497b2db79ff21", "e0439760bb00104942766bc250bad7ccc78c100af9a32a3be94a2ba0c3cbbb6d2099e9942e83a76441b162254f5a4c03c20d3ec8cf909f32393400eadd8e5456c412e1889d00721a3a1173ae327352ed4a07446b96092e93f5204a40ea105c638f0e378563b591ae58bd44488df5bdead5d8a220de583f6865feee6dcd62d6a6a91393788dfe25e498072a89d337afb402575ab0d5", "ee4b826ce5a95dd608b9164b01d2ee6914b790a6caf6d468b95ceee4e5248470bb654b721c762b24f0ef9155de77b2324f64d2b5226f9138db205e774eaa3532954fc0e8d26f54307ab2f040412245a0f132d9aeae7dd7369cdd30d24ae865f7f16ee58a39f17927335cfe556817c75cfbafccd2bb64cdb54a13ee511b3fee97a1c1c582855dc84c03c555a4045e1fc4e3b0841f4e4c", .Okay}, + {.Sub, "-ae02be8116bfd6b2ef911bbd8e9a2d7e7b98471ed847edc4b0a8319c3129d1950d4e13ee695593ab2c2369ed0cb2f5ca3b416b13dcff705df84f907b25c08431163450d552179d76253d3e0532c72e79609018345bc0e796641a9de8d28920aee04087a4127c76cedbeb8b72aef9733fb4e424449d745f1c2cc3943dc739b135673a152002109d5643de6287d0c8da985f7e45bda04a", "a66668e3d7cd63801cd5d37cb884922dbf3bf8340f25a8d2e8219e8f8961e68b048e0773cc8f7ce1c29cc90227d55ea6f5e9d509007a658e668cf8d06f64bb66c2075fdf9189702b9438bc207054b620c6e591802566a8c416e8d82eb1ddf0e6ff8831768de53a4574df39ac2f7c42164c5fb33aebace4820b6c861018631265ab08cb23d91e05019e2d44ea1efa5de841a3bc7baa79", "-154692764ee8d3a330c66ef3a471ebfac3ad43f52e76d969798c9d02bba8bb82011dc1b6235e5108ceec032ef34885471312b401cdd79d5ec5edc894b95253f97d83bb0b4e3a10da1b975fa25a31be49a2775a9b48127905a7b03761784671195dfc8b91aa061b11450cac51ede75b5560143d77f8921439e38301a4ddf9cc39b1242e043db2ea257e20ba771efc33880a12202394ac3", .Okay}, + {.Sub, "-10860195e30b93462a925609a7cbeeffd2a41c986ea7cb37fda7101848998e74692a09296dd218c262c397a1edffff0c5e42cb0d52526772115149bc9d1295273cb6a642b23ea58ac6d8dfab9735a21a3df910a0ea02f0643481d3c1aa54bb44311dfd62eb08185ea5741d907832ca7cdb7b506775763faacebbb7d41626112f1b1b85d10c3e62b9948ee5451ee3f94070c85790f01f", "d3e07b03ce63d3f0e69dc160dce51f7d09a5f5a415c45861c5d96d37a1fc4c06ea60493bdb420ffc1287c23165468b7dc822fa93eac9410caaaee9dc72baecf368b3a05394921a0c7822b04a777d8820152a451bd7defc5ccd2fa743ca4dfb14738d658530edd26c9282eb14229ba8b6d427fc720d226fbd8688024975784e40f7ec9da415335fb2223ac51bb082889fd91bdb0d1a38", "-e4667c99b16f67371130176a84b10e7cdc4a123c846c2399c3807d4fea95da7b538a5265491428be754b59d353468a8a2665c5a13d1ba87ebc0033990fcd821aa56a469646d0bf973efb8ff60eb32a3a532355bcc1e1ecc101b17b0574a2b658a4ab62e81bf5eacb37f708a49ace7333afa34cd98298af685543ba1d8b9e5f70130823752171c26bb6c9aa60cf6681e049e4329e0a57", .Okay}, + {.Sub, "-ef6072f469e5b0dbc7808efea0e715cc8c29a91a5ef206c35d28741cb04e1e088a4a2074e530256976f5a138b5f0d0e4b549ce3800a194a7995eb6b525952d347bf1534391d1e16888c3d98432bf65776f1e198110f61f78d79473a0f779dd4b0340c29e1eb138e5826289f86840cb16a8c57239758905a546851315ffcf2da4e1ba0687d5693c0b9710b8511c816b4b1b79892b3a4f", "24dbc75e373e2ad36a397b1e59a0b1dc071b5185481fe732e9836a3eda7edec956e838f4e6f907e729910b285f40ca36a0b7e5bda747b59f3e876f8f47490115d85091c1d8d6d0da3870b032fb8b0f2dbb6943c26a1f9feb5fc9740e85ea7295ee98c29cb204467292222f0b5fc9a247f83d78af41c6abcfb2af0467de6fdd49cfbaa94c61bececc2ff4014a704f18fea99808f5d77e", "-1143c3a52a123dbaf31ba0a1cfa87c7a89344fa9fa711edf646abde5b8accfcd1e1325969cc292d50a086ac6115319b1b5601b3f5a7e94a46d7e626446cde2e4a5441e5056aa8b242c13489b72e4a74a52a875d437b15bf64375de7af7d644fe0f1d9853ad0b57f581484b903c80a6d5ea102eae8b74fb174f934177dde3f0aeeb174afd437280ad7c704b99b8cd08449c511922111cd", .Okay}, + {.Sub, "d6f5d183b371ba08776812eccd7f73cb98fe81235e0e31816354e74bc37ef7e6e02f32be66d8fba30b20f1765ab6a08cc53e79f7ad6db94bddd006a3017c73ad2c512ddbc36eddda686c366389ed4e228c5c2f7476bb0fef919822f85a0dc439436e46a0e8757d6ada5d5c84781ec17039846ac3b8f746e896992ac63fc0bea5d75355539e387d1e0443bb62d336980d1168b8aaa982", "840356bc93152a20496261f2b6f8d5e409eca14b1fe0663ba38b3f6e675db75a86f1aebe63102a9bdf84e123c7def4bfbf6f5b4d2f58b905fdf7a2ca2cc47169732bc8cbf7a32731fb081fe20e0617a40306784f045445e611cb2122efe5e8c9996f4b9a9ab21a4c2a122c7d3fab10ad56e70138ac94845b66a2ff367382ad78c3886bdb3ecfff71b6ad9ecad0341788cee0655b636d", "52f27ac7205c8fe82e05b0fa16869de78f11dfd83e2dcb45bfc9a7dd5c21408c593d840003c8d1072b9c105292d7abcd05cf1eaa7e150045dfd863d8d4b80243b925650fcbcbb6a86d6416817be7367e8955b7257266ca097fcd01d56a27db6fa9fefb064dc3631eb04b30073873b0c2e29d698b0c62c28d2ff62b8fcc3e112d13cae9785f687dac4d961c98030280844288534f4615", .Okay}, + {.Sub, "cc9859534c70ce34798fc78992d8061146195af9d33bfd1b28dcc2daff60c098e8f214e52e85315af0cad448eaad05e09788b73ed13dfab1706524969962d024fa29de8f1c8c5771bd4af27c6e1ff9800e668cb0ef2363e0a54b35ff92de5d015444f0c510eb92153d4899c385e12107f11998dbf5ccfbdb475256623da1cc8f8c85b27071adac975c49b4c898f4a39766f8121948eb", "b18da8c45c893516f483c5afd80a2bd8a19c62357aca87dfc11529bab0c71e18db0b9fbf0010e50c533f8ffe936e7752b56cf4bc6960fc17752605b5487288b321c28d21dd592b758f811368f0feb837830f5dae97dfd271264a26b77fec3b6ee720e879df10f8547b28f7862867105b69d01f7ba616a709715ff4deec901db9aec2dcaf0567cff6d39409b0f6566c8e28f17f1819c7", "1b0ab08eefe7991d850c01d9bacdda38a47cf8c45871753b67c799204e99a2800de675262e744c4e9d8b444a573e8e8de21bc28267dcfe99fb3f1ee150f04771d867516d3f332bfc2dc9df137d2141488b572f025743916f7f010f4812f221926d24084b31da99c0c21fa23d5d7a10ac874979604fb654d1d5f261835111aed5ddc2d5c16c45dca088b5ab17a29e37093e0693012f24", .Okay}, + {.Sub, "-fc7ebb2b811d9d51879f00b92397c1f9ce59b44a501c318c21c689ac2db7c2077bdc271cc90f02e8d0d8fcc094bbe316e260070816248a16a0b7c72a765494a8f25da56d3358a890b13008a4ca4d67855a4a808101363c3ed34784d3756732c61ffa493739cf1d30f1bf1257ae80ed35b85ba8e87f89956988e57682946e2dd5fd73957c7b23917aefd82457e2cfb8efbf87a41bf595", "7b738f4d2482377ddf082750f8c9544d1befb57a173d5cb0283576b988751bc643c15cc8ac1f90693e9f8222dabc130bfcd390aa7368bf0ad39faf5db59cd1dd573974f48d09d32b29cab0be2fae7b185aad276ec2a1967362ad4d16ccf12c087ef1495e9ce2a9d699049b663596eadbb2bc7e0742305796b83782c9959eed5bcdb6cb47da0c0cb9beb02f338fc8e650fb6f91b5e527", "-177f24a78a59fd4cf66a7280a1c611646ea4969c467598e3c49fc0065b62cddcdbf9d83e5752e93520f787ee36f77f622df3397b2898d4921745776882bf1668649971a61c0627bbbdafab962f9fbe29db4f7a7efc3d7d2b235f4d1ea42585ece9eeb9295d6b1c7078ac3adbde417d8116b1826efc1b9ed00411cf94c2a0d1b31cb2a60c4552f9e34ae88538b72989f40baf735d1dabc", .Okay}, + {.Sub, "-12cc21e163507d82c84a9ff140ff64695423ae49ad657903ca9db1e06217a1e3348587eb7a125d962ae251ce152849f29af9465a1959dec4a60919d114bf301abe7944fab32319be76ee496308707fb9f4f0d84786e7164a873ca8ebc32ac9600aa52f01d43a3f9fcfd826d4fc543d331d0cb9a9093ceda8a11ec80f96698ae7b5c370d434f4e509ccbe54ef50dc6468a01b9a2b5dd4", "866cda704a03b081f9428460df2ce8a480d938ba95b42ed46597189c7ce33192e69c4e50541c60e68a883f296c1ef7ae5e22dcde09d12c3040a4bcd916f020f3287ed86babfef8d2ad0809da32636748f2e6f150ffffe730e12a9a6921bcf7ed7c9b7f4b0d066924f208dae4fa86a0e8e3c64ef7f5465b47ff6f16cfa661a34c4487d324ea37db06d8f33d02df770836f64d7777060d", "-9938fc51ad542e04c18d2452202c4d0dd4fce7044319a7d83034ca7cdefad3761b21d63bce2ebe7cb56a90f7814741a0f91c2338232b0af4e6add6aa2baf510de6f81d665f22129123f6533d3ad3e702e7d7c99886e6fd7b68674354e4e7c14d8740ae4ce140a8c4c1e101b9f6dade1c00d308a0fe8348f0a08ddedf3ccb2e33fa4b43f91f2cc010a5b191f230536c9f966911a263e1", .Okay}, + {.Sub, "-99ce546d73ed837414b1099e2efc2f3a49db2fa0130b3fa955cd58c5fbdf8b9775263b8f53a4384bb9df93a11b06d09ade79d2747a965eb467336437755d9682d177fef131f766b55bd2698310e8b976a4f43e688d8831e0e351a87e064b03e5221f47a475aee4e83445893d21a7b762d8d1304398e60ed687266349282fa918e411f2d718a990dca87e4cc202b951fbc725a3e211c", "7ec8cc36f4c6452bf197eefa576eb18691ed76e2ef1ab44f7df961b7c25bb78ae746b81bb45d5b37be4a27ca0d05457facbaeab4386e3400f5ec3194702f880520d335520c82deb0af6b010fc3612df1daa5a70410985d449d1d187945599aa55c886555bc198ef7e025588d2eb74c351705488aedf3b3ad9e050826cb96b60f26201c08841398e290d857fcf78b5fbedb4244341481", "-8865b17dcc051d6332e2ff943a5e747a368b29dcf04b684a135637442219b0445e991bd4a9979ebc79e821041eb5b2895aa287db801799ec3c5f67d7e785616d4deab5411fa2551c052827a7f46fb98944f4eaea9970e062ab52330125be4ae3aeaa59d003747d466369b12100d1c7ab44925b8f2782149b06776e5b5e19b0a0b4613b35f59e31f05b603cc917b6f4de97b49e72359d", .Okay}, + {.Sub, "9924e733470eb7235edde8a1428cac3da08f3edc92a4a78ec101dfe719726b40def5606d6aefe72f9296112b8f27cfeba0f3141fe244ea396e03e4ac7b609fee4a724d9dbb2817eed5e980decba83ac402d4ec9198adbff67a9dbd276bf344fd7307ac0750b90f534eed473a75b133a710b105dcbe5f1994cb225fe72fb71620566f5c63bd37de85371e8aa6574cdb8c2ae252cd149", "f02369a7dcdc9caf15bd088a64de4a00618cf25b9610139e82d96eab4413c285fdd44ffb8d09fa0c0a85dd78fe0d005926972d8b300c484bc8565144707df3f296ea0ddd14714f5637b0f864f33f03f1ca6432ca761cb214355e072ac5765db0c9f9d3b8553b365b40c2f2a7dce41c243a859815b9e11c94cd9b2d3a4b9e610672912f07f4f734014768aaa4cbec91c9f5bd0d8a2e00", "-e6911b34a86bb13cdfcf2a0050b57f3c8783fe6dcce5c92596c950acd27c9bd1efe4f9f4b65afb99115c7c66451a835a6c87fc4931e7f9a8317612f9a8c7e9f3b242e90338becdd74a526057068480458a36e4015c91d614cdb42b584eb72960f2c958f7e02fa5660bd41e34358908e9c97a87b7edfb2afb80e9073bd8a2efa46d2a3941b923b618f3f6c1fa6677c411330ee85d5cb7", .Okay}, + {.Sub, "-fdb783bd20178cbda678a5de37917f05c10169a70a4bbd7de6d28f5448a8a1eb81c8b13ac5f51ce9b87f213d4a9a8c67dd3993e58c7ec7863961dbaf3fb5eb0e978e63b01d1e7df35f077563be89d101ae6b6ff8d11858a4f0b0e8b0048650c38cddff99aa49e59717c2f2988dc000cda36bd8b40bef5c47128e118ea74fc7693407016a03dcd12cd8a9b286c2333a9b7914ca9bbf9a", "f67ece0c0e1a5e8f0938b11254f4d0232f79ac5c3dfff989ab733276dd00eee480b29fcd32501c61068da4f410a9a3b1a5b13a10ef63be9e05dcc326223a82430165eca22f227bd4f68383a48567de7b45ec460f9b35afe011c0f75c0478eb5eddde61487d4a874ab7246dd2a91e18bbfdda83ed9fb46b08c3b4e0711f3b61ed60f1cbf18ca848c01efa6c11ea37695831f813900605", "-1f43651c92e31eb4cafb156f08c864f28f07b1603484bb7079245c1cb25a990d0027b5107f845394abf0cc6315b44301982eacdf67be286243f3e9ed561f06d5198f450524c40f9c8558af90843f1af7cf457b6086c4e08850271e00c08ff3c226abc60e227946ce1cee7606b36de1989a1465ca1aba3c74fd642f1ffc68b295694f8cd5b908519ecf7a41e98ac6aa3f3ab0cde2bc59f", .Okay}, + {.Sub, "-d2784179884f12ad65830347dbb2f51fbc1a1ac0af18125ed05fa3b78a93ac1d87de1b5f532ad297f375ce98a40f37c99fc695a6d55b1ccf02a3efce03e06848af9e23abd4e7c435666c183940bbe35ee7284f4d32aa6fc99e3fd19cd0c9cc70ecb251d3a32ae5e8184daeff6f44507c5c82b6945d021c83bc840dfed4f0d0e4389d3aa53c77c07c3091c396868deb620070ad4511ce", "882bda65a0f69936b387b61eb516a153f7ab4bd016052f5cab79f914fe8d0a505126a810fa12bdc02a55e2417c0b193a67e248c1b725648e4d2dca4edb0781ece1d4ed2aabe06b70e8b096b1259766b6d0efd38f5f279e06d6a29cbb65331a7f689b10dd6b0a5bd2a56a1446468f31db1009f61193556d925ea782db42080a56b3fd8336bb08c3ed3d2074e951d2fce0beb285d9ee83", "-15aa41bdf2945abe4190ab96690c99673b3c56690c51d41bb7bd99ccc8920b66dd904c3704d3d90581dcbb0da201a510407a8de688c80815d4fd1ba1cdee7ea35917310d680c82fa64f1caeea66534a15b81822dc91d20dd074e26e5835fce6f0554d62b10e3541babdb7c345b5d382576c8caca5f0578a161b2b90da16f8db3aec9abddbf78084696db2387fd860e842bf23331f0051", .Okay}, + {.Sub, "9ef49ade1c41fa5876649403b3714465c0b8415862c25ac868b60e08c2b5940b24fc7fbc31b427d14ab8699e9e3e1685857f41a31f3187543ed30b8e1d261a75e02857392c637c05fb8a333d87c911f018814aa0da85eab30695a6073d14296a4dbf8b7ed35fff293f97ec8069b5097098a68571b337a8b14472dcdfe80c0aa0496dee98217f16541c2524e9bc7aef78ae0a1d08c299", "c6de7ed220d9a250afa12990764b4178442f9dacca5b8b62fdf70496b6d0e5e19d07c4b2caf223e78eeb2cec3381d19e7546689e15a0cd439c6be8a663fc3b6e6f2dbb62f84705a4c1777eaa3477f1dcc5bee58508f9918ba370f392b3d83806c8651774556bf5fd150e3d7883e56fe45f6adf634605595560963f1c0283bb6a439f1b14180f18dbafc97f82f8c7d7c844a78b67b7e4", "-27e9e3f40497a7f8393c958cc2d9fd1283775c546799309a9540f68df41b51d6780b44f6993dfc164432c34d9543bb18efc726faf66f45ef5d98dd1846d620f88f056429cbe3899ec5ed4b6cacaedfecad3d9ae42e73a6d89cdb4d8b76c40e9c7aa58bf5820bf6d3d57650f81a306673c6c459f192cdb0a41c23623c1a77b0c9fa312c7bf690028793a45a993c4ce84f969d6e5ef54b", .Okay}, + {.Sub, "22d7f1c429cd10c0d8f9c4ba093bd92b11d1420ee65b80a300ba8785061199bac89b17e6e682b482de6ece92abd6b8d269106d9a75c65441da652e81bff819b45b2c678b8725d45e8ffe82300045b295c9258e67a53ddc55f459cfde3db8666855b4b6db8cd1fdb63cdac0d4da39e37b559fd28c442193a9315c16a7455a5f4a6722d3373af3f6605baba9ac0ea069ccd0e97543de18", "6e618a9bb55b6ef12a5949062ba6d5aa2263a31ddf6de430100870cbbec3fbee00cdda53a4707be5d4e6f1d9ae054b14688f49a2d88eb9e24cc6d6276c8441f0a01036244bbf3d556ecccf437fb42cb629401e35190725805520bbcfa42aaf5b0794cf9d4dee29f02bcbac79f3e7b126d332799385d146303f310cb51da21700e08d90b5d1cc99992f28525e6af271264a0bb9cdb598", "-4b8998d78b8e5e30515f844c226afc7f1092610ef912638d0f4de946b8b262333832c26cbdedc762f6782347022e9241ff7edc0862c865a07261a7a5ac8c283c44e3ce98c49968f6dece4d137f6e7a20601a8fcd73c9492a60c6ebf1667248f2b1e018c1c11c2c39eef0eba519adcdab7d92a70741afb2870dd4f60dd847b7b6796abd7e96d8a338d37ca8b25c52075979224489d780", .Okay}, + {.Mul, "5e832f3f3f0f185b6d79e87a12fd44b2d9ee80880c46b4e7bd4c4f110c4fac7388ba3dcd13b65295be7c6e8fda354dfcf307ef0fb76db773663b56a048bee4ca6483eee69b59e8941a9c19f88aa64ec2230638c028d4e462730206b433fcd27c5651aa3d101a355a03b1150fbb0058f1052a9521666468cfaa0935e908e2192b3414a7beff3e8370c168689ce0ff6fc1c5f55a4621fc", "bed8d1c18dc39c3a0b2c95e667a5ba5692ee56261df43b92828ffd753b69228ec90a5699c51c8998b2ecc29b8749e7729f4a815879c9add4a37605013b105c397973d4bf7d477ada55d4badd8efac12f4067fdb6274c5f9c8354b9116020cfe6658e7ea5606f497ce42fcfadcbff5d37fb4ad468017e2436866f8bc12f800ff6a4f1fd40bae8275c3f4ea09a85c92eeee94d7f43dda3", "467569315cfa229a77348b4b77346711ee58387b32b287c12bc874b845cf7f55792fd53433e53a7c822dd2ae71b2a09ddb03370b4ec68764c3bc0137fa98ba5a7c794748f84e83d4fd9c78c4bd79ff2d19fe05d5b2dd269e53d4108318b73f58004955a617c034b3dc50e692279d38d3d388365f2faa27b85524aeca85c5efaaf40ef722a290d7736a8e1a9ca6efd7b0369c9aab861a2286d047f335e4b8af12383eb393a703213aed12a19cf67296bb185ff7f5a347e36e1186a7a15a4c48b81bdd6165ab670e2c1e52ef85089562ddacc06b5529c6fc67326779cd7798580153cf86421f2cb2337ffe8c8f44480e88202038bcc6e536928d99cae41477956b8dd17affff8222ddfb633636336a5b53a9b8bb6807b9ed5570d8e343fccec57c0283232ad393da29eef22f74", .Okay}, + {.Mul, "-ca5fa63b814cd1219cee6316ece624343444cb141b7af17d583679628ecbcd37cba97b34da4c263c823a6b9e9111f1191acc2f8519a8f91a89110119dae76ff8db8b0dabcd107a17606b905389ff510911629c80d7e26a5ade8b28d891b1e09d445e68f3c0069430f35cec2f8fc64b000bc6b77fe40275681649a0e86598adf228ac66e39c3d11e4da92475296e33f41471450f5e205", "1af3b536417e273a0bbb48955b88e083ef1bf7aaad35a24f096b13b30f8e5e8ccc40a53492d60e4ed6f25beffb401a61fbea7d634a0ee1c35908a899dccd4e1bab3d9c90dbf2864f561e1470c741016a6f0d88c61ff78ab89d5177d4ca26ac0757ab0b67a847e2eea324a62601e2a61f13e1a8101b59419c12d6dbe5d15f041b02167daff617952a0beabaf64a48a9e8fede3ff807c0", "-154e5eed5a18af6be54c15de74a010f6575cb589c1e5c231184d04d32d5eed6118df05173d8e2e13b636409a20616e1ecea78b12f8b8ce27df1f772935e431fd12c27e11e9c75b4bf2655a10164fc72831d370e7d66f67f186bf586ad2fd6883963fcaa1de9d85842839b3bec978dd17c9da7a29def72ffaf9c2830032eb8e808378f77fcdede7eb0904fed0a5ca90c4bf528ce03ebdc7d9b0f1501fd25d7764c959f80ecf05dc4882eedb58e25729dd113e5069a6344596de5830bea53c9e32ce42e369d2a3da7c6e1ffd6494124b7ab789611db737b356c9e040fa6166fccdc1f3aba8380ab89c0f453fb4eaa928e73b0c0c285de37b4b75fc31304ac3f27bbbbbca18b3496417dc31e52a296eb7d21eb7dc4fd9a36a3aa69106d0417134e3f71039496284c49ba16fa6c0", .Okay}, + {.Mul, "a8999bcc987f3c3b03823d6302001f77badffd945ac56524c09eadd150255af3ee05a45955564907c184326ab28dff200f098a7e371a79d90de124ee3171aeb7b3b6bc9cb54e0fb9a2f0fa173003194a55f6a3e7960fa6e5846bf83708a96242f0a8be77bd3edb873b0cc37f30f719a79d752b3a00d6f94e3134ed1a1faa5d8192ad6e8dcab3388bae33cdc3b0028096f4582476efcd", "49262a393470da2a38cfbb56f9023b011f65ed450b0a20d848e277cdfad83ab5245e42d7920bb2381e8dfc067da9fa50192dce456775297d5dcd67e49294e3ea2ed42dc693d2d59d4ffc7d52b29670079479b95bb72a49ae580ab0ba2f8866b86580d7725eaabe09e6ba05f554033bf1b48a4edd73842212e70313ebcacf352310ad59eddbeb4709c8ae4db5004be207fb27258b4101", "302cf0095827b32aeebf838c6b3b2d43def3a6a724f950f619714ac41375ca984ef6bb9d4b3024c1094507af3b9cfabc7402044d5540cd8bab6b44587bcf3af21de0b2fd28100e0164a711e5a4ba4f136f3751a948655013749c2dd6a1fff36f43a1bbdf7b64d44a3336f47ef15e97a06830b43da9b423795f1c665f3276c09cbf7e6e50a2b7e2b773ca4b886100d3d63307fdadced7894e5dde82c152aea67c02a3829003b7bfd89c475f68088373844d8275e299739fb8e5fbc05a839b70f36801a31ff3caa34db5f0190556780a863e09c053be43c4930e130f5e75f73ac9e247fc9bca9a35ecfdef52cedfe0bd03fd08fb5427ec0050bf5c3a81b96b8ad9f424d448c36a79e05d24e3e18636286436ec5d6edd079d36cd3e7eaced852cd0665adb20f199da122ca8fccd", .Okay}, + {.Mul, "-cd5666373273117f18da0a79dba4b2c85c8e2b3162fe0a407df7fc7aebc5304cce1912d8a6f5d88364fc5d04250b5f76cf4aa719f0c59fe94d82299a2f4f040c8425ecdf8829e9288bc638093e1baa297484d5de95df9d8baac324b3205af4ebbc57ba3686dc1e6ffd7fe8c3df22d8889855786c64b61791ecc8df5be7fcc1aae7be7be6c86fe6c8e53722921ee82a13f28253031cbc", "b9e19a2aca0d4b63ee51f84a91bf01d08a2f035fa9407c2b5b41a8f25a3d5a18412f2eca5c094b26c88a88ad1e7e8238661272f77ca9208df7a31559ea06287853fc588c07d25ea4f6948fffb2ae0e407d7c58b1e316e4478f7bc977e8394090e44500bd5de22eea26f187541f7955c1e1740ac9aeff66b3c41030e21eb23f1a00c40a4bfa8f37c1d8f6b87559c53bf7a76332196265", "-9518647605b34eb1ef31de4e13db8129192aeea47d452dd9768b618947cdb260d91a3df1db26b5534f8444a591f47f7effdec7e85e4d1d7f99838d1957ea0d65587f2e268b2806e1301f2121c541c641d23610613e245d3e39f97686f6b8b8aacace9efd4ae7a3dcd3af5f6a73140636aa7623e1bbff9d6e493fea7fb4817c11518a6065795b7029c10a7b657931154fd92a8f70d09fbbb8fe64acbd848e4a0d4655257cff11911b2e4be80bdd540adec1f30ae72d081611f422b232de0c8797e2ac3a286d8d8102c27a9958cfa949f6bfb2784032b209b2ebad38a4c086d4d1dcbe73878184fe380c960db0474c32cdef87c3caf88fc676c53ea38a3cf5a11f4088e953fa8794ef3cc48f6afbcb36d87fd46b01b0dc28c57c744a61655e648a767727dd8efc08d077964e2c", .Okay}, + {.Mul, "4d58ed38405f223c69ec1f5f10b34cc0ece26e8a968549eda9ef4ab606a0ad76d8e3e9d82cf0c5e66197ecccb2bb1beb441ddf27e5e5f8cc466ae70987e601f1bafccf4ad5b89b81ff884475cfd01043cd6cde65e81d47cdcae152e2179eafcff25dd81d999bce7d40ca0b331b36f7e5fad1eede1e4ec24aff6ff4fba85beca97433b4156cb187856ad71a82403460f209d71c8544d3", "6f51305365a26c379dd1e5e802fbdfb7babd86ab3928838bb494029da348ba208b42be72aab57321b27eefb11b161e06b9adc4a91b32371c9f9779484317f024f558e16fc76d358b7fdc701c9b7a865610385137a454cc8fc52921c2626950c7e8e317aeac55666f7106d35e6d1f4c6080b48e7fe027e305ef9f1abfdead7f0f4c0b0ba1ab3d7254dd9baf17154acc6ee941f6769a5f", "21a2169851ba3bd05d2a3e4209c10b4a236600ca93a1cf42f618d6fe0812821fc412196f9874181f3106369e6ff34b049d761dd4539f6c829da1595ea389f3858ca724d7a7f95e9e1d5fdd9e621e57c2f4d38de41e68846c7830b9545bd6e8e887b2b55b91f5ed344c86cc8a1f408ac0b60fcd735cb4539d58a2e08f364007a946b474c4da4b74e64b99a3dbf04f55796fe193cc0a1fc87078a4e64d7841ba6fc44cc9fe07cd3b047790b0504c124f202ccd8eae7d465449ee3773491eec6f01491ad002bee17dc824ae273d40a0d81b754e8574067be407d0b19d4f0ee4d546fd9f139806beca10965385c4303fec6f7b578f1d7296fa374f11214eca607744b237d1aac1c1a18a95684ea64d6ed7ef95565e24c103790652b59e86c69ae92d44f48b741270c81f3c1d784d", .Okay}, + {.Mul, "b00062ba181753c0d627e64d48de8935064df280553d8f43cf5e5e0063895351fe92276f69490c554cb1878b1c1e6b84083a1007f73435fe33314a1607ce2f1784d7cfb7cabe5365fb06f177cb003d45a911326c5bb5823999d4b5b6fe8df5400e2ac9aa2ea0ea56e5ca613f9928b1489aee7d6185a8b982aa95a95d5f4115e09f888011e3bb8ea644ade26d16839d949ea5a6e77c5b", "518428e928275bfa4b7cdd2d3b700ce7952167f97b0fa362e6db6fc6d91caec0640440dd933baf67bb9153cd1c744877cd951cbd1a5322102d8c7742109cdbc22fe29889e058dd8e5a78e2616161e3f1dd11e65bc4fb503f4282e8395a5aede294376d884981f8bff980a9437079e3307fbde79463f7ee8c14df607dd447e9b5d53ffbd9222e5ee06bcd76df1ac859abbd77dda7fa6b", "380afb9024f5db631afe3e85d4f48087d953dc01ee27e44745c73095b29fbbcc7cdfd3d476e005f007eac00d1bb5a968ca2d74676ef8bb7afda41d8b778020425861d6f2cace9bb80f5f718a843abef71eed141799eade68e06bb855e938bea322735e399c9b291a3842252fca44ff19e5a6263987eff3da01f7438b7d58f1e6c75d6c2ac4752a6d6a0580a60155075fe1439276a03fd96b19b8a27583586463c083233852dbd8e0574529ae966b23f576d0a04988b2facb4f9fcd2c66336cc31c69955b361f79142d418157408e96bd87d572022a36616116b7b8588905bc50e8c9b468f22e1c9e6d98a461f577791c71538cda62c5258710c1a6db8f733d459a0478d20212358556c353cb8f217ba6338c34e318b7fd1a6ed3e388e1eb6e8c301c70fbaf64c8e4808ed809", .Okay}, + {.Mul, "25617f8125e004d98abed16e1596284bbde1b442e8ca6b53854491767fd9b7b74c2b2bcfe1b6535f4daa12ec33684cfe1e8413880e8c753d87c008b9cd0f93535c14168fde176370b2621cc5316d57eab1ae2f912fb9c5fe70aaa7c4fd81ddcc4a90767d3013e1e7c3b71547be886420b38a4aee9f8bf4abb8405de19a82129c8408a4f9cc1dc438fb4094f2934c2aab19e1fd53bb5b", "a4d6a859fe7491a8325e37a5576a12377c3944e88156f72a77c3fa94962bf817b6b5172c79f85d015184045842bb913b6d6b4bca556c75c6b4700d80e60987264394b2de532d023fc9c0d22b208e1c4b8f7e73fe5e33549302e2b40e2c3d97a0cb5bed4a1431391b695dd8e95faa57fad9e48cd66fa9afbe68df781ab6a2b14eda6e46442d7e397683c0bf4d3918df6ce2354efa1c35", "1811cdc471f303154b74bab6f7711952f58e8becc071541317684b3190ed1fbfb18f630a12e837980264967ba20624dc4a04eb7af71c8f4397329bbf4edc5cd4f75a5879c0ddc5a0c61a5542e36b1241627796c45d295b0298ed3af0f2daa6df53738058888fd1e3d208be67560af43fa1495772979777ed89d5d8daf714064fc1f362f8bf4d265d8dba7ba2042e496c3b0e3b6be5d3c1dd417697a5087a6fe6980635b3c2400f253a14e3949928eae2eea9b493f4a7595145b2e9812e914dfcd500714d36552278e3e57f60eaaed608d05e8fe00ecae7a6d82e7882674577f88aae123e16df92db001d1c770831f00ab58d79ca886ca327a23aa7790a7c356a396a9d5487f0bacdaef1ba645ac2ebc6b14298fbb4040843063c9bf953afb968b8ef20e65b421a304bb1bdd7", .Okay}, + {.Mul, "fc5be50ff14b20b6a09ca03d8b3cdd35f86bfceb91682dda1eea03f92e83c8b670ffb94d831a611834f1e33c3698166fc9f1a34f10ca6cb36831cb9646dde25b6b2e704ad1b0345f2a615c4b1958e2be1ce32b9c102f8513460aebade610eb84aceb14f68c9a52f3ecc63a38c8dea904e0279b626b9cab0d385d130d62c57fb7825c6907581dfe40b07e7a568342fcf77e51066ac81d", "1963b5275f5ed883039b0e6d4fa625f94a349904131cb50966427895d19611b67d31b1ca3678228ee63f6d281ec747e2c1eeb8e94dc825a2ff6043f3453ea49700e9ed67e0f65193c4048be0928fff37e420a6d9e7562e74ece0885b5a3b32f6ae444215e5ce7fbfb35a2ca34dfe5033b0e72f1994d1d46d8e277ec0ba525939c670f717ba987705bc2064553373c04a35cb7394db95", "1907437becb26a751321969e7de92a785a1945e6c2aac700e2a5e0b7623f1071682b21158411564a82b9b8c9b25224910bc5fd33309034f8f48186f6fcd2cf3811c50c04e98dc593e13a27a088b79d34af32194ad2f643bc5f733b168e5afc0bd62318eb5b1078fbdc6144cd980030233f9ac1b98b5ecbc028a67caf352b911def1ac5e917cb544bb599deae820c347298e773c691953e5787a3bd0a44e6043929df290b3770bbe5459d0c5b7c64ccdcc5a98132e8a4730b386c1b1720c57230c70a964957fe9df300d61bf32c068af03e077c8a2eb4321c3eb0f89811bf5daf6cd2b26f919b2954f112b55720fbfe1abbe8d9b776feb3bce4e20c125e513315803b8e2454cc523c308fe447029c0883126ba9ba2f9dfaf883194de46c343ff23c1caec72c523345cd1b47e1", .Okay}, + {.Mul, "-d19b1bc03b5587828a1bfe8813635630990221522cdd5945bd81abdb7927722dda2886eee6db730a3f98cc08c77ab5d58651029e941dd1c48fcb5329d52a062864ea41f54fb4a94cc7a8b98f59186ba4ba2a205a8bc1f0de0af8e6b17dd5c732d1146c52b8538b23a7dc34fac36857801f710202c315f725638f72f31ee8d1d4dc90a5585902a1bcb635e610d9d9bb528eb476a87b61", "7a74ffcdc40df2e6e496202e943877c6bac41e954f4caa0efbc50ae7f010c36e992de080a0b7a903f65bcabc74dfa88f81c196a579a97dfaa0b6130b7e447dfbfe693147e70b58c7800269daae7225e586fb6e6d28ba3e4d13d92f336179055a8c2e56fda885813682cbd7567b7849d206bb2e3e76f5bf8933925f019cf7d1fce5407cf280e6d96f5a45c5c3aa170efd6fad410d9bae", "-6443b6f429c186609560aceda457f34e60cb2bdf90fc7a2b08b8bada36e0a9be81f7652066d69ddedfebcc58c1e7c7cc5dbb6d3ed23079ca69c9e4c15d3c563bb86243976aa6fc25353804a483e5f8b173e297f8f09c4375a9b21c38ddccf509ee4f9adcf71e6fb486b67f38e3b8c1fc89d1df0cd77225b6a31094238989c6443aa869eebd6c3f992b5320ed5d7fb7d6b0c785bc0a39e3fc36f3c06bd3a839db0d6ec16c8de1c12852be64069e875b445666897dfe309ed2e87ecde80fc904f35bf368ee26405f952d02271ad4901c0234511d770ec24adea1d845b9f85195cb1383056f1743f520fb9f153fa44453a0c508182c85f6516500dbb283251fa87bff7095282e7c97ae93b05f35781a6957a0ea3793903c740762b5ea1b45cfc34a606f0a34da067fef8e2496ee", .Okay}, + {.Mul, "-a0a96692dfacd9fb362f94ec00a45c6f307a9d0d6d902170cec3e2dea2a73fc143df5e4f1038527b7c5ce4616bbbe356a3c2e1a16e7e6802a57c0f9bf8f5b2d7a94b9bb1facde8271c5caa83f494b0c76e2f61a5b5b079206bdb11f5f27e52bafaeae7b3bec8f135b78668e674285deb661b3a26da665206681777a41ee8f626bff3ba5418cae4a38b987f78b09f3312c5060f36b152", "2e61798a128fbab1c4c5d34eb33b73ac56fc2740593330b9ff6af634c6ea5db35eacd047ff5de3532b1ce53d742ed1fc24f4f468d8a83e7dffa3c8c07598f5fcbb9a1e71891ec285712a5b268b3cb6f3bc3a4f7bd566060494c083164421dedb935b5f859eb97c5ab4c80736a08e9acae62803f0f085a6819400dfb6391711ee32dab5ec7848a56bedb676379f1f265bc589ff64c41a", "-1d1b9ce4fa4aa390470ae7449883fbe423f83193a9486458a804fa208a9ef8229f6b1ffedb55ee00cae857871170bc39d437b1276774044b09748bec09e07af1a874525313836eeddbb5dcb31f2c84a38a0a456d579698da35c25e77b1266d44c048b056685e6b051f030172fe4b3b359a14385dd58eff7c510136acc74a511e2d0d5db08e29347e3242245412ae70a3e4a7b55100d942850d2b852855bbd7f6d6f5127f1365d5baf512713dab26cfd75d6798dfa672e9627d901affbd5a10414913a7fc3141bdd310b1d6080e5713d4e3ec922d204293bb6bf76146938241bb524370be7714d6559bf420a96b8aab107579f1f326828fbafa00930ff7d4f495d1910074c81c8b7286333db6b67b665bb3a4d80f2211991196d5d9ddc0fafe8a55fd807ffd2511235d58ca54", .Okay}, + {.Mul, "-7cb09b5f56a61b3c9f9588bb2c80e0f180d4c8ab86d48f7c693c05ad410d6e625220c2ed916a903a3009687a74e9fad2a28c1c62c6e14f5d7be87d70b5cc333832bc123683ec94e6734a743284860e6c206945830ee07360b8ae6c9697bbe3dfbf03334440d43a1942c2aa805ef9b9108218dec2044446bc4b05bad30865ae1b3c41b25f36808a9c3e993c092e9bdfceae984dea74cd", "680d7229c6ef3189e1e930fbaf8e61aed92f2ddf52e65b643dbb0010952655115efc1be43db69cb10f51f91e202eec74ac31f1ebe3e89357eebd811ecfb884f0d323116abade738d1a4c2aeed10421607084ddb842382975758d55f8d73f961f9def740076ab80492548c2cf9ec6371519f10d03a4698edfeadf76f27fed0acc7224b5125f7e910aaec0a3fea128da7b3126b900d852", "-32ae4bb19d6951889cf3c6d18547d5aa1afc8cda8a33ea20458d97c2f65bca35ee95f9e7475f66746d0832ea1d3eaf0c0fdda72c39d22b96bfc34c6c962e2ba9a3c3f84a3e5f08a8149fde28120d4387190117af59176543f4c27ee23ccf9a9a86067117d4a6a4355741ba492c8b00b5f84dcd278f66135371e2ef2e6396f10198ffa7fad6023502a768125e2535b32a62d392ccc205cac72c2cddbbe0c206f1c711111287a8f6f10dfa2a45990ab7d98d69a9c2c1fbe154fcf35d6024ea03729fcdc642be3468b509ce046e6a9294d736e380b189f6913b99c02a3c03b4228e4e876c35cabaeee3f52e6c0ea1f557c71dd17d8f3540de1a3d8e68eedcfbcd9e43c935334591908db478985a1e563c3fc83b95bdcef3922afc65f3726512dbec071e249a457a705ceca661aa", .Okay}, + {.Mul, "1afe9cbcc1b1a6e4eba2cd72e02f58775aa22c85492148364d8eb6ce799e03dd7491e412a3a9a277708d0b94e460a346eeb0d9f197112b2a0ded7fa0b640792ee048e4c6f09d2a76321fc2dd4b7bf4b39237aea032decaf8f24ea10361f37f5c1199930100ff6e16fb527307d140dd2832f2641953933f8b43d1dee4540b25bc82dbacb167ace1570a70502c4a274269aa3e7566ea1c", "a562e16e5916455de329d12c92da630e0a70fce88aaa5f66c7ba610a67b330509aafb09693649efff4463a7eda0eed58f9883a3e62e6e38c915b0a9e92845fe41f6b103fe3035c2b9f45170ab2f263cd7450b238a04c5c4a45d41aac7cff8cba13deb766a8de37d55641db4feca498e35dd038f9b07e53339ed42d4811929cf4339a08436f853a491eb8b03648dfc5e7bf85e52a878e", "1170884313a7c39b6bc873173f4c964cebc4d28bfb1017e125496b8364ac9f51349fdfe26d19702683748908d1a120efd9734ab183ad2a7503781d1a1df6c365f3204894e9df6e04e4da685154e413e8e260446e4f8e6e5a19b98def4127d231457415af05ff9ef9cadf2267e410f5f1bf9a2240225e9f34bb1e6dab3189a88691cbaa9a6f7f627fae0ac80c072d5f35aebf081e4c19d6fc7e1325b2e8ab993d3afae4a89723b3e93e683fd0ee317e20a0538669afa2bfca3ee72fd75beada4766fce741d267c1bb6ff17ba8b8b076f756e945c55f36ee6684b26183960951561d471b1fbb275f7b6515d1bcf0d7dc21fde3099ca669993343cd5c98a9c64feca89be107df288639a0f74a60335c3bd7307a7ccf2e4f51235d0caf54dbffc6affa893cdfef0e3567d9229f88", .Okay}, + {.Mul, "-56bba34281fe6efc2e4cb08947018c480f4618ab43bb97db6965a37e8baacc37e73e8a99bcc83a0e54283ba6892067b4aea05f6cb183dbd0a6f71fe7b3af29a7df2e8d7cf9e759dc5d91de25a306d02d24d798ec5d805d863fc04ddede3338e5b4096c2ebdfcc1201c252559ba41bbbba0a68223a630676670e285ae53e27f6bfff92ff32dad205e9bc4977487a6f9fd2973fbdbba40", "684f6629770d3c967fc63676917cc3f203ef94e91ef1020a8c136719a326f6678237abbc6dc911ce39820bd683046f32b20173c6c8daabca5eac271c8a55233be2251ac6f5d72bf48fe3bcf41d69e558ecaf045b18a2e4766900b10155831515a896ad04dee9de79121fb5cf10ad2f91f8dcf8539087b4a8b93fa77b823166756a0c38af09671ddd520f46c532d452a6fe68f03aaeeb", "-235720d735c4d4ff10e70ebce5663dfba37cf41441a6a8a817072b74331c092fec91e19995790462c2ec910e8df713a41d0c618a3607862ff4baf53671cbb8bbe719c518d8a6d6d9ede78984818a1b0a3884e4062d900fcea80f341c2d51ee550382f7180079c616531fa2647e3cc1f38ff258aabe10bd0197bcd319863baefaae7f671eedc465f21687dcc51af17a66c9b6d73d57d6899ff78e66d704d1209091c33f0d3d175e2ccbbbd066363c52eab2d3ec053b33ace4c8a575a7af62d48a596b4a13a6bcfe50301497b420aae1dac7742154e921d69b126dc2b0f1b4137c2026f73154f8c011009708214ce981b183cfe2ad7be7533496effd691c2f9b38c7520a5938e72dad1203c6c2e042a8cfec8e3de18ad9c2aa392421cd772e6f4b97d0588f47861b0bbdcb78c0", .Okay}, + {.Mul, "5eaa54c7b6e2304cae438ac714febdeb1cb49b7221ebbd5c44f762f8fb938553c00c1fa35309b83d0d2860eb84c0d167bbf40cce064733514084afafe099de5564732dcf132f7d612d03d74e17a98e2639ca1531754a3efecc94811960f5ad78bb9168308afbe11ef4d60a2fa39e343225d7763e8ec17d1e8c87e751dd2a2d336ebc22bfb6af449327626952051af9039245e082b37", "3f7c0a70c45bd5ff88004b0301b18718d4f457357c47dd4f4492c48248a71fb7132e7cb7dd5ac512b57ed498ef884bbbac36419e85f0ef19d087b44887a2b466567ebab85c256ab57f2b05b0943fe4bd8c659a8f4e6a7f332811cc52d12a46cb255d28eff5071e77d6dd8f1e43591cdf7b0fa6d47c168007273095848c1db0c6090fcd16fdae4da04592a34c78339f30c09d4347464a", "1779c93a912f828e5e618e7b725ae6511200ebacf2d9504451d219a6bf2be3ff182ab025207b92347169888f202ea7256786a2f514011572c3c7dfb43e4ccc92c678d3a8342ae8c05e8410918f7e4f1fc461aff156303e150c0de16f9842744b81c9cae0a0b8117bf25f05020e41594ab6d057c0a5d629e69ab22660a4b8703f1d5bf0142ebd281f333289c25a52400b1d1e22624aacd6789b8d329dcc1021f63dab16350e031be330767fc620b094eeb0991d22965e93b8bd942cc4b175166b38c83280334a8716e3a5257b8b7260be2f1c8f9f2ac4c355648db2b697c885ceaf5fa02b6f98d693ecb4ab82c0cc7d399a5db771a656a29dff652a3a1b7651f5ab4a1b70894204d9e39b34ad19369dde5550a3c798ca400057544fdedbe3873d24987ba9bbe6e87cb6e87e6", .Okay}, + {.Mul, "46f6a4225eb856203567200b7ae7a3bca705b7ed339bf3da2fdc9b2d225dcc5b6d0f7c456ff4be48f3c1557ca7dcb1cc35cb2179ce15ac92481a527b1cedba6b64a4bf094060dbcbb71cee9711e669e66fc9d0fc0f2eef6360b72a47a6b4f488d45aab3c40b60395f8ff5bfb31092e0b3d2ab8fddb60ca8ef5e9da8a3082a6ec5de70f3c5893e474cf5bcfebe013af4ff0db6417dbeb", "c2c9c0ade9dff0b6f798ff82aff8a0760f4adbb871ca980907fd48c289da17944e8b3e6ec77069a1c1b83ca39096cde749b1c4295666ed61ed00ac7b1acfb7a7bff5123eed3f6349f350b56ff09ed5571f00cbf1d962046f22b96f5c077d6fbcb625ae7adc520732b61c0dae81745f34f4f84972f505ee6a2c5229d9bc84196d7113cb18be5caa9001812268065cea2ebd6089ad1fbe", "35fed5721b5f513a7eee03e74ea64fd19fdb2ed40b99af68646c81454455f6748c97dbb432d75fc21ecb004f396bc1b1833d2ce6bab76335fbcd533c57a46cc99c6e60079785de4b24b36a693cc584ecca4a21cca0c51728b0b0437a51c54c3d09b10132050d48ccb55f729eac61b5959ae51c64ad790a2f574007f98689c0e197e5310e4ef24cad4aa6796e34643609aa899b5b8412d4adae48602178966329cc8ccf13146995956ee47b7bd861ba013f9560bc9e66a3be27cf8db15866fb0d215e69249cd0dd54bcdb7d71a313e2f2f63f8f652158951929dd4e8671437e15f745c9113b15cbfec860c76141194e9606ea1664130df0b8c53f0e91813bb5fe48221fc1357e995b20cf27086d5e98445f6b7bdf7fd463561362b3fa7ca7287a803a92af70dbb3e38e25ad6a", .Okay}, + {.Mul, "27f25bc8989c8d431f67e9ace636991c71d2a00f0e9dfe978d13b873ed0b7b9ee26312fa631a3ebd53c9980764fa77a7bcbcba10d26d25dc37fdba0fc05783a29b4e728db48d78bcf7d1c29b90131c5f57a1d4829984382cbed29a1615e383bae5f3bf571b7baf8e6941502991913503f07111fe1445d2f2d07f86567e5b2112202fa6e4b47aafb50241cde1169da17175b44c4d9838", "82e14ec549fee11420c539fe791a783aaa6d59f8e235f0dc54f80f7d7e8f126eaf48fe9138f737cb11058c1d16df7e152987a9470c391040d549a4f3c019a875c7defa7d4a39169000771e43ccbc03422a2e350d0b88231fae4d90d4b085cc599dd4cbc3ada27556776922341445cfb3f2456723e9ac5511c394690b1e2d38e59cc2fb4d782a8519e4df8ac5c69d07188e56658e5fe3", "146c3ae929d142f3ccb822a73335ce69028d463e3b12dc99201b43e7cf0f21757ba61a1e0f138b1d1ea0e7cab1ab436ff8b81988c66615d8912c9a5e63766008782916d7b5db825e2a9b98641cc428a728a7cc150c289669afbcaeac42d946c25b52948c403928b5bca765bc46d0e0c6a6a6075160474eba44ca12a421da38b83cba9528713db335e1476736a317f881e3ab3dec3972210568c45f0ccd2aa51f45fe38f11b9c20b1d069af8c5793d75b3bad49eb1ab65fee6d8026f95612c166addd9ef2cb2c95d8903141189196fd4058f9554f727705456cbc624c7665e0a293bd1595a89484d23d7e3cb8fc1b1fd101779e5d9eb2f15b9ed4b57869ab03e4102aa8424b18b10f0203414c204645208d007f9a27e250a6f8b56f78b38c590616eb5abb28266a18fb5ac1a8", .Okay}, + {.Mul, "-416071e5eb609e95d08db0eeefa45c854cea748894c91f94e03865a4c418e46b7738603183026e4f127c5fac030cdcdec40e95aaad93e49534c2b9150a131facd9bca67d38e79d2440723e9f045a2242a9e5972e45a9d2ca54794f956da28eccf0c98f049745393f356eccd1f6aa94af80ea7c2dfdb61ef315967d004e52afed4c1bae50e7e96d5385b629044c5f939edc263593c051", "19f29261cec54ffb8fe030ae1dfda9a2ea966a8159820f7c51ea986c8a53226893cd70d963c4bb215d09b01e59e5bab9bbd508950935b9722ece1e8b0ceaef26d46ea747037fdc54703cf9916a5c29a40af03c06f4c36cd760db0747046269ef31fa39e2d9dd1880aa591a704848168a5e3f46d9c88da72cfbda03d54c4b42387be39854d960e694699d8d2912d169e0c2354e8dff89", "-6a05dad1aa338797fd425663fdf475813ce12706687963f059739327f33994e35f9638e41b0ba5accc8d98adafeeeb051cfb056785efd4684c4400ce4f378ab50b5470b2df49068b7e65816bd7a89f74d7107e262d5c04365b13550abf80df844d2a78950a99c91b7dba242377116a9ed15556014db7867975f09ecb39ff7ff1b591b4415d2f5fb751a0999833d0cd8ef3531e4393b80ed617f700e9986b6bee58b3d79116fe328a9403105759e5d42555aea8cbec2226a12ae16bdf4eb0d18a618a3b891962cad5088aca4bb7800ac1537eb0f77789de333c05510f84c5cf1b012e2341a9c8839d5fc5c65f9cd436352852ecc7be86fdd02b9aab294d14f480257ccb568663129333c116aa6ce199d4bfaa91c239c8127db750f8908c80428363e8091b1e0998f733f9a59", .Okay}, + {.Mul, "2a53bd3c245492156404455392f9865f99e23f8d0f3f5b35d46012be560ba913926487fa803b49754ad1f5a1753e95b87ba80d6e03602a1c638e048460de99e4ef184c6c818b8499ceb987482a7d1defbdb7aa99ea86a5016cdbcefb2e76445322f605b4e907e77b571bfac4eb1f23bbc6acafedab51747b26536ab56d98c08251d0c2c035182dab61dc8e0f4c57a74fb44c441811a5", "c309e9a594578239b162528a8bd4e6fc11f7365fe62b50f758991314dbdfa7269d7a0837e067809102d55e0244b799a30cc083f521097548cd2cff7d181093ee07a838137447863c75999449c68f8b191fd715f9b2db75026a12cb9e554f663cfc42fb52593b7bffa0a229e6df962070ef7692ff9f8e12223d7841348e2dc2426c9b181e8176b5a17b4bd22f2d32b8a6c75e2733dd6", "203f6cb80e854877f5ea765a3fdd27915be70a73319cc5f559c301311b53c330d6ec46cc1c9caa9a7fcb268694cf3c1e3b1f61435103977d0393c3fad1ae4b6802011da488c86a21fa972a97d939b7154bd1b635b4a9a68675b10b16d9c8996611f667ce378d93438ead8045ece0922b57edfc388fb1308b307b55440c9553bd0b1dfd3b5978bbd82ae9eb8c5d517d70b3a1e3df20b6d73196de332eb64f90ea5b8762b808e77313ba4ac99a2315cea4d2e83ff8df67ee7d19455fceb9900b9703d6828cd382c12cef552d7a42ec6fed975571475ffe1422dc6116e8ed47c458319e4789e1f5382fc21a122490c11e2997b090234590935bff3ea4cbb4ca5161fd5178d3482c04550030bd236a23860ecdf48322f2dcb3a239f77c8a5acdfda348812a1ad5a66c73f7210ee", .Okay}, + {.Mul, "cc71aad10e8497c8ffdffe736dfd9d10169bf7346f2fa9eb4b8c00fada5860e7549d4fc870425d87a6faac076be0bb65ed67e561161be63a8dc2df32dc7812f302eef3a87ab369ef91970bdcd30b204e13326a1337dc764f57f1a6cb0af9324030464942089d624fcc25ee44ffc576da8f189bead767a1a678567b3092e3d37bd1b7becf07f38ccea38615e3ee0f092f57b047f55523", "d86658a4a348b69e332c11b79f559536c60017b045acd21efef27f5b0cd93476ab8c8124b1355dd861f1f9f877604be46cf779692551dc8f6e0447991e5efce87f2288c617ce152b75d1b3a2bb68f9213966c0443cbab1bb1882c0fa07825690ff8755d8c9faa77d3ffcf6047faec9e93d80f91053ff83676a4ac92751a7fe1b7ab8cd7610fb0554c52b426e553c87f7a99852009168", "acd1a435017b65634099aca9c99f81bccced99511ad071844015ba86097e8f6915b34b14ebd83d715c57149c6b7626748dea928928f35dbe263f13f4392ff2a2fda1f536ddfd9b148a67b3b508a3af0cfd2920f507151b98b43df6f2d3c2eb452e632ab6fd4cb967ac01d19fc05f0cdd611a42d42c331c6f9ec3c0f450063d11467cffa1bc274e938a2c7d9e44fc5ba7665f1ef45fbebc19833f43cd0742b488fb67b8e9dd8cdfe019cf0b8279efd48fe3321b2ab3d28b7da8047847fe2f1afa7a141f82b1a7873d3b213dbd1cbe45d62e00befd4a617e1901b2f50a7898676d87995313f4bf498b15f38424998933c45c6b236986561dbbb04032a9baa28a869e0d61239360ec04aee29460061f1c67816369a4ca91eb099e3cae94c622f97d033635604b96b56c66e36938", .Okay}, + {.Mul, "40b6d5ea3d3bdaad2568e66c3912a37f14d044f4dc6bdead7271f4fa06c29cf58605a99fb422e546927200efa216491ceb97399899334a7b1549f4992fcb9434a30b8fd5d4793dbeff32bac2bdfda790c1e1903085f566ffc77cfe490acd024cb8a0efdffbe33d7f494c02635a926bf92bab5427dade79f6ad8a3fa45e34acdac1087cf575884ab7d4cdab7ea3f8ddebadd0bd0846de", "da87216ef08babf17fa63a8c2187a8733b19902a02f5c775e8341022f46bfd40b136990b2b989481fbd2df769a26495f4011034981b16d8496573444dbba3fce71c49a782c7c3601dfdf33b92e1a587c78aef0131ca93ae45afe1ad63df65f23cdb21a8274cde413d0bca09f2345e2d972f69f7961ef83da0b0d35a95b58677dc9220855f5b06063d847d49b49043a8b0983213f1c32", "373ddb07e39d169bb6f14529b7256bba14be2c7fda1fbb4184fca608fe528af485b0df3aa7b6fb874d9b409c831c1ba53778916b31a8a491fc06eddba89788ac1c726603746a40f8805e58bf30e726cb705f9b3d49f18a5782515ea512e1c0f1354598ef06770079c801075e386b0b8e93b9d83753e4f0181ac2d68c43b1a0d8d7061141c851ede89cf4bd4c29b4fe10ae2b4cdd64554f5274f836d120697ec9056b2d434675deffb50294b822f50e6377d457af3501202bba0e6024580e51bd81b40bdf54bf906d630105585882c6d45584af271415c32e0c81908edc793d3378a223bd531a90b877e223e91d827163a01516be6bb4d360decc2a5f30a6d1adbfaf5480350f72e2d2655d9cc8ef1de8d954cfe658788650ff18aa3f0bfda6295c2672c39a0b6f37e2001f5c", .Okay}, + {.Mul, "-58f29a32aa870abf7020dc38feaa1c21b94e1f672fcdc49127b960b80c9cd9ad00c430beb2500ff7125da1c5901df127083d19600162de4fd48e51081919d67fc273a4c1f6c37539dff306e1b0231afc3356186a7253f9702c04cc984b4b875905898e7c982a02d52870877e1bc9fe6cfa077901cf0ad05d934f860dde50a73e38707995a72ccfae941db2669fc9b96241703eb54c9", "625929f13c2dcf0525a8c75e0c96da8876749e3a7b76b6a294ef93d05df5f10264ce34f0a29d4fba645cb7a512996644ef4a7c58f44941d21e7ccea0efa28427af915a0633bae2180abf79e39563b0f13b44eaa1cd5215edd4b239c80f3c5f8f96b289c3c37c56761983d336779e24d7dc93bfc1bc036221ddde6c4c4917a52364ee9dbe13c95d970b6316d5504a1b7ed906ac14b65", "-222bd9f1ace308c91eb5a6ce42fbbcca8c88fbba5c8d8fc32b8809711d14d81296f2d8212aa734e7b068e7f092597ad823ce3b1c0e257d73fa9e45c7cd9fc9050642bcdb28fbc52487ebe7d23d1db29b95b0aff05cc64944e457b1ed22be450c27bed4a104931a14c00c6dde1660542df0b892a66bc9c8ef3f3fedc0930e759961cc90a8338509667f869b0a5be69cd8e9fb528a0f54ef42ff1c9cd4d64e75f1f7804dd2182a70699e61629172365a72a7a1ab53946a25ee506a6b6aea3c929e1c906d006b8e4db54070cc83be0d0defd0f8b08d7facf945f8df467c811be72fa0839b840adc53ac6e654ebb92dcdaac758ca5d098979716e1ed053e59e7771e357bb45e8e6aa332c59b5269767f5c8344c27e8f26cee6917acd979f87b32cc643c2a4325526d0a338564d", .Okay}, + {.Mul, "788ff50c41b1004495893f753dc1594375631d802f4a155ecbb876812244617ac3907b9171f37634a9abf48745f15655bb3939ef7ed5d4e75c8f9dbd93f6048cd41b01bce7e9dc28573c2f3b414a1411e51a2c14eebb827708a1769cd5b8af5e05b32a391b7bc7b7eba2039061ea2787eb92a0626602046d010e570ed31a063c418d98d51f68c92552d4eedc98dc08486af1e4c61ad9", "5941b0b7165ea866b14105fbf805ba99a727a5420bbced163b2a8fd9e0b89c2814b24ba984ceba4ccd824e2e7845534065ff1898cd7a1555225fc5c1e61627cd17adb1de5a535c22ca934844789f04d1a77950b4f8a0a20268af6d702117946fe65e36a854a01f2da0ab3a82134e355ea1dac055b83474727c902a6d40d53b04ae39ec5d8fc070687f60f826e79648187971d303ba1b", "2a08fbf7acdcc32f6ce8318c9dfa66352f3d1f872b5ae287591ac44360e967fd08ef5da38c90b8165b03f61325d052272b34fce9f0cc03f395cd2730996965bcde4be5e9fadc7750e81aad5e0c6cc98bf03b215df6c234bdce9bb09dd7da913ec0aa7b85c5c3e7f5cf82a220e3e017293bab2cd40c2665c2613ae525683d2971ff68a47577ce6b1ed3c562890d6bf576a0a61364954328ffb4d46ccab7750095be3cc172e64dfa0bc83208460b61f1861c188c6c59255c6256b9919d9bd25384a3d2b093f676ff79e29a4109e35dc5ffae42211fae31bb4fd81ef4e26d7f3fc934dac1a8dfba5295f9062e6091cabd6a0a03ff54cb40bf5f2e15abf2ebbaac3998b617590e8301b5635ea08d13131abb009c9fd389afe2affceec5660b4c357191c80465483668f73bf17ee3", .Okay}, + {.Mul, "-43ffeaa74127b7100bf00956cfea2252c26eec5fcd669f6bc34c410ce10d410f00c8b942900e88abbd7e92b8d741089b1773ea43b9d6f843e9dcceb94b6a55a51c5ea7e9445d5c06889ddd346c4bcb17405bbd5e3fd561486c224887fda2ba96d10320933c8c8024a529bcede0db6baf8bc52bd870ff95e9432750ba567a464602f671c173b8bb81b6b2d873a806af5260b3eb3b577f", "223f979977149887b1aece2ae16eb5509b959e7d133bdfb6ffa0f1d308ec6a61fc90ebce2e775414df68bcbb4889c8aba083d22d77f52524b4000c4b20b30a480bd4ea7ffbc911e4a09eb36939b6054ff972754a3a34d5005c14c2b682d5fd8ab3324a20a2ea533f28ccad6efba95580417b8f73301f014ac85b2c632ab72b5ce851f2d5d24e67488d107f4acecd8c5b8473b21fb0f6", "-918e169accda3109f14aaf9b3cdca240d3fa89409d7db58ab928741c7b4a083127ad29e05cab679d55340bc9cf692ffefaf72bdcc9d5b2dc82aaa74e2ba4e4761b63fd77aed9a8e7b257ab5c551fa2b1cb374df86948edae6d80b340ae13667b1e09a7becf93252aab043528f24dc9796faa1f1c32bf1d3813b73b8a2cbee71f567a5f228a0cf39278de1fa87cf819a9da453e5b31b59fc0a80f35f8e717d32d63c9f48a98499d1a19d24b0e70eb4f6e0a855f5a5f5e95aad3863cb8b9db0cef6549e84b3b8691eb41f46495953be8c8fb772c92779c5eeb7cfb4ca04ecf75059c13de78f01a5112d6acbda1fa8fa98dff44980d8e2eb3f696a70cdd043b248041cc3f8b796c1f760ec6382743380f8a1ad26f62564d5e50a8812bb135d83efec791bedbde827afbd8e640a", .Okay}, + {.Mul, "-84353ee0ba4b75990fadef6369260f7a4396f36e4e42791565bf80d2fbb8b1009726a82ffd479209a7999f3c9c02f7c39e4652c910bdaedfafb389a18c5fb4be9dd0090efc6a8985f39e9809ee767cbbd678f86466cdc9de7ccd8c90ca14b5c17ac1cccaa4afa0fc2f190d41679d6d8db513b8ccf2a1aa4c888b812b974f76a0e8140ea79cbb2b6372bc302d6d53c4e4df8def32bf26", "1321306fcf072cec67984e56991d8a87530bee8ea808e85977f33ef2e1852048070a0908a858646947a4a6f9e4dabd159fe282c49546882416a200e2c2dd9bc4a38f34200a4131cd0610b57953f4c8876dfe1e5c823ab4ed540d284efdcb8ffb873465a81a81f8f7deeb20a6a5a7c29f04d18db478097d316e8c522626a318cea368befbb946f03607dd84028b6ff0dae743d95e0ed2", "-9e1178b8296c6531dd6663509114086147155e8ca49f7b1a0dbbcb48cc2aac70a0fb6a14309fe2f1bd3ad3c769a52690e0aeea1155a7c5185a53c8ef88d74139ccf68d00fa851c8d91658bcf788b63a782d547a3cc14a4797dcbc2903e180bfdf33289dd908b8b1a57f5a6b26b703fc51a791fff5e0ff81237d801c492c7d6e7a67d0ca59088e6e7ae2af47b98c2200a1c33375810f8e90fe0f7e63b3ed788ea5f0c351654dcfd1af0dbb2d4db0a161420332b22d0fc107be2da7b98f5b3ffe5f3c37cac30f14af9f659fa011a6386768b506ca4382def7c15d58818a532655b1226a11b190f413baadee8db98f2aa97b127db4c655b5fb26b2ac496b3e8415de31bf8cdba05a1bc67861aa737d0e307e8d248d24c042d05def8e3d505f219cffb9ede638f84f1e6408e12c", .Okay}, + {.Mul, "-76cb13777748efe8490381d80f263f55d9699a07934633b6b462e1a9da8eeafba0fdb62c98dfc11632b36a314570a7ade3210b73b9da4426368b39f42f332ebad2b560f888400ee4c137672a7d3b1b1fe7c629edef9c2cbf3a0f3355ec274fe832f88098de6b66264a26ba0334cd0dbbb2419c94d172d2eb9d280ec8123b91ab0f26f4aacd00835368120d15a98a266e25c20802f416", "798682795f24db437b0d19bf943892c59494f1f61f602e551aea8a859b2fce328713ba44ff3007e306dc7115b86b446a5a04d50e43bc632dfc8f9957d8f8a306d167bd71ce312b0e88c2a1a1bec60c3c79e97b203ec88d5824d8098968bc8df7a69f2900f22a50b0a91ee5e309430e4b8cfa272ce5f7d4dc6c0bc3110eca993bf1610eeb2fe998a9e606b9f9ac297af4225d10a4c29f", "-3864670b19ef3e23e55e03490c811d3d98145900213a6f456bdf526021a9469f9b0fc7aed1abe2a0c01fb355b19ba336dba2eb6f75cdeac6244388d3db43e3bdb460a19ea9cb0843cf6c25cbd5d254da9748f0d599200bcb4ff8cf8d8acd73b6cdbfb5dbffe24ff8772ad405d0c091fc92440a4e6a5c45a210799ea02e875138257e7d259f3b1fad99b5baf1152d2081792be3571a3defdcce3262f5ade0a52542666586bb3a6fb257a53ae8baa9ba05cc449aaeb736f7afd8fc6ec2e269ba30cab19d024b25f65e7f89350391c1bdf369537169f8314b9d4011151546c3a8f001fd29f26b076024e0ec9f8eab09dba0b04db1c1ab17d927870be2864a9492d95ba12d18ff35152237d349dffdfe7e776e8d72cd332c8c31d21b7486c5d6f01b697ce610164966b8f4e645aa", .Okay}, + {.Mul, "17d2042b34343f8f3e441c26f66273be29e751823dc1fdee002aba0b8ad094ec8753f3b3ff766b4d2ea1e3287b0363addfd6a81b35be7c1b1243c1e7ae0125ae55b641ab50240fcf63fd79ff1e04473935d29445b60f4d17c4f09bf1de4d1a291054a3468a7168070efff2878d7a6a249a7a1cbaa320070c69fd09f7b5fd7ff7f6ee032cb79986226fa8f76719ebc679e7049ee26c7", "d4278dee8428046262d662cdd0dbe6b8f44aadc7b6b5bba679daaffd045394816225dff62453e68c53838d3c6a88aefaa22c52b48ff0484bb18aa284f93eb3b15111edd65c70e7c0a689492ef75c219883121804729655f6dd220308e2bd636985a75d80c24327b5cc166f59e168398a1d09715cc0c4c9dfa57e2645ab6fb343b4019aea6a39a6cb754eb54a06a2185805b65d04b380", "13bd99a747a7e7e2fb4b96cc1e96bbd92024d5d721104f2f2b179bef660876c0f5212ce6b676e7bd65669fe4ea57d6b3ddebc0381b18f63a752d8a738c3c1875cd7aa5f8ecd1d90568630ae653cb4f780897310b0186323ab1eb4a1bd22cd585d82ae9626d1a856f6ead6a019e6aac799386e6e29cbfa6b2042f858326d1d4b9d88da3edb54fdfe9d3c4ecad367e3978c773340e448e0d06a955f3f6fadc8fc2c609ab92801ef9ab5ca9b69732ddb761473c09e6ebe317671cd928d75f65585fbaf7045b31c7082b3fd4ed514fd107d798ce5a46a1124d9475b8badccd1efd8b3bec5bd4d4a7a408f16aaf2cea7c4e94a37a677bd60027c3f69dd1aa493e98703ea3edae10004ebe7eb785f5efe01bfe0024076ed3602002eb3d77bb31db867390529fc1eaddc1f624c8880", .Okay}, + {.Mul, "-c307f748fe4ca6b45d07d7ab592ae3b980f31b29d026fec10ef829b2e845e1590dceb69d177bb4955bb4285941ffd1791c25db786493260a9c225bf5858633705980059bcae526ca9a7da41a5be8467f83433c54189b5d5551044e0416df6f1fbe3411ebc0ce92b2647b1da6033f22232df55f9ceb3d46ab95672a14284883f02d1f05853e1de25be517ac3d9c1b28317e335fc7a4db", "5a501e8b5e177f2e1598a160c9b54750689c1a79d72102ac35eb42f55996418ecbbf65bd0e4799db888417e7bc51dae21501f31d00429d224020c0ec7fa36d959a451fc72b85fd7e552f8c959095f68c1b3b5f1e5b71a7d8ee732ff9db0b99a29fb597c98b692d6b89e3141aaa312ef27b8a6592f33c62ad323f3b3b34f66f05e7fbc9f9c4393dbb3f6ca1ad8e21e73b3519d7f583c7", "-44cdd6b20c331066a4b80d6f8da41203af2a283fad1196fe069e75c63141d4593365bd9b94bd46ba7020ba80467168ea4adcf7e2e87824ac43b136422c4b4e3f4b92ec2e846f2ed2ab7b463da27b3441996c1cb9882f46fda9216d4e0f76f910e65b70a586f0c5514cf882fd7e3fcd0b4ded6c21ec873b3afad65156be36a0dc9eaf57ec5dafb540e3b9bafb14a9d9cd98f420ba9d1ec2265c54c7e5e789524b9301f37c1aba5885a8777242927cbc6a2c402ee54362ab38a7792ba148b929105db4bac295007dd3c762c2a34b8ba5bfe751d451cbb5e58861d69965eb499a65483479ae151cc05de0bcbca5aec9e6f9e854e38e37c598586bb24f964ae9653d26536e63ee92d08795eae93f15728a738307fb6673c892654c7a392c8af10f9975ec2fe0c9c229da5024373d", .Okay}, + {.Mul, "-1b3a21c15e19ae0a19aefab7a8b3beb063b190a64e7f6e8b2be0ba95ed1f88f4b410b431feedb4edb538ef3a3b468eeeabf7eabd4cc6c707bc6e9b1f4b73fc61cfc36415496188e7d5562f6095f695c195d3f9659cdf099c6bdc6a3152a764aef0289fbe4c0af263dc7f5107a7982c08af4122c8623c1e570f4191bc7dae2f2a9bf8b863e99bd35f9b90718ea9a9b936767d53f2441a", "a069f0534819b6b2a333e3a3d4ae79a9d9433999d072cb2141557aa6ed88e9acda7ed03e46a12823d3b15f87f736c14373fe0161dba8b1374a9ec91e27d0b90e875766c5f0dd5b4c85309f81b9cbc6003cc7f6e38a26e611843447902ba539f0b92c3f251026f7a6df74bc97c55109bf05e8027abe13527817a799701a61d3e77cb68e65e6ec6a6bb771fadef126012676be31d3c635", "-110f99800e48f4d249ceade95458aa6376d49d12bd24f536cd1146a778933460ab5414b2e2ead3a965ac6c1389be968193de81229b7e8af52440a7856cabb01ad559e346d5af33b1610b7ffb4aa7bc43fd94155c7ee7a03b84d7396f38714007e49093740aa22165b3534f5b17e47665359ceb4a22e726cf0dcf5be2831022b0192cd185b3b2bb4a40ec079808d749f395c19637d88a8bced49b4534a4c7570c02009be874e1bfde4a1f0a18e029bff276096aff8a0aace1e4f03876d76864a5c9a634aab731a6ec53867df30a64c7b9139884b1c2ed3565e42f0f0631d387f549bc753f42b4a47338f1baa89635354bd6ce3fe0e1db455f26764bd6a8ee03e50fdb48344b5621bc16b802b5a998e29f46346d098f931bbce76d0cf5d5af4a61ccb02dc14d578de2dd423562", .Okay}, + {.Mul, "-5245912aa2b4881688eae5bb197a4d08c254d23a90bf0960618b45b581ce40b1631f83eec3e9db88662b9028e24499f86c0f15c67a9a676ba030848a8b90607ce72f4cf72724d4c5a9cab43c24f02c7b0cc31db19b35c311fb33f39f41224eb2006025c100a2524ddeb3a2bfdb15c5b3aceefa9cea92ca2e981f48402f399aa97ed7cbc31eafb447a91a98c01248d230c9a5e9baea15", "6384af28b17077ad9cf25f14343d2723bd3a8916fd3ac7be569c3f4e29bc983eaef14aba332067fd2a44e9496d3b402ee0867e143fe0f7930ea14df0036e6aa8af74570b3825ac2cff9c4ed9f739aabecfddbeea52439c94ea1b230a55ae84c82dac55bb0dae5679534493d3f760151214a9a64da1cb5aea74b1f8ebd7688b51849f4b14085eca85d1d6b0543f83b019bdff3ff77883", "-1ffb8b4cf908c7ddd6e250604966beebb26d792e0135a3aca86fa2d424fd761c4665ad189a4d7f455257dccd7a8877608540d64c6a9d8ce9b395592edda9a7258cc4779dbe843344e1306d5643868738d2559fdcdebfe3f30bc1687f895f2b8deb6cf2a2eb5fdf3a37b92940e487f0d867c00c1cb023663923119556213a88497c67b2ca001808aef8066aba902e0b1f42d1b71f52142cb1371c386f8af21e0197eabc8aac9303fb9c74e97767d54baf0c8109542c39cf8a239af5846d132fce60d4e114b9aae0324a424bc160b175bf5034552573e79d9bb525c3d74dd3b7b5fffe7f8ba4b477b9b53f6adb7b4a50982de3b1243d5beb805a8f3dc83fdb23782713341f0be7e36f75a89f23e91fd1298a69d60017f2fb4dacc6046f509cba61c159ee3ded2424543da2a0bf", .Okay}, + {.Mul, "4bd52519bf7d655454b67356d1676bab7ce439994de8562f82a1b09f9ede205e8abf812064aa99aeb0b1cff4248c7bc64d6d67ae4c9837714b54976fd07751c91b34c49a4999fb0c9cf682933ccac5397f54e384834ec3d599a1cc6ef218d07d97a518a0782c66955f9bb633a6f9d2ef90edfcee2b53dc87b05ea9dfedd67ac1e471e03f2195820507df1370f7fd63f1928e9d4a970f", "fadbfcd286ce27833b664e7f5166637675b5cc2dcab99dabe6b17e92a9fb14dfc68f51ae5ed6ad44e23f731b1957347749c376f07d875ae003769bf37ddfd1346a5c6fb05245b74eae56e51ce46f54603ab973a313c3585de033fccb1d18ce08d95b9d1b5f3ae4de2696d9281b745356067c108739bf266e91d7035fa685b7d8620be758dec7cefa8eb7f9c2961b45a53adbca679be5", "4a4f50760f53af7c3bbfd74db052cbc70469cc04378986c3656a70cf758f106349316ef8b4fb2af1bd69e8be0de114e58e7a0296e22f404c0d2b9f417a8f1a922c1c9e5dc83418a171cf907551f463b212ed97c50fe1e633bf3f00b6679a2d14d0cdc775fe91b2562f7bcfdf274d2d67b7c03df9c2d61642b0c8f76430d9382c265ece02ddca82b2740db56c657d6cc3f0792f93c03ab51066b3d33bc9199311bad7d7b6a388eb51808e96bbe6aef1a515f8d472644c3087a14da9513044857760e5d7daad0e84aae331ca5eba7078f6c6b731f203346aba07065c4b225d72f32a15feeb395403cc9e6f0bac5db0979618a7cdc76587aaf90a48108c1410df9173e951807ca92bb49b6fa61e191dc308732b93f1085a46443e125cbe2a9e3971feeff907070636d87a38356b", .Okay}, + {.Mul, "9881dbb9012c9bd63e6353ae5b37bf6f820835488cd239d1eea441d89722d2f343a837a0906bf84d1b1aff3e7adebf673a7aeb9d096fbbf3c18790fa12af94168264fc09dea8f03c89d007204fb65cd8b93370283e281cae5207e3c1df4f18cc9c4616268f1f7629b4832421e409de113d84cf83991f5f92e8c2b0afe12b7d3e82d0a09ee5b75de2b48d85f1fdd97a1ddd524104fcba", "b3c0983599249d2df735a456013898a5edfeade82d9541a39463c1385b3704ca0f06a915ad90053c43c3afe897ac5b32460c8248b528868ce48e687cb060dd0d2cb5f28b5a450ca5ac01465c8ddd731d57fe21ee53f00049909259975576f239d5aa0a5f2c5939ada2fcd71efac7fbbab3bfdca471b0ceadbfebaa50947b38a9bfce26f3628ff8f27592d43690c557b6558a9930c46f", "6b1588b42f26d4a2e6a2ded6812c0086125b13f4ef4176cf9f96bd1f2952e767fc13cdd82c1720791da83bd88f060f28c361891b9373a60586805a3ca33391ebf8c4dc3500ec995349fc4cf46f4b1ae25adea2ef3acddc1a95a731159765ac79f81966bcecb1024e2da704898ae570427e3a53fe1b70e345f67379b7af1ac69579071db447a654cdad44eaf00f98d28011b6ce9ddf1fd27380fcf233ed24cad4ba52dceabd917010467d6c6d51c31db8a5e42108fedf992633cf6a5534fb889427fd2398af317909d9240420501cf1262dbec90860e2c286f013dc999f7dd47d2467fc83f11af1e7d110a780d8e57704c4cb55928586ba429c83b8b981435c5d66e1be6df06abe3fc29ad4aa0a1011b5d632c0698cc57dd211958692acd0f785266df6290f841ab08f87fca6", .Okay}, + {.Mul, "-70a0dd955719ad2ae112e6eeed6bcb9442c6548c08eb6a057eb292205e95504fe7195e8b8540c916efc890a87e4b56f6d7222669c8dd2bfec72c9024331196ef931df8a745be29af15a2d2ce556cf561029bf7caae9bec7ae665d2b37c051ae4ff8c5a37a792d9a288433ebf77602c533991f778ba1d2fc647a45ef45a70c82fd1d0182dbe19f080eac3dafc43cff50bcdb8d07e036a", "1b9aa4c3cff1a2cfd35417130377c56aae6e65aed5a655b4fddbe78182a1e3c68841f3c2f95f35c3b9425c3a99a63456357481c5f1ef090daff2dcfe737d2af6a12e7b02e836287293bbf172b79e6e4f7f8efecb7d23b14b05bb698441452569652c292d1f3d67e7988a89ee625d05255f3703dc8d3ceecdcdb1a79c06dc21086b42c918a03dabd93d4ae5322da1ad4b4b8d3a52c8e", "-c2500a13ffef1811350c836a7faac53f86f3db44dcb4d0d58081c704db08518f17a3ea89ccfab0c58b2137ca1349929a207ce25f4f573ff96fa89f8e0277e46b44f5144c6286ef9c0b91d690548e9d391e2acdc58f47ff9fd3e791689707b25a19d3a5e24cc02a030deb13d344d07cd13d89bb7c22cb842f2e862805121251bce1673645e03623a0002cbe6475aae9aa0e74a628382f5dab6e3a7fc33370b2281b2765b4b73540662fac79cc7ddfbe598f799db3aa65ed1263b522ec00b770f18b73eb6f493f0a4cf5a57a865e9440f6da44870f80366cfdc265efeb4d27dc26871665a1167879401f52b7465e50b16de1a6a1aeaa301d217ca151ce2cc18208415c340b5f5b846dda6078be6f820b4b6faa0cbf0129b8cd355417b542b539ee134708ec9f1a91dfce1ccc", .Okay}, + {.Mul, "-42a101f1d2b0cd16ea0ea1a2796adfe7dc365942bc3b0b9b347f96f87d2f5ba5ee32d119978179d989cf482f19b0695d96267c96bf5aeec6469ef8b744ae143a38a61141bb68223c0a1ed3018074f89394d5e444c18570f3a6a695717abe33774d8ed5e13d91a3df2d5dc78388c6972eb688b9376600ab7a2e0e42dc504faace56f201cca3eb9f930e38983f9db3e0c17155a4d33846", "2880f840a9b885318efd589538507e52cc22fd44d5327d5124cdfcd34ee4a34253b803b9db80fbb962c3a7916937998f08dff0d993edbda8993c7a04a57c031bfe62337c28d8f8383ea947dfcbe0ab9b97e6bc4018087b781b4957d0caa6b1809eb41d0d325c9064e91a6a7b8daa58c321f6b64770112acac04c304943cdbf2a3ff1ff013840108924e41e7d6943533b413a463593f4", "-a8ab96b902409aea8da3082d9b7fb2701de9b423fc3c6c8f210667a8cee0b82ac5f529f5dbd59947a10d52a7c1692af036dabb3e0c82bcf93944708c15395efc9b3706fa11db1464386e474634709445057d2292421785cf212317dc6df4d89ebafa2df1e40ff07abe0112f69c90e977f293ba34be764e7fb8dba41101b3f1021a14eb574198da9f31a8c1d79ea252cec30d05c4cf7dc8497e14764dba6ae8ef1d91f80ae8bf8d4c684c502578fc439793e35ba10a47bba093d4c00bc20fa85216a37b139f2f988c8d6206134259eefc2597b33a21976fe3375ffb6154a0f1a280901e7509f7cb873d3122e5ea8148e96991cd2ca7c57824ac402767d65c69a78852ccfb010d74fc557f7ad354941d222a2e111b1ffbdbf772b5351cc31dee5da355b0ad1879a402d1fd4b8", .Okay}, + {.Mul, "-4bf2f0f9808c2b6f97d3f9189e3262904bef9ff86362d6a279d14b8a5365a4f13027bfc8edefccca3395ee26ba194e147d5f87d2c48d507b3b0750245aea56f2c9262ede92995dc2cc175348efdaa6f2746643e467a2493daa2ff69132cd4d658ac3f3047befe378e1ec0bbfa446abe432031b60de0633b4372ee48b8d724fee3ee38f07c694e41d6c68479c28fc4e138b746aa19009", "aa0bc3826a0cd24da9d2ec15f9a0ced193ac0679fbd160b5c418cb2464c1340b0f41063d8e2c42d6357fc153086f9f4e692d6b5fea9cfb9e4d26276d2a13a2cf6b508ec407d75d28617fd4f7237e78ef7dd64f388f68d2c04f43c01718ceef80d715dbe39a68db5abe25130eab1c49a4e2cac851f968f430881fc75125fbff9718db96819633a533e8298851e685bb633edef831e7d0", "-3272d176c8786c0af3ef844d5f0cc305366263f321848a7104609fe64ab536a708ba2eee9441756568942da1f580387b65ecb4a5420b5765718208a26ace4696d09af97378f03979013ee340796dca417170aa520d8326aa930ba6b4b7a69585256aba2042268872c3e9ac63d7b2b9f30951b7dd30f839d20586dea59bca1898d552e47779f05fba15c6591917d2f6da587f79d34fe1c21957355b338824bd8d0ac3c722ee156534d3fcce112693fca2cda4edc442de2f37e029f6f4200b39f5b62a8bbaff77be4603e7db9bb804fdeab3e2d135564977e5e26da86b5978a2df8e462f4a10baf3ecfc2766eda0044db7888011d0915f72135ffd89732b8941267534d6e260b17d3db5bfae4ec85aa761ca0ab3a614b7c490d2352227d1231e6eac9e246f6ac45d11b5f62650", .Okay}, + {.Mul, "-9afda424466de1d2bcd073f02ab727da0a535407c9cd54025d1d630c7fc3e3edd0f64df4d76fea6bfa19d5f67d937dabd64646d6f2496de387edcb72dfd566bfcfcd84e8ec97722d9f14193f08f8909b92aaa9c4cc8bd9100b50981120c54b67f0bccd5dfff24a76bb06431a80853cd25e7853950a681fa0b6cf3b04261e05f9a9d1bac7acf1eff7226496a4dbd50aaf2a60399e50a2", "36855a032e8833f3894465374c6126939ca388dd9df2564f9eb26b90285e3e397582b4d5c90c10627396043e5a2d3eacefb1ac7b7fddafc611f4ec4e7ac04223f7a5f9353f13f06d20b4817c49e9455780b35e2952c7464829c62f2023059be4cfc090cf94ccc70a2de29d42cbacd0e968b89c14e3902cda5f7540a71e8a587f94f1f7a4b82dfb318dc00ed3af77d8c15c701eb98063", "-21023ce5068d7b99ec7c238387faed6d511072aca61f0db0a43208d03ecefdc7d40cde445aede0c47701276eb7cc10bcb9e12a1f89710f3cca1a8f1478abeadc9376ab88612703991243ad0c4883bcdfe633538b63282b937d1418dc24ae7e9b0c014008e68005684f5ee0b445025fb5249eea66914dda58e55fc802681e9421b2129004768141105ec422327442e5511af72ffb852d1daeafb607a18a730b85a32886571fb0422fab295939ecacaa1fb157c30a52d05d7d8d3d53661937336b2276a1ca8614e2e9bb4bd7e7eea567c8343d6518fe25009059bfa2b12a862cf364a362efe76b3e2780a0a22037a0b3ed9f93929c719037ad51a48bf7461db53c5cd01ff6674e94fbcb336fa182a23eba2c09a18dbc4eb8ea6358f0da39e0b17d9a2324c731972fc0b19c2ea6", .Okay}, + {.Mul, "6d6aa99e353102164f2fc45d79851c76415996cd7f8d7d4b22d0c66d5fd6e7ec32311b7fb079a8e05f0c540bf2ac42523c26bc75c64ca3156f28911bf97c94be3ea3258e72041075c8e971bfbf43a83d4f4a1ebf42aff8c19760586b9b36b0de2ffc6f557b5e01f3c38979c942559099826cf5de05dd516cf15bf1774f5557c16a90a4b5ef1e9052adfb9a87c89dbec494e3194a50c0", "9dd3dd31d82eff648135ca9344257ed019ff57804cb2ea7db932bdfc86b90dcc9d64852a2205407e15b7d548e69d683c0fb068a525bcf667bd6a9e7a679f70acea12d8b458a0cfd450a4efa913b470521aff1e021dfb5bf982b7fe4543b8ebd754461f0be7db3fdc33d03e47b342c98760fe11c27bb71d7bc875069ea8dd3ba1b494ebea21a376c7677804ae0b4c5f54b26a112df5de", "4374f77a364306500f49b6ea4e0bf182b0be82921946741a2914303c7d988d5e7a0ae53de6b5312ab814ea695a5041346f9be9d776b666e5f84962897746b6b08648a1bc3bdf3516e6b7e76850046e54f59f5867df66538bbc3a4bc0637362a8abfeca6cbf8ab7827c974145d577a33c1c2f381e7235cd776894ba866beb127b0d4d2cfd61e7e1dd97c3d37f0476c5f70558ffe017d96fe995b3c669a6912d6d828a6af6bad7568bd09115fdc24048f7491e56f1d887fb52c88dbb45c53412fd88cd173e248e3e35f02c5f868e4cdd977f8f2b96320fcd0a619f85813283f1408a568dee6308b5c6b46bbe9e5ed6d753185e09b33f03152bef1eb5483ad544c96381c136ecbc632e7299cb776d8ddb87032094cea2464b6eec47dc2d300b8e4315ff2dc6b57ac510ff79c680", .Okay}, + {.Mul, "a11f3b5c52865d2584266e87467f78f5cc8880a69d5a9f400927cc76152a5f814fa098f84a40c9a9e8b2bac123948c22fc7a8021b99365e87bdcc09ccc8738d6a823aac541ede21b8257593a1c81247f0bb90d7a37272f942898191db50b290af2d8efc950e0a811d3010c683015d7b1c716160a246b390b4a2cbfc12addf685cc5d285adb23197cf377c6d4b20244e5ba76de45c3b6", "8e878d1178abff65e0e580296a95c9d54c39a9009666d4e6164fb08e8bbe6e7678e63667dbc388217e19566c05638ec71e238ef7e6ff011d863d659034b66843a17028059bfd90d52d52bfd47fd3e1e95d208a15e15f3a90ccc66158768efb8291088bdc05df31171826b4f345c1a8907e1bbfb33a9fc710f6f294f3265656cf68730a0243e8fd3e9c93c911d28f1a19703682530377", "59b4a32eb62dbb8992a91d6f083a6693c594cf42f868af3556878db67a54d29e6f7a2d9499c14453d7b8d7f5ad0f81ba26dff8ea2a94aa1b49883e670ac9eb1099184a82bfd02017ed1afb0016f58b30c0f905cea07eed3300e13b6ddf90a5c4c2259ddac0ce141cd49097da804a35f73c399ec8840dfc65dfd620d79920b22c2451c93e02604e9f8b61993738b539e825d01b073a28eb99e7b6e30cae60ec682fc558c72bae5a54e73af1d395044dd08b5385daeb75382f9ee234b3028224e94987bda8023f3e0a231794e6117855d706b5020e2620e6ec5d7dca40c2c145714ed70b61decfd5eb0714bac034fdb549e5889fec92d1ccc3257c647613b4ac1ab138374afc1e87f28db6fa4637f1adae9ac8fd2b48c941f257d54b43bdcc24e4637f84b48a7f784103bb1b9a", .Okay}, + {.Mul, "3b2554dc89e7d517c84089a1416c78f5927460ce496462fc7e3cc41252b18fe0bfbd11ee15ef5d86c0965a6382029c60b5b455c4520a2f81151648fd90f852a0b8449459cef87c838b78cae2eff0fbbbf0275f2958e6d381e8c49a9b647a4544f46c3030cdbc0958dbda73d0eef3f65fe692cef8b9ac6ead9f59ab752db95a63ad6510ce9dbadc6f236bb718c7fdcd3b806cea04a5a7", "c25d02382fdfcbeb7474d6ae178288b01569956eeda8c2d0f773a688bcdfda86b6ff3b4baba92c95bd00418cefffeff3ae39c59577b10687f63c3a0ebd76f636208270b152e492497eee72965bb1bd10a7b50e8d65a01b8e19302376a385b0778b278689b2911ed284b4eecac3f2b5a007c9f5c40cd16188128f13412416720243f5731e8f5e6cb2af8db7ab1774b79b66b41c9ac5c9", "2ce7c7623a83a13cd3aad659bdca2de9fb0768d40776f4af9aa6f7569b2d2c9ed745b29e44e5eb2ec1666af365199c86fa75e4068357ce3813a78b6dda77ebd03dd899821ac2aadb51f1ed68a63a6192f2863f5553ac2b9e541e86d1e391b5afba2a51f4b391e6c40e72de3ccdcab2728f0780d12cf32602f33a5b2dcd02d38823c31c3f5495739baa86f74cbfce8cdbd50c96c70b5045edd00dde320bced1ff903c189124265dd1e865a7b6c0559a63053e97960c96cfcbebb96e9fdee6bd3b8b088d38c7f3c7658112d5551511c4a54728dd7a4dc53364d0e237a7298c5434d35d2d9f602af6b44d13f2dd52b6b9dc0c2fc93ad10c08d5ff00989857ee38443bfedf78b14a479ecee7658c77f67b3de02cbee31c8ad6905bbfd11f81481c30024212c52b0af1ef3b95931f", .Okay}, + {.Mul, "-cdca214817e810f835760540a74ae69cf31b82b1a63c499d6f39a1dcaf3e9a648fe8e30b7381df412f997df62c2c21ac6dc6c088b6b17952f6ba53edf5463fd0c84193bbe45cde83a258a11626522f9113e27d90ce5a069c339f4117baf2de8cb8fad7b63891ed43c44654e3cc10a3367d4b525249137dc758b0520bd260681afb439afd3a0c03184907a7d61d61fedfc075f1a2f174", "6277f38b34132b926247f3188814392c1fbe24aa39c9f7a2bf99bc5c4f86f23fd7ac84ca5874eac2d8ad9bc93ac3103e07506e7398824e2db8c06d293122b4762e473558d4aaa4fcfe718173f4df9cccc0dac09dc5254ce6d49bfee2cb99167788d85118e60395e36c450f0916f515b98f7c5a1030c05697f487cd74b08a3478da7c8ac238501c58d4058213a14cf568b0c606a0360", "-4f27cd79d5ddebfee8091167f3b8a11aabbbac50c3efe496450471a3f41be92034d7b7ee1bc7da1654be23613ec15e6ca134800811f9aa4e6e8a1a3c40828a3d2e2a0778a874bef1d2eb96217e72dca5e3e7bb3ffa821fcb1ee7863dab5ff4af8e2dc0265e7d78ff3822e09502f6efeefa028c55023e5664f7c143e5e55cb0c9b44963127167499aea7e2984e28f620c7cc76853ca0c1878c11701663f805806924d870370126d7dc854ecaa7bc2850323d6896829bd9d11c180d06f6f03ab6c986432a1045d0cfc6da53e3d6e4d1d143de541a69b2153acb479c8efe96faaa1f426edb095b0a68372d3c06e2adfa20d855775823bfa953befcf6a57cb60fc2510d859b4fa2d31a349c06455d54845e3ff98b3e0d613d79f7ba9ebc2969913f9e2cbe52d4520382fff6e780", .Okay}, + {.Mul, "-7a5da82875eab9175866f210e84b343a8d74e373f9447e1b5be20456cfc9634449cea638c22eb400b135e07915e0eea568445f813c8e4a00f892ec6ffdb0a2bc9621ec811c40e029927c96d2b8049782fd99142d75fecbb7fcc557ddc09a79d865a927acaa046ba9b38484b1fcd250b9ca25e27dbd6436d93b73237912ac289e881dc60938ecd043aaa9d2074c3ebd3f2ab2df0c9fb2", "a957118fe42795844de44ceb8b6f60643bb0df90966197eaea5d2fc7c329ccb6d9c8a1349d898d0c4f72e54629f4c8108ce634feabdf943a6e070d2dc4d729487204e5f5502d3cda6fa17f362319d6a858cacc447fa18fc157ecf1b930dd32653e3fde2b7b3116229afe9269cdf4ead931bc159738cf446b9418710e0ef697df78c31ad0576f42960fe8f83677eebc1dbff2db48ee98", "-50f1723bdb21fae42c47828e60c531874cbc6c5851fee36af68741d3feeb880f64079b5c87caaa3773d17dade0db6d3d2cbdee8baff42c72aac2c3b6cd614a85977fb77539a703853bffc6667f7a80d41f8d888a63facca01e24bef025d41d691a98ddc8d1e32e736352bd26c2c37f478d7ceda4c480968ee81f1d90a4360981d3e8b284912ebff3539c2280eaa9d9ddc52761ca888920301522d8b26ca691b215c9d6e1c27716f9770a285b3080bf15a082aea4eb37a281b3ca29ea47e25f44e955609c962fe727e70eab203d3f3c188e95f0873628e354a5271cd241227ad10d30c2a151fd4f663476e7b5e70fede3f5baf261ce0a094a34d366e16f8e02d30f0e2b979b8cde7635da0f47740733f813bc2fb234feae9fd929a037789f830b2ee86d2e3290f2005c064db0", .Okay}, + {.Mul, "8cf0fbef0b0d0c75c93e99f148831375612ce0162bbbaa7d3a9e873914ba254abfc41dd7429acc695c184921ce3f4a181906f07077b679ac904313601935877f7643081ae4c79457d118c2d1bc14da836c7156eef3fbb6a608c91b96f8697d077f2b4dc33061d7c4e6d8769a8a1f78fee76fe4710f4924ae469b7c3952f1fdb0886b48742443fcf99d46ad70243c0bd881f66cd37cbb", "32574ccfc552b96c9d2f33ec277fde6886fd8d16e6be9f7569dc0a6805a9fe612f1b5943ff15646c3bb0c8d4d1f54e68e60e94fe8d9d7c677692cbab07f35df5e7bd1391438efd110d3be37d5707d7c9bbd3887caccf30800b7a0a2d4646494e57d8a760fc865be52bbc46d372fd15f4ecb9e65aa745900662d0db56b5bba5bbac2d03dd027556195a898dc6af4b5fdded8d107a206d", "1bb721643caef895a4ec0d435a57609871e5e948dc80c456987d6be733c36b51297d1096315f5d885523bf9b901e7573161836573e0382b329cf236cc188b4122892c2fef22e5c63467be6d5892a013e347d4e4a76b6c73eb677da06cb3eac739bb6c05a13a4d67b269cf8c70577956674438622e7f4b73338e793ae75bf1bdd54c5fc8464761645ac57a3c6f17d83308b3f0ace6bcac5218f8cbcd5e866e7821327057b41e92ec869e0a57b4be96cf209df8776d0e9b0f39c389e789a9f0916c4e8a0a3931d49001c54e064812152f68031456add1a70d39bf3f8205fc2da847cc7f3ba04ff78ca3191778616b667f977152e236c65f28ecfa44447cbe544c7fbd0594679f20c793d1b0aa81d7ba6a72349ce9f15f7394a147de4fc801a4196692ca1783f0f0a1ae6c17b9f", .Okay}, + {.Mul, "33a349b9299f469d988fa36f0bc95de465681cffc0e3b331299db2a8f5c0294d0d855c6fe7a53ab7ce8f12a89e4e60fec9a8ba62c225b4d24571115905f71b45dd3bf3ba732ec63434176dd92632389abe6baa31565433a92b0939e02d38d9b01f020b03474813e890a81d2e7578423cbd4fb628853727979c4ed635176b5298a5381780a1843b3391834c02602e3e457841a799e677", "c7ba457b946c207ad60aa5e08dc02421629409748c5bfd76e8f538e905ef2c95b474b8aa9795ac714a6e89f0837d83d657f72c83fcd05eb41fd7c00459233ddbe7314d5f475fa8a387b86962bd19f2828bc290f97d763030f93bcdae670efd1ec0d33457440fd37ad580dd5134fbd3ad59bf9e2b8e0a22011c56101395cd52485192ee4d113d77269b00da9c36af6de3d9bb0e13dbc7", "284980f6702697dc140a792cee569e890e09aff1aa0e4068a0f6cdd500d4720566204716a0a5681ac9158814e40d9c7cac822bcda5e8b142e565d0fe40c56f396e38b8e493f05c21936cbb186a4b1467da957cad2006eaeb9a9cd74aedc541856e32a44ab11e2876a5256c1e3ffa5f91f5b2d43759a48d91cde902c27b897d5a89a4f79488ff3fb7ecdd3ce55f5b84d645b2a0dbca100662053b5415f3135ff6edb44577eb5e1f2ff58f3f4e54ba916041c7343911dfb4c8a9bf8472e4213368f26ddb7798d95511e04cd515020394e2823c19a7504c9fe4d1a4f90b2c414b011280e9285861fbf0c12cb670612ed21cb8828bc4bcdb76e6fdd837960c3a56992cb5c2cf2a153e5cdb49ff7d40a03cc198c96c32c1c45aca685e7ae8bf0ac0298e8f07eb4235b85d8d9ef381", .Okay}, + {.Mul, "ffd42b2bf9b4591e79ee307fc3b3bee0a56dc6768c094680a8b09cfd8971986380c166fd4dda8af198fa1b20350ba8a5510dd54095e90f3b9619d3cb3bc0831808d874a1e583a5ee266032fd0c4190dffb15d4c640b4340fcbed1162b37c5e7df0a989b2e9247f15f8fc05a05e16879804685e96a8c61a3f87fcc83733382258bdbee44597ac557fe706a929c5814c9d094f857b64d5", "115e307d5e8d0b61eef0b158c7c0838fec74cc0cae9040740c5cbe04dc4cf833a8e4bab3d7199ff550b44b21410ebc2cad6fd86b91639ad40374e4efa699af1bfe7ae986dd38d9bf7feeda2f80f1bfa86866b4f1c2bafc49b3a0c19e9ed8b774de02ec7d672f8d37edbc8e3b06c1fc4f731817d644db85df88a9004db8a55455068a403f93f9ad8875e8cf3b8e5a28333b8dc3fd7d13", "115b373ad6e8d88465fe9a24e6cd7364b320df019874f8c4e7709d25e0d6fc97c6d6b0538de4dcfb8083d1b3af24d4d876edab169a5db90ca84267a20ad45f427987ea1190f863e4872e1866c088a6e004e512d7341a086731974d3b56bbc48935cb7c47528533e23f1ab293e9b17381a82bef5c51c29a63c759d9ee2f4a24b1c966d913e74ce41b3087e715c901c6fd5738db364049c340631e30df434683356120b473b51e1a6939936a1fcbbc61b19b1ba8c83e405183e566ed5ffacde4c595c343d15566cefa3f99577bffe0a07e4407fa672f29c4f344902eb4c2bae30e44679d204660ea14e8e77a8db78d69b773635cdde6fc1ae5e89543c54a96e5c80f9bf8dd776b273750bb87087e8befdf300263db216584f11275975ee5b06d6e246b0d13771a0e260de57ccf", .Okay}, + {.Mul, "-7c5fed386943bc1109161f07c293c2f26f1d41bed792a0d3d05bbe52728c855eb4c43f39d82adf20bbbfd84496b7bcce49aee6e0a612b159b5cc95baa6cc9107a3152812cd493c4840fc809b55c33b2f363a4426b2a21a09b8847e8978302d277e0e3e8fd07c08fda7068c088e81756fcf76527497dad72e596e47a17c4536f0a2de353f9217d82708fc398b2f5a7e8cb4db2e8b4ca6", "bed3fe82555ec696bc909735b6ac427c69c6a25c3161aaca028dfc1aa478e25eb1d93a888a48a72a211115815cab5d581a20a5044e0e942ac103c554e8a11ee12d8bb9afffa8985c011fbf2930190d6c4d14928adba16857a0e8c399ee8da287429077af3077acef90184625f39eb14113f3b6548d6cdb3e26293355bdfa1676a54523ef43203c05702e263a4aa98afc4a9eb703fd75", "-5cb630c6e32d5cf792bcc65837d0c74a231f0a74c360bae539f2782d8ad88c315155e35082911a3f70291ebe653990742d2920236f4b95b1dbe90fca2bb7f5a10795293455d75e01dae7de8a73b05d6c93101505e3a1e2aa6e57e3cc0b5563bc6426afc227a92c8811c7d0351c7baca109325fc644cad69044661e7a2a14debc475424ce10e728497435dd498791327ab53817aab4f6a09414ae1c20c5b3683c313fd955cb080af5b50b866cf1481f00a9a6558cf74543855b62c13338b4167edb11e3954a697bbe57c7f09aa5ccfe0e1b9d388f3b06925fd287bcd1d6af3ad5b680855e8e23e1e78481f58f7c13ea72b8dcef842278571eff6a6e448bf3f6c69e6254f52e37f5677d708543e81de6f53a9ef141c8a531248820d9775a3db8f90ea09d1d9f6baf0c805c15de", .Okay}, + {.Mul, "503a05f4805cc8f0aac2caabb6003b15e26dcf90b18f8cc1cec1cb8de7aebe859b8a453f1af6cecee682b0bab629d929ee0646cd310a4cedf14ba74200d75bfbe5e2a93aa1061f6a73c103920835d59907bd7275bc5a425cc2b9d092f2d6e4ac025ea4b5aff702be69c6277eeb248952041a4e5524fca079a7ee976d23e6bd99775be1c3d25b03203b871b35a9d13b5c19efd24bdc6e", "a29cdcfebbd06cfb205318a5528ece96e56d010557d126c28b99aab46d075ac98948c5acba692fcaf1e59f8db72bbb31f492e4e12494a3b8629a1377e2e95dd08e458cf04ef2952ef02db4ae4a12c52c978045563590c2a78a312f0965c2d3d802290d8326eb767790302e7d150e18acbb83b74914c7df80dc12cdd3fae03d321ceab57b3750eac602619a4a7dc38843478a5b17f040", "32f5e0620bc4aa3f7569ded0cb6a994899051b67af06f22f50575c7f9b8673bf615b31282c8b06084e3a951ac4bc14bcb1050e88c011f6ef02c3c1ee63090a8f53dd6e0bddf2c964029edd1e55e96911c77b4b6a51a1ef71366b93126100155218807f94725562f9e4dc15ccd22920fcd4f50663dfa4abb0051970e789174178f71b2ae885df2ab9887cd179463519c8646e2841239a40e9840be091fb87df936c708e336559d9b4f9c0ea9e1cc8f43f23586207c870960fd5dae91ed8dc07ab556ccd812b4e60f7ca2812b86b1196e5941f6935adf5b297f9c412323c9adf17c11e80d544bdba2a6ea07a226a04a0ee24c04ac435a90703b7086ae39f2e3ead4fab91fba5b39bd9b30c4f29260efec251068a712524cf8151dd2202c930c32d990f21cd4b75829399803b80", .Okay}, + {.Mul, "-bfdb8560a755d4926d3c6761ea9a48ee97a18cfdfa5e07a8f440e91decfb2882661784b4430089a03cad604f5b5d6b7f751558612e71c868907f74bee634cb0f34a14bdcc2bc0f2e69a4a150ad6671472a5712bc635c30b6116d6038d61125060230b4ab827be22dc9e0c14fea6af7b83f53666b002dda44da378da00c48fcbd42add04239a7e343121639dd502d9276cdaf657164b9", "a1955fe2a9423f7240d78d8496c50e21db88dc59aaf87609a3b5f152609ea67ee7b9ae70fbac038b34d7ff254bf540206d4940038e8f239b05737d5de055aa547c533f13917ba61a49b99f66156f631b2d59bfa58d310019eb290bcdd3a5a0c162069fbb4d51b8da532640b1340151c843f7042b1007510c00d2c07b518c798659190daab39dd6d87a9c56fe66246538cd8bca7f5592", "-79190182bfa28e433b23f96d2a4638fa0220402d4966f2ed04dca3b675204231a821eef0aaf7224530e2bdff747c45079453b5a7a3165b6e70069a75254ccb1959bc757b2a4664559223cc3f9cdc797b4d75fe0da53c31c9c3578b5fd9e4de53d75d727b98480b18bfa6d79d6fcd145cf4bfd7024045777bb8e5ff0561f63a28692ad70aa3cf213cb7d46bbf66a815f465a66f25228aff93d48dd1b885c5783a93d8469a9326760d6a06aa9ced75ec5f5c128e1cb637f7f1a2896fec6215712d93583373efc47b15cf2cc25723c47fd78689f3864365e60723e46adec5eddc4667c972ac554c1f2a1e9c8d658e1892e4a06acd879805dff18521801954faa94eb8f6f0f3b2b2488b50f59adefaa82b0b9348344f9e77eb01a9a1fb7ef90610469a4132e251cd2ce472e3de82", .Okay}, + {.Mul, "75c56c9929140cdaec8a19f918b07b5a7b1b221f61932f1a8b1441572733922c553cefa0343025324cd57df6257b42a366a5d3528c07eed2601a389230382628d082b698dded8d34dc58f7731f9c41542569105534d558448955c3f246139505467959e2d58ba49d7141783c5f6dee0bb265e3fbcd04f2459c87894b4ccfab299cd7f442765285d662c5668be54433de397ebe47aa08", "a20f50e966d97ffe517d0baa12648fb3c58713b34f3da0eff2140986bb309b9d3f0ac0f189b58713a396f7b4088a6e89f922625ddcf3aceba4c2acac757e4640f1a7ec5221504a134b89391a0ddfaca7a054ef0f7f28cd812bb15dd214497d972e1ea1099e1b60609c7c6037bf46f2fb462696b45f57a2238e995ce23727e9945028b64d2f3ee96a20c1ce33767dc3515b2ea3cd2d6c", "4a8dfa835ae8850bf637e649a321bdff6f2baadc298a0fc8cd7bf28ad8e6c3df606498f75bc842dd13469247fe4ca95b70b5c7dfdc8a9f2608e3341766f31d364b19f828fbde7b46ed7a8e610e72b09333b6474bb2ba36ab1c8b6107aa1a7b0f0acd43f70a3744ae856460caa91329f9bf452106fd4b825cdd753953f2cf1e85af21bbd1c762543eb18c463855dd43f30967a1ff8b4979f3dd9dcfc7845abe6275edb6b45e5f041b3298326d6be78c8d9f1d413fdeb3d3874d715aff7f60faa5ad08e1253022924f343a45ac767a19031ccac0cec06e3cdbef532d488382e6bdc71ccc88e4ec16a81c824e66b87868493f83c619c6beb28df1b17c476199d21ecd39402fcfc68bb76aa3b36844042e212e5b528266000ea61f046a2ddfddf0d52c54a0f63e5aef011f872360", .Okay}, + {.Mul, "bed73fb9913c0b32e233ef3cce71eb4aa6fc4482464afd163f3781423ec916428c3da8de893ec7d5801b201ce8ada44c0800f9791b68246b514d1e9ea08ec27c8fcd6b946787ff6158958fdbf17c87a493b1005af9fe8290aed60de21c8d900f32e7cb216c269e433922f521ce4114a37c62bcf9f26adae8355196e82b5da0c93bc5a7e7ddf47f47559b4c29ebaee8d0cd81f09d185d", "1b52e0fbc81a969acd4d4e88a28b1cde56a5650738994afe5909cdfefb00169d05d7b14d1251b74552e76941bb7c8583d7d9b902c840980addff0b8cdf9aa5039b89a50038dfa82f7382d4a07086a0c56f3a19a4910164ea240bc49b954f988ce927375e2d3184a7fe92a5283078e0248d351a5a9a1c08ba0f46f5c1cbb8cff6e5ea7f0c07115d333010d5177464a41ac72e4b0e76bb", "145e7c6305bbb05adc022893eb211679869eb85f74a1e98394f0d3f8034a077412f0c4f6c8985420b91585263baddc417222fb66252539a264919f42835f12c1e3863bc9159e27358055c1a3b8c37859e17e39007723651b6ecdef04b742fbe603906dd1aed1278fcceabb122b37b7270893cff17a4a7f3db4a75ae7473f9656bde7d04e5fa5d448b0b79d82a9383a3587b21391a7bed3fa3b96f25f5e3deaf5ab576a23dc5e60502c53404d179ed39d43884c5b1de9c9dc48b9694f3f1dce652215b7057de0fc95c28377441e1f9abd836dbaa88833329879a64a9e2dd7b7f60a9eb46168af6910f5f182ea2bcd920301b6b84b0c2e365d4264793ea39ab640df32522d46b15f841d14bf19d8dce5f6ee9538cd5d069cfba632b8b98f7eba2317665afc0575dd43c011a9ef", .Okay}, + {.Mul, "-ce42a3a7eb13a569872176e56e14271f4eafe74e93fedb3d0adc23d9000345eae610f9c35252d92d8805ad0e77201599c1bbeac0f8635c9c8269c23a6efbc841f294f25a98d5df6e34edad73aed900ea679cf2d24ebeb69c36702c0dd5f21d2da362d901a939750fe6e07a2e947397b7d40f772b0c452148770be0665bdc72fad146164604b2f5224f093a438dbeeb2bd25794ad1bf0", "c3e25036dd42733c752daa90ec4a3423b14407f5d2873a8801fb16e6a825a305b2a0fde602ad108799d93d86d98d0c3ed22222756fa066d8b17ed2f418f9731f6a0ec82a621cfd6b88b2b917b9ee43d6fe348df6625b9a72f40be3a08f2e65f727897abf7968ecc5c13ebcaa6aa33abcefd3cad34ab907f51f7096479d4666f72a198273ee4251d757be4ccb662247eb31ccd233ae11", "-9dd31a1e69c58e87efb44259e1e04ad84e1dcd5342941e879c2467a1a38cbcd3f789775349e54aca4dccdf322ff9cb60569860ea3c0545dae2e05aa1c12e41ab3caa47783975b83d3b116aea651aa073e1bb04c64cfcb4b0e3d988ad66683910d0d3c1cc968058347d0fb2f646d3e42feb6dff6f50f7d9dcd47d353fb7f6edd37f0ebed80391aaae15bf305ff963310894edb88335b6b27fc8e981f6b921cba2de1f1f1d23d8c760bf93184a81097e8e65826300b6eaa800cd5880c70d1eac6f1010acbc2894b37a3bd6a8a0a5df48344db9059387e1dc4c6b1553ef34de3f05774a49b77828ecc5f3447d5a713bad388d32f6ed0175b6559b8aad166a73fcf2c0882d650cafd61651a784deafe37fc40837548a858e48cb0d5b1fe067d37d38ed062e93f7e45185f94bfaf0", .Okay}, + {.Mul, "1cfe8c1149cd468f8d60c369d6c3fb1ba73f0a857549681a9c54a19b19625e5852f39edafe1118f7740da301080967e7ee218a57e96f35f12ff027658e6a1c089e4428c0f3b0d4d84d38193393e898a83e8bedcc0678e44465e3ed8493de1d0cbc20da31803fdbb94f5c05fd3f2efbea2445b2e8ef08ee8412976e762e3301b8b942c40d4a74d13d3cb13b1914dd38905a43a9b362c6", "ba40d0f1042ae7af9b800a8109b60b4a479b2b590c3ca74ce5b8db2a08919cad2f28d316965a781465026ddc9977b06277374bac72771a40fa3d56ee4123f1dcd2d1e073cc2b0d0b414fd66b189ed94b469f00f56f1e72dd372e6c7f774488d5cfbce1e673ed7c9e4fddbcc655326647e766f64741b7e8719dbf09bffb21b00ba2e4f33326663eeb312e77ed91e50fdb0011e2c66ce5", "15184911b1da5704082effa5064a8754e65063912a452bab5cdfb7ec8d5fde29b3d6aef37083bf8c1d735f88c998f35c2c2cb4d077bf48b109c82857697c231281fc8a0eba323bfdd5363546a0d9cff558d78f0e57e913e39d0d443408b7e25955f2bb6f189363a1925d886b8506b67e20f633e7e694cdac997a5bdfe9f1505a4ced72a737e4b522c63e1309aea7eda11e3f6c021397da1d87912178190debdf473d8ab93c7f4c849806401d399bb5350c0836bf416bf1a2aa53b1579045cc7add61cc9264088fa4d31c93f8f05be94d9ea56f232931566da82e22247872397cf1f008363bfe68b1ff92e7ec8ffc27fa8df52db6fd84d22246e3ceb9c16f07f775dd2c7f1f20fcdd25e5213f99fed891faf448dc096c2b0305df68cef98959f7b5675bf169a67735ac46e31e", .Okay}, + {.Mul, "faa5df3ed12e9a7190851109572f745cfc3bade6dc0f301a1d512bc87a31c465d9b20e94cfe6eef5b7dc33bbf2c79257dd2f3bf63d2e7c44cde4eeb33500b75cee4af5c1ef49222865c7e48eb7420bb2491f1d97cb1d0fe1101b7d4ada1309eede888c25d6354ff16892e82cbe213f52aed48a1b4a54011025cedee2d1d6ec0cc7562aa9e696575b602df5a7c1351c247c892ab4604a", "4ae3f88cef99f69535935578a71302af9f64d5633658a4cde4ed56dc86adaed596ee47ad492fcbbbc00ea407a7920fc8ae487db82c04ee54523af5938ffae1f460e96b3d64f83e3b034cb6dc113775df0b9ef7c697e832338a0fdc9f6c35dcc21790aec8dcdb0f634c0a08fadf4dc873413671669d001ee0bf63c75c1d75c45629c608e6fd761adeef170370bf2681d8bd8d6451fe12", "495326f7cabd7ff2deef82ca02ed19e61d6956eb4eb1d1ae234ec04cf1a4f1f102676a6849ab3b54c22269acf2ccdb056b16a1cd3b7cc9f5abb813b44a23ccebd8ceab2b0c9d0af5bd82fad963082a44c50cb9a34b52cdf9d46acd8e853001e2365ddcc580457eed44aa2c0aa4ea5352b0f5c046ec264343d1c954b579c12c7c77fb0ba45b5e518748b471d03474d387b9f6eec5b86d9f16b63f388964f8b286bdee36ee86491ceceae8e9688c841b940a680a4aae1362605ae6e119ec82a754fbb6902fc5079336a6cd0a157bbe20a539e564d6b2362001289b8fc307cb3f6ee8408214adf49c8797430ff74c561dbbe54b5652370429bca4150bc028af9f1c5406d27a420f80f2175bc10628bf07bfe65f16edc43879e8358f951bdd7fbc002392b99f63157d7557a23134", .Okay}, + {.Mul, "9aa27f8c6fd76972789f556ce0375a9a399f81e758be46155da9f2e07095a5f594e2cd94cdcc15d70319e274da8e5067abbf294103c593d1cddfcfee2dfb959f45592acd9cfc3b260fdd36480a196f160e69fe0d83d5f8dfeaecf79ce974f6a615132c246f1745f138ebd19d452f28fb44872b929f772f9de122cc999d8d7abc55b8ae4f271623424089a7c30071a5e9b8bab2fc0411", "81219cda980c46c885348bb9e636b931d1d7bddc2c4ec86f6011ebf5ebe04d86c1edd49a144843740ab8ae8e655bd6944d148fd790a0fc90bfb13ffcc2d019cc560ef5ea76bb8786fa34b9eec002f33f52ff6dedbc2fcf2340a79a40ebfc845b55287746fac48a8bafb57fe914fb9b12c2f6e3c0744766ef43d446fd513dedbc4bbf9c29eb703f760661078135b9f504a617198afe18", "4e002ff745680ec0b382be3f443def3aca50785b36e789b77a3189d6d65075bf68c1ca22a0f100c8abc3c84e023c0947357720aa873df5abf3ddd700199e4a10f3031dcdf1d31d8f2032d49faadd7b0dc959602e2f6ff7412203968043f768910b30d0aaa32aa0d23aa274ecf58f8168c189c55e5587e6621a03e9a16d7db0575d42351e83f0ccb05a2637e120b55508ccac47bc1a0740598f960f05c0b9670d978899010f0babad34f1bf4027d5a2512a84530631d8d864dfb3aea0c7a601a7da08166f858b3bb08f0b720536efa7ebf19790d66f3dd1aad55a2c70afa9cddf2f914dabb5274541faf36c0e97c654f824ce721fe6c1aca3715604b209e57be19bd49a4b32c1801738a0d9272b6ee507506b2c60c6a31388049a8789d2bd484699b62a4017dd0addadd33f98", .Okay}, + {.Mul, "-b278343da789ada916692339fce673eaa553067c4b384a4aa5822be893689bcd33f20e0725f5046c24474707e500de7281c3d882d3a28c363d778bf63bd7dfb329c319b0ac65450ed9046fdb215ad9ad969c4fd70a4961f91d3a21917b45c20e39a5aa88397e2d71e5626b01febda07ae07da03f41a78d77e3c1ecd88331fc9042847c30a2318de184ac78e26c17628ea120c5eab7c9", "6e42492303c32213f0d9d2b17f4e350dd26206cd3e67634136727864aa88f6195854c4ebdc6bc1b4d5edbd5bcc2a6bfce90e16fb57bda57a3830fcf7a9eaa54a1be0ce89f524ff408ef7718bddbc49551ecdcef0417654eeabcd250318f8d0cedccabb48d7e974d7c580210794f59586d8f84c34bf3fb2bd2c863d0d8bd287e6cf385696458a3b72e935482e3c2e96f3032e87c9274c", "-4cdddc6ca5d6853ff942c13c746c2963aa2ec22c072d478a4565a39319a5f3609fb6cf95e063bd42f04b052916f940bb851deb395e44a696c7a4bc1abc96351379595e86b562099275c8dc8ace7fbd028b598b5a7b66b93888d0fb3fc002b58b948ec4bb730cfa8a8e17da647831f28918551d27005e7158026c1e976dd6344541c377ea0718dce55a9c4689afc7579f13f72f968ccd810244273439eb650377ac7d2e1afbec09910a93395a0548f5dd0c9a648b442d6b5b9d632c8d751048f3ef093dc460d58f6fdb383ef2471eeb8a11d56da6d33ed75239957a42ab049ad4eaee1e807226a0035f363822e5f01597d39afd3345edec74f7de244a4f8e23a76d4b3379cc05cd8e8f9e5275e21878141b6f6f5772d1f4315da9b16c5b8c004e3dfb1db9521d6134cf7f2eac", .Okay}, + {.Mul, "-9d2e0af5c2dfc4f85ad5c300411ea18a1f33ae59566c35f7e4d65f37bea7a305ca27b007ba256e587c2a6a6dd16a4ba903bdfb770a0a3fd65832119806612dd2b0916faa180699168a41e3611af8b3978ad0a247ae0853fd72b3ea75ce49d10640a113c116532d6f6b4d9bb03dec6099d66ee77acfe1037afe2434f1cce701fc4cbd7d34d64a5eb1635176d2bff8d3a1149af17df8f8", "68b202ed003ca8e2372352509965bd565a3e31c868c9af1bba3707fb30d4ef8047cc9964bca4960427c31ed2acb7aa40ea60f983aba790af03232130b3376d2c2f00bf6cdd7af38368ce201e279d3228ed3976f9ca843448fcf83211ea71e58879547d9971248d34beaa832a22ba1704d9f9831f3bcd6f2bda63bda079c583c31d2e50f4c4a1d72dcbf338d1ab35d019759051320ece", "-4048004355e7b722af947ff7099e42ba35f576d98f725922c90591c81c2dbe16d8ddf46e00d6b61c24a8b987a946aa37d2b51b5e56b0c28de02626d7d70c817c365270eb34b1954d9f986d97f5136eaa760d9160b2c76d1a1943123321fa3e9569424093c4a2624e92194f51f05421bf5a985b85d450a0fb6a4002e8885db30656b763e4dc44abca15e977b8863afb6148aef363a269dc9241732f4d576891610c38cd446f6dbd9b3de17613cb3eaccc82861d22664fbb43c7f636a79234d5e89a6088d533afa70bb6953c4b73d654e9790e50fd29c4f2e3161a38ab95d6fd646864650737dda3a545819ea27a5d3082718a32648a8609eded64114b564a1a1a4a1b493a202131cc0e2e509712d259e6d2d2548a96fe404345342673713df93694dded3d614877c44f6be790", .Okay}, + {.Mul, "1e8f0b4d2e387dbc0141b2b0de380a0d8344ae56f775c06c7addd2e341f35f08761638e81aa5da0433301011469429d52e9d7f3e04d7217fd9fefccc2f7fa05f6346c0d39586d131cb54093ee8689c827219c022c714170ca335ee04e7a8200779c3637df376e09fce19e563a690f426a9e6f045b3d606a98d8938edc86ba506bd82f8d91cc340d6f39d195f9c910251683a31cab04d", "2bcbdc2e0eff472828f0ccafc00e6878dee9042aacdb026e9a879f53521f725beb2fff9db7bdfcec494c7ae752e753841376bab529de115e5d13986b2267702486e7b018ca20af87dc1512a2a5feb6cb37a725cc98297fbacce168c8fdf134c212571880f03e37d116672b3be0853c766107207d9db1229464b0aeb9f27a2f9f26cbf07f78a5959dafae757461d96c95534cf18c7658", "53a5c9c5a2bcb1a1446964d2046c0c852070e7ce41b1ae10629e3e4c06cf944b64d142d74d5bb85448372be63a4abacd31d0b66953bf8181df91a8efcae13eeaa53ffd1322cd8c9ad162b5b29e1a8a4c595fbc8b20205487b987273a7c6524e48620498e8417ddac87d552a429b533ed10aa5f95f106d13b3136f6ea276a3494214b1cc2a6d0e91e5f72e89d9aa76ac441e41f0a20b43942fb6843673f338ca45f39f3c778d3ea127c06e2ee0f02cd30b0ef25b983dc1945cb38417285c64614d47edf04303643b29024a4059cc984307d2b20172a0100338c6aba9ef3f9a57954bcded8802eb17bd449fff01df46641856469a14ff4207c0ceddb2aac80eb8f8902610c2fc417751ea03367346fd6160200410e5863c8ae383d5eb4ba24a7b4edb7b97b2dfffa1720c1878", .Okay}, + {.Mul, "5e792299720a5d47e7753aefb38f22922adf89dfd73791c5732b5761ce0032e3691c78076f069845d6640571f57325152d2888a6b0e7a563609386f9f8f9c8c09f5b7d1d363b095bb639decebfb3cd06d39b54ba33c13fc8cb70d5e657d62d85634792a69fae312664e35bac747ade26e1850dccc1e4d6347fa8d9d5a43e9c6060e296bcaed37113e2d5b65a7065a513e23229756daa", "e30b57d3b49a9493a28969194db9d4db9ac0af2a7ca8d98ea53c202229a6b97b1dc13b2fe45a73392900505e94ff9c5301e7f15e6877aedcbae75370a349f7b61bf17d6fdf14b4ce9266756cf37bac41a3ec5317464e5b49211e82ef12c3d448861beef29bdf58a6fa8f4db24a8a563c14101377fe7fe2dfa84573d092be2d0c82a9addd17fa7c73bbae5cb9c19fb77cca780e4a987f", "53c9994bd7f6f96a809b0c977b096349bba82250f93e7c232ce52a251cdf226813ff343fe14d618713358459739fe535aa37ad18c599c3eb8a49aa21d70d0792502c9ee00719151c63a07cc2e0ea954fd089ea835ccccda14fc617f87f6aaef11bd50882af245b3a05659635eb23a4abab1fbf1424e05f1bf6509cc938cc1a101202853c151b42b3b4c025722832da0dfa81693d67504b3c822f9f1ff89a21e853f73aa24cd52c4454d01c623d87d9689da55089a6576e568a6ff325d13354042d83969cc7f6b180062529745dc32f55ac8770e82244ea9a36e41d253ec882bd1eecaa1c648f14b215f6d77c767eef08533e337e94dd2409407abc43c40ec3461251d244ae848fd839e82de6f4e0124eb26fa8d2707e41aeab391ee9acef540a5335d3a48fdaf32149825756", .Okay}, + {.Mul, "ebe2cdb220f2f641710a3d0c9773b7e10c52048ce92e6792cd7c6ac94dd270d5014752c84bc6739b78ddb8fe40b3aaef919c3a315bb76a67e18e45bf76d220d0f2938d27842a2bce25bd605c1c10d5efbe27d66188a47668a9b36aac7883d122d852aa8f915b796c2c5f4f61ea516a9afb0edae4211fc37d382d6302c24678535699804e29712207d3fce7c96d1714d4c403b8a39087", "7df192f7b5a16b5037dbfd32a4215af675f6504d5669dccc1ff00bae65ee509ea4c7b7757cc779c32f3a6af98501bff1b233963c650688b96419d8d4b3537dd9f06d40bd97f350dd80dd2d4763fe5245a2e8211a6b4b7442e4435d1251e520bd5b5b5cf6466d27830104ff5e9c83254a4dfc81244a7b4af4637b0bd1afb19e8d3dcf123b84fd343ef451c49fcf7d19b2faad358d7230", "740c565f3747cc94274f00ec8eb66f7ac03a48c44965bba2987b760878302a0db71264caabc5dd9ba21ae8fd12b7f8409687bdb3fd973e46c46650e8af6028e9fc71cf57862d589dd47feac2e769c06a4e26e72c720977548139872ed778b61f850cce6a68b4bae4869ffea7b8e440e9103354ec867226b135dc93ab458651d1d11452edcc1cd1099dff007925d4abf9041c7f43452dec1e1f3eaa29bae3b2471bae70f3b73d9ea6d76ee61ad53329ef254934f54664c3b7060dcd961a024b7b04fee5e7ebebd58cb7c6c7265b733f4dc36596467d89ff1dbdfd7a844bb2a8165cb03003b11609ee707bf06891da1a02820b180af542d923609d5c8e4542a78cfdf93d2a70a9e09191d46df3b771f1c632b756dca61d0b518cf14d6bfb26494211c56ff590ff792902623750", .Okay}, + {.Mul, "132ab1a37e6ce3e7f7d83b12cd06af5d9da4c416ab893281f810f924184d0ffefb184516606d435f6e8961f8cae9df95ba428072b29f0c9353300549691f0181fc26a6cdf6ab242aa64190f848eaf0b0f828f25b2bab7d349444514d38de55a45e8706030aede8f4566625b6ccbd38770a93efefa0823e92a526cc9f212ed9fd406e303978f1dd0a5edec0225cf5bcc9a9d0cd60f1bc", "6ef9784127e807d46ef68d8bedda4fff12450e00ce38c863a950f31dd82e627ca29a4624fd5c4961d41ce94965ace7e5241ff3579f29470cc77d9c730c292bdaeef58a8d07891d4ad584f1f9d78dc46873b293155b0b6dd936997e8fb7450f552fd2978af6df599b178dbcbec1e0e16eb84bebd224a096eb98b28afafcfb82377c87630edd8ad5a34a1d412591d1a99bf9aa10d50e48", "84f05dbec715ff4748c1ffb519f6156beae6b6487b166310a3ad0a1b6dc55a8243d58fb3bc652ff42040359ce3fb94819ba349991bf297753e78638a7600703ea0b7a389506c1c2986a177a3fa1ad1f889b8fa3a28dcfde027a60858528d238a92c1b6d48c50c03f329f7441f29004a561af8f00f0e31c45b8c24775aaffbda295baab17bcbaa53931cc97bd553ce8b8ee9e031fac3a6972e0175a83a7dd276637abf37c22dbb1d409a7f3d1659ba3dc82ef0a3529ae783e96e086cadf9b51f672a544814fa09537a2ee0a06636db1536a9885666810d90f7d68befb55b1d7def71fa2c436ee9bf7037e45c29c732e3f4c57107acf279a91e0cb3d17bfd0ac984688b4fc3bb011cf538b8d9c02decaa88f14171fcd9d6a8d3d8adaea6cffd0e0d5750069de68191f1e844e0", .Okay}, + {.Mul, "ce2fe60058e9ff89ccde53b5b3640a1d38c50387c218de026ee74849a264f722c93467ac51bc2d26bb974ab07d4d039ffaccc8416be69ebc81913965aa17a705296e96407f71d9a44a5f49e1064bf9ce6565e349947b64d336905c8bf25257aebc3c9f79bfa44dd9c79c332e505d067d669686530c04494d544bd9155926acac30cf56401fba6ffe332e94df2a657492d3ba5ab860b4", "d556f8ab00bbb88980ec2b8c69f0445521bf9deacb9c7672605e75a927991da015d9ac62964f265b0ddad0586acfe1125bfce08078d7f955ff32014c87bf40817dc8ed994bffd92e1e6eefa947095e1682bd6db50114c8f6578a0149b741062f41b6ebddc2f72775a9c21ec715701ebcea347e98fc5fce417228406284dc0cc21f80e6592c6ceb78f347da2e3b6299b5f2a55135e76d", "abd3e6bdaf7eba35c2a4711a4d61da767ee0b5f682750033aa2119491fe9268d7ba5fec7caff01e5a572172c14fcdec0adebeff633acee5e9bd30b7579b69eb8ac121096f906f3cc7f37c50328cef86f6cfc1745d7c89a16bb0e1123de435712b4d29d0b76543a485cfc11a140258adc473e040948e7f96f6f4f93b36ee2c6d23117d2aed008aa272a32baef89cbcf492b92c6b13e5db8830ba2472747cb281aa47e746009549cd96cf46ef8b55019fda18758a3d8ed02efea6c92d72a2c14eab1e20589b2723ca565f92bac547a4e49f3ff42b0d23d58de07c003b5ebffb4fde67ee48dbc2a9450b78de840af47f7b30609a219a85e2d1236204eb8208eb9a972ad1550908aff9d8c841ed9bcebed9499ef1d40fa891d49681cba74dc87a75f8623a8b5a35ee8fdf90798a4", .Okay}, + {.Mul, "49826afc6110f3b30378f09934f217c40ae45587020d6492ad6d5ba6f486966baaffbb4942cc1929378bb99eae474d84cd6e634032d26e3c9e7dbc0161f1c3c820771b41327e4a38ed84968fa7b2fce0d84927abef551f54ad7d6ed78636cf87b2f8f225fb68791826c3d6470455914791c95417ee127f90ff7a20e6a56aab22c6def2d2157702710802f6c7a0118605f94f1c668835", "d357fc768421c3ef9f4bbab8cecf0f55b0a62815239f1082f3c07c0f786febe402de9fe88f7730e8d955ad2a7b7d91e22d91f65e95018c139356165dbcc1ded2dbe29ac7c5bfc71d4482bd470cfcdc76e1bf61435132b4b73c83fafe0cf5dd8aac2a6872472518062227ae7a3ee0ba5c3b374b1b9d411b35537f140340fbb2dbbddac8258724bfe0a5bcf5843ac6d56280fd24c0bda1", "3cafc1fec924a6bdddfa8802dcb18f374122f9fac800aca317d1d1088db8267145eae44cf9f5c515facea32b1f367b341b4e33a78121f20b16b795c4f9527739c888a1467cc15698b1fcd372396e600879633909b21bf2308543dbf7c077c36f41fb96a990de20667bb3577233c4cf569447051a92d5ff2837aecfeafea1649758f6d7ed812e16a91375c02fbb0bc9b7b9b20fe615625dcde690f0ab68a871079a875d2c8231587faeb3ef1c897b20d2ead0991c0be1f83fe4bf24d302a1899240d0495dfa637b5dc2d0025a82825d3ab66fbbb0d164e9757e84d333f5eeab9998fe74564f37f6381b992e655900a2feefd0a3421af637d50f11ab0050d2cfc9df84887f83321d892769e94f9e4b69de41dd55e2a52ddd1d1c1a2d41e8015219f2ac717660de07272acaca55", .Okay}, + {.Mul, "-daf97878e97f730c49de7799544d33b779ddd7cba65a2aa5c091d22dac8da9db478363e6963ffa07bf20940f36ebac677661822720f6afa1cfaa003974a8e6fb025f588c24834f0704e764f3a0d70a6f400f77d5b33c2afb88b53f2fcccdf9ff11abcebc119c02000c76d53914343dd5b540c9471b6b05a6a51b30fe38befae453398283e17ccc9564c0a534bff3a8f7c7d0cac47dec", "a2a3057c377855b0f7564a68a1c4c5c40bebc5bb714a68a9702e76a24074891f41750bfb933d73bf0caa41fd9d80331047372ecdb70b2084ffb0725a5f5d7c96a65073dd9dc168ef74e2a607e796da66c809f3abc343315a29ab75773afce13d83eab536af880fa75bc7359d8723832dc6366e946125e2227a620ac71c0d4a8c36a3445e7938b2b517147aed72419228deaef1477972", "-8b1d4fc5586291334578188876f8901d2ebf33bf12af194ab244f374c50878abf818661193c6ce21090d7a21ebb2818c78707f473b62659c6cda5695f51ccf8899e742756d00c1401c85f4f6adc9240ad5a84476ab79468e4bccb60182e9a5467f1eac98ae7feee60bcd469d9ad0d4e37e46d5bbb33f135386835aa5542b6b439f0e05e38779c1696d1930caea1a1c3b306dde0f22bc682662e1f14aecd0931a5e9202aa9c979724ebd060c273a8b1162a4343d8f320fcc8b57eb4f101967b3bc8cc1df20f492fc25c91c8ccbd2b3b31807c38bfe6221be422ae34f0149db6e4f2415b5238ce5b770ea25ae7b65bc0b5fcc60c124382bd82a41770d9d08060446b9c100850d13e39444bcc320ab007362a3b60523a1856b305cb6ad55a31fdaf2a447462d134204343789f18", .Okay}, + {.Mul, "-4cc85cb43ae57a3815e7b3eaaff3a07f0258ef60b88f1970d3293c3b20300358e316f144aa5b0dcb27b667b066b45019519d894d9149fb4b2d38275f46332db6e4682157480ec74c9502a673eb730f4578736c38b51cb3d469b0114987854fcdbfac6bec313a5c96cfe5498c339f0288fc4c7575edc44c7f7a756b79055295aad42ef770789a91f15b6cc9431397442336ce79688046", "65114e8cd1b4a0f703e5160ddbdb54bc972c16f30b7fb039c644ca93c4507d92bdfe488e361f531c3826ea2b09b0adcbe3a4ec931214ba8cd2e56da2a4ec849fcfa542228dea3481cb20b90e2f16895f76aa80b57a142957051548c1238821b5c858c32b916cbc74567655f0e1413a86deda48e7cbb97f88c6387b55a3afc97e0dc1aabc9b3665a63b7ec97f9130246e6a2fe7818182", "-1e503d708bebcfcf0255b37b80a5001ac43640e92a4a1ee71bd75bde6d23b4fd55e80ba63b7bb97ed36ec2d59b4dfcc0e985f77f5b50f664936f2cbe6f0aa1f577ea6a00ca57b0a2a188efc6bc1e444a3741d564655e6d1004d26f567ed121e86f75b71669755f6ccc0394ece52a165a75b96c9850db5a7d7d521f757c4623d61737314725d6f8962f654c815a8fe3c6b5608e9973508a5f2de723d582f9840acba7cedca2e3e26754a959f0ddb72e69f5571706fdb30a0aa642c4e76ea4db3c779b2a7dba39027acea9abf2fe0f5fe356586381ccb15edc23dd85bf4fe1c05f83262d8a5b69e1c223dedd925e77ba6791d10c4de8dc3eea2b7d5172478969894704ea3808d890b4b49be635d8bb4ab49b7489d3ab479fd552c1f63c09da6b7398916697cb78e2491cfa698c", .Okay}, + {.Mul, "f1e5ebfff8105f55d3a8998aa119d89c1bceb277d5274f64d8ed760f198e433bedd35b7881f610a09b4083986d2a62486e207e39037329bca4b75b9e190913b8e6914e7421f83c9fdf664f10888388ec664fd340c51e2ea2aebd6bff4cb5fe592529175e5d5a833e061dbf83f6aaae206d15ed7141d1d0d4aaa2abb69523c040b014898ba38b13e9f9bc7759904d2e2729a7b7a56222", "8e9baae3e1941a8fdf3a5c7ee4735306ccaf060ea9358d2f08286053ffad84fae4f534e96a7db74313d1b723a73d84c1ff9f92a14b82002d86bba4991afd24f4eda944512ff6645b646d58517335ba5cb0e710e0afb352cf3553d5682daf788c6af27a4c422abafa8a02bf87d326b80746f7d3a73d7ac1eb4d4326bb539a75b7b088c75454802b51ec700ef87b4f148b19a67068c936", "86c0a097e2538bf0df8942694127f5610495a70ebc9ee79847f1267e280b8b38798e8b5f67f55cdeb1cadebb7b66ea9a85ac299fa8a64ba9f02b827ce8c5b779e68f37fd2afb53239604993c5b4290725d6e3cffb01d096f8fce59350349f25bc912fe633f7915e7439671d22e6eb03059dd54108db87ad2e815e5226523db087c7975017b14de2a3cb279a816dd1111cb24033fba04bc46367c8af63a2fd7fc669bc4d9cd7bd68ccf87fc14a27e6a39b6c931bfe5e2318e94f123e3084f5dbfa84e85d8eb781331ade21274065d2974e842cf3ea2935d88c5fc3f56826c170a388eb77784d65d9242e85268454363d86c7ef20f8d7f45d60d3d3587497d44288cedb79caf272db0ce2b9be47a1297a5c2c84fdc7a5abee04398b4bf7d1837806abc904bf4bb62bc54bf652c", .Okay}, + {.Mul, "-2219757bbc6cea2601fad010629cfa8ac43a77023b60be3d4504c1e80cf44eda7976507b9ead6058b810115f836d9dc2e3fcad78a21db0ee615e90cf412c0f3e0b4538f29924a4470ead0221da78fdae3243b02077209c3e84e936b33309334e5246aa701e7f76e8c6e1aea862e1b7d49bc279db6cc6836810287e7adf4ef5113417622c37015d9148d8297368b0bbf749c2116777a2", "c7a58c4e69fcd9fd8397d6901b88e68ab7f2d20cc4a149069c27670f05431556a167e201a0604e9181eb433129485c7d1f7e977c34162e8df3eeaa3b5ffb6de18a4ecc8cab7069d4bb7bee9d675aedad1f8ca579de9b566cbf44838f4c0efd9010e12049795cc3b5a1a542dceb668f616ab91936729a8c72a733a8baf89c22e2b969869167e52413148e2781890c25fb73aa99e4f730", "-1a97d76c4658b23e2ea1c507515db320bf73bee013206486659cb690351bf79efc1302610f3792d1151d6baaaad76aa517bc0117c487b5a3f722ee14c8ce5cc5b22e663f0322622db1f4a503fd96695f0b20d3a9812d883cf1b02d585af9c41f62d74754a90df1cef62dbc3475e759105cdeead2f50b5172f8db93d15f6d33f203f094c158cd18340e55306e82c9bb834b05ad76a20c133d2f78afeeea2961f094b0058f225e3d7d9c71ba53e33309d7f9bed62d0579268ae6b12be5ae0e1b3830d408e119a9e1718957732e98e5514e8b8546248cbf62ace79e22716bf5e6a5568aae91d7302866090294aa61b3b6883e5e2457907140aa231b89d76915d5c5743f9b6422135ce9c4d44e6f9bc0548a96b0a2088a8473686bfc950fa033ec6e6a09d4d7430fa168761bbc60", .Okay}, + {.Mul, "3e9b62304654d7f39f2d3f744e883dc51db2a72f2d80e094deb0e49b78a05cb7bca825f54a6822b486dabe4b34006485d5a796a5a829c9374206d1f6ad69c4315b0b8f0424b36305073e7e56f8d5f573172f4869dadb9eb87f657da0309001f86f59c1e39a48bf20f54e1eaea878d3cc2a19bcda69ed5b77b75e231d58b16f47041fcdd5215f81021ad753db8fe8f7d492c837a2103d", "55512075f32478ce6f8b023ac64c6c9905f071ff0e854474df84d50471ef5a97d1de41181ee3e901b648f4b70b29fe1e97b1128ef7923528af9897d03784ba63284dc17365b19c5d9692c540a2f235b2276bd302f09a148d76a088b9c90bc85742891bbbc2d1fff52cfb03a81720535158cc40c7c19e3c526c911f38e1875279940261c65f40e78cdcaae4cb61ca2eecbc4abcf52175", "14dd6eb45d60beffeb97f8d7ea8365a87bf2cbc1f0943eaa6fb9b65f95f08495fdb016e7690b47a491f2b8c9724162e7aab7d85c795732b1cbf5224eb6770c4de46ddded0d90c9b40db38876bd09a01b4f102943063f4cf07ca4ca1987b4118010a14657aef9ba380b8008873092bde6f80f306deab38c34e36317f902263f05a6b8abf6528c89f11790cd1535f167b14ba976c3d05de9b91464493bdb19a994609f6c937fea684ee560c40d742257e0f01cd2ea376017b63f97513b3222e1f15956edb6dacf64750f55833181b77e395b095aace8f5904c505350fb8f860d194f33b67873ba04ed87a34dc9d03a3c561972670ae556820b27d0c908d2a3aa799fb1af621cb792803b91f119a87138cb140322fec6bb55acc5b2c96b03213642fd11e3d6348ca455a78a48e1", .Okay}, + {.Mul, "f280853beb4988c552a479b9337f4890e2e3cf91fa9ad7f113ca07ee6b8a5961a9d5b2959bceeedb36900c036c1e3b6e1336ba111fb96017f09ecbb347b2b95cc91ebf8d47edb72b426933cdbcc6ea68fd7531119a138fb7a90fb1c61a34e44e9a939629dc42b19eaa214f3a461ac5e233fe950cd0187271f83ca7a7cb3b8c5656ca1d50e8dc0465c12a3bf4ab434ec2866e868ed346", "37f40d09eef02154d4f8193c1ddaead8fd1e027f6d2a271116cf8ac8141ecb570f01f3f62d55dbcaefbf63b2acd2e465c4d6ec849f46421d5e589fa6b1380f9eb145ec5a5f31610fdd49384f52946cf64b63784395ae947d430067ec212a0c542fd70072147a41b8af51a730994207a4026453826ff6a2e3efaa09d93e57a6ff4ef94382edceab4e185166a6d59bf30b641d2791b0e0", "3500cb78cc48bc744c5cc4e09b6fa850ae0571d59b1ff80f6055f49573b5125f8e39497f6849844412922f56ad66f774ee777ab591609015a31d0b27729c03088036d698a8328ea73c6d92cc9fb23296175c738662646e90ded66f04f5ac3d4093640f801680fa8f07b737ff235ab822594db96b7c1e5a04910d1a1b680f3b79b51625929244442b281821682a03372b9b6e5c5abd11f30838d6627296466ee1ac7f094514d51208cac0151e24645a165a7bcb3f24ed7bfcd4edf12a3ab2e9777a9e28c1f352ac600848dae3b4bc777cfc8fd6e36afd56396651907658f1830bc781128bcdf819c301792f0444dc9482debb6ea73fa63de676221e8cddbe10eaad91c4c164e84b3af60b6fda8e722726d40055ea3a73d9301f52976c1a65f004b8a04ad93072dd3b42defd40", .Okay}, + {.Mul, "b4ebefe95562f698cfa76676a7617d46cd2ddde99ad84f6f287656587ac90ca77e0001691af627f1e05bdf9e1439bf79ca9c9fa79f2fcb1092cbe6b83d9ee1d7f1107132b979c2d218ff225eae437a50c26591d673102b3ddd3133bbb607c8e5779e50793c4b99312abb8730ca8fec671224ff47215ca27745bed5ad554cc30ef1d94e33c4cfa112e76017980c72fbf0f1c1e6dc7105", "5175e9ae587d51c311b02d9ae3ae272054d5f8cbff877cb055b2e9365d09402b460d5da0a8b2b5550d7bba348b992eabbea87e23b8108886a611af4226c148d4894e61ec63415db42659d494252017bf25423fa71d99d7cb9e32931d6ec12a00ee356a7ccdfea8c696b03f831d600cacde328d2e097b7bced8ce794f94238c97f28dde2f0bab14018294d6a51144ab4890059f407d01", "3991fbe36dea710506a905ff88ba01c850ffc054d37ebb43c3aaa59daf3cb95f970b70cb4db946f4adf9f67d2d591387f8dd19524c65bfa8ac25f9a5b9ea92cde94684d0685e669d8a93f9ab0af46ec901878cbd9073870b7b6a0c0a767e9c7b6bb4b4cbcbfa8456704f24cbeb407cd9bc680847f69d38da5fbf29e977fe3c2e2b5ae5098f8960f4fa074ee5bf8436872c7b584a2616b0ea99c91150337054717291630a23f59758e6bcd6ef42c31e3f2b7cbe771ecf607d0b7848a61fac80e0303b4616b971f584753d8ac767ed3d5ce6f4f77465fb1217dd8a968df1d9b01cbc8fa210d910128749692fd08b51404bd6c899cb6cf598de8780ae7501b62cdc56e3757761439ac0b1f4f0e5e1246f5453dd965cac7c3528285dbc25c132ed23d09e2653232245e2e64be205", .Okay}, + {.Mul, "-a1bfe97853a40779dcf6f9dd8e79ca1de1f4010940f1a5fc4726695493c1763a88ce459458bbd9eb5dc7e6c2e3d7a1d9a39e05bdc0409b41f6741e9c5f04fbb65c3f2ad83c948231d08d7d770caced44a5c692203fe6c0c089e8463444ac6383208f67094b1be2110b620cf7a9a6eea120ff3102862399ab3cb22b8dde62a6a1f04092c187fd4066bf5b7e856f12490af9925f47a5e0", "e6859234a5ee17ac0733193b29d6294117c255daa71512a9eebd65b9ae01224c45b5dd9c50a0f2b60f93667b6b13099b2dd108a397e97c5663a9afb6758d41ca0dc3049d203a6dd1a2c31eeafa5765333616190b1980bb795c9c4691fa1856961b36aec39bd95b3e4706c1f536178f80849dfd8081751f5af37814f68934f2776db6c6a2f34d6ffdbddd5f7e1c991cd9e34a1b1f0cb0", "-91a6d0d71da1ffee73a865cdf517e42c6ab29d6781622a1a32ac725baae9a4849c44e55eacc2ae8094ba8b228375c532237e980b2724bc6371d315b850a23db32d0213865fb8e9806eb51a64bca2990562cd47f5f7c970587badb3e2801967855f43bfbdf4aefb1e0084d8fa28829822c1f3902bc22589478645fa7a270bc558c424dd3319549e790bd0559e83d0839b5f43f3ff14a0fa421ff2059aeaa248317cdb0ac8a92db62fdd44432b62adfade08593f644420c02d98a610c8202edd9e157d75c8ec311c002201633fee7e723bdbd6960a8a349801b8fcd449445d1fb1b7049c63090bc571b05cac54ce8e75e8c8a2f19ec4fd6880feebb16784a16618575c5c3f43702e3e8ffd01b34e729ca725d54cc0fb9897ebe71cf3632b86e674920a643191b01c0493288a00", .Okay}, + {.Mul, "f32c7365d4869aed370a90a7c280253415d44b110d421b738ed3e5180c27319941150280c10ea7efdfe70dca81bd6e51abd148f9d3741920d80e2bc40a4263186195e3e1ca9e859f3c22a17b7fad8fda5652565795949a8eb910100e2b6e56a9a698aca0a8a7a7fe2faf3c95071cea131146d8f40be5fd562b825ee8775f3350a45095d5d854778cd9ec4e3256ed43730015a6002e2f", "42f20c8ae6cb67b90ba687f3a0482924bcb6645b3b8d23c02645f997f2c49c415a0bed9b51ddcfe7eae2d2e75a6f767c076bbf7f2c18d32cfedd487779a3bf099bfad579b1bee754bdfe07aef478abae804b81a03b5f55be0a426eb644662a8b34a950bd9f2bd7586a1f7338e3c1aabc8b3eee00e86ea3c75e4902d394a54ea25be40ba385cf3291f9398b2bdec19ff52243094cecd8", "3f9761af5da7bc7e23904faef0d470926468e4a570350b5ea75f2d01c07f21188febdb18e424f0a4d2ea30969ed106e082a9c2444befa49ea1eb0b273b37a5e717c608708e580ce8f1576b7b44fef8cb45cdda110bd1a11d94cf0df85ad49e170f5e1d446e6cbcd7c4b566c7ec030e1a81bc3c30c17fcc65d859e9605494463377eb98ae87a8479d5090bcca36b92da70ea29c848fa7090af58fe32b8945901645d322fd75116aea682320e146ff3be2b917bf4ada3b475393c1e4cc030a201931d06829194b472353a1f8d81f8d29a1e2f2e934d36c8b1e0923980634ac581277ef84ee147d55be186ef76c297cd5268c395a7c130182fd3eee501f8e4a3d4c40a3ad4514541ca423fce9c5272525937ad91dbe3967ff4201e9507d3f72c17b916d97849288a54697ae4ba8", .Okay}, + {.Mul, "70139c1475031dde25bb11c1e46d841da1c443027e61ea7377e81c3fcc3610d02128980555280534b4c04c8fabcdbb30a962db6aaa0870f153701c4ed24d66c45598326b51c4808f9c6dd83ad0909b8010d9ac9a811509c05fe1ab52db8e46bf7503ab493c5de6990a862d6855d3941e2d39cc6ae5a26ae7bfd43cf8ff63313e6684716b5cd509b03e2ced27f3a85ef3d8deeddb0239", "f118ec959fd00102780d98bdaf4964eaa71954882d96ace0392328e95a0aca09d60d6a4a5848d45a03d6adfb90fd9b52c6623ef11469808bd1fe486fded50ec93a7d5ee4fba6371901388f77f373e9a5d68257a15bb156b4b96513aec311a81a1ca6008f748b4151352a22658e3606b891052e1c07ae1e285ffe584da29f85d8bf22d5757adaba606629577b789a00cc56618e73286", "698d5f597956d9809650460ffb51db2fd76b3efd944932016081ab46e262cff5c1a1991d40dbb64702f34740335f2545be98d2b3bbf3f409fc0ee8dff0aa769d2dd1c6c747e46c71c06e55410db9c674448834199d9552cbcb0c6e8fc3b718d046def309777aba1ff111d2e88e888fb4a5fc2d19d96580515ab6d222ff4c1867e320d1cbc7d932139e0aa38d7ada92846cb355cf92cff4102cbec0d725000dd2081adc59e64e14c3bf924be22bf9335c01e683e34274384375b4f820567c3806a732dafdf02de1c1e742150ed3f7ffd73c6d94249e7d33fee59aed75b8b7385cba6566c13ad0c8fd018e6e17791f8ab5bfc34f6d3c0d169f2803ec67c83e1347e2e1acaf2c4774f0abfcb3e0fcb3d3c27e36dcc5160ba53d4f35c501745351b9ec6e40ff418f7afa0814bd6", .Okay}, + {.Mul, "77064a6f00382cb3ef7b8795663a6c742f72e6d69e04d37163df78f360e038d0cd8f8832149c0e54336e33b86c15e81a974ceeb613f6647358679e7e38db6a1a4356cd89bfe7b0bd456a1bbd39f23c8105b6675a875baeed967ec8c09cfe9283590a4eef6e924cfd96de7addcdea1677934507d6758f535b3e5dd5c316d24e333366c9eb16ffe1e4dff3999197b190e68b0cf8e7a844", "7253ff5f04e0d2a0ff1ddb909f7974fadb49bd062d814e7e3f095ac8871d1d66959f8b845db0dc6ed89408daa44c54959b1865572812ac317b1e703b694bf54d44a0011dce7ae90f4ffd61f233738a7de88cc80933eeaaa25a55192041edd5cf6c54a1e9df0b778932ea46b457f4ad48ec0b7fa9f4b862900fd67f8a9566378d9998e1ac9f77b3a6d8954d0972f663dfb941858a1a1b", "3527daeb01d4e720891745182bf97ebc187514c6d1a33831bfe11b1a710bce2ce14b42d75390bf57253a0535c053ed6d4d0a6f43515731d5b97b921a413e4e174cd5e7f194d35abb64c5c33ff6d0d8551124d5d2c9307c678421c133ed105e27e53994a2d10f82a503d339ca9381bfd92d72320b51bb3b120d24350729a59c1c7578760e0dcb7bc4a3771c50c8151a839cec1c991f6f34ff019fd5a0f471206346c3db2f852ab7f4c31dffddcd9b6cd2405986c6526e9216a839b40d63ed1e8bdbbf2991b7f3e06175b8256a0c08db71b8ca9b9790641b86a97c5be84637831de2799fc5c691a513c22dfbd49734b30053cc477af9c8dec812a1769bf481b9f7221927cf4ac24ff85d5ff68d87caee4d5e4f54c97bae1b4b31160e1a0bf7219e4144fa56df656035d02da72c", .Okay}, + {.Mul, "-bc57df80993211e647ea8561478c45a2149e482122ff90fc1bc30526ed07653ccf97a933964b843c71df1931bfc58d7f72604fded989c3b7f3f2f5c835823643438319af7610f0f610faf679393e71023112b9ab6f10c5f7eec6b2d4a5dc8f0aed3efcbe4e501911f570a056873fb5baa0c5fb44bf3e3922a349bacd8e72707ab1fa4fb9973aaa681a09c16938d03148e2cbc4fea752", "cf370f8d2b27f2e76f32e40237bffaaaa05abc5bfac799566dfe9ace2b9f30ef4011d3f21f2535a195ae1ba7a3a6d3cc87a2820ca46966783d361bd46c7b87fa904e098d83330c4657707a622180c452a089ac357d5d21e92869c3f597597d7bdff2c2c0dc97c26fc05e56a15da3d05804340c7b3c09c824b783c55083b3430ff6f978da70abd23c2e6a26e6621497e8978f10838351", "-9873900b02bf2fac58f4f798f24d2d1ac151be242fd89aa878e5959c7c2b7190b26956f22037299f0c576f4dbfb2ad342dc938c1cfc870bea50f697948ecb9d8359a589178fe57018fd3246c4cc79f043a410fb88622db2daad27ad61dd11de8d6288944be75cb3ad5b2c60979ef07bf160c28330d61f64b24ada37b4a0cbd33ccc63f03b1d54593027733d73c9e3943615221d717c94c23f887e5a7fae2c2377a3a58e2c365a917453d1043e7784b6cda2e5db5de82ad0d5954489f26dea76d14c30eec4c821f0c73c5b82d0dee5f935c57649027e4fd26a0da3a8c00eaba948bf1ce1e93fdc463f25cca35231bce4741e1bc42a0ba104155a55c24dc65d015bd68b6d2a8759f7b0f412e47f07e30d2ef315cbce22572b342f6aed314ee7f8ebef35c76edf495da6327e6f2", .Okay}, + {.Mul, "bb3c65e06be56e3275b9f8b8629fbaf5c295d66748492bd1cac65c014e4cddfa371d4cfb74220e5dd0807a4ba6d373a60cc7fb019f63fee16bbd1796c0d56a451705064a51a62973abe2ad04181067dbcea282b6b5eea112540e262f442cfb03c0543e46a7e29e3db361616519d743ceee20d30f914120750fcd8488fb8eea0c0e3af7071261ec2d28669904c44084a49caa079e9a6e", "89b4e08308fe8e93f98be4a122599a0be5bad08acf88c833d442d93261d5ea56f9e00065e34d1b23d00f267db9efc3ee291dfb3239d9b5029a39aa71aa1b4f3ebcb3e561c4611ed896eac9b3f53e11beef4bc38209b54a66afcdcd4551c395daa38e53e284f262c096f928ac24ea0003333f94d51de739d07dcf193464b6f4d0a78ad713862fe03fbf37b98dcfde22a513e162b8376", "64b79d316b2a36ee460e1c98e67990c4dea1bbfe367787461684c27bf61302394af890de481779baa342694096bd301e2ad12ffff546a8dcb006c3ac32c34a9c0b2d85f28ff5caf1528f6388f853e77431252ec419daad5c5b967b4eca0b1294644e80dbf6adf011c179b3b3fc049aae99371d9838f8bcc447f5d8643701b20b564e013dba2ad58d3c975ed2c870afcda7848521c1e2e806d7ed7504100408dcd7aeaaf30ef37cab40564492d2d49295c8c08f6373ee0213efe02fec7ced2c13058a3f762033acaf849103cb6834169d2c529637cb4f9edcea41806f5bbdeb78e8df27879a0d9d96905b8ab1b7b690bc73287b95b452629dbc01d913831e8af050d1061302c3ae2cfc7324b9257c354a4858302861bf23e79e9fd2b3ffd6088deb00f61c69455d3109b78b4", .Okay}, + {.Mul, "-cc184e56bef73aebe4c8755090f65cce0b7374d3b71f26eb9e85f15a5f63f26b092aafa18ff38ce5be45a50367f7b1aa7686f13301e1fbadee7be450f998b6ca78a703be0eda5a21d83680c764a7eea9dc18dfe3bac3cf55f451fd20624554cb5e1f461d3ca72474c37e9a05985376e34ce30a584b0d6785999efb5fb2d733f33152543db5f5bd45b41a37017b187060787c5f8ffa8d", "bbe2707316d1675887d67e98c8f1bb2e13f0c6d41b52c2d2e64f3c9a0ad5fb0134275b3a920f73d2719a84e745616103bb281eaeabd308686b0fbaa050b46b292fd5778cae092e727c15cd0cd1327cc7e06ae590d016cd062d71b0e25aff0888be4e079e65a04a649e370358469138862373a2d17df7619d6627fd3785b8dd4b86e3f15f20f110d0212bfc690702b64e9f2bba7a0200", "-95ca4854e9755bc80c9be0d662bcfb5211dab80960b3c7e2b76e9349854ac0fc713045685f533dcf21b8f6fabf2b9fdee0486ffe5a46a461ca59f53db647024a7644353da279cde18658c078ff20ec63f19f84b989d8ea5f3af10f275c17da117826a73cdc2b1cc505dbdd4c1498e5fef1c13872320e516720f51e9d1ac1b255f5bfce3d448453a0a15c2b091be445672301916f8862c3c6898e2988855bbd240aada9e1b9f61583a2ce5471b1382155c70bdd4f2c72aa5cd317d2f44ebf2893777d64be2a78a8aecd7c61f87602c0afc45ae4eecf333f641e7abf8c7dd8e8f7787258aec93c3a94200cde7e364eba7f3a591c19d486582f9b062deeee5dc4a41493cec3fb0c4800d1f1de075d6879d96b83eb38c1204bbc02ae341bd214b37b99ef9cbb9867c815f9271a00", .Okay}, + {.Mul, "fadfbe0b2ba926d39a11878c8a305eebc50596e51feeef74e2749c21ba1368f4fef9b33251f2fb861e7d893b6ef6e620885b64f4b7e32c614dfef397bc14e5abd4e61323c37ab90744c351cab2eb1b436e641fecac89391610675930d5eb09d57da0f62371d126093ebffff4dabc49963446a4f40353238e31beebff7e02eda11615f8d376ea7181de61f869071c47a87c1d22105c0a", "b928b7828f3f0893d23b18524410ba08f3db314e5233ed5222ce7381218d38a268b25de1700dc921b704d60b08975e49c85c44395324278a61f2b90dc4ffac35afd0de386fc62e0cb9d1ba178cf51172f9c2f9da4b68febb8544ada24bffd8f5d7d0dfb9af5039fd36ebfd0b9e80531eedc00e1133cd61ae71563e3fce74b39764b36532552a215ec4444e07ad1386249403b726afca", "b5739721a7254dfeeea0e0ac2dad05ef6506e0f54c386cbc949a2bbbc01858c678bcd85dc8e64ca74000346106435557dfd51f80dd7483a5862e0caf611b576ded06dca36f4048e4905f2943d09f1f2926167a8c1a89731a1b368b4fa0537e5d098f03f19ad5881d6fd4cf135fdbec2e94d1b80dc198ac6486bd69f5844eeaa2511539fddd79cbab06c5b5862cb0c8c6e707e74b62feb548eaae6655b587097ecebb4580d72834c9c34159fee61fe4e7eb1ce71830cc6885bc94ab0ff546428dd3a657e42363b8425449adbca4504f16ff38293bc654c2b18a82c3c371a12c758439fd563ed789cbf3068dcf5b6702e4fc562edaf578a25a01fab34a78cca50f35544e8d903a6479958afcedb2f4fc057373bb2be877e5dfa0402d5bec7a04892c7f42490045759cdf4f75e4", .Okay}, + {.Mul, "-be4cca16b684c35f392de10b574c3a687411349c39a56c68d47e721e29ce29ec81ec5bfec0d47ad762e45b293d0929045cf8f4e77c5690891a0087581642215a9b4a77983b68ffce69fbc32b7904a6131b6530d7a9c8fbab60f9569e9c588fbb1ab9cdab8eaf4980cd01e90597604c31c4bc79b870a4c6a82ff1c633599d98ff2ab81c5b083f3ac5d66c2ade2ff15f35c5ca4805af87", "6748fff13abb37bae2d760c54c3d4315afd0af30dc96f25b5f0d766e4d72d31435c57734806c5d54c2c8df0ec8b0ae28c16cc29f7e2c2f76a6a7108893db44130d1c5fdb59a0dce72daa443531eff1b6524f9822f1a6b3f39fd86575c1dc1956846e336e9dd57aed2982e64d6ae356818e6c6a1b32d632fa734406f1465d99853a22db23be01300e405c88c80c2effd98ad65fe6d253", "-4cc72929c9123070842852d70a5ece9a6d2034d27dfc60ca89c4887cf4e96dedff7b2d622431963086a1274ca8f3cf32001dcb3c775983b1f13582a8ad8792318de6a92a22a2c674ba291ce6a675d3d40f7a1829033db2014887add94d716d81e897d7f461d3a2258ab3be9a82532439c4f0f7dcc74288ce381d35aa231e3530fc3ed83bae17669bd4bb696a55e6bd3082b6e04d0be3f9093256aa8b70fc36ebb9b3e438e7fee1eb2e0e783b099a9384313a1cd1cdbc7ac55fb093096d1e05ab80d515e4e544177bc88e7b60c2d303679d735b9e98e08add626e5746247f4a737e846e1f17be0989e6b616b67128f8de0f1ae6d2809d00d84ad0696393eeb2ea4330a119d9162a9238bd44992dd6b4b02254a9d71e177fcd36ab6305a2add145970d00e846f461c2d01ea6c5", .Okay}, + {.Mul, "-33efccf6e853c82ab37adf0cdaafc6c3471a5426c2a65b3a584537738060518e823eda10edb8a9ef854373c740e721d1798239ef33f05a67a0bedaa226e2f0622bc2da2398afeaa0398d2a139f9a3b42f02015e855ba333e07717c0c58631e78c87ee5959d3a5ee68d4f90529b2b5e6a640ccaa50018d30bc7a4cc7b6055390cfbfaad86115701f2e8700313b9555f8fc7a8f0a373c", "3e0b26e3a2013a852c40c977b377884bfcaf7c41a0bb92ddaa54ec54512cfe7aebb5bddc4797d04c3b6697455634bed7390dbbe55bc3f8ae14ce11c014ad1713aa537bd963805a68994ead7a8eac8bc69e680bbfefe2bca4fa13a1fa0207576765e7e919f8f00bda9eb05b01cdc3acdc4d31bcc038d36b453168ccfeff0325462cfa842d3692da2fd1e8f5e04a746141170bb068ee54", "-c9656d561cdab03c84a02c3d0aa52ffd10b8f4cbb49a8bec351d92aa86d55e87003a4c4b7223e25af0b2db0384dfd3be4a17a0cb133f4f1bb3470026dbaff14eaa9527862cecd84a40c00ea2b240390d09e8f2aa024dcb0662df8f25d90eeaa249de02e358f55a74ddf3441c01b0dd2be2039a20b57a8a539f69bdd2299a23009b1af11c0178a292f3dba601609d1acb4088332afa2182c6b1953ac2dc4ca3bd37773ca3a5bf7b0be3735b1069ddaa4e798d9b1bfb35858f08ff154f2fc364bd5e24e85b2972986a3d2c35dd13fb1637f068ed365e9ae2e9767ae41f3cca9e3fa28eaca857babff14765c883f62cb0f36eaa88291501416f7ed11ae4a5806e4a17b94f0ea9e827d4a81108522ff6d561a5c7a05322886ba58044cffbbaa885d61de97c5730aee61f13e7b0", .Okay}, + {.Mul, "-1781f43f7f8e106b97560c2699c2dd6d57a71a6fa1f809426a73471be5d52ddd39aca69de03d587aee207bc9cda225d55cb04bb0df38b8424e9e3bc8d1c263311bc0df0ff03c55ead4b5b7430559a72cb946f6cab1b2564c6ff4cb4ab513d8aeb58e894ee0ea774416f3a5aa05708b7601aa32fb141aafb70dc3bbd1e1280811acdfe15537860dfce2cab67f268a37890141c55b3eff", "58f6a2d4dddafa93a37dd02f0531dacc4b077bfd27e742f77eedd847db87b63ab3992f99b1aa9fa8c7b4c67b2f328df932d7df654639d3fbff024990c50d6b3036b8fa7098f96c8b0270892d437bf881758c1476ba102cd46962a457d0538b56166d8439aec3e05ed9a8aae4c4a62dfe8f7184ec577aea91cc0b4f4d6aff67127c54f59a68367d460be5dadeb661f751d3d4e7a6f67b", "-82b51ca516b26fd91cb81ff29c82bd364fbd6cab1b066ce0dd6304a61c03fc72cd46a3bccd7051b68101ecb3446e3fb4f3a89a344a299c40d9f6389c8d7dd4291c43a2770afd2713bba377659195bb945d2e9ae980de168dab48ed233b0fb1113590f932d721d9b5b02232d92c09a503a9a02aa3ac0df91b35d596f5c1bfa8a93c1dce93b21a032cb97d1d69b68d6b42d83cfb674cb8e42d681a56158ccbfa14541ab27a85fb073502f3ef1a868cec87050fb758824208585bd45bbf7ea2b84c6a3890fe945b836530de59c0b1d75fd7fc1d4eafcb4c76a2e034b3186c00338436ab1f56d6015a68bf57a0082869af6a3a408b0525dad5378cad43e8dff2311c73e4b52425ecfc5e37785c9e7e7815466466d4de7276578cf571db9ede4d1e4c613dd271bef756e73ba4e85", .Okay}, + {.Mul, "fc7e80fe7d85a5d19f46a30f37a9b8d8a026b6bd8cf3c9773805054fe2ffbdc303ffa3cda3e747f51e9822a8a8ee88806a751dcbc30a75452a609397ae8074883b5c284cb2eb3a1224efa20055c863ee4db847f4f724037bd1e8643b4b8b822e65363ce3ccf41e15beaf8d4e2a6da9ac0ce8be6ff82ed1fd25f69c21ba132daa19e09416767860751a5ea11453e1e83e5dea3ca2028a", "bda1cc5a5b12a7b514b4df4520f6fee7dcf27d4c4db5a433c0748628e923b89e6d254b5d7ea2bdf8ee3162d075b1207907514d2780bde8f9b8162b964b1ef4edc91dba573f741583e80dcb204b1baa6a72853d5598c4733aaebc364d921c26245da8cdafbb9622482bb493308d799a7d26efe2276326e987cc6bd3faad19fddc0925adc3e4bcb1c19bec0a6727f01dab9ede4a3cae60", "bb08fa58efd0202055127cd2222da1eac13547c17a775204a5519eae8f065d619f26a18d2599468c0ef99ffe341102c1858e065caa44fa46c429c1f6160a842e416d9aa74487ce277cd28534100550f187dfe69ee3588c6883012fcc296580ad0b05e824af6c1f39c38e4c45f2117919767324cb5a18da3b91d40460fdfc3de7fa34abf1b16a2fb8000af230b75ced9078c33887e68e4a4960d77ef1451ea84605c8f467b639af4100dc2813090dc935f1e206246b96cdb528cb17a0c1ea6b29e347e996bd4f2c3062c070992407e579c35941c8aca83b48bc8d803212f484195c53f6d10fc661dc21c2eb03026d47026a7f24abf2b022438607aa7172e3df0f267f3e202fd117f85ffd8826bbee7c813b8576d88a45cf21ed59b425a2808cdb46e3bac319e2d76d56d2bfc0", .Okay}, + {.Mul, "20fedaaf5df55c45513a89335f41ef0f1a8bf23a31bfbb7b0b07c229f1c96fcb3c99ddb5199baf7e0cc86879b7e1203ffc985047671c9dbd1aa4a9cb13ed999dcbe65f4532ceda8709fc5b2edc3f74bd6bbff939b5a8960d3c5a15c44e6527c150724963fc49a2e0ad3ff44853e03cd5809412cf6ff8ea2c7b7d3341b17221e030ada55937774ea89f731e5f711f078976d95bad9647", "da66a0990ee779ade0da2fef31144095d6ae77e92debf557fb87237095dca664a6ccd55d9d358980958d7856f648b037826898b01b4093193986b9ef9cadd1bf121bcad54d4ce47f6d743e2fbf45323217934c107d141704d4b69b124795877a0bcd6ce104a2aee7fead55d556c1fee4a33431d03cce268a8dadc0a7118b3e094e0ff2ce4ec84aea4cbe6708c0060617b8022e064883", "1c2640777acc737a160cac4559b0466217e1d75b1a412ea838ab795c6b89cd23a8f5099643351fd5a43119b29c51abb8eb1c539e164690b818af324fe4e5bc207644b0342058c0b959be64bcdf38c0073196258bbcb5e8a145e81b1c0555543432b8f40139fcea401271b57cd27635b7e80b0f0ee9d576f291701245b44e01e9f209d341dce9087ff04f6c03da7b67ccdc60b678376758066b4ca67ce7bbefcd0420f5f5c8060c536c3fae62286d7b81737d20a24f4d3de580acb8b680d10f4896cded0629db409218c08c01ae41579d5c9bf8c7dde887e132175d8b5ef333f02ae8960ea6a4d2b81ead2d3ddf3aad018bff221834f049508b6429b97d9c4944cd948a3c62d360a5e712c677e0005c6e1ad7ac47674475ab04434057bab00a3ed8e7b8f302157ea303c1de55", .Okay}, + {.Mul, "-4af207db822fd84f4b8909a6b870a7316eb0a86f3b84025a66f9691dea7e8e8be2ba30470e39c29f2462990a023714d4626d085e43f43b24f849b2ab0b51178ca705a85fb7546ca0440e2012474385439295d32fd197adfd0f411447cf317dc7e3996ade4ec08dbdb4abaf00688bfc74467664e6917ee5e6bd678923b875c254c2d649b54d7550a0d961ff010e8be57da9d3cea9edb7", "53c0e2ac230751bccb03b9257df9c9c1a6db890a89c8a349d0bf1b38ac670802ca4a533f23af5856bc940d8c8135479b38c7c292cea08f46400c92d892749fc18890e32e6540c4ba6e52f4ee547fcab95556d81e6da55a0472fecceee5d7827f13030b527afb1acaa3e754d68f0bfb7fb2ec103ed3197767d3e7cd6c01e6a5417edade9b8e4970e353e7de7385a5614a7e4345be2437", "-1884f06e1fa5730cb987c1698ed9ccf209562432e653ed22a3782d48e66fac4a8ad872b79c5bef061a6c5614772f8d79d37426b6efcb06edf1f9259623f0d0116b3208056de8b11b323b0567d8bbd16972fd0260567b39185c1bb4710c5ef243afc8e56f3a5bfc7c355878a1e97deebe761e378d4a47a19bc1c27fa9b08a9bdb23749f366280f83f17397315e255db89b665bb8c8ab62503acfac8288bfb289bf9b57df0bd2c62853e0e3cc7ffeb033072fb538e021e020884b14110fe0ae638cbbbcd6016b8aadbb1f50d5a3d1a636948138e80812b72d0359c0c0856fa49be38205420e45df9e6f266470ac4febc53782a93aaa5d6da97c316a9e1c890d0cd1c255e8d27e958ada6f3c5fe339664ae7e9aa33fb11b2e1753937f98c1af2c59a9321aa8e327bda70cc1ce51", .Okay}, + {.Mul, "41388e184aa7c4e618c50be3c5192f57c8804c5833d5f1893fcf9530981766d7d72576ffd982dde4af2c16f7e37983a7c2f0070ccd47cfbd2b335b34c5d5a5bc535ab6f4c1c04d414fbdc590d3cb1b301849bd1f83250f857b4f66b6049e923ae299888af29e0bf5ede07d3124619b959a4aa1fa85ba7ca5c39988bd6b0a98391cc29809b12302e3db7d362c0f36ddfb8b39a23a4a7b", "28d126a8917d3411890c1189f55094cd1396651cedbc7fbc0b40041a0c32414438e9a4329cdb6e2d59fe9efbe24ed639f2f23b89f78dc75a63cdc18e5e1f6a8cdc1bc91264dde47bd99496996fd6e0165a41d2f59d1201187e8bc0f02b7eaf9d9342e15b3ccf1489bbb4fc57600ca5dc271f9f9a1a835dd9f49f152191ff7c9a5b48f2b020bc8e000e8af299b9ed8d15ccb20697567", "a661f3924c4f31eb1ba91c9dea291b6fe44e49ed320691b6dc6be99892c5a2bb337f6ac0de41db35419040b061b29bf2ebc9d184628fd519e3ad71b1da84592261b09b40ce9f778a811f2e3d92ee768bad382233fe04b2155bffde1ec067abfad86bf0b4c611b2358df14c6a5e8f3e001d0f5e1b3d5a2c0a16789aac61c27791669018c02c84310ac646c8507167be8a23462cc4ada394b2cf9613b4a6637bac21c05a9f2ef8cbfc8e032212942456ab240e2f39fd488fe1f0f5f5b9d92855149d2193bea82b4f9cd45ed1180938f9f2c29cc0ae207eaec9f1795ab895ef7e60f56a74a4b2d7ab7a0636f0ac83f73627a0e7f1651c2b6ce3f3c846625eb31219d20f71e0b8679e48ebde440f7e889635ce92b24e0a3dab5de3534cc4bda9bd2d22de73c3297215d5f12e7d", .Okay}, + {.Mul, "-2dedb991c08d8a2e4a9203fdde8dcf8deb2dee030f7280d50e15dac8e07df9c041727f392714bd744f9d315a2a3e4dbcabeeb0263816bad1d79e63e3a13eaf49f5c26331941d8980dded14b598f8cf36940bb1d30579e88a9d395d05f24a0f5e399d0a8d34bf41b7f7705f06d572f12d808314f6d017b5c8df0111d550f4ef606f0e4f7e0f83faf9ea894102e63190fc83d9a9e6b2a1", "55e09e29f450dfb67831b5edbbcc3d1605d091863c716df8960cee5513774a44c216c839c95bc4b09fbd466e3c0e15b27bf2d37beddbbdd7ea2c4e0d8ef9bffa1221698641b5ada042f347d8969f2995e02ad63c53f1e30e5740f6607c94abfc55440663ff428ebb4d1107fd15ef7884af476a121f6f8e927abbe89d45893d7f14387196e7815f2e085957038ae6813bc619086f37cf", "-f683b0003e73f353382c0f0e88c8634bedb8000c31e37008489f4240e65c18af308c04d9758b4250bba320fff15463d38e859baac40a3c81ed9be595633d7e2ce84ec1c54744477d5941366df77988c7ee4dbaa6c701b59b6027d28163d0d7e24439509886725b3c53c7c8127367c383e38ff45a161227691e924f0a1d2d43901c9cb69da4976e61f8271bafa2368c5401f8d742e21ae70e3cecb5dc134404dd4fa39d39f2766549245cbe0ab23567755daba79c3878814a14aa9fd881e61e7adf07c627f30c3c78b37e69bec0876d3bc70ee969ed1c579145479d467c8f4c708879720496f524944dbe5ea4fc71f56b3b85f66daf9516583f6c16f32059ee426075819896bdff601658ab1adc41d55bc416bbbb057528005eb27fd40c5348ae5af7254c6fd38d66dba072f", .Okay}, + {.Mul, "340d4ea529c7f81fcde8a5d0d85f49ede256a2b82eb24ffa8b55222e4cb9828ad35a52a981fcd7f717576fe6d5493a92c05ff0cefc7b819e7dfddf52026a17b662ca19546d3eba1d448c2ebf2207f709f696c5e9b763eabec691aa388bfb48c79654a6609881a554fa3649c30f2823a144a819d6c3015f755c063aa4e8178cdcb5307a17dd726745c4d43d6f62d2d62ad83ebd389750", "8e81ce72a7109118638262fe0b08f2e7af0e0258d69e4a032e231c40871d8f1deb8d02fc6d27857655e8d88bcae57bd4e2a3f7eb9da35915f4b905a528114abac1d05aa29140ed8ef31228ad8260653138ce92ba360351b06d15010b413eb428bda1c1f623b8b75e645e877ad749b5b6a70376dbfe1cfba2f716eee023e01d42b4b164109df7928cb3690c562fa5602d7dfc783736f7", "1cf9c64e4394f334588e87df4b77e4027658ce5947d9a44c138b377a2ca75cdeec95c7672b27c361e5db4d2d74545b10aa993ea66febbf9066aa96fbb4f552f8eeeb1b6607ac93e6ac9f75777a97a6bda238a4d8d3ab97eddb3c05f0c38432ce87ea6653de16ebb5c3f09de05fdf70acb278a4e4c17f4fb06ad84002da69de2f9eaed45fc2f830f2b3eec9fc736d8c13ab6111d2788dd7e9cda805e7a5fac39decc42f817d29e59db78912d54dc97ade0d402148a06ec14b18ef63393852bbc2f411633b67c38d81790cb864efcfd0d39ab37d989b5fd596b594d7cb01596aaef0be7eee618701747017b341782eaeb404fbb62a3e1f49a1e184f96402bf2df69e5473d25e2933377a3702dca2769fa9a43ff11338b8bf37e70f5f30798724d30ae21d9309c8114883b4de30", .Okay}, + {.Mul, "-58bd815d5702394a8fbf5fd6df641f2d57aa36222f512892a193f60dddc7f6f8dc1b11556d5a299147fa13a238a25e924997eeadb8c5c90db8267597b7b6a4feb1a156430ae7911f5a43af94eea2c0ab6df2e0c2a8e352f385d01e542375994469ec51050644eb63dcd3b5f4f043e43c240c9b5871bc5f44146c6502028f3bb459e2d27e93d8e93ad9102451f666a6dc159fdc79fb18", "ff4f9b711e30d7c04fe4868bdb53fd56ddc21fb15668c87aa52d62e8cb0dee0d9757ec35300c76fd7d62b76706182c16d93afa6ed7a5e0c60574d92b6ea30766cb496395f7b1df1308e0d9ca2ecd467e901f496f2dcd2f1c6b566e06476cdaaa537f926f82a3be3aab81691061a8961367b0fc67f0d1d4182ee4337cc6ce079dffb67dd7f497abb44a0459a37e0799ce4d7f29acf61e", "-58805c38d8e9d21db7081b043a8e8ba053e9b1d5020716c7eb69d8dbc9f0acfc164c1487e9c684f5d2020a144a4f069f512ecfa24f134c8e07b200598b4991652d7022b643e6cb22d02ffa095291b2f5db0976f761337f1e5b0fb9c9813e069e2c0a615bda0ff06a5b23514e9c1015b166c103823e952d5865783702ab361f3d070449cecf4a754d84eb3d7b3e54eac7be07c9ebbeb1d701b14f2caf1c94670ddd7a3c7a85db27ea13f97059c5236793a5eb271827cd3513cf4fbbbd1fd7af82227d2911f83159010a776d81877ef809cdad96457646d942c6e0e056a518ad7ee57b65d5c6902afb656486ca45bb7369cbbe1c9e6af20d48639217ea58dcc538412cb75c616231ec8f53404dfc6a290c19f771a4ac3341291fdab0731eb451af365eae34a2a39aac99b47cd0", .Okay}, + {.Mul, "-70b697b5d73c10c1345d1e83758e8e4b132292d8d90868675d935ea3cf4ebc22df6b5b78ca34e2dcdd13a0894ddcea7e75495893a8f453c8143d7a989121e60811a3344cde8c1a0003a2ddbfc278ce4689a09b1eab0021c0417a52988f5f86a299888836205e3bba6f0ffe47301111a397f02521ff62c88a61303901435c9dead990552bb6fec5d27efc58d198bd4db008c1f45047f5", "2a07ca0b7798c1adc0eccc8dbeca4040783ae1a0f5cf7a52957df2c1b35db3e37816c96488ff26a100fab82f515af407a7c789a98e92543ab9bd16d459b33ca63033e047bff0f56e4edf52ebb177cc78a83d409d726de53386ad13a5b278eb58e5ef2a924b7a797d11f59a7604375f665a0336ae0a3f43f47d218aaa62bc256776bf53d810cb6bf9e9e979026eea22ef120cda460534", "-128162d71b7ee03f906769f2c5c37fbd05c8f5682a3b59975b336569ddbbd7db6b836efa25e8929c52812fb908d47ac7a066742d8d5779adf4b44a717fa0ebe189a11b8c94b2b862e90f91187242105b67e4bf4bb3804b25d8bc0f28753e15180095c0376e82950a1f01bb69eee40a625647c58d54d2b5d35a6b887e5e7cf6c1ec6d072538cae43b2accb88f26822763638182dc33ae99cc6c20287088faac941ff07532dd6a91b505652b59a6a1feca60f4cffbfb0e477ac6692a81707e5835e3c7474eeca33a7fa0ca1fb52513836a52df5b5d7284af651c6a888a348144e9569158e2bb1cd0a7d7a5e7138c3fe4834d1ce5f208a07863ffc902a35e9f672ca5621b65282e765c1ecd4c26df350f20a422654c28ee3a789d00c49bc3028d1b3c14b748979055e180b466c4", .Okay}, + {.Mul, "60b217c19634aa566e44f2a605275f31b986aef3f9d0c46612f95df85f8c38d67c34bf1e2db435d3a6f328dc5f729e16c42e3296172f2963f6d7325c92d8d1880e84ea59147e382e6bfd3e4998bc804272a40b11233feb9f93e479f2e6c170a1de318cc417eaae02eeda80c49f62039791e3a08d6cfcac9208440858983ca474437772a4215d52a37b9aa3de3d4eb1bcb1ebe9ed2c43", "5c1da26869342d38bcc4ef44213ad07847ea2d86e2b77455fd73561d69987e9a2976be8be310defd22c98771c1380388b6b2ad49b4adb143ca5d2068e84d1d180aafc20d49404d0ea0041ae7aa6d65d8e633ea07555db2a78a3c7a6d9d1298956902d0215ce264b54c82e696d13718f59951ff1217211529aa1326260812d466f673a78f51cec80eaf018de7d0619f81b8f2da571838", "22cb320e6607d9e0aaf8ac641906646ab5731a22d3a66a589dd286437378face6b9454f068393ec44167793f000a684d07917e5e0af371af9f2d531b7fb2ae90778ea4429857a3f250f285eb6de9363dc8e9e05edb75513e1711ea3e4350565045b5bc9f01f296495785b10b1d94a24b1d6a9db153211ca176388dafb83a15f4347ac76a93e5bb27f726d90919503be425b5284472d03d9f1cbabb925b32b76e11986fb1a9eddfbae92dcfb2f0bada6bd3b72d6ed776862cc088d7b24340539151337291cb206f729ba71282b97d7fc73176e19fdd902d776887cbb5a2732bfdce02ef4f32e9466bcaaf911e193484c1176270e75a299a60927b9fa22ef2009df1afd0fa7d0fc83b46db973a224067693b5321d2ffdadf4efc6d49cb754488c2882c060d731c802a80ccf6a8", .Okay}, + {.Mul, "-32c409e64aaaa4a1a172321fdae99b5dbb7376fcd98090c1ae3f9b51908e62bcabeec063e88c76e5f02c7062d12bcea0b5ffcd61a63952080fffef52a3166b12f44fff9c4ffa8bef38da51a6a43a99b6be6c87f52628a14f2ba0b3ebc046909161aca484f12725b9c3a4724fa791c46a47afa2840075aabe2985b472978e81afae76eb651496b370fd6ad85f9c5d30b6f18e8ecf88", "f57a288e1498c4c4f33a56971141427a08b7e7e1f8586dca4b548726822b034de7e55cd1442276e2b2f8b0a1667c644e81c8a92fdcefb67199ab9d2c0ed293b6d9ea63607fcd8821adc4347ebf59ac017dee341e65e02dbb4bcd984b5d6b3f0fcf970d1a550fa8345652041ac3cee4c8164f2d85045ba1eb314573d74bfa2b1d7acec81f798c66776669d093bc559be6753f67ff5222", "-30add6f0eb93fa7a3d6303eb9d914e6f99b502bb0392358ad2324c9a80946e991148b796470040206d31e80ef655ce21d3405153954b969c8cd271fdd9548c5c480d4a3f351a8ebb0994521ece0cab312b49d141563344d651ca8f7e6bcf926027928e953502e0a81252efe493da7ec1bf53a0801ed74028354817a821add08fd87f45f662accbd12da4fd9aeeb96f736ae01f4da97eb5e371108dce16f0c8123d4169843d125415af8103c545cd6e56970dd13265229002d7b3f1204b1af564e949ec5fcda02d6bbe9a3500894cc1698e38b4e6c8138616bd02202af8d6cb89627db7c19c9612e26ea2f010f78c27e6d3e85382fd1de018fef0d0201acb26b5f9da6c6df1d4d926bdf555ca2a95edcd01f2b2257f97a94b21d8fbd1d536c85776f5768c385bf71de92010", .Okay}, + {.Mul, "9f1d5014883e4e334fcfd590bc4b295d279e114f9c1a6d5b98604e2a7d2c733755181d3925b14bb456f45e110502798f5819f27b88663050b78e6f77b2b00989157d2797a916437edca5ba7c3572f50d87297346c0d05cc27e654de85ac3cd79c0e8ba6a59b72c655782ff54cbb835f8f9670c34bb3840acc99cb23060bf7426f95205bab2639c969aa8767711095f2fddcce7e61c40", "8c64ac469e221d3400b27dee2b2f32336cdb886ef2852da8e2a3397ce76558beb78812c369ac8a1947f212e684114fd38267b69a888fd64ac8e7d7e2f19809600893091ed9c1ea06a2de31038e0688d351d97d9672eaa5eb9a57cf50eba455b10d33258100692d23b20dc4958df097d5ca0e8baaec82a4873fe63881c0ca7ba41523a9c81872ca91c1cea46efbe6200c503e9697f5c9", "57429a5218a247b9ac8ac66dd9e354e9d5d27fa93ea95f447c7ab2029d646d551b4e32a3a5d764c226cda03f7d0b5a99d79ed4d7d5c10fd1aab1913662935c4db314b714366a66ba2a4c5aa62dbeb01cda433ce5f2d6dba8485573e9c09ff29c198670e3910a3efbba2d9ac878d69ec67a5dc3f6dbf0a2554bc22a8b6e643b1eafdd2a9f0f9434588aa12f9e2ee6395a6b4527207945ba5d2a4af06683bb043667771248a0e4fcb16fb1ab0d3307ec977064ea146a770096fe1099e0bcd83d692785668eb5d84c1ff599471b56da217c9944404ed47de76f0dbe06d48e741ba15c32db3733da873e2e9934adebb87992bcbaa4d0331d9e019e491c10bb5964494877eda3b9ddef50fa7935d69a4fdac222205745e0817526b5e80f4d7e5503c7a0870d8fd526b49976756e40", .Okay}, + {.Mul, "-af2a4bcd5ddd3cff35bea91252a9e9358df839f80db9f1d2a2ad4185024032c6ed037d2ad129749d37d048dcbe4fad62dc72f550465ce73763a1c6643a2708c5837872fdcf235b6f22905782bca8e1c06e14ffd48f8fc7255a28e6ab25b2a39ff50e67f2d6adb8975e6ca7c42f8fc8f7db0ec5305610dc423ddae7a5680906a848683fac27bf7cf82646d3e2f1b7c5569f0edda16b2", "4b76741065d99a152418661db8884646e84ff5da81600e3211250c7ebd63c7ebef696b16d88c9b45c6be01661782f54a4e03bde4b4a00a1e96ea62af2b7d9fa6cbfb2dacfe52e30335214c62a2bca4f8cc3e7e14a004ca7990d15c5759d741f14249487ad8cdc3c45994087307f094722f6c5dff498cc8bb10aef30f5f88cbd71098e7201fedcbe4877593ffeb0f012064c2d4411b7f", "-33a2711e7dd774672fba5620684706d956ba407b84fd306aca35f593e0ffe23fda61e77411be0c2a7fee5ce0db482a8d16241e4c14ab1e945248f59784d76d0b1de13554591a7f8341c2c12eb754c7e43f829742ed3e9989b3a15c7da1063cacd41d3f190fdb408d0deab3dc9f8b8f816d02446022b8e1917025eca10c28dfd2de44d2f770cfbeea669b119ce3835fee50c6333a82b7363d244a2e68dbf871daa7938b24b3ff83ea73cff46fa181ec53bd65d5a328adfd75f097f845b39743d56965202548834224e0e6dada62fe66354ed2c8e0fc428e0b9bf6f3cf43ee068b84a923c0ed7755ff6e510a57cb2bc762900d254b9b0294dae1d5c343ac4b6cdc6095b8434da3e81723cde883f91e9aa6f71795fdebaea37076cf542cf1a96b532d547701413b1ab2ac8084e", .Okay}, + {.Mul, "-103c44a384efae75be7935f1e9fbfcd84aa753cdaaaa89917530c94fcc28f092072b607e9e36c57cfbdee08189093528773d45d11f7e3e59d5203a8b799c17a0382e7f31787e6c50ed714625f2be3a6de66e563cd8b7f584add1f1fa24102bc544357f5debc4a00b7419e655d6de1b5124dd2bfb820ad3015d7cdc84459732782d950121e342ccbaca8b896406447a8930bb6bff7e98", "b666c6ef2de33ad82de4ce91c22ba6a5f860c11a262b2deb86293e5ff3c16ed0a99e48a2654c9a51e1c7a27bb0c6102829af241dbf24794b2efa625fe0b5e9cdabee807e90e9e63f672b839a802b4f7b4a2b31558effa4c82af5f56fa414123c2d5a36a2b21cb8a3071762d7abbe2239a2cfd70d9c36358ebacc7e79ce6f46a41f0f557d61d282bfd83dd847dd3e956385146d20a354", "-b915d6d61ecec3eadb4150487f359dfae0068bb52e40708191024f319cefa8932b0f9b051b088c0353b530008ffad6c0e0e4ff7f94443b50fc80945cecca23a6e7ac46579213ec6869e336510813688681cfe173d3568aa2ce97a0d5bf4a26c52725821957864a2e0524bee7cb41bdd7a5ff40a4298b896cfcca7aa2e758f3b22a8f725d5bc30ef84451cecfa33d4c3d6165d9832c9916366e4068e97d5ef62b6c3311f46e0761682ad2c841f39de21d588c3ee026b5987725773411f47989c378a13c05f636f6b28a9fe05c1641f6f92da996722ef429972167f8092900704a5f0f3a47f3b460f12de0be4571010df5fe63ae3b34b3ada3ed33fcba5d05e40061631a636e88064e8219f598838428a65fa616a767a81eab05cc6628790e961913cea700cf777f9a87051e0", .Okay}, + {.Mul, "56663722c59cdb186f42ad7e0754da6ec2bfcc60b376c19dec701b22214ada2678cae9ea789aed5399b90ba1a58b97a44aa3b4633c5299d642020c0c831617766d1628f7829e32b56756479786b50de78139449b388d7e39e38003dfdaf0fb7d18e60ce60f573cf2ee4eeb48a306e5105e3b01db8a44ebe8c44b8dfd1a1fae0fcf8d41febd0920e70b20ca7adc76820525eb98ad5582", "3bb986a18898a6f0285177a3152d094a6a511ac6097de8466e303eb9eecf68c17bf7c48f0134e8d3dec9e14431c0eeec4565ac58375a5724fe08e4c153b247352599c6b6d5e1fddaceeb178bd58bf71fb5c09ac02020879bb2a9b5c1cb78bfe3e35b3d397afcdb03fcc3d55bafd800198df888ddab084084b0bc2a49d4f387e470981c41bee313ed990d8712bcdd1a4ca7cf04728c5e", "14282c02e0eaa779e371b75fc4fc8d0f0ae208ddec88ebe2a44f9dfc315b6e41e61c852d17f79ef88d4177822c662e54a1f52ab481a133996fbaf0a35f51dce3b1bf84565155166f2e20c7f47f36aab59d2c53e13c68ef2e89c78224fd515a7bf0802304767ee993e945346bf8fab6bc9c42849f572b5127280fa851a1b6c66a5abd7830b35f2282cbb57f511489d2de394b1790bbe1d2f48bdd5d523f0251ba98710df22a415b110bdb7e4493eb2d26dfe0b96045afd5e9992caa6b14ea84128578e1776d52f93af7951e66dc6dff111645ca51148d8990fc26c87f6fa9b664835d84c891d7c900a1dce6d4689d2a90e088af175ef9b2a5ffd3bcd3f019901f74016b0ab4c39df968a6318c8dd1c1caa7a4b5ba3e0035e61246195258ddbb56e7674ef93d7568a4f64c7dbc", .Okay}, + {.Mul, "b129c3ca16a280b796e5cfd00865064b5da1c6ede66e1333facca27457e3d6896ccac74b3ce33f3b6ad4af24bfc6bc09774a7b21fb464199c5eaff8892683f76b5c46eec28064d480a0dc2f80b44772a04b98cff6dcce13496ba5f76f1a1581b9c8bed699d40792387835052f93234ab916ba3aeb624875e9c4e1b546b2741865923b2d134e74c0d49a39469adaca044eea5c8013502", "f74ecb44909da689c8dfe1fd9d48a59441a60b37012a9e2cf1621dc4dfab39c45f152c90b84cfea37238020173f39855c87c3fb7076a3755d5c9f2ff7ecba9d8441ded9e8c74bad8e1476b7e439a77fa9b2f6548b67b161e6d9d02bf7c15796e2bd327295a26dd10a100631f9b160cc4ee15c5c531698d5bee473dacad6e1edcca70d48465bf42fd46dc7f0136d43f4838cd90c94761", "ab25d34d34d7895468c12793b3249bd67b33abfcf72c7c09e11dc55e3bd32cbdebec4e0d9176c419218e06d15759ba4c724090d831254e46f25fd41ecd3bb1ffe79170e5c5c1d35328e5282af208fb33987899000a5cf5eb8c1da2983e577b9e66b4f4fd1743187886550472b35bff7c643bb1e7976902b97cdbd9a4eb6b000b71bd0377a9ba1ad2104cd4352d926afccbb3e200fbfb24b45d68bea64d5e47a43611e90a3840e0cefc62190e3ab2e9720e48fd3d7dc3217d787042e5130372a97f43e5e239252a673e0a51ea7386f011d0803335bc0be6e93eb1b859c1b3d6dfb38407d2b3de3168725558436bc46d00cd42e7aed4dbb5d36a51c423245e94336bc79984c554022a40dd0e8cd6582bbe9a30ab6e12e8d70290adab702cc932b76d5687c44c1900a6dcbaa3c2", .Okay}, + {.Mul, "-a507e5897315cdbd9b32e3bdf0c8bebc82c163fde3082edbf64ad86525911e9cb2cdfafe1ddcb91f1ccd54fa20534dc70d2e144e8abd8bb8186debfc06556c553de6b7c8498957ae357358b2a84f130dd0d8acad45af6e7c8df71fb568e4f2cf809753ab88298adf2e0299b694ca3b2fb37a2e7221426af2b828abecceba057e7d8c5f5711dde8259bd623b2dfc11f047c4012a6d5a2", "2968dc20ac8a399153289f032989e8504f991cf6634cbe654edff4b8c318aeeaa5dc45fd8158346211d28cb7b63d590a231d678bb9efeb0b0456be1a0867c30d6dc0294fb0a3f9fd500e091e2fd0aa0b8d0238c460779d7af71d1f25d4aba5c1a8f6ba68d78c3f6a249e4f3950c8987687f1ebcfb6946bc827d48fdb85815919abe9d521f89aba89a1e1dc186b96ce167fe48360450b", "-1ab1dce01cbe787a9905e8d8c8ab8c1d3400559175fff89e88c4973093de5ab04c18b23ae8f6b4ccc17e0413b605dffcbe0f66a485529e5f5bd3d5255df169501ba9147f1275e514dcd8dbbf3876ec75f3c9c1280df1df4e47fc4b813ae2edb4d74eef805a0fabfc0d93f549a20dab5fac6d536e445b18a35968e2919adf3df6a6524c49ad7ab9fc8e4df125a442ac39ccb9dbb632ee2b52023fad215dc8d95f6bc6aba4aae76bc46ec7e168bdd680aadead69fcffb9d808ab569450979cfe74347c8268d462044b5d64972342ee6be23be41f70505246335e25699ce5cd93065fd4f852efa8a675e25dac4190390f4d9179a86de856fbf6b8b128303a82e5d4caba4decb5684b67f08c6add9a2681eadd1a78f0aff148a3dbb7a51f66560c1b78abc76804be9bf1c77fd7f6", .Okay}, + {.Mul, "-32468844cfe1c05680b24ee7ae11b37c0580846be4f99af278addf4c79ffb9b4dedd9abc3370c1f72af6259f22725f893c52c4317780652161563d36e86fe40e9ebca25fd8ab2c86dae5cf4d9ef6e4c03c68792e8a845f8258ddbd0bacc091223f3f2af3ff7a0943c24eb3c7ab15ded9055a67bb52e09fef9456bca1139546f46999c83a42820888ac34ee43bc31fab84098e2ac5aba", "adfa67bface36b59ff7bd6553b712f1a436b54c719e46f114839670c389fbadffdbcdec6ce4f5b51165cdf32ed807cc56150b5884e8bc864601baa5b7391c9d2c69a5a517f406aa6adf03f80cf4d4566835692aa49daa826533835d4ebe785b84066d319b98134376abfc7e67b723a1f0156499bb8beadabf6b803f89216ff1c5af8183457a6b338f300780f58d06eac39ddc3b1ce8f", "-222ad7579915f9996f9a34b464d8faec68cff6d283daa3cd2364515f254ceddaa46cb4e4f899f4d0db1f3b7a18830563b847a65dbdf882709d316fa43fce81075d7fbe7127bd819b6f56cd9d1f5c46aca8c16cc668d10010ccee6820ac28cd9f589f4fd12b40233d3fbcc0a8a8d597443fe5d6b69c1e3473366a9d737645d2ce907a8559a18cf33f122f3f365045357be08922ade6911d8f24c6088efde01b787dc933387352ba85ed5620be165018a047ee20458f5ee7be49f5d9898c5c3697e325026f5c6f6550cc21b523164631bea1b7cc2ad7d0d3594a88c67bd2290f686eb994814efd8980160a098412b387272cd618cf9f48f1025b20f2e3e57a59e59284ce6ca95483a8d6dbb2e53c4eb671334f2df51955a65eae8cd712d19f00c4457edaa15f3adaa5b7e259e6", .Okay}, + {.Mul, "-3e28bfbc421ccbe346270ed3ec2a758f5ae9b280cc5fc08fdab8bc5c503715a0539c40ac9f2e2f9f74530347e04c45dbfc0fdda94a16e9ba16a84a1ae6aa8756efdcefe9cd49bf5021bf74ef28af4be39af5f5f1da5ab0c14303023f35177e98239131794b387ac20f00fcc0bdf98050f83e459fe207dc5a61e4f12084cfa11cf79c1adba23a918f4d9931da88a804a723932980d942", "37bc165061816f497085c39fefa25b4f5ecc2800c30be0e4813ff04387a797d0daa91f6356c8242a68b20b11e5a9d69fc3a5286f5eec50d9b3aca78795a909fc5a6b8733403023bac26f52e878e539d4b2a276a46fc1c5fb1b4e0687fc74937b45b4c41f1631aad540df7866bc62d6dadb3c9331eab2c0371fdc499612074628ac6582b70dcf52ac521bf7e0f50a19b6ca424a1f044", "-d886c894557b3ab247cfd96bdd821e47e94de7b9de59e62342fa0c6d431c738722ad43651e425f1338e1bffedabc76d82d50751404644290503497a3f92d07ea54992b57f9ceaf248a2fff88903cdf737c105ccf84b840d3e1e8bf6712770ff3abb515bec552a0e8054c250fa7406489a06cbe1ba2534d41963a979eebc1cec7e3d11372ee03d8b0beea7cf495a6eb0c59ead592299db638444583877953c037c0ec075bff9c6f17622ac5b08785e8de7c677aa249013b2173a1853bb36c59ec25681817832810a3a87e3848ffa8537f23db430d4a496e90b7392ea32f4472d4e6d4dd2b0cbda934d8e74737f01c694d1b2898d53b0a3b12e6218875b6ec42d0da69c291bd9408abb13993a7456979864891870e6d1019737fbbc2c2cfc5b1f7400b2afe4ba8ddbc699588", .Okay}, + {.Mul, "5715a0ecf738a3019e79a36d86a172932baf361defff391df448eabf8a172ca74b67251d92bbd8a1b70959debc77fc726834faa1ff8a86e07459b9e9cb1267a418b28a3c8e67a3bd186ee0ef8a4d4b92b25093adc032f1d8bd1efbe3557156de7ca7628c41b1d855b8ce29149696d7efadd9f9689888a2adf39cea3e434013489c28decc4f43001c29782020f3b5844cc0ef279aa5b5", "6066cb377bbee4e99b4d2570e9410a3622cd61b384b6ec394915002775a1fe8dcbef2468926af396757f6b0ee82b284906cc3c2759d433b115e4ab0212f68a1abd0d8a1d97c759072f66c65c60317116208b10a3fd9886a0f073c994681516f0bbe69d2632c736644e305ae628e509d1bef8700bc0ae3f403d0975d974a96becd4d822bf7f54f179e48c64245ed46caf69f2dc448e7f", "20cb141801798ce299fe9ca750f320906d70554a63c7cf4b8bd712e243af5d42be1c2eeb9e13a86aeacb10f61df97abbc24c759577a739fd8b4a77efbb686094184ab88233d617bf50859b59d44054ecca74d87cb28c115ac976b0cf57f71aa5ec0fd173e54db07abbb0482debc11eff0ec514f86fc203d5fd740017f82ae9d08b12cfa05a79dc5110c8d65e7cab8829604dc1c0aa24682e200315ef90f62a576337b8e5fe3281237d41d9b90310ad1cc9602180dbc5023df71acca6b5dec5759aeb60641d51eadecc2bb32f997ac9a49dd3c4b2596d7ec6a31364136a0fd25795b71b75db725160de00890c1abb3fe19506ffec536c6beca714a86f1d164ea6c589951a2ad0c6c0a6365754a22dd0f89666bf11940693b67b9e171763b6195fdbb02a757b8aac31fdb69acb", .Okay}, + {.Mul, "-26bfaecba2beb11f211193899f60879c66ea88a2197d56eb72952ed4389851f8000fc1226b5dbe72e028af11f2061a82f8782aea74de2ddcedc9d41c7d9ef3ed5bb0810c6183a52b8ceee316cae6502543c28ad7b5b1e513ea64a2f78efe2e51fe5c9fbf0565e2849d6b65784ebc6f3950f1df05ea5a50cedb4a6213194678d0031ab73d303c4925e8552358017f7a7be9da3e019fe4", "7149dbd99f74b85e53fa8287a7dbf95a2af34968ca0f12ba97ed9771448b5940afe7c0e4820a7dde9cabb506bc9d714b4ffec3040936df07beaf38d215c48cc4ae6f7335377ceaeb9172d1e67135c21fe815facd8e31ee0fb312bdb64de98cff10c4c844388049598fee49d4ddf74a7a2beb4ba208fc6e85889859695b4e471473b1a5b631e66f34336001b62c64c073fcd1a68b4325", "-1125ca17a60dabb90fb7bf97e38ed79bab9b7f5d4ff1e62dc908abbaf8487bcfedf9e9861ed37f2c204e734d15050b5559b8a49e5d4ecefdee5c913f5ec402179bffbd4376b877c27eb7f8fc832def961f6480af0fdc084f62d78864c2137f522bb521f6a697f11e36a97cd1c4159ad3d92ed80e15d2aa751b52c01014dad39db1efec12746cfd7ef5a3b185714552ccd0da7006f705c32e007ebfef34b439866ccf2ea8a07e6800cf4ec23ad45c571dad047d92988f4b5b156cefdb34f0436c5a3f6c42c662d081271c55dc5d9eadfda6e7119cc9b715be3c0dc745726c0c743abb3a371c7d09745124519942b043fae8e8db25b99e98879a081de68ff72a6eb9d1995b6c20d0240363bf7aa19fcc4c6c7dde919743064aec353c99c7a71d3262dde752abf59c790be0c7f4", .Okay}, + {.Mul, "-ed8774694b5238ccede299d32d4c2ffebe9176aa8f00bbfefb21f31ca98c40a6668ab855de1345e6c77ac9093bb81e630a7b0dc508589471e8072dc5150368b80e0fc49ebdc46f383655916c29e1d7210374d5632b4a687f786cafceb809ab2e74d73b10c5b8490a18590c74db02b50b03125897a2e5eee6f0e866779a169d53ea0f0ac1ea0f37621079382d501906ab6afe7fbdd2e6", "e9921f09c2a30963329ba08c40b0f89e757e614585ab0c64a2c2d50066a683a623161a4b7fceac7f9090ad7eb707b76ab9701ba5ce6c696c51fc3d47e599d27017cd6ec8312aa8820834c920d34dd510c460c010b5b3dac5840c08f89dbaa3dc021c21b65dc484b577e0c39f9c02a9dbd3de23f88f03a0b459b876faebaaa42ae304e599cc349d467c3dc12967564b4799ff2e2bef60", "-d8b7dd00af0e8e963bb590ba0f20b6f395a9e4efcd7855e15fcb9a6f7be0de435055fb169fec46ebeb02076353410e0b0bfede0790235ba29f790b54f33e82b394199e109e554938653b5f6bd13944baf6b6314fd24b5c9d24a91ce9cc341cba83cfe6ae51ce62b1ce68819ff7bab90cccd0f2dee96f9b2ff03fce496a307e2b0cf9a598764af17d04c4e3f5428071483d4ee171cb988a90e2e4bef49191c80f9818c56bd15dd9231d475dc144d13307072010027d36c8c8cf1845e635e6d146fc6f09931e526fbe16df66063b433ab91f84c1c8c05ed1a0befec0d8dc5e1aa56bc0b9d3ca79be2b737528df6341cbdb92f498578d06e6033c61033911dbad365beda7a1c25949d30030e655ebef1e82e0614c31d3f5586ebb831fe2c67c4dce1c556e2dcdc9d293dfb5d040", .Okay}, + {.Mul, "deff790efed3e6b6223461ec5d41e23b0917cf473ffb1de81abe3068bc03f18390413dcb7840bf5dda16360135f66aac889fe373cc80ec68cd8468441386178a8742ce22138a696f0243f3f3dfe3828c7f0d7d1029d7bfc749d40014025c273557539dca81717bfb31627bbe86ad8500f55600d458a5dab5b11b47b26b1a7e48c59c368d101980ebd48be24f711ab80c616c5ccaa1c0", "1df4099758356da2c9dfac8e80b39964f07ab748952f88125f17b968dbdfbcbe39abceddd2cf6ac1197dbe40e6da5dfdb3c1ec536cb11c7b02ad5a98ca08da8bf2be935ac27b6c87c0b6be3ed7f739beecbb5dd13085a57568db7643d83a195fadad5e9cbf3dec55576ab2eac95d2475649bf91efcb75bda9aaf51a585e3931550b62bad94330e8d910b0076abe48dcc20970d040f19", "1a178490e5f12dea155509b8fc46d07c8f877e1a4052b1edeb0ce63c7ac3a9efbc5a6582ab7927a094117d2311a00745b0f90da4feaaa43a85c4bb11576541c8970412865859a470b3e7a2b846f8852781b64da6cbecd4bc7fc2398dd0ddb9cb8d7ea7d32d1b21afbe997a4eef7ffb550515495c08325035b560db8d4eaa0e982e3a0bebae4e02c6c50f663b2c220274587a201a1e3d04b41553eebd9c73a221b86a46496805965cd67bda759b471514113864f8b6cff0940ed4b7dbf6c9c59d5204343ae7ec43225a7ed7a121986124a66c4f5d7b6a6b4baa3c3107ada62a39918703df4e66f6104ca1c45c7beb8443fddd5d967b0f825bae1568b389c01db152118307b365d722df452f5fe1caf0bc0dd4ca4ec526a95f882c664789f1ae56db19fb9c6e1002a636440bc0", .Okay}, + {.Sqr, "-c12abad02eb2bfa25fa8f426029ca327b10ea87e5b272677c71903746db85c7941fdc764b90fba98d6fe2bb160cc19f6f01653538c6696b15c111ec1c07fa798827c365568ef766c7b27dc6348b2b8a800b69327200d866d55263a28a30343b58e4935935d456be5f73dae55f4b68d822217195b8709d0d0a8310e78b28f04a9bfbc95d1c6a5dea512b347e18f7527cb91025d1b330a", "a23e6dd193e5094f3ca11c1e8418037192a451c10230d2d80d031c9c5c5ae1dcad0d3906f8a23e11e771f9847da0c163948cd1b631905da77b2bf15f9a205a71e2070e3d72fda147417456a4f3cc14f7a718fff1e1d63726cc47dad2d321cd38be69d2ea0c885a164bf0c639b0ee690c821b0ec4f3204ef18532c15e3098ef1f2d9f5a934a0fdbec0c1b20f0a4a0e92180e11f52dd3", "91c174cfbb0c04c15ef8381bc95e7363bd4d79d294c3b94ee2846b8e32893a99d23e90c126e90dfdf2fe8ae14dfced81782846e24f2cdc11ab6e0c080a3e2cdb732a35420bf46676250615233fb147399ada40ff3fdb4e2b6cc26cd79bf35ad3ce75b03203b63d6f7572e00ed5d6962e5fd7cf07c18d27093f5f0730d81cedf5e929570ba09bc31f2b29ce6119236f95241cede535d640207b3be29a38ac1300ae8539eb5feb30665c20dcb270d0280ce8c80aaeaba98ee4b78b1c3489b48ef401d2779d8c237e7d71c6777fb4f4a228ab8f4cfd69ea0db745be034eb90bf8bf321570ddbb0d97949344b71a86df4f4b551e3a3429fb44e479717f2dfd8b9e465481087d39ecafe74f60a3ecd62ab83ec390e014301a7f3cd8568936322a6056c5b7735263f6e6211248fc64", .Okay}, + {.Sqr, "ca1633f8a95c60f56b9f535f8d919fc7134165825df7915a2dd12d5516689bafaf1c6a4ad1846ba2f4a53b9311032f590cfa7f4b767548d8850c1fe64e6c1c4a5ab8a31859da292beea8024306ec9cacafe331949c13276254c80361aadebded13b6e85e7c54fc081b264e431167497f4c1bef87283c7124d4e281183184c7a6140a7e9f233bb338011b32dc24ceb9325e85909fff96", "926d4677b47fe8172d3b3472e574d3017aa6e127f5213989284994253bc06a654d4185d05907f8cc28adb5af0fd26c69fbc208612e879d931e9cbec097e4e07515409fa8b726a59240b4aaaa7a617865b65eb4f071c362d3a2b990b17822971430b166d43d4738d02d2ff74578335d81733a94b099f2379ff630e08337b82fe751a78c6b1eccb7c2ce140143085a490f286d98389682", "9f870bf1648fe9e759aeacb0fcf6734eb0bd3e5cf71d7664add0017eb4cfebf99917334ee4eae309030fb52d3af0462ab01b1a58716062c4e1d804cd6ef9965b66760dd4f587c488ae775367925e0ed5d98bc7836d8844abec7507cb57c5b0a694ed83832c76bcc7a985a2fb7cdcd2012d9a879e6b909aafb87964824649ff81800f6ad45020b346d9ea86e53577f80c2e354a097f17cb778b155858a11de68674cded863922f9adb382acc6290c3be6ad928642b21888387786c0f105e5da63ae43099602285c091a894d2b28aaa41b94c632a98625bcb98a44f3f6460e2525ee901bd5a5df0e5782794b86b8cb02d3c08328bf64115ac85854f3e807be92394a30f37aecd5cb4654a2f9784f5388d36f64032fac9038212ef39a60b70daea1bd4b9f33ba3e1d643b802be4", .Okay}, + {.Sqr, "ad36b8ff424a9efc4db7c5756653bf4f912e83e0545a8f5ad8c9808988c71678bce9e70d53e92c3c23de25136453d9534d59247bc660d1baf3d5b94f9b8c2e9b4ed425a061537c82602d27b4aa788426c321e48be711116b6f5b1cf0dc7ca5ad729c523506d4ef1b03f7dc96aba6f207e0b9396abc5d3f9a2198c12b7902ea2f3c4f85287f033866a516f5d54d7c18a28503dff13a5", "ff97c4403606b1c45e14ffc0153db9505a4feb1b6220887b2b9279eaf43de01e9d570052e143ed89e7a1fc563112b32b1e7ac2e0ec222e3491e86455125d5cb52b477f8ddbbe08b284693cbd3f6fbaf9b698e2a7834f8c1b7660eb41043b29c0906f65d4c34a1f360579d91035eae56706bbc6b0260f87ee530773834701ee1e8d81feef571ddb6349e038494115b42be940b804d211", "753301bb90f8c02c79d9247d5e7497871f67b047e87a87039c57b34007d61166cacf7291768d0573d904a81bddb285d0d8b9dac1245d513a1c7f6dfc75c10093e9f8d321f0238417d1b9bcd75771b0c95e617bf831a6c680c76e4dab0e0f2dc69e36e056d9904ea1ee03d3fb570cffdd09fa0f4960bf84177ad7cb8c4ae788579d6d1b797a9cbee3528788a408cbfab337ba3e80bf8b3cd78266d0b9df394e92feb18fa8812bc0c2cbfb254844bcaaf1e6b9f3da7b3fb8f9039e8f6d2240fa2cbf8d85d1d95dc8ee83126775093070281bc2e1ff251d52f3c6a6dc709f2bfed6f277451e3aba24dc35a74e968c9bf530e25c5089c23dee6ac82e115f765f758a4b04f138e848f95771f42ac4e2cce3b3a1cf00f88b8f1274ec148af9514b975d8fe64c7c7764a4c637e859", .Okay}, + {.Sqr, "14c371ce79c3a8dc208a40147a79c0446d0c74ccc276d17ce3c6da52d1fc58c482ad7f83340c77c8154c353e4567629cc464f8afdcf945fdb5d1d65fab4a5eddd2ef00247ee4d5605ef88a537f590f1f5ab097baf55b87e3ba62586db328db91d3363d12732d9a8fb44ec5e5f13a240504f9ebf7aec364ef4051d823eb93b81bff7deab8c0bb89cf71d2238b921681216ea25c1b4f9b", "f32bfefc6e6cbefbd58e2ce63c16cb7b97fd47cfb984534d3c0fb9d341c35978dc427e54136c7689ef6b759bb2e95e53d76bcebc3865c701a04a0f31ba2044eecd1d324c9946e14293f00ef4b7f558b820ae7675c7cb5bc8d20fe753a36dda20cebb23571cafa699ec4acde1c4e56085ce1fe30dadac08aa58e3e64e2283b08eb7c73aeab1e4bfc4def883cefe37be0b92b2a333d8", "1af1efed62c007c904fceca02e4bbc891cb757a972875486d46c057f93e6c91475b4310938df4bdb71bdf0ddef3352508f7c4b146db07156fd2af4906ff2f232e853d5443662a162d2cd782d975de97c97bfedf174c565331c9675cc9dc8a8af6b154511e0d089c6edc6bc694bf2304a79e4c79aac3e039842c44098fd61df981b5956a0edf234464a245295f4cd7851418ca31603253f209135510fb8d74eefa64a61a6ae0f62e0adec0682bee60ad421ceea574780acc4c2dfb5775c49895d4757f86d018f0497b822ef74fea21ab4ee1b91594854c677ccc9e3016d124721876c3a625bdbc9a8e6f290f847767eff2528b350434dbf00bd91e08257c4483e92846195392e49adc7266b9149482b54b8a27148003a4f380e6df52fa51d88d264fae08e813984d4b7307d9", .Okay}, + {.Sqr, "-a67190e82ed7036bd3e2b71c03daa513c384de022c268d590d5cba21f0634d1e0d532c43da5b949301d4a096273ef75777e95009a67b82c3199d2e18bdf57a18b3bdcda4d26a79d0dd4efc028f38314f4ebfd221b9b9c4f035bb86a9d7776e02710cd30b9910b515ab98b2d975905eb1695bf3da88eb917bf5c1a1af415a9bd73ea7061fe2a2b134fb66b8271dbdfc93c06cc33ddbe0", "1fe2c3606d1c1b5f1ee9021e1582a62f0880d1081d3be363b226635ba5c78289134943110b7e4464291445c502dd646518c38ab8404f73c1228c80a23d5a543c26fa8ae6add024d4cc96874cdc90bebc8f579436545ec1fc941bb2d3bb5d5fbcf791d582fa85064b72eaf64f5a2d0e629a6912d78c4044442c34f813374c332f702e941dabb2b669fa91cc5f4cd0a45cfb45576d5153", "6c377a4e5bbe3987ae1c8f3e93f5713814a4a3b562a6b7c163b7891e6ce052bfd5914952903da52f05fee0f9388f74f8278e91e18d923cfb0fbc239fc354a5b6ec0623f24a24475ab7f0145c0065dfb3b433c986e31837a1f7d520388bf2f3b5235edd70171dc15218dacd2d46e03ab0a2fb963fc2226f41e8bea4435e72fa252ac4278599d68987bf69e16dc819418b35cb64cfc11e35b3e0c3627cafb622922b9412677000906c909b9e67f58082ed673a8b1d790685036c5ddcb73c2a2fe74732620b7b50b84ba0351d7af6bcfa63933afdac0cf3f9696b5d59d355b30d2323ac8ad2897f095a4c231b5a8a8168fcfc9de95239cf6e33fd462377ca53c0ec4002bc37e0a927c4764bbd2d90c7d488739f9cb0461c8d70d46b320d5436dc5bf954bdbd9e28d0e9c5990400", .Okay}, + {.Sqr, "53712c7153caed3bbf060c6df36117e4909aa26e8415d54f2ffa5c610a816fe4e5549aa2522eef02094c886ac3348b17d22b6af8e095e97b1226277260b1c399c51954891950e6c9c55dbdb39c0f89f58c1f07428f1e027d69ba8830e94f347fdc4507f3d8930860c0321ac43252eaf54edc583058eb8a36706057069f6060b79557753efb9e2cb53edcb091fcf99ccadf7c89d7ee01", "f9c6b5d905c307a6666d4a226acaf0a68cde3e4bf398b99cecfec71adeb7d18e840cd459de3dd7ef92728dcbb0b036b762e158a8b736fc3a7179ea488271a5ec0ec2f48683dd8fe4cf7b6afef746b5677576f802b17419a25e5c75683734fa18b9602f0bee4a47c775983b1bb2e7309860a8231ccd2c6221d435750d9877bcf672d31dd97b97b7a41668c20db77485b9bf0920022709", "1b3294d9c018b5f302bbbe7ef87da52d4125f80c65f39f432e7f199b5f8095dca09f849d9e3a3c6e5800573037d4c9ae44863f2a6518737e55337821facd558c9fd376191228d3fad87d26fbdd175db01772788285ccc26f436769e6b25a1be5e53168f7ac78968aec5f0ff9d09df30942978029fa8c365c9668646092867b782af4a714368b97706569fd8acb79c5f5f0150484019b652dad3e66c1ed97f498a360fc4f523d17eaac7aed3b809d07ed089de8e2a112177d5b0f59de713fc062d236c363b0030f7aa404ef18d898f2f219d2727befd7caad85ddb6fe36b741078f662c03e5f703e867f82093dd96082e18f0cbf634a3c9ce4b4264475d895e875b842fbcda4d2d9e9866a7922b2ddfa3d3d0445db6555e9c208046629b1c6c5f7b63dd82d5a121d6b4f3dc01", .Okay}, + {.Sqr, "5ccbf2f8ba3d9c3aa4025912b2cb5d32445ca1d426ef3d6e2213cae31857540155cb26eed006e5962e4475c36135ce01eac877857e1a9f4e9feb2aeb333ceca19c596d4998d82dc374a20e2c0c3992f03e7fa5285c627fa8011d736b387036c2099737ae7b9a5e2c2d95aadd345b97389e23840ad745d2ac4c385a5dbfaca419eebf9abb6f7fa7c92c1a0f149d64ae11c8e23967ac96", "1554e1169bb8a1f81badf3cc6f13e165b8d59058ea989c64f78e80f3f4739ea749520a8ef7b8e9b26d3ab05128fd5b883cbc8167a919be7d7b5ffe98dd535996d8ef23b975af70250f2aaa226c1cbc3e844b50b263221cfe1c8cb27d296220918e2354c86ed0fdbb1dae68078733f8efa3ab4c1741fa4b68477944ca6e92fd96f6575928318ce6d2ee306b370f8c2dc047c17f4c3d8", "21a3391e02eed7c5c51cf149f2babfa40a7d7aba834461e4805ad86e2c53136c57fed026daed7f0cb4ef0a04c9dbb28bd6aa3051d10190a7790a254c01ee461563acfd59557d0c660023bf2cb2c946b3377380984f95327b430a9b855ffcc76560279eedb0b5c05051f3553afb66c6826b681868499320371ec562a05fd798014db2c00637a4405414519fb7eec2b92698f5243e38eab02d27267f64728264c595d1777693dcac30fc510c3f3e3f483aa6f6fdb845d19d809716db141e9fdc05b7d6e77e8796942afd68d0f03784f867e28c08fbb5738248677fb1c3006616542d6f0553999e03d96c20c435ab07f3d05b0fb07eb646d82dca1066f0f2bfdb0c8e70d7747457a5255259dc4ed9e8ccbccb44e550c6b313944f5f37e82ea8565a5fd5a12c39826daf210de7e4", .Okay}, + {.Sqr, "-490baae2624cd6bed6cfe1fdba26d86d1bce18935f46c4cec4046a8f0be9c4acb2208f3a0790652fc91c3894740f8a371ab3b4869aebe28bfe7a5bd97ae3ce8430c350f810a24dcc40867e62d7bb72c8cba686d21040169fb67e3e3ad4910ecb9b65cc2e4f5aeb9fc586432ba2ff2360d1846538a97bb9f3980c45bf3944dc9ccd94dcdc571f5becaa07537a4ef041f153f5605f9fd3", "f43ddb9187790e4f9311d1b26809466f3b8d4dcbfe4f584d17db468ee2d1e2717b25444106401b6d0a7156b5202daecfcda2bd0f895e4dfa82d03b495d05d1fd87bd9422379b14adb1accd56d522787efc552c0e7957cc9dba130bacf84a962c69de6823732bd4d376b8f7dc492dab54e743a1ad1dddde2e5ac9948959c95edc3c7ca62ea9b36632ea04c037fafa6448215fa9ebd8d7", "14d7a7fd3d95b7d30d888e79d11277d8a7171a8dba259e0c7adea89c7b48200ea34492856f43d36cb2231f429b1844a7512a78bdd419b567513a1e8408cbdd228272f0b1cab4a3e1ce96d65fce2cb7ed135c241981a1c4b79294dd23b664ccab1607a9cacc24fc277c96dfa517f8cf6bc3ed5b02b4c75e7689fc3bb3517ef52ece30cc32fcd31c76f51c5f22b3c82b65e1f8b92bccfc25c2b2f8f235fa26ccd4e10d7fdc09be6460db24c06701f85e0eb5a59a1b824101865e80b79e9104d2c68bf41d5ea8f0830f8610689353e654379255f6126d6b67ed029e34599b8f85c07e37173709871ccf8209f798e6cb374ca1a95da928f11a57d441ed48f2fd3da387e1f9029309989114c16155a6f9f1cdee5be0328730eeee2e2ce692db883941ea454a83ae3897744261c7e9", .Okay}, + {.Sqr, "f3583386b751934c7497500b7673a2444027404bbfb89b19ca4676099b7d26744717bf8a061802f911037b695b65aa1f884b17b4f599e50ca9643df4ca685fc567db63eb4a621887d92ed487eb27edda50ec308e07e90579f8fa39cd46f52f121df4676ff63842c1a6ced4043037b07f35c96560315f28d6e815434c95eeafd04d9dc24bb579640282b7d8582e4925e24d08a5e6aa8a", "51fe16e59dc88a6d3243d3dfba55e4da0e0ac47506aaa44fb6ba4469d720b6cb6415abc942983085c940c1a3f104727f4a206dcf2c9d957c1ce85045687f578e2b2064e505674e5e24e56e7155ef20497c3c5d075d38cee3540208055046de6f542006c9ca6ce07fa8d4ff4539e6640b935db386847b358e332d4a8fcb5f6c582fe12134654b4c132a5db66dedfc4146cf28819a02d0", "e75090353701d9a75743cf10fce053ab73e4220a1c92e606f2ca8e32bbcef29ce4a90514be81ff05117601b4477ba9afbf7a022a57e2e9ee175a36a4f76d655ea31c21f0c6bd8d7ae001e53dbb9fdeb15fe116ebd489ae0d1d6ad519992c0bd4777791ce272f2eaa5485700d74d8b4caf5b56c8b1c759e0687c2d08a087db30783afc5b0493d18b1d70f2b8f9767be03c5a0beee064fbc8426a529ba4356b5f1d1ca804f2050da6f272ff8b686241f2bb97713b5a7583a5d634478086231e0ab04cf22d5aeed50c40091f8bddfd682a45a11c5e76cc1c6debd5550642a2a4c14ab0948ea991e2bfebbb52f1deefb354f646fb7397bac0bb5edc32b224bc523e77f898daee9ce28d48dbba70fc8a84b5133dc425a8dc8d4eb562c5e3d716584883c1ea75c8c2cd44cc5939264", .Okay}, + {.Sqr, "17d47ecfd9e4b2652db61ef622590e2cb980fa723b9ef3f5e82e82cb4d698e61b01ddad91302273f7d6d93c07e7bb9a53930ba36fe021af9d6eb4dc8b39fefceff81e69c317158b9c8861494382ec62bdee1f2f63ef984d6d24a92adb00c61a5c4cbb6af1a3cf953f926c8d848ae144cb93f3f2a15104e2af913482263334d70183b6db06bd8a3ed0d2ec0b968439efc671271bab21d", "5fa44389c49e6e19cb2bf20dc3baae637cd31d040c1b8dcb0be29a5e5fd5011276ce6d05192bfd0dd45c8cdf42801f812b95486bc9c315dd5aeb6fab38a6dc80a4fb4dc2d7b775cee3280c83859423dbc87b33383489ffc4235b9cdd473baa3e59b7472eb379c0c39cd79ce079b5dd1c61d8f2fe489895190624fb9c1d59b2e0133d317efc7fbf292b8caa57ef51c5199cdc6a1df8f7", "237df2ba0393e14deb40a907cde485982f5c4a4def4006b6ab44227b40aa27e0b9d26caae3f678eb947976f43e434cf8ac35303aaa4a5ecc05d25c6f1ac6849799fae6a9dd6a5b9e2469f0e71d2a8d6df60c5c06f1f3bcb536ea6e8f15079266df5a6c26ea67b881b19d7e9c52634416e62f80f68d9615d7cfeb5fa3ef29cc4dc048bbd30056ea86fc412dba356aef4b71477665d48a03f33f5fbf50bf82a25c6a40eda301d0e895b3ae50397bd3b7baa6c8ef33709bb3fe88e496c89823b58105356ea6108dee8784fd37536598b37ee36b057fe9fe7169cd12c8ef7afda34e47219e2597257ab18018bd62dc7bb742c7e4345e5e9647ef40d37c11cd668388ae8e2f4f2a0aa0dc2cc6c81231b093f5522ede7411903a9faa5720edebad792008cff70e132bb78e8105749", .Okay}, + {.Sqr, "-6599d2b76f028b4ad4d20e70e16cb4f95eb83317ba5c86b025e0abdf66d4b40e1103466594a67fbed4cec78469ab333ffa36df97ef14d667811c99d9a9c66f0469b22643d3c12b340065076d4df830a1a1f63988244111e89f54733595dcaa01267014f2f510a19109e95e57d0c7d1b1015e054dd1e4b0c412c001e4b0b41ed4034d9bf96f93e5b9f574699d9119577889ad0a3bac", "5aa5e9e360a2af1c3228a5762d11bef1b12592156e75f0f23a5a00e70ea25e8fb87051c67ec2b384bc5f36f582dbde55941bed8d0fd648f73cb3438fc31ae3da4e6baba264ade5b0b94414a4e76c73b176f0535fa9ffbed365073fd48776c818cf84ecc9a0cbf274895d3b3b32a2ee352b979f0281bba04d790dab8a3155df2f1e9440bb54379b83f94961e2cb76c6f2d77fc03dbcc2", "2852bcb24a4c28839dad41709652e6bfac6fb961855ccf463b10f0273de9334fbf2f406bfa599285ae88f67bf9509c4aa75ebff81379a4e6050b067d862c47e683e8e8f8ecb6992b51d4e31c53882474b1aabeb6d319d341f007595b7697c89ce969150c56291fbf87e47b45b787cc7e6c085c8022d42ead616aa89e1d9dde66a6e2be00cd17c4658321a8ee22eb444c07f575d1e4acb6c5912e965bd77717183bc6d3b670b88fad3748092ff0f1eaeba2eb85b01f7436cbb4e732402a6292dff38652d627b1bebc5e7d3033688978ad08c10c6a85897d7faac0ad5d32573e4638d4ce591b0c9bd6e4f0d2b812f914c0ff079129da9bbe359a1041d8a9e5c11a199a2a1904aeb87f92f47baf48648df6abb2fe0d4df882e2b9ecf0bfa553700189b868c3f3272f58bb90", .Okay}, + {.Sqr, "449c67d89b619ade753dcda1db202667c2b1b0d7c904c770da79c161b8abfb62999a2605c48ff6c83c78c91ec3202f5afbbc51ba1e72ac20f332fda1500173d5fdd70d9bc04edac9ba33531ca6c7b940e57a82009beb16220d63bea61c4bd565a382a22da552a8c251f024a02fc89ab76f4ab05928cfc365059f524b21ad3dd17de8f417e87cc3ae8cbf5d1cf316d6495762b8ad1a9", "8b73039ec05ced44b293f3f31a907dca4bb3d599c6a14560ae602cf911fb4609ee9e0f2ec36e82da8a6d55aec307084c010057f8edeec4709850bfd68e330a909d467449ee3a36bb6d8fa7e89bd1cf66618fda44da7cd7037d8f20010133f13dabcc6973620be8db84e5311395ebd75fa8d5c622baf448da4cccb80f63c125477f0ff7d1fe1758d465611b7dccb370230e4e644f91db", "126376b9cca93d8a0b0b690e49ad79414f55e660c2e63060d8f87b0094b7f0782c216c363a250bb428903088f179f8faac8d25d0707c74771261d67738b0171b831c42e16fc6c9b2c7f645f18e1f324abdbe0f64714d64fe27fdb482afb2fb3b7cb8a3ee9c769b9571712bdf9fbee414dd02cca9b5fe7af57c9f12203489e9beed6b4adceef1d378e5723de72c4ad1d4e248103739366009772254b89acfcb1bdf4f202b34a87eff3700d8bf3c3d1beeb0ea56ea3247352de993414c2bfa2d8b875b19a55a5374622b21e9586cf2ad0711a5fbbb55f23e5f1b6dabbd6e44cf8b2c8aa6db365b9f7719ac956bbf32fc659e20b48b600dba6bf9f823a50dbe38d19d8cecefbf76ab4b91cedce0ea6d8496d741980f28784e45c1ca62f5fec070b6ce90eb7977ef817be96191", .Okay}, + {.Sqr, "ae0962f03f751d805693967e00024b43d55f8aaa4b4dacb2c3cd91e94944c713a6858ea4ffd5bf8ce7daaa3a0d21e2d2ddb42f357591e5996cd5323bf02bd46a48517adf5a4bc50a7b376b9982a10ae8e5718a713ccc97545d2862786aede0190e3298ce0640187938edbaa2b49d1a685c7afee3315d9e1a705898fca3d38b5d3b720266274732e9fa163f0f9cc60366f2a302624690", "2cf7ed5fc31d60638acfeae38e7be18c4e2c64d78a770cf30f450f8de460fef524a2f9b239500c648009e915421e063b7405d088561b6b54787e50ad67cb1465ac5f65c520f9e2e59b37bb54fdceae7fc95fcb7f3e27a4c4a18ae0f1b7b10bf018d5cac9b046331eba7a87f155827b7a19d7f38ad819b5787382d558992ee2584ad6fd19072d4256d2f9720efbc6413fb3fca092deab", "7650c2d6b1647c633e9f23f85623dda8fae39b1c0331682a1c0104fb93a3136a70834ecc78c09195ff53f396dd74394ed756897c4590ace9534a01b952b37abe7fd586179b9a6e9df5c3e5b6ef0f279c3d082074f662fb0a341e410b572b231e3229ca4ba203f5c7399a644834568cb3546e8a9f55d03cd939102ddb9fa668ec2a60594ed49e8a4a884b8aded7750d8693370d8f5ea7fd4dd084b1b038ff6d260c3d6ed2cfd7257298f3b89d780120b4da1971e9f714c7419f7d8cd0485f124aeb665155a961a3aa0514bf26894ba3ef51b58628e89b049a4f422386eed485fa8f634f19f1d4fa4d79205d98702807a000fc7566fcba2e13a3ea73283c24d103e312ceda2a316826460bed8a2f8cda366d9f572455d5b1c7f4e6d1cc721d9924acd173057153ca3459b31100", .Okay}, + {.Sqr, "-5b26a4bc853c4e14cfb4662d3337fd76b72b3abca0b6f878fbbb08a9f56ded737c1e2bb5b1024c5a3bb093021268c5d857303cf86600035ca3995c6e4c18271576a9d2d2d2f73f42aa3167f4ed7bcafb8f999181cf9e0884ea8bd4a22125a2db88394d2d2642ceeabdac5fe5db61d9ca04773236d478655bd937c230dcbd53d61e53acdcd219780a224155a8da9731388c54db1deeae", "f2ed13eecf1c4d4faf6066b4c2abf28e0c2e28cb2d375aa2489e8b7dbec76d7024bd0477b35cfeb2a3c6b217d9aafb010b19ee5027533482cfc526bc31347560b6d88bd16822a8154b7b57de2094b2ee9485f8a3706e7d2956f86411ff290f24c35bcff37f0b47198f6fabbcfff0eeff19fabf1e4bc88a50fb2ac45b69f469cd32bb9d5698ce2970e40f14641b8ccd086c4aba98d55", "20747ef358b282f333ccfa38fd187dd283d46be32f5b16d2d501c9fa3d230b18770d35a790560b3256fae3340605e51baa24518f7a3840ca6a1fb24b045ed935bad5300791d81a4f7df6082ce5c250f3da60d6b6a87685b64067a7692ba782f530fc241cbb1c53e86feed6b1a63808098778a0889a0681c84d8c886e624f9f7ba59101384646a75965cb2f43f4944ae82045512199b939e0f36774653d004780022a29563335f988e915b7e11da0ba14e06631525e674ce112417fe7c4f90d851eb5a4a095443c53f135ba39fbfc041ac6c98597f977faf5347a9f942cba2a599d44f7186d58d4e3076bab998ce529771933ccb531bd70d87c8eb735ca40c00950bc5427d3e9485b136a3fd18f17c68396c9dbb4dc3e976c824f11e8f03fa7a4761e27844c5f2c0da5f3fe44", .Okay}, + {.Sqr, "de75d46bb1fc2cbeaca9e5c7f596c76b67fc53d81a004c46adefdb55a3f89c98f032fae1f8f5aeccee9252aa19235eb8439d9bca672856d5d5852f84e5d6cafe29865bfd8f12d833377d880b96d6a156003ed1201ac5627bc1edd20c0e29cdbe5195243e1c4f61bf1c7cb7c0870b4ba02c6afa90503167483a0e76536e62e33e546485d7d990fb78db698b3f56fa943da068a0790d41", "51314e692d9bc7dc54342fbaa2f2357a4c7216a0bc4e97b1e2e76152ef7fc47c7c47a8aeee9f48ce14f25dd4850d4e8e28f50788fd2295be6137cab8e603377da5b50d1c45ff3d5d273675ac916120caf4d6aa52ec2d0359364da5a1df8b2a2e4698cf7d4ad5c086207f090928d6756217a0f648ddf836ed2d4688f3bd33fb9aa1cfda9ae59a5ef40c5bd705d263b00726a0ad066e81", "c15092a6a3649a33886861785b4a3933a1c3d56fac4d14c4a1f6a7f05994948502dce8f741bab2ad0fd89fc5774b49e42996d96edbcefeb395df7884fba49d3181d9926b35f3f8f5fb00e0f433a1d5911245ea1f3cb4f5dca80e4df1698b34946ffde51c3043b7e96348d63c099259261aef095889b2e772c54cbb6e1af17f23c1379746ffc4acd62c8d0321bdfd42d9baad5e4f56064fe9a407754a1a117667c74f2a5a1bacc2c3e7bd69b3508f07702dee1d853a867f6da8ded1e93b130dbd15d661e56172ec28da8e3456c1b98853674098fb8e81d77ee34eb31c522665baf6f854896f79fc2294c876f43cd9cf3f7f66f27c98172370cf03cf538b2d6f80c4e99362af15bc4effbebd10ee627616ce98960eb4a1e9462f76b8627aa76dc4ad3ef351907d8e9ec821aa81", .Okay}, + {.Sqr, "704cb4f62e1c92291424a3ac9bced944aad4a78bbc46971f8c52543beca01bbe0089169e9bc298715fe8b932d82051187470534f7c9d27adcc0f9bb03fef1fc91436cca1750351a7751b5a834947c09eac3c3d86138e46a009a9b9fd63e5435c4938aa214af461f37ff628f1046a459dee245ad7ea6e48292cc25d887bbaba9f0b908f19561da91175070e4b989fec66fef2b8a20eb0", "54bfa64a9d2413b92e428f0aa32b1a6ab8f29df37a99f71dc7568433c00404407e3874c3eb4b7def7d649d7308b6c708b5589f35243fe95e3ca4d9a13cab27325af31462eab5f477dfc340aadc27aab2a2e01fcd06f1a6164fed6e4b7ccca8e6949c3a100a92b8e62a9175562415aa1b85729941429a9fbd50ea42a17dda00bb297525b8df99a9aeb89052397ae807ea72caa984037d", "314335535a6f7e6f8ec4f7f58313402a7f151a38920b2bf5929c91d7f93a69da58967fc9ddafd0491667c626845932d8ceac7103816a69687f74da009545a163fec2ec390296df7d59bc9bbcb48ef105896ce0d6196480da42b291a8b38eb3d058c23c0ee81137424fcb7677dc48b11f046673b20b02266bd8028740569ea8166acfa43bb49727bbd5c3bf05a9d90dd739f143e24255286f65b9d7d7633a0b68ed3eedab0622953fe494e73026d1472f44a042a620885fcd9cc27d6a1bbbb686cb7ba41ccc85daa3e14f062099babb614d188618538d5234dd769fe13d0694ba98c1d319631d18e137dba96e1901156aba3db99955006a173f2378e0360898b1ec0eb13a743b4dc16a285105bda9b68e46816825a84fdd3de231f3b24d129271519bb75b60f260739797b900", .Okay}, + {.Sqr, "dcd67358cd71ead402f4bb48bbee485e03b52394d366b2dd4c005063f841b770e9f9b76a258b978e824a2e1437f69c1d81d8aa23e3d674f5ace6db6b7c874e932b5fb9c02d90c16c947fad0a62707154dd653efeea96e8741f94f622894bf7a07bcc0611a28ec80e2d52548ea738ea4d0c199a58fc516d4c474d2d82a3d9c1269d3ec8e36069e7843e54ffa9a80f1c9ef24dae317697", "4b5c2895acae614fcb747140aedaff0bb5634c82ed75d997c211d415d3196c6b65ba829059cceb539477dca38f1aac807433979c465f50985230ab87edcca52f1c11f1975922a184ca88b504eac0a29aa86fe0ff195421222d69c5b49353b5f48c995661f06d3d48f9edc1ba60a54e2012629f9efba1fcaf0d20677b8b960aec46f562e0b970e9a1590a9719c019d82049452c148b97", "be8149e5ad8c2d733bb52440bc6eae97fb552d2295268955d5eb70dfd1fe0ff19305c0a62005699f6de04b2843d32c977861f017058fe68a0cf8fc885ada6e780d587efdc23ae05d95033538fe9d41133e40c1215ffb4a566644b879ec6a8a2f5761df2311326b4734111fcc76b04bb312c7ad798d4e657166ffd35ad06aa43d8ee06b6887b98db353d96f25a0d384ff62cb4578dbf988da5ab321054c33f9c614635366db5ca3dd6a6823b3fafbbefc6ba134e9d6a3b232b5df6a919529a8459760969b1abf6ed07fd24c6b48f9bb0652e0596974c24ecf12239fb148ba39e30915ce9362a4fa9cfe254f0ca808241022d9b2d15504f3131db5cf1a7ae96296318120e0e32cb0204d36cbd66e1e7efc1117b16d3d9948bd80c05946bb0f0013b624e1992ee21999e0bd8d11", .Okay}, + {.Sqr, "-9e80256b77eb2e23bfca7ec5a59f56cbcbbb3b93edb6aecdbc14a0ca9f9de4176ccecd3714e7dc8f84d27267d9a6d3e6b2afa65a5ddc86501cc51faa1f6a97bf75a4b84497f25aade37200ea39c1054fc4b9836efa59a913c5e7a7b23eb712ede62f3ff36b4eaa2b2a32196711392bc3f6e9c357026e63744fcb4191f4715676f313e68a6a0c9a170511a2d3a261e6cf3c2475abbafa", "49bc067387576712e1d3b848110ccf65a22998bac642353d31e43dddd743c312c1dc36be0638c695e5f3e64a4474d39c1e7e7a2ccef96b2993dfe0bed15d0165c5186d220400916faf314e4e2e1bbc05910f54ee7a8e9985e60f92ebd2410b9e55e62c2e5591fc113b6f17c0324b865318173749ff7f3623885442887a2db8a60fbff1f29f6333ff0d58a6cf88159174f452e3426ccf", "62226e5618f675e9b69923409442a71e23060029353f25826dc6bce132e4bf7845526a1d868405620cec7bf567aa769e82348e5e8fab832a44c2186b11a31ddd178572dc08ed4833e9ec42ad7afbcc38c5873bc9ddb282286ed08babd4e9d60b35cf01ce7ec4f87dc0329546f5fffd063f18b43cfc1a89fda7990caab172c4b407b0cb09d3f83e80892bcfd5314e99127f75dd168ff451565835fb35f62fb7b70e76e9d57d36000dbbcab945784ff9365e2d40dd4e4344c69994bdd4f273a58c95c7fb659419eed581e5fd72b08132015ec04f59983c1ed5eff312cc24e8b43c364ab31ab979e9a2411cde1948a65331922b93af742221d9004b491209af2502a16d01ec76444a717dd713554eae853e449cb839b2345d2e74f889fb0152ab50f96c157f6654326bd68c3c24", .Okay}, + {.Sqr, "425d13ed5f61da9d8fb4296739d281badc195d2cf093cf9d0c2afc1681b2f37b0a314bfac8b3ca5dc981fff91313f4aac03f736ee90a648cd98d880de0846342c4b85e42134c41f9a3c1c468a436734228bc468fdfe5b44fadcd878265c9e5b229d53f0927d8437964b1a4d49e5c5babec46fe3935ddb78dcc1ea4691292ec74703da9358ca0362bcca99f2cf1343e8904df115e817f", "bf51d5112adff924e7594676cacd180017a3cff58d8db0ab58f2d4bd71839f43351fa1cea26dd76c9c23ee4934f547de6ce3c520f1ea7e7400c5376602161fc705403e21e09529f7db1072bdfe9dda5dd05737f578cbf03bc324d9ac6e7a6a7e8da7e25a2b7b131cd566c762ff786da75d00685e875e21baf89eddce7891418ebcf4878fdac226fadc14714726e6228f3d1f14f9fca9", "1134201de132da1459bf3ef87749e087519459122c0de6e487f5144129b6e9da483fdadd46651a1774c752e61ed3179f8e4821c2632278d7f9c1a49a6183b5fe05df0cc7caa6453a3aa2ae98d0eee248b7803d193ad67789b4254b7d0b128f28132fbc194a3080c36c7d76235bb6ab88d668da128827dc6166741afc0004ff03963aa5988006d2e4c3bc7ba478319d85a8854c74bed32fc27f0fa6fdb7601063f6b7865be908880cff5508b755e3d1ae1073815250c24f1da4de14ff79c327348baabd57e87eba50b11a32d952509ee4404333cb6496146afb1451bfea9ecf07d1da01d9435884e6b72c0984599495e6a5c1f658858ff65d733a36e45a696e81fed57b6acfb5d814363358efc43815e45ddfb6914c0046b3c23188e2d831600b871fd26255cd435838c53d01", .Okay}, + {.Sqr, "-23233b0e31022d1ede0dc97c8bf9098d04688cd658a7429f96579c64e5ef1ef81e0a4cf0e4d4f6965c292f2c67d78375fe49af940df50ba9e3f4a2a9c2afbb5f2450d92cc65ad0a1eb5ac8490f9742a2b27c26231a887df335f0556047192a16369486b6d91ebbcb8dfa972ee372c5a951a5d67cf36e6c19f0c07c5420c27562862433773bca8ca74e347275d622b2f3f999c50bb62e", "2050763c90b3c97faeef17d19170dbfc2d56161af698c6050a9cdde998c81603ec3570d29a8e33593c26cbb3adbdf411b57e2fa7e02adf0bc2b5b690254be7ccabe97eddbc176d73cb4cacc0f893d1c9b57d52b71877f02a9be37a7921a99e83384b82ce6c5341fa8335ebd964ba0bb27dbaef2c0d86e998341a129f3bd2735a69a343cd81e79575ef7e76350135d8d1c3d0e3b1a4df", "4d2a6ff14e78a4f2d937be258266dfbbd9c48b260d10aa933ce8c0c1e3cee14d19a24ea37e3cbab80b9ae41cda4973b4ad27ba4b97fb649557bd0dea6fb24ab4ec505f8ab5e9426dcb76aa66a9057f75ddb1b6b2d118a76e43aa82ee41d311a0e01847783d14ba4a527a6822bc19193882b8d40f25482b2490638c164b6d0a0aa8149bdfe994cebf8580741dfe13366fa5f710a799b8223b445409c6da7af6bca6f59d8926b5de590886bf0f35341575ef9187394250e6c0de43125ec65d7e0fb12f8ae3712a8ed07b952ad06c30c1675850a949e87913877bb6dbf5fafee2f6feaa8ba621c811a040ba679d33210d958d58226088a3f088fb956986ab77eca59ad9a8db79b05504904a5351d49dccf6efa16b33b4fa7519aca98e0350a278b0d0a2779bb6445e7f5997044", .Okay}, + {.Sqr, "-3f73f25033211eb1f9ab19550b6a03902a8983f4eb3d76d2420f9cbc87955d4db07bdc6b0649cc2e71a00ccfa355613afc4e4cdeb72f27cf1fc2a9a3fa94458d64cfb624604baea4451a77b0b9ff9adaf577f034781617d4e1fce42f11ea298faee881014c6e9a42c20230247a5bda22a312e5e515ae6b81702c95470d3eb35e2a4d9a2c38bfeb76dcbf3a0fd7d2b44b5f744c722e32", "f79b3749aca7e8465a2a1308b5a7428a09407b2e1ac01abeda67e8495766c48da23ed249af22c2539e986bc18f3be66a5f24301ca7ca4bb9ee9e68e6dc1b0d418053f231bfff6d27709e60779d5471137579df6ee58b98be35387df467327c33dab4801d2c43120439ffe8ff2997deb26d991ba60cd2b32ee5eb2e172b961a34e98be8b4894c77a62de553875fe9e3e648d696d1ed33", "fba45c71293f6a7c9ba67f7fbe5ca2f6ff51faef520cbec9f62f923b2919a3d22b265c329d1ed2e5006528ddda8f4e9ca24975ce36f7e89f7657a8c4e650f64a5ba9b2881fb33d9e8b96c7dea59e578fb898de95219f979856818a8b2564ee9c47965f83e16259b32da3e9fdda2c5cb07a810b200c9ce61d6d3d7aff80040a1285227709edb341b484d6d907970584b1711bd7bab46ad5f4c9c5df83588b69cba47ee1cc4ea8627a06874ef10d0b4204e714d39fcb7db08a83f02343a4891a1aec4811ec25c5ea3f139b753ec42bffb5ec8f8d06105b4d7fd7118dcd4c052cbb663916b6493f17e18a6c10eebd0699f54d20acc8cab840befda0015e89c6b793b8fae85306bcbb1748a8eb249154976f759953cc3c121b0a2361bf57b1b988de404a7777de2f7aadcde01c4", .Okay}, + {.Sqr, "-626f1d383deb9d22e4abd638544edacb189d7990fa7431f7a5ccbdc5281cb5b7a0f81621bf4abd33f36356b0a8da536100f3829d1b0ffd7b2feadb5a2afea115bbfa0ce1441f06f263e84910c9250366a1d3e57772f8b5bee1d7a4a11a065e7fd944c227003a24555eec8c613596440df187439fe2476fbfa35b2efb8339bb7a8df35e166c9d5850f56e033849ec01ce8ec0a8377258", "9de72524de5fbe59e1705a6c9ee1a0bea87694268923d186a1d275202f9a24f4eb8448cdaa12c6e60f8c808bfa00548df6107ea4d35e1ead6fd606bd4bec09133c0c4545c19a93237dc1fa42ef71b7cd204b94204cbe2e727f468808d2e800cc91354a079013b3f7e2d534e1e55c56de301c2685245617b375c21d4e1ce7d485e2c4a3afd42ec452391f0bd35a68a59c0b6bf15c2b8c", "25d942996983e10382fea5d65e9980726d4a8a66ae82f6cbb18c506546ef7604f0dac699caecd68c97bc75cb75dda57d839b088624dda232e6a74d68982e656ffaa20cb57b252597314e684afcd544127046dfd9085ea812b04de24171782c097b9eedea43049f0e4aae725876dabbe67a17116484687df29352cc97bb5484d443729797483d3eed459b9dbb1f282defce34251fb9e45ae97c4bafb1925857c3bc597ae376fa86a4da647bf77419b59c484d74fa21cee05db954514b50c9e3c4bfd103f1e71b4d4ff4fd5fdbdff828d39b1514e9686f2b67acba21243e713066351fc7086497d56b3f7fc141c46a59b59af835c8970a02793b00479ef9ad66e63906a3b1d47d663069b5249a98a931bf669dd0e974320e6def0f4510c201ef7d6aea75fafa2df615d4e27e40", .Okay}, + {.Sqr, "97abf2daadf3f930134231f17ebd36a7f954f8be763ca5d7a710f1928526d105704740f420f6bad703cc993f204af475be26bf02fad878af730a0dcb3c280be904a26b11b487fcdb31dad635ca50e747c23ed0d45fe04b66714780674a793f6d5bcad09d965a64615cef49ee80605260054764d13b67a570170e37c3dc82a7195060d6e230a270505e7311ed0448be0a54b355a1834c", "30e8a0d4b5f51e6ab2eecad10574c634493f82449b5a33f65aae9bb0c4417de88491d05aa94053f1690954c88e0ce567f4505673f5ba9386b6fe1c26fd2dec4e76604c5519dc7eace7ae4573ca8e460caa7082630fdb81cc0ba1410c7095137291d5519233f1fc8b5e8a5fa431ea0b885a4f2711ec0fec853602b8761792488ce2bcdc45ba5fc29a57f75d4b3e3ce5cf3224afd8c403", "59dc4bfc4fbc5f9399c8c2f18d26bfd3f74fbd265128741ddab2c1925f0e31bb4b58395d5cc8e7639cc0f235f40346b43778532aa10764ccfd3256f6cb74dc710f7fe5b56a4478933ed7c96e8d4e5b6ebc1f98292cc0b5124d48b56579d5300b59b0b63517cf6499076e826353b89d72c1ca2c2c063ad15d66faec824c52d5fcc08264691fbc700c1c92e074aac050dc22757eaf442490d9ae81170c1d72cb6740201e067d6968fdc609410c23e154dfe2aa3f0991abb2be8dd93e695172e0f544b46da1ab30974e07ff6c1325675c31bf16c415b003a9fe79de03cd794f6e3da476a8d0f230414db8e917ac19b0d47a995ab7d6443355e1c87d1c3fd57edec8ad2fb08f53be5944edc81bc30bf86bd55b1bd8013bc610429a54e90285fc5c7756d0d815ec9c235ee0eede90", .Okay}, + {.Sqr, "f6716aff74cc264ed776c0929058957b5a3c1ccfd8e9ac756bca27999a3237beba9dafb38c405d29576b7ffe06b660fe28200579c6a50ca29cdd131380f213da460b11b604063a5cab611b27b45707558512a4645063e9c9576af42b76d6485d4183d9055e275b152710b3b8748afe13bd920e1f89119da552e46d4097854e6a1be9935e669f5def8ac8869b1cfa9b8ea31a056f1286", "3c5ace92f3af0ffde96fde649e7316759ca51067f3c81dc84dde7c4108880f9349888e6a7ea9061148be5a0b26a48b38eaea34f8cdda732b10d4f88659520a86eab22fbc92459833da3514e948cc8a2f266d3156d60aac490022d507dce0ba4916eb2fc3e782924a683aa6dc5684a6f12fd1f48461a8b3d320f29f062f784c9c4b68bdb076a448ab9dd1253ac55495ba26d3d3816aa6", "ed3e2be296b6017c4b69b1f3cb813508f3dd0244ff24247b821cae33c93b428c2547871691014322973e2e63ffda91769c2f0579eea5087ae72d8d6383cea91cece2d5ddbf75ff7b75442595c513a3413c5f2ca695a344f9fb4b9c5ba6c08ce911abb4ee3b05ea1f3b968a52988ef1b873e1778737544c9071b68dd620eb93b3da6b6d46c5f03728a35b37029c65a2e750f89e15f6c51f3386ac3034205e7a2296140f9408cb5b1726ee732b4981689de87218c76589bcd544ed9524d301579cdac9329798b7ea7197f71de1bc40fb6bc2b9396698317b5a0263f0995d52768723ed04e08eb888499afbbf118c46661886ee3bb2f70af6dd1bbc31189160ce4b5cf221c45a197deb5061b2880df6c27a3f167b36e4e72ddb7ffd02a653b68e427a9e2aef5cebee224d8b1e24", .Okay}, + {.Sqr, "-9fe488750693200caf92b01b8d0bd010ab8951173defeb9c51978713392c8010928cb925550c10168999b576040d5a0e14c1db0abe03a42d813a5955b7a91aec0e7bdbe71758b0e6761ebb9976d390f48aeb323eb5af8694e0f2ee0be5122d5023dac2d4ffd55728a5b63319c49b00c5ddc53e4b5b3f2e4c9a6e26e7f653012512e8f9b46126757d03fed8c28ffc6a26bfa0c5f148af", "3858416353a4e05ceb0a56c1db28f06a3feebeb2b2aec1bba063646bd7c08f2f847c95e276e58585aa6a481c2f8ba3f7bf1686a293791893864ad8d97d487fe45032ce105435cd4d451fc377451d2fbf1ddffb537698724b6a61dfa596694f086e1532611c42f09fc444d9246018b6b3701563c64d9122514ed5e59f7224acedc9a04a201d76e143e2127b8815a8eecea06a2cdc4f5d", "63ddad84b75b045c2d64f43eac49d7c7f115d4ceedbb33df6e010620ed2dcee0d190d914e2d753c0b8d841b5dcf1df1984763450038ad6557bfd0ed45c17118c72b8f8b63a4d5900ce7c61d410340f8e1ea2f2d2ca8ebb572198d72d29f391006849679736be0fdf30140fa938360f02003595be81a26bc3fca21dcb8d26cb402c97190aab2bd12ed987f773e2b6fbe1aa3f5fae11d661b4c71667bcea517f4ad338d2c330458bb9a0f49b87a6d83e0d6f039cffab1ba7d48c99406ad5e21391b03442fafc21000601b3e0939a29611a9e18846bb897f172ae564dbe99385306f3fb38bb91977eda0887d6ee44054f02d5b65a4544a37fe7fd60d9be85371a4ce1245454393c00783b5bec7a57d1b188d690aa10ee866cd664ce5143937c7fd5528e7ab091113a074420e7a1", .Okay}, + {.Sqr, "-937113b069d51f1abf0d47ab3db7ce54e3afbc7d5d699378e556a08bd2990f4f66c8f7c55c1ea1cec6f0e8776a55ddddffa79c0f6333ad66e5809894bbd7f53585c54734a7e0596543d094bb723d7ac32dca87aaa0638c12ba574b7653acfea42671fc17d7030866dbbc5c2fe9667265d19d49deddc6436589170ea6d647a0446b364ca8ed45da6c5f91b9868f0e9165d9786f3f97d6", "7aa005d41b2e8ce10cc635639c7e46e8babf1ce044beb22aacb70bb74d9a90104b566cf8a3645d79323a22dd3d37801decde712caf2235e5cbb4bdc9ace6630b90165fa5c12622ef4082913f1dcfab5f14156712bf742626bd573356d545dbdb348219df67f8152ebf9028d58c26fe8a3d73cc83d222d4862086d823ee11a1821f46a09fb9967f093b242341d899b5cdd9d264d46d40", "54eb0e8efccbd925806f2c1b4ff5d7cc1a01769d7275fb958b0290fc965381e7690beee3a0365ddd17a9e46232cc390c568e74be8fa3da09e629d8e04442a06efbdc4c2b1526a9e93da5c985a4723b7d6506ca4bfbd13240e7e18bb9e32e2807aa97fab10b377d1a3cd1d8ea1e79644c5391c66408865cad61c7201db3b905ca1b1439375f16329c7c662aeb83823b759a0803a682b900b92070a67c969344fc6b450d7e9754e1bac03f9978c4194636904c7900942e1880287921b7b29ef892ec9201347f62fa48e70b54df67fd511af1dcb274812ee00b5b72eca73d2397f258d53271dd0c9f4dc1c4099c92b72d8875a9cb56c1b0a43b92bf55073dd516c97166dc3868e73ec976d525c7103a1c396ded99c73a1bb506197eb0cf8ad612c73668e6d8863b5a17a96226e4", .Okay}, + {.Sqr, "-77c92cf9222c5a467f7a821003da9d6040cb4acea736edf63f6e4c5596c5ed2cd45bd0772c6a6747adb3eb1bd886fd4a794306398d330fce3acec729d8294e3e9ef975a00f17fe4dba771dd83ca3aa12031f5628c60bdbb30132c962c7cc527632356a23d838e8a2abff8d176387d2135237618db8702d089e023e795f4ae6354d2322bbfe413f0aa827de508adae24df6ef47598ac7", "54d073ec765bd0db74b31a965115d38df13845d707a536eedff0f07dcf1b4dc6f92423b3613d487ccb0a4296f38cafd05bc7dbc6faaab42849f13672f8c31ec40969c8b6a715016b921ae8a32db8b019a5f2767ff059ead872d83d8dde18d400d8eda4f2d2dddffa73bdf47fb6085225535992777e781a177bb9b1b4715fb71e6a60d812bf4c3d83a6bd5de857097df8335e6b7ad9ae", "380ca5e744e37bc60b17bbeb1bafd1ca53368a631ed31259c4c9bbe198b07edac0879c2c632a3c7ae43d0a64499376c4e858c0d598b3091037164c84694920720ae46bc55be7190adaa1d141f8d67da116ef89962bbe2206d08d447f41d8d129b99a3167ca86cfb323f7adae7c2fb850485072b097a5910ee5d5090702d9651020b6996afc5d683ce28dec46a448c4336f2ac1bfb0bee47cd432532934c8b68ddb33a651bad9a55cba1b7960f7f20ac8a21dfd24776a553f2b15e690dcc6e4267e485878f8e32455d9065877fb8393aca542c7ea8b4450288a941a12b0435246e057dbefd42c50700b32a2cc4b6df719be56e204f24900c19ceeaf1e9d5da26096ae3e93cf59fb0f6be84796d2fb59672d59603024d354b291ddad0ba555a578e29aa8973b805dde2b9926b1", .Okay}, + {.Sqr, "-6d6f7b528b91dfb2643b5dd83047991f6c4efca9ac8f910d943e10b4dd4a8ea78c1b1820faae0b74b7ea4b9af8db6dbf7f196f7c132bbb2a5d7b1b34e2c4e85abb8ca9818f480af8cf3805e15a1278961db8c8915712ff46f5872988f0f47f962e47dac1b0221d09b02cee64ce898beaff12984e56abc6e0e350e5f0f935630bcf39b7944f70c5e8019df1db4ca90102d6a78b51d41", "86488fe7afef344004fe747a6b77953dc09fdafbe2d0c046aa553bc1264b6bc86a9b2dc6534632251586432d903a1036135c593363a355ae6fbe08d4871c27493328dc969e1b839bcf2703f08ff4fdc1dfb85c5febfd57777f98afd378cdb2a4618caa1f9149315902ecf8e338829a19e5a9053a320725db9a440d59ab391fb7f5cfdb491b7c99a417c49600a1f68daf4d86bdfd88e0", "2ec81f9077d7adb9c88df009a132fd77511d7f15a0cbef0f374782e785583753fb94b3a74788a5b990e3d36c09a8403012f7510dbc6cf42a5cb88be1b0a93d2aa9162332ec7ebc6b163f72692b5c2ac3e2a2c3aabe3347c4c0a0186ff1a4d2bffe86257c0f5039766e56cd32e63c773f446178e61847dadb47550306a9dd923f6c675cab1f52aeb8450c0936716a194645335a6f81b74d075b5c1e27fa36c4cdffda4bba94235bc824ec15b295fbcc85aa93f1edd04cc3b1674f01d4803d9a5ea8c82f0ed08328e8de0ca9b57c2e6866f83fe85f98ad59d5c873fd685232a248186aeb26699aec74584abd273abbdad6eca1b3fb5d30800ffb2866ef5d6e6387de3314de601634fb75e313b081b409c36f89d710a695cc851e4056773f32948ad904d8a34f5f635141ca81", .Okay}, + {.Sqr, "3e52f8bbb514b81950a52b778867360a7ba5239184f6baf4a784ad398ebff6f754765919899cd603b4163d32248cc2172cadead17d53e759b4bc7745b2dc9aed398f7b1d95e49ce8e7d66cb1e0cf3475022961117670e4d14107dcfe5371c7951551645a59aa8d83fa4c90c6a503b63ba84dbba1d036fd2011aa8f4cd64003ec870fe24a2c0ee6e0c76a87c7208917c554b8283d7783", "fa0f9d12b91bdfae70e940c9fb8b0afc4385f08c31bea6b07d5b2bc820d5d01be82157a1cab654c2e379ad3088c42022bd9456f59d31b9a9143476eb0be65d99465180c92531c388a90e7fec326f7ddc23b600a1dec1fd48eb8c237df67b9073ab4b2e05b45505a2d304c8af1da7373d69d6b8ba5bff4617382a7fc360c5307b79dd8e77efa739b3d383b00d2971733f12ea284f1aca", "f2c4b5f35a242ec6453fa1aa88d08e90bcdaf99e8d6c52c6a46b6c95ae5f3a998560bfd7363a8eda9ab095839beae7e83b1fdd94a78bb775c1cf19832b2164897ed89f9d81032ab777f038b998768f034e63b14d171f7bd76519e24012ecace0e3876fbeaa7746e0004a0f75b1798112124a40c6e25e5900ea69f30386661b1c5f3baad5de4cfc7c6da389107f5457afc2ac0087c62894224ebfaa1e93c752609cf6f3cea8c2303e6b7ee1b47c7d1ed152497123cde04355003be92a2ec18abfda973b1a80633de96623940d3a2c60f67f050c5c69c7a6ca7d1065de5f47267fba2aef9557b61924fbb687e1121169db0e3b0bae4f32c95c6c25d6e037ac83539955e1d2e68684ee9d612c01882f8e2cb379cd71b20691fbf971335254bca96fe07032baebb086b1c390d09", .Okay}, + {.Sqr, "13aa13e719727e374d07e4ee21c8543159fc036ad05ead7b448038b5994df6149b45213540a5ddb6e7b0438fec44674c6deb3919fe3967cc73e3c32cd97b2b89e7c0a7974225237113de40d5b34c709a80ebe1ca960853e0cbf49e2f6f8938bc89d155c4c48e78f12fee2049210282499023e387971348a28612904b03fa3bdfb838a0bdcd3437987b7d58e6f0af5cea9f1babe306a3", "523fc14cd15a16af991901577e76f1e58d43e84ca5bbf8bbd0e452596130536a54b1548a574a22aed718dde53f39d019d962a5c6e23f37c18138aeeb2648b7008f3c94492dbe703eba27accbcda9ec49c90ac2d5ae395da1da4c64cbae90c564b142bcf7dc8845b452033d6b88a54b1684bd91decd23cc17f13cd67134855cbb052747597b9a41c939f4ea3458cf4074712fc58a97fe", "182aff2be40e931c4c5078f0a09bad83589ee081aa8556167b84ee9483d60bf4e34228423937543e7c93aa8cc1b25a12d8cf1edb6d5a883fcf2bc80d80e1c81c0d86a109fb2e3f780ad6d2883ee1cf6564638428bea0a06ccfa919ab83055f2912c2bdf9ee2b58204a755130ed95e5c303a26cd44138a6012dd505cd11aad35a80f5ece0b43618819c5b6747991b3d1b967a1c40235381c8ccc04b0f64ac2be23d0fd9c83c2db00d7bfcc38a74a0d5be9e33ed732230f5b3ef58b0902982568d01324950db214af065f169377d9f9fde9cf773e3132471c80e667decd167b20a4a3859905eb9b906efa9e6a7726ca0c3357c1daad5ff85ef1312b2a4d89e1969f042bbd616a2a96bb5b5d5e261a3ee97adddff84c8c0caded8aec2cf05cf12fcebd7d290186f494873e0bc9", .Okay}, + {.Sqr, "89f2459f06b35c522c3990a26a0584c6c7ac4f114f4f017933089b93bfff43c5b817f70d9fb9272fccede71fcc9db27d2551450c746d8e6597e314a5b180c6c9a1473726d34e28aa65b1e3fd195f9524bf068c611f1b5c4359a265380fcc56b9f3f53b921c49ed13cca02ad43b89e180499853fb107418630661e5689128c6e284951602aaf3090f33fc6923e0e366b683fbea8c76f2", "7745df055f63986b9c9fcf275192793f201aeef317bbdc1104dcc6c04776cdaa5c9f43a5d21c968d8a87afc29e09e007140b13a09f07d89399e52387936a92c07b59282aa40501bef1a6f403cc3b620d30d674c65f9ab55cce92f8d303e6944a9a9312b069f90704b5e3e1e9ddef62f3168c0475302fbf4e517d1d764675bf1882a1df1908591ae36f64baa4e393fa9229d91697ebf3", "4a5533cbe8c3c050816f198b564b46e41287c5cf5f118524c742f5b26eef0b1f64c2b743f47250ea1da1c73517234e1c5edfb85ca27662176c26cb84bc33414dfe1d0e10cd9f6e79dc553bae7d2de7752c9752213b0a71248fcd2bedaff492b840d172ce3b76271ea80d79173b730d1b906c12b8dc2e5030e3a2b18cd27f1952706e35e58fbb7ae7c5e35bef47ec198b6d3dc4c869183aa8fc3f5e565ae92ddaf508a52dbc5105363b9791e01790e9d7284240aa565b93649d228a95c0693d78db8792cf316df009c198f3b34c1c78da0c1fb3816ff3500a2caa5eca3e4ca5a16ec8ae7368805d775e87372fefc0414a2be8379b7163e3786c75891a2963a646f8585a3ffebb850265a3df654a5bc0633ef77530ccc7a4e5345757942570d2ef7c93a99f802a0110b7f3fcc4", .Okay}, + {.Sqr, "153bae001a1fe33895a38cad01b6ee0cc5a1f329c7673ad5e7e770f13988b76308fe67df00cf6857567e969ec811c4ec70f0e62f37999121cff719a7ff7ed9170a43050efca4b9ac8869cfae941a1ff12680158bfab8a46be9ed3999da280b13d471dd1e67499fc83d8d2f55aaa4aea80ed62b6860fbe56ccfdb2ee2f8eb2c2e5e74559f536cc6ccbe914580b045e3441815d77706c5", "724f36d990363f4e7e670f70db366867a4402d711933e766f9835f5877c254ec3f807a91e6e933a00d3da308e336f7bbb281b91dfa20d96ac8f9d173ddb17b77d087e929c13d65dd93cb51da05242c93a35598de3bcb7e2e8bfbccce5c1813e9f3dc48983a31fb46c79a8043e4ca6a70d078cf591f4e4bcaeef882e44d003cc26f41ac97879ba1b412d5f14df6a1b41e2e17c08370f3", "1c2d875ae99697d602d3801dd08d7c58ea8c0d4559201d6ff46389a3bcd97f38b251807aceafd53431adbdc150804162784f48e25efcb54c8efbfa1ac0631465013c104b3dc7e51efbdedda9c41c605d2b2663ea88a1625ff638797ac963c551fada70c1bb12ca345a82d3c038240473c3ce43c38f57e5e46bd124b9879ff5e131054c9562924d8cc765180644b3089ce4f83ffabffa2cfa04d0bcf9cc980ed727d6ce146094726218bdc79fcab41e527786096c4662904b2c027e20b9ca65a04f15f6bc1d47b4a69275b52180defcd9f8d8829c84574aada75c83014db98eee3834e4621a3891b12e236ae3f3a1633fa066f2bf6123b6211a4c15a60cb72337b30b644cb24849304b04bba011e3347864bb31908299109544cd19c126c90b450742db256cd31083153d399", .Okay}, + {.Sqr, "-2e539bd78cc8cddfbdd95e98c7be10170e954d769cc8997e5f5dba4b01afd69cbcf35b386167f9741766a1e4d7740a423ab7c492a8fba292bd194c8b5ee867a05078828b8efafc2b00e28cf90850fe3c631e7e8108d662c1ad34a76d78e21059410b45ae84948a5b5ac19c3b507b03353916867d20e3e8f896416cde5b3a2a979217e9b13cfd2be4f78cca6ec96646e70bd256fb0d78", "1ccc91e2d437193469a42b007002978c5ac49a922a8ab28102a1275290780d882bac63e4a30e33d20d221e99614e1817ddc86fd9f615afaaab120669782bd6f4fd29190d52dadcb47c119e88683580ad6cf352cae43904f8493297298355bb4a1ae6f5a62a79ab9a6c8d7d88f7a15c42daa3f1411e1219c870cd8ded0fd898f5faac393252e6c5dcd22c2bd1e68b0e9f7ac9c0efc13", "862274fe33c2e2ad75235576552363bb91a35edfd9c5db33401ee3f12051af29e9d10733fead1ac9b2501b2dbcebf7de103692379e305b78f455664d57a4680500bb1fdb0ff475359a30bb6e3399f82c6b04789ab8a80d0d19476e599b228bcb55d68ac79783dccba471e3453abdc061aab4206fd88e04e1724673c80d08114972c2808669dac15196e1b7c2af4d33884b0e9c0339fc22d3760f2643e2ca2dcdc61b769fbdc0b8828de7c42fd12dd9fffdcea74600c8a1f818580db1475d4e239d3a878f5c58b27da94d83e7df28c7992620804f5d567b3ca66628acfd11ed4e5d08803194288e24ced4f358b8460c5a5aaf0e336fd3c9bfbf958cd27a039cc86232dc8697ced2e514732fdefecf37da72ddf6dd9551bbee21c483762ac1f71dc0b305c53280c200a056840", .Okay}, + {.Sqr, "-8475f6f7af2e03f165d1e227d77cae7781318f9f7459545a3be692c9a6934463a12ab66792129c5f7dbf0d8f1deeec6780b708dcf8e69183e23859c142b268542d0775ee27c087824ed0cc433a9638a1f2480efde469acbde4ddf626a599891b69fa622638ebde2e051d3ed6bdf486fbc9488f018ad22a53ebde8ebe961a16ae0f4483d505e0019e5604d14242b381eb87943efcf9a5", "ccb1215c159d31fa707fa1f95d73a63c6cc84e1d1dc3d818d7635d7a44c818a1aa9d48cda6fdb9f975f2b38545c55b5323942d7ccba1141c21558c52c776e8b5796b68e215db27bdedc0d0d35212da0cb7fe80d545998b6a35cc83a0f7502654ad3eaf68098e1cdf32730666c95c24192ddca20aaf3b22801d5276c94802e785ddbe44c3d2afa828453c12b12371260efc80956714c8", "4489dd0b194e88707de7003d1c4f9d8bb043783d7cb226110e49b24d1829765629d3e7ac860e9cae8087ee51b6344ce07aed2ee50340426b52e26fb6e5342458496678f8dc69ae219de9877d287dfb2bda4115e2d7d0b7649530463b4e6c396ecad8db303f949a07751aedb3679bb01c84ccdd01da37719f34ee3889425bca5e1e72b9c8684c0f4a288241a9d41dde5a593ed691c7f792256fde339f43db718a1f27aedee8ab0959eef699f01df37831797fe584d98159e0d90f12899e2342bad48c00ac77a3fb4dacbdd7d8a91aed983a890c1e42b398989756cda783cb368a123ab15736d2cf99d2e671e1ec08b724cd68c92b5b4b680955349f78297d24a7bf662dc01b316aee2f280c5b5ebc405b18f19d5a2f1ae4c2c9098199bbcf745843067910523a2fb05c4a6459", .Okay}, + {.Sqr, "4a8beabad217ccc3322c783517ce0eb71e98ffec90265787ad345842a8ece9c5b38d861a01a44400d7f35b7a731a74e349b2c2060e123008eafad47c9802b72e5841beebb83c5aa43c89b28d9ca77b7d57830aac90fdcaf78c891b3e638f8e75d71f72c12a7417b496c88c3038588cd60b243ea6796ebd2fac0301954f748f082a0986c35517e54970d6a49fef75ead880368412b54a", "ac3c6fa52d122a468d1b4edd7d57f63bc649356090b3901b3c003c94095e1483a1a7dc79770a6d76095fc18300e476c6b4d190057831284e341e56939eb09fc28d41fbe5268a64f064703ac7be38f0c75189258de1f7bad0506fd1d39c3ef3175da3474a5dbe53969e1bd292bcb15b122f985adc67411e9fabb9d855d509943ead7b47bf0677b7a9d6a21d11476b88d9727c376719ba", "15b5302cbf8ff8a2ae4fa34e1cf65cf230a150cedee254883d6603dbdfe0a811d8e5f37ca355ead81ae6ef0bfa3a6b7178187017a82c7bd571e8215fb438a2338057038a642cde404905ac35900fb62cf3f48813cfe49c7ce5ed588096c4e4aa4590f11dd04b5bd9732d4f12a8a6de4b64d1d666dba32505ca28739f36f7318f10310737ef44505477664ed4733ffbd1b79a2991d5196df452ba979dc6877d4ffdebe60c42f24900d1edbb16df3d17ba57d11b2616968ae7b1337f688146df70aa63245798cb4b9c308f4ffc7738cebaff545f79be101bc4ed7260730fe038b95992add2af395ccc9ecf5cf51a6748dbcf5c70f6315d7734b0fd59feb0aef488865c8145c3aa459889e360db536d0122e92850c2e8f92934f15f1108d3c75d27ef2d844fe631c78a4ec9b964", .Okay}, + {.Sqr, "fad6d34127152788957d59aed4ae5c6608d0251c0ec73eb182da5f79d9f17131d6ffc688381cb0133b797f00aa5cba08edf26d6436f1ccb64636f205b4874ba0b583b1c73a8e3cba3d456d9df577feb38b6589207951e9015f406f9296270f6a421663bd30bde257f425e8dba8a10533bc3dee6bb8314ad5145a441f1467e3e5c2cb3502818548df0e29969f12d00ff9ed4477d23bc8", "67348bec215e512977d86605cb0c4b0aef91ba9d555d5fa084b79c8ebb7ce66adcb70d8aca354eb3d2b866e1ac40baafaf67fec64a6e75ed113068eb6236a3016e821c943e085dfd649913af439bc492948d3b384047a6787dd58ca71d0fdd17806ab658f3f25747076933a68e271dbcee9364feeabce05c17e5364c7f38fcd46196f6defa85c3933a6092dd1fb5eb66a5103b0f98ae", "f5c848e11f971f969a336e4f133d7ba889f21de7ff34c5d4ee4d8a9b277686a9a786acfac0e2f6b38121fe23dca1142491a14fe29a5686ad7f6f72ab03bced951b6442fc697e3f4d1e1ac99bcddddd5824b77db6ed5e5ed164c947a5d7a966c952849d9c0a36ed591f42112b56780a29faf2963da6e5358d4ad59664c01af54dde29baaf48433fd316a1ca50e1648251a7d843f396524af8a1d270085943cab42b1e6fdf8ec6bc16a9990d359b2702205d17fbc23d4b9e1e30939ee4b4630569932f90a06c701ef65b2d120490978ce7ec89d8d0680a975467b929662be2aaeba2b767089499a8dd8d31ddbce23ae831826798cc4ab99dd5f6c1012087cc8475a091cb5aeb71a7b1f7f54cb5998faed25ffe0ea7a46e654aa710d2981a46a92e599cd724dd85327a1215cc40", .Okay}, + {.Sqr, "d057fdd180074c110e967de5b56394405005babae0f4f5c69a1106e798729c4303349268eb541e4f0f70589450258974407dace97769666a1547582b1e700332e4f40ffb81e545e57300cff48ce8ae55d567327ea9f27de45bc261d808a13cf573d40878be641903ef97d3a3e6b2555eb76346e92387b31758c03fd16249c3750ce5004129b10931e4c1df815fb5136d792814436025", "d00afe1b5906cff0fd73364657e073b12d128a5334debab7a0893fe8c9c35dfdac423b5aa23ab66afb46588bbb34e2240e5c32a390922fa730d257221db849a0201a8e45a0372eceef2e296510d99ec01bc0a3a59859eb72606beba2f15462c4e4c372c1077936ccbc343ca6758f0569c69519c6212e83c58e1d679ae756ac86597d4ac0d158ab667dd24398d907ce04c89136ca9f91", "a98f1ab2f018a3122397add46d94201d28e44ca71ebeccec6b7da9de94f0501df0820d10f553d072299b40bf81d499e069405dd613b84fbd682864c861f83ca298895fe4775ec0b2f4e3b0e3f73e00b92dae819204f45e37608a028ec141f956d5f25e739dc5ec546bcc7552a65cacd5c1a44e6335fabe88b04b2354e47d33674e7386ec486e25e16705d059d1d37333592cc6334af3cf4a3a3fe5490089e136af66e8202fc06e14c319a487cc0207d74b8489cbc234d7711dc511654cc3a96c740bd457ce8deed5d6378128ee4aaf5111d919cbfb702d8d0b3204cb5f459a9e1f04806059e2325af037dd434ef81b5a4abeca785c5a470c10faeb7e164fffcf5dbeac2471698c0af5232cbb6102e4cf45059e2adb48c680fa839025a0e72db45c659565650d9e513f79c559", .Okay}, + {.Sqr, "-be26b97cf43cd97e97fd9a7700d025fd9aa50b1899dc6a771d87d4ddbfe4cb198dba993a671a445e3d22e759cc4c0a50a1ae6396fd3a6bc25bc3b3cf8524fd55aa6121503b50363264dc8fc2df0167157c319cd13929e945fb39fe12a5438a3b6719f7f9b4d1640be7c677e3e920e945b917347d9f557bdc7db8fb8e4ac430eb61d4fc32ba2ed60df71ab85471ba9744070c02558dec", "21e1c8af3169f49716104b02ef116ff386f802b3855a46b14079122e80d5938aa16d4364cc763f39f7990032f33395d765c82c1a75370dd01b044644d9c10cc41e495d99acac4cb167c29c23620fe19808dbbb98f2c2c0cdf4529d7a7b50561a918faa4dcb0b35d30ed52ab688fa01cf4373936bd17d1e811c0a904587949475fbb2ab58758bea5ac549084d6917615c784ab1ed8ddc", "8d3d81311208aae5f18147f24551623e82785a9e23f6268a9da012146e2d71b497954158d0ab3938898008e0cab7e4ae71faafadc61b252db9615125bd790fbe6fe7896f5bc9cf1bb4f4a5c119e7d8e89b48350e809ec1778fa8ad1a8d92fdfbdd582b4eb11d920e8b7f5b17d76ae59bc8d24226ee86f786c91c9628b4d77f83ff02474f3f905068895dd1137900ddca9547985625cafa404404e520694a169ec24d8667fa4a2b854083687b9033a206926603eb063dc9b6c218f685e9063d2644a1acec6d77af8a946c6f232bbf04e82318548747a79ff250ba44d631bad0b00c6de2174e734fc6f86e5c159a55da6adbf2dee58706570be3d2207df8d3d740fedcc7b9f7fe30fd397f83530b18cba5378265d7c9b0fd3d121f2208a4e6e9ff37d06680b32da8ef3d65d190", .Okay}, + {.Sqr, "3125e21fbc629b2a5ac2ce8ac9ce1e1a9260df459e331e3a19f770d1cb55df77a16f499ad8fa077eda9a5efdc98fb4bef952cbda60e5fe295801a5ef59d94d54cdf46a9646a4477d41bb9782ef85b63fecc90eda00cd0737d2bc942d44cee7311a2c1645e19cbd902e353f64896558231d3f213a17dfbda577474b648dcd9ad56c093b866f0560269dd1b67155f2be82e5e5ace6580", "70c42cc64f080907c4aae44bbe2cb518dc6df6a5590559ebce55a91e6888a04c0853ae75eeef825a14de5915f1e9eeaf98b70ed49fabfe9b288d3a6a49922ba41d3c46b8add0806added34d7c0c5db4fbad318bd8cd28feac3e6154396556b12f1c5fea8dc8d2102ba5641af1c12259790f2d2860436094395b901bee90cf69e1c202827fddb14f3e1b1a44c79227e498866829547aa", "96f862b4b064074557625c425023c7375a83bc2d8ab24304d3e67d7a44961d0d5101871fea229236ce4049c6c77fb125d3e3c3a2ea0aca277f0ffd28635853689cf9ade7485d4fd3851cabebde8ce8ac4d5261e7dc50aff3e916b8e902368aa14cd5fa27973e79869fb764673912c156f273aeba4e780a96b68c25102eb13c537dc4b140a6bb5aef34240af56bad7ab387375c091c899fcca88b9b0a575501aa04c7d0e42812a6f2a4a1a9f678df092542aff084f0774ade3a395160d9025109c64a5d32c78677945f9762242bc18f05415a4db6c8ba463d871899c61333d8ed746cac8a789cf1cdd2b0068908bf74a45e0c852b6957f725a2f4c0ba46d813758b4c95e8853cd60ecba0df4c6f7aae7ec8570966e81ac4ee6ec049a289193b4c24c99f4424fc5823e4000", .Okay}, + {.Sqr, "9d39701f85702ad218194a9f1558680d18b50f8d92d2ee96a3720820864dbce56cbec6f03dce47ae9188550318de77229738b136b9a9e8e9b82da420a62af7367e91614746a4d2e64b49955d108478fafa877bdc0783ed910870bdf0d79e457425bee09f59441e1f8da5e8f11b864305bbf3846680e8fb824e7ad57395e56c42f22b1edd196fe2221125f72c5fe8c6bd0f3ad1f2b9f1", "199c648a413a88d09184edf215efc0c36409338ec8aacf02eb9c5c087c3f79c36eab04ac2918f62619aeaa5d0cecd54f47e03fadfc38d9da94e986ccf267c0d92ff53316230f2731cc66a3ef879324e408a0da0e6a5ede45f6b46458f6744499d26b60396e6d282d7fb5663b4ad6de47e0b4b7ec29cd2c54efe8907a8f2b54dce0a62585572b1aefa308f45c8926aee2d7f7fd2527ae", "608f8069c8d0991c7f4db2661e7a30315c37a87527bb9b7d34f113990e5cad264444959f4487f8bf795aa516185172a1d8bb054184ff691e70bda1f66512e6f2e940609959c68f3f5e8308ef3f29c06563752d48be94533930f704fcb9d1438039cc9aa5bf3bf27ffe6da8bcc47adc4986feaa73339d1e61c5b164ff8fa0f94b0d7f9b2e889628ec4abe4e247aa17cbdc2210a104986c8cc960b8a3b2e81e914f786891d55d7b7677183d7995f1176650e47bab0e1e97853639503a7bb8fb40dfd1a7c5b40434b8c4fd7d1f35cc21067c399a965c7ad93ab7003ef6ee6ace6b1954b342ad53ae2edcf666ebb60e7b5076bc81ff1e6a701222394a2a2aadff2f78ebeb212e0ebbb4b306b2eb879ac4232b258ba27bffc1331bf589831b47c9186214f4cf599ceb8f394b234e1", .Okay}, + {.Sqr, "-f5addc66899d1420bbb5e46f394c21410e3a00a0fba1e53969c2c2273a98929d1edf41dcfb0cd774a0dea6a27f9f492e785415a4e4e21416ee8e263b336fa8ebc973affe67edf6dec53898fb7349c99ee429300856c2733809b4d757061e720083817350d8c2d9420595768a78c4234bbb2397ba59255a95cf53794321915990715229fb7500bd93a55cdd2a162b5b668acd1aa2bd2a", "3ac538f3b968d3b50b03d0bd3a9afb145beb2f39cbb89b9d6a57d3cd11ee6e3b03861bfb8bde48c262435dcab19fd4180d3925277d341e3e7e475e59d3389f69a4077e136ef3ddd9439339420fb1a34e623b3197a07934b402d57c8e0f116e81e67af6f9984b7ba8ebdea9844ace18ba2ed3ff728e6f41a5b988c6be087672d84e39a22b2ff609632a08d06002e6e93cc1a8c3da72ac", "ebc63defe3bd0c6bc945a7b6923468c517880c95f497b9429540dbffc9f192eeab52a05c5de3104a3c534d56b2d1014dbaf6eb948f231a2338d0b2a62101ce84d4f21291c4cf2348445c0db4f062573aae4fa60ca3465e9dcf227ee9743a964ce7a0291b95531b54ab1f92d34cc1732e83203034628f18afc21897495138ff5de012c51361911e3cf1816f5c83c326cf935152508c312817a5dd7fb55ea81bda5cfa9538ca501ad18e4c0cdc9055fc9de8a83b62f82576a748969d83a44f5eb20c66a82ceaabcdaba7e0036d16b2a3b8bc2e34822c6f8c2b5479594117680a3df367f41e59fbf9e671febd2eeff671e5cb2b119b3c822ee1a8e2ae046e6858bd69acc4acb6705c676b00c980242879e4f72ee807cabffddb6ab9f24f4f45c36c38997551b8d1b3247cef0ae4", .Okay}, + {.Sqr, "b1d233bfe62f294f40fb000ba5847814b92b87e0c959d7eba46413f2308a69cb5bb95bba94253ba560a5d5dfbcabe2b0195ebd15be0c73fbd039839cd2c756278b7e26fcec7a3b44ed90f00946b8341b7b238afe72f74b502cfaf29e421eea8cf4c0bad0d321ad138e33ec7f6c1b2017254d1bb66e78ef31186dc98274369464dda4f6d45df60aecce335a5fc1280fc35c19096f2c7d", "94cae9819b86b76211944bee7381cbedb684dab1e508c32353ff7b812c38b6aeeb5f08d7cbe829346cbbe99b6cf7a94a302ec71c2530389591b0026b4c5789dcb3935ef0ee88c25868c8ee8857b42cf80268a8ce9794862a1c589f6d407d1c021cbf8d8a26ef600c82a893596cd47241babbf9bdc4762211b3a7e2e11bcfbcf22d2bc2501a500599c12abbc1dd3c1657a9ef8a8d2b99", "7b8458284d98e20f71afb0edc112cc4df0ae74c03e78aa33da5ea18413e02b9110f4700608b891c1cc0f34a2798a491e4119ad1a427072f7868e112713e2b3344a4bed168029b76523cff9424333d505b0fa211aa54641fdc853a7b8f55bfd37787055ae69a618e6c05537892f690d9e8c7850bca48eae5cc0e97c2f144084b0e58b3070d69e599415bcdd24a11207020142f2ce41f10b37a9b60a0cb2fed04f90136d1462d77c71120939078f267787e5db3268afe8ebb1bfe524702c3ffa31ea550e2988c8e4c7615b5eb170d5f0312b4a0f67601385900a21ef30935bbfa10783c466c235540a6328d0b02a10844a62a08e83eb0c4f83ec256b90c4d952a2d4beea94a09e787800f0190376d48b519ccde1cab6e4871c5e87e1a1ec771385daf9c8df2c7789d266213509", .Okay}, + {.Sqr, "aa21f6e2b11814fd043a649843f09d31094cef0eb3bd6856be8c4febb8ff6cf53240714619bb1a26f57180bb04e752038c09cc809a8e6c77087bf33f1fa658f1fa23175d713ad06884aa62df0e7c159e90ba9ef1987c260bef59dc0cfc394c6b083564d9ce906ae8998c9af543615053d925de40215b324caee76fd1df6dd599d5087ae67cf07b42c27ad366ea32dbc840e782d968f2", "304e1f17fb54ef791833cb9bc97d15bed83b96b303c702f7f810472a0e6feb3530f288fb7747e1e1ff966b703001f53d5adc426fd64d741bb04200a2b2da4c1ba9c67efb3537990697ec214c6eec09a318c47b73baf680ef41b3a4fff7381546a9b78212461d42379807f0da1d719f4beed3eeb510f3824aa8dd6e37e98c8559b9995968d2c0cf1add5068118db36fb6465a19a2d16c", "71112066a7be192ce43646cdaaed60ffefa2524f18a257c2862e42e2dbfa3b81088973ab6e347d197cbe4d15a0d4011730033fb9d666d3f737865e5bc2d395e04cccb3339616697369e4afa46edc6341b415c606cbcdc35ef41e43df50b9fdd7b4be34e5dd822174f0c75c7d74e06326e344038c4c8d6895e9fb5970c047ad082e41669addfad64d965290ca57f29c8e99791a369c7a80a7001494196c48e7fab8779441f8055c7d94def8106ec9f665b84b8d89b3d446a6dcc81279fc8eb9dcb6d4f7ac9f526b6c7bdfeaa3cc18e373aeee058172b4b0104d11171c80ddc34ba755281ecb42377484e90ef8901a1ed51f7a5a0b04ea8b40fb5ff3701e75e254c6a6bb3e350c5e0085157a1ce3972da77908f0374398714b69949a22eace483cb1b0669421d5ebf4dd4984c4", .Okay}, + {.Sqr, "-527f1c69118395e1657683d0d91c73c8df514813e39d014a31a18bb3882e26077513209dc69fac0f03a445804df34a6e120874045dac739f4b5ad5a79acf3a2deb454b8b1c46b8056ba346f11f8d6fadbd3e4d90d5ec548274b56c9a5b3478a6d073c80eb1319b655775877478fcbde8f6b6278ca99d801c243ebc316814a23b7db25c30440d78f6d8d3bf0e8a59a2bc5be902114133", "7cc9f0a44df5197a3f7e26fee342c8240aa3095f74289a4320c73875bffa03bd64b0f855f6c1561014413945d472cc49319aa05cb776d116f9c90bc581121ec715529542c662828d73abf10c446d3fe7658a0c113b2507becb4ffcf8cf656eb685476c87e2cf9a16af27a31fd2ae815c12a9f197e9b42b74b6cf54e435ee485e00413cc03c3677e86467723e420129a3af3a3c78e181", "1a95ad50829ed387428f96aa68433093ff9817abbdbe9ab1541aa88001255e8aebcbb5fd35e7645ba259674e577acecba76662502c64386dd256ff2f47f098b59026364c8dedbf584134a34e42224c26cf7abfd54af4101fecc8b7d568eb0615022df8c54cde2febfffcffe52c428dbfd071f38491adf287ed1077d314912498218466cf8fcbe6c0530f7ba802a45df3cd37523cf294b7ec7641e361737804eee7ecf8130a2f8d14136a925ebf4c66e5117cb4fb368fef87d568199576551872ad22a5b98abec116bdfd87d715b828e6a4bb91793caee8bbd0e33acc94b14c415a64538c9462b62d056db4d6a2ea307c7d118406361f2d2480a676244532dc86e577ebe948efe83fd9ad2e8640f207111a2cadefd2da22d4dc4433a3048f90674bb6acdf56af37048560f029", .Okay}, + {.Sqr, "-9f72aa5b235fe3b66610c7f4ab9b55ce5e02bb3dbb43d4fded9b08090a82569cf38df0e72d37b85e3b01af8b71046fcf0526a9e8d5c0acafd95fe02d59fd341106cea2de5ca7e3b8dd4c8da6b09eb75fbec958a30953ed539b3c73fc0a0f34666a64c85d3190e8c154159b96986df5261ba91c97b8b3aac94a1a37ae76594fe760010f4f27435e2e87c091f77d3f0e6ac4f223c65448", "d1904575b2cd3671096a4e32d711c0ed34d4a8c90ed65fbdac3059254a3f257db128dad783cd825c378df88d8f51170d92163de7593a03d3969440006ea5a26ed73a5ff4c0468154b4844a31f1a93a25fb39b5c742da68da5d66dc94bba2b4564588e5fd38c95a87bc00909c2f4657a1ce49d11765ee8428def7b8ac7093a2ddbc894824faa287f9572de33caea2816741c361a8b8a7", "634fa2f96079c9b0e6b93ebd886838e36ca5a40213a42f64f4a154980d1b7101c1ffebc9376ba31cd844d7cf68a9de75c143edf084771e44b74314b8e6627c068acd32c70193eb86b2570f76e44995834c88182a8f9260e958133e66d4414cece85cf2a5cc4d9ea1041f737475309400468fdcc76f82935fa68c5e4cf817594827dc5dbb4029ae8e2f4a1115d03010124249a47bc72c9f0751c8c6c296693c395c568d3a6e7804bda5f5359618210d2df972df84ac8e50e690e137b26d07c689c438fae5d02e3ccbf62d21bda9ab41050edb9843992825fcfd036d234572f55279ed4143c1ac2fd778c2d009739e0a3303d2dff86246ebc06e066ef743168198d0bc48fe966e749570a076ccc949f82d43c824d330091a6ccc60c48ab5bb505fa8cec8b504a56cd22b1f5440", .Okay}, + {.Sqr, "-b5ab3b548e43c95b4de0879e0b4280ecf4b1a5847dbe69c8f557022c3f82efeecf2fbce5f80db0c2bf6d01d0cc3054d4883ddcd77671733f2d995c337c0b7a464c22cba4d0949f2552bdb44c5b2d39c7ea3354be987b16d4afec1d8077305f45aa22b98488e129812fe3ce85313c0472903d1d04e9b80ec85291c70321655b45df18d5d7f73a86c8e847b9fa3868cad3fbfc07a27ef9", "804c6bb5dd5569effbe79d9ae4bef8944ead4c47213b9677836d971254296d635ac73b477f62e997d8ad87d71608f488d41233af7e753b5ab604febf462ba867d7124ecdf330da8ebcef6d99c821d6ea535a30d1f947434665127ea049cc006a4a1f6083a134b1bf260ec514929779c1c8350ecc4aa8db983f91f7945d60b79eeeddb3377674e16540f3c6b52e416b232f9005e245ab", "80eb946de1e1fecb067508df917b48e4b523080e6a199f92869a8c53275d6f78095b8d7cc1e9dac5eb9a6f193625a61f5fb88939ccb84c993327229a246a47a1f2964bf43c010e91108f207a5462fd493e03119cac78648a454ef3c3cc2d0282bf325246716ed536a75609e5724bd10894754ee689c23a021ed6827fc2e695fca03a80e2963989c39787a76b3480a2a97997d9fd74a24f7a56644f251b472adfcbd62e84025829769ce7ed7c264bce5a27a4310dfd6f0be8e13be8f5bcf6a4dcab37e53fce6516229983f840ec6bcd5cec36befe3466373c4e49f4a31f51afc6e06013983d56cdea1a623cfd9b41772250ecba422c7762e510f056a18191c2ad4608591d5707e111990d9bbb128e86ed7820325dac7706baa13d312669cbbc5241714fa5ef968a4e901e0e31", .Okay}, + {.Sqr, "-98f52a729e32cdf228f14e76467a8dbf4292e4ef1ed27e03e81bafe4841f22652650f00c5b7ab9d6c111438167229e2f4f1f8a6442770fac3a59c96acd5037efb439d81eb663ebf37141ff47251b2f58aba59f109eec0994a26ac4df878d64024611b3478cdd4800d8c46376d3bdb89b5207dc9a5311b3ad51c93e05f67deefafde754f44683e648fbf3552a2bb68500e1bde9eaa1da", "a3aee67b4d10278cdf5e3a9ca8b7021891b2bac2c52440caf9b5052d588b7b1db5fd098b814d79756decea9accde63c127d50d84b8a05ae618bf483a267203b3c7e1e8d2e894f52c42ad372e1f0fd1849195ec8deb68ea91c11dc668afb3aa3bd86e17b75073832632406bb572b2f3c1a88cbbcf897976e807288504ce8ec76ba3e1e4bdf7c5d127f4c12a2026ad9e48e6809498e1b9", "5b640d326248f107b4b68c74498cb51df66dbc84689c3a72756c0bebee7172b826b5a5ab8913af196c6017aac2a16ccd249190063a536ea9e49faab451122d6cb2748c19462e5da44da71f2cc92c50176ab349c1808a04756a2a261fd19a7b2d78c4b097b8350cd99ebab5d6cbf97ccecd29f1271c44b5e353a0f8f80c4dfb4ea24311a750bed3e5e0d4c670574703c280943d6fd075cddaa283f1ffd09af82c1ca14292f082858fe47d11007a9ecedbebecddd88fc98b4173f8dce49d8fc9238d71dd25f9e1110e269674d965e56603a91760b64fb365e16acf1a241f972cc8b01341635a9d4298c4a64ca0a314fa3f75f21c1ddcc9517aa1ce3c692b6e625fd9a62e088c8f98ac807a8f60f89b92de5680591af6c8149b575e1028cd48018167a28c362eb1218f1cdbeda4", .Okay}, + {.Sqr, "-6ed195d98a72940c331ecbcaf5452992d81578b743167606aabe85d7009f14f32d4934b521ee4ef8b49958a06dc2d9c3db1e8fa38f32b82d43f9bf0a10158df2ae69c1c12c228e496c421bf6aeb9c8ef1012084cb2879f23b4a02ab2f5f67c4a59564faeecd642c46a39e1cbf8c893be287d01221ad9e9f40e8ce73ca711b2f6854c2e80017008a6291107695185124fd7e155c7f212", "260f219b612a13b884033f406640f5bb3307bb4c40ce1fda926efff3d9666efd60add7d9cf2c6d796d97e64411593725118a2093b09af040a194235b749130204b229f200af565300465e74de68949644e0a48e942fe3ab3b7263e04c705f98829cfebe665058510b4887f7f04cea837dff724c89c31b530616e03b62b6d95269732e4f285cf362759a7229f5653b86196f798cde836", "2ff8c85cf7e57a55994eda81073481132708c3397da2a86e6cceb3fdfd80eafa71cd344992853ac5e917b782716b2a4fad683d8d1fe200024ef4f22aa652556b979dd2035c2939063f280c5172bae35a66f9e115691f5ac648e90a7b80927e1273a3070be16223017bf4fb5cd35bd7897e9a8b63c67db809ac83b4bee9b731256f8966a26862a3a5361ba3443d6c3cd5fe33222669cce8e41642b3d6c38ef7984079fc4b0653cd4f5dbeeb943cf7d8e638c100c56fb9e9e08a84ed4bff74562847be64364876b41860e53d683e94d718b2cd247872f07184d168f107249d88bee56de543db6b2ca9e8cf48d1ddfb223fc800e0579ef545633cce80e1569a7b250aaa8bbefec281a1cad69e55f85179cd4c78e3683695d7d4784f69a677db7353dae43e93adec228e30e20944", .Okay}, + {.Sqr, "-c9d3c7d5370475596e2f572f2b97a95e2a3abc9227849e637daa855430bae4a1ba2e531e9c01ce70c60a00f1a11dbb97453020df7ec88321c7f5b17a8a90d02e138531435ab507c069193cbf0c902db00d8cd9716a0d4655578c95127da155da43e17ab44089aa88dca17f18c6801483c502c233570ee1ca57b810e4ebbda7795453055f2a3ba5f89e84a2367b922d7398138af158fa", "5fd572d34b1a2796ca9f55ac11851e01d6a8f3312c1c3df761ec2de2fd2be224c0026430460936d77236df77b7b214e80f9716653d6e878fc6052026d0e3310547cd2465c5e1deec0e478b15a1e6567e9350b8134dc071b3f77016f0573598e3acaa54f82c81d0d56c066fbbef984a61b9508a4fb367328fb0c06e5ddbd4399b034d80f4d38888556cfc07da7464ada520d7ce6e2690", "9f1e3effd5dadebd682133910c771521737711204db83e7a3e1e92fbc120e7fe890f7247f5f4bc0c81b13204409d0e6213c243222b5bccb56c5c83446baa40048b17eadec723771f53f7ff65695d3094b6e99546857d709e7f86fe06f61213ce26d4779276c0832e47d41069b1416d3a4e8e43d2f7c5448c5e01f2921d92ff1b2abeaad7ebf09051bfecb326d846709b52fe9d26db4fda8a365f71150e942529b74d16d62f1d276af8c831306bfd42fd8a49abca2357744ed46e71f04361fa43f1e2244be3fda7b7f633af670f67561219bbdf57ed7119397b9d8d965c2697d575eecf8c87cf96fadc1c33fea433ffa63334c4069fe1d5c63ffa0a1b4751b8d338686d8ecef71ae02672139b1ae74a0f23b3b50e0fa4c225ceb99395b33e81b533009dc259812c922da0d424", .Okay}, + {.Sqr, "b4c40cd3ccd0da3570ca7c83cf695c437e8a7eb0f7f1bf4be4d69565bd125eae0e3addef57ea4149c3a4a73e57e7df7bdd340494739121fb388e736fa835b06ca2a4b24437f083793b1a6f3c3ff606cd7d8b4d204adb4a6dcedab6300d295f3f5183f8cdc9ff5e919cb6bdc2c1af687386d4dabf646efc15c670af22f8743039329b1a17ab063185c50a7b931a2525af86cff28ce1b7", "cc06faaeacb8bd1fed8caf3558d02ea33b8f2927e4c16d0104ad1838ca4f91395b092bf74149f844424498fbff39c1dfde91672747de601f45d11bf992652e69a583159ec23cad8e05c927cf5aeea0e5865a490de7580cdf6e574e61eade9107e8fd41551e24098154ad0c6ec897ae447e84a09097d95bc02408a3f7eb2bf5d0407bed4b391052b650522dc44e33d6c52df6013f6e0", "7fa4482d7cfbdd18210bb1fb6b906e8b23fbc08b54020861e0ccec27cd4dc01da89f4a3f529c3545ba45149a96bc3af421827936ae03a548e50d5229e5d41a896ee20935a3800801180afb7f177a80672fd27882c4a6ce840c51e0e18520ff122ffa85ca0609853ed2d29d51834d4c12e6d2de1463600a5d260da96544e53791cafde33b5a0920a15c785a5a19edc30c1fa1258ed84bdf5d69a3677033be67f991dd6781b7d5dd3e1f30c692dc116f970c1717e093655e9b621fe10d613294ab4ad4d20242f858536e50c70298c43d1b5f27e2f6cb248ac9f1a8b1019f411d4292405d2fbd514ce2ef2032a9a0d96853f75c8c5905ee62950c813e753ee473b45a618aa3b13b0feb0efd9e2b18a7459c0863904447a16316d0b11b16941aa1af80251b9720214237a32b30d1", .Okay}, + {.Sqr, "18e856af2ca92bae0d927d072a2f72fe89a46cb6394e51ef52c7de632d9943f780400563b20d1f2110f68e0763e01ef69930a1ae176a2457a101754c0442e53fbaa29cc30224fc54bc4e0c825a3aca51f8e07f78822fc94c068749f20c54a772adc65b09f66befdbd4b5a763b3f1f963f35e3e6472915d6d28f774ce001920dfa6cd0f1b4332f0a0193f699d0451ba4cd5fb65cc5f89", "83fe1febdd424563bf6c5fa7fd12d15e58f2f5a61b0bef76e7694e01f0c96e22f22938c4918eef72babca92a16d53550e6e79ec9abc53227573b4720b3a7be5ff429dfa35e891db39d793d5e64dd1555c403f474cc91c9299266d3b48ac30bf015852708195fc54f0d334369ab400d6bbf58dc885c5f251cd5ce2fc7c3c3f7106767bd147c7bae5ae00fcab0cf3a84225f366f6909c6", "26c631e133ad4af8e7150d7771950fce91b1f7e0ce6a0dd8de812c358853d8b41614231238a383c26576a83913d5de1085fce49082daa238d5de53de3200a71b5a218e0175de3be51e8ee2802f53d0f65fee2a957e25c4f0438c4d8479b32b99b2800b38dadaf47ac0a433fa1b95f666593db9b347a757c2edf0567b19fea8fa136255d8c0132ca0a71d40a148a059e74dd93553b02bdbe171efacd41a42448f043949753b3ad32c125c9460adfccd59179c01872da3d059d310bc0f807eacceadbc1957ccfcd7c65d22b6dd37dad551a55d7f5205447be1b19a49d605c9943ecbb1dd7962f80e002157b67a3a43b643135ccf299e5f053fde7f7f29fe4744443f05ac4f3afbf7c6c765917f676fff5dad87ac6d20a7cedd69c176ad33f4cbf6e687724ab9037307ffef751", .Okay}, + {.Sqr, "e5cf1f4e68db5eda999327aec184341bc4f2beb5c5393efcf063a04a1151f2bc01095643c75dcbb9640bfb27f6b326085d2ae6ac2bda46a3accb5006bcc70b3683702b12f2e17406cfe6e22f3fd1950fd80f506c0090a3c90ecd7a97e98e57fb55778b76a0d7a78ceb61e9d1e16d9da9246038580d522cd6ef3bf76e8fc3ff6c000d3de88fe082046caa847ce4efc6047477cfc643f7", "527cc5cd0d4264a30d9eb4c80d70cf99af98f3538c6ce0c2ae38e4287226b5c706d34775a2c8141d9366ea9c5ae3b56929e0c50610cb6e6089e83a13d8868134d866a12522cad3f38e8c809af5ac4659b1aa24700d7cc5ba385783788754f8f6d4b91d1879e32e4bd06c315ae1a75468e8f46f19efd963026ae13d637b138faca75a4c1ee4f2efcd231d48d20026ff7ea84c9f9923e8", "ce4c3595ec3a1fdfaddf586d160b8fd7c290ecac4a07ea5f0f291d1b30eb774304a9a84fcbef5aeca455ecb0e5e2a4029a3790c52526161a6bb403f9beba3bc86578dc9332b4037b234b5d97fca65a3277041eca3640d7934f60c63200a43de68ef1ef6fd81966e72bcb6c403d1d41182e16468ef6d423606ab584672062dc77be4bb7ac1df4b8270087d4d82fa8af1591df437608bd3009f78f429340c0b322d2ec6387d84871dfbf6057f233c348280b82bbcd29d26dade9551ba88a17f9409e820b6c44331555f816e5c8b4f9266d8c999acdf1c703cd67fac8da83d3680929863fc9e2e9ebadc544082a411a154b1861c8aea5183eb6317574f88a4b3a5c4c6a734afb3d52a30130f20faee8f8817f02735480d7c399ecc0e99fdfaa3040daacdae4b4454318a61f3851", .Okay}, + {.Sqr, "-732af687b9898705ec86c87c2b7c5b59c5effda4fe038b679d696981c1edf713247fd6077449edaa1096a277e79a1e7421078baea475d05de89af64f1a39b2747c126bae9378e0e0cea078dcc195fa6cc0b1d190028b9d64555669b7bb6b391cca97f45b3603ff085d54597795755776901a0a528579b7d0fe2b717d7d7aa8ffec95a7270d76f0c30bc19a83f8f96b37e35e7d558de9", "1344f224f93b1d5a7a5f364b3f21ddd3510c021912ab97fc342f4eef35d3f766f72e712ce321f081b647cff2128eb6099fe68dd968a16fc05f4bc39deae08e8bcb3aaeb9a787d6f36a2a185d44a1127e1ece63ef87459be9e42da5f596ee6430866e55478a9e8ec2ab30873eaf0729b147955d06430df325f2a80eea41c08a9e0d3b1ecf964bc1997a0eb413e70d9aaad1c88a09a2bf", "33cfa0b3c2a390f925768e3432af4b08c9034c2d457d2b1ff536eb0db044f06184d2f01f2dbccf06a72703a05989aa103d515d8b26d98e9e41f6dcd80474693ce8cc6d95404c5f50483a6eaa3de44b11ba26b89dd970d71997b00ba5f186fa7db7da7b2f6b7e803664ff83300680ba54cfae4bacf9fb7783131188ca807003ff5003217358f2c715d612e6d63f9b716d230b8fd447330dee05dcdbdc7d7df9916673bafdeedb722ccb3ba200f1781d8d4c2b5711443e3aa4a634c335030bda685d29c3d97ae2812fb6e4d95e7be97170fee0b39ff7646db84a9c5b0718a874cabb781cd0130896772bde2de325481507788c51b79cb91cfb9c3a3b39988ab607c6ab67cb9d74033125b9d8c9337fa33528b527ebe0ffd09c516ff5f3cfce58879d2793cbc1fa164915647e11", .Okay}, + {.Sqr, "c217672091c9cfb60d1f24f528e6f8c0a336e38e5ca7a1e98a7a875998b49453692ccf058ba7e3e173f97e8ddbea1308549b6c23b8b1f12e6345957294b377b68dfa2c1acd99969a67163f6917a80e8481f9fc45ba99ccfa28a33700e49e74927f37392d03d9d4ed9446ad697cecb9240f85b075a68c104b1d6f6e1cc15c74c0cde6e55fdd44144f402e6a88d6bbc9c4959a98fed74b", "e8a2cb2776275b771391f75afcb13a89026a00eb7f669e21113e2185f742b11c9dc627ee5034019ccf36be1ea7f7c239c196a8a05af82bbb11be34e1eb271ff1e939d0077309e1d2da8e30ead035794678985d650ac51132072dbd7bb3594c755a0d1c2c886b03a9be96ecb280e5f9db4e448504930c34b2ac82f0915f32797256ecca9be42552cba36ecb11bb5e3bc502373aebebcf", "93277a710e5b4a88693838129cd7bc2d87eecb0305cb18faa26c930a82b282cc06bf450baf67e197bf8c2ce99508f60d07f41d39419cafb55658a9863703800d33ee39079fd28a18f1bf09a77d8376c1fa65881ce0c38230ed38666e85fc69b2cf14637789ac09bdac0869b8e41ea16451a4e6c2b46e456e832ba02b905a36ee08527642a9e54de38f434ef7fb7729490a1bc003a4aaa6ec4b21c37c5eddbc7c49557949d92e1e90d9e92aad6fd64ec818df59ec224ce9d08654f4f1a5c58096bf870036f5429f1eb5c46fa98948a6620da80fa3b89853d89c617463ebc90340696e5ea94dd7dbf7d8743bf339ed8e7783cd93dc9a8af32d6bec6fd0685d06afa81023878682fef904a684761fc8cd87cac2d178f0b8c368e844d8ab08d1c98aa057b354857ff194fde30ff9", .Okay}, + {.Sqr, "-c5470743a6e3c5f9619ed17ff9e5546f3085238fd474ef2f362ae6ba56a1ce2493fd8a4b5d282117a3e36567c7b69a549b622462ba792a9c049bf03a1e7be3eeaab9562282320ee62b5d7f4c8e905e908bea9d71773fcebd80db4103f6f46020d8047afb5992ce2477e26e05a279d9f78f3c580e4a533ba34c5eeed39064bfd94aa204fae7ff02dfe464983c2e86dbdc0831959d8aec", "1cd2272b35f0374a76fd513916e96fcabed417c83724fd9c90379a10858297816deb90f81c7231267ff01a0abc383c8bc2becc8e6383558328b53beefbbf51acc9a351ff4587bcef371215effc6c3fcb9360c192e6d65ae37a04aedfb825273ab23e58f01394054c8cde089995a3df137874948023d88fd0f187d746acc5d798ce850a11a68df9ca392ec1df1065ccf002558d5eb5cf", "980664e32695e60add6c07cf102514564aa8ee7d095eda2aa988db730733a685b9e415250d81441ac55d54741dfc0a2eb87d391ce83768e77799435fc95fd86d6be65827a800dbc8c0d70643c8a0d4fb619425b806aabb3b2b57b1a2f87a1e9ecf164803734cee59a9e3bb1a6b89a72c116448796e9c887531833a5dea7f6b6267bada0fd2f5fee2e0861950b9a88bd65c43c31a1e2fa626541b7aeb8d5d8d08ac9378881460958f18e9ecb444badd0b7779c00e2440580ffe68eb181bd0a8fa901fd61e8b28e7f48adc20201f20d5298d5766ddd042ce62a04d5b44070db88edde92985bf75fde6b279e6e354f8344f4afbf3681530902e37a532b1fe8461e9824fa2c6da2e55154ed0a7ffb0ffd2ed8873a7ba6741c55dd17998f5ecb6b80188f2147b040eb30268db4990", .Okay}, + {.Sqr, "-1eebeca1af2dfd2cc8b0bfa6be310e65112fd6f91877152816a42b646fe4c8566e5f504b356d716380b93462e3880e5cf7c038bc61e67614a462b902e465a94b82c2b734f197d1b8856e88e46a63357644de3c7c491151fcc79ba2b6922bcf8289fb27b2cd404bac16825da0b59a3528f919146d39c36d4824058278b8c1bdb1539129dadeb3b2099b337d823ef655964b6b27c36e67", "3df33cfc9dfac48603abf5a5d283c6a3f0c978f499a7f73472c0ee0da0e303f351a769bb46a4075c02e112d7f5aae94cd298e39fb81fdd7f599e43ce4da34432b7cdf099095d7780d773c6ed8f651671cf8af6b46a5210de72caeab099f465a8898613594d168ff8564830266800dc36e4726e19876e19d85dcbbbfeb04a8a1a656bea5bc85f087cb2592b0903c94f57b99677ef5f00", "3bc24e230a0e6dfe9c4ce2b76e2ec82175f40af13db0dcd4a4af1ad697cbabc76c52d0f757f53c52f6274bce3b7471967c03f38189377cab44067a40e3b19172b337f82ee5842410db6323caffc90766c16f0ed0ddf941ae411d73281966641adbcbc76e7395978806d4684fc4b01020322fef5d61e904903e04583bea945b139a6eb478223f3f91770ccdcc6bdaf63507356422dfc080c4fad8eb570f47b2834fb4b7efcd07469696e57d25d1cc7e861a6353db6cae031311f968a8b84fdf5b6aa351c4a6dd14570a7fc3de2ccac72b42a46de334e87c0c26216b64a58a00e169ed7a0ed09652ba7aa7d647e5b3839768e8d27d2f405bc2b267199503ff17232ba50c9cb43cd38d76d5ff654334db35a8787d799a258b08f7d58f02273f2db6be068708cefc4eec286ad71", .Okay}, + {.Sqr, "2b98bc0721949b919fa72adf4c37ecd48b8d75d9bf68df782fdfb8c4fd27406af1764df773ed74f69ccc76ea096a8360c8332ecfaa47c35cd7b1a7fc79d07f6e1322aa4434bffbc80a6a8383fffda2fa7137a4698088f44e496ffee7103562cc0f66f8607c90c76cfe3c556c5f3c935462fae8ab7150cd759ba29743f3098545d7acf79165e384e013cf2c1b4459a4c127a4072da427", "4783f0096ba5cb0c7cb982049e9fccb4b736765d497bba332772fa046bbfdda6c9336d9d5ae6e37a6c6b97f187a69b74d420a87a49b2f5ac4387937d9f6cb9a2c226cf487b521fd6b43bd9ace5c5e1d56d5c5bdbb650deb1276e5c1098cb22f5585faee4fdeace66275597b75e32ce1197a5465b71f3ea8c481a5228251c2e1e88c803c2acfa80f1053aee8aa1b212e8dcfaa2d4320e", "76caa4a37da4640c795c9bdf8f4f8a2c2def58d88c5394b4553add3999040626642fad2dfc782871f7163d89cff971cb8ea261e16f0e799e424322efb25c2740740a31f28a608e37ffef481096e4175ace5b716b1528693129013146a901554d4a40da19138a7bf9c8a01b3e94d39b8413b48f6743acb5abd7a1850b2ef9b2b84310262b5e5d4e69f9325aab523b2a3e551273ba1189e4a4ff3dfc5202686b4eabbff0891376b372d4c76f4200f4ac2cc6c84acf75cf01d1a396e402f2f27d30fca42f725f8b8802c81358a30b24c1f8329f11cf2e6920553e71bbaadc18d085c9dec23fe078abb8039d6c18a5541952e7a8d0c51fbd18f6711f302c58bcd456aa783d8c7d6bf3900f9858a6419ba1f2e9aaf11ce30c227e524ddef32e3358439d38b8a957fbb1540f7fdf1", .Okay}, + {.Sqr, "-b70f1754262fbec851453e67a1f8b26b9dfa227d4eaef7674acf99ff03c47ca944580bf85739da0b1684bde45910e3b068d2cdc6b3edd230bf4923a1702e548f5fff2e8c34d972dcac1f66329a88b3c75e17e31304e29289b792938d73ebd1d0c8d353bdea86182fb71b9ce3ddbff53ef616e9bb8124e12ea032729aca19e5997242e586f4ea49da94e8c3bdcbd5b00087afef0b26cd", "317e4211a6fbc31025a5a37e82a44e46dd09d28b17ff0ae5ace2f8e705de42257aee7b1de07689ea78a75cf6bd7070efa9411e056e33c15c8fe340b4fb835aae60385b0b47bfda39b7d49d90535202c408dd27b1c89eea0d71ffb0cf3dde1c246db9ab8cfabf7b09599b9d340b55ce344eca757775985e7d7a0787d8cce9fdc89e83634de7dfa7b7a9faa072f8f8b0a32e71d4cb0eeb", "82e6943e0c94f6e068f9ecf0543a78ad4c80167dcaf25cb238bf1fcee8d55a7034902bc7462ad489d6d7958ce6d08b759c13fc1ee08fe918812924302f512e05a0da21c03e0c3c163e4bf0d2701af2c03b92aa9f50bc363c5c73d883030d3daf89acd11332c016a4144fe8337a5f32a3ea4f07aec64bcb2c545500874084ec78a90fd81452153d3a8a486ee6b56292748e8d519b3ed5f7af1aec11b2562cf48063cef37cdeb24f2033c26bfc6a3e4888d2412413b26d1161ecb4e1eaba3285634fd1395696f3d9f2a131f4681ee5de74480a5aa700ebc73f62d04a81f0feac5d00eed936cbd70254eb4b3cb6b390afb804a9a8623cf2c04d8590d84a2c2a55e4c98cd7dfe3b2868eb504a4b2c3aa9f8dbdec2f51bc7b7c70d4b9d426b93cd99541640b8253611535217f8029", .Okay}, + {.Sqr, "-893e4cb7c5a269f7a32a78ec4d05b79386619afac69606558523e6486b3f90a74818954632a723eff66a8b8ad890bf2fd45b5707eb163881c4d0af8c2a4d44a5f000342f04e99ebf83f7d50c273a1a4910dd3298b0c70ccfdc172af74cacb6493d4e9a295b33eb484c28adb45427d57ae332d54928ea8cda887f3ea41315aee5f02057be2b57b0559043b31029949ccd0910d1f18131", "cf1775dd624b8c5b76f6c4813817f033f3abb3083a3b9587089b8ee05f8f876cefddf6142adda899b78f1c025a4847e2e9bbda023b27534a01f9f1c0462402f11a0f331839e1ae08af6fc49b1ff9bc07f9c7ae152cdf7c6caec6bf8d7d741c788ed7389ced4b68d7cf26349753020206bfad7474770f4a6fddb06bd165a9ca7524b92596b63fa7dcc694d28e6b7974a3071941a301e2", "4993bd45f189315af648650d65d1901429382fd51379bad4a4075b8d886f9cf14b78d1053ef323300d274f975a5d9747f8574637e58a8d8ea2cf3afb567be14ebda36436fedff833415975912f4a9f514fa770f880b2875c1437dada4ca5434d04e55cbfaa027ba6200ab3ff075ce34b1849fbd7e3904ee7e8d6aff94c2a8854cf61b968e1196ee0a70bf02847f2d90c8200415114e26283fbaad60b4eec967fe262677969fc653356f4be88f8b99b5f5d295606ec583a0c787b0798efcd0ee1fd8c6a7243ccf087def954d3b873f481a914e6d566f79d5b7aa8520eb389de238115e75c27b19e36faea8bff0e213c5c027d663eac990ee749e7bb6d7a057102f6274defaffc1661661cf72427dfd43a59e9d506bf1e607bd640b11cc2011e76cbdfd4c285ebd0e681746b61", .Okay}, + {.Sqr, "533905e392d53cdeba91775ace597d7c92cd0895fb8e207402820f391907ffb162346a56e623df6e184e809675cc70939da2cae21ae4072020087856ba8e3d6c412a14e28ffcdf7eec61aca4a65846304edb2316def78a53ff5777c89ebcce760f301114e9a00b2c48610f8b071c84576b899b31a31816e91ca3bc3f62ae4ed14978dd70b5502c1cb08c3cd5418d40eeff8727db12bc", "63220a4f207241eba69b082c0ac0ee25aa0f1adf44c18685ec5dbf51567c55cc3101a5c7a5d27ce0181814f57802f317ff8b717a0e38d288c502cf98cae83540e3989b53561dd6434f28e5c3c995670d4909777f595acf82fc69043406b47bbb448cbd1fa143121996744a746e73800dccfcb4a31f7d55e03985103b6ede6589dc3d6e537a06fb5dd97414b130b39e4cb06a312027c7", "1b0e068530b0567796ebf980facaadc296f475e48cfecbc58919e13d0e80a79dd49b7dcd5e1dd02fbc259dd43eff8aa2c8023c792dacbc7017d943ef159822dc5c0a66c681b159b1215776f53b950ecc3074873975f8f22520c9f68718710711357eae7861c1cf5cb70f7db133dfa9b6d41b4a5ab5e0d515ce1f2ebbca27db669f279dccc596690330a498b9832565b5fea257037a9e63421cfae6634d2f396dac3a97f931507d483a1ef4f2aac19b4b3ea05c41f5ae219a787bec1f4f6b3d91cdafe639e3bf99033707235a35ef365b5248bb6a3f7061d50bd0fe50bb6cdf51898cbda30262c452d6d8f8c98d1d940cee15034e48e722b60e0428cc10e70c4f782f4cd27544f4c9555db47b2952d3c02478882fa7dfa9640a3604e411967cf825f8488e5424c5765706fa10", .Okay}, + {.Sqr, "-edfeac9cee7c0335e39de968a220b761ef4df2efab8adc3045a61c79823ddcb482bb081b2d753f59c4c7eec7974f74e9dfd6bb20db6c651754151c7f446a3c13aa6ba6f110611e4a7db97516773f5184fd8c3be5a09c7e6f73edd179ad27034421e83f396ab283b57ee9aa93ffd178e2b19236b87f30decacfa1e1dc157087350066267601ec887885adacf6f2fdff3abc008294f3c", "f18f5f471fde33b3dbd12504ff27bba8811a64c412b803b0af536da793a767c795945d2a6ffbd3c561a9d33b47b5ece76f58e73939d67b4e6504a3bb8d94413e9d54f3fa5b8dbdd12759b32c03bb29999fa70abafd904ac325cfb794c0708e2721562bcfcb03b96a97c6b9e9227d5073ff141514c772b376c2e40aaa63cddbc9805dc111d8401fa0df7e6e23dd34928c5391c52b312c", "dd4188f58d5e1cb25001351bd163cb7f31c6b68d910326782a9007dc945d9458db07e95779bf7e6b15abe8440c10883da586bfd060bc6ae5385a1854365de2b8bb6f8348eb36ecff7958f4a7b1b76d52f2fd9664612dda1581052dd304880c205feefc97df0af9544b5ce8bed18cb33de3820a7acaa12666b9a02e445d062dfe88e46a1dbc9e444faa9f87931d053277ec60140a91d2723a60fd79faa124ea400949959ba176dd3268e88679ddb3e5d9279c23b9aab3477d1699834dc69afceb1a9a307424666c363a8a92ca9d9b721607108132756de6aa285954d523d072920686e9160836b39f0b4dd2338b8e2cf56c931a3b2b1385a905c9eb71f976c5abbacc5ed9d50b5ef6fd01b683c1ce12fd4898f2a97d9c42af9f3edd0f4b08af34eab17261fb9d9e39be1610", .Okay}, + {.Sqr, "cd0ad78deed7219c5ac95e2c1412ca39581ddd7873ccb843f11939712caea9633b03b0c918ba408c66ce6d8ad9068bb1f648d828699ab90a0f4df36a190d364b989647951ed49d409db8e377c158337604b9a345891c564a5b9b92bbfa40a246da2c7cce4ffa7ceff867ace293719f06d71e9fb4dcfc5d575e7a90d617dca6eaaea2531ec9f1bf232bfbbdcfd895eed59114b78e6990", "f9a86d36526b2ca55b72ff86258d010161396d3db556773c4aa4958913a266151c6c824898102762c94f8db8afa22058e0120aa72ecbf76f987a8e69434507a545a903872e6d7fe2369249a76bb9c65a26f2f88333f76e658915c8883c6115b6dc7877153613e0d33ec610c8a81b49800a170e0343b9ac0752a5190ef5a5ac8e3a6949e88a007b1178ba4a251fef3b684c65ae4450ba", "a43a5daedd1aea815be1f690637007da233acb490ef11ee4462466f0292688fabdfde3c2aef1e212bb2c6f290baff4100c5aaf427791cbc532390453bdf1b2d6489e959c92eae719975ce3d07cb6aa9e052fb37d4904e3da5abd4c0a97bcb1ed6bb1c22d844d82bbbe7fe1ea1d0cab97d01134382376665fe6b239d23dd2dee4a70a0aad575bd87dda9973a694ab46cc1371ef34aeba5bbea4508aeaeb5c4c5c943f77854fb4e7250c5f1e082fa35db6b876d4357d3a16527ff59c1f693a296932a27acbe5449534801675fa253bc89832d42c02516442cdecf3eb93f747568d03e7686505c8e193cea8f99f9f41a49f032a9e31e849536a92bd7bfc768a56d57dd38c863611260149f35b1c04ccf35cb3019f4ca7400901611bf85104e2245898c89a7fef1288a527477100", .Okay}, + {.Sqr, "89c6268a7933876511e7601326b11645917e82d95ad36558fab235521ee1874a724e90e984dfdec26a81a7908bba57cfd649b5442a6f4b8d6c74e9271788f8a5ba19103ca981021d5dc34471a09e1093d7e481664173e4a0281caec2d352a46d3610b6aafd85acd8039dd837f4cbb941356b2f4e0aa663bc1c4a32b3841619a438a28318c5b40f1d402e852460778e5e7f710cf91659", "efd6b2afb862aaa5851f9509b493d0b247684c25899d3bcb815910acf37110df2208bf7b15ec19c88f98b6f244eea31f51b9caa85ac987972d9988ff0835c41d28b83eb990be12e3c0b8db589b03f09cb5012e6c87017d536cf068bf394e632bc6f2a6623262d141d003931d79cbc4baf67750337d80892a18de43752f9cf139f8587e84df1583eefc5d5c793e970e88cfc10d73ce3b", "4a25ae9fd9ba0981cea31161dfd043b2be3a815a78e8943789f6a2aca0be64718fbfbbce50d8d4d9f341ebd60cb3d68f3727f984ea36a383ee8733af4ac26ff212d570b8cd058a677f2defbbb0b23c164cafdb0f487cbce99009b047010225fd69f9a874189f10555fbce5e10ccd6cc948a77ef94b5f27af5d41fbc29a86ffda9b5b4d32bc5eb843ebe43fd7ef761924ef37fa133090f2f8cc9577a007c18fa488c69e8f75ade6c6e00c9c13673001c209dcc6a4e7bc85ae4ad304d236b8045c662a7c20d774467f54ff493c21d96064f7051697be7aeb93f2739f627ca74daf1ff53b3d712c5cd39ce88142d4a880298b586e8e5bcc6b78e7e88e8609e9baba421871ce6b96f6bd5ec297b33d7611a2bb086f84d2e2610eea14f8ee8cbd3c5ae438bf40be165506d3156af1", .Okay}, + {.Sqr, "6eb6d167d39d5679a6312f45419c162a9af477f226542ec5ff8afe13c24ef140674fedfd66780ffc90a9d313af5f7c1b27d58c59c4560768818dcc57e542c8002fa556c4e08b818ab5d982dd23ffd3abccf52f813d7b96b5fb9e4d7ec0ad9b5324159b2396d0db6d19f704b6efd28b9ecf1113b2f58bf8060bdd57903aad09fbb87f7680de3a525833439014de7bdbe11da20f04080d", "e6a9881a7d49da614d1f427043972b61c804fb5b1a153ecdf7aef365af54c68faedcb94a99eda5aa70c2069d2f729a6ad32a210414a4c3b0d7d2fd216f0211cee9dbcf2e8cb35db5a0f81ed573d643febb3decf49f6e4ce007d504bf07f372f39a8da4714c6d39900b89bcd2d4a3b8f959ef382ab4ee4f15c0afe877fb88fc3b13f8702324936bc365513cf64afc06a80518adee483b", "2fe19e83a4c6cbaa5e85870e7bff6d8f80c8a245c4476c9f777e2f0149a868fd6f6845df13b7b2266e6840ef05f96d3e5c5e7c5059d57e46971f8b48471e7198684ec81c5dd0622d5457421677fe34338e0e8dae9f43ab9de5fd83914d18e0f994a8738463246ce4e90c887105928c4b5b503b24c9beab327277ee1dca4b7daa75e74d30f249da4f9d383f007fdc59176962edd8c82a1469adbc4c615f7a5cf588004b1229071f74afd71b9115fcadb9daa26d9d13fdaba65971c35caed2378e55b6503b7ad50663b1a6b70654034155aff8d06c0bb4ee35d3e645d999d7a148d8e8c224385a1b121d3c7f3e533aa4c4f7320b48eb7eedb0d21ddc408d7a13fb8e660f173a0c6bccb08d45b66316467bff6c5071d90a9403ab89d86bbd0ac0ebaddbb15850a89b75c6a8d0a9", .Okay}, + {.Sqr, "46b154f93ee77d35a455bc7c0b499b4788888f9a6d027fd69f5caff8d45cf6cf708f7017f5be11ea2328e2b3d1b9e59580ac7e5b96f303783126e18ac74e78d46fb90e936c4f0476dc61fd1982f7ffd422f49ace69e509d344a365cbbab3f0597800e2e805300bfba6ca733dd1718a0c3c16e28c5ff59bb906b9dd52dbad888c26316240178262090d0f657e244606c745d35411a27", "a46121209f61351968ad1fdbbd3fbd207c8f8a2621c91e74f769af9f3183992b26813c4dd1a6856a02c99e33aed5da584f9dfa4e6f13211942c7e8b414050a0d7cf67e37997e3450b37a66f34523c4af41f94aa114d77bcd3f64fdd0e1e22bad80df9c6dff8c1f1fc34c394bb2ef5bcbb3129a0deb98e8bb7588a9bbe0a5ab373c79aef8486e068141fe7b030ac526274d0e71421fd4", "1385754eeb441887d1fdd9cd9bd37529870fa8c55201bac983455456a08bf4a62a288f47d0d705d47e6dafcf9d3b500893f22d0f5eb9e07688a8108d1e41e7525996c95a71df6871834f6ce9be46b703592e5372fbe53aee241113e8c3f0080c642e02e96d263a91314cbb06ad24befa8b4a4c712d439bc4af82c07a65ae166ff341991805a3bbe38a422996afd07ab22387a814bfc144e925631c8559aa43de05d6f3f0144e723b0ff2ad8140d74fbff14837f074fc7fcd47f8601b93552326b7d6524906969439ee7f6e0cbf8e800f7c1c58b78c9e3f79f1bb5cd3300cdd748be0ed9eecbb7c83090f66ada1ac3cb3d92e8016fa8725d8d52b7027b9aa8ea5bb1d7703db974d0ef6e0337a79a45f171944fc6b83410af03e2fd6fa0d98a642bf1d760cfc5db87079f1f1", .Okay}, + {.Sqr, "d98ec57db147e081b9405fb507721a481bcf1bdf23b4c10e98afd15d8ef600ea4093ba1895c11d107909f9efac4c71074452fe3548ed4431dfa64f12104c960e6720790d06f67e059ba849af41d03f08f67fd98d19441cd9840ee1f78c277a60178da914ca3abef3228f4e027a7698c220b0474d300d2aa58edc4858fa06717dc9748ef7aff243c32bf607ed5467c4ac8ded7ee66148", "d2464be11f5d1be47d164fadfae4ff26a438306ece214708525d98e6862f7f6629687c12ba2480af5460a7a7fddbc8cab375adc67e128d9028c29e01f61d1def7520d5329814f0f6bf0a62262a6ccb26dbdc239b54f7bf724f92e70eb34a5f366a85592260a1bb642fc001c0eda99e60df708e959dbfb23e8273571301701bb37a492db0f52bd28bcdb593ee9f9c0adb6394da6a4b65", "b8e35a6ec65736e836760418bea0d35c9425e1da3bb9ae040aa82690fe7ef82e74e405ee91aa716c0a0e76adeea9310df9d0a779dce8fbd735b71fc41923c7725631f2809781cf0c042fa446586321ceddc379fe39ad5605799d67b4625dac3d26669ce8a05109034bd4cccb8d2ea26e795b678d512463cdb8f180c684df0746d00070a7373702cb2452732c325e7ef727e921f230c69cc8a0560139269f297fbc7502b6066c0fd4774badfd93be1bff8ff1895974d4f50e30c971f910bfaf47b79e21189a94e7a538688dab40709f4d6b8be4ba43d4881590b058413256b0e77da775047a70ebcd85f646edddbedd73db4a01b429517e7853013351abeb11dc235d26da17b14ea829b835a2cfd411eefe8b55184cf4918c09c2ad7808e574480cac4c96f5610665d257a440", .Okay}, + {.Sqr, "-aac5f3aadacd03a7162e830bd93a72914c6127b120cbabfc3235b4e03c2ca5df53b49329658516e6a5ae8ecc9c1810b0e9572f798a4fc329d714627974673d4308c424fa9349e0d65c909789198f8d48f887e76bb5edaceed1d5e297e8efce1690d4f6c1772e4d66e5a1abf6a3661474bd8d33a5d93a310f24a8e451c12f6c940c311324e4a70bad811c1f1831fae6d0daf279b2c053", "29c6fe3aadc9da5e3eb18d99695a9d5a3f09e3511aaad4f33bd03c4a03d95823acbe7c8272b61b4221cc31b0b84b490f72d2951e2de03dcf01f7f9df61b81d5f624750b7ba09078d159247132eaa691dc5c1e1149e346e1c31fbced9946507c360a510c1e8cfbe808f5894ae213397a9fcdd7b4f7ecf4e8ab70fc305d93ed442592fbcc80ce985b71540a9d632b430cac86e7d6e6615", "71eb80afd77ad5ca10d7c60e9aba937fdccf507958f5df836101fa1681c88ab1c1d7707623ed17eee078fefafddbf395104d247454365138d2aeaa3da097249becd6fa018523203bf74fcb9b9ff513a47a6c7f0e1a5b92cb0d8fdd6a8520415be6aebf3d07acf17f1e7b42a74f10b625e8c6c0c7bff7a821f75a04bec166f2328c5da5d33cc8ffadaac17d472bab4b6b7d8db87d3accbac86905df76583c222403e9fcc9e28c3520dcb349df1801c2b75fcfa409b2c4c5a0c8db321fb8e6174b8401020aa7288f17eebcfd5c26359d1fe434e2477659b548263e517bc5e15c58c3d8ba210e6f455bd71b6f0acc57393d9c99486240317de234fbc335dfa80205ff9b97911a1c20956f1e4e91e1ac301094e35ad0cd904eb7805cbe8d31e43c3c804439186a3b6f8a79e89ae9", .Okay}, + {.Sqr, "cb13d730480826a4f95c87170cb403dce5087f403a41507b68419831d022871caa264eb2cdb554bb4ec1ba1d596be423a079221424d0586e25c82b4251946bf24e89ea78d980fc7cc10f05645b0313f29ff14a58313df1c9a05de7237bec3a7e7879a061140dae319e20003cb370bb6cf2133c2ca78272bcbd83262f07a96a0ee07a4e903c5a475ab95038133cb2c8a4c8ef4d3a3fa4", "6282b5e6f2bc447714667de3c488acb83a3ab16d708075eb88d3a0742dda565f7a8a035067a8d64f217212682b9898109573b24fe6c454b89878e7de835db8e0d49cfbf093616bbfb0178952aab59a6aac0e0c0707de931cee3ffcdc10c10c7fd711e99bd810231a6b64db21bd512747a22d1808e877c6a7b8b043bfc0f24e3e22e5336abb9027653df243ff335396af796f5b956c7a", "a11878d03849c0982831f0b0c595c6f15a270f9355d816c4e625a54a010ae4cd07d0a9409d21acf022884f377cc2f22c32fbfec399af82c5f605819e66d529a9d5e66d8e9d16504f9992a938acb8bee91b1a07eaad94383e056672404825ddbcec1201957c447c747d5a9c4623f2d1437aeb689de3814e136546a6f15ad2a64828bdf574e3b0e040177da93e8d47024bb032621a2a63bff8bead6cf20d1387f436a0ef8b34d306e19b834d97b62036d33542af8c401936d47054557836f1e373a957b3c1e64a8e6b244321e6bce7b1ea6f5f3c4be87f015159cd298a1c8322f7527a19c4bce8299561fa1847274077beb055edf8c671e82a56d49b591d96f753d9c051a6da1b3aa0fd587c27450a9c83f675bbcd4230ba23027fda07919b3dffde2a1e7e179f2bc18e222110", .Okay}, + {.Sqr, "-6b953db03c037236c991ce12c057f2d0fb8fe825ac7f843e3453f82b635fffd666efe7271145e230d8ac7c861c8a9acfe0935d078979874d4dbdbe81ff58771fe6bf31508a76178b6f6c0222e0f30bbd2ce7227a3848ae17cef25ca27c2d6ce93fd33fe12c6ad695172ede2548101d5d12c143524465b7b1eb16be42e02b44f8b573e137354701f7c8b684ccf4f707e01731653210e3", "a4c3b8b6939ada28cebe7984684c8c3003a11dea8e0258f3fa7bf15f347cba6be1afe14564a100ef03086d0c825689aae7cd1b83819ba955142a427ee7e7bf3c4341d491c0ca4b38c48898a1eab9679c25bcdf0d7bac82e9bd4b5fffcd98104ec8c8bd6bd74012281fc80d5a07eee460d3b0c528f59cb2e5168f1ef1319ce6a6eff7fa9bba3beac5572201cb6dbe5a4b729d454b96b0", "2d361892302e3368f7834af7c2079e10de90408ddde6a53fad275c6b3ff7290b894d53a0ead9de54aecf1348e0d948abf7bdb22616422e1e6e31f1e78abb00e3c77aa1eda6afbcda9cc76b0e3dd0c7f8fc2ad8fd8cf5f1e6d5bb38f7cb868f3a2660cd6ad719d318eb812307fd7583a8bb123dcf4aec0e21268df70f77dc4a376d19ea88fd30393317f072f2ee842d73326d5e7a75eeb4462627c8e94afd6924ba8ad4e951d7febd0321a1d732d3117e3db70b5bb792f6812b0798c20736a588a7ed6e265e8cb84fcd2b48249246a2734d9523952a547eadeaa3b35554397fddcd4803f19b45f9924eea6233cd8d73689899984cbe083075362bf96a937d4e394101701a29cb39bc9442e2520ad43774c6b94a18f382374fb382a975bf928b9f04a90c4adb73cc03b7c92949", .Okay}, + {.Sqr, "8b220a6a9781f7203c1e2a4de576d5996faccccae370aa444691c7d400a7199348683f741fa77da3f699588cb10bfd6adbe4fec43ffb858b36af2647044b3c477fa6e5ac71c0013d017960f0e8d0f2267152f947f7817e8a3ce53b0a122fef81c290b871657a734c9d04aafcbdf3ab6de510003f3bca7637319bc977ecf94b65c0c84cae0fdcf61dbe65bf8dfedceae6cf17a42cba9d", "627969e3e84047018bde7b70dc4c7f5e64b75a4bdcb2ee58eec031b82f59d636d9e11c2d3eb5886c7fbe8409545b70735c0e77fb0aa2dc72678e812427a483eb7e5fbf12d018283766350fd877b3ef50d1ef2ffd826dfb6709f6a1afb1fc4f7efc7d24795124715465c1683f9604793dbd00a2c4e23ff9e514107c4021d4de6fe24c32d32b59a2b821b390e94ab47874ebafaf44feb0", "4b9dfbd68543e11a9e7278dafc2082547d9ead7a1d0d392e721a0e8aa2ebc40e77549ed3eda30830e9acd2d73b54c555b2c5f2f8dcccd5ec4be6360c3779b0841c09973ff27375362ab139f1dbfc8d6b16cb9d434975b2b0751efa71366f458aae1633a76ebb6fdbf2244e28a8a48e605abe02d4ac81885266f56947492ad91078cdf994ebbc6828e01758cb5a5fef34402f879e5807d3ce942d0f7b90e52b83eddf5034119e0a491617dcf7f206d58164775fc11abae22f47024511c216a1dc939cb85321d57b3eb1b14ab93a21bcc818b9a01d6a6e0d26f796f3fdf9910f0a8fc0871dbd86d692c57620d8a79eb4369acfab83397965d9cf0099b2cf64e730f1c989c5171258b7389ebbdc83e2a37c1dad11f6ff788d27042d1905f21580b8c4464d0d9538c51fd6008449", .Okay}, + {.Sqr, "261874f4663e1c2c910ea9e7fb99629ccb23c8d3cdae1eb9da77e8d4924ce9c505d7322ad0250f8b76ddbcc5c2312e5025bc4541632beb2f0090ff980f34f63cb9215a5780ac06db10cd0cb7aa037832a85cc35e0bb448ace6f998e5c774f6d5065bd868d55f14be1ac3583eb43a828cd53ec5d8d01bbdc2ef67b34a09fe827c39e3aa86f2ca7004e52d87ca5a47c502ae0c7d239e0e", "829c18de14744ddff4fb6ad7e6e6d559e37d9d0766b45f78d7e095a9f35cdda8aeac3c10d7db39c14fd35e7183c34cd33f99a2c65242f9c6e0b75daab63d84aefe682cb3a7eb3881de534fb3e7a90d804ba9d93048953703dcf9fc3a87d20935482a0d1218750eac3c40f4127eb3ff9467b71c0ead3f488a22d67510ce65de49f4519fd160864bffa2a0888501989e5dbc2aaba6294d", "5ab450eb19c01fddc2f331fb4668e4034b9a648c443868377bf2e5be5348eb6608464f011e63ba9a24d04414d7bc673f01bfa8f6fc8eb010bf6a295192c2e4f318dde8dab945962716b5750a4bf5e37495a07e6504b990ba2efc8558e89689fccae06a006fb10eef1dbb083a129d995bdfe76f4ce2168e54437df3310f56f9cb2dbd2fd4e79bcdc903d28fe9756a4da89976bbc8eadda4462e16cf85284ef7ff565a2d768afd5e6b00201582c7c00e330b89243eaec8ee7bf85c4353ae1aefbb4dae03d6ebb0d677f1cf14585bc1788c6feb6916fe6c51bfa1b12e728af586266133b7ee9267ceb405ed3c2249a1e48beb2507b9c7f2a00ba94b346fea2621ebb52c49946ad3be9956e758a897e51ca278e02bc8cfccf9198c8c83780e61ca50e1b444c6795a69e456948c4", .Okay}, + {.Sqr, "-3624dc1567c123a602e589c75aeb534b3b170dd40730479ecf9dc38bff9f126183016f7ed5428d9ababc69f94ea134943affa7ed72d64ef1e02da19faf0a55b5668e3073cd8f984ee97ef094a6841659cbe225b4df600426c5db06cd1d3c08d497e429c8469e0379671a54325aabf04114615cb7533f5055edfca4319b77354e80c9311548ff6b9d6b0dcf10336be18feb749ca7ba8a", "fe715300c29523d01059facdb66aa93add7f94007fbf943811fb5a1a24ef492e983ff84a6dcc6e7263de47d3dcd4299c78fd28ab53a95878fd636cb9bdd59e267df52edbbe97ace4980109cab3cfe33b8f058ef67d2da7ba45c7e7cd33ebca1884a2b78ecbcb3aa19b3833f96133090648f27ef34025de58c9d389f151c1896d664695021a4d1f634846a0678c87bf329bcd329fcf5f", "b739227aaff757a34ebd14c347ffbb73aff596ff164a36a3f3fa7af1ac4a0121ac2f97792bf00f14cf3dfa35219a2ecb5eb115ce78f117ee344be1c9aba05129edefc2c9401c5559feed3d090271588781f18da49e002e35eaac18e58817900707925c168e3ef85fa55250d85f11ee03b3a8752a412253b74af46f95786d6a6a8c439b4ecefee95be03899db56517bd90df4e35649e4c8e815e9fe13cdfb52caaca299cf02e0ae3c15ebee6e7ac1436e56ab3310b7ca5f6e872e1147b4fb89c152a2c8d74edf2722708e9d148306402b40713be764da9f5fe55dedb0503d2ed8f01df6f2a5904c2d5adffd2e9ad456b977c2d5e145f49f61a7e674a262dcdc375e4a991657de887c36833d4f21d99ca3e1315c19b45151c4bbc197bf904b95825fe115f4283424d17f8d264", .Okay}, + {.Sqr, "-e920f093db13d143980cd28c4e42f4f26cb3c0e84ee19ec151b77b458be8afce1a96504d52b37dcab66a7839b42f7ac0988ed2c3a0cb78aebd2298e9367662fcc0e91ce4a028aee05c2deaef490e219eac5dff101a6f10fd80a050b2648c81c3ad583d1f4c33c096360596400267a24d21fa1f66aaef39f479bba6872cb10cfb2f1d596a090182af39fae93c667500c06bcd51576b9", "cc5b216e8ff330dcbc02b942b9fe2bb82650f8510c1d32b3dc448aa4595f92f3c0a3c03a301b0140f8036ff5274e85f34245de13bcbd2131038615fccd9b66221c1d32b72ea2138b192756131ad52739be2e2bffed869ca814269e8e78181a86dfedfbd046993d65d816ddc8813291e7d14139fee7c3500178d6270633d78a0fa186863cc63c0d992d7fe90bed4cbc755980b37f4ad0", "d44cfa2a2bd6680bd84954c3144844bf222ef13d6e069ba61b356533fde55d5a01c7cb35df0b367e5cfdae9e17a05c4a23cb277dc0156bdbbb5a4164adfb075395603be60462ebf173219de04a221b55013d0ce1bf3b21f04a63d581e861702c5e1722bfe809a928596c50e58ac439989dc1eeb9458acdc25980ef7f7da2414331e705ecdb84c20d03b1a1907a84290489c6e2451fb5aaa42ffc061ab6eb8b2fa77002bb2702203e6d7bb7e3b9f6b118dfc6be2b4ffa7c018be1e5d8d1d46938f325faca646f3ee924f9879aadaf9e3bb5790c326e4f78a226c90c591d11b222d9da1a1cee7c70932c60ea25a55737cd921bde34fc38bd2ab986e2f083fd934960be4747d275841541e55a39c5ff709b9d4d1cb6b22a574e37dd01a0679e2f26707e5b6bcbc5148b6911b1", .Okay}, + {.Sqr, "-d7b4e2404b0abf5ad03711f00f41ee278ee5a37671cae2070439fd39a06d29ed79bc8290d2dfb7089a56500ebc3f22e57dc5979e0df1f4c08ab268478e7f5bc99fb1c79563a2d6b5b71513abc1c07d00a8a578d87938816661c625ae8a073c59ddaed6557cf931eb1464a64fc381a039cdcd56d6000da2eab80170948e46989cffd2c3ed0186f43c8df4cea748c48a758586b54fc2bf", "8d96780634dbc94e34db94c353f990bf3a8f04ae769da76a7ee8c046bbd1ea5c8164224cf131d87dbbad9d5a4595c0bb6feef4cfacf16767f46e626499aa05a1c1d3e68a59ffbf610abe1e1b0744ba9c7dbfac9aa28cda03307d5851b84188eadcb186fe0800cc484ff21fea1fbd794a043227af596cab196c8a7bc215878fafac455bba6013484db5cc361ee46f5b5f8b95986153ce", "b5c153d6f06b292c36ac9f2e828c316eafa3c6d36ce150540a2957907e06e16567a28fb986536f9381fb79846c169bf06e57a3dbfe6571990a4baa552fdb404d79ed4dfd66a6f6221c821282186e079b45265cb75ee56846a84742d70ba629d4df4fbefa552c18b0953d0d334981302593f2dd6aeb6ff97fde6246ee2f68af583971f2260117cae066d4e6e2261c6af4890b7ccc2397eb9ce602baf7a8f2cceb090ab58155fcf338139f0d0589794015d9911aba2cc628cabf04d32b58239bf13f039c526e4dca018416a57b29ea615af89524353e0ca817483398f24b3eb751a80dd294c84b8d97b0e914ea4768b659bb0d4300bd1632eb2c50564a1086e6c1f21b5e1aa8ed6a8220838a3b6b88b46d3cbff7dc773fdd63187e40164999b3be87209c9d1eda382fdc080a81", .Okay}, + {.Sqr, "d3b0e0563b42f06a23f47ac22310e25a537dae2a1dcae9aff41164f535807e41b93793cabab3bb91950821b67542625fb10a51e173063a8bae702fc662bebd677780a474c13a44a4b5d0981df8e21f270edfde06cee8561f650ba13d2f935f4d567244cf7064531590a9978cbab654e8e57689c31fa893739d82ad98fcd05816c518f11016170015da2f6f3879287ac5adda47f722d3", "3d4c5b8b3b616e512ad0663ee7bd6a0c94b96eb420cbca6342a399daf64d651e25cf0835b6aafdb3b5c686bd62cdf9d0080560465e0b2b9679adcaacd179201df5b0d3419febfb20d3832f452617f0b45835c86fe2cebda9d0de6adce771e35ddbcbd9346ad8e4000e4c16030327618c2867e22a01f608a9c82c77790fb919e4ad56bb57ce9a1db0f62ceb522bd50e5fc4868f8cc811", "af0d0c0360d8d91a8ca1a51294e8ae36373c6b4f4e3b09cfeec99571ce526b92b4b4fc591e7e05673b29da2ad30dd6c04b87904694c3fda7947742c21a4555ecd24f426a75ff2ebca1eea7a9ead53c935a0785be7af7ace5fde3f0754b0dceffc1bae394121b39160d09b6753dd2ac349d7c151af89306994111591150d74a16b55341b7e43eed97d680c2a9522b86e803b60b5022a00c468fea50e2e5efeb983d27988bd675f91358443904bcd95de5f5dd4a606dc079b3169a220681776790c3a3b5bb84680f2106bade89bc98d5e2ac0083ab782397e2e2fd4ca79f8dd794ceb388e8e9a09a934d3106462b0146ea1e6a2e29b9cf7712209c593e05fef872ec6e3b1ff4c106d590c61ad1c27185f3cf4626dfbc6ded87a4c65ae1db93a063671166df5ef1814141e6b9e9", .Okay}, + {.Sqr, "26ffb67f47cc992e053ad6ba37effc5455f2312fffc5a606443919b2a884a1a20cf7badc5f30773bc2e4f5da2e1169b3df94eb30e97b3700c71876eef15c2ad9e0f4d1fc87175f02c019e0d88da4f696d07b2e33a5998509d2e7fcd76e75aa9fa847ba3e1f91e8c03a04291c39b2f5f2406263ecec24928e7ad0fd0f0322a14f049c89c3bad1f6be0e52b05373c73ca68bf025db530a", "9b63d33da4dd1c63a9346ee05527614788ba76c60cdee8efa17baff438271567df33082498847cf69b8b9c692ac09f43846783c2b178596ea7293a06f9d01ca8bf90d3915938422354b8f5ba2673c4e08b9ddc7ffd2aa1bff6c1a983371a222ba1f115270db2f800d2bcac2166519f9f61da0a209b9a0792be54395fe7a3b19b3f357f2b7905e43cb05a1b52c060eb88b633a718ec1c", "5f0e99adcfb00720e2c6e8bed2f86b62e26c51d0c68aa3d017fe3faaf7a35e61bfdfa2b2c33a6d936b9e17fcb73266331733ede75968ac94987ca08436908bc5f361723af052a40d27a69048b9522726e960dcef56879bf391a72cb693f865c4bf4d48c69c55e229fbf684726565285fd98037749499ce369f6928344c7de81174c41d185a629a2168631b88d0ddcf2e9014a503a76972239e1ee7b703fff3f327a40de9ed2f7b78b1f7c05dfaaab9d1de8cb1b7ed02d5b2dc9062786fd1cd05e0d6d336b25b244070a0f1635a7bdad652ea5b1f7a2a2acb19caa870c362c1ea41f20ab30afeccb5ce8fc2b6c7a73327d5c1d831e6725f57bf907e4a52fa7cfc5538c7b3ee972cadc22e4aa0b5cc33339ec0fa9699a51264830ad6ca53a381dd9c0a74b8df9b0a8120b7c64", .Okay}, + {.Sqr, "-182f5891485d0d44d1e1a5d0c75917b858f38ff2bee0a5aa88e317f02d4b5ae355afd3a5206387ca588a402eb3e7d324236ea2d8ba261fc047d2e4099747c46c8c0d0930f9b4bd388c914c7775300f2787e4f0ff93e5f820cbe2c6bdfc91770fa757903313b6f8b9ed67d894cdceb5db67c7e44b8131bb265a6d6bed53479cef2b59a5e158174ba0d8d0e23c16ae401b2609afbb9a53", "2cfa3f54bba5be73877900f297ef67d0a7fe90fb99ba170752919c8ca992776a8c771f5b6cccc3cf4553936c519f3b7cb5a3f0aeebc652fb253c049175dd9aefb85174d87a2cb07832ec97f3b9445480410b60c9e33d42ca9b9f2798af3fa27d418e0e7209d93b6ba5b8bdd7aefc7bbc58960e216b41317d0e530c64b37313974738984891b7923b1516389416fea868d7d81c8eba52", "248e95ce18e38dacd9c317c4666c1c15a3667484167cd3eb249cb3589d9d8ac0cc36c4c392675cc6f62ba2ed6c315d20577bae24ccec7944567fc03e9e960d1aded0268e712aa94ec82eefbeb51d45d8ba53f9408e58bba995e71e14f7894c84486e4e21b144c328bb33036cbe3b35b421292c97566e80804761f7f5fc4cf9ca1bdc9945b1f497141703f821839b0901ab6cde58142471c69618ddf6bddd3373070955b35f3688d6fadaacc5d555ef483204dde20fea003088a926eb0f68eed6d29910763c0f187e4a2e0a357b3ba73ffa0e133c22421af3ff3db53164ca38772e76ff09f1f4f33b9f9d6e075909867a44e69254625f956a762eeb9a9cde76de066e868dee81ca1dee406722b77cc255a589aee511282ae53f6efa47d57688fe803cc199325844e4c49f6e9", .Okay}, + {.Sqr, "c17ce975a280cb8494c238e443e6d0a8d25607c1ff88d9ff14819df8a852c48c49a69a01e9af728ce827a5760822be2b8adcf7d9281e51e3ef7c9039dda77b52b2fa3fbe312a40574643895c8108ee4391797087c0a21f40cdf3858febefb9eb85aee829f5135c130e837671df2d385e193689e5b09d9e5f329dd97d482607b98caf8d4263bfcab16f8d7f62b2ab16ac29cf3304445d", "d0e2ea02b242e8fd5c0a4193bcea4b14cdd263ad9e814c9dc8d5d02c51d45b17ed0b5a8c13132f1bbae3bf5556c221c4d6ded1317a5b73e438174338e3ef0c33be3fe6e67cb92c9911b489b664a8b81f59f366ce82f1137aff151f483f5e5652843c7dd42541bd852d073c21e947cb3715a1bca934372d5d6ede5551334b853e9917e595411e4b51034f72668414eec4dddea7756822", "923d94f65de2f77f74159648c3416d4878a95f598116b79c91e1b9be6042c3f4406c40c447a5905e6e7763e91a1118ffba42708729b8704a7a66ca8c76ed267ebc2e181e5911fc1cde5547c9bff4c9a74c1a6f76fa3d1dc2b59f87ab0443d2e45e48336b48e22ef16947cbdb45539f430d6d7dc30a948fb23b5b8ccd8fea4ae27cddcab0c989b6e729017b09abcaf758f16e8dfde7bdf11981b9fa65aa67de21666579fbbcc746e3046ddcf5f200b1ee3cbc486ae13138abfb1fbd9c90bbd33c6a695820b5cadbc59809adf960d099612c2d371c824698c80fb80908a205b6a9b8a5b7d1989e09a8192bbeda1de166705e7496b55901ca2ae8195601d5e1e30c2e0bb7a772e1c8ed044d0647da1c9490c9de8d5f52b422cb3a4f80357ffd484285fdf7c4c1ef0bb5432989c9", .Okay}, + {.Sqr, "-3374864e51c6219e4bd14c4816142bc42959edbb81bd0ba22dc665d91f3c0ff0149897e31a6ef7ddd04b0c2859a95d10de984e8bc83ba13e990c57b226bdb55dd346a251bda328ca3c2f39497efe3cafb03fafa90f3a121f792f5bc40e25ce106516b86d9d444cef4f67b721551e8ef4d790aa3a8554ebbaab33cd3adf3b09064a5bf500c6f7b26dc8f7eae89d15332cec04b496f73c", "72e348511589e6db840e8e570d0b704ec2065d3548ec11e7bd8873a06db12512fac56004771efd357ce2c0dda5ee17a565a0710d1ad2b1363483abbb5792a92a152bf341667ee31c05ecbc7ab59a4ed5aee6f7498112c45f415df5b148cd3e54a204e91c47b33be22573ca0a427b0b6692621ba13e84a8b70c9020c308526a47ab42ab1d25b3b6dfb9b4546867bd7959761e2a13ca3", "a57a28d32052284e3b748855ac7ea37a44f4c6daa74485f8ecc49f53015323cc89011bb332de43d7a3071d4d6c8d4d3daf5e887f78915a38e3c177a8a34cea89cdfa807a79f644502986f6b81ecb855c7c7c4efe9ce2629e9dc31f8bab3846d289ade27f1b9f56ad29ce5df5b9d06231a395f588eab93be15a1fda1b9e675128efea049694a20bbc4215276b58ebc19452d215ca24258995066b0f0a9e3dbe7a20f66da89af1add0897d61cfcf6b57ff6b7d2ef8ab2ae2cad1821750b37695f865ae5f0b76952bd32f767e4ab25a0d5929be81a615a0032dc9461a9419e786b19c61c9d799d079dcba7ea704091f6d6fc93d62f3ec063fdf1b3dd2e39229af594a75a0080fb8a47a5bcc569e060256b562bcf5a9198802d2aba4cd142798f9473ef0f4b6092fe930914d610", .Okay}, + {.Sqr, "-ea1384ec1edd9af205a7f38f69b9f6886c2290c6428d4d03b7e76f0411c640e745f9c4d27c2d955e0ad84b100b6a8f26b9f1c76734c1b27cd287708f49a225348ef3416a33d1bae484bc343a53429f6abf54ee111fd57b903d620fd3ba7b1333dca31a4bd6550e8c17ebd978ecd28f62f648443aa669b7ace846b5870bc23ef5cac2e2becac2c03a3f0ba90c428b30ee287ce2ccff81", "84c22531aaf411a65dd306a3051a11db14fdaa8d31f383707a298229ca1bfd590f7f3f4a6128f422ecd0e15022a1962cc3dd3103dd613e7f1229d999ac87b7dee5eda8be042151510012a0c4d624fe0a9a666a13eb7069fe495097e60aed39a2173511808608d3655b2faa2bba6122b4b1bb189bef6c05563122190ef0fcfdac602d3347450408aefb5cc25f801b64513b38daaec2fa", "d607b07ca87e0dc4e65bd465925fd26b981f9dbd7c2b64e269cb688089a3623f06e9506580bde22580f9277f76849832bedb5c23390e25a4b35bf374401cb154a2e047eafae84b575d70d917051eb26eb10e2b9984ab6a78d451636231008acd88a20898d4e1f58af3d48ef06f4da4d0c306861fdfe57c31ff2c1a83a23148ceed216ba63311de27fe47911d07fa7f88ca6e0ba51855e6467ef7b9d9dd278ed7b56057172589a7df62052ab68d61eca270f85494e11e744f935240a7634352bc49988085e0938909cb35122c4adb0d98e7c9a705eb31a376768646e6bca0c11a00918ac164e6be1bbafc1da091d69755782ff138fb30c1435d03c907aef3f52c3748477b5f47d074e703fcfda108346d757191245568b545778922b751d5e8f4681dd2de033a6c3ff89a3f01", .Okay}, + {.Sqr, "-81140d03f3e634ddb98e856cb250dccbf46b246e3fbe0d541730f5e5493d4924842c33e53427735f71fdf5b5a9da2ccbc4e4c32a7c67a75ba95cc817762df80ca0f1bfecb2135939e678749bf107110e5f7e9cd3b40c7400cce00329ee3dd4ecccbab0b98eddb5da649e277b2610bab4375cbe7d98569dc08319bf9b02798eeb55194c3eabff15dd6e81574196390a4af523ea898c9e", "d4c6616bfa5913d4fed84a38bf126a88e59a1c4614cdc2f7f2b69ee3455e99417c59171362ee0cc1b1a81f39c2bb1fe8b84cca06534fbbacda3efbf0f8e4637e9a1530f95702dc0765c916bccb8d0903e4dc8b73f16b00b3d241007c5acac74cca47d762b8d00ee2b80e7ada9cb6943b688075db910af5ec9dd0cada71b815e87f1617f3ecdfbd8fe2692b8c022449d4b150f425f316", "411536b005158414b8c93a272f2e56a0571fcdd3775507909a999eff8cedaf1297b332de0fc17e8494d59fca4d373d998d4f77e06f82eee2aaefa2db712799bfb59ed26fb6e22f5dcb0c4f75b57b2ff42299ac858fd7e2f4117260615bdc75b9c422a6b3cbbde00aa3759a28b54f756830bd19e65f0234ce50606ef0972e8341eb1e1b315fb77570d2b8586502919db621f68af2db48ebeed651b9fe20295d61fd877570b21eb2e82f67f494175f941d0de9454d20eeac2f2859fb3e379c883f2c15c06d5950fccc717f99ce255b9c1224aeefbe0e44f01cdaf4d434a460c544e8588e7ee4b3416ede4eb277d051baa1c533baa3f6c9f342fbb0bcd54d3f8b0c7ee1dc726a82b032b289bd2d07ba3746e1881a1d72e822bb4139b6879afb4899e019e0d2e2fa9e2ca6593184", .Okay}, + {.Sqr, "-8f239ad49db02b2db218f930cc144d8ff3be9f8f3a5cd174d4c50ada00db3c92e1f3c553b4de44873c17aca822b80f14e1610664441f471ff094c4f0f3c63141008420cfb6c9b0862ed1fef42d2b6febdadf7437a292cb41026ab4dd7c5642fd23f0447679b440d219de4e22075f1eabc79ccca869bf9e9d9b5763bde5553df2d7422f62a7a0d412023a64d6af664badae7a349c8727", "a545102ed5fcb8928adaeab4145778cf540d4ba24c8854ac44e3a649d86d0b69f7152fe8736952711bf9846ef5b53b60e1324b1958211ff45bc4cf60faa2ab87ecc8b947f6284499ab62111838343a1cf970513283c317894db721ac70e5e0b0aa6a40c4fd082d256890646ecfef35667af7877efe0bd197f0d369dda28dbe33ce240d035cdb212b8efc206dca354a719601231dea10", "5008cbed3bf26cb65c52a55f1f11d087706b83c9ffa94b1851a85cfbf0f0d4176ec6eef5cb9c73c02e0dbb94c208d4996bea13099fd9f8dcb616387f3fc28f2e5fb0ca2b13e2811094bfe03db286136c2006a94921942d1b0bac4cea532f856c4aa0966389ad59975a32c6e7d68405267e66f4c9d627ea339ff8530f27fa51ef94bfae3f3fdbd67387b55a5a4822a7cf409054ca57b4652f6d5d50038ce63eb50b01ba3c099418e96c4ebe17def13fbb56cd11c631e1ae5b6c76cc36951ad441239ce0596b89ec85853e2403a73d14376fb5bc184980fd920c285918c90ee24f2bcb06105b1121c5ca9368e989e741dddeb99ed52f6e4f48a59e978532703184f035b07b7f39231dadfbf1cdba1f491a969df6dd1a8c4afb5becabd4e94170553da031ae7c6fcbc8d6e227f1", .Okay}, + {.Sqr, "9eec95df0af6597cbbdcbe6efff24c5789df6cddc7f39315462ef3bc8a666002054a9582ec959f7a619f9fa5df21e42ce05909821cffba07529136481bfc6ef90223c63d43b5bb125bb463454f5f60cea5d62962c83aa7662f4d9660777af22ebc0e2361905e7781274720376203e813519964a8c3dc2d8a5fdfd8b02f561ff5745e3a09e62b6cdea4a9aef54d4477f02a9ebb643836", "d509e2d835cc88ff45d411d463931eab000efa4a7c105837d2b096419806dc9d8473810c171582ae834a365a169bf5cf4775e81608c5d287a6a329d165de7f8c81e6a8351ceb5089ae9d1f70c25bf0ce6e4aa1a4269bff3a67c3faa9dc11b19ea18d548fae156440645d4494ecf784b110dc67279ee661214e42204fc8069446aeceff8d64de19dbd9b166f89b7abff8d4d634152146", "62a8e3a3fc81b1c1d3b2201c3a863acf72059f00c4e1406284bce00a846d9f8a2da3b0a0d3a4b5a63e475ff706d17fa06baddb10e179c99a1cc67e0a0b4103f8c450982cf80c72fb0f86e70da8f8b9bdc2f3c1447d14d5f3b3abea1bbfdfbacde62f81396ea49998a46cfa88d446044cdea2e1d813db61dcd41126592761acb2efd0d3fd65aaaa51c14967c287e33502056fc34139d94e581a7528dd2327fd40f1b670151a7590a5a1930f68bf78e22674d682f8745c4c81e315949c0e2475cf144cb138a45d06ce9351805d5ae0d67ecaba0dd667b5c857df444599ade9a3d92ef761bf599e8e1e0a6d978bd4c7e148e4783dd87bd7975ef3e4da1b7154d9f4b72e5d7c37a27bb4bec30b19387a85640caa341a69a11edf6eff6f26a3f99b86595958c45492ac02da87ab64", .Okay}, + {.Sqr, "-5b46f79c8d8903d6ec891f3bb735f94e37b8e224ded868b17ce700e62346bffdbccf0c020364152405e196593fa2997e347500abc1aa2b591c439c704c3d53f765870fd88ebd3805c34e43f1c6da3df5c253d8ae71c648314067d0b363971b666f1edfc46acac6f034e7660a47972727d2b63b8b2d279f54483719a9a252d6bb894235cadeb9d2a7cebd26490224172d91edbbe9ef60", "737483a3cfab7f0c30586d34c2960f278afda7d4e57190e6ab6c6b7cf8be571881e0ff9330eeebb2a96819553581413d03dea4eb9e66f933551a6fb06917f2916a62620f527d66f522585f28d3a03a5964a9e4b1d94fd748077950d7753d40c6a397b075ae9a4c4f85d01a93725f3373a83e7eb53c8cf38c195dcf88980727bc2d0d5c99139fa61d0e826a4e7396f9a66c52ba87ee0a", "208b87b5a5bc48841858792246f2d23a1f84f64bad018c88ddcf1050cb2f756c0d0dab11a98c7779e88851db71cd9cd4063d039a3741ab041466a0fa0848efad5cea6f3be09e57bd7de715033cd002de3208a75b031341c9b2434d153b72f9128e1fd56b7fd71e9ae6cf51f746b65bf1c48c8c8b4baff637a7f3dfceb73ca2fd59f1d7701ab279632b3d36e8c2651a17328560bd28f963e646603cd6a13f16cbfaf9c80ae6ff523762d6c9ea438b6225b34699cb360d4a158896a424a725316792228a3d984591f387426a5070f749b51ff94883711b37a04e20861d83fc191c52e3ef90f7462a049c2ac9fc2875328aa2c3b30087c8f41b075a2d6baea965ff2db2b81a45f3249ad8d75a8168d80c069f140203cf1ad439c2dcd8e6ce7a8c5cded017e5e1ff913bdc946400", .Okay}, + {.Sqr, "-30a4be6948f7ee1f19b30fb875584afc037781709434eb313cebb669002d6440059d399c373b4a6fa9db1ed99b141b4e7128e685e69d7f4b5f2249d65b06ea90bde47cd4ed96473616aa12a21088c5ebf3fd8b1e132aa68bd01e35d48e3eb70e4990b380e17e58387392bf1b6e6f7e5406b90d66b65e479d932e68a88bc5038ab13d1a3a5e28e7c55a506aee70ffa0d521d383f372b7", "f871e535b68f0833ec3c220706980ef09fffc31e5d4a6ab20fb30ccea116cf7ee7cc8f24db175b216db80fd3a34652500b33d801da0a74dc610ef5ae612ed23fc9eb4f86f13b9e78d18dfc9abb9e77cd3a5d5f4f62e1d9d15f97f3bf9f99a32203b382e0fcd8613f4bc5af27aebf3f5a417c7e98de2f6b97f49df7ad9fd97cb8f6447802dc5ceafd9b1eb994fb753bae13b352b72a1e", "93e316bffe2ea91b71ff9090c8650ae2b0e33445ae42a0567483c8cc3dc8a83a490005263cee24c536f5f1b9efc80dfcc6fc424fa58af2a67718b66305bdf54c1986ab648a5765b5a3e56671107608ddbb98f6374d64667a24f402a4ebb8e0538577e0a079542fd91801d02f85b5c5baaa072e5543b69f16875a90cb266ea1e4e60d3744fa4d524b46b17cd4d57ae11cc77683608cd1dff93059d97e9c69c9d94efc03fe90d536e2cfb61112b13bb62fce4c20b066d51fac2ba8ca88547c34c7e8fa0bbfaa11ac9eddd202f9dd6ab4556aee2198d4d94ad16f58dd5a891993590fdbbee8a5e4bc73352733c5e140919141af1c11247897c49e079090fd44ecc38515cd76499c5cfac0e75e66285c7e8658696dc76dbb9695246c028ce42e4986f04c1db2f6b569444d17ed1", .Okay}, + {.Sqr, "4edbd5b1501cffa3cb355f313bba606046fa57b7fcbc52169e0b86132ffecb34de01efacb2da4184cd5cb13967f3681341df536a06f9d628433fcb0382edf02bc707d175e233be2ab8f7b7852c1a63e156b7ecdef08428f6316ced55fb4ccd4e3561cbc684a30eb879ccd4b3770b8a03504955399afdcdcb0529e78187217287a20429a61740fd55f89d70fb67f790123fd06f8dbb0f", "d74d93de97190ccca1b7fd9c58ca7bc8a15e3aad278cde3bf1c1e8fb93a165b84ae8d0b6e397caf3b9d43ad98de9b7fcf39244ac03a80777d1d38c719e546a5b691fa06488b2030eb318ecf6db8222b4933db53a452fbb27e50066183f4fb4666cef0674523350481aa9757e7c201e337eabac6f73ce676b139a34c12a251bbc7d6453f0cc6afa946e2d3ed5ab26be5be5d4f392849c", "184ab2ff5c91478554a46707f8f4d9e09f1603ce2e370c9f3b040267910a67f7824c53df4bb5e31ac96366d5f6f86d0cac1fef0ffeac60e6ee817745f41e43c700e3a97e136051e260f95760dae1aeedf13d7c2c36f8ed9c6e14e47fc70400533b9a8849139f5e5eae6fb9b1158d1ba9611c8bfc79eb5debac7bb9acead7829ea4a9a5ed8396e1fe4d21193d25a39396d2efe406d3eb15da6b6aee0a5c304bd9a0373c0f4a91f8a11fcb43a0b472a8d15db5d10b27c633b3f6cbe8ad1b1ebd910eb7a5c08a530a897dfde64b8e381307706d2767a7c2276b82458a45bcc7af2c15f052522378162c8b72a4cba1860940713a60debbd384687b119e3fd06fdfdd9e5f7608504c86de22f73b469f78756a665e3f9996761f5cba9a301ad436ab12c6266bee6719910e9934eae1", .Okay}, + {.Sqr, "a6d3443d23252bd56d470d5f33964bb36d4fbab18daee7bf0a760a953e45b065940c00a79bc37bed32ad9dc943d9089cfda106641047dcc60f5c8e47cc5fa75a8f91b2596ca8e4c0f224083e91ce174822abce947ab1678895af740608fbe80afcb9e6e4c061e4cc3c5c0edd99d1e63223cd808850012bb996be58b76940d8970534fb21cdadb43c924f6dccb468e5de863dcc83e33c", "d8bed5b2b7053d60f4f71a33bec5228a6701a48634ee376bebffb04ff34165aa40c9db21e3ee377ea401281ac57fce1a25346d2c4d3969d913ad9b6633cea767c49846bbaffd5ccbde9962f108eff57d4c91f5be116e2b00a139122d0973a790103cf4038f7dd4edbab1249fc99d47cc28c593fd447df82133d63bb20022747057c56fc30ea0b0ee71cd2e9386d730764106fd1943b9", "6cb6aad8d88cad648f5dbd9d63e14f8ab460d0213c54bc9ecaa785c4b71f187094d3ff1c28be761ecbd7633a41dc28ebb5023d014b706d8c364d54bc3d19c054bf1c7082f25766d2c7f77f2436b1190f57e57a5df834ad99ea7bbdfd667ad61657122c35592098e1761eb5526091b7bb59402b31d91e2e899c3d856f157e42e6c4a12460660c472177d7247492485349036f60c4532862e960c00b537b9a36e43408bf528ae7ffd5b1813b6ca7a2c2b4e1122a2a3afcac4a30c1b039f9551c6bedba47e6aed6d99c0b2454ab862366c99649f4c251cdbbe9cf35c80b2fc608a6aa065190a78eb543c3162cacc9123060ff4655424c482b7254849829695ab51054480a86014369ca9d9325cc9fda7afa5c771836ef9a0c60c0bf6b149f58c8228bcc6b0ca02f90b1f91b7610", .Okay}, + {.Sqr, "-f2ebbc7de389c362ad0da0465b2eaf3b7f3411bfc547fb11431e5e0bf738bdd8a88e3e464b174828e92441a4cff5041bbdb32af9e848ca14708b5ae7beb971bbcbbecf56b773df2d3d100ecbea9978f5248da05cfc4b36ad974a6be69c55577762aeb4754e272610ef4a4fa82cbd3e57f79b75abdf1c3266fb7ad8165c9dfbc3d379c3f4bbb6db1b8645ceb813db7e352ec3f7338725", "6f2c03fb95e2ddd61c1db4a2934abc17400713e8d3ae6af1328d1a9407ded172d0aa8dd3be5ccf292dac9946ed87385c4c11f955ebc4b64b513444da3cd53b457cb8151b11cd01e82208a27071a33dfbcbf1f2bcbef582eb08d9118dfe121ad9f77b4fb88acc9d1727333b7283ba44f44ca56fbb99e6d18a4e4629c2735a6134fb3a602501717336ab5fa8af1cbb3baacd53c83d0454", "e68289719c19586d9c16d135fbe86221d74830f09cacf34c52ad7092dacca9d6f0c559719f9fd71411faa9caf34e86152bb6d57c514f03b25402f5fc4deb9000c0606fcfbbf2fc1f1f121df77ac5d246bef3767eae94245f1d6e9dc2a09cff91ed2b8a1d7e3d1c391a6b730b60c124b8b31a083504c46c7afd76383e6aee00c81afb9df2c054b4c30e9999e33ec958b92480640cf63facc270dbbea5dfc7b6463f386a97c88c0929fd7ba439637b28073c31e5de87f9e9de2f27cf15180e1bc91221b1314381031e97d597d636479deb93f3095d3b92e4c4edafebdfc4dcf415d0d48b5ad117700a2f7eea9b42201a911b84f7546f656e93fa0053e16ce47036f6c5a66c2de7249b2719b152deb9a994879b72fb6b2020dd695235c4b0c15c93b66ece856d17a78686160b59", .Okay}, + {.Sqr, "1d4b8df5ea2762d720cc3871b64eb87268fc14586fbca275247ba0809e05f7dfeb564d1f1f2675bcb7b746ae0b76705d924b59ce4310245a39cc25470a12c6271d40c4ae1d6e848506120f8686fb4715873046c34fc88ffdc5538095f958a06156892cb28ba63732fc0f8a4aa14a01eca86657989dab3dfa739c6562a5e46390e79c03d2e19984d2efe479de8aec7cea909400b8072a", "bdeb3cf136a45e04b1bee4f797fefb72cac1f8966a9a324311be9af1282ca7ae1175f02c64daed63db58fa33b40aeff35d4615924d0d0a32a3aa4a024d343c4660e4c624f8afe45a3e61683a7eddd75d2863bdfc58e5f4ed6d21f2011da78f87172674fae7e4b392e1ece04d3892a578e8d1325d34a1945dab847e28f1a5e1f510c8e20bcb3244444531fb38a5926f94788c91f52aa9", "35a347633dcefa20febad191eaab3b1330cb7badd84fa160fbb68020c6b7a7c869abc7908d7b689075d053d77d337ebbbb3beddad9557f1f5dc082a977432b46b5b838e24f7f01ff09eef162022f5f5512ccc58a4dc05cefe7f5b4cc318ba191bbf8d0a92496899940ccf5f6d302e36be3211ed1cdc8598e93de0968607f7714fe767a094464b1bf1c7daa294d50c01e3323485af005e4967995bdf4a15fb6f13df79fa73da4f33fb3f9e2863972025c55d806bfc5dd1ed54302fb886b8dc12eceb0a92bbb1187468de863a8b97d0426d0747705c993ec84b9ac2ace35c8c6f8663c9661fdfc686211246d1c304b53e0169052a6a649db20636e73fcd713f1f4c6a90773f96edb031e66559abdc528a337d63607870fca6306f6f1e10c29965dcc8eb2da5a00cda4c9352e4", .Okay}, + {.Sqr, "-72812abc5b093b2bbf37ad12345007b27ed762d43c5f7ca1048ee8cfad2d778169ee517d6fb3e43095a7e0341f105ad3e057668c78870c4d309193d78ed075964db2746f2225cbf83f6af278b7fbf9536bd06c58cf7f165b2d6278fa85b02decf66833563468c5ed3c474de042382d39f05445d94fd113c19c9d6add1527da523285017e2e3f8bf9577400b6baa82278a5e179834769", "1005131c5ff7e1e3912b3e02ba762a5b4a2ba8b565c287dd5b9c5ee5b844809c230932303b30acbeaa053f43ec39ede43397f8aaf3aaccf7a273d8d629c113ee631a4573681fa4cf3d099f74ee26ac7ece6725c4d47f94ff9eeeaef0b1a854346db33ece58a2422ee864afb7542dbf13a5c846b1e380fdaac29933d816cc2d975328357c40009342b0e73086b278a09bd47cc33de50d", "33374b3bda0a507575bd1fa6123263fc64b4c4907c7d1877f58bc08224605076289c163372019ad7f727f7dfb839e64c6753d5004bd05341414c9b91c5b43ec74938c3c8844e5b6b086db079c3fb6c24bb3d51fab1d6eef5d20353dfa3f0f553a4fbf3645e1ffec6c0da959dd8dfbb3d6b720c5f67bb858ca8455c6d3facfd0e575767def87f956e37ba538f08d4aa582369fd8b1a2ae376b80a3e7c210c096ed81efcf5c7618e26a69e8a2befa03fc7459bb685010c2bae9d32bfd3640c0424c48a8f6aeaef156a8fceba715d2349ad089037dd0775a9d7c62a1e1cf135a2bf744e2610fa8ade9cb730790218f26acd48717db58a6d9b8a865832e469dd84593156e5fe67a9ef5c3282bd2e905a5fb451a9e3e006708c98d1752b98ba667d3f9c838514e2ee3d656b616911", .Okay}, + {.Sqr, "-baad570a3d9cc9defaa238878111de7f2a5de3f50a34bcb4ad3867cb55cebc7117b2282f5fde3cae3ae2bf8f63240617d68992c93ec8a9df6de189009f8ab33a6b30c0ad0e5fdbf05c0da146fb7179937e9ed73690317bbcced0d05cfd5ec763b2c9be2c82eda30ce9f6b8ca833b55e1ec508050f32d4e7021d90388227261beb83a28bb94c33f143fbbec7fec66295d9980473e7417", "2e8fce69ac3eea34656f45c48fb8c9ead7b9a62f658f4096bb536596b043b0bf4e2bf624cbab9e5e62e1bb233b9b9811274254d715da8b3bae2382a194cf82525afee43f0ab1aaaf33cd09cafdea42863b89fb98cbfcf3575bcf746a04d263d09a8171ff5bff782e1053a9b5315c5e996b03b1df63870282e819a54e59f7d6e33c1f8d445895747375279e625a1ed5cd7f3a0f8559e1", "882057d9a2f7118a4bdbe566102d9a37983765973bea9116eb8daa548eca4c1b569300fd8e8e816954a8ca284867d5f1f4f423308dd56bb1761018e0724c86bc6e1364b3a56656027611a60f65608fc507f160168d2a44417436c54c72c359d878803e1b6440d9c9565d34007ba24d00b34a724fa2e2f27957105f78b901a844ae13199abf96709d8ca4453b9060a51d6f5258b5fb2b09fe2ce9bf4fc99cd991c57c73f4669471acc5f02d13cb510c6a58b1ddc1003c3fec2de0dc080aa85166408889c8242e0db32a861c316a79a5b68dcacb165f7610a4c2813188fdbdb5d07e40fd6fba0dad0f64f8f8fa8b348100cc20fa5f63bbc783ed1c2e553e0876979bc8399914c6f23c7b3dd5d61159d5bc4a666e92f11db94fec4ed954a8e4b4937cb14453afc148a131c8da11", .Okay}, + {.Sqr, "-48a6df763e0d9a6b285c4ed95288576f20f2c42bbd19715143f3b589ad34a6ef9cb621f247a11e6c6879b1b30174596abfdd260bd316527eb8f34087eb74bcd22a7715bdddf95202cd428649dc4237acbf9e188f9f78f709bd99d429d43d9b16f2c9a0fd6f13edbb76b8db2beaa7b99669a70252ce3c4e80dfc09e5bb0e2941e4fe4a73781cf0b82c68ac8acfad26aa97cd9efecd2fc", "82fcbb879ce1ebd6501b898f06bc15ca203c446145c7093b20eb17a6b1cfd446ce465e46fe483d51b1c3f5dd59571cba2eaf6309fc4c6fdff87019ede66591602107777bfff674aa7e15989dea2792446fdf49d82e93dd6f0aabf01ae4fd5d5083bff97d0a26f58fecc1191361f9a7edbe3728c5e1e261b7c64e8d952abc3a435cefc8d08d00df2c9d4a3980798d1c4ae9daf3b3929d", "149e4a79134f57398047e6af7a4ef11c9d1c461ebf5966d1baae83ea545f3e8fcbd4cd5098c43250edd1de1f658aa8f32d0e826f75d9b452f33d44a0aec0c1cfa24cc2a6594fd9f45f3db96d49687d66694ecd6c18ca1a05e909a2a6bdbe97bb513b63d5f3ce948841ba710fc995a18c468c5f9d88e4d0fc850e59e18148bc8a29d4ee7fc4652c3de6f3c3f548e2ee18d445610a451afc6e0c2cb6bffe0cb5a727393c8da9a28179d05a246aa269a1969eb6020174f21f1070ddcc4db669e8c29bd3e5bee5744f5f241140f5d654e9d54225af86c82407f853c38453149933a41aec87a0ed26a9a8b0889175ad882ddbca76fd0ccb12ee7b9c3acb3af0bcbd44c329bacf4d4b5e2b3b491f1a43f37c557f204711046081a798e0b8636fb90157fe9114cd4d75dc4036826810", .Okay}, + {.Sqr, "-f760921be163bf54ebede8abff70b3834c7af897cf9df465a8e8cceef5fc4c104e324970fa168deb614e7870a15c52a7c5f96b28eb9ec0eae2dce067f95f77109d9472a6da43149ebfe5ca5f18325720a784e5d85319b0414091de8256c0e60a04f2bd9f331f712a43c15375980f1897984b18bb9ecb5beef1e3eb842ec5da80e33f9d5f4bdb672a43814b2de9f8b8b09e29ba55b192", "2b69d8ede109e6cfcefb653153d2776dbc14d5d295b2249798bc7225fcb2709d2c33124c9c4ad07b29c3b681154e4b24466e701b2c217b725b90b43e94392d400b9ff511fe79e43424ce48f86ec7a44b3d9561583be4a54c77b197b46d37e6bfb859bffee4206319732e78dbc11141328282969332bb696fb96713fc9dfb01aa14f6a5ba2d3083cde1d018ee8ed89700d78834f451a9", "ef0b7e5fb53b562476adbfa05ae4d3cb6961f3e3a4b53a15329e36b8dae187730e025981df9a2547469809e5395fd0f23e553063dd8400e4742be982c8bb9d7cd703546b2fb440e942b8e4d903dbcd7435549b8ee9a33c469d6e81907046cec15db1782032610b60d410ed562caa206e9473e540c2ad849772f2d3391c9d85aced7c5e0722eb3b192873c40367fe8378677e25cb7b2c952140e5e9cfbf152ecea6a436a3a58c7b57c1671715a40cf22bad076481946cc9312843125e403ac15d8762e0701080f85a63027ea86842547c16e41a443b3fce4368f024cb1a0d089f0ae92e13453961155ef76873899451fe24b9e75d7ff74a32b50561bcdddbcb7b2250058b90360b7ff97d13a853fbda0c9c4430a5c2836db9c4efcf004e69dc8ed38abcc50703bb7b8e1f3744", .Okay}, + {.Sqr, "-3679b97a7477fb3b599cd32a72b9075d1084a2be72567abeee1829c56b9bdcb3810a4773b5b7c241716ee5272a0bf44a8009841cf4391bea284e89588196e64c7f354807e0618d051b3d24ea2fb44995276804e6d2dcc3a7d54b95c84384ceabf109f37060695c1233b327765686352941726290efa5d47b63c3e4f59a72ad860f8770387aae5893aab63cd9accd9a8874741b872c9", "68aa6154e9ff5c820a6c50dac2bc1e5008c5bdf0ec3fc83973b9a33d80469a52345e10eaf8cfba1c45194c1c3cefe3ab4365b63deda67870701a63804ea70ecd14e2a2c4f5ae9569bd64165862584c4500b63f8b0adb2017ffbd1035d60e2a865740006fe52edc78f36ad704282fa0ffda47fff44006db53e1ca4676f6c0c4f11aeb818ccbbbcf809b1e46a8cfb82713832c74c76103", "b9794208546ee51285d0f54ea23feefbb1c6cbc14cddb2aaee0d90f6a17e67296279000bb79e30950a2d0c86e173aabab06cb7e16000cd9e710afbe67b81f666c94e9e41f154ece4569ec9fae57c228db2d24fecd01a30ce9660563faf3cf1ee79659718359215d2d0c95f9b58c984cf3beeea231fb1b3c3df0a7f627e7547e096cb02c42b74dd4e5cc274e01d5b6f0aa3e5abbaca648646270b57e32a337b850f4fabdb7bab54449cf8fb18c0596457770965e367c18326506e3e65fb9b7df91b0a28bbc5518a960140422556f7c8bf733fad80868890bafe5b0710f2227c0841a2f626fec4aa08631c438358e7e7f16e625c0172f69e4b3e1434791ba031135046c84c0720f9ab47be30f38ad63eb3caed5624dbffa850fd307faeacfa09667f42d780ed8ad4667a1d1", .Okay}, + {.Sqr, "-bf80beccf5710eb7819fe0b0e61e73a1dd568e39fbb3dac9beba1ddc1269b910de8b3f73fa70b33291038b6e5b6e377cc5cbcd43f8f76df7662ca445ba0f9544a2d02bb9ae81277a30b3783c7549cb465a1fb0ae67fd2ac9e7bcff98469d87ecf80f5592ee3f72df62587973ef7fc96c29e5d96167e9849eee0d1a8917cd5c2d32aef0bdfc1338d9bf7c41c0c29ab9d0e0b53e21b4db", "3fb0e8e3bc33c656d19772d3bbc7d6c1ced2610bc1238d2c419cd0abb7ba65269efd0cc2ade60bc65de0883351064aa60532ed7427eefcd388f018ddef8b928f443da19d629f2f40911c0b7b2e4ea6d78d38c0c1e5e5ce5bca81aed898f15b2a7931591d521c6a010f6a7470df4b2b2e11e1816aacde3388c6869061bd088b7dc377b4929f3ffeaadbc081c71a48a3c99357fc376e6b", "8f415d75316905707447a221cd91477223bb97e3603d81efaf3be974643717de83ebc9023b7a8588298866cbcd2be48ec09714318d2d3f0807d62b12307465dca910eecdbed80d8990e098a3d26ea1964e53996ebf11e7fa62d91f65ea78d01c9e082a5266b35059b888e12928bd98d6226644185c0492e985f8eecc7c92a343e671e6019ffb8e45f6cb89304b050b4751e4bbf7406ffe8c528572209cb8e09ad72b230eac40c9988bf12ab47ac2bdde8b4704ccc0aac128e6dab8a39e2e60377fcbde6cf11cc863ed745e2d40238f31b50e048c1f8b8a8d00c29d3b784a3fceb102bd10a7f01bf88141f51216bbe8015438f936fa1307e13d13201e9a5e30796168205059010576eda41140ba3d5cbc563b4e200e95c55a3ee9e1a2abf6e9fc34b8deb2511d55b8343ab359", .Okay}, + {.Sqr, "248427639d1c8aef838cad0d31d93413ba6d2237745cbb2eda0166f4d2fc792296afac2bb97dab826d702cedf9f16b32b190316c32f85d2d29de2b0c601e6da97e2f207e55d83d0d1c6a310add83d8eb396cde970629668829bf3a63cc461b576137724250d4699092625931703796089c4c5863e133cb95861b7e52da4edbe64fb99a87977ee777ac714639afb4a72f27c4eb49c580", "4517e01c899380be8ee27fd04d202f196993886e7c1642f0f3669d77aa33b9c87bd647d6efc0898daaf25c14cd0fbd4b11f76f76678ca98ef14000614c941a8567a6cd9a9d463a50b2de9c0c731756d30d59757ba7e7c9278652f282b75c89bf6acfa8a8bef88ca4c370d5c2c2498e0c83f1bd8bc22ec38507938071d8745d2c08f3e0f046126f4f3ac39c7f1e9352d826c3df8cf586", "5356f4ca8f98d243ad3aeab3e4ec8fa95812c6865dc3d34886d8c833958b072bf606795269318286bdd980eb6d36056ed53b5e58b0b16730e966bd7d106c9a7c9f66b18059d04aad51368dc6b7ad498a7b9dd773ce938ad617a839b0f2d4057506e08024e1fbd129c8f5e68793ddcb9b65bc022dc49d563ec66145a1295b4d9037d0d2a6fc039c8a440ec00a5b66b3dc06c79a8a21cfd1805b385a8a6b373f8003b809b015a78bad9e2935d34d39bebec3a980760b066d6defce1538306452e80b6bbc2ba184e553686d3a3f725b0198d614f745023b9c172db2fe051d0417b7c8eda82f022a7e4302c8c8fdc0a5a0aad38cc199acaf7e73a16f0862a2508603009625e6beeaef6b74a791f2e7f3230b25d4e248094ceaac1d7bbd2dbbf2f083a38f7ed2063f1db3b5e4000", .Okay}, + {.Sqr, "484fd65cd325d938fbed6eb291f145d8d7b3761be2b524e3cfaba3512dccafb9425faace0c36a700e67cb1c81e612729f30ed8f1fe144e6acd61ae02c71eb7aafce0614ce00d9379039449dbf3ad8d2d7468f0c93a56f3e106377756870aec84c037279cbb2fcb32e564c9ce8d1ab86c6a12d954563ad8a1b16a6fe2e2ade5d4d8c6f4e0c816e4f4d7f5b24b3f5092c67ee1350ed81a", "4a2528ca87bcae102f48d3e6039ad1a9df4a7fe39ed24b2eb041dd51eae4ddb9094d39035fbe23d4157952899adc8bcffb177d95fc7f04072eff0d8e8479ad29680871f380ada533ff39ab79be32f346dfbd6bf5e6b6efc2134173cccd2391615928fcc7050279fdf66b845c69f3a935b2c356d10afb968d011f9b969dc40d3eada367c2a1a34d095181087db3e2948e1fa1033f6715", "146d017a378eee37d767daa13e1bc56f6d0355627e16f86a97072bc4ef2f09a407ba04df07f7f0a97b6df6eb89715b88d26c234b334344214392116c105847cc9b6ebd2e689deef5146e278e016a794fed820e73e9e9f9570a284b04f97f9f5236d4ab364cc1f294339c55b6a7eee38f6cc2151290e27b1f7900f08d6ff4dc761c0a863d2fc7f41e0f6c5643e301ee0707ded19e39770f4c9097e55cccfa54258827c0abd2beb582275bc17ebf263a5f17bcb201f98ed179c860d150fbc06b4b008748113156f4e8c64067cf8b3d3c1317a76495f0284de38202f159d505a40055f19c9b4e138da7498dc4f0f2cf2093dbf34ad133eeecb7db22d6de9024c6c02913faf336988a0410a492511f2e3951b963422ba1e79d0f9f8d463a075c307aa2a5540cdc089c0b1d43e2a4", .Okay}, + {.Sqr, "485f1f180ac4d560e0ef1b0336322b0764ff4a4659d6b2948ac81e77dbceb3cf9025f7c586c42a1231d29b5c02a66c7b2f49c2639cdb75470b200d18f51446f2bce7b4ba3dc0ab9ae45ba4d099fcff122c480f5a191f7c15c5e57550ef800d3b0d8eda9efff10d4b6d6dfdc92b0b10aad2913aaae743eff6110539bab328b538521e8d39c65f6578cec6a891c724f6fd89e3c1e48ce9", "2db5514cbbaeffa1137a049d1a676e4eda462d64fe8de7ed78448224ea08db4df0385c81a0314b14f9a1eeba40fd09c609ee311fd782da07ca313ac1edc5c7ec6c9374c1aeb4aee7a530bfe898b72b416652b504bcb5bf806be386070898a167c6cb3af108206409552f5a3b683d1effd53a085520d21b24cd8c618942fbfda8c1d6cc0950125a547be21929bd18f54fc57090166279", "1475a4d59dad8afa8d76e14ef003c05f61323c7920bc3f84e9e7403632f2189e8400052f2ea4840a901fe22dfa2b438a9e5fd213dcd8e7d6f2606807eed3a3596a3df4866e8366db10d9fd9b756a646ff9068ece0808244535505737eada78d9159f390db63bab1ec7cf74f6409d3cc301f605b2cd18191a5655ffb13176b64e3bddf26920c3e878ab394f869d0ddb0780b31dc028a87df4aa5d16b1089e401a123914d986205ba626d9d8e805621606b7e457b636a6af7b520c4acffdcf1bbdf46ea863add1989047640d55f646f9abf7738fdefad29387ae3b5f19a13055b50596c55080cfca1789a840f161e9496586209cd7f5644bc86976e5d17804aaf669268aff7238c5f43b2497c1e1df77bcb1afbf3472cbdc23a8f204436939b1e0da61ec3e5d87afb89e97ac11", .Okay}, + {.Sqr, "-b624e3592cc6124faef08b74e27c847430446b0c4d50a2934000156ee36d5ffcbfd766428735d5855edef437967382e4d16a24cd21071146a9c99f293b3a3ef6e14217caadd39d0f418d5ef82ad4878c8f50b9fe9b15d680fcdef02bef76b6a09f97cd406935d6ec5fb0c224b7653f2d0a5dc01224d61fc2b21dbf82a87a9e201d963907030a0b0805b3596eb2411486683b143000d8", "549ea14d7b7db77c281d8f93329d1b2fe37a5790668f433b8988463a7fa639175ab1c8fbacb674c521890978ba8dfdad6a32f15c2c0eecf2edacaef61e987d87a85be9eeb695c9362ba1af0744c56ed416b223eef540e99cc7ad04c8db64f08577d6e6984d181316eccc4162d65ac0750401d06d82f813103f758ffaa68b73543a01f0ae6f368382081abaa562ef8a0dfd89eef8bc26", "8198789386a57e35e12df5235e2f99b7ed108991499cfb7aa2353768b5c3a625a58d79413b1a1f865373f6fdf639943cdfcc217076c063e7e18015f61be6ff11fa1b070b9b2f55c019ca818414a07c8a27793add01a1f4cda9183d72516b23578eea05c77a7735f275c770c266015a5b166f0091092e33561cb27e0cb7293a0be0bfb2b1afcfa67be6bcaed5b99407323212aeeed201e151b3182f636ee58c7f1bcfdba25426e54d3260f80c43bf9f1fd6046451e9220b62868aca1831aa70845a2460d2630677f91aea8d2bc46b04cf7bb9c414526d08040ae597acb3929474d638383571973b0faf91c869efcaa396b182293fe2411ec8922e594d4b5fe60ad969f748a089373d164e9a52eb0ac936fb98296f6072be31675c3e6bb650b4d46e9d7e1bf2876cb21100b640", .Okay}, + {.Sqr, "-85f0f0778bc2a1c9c9e2ba934d41e88340c7ff3e0cbd5ac62c3937e6e60861a87283bb600fe13a51aef5644443cf88b902680f6842124041a34394936dc8eefb287d8d5dbd51487ce6a3a2fcb2ab9b65380a25e4927fca2fafcff9e0ebe433c6c4ac448a983cd0ef8abd920eb526ca8d17f8c9fabe8d2d6c39ea880270e4cda901670f5245ff477ac777dbffd595bcbc1dcd55bab1fa", "7c01d980d504da703938ac89a465caea4b7ac2c253383a882b034f1513f514137cc64f2c99c4a8d56804b4b58599bc6939e91f250448694c831f56e5f0eb1f11e0dcd2c7de849d9aba2df9ab2691337bed127a92c200ba0a889d61369dd5190e21db586188b22ab5a4eb2450903555e53be422c3d8b52c09abac53d1fb738f7d62fbec2e18de2237955f6deadff5d49a989f610b14a9", "46143c9ff93ea6eb30b9d2c86e669e364fb8485ab0b42354bf19093210d065dea53d0191eacd1f1c48c2184aaf909d58f219391f77b19a8b3b32690ee7933976133110c749539c77b46c60baee1e8770fcffbf74c0d5dc0f44258fbe3ebb908f12940236f94ec0a89619186913c917213d707a6b28c042e5ef56e686e04cd6e946223bc2b3f9a4e52d06c3f25137addde8d7cd8cde51f4563f7fe73de0af0734dec6054c591be52c83ae3a530e76bc71a8c6242fe499e2392851abf8accbdf7c3ab92e86f133b4e2ec91a2e910ae15477ca857c34408e38212f6383cd23dc8f301fee7e1217f61c090f0cafd7c49fbb60f119c395b6a4da458be1f545dcdfb641d8accc971c6060aae26c2a5ad1ae5b5cabde143047d56785bede64b3a01908c22817abf4d3930bb1f03a824", .Okay}, + {.Log, "362e8cce31ebcf0b92e69c330db066a38cd732999b0b8dcfda9a99c921e37742d1b241c5465d275686f719dcd9c83cdd0a5da6b7520eb86a30dc0cd44f4d19ff9e831187b84a30bcb14eb2ab0be7053d14d8b054b0e58faa761a6cf7c45fd7d3c7985d6435630dac305ca7ee7861ba925c83e6d8560b9dec49cffe8d8aa1494032add64d8a27e040be301f9eb3b2a18b18910bf2f073", "d911edc60028fbd", "14", .Okay}, + {.Log, "2c8cc523fb2f5738ef6d7804c41dd6c131c043b15f2cbc084a8217a9af4c29b0ad69833733c9f90482ed4d31ce2df90f1e0eb2cd396d921c7ec82728cdb2215661f536f54b7761e684d6ed7d0aa79b1d9367a8a08cdd397674e5cc5d943f701ba89dea3536b37e7f8ff27d0e28e7371fac5d8ce03fa0bd3527fa8955bbe4f6aa7bbfcbb63d83c63c28eafecbc1b25343958a315e76d9", "123a8eaa9f84538", "15", .Okay}, + {.Log, "affa59b596323e1a3bfa3f18eb6dbdbf1dd3a89e0a77dab81ed390e86da329ab91582a07955b0f882ddf10ac59e116c60ae9a9eda1c2c2693b82cdb9c3dbe4a8f37a7f3e43d838f503f653bbabccf7006957b7d18c79a712075352426735c9a927ea89f6cba016a92bc05a4e8dcb7f57b241a3e6e23b38dfe0b999fed37da9da56adf8c740281a05d7d41f25b3e5e005bc6093882b36", "ee95780f1cdad96", "14", .Okay}, + {.Log, "4fc95d596e7b4979e7b4e5af98c9bf95e3a05322d36c6c6005ef6b0b08538f4ab9f3754f71de963f4ae481cebc5eefc824dbdb63b81d7d9ba723f876dcd495cfebf90825c2122cbb6519e513e3eda1a7c88bf672f3ed00534f9ff25131e8cc139081d3169a05f9acd6015463042558e3a49e635d579b2703096e0b1830a3344125ad6149964770d07c4de25929ef6e6f18ad2770df4c", "28384cabd2604d6", "14", .Okay}, + {.Log, "c6c398dd333b8ade80b6f2de0644b798a1d1d88467aa88f788544e8509c12f8a8e1ed39d059ba3757e8339bb538d5e40dec6b8447ef3b6aa90295e415245cde2a411d638eb480fd06195e8f4f73993b50bbe2ea04f326e698f366f1fb38631c1111701f660cff86db4050bdd4091eba7f724777aba294d145df53ac129c739520187ef295626cd173f2640f0dd86360811c3514097aa", "fd0f7f44f350557", "13", .Okay}, + {.Log, "ddacff76d522227e1370e0d850a24fcc015350e42100effc8e5ad0e6d6fc18652eed3b5d69dfac14cd627fbf051f438e51d7006fbfa08e0b72d06edc28bfc1575e89486dffc8858494fe24195e471f97709f30c9be7a6c83e5a67ea2770dd9666312f62b6bb115bb3b0e8e74839055beba60f2fa21ba9b1a2eb9597838b6e46eaca0ee404373ab0045f361d6ac093cf0ed843506b369", "c480c460682aaec", "14", .Okay}, + {.Log, "7f96274d6d68095da832036cdb7ea69b493ed21a8193fa7879984d0282152bc162af01fcfde995a38b50b53f607c612081938df510a7fba5f2f2432bec0008598e48655248f8e9606c2af8632093ea4c89ecc830a142127ff5320d89d115e8aef3f0f4bee312c4bd2c867435aa36bd4def544f4f46db4c8215c0ec2f734c617702b78ee10415c2df03c4ee6bb7f1c49b149fd121c15b", "768a337250e7310", "14", .Okay}, + {.Log, "4f4238d8abab35218031fb7c3860399c4dfe2ffdca1d201c869f2e614ea62a2c7fc94e4c17e0e76f1521ffe5fe51ab36211b98d9966c3e5a4a9f0de13dec925a238a43e766f5c56d947d8d65c5959881059c6021aac3e20fe1c61b7ef25b9d29b66507df92001e523f1b4b3c2447106cb0aa7baf54abad58bb4549fbef6344880aaf8a91e1ae9ceae056fd142e2dc4435df86148ef49", "89aab7890312729", "14", .Okay}, + {.Log, "6fa87cf2af8a85592ec271dc73163764c8a777320e2c4f09e0b3ade6d1ee1886300fab8083c0e2d18032b32bfc4f20a0deed99f58b0160272a01bbd60507f0d7c8dcfd801274c0f9113a58dbbc572063d32ff4380962515ea79c7043345f1a579f13f319b130cf12e4fe01283942321ee97b7c2d3e743395e3e5b531b4d5daa6580bda094114c876b02d98301da8ca8654c082cf2eca", "7b4b533c89b4a26", "14", .Okay}, + {.Log, "5371fdbd51d95020da167fa9d4efae24792328bd8ea7c0624fcc59e89bcd3bcb44361ca87f3f7c4e4cda1c16647ff92c9590abdc4edefb43990040d2eb9d7cb3374a69ae2d002ec5cb2bafcd088a4faa71f805903a7fe29d43c119aad7a33276cfc32eef9333bc595c7e890cc345a6ec59fb0299ee21f4fbe3a20ac76d89927415556dd54e6ced21a1c8481bee79b3a741f5bbb63a33", "1226c4979224512", "15", .Okay}, + {.Log, "8bea45f6988146925b49861fb4fea66c012a0ecd023b4fe998e906542e0437172a2b29119819223f91a1505d20351bb76eb0cf35780f4a9d5c533f6e671934c43e92c5b366953d8848f0c37e5ea4a9d362fd045a4e023afbd199c67eea7322d673038de80763f8b2e3b5e05c38b228c4ee5b83c55f463a3b01ce8f19ec66dd5ca1f1eac337b2be4f2bdd34bd95dd88d29a07856ee9b8", "dcedc272e55af60", "14", .Okay}, + {.Log, "8116de1ae69f519fe45e6fbfe69b3c59d4148cb2250ddcae8dcce411fd4cd5ca706a6dcf9175240dc303eb48e3b251638de3aee5fee2d30f75983c761799f7d641e36ad7b7fb3e488c5a5362d0b16ae7a37ad6203362b8bd7678ac647c60863e0f22b91d91989f3e8ab0756768e9234a525b6ee23e30cc49719fbe95264f53f5fd521823fef33bb35741a4951af732493009cfc1ec62", "5c309576349210", "15", .Okay}, + {.Log, "a481db0c826a23935022e7bc85acbc4745af3302dc551b7cebde5d155fb86dd3e8c57e506b2b42ae50ab208b90268359ef9ee97a4bbb37a8feba2e39334d7cd1b482a30301665fc2b50881ce776ae7b10a6766ee867c3b401b1533abbbd64ea689aedbe5357c1701b0c875ef8904da179373783f3d627c3b806908fc7cb455fe6a6205bda6f5616331fb748e2aafb9e912136eac5635", "8849843b311ea76", "14", .Okay}, + {.Log, "6d91ab7ba85e51f56ed4b5154fcfb419fe0135c736305f11b86568f0b9887d56ca26ee5b14438cb137030f6d085acca567c79a390495d39dc1baad8d153eb5888fe877f4aefa732d36d023d0d6524a1c0a6e510612a9958a8e0e488bb2a2e49511d12b90589893247e11fe355a3ca3f843d538e82c13500e6889739277b40d5b629c44dde2f239dbe018f586949624129a4603501f5c", "5d66c3566b4c15c", "14", .Okay}, + {.Log, "443bc23cb557718d9128854e8fd65bcccc7515a54388f7bebe5d6cf3b02bcf6b9be5aab53f681d5f78ae717c572739c847750b512617654667ebdcc3b5ff52cabc7370531e6bd6c411ae33ff71fe3381d5d3059acb447a227a708672f2fce59bc9c682cd96e7b891d5fad08d77c1ebd4b54fd9d48fdec22b8cf6ef95204ab214e730f727567c76f328b767566ca6d63dd9ce501db43c", "c43e11283381a28", "14", .Okay}, + {.Log, "d49ebbe08d95a1ea0fbbeca5359b084b92e737e880ad005f2d5b58d1057f93aded785ebb639101aa77ca0bff68b9792242d8f037e78bcdd2d988d1d563522d74470a2c47e0a0bdaa47d847dafcb8dd77431b157e587cd3299e9704c350520b80d1136af24c267fef7eaf7587551dcc1260424532fe5c2ffe286ffc99ea455c2a2cf1317aac0d3124547b4fe289bdfec84eeba10420b3", "f3852f0dd5e81e4", "14", .Okay}, + {.Log, "7372e45d8218688d70d5d40bd10fdd145cae21652b9f68bfe107d452d2bea769310d117127bb9630705454291191ab11a18207d70502a43926f8c4d1b522c9958b4e540f7d82686e7eff8855e76c7112f8c0bc19c7252eed9fe6beefe17a1d93c9f9322735e520cdc9709a8535ef6962cf32cc2737c32fb89ccd3ab2c283e05634a7dfd42688083d0cb2744609bb7d38381ebe32ead7", "fd4308a9a1965a1", "13", .Okay}, + {.Log, "6b228652f5dc8db119c97889f3c01b02ea27fb5792b70d3ce2acf3f3133744998e1f9d88eb85dfb8dbcd0dc79bff38d99509901aaaeb813fc02da9c3a42f2b0b15561c3680943f6087f623b64fd255af69ffb74b5f41746bc93db69034f395a2e098ee4c558b2a88821a64a711d4d404d173297508dbac00d070872172a4f7145704223cce2c28c870950db2849756e4b4618c65089c", "371107fc6497cbe", "14", .Okay}, + {.Log, "82112120324a6f848ab3542439392a95817176385362116ad178c9a528e30768866c74ecaa6230c1b4d5c557ef66e5939064d97b588b2e4310f87ea7050984f8af94c795aa1af2ebd75665ea2469961f6aea80eafbb80a76672e3f847cd425f227a57465423004417a3f5e9bf979d7c2b019c628bd7862166c487411a3996ed633b6371c9e75c69ae8e978bfa568d1491bbe962af781", "a1bfa3163b3a13d", "14", .Okay}, + {.Log, "59e34de2b7312d5a5fd1ca72c00e4f4e2c8abc50ce4c1cc41643614f53dc18f180a6b7ef58ce604af4500c0c55e42902b3d23068f173fcacdd9d4fc7ba44f4740d115e918a0d3d08dd62ef867da6758982d56f5e10b0eb7fbc900d50bce928f545ee03b98a0e3634db3b2200bebf17bf8e6b9b595efa0cc8592b8825bc9025e06a8c7551aeb4888fdad5b52524490f642683537a0186", "26f58159e496778", "14", .Okay}, + {.Log, "bea2397236a4ce2c397e83892fee75b4cc5c10ce14e9c919c67fdeba13f7f56d5702d2e2d66b2378a0b4b5a992c574acefb51c79de9473c990aeb8f5dcc60d9438670533c60a7e69e47b7bcae896b5e8f970ef78ba7315999b44e43aa366896daad8c6cdabe74782650f0b2d091f047c280257cfe90a475b0d0f29df89a58ac9c113f2916e00141bbabfa6c026347cc42404de815ee9", "af398d29553801c", "14", .Okay}, + {.Log, "7d893e38959cda15ecfb4ec0e975f504794f60bb5585ce18e9d172123feb965113382d03d3322e276806843c4aa94f470f6ec63e1f03149163fa59cc5b7774dda38fdb8726f853f9db76de31ac3ff29eddaed72514a62488fa9b247cab2df688043336dbbdc8c5a8f6c3bcb903a58bf8c0d2813e09cc1b7805ef81e803578be045b617960b1267b92a44df940ace8eaae009eedd997c", "e6f0990527fbcd0", "14", .Okay}, + {.Log, "a791a94a3dc869327d76c2695cb6178de97f2deefdc99f3f2c876b0696c01c6f428223993c53236018f685d4bab1c74e460108a154a886b7cb9bf87771d2a5b15224e5e1346c8f9ffe17f141aa93971bdc4206457e063630b40b557273106247fcceccac393132d11b34d5539ef87008d44babb9f74a422e5d4df2ad9cc79740c341a0d19e83b8453bd915676ed2f96207e6ba1d93fd", "479c58e2c723a4", "16", .Okay}, + {.Log, "94cd2f0225136aceb9ee05a16fa224f9f6e8729794a4486def97239a31ba8000625f3e9fa165a5d6415c514994916929cbb63cb6e55c0e0f0eeca935b24900ab209f4dc5c6b49f48b9d10f629452a3dbe97e48866247ff4650030e5e3eb718ef657c4722fb5ac6b0a08917e08679bad633606bdb18f2ada3ceef5e0ecfdce42964a7dee7e1bab922f4ffb85d08c05cd0514d89059812", "b1426f4562716e5", "14", .Okay}, + {.Log, "1f5b3cba20f74a081a8d59e7100fa476bba1b951bde5f710ed5c1a5edb028ad724361d22be1a0895980c05e2fdf9052c5192739a6c159c86b3f7660cd8a2f65c359e1644a68e9ea10a9fe8eda157cf6f6df5a65339e3659b4a9d2f3a1c3f8a6679443bbd1530de7172e36373a195f284af466e6e80108522a06c48f23d3ea4c05f35363921cb11b41e58a80f8950bc427ce9095691b", "aec0d4073ef1d42", "14", .Okay}, + {.Log, "f5ac3399d2eec09724db2c19eedd12393abae23032e4aaa03e2e8744ad46d605ee2c4679558d2c76191ea04a396a95fa54469b56658fe42753d025f210fe9c8bf77957ddbdae45cdf9332c0f36fb4933f75d8a44072b0c94573ff2c1bdc2bcaeef8ec55de63e3e8e2b66788fc15cf2abc8bc12383db1df66e8921c316a8da6862812106715bb58a31a6c781997efa78b2229e77d2edd", "3c8836fb10be129", "14", .Okay}, + {.Log, "77b35a7e6238f542a32de2305b9db77fde667bca9d514ca8a7e3f52ab201d9923f128b81cf9b0c17d37167b1b2a8a096ad572c820dec7e74497a58da0dd5bf7937361bf1d4e62627c03162c7afd1c53f1807a27a9385d049390c72e2bda4ab7e6f663b427d0cb5dbf288c2077af8f2b5b13b46fe233b3f515264e6c21f3d7568ad72e400e11c824bf657b5d2fa940230737c2fd041f9", "f23fa09283c2219", "14", .Okay}, + {.Log, "6e074bd0fdd7000f9244c7a84377894eaecf08e87b4dd195af10e32dd1e9170597036e5b59f2c95cf2b83bb1c143f42a57793941f8135ad726557fac3daab3c016366661e2683c33a5fba8cd0aa8805e0c2f6f1d10bdc6b69a61de0976b74ddc9cebe279ea972dd9547de54771791a9c7ee308c7807c314a0dc627836ba062da28d7a672125b9fed373cf2dcfb6330e150aa864c598b", "c76b83a80040378", "14", .Okay}, + {.Log, "2f215de75baed70506781bff76033a1b5d8dc0415c2395ec0dcce6fdb76d18df4ec9dd0281426c3571bf9d647180ef4789459bb8149b595f33d1e946767851dd6dc60f17f18161abb2f5f8e6086d4f14a71eee31be4686b69d5450e565f5b7f7512af2de208bcd5bb8287fe687e36875d9d3c04f01be8bce892deb03c4c6e6ccd4e7ad5f782af44cd0e12778138d5bccfa50890f1ce3", "4e32b3f91b554c4", "14", .Okay}, + {.Log, "517b0c89f9c6fe1b3bfb560059e711441bfef41558f2069310077e381a7ba36d7421f0c667fb42591ef7a30591b5de902815b9c5d8e54c91ab42b06ac3b84b22b5d70307bccbe4aabbe0b136317928cb4dd4e39058bd5df0a0f102844fee4d75ccb797e4b3e10d01e957c8cd69dc4c17c38343341d949c263728f5e68e7979a39e462ef52bb6c84e7226ac2cff47c2cb453cc0eefeb4", "3983bda3e7c2df7", "14", .Okay}, + {.Log, "b504682cadd27e5d54d54f6feba0c6efceb0fb977e459487db9f4ed80460b80ab38896a2fc4317eaf52075bc0c87f9dde5d61f2224cd756ffc5945a36926ba8eb1043fa4daead29dfdea76966470a7129fd150d33d9a57630f3e38ed65f173f30af52fb6090d0f1a37ac0ec316c9f19a0f5d361286361df7ee3bef207dc88b365681baebc727b76a9ab594c80f49ad73a39d6cb87808", "fc95736693cf14c", "13", .Okay}, + {.Log, "a6e5cd05a734e887d48803a8da2041ff41b229142b29558a5fa73f76cd3f42bb3498feca67f34a7b4b4569554a22fc91748112b88d16a26013d04821d19850d09b8bd6f126b51cc7d4f5b584e88c1c8dfb2e455687d85fc0f97dc39ef6bb7c3f1fe50ed7c7ff3bd616d629895e774142caf2c6abf888e822214263fe935dbce415cdce87f435e3943e585343d0447f0a62310e544348", "97ebe32436f4de8", "14", .Okay}, + {.Log, "138a27cc0a0b48af26f7f8f1681ec927cb9b97d989b0144edd8283bb61e178ecd31fdd4ec019791fd6da83f12286e458c2a5e96f504ee73facb2c1aeab84b669a18a605ff4a6ce1db1cd4e763b13f3084597be5e63e7651fa03c0fc9e58206e70e36df0845094308830a0d8914c02152233f3f9cb12d90e71f76d07c52d363ab7ac7739d22b379cdc124dd726e950103f24f71a475ac", "c6616f50c45a94e", "14", .Okay}, + {.Log, "df4550b359e8abbb89885341583a21e5a8a297111f7b59e26474ba1138d2d4fa38961755185dc38efcbc162c5ee63bca064a0ae4a1c1bba59e81272edc88c720a59fef19f43c7328c3d1cfb1328b231e35602f00899f78713113feab2195a9d7df704fd437c29742ecaf61f72d6dbd69bbbedee44278bb1f01d3f79e565bb7057aaec3fc0e0d949875a9e57fb47174139b45ce765728", "f3caf8a66583e96", "14", .Okay}, + {.Log, "18f0c4fbca4f33b322f83eb8f5a5b5cc72248fba512638d4ff5eec3ba65b64fc2548f8e4e8c783c80d1281bc9c0a811178f2f317caabe68d5b304bd2ee3666f18b2353f938bf77efe014b7d20f42c83eb9a87a7b602bc39f77be3200c5df5d23d0df84ea964a9f035a8f16093b85afad1106ec8a5a4cc43d8d793245ad69033c7008357c2d74f6cccb8945365d2ad277a2207e8236eb", "c5fee97da0c6ee4", "14", .Okay}, + {.Log, "a208e433fe7913dd07ff925bd057993276049ca56cf57244b04d3df3600f5fc95fe070486174e5f93050dd361038085bdddfe2025345b14f6e964678f8c3efe60545272f3561e12c448812a37f30ac55832e97707f958ade478912470b77ea17149cddecea4414625d4038b8c8e4db915992f3e9e9ac4c0f6373cc834cee5c5e50d3e5b4024331158c78c369f6a000c7fa120d50da6", "d57f26f6c2a30e7", "14", .Okay}, + {.Log, "885237a8372b1be40500e2f980ceaab295852630a4b48f53593099295f2e2484a7e13781d8ff324473b55561613a4d262b6176a7a015aef493817f2276145a3eec0fd20e2e64524b0b6fe3956d9f5bf68f767dcb1175c304879cf4332b8f1e9f9bd64d3076bfaef6e1dd08ac54f0e321c08926399cbdca54f829d9f8c9753b84be98ba91316157d943d5be3c03b1425161d77bd22552", "1cb320fd1659418", "15", .Okay}, + {.Log, "4721724b9818a8da9ae45263cf0f58c5fe57327ad2fea0f3ba76a27d958c8245617ad1d72980b6454053e80992c7de88a05909cc15da0924fda55bac7a47481b1e387d80986c06d25f1cd39bc14a3ba227ad44cbcd1db23ab77c1ff3483b5a90bcd8d3c350921123a81abea669a1d8ecc71e06577e36834dcd58553b422840259122776d9037bfef77a87ead7ae107f7c62ac706e17", "dd4efeb3db66961", "13", .Okay}, + {.Log, "dde2a2c0d5c69b862354cbbccaaf43c30c8378a8150a3c39ed539647fa47fe7deac846a06d9501de0b9ca3c442535eaf44583472f9715e6ec2b5f39bd1c15fee375f28bee76fed41f6c74f3b19d1ac8d3e69aff045064f28a290b227639a0cff3f53cd7e6a20eacb24e55914a5221b73ed4a5b9aa73b8a60625acff1c0e29f4857f1f735664a0b5b39151841d5ce2560471feed73b65", "dd9b8c7e2aca240", "14", .Okay}, + {.Log, "812d4ee1f782dcbe38d18920cf8d50a6417be44ffe59cb015cd09708a9587286db79bbf67e440b425097f7eea5c8a69de5052ed510a473b363d568982e1612aae26030e8efd4b7fd914ad9a3ccca7bf3957c6f738938c4349ec94f8a6ba92104ebb808ddbd104696a9bb9762cd106f8d9bc84c500e2fb0998016125071d763e31a9679081e1dc0bd4c65b48ef21fe90e16cc70240fe8", "9dd4cbe49400502", "14", .Okay}, + {.Log, "6ca55b0676e69f12a16b112a10e4b3eee5249a2d1764348e297e806deb9028cb512945d2a35174cd5fb19db4c601efce99e6f5d46299684bec2b7d39fe7d2b7a6da5ca962c326c590955216b08599c274bdee5f354f3a08c0fe78022868438ceaa6e38506d8b1cbda021dcb0c91df44cd7dd3d0b368332f97b6610055616ae9fc0910b4d8478989ce5eab5d3bf0c182f080be4d51c34", "9730a826bb74fa4", "14", .Okay}, + {.Log, "5d1a39dbbf44f47622de5fb42b3a965421307bdfd10492d12acc797bd7414a5b6f55a09a4b4ff8d38a8d6e96e70da7fb005298e8bf7eac42205a6dc19bdd678ad769e78460b7ad8b323ed50def8dc37976d337bbae886bacc40383ebcc07697828575a2ea72d1a941af86479e7ab88cdcc876d7a58b09fff14006859d82956cac73e1ae86ba382e1c24a0257816200987fcf5f728a4b", "89573134d14918d", "14", .Okay}, + {.Log, "b20f7a4d032d98b69adf63f0ea87c343d1b971ff5980cd64db7b9481ddec80335547b9c6cc869f200bb5ab6974f819c460fce845ffcc817dfd676cd35484a016753ca4ec8b812816c0d57601b831b5869e8b3f6d9ac7fa1b32ab325ba298d0036c7f21a996502c99736f2aca8567572ca361a4f6c3668a810ff8b6d3bacb6fc75534d98ff1a87c3b5d8a8478e476e35f1d0695e0b75d", "1edcfd8f587746a", "15", .Okay}, + {.Log, "38c597cce212a3c488fa4071b15c963be80d3193c2c6bf199a2e857035b6731b0e491f1dbd937102bd84b844a9b719cdc0d7d487ee7c4f8451e28346cdfc037810e27580ba7c0bb4b5280e590a6946763fe00d7ad66b93eb6be094d63798b38b39ff88a8ec7c971067faac9ef2ea161e636904aa655b03e5d167df8d77ebb307acd7cea37e818b73370dd319f08ba00386dee5be12af", "9c22e1d25840ec", "15", .Okay}, + {.Log, "b1e3029f05149dff18a91afeca82a8e8aef0b04673dd33ce229ce3984f3254ebc5340a79aea12619bbd3bd8fb217b3c05550e70efcc1e6727015f1867a8b1c46df99f109725a9cc9b69c62c3364578b00c9ee7975e41355cc66a6b7cc9d81afd46feede746e4161302747a0e648e7053720588a68541d68aae07fca8615c0cf738e15d5fe4b9776290948e13f2b6cd605629d5e956f9", "7a78ed230a70cf1", "14", .Okay}, + {.Log, "4e5975c3bfd94570be54976951e42769070e9e4e8d6511e6c74c7e6c4fcc943130aafd4ec14f761cb1081b9ae7365f721383a2ac0b5d617af3ebf5aa288c52d0533b8ea097c6debd3b1028f2310134b4fda929db3219a2b494c615e82caa27b4e2e58c5d46883c30b7926d274a97988e90ebc92b1ccb524c337a38cef1a191c5b134a6e6e97785b5ffeef2ab49261c98ca6ca5d08b16", "fbc6db6c4aefce2", "13", .Okay}, + {.Log, "f37a53eee2f146ded13b82c8dc44eb1879e19a5b46f8e30ac50018f5b6030253bf6a2549496829e3614f9cebe4c66679d948bf0fdaecc6f676cf13eb2def35f5edbde6e685c71774731945226a52b8e8e3141ea7d9e67a795600b349e3b530cecb4745fae119e7b2bb86b9135a7d024ec830df5f24ebdcbe836bb6ff80cdc356fe6b7ff3925b2a838b55859a650a0304719a14e50648", "d4caef323ce862c", "14", .Okay}, + {.Log, "8f3955ccfbc06d19d5c2e77e42d426c02fcd2d106b57e83b1ba5d8e838087227ddbbe38c20216d632ec0aa2a6d27f7cad3a2f5329044ae2fc12a69103bda8688e6491179f333c443b789c52458b3a37ec5ee77c7e05a071e983821164840a15ec52382056ec956787947042de5c3117486c4ae8b987697674c5f0a36b5d4993b7b0b9c27fc68b8a02087e77b96c8f3bb55a36cb16673", "e5c8c83167f4ab5", "14", .Okay}, + {.Log, "24c7a961c1dbfb6f922458526b4a5f832ce4d7d397cc4ef30a7d23c6e8addead3db7d81ec47823d3630a14ff1b1090afe9beeaa4840cb187995f18a230cb62e2c50d5fbe884818a47da25c56b413101de325a521bc970740e0e76fbc6f17ce216f93daaeb6c4ecdf0ee58005264cf1f828ca2d3217a6380075383e6c12c554241c0e2d769c1c9bb46f2aa0e8a842cb7b94a1a42e8803", "e854fc9785e26a4", "13", .Okay}, + {.Log, "3e3673afb47a1a09ce6ac3d7d4ed7cb9f5d02c019ef369fdc9e3001edb265231195c0fc28e69a8d6ef67a1da5db2ead08fadc08e23cc21f982fedf4f1a3282befb3c48e9a167c7f0c220700c2a069b7fca14da6b00461355f0e72723a138f52aa82e786c8a20da2c7239dfd5b3aa63c2fd3b0d9017df9452b21e1652464b1051d468a70701126ed0450ce6e35e27de9b42017abbb5d6", "f96be9c486be355", "13", .Okay}, + {.Log, "b76c67c91866a36a85f2284b3e3c294dda5838926da4ce3f737a3529985f11f4f2c957a81271097ea691d93abca443001a972eb4cb00cb0f34d9c703519d9b2b68ea1abe76711c94f4482df0d32ad368a6e9393983accf599a28a4ddde14f5ec099437fba021b73816c0410da173a41e2eddde74ee22e0d7794b40758809a4028cd71842690788197ec3ba5cd2917056c77d4671bfbc", "df205bd268f0fa6", "14", .Okay}, + {.Log, "bfcd544727ce86345b337a59cf481e83182f183334fe998cabea8b1c854bc346e78a2a34ad7a75e54914001dea4a0f64b86b9295b200a72a5fb5147cfa522db61610b2aecee3dbaa8a4e6d1542cf60ab522e1062760179aea41ae8262fbf9e2eabc2eac8f0879138de3fdee23339da404d91ee5567455f2a52650257fdd44e76ae2ec315137dab048e307a5e6bbb5f4b6e0938bf33d6", "5df433007442e8a", "14", .Okay}, + {.Log, "f1c6df76ed43cb2638ab38af5dd916e754c24ae247f0a6447e8a7d7a8fa31f2701be9b450204445eb62fb4293bc82af7e09c6a47e8d057ebd487bd13ef5bb9e72dae916e499147a58685bba9fb34e3ccedcf01ec54f5c50a5464fe9bc1cac7bea29c5eae8ff99e069a5f9f9e38c29fff4ed644296a8b43cd970ac9f29a255e8f0f81b5d65e71c1eadb33a4de3db652dcec794274b7ca", "5de9c3a8211de40", "14", .Okay}, + {.Log, "7b55a6f2c6c46fa49f79bd95aa3f9cd0d9a4b1cbcb68b088410a4268e427275e579a389b4660cf7e16764d8f8ece2ae38f987ea7ef69d7e4139bd7cd32272a3919e44db8c07eb68b291650908c453247c73d919cc173836f99fef2d9f9e120489a42c5217978d5012b9341b269ea6794ec395077ab183f6a411b75a6e60707d215c44f1235f1fe398cbeddaf0632d475e74641548bf4", "7bade112d557529", "14", .Okay}, + {.Log, "3a7ccc635e5dbfa85ad3e27bb531b2d903db5055ff566b695edcbd818ade627ddac089f670422c766e92d4aea04cf0088e28e24a8de633cf00b99092bf4390db69e9561d99261f8ba26c68bbaf04d5fb1dae6ccfe066fceedb54b7df1675e93b0cdf9922b2f198bca8e19f4051173f6eb68fe93cddd8305a2135c5aa1ae508815b8088f5d3d4b829e2101c7c069d3906066090772f0a", "b7a08edb3912936", "14", .Okay}, + {.Log, "58c89f1ae532ec845e9d5b5c0beabd1b6c3132f7a6517fe925f82bf32c9021419d1b931583ec68a6172b136c19e9ed123d74b98e5df6cc160455c6323cf2c5bb7bd806bdad04fd87b75be7af8ef5c9891cb98be3e40017d05613401f29f03be1b10c4fcad963285eca78979991f5c3e20ce7bb988ba9f64cfb076c872e756ef97a52a2fe29b47120f902f805746de8dbce6c39326bf7", "55a70c00f0a796", "16", .Okay}, + {.Log, "3488e633f95086fe0d3f12c8de6627223c85c28eebbe293970e7e1bfc19e2a6f9f4b9c0a0d652d3995a67ff79c696099cede1f9ce464f3f1d7139bfc987d1088d72201afcebcad2362e55af1ee7234fa278411d71c5291a88a405a089d18b885f4e8ca8267aced855300a47dc3ac2d7170b867dc40ce5256689d0bb7713c0254087f6de4ec37900d0c251b2642fd1f674af2bb405922", "22a6f21b156a6b3", "14", .Okay}, + {.Log, "550f0d052947fb277b701c7ae3fe1508c6d065136bd4e6ca4666e1f579ec7050412b77f94922816d865efc744947a3f3a45fe2bc0b331d7356d598379233f6ae3b54b10c99c72739354b764388c4157fa07bf7695ac444b95c67cab682d0f0af2c95b64c5906eb29212a051510fbd947647fa578d3741a5feecbd2f1c7f1b63a2a300c9aa95e91217826e87227718608531e53591f8a", "9b12d58226a9f24", "14", .Okay}, + {.Log, "9c26731ab02abcb5c529c238f9b4905b21ce43c43fcfb15a30203a279f74ac8478b3de115cda81a776d10b45760ab665ca3304760ef0f325aaf7cc0b40edef8737e10f8ff3d482c14b3eeebe3f456a7f8179e17b6588ef96f537ee1521a495669faa7f5a4f14b9a594f411ddc72c3ddb6c022731f918b979df0d7d723b99389635bd12e8bb6b6fe1bbc7c8b566c5ce3cd6e5471c1674", "dfb10242f5f7b1b", "14", .Okay}, + {.Log, "5d1edd0827feaf8f30cfb53a6e4bc31452600fd114782f855062e7aa6600a51d936908c75bf85596d1230aa4363137e3fabdcc0425f79d3695a7f015b35e22b92b803b244d6b4b9ba2e37e90490e7da80279d787d6bea012d79eff61096506be91f3dc8e2af70afdd96465d57b55aa47c17be3f35737171bb3af56ea9b20ce5c7d5b5c4eab9027166a44f48e957e578c3cb78a8cc4bc", "307d2e582c3c4d8", "14", .Okay}, + {.Log, "afd9ccdb5d839b822ebea68881937ca15592233d76643d4814afdc15c2af88813b28c8401127bd243576e2bf1ea675e46de3a80f67cc0e898dc69e94928d086674d1d54ba6958947d20615e0d85cd8dd69e55356fdecee73f3498dcca154ad7db16ae99cf308c65eef7cdf711c6e8e5382eedfb70ddca6a45d19e63c60bfe2d3cad71aa94902497a0bbfece5ddc6624eef2a199c82ea", "1716ffdf1e9ca9b", "15", .Okay}, + {.Log, "e274b428ff4e37b22956d38b2e0135e72a10fee09a504ba72a4d6b432999adde83ced4bc3a50e708695a834976a2c26e59a754ff72c10881efac106ddd0d5ba8a679cd71f86220e10dfb181d2b760808ccd9500408ca1b275a7b83948c57e342fde97d23d1e582292bfee54038a7ee8641c75ad2ca81c56bb14c0f88ec5126be124433c726fce2aa3a9f4fd02a5bc24abdb58a8bd177", "27db3a77c186174", "14", .Okay}, + {.Log, "7935f14426314d3f9f108e666ee2b7eca2659582d5d0e5df07bb81975394a59b20948ec0944d56a42719ec2c2240316490cf10c5f1a4e06f3f8482db56dbd55ff7f951cd735b3c407dfec07ec048c1c9de74375c65124da50621975fdc91bcac2da0c6fe1b76947360a03a0deedcc9edee41fd63e47f3e3b5fa4df475c2cb6efdc0e4898c4247c2f76887d716f1225a932be3adf55b6", "ae912a76468bcb1", "14", .Okay}, + {.Log, "50f53827161112c66c6086d5eca2a10809c5ed04c16e3ea785efb01938ec4135e43f613be543e5c8954e2a9419c2af4bf46d49978c617e9b7b58b62112c9800f7ab17101dbe9e57733b16a7338ed5892cce4029d1fff2f202c3b23e5f8cdf99798a4213eb614037167ad88df75a6cf564bf26664f9e805250683878f14172dfefd088142c988c888c9bb55558fa0fb2aa85cd8bee9b8", "a8f50064f556316", "14", .Okay}, + {.Log, "e5d03bf83cf884b3ed7091746e3dd64916a55c058baa8139c498dff9a0a1a90e08b6beff1597a11953d526c73496b85015c1e4b12ed63ee44b00eddcc269f616ddcb62aa7d4b46a33d06694fa31a6898a326dafc44b476b5ad459f78c675448545ff9b818bd68e89e21ca7332c9fcaa0c5152e0fb92f76b9117fdc0f40898745da78891ee230ee671b90f26b975c72901e5cf05ade02", "761c62a3d52c39e", "14", .Okay}, + {.Log, "f7a7af3aea07e589c4533354ca11dd6989c461616789464164eac75a295b57e002d08c99c20e1cebbabde655f36bf407a096458f720643eb51e8193a125f601a89de6388594de04d4b011fca88fe19e31f12fb74c7aec6bfcd63e363516438ac9deff8b3cb6700f97fa745de62b2324c39339a5ca7beb76baf0b41ba9452a34ceb5c36aeec3c272cee3d1b35db2b29da9bf8b3129c68", "72b9cdbfff5f825", "14", .Okay}, + {.Log, "2dbd78118f9564b5165ade64fdc297b3f84c9c64063d464eb2457a9cbdf9ff58d39386678f208da9429bd4b781157f47ed58bbbc1eb00bf1d63bbcaeb95564ff0ea9b29b751772590e05b977bd929ca3a49489ede651338ef6fa35a8a9ae9a9b83b8a9ed9698521ea54b68742b30b3f6e43cfe2592b550933f7297a03f7e6f15285bf0d159fd0d095162e42e92a519c5d7bb6df33521", "2c00809ba3a1218", "14", .Okay}, + {.Log, "c78023860f49143811ee04717fa62e99e2e247da7f4f48f9f499f2ed75cd6413a70a49450142d01b17a1b3f1cdd4f34d7dc2af06aa48d0306ba07a03ce1471e0e08f04718bda21a5079a2ba8b03720f454fad45bcedfba82edfebdbcfe7b5db9181d133825ccc3082284a3e62b0f8163005a89f6e2f0ab5c5cf8825cd14cb672bf06e77892b46c0850757a6acb3972fe8a9530636d0d", "24738df5b7e9c72", "14", .Okay}, + {.Log, "8b57d344b8402c45b76a94374e9ab2dee42398ee14b6d7453c550726f24b3ddd0fecced7227d9f6407bffa2014ffc2d45008582896068b1da2cad5d0c7f5e262136669d466e9a6f37e4da42af99caae37d8ae7ece2494093d0f1c8f75a9b8c487ef88a4b26a028e94d8654a8b34327ba0fef0bbe954868a80814546a0817c5be93f82e8558de8828016119d7f52a1232dd79071ae174", "fa31ab21bf469b3", "13", .Okay}, + {.Log, "ad292ee1d91fc802ec59d524e2fa56c26a440986a755ed43096ccb9202b006b50281827f79f701add35525f3297544d8125f5dc366ca5796ddba64d42fec79fe88c99c53a9fc7a13d1994aa3df29df1e3f4bd0a9de650c2e2c96f3ae2c8fee1bfd9f926492be1a47b1cbd834a5ef63964525c917d5d1bcbaf3c9467d34485cf5d8590be2cd8574865044e55ee2aba8ae3c65874f6f69", "29ff48636342b2f", "14", .Okay}, + {.Log, "9d4c2767af86d2cefbb539799b37d79fcc40d48d49f5705156a31cd4de42d2b3ef503aa51f40d99c4c00bcfe625dd163638b246ac65df62013050405f163bca5c7bac1e2521284d599f278956d3cea56587e1ad731097beee189c87e25671e0074e44661aa34512bc5d880c3f5f8a47ba7b96fea6aac0cf8f53d4b80c851ecbf3bd48569ab88d6758cc7aa6a48d34d0884cda1d8a4e6", "ce1852094281b", "17", .Okay}, + {.Log, "175ffd6c8c69872c9d9c9a5cee272473fedca98edb61eef277a4c0af085ee8d0189c57ec7e8cda850667cd0cac5925b348cfc61196ea94dcbcaefadeb65449a0e2e63ad028284ac179a24428f86e5490e0a73548a82292906b70859f0fc81ca7adaf515ac6be09ff99e85be50f1a49bad126b098a564e660e850ed61d7b77bc135426180b2d8e728da08502151d6d45ff3916b11daee", "beee2f8c1363ff1", "14", .Okay}, + {.Log, "b82fe6892de28ada77b872acf2689e8dc1d73233e57559b209daac3fd205878343821d6cbf8736c7eed184a287691e1d0b2d8e2c1cc4ce48d9e3ae16d54586c48e121644b1e4bcdea70f585c0aac7972c5b6ccd64fdfd85cf010781b5534b66f11214d97a29af9a27a223666699ae32d55f409b50fc4b0ac55e92f9ab0df5a93236987c8c9c9fa12aa028645ee4948546b1902017e37", "7c192d16ee2a0c0", "14", .Okay}, + {.Log, "6ca692b2ecd68192dde72d241fa8bc460c9f7d799a130bc57ccd1a84556dc2abbd2523cc5529a211fecf4204d0119ac6164f3d78431f978d2eb4aaf6de7f8cc703c63e302070bd5a5f6230323867e7c7807852d34d6ec968810f0fb39a2cdca9d38dd63081389887d71b3fd091b198b8a5a9be55f0cda1cb01badcee7cafe7e203e5994f22fee71aa33cca819fb43bf4a4ed16234cac", "baf0619bf8c1428", "14", .Okay}, + {.Log, "3427ab305314d673bdabd0ca93e771f28cb701f11f37abcd671d2ec9500e081766f88e54a49b49edc376848f1ea1fec21568db406a71c0b46cbf83a3051d7690bf07e419465c51527b0fa0a4a2786ac21cea3f633b8ba73650bbc78abd458da53db35e917eb8e4e39f6458dcc329e94283c398d3f559d66aec1e0e956e5e6ca2065739ac8bc570671cd8c13ed9faf7705264471f28fb", "acdfb76f43f1338", "14", .Okay}, + {.Log, "c4b4c342aecfbac861a5e11b45c0f7a5c3938c20a0384cbc9ee67195ef3051ac12daafbb9cb96abd118acd368358570a5809e123a9354216a5f2e3c8eeb53ec5856e67401b6e87ac870aeeb175d7eba6319c13d8e373c509abe9440188f3752d65cb58b0da4f9a05a77e97719e9335d2ace62f69889cf5e4cfb6af00bf8a3bedaf5ebb523ab1be9b2dc6d3533ac6ce93f1747f838d6d", "661ca3093fe920e", "14", .Okay}, + {.Log, "b66c87ab896d5e0db6caba614ab2ee3def49f33e4b8094430371ba87b3295901247e0b138b02462f648fb5066dd40ec61f7df6b9e1f8cc797323aeb317ac708a25b079af606d0277ba0bdfef5a7a0ea92245a9152dc153d273b9e4c05ef80ee048526c9d300bbed451fc07d594332e5ad7e8b46795093422232643e54cfa51ed561e0b29b81b2bd22915a838dc70ded8316ae6e03e7", "49cdf33e32e2153", "14", .Okay}, + {.Log, "cc3add39000e679586e5897eebc77cc4eb5035f522dd714a805cd63b8c1919493a81b147e3535e35361817cc398811f72d4f9b9fb5175605b76343378f5cb48b4270ad00a044fbf3c700140c549f373aadf8bb640631bdb491f6a4955211cb5a36442148164c211e155f87dee5a5f0ea57f7ad733ca2329e4f6e8674624cee8b1a98e9887f2585283f87d2992876db907bd392301ada", "70d0f568179096a", "14", .Okay}, + {.Log, "bdc821b3f623775701d12e3317b61f9db282b7ba775b1de0467893548e4f557fb18535560ec8e60c11faf9f0c63bf4e5603194e5f12a5e768f3d4e1c5202e38be12f5054f8bae23375c81ec68c26cb3cca0a9f7861cb954196d28d7a3da989c58a115b1eb65faa208cbe44f3f2854c2373dcece407cbfa93f614def54e5889f640eca27ba90fd1bd281804823b8bf510a44dce9fe1bf", "f74dc674182cc06", "14", .Okay}, + {.Log, "17e8e8ad52f4c4e12dfe6ff38377251b9602ab8476c0068033cac5dfa94bffd887817631f006678adf2e11256ed08c8e3fb53317e19f64700d9f1960e354289d32ceccb71a189736a00f43e856db7eade10e7184e7fd05c61ea1ddb7b94e0759272915ddd48cbdda12c4c9b0caf00d358ecea333bc0049bf080c41b2caa399c4aae6604efb8ea5eb1012218992a80a683a5fcf3e7690", "156e92827b05e47", "15", .Okay}, + {.Log, "82c702d1ca7b0a369cb2c798f2e0250647ea10e6f50a93703d4ac2da384b545503ad702e112ccd6876c4bc27dd3e6faa8147316202c97f348bc70494e19c3d1cb02569f46bb1cc2cef82d189ead52c4d8d5c5b9affbdd98eabf31c06605f31485f256858cc38261cde0a13ddd4f7eca18ad4333625b7ac9010d859c9b9c060ebfadf55beaa6784347c28d9ff87635d2a24e5afcc0b40", "760f2f7deb1295d", "14", .Okay}, + {.Log, "ae0e3738e2afa00a3162f91b1072968a9db01db86d82e68eb708f24080a5e972ae0d8031df1ddfc1cee145147850faa9f5022b9d2d16a51baa2ce927890d21a161ce9ea83eac5935cb517c7f54c32d745ec69b8fc9ea4388093c2534c3f5a1905ba928c4d6c8e0d4f1e76d2f3c1d9a2c47530d9a2eaa3e254ff40a4900de9ccb6a910cf28776af8716f7149d898f33875d002ccabc1d", "f3085ba3fdf59f6", "14", .Okay}, + {.Log, "a77d25ccf1c5d77d9865685f6f118e198223a6389b1c6ef3fda7162a9b0bcd79a8c2b8597971d2946c1760dd87144674e7b96991783118d1363968866315c5747150934d0e8d9e1e8d641c7cd7d3cc4c83799d36986f2d3592e6a13bc55eab28914f10b7d1cc18d90a77f4c4cdb41fa8469a05046892eb4ce1e58733065e4fe5ad1567766bfe7674d65938f0c7a770226f93d41566fd", "bbe5e1c2b583433", "14", .Okay}, + {.Log, "aab6748d6c2543938fc63092736076973a8c17fa22ba868c8f32e868262e740011cb1bb166a0174207168eb25291605ece64b20678c76be6b6fe33c762c98f73ece243b887681646bd03ce0f7839bed560ae67cb7ad6bb3cfe29b6b1f869b1cdba4304c54cf2d0280a588162852c5d4684c47aebe8697d7f90ead87c5968e60d8f2068c601d4dc3ab5ac896f3250a9afa299ba102c6b", "7b78e0b8a644f3e", "14", .Okay}, + {.Log, "455a45b13ec262dc750a5cafb1bce55eebcc5aaccffe2ac4e9f1fb1646068de1405661a152152c1e84497f9e6c51fc75e1a05b2b771bf7715432cdedaed65a76c7b8e1158be186c9c1dc9a2a8ac8b2be81b8dc6a0128ae55929ba18fa29754c341cef04c36414ad2b0949efb825ecf1c6d103cde51eef228c0860eef073d5a0e2070ed3a4560e004610566cd31b9ee26f2122112f408", "8f592c64a622c3a", "14", .Okay}, + {.Log, "86cbb268a43b82748691df7a37d882dbed4199dc86c93ed4f24d563beb4d6df7d6953f675b1582939f6ccda86c3f249cdcfb92b42166101b8b0ab9646f1b112c5d9e1b832ed3229629dfa9bb5c099edd1a45168c7300d13470712045c79fdb11d302a17c5441ebf7529adf34459efac6bb1bd2323233ba5fb51276b879fe779024a1ad54460027a84b9b495ed8678f42811520467076", "1464d6eb728283e", "15", .Okay}, + {.Log, "59ca6769a9ddd073baea636f0ba864049ac1072d5131b8725db0946a885ece7d27f22df28df31f5edb4a653f8678a9d1ae5bcee2aef192c201cb8f109d2e5a2a3738e72b113eb6e33d39434e7b80987a1f33b271e08229ddd637a649aa57d00d230593e118843b2f6411038a15b2340ea0ccd4d9d87b6f1894cd64113f8369feb3307bc4ca11d6b4d788b0beed8e966a35044c6947a5", "7d82678f0564ac7", "14", .Okay}, + {.Log, "7d632bd0a3f90882fb3d02436ab9bff5708131540dbcc5ca0b360484d78e2c82a2531c7e6ad1dd1af2c8f39fc3404b871504771a9b1b6f088cec583a8356e98bc8c228275ac09c75dfbbe3d96646769eead58f7f44f10285fc7d2d623eaf099fefb21775a5182e93bedb9185ee2e8300bdc6050b85322981f522e2ac6aa0a90f04a2f96cfceee2e3cd3e0fe519984eac874aab80dbc", "37e12bc40ab000d", "14", .Okay}, + {.Log, "38003e3b5f8b4eff854c38bfc5405f53eb75b1a855fa5b5666fe6329c7a5b47c7325828eb9c5b753b1ce48b1721854ca785f46b5e8b6f5340b01fc96a54899ad2e7d5ddb780503ee09a0d6298e7c19335a71a4c2404fb71b93a5ade943fa5e0d14f4069af5b602a1b49d828e7d29da630f9d23c38962776a25f7f0f51db74b9124c49876363585a1ba7cb71e6f48c94b163558e37131", "22241ede456c223", "14", .Okay}, + {.Log, "c6b72488e7e66d50bf8cb1bb00e1261e4ca285bc5ff7067e88b405898f4b1eb8183a84a0fb095ed39e2c1cbac98aa2561d7cd3d0691b5b8176ddd4d8c52653b4a5af0bbb21080e9725c8abced5c1b5c3190dbb23aa4ae4ee3ece049da93ded3679f184b801409c5250cfcb9e4ba3af2f03664156f0e7a953137d1a753d8f0a47b0d630e21f986c138c03bb444ad994710e77b56eb4d9", "9f40243f35a00f1", "14", .Okay}, + {.Log, "9500aac38f50dff51c86317f17157e0d6143dac6a9c1ee2825d4be685bcfe9bbed6c028edd461b2c5b5f67d4c57d3bd2a9984d28373c3fc82dfc3d95d9a27850c98b98e7ad48269f59626c4c5c98f5c31c0bc543462c1636e6653d1e7080341ea5574d5cd545866469c853ab0badae4873a9ba45942d45a9518d881274268c4b9b039ffe211bcc982615c719807e2a51e60868c4807", "23057dce88fd236", "14", .Okay}, + {.Log, "6f029b43bbdfa3e6d9a81f3f33e20edabd191a8a090e9dfe1659582dc4b3809c705bb90047b8633b07b29105e8ac31fb8ad609cc6ec53e040a007abb137d6c7f40ebb996e0c7ced41c9ca8fad6a02874b93c1fa60d2aefa6aa5ade4e44dff148e108b808f561ad32a7302e1caf07c868aa0440d2e24f4174073b5898ec549d796fe71e5dde4932c96e93e3cf2eebe7b1b1c8f9d36e97", "8a8e1ad14e9f433", "14", .Okay}, + {.Log, "d9a3f8b7f1fbaf4b1bd3c81cd4867fe58f2fc7d33698460dde908095cd5db37d1cbd30a05024be81285cdae786cc642e94dee2cab1a81f3cdcbd58d99dfc273f72d1d42db2fb82c40b66ec70d0bdffe39d59ab8a6002e2ac0cee0034a19eb1225c85b6fc94106bfed56f5173a3b0855ee671129aa86185ba37454b698ed1f9d1c7bb469aabf0adb462ddf739e009aaab16ad09470777", "140ec7bd411b8c2", "15", .Okay}, + {.Log, "9a999ff62f80dd2f9a5d94702fc9ff617bd2ef1188f039cf30bf5e539b45d6f517f805afe9664547530b83fdf2317cede038c5d463837cf4e2825cfb704b6b024d24460e69fe6bd90a2da33cdce8a38768effddb79fff8e089ff018cf8abd5996f87f7527515d03b459dc6296ad8ea905d3b94f3ed2d9da0a2231ae562e2a0f15a640c550f31f895ff01dcb3af771fcee2a20c406da5", "c76464d0b3ba738", "14", .Okay}, + {.Log, "3feca8b3f114f254343889cdd75bf22cdf1ea380e881f14c2ea44957bae690018f4d2b34649b0153c8db75faf564dbf777ca48ba34ba7127d4b18747b8a489585aae404f989fee1bc551d55f089734669f8dcf192e76e6dd34b7372572a2f14206b2a06ba4d5d537c913c902924af2ea3e0c6dd5d1b3ddf044ef24424fd3c3ed40519693beb51c05eca6c203d1db5cce9de9f7cb3b8f", "478829c9c73762c", "14", .Okay}, + {.Log, "9054f75fdf67acd1b50b696e76d1fa0b7eac00e9a46a374d6c0a77830381ef83b8778009656b6aa78c9e9ef300f4539ac8a94571035c4a371984e7803b5a36df0e0c1c8d1325af9569d6092c155d804cc0353c549b5cc4d6985386ac85b54e9a7c4ef0be6ab04d6a91d3549c3d97582451f94365bd8a556900567c680cde39b4413ab8f0ef8af291f7af42c9d00a4b7ccf54f04fe2f6", "5c903b102a58c57", "14", .Okay}, + {.Log, "ca630e784f485f1243df60a136070ed8f5fda9fc875fa19e8a171dbcc0fab66188b6735a34eb47e389036e9139b453c327d4ca097bdf9b374de18cfb9f08276a2ffac8d6c53581550e8fe8ea4f8e2fcd0af4b2aa89b50612907f2bb792ae287511464fad131f640b45f1e0d1513415269cc508bddd7a52aa72dccdcdd2a07b991ce4266ed321b02914ca68ba7acf5ff205c2e8436fb5", "51edda0a0670305", "14", .Okay}, + {.Log, "799327836d22a9a2c186065b81525d63f37a5ee91c7ad77351e512402e11f50a10d204701950992abb1d951e1d54a97d786e8ccf9f76946f3b2ec3e0bcbd66100b50038fc07999889f7bf30d094d7968888c8c938361b314fe393d3dfcb9c407d5fc6d5cfd566b2cda297b6a1f55ee41b6db2a1e3dd4f72dd9d5341bf5df76741ac96b852f89bb3f5db2549898b6fbded423fbd8644d", "4174f5c49ab5c71", "14", .Okay}, + {.Log, "b33721bdfac935451ab95e7f9fe26f5563b75f3a4dd53a0595106ac1db30999476686ad1dc37cb4174712007b2051d73016e25a1bb4a1dade88c42d62a8dd5630bd9f28f7ec5b314eddeb840355fec3e7f1233fb32a1593710fe2f1cb9c1cea4ecd2b10536f60f53a14b3c63032d207efccfc938d62a91f26ba7201dcd62d270f1a9b5bad58e54db503a376d6807d2b77eae6d2b295a", "b7e00268a2d0c79", "14", .Okay}, + {.Log, "4168ac0799ed546d9d7a9cbad3381aefc98bedfa42acbcbaafab322f28fbe74d43fceec7c9a1835574f0eabc593da2639546de8e7406823980c9db1d846abaf7c3e564e26b2e0109a9670010e392a7767f911bd539a9a32b1ed255e26779e6dc77c618ad5cf173e6c372648072d95811635fccdda880cadc88d65ac22512078dc2b7f7faf49761079d52c5b42021f0dc7bfd78dc086d", "b7eda4572dddfd3", "14", .Okay}, + {.Pow, "-9369df47438e794b51ecdb09a896762c1ecb4caf236191d16953140f2e41a16bd54c749f9ff7306b8640c99d12fe66c89f140c373d1dee4e6a57bc4775ea26aee45729ed8144fd689435d50829def60aae7308486e99a5c621753548fbe8b45b8021ba6c6b159fd5e4db2c79ffef6264c599df8cdab55cbeaa05e7fcc8df7a64a18e26664ee314daf6734f9ea04a9ae2767043af6a6a", "a", "106b25edb1d18f454df038dc5e7a3547c55a23bcae7f1d39fc3e7f1e9c0e13252086035a299c07026efbb5b39299d488ba935fd417d4277c9409dfc1a3cd044c4f0ef9a65d712115cb58dfc6c58afbc1d73b6393ab96f10a5073604c1dede4f6f94b1e207d4d5cf0c930b10b2b19bd35eae940aedb1e14cb5fa434a05bf760ae65a89e64ba5c43dcf85759003231cd040bfa95b5b323b3e0126d04a21392518a45d143dd0278974a480b91670392986a152680cba49f17c1f8592f186f1f19541dda0d1a0d5f63170c49e0053a05049198e9aeff0adc144eb1a5e0c07b5357119663667252f756724fd81e238c6764e6ddfa89508181cb027b8e54a0ddec5973ff9d5e0fd7379b8b4fdf5562a0c1bc928bae582254bfdd8a940478e7430773464b97836625ad77257d22ca2534579430c7becfe45bf53da487300b771ff98e02187218df2fee9c79111170bb7e0328da1e992d31412bfde94dbc0f23e076f8b744e06f4f9c55e922d2ee31b8b0ef798f5b0ec305208d2a1b8ce0362557cc732f31d0a4097cc47db96b21b71e8e277129a0e6c8f0888c4fa5f45f8b9e9909e5b5c34ccf15dcd334ef8f028aa88ab14e167a95346bdf8df19b9702a17513c5a02552c337583c12d6665278e8f0385a5448c9feac758539e73c1422179c3186be07932504a145c2b002f0225b7b4435b85784c1c3433bad4424ea66e7e54d618530f40b79c822cbde3ccc02862df50fdae3ccbd22aeeebbd5b76164ac45948038a3fd14cec6065c2198886df3b4feb5770dfd65a68a25f1c4811bb89492a3b9543a2a2cb67be4305414f12343b04859daf2a55f9db44b02a074b9ce90dbb2d8355a033ae3b86af795f39d9cf9ac155f244aba4b4d10d1c53b745d08c98ae7086852e577e5e65460e8b2e08ad1d2cb9c17ee9253d0e8cc853c7406d8b3158085b4c8bcdc0b77be7180f709983c69588951208fc44cf512a90dd30dbbad02ec3cc5cec6d6d7f0d92f2ba1166bd8b3d1b620c36f4d68955bfee7e5ded004f0d45bc0ea349ea6b6e0f7897be49290435bca3a628b31aa1700717c070008e60b415e858280035313f6c9c03be9c532a390306d12923098923326221198fc05dc815610163f66b07444eadf821bd7317c9ce51171a135f8101ee689d8b4bf078637bd4751aafba8c742d3854ba72f0d307d11985fddaae6ec6d916eb954b7f6f08ba05fb694b73e4be7b855bd2478258c055d4076e4a5304ef07664dab6e7eeb0c40a82b36f10371e4f464ac0d81e0d1d826c272ab8b1638630242b3b070bd45a865f340256dc5006d6dc66f52d0445581c0d74e70fe698982af0bb6dea9a5e610d592034d98aa70b8017710c28e958492507520acd8f543e76f6ec5f9ae25dc63a8852898c6c9071e299378217bb54e3c138e57b566704d9942383d6719c46cdf30cc77718b4d48172fe8e98abb66cad1afa6339f5d73e5373a1c19bc340a3767093ae345af2a1eca12f02c7a6fbe10b24305e1d8acbc096b06ee1ca58e7dba001d1b347c5780acb686154e35b4409d814a0e00f8b7afeaf8a4e7d935ef9aa3f1a8c0e1bfdcab0c5fd4d27a947922f0d19a88143f15440d3c765d94b87d20be4d9d99432b8026fde0bb34396b2418d9f396ee6272280c8bf6412fc453db731ee432d3fea634a880ad952a8765dde6b607842313e47c8d93abf69f43aecfd0b0d53c7b21dd171896c2b9404deb9ef62e7b3fbfd2a101d9220e036ae6da83040d197609905c6f4267c7b40187b2164af4bbc99c968747812716e61934ee55540bb5ac578478490991631652bd69f0efa97fd3d07cc169055d1bb4abc319d84751a20c359118e8691999abdf0c58324a9a20d6ad25036a9ccc0fdd25560c9a017ae7c10d6f2f482c3c1708a144897d99d81097ae321df05ec0e9d9f8d29cccb4a3f94d2c447d57610ed2cc2c37e71091e297c3eb9b5f0982b7aef925d5430a80cc9ef5e96fe606152ce91768e1fc84806f2e6616307d2c2916845ffff12dcf160fadfa4c0a84f8703f224f2a04f13230df958f4edc68edd84ecbf6b7b70da7016665e5191e1f03c59dcdc8cdc613d4ade200bf93217a9b714040c103703c3d6400", .Okay}, + {.Pow, "-1b501ea75a42a914c6c8ab785815097b39f18ef11eb23fbb4729cba50d9b21199e7b74b2fb3fa999823065bf6126b6b0e7d22a5bce52a95f2c6c95b2307e1007f6a1bb02bc20d8ffe6da7b87f31e4029f6e9f4cd7347d3593ce01d1d99edd9eb288926211c27b5e010904b51f57b754f8d9a0ad419e7b447635f70563914d418bc78700b5a6aca84bd2bc5097fda1478a862a5475c6e", "9", "-7b184da1508c29d83940746586a3100eeb50bad4bf8aa32400fa5b31d71128532e35f28896602b81a8eb5c64bfc932780a228cc4cbda689bff7bfa4d15a73868bdecfc19f97b1d6c2fef587133bf619ecef4e94f986697617a7f0086a808023c4859527336b9c901a9aabeb038b0d3614a47a9b0a1450157e3b2fcec8d06331f3075a6aaf8c925583c780488f04b9258b6e65af132f8bcd0f4c0473288813b880e6b8019dbd6f1ba3083e2c88e8c2fd29d2b40d286de32756367da9bfa1aa57cdda3a976c5a69ca34c5f14572de2f41497cf504273c95b107f50dedd09fbc785ff9210276b60ae0952e18021d5e2ac579525ab6c81794a0545dca7856a62b1b085ffcca5880305ce5867f265994d080f0f846f71c5a8afa2851250293555ee0c85fd4939cc837f6d3c17bf913dffc6c1e93e213b619f0479d1493e0ce247e193ebfd4b8f95767bada136d78138601b8a8373bcaeefe4c62df134799a6c40f3b1b53eb906622bddbfabaa5b8684e9adc663dbc05a0e804dda05f64ba869b0d817dd9ac37dfc10bcdfb506b748789f401a2c8939ab5b8feb1a592628e9469bc71299658c19fa35be42fbe879127a83232d72feb1128ce0caac70e280830960d9d40011c7577802dfeb206a4759638161b8b00267c9b76ab9fdd1be89f379a439c9a79ce50b70116dac5e813ce5bbb9fde067d16075a1901b1d9bde992078a564bce34d6bf50b051dc0efb3726d84a325e46ac19ccea168876ea9acc968eebd24aaf35a3ab3e25ceaaea8001ed2a8fea6e471b03a0e61205943f0d53e94dfed2fc03184bcfc3c567c729ad95b285a5106012c9db56e9ba8007e8253fa9bb86594113906fd0ed108a0e61740f278092aebdb8880fb389bc2ee37c85ce0f9a0356f5f8dc472da33e0a88c7335ffd9c7faab56c1480ca4a154d958d31c1be9326df36c971be2ce54ce0dff04948504dcc3299db04a85ef9425b6fb1aaeab8371209adcb006b42ce962af15b8dbaf10246434b6e8d8585bb01ea036f215de37d6a580164b789e526a702e62d3772df92cc416730b5aa93df92f0e95e2ea337e2c48394481b922c938c6ccc6eeff15c4fd54c7702e3ed0e26857b755bb4bffd31a73c2e55ad09e6196243277f2cf10b2c49ad8f8dd2702e47c5c98276796b6a68447b41140594385ee68f433e08c795d064a3e1b2fa8786fae018cdd7e7c864554a1d15c115b6fb74d3bb24170dad9105b762fed48f7136872d9b1d28dd69168ec7cf09cca97a35a21bb14d05cde1dead4309826a59947cd4f8a877d05f425fe24a4a0577139995033bba211dbc5fcb0c923388871718c8103f2eb0059babb43b99d0c6a0ae4769971751eb586e5c952a626862d56474129dd501a3ddda900e64d1749f03cb876b7167f4bee0bb1fe5b151b824fbeaa07b854e42ea9ae0a4c06ab4246f2c6af1b9d6328f2478760ed73330315f5fe85d518c28646fff6cf678dd7b0ed7f3718dea035ad77933e553b5085ff385d4f6b44bea8a10ed909827a3de455b7be3a407a161ccd19777b2a14d8f7c5e2f4b1008ab541173783547b2f0e02442687605757c2b7a1c7082f68db12d7ac307e979f4b88175aa80c7d8df659b7a521a933e5b43d24aaeb29122fa0368d6d4f7d203f4904438a7784fd2062d464991d96256706622a3901fd2f6f571b557a05f7409d9397a10d3bb316a04cfa4ba39fc16a6502eeec35fc63a4f00db0c777812b118348cfc1f026cd7cfd775da8f080faeb8c81a2f5e5d9c37e940f1868916f6e06be02181ee7537c655c453daf23c77e96cf80f87a90ce4873e931b28653b13d26fcd00aeaabc366195685d05e0793545dcfaa4c08fa5d66d34769b360358a076fadc96410a25a7d20ca616442dd1363dee00", .Okay}, + {.Pow, "-c0341bb60c4553b074799bfe4d94b1c52e0d78f0751dbb8eb8e3ecad8e14cb346720829e7f5f2e7115d17791aa030fc6aeae7c548a03fe0f7256f19d73dd760b0aee52d731fadd51684161044d868012c994869efe7d743f8a34dacafd52e7e34bba8a76cff40bb351c7bd512c84973bce5a139649430df3e00435474dab58ff0fb2f8ebb6d2eebf70f5aae7a83c7b612229d882d80d", "7", "-226d203951df69f0b00b51cd57e2aee02fce7c5d5fc5ac3b7267844dd0f84f0afefb33e5085ddb686ce341740812d7d79abf136219ab982430d2d9107b2c2067fb81dae39920c8cbae4b43cc04513264e923654a1a79bd00a44202fcdc5e75dcee0d828fe7ca2b05cf7c851df311252763d7d25e7149ffcde6fa3c9b726f2577cb7cc7eb9e89d1af05bfc72a3d2873058c4f2b9407200d95bb357aef31d4a3583baebf4f72d6259dcc5fce782ad9ce61285fac08b1bff1267ecc32aca7b28df1b83d09f13ce9b6421e91a555808ba95da94c00dad7e3f42284efe733dc7e4d0c349a6a045bbaa27686267b3ec437accec10b4195e6c2b06822f316cd238d56ecd8b57b39f9705925b6c93131359156c70df8152095e16a656045124d15002d290cc54193d154c598929c1b6e51f8b451465a833fa96c0398e741eed9d9b3c94e4892b9bc954c14c373531723b58dcd3926e4b48487b9aef098a74245d39d724ef4184c9fbd159488dfd95aeb061c41e616e80b7b094ad5e74ff34f578be1a2e77993a0442939d1a6359f700a125a83897985048b2578af19ad534dd39ec295f8951bd8108a41d4323af52b26cd0f365d40e61cc71abd57372dbfdcc704206ff36144b53f4fb1aef6e850dd9d28b7946aba27114243d0b11e0952b531998117ebda221c65d33d181a6be5b91711ce2857e5d6b6dfbc652de5b577683dae6c529e61600a48b9898b42458c7bfb2ab634544c48aae27313c02e4c9ad4f9148b91dd391cc4396095f020727105d27d6a9fbdd14401fa6443ea9e6790e47b031a040a544c78002964a09d2f67def4908984c13fbd030492b7361a8c8563ca691d4b0606eb1f9053d853b686ade8e26dfca9a3fb2c9016534be9765c19de4bf5a9f5576b05b25a10da5b16c4572fa5035e8ac6a8e36c9b08dc869cca69a010f8c3a712d0c3d1d734db2820f00995086f36923fd0fa4c2b4d4b58496a9bb728a44cc7eeff0dac44b38aef36b235d995d9ea8e7d88e96d6e668cf910462b36a63a5cfa1ae6df6308bf2a6fa06ed6b69be56de5bff89a0bbb2cc07eac89375c2b93c940e47689d319bd68083d20cb836c2d35f042780a2feb73ac67a382525c4bceb137b643307adac2a97fcf84d76274706cd8d9865e95ebfde04171c32457e4d2410d82ce071a498c82866e0b0783755e02fb07cbeeee634e477e28d74103b8474a32e3f8b10dcedf6e6f247615bd76364804490483f430187b62b9c35d96f412f3bb421c1d71f30cf97af66ca1e8175cd86ab221682a678389c5629e49c8fe10e752f6fef66d782539efd4a1e216d364201e4ee67249ae5fb19b5c4ab3f65f37f2ac207a23281c8020ec67bbe927fa8d3e1353f7dabbbf9cc55b58b496787ce7f29637fc275dbf9435993aa8170841621879349bc569e7aeea239d57fdffe1bc8357a2e2c60b6cd11c0d02c8439d812c4c6ed5d875406078e190501f65", .Okay}, + {.Pow, "-dd315ffae0498f56ea334bd35179ba987a0649f6a420f1c89f289d61678df41c11151ea0d06f2b3b8d0f30684b236c565428b1945634d40232ef8bc7671630b4906af563281ee5c079b062f4ebdbce33df7f9b4cb85e4f2a950772268947677519121a4c017fc04aeac8ae80039cc9b2e02dcc798b370d878c4e082b1fb4ccd4c040c5113e8cadc9ac00bf4344ba57edbfce4fbb22a7", "1", "-dd315ffae0498f56ea334bd35179ba987a0649f6a420f1c89f289d61678df41c11151ea0d06f2b3b8d0f30684b236c565428b1945634d40232ef8bc7671630b4906af563281ee5c079b062f4ebdbce33df7f9b4cb85e4f2a950772268947677519121a4c017fc04aeac8ae80039cc9b2e02dcc798b370d878c4e082b1fb4ccd4c040c5113e8cadc9ac00bf4344ba57edbfce4fbb22a7", .Okay}, + {.Pow, "-c90d8f31c36056ff3deed4e9fa93820396c0caf6652ba6f96a18a4ce989db69479967f51ea0c773762b6af698af8c857b8fdc0b447122ffe7218d8c07534a1660b4c0d748035e750572c36a0088a6f1d0f09ea88ee6eab0f033ed3c71f03aa51cd22297a5733e4b3418413fafd1436f03ce09011f69f48e154d8366ac0e4a92f072552f5e5759cd20c8ab11fe206f76b90bcddefc473", "9", "-1d194907da85269cf44a9e9bb1de9004f147e7e7efdcbfe5388cb263caeff9f4b5d3670c3a61262a5f7ac0ebf5f21fe0d9ef3f9ef06b066be5424e9ab0054fe3c0f367cd5b52e0185d532779a2bd3ffa3c1080096f5c07adb58a0518d234c70481ddbe43971bf8235ebac9d6d83825bd23c95b3ca3c578dbdd66fc3d72d8c1ae5f5e9b6a07ccfee53b762eb88c610bc50b1ae9699c5fdd906963e2f0bc30843b6eb4635aa20d729df49700f0c44af5e62322be1c817665a985755ee4b4a9cad3626a9071f69f168afe55d35a0aa090e82b0f61a171c9c673f012ec82435e1c768c6b158fb4658864f3905e4b2d1544b572ed96e38f80fba8fba6c78db436d3b4da8351d619c537d1c041e1b0f66f1e2ee44ab5c1479c3d8c34fc6570f41e1ad26595327d1f050763c606e3f2a5858cc2623379f3c01b034e47f5ffed7c39fccdb3ad4bb6bc2ef2e0a10b23f93f1e2a39998b5fdf01a661b03b5bfd9bef3de80ef62a635b6930f8d90a85b3aad1f82f1b89e37ce38a4a59beeea1864cbb5d5eb8b40810e1dea56f3a241e32d976c671b0246eb668021896eb4696ef6ba49972f8d5f5a9b53f5072b9999a3356c96c77236e8725d6b1264c4c2b2dabcf0f301bf733c71cfb5542e0c351ac891c1c3f7fba470e38e90f53f53a8e6b216eb97eedbe85cc58d8c8dcda5d9c2a3ee7addb64bb6631974bd2113f1dae414ccbaa585eb71d570624b7e8cd12286a02152da6471803f93de4f6379de223fba0c66b3a062764da8641d4511ded9fba0f52891475193641a262017e9ae7e86e60378b885eb1148d79d292ed6f6aae25560a162ec8f7515c5c54514fb7093819fe13a71f140e0bd6d0968877b42b05d783e217736bb59d4d82a7b79fb847b33b8f63d2534276a8da776c7a2bcedf4c7b33db51001578af63fe40c982662d2d647edc7c29cba6c4a70dcdc7bf47fae894a2bb0089da26bdf8d9bd19e58b39351d9712946d213d2c5088b7aa21e8a027c8a852db67b71169f527444b14653c437521a25c0929c94c7aca935c783d3fbfb900684c1b28174401ffdb79cdb0bb719068b53d28e3771d5747b4ecc51f1b5b3093c4855da1acfcba7f674e0832ac44a9b982218bdc4aa227fab5a3e09cb05553678d44e08ddc74f91fe234da7213113626720c29d471c47f029af8bf527b0b834800c5ba5a5f17e09bc305a792cea5ecb93b1b5881758908b5c301a46f95544b852f62169e5328b5d924b3f5fb7d4da6da36ed00478de34ce9fe5df0555b8b388d3176370be818aa11bcc698ae783ee38c512b022d473f8033e733a26bea55cc0181964ef24e0f272dd9de113bb77e95af43752a749d29e6123a5ebd917791aa4e59d21c7aa314702fb22c8be45310f62030ee72ffe27e506b8975b928c6134b94b796bc5eee07638b62a6f4417ea1a4f7bcb8091f6cf3ed3f49c5a3f95c1a65e990ff50bbc1cf03c154e27581d529b1a850a59af67ace58c4ed51afcb78b5640646dfec65f8a117b9445c67c9cdfe9a63b7f9eb0c514254ebbd343709cda314bbc2ba2dde0184424c6b5545edcd60b509fee6c9daec92e81573efcfdc4b8beb9937cf681942be2f651fc4eda710b2b8cff848fa83830e84cd4baae82538b27dd1da385dafa04aaede5154767be5c8b07d6e06be1469436838ab4f2472bef3aa1b9fde62c87c0533f5378f7c9a4e0417d08e8f859619310ece2f77faaa3c4776a364835b9359a8e9e0333e1defa2960380cf68805944f4d2bdf630004fd9a380ea7c1357b25d956adf99bc673b1eee4cfa8dae07645870d3769d84e655d6446331757e855944070104a8a07d95b28e4b9bb883ff4139590521b4d46a2df8ac3ac0a2b2cedb3e5e18627a2da1f03b380572b7ddbc4f1790b9b20226d3", .Okay}, + {.Pow, "-b4caf2e1697dd2d08a65f37076b87ec2b6da9caa5357c7de55a0ee9ab910b837743f263e6f68d45f1f96e0a4e652cf4c4be9a21f64135d5cbf59717433fb8e625c12d3d04ea0d4cfc286dd4897cfe3d2c1d28c1a0edcfb5558d349f35ced1e6fc9a3d7a5c48831a3f64f77f7c83ed1a0b37de3a28b762af4d0d1fe435ddad787be68a23c539888a7b92950ff465253acf884b49f715e", "a", "7e682be3954c1ec3c46f7d452a1993955cc0642a1703db1d891d8bb2a537f89b3f05b8c3f12b627548dbdc74482f48d1a1e884a582a12090a660360ea7dca3f926e1524665fb6c3a501392e1ca06477737b3ecbb56c50298d04d26f799a654d23e21f75a09d86d45a2da0f5f0f1de6c73be4568c1f6f4971b0bf33bab2fd2aada299e1d380905d65720a7e40f7d08bbde399b3433c54566a8f8e62f37a44fecd27adac6cbc86f82df53eab82ed2e4879d4fb7b7accf209ebdcdf368c84c7106f9c9f9616b8d1c09d0de3cd6ac40e87eb29fe8de07835431fc9537c81c74dd786d6ee977c6426b1d761d6574fccd7da5cc5dd8e90c5b2a8f4ae93f2acc70225fc779067afbdd5131b1ad68cd2468e0811e7c94e0497a24e504f8845c4167103a1af12b606c565fb3fa77ee5c3274329b824f65dea557e6c09c1acd5782987507039f68426e4bb13518b79dedf2c0fc409f7de83dda5b186403ce751ab278c87c2b21511bb73448002e0bb88e260ca3473a43928ca034376f197f96b6785fc6e75040ba27c7ed3e9644496744bd1c65286ebf43bff5ee965429decd508c7aed10fb2ccb8b8d6933efe8e154bd05e477147930c34f90087f8ba6983c5f06d8f2a8e7888587bf3c34d103ff7047347c9de2f601b813713b65dfb977b2e21a44cf8a298b58d696d24909d7639cf62d8819f6eed0c6fb6c643d06fc3503f47fb231a1c3ea98aaa33c404ed16ff391a5ed1a39e30ca1b39089df299ca455877e4a1ee88a38cc08ecea890f60a92d6ac6ee53a319b137b8ff336a3f2298add4b30cc2c7881bd1dcee89fe4638688510916027890f3d354b37784ac134630679750f64d89bcacc9f4f4edaf2fce3752cd9b890f0687348927ead952e47bc33cb615a5c9f7c9f390478023933ea6bbd996501c6e7b89af27d74308b06e8de7fa1551e9f0a1cc653f3b5328d2427349bb79290cda188935ad7a934fe6257d31e58388c9f3800d4c9dd6305eceff6666ddfb21c964db2b10035464145a2a5689eba2157ebd0c04c98ab0e050efc1e856958af61ae71701e7acd86839315ca9b51ba509e194f46717cbfb2a8d3a880ee0d3a2e82a7cc0465c7d255ac4d3293ade3668e46efa640e0c244176f543b05d793bca6f60bb031448e93eb23b6ba3f2b462e7302f82866596c8251401a0c101fde92cf6ed32c9d08273828503102acedeee72ada9599bb60558eaed1f481329eb2fc08ead23aced7fb46295b79e71de864e17bc46945354540c5b065c72090adae9da7643c628d5b90fa5320adaef10751447b53e199baa9727c75b28b45bf176604eced7ef5b42829a8275cfed1299eb1e0ebe3273251eb10ee08acd3c1ada72d526a743970a0d4b51b2b1bf6adac8c41898f27804c501c20b5546f5ccbfec3a103872d93c4613a8a78566119448b8c6889065daedf18e3cf87f063ccc89eb9c52f3441c50802d832409a8131438684236ad9e42c0a2327a5a558bd033e810c253002d53d422b44948ac07ab5a92fa542d767566c539fe89102e7f1a2eedfb02f6656e35bdafbbe6e588b92b77a2af34aa9b8118b5c17f0967c04fd0459f78f9ebfa87440a7ac539e5de319ce7282046a047bb5e7d5fc243fd2d149b68e27f75dac8c12c749bb9fc7a95c5dfa97fc8660a98ecd521f2bfbc92b3b9346c366cc348c1a87d7dae5a53fda6054409e0084934aaefa1fe2d3c60767c94065181779c98115197432c4f25281c3cc190e25d2cccd27a92b394ad9ceb3cf6a53555ca7d81369e36591a79c86d357662da89b4c169b72ce84ad804db53337becf63819e0b6e0d95728e4d00c656973ceed38af1719da346d5fe4d08b512791257dc0301db3f636fd612c2ef8d15847a9d214d7e6f17c0950a905bb0af597780360c15841219dac7f58d169c20f4f27422b560c277f6c30bd63716c85ddb098a34e4b4bb794d295166e0e43e5194cb06fd442bb635a0b785609d425a1c55b34d2b76b713e35e56f1527555ab12053907a5fbd489458ad260f480f5f1dcfe367e386c6b3cc8accc494b044d37eed1bf24c8b9768391e8829868f14823ad9ac542ce029e6b4ec76c246390766c86fe64c1056012388400", .Okay}, + {.Pow, "52196e96de7915f48ee4bb54f60b85da79ff064476aed3c7bf4bb0e16b1ab65239ffdef701967e50f019de7993ba2ae1bcbb33342eca293dfdf0e1f049cab6eba40c942933991146e32329e93beeddcc98c67e268e5b7938c92aae5380c05f8727690231ef8eb229638af927f1938f8ffaab1ef7c48dba26f9f68730dd0b4a164e847c6f9b1c59a62bf5d33330f4f6a05529cd02b1c", "a", "c1122e8caecb205efdd18d103753661d57fc4a96205a1d11c0acb6fe6427234b6b501640c0a4b4b06a7d4859f2a41965deb1afd4410755160b35b895724e723c0615c4e8e8b962316709786a54fd6b2cba3b894b8bf59e61119250e7a3e88e3b114266335f0346174f00777760d94d2eef48ef9e0c59eec94fa749cd154e1e34fd29da687d456c123e54e3e4dd8cff320ceb86c7f8f9f5b9702445d5bd48c2a693e4c6975bd64e63794686f26410d52ff232731aa0e50ca96ac62dcd6182a0712f46130c1480e44d88fa7c9f4ac89398cbc0d441de1bc2dc4427ec9f44daaf1631ab3780c8f20216940de33434ec0dbf3d3b48e92d6a14552cf2445464c9993aa34fda235aff6b34c27514c4bbd37f6cca9951d1dec3545e4889cd861e896f50d425bae85d5c628cd43bb2e2c5d9ed878af1a5863339f057f68216bda00a88d1fc7f8e9890618bd467d427c4434ce50dfa38a01a2f2e628aa3494feeb91518f37f6415dd9274d65d61a618ec5576f97f00535ef6919cd15f3f5f94bc8305b3b23f82eb69bcaa328a08bc5f54d2be5ab9190226e1ecc8728452950436932793d1ece4c8bb9eb832a8f50933fa3cd7017ebd07201386db9963d0b1cf06b7d54a884256d38443f7d7185b6d3502dbe95b262467586c75fc6d463411b6794c628bcfd2f521776fa12bd69057aac39c4d27db0919ea426919f8450c0954367bbb11320b3d079db409044a260daed9e644dcb619d1583621fcc071c1643b596bcea392fbff0440e6c079d148952debd2c4bf4a58767f9901e3c9f3e383a0d84e61ec1bfd95a8259186f7a5f044830a2a20112679dd43261d8558b66677c042e127ca5d7059a1bf2abab3ed08f8e0140be030314c7cdeae640ef1ebc6a67e60923d0619f42da483f4e09ee4cfb81c5a0098b12a5a2799d4e0597160b17b63f6bd0859a9d8ffc915ef0899d8505f0d6cd08701fbb5d71c4e02ea7676642980c23a539fce05527292de5e187580079b74abb57cf93ebdf50c19a3c5f4a1754533c6c70618605f511b2fd597ac1befbcaa2586059324d732cf8d62a09bf7905d130f2e481fc50234f131993afe9f20ddc2ead9ce4b730902dff4ab6decfbdda7bae05c04f264660b546a5bfe68b562da7ebf6a142b5fb8d74a74630778cd46741401450ac3717011ec4638eba912f5917c114cdc43795a3bb691c916bc142701f1f04384e23568459e7d5787061d78a44eb21b3dfdf65ff73fc83ed7cdc555af7f305c912307803b3cafbdeae881e15c1a6efcaf7254ec74b49fc9f26d48cb3a03861d3cbd2ebbbf6efe8ae448a779685d590b937bd9598c34ccc9285ed7d5d890c795a4e01df99e8e529c9c3ffaeaa61b505f5c5da38da6f58d50afff0b144d3c66aeb8da4288e2321d90cb8582b5c2c86eef0d59f3680bdef31a6802a94715e3525a5b4a04d88e1636559041ff15e99eec8db3baa60148374b39784e83ac90cf3067775ca10a6e7d9081637d0e23a452ce00148123a8ec1723ae5361316e659ab3e96555769e84e1d21ca75dc705ffd2a2cc116a0b0a49cf95165dd668acaddd42c8d43010bcf6bd37e77c1aed23e54e7e5de34fa6631dbe18db01a127a397d45abdcb4f8e3c741f5d08b690ca69e001ef61f515ed440478fe79bfd72c463812770f94b49a420377a06054fd86d14d02535a2547c3b6f0bda4cf175c06c6f6058adbbeef1c12acb7b26e905ac327e0de664bc97238e920509eba676bfb1425284d74c325072ca3527870cef3502fb3a72665ce266e1951860d8abd7ff9401d27c477ff02c54c8298a9b9a2b758a332569119d10934114018dbe7bcc28959d170fce09a8b675c811073227507bfcbed92196407ba0aa9edb14d47f924dcd5450531d6391fb3017b5886edeb98505bb1c815e3c043da87ed0801d7e54b9596cd8cf73e9d1aad2a34ede303495e567904312f522fb89f31e614950597d70c45c4aa4304149a69c16765cc11c17c2089145fa196c97a509123ab856fb6012d986d7b7e9c09abc9b22bcc17883fd25b17ff7ad171316255f385b5dfcc2a84d0f6241df839136122165c431dce190b01c7dcd2804ee88acdb7100000", .Okay}, + {.Pow, "-824e9400addafa1817f49e296c5dc6551792b34844b1562c252fb40b62e32f83d30e1b947573624b3e932f4132ae0790c31eb097038cb098a94282bd91669f0c0ee44d7914ca469e9b462f41d193ec24ab1c164c7469a092eebaae402c23126ae8812882fc0f81d07ff101df673c1c1e7b016d8789abf4de1c53a04d29cc41605899b2d8bf144d49d40d5131d4d9468b2fa004941e75", "7", "-24431a14fe16ccdfcbc8925823e086436ab8a38a1ef06ba131a5ac8e769ae0e75a85563e2b3dca1557daebc0f81c8556d67f53e648cc33f0eb816231b0ac0abc0d7f1ecc0dce886f00b6690df38e23b896e9c5caec4b2236e77abd7f37bdc2c1d13d81bbf595b4a7c5292fe73d9f0ada5313de2b9bf6f12e92d1cbf38ad8293153c573314dc3864758c6d3a51ec654a4d5dd533a01b3b7022afc4e4fd1cf43bfc1190c008fb53fc4e479dddefccfae71f4b6cef5d77336076311e2c63a1facc3ce7de166e1476449fb49d250ee1633b34cafb38ffdd86d807dee33e2b4f8d5f992332c960732e6e7aa832c5c4d721fa6060be9ee1d87c4ab0a3c82c06ecbb1754187a4473af863ec91fb373cbf7360f3bc753197c7721740b08a712ee95eeeb71e8482bb65be1c785aa79d8b671b390e5ebdf75522ab92c6466ad76efa0a93d219c35653b6c9c51b6c859f0cd6f42de916f2c825895988f93462e33cf4f6317351950732217a09ad0df8e737938f396d7742fcd9ee6f174a0b55963d98ca533e7a2308e821cb36519b426692cf73c14d964b7b81b157e33c19f651524bc10da7f64d309f1adb2a54e4f7e99175e6fe46f88976ca6fade65bc74d25b7f44ee233453a6590a1257c6fb880d913da998172a6544c58eabdec5bf9e7cb78b0da9672610968c215331a9e0a265102809150247a6b1a8c5e0eeff23f8da085ccfe6abf3db3070b1b83be8bcfd13e63eda970f7638780d71823601491492814c200c3691cb7071b2256e7327ec48e84e132d064d4d0cde4eee10e1f2a4cf5859e332fb616bd018cb915a629201bbea77659320d5de43c392d8cb17950eded99f1c52b6f5a42a86850be85d979fc1bbb6b97cd2f0ef71ffc305988edc7358fef5eb7c3f735bc92d7eaa68f23df5171cf593f8e0f5620b029832b89d852b2fa79e3ab314723d2983cc8c408a79bfcc1aee907ddb59a2d04fe02ac923fb4d0c05c90c052b6cf865e61c668a2c28aca33f098d1f38a2272fd093fb8959b4af0777d074eb33a31639dc71e52eb692cd80ac3eea01afa0a795a05b81e5fac4dab01812f9ec676ac7a7865ff941cbf349a713f777b0491524f398519dda0e7c3ecdd5ec3e449ba8d2d98d200a913619cd7ac7186989009703e8219f9dcd71b42faa581a212f4c8c20f0d428689eb86da0f8c5b402b58e5c1fd0d566d4a70fb7f5264c86e0bc5b355cf7a5404015c1c53d5a2003f56113d779a3ba644725be4450b50b1284825ad5c5c14ce1e514f33ff81790c650ecb3610db7ff975eb3cdb5ced22979a80ff2a2269b29a4d2ad07db10c7eaf4db6792fb828d275cd616aa2c09dd8ca0916edf6e3eca5afa1d408caa558b465e3e9047610a5014a027c8202af15a56a8f204bb4563590b7a2bc237b70f386810b0845851fdaa6b07cccd57044403dd517ca98ff5c3ed5a7ba0fd3595044f183c7b7083addd2e4f74d3675517bd", .Okay}, + {.Pow, "-316664412f2732f074bd003d3a71ee72ee28d0985db924eafc5238668fa90d8c96c1febad8f75b1e0fefe6a51a792c6cc8ec29151a90066aec20906c4e3ce6c1e82185a495f8298a7d9362586cdff8517c44ad9ff7ba5b5e99cfe117ca35739503c1e7145d9946a8f4fedfaebe4083cfcf985a5559e8d065a4227bc31bb2666ebba387c5fa941d44c102acaecdb7875bd808be50e05b", "7", "-a728689b9448eece348d06d2c3f3d0a2589bcc2240acf99a9a5ddb68308966237e411f6078f9149b684fd67cf4a25c36513ee17ab6b82573dc3e63a34ed6cfaab8ff713617949c519330bafb1fa6991bd0df6a64192d5c5a7e0a6f3db3655a64b6c8372a4189f8e8f4c741a8da3fda18b46b624aff6c7d0ebc04abfb9bd59f3837f00a25f73af7612cb7e8c73d2f9e35cc6c1d36c266413f263130c2f60db17f1c0dcc63b32f8c2d0a476d1d3a7c9927d049716b5ac2252e00550f4b544125ee7e4a643678ce4691c60c4049fa7687c875b73e4d4f1cd7e6047a30e8cd21d657c9112584ec194e0721e4b6f3344d1126e6d7fe299f1a9f0ab09bd0b4c0ceb798d40bee5f6025b4008febce1d4149b4981d29ed2ac9c5abe84d8501f060e10a6fdd54ff545ac0403a1e49c99955bff360c10822d7eab459b69d7084f8ddab9b164ef7ad27f135c50dc09fae46ce61934798e86eca2d5a1153ef7ea229a46fd16e4f8c62ebf15cd1d13a568f73e23674b1934709ccce9a90e50cc7cd3ab5108504a71b62180ccbe1e4bcea710a8de44f72c293cf9005c7ce4cde3d4e640b067de29f7e8615096f9b398d66dc59045503cd1c46d34d41bdafbe3582904d81183ac64565e405de133075fd83b31d4b3b3a08e8de72daf8b8d82e47c681f9ec708c1fb84f6e3be621b17683d30b52ef3043b04cb0ed97dcf6ecdc19086a5cc0f16b2863ba88f4dbc2b86ea472c6304e6ba0f37e55f97149c6d7634bfbe20c9d2a526f54a7df2fcadc2f2e2599012278dfa908331de281dd5da0ecaa3c55a44a345c4a621eeade9a6ba9ea9a920f7cb9d6ad066fed2ede50977e4c7920903f06ea58d85a528bb0bd464a218ea509b6c75cdf5f199b7a498fd5110ab61bd51639059f26530ae4f31c259964c38664b0158c55f7849ef2d3450ccc974aa506746d055f0893dabed524a67598b2cf95480d9801910dfc77b5a22405681e50159eb2833a641b278351ee16f527479fb6db9c7d336b22660c2dcc6e84951e9352fb29e3c83524e14643a1c1201dfdabede1f5a47e9f9b0b60504f08b92f3061f31557526984d97722c6487705d818bb7da6e722b32344ed942ca5b2a525e9cc7ead5e104442fdfef920cea8d9e6befa382dabd0326e0adeeec8aa5610563fad8f6f2af90d065b1bf50690ef3f35ab1db4583250733ffc05d04ecaac405d3bc576a44ec78d2285fb8f202d721d6124c29ed6742fd480b041d97a5424e1c3050954fe198cdc0623ef1fc5ed45e6126a47b3e54c498721ff3cf96d22bab7c1f776ecd79884b54fcf5343e952b664ad169c39aefef0877d312f4fb054f1c7257ed465c74cc6c2e1441fb04e1108593b0644bfcb8eb511397aee384eaea2bde151aa9c964890b70c3be5dc304f4202c7bc0aabbd9a69b87ab8a2683e85698c74a081aa853dd3b5d723e13a8cae25fa2beb7877368144f8dc69f4f908bc522273", .Okay}, + {.Pow, "-106e7657554c4d87feea332fec11b79d4a5e9f649417bf5caee357a937d041285c24fccbb2eb6590c1ae4217899a2a2ebbadcecf93a33b3375162ef8111f436588df33075a53050b9843171ba6e3c8799a2137dea4c21bd478107eab874a265f22c59c955d90df53827c67b7e0d26c1d3fee0f11c91597cbf442555c9ad0ad175ba131359e364bbd6e76bfd6435dd8fdb17a6670859b", "9", "-14546ec57de86ce49b6376464ab7b721c7febb9d542cddfcb392b970c7bf218407942e29111ef53624b7d368da76dfbc2eede1a60d5bde678675ec36e7cea566d6ad6e326320e944c34e3f4cf25579d0b2ed1ba570a8350a864956afcc62cece57cf0fa8cdd4a9f09f38a4eeecfaaa5ce1a2911595af140bf26613ed19533e5c5f9b6c6b07b519e3bd17f4ff035ea31e419bf3240854345537582fd4bd5554fa662e134d6cd9951a909e9af04b0fac3af0fc84000651435423913edca6820142fe5aea3c9a6cb3bee24b12f7e5473babdfbeb1f7c94d4f21196aac3e6213291069273ecb7cbde8e46b4a867579d76cf418f731d0fff6a0f5a756690f9d1c0e1e16625c9483226f2da86a39ff10fa0968f217d4740520634ace0b79dd4ccd1e91dff940ba592c8d6c1b2dc014dd92c4d5161eeb445442031a60965759da514b6a3cd756c4add9c6a27fc711efeb6103830ad61be18f1a6f53235718ef2a8e74926bb5e2681ee1b3204b31c4059a1f7f490c5d1d4d9f14b2d7aaefa0153fcb984144ace03d3d6e62c41069191fea846daab01e250836fc96b3147a2fb09d8c0917d63ec4f75fdb66c20dba92d4a2ed6375406125c2ba95030e3d0b7172ac6f36495411fd0434206ec992c6f4c690e3d82b3877120b146695e07e6a29467131316db2bbaf2cbbff1fe1145f618dd6c7dfabc7eee93803bec1e3eaf4037eebc6e44365a60c0589af66040789a4d701c42c9c8176e188efd3518bf3bb0febf68439393c54679cff8314ed62fd74ad152218ba27d590dd61a242bcbf03fbfc62d1358f4c911f3f6e48315b40b25a6becb47fc186fb8d4839f4b0519152b703d62732247ede7593dd5444e82affa3368aa640dbeb9dc7ab286993c2e0abc3d7d8f62fb6910c936fa8dcd8315522b3a15c965e42a93d4b546cef2467451aa93ad287dbb0d9a493cecd1c1ad4f9f105b2b66ca874c42bc91a72aa2b8e42da229c4246bf41d697a330315ae6bb8dcec1dbbe697cab6d6541df92d5e522c1bea8f1c3617a49e9a5dd299a82e13c6263df2975ce6eafd44860ec5dbd32403e888fda784734dbb60f9d8427ce79ff949ce07e9ed6b2a7bbab1712ed0740746ba86eb80235257b30f52e1b1f20cc2c2679a4f02ae91700c8efeed14861aaa879e3bd73a81f5813b15f6b4431fd03b16311468b39b1e09d49ec4d88435f851a63cb7830cf713b6fc179ba367837c40d9b7be7eb3630efa53ff1fdd6aa1b251fe59f368dbff6a81b72214c6437fb89c058a33b7a1851c1a1b5cccf0a1c8fa3f39615dc959e1003741432bbdcbafe6c9cf2a763005587741f8680370ab845ff761912bc233bce313b15986cc5400d87ac38dcb191dd3e66425d7c74e8b8b62e15c625dfd95afdaa831689ebb3e88449b6ba164a0bafd11e7e6c078612e39ee633847926409e60f344370615bdfe81d6ed2cbd9ede96d449e3af6de548ea36d849e60c30f2884a94faeb8437037fc8615230e6b80cbd1194a785d306421ab12225216de4862091a2b4f43538a4303534cb08d9b3138e985a03f927a037901be49026dde5e6c6ee9e309383c2602dad6bd56ca75c287c626db6edbd23b22a2cf6018410648d084ff3bb8d0a956fa1a1f9ccc84cc0a59b8c74a89bf9a203db4ccc59f94b374b73b01a6a3695409338abb9f140cc65c334e5669ccff3f89d87950ad03c2d3d6223053ad08310bd596b8db235c490c06dc22e0f08108eaf39608e2407769c271f6a214d20bfa2d7d7713098da5f73e02c520cdc3404c1c647410afa9acf081eb5542517006ed2ba83968c8fe9312cc37acbc1e890314ae3cf1beca207db06bb36ff02d10c6d987d94af78f264cf17013ec7907335bbfb744c9ee6cd17c864abc6ff33e39e813b", .Okay}, + {.Pow, "-d031b9ccce4f2a9c228c4b5bd2a65a10a98f0c0f86ca8e0cae3292d4ca3ac5ec69be91a992fcd43da53d543b4101c34c5c5c9e454d8bd1c6955c238750152fd76adfa7b5a83fe6e558d5e206cfe569543adc3b2604afecfd5274a2fe2fb0d0247b2a897477a34e82e57b38b04f187bb5f67b0250f9fd033294f8760733cd7f42515f195ebe227e4c9f0ce76141c84499ff1f34096495", "5", "-5b125e7d568c17a7939f205d2d848f4f8597abf9ef54c55ecc57ef9b33e8d623b387df15e6b35bdf16a5adf5c9326bcb2f495113e54bc3b72e029befd246f55bbff7e3cd4bc4a0bf5dffc1ced2f4220cd61a3a196f0cee307b0583f48fead6c5738e6b8d0bb4cb33e7a79d7528be6bdb4a5a9d32476f2d1fb8141d38a688e3d484d2ff95f9d3e7b6ce457988131b74fb9542429f84bdb1e41aeddc9753ab195a4805799bc9721030f7157aa8c2b98c7911723f3ae44ac12030a8026e0c7d3767d7ac170d28db90ad5e6e8d786ab1ba05c3cf9ebe860f436ec8fa52ba7a4bc01ff4b5fe4eec862d32cdd437eea87aa86545879336e5582381ab6ed983a7a77417133ed51f818f36ad3ccea329151b1da65dfe7822ed857a25c1f21ebf389b1554827bf96b843b22ad0edbf774e5fea4779eabe5df341ef76d601dc54409973a3ae005f5a1c10052d5f5c4edcecacf9fa11cc0989869f0257a2e348146838feed099c7a102a55f50c975984e66d38b9ea63cee4b5dc96ba21209b232fe0b70b2a7ec67ba782c7affd9320841ebd14134fcc3c36f84a83f0b08037b9124d9bacfe9f3a1b73bbf643fb3bfc587a923105c0bbd2744f280115c6703e72a807dc431acb26cf2f66c9d93fa168e9c7b2d2a1bfa613b327a2e799491d1347b5461af81007726bfe382a688357d951c7aaf3c3a6fac0e1b5f9cbd2075d495abe50cb99d44e1cb87eb70580765f358b88e56d316ac75818bd7efbe0afda10e6a514e07d127b1f62764227c50b7ed9ce47dbea216fa0ad72f2fdf0876532819eef802e878a681527bd275bf094dfa7ce6bf9907cf3e0f95da95914c25d456f5ab73791d79dd6d23af0c33d0c7e2d2dacf248e9383c4cee44f4717b6e75d0db7dd4f01c1c56ba24b74ff1e1d761aec394838f7333cd7e4bc9403ee199be7f8dc8d3eee61c08bfa1d9b61eb681967e8efc55458990a0ac9b400dc01837d9e6962912e337e43180e89e0473b79dc328d8be74d5957b2133834768faca639d27a0cb6817974e4db4f42b10a980f8389691bfd24c005", .Okay}, + {.Pow, "-7037330e4ec6b192efe28f2992f706a5e2350775243f75e4f1ed148ad3c842d3758597ff017b41dc7c4cc1c7fcbf2f305daa8c1aa73cbcb08cada1d704cd6d20eb1c5b274dc77081ced2eb360ab60b9d0b0b9c7d675171dc6e04f73ae26a81ba789d0bee3f9b5f9117abc7c19c67b87de84a580c917edb1efa379d8dcfcf455535e42576f2531b154b440b2820ee7b27d6d0c34e1e52", "a", "1129eefce510ddee3a9b9154f68e379e1374caba940fa36ca4268a25b94097939b9e7edbd80071c4660ab00184a49bd5aa5361869021eb0542c31aaa303c9b71630be7afcac75152fbbfb9b8e634418a07fa95023078ed3d93650a4a50399170f35eadc3f122baf99570a25b7cada47e192f143aa5d8893945c6fd9bd5d12a3ec314de9faca820453f9433cf2ffccce9e5571d5829bc8502cae9409826eac42590f82022ddb3c9b4a029bd13eed29fcf701bfe018b3e2d34b1c5e7c7b1dcd0d6b18512e65a97523fcb0359fd495f7039a733ebd4af532b91eec82e70f1f6f8897066539344b326b6cc80db4a6bfa5a41b9abbe3fa8265c52faf5a56e26d9961e39b49323839872a8c60e499cca77f65d18b7cab95bcb3b889fa8d65a21eed7cfcdb4229da2059211d429a7fb0ab1c4f4a13b1059acc29ea8b3f56891c177988486be5e09c4513e6922f1beec51ac418d4ac50753d4efdf800fed843950d56ce72b7d129763e5f19a6f4a5f5214a4241e26d093bc8f409e6ccb45bb63ab49f14f335b086fec2478b6630ef92df2ab124369d63010d9e86f1f7b95d375817231c5b9b23dabfb8c23b279b6918381389624cb8798c967df8661946751661b27a7627873b2249e866defe68e12011b59bc479eeb8cc42305b6a47829eff104e90868b951eaf8707bb7ab373a5e0f7e86a95232b8af2fa55147fc9c11806d25c7530211a2b658e594df1a55452c3ad026e8e19489f16320161cd3058ca0bca3debba259ada2c4b0fd241ea4eaa1f755c62587fa02e43e823bc066c4591377ac6e61d692dda41f1cb8ff02fcd72fca0f4f5cbefbed95cf7c69ee52e58ab7593f41f000ce73530c5378a8f7a166bb7faeda8d6cd6dddb4d0e4c82758b6d029ec36098359372d826d4fdf004af06d213d8d5c62f5c6305f4ff49f8b64b9d13e827225b65cd871d45df6ac3482cc21bb40b66360e39f01482df01bb5c2e2c2ee8b9c9b9d722f398f7774be86166b750717bf5847cddacbab8fbc517216cbbff9d7569a35d13413bc83a1502d4b3eee09184a644de7038df3507eca3e8c7feca657f2777b364d03a29dcc9d62b0c577f68bc10280621e38b932e51021698e9c0e3c4bd9abf5cad0e69bb548bdd3ecb8cc5263cf79e16e0643f23952e4f0ad31002a0285d3dc04986883433b0b75aa8f2fad732b39017d35301cc6d67249c79affb5155b9a7e3050cf0bbc596444d1fce47591f632eb35d866d711a88430a027837e4a3640ca5f0521a1c4ed5d63c0c71b19d8cf0ac31a00983c90b1def68e81ad4f2aa27e405ab9f6b8c782a08e3fd017b269d56a768ee01b916e99be9f47a95e6a604c0b726eb17f106dba36fb13c02a836062556194c976db672c56be8ea3ee587fe07adf1493901f0a157d46c185b1c3460792bd9c68ec43e36102906d525ee9a8ec0577416b94da078d0dc79c10a894815b14d643a7b02cba4439e14e4784b96358b1b99f1e568ac78e75552bf121b3732a0cec5ebcc9b7e7cfa9d4e9818f876bb56c20ff7915e04d0252e7a901dc5972c512f9c3c9b3adbcd9855a3c739cafe6ede71bc1a25fe59b3ff2ced16578f8f3c5625b1ace12a6d075922dc5bcce1700bd385f0d76676aab04ce7bf4e8e6cfc74eb765c5461edb9621cce74ec1517185095e65ffe0aa1a72a77f696c93d76722a40389db1a9c1a595331d9c529cfff9571d8a1e660ff9da905f5e83cb7341b3f404756a19a28d8363a978ea7ed2be8b199c28af4c53f26b74c34b59a390ef93dcb8232f1afacc5772cad5a2c3101f597e17ac6c1e9cd3dac2904f3d5298efb1cf3bcf2210712ae8d2f10da1409e98fa73c86fa1a05b0907080ac6d58977ee5a8a66eea9c8052f092b9ed0bbd83c6e2d95ba5e32e8217bcebe6a6f60a8e4c51758997e0fe98bb11cb6087ce8b4edd6021e603c394269f8a6cb9d951c5511f70a462986d1ec961292e461cc0b879cedbf28548ee321efd15070f1ddbf72f87d07a9ffb81d7cbf795d92d1c5e23ea9d697a9486b33e9d5614a894328158381844304a4ffaf612773bc5cb40beadff601f4fd808f734fc6d254ac211b50ee78f835845477f76305f19978e1efc34400", .Okay}, + {.Pow, "1faa4351fa9859bbdf528dd8f83cbddf785c0f2e04378582e83b2cc557e31b4423a220c59a968e287535a718688aaf89ff8787aa9ab44f8b0843cfd0d4eca72192a1bb4ec3eab515705dda79afd7f21eee38374363d83376f6c949eed20209d6e1079fbda7ac78930d51ef34eb852ab3e0d81422e15863f36b83254a205f9e661f2485049fa25864aedcc5900e7a8b45b3eefb73a617", "7", "76e96fd575e6d8d54670e4433371a2f3238b49f0fd8411fb01a95472a100df492ede19661fce6658639a233c8bdfebc46ffe8714ea251e019ac4a830d170121fb7e3d6e8cffeed0dc36b75812bade55adc46faa7a14e618813aa00e7a1db7a3ae0d135666e16e438249fe45e61330a3c02f997ee9430fde4cf42a89f6a1bf844e2e9b4181aaee0ac6db04e5f2d4b055a42896991f426a8c8c794421e2e9193f9a738a543183d90be87a7eb65d5e302dd9bd3d530f8a60cb55f3cadc129742dc657b9adc2c5cf93ceddcfa612c89a37bf0c6dc5d417e91f86b320427735f523062c4e90b2d060df6a548b5b22acc660291d872ccf194e0e815a2ee4a33dabab4c4a848a7a263ada47906483223e7a82a261cedfb7dfbf3f965536f1397ad9442b1368ec6600e8b9247f71302d1cc67054b5f9ae8ff1598b0fcb40018409f013252aed8663463fa78c403e1618821bdfb805372e6cd80acbf612369ac25d189e5770fe258f90400687fcd6914fc897c77545b8f0440b86e1dc7c22f63eba3555a2599a16fb527de9b430fc5f4da5059ef45725f6cf9954bae035bfdd6778809dd5b3a24c89acd5ad2d3d4f7915428e76fc86e595fb92b23f4eca123d7f7a7fd963cc36f94e22c9b55ec5a016d1377970d32698b75888ae2c6f16841ee3d9dc2d3de4392fca03df7eb0d8931192c15108065ffe16a6de57dafcbfd7c4af106936b0a0076dd3296103eff049e8d2c5b7e19a1d4c6328b7976c1b6d4b11eeef053ba73652c1509cc35a3f819c7a6a3bbe8347499e1b2fd4daa1ddba654ed257293e31ecc9f376c5ac942b14a61b8ce658b853bd7a760ab81e737f678ed3639703521478c9a2c0630a060529ae8d02d5134014fe8f5e544c37802be90a5e993723c2c375e7ec25f56cc5e607955b0389c168002aa8cc77d249f8ee0bd4574119109829d0f534e36209bf2b8c60e1823a59c79ee2969caaeca9dba23818e17d297ce492fd764fce7efca7369356816bed569498bd121016ea40cf1927656218e07878afcdc9ddbb8ea0aee3623848983851fbc5e42b6453daa37e134b056619bc23182081d83198b326a8dee7bdf695713613d81fb3ac576ca94c6ea83aa3941ef777a083fb1b3d86bac1894f498bce0435c80fe3f439e972c3da2105ee28a0af8fb0e309f8764476e47d3691ae243eba6a28d44a914464a1bf0b9b3ea52a059d768fc51e8dae3c048b78a7d7c9bb0f4b4ee2087d1c8d6014a401a7ec70c48f1c296f4dd85377330afc66e04e3514ef2ceb562e3d6b55285a609950ceb4d974a586627ca39eb04959188ede74b24173468f04bb7b56d92874dad9611c272ab1a4e09568ec49aa6cc2947c40325cd4f47b92000aad840c98bfc84475db283718d2744db0007b5a8091c1c0cfcbbef009c26df410abd0575e6db4dd14ebdf4d26d24d4e5959ced266a294349d79b5b9d81efc2b2eb1d8f1b90caed67", .Okay}, + {.Pow, "a4cd02610550b69281298498ca4c2f2b5b24d8d3f6d509a559ea332898a554335978fd8036c1a8bfde9caf89162951d017a5aa51fd53c074a2dcc08fb1226d7c80b58857100b9cad6f39def47a27366bc5662c09fee82e9466f45f8c1c0b2025862cbde364aede8d128d388b74533834800695ea4d3f1404c84f9ac8598723856bc4aa6e8cae218538dafa772da54a425ab83225b63f", "8", "78d03b3a55412b4915a0f9dbc6e7d40799eb66fb001987944cc88397c046ec37a58be1a13784589a24b896758b72341246f5dcbff2ad33c0b1ad42ac16853fc8a048178496fc9250cf078e8d0418eb2a589297f5db4a0451c5c6ec3ab702a132e4959cb932af07d10f204d278f3394754a9d1d7a80b782713434b8ac64eeb56a3c0fffa0a35d4ba67d670a5c8402e87d34b574f18358270d11c036e42909aea95e66ec7d68cf50db8f40194c5b3ea6507626fd471ea05e71ee4f9a6a464cf6869ef196a90ddfdc9a4e56adc4098b1a81b7c4aa1f6adeba4759f70b47dbfdbc3750e3c5eccc48ed968c5b6a55e62c306a4d2233aabd3cf169f7c098859db6c2a5b165b14a22a28a5788e8fcc3fc5b91381ac1c0c0fc0421da3a824aaeb88b6d106f7a6e7e9769cb6154d428bf15f288530d900b366d584dc058cdcf43b7fec1791970b79edc2779e1b230bbffcce4d620e8580080fa82967e6924bbfa4c8e0ca2d2ab67b1ebcfa6204ea0c73bba8f363eacce4cb5ed1a89aa819411ec5fcd07f73b2acd1f501590b145a6d1353b963ac875869ea5315176475eb2841ca31f0236ba589b6f1773fa064bfc6a27190a9c93c32abec49ff9b014e5437bfbb3e5f522160968f01656bafb878436c1279347e801fb64800d5ffa65524259cb7a92379b40227877bb1aad04f16088367957f1da8b9dcf533f164463a8c702d36d614b808a6dea05225023648e0ed097bb7b44fb867cd3588de0095f1611f166a7f46dbbf02d1ecb81d0705d15b046d7358bfb58e8bb38a1947e5d9c54198e694751cd1d1ca55502f6849bc2d0ec2b5269b3d322d928a6a8cc4cc9a2dceac17de7404294f6a83ba76ea28a7c47a6e7229ee53b183847624e1f58ed1c2efba9f5335e86844cf6d49cc36c18b2ba0a76e702545edfe7bacd42a88899dd4cc59fa9b949c5bfc7ddf919d5172abddafa162e886ed23fb231d73443efdc38cabfe36874db8ef7e502f2f4526617f7557a9f9b0ec8a556c59b531d41a02298d73df16c6ad871b4a27abcf775924ce8fb87c08718e378f9c2246b6a47c138234b84d515f138b6ee00ad3fef1ecc62692787bec8e6c2aebcd2e5d287f641f34f204e8a8396e9fa380a8f5bb73c91f08d093d449c859e6b3233670fff54012f5390551455f1502fda0f76c3960e478e5a5a04b4e23d9436337dfa4c712fdb36e13c1b72fba61c7f63dee363f440171539bcbedf53032f18d67cb69f12fd0ac2309969692d04ff7de1743cbbaa54008a0e4d93b94884041ea99554fe6df7bd2c870db022c1cb426403f128da891c3bc91b71aa641c947e8f590353c3a7f0c593a33498ad8a89c4c427a43092c323a499e1f1032df300e1c5b0c57a0db9e37195f655ee5dc39f295195660f416754c07b28dfbb03b3ecd7b145542da3a0ec413899b61e59ef66a94e916d7c2cd0d6f5b0fd885a0add8c1064173d75ff9d404803ae572a8c70ac8167686852f7c57c4bda0f5b6a9013f76697289572f89e586cf7dfbc10a0bdad21a235d57f40eb6952f0c9c49f104e41ad2f1ba9ef7117ee4f3367c814d7d2c7c03a2229139af3f65a30c38ce16ebffc80c2462bbaaf4ad4f15e3eccb49333e1833cc389cbc0942c5703759ef22e5eee00e40fa7b922186f6aaca729cde3ae5a159830208bf1f0feb0be479300b5b9bd80e01", .Okay}, + {.Pow, "-9e3320a2ac2f1ccda35121aa6cb8677afdc2907663a48e1ed72b7d938d28dae9dc7af059b88eb328e7ac415ded09b78d62c410f61b55dc2a02700213ef6a5f6ac104fae7bdd651655891ad63d7950677d53364fc7e1e1144b6cb8e7e739cdac13b45fbbfc4e2966bb8e3d0dcf816751b37c22fafd7c4cee4498b07de0a8a1452ef6edd2e2da8d69caecd401bb7910d960016b68ffbcc", "3", "-3c69f81974a26cb2869801b51bb20784ba95e35a07626a9d522e5a34a2424a843e1dfee0136dd4f5b087a63927415261a70efd50a96edd8674276927ad0113eeba6ff947f5c18f671fe7201fe1c19c0948fb67528291108c46c2b74ca12c53584b11ef402848bbcad1926b8678f42e3d1d986fdf881faaec565b7d278ee53ee362a558485ff4919bf0ab7a87837b0928b93cf4b8852ebb95f58c1721f31d378b7da4b9ce6a6385d8af8d664f7e9f234fb754ad82ad9294fd0ed2b801e90a202e0ebfb2d6ee3cbb0e4f2ad07c7ff3af525e0564a1d5bdf15a2f9d723bc71c60e017d99ffe8cd756f0f55d53711e3b017677ad31f08f8a5aa73a3c10361b07a532810bde99bcd14b290b17e6234ed3fc1b9ac5cd8bb6afa1179a2477eadf862767601ba197c70a3c34bbf229d72a8c0333cfe4c73650296236a999f1393efba5ad9775e33fc03fe704c871df039f92b3315e61ca8e06a40636db647e7a6c9d3437549ab28c1f1f7be07032976206dfa3777ec90cdef46f60040d9b87960235ba9dfc91aa915f3473aa6d1d12f9fc01603a32c494230953d7b83159768695f5ce8b18a3e5da4838fade6adddd3eb18b596df21bbbed38af0d825467be2168b6a8bf1ac0", .Okay}, + {.Pow, "e5365cf9eea87cb8e2c181875fce10ab31953fa58697744f91719dc32dfa5ed8fa0bbd5c43ec3056aeb262018f786e87a13b2d732d790f86a0b3cb0fe7c30b70b825d4f6a8936a036a3c0644c797164362bcc8ca40af08a189094ad7329d2ca6930a44d9d24f41c78f135a92358b6917a5e4a73d4f3ddb854cf1505ceccecd8494045e4984d3ba676c5cc910a1a432d6a700dbf9ceea", "9", "5eac15d78d47baa363089b8952119bd60c230e19772650ce9adac67e446f669a977bd5f237a7275a5d73e0add9341bfdef82fc23644728676dfcd59f055d12819b96c3bd4d62e90cec001ebf31ed348ea6f47a720219665c8743d0f868c48e99766a20eb030a37dbb9863b0faf7e97f95000dc11a920f94a05868e5a70fa49d85527bca38eeb564815c48fe974346a98654211724ccface443962347598b6f0286e79d9f44675f56f45ebfd213b02c057513df8f142d5c1f17318f0a25792166706c2b271f5318d78b50ce26a2ba02fd773610a83b95ab0054a80ae48a4894479f55b4fd7fbce962964dd683672d0a9828d89e6cba08fcdea3404b768f03d932cb89befaf9de324e98813ba3c4743a5b183ec96ec6a5097f6c4156c2b929a94f20b9a110ed3eefa723949731e0f18f5d1bd28ef830c5b531cd6706488d198c4b22281309d2630a3c801e99da12816685bb66c9dc8c545fc1b1fcf3bf14e0f7b1294f81d9854e5a931ba842da6d931a8a6ea07f1596c87f85a3cf0abf1afef3de36a5f0654590688db3cf0ed1db707cf088c6eb65883f839dfb266d1949101b07fa74d9da9bc851b0d9b1508638cd877d14fc2f0f82f958054dd3dcd52a945a645d2827abda83245b6076763dd77f31cefdae20702406fec217d84f0df0a4f2ccc3f0b3d5cdcfb77c7d1bc4cdadfaa211c33d793f5194c5374d66cf9ffb22b4067bf4b5699547153af6c06efb88810a62665464e4b160797c6268848d818d060d53fb99671faee51f95f36df64388aae30f97d86ea3373c31896b697a395ddf453b91abd766fcc389891263bff8fa9df516beac774f3adfcccc7ab4fb3745b66917fbf53c785b9d0c81b9009ed563830713049a852c6d7f7eeb1809114e2e3fd45d456dea55974e7d59f22d9ccf811f227395b6d4918553269b7c8a94587e0736102a51ba93ada780b9cde8f78b6f456c693b95f9fe8c42bf8ba6e1b9ad20769fe172a087b640afbba76dcb0529b9c9ed6c557560a4ea6456b022c5d79f70d6eb0dd29dfc389fe1a152be4b830e659774303f744e0849e42d0d166738b1176e1701ef83e0212a10777e0a72bb6a48e0621dcd79acdaf6ac2e3f402581bdf9e4876b1e160a2308135dc1d52631b74b1c1a063238908e8f14fc16a47be98938a775b74006de049a283da052cd433f2eed7b3bd9521c38cbd72fc6b535117289e5d5ea7288a68cc576a23f3402449a1a6006973a33bd91c5558c27c43a438259d070b69f6224211d8b44c39e1d39acfefd77ab9a79ccf37e62dd3bdc28e2e3d7ba60dc3a30f557fa29fe79b8f182cd9cf32f0541d19fe55af61c01c5fcaa16734db918a0ad84187ae906a715fab50c0875472671bf064bcddbf21f642f79d22825a1f0295a6977b7254b638e365799102cacb89378c5983543b4b3046faf744c405f2450836f70a3af0898e5fb848259150982c0c0618259ed38b4cf1d28a567f0649629e41c8056d1016e7447560d62d305bbc699d143d0ae5dc02b721446df56c3eafc84325ffe30113390110275492a24e86cd907a7068e1288c27ace6a3698f7880af70b38e3795423fb35bf82945403ee1bdba7f5585f737e043e59834e6d405036b4e2b519ca45eeaf7a44fc1e968652c6ffa78bffc4847d81a7e45a5aa21eba2b104cf2ecb66cdbd08b2f6ca0157293c70101aee0c37ddb171fa9eedd4322cf5308db30afac9aa69bc3bc92464f73908ed61c3a6953322c212931ecc6dceeb036e966b0a63270b910acffdac450f544ecb9fe6faf732d2c97d70ee815ad59ee5b6b1a8772036c5f486e450deb13ae38723812815d7d2c6968408ffa13590f3a48d0ff6692895ef8ceac869c1eec7b246fad1e1493b1487d96442383ead2a148bd930caa00", .Okay}, + {.Pow, "-4c0467915263878b73af42b4ed69b9edda4007ace9ad01a50c50c468c0f1b1367d1e1a0fc1753c3bd324058945837f3e13fafadcd411a1257d1a10d027ee7a17ecf4cbf5c67d321e1e63fda193c80b3427e7fa7d82ce1d41eacee47125e3be68667dc72daaf1a614d3aebe650b7486f80ff6b87cee79ca67585030e490e4fc73ae9689f1ac17cd71e3131e3a862301f58f755846a225", "6", "2ced6bc47d5e3d36b8813ed5de2b853a9b3025aaf55798b3c90ddd1d8cfa0086baa3b9085eeeb4942e589a690199af5e367db57215ce557b1531a9b621bbd9cc239297d2058012a40f93452bf842bb892beacb2d12be8e64f5610b6ce200c8b74c983d445000411aba0356c534e10d20baaad6f8a7b963d5641d122b1b7c44e9ddef802cf30a034b05413459ffa03dd85d26a9c34b3f2a48c9159c2e00d1c10eb2dce724b3789018eed60705ba5ab6db00f32a638a02633051a328c258656cde71857ed329b1d3049b422d6daeea22378e8b60e62b517504cb69cc40b0e8dd80675831af94de8dba499baffc8f86c2856f9a19552cc738381ed9c8fd6f8c2b0c2ba639a79090cc101402b37ab910cb82e8b96407a10b09dcd1d3c737462bd28b2135e351901f3010b0053caec2998fee9ea129e3fb88fe0d596f2a90e9f1a04e167643bdfae1d1f0c5e5955a293fe4bcd1aef342c69b3a1a9e62f9c5042eed1af4c1b47163e549ac56fbfd3b6260f27bd8f89d60f859850a214f44ec6922dc751eca3723e0020910adff4d8eb5bb53cfd02d80a133173228f15702606183e6213a0a51afbcc2c25d1b430b7fa0fc82de2c99379d6e40c235640d03da7cad99ad0f63c0302ab05cae4bd596b33f95947f0c4121d8e7882bc8a51b0fbce3460944880f25eb5f27ddcffec044b25cb5b10ae468f06d8dd4b04a1f20bfeb7af5913a2166d5f370f5fb722af38399753c022c5cb315394d1266e8c73f074e5326fa1f06046084c1746914dc05b76b7a5e4e2c2ac5319402b0bee7705e042e30a3e87764f1c880fa3e7f46ff45a81abc0ef7b472236fdcbe8fac278ddd543a4a7b43a2d8988b6f2fca4217541ae51cd364ca7127811c2944fa5367b1bae6fcca48df653ddafeb95170e78a5021d712797f9e8314d9b10bdf0e9d3895023445cb988b889297eae8c8e3a1230678f9dab9af1e860a36dbad35fb5c7999a17cd659c703f9e0ecf9e5407afe83951e0e055280d557f5f794090757dda2db4e8743d911ea9dec98db2821bbe10385d49104ab5f45ed1d5adc9acdc0b691bdd675ce0b2806127b589e5ad050e412d695da26c50f236fd119d4df7bed989cf6989e465a205e89f0c64cb2437efadf57ff6c889ff64b71801ae567e0fa998edf2687b8ee6d19646944538bff259735b0fa256a7598ad11e17486160904b26d26533dff77c62c2278b5fbf4a28522a9bda23636ac1eba32f008ddc6ff750104f42f705f683231363e9cc9", .Okay}, + {.Pow, "-ef5a22e0aae7eb211d95e66232f05981da4d165413270ce749e82ffa70ff56a9c860bc2dfffd3278e05531336bc96058282b3ba38f62b30e702ce60cd0e56dba16ac58c9e39b29118f62b981c344485eec1ee9282aa42d1e540728dc248dc72647cf500b8847414f9f51851ba2a71b63cfb76982db50e037f3fcf0f0b63646282d1a8750293f47719893ff86c72c047d007ea38e07e9", "8", "957df71f012543ae9d068000800137ce5dce7e626b379ab6f3ecf4c0a1bc8adc2c3917ef733d6ff5d328ef0360d804cbad960a2de1b7f172e15f59a59d5daea59c18d4994287453d863f9e81d1181f70cfe31a71720ef72349568503728600bf3f4c4f6002001da984c77a9bfaf7cb3ecbfc6e6d5059a653d2573e52489c84f1cd6601a92ab8c0db5103d60ccc325cb889ff282fe25c4713951f5684519baad0b4020f6d7d1dac0ad6097fa195e3cf78d85f6adfa2c076255754068260b0c143857af1eea89a097088481fb6882310d41eafa88cc8573613fa8e2bf9b8001d6e823d65292b9099738d1de4b927945f64dd7343a0955b734bf142aa04c3e964b9712c656b4045b0afc5d60b7093eee2f7f84d5c3d2204af5a4f30fe36a35692e649eccda9ebbeac93c0cb5ae4c87a09c891fbda20748d119dde3248a0b61e434d15716703fd6caab6a7d10120b972f1eb09e78b8f768936334db6038be01f3855a13c55981ad523676321948d3dfd54824a6291c5f8c6076caad2dd12fe392b5bf1fc0d7681cfe14171952da7f7bfc98d74288e70eb2fb8180fbd63656aafbecd9f9a1d551cb0f50c85ea508d59eee232b12f68910b81089771f458f84b232a39baa64e0009d35c79069b1cedfa38126e7d26cc7dd76ca3b0039a67926e11f6e19ededca79f74912d44a46fa5b2776ab39ec098d0895e81fb1abaea843fa4c2c687d946b720a0b751cbf4760c520c5ab0f03bc98bc8e4852df8018cc7537f409f1f0d6f20863d24fc27ebfe9fb9019c8c243abc9bd92ebf0779b3a094d8fb523d0405c4ea61cd8b86fb047e88c4d3916790dadcdd772ee9c0fbdccdbb8d474add785acf26b5dfa450a85a9c992f7a99048f23cb9ba060a97d10ce030b45873ff4eee306e24c10068785ee49faca41dfddd2739e18161c8e39f3b99e4bc4c102d5c2dc9d6c3275955b65801959f7eb29932d30fe261be5d26a8af6b9b73d969e21ffaad47ac436f2515768d1f628d87f7289890c81c5679302418dd2cffc9000b97810a2b62847370be2ec245f1b7901a02cc5e1f0bd65a28eb98ad452ba170852ea7e421935ac949f9d6639f1a71fdc2bef235153de4c3aedcb7ed71e275748b141f221814c91961072cb61b664607b5df724c1f44b7e7d008b6efcb9c07ce7048d691fce272901aa67eff927fc0a40ba62ed139535538504d49d71c2f5c9f76ca6c76b08414af7a27cc334b28763c5f0feb36e0636a7a8c3bfc090f9eacadf76b70c41756fc47b31d058a3d845a6d06b61e21f62ac4754d761c07bbe229658aeb09307192cfd6dc109a788739ec6375da83a40eb998170419b4c3ba5748f828031dd3418d04f69b1dda1bd0d614534b7c5541b02184a05c799036064a231eaf6996b1334020bacd1bdeaed596a7bf96be610ebddee46af0f1e86d75156282f419bbb7cd21251578e1d56e09d1f5c288b83de982bfea4b70c22228058002bb2ede99b3bc45fef8aaa38a7b44d9223a71c0a9d1139cf05a1ca9c9b08069a78f69949a885d9ff9811434e5429036443460c3826d412029662faed86ee8b87f11768280cbc6bdc717c993b0eb11bd39dca5f15c611367a31db2c1c95481cc54575437d5551562e5b4775fa4972218408910d149398ee909285c21568a3620db094a4c78284457576779bf0f3465af0c90e41", .Okay}, + {.Pow, "f6dbb334bc2c50fefc0255982414e2a21017d8863237ed296cd99b283808b35585298488783ad5bb079eec1e58ea7df989f60f72a9bb8d3061b2585cf9868e8e8d2e38f634b7ad15c7fb06b23d811dc63f68f51bb7ecb413042bd18f03d9eb71d03cb4dee0a546def6050932c038832e0df51d6ff9f9bb8047b919e7a92dc010c3f98ec474357655e41a5a5b79ef33a26d83f900ed0d", "9", "b88c2e130ef83482fdb0101ae9c92893cce954216d72be3cee944c3d9f103f1ba3b97d05e6b89e667e8171c51031aa92fc50c6a30c06a63f61be6ddfaa4252245a2e30d0a06f84523cd53a8dd24256ba7f6ecb479e5001ecd8a44a5f1f7f0fb2788806e477e85b7200c0cfb31fe7df9bb4e4fc3a46aaf0b4929024086d5655ef13cba8b5a3cf3e6ec8c2023022a2e3f7ddb37ff5f20ef88a8b3c6314b9d58ac0999b19024518fdebfb5eac5c7fa910b03431ecf0352e32e41cc8723ccd335fb19032cb5896e6ee63b25f2b86e33e319bd4f18ce7514069f77878221a53f944a6d9b4acc3a4228f93e69d0564624396ab8c5a8cfe81e609175a78b8b5f7f4457617420156084c10ad49251195d45479625380b12b3ed99b155c36cc6d65a5b5f602982ffc80bfdd640a43861a7ef503b3b8f4981c7af21f5cf6e24a9bbd0b7e04d6312c6b1113d0cdddd87bdcef19f8e45aaa9f9613b7e8025cc288d71226a4824d3ac7164759d3a7d1cfa3d673750aa2a32214303ae2ba03f61b92b88da8728a2fae462d93ffa43b5e4e34506ad8156bebff33e8b6465c948418a38ccb44de414f114a513bde585e863491d3634286b55c9f5ccfd1b78fd0af5851115d5cfff8fb44fc40771e7982db8b1d251dc63ba282c49a16aca330e6fd35c6709723efffaa44422f6498ff49b0f443ce7968078edd38c26eaf9dfe258b31fb89d388ce1aa7758a100ac7c99340d6ea6bc923f809e7c6da77907eee52bf24751d84f7e464de6ebda2c578e9200fa24e8b501a26e38296148375c4f622da873ff4117f7d2d48d417cf4b54872e1d222c1bc24d323f0adaa60e71a5d80f5979f010ea22dca956233dc7876c0e8529d30d1d49eb5c09f41a028e0ae8e2352a72923d772b66bbde16e2fc0169c862c6259b5251720bfee0e38bd5a4bf70e320e8955a9527c92cf9224ff1d36aece2d7fb32fafc43c38d6796fc111a080aec77dac932378a5f06a4178cd903f6ae35bf7fae4b2a38af96cfd0bffa61b8f2fc5142328005b4154fd34cec32cd94ad42631384876432a84f3e75b82d5ee47bd1ea118ea3b3f9788f3acad7f5adc8f5a0ce64f4c02abf4472e3ecd45cbf6a1816df87fd6a3c3d29cdbe1c0f51cb9ab938c5d7b6f4277ffa4619cded437cfbfc77f1b33a1cdd5ab6e9a7f1835764f8af88b58eeda3016d4d2d66211d96ce98879dda3227896eb9d84f33321feea77ee35fe3bdf8780eb6065f59e18d5e8bd42bcc1e78a86ea4e39c1fd99039c28023498a829e967ce011f72562c1968c4f27d290d899ec1f81eac6859cd501d41ee637a1517e8535f4a50eb43c8b90bfddab719788cf012ffbc00a3f5b1f9f4fcfaf62efe0c347a773f044b004ca291c09b497f16f061f1ab2f879e1502ee76802eca624feeb9e498fc05f80b5197cb45fbdbb93432dafed84c5b1887b0f3b36addf394886644b5cdb0a29cc1900bbe57f07de11aa50704c6acab96fa03c6fcbab21db9ebf2f86845a65fd45265f62b93b7b86dabcded0affd02d077ce62cdfcbf5bbb1e341329cdc4ee60823625908ccce2eca79fb833b6b38dca27b2f1efbe4b4de2f41cd05f3c8d7c13920fa0856df41975d72161d4cb270ce42cfb84fcec8e82a3e161b9d5532509599d25034c3a993ddb24cbd0b8d5bd81edbec06b58dde529de9f849316219bbbeacb262e9ea7d51ed53f9e5f898b99969c7dab709c91492672e6fb3f9b65abb04260dbc2cc8ab23aa9c77ba5e566747c90826102ce85fe95abeca322cd63e66c77e6bcfade9ccc6f3d7d314d092ac45f3116aa4d0c316a5de99d9899c99c79f3cb1f20907d6e645ebcdc7036ccd1d7ed1c39af86b198e6c39990045ae633aade81885d132302d72878d93a1022b0302b3e709af459cac6ad", .Okay}, + {.Pow, "-dad6bd69b988f46232e4d0c9bbab29fecbf471b88af145c603d66646561a333c25729cdc9a887bce73ab59b966a0392bc56e9603fae1dd89a12d4431b01a87434998fc0649849fd53034cbfdc9773f1751a54a996420e699febdbdd526771e168deadf6b4f0ff75186b08c64a949c75a0e265cf6d55447987a36f5c51849c5b860d2b9c04201f35801b2ee14252c3926cd207013aeb8", "3", "-9fea9e1c34d84fc5837dc2570b4e54c5d7bb059d4df0616d9222b216de4e03f5bb51c0667968e0494eba476c25088f369ad2352829347f5d0c8f5e150d4c7004f71e7c0f96d60e0225e4112d6390c82fdc0f1ddb07f66b72531e535832008441119311f178df1508777661ed5efe0fbf09c66ea9e5a4f91f332d4906f0ff85f6438310ef4d4e849c872c754b797d45bbdbfd552b52045666fcf8609c0fd87cfa09e8a7f731d4c303005f2287ac2052a9a4b76daa794e8ad4c16ee55ea4a4cb78f94e599312fe884e563b64147e29728dce39fa94fa31d0b91cccc029dbaa3775562d06d10841c7e2f655818e773ba4eb51dec7518a72dc776ea4f0290fe8ccdabb6792d8d74676c194554e0edd576c265fc4730872f9dde803a56c91e5e4bfc71fb4483f787958b030d4cf528a0005166490c7a45f085dc8e0e68fa9edf305dc2376f399bc11a498fdd4dee83ac4bab7028c05c03b1f3c8a04380ee6125327a29ff38a701125fc289db89a724a3b7d52763bc4eb40bc672807bd5f5839acb0693b17732e0010debdcc2a9b627f5d589ef76b0d5aa0a4a1386a5d1dc2c32a07042f34cee20d64f87148c102cfe534c975c72a53be106733ce6b9342f79250dae98e00", .Okay}, + {.Pow, "a96059b27fd410a74eb40c47361e4cf19ba31a6c5cbae6a3febb4444a6494abf4ec129337ee287a9275e222d98c9a63bdfb6f54648cacf39068ec729c28842ab841cb08f39860aaafdaebc4b3e45160a469e10c477dee118b9224e3ea40a3caec7c55e123d3bd7cd9e20846ed902f5b2a3a7e7197a71791d3949665f6f4fc219f936ddfdcdd2d6c9521eb4c3b5140ecb240b83fa0407", "5", "2074e9a1ee2fe6e7208ca41b083bb65d62b1fc8f223447c09539f593b00e7840b6e90d8bc7a7651848ebabfce2247fbef1008659e9aa6fdf8090228047d3f536638df1ace41f0f6014c8ba97ecf5e6488625b3c37b663235aca75c7fbeb4de1f1ec311ee71bdb7202d73bfa74c68cbab1a73eded103541d71b6bccf225ce61a5cca6b2bbc3450b2245897348d446e6c055549f3cd2d9209da73aab7d17522eb4cb9ed600c1b07452369aa4180921f98eed46b26562727fab34d7a8f445c97585ddd4c01a331dddec6dce85d8c446d980a065e30ab3b938863d9da6ba09b151fb58dc0e9bbc3986a4bbbd1917bf77fa494dde644fcd7aa75164bc6ce057b408ffecb801fffada1eeb3a473e1fb7a224154c9c019e0a33a467e49d425772b14c31a262484c1375a870d6c8d5fad7fdfa0c7429fbf45311aa85442374402bb1548675943ea5b6ae3369a86451b52f7db2a04fec8775786be034b367e37a39fbd1751478887474f32cbda9e5f1b46ca5824ceb0e2bdc204545fcbe9aa5f6ff5d3ddb7da0c833f855cb0164ae476f26a9a30e2c6748f467c6b512b8584ea751fe132d1d8e02dc49d2bf65c37a3b56587bb974ecf55262b06941b3ab261a88a986f497b4e5773b3c22d56bb8e4d2257be16284e25cc60e02fac8b6a97400e6c8c07b691c11b2b541a940b8485c3b199ff20251e7ff72f353c34c83e1ba82fb91ec6770b3e1f6a89f1d6c8fef13860a449af04e9eaea8dabf6a372c9538c44e3ba2a2ca23ea443fe51f25594a91192d84ad13a4f0b88cd675fa83ae21c5117005593a5a02ee5c9b861560f9e3e9aaa8e72a05422c60a6145fb38ee5fe7469bfe239479194c711cc9f62e1f10f643db5cca76ba69a6555f9716273a350deaae25a0be97ec85259b11eb12abfeff3d10b663f547e2756eb15e91f77eb2bf7ac061ecdc38ca46f21128f5cdb4706cc3ffd25d0eac9803816eb98c3db1cb6cb74d818ea8b005102e3a174d95d970a9dea1cfc3ba1556e0cf5bf82a2728e616e53b9ab5a7d882c603842912a35a0c0d431bdd5a7", .Okay}, + {.Pow, "5cec42a42f2d1febd00c0e9637b690ee4bcd25a0865ac27d1d7352581a4269dc4dfd40614c6262ead21ef6af92a2e12ba22d96177b35b96ff03bf57ba1b9b09bf419042f1c50e8e9f04d8d4abff3f8231a326350f86ea16f84c5bef6f7169948eac2c7cf596b9c2dff586396d55f45ae145d3e26e77738f92ae15a6d4ed75209b6625ca94d16078b7e729036b0f92e97d5d496d9af18", "5", "19cf247968082da02522b5aed788ffde57a1702bac0aa34429c573a2cf6f8ed206655236ae5a2d81d39ca3a4e263843ff4f3f3f4fe7be353f342bfe36b3856b444e4638550450a18207aef993a77d9866ee337746a641904d476561b7fd32a205b8a2e1c27c7e7bf3fc0105be200ffab98d57e7ebb4aa527101a0209202eadb32288fdf2a63467f7c54e98472dba0478436e17c47a47e7defd3cb2e2fb4dc5c3fadc1a0906f530cd7b1557e56a3d4a80a37c0e1d71906563929a40ce6536305825b35527f68b27ec0a78e8847c6150420b64ea28833ddd0c475e76a1422d7af943ee780c3e3b4ef385634addcae442ce5d65a6aab929579e1917fdb2df9073e4188ef19be527217b5778c12014ab7203d0a6713f39579d209f3c7c0d26f39e33880193b5d06f5918506cf3bd613086f4a4fd147db683caa82b4aa8462bf3805ee5ea38ee92761474aac6e50094b9a1b38f90e8c2b9816ed1be22dce74ab42c98b06d7d882ef2c1d8ce77e242d0cb69983addfb6af1af830602f19b53d8f126f79b137d344a84db29f9c9e6c8638e48c54c203efd732e8cf8dbc1baa445de367f30ed5fe6d81e7f2d6ebb0a64ee994a3d93b5e1110e36c3807c6935c2ff232c3fc5696a93568fe518ab5f96b4a3eb1e9e6dd6b4041b881962ce7e55e9b2781ec4b11ecb1ced4af0e6c9f8bc517b840cf745c775bae875ac17fff0f2677de9dbc2bdeec300381722f0384d13fe10f592b3e60d3d8ef041c00c16075a69b7c7acd2ee68dde0a5a593d0d8c8af22385620bedb11123451ac30f8bc1dfa7306b208b66c66d2c79069fcae64ef7aca40d21f1b21dec46a50f657e59315c0273cf36092f255735154609ee6fb06cd5840fc09faef94f421c5b28307103c57b9fe2cbb2e1965d95d7bea16e8a9e3015bfec1e00b432a7d8241143f37fc433f0a4d28a6558949025136f1349d4539d496e4daca390e9634636ea07eb6566bc1be6674617af59c6d7b26415722a6aa341ddd1dcfd21fc29849fec6a8baebbcfa5005f20b9226cded9f464180efd8f3a298000", .Okay}, + {.Pow, "14701ef1eb1a63c3dfce47336b781f5f36fd41a1c43aa3b900b091ec456edb94c7153e38aeba1b51c2b1115b38f30e3f359343856a4013eeaedb1e1127ea3f29e2077659df2249e1b203ca027316ab6cd3ef856b597198c703dfffd7a8907661b486e7464f66422a66e5a440217af4ba94bb4aa222a4186a2013e8cfb3049fb7f29a2356aa1d58b92bad01ae693aebb581684fbcd0c3", "4", "2a9923c15cdc1fb0e00c960eb9f7f14aced5e1af824211306d4fefaae514c854c4a38689cc0d27a79d674fd3f9fd94ddebfad68e7e38f9c3cc55bad4cde302c15d9e8957f78c5b4a0e51fc7b85604a298d6e2423639ae3229a5ac68d86bc60b910fdc7f877ac6774b6184bdb52a58add82c59e554c7b59c143720af496c4a188d6958380b8017ad440442bf6be05192b05a61ef8eb27c78ac7e611f0a2aad526ebb378fbfd080e6fa9c2411f93259a1ef57ce65798ddcb78210f15d66373bf65329b9c61dab813c3cdef475b8a075835f1c829bac8abc276bb6c4cec77d672d3ee742cce465eb03adaa5b7d84133e44b9edc6ef2d8d5adaf02ca0072dbc20d230d9da5d0b75ca09769d8372fd43fcca59e05a641625299cabe65b1d12e7e7f481d27543b9d4f7d2654f16168a835e1ac75bb377fe356d7d84cc5e16bb8814fb674997d5a36b66af4bb2be1b71549f71daceda42bd75bc3d1e0deafaf285653e7561406349de7af4015bc3d1fdf2489e574a1452d52a4db7f835ad8af05271dd8c053ca153cfa749d1aabcd761b862caa3c7c024b1bb56b331d1c2c6e99d4076c92b4edadbce8e7d10bd7ed2728241a3bc2e933ae16ee5de24342de3f4f8a1a1224c322ceca0e17b44b0ea9680b2a17fcc39ad9786745ac8237f5c98b76805b1bdf3d7317ada477a94a5644b91dd97e1464b3620d66c88a7a2efcb176c6d5edf7d32b05eef7a68eb70f60fbe0abc187f251fb3d73df016eb5c8e4b5d7eea17975c295a37d57d69ab62a95d3e734870ae7e1db09816d8c5c24a59506da02466661f78a09190615a461c95425f7ce01486e24f32d1a67151", .Okay}, + {.Pow, "-a955f2108d73128ca8be65c4be6eeba55afa8f212bee558c37296e9faf445fb984dda0214b544e1a9c4594718b626cf2ea8508a1ce9b17fb5db3bf748a218063420220f04083603ffd422d850969dd1ea16f8e13e429d3e4e6f53e8278f27634265c179ede436ff9c423c21594a4d52a15dc173ea96cff4c630073ccbbc7e96d36a620567fb1b1a57abce4a9dac3eb4c9d287f6077a4", "8", "961dded363d7ceeaf55c5459087a714e0f89b9c148acebaf2c5a2d304af0945d4fd827ecea0375376bc7df7d7dc380557cb19467a9372c9b30d1158750b8ac2fa9564b3912db640cc2ea744da99fb4eacfa83ce2491cf2a3921d4e2e3a6759f6e7859d901a037b133970ccd722e3472a0abb7eabec3ea3391558577c02051e7691c9cf77fe15efaa69d76bd858e474482324d7c3e138052d415d3d016e7e7313db0d73c7fe0e2dff9453a8ac47b4190f057294a21a69128424879d7530579c51c3ba33c83cc0002a664c91138d0a4a6f9d6c063898b255b733dd6e43025dcdb802f1f66d7f775fda0c6a9eb6addfecb13546bbc677817a5dfa00fa4824893c631f70dbc15cbf44cb31a5e7f6141b7b6809e2f8543537678ffea6b3b598cca5fa85cebf1fd729ff4c609fe18bf3158d14b884b8a9eb6d14ea0e1b9e08adbcbc925bc8b0dd6a0205e6e84d6885731ff05b709610aefaab1bb87e6f79cc6f01caf2ce966e01e9de11ed739479b002df46dfcd9662ab839f5cb1ed8a46d67e48aade591829937b1de8fe4bd7a49a59eaf57b72c923311705645206294aa2dd22238aece8a6390b105f3209b1aad9a31fa9e6954be72713874308b53da91017b27a7650dcc7bc76e7c496a7c9bfaf95e6a5ccd0308ba2c1e0b6aba01900e805a86ef0f599836b06b17cbcc2cfee1345d80832f0fe6a0e57f39d6c05d0f9034952d37cf06dc6a3c68dc950698821fff3522970af8022cf2b668c8229f9b34dcdf461f8048f04447139e2a02e41b2a7d5bc3e1cf717c888812f172c4130215b3c17484a04a7c891ef853bc58a55a58d8be6b1e7f18f9188f4b1138977110fc9fcd3885e39e4f90bb6955f1bca01e02c5045b0f361d0f18005d3c47788985d88fb324efaeb214e449dc90cfbc6dacc86a6b5078c3f81c27cee02066eac44d3eba826b80eec7cf330fe96e6f9a9c867c6fb750a24d18390d24f106c3bf2beaec978061e08f9eee35f54b28444ba86e57069e417ee1ed9fa29f19474426ca5f627f86c8f264ea8ac9d68b13d9816f09fcf7578f56efbd1d1b349a11e53733431a826c278bc84c3ec7cb8b88493e24ed4bd25c9f045866e674877cccfa9551fb95fe8f24eb4c88be4c0537364a6a84bfc6641e95e28b0e0cacec1624b8fdef71ade696a3e92a2bfd9f134ba3bdb391d73746870593b2bc503fea65625425013a3366c4e4d643b9510ec156d23977b14b4d5bc1cad72684f62356c3c7982d46e73832130a780224e0fea7b4d265e84d59b4c12e605cfaf558763150f2454987ec858bd65b4a89b50ef7003d8df9f67a54eb9386cfbda7aa48c948be9d2b6a7d87dc8bcaacc7c8ecda3ab2213c6499e062b8718f2f2271cfda9061283a6831fb56bbaa1410ba221f5177d0fa52928a9bf4700884c1add2846c49522320cd352cce62413d70d0dfc49bf9edfb4e06c8ddc4c0cd496b0a64f2d22f7db3d29125269bdb6bd7834cdbc6b147ecbf4280ae418279555961a34fe0a2088cb1fb8c199ab08cea8ae74fceeccec278447387e86bb1bd4ad29b2da8a26d69c813383db58fd5338dd50b0ec01c410e0c3fd12cd01835abfcd4c4672cbbc9a8c6329e9b1508fed74fc7b69af85c5c58da302f97f85bc2973e7f10ee9e546582d641ab33e986166c4a1f3bcf7ad50a643b07e5c6b34698b23e410000", .Okay}, + {.Pow, "-591a2a0be18692195bc7d09f916fe5bce929bd2186cab668c84b476180473e543449c1457dc46bb2b31cde4bb3536d586808448c49e361589a9ccfc212be581225b5595db8ba507a2514e2b3ceae30becc38e13ee519921c0cbcde76cbba58e9fd2d79f804e84ec5c0655f5d776d3a8f15ca12674c5869c75bbf5b47500e168a46e2c1dabe6f3b628a267c367e6c879eef1c30b9c3a2", "7", "-288d7adc4a4a909112ebdb073993cb21c43fe7ef30ccb707c457c857273d8c747e201422a13b6c4057c0da9b8aebb88ea9f6e18c7e4d376b0cdba18c0a389882a64b1d7b000e863131c92b11beb57c4dbc52357c94a7359bb245af0562e9d35093c63adcbc67bbdf1715be49587bdfad745b1d97ced227bc75f1328456d854304f4dc1269e5ee3de9dd434fe97f808a6a71b4339dee50e5ae6b76816aec38f981c40503e4d92e059ab52dca83e4613ab933bd5cc3d875bfb0963da62906f5a9b7084c4245313b157fd2a0e604d2e02794822d1857a2245d122d27e0d8641b7f60e6dff2b1c471495362f356c8b5e43e1ed59c02db996fa4bf9990e4ba85f76ae0e6f59f3d6b0dbd90e140f0e5aef53d00730e8cd3c2297ec6ecd35d8843df4d0acc7d2992cec3dc5f7d436873185a2c537fc12a69feea6f9806926b1d7a619f5ae54cd834244ef4864243a12dbf12a98a46f40c737aa3520bb95c6ae9fea0871ee51ca1ad86ed2f25469852967c6173c5dcb841ae22734382f47f0b36a8e15b74a6a4e28de4139c49f3094ee3dedc8b89a4b5df642e3e2fc078ed90235bba0fe64d2b5d79d979ad0667eb747790ca6f9215c99bcbabfdaec54f371f81c4903be77ba5d111ed970c2d784be85cc271e1e4f08a3d9726ed345a50ffcd72c4fd4e99d23332f66f431d26e624af57f9f9a779e0b4c1702f27786e3422007dbf860b44f7a3c39d93f7f8bde3c9c1036b5d03048b2eb0f107697d6238a55f3ebc5e0969f1a81b6028c40d9ffe10c9f1b22dfd47cd54acff4bc817e68bfb99201e48789e8badb562880d2ada99bf9a9b9b19546154d3fe4f9630c35edca646c31e43e358596e1c0911fcf6f328aef1b13c49f4d8b6e4374097112ef5f73ced29d930645dd3c4a41c6e956c5aeb72dada854a0359a2d76ea6ef33eb50dfdcc0854db8d1b272a386197b50207fefdbf9525f204be7a1eb26898ce78dab3b5dd9c6cb516aa3eebbbcff22e272122583c1e4caa867791595af79c7e8847db5b14f3759487173774b824abb1a0fb6bc2ca4a2d7bb1ea50546048e252c80708e6e5af38d6530e805a4ecb6b24fef0ac7ba0961e2fcf1b7aa2e8cdb939381092f245cdcbccf1f303d9efdd983b1e51a844c0bb47260a594606a32650962230ef8445f53bea3f62518ac00acd6edcee9026ae55397b1d8784b6095bb853006db6b59b317ced8c6c4da0454042c0d7f5f86e7442384e271125505ec93f31f01d493ca6f9135ad895376628f1a0c8c1efa99e8c43e252c378be41b21742511d69027b7c0df05a4b79d186a5c940f0b5489a2f02a4cf233f0010f0214a7d9e0db72ccf6b031cd929fd06e51a37d6f0ed6e222a23f84845f9caa4c1ebfb4ab673aac1d878e6a8be34aac03cc9f9b1ef1aa318d8e8f7ef575b763114dda940e4230ac502371a830bfdd59a3cf019e7bec8536f629c9596d9e5b448d6d1d7786a8cd880", .Okay}, + {.Pow, "48f8d26a41e8b67c76a19b6183d8ea2d193639e2eb0d93ca377dec62e4c8052000d7290eed5571d07f7415ccdcb504328160f2fded6283dd7bff2065f0dd3711a5619f21068c6cb065e4523c6ffb940d805073e97cc00f4806cfd57d2c3969d41d59a11a238bbc657e6910d7ac819e95929df8c4d39eb6dc0a275d471135be6d28edbd9d139adbaea33a103393e8a084757dfd98884b", "3", "5edd8e854252c6ab09818777b0ca887bf50d9c99416f3e7b30a91b4ec2bbbdca0f4eec3f573204678c6852600563610940bebd935299c0ae89eed27068c104ab51080dc362ea4a5a5a69857788fa509959056d4d26afbe437f2393a768a07cfa098d52d83e0101335e171061155644fd1ae03bc621ef154ee9df95a47a9fea8e49400f9b012356a8febdfb9d167333d426644fbbd03610242b0ee1c28acfcd7482d8aac97be511834c594e7371540dd7ae24f83e32996f0821ef2743a10f37e9be7cc2f1cc005023206bd6906932e147640c74f1395333633e97d736329de0e3c505c0ced543e561c0ea4c287f6938fa2bc34564ea1b231d40b77e6b5573aa143186fb9979626c1560620b33ebea5962c9ffe9f027e04909420f550111e9dd16c8234f9b987684c64edde0d93c227d59189334110a949048a4d01db53b9bbe6778ffd33a809c8970d465b2a5d54c6ce1d04ca8d12e2d30d339995b0aeae19cdd446f3470fec871dcb69c052bcaf4aeccb8d6c3f306be6897ceef5b53fc140872c32214d1f5674045d278e359d6a4b2bc657e4e314d71545fa3d8b01b157da19836cda75052c1d4f4bc3637cbe25bc1750b370452ce8827fd978f2e7d3ae85d347f3", .Okay}, + {.Pow, "-19f5304710afafabdc602cea98733d7ac913a5a62e93d500dcd4cb9f618f1a5e24b8fdfba5c75b6cdb9354fb05f7b686996c86d6ad68b60450d1e53a6e7748cde9e6043ac4f67592f7f57f48bb86d400f66c74c5702965f20c1ae3cf56c4ded779e9af20bc429a0e2fa9620ec6a6a43b1e4646b6f05e597041e81aa693ce049fc8d2a49b53a56c11fb0f44df3e2813e7e1bb5b3c17ec", "7", "-1d950fd33bf1d8d686c3b747d07c21e698241e867e510814832ca9309fa2ae5b00a9aa9a8c3f4ae9829759c8ea303ee9b413a02c08d4f51c673b74ff1d25f17c296e8d5b567f659099a689669ecd0830b2cf43f0c6f8b94f61b5ba1cac568fe9486af4b35aef1749acadfe0524143ca4eb58094d141b64f3d20421686f08526b69b953d9e864f6aa8ae076d6f8e263f9c08968253db2b37898c7348767154fbff6fd2fd44fca94874b74457af2997697719a8af4179b4c4a6363b84ffdebc8800970f310337038a27b8e4303d24dfab0099673eda06dee4851475340a2d1b1bf5723e9eebd58ecc64cfb60f7451b049fce0a490ab6dd30362d3cf6ea0862f25daab2cae367a03b9766df2f258ac9c32baeed2056921e736b708f12045cbb89743b08f4c7bec24ec4fe87072afa1f0e8ca8a21dcfb13f531cc0c68229dab3c98239fcc2c9658928822a9db476fa794d43d78802f885b38cd2474d989e2d9d5b0e0cca4004557e0b9a40d038308f748b67911e59ee0c3a9fdc7851a681a8112e686312aa692c9141b18ba4f2724a1db9a4e7f0386a6c4c8d519cca0884a276a022e55c2edb316dc1a30630dbf46894bcf5056e23a1e1c430c5a3bab531cdf6efcbca8076639f1a120c366354b24beac13a08a7f4e4395ae6d12169f61629dbd85deb21eb8c4cfca1068561b136025f17c001f43d6470f5c9cf150ec395eedee575ad8325c2659341a44a67bdc5567d10a462b22cd04744bcc99752ab263ca409b129b5a4481b79da6b9be34f71a3aa8d9c552d2953994d765fd4b91492b9444a57f8ceed4d1a15abad8b172ed72044b53a4a29989ee14860d126c7e0124750897582009891cf5fb73ee4fa21511ac9b6d1c643e783b759ea000297388bcd38a51543cdcae95860adfa7909bcffb6e72f42dcd05d6bc291365ca28e94da4853f44951a4e4c64018e354ae5360efc287a274cd21c175a2217a6595ca496b8a11de7708bacfcae8eceae2196ba194b8b81b2bf1e68feb92942c6b090e9084debc08c58cd825ccd4aaf40c3a297f749dc4301af1f8a0a8394d59ec431f9cb96602aef38e8d5c54afe865db50f43e2f66f204d04e0fc0e04072e64fac2c5a5e715c53d0272401bd0b59175ce2c75186d77d24c9acf75086de12c5980b56c22bfe51ad5809da120f8c1a212990bf1278a74cdfc8a303c6e1b8d49acb030c965ff72cf672d8556ff46f8f3c568cd6a7a40f7f93a1adcf486e3f142324c11963628d073ca91218e75e9c28cc16f006ca02a1e9a973de8baca0c29e63a90d2b31117e4752eb48fdff3da66db61f74fc1628f1a1bd4ad5972de9cdfc29a548494a49635dabab48874b28052cfa3301668b1dd5242a25f2487bc7a946540e5e043053250697cfb100b0de531bd3b133cad56db8228dfdd2fafa0ed3a696fd85cfd0d768abcf08da78bd398f4ca7560649da80cd8ce65b4bca4dbd234c000", .Okay}, + {.Pow, "-f8056aa46266330e3fcb2409729ffa4b438f6252865b9d4a4b688820b11bc5ad36b7024b3e6a68f24451c4aa2984e0de73d0310317404b400199ea7400e5cbb6f34267b3fbaa51c970d8c3d659c5303be7c07dc76aa5673a0b2f6bf889d26fdc220f6ad3c044e2088f289dce168426b9cecee5c934d0c70f8acd7ffc7a74f47af96cdb33f1e596b90ee1852fdcec9859e8aa05086d2d", "3", "-e8cd4053950d07168845b7928f46d5db194ecd6691adcd773d64b7ac4efd221d8bbb07a581ca6cd4894e447533740620c773bce1b45130e789e9f6a57a949fc51f2fd94abe8f9afdb1899af41eccc2a2c1af9c94d2bfe6db1d8a0d78c90ba54b33a6b543d24872bd22a3cc57e59139fc36b4e3c704ea7b1b3b9c9a7562be8a46fc3233d229e4aa6d3532a7a14e0017cb80c41b7b2bf82995ae7cedd8d3ccb44c1d734ef3385a128b91111645c611406ea8106f4ddbf9c59487a4dc6142d031c5a0fc2b9fe766d834c8f9aa591a12c6e0d68d5e3de5f8f114ad74a814198720b9713a039f153cbe23904e83c9e3e0ff6a2cc48bbb8b5d29455773432993f50437377cab1565810acc9a893cb632736c819c606b0aaddab3dc60314864159158c5251d948243d224753aed49ecfc721eab01e681155ac5462f5e296c601677d3f4fc9889ec2d7619b0cec4d4a2c95790954f9f60a5bc7569a3242fe021c58c004060dd0ba7951375d1def92588d1ac47841d554ba1c8035c412ae823184cc2879a2e60cefd2fa15f66cca388cc8497335b4147e22df5a9e88f32d0108057df0e2bec1c3e4c7f6fbcffe9288d99bd15a1b21b5c749966b3a739cc526a037f7e4d5302f5", .Okay}, + {.Pow, "-8cc65050addf8be8779f5258dfe6a2d30ba916267b89ee065284ed8ca05ad13de69c69eb085bb876e2cc19ece958b1d435593ba3234733e975f981d3297a2e0eac6f24312a3f79a520a843526b2683a4aa7baf7e57e79d4a0230af0bd1cdb824505752703ada426e7e5fe00c33b84ffab41d87b04dbc08999dd6e26954c3a422a0e0adad623d482db868dc96075a50a4b23e0388c2b1", "5", "-cdf5b9dd617e7fc42a4624d9c76079e7b44f9114ef908b4df6fe3d978fd3e980433769c0db84a0b787d72193626c6388d6ef0582c63700a98522324b179477fac4236ebf6c01049dd89cec46195643f7bc826a47babb2d32b629b3e67b4d01856708700a18227e99bf7bde24de3a1bbd10ee83bcfd506e3f0d42f97022b78d2ccaee73056843651eea9a37fe2ed92859f37458b05f8ef16276136033f63f7dd19c9ebfd4d31b40aef4be174f5e3fe9308c71e8ed6ef26460a001ffb6b2a77625ed6edc9a707ff7051afc0d03beac2808cb30789cba13a8bb5da26783086b5b7ebdb6a3220ab9c0598082b26a62442c5132e0961e3bf83414c12781d80f47ccb595c04f1ab38f54c774c1b7c7d66755cd7a752e15c660a39889b2a5c256ba223eac34390a93438ded385096156e3b28760ee4882894b1187c5d6e577f830ff60e389fddfec599774505e8dd1088dc92110aa246e78f18e74d747edb4305b7c537cccbdbcbdd41d2fd95ce176ff44d5a8aa5f484d27ac5510272e0d7fa3ca117f62a22f628418ea7a4536029ee9ddf418280c2384099272924649f73df217e7793f6c98419df3e52381e34325e7efcb69def49b242de8583900f1d32fe5945bd9f7a50306548a1ff912cea2e1409fa96338c1a1e640abc5fb9d4a77ce927acd9e6db2214497d9f8918f4a0cb9c8c9d44e0d852927c160d4049e723cf09dec9790562f64eac97f0ee480688140861fe8d7e51a63cfd913bf00f61267d28a1f40b1d4c8505853251657faff216497e2e6b1f2d54da2b9fdc08f8ff9d80e0074d48db1978b754d48e9d3aa4e8b80de3c40db9a4f34cd8dfdcf77940e12d42f68103e7811178f7bcd152981822d4b4876dc6a82afe0c918ae4a97c5130864010d1e760728a61297894e24341b2de434cbbd80002c57eeb71a5fae73f29aad64b1750231ba5ebcd342820a3b78e2b71d613dc6b67584902a4bab2e67ad7933bc9c120149e4d9559cfa55b2b8d3a7c067adb11eb91b218ec1ae925ba02f58392c10fd8954b4f31ca152b26c58f47e04e771", .Okay}, + {.Pow, "2a633448633ff64672065f568215a6afb59f208eb20cd0f74f50843da851743f06f93c43a693cfd247a67c724e9fdd5b5aab8a1ad27077e9cc93932d8ea4aec51ecbfd5142c4bc4f83c958109096a9bb7194c73e8708c7b2092c309cc6e05fda67136e29b3c0d5f169737999354b35f20547183366cb5b77fd8104d0dcdea8880325732373d1364e3ae0d9474834a4230f357ecb1c3a", "1", "2a633448633ff64672065f568215a6afb59f208eb20cd0f74f50843da851743f06f93c43a693cfd247a67c724e9fdd5b5aab8a1ad27077e9cc93932d8ea4aec51ecbfd5142c4bc4f83c958109096a9bb7194c73e8708c7b2092c309cc6e05fda67136e29b3c0d5f169737999354b35f20547183366cb5b77fd8104d0dcdea8880325732373d1364e3ae0d9474834a4230f357ecb1c3a", .Okay}, + {.Pow, "7230eb191b623f8dce126ec7109a004bd92125a1b224eea06d15df433fe1c3a08cb20cc85b27e10e7db339ec5ce7eb8f10f52fefbc801ce2a5f5cef155d1952baf63a5222a51c7e90da490dd1096e93e83446e6a205d724b6fe2c1b6edeb62d8d25698642bfb5115192fd88039117f7d8e0f8fc1bc53bfb4f0cd8e4c9f56fc3548af92856483bd7298175aea6c53d28445c0b473d0d", "6", "20437e1e47b915fd464854948f63a4f071ed60ef040f3ea0b3974a0f916405176e418aef0db5242ca3019477e24360c7cc6e81c32846886d97d0b40094773c499c4dddc2b692237cc19fad4f3669e03e737cc5cce2b9af0a3dac0706ecfb2e021f8d68ece59330c41c434930c9cc848915ed7e8b5999ee0f0e1a2bd860047727e2c39f17eac0815a6c02189023be179401e488cbc3653be7b689782723406165e0802060cc0215726ea04732e955d744925aaff3b9dd4595d4afb037dbe182172cbc12236f0a32a118a094e61c5c16b209b45c9dcbd44e3cf9aa877d2c148715bc0702da811eb870e4b67d5de31b7ba1b721a7b4edfea440f7cc0e4efe268decd93d0de5f071c3f1845f37ab5a5ae507f24ac8ed30cfb4ee6581e3f0670446f461e84a07bc72b2031c484ebc8b49f8611fc818ae03e72624ecb29988e6c002696ce8dce7bde451d4bcd81f8da63505485c8537988252b4a80a1ab60d5ceddd43bd7494849d874d2cd964f7bceaa0f13d49cab27aa73b2060a1b6e75844c486289ffd7fbd12dc1ad39d03f8adf9b190fffd77a58f7e7c87e931dfdc3a148745bc9cd1e32b40f6c54d891e6279c1da27583d0bddf92c4b9a82ec4d124b42fa78340153d31620db49a9b995473f307ddac7e2b03f9014551c222c890c4e2fbbfa8c283b599f9cd3dbf37180f67017fe2f14d01447e7789dacea75ad8b488829bc3977f57cb094ab873fe1eea1b2e708425a41bfbb14d1c6ece6f368db18d73daf8e8287600afa5e2384ce1c7d42ed28f7a2e12a4f65476ffab08a36883c9547b4250120e5879865386784c60c7026e9ed4c021c27494d46cebe96eda61326fbe9f92fa620336512b7ef9e491f288023e1362c6d33257aff9b229df49ef78b5f9779117c92f1e661b08eddb158685da72d61ac28ab6852a57139e9c8c7a4b5559b485a79cc3dacb0035d26d1e1d43b2f43a4965a04f141e05dc6ffdcb62af9cd71a9bb4455776f63a4ca49453f09b250caedaf88c0bfcdb197bf71467ad9ecd6411dfe651c4ebd4c71f3aa515e36d0840a21b6c81415a0fcb88ed77c44e5b713d1635c985948b7bb30a5aca560aaf31794b6a1bbcb16620636559913c426841d7fbdd74077e02eff901388a4178aac8cc8de7ea573b5ff3225ccbd3f06dcac4a8c67268928cab2e705b42f7eafcb7b9b81a161eaa2b74542011c4c3d6288fc2f2f023afbea0b96007285d07d4015ae96d449036fad0927e8cde2c96533731f7939cb9", .Okay}, + {.Pow, "c725cc28d5085e040f1caf27a6383993bb3fbb5390232aca667c2665fec13255f76663620471b68cfbe0a9dba843dcfe8ab0c065eea01d9cf36f56ad0d064fcc10b0a3f865066b658b6e1fc46e6052e079d4a7884c377f0b806969a08cd6e2e0cc876afbd7421e3fa2edb12c66a502568c29d5dc3d3af9b7d7e5be9755891a6b9ac14fe11793aaa34b7dfe0d9fc7d902affe12dc230", "8", "225572dc5a636492486744893d962937a6fc42c85a4707f1adf374a84346fa3aba16721f0e96618ae0b52bd58daaae5e41983c6b600fa7dd5747decb120f87bf14a1daf7572e9d931dec4d47a61174cc923d46c534f936cba757e57899117546c81c9d5da8d9bb6919ddcb3a6da7c59d43e28755519852d853bf89a54515bb45495071786fa828d33549625a51edeccbbf20fe989393e10d8889535b29ff421e10cecc60b5b62220d60232d330af73bd466c019f176e10a2dd57c73e5594ebc06f0343a77ce6111313a2977744c515143cc789fd7847779cd23f71b5549cc4032353019d855b0dc92f0777133b787efee1869485078af3c3190835bad5d818dc9b5660598ccdd6b09ef01c5a5f7f1be18c0ac56e3cfd7e31578253166f6938d6f80b27467fc86ac0fbd3309e394151e15da7d5f004df29deafb46d09a73a6644b1b5cf9ae7b23712d1d6194018220c34023480df15690ffde96118e8c0dd6d55f9c52f87d45083d5b87f7db3d581686835e8be095c4ce690549c53e53bbfea429be64e659c00bebb63d650193b19ebfbe1f977ba0f0e24a5559f55e51727b686dfc71031a668833a7b2f8bbf10105a5c608ff6a90dc3ccfab9b77f5873216e5678cb8d1977616047a27eef79148683b618b75950327d58d0522f8639a6bdbe8536ba1f2b6862e46cceb34eddf224a980dd4c0a67e08b5002af5c75919702968493e21682538bb41c89d50f26f721697d274286a59cd73dfa73c9f900bff09c5a901e95ba77c9dcc00265534ca305aa2888e545962ed25b93544707b0ee067556d793ed4b2366d1b3c800b90d5a8ce2e6852527ab44decf8edaee8b1024b10ae336143346cff170db3d4ea6bcc51f4a45e77a974cfba4200e6c73346f82f93a07e6c94137735a5f6e8ae059a98a4f80268f8105b7a7408547ac55ac472b3ca240b539af7945c89f2c41f7ed06ae9df273b89d9c5aad605c73dc241063eda5424bfd2560e041f0d61d61d057d11cf8b08d3274a76e902ba7751f08375e4ced33bb52a1f87deb4a9989ce05fd73e675b4120b5ece43c8d62a81caf6a42fd5978bc940e2b736b855ef8101b55dff4657684cbf1e0ae5a09929c713967ab147bfbb0c4449026d137157f7a7cdc339b1a8d19c1d511f2c83366e24a59e7d6f6d6cbcf8c0e46008fa21ea0a3d36dd8c28b629742da2edf900de2f02e7b41b62b18e11ae901f65b4cb67ddf3eef71d022db7d5bac06fc32f7fe466e0745bdc39daf14642e8187adc9f3f9b01f3fd7b4699ed00c9fef24c8d9f75141f6472185c31ed2d58bacd4cbe6975d19ec41b38e50b66919ad745673b66e16cbbbe1729b23352ef1b60deb23caf38af11ff3ddc779f8b5f0c9b2e76db06376825caec76a4577d81337a7a97dc4ccf5754317553586e05a9a6ebbc154bd30a83650622c976d00a176f37e3d4becfbbbb902cd9698c5d8dac1c3caccf408c09cc7361dcacba08471f934474b0b02190fcdd40a5371ad80446836f9d6363249da91328c0180b6585d67ca9067f32325b8c3c824072ae2f9a8146b217f3bda5f4367648bd1c24c60eed283e54592ec98471c640e0eeacbb33e33d84d815c1e36b7a90fc9b0c632ca370ee2ec25b57218f3178fa77a150f80ae7dc9e668f5fa50d350695b5dbbf5fb01b6630734843cacb34a100000000", .Okay}, + {.Pow, "2360acfca22b3fd0f0b9e3767f045ebde867c6489fc9910a00137d35ad09e607b14bc0ed40af64e2ad2a0ca8732944c319a062e63f0977ae0c3a46941223001bdd4d19250f5c3ee98c8ba79dc0b075db63fc41d0baf4110bf1eb6756d322fc5dddace05a531287f56735737befcde94dda1d039322055058e2b6b9dc4cb33bb2fb656ccb9996b09341f64ce7d0eb268ea051e565c62a", "a", "ae91d40b2a55e132056e21e4a582abc0472d062c5cc42672d5c6357248c5f1e70dcfa62163f72528edd257220c044bff082e0a41bf8747137d18307b813a7d7839f30b00301f14d8afae0d7c15046f7e938b54141044b30c60078c6b4678b9eb72f21af4d97860a51602b15877e03c9c483e586070e4f938d5c91b7a6ad103a7e0b3543b3b2a7f3d69e84fa34ac06dfb8bce83be03d141877e79623da930b9852d5def93d7efe470f0eb324941ea41c5442c391a9afb96725f60ef169906545564a41b74b868df7aa09c73b95426e6b4ec3831ca22b74486223cfa12a7139274278469030e6f7a906d8dfeb7eb152018b98a525d1afdb7a3a092ae02c4504298ae8c7a75bd85ecd04e7450b7503372d174eab8de089d570569e7c73027c2d2f8cea52da4aa707f5ec8523c9b8088741f425003d83698c5ce66c8bbf152b8cc354e625ef502b7db3d9ca40c2435ad3a46acd4084d1153588ad0a27fb9b9e53c20ac102eab92a835fd8bb9ee6ae4c2c85d9f7882167a7ab96a5408571027ad4b9cba39ec40c9459beb7ab3ba8c6fbdf61ba72f344e802ef043cb18296d242a4a89d309f611d77c69fa4914720cea7524bd1becc15f0525a8142a64011c6ac140ccb12a51a7631106c6fd56f65766b3538016e6339b12dcc96f3efe367f8d9dcc5706d99cb672f7778ee64b97f3a224bdc0f582d764bd4866528bf72bcb5d755c9d2da0d7f6207be0933f29db743a3eea641795e112b2b8f02577b7e9ec3726ea4be08dba0c62b55169e8f4d005112d893c5fed881fd5a548521db19dbcdb94186ef6b70ec90b0b96621c78e2e461bbf19b59d25f0d478eb96a1cd1e479dca0ba87457541120ace2b66a1a91f6d244fd33d30c0aee1e6812f349b13ba02e6b90ef94f338c0f61f119658ea848fe1cf8718f0d0a03dc22b2379320351ef55f016ebbbbc1b6be9a66a7bfbbe9ce121af480d6611d0657c1dcf7ee7cd754a9ebc2085a80a4fd47dba8eb258cabfe22290a4d4d13777fc4699926febcfce7e605dfa06fd463b780aa7e0eddc3f14d4930099bddf07cec58120ace80f33b627d9b9d538c7bb3c331fd750aef61ed255dc18fe14c1bd064c62141ec0a1d9005b5520f01f0011445e56518d30e562b078dd7791ff82600e6ceeb408e5deb7e517f65c996e5f7388a57d2a7ecb28d902b2e11db64bfce33a1cf619052c4d7d4f9868c4147b1c43de00fa666fd2894eefb4857f4eab8153c589f475f38d94272769ee2167f126bb4da9a696bbb31a4386f416e6bb2b3a4babfe5751142e442fa383e083a835a5e4da596a7a3ca0fa16553b66d5f793e7aadd8a655b927154379942bb1dc7be081c6f2f88c1a398d8eed709c1b65b9e2798cfc4a9422f88cebfeaac31fac779519e7e5aaa1456cce2a5740965dd4ed17eec7a22cf555fa3dea1ee3d5b1e8257fd51a68476c95d9d454aeb9b6e40aa5d80749bfc5a8d373cd174532cd4bdf4a13cb7b29c81e67f514de9075697e564ea8ff63f9ae7cbdba76766b75d936729b8f65af0382003862e025bde876c54094684f9ecd2ac530c1e8b98db979a7f80d0d86d7a156a42ccf309fa2007eff1451d99a12593779550ef231a940cc04e9bb2488e96e47f73dc5dae7d2fc1140e2170d8606a294d5bbf88998899a7750a0ce76e95c663ac2ed374851a2e39dba3856f6156e51e78a83a3e16726731b9f9c42741ac398709c7e902e22e85e7c43ec74fbce2cc199a44e03ec5ccf97478ae5a86db831c6a95e817c933d3b21d8a6a97029d910770ef3238e745f1ddeb0fca782983dba9b914dce54eaa793b03dbeaf8536d3b12fbf0de07749d8537d8de42cbd33919996b4150d427451fbed80042f24243fab2213c5c0c98828b5f6feaaea1bc50d3f9409b837cfdc15aadb79cd66c327c04410a104534c7ab5ce35f32d0f1329d682aedda413adb28210ffa278d250022e68f67177db871e60b7d899ef91dcbc566b0cbb0f94f0e350a063bb2c5d15ae9bf28e3db7520ee03ad7fc9557f21b4652463c0b5e97d762c09e9642a8473c1588e1b3b139e615c66dfeffdf00dfc1ea09d59765f89bb1ce6962a5f725cf40b72d14a3cd763946400", .Okay}, + {.Pow, "-6265263051bef8e701e259791b8390a943e9f4861b65d1ca4d3f0e7f78d5e6322fab355ec35d12d24a38463abd429ea10e75151dad9a6514e4d9dbe7930b25a07ecd7974ae5df2480ca7b224b6dc150dd2c76a0351ce677f36e06b5769904f5218becdfa1bbb7a51397e2b21a04944e7bf414232b229fe0ad4d3f5b8bd842b9c06a7ab4c9e449bf167a260534b0f5e8afe16f5f0ced6", "6", "d34a89c607c3d78349c7a717a504723b41a7b94e45ded79db7c2c3cf127c00b39dd57373a88b6b5672accd955a76b20e6a5184be41686b96a898807ba2773d4652f7ca3b8eea1b25d94256aee9b7e4a7a44c73d6e68fd24e846b424ae2a8da2de5490e50c41c84d060c0e2ba4d7863d7b2138b2829c257af72c5618855488463f3db1fa144b41ae3129bf1c19fb4784ccaed4c31089158216b8f7955b5c1d5482673c2c2ceb40b44ece45eb2d6bce01278682a7cec2bda1f601b983ffcc44527bd7caf3a0bea2c2b8c5a9ef4fdaf27e648ffbe96d5bea38023abb7c2b7a146f4e8367d3846ae395401cdc1311e02228b6355a5273ca6ca8cf9812c227ee461b3b88c0c0dbbe4cce5fbc171ed4bdf6e388ba0e36a285f71a881e7372371ef8cf752b6836e88c6d8d6ec4bc623847e4b64cf4f1a6ab2de031fa7a675cd20e857f39d1b4cee96c25d6f7a3a9369e453605fe946be16164c3974ee83256cd1144b7b626c64d2d8394691bd8e55e62e6f45e31d6c684494c3a061411ab5551b5c95bb5c15d8992033cd50e832adb38ec84ec660b2e1414641f3aa57608e70135f3d4ab19090f3b508b9f674418793a9e6729fa1fc3be50dc5c3ec4dabf260dbc6ca9967331c3ff8ac3255950946f5e8f5e7cce551b9b7ab68f79a49f28de151efd19114562c6cc7de52fade985d968f4fe24ab14acc24546707ffd5dcc6b38a49bc0fbae6ee2c9ed8d80a3c177cbf4adf04c5570589af428f3de32803a943647dfda9a0043161ef5c8dbc1aa06ecc4a118b0df257cd25e66f8fa70f3082885a808a63a84feaa1346bd6664ec58928703ad9ecef823219f5f18273696525ca37803607a17ec69f6253fbbdde53605a07a80869e938aaf67f511fd1b5152279cb674bbb33ba3a47a26a4543a2105ac28c356bd037694a65c13eb6a4138a2ce6b6383faf8447dcfbd5116b54df36256f55248b821c23e053401da5de1b1d1f440e1a3eb6799ba7d63ca8a3134a2614918e156fdbb4d24af9a3cfeada935cbf93c964645d5038cd72639f49f7f206ba3420e09ae6ce48a0d6713e5910da79734877ca368897cc281ae356fda8175a35600a0f954807fc84fa89be9553f70a0ae4c87743cc1c906597edab073a7d16da10cc58638c1271d47fc1a0e911c4ef8aa7ee54d51ab055fd8b74304b7559aa56ed8111566d087179fa13c2f3fb3883d7abbb1cf1854e367368e98ae443d90a0476285408a1d36a129263107225c18b95bcffdd223333ba40", .Okay}, + {.Pow, "e1a2478e76db4ee66793679a94360e5a2a06821fdf9e3ea21e1094a2994924b1da7baa1d8d3bb3af4065463e5afcb62bca1c4bee1797238701401a0181f106ca1bd01d4accd8e8ca5f55f48826cc8b822448bb1066aa96ca0a1ea97d61e51d975affb569779ce4ab7852a17197c64f005e0601a8d745b8addd33deb8abaaf4c9cfa86cc1aeec9470ed9a0c8eb7a524d3fafc9df11663", "8", "5d3ad9362b7fdebf6c5c67ea210f74fe7eaa77db397dbc990cc68bd9c80c090ca83c4081332b24ea9b38575e3add992fdf8066cdcabb47822c6e4157fa5c7811776a917592a2809381dec824397ccbd8be33e1aa96b830f6f75c57a093a53cf7df66021d874911a1b4f2b632ce8b9e60c390030914d38ad2386b6719fc0cd57c209791aa7da89c014510cf2e040d452293cd4c9e0009add7b383945ac9cf91a212fb3a8249ef068804b70d6e895309b74df5dfc38c6d10758cf4ec2dc5acaa230080013771910b09aa1c1194edf5f40d1b8723bb55ffef9c6c45a8635cf8fff6e2e0be3aac018fb14e1080ac24484699a18e14aff234a7a36c0345099b6b59d707e04c85e9c0e2551d7fae6c84457a4b7824c54be1ca6d013b9b586a3df4a23a15f26a17fdb57b3c440206f28b2aec428a8e3050a3cdb4eeac87696c214519254a64d3838cd9ff53b99b0e5217e0a6d2cb97680c108b3b8d83a9ebbd69d1e7f472c93407c15411b81f7bc1a7805425d2ddebec52bedbd669e554e7c91b7dc7f8c1a2aa99eb4661be525d8a3f3343e4fd85f1a2005ec3cb9d347957ba804972e8a96cc5cd617d7ad848cef3df01d28ea63f1eaf05a9baa0e910c4382e8e0ed6035fc4afb288ddeedbfac245f5b361db36791627cba1697d3cee63e5cef2d4460b47ec8bd6f412f37ce2584cf4e45c825388718e64123ae0a592a0a029ae825e041baea41a22ba2b6468e875a7c827611971da21ac05e011b048ffd5a93473b4e320546941ae0c4fcc02bfe5d043823b4b3fe9560c5b5be1663ea64fa64f68b2b34cdfead6662a7b571df9addb06e74b9952cd41267a1f6b14e00c751f9856d1bdaac5b32712ac006589f7f552c9cbdc698cb82250e22afb5d44a4c243b2daf1f21a8d3e96a37add545c1e19f12160741d05c8aac4d9cc289227f89d613a2819eb62755446b75d11848b321818dfadc93339d22b3af538a6275f01475a9e57ee54c2e8585ea8dfb8ef28b7375d38ff7de62597bfd73f562cc443ecbc8e03b71e5fd07b2c07095c5778f1f17ba90a4537ee361029a6bd262bb94a1d4d4448eab66006ae61b5978f3305ac37ea348e8774abce2fe77fab616e958b247c23ab347cf5c90784218c7d873309b504d4899dbc0f219a7ed8175f66df0d0d57fa97ce6a60f20394dd3d8ef7f562aa68e1e3b58a9ba50caeb2d17f878dd4862bc347b817a2d66122318064a6cfda6a09d501b01dbccfbe745d56f3052d6210dbbede6929af3a6f5f82fb0c75437e877d20c07684fd3faaa14a39c3d908783cf25e5c564dd743dbf0051a88488991d7e387aaec02567b44e4771163a57abb109b6b0eebf7298b239df9a4e89a0cb521cca8bd7401eb38323ca1d0da05de4460fd43c290d04d21ecfbbb8687a72004ff02e103f83da40e1b174916e8a5228a5d945599cef61415a568aa121099eb230164633bf6d5e736a9f0a8b8c730511905b0c0213cca0468b0f20773d7d2285a615a592821d6ffc9ab1420072c42d231de5f49bef2b12ad72c9d4c189cef45a295494c0f2e4a739c62bd9ed5a46a26e61b344976edb8cd405d89d7dc018b3b0af358384522aedb110fc7400487cc36f8489e33ea61d86e870e47dba19e24a74e303050b79eb38d06956b5882dcd71e688034d56c3b68a3748883106af9b086dccfa1e41551baa1", .Okay}, + {.Pow, "d35359c1acf428919aac2f6fa0b5190aa0fc9349330883f816f84dd23146580bf28953b1c2a54526bd67509606564dc063e5702c4eb4b7bfe8d48a7ee4c2710950ed3c9db4dbc90b810abec574a13135645c412f5153580f39b8049f098552de0504bafb9959c6071cb9455b265a6ed0221f8120bc6e2dc7c525fbe58706fcfa30692cd258ea3c632ff076d748b6766907b0733d222c", "7", "42de76a617d685a0a83630083ff91cfddf2cce5e51a6f79659b4fda0821b2d0b3cc7ebd53e9c889dfc376126968e37c0d779bf1c9fd56a6f5fa91080050029462517ba7659b9ab873701d59c8a8f86d89517ef9b4f4e0fdb8317eb8fe4abeffe8b93242ff2d66f96e0e1f728684a1669083fa4c1fafe173d4f6d95b8748dbf99e3423068cf2ccff55584684bb3031bcd59e412cf6fcef316ae7c8d336cffc2752124ebfede215b042515e20ba7430c13f768ec2461ea250ba64a9c727a4292568ce581df5bbf7219d145cdeec4298bd0d60ca62146ac88d8b19b4ef57e5316eccbc2dca49c1d72340025600146f093dfa410b583b9d2a17f491e0bf77bc99de0ba7ba39d8bd38d679ff8e1aa9a5a3e9a0cdfebe94775d67900b7d20484442faf2c47d91fcd7a5c268f48b740da20aedf8ce0db03eaaa65dc123c894af2eaee7d8076bfc1d91ed0b64043380f922cb6872dd3fdc660b22705c67507e95cbae2008a3afeeff6eadf003f4209ee11a7ff09a988062e8f1d751a260dae0b10ea9dacd3c13ac47879be499b56dbe7a7ab39c942e10c655a14739e2a4ec47193a310a4125438aa38029bc91d05773e425bc5b362fd0ca8b0c1d73364533d1d392e3605996e9f1c4f0ae8cfead43664b4ad75cae5d4f1cfdec93c0ce74f14bd331c9963afa8ee98edf720180bc9c5373335829d5a4d2c396b03f9b6c9cb5e8a5d01c6fdf5649119cb399c289cc1d758078785c25155cc6d757ec3bbe7e62080512f3ffb3bf65d3d2377b07548794fef079e88fb2c086b5259969d2468850c8c1e42ab61fb582a1be4010be7d8e2da3a8d90f8be30dd19e3aa7ed16d4e81bc104b4a7e47901d470a0f37e53a86e857a2940cbe61a04316efa209086da193a6c706c78b303576763d2a0b00d987269b85629ae452487dc4550f7e97566cf2e67c88707424f5eed3141838c7defd0dd0fba2111b9e855b678c9a2e0ca0285ec4fdcf7d94fc584f23fd32f37d44715f0a08a26a56581e90e1284a7b1bdff6f3cda4e90c44388e453211c23fd3273a7cf3aad85709d5210fb50561d11e94d237db0330f9397fefbc791e266552fa19a807c31669b2dbf81347d36b5a80f724a0b1c948bcad04b4d4b2274c22ccb9be0a4357ffdaa14d0409d0318a24710e6d77df20cf1e21f7b2a79524986998eee93cc2639edde6ca7af47362b7ce39b2d1aefca096279ec06ae9ee79c84fb55c504565a2d63ff4c6e7258c3bdfe35ecc0b9855b7f27ca459e6a3d3804a769c7b2067b2f4a3f5792c45726edb4db8dcb317443faeff23775e93e074b9cb3883cdaa1058dbd2526330a2881dd1de8577c52021f4f8b7a49cfa8a75f4cfe54e25d3a9ab541645343f5b1ed6d222ebb52c1f2cad162c2b0c9e070f1142d6373ca5b38d7201f71c845ec362465b948939f18ef0a0893e0a867aa73a14b6ea277457488c3da8d9af921e890a468dc331535850c000", .Okay}, + {.Pow, "-24cd5197d865e34b9aee1ea0dfdb6d81045017ec4788f933a6c6d72bb13df3d4eaa08aba0db568695a656372da7b0e8a397279f0c58420a3a531464affa209f044b168febac56d29108c1dbeadbc58715a39fac6334bc291bc6c6560093a3cc74205509cad818cd19d80f7353918bb6223733b8abedc3da1fdfa97f24bd125622324528f0bb7d6430ce442feb0b169b3fcb371f8d46", "9", "-70a0ba0fe4bc5259f663cd04d5ef9686eafa01a472dbd5ebf3722ce8622e57498798d2451d8aa59ad6dd92cc19c38421bf52a1891d2cc152e8596b608e1e53789e6484297bb73505f983d1a0b150c63599d7fd4bf95d6ab1fbbddd2e0d80a6799edc1e250caff0c645ad8cb40237ff22ce96f77a51c644304285474129137c60f4da8743f4c0aab1f30f44662c8b5c9f513c7f1cd8e2878322a221849758e9fb9be0c35a747ddcf8fbe0e358655cdbf9e5499c76a7298677cfbe62ab88d31a0a0e19f390cf91636131b6c67a65cc438b2bf87e1b5202e0e121b98d573d48e78e6b07d2c8de8b59ea31e3e03bc041bb1e3590852054507ecf6a6cb9d4f80357920914f920bbe167ceac15bf9d9066e25387e36dda96d9693eb546f0b74c2c89b2e2a76333752b6a17a02588725601310100f893e91e60dd5441c56b895641f6a03ccff8b04144625935ae7fe6ce9ffe07cd543dc210a35c54233f125484ac4f9e92ec000f3be7b1e06ffd8cb9e47ef89ace41f7a84541c57fae03ab374c4ba20fe03a170755fe7020db113487d25b489b16e9f451f4621fcbcf5066c628fe5b894b988a4e3aa697cb8e8e9722c3cbea112e7c16f402841974d61ffaf13e3318072699f37666db3ae322927618f7248e92de014b4b0b13b09e38e33548f64e9d555b4c41ce4c480b93c472902fdbf45651d11c7ac9de8632f7045a6f412b9683e6fb58c4c5a797124c148b3b7cd1d3d5cc49747a8a630f56883beeed8eeef497ed11588f482974bbeafdcf3414583120bdcd5618fc0fcd6c90a074abcaf3d01e8eddc713dad3cef0f46599c6b0d4057cfc528e650009f7bcd74d91b58716da1e6c67288096b74ad5a626387a41c58f4a5f82dc843b72088d91c034d316b353d7edbb8381323101b7e9d00bf1acd8c7ac081b867a72e29e5be0d652f726f4832bf8c7266cffdb30e12d19752d4856bf80597d6fa057e53597a0b8d1fb4bd69731de4bb5be48863e2155bfb4f2fe8d650e1449f16c634b0257fa6497a59f35559ddcc709927603ea7276f0f0e6585b36d30517ed8025b5ef6232c4defc077e0f665893d59ed04fc1f096662fbca7d2a9a49955ec8c255c2ce94cde7580a68ffde4d9cdca23ba9bc1e65b319ad372900e7f3615a76602a980b4250aa24601a1849e05ce8134aace92eb6ed0ccc793ccdc9e93caaa669103d692f606333cbaa24853132c952b75612932b0ee2b291290ec14313b5f12455d37d3ade20ae679b64375a5fe99681d81eb0d88b6147f7805f1784a444a6b97fbeda3bede0d0844ecc4a8f5f9920a08740c4c53fa0d7e5510a1a3fb03bda1d1ead1ce6c8097c2f38bbc4fe9d627f228b9442b176d5df3b04bf3f64f6b1301e55a5f5c3d5cb7c092fd25152ec320a7950c86c49f42fbc845247f28f21b337cd2fd6668e70c8be05c0125813e0b60ef45e3d087bc2f40868fb97de312f7ad455b39fa518071f5312c8ba7521360e30c4af25a32f678122dd51428b0fbdb21c9907e5d35318adf6a3153239f6bfffe2f8ce91328ecb9e08eede9438314bb941cd13a96594242230a78e48a153889b1ba9a069c1d2d0591aa38013237921438683d55fda339a1a64b09db51a7c5945a3be9936a86f9d1f19fc8bee1b4cbdb024fd756f2066cee0da7cdc8b39fe219670c91176c68f940a0ac6cfd29ffd8c549b274cf4a462b1c3b75d6f715131eb6738ad7faeef75f572e64d24b11c50b1b5fe4148e8eb20f7125ac800d2babf4651aade792896c1adae97c57b7c072792826718c4acc096ae1bf66cc1e4e0b57d37f809f09787eb4f01a1787a12411ba625f1921748638ae6e174f057f92d88b9baf795c3768abd0136b8b72910baa86fc0202fa52398142cc5c4f9b90600", .Okay}, + {.Pow, "-49deee9412bd3083170518a620890be3a84048d98703989798dfe1c48d06d439dad9f91642b3026fca5ce95991ac90fa8a268f3e86a4152dd7873d3edb681c4c145dab0cc363dc51babe1fe89643eeff915725dcbce50654ae6d92cb5f7c43c49effb170144cd0960f4345df7048bd05983fa2b53bf13ce71ed2fdd310b747cd7abee2119b36e42f98980c8a0ea608a8c338a2112e2b", "9", "-e8b603e1c0f6e559c3ef86925cf6a6d83cde2ef5307297e6ffcf81e3cf911cc586fc5cd2f7062215d885db8903bd307d646194cac2eaa865539c927b44d23c2325629574db4575029921b92726e980cde44d353650180b90ae05cc1b8637fac62d4d64a5c34b30cb6d25c9c2dc5430fe38fdf5b51f353e1d7671b331d9584968952a2fccf1cfc3494e4386e8aff1639286679aed47856e2b651b1a63abc786e3112612b2e89723fa2aa6c858c9cbf5959376774c6fdaaa6263fd9895e119d1e342b06118e46725f72006a4a56e9b27fb96e7468d5c667dde076b75b57c46b62c39b3ee9a669f26d878038906f0cb509364a9e45a24a86b12693bc30fa533861faa2506156dd69ae105ff6fd1112b181e442d7124628001d2fe20f09dda66aab658ac26a75a8f50591ddd2b70e7d3b4a6811b00aec8a286d90a25255a48afaa45566cc9493eabe161fbee65f5f37421e2c70c8543ea63847ee2548d2b313a03c855c084e7624481671eb48485fa85c4950deedb23f9c9cfc87542b30a38ee1ae6ecf7cf07788cbd9ce6cb89a7f64f9c22441314dca3e4e8252744b425c89c9d8b4df901338d0a765e0ca32c47a44cffd5a06c7a5ffb95012d9528e4d8c260dc6414215f6161ccd9e4faa122d46c0b8abb482697f846711aa06826f1b4670bc4a94e0109233bab5e82efe1cd4b3729c903a99a93434577c164f7ac779ff4bfdd88e7c60eb0f6cc78b97b6d71d2af918e6a263c77a40af64869e4baf861f232897a43974cca3c9a5a7ba09cb8e853c55580af9ad2e51b1529a1b13700cc95c44b542116e84bb0eba8243476771dba92215577ed14c59685359c859785a9b6d67b8f941b7ad4ed50ee7277421cc3c52243aa017996dbcc007e604f07bdfb2c4d9fc25d859242856da1f301f63ad878be13b5959a797c76ecb2ab384e1787e9b2e0509eead2187b594ddd38bc93d69460c666bb29e766291fd2023b26b00b7a70f26e9db99e7465b933981d5ef5a3081ba8862a65edb3ae2483236e87349f90e974468e5045113b90ed0297bf69b14cb445d9402a55eb85e1754b45e609bcbc2f9a2dc888c53c0966f931347b927af9b70c2c22224cf7d010045e3876bf279ee5d01a76f33cf87da73bfc3675a19be65cd4c990b98539dfe7c69897fef690609bc2bd0359f3b8bdaf5924f43f769ed09a5f0806ab8cdda8cf721bd723de2220a574ac2ba7646ef0bdb7b1675fb7deb21f16f5ab0852bfd57064081f2a1f5d0d97eff66f3b2643fafc00aeeb3c446f3884144ef1a04c9a257b21fcd535440b1daba642048d5031cf8ccd37116da25c14e9af6dea85f7e8b1906bfca611f2283e654f16934e4dc84cca64d25439fe94992adb92cffd0d820aa4a9ed13d764b2228fd0d1533e01c928a51c5a4dccd88d416ed0940adc87786255701681ba2c926640c73d8e8c541b494b2322940021ce959c08e1c8b41f51f01300b7cf3d7107b3552ee34fa80c47b4eaa3b348aeb7f2dda89ad95b78d62b6f92534434e63219f54f03a38ea4cf46b731fd2d6a175991f3483dec25512e618ec3b8337233b1266ad2c73aa289bbf925b75d050e6f8c35a1a3c74755c22fa75f8c5f029b7d219a12e3112dd42c4aa9f8d62630df76e9c080c914defc42219c82eda8482f5022863f498151ca09b0173cd1d6035de0c861f2903b102a2096ef0e47bbd8f66ad85c108ddefa6fd5d32b11c772e4f2b0d0b890ac208ecc8ac0fa9184020c12621d4ee00398dd601a2d13938eb04cd5f856c5e28b016e1720840335adf6d4ebcf86a60ad1226dacd4223f072f5d9a9ae8f9625eecc284cdff2af4994b930c55aa38815bee1d58130cf2a280ec33352b325754455bf959e6077fbc5e735a96a7a48a6fbc434c36d103c84b", .Okay}, + {.Pow, "-3c92b9d91821cfe4caea5bdf043282bd48c983cd6f408c0236f9c2c1e64faf45a7d76898eebe29ab4b8dcaa110dfff8f74973db0c17e03710921537ae1c1c80996ce554d76bc1b70ee784405be3b0a63f7a2ab961cc8bcde57e3b85c9c63b826763d6291bcbf464af532e8c64ea68e3cb3a8d2241a70388fee9b7f4369e50a8f84037ed551c82307446b7aec7921edf84320a461cd81", "7", "-2b8a0dde8a444d21cde3bc3450c334cb8b5de4d9cb6139634dfe161e7fe4ba450e5f06c28b457df4bdf8414ed31b03b05cf17b36f9960bc270a390ea49014fccc385cabd47ae31753d77eaa85d9c9e1945f9908b77ea90dbebc7129f81aba99ad3911e9ea84e41bcb96bdb26726ade053cfdc9b48bd57dedfba0e60001da119938f561813801cca3be8cd560f318be9b37faa1ef25c586879020f388439e50c931acbfd80e09544d51ffba81b5d9c88609e4193a4b2946162f4c647fc3d2796cb8c21326da9f5e1850bc88b3bcc798160086c904e4480902c8f680228313da76ab606e4695da7bd9fa8f8ca09665ff456ca3ad0f36796ec0394bed8d9431e2db551afcc191bda392a964e634cf5a6aceb4bdf93d73584d07941f08f18ae6cbe03ca86ec94d6153dde3da93e63de8f49d350a077db7e338e5110ea62b1f12de4f032c384df9ae5139b638f8c7f1d39cd13154602c0086e0657ca8ce6c83788b0d9b96d24b7f5950e1d82875a0e5b4dd22600d1d0800deeb414d53ac1ae1b8c295e160b284e33ecd6c0f98812f4d42c526b5054f70f5b81c4b52ffdfdcc4abe90e47b7c5a7d04d5adfcb6b4835fefab8f3a456c22a9fe120da87e4a1b0ed36b0e8a7affbff988e300599f5d84a2c1567baa78a5a71bc814af764bfa0d772afac7b23af6f2097e2f0f63199b4df6ac02a11a7f28d1a17021f8119ff62187349b4cefb382fd7ea6dc06341f6f3b7aa03b4dc7ed6a2635295e79b89091d35732bccaeb7d00e54d55f44813be77fe885096aed5f8ce8979aa350e9900fb45bf3ac839e8db8bdf99967718c54292f854447ac01a1903d352c89b3bdf5d3d1c827afe544ce28fded384e375c3f26bf0d1d8f9eb3d6045afcd004c93fae4b3c07ff933e3acffbf52e73ddfa89edc793022d6f82ae9f9537216dcb0956d6b267a758690e0fbff3117ebd37510d271fd03638b682cbe376b296e34d64f333fcd3956fb25dd0754e39ca822b93b989d8cd3eda184b60461178b400c538955cf476c109f6fa98ff62cfa9f7249c3c9b6a0ce434c20578c3f6d1d1e7fcd172157c2f5d12fe09c856abe16c3b138b83a968479cfd122f1fa233cea26b1b65ffa92f25b58b4a93b58f06dafe1f4e5b8c0eca7196cf03bb2cb55f2bad772507d3a91446432ed3b3bcdaef7e14ffd702ba40c64601038ef28fc43033002fa7af30fe12c9b38e04759ac7f3ddc4ca17901ad59e6beac098f41db8adbac594697b04340c1980484338adf5ce5fae6a74f3a962631da2b7c985b8e87c1410ee9b38703811cfeaf8118365e624d4b956fe5a8afed30ff5b91f64289fd4879d40a3b11fc88f3d11013d235bf0b1efd2048694c5bf9ccaddd494ebd341edea51bf94ad1193e6de74a39a9ac43961e93798a82ac470b3430aa4f43161026df12442204f8d5cd8167a1a998a6ce7aa1bb125dae17cf33bd858130b952b147a669515effde81", .Okay}, + {.Pow, "-139a8e2b57624f3cc256b284d82676c9cbedbd4c417c1f72691d3a4671ba4f5de7abd59edf380821718b85a32c4ce1a19196ce3ce03124f34086c0fc7739f5d7062c28f3e8b27843d68129f72af4e6b1c45a5131949063a03564d7cacda48ac115e3466795e45503739f08a64aa92a9fa5d01e91c17bff501eb6b3accede54758d10d64c4ed4ff296ad1c067fb0cdda10316f365f238", "1", "-139a8e2b57624f3cc256b284d82676c9cbedbd4c417c1f72691d3a4671ba4f5de7abd59edf380821718b85a32c4ce1a19196ce3ce03124f34086c0fc7739f5d7062c28f3e8b27843d68129f72af4e6b1c45a5131949063a03564d7cacda48ac115e3466795e45503739f08a64aa92a9fa5d01e91c17bff501eb6b3accede54758d10d64c4ed4ff296ad1c067fb0cdda10316f365f238", .Okay}, + {.Pow, "-60b543fedd07f2e631a8ddc39f064525476718dd2b3a695979b106821edbc64a5dd801e92bca288b0938b03f32e608682cd1678e66703967bc6e9a2b9c9734a8488b3e25f1ad4de4e1f5af18ffb6cbe157f8d4d975abcba56d2647d376d5b1a6ed9ea99d07f763808cd94f2d63ae67cea00bf7b8a1c36f0d9f143b5688a33d701953d85a34fd2de2cadf9fd729987100d5fbe41226a3", "1", "-60b543fedd07f2e631a8ddc39f064525476718dd2b3a695979b106821edbc64a5dd801e92bca288b0938b03f32e608682cd1678e66703967bc6e9a2b9c9734a8488b3e25f1ad4de4e1f5af18ffb6cbe157f8d4d975abcba56d2647d376d5b1a6ed9ea99d07f763808cd94f2d63ae67cea00bf7b8a1c36f0d9f143b5688a33d701953d85a34fd2de2cadf9fd729987100d5fbe41226a3", .Okay}, + {.Pow, "3d958ca316cffab9a26305af411ec359a7649facf9f3e6ae0be04d066fb95f06319ec991dd14060cca9c9a9b8860555363b5dc935bd09a169e0ac7ac02f9aad634b0769c89ce38cf7e306964b6239d5d4e2900b72dea3adb7f600656eeeb1d9818c9beb7e1ddb6bb1a14bed58cf05f979845d3300a00a8e6560874a4684169c46606f390e8a74fffc128af60ec3861c5fc24bf43edb3", "8", "bc2bd87a4506b2b13f2177a37932051a3166500d23cba1b95f459e4ba017b5a8e9546abf85eb54c111fece29957e441d7ae38b554bccb6bf4326d5d486231d9f9f4bc92743a1d2e43f5ebaacbf2de64897052c63a01176786fb5e815170b833644beb7b3200ab09224aa460248869e60e23afc723f9e9210623aea7fa0bfacd30de6c3c91a80d65ed32482de397f33d53449bd03a218a89c828e72f4c2b287c7ebbf8454d7495c3c4d6d26e2ebda4a5754ae37a67a76f2e0d6490a5e03d03dd607e9d7a56a33b6375a6c6787a0aed5670bd651b70bc16bc14dee88b7aa7d828c9fa9d75c11a0c6b6c113e55e86f94f40e3f07fb0b161435abdb7a651df6b1c4bcad558826b1e9efce6868e3f5986fd1f6145ab306e02607b744b3096db0bebdf81e31f4b1d7f76405a7fffb08eed12624eca09de9c503f0b336430b0287dd011ef46d28fd9da54376b615dcadbde022b439eaa42127d802e970c7e538d47624ecbb30a29b3779ee5a683eb1bce274310e53d4056553a8f20609ae5c50bcebf840e7d29ef3b3e93e147e6a86ee3e77ffbea99c7c62dcba48d18ee5adeb41991c0a1db22abd741b213216a05c4039a1d8489f641cc155795e63517b7da22a51d25260c3f1b8960503ab557a855b572dd39d81966fa4b91e1bbd8300ee8fbfced4639cc27669118b467eaa13f75c240b52e394843f38583c1dea8102a2f4ea9a074d76052023cf3eb0371a8594cc3bedc63761b55ccdb13bf252bb5a13e5da6e37f31f4dbe7758521edc20c28b861bcc94c9618e09dd346d4e6c778cf9f03f0b9f408f83fd23bb94537f1bb623da8233ef672795cfc0da39aaa3a40bb4404533be720330b1e68f01a2fe0eb2b7ad8a8d2d0b9858a17380d8e4a06e58a7ae78d881b5b4e0a564ea628111391b0085e6051a7ac012b395b45ba8e750cd2b31be2c696ddf33f366ebdd0fe1e8bc3494e171ba0a9b7c9b7f052343258cc78aa90c81aa5adee90ea4e4e8ad618cae82e29684aceebabaf50810682978684165aaf5437b203b08c39553a13c558eb70cb092ae540449d17978fc0c55f3151028ac43b0d9303ae22f285237fe479edfbc8f95f4c105fb8cdd3d28ddf1d73dc1167c548095822233fa7a70dc11fb21b9b49ace9892e52631937d4ecf77658b226a9e791e9abf3063935d094e128d1e551c94cbf82f17703ea4710006487db0411f3129e0252b8145067e00545fd3713ad4c7f2c800c35940f15c74f1bc88ac7de7c238c857c3ffe14eac13087cf8669e83a989846adccfc0297b06cafc9421c0b0c3e6b16bfd1c14ffd7889d2d1ed73bfc61745f2066f53ffd2278a2866003a964d26aeecc235acc1754e8061e5cfff401f05f5612896820ce8a438727cf51c48eb32fdabf7621feec2e5d362fc286a32d683a5645c6eb5bdf9fb85f7488be03794cf2a099029c2e64274fe1f37f2f63636dcdd3ef49bef412e95332131ed739b75ccf3a03f68025fb9f5fb99acb4d41743749cebcb42834f116755450d10b2c6d3c857a09425ef572c952fd2fa8fdc9aeb50bfa7c896a162df136ced2b86536eb6e834ab25501e1a4866c2b7dce8406350965c01c8a2d654215c02c9bb256e669a302c99a2832f566be94ad7bf29154a9bd99029d5750ab7f0a396cf8c24b4fff217234cb43574a4798032b2ea1db09e466a21", .Okay}, + {.Pow, "c02ed8f74fd7b89e324074a7fd28d4c18db4725e7f036a52cfef4f27819868161cb57159c540350d1038ae49ed4b35cfe4f8b03ace9a6252e3832f43709b19fe31647361ba9907e253a90f5624037f5898ece0c665174310bc29be4f9fbf0aada5e9ed7dbb5b60af023e43984328d67c56896865d6534f33de534618e1d5f2ea29d28036a0b0cbb6be55e9af55dd7470a0b380f62e8f", "4", "514f2b152076fa04d211671a31be42a33ddeabcd232aab1832b28a15cf02322a0041b4936b3dce7a9e2cfedbf5ced0475113c2906ca4a9431bfc7fd7022cc8d435cc0d25fc2783cbd811ac0de3d306bab9a8fea200c5b780f1b81e972c0e10f70da00259895cd8e1f60bbf75f13f79a898b11730eca1f97a89b16275a59fe478b3bc6d5cd22c3ce77aca431f6e75cb8b16516c31e10b59eac59bf4a98f1da39c014619d5b0543918738b0c305a97e76d63075bfef4d9cf1b1c989dc8832a123a11c3ea2c82153633cad37f73cd9737473d16f1ad4a24d49068579c8bd532c46721deac2ce584e5497dc13c861d33458c775f00e61a670c6dc06f9a69abdc83287fc2641b7812927e1de2be7adaec90ae805ddc864fe033f108e229aab57d04d3d2c857b8676e97a603ac3640350d793dfc87f28804b0262a9602877154ca1811af38ba973ccb5061978748b74da09cf62f315294e73e6782a0bd67202e31024b65ee161470707b17c26fd6b66257f483c9868daf7639e1c4475cd2a0d2d754db8c8ba22fe608fbb92d0237a5f3b3354595ea07064fa3bd058a18ca8a14fb09a524ea2421598494c246b679b9d3d03639b2981a448ae8394a679643ad92a81305897c2d6f25c0137f7878270a5a24d1d4df1ae7eaa48a2bc916bc8b3d371cb62b60b86a376ca170070645d8b0dd84fa0341e4df854202f2b4132340e3564136d79c2590e3317ce80b10b7a8b07f628e18f80598e757de5f12814ece8836ebf042fce38e048bd2c3cd2e375909fa3a0b5de7965da413adc39c9937381be7c5942cb277de28306752f83bf758f856d9ffbd03751d872a3a6bc1", .Okay}, + {.Pow, "2379148c426421b07a268daf2563a6367126b46109b6159c55bf5f534899117eb2f1137575c11b48e50b1c705eea7daf8a126317ec277bb4082697f2045fd15b062b87a904d64dd8761363ee8b75b5bf2eb9ac9c031c0c1612416cdcaaed9434db305b987fa6e7d2ccd44d71daddb0b7ff1ae3669373d5eebddc54b35ad5c9f8f4e226e23e742d4b256147ca228f5f450be0f6ec2fa4", "5", "3590da2da7d4cf2c8945ac0e55f49d8b90211e757caf63e7cb0352bb2bf7ea1ee2073261a5827ce05d5caccace6f1b176986c958f6dd03a410ef7cf03b742ead49567195aa9172db6286e2588561b591b06cf542a35b8e1b4ac88a7270a251a41842c6acde5bb971e43a5f4bf6e9d7d9367bd6a8e58ef9e54fc95ddf6029890d08da9be7cc0a0337d206f4c020955020d61b9caeb88b1bdce78525ebdf465d1c964fa53f3f9d31da21369a973b4bdf6f02f151798888edf587a99b9fc181af4af97598cad40aa658ae55c758e8447904427aea1cd36689cc91ba65831afc750f720b641886695860c440660faef6e4b984bdb622a37377c6425a3ceb75821ffe761e3fbe2b5e54ad58311afe20069bde98f63e00a33ad1fb9aa630c5ac4761077a729fc8bdf9d2bb5212b858f9ba3f33141b9695b77957221fb953e312dcf068f7f73892d201d8ea62930bedf2676c0052739c63db6a627b7f568f6db58980734eb6ed8e06cc21ceb8d25c927b3d800be0d0ad570b391549bab538bc0d3d9253f52cdbe53a95474f357b32d2a6cdb34ef35c845b5ad651230a9d19ba7abb05e01deb92dbf6da18c39bb30e644f5890bd0fbd78a918996731382068818f79a12281628f35b94a0f9e1190dbd79aec6fa30409bf2897bd29ccd534887c0ad3c5b168bf25ae854f2cf3b7dc4bc0add4ea3889a20a9490c63af23b4f9ba118bfc9c046302d49fcf34b4f65a7acbc75c4ae21340b8ba7d577c17a85139391f957421775b97c7c453a9da293393b465b8c527b9dd47bdf7cabaf29f079dea5024869030c49191052b1b83c9dc6b363825349a72efb7453dff06c4269d985c8bd86ebbb4474f549075c5c048d55b202b73b259e70014e95853e77886bde451b0460af5705aea61b0d2bfb74cfcb3d87082fd3fe9839760e081892cd17bd5e2444b099c17927183b175a0259c0b453060712599ff146e4dc551e74660c68134ca226cfac1ddcbcbc20ce8c3a78cbc74b1863fcba821485c2db788c11db0e1a1813ec23611ecb88ef8743e5313e2182400", .Okay}, + {.Pow, "-3c90ff0534f346082fa6d33ef5c06bf30e6b4a888563926059fe864d28f804d15bd2efdc4bcf4fe4cf01f1e4786aba3de90340d16155004c8be1fd99237eb77c9e3d55461d05a1bda49403e6dbbad67f9ecc44e2398c117fb633c44044b692b90ad568af59377ad2cb29c6f833046ab9e63afacf033211ecd1b6d364c042914768f3f15f1c1d7dd87878e6bcf446e6a53906f0cb214f", "1", "-3c90ff0534f346082fa6d33ef5c06bf30e6b4a888563926059fe864d28f804d15bd2efdc4bcf4fe4cf01f1e4786aba3de90340d16155004c8be1fd99237eb77c9e3d55461d05a1bda49403e6dbbad67f9ecc44e2398c117fb633c44044b692b90ad568af59377ad2cb29c6f833046ab9e63afacf033211ecd1b6d364c042914768f3f15f1c1d7dd87878e6bcf446e6a53906f0cb214f", .Okay}, + {.Pow, "-c825ca790ab1731d9a7e9dc86921c4856af09ccd4b7b9f76163b67e1c3b627204089b9b94f5bc86e3271ee4a9581479a6801ee8bb6854101ab858a5eb9b42687b926def5803a9a6651f4f2bba8ae5d126e5fd3aefb2ecace07dff61cba0f7e1d6c500526dd6f08fde80b3ad3fd7fc0262627826288b3ddb22253bc55120a505db8013c650b7081633b2662c3c5349cdaca8cdb9ba1bc", "3", "-7a573f9130db657e83ae6989af36a92032e7dd8636ba2c63c205ae592c60d84a766be2aef76bf698687c56d75d161d8090f6c1dc43ac6c86e1020e73004830b222842de026321f12b62f99d1378b8746621aae86f4d0b021539045cae7816b63a19094bb212378037dd099b12055aa8a39401b4de0a5b1757e361a7e6fcd64824c38e0337ff13ac776ec20357b8b20768b91c3a59bca0eb2c517528a81ff0a8d1a1a525342f1f08534ef42f333ecad914230799d5c339bb874855c133751c81fcf0ff68e00db505df7320e3e98e3fc5251889d3f8b144ad7b252259b0bb6b50f1c0849128dd0fc1a8374e140b59f4faff96a85154a677d3a4b70ca6d9a55f0de02a5624011411ceec39d847643a3f57cf537819bfd7e9e55a555abc8f04ce2880ddd145b5e3c16abbfbd5a9a8a271dc33207b57cc6382581ce029b397725f3226bf08bdcde3219121e74b7aa1859fbba2ab619530dbc49c8f0014db10b4639ccdf2f5c97530670e3372f4fb3cf307d4834582f21e4f008df728eb84dee69402b176ab978ca1f156d54a09e7c54bb027c5f8b9eb94f10e2de988b928e979f69fa465e253df68e498ac540ea7b622c17cfdcd7d5917c9c0e3ad16139c184bec82593c0", .Okay}, + {.Pow, "-55c4aae762e4ffbfe5512c00b39b0404ad926c3269df4ab69145588e91e9f3bcddaf93cbcc5327ba68d278b0db091c76fdfce62667bb104685ae9dbc8e6ca265b32b77485f16bcd1575c7fda53a04cd8d6cc0bfb64f12cb45365ae8b517a70337265433f88dac962f6a6d5479870cc5156ca1d7f510b7ed0997dd3816f9ac389491de2d92a1c41c8ad6fdb3c9bb4194d1d27caaa6f28", "1", "-55c4aae762e4ffbfe5512c00b39b0404ad926c3269df4ab69145588e91e9f3bcddaf93cbcc5327ba68d278b0db091c76fdfce62667bb104685ae9dbc8e6ca265b32b77485f16bcd1575c7fda53a04cd8d6cc0bfb64f12cb45365ae8b517a70337265433f88dac962f6a6d5479870cc5156ca1d7f510b7ed0997dd3816f9ac389491de2d92a1c41c8ad6fdb3c9bb4194d1d27caaa6f28", .Okay}, + {.Pow, "-30de7efa00159fd2f5fec0c584e0a2355e43b4b5475b7f880d7a2d9ce71a1a8795ad6b07b7d85f254b401d0174448b230759480f4bf3f0e6a7780ad541680b5c8877dff9e3e36c212098d7ed914b8055bdc26086721e005445240efc4aee62c939879bccfd21dd3f9d6384fd7bb550406a0858d1d78a7b9dcbc9c70586b348eaaae603a7e41333cfdfe1ff1df5338fef20dd82ab7623", "6", "32bdf3181b88c5b5d8eb9164c25a435459cad4b8f587b162a973e2d872fb49d81ecc339192b13fbc6b34579c9db89f1b9ab67544bbe467bdfcdd5633d1634a90f894f9014185607e3dfa444a616ff2802aae3b1e8c5dc0bcb787f630d72ff1d025e99e3d93cf524e8b879acb22369bb759099781b204e030a9971a219981e120bc49a34e9addc8a52a9bd777740c226ae6c130e98408ad400cda4f6f58b3b99384eab2a06cfd2e6cc052bafc7c693bb6e02187e13ea42b3dbb67253952f965968cc1b1ac22c0944ee34256bafce680f8b8d916a6273a0b1682cc5326363efb2e7f99969d36a543bb5c9fccd9606568a4258a62527d6f419915efa9ce9a45664089958a6436b1db9cb365024d60802241f01cd7435204caf8f4c660f7a6d36b5121106c2a6353a0b6b3803907a3614fb6ce207740af0140e63bd3eecf70508afe73c593cfe5e37590c081ad32136b12dd6326c95c6b285cec450b26295fde78de2a44caba322b15a41f013ca7964623b5b5488e809f7fa60791971cc1ff6208583d9d2908883350062059af6ef9de5c03e9af2ffd06df7dc16d01a9c220383703842ee742fa19ec9db1ee8f9eb88a14ff515db07a8673e6ce67e63c1675c9ab049a6c1c368de4efa5321fec0645daef803611ff765ddb58390c309685626b4da9ac00c3c091efa0cc696240d54b851a00758f022101444a75bade2405c88c53f36d0f2004242587f5c79ae27f02872b74c1dbc3f9512a335671df9bcc2516ed0aa8ff04824e0dc8c44a37f6ac82cc6390a1be90c1a3e6a917e863d1846578879e8539c4660480dbc2b0dfa7080f83b32c0c376d52db763f6db2e756031e7ff88af7ea780145e51a4d5c23c484c58ab0a853fde63b39fb1bac9d50465bc41af04fdc9dcfe714a6ebac7c8b50e458139d9cbfcff53b678dca72cbd970d3a23a2cc2cbe7593f7bf07c9826df96089c73c5f8fc160a8f5a2b2a7df1b8c4fcc4c144ffb18629faf8ec8ef2972b5192794a92c078e322dd10974953f5af17e7b40c055eacfb97669479b83f31f206c6ca0443235d77da638d1e508d48efccef6b524c25920a8149c64f6095caefc383f4ac37b82e3f3387509531b54587c2e37323b1092b086a71241bcaf0307b3a2b46a6d02acf7af11c3a3fccdc597c09649546517a03ca41e476bffaf157e5fca09f27ef33bcb71f61764dcdf82e18ac9890413f6e39dfa7d0f5fc7469132638d112d63c32a5e0cbf4575adc97214ff8a4aa1aebcd64119", .Okay}, + {.Pow, "-e44f4a54d9509d66c629d3f66453b8645f59ab7a20ccf8435e6aa8ce27516faec60bb3d6a04ecc29cce5cd1d385743d8be22206b8826f94d3308acdde7803bf3fe28634e55cbc12404b55e9f798746c9d578480971881bcaadf72683e062942f63762250b9a43d7c483e2f73c4953f2beee1b51a870b110961e6913fe389a1c1c9292eac2ea95aa8e4c2234ddc6a73a32a2b5ca6aa50", "6", "80cf23a59a17329eb5035a0370de4a59f422649b1433fe995f52d8d9491527aa1e24f7439ce8ff40888fee1d26cb0509cc303e6af03bf13b404fe41d8af0135a5770f51bd42403989ace9af28736b43c69c768ebad290e6599671ca9aa978a05931313c0d21f989ecb3d3f8d86a9cf45c2825ddacf1d614ae0d003e6ea3223b4cdb8fcbc0e51ccdbdf2908651ecf674ff4bf889cd59da60e9f63f95f005de6cbb2c0046316c6076f19c019d92066b78069bcdf607c372264330ea579c099bc6c9d6cd382b0bd3e764202d41aafd6dcc226f015725ef66926422b23381818cd0d6c7b39198e97cd8c70d9a8361997d1e57eb9b9fd4a4e2363f64fe5bbb98eae714b7b205fa6ff9a1e822bac35abaa6c420dea0bc126ac80bce809a05bd548101491cb8081f3ae7eab25c994fd59153d918279773a97507df6cd36e56e329db25ba25e1c7467309d64ce1e8180ebdf1d5bd13dff653f9c76150b5877a734bf66bec9b0400fd429da2971a86f9c85ab88c123965b631a7e0ad7bf2aee082a7af384a75ae1f2c4c0c28df500f044a48408133fed92abd3defbd2649872441699d20005d26853dad0a023922dfb00ff1a0f999cb69929ffcd02d79809fc0ee86d5d0acbc1a4a9326cb34c33012887fa4f8a3c6645a68f46c0e7f39773c49b9d761ab9596b64bbea63819d629f1f140e57262a19147d7d1911a85f2d16d81009bc4ca595113fa10472452795b65dbbb457aa7b8919919dba44c899b18b2c2d4195fffe9f925efaec9afa1338ca55fd48f2379caa78cb99bddbe71d2132806dfefc9276a28a8d5decc0c6f01ff8944b5ee3363171d558c974fe4411270bb454386bbc8463c4aa2a81066a7b49a8bec2cb29247e1928fff69e776691eaabf6e13df19f2a4058b7c2e148c9b7c002ce0a676adb896c6416dcb9036925a95c9b69e82ccc6c5784099ee5eeafa7206e453d7db6e7281e0e2d656dc59049f6452cd0e2f488dfe6c11e2d8235bf642f913d7a95b09867099961de2e0fbb5b225b05510a5c8e5646a7536f52ac3e8019330579079eb8e98f45e9dc6212b15ae8428440945c52b2e384a66cd4bc9bba9d3a7d3145649964b41ff03249e8fb482aa3c575ff83fb647a926eaae6250455536f4d7caedea1dcd59e054cd0124215add88d014d8d99d6522163f0262d0f1e95383e789aff9e4452643b8b5d887431d321893396ce534d73baa44230afc96d15f965b79c9217a360f51b7fc6875b94efc467240343cd4bc9000000", .Okay}, + {.Pow, "6c39877d1d3626266e958fb28e14ca88af0b673343cda50d6d32508b06c716ba98a867597591ff28a6198d208eaed1ea5902b84c42d7a648f796f761f817510f2acbb3f50bbc9d4c30e074e83e2c84ce4f63a1e126a08f6f973faaa71c078685344de23d7d535a50712461fe2105b672140b63ca2bdfe5d4a68e5d5c0d3d79de2a05fe0348e1123a7f433ef738b02dc337703346392c", "1", "6c39877d1d3626266e958fb28e14ca88af0b673343cda50d6d32508b06c716ba98a867597591ff28a6198d208eaed1ea5902b84c42d7a648f796f761f817510f2acbb3f50bbc9d4c30e074e83e2c84ce4f63a1e126a08f6f973faaa71c078685344de23d7d535a50712461fe2105b672140b63ca2bdfe5d4a68e5d5c0d3d79de2a05fe0348e1123a7f433ef738b02dc337703346392c", .Okay}, + {.Pow, "3d6e44aabcedf94afb8148ee0f616d0e985a6b9a59a87ca88340b083fc5f2ca9d765be17088163d1bcede611e2bf89db059ac29e3b102a36abb451921e2677c415d87bcfeddbe60261f1daac0bb15d6f2cd470bfd6bf27fdbc51986c2fe8c29c3fbdf49a2f85ca3de3f6370090663b878237e0fac0e0e4c64bb85480a26c99046866d240e993ac3695b7649397228d15ad1cafe02ac0", "2", "ebdbc38732eeb8ddc39106c7f5b7dc1698e39b996bfe92bdd510cc5fb79d59aacd71cd16e1141f222300923c5d59e4262c1af3380da82ab93b7a17f9c51e56515bab303924eb3ad5fd7afbca8d59e1e50dc76a9ca5b593ed7341543936b8f6451e62d5e0bca27b0b3c8ff01bb49ddca1259e5a4b40c5ed2109b875458e48cc25f4e5e833b077d098ee12d109b914f1934f090f82dd8c3b99e27ac0a5988a3fed2b7a3c356c781358363cabb8a74e336eaed0dc6325d5f666a680a92509c77a1ffdf0d7f87412adc2faff42555a7eb85b9bc1a7c750f8396f64f6c3469f7f6e73dd1bd2a48e6d54277a0d203c70e68daf71a2f623db1d303fbf6413aa9e319a87fc33c462cb6aa1cc1320ee71fadbb0cf3ba17052ae162ded753a57eff5470f7b7fb6dca6f2518bd57239000", .Okay}, + {.Pow, "c61c83ea4e04d29767fb5b8ca43135e021a6714ee257f1c04d4c744603ad049b1d4b099812da3e7af91586db1852f17d46da74295839b805333416479d7060ce5c10847649b144d338ad75cc6ea04e1394d79bdd469340563550c7100afa63f18fef8ed63e90d13f765aa7fec1b6fdfa50f3df7c7eddfae8b3ce7ef8ab7e4db324c00d82105cb5b7cd011d236fb5d716c29a4057201e", "4", "5bd0de68bb0f523370d6c936cf9af78943b72b1801057a6d70ba19bc39e912d4261d588125693f4afe989c53049346f5987955d6583a006db487464eb0e5b40c1b56ff8bd47beecb6fd150d1e5bfac11d96c43f754197925aeefd57be97a650fb4debade64a24b77c387a500d805946217c7aa2f1f653cdb1306d8045c589142d5445effaec371f3611686824134ffef41134b0b89bd5a27341fcf62e108621fc212e76ca697e1f1def3931e85471e84638889b376e2e274beb7f0ee9ce0a93eabbff0dd289cf36ccba9f3a548f7ba0ad15978785a2f3a9277409d7b83f0947afa46eac7d9994b7253dfc1c1abf4417048db985ce1b1b6deef24743c4cbc3265a9fffd98c2325aeca66d73986ec2442a53d5110f65fd4a86a8609fdbef3c48b39a4780d5a328f9cf082787034320b5eb67c2bc5a2499dbff62b1879cc2dddb27d3d5aa588c73669ffe985363c308228e985e7e01c858f6a674c6d897fa8b5bc72db02bbac2ecfb7e420bcf82ea80e7d82f60fcdb8ec704b494eadbfcd0d7472a3147b2b81e91380ee709bc064897cc1aa32046847d1f6068154e3b0c624f98b4b72731c1a1b60a8bbbcea125ebd24a3ac958769bd3baaf0b96652d9350fb4303f41d0e60da06a08db73beb8b7a79eb2e8b0c322079a8c2d70fd3e3502909678d36ba17b753c56ffcd23615d0fd0950a92b6eed21d33c4b1e8cc7ea30867221844c0b63a3497e5457ac9e01139b7d70eaf53793a0c6726862dee04f338dbdaaaf65abf3d1504b1cb963c6fa53a4a8722f6d9d5221f256012fd7c31778fca45f1f7b070251748bcac71efd021ad89983056343847df3e85c10", .Okay}, + {.Pow, "-d8eba2457fdfb048a944d9fd2ce08f69cf330b3a5dab263c1e6ad5a961b115ba1d1516f1d4775725f4159889c0d10e3c8ad32b9d83671820a845109aceb19fb19aa79c49d6c93e4df1e7af40afa6eb1ef2b4b7fb1f32a1acd08abdd6033eb151905b9e0abe22f03a52b56103f5757598494863c2255d7e5bf339ff05bf56ac168b64317cadcb385f21aee3a7397f044c9813cead1a0f", "2", "b7ce7ab89a3e46dd8c9ba606857a792b8c7577e70dc0025947c2abf6c0ef4c74634ab10367df71dfa672d742ff6bb89f3e3b0c93112acfce6996ecbb38a2eb2c7acdc2efdc29cf204bcd09c669c8b76b609552b41ddfbdc85bd3617ff2109abea60c1da99f84a7bc2c7fbab3d9bf8e61d82f1e448aad6b61090807bb61ba8b18eb9a25d81cbd57de1dc0de9de36cf95bcec77534c11dd0ca449d2f1c927013fd3355cd07a40e2e0d2c23f1bf7dd31112d33ff1e43d647335464e3f9b33a7d3743dffd0442ee34d1ba8cb760843544fcd31622ed49a3a452a49ae2b7f208831dffe452dd243c98235bcd25791a5ccaf912864914d775ad0429ff52593dcd16539c65c7a480e985516c55c3ced26315ba143535bdcf02cae7d2afbd07065521dce037c2f6fd466b9365eed0ce1", .Okay}, + {.Pow, "-a1a23a78e07ec9bb39bea04be395126d613c2e046eba6a00a8caa78a7479bf0dda1ac3914c34eed4bec1cc2ba70d70bc44808f64f011992ed9f5b50f11b00580edd91379eb36655105ea7f7ef2c4c78f6c0c3ecbc65b66e46e0fca64642ec488178b80611497a8cd31fd50c8f1031c19e51e30e268df54d13c0f20c4be5d75f574c7dc47c2153256bde0b4e97b716232875b61794174", "a", "293c7d64251305e9ece5f671ad7214d78fd39f4376a795d4289b965e89408195ab39e3f1eb785e7dbfb63e99021625d88fabc3868e5b373a0034dbd594c2d83ded50346e6467e933d54e456cd8412c1a867fdf4e7599a826ed64da20136711aefd3182c9d5a0aeea5502c9bff7506c968cbc151733c90e193cac3c7ec90db74270d6e35ea4072b861a235e0dc27b12c8a803ebeb0b54068f51456ff4e98ef117fbb2d5602a7b34b81ddafd5b4bbed8a6d305956aa66b40aeae9ea15f7dc41eb3aacf16e5ec9c96cfa869ee189e130c17197a37e1c4a5e80a312b535ed878184bf54b3588146467faf9c49e9a10146c725b4180cbbd2aab4c246a9917bd669570d323af235635c8e7b26bc17e557e7f488212f7ebbc1b2a2a085c167f6f809fbf5bc6b0663cf6344e93b83eaa51109018943b2bba2f13d6bbbe4e7e877cb5fb5a5a8722dadf44c730d12079e46a733cececd43af52468d998c4c533388731a18dcbcdf844aeade2f960cb6a5529dbb3d9a8523469bf5573e33cbc554985af76deaba0c7d028c89c5134943016b1d3c508fd9194b55802d4dfabe05aba91624df8bb9547635fa49b78db03c31c5166feb6351295ea596b94aa23346f117f83f2dc6c3dfe803f238d1f9047ca8e2f0803f7b8c4d4bdabbf7429476966753ab0d75e02dad28e38019731bc59fa2fe363804830e60d50d4fd813a3be92731f2e33d25f940e0bd4f93bc8bb84500516b6ba1acc4d2c8d8c3321769c09f4779c16bb1a0ed79ca148ba31e93b284abf3b3da1c7a1c5a5cfca7d0cdcc7d13d55f362f11208048d15359b263523f9b04dfd85af38f8070c18e9e7fabbfab5ab9edfce639ff3d4ce442b0a5d76c982346517add85e54b0dbcb51f273dea19ab68b08ce2a978fd7950dc368703082a9f19e75272ab56c3b0cea0d45eb191e6116132ee32f9f514bc77327556c126e941ce7448c5550539bde7a8314d2517156503fa300560091c5aa4d9d72a0d86a6dbf10c846f6aa0018bedd850428d63c0f20ff88d9b852c97b5ddc9b990b25ab57f514553b8249d9a84c924709c63c2cc78a8dc1ead20b413e2666d5db2d8b0650047bb68d3eb6609caee098d972b31aaa88f1ee9d0333255f59428ed9c3499909b591dea9dcb3be902090122ad04c5dff874937a839e121493f3c4b91e8b7da94db593c6db2037d6e784039748348af471ebe412ace8a2cd086fd537eb6ba55adeea0afdafe931f2e09ce8cced119405d64318b73200b9343d96b94eb338759c8828f0545efaa1c9aa5ae08d2ad9445733f8197be49067aad7c7c576f8fa3c1591e867689a7b6d8fbccd64111fae0837c966cd85559687165827e7eba0ba2cbdca0cf01e5d33d3955feee464375fe2f8e53246bf5acb392b76576c2f6c67680e1485bb2a82c2e14e3feb0eb52d701b3a22b0520c364517c265e94d2316d84e36cfd02fec9afed229bca5152ca49a19c6a97eb1a3ce0dd21ba37e35936a6d137596a7aae7268cef51baa9bb195c11b3e17f7f35ab1ada00e514c4d1726f309151a0ecd999aa797f5f01b367d479745310b033ca224df27fa02f96c0def1e78f73aa9a0a40e0fd0c0397fbb641a06bb1342b84ff518a4dcffafbbcb53d1846fd97722eedf4a1531641cb3f856d18f1a0c4688804cc185ab46f390df659800080d1236ed879f4e0acb027359b89118f5c055fb0cdd191204debfba629970b60fdcf481296126792decd21e52069408f807b2bd48cc21608f0cc54f5fd17ead9c55ec0ee26050739feec770b0328d48ece3bdccc473466633d1232831df4abd5604cfc7b80fa8e6b3b3942b598b59562ea0426eaebe8e9ff41c29bb72b213221cb200b1b75dfc7016b881220d6cd3b36b2fe82ea936cb8fab0bbab7894720c5b2c7cadc5db626b30a18c573084204ba2e46da2ceafa881b8d90bc12802188dde20e08eeb84c86751927e7c4c6cfb568f921576bdf9b70cbed27f15c11d8da92efd57b6ac7ee051310b0d43bfcc24c060139d6d6da8c97606958019613a670a81d8034e1bf447baf7bfb286c4014c30f41c3199ceccb8c30a28e6c65054473326e3405c0382561b0f4bbb245f0dc2f356076900000", .Okay}, + {.Pow, "84d4d825a02160d2e56e377a624a219c20dd055fc93b2023ed6914657b59173ea7f99d7c25ae683d2cb3e5e850c44e46ff0cd3138fb999dc38879ea200821708d9f877db6dd98f6852599547030ae41b6597a5f73b3f8cb1ded2fa455abcef502d0032c7eac0a18ebe921ecea50cb4eee4b2abcf525d2defe693d4030684aa5fcb530728819ac0b31abd36e31613ecf98b9890198842", "8", "15852d8a5243c1cfa3d3581faade6f1ecb02327cd7f8159fc84d8011ac52ee99c9c7aeae75e05a15dd85eeb67a12b4cfa5464ec4cab890dfff725d41f18b91e1c303f866726478852a80a543a20d41ae7de05b4ebee1d9459cc9a678f71f1dcdf6e1105cba0856897d7c349d7287d3f29828b356e42a71befaa913b246ee263dbd08a925492922648c34fb38f8194fce50bf74acaace0ec223ce1037e2bde0c25bd382c41913b2f2952acc2c4a8dafd71b5d18525e2d2f001a93ae7ab8329560f5b3823a7eb22b776bc41aa57712f81b2b3251d3f7f88be2be5f6a5b5398a54c43273ceca6dcdfc78eadffc4154fd14dc1f247b19b498e53b9dbc09ded8d274cd206e2354b2e960691200cebf12a356214ec70a8662ac56d5906b1966b6fa965a159da284e9761c1237b0cb31dd766d910e1be5988a6473a79149afe7467066b237f59a0d7de21e06a602f7ddac69cbe698a21a6210434404e9783b0277055509846e6b29614bb9f69492d1de04e6cd5c6d5c36d5e2b5ce5f5de83b09381095fb8e4bf0224bf294593fd483753382dbe8e5f01a244b140a355bd6f5871c668e7844dceb5bd9ccd2b43323a36a4ff309847e881683ef7f38e07be8e11882e5b6318bc7f808493afc1bae3b0df8ebf570b462f72dc839b48ac10d77e7c0ff41001d2fccf980788356e9151b32cccf69961725e7e42170791a002f0a3a32c2a48fbb18647204c7a4f45695154d064b74e1f8c057a4be279ab16ac4714941efb1c38a25f0768c2c432cd0ef34d9c126ea5902c8b70c01cbdac5e61eb2ff950af0bcc6b439bfa9cd2dd5128eefb90302bc96d09c30891f2a15b15b34dc0332b2ef814cefa0d4bf5c5ba46ea5e5a037aa15e92642a4839772ba6a2bd7ad7f8d16c865e6c14dbde5dddf315838749e10422341d5596d2b9abc5aed8367869d0a5d38c4bd80f6ed3fd68f5de1932ab413a86d2aa1264d2e3a3dbfbb46b98e8ce472b6eb78821b33601e39eba91b59393ca3cd4e1777254fa1c1a0defdf079060ce091a281931cff0fd8d727a68bfbf767f717f7422a70b48c7edb7d2b2301241ed969e95cf55ded3df197ef95e56142afb28c2ae64fa4e5ccfc0bea32bf43b8e39f28561413ca00a3fdf3994b7f66cbdcaa4aa1814a29b7811fd45b1bd10534cb612ae4552cc7b643005904d4b47ac08db5834057f31f95b8f6feca827d990f221aad8d730a4f446835343bc5f14b36896c2c770bd28f06023169111ddd355224472860588d183d88b2fcf10d9e1f1b949e4056acaa4b978e99abbd65621c1de1d8435458ec0db3c14864b1738e0a65be41031c9e7963d684abba6351b54cfd3730c0c63347a96d27c5dd01f1f8a6d67e1279c6bb8fbeb2cecfe2d8a28422e8525b71d87731a010699404b3cd03f6fea56010ce969465d7196f147b0f31c2609857da7e0ec1ab9190ec9217198cc5f81a6a5d640fc65695ff21722b370a65f3b844aa50b79d37b0f4051dd4d5cc22f33c8b947f55cf1d7e01158bab86f5809ac35cf693d168730de264d580c241d99302f9bd0083a3137a13eacc3e3e2aee522fe4665bfabf2a72a4fdfbd868cee233a087cf153f5fbb3b579bd629df942477f62c6ac25aca7cdfd291954fe4e064414a1e250b96049e7ca9215adda5193d64bc4dc9b66c1a440c6c07c1a3e2805dfa7e910100", .Okay}, + {.Pow, "3b41c70505c8f01c47dd7d839081b3b829e5c120aba4bdb3c425224dcd86e1978d64b6a368670fb3495df9b48fc8d4e2552901f210a366700674cfff5c9b5df2564401cc1abe88930286499ab0c1d6cecbe648fa5ee5a59de4a90a01bd2c5169516bf7930ed6668244d30567497336f8ebc01cc78545d5edb039faf4fa289821e1860f760aea7e2e83b6b66cc9bfeea3dec1c17ec58d", "9", "20013244696e361aafa0a4ea46bb7a2f9d70d9f0889a3386bbed9f158be1b671fe6d91f4972e75de366f38ea6b2734d3d4d8caefd7f84d8c536f476cf3ec23d38d73d1a3ea3f3e0bbbdfcd5e80455e5c00fe41eada523b34895abc1250bf6566dc72ad8228ee397be03fe684b447ad41b49e24cb23fa33ea45bb66cfd1a16485581010521a3619829a2f9a997685f2b1bf5444c96c284871038d94a1bd7dbc4f4fd45adb4af22c5aa8843fb6a4fa4a5edaed0a993346e6f0e0916079e04cc97bf08544da0515c0bcab41d9ec938f0b79e93d08803342be38943cd1c91f3a96bd97a3c9acc91950c0c6282c1f4f7133f69e30716140af2e23e064e480a9ae28212a645093bfcda05ea2e871d1306bf7f49a7c7972d76ed9df9662824fcef682985c3b4469727ab11106f90392f42ffff50c49905bf4adcf96c55ec8762556bbd66de0cdefa71ab5911fff1a2da439813098cc8c09720e1bac79a2e453b00f383f57e3b5f0b4ba951c6abb6f4d3a6c0602442fe2913fb21943bda5bb27eb900695afd4a8384188dbab0964808152f45aa0fbdef6c6fac81336bba54edfafa9ee2fcf03c704537f5941236289d1bef12c609ca202efb693575bcee9cf28dad84e7a38fc4ba63dd89b58f152ee43aaeba4b7793328e272b4612a4782227880e1f7ebce56d619a305ddba23606290d7710e7520c7d55e7d8311700f0bee60f3ee05540f8a85567f6259ba170bef7853b3fc8c2a95125c5c0a89c9f16e32a3a435872441ffece22653c4b463016c45845128b9d6c81af0cde1816426011fbe87b49119ea051d293726f17ff67c193f62d18b4869d20b3e0a7f70d74dcdb4a658e6e9c2896258020b674187d30292e0cb710cb5370d1b5ba64264b34db6062e1e2fa1cbe62a157c5482bb1ee459bb31de29e5f687ba564664c8962af0a3f258c8c2848b8770ccaa4447cc96d7a56b01af72f7aa385ed044c2eabb971eab19f552de342345561076e201a49b5ccb636b40ac08daa49e02f24d480f40c5b3f81faa2313e3dd352e5ed0c974bd3c63c22c00578786f03266256651ca19dcc4e2d7a6bed05091a956ebb0a002d969b7eddfca408acd0ec73b8e27a4a4235859ab39c27c8cfe7fdd1e58db37fbc31b89827a1bc80021f7c8deb2e2a38f44f30546c33760ef42f1d8c0b3d168125f39e929b2ddab9c19ee4b5b33e215c866d0c0396f72e01fcc8d1f2741e147d78ee7f1ca8a9cd4e4442a8a6a39e3245d4a8e3c9853caaf994f186c7a751851aeb9f6fc53bb87cb9a5c8c706c9e710171e7731b94f7aa68beb49d5e1e9cff8d6e6d76f5de2ade6164795558558147c70236e3a3dcb47b987d0da3fbca2980913d37a3a440b8fe6c32c87aa73ef2801d91208acf8afae6fb4962b4cdacacd9e1ac948c1e213ebd77754660027b60d738bee1a1b9d5b902954917f619463719c201ef615a6f603188fc5f5189811b3325f81ebe4043e0176cabdf560cb0c19d5ab026133c0bf64b02b7cd4694f76ade534697ec7e2faa3264430781857b268bde34850fb80626a18c8e7e4a57ed5d03354e24015396ad11eabc17f77a51cfa71593ed897d89721e8dadefb05f0ec58ab542988cac3e053886429a965140f576f6d1310e7cd401d8876f81fc47f37620ed6ec6350dbb7493bc688408d8a6970b6e1006be39be54681df97eb7ac53b9c6462cde28f551fc119c1b3b1ff681e5c3ac22de1abb072fa240a52f08d5998ae485447549ee39e9526af7a44543cccbbdcbf4f2e1d9e2b57b61fb4a652ea4104d488b6102c3f910a2cfb498f4d5672cb885f193c7a9b85f7f076feeb893bb4844322fdd5f77ff0ca2588947a71c53ace313370b147a13a6fbc160fedd20f899548f54891fc068b88a47582136e3f32d", .Okay}, + {.Pow, "6bef477eefd9cd38e9ffd4b45752f33dffa6fa9aa01dc17296ea3e74381ee5a688df3108c9c5747349ea9329c8592d7769daf3533939cd75559f1a41f6845d5934cb6f9e7421e5d6fb06c48c92c2ca782d50463200876b508975816a08759e5c4f6d687fbdda1d08b2c65a5106aa5ff4d8e4b836a186b4b55f3dfe33d3993df3845d41781aa7efec7b8f986f994102a65024e31ac9c1", "5", "3692489a0e707762d86c69af8148f3f85adaf1e799c4d65c571caeb9bc36a571da84b7f81369a9684982a67db470aaaa95857097b955fd7bd4d3ca525aa4c10f0064f0931b711dc4177edf7fedec266b8304f313d888a1a9a03ea667bb7dcac6b29b22faa484f9e934f118b74af6544304170f1bf7319e14d7be12e4753a90f1dfd32030dde468dfaf631f13243fa2106e97d7fd4dc324f1c66dbb961b192557832fa7117f09ef70028cbdd4822771b554a3997de1592ac0da15b600d7a37e6da10fffd0eadb07dd606967d9d94796c851049c13c8885d57c431b4acf7b4772ee9523841212f584c8751d001adb68a0da5abf15d06471542a374dc4e36bf1a1b2cdf65ddb3d0cd105b156e2c4c490bcc57c60bc0aeaccc97174aec9a8a137364a110778cd5e08c13345bfd840e8c373d9dcf24f0a1e346e0f16f62c107daeafba51a827f53e20e59c0964f7d86f3df4822e9274c743af54fe4baa6deb2671cc5cfb0ab2876889d7cb692c3c1b6c1926d5099b106a87d615eee2bc63528d2cb57f1755d7c562b48b21f299634e7867dca279d9d3a120db1fdb70d887fd69a597499691b9e8d762232faa8aa888cb80db2ebde126a8e64e4b54d876aa1d6e0c9d4d75c0fa100a22a41249e79354ef648b3f0f565ca3abf281857523db22148f990c0e06d9e41b18c1b6dd86814f5d71f117a19b1f42085be8b9bb00c1f71d9c647efd960c538bde3ce3303898404b56f21e07aa6560177789d4ea729e0ac0dec3fba8659180082583f612ec07a334bc5e6465049f2081f9c9aba8d619dbf3385339e876fe16b0e76208416b4c996a00a9ae9d2a661ace0f6442714e7b3806bb65a3a0f844304e8b981b7f785c1e1793e72333cc2ff57684c8c169acae600003e2c3bfecd46b3d8b66572c0c157d5766018cfe3605b3dcfef079edee98958b0f93e4b8cabcc0c6a3fbffc41b997574451b181c66cbf1e0660a3b369f46ee334f0ff47f6d033aaeecbfcd03f4235c727287a1302d5c50f25d3786dff92013281e89dd35cb68be1a950bba0b751490c1", .Okay}, + {.Pow, "-91f2df9d02f36267013ea5c5c70663a1b64a297d8e208c601c44ce8d87b22c40185da15f2ff5403cd9319957409faedb58e196a2c6a65251a89b744d1ef9c81b71a20dae2ae802f935e4ba977ba76c15fdf54dcafd5bd63814af666ce2a156c09a60b3406bc1a2c35e3d6696230d7e842647d7b734c7353087812a88d18191b993a38f33741cda92db2f1259214a3a62cd1ac2685de1", "9", "-1a0fcc93a174b16c7f198e8cd4372572070d6fc471aff9360bc8c73354eb04c3517581eb45aad02f22d371c4b953593327a031cefa44f09b6832a1f003110f0fd42b1e8901a5e5dbda08c7a9fe899b4c9bcbb45da4e3814a318cb713e97a5d7bbe5bf4fea378021378213ecd8227e6bbb439bcec9017f27d84e81603a64ba832ee17a46c91de3cbab9721903613d96112c2273b0199827f5f495d821042d1230b4e24c35f6dbfb1d7cb931ed1a3241528d38f1df7f1a06d8ec3fdb9e4f1d83a8f44174aef4a5b711e069a9a0d01b032754bf6c719868a1bbcfac6950c727860f8cff7ab7535e2f0d505d4e643f10a26094cb63c4845f8e9360d5b77cd2ab7d3ae31bc0c409464f3e338584daf035de1e78f404421cd372e74296ad88e25334bd63b07a4a111efba4396b945515350a140418b5a8d59bfe3ded54847416d0da76f03b9b7c972997e75d8c22e4ae40c29a6857c603ad9e4db958ae8274adc833af2eb661f63d9ccc5cfb60e8e4f5c8d35135f2b75efe0f64966a1e7e1f0f50fd41f356a61a7f64370a5cb102aec3a13bbf8db947186dc64ca93f92c60f8ae37115308219dc624307aaa3f78b0d311a24bff59fb96973c0b2a76b35d4310c97329f80e311f7abcea4ce41ad959b55ca72694acb9df14621f3b1558c6c8919c947a560dc887a17918b6c3432f82a9fc5f879ca65132d50cfdd01c4438f90f5aa3abd35702b0c59522b21c7f58e071458578a9196c9cd0770a95ba9944bd79d9922c124cf9eeac7acbba543ee0fa60610f17e659bc1c1f7a3f2a069e256fd858a738b3e7c718ed5199e04587638b924789a85233d3ddd3fa1dc397c3ab5335b39e06a362ac2d5a241d1a68d4cd91e7a43a080c7678d7a01faeaa931bbb6158dee20392529c61967f514b2bacf8b77f04e3b002f327600d6535069fbff84d89f13617d37b5f75c8fda483e7760dd38b5dc3546f3fcda95b0b2ef596752ff6414e99b19098a5aaadf8f9cf9a66bc2d233b7843799bca33d18ead6dde5a45647134ced994f127e089510114ea31e16c1db49e527413d301d9b90d0261825d15a655bcba8494fe8ca350ba55404ed8c11c8ff1d4100f033bf1846205f178a397b879499f86cef1194e59f48dc5791f5d548ce0c34ef7ddd8ee7a4b5842ad44f2d552137de0bf9e996764cc646e8e18cf2ff0c9046d9c5a2ecffc7cfd4465e9d5fdfe310adcef389353dac88dc52936168fa0aab61d02db5b7e61ba7d56c17653a4f46a7cd30a6ab4bf0af9867b0f9c700c89d5ac07fcff612d952fd46cd8eb50247462987cde6df843788b3eae1f18c463dca7e52abf623692af88b899dc78f860e8393b56daa00b387d84761723c94475c0bef50f14aaa3aa54b925a04c3ca452e4835a930917ca594a6134b703a0f7f3531052f51212235283cf4e3fb74411ed3c747187690759d1036bfb0abbad9c281045a48aab78a5e9e134c23bef51fc03b9c2bd9d167b3f7cf28e38ae912891ab24e204971b70522c1921b3ca3720ebc803e2bd0bd48d69a369b23a539c61108772aa3026d3c76b48af811c67d95fa8b7f22f94db601080fb0705d8be545effe2838dd176543bed52d9aa15b290bc71b360cadbe8562c427b338a8fa4d739c6e6d5a3a30eb25e485f631142a8488c0d61af0e962f7ad2fc368d7939deb609d767cbb680ccd7c998b755b4a0d52db9b275ded507b6e3d93e53673ca45fe547e83c30fb78c86c0a9b64b869ef75a53d65a5cc31b5a23b19959f368627af86d531ecd069afd245dc914bdae83592bdc458915055356d65d9ba6c8d0ff1584f1111bd57a802d508c5c03fe3f62efe2a0470e8a6f221a3d0a74e0c23240af49cc3ef1e22439fe7fa11566013b9ebb63b2413ff6f8f9d7e849cc3dce1", .Okay}, + {.Pow, "-ff04c50e34c99da12d0dc6c2f0e1cbf6f8bed4b83d3ba61c3fe36879bd84ddbc467662283e7286514344979f7ffb01468e3adca517ba92f2999fa8108f4c4adfeb5787694aef8223e490eed8dd2437ab79e31c19cdf0212adad58eec9701f8f0dbd6e1a76f99ba6aa698a792e52fd70ad4da41d47e843a7541e20f2eff33d253faf92087d38409b9b35b074d53a6b6c9c101c60f4292", "7", "-f9357bf8cff4eb7ab6dfffb6ee5a06e4a215be913c5d1428a72ae95af5b163bf535f7088c70dab705d1036c9e3ebb1bc0afaee376926c5d4349f0d59c1d0b54ae611c03666b6bd2d0cb892eab543486fea506d1605c4c20aaadf010b21182281040a21fd4116d50e9e81ebd12e3549ffa8cf7421aa13b02c9ef4b1bab2ebba9fa0229bb70fd6479d6a8be75db978ff6a8705159791065fb33aae39f9039460b8776d9f957dc45bd5d6fb4460c5f2db8a7de58a994f662b71eac2c31a43e9db0e8420ed4a5cd08908a33cc1d3ab3cd8a50a9a66ed07d5495dce4ce0a20d70fe9953af93e78f05c77cff5af701ea3354921459f04ed8a02a5fab8d36afeaa1880b59afdffbb47d15727849961df037392ac790a212060656d1e63ec9b1b3ce3149996f3002093019a6bb1d68d4d1c289b5766eee6a1f9f0cf75b1ab3d1acbbd64f9a5c5fd5ebbdb73cd31ab9894ca30d647eeacfccdea3530ad5e84fe91cc380da31e9a5862f9c30749b57a8b598c73f25fded16a211eb867103b6124e2443b8110200ebb4c7aea24a2ef6734deaf5ee255043358a10d40af4f90b05798ce40871a94610fd5dcb809dbcd880b5ca0689d35b51adcc3026c7fd79b3aeb3d2d6c4ef727807b92a4380e54fd63edd23cd5ba55c9dd642251feb603daf855335d70c163989c1842b9e62d7a36f071f5e0ea0c09b2b711ed69d5d40eac3626f0839a40053840f1d1b94328058e2b5ecde4326d574ab5c0be5a2bb5dcff5ee0fdc6edbe6126475ddbe47aefbc739c1dc5d5b1ab9651b46f0e951bac3fbc311a26587b39e96a6edfb18c053d51e3dd01371603fcaaefb4c58d7f2d9166f2a5a02ef6112a882edfc81df708c3b344c3677311d55c18d5fea0bfec5ff4cd281630bc7e1e98325ea409efc582ea7043e3b9a4283f72cb9120501c0d44af1c74b525ad52f3e31ec60bf39ad10825686293acaad272a1fb700af8cce10709d26f0ca5f6cf91b6386318a195ea4c642933e30c0eaedb1939879f5a4fdcc67acd4b316b47359bf18b32639138cc55d3d08e7d31d753783fb5d778b0a8e2a2dfeca44cbc97c15054a9a822f823d818059b1f7651ec478a550a2651af0f1f1e894ecfb7edb4798d69963e4e51f7149baece17fc7596aee04257ab514331d62d09fb3cb4e0b68991b38ab2b6dee44084e83e3e55201f1670c5d075a672386e3889c599961ca47bda9c37956b9e2c75395866b1acd18a0d8af1c022faaee5d683a43ed2a4223dba6e518bfb6c85e2f10efec5242020f4a4a8fdacfdf0a2fbd9f8e9e149df25e293029456098c1e14b4d85a1d0acd1147eb3ed82ebeab7090dcca91abfb45d65b95690b9144eb2c64312652df6608338c31c359e9cc65671e7a5ce03ef37e9be6a5d4b0cfc6d911897ae4069077711105a40574b2c6834205d4ec642aa1202c92bf23e83a629839b1854766151ab5156a05fd103616ab1e6079be9141c80", .Okay}, + {.Pow, "b8d1732d81afe32195f42a59cb2d85adb55a41623b6eabfd92a39a53e1fbeca95a822e931c3beb28563131dcd9ffcb8a6be9640090a12ac7faf08e142a7f542562cd4d115b65945d44cd55f0987bc46a7d49f5dfe2bd5edd71d93c7acb5478cd13bdf4d1b0419aea0654f92192cea4088195c1444682589b90f58fe2c5ddaebff0b4019d3d170c7b01c8cb319785c6eb45cd18518563", "1", "b8d1732d81afe32195f42a59cb2d85adb55a41623b6eabfd92a39a53e1fbeca95a822e931c3beb28563131dcd9ffcb8a6be9640090a12ac7faf08e142a7f542562cd4d115b65945d44cd55f0987bc46a7d49f5dfe2bd5edd71d93c7acb5478cd13bdf4d1b0419aea0654f92192cea4088195c1444682589b90f58fe2c5ddaebff0b4019d3d170c7b01c8cb319785c6eb45cd18518563", .Okay}, + {.Pow, "-3cd7a84397006cd2ee14512e66b484ae88d209baf11dec5d366f73045480233d6e9f49658a89e186971fb2e0672e53f7afb5fada6747b42cad61d27938d14435e62102276e2539b0550ca862c1fa386d872ac600745d2db42ed3916bfd97e58d78d26b9a0060dba7faaf082d727ef8bd0614f267c6b8f0531c5ca98624d3f4dbc016d6047d7f439ca63b3f61499fbee38186cbf6a37", "9", "-28970394719d8becb23833d6435c49b1afbadae02e0d17967ed0f36e29b57aba5b5529c4af86fafaff2f420125d47cbb7fa9d14cb38375491161ee00e2f53cdc5a9fc48fd0570dd71fcf686169b4b084e7edcdada8fe8c37a82f70e59bf0103f94b3843f85f7641bd9bbf7d8abdac0fb0333a9dc2ae03e65b791ba1e9002a7b9824cffc2f143458f008b83592a22a97962a85ae29d83b5648984cc52cee3a20ace9cfb0ea209297e72e6a62ecfac79011d265c44e656a8d94fd64fd1f5a4b2dc36f97e957d402e435833468fbb8d220d2520b36a9e9cf55a0b309c7b2899e4c8ff6c98780d13b0d232074278e7285f3d73e6cbb9a6b1d17b9daf96a19896062edf578b47f4cc4bc96ecd64c600654621c6f213a6d3efbcb2ca0ec88b78b684e13100962db74eb10662fd5d71dceaae62cb88f927c75844e7f1e50caf2ae5da24bd5165773270c3610300835b8fa5a71619c2e06b19911df35c42fe97091bee2f3b1637c2fa513b0229f9ed1eba8f3cd2318654b7bad8511fd43ac60eb9cd7b6e897cd9214368e7b93991641fd0f5835f3898669397423939b86455e0063cd351e28e9c7ffc37b7138ff077a60e12d811e98e40b1cbe731621e7b33c622a7e678e23dbd0d578e10f0ce66d7cc8d80560ee75713a42104fad3188d13b06ec977d2b08615afe208e3c13783b5dc72b6a1772031eb903781b70de79653fab8b7682e8f62fcfb54ddb9aadf2fd82d0832cd4c0eaa53c4babae9295cd0cb04d19ba85b119e81f369b6567efe9cfc715ea368ea26a3c7dfb827c2f148332e8f1b8b07497084b43a5098d1d44ec31e464e717b631ffa7184fd43e07d1cba58408f192e5b25dea4c14e37c76258cb7492dc61f9c0293d9aa112aec70adfc3066c12c8cc0cde64697a7719327cc28b9f56eccb7731388c68f3833bd7e3c279c2cc7fe8ab184c8d7ea5146245a4fda7ea36a45e3208bfacd04ed108d916b72cd1d97ab215ff2f5ad91586684bff11ce56df3f0700e4479082c8d46db544ff9cb15b8fd2808abe85cca0d35bedcf8fcdea9fe2fd5f57ae06476e6e413d3ddc09d1e3ee33f07822a2deedcecf29a7e94054aebc5c14c93bfa547d51ef67fe394850828fc58b5883146316d1525157a68b738b459fca08c76370956ad76dc2a7405ef1d01b0e3bef248800cce2a45ddd954e15bdea1aafe284066d464064193118783ba2fd2b65c2415016d4e973925191c64f0c35b0e6ab55dfb4c9909ac97db9acbe991bbff7f0363ec67311083e889744bf8dcbeeacb49516ed6f3fb390409c75129cff51e32cecafe42bf26d98ac0d7bed945159c78784e9958ed6261a0ff74b11b325c12a4335975b608b7068832aa52ace7b737f287a8c406752d4f6c54febf06ec659ce347c75c9dd388d58d6d5d886bf4eb255e1948d95b70e672a06922325d02ae0e182fad900a035dd1364e3a911f0967c8d16edb2858b11f06183d3d56d818a4681a3d62f8584333e073587683ce59384fb06167b9c253e28786d2d1b045b4df726a1ccafebbf7c5eca281d1aef8bb7e4d70622e4a74848e479832f9f419aac0bc217b2238fe3be0c54f44e1e270f7c36164bc3139068cbfe66dceacaae58110152e2867bd5eeb62f3b2ca3e3feb82756588f14a03b7c2212b3a9c6f096cb3ea6d2ec2af674d1bec4a98ff3a7aa5aeb237ecd0e9ffc67a99cae8db038f79d1c63e4f1cc0a47688b2ef7b39972699954f568fbbc3c64de36b5358a7241dec6507e73201100bbabb41a7b967ff8f372e5f28afa92ef0335afe6dad5d1788a496fe8659b708dfa1a3c55e0a210399e27d4ae2e642a06aab3749adc07f6d22565e8fcca7b7b17fdb878de9675a8a5a624a4c0e2daaadf2753ba41a88112c542107baf7", .Okay}, + {.Pow, "-6372dfd3f11298007b7da74e8a20126f398868dc21b70997aacc96c10878dcc8e55c90e631c0cbdd06c91ff9df4ab6440f700b9cdad2b5d6da6bfc3791b18c6fd9e1ddc230cf2047632ccf1119fb06325127d1d8ffb449057045372bef229858b986d14cd6f4f75774e1f10838e3d52d182925fc6a51a38701b0a599cfb9bc3fe271f7fb6fe419aea08b078fc199c797fe09f8db2b1", "7", "-577f50f91c74af6b28dfb81b56a42fbc72b1f84ddf17609af416de0440ff6214390e50cb289694522a9050344181d43e1f58a0a2b2414d6a496e84fcabccdf9830fb823e50fe46343984aeb26da376ab6804b9db6f45f0ebe4b1a9cd949fca2f919a9fadeb6dbc074a03df4a3d280b1748f4745be59b782c6529e3da805c1478a8e7efdaea455394344d2dce1c29ba7f45d856d9a5cbf5335b74bf41b5fab1287c18872c7934ce00de47ec76709f11c4111012e1a6dd7fec49fb520c1a0c3a0dea9114b073ca2d656f9f567daa10b942e9731b53b65938421660d22071bbb22210f51d1926ee46ebbd0e197e923ffe59ca19e2b9dd2fed0c471aaeb82b964ab2d690849f3e7056a4f968fce54a2331810e0551cc382dda636229bdca23da840921b27b8764f01e3767a749b9ff36dd514912ac9660d43c3c3d38dde35f381962537c76ae0e255b1c133f778921a493896f4ca0116ea7cd30bd800e876678b2213fcd6000628df4fcf755741175379f95e24724c8ce49532cb8cde484a5ef19e44f79e64c27f7a4bbe03b88f604f18a8a3661838b987ab32850f879f5790524f6bdf10809ea0f8dbccf5ac1c939b61e7ce6042945bdc022197c2e7798733a4008f1eb4793333d8205b626b2110110c07ac5ea9d6771784464367f13b977851fe2a43586cb3086ac42c69b4ad59fd9edfdef37f305e52a099859269df6bfac684f39a54f067332adea8722008c559a68f51349eb6b8f438201b137da4e832acf57df875dfc3e257126a2ac123f6572163bdf95101c6d96dc10b7001a3a30d39eba5bf2b4fec02daa646c40acf70eb5473b8e1ec728e3caa662f7ee9116c35c28ad601ae13b73d965b153799f117f2140262f04c06280cf3ff4bf5d1ccf028a9eaa397a6b51735259f198dbe4911c94c3ca6fc1196cf706751b3f61d8df50f198bae0f15bc7f2b5bcb447994e2276fc9f6caecbc30ce39b16beda3d205fed681d6a061c36fbee22d8c9fcaca5fac40525e18de1d080ee193e0f59ab1eb7f86cef94ad41a6a426acdd0dac729639404411c60c93453dbe8dac0558b6eefef7ad8bc4fe2e8b40a7ea6b2726aa8a74b7619663d555d7dfa56981a69b2aec8a99ddde06fe80187633759d79a801a9578e2db46fdd308edbe9f0c74c6393cdfafea5feaa584871dfbc1657e7570db4823a5b7af232a7e4b9ef9f8592c57f3a55792194b95c6dbb88069caa472d0eaaf23d9a69a4873bbbd54e7ccdf364f94b87cdf1ca497a088c775e0008636c1aa7bc6cb5a64ec5dd4ad926b5d084ca8c2a898cd7f1bbb61a75438d24369ec36c630830cf750e7597922acc21b7e7ef61d4ffc186d51c3bcb3522a5631a82956d80a01fc10055cd75c0eeb9a4501b71154a1f08caba8fe1c53b185534677f4554db765fb6eae3206f582a3ac349411f1d80b145fcc36c796577229338499eae75c1c7e717658477d71261fd1", .Okay}, + {.Pow, "-402ac76fa51be265aa0d69110c96d26e32a0aace4bbeaf66ec4f67a70ac2eb254ffa98933b6e84e0c37ff59c4eb1a66589462253fcad3dff15b4f3833a3a9553c711f9791f3751b5cfd64890f161ae3867454ac1271438e59a67bde81934647ec3883783d472fbcae76caaaaf50314121b212da188d7cac7f8af63188bcb32fdb05ab8c051ae4edfc421e568d5bcc7e0481a20585ab5", "8", "1056581510114a893c2e770ca05bdf7cfb389b0d3291dbc91b9ef43e7f9ee22060942fb0702cdc6ddf80a6b7aecd2bbf33b2c116b0aaee225c3c25bfad2cd4939145ca554f1ab5c668aee5d4539042be0804837da20594bee1729ab22935d4dea6883c40036609804fb59880594e73341d0322e5c0a0573e903b318c0f0869f5e7b2510543aadbe6f0ea1cd4c0c2a6da17c813132ee57f3844f936279f087ad18f9fc0c63e8790857ac9d9321a94e959859a620de62d20ac11f1cbee0ffdc0aa408d8b65ffefec9254f0a4d6c1717e5ebb8ce972478828a13902aee7ff872648e305acb5556bce8e827e3f853a944241e9dee4e566fefe154e6334dce5c3eee82cd7a5a0cd9f5bad0e10704def7993124b751b8392632bb5aaf67f99d5887cbed1a7d8d9c07d57ecdc47d4097666c22dfe1624ef177b1a1c2b4a036f603ef8aafec84cf2ac5f50d8f0a463d6e3a837f8a622f1aff127c955848a813edc102bd941e75617e0d6d219789380b1a5dcd12f81e93b9bae4888a82d126caa1ccbc70556d0e399472d9795f6130f171fc0b02ed7cfb35694c5d7c0e7936a775ef20777a3c2b87d5feac58e2a26685af9d199584e6e91c75ac2121d99ce03b9e6e697ec6c62dda713991b13cf8034b9c44e9732ff0e8af47f0feb29d7524e5ed6ccf89c4a537daa70bde0fc197b5e6c41664f804721a9daf12e44d493af73907c03fa303f14fb2f08d9af360fb41de7e4554a0fc211c7d3601d5ef93a28cc804af62d001303854c56c916a4d7c0ed595d53205f3c67d50c468c9f350d9dda12f8784c49d4103360db0d9ecb8958ea59148d5dc8dc9aa0a741dcd17067f9b41ef0c19985fcc0633d9cebf26ec8251224a1a274fcfe12a91241f986720c76d6b6a5a8ae2c6ba3d0e07e2bd62ad28758f44e7c8dfaa37002716cf5694c9349225538e6fc0aaee5e12ddf25322f98c5ab1946d5960f636fac0dd88ce76da81be6815397d9c46ee4fc14bd716f6e0c62748ff7bc586921356679c100018d72fb15a6b6faa2885595d7ff02b9ce44ee9c2c6150cd807b9ab70325cbdb9a01f160326b3f799d95fed67b3ca724ae099939372900fa3db79bedb05b08a9b4a3b8124bb65137e83281732e6a85c58f5055baf8a779dd69bfe0a1a9417079e60c61d85e43de0cbfa8544c453634674d28ea809903f5b1bd9fa054c3596b6f50747eff70c04cf112f02008d1576e9a448026d9d0f5514a9f5bc22b208299b481d1937fe4b1c991cbbfa4c4dfe881eb819dea279ef78f5b4ed56040c8243b17e3877e13481268c9f8e5672bddd1fd278394dcb0374cc317a63e2a80fe7070d8be482318a64105d57a15f8d1be9f2540abceebafb6676d5c97adc8c33fb24692e5535de2a0c41fc3816c3a34a149ee6b926694140d6fda8b6dc7c7163695ceb028d55dc82c13f39e74dbf4aeec5cda2ddd97ad1f7d72797e5697a3929d7bd911f05c6253eb1994ab4e9a5685f9198043c272945c00c832b3aee43422ac9c48f359270ea04b2ae8d0139a1f10e652c8d72e92213ccae39f9e7fb11465b5cfa295c84db1bb42f4df7b1b2d2a7b60dfea7d10793bab14ca108b9b630b1446938a6eddf18531f941d035d35b3f338b5c632caefb2ce345d1d7837176e6691ad69e1773fbbab0e468beeefc6cf905c88ba8398e36462763e719961", .Okay}, + {.Pow, "-3e3e6855e09f89532245ecc6d269095634762192a61d4aebb921de669b8e56b01dc232d6c889ed2fbc03206d564b9d19d6df643cd6a9371c26dc4b262c38446ff1566296311f4951e0eb0c6d539277c43ad2bf9242ee893507f3800074c244cb09eef4aa431562d0b67e080700b3c3d4cf01e5fe19b5abf633079576898e0cb5006b14e9648ddc3c19f85e8e42b3104cc62cb108b23c", "3", "-3adfe5570d3d20a33e5d570dec187e430413b4521f473130d62476b607133c8a52bf0293ccad247a7c3d777486ead5ac05b05e8169034cffce9fc45373afea2f28f7c2faca2322881446b53e4c3966998293a3dbedeeb9b97bfe220db6ecaeeb72244b26ea25a1ee8177b7fe0bccc945678ece83391d7cea8137d6897ad390f8fef1acd46151016db01e9c9de08128eea7222aec520e3ef29eaca772d75b6a190ce4e1f25840680cca2d71fb0823b9b9921ec1da7ee489af406f026e6d735aab076c8c8dc47a724feed2a807f8d897b1d702990b84392a4db944138641606d0a9b4eae830c8cb4117a308802c21a1e85d2c28f2442c1024048fb27162d0632c5b677c920eec6fbe4155de4a257db521aadb9907fc7d393736b45f1aca21c11b56ee8de125481fdb1e84dfd1c34997497b3e48481be72e0763be34ffb7c9cf5c5d1f31e487e59aa8324f64a216ad407f8ef5d96bfc16326bbcb96173b67f674c7922af8eab32e7b2200b541d16a2a19c9e1640763e7ecfee12ea6d0e0b4c2e1b4f6bf2db769a68f9fe910083b696fb57058ca3ff98e8ee38f538dd299f4b1b7e4def72c3de5fd8f6bdb856c2b893272da9a59dc8156ac7d6ef58d52fc0546ca8abc0", .Okay}, + {.Pow, "-a2ef2fc81c48182f21dd295680ad7ed4ab14a70c701dde364ebe8ad6f5ba26486f1108e6a98db7c20aa1362c63c4cf8083114516b40c3156f4362f58f665b52f2e485c71f4eeb1ac351bc389509f429b9479314e9cf06f715dc43eb8db6b87ce8c59a84ed5dc19f7d11d14c173b17fe4df71872c110844ac723415c96fbbc2d2d7aabf4ec378942a2475fbb190169a4b112b59f9c009", "a", "2cad5df9923753141c13bceb017676a9813e93817adf7f9c56778b5acfb1acaa0ddfd4413100dc3db421f61ea5fb9876265bfa1d9bdb1d71eedd1657222096029df8d97fe280aa9228e8fc02121262ba22772bcc0a0a60904b2529bfe48e192f690c0f61de961276a82ea422ddac7f7b860d2484e9e5539a7695054e46b42a79390de31c6d086a91d9a577869f4e0227348c8787cb7af33e9695cabfd07404d1393adeaa1d523a6d2093a0e3e9ae226d2a49b61e41486386c3fc4aaef0b099f623f8d5642dc225747ab8fde0141bae545037df3e46273344d094b1a09511ea56eeba31ae66b02b07e3bfbee513004031dc20aa514bdd7754793bb73dcd5be7cb5bdaf22af50642d2fa8e02111d467efd680036faffaee8de0a583652eb0248e56a743541ee398c7fac9036ddeaf5847eafc80762407e42828e34370dad06c579b31328a64369c0c1f69d3c3d7ad9130421a8a2b71849a245ff023447e75384d3c2eab3f15459d84194adc1f9b29a0c8e09c47e566b5787f67a7c1fe9a87ddfd27a7776608001be167226341cb1afd65395b608f754fa6a4491ef7f5348da91e0bf907d096871b6784eedee85cf32f33d9e1fac719592ed82345d33fbc2f1c825cc8591eadeaaa52d677851b8b0d2e20fad49be562ccccf91cfd3cd79e8c48fb150cc3129c7b705985ffe0b5ec13afadc7519a5faa40cce232a3174ead0f77d677c24c5e5d6288fc92140fe16715224ac2f5dd42c21f88aa3be78096426cd0e6b4f1340c37b479ead1e4d01603df45aa0bd90a7651a0c293bfa3b35c39f62b589a5c9a3bb7d6c5940c9352365965d1993a67ba41dabf5d04561f4800b2466ec579ac4f52b06720b209259fe19c8be4b3f38a1ca4b01cf681caf80673270bf07d6de0c43cd98e46b17b919cb7045c3d3d1880b1615db1db6d7e68ce687ff7e28440a97a2ef77721b955e7f92ce0004e35a232c2df3aafac489c1f26d74c073a4f9cdbe3347ed283e5e784510d27eed28c263c60473c1f911c4b51452a66f9f78120e4f7609d26e31fb8d81dadf3267a838375eb13ffda88c63aa035d58d90e4b633060ae780a59335c90182f369d15443c110a5071431af2d5182935fce33500d3c8ace31926ebe66d080c097bc00d290b6be889f43f0198ce077be005c197deb5d0c4d9993483524e5e53f7c67f3e305557a1bf51521129c2f482a11103e0d13cd9875e9d574999b4e20a4cf79c33473d2e1cbea2cf9fc4339a7ad17f6e597225f96e130b423705db0d43dff5d7f7681562d7fa1e2d0904cf1fd4b75220b10b212989c0826a41be4316e6c39ed5689f460fe03be43bfffcc2f04d9cb61862da2445117fdfbd51edc7e5e9e7d5a66bc09f950eb0a17bef1e09e06a1e1bccbee99473b2b163998b9e6bcf5aecb9d6a33bc6179c2dcb65636bbd00e3f9bb7f8866ee11b3e997e020a7b029c2661df29686b2145f18ac932c9b1b69ef2251079b42fd201da84b972c74cb990269142702fad64f92cf71d9d84c8c334a2dab8b64b46b41981e42ed53acb1428b822f45c624b6eb7bb79a4f421b241ca0c08298871894f358bf19d61335e475c28753e98cb65ebc3616ddc0bf2f99504d8852fce0eed13cceddd1fdfaefbab6189d3ff2053c46bd6c8b29642b200ba365f6626ed22e67d14898c5d9a3adfd7acabf9e16bef00850697ec655fb551a8901ac825c1b0f9c8f72eed4d3c15f2e9943570cfbe85734d4f1705c68a4fe2a8492f361cd4bfc0b0679482e35da37502b8a8748de7533859f7abf47d472b48eb556d835ec0a5a72ff5fc8830043baeff8bc5c5695fd19e09be0a242581dcd199118392257185a6b895813a6dbf2d0b079a47e982f74d749a39e8443f2940a00dd2fe7a4334aba9a42cc15c9b396c9e45713e2a1119d4b35c548c0b828041b1b9fe418f48b9b99e4ac9a532dcfaaa17c873fb81a1cf0fe18e46c49a22c18786ca169dcda047a4126d82b1e4bf92b2fc7f08f4f16251b341eddc81237b26baf0ee31b21cc411901f8983cc530c6e3a8b5214807f639e15d182b36a724c0c9040ef01ff13e91fd86493c0f9e40a1e94efd68d79dd165986a728c652c27c7461244b819b91", .Okay}, + {.Pow, "-e495efc303a5544cd86690d661cdc807f694153b0b09fef649a9f1b5d8a286a5bf532e0a1dc7c86ec1d8ae8c1b22ffe22b1cc6f5fae241fbc17d935df2e40bfb1ecd01e6d311d31e1874f443398ae41e0d4331665e7ae8286017bcfaf9b530a51431c17d06d6d89f9ff6a91af9cb77ed7f6f3be7e939ee74cd5bb872b12d4ffd4af132d8eb095e731af698e69d448993ffad4b6ca46d", "4", "a2bbb54ba5237d4bd5f519a5e646a486f6db93861ce59e63ca6f709b096ed4e541918e02ab34325572dadf708f122c42cb83d6ff12287ff76774323404432383cbbc2e5b478f137a526eb1d2c6356d42771f07a70106e43f493d21dcd27f74f3e6bb26c89d93c6c71941e9b6781719b648bc913d8de1e99458e33ffad89622d7343ad2c14a52dbb0a5f1e958ade11ce600a727c96fd07e09833de9db25115e5ce07ca2b55f89c099e33470cc48749c67d1471c38ce7f0e9aae575f137b65c54af7091ece2397fa4b7c6e218238fd4a5f108d76a4c44bce9ba5c0ae4d94a201d1a6dbfee8e5d637838ccd1e22f1ac4c6833025131fa7aa9b97d6f04671345852eb9c3491fc8aebef4c4746b94854ce0a48e61207233e44928c4270443e1e43e3a308eb68298ecb71b55330cf38873cda681aa40993c97e16e10d24b4e5cf97620d138ec9fc1f78f497992265132d5802b000268ede664e36617a9eadf3b92a25b77f829729db46795c973a71b7a37a90dcc92c672fa25f9fd8826dd978895c7ec09f2fc05442bf2a9ea0ebaf379c91e068f177db57ac24b608a4e821bd2c2bab5054e399ac1fc5b608f2e0792852e5ece21ed9610c60501504ef77417c9360033032c839b6a4bb52bcb2be37ffb7b3877dc1b7049090097a5342fb8f33d8a4f9b6096cf9dbcae35a50e56609d72b39e5fabfd988955432f7aa2aaa1fa9d6faebe8f06870e160096163e6514dc65ea238b590e935d72ead092cf42c6b56ab17696e1ecadcf8ea6281dfe63430042c3ac70df225c9c56200f694e563ed4e36cc7fec29640410da5731d59ef06b3f598a90e12b1e8006629b711", .Okay}, + {.Pow, "69334b27ad3c5a8230790bb6b9398e31c2da1a73effbb57eb26e0ddc29f00c6a34298ae1786e34c746d57c96e37012d226ed44430c474b51860888f3e2d0e87f5c7975cfb86f0f0e5f537f96a4849a328342ba9bf4ac0cebaaa074139fcd08964d3f77a3e060f58098bf2f36832350e1d2b23f946aa0c3f6bc92fce87b4d066b8477d19fc989d3d5b51a582a4c692ee7b51605426b0a", "7", "81b1be251c67ed4d6211a76cc2878ea344971291528cba6beb28e6e502c932b374efbd1a8303fae3ee35ae89040997fb009e7fda106195c908656cd4200735377e2d3bfd6a69b19a15f10a9d51d7cf93bd026ab3aa3d9054020934731323bf2ba440e3a5e09b9149e20a5c2f01934a7c5ba509a9ff8b9dd71bd99fe67e6e9f83acec652002a090f05c64c37476d2f384f2134afceb130b947137bf6f0bb3c008ae035d4adf5d179e637a337ee26eb7c083943662c6e502ae064dcf74779f83e326a3ba4b1c492a87aa3f2db8d366b018254e2468fc609566ba731e0bbc200ec9495e9ace9166e6b9bbcfda81175cf44d72c728ea8e918a756f4df13c2bd2d6ecec94f0c1adcbc4ebd258e26401f5d11d3122908205bc0bb72a8b1508e6f9564e7dc4eb229a873167ae2b547e97d5c081deab55e580a5bf6bad137845eb865b3ec874c54af20430618e4794c7de5a1f0cb5ae1c4335401f56b666e20bbef3e9f3c09d879b207e60850c3e17855b65e50fa80b5bf9a4ae0dbcbe951963db7d3657c83aed100e7d28711a53a8de649083a66aa8ce77ddfac2237c2b6f317435e3fa561b1ba24e5259b0666b90a5f72407f2bb6fa705330bff1c0a230d570546ea3bc31fcf6171365ca70c245cbde8a6864dd20ad92db4881ae353a40752f10dbf0c277bb316ece5e0aba604cc655529a00c515eee6967a3839485bed2d836df9ff0ea4f70598a3f7fff2d612daf3df5c2c9cbee3c77f3071ac19c0a5da6790a3313652a001c90727ad01baebb5399cb5c183eb85f2f1d37a0c924c8451e7f08e88fb5012984e8532542174852928c59658baaacd39fd156f975e0f6a43df37af42a969e608ad10add132a3ddf48f9654f9881ea6340082c84aeb5f1a93b4cfcfeb7a91f6245334515169f0056b4f59a955a45e45a65bb87adb3428e950870dd11be6759aa0f9c16ee246ef42ea0eb3502d87188f716c640b1d0746b769e462c60917debde7c3e3b9b51f0d3aff5e4dc4e24cb08afae55c31573fb4c87bbfacdf92eec600a74049513f7618bad393ba5630c17841aa20148a2d3a2fbdf9e793ee228a71110d0c4d49ff227679139e55352267f8819d035d014508344105c1f409dd72b42fcba74398d1c2c3ecc298cc5cec8dd130ccb79821c6f799b41af7e2c0a78636f1686ddd73edfd3482d82bc119c3fad874ab49dfa3a762e06ebcd2547b13169b99aa1648d3a48b7f8dcdc3a9e8eb5424f093c07f8c3c8ab388391f9ef75fa3038373017b77cf87c5e1c5133b914b35830704db00ae93da2c11f97822e79f9e767c641ecd409eaaa81d06c11dc4be61cd9b91e3023ce582815783c08d0638e252d8614f7a92c2bd171156e606890548c8be76f891730dfe8eead7f120c0656137e473e91fca4eb09c97c97b110444caa5d3fa6bf9fba17078ce9bcebb2f8d3d7b9f3413e6dfe91b04b291c94df1c1a1a05c9f42c8f0dd680", .Okay}, + {.Pow, "3dce04bacc7db4cc70da27f62cecd51edaad71e8087c4d9b8009b4e35c6ac5d51ffb94ce7d75b194da0cc7776d423b7178bbb080c4adcbc06697910f6b292179a40043fc613525e4c79fe5a6314536486dae0c17f3a28f70dd37b017c59da086e4f1c8e37f5af489f98491406a932bc3f80601b627aad432e5d4d6e21c9d0942b59e6e583c01ac11efd660b53d5cef441a725a468fd8", "9", "2ebf55ec19dec804c130ebc781e9e0b81606eb5730a758633df50042a0817ed49134cdbbc7ae13ef3d6e706fc6e02afa19754ddc7c5752739ead1b6b3cdbb0dca40cc8648fb1e4b383a176155ed26eb5b7cbc9528908e8a90d9081436c72d58f5d90d123350ad01f629e763982c2ce16f353c57828185e1461e311b2b68f62f013483f1a264b2466f64a71edddae25bb92b0228af85d1e2e5523e0a2d727165125eb45a1060062194b1a2c6c3a1ccdc5ecf681cc3f05619a53019f738ad9243c7a781b34a3e780e1e91ad497455772db4aac792ce16d6b33ea50de8567438ecdf21ab56c05c5931131ec3234cc3d188904f5391ca1fbf723d8e794fb91d18354b2f833627365bdffc2f63b3feaa26ffef61d03f8cc46a9ba440a603a86c2a4d702c9d7ad81c3b074bf06e5c9221fd28a901fc1afb7b015232c69a23492b59d6c5ba041acc0a5bf40ab9554587f6a3cfab13c84f48043de451de0f28637dc5f55de45e8f00818023e30aaa613dde571a5b1a2d98770a9a5849ed4f1cce12125e654431163d60f15296dbc0ed311e7580e885b52aff50dfd50d4a870225e74598a3c7ea1e915e4a3e9b42a5f1a79f0a9fc5bce30cdb11c8b6efff08c3f579d723e5f01182b3b4c964fa4ee45a62d721f8abf9d73846e32a3876df3f352a2aa8c7562487048ec8913ac389f5703e5ecab841fcd08cba1dbf6f135e9fd39bd309c33b42374d8538fbc4abc2e0c1e2a440b05990bdb7cd454e7fcaf472c2db30c34b58b6d8656c1a3d24dcd97a7f49dffb259e408e8a8e04f2c5ffac665026bc9e57f4eada13b64452e0912c6a5615d7d079268007d1ceabf967e3e7957f5a59738dd67a4f0a7618a33bc55a7bf65007d2749577ed96de9e9b672363f2eadb6a7bca6d5b1ddd3eb4b722845b7b4771a701b76e76a8899e35369c6ee44b52c5af772f1319f482dd4220d153aeb5390aa80b4c6f6ff8303ac0b8ca0601621657d6a79d5c6fd37f6c5455482e24fb15dcfc7e4461cfc64df837177f08a35c031e7d790b7aa925c7427826e39285d88af900125665ad6a613427c1ab4bf5e95fc7f6a3fc5915ae00f5786c5f0ea672427c391c15fb85662d8af371907fffc5c7038fd69e30b5a0b0d7be77fbf1a6eb81a62cba2bfe1be1946d656aace8ccc55efef813f31c3f36638529bfe934d0cb1cf4494ff46784343cdd740fbb0970c94e9e86e82ba4e1e70d0e2a59b55e65899a4b27668f63f69a122aceb17be166dfac05e85a1e9151b9a5f37b9fdd2ed4e13896e4f27847de783116a1fcae04bc8bbb5e310436af316a303d324ad65dcffdc4f49679a46ac5d4cc6e13e8e2f5e6bbae8739019503b5147f2127781563428fd0f88c9e4791b3789973e71c4b0c3c8446fd626082250af22f295440f1e92bc36b54966d8528433c6485b639631f0e4f3141187b4e8c15252867e8932b948d2ee8eb7868f06a00c31ac04119ff68c26dffd777242cd8080f1be1246e2473aaba48a2816ca882136114508631c453414ed593583fdeb0f6e7b08bf4312915f5e927a13a6fe6223f0c26a88183ed4d181589fa7e3c9e8483a02f7204c31336e4f9a8c3d06065981c79b435a427156f9506eabaa48e577a4474c199aac2f5460ee148d5e16f321babf271a9f41dac496d44965fa84c550c4454fa238e349bdddd051e2267673987949e37806ed7d249ad5f6a4aa606db6f04dfc2c3ab57811d5f4f3304047c50188fab995e2c055e0af195bf80bbeac4ca2d7fa882270f4538d895ef99e9d7c8748c3d1e84b88ac3e58b685c2542be6ce64282606dba9be2e05b3df2bd29bb432cfd5596f400de0faccf5dd58646652d6430a4a5d73e00c53bd04d8839759c2e59953dca7f48840735cd64d1d10bb0aa4d8000000", .Okay}, + {.Pow, "-b610622509aadf14844dd9644812f7df9c4e7e10e653294a69dc7ae408389bc6e57c0764dd57d335b493fbd6bd9d2d4fe2419ed4cbdae79f7b49d40897c1b3504784ebe3d5c72f0f15de3c55adbf732cbae54ff41dd3e95a592df5acb4f3f33c900818b0eaf886daa46c20a22dbd0749382419505e4e842cf8e4fc132c6b1bc0a52deaa628f38c74032ef017ea23733cdc9609b3cc9e", "9", "-bea42a72ca767b052b1bd5ea66f85cf09fb99129881263ea81f05b14be0a9cfa295ee09f1c45403262fc9b1ca0cb9d866ecc564dfba451c3f3164dbcfe5352bf3281ecc689667aeb04f63316d84af66bf00e013414cc266622a4ed898ae5f1746b7383b2ed05b2d5eb8ba57ec958a88bcb4160ba398286e2dccec03084c1ff5114ff6fa0bc5b21254b1f1117c3b1238280334487c9a66f90e328d2c088cea4f5f316026126b6299d4ccca361301f1de227d8838782ea6e44fabc0e5e5b7248898bbab6b6b99fb792f5d2c9325a659e54a73f051129711d42b79f6f5ee715dc35b052b0563e094d4ee1f292cb161d088119db6d8476d5de6607d658b59244c747e2390947f14487dccad001ddb00853bdf91288fc4bc03538f09697308bf18bf35db2f7bc073f9bfcd3f17b3740853e076842f1feed40446e9e33a52fb41441260b9a42affa8743d8d74f9511c1193425eda9531cc78817d070277d159894b8377cb667cba34193678bc14abf2cd66b19618dbfb735844deb03dae7fda82b3842440dd58a366e74ec0847822043f749282fc86346952a6e44bf911d6451bd204d00b75118a1f20f10b6a42b57c0b044726e8f32b565f6a4224e3e9907a954cc54a46d6163918e7d9da741dc7a19699adcd71afb2188b442b80329512ddad42c1887fb6b85195894d080b82423b3ad347e41bad4abaaa9744e95745b03c478881d7295b9dbc2fc1abd587af70e5289fd8f82789ecfbcad0bbd27054272281b6c39913d504bdd7873c0380d1666a6d556fdd81ffbc8dd19453fa669e2bfba6b8b697e01dcedd257cce16445c78419197a188601a10f46f9785e6aef3ee232dfa532c2c2755ec321a9d3289e9ce9459db2e11ca09f10a9c5de6d578fc2d811481a0030b27c9b5665019f566372785ffb13c38b1d601f12c0d3370f27fc6c8ebeccc7640673f97a44af72526d234eef3f1b6f238b707206975326740d7379d1b553f4a48d19d5eaba197f19edb9254da36c83aa0532a54d98a5dcb28a8f868f2c411505030fc59d3f1657167b3be766a424430e8cf68738c40b5d2cf3c3c812eceee03eae8f639652158b04787bdee356ae5c95e5f849afbed80f45f79f5a866e2436ee6fb6d09de93ce188ecc8420abe73108c7b3f746721414a4b91e9732b7ebcc1aa81cf3cbd810ede2746ed492686e1142e20f93f524021c69a1ee1d4fd0faeea67ed8f04e154522fdb89e4383b87bb9d1f5eeb7a60ebe2fe6676dffbee311527566c38704d363a1ecaf3bc5e8311a091bad5079220d24418ac813056689675f2d6c253ad4be7b503784bd89a7751dee0a564b44f93bf512aafae9e8604d688055ad9f3f003947f1e89e5f1a5cd783c33999decf4f71891fbb087b5a6213366d6640b11f9769f70c68892a7a84fcd7d94eed4ac032d09745692d9a17b3842ad257459adda2aec713d9f4ac449ea7f3d7fd915f712c92408d287866e0c4f12136ec0ebbcce1662c2e71adcb9c75afaae6ebb64f255b8eeed08b558420e8f2681da1bbf33459f62a568c57b6a783b9ea55b11610be832894a4a8a336305b52f7e38b63d6a07991d864e450aa5a4b79bc19083569602836a1f15ea52797c693ff35fb208f7a623b075481d73307481994629592c9a38c14d7092a20f32c39f76610e302b3f2baeb487c3cd35606db1dce5168b3121fc8090d38e1ac130d448157fdb1794f1a10580b9d5bea2754de090c00bb6d504af2e4225c01812ad95acef8044073b9be14312b52abb23e1480a962d9ee277e1000f8042981dee890e902e43f3cf6f080a4d8b4226568cf9739b7f86ea1bfbb0a3b9f688fd9bd3d0d4206762a5a1cc2477017ea66aef09ffa0a63cc145dc45c7ab469688884989b6fb127a6a6dc10b1a99e00", .Okay}, + {.Pow, "-220704f8ad6a8caae326a3e72731f641e7d8715fe394a757f6e5480526a4a1cffd00351a4ac4c33a5dca14b780e75ee1c43158d305f76f7845bbe859dd8d2400dfcffcb30a6ed43c006b445b28d5b82d3dffabc358e21a66d031c027263a9a946de5b46bdd43269369eb9f54b8d6bf1171e89b397b4d4138d59393391513903939dd1e9c78fa5d693faa6fa23a46a5c529ceaa4255b9", "2", "485dd8353c2802cddfdc04f6edbe3455c396578594caf3f9c977fa52bd7b0f73d8e3ba95578bdb577310c47f73bdd3cce5224a73929de7ae6f9efdba4401ed970caea6aebf3a0ce65dec4aececa7a05e66dc2abb3fed2d5228a1ba07bb5626344af0e67f7bc5a58155c6b0d2ffaf3d8c165feae73fdf98a19dcba06798be6681f0f12b9730c663d7431e1903798a62bd4ab94eb40459b01867e3d1a8c704f388cd68dc060ddb3e0d8e07eff2c9b8b53ab8a724daaac654c808e13824accb6e8337648ad23a9ee7b0f3363335d343dccb7b8fd9e425db14f806519bc31675ba046703e52da64c5c92fc7c6c6cd5b6ed7af33bd0b8ad8f792e65b11754c0f333314fdec127c469032ecc425677aabf620be16cd653c5c547b497ed6b40d5e2be7dda21b241c2d62c604185fb1", .Okay}, + {.Pow, "-cdb965baabed70a74bf4064fa62820d5050f465d1bb0ce85914f49ab70d31f69fba3b5cf2400e3ec06977521f489eb338ffabab1902daf890948ea5162ee655766c2132641c9cb7cb4f86b214de9de3778eab2d68ff9eb686d3b5c300e61c8c975926a6e4c04af9c567234d4a15f58bdecd9c80ef5e17a8c10dcf7806e933f932e4bda36369f04024789e027974cb8c783be43d7ed88", "1", "-cdb965baabed70a74bf4064fa62820d5050f465d1bb0ce85914f49ab70d31f69fba3b5cf2400e3ec06977521f489eb338ffabab1902daf890948ea5162ee655766c2132641c9cb7cb4f86b214de9de3778eab2d68ff9eb686d3b5c300e61c8c975926a6e4c04af9c567234d4a15f58bdecd9c80ef5e17a8c10dcf7806e933f932e4bda36369f04024789e027974cb8c783be43d7ed88", .Okay}, + {.Pow, "6878e870b5649e08f920698312e19e6665ef9be0d99a43e8064402c76503b27d519b99813318ec8bea77986fc54679cda13d68f1d23c0cc997dc2c1caeca3677409ad90aaf089be67c9522cfddb95318772feb5c650dcf9dd5df97f1b8f79f3012a95ca54dff8c0fe0c17bdb43218beb330ec4184e40666a5775feabe2c3ca3efa4b26ea3c73bae8e339aa68a97431b39a7868504aaa", "1", "6878e870b5649e08f920698312e19e6665ef9be0d99a43e8064402c76503b27d519b99813318ec8bea77986fc54679cda13d68f1d23c0cc997dc2c1caeca3677409ad90aaf089be67c9522cfddb95318772feb5c650dcf9dd5df97f1b8f79f3012a95ca54dff8c0fe0c17bdb43218beb330ec4184e40666a5775feabe2c3ca3efa4b26ea3c73bae8e339aa68a97431b39a7868504aaa", .Okay}, + {.Pow, "-3ecf07b9fb598c4da7e72262d9d2cbf4193793600c21de47f6c44d24196fc502a4fc43279e176a67ac4f9018eac32c05e35e07854bc87188ae27b28909847fb73370fb23041491fe0ee4ffc379508587927521111b90e79612ac61a8ff04980a4cc55a790d4a1a09a77ce69f668c3ce88c8a406527212dd9f0127566c6c697814dc27e86900a6a7e92505a1c6bc68b02c7fbc89b35e4", "8", "dc45a06f89ac998ec22a2b41486d2264ac5110015cb77fb50ea21a76c9e34b1d8a5a86361f346a98b5d1ba5eee8bd6a201f9e196fefe49fab13dd87ecf59d5aa7913b13af2f7eec769003f905e5a75e1a2a21c43239c47295066292628a7828a9c95bcd977967adc21cc29aa91438432c46438ca87521df03e3b52ab504d0184541ef0af27190bbd08ab57ffc1fbe6b666add0d2822bc25d62aa7a8e90ecc379f5ee1b1b8dcca20e995f5d25acdb83a15ca1f042fc4d2b42f291fb0b6a84bb267aa2972a1639a6802936c08d42bc275f8640caaeb007155a2ae344ed241e86df3556fa8370f083a57055bece655005e500a2b468f6a3a72005b334f36914d34c3aa26a9fb93c152b79e0902a7d07bade929e1e654503b19777c4012ca19c549778d537732501854a1a6898b06bcfca9aaccf195795803772b421890b559c2825b0e9880f46a7f03e9fd9da07ba3b2d70d4717895e224c75735d967c5f647aaa7204b3c85864110cdaf716ed70753729f214bce707e1c291d0270e6b3c2c8c407a2c1247912c8be41a1d645d806fc8b46ea24db7b7900a671096f084dbed4b4f75b7b1b50ce994c0cf35860eda040d55976fea3a55062568f5049ca8d5cf4081e663b8adc77c221d7628957938aa68c270fe42a125bcef0bb93109ed87f37a9143a868e27f87e1b9ebcd4e6eabbf9aa1a04c7be9644da0e8f89232bb2effeb34b3b52212b0a9c956e3393d61dcb5223e575e60e6c0e9115e24a5929d6325bb1cd563457f2d6c78d8e0bd65f89716be8ea9e9e0f054558c4dcedab28adabc3f2241213dfabea4205508af4a57f40a1bab0c778dff25c4a6af4e1c6f0bbf78f7a06565f97de8f8429dfde485d0c9980215688ec2ee0292219d9db76ff2020d877e1babf6e3a694c004985be65ce62a16d11929d132804f532fb626ca3a5b1a4197f3e7fee9a9604e1d3b7bb395e19bc9c4f462b959c634af01156989aa5c95825674abdfe00b44bd335f2a1b0a4fe3a94f190f6ceb7473ee4834f6d32aa392cfed14c0bd14f91e6025f97244e29aaa6ba47d188d43bba85c23d3970c0a9b3c7648ec2d7c8c7f8ec53cb2358f9129a898075cb9c2d7088f21012e144ec29c3eef0dbd04f3c874127d1da236e939fa7e02506a3154024d1d3930159d02f1cb938065807c53e1cb0c57f7fa8b7686ac0412f737416794f0d94ae9f01e4493983da79f69b1fe5508550458be0c79efe8a0debe4ce6667011c7462404605443941e6149b7cd39157f4f217a0d1146bc85d05a586f9d5757852b3bb67f0567210937485b02dc92f8db41b623cb8624dfb7321ca4a07e9b483174f585fbe857abe198fe3f9fe68a245e45d3dc2006e66f8cf0e9f058ea30fc249344da50ac81ef06189946ee23a1f7941514ed9cd3886131696ce7b573c51066bf18518d2edb2e2ffb671845289a957ba12a3953c2f694e2170ade0b6cf8defd0cf8c2ec25b1769c33b432693c4fe764a025aaada080d5d1fd056b303ded66967222f22826f37da85362f06562bd6b742961007be485ab4350bdf26c7af0dd7b81a3cfa3a37eb9c1cbb6d2aa7f46d5470a2d17af80201bf912542ac3c1f6e7af236c4c44a9df413434b65f6860537e7cad406f1783b71024a874215807ef3f4b85db0484d28e13c15d5955e3bb195ae7b442eddf374c2c10000", .Okay}, + {.Pow, "-6f2dfb030a5f21b3599edd687a4ce3c1d87fea964cd068e0a6515dffc1e80546446c6ed7520c6b9a73c83aa5dc735017faa302cd69d2aa801c7811a8dc871e897981db57611fbfcf28fd931ca8bbacdb6fb8f11b731db2a729d4be4568d6ebec8dc5e9dc15df472c9b1ab9326f45d252b57a154a0c1eb549cc2becc8dec9fb0852c9b14d90522f8bbd1bc6f33fe8a2150ed2a3051694", "7", "-bef9916e94ace769e07ea3eb37f03f176d6d260436c143df49e8cf40025df03630ae51881b9c5d91fb5e3fd4090018e28fde095537f843b3803444af94af81b78ab75090e255db91b4e696edcd78f926cbfc655a9bef97ab5a4c42570490426b6a7161551ebbd8e7a89cd9db7b688ff5a030d2b62dabde971c015080652b09f6a03658c905cc1441a4b7af113fa090ea3309ae37bb69187d3a7ffc25553988eff7d13c5535b6afdee366e1c526be5e7340560b3a666d425c77ad837ca14db1d7f137bd2ce4487b65d482682584b1aa43e01f8d4469eacabcffce55ea448beb0e1247aedccbc043ded207f7a27c630c78d7805322912b488c3581af5fb5e87d9e8b1f667975278f44d76292492f7c46b8817dad7f46054c83f40d7f1a6352cb70bf08653108ba7db270274003f1e86cbb7669f05c0ccf19c9529d55431482d6426c33916a92cfd5634c73cf26363c015bcf6929986cefc9b4b98f952abae315ce59a6a870952633b97fe7feca7d0c4b5a7990a879a6e6b39cbee04831984017dae1ea111889f31ea5b11c2c657e3a52311a4d57abf4f98c07e6aacb9c989f157581bb185c349442fcdc803d88f40a47e77377e64634a204ecafc238c57838d772c7e085b8b4285ff499278b65295098025f25c8ff4766ac17ad77f790b0e6d8a91a02a2af7b7ec0d433ce298024df829a921c95ade03138e77ffe6df2433463c50a2ad4fce97c00d465d3808d41c87c9d9fca83f4b6528009aa083e0768746d3bd3e2ffb3f709b733557998b9fb4bc44ca18a8093b7befcf5196043184ecc24e2feb557744a9ef5f72d18f2bba39727ca7a751b402523afbe4b409ffab79ed3aec8b33a130f732ce606c36421f3d743e99ef48c52734eb4fdb4e883f46b8a7ff2c94ea6f2a74eb505c291e6f8910e556193f70196e2c2398d3ce3fa2ca19497de58ef6770b949ce68b49e7dbb6948512e1d458c9fc522c2d05b7c97a750336913f4828f90e4827bccb69920b5037c204aaf3d683ff6553aef8cbab70eace87bdfe072cfecda3527ad4807d71b3660e4d9f7ae567f005a8a4a9f5f08f49e673b74606ffc8b132b5b136511ada750ca09bb89dac2f8b188592b91f2e21e1f733d74d67864a3c3121e87e9e03ea761e2c9f2df89da5660b437c035bafce1fc1288053f127e70285c6045a8e9bd2a2ce8dfaf004f47935fe473f51d6269bedcba7e7002a93bfd2a0cf500f38e7830131432c58eba06d80cc9102ebbc581de501b6acc5f2dd80f436e5cb30074ee58f1f1eedf9dc73b7fcdd4d66b4c00f25f3e99f41177740bf07bfe73e822bafc4a22d5d90efbda5c52f15214f4e8b2f42cfcd8e2dfc22a6cbbbd4b25ca6dadc973952eee93e9f1e55e9abd58a982c8f36f1e0c2e4c44e44888eac0d2f80196e886f1c5b2570944af3fc390f41a94765080878dd7360d5cced1aae95675a2b523952bd57bea1956f9662eade34000", .Okay}, + {.Pow, "6803bb405bb976096b7240030a5e1424162f12d48811683a161f7899081850ef5c72028928694e931acd3ad4f91b45dd46e0655786c8a57f49b25898abc80cc016eb3b59bfc7a1a74d111066ce530d817df05bff7a996b28b8564ef41334a573e68a44448b8ada6fa09b530e780b20c638f332d74b6f09a9e98c188374c725cf97088ac0079bfdb42a8a5fe8b345f945ccb0e3bb1e8", "4", "6fa103dc497f0d3d2e54c241b0fdb48f2937149b2f79417e100851609017b6a4a5946982b74f442fa2864e2218b568ba3e600412f508086b69de91df5b05c9a9a3dda1b43890a9be8e57adf0eccec133a7f02a6f96613453cd7e50f9cc60aff9f4068e00c47c60a1c0afcb93da8d7d4bf7da61311fe0dd034b022f42f5de545f2e69a2c0132de09cf1b7008923b42ef141c56f9802e38cb7e5b8b9ac3722fe6862cdb46c86beb47b90a1697fd11140c47b1dc728871436b163003ad40c012a46bb471005ae6c3685677ab072bfa2cbb8890ca000638262305f190cfeb4b81c39fbf9e766d277d9fe3f91ea5edbaccda8f9e3618c3aa82fdb4e1011973bc8d844a19c8b21de117fb547b0b71770b7cdc3daf4284bb9b240aafb7abc892c34b1829d218f2d2e804f0f734dae93e473ac6b2de87dd2a51f3128a2140ef04eafc2c56927bffd9e969629d899299fb6c492467ba3f2be72d14e75e94b3501fa35b9b4370667bff1e43dfe2a072c731bc873306cf743cedc89ecc92ba047fdb1053dfab73863f89ae49647580b35da50ea6f7b81d05ec713f44a587e95e4e8c52fa96dd1c28a2c5b435dfb76d0c76bfbc054df7ad36c2f662cc1fd88fdaca2bb964bbabef1603335098edd77d8c3adf778ea5fe1dce9a16a60bfd156eff529f42ea8e9738111f3a3c0abf2481485c6976616b0cd4fa631c7d56b72d0cf02739e371aab65c1464151c26da94d11511efd8ef1ae441945794bc986f29b41cc276e9ee74296258f8834861f7fdeecb06fa425c1ea37f396bd8a75ca0d51a4f5f1b6df6e7101f47fa698c979199ea679d999be01b42db77d51000", .Okay}, + {.Pow, "6408755756c358c1dcf6ceecc579af683331aabc724b59800ac5d47182d97f0903dda05d35d797c45f3149f444eae9a58bf0ae82d690df81a396b15f26ba67c528689e23a1b41ed5df8e7a43ee642dceb8c8c133d1ee2bc781149d4ea78265f9fd73c793d695f3b3101440aa90819ba7e39b74c7de52594346b43b2e1453ee19cbb6887d83721ee3d5cebe5c1d8381901be70c8d36a", "a", "5705ef2d0db67bec6b9f840deefefccffe04c4ca83fabc2f6ddd0300b0dadcb76e70fcff54a1edc898eeb6ee2c96d3822dfb4276ef3efcf7ca011166bdee03c482e7e50f83d171954f6e66db04a262dee64a6aec4b5bbd1010e88efd5effadbc1c94c7b203683316d564d4786a1045e0e3b28179c1d7af240837260dffd2715d3911b18a3ee8546feda9ff9101855af0a4358ff0d2d4e637336f16e7a2f8a944241bc9486ad190345d0c9bd9c3699642abfac0e3ad1bdd9d870d929e850d1dacd7f96f9d8f84d37bf430c12db2f29361f05acb4c84a83a755d00eaccd004bbb07b7ca8587ad88dee24a3b9618bef169783189ad0da8bf394934058aa6468d4d05ac201a5c3b4222c6f6b7f1ae0e8668da04dfa53a9df8e8fbfafdd4e7eb40676ad31eb78e5e6644268958368e1d7aca99f711f627a8a10592d09338b859d5cb528e20e937015b56b77123d0803269d2008a18ced822eb8225f68f581ca76f1358f72aee360e24534d289e929f1373231d80a9653f399b37a48b21275d059d70073aae503c3a4bce0ce8eacb137e96de873bd072c2924ebfc04aece7a2a12aeb9266ca2d79aefec5c7d36fb80d0b7b4627c0a056a85cdb1de6ea30d5b415b0664ddb409d6648168dc49862b02f51473c82a3bf58a0431161acae9bc661585fb330037342c9cce5e11220498f1d3a1be3cc3b7455e3fc3fd32cb215eccf15201884045d5804ffa2f4baee80387a735d6bb3ed280438e94d8a0f96e5de428b8678decc56f4cf09f1ffbc8ad8dac9028affdfc5a1c605b7add432714fe6ad2fd44b273b71785a37b7c5c608628ede4f9c69a679fd1cb3a1fb660060472c6887e8af6a85077eb27172993e1a4e1bf93c12e9db37b889cde2bafefef4fae4f5b814a0f5e5383e04e4faaf3c8a02787ccfd61d1e463d865d7d1c0805cb8bf571a30450a546b683dfdfb36a29db3ffd4483667b8aada8bdf392b6def5885a9cc66ef424f7324fa257687714ea981b62cdee90746c0eae1fb6bde3b451eef3e98ef565c2e4cc183ee98aae7bc49de2bf541647b57bf0aa0f6b7eb5d7b57a8aa518257bc7e723fcf546e82f7baace76b167f608d5be767d54d8d7239ed08efda67ec68503694dd358e7ba0762e9cb24b39ff8559efb129413a119a57b87c08636643edd875a67f3af7126a3e9926eff1005660cd373d6b792c9d74c8199f3e36397ecae5dc09dbca6795bc439381ae4c87ed27dfba7ea5d7df3edca2bed62a10f5ceb4858558868c85e763db8241e211aca36f2f11764d6d2640089a846c051a7b96e388d04933c4bcc3756b9e28cf7f7bdeeda2c9e5efd586d84e1ed9da4a9b3884de8b48e5dc2ecd5c972e568b77516f92b6f99300b6bb33e35ddaec9e0244156238bc1c4031ac53f336957d1d611a3129d3b9508c9ca73b02d411f9a43680b4b6f14620cca6d00bf51e6430ce53490e9a2e74c19c74fae4dcb107cbcc590cfd8eb541eb8572d1b574bf3cc259d71ac27fc1b827bde890096e4e2b2c5fc126d2e606d1f240fdaa8a01d98750a72291a541862e4883b352b0e40052e2ed9bbcfb48f107888e61a11031cb448e48e41fbdecaf6cfd8dc244eeae2e3f6e1f05c9b312b4e249759dd2332198909bc3341bad1de1edc9efe17e6844822bb17d7975d94c324ad610cda2ce4d117294feb2c5feb9c4f2f46cf0876b385f311a00b7d3e26988763b751b10f0aaa492131f06633e169f33de4dbf406e30c43e99df468c05a07161a4d4de0e4446408a391ce5bcc1e2e34a57ff37d865b4c4068020faa4bf4d4436c0ebac52b4a1817358770300427092cff1940eef3d5612f72fce65a124fdd2620f46672324c0b4c18d23f637fde4ceb21b8d640e5cd62196d8e04150ca87b795e8e45ad62b3be93bf7e926f04fe6581e5cd2a9089169ac6ef1f7c666f9074f59cd3173cb9b06995a161272186977ec691b9f88247a73a2588b5c18cb3116806569aa5c283a9079f4a54a20f16ce7a9c7520cbf193364a1bf98c5d8e0ffd4ba3b77e3dcbd1ca2b28405564d9cf85db6d130c59d8e155b8bf29ba56316f1f4f0e762a9dc582f86c1c6a1ce6cdd5e2bd36dd5b0851816400", .Okay}, + {.Pow, "f3ab556ad9c3409650f2f50fa96f9fbdcc6990b184b712ab035980992ad8aefefab40b9c993554b68fa8ea19478fe073e110a18b287fab57fdf1d20f34ed29a9d7f3ec642eed8987155b2934f874079f7b829a04d59f72dd95a181e2492c1b1932f97780cc544e5270a2f05e00fd320942b69ba8645a26b0ae23eaaaf098e7df12908b46f13c0679271cc2a16647ba6ff091f3a419c3", "5", "c801a5b7ebba06b643d8d84f8c37dba6027b7d3e82d59e6a4501ab57ab32b004f0f75ab4beef3e9504ff689491aab3827ad347055b381ff72424e0458b34ed4d606ef6efaf15c2e1d3a9249e2bf7d3742f49750021c771187de72d06eb81a65aea27cc977db42b109cb2b172e3b252680b073e8e9ad55f7ed3cf3da8070967794fab9edb69dc97bf2b2119a86f669d929af204bd9f41c8d5c1fcb25ad67e51caa99a7e34a3c7e195eb485c937b47f4d82477d6e85f8fa834b648c342184ba5ad6eded4ab7cb2514203da9b895bbe1911531fd6208dfe7dc02bbd515c49f06d9078b9b948db2856d444c67e5bf4e33abdcbab472aae15c167ea007585955e240e6770271dbbea23ecae4909114fc97b769573785cb9e4d904dba6e556e67f74213b9677c3f9f3731b4e2b568adcad4cf23396b51bf95f8f9e3910561b17b11ee798a6cab005f63264b48c3541b8ba16eb811bfb2009f1f9b9be4695797cff9ce95f51d8a793351db80c3ce0a5d77dc53137101d5776856ae287afb1772922f44e7d9880ee427493f1d031ca41c8134e29edad2fca08a47011f67b6de4767e30132be21dcba189066f1c29f940f5c7f0623f4ae7124828b377b929a6765cb581a9331dab18959e049362e1deec1f063fa03b02b93dcbbc06a092efe4231cf30981243d6ef24f922d2b7f48fd5d6421b580504e20452b118fbdbf14623e00385010dfdb47ddbc0e4448832fb9249d9fc910073abd356869cd030de770a3327bce39667696b33adfd5820de700e8e4bb008a11d3b47ec9031064401a57608bf0ca6e9fb2e277ff3a1aed413aefa4a6c094a3a78af7ec55b4f5ad9d250dedeec343959d71c29c28237f5ea753658fa6266f5d91c7b6ae331c51cda64de972792833d2301d510184d08928ce60b4b912d3b6af439b79c73959a42f48ab5115e80092b03e02b8b5ce804ed5d12be0e3fefac9644a3f7992a346cfa65e9cabe72d88f4a71c2430239568217b9a0ac64b227260612058b18ac53a114c1f53bf08ea87b0af3d03a5fe6a01ebc9bc9e08479db3", .Okay}, + {.Pow, "6b00dfd5eef186b7a65659ea523ee73dbe8a04b05888ef6cfd5e422e41fd0fe530094646143842ed37740d1c22af26f674ab170715e75d5d1076aca28ef80a91bc2a458eb14b9d405277e0ea587461fb3cfeab757a79e026bbba3b553b117b7da92183c74727f84e0a6ef76cb925dc9df59e2866946a953361c07c9214107b0ea9dffb3113d8574285591c439d580a3e8b68279476fa", "6", "15d7ba1ef6edadd2c9964c43f9420d401a54939195cc87904bba6844452c290af02034beaef887de1f3debda60fb57845708c3f41538e71fd7bf59ab6969fca28d964d8cc587155777df81179c57a49a773db5399b44d8719cff39e945afd5547bd6b2d552dcbe88686633d8250838dc22fa44ee4a0a3385e11a7b1cbba74f92d25b4b1b9a7e0d4607579fdeecb92618fa0a5d5dbd5ec727637d2f894944f350d817bb3db9260f9f08cb8ed76bcd1ade9c16fb68e44a1d5e4701dda079576292269c99d10b594b490d40cff57009bee66048e5d2461c9cdff82e5aa56330c4cd40438ce563af3b7aab5d2d4bc1a45af1b16c8cb61176eef962654ec484fc31cafe746ef756242fb7c96177930fe9eba8b35ee94c46e6a25ca5c5fe76560523ae56b0ac25db5deffc3b2f857ea74e397a934ac862bff7f21f645e9ccf83d009a74abf6da8de019ffe1cab5a6709fdd8a3aa3e539cd7ec6878eae5ce9d461831975d53dd699a32833afd1b2401dce6a08d491976489de68d35bf8a4ce5e1aba4f8064de3d848ddc38ff295b6912b7b03e0463a00d3e1dfaf544b5330032c553dae1a9dd7378946378ff1f48326805b4fbaaaa224ef3c42daf3b46cec71ebd85f789f7d8e506ff1be35d7521e4bd0a01abea5961ed494a1aefef663787db1b3e2c98c8f9a76a5ed228422f7e41e919522d0bbe7d717c47f1c6400c79149e8295a9f0871b34b6d8e14574c222fad3d2ac5301ac9d89d1634ec3bb62152700add6d9049da9a77c58120a641570b00c582c2dfc9f781fd1749995821c0c41b31ed8ccd02056dd20fb8de1bc3a234263c3e58dd9b0f587873b78d7d04358ad7f089a37d287fd86ea26967adfa92387130acca7969697b46e73f15a26b4a40bd15918115b316097c38479d261161b3bea728017af604cc62b089870023be700b040c08b6d31e1cb7ec9a2c74c5337bb7fde4ad1e321a330684de946fab4bbd9c2fcb6206ec8e7ea2aeb8551da0b56204578ddf2b9b83c2eac21ef10d39554686befa7c6c44ed542f777993b086eb051f1cb3d449a3c2e2475474a866bbd94942f0bab31f891e7d9bad40e7bf3f1e8b3060844c49d9c1c3cdb3571d5b2467b2a62e2f1dea8bed4383984e391872254717646dc3aa321ea3eca53b1ff016fabfd6e77e746d98c6bed88a102e6a7a4a2e7ed8e5bfe2823a92adbbd232a2458f191433edaaaa457027849baaa7672b8edae62bea1c91bcd40c93717d959f8c51ab9070a5a7b8538f640", .Okay}, + {.Pow, "-b5ceb415f5e389fcd7616aba891de1dfb1ba259b33547e23037c9a9207932f8a65c6c2a19b4c0c04f063c131c634e63ea03c88b12e6cbf302ac4047cd2efdf5f2af8f0af45c74c0b74b27ce630a432879a9149d7374f56ac324872b0ebab0ad1fec1c4cfb4d72f2efc8acb2f163dc140976f91b8cf493cbf147f7eaf150849d2a7da887a3b8e4bdc79dc434f4ae679b4ae2e864a3e73", "8", "1090daa7522690bfdf5ac6e1706a610ead9064ab5f4bee45b5eacf118e76f132b1d720bca93307b71a8505d784dd4aaabf2889ee37f3191e91dc92ee84ca4e72a9dd05a9fb360d933917e432b0ccfbfe445feb58dbf4e4b32bae07a1f4adf64e57eb5808986146defc827a43a6548504b8e236fb76055c70f2f9ca0bb4e4da4ceb753d3b211ccc5c1ea8da4fdc23a1bc21bdca73ce8d6dbb7a22253a734c1aca7fe7a0777a3bad12002bf9d89f0feabadb73b7474d1aaf1ee1317015a22470af9097af278866872ed86d6763704eb5773b74933938b5b86cd1b3cc78a0ad4d83200a088e5c4941c35ee2eb3236e230bf0a47da8ad64fac667ec26cee4a4fddaed043b13b210832f20fe8e488d5a4bb91a421eff60e90409cea2ba54d685018428fb361e38d8c1999e95d560da2b8a996ede8a230ffc7dedef2ba1a9edc46620de5011b594052d13a38298a418c7c062e85341f86fba371e54afbc4b080ca80506e525cd501da5c107ab23763badb917230143cf765a3f731515a3e4ad0fc5212c7215be1dc76b3277dee389143b9333bc6b9c93ce17e77d77c2e7ccbdfa8a841c4e165b494c4e17d91daf9aa6032ab4e1e6e99b6bc7e7cd6fcd4b7ace1cea7da8952ab7ce97aab91dad79298ff91bd6cdfdfcd885df609caf6130ebff1d356df25af9f4fca760524cae71ec293e30480595b19f51cd02a1b2a6d434b12cbf9760f1b8aeb79d060ae6747832d3629a63e3a891f0958e94a20df9f836fbb4b6f19f4847104c1def63a61d4fba532c5a5ce4abb1b219c903f53cde3f9f3bd384dc13bb386dba17dea0e730c7640fa1ecf81330f0686bef9fd8e61d1bc5294886b8889604a6471825d7d36cabc4cda04a064b711be3d2e918f0b5f30f7950c1eb6a81455640f2b71ea745efbb8f5b9fbd068d20d4373fd98717c6d8bc37c9240fd9b8e039769928f8073c9d6f1f66d0bf1d10dbed4cf76f1b51dc68d9b9d0a67a4f3da0db7c4ac015133fe93960484c2dfc16aa4f29a9f526b6133c7bee5c2d4cfa3b6ddd6d7dac00fe85b3e09b84e88a2d00534776228769650095a84223dd1afc3434d87b8e6de989de4a36cbb35405c70e38585ba5affe8b5978cab20f662427e8ccb53650096750d2bb918a88ffda6c201903e0b8340269cc08a70cb6095f60ddfe96f3cdf8f031a475b16074fab8764e0c83f858f5a438867099f802abef8c9fa53a332c17f75249e4091b68df543eb72cb115d650dbc6acedfdb91765b5a66818db150153455d8e3fd6036bde2bb409abbaa730bf8039d1b22f03d04dfcfb98a32402a7c4c6f381122c887b192c97e8efd2360b1e06c00d154a50d93a7d98168b306e6bb68dde6cce910f4db996eeb7a49d6f69cf13d579364443cfd8a56ec71060890b3717be07e415ae4432df126c41af2d575241ad9c12855f2f6a4a9b76e2307e5e684b077d7ef5c7290172cf513ed00b12ca12180a28cb70662b5f0d8e0bb39af3fc439bbc80cb7ce4f999baad414d84e4b8acb0b12192264d9c97c8fcab2854bdb2479e982cdb09cf4533c4a4eec375668249630082732732ba6360d3813636b017d550c43e9d21e51c45d7e288ad2e802fba844382cc2746f6fb4709b191d68b8536ae8d52c0ad6471f126e94392bb4e8eb48bd36d78bb1f7b43bc3af8ecc3e1ea41e3db72dc11c3564cc21", .Okay}, + {.Pow, "-8de1403d14180f8988ecece6c839bd3f398b7e0fe13d95c72c879f97698a5ef9683728bf68f4c392c42bcf39760e5dbaa3b4704859011610645b95c02a0511712b701168c67ae6be9face9d36c8859f1db7b959570dddbea6ad7e5005b7923d0fad966221c5c1d75eec4dd88b8ed32fcb154254c1ff1bdeb8e901af2e3763b378cdadee83b8a5b54861502e3941a13b4f76f9099ca30", "1", "-8de1403d14180f8988ecece6c839bd3f398b7e0fe13d95c72c879f97698a5ef9683728bf68f4c392c42bcf39760e5dbaa3b4704859011610645b95c02a0511712b701168c67ae6be9face9d36c8859f1db7b959570dddbea6ad7e5005b7923d0fad966221c5c1d75eec4dd88b8ed32fcb154254c1ff1bdeb8e901af2e3763b378cdadee83b8a5b54861502e3941a13b4f76f9099ca30", .Okay}, + {.Pow, "e96b5430412b7601574d9db7d142a38765206a5ed7d10e1cd22e0388390281b86d1892cdc17baa77a64fbae4e367d8451f99ea78d564da6d0ec18d84db149da72e256bcc7969a4bc6560a0958e0ca1832709f0ed2f4ca38d836b3b7ddf2f4579f32dbf7f94639a8990c2ca00f972cd5949f21de64a3f53a7f7cbfda43d708250a257eb185f3729fd1388b5e6f3090c863f9a63efb293", "7", "862091c4baa00b2e8c28f47911da5802fa50b721297f974cd022f1fdfbdac30fda56ce905a3839339d8bbdf5673a2f26e6de2426e1c58c98c83e168f1abdd4f220d440b5ff018824d9592e15a36222661093d322b05102eb8b02cc8a2e6d3631ec8dea6d20e5f3852eb23ac0bb81c36a39f569fc137a676b1075a31b4f2f7663218256bcae0b1d4f334187c79ba5771b59f636acbd62a6cc5d31f117b9cf6c585a36b7080ecae1ff685a0b27799f60f29a8893e7205c30fe300512e65a34cfaf11e08b14e6aec06ee0cbafd22e2925853618e08e836a62b88db635b1a2be21a7de3f602c379c8936fe33761159f38c7e35c8f484cab2ba8eea6b7058556950860ce6697f1b078b02adbe2252a3658300560d31cb8e4e0703b5860d812e1dbc5c8021e0d491e4afd871471a4f877df4a7c968ac47debdf47c68a0cc318e99c31cd6d49f5133c657e6b26514641e83cff92bc82cef820a5d89877ba3370bafcfcdd1831de4dc4b2210a4687eba4bbc760f2fa01e901c4910edcc6420cbd088a46cb8033e4b726dcc7ae983966fdf2c3f92888bfba57b35a4a0c4900562f7fbe378cefea388617de8689af993145063b796ed30a7b9811fb040ea512dea54ed02fedd045cad2dffb39e8e063ce1e045795dd84ea41e6e2d123e46ba4edd0a047fe17087b72cd41040ce77f839f5dfdeb627f80912168f26c9cf8becf2a0cbff5725429fa8be65e08ed67b42539bea82cb738be8b506488d4d902d1bd64cbd7b15ee64fcedb05aaf044c493ef0e3b1bc1df54c9e336b99fccfe5184349b5a20c2d889e7db76edc7b386019dd954e01e2faf0bea8cf2646b37d89058884a6564dfede02c919aaf581e020ad582f675b80fcd72d34bfa6b43149ea679edcd9de1576e3d59c8077e87480f415379510d26d29e0a9b46cd4c9cdc7afb94188d111b4b3d032a59f7a96cdd39ed178dcb66d7ebbcf06676e2d2f52bef30063751b344b316295138ffff05c784c46198678a176753f8c4735131a8f8eb632dd9a1cf6e62d52fceb71dfe3caa9de733b8ad68ab53b12d1b8a6985ed39d8d65cd606d50ee26756364d8addd04606c4d9902e1aeae34ac324cead0e13562ba12c1665cfc248b93f1e6a83dfa7a0eaa5927b4d9391caabdda7135c69a84b85af8fe96d9056eb6019d81780521ca6f752de8dd1c653350040894480f82cd9d92d8c6e68a57bc1b0d68937a73d5d54d5e740525fa838738bbd4778431e7981d7ab0969cc2122d6ea81567385b2ec92662db7957a8e6466acbca3032f6128a041c19d0dcb42528f7ece5cc0f53e42ef86b11dc227438fc869936126d98d19689939ff170d77ba5c807f2dd64e1129c4afc42229513b5f432c04d769f4baa3a8c8761878b4f54940b9381110d410b3e7cff969e30cfd7844c2374da3989af0f1b31150f82160c51a400f4be968fddd52eb995087dc25ca1cea2ca0c78ba910f9d5b7bfb", .Okay}, + {.Pow, "213b3302f9bd49b7da192448b72260adc3349ba344f4de1a8cd285dfabacf2be3af2367210478486f69bd6e15e754d9cc6acf46ec5e191e9868f9c85a38f625ce11cbcb8b4a5b44c59377d24f86e23dc0f14ade1fdaab61dfa31a6c19f8208cd1171855ce3ede9f6779666f141a3113c4ff00788412635aac5d4d28bf97aa402f49ee5faf356ba43a4ced6c877b0b8b959df1a96f59", "1", "213b3302f9bd49b7da192448b72260adc3349ba344f4de1a8cd285dfabacf2be3af2367210478486f69bd6e15e754d9cc6acf46ec5e191e9868f9c85a38f625ce11cbcb8b4a5b44c59377d24f86e23dc0f14ade1fdaab61dfa31a6c19f8208cd1171855ce3ede9f6779666f141a3113c4ff00788412635aac5d4d28bf97aa402f49ee5faf356ba43a4ced6c877b0b8b959df1a96f59", .Okay}, + {.Pow, "13c014bf5f2fcc131eb90253327bccf9b84560e903cd8031605f35a6df0d18f94dba7fe461fdba1cf213be72cfbd66f7d8a86e47057a28893d2d61d669bac60223a4343b3af71425de9712ba8a67da519ebfd17ec8cfd8a2be4e52c5fa67bc0eaedcb075a4984affdf19ccac5bedabee71fdcc4d5a7c0d49f8f010e5de72faa20277f1d959672477965ff44161c17b83e2aa9c572a9a", "3", "1e181ad6e88b3a043f54b6bcf35492c5c2ebb7c1e1c4c5b7aae194e6c08ebf885ee2fd86786fa4164a5b4e8d8a29006356195f1ae3decba6cf0e2e390da591f0a3d0a44c6a6e5dcdd8c8034f6c49f10a09f34bbdc67c55d5d1214a38fa39381e2a28bc6bb887295c815bee80d660902d24a7432390d6902476281fa51dc17211a9f3268430ff8c88c09f7d90d825114184d7dbefaed3b36855faca4ddd5ea918a4219d7ec42d898c4d2c60f31835649715a470ec03fc95e61ce84cd4aeca942036b029b31f235dcd30d0e34f2fdab393134eb0ad761b18f1bf2fec9ca82cc8df8c33d2341cb75fcac0b76ba038e9b660845916f5d516d1a6351d4f007d8a8204e72d282ae1e105b9eae3f54d54059728ef358d2278b190d84e24bc728343e32f4f9d131022993f4162f7283f180314c8d5e2742180036d58a2a3d92432dce1d96d3cf94a92c30e84965816df631e65a8270a6abb53b2965de2f02aafb4f599d00f6458570649c0d60bfa8fac58fd595f5d291081e99d307d43d65ff91f37b8d7df36bd8586a4eaa50250567705112964529e7406f28dcdf1450ebc0ea3e8c9acc5f26f894bcf7bd4a2d84347b25e56d68a85fca648a2a4d64155c315e6f07c72a8", .Okay}, + {.Pow, "70e6941c9b84dd35b43713bfa30d560ed9e48269ea2def06772d18e7b4a7f72f028aad7af07f57e9e631daa3be4413f7d7a9e65539178c4728257189c0761d97ae254b3988e5a5befb4806c51da62bbb5cd5637584ab4ad2df1d08c9fbb813ca1fb40a9abff5f0150eac2ac5979a10882361d2b8361a8babc21e07781182d95c1dc6f166d5f17711c391b30e9dd64757f11ca327fc84", "2", "31ca9147812ccb507d80a9322ca8dcd85a9a505b246f7bf58c38ed671ad93bfcc20f8d5f00e3e1c3cebd32dd55a9554971df939155b744ba18c4800c4229fbda7b596eaebfabceff3c06063f4ac3df455edd418ee596e9b5fdd2e4d7d6b860d1844ac03cc76f880137d25f801028a414c710d09c388057f902456dfbb50f34ac864112ff81f97714fdfe6e46db87f82e03b93460605e28fb2cf3e0bff53e1f39d2f008128939df83a4be2e501545119b86c9aab31cd063090fea7cc5210c39480cb988cca320782d4fb689f5eececf6b8c2f7ade1b2f0561afb45db9d4237eb4d04a531f03b3d53b72ef4fc39ec44740b163342630d59d83e26a61b19b05ca47e249f18f8f67fd23ddf1c77b6a608abeca3758c235cb5bbc39a00343a3770afbb01216543be3b6af014c2410", .Okay}, + {.Pow, "f98be61322e857015de10acc415c002a80bb3b3a86282ae5553020677c04a2e11e6925e36e58bceaa71e85332674efc1aadf3c3250bca63394d75c80cb6499e048971dc08706fdaaf87500a22a080b2944eb54f7bf1516fec363b76f7e61db9091e8be6ca08b4712e6bc0222b828474e51dd29fc1322b9513ea17e8dcd8793eed7e883a573a15bc59538ff659438e9268856ba3c92d9", "1", "f98be61322e857015de10acc415c002a80bb3b3a86282ae5553020677c04a2e11e6925e36e58bceaa71e85332674efc1aadf3c3250bca63394d75c80cb6499e048971dc08706fdaaf87500a22a080b2944eb54f7bf1516fec363b76f7e61db9091e8be6ca08b4712e6bc0222b828474e51dd29fc1322b9513ea17e8dcd8793eed7e883a573a15bc59538ff659438e9268856ba3c92d9", .Okay}, + {.Pow, "-ba5f9a8930f4302826fffc9aea62bdce48bf6098a49b1a4e7499ba84d1e14ef7b10b2b6ae42f182d5de0fb9d421a792bb16f544da593f8d622994612a6e5cee450e948241478d3f4cdfe73a3d4cd1b7c7c5a42dc3f61a4ce14989e2e90c0097e4427a1b311e2d8ab47732a8351177d67794338e26bd8ea159e5118f12a8303779719f0beeaee912cfd9404dc9b9ae657911399bf6075", "6", "261da1c52fccb5ce23b5e3b3875c2c95330d4a3768f32dcdf56693f192274a8f662143a01a8bf3105d41eefe2c03e72815efe1d8e23528280014eea7799869eb440799f84bee1a9e0b73d457b610b4730f3eb06b25c2f28a696e309a0cc93f2e1910b2b9add61b734f13ae50f37bda7b61cd96f8e3326ea6a48bc198819b41aa77c51a7810ee406b9a1cce59e6abc39d25e1a7b407a656e00d7f02b694104fb4120a62a515c099406196aa73f2acc0b9e5c18353905b8937d773a16ea522238f03f72f89ad4ca7b909175e69b68c48275a3a9c94281a546f11cb3449f14c6e6ab3923c6154cb2719ccbad64c27e465ef15ca8c8c931ba2db650ba8af9f33808cd3a7dab63acf6a2c629175f0f21ce36691b94a81daaca18650b574fcb519770eca87e5b5805d4f7bc30c274f596fa735cca88dd2bdec74da547f6bbbe56cbcef83f056853bf00b9305b3856030c786dc471c074ab04c3fd4f9f0b6ea50ec99226c65c0f925c408ddc91aaf769117e762039ade4d4f68a9647905d9232be1de48960c1b8c9d2f25a4e429302ee241d62680286dd2c0a3e5e48aa1b5d6690c38576223102a3d24f82b42851f59e62425ac44d5a9317cae282df04ba1a97fab3f6b62b225ee1ed06ff5d236a76ec8edc6cf0289e97ce7a0ad68272d5dc51a235febe547d8607118d877a02b27b9f87ae3a75867722dc721cd9ea8965614847e6ed939c73fec1db50f06bee5e473e61a586f578a51eac0d4d97c4a8a5060082cab2d248ec92c9efc142fa6efdfa515c088553483470dd16d065e11d0c6a877b83c5f66e3f15a076e3e8a3573683abc39f1993c446c041672490f07c1de1dd708a48361aafb62ad61c9c92f8c148bc94d20fedc6bf21235352c6c68a11e6650b4730cc852b0af54fb39696d8fb5cb7fad41c08ebee7f3385f2cda1265c34b013385edb5dfbcc7c3ace53fef854cd6b03c9b46b55ecf19652b79d0f680f8ce4cf866dfcd1e3bf6c1151dca3cfd250d5a3a0740bee92ce1cd23d8b9504115dfb0784b8011ecfea0b9023a891b88b9f65227f1366204ef6ba4be23d6a0b528cec4e862bd5e13884ea3b01d5b78b01bc7434cbc0a2f30ff0dbf8da5b715d6bbda5b1b5cc5485d119dc84722eada44f85106b318d3f334bb971b695cfb225872415742ac74ef9fee796823cae00d2ef4a639f112cc81426dad5a14d52b81965dc0939e5cb8ce94fe553af1b686dd6a4070a60c906cde54b1fe22e263f309c3614749a7a661fbf8b729", .Okay}, + {.Pow, "-bcf58fea74cb3e427cd96694ebdc3bacdb1c918fa0872d5495b8e99ef03ec857973339c64b9364a66eaa79f26a7ba1dd87c2fb18e26b6e2391fc591924b7e0c7893b90c4624ca3af04bc6496578fe4653f9e04253a89fa658fde628a891594aa397488ab030fa475a67e6514ea594dde34a22456d0db7d361ca0c23a32aa70dd574b0cd503c07ead52a4c264c2bd05360d638a3f3133", "9", "-10a63194cce2f50245243e7f45075faf385c79bdea68f11d7c6234639f3a7b82fd81e5a4b546675499fadc165272def4100252c96cc3a51475652bbe8290d888f04502f08dbea27979e225373b8c8cf4756cc7260e4a17fe2cb05b97ae241d8599627cffe23b2ad24b47835380f8667041e81aabb49ec4d898682e763bc2b7a26864cdb467d16d6632ed11875709ea02df7c437fc4fee3c13d72be41f201c0ac4e1b5d0973fef9dfc33276c7dafe23eb4871dfdccc6768cb39c73e412bd892a6b8de988a190ca1f79b0067187ca6c7ca3fa8bfc3b7320c2074523adbeb4b65d41db000b3b0405d60ecdd696e820c6712e3d944bf7551e2f30350982d0f7d867d6b38e48bece2735e7be399c85c2abbe4c46762c2e34f4dc73b414688a470269d97b8d4a860f5a1b986d679112162f014dbb482ab74eceb43af48ebcc0198c33a764bbe6a1df13bbf9be52e4a9b80e6201d2688b8a60a744f030cfa39aac0d5bacc2bb483570e055ee617a16e041af3205bdd236a770542e4c099641c43d666f0be96ab037ae8a3f60c40f95efaa2f983ef4dfe978060abaa71eab73a45e850996ecf2472a6cd5e3110602a5471bc5b65c4b69971391e12b7f65fb802fe677c7e7f4e0387e167d9956677bfc6a95c5502667b735265e124dc48516a8a4938fdd9583e1986d01b3768cd69a18e39a64591f80a5dd5f7e676b2077424b69b44d7a5eed8dfb949f8092b4cec2454e551c610e9271cf4455e1e6dcbcdfa69396988a4b37b3f5229e7455bededb926bbf6cb594fa74aed05adb24a69585dcc28a18b68b5a473bb9f6dfe890edca78dfe382e70f455d06b948b35b2e936679f7127ad831115b39c22e8f0796b0bd7645ce903d727cacd27b744e2f8e4b18f4890c9572e0dd455dcad6923f410f4dc2b5beee242a7c33f3fff2441a8131135c9786944861be326e9f8c3a2523bcefe11b0df82b7938470e71c834b243c628181b60ef8ea687a74d67df011c15067d2ebd74609ae231f70445c9c0cce987d21b9264452b247aad10d826c575ba5fbeb5c45a0e095c3d07ee9971ee2437c3cb2514a4136d7c7abe70e0ec231f9be23255debd437479f187f34fa37bf37326d649b2a8f6f41d29a17e9118072ea9c47212665ed72659813e75d933f0ecf4645f5907484b35be15ef68aa1b9948b89c463c74bd617c03ba85484384a9619d021a3011d5a7d64dd07a73dd8fc35c90b90b1f4681087cd84c35420c3cbfe3c554ef077cd652a1fd365b3c5b66c3eeba6d1c29c7cc08e2a1ea6639fafa0939f8095dfa700f311da2b85f86dec4f7f9de9e150920053cc071996a70ebf3ce0e8c54342029923acec8ab504831be1ee288b1f54bf1a44863c8793b8d2f0049a67b459ec65b2cc6ca2827ddcce0ff0ff07b1970953c5d48b7bc06442bbf3bcadc60fe268501a2844a3e17b6a534b1f8ff99b5940518b82fbdcf27068d2cf0aadcf70dbbd10fd14a87c1576d48cd12c566298fab3c52678e3f329d367e9a985f5ce06c62055d7bfb857c5d48f48643b476b592e81ffe5ccc99adf2d18485bdacc157146c6852df6c94295bcba9f08f29618f3ac8e83f5beaf46b904587d314bb4133973fbdb7baf45c7479d6f290193745b1d35406a7a66676e04245062bfa8fecad6b3e81b54690fa1757062074324a5b693075834f95254ce28209e71f1f573124fcb147352a2d19d9b307a4e79033806c5a52f8e43dad5026bcc373fdef573500639687b6287c2745db085028205f42071d7391cc3b92f661b09cd2601ec54778dd6445a4d07d57a2fab7e1d896bfbc7b73aeaf7cb02ce06ba8de6dabc777d4ddfe701fc82e1e96be9e7f251dce36b3dfb6372548b99ac8807106d26a1dbef358b7291fc1000505953feaaef1193", .Okay}, + {.Pow, "fcd62b335bcfdf254869fefa89f972c2789ef7781f87452b5369e52374146fc386063d8b40036711c183095437126873be25da5e426cf47610a772c13bc10d4029ad30b570ea8704640dc5b626bd55e670291c53980a7eeddbc4de0892e746d9201289a38e8060002ac36103569ad4e738a0b33b615ee31635ccaaafce2ca63d4b566dbdde9ea48820f3268b4fd7fd29da8497f8888e", "9", "e4e593f64aea42c2f0c7b4ff3b531160d8e106236ba52594c9afe110d1622be6429f6113bbe3d67995daf789274ab62a4c003534ae095590ddd15bffd1cb2e2f38add197247ae6d11c9a548ca7cf0bd670286cbbff7910a32dea3ed89e80139986f83d6eedb5f118c01066bd1504528750593a67d9863f0458a82040072e503d004b2b2bf0bb4b9aaee35a6364cd8f6808d5bc7d8dd647effdbfcfa18bb42d9a332786b7bfcfba70579f603a7c2b3910f86c514612e2526c92a029dd3516448178f26b6cd35a806b4a0feb30058d2d1596809741709f010c712f6bb3be0cdcaf76dd8b25864b7f713d55c01d41c43e8b088d426216b6dd9f07645b85e36f50952246c4c92a11760af575b6a20132def3353860784c3f718822da6b16f67a437a83a80536a406f5a7851c947c9b5645cbaf53f4e15ef2d9505c00da290037e87d315859dd5362c9d29c3a2a0529b1abbd81ee85e96545525e6073e1d0ed577b4fd1484f8f47a3ee53692b487b321c4dab564eee637bd92660b40410e6af6d138e164fa47fbfb65f713524a3d5c72a3588b378e8bde9dedab12289586c1c9dad73b16c1dee21dee9ea3fc3a1e0caf16cefebb3e49d4d632623583586a916124f478903a23a2ce3fd8d91d53a4ec25d7aeddb3e559df6f47549f527736891505ac82464096d35b81f776647d94c52a5a67e0840153705dc835f40078f48df305f61915a237c98e40a846ed66ea235eb0bf5ec5b7a933634629de9571371e30bbac5346a8cfbf77279bdf59dd5e3e29b36fab55984164cd9cc6a3328a62609a7dc0aa66f178c117e2ee5a30bce8b1aed661629e503dab19d4d5a4bc5a17138e8c5970687513622bb227201b358aec87ba9d753378a8e0b2a8ee6ba3ab57e8297889eb69f834f907b9b1f705aa0d494d3367ad8adee1dd289b14cf7a8238a7b9c7fad32c64fb0ccc5961eab116f08e44eeab1c0525ec3260e52a81f5c7b7771f16fd67119162e3f750c1551f427b96e1e503c3133d4ad7884bbda67d448a708562092259c30ce1e1634fd99b6f54344028ee9579d6073cd3f29620e23a48915e7e72be26e57a3f3dadaebf34cd606cfad431bcee4b4a291286cf1adc9c7fb30d52d01176968ae81e2b85640c02525a6743c9d6438cfbeadddb87132f624cef1c42f099aad175b6673d3c4fc60b58f7722594052607989f8b4bffe88de7a197ac9c1bf1b2f02811cc493e7517cafea38ce863b9f83b3e2b81b37d821bd979f7f310ec1cf716e2ab686c6f26a5258d0f2096cea2be6e3c2b3df6e014ec94eb5f1b6d3a2e1d48fd5cff39a628d7024194939e9fb9f576f6d3b60e892fa66a1b268c62cf9ea83e7ee24518d8d8fac4e10ef2b00d10d89e21c7a424d4668540d72c084c3b40a1e7f332c63b75be7bc5bafd787a1bf7bdbf1b12f5706eec87a6cc4f046a58970884d479fb7a21850f1b5d4ccd7896d4154936c7e933ea0f4dde98a99a59661a17a63ac47e5e5924d9e17486519d8ba85a89bb456c605dd7144503bcb237e6f2558689e804636625514d2e7f95af2fff4a2b63a842ec61908bffd8877910835c9331483d2ba7f29875fdfdb8449ebb7ce6db4ed4b8a367c442c6c9a5e1bf9c5070674e641379a709fbef4aaef0477d8849206b91e8f089deda8ec5e86a121d0fb259b5c6e2612966f3b2a70996871eb2c262d5c114dfc209cbc46fb9826c1e0f8a89c75ccf99989c012f736bb2f6ca32232b1a0b4f48a34791565776f97d909cf4658e4dfd671c86ddad21c9c787d68919aeacbc72ace559985f110023bfb67159980f8ad7cc64b2519407d78af6e04c3581727004284e125e6ad2dec979e2258e306febe32a4d3ee1d5f4451c3dfe3ad6f60769beeba5d52681cae938efbac0792902b0e00", .Okay}, + {.Pow, "e2c7e90e91fedd9e9313f8557aa05bf145545fa83ab73eed85d54e6ac0902ab429f356ebf64135845d21fb6ed8c1b986c9fc992595c58f43de0d1e910ff3455d27f1a20162ca17a6fe7dd9123e2825c985b09f9107900bfb206e46be6bc5cd7ae39b865c28c82daa68c4c3325f2938c1322f02f866346d7c8763b8c26c497dcdb1fd3ec1bae8b8771c4a63c7efb4d90d17494d080c7b", "9", "5602085d4c5096d60e8657bb2115f0d47f7d09d2edfbfb52099bd58f117f641e73b9927fbf440c78143a86ad3d3d343fe3f444c2b2eb36df206146391a83dae09c58d5570d2956a871eaa2a8831d5003af31a6c381697aaedb9cf1e3548c217440fe4c6c9cb7cba0e13a1003f6b639b2d91e4d462d17ae83e0d27dbd2d3bf127cd782fa2548927e17e680584f1109a24295466ab9ca954afc387479076c54c2bc8b05fa701e4e3edbc715182372bf946f490c72c3a10935677fdb3420e3fa139a83342d8a72a9ad1cca4eac144652021cbcf80edb5eb1d298b626d3778517c75b6b9a758f720143b422918bcabc483613f0cd89bb5e18210ff67506672ff010cae477365e4376f465f324556edc44d61ee62f931c6d88f115dfa47b11d53a99e8c071b95ef31dcdbad67362d26bd5730dc3f1042c171912b6b77abcb7084c3b5b1443a3149f5090f1f1e059767715febed4e23448a0c4d3f29684df79d3dd7268c93c7481ec74d8fe0286b6805dd6ef45ce80226dbe2312a893653cb2a6942941ecd52a97ecb44f3500e284f36615dc4e8c4d5cb2dad12e28c0e24a7f0a302c6b3863ad3ab1a384e9ee20a54c5de4e940ee3615aa1018301a3d264c0acbeb19d5c69c22f9bffd88a1e3c24972bc4b112d43107cf8eae31b5be7d00a66d162a051334d4f005e05748537a6ef50faf65ac69d90305bc3769fa20375ad30e780e351ac16e72115b1d11f933a01199e60f099e4942b02ee0e699fd2160337358a4e5ad4ab15756bb13344d5d185f5946f1c24d0260ba4c0ba9a08d98b93a83eff6599cdc5975c50616e8250c79300f340007f51e55b1a238146e9aa80a5852b969a4e99ae5643f4114cd5c976b3cacdd60d74c1033df51e182f1a830d9d980b7a440b84a0a01167c40cbfbac6c7a61021ca5c24b874b7ea666bcd68b4d9d4b97eff88fa8df543a85516f6281362d520596c6a3fca123dc1d28ac891fcbf0572930373fe9fb84ada7c8c3f44a1422c6ae418f3ed22e8edceb334ce4720b8dd42ac15e75c0c2c0b760047008533c87ee3d07eb8d76aba7a6fe85d13ab75d000893e0aeec0ba0fd4f0191e1c5cf7fc5f6eb8963dfcb88cfb54f81cc4e9a14e0f1bbf9c81fed329632d46416e8927dde3a3aa1521a5270b4567b1e4bfc3a6c73db9168628afe76d902fa7a28c136241a6826fa45bc90c5413d70dc1d0db4fe625661e94dcf43e1c1201e85ef5bf1510f41437e7cdedc077ac578be05c3f6c3e2ff52fff15e950812451fa5d95f3c0dc1ba6193266bafb4ab5f7d9749fb5875a00db3e73fd350d7001b42b8be02d8f667b9704907d846609f5328264c89502567e85eada1cebe3d5ed84eaefb9b496653cd8ee0e3e250059fcaffd6284e16143f8ef744b13639f3bf3c14d8d856866a12c50b5dc93e8305d5eaf3a4d1a0a764556f0a8e9f13c102dfeee40375ec7d56c80c4363e5703317c55b44bc3046fc4a86cf1d2615600d86c2006d5f640e20f6e7e910dfe228e38b4e2d9384ee3c3619c8d4b4104a2988a14d62568995f31ff7758a4acdc9d008e049ff96eed4cd5c890e42aa3ac43af71d78b368d7e4be2d47e204a6dff1ae1abc0afccf2027a102496011244cf87f0c481089fde0287d15e8cf938936c496499a160592f64ceb915dbd7e9eb497ec126acd04a81850e677212c650b2afa3019842916e6dca6c68cf713b901308e11ffcff42624d4bb32b102bc2ac7123254a7cfb9181d15b90c9dc9e8a83a51a59a289e06b5eb4be4a3e6906dadc60084fa01493b8c55d251471dd140c5e1adc7b9d373fa90d99ded975c5a26145836dafdada95bff3ab06b6f95b6e824bf9c5bd49d16ae49494ce50ec36c1f22b04595e9187725d508afba0ae7ad505255b13e55d2a772931b", .Okay}, + {.Pow, "-4b424a9a7e68e12143936c35a86831965cecc4254c1641953dda84a6f07725a8f557b0dbc6bbcae9ce0128ff3639794bfadc6f333caac5836e411ed33a0cdf7f39ee57d4f4a0c2626fecc0f1cc7f337fddf03dc5f63703b55661c57c1a6cf72737ae9ca5a3b2ad604d5245dc4c0f2c0f8d26a8f4197883c520c74f4cc1334b21450a4756b0c82c7c3aec93462b8212b7758a78497e1d", "8", "3a7fa437dbbd00304fa898311375bae52648fa2d0e711bd53f81e25eb172cc109461a037133fbfac0ca8700c6983a7d8ad36c5577ac6b50eaf10bc9a4149e77b39ed0e6ce2b07c362fe1b48944101677322920ef6323a06e3d06bd382956e53096752fb2c8faf10e0150c814997183d66438d5f0041ad14455687c76674539f96967aea323d0e4ede4ee9344c6517f412895bf65530a9299934118bb6689077ab4f4c846aa5c73072d8066e6032446b14943799f8b518a807310ca9e3568cad22a102411b462633256202d9d32e74590e8861636d1db66bd75cab3ccfd4eac375b183ea6bbf4603271d279d4da6ad7b163b6773a1c6e6c23e8cdf0f5b838b826bd422b95620a925a413c783c2b6b9bd58c54d46ed7a0a0362db5e219c4e6531d164e39fb7b83c475f0facff54637d72e2452bf57f080489ee15eb6c06841631a304ee28871f8eaf656da48e6deadcbefd17a82ceb75e86828fa0284593dc7f5c75d681d11515404099baeeb3cc4bc75a0f6ac8ba780556ceae3ba999b17b69f0ad342518e51abf7ca590e69c13529d953be8a5bca0b6228afeb6f740dbbbfff0c8d0a03673b7aa11bc85d9b9ed833fa9c4443cb6739f29e4318f886367651de8e2a282eb448273c646d87741895f1f04a4a85cf83f26e4d540dae959bf4823c5abb6eb803861eef60ff8bb365dfa17d73de97b8c8733d2f0e71b5cb8b3f789a13eb9e49cb8681d8cf5c83ea8b4b1a36d35135f47d7451ccf2e2b00837e39619eb96783d1c04f717d5a68ab05ca77308b5ce39589ed9b91c2ca2a1607114213e70c3843a99098a451c2fb1973337b3c52c86c8260584a7cf9d08cdde3c2e2926e7ebe8cac3ef1f674b2c485d70b130d2bd67e9966ec072ec1e9816fa793ab671157fe459b3908f5ac04f28b581dd585f3375cd3540c2d7790e9071304cf4d00495c07b29ce982ec8d7411a999a43c6e7d6569dccbe9eb6cf10b9c6f9e72091ee101aef29b0096a5d5150976b984e3526394a40cd54488d2ad545883f9b1fa21f359626e7a079656ec384227e14a39cd992fc7ebe661134790afbc03bdaf733adcbc7b050f198eaff92b4c2db10c21a231b5f2a33c173de59ea652827cb43cae18b3417addfa5047950bf9fecd56a30aa46f1b899f147f851d5bf55d99ff800ff8708aa1997bce52c4fe3c7a8a4cfaab5d663950783d88d6fc17c5cde58a7acad822b240347804453d7833383bfd858c5dd5352e02d0698b1de82c629f3bf9cd15e4f4e335807bcf5e981178bb385b37737ed3d70c9da74003b1af4375ec5da198717a3c096be95eef1c3b2421bb1566afd1c595b5c1612a71e4b17145f63c96c29a715816e4d01e43615ca5e5ff0f60f014b5039114751476067da8f8ca49bfbc42d8417336b4158b3a8dd076a268b2723022fc9c06be63f1379e7daf9df367e9cc1fbe407ea0481738a3a612ab264be1c060fa83776a499f5ccb10f560a83c5fdd374005ad3570559c0a57c99467ae195ba94c3a6ac009e6b4a9fe5e7de4f9737f6f85f90f88dcf6baedccff620c507597e1f3a67e52c5b88fbbcee92f83920d6692962d7c202ef6aba46ac54848aab6491d32d72aa442244458e706f3bd6feb9dd5973a177e0ac390689d4acbf10d252e66cfd25dc033dbb72c53691b40b34d6bbade73f7e565e2dde243f992ea1", .Okay}, + {.Pow, "8f0ffcf030985448110868318819f67ea7713653b1ede71c73ddc260f1d452f7b117174b92e0df5fb321bf8a10669ccc00070639cab45fd3f36a1de357a96d135df4d608792933a04005fa98e0af1f7cf8f680c0c85a7d8d5db58c7d7c23a7612d758813b37ac677b27f4307aae2b6d242bfcdfb6a328187cb682e7d080900cc55da8d41d989b1ad7b5f3e2939a5f92b8d2738d257fb", "9", "15c60e0bb744a2385cdb136c2c2bfc1d602187bd4c6aef683eb3fddd4f30a9070084cc4e309b31504553daae3db35d6d40f89f6f486fc4fb10ac13fc772223c423fba55f47b77032dcea3eb3a10e99488b264ae782f92b1bcd36ffc0d28f4276687171ba4ce7b75cf4771ee8962fc139b3de23abf5efeacc4ddeb8903b99a333d26213525cc37e4ff992bfdfa6effa144ce1f603c8f89f10ec20e144169f64facba63ff5e6bcb5b6950d28f87a51daf0d9162a6d32c721b4400d1475a5d2f088e0f4fcdfd80b8453b1999c604d1aa25ea080477814bd332a227cf52d393ccd39998aa26f1fa3bf00cd8cc719a0a3fcec0996e8caab7a856f16924cbaf26823742ef864e9fcef45597e1e7aead28852260bcd204401e028a1e84a7e13bab6819005d031649314b14475a35183810efd91a27e0d8add47a709e418dcbc9b38b7a42930b3b2d969f36174591e9165012b71ddbfd222f198e65c2048e145b0c51830a801c8f98c4d5f4a35d24131e98943c8aae44fbfb4da00fb2f5ea03f47b10ba10510a960c3c31a05d52ff4969a540d23e01bb01461dce8141c9f8f6d2855a540a74451f86d90a2e0052277d18f66edde6f4f5e2288fdf429957ad3c76440a55615b773517d31b7099b2e2488736e56e30eec9d51d9ae1de6794263f83be1af6a9521dd467686b77655c6812608ff70d645076d902ed49f6cf92f4285601e5d10262d45f895b70a2f3072814b93e3cada4ada4aa2a6418edf6679dc330e816a8d942d8d6393999d813ecefe9aeca8e666d9e89c136edcba29d703e9a956294918c3b19e0277211013481f1a73d565ce2a4c7cd0ecb7b7c2ba0d5c12828c8f2c5737340ffbe9301e0e8b487ae55fe9512ef134ca4a4435f751b4212c432b39b648f7a0dabfb551829caa36850a2e6ec94750fe3df8f5072753526c89d10af4a887058c7d7ac8ce41be605ddef96ecef5762698fa1b54c411dfee1bff2f9639e60b01583f06ef33173fae1e73fbb85c83b04f09ab87634a4a920dded1eab62326b998fb6c3d07ad1afbc9a28c83b97ec3d63311c6d08f835b36a568c2c1fa80886ba6192aeccb97b554f43c2a15f0f60499c247f50be059bb5d857ac8ead115a249acfadeca14330b2dd5426339f05d5bbd38c1b71bd2be1ed4aee0e98f77b6dac8585fec56cb3fa9ddf8ea8531c592bbe081bab1d445deb140d6098b2ed95c6396a76011fa1af5dfcb785b586136a8d33e089d23251343a3463b4e8cf069f17589407e301db5842a4393ca36e2c9d42e2d3a510a66f8c7d2496b2bcba0f7c16cf3f643d144bb33cddbdcdc05fce60ae85f83094d37cff86080da71db72f596da7a4199c8c2869d9f8e3c2b82e7f1f3e9bf7246efe6adb84d8ab7e39d4aac37a6f6dc164bbd5370842fd629bb40e23952cc83f36736e663e6a2b8cb9fc570da72c055834bd7e9770529a7623635982c2e0637d5442108d8bc6663ba771137dacd2f8ce95390cb16a29375d8e7dcb81d49ccf0904df1314ddd69413bd14c351f593d85a043ba2fe226373e0479a63e66f842d96a0fc0fb5c8fab49a1bd54dbd020e1542e0e5edab4f4b8e21b3daec04685560b6592fc874fd49868ccb3f6f604aedb72a2790829acf0ddb717a80db7dabc2f4d6d30899751912b89d752aac96b4df0984ebc2cd595ddf763b2b5cd4a5585a1c106bb11d145bb6735aa3a1f07596bf7fa0fd72432f792d44ea36080f883c8dbbdf52d956474e454aef02c2f3ddde3896de6394ad776188cd6cfc4c92410c2173cd04d435ba6377540377f69ec9d808dc5917426bcf23a978f783d9a2d43bc7a6d0952d29816ca3d3d610dcc3ada4c0a12135bb22c82a1dee6c6ba8d1b8204095a9f3f42cd5881e5bb2152781c88818ee3dc2b44a9b", .Okay}, + {.Pow, "-63d548331da922025b7ae6c092a8104b57fd96eb7b99a7078b1fb9568ab43a56d9091818568b2e66d690335d3715e8a0fd4c1ce6ef2be44748878daa932551bba550ed52d2d6782dbedb859b75cf00a0beaf5dbe076c9bd8142dc656e96ef1e4d63c462fe229bf30f988d575448cb8a7f692cefafda8c59a7b2531324ec930a6772b06648b31038bec2424d3d4af2d6d2e0103868e9a", "3", "-f2eba562d204356cc21e3986645de2758d27d3c44becbd8be8475de3cad7469f5b5d761f1039d6304805138ad1c81629f27665b2eb067dac318fbf0290f584597b2270b77828b6e3de41415cb8a13b04d0945ff0d339c934b6423ba5d8a6ade49908b935005d8e5924e7bb6702dc924ce0d4cc09cfdc75267dd545f11d0879342a64b9bc2baa812f63c23ef08dad8da662fe7351b6cd2094a3031e93a1ec1e659f1e0e8a1b6a65413e897aa370dd9c0d351926b210d25f9e23360bf4b41a114f08ae939caf7bbd01d1653faf57ddd7c525ae076bd6fe0b82066d9f4700e6c8b4db4ef1f53f31d9435c05966fdc459cd066b9c6d0e699aa1760d0f62104d0871b2e8485a87a1c43cdc48f0ac0952edabfc6406552dbe59ba20a5e00fae3c414322d58f3c745966ba6b74393112f3f1aa4cd2d3005134da2a2239e8ee02673a8bc52cccd0cb861360446a662d2ba2c09aa9601ff1549b620e87f8409f740c344e962c4b4d88d5f74058ce2ea7e6c32a340498b3b330daf6fc61e1c02641ea3449e27aa267c196e1e92e2509c72f84f9ed1b90d3ffff4d672623f1ad9ec39ef3122f19a13a70961984a77d0ec251b4d260bca3be8375e169e142e136f94c9de5a0a2a8", .Okay}, + {.Pow, "c2e4bccdf052a58cf77a0d234ba801743d7cc69809f9a0323c7a23fbf1be0bc394e9c385c4ff892181a2c6d895372299c77b5c57b1d2ce0332b30b6eacc04bc749ee6a5db32e2d6a2349bf8393a6756e7087b6e30fa3bb3c3afb0de470d65c4f8fb5ca4015c5d01ef2dee3680600f5dcc833eb75155ba556ee13a5ede147a1d22286c957b1c7321eb3dc21d35c05bfe2a4842bfaf662", "5", "4177ba28e03109cde936602b83d05f9f5aa259c1e6962828792369cd4da980c2da187d6fe017cd30e439a5431dc1083c59c3c21da19a3dc0dadfb754cde5991ebe59509e2d5a93463c3f8da918724b1270487e4c12d6fb5b532d5a4c7092fb86e5d2b6922e749e05176bd61cc67a717b1d16c06953e163aca520278c99d1e4f935214f69780fdcf280278de8e8f3c1cefbd2c54c407dd90ae96c2ea6e173af77d377e2c3f3d04f966997fe362311808f65caa21a713901634e9e5c3901893c764f91b28dbc4aa1190120859f6e41b7ec7c7a87441dd687983582f5d766a711591f9f2c5c1a2dfd64ce65eeb53963dc11755da59707a445066b7e47b73e7497b25af3e892267718ac90a8d28e7877f35d661c5cb9c7c240dca385d91cbd82f17e04d0acd3d9128edaf354af63785f6ee23306b1dc9bd6319803b0c3aa11270301ae686ae68fccb962b4ec1ce3a6ab071e8d8914de88dc2596ab8d46179b95c583791f487e4db298fe3488809bd966fb07f6baf46829a79063b849f45cd17746fc6fef544464e7fd18d5428523f4b0f3ce2debe2f5d7126da7b0c3c269428a4e1791191321cc58087563079a48863cb4a2900ca7002b8ed19d395020be7e1bdddd4bffa5f98f6bc0d40d238e98d435474495979cd7f3fe51f0f53811631a4870c8d03b4fff866ed574b482dc4ef11c32b31bef2bfe4a2a37ebab0e8b6b922e931b45ad7f4a7d33b8c679202acbb9bb5039f3e13270483b33ca48ab8b134842578b1aacc070b0f0ea78529771d58bcb4afada0f486945f228d88dbad91d31d3035fcb68c5122e1454c255f9f17d4fe5b03470bb233eef1a4e65347616c0fcc7b5de972886613a45734e77dbdeb5ef9caee3905dd24d511057d4364b82e1a6290c8629b67b33ce144cee5a7e8b86fd1344429ede19d806c30499afa38b66cde6f5ce41596ea146e4791bee4a8a669f20ab960fec7c5633d2c6600ecb3090570e6786498e848cbe6b17ff18563e861b9063272d927a58f6ce62f4ea57c1b9b9ef07bf8df069c75b43e8d707c3dd5c3e20", .Okay}, + {.Pow, "e9f741972ae36c2b00de4d2781e2f8ec04292b676e544b0a0636878be6535c5831744c6039c3721446f7d2b04dc1ac279611ac5a8903e3f1b525542b5cbc4943e68c49a1a7db018123dbb9271b4da2e267e7667eb3e324b3e5df60b6bc23c7410e5e33490ae0d2f56537427616227289b43c67c021d7261363688c741557d88cfd4acbdeab6310e460e89278ba15a49215a16ae3fce4", "a", "681455e7bf42afc094d1a0db6639ac946de86575b730c0aa6bdc79fcfcc8373beb23a2ced31e3bc82e2b4617ec0dde41e76a60308928ecf51cd6ab810753bd676bf78fcb57c8b1afa4fda12d6b30818777dda7398312bb0bbc1d77cb3a05637f5c75e67ddd0a3fe5aa57c700ad40b0aad91f732a739ac752056f65481c022804ad4417ed5ce60ec43740a33dd2939689416259640a9964532c2b48f0a3c6a1146a02413855dc52c4da82d35b46a92f3561bbcde30d2d2bafdb5c99134072c22f909d0c7ad281aa75646a3526e7af4cb5d5255a7731944c821433514f982fdefe236e47f53358b41e17daa79fa0e02125e2924fdeff6b40b3ad188757f903326e402e245e00abb613a260aa4943d888e0494c9fd4335107285e9486a463b17e7a411882e179262f12ceecaf7d651fbbe6e2606a1eb72f062df968256f64cc538c2ec691ba34e46f487943955fcfc66956257802978c469cfe5de5ecc6c46a0c80b81015f77370b3c242205a35d2fd4effa0e9c5c9d85152c6c471c10552f47768dd3eecafea5923da66944839e356c49657ee96f3139accfffe472d8810b0a888d5b01dc50a107d8eee9d8f313a741f6e6dced1b3967901155944c6a06062c791a1f537d542662319710a7ab3727c1ab329e3cd5c315613e9c6d112fc462449300b9af93acdf013743a674c856ee8ef72b92bd6c2a5acefad73c15167d3a8c3ac2432718c50afdf40a84772d43b6550393391eb3e4578e607c79bce4864608c39a35fd7ec079b5e898a4405595e6bd3cd4885c7305672c8704b7b5f235d6efa024c9ea1763e7d11cc17d59236f622f14ea8a42f54ad65f2c865e583b7118121a2f138a45303f751e4e89858c71e426388f4f4d44c26e625b4426c8836d4f149d232e0d126cac8cc99ba11fee3e2f179bfc7c63cea163480158d2f4726359ee049a6035e4242d8a2837b35c6662bf4637d5c3374dbe2b20da5ee42b74809619e74b9aa72123898e883551195c0da453b36334188763580d4377547516bf7eb9429723a0f3493236d1d4c70ae60c0ada6e8c2becfcc8e864bcb04c2aeb04f9435d7189bbd044b4fd197ef631d3329e466489d6912ace1646d70d24d19db26d3f7bda4ad7dad0e6595bc79ae57679810ac8eb886253d2f99a29f40e4e5f1c37c2ab9c7c183ac9a87f26871a530f0ac4a06b39427e6bbc8b3883f9d0209b41ff4b6d0fcd98c9d392af3ada28d2d1397ec9b468f05674d9dc39c6fcaea47184b676392e566b8746d8884c3b685e787e1e26dbdc0d8acf68a222d6d632fca53a38027b4532f3fab7f07dff5992a4edc22d3e80b4320caca914b6299122c3670cc2f9c3fe14c15328c7ffaf7986056fdecc79e6d958a67c516cca0762af0869db15c32c73686063825ab809211a9279e5f0c3202aede33c63cdf949497b8a5bb35f838ff169f60ad84fee081c82dfb54704ef2ba70bc63fdf10d83f4e27a7f1669199031b691493fa50024c7c83de90ce46942892be8b45b30cf97ab4d79429cae7f671e19be2a5adedb86c4f2313aaeb54890e3cea1f51ec3ede1c150b52f5b208d17c18d067bf226e125615690ebf6646e620cb5dfdb6930eab09fcfc23a7e5c2e7ebb639414f2a7a8a41cb2e0736e1b57ef8738edb3d4deefb778a50aa9be01e45e399596bc46c4d5e5531fefccc2771fadc6ad6070f7cce7c04a5ed6ab899bd19928c967d5521312eccb5a875b28f969f779366ffb8567c5072b14e591486d1c61ccf881e94828b5eabcfd89917abbc5d6ede23118c61da249417b73dfee1f510ba13435ea7f7bc7cec8c79dcb379253b9ca441734be28e168688df05d1672913322d0f6b18872e052cdfb9126dce846c34879f08d84f48ec52ef3bf15cf81ad140130a587b1a7edab2d0d4b74d4276221913aae237eb17db03913367c886a87d9f4110eae321dc8e00d9046064c6f7a8f5ba17e32de74f7ef4b508f7db61b7e3843940645a92e0a7d7a9024723aa77a1db3e0009946ac8960cc1b487b08077712cdc97d21d23357882e7334355c903acdd8f7f56eba65f786d75e474a24b5cc2dea2e6f81cad71da1fd311f4a2092a000a31d8d6a1314250b01f7100000", .Okay}, + {.Pow, "-2118feb0e719092057b32671a0e1119b89ca6682b70678b0fc0bb0438972524ed4a7df66818c9f0e1359c09a28f7720d2521cd13bde401c44dabe0a0eaea1ae180f3a634fd6ce66f9d827386021f577175f4622ac33289651fa3bdb456d87e191b4ff47649b4df157f85d55ba5d7b4250a3747e1f2e834636b5e22707affce682464f1a5530328d4e9d9c9924e88665a67e731dd3d02", "3", "-8da0ec2245dccb61fd08ab28b2b074dbbb7e6c2b0649b5e90dfd85a0b8562b2de53a12e82ec7cff53016f89088ad0a8a8d2197c9dc73fdc4555ac3fc76f9cd9f6bdcdb26decea943d8f3e84253c1f9dc164b545da95d72c4e453f1fb645aaaaa271bd8a22e2480c74e1b7e98143b8786a35194e526488d5df697730937878c1eb6ad43c386fe816ec21779ec24c0d3b7727220d372e4112705b40361e4a84eaf11959d88a436d9a4f4caf165b8f184427e3f0e5e804f10d986f2cb35256d85f54a37cb7098f119f2edaa50e79c1e8be70f50544f1596b8c8cfea1cf9b69281f00c8e1bca4426833e13f5c0bc3b2eaaf44364aaa546f84a0535f937829de2c3462f101054a9e449399a9b5d854924d10a1b632d2484e62a1beff67e09d877937da15e574f775369ea5ff1c86a7d298f697e706681aaab3e023521ce3e848045c010d22514bd0d21e2009ff9710431405076ec2f48fd345cc39f2f526d8e88b4e72a1990ddf4de0d957b5181faefc45214859db6cc69eeb9d682929f43d3aeac96564dc46b0241c847006a3d031d97e294a1c51451272bbf40d40cfa1b1096cff0ef7d32f0908441d10c850ec53cd9acd68f2b3042c2fbaf9f47a8f808663e94dc08", .Okay}, + {.Pow, "fdac259d1d5a3785cb55a5d9ce2371f46da1fcb43ed48f5c9e02e8dc77e824fa5ba59548c6545ff2d687d0bb48bf4f5e3a2fd2f480962398cdc72edd476f4c72d1179cb0cc60b6cf52c89e8abdbe9a29f73fa36347f114f7739fc02f2f1b97dd4a6990c4f61af24268ca1db3ff5ae286d073ad257be1df72d26581896f411e6453ddd94fab38a48774a56a89c380dc65702b7fba0c1d", "5", "f4926b549343a38d946bb6dcdd25d4e656f8e238edd123fa644f1bc4ed9729be751bb3479c178ad2053fbd5192fdb659c5959267d54ac02f7cd2eaf9cc0414b277c29eb871b89a10bb457c177c5edd15db2f586bf9d001897842b854eaefe4e2f279e119c107a8d3feca365f8b465bd66fd8aca196ab7fc0c12c01e5e2ad8dd533fea25c095e5e96370ee23c7f40f6a707d6ba856f486876a1c2929b3852a5e3f2b9469051b5d142c0b6b8a6b5a3a3630b765b1893f7c9b5c66d06da17ba1c3eb4d13582f46198327289fee32feb20e0be346fcbbfe6a5fce2c30dd10e5c0ecdd03951f2556934c8c090088e0cc910050982220fc3b8702210adaeadc2f40f4ece125c9854c9cde57f5f1ef06bb8e9f83a3927f2e7b5877b0b53db54237d77629d989b5c87cf6bcc165923b5c71ae66644a0a2494053ef869e20348aa50b7fa133ebc62d1eaf7d34d08c2e97b69946ccfd61fb7536a33cd1ca1ebe680dcb7d4fd0da813ac9d9e82f9d5b2cff53a8a5ea70916c6e8e13666813f9f94eaad2b9cc6545658555c2fecacfca97f0b665bef1d47766445267b406c9313a88468d4543897b5ed96d9861f6eda7bc04fe451631648a418afdc708a627dd3a8a9a1fc141203d91918017c67b4907b4f0af27300f1a1c53b91b1fbec6ede6e49b84ba8b057aab8c34f8e3c1d7037000d9a630a213f0b4391eb5ea3bf7416c08cfee2fd704fea68bb7e64dce99e2467bb5072e14f18776caf8b68a61d38a4dee166742da0c84110f4c55dc2c22c3653057516c4793be4af23a6527aa2f8d8aaf8e2899a448d69efb4710a21883ac7f5d75784c35313bb9169216788a748207fa695b95a19f1af4056cb35eaf81e9b5531fb7ca4d2bb69b6e3587e92925a473df17cf39c08e1e67e88cb81e359d7847cb5d86d158d40dd1fd448f675bdaf61e5aee5a540cb26e6fd86af60b6886d903c7c397913425340a377d1ffaa9a72a9b484e187df3c8d363e2014dd2eedb499f628bd2afa67e9c6ec55b66d9161151bb7b79211b065939d296c05323a139e6620323f5ad", .Okay}, + {.Pow, "-b38ee5c7b237346c8d6a98a8cb9e92796d6a6b68ed08b1778e0a18738e8b61195c74be9834538d6ae423c87205614991bc262fd3082805c4a0dc820ba5d701d4ecb8df1e73008f7911659fdfb18c85bb900f64e4d632747203419a4fd9417582bec92c8d013d711235d12e63b1d733e1220c54c97daa949fb2238bb006ee4987ecdaaae42b2dc0eb0d65e44f3dc032f483b51f66462d", "1", "-b38ee5c7b237346c8d6a98a8cb9e92796d6a6b68ed08b1778e0a18738e8b61195c74be9834538d6ae423c87205614991bc262fd3082805c4a0dc820ba5d701d4ecb8df1e73008f7911659fdfb18c85bb900f64e4d632747203419a4fd9417582bec92c8d013d711235d12e63b1d733e1220c54c97daa949fb2238bb006ee4987ecdaaae42b2dc0eb0d65e44f3dc032f483b51f66462d", .Okay}, + {.Pow, "aa08b38d0874495461b1eb38d0bdd31a2e59788290abe8d20a5eb11fc3c98b9f462a09c4a18ded2e63f7026c341a2b1b4931d8e7f40859924e2b41fa9fc34d9aa1f3c7d2cf07557827d18b610b201ce0d88e686a655b92ffb66bf8360dd4f61c7d56ddb4758603de67c7596ee30dd0df6f029ffe58e98e5c6b82bd6985bc85f6f9f485a7674f5dae694695fe1a43e21c9c8fa014d874", "2", "70ef8ec305f9802d95f2a880654c9c33d03cfec379db9ea458d156f6433e195c2aa5aae6ef8e0a549fbc11c89fc52e015ad53da82d8507aaeb8c4575a342624bb02e07073ca90a1fed88a1f24182c002aa12c4bb4fc61110abf3de87c5f767fd603fc4ec8840b1cd9ab18159895bb44a733c3d5537170e7aba883391e8dc05dbfc3c0cea425ff090e79e833f89c2e63d48c4745fe63b1655ef9769c4f90a166e14fe0f8875f9b210296e98312a02886846a672d55e08ad2c002483f244d04b82220cd335e129259dac1eb33e13176728b1f94f099d829939bf5966d613394754f81286147cbc3b74a8b9e7acc39f49c203799544655ec263fc874d1b6b9c580d1236c71496071d70d51c8e27d7d82d1ed7d8ab66260ef8bbf69efc02fa7d1c16cae00b21cc9141db8923f490", .Okay}, + {.Pow, "ebf4e373e61acdcc800ef5392bd2962914cb1808a8fb11d281f04e12088d8ff104d6135f64b59f839d37a85accfc3d5c8a9ffd0b4dc6cce1f6b146255dc85ec47acfc7ac9679e2df69c56284f0ab54a12e5e89dbde66bb0709af896f4ebb5d52577f18179c8a350f7180c7e9c64395db4a4e82ad68b7a66557253b8518375086203a3cb172cb5fcbdb9a60485e6660b618fb5ee7dded", "5", "aa4b67906e509677d0838172d48b0d7b54f5edbb0f0f434f2914d73b7be90c233ebd18152d8ed72014f5b922e1a2c25ecefc9abf8badeca46693dbb4dcae907d5ff8ae8a5751fa570563387af3e90ed01d1e636d94c5ead894b82460434f98fcb89b593b8c5196496b1878e9cacb4e325593e294bd29706eba96cb7e58332ae5246df73f76baeda23790af0a0d47ce9e3cda0c16cc75a71e8e2a869ed1870ece4a6caeb724d949e08f05b403023d1175a7147a7ad3c6a6695f7dfe14abcdb67e8102b4058689e7a06966e55c3c898e21e3284c66d97926ae7f0407cf01029d68295e2d94b6695e2a808047278bffaf3afaacbb1e628193864b110463863f70c2da743f15aca4bbf925c206122b9801c901d5d89798b0a27f55b26d853322008179db4da72b5cb592397399f8b9ff7e7f24a742b8f58a2d0b98768a179474bbc68e713c46c1b1ed33e73bbdde0b070d12e531ddb05401ef9ecb0c07df69bb26acd03bb071e4e022ccf61d3d2e670d2f544e643d6a9965709813ea7f957efb49d259a9b9c54581feae36054251b9d8aa94fcddf2910f5ae3bef941b1b869f317baf40da52ed76c7ac5ac17c1fc711916f403b71de5dad5eb1bbfd355fe9db60d0595ad9694d9e3d30a879e6ede31431c7d7dc4ec87ba49eab6f8dc0b608d7c59fec0d26d78add3201e3ae0e1f310a987f2cecaf2aaae468eab3e132e7b586fd4bc49229d5b23b4d4c834be8cc3c0b4fc901355dc4d06da24253cdf889a8cf42002887e1e34d3d99dc99e255a6b8214e3edc29eec00447d5f252cde43ada0001a202257f79f16aa8634dd00478a6785fc90bc85510fdcef444e04d1446a71d3b03f07453c68403f2573c11e5f2b8b909faa2fe2d6956a3e3fb9082f072f64b99a519747c12d5429020389c982d14ff7dc8a39c367f3c426e930167fc7fef0e820e5e1677bbc77a20659b70eea65e8c6cab09c105e77fe778b8f4df73309a1be2ea0e65d8b722b30e2a598e2fee0a69f702feb21df4ee06c67f9d006861ae999c808c0dae5b150be5d165b3eaa1cedbd", .Okay}, + {.Pow, "f534918e9b634bb6d264efa0674cf9156e9852aaf5e2a2c20b982636dc7ce6162117d57ed828420d248f0ab6e146a95cc195443e7643fed658b35c577fec6d988387c680a1aa9ebb73c52c81487a17fe1b9680da9ecfe184cf750d84c123118587a3f7265c7cb540510c8561abc255ef64f774be5bdbac49be8af14a4caf083ca80676d2e522449d7c7b1f34d4e5ae4eb4080849cffe", "3", "e0f65dafced296082ea23fc479c018fcdd1e07be554edf3e594305d03e5596bcf9051eb7c0c7101dee0fa8fc3432cf446f7a56c52ddc70f7ede89361591275233dd3282adc6c07073d88464415176cf7bb12f7e3894f31851c45dbf6683605347ac1d4c68f87596b5270439ae9bfb7d02658363ceae589fdb788da080b5c7636e683bcba6db926c9506e9d93fec4380f6e174677c56b9cc2dc8d3cec92d8330fb3480bfeee3811d9d45fff57f63e819c0c458f582b7b3f16582b3782324d439cfb1e5ae2bc31521de0552f0c0c25f31b6d9f8638aab6f624f02b75d0c6afe811b5b0d372ffb6db6e654d563d1118f8d344bca380b78fd82523eabf09d5e5858de02ea2e63b39df30ba84a34bd22868e62529db978e49a1e98b3a2f13a63a5ed344e12dcac60149bb3c5007c8f23f159d1574d19f36e84a70eb34319f9cb5e47cfcf2839d7736dee855568a14d3a086912728b02d2318b43b130796b22bc017c78d6b569edfd4531204c2eeb229c05599b68c5b1482a2f225e5e0731b4c1c2814fef35d0809a76bfea77b942ccd697082a02a97ecafa6372b2ba9925ba75d4b01c1cbb26d7176be5eba6b85b7fbe468dcb297e39337a2d65541158525cefead75bff8", .Okay}, + {.Sqrt, "3d5278fad55ef9cfe9ce2487f81ac41cc6c6af807a3cebe60172d970f37f73a8b0c104551ce114fd716b58dfa2fbbedaf8ef975d1ae6b015401a2b2730b98a2d719b19492d47a40384bba43270ef1892377a630016c050c65faa28de3324dc9e34942e3eee5691566ccbf5314566523713b52c46f678bb707d4362d22efac79d01dd21b475181e63ad19f20717512a39312430329dc2", "0", "7d4b25ce7fc97b226c8a22e38070a43c6e45be4d594f06cb51977982965be3fd8b6b43cbdaa5edcba320c852e67bcf49d76e3a758a90dae5cad996e7c8c2e84b155ecbd659f989acda4f69", .Okay}, + {.Sqrt, "916261d5dc7aca16ddd77ac0b8249772875ef9e4bbaa5ffe6913fda01a7141fa11fa513db06f5dd4ed30420de878978e848aee43346ab4f9d9e92fc0a66afbb48b669f33234d412a9e72aae5d16c4fef838f9c51f8da430eb9d1c1b9cf40e9fa94952ca1a6a403fa424c6942dabb2e32e411a2a33bb24702fd7d38ffc91ac45eaa51c81730c01c39c70367fadcdac1d0cfa25100e060", "0", "c0ebb09026b37977ae39c06cefe87bc58232c89ad76f415d41451162b018bca2e7065ea966318c0a5ac2adbdd5167f9f7b26ac8837ed392cf4243613de91bb37a8682b015d6b5bf740bfee", .Okay}, + {.Sqrt, "b33aafc72be7cb2c8015e6d24371389767b4618794e2aede62d38fe44a7b1d75fb8aafd1ad76080876af9b4fe246d2f5b437fdd5e3af7eac367e4fd3772e20db1df392a46f257e25d663a67de13c0bd095b373d3a424a494b142cd53124000742913071ff7b9daff2aa112a9d40b5365ddbcb972da81e71073cfe6908e19809bc6c54971bedab5594c55ebcb21380a3fa1ec5023ded7", "0", "d633d34fba723b8120738e71d3b80e5b20d1ff313cc0bf908cdc36e1b60cc8f5e69512fd0fabecba9a3ae8d93142d320a7c603c0c48217d0b8b203688b806ae812ff139957669110f50e76", .Okay}, + {.Sqrt, "1a99962215c83c3a5583341d67045737ef0947cd7733abcb800c62422efd4f7473f731d2c77f93dcb68689e9406381a469ed74c3d106729b905e2ae9252ca4a0b3e423cb2bd8f170bef29560a51500c229bf0b841c4cefd8af716b3ab9320ab5f3ef9823eeea47cd470db27028cd78ae51d090789be0e52e60100f207dafe403e76f4c1d88d8954ab6d62e2d15dc92ecdd3ee9e8a60a", "0", "52852d09c43b2ac121243b76c383fde6beb682775ac3a25ec8c83b3eef7e01583502641ff524b9979815f871832411b5c894982b9aaff69aee837ae4ee3ef1d54c888533a0fcbc22700539", .Okay}, + {.Sqrt, "e26e32ff43641dc843dc31cb65e17c4140d3bb6a17afaafa6ec4bf980472293564cae8fb2366dc8c21be13c596e552b0c40dba76345b8ad5c90a43eb5cc2d90671bb4f0028288b946cdeba1e1b33322537f0647dfb381f60bbf58fde941e2934e72a762b5435e7aa7323b392712caf49543a523a2d20facb1b845559dab0539aa464b6943d6f5f56bf5b8273311ecc32e7a429b85811", "0", "f0c2ff2eabe2fb1b5819086dfe744ae334e9f44090a7782f2c1d827d45078bc0e1e4c4f24694ea589dbd60b02ca25b37abc2ec3309e0c5e4fbff10eb1f4a7af6b26a7e586025fef2dd69e8", .Okay}, + {.Sqrt, "2a64a11e85ce3cf0b3ac7b9f74531a29e8b8d10b417a209805059c11039c47fe550e805b391ad97ff18441f789726c4dc160b804fc2eba5be1807886c0546d0575a001377519315dd51705886e0d0b6c2dd3c9b1ca943d42737d4b4a807978a50df539857fece57fbdf114e9769694614f70e58740b84639bb50f141648da6e5e3fe74e6490d73fdf4be08eef8de97cdd73590e2ecb", "0", "1a0b42d42ac0a448a7c024fc0e048d08c2460f0513c82e649ac7d0a02e52348d3b7b8980c4b93411eb1600d0658ebae689dcfe7367b2b50a4e00859e8c0898f234a9f573048a86320b62d2", .Okay}, + {.Sqrt, "85fdf7b9e1dcaab9addc9930f452f9fc6ebe8e64bbf3e548f411d627ad5555a72ccf36d4aa35e2c826c2d3b550a66cef1bfeb89a28e3e33282169c69c440c42f3129dbd4cec7e7fbd2800d11a8c0ab4488af1cdacc70f2a745854bf78a536c6c2167983970d6939e8b333481eb8807e5d5f672f5c822aa5cabdca36c78ad1ff38cd2597ac51c7940fff61a0f0da2ee28b9e6da60ed2f", "0", "b93539313a9a9902c31a029f10b63e98ea47f43e7ca800ca032e5c9e7fe438eb300fed83e47bba2037d73b0427c0d16a8dec068b8d4f82d72a03ece752be1edd622c356a8598cc8ee5d7fb", .Okay}, + {.Sqrt, "d7992e56735b1938227b1fe8ac820b04891df59cc15a841cfb0e769708e823f1809a1bcd77b1c85749e235136f148331264673169359b7a32b113d427a6682fba148efdd9f0a061b2d5e2c861c52018780e410e568b34f431aa9e14c856fdb0e4eb43eb4fae29e2f6bb66f1286a3e084860ddb884f4446915b5cbe45ef04c9cf5f22a5a03666e342d54e0f810b4b7b3bbccd71361388", "0", "eaeeaa930f7572c7192d73f3106446b366d319e6f9f7e2f2dbb008643891253a6e1a0f861a55ba8721ee8b1596affe59f94b3ff63042f17f4fcc81733883f8a2df8cadefa1ab35407fb781", .Okay}, + {.Sqrt, "6994fa81292953bdbd2881cb0cf5e1b485cc52e1a7e40e4310768a6ee80e49b050e81a68da29aeaef58d311ed4c041a43a51e7ae0698bd1114e8d54804e68e671e7d431ceb757870b97d1786c8229c59e712ec4f3763b41c72010fb00e6a2b1e47492d58d234a56391e8ce59fdcd53727bb1f80d01f5e8815d6c4452208d22daa30f634d8a6f882d799b3f1bb7feb383e1f31c8255c7", "0", "a467a8ffcabe0405ea26f05cae065cda28d169ff8a50c28816dd6d7e0ee4f4ad6af8556bc2bb23c999c2faf6604f3688289bf49db1b28ad7ed1d6b79f8608b1713063a6432a081b763bd43", .Okay}, + {.Sqrt, "6b38445de28a0d1014837d8fb49251cbb5b6d20d44f0e01bf93cc1504ed43e49ec91da2c218bf43d869ac442f2020b0bc45ff39884ae7f9cac0f445f1b53a548ee6aeb0144fd85fb9025abbee4bcee14382333ce8dcb916be1e977f24ff6c3c3b9cf4b99fadc79622e91bff052ad821e8b1053c651fa49b7dc21d5b4c4efe8e965d40b5d40ff48a0e6e017dc0fa7b73824fc2c77cea4", "0", "a5acd8f34eec3a56fba53cab6f0691078c39353c7fb655b7f801451035253ab314b948d8e07caf133554cae09ba06ad077a8c8f1429f18cfae1b296c4066cde2b2b4605301c8ee4c071798", .Okay}, + {.Sqrt, "beb080179fcaeb8fe03901a0a04973f4401e5954bed199e3461697faf189d4050f58acf4f5989ed571107a69a866cc427e2090fbd9cbbf84738f7b1c2d0383a18ec342f91a386af7c40715de9f37d632bf97d8222610733cfa10b354d8c937216a8ce677450cbe5f4041d0b263d938ec6f5f5f18e669b3061127a33a95fc439749b6a336f455f7406ac48804a2dad91672d736daca20", "0", "dcf1cef23a6ea53c9bb9e9b500565985f0bc1e7d6a31afabbba92bc5b45b081809c7054b6abe7ed1a1ade8376c3066b5e7bb95d176b7004aec13d17bdf706778b6add5b736602b6e7cdf72", .Okay}, + {.Sqrt, "90d50f9920fd5ce0666adc1e6c8e0501421bfdf53cf31fa8e71441c06724358929a6ab4c723d8e0e92e0622b76acb943cb111d8f50fec417197c93e8bd2c9ecd58723aa21371e50b14fd450aad20b4df01e3cf4cf4bdeee8e591da8df92bf6af6d1c423a5de87c38fb922e7f9525cfb665778fdefb70bc828b012a4c0db4584065e416ca3a691dfbd1fb9b2b431aec01754569dfb865", "0", "c08dd60274eaf9b1a42393d8bcaec4094172ea59e31ea75dcb57784a526997db37b697e18023031d819980c6000917bcba5565f29a2ac5cfd20a66fcd35b46bb56e635a10006a142337f03", .Okay}, + {.Sqrt, "b2643f1a485aba731cee8b229bf7b7e02376f8c2f37319d90a4c793b89f3cb38251a52324e342136a8859075a4976ca68f63d50f07214c139efa73160e002876d3767353d37bb9d1fff0d6b69c8570a16527b489364250f81b50076415e127ccb566592e1e2045529b17e12c5d89142afcfa5bf1cb6fa747c4e086c65559b0fdd3921b0395394801ac932d3f0d34e4564a75e4af07e0", "0", "d5b38887da79bcaf532fb1d08a96ce7c4ae5113b44a1effb7a5d5fd8ab7b68f98d7a4e6c5986a38ea5c00c735230e799a184320e00914d5f0206f6fd394924b136f8d9fbf84f3d245fe148", .Okay}, + {.Sqrt, "23e1bbfafe9ada939b041c34eb4181494ac9ada01be37fbc4d6a337cdc966493c0f32840e237f41c08e2da9931bb4b8a34c93db0145e0661b0f5f773e8b8a37e8e5ae12811e725a91fef1d9cff55953e5e35c2be6238ce13546b64837e2f4b89fc1da5c2c52f6e65e4d7a9a8a5d122f757f7fedf3130a44218b88008b1c7a34bdefe3e4f7406ca89b537bb87e3a7bc866a3e7b542c34", "0", "5fd79ccfcc25c6ef571dd5348c827534674d89ef472c5e0b68f3fb57ef526d45f97f21bd8f6ab498abdcdbf11bc180e411251cab23acca55499576ef84bc118ddc5932b2f9b44250ebbc70", .Okay}, + {.Sqrt, "cef6e38111e678477f084d2435bfbbe3823e2f8a1c5d5b4a3733f20fb1ed142689c2a41474e5da7e6a964564b7ccc9c9c71fed9c144885edbcb041b7a7a30facdc58ffae2c60fbb1ced8a68dd7e6a64c921795ab303a2659fa40a185891905c36f4aea06a6589ddd558f54bb4285adbe47be5858c3f5a793b5be231c3d45283071cd12e68916c1ce6b2a834b426f363c8cf075b6f320", "0", "e62e1c7e3aa35ca99076e63625d21a1f02816f1fd2e0da8019f1c435d355970e1023e95f12a366c48c6f17d902350dcb18684675a4f454bf1efb7b51b1a9d527bb7061646349e8f7d455fd", .Okay}, + {.Sqrt, "f58f6c1d4bcae9502f92e3aa28d25aa5a780f51b781b8236c5dfe3dada4c27b4104a8e4de51f3e9159d93b0327ae6efb7adc754896ec94fbc4cb5ce465c7aa55fc6f5054dd7ea27a5efc0c383bc2ea61a224a25a4cf5fa7bfffd5018d4740ac1482efa8b27658558a9daf845e0aaa5ace54e810c62c2c3f9ba26ac364e55dfcff40eb0169ea439f23979551f8f857369908f91312f45", "0", "fab9cd72083f0f727127112e31e060911bf56c6fd8628fd6870820edc641c5c0d8ee82c33735e63c768a92347e543a4593cab5a2d0d904224a393b850a57fe8062de4d60709e650871da7e", .Okay}, + {.Sqrt, "dd34e5f8593f7008a9141e03dd835f00ab4036111f838e67f7390351d499843b0728b714c032512da9df668314088e9685f39b329c108f956cd348d82580b4d68774d0357c7becaad68c6e4287b0a92d4d6722f50004c36aefcefd013b4673a0cc1e84cddcfb56f115210d82d1453d47c86ac5aea4994840f7db8f5da1a987b6ba407569e10a9420ed0d2da0504fde62875a98359f4", "0", "3b7df829bb236eae44f7600249f7fb7a1fef540e4d0680e3d606a5af4e70f8af4b55cba6758dafdc74ad82224c47e55097e9f9411847b896f1833deb483ce35a939e6f602fa261ecb437ea", .Okay}, + {.Sqrt, "277ad6853c6dc86036f600012694ea62aa798764af243ce96cb56c0b7475a37508d4c6089ac2662485b751892c9b3968980b750ab93769185659c161eb6bccd9b0124c5e7d7e07dd88e1e11e6fc57ebf4ede2f55872f0a388677b834c07876b670fbbe8556e785769c90d96c072bbcaecbade54f46703a59e825848951815d80b7f00e2ea2cfb6a0fef79752cf4a32dce265da7720bb", "0", "648863a7ef9e8d55a5c251471b61244b040d31f9b650aac929900d015c50dad04a271289b8b45337373985be6d692fac8ca2ec17556c17c14548adf7acb1751ab8c11cc7bd22a32a76d33e", .Okay}, + {.Sqrt, "1e3dfc55b87ddbcfa0308658b8b8b2c7436fae4813d7e2df53d61e8efc6ca5f1ed77fd1fbc60ab58d1fcce92a3fd7f28a901080d1e58a01c6b1073690b6765049c03ca410a5ebb5eea29d1366001deab057fbad34856e26611635e4ea15473293ed9e5e3fc067713245cc2d5bc63a5bbe1f647295c6d42883e629a52981be1afdff14eead64dc557b5b8b28fe49dd80526595d30724e", "0", "57fd11e48f6a478db1f805ea968324269072b10ef40a9fa71fea294717be2a8de5b9698524363067c46e669e6d99578ed7bcf2919a089426e538d7e7c34f9c39d19a2c5a0a951b7744ed6a", .Okay}, + {.Sqrt, "2764b7de009e85f790e9284707ad2aaba325ee9d70055a6e3ec4630c17b435153e40daff30d2f1e3becc87f831b7ee2fa14d52a88c148d94338dd492ddbe10c8d3e6a68a5f8b1a97218eeda3f1474abe57919e90e3213a00c4e0435c56506abd7a3b761f8ec099813a2f30498df1feaf0312af2cbc2d8b69d158939c68b1345e7ee211dd0153fe8e3b6b36e1a0ae3471ac67125a3169", "0", "646c35ec1c372b7ae1c9956c49350a00da374a110910a0579d0203a67537ff3d7e8a1128c21428d254c7a01c1553dd929668953ce1c08548ed5919eb2d57de8a880a831e6bccd5254c383b", .Okay}, + {.Sqrt, "527414d68c36e26aeb76bce014df88b0fd12f44dc88b097f8088b1471098c2262299f9cf1a3c4254ca3728e46dd9c32eae7838312c519c3ddb8ae80428cc9809f525d4f3ec2f01ecd0ee82f26a1d691487abafea1317257ecf10bb1d26895e07b06a67c3921c0fe6bc4825d36471fe58a8810323f79448eb89b8263b30b9005886be5b9eeaeed29f9fb153410a5ae306d0a633759b8f", "0", "914944bd26bcb2b9d76e10dc7481c95c8942aecf8a0060219c5db4c10858c611fb69a482e2d48397f3b2cd66c1de462a4479aa6a7c16ee92d8d1a7739977c33e13615a804b0d1baf219439", .Okay}, + {.Sqrt, "6a2b237f17adb53c8eb222d3e879fb7627408a6a6af4c64a46c3f29e5200c946185727ea4f5ba7de813633bb9ef63521f53a43eba66c1a57356111db05383dfd3f25268152d74bf379a0dd09771d87147b3920e3d868fed38e4b31c564a5769938f43b70062bfe983fe2f63005b5b7bf1f006845539eeb9ffb015f073fdffb1f7d7e516a468d1be55d1c62468738df2f351a241497ef", "0", "a4dc686069b00ff592b5873bc09598c8bd2c51fceb351e3b6c14df3dcdd3d321ba515657eea045f11652bce4f3201b55eef50c2e99f860b82d44fba2cb018d65f338bb6017321977605d65", .Okay}, + {.Sqrt, "702f9f744f2b6012fa08ba0694e4384d3098285b71b873580a9b4307d944b522d16f7e0b52c156d3c842a84674204c7302fa43e0854120ac5b775dacafac410fb26698d6cc22721490aa066c3c68d18de67d535d877b900e9c90b3c302b41672be6094b6832dc907a4ef1e69644d7dc6e02f6f4d647c6a6cf0329b2cfc42db564b33cfbca060c883c4b69eb327a7b663fbc6afa7ca31", "0", "a977f95b4b4ab87d575da69e1ebbaedfe8396f4e1339516c69a9b916e47245be67d210ca873cd8df582a010f33260b7bada0da68d4ab13377226c83c531e44943ab9eddb05c86dc3c586ac", .Okay}, + {.Sqrt, "d400f6a59c06d809b88fb6560ae6b2380343cfd271f96660121a13e675fe5e06af1bd3ae4e582c3b39b5df3a937cdf77f1a88fbf62a0a4a0eab67b5080d74bdb6cd33ca573695ec3e405175c7203cf8f85b022d101d329aefdf7968681c11be2d8e689a3dc56327ff61ece2a79f98eb82e958bf69d1826cbea56b05ba26fc7678827fd84705ed7d941b6da0694dea16de5b1f587ce1e", "0", "e8f730883b8d8c2c970243e884e3b5a020631879284dced8928854b57a7a87be342b64e765753306a0d3a7c910ac4a45896ec424591f69ec326aa41859d9342ee85a7279ef738d21dc240c", .Okay}, + {.Sqrt, "e5b13a33af06517d4e3617c1d11d2ea16fce6558165bbf412731fa3d014ab9789fe60f6d792cd47a8303b978798a3f139be555c64e5e445e450d24828272080ae6d02100d46dfcf61a01e5584d3d4506932bbf493f961c3d639455ae9c8f3344201c5dd721578a9548e408b1f7a4e49ab75584ec06d54c0a612098011158341857cb076846e24ceef8304686aae491b0e7ebada7ccdc", "0", "f27d594bd37ab3eb355355bad14c010da1efab7e6ab917928184eeffcea12ae2aac9c9e1ec33dd6894d694fd5c33408d0b01a114c0725d9051843c3fcf487dc9a5a9263336d0f18b3716ca", .Okay}, + {.Sqrt, "17e4cb0a52c3fa4bd6c11b054860940a4aaa9768b8a7665f7f60e8b250f7769bcae96257e2d4591e75f10f4c027e2ff8c222f82fcbccfc7af8a0212547e0c8b476395e309b4e066ba6293d25392ce0b1a66dc407529405d505203eb6e2a81fd74e50288d08808510afdb3c3dab6f9176c9e4e9e188e76a4978cf5ae5e9e28270aa53be8360dd238b653c984db64b0ade78011c3378ab", "0", "4e35bdf6584b1357408af4cf60d933b20012a35251c614a38e5b2630cc2e7ef2c4cda92d8ab1cc7f64555c1cee057daa58ff89e74c5278edc136d2ae5ec868c2590472c554da02d583a2b1", .Okay}, + {.Sqrt, "f1fc06cd0319eea092fa61657f8d644cf9cb5536981e61ffd3e77f646d74c8c4a638883704aa10a4324ae504eb185d003cdd719d3ea3a6ffb3e8856990caa3d471312f05df37328bae55d006b460acb6c1ba1b863ec5f0b46b795376010761a4c8ee18ac5e711166a4aafea6492f12fefd45c02f8f4b7b5486c6c66121e7d77872ea46fa1a733fd222b3e7f1de444e9428613aa1eee", "0", "3e3930d2a761e17ba01b451a4719cc7b0affea5dabaa1ac854f433fffa9d363dcfe6e5536b42523bf0c579fc3c82b0790145c04ab3e66f13d697ad06fed47cf4fa8b6df83b1d2dbdb89e40", .Okay}, + {.Sqrt, "2125149018a324a327ad63c64a5207604c98632c10eb6b3e9038130fae8f7186ab24a7f68cd64fbf44c94a8118c05d944bed44666470e5d1c4a68274e000f719c0bde27a6ec5298af47a39a1734a0e07b5241a89fd95ed961030043290f235bd7a45d37d4bad8bd8a8ab361f4557fc4c7a504835a775dcbd6ba88a6c8e1c56f136e145193505d125ec191f4e6b30fb31fce87c8d7bb8", "0", "5c1d4f979b30c8604922a5ed7a0e0b8e23bfd17d742c12d5af5acd94da5bd36fc0c2f738b2649f1042f1b5bad86d0b6d8f1c09dcb50c9414021ecf9cfd1138ba0a186f11490af6622079ae", .Okay}, + {.Sqrt, "83adb0e0c38794dffea03c4f944e77c417281332a4f66b7e5046b158d4c33782a0a5880eeeb9c209504112037853efa75e0d8da6560ae95e49148e2a6d037db140a98399488f8975e058eed2f8fa962887dce33f2d2af99e12507f6b20ad7e85bc9903753288985d95345526e5909a076a40e3774717170d35f5f64c4cbf5478c784b59418abf26c5aa7e9d327b031281e497178d0ef", "0", "b79a1c0d4a77a937a9d839132edab0537163a42955927ea76276caaf5d88e8912ef1e0e06dfc1eff4ebc18ce68bb2b4eece6e0ed7fb2d001080c97a979a0473951f0bd785def745df97bda", .Okay}, + {.Sqrt, "430946d33d8ceb639ef85756f374d90510269ef17cf93b9c9ef4929b243f5e849a265af459b4af6ae00a3632f3e0cc3884cd976e4746cf41cf8dd7d8d6321e9d965c6a860d244da3da92de5ff3abbd53d4190dfb1fd10a30d2e056c74bd4d49aab0f3792c2a2ffb6d9ed58aa03d50fe30e1ec310174d2e1ca5e33a6ab8913eb0908d513609d53d8b7160d62c88c8f838fb90c635427b", "0", "83004533f32501bc7981bbb318d6124c063e5445fcccfd2e9fab493599e6c8af44b2386ca03a00a1e70f84fe4d2e532d9a7fdf6db396e873e1abae17cbd984c615cf52431046075dcdf3c1", .Okay}, + {.Sqrt, "708b2c50f578cb031eb7555ba493e35c8b13378c214ea8f2c939d33e1ab1d4fa35a25051daf331b09ccc138f2221b11ba9a567deb573dd882cdefa8322eee615aae107b46db164fdb3118d052c961f859b93245c418f879f7e5538d25daa374109f1afb0bfc5b8ea31767a0ef54362dfa724251501f07a1762c0d1e7652dcca939a83f1cf8824109e0a863559d72e3dd0a408ed08f49", "0", "a9bd112de3a4c2db6a6ac105d18905189a1054b3a0ccd9bb22b83e88b4048d95cac4516a7f841e5317c1c77e5ec25ec9c566b15121f5d4c9fc7a18d71efff0049bbcf4f50a4342d881fbd4", .Okay}, + {.Sqrt, "a0fbe14248f779706d06ad49a4b1c1b50a88a2237ece47d34e997e7128a974aae3b6279ae5d70a2ab63e08a91307c0f674816a17bba361cbc39c130a85faf2c24ec902731557bfae9b946ac5064ae3402e1381f276be4071a80545721d2746733950cfba6fb1ae81e3040c27164558408cc5aa686f790ca5e5af6c9ceeddeeb5e65d8885c22c8b90f4c6942c2fecec60eeff8f019e13", "0", "cb01d0dd4ff8bac700f6c30025690c2a0a86b07efdeae9bb93bc1400045bcd9dbfe5e174984c7758a3516c85f2ccfa83051e875dc1568fc06b1fafe0d2b35550c933c14ac79be92330b4fd", .Okay}, + {.Sqrt, "34caf5fa616aa55dcdce038934bacbc35d29526bf2b7d7a26ad1177ddf7a9ef38639479977979961c682cec38305ef6b40bf76c4838f1f164b2092074f98d963c6649cf2419defd53ef86f46e73549aea175220671086191935a074445f9eb741499c7d0d3581bdf78958f25f22758a7ef2de83646c18bbca004f68c4d7c4b9dc0229cf9a454969d24f589c52d70777d5882e432f65", "0", "1d103f4e0303873b14e42d005b9388860f50dcaeea33f63ae0af980619178b2f1035e734491606c824849b6fcc76c85ba1cbb0dfd50d9d9a370b4f0c1ac3bc90abdde681c52b04232ec7df", .Okay}, + {.Sqrt, "78f75f8dd5b885055ae705402b8e6642b5b7138f1dee2cb1444bda53cc3e38f39bd9e45f815f78061b7bdd606bf377692b31c55709ea8f560a65de71e030f6d163e6b8b094ee1df7eebc03ae7107ee882a36d2868a422fc0c65f2ba8c88a1a1296535c3752d8193ac9d4c09bd816b7bfb18451a9488f8909cd95aa8cfee95de05b87ab68fd1bd27b2e3d66c2376d1cb6d141a3c0587d", "0", "aff9b9bee276e15dc28cbb401b0cba34879bf324f06567bd2ab60ec7edb1103ae740340f3a80c51a3359c913d120831b4c96a5ab413ee7ef5083e544bed0bd4caff7e54ee1decd33ade3e2", .Okay}, + {.Sqrt, "9948fc1d7480a16ecae542535dcf45d348303653998516b92715c061939c0958cb0c270b524dcae24af51aea63c132483dcca0644fa03d25accfdc581dfa0b29c486b73311411a793bdcc658fe2de0fff537b5f6afec0e03776a4632d6ee876b0a4a5a7fd26f449b64fe3a3272e817c0017daa6783880f640dc50d5d2c3f59acef3a9c8bd70e4444ff14455d50151feb04b7279cacf1", "0", "c617e75bd737016cf76888a3f654115d8b7026dbfe2abcb70746d608469e2b609389c0a1ca8db4676c29702344a74716fce9f4155c5559a4cdb0810da57cb64320711ab8862d422e7379a0", .Okay}, + {.Sqrt, "ca99bc83948bf7bb1f99c109d5d0122afa40fc5e247b2a48095ef08bf6e1501297cfb9ba973e4a2cc2e19fab4957f298a2c592e1459f9d3e92b3f6a1262357af72421e27c31bcd3eec945014c53526569b67c8e26f55a3aa95a9bbac87135d65e3a5de3cd57a43fafd88bd94694d527c9394ea8875f6031e1470a893b7acf90c4d6f9244b8ddf8b752a011359b9f83112b48156f6bd2", "0", "e3bd918ed9039c1cca05f0a48db0d20609b09a053d67538c2563291c895fe792faee3ce1b3aac486a35d76c4ec087295594a6b9860566b26a7c5f5cad7f72d839704f51ae24c98a9af46fd", .Okay}, + {.Sqrt, "e3b89f1c71d0bbae5d1cdaa0906a528ec6e63bf60dc71e5abae6f4d38b1a2f4a417dd474b67a9f4fe40a5b7c5abbc532f0aa22c9e1271999168c15165bd473fbb020dbc67ec88f22ba6a431bbba173ed52ec1449faf4d082378414d2a9e5b6a676d591ab82ced7eeb2b3799980b027c710ddd4df7d7ed4cdcf7b7f7190aae60cdfca065c615cd3ff973fd1f349e9d1cff8dd2369dd72", "0", "f1726a3600e0c31fe8c7b6466b400d37ead97d112421c358859294865832d48d8533a2d1ba492274e45735c81dfd33a9e8f9a2d51bba9a7afadc17f544f2af3c7e4dfc8a53f1d77025381d", .Okay}, + {.Sqrt, "bfe829299a9f4ce1081f5d7887d699b8886f50e48cf904cc7020c545028019b65fab3d18d38003e5549bf1574ad28dfa5b5e1df9c71bdfd86b42f31da63a6b47ca5e55f0f1c948c60afd0c0968111f43ba7f8bec3cdcf551229acd5b7d11306d852cb69ccfcc985dcdc1b809b69c6de2e857b1b79e2eefb5ad334ffe216fedf05f059c849e74472b20377bf1d0e4af141d2a0df28a0b", "0", "dda6135bcbefd20e2165034889b561efdba7e2bc5cc30851227d8f268c9e4d7a058bdbdef9b8987f0d9238ea57e1fb96ee07ab3c63826d6c697487bd8df84b30c1eafee63c3cddcd77517d", .Okay}, + {.Sqrt, "680b9ef3fb575d5fc86e0a5198315dd53640daa649de38d827b4fdd196216692ab757267a9593219f1b3dbc587eeb25e14d2302016d4446917e2f147114aede7b7a744093d37b04e5fa1dc948fcff38a47c5de8f0d61bcdadbe3390b5ba5d906e9f9c960cbd0bdc4e845f7e6c7673a978b8e54edff58e3c04e38cd7ecd774803f7c3a332170dd14d1908b67ed49da663ad4c00ebff16", "0", "a334487627ea624abffb651a51a912a6c63ac2302db37f9ef2e053f60bfaa6cb7267748270e4916260e7318e1852256550642816425abce0407109702fa6a9b4642c8024a14ce350fb890e", .Okay}, + {.Sqrt, "beebf941567d27c10dfc492594115cd15a250f66ffdb7bf710bef9dc1f0c6e1e15ba30781226c8457e40c867d25f52225ac418d7ff5c9520b8e173d6faa1ee28a572e0b5a21e27270f40930d594ef00052eadc297dff5954db07c401727a2ba0ec4564ca3a108e78d8f577369fcc2a69da28ec3c66e9423d75ddd45740f70b2b96eb3ba085f16f0f893a07c545359ad9afd862865ddd", "0", "dd1440aaf5403cc562becdd32eb20c5ac05be5e92c34faf6500d7aa817663c84abeecf9272ef7f355e432a6b003976c5c925d443ee5d0126bfb2fd206d2c191e902f8d338c9ae57456d831", .Okay}, + {.Sqrt, "d616f383ad5a535bd3bf55f467fd47ab8307e9fc518bd82fbbea882157ccd94b1705d4621af80b131e59d1e864d72f403fd4354442f58af1ecdc0620cab7e2d975435f5d5ef15e6c9db64cbd7971dc0a5c6c0a17fdc702569adfc02910b37477b74a5d85530f077a5ac721b1707645899afa70a6d4b7c88a37fb611586bc194534ce3c3c0991c5ba9b12386efe15165fc5dd15dce68d", "0", "ea1bdd413c5f1eded5d3bde25a8c0915ac3d6c0d234f5ce497f83a9e43727111350b14d2986c14d21800a6efa92267188e39b73cb8e1dd7b185d3f7fb5c4775da7608a507f50d0d0d13632", .Okay}, + {.Sqrt, "c34c312fd7e87b68e0e5a105cf97601872b36ce14c379bcd9f7b9b3e274ba97be588aeb98f3fd41dec1bac1c1992b41bec2fb7f26bb973af054629cb5deb74ddff21d74d5520051bc7644de431ca45da3b7ae304929b49e37f27bae281137cf7662a665f8387e851084b656c8616ed875b6922909ccb799278fa5164a0ab0487e59bd48c7b34c0be27c9e52ed83fabbda1d298eb70b2", "0", "df99291235b2c627b2d68a3a9d8767fcb87c31dee96fbc5a08737ac4867e119688238ac0f437ac99df0aa7dc313c7f6a055412ac931ae668809ac9190b03a468a741e26d8930c9117cda1a", .Okay}, + {.Sqrt, "b8552883e976498bffa62b6b69a5bfaf1ed9eca20e53f5795b7b66f22cb75d350d2666ef41eef3f6d0f757fd4eab1950419c60671eaaf66f7ec5fcc72e64a87dd0b108299b8033d10f3bda67e5a31f4de15edaa87bf945d70308b5fd2f9dafa7cdb7ab9fb01b2a9f85afeb315a4a2ba8a2038afd4898126a7a4e9673c25354fc3a59856db799f3e9e7d201e41d71c0af3750890b7119", "0", "d93b0c534e2399c762263a30a2f7e745f84c582086fb17a53a3c8b17a0b606810560f9dac881e616109ac8b60f008ec8a58d7c0aad0f82a1249a6c40fdb4bd7db00f2abac5f23394f315ab", .Okay}, + {.Sqrt, "4136c41b1f8b1fd7bec1ec53e2d4f20172ecdb1e41871b22c044716575a58326e06fe6b9ca58914ab92cdd7e3ea3b7e6eca9c7128f7b47d995463324b4d4517dff931e65f1559d011e43e566434b25ac3b4ac49c1f1cbc6293b98c27e473233dcb2363052f979d1c48b060bc4a28c43e075de1806e77ec1fe2b1245e49db21ca1d5b6a7913058a65bc19635fa50687a8721d43f12ab5", "0", "81354e64c83e2818072190722be91ae203471a8e3671345a469465420acd9713fa33753fe8e0066462f4be9f7db2d36dd51b357cb2555e9d8564f1abbe27a111aa7df34f8c01ff7cb1ff18", .Okay}, + {.Sqrt, "292e09aa83f8fb4e028bb28800d45df43c63856eca6ea88f8ceb2f4b290789c25b7eb1dd55b83ecc276f13f3b599fd899874f0b46cfc96d649a33084ea2891c1a5d6ff1c763a609890f972a73dbaad2b408845e4a10b5184b6c617cda5593e147e2085cfdb9f2b437621d1c55cc3624aa4ad739e2b3ed967eee3aa2e5d80f68e67be2c776f20e41d3d0cbfaa5ec8225b37ada358fb76", "0", "66aca72efa8f048571d20b6ab4338682e70725da29fbbf9ff02cc895c4b8b503ddbba30be6b330567b3ca45e096616f0c4d74e74aa336b1f8f9638de058f9e97dd4282fc203fe44134ed78", .Okay}, + {.Sqrt, "cb042997e1d1ed45af2f7b5151bf7de701d3634585696a7df7a883fd9f24edfcd95e70a33d0a510a4e9c85e69bea3656895f5b3d45ef9f400a6a382d5edf0375551402084e94f747c6f98aa150123135272bace032bccbeb01c6e93cd36bf5d210ea45d74f5696d6ebe30f2116a891e7b2ee88a7c456e8c27fe594b8fc1360e88f78b3c8c11cb9ea18c5ce1f84d7cfc52dcde58aea64", "0", "e3f95a9f46fd6f397011ad25730fe839846f768ed31fac0b06c2bc15b421069547ef83dba6dca9d46332bb1509091241349638657013d0a2389c07dc79e008de615ab7e2b8cfce0135cdd9", .Okay}, + {.Sqrt, "2cea1fa57cb49200a0329dd3dc16003f6fdb9329ba08e4579ca7c7a135d9a0e708090b9f5db857d3dc0032b229c33d08974c6b12a9b858a91dc9319e8e6a798a78012a9768f93d5a10131e5c0185a2e1f782b0f5d16a25b451375b1bc212d4f0d38fe0c6df9b54a65dc39a7e4a498d0cde8d54e058be981d7daa74bab4b01aba2c4577372f94f7c8fda4f2589f496ce93ed78a112282", "0", "6b3ab3a95f8bf05965dd3e75c084dcbc4804c6e06d34ec637b550663dad769daa301fc4881959b18aa478d719fdddf649ffcd3495346ea64b5c3feda0173ecb7980a50cd01adb6fab41bf3", .Okay}, + {.Sqrt, "d2be3ef72fdd26d8b81bf32c2060b2a10078c8e5249510bd282ab3d1b8e65f40fc2cc1192a5c918028eacd16f43cbc71ecdc7ce0ab705fe4764b74d98d67ee141231abc263418c37cd3da05726e9a80d651ed52c1dd9ded358bfaf798f3cf4faacf2ab3130af54dd66f37ca8c9432c86d958ffc0c19c69c717bd14272f772858c556d28510057e7e216b65a385acae8d3576a79e9a46", "0", "e8459cb5b3da9e40a2b3fe0abb0b87e54b17f74ae6a691c592dca6cd17cd27841cde1cfe4bb1e9c5ab344929c1b99c66a54dae519dd0a5b96385ae29f713dea572193e58db0db83d5cbf25", .Okay}, + {.Sqrt, "141f9d6ccfcabe3dd9ff33ef6f322240a8e40ce2ee2940dfe7cc858ac4773fa834066d11c7a02697b6978f42b1870e72165298dc08f3dbbb65ab1ec568c834e6218d46702452d957d1d4612edae4862487e1e141606a39ce3979135727c8f660c34fcd36eb0a81658e209d8fe4b84aa512d0b64bae9da1bec8717f578a8d61855fd1322c8dadb8ec43863c653153691aed75e4a6e0d9", "0", "47c6561bf0de6759e3192885668a873e0a2db94fbffd77c20592a9650e42eea0ebd6c351c3a5d77185aac5b30cb0c449458fd55f0bf3e667a771e28a37f640fc9000b2c872e65064d2124b", .Okay}, + {.Sqrt, "200f137c56911a0ea8f1daf813ae02d4875c2261649b788a10a2dc43851c79b2a282e843f59973a26a19031c436cdeaa14dc2b1c5a7ef01a163faf03d8d623100e23ba2b22a67e2cfd823c78db0b21373f65899abf60aef9e1b15db488815dfa8c50ffe40ccb95d24e76a776912d0749f36384531844484fe5d5ba535ced9fb4190e262c1080cd28c16b569a3de62b111da0871db596", "0", "5a97c93ac898524e07bf5609bd60d3154c0edddbadbfa86ac0456a95d80b9a26ea3798a55f9a7ee7da8d1ea88a6f73468a719d90985d1a6136f86842df81c93ca1d4b6f53279393521839a", .Okay}, + {.Sqrt, "32be06e8cba7f67df093ec3162c0aaef4859bb6ab5ddf47bbd42718ecab364c5276dc24008eaa036363e70886ca8ded6a120f663a9a745c7ff656053bc04806455b13d19db72b57387a43a0e906beb35c1cf2ee2348f450bc4b935f97c0ffeccade12f12c9b249e3898dbddaa9dfa7311601873946ff58dc28529e579e76dc17d2713758e7082ecea2f5ef75b4815d4b94c381a46db7", "0", "71f94aedd1a9a144494df92d591bf35fc7c84db5239899185a1f362449574acdc8de6ebc888ad906290c9c8f0a90376f6c728a5b85d83486baeec85eb833f6d45860b0763027f5f0ad8a5a", .Okay}, + {.Sqrt, "d9b3766faea3d60b99bb16bf768c61a9800cf5efa085e98a8dc702fee1209fc3b968cdaf5a7e2632bb369f92d55f956a9240c940653e246e39e6ec1d3e12f0cac4fbf6559e1457670223103c5532fef90db664995c37456a0921cb9655e0932eb0a708cad4199844ef4498cd7140f6d330a5fb0e1ee220b729cf72a9b8e32d5530d342e23acfd204720df1c549a74fcfe5205a796a57", "0", "ec133b1d3581da74269ce8b0bddb2cd0bdaa088c938f5c9ae09761a1431829bda955f1af9ad4f610deb9276c56da68ca6388db6379158c8f1c3d040f1407bff8325a9591af2c8cc9afd52e", .Okay}, + {.Sqrt, "83a4c661bd761b54661ac8c282c4b284a2a98958644644bcde585b1c66bae906af19268dafd0b0ce77fab9ab149c0c69f36bf28b785654a75523bd8bc7398bc3524feb7b5e82a5e4f35c3265972db7bf3aa686bf59dec2ce0e9925a54ead22232b572ed3cd969b55edf5dd623447292b7c246e3f252cc44b215bb83f76d24565d8995ef45d815819c86438c27d3f9c9677c3371dc75a", "0", "b793e4ae628ff75ac22f1721cecc700eaa15e305e1d3ffca784df2fe7f136700d2693b979bcdceb1b5ff46655bc4aff833a99456e7bb15657269a5a790a4b4b8b4f1a9f876668adecb7e78", .Okay}, + {.Sqrt, "1947f1ad27d7c6d854e22181b7750ca60891000e5bfaa566605268f0bbe63d4ef576e68dec4017c354f4fdd85d26f5f330bf9c3d08023792f2f34312a8be906431f4fe4108a19e1f39b8276fb70dde20fe1b89ab59f0a2c57ecb95c08a389c69f5d9ba2eaad2f6e0267c9fc265218bbbd8fbf02c4a02e3eb8c78e726a3ae4f514bb457a0fff1914fa3e388606739100e90d370c2bedd", "0", "5072c9ede77d0e316925e71c3a4700cc59cfdd64e35213f761d06bf1188efcf41ec2b6b6515d6e57efb91bdaa17cb81468e34e64d81bd57a779c290d4363e05abd3c3998b8b5f3adf61739", .Okay}, + {.Sqrt, "5b94306e1f3db7800ad3cfdb340e7b3a88ad26941540de141188fd3cea5e3356eda1b10ebbcc702fa90412af022a70588d1bb3fe227d9948f0608e1edd446f097f312400f38481c6cb67b8115fb79e5367a535970e0f423122cf889ec770fb82dee8338490c67feed2c9d2d6ffb1ea13f638f74f53a155c146e7760ee067ac588ce655202b9494cc90db6e5d76cdba7463777aaed933", "0", "991d6da2624cc4eed7eec1ec26fdea29f56366af1f43331f64d053941d0b5cc224b42981ccc17de5b6c58e9f6a64dfab8829979037a6c28f851561c26080f63232a6d75439cbae50eab93f", .Okay}, + {.Sqrt, "d4fad1b8e7f4d3d468eead3eabc0f9a93848c9d645a69347d22180e37bd059759ca7df506c9e5fcc10a6e36053f5a4d6f89558c263875b51d7a9ff777fe3dccd755fd80091e28deb20b5ec5e7e1048ff699aef763fa78cd42645137ad7091be4cae252f6e7d188b6c4c2ed812cacee714bcbeef86a246623ba0c9f93d0caf72b778b3ad32f3c9aab0ccd480b39af2ddf10fd222a7fa9", "0", "e9804fe1bec87b593894541612cd13d9ea75b22ce287a7eb856d2b4de476fe70eb681bb91578698d8c1bda644ce1059e7c01e7e1c751a9b8b92c7fcce40619e0a409116b0a9db243108c54", .Okay}, + {.Sqrt, "1078cc99cf195615a0098d8a1c4466fb8a3de7cd8bdf60592c312299417bb00f092977107ae9abcbdfcc7658cb309fee24096647f02541c0abc73c264fc7493412cc08cf9e2c7a86b5a86ebaf1eb0aebeb42a919c5ebebf1d3bfa6a17948de5af1c031836bbfb87efbf5bd264ef187907d406453c7e7635b03ed85d1a7b92728573e251630717fe1c52e00e1661909c93372a2c78530", "0", "40efd7ca5abcca6e6f6e7c75621ba41c6d44d32e7beb54212d667f1a6eeeb643dd4c720e78d87667ca96f92b72bbf07ea3e1c64131ce201bf50a3e4c8cd9c084f56a29d7a14c3cd2fa60f6", .Okay}, + {.Sqrt, "a6e9de94d12ffff4c7b96987e038cfb653871ee2fb0774901e5e203c0f4d09606f11fc8fcad26e28586dd4720e9c6a90f2426837336b8cc32b7b174524bec012bb7dabc89ef45594b84a402b4de0980763e048b2d526afd86b3505a72c21d31ed61d94aa2416f0496317412dfe0a390dd6d8604212f508cdb0b80602cca554392953e63300cfd8918854a5a862844a2f3ea25cf06770", "0", "ceb648911f3caa2a708bce269bcb3515ea75be583d477078ac61fb3e942aba744841c024e4f461846bf3b4400ee89eaf064ccfcb3546f60c493462d213dda7875b818c6c8382248dd65652", .Okay}, + {.Sqrt, "80a9926ba1cb692592217df87c22b19120d42863fc0e033af6b5c8881013a8b28a15824db1f75d2f362368de7bbfecb09162bab1e3e834be0a099890957ffda84613dffebd9f05441eee43256a4b9ae9acf814bcfe628a148d7eaf4b519a4b6bb8fa17b7fce214b5609eb1c7e4bc1ed63ee1caf93cac388a17ff76890da10c29a0beab2cf7a9c4764058003d7e5bef05b4aafb6f1089", "0", "b57cb3656016351f2eb51468b65a557756dd25338ba0eccbc8d95f434e73a8a0a9e14222e3e7165a45406da9f693260c8e6c54c62e49d3f31674babac342a8f5a5b0a7cedb25bd262f0bc0", .Okay}, + {.Sqrt, "1dac0a4ed6e93c3d2825c86c71339a98f1239190f572ebc461c3baeac651de5eae0f47492d66cda461f8040ef55ce183477260abac29b511768f315661550480e59ccf13bf949c8ce06fead4ae2bd5b38f24966f6120fbbe7a6b985bcddd0ac59e0bd3f462053b81a66dacc7ae1c2501d6e34b20770c14b22dae6b449b5bb0779eb656f57882f2a054f0fa0c6ccef33208b3968b2f55", "0", "5727bf7716b29cc3535846a17f64addf204387565887f44bc9da51e3d1e4245664ee00522ebae52b6595d95d5b9a951bf7b3c9575e4e85bb2c09df6c9066531c5c483ddb44cf1b6a6c494d", .Okay}, + {.Sqrt, "3e70371db7dcae99de7a0fd53838d711d8381153396c86da6d91999e2abf41e3344b2cdd9ce9043c6375077de705440cc0037a97c3e17816c866b05d75513e259c0a13e49287a3922f6966f3da94bfd4644ddf1cca8ed78b84f85d2209da0106b393df923e79527c89f93cf4550bbca67eb20839318cdd43dc2e7fd4a848427c8e914426f6f65c698b776fbba6f25d10734bfa5b6ecc", "0", "7e6dbf0dae5a33b2de95f59a9260ff5d63c080a64611f6cc4cad7ee583b4dd502d694c946476f17377387d3a9273e2a16f18db37ade3b608150fb357f1d0a1bd45e4dc302db5a28672ad37", .Okay}, + {.Sqrt, "31b4801768119867e07778a719ca7453487f5ac6c2dd63843302e6426dd8cb92810d651a945e570b3feab31c83ef497073dcd8332af60b0fbfabd65ec725227a28d707850ff0c276e6356e8d871d1e6d92aae6d3d14fd668d8826c55890a40e7a7c10ce490dd2339797b8cdb913b8b57453ae717c16469168a4ca08c12685fea85f584ee3df204adf1315194271c6b3abbe27e228054", "0", "70cd8ca1011865927271334593b4a962bec17849fbfcafa20c8410163612a146f56d61391959558af02dfd1cc4aef8870afd1dd63fa74c42c9728f55b2c7d726a3ba9ed25a54e10bce23ed", .Okay}, + {.Sqrt, "da623335d8db2a7dbfb0bc6ae96e7467e72c9c556e6438cd96a54b68f804765bbe789629f129ebe951c6d86a625431a30eb8c77612389a8e7c6f0a6dc1b454dfb113d26b403b646be0ee26dd95e73ded4e4f4320071d2a59428876e9086978bd96a3df4dd2fc3a9aa9802527bf961d500f7d0b5ba1897ccbea2afcfb9c190404545ac71a3b1ffad75929bddf27d8d896f4cb4b702f7e", "0", "ec71e6417ff6799aba48b158c63ef772a14d11fbfa5c2149ecc2e219bf87fbb3fa27eadf48fd3d30fb44fe3a0be8db2352380cd3335b35705c875ad62f505b3f035c1682716480879871c9", .Okay}, + {.Sqrt, "a65cc56bc1041a35516d4a15e52c5634af2424346fad82f167293cec0ba0340fcc143d9b54a8b1d86c1278bc6220404764c48f044d1c45851e8c94d8d7c5611518bda08ac28150ad4eb5eafbe1758538f3d9f4bbba94f180b6dbcf078b3da13d3abf6c942d40248ce6d5802abda98d71ea9e5d32b593b56c6e6b69cf0ef01a5b02d25dff0e7f7adb47ebb428b7ab3a9af297cbce4202", "0", "ce5ed72ae51322ea9adc758dff0acf9aa1928935f5dd424cbe92f9575373ccd42b1331f40443fb24460962ee26115f138c761e1f9ceee2fcf11bd95c8112e244ec0a951cd5e5ba34f73c68", .Okay}, + {.Sqrt, "dbd7e8b768401744414eef186b9db2c3bd63c52a7e0de9a77904db6107b587367d4835606bf1273ba09264f8bb6a55db29371696d9480edea159d57f7ca3aed9eee6b4cd3191b1a84a785b08d94f22fef59eb53cf054aee37c1724ab3d5fe2d525ea075756a55ee3b65596cb39dd666538b3fab5974f6bc0fbd911f7cabc6d749e207a49641f62a15550ef77ed726eba3dcf1e0fda1a", "0", "ed3bdee690af5de31ebb1571548623171bf57cc0adfe82146624996fa5bf477d8c08e5476554903439b37e90f41045265dda2f741746c1c36b00f365978cb5c59c3a1d99f9a803ef751bcc", .Okay}, + {.Sqrt, "bcfe7aa47d73a7960cf0809368587406ef51e27a31b74aa23c63eb07bbc70ddf17495e9606b73eefaeaa066db3ce49058f4c576a7b45816f0e0fe16e018a68d02d3ce5b806f766475853784373e9bba3e3d1dbc9cfaa0294d31f58cae9589e6cb85bd7d75cedaf9c523c86cc61b22c884fd22931d91fe37034a1f4e30629dc39597d671d70ab37e17fd37e26ea5d490ae8a6829513bb", "0", "dbf5ce19ec12be0bc9bd334086d6f7bb50235da6d69a956f178536b90f589859c6315e97dbca50db883badd164d1cdbe1eff025186c766558f5ff0741669c690b77f68619c65a58f2e1bb0", .Okay}, + {.Sqrt, "3b3f60bd69312dfa72f044549db4fac9b8537e9525069a558580496b67d6dc0498d684dfaea5003f5da8024c55169e64d774bf41b1014e0aa11e675b3f65b802a39daff3ef61506616d18ff3b7fbd5e2b9e7fb645b89a9680b4103e954fa634be9d8d7e8b8c95d0cc05d76270a6652ca3bbef8d9e7fc5e32a8808176cc323546822f36c9eb77f43fc8074b5b44deae2bf63d03e034d", "0", "1ec9fa693500d05f4849214fede26b97fe7b4eec5d481f5c7fa8ae7528c6b3b6b949a50f08174b9860e7a03930b34bbd30e5aacbdb6224b4b46b3bd46625748cb8dde284b463f1b33ecaa4", .Okay}, + {.Sqrt, "1a7564e991afdd6fde8fb0ef0ec2b862b39b5383d0c89f8f6de14ae1df92406e81cbd9e98f4248fd6a775a520a1b06ea3db87731b98ff91960a06622799e88d9599e9077294747de28f440f8682d6d14d37169a60aea437848b5edbabed4d979d4cc0b3cc54905366bcfe0ff75867c19a16ee92b6a89a00deabe1f3b257bcf960f34b110efd33a0121f1ac2e1f0cb75d4c1be8e1e3eb", "0", "524cf64873194c080f1a1dc0d23a5ad5a3557ac5aeece53290e3149eb40d8a4c28c1d1fa1317bfed54c742845d8f03f7d1f1912f485290a616b5e5c01e92aeec401c037b58abf6c8fbbbb5", .Okay}, + {.Sqrt, "eb01cef6d95b46404c4a0cff1091b1aeff0e7325e1ed991ddff5c62dc957557a26d3b4ebe30662fffa5433d641b2cacc9e81c2435ce1cff40d7aec4aa5fc8c0ac6e727b704c33e7986723913045e3e8cbe03cbcfe7b38e82697a0a4a13a9b04ffa28610e19e399589265e968ed9724bdb31981440ff74fbe053bb68daeeb020dc9f0974ca5c5e615fc0c20050d72741341b0425bb623", "0", "f5476f4c3cf5afc10bb49db59ff529c22d2be1afed8ab7e606c249649e6a2be42b314e53706edaf2213de860546a05aeddd922d2d5c8aeaa58eda216144ded34c5e5158427a2deaa186305", .Okay}, + {.Sqrt, "fb3dba565d00c23ac032aab0c542ae94c9c0bacbf1baa76f0c0093e521b5775e47cc1794262eabfeacfd1dbf3c8f5d30f0f804abd7dd0a17831793d47cbb4dde032b0e305d2c44b211381b7fd0db709c0aecd741aeb1f7b9db889443cd7bb4b932878c482df3e4ce437d065081647fc3189da80f41d001a96b8fbdd6eedc8129354973ad8fb33c50c71f07040eb398e744187dc38367", "0", "fd9c01a7220c6917d8553460f83d804c5abb0b9048f29667e72b6020bc327d725d83e24cb61cc6495c0bb243c541df7c48e3e9ac80347e59a6d13eb12bf89b64f2ab52dc7431c79ce4ba07", .Okay}, + {.Sqrt, "3c556871bfcde51b8b7dee30e9c801f1ae4138c8f20352dd6d83bcb75cf9863c2abb18713245b8706376aef0a711077752000a1f17428007f571ce65823a47c0e6463ef7393d7627f91dff3dec14b68e6cb30726e8543c496e241d5fdee2a89ba5c1df84d9d2cd734c605e95ce3ceea2088cd46be6a2016e0bdcc9b50aff2eff209098f9ca8e833a37f649df4790635ea802343cb480", "0", "7c4790f7c25b463d305b1d15e63957affe50c30544f1ff3fa2fd0bff5496a804759235baeeb502f6531d13a39133eddf1b3fb7cf70a24e66bf7b64a1c068ec5c35b9b65ff0c5593ca1ea32", .Okay}, + {.Sqrt, "9a68805ed30270da54ef718a13c7e858269f604a977659655bfa7659c2b8ef89cc7f304a333dda6a9e9ac39961bf200fdebbbbbfee03af9dd189180202bfd8c4386fbd62397f65c37379c2bc2d2f7e9bf718e8adf913bea5dac51aa4e24d3c3e9bbbc7a34a788d7caad0223a5c7df3d89d09b810b7820a874b39da9f0e297fdf39c7e6fd9952897bd4c5dbfe515e13b168353075d966", "0", "c6d158add6e9bb188cdd25a3955149d941dab250a3f5ac541b8c2dc1b02c4d8f89f2370a3cd0c9b045736d24bb7804b609e539dfe249fdce045acb94f94ee151a57d13ffd087e2538655bc", .Okay}, + {.Sqrt, "ee77972fa1a6f7eba7305c002551155481dd0eb91614a2c0a222e55bb7c3ec7ec85d1b5347d52be89526640ec27c2c94cf744022f85595d96dec30a88d5f4014bddd5a9dde4e3c3e75d565057b3b0878420f7b5fa02079e0a3199438c0c20e5b0081ee3a03a6af6b260c42f0a193b8eef0de294c3077276650daf9023c49e5eb4cbff3d5c47601691626678d11533b35dd7c3a804be0", "0", "f713fec4d4ee79993446c2a73d7f315deffe5c377c66c65a9beaa468964bdff505bbc130945c3553efe1d77c8d8eaf073cd942b738ce69e4176ba4853ec47440d95034cdf843e460943e1d", .Okay}, + {.Sqrt, "8b487adcc28040b95d3404e37217a8feaf6dc47bb54f931a9f854174745e190174f96c59cb278c4e33e95084c414582f91450e87e7a143dc0361a8fe4cd556f15efcc429eec67920c5c1278aad4b23dc0cf6e6d544bbb1a505cee68facb87ba7bf1d1fc6d3cfdd88137a3f03073a535762c78e45d45e85442ba848a59f3a7a14cd9c073aaa073fb2466b75a5327a4334d9fea79c5648", "0", "bcd448bc0f39ad43cd7f7a0fc9e0ab253288c9fef50da5bda8047079b19cbf87509647a8e33e4f7426faba0ccff41bcb9f0df911784c9e800111e23a38b4bb955de7feea3c3ce7682555cd", .Okay}, + {.Sqrt, "24da684fd76c0356a57c3400540f798040e3fbd8da762eb0d5499e7c720df51ef72c18e8ffdd10df408a9a86d9647eb17fb7ba0b0b0d74c64bf25138f19875f1110f242927f78b2eabee3aaf359ed91d5008b7e6ad4817c2b0a679bee90d333c0033014cbdcb880a91c7522b897ffc8dba3072614e5e6a50052df4949504ef26ea9fdabe3f1b37428b5345d82d370d7c2836dbb230e4", "0", "6121813919b1decfd28fdf1495aec0ab00767e3b53000e838e05b0ba9db0cd082e1d931f665c319a2e8c902919ad4f48916bb3b023287043f90e1acbc2e2677cc9e0758e6134b656b29ec6", .Okay}, + {.Sqrt, "2eeec571154e728cf8a1daaf9aef56d6e10739b054a7c2b816955de53a2549fe914202e62e999be01e42d00a569d828fee31b85d383e34ae3cb6bb20e10356b60476092a30d2c391e2982808c0509b57b5b86393db33ed7c31d8e5981ea0210132ecfeac988ee585b8ffb6e710e3e52be92fd3f025f608b6ea38eec621f51a63ae2d42b4ed3c364b73bbe10c7cbf25733ad7ec472028", "0", "6d9ca644238db6b6b816caca665377f75fc4b812509be9e962d97743f1b786b570e0ef8b1363c2ac13f43eb26d4c4ddcbe2cfd3d47ab071dd1773045b3556b53478be9b0c593914d7c4692", .Okay}, + {.Sqrt, "fe1e95eedb75afb13c169fbd0b266e1f8d06140a72812f0c63a1b291bbc4a8de58a9869986df7e2e093570dfc2f32e5bc0173421834a264837e5a60cfc6e1480341e25a84039f19a29fce0cdfbd38ee031bfdae9983288f0aecf7221530d519ae1e708ddab020e166caf15da04d5ed399a41634807ccc3e1a3505b5a6f110a7c4a7859ae85dbb953650cb6a52a48b806db2709ecf403", "0", "ff0ed962909b6b36b58ae6dc3e3785d01f0f402e15a4c7e8d69e4411159db6f4c4af4c75692b2ec3f39395f00126623eb17f490c719e335ee078515d44e839369be698a798c4ad35cd220a", .Okay}, + {.Sqrt, "737878c84f679335c10307b495e9b0d037360e36932e5f11179a27d62b90ec1297abaaf0bb641a8538384df12b2b35b34f770528c3819c82dd8995294bb9d864f5b933e3cbf6520a714f9feb5d47b774adf76d758055a5a58e0d8e5fef16674ff8f6598c2beb7249176e35b247489efc31331f48799e89a7c46e0684fccece1597d06361e448b1c7c71c049d227309c38c26442c5de", "0", "2afb9f2db1ed09c837c6343a264ecb8d06b43f1f46b92abdb7d4baa9683a4794b278079d7d6d728e4644cde29895b70278edb8ce1d8695f2d6c6e50ae5d7694e84776134502f07b4bc3816", .Okay}, + {.Sqrt, "7dc0af4e4bb849928bcd264fb95d758d06f1d72f6bac636e80b395ff66f592f65f42d14538a05835229f9554b8aedf017407cadd4c97ac9dd749b3551b3036204677980eabc5d607a43e1a3474504081ff0aa8fe50896a542789e4296d55749c49f94c6d86b8811e5cdf7a9d107e71e580926ddd3bafebf95bb84ae9aa34fbc5c5a4cd8f38156cafb1c39dff434b341ac078dfee38f4", "0", "b36c56da075c2608960f9ac7aeaf39051dfb6e715d784984e173139f7bb4537ed71b39518cecae816f55cf92eddc52514600429a24045cae17c06e42621c64fe92a932fc28c37b20bbfed3", .Okay}, + {.Sqrt, "87a3781b3dda274edcd88ae97625cafa3aade7e9bd726c4bfffe03361fe462536dd0f33798ac4685e0137e1412434e8e4417249ef4db38eb7294d50a1ef3567f61fd0d727dd210d35255831ab9b3d2995c6ed682cd9c71e696125afbdbd083ea7ffadf98d8c4f7bb00da7f41bec736e57afc28f31ce3b572529d659bc626a2299f4b59b956c02afae0dde6ea3fba4b30e2d7c7463087", "0", "ba57a3db27ecdedddf79a5d2bb7a3f3e1fec10a01b0b543ccd6061ea8f0c75640127b6814b6008cce5a6c4f23dcadf44203d35563daa1434a799e8be70e0c9bdb3f8e9dacdddd71d38f383", .Okay}, + {.Sqrt, "78a2736ff9e88c6dcd04a4c089526b809848b9834af52f8e5b81ba56b2f41a8688bd3a05c98b41a3b3f09c39bc5d51d78dae40888ada4a6d60236fc83a390dbebffd71eee3174f3b8c9606119df91c8aaca52b0f9a8b13923c6e916f2935222e0ba519886d85bd55bee7c5e9255fb875d29236fe5db1cbd905d90b524402dd5c364d26375ab050b720b53b1ffbb81815e95082c0b0ae", "0", "afbbe9b18a634390a2da94f1cdd35a08a048fe57cc5f27e60f15e8866f95520d00ec09899c2da09cd5beb5a9832e4fedfc6daa37fea70bbea573e37a51b9256f30b3302ce600055a7dbccb", .Okay}, + {.Sqrt, "7f96fe10742046aa5c6b6935ccbdfe56444c7cfb0cda6d13c708ae732beb9c158025193ca69b9aefd1289edb37269fe4d31d8c17bf5790655214bc78946052ca8a35365d5c3f0675347e6de580886bbd99daecfc07487bce1c5aefc22f6e652ccf21b2317bb549b8ff9e40100ddc5640e3d7cd06a070b77ec9e7938e28d663ed9f7630c76df1b39cd0a99128a0e2c385f50b7179cc7", "0", "2d2ea8e344bc6879dea1aa9b8992cc1884b75f0489227c6ad77714eb8dcaa38fc67a742c200438a19e1a5aa59add9fd31ac1e7beb075b726798c0510723809df319718df995eb0c2438333", .Okay}, + {.Sqrt, "c90e68017a5efb16f5a0c1cef242e108378fede724ab91e63e8ad79d8c2c03eb15328879875159843bcb93f05a0dea1f7f99e2434759d93a56d8e92ae2c10b933cb17370c967181789bb8f2fbaaeb5d89b0e87c8e95ae2f416436a487a72d3fbf0a35c0bce02bdb7838e1be90b2a951a7f076cc6c47f435bc4e6aa6be21f1a5da13818e4c1c94944d08d3e04ddb7cd8c85b7a58a8da1", "0", "e2def3729a1bb70665bacbc8c2f6ce15930f2e661b77745d5b6310ff18ef906f21cae85bae57650f3d1117b13e28291119c0830c5b39ed0ba30bed8cfd5f660d78f848f6335cf7cfe212de", .Okay}, + {.Sqrt, "2adb17e6e29228ce1068d8ad4e53ac23f4efddffb7d7d7fac85c471cb328916317ff2ad126d7cfdb3ccb950f331db5c92a3c21bbee8d13c5e0a018b6d2e7f9cee4f96d8ca8edd4d16fec385406251683228ec66ad8e3af342a77e464b75dc1759739cc07f2788b631130007f3126c1b928c3d19f4ab9e922a903410e512e2d957b4e8918d5e9da229c8daded1c2d1c84259fe8afc68e", "0", "68be3468ace10bf61bdbd522c60894c60a720ff1ee102b00333cabbae844c0d92987a80af1676f487c9efeb78fc34bd25da4e3a33352880ea5f1286ababaecad1b9b1e9229937ef6c90a7a", .Okay}, + {.Sqrt, "ef51f4af8b6e55e857869b17df3e96bc1166281ed6b3ce00f91b134b8958e8331ce57e662a6258d4f7740d40ef316e0e1e0f8afc76b2521c7b873b4208edbe448481e0603bcf5c66e55a875a2a5fe99bb59d0d7c78b498dc911df501501e8c5b16df5b4640471eedd1516236cfe2dfe230dd9dd945670431c032542393fd209bcb2f4f57bda69fe75a8c67363c15059d908a6a5c2245", "0", "f78504f5521a23ce496e285c80094215df312a5446b3e8c001c6bdd655f5e4ce873bc385e4a8f1eda158e09d71c7f18a8d36e0b741a4fe59cf7c49a47db19b40beef107792fb8201e82fdc", .Okay}, + {.Sqrt, "49ccfb703421552d607db6c6061539957079309d59b71cd2055663089ff3365fe5b7287128e6d3e1d6378338e9837b8f7a5537a4af2a22f8bd27a722535e6185c040340c5a184c9ad79f7f04c9407663116c0f36727ff5c077c583d23ffbff4df968c9a46f6923cd96239a4912ec5e0ff5f3350a373aa478b78cf24f789808e91b904bf6986638b4fbe4ee9bc0797f297670a8185913", "0", "8973a58e0e6c547d07b6fcdbdfa401b9531c5795273d09ccc29f9e970c5fa60f7e609f9a0eb9b99b9e07f790e2cb28de6bba96fcbd999537ddc2835078066f29ab9416e3602a1027f07391", .Okay}, + {.Sqrt, "cf8876980bd21e6873a8bd1b68eee0013fe297ff9132d2e51ca5b14b60e1b908dba311738a5d3a186f5e651c5ce2a24197830c9c7c686285b8b650afba34abb8086887946cc7cdbbba1023c3ebe438406332927393d8ad5e8821a9cdc992cdb9168e80c8b8c590a6d6a6fe88e026496d3987a2fdc844dbcc8097f15b3f3bef7b4471939d7d36a361a5b5947e4406de1e4edeb7919b92", "0", "e67f01fe5e49ca69a174bfb6206448f41bff99a8542b2a2d535332479efe25230f57151f9870696747eb238c9b949cf3f92b108fd16061056dec27bd0102180100b0aa4b437d48953d1ec3", .Okay}, + {.Sqrt, "95ac807764faea0cd659f40ad28999554fd42e5162a56e66d28673a7ec6b6722f43e8d8dbbad48b756bb12a12b535c11c4941020ca539dc16558a7f3fe6523996e4ca8c3b809fa727d262436665097eaf555a7add2c756d269bb96f862f1d2f252542eaf09888b730f7bb252b1f1237b365048f661685d535470e51fe7ec11cbd0343094087838d24aa1341460c03e8d486ed99f310f", "0", "c3befabe83ab33d72b3b05f1960070f6a79c382c7276bdec57ff7ce07f12e04ac5f0f377fbad9b168e35bd126898b0513edb25ad7290b07300a3b6af4ce950b926303f3b7e69fe8c72dcdd", .Okay}, + {.Sqrt, "7908d87667ca33aceb5e3fc1ee581ccac093906a5ee9a759f49abbee6e6025a6887de6c4cf165a58feb68097de6392d209087ee15219e40bdb156289107f91cbbda832ee5e079ccb7d81beb642f75323c9b45b10b3017f869274ad3a66a529b7def842f74c2620cd755f9962b052aaf04ffeb31c81e322b6b21ec363d141246f9737b018f5fed55d8007d5451a39b7c2dde8fc6afe41", "0", "b0066ec3a7c6fd8c5cefd6ca127ae107cbdffd7bad17c093d1a656abd0cdc83596226509d045c0448c88f4bf1888b2a2a80f0ad633d2e3f5a9b17458f53a0ad9a95ccf70ae288dd0bb14cd", .Okay}, + {.Sqrt, "15e8b8f6d6efbe453516896843f47a617d2ec760ace891c60a81066d457c146bded894a5bf8a0b1a6d7711833d5e88f7fc151521df5df939182ea85c5b9b5a3c8f0346868ee8abbc340fdf9c584f97f9f01ca66b0b4ff5356eff8121d3b502edd227d94d79c636375f56b1f8321be84c0bdf87717a5294343254d85a61c3384d293b92bdcbe137ff4809524db0e1a13f16aec443ef6e", "0", "4ae4331b4575dcf73908cb3a5ceb745fb7c4550bf3f27782443bacce8c313edd7d49fdbeacc83b3995a9face8c07dac99c55a083d64599595435d0cc3f61bcdbb94a6875c0beb6472b6700", .Okay}, + {.Sqrt, "3de70294125fd84f3b4dfdf217f7e720b5fbe800a854d726141988ce2995706201b521a8a0006ec3d4648495de102c45752c877d72925db066e6e6e985b23795b3aff52582aed4e5c52b66734343ac16057d775a3c03b432b2ae57975e6bb1256b0570b2bed271371ecf7bac4c81261d360350ada1e849e0483bdf26087f75aff97c170a8f7172f1313a08c4aa60a369f10f11b0d74d", "0", "7de289554de956891478499c5a43e1ba24c26efb782056010ac11389c8046f853674fef95c2f2a75e49142ebdd349807a2b8a8fa6612385f6f77d4f5b57557af264b1a0928e5a53864a080", .Okay}, + {.Sqrt, "880aaaef1bd4e3114e1f2fb8acd86f7ac5e4d3ec4ae8f54988771a0f2b74f93ea05ba80480a6ce64aa09bd67cdcb5d9e8decf558bab4321dd2f08535a4a3bb65bd877a2951bae34243918d8684256d07073cf30c4c86c914d3567cd783a43bd7a345e0d3b73813e4eb0a71d91d64255496b44208475fb3bdce56caf24c3bfeb75d00ff6de0232b0600e95be4a695fa610f348d6e91a", "0", "2ea79e6c289816276d74999c692da7a6e3b33b2d5db13b9fa39342420bd3eaabd0153563e48e14255e9bd26936a8515ea6d26a6d757e067533ec1c3c869ce18143b2de5b562956dcffe9cf", .Okay}, + {.Sqrt, "91649de2ab0f5eb5dafdaeb95e23811af1d5a674eb15f1c591266217e4908d94264847639f8e9e3d1a755ddc0ddfe1bfc022866fc296256d221afa1978831256ef2d926a6635591845f26d4f776c424e9255df8c967817886a330e92e5fbb8ea0714e2316ec58fb225aa22af3f3490a6752841a25dd87c861ff082e84aa9907f164c3de1628fa55f84d6186cb987833fe9ef3360eb36", "0", "c0ed2c1aa6be4ed5739b41a209fad9881ab6d7d7fe19aeb65b6caa2241ce21e079093632d530ac49b3e48e14d20ce9d1b6bbfcb567c2ea85f305050b7e8a685cc331f1a3717b7df2fe053c", .Okay}, + {.Sqrt, "4d463fe58acca5f27113e9f96779783e61cfefdcadd971a8055c9d1ef782a44292f11bc4a7ca8930246531daa1680045f3c95549eabd5959aadcdd8a38a6ff1212a89d8683e7ca25d35093d40b747932cea4c902fc32e7b67688e859d52b2dfaafdc4904b4aac3f504e40b3a695ca597e149698a76e091da6cab5a33ad445a50074faf23f9e68c5663a48a0227506eaf45eee6604698", "0", "8ca63e1e1a3a8c97669a2ae30506920ed8373603fd599a1a89223879ff1341b81eaf6c33727ac751887fd69f3267b8089ca1c4b0b4bd4bd0525b8fe840274592d37d20a785644145174e7e", .Okay}, + {.Sqrt, "fbadfd83ad6c46d67b9892a23dff7663c46bc47c0a66e8e17733ceab270534c0d385c8f2fa06dca23132e3d8aea5fcfcda0b74cca19e02101fb2f3ac2c3c227b983d396f38a4f72b7397e1afe2c687037725a0c43295a2de321dd94bf6bf5719e3fba5ca5fd4264c83f6d5a1582d171e53728629e94cfc43b73d7508ea0a39e593a6abe3fc6ad5ed5964a707d04d9c43bfb53a606e20", "0", "fdd4a45e9f73c3344c2a062db09f1ec9476b0755a8b0d49761d6cdd1dee380e239e42076b563771b48cb5b9d7b54f89bf206b0670816ec9dd66d19a10c6457033a2b5135d1fa47288fd30e", .Okay}, + {.Sqrt, "35f0916917a6e5d37144c9998a1209c10dbde3a5a46d6cc8196626a6fefc7ec8469c519598cd47ca9ac60983fc6b18d6918cc926eff13d4d52996f2cbd20859a53a5ca301be4c2fa005b721520739d6695834d2611eff2e30b629846e04e3e6f3fb5647e283615cb3af21468d56be5ecb681bd517997fbfaf8b180412b1b6edd37e8ea1808e4b473935dcfa0426cb0709c925dbdde9a", "0", "758286695bfa8bb886950a513d7121288836c58b132695be7d0f334114761fc32ffa26513546aa33d39d8c08f0f5f9aed041bb7f8b596fbc5a60fd4fe3f3eccb2ef9d7cb2b4c2d00ae55d8", .Okay}, + {.Sqrt, "4a873b3038134e82914aa942ff2099656480f3541c0af00c80430a1371d4333e362f65736a0e9d12a39f779b8df159668e26c10f55aefd54cc7c162e774bec99a861cf40cc021fc104f00b0f7e438ebf5b005e82d7668ca6be301c179ce8fc72a81dd4b4bab639d11892ba058c91b59ab001238a211e5dabf48e0b022a1f5b90aae05ff2d5c9ec00e9a79fc53b7bc333f133a9a9f988", "0", "8a20a9c22b8f48421c8e2a1037db69da5f2352d3efb688b3222693085485d6d24665d2d00e3828447fe59c41ae3d57f149c5f116ceb99fecb0b515e8ace42090e3c44dc7745ce81ba5f91c", .Okay}, + {.Sqrt, "9931df74e92271a3c255ec2b8d5b7e3caa1d14b9be4e457985d07f69ba3f29f1cc5f4595757864e7dc73e9553378ce64135d29b6dc78ff171b0ed26c93f4ed23afd8b27922295c3dd1b0474c501af0a924a6558918fb6fed892e94e1f87d4c4a9fc1df92812fb4959399ff988e570229c2c58e572bafed00beeb01164b76c1d3ea993b1f7aee6b46c7ae3e6055e7d4943d2d18c4755c", "0", "c608f7b02863e3b5cae38944a89342efbddff11b40da348d626b23771072fb7f80ed403c5a440e5c6c4f5ebab18e78e3c9b6c9d8e908f2e4370ed976e36060f5f0fda5a8a95cfb95a55f8b", .Okay}, + {.Sqrt, "b005136de68cb2eefdb7eeafe71c000a2e31c84cb70fa1fc2ac6db8c143119a037a86b78e05893aa76a2ab111682e19d73aa6d8e969ac70dc738b4aa0e20773b8950790269b59bd0ad893b2bc873e84b67034cb1b40eb0d06fc80ba87cc1108febed7cbc88e33e65e417f847ac9430cb56045858fd7d1a0d48a19ff8e1c5334652898f9da6eb7f4d723798d621ca7994c8ffe55333f0", "0", "d446a4301ec01dd78860db29f8edf1a4ca3aeb0008016d35b6ba4f915471be26ea74d11521b029f18688f401b03ca04c124aa74f3999a9fe2449ff64292f33a3a80cd268c6ba2a452f3155", .Okay}, + {.Sqrt, "59efbbb8096df4c25a17ce95a7a3ba58810d3d7f7e043c281369c9e00e071b1f10107fd13eadf79ac97431cc935f60798f1a2a030e441c4ebbfd9a885f858ec936532b3f5c2b710a8288e93afaae8eca899584182de398e71eb2e549d8ca2f7bab2ad9c5d37b18759de420d9853e46262d7ca62e60ce6152ee6e84d68c4ceee3c24d0f1e6741921787ed1e79d3b1197362a7016a1d8", "0", "25ef16484433f986768dd9b07c6d94a09e088289464453d96df1b5d6e9a79dd62325f0ba537201aec988d230bcd278b339fe6523b95ceedd1563bf9e05bb04bbc33a0dac4adf596773b907", .Okay}, + {.Root, "ff4c1dd9111a8eda08d5dcefcab688a2f5c66ed6a59d52a136ccef8f330c4dcf2d82cb70a4ff569df6c9536ae214dbf77f3d11f11f38442e1183b01d6da7ae19c35efb5c4935a587a8bf1e3ccbc3bb1911fd378f3e5c0f83f6c707873e5138ee7fa936d09eaa390bfe4e7976acef15f2150377b5acb2f349e7881f72ff3c65008655c6bbc589541ef01154ddbebeb940789b87589925", "2", "ffa5ff1a37c47b6078c93bfb32ec6cf48d3c26fbe5b1574bb6a7a01938b5a0ffb8aee18aa9f4bd62d7ffbf33a1638fe4769c33319734b63478e2c74deb77bd4f21a5df597bc41663955602", .Okay}, + {.Root, "288aae8610294938faf6b69d984d3d39e032f08972a7c6f432809a2ec9706a5d516d807e0ba3435ffc583b2b1a84dbd8d0b65762e42e2e6c1b9d7ea89897d6ea68e273998b54db74b11364086d584660581f255b1c9ecc04a57ea83081cd94bca0ec2337a63ce0a004018684cea0b347e3046f95f536b88eb37259d80b90963f2d33e21052f52c0296f58845f3fe691b47c05c2b3cd8", "3", "8a80e4c8a74e499f3eb264ad1043653f86ff4cfe62bc704b754399fb9d0378aea07f08200c50fbf19f385fc5fa4ed3aaa090", .Okay}, + {.Root, "f43496c2d235b52f512a8c441b3324d30df904c2e311a095447035fa758885dfc43ec449ccd75311e1d036233d0aa7bc2bbf2e45015253f37169d7f5c2e95556694925b39ddd59de2ccf5ca0edf27f6a9bcd8bb8ea3f4dceb1b38331a67543e83a4c91ed115c66cc4d6e0abfeb40cc97099bca27c059bb891fe9745efbfc4cdc09d84fc1f173086cf5e9bd5b33aefc89362f12a10644", "4", "fcffbe5438086ad7c8274d9b5974d572d94b49a3c1b7feb6969f9a9d442b4415e4d3a591c28", .Okay}, + {.Root, "e5f630ebe61ac231eea9f543c006788dddcb59b97e07d8517817aabd2a6f9701d9a3891153e3c2d1350f497e97463ddf9e0aa9b57b6ab1277f12aff8a7b070f2083ba458a67eac3d198703726ed1925f44db13c399eaa9a48fabbbf43ca8ea7e4bdfa2b7b3e92d89281f940a40251dc627d6ef1fa98eb4690d020a50ce6352c5032bcb12546f41c5e66d46c9b34439aaceeebf9570c0", "5", "fa910879a3920562a9c452004dde25546513bc122575ec42059cfaa7f401", .Okay}, + {.Root, "a99bd40e9bc013ae1fc062e957bf20cb35db4b07f675eacc449a762bfac8c10ca15b426a772a263aa3c31b999035870b3bbc25363227c78957ae786b65782a9f51f94a291516af904680acd60d5d8d72cc8afee535718d4dfe318e33ebe362ac3dafbc2330715c15c3d97beb5e9f3afc7aa396a04e22a3d65a37401453b47116ddff35386350c4d218182c24f915d058cacb9d3582aa", "6", "ef061e466902eac16f80e281de452312ff29858dbe1fd2294d", .Okay}, + {.Root, "af64b7f992a9d0535ccf0c68fc240cf705d50b8358c27d525e814bbb0da766bf31f1151879cc71cd889031fe4c55458affcffab7940cfb361d86c98a7922a80bef9cc79a7e0f0b0621951ae26ca544525049552d1f5b6cdd884a9cd0ed9de0c2ab5785c6d7ab5c4802690535c726175293abf23df2df57e16b76a815900d0ace9731fbb51268f799ee34d04d3300c3358167078843ce", "2", "d3e5dc8fe9a781e90d750a948d508bba45bdd9ce33cf891d2501ee116f9c94b3d1dc09428baaa6326a95d9cc20088c047e509bd9a6908d003cb511fb85520f2f3d4258c0827b8ac5ccac79", .Okay}, + {.Root, "50b5d7e3b5a0fe4a6b92c16973d8eb0628e1b62761c9b36204bb080e2c9745daa56107b1f1e3f37128e371ae8fc5e7928ddeee101bd9029b30f403e10201af6766ffb9b3a707d9f1d1a9f60261139cc3d4c0ec3c00709ac6aec8ce4bfe338efbea79b00802ab04eb329a07050b45ae25dda78a4876d8cef15661786fe7b9959c2b87654a588c1259fadc53529fcc73cd69743f1e68d0", "3", "ae3c41c3819704f7a7b2e74bbddab2caf4bbe81e84b919f89ae3e89a2116f746568dadabf6a4b36c5d2a847a3ec3df30b17f", .Okay}, + {.Root, "bd26e4e6ccf3d02e64dfae3b6eda8b2104cb085e313c32b052da8fc583105e040684c30357657cd1e9ca77ec27ce5013fa32932d448ef38659ad28333b1190789c69b3a964450f770fb565f9ad7d08dcb113694f75c50a4e4e6c810a6246985f949470247563de4b2b2448289adeed89413e50a642e4030fab6d82f61186fe81d8c79cad2e3307f2bdfe429045b1ce14b0c49019e5ae", "4", "ed58ae5e9153593f6c50610dae79d771268dbd96d661fe948281a45d5ad8b72035ddbb454c8", .Okay}, + {.Root, "e7bb6dae94f2d779b1c3083cef2613a2cc8cd84841ff6974f7d5f624e78e3b801f18d87123f030f918b915c267073a3672ac0380e3079cdd522ff945c0f68e4e3fa7425d3c2e865fea1ccdfe61f47107e9e2bec82aa3461c714355825a3137608843151aca1bfea2dc68da55839465e56747d14468e683a7c6124a109ad5a527b0d0121dc376a8c27ce2aaa9001d45deceec303fb2b5", "5", "faf37ffb6cd2d1558ad658b1f2b15c7f24e5d85baffe3ecbd39ca32121bb", .Okay}, + {.Root, "b177ec800f3637dd63696c3858851948dca4da2822976d4dd067e047b9de2d85577d53e12cdb4078f87a49925e96aae05f7eb5354a015039b3241357c236c7e4550f5f50532c3291e537edd9f90e0a534e0f00cf25cd783d26b862e1fdc94fd0ec029cc54b4802cf734530c83437808b6c8b807926bbf64e7dce75afe0477c6112d71daa04715bca15ac6a54e8d1fa8264dab0f2f456", "6", "f0d5d701a142852857051ea3d3d7a4b081d1d50bd170d55e6c", .Okay}, + {.Shl, "6abdb2087013cc47e27b87e2216bc2ee440680c546a55282ca1713ce20b897a7690738011017e2b35ef28f10f39c4b63519d63cf5e26d1f45bd9795d08294872b6b6c2c1df410496d237358fef30c8564fded35adab78e97fc73cc29d1b5a7b1a7a4a3b0e106a98fcb13c345a39002f6bd6d47dae3b81a1cc7b53e8b19ad4ecf99f7d1baac800072ab59861408bae4b3e89a108d89", "168", "6abdb2087013cc47e27b87e2216bc2ee440680c546a55282ca1713ce20b897a7690738011017e2b35ef28f10f39c4b63519d63cf5e26d1f45bd9795d08294872b6b6c2c1df410496d237358fef30c8564fded35adab78e97fc73cc29d1b5a7b1a7a4a3b0e106a98fcb13c345a39002f6bd6d47dae3b81a1cc7b53e8b19ad4ecf99f7d1baac800072ab59861408bae4b3e89a108d89000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "cb39d45f62cfc2d893e1960a341082cdab61699781099b6653538461e44374677d4cb837daf9430a4cf7b84d4fa38b7aa9524fb328a8d67fbed4728f7c6589a829e0711e07a2d497a35b05fa87bcd8666d6a01da920e5fbe46d474dc3584497b7ba2dd3f64104b8b2eb7049b7faa7b876e104c83d4c5cb6c4bcc0f9faad1cfc093fcc86ee3cd50b63990b68600e2860b9a30378bfd55", "258", "cb39d45f62cfc2d893e1960a341082cdab61699781099b6653538461e44374677d4cb837daf9430a4cf7b84d4fa38b7aa9524fb328a8d67fbed4728f7c6589a829e0711e07a2d497a35b05fa87bcd8666d6a01da920e5fbe46d474dc3584497b7ba2dd3f64104b8b2eb7049b7faa7b876e104c83d4c5cb6c4bcc0f9faad1cfc093fcc86ee3cd50b63990b68600e2860b9a30378bfd55000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "3b70dfabc9e534abd735d9174a904c6149762cc503eacbe50bc1b45b23fec11d5aa56030ded51090262d808223a97b9a0566e06f8fa549298e92b9e1117a935b9b7d02eafd073cfa80fe27cd0ccb8d6e1d07f238816a0e0388fdad531695179beb5fb1a3adfd8d735c3f5e907c70df5a214fc403af0fc0831adf399726f3b20682d0296f8ed26fbe26e513b06b31fe422b08781e7ed2", "12c", "3b70dfabc9e534abd735d9174a904c6149762cc503eacbe50bc1b45b23fec11d5aa56030ded51090262d808223a97b9a0566e06f8fa549298e92b9e1117a935b9b7d02eafd073cfa80fe27cd0ccb8d6e1d07f238816a0e0388fdad531695179beb5fb1a3adfd8d735c3f5e907c70df5a214fc403af0fc0831adf399726f3b20682d0296f8ed26fbe26e513b06b31fe422b08781e7ed2000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "37b0d2973e029d19c9b59ebbedc722d9d4c6079efc348efa21c95632960c85ed6539f8552849a5a54a081106f506757a450a41e9bcb51cf3cf1123f4923b12cef17b1563d7dce1d39d9b7db6382935857b8b94fea602b199c9093686f47ac4550a0c686cb39db9c1e90f7f945c913978dcabb155dc3ac572e453ae2eb7e00dbefbab2f27381aa82523c0e2ff7f2786f2302f023b709", "258", "37b0d2973e029d19c9b59ebbedc722d9d4c6079efc348efa21c95632960c85ed6539f8552849a5a54a081106f506757a450a41e9bcb51cf3cf1123f4923b12cef17b1563d7dce1d39d9b7db6382935857b8b94fea602b199c9093686f47ac4550a0c686cb39db9c1e90f7f945c913978dcabb155dc3ac572e453ae2eb7e00dbefbab2f27381aa82523c0e2ff7f2786f2302f023b709000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-83381d99ebacf248d2b0f2612366836fb9e302bffa9b1ff86b10548b15f224f4866fece80b932150038b335849034ff76deb57567084fe7d03f19629b7e715fe8db1d1fbbccf0d82987cefc3c80231b038f118770f76d855b1c8ccca8f8b4cbf4f5eed389c0ec97f203f8d57392a620f3fbd4c81b3c8d971da0e75c9aaee5080cf9d6fea0b0216f945b2af8401de6bda2038de74ab10", "b4", "-83381d99ebacf248d2b0f2612366836fb9e302bffa9b1ff86b10548b15f224f4866fece80b932150038b335849034ff76deb57567084fe7d03f19629b7e715fe8db1d1fbbccf0d82987cefc3c80231b038f118770f76d855b1c8ccca8f8b4cbf4f5eed389c0ec97f203f8d57392a620f3fbd4c81b3c8d971da0e75c9aaee5080cf9d6fea0b0216f945b2af8401de6bda2038de74ab10000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-768a09209e51665bf179fec89e21481a4d83df997345cb4d46569c7d7009478ce70fe140243e9ea848d5b44774d9e2bc28ece95bc9bfd9df41fffff35105ac1457804d4c81992292db9e29a38e03cb0ac8b149293c9c127499b94bec9946fc017e978822027aeacbcb1455cb10cc6266fcc9a57c516bd284b2a362d9106963f380733c22111d3ce21a128e87c16e591b4d82e676585", "f0", "-768a09209e51665bf179fec89e21481a4d83df997345cb4d46569c7d7009478ce70fe140243e9ea848d5b44774d9e2bc28ece95bc9bfd9df41fffff35105ac1457804d4c81992292db9e29a38e03cb0ac8b149293c9c127499b94bec9946fc017e978822027aeacbcb1455cb10cc6266fcc9a57c516bd284b2a362d9106963f380733c22111d3ce21a128e87c16e591b4d82e676585000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "31e255323ab69146a1e8ab5324bf2a69910478a030d1e26606770d6943f7c16ab062c989f8e355bc41eaf9e54cebbdce5bca441de5fbd513fba5e41694e092b32e57bb8ccc04142645f1662da04a93a95f74643a3bae3f14dabb017f26139cebcf058d2d18136763e0271253583a5a687b34e231cfa732194a8a4cbc2d6b7d64b9612b44310bac07079f138b368c92b4b85e800b27ae", "1a4", "31e255323ab69146a1e8ab5324bf2a69910478a030d1e26606770d6943f7c16ab062c989f8e355bc41eaf9e54cebbdce5bca441de5fbd513fba5e41694e092b32e57bb8ccc04142645f1662da04a93a95f74643a3bae3f14dabb017f26139cebcf058d2d18136763e0271253583a5a687b34e231cfa732194a8a4cbc2d6b7d64b9612b44310bac07079f138b368c92b4b85e800b27ae000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "b416a18db6dafa15b4cb756ab32993b87f080a99524c888a14ba685917440e463e63584266ef7f71b3968788a535611d72b425c31debce1967bff658352c4b3aa9d320a26da4eeb0d5a01faf7d98352a003f0744997cf6899b1fb7083ef2c9804bed8cf154a52d8e7159ca2de8903353279afc78328599a2e2237a0ee05dcbe13b4096baa0b5fbc025abf0a0796b6e3f7f7d1d7f6058", "f0", "b416a18db6dafa15b4cb756ab32993b87f080a99524c888a14ba685917440e463e63584266ef7f71b3968788a535611d72b425c31debce1967bff658352c4b3aa9d320a26da4eeb0d5a01faf7d98352a003f0744997cf6899b1fb7083ef2c9804bed8cf154a52d8e7159ca2de8903353279afc78328599a2e2237a0ee05dcbe13b4096baa0b5fbc025abf0a0796b6e3f7f7d1d7f6058000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-9048e68bc6d76bef13c38d4ca89abe1e63fa910b5479b4404148b5599c0f73b95202e50153bbbfc732eec8c1bb29834faddafb261d5844eb83a9812574f1e69201cd06ca8d2dd12fdb0f7ffe734bbfe0a313804f14d6b9241f328907fe1f6cf343efd8a5b7bf73b93a913663b1a8e616a1414286603cabdb600ffc105d5f4cc9b2caed194e98bafa88152fc03351a57b9f83e0dda363", "168", "-9048e68bc6d76bef13c38d4ca89abe1e63fa910b5479b4404148b5599c0f73b95202e50153bbbfc732eec8c1bb29834faddafb261d5844eb83a9812574f1e69201cd06ca8d2dd12fdb0f7ffe734bbfe0a313804f14d6b9241f328907fe1f6cf343efd8a5b7bf73b93a913663b1a8e616a1414286603cabdb600ffc105d5f4cc9b2caed194e98bafa88152fc03351a57b9f83e0dda363000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "6ffbbe3caa06ea7dc454c1365f7d949198b4b1917d068a85ba351de2129742f971d93cf4e38f2dc84009cd6f8119c1f508846f86c1dece281575f7b9467fd2efbc7db7e4b224926fa1addd0bb275256751dab72c21221ea7a3e75d327cadc345f5f3bc78d655d4964b9947021bf6dbf49b75273f350b0a9af7a672654963626fb342a66d041cfc5588363425d2a1ddf427a20203e78b", "258", "6ffbbe3caa06ea7dc454c1365f7d949198b4b1917d068a85ba351de2129742f971d93cf4e38f2dc84009cd6f8119c1f508846f86c1dece281575f7b9467fd2efbc7db7e4b224926fa1addd0bb275256751dab72c21221ea7a3e75d327cadc345f5f3bc78d655d4964b9947021bf6dbf49b75273f350b0a9af7a672654963626fb342a66d041cfc5588363425d2a1ddf427a20203e78b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-2a3293db39a513bb492a3159066bca38f5cdd94dd9d95938c334f88e359ece5a44ef55a2f1b597d34a2b2b58beb11ccc67c92d56c10274713507251e6f9d9109cd919b0ba051b81764ff911dbac7dbfe702f5f463f8c301e2e5c7b25b506c07bb7783540f0c5b0484e969a413d544d95cf45130cb11065d58b502a140fd320e8a4e1eaaa253ebafaf80b807c51888f9c771f5a2d1ff", "1a4", "-2a3293db39a513bb492a3159066bca38f5cdd94dd9d95938c334f88e359ece5a44ef55a2f1b597d34a2b2b58beb11ccc67c92d56c10274713507251e6f9d9109cd919b0ba051b81764ff911dbac7dbfe702f5f463f8c301e2e5c7b25b506c07bb7783540f0c5b0484e969a413d544d95cf45130cb11065d58b502a140fd320e8a4e1eaaa253ebafaf80b807c51888f9c771f5a2d1ff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "653c27254855b2cc0647b2cbc049d5c4b6063eda54f98c7f2619ed0b1f1af31977b206db9be44402e0e3160d925828c9c3ec9f34a2a4423f497b523c993eb9025339949468d46e712308e305762c1237bb2ed6f0d389f13df8d22d671fb66f934611809d19fde832fd8b48412f2a9dcab27680ca1446c9b1fb2ab35a61424b66484b22710a82937b8d73b5d76e238b4c1bdb64fd5798", "258", "653c27254855b2cc0647b2cbc049d5c4b6063eda54f98c7f2619ed0b1f1af31977b206db9be44402e0e3160d925828c9c3ec9f34a2a4423f497b523c993eb9025339949468d46e712308e305762c1237bb2ed6f0d389f13df8d22d671fb66f934611809d19fde832fd8b48412f2a9dcab27680ca1446c9b1fb2ab35a61424b66484b22710a82937b8d73b5d76e238b4c1bdb64fd5798000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-e0f02ea9a5b8da1fd5d96cd07a86b78717e047414c7a437d0dd05a6d20397e5190f6da529737a9e06a76bb3513a8f6dc9ce9bb0660d5d3d55eda289ba82f643a1ba54c8aa8b3970420fe19c4db1d2fc52143e58fcf3c0aebbe2395bf725151b5a44e826c4b222c69cf1f070f88235b31932f28b2b4f3e99a7c8bffe1317442f01ef7980776cdbf88da534bc99012f3d49d4243b6cdb2", "3c", "-e0f02ea9a5b8da1fd5d96cd07a86b78717e047414c7a437d0dd05a6d20397e5190f6da529737a9e06a76bb3513a8f6dc9ce9bb0660d5d3d55eda289ba82f643a1ba54c8aa8b3970420fe19c4db1d2fc52143e58fcf3c0aebbe2395bf725151b5a44e826c4b222c69cf1f070f88235b31932f28b2b4f3e99a7c8bffe1317442f01ef7980776cdbf88da534bc99012f3d49d4243b6cdb2000000000000000", .Okay}, + {.Shl, "15b1ea0afa777a7074d4f7d2d94e870259dee470423a8cf3b26067731b9d0ebcc7b189d932193988fef0885f473b605554372090b0e5277958be64dcf84f419c882d1ad2a225b2054246631a30329daa724d34a75b3823dff77ee2e204322cac1903680536bdfc54566423232677535241152d2b296854f8172f183395c5664ee1c76ca06e62559ca01937c51c14f7d4186843e1603c", "21c", "15b1ea0afa777a7074d4f7d2d94e870259dee470423a8cf3b26067731b9d0ebcc7b189d932193988fef0885f473b605554372090b0e5277958be64dcf84f419c882d1ad2a225b2054246631a30329daa724d34a75b3823dff77ee2e204322cac1903680536bdfc54566423232677535241152d2b296854f8172f183395c5664ee1c76ca06e62559ca01937c51c14f7d4186843e1603c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-3aa41e0940224a392c82f41013b68cdcd3cb6003bdeeac0eb5e4530c06c56dc894c7f499d147d9a7ba870c3964079955d1fd9705ed247306cbb8d4f706309b30a45d64bf61448be3c67020cf9b5b123f36b7d727761b0c8234f28b226ebb3b00eb6bff2cd3397b4c18f6104ab98c77ab1e1826b9ea04e65a28c769017f6447b1deeac853ac270ee5fefae06aaee4952883f63108b477", "12c", "-3aa41e0940224a392c82f41013b68cdcd3cb6003bdeeac0eb5e4530c06c56dc894c7f499d147d9a7ba870c3964079955d1fd9705ed247306cbb8d4f706309b30a45d64bf61448be3c67020cf9b5b123f36b7d727761b0c8234f28b226ebb3b00eb6bff2cd3397b4c18f6104ab98c77ab1e1826b9ea04e65a28c769017f6447b1deeac853ac270ee5fefae06aaee4952883f63108b477000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "44c9f81026215d076a7be5885b959b09a25284fa89c96ec5f65e8fe844c86e4628f92cb2ad21e8195bd8a0084bf336db1a97b9520919676aeb3371276bd60efc7af6018b6ea5da254277c481caab6a6b84564b5c952e1990ce08c4e5cbed049ca294e1e7d834dfd87f792aac3160330bb9ce4c31da211cb82b81ee94de7bf972834b3e7818156e351cb59b918648c72de7ea159117c4", "1a4", "44c9f81026215d076a7be5885b959b09a25284fa89c96ec5f65e8fe844c86e4628f92cb2ad21e8195bd8a0084bf336db1a97b9520919676aeb3371276bd60efc7af6018b6ea5da254277c481caab6a6b84564b5c952e1990ce08c4e5cbed049ca294e1e7d834dfd87f792aac3160330bb9ce4c31da211cb82b81ee94de7bf972834b3e7818156e351cb59b918648c72de7ea159117c4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-e902d1c81ec3f611449bda52693d6032932de9c4e47e58525602a1711857175eaf93049811edd57c2cc9ff55fa0a2d5e5743373b2750a75084221a97d6607c5df2968751680676a62d65f7d1c1e23f349841c6262d737c5b368a8f07aee4c5a8d4b35b989d1e6605c4dcc525654ff883db0c3f8827ec432303e76fbc759453488904f2ab8ffd33ab57635b14d36b2e3654d0e8c8b9ca", "78", "-e902d1c81ec3f611449bda52693d6032932de9c4e47e58525602a1711857175eaf93049811edd57c2cc9ff55fa0a2d5e5743373b2750a75084221a97d6607c5df2968751680676a62d65f7d1c1e23f349841c6262d737c5b368a8f07aee4c5a8d4b35b989d1e6605c4dcc525654ff883db0c3f8827ec432303e76fbc759453488904f2ab8ffd33ab57635b14d36b2e3654d0e8c8b9ca000000000000000000000000000000", .Okay}, + {.Shl, "-e4a22d3ef72ac8945cb26806df47afeb755b8c7d24ea0b3a6780858cf6c3e510bcc7dc917960da3af5ce0caa767f03b8386514582e0dfa1f036a6a2cbaa282f4846be838ef721e2eb72026afb024ab7efb71d8293612123e9b3a4ac01e01d98d7dce8a52b9a46e52dabe800b83f8ae583f6711ceb309ab9b3c9eded1ff042e99cc1004d3cf79cebb0d0bf0de11f34e8b9da2fd3f49a2", "168", "-e4a22d3ef72ac8945cb26806df47afeb755b8c7d24ea0b3a6780858cf6c3e510bcc7dc917960da3af5ce0caa767f03b8386514582e0dfa1f036a6a2cbaa282f4846be838ef721e2eb72026afb024ab7efb71d8293612123e9b3a4ac01e01d98d7dce8a52b9a46e52dabe800b83f8ae583f6711ceb309ab9b3c9eded1ff042e99cc1004d3cf79cebb0d0bf0de11f34e8b9da2fd3f49a2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "894433c93d8a7af3001f6f07e7ec580145f5bd5474b5d8596bbecf2217293ec6d750a3c74f688d2d941113b4e9a48f6460032b1e2a52dfd1458bcfbe5cf12c90094b5e9fda7b5d773fe422312e8095805659cb28eff4c87cbbb8c607c14a681eca8d478c7466b24d2545157693fbfb09b30b4f28d6a040286076202de6b9ae6a5ae8bfa403ece96fd2dbeb2bdde759077cb6eeaf681b", "258", "894433c93d8a7af3001f6f07e7ec580145f5bd5474b5d8596bbecf2217293ec6d750a3c74f688d2d941113b4e9a48f6460032b1e2a52dfd1458bcfbe5cf12c90094b5e9fda7b5d773fe422312e8095805659cb28eff4c87cbbb8c607c14a681eca8d478c7466b24d2545157693fbfb09b30b4f28d6a040286076202de6b9ae6a5ae8bfa403ece96fd2dbeb2bdde759077cb6eeaf681b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-c354c7bb70f1d897c3df170cc1b1db94fde731901d4a55aa776f85881335899af60f8d4a3f4723c715a558172b7e78398e4f8e8426353d1f79c66d629cea59d760688a76c57391193c95d7d4d563e4e0c82fd8f630c46b5a7069ba847fa3608ef6b1e9e399d7c72697c7516cbc4ba1bc2bc23bb6d285a1d367697b06efbba00a2903c865cda253b5e0764aeef592f567d7d377318951", "12c", "-c354c7bb70f1d897c3df170cc1b1db94fde731901d4a55aa776f85881335899af60f8d4a3f4723c715a558172b7e78398e4f8e8426353d1f79c66d629cea59d760688a76c57391193c95d7d4d563e4e0c82fd8f630c46b5a7069ba847fa3608ef6b1e9e399d7c72697c7516cbc4ba1bc2bc23bb6d285a1d367697b06efbba00a2903c865cda253b5e0764aeef592f567d7d377318951000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-e5b99f9b8a29822ed9ede436eecdd477175d8ee3bc52ad07aa575fc6c8319972a750a302bbaaa7e9f1366209f59453db8301dbf834da26db890afe9d9f52c502b248fe5f3b9f87b2c50a59e315534650d50e3beab8bc934ca7387f52d4acb1fcae197bd298952b18b5852f3f9a5bd6cfb92122e2ae2459f04dd49b7b33c23ef99de39bf03f914a3a813afaf23dbcf0046f78ac82ea1f", "168", "-e5b99f9b8a29822ed9ede436eecdd477175d8ee3bc52ad07aa575fc6c8319972a750a302bbaaa7e9f1366209f59453db8301dbf834da26db890afe9d9f52c502b248fe5f3b9f87b2c50a59e315534650d50e3beab8bc934ca7387f52d4acb1fcae197bd298952b18b5852f3f9a5bd6cfb92122e2ae2459f04dd49b7b33c23ef99de39bf03f914a3a813afaf23dbcf0046f78ac82ea1f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-a12094a29139fcba84fbad660b895e614ca331aaed6b54366f27d724433818b90225b475bb116bdf2b0bb392c7945797ac1d9264cee986bade46d5ceee52cb5dbf229ce9bec7f87b211abdf964d29f555c85aaf821cffe8f5d09622322f7c3378ed95c05d9b7aa049e2ad7519ecc3872f4ac5a8ef50565df7d344619f94207ca021080242317c9a17a99d793b67ce31797838942f94c", "258", "-a12094a29139fcba84fbad660b895e614ca331aaed6b54366f27d724433818b90225b475bb116bdf2b0bb392c7945797ac1d9264cee986bade46d5ceee52cb5dbf229ce9bec7f87b211abdf964d29f555c85aaf821cffe8f5d09622322f7c3378ed95c05d9b7aa049e2ad7519ecc3872f4ac5a8ef50565df7d344619f94207ca021080242317c9a17a99d793b67ce31797838942f94c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-a8c287981ed6987c299df3877a6ff5046df9ec5b1d86bca8504b92e1ed240f0f7df07b5b1d6dc47bf961086708b5d0812d956c5a21263736918bfe49367c0669744d9dfdeac19dff28cb4e0b9db030fe97585431b0ad3e577111975a5f3db76a1011ef826b3f80d3cdf9e8c6eb238640135b84c3e0c1ba906de87c7e3787826a21455a858476807f1eca333d8f05bfeba175047b2cdf", "0", "-a8c287981ed6987c299df3877a6ff5046df9ec5b1d86bca8504b92e1ed240f0f7df07b5b1d6dc47bf961086708b5d0812d956c5a21263736918bfe49367c0669744d9dfdeac19dff28cb4e0b9db030fe97585431b0ad3e577111975a5f3db76a1011ef826b3f80d3cdf9e8c6eb238640135b84c3e0c1ba906de87c7e3787826a21455a858476807f1eca333d8f05bfeba175047b2cdf", .Okay}, + {.Shl, "285172d51737fefcccc494e11e91a217189dfe3a482fde16fc606f47c8a2968b04decf675d067a3c7aa045012d3dedd3f7cbad0102848bce0c1e7f5749d8c0d1e6adff5c387d8818046589b3b33123cbbf0eb5b26106a1ff177cffc010d69a073c915d60f269f3079253bef24f35dc714d1d92b1b1448d76d82bce6b021131197f02f99f5a5df0f3033f7feb519922f9ff2fa4fbbf5a", "1a4", "285172d51737fefcccc494e11e91a217189dfe3a482fde16fc606f47c8a2968b04decf675d067a3c7aa045012d3dedd3f7cbad0102848bce0c1e7f5749d8c0d1e6adff5c387d8818046589b3b33123cbbf0eb5b26106a1ff177cffc010d69a073c915d60f269f3079253bef24f35dc714d1d92b1b1448d76d82bce6b021131197f02f99f5a5df0f3033f7feb519922f9ff2fa4fbbf5a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "bd583f9f89be15cb4c421fc2b24d1fb42529fe739feef562155c6be8cd18c44030549b1c3836c319cc4621e11c1e983c10ad9f55e14f32d3af8d674939afaf001e5042fcc4dcbb6789a17298266062c9a94b1034d614d44a5ded4427a3624dd2cb72412069e122697c4f4b7a2c9a351931f9abcb1cfd5f72a99ea01a300e85f33f203338e05be00a688df44f4f60f8a269f1f78d1be4", "12c", "bd583f9f89be15cb4c421fc2b24d1fb42529fe739feef562155c6be8cd18c44030549b1c3836c319cc4621e11c1e983c10ad9f55e14f32d3af8d674939afaf001e5042fcc4dcbb6789a17298266062c9a94b1034d614d44a5ded4427a3624dd2cb72412069e122697c4f4b7a2c9a351931f9abcb1cfd5f72a99ea01a300e85f33f203338e05be00a688df44f4f60f8a269f1f78d1be4000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-70b6ea9277d17901da6b9e0d8e94dd22aeed3f758dae0d20b6f9dc09d92ad374b2142509df9c7e5f1c90d8daec730178400836570d57a949749ee927dcbf3ffb1e18d2f070e74b435d0615d6f00a90fc68a19b93bb4546aac27b2d100f27c7b23d714c174bc27b55aa97b54559dba85ce426956e2601c60dc1bfecafdffc565154752234200e0d748a6829f94bf70e7c31e6c1adbb72", "1e0", "-70b6ea9277d17901da6b9e0d8e94dd22aeed3f758dae0d20b6f9dc09d92ad374b2142509df9c7e5f1c90d8daec730178400836570d57a949749ee927dcbf3ffb1e18d2f070e74b435d0615d6f00a90fc68a19b93bb4546aac27b2d100f27c7b23d714c174bc27b55aa97b54559dba85ce426956e2601c60dc1bfecafdffc565154752234200e0d748a6829f94bf70e7c31e6c1adbb72000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-d651e6ef53d642b97b4e4fa0ec9a5709f17acca9111fa6236e0f20558f3acd4e4486766527f2cb776b48126e49d45376e9935dcf7804680dba1a59a21a4a064c37196de7e1fcbf847bf411375f869468113781b84d3937f412de916daaab01988db6ce99e3ede4b4ec365351e6b1c1de690b8519b20de48d13238e107a5095d0fd93ca4afabc817cc44ede50ba327b2a8bedfdbf8139", "b4", "-d651e6ef53d642b97b4e4fa0ec9a5709f17acca9111fa6236e0f20558f3acd4e4486766527f2cb776b48126e49d45376e9935dcf7804680dba1a59a21a4a064c37196de7e1fcbf847bf411375f869468113781b84d3937f412de916daaab01988db6ce99e3ede4b4ec365351e6b1c1de690b8519b20de48d13238e107a5095d0fd93ca4afabc817cc44ede50ba327b2a8bedfdbf8139000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-1d8c217a88f9afad8f3e3c9a0afb54e67bcbfed19a54167cd3fe8957fd31c87b72b75b605b34f491e34248b5396a033c287595f1c8662ee7b8348b1d5c9fbdac8fd5c3870b4b0e681c0075f32014be18d0e1099bf3dc427757d140d28032b99201c1b52f5a2991e057de7b41b20c4ebae57e737e16b5eefcf9881f1c35aaeb2060231139aa6796f06b0dabc1af98cc8dc2299a94ff9d", "258", "-1d8c217a88f9afad8f3e3c9a0afb54e67bcbfed19a54167cd3fe8957fd31c87b72b75b605b34f491e34248b5396a033c287595f1c8662ee7b8348b1d5c9fbdac8fd5c3870b4b0e681c0075f32014be18d0e1099bf3dc427757d140d28032b99201c1b52f5a2991e057de7b41b20c4ebae57e737e16b5eefcf9881f1c35aaeb2060231139aa6796f06b0dabc1af98cc8dc2299a94ff9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "9f0629a8fc4b4cc4e482f782ae2a13adaa83852c92f5f6b02a90dedc66646727d7830a986fb0f971c0a3c15e944eb70ef093b574fc150a62eab051256a72f60ff8092c44bc47991dd9302fbeb9680d0e04f1a6c8a5feef842e9b34332b3c923ce675964e7e565b8e3895b3c7a2709e139b4bffc2114f20a511be82989fa9c786c327dec887e1ae140e419b2e7418e5a6325ba2eb8ead", "3c", "9f0629a8fc4b4cc4e482f782ae2a13adaa83852c92f5f6b02a90dedc66646727d7830a986fb0f971c0a3c15e944eb70ef093b574fc150a62eab051256a72f60ff8092c44bc47991dd9302fbeb9680d0e04f1a6c8a5feef842e9b34332b3c923ce675964e7e565b8e3895b3c7a2709e139b4bffc2114f20a511be82989fa9c786c327dec887e1ae140e419b2e7418e5a6325ba2eb8ead000000000000000", .Okay}, + {.Shl, "9279511fc2cba2debb66e9db31044198a73ea93e57dd0b1549344d3fadbd0ca640c2a83023a57693291567910fb0a94b433c5981d665546824051ce1ad9e5729f67725608b91814d7421076e754c63afcde0d4f72af2d612eff8c0ba6aa9f64fd224580661597edfd7ff2099145ec441daf42b6a70d4e76cd9f85f540ce256031ad0c5d9fe145f85ef55fa2c306ac9af9c8fc849e67a", "21c", "9279511fc2cba2debb66e9db31044198a73ea93e57dd0b1549344d3fadbd0ca640c2a83023a57693291567910fb0a94b433c5981d665546824051ce1ad9e5729f67725608b91814d7421076e754c63afcde0d4f72af2d612eff8c0ba6aa9f64fd224580661597edfd7ff2099145ec441daf42b6a70d4e76cd9f85f540ce256031ad0c5d9fe145f85ef55fa2c306ac9af9c8fc849e67a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "c7f250f2092155971f30a04b967a2c251b664e9c6c0884d8f1c77b3df71dfb6720aea9e6f23d80cc6f0d8d0a17c55dc696ef4952e6340f4814e32d3a12e7ffedc5c656db793579a87e1fe0e77343085009f206129e5d7fcb30f7381d84eb8ef901dbd999646c7e71e5096f9a13dd035e9dd4decf9dc351dadb796df3c55bc91736e327e61a9bb3665ede7ef183d74b62b1cc192b0647", "78", "c7f250f2092155971f30a04b967a2c251b664e9c6c0884d8f1c77b3df71dfb6720aea9e6f23d80cc6f0d8d0a17c55dc696ef4952e6340f4814e32d3a12e7ffedc5c656db793579a87e1fe0e77343085009f206129e5d7fcb30f7381d84eb8ef901dbd999646c7e71e5096f9a13dd035e9dd4decf9dc351dadb796df3c55bc91736e327e61a9bb3665ede7ef183d74b62b1cc192b0647000000000000000000000000000000", .Okay}, + {.Shl, "47847cee268b00bd10624eb6cd59a68909e23975511fbe2abfb5759262f9cd08fdb6d78737b0f64bcc7cbb6193eb1b8d9fc3cbf3af511e83e768ce8cfe7d115abc487b21b627c9c2606d3651b7400837fd69adea4f530e69c6e2d0df3bcef766f84e1e97b79e5df8e565f06de9ca24e2b5a2a0fae2198047abee9f0b3c7c2dfb87f3e743f27927b2cfd77874598ab63e3216e9cf9c16", "168", "47847cee268b00bd10624eb6cd59a68909e23975511fbe2abfb5759262f9cd08fdb6d78737b0f64bcc7cbb6193eb1b8d9fc3cbf3af511e83e768ce8cfe7d115abc487b21b627c9c2606d3651b7400837fd69adea4f530e69c6e2d0df3bcef766f84e1e97b79e5df8e565f06de9ca24e2b5a2a0fae2198047abee9f0b3c7c2dfb87f3e743f27927b2cfd77874598ab63e3216e9cf9c16000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-38fcf7ac8799b4da94c3a5745facffd71161c73f48885afe04b0eb29bcfb303dc7212a712e2d6e7a1f9f66c67eec9c852ee744e5c36dd3498fa87a43be81da2ede04f583ceac4ce2cead1ce555a0aab93e3dddcb4d6dcaee3aa9809cbea8d03c48f32108449e3b327171c782c36f3602226a3ec18eba294d582a33d55a0aaa2a7e0acb0b3d0a2b8d86886990f0d1603600507aabfcbd", "168", "-38fcf7ac8799b4da94c3a5745facffd71161c73f48885afe04b0eb29bcfb303dc7212a712e2d6e7a1f9f66c67eec9c852ee744e5c36dd3498fa87a43be81da2ede04f583ceac4ce2cead1ce555a0aab93e3dddcb4d6dcaee3aa9809cbea8d03c48f32108449e3b327171c782c36f3602226a3ec18eba294d582a33d55a0aaa2a7e0acb0b3d0a2b8d86886990f0d1603600507aabfcbd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-17009c5206aeb56504e1d3c2cdbfa7cd7479b9c13b68082d3d150813913582ecbe881caeeb0c89e3ae3f7abe477106b3ad1996e052d0af21ae15a32622d63986f437542273d04a46d0b0c9e8b0a14c10620bb6cc8e3c1345ec9ef65779d3d8127a9d06c4275cb70903beb28e21cd4bd1d2e3e70fd9fb882b3fc0e466d5b9e26e5b770d2d3e668e9834ee08afe65aa00b0efffdda852c", "12c", "-17009c5206aeb56504e1d3c2cdbfa7cd7479b9c13b68082d3d150813913582ecbe881caeeb0c89e3ae3f7abe477106b3ad1996e052d0af21ae15a32622d63986f437542273d04a46d0b0c9e8b0a14c10620bb6cc8e3c1345ec9ef65779d3d8127a9d06c4275cb70903beb28e21cd4bd1d2e3e70fd9fb882b3fc0e466d5b9e26e5b770d2d3e668e9834ee08afe65aa00b0efffdda852c000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "21c2b3e2b92694a4625d7f3644e4d5e3e86967ddcdb13e514d143c9b799e82c7c91cf56f2912d8570844acc5af2986894ac8d2ce2755bf882ebecd4d02a6971ce16d9ce9fb5ca4d00b543a583be4fd7447583bd8e9b0c92c110327eecefac75a09f8f001310cab3cc3fb57ea3606529af95564295e6278a195efadd8c40cd7ac40618486d56016cf1f0320b9c2ca8f4cb520bd9e7595", "78", "21c2b3e2b92694a4625d7f3644e4d5e3e86967ddcdb13e514d143c9b799e82c7c91cf56f2912d8570844acc5af2986894ac8d2ce2755bf882ebecd4d02a6971ce16d9ce9fb5ca4d00b543a583be4fd7447583bd8e9b0c92c110327eecefac75a09f8f001310cab3cc3fb57ea3606529af95564295e6278a195efadd8c40cd7ac40618486d56016cf1f0320b9c2ca8f4cb520bd9e7595000000000000000000000000000000", .Okay}, + {.Shl, "-7e039d194389a7adfb23d4bdc275b38e09133c51bc8fde698e1d230cc124e75cad424f5beaf83576023034ec122bf1370b472725b7bbca20aa75fb78de37d2a68d4e077e4c1823eb81e2049a42dafbe6362d3f3bade3705cd597b01dbb4dd8f6ebb711a9bb87e295c489e17a0e19fb6a152e8eb93aa83031063a8ffad8cd64efc5b77b65d0406354087ad2176192ac63d8ae272fd825", "0", "-7e039d194389a7adfb23d4bdc275b38e09133c51bc8fde698e1d230cc124e75cad424f5beaf83576023034ec122bf1370b472725b7bbca20aa75fb78de37d2a68d4e077e4c1823eb81e2049a42dafbe6362d3f3bade3705cd597b01dbb4dd8f6ebb711a9bb87e295c489e17a0e19fb6a152e8eb93aa83031063a8ffad8cd64efc5b77b65d0406354087ad2176192ac63d8ae272fd825", .Okay}, + {.Shl, "-f33bf46a6828ae5404f8d10a3a2f0de7368caeac1ebccc3765fb17b8106961963e33119ea914056e6b9c31d31f9dca9da174105e3c8e6f4fac5377c0af062c391fa58bd0f1adb20e0db3b1609733eee30ed23557d98d9b5133b3fc4bdf1aaab753a7fb16489d85570185debc1b358fc7024f9d8ea58ad6d6160024f2f91d42a3dbdf1ed2d048381b8e4ffcbd1bfab7c1825c69098dac", "f0", "-f33bf46a6828ae5404f8d10a3a2f0de7368caeac1ebccc3765fb17b8106961963e33119ea914056e6b9c31d31f9dca9da174105e3c8e6f4fac5377c0af062c391fa58bd0f1adb20e0db3b1609733eee30ed23557d98d9b5133b3fc4bdf1aaab753a7fb16489d85570185debc1b358fc7024f9d8ea58ad6d6160024f2f91d42a3dbdf1ed2d048381b8e4ffcbd1bfab7c1825c69098dac000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-925f10757909ce07a064c976779c1b05b6309405dcdff710d4483d53a933c611af7916bae74327086e30a5c187c3fc004050d74734f71ba379e8d81e62601b434e20fccc767157bd402e3f4af7b64f27bdf51a1422c71fa54692a80822a86b2c8d5c6e62ea6950f5a6a263f86bebcc69b6d0561cd652bf7104cd714913a82641792959a3401fcb37232ce03fdaf20e5ca0f4939d882d", "78", "-925f10757909ce07a064c976779c1b05b6309405dcdff710d4483d53a933c611af7916bae74327086e30a5c187c3fc004050d74734f71ba379e8d81e62601b434e20fccc767157bd402e3f4af7b64f27bdf51a1422c71fa54692a80822a86b2c8d5c6e62ea6950f5a6a263f86bebcc69b6d0561cd652bf7104cd714913a82641792959a3401fcb37232ce03fdaf20e5ca0f4939d882d000000000000000000000000000000", .Okay}, + {.Shl, "-bd4043d3e5066096f1a6d65eccb875483afad0fac1c8c570ac908f874c0a0c2efd57f5553cf9bd344b73ecd4a1ebf4f53c82c74121160276383d748c93d5523f0847b68b840bae25d5885aa77714e74c66a4046518d95337c59a95f64f535f61999ee29d1e64eed61b1b62c7b2bb0b1302614fa4f530579c7b226b6bd5487984a9942ccfb69ed63511a654783ca9f20c7df708695ce2", "168", "-bd4043d3e5066096f1a6d65eccb875483afad0fac1c8c570ac908f874c0a0c2efd57f5553cf9bd344b73ecd4a1ebf4f53c82c74121160276383d748c93d5523f0847b68b840bae25d5885aa77714e74c66a4046518d95337c59a95f64f535f61999ee29d1e64eed61b1b62c7b2bb0b1302614fa4f530579c7b226b6bd5487984a9942ccfb69ed63511a654783ca9f20c7df708695ce2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "a78694286aef4286240c9930f67030aec124aeb544b5e2fb71a419b7362529327d37fc534c92863f5671519bbe1b75cc30b4b9e11c0030c2bf25f92cb63793793f6576ae15df09db910c8f7c4a066c46806845e01c61d779be8e1acbf7645e976f35e99b3ac1e7e6286a44a14012de0441c17ea94cc4ee1661446667b1b8e740ea18543bb2d683e98a3c1bdcd45062447ce436e87afb", "1e0", "a78694286aef4286240c9930f67030aec124aeb544b5e2fb71a419b7362529327d37fc534c92863f5671519bbe1b75cc30b4b9e11c0030c2bf25f92cb63793793f6576ae15df09db910c8f7c4a066c46806845e01c61d779be8e1acbf7645e976f35e99b3ac1e7e6286a44a14012de0441c17ea94cc4ee1661446667b1b8e740ea18543bb2d683e98a3c1bdcd45062447ce436e87afb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "f4ef97adbb2fdc0cdae8340554f132b83fc8d494974db4045cc3cc8a9d4d7845daf8d9f87572cf8b0a8fcc076d9fee480885fd48192014f9637c310e81369c94e683ab0ae8c792313c6b9d4a833df056ad9c44a8de00ccabd310be93543d1f3021d0d555c047c7f9d6ffe75e1f1783a197be6e85fa662f073db8678f1a07fb6a59c57c4d9bbb05f973e9baaa2b792e63ad70e14b1cc5", "b4", "f4ef97adbb2fdc0cdae8340554f132b83fc8d494974db4045cc3cc8a9d4d7845daf8d9f87572cf8b0a8fcc076d9fee480885fd48192014f9637c310e81369c94e683ab0ae8c792313c6b9d4a833df056ad9c44a8de00ccabd310be93543d1f3021d0d555c047c7f9d6ffe75e1f1783a197be6e85fa662f073db8678f1a07fb6a59c57c4d9bbb05f973e9baaa2b792e63ad70e14b1cc5000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "7fa484648e0149ad1acddb2d02f089f811579d24ba78345762fbeca4d95d83252df06db5ea0d1932cb9b13197567cf0c9e36d3edc60a72d7105e0c3573a44fc1451db748c30fba3e8061f7c24c47314ea26e454967c2cc74e7bae52ade39f847de759029a2b25b135f6231cd0820e56b31bea967b53eb63070ee799ad92d65dde20aeec09b34b7763060e8af7052af0eb17276f52853", "78", "7fa484648e0149ad1acddb2d02f089f811579d24ba78345762fbeca4d95d83252df06db5ea0d1932cb9b13197567cf0c9e36d3edc60a72d7105e0c3573a44fc1451db748c30fba3e8061f7c24c47314ea26e454967c2cc74e7bae52ade39f847de759029a2b25b135f6231cd0820e56b31bea967b53eb63070ee799ad92d65dde20aeec09b34b7763060e8af7052af0eb17276f52853000000000000000000000000000000", .Okay}, + {.Shl, "-c84b0cf269968ceaab02a9ed4544b13b157d164000a41d4e2d680e212fa3129c31d1de2f1e1e9f4949cb8afa995fe258faa6352c38c31f43ab8d209d37a090eb569cbbb358b53e9cbb5332760481ffbfb3562e5422c59f1de5704002471c951937daad54ffe9dfd9312dd0cb7f2ed47a1816c845ba67ce15d168404e857d710e6b23ee59e18d9457df118dde7e62c82ef8c09b9a18cc", "258", "-c84b0cf269968ceaab02a9ed4544b13b157d164000a41d4e2d680e212fa3129c31d1de2f1e1e9f4949cb8afa995fe258faa6352c38c31f43ab8d209d37a090eb569cbbb358b53e9cbb5332760481ffbfb3562e5422c59f1de5704002471c951937daad54ffe9dfd9312dd0cb7f2ed47a1816c845ba67ce15d168404e857d710e6b23ee59e18d9457df118dde7e62c82ef8c09b9a18cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "e08c0ceaf6cdd8c40a50cc41aaa0497ee9c00968a9298abb40fa01518a48cbed524e438d5fdecbc992a83b3e22138393a581a48ffbdc6016dcd3fb0bde35a0e6689b3f9f30cd45b22cad95997ee19c5ed529a25d02e786e5295460c1b2740f37b9f354ebb570ca3d5074de03a53d2d02f601c877d8744eeee92d9513f51619e8fbc9f82beff0e85855464d7e0bf2b9abda22032f2a61", "1a4", "e08c0ceaf6cdd8c40a50cc41aaa0497ee9c00968a9298abb40fa01518a48cbed524e438d5fdecbc992a83b3e22138393a581a48ffbdc6016dcd3fb0bde35a0e6689b3f9f30cd45b22cad95997ee19c5ed529a25d02e786e5295460c1b2740f37b9f354ebb570ca3d5074de03a53d2d02f601c877d8744eeee92d9513f51619e8fbc9f82beff0e85855464d7e0bf2b9abda22032f2a61000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "5cccc8c34716a29dcfcdb7342d97434e9024be933218d9e273ca7f1f9589b74e9ea336e94359d060882c9bbe1965221db9858f17086543158ba1ee531818078256e59ea5417b85ac23a60ce67bcb609fe4b06efe40b97805549d0c59c7dcceb84c38ee5090d903b37883630166257fd269276a71a64b651892d6c9649b1aaf4c8b58cb51a4163875647388ace0f627e512a10aad73d5", "b4", "5cccc8c34716a29dcfcdb7342d97434e9024be933218d9e273ca7f1f9589b74e9ea336e94359d060882c9bbe1965221db9858f17086543158ba1ee531818078256e59ea5417b85ac23a60ce67bcb609fe4b06efe40b97805549d0c59c7dcceb84c38ee5090d903b37883630166257fd269276a71a64b651892d6c9649b1aaf4c8b58cb51a4163875647388ace0f627e512a10aad73d5000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "80dec38bc78d1c110be1f5a54dc6cb484088733138be402add421d019e4f3fc009a1cf4c3d6cc05ea821f6fd38c6a72e2094f033b4f950466b9613e32c0bc185efcaede6f212e0ef45ee284d559f63c7224d51d44061c569bf6c3513db161f60af53b72e76ce8cc259e602c9c75d2455dc898d57b38c2082a12e17b465109a98d14a5b29b2d590e1990394e387f5ab1b055a1a60942", "21c", "80dec38bc78d1c110be1f5a54dc6cb484088733138be402add421d019e4f3fc009a1cf4c3d6cc05ea821f6fd38c6a72e2094f033b4f950466b9613e32c0bc185efcaede6f212e0ef45ee284d559f63c7224d51d44061c569bf6c3513db161f60af53b72e76ce8cc259e602c9c75d2455dc898d57b38c2082a12e17b465109a98d14a5b29b2d590e1990394e387f5ab1b055a1a60942000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-a8852d15b627554e85417e7d423f36270cc5c3da119635418807efe3822706e171f6b8f709b5cad78d272ed9e0f3fb6bd4c67536c12a35961ccee263f2769eaf02111ce74a405577c4e876808b97941670607de4e0473385c909e28e59160eab7d74b63644adae78c1dabbe6e7fb18779babccd118f38aa4aa932626d49ca98ff482936fadd91937610debfdbb9552982aeaef07c765", "0", "-a8852d15b627554e85417e7d423f36270cc5c3da119635418807efe3822706e171f6b8f709b5cad78d272ed9e0f3fb6bd4c67536c12a35961ccee263f2769eaf02111ce74a405577c4e876808b97941670607de4e0473385c909e28e59160eab7d74b63644adae78c1dabbe6e7fb18779babccd118f38aa4aa932626d49ca98ff482936fadd91937610debfdbb9552982aeaef07c765", .Okay}, + {.Shl, "-cf698596d8e762216a98391d71caf3995548e51e538b5c04c048d01b6cce22963c3463f591385cc7e2eddc3077730037e974abda17709f0a3732e966835e22534d8570efca3b9625b2f9b2aa31f4430cf175ea6e7dda13dde400f490faed8970e0dfb45b0766a754e87b4e9b26306dd883016541e05addde247af3ef1e83c9d00b5f2e44989754b94d33be9d5aadb3b24b3e7dc4db94", "b4", "-cf698596d8e762216a98391d71caf3995548e51e538b5c04c048d01b6cce22963c3463f591385cc7e2eddc3077730037e974abda17709f0a3732e966835e22534d8570efca3b9625b2f9b2aa31f4430cf175ea6e7dda13dde400f490faed8970e0dfb45b0766a754e87b4e9b26306dd883016541e05addde247af3ef1e83c9d00b5f2e44989754b94d33be9d5aadb3b24b3e7dc4db94000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-3803183bc176c3444c0bd91353e08c56716470943e44f14925ed58698a6de9ffb6e09f16730b76aa39401c9474eb894f28149ebd9a501c441c301782da220889158bf5a3b0036aac5e447dbecb368a564b485be0810d2e99e22887f1d94a8b03730c7ca80bbb8f2eca44dcab9b8f724808ff3cba848a1cd178d62809fb74f85c9fe79de719a5768b208c5601e0d7ed3fa7f7a51dc50c", "b4", "-3803183bc176c3444c0bd91353e08c56716470943e44f14925ed58698a6de9ffb6e09f16730b76aa39401c9474eb894f28149ebd9a501c441c301782da220889158bf5a3b0036aac5e447dbecb368a564b485be0810d2e99e22887f1d94a8b03730c7ca80bbb8f2eca44dcab9b8f724808ff3cba848a1cd178d62809fb74f85c9fe79de719a5768b208c5601e0d7ed3fa7f7a51dc50c000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "ff8ef7310b4271c79c08ca4bcffa7a0cd8297d456b864a2b6a05036f457de0863b9223ccd496ee38d6d07d6fdde5c50a1ea50419ae4908abf5225a2747a0fc2e2f86fad1b2e90d3b69c876b44ca27e018552244497cd01155148582b9efd7cf0be044df9213111446c046191198389f34edb138f2b6efa541e1d70ef272df7db5d4ba4116aaa41126ef97ed0ac2277b17b0205301a63", "1a4", "ff8ef7310b4271c79c08ca4bcffa7a0cd8297d456b864a2b6a05036f457de0863b9223ccd496ee38d6d07d6fdde5c50a1ea50419ae4908abf5225a2747a0fc2e2f86fad1b2e90d3b69c876b44ca27e018552244497cd01155148582b9efd7cf0be044df9213111446c046191198389f34edb138f2b6efa541e1d70ef272df7db5d4ba4116aaa41126ef97ed0ac2277b17b0205301a63000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-c087ecd899d5d1c288b018c1d48f1ad2d0ebc6db3ef523c2c1fc2eb7781cf240e0e8b5db9477fb4e727fe52f3608bb24022f5568a79c094aaf759f8baa08fa89302fa66971e61de64cdbb8e9c7d125a48296780942a5445ccbcd0010bd3d0af6ed0e33705d301c0240f7f23e8f74ac82df1eedf3b75ea3765bb8e1e96c72712d8edd0cb67b6e33a4a1596d0745cce42f700e694a128b", "1a4", "-c087ecd899d5d1c288b018c1d48f1ad2d0ebc6db3ef523c2c1fc2eb7781cf240e0e8b5db9477fb4e727fe52f3608bb24022f5568a79c094aaf759f8baa08fa89302fa66971e61de64cdbb8e9c7d125a48296780942a5445ccbcd0010bd3d0af6ed0e33705d301c0240f7f23e8f74ac82df1eedf3b75ea3765bb8e1e96c72712d8edd0cb67b6e33a4a1596d0745cce42f700e694a128b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "c5ef326f34f213ab86443e07cb504f3f43a0c256a2d7f37ad91e4462eac4b6b03aae29b5342ad4ebdf5d4e7ea48e33b5f5817b4b360563912f66a50bd56e98173e050dc6ae9fbf7ff97a4777d272b4291321570ed5d8c2c614af95a9fee780d7fe10d059f9520cf5761dc70ec82fef4054046fd84c2c0a2c402cab0b47fa4021e199992ff56347627f73b2e21f32db0647a58aad1bbb", "0", "c5ef326f34f213ab86443e07cb504f3f43a0c256a2d7f37ad91e4462eac4b6b03aae29b5342ad4ebdf5d4e7ea48e33b5f5817b4b360563912f66a50bd56e98173e050dc6ae9fbf7ff97a4777d272b4291321570ed5d8c2c614af95a9fee780d7fe10d059f9520cf5761dc70ec82fef4054046fd84c2c0a2c402cab0b47fa4021e199992ff56347627f73b2e21f32db0647a58aad1bbb", .Okay}, + {.Shl, "-cb9d982cb531764f60933b8fa22a7dacb57c8122b03979b710ce66e453606caceb0e8c6ef4a37ac3dcccff459dbde4a168ca8884e5ba5725dca82ca1ef21ec4440f1f1a8998f7c657448e1e6f2078a042fe65cc535f1f27fa576994c25bfbd56954569c3d4bfd7f4032d38e36713d310623962d6b601c2ed3f67e4ae930821ce6555a5a3d283a8fe343598887826a01291eb2060cfca", "21c", "-cb9d982cb531764f60933b8fa22a7dacb57c8122b03979b710ce66e453606caceb0e8c6ef4a37ac3dcccff459dbde4a168ca8884e5ba5725dca82ca1ef21ec4440f1f1a8998f7c657448e1e6f2078a042fe65cc535f1f27fa576994c25bfbd56954569c3d4bfd7f4032d38e36713d310623962d6b601c2ed3f67e4ae930821ce6555a5a3d283a8fe343598887826a01291eb2060cfca000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "16d28ed703e234dd0e025f4ee2174483154e6ae900d109b7a5bc9ed30e34970708c38999b7de494078a6ffe827c71f373a01946051be958c3f078af18c88546d8f6bf4cc5147dec029e4563626fdcbfe033c22732214f94138f52d4a664f5f3d13c55492c16c8a5aff9335e00bf4e268bc493a49cdca8f2d604832d64c8b0a1e4c3c23211125f8dd32dc192660a93b29fc50b191cb20", "258", "16d28ed703e234dd0e025f4ee2174483154e6ae900d109b7a5bc9ed30e34970708c38999b7de494078a6ffe827c71f373a01946051be958c3f078af18c88546d8f6bf4cc5147dec029e4563626fdcbfe033c22732214f94138f52d4a664f5f3d13c55492c16c8a5aff9335e00bf4e268bc493a49cdca8f2d604832d64c8b0a1e4c3c23211125f8dd32dc192660a93b29fc50b191cb20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "a1ed5e6501a54bbdde148555b71f748a7d7a293b13943825c077b9027cb85b40aea02f0c214c671c2048eaf10a547848dbbec7968f0a4336982f332728418bf85ff024fd6ffd064397c74dd18cb6fd12106aaf5879166313cadaff16d375f850e67534329a62df11f5d04ede2d6cc2c065398b63181a99e906bf772c378273fcd1537843323eacb1ae3c4344f6555d39fe887d3dc1ce", "258", "a1ed5e6501a54bbdde148555b71f748a7d7a293b13943825c077b9027cb85b40aea02f0c214c671c2048eaf10a547848dbbec7968f0a4336982f332728418bf85ff024fd6ffd064397c74dd18cb6fd12106aaf5879166313cadaff16d375f850e67534329a62df11f5d04ede2d6cc2c065398b63181a99e906bf772c378273fcd1537843323eacb1ae3c4344f6555d39fe887d3dc1ce000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-25059e993a7e22f4719c9d5a3b440c7b559029d0f03ee6559fce6641f034c3d109ba46673cfe8df8b42da0683b7d1757d485db1f2c0394d90aa3ec7f5c355a476752a7ca80d63532b84102589b0ae8bfda0e7c030a54628cc2ac2d82a3958dad0abf261ee0f444b87b921de615f383ae7d39510060883ed4eacaf70584a17a8284e8cba82225eb1d5543de3f6eb5fdfc539f92861f2e", "168", "-25059e993a7e22f4719c9d5a3b440c7b559029d0f03ee6559fce6641f034c3d109ba46673cfe8df8b42da0683b7d1757d485db1f2c0394d90aa3ec7f5c355a476752a7ca80d63532b84102589b0ae8bfda0e7c030a54628cc2ac2d82a3958dad0abf261ee0f444b87b921de615f383ae7d39510060883ed4eacaf70584a17a8284e8cba82225eb1d5543de3f6eb5fdfc539f92861f2e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "caf7017ace9b96672b926c48009c38b181de36180d176172008e60f537545c68c9921eac469d3e8e723054b5f5400410cfd434d02e0dc4b3d37110243167feb4b185a9885b58299a8ff78ba3a9a42e73629459523da367dae1dd1efa1c4157a72c5addd378de36eeaebcd2fe4c286c09030f50534ff3c28810d60301280ddaa16b434be016cf73c17620e139d5f4dce41f00550e022d", "21c", "caf7017ace9b96672b926c48009c38b181de36180d176172008e60f537545c68c9921eac469d3e8e723054b5f5400410cfd434d02e0dc4b3d37110243167feb4b185a9885b58299a8ff78ba3a9a42e73629459523da367dae1dd1efa1c4157a72c5addd378de36eeaebcd2fe4c286c09030f50534ff3c28810d60301280ddaa16b434be016cf73c17620e139d5f4dce41f00550e022d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-fc69c62e66102d58da55450dd5bb33e774d651a48c7f81d5da108c706a2659ca0a37c2535efa992b6f96f82e814ef62470a42df2a3f9658db964bb4202bc58b547ae41ad00e8a890787049438d87ec33c4126a36dca42edb7db9245ec5829f91ed23444464af7cf72a690078f5b743382368709537b62eb1e159d6e07911dbdb1ac7d23871c8246393e5ff4f72ebfbecc8a44375f19b", "0", "-fc69c62e66102d58da55450dd5bb33e774d651a48c7f81d5da108c706a2659ca0a37c2535efa992b6f96f82e814ef62470a42df2a3f9658db964bb4202bc58b547ae41ad00e8a890787049438d87ec33c4126a36dca42edb7db9245ec5829f91ed23444464af7cf72a690078f5b743382368709537b62eb1e159d6e07911dbdb1ac7d23871c8246393e5ff4f72ebfbecc8a44375f19b", .Okay}, + {.Shl, "e8df231efb5250778534699e63d2676a9868f6d8fe012c60ec47f607c260f59a7960bc00b9b7e8a23150fbbcfe65e9bb491eb3c15d03ca8bf1a3d0fadb9c3688623ddc54381ac8f7cc014e1ee461147c455740d6a5ff2daed273d91334df893c69a991f06898097bd6964a23670c2b3acfefa6e5d0779306d5a3fb0f258a7776c5da41093903cea71a3875b5e796680af2e5ba0274fb", "b4", "e8df231efb5250778534699e63d2676a9868f6d8fe012c60ec47f607c260f59a7960bc00b9b7e8a23150fbbcfe65e9bb491eb3c15d03ca8bf1a3d0fadb9c3688623ddc54381ac8f7cc014e1ee461147c455740d6a5ff2daed273d91334df893c69a991f06898097bd6964a23670c2b3acfefa6e5d0779306d5a3fb0f258a7776c5da41093903cea71a3875b5e796680af2e5ba0274fb000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-99aa2298dfbf12c3d3bd33b8e5143dacc06488cd9ff215b7f83860f9c83d602a0d5890ecb5d2482c43ce675b10b7888cd73dc591f8fdb31be57e94cbac1fe5cef8021611ec7367c8ed6d5a8627506307bd1982df1705fb1bcf7a23bf49956fc982315742f906bf2f643a5eff6ef4962ca3fccd2c2b32298428fda297da3f8c1ac1806f789237ff72a5893bed81b97d526b8027ad319e", "f0", "-99aa2298dfbf12c3d3bd33b8e5143dacc06488cd9ff215b7f83860f9c83d602a0d5890ecb5d2482c43ce675b10b7888cd73dc591f8fdb31be57e94cbac1fe5cef8021611ec7367c8ed6d5a8627506307bd1982df1705fb1bcf7a23bf49956fc982315742f906bf2f643a5eff6ef4962ca3fccd2c2b32298428fda297da3f8c1ac1806f789237ff72a5893bed81b97d526b8027ad319e000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-b313030a8e626ea62ac0a8eb8f2bca71aac17b6d759608e8631297c4aa9cc830aebf5654cee59c75f5d711b775caf059a771a55c482f28cef81ae731c45114f68b5fa220f2c426e76bdb6c4e5c13aad1e18758838d054067d705d2c17f4616cd3bdc23816518cd253051a917b60a7fed89955199f54f77ce9e344f60d3661852f88158367568d61f71b3ef45c18ed3fc7ac91241df01", "0", "-b313030a8e626ea62ac0a8eb8f2bca71aac17b6d759608e8631297c4aa9cc830aebf5654cee59c75f5d711b775caf059a771a55c482f28cef81ae731c45114f68b5fa220f2c426e76bdb6c4e5c13aad1e18758838d054067d705d2c17f4616cd3bdc23816518cd253051a917b60a7fed89955199f54f77ce9e344f60d3661852f88158367568d61f71b3ef45c18ed3fc7ac91241df01", .Okay}, + {.Shl, "e8c8161d4be564e6caa2238df86437f7b83ef6bd82c7d4c3856f4cd2b7376783c204380ad637cd83abccecf32c0c80f8cdf864b049f383e62d631e9f5c5985993263c2540b0021ccde73924a7504174f6ccf0e24ff1caa299bf79fa1f7974613e5b41be357d4f66172d0472331899a5c12ce8e163391e1c795182b3eb0fe456659bfa1b9c2d6c51849816bc924a28c5b7dd95c384807", "f0", "e8c8161d4be564e6caa2238df86437f7b83ef6bd82c7d4c3856f4cd2b7376783c204380ad637cd83abccecf32c0c80f8cdf864b049f383e62d631e9f5c5985993263c2540b0021ccde73924a7504174f6ccf0e24ff1caa299bf79fa1f7974613e5b41be357d4f66172d0472331899a5c12ce8e163391e1c795182b3eb0fe456659bfa1b9c2d6c51849816bc924a28c5b7dd95c384807000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "70d06cc5e00bf5afa87090d30f6c9186ca0f522fc6607591d1352377f493029e43345a0bc432fed1267356670d401f016c5701e02ef611f6dcee43d7bce5f746d65f86aa53a1fbf83e8cba23b1e903550a242e867ae9ef5fc795ee1ff61298c55964a1d5144f1a172b41e8220ff77ea313c2b51367997161ba8861cd3a2ae134ed746627dfb3a71a00bd5284518cbb2ccee16f328796", "0", "70d06cc5e00bf5afa87090d30f6c9186ca0f522fc6607591d1352377f493029e43345a0bc432fed1267356670d401f016c5701e02ef611f6dcee43d7bce5f746d65f86aa53a1fbf83e8cba23b1e903550a242e867ae9ef5fc795ee1ff61298c55964a1d5144f1a172b41e8220ff77ea313c2b51367997161ba8861cd3a2ae134ed746627dfb3a71a00bd5284518cbb2ccee16f328796", .Okay}, + {.Shl, "-aec26ad426d58f990f84317c7bcb5cf47b239f51c07e1b6eb3d0388ec398bb4e74f78e2ab126711e4f63c9d03e6b09f23849fe6b74a6bcfba67594e5aa310d633272a6e88fa99105c21a0f55d706a49ad487d3088e52637e19d179da67c6296bd3748858e1209cc8481ab536f9c1589375f7e9aed722c26c4e39ae51d40956fef13a9a1eb688d6a138ecfd2fe8ad684323c06b962816", "f0", "-aec26ad426d58f990f84317c7bcb5cf47b239f51c07e1b6eb3d0388ec398bb4e74f78e2ab126711e4f63c9d03e6b09f23849fe6b74a6bcfba67594e5aa310d633272a6e88fa99105c21a0f55d706a49ad487d3088e52637e19d179da67c6296bd3748858e1209cc8481ab536f9c1589375f7e9aed722c26c4e39ae51d40956fef13a9a1eb688d6a138ecfd2fe8ad684323c06b962816000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-9d4a2c523d1523bc7bafee7926e74458f20f204e3fcc96e74258d56797a80910994ee09356bed0d726c1167cccff23915a96bdc1f97d412a2166408a258d686d9b936cf87d928dfaf3bf7feefe764fc800e2c1553c5634b8eb558b6b9dc4da0c8cfd8cca4a85d50c918583d6d5f78c7c8d8fa24c6301c296c44fe05259b602472b3a541f6c5afe5ca4f1a2c4373d086cea65ef4399eb", "12c", "-9d4a2c523d1523bc7bafee7926e74458f20f204e3fcc96e74258d56797a80910994ee09356bed0d726c1167cccff23915a96bdc1f97d412a2166408a258d686d9b936cf87d928dfaf3bf7feefe764fc800e2c1553c5634b8eb558b6b9dc4da0c8cfd8cca4a85d50c918583d6d5f78c7c8d8fa24c6301c296c44fe05259b602472b3a541f6c5afe5ca4f1a2c4373d086cea65ef4399eb000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "684cc85b99c4abab16a1baed0bc6e5d89f52ddedf5e1b1b6cb8b2ed8b4429afc0f70dd737c69c251189befdc6523c7454ce03751a644f586f2b0a33d49d216ced6ad772ded495bd52943f318d1b3565132dbb8412f05e40af497a3e3f340c6b469ced53ece87f57f2cf6036d8e87258081182317e60d4c004981acb9d80602bd00c162e4de39461b436b90259b8c87d303ea449900da", "258", "684cc85b99c4abab16a1baed0bc6e5d89f52ddedf5e1b1b6cb8b2ed8b4429afc0f70dd737c69c251189befdc6523c7454ce03751a644f586f2b0a33d49d216ced6ad772ded495bd52943f318d1b3565132dbb8412f05e40af497a3e3f340c6b469ced53ece87f57f2cf6036d8e87258081182317e60d4c004981acb9d80602bd00c162e4de39461b436b90259b8c87d303ea449900da000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "5bef6cedb8c7299776213bec5bb63bd905a5a75a66160f57937120638b6a75f8cc82c587fa5cd54713f6382d80bd874ce08d6d95e95b260f4d6ec5fc6ed8b0e44cbbe612d0fcc23e09ac1dda309c74b4512594e5052c580dfab28467897cacc4479d3a135a118bb872672b57f8c91cf81e63754ad92b718268bd4d7378840645e56caaeef3eeb689ddc386e7d0fb445c306ed050c965", "1e0", "5bef6cedb8c7299776213bec5bb63bd905a5a75a66160f57937120638b6a75f8cc82c587fa5cd54713f6382d80bd874ce08d6d95e95b260f4d6ec5fc6ed8b0e44cbbe612d0fcc23e09ac1dda309c74b4512594e5052c580dfab28467897cacc4479d3a135a118bb872672b57f8c91cf81e63754ad92b718268bd4d7378840645e56caaeef3eeb689ddc386e7d0fb445c306ed050c965000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-db047a893690d39479869703998efccad57fa39e2e7ca1edb84223a1d38cb2f02e0fd9af09ebba432aaafa96f4b5a7b0ae6510fc49a9925eff7d7c77eae9050ce7d9b285266bba9387313eee723700730d1a68525656824696f536fe3947cfcd4d1c78c2f4317f790e36277a8693c0e3e00d9aca8628d14f0f88f485523d5007bd6cb9c1f2abb91a54816091192fdf61d79b77bad052", "1e0", "-db047a893690d39479869703998efccad57fa39e2e7ca1edb84223a1d38cb2f02e0fd9af09ebba432aaafa96f4b5a7b0ae6510fc49a9925eff7d7c77eae9050ce7d9b285266bba9387313eee723700730d1a68525656824696f536fe3947cfcd4d1c78c2f4317f790e36277a8693c0e3e00d9aca8628d14f0f88f485523d5007bd6cb9c1f2abb91a54816091192fdf61d79b77bad052000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-489d875e5005b319f2e1a2b90fe951666268ef4079d55872b875999b1479ed4287f347cb4a38b7894fbc01bed8b03595a0dc25494b1bc9243dba8b5b112dbad3b3d416395327cb2fa60c741d6323a52cf1934dbb34a21111cd8eb93aa5cb099e9a33a423249c763b38a6caeba45638f356a0dad7acb2f83d5ac2d240c1900c2591de54443d8f55ad4c80887278608d911b7c0d8d9297", "0", "-489d875e5005b319f2e1a2b90fe951666268ef4079d55872b875999b1479ed4287f347cb4a38b7894fbc01bed8b03595a0dc25494b1bc9243dba8b5b112dbad3b3d416395327cb2fa60c741d6323a52cf1934dbb34a21111cd8eb93aa5cb099e9a33a423249c763b38a6caeba45638f356a0dad7acb2f83d5ac2d240c1900c2591de54443d8f55ad4c80887278608d911b7c0d8d9297", .Okay}, + {.Shl, "-a91f21dc9fd87b7af4423eb82c6945990c6924a611109661a2510c727991cecd98b63960a69fe338da6026b9da7cf5364be860c116511b6ab7ce592ec005776fb9a1423c20b23c2cab8b618cd1f57b54b1b0e0243cf5e0fe34d3b6b4e13ccb44e4126a876da50fd3e699a660d722ee52105f55ef4eb1438872f66df4f160244fe29d5facd4abe76acd74c0d02fd254d22aa9e47fa27e", "78", "-a91f21dc9fd87b7af4423eb82c6945990c6924a611109661a2510c727991cecd98b63960a69fe338da6026b9da7cf5364be860c116511b6ab7ce592ec005776fb9a1423c20b23c2cab8b618cd1f57b54b1b0e0243cf5e0fe34d3b6b4e13ccb44e4126a876da50fd3e699a660d722ee52105f55ef4eb1438872f66df4f160244fe29d5facd4abe76acd74c0d02fd254d22aa9e47fa27e000000000000000000000000000000", .Okay}, + {.Shl, "9ca15b6953c7671a05525af8c1d94075e883d5f0b90886a2c8cb5b95b0c3290d0ad7fa9a77e769f1bc5772e2d5b6a719f1e32341774fc4004cd5621a138b400cc0f07bfe9328628612db1d31a4b43ca5d2fc833b7f4ae17437bcbb5b9d83071ca820bd2443f2bffb4643132ae742de9153d7fc7ccec18f3b09864e5a5d0cc90f3c0d07f417e3dc8ef544dfa662d4c6c2b5f189d283a2", "12c", "9ca15b6953c7671a05525af8c1d94075e883d5f0b90886a2c8cb5b95b0c3290d0ad7fa9a77e769f1bc5772e2d5b6a719f1e32341774fc4004cd5621a138b400cc0f07bfe9328628612db1d31a4b43ca5d2fc833b7f4ae17437bcbb5b9d83071ca820bd2443f2bffb4643132ae742de9153d7fc7ccec18f3b09864e5a5d0cc90f3c0d07f417e3dc8ef544dfa662d4c6c2b5f189d283a2000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "a4712474678afc603ac0f4d3caa9bbd14d924316a7fd331148ebf37a65ab6096094e46f2f44fe5452acab5b73309ce090d1cd5bdfdc459e830fe78cbc532f0bccaf7ef4a6434db2fa299c4159da9c768f0bea997f1669774e856278e3b9e315b8bc093d13ea38161c2b3c92f18c2e65dfa7d3021c6bbee3245b6875f3bc6b3fc47cdec3008c02951a44c623f8b90a81c38c781b75628", "f0", "a4712474678afc603ac0f4d3caa9bbd14d924316a7fd331148ebf37a65ab6096094e46f2f44fe5452acab5b73309ce090d1cd5bdfdc459e830fe78cbc532f0bccaf7ef4a6434db2fa299c4159da9c768f0bea997f1669774e856278e3b9e315b8bc093d13ea38161c2b3c92f18c2e65dfa7d3021c6bbee3245b6875f3bc6b3fc47cdec3008c02951a44c623f8b90a81c38c781b75628000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-b7b1932cea63ae61cca8aba28e02bdadcb7ddf26c5cceed1195d4f5421c77206104848e65d69cf0ba1e9c89661eb39a3eab73e53621dd43d0c4d118cbf440704b3aeb3877836d1774d7cb20b2c1d6542511941d175810edc3a674925c74076549b030c21bd4c331c4d48f83b772fe277732cb22f3ce98b2a78fc936d4b24d4954924f646bdb860b812dbb628d6d80a5b33fa501cfc0d", "1e0", "-b7b1932cea63ae61cca8aba28e02bdadcb7ddf26c5cceed1195d4f5421c77206104848e65d69cf0ba1e9c89661eb39a3eab73e53621dd43d0c4d118cbf440704b3aeb3877836d1774d7cb20b2c1d6542511941d175810edc3a674925c74076549b030c21bd4c331c4d48f83b772fe277732cb22f3ce98b2a78fc936d4b24d4954924f646bdb860b812dbb628d6d80a5b33fa501cfc0d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "54b2e4422be21d5ebbb067b712530a250eda26adbf94bee58f7a97b4825be85c327e1ca105be6cacc636abfbc352d78321a59a74011e524f94f662320fa74ec97ad0aabebcb94d7a6f9360c122f1565bf63d11538818aef4a9b2aa98fe287dc49ac886d43a255ab4618f105bfc2fcfe997083d51e95b0ac8911c8097629f131b5a7e03f96f287e259db163fe34f11982b8b39d7707e2", "f0", "54b2e4422be21d5ebbb067b712530a250eda26adbf94bee58f7a97b4825be85c327e1ca105be6cacc636abfbc352d78321a59a74011e524f94f662320fa74ec97ad0aabebcb94d7a6f9360c122f1565bf63d11538818aef4a9b2aa98fe287dc49ac886d43a255ab4618f105bfc2fcfe997083d51e95b0ac8911c8097629f131b5a7e03f96f287e259db163fe34f11982b8b39d7707e2000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "6f56e1943cdc6c995f2a21d1c436570930dac219a6af0535e21bfbd2da152bc3e835672f9e60d147264f9931c99c0f1f7920783b84e52de17ceabb5a9aaeb3802bf044e24a0697db096aaf4dcb0a1d43636e516b8a515cdd672a756e6d69966dae0aee255e1c411cb9305860f1aecb848522e318ba64da6020847748106948e273a1abc1de49607b61ce3b4ce177a5d98702cca28adc", "78", "6f56e1943cdc6c995f2a21d1c436570930dac219a6af0535e21bfbd2da152bc3e835672f9e60d147264f9931c99c0f1f7920783b84e52de17ceabb5a9aaeb3802bf044e24a0697db096aaf4dcb0a1d43636e516b8a515cdd672a756e6d69966dae0aee255e1c411cb9305860f1aecb848522e318ba64da6020847748106948e273a1abc1de49607b61ce3b4ce177a5d98702cca28adc000000000000000000000000000000", .Okay}, + {.Shl, "5b9e6dc3397bebedd093cf90cd6187db58f983d4b192752e9248f5d54cb44cb5d4e40a82701b7f23007718424194dd4cf904a681c73acdf4af6e388ad4fdc0fb8ea3c3d8d2a3da0c2abbcba0fd1590d80c50ee6d35d786fbd536a764867197ec4f1f44b3ab31f74bfc7b5d0102d1b012a9a92c81f83c1e59ca30d0269617c3c063f02147efc4f241437b692e1630017c791bcd4459c8", "258", "5b9e6dc3397bebedd093cf90cd6187db58f983d4b192752e9248f5d54cb44cb5d4e40a82701b7f23007718424194dd4cf904a681c73acdf4af6e388ad4fdc0fb8ea3c3d8d2a3da0c2abbcba0fd1590d80c50ee6d35d786fbd536a764867197ec4f1f44b3ab31f74bfc7b5d0102d1b012a9a92c81f83c1e59ca30d0269617c3c063f02147efc4f241437b692e1630017c791bcd4459c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "129605e701e2049fcb76a85e080af544557320cdd82cfe4f22ff3d632e32ecd0346d427aab99f430b4fa150de69859240a9bc111e57281c34cc45bf0628fa5bd6a38528d8cfd12b09d24e82f7e73d3125ff55ef67eefe601e95b34cb6830d6532eee8db1d941165a8c990e8f2d583d922d72034ab791ad96f035a52b61ac082105a0e8774a18565de76f9fd5e130eac00c23324eceb0", "168", "129605e701e2049fcb76a85e080af544557320cdd82cfe4f22ff3d632e32ecd0346d427aab99f430b4fa150de69859240a9bc111e57281c34cc45bf0628fa5bd6a38528d8cfd12b09d24e82f7e73d3125ff55ef67eefe601e95b34cb6830d6532eee8db1d941165a8c990e8f2d583d922d72034ab791ad96f035a52b61ac082105a0e8774a18565de76f9fd5e130eac00c23324eceb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "878862bc699880e255e4cb078173f055901bd9b9e9a87286437bf803457dfef8738eb1a323646b768abf63cf39288d44317b204478e486224fec9496cc735b5608b9a0d6906e85120dfb80d857081bbabe56940426c9765730604c6d9bcbb75268a3de559e7b596b03f8913c5107689eeceb48f09a97d7c30ea4bcf713e56e2cc89df0b39dea9ba5a8832802152f5af444cb3ca1b0a", "b4", "878862bc699880e255e4cb078173f055901bd9b9e9a87286437bf803457dfef8738eb1a323646b768abf63cf39288d44317b204478e486224fec9496cc735b5608b9a0d6906e85120dfb80d857081bbabe56940426c9765730604c6d9bcbb75268a3de559e7b596b03f8913c5107689eeceb48f09a97d7c30ea4bcf713e56e2cc89df0b39dea9ba5a8832802152f5af444cb3ca1b0a000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-bbdf2afbac51f95f49169e50620bc46aecbbd2e6b9a73996f2fc934ccb76e77902cbd3ae415f5755fec869fd29fb135bb5b5be47a75ceee8e13100478fd257f6b5b4d494e1a4eeb865c6cd41e9609a371861cceaaa823863d804b05a735a09da787d747d86c9f120b5538edaba995d5351fed9201f2c1d34ea9507c285562816a652536bbf07a125994da912cb11a2bd494fef639259", "78", "-bbdf2afbac51f95f49169e50620bc46aecbbd2e6b9a73996f2fc934ccb76e77902cbd3ae415f5755fec869fd29fb135bb5b5be47a75ceee8e13100478fd257f6b5b4d494e1a4eeb865c6cd41e9609a371861cceaaa823863d804b05a735a09da787d747d86c9f120b5538edaba995d5351fed9201f2c1d34ea9507c285562816a652536bbf07a125994da912cb11a2bd494fef639259000000000000000000000000000000", .Okay}, + {.Shl, "-a1ecbb163431ab2379e25c82ff24e74c8a68935b134fafe4457f44c8d2031c8a9bac846c5ebd3aaad1ae7cdf05ffa10cad1b165857dd7bd26e19f1d47221f5f0b44ec73d3eb1bef4af6b354e685e3201ab75e6f4ac7ffc03d5601d26a63ff21cfd952409e372b89e28b654cfa5b286822703d5f5dcfe1fed34b213fbc38b720e85765af498cf5c9fa5c5911619e4eee1dc3256d75fc2", "f0", "-a1ecbb163431ab2379e25c82ff24e74c8a68935b134fafe4457f44c8d2031c8a9bac846c5ebd3aaad1ae7cdf05ffa10cad1b165857dd7bd26e19f1d47221f5f0b44ec73d3eb1bef4af6b354e685e3201ab75e6f4ac7ffc03d5601d26a63ff21cfd952409e372b89e28b654cfa5b286822703d5f5dcfe1fed34b213fbc38b720e85765af498cf5c9fa5c5911619e4eee1dc3256d75fc2000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "e350aaeb899d3dde1737e8864d4f94a0535772d1480ebeb04fba17a4b38afd19b63fc4d700504392e3c6966640d8651e56cbe2d23f0ca27bba62b94dd47348f935ecefe5ba946b8e0cda411b1e464aed7619bceba392701595771cf0a7c94d0c9031dee20c281f71790f0407dddd176ad3479e84a50861869774c9d88950e216229233ec710ec2887321e35698a1efa85cd045d454fc", "78", "e350aaeb899d3dde1737e8864d4f94a0535772d1480ebeb04fba17a4b38afd19b63fc4d700504392e3c6966640d8651e56cbe2d23f0ca27bba62b94dd47348f935ecefe5ba946b8e0cda411b1e464aed7619bceba392701595771cf0a7c94d0c9031dee20c281f71790f0407dddd176ad3479e84a50861869774c9d88950e216229233ec710ec2887321e35698a1efa85cd045d454fc000000000000000000000000000000", .Okay}, + {.Shl, "-283a4d2f5cc7f45d9cacb788a8c4a24d6dbad4cb2543e7f46dfbce23db4afd624385e9128c1e3f05f8572a20c2a2d5b879acfb873e7e7d081f5218ffa1078e6a2077139b72840b7d1f1048dffcd507d196e502d6e320fe541332522913e98e9c180a29f8d5b3410204252cacc114655695a3754a946b0cce46cc641af75ee9615d2e481b3d046839d1150200e18d14073b005500ef86", "b4", "-283a4d2f5cc7f45d9cacb788a8c4a24d6dbad4cb2543e7f46dfbce23db4afd624385e9128c1e3f05f8572a20c2a2d5b879acfb873e7e7d081f5218ffa1078e6a2077139b72840b7d1f1048dffcd507d196e502d6e320fe541332522913e98e9c180a29f8d5b3410204252cacc114655695a3754a946b0cce46cc641af75ee9615d2e481b3d046839d1150200e18d14073b005500ef86000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-242d4304153c0a713c03f3bcd73bd6cac7c0dadc2a0ac390f917611ae6b0c09f08661aea64ca64fae2b5ae06c5ed926330c50815f2b914ba4e2948ec35820cc9b49fc2acaeaecaea0815b0b48f66b5438513299974fff396b91deb751cd67a212ce1356e7edf206c26ecb5c5ad7c157fa8278f2f771d99f55e271bc8424f6e11b5af1b8a080274cb6ff037cb35a6ba2c699472960e8", "3c", "-242d4304153c0a713c03f3bcd73bd6cac7c0dadc2a0ac390f917611ae6b0c09f08661aea64ca64fae2b5ae06c5ed926330c50815f2b914ba4e2948ec35820cc9b49fc2acaeaecaea0815b0b48f66b5438513299974fff396b91deb751cd67a212ce1356e7edf206c26ecb5c5ad7c157fa8278f2f771d99f55e271bc8424f6e11b5af1b8a080274cb6ff037cb35a6ba2c699472960e8000000000000000", .Okay}, + {.Shl, "-752c725ed8b55238f568c74d6360f8ff857d7004395dc2fd7522c4eeb8ee12dea42ba0e24a24829b67077fedff3af70f7d15d151438d4d52d008d65a384d4ce67ac202c87fcbe4bd7051783de20fc17b2ce0e717a137e54392443664a5dad860431afab406ce1647db4dc52748b1748a8746c688c32bd2d36e180c693435fb8e5452397822db3eae3179bd6452ccaceae207f7996079", "0", "-752c725ed8b55238f568c74d6360f8ff857d7004395dc2fd7522c4eeb8ee12dea42ba0e24a24829b67077fedff3af70f7d15d151438d4d52d008d65a384d4ce67ac202c87fcbe4bd7051783de20fc17b2ce0e717a137e54392443664a5dad860431afab406ce1647db4dc52748b1748a8746c688c32bd2d36e180c693435fb8e5452397822db3eae3179bd6452ccaceae207f7996079", .Okay}, + {.Shl, "26b0b769569cee29836c78e5d2a3ddd209204b0b1c078ff9bd70b1a78bef59f51e20ede042098147045477416b647f49e907da0592d3e1924ba64b650e9c779ea78576583ad53cfaa09441ad0be6a5ee82eddc31d5ae493bcb3c55398d537a1488685bb8663af881c6c4c177047c67d7240c4deff002defd8dcbe6339eb67c1bd214716d1cd9e567c3a671685ff0b775bd164ccaa302", "21c", "26b0b769569cee29836c78e5d2a3ddd209204b0b1c078ff9bd70b1a78bef59f51e20ede042098147045477416b647f49e907da0592d3e1924ba64b650e9c779ea78576583ad53cfaa09441ad0be6a5ee82eddc31d5ae493bcb3c55398d537a1488685bb8663af881c6c4c177047c67d7240c4deff002defd8dcbe6339eb67c1bd214716d1cd9e567c3a671685ff0b775bd164ccaa302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "9d4b87d4be552a7dccbe60079a3c51d35b37009baac13f15de6358603ab1334b82bcbd9a0965f6f31ec979c130c91c59a7843bd8e7cc47f633fe0b5bd41cd1979750dd7b52023b51d473ccb47f30d215af17039e880230d51a854c3b88cf4fcb7e946dd436c52d718e89f78ba9e0cba464ac575d86f159214c26a50de10c9f235758d47ea980e6c135a897d062993dd2e00765c0627f", "1e0", "9d4b87d4be552a7dccbe60079a3c51d35b37009baac13f15de6358603ab1334b82bcbd9a0965f6f31ec979c130c91c59a7843bd8e7cc47f633fe0b5bd41cd1979750dd7b52023b51d473ccb47f30d215af17039e880230d51a854c3b88cf4fcb7e946dd436c52d718e89f78ba9e0cba464ac575d86f159214c26a50de10c9f235758d47ea980e6c135a897d062993dd2e00765c0627f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "83ea2cfff8611356f4ca46ed0235384e0a5c904dd17a250e47d8c296324ddbcc1a74ac64414f0641554f47061af4cbfe768f774c25e4b68d0396508bf06bd4ef56045fee57a905081af79a41d0958064b696dd7c4844d7d8555db9900e8c4a34aa9c6e8190180949262c167b410d38953eceb126a30e7a2804f14a70729a25cc5989c2c250e7af1b434ae5bbbe82b3c211268ca57b32", "1e0", "83ea2cfff8611356f4ca46ed0235384e0a5c904dd17a250e47d8c296324ddbcc1a74ac64414f0641554f47061af4cbfe768f774c25e4b68d0396508bf06bd4ef56045fee57a905081af79a41d0958064b696dd7c4844d7d8555db9900e8c4a34aa9c6e8190180949262c167b410d38953eceb126a30e7a2804f14a70729a25cc5989c2c250e7af1b434ae5bbbe82b3c211268ca57b32000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-e67b3013880c14877714a79f3a3f1cd6d69dbc73740ad68d5d71b631f6ff8b9dc1feb2671ce7c08b0103ff6756a90720962430f5b330b616fb8176eb46d72eb0a2940dd079210378a096e5ae560711395a907eb83328e186590434a12ea1467c036f8eed2ee484b5e66d5e615f605724634f38733c34f785a62d71341c97e485aa567759545728680994160170b066a29c398675baea", "3c", "-e67b3013880c14877714a79f3a3f1cd6d69dbc73740ad68d5d71b631f6ff8b9dc1feb2671ce7c08b0103ff6756a90720962430f5b330b616fb8176eb46d72eb0a2940dd079210378a096e5ae560711395a907eb83328e186590434a12ea1467c036f8eed2ee484b5e66d5e615f605724634f38733c34f785a62d71341c97e485aa567759545728680994160170b066a29c398675baea000000000000000", .Okay}, + {.Shl, "-d0b079291ccc8cfe14590687b055f674279e5295284fb95e4a81d4a0b427164693732fc5d6f661e30a4079650f20aba491c2ad95a262f14131568b4066a4ce562e0b4c5048d0600fce229fc36a8dc27613124e40da97000538702de500869a93c79fe30177540db370e24399ea601c0844131f92637ea2c15f44c4706ce7a9b9b7c4bea2c2d8cd56ab5ee2bc2d26d9fac89737795aa5", "12c", "-d0b079291ccc8cfe14590687b055f674279e5295284fb95e4a81d4a0b427164693732fc5d6f661e30a4079650f20aba491c2ad95a262f14131568b4066a4ce562e0b4c5048d0600fce229fc36a8dc27613124e40da97000538702de500869a93c79fe30177540db370e24399ea601c0844131f92637ea2c15f44c4706ce7a9b9b7c4bea2c2d8cd56ab5ee2bc2d26d9fac89737795aa5000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "c2a7310cce14c9f8c2a1a03d629a45f31f60053ea0ed9d3a4970e9c4a584d39d7657cb19eecbf84a9992fdd6db2e4af7c3c55ae2e44b5499aad204da869480e6956455332f30cdaef89dfe1f274c872fd2e6fb2972e4465b60c511983d41513fcee2f492d55ccc06a586e365265f07c8c06a1280ed6c2d016c55a9da7cdaabd94fe8d28720e93ed50fa40e7aec724396f6ec8bd15dad", "258", "c2a7310cce14c9f8c2a1a03d629a45f31f60053ea0ed9d3a4970e9c4a584d39d7657cb19eecbf84a9992fdd6db2e4af7c3c55ae2e44b5499aad204da869480e6956455332f30cdaef89dfe1f274c872fd2e6fb2972e4465b60c511983d41513fcee2f492d55ccc06a586e365265f07c8c06a1280ed6c2d016c55a9da7cdaabd94fe8d28720e93ed50fa40e7aec724396f6ec8bd15dad000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-9a0585a3faac31552b56f2d77ef0eed4da3a7460050f37eb1957b7c5a9bc43abe3d254dbd21c4b70b9e2d3381ee8b005c456f6f6463f40182810befe56c9b7e4767d7f5f7639555f5a67c431b52e8b91f5fecfc6989e28f45bc121262a1a52262f1d220009abe8b6a495716ba1f72e4bc114ccee9be19d9afd67bb422489b23c11e0f3b8577ea18bac73ca036a81f411421dffb3412", "78", "-9a0585a3faac31552b56f2d77ef0eed4da3a7460050f37eb1957b7c5a9bc43abe3d254dbd21c4b70b9e2d3381ee8b005c456f6f6463f40182810befe56c9b7e4767d7f5f7639555f5a67c431b52e8b91f5fecfc6989e28f45bc121262a1a52262f1d220009abe8b6a495716ba1f72e4bc114ccee9be19d9afd67bb422489b23c11e0f3b8577ea18bac73ca036a81f411421dffb3412000000000000000000000000000000", .Okay}, + {.Shl, "-88ceaefd36dcac55c4542a53537cb1961645b1194817c9646371e1b054e1aea1afdc9748367bf7c1339b842c53d4b567aecb72e56585436cbb05499f9ef979b771f3bb0056d34dc33f0469f0c6369643815e994c118b51c25a7bdb17c4208573f3e8ef49758e8981f8c7488324d67065e3ae439e7229c76150501ff59057415ec4d368e087ae55e5893d97a08e9adca45db915bbe86a", "1e0", "-88ceaefd36dcac55c4542a53537cb1961645b1194817c9646371e1b054e1aea1afdc9748367bf7c1339b842c53d4b567aecb72e56585436cbb05499f9ef979b771f3bb0056d34dc33f0469f0c6369643815e994c118b51c25a7bdb17c4208573f3e8ef49758e8981f8c7488324d67065e3ae439e7229c76150501ff59057415ec4d368e087ae55e5893d97a08e9adca45db915bbe86a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-eabcbb2e2a0d73526b33dad70db2ce51873ad528454ca3e3d430f109cebb3201ea86e01bbd1a0fe274f149918f828574a6d5cc62fbd0af2ad5d6e0048c5deb9632f1edaefe07d852206039d0c9f9c7f184490f17883a67cfba61877e90a2daf2aeba30e12fa8f2c5f98c3457a46227e2efb5eb86f986d3fb53adfd2fec7375adbde1680bb555c290788bd4340e5c208129cd2ac61bd", "0", "-eabcbb2e2a0d73526b33dad70db2ce51873ad528454ca3e3d430f109cebb3201ea86e01bbd1a0fe274f149918f828574a6d5cc62fbd0af2ad5d6e0048c5deb9632f1edaefe07d852206039d0c9f9c7f184490f17883a67cfba61877e90a2daf2aeba30e12fa8f2c5f98c3457a46227e2efb5eb86f986d3fb53adfd2fec7375adbde1680bb555c290788bd4340e5c208129cd2ac61bd", .Okay}, + {.Shl, "d1a87885175d14470f358e3298c7e9b59241c972c79f1b33bcea3e1c078566e76d6fb306297b79e21114bab2ae528d4d767eb9c92cada2f143cf7cc3e7954c62c6ca1b88f8145a0923dcee66eab5a7b1798de135467b92f0cd4a924e06b0394f9409892ed995c7a25c41a6167dbb1b0d125ec67feedd6eb7f15c14180ac116df18dfc48c88c5c408b273d3755126a8113c7adb12af41", "1e0", "d1a87885175d14470f358e3298c7e9b59241c972c79f1b33bcea3e1c078566e76d6fb306297b79e21114bab2ae528d4d767eb9c92cada2f143cf7cc3e7954c62c6ca1b88f8145a0923dcee66eab5a7b1798de135467b92f0cd4a924e06b0394f9409892ed995c7a25c41a6167dbb1b0d125ec67feedd6eb7f15c14180ac116df18dfc48c88c5c408b273d3755126a8113c7adb12af41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-87d4503a248b178c7d5538a43dbf3b029c31156f162e2df94b455d7c591dff9b367ee829bdfd81d4afacd28e9254252a2baefe961ba328edf3207f3f5944a31ed400ebdb73a55bd35f93f61883911b1f298c3baba071a3dbb5fcf8540788971d175db449037b148db57c4b56bda1c5385fc3f432eb0a4a6a62fa8e05f8813e6eb0b4489a86153d952dfac0224cf96700e4b28567ea72", "3c", "-87d4503a248b178c7d5538a43dbf3b029c31156f162e2df94b455d7c591dff9b367ee829bdfd81d4afacd28e9254252a2baefe961ba328edf3207f3f5944a31ed400ebdb73a55bd35f93f61883911b1f298c3baba071a3dbb5fcf8540788971d175db449037b148db57c4b56bda1c5385fc3f432eb0a4a6a62fa8e05f8813e6eb0b4489a86153d952dfac0224cf96700e4b28567ea72000000000000000", .Okay}, + {.Shl, "34ff3e9109b6994b56632e0dde9f78d4d48fdf388c80d2b14ab778b5b63db57ef4a2fa124876833d45fb70c15243c809f85de4096caa1a9dfa96d61ebf85730da5e22a26c0cd118086779e740159de6f10fe536705bae602501d04e0dd8c7954673f32ea41368283ec6824ae11615a48c8e3861f3dc52e783f25dd78b52b3d99dbdffa5566d63d9efb1ecfe5b5fd7a745bd83f400250", "78", "34ff3e9109b6994b56632e0dde9f78d4d48fdf388c80d2b14ab778b5b63db57ef4a2fa124876833d45fb70c15243c809f85de4096caa1a9dfa96d61ebf85730da5e22a26c0cd118086779e740159de6f10fe536705bae602501d04e0dd8c7954673f32ea41368283ec6824ae11615a48c8e3861f3dc52e783f25dd78b52b3d99dbdffa5566d63d9efb1ecfe5b5fd7a745bd83f400250000000000000000000000000000000", .Okay}, + {.Shl, "-950e5a4cf31cd9b86bdd7e2aabca436405aaeb671119f7994abc7c1745413296537d68a085a43a1901cff668be82fd340e8c4a86a97b8a6db617f795711ca7fa5ce07c7c4837da7be653dd16ae35598610a140826f2bddc23dbc6f3ccd7d802173735b7346e5a664e1c658fd65aca15bedad671173cb6830e83b8817075f3359fb93e22e021dc0f1b974294200b6d800835ca6c3a31d", "258", "-950e5a4cf31cd9b86bdd7e2aabca436405aaeb671119f7994abc7c1745413296537d68a085a43a1901cff668be82fd340e8c4a86a97b8a6db617f795711ca7fa5ce07c7c4837da7be653dd16ae35598610a140826f2bddc23dbc6f3ccd7d802173735b7346e5a664e1c658fd65aca15bedad671173cb6830e83b8817075f3359fb93e22e021dc0f1b974294200b6d800835ca6c3a31d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "f7a12cd63e5b1f9dc2e527be1194dae9d37cc37871c006094f456381c9f7fa6fc5b56849863e325cbafc16b5abdb931b868fe7c28509a47c5e59604bf28ebc898cba97d7b5a57142abb5624f792bf96cdcad1d07ca05fd59242e12dfcfe2f2a7c6da50d3f035127b2c5126da329e617a5a3dc88d87b3887ff5430ebfa1c85c5fc0fca09a52be1b17b6789c12f37628922c8bfa39282e", "b4", "f7a12cd63e5b1f9dc2e527be1194dae9d37cc37871c006094f456381c9f7fa6fc5b56849863e325cbafc16b5abdb931b868fe7c28509a47c5e59604bf28ebc898cba97d7b5a57142abb5624f792bf96cdcad1d07ca05fd59242e12dfcfe2f2a7c6da50d3f035127b2c5126da329e617a5a3dc88d87b3887ff5430ebfa1c85c5fc0fca09a52be1b17b6789c12f37628922c8bfa39282e000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-1dd769103c1eff338e21b7eca4912c5ffe407f4002beb6aede180dd54c19f245f0fb439e75bd0ec64ec74653680a11c2302f0e09e0f7147b5c1ef2d66bd8d7b538823d823bf72e27cd47cad59f6b1b7fa9ff79a4fb0e3a2b9d7d6e9637b4a502eb3db0fcb5c2f7224df1c47053bc3c700e2ce6341af69fd7e798e58cb1789765934060cee12e7dc42c8fb3fc8c4da04a1be99a7b0b6d", "1e0", "-1dd769103c1eff338e21b7eca4912c5ffe407f4002beb6aede180dd54c19f245f0fb439e75bd0ec64ec74653680a11c2302f0e09e0f7147b5c1ef2d66bd8d7b538823d823bf72e27cd47cad59f6b1b7fa9ff79a4fb0e3a2b9d7d6e9637b4a502eb3db0fcb5c2f7224df1c47053bc3c700e2ce6341af69fd7e798e58cb1789765934060cee12e7dc42c8fb3fc8c4da04a1be99a7b0b6d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "7047b7bdb70e495b1b437aa0dd832925a73205a6c25c6ce6a7864604bd244782d2d16a920deaccbdf54b707ad6b9975b21d0dad9d718fe690bd9d8fc43b44b4c973976b1317105f462eb3440cdd00ffcc90a906c879ee58a86968021daab879b32d00a9bd131c1c556bee01b4f113a0c3e231fa4908c6378621d17019ce3a60267f6d3819f8e7b624d37aa4b2b19da3e2e78aeba1c9", "168", "7047b7bdb70e495b1b437aa0dd832925a73205a6c25c6ce6a7864604bd244782d2d16a920deaccbdf54b707ad6b9975b21d0dad9d718fe690bd9d8fc43b44b4c973976b1317105f462eb3440cdd00ffcc90a906c879ee58a86968021daab879b32d00a9bd131c1c556bee01b4f113a0c3e231fa4908c6378621d17019ce3a60267f6d3819f8e7b624d37aa4b2b19da3e2e78aeba1c9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shr, "1a507a041f8d14d77f7ec6568715c771af46f881834a93db69f2c3869dafeb9eb4d524b5fe209b2462e34b6ceac047a8e7b24580b4dd4e6af05f2e50a66db00b8eb27d595a42f9bf48ba1b4fececacbfed874be4e0257b3ff9dcc0f4f2b23dd4bb15a52c8ddb1f00c1aef38a5cee77cb5df859afadcc0df870c260bf5ea5c960fe8a3b08f002932527390306404e2a9ec3c9e8291e12", "21c", "1a507a041f8d14d77f7ec6568715c771af46f881834a93db69f2c3869dafeb9eb4d524b5fe209b2462e34b6ceac047a8e7b24580b4dd4e6af05f2e50a66db00b8eb27d595a42f9bf48ba1b4fececacbfed874", .Okay}, + {.Shr, "60b77fd652d876948d45c044737e06a6583e05862aa23138e26a1bafb7c4c78129e68a787c91c4e9d32b51eab386e52ef5a930bf137c50fb9fc9d41d98b6120381a2b7141c5bd07bac642b03b49a430ac624ed3670a050949357bc108dcccfb93d3c75e0998d10f56dcfe987299ba7397bdc11df2150ba88740ebebc879b6709074b19d59e08db3a7b8863f5dec74ada32a0ed3976f4", "12c", "60b77fd652d876948d45c044737e06a6583e05862aa23138e26a1bafb7c4c78129e68a787c91c4e9d32b51eab386e52ef5a930bf137c50fb9fc9d41d98b6120381a2b7141c5bd07bac642b03b49a430ac624ed3670a050949357bc108dcccfb93d3c75e0998d10f56dcfe987299ba7397", .Okay}, + {.Shr, "178625098edb65c8b3e9998b1d8896957c7e1fc7db94beafe23da53cc0904f74ae971502b6e297ceb37d59d0e479a07c23b21d5b4dd94cb2e39a5ff0dcd6ee6a45503362ad64ff019125ae4e4297be8cd00de4018f8ce38b3cdcc610109db21f5e95e21c57b83d5b186aa10c392b68794d1f11707c589759d0bfdd72ae87ca5ebd84845f2471fab4e116d1da5a3ad90b8b5a92c4d632", "f0", "178625098edb65c8b3e9998b1d8896957c7e1fc7db94beafe23da53cc0904f74ae971502b6e297ceb37d59d0e479a07c23b21d5b4dd94cb2e39a5ff0dcd6ee6a45503362ad64ff019125ae4e4297be8cd00de4018f8ce38b3cdcc610109db21f5e95e21c57b83d5b186aa10c392b68794d1f11707c589759", .Okay}, + {.Shr, "efbfd55a38b0c9972db2d78bf01503c9fdda76b83c791fe34ed15776310d04ff9296057a005f56adc968a5dddb37b44c9fccfd8c8a1fe3e97b992ee7ab44924d540f43162b610ca17c836ad59b1d447038a61815bae697e151bd9a6bcd447cfbf6d4ceb9818d4edbc5f2ec62d040463fba60a36ca657e1020e52b7c08918adb3209b0a302a4ecb7c193ce9e87e99ffe2de76aff00fef", "f0", "efbfd55a38b0c9972db2d78bf01503c9fdda76b83c791fe34ed15776310d04ff9296057a005f56adc968a5dddb37b44c9fccfd8c8a1fe3e97b992ee7ab44924d540f43162b610ca17c836ad59b1d447038a61815bae697e151bd9a6bcd447cfbf6d4ceb9818d4edbc5f2ec62d040463fba60a36ca657e102", .Okay}, + {.Shr, "37a97651516b27a29e87bbb018ea8307e0d6a1e838b36299f1c7d0781c71219dff735eb74953903fc62dcf9e92778d6d2d966a9b218d59b602161d99b884ce1bc77aa711910b9156fc399a84abf32791ba562bb0f7bf9d05ff52be4dd169889d0345a4b83e0bbe871367f7f6fad32af36508269f21b509794db10e2612aa32888f194155fc604a72b4575c97f119096281e78ce3fbd7", "78", "37a97651516b27a29e87bbb018ea8307e0d6a1e838b36299f1c7d0781c71219dff735eb74953903fc62dcf9e92778d6d2d966a9b218d59b602161d99b884ce1bc77aa711910b9156fc399a84abf32791ba562bb0f7bf9d05ff52be4dd169889d0345a4b83e0bbe871367f7f6fad32af36508269f21b509794db10e2612aa32888f194155fc604a", .Okay}, + {.Shr, "a39d3f58a9f65f88d29e83602d2b78cae9457bb5898280c1f3dd602ce069f36371a6c77d2be7becbac87afe5d9d0be467009f795a66da430084679a73e8148a7b9747fe9d9883dc830521555a69349e5e088d42807bcce2db009926de87bc3efd7c8ca148be0fbf4d5ee4b86a41ea0f1ff58fc15d11d7aea36e44743b1db6c513c0dec67031683d57cc32052fa77224d28af3eb3fdcb", "21c", "a39d3f58a9f65f88d29e83602d2b78cae9457bb5898280c1f3dd602ce069f36371a6c77d2be7becbac87afe5d9d0be467009f795a66da430084679a73e8148a7b9747fe9d9883dc830521555a69349e5e088d", .Okay}, + {.Shr, "7d055ee58b307c72a57f0f015c21093419cb630c55c1d600fb1bb7a3aa688bdcf254479b4ffb819ae8469fc06317063d367b67e382729b1a2819331fab27cbb7ade5d1626e9924f8a4c24a9172347db78a673a7bf270edc54d2820d6f708dbb5d2f4f818a24f1550b4a439e71a837675dbfde6fe7c3b94b39f731c8c24ba156ced6b1682cb53ae78d70ed0cbc5e3ba8f9d0f32496978", "78", "7d055ee58b307c72a57f0f015c21093419cb630c55c1d600fb1bb7a3aa688bdcf254479b4ffb819ae8469fc06317063d367b67e382729b1a2819331fab27cbb7ade5d1626e9924f8a4c24a9172347db78a673a7bf270edc54d2820d6f708dbb5d2f4f818a24f1550b4a439e71a837675dbfde6fe7c3b94b39f731c8c24ba156ced6b1682cb53ae", .Okay}, + {.Shr, "e7b8feac688f1d59150bd06fe345ca648e2b2aced515b3dbed9d831925c4b07c9da25bd41edddcbff58d9ce4b14526f55d8a6f42cf40fb2e042810217bb28fc4443afadb91c6bf8dad0d2fca0b1cd10aff81fdb776936f3ecc5d8e731ff92bdc5eec2bfcb15b33ced058e00ac831880374e29ebdb49761b0bbf074a0ad6046a712ddaf474e27cb0057aef1a382a01cad054c37be686", "168", "e7b8feac688f1d59150bd06fe345ca648e2b2aced515b3dbed9d831925c4b07c9da25bd41edddcbff58d9ce4b14526f55d8a6f42cf40fb2e042810217bb28fc4443afadb91c6bf8dad0d2fca0b1cd10aff81fdb776936f3ecc5d8e731ff92bdc5eec2bfcb15b33ced", .Okay}, + {.Shr, "90fd773dd0d300a9b06762db765ca4bca6ae792995e7e4a504d069760e9d36d3aec9071ecc424828d3575e71d918bb2588a975dde5862d80f87c9cd39953e20bb72b4eb37e31e3f0a80f9ca0c6462ac50400ea0d6b6fea89689fa1a97ddbdd8ab7644637893deb91942bd345232bc97d33dd5073bde8f635181693ae982325985f187ea102a30303ecf59e54aeb51f86e1d78a5c5329", "b4", "90fd773dd0d300a9b06762db765ca4bca6ae792995e7e4a504d069760e9d36d3aec9071ecc424828d3575e71d918bb2588a975dde5862d80f87c9cd39953e20bb72b4eb37e31e3f0a80f9ca0c6462ac50400ea0d6b6fea89689fa1a97ddbdd8ab7644637893deb91942bd345232bc97d33dd5073bde8f635181693ae9823259", .Okay}, + {.Shr, "17e318dcd167175fe1d0cae0e47988b382284e07e3c3c6393d84eb9b3e08dd23821b156c9b9572241222c0b687ef7df9b7be12584842a391a97fe3b3aab4361bb32f310419f1f5ac76bc3e1c6ef6bb273ad3d98b67003fc2e576736d05bb6a84b4aef8cda9032da715fc0e1d16fab097b7b21ad2dd1e7e06e2fc2f3171612b8181de5dbb5d5126847846cc94c5c24c5431ec083a892b", "b4", "17e318dcd167175fe1d0cae0e47988b382284e07e3c3c6393d84eb9b3e08dd23821b156c9b9572241222c0b687ef7df9b7be12584842a391a97fe3b3aab4361bb32f310419f1f5ac76bc3e1c6ef6bb273ad3d98b67003fc2e576736d05bb6a84b4aef8cda9032da715fc0e1d16fab097b7b21ad2dd1e7e06e2fc2f3171612b8", .Okay}, + {.Shr, "fd4a645c2b7afb161afaf18516a6c8e58d92a0199dc3040e3cbf5c656f3564ce85c3c0ca182b57a4a7b1fe9d82ca90f4bef6702ed0b6c5ecd17ab3cbeef1129811d30c04d7832999dee4f2fddb5e05778dd6fbca702872265e53d727da4e55cf47b2cd62a78b25e5df0f5c70bcaf9b53eec3b697234a78d9ddc3ff7868e801e5927eb8e78215a27ea557afe9e512d4b12e255cfd78c0", "21c", "fd4a645c2b7afb161afaf18516a6c8e58d92a0199dc3040e3cbf5c656f3564ce85c3c0ca182b57a4a7b1fe9d82ca90f4bef6702ed0b6c5ecd17ab3cbeef1129811d30c04d7832999dee4f2fddb5e05778dd6f", .Okay}, + {.Shr, "1b9106e3cba598fa78335ed23c649eab0a96e7f36a0f9a7244ebc960649a0e82634c7648560d3b67452bd7bcb600a41969c4138351bbbd2baca87b2149a9ef96886f32620ca6ca0742e3fd5ff75e9f639d43d9e1a3ececdd7cbbfbeb92a2c7a9e417fbac246e17279878c06972494ffee756c34b037dcdab9de9c1d79392fab575ac0ab6a2bde8ceb65245175793a37698d0a3e79d16", "168", "1b9106e3cba598fa78335ed23c649eab0a96e7f36a0f9a7244ebc960649a0e82634c7648560d3b67452bd7bcb600a41969c4138351bbbd2baca87b2149a9ef96886f32620ca6ca0742e3fd5ff75e9f639d43d9e1a3ececdd7cbbfbeb92a2c7a9e417fbac246e172798", .Okay}, + {.Shr, "2f421664f54a2e62e9de2b67c978fdcbd40741a2ca6a45149bd77260972a358fa19b53fb3db385a372feeccd884e2b90387b93cf5e88d5c07d7083a2cd723a0ebd01d76558c8781f20fedf0160bf94824e4466868c9f74858d4a7eb3beab7a0d998ad1d74eb4c5486531dec36ce304593423933d32a5b15964750c7eb5b47d76390f0c03ba11904d6710acd8d580aa78a9d160f616af", "0", "2f421664f54a2e62e9de2b67c978fdcbd40741a2ca6a45149bd77260972a358fa19b53fb3db385a372feeccd884e2b90387b93cf5e88d5c07d7083a2cd723a0ebd01d76558c8781f20fedf0160bf94824e4466868c9f74858d4a7eb3beab7a0d998ad1d74eb4c5486531dec36ce304593423933d32a5b15964750c7eb5b47d76390f0c03ba11904d6710acd8d580aa78a9d160f616af", .Okay}, + {.Shr, "6893682d84afb1ab91e526c5dcf69b42356787a09930a9037c55f95ace20ee99be2c62518ee39259eabf958ee3efc3a76ac5c04b427d163557e01f880291025a34ecfcad598b31dddf6512d8643997a6b2e721acf4ef336209b1049626b37795a5fac19dbd8443b2553e10b386dfb0d656e02614c74e8df8d3a75eb08fd8169f68dd46f8ee9cc079ef6872af7e9453088027959ccfc5", "1e0", "6893682d84afb1ab91e526c5dcf69b42356787a09930a9037c55f95ace20ee99be2c62518ee39259eabf958ee3efc3a76ac5c04b427d163557e01f880291025a34ecfcad598b31dddf6512d8643997a6b2e721acf4ef336209b1", .Okay}, + {.Shr, "449d6bea693ffb2d18c7060117a4c890aa78f95ba4edf2d5a439876cdfb1f7abd83060d0a0b572b01cfec65fd50fc5829dee767e2f1bf9bbedee1aee97320f15b04ed0967cb7e76d462b53d63bda0d2cc19e61e8aaa049280cd655ceb9b884ef8f0468e5e7d2842df7cb7cccefdabf6747a1eca79541e056ca7e0adc57edf38c3484867bfc72e25663045dea292de2b61f58d63160a5", "21c", "449d6bea693ffb2d18c7060117a4c890aa78f95ba4edf2d5a439876cdfb1f7abd83060d0a0b572b01cfec65fd50fc5829dee767e2f1bf9bbedee1aee97320f15b04ed0967cb7e76d462b53d63bda0d2cc19e6", .Okay}, + {.Shr, "9740ecf550d787b0af6e699d06f8a46b9bfc191b7e9276fb59dddf05fb392a8a9810457af666d97ea8aad835455c1ea59994b32782e09959a5c96ed82df015380f43ce8fd5f306c25014ff09920349b54679f744434f24a499d29e248a681395a572b89b1e8ed8c744c2b73c8d5719a1c31e7c8d698de8c5c930c9d04eb9bd7a43f3403804a445f144d7b73af2350c011962dd10a4ef", "1e0", "9740ecf550d787b0af6e699d06f8a46b9bfc191b7e9276fb59dddf05fb392a8a9810457af666d97ea8aad835455c1ea59994b32782e09959a5c96ed82df015380f43ce8fd5f306c25014ff09920349b54679f744434f24a499d2", .Okay}, + {.Shr, "b818127a903d16c68fd4cf9c7d05cb350e3d9a1e73040d4640e09c021660b51655bd714c1271d459ca6cc814630e1dfc7ef70d884ea8b860d4342e3388c39a6816c0ec7dcae9d280d32d0fab13f3d45c8f34426aed9ef214dce30504d2dd3fead99d32e740ab9698afbdae397816751abb8aaf2b2dfbab702545a02b190809295184ff56d051977b16bdc4211083fce16894302e6402", "b4", "b818127a903d16c68fd4cf9c7d05cb350e3d9a1e73040d4640e09c021660b51655bd714c1271d459ca6cc814630e1dfc7ef70d884ea8b860d4342e3388c39a6816c0ec7dcae9d280d32d0fab13f3d45c8f34426aed9ef214dce30504d2dd3fead99d32e740ab9698afbdae397816751abb8aaf2b2dfbab702545a02b1908092", .Okay}, + {.Shr, "69e6df7a389918c3e57364768645bdf8ad8343c9c6f0444e6728e4eca0cfd8213ae91af2a9c5ec4779c3f8f26b36d2bb04c10569ff1ce580d72569fd68063807445b09bcef698110f2d573bebec609031f39460570b24d0158879aac7c9df853e35566148634b529694c770a83dfa14542c9c977c1fb954cac8161dc227895075ce1488deec1a7d35fe3cb205e0740dd036c748d4e89", "258", "69e6df7a389918c3e57364768645bdf8ad8343c9c6f0444e6728e4eca0cfd8213ae91af2a9c5ec4779c3f8f26b36d2bb04c10569ff1ce580d72569fd68063807445b09bcef698110f2d573", .Okay}, + {.Shr, "4e87de8a82e441d3f29e4fdcf7d3ca0ee55735cf0cf27a496e9e7540d729c625450851177b0d9fac429576ad521d4a57add8578f0d99c5f228ee53dfdc9ca505db571307cd1aad88d83bd429805445f9791c5218d5bbb5442e72698aaa205f8965c299de3dd61fbbb6befb6c6febd01e9f937e0a55fb8a564a6e1a9e7476c5a4e1f3809e28af72a639d35de1bb06ac03f08dd583a228", "3c", "4e87de8a82e441d3f29e4fdcf7d3ca0ee55735cf0cf27a496e9e7540d729c625450851177b0d9fac429576ad521d4a57add8578f0d99c5f228ee53dfdc9ca505db571307cd1aad88d83bd429805445f9791c5218d5bbb5442e72698aaa205f8965c299de3dd61fbbb6befb6c6febd01e9f937e0a55fb8a564a6e1a9e7476c5a4e1f3809e28af72a639d35de1bb06a", .Okay}, + {.Shr, "44aca49193d1a7bb20246272df234320ab14080633d7ae1e46668daa82d0034ddd13f47b21172d801b44a532080cf0df5fa41758e109665064a5bdbfbc00af112f4de2bf48970af20d17b11687291b638456d7de6f75908d38e5f3ec371e82750ab92ec34cdbe1853975e4d501b500ba496de80999f5bc128a0879fb9942bb1adf03e9be6c77579a8d4fc69088329f2eb15f812392a2", "258", "44aca49193d1a7bb20246272df234320ab14080633d7ae1e46668daa82d0034ddd13f47b21172d801b44a532080cf0df5fa41758e109665064a5bdbfbc00af112f4de2bf48970af20d17b1", .Okay}, + {.Shr, "c9d465882b59c0167e86e7b365a9af61af459833f6ae4a0d26318625371d0d69c4a0d983c603c41c23bb147a73b68a18c97289e118359b97fbf8f5040153ee81c18016228cc52b13a1f2be457c3162c0a83ddbc0205052b6d33bfcae3e2d2ec9658fcfa656cd89e8c57bf2ed4af02c38a1caff9b8abca6173d021e638c5b68c11cf82468bf6941530338c8dca0e4485d45b49ed1f6a", "78", "c9d465882b59c0167e86e7b365a9af61af459833f6ae4a0d26318625371d0d69c4a0d983c603c41c23bb147a73b68a18c97289e118359b97fbf8f5040153ee81c18016228cc52b13a1f2be457c3162c0a83ddbc0205052b6d33bfcae3e2d2ec9658fcfa656cd89e8c57bf2ed4af02c38a1caff9b8abca6173d021e638c5b68c11cf82468bf694", .Okay}, + {.Shr, "9d3235e7e5f6dec4b97d1c1d8ec2e6378d0c073daa4db239eac4e30aa8cab75481aae91d38471d298e0902c3c23f5cee479a8c9c138919652b7daf19f6c282e7504a39d95023f40a05db9b7fbb68cfaf6d353663acc015b653877f809d54f6a4850fa9c788e29cc6f045d4eba04b75bd9d589032bb85f4f86ed2005c18fa4fbe3ef22cb01f6e7bcb94af0bdbd2809e4941572e9b9b2d", "21c", "9d3235e7e5f6dec4b97d1c1d8ec2e6378d0c073daa4db239eac4e30aa8cab75481aae91d38471d298e0902c3c23f5cee479a8c9c138919652b7daf19f6c282e7504a39d95023f40a05db9b7fbb68cfaf6d353", .Okay}, + {.Shr, "61a5e1803b518783df1eee710fa3c98cb49afbec1f0100c760d96679e093ac8d99bdd067154c7ec439d9f5fb8d91d0df774e778c1275c1ffc693e66189a59d82530ec34e24468a3ec1b0477b5f237c5cd01cf7cafd61c1a5b97ad311ab9029888cb45a74787975f7c5d925eeedd136849eeb08a64a27aedfecee3b80bd36edcb82dc02291d692d9d688faac44937153c51acd928d0f3", "0", "61a5e1803b518783df1eee710fa3c98cb49afbec1f0100c760d96679e093ac8d99bdd067154c7ec439d9f5fb8d91d0df774e778c1275c1ffc693e66189a59d82530ec34e24468a3ec1b0477b5f237c5cd01cf7cafd61c1a5b97ad311ab9029888cb45a74787975f7c5d925eeedd136849eeb08a64a27aedfecee3b80bd36edcb82dc02291d692d9d688faac44937153c51acd928d0f3", .Okay}, + {.Shr, "de2480ddcf32d0455d9f7b55ae0db3bc89ba48cf31fbfe017ce7156495b887a30f30f1247733c52273c5dc7797789cba14b8f9bed297d6042b3b89f69ef78821019d18827140c06b8ca32f83dfbbfc0bfc156dd90357d020e7fa8d5365e40100f125802711f7e60de556303071afe72a313bffee914612f9c6ef370aa712ea8f47cbd6a36d995926bdab06e0ec6b81ce47fed70cd222", "1a4", "de2480ddcf32d0455d9f7b55ae0db3bc89ba48cf31fbfe017ce7156495b887a30f30f1247733c52273c5dc7797789cba14b8f9bed297d6042b3b89f69ef78821019d18827140c06b8ca32f83dfbbfc0bfc156dd90357d020e7fa8d5365e40100f12", .Okay}, + {.Shr, "f2fa5db645e05d1c11ebdf9e1c50d0ba5c63c3c74f1455b49cc50238be7d9639a9f6f4394ca06cc60cd155de3f88a019b95c81f5a4bd4d3db5211b7073e1d5cf83fd374bd9a1bb66b93ba880b903a3b233ac0b5f744c9ac3804bcc357930cc2fa679e9d0ad3378587b00ce7fd9df10f02e9c175d2134b8dd30a7505d972b45c1c55f0132c9fa70843800633b7c1cd9d540443c80867e", "1e0", "f2fa5db645e05d1c11ebdf9e1c50d0ba5c63c3c74f1455b49cc50238be7d9639a9f6f4394ca06cc60cd155de3f88a019b95c81f5a4bd4d3db5211b7073e1d5cf83fd374bd9a1bb66b93ba880b903a3b233ac0b5f744c9ac3804b", .Okay}, + {.Shr, "f59b58a8ab662d9b5e61b9ccac42590bc96dfc1f2775a1da48f10172ed6baf0e2171dcafba52589843bcef161704ba411add42280da75d491072db04f4d684e074d4fad41b9992588bdfe81fe96670dd8f39305b8a3caaa8bdb5b70417ff8ab4191e9ee134c12771c4468e8d7273487e9c6a3bd2707172605b46fcb332616d526a1467a852f03d3e7dd96320cff60ffa9dc6f7fc43c2", "12c", "f59b58a8ab662d9b5e61b9ccac42590bc96dfc1f2775a1da48f10172ed6baf0e2171dcafba52589843bcef161704ba411add42280da75d491072db04f4d684e074d4fad41b9992588bdfe81fe96670dd8f39305b8a3caaa8bdb5b70417ff8ab4191e9ee134c12771c4468e8d7273487e9", .Okay}, + {.Shr, "ac824a97848004bcf4374f888e5215cc2d3cbf75fc5eb1edb38bcbd56121274844df0897509cda63d5ea4cb9d62d068b60bb393cf3eea838b235fa18ee26c6c10f977c2f3549c377ce0590e9799b104fd4a85d2917639a81b039627f25c9a8acac35dec9c345802778a18122e69e5e3f9c6758c4c5f5b795c35cdd19782a2b744c9ef8a288f1187e315534e28cdb27f75bd6301ad89f", "0", "ac824a97848004bcf4374f888e5215cc2d3cbf75fc5eb1edb38bcbd56121274844df0897509cda63d5ea4cb9d62d068b60bb393cf3eea838b235fa18ee26c6c10f977c2f3549c377ce0590e9799b104fd4a85d2917639a81b039627f25c9a8acac35dec9c345802778a18122e69e5e3f9c6758c4c5f5b795c35cdd19782a2b744c9ef8a288f1187e315534e28cdb27f75bd6301ad89f", .Okay}, + {.Shr, "5c3e0f7b7d9005357f2ab2f0c54387ea27bda76cbc22df05f5c47695a8ab4c29cc321a20c80400684f977d38ce26ef237e0d82538aa8b0193d1590955de4b95ea0b0c901798665e8302836cc2af6b3f0d68c32d9c5f60468abd42efbba7a9ef0b8d9abd53988176e64f50652d25e9b98b85f2628dd0b4759a310f693db9fd52dca8d3b4d2485b9ff918e90ab0ed95f5020bf309efa0c", "78", "5c3e0f7b7d9005357f2ab2f0c54387ea27bda76cbc22df05f5c47695a8ab4c29cc321a20c80400684f977d38ce26ef237e0d82538aa8b0193d1590955de4b95ea0b0c901798665e8302836cc2af6b3f0d68c32d9c5f60468abd42efbba7a9ef0b8d9abd53988176e64f50652d25e9b98b85f2628dd0b4759a310f693db9fd52dca8d3b4d2485b9", .Okay}, + {.Shr, "1b2372056ce329ee8b6128ef62b60c5e566667e241e1ce8371aaab68be150800a31ba9f02007886748b43d7e548c804a28df5b4b00d2b3149feb6492aa5dacdce52b480d68000e3c2ef0a959502e02ed02fc747644e2d2329d1bbf99f23bb711915cbb47ccb23281253435d77f97298f1dc8a3d341685ea643a541131e193a320bac6e8c0af46d8c0aae81c11fcbfed290940e1cea4c", "b4", "1b2372056ce329ee8b6128ef62b60c5e566667e241e1ce8371aaab68be150800a31ba9f02007886748b43d7e548c804a28df5b4b00d2b3149feb6492aa5dacdce52b480d68000e3c2ef0a959502e02ed02fc747644e2d2329d1bbf99f23bb711915cbb47ccb23281253435d77f97298f1dc8a3d341685ea643a541131e193a3", .Okay}, + {.Shr, "c55821838f29cba3376060145d56a50380d69a96d0688536cfa952c4fb74e111ad50a218852fda9a52b2a66b4f1ea6eff0316e31f949e60c8e2fd915aa8ca1495e6b6c806bfe3deeeab695872d84e069da42e8e92d33c7c2e11e9fa429e45112772f0718a1c45edfc899ab9307ebb4e8fe00daab2d1ae7e3d884293c99e635344e10eef33edc0c936955c31a54319989a6d54d7d4319", "258", "c55821838f29cba3376060145d56a50380d69a96d0688536cfa952c4fb74e111ad50a218852fda9a52b2a66b4f1ea6eff0316e31f949e60c8e2fd915aa8ca1495e6b6c806bfe3deeeab695", .Okay}, + {.Shr, "46bb32b75c2d3e2b1c8c6a863651504f17877c5344e6b7e1d2427115af122076adb8a937a70e5481f8de29f1b5b1446f386ca35f4572f9cd7bddc0164b4a79b784905e9685b4b12bfb1f199f22b4124a5d9d263813a0674e35915dbf86d9b767b04e39afd739cdc6a12cc4bb59165309584958f5e4a74420c682f0167fe157cedd6b0e0877a0fe5bd067b7da557a9bb8fe93304e54be", "3c", "46bb32b75c2d3e2b1c8c6a863651504f17877c5344e6b7e1d2427115af122076adb8a937a70e5481f8de29f1b5b1446f386ca35f4572f9cd7bddc0164b4a79b784905e9685b4b12bfb1f199f22b4124a5d9d263813a0674e35915dbf86d9b767b04e39afd739cdc6a12cc4bb59165309584958f5e4a74420c682f0167fe157cedd6b0e0877a0fe5bd067b7da557a9", .Okay}, + {.Shr, "b162f2ed306acfbdafa77e13f3540008c169cad1b9ed554ee0d612fce0ccd758fa87a304ee34e81e3f2ed6cc3345acf8a5924a08ac597ffc14b2e667062f7e1bbaf606ea771e6bfafe1d3a0c6b9737c5483be78a6bf123f411f83ee9f05cef3b62b7feba4ac291a7b6bd86c8c239c0e64bfa9ae01378fbc35592d7bf4b98fbdd82a88f4ca1c9dc68e2f1675b08fd327d5c3f0fdff040", "f0", "b162f2ed306acfbdafa77e13f3540008c169cad1b9ed554ee0d612fce0ccd758fa87a304ee34e81e3f2ed6cc3345acf8a5924a08ac597ffc14b2e667062f7e1bbaf606ea771e6bfafe1d3a0c6b9737c5483be78a6bf123f411f83ee9f05cef3b62b7feba4ac291a7b6bd86c8c239c0e64bfa9ae01378fbc3", .Okay}, + {.Shr, "4225e77cf1fa09a2c5c9f4c7d09562b52f301464725d9633278b093a66c5249b0821863c8f8ada1918ce7d45456c8846d42c7a015ba61d72d70de8dc8ac8668f589da9cbe6dc6408246943342a51af4617ca913cc171b697ec96d24cbac9d8d0cb5ba2af384b63e08c6d93577d0707fd0f16ac55730e2ccdc4518f4fc46a67291cb127035cb170892ac98d20b67281467ff08e866c06", "258", "4225e77cf1fa09a2c5c9f4c7d09562b52f301464725d9633278b093a66c5249b0821863c8f8ada1918ce7d45456c8846d42c7a015ba61d72d70de8dc8ac8668f589da9cbe6dc6408246943", .Okay}, + {.Shr, "af92122e12f8b4c29a8d56c982533b66e58964f8d4cdc5626824afb8367e0550dc098c6988d165e1d2f2de3908c480f2f022e293e6296c46da5c2e78e5acfce4f34daaa3f4c2761eda246f4ae8161c9b9219b963f61cde5ac5077e0fac89d9d06ae4e7fe2382ed1f8f21980555039b65a3dcc11baea64c23455012b0a2a398b7ab5e3e2c7c3c1ddf004df90f8dfbb4dbb8490b85cd1e", "12c", "af92122e12f8b4c29a8d56c982533b66e58964f8d4cdc5626824afb8367e0550dc098c6988d165e1d2f2de3908c480f2f022e293e6296c46da5c2e78e5acfce4f34daaa3f4c2761eda246f4ae8161c9b9219b963f61cde5ac5077e0fac89d9d06ae4e7fe2382ed1f8f21980555039b65a", .Okay}, + {.Shr, "8c7b0d2c5db0ab2ed8836b8b1658859550d415286c5875be834de9ef7562888422802d43ca470b76232203f86fb44718dac128cc18f417048a5debf05e05bc6be5b2996bc2d1c969ef04dbbc2bb3c9367a057281f23e2e655049b92ba51438f920f251142b27894e04ebfd0e6a6e9094fed49fc1b9371647c43e9fe860ac8840c15948408ce73e535c5252922700a09341b5d4722826", "168", "8c7b0d2c5db0ab2ed8836b8b1658859550d415286c5875be834de9ef7562888422802d43ca470b76232203f86fb44718dac128cc18f417048a5debf05e05bc6be5b2996bc2d1c969ef04dbbc2bb3c9367a057281f23e2e655049b92ba51438f920f251142b27894e04", .Okay}, + {.Shr, "54c83f44a8bc9822a17b3ece8c27d9ac5bde03ceef03ac6c05ce4ca26ecd7135d7abf2492e8d871d7ae21d3319fe030a34f12d00e8898aba5eca10ae8c57023a3df72b2fe9b2083bd8323f970113da8ece7e1123429e1dfdfa4be9e4b47e21c1740c1ff095a2b78c88c760053e32af8156fc045b4b5419a5424a61b9a51eddf5387158a55bf3258d14dc1d85b9fadf9ccf23caf87f50", "21c", "54c83f44a8bc9822a17b3ece8c27d9ac5bde03ceef03ac6c05ce4ca26ecd7135d7abf2492e8d871d7ae21d3319fe030a34f12d00e8898aba5eca10ae8c57023a3df72b2fe9b2083bd8323f970113da8ece7e1", .Okay}, + {.Shr, "94f5d2964b25f3812246356089a0f2028bd875be21b6a7e746c07f420678c3a7c10cf553f66b6e04f2950d186362e4ed013dc7fe69f53e88afcd7a1470dd1cbcd41bc3a5cf4420b157858d3fcadd5eff5aa99d7f5fcb7b49a6d861c82e5ccac01bf275435a09af06644938c705bd6249663ca02292e431c23584d331d496fec0b9210542ef35472f0ffdcb125fc66f3f6474fe6b85ef", "f0", "94f5d2964b25f3812246356089a0f2028bd875be21b6a7e746c07f420678c3a7c10cf553f66b6e04f2950d186362e4ed013dc7fe69f53e88afcd7a1470dd1cbcd41bc3a5cf4420b157858d3fcadd5eff5aa99d7f5fcb7b49a6d861c82e5ccac01bf275435a09af06644938c705bd6249663ca02292e431c2", .Okay}, + {.Shr, "48314a845147701b1e14c9cb3aba2aa6fcbe1ec3580d78b253a602ee6c0cc83afa48aa736cce68619cc4ecce61515a0beb7e8c2cdd50af6886494d43869555630396fe1d36a0757683113d6121cd96686079b4ca66d37c9f6cd94d2413ae1bac9a3cddbddf3d2a2af4cda76c44d1c5041336a875726c0e9b3eb4e095f53be600578dc1cfc6f7a2304c21a70d30d3e875ef961e7669c7", "21c", "48314a845147701b1e14c9cb3aba2aa6fcbe1ec3580d78b253a602ee6c0cc83afa48aa736cce68619cc4ecce61515a0beb7e8c2cdd50af6886494d43869555630396fe1d36a0757683113d6121cd96686079b", .Okay}, + {.Shr, "bd523718451c676accba7db9cdc81d9a87f1d9f7dc74bcb5e8c672691556890671a19ca3898a6651275a27aa57eb9ef741a46584033ff9f13ceda41cb963ab123bbe16673ef9d3d03962ec83477a4495d981af4bc0f8fcf73f101eff973b2105b793427d5a7e5abecfa6d724c03aebc2b8f1b5f388f9a4830b3681b2e81c2dadb3336da767380862b5ceb9e2844bd85f254d12f90e44", "0", "bd523718451c676accba7db9cdc81d9a87f1d9f7dc74bcb5e8c672691556890671a19ca3898a6651275a27aa57eb9ef741a46584033ff9f13ceda41cb963ab123bbe16673ef9d3d03962ec83477a4495d981af4bc0f8fcf73f101eff973b2105b793427d5a7e5abecfa6d724c03aebc2b8f1b5f388f9a4830b3681b2e81c2dadb3336da767380862b5ceb9e2844bd85f254d12f90e44", .Okay}, + {.Shr, "86eb66551f35394c1947c3480c55601e490406017598ff31dcf5aa059b77b502c2d6d91f060b0bc57aec6fa09eede7571b748e3f84bbc90e2c29c943fe53c78aa4a3b3a3cb36455fa7af67af9f1ff8bfff63435300a2e3f393c995f9276af9d88b5b279680df36f27732f97a80a566a614da811d0bb53d260964e5dfd1029978cfbc8da921f3401c4798ca9942aed39c73f82226b679", "12c", "86eb66551f35394c1947c3480c55601e490406017598ff31dcf5aa059b77b502c2d6d91f060b0bc57aec6fa09eede7571b748e3f84bbc90e2c29c943fe53c78aa4a3b3a3cb36455fa7af67af9f1ff8bfff63435300a2e3f393c995f9276af9d88b5b279680df36f27732f97a80a566a61", .Okay}, + {.Shr, "2617701de71fbb17d1b72dbca189ced13023cecef1d9874582aaee1b1b6801a045633c0e5e87ab6470bd18bacaded760fa01877b93e7cf536a529fa92e7bfcfc6d47af25aca861a3fd416912b68c258ac2da26d18e5b7bf4576d945aecab679048e1b1eff4e1f9969bade6294f680307d69b4447fca915737529cdecd9659a748159617c545c40296e2051f1b06a2014c8e53e9d4bf9", "f0", "2617701de71fbb17d1b72dbca189ced13023cecef1d9874582aaee1b1b6801a045633c0e5e87ab6470bd18bacaded760fa01877b93e7cf536a529fa92e7bfcfc6d47af25aca861a3fd416912b68c258ac2da26d18e5b7bf4576d945aecab679048e1b1eff4e1f9969bade6294f680307d69b4447fca91573", .Okay}, + {.Shr, "4378b4cfa1c3dae807c9ffb64fe9da2a3a9e7d7bfbe2fd63e3828c03e6f590b2a6e573c12cb126e2f2f378c483c1eadfe6add070a62b4916af06149e885cb5e95a1fa046a865d6d84f28f2db325c7553b6a3d9b76f972f5ad9168fc40abb9bb84f3f13a5b4fd76eb27015d9037b27229a00b63dbdfb036282660c9ebd0d3705a8ebd15171650feba4269cdc3b6bfe1cd91fedb2aca71", "f0", "4378b4cfa1c3dae807c9ffb64fe9da2a3a9e7d7bfbe2fd63e3828c03e6f590b2a6e573c12cb126e2f2f378c483c1eadfe6add070a62b4916af06149e885cb5e95a1fa046a865d6d84f28f2db325c7553b6a3d9b76f972f5ad9168fc40abb9bb84f3f13a5b4fd76eb27015d9037b27229a00b63dbdfb03628", .Okay}, + {.Shr, "f3c22a2ec401f766aecdfcd4b50f76497b0719764f5299199a00dafbaf467f58d6c14fb4d785bcffc578f57ab58ec159289034e8c17df8d715bc43582b8e1badfe59912f0da7c33215deb7d403da3c28b86c9afa4e272153ed8d4c69d7a997c49b4e448a0b74831712232462ba1ae864b866b3301a0deac93f8b779ff958238537643ba9dc4a9ba2d09da90acaea6ed042fc64f5830f", "12c", "f3c22a2ec401f766aecdfcd4b50f76497b0719764f5299199a00dafbaf467f58d6c14fb4d785bcffc578f57ab58ec159289034e8c17df8d715bc43582b8e1badfe59912f0da7c33215deb7d403da3c28b86c9afa4e272153ed8d4c69d7a997c49b4e448a0b74831712232462ba1ae864b", .Okay}, + {.Shr, "16384db25f717865ebe1de5933e997d5d1436c629a86837d1fa2a45607b90e7d4738f69410cc7a5c1a4eb625a7c4d6c0c5eab4dad5a25347082bdbe3118de53eec6f5592edb5e9a97e500cb1613b7161c6ee728432126e0c3eb6d0fa1a6fd8947fe45a62312bfc578e1a8f43f860442fdaf658cea97af62664abc064761417750c4f7e1bc9fbf630be79857b5d9430a31d5bfe7964b1", "f0", "16384db25f717865ebe1de5933e997d5d1436c629a86837d1fa2a45607b90e7d4738f69410cc7a5c1a4eb625a7c4d6c0c5eab4dad5a25347082bdbe3118de53eec6f5592edb5e9a97e500cb1613b7161c6ee728432126e0c3eb6d0fa1a6fd8947fe45a62312bfc578e1a8f43f860442fdaf658cea97af626", .Okay}, + {.Shr, "1742d53a27953a21687ab468ba345e77af19f2418ae2b2097a09e660191976ac039a6ef8853213800d42ce5873e78863b31fe2291cbc89c9f54f02d5c07170b559695ab07eea2929cd77dd967f61ef5f3480d950932a10ade460fffdee2b64eb4880af270e61ca377f7e8a9c90195a1544b2586846cec2189bfccd052452cab28aabdbd1ed61e2470590605bf0daf5672ff79d06024b", "1e0", "1742d53a27953a21687ab468ba345e77af19f2418ae2b2097a09e660191976ac039a6ef8853213800d42ce5873e78863b31fe2291cbc89c9f54f02d5c07170b559695ab07eea2929cd77dd967f61ef5f3480d950932a10ade460", .Okay}, + {.Shr, "45108429df237552708fb359edf6630be290613927d94feb4553cba6272bc5cad1cd21aef7fc227ff7ce0ce379de1984c7c78c9d17ed74b50dde2c625e2a582020af023518c943d90e238089ef5fccf2c77728d9b26baaf438fdcfa85a279caede3872396fdefe259c04a5da6324ff49adcabfc0a8b5425edd6d6df48927e7220a927aff9215fa96828619a601ddb1d97ff4238612e4", "f0", "45108429df237552708fb359edf6630be290613927d94feb4553cba6272bc5cad1cd21aef7fc227ff7ce0ce379de1984c7c78c9d17ed74b50dde2c625e2a582020af023518c943d90e238089ef5fccf2c77728d9b26baaf438fdcfa85a279caede3872396fdefe259c04a5da6324ff49adcabfc0a8b5425e", .Okay}, + {.Shr, "fefd807d7523f1fa2f510bc002f788afcd782cae2c099163390206ad1332ae9ed9546656bc7334b3e3be4c8854d1350682fb05e1c0055fc30ed67b2b0b5621e95c37e2789a7c6fb1b7a540ef2647724e48473d5cf0b95a2cc31a3b6e1eece8c0a22c33a7d63fd1e2f2ceb4db0d371439fc3f0c9a1be8ee9e9a3e3a72535c327681d8eb54a287ead3c3303eb704b59d7b96590c4a3f2c", "0", "fefd807d7523f1fa2f510bc002f788afcd782cae2c099163390206ad1332ae9ed9546656bc7334b3e3be4c8854d1350682fb05e1c0055fc30ed67b2b0b5621e95c37e2789a7c6fb1b7a540ef2647724e48473d5cf0b95a2cc31a3b6e1eece8c0a22c33a7d63fd1e2f2ceb4db0d371439fc3f0c9a1be8ee9e9a3e3a72535c327681d8eb54a287ead3c3303eb704b59d7b96590c4a3f2c", .Okay}, + {.Shr, "44e393e3d509df2211495e3c0a67b9ee1fd8f66b5c03fe4fc61599f6985006a23e73b43f3c276ea9f4aa5ef3bbca96d37069d636c9a0e9fe369564abea068fa8ecc8928d8643734644355d8d1c7f6a9bf8acd366163df2ee8b78303a63446731284bf1625d042dd26a16a5e2604d4cd664d483b0bd693c359399d1d9998a167539b6e49b7f19e4cfbe3b638992cd9dd957fe82e99a00", "f0", "44e393e3d509df2211495e3c0a67b9ee1fd8f66b5c03fe4fc61599f6985006a23e73b43f3c276ea9f4aa5ef3bbca96d37069d636c9a0e9fe369564abea068fa8ecc8928d8643734644355d8d1c7f6a9bf8acd366163df2ee8b78303a63446731284bf1625d042dd26a16a5e2604d4cd664d483b0bd693c35", .Okay}, + {.Shr, "c398cc6acd1619701fa4d036975ad8fd262152df1f8cfc8a08095bfb3920899bba9daf6252257d7a8675e54fcc03d7845cc9ab9d34cf6b9ae6df7d0081779b5af387794919a551323f795e80703a8bb1b71e5baec82e2a3fd67472783e371b84d5b3e3fd048b50b11cc700aa6f0375d9616f4e72bbba82c2b9b0b60b6dda73fe37266f7114f364e3bf6c043e57c59e7884bb2e63067d", "12c", "c398cc6acd1619701fa4d036975ad8fd262152df1f8cfc8a08095bfb3920899bba9daf6252257d7a8675e54fcc03d7845cc9ab9d34cf6b9ae6df7d0081779b5af387794919a551323f795e80703a8bb1b71e5baec82e2a3fd67472783e371b84d5b3e3fd048b50b11cc700aa6f0375d96", .Okay}, + {.Shr, "662e35727a2e45c38ddc572984ee252078662f5e87c22e0c853c002d9a8a56613ea9c8ada259535ad8949ae72c14b2fc6707af3e56f4c2b003ae2a014e56b1f45aa1ba3b4c9e5040cd2879c669691a74f5e16a7f50ad3355c9a13f6a20b6c7d7354b6e5ecbdc800dfc65cc0b4792bd13aa82f96faaee3b97c42df67cee2a15b1952ddaa49ab3afa44da086e749a17ed3f30685e4fbde", "f0", "662e35727a2e45c38ddc572984ee252078662f5e87c22e0c853c002d9a8a56613ea9c8ada259535ad8949ae72c14b2fc6707af3e56f4c2b003ae2a014e56b1f45aa1ba3b4c9e5040cd2879c669691a74f5e16a7f50ad3355c9a13f6a20b6c7d7354b6e5ecbdc800dfc65cc0b4792bd13aa82f96faaee3b97", .Okay}, + {.Shr, "9355e3c505485908dc75eb117fceedafed37e6a852a6238c06e9030de05b0584981ca06f11f9f6aff8525197768becd0ae3d22dd67718cc11f6e9d22ef6a1bd3556a71013822f5b24f170b54dd81369b4ba6badaab67024c9488ee0d3908b0145c1133663255dc691b9b0f42db07ac2b348969298f36c2e0fda63d287133b92f6241101b358e18c47d4b3cf91821b488bc642353840", "258", "9355e3c505485908dc75eb117fceedafed37e6a852a6238c06e9030de05b0584981ca06f11f9f6aff8525197768becd0ae3d22dd67718cc11f6e9d22ef6a1bd3556a71013822f5b24f170", .Okay}, + {.Shr, "b18897b76ce62ae13b6cb6636b926fccc2ec9b3068200a14f330881074ae513b3168be746bcddb8dcaa5caeaff319c36dcc1fe3843ffaddd641afc63a2a336b6ba3dadbf951df8f1852bf677931af77070b57b80dbe3331616b23f65da7fb0ac140731ffb4dab6edbaf5c91d6ffc6d8ca42ccfc8980266980cbf3fedc495411ad4fdae8f7bdd69a87dd98bb26f7c0c6641830ff2d924", "168", "b18897b76ce62ae13b6cb6636b926fccc2ec9b3068200a14f330881074ae513b3168be746bcddb8dcaa5caeaff319c36dcc1fe3843ffaddd641afc63a2a336b6ba3dadbf951df8f1852bf677931af77070b57b80dbe3331616b23f65da7fb0ac140731ffb4dab6edba", .Okay}, + {.Shr, "8587edc448d83b9cf1bb3865192aa5cd801fe9e5493f4bcb97ce4057dbe3a5fe33882fc38e808dfdd09392339ee85492fb4131d2bb587e6859498d238a83b4ed049163c28e8db370213947558d4d0b5846fecab53281e082a94a1501e20509fa16a468fadf8e105043b8c68cc64a61e620749d11d28192a941271f705dd250fec564434aa9d3c743d96e9a858040f6094e62f7e39b49", "1e0", "8587edc448d83b9cf1bb3865192aa5cd801fe9e5493f4bcb97ce4057dbe3a5fe33882fc38e808dfdd09392339ee85492fb4131d2bb587e6859498d238a83b4ed049163c28e8db370213947558d4d0b5846fecab53281e082a94a", .Okay}, + {.Shr, "4395b379d7fc7a37802a0a1c853694f65028cc4efd0931242a27ff9b28ed343e1dfb577d61d9d57e0a04ad7aa9adf3f41871ddea4452f24dec52b21e5dcddd93071a19d00be005c28ce5cdd09abb5b6c738edd0d8e86ac2cd344a7147fe8ac4db25f35fc36664d6a4fff008f88dbbc9bf05b6cf34042deed42a9e791f287d67bcc7eb1125fc6368fa5de214af13131045cbce43c5ef", "12c", "4395b379d7fc7a37802a0a1c853694f65028cc4efd0931242a27ff9b28ed343e1dfb577d61d9d57e0a04ad7aa9adf3f41871ddea4452f24dec52b21e5dcddd93071a19d00be005c28ce5cdd09abb5b6c738edd0d8e86ac2cd344a7147fe8ac4db25f35fc36664d6a4fff008f88dbbc9b", .Okay}, + {.Shr, "e3e6384de09c49b4a3f25ff0538c2fd06173933e0ef6e4ea0f6b950b33f99460d79cc2f582a69ce8a2849a38c5cdaea628561a329bee0d31b346cf1fd092c4c5ed7328b271cd7f32589b4463e9fa6cb097cf561be2baf7b7fe556759ac92aef5b3e9ac86e4530fb3ab2e9ae613be62de6b74552e481e6ebe3e3d09be24f0525c7b9a571fa30c970e78507815a255a3aae5cd736a4574", "1a4", "e3e6384de09c49b4a3f25ff0538c2fd06173933e0ef6e4ea0f6b950b33f99460d79cc2f582a69ce8a2849a38c5cdaea628561a329bee0d31b346cf1fd092c4c5ed7328b271cd7f32589b4463e9fa6cb097cf561be2baf7b7fe556759ac92aef5b3e", .Okay}, + {.Shr, "968234eb85a3e4ec048420566ba5736f1a0682707f9f42d0983ea75fb61dbc2e6fdf983b9ac5e3dfddd2733ee86a6b373ed8176ea40ec23c04157260f315cf1084291125845dc2a0e14b819aa882a3d779c7f1d479a85d13c648c0d59894b8904bdbf42410f2bb4d92f7f85d5aef1aaad7b0b5efb2df4883424d96e7896271b29a871e0c28e5914b9c84b0f2ddd6d8958fcb41a1d2cf", "258", "968234eb85a3e4ec048420566ba5736f1a0682707f9f42d0983ea75fb61dbc2e6fdf983b9ac5e3dfddd2733ee86a6b373ed8176ea40ec23c04157260f315cf1084291125845dc2a0e14b81", .Okay}, + {.Shr, "41eb947e0ea348fb7a45df8041a2be8ddfb34330dbcdd30a0be8ed0384a140059ef4815b5c13c609aef590b6a8e4b1093b687a4a4f3ebc1ceb92ed46fc259af498a4f73fbf8d47a478bac97dedb30cf429b4484d5dc9435e6a2c6d78a96b95769764ef01a3864450942820036937af57c086a3b9334abfaaec171b183c5c73fd377c24becb4e917b78916a0b283bed3f5e55af2d9797", "f0", "41eb947e0ea348fb7a45df8041a2be8ddfb34330dbcdd30a0be8ed0384a140059ef4815b5c13c609aef590b6a8e4b1093b687a4a4f3ebc1ceb92ed46fc259af498a4f73fbf8d47a478bac97dedb30cf429b4484d5dc9435e6a2c6d78a96b95769764ef01a3864450942820036937af57c086a3b9334abfaa", .Okay}, + {.Shr, "1b5288a3b04de3abeb3ed813e07f2d4a2116b12a86c84834f88460fb6cd25c9795e5770b75f9ac0aff8a89383caa0decb2b749955c34d14ead2c053d28fe0d97c314f3564cc7e41fc9020a1b4e26cb17b95966e61499e97c14a5a04726d8a06c9b785e03f4818449f010c34abb76ed5545c8bf4f95c36774c5087b26bc7b1881fe82d4da55ac56fc8a10435b0c9de9c0d36dbd9c5b30", "3c", "1b5288a3b04de3abeb3ed813e07f2d4a2116b12a86c84834f88460fb6cd25c9795e5770b75f9ac0aff8a89383caa0decb2b749955c34d14ead2c053d28fe0d97c314f3564cc7e41fc9020a1b4e26cb17b95966e61499e97c14a5a04726d8a06c9b785e03f4818449f010c34abb76ed5545c8bf4f95c36774c5087b26bc7b1881fe82d4da55ac56fc8a10435b0c9de", .Okay}, + {.Shr, "d1fc5e25380c577b3540761b2afa178ddf22049afccc81268da869d49216b42e5dbd8159f62d169960260ae9493e32cebd31e5d680e81cf0c4f6bb7c78adc75c23cb2b952a99cc4d7f9a4226d4b0802686095d6dfd109cc258da2ea484c2553b43a8a235ec59ff600ba5dba15bdff009573553f7458d1cc10247fdaa37cb423077e399789672f6ccb69b298fd9d750a96eadfafbd08d", "1a4", "d1fc5e25380c577b3540761b2afa178ddf22049afccc81268da869d49216b42e5dbd8159f62d169960260ae9493e32cebd31e5d680e81cf0c4f6bb7c78adc75c23cb2b952a99cc4d7f9a4226d4b0802686095d6dfd109cc258da2ea484c2553b43a", .Okay}, + {.Shr, "de145145496190c6905325fd5a352ff3f2b8b4cfe70f0f1a2c76335cd7387daf151dde4fcb74d69e7d4e90070added528b3a14909464ec60e90964afd886cd729d3313ce951b50c792289a0375756f0b3fc32d836142233c792d26c5b50c14224381e68eff0e061609d78a94c749c35f23df8f9067e970aad33b7a7c26bb3fb79dec31a30431ff46db50d5cf8f3d6b8a4f1befef0be2", "3c", "de145145496190c6905325fd5a352ff3f2b8b4cfe70f0f1a2c76335cd7387daf151dde4fcb74d69e7d4e90070added528b3a14909464ec60e90964afd886cd729d3313ce951b50c792289a0375756f0b3fc32d836142233c792d26c5b50c14224381e68eff0e061609d78a94c749c35f23df8f9067e970aad33b7a7c26bb3fb79dec31a30431ff46db50d5cf8f3d6", .Okay}, + {.Shr, "573fde1be7ce9bc53f10d6ef7058a660fd70f0efd46ecfcc36b492aa8e02bdae2db60ac21615894a9eb720b03c680e6568c21a00b429f41b0131783e5e36e5315fdae440bed255d65a9c1020cc8c21675ef014e216d976908f559aacff91b23ee48ea32dc587fdedd6d991ebfb81d84be36f8971a0a561bca03223b773073154a46142c953d9e2bd778ce0ff0e4835310eaab086bcd6", "258", "573fde1be7ce9bc53f10d6ef7058a660fd70f0efd46ecfcc36b492aa8e02bdae2db60ac21615894a9eb720b03c680e6568c21a00b429f41b0131783e5e36e5315fdae440bed255d65a9c10", .Okay}, + {.Shr, "6abf09cc17d7bb234be1fb3540c1797163633d88f56214a63e41342982bdf4f878c7c7565707da112596005b6163941d03a1ce0ef82f57dc7e655daf957fc74606415be751507f74adee88dab30225603d8242f0f23c04802dba0c2a435a0c5a33c0b0aabefba970e78ba91964c319504f7a58e623c63a3bbc8960ac0c5c39cf445f7f08978f178f3aad1908d271b20610c4a15992c5", "0", "6abf09cc17d7bb234be1fb3540c1797163633d88f56214a63e41342982bdf4f878c7c7565707da112596005b6163941d03a1ce0ef82f57dc7e655daf957fc74606415be751507f74adee88dab30225603d8242f0f23c04802dba0c2a435a0c5a33c0b0aabefba970e78ba91964c319504f7a58e623c63a3bbc8960ac0c5c39cf445f7f08978f178f3aad1908d271b20610c4a15992c5", .Okay}, + {.Shr, "7a2eab4559abb6e7538553b405ea8b2e18fac4b1565cdfdda66c311d050d12adcfae485af59be3ed7899bf4691d8b18f2cbabe4344663d079dff6c633bd2dc5fc0ce5a26f42d17da5923049b9e74e7ee34de2e0a4108f5b63520be7e59d4baab32ae0ed9e9cf5a66bc2dc1e45d34e5823607bce48bf4fd6368502777ff682c20a80cb943482aa3f20fc3dda28f6bfc253b26a70cfc38", "21c", "7a2eab4559abb6e7538553b405ea8b2e18fac4b1565cdfdda66c311d050d12adcfae485af59be3ed7899bf4691d8b18f2cbabe4344663d079dff6c633bd2dc5fc0ce5a26f42d17da5923049b9e74e7ee34de2", .Okay}, + {.Shr, "79ccc44377b2997eb33c3d82ad7169256cef63838e13d02d1936999e98a93f7eac11cffd02ed5cce4af2f1d8f279ddc92c41a690908c3151789b1b6129323d19ddc92d21f3bd60d2e5f3f58b9efdfc9f9681c2fb0b5a4ad11b816d403290f82b24307223e73655d993e0d1356e20a71f7fcef2d7c506a178ad5544bbd5d0b134f144bb7a5c62ad6ca1fa34a793f03b9dbc1d084abdf4", "f0", "79ccc44377b2997eb33c3d82ad7169256cef63838e13d02d1936999e98a93f7eac11cffd02ed5cce4af2f1d8f279ddc92c41a690908c3151789b1b6129323d19ddc92d21f3bd60d2e5f3f58b9efdfc9f9681c2fb0b5a4ad11b816d403290f82b24307223e73655d993e0d1356e20a71f7fcef2d7c506a178", .Okay}, + {.Shr, "26d8ad6c6d48b5a16edf6b0dd4920893478050c65699ec9e118ce7a965267214dffa122382a8fc1efcd7db1919481cb7562eaa8bef98e3e988d0ccf6601a4dd9fb6ef44f37706455c0cd909759b9ad9d1462514ace15c251a1457bcb080bd7fb47361b736ea8aabeccf8c95d021e1f1727d4712df7ddcdb580725cc8e175a65cbb905bdec73bd4882821836a5738c5b1590770ac3e10", "168", "26d8ad6c6d48b5a16edf6b0dd4920893478050c65699ec9e118ce7a965267214dffa122382a8fc1efcd7db1919481cb7562eaa8bef98e3e988d0ccf6601a4dd9fb6ef44f37706455c0cd909759b9ad9d1462514ace15c251a1457bcb080bd7fb47361b736ea8aabecc", .Okay}, + {.Shr, "8b19d5b917a7f95fcb0635f628bb962faa003f785a3ba3bec0ae8ff2e3879ccc7d34235bd08ce04b335f558838cdcf2d96d46a9ffa7004558a5abe22fe6882a1275d0a68b66b0ee2d98ac357e3547190cdaee15a3fa2b7e9568764570964a48ff4328d7d2e5ff806bb0d4ac9d411b9d641956d801f3066f8f927fa156a9bae7614cbdc0a747a250dd9552f7bdb0175d9943bb0c22ad5", "78", "8b19d5b917a7f95fcb0635f628bb962faa003f785a3ba3bec0ae8ff2e3879ccc7d34235bd08ce04b335f558838cdcf2d96d46a9ffa7004558a5abe22fe6882a1275d0a68b66b0ee2d98ac357e3547190cdaee15a3fa2b7e9568764570964a48ff4328d7d2e5ff806bb0d4ac9d411b9d641956d801f3066f8f927fa156a9bae7614cbdc0a747a25", .Okay}, + {.Shr, "3c005ae0ced7949737aee7bfb831491f8d4f07eb0a0baf47e5babed004460cac9b19143d91e34d0eb21c00eca94aa2bca344181faed512e8ead07a6b6e4b1f6d3c14a7c11728596a566ecdac7c3083a7efcd856f08da3e10dd5200fff94011f6a1e3c08ad333160caf316aba98ebcaa787e16c4c6723aa5fcc0c6c7b3adb82278e60a9d6910583554b35895a25b5357c1bcf32b79484", "258", "3c005ae0ced7949737aee7bfb831491f8d4f07eb0a0baf47e5babed004460cac9b19143d91e34d0eb21c00eca94aa2bca344181faed512e8ead07a6b6e4b1f6d3c14a7c11728596a566ecd", .Okay}, + {.Shr, "de4db608890969a0279860174b39e83958f10ca073bdb5788c1971b062a766a5ba4f57560ace5005ec5c7f48b6924899802829e9c7a4b49fbc7eb345b4e1c5a2b3f9db6ba6948ac8d1503529993ad934ab3a67a198a5e0b90b518775f36ed1cd1bb0498b0bd2891d095258954507495c24aaf28415b486b36d7e084ff448dfbd0c7a3e2265aa0c59cf29019a12612279459892a3e114", "1a4", "de4db608890969a0279860174b39e83958f10ca073bdb5788c1971b062a766a5ba4f57560ace5005ec5c7f48b6924899802829e9c7a4b49fbc7eb345b4e1c5a2b3f9db6ba6948ac8d1503529993ad934ab3a67a198a5e0b90b518775f36ed1cd1bb", .Okay}, + {.Shr, "e9180c0dbd9adf5b2e204a1a603b07f111f155c21c8c7dbf353d241f30937646d46a81a9596f02b94102e11933bf5b7cd9b2995869a4b0629bf326d9fd161c1ed237679b73ee2891d1b89b9d7fd879b6eff258f6ade33bd940d7f60b3e5f5acf1f399506aa55ce42529555a99963c321bc0b73580e85b321196b420263103f79a10cdc4929ae0a6ea413a366af64e04738d457d1e31b", "0", "e9180c0dbd9adf5b2e204a1a603b07f111f155c21c8c7dbf353d241f30937646d46a81a9596f02b94102e11933bf5b7cd9b2995869a4b0629bf326d9fd161c1ed237679b73ee2891d1b89b9d7fd879b6eff258f6ade33bd940d7f60b3e5f5acf1f399506aa55ce42529555a99963c321bc0b73580e85b321196b420263103f79a10cdc4929ae0a6ea413a366af64e04738d457d1e31b", .Okay}, + {.Shr, "b98c8f1b67bb78d24f8008a94f3a0a7432917dbd69f587a253864e9ee8c4ed870ab24c7130d519a349d90196e080721c2502093baf8e5036af5f79a6ff8e2340ceb1ef5aff50e06e6f95190e74e2f9cddeac4a58238d2c4967daed7c66234123414794a9dd5a7f82d561c6d10d305ce74aeda399432962e47b1b089948c82935965ffa988248906ac0c7cecd593dd4dd4d1fd9b8f895", "1e0", "b98c8f1b67bb78d24f8008a94f3a0a7432917dbd69f587a253864e9ee8c4ed870ab24c7130d519a349d90196e080721c2502093baf8e5036af5f79a6ff8e2340ceb1ef5aff50e06e6f95190e74e2f9cddeac4a58238d2c4967da", .Okay}, + {.Shr, "aee5b2cce40acf0825c477f34c40eb36d8f2bf118b4c626379cc8937d5880ea91afb266c489a6373f99cae3af3f2f622266cf02902342a57867d78306309e20bef783ce59314dcea479e2c39c1aa247feea1007aa990876456f4b2364ca5c762809b8d88057ab9f93c4b2274c5b6a6c328de0fbacd6cf2033bac66bf5453873bd502ad508ee0de7f551fca02779bec5bae7e85015a93", "1e0", "aee5b2cce40acf0825c477f34c40eb36d8f2bf118b4c626379cc8937d5880ea91afb266c489a6373f99cae3af3f2f622266cf02902342a57867d78306309e20bef783ce59314dcea479e2c39c1aa247feea1007aa990876456f4", .Okay}, + {.Shr, "f65d71f81deb7615cd77ec4dcfa8cdb7ea8061a02d7b4f1822780fa97d3aae09996df817631bb5e0c218db61401364d3a4760dc399d9b14a4d9f78ba5e74fe34305972b0c03acfd35c02d51a1272518c64d7848e259f446e44cba97cc9f440766f70ff9bda8d2e934eb79e1749f1a8a9e29d9e0195790d090e2a3a38a0602cb7cea6821eef99ee71d16f170deeba87c249b9ad0245ca", "12c", "f65d71f81deb7615cd77ec4dcfa8cdb7ea8061a02d7b4f1822780fa97d3aae09996df817631bb5e0c218db61401364d3a4760dc399d9b14a4d9f78ba5e74fe34305972b0c03acfd35c02d51a1272518c64d7848e259f446e44cba97cc9f440766f70ff9bda8d2e934eb79e1749f1a8a9e", .Okay}, + {.Shr, "c67577cdb233273d615b3ce4e2627217fe82625923db7a1b31b8cf3892b22ed408dbc356959585f8d5ccd7dd7465cdf7a8a10b13db662a0fc9ae93ba5dcb6267be1b47ba5e6dee800df2a744d4778ad5a4aa29989348287c997515c535fa1454fa63484a16ef9f8ffe03a048c8b02ff020bfd2fba7fa7a489cef5dbb75db7605184440276b651f751dfe1e655ea020abe996594628bb", "168", "c67577cdb233273d615b3ce4e2627217fe82625923db7a1b31b8cf3892b22ed408dbc356959585f8d5ccd7dd7465cdf7a8a10b13db662a0fc9ae93ba5dcb6267be1b47ba5e6dee800df2a744d4778ad5a4aa29989348287c997515c535fa1454fa63484a16ef9f8ffe", .Okay}, + {.Shr, "16ac59faf630f03a71ab4b04f721a79781b3c16c0367dcb8562ebdb1ddd689aaa11c16af0dab13fb12113d2b17dd4f149fbbba8aef81fe3ac45a7a56995832f0d996778079e1ac02345e87480fa4b0f448a6dd6747b6fa7050e94647e5af0faebb660bf74b3bd208f93ec9a871c6a9541be0546e2f4a0a6d23c82fbe4d623890322b625848e21e6e35001fdbf8f278efcd5c54ef57a7", "1a4", "16ac59faf630f03a71ab4b04f721a79781b3c16c0367dcb8562ebdb1ddd689aaa11c16af0dab13fb12113d2b17dd4f149fbbba8aef81fe3ac45a7a56995832f0d996778079e1ac02345e87480fa4b0f448a6dd6747b6fa7050e94647e5af0faebb6", .Okay}, + {.Shr, "8d705a76911730d0a04befcba6830b7d324a9167e073ef43ff20009de4f3afcbc3374a4b25383f194da89b27b109e10d0611366e617d5c2cedde8dc9fe9fa4c1a9a2356612d754628facd9de915907c622509b610a2a7836139f0285585f01abe639e6990d7e9f6b6bd43ae287a2592b806141a7e06bd783f27ec13dee81a73dcec50477645a4d468302755c10274161d9655b21b00d", "168", "8d705a76911730d0a04befcba6830b7d324a9167e073ef43ff20009de4f3afcbc3374a4b25383f194da89b27b109e10d0611366e617d5c2cedde8dc9fe9fa4c1a9a2356612d754628facd9de915907c622509b610a2a7836139f0285585f01abe639e6990d7e9f6b6b", .Okay}, + {.Shr, "393924036bee2d7945431d43eab7f53c7dd65ad3357abb657af0c650efce0cbe8c8e8482958d9db7176214a6961c4acd9b212296b75feb587b1fe0fdc480737ae0724be1e385dad81faebe9d923c253b1857202fe95012ae960e3c9b89aad676f5555687c328ea391192e7eb657de284ff7bad462cbdd1f0d0d3a63ff8d84d331e1333db035c082cb88cc5c47ec0a12063f19574daa2", "258", "393924036bee2d7945431d43eab7f53c7dd65ad3357abb657af0c650efce0cbe8c8e8482958d9db7176214a6961c4acd9b212296b75feb587b1fe0fdc480737ae0724be1e385dad81faebe", .Okay}, + {.Shr, "8588aeaa506cd17fb6da9acb1d90ccdd4c8341aec376025808a0422c17964d0cadffdbef5a7a30a72bf9da15aac1f2246f30260f8cb9b53f1fd30b5032ac16b8f2e97ab21829879e0005b15f43f618bbfc70f6bb435f7a5ddd0375542da5923bde280b0cba7c55b8e70f353600109d266450aa72a1757b3e9420a5a80c593695562d4fa09e7a30d094b1a3677dc5a6606782587141cd", "3c", "8588aeaa506cd17fb6da9acb1d90ccdd4c8341aec376025808a0422c17964d0cadffdbef5a7a30a72bf9da15aac1f2246f30260f8cb9b53f1fd30b5032ac16b8f2e97ab21829879e0005b15f43f618bbfc70f6bb435f7a5ddd0375542da5923bde280b0cba7c55b8e70f353600109d266450aa72a1757b3e9420a5a80c593695562d4fa09e7a30d094b1a3677dc5a", .Okay}, + {.Shr, "d288dc42fe8a44d7ed3a2532d14a382eda164656bfd1ae2c3004d1a5ce8843b8141911034ff43fbf86ed3fedbc60167cd8bf47e67f88c1608aba766a0ebdf9dedae7d76240885bd352b051c743c6916b760b5347e775b0feb2be951040c3b81347685505e6553012b45a8082a6d977ffddfe28fda11cd86915b572ca814810df8d515befc7a330d9fe035653d67a95472a54d2e7001d", "f0", "d288dc42fe8a44d7ed3a2532d14a382eda164656bfd1ae2c3004d1a5ce8843b8141911034ff43fbf86ed3fedbc60167cd8bf47e67f88c1608aba766a0ebdf9dedae7d76240885bd352b051c743c6916b760b5347e775b0feb2be951040c3b81347685505e6553012b45a8082a6d977ffddfe28fda11cd869", .Okay}, + {.Shr, "bfc32dded129ffdea2e579938beaa0ea8163df869ccb6d6875fd6365d3e06d2537de13bd2097029d91a3010356640999d30a3bc03964ada4e5ef76454afe685a81d8fd19888d1aede2b4cdf18a3d509ae2b1d5744047d3bab91302ca6b729221e622ee5be6b15317555d3284fc652f72c5ec160bdeb78bcfb4296a9c30bed91b5b03ed53edc11f075fd1e08835f1e1c01cdf3abfe1e1", "78", "bfc32dded129ffdea2e579938beaa0ea8163df869ccb6d6875fd6365d3e06d2537de13bd2097029d91a3010356640999d30a3bc03964ada4e5ef76454afe685a81d8fd19888d1aede2b4cdf18a3d509ae2b1d5744047d3bab91302ca6b729221e622ee5be6b15317555d3284fc652f72c5ec160bdeb78bcfb4296a9c30bed91b5b03ed53edc11f", .Okay}, + {.Shr, "e435a11bb6f8722ecd2cf7ffb0f93b772fcde4dc42288743d1e872faeeda3a5d0051e61dbb9c5b5036aff1d23c8dfa775e252394810efb4cb3cf2817e64fc7fc1319db70cc4f61fb60aa4c13ce9ed2db1be18093aee270f9ad498fad5611187267599f39c5e1317ddd89718c83e321f0472ece8389e84297801542803042b7447cb79962e69706769d84fd3fd700948c4f133e4f15c3", "3c", "e435a11bb6f8722ecd2cf7ffb0f93b772fcde4dc42288743d1e872faeeda3a5d0051e61dbb9c5b5036aff1d23c8dfa775e252394810efb4cb3cf2817e64fc7fc1319db70cc4f61fb60aa4c13ce9ed2db1be18093aee270f9ad498fad5611187267599f39c5e1317ddd89718c83e321f0472ece8389e84297801542803042b7447cb79962e69706769d84fd3fd7009", .Okay}, + {.Shr, "84f693519293dcf588a7dc21ff23b1218e9eac9871bc3d722e77184f535f6e0e35c20844f1d5d8a6788e41f6568a90c691a0bf119378a87a6841e81a64572033a8d41b3153d107cf175c56d1cd9f8a5b8a0f1ba9959ae529919862e33f2213e06538875b859b5eb7edb92099d03ee82f47b8f6ae6157bf287ecd2b96b04cea76c39ce103ab209989533eb08e2fd01b01f4ad4b5fcd63", "1e0", "84f693519293dcf588a7dc21ff23b1218e9eac9871bc3d722e77184f535f6e0e35c20844f1d5d8a6788e41f6568a90c691a0bf119378a87a6841e81a64572033a8d41b3153d107cf175c56d1cd9f8a5b8a0f1ba9959ae5299198", .Okay}, + {.Shr, "562f28fbfc8b5de271a3942f8ee922bd7acffad4be01611b181b46e4499796dd328863f3ccb733b3682894710de7ad7215f4ad519248e545e2a5923612503869ce873af8d927be8bcb96af959091005eb0088c8494cdf45356c74dafeb9ed62f9a35772fbe1d7f6d139e760b7c3a9814ec1405b62d68144fe77a7145566fee325f7d504c85c8215e2127299b64bc5cb07ee4d22e5a26", "21c", "562f28fbfc8b5de271a3942f8ee922bd7acffad4be01611b181b46e4499796dd328863f3ccb733b3682894710de7ad7215f4ad519248e545e2a5923612503869ce873af8d927be8bcb96af959091005eb0088", .Okay}, + {.Shr, "a91b3ecdfb08944be8e9c43f72d6840658ae7fd470c00d18260ce48fbba353c3c193987bc2120bc6a952bc484b74384759a2a4c0c596cd4fce4dd83aea23f73f9d6e3df979a7c86ca27c5ff9241b0353ff395946ca5dcadc9a687123b7332cdc1cfe69c90c7018a6a52f8d393f85175f338c8ba8418552bc59d2f5696df977a78882d0ab4d1b91673ab6bf801ae0753b57b644d0108d", "3c", "a91b3ecdfb08944be8e9c43f72d6840658ae7fd470c00d18260ce48fbba353c3c193987bc2120bc6a952bc484b74384759a2a4c0c596cd4fce4dd83aea23f73f9d6e3df979a7c86ca27c5ff9241b0353ff395946ca5dcadc9a687123b7332cdc1cfe69c90c7018a6a52f8d393f85175f338c8ba8418552bc59d2f5696df977a78882d0ab4d1b91673ab6bf801ae07", .Okay}, + {.Shr, "3516c9004f40ce4bd8770a8fede9596b40a139f608c7ffb807269361b42001b571fb5e52d9e54e49e67fc01e6a8bd5776872b3b3dcb1560a026dfbf756ea489364552a467ee038cdd70ff615cdc85ba2a89c635a1518b3bfc760814f1098f9563fedf387e1d505cb1f24f20220bbbb1290b9f7be1ccb44e5bf8207fa296dcdbaca152116796f88b6b72b85cae065ebb70df8bf3488b", "f0", "3516c9004f40ce4bd8770a8fede9596b40a139f608c7ffb807269361b42001b571fb5e52d9e54e49e67fc01e6a8bd5776872b3b3dcb1560a026dfbf756ea489364552a467ee038cdd70ff615cdc85ba2a89c635a1518b3bfc760814f1098f9563fedf387e1d505cb1f24f20220bbbb1290b9f7be1ccb44e", .Okay}, + {.Shr, "7beb310e786cd36a1c1b82fb8fa6144b07e0b398d7992af81915b76134ebcd6970bc136189e010456707d6634aa4faa6a2bebdd45a2f61db4c2cc81a4a31386c31048e85cbcf04211fb90a4fd54337cbb8bcb36e8d6c3e641e1c03f588215cd46a3b76b91781bb6a16d1d611f43e93ed5887900b2145283dc9bdd1c587998634c583ab6cd760ef2fabfa0ff515c2600586b2a490c1bf", "78", "7beb310e786cd36a1c1b82fb8fa6144b07e0b398d7992af81915b76134ebcd6970bc136189e010456707d6634aa4faa6a2bebdd45a2f61db4c2cc81a4a31386c31048e85cbcf04211fb90a4fd54337cbb8bcb36e8d6c3e641e1c03f588215cd46a3b76b91781bb6a16d1d611f43e93ed5887900b2145283dc9bdd1c587998634c583ab6cd760ef", .Okay}, + {.Shr, "41a2d4086994b5c3c4d225ceef0d3070dfc2c0744e907a5299c7a8cb8c986da98e8ae82125c80c1e241a41b5b4f9e081b27923eb5fbca16cf31ef91d4c4b0deaec8eb9e23a52ec07e0fbd1fa6abde43ac6fa2728d66c1bfd76116965fb1ef55f28812013e1fd413b6582f1cdaff39b364cc052b8be2e68318d0d4e124f368208465558fb7d768836f4c1fda9707498179bcd53ff7d08", "1e0", "41a2d4086994b5c3c4d225ceef0d3070dfc2c0744e907a5299c7a8cb8c986da98e8ae82125c80c1e241a41b5b4f9e081b27923eb5fbca16cf31ef91d4c4b0deaec8eb9e23a52ec07e0fbd1fa6abde43ac6fa2728d66c1bfd7611", .Okay}, + {.Shr, "8d71a0b28c8734f11158c0eb416cc5cbe45dc6bc164580d27e80a76419b0b1053fbdc6e265502c7a085230e51baaf3a940343a5fcdd38ebc577caf8f375dbfa8f99e1535933501cafd7dc688b45d9b71a560998d69419e9f4748fdeb17af5e58e55597ebe2ba112d61d7da9bdbb2fcab1d681f314f8f13fa0c517d1d56747d5b1f277be943d50a71adfd7f1b742e01aca29ce4322c7f", "21c", "8d71a0b28c8734f11158c0eb416cc5cbe45dc6bc164580d27e80a76419b0b1053fbdc6e265502c7a085230e51baaf3a940343a5fcdd38ebc577caf8f375dbfa8f99e1535933501cafd7dc688b45d9b71a5609", .Okay}, + {.Shr, "b4bfaf6b3e33faf32bdcf88d839d1bc58b71d215f92281527eb67298c7086888a06f2885c2de7ea90991c9893704a4b4d329f822cd8326de7665fa8eb3b0c0b41acd9f0f8c64410d3fb045fbb5a5714bb88d668f4b28bfacec5a78cda9eac165a350d93e8702efc82ef52dea3fedbde27b8de59872b7beaa8558f44240659da98ed0adb46207215ee51cc0afd2d1d5418e3af86d9224", "78", "b4bfaf6b3e33faf32bdcf88d839d1bc58b71d215f92281527eb67298c7086888a06f2885c2de7ea90991c9893704a4b4d329f822cd8326de7665fa8eb3b0c0b41acd9f0f8c64410d3fb045fbb5a5714bb88d668f4b28bfacec5a78cda9eac165a350d93e8702efc82ef52dea3fedbde27b8de59872b7beaa8558f44240659da98ed0adb4620721", .Okay}, + {.Shr, "c403a7ba0ac0a140b8b9764b2fac217fa489d90b4993f6118e6d68a26b695f9fa68aaa5043427664484fe6b196252c2c577b194c86cbfc8c5dfc7d18205a7519b63c9f18df9c83303aea01ea6634a713bbbf718ba3795741b64707da1b484ee3e07ece0a19a06e41a1603f7c980bc17c19f51a645b63b5664a9c704d9028b24f98224723ac464074b17c64d624b966cebaa94fe62eee", "b4", "c403a7ba0ac0a140b8b9764b2fac217fa489d90b4993f6118e6d68a26b695f9fa68aaa5043427664484fe6b196252c2c577b194c86cbfc8c5dfc7d18205a7519b63c9f18df9c83303aea01ea6634a713bbbf718ba3795741b64707da1b484ee3e07ece0a19a06e41a1603f7c980bc17c19f51a645b63b5664a9c704d9028b24", .Okay}, + {.Shr, "75bffefce163b91697770300dffa926b73ed9cd4a52aa7c84e03ba63daaed72782b432f34ac142e97f5d556aaf3ba37a93efcb3f7abbfc9362c75f76853b1b35adeaf999a518956c1460da4bf96e3ecb2f60febaa6067d94a698fed1e0c7ab09dce501205f624b3a3ba330a1001ad595fdcb910d0869de2b8f7f7d20bbcb5af5f96b709ba22095119faeb7b9ae378e33cb56cc39b67a", "1a4", "75bffefce163b91697770300dffa926b73ed9cd4a52aa7c84e03ba63daaed72782b432f34ac142e97f5d556aaf3ba37a93efcb3f7abbfc9362c75f76853b1b35adeaf999a518956c1460da4bf96e3ecb2f60febaa6067d94a698fed1e0c7ab09dce", .Okay}, + {.Shr, "358259107b71cbb8adda7c9651cb110eff48ef6d5d432e517504dcd423d85cd23e9bdf3eeae88ab92d4aec238ddd0bd3c71b723bddb1f041c534629d83ea1153c005f20c83d450df44e819c801c0f09bc97341564fb04c39307297a995c7370a147706a0d0ac491d149414658b717a6c6a3aa1cf21d9ca650adafdd6a54eb4ad34f1e4717016519280bb42aa07ed1c95d009f480e520", "b4", "358259107b71cbb8adda7c9651cb110eff48ef6d5d432e517504dcd423d85cd23e9bdf3eeae88ab92d4aec238ddd0bd3c71b723bddb1f041c534629d83ea1153c005f20c83d450df44e819c801c0f09bc97341564fb04c39307297a995c7370a147706a0d0ac491d149414658b717a6c6a3aa1cf21d9ca650adafdd6a54eb4a", .Okay}, + {.Shr, "a61af3548ab822d7290e9ed98ff8ef7cec34dd8dc60d176bf1d6e1b2dedb3317ad506a2e71caf5b0b94ba7bdb0d973435e8ec9aa690cdb7ee93451a0cac68f012cc192ca6eae25769e7092255d3180d201fa5a29e55f76ebad4a46352e8b585422ee083d40f2870945fcb20c19122d26be4765efce2d0e41739fd939a3ae7a21fb7045813d755cfc792dfcfbc6248b9e3c0f87d37557", "12c", "a61af3548ab822d7290e9ed98ff8ef7cec34dd8dc60d176bf1d6e1b2dedb3317ad506a2e71caf5b0b94ba7bdb0d973435e8ec9aa690cdb7ee93451a0cac68f012cc192ca6eae25769e7092255d3180d201fa5a29e55f76ebad4a46352e8b585422ee083d40f2870945fcb20c19122d26b", .Okay}, + {.Shr, "170beda631afe97bb37105f6a260ceb49c1e1dad3fe8a420e47cfe07f8c3d9b064b576171239f6dc016a3410895c1e8a634741efd5e41462cc6ceb31c633dc91ce29b6e846de1e6e4e71e9c10e0b0b2c468d4b9a92e2aea7ce8fda29d14f4ef26c7125e6339e51bf2b0db6ec3f95ca177ca3ab677bb8a25d3686a8be240f900a6c43ba0884534e34bbae0c95d720503cc5a7ef72955f", "12c", "170beda631afe97bb37105f6a260ceb49c1e1dad3fe8a420e47cfe07f8c3d9b064b576171239f6dc016a3410895c1e8a634741efd5e41462cc6ceb31c633dc91ce29b6e846de1e6e4e71e9c10e0b0b2c468d4b9a92e2aea7ce8fda29d14f4ef26c7125e6339e51bf2b0db6ec3f95ca177", .Okay}, + {.Shr, "a100f2be742808c3321e8bf51feb56427b633c587a29c50b3d22b1751cbfac49ebca09b4979f897063eb29769d8a0ad55f2ddb0bfdc7c79b3c19202a01152523824f8e0f74920d3952798a6401ad8e4542c8b256f4a9d9c67055a958cb5eab9b973e87112f1f37f7f550e5b9b41f5348f2cc28f542b9917e555c720b8bb23f887bc5471cea35fc996b777380f9d719a9ea4dfc42bedf", "1e0", "a100f2be742808c3321e8bf51feb56427b633c587a29c50b3d22b1751cbfac49ebca09b4979f897063eb29769d8a0ad55f2ddb0bfdc7c79b3c19202a01152523824f8e0f74920d3952798a6401ad8e4542c8b256f4a9d9c67055", .Okay}, + {.Shr, "cc7eca3045c2acb29e0ac282e3a6910104d36806ab746522bdab7779482db0e55b55ba5500c97ac6cb03cae954597873cc66a44d1f6b6fa796f74bc3ff0b98551c313fad2cca5a7d60a9c7a09149b5f41870a808720dc3296148af6c9348009e59106c5b2455eb3018df6566de08e763d079a40919981550c546233f8f683060a7fddb364ccf5cfc62128ecab4182cb00398a923e797", "b4", "cc7eca3045c2acb29e0ac282e3a6910104d36806ab746522bdab7779482db0e55b55ba5500c97ac6cb03cae954597873cc66a44d1f6b6fa796f74bc3ff0b98551c313fad2cca5a7d60a9c7a09149b5f41870a808720dc3296148af6c9348009e59106c5b2455eb3018df6566de08e763d079a40919981550c546233f8f68306", .Okay}, + {.Shr, "92c6b58f327ed191d58f95d09828b4d4a0e09b546d31a6f98bf3dbdaea800c1ef26e8bd58cdbd9d367d4ffce941187dd524bd18558c28c7cd614ae37f400c07a887894107587e14f92ee5c2b2ce661d8a7a17bb97906f09a42c500a1b5ca3e4d097d2e0ab344fd67e2aea00c88e67be5fdcba4cd4c7712267a5e93a53c7640e3621754f187fc05e1ee41da0520a7b14782dc23eb5f9c", "f0", "92c6b58f327ed191d58f95d09828b4d4a0e09b546d31a6f98bf3dbdaea800c1ef26e8bd58cdbd9d367d4ffce941187dd524bd18558c28c7cd614ae37f400c07a887894107587e14f92ee5c2b2ce661d8a7a17bb97906f09a42c500a1b5ca3e4d097d2e0ab344fd67e2aea00c88e67be5fdcba4cd4c771226", .Okay}, + {.Shr, "c9a3dc8c6badf758540097c8c66c7a7b503e22af40d7d736e38d1802f51d9e1111beeed4576063c34577f3a4f374b8f7b02448addb8d8a183aab809eac9ca3aeb0bb4d4170671f195591df561f7519c67a096d23c82f9fc96440aae8eae8c087c4087807bd63ccd742f9bb5ee24c7645df63c64eb982d6fdac7a18177c4a17afb60bfe9a24f6eb26c42adb796555d3efea008c5ae4f6", "258", "c9a3dc8c6badf758540097c8c66c7a7b503e22af40d7d736e38d1802f51d9e1111beeed4576063c34577f3a4f374b8f7b02448addb8d8a183aab809eac9ca3aeb0bb4d4170671f195591df", .Okay}, + {.Shr, "b5c24d91ee543ced35f694d6493498109e45867c574aec11d18106092be33edb5d40e7deabcb9d0cf54fe948fea4e68a13300360c7975fe26b5bb7b7736543555428ddaef4fb261b8244351fd4edb402437d3ad862197ee5c3214d20bb20aa1cc403cd89baac9c378ae4d8b3a1d46ebbfded96c06a679744a3607ea5c4dc502c0e02bd58e740f324add1a6978921509f0b6cdb84d77b", "12c", "b5c24d91ee543ced35f694d6493498109e45867c574aec11d18106092be33edb5d40e7deabcb9d0cf54fe948fea4e68a13300360c7975fe26b5bb7b7736543555428ddaef4fb261b8244351fd4edb402437d3ad862197ee5c3214d20bb20aa1cc403cd89baac9c378ae4d8b3a1d46ebbf", .Okay}, + {.Shr, "d982d887657219736eec9e1b9eae8b63e122e1a9f0e75949ec1ce25f20ac59a7334c7105848e5a95dd3627a21793f1f43d68919b0df3881ce2fb3b7c450fd76adedd44eb80cef1a1ec1e973d3916afcff79e22fa6312d050c135db692c3d0f4ec6a8de7e683ed26e52ef5d475abb2ceb1f49429079e51f54de4360ae13376ca508f58bc9650548923c376639af3f3cf68eeb204d118b", "0", "d982d887657219736eec9e1b9eae8b63e122e1a9f0e75949ec1ce25f20ac59a7334c7105848e5a95dd3627a21793f1f43d68919b0df3881ce2fb3b7c450fd76adedd44eb80cef1a1ec1e973d3916afcff79e22fa6312d050c135db692c3d0f4ec6a8de7e683ed26e52ef5d475abb2ceb1f49429079e51f54de4360ae13376ca508f58bc9650548923c376639af3f3cf68eeb204d118b", .Okay}, + {.Shr, "58c13880a40d5e33cd1bd9d007d3708d2b0cbdf249f301ecb9cb4f5677ac6522965fc67f840c9ddf69fa8733dce5606f51986a21074f0b5d1566928061f29a504047be681c632802ea3c31cf8ea68f4310ea8bc761cd232caccfd2ac2750ad6138fb344f91dc310bc08e17a5f985f1f2047f90a3545b3d963e49136248e8840309f66b8ef6301647ebc066d0c30061860f861f5f36c4", "168", "58c13880a40d5e33cd1bd9d007d3708d2b0cbdf249f301ecb9cb4f5677ac6522965fc67f840c9ddf69fa8733dce5606f51986a21074f0b5d1566928061f29a504047be681c632802ea3c31cf8ea68f4310ea8bc761cd232caccfd2ac2750ad6138fb344f91dc310bc0", .Okay}, + {.Shl, "2b0303d0f3e82fdd70ef51b02c3ac92ebb5d2c93d85b1632391778ec3540617ec8ccba10f03c4e03c190403beb960fdaa9c1eff547560f02674cccdd9fc1aa08702cb6e46477aa9ac926e77d24334867bc0fa87c66af057a4d507450f819c944d768c7ec8649b1b6208c31022e41b04414e6c405fed8315c9485855dcd0213fd565f3adf0ce5010a00b1766f33e396ea16338c9a3521", "11", "560607a1e7d05fbae1dea3605875925d76ba5927b0b62c64722ef1d86a80c2fd91997421e0789c0783208077d72c1fb55383dfea8eac1e04ce9999bb3f835410e0596dc8c8ef5535924dcefa486690cf781f50f8cd5e0af49aa0e8a1f0339289aed18fd90c93636c411862045c83608829cd880bfdb062b9290b0abb9a0427faacbe75be19ca02140162ecde67c72dd42c6719346a420000", .Okay}, + {.Shl, "c536020927d3a61f0ced78e8af7afa1867b9e410e03c413c170c33e382d346270bce3e8cdfc1d045ed2a5b6654ed5e6bc703a3ecc837533efd74041e5974585e3dab527f16fcc4ee09b3ad5d958e8cd8d9388bb3325c75674049eac9849b01591c88958e142f6879fc33e8449d27bb6ed01d32900abb0008a796385e271c857879d4214b87845ab91ef90641eb8e732367df22c99d3e", "8", "c536020927d3a61f0ced78e8af7afa1867b9e410e03c413c170c33e382d346270bce3e8cdfc1d045ed2a5b6654ed5e6bc703a3ecc837533efd74041e5974585e3dab527f16fcc4ee09b3ad5d958e8cd8d9388bb3325c75674049eac9849b01591c88958e142f6879fc33e8449d27bb6ed01d32900abb0008a796385e271c857879d4214b87845ab91ef90641eb8e732367df22c99d3e00", .Okay}, + {.Shl, "870e30cb3f35c349a01d6e2dd6ec930669ab27d8d89fe84324422a20063fc69f06a0bdb2ea79a0025372a5fc04e69ff0b8cac5d8c58578f3a9c767ba16e5c870d7069cf8a9e1d3d33fbb63e8572a6ad615856c87c56ef612303d93560d8df21a99d6d08c2ea1bf0512b279c59963c87d16bc24d22bd9ba2b97650e97720ee84f38053a9838f98ccb69695ed0d87f7ab5444df2f0b154", "1e", "21c38c32cfcd70d268075b8b75bb24c19a6ac9f63627fa10c9108a88018ff1a7c1a82f6cba9e680094dca97f0139a7fc2e32b17631615e3cea71d9ee85b9721c35c1a73e2a7874f4cfeed8fa15ca9ab585615b21f15bbd848c0f64d583637c86a675b4230ba86fc144ac9e716658f21f45af09348af66e8ae5d943a5dc83ba13ce014ea60e3e6332da5a57b4361fdead51137cbc2c5500000000", .Okay}, + {.Shl, "-de79c801d03d9b038e8f0512c4cd83a14cfe738d54e93d7220dfec6cb5a11a8bf6c579c26e18db0318abfefe34710c3d4eda7350973c3eb30d44eba6907fc230e3b3fd16907af1d1917a5930a4c47065405c17f0add0ba56be2828dfe4bec91ff8d8ed77cb82a550f6fe4072aa560e148a6c2d250256e6c6aa9c155ed39593736c02350ead06dc62b1730e5e5035bcc0345cbd5545ce", "75", "-1bcf39003a07b36071d1e0a25899b074299fce71aa9d27ae441bfd8d96b423517ed8af384dc31b6063157fdfc68e2187a9db4e6a12e787d661a89d74d20ff8461c767fa2d20f5e3a322f4b2614988e0ca80b82fe15ba174ad7c5051bfc97d923ff1b1daef97054aa1edfc80e554ac1c2914d85a4a04adcd8d55382abda72b26e6d8046a1d5a0db8c562e61cbca06b798068b97aaa8b9c00000000000000000000000000000", .Okay}, + {.Shl, "-ac8b1c4d5f712465d49b63bc63434aa729146ab26f7fb97cc2c7b957ab8c83e5b2fbd62b480a9a28a873b956c924e37aa920fd1549cd8ad416215c9e57c7a5019b6388e504da8cdf221e0e697f6c72596b045ec071e7de513ba215643c9030b6d8de4ab35db333f8f49b7ed015cc27a9869741a33ba0bac8b9ce06bf0fbd828ca9ff4614f3189822561188a837c9ea1bc2b0e45902c9", "1c", "-ac8b1c4d5f712465d49b63bc63434aa729146ab26f7fb97cc2c7b957ab8c83e5b2fbd62b480a9a28a873b956c924e37aa920fd1549cd8ad416215c9e57c7a5019b6388e504da8cdf221e0e697f6c72596b045ec071e7de513ba215643c9030b6d8de4ab35db333f8f49b7ed015cc27a9869741a33ba0bac8b9ce06bf0fbd828ca9ff4614f3189822561188a837c9ea1bc2b0e45902c90000000", .Okay}, + {.Shl, "-65a022a864c11126e0b334f69f2ff46d937b2579c9de9cd6db99846f298c3606858ba5f2bdea4cf83700e50b6ea1dc83cf432a67f2065793f5339e8c42ab6efcf7fe82a6ff06511156dbce40a7729542439f4137159f7dcfce746f82951a25c20c0657f99942e0b3731a60cb651e7169141d3fde337399422bb69c7c82ff8f2503e9bdffddf76767440fa85b51fb3b65b56091bad6fb", "63", "-32d011543260889370599a7b4f97fa36c9bd92bce4ef4e6b6dccc23794c61b0342c5d2f95ef5267c1b807285b750ee41e7a19533f9032bc9fa99cf462155b77e7bff41537f832888ab6de72053b94aa121cfa09b8acfbee7e73a37c14a8d12e106032bfccca17059b98d3065b28f38b48a0e9fef19b9cca115db4e3e417fc79281f4deffeefbb3b3a207d42da8fd9db2dab048dd6b7d8000000000000000000000000", .Okay}, + {.Shl, "-2e4d86038680ca147f044f9845ced109abb46b8189f6135cdbf3594ea58c85f579bf19d81e28cfd4ed61765bc50eb87e4785605554567abd4642ebba0d78c310abb2842e6eeeb833fde1f1069bde2145c9e7b8d86c944e46d33b5ba0642e52721301589d763bb41352a7c331aa5f13ad73bbfd9e57b8553e3f87368927e4031146c828afe1ddac38f5bcf565666002bd4be3b514c28a", "40", "-2e4d86038680ca147f044f9845ced109abb46b8189f6135cdbf3594ea58c85f579bf19d81e28cfd4ed61765bc50eb87e4785605554567abd4642ebba0d78c310abb2842e6eeeb833fde1f1069bde2145c9e7b8d86c944e46d33b5ba0642e52721301589d763bb41352a7c331aa5f13ad73bbfd9e57b8553e3f87368927e4031146c828afe1ddac38f5bcf565666002bd4be3b514c28a0000000000000000", .Okay}, + {.Shl, "-537ffecb8e9df06b238367d2a3ff6d15d52b284b73dcab109425f10cd14d5334ef2910daa199b0c9994fe8c6d58941313be44521cf7f76973ec8d38b9beac58320098a927066b254636eceee9cabee62a73cebbb607eef10a13a8ce0dd2d5a51679048cec6fe56bf988c5fcd23e70e9f1595ec6b2d6b27008978d9d11f1b1ed98fbe1a0c08c55990bb132b6ac20ba5ca2617434787a3", "63", "-29bfff65c74ef83591c1b3e951ffb68aea959425b9ee55884a12f88668a6a99a7794886d50ccd864cca7f4636ac4a0989df22290e7bfbb4b9f6469c5cdf562c19004c5493833592a31b767774e55f731539e75ddb03f7788509d46706e96ad28b3c82467637f2b5fcc462fe691f3874f8acaf63596b5938044bc6ce88f8d8f6cc7df0d060462acc85d8995b56105d2e5130ba1a3c3d18000000000000000000000000", .Okay}, + {.Shl, "-c0d3fe71a5652406b293d26a67fc786cae984abf7a565e72e655942a570956a5f2e809e93851adbcc320201233d3d6ed1ad52847e842b2d10bb4a10ff2180ac48da80e46fd33e6a21b5dd27129a1a994f3d246ce2938cc743216093f78027ca0ff0486c10b887478adb25e2057910764fedc9d609dd68300ed059326476bfa3b23d6a1397e9f7412badd2ac3f94b4d5366d0644a3194", "60", "-c0d3fe71a5652406b293d26a67fc786cae984abf7a565e72e655942a570956a5f2e809e93851adbcc320201233d3d6ed1ad52847e842b2d10bb4a10ff2180ac48da80e46fd33e6a21b5dd27129a1a994f3d246ce2938cc743216093f78027ca0ff0486c10b887478adb25e2057910764fedc9d609dd68300ed059326476bfa3b23d6a1397e9f7412badd2ac3f94b4d5366d0644a3194000000000000000000000000", .Okay}, + {.Shl, "4686f45d2e068cdb4c5f8b86bcf022ffc7809d08c5acb9fa6314e4aba67cadb4ba03a16c3f12bcf8a0e7e20305c7c02786b37061d93f3aefd91c71a17c893e0f4e5eeb3bb2cad389320e1d43dc0debd768e79473b6b1a71104c08efe770fc64a5d7ea14b53cb1c80c448b49d3b1a8c6f770f9317bcb80f770a2a84a3f14b166295a0b464c49ab51fb3eb7f1f20b59fa4c803e58d994", "72", "11a1bd174b81a336d317e2e1af3c08bff1e02742316b2e7e98c5392ae99f2b6d2e80e85b0fc4af3e2839f880c171f009e1acdc18764fcebbf6471c685f224f83d397baceecb2b4e24c838750f7037af5da39e51cedac69c4413023bf9dc3f192975fa852d4f2c72031122d274ec6a31bddc3e4c5ef2e03ddc28aa128fc52c598a5682d193126ad47ecfadfc7c82d67e93200f96366500000000000000000000000000000", .Okay}, + {.Shl, "8c5cfddcd95406e1b9d5e2ffd5f7db853de7289ae87636ffa2275188525aac760262f3d7aadb1699ed4400db3182709f573683c46ef787a7c3bef01621203c082b0f53c8ca5daf7769338cef519e56b197aa1d22ad90185cdf1b848c7f23073d239b73061b58f2f6f7adf29c1576936f3d0b9fc1a393f4e7cef2249f8270d8019d5fa4dd58e83b757c1823e0bbac0106647aa54306a", "a", "23173f77365501b86e7578bff57df6e14f79ca26ba1d8dbfe889d4621496ab1d8098bcf5eab6c5a67b510036cc609c27d5cda0f11bbde1e9f0efbc0588480f020ac3d4f232976bddda4ce33bd46795ac65ea8748ab64061737c6e1231fc8c1cf48e6dcc186d63cbdbdeb7ca7055da4dbcf42e7f068e4fd39f3bc8927e09c36006757e937563a0edd5f0608f82eeb0041991ea950c1a800", .Okay}, + {.Shl, "e7f02f01c462759096000ea541854ac6df40d1bf8c67829750fe79f4ab830f21430aeb8671dfaae7a3d32b2ddfa77b549b534beb9fa99823e473d24d99ef167dd7e881d7eab2ac5c93d953fed270a2e5db06ac92465685611195a414a10cbc815db697bdd6cd734fed0041a7cfa79cafe430af31002ac2a015763b33ad60b3401eb0a415be9e20b8d31111029b06831cee572d25b905", "28", "e7f02f01c462759096000ea541854ac6df40d1bf8c67829750fe79f4ab830f21430aeb8671dfaae7a3d32b2ddfa77b549b534beb9fa99823e473d24d99ef167dd7e881d7eab2ac5c93d953fed270a2e5db06ac92465685611195a414a10cbc815db697bdd6cd734fed0041a7cfa79cafe430af31002ac2a015763b33ad60b3401eb0a415be9e20b8d31111029b06831cee572d25b9050000000000", .Okay}, + {.Shl, "-1f3a5271b5781ee7f60a123c12f4a3dc25a8620458f01d242fb05033ee2d91211975d4d624fe0b3ac4b44455d9a8c9b24aad381966a06ac0fa0fffaf39bd454fdcde383c98ad9ff2dde11073807a81e64ae450d8b0c77d253f6bb0102dbf6ac9973bc113ebf5a9e0b4930d08545f27ac5a13c10ab3d19adc2895bbac84cbaf3e90a8b780c0b52ea243cde06073378e4b00f3eef552c1", "f", "-f9d2938dabc0f73fb05091e097a51ee12d431022c780e9217d82819f716c8908cbaea6b127f059d625a222aecd464d925569c0cb35035607d07ffd79cdea2a7ee6f1c1e4c56cff96ef08839c03d40f32572286c5863be929fb5d80816dfb564cb9de089f5fad4f05a4986842a2f93d62d09e08559e8cd6e144addd64265d79f48545bc0605a975121e6f030399bc7258079f77aa9608000", .Okay}, + {.Shl, "-a57bf5fc66ac74dba87ed55c48cb0222bc7fdeffbbc451d1844617f7fb30c2d81ac14563dbee873ad873d19c5ab89f02e08799a1c2653d0b7f5e6bbf5ea1d05bdd10e91d8efb20f3e1b44f56d1586677ac844f1b9ee774b5a46a917c4b10751ec408c0609609705cdbbc4d0654eaac4694364de5225a5f95ce3f6bb234d698551e98238565b6ac90c273c96d0dabbdc80b7046ff9e7e", "68", "-a57bf5fc66ac74dba87ed55c48cb0222bc7fdeffbbc451d1844617f7fb30c2d81ac14563dbee873ad873d19c5ab89f02e08799a1c2653d0b7f5e6bbf5ea1d05bdd10e91d8efb20f3e1b44f56d1586677ac844f1b9ee774b5a46a917c4b10751ec408c0609609705cdbbc4d0654eaac4694364de5225a5f95ce3f6bb234d698551e98238565b6ac90c273c96d0dabbdc80b7046ff9e7e00000000000000000000000000", .Okay}, + {.Shl, "-d2b3ba293a041b25f63b25bf061d4e50d0abd35398294e3404d866d50a41d5ecdccfe55d23320cba74f2c0dba5df574bcb500d6bbed5cb3c46b6790cfa2e7338dd297577625cd297a47daea25be837c6ce5b709e683fcdf2246181a0416451be09e05a69699302e7d3f5d49a312f58ff3dfb636555a9b3b9fb5713a845f1618a4276a376048db5c8b242ef6827b825ea2118d8ef5146", "76", "-34acee8a4e8106c97d8ec96fc1875394342af4d4e60a538d013619b54290757b3733f95748cc832e9d3cb036e977d5d2f2d4035aefb572cf11ad9e433e8b9cce374a5d5dd89734a5e91f6ba896fa0df1b396dc279a0ff37c891860681059146f8278169a5a64c0b9f4fd75268c4bd63fcf7ed8d9556a6cee7ed5c4ea117c5862909da8dd81236d722c90bbda09ee097a8846363bd451800000000000000000000000000000", .Okay}, + {.Shl, "5525101d8f61070f95b3628c74a12113575693df0bbd128a9d35a22f5f8b35b770936c271e5511dbebe59d3f6a01e6a3d8a4b090adddce2523314ebe13eb9dacd9e0c7de3f7bba15d2a25b832512d65f0a4346bf0bf5b7838aab76287aff9c2e0a0de18ea12de9a1e4721b9fa0a4f75a13b8d05a3130df5c8738de88d6a6791820193f3f9f218077031d6acc3534f4f7a517f7ee6c", "35", "aa4a203b1ec20e1f2b66c518e9424226aead27be177a25153a6b445ebf166b6ee126d84e3caa23b7d7cb3a7ed403cd47b14961215bbb9c4a46629d7c27d73b59b3c18fbc7ef7742ba544b7064a25acbe14868d7e17eb6f071556ec50f5ff385c141bc31d425bd343c8e4373f4149eeb42771a0b46261beb90e71bd11ad4cf23040327e7f3e4300ee063ad5986a69e9ef4a2fefdcd80000000000000", .Okay}, + {.Shl, "50efcf20dae43a8b5431df8b7fd3bd1927f769e1276a99b3da07109a8d8b117653405166727edefb0692a1936f4d78e6b39e75d589b41d6d2e4f7174a75594c2bec99319bc0959e6b7b69f817ef98ff23830dc55f45044568003b3bb6210c4cf324d873cb596060a6b52c0335950e6384a5fbf783a2b16e3f64ba0e17369d31ad4c3e2ad8c5efb2d64aa5a889ea2e62db26cf80f5226", "4", "50efcf20dae43a8b5431df8b7fd3bd1927f769e1276a99b3da07109a8d8b117653405166727edefb0692a1936f4d78e6b39e75d589b41d6d2e4f7174a75594c2bec99319bc0959e6b7b69f817ef98ff23830dc55f45044568003b3bb6210c4cf324d873cb596060a6b52c0335950e6384a5fbf783a2b16e3f64ba0e17369d31ad4c3e2ad8c5efb2d64aa5a889ea2e62db26cf80f52260", .Okay}, + {.Shl, "-f1794e25b0d76f48d960371bf2e1deef93b999a140e6f99f7058948b9d217f7b6e04a3bb948bcb3f0e4ea5fefd40c5e8a0d61266421d4588b533bab2f48448cad398232244e0b03fbe5119b98c67bf2e07526570b210e34029d7e90824708a5f1f85ccaaae980fc91e450a6a1c7d420d7962c7737747610d07988005963cb5c13139dfa57c75dbfe5b23bcbd31a9f564e0bcb4780314", "31", "-1e2f29c4b61aede91b2c06e37e5c3bddf2773334281cdf33ee0b129173a42fef6dc0947772917967e1c9d4bfdfa818bd141ac24cc843a8b116a677565e9089195a730464489c1607f7ca2337318cf7e5c0ea4cae16421c68053afd21048e114be3f0b99555d301f923c8a14d438fa841af2c58ee6ee8ec21a0f31000b2c796b826273bf4af8ebb7fcb647797a6353eac9c17968f00628000000000000", .Okay}, + {.Shl, "d49cee3520b049e8794604133041c0148a0e45ad9e261ebad43b97a865cf9290cfc21802eb0331dfcba8ee8294a0c4b7b1d550bb26ead7bb73090fc0d514cbbd855636510dd44d1dbca1cee700ce20165a04d0262377742ca7c16f41369b89931d73a47be99cb9483082491e1857481deff04fefb2683d5cae14c08847c84cc7d98c0bc3e8629cbfacc1e7a0198ea364710a6f34cc8d", "48", "d49cee3520b049e8794604133041c0148a0e45ad9e261ebad43b97a865cf9290cfc21802eb0331dfcba8ee8294a0c4b7b1d550bb26ead7bb73090fc0d514cbbd855636510dd44d1dbca1cee700ce20165a04d0262377742ca7c16f41369b89931d73a47be99cb9483082491e1857481deff04fefb2683d5cae14c08847c84cc7d98c0bc3e8629cbfacc1e7a0198ea364710a6f34cc8d000000000000000000", .Okay}, + {.Shl, "bb8534b24be2c558089c55fc508eafc75952bf1417c23072dd1694e9423dc87b1b26dbf4dec035d5062c4c2e45c212ea25316b53de048529f0e69d40078c168bf047f2a39a020bf59579973aabcf4755bdcb9ecb5523cafa6d7673392023272b5cb71ee0cd838019294621fe136f5016742b386b62bdfaaebec23bee17e276b65e8c52b7eb4ceabc62812aa649a2065ac1476e86b5fb", "a", "2ee14d2c92f8b1560227157f1423abf1d654afc505f08c1cb745a53a508f721ec6c9b6fd37b00d75418b130b917084ba894c5ad4f781214a7c39a75001e305a2fc11fca8e68082fd655e65ceaaf3d1d56f72e7b2d548f2be9b5d9cce4808c9cad72dc7b83360e0064a51887f84dbd4059d0ace1ad8af7eabafb08efb85f89dad97a314adfad33aaf18a04aa992688196b051dba1ad7ec00", .Okay}, + {.Shl, "71f3b776545f41ac160cf52d97e73c25f3631734ca9b4add8f0b5fdf04ad88b934fd7a11744d4292ecade913229ede11f5afefe6968f74bee202bbed58abab02c223c6f98cda2717f82e5a6cbc31ae0ceec40052d553ec179c80bdaf3babc6bd12441ab6a813cb61f6ed5573a21c8fcdf57602d3813d34bc32d881f5c72f7c469521ef7ce3ca3c4f80b61bc2f59322cee48d74247f75", "38", "71f3b776545f41ac160cf52d97e73c25f3631734ca9b4add8f0b5fdf04ad88b934fd7a11744d4292ecade913229ede11f5afefe6968f74bee202bbed58abab02c223c6f98cda2717f82e5a6cbc31ae0ceec40052d553ec179c80bdaf3babc6bd12441ab6a813cb61f6ed5573a21c8fcdf57602d3813d34bc32d881f5c72f7c469521ef7ce3ca3c4f80b61bc2f59322cee48d74247f7500000000000000", .Okay}, + {.Shl, "73ec89b04e5156078abcb963d966e9528868a81b48ca05636b78319f4f5203e79211f6dcaa87d068b59694e01dbebe374869c09dfe3fa1b6d8468d742d988e6a3f2177d532018795149ef5976df55ef4a80cd09fd397486deced00b6f2fe2b9e847938063d1b45aae3691cc4cab7308e753e05c3f6bcd0a332d0fc9746c7edaae5ede4e7ee811a414208b4d06fceb36af0ea87500812", "33", "39f644d82728ab03c55e5cb1ecb374a94434540da46502b1b5bc18cfa7a901f3c908fb6e5543e8345acb4a700edf5f1ba434e04eff1fd0db6c2346ba16cc47351f90bbea9900c3ca8a4f7acbb6faaf7a5406684fe9cba436f676805b797f15cf423c9c031e8da2d571b48e62655b98473a9f02e1fb5e685199687e4ba363f6d572f6f273f7408d20a1045a6837e759b5787543a804090000000000000", .Okay}, + {.Shl, "-1e2409141582682c39939fada23b664efaae3c22ebbd750db3355767176242862a2e79420afa4c30bc17f09bfd11c1b8e88208351fbb124c63e0652f9f36f27a4ee6207ccdf7f3d227dd4a7aa5b13d3f5841f7ee1da7460977dfc478d34d01cb79e3f5b75f67bb461d5e1a1bdc2bb93c70f3a532344b83bfa0b39bfcfeac37f8a6261be4f363fe8dcabaad64abda3f4daf4af629109d", "7", "-f12048a0ac134161cc9cfd6d11db3277d571e1175deba86d99aabb38bb1214315173ca1057d26185e0bf84dfe88e0dc7441041a8fdd892631f03297cf9b793d2773103e66fbf9e913eea53d52d89e9fac20fbf70ed3a304bbefe23c69a680e5bcf1fadbafb3dda30eaf0d0dee15dc9e3879d2991a25c1dfd059cdfe7f561bfc53130df279b1ff46e55d56b255ed1fa6d7a57b14884e80", .Okay}, + {.Shl, "7daa8e93997cc034c8a33dfd4da3171e439501ab4e922708173ae7cdba19aefcb75840fe92b012a508c0c8041bcdc33be75797026891cf7ebf6772f6d4c9b8539cfa7255438a383cc03038b436747cfe7982b3d76132920f918ac8500e569789315b71dc7d00096323754c86890dde5cd02d7784fcbdcdfe21217d825e1664278871e028971c3408e512cc279d1e94e1278f74fc38b8", "6f", "3ed54749ccbe601a64519efea6d18b8f21ca80d5a74913840b9d73e6dd0cd77e5bac207f49580952846064020de6e19df3abcb813448e7bf5fb3b97b6a64dc29ce7d392aa1c51c1e60181c5a1b3a3e7f3cc159ebb0994907c8c56428072b4bc498adb8ee3e8004b191baa6434486ef2e6816bbc27e5ee6ff1090bec12f0b3213c438f0144b8e1a0472896613ce8f4a7093c7ba7e1c5c0000000000000000000000000000", .Okay}, + {.Shl, "-266a4ffc612280ddb01196fa57522fb3dfe1aa05516ee230d06217bc09915beec251660532dd59cd2e2f9cf99ecef9049bb0f7a2a14f72b868de7c942663800b12077a2c4b407bce119ed3fc2f66a1eb48f1091d9185e9ce9978cf5efa48a4c57e7117c83832f4f3b463080ec6bc59778ada59c51546419d6f9157315e496f2e04a549a29c27e0a1c3180ac33ca83a21bef1af8c4394", "59", "-4cd49ff8c24501bb60232df4aea45f67bfc3540aa2ddc461a0c42f781322b7dd84a2cc0a65bab39a5c5f39f33d9df2093761ef45429ee570d1bcf9284cc70016240ef4589680f79c233da7f85ecd43d691e2123b230bd39d32f19ebdf491498afce22f907065e9e768c6101d8d78b2ef15b4b38a2a8c833adf22ae62bc92de5c094a9345384fc14386301586795074437de35f1887280000000000000000000000", .Okay}, + {.Shl, "8029a64936fad39bac99903a2c14a7ae1e329214f092a3d119f35171aee4d9b51713d1986f60682b538e22a35f2836d684a8f65bb92a6a3f0f9c11e6a4824d9817e8b2681681ee3d8d5dd2aa43d438ca3c0b9b0fa8bcf958f3fdedaf86303c1e838707744da97bcaafad3075de1b5a7086872af5bc942299e5568e956d0cc7b70813039ca3a76a4745044b6f9a33d20fc95cab22b9a5", "28", "8029a64936fad39bac99903a2c14a7ae1e329214f092a3d119f35171aee4d9b51713d1986f60682b538e22a35f2836d684a8f65bb92a6a3f0f9c11e6a4824d9817e8b2681681ee3d8d5dd2aa43d438ca3c0b9b0fa8bcf958f3fdedaf86303c1e838707744da97bcaafad3075de1b5a7086872af5bc942299e5568e956d0cc7b70813039ca3a76a4745044b6f9a33d20fc95cab22b9a50000000000", .Okay}, + {.Shl, "-3a8e11bd8a39d45f7582de51c5fedbf78ca51a6f116d044723e6cdacd0b347ea4147b61d7de4c8bcb316134fe58139b5f6dac6e35608674b320c2ea477b37ef5b1c1a8510a09a78a85277368d951b8dccf3bc38e9318f32e7606dc7c0692e045eb06b0f0bc1b2fb03b9e2baec45628202b9c6771ee47a2682388f4cc12e436b24936ee62e7ee164d8f65d89c8bdf515b08c9343f28a0", "51", "-751c237b1473a8beeb05bca38bfdb7ef194a34de22da088e47cd9b59a1668fd4828f6c3afbc99179662c269fcb02736bedb58dc6ac10ce9664185d48ef66fdeb638350a214134f150a4ee6d1b2a371b99e77871d2631e65cec0db8f80d25c08bd60d61e178365f60773c575d88ac50405738cee3dc8f44d04711e99825c86d64926ddcc5cfdc2c9b1ecbb13917bea2b61192687e514000000000000000000000", .Okay}, + {.Shl, "56ed254629e58148ca6fad296b199c53f737bc47933e4a4c862bd84ef31930b34d8e2ac8426e0b98639f177274aff3b3eda5c54aa95fe3efa9bedb74bddaa7972c76fe071e0c04b5e1609f14937b62fea0102367fdcf18b5eb2e57490e76a2ff93a9e6443c1d7e0e6f417849cdd46c8c65ace3b716cf06632febc7faef71adab9556fd07b7563aec6a31df4dbe45cb8049d9dfe767ca", "65", "adda4a8c53cb029194df5a52d63338a7ee6f788f267c94990c57b09de63261669b1c559084dc1730c73e2ee4e95fe767db4b8a9552bfc7df537db6e97bb54f2e58edfc0e3c18096bc2c13e2926f6c5fd402046cffb9e316bd65cae921ced45ff2753cc88783afc1cde82f0939ba8d918cb59c76e2d9e0cc65fd78ff5dee35b572aadfa0f6eac75d8d463be9b7c8b970093b3bfcecf940000000000000000000000000", .Okay}, + {.Shl, "5fbb1b73bedaaae2aa2bfa291cb4f203c3840a219dff8a1d5aa07fd7d3b8ba6b5e21db6f084c97a5c6988a03c88048fc3dccb0ed675769a7e5473529eb05da3959a1c6099cd945c9a693df9cae2ab2d30254373ab541c91c78d87d4611240405b63ff44c907b99d278e795e1cb0f01decfbaa5172b2b470927223415ad2210acecfc074eae1d73e414d5ee45da7059e4934fb6c8c53d", "7", "2fdd8db9df6d55715515fd148e5a7901e1c20510ceffc50ead503febe9dc5d35af10edb784264bd2e34c4501e440247e1ee65876b3abb4d3f2a39a94f582ed1cacd0e304ce6ca2e4d349efce57155969812a1b9d5aa0e48e3c6c3ea308920202db1ffa26483dcce93c73caf0e58780ef67dd528b9595a38493911a0ad6910856767e03a7570eb9f20a6af722ed382cf249a7db64629e80", .Okay}, + {.Shl, "-12cc38f066a2c4b9a8709b0bf64a94071ea26bdb1893c330128b44611301dd42c1b3e1f4b15cc0302541f4288880c359a5fe26de0838aed47961979cee0eb54635678b5e5a556ba0ad071112f1189e5595085e0cba5ba3517fbadc6ff888fe89d18f2731dc52a5f7d4912ac1851e03bcb54a6e56e3afe6d02bc6dd3c7595421cf13e0b0f4f21a9b5bb3e08e81107c15f86b81736461", "1d", "-259871e0cd45897350e13617ec95280e3d44d7b631278660251688c22603ba858367c3e962b980604a83e851110186b34bfc4dbc10715da8f2c32f39dc1d6a8c6acf16bcb4aad7415a0e2225e2313cab2a10bc1974b746a2ff75b8dff111fd13a31e4e63b8a54befa92255830a3c07796a94dcadc75fcda0578dba78eb2a8439e27c161e9e43536b767c11d0220f82bf0d702e6c8c20000000", .Okay}, + {.Shl, "-b08220a8a5288667fe011211e2e5abb2dc36cb4fe5898eca25c5134c7066581d45e819f285117cc4b609c614b177a7690b423bb6f932eaf356eae7b577c4822a2e2b41eb5e474f2a9b3b8b8e12d0c83750831bd4602c28525403d98aadd1803be681e1e2cb2779be60e15c668147f7aef28506341ce52fbb71781d9111393369e433f05939a90c46b33a1fc25ba2b5c1c515445b8bdf", "1", "-1610441514a510ccffc022423c5cb5765b86d969fcb131d944b8a2698e0ccb03a8bd033e50a22f9896c138c2962ef4ed21684776df265d5e6add5cf6aef8904545c5683d6bc8e9e553677171c25a1906ea10637a8c05850a4a807b3155ba30077cd03c3c5964ef37cc1c2b8cd028fef5de50a0c6839ca5f76e2f03b22227266d3c867e0b27352188d66743f84b7456b838a2a88b717be", .Okay}, + {.Shl, "-2aa31f64cf3781853bc503b46b94e363e51fffe47f035feecbd54441dbd30ecb86fc12162e5d85e743f5a9351e69dd9510cd4090a7705bdbf218c28400a5138b95b5aa1fba7416ccd70a04181739f65d8bb76f454549eae4dbb4fbc68cfb5122e70ff6e762028b5f92082da97061dedf909ca483bc7b4bf6235070c5b0444d52ebb85d16dc6b50c43150be1ff089780c9ce25b447112", "51", "-55463ec99e6f030a778a0768d729c6c7ca3fffc8fe06bfdd97aa8883b7a61d970df8242c5cbb0bce87eb526a3cd3bb2a219a81214ee0b7b7e4318508014a27172b6b543f74e82d99ae1408302e73ecbb176ede8a8a93d5c9b769f78d19f6a245ce1fedcec40516bf24105b52e0c3bdbf2139490778f697ec46a0e18b60889aa5d770ba2db8d6a18862a17c3fe112f01939c4b688e22400000000000000000000", .Okay}, + {.Shl, "6859278728467ca44b2ef2847681c8d234625c5737787dd633a069b86941c6bb991ba0dd7f245ecedf59cbdd92e7cfc5eb084286da58396d16ab1311d194f9c4c337fd873eae993b68d80d16a4572c25a8b92869a36663c1f26deae8d32520d4b2c591f5eb8fc715b9951ba66d8a3b14b47f64acba1714ba6b7ad77242f5c509cd1c0d18d74e6d2e64f0c62eee773f0d84f07c60ceff", "5a", "1a1649e1ca119f2912cbbca11da072348d189715cdde1f758ce81a6e1a5071aee646e8375fc917b3b7d672f764b9f3f17ac210a1b6960e5b45aac4c474653e7130cdff61cfaba64eda360345a915cb096a2e4a1a68d998f07c9b7aba34c948352cb1647d7ae3f1c56e6546e99b628ec52d1fd92b2e85c52e9adeb5dc90bd71427347034635d39b4b993c318bbb9dcfc3613c1f1833bfc0000000000000000000000", .Okay}, + {.Shl, "-27036e37e1456f94a160d67ce01e632e8b80f2b1751c8ee5ee32c54347fe6336f45c82093f92b6cfc60cd7440e187067299bb15e30e56cdb3e0bc20693688cd51a5ccf77852e277f67e0af13ba9b71715720ae308a76dfad1e60c4beb2eeb34228d5cc99c5e0f27fa92022667bab577616841ae2b9760830c2bf4a727419b215e5908b21db5f1cc462aaa3ed34965bc0e77a67c16a94", "8", "-27036e37e1456f94a160d67ce01e632e8b80f2b1751c8ee5ee32c54347fe6336f45c82093f92b6cfc60cd7440e187067299bb15e30e56cdb3e0bc20693688cd51a5ccf77852e277f67e0af13ba9b71715720ae308a76dfad1e60c4beb2eeb34228d5cc99c5e0f27fa92022667bab577616841ae2b9760830c2bf4a727419b215e5908b21db5f1cc462aaa3ed34965bc0e77a67c16a9400", .Okay}, + {.Shl, "-2e63cba1a743454a83a645019a53c7235a8f0261301ed43b00338292184f4c8dac73d6f490a72b532c17d8e42db6e1cedf864d00b0c711352ce658f39113448801df98874151397e05cf60ff6d7b37d7c4feb1845842837b709a1a8df8d5dc292a5361aeb8327c6c65e8da93e82e2fa411f54a40351303df9c5108c334f31368f68fc57742743cc298ce7305d486d6effdee72a8a7a8", "62", "-b98f2e869d0d152a0e991406694f1c8d6a3c0984c07b50ec00ce0a48613d3236b1cf5bd2429cad4cb05f6390b6db873b7e193402c31c44d4b39963ce444d1220077e621d0544e5f8173d83fdb5ecdf5f13fac611610a0dedc2686a37e35770a4a94d86bae0c9f1b197a36a4fa0b8be9047d52900d44c0f7e7144230cd3cc4da3da3f15dd09d0f30a6339cc17521b5bbff7b9caa29ea0000000000000000000000000", .Okay}, + {.Shl, "694c1369832a42368e51b2e93c2552209c7c877a12e136a4d4893310f1be801e47d96055b1d937326d91368329a3b3d96788d80365d6dc5176c3a9efd81b09de16ae81c2a754ee5a2a12f3092aba7ddb44f7f8b5c96f1dbc08aaac0b8ac40431381bc72b3e1951820e83fd350c8e273d0cd3aceb41c8d66d8285abcb53f7559aafd905d68e0cd8160d791c55f33228897065555722ec", "3a", "1a5304da60ca908da3946cba4f095488271f21de84b84da935224cc43c6fa00791f658156c764dcc9b644da0ca68ecf659e23600d975b7145db0ea7bf606c27785aba070a9d53b968a84bcc24aae9f76d13dfe2d725bc76f022aab02e2b1010c4e06f1cacf86546083a0ff4d432389cf4334eb3ad072359b60a16af2d4fdd566abf64175a3833605835e47157ccc8a225c195555c8bb000000000000000", .Okay}, + {.Shl, "-a571373e15cb4b10ad8b75020791896d0c76e6c2c9c39a6b444a8b2e660f401e482d208e937aa43a223ac4c00bf0f15b65381c8e47e8db10667b98df6c35c8debd79cc488d2901816aaad1846e04ade9e80ef6fe8eed69ed30bed472fb0e3093568105b323bd9e7fb18a2a93b1738e158907ee033cb3b382bfd993947fbfb1e49b207a7eaf6af95be627b65b80097dec0b275cf0be9", "4b", "-52b89b9f0ae5a58856c5ba8103c8c4b6863b736164e1cd35a22545973307a00f2416904749bd521d111d626005f878adb29c0e4723f46d88333dcc6fb61ae46f5ebce624469480c0b55568c2370256f4f4077b7f4776b4f6985f6a397d871849ab4082d991decf3fd8c51549d8b9c70ac483f7019e59d9c15fecc9ca3fdfd8f24d903d3f57b57cadf313db2dc004bef60593ae785f48000000000000000000", .Okay}, + {.Shl, "-e4a165978a410cbb35d028184473eb67fe174c6abf8b46622fac6184d8a0016b22c69c8a516f6af73574f1df0fe829868c49239282f637bc1e5aee302c1d503e1001b67af71b40789f8269003b55f6817849600fef5c98904bd9eaee816b78dd608e8d6800fb7d37b81ed8b8d66b68f54fdc717abcb815886aee768e7a9df70202904a895d4af35eab2da9a95fab34fae21e29d1e9eb", "55", "-1c942cb2f148219766ba0503088e7d6cffc2e98d57f168cc45f58c309b14002d6458d3914a2ded5ee6ae9e3be1fd0530d1892472505ec6f783cb5dc60583aa07c20036cf5ee3680f13f04d20076abed02f092c01fdeb9312097b3d5dd02d6f1bac11d1ad001f6fa6f703db171acd6d1ea9fb8e2f579702b10d5dced1cf53bee0405209512ba95e6bd565b5352bf5669f5c43c53a3d3d6000000000000000000000", .Okay}, + {.Shl, "99309e663a305fb75369fa13c3147f301bc3cd985ce1dcb9f6bc96341774fa765be19894453d901b5f9ad5cafcd6a64a467e54e12f51836103f7eb1b2d1de869b33722c8b1af806b95aa7d5b5d8d68ba360cb9344a3345041d2536eeafb6dd5d8b4e0034bab3add7ff134bc8798628d2f48915aea82848f7d745f5110061679bbe43a13884bfc6bfdb12b5fe6ebe4bc3804914638504", "6", "264c27998e8c17edd4da7e84f0c51fcc06f0f3661738772e7daf258d05dd3e9d96f86625114f6406d7e6b572bf35a992919f95384bd460d840fdfac6cb477a1a6ccdc8b22c6be01ae56a9f56d7635a2e8d832e4d128cd14107494dbbabedb75762d3800d2eaceb75ffc4d2f21e618a34bd22456baa0a123df5d17d44401859e6ef90e84e212ff1aff6c4ad7f9baf92f0e0124518e14100", .Okay}, + {.Shl, "4800e7047dfe4999506b80946f840b67bc0b18652a3157d5603fec58bcb93e25089f342e2cf832f6d0d72bb1e942ea22157c95e45795d93d8a6002981cf00cfed1478dc76f603619592f23fb507fcd9d88ac5a2da463bd44322a05ab98e6d924a5aa38440fa2e43612250e3755c28f63821e5c37b13f06de929a7b873923f15503557da76bb76d2dc8c69d9ba24732e84970ade7add3", "2c", "4800e7047dfe4999506b80946f840b67bc0b18652a3157d5603fec58bcb93e25089f342e2cf832f6d0d72bb1e942ea22157c95e45795d93d8a6002981cf00cfed1478dc76f603619592f23fb507fcd9d88ac5a2da463bd44322a05ab98e6d924a5aa38440fa2e43612250e3755c28f63821e5c37b13f06de929a7b873923f15503557da76bb76d2dc8c69d9ba24732e84970ade7add300000000000", .Okay}, + {.Shl, "-7831a63e4eb687bfca088442409b1b113b1badfbc95dd9a5c2d0260d98c6517609e0228c9f0bc476945a52298e281f8d49d87e4468b29f5c354703e058d1d5f0eda99e18a116cc16703fd8a2eb21ffff728e79e49f725beb83be296c0f76ac9b33298ef119a1a2638d48ab3a3f0c271b802fe40c5769ac71a61f99591fbda75e65f7ce1d33783ed773d8a03d3ac8e057b17c13230a4f", "3a", "-1e0c698f93ada1eff28221109026c6c44ec6eb7ef257766970b409836631945d827808a327c2f11da516948a638a07e352761f911a2ca7d70d51c0f81634757c3b6a67862845b3059c0ff628bac87fffdca39e7927dc96fae0ef8a5b03ddab26ccca63bc46686898e3522ace8fc309c6e00bf90315da6b1c6987e65647ef69d7997df3874cde0fb5dcf6280f4eb23815ec5f04c8c293c00000000000000", .Okay}, + {.Shl, "-14eb27b2add9b866c70117dd0faa9da69c73e08520c8d6b01e8ab09e0f58aa1b298ea3c5e89d9aacdccc5f19a33691452a5f926329f5f85b3e62bb75c6931f1a088ed6ca6d4bdce0c350ed966090c0548bbca441982c0362af19c6d7bcacfcf3c425b71c57cf3792101410b8d9c3ce761dd261de500734c798cb6da9afbf6516c61622101251d66e98bf3865545ef805b4d7a2d4ca40", "77", "-a7593d956ecdc3363808bee87d54ed34e39f04290646b580f45584f07ac550d94c751e2f44ecd566e662f8cd19b48a2952fc93194fafc2d9f315dbae3498f8d04476b6536a5ee7061a876cb3048602a45de5220cc1601b1578ce36bde567e79e212db8e2be79bc9080a085c6ce1e73b0ee930ef28039a63cc65b6d4d7dfb28b630b11080928eb374c5f9c32aa2f7c02da6bd16a6520000000000000000000000000000000", .Okay}, + {.Shl, "29f2d6b681ef6099d82fb5614ea7ffaf2d2f8ee82a17a34f4eff1b1cacae491067b07c1baf9a48cf5f005d8ae7b4a6145efb61e1aca0588cd361792c8bea430da40ebd342cadca77d63438c2ba56681c49945b24d9949b8126c9f138b4959106e09c14fdb9fbdbc2e3b85a7b1c017725ad9b051662463098adc2663f8c941e2f5a5508a3d4ba1e215eeb6fbd5cd80869a134d17ae09a", "57", "14f96b5b40f7b04cec17dab0a753ffd79697c774150bd1a7a77f8d8e5657248833d83e0dd7cd2467af802ec573da530a2f7db0f0d6502c4669b0bc9645f52186d2075e9a1656e53beb1a1c615d2b340e24ca2d926cca4dc09364f89c5a4ac883704e0a7edcfdede171dc2d3d8e00bb92d6cd828b3123184c56e1331fc64a0f17ad2a8451ea5d0f10af75b7deae6c0434d09a68bd704d0000000000000000000000", .Okay}, + {.Shl, "d8e8e4992b8744e8d9992d97a9d61269a6425962eb409a1d4b8e17a45e8dfc4ad8ecad42b8f7a8055ff6b96deb8a5a8e21e08b5b2a09d437c2ac03da99066e82beba0dcaea03630cf6f2748bcefad02d5cb23ad5900b1c25c8b2e23fdfcc77d8986283fa6d46d6e8f4188dd2495e192bfc4c619686f5aea16cfd6d9f130644d766611697c7b88d9f2996bdf71b311840cc6d6f896358", "29", "1b1d1c932570e89d1b3325b2f53ac24d34c84b2c5d681343a971c2f48bd1bf895b1d95a8571ef500abfed72dbd714b51c43c116b65413a86f855807b5320cdd057d741b95d406c619ede4e9179df5a05ab96475ab2016384b9165c47fbf98efb130c507f4da8dadd1e8311ba492bc3257f898c32d0deb5d42d9fadb3e260c89aeccc22d2f8f711b3e532d7bee3662308198dadf12c6b00000000000", .Okay}, + {.Shl, "-7ca70a2e04a5816fa086fe2e88d2b670b4bc12a00337eaa99921bb9a15da9ad656d5dd70586ffcc1ac03bcd0a41135ef94f68afcec5d44e1b7702a980eb6db8b87815407da59b7ad037ae9d9cbfc87ddd45a2c5031280cbb54389a14ab081d882f642498e7d55f6f97705251afcf2063038c7fc93534bde79960a8a8ea22d34ccf42c4a8d6de186bf5479d67f6c270ccae7866a08573", "26", "-1f29c28b8129605be821bf8ba234ad9c2d2f04a800cdfaaa66486ee68576a6b595b5775c161bff306b00ef3429044d7be53da2bf3b1751386ddc0aa603adb6e2e1e05501f6966deb40deba7672ff21f775168b140c4a032ed50e26852ac207620bd9092639f557dbe5dc14946bf3c818c0e31ff24d4d2f79e6582a2a3a88b4d333d0b12a35b7861afd51e759fdb09c332b9e19a8215cc000000000", .Okay}, + {.Shl, "-cc52ca5a2f955b5df31f0730a08b76e588e0437e7d4ad3b7e19e38809ae6106c84db0dc9f47ec90457f75476a60db70f61ecd3f42a227e0aa5e13e3c4a1bbb11f61b081f9c6f03bf2a8d8646069b860c7e87fc1ddfbcd070b5a216e3df2732730ae083d70c27233a05efd17bc817c0a839443341d08a94fb6f90280dbd952d5f7bdb29197d50af0e05dcfc4e7d79b367e933822a704e", "3", "-6629652d17caadaef98f83985045bb72c47021bf3ea569dbf0cf1c404d730836426d86e4fa3f64822bfbaa3b5306db87b0f669fa15113f0552f09f1e250ddd88fb0d840fce3781df9546c323034dc3063f43fe0eefde68385ad10b71ef939939857041eb8613919d02f7e8bde40be0541ca219a0e8454a7db7c81406deca96afbded948cbea8578702ee7e273ebcd9b3f499c11538270", .Okay}, + {.Shl, "-3e125e5be08f35000ccdc8b37990bed0dec9189289217418f860449d383b2c2d2c2fb547111eddd771e95646d5290dbf0a3d6ff3339977c455a92120aeb857a8b8bc194c710de9a0e5e49960a7945de63226acc39a80dcecd7a78ce6169d12bb36a9a6b471331549f39f1297d1be01b474c9725ab85d5a6701e49360818e103bceeccbebdd2a0686bd3ee35dc4d6e0d084061eb177b0", "21", "-7c24bcb7c11e6a00199b9166f3217da1bd9231251242e831f0c0893a7076585a585f6a8e223dbbaee3d2ac8daa521b7e147adfe66732ef88ab5242415d70af5171783298e21bd341cbc932c14f28bbcc644d59873501b9d9af4f19cc2d3a25766d534d68e2662a93e73e252fa37c0368e992e4b570bab4ce03c926c1031c20779dd997d7ba540d0d7a7dc6bb89adc1a1080c3d62ef6000000000", .Okay}, + {.Shl, "-27b690229ec459cdcf0430e55c02445ec5cfd077787e4a0e6c6df8b30644cc8eda8f03e9b3e64ffb9126029cd16ace69410a9d29ae226047744d6cedb7d26f4fe160cdb29d452e16995a23cb95735c2aedfc68ad63d252bb4dbffbc27b820d52b822ab77b016904cfcade0fcbbc0bcee990cce5cdabf811eed64e8f275bda688fa98598ec062bbc4189d2900bf7d39efb7b232f21a55", "23", "-13db48114f622ce6e7821872ae01222f62e7e83bbc3f25073636fc59832266476d4781f4d9f327fdc893014e68b56734a0854e94d7113023ba26b676dbe937a7f0b066d94ea2970b4cad11e5cab9ae1576fe3456b1e9295da6dffde13dc106a95c1155bbd80b48267e56f07e5de05e774c86672e6d5fc08f76b274793aded3447d4c2cc760315de20c4e94805fbe9cf7dbd919790d2a800000000", .Okay}, + {.Shl, "38d1d203efcd5c32a7209c61e1709e861c1a812cc082705757252b8699850283204a3284a7acecc685184e2cfe4103c346eee21e5474e8f99b18a8f09e61b041c977ac5dca205d3be55f502d1887d42fc4e5ff251906bc3a11fc1622f79952a3b5e9aab92055ea9ce1e73c787f9d654c1e7231a1ae3b5933783615815c4bb096611a80ef64f6c21895861e95be4309d4ec1573564e0d", "50", "38d1d203efcd5c32a7209c61e1709e861c1a812cc082705757252b8699850283204a3284a7acecc685184e2cfe4103c346eee21e5474e8f99b18a8f09e61b041c977ac5dca205d3be55f502d1887d42fc4e5ff251906bc3a11fc1622f79952a3b5e9aab92055ea9ce1e73c787f9d654c1e7231a1ae3b5933783615815c4bb096611a80ef64f6c21895861e95be4309d4ec1573564e0d00000000000000000000", .Okay}, + {.Shl, "49dbff1ec28a3bb5529ef8c774c4a1310c6365511ab50aed82556b217fc7429dfb312afc4c0e82d9a01fc351f8452825c84e48af4fddd57ada736e61d187791293947463f66200077ff99499bf3a8ea2d3ae9324f26b4f0cc9e406a94675200b666920e972e85d08f5efb2264cbe1af8095e80c10bfb15d5ade1c77420c71727fab84eb7d98aa0e36148e341d5e02fa8c7ab37916e0a", "4e", "1276ffc7b0a28eed54a7be31dd31284c4318d95446ad42bb60955ac85ff1d0a77ecc4abf1303a0b66807f0d47e114a097213922bd3f7755eb69cdb987461de44a4e51d18fd988001dffe65266fcea3a8b4eba4c93c9ad3c3327901aa519d4802d99a483a5cba17423d7bec89932f86be0257a03042fec5756b7871dd0831c5c9feae13adf662a838d85238d075780bea31eacde45b8280000000000000000000", .Okay}, + {.Shl, "-532d98b7cbfe2aeecf05e627c4573bbdb8c15d1a9184587176d9e99d0bd3ef9e09d3ae0c2856836caca133ae375e5003a79d9d8702498e63a99f3bf4c18398d0b233b924c32a5e4f6e9499bf1b594d82aadc751214f1e6f21137564a4ffb40a1026aea5156507dfebc7d75b09b60b0fea9d481abeab273efc78b334c1a3275e8fdb40e4876fbbaf09fe80f183041a3c4732191a7ba37", "f", "-2996cc5be5ff15776782f313e22b9ddedc60ae8d48c22c38bb6cf4ce85e9f7cf04e9d706142b41b6565099d71baf2801d3cecec38124c731d4cf9dfa60c1cc685919dc9261952f27b74a4cdf8daca6c1556e3a890a78f379089bab2527fda05081357528ab283eff5e3ebad84db0587f54ea40d5f55939f7e3c599a60d193af47eda07243b7ddd784ff4078c1820d1e23990c8d3dd1b8000", .Okay}, + {.Shl, "-925b0dc9359fd45aea16be1e8347a58890534f5ab2009d04c6a5a5604435abe4d7200782ea093dd0fcd1f35f2fbebaa74e069eb05cc35e1a4a41e8fc83ac161e058c55784406d82a6a0378a689d29a62564bd6a2b63fbc302dbb351b4c7411bc4bb8591cdf66769192a1fc39a0e40f449110e026bbf3e50acbb5aa61712f1aedc11e8b0337435bcd1627cd693594444e45e458d33602", "66", "-2496c3724d67f516ba85af87a0d1e9622414d3d6ac80274131a96958110d6af935c801e0ba824f743f347cd7cbefaea9d381a7ac1730d78692907a3f20eb05878163155e1101b60a9a80de29a274a6989592f5a8ad8fef0c0b6ecd46d31d046f12ee164737d99da464a87f0e683903d124443809aefcf942b2ed6a985c4bc6bb7047a2c0cdd0d6f34589f35a4d65111391791634cd8080000000000000000000000000", .Okay}, + {.Shl, "-ea79d96ca3e69c091eb8f070ffdad303a84291b4ca5b350ccd074b1324eba2d2c769668468c973e6743ae6b9c2b9794856ba6ce894176b2f7d6bdd1c0136f0d919885b173e4ca29ff4a7245f8ec05541d5c5e93ee197835346233a0270cf12927f2b133522dbdee515da8a42924e2e1f0da9718c0057c241e4d2392d2578276c418ef37dd92181779430f1e36bb36190a28b1fed6678", "32", "-3a9e765b28f9a70247ae3c1c3ff6b4c0ea10a46d3296cd433341d2c4c93ae8b4b1da59a11a325cf99d0eb9ae70ae5e5215ae9b3a2505dacbdf5af747004dbc36466216c5cf9328a7fd29c917e3b0155075717a4fb865e0d4d188ce809c33c4a49fcac4cd48b6f7b94576a290a4938b87c36a5c630015f09079348e4b495e09db1063bcdf7648605de50c3c78daecd86428a2c7fb599e0000000000000", .Okay}, + {.Shl, "-33e57485e39bd6d226ceef8faabe096a889b60ea5537db0d892404efc1cc280f11d43ac8739acae97945257071fb736e4b0cfc243167c01408e0a8cd560cdb3f99f7c94f44f3f2b134a73f06df8b99ceb227547f29cbae74e7f3c80fd332d47d0de290a93720234500814e4fd65dfd9cf5efff045e4af9fca7f90f8429b214f23a9b1a56754443c71ad873b761d21226914bbd3f6db5", "13", "-19f2ba42f1cdeb69136777c7d55f04b5444db0752a9bed86c4920277e0e6140788ea1d6439cd6574bca292b838fdb9b725867e1218b3e00a04705466ab066d9fccfbe4a7a279f9589a539f836fc5cce75913aa3f94e5d73a73f9e407e9996a3e86f148549b9011a28040a727eb2efece7af7ff822f257cfe53fc87c214d90a791d4d8d2b3aa221e38d6c39dbb0e9091348a5de9fb6da80000", .Okay}, + {.Shl, "e9b64f29cb38a0468ff874317c5f3ffb7ac7dfb5a957a556a646edba1ae5de16d43ad9a2c9b0ae037e90a232ae2db6b44e24ee430c74d3f1a5200074a45c721464c17ba099eb9c6027aecb44e2727167083732bfdabf8bc7735a0d8e0433403e935ee483713ae1d24032a9880ab63a596e467658847e9ce4fd848ca6eceaef77a160cd2751438c85ad72cd39a2d10b6e7df4bac81d86", "2e", "3a6d93ca72ce2811a3fe1d0c5f17cffedeb1f7ed6a55e955a991bb6e86b97785b50eb668b26c2b80dfa4288cab8b6dad13893b90c31d34fc6948001d29171c8519305ee8267ae71809ebb2d1389c9c59c20dccaff6afe2f1dcd68363810cd00fa4d7b920dc4eb874900caa6202ad8e965b919d96211fa7393f612329bb3abbdde8583349d450e3216b5cb34e68b442db9f7d2eb20761800000000000", .Okay}, + {.Shl, "-7de523d73f78a7202ec344e5f2f2434edea54bd304b0d76746953106f7e446cae9186f0db830568e850121900064275c620bd744a902e58fa668685ce61932ab79497a398c2642f5ac5971dd2574e0a1b3311d8711141b330442b09821592711c73a6e747e07f928c3943f2444b66a1ff458d11972f5e439e39e31f8f28fc91cf06314f95945c9e5567ea06c92ee79a032665cd08a93", "20", "-7de523d73f78a7202ec344e5f2f2434edea54bd304b0d76746953106f7e446cae9186f0db830568e850121900064275c620bd744a902e58fa668685ce61932ab79497a398c2642f5ac5971dd2574e0a1b3311d8711141b330442b09821592711c73a6e747e07f928c3943f2444b66a1ff458d11972f5e439e39e31f8f28fc91cf06314f95945c9e5567ea06c92ee79a032665cd08a9300000000", .Okay}, + {.Shl, "f2abba0450ad2d7ceb270f4d3d9840e2b61c03caed3311ac1c8e9fb86335b582554901da24464757adce89e43fc90a58a0c27772366c44f3de1070ae52a3cc562b37fa5eac59dc76b7ee6d7b6ff3ba19eb0716ba762b3724e1c1ad90a26a9b0cf16f1e30378bec6ccfcd2b6e9172237ca642ed60f56cdf5386b284988181e87f9d85c9a9e6d3b6d06b0b1a9e3ab1f3a4765d52bf7886", "49", "1e5577408a15a5af9d64e1e9a7b3081c56c380795da662358391d3f70c66b6b04aa9203b4488c8eaf5b9d13c87f9214b14184eee46cd889e7bc20e15ca54798ac566ff4bd58b3b8ed6fdcdaf6dfe77433d60e2d74ec566e49c3835b2144d53619e2de3c606f17d8d99f9a56dd22e446f94c85dac1ead9bea70d6509310303d0ff3b0b9353cda76da0d616353c7563e748ecbaa57ef10c000000000000000000", .Okay}, + {.Shl, "-e0f5e95519820ffbad25e4231e2ea406615fc28bb4b9ae0887c62e2ed0c9c698e5f5413428f134f2dafaf2c1390cabfa8f1f20efa8c01372b895d5ead1ffb2eaea883a78678793ddd55bb3a3cffcb7140f228e6feef75d7584b1bf0717180665ec5a7a7001ebf7e4bb069cad0a9f768b21b12062e44bb469247657392b1bede5885bf58a97f4fc171c0b09ae29708d66a02d746c11b7", "74", "-e0f5e95519820ffbad25e4231e2ea406615fc28bb4b9ae0887c62e2ed0c9c698e5f5413428f134f2dafaf2c1390cabfa8f1f20efa8c01372b895d5ead1ffb2eaea883a78678793ddd55bb3a3cffcb7140f228e6feef75d7584b1bf0717180665ec5a7a7001ebf7e4bb069cad0a9f768b21b12062e44bb469247657392b1bede5885bf58a97f4fc171c0b09ae29708d66a02d746c11b700000000000000000000000000000", .Okay}, + {.Shl, "fca6ea9394031001be7d213a534e52831685b498a903659aa4807263f9839b2969350d4acb2583cb698a6ab47cee1b2f48d23b198be54486b131d89abe5793495ba7889007d06e99d7abec35b1d367fd5b9ebfbe9e4fc1754b22e439027aedfd236047ab943c75833191a6d19b8a0ae881cddb16e201e149e57557dd575f98d0792f16d5887055799ea4a903aa3860a863d725078f59", "3d", "1f94dd527280620037cfa4274a69ca5062d0b69315206cb354900e4c7f3073652d26a1a95964b0796d314d568f9dc365e91a4763317ca890d6263b1357caf2692b74f11200fa0dd33af57d86b63a6cffab73d7f7d3c9f82ea9645c87204f5dbfa46c08f572878eb0663234da3371415d1039bb62dc403c293caeaafbaaebf31a0f25e2dab10e0aaf33d4952075470c150c7ae4a0f1eb2000000000000000", .Okay}, + {.Shl, "1fdeab42a4d28688edd5a8d0a10677908b8ffa438bd1509a56eb9f95daca9bb9d8df1c20980f0e8a80fd62c6ed730610c2af102f57243f53870fe27fde590e1096b8fd9a8b575b7b890749d3073353f99d3235d77e043afd16dc140ce98c4d5ab3e8208b69271fbae0735d45e40d147ccf461ef03f5d5dd6493d6791abbaf23f3c27200d783c45a7c2b5c0752cee0903346d210fe55a", "56", "7f7aad0a934a1a23b756a3428419de422e3fe90e2f4542695bae7e576b2a6ee7637c7082603c3a2a03f58b1bb5cc18430abc40bd5c90fd4e1c3f89ff796438425ae3f66a2d5d6dee241d274c1ccd4fe674c8d75df810ebf45b705033a631356acfa0822da49c7eeb81cd7517903451f33d187bc0fd75775924f59e46aeebc8fcf09c8035e0f1169f0ad701d4b3b8240cd1b4843f9568000000000000000000000", .Okay}, + {.Shl, "aedc339fdd2787faba971ff6e3e75f70073bf39d8dd6473e60d7aef1ceea00130c48b93143aa059be6aa71fc94a77f74d00b64cfdfcb5e0f3fc570b7b2ea2f664bcb2e876d21062ad84676e534f64357a12dbad2eafb11715af0cde6bd4598ef16275e76b8493f2932bbf8b66edf725bf5990f875a8e487e9036d75d2d843c7657341d429b439ee9b6cb51258a273bba37f61322b4d6", "8", "aedc339fdd2787faba971ff6e3e75f70073bf39d8dd6473e60d7aef1ceea00130c48b93143aa059be6aa71fc94a77f74d00b64cfdfcb5e0f3fc570b7b2ea2f664bcb2e876d21062ad84676e534f64357a12dbad2eafb11715af0cde6bd4598ef16275e76b8493f2932bbf8b66edf725bf5990f875a8e487e9036d75d2d843c7657341d429b439ee9b6cb51258a273bba37f61322b4d600", .Okay}, + {.Shl, "-346e1df1dc58b56a9abd10e11a9649c2f0fa7d86f1c280f6ac503c03db1ff889f274b14c747ddba402b6bd4b7157d7c6c73459358bbc1bb045e530f721ccbde0a3fa242f2399c1bf1ea3adddc9e6867b2234c5d4fd838cf6140c2a27079a51df1fe4513a786b4fedee53cb3ce5fc98e7beaf5447c89a130703f58a2f81bc52a5b310be2e0e06f2301eeb86c0454e0261944d9dc17204", "35", "-68dc3be3b8b16ad5357a21c2352c9385e1f4fb0de38501ed58a07807b63ff113e4e96298e8fbb748056d7a96e2afaf8d8e68b26b177837608bca61ee43997bc147f4485e4733837e3d475bbb93cd0cf644698ba9fb0719ec2818544e0f34a3be3fc8a274f0d69fdbdca79679cbf931cf7d5ea88f9134260e07eb145f0378a54b66217c5c1c0de4603dd70d808a9c04c3289b3b82e4080000000000000", .Okay}, + {.Shl, "c5b0660ce03b0c1856f86b5f173a03980797b67543d0167a3c68f18dc4714682a428fd5dfe4a427528a0b234de083c0bc05bb47e3b5a55e2a85cdd8f47458c38b3a397a13217b242f2582126db69d44067f97a5a6c29f911ba4bd7db467958a2d38f7d6c18522f678113ac827578c197c40a52070e4097323c5bad9cde3fce15b9b234874659781f05335c4856053db65c09efad3756", "4e", "316c1983380ec30615be1ad7c5ce80e601e5ed9d50f4059e8f1a3c63711c51a0a90a3f577f92909d4a282c8d37820f02f016ed1f8ed69578aa173763d1d1630e2ce8e5e84c85ec90bc960849b6da751019fe5e969b0a7e446e92f5f6d19e5628b4e3df5b06148bd9e044eb209d5e3065f1029481c39025cc8f16eb67378ff3856e6c8d21d1965e07c14cd71215814f6d97027beb4dd580000000000000000000", .Okay}, + {.Shl, "-c52879f49b8a3ad936b90d8fca4962c4ef9af6a3ea42cf2257be2f752ad5def2e37d138d83eef773ce47c5265f6172dd6fa2a8a092e26581de24eca2297444a39ddde250895e8b2ad09c95ac1b114f1531baa29521f12fa4b1a54848c8916041d455a8e1bf0c55293746a42b8e29149f01bde6e45e0d6bed03ed5f7b539e86ef8b6812e530d1c67ec2c0382cd665385960cdecc56270", "4b", "-62943cfa4dc51d6c9b5c86c7e524b16277cd7b51f52167912bdf17ba956aef7971be89c6c1f77bb9e723e2932fb0b96eb7d15450497132c0ef12765114ba2251ceeef12844af4595684e4ad60d88a78a98dd514a90f897d258d2a4246448b020ea2ad470df862a949ba35215c7148a4f80def3722f06b5f681f6afbda9cf4377c5b409729868e33f61601c166b329c2cb066f662b1380000000000000000000", .Okay}, + {.Shl, "-a055bdc8d1a3003cc8b199c098f58ff409af5d1f7379b0d4a7d157f1cf6bb93cb02ceeb266a61ef26c495f793149b5fe667c51efa401baf0eb9ab97ec3fe42a1075d83441dfbd870534d874018292731b3932c9bc4f33f19a366d8ff102e1ec3b6f18b22eb02e858d4169868bda4b78cb2821de5e3f8a8c820b325b2d2be36c6c79e2f5351242148e011dff1d39ae3a89657cbab6c2e", "6e", "-28156f723468c00f322c6670263d63fd026bd747dcde6c3529f455fc73daee4f2c0b3bac99a987bc9b1257de4c526d7f999f147be9006ebc3ae6ae5fb0ff90a841d760d1077ef61c14d361d0060a49cc6ce4cb26f13ccfc668d9b63fc40b87b0edbc62c8bac0ba163505a61a2f692de32ca0877978fe2a32082cc96cb4af8db1b1e78bd4d4490852380477fc74e6b8ea2595f2eadb0b8000000000000000000000000000", .Okay}, + {.Shl, "25ff8c77bc04a276172e1281f81bbddf14a3239017a66fb9305976cc28c55e33e8fca01c8fc1bae5873aa7f7c56f55e75630326069f0991bd9d5278357b7e5fb226b526e9df7c6ac5c895036330370e96f78bbba70cbf2f13e6e0480c65bb9cb2a050b9850c118f4b29869d15314bf00fce09afed9e36547caa20d5a26bf3e9c30855ae18d644b8e5fbb24b3dffdfcbed85bddf8e63f", "69", "4bff18ef780944ec2e5c2503f0377bbe294647202f4cdf7260b2ed98518abc67d1f940391f8375cb0e754fef8adeabceac6064c0d3e13237b3aa4f06af6fcbf644d6a4dd3bef8d58b912a06c6606e1d2def17774e197e5e27cdc09018cb77396540a1730a18231e96530d3a2a6297e01f9c135fdb3c6ca8f95441ab44d7e7d38610ab5c31ac8971cbf764967bffbf97db0b7bbf1cc7e00000000000000000000000000", .Okay}, + {.Shl, "f820074502cdd4823f44b939ef8982a0bfbd01cef73cc1dac8323c3261ded35c03c67c9641c90813c48f4421f490ae7af405941059f1ae5f394079c7bf69ceab35042db2e913766a39f0227f4426d2653260b522d442eb3169e0bfa8317a9462e23ed433631ad672eca78748b3a3ff625336c60d21ac792b65d93f88f27da33da1c162965eab29121e14392e3f636d96a99c2e382e62", "40", "f820074502cdd4823f44b939ef8982a0bfbd01cef73cc1dac8323c3261ded35c03c67c9641c90813c48f4421f490ae7af405941059f1ae5f394079c7bf69ceab35042db2e913766a39f0227f4426d2653260b522d442eb3169e0bfa8317a9462e23ed433631ad672eca78748b3a3ff625336c60d21ac792b65d93f88f27da33da1c162965eab29121e14392e3f636d96a99c2e382e620000000000000000", .Okay}, + {.Shl, "-50b040fa6b955f281924b6f1e3a30c46bad1d05628d38d2d5195dd0c3b1b8def7b728d7329c812b07d9e9447707722069a9cd52e9fe1338ea2b4871906e7f16c22ff789c2833c21e674f0aa755fff1f939482b43eee839bf238d981d50a2ffe503f72bdf325d6c20fe438d7a8dc160defd6effc6d8b0c956a74830b48207faac429540de3e1584fa2628464b9f40c9bffcf616e151da", "3f", "-2858207d35caaf940c925b78f1d186235d68e82b1469c696a8caee861d8dc6f7bdb946b994e409583ecf4a23b83b91034d4e6a974ff099c7515a438c8373f8b6117fbc4e1419e10f33a78553aafff8fc9ca415a1f7741cdf91c6cc0ea8517ff281fb95ef992eb6107f21c6bd46e0b06f7eb77fe36c5864ab53a4185a4103fd56214aa06f1f0ac27d13142325cfa064dffe7b0b70a8ed0000000000000000", .Okay}, + {.Shl, "-4782c3fd1f8e811a33d1fd36a2aa0067c191c0c54168bd21e3dec443e8adba629a26ac22a697e499cb23c4cfd05e72dcd835f5fb5ea1c22d27884a7babab780c986929d8d9fe4a2dd56e52c8ac13f787cf48b4f1b4e02e5abacb7d32702efdbc0e2e25dab073360c19c7f67a2f06eec042248e3e64bd3e1af1fa43d0631820dc030aab44305c77ceb42aa6f47acf235c9a1e00bcfaf5", "2c", "-4782c3fd1f8e811a33d1fd36a2aa0067c191c0c54168bd21e3dec443e8adba629a26ac22a697e499cb23c4cfd05e72dcd835f5fb5ea1c22d27884a7babab780c986929d8d9fe4a2dd56e52c8ac13f787cf48b4f1b4e02e5abacb7d32702efdbc0e2e25dab073360c19c7f67a2f06eec042248e3e64bd3e1af1fa43d0631820dc030aab44305c77ceb42aa6f47acf235c9a1e00bcfaf500000000000", .Okay}, + {.Shl, "-291b2ac6ce7b1af1e7f630ecfb88b1ed82e0d978ce6362d8e75d8af32502757ba50979c58326168a6a1c49c89e79ba1d27c7fb5c90e7c019e0aa7ad4d451422eebad4937190610b2fe9268a654a797fe022c1d3291b333ef8fe86adb7cdab65deeccfbc1a349ab271b1300a90effb1e540609af43ea53414a900cf979affa074a95b1fc52c110609d57cd745f21ae06757253ccd381", "2", "-a46cab1b39ec6bc79fd8c3b3ee22c7b60b8365e3398d8b639d762bcc9409d5ee9425e7160c985a29a871272279e6e8749f1fed72439f006782a9eb53514508bbaeb524dc641842cbfa49a299529e5ff808b074ca46cccfbe3fa1ab6df36ad977bb33ef068d26ac9c6c4c02a43bfec79501826bd0fa94d052a4033e5e6bfe81d2a56c7f14b044182755f35d17c86b819d5c94f334e04", .Okay}, + {.Shl, "4367438e9c1f84f4d399683e4a85c2cecc47af17854379911c0a1d04c655514393406bd1946a47a9f8fa9e344cc07f9b6e872d7641fec3b1ef5c2124db3745d47677f83331763c2d7133bfc69f74ea1ea7f0d32d2ca3af95c2a125e622d42c68840b3e4a3d4e07d63853fda7098abc151f97edbfa3ba04e340dcdc7a19dd0bbcf6e286a6d5ccba77d6f88ee9e92db1ebbfb84aab460a", "f", "21b3a1c74e0fc27a69ccb41f2542e1676623d78bc2a1bcc88e050e82632aa8a1c9a035e8ca3523d4fc7d4f1a26603fcdb74396bb20ff61d8f7ae10926d9ba2ea3b3bfc1998bb1e16b899dfe34fba750f53f869969651d7cae15092f3116a163442059f251ea703eb1c29fed384c55e0a8fcbf6dfd1dd0271a06e6e3d0cee85de7b7143536ae65d3beb7c4774f496d8f5dfdc2555a3050000", .Okay}, + {.Shl, "-80b861c91513357f6a1f3618e99b22aa2478018b65f909d5ad9891b16893cf504cebed05d87a512b3b9480859839b4b4d376d822541f6cb6b15d44af43d723bf937619b4169a79cae05b3b08bc6ffadd16422079085063bf1ebd664dcc39279967c21efddb7a1cacbcdc62b5a441f675a8e047e5a8bd03e6ccd1aedbda288c034d95b96ffd0550f31e0d371c1e81a52fb3a95112cfe7", "a", "-202e18724544cd5fda87cd863a66c8aa891e0062d97e42756b66246c5a24f3d4133afb41761e944acee52021660e6d2d34ddb6089507db2dac57512bd0f5c8efe4dd866d05a69e72b816cec22f1bfeb74590881e421418efc7af5993730e49e659f087bf76de872b2f3718ad69107d9d6a3811f96a2f40f9b3346bb6f68a2300d3656e5bff41543cc7834dc707a0694becea5444b3f9c00", .Okay}, + {.Shl, "-ddf19ff05a4595680227eef3b2fde008a30af05b28335ba74fc1d610d594b8f0535bb4a0a9e3b0864fdd23273071b7faca7d428946ee07014e927e9b5f391987ddd23a4f191668859c05b6af13a5892e933588ce38708510f04b54fafbe4f5cf7ed8bc8c9496c4c660b4da25ffe449e6652aab3aa87d59127cbe464bc7dbfdfa498e1729cff67ba2ea4ca385f3ae184726da82a0b4a7", "8", "-ddf19ff05a4595680227eef3b2fde008a30af05b28335ba74fc1d610d594b8f0535bb4a0a9e3b0864fdd23273071b7faca7d428946ee07014e927e9b5f391987ddd23a4f191668859c05b6af13a5892e933588ce38708510f04b54fafbe4f5cf7ed8bc8c9496c4c660b4da25ffe449e6652aab3aa87d59127cbe464bc7dbfdfa498e1729cff67ba2ea4ca385f3ae184726da82a0b4a700", .Okay}, + {.Shl, "6d29ccc0bc3acc49e433e7b0e15075bd9eb7c2119ae3dceaae5db15e8ca2f0566df4400844dca4a3d23f1a84118ddca3e2ee3951aef2916781f48a2f952dd3fd2e460fb33e00193856e4eeffdddef214bbc509a64be9fc59bf89dde20b71545d1fbc7ff1701eb1eaf3702a8c5367d8c9e189b30b59c3e75100980999e855055358c14efa37fa08d1fe0eb3a15885efd8731c6a99a289", "2f", "3694e6605e1d6624f219f3d870a83adecf5be108cd71ee75572ed8af4651782b36fa2004226e5251e91f8d4208c6ee51f1771ca8d77948b3c0fa4517ca96e9fe972307d99f000c9c2b72777feeef790a5de284d325f4fe2cdfc4eef105b8aa2e8fde3ff8b80f58f579b8154629b3ec64f0c4d985ace1f3a8804c04ccf42a82a9ac60a77d1bfd0468ff0759d0ac42f7ec398e354cd144800000000000", .Okay}, + {.Shl, "-3feb0fd712a20fe3b38b71a848c3bb9989bd27fdf8a83b513c37b291b1a7630f3cafd52699da510f76167878a1afbd592d9ce4171811ce2fb43e791b9fa3faa88778bfb7c6f5c79da98ca7702eef3c33e966e4380e5b238d2262df6a429e0546996a1e73b3297fb3bd67e2f340256d53ba14cd117d4e5c696267b2cb401d2019f21d416b8243fab524e0441f75455e68d4420e000516", "2c", "-3feb0fd712a20fe3b38b71a848c3bb9989bd27fdf8a83b513c37b291b1a7630f3cafd52699da510f76167878a1afbd592d9ce4171811ce2fb43e791b9fa3faa88778bfb7c6f5c79da98ca7702eef3c33e966e4380e5b238d2262df6a429e0546996a1e73b3297fb3bd67e2f340256d53ba14cd117d4e5c696267b2cb401d2019f21d416b8243fab524e0441f75455e68d4420e00051600000000000", .Okay}, + {.Shl, "-d0307f04ca283e10f2586a0f2ce7218233142da075c54d202b068442d59cfdbb3056de84d2b5f9932f3631623f597c413cd2e9c45f74b0ce3174e50accbfe43f8b96694ffd49a2d9e7fb289b8bc2da3c6365533ed66f5f056d8fcc4b3d0a064ee5790d3b83692986c670e867dc38f1441af678aad0ecf3221a77833190a9f55591b670113893ac07f328642ad39c7fed08beef73f0c3", "3f", "-68183f8265141f08792c3507967390c1198a16d03ae2a690158342216ace7edd982b6f42695afcc9979b18b11facbe209e6974e22fba586718ba7285665ff21fc5cb34a7fea4d16cf3fd944dc5e16d1e31b2a99f6b37af82b6c7e6259e85032772bc869dc1b494c363387433ee1c78a20d7b3c55687679910d3bc198c854faaac8db38089c49d603f994321569ce3ff6845f77b9f8618000000000000000", .Okay}, + {.Shl, "-9490fe1c9427a8e0bd56d86b73d2379790fc2139a89148af932b94e3224d67c24bbad56766e83ea88921506f1912081efb60a6d80be2e409ad2c354087b469ed7d0d604922db69281b00313aaeb3588d7894b9d89d140151b33c73841c5ac56e801caa9c913f4abf82f73a165f11d20e1c5d0c0c44cde8724b49eaa6bc693aed869e763dd48e4efa4e1b9e864293b83ee2339dbbd36e", "19", "-12921fc39284f51c17aadb0d6e7a46f2f21f842735122915f265729c6449acf849775aacecdd07d511242a0de3224103df6c14db017c5c8135a586a810f68d3dafa1ac09245b6d250360062755d66b11af12973b13a2802a36678e70838b58add00395539227e957f05ee742cbe23a41c38ba1818899bd0e49693d54d78d275db0d3cec7ba91c9df49c373d0c8527707dc4673b77a6dc000000", .Okay}, + {.Shl, "-a2e00cb51fbd19581226bec7d415ff73c18235fbd84cd0ed91f3c78eab4dc77e7dce4a9fec6c498199b937f6dcc11ec066a07387ac5e51ad9c16f45300d80887e50ceff7f12fccb1b3342ad3e1edfb28ce228ee69ee07e9c673433ca3de9d38b1083aafe81debf6f6f817d7db0ed7aff8d5225b21279e61071120000361e5f326d8032b1af655e561d2af20d092b8ac9c3e858bb30bd", "6a", "-28b8032d47ef46560489afb1f5057fdcf0608d7ef613343b647cf1e3aad371df9f7392a7fb1b1260666e4dfdb73047b019a81ce1eb17946b6705bd14c0360221f9433bfdfc4bf32c6ccd0ab4f87b7eca3388a3b9a7b81fa719cd0cf28f7a74e2c420eabfa077afdbdbe05f5f6c3b5ebfe354896c849e79841c4480000d8797cc9b600cac6bd95795874abc83424ae2b270fa162ecc2f400000000000000000000000000", .Okay}, + {.Shl, "-afb99f56f846932399cb23683a3dccf18585c35cb2626e053476c5a45a54698435910aeef64681addac2a956b200cb7e69c0505c4a796e659c0685d25776a611e5bcca4e55eac13c8ffdfe6c653a5f29e8ede0cc7a176c0086de7da30409a353382947ed034190114a7bf71089d26faea47781c56eba38f0573c96654fb25c10c90ffc2a039597553aa25a266fb258520c5d80160b40", "3c", "-afb99f56f846932399cb23683a3dccf18585c35cb2626e053476c5a45a54698435910aeef64681addac2a956b200cb7e69c0505c4a796e659c0685d25776a611e5bcca4e55eac13c8ffdfe6c653a5f29e8ede0cc7a176c0086de7da30409a353382947ed034190114a7bf71089d26faea47781c56eba38f0573c96654fb25c10c90ffc2a039597553aa25a266fb258520c5d80160b40000000000000000", .Okay}, + {.Shl, "-eaaeb9845289c656b3f68d900a79f7668bf1f69ae4529157ac9c17180a6a9dc997543ae1ad1cce04cac1dc2b8121a37718dd196e6ccdf959a5ec48fe696b7a5ab6022940713fe546a5e11e19d2e540c6449981da14c0b268c0e020d226aa0f367c9729dfcc09e71a32cb2b300ddc10762b9f161d41d419ef3fede72dbc80918e83b5e13694c49529aae41eb3b3b16814523584689135", "b", "-75575cc22944e32b59fb46c8053cfbb345f8fb4d722948abd64e0b8c05354ee4cbaa1d70d68e67026560ee15c090d1bb8c6e8cb73666fcacd2f6247f34b5bd2d5b0114a0389ff2a352f08f0ce972a063224cc0ed0a605934607010691355079b3e4b94efe604f38d1965959806ee083b15cf8b0ea0ea0cf79ff6f396de4048c741daf09b4a624a94d5720f59d9d8b40a291ac234489a800", .Okay}, + {.Shl, "-7eca7d013143c5857b800e3989b82ba214f9a2740fbb41b81e2b6f9ea77f5897e79b496e476c8b0273d7732ededbe572f9c84dbdb96e8fff1f7af44dbee07db0291c76d672476e7a016dff2c3c0731c203a06f1bc3f70f2ae6eb13cc629ec62796a3d33d914f254c4cc8cf5e110de29620b90cbe4e8aee042522ee1476575b9f9c6c52cb7bbd9ba68edfc45adc3c0d5ce9e1b8a3e8b3", "49", "-fd94fa0262878b0af7001c731370574429f344e81f7683703c56df3d4efeb12fcf3692dc8ed91604e7aee65dbdb7cae5f3909b7b72dd1ffe3ef5e89b7dc0fb605238edace48edcf402dbfe58780e63840740de3787ee1e55cdd62798c53d8c4f2d47a67b229e4a9899919ebc221bc52c4172197c9d15dc084a45dc28ecaeb73f38d8a596f77b374d1dbf88b5b8781ab9d3c37147d166000000000000000000", .Okay}, + {.Shl, "c773df1157cf00a8a40016a16fba9e9b5cf2463fe90928b2eed810d74bbff52e630720bf9162db243506acb2184149603bbcf0272f739aa781fd3ad87f9616eb39d4dfaa7269a2b27255721e88ae2a87415ce84e149385324bf0a2f0839c4d9223d9a66869f1f5564bcc378132e09a037fed7ae7dc65256a30e844bf1a4c1100c749e5eb58b7319707ef236bcfe1e8bb71231547781f", "78", "c773df1157cf00a8a40016a16fba9e9b5cf2463fe90928b2eed810d74bbff52e630720bf9162db243506acb2184149603bbcf0272f739aa781fd3ad87f9616eb39d4dfaa7269a2b27255721e88ae2a87415ce84e149385324bf0a2f0839c4d9223d9a66869f1f5564bcc378132e09a037fed7ae7dc65256a30e844bf1a4c1100c749e5eb58b7319707ef236bcfe1e8bb71231547781f000000000000000000000000000000", .Okay}, + {.Shl, "55366899a50ec665fc04f40a5e3950559e79d1c8ac7b3e34b05dbbe3c0b1359f76b7ef8fc298f2b1c8bd38e552b524ba15778bac2ec398fc4344f9788ec03b9ad7e6e2ddef2fd05ccdcef0c1c9edf5b21606d0bd5d92dffbc9eee135b707233ccecceb4978e56dc1cbd3ae5afe4a494ca02709987c8d02c1eb0ae2cdb35c18f5dae566b8245d42cc3dc6247a60882bdd6cccadf3ec43", "4", "55366899a50ec665fc04f40a5e3950559e79d1c8ac7b3e34b05dbbe3c0b1359f76b7ef8fc298f2b1c8bd38e552b524ba15778bac2ec398fc4344f9788ec03b9ad7e6e2ddef2fd05ccdcef0c1c9edf5b21606d0bd5d92dffbc9eee135b707233ccecceb4978e56dc1cbd3ae5afe4a494ca02709987c8d02c1eb0ae2cdb35c18f5dae566b8245d42cc3dc6247a60882bdd6cccadf3ec430", .Okay}, + {.Shl, "c7d44c6fa7509e4b2b2bfbe836edf783b713105dbe121206dbb1b14e3678e30843cfd2197ada73e29da7b0a77ba67474065e62994d096a91b6ed7e350eba85bd7f9ef4368a125906c916719c3495c9a330fecb14d0842e836a698fb266aab12982b328d97417957d04a3c8f21287cad661e49a2164e695308d741c9fd1156a86c690ea842f3a152831e272a0211ecb6fdcbbfcf943e5", "2e", "31f5131be9d42792cacafefa0dbb7de0edc4c4176f848481b6ec6c538d9e38c210f3f4865eb69cf8a769ec29dee99d1d019798a653425aa46dbb5f8d43aea16f5fe7bd0da2849641b2459c670d257268cc3fb2c534210ba0da9a63ec99aaac4a60acca365d05e55f4128f23c84a1f2b5987926885939a54c235d0727f4455aa1b1a43aa10bce854a0c789ca80847b2dbf72eff3e50f9400000000000", .Okay}, + {.Shl, "-ed184f9f2630d93cde2941613612ee9e6c30a0ded5df73a2e98865fa171b691e234bf4e377cf655e0abea5e8a462d743f468799995e4aed16356b518c094a151903fba9c8f1c7ddeef62ef2afc03b75bc8f345fcc699d8186a9498bfc40269670aba2912fb8a269e6b03f815e4b2119c6c3f0db0918c8f1e5c56a3f6302ae6211c5044808869e2c07065799d4e8ce739dc92a4690f73", "17", "-768c27cf93186c9e6f14a0b09b09774f3618506f6aefb9d174c432fd0b8db48f11a5fa71bbe7b2af055f52f452316ba1fa343ccccaf25768b1ab5a8c604a50a8c81fdd4e478e3eef77b177957e01dbade479a2fe634cec0c354a4c5fe20134b3855d14897dc5134f3581fc0af25908ce361f86d848c6478f2e2b51fb181573108e2822404434f1603832bccea746739cee49523487b9800000", .Okay}, + {.Shl, "e9d598550128bb56b1ca9c54cfedc4d85054c93ea3e076dc4e53b05c11d4a81baa0529c71f521ecc68552b5337b2fad3676f090c3727cb3f3235f7c854f404b1227d6598bb57756bfd7774f304ffc86204ac99730b07bba3cda2d3adb310a3d2133f55c12a42ef6be77872821269e37758b118dc2c94846dd60297e482f420e2871217d1e562198305e6966f2c197a1df76c3b84f44c", "62", "3a756615404a2ed5ac72a71533fb71361415324fa8f81db71394ec1704752a06ea814a71c7d487b31a154ad4cdecbeb4d9dbc2430dc9f2cfcc8d7df2153d012c489f59662ed5dd5aff5ddd3cc13ff218812b265cc2c1eee8f368b4eb6cc428f484cfd5704a90bbdaf9de1ca0849a78ddd62c46370b25211b7580a5f920bd0838a1c485f479588660c179a59bcb065e877ddb0ee13d130000000000000000000000000", .Okay}, + {.Shl, "-14c9918d2e65a819487e9d603bcf570b602f39709d1fdb6d77b325a04267e773187d5ad4115ae8707f36bc5aad941f204af6ecbd2e1b313602f2bad342ed60d7a33fa3344e457f00f7bb7e24477ad5992098fc645397b27724adb4563c005719f13cc8840038f48062ce415566c6a796382fa9d94a8f897007f7a51d03ff44d2f8d8744b48d65caa421d4c4365ca6c57b5ee4a0423ba", "12", "-53264634b996a06521fa7580ef3d5c2d80bce5c2747f6db5decc9681099f9dcc61f56b50456ba1c1fcdaf16ab6507c812bdbb2f4b86cc4d80bcaeb4d0bb5835e8cfe8cd13915fc03deedf8911deb56648263f1914e5ec9dc92b6d158f0015c67c4f3221000e3d2018b3905559b1a9e58e0bea7652a3e25c01fde94740ffd134be361d12d235972a90875310d9729b15ed7b928108ee80000", .Okay}, + {.Shl, "33af503e7433916b09542c018bc6d3ef86bace760866eb81bff265b6bf559080d7cda6aaef535e395e0e5544b09234dd68fcad85f913fa6cc9653f4afa764548077903f613759fdf44d94d6567321622136a1a4dba25f321e80d8f009f43c08002022aa35b51764f49f221e080cdc567f48e7fad1ac760de1390943e7d3c422f147bd8e62339a66fb62484e4c241fc01d38667d4a946", "61", "675ea07ce86722d612a85803178da7df0d759cec10cdd7037fe4cb6d7eab2101af9b4d55dea6bc72bc1caa89612469bad1f95b0bf227f4d992ca7e95f4ec8a900ef207ec26eb3fbe89b29acace642c4426d4349b744be643d01b1e013e87810004045546b6a2ec9e93e443c1019b8acfe91cff5a358ec1bc2721287cfa78845e28f7b1cc46734cdf6c4909c98483f803a70ccfa9528c000000000000000000000000", .Okay}, + {.Shl, "-794509acf09f3e04d2770436e818512363c63f90dffeef055d388839a57047dc6829bc7c9fcbfe9ebbb5aebe0c46df02b5f51cf629977f50e90ec719ba6858ca07a6445eac3ecd1e1e1cc1a70166626989663f6c07de227945642f4fa4d340f06b133068453a2e0c6140f39f7ed5df0ab4688becf615a5f3040aabc97eb424e53355e3e17993e7582e8dab0e1eec5e00d8779bb461d7", "22", "-1e51426b3c27cf81349dc10dba061448d8f18fe437ffbbc1574e220e695c11f71a0a6f1f27f2ffa7aeed6baf8311b7c0ad7d473d8a65dfd43a43b1c66e9a163281e99117ab0fb34787873069c059989a62598fdb01f7889e51590bd3e934d03c1ac4cc1a114e8b8318503ce7dfb577c2ad1a22fb3d85697cc102aaf25fad09394cd578f85e64f9d60ba36ac387bb1780361de6ed1875c00000000", .Okay}, + {.Shl, "-2022594775e741fdddc249e3ade53df44c561fee0c9175266d9d1c6f132b5df80783c4126e7db0f162fda3c46a9e1768970ad73f5ceb95b3338cfb2f8575778b4d89e910e044d3bfc89fb250a757ae4840addc091979a92179ba0a389634a0941a9e27e5fa21b6d0226cda7a2b8c7d56240193512f0c47c372151d068913575cb7abe8bbbf3567448a29dd1e4f55fe3c42cd32c3ab07", "35", "-4044b28eebce83fbbb8493c75bca7be898ac3fdc1922ea4cdb3a38de2656bbf00f078824dcfb61e2c5fb4788d53c2ed12e15ae7eb9d72b666719f65f0aeaef169b13d221c089a77f913f64a14eaf5c90815bb81232f35242f37414712c694128353c4fcbf4436da044d9b4f45718faac480326a25e188f86e42a3a0d1226aeb96f57d1777e6ace891453ba3c9eabfc78859a6587560e0000000000000", .Okay}, + {.Shl, "51bf53220729fde68fabfa209707217a41e5496f6e3d9b05e0e0eda0ba3416326f4bbb94bb2ec4c7b82222e8603a2edb2745302110e984a2c02de63249184ca496ce1f126b46738c03f83214b069e96baf09f9d546e9d322d3351d9f4a26d83b6863cb28aff76238d1bf0cf797d7c280aa1e7b96e0c2d6fd47d89c590befc108ea5056f22a82491572078b028061b28bd6c85f655cd4", "23", "28dfa9910394fef347d5fd104b8390bd20f2a4b7b71ecd82f07076d05d1a0b1937a5ddca5d976263dc111174301d176d93a298108874c2516016f319248c26524b670f8935a339c601fc190a5834f4b5d784fceaa374e991699a8ecfa5136c1db431e59457fbb11c68df867bcbebe140550f3dcb70616b7ea3ec4e2c85f7e08475282b791541248ab903c5814030d945eb642fb2ae6a000000000", .Okay}, + {.Shl, "cdffaed1c25fe8228dfaf4e115cd415e6c753926d84c386f93601217867dceb8d3935e4f0fbcd4fd343535b9e943f2d82d002cf33412252b892822115678e5cb9616f36c2dc58b1236c64b949d4468616f5611a5769d934314808a5a6084a7dc718f9493a6eaaba193e3a00cfd149594d77cd9bbd50b61264d403ba4ff6f7b33d27b5ba8750dae08c380d632989e20bd58441bdb6421", "21", "19bff5da384bfd0451bf5e9c22b9a82bcd8ea724db09870df26c0242f0cfb9d71a726bc9e1f79a9fa686a6b73d287e5b05a0059e668244a5712504422acf1cb972c2de6d85b8b16246d8c97293a88d0c2deac234aed3b2686290114b4c1094fb8e31f29274dd5574327c74019fa292b29aef9b377aa16c24c9a807749fedef667a4f6b750ea1b5c118701ac65313c417ab08837b6c84200000000", .Okay}, + {.Shl, "cc4b93e921e2916a4bef59d1309b9a593308d8c295300bdc88ad063921f154ce440b79ff5aab84d646d129dc462248157cec269a0b7d0ee07aa9543ecd40c486bfb0555dbd4881c33286d7737bad0f962374ed5524973220db554c07199b8b2dd8484ff30cf42ad490379e02f83d95302d6b0d256ffa7b868a5e4e1e78ecaec44633345adb433cc7bc0a1822bb8d6cbc5c70cd38dd7b", "11", "1989727d243c522d497deb3a2613734b26611b1852a6017b9115a0c7243e2a99c8816f3feb55709ac8da253b88c44902af9d84d3416fa1dc0f552a87d9a81890d7f60aabb7a910386650daee6f75a1f2c46e9daaa492e6441b6aa980e3337165bb0909fe619e855a9206f3c05f07b2a605ad61a4adff4f70d14bc9c3cf1d95d888c6668b5b686798f78143045771ad978b8e19a71baf60000", .Okay}, + {.Shl, "715e2c51fefb3cd988fd3da174490ad03a373af9dabec597ff3ee3a98a66616d51847e1cf53eaa986bbf658474f5c9804175f4f46bf5a30913399972efdbf72ce5a143b7f525d03d353cab8c48ddd1ef2c5d0a7b4ab66dff103466d7b69dff55a18a48185b3fb40563f4383d9050cb7f7eae3c7ea55005a375f0841d246f6b66a749c35fb65389eae8b020e01567ac3d5e7d58df0377", "39", "e2bc58a3fdf679b311fa7b42e89215a0746e75f3b57d8b2ffe7dc75314ccc2daa308fc39ea7d5530d77ecb08e9eb930082ebe9e8d7eb4612267332e5dfb7ee59cb42876fea4ba07a6a79571891bba3de58ba14f6956cdbfe2068cdaf6d3bfeab43149030b67f680ac7e8707b20a196fefd5c78fd4aa00b46ebe1083a48ded6cd4e9386bf6ca713d5d16041c02acf587abcfab1be06ee00000000000000", .Okay}, + {.Shl, "-eb60e17338f8843e30f1d4fac770946bc327f54404ff21c1d9138be01b2c05ebcae251cbe140da5028c4a09864bd9875fc241283a67e667ff2ea31f48d8242efcaf30866c49ad8b372bd585426878842b0bf204ae8e9311f8c6c908a4242a5521245f82b1fe5c8410b9d560e10c6845b5f2bea7f9fda3b2fe6295eda64f5d9db4214fb75c58db28e1526fd75c336c72f9fdfad3d9e55", "2", "-3ad8385cce3e210f8c3c753eb1dc251af0c9fd51013fc8707644e2f806cb017af2b89472f85036940a312826192f661d7f0904a0e99f999ffcba8c7d236090bbf2bcc219b126b62cdcaf561509a1e210ac2fc812ba3a4c47e31b24229090a95484917e0ac7f9721042e755838431a116d7cafa9fe7f68ecbf98a57b6993d7676d0853edd71636ca38549bf5d70cdb1cbe7f7eb4f67954", .Okay}, + {.Shl, "ddd71c59e7192f89affec6c09fad10577e12b7804af847405aeba3efd845395af6d06240c94bb970f456e2125ae52809c921c58ba67797c265babc7ee8e93089a810a74ed79807c739d094cfa51823a555e9dd68592f9e6061d53ba9615d40b0abedff9da3f4c5306fe1cb39819567d9e9209c2c134b0618b92aa6061095612dced44e7f055ff0b5e2c05aab261e42a7279ce6148b46", "40", "ddd71c59e7192f89affec6c09fad10577e12b7804af847405aeba3efd845395af6d06240c94bb970f456e2125ae52809c921c58ba67797c265babc7ee8e93089a810a74ed79807c739d094cfa51823a555e9dd68592f9e6061d53ba9615d40b0abedff9da3f4c5306fe1cb39819567d9e9209c2c134b0618b92aa6061095612dced44e7f055ff0b5e2c05aab261e42a7279ce6148b460000000000000000", .Okay}, + {.Shl, "20ce3278fa96a58420e27c69390d360d40288b7476c27311f1ff8982424099f4063c73ed0b07d05f52ca1f8131f40ad3506e3755a9ef15490415aa1be78e4ef4b3902098f6b7682a1115ffc9afe7ea5b0e93449911565bf97eea08c416c7c47bbc47671621e4df74394b46690979c06da777739d325219ae40fe2f9ae070c472754822379dc1d5cac234aeb6efc748200d4a024567a4", "53", "1067193c7d4b52c210713e349c869b06a01445ba3b613988f8ffc4c121204cfa031e39f68583e82fa9650fc098fa0569a8371baad4f78aa4820ad50df3c7277a59c8104c7b5bb415088affe4d7f3f52d8749a24c88ab2dfcbf7504620b63e23dde23b38b10f26fba1ca5a33484bce036d3bbb9ce99290cd7207f17cd703862393aa4111bcee0eae5611a575b77e3a41006a50122b3d2000000000000000000000", .Okay}, + {.Shl, "f44486c002d112c1fbc0008fd122263d7cbf641f0c0f2047fb69d2e796fb3ddf78425ee3561af2b88742c556463f565aa2ec44a4f1740c6ee841d0ba24d7a3d882e22c42db3e92cbdd8bd576b8d78460fce23ef86da397d60d7ff2a67cfc2048f26fee28f4b7594ca59deee0196e2673e9e498ec34a463d5cdd373fa91b98b3db902f59dec040a4bf253c778bed877441a48a20325e2", "1", "1e8890d8005a22583f780011fa2444c7af97ec83e181e408ff6d3a5cf2df67bbef084bdc6ac35e5710e858aac8c7eacb545d88949e2e818ddd083a17449af47b105c45885b67d2597bb17aaed71af08c1f9c47df0db472fac1affe54cf9f84091e4dfdc51e96eb2994b3bddc032dc4ce7d3c931d86948c7ab9ba6e7f52373167b7205eb3bd8081497e4a78ef17db0ee88349144064bc4", .Okay}, + {.Shl, "477dd246ac66bd3d9a127750764a8993883d2eedc036b9de2c659c5f58c4cf232e198ade26108910dd85dd28dc952a7c1cc8d8acd43aa8f8eeddd31624b9c01ff96fd0c8d8c92961ebdb9b3449df68a4e2a55689791f7acbf1b9a60523a2be46f9668a2fdf6078cfa91497c244b07b7cafdc2533ed79bda6fa78b3c8bfaca4e4bef1c627d2bd55ff6dc61fa3cf37d713ac4e026a906e", "64", "477dd246ac66bd3d9a127750764a8993883d2eedc036b9de2c659c5f58c4cf232e198ade26108910dd85dd28dc952a7c1cc8d8acd43aa8f8eeddd31624b9c01ff96fd0c8d8c92961ebdb9b3449df68a4e2a55689791f7acbf1b9a60523a2be46f9668a2fdf6078cfa91497c244b07b7cafdc2533ed79bda6fa78b3c8bfaca4e4bef1c627d2bd55ff6dc61fa3cf37d713ac4e026a906e0000000000000000000000000", .Okay}, + {.Shl, "97f74429b7bed13aca5e569da5ced94f27bf00ecc8c225ee69fa7f7f72504b9a227f914f467a439853bdcdcad73d57bd018deef6ada53915a0c5128df5639c4e1d26897bf3e30419210c93c99d649ea4595870b9234018ead0552ec4f129a6811db06b5df04298ccda7adf85310fa9f473917fe7d1ee74e2ab1637b85f33939783fc18ce6a3db87cddaf8149d727864a6d1c3d59aea", "14", "97f74429b7bed13aca5e569da5ced94f27bf00ecc8c225ee69fa7f7f72504b9a227f914f467a439853bdcdcad73d57bd018deef6ada53915a0c5128df5639c4e1d26897bf3e30419210c93c99d649ea4595870b9234018ead0552ec4f129a6811db06b5df04298ccda7adf85310fa9f473917fe7d1ee74e2ab1637b85f33939783fc18ce6a3db87cddaf8149d727864a6d1c3d59aea00000", .Okay}, + {.Shr_Signed, "-c5383bb26b02e40a4b64a9a55a5a6612729876436afca1e7b09f8a912ef209dc279dfa4a0f175dcab6a3a33e5ecfcc70d3361b99f8d2161424e07eebb5996b96af1c5dfc1d7db87fa3ba1cd26e098bc05d5a1a5fd1c6abeabdf6cca934926169709cf02d248fd2588543274bbcd360980e8b3aa78c29bb702b59cd1206369425fc11ef9c9e155033b7a7f1f4fe386f86561d334cb5ca", "36", "-314e0eec9ac0b90292d92a69569699849ca61d90dabf2879ec27e2a44bbc827709e77e9283c5d772ada8e8cf97b3f31c34cd86e67e34858509381fbaed665ae5abc7177f075f6e1fe8ee87349b8262f017568697f471aafaaf7db32a4d24985a5c273c0b4923f4962150c9d2ef34d82603a2cea9e30a6edc0ad67344818da5097f047be72785540cede9fc7d3f8e1bf", .Okay}, + {.Shr_Signed, "638c79b3ca747c025610274bb90278dfc5acec68e1944f9addb200ef1117e5493cf22a8aa8a39f3b8028d4ed696f185cc4344493d458b419bf7f718897bf6925c36df5bf5d5f4181be187e151ce1bbea58bb7d830ac787762e6bde31043b0d4ef81abef69d7f94948d23b0513d7ead07be90b1dc01e589fc77c9bb642a67990f1b727f4cf45877e11f30d3d4d1955ee102623a29d4dd", "6b", "c718f36794e8f804ac204e977204f1bf8b59d8d1c3289f35bb6401de222fca9279e4551551473e770051a9dad2de30b988688927a8b168337efee3112f7ed24b86dbeb7ebabe83037c30fc2a39c377d4b176fb06158f0eec5cd7bc6208761a9df0357ded3aff29291a4760a27afd5a0f7d2163b803cb13f8ef9376c854cf321e36e4fe99e8b0efc23", .Okay}, + {.Shr_Signed, "-5359c5316fc4fcb6886effb102d46b52cf7e1a0567d62bd0d1f0d006c258cb831b7551f62f6fe0d83986beebbd2f763379a732b5b58fbae9fc3658438925b769656f52a1037778d331ab20401e810ced4e89f203b9b05caf054e6cb5733c4c9e40e0fd359bebf5e1fad98ce5d4eb96d27abc0125653d6acd7761acb9be2fdc0f5fd6f6743084f97d626085a0b9c62e9bde649a5f5854", "20", "-5359c5316fc4fcb6886effb102d46b52cf7e1a0567d62bd0d1f0d006c258cb831b7551f62f6fe0d83986beebbd2f763379a732b5b58fbae9fc3658438925b769656f52a1037778d331ab20401e810ced4e89f203b9b05caf054e6cb5733c4c9e40e0fd359bebf5e1fad98ce5d4eb96d27abc0125653d6acd7761acb9be2fdc0f5fd6f6743084f97d626085a0b9c62e9bde65", .Okay}, + {.Shr_Signed, "-cef57e8b5a7b70088df176a1c2ed327142c19b66df270a96ebae7e1b3ad6778a05432fe8af8f2ddf46dba724848568e2fb3f04ab5bb1a1cc980227a6af6492b397af6531e6c7388bed25df578e503a0842767d97801186905fe441d5d6b719fa51950e955d073319bce8863b64f887595e9fe6093a53ad7578890e936a64ddc0cf465f8b1f58870d1a7c09b4380059507d4a711791ac", "4f", "-19deafd16b4f6e0111be2ed4385da64e2858336cdbe4e152dd75cfc3675acef140a865fd15f1e5bbe8db74e49090ad1c5f67e0956b763439930044f4d5ec925672f5eca63cd8e7117da4bbeaf1ca0741084ecfb2f00230d20bfc883abad6e33f4a32a1d2aba0e663379d10c76c9f10eb2bd3fcc1274a75aeaf1121d26d4c9bb819e8cbf163eb10e1a34f81369", .Okay}, + {.Shr_Signed, "-68f391abf261ebca8277feeb4b3c20b3c9d56028b7717642b35ff420c358da07f5b7e578c189797b658e44e55da668c7356d7ed6f4f70bdfe0c0f35b7ed2ab99833e0da8a61b42c1e1a9ee0cbd689aa3b0af5c26462dbb10b11721a175d77d3605cb5c0aa8c9647d3bc05359fed4a5791bf647cc53e1e065be9e9daff1b991a1d986da8a505d542ecdf5ac2cab58d99d49982c3b714d", "32", "-1a3ce46afc987af2a09dffbad2cf082cf275580a2ddc5d90acd7fd0830d63681fd6df95e30625e5ed963913957699a31cd5b5fb5bd3dc2f7f8303cd6dfb4aae660cf836a2986d0b0786a7b832f5a26a8ec2bd709918b6ec42c45c8685d75df4d8172d702aa32591f4ef014d67fb5295e46fd91f314f878196fa7a76bfc6e64687661b6a29417550bb37d6b0b2ad63668", .Okay}, + {.Shr_Signed, "-c1900b3ce119b6a3a19e9b440228b42e56d47838ce0c3630f4cfe123995fe69322b7abde4f7718b8d9c71ea7035d632a9389a4d538fc42aa9b8d0d353cff9a3d8bc6fcd76ba6d6538062aad7377b09fee6965cd0867357a1e4ae5b70250610a21acf426d8c4506ee7d842aa0a3825d08315ed87f4baad2c2e5fc2be0042918a5aae1f2d7a650d67603bbfd8dfbee16ab0ad0311034d5", "4b", "-183201679c2336d47433d36880451685cada8f0719c186c61e99fc24732bfcd26456f57bc9eee3171b38e3d4e06bac655271349aa71f88555371a1a6a79ff347b178df9aed74daca700c555ae6ef613fdcd2cb9a10ce6af43c95cb6e04a0c2144359e84db188a0ddcfb0855414704ba1062bdb0fe9755a585cbf857c00852314b55c3e5af4ca1acec0777fb1c0", .Okay}, + {.Shr_Signed, "-c7bb88869a05b0498d29fcdf65a920a44ede769a59124a6af9924eb4460523c4f58685cdd92ec343132e6441eaf8475b9aed98cf02675bba83fb62d4490b250be848f564df5d5851c5533bd1dc759a798911ca1c5730861c92299e72560c4be5004320b862db3591e647b225df45bc25a5b906ef7b10d8d14ed0837fffb159e0a15b824d2588aec4879b9601cecb1d654bdb078db017", "1c", "-c7bb88869a05b0498d29fcdf65a920a44ede769a59124a6af9924eb4460523c4f58685cdd92ec343132e6441eaf8475b9aed98cf02675bba83fb62d4490b250be848f564df5d5851c5533bd1dc759a798911ca1c5730861c92299e72560c4be5004320b862db3591e647b225df45bc25a5b906ef7b10d8d14ed0837fffb159e0a15b824d2588aec4879b9601cecb1d654bdb1", .Okay}, + {.Shr_Signed, "7d3ceebfd81b96a24bc95e03841c73aadece897800cbd9dc7aea1eb8c174cfa55b3d67416581e36a2a2f78dc10eff907bffd3e6db3b9e9bbdd64107f4641f6256f966a288c3dfdaa8866ee896fa412aa02688570f6a1603f82f13e0afb4e237d86ce3fb4842d5260adb699dce351376470b23b0348a2d110c137f033e02cc5cd86201fef362e3186d69035807a5ee342bc5e99c865c8", "39", "3e9e775fec0dcb5125e4af01c20e39d56f6744bc0065ecee3d750f5c60ba67d2ad9eb3a0b2c0f1b51517bc6e0877fc83dffe9f36d9dcf4ddeeb2083fa320fb12b7cb3514461efed544337744b7d20955013442b87b50b01fc1789f057da711bec3671fda4216a93056db4cee71a89bb238591d81a4516888609bf819f01662e6c3100ff79b1718c36b481ac03d2f71", .Okay}, + {.Shr_Signed, "-bd8323037c9dbc89753887b5083cdce660c18e96023ac3a6cfd82d2a8b948e474404c46adc1e77a95210a5aac03061669fadca9bad9da7bccd8b714f83e490cef7afbfe3b5a29cdcda680aadb2fcce36eab00e711925e5744f90b6bc55a893213128766390e250cd1bc991c7f4fc03f2465380519a2b6d6983cd99075de730c5f84ac8562ce697338cae3a3950efe33dab3119b61cd5", "e", "-2f60c8c0df276f225d4e21ed420f3739983063a5808eb0e9b3f60b4aa2e52391d101311ab7079dea5484296ab00c1859a7eb72a6eb6769ef3362dc53e0f92433bdebeff8ed68a737369a02ab6cbf338dbaac039c4649795d13e42daf156a24c84c4a1d98e438943346f26471fd3f00fc9194e014668adb5a60f36641d779cc317e12b2158b39a5cce32b8e8e543bf8cf6acc466d9", .Okay}, + {.Shr_Signed, "-7c134179ed6e1b175a544fc3659292815007328f874440b9f28130d963d68dc5a1f66fbc1c6eb9637460bd4b3ba214917ce02ef03801de1f59b98bef67c469e85bc09a433a05efe3ec1978ec37ced181e5f56fdfc821f3b3f696d4d68b155a9079fe08058e1e6ef0346f6b468a63e6ffd3e9189aee97ce5bf06d339832993cf248d4569029d8b5c24dc31fd3d534d563aa3cb7c0419", "36", "-1f04d05e7b5b86c5d69513f0d964a4a05401cca3e1d1102e7ca04c3658f5a371687d9bef071bae58dd182f52cee885245f380bbc0e007787d66e62fbd9f11a7a16f02690ce817bf8fb065e3b0df3b460797d5bf7f2087cecfda5b535a2c556a41e7f820163879bbc0d1bdad1a298f9bff4fa4626bba5f396fc1b4ce60ca64f3c923515a40a762d709370c7f4f54d36", .Okay}, + {.Shr_Signed, "19ce7a82806e920313bffa559f0e6995ed8ec03a7611f54883f3a4235a3af574048cb140ce00ed785330ba38e1d6fefc6d1dec598b6c5e3c4800ad4803e675c265bfd1e42906c0d6ef446695a035ca80ebc74d34796024f67c20a0489a1ffc5a4523a73e10b44cf6991a6539517d0a60ca088e5c8d47409d86958517f5befa9b8fc202e9b8ed049fcc789edbf5d48248317c2bd4cd0c", "30", "19ce7a82806e920313bffa559f0e6995ed8ec03a7611f54883f3a4235a3af574048cb140ce00ed785330ba38e1d6fefc6d1dec598b6c5e3c4800ad4803e675c265bfd1e42906c0d6ef446695a035ca80ebc74d34796024f67c20a0489a1ffc5a4523a73e10b44cf6991a6539517d0a60ca088e5c8d47409d86958517f5befa9b8fc202e9b8ed049fcc789edbf5d48248", .Okay}, + {.Shr_Signed, "-3a3b3747c20a42bac04733fdde8a2fbef6cb392901cf2650e949d35de64cc5a73f64901493087afd3631e2f18edbca9725d4ecea9bcebdfce890c1e7b27674244e9ab5f9bccd697b81e7a5714751ebb7e13a157851caac54f1f8786d8471f704b68d570e6347f7b99722cde34213faedc3f59640aa7f573cc9d02ba090820e7682e43d4240355e6ea0b1ecfa99948eabd31636da22d4", "57", "-74766e8f84148575808e67fbbd145f7ded967252039e4ca1d293a6bbcc998b4e7ec920292610f5fa6c63c5e31db7952e4ba9d9d5379d7bf9d12183cf64ece8489d356bf3799ad2f703cf4ae28ea3d76fc2742af0a39558a9e3f0f0db08e3ee096d1aae1cc68fef732e459bc68427f5db87eb2c8154feae7993a0574121041ced05c87a84806abcdd4163da", .Okay}, + {.Shr_Signed, "-96637deb9f2401ea9721a1af35b0b8d097dcce50de5fd381a239906a1c0773336dbce8b9a6b7e9aaef4836ee5821c9b1284a2377da72b6941be4fed006ede2c39ff246fd74d236cb6c6796d05e3c496c11250a600cd7a81d062f48f0c4c563ba196a9a0928defa9cfda52bcf1b393c2df863e7abcc61198aa9ed913bbb00efe550bd2fd398c92fbf08798d552b5a592bf044a7be5469", "31", "-4b31bef5cf9200f54b90d0d79ad85c684bee67286f2fe9c0d11cc8350e03b999b6de745cd35bf4d577a41b772c10e4d8942511bbed395b4a0df27f680376f161cff9237eba691b65b633cb682f1e24b608928530066bd40e8317a4786262b1dd0cb54d04946f7d4e7ed295e78d9c9e16fc31f3d5e6308cc554f6c89ddd8077f2a85e97e9cc6497df843cc6aa95ad2c96", .Okay}, + {.Shr_Signed, "-4f94703404330de09af71e87df774a125decc771707350b49322d0fd0546b15d4e6cd8a37ad9c98aa7d240264b2bbc2e12c9a4c568d182b12c7857092324ca7d6dda37053bcaedc0433aaa7517adbeb16c96f99db4ae14ef4eb0976d3125d303d4fca62b150e7933b2513a30101c0a83ee6cfa79944515bde707e796b2806bc1695af9d63934b153f15596cd35e41c895e261c461a1f", "4f", "-9f28e06808661bc135ee3d0fbeee9424bbd98ee2e0e6a1692645a1fa0a8d62ba9cd9b146f5b393154fa4804c9657785c2593498ad1a3056258f0ae12464994fadbb46e0a7795db80867554ea2f5b7d62d92df33b695c29de9d612eda624ba607a9f94c562a1cf26764a2746020381507dcd9f4f3288a2b7bce0fcf2d6500d782d2b5f3ac726962a7e2ab2d9b", .Okay}, + {.Shr_Signed, "8bcc89e231e2d00d5d88523904fd1c6349a7cc84e3285fb71095e6bb99a162eb998c336349e3bd5fbaa73e74ca1bf407fb856d70cc773e4e0eff5a1252698f82a70e8a755cdf469697ed2d064006fd57b1583f93f914914ad70ce2568d51f48c72d4e9c0dfdc05f0247e0ecb6fbbae55a5b21f406ab0868d66eb5195a8f5e9af095e9b2189b136c047e43b6e308b1da1223e18c73f52", "19", "45e644f118f16806aec4291c827e8e31a4d3e64271942fdb884af35dccd0b175ccc619b1a4f1deafdd539f3a650dfa03fdc2b6b8663b9f27077fad092934c7c15387453aae6fa34b4bf6968320037eabd8ac1fc9fc8a48a56b86712b46a8fa46396a74e06fee02f8123f0765b7ddd72ad2d90fa035584346b375a8cad47af4d784af4d90c4d89b6023f21db718458ed0911f0c", .Okay}, + {.Shr_Signed, "7ad5bad19778f02fa94c61d23c3bde577b11be4bd2f15d173b185ac4e9dfb2aed6d314b5b0766308e08a490c1c7d6ffc021d6fdd75b742d0229ec7c4e8a89d67a5c5056b8072059cfc937107d739e37b577cfc7c5c614d67a4025854bdc4b00cb37d5aa54ff622676222ba44715ab1d97942e4f8ffeaa2010ad224ae1a8a3b54125bca6f4eb918a174b3225bf0cb26bc955b378f3f1f", "26", "1eb56eb465de3c0bea5318748f0ef795dec46f92f4bc5745cec616b13a77ecabb5b4c52d6c1d98c238229243071f5bff00875bf75d6dd0b408a7b1f13a2a2759e971415ae01c81673f24dc41f5ce78ded5df3f1f17185359e90096152f712c032cdf56a953fd8899d888ae911c56ac765e50b93e3ffaa88042b4892b86a28ed50496f29bd3ae46285d2cc896fc32c9af255", .Okay}, + {.Shr_Signed, "-5c8511adcede1cf728cc1b52eef340414d7faa2f7ead4e8e20ec0c7370e064d9a77748b33f3b795d471dd0b7af6821488ce0ec960f2ce74401985237174c4caa5f44ab6624bf63bb1f54bae5d346f8aefedf6a77caf6be8cc6276cc1d9fb89d9075a364f9bc3e81c3229cf1742bc8fde1c44096ff69948870f3f1c29820ff42be430084ebf4d3b9df6f1c08e613f35a384dfc6261507", "31", "-2e4288d6e76f0e7b94660da97779a020a6bfd517bf56a74710760639b870326cd3bba4599f9dbcaea38ee85bd7b410a44670764b079673a200cc291b8ba626552fa255b3125fb1dd8faa5d72e9a37c577f6fb53be57b5f466313b660ecfdc4ec83ad1b27cde1f40e1914e78ba15e47ef0e2204b7fb4ca443879f8e14c107fa15f21804275fa69dcefb78e047309f9ad2", .Okay}, + {.Shr_Signed, "-62f0389b63d1849cb456a37147df81d95e9e5ba9bb654f1ef5d68ec67c98ebd18ee25c25948d8c843dcce1b38ca8458bce004772524e92dfb0458a02af08bdaefa258b4526ed60a4adf7569a82f6ed8b191ec47fddaa656056fc2f8876cce0fa39ea64260445c6c051ec12da4faa1d4e65dc354a78353ed178bd6e394a62944e751923d35892687c9713a30f7d74e7a5e76359674dc6", "3b", "-c5e07136c7a3093968ad46e28fbf03b2bd3cb75376ca9e3debad1d8cf931d7a31dc4b84b291b19087b99c36719508b179c008ee4a49d25bf608b14055e117b5df44b168a4ddac1495beead3505eddb16323d88ffbb54cac0adf85f10ed99c1f473d4c84c088b8d80a3d825b49f543a9ccbb86a94f06a7da2f17adc7294c5289cea3247a6b124d0f92e27461efae9d", .Okay}, + {.Shr_Signed, "5d9d22d2c41295ec9adce6f9ca70692d1551b007e654a411e6c79de005c960ae286011eb12c2e05c622a22665fadb77ad9b99620b1562056762cdad5db8ceca016a585f94c206a3c5c5d814ee08d53b7f3f0c08039f080eaededb77554fe727f510ec3db560da233b1b372ea0503a4ee0011add31f3955e31091c93fe53484f5b71e164c6b5687a2e2d8c58e5aee3752da6c6dcb198e", "3e", "176748b4b104a57b26b739be729c1a4b45546c01f995290479b1e7780172582b8a18047ac4b0b817188a889997eb6ddeb66e65882c5588159d8b36b576e33b2805a9617e53081a8f17176053b82354edfcfc30200e7c203abb7b6ddd553f9c9fd443b0f6d583688cec6cdcba8140e93b80046b74c7ce5578c424724ff94d213d6dc785931ad5a1e8b8b6316396bb8", .Okay}, + {.Shr_Signed, "-b01d67fdb2ab2f682f2e419a1e5ad344cc3c33c4ac66aa71548518fb8e5796e8b2f01e4ea20fa05e17c2f610b94cff5492c0bebd6b7d7e400fb193b5396e5bb6338b8ca9080b0900b6da7e54bb0ba70fece5db5d04f87a2a7345c5103b2528363c562a22ce26e5449b1b08cc6ae2d8c9d08131b554a193f01d5b8ed1ec330fb6cb72a6c30c9d63b1b017c582a9ae356b629b28f17afb", "4b", "-1603acffb65565ed05e5c83343cb5a6899878678958cd54e2a90a31f71caf2dd165e03c9d441f40bc2f85ec217299fea925817d7ad6fafc801f63276a72dcb76c67171952101612016db4fca976174e1fd9cbb6ba09f0f454e68b8a20764a506c78ac54459c4dca8936361198d5c5b193a102636aa94327e03ab71da3d8661f6d96e54d86193ac763602f8b056", .Okay}, + {.Shr_Signed, "2c3f06d5b9e657484b6dd315ebe47f7c3fe730dbfd78eb7b463a4f479a751323ed09cc70ca54822cdb10f89f245bec3ca99a1450931ffcac288193d2d975e1f77a5f900e34dd63b562505367739aebb1aef072a9fbd09b4284188a5f5763a8837418c19e0416302adde8df7db9c5730dbfa26488cafb2ac68e4b2c7b9628d0c378310d73cf3df752080d25e20405d72ccd65f4622793", "75", "161f836adcf32ba425b6e98af5f23fbe1ff3986dfebc75bda31d27a3cd3a8991f684e638652a41166d887c4f922df61e54cd0a28498ffe561440c9e96cbaf0fbbd2fc8071a6eb1dab12829b3b9cd75d8d7783954fde84da1420c452fabb1d441ba0c60cf020b18156ef46fbedce2b986dfd13244657d95634725963dcb146861bc1886b9e79efba", .Okay}, + {.Shr_Signed, "cb866c01ee20c84159107fa0fef87339bdfe1828b2f3f877a6b857fd03425bffba4e0431eda9d75504b32d1ebf9ca33c6b2f83b580a3dfd9f063caa513a09016d8ecef029dea318e5d7e79588600d76164b03afcebc72653646451fbf6fe5971142f10f18f5e103b02adbd1eb4b258f8ccb8d9eb0110819fa09d3eecc64f1c964e565ceb63e60beaa5d64c5dd7f1b2c1ab6a4bb1f94e", "25", "65c33600f7106420ac883fd07f7c399cdeff0c145979fc3bd35c2bfe81a12dffdd270218f6d4ebaa8259968f5fce519e3597c1dac051efecf831e55289d0480b6c7677814ef518c72ebf3cac43006bb0b2581d7e75e39329b23228fdfb7f2cb88a178878c7af081d8156de8f5a592c7c665c6cf5808840cfd04e9f7663278e4b272b2e75b1f305f552eb262eebf8d960d5b", .Okay}, + {.Shr_Signed, "-a62ee8776aa9f9a0b0ec6263c10670e45d23a6c92cfcd7bd8b149ed7952ba5598fb93c55387d6e85e62b7b61cdd0decaf95263a5e38db098090d5367d764896ee8b2eefb5d00ed1330619b47078b1cfb0aa829ceb9d6c3916d76dcf601c3a358a55a8a51fee1aa551412c6fc639af1dd323031ab433297206d04c2df9758e84983a9c9cd7e350c172a52340b92af687c371aa64a132f", "1f", "-14c5dd0eed553f34161d8c4c7820ce1c8ba474d9259f9af7b16293daf2a574ab31f7278aa70fadd0bcc56f6c39ba1bd95f2a4c74bc71b6130121aa6cfaec912ddd165ddf6ba01da2660c3368e0f1639f61550539d73ad8722daedb9ec038746b14ab514a3fdc354aa28258df8c735e3ba6460635686652e40da0985bf2eb1d0930753939afc6a182e54a46817255ed0f86e36", .Okay}, + {.Shr_Signed, "fd55e543fd72a755a7da4371ebf549865757557ae33d95167217912191f440c2a70e9fa749998e064e05d62d3ce423e161ec2a342c29da0be8d21d2cde6474a123dd8ad4a75fc3ebc761d4db8008cdf1cf4d6dde8965da1b00fddbafe3a351f6b10ce06aafd387d6d885570b71cbf8432fbac1160ca33f77d5856340c5ea8b70cc2b346361a8d07fad6177426234acb1a30850682d62", "78", "fd55e543fd72a755a7da4371ebf549865757557ae33d95167217912191f440c2a70e9fa749998e064e05d62d3ce423e161ec2a342c29da0be8d21d2cde6474a123dd8ad4a75fc3ebc761d4db8008cdf1cf4d6dde8965da1b00fddbafe3a351f6b10ce06aafd387d6d885570b71cbf8432fbac1160ca33f77d5856340c5ea8b70cc2b346361a8d0", .Okay}, + {.Shr_Signed, "-63453f828625a6f2c469be45552c6b0eda276f830ce1c6065d314b37f511427eed3f00cd99cb440e3758d07b63ffe061144116fe5db5a9bd71ac268b4f2872a28a8b5d341cf92783f9f733f64ec35c3a464e61cdf2884bda1f1b6432123aac122fbe8722656a0c0ad9e3ef893c87ff08f979127fb3a370e3449821eb0188e6eacab7c3dd69800d2d01884e10808c11784f03c5b5292b", "61", "-31a29fc14312d3796234df22aa9635876d13b7c18670e3032e98a59bfa88a13f769f8066cce5a2071bac683db1fff0308a208b7f2edad4deb8d61345a79439514545ae9a0e7c93c1fcfb99fb2761ae1d232730e6f94425ed0f8db219091d560917df439132b506056cf1f7c49e43ff847cbc893fd9d1b871a24c10f580c47375655be1eeb4c0069680c5", .Okay}, + {.Shr_Signed, "a334bec75f8a0beb237edd6bb24a8996865df27c96dce83394ecc5413b41b1287ef51cb018b879bc217bf823966efa0347f7e53adc9c571c121132e43e350faf54fdd2eccfb539f8683401af75e1f55eccb3797e603617c24a2b0f420f5ee98e43c4873c59cb2f74504ca1307bfcac61ae17d9360d91744f56a8561b378f94ffdcaeb92c8ac3eac7422cef4d65c43da028358f6ce9dd", "51", "519a5f63afc505f591bf6eb5d92544cb432ef93e4b6e7419ca7662a09da0d8943f7a8e580c5c3cde10bdfc11cb377d01a3fbf29d6e4e2b8e090899721f1a87d7aa7ee97667da9cfc341a00d7baf0faaf6659bcbf301b0be1251587a107af74c721e2439e2ce597ba282650983dfe5630d70bec9b06c8ba27ab542b0d9bc7ca7fee575c964561f563a11677a6", .Okay}, + {.Shr_Signed, "-2d5b0340393ba105e0c7e0d35934b389829fccdae739b710113782e2fc2c937924267ff77c995a65d3b1e9bcb7327295039788a40283d8254abf80b74708152fe7016d0db7550cf0bdee0e2138daa87db7004a4728d02f75ce279c833b5405e65ab3b7b3540865fda9335d3d5dddb7ac7c16395a71a70e1dfaee5d95314a46643c43b300e009a9ee00dc4055ccdfc4482fead2f0f8bb", "47", "-5ab606807277420bc18fc1a6b2696713053f99b5ce736e20226f05c5f85926f2484cffeef932b4cba763d3796e64e52a072f11480507b04a957f016e8e102a5fce02da1b6eaa19e17bdc1c4271b550fb6e00948e51a05eeb9c4f390676a80bccb5676f66a810cbfb5266ba7abbbb6f58f82c72b4e34e1c3bf5dcbb2a62948cc878876601c01353dc01b880ab9a", .Okay}, + {.Shr_Signed, "2088c23943c09c589018e6653d07a35da498c9ed6a3b113eabf2bcd43b4d5b498287cf622c74be7d2ff2f5d0143d641a5cda833ef87d3d4e6f2c887453606de890e6ec71172bd4d4a762a1acdcb8e4d6dd1331e63e89cbc56faac608a94242e73fb784dca1acdd36db0010f9e91670aa07059cb410cb8649c6558be48cec97e5a24c4031aba1c3bcab91bdf1df62153ae4167667714f", "2", "822308e50f02716240639994f41e8d76926327b5a8ec44faafcaf350ed356d260a1f3d88b1d2f9f4bfcbd74050f59069736a0cfbe1f4f539bcb221d14d81b7a2439bb1c45caf53529d8a86b372e3935b744cc798fa272f15beab1822a5090b9cfede137286b374db6c0043e7a459c2a81c1672d0432e192719562f9233b25f96893100c6ae870ef2ae46f7c77d8854eb9059d99dc53", .Okay}, + {.Shr_Signed, "-2f9653e6c8be5161f27bd22c04497aee37590938467bf7834a5d76d8abde6a141c2debd487dfb3b49331ef28586dd326cae4e40ee56ff59d114c53075fae826b14362c022092758b65b464b34ea68615a0a4a382a729980d936d31939c61a1170d3bcf121b1c44533288de5637d48714c1dd3ae896ae73106a2b396fecf5363ee148743ef5fde07b7dc5f748031e30d90ca8a83619be", "17", "-5f2ca7cd917ca2c3e4f7a4580892f5dc6eb212708cf7ef0694baedb157bcd428385bd7a90fbf67692663de50b0dba64d95c9c81dcadfeb3a2298a60ebf5d04d6286c58044124eb16cb68c9669d4d0c2b414947054e53301b26da632738c3422e1a779e24363888a66511bcac6fa90e2983ba75d12d5ce620d45672dfd9ea6c7dc290e87debfbc0f6fb8bee90063c61b2195151", .Okay}, + {.Shr_Signed, "-a6e83b32fea731c469a40b55ff83a9682973a009970b17e2fe54a0d577f77bae64cef35fa3969a8c51c87599b4d275fa34a7bb5baffa9fe67268cf2a8ece42cf2013c2358f475b8f2e6c7888613447e81c5bc3f983dcb1496b6583d19baf28c4a3e448f54806e19e30680f9fbe67b3cadf61de80dbd1977e90f018b445d5e53b4ffcdce8e33345758028493ac78e2fdb43b8ffe312c1", "4a", "-29ba0eccbfa9cc711a6902d57fe0ea5a0a5ce80265c2c5f8bf9528355dfddeeb9933bcd7e8e5a6a314721d666d349d7e8d29eed6ebfea7f99c9a33caa3b390b3c804f08d63d1d6e3cb9b1e22184d11fa0716f0fe60f72c525ad960f466ebca3128f9123d5201b8678c1a03e7ef99ecf2b7d877a036f465dfa43c062d1175794ed3ff373a38ccd15d600a124eb2", .Okay}, + {.Shr_Signed, "7427f5738719c6e82247536f90ded922c9fefebbef91c243e7da4d99f6b5d86c29529b92228d31aca5141db402e07bdb6fe9c3cb00e3e2543819c90b81cc770adc840ff0a13d0ee178ea524f17cc5f10467036746eade17b661e7a3ee56faa8e09b7fcd14807a6b80db76ac461a0587ee00bf9245af9bbc60e60879579c3606cf0a782d2080e76cf1743582963ef886aa252aa6f12b", "5c", "7427f5738719c6e82247536f90ded922c9fefebbef91c243e7da4d99f6b5d86c29529b92228d31aca5141db402e07bdb6fe9c3cb00e3e2543819c90b81cc770adc840ff0a13d0ee178ea524f17cc5f10467036746eade17b661e7a3ee56faa8e09b7fcd14807a6b80db76ac461a0587ee00bf9245af9bbc60e60879579c3606cf0a782d2080e76cf1743", .Okay}, + {.Shr_Signed, "fdc4e04d0632cb2e13ef103ed40988a0d9f8fb3ffed0a0f39b132dec9df17c8dbdd7f4e0e351dd85814a5fde3d6224f0165a9e6465ad13b7e0c0fc891bf920aa379837341c776866b2050edc2112c0696024868dc1d716b5605ba8d756fed956365c8b9271a483ca2070776b0f84eeef07c25107be9d5ce62ca09fc790c0c60b050dd50a9e6dee57afb6d9ef93a4ddcad75a2b26850e", "f", "1fb89c09a0c65965c27de207da8131141b3f1f67ffda141e736265bd93be2f91b7bafe9c1c6a3bb0b0294bfbc7ac449e02cb53cc8cb5a276fc181f91237f241546f306e6838eed0cd640a1db8422580d2c0490d1b83ae2d6ac0b751aeadfdb2ac6cb91724e349079440e0eed61f09ddde0f84a20f7d3ab9cc59413f8f21818c160a1baa153cdbdcaf5f6db3df2749bb95aeb4564d", .Okay}, + {.Shr_Signed, "-47000be6427a77ed931e6e319bcdd4702649e6bbbcb2dcc5c37eb5d6230c964adb7bf9c6669025affdc23bd039f902716572b1751700388e485322193862b166b09dad39b8d66b87a9e8dc6b496eb467c4cc5116ba0e054b6b5320c650fb4cb45a6b47706af6fb4de44e19b56080ea0d140a35d0f8ffd9fba0be19d195c3b37b78ff0a9c3976895ac9db6f734450f37173fc0f8c94aa", "49", "-238005f3213d3bf6c98f3718cde6ea381324f35dde596e62e1bf5aeb11864b256dbdfce3334812d7fee11de81cfc8138b2b958ba8b801c472429910c9c3158b3584ed69cdc6b35c3d4f46e35a4b75a33e266288b5d0702a5b5a99063287da65a2d35a3b8357b7da6f2270cdab04075068a051ae87c7fecfdd05f0ce8cae1d9bdbc7f854e1cbb44ad64edb7b9a3", .Okay}, + {.Shr_Signed, "d49ef912921047259d9289d1e7af1e5e51b598f63e9c37cba81db146a3e743fadf0c5526ab45ed8681db6b4248423eca6020146c9ed3a7790a2caee5c1c838ddf606c05e30f5d3e1688773c6f6997bddc4b06bfb3dbfe5fe162870e3426e2794f6d8d0ba6677d991dbf5bd563d310d5a7ba1b69fec27136a7f278cc86bea257e9754f31b89bf69171ee77043964dff3883612f29ddf7", "d", "6a4f7c8949082392cec944e8f3d78f2f28dacc7b1f4e1be5d40ed8a351f3a1fd6f862a9355a2f6c340edb5a124211f6530100a364f69d3bc85165772e0e41c6efb03602f187ae9f0b443b9e37b4cbdeee25835fd9edff2ff0b143871a13713ca7b6c685d333becc8edfadeab1e9886ad3dd0db4ff61389b53f93c66435f512bf4baa798dc4dfb48b8f73b821cb26ff9c41b09794e", .Okay}, + {.Shr_Signed, "-d25c7de25257ca0129aeb68af356aa2dd9af1bc6a9574be7ee3a372d4865848ab696f7d80537820c10120ec0d9a55a59f056503f62b63c6676d3ce91c8cef6efc546561e8f64aba16df6be710077e5313746ef103f3dcf1229d4fc0e38caea0bba0c5d13980341bb1b41c2a85d9dd5e34003513613678b1c1f50211d67d9fa7000011df48e20ca0299e4dc2e3a53466e340b5d2dadc6", "27", "-1a4b8fbc4a4af9402535d6d15e6ad545bb35e378d52ae97cfdc746e5a90cb09156d2defb00a6f041820241d81b34ab4b3e0aca07ec56c78cceda79d23919deddf8a8cac3d1ec95742dbed7ce200efca626e8dde207e7b9e2453a9f81c7195d4177418ba273006837636838550bb3babc68006a26c26cf16383ea0423acfb3f4e000023be91c41940533c9b85c74a68cdc69", .Okay}, + {.Shr_Signed, "f802728293ff04cbad9c134d89cd57854b9c963286228c08e534379b9b72c0d720e087a82dd2b92baa235be464666b7ede30b94089d97c410c715eafc2c942612b296ef42546ad68437cba853f257825ebdb84c385036585c2a17c664d89116e7008ba5b65615e0bc3117cab78c0b6d936bef8c3a64d387156ac00bc5902da969740f2e0632fb45a2110dd7c78694a801edcaae98645", "46", "3e009ca0a4ffc132eb6704d3627355e152e7258ca188a302394d0de6e6dcb035c83821ea0b74ae4aea88d6f919199adfb78c2e5022765f10431c57abf0b250984aca5bbd0951ab5a10df2ea14fc95e097af6e130e140d96170a85f199362445b9c022e96d9585782f0c45f2ade302db64dafbe30e9934e1c55ab002f1640b6a5a5d03cb818cbed168844375f1e1", .Okay}, + {.Shr_Signed, "-d6ffd41e83df1f92e4965ea569fa48902363f32190367f0475324e8e49eb309a5ac18b67bad583b39af8acba727657cb7efcfe64fe54d3f1a79b475a9e75a63ca67cb0cb00e2855deeae6b3ff746ebdf88e290935a1561f96b685b5b97e47cfd35570644d79b20e409f47797a2da92ae3d3500d1db472d22e078670e45b02457220e0ceae18b1aea9f37fe24a78c00d83bada8498a1", "30", "-d6ffd41e83df1f92e4965ea569fa48902363f32190367f0475324e8e49eb309a5ac18b67bad583b39af8acba727657cb7efcfe64fe54d3f1a79b475a9e75a63ca67cb0cb00e2855deeae6b3ff746ebdf88e290935a1561f96b685b5b97e47cfd35570644d79b20e409f47797a2da92ae3d3500d1db472d22e078670e45b02457220e0ceae18b1aea9f37fe24a78c00e", .Okay}, + {.Shr_Signed, "-98269f8a6baf693cf1b0ec28c95d05d2957cef91a70b478bb2a4eadf4bf2f15629665655dbdf60633a26703efb7c037d71a389c5480d7609af05b92b29eb5a1ec373ff35b5a98299fc4fb4115477d64c2426268146cba0ff36a6365f43f8bdb6ef5e487d850b96005c2a0f2ce470c918bc86058b742ebd7934383936bcf0a9c6d1b262885ebe09a11050edc5592a1b6fec8372f5d9ca", "e", "-2609a7e29aebda4f3c6c3b0a32574174a55f3be469c2d1e2eca93ab7d2fcbc558a59959576f7d818ce899c0fbedf00df5c68e27152035d826bc16e4aca7ad687b0dcffcd6d6a60a67f13ed04551df593090989a051b2e83fcda98d97d0fe2f6dbbd7921f6142e580170a83cb391c32462f218162dd0baf5e4d0e0e4daf3c2a71b46c98a217af826844143b71564a86dbfb20dcbd8", .Okay}, + {.Shr_Signed, "-370234a9f402c347f5cd59996865e829793ede57e579c758da7aa8bf339e3a4f0f2d764a6198c87101f1b13a91012e38da8728d8e2d6d2d2710d2b267a40aac03d7afdb3e58857209799a5338b94638828eb14630e758008e0358b9f8b8067a6d861f7cab5b24ac46f34682e84782c126efa666e8f45dcadddc4e6f5d2b984975d6b0f7af1d3f6a7bb111b2fbc2c8bfd20633c9375cd", "51", "-1b811a54fa0161a3fae6acccb432f414bc9f6f2bf2bce3ac6d3d545f99cf1d278796bb2530cc643880f8d89d4880971c6d43946c716b6969388695933d2055601ebd7ed9f2c42b904bccd299c5ca31c414758a31873ac004701ac5cfc5c033d36c30fbe55ad92562379a3417423c1609377d333747a2ee56eee2737ae95cc24baeb587bd78e9fb53dd888d98", .Okay}, + {.Shr_Signed, "70ab9fc6aeff2c1b1db785e21671b7139c4640ee852f6146b19877b2e0d2ee4a039257cdd239367eca305ee6e0513fb455533b0c46431e640a8ae668523ec657c4d59da206fb8f385d08624c9f20574bc1006745ba66444175b00e5390ea73c76254b258979315f542842162152d49df453b8cbc3f5c4c644f0caea9806a15b55269e29cd03586f7d9cc1c19a7867acc6e10b3ba9d05", "6a", "1c2ae7f1abbfcb06c76de178859c6dc4e711903ba14bd851ac661decb834bb9280e495f3748e4d9fb28c17b9b8144fed1554cec31190c79902a2b99a148fb195f135676881bee3ce1742189327c815d2f04019d16e9991105d6c0394e43a9cf1d8952c9625e4c57d50a10858854b5277d14ee32f0fd7131913c32baa601a856d549a78a7340d61bdf6", .Okay}, + {.Shr_Signed, "-c25600e5eb63ab6afeccac02cb20b6ae88d16f82c6f79f097d0e62a11398a8008496fc06ab996a1e31d63f26ddde2801c0e4c6dfcad97be1f5ba372c94c8e0ad8e03a78b3092ca03951947dc1e5cf688494990a3333fccf2670be1b79c47cee812ee9819c304f1f8c99c397edb95e26b7b6df277ac9f846f97af3dc77bdbdfc11821be522b288b27ca1869a943b6a3887a0a75d58cbd", "1a", "-309580397ad8eadabfb32b00b2c82daba2345be0b1bde7c25f4398a844e62a002125bf01aae65a878c758fc9b7778a00703931b7f2b65ef87d6e8dcb2532382b6380e9e2cc24b280e54651f707973da212526428cccff33c99c2f86de711f3ba04bba60670c13c7e32670e5fb6e5789adedb7c9deb27e11be5ebcf71def6f7f046086f948aca22c9f2861a6a50eda8e21e829e", .Okay}, + {.Shr_Signed, "b745da7093dd87920c2517b7fcf5e9fb42de8af692852b20541b162fb58c1a51a95f5ec2a28925bf1cdd1fbe1d522e95cc7e5bc67ffa7dbdf60125e784f539437454b4b6408e0444601eeaf7abca141dbef2010394b4a3118269cfd35225462fa241a177d6d93dfaed5354e071a583f7482484acc16d4b1b9e2144410da70bb82e178ecc5048cbfa8ae0428db875af3cbe6a62de8b4f", "2c", "b745da7093dd87920c2517b7fcf5e9fb42de8af692852b20541b162fb58c1a51a95f5ec2a28925bf1cdd1fbe1d522e95cc7e5bc67ffa7dbdf60125e784f539437454b4b6408e0444601eeaf7abca141dbef2010394b4a3118269cfd35225462fa241a177d6d93dfaed5354e071a583f7482484acc16d4b1b9e2144410da70bb82e178ecc5048cbfa8ae0428db875af3cb", .Okay}, + {.Shr_Signed, "a42697fab1765ddbdc88193df2cc125fd5a55c9c76b703b005096992b34f01d74d1bd1f34c4f2ea45871b2a0441f0bbedcca3f8c2579b2ef3ebe55bb5c0998e4e7fce2933ff397dcb352329405f04165ff3f6c6a8dcda1156619424ab743d267f496c2d24d37580fd3b1a1e9e5c5526a12c0ceee4aca3a14a7f3fa42336f7eb7b790c62cf089be1e165f8657192ac95e67a9ee9fafae", "21", "52134bfd58bb2eedee440c9ef966092fead2ae4e3b5b81d80284b4c959a780eba68de8f9a62797522c38d950220f85df6e651fc612bcd9779f5f2addae04cc7273fe71499ff9cbee59a9194a02f820b2ff9fb63546e6d08ab30ca1255ba1e933fa4b6169269bac07e9d8d0f4f2e2a9350960677725651d0a53f9fd2119b7bf5bdbc863167844df0f0b2fc32b8c9564af33d4", .Okay}, + {.Shr_Signed, "-6c01e505d2a169992ad36f4a411a9b4d6d2482b7286a25881ead211de9b4af7590a5233109ec054c9a3b9fd102949b21002139152530b0c413c732fda05943f66f9774eb8fe00ef09e4a599e4a5a042c2827aea01f17a5e822fd7cc9a99fa4bd96471d870689840da4f3a48c585ee3846b28533312738f760f8ce689678b5f04302480ad816495adb61a9e8cf8d11063638a16f3988a", "2b", "-d803ca0ba542d33255a6de948235369ada49056e50d44b103d5a423bd3695eeb214a466213d80a9934773fa2052936420042722a4a616188278e65fb40b287ecdf2ee9d71fc01de13c94b33c94b40858504f5d403e2f4bd045faf993533f497b2c8e3b0e0d13081b49e74918b0bdc708d650a66624e71eec1f19cd12cf16be086049015b02c92b5b6c353d19f1a220c6d", .Okay}, + {.Shr_Signed, "-bcfa3da7c3cdf446831afce4c2ffbb08f49e5f811cb297a035663fb2e3a4a1bb2dcce821ec46c63e3d188bd7ea0536b5418bd17b0281fcbaaadc85aaccc24a02a5db0938bd9ecf6d5bed5fa5f99e68966a0c070e296bc31fddba721ea8f53a3ad412979ae1d607632f5cc795cd929a84ffa5326f837171a893454da03c1161871a680d9081e1f65c9b3ef07791cb13d78c3a68007040", "12", "-2f3e8f69f0f37d11a0c6bf3930bfeec23d2797e0472ca5e80d598fecb8e9286ecb733a087b11b18f8f4622f5fa814dad5062f45ec0a07f2eaab7216ab3309280a976c24e2f67b3db56fb57e97e679a259a8301c38a5af0c7f76e9c87aa3d4e8eb504a5e6b87581d8cbd731e57364a6a13fe94c9be0dc5c6a24d153680f045861c69a036420787d9726cfbc1de472c4f5e30e9a01", .Okay}, + {.Shr_Signed, "-c669f94775512fd8180bb149cd4f6da11326178d2f90d2f68c9639884cff03f7bb9941406c6b1449b2323384de26c4d38882a8647750582f31a0f0d0dde91ce3e130d30a86c6db6426adcae339fba58ea4f2aa2fab8efcd95db1f45a9635d5a6f67977e25e52efdfe7d75c9a69a40b807457f0cae3341583e67b27e081ca20e919fa24e9512ef07aca2bad0f5c94017467b9251d60ec", "32", "-319a7e51dd544bf60602ec527353db6844c985e34be434bda3258e62133fc0fdeee650501b1ac5126c8c8ce13789b134e220aa191dd4160bcc683c34377a4738f84c34c2a1b1b6d909ab72b8ce7ee963a93caa8beae3bf36576c7d16a58d7569bd9e5df89794bbf7f9f5d7269a6902e01d15fc32b8cd0560f99ec9f82072883a467e893a544bbc1eb28aeb43d725005e", .Okay}, + {.Shr_Signed, "-68aaae78b53a04028542729d39a0b124493571801a4a5507c6a6cd30972b74cd1281cc218d798e44f75df1cba128264ddd4fe8fbc6d9f0db480c4816817e3b158260b8119a1e2f428cc4aeabbba14f0963018c4cd81e347a9631cbe02383ff27d70c20a001465d8ea2f01502151d547d95239b0644749ed90b9f1ceba4d9a9aa381edc38d60f634032776e5f847cc046349abacee761", "54", "-68aaae78b53a04028542729d39a0b124493571801a4a5507c6a6cd30972b74cd1281cc218d798e44f75df1cba128264ddd4fe8fbc6d9f0db480c4816817e3b158260b8119a1e2f428cc4aeabbba14f0963018c4cd81e347a9631cbe02383ff27d70c20a001465d8ea2f01502151d547d95239b0644749ed90b9f1ceba4d9a9aa381edc38d60f634032776e6", .Okay}, + {.Shr_Signed, "cda7b1b8ca7ecc467c619f9804c8c9505fc40d6c17c5730990a140c532ce2d9063bb26aa0af94414ed2009f61ec53471c09cfc793f597ab4fad8ce0b20248616422f32bdbbfee32ab45e23b9f9fc3e37dc4b35f488116178f1f7b17b371cfd526391d3547b572a649ce762efef3f6720e85fd7cc7de81fd4c76a0aa00e79f751cabbcc5a815dc4fe57fcd3bf4bb6d9fb365574ea0a3c", "46", "3369ec6e329fb3119f1867e60132325417f1035b05f15cc2642850314cb38b6418eec9aa82be51053b48027d87b14d1c70273f1e4fd65ead3eb63382c8092185908bccaf6effb8caad1788ee7e7f0f8df712cd7d2204585e3c7dec5ecdc73f5498e474d51ed5ca992739d8bbfbcfd9c83a17f5f31f7a07f531da82a8039e7dd472aef316a057713f95ff34efd2e", .Okay}, + {.Shr_Signed, "-f3531a876fd149b135a86ef900eb4866b3da4415b5578217f0fa8a8839c158f64909e0b95e4834ff15df9a4727abadde3b412f7e811e30ce925b17f0dee45c7457cf88de54d3434828c53383e7519556b2391f77b78de6aaf3e68dc9a82a6fafcfede454f1e1f5ba598fb505b95307809a82a272fcff13c23d3ef01d86f362e3d62237414954a93feebd56f0e44c8d219954d2c2cdf1", "74", "-f3531a876fd149b135a86ef900eb4866b3da4415b5578217f0fa8a8839c158f64909e0b95e4834ff15df9a4727abadde3b412f7e811e30ce925b17f0dee45c7457cf88de54d3434828c53383e7519556b2391f77b78de6aaf3e68dc9a82a6fafcfede454f1e1f5ba598fb505b95307809a82a272fcff13c23d3ef01d86f362e3d62237414954a94", .Okay}, + {.Shr_Signed, "414e2dc0c51bf1d74ad1e9f649f6719e7eb93d081d1ed2aeef2d53106e356b2584a03f754bdb279a6ed7e329892416d6e23c5ef89f2959d1a5bec92c32258abe0635ffd54c5409809ed365092bd68a0ef3df47afe1d6be9a1eb60d4ed2fa68a734dce400aaa8f11e1c5bd1fdc7c1f20fe6467551abe2584672d9c2b4963c5b99dc4517823ea30824b1af390fc8982f4b657bf8663610", "5b", "829c5b818a37e3ae95a3d3ec93ece33cfd727a103a3da55dde5aa620dc6ad64b09407eea97b64f34ddafc65312482dadc478bdf13e52b3a34b7d9258644b157c0c6bffaa98a813013da6ca1257ad141de7be8f5fc3ad7d343d6c1a9da5f4d14e69b9c8015551e23c38b7a3fb8f83e41fcc8ceaa357c4b08ce5b385692c78b733b88a2f047d461049635e7", .Okay}, + {.Shr_Signed, "e7f6d562fb5813cc4565bae2ed6bcec2e4decd3b4405e455d8661fe87fefda02986306b96fccafbc5d79b11be57d0a72db4bea90d9672dcdfb744b8cc8f1484bb182901fb2cf3821baceec08da9da877645b0de15485c23bd3101fea9691cee455e1bdfba7f384a8723e4896763677931e6b47fd7a9dcb636e7eae6af6d77a542b70c6f4b12f98c8263a71681e566e4fde13d27f8a04", "76", "39fdb558bed604f311596eb8bb5af3b0b937b34ed1017915761987fa1ffbf680a618c1ae5bf32bef175e6c46f95f429cb6d2faa43659cb737edd12e3323c5212ec60a407ecb3ce086eb3bb0236a76a1dd916c3785521708ef4c407faa5a473b915786f7ee9fce12a1c8f92259d8d9de4c79ad1ff5ea772d8db9fab9abdb5de950adc31bd2c4be63", .Okay}, + {.Shr_Signed, "aa678846cc6636bce5cc5a1ef1730ab18b0773d18c63ad7f0d929955e869f78cb8520a37dd0c1fef9d35dfdc2e697d28ab8b3b6c57577cd93f420fb0f33385f09f3834234e74b9974797c3b57514c9c2e63ef7757b5fb537fbec4831c4b9f49d720c08a84312d412d161271bbb66d044713a31cbc8a666693c41170fe88baf00f6155b9f52b8402132d03fc3c44b386ff03f50b17df4", "44", "aa678846cc6636bce5cc5a1ef1730ab18b0773d18c63ad7f0d929955e869f78cb8520a37dd0c1fef9d35dfdc2e697d28ab8b3b6c57577cd93f420fb0f33385f09f3834234e74b9974797c3b57514c9c2e63ef7757b5fb537fbec4831c4b9f49d720c08a84312d412d161271bbb66d044713a31cbc8a666693c41170fe88baf00f6155b9f52b8402132d03fc3c44", .Okay}, + {.Shr_Signed, "-2cb0f36df80d7a4acd26236cf3febc23048823f751ce2f2d26773aad069800b824fcfd54034c7d74c4c3c0b3d1855c73a09186519855ac6e219c2891751b0b9cd828cb00738406b63c80325580521dfc4b1fe9d09148f2227c439fecf5e8a52b5c7ec99e8b6b15b7b3ef99778adce7f78ca09f6762ccfd824b168b7a68825ce4a398fac177d8afadd280dbf39697be83d4b5564aa7f9", "65", "-165879b6fc06bd25669311b679ff5e11824411fba8e71796933b9d56834c005c127e7eaa01a63eba6261e059e8c2ae39d048c328cc2ad63710ce1448ba8d85ce6c14658039c2035b1e40192ac0290efe258ff4e848a479113e21cff67af45295ae3f64cf45b58adbd9f7ccbbc56e73fbc6504fb3b1667ec1258b45bd34412e7251cc7d60bbec57d6e95", .Okay}, + {.Shr_Signed, "-316071c4265f0b7f944467f01fb027cc8cddfa08f717ca8c1d174abc428aa2c1f2f93f6e2925d3c3c4fdd288c9900aa51a2f9f1b788100ca6edfedd6f11088ea0172a1bf5481a2bd8f08774e4a8afb77c5bd94a9ae5cbcb940d93c74121a781aaa01f1635f2efa39d72e0f4a3a1be29de6ab693ce986444d5df257f847dd32ad5792aac4d2be351e8b181cb0297552502704cd89018c", "1c", "-316071c4265f0b7f944467f01fb027cc8cddfa08f717ca8c1d174abc428aa2c1f2f93f6e2925d3c3c4fdd288c9900aa51a2f9f1b788100ca6edfedd6f11088ea0172a1bf5481a2bd8f08774e4a8afb77c5bd94a9ae5cbcb940d93c74121a781aaa01f1635f2efa39d72e0f4a3a1be29de6ab693ce986444d5df257f847dd32ad5792aac4d2be351e8b181cb0297552502704d", .Okay}, + {.Shr_Signed, "-2933bb1327eaa9a125c5a7d286c1c2c7bbb94feb407986bc84cd806380474471b18d84c02f582875b59ac35804e6825e231b2548d8bb7dd400b47bc58b1542aca68e620b1ca2fd35a67bc216e36c8db77c934fc1655db710706d2543f68c87d68f055492454e01d2dc7f616f8c4fcd5166d33f05a44905b0709bcf552c0a8c46fb4227a075899b06d42547328a3e3951dd0549ca01b6", "41", "-1499dd8993f554d092e2d3e94360e163dddca7f5a03cc35e4266c031c023a238d8c6c26017ac143adacd61ac0273412f118d92a46c5dbeea005a3de2c58aa156534731058e517e9ad33de10b71b646dbbe49a7e0b2aedb88383692a1fb4643eb4782aa4922a700e96e3fb0b7c627e6a8b3699f82d22482d8384de7aa960546237da113d03ac4cd836a12a3994520", .Okay}, + {.Shr_Signed, "6fbb5340e6c7dfc9f9a729a4dceba2c6da3766124784f084fb289fe434ae575f3dad6b8eb579962ee650eda7ec2249a06d19724826c66833801edba3993c677eb884629be57c028943f1b6b33cfcbda5669ca5bfbbb550856810161fb0bc64218c0259c2239220c0e94eb78663196882f137753e6b923374c7b76ec7126bce3b83af7e8f882c38f9cfa79558022afb25e673951e766", "6", "1beed4d039b1f7f27e69ca69373ae8b1b68dd98491e13c213eca27f90d2b95d7cf6b5ae3ad5e658bb9943b69fb0892681b465c9209b19a0ce007b6e8e64f19dfae2118a6f95f00a250fc6daccf3f2f6959a7296feeed54215a040587ec2f19086300967088e488303a53ade198c65a20bc4ddd4f9ae48cdd31eddbb1c49af38ee0ebdfa3e20b0e3e73e9e556008abec9799ce5479d", .Okay}, + {.Shr_Signed, "-d2017040429cf035554c0e9a1feee6aa35835acd58d7c358f2e9e255dd8c8d23b5b2115be6e9ee10c6b8614e59b3a31a352287b5b5f86cd12db30976b29c71b5d5bb0c77e550463b725cda0bdca95447c735f2468ab6c7d28a00166b567a2389558ed49a34265f91046078da49d32049c720a7905c10d9ed6d8cd33f8c5464067a0147e386db1a0175850ce97fb0d26ec91608d375ef", "35", "-6900b820214e781aaaa6074d0ff773551ac1ad66ac6be1ac7974f12aeec64691dad908adf374f708635c30a72cd9d18d1a9143dadafc366896d984bb594e38daeadd863bf2a8231db92e6d05ee54aa23e39af923455b63e945000b35ab3d11c4aac76a4d1a132fc882303c6d24e99024e39053c82e086cf6b6c6699fc62a32033d00a3f1c36d8d00bac28674bfd8694", .Okay}, + {.Shr_Signed, "cf2fb403ad7e5b83050a95089c56a53c30c76d89a8d86877a6de36c4424e0b2719c217bd7bc6ee34d669c40bd89efa5e89156b6a6d5a09873c7148f779ea2e5182d3601b8f0d170545c69b302e70b9d83e33c9b891f1293112c4b4ba9c5eb91f11e526640eb81979f96f3bcae6240de2e4dfd1a2cf0059f011c0e93880603d219a022c31ac1a534d023bd797c374c6214cd42240b8b2", "6e", "33cbed00eb5f96e0c142a5422715a94f0c31db626a361a1de9b78db1109382c9c67085ef5ef1bb8d359a7102f627be97a2455ada9b568261cf1c523dde7a8b9460b4d806e3c345c15171a6cc0b9c2e760f8cf26e247c4a4c44b12d2ea717ae47c479499903ae065e7e5bcef2b9890378b937f468b3c0167c04703a4e20180f4866808b0c6b0694d34", .Okay}, + {.Shr_Signed, "fac753055c8bb5b5bca9354bfdfe0eebfb663c3e16517c4f87549808fbc38919706983d3ea8092e02c8ec033da6d4c6e7b204e9eb895e2a2fa5e42a71a788a5247dde224d8db374012511d4bc89898e2776af8ab87867bde1eda81b1ed87a004fff6448d94d607eb5ce974b913ca6f3d6cba4ce4524c489d38fb67f5be1774c2307e03c6154ff1bc98622cd525f3ef9171b71238a844", "18", "fac753055c8bb5b5bca9354bfdfe0eebfb663c3e16517c4f87549808fbc38919706983d3ea8092e02c8ec033da6d4c6e7b204e9eb895e2a2fa5e42a71a788a5247dde224d8db374012511d4bc89898e2776af8ab87867bde1eda81b1ed87a004fff6448d94d607eb5ce974b913ca6f3d6cba4ce4524c489d38fb67f5be1774c2307e03c6154ff1bc98622cd525f3ef9171b712", .Okay}, + {.Shr_Signed, "-a775cec8722e98d485ca1e00c4c1dfcc88caccfa6771c258b68fd6a605052ba58c30125f02bb314bd7063f1e5d4255b39717b1ac617047d91dbe89195a6350fbee3d609a3e1b859b27ffc11e75990010b61f949805bf971a7faadce58a9bae44ba06c718d80b1d23669401e3831848ba71b7bd18fff847a2cbed8a4d84a82d81c19b560d4eeb0e94366a86adacc2fc4b315c0d989079", "16", "-29dd73b21c8ba63521728780313077f32232b33e99dc70962da3f5a981414ae9630c0497c0aecc52f5c18fc79750956ce5c5ec6b185c11f6476fa2465698d43efb8f58268f86e166c9fff0479d6640042d87e526016fe5c69feab73962a6eb912e81b1c63602c748d9a50078e0c6122e9c6def463ffe11e8b2fb6293612a0b607066d58353bac3a50d9aa1ab6b30bf12cc57037", .Okay}, + {.Shr_Signed, "78cbde17f7ff3c3ce3feeeb59ad31062110e6c80c8383af4665abdcf740d00299f967209bf562a10bf08e69d96ac5098dd281d962f4a6ad9b5e25fc419fb446003cfde635fbb04c0bd6380fe8f6a425343e5accce643c42d22f852dfbf59f3ee78701771d5ce65ed6e37eb00b0a8fa06983906bf2a0ca93b8c69ec47061fd88f49f55870a22730fa0ad0bcaaadb0c15674f4e8df1a0f", "8", "78cbde17f7ff3c3ce3feeeb59ad31062110e6c80c8383af4665abdcf740d00299f967209bf562a10bf08e69d96ac5098dd281d962f4a6ad9b5e25fc419fb446003cfde635fbb04c0bd6380fe8f6a425343e5accce643c42d22f852dfbf59f3ee78701771d5ce65ed6e37eb00b0a8fa06983906bf2a0ca93b8c69ec47061fd88f49f55870a22730fa0ad0bcaaadb0c15674f4e8df1a", .Okay}, + {.Shr_Signed, "b9756084f091a4912f180b27f30dc2f16d7a0e9993943d80bb3b9eacd7a1d9d97fbd27636924773e76bd79fd551ea36c6f6f34e8d557a2b6c975e7a3ac4d1770e304f4019b86f367f6c07ade03d0f070dfad222a1d5071321e375b6581a8d9d1c46a1f6a1d76dc1311e9f377b436b9829349bbbbb0ec9c1b0c92290fe0987ddd276727ecf3921e1ba326c7b56bb8aba117ad6ebf98e3", "74", "b9756084f091a4912f180b27f30dc2f16d7a0e9993943d80bb3b9eacd7a1d9d97fbd27636924773e76bd79fd551ea36c6f6f34e8d557a2b6c975e7a3ac4d1770e304f4019b86f367f6c07ade03d0f070dfad222a1d5071321e375b6581a8d9d1c46a1f6a1d76dc1311e9f377b436b9829349bbbbb0ec9c1b0c92290fe0987ddd276727ecf3921e1", .Okay}, + {.Shr_Signed, "-48e9dabdb8999855f4b0466ecba0e463aa6a3c89c5410295e7a928b02c8d10f0b05939d9d1fe3913c91439efc5e90ff6289ab36f6466086ac84aa4b865ef086ee1d7000b1c66f9e98770d69a92271174d237b52fc20a47cb9b7168d484652edaea9129f814a8cfd2237fa10a7da3a5a91bd9a3e691807d523c04f16c100e3bdf11fee18316786b1ecc621be9e822905f65e99642b816", "5f", "-91d3b57b713330abe9608cdd9741c8c754d479138a82052bcf525160591a21e160b273b3a3fc7227922873df8bd21fec513566dec8cc10d590954970cbde10ddc3ae001638cdf3d30ee1ad35244e22e9a46f6a5f84148f9736e2d1a908ca5db5d52253f029519fa446ff4214fb474b5237b347cd2300faa47809e2d8201c77be23fdc3062cf0d63d98c5", .Okay}, + {.Shr_Signed, "-93b5031fbaadec6c237d0857df2a597a1cd05e359600cefa64624eae0a356012c86123d7362627191e647b920987fd0477c50aa1ebd833830ebaeedbb0f880860f326389bae35d04323be5c1e7af27bdaa9439e31363209d5837ca0fdcc182529c33f973cb97e5a16bbd02e37d08a24d08c84917747dea9c6ea7409f143cf7bc71fb7739cfc4f4bfc0b04de530bd9cd643b4aa3bcb78", "62", "-24ed40c7eeab7b1b08df4215f7ca965e8734178d658033be991893ab828d5804b21848f5cd8989c647991ee48261ff411df142a87af60ce0c3aebbb6ec3e202183cc98e26eb8d7410c8ef97079ebc9ef6aa50e78c4d8c827560df283f7306094a70cfe5cf2e5f9685aef40b8df42289342321245dd1f7aa71ba9d027c50f3def1c7eddce73f13d2ff02d", .Okay}, + {.Shr_Signed, "4d0c9b40710b78b645a22fe6fb0cec728d54fc1e2f3eecdad6a806e970f5ad824540463b0a1432be29917217bd61a4f963ec52203a7c5b9ebc54af20c21b719aa2fd7c88d0dc115a455af4e8bc8b2f7b5be8f947dc9e9dc2958ecd151f15056a0a74011216e10c7ffc463f43d90b361670e622cd530b0a763272911332658bca7b34c2dbb843d8a23c056ea8b5ae5e0de1769ede299a", "69", "26864da03885bc5b22d117f37d86763946aa7e0f179f766d6b540374b87ad6c122a0231d850a195f14c8b90bdeb0d27cb1f629101d3e2dcf5e2a5790610db8cd517ebe44686e08ad22ad7a745e4597bdadf47ca3ee4f4ee14ac7668a8f8a82b5053a00890b70863ffe231fa1ec859b0b38731166a985853b193948899932c5e53d9a616ddc21ec511e", .Okay}, + {.Shr_Signed, "-1736641c0e8a4f2bce43f2a5f02bdbd3564eb89197d41622b68bcd35f956f72ef900e7e4f6c6a30abf896db6bf3b79592f07c7cbb8a02e842640f7b79e54b568ae1c0c1ef7aa28b9dfdfbe68f44d707634e2955e28d2e22fb8075b364d7faba19b647da6254890aaa6edb35f84ad75aff9bd7232e24131052dd6809110c720b9822f2fe0889d4d94a3a6bb89a98540c405b337d9f390", "53", "-2e6cc8381d149e579c87e54be057b7a6ac9d71232fa82c456d179a6bf2adee5df201cfc9ed8d46157f12db6d7e76f2b25e0f8f9771405d084c81ef6f3ca96ad15c38183def545173bfbf7cd1e89ae0ec69c52abc51a5c45f700eb66c9aff574336c8fb4c4a9121554ddb66bf095aeb5ff37ae465c482620a5bad0122218e4173045e5fc1113a9b29474d772", .Okay}, + {.Shr_Signed, "84d3f9e39fe712e14cbb181069d33e618e638cd04d14dc2fb0cc6a340589eb0b0c3250576a3ee804f9e70b759c356ca76ed24fea1ade51d36f7bbcbf8d78eac553bcd3f63e9eb5220467c1f02b4f2c66078dc5607f90f6e0cf05dbb53180dcfaf69d2dd851be276f1f409cc23ed4d21a79c121a523e4abbd3f66db20a46a71313d11fbff1b5f0351a694b18b1909b231d9b613ba374f", "69", "4269fcf1cff38970a65d8c0834e99f30c731c668268a6e17d866351a02c4f5858619282bb51f74027cf385bace1ab653b76927f50d6f28e9b7bdde5fc6bc7562a9de69fb1f4f5a910233e0f815a7963303c6e2b03fc87b706782edda98c06e7d7b4e96ec28df13b78fa04e611f6a690d3ce090d291f255de9fb36d90523538989e88fdff8daf81a8d3", .Okay}, + {.Shr_Signed, "-98d83ebab1a7eac1621832d72fe10c4f79dad61ed44e433b1c0f3e95afb6ec9ba6455bbcec88b99f272a8e90c06226169974fff1418e487de29509970aae231d1522eddc991767925fedbc190f08fcf34985c8a2fb3b7249717e55fb44856bd07349a4d64afe544d6db118693d5b44e3b4b7ccfa6ea521299d28470122075f4c72fe7ad7e0f6ccaeb3f02a8f73b4195ad19b84c448a2", "56", "-26360faeac69fab058860cb5cbf84313de76b587b51390cec703cfa56bedbb26e99156ef3b222e67c9caa3a430188985a65d3ffc5063921f78a54265c2ab88c74548bb772645d9e497fb6f0643c23f3cd2617228becedc925c5f957ed1215af41cd2693592bf95135b6c461a4f56d138ed2df33e9ba9484a674a11c04881d7d31cbf9eb5f83db32bacfc0ab", .Okay}, + {.Shr_Signed, "180355dc11731f369f1763408bfe8fb38a7869a65c9e16a7d22d9f85528c1fff384051653a96ac495ad299de88c3d1a1602806abcd1b1b8f584bc922eb3b4be31557854e0ed41091628335233d3802120386542b8173eb352da2b4cd5669ad040a8b2e9da95f89e1be2e83b61b2f761365d88e18eb084cab57d114e08814951e008d2e44df702c0c997498bf822f0d168e784b4bc2c7", "2c", "180355dc11731f369f1763408bfe8fb38a7869a65c9e16a7d22d9f85528c1fff384051653a96ac495ad299de88c3d1a1602806abcd1b1b8f584bc922eb3b4be31557854e0ed41091628335233d3802120386542b8173eb352da2b4cd5669ad040a8b2e9da95f89e1be2e83b61b2f761365d88e18eb084cab57d114e08814951e008d2e44df702c0c997498bf822f0d168", .Okay}, + {.Shr_Signed, "-511d1bee742c454a23464b16e763463f49da5501aed6000e14c07b682c3dc743d057647f6e5f7afa405697cee483378c417b967883074592dfe06411b50ef2b6f56665bb01d291e229537de64466ce74a59d5e931d0456f2c0d72a5e69d236a66cdb784ff4d9dd5d0a448100c13f198a3c707b7c32b3ea7ac3a9bc14ccb3a0a789b882f44edea8c01ac2b7aea124b965e82d6170691d", "24", "-511d1bee742c454a23464b16e763463f49da5501aed6000e14c07b682c3dc743d057647f6e5f7afa405697cee483378c417b967883074592dfe06411b50ef2b6f56665bb01d291e229537de64466ce74a59d5e931d0456f2c0d72a5e69d236a66cdb784ff4d9dd5d0a448100c13f198a3c707b7c32b3ea7ac3a9bc14ccb3a0a789b882f44edea8c01ac2b7aea124b965e83", .Okay}, + {.Shr_Signed, "-5f4399b93b47d51a16e2206f98167534ed6c0f33eb2553940c2cb9940f85dc1bf8f39090a3f90b6bbd7cd3a45cf99136db31e5aef2d5667d8af7bec38e3b69c579394e41dfddb3b14035ace29906c2497cb1b0a43956f84df9bdbb46ccce81025d5d4073e450da7a7842a6ab3cff688fd5c06e3ac184c524cd5e503cd39ebb37f841ebf344eba03bed2031434fe318927ff53577b6eb", "4f", "-be873372768faa342dc440df302cea69dad81e67d64aa728185973281f0bb837f1e7212147f216d77af9a748b9f3226db663cb5de5aaccfb15ef7d871c76d38af2729c83bfbb6762806b59c5320d8492f963614872adf09bf37b768d999d0204baba80e7c8a1b4f4f0854d5679fed11fab80dc7583098a499abca079a73d766ff083d7e689d74077da406287", .Okay}, + {.Shr_Signed, "-b96b0f23872efd8354551e4e541dc4fbdf21d4e6be02797c4ac9717116671a6ae02ede47a7a1c6d620ce8a206bc19e9ac5c68381e1b5116f1e677581965d0f4a39f27ad3ac5afaaa476be6185f5d4b0a27f2ea04f65ec5677fc67b1a5b23c94580a4e557a916f65a4153b941413a62b862c28e8e6a91bc311c20a0e6f7a8345dec2b17b6769cd3ebf08221426132d9026df54b541a51", "e", "-2e5ac3c8e1cbbf60d51547939507713ef7c87539af809e5f12b25c5c4599c69ab80bb791e9e871b58833a2881af067a6b171a0e0786d445bc799dd60659743d28e7c9eb4eb16beaa91daf98617d752c289fcba813d97b159dff19ec696c8f25160293955ea45bd969054ee50504e98ae18b0a3a39aa46f0c47082839bdea0d177b0ac5ed9da734fafc208850984cb6409b7d52d51", .Okay}, + {.Shr_Signed, "-568c5f3911236176cde7877cf392f0dfdecd7774dd0e1a73e1c9d3038aee133b8d4d4410e3bdbda4d8c88b92cb9c6d20b2b4caeed0e367b9dd352e88bd5046ff4cd903d9f73b1e2493c930526cfeb740c388a65478163b1fbd8aadd0c729c668e3a3428e61fedcb5724066e85630b22b1d532c4b0f086965082ec684601479ad7268b93d07eb9bc15c360c53f1796970e7c2b345a2e8", "6f", "-ad18be722246c2ed9bcf0ef9e725e1bfbd9aeee9ba1c34e7c393a60715dc26771a9a8821c77b7b49b19117259738da41656995dda1c6cf73ba6a5d117aa08dfe99b207b3ee763c49279260a4d9fd6e8187114ca8f02c763f7b155ba18e538cd1c746851cc3fdb96ae480cdd0ac6164563aa658961e10d2ca105d8d08c028f35ae4d1727a0fd73783", .Okay}, + {.Shr_Signed, "9727e1f0c2b78c24b8a5743f6df572f96edd6eba64be410b17db7d60bf124862f16c8ade1d2134ad5f09a1d429fd55c630ead57ebd54a67d853389da1a5ff5dcd15d11dc27c2e41b484454281e710a248c3c685a02162690408e2039ec8e2da8b01257508571ee0236c5820d71c8699032439a0924fdabff98763343661809a0434d244aff77b34e0f9cf2aac2f420e22fdd027fc87d", "45", "4b93f0f8615bc6125c52ba1fb6fab97cb76eb75d325f20858bedbeb05f89243178b6456f0e909a56af84d0ea14feaae318756abf5eaa533ec299c4ed0d2ffaee68ae88ee13e1720da4222a140f388512461e342d010b13482047101cf64716d458092ba842b8f7011b62c106b8e434c81921cd04927ed5ffcc3b19a1b30c04d021a692257fbbd9a707ce7955617", .Okay}, + {.Shr_Signed, "-d3f9b1410438326fe7cc44c557ff85249812334a4dea398b18d69d707558bfe91d64f4934a2dce1a8be0004366ea7730ce76ea692792710a84f4c0a4310f4efef76cb18032adfd5b365153079517e51065358c0bae886224021854fe898afef90fa88b027304bdb57a60e87bafeddaf8145ee87a92982bdc551867eefffb9976498b728d0a301ff1f15969990ac15ebcfcd7b02d30a6", "52", "-34fe6c50410e0c9bf9f3113155ffe14926048cd2937a8e62c635a75c1d562ffa47593d24d28b7386a2f80010d9ba9dcc339dba9a49e49c42a13d30290c43d3bfbddb2c600cab7f56cd9454c1e545f944194d6302eba218890086153fa262bfbe43ea22c09cc12f6d5e983a1eebfb76be0517ba1ea4a60af7154619fbbffee65d9262dca3428c07fc7c565a67", .Okay}, + {.Shr_Signed, "d50ea8d7da349413a66e0a971510f6af57be9bb29f6c2f1ec6fe89e8cf1a57aa291bfda08f19fb078f1b7c72fdd438e4faaedad2f05943b441d96c93b7c4bd1d15cbe2e7ecec6a318bd88c65bb6d9d98f99f7204f00a90ba02d2525a4e886b55afa0a55c2acb9f2d21bdde631d26f23c03d7376ad6fab8eab1ac1bdc74be3252b8d910dbc41b87e94c3ab698ff575ad58e5f6cba99e3", "62", "3543aa35f68d2504e99b82a5c5443dabd5efa6eca7db0bc7b1bfa27a33c695ea8a46ff6823c67ec1e3c6df1cbf750e393eabb6b4bc1650ed10765b24edf12f474572f8b9fb3b1a8c62f623196edb67663e67dc813c02a42e80b4949693a21ad56be829570ab2e7cb486f7798c749bc8f00f5cddab5beae3aac6b06f71d2f8c94ae364436f106e1fa530e", .Okay}, + {.Shr_Signed, "-b06ad71a6bbc06ac0ec827d54c6ff4aabd115349771b62b482d7c3f7356c09bf7fb5eee2ca90ced6122447d92700de663a0d50be2c509826acc8887b712e28cfd4e29ae7e9d08b724163793f9bd1634ce960fb03b9a5cb4583194cd0b6fcea70e8a60042d4477983c210f8f155e0227df9477631e179355ad9faf23cd9b5aec75cf383f078700296ca7b368feb19f198db00ff663d20", "61", "-58356b8d35de0356076413eaa637fa555e88a9a4bb8db15a416be1fb9ab604dfbfdaf7716548676b091223ec93806f331d06a85f16284c135664443db8971467ea714d73f4e845b920b1bc9fcde8b1a674b07d81dcd2e5a2c18ca6685b7e7538745300216a23bcc1e1087c78aaf0113efca3bb18f0bc9aad6cfd791e6cdad763ae79c1f83c38014b653e", .Okay}, + {.Shr_Signed, "3d4bf881aa6b28dd1046a097871362733e4d2431025cf482be1c25baa933869142bbd193b8d2859ee604d95e63eede081881c426d635896615170e580954e1de98061d12ae8fdda5160643b8d0a7d1839cabd23ac2a408f132601e60318550f79f78f06c1253ea16f8c22b227c54351116f329674050449a37196fc47f35dbe8d0574a4313e37dac5cb92502d0e351cf6e2d08425e5c", "15", "1ea5fc40d535946e8823504bc389b1399f269218812e7a415f0e12dd5499c348a15de8c9dc6942cf73026caf31f76f040c40e2136b1ac4b30a8b872c04aa70ef4c030e895747eed28b0321dc6853e8c1ce55e91d6152047899300f3018c2a87bcfbc78360929f50b7c6115913e2a1a888b7994b3a028224d1b8cb7e23f9aedf4682ba52189f1bed62e5c92816871a8e7b716842", .Okay}, + {.Shr_Signed, "fc4f2067e7226babd6e51eb89ecc636af0062872663c61af7efb925b7537beefafcf037da6a3da530bb73b506e48c98a50e45f3549f0a566f57ce5318ebfc3ce4c4a5c198ee14e9383dd9674e5aea4295b029ed28e98dff837cb10d11365ff018f4c3cf18671d8a97e727961b951838578baa0db9879c007dd81f96b618f5e5a25133db1db472d0603e683650f42dc97802af6354950", "13", "1f89e40cfce44d757adca3d713d98c6d5e00c50e4cc78c35efdf724b6ea6f7ddf5f9e06fb4d47b4a6176e76a0dc919314a1c8be6a93e14acdeaf9ca631d7f879c9894b8331dc29d2707bb2ce9cb5d4852b6053da51d31bff06f9621a226cbfe031e9879e30ce3b152fce4f2c372a3070af17541b730f3800fbb03f2d6c31ebcb44a267b63b68e5a0c07cd06ca1e85b92f0055ec6", .Okay}, + {.Shr_Signed, "48cf5d84776850d92d990c4ab65d89352e2542a47154c0258d0be4fc4df79a97feee3402269d8d6a1651468a01b6ab597eb12faf048669a3334a3361e8bb02a018ec8fae3605d18fc374403a7bd6a35a28400c49e0508a497b69bd32ddf3f54086b4f7cc4389556fa0f2d79c24eb2673d71ad49dac2179dba2cebb97fc9bf50c8f8adab0d115f12b6d2f43c09c83e970424f8cf72a67", "17", "919ebb08eed0a1b25b3218956cbb126a5c4a8548e2a9804b1a17c9f89bef352ffddc68044d3b1ad42ca28d14036d56b2fd625f5e090cd346669466c3d176054031d91f5c6c0ba31f86e88074f7ad46b450801893c0a11492f6d37a65bbe7ea810d69ef988712aadf41e5af3849d64ce7ae35a93b5842f3b7459d772ff937ea191f15b561a22be256da5e87813907d2e0849f19", .Okay}, + {.Shr_Signed, "-23b2d4d0da16305b1d90daf8ea6806aeaee1d2aeea8161364b0407ed58bda620899a82ddcf407f23da0c0b29268eb915e88d40cbf7e70b44f7a31ffeeecf10a2f8ad550a8e80d62e900c03ce5b2bc2af2e400a7092cb44d9c76eb67204edb9220010df8477f9f00b7a77647639c722de9084e4c526cf4e032279f76cf02f0acc17d3736fd6169ac298ce8ea23739cb3f87a0bfb908ab", "4a", "-8ecb53436858c16c76436be3a9a01ababb874abbaa0584d92c101fb562f69882266a0b773d01fc8f68302ca49a3ae457a235032fdf9c2d13de8c7ffbbb3c428be2b5542a3a0358ba40300f396caf0abcb90029c24b2d13671dbad9c813b6e48800437e11dfe7c02de9dd91d8e71c8b7a421393149b3d380c89e7ddb3c0bc2b305f4dcdbf585a6b0a633a3a88e", .Okay}, + {.Shr_Signed, "-5dc1a498dccdd33e1641781a15d451ec7c2d0bf815ed2238b347e7fa476fad74db50af5543e9fb0f2ff2046e058c9d4b91b068b0ff08ceda310b0820d021ea46fbb3433de8f9d22da4be1007ffb72366f589408edef2a17d8a3a019cadf457a16a0c3dd8c836509f69860ae023be1399bde4035f7551e1e778aaa9b6dcd75c595fa485883f0a8d58f432eff42b49a1d63d94b4119bb3", "2b", "-bb834931b99ba67c2c82f0342ba8a3d8f85a17f02bda4471668fcff48edf5ae9b6a15eaa87d3f61e5fe408dc0b193a972360d161fe119db462161041a043d48df766867bd1f3a45b497c200fff6e46cdeb12811dbde542fb147403395be8af42d4187bb1906ca13ed30c15c0477c27337bc806beeaa3c3cef155536db9aeb8b2bf490b107e151ab1e865dfe8569343ac8", .Okay}, + {.Shr_Signed, "-8589cf8ecc67022e1833124a9d8cdc3d47430292f18a79a3aec6467a6fb8a0baca3a2155de31457959f414cdd6b4a93f9ddfe90ec1c9a5766cb21229c56612b666d2e9ef040e0c86ff437f0cb34b020570d570e5badc4db4e7ea9b5ac444e35528a249153545d942b78e73980d986ceb938d2f382f2c8d024821fc1193d9b632204eea5b2f91ebdfd11dc367d33bbd92914253819b50", "18", "-8589cf8ecc67022e1833124a9d8cdc3d47430292f18a79a3aec6467a6fb8a0baca3a2155de31457959f414cdd6b4a93f9ddfe90ec1c9a5766cb21229c56612b666d2e9ef040e0c86ff437f0cb34b020570d570e5badc4db4e7ea9b5ac444e35528a249153545d942b78e73980d986ceb938d2f382f2c8d024821fc1193d9b632204eea5b2f91ebdfd11dc367d33bbd92914254", .Okay}, + {.Shr_Signed, "-b50222c1206e4fd6eab5a93d30b004d7ad5101bca1ede08bd47bef7f09d8fa87883f3edefd4f3e2e68db8baf40891d724ac71a0b0545a9a8ed0a74032c1e63c220aa50f48fc7dec76e39c8b612be2c7b651911b05efa1eca73c404ae291669218cbddd0e5165728e944a077e2e7915174196b59fe90e9f3f841f5a3779128c6525c68cf6c4a8546412bffcf2f6de75e67354f802a7a8", "78", "-b50222c1206e4fd6eab5a93d30b004d7ad5101bca1ede08bd47bef7f09d8fa87883f3edefd4f3e2e68db8baf40891d724ac71a0b0545a9a8ed0a74032c1e63c220aa50f48fc7dec76e39c8b612be2c7b651911b05efa1eca73c404ae291669218cbddd0e5165728e944a077e2e7915174196b59fe90e9f3f841f5a3779128c6525c68cf6c4a855", .Okay}, + {.Shr_Signed, "56e6788d00f86cbbf1db32c25eb96c41ac62297d613f5d45759dadf762ab4ad82926bdb76a34548577b4a8e1f8d5c46f7c849c204253b7a767a6b362f8a9f28997274eb995e7c74b03181b982b946971c9fda8661cc6c58388a8a2b895d3745f79de295baa3cf63a9f7ff00095b522322d7173e47c090df98f45266e17269f5244fcfe98644b12d88e24145e0c6102a2fa95c4a19523", "6f", "adccf11a01f0d977e3b66584bd72d88358c452fac27eba8aeb3b5beec55695b0524d7b6ed468a90aef6951c3f1ab88def909384084a76f4ecf4d66c5f153e5132e4e9d732bcf8e96063037305728d2e393fb50cc398d8b07115145712ba6e8bef3bc52b75479ec753effe0012b6a44645ae2e7c8f8121bf31e8a4cdc2e4d3ea489f9fd30c89625b1", .Okay}, + {.Shr_Signed, "a64c93f9249d0c02cea08a3087bab44964989abdd7fe176ccebfef4c52ed1a57c2052ca138900016612a0227ab2c01e6c0888df27797bcc35ef29c3fbc04a08a5ae6cabe49ce7162034c0b75ae2e8d5bcf71643de85ec3c82755c35e4c621c588d93a4392fc8c34bce34a988b1e81659825d8b9343f6013fc094d3e9b2fdc4ac86996c2e8cccdb2390d0920b642cbd3e44bc5f20c10f", "71", "532649fc924e86016750451843dd5a24b24c4d5eebff0bb6675ff7a629768d2be10296509c48000b30950113d59600f3604446f93bcbde61af794e1fde0250452d73655f24e738b101a605bad71746ade7b8b21ef42f61e413aae1af26310e2c46c9d21c97e461a5e71a54c458f40b2cc12ec5c9a1fb009fe04a69f4d97ee256434cb61746666d91", .Okay}, + {.Shr_Signed, "9abbd282017e94dad95c37dc37f246dc193e5ef5a33e92ec4c1ae82bfb305405e1d7b06f15aaea2ccd6c69c50daf8ca6dc8a743b6356fff72e4b2932e642ad3ea7030a8ca60fd3cb25ce6981fd9633ad4e6e4ba97616b97db63d04f917773393087921f78e812b7f52aecdfbc43394557c45036f9802e3b5f0b222ea6b544f40e8fa8c9dbc1df694f5c3ad4b2e134318831b7a0b04f5", "6d", "4d5de94100bf4a6d6cae1bee1bf9236e0c9f2f7ad19f4976260d7415fd982a02f0ebd8378ad5751666b634e286d7c6536e453a1db1ab7ffb972594997321569f538185465307e9e592e734c0fecb19d6a73725d4bb0b5cbedb1e827c8bbb99c9843c90fbc74095bfa95766fde219ca2abe2281b7cc0171daf859117535aa27a0747d464ede0efb4a7", .Okay}, + {.Shr_Signed, "-3e22e1c410863beea4753065266c625c2fd63edb22132dc06d7ab4dfc8a60b0f36e9fced05d7aa6640bb740a63968b41fcc39d6702d8fa203fa15fe8897aedc8875c9b3d34be48996712ee89f96d31d54d9cdd4f02d302b5204bec6fa62c04224a649cb45c418a5f5ad443b9fca7d5d6c2faa99ef24b411e465b4ec2ab09ffc8b6db3bce513ddf2bfe01b9e03f15a3d99e2ab158a04b", "48", "-3e22e1c410863beea4753065266c625c2fd63edb22132dc06d7ab4dfc8a60b0f36e9fced05d7aa6640bb740a63968b41fcc39d6702d8fa203fa15fe8897aedc8875c9b3d34be48996712ee89f96d31d54d9cdd4f02d302b5204bec6fa62c04224a649cb45c418a5f5ad443b9fca7d5d6c2faa99ef24b411e465b4ec2ab09ffc8b6db3bce513ddf2bfe01b9e040", .Okay}, + {.Shr_Signed, "-8b989963d9db9935ddf029a547415d7c58c391f45819363d9d0e1d893073cd3d8c99ed3fc53c61e9892c40f56fb9a4027529006a8138df459b22512350e15b1f0eb70bbcdfa4fa1d7e2fe2a6d710dfa55f74814a1294a3761e54f0902b3d9cf551c0e9664f7639e3aecf6d9aea14a275e6aba241fdce5b333d571f9240fddb8e4c47edb0f9e76ffaed0ddc280875759bbb3c2f341f84", "4e", "-22e62658f676e64d777c0a6951d0575f1630e47d16064d8f674387624c1cf34f63267b4ff14f187a624b103d5bee69009d4a401aa04e37d166c89448d43856c7c3adc2ef37e93e875f8bf8a9b5c437e957dd205284a528dd87953c240acf673d54703a5993dd8e78ebb3db66ba85289d79aae8907f7396cccf55c7e4903f76e39311fb6c3e79dbfebb43770a1", .Okay}, + {.Shr_Signed, "-ce34f77b7d2a4757bba06c8d7d95aba3715ec40516f5d234d8c586fe72da59ce3d61959b0262fb931efce0c1937c6de52ffd613b27a9cf672689024230127d00c5ac39f1259e9fb00dc808f3c5b37961bf60def746e6dfde9940999386b1af3acc26ed97bd0c4611bae2cc6ab688dc326cefc428daf8668305b7be4fe0063571d7e0cce7fa89b06591f178230b48752a9946e19cbdce", "5b", "-19c69eef6fa548eaf7740d91afb2b5746e2bd880a2deba469b18b0dfce5b4b39c7ac32b3604c5f7263df9c18326f8dbca5ffac2764f539ece4d1204846024fa018b5873e24b3d3f601b9011e78b66f2c37ec1bdee8dcdbfbd328133270d635e75984ddb2f7a188c2375c598d56d11b864d9df8851b5f0cd060b6f7c9fc00c6ae3afc199cff51360cb23e30", .Okay}, + {.Shr_Signed, "-12dfe1857c63f9205463f6d569b2c226ae6cda296c96ce938198a1855a48195905a57cbb50acc8f75aa1b34ee3e35bc170f0e4e7076c944dd27e697f0a816621812af9c1f84144aeba7bbea6c1e355f2f49f5a5ef30f64c225c96959ae21ac5e91a7f37389fc5fe970c18316a794d3dc62eedaccaa0a428e454a8b8ff8e991b51c7ef0406e1a21615a20e127df4444ed831564df5487", "3a", "-4b7f8615f18fe481518fdb55a6cb089ab9b368a5b25b3a4e06628615692065641695f2ed42b323dd6a86cd3b8f8d6f05c3c3939c1db2513749f9a5fc2a05988604abe707e10512bae9eefa9b078d57cbd27d697bcc3d93089725a566b886b17a469fcdce27f17fa5c3060c5a9e534f718bbb6b32a8290a39152a2e3fe3a646d471fbc101b86885856883849f7d112", .Okay}, + {.Shr_Signed, "fa93fa3a4d9e74bcc1e0506553a9f2751d0f8828ee1a94af3665dab70b29f9130e3eed89ac998ad6e7639a2fd5a2ddbbaf200d63b1f8de07fc491e2fbe67edbf4c865fcbd2dcd58e6891fe9a2f2496270bdf0321daf095f11732304b30e33893b5218c4c99cfd70e5d33e4ff2a94ce2ea62f22787946b1adb19dbb9b7488d6ba4a7ad859c792ce37b15ae6694fd6691993dca1ea4fa9", "1b", "1f527f4749b3ce97983c0a0caa753e4ea3a1f1051dc35295e6ccbb56e1653f2261c7ddb13593315adcec7345fab45bb775e401ac763f1bc0ff8923c5f7ccfdb7e990cbf97a5b9ab1cd123fd345e492c4e17be0643b5e12be22e64609661c671276a431899339fae1cba67c9fe55299c5d4c5e44f0f28d635b633b7736e911ad7494f5b0b38f259c6f62b5ccd29facd23327b94", .Okay}, + {.Shr_Signed, "475548682a5cf974c773e5ef26e86b47afc552ac55f14b7386069b134c84e24a9470700faf5baa9f72c45907f9037d585d5cb3fda47045d36cd53b7fcb6af70c3b8fbaff9975bd19d702636ea6fe35a3bb9c61229931c2be137be606467e147e20fc665a629d2861ad979ff5d74351a55634810ec27649c0767eb95c69053a29e3f62cbf7007b2f113abdfb6a55e9cb40d01205c7fe5", "50", "475548682a5cf974c773e5ef26e86b47afc552ac55f14b7386069b134c84e24a9470700faf5baa9f72c45907f9037d585d5cb3fda47045d36cd53b7fcb6af70c3b8fbaff9975bd19d702636ea6fe35a3bb9c61229931c2be137be606467e147e20fc665a629d2861ad979ff5d74351a55634810ec27649c0767eb95c69053a29e3f62cbf7007b2f113abdfb6", .Okay}, + {.Shr_Signed, "-c4de54b4a61ce530e5d4ce5b6cd20f5cfdaf655dcb1e250a8738fcf43b279f99ec73629fb5e749099247488313071e4c09a3af5a4f6a611a189dc636be3a4272eacae1d8b53b5c872ae31f6e7e8eca3dda2add175857749236db58ea31d2e0aec7af9b976204f52ab7c8f54e84c8937afba43fb30491d8ed61959ded29d1610bf8757e9e038a5e1bc4fa1030a61b5d14bef8720e6f34", "1a", "-3137952d2987394c39753396db3483d73f6bd95772c78942a1ce3f3d0ec9e7e67b1cd8a7ed79d2426491d220c4c1c7930268ebd693da98468627718daf8e909cbab2b8762d4ed721cab8c7db9fa3b28f768ab745d615dd248db6d63a8c74b82bb1ebe6e5d8813d4aadf23d53a13224debee90fecc124763b5865677b4a745842fe1d5fa780e29786f13e840c2986d7452fbe1d", .Okay}, + {.Shr_Signed, "-e271c3d22f37b8ddf57ed07c81e2fbb9654b94a6759c2fd653a8455b07e45681bbc491adfaa994a9e54717f1192e9111f6dcfa493ac277572b35cbe369763464a171c763acbbf43bd417b9992fe8242e2c62232fdd1dad8b533dfd83ad029f93d8be86d33117985826767b2a8adad3d0a902f54393815e5323b60e543239ac75b3bdce1bc5bd1e8b7fa4a82991b47057c1c143a93006", "2a", "-389c70f48bcdee377d5fb41f2078beee5952e5299d670bf594ea1156c1f915a06ef1246b7eaa652a7951c5fc464ba4447db73e924eb09dd5cacd72f8da5d8d19285c71d8eb2efd0ef505ee664bfa090b8b1888cbf7476b62d4cf7f60eb40a7e4f62fa1b4cc45e616099d9ecaa2b6b4f42a40bd50e4e05794c8ed83950c8e6b1d6cef7386f16f47a2dfe92a0a646d1c15f1", .Okay}, + {.Shr_Signed, "-4593a4ef9a06081c2140927edeb948efb4cabfb6efc0983269155f0c934ee2e64d609d99d2bdd201513b75fded6b3fca2673293367cd2627a8fc92abb8924ba64fa8f3e5e4d1c8a81d4f14546647f90d7f621d342d3484883f92684dfd58b602023c3f66b779c58ec66aeb9b8dc81dce0ca36b52c908051a335b245b087ee6c95d8820320078a5179bd3b4bf67cf2a96653b4fc8eac6", "22", "-1164e93be68182070850249fb7ae523bed32afedbbf0260c9a4557c324d3b8b99358276674af7480544edd7f7b5acff2899cca4cd9f34989ea3f24aaee2492e993ea3cf97934722a0753c5151991fe435fd8874d0b4d21220fe49a137f562d80808f0fd9adde7163b19abae6e37207738328dad4b24201468cd6c916c21fb9b25762080c801e2945e6f4ed2fd9f3caa5994f", .Okay}, + {.Shr_Signed, "-99e6ced373131cccf43997a4891fbc129f9d77fd01fe9b8b4383aa38f208384c647a36c9374702d7ab60162f60415bd23df89192c5cb76590be62152d537b5710d655e9d4422d38795afb874d13b9529ff4c3eade248b42c723f126b5ccf9d7b77bc44dc24f6b95c6c5afc3eb3f53de160e451d1ceade2beb969b08be4d62624ac3104cdffb5f507f4228759c6b1ec520be1a64a1b00", "56", "-2679b3b4dcc4c7333d0e65e92247ef04a7e75dff407fa6e2d0e0ea8e3c820e13191e8db24dd1c0b5ead8058bd81056f48f7e2464b172dd9642f98854b54ded5c435957a75108b4e1e56bee1d344ee54a7fd30fab78922d0b1c8fc49ad733e75eddef1137093dae571b16bf0facfd4f785839147473ab78afae5a6c22f93589892b0c41337fed7d41fd08a1e", .Okay}, + {.Shr_Signed, "-78333eb735a71c8cefcdefcafe66c7b644b6c0d2cdc68b4ec7ed9862041ce42abc3f7dfcbdd313efe15faa9f65ca34a2e007023438ed7b4deb5e8733073354e043f7729aa2efcb80ea735289b8432f59aa1aeb6084ecc21c30a91ed0a4dbeba52c14320c71c4450df7117ab040e675c438383205ff8a8f2b34e68c108515d15d92c67f3e7feef3f8d10fc8399b96293ebc6d6b85a317", "1e", "-1e0ccfadcd69c7233bf37bf2bf99b1ed912db034b371a2d3b1fb66188107390aaf0fdf7f2f74c4fbf857eaa7d9728d28b801c08d0e3b5ed37ad7a1ccc1ccd53810fddca6a8bbf2e03a9cd4a26e10cbd66a86bad8213b30870c2a47b42936fae94b050c831c7111437dc45eac10399d710e0e0c817fe2a3cacd39a3042145745764b19fcf9ffbbcfe3443f20e66e58a4faf1b6", .Okay}, + {.Shr_Signed, "49609479001d385e69ca0851a00f2e5037b2c0cb75aa5abea3ca320cd15e6ae49b8b8febe82af566ec9ba70af397197cef1c4836c683fb34cede40291b54d214e4c16665a5010c73658da7fc9f439699b7747b71f384f22d27003129321294ad53a16121d60e7e9ff0c3e8371d15241495cc07e5617a68b3022c9c8bc3a1afda4305d0292958718901e5ad8c57794fba91a82e1140b1", "56", "1258251e40074e179a7282146803cb940decb032dd6a96afa8f28c8334579ab926e2e3fafa0abd59bb26e9c2bce5c65f3bc7120db1a0fecd33b7900a46d53485393059996940431cd96369ff27d0e5a66ddd1edc7ce13c8b49c00c4a4c84a52b54e8584875839fa7fc30fa0dc7454905257301f9585e9a2cc08b2722f0e86bf690c1740a4a561c6240796b6", .Okay}, + {.Shr_Signed, "-bcc96540868d8f7db67f177f054355966fefe156ac354cde9c230814927454f10be4384cc205a8c0b8b5097c10d1e24ae3e73073c47b7016e10253bad456b57616003cb37a93aad82537f43492e4992d0e555ce4b91295fb389e863767824adf5ca5f04018e481e3542d8d34dfe6559d425e8224a43b5be1321a94c8a58683f586a47756c069a6ddf910f923905f7df0bfc4868cf55e", "5", "-5e64b2a04346c7bedb3f8bbf82a1aacb37f7f0ab561aa66f4e11840a493a2a7885f21c266102d4605c5a84be0868f12571f39839e23db80b708129dd6a2b5abb0b001e59bd49d56c129bfa1a49724c96872aae725c894afd9c4f431bb3c1256fae52f8200c7240f1aa16c69a6ff32acea12f4112521dadf0990d4a6452c341fac3523bab6034d36efc887c91c82fbef85fe243467ab", .Okay}, + {.Gcd, "-dce27058ecea31a6d3ba6b1249c3e7f0233751e474863da74f911ccfd323094be15561afb0ed72fa2d85b3e15b6e7810d5c67ccfcab33e73548fe3b287cea2cd2329715da0ac07f9b01a1337d2f10f196496c625aab4735a17d06c06335505dc77c5600ce1de730dfa852d46baa0d2fac88312b243a91cc848f70ee3252f7e573d33dcdfcc916dc734dd544b603e907ab57045b3f11", "4213f99f4e9f8932736c87158f4db27a877f205e640b5c26164395b8fc7f31424968e2b6c2bbcdf87d23177993e5ccf0545e0611ea6972b70ffa9026b67b1172a3cb245c4a7ac8045e56f032a9c11cb15528eb422e516ae5f8b57733a1e00149ccef51ac33c08050cfb185eb9cfe44f47151263bbc5410dd59c549765dfd2cd015fb99c38cfc826d7e06cc36e0fcfd35843c7bf2bfc7", "1", .Okay}, + {.Gcd, "-30fab377171e64bb7b931906247097c3ba0d6a124e639bca5514dd79d126d5cea1e4d7460b5a7a48781ef9302c47492c8db7a9fc0090a59165f4396a70816f2addb6b8e80b846a575d8c4df952276858702d545279fbb0f9ce09bfdb5a07479d480db71fb20ac54dbde6957eb39bf8d8d6762b33e371bdee134ab6af996cad011e0195bd3f43962204bd5a2ebeab6c7d7548b9a9dc0", "477eae4387c95a69c8775ea116065918a63964cee4724749c6b80a8637b2e52b441c5d675c794ede19db2264061a886c8dc8d06d57cdfce18ed5cece2a0a565170826a3aed3e4540a9869a69c3b565651d10ca7c759baeea0d40170e9df92e24a5be9f090a3ea83ed6811ee8477ee143979ab01affda04c3463a6ea83f719abe73688050bfb92413311aeabcbf6fe129ce84e47dbb9d", "1", .Okay}, + {.Gcd, "d2fe4cc631b0a04acd7b38836d9fc3c5b03a0723de22a091f8057646a853bda21277b516f37e0e95e3206ecb2d4b10d719ebf15ee68f37398de5d5888655fe3a05fd1539f04cf2019a72ee7327e2817216810e0971342dad9c697346115b1adea9d4ec23ca206b32af65f5b0e99115735b9712d8239514ebb5a4d87897dbb36118438ea748e28cdf7d468fbfe6c0d2f5d2c5797acde8", "37c4582f6c93c40c3ee2b690637de4f8b5cafb69d65042a918eea0d7edbc6239b954edec76563ed135f2d83c90acf9f87e783dd1ff205fcfe6cda3b3ae642472b6438b2fbf23f7c2bbd445523816a8605ca45ed7ae191e6889183396e60fa3e15b0125c9dce460f605a22229e2342c59800796c459c5c99cc88c9e1ed1dce3a8ad98e29e1686d29f5d918a28941934895ad09db400a1", "1", .Okay}, + {.Gcd, "352eb8a645e374a0c280a31b8778c536a620860dc7950c83c4d42dbc5a024bac648718cfab2706fbec2f43537295705de952f1f583c5b84c2ee1f7e285a0c1457b2909635876e4218f427356f439e4627840fdf4079e41bab64332efa927f24b1cf65d48b4671e059347e3f81842fc806d35fc7d29759331424fa6085b425fe97edd969c8bd083fdd1e52a69feae36bc298ca9914f9c", "71428da161651bc4a2bb3fd9b619113ec0eaba47376a94d12682e015fc574673239bdde2a3a10a99498ec20e0ce3ac1808da41f673b666c46cf588c4f4df219c55fb522210717329c72a5509f7c7ae23d54963ae2d32c12c8a110a7069b7b7b4747ee95f20611fe167edcab48f49c109410193c45a7f9cb89535bb5913f19329c64156df8378c3e843d4ceded21cfb8f018c748ef7fd", "3", .Okay}, + {.Gcd, "-1e12cb15f32fc005409a920ba5055e6f07707986a53b6c76c941c027562a3102d70c6b9658293545ea3fee68dcaa9699bce59013f8f478eba648830172d4bf6f25e3a3450aa2f2cb421cd70d4a331cbc6e33a45b63707ca24f6cfbe63c11bdd5497ef7de6cf2c5151e78b02b60fef24e65dd7ab04e1e961c6881d33a53b8a9d25e7b9f1825122445ff397ed2665aafa12d770fc8f43d", "cf70e40a51995f0b04f8ebcbdb7adf14e8cd46066808818b3243fa5b00f60a23899863521e2b7f320c4fa68f3594b89ea6fd70647f5c13b01e9cd1eb9032e355458e6cc9cd4a4151bf2abdfb4027deb801ac713a05e063c189b74f2e89176b9c05b5da4cd493e7e4236fb96586ec08a4fa376381fade441b76a0548ad3f3ad39c58bbaa1e0daf8c143be236031b8105ed45fe6b3a7fb", "1", .Okay}, + {.Gcd, "98e6c94741fe4558583895f3bdeb74add31fc190c172cfa931081916f30cd5234c124b0b6a924ab87e33e7552e9438dd3fe6a985be3f6211a32f4a493b61cc5809b9e0bb731b6ec378cd2d3da33a7e3d1fcc8b61d6a860b65c57720669f11d99393570bdc0866302b2095ec7a4cda5d9e61c365d091e476fd4bed400b56d5cc389ac11bb830dc6abeee44456d3b9f5dab94fde1fea87", "244cbe2b4fcc9982ac983a66afd48f818ce80e284162fd5ed355188c67a302484633cd3ce60b590f34f33b2a345cf29c5b2934cc6baf062d002b8f1e9cb0f354dcfde1c50d3875c624d4f33c748f50d7e8a8cad6d47b0ae93c70a27a3b1e3cf5e150f2e0c18e9ec5d26b9c7009ed61d51ad47f06ff9d89826f5463aaae351037e04e2c81d1db44b9fbed9754417afe248bbfefe08500", "1", .Okay}, + {.Gcd, "2754aed11d65a480fd309687bfca3e6ae6658bf20f529a73b7b85989e2384180b96c9755f78b6e2c60af84176617cf4b9aca484c024016a055ce4e41e10871cb126398fc6dd8e0edea54856da041e5fdd9e5b37a588df755aa1c5191c7476c7e6de00395fb00a26ac456519e56bd816ebcb16cb5900a849686984785a89b3bb127a8d6e0f86f3caf8820644aa158f1c48d26f4a22f79", "17e25a22ce94b4e600946c95694dea26c8b8361722df5a59756397c9ab41c34fb2ab01e4ec541f8ad9600849ccc9df47ec5da332d5539f61de869737fb4a5df38f77c08447d829eb2db09a827aaa15cb15e5bdbcee569bd15b26b91e05843a0b6f13770d3497bb7b7b53486a71745bf1acbdfda003d1ec0b817d297f54342f5a2efb8e7dade21212e43c357a9249e954bf3759a3d0a4", "3", .Okay}, + {.Gcd, "-bf841c6911eedd977bdcb0d615b0687f9821fcd898eea1c44d94734d9551e20fa01fc101fe9bdc4cdaba4bed7effcb43ae85d201a96a0d1b1d8cb4103ff500447904664a4dabddadceff57042fad02836c578c0b4865e669f2583edda418c553d7abd092143279e6d6082247cac763bc97b14c4e0d0000b61f1ee4dbe04b7c2e16971c972bd3f4c4580666fe46e5250ee131c47a8b4a", "fe6a15db9361d901442986fd413008b8c6a86cb85527278885d056d787327d174758cb7b096eaa3896f01bd48f6fdaeaab34e7b4f3614203534f80bb84834f4a650bfde12a6f6c1ea3a92076447392f33eb1060676d40a73503737340f193344d65bf94ecd578240ed3b8b5df98bfb52851a2371729fc1163de86a9991403fb7383997b1e860adf3975e61d0ea7400adb004ae822203", "1", .Okay}, + {.Gcd, "-e4b5787cbc3aa5e9477d4cd7308eed660723dedb915bac787fa796a912da77b246db8f272440bcf830d87d64b4fc7091606a36519a2f65f600e75a3b28add49c154d72649922ba5231352f01bfa5859589b7ca4a560cbab265df55cde5689494f5518a9c559143721bc0c9b056ef1f280f28b4069277db8bcefb7062c77e247fc3dc3baa4bc9d575da9fa590430b493d9d0d1219f7b7", "cfcbdb39e0d01e8ac8cf0439fc77085281e4ed11ceabbfb54b0a7d1ef5b71b116afa36c067c366d35c7499ebc4a08b9a3042232a017a69216e3852675e76605067d57d784d3b59ce2a79974c0c35e4132a3c7e61cbffea297fe39c8690a818139f541f735c5c12d00b56b6c11001fd4a8b1ca03966066c7ad04847479c4ffb77b9b93bb6e1a426d19fe5229557cc59a3f52062cbc3c6", "1", .Okay}, + {.Gcd, "64cd59d816ee8b6ada45a4f837beefbb0700352e3be7edbe76950f6c209288613a97ca5d07d7968c92a548fa8b0e10a8ceb62f3ef24baff353dee71fbc668fcf0fd6b577b167e09ca0d3f23e823ccee47e68e59af45e1753429087ae6e81f3eec72c8285b966894b4733e12e97a0fdb9024761b86c4491ece8721abd64ac0b463b6693c9e7dac4e587b1e0b384ebc973e68b6235b0ee", "c7d997dc1dae0e60b3e65c4e3365fee2687ae17703b06be54dafa67c65fdf39d747968efd82123a1afefdb5e0e6af01d2c889155f2f7872f7d0bff85800abca4ab8dab7a9fecc0848974a534e5883801713f85deb2c08b2ecb700535d88fdce5efc305d3555bd474c1052a5f83fa101abb2870d6ce331469b3f7e65a9751afe587be0c23790d48dd840e6789c0257dc0f8cf9f9c6d62", "2", .Okay}, + {.Gcd, "-178da89ff100107a3fd9580f11d77a49095eccadcd385fa2091ff49d34f274da47587926a4d78a202090e9fe95293c05bb3f275591ce5902556b44df8440ac4fac24e7285e5ff5b3abb2234647933759867eb5966555ab9b44e3811e75c6b1e76f95677a5fa23a39a1d506b835067442470c4bd64584ea9896bec0bd6dae0a66323d025610fe98a85dfd0529fba31b285ae1a762278f", "ca77223f10be6d09b27888a10183fa1fc46c897c244af355f5f80214000a4f03ad9803a760b28b8934034d5c68a6d81437682b3d832314919047caf725fd54c83b3b842efb307fd4e55c4088b1309421c6f6db7b48fefd8d1e826cd9d01bbf41c712745a098ca95a5f791eac53bb6dbfa84b032bcc2debaad850d96d8ce2abf7662db1c2c73f5a1c0d893020a5cd0807669007d0582", "1", .Okay}, + {.Gcd, "a7e707cc26477774e04a73beb70fcef81aef2a9ecf36508c073b953ca31f631de8b0170dedbdc3603197741e05558819257854ef4b23169b7da796019a020799e82f82d058e1953eb6141ea66f4c4e3645d33dcc012a15c16388c6ea4895c9f24478e567bcb7b4f6b461477a1ed94bc8ddb4183b799db5bfdb4423dcc256219b3ad7a2bb56c197207a6559e7695be671b1868c28f9c6", "875ac541d7e3c696cc5497f599eb5dc89d72ea2c0cb93bc62d635dbe6c40b0e257b4bfc871f646be5f23f43d0e59409b09017852d8ecfe2ab5592a8b2fdfc24c2be12dc9f269103bc2494ca1a3eaa84047f5d42b8a91b16533017cca1190807f9366c08d6c45b4477b5dc3621983cc301dc00ad1bb680565f92067a281fb1eb569bdf52a7f633089045a99657c2e3f21ab2b77dfcb9f", "7", .Okay}, + {.Gcd, "c9d5cebe5815f2893834dda105fe4f97d5f2ce2aabe4998b57298709d5665843f8f47b0537f7715da537aa1573f7ca532b04fd0abfa0d029c24c305575101f26cf8a9e32530df07ceea26e289721e17945481e007ba992e4b03e16a08e1de5594470da20fb4a1ac101dc4e46eae7e546d96e8882269b4fc52df62d142601ce03448608d9ac5e3a81771a23c85be44c030a7d59beeb83", "8b89895ca471e660c9e5e4c6cd5d3378ac0abf5701caae4e31fa0cefe67402a03b65208ebbff165c4b1aabff1eed0a874e8690c3dae8a0d12807c8beca8a7c790c93cb17a8dfcade73d9d65848fcd463bb0aec29db384e03b3524b28a4e9335de5c5219410dc3fc6793205526bb0ddf67d1d6cd63c647e43d269e373eab21a763fab62c206350662cd2af83dc5284c11671618a3297a", "1", .Okay}, + {.Gcd, "db6cda25722f5402f1e4b301f8bdd7a03c63ecb7c023b323380b805ade5afde42548ecbeceec942d4ea2dff19df6221578689068e03ad1e2d7aaa1394730a6e7d0983e87d4c2df4ad3c5216c7c5cfaa63e26b71490cdcea6ccbbf63ad51b8faec5d6c4449335fddb82124380e91c375a09224d4bce91d09719fc42d3d08e37bd074a8b3cceb79ddfb11d3bdfe4545a8c690308189616", "d64321fdca952457ceb06151757c10ee9cece495e2c8b605cdd25475e03b732cd21f0217af0b7e75b6ea63c0bba96266f0440f11e4699a90c30e473acf4eb244c0d88f8223377fe95bf90eb34d2fb862614c6259f2d5ce986b267cc991207b43f6d60cb0e0bd56c133415e86cc966ebc65fc44694141c780d0d52ac68a00cb5bb760530ce3244aeff045f527d8240e2147fa7373cbef", "1", .Okay}, + {.Gcd, "-253181ecbf9f80f23cc283410daec8602aeef4c5cde944779c36e28a16efd58cabeec2ca79f1e3685c0ead5135bc6526eddc9a169b7c13c545e6622b21e2835b48d3284df2ae0976e96150bd6a2e533fd7083312ed28152fb9f7670a78d5d25f82c44557e0c1e1d09a8a13e1e2e09385c0ef4152987ff89394b1bd07c2731736c5f21c6ac1242326593a08668ca6f50f16fd3da04656", "ce2aa279dcb5acd9249ef6ddb283ee9933819233b274b46ce9193da41eea493abdb04973db9f797b37c5b3fea455b1b4dc6dc70c857e4d93b1ab0e363b10785454a86ae929cf1aef6b329d6565c08943cdd9610bce6a00513c223eba983e06855a8b2af2837b5b7f1fc4061a0ffbd1256a0b0cbb7a2da9b20bce37367909e25ef8e1eaa3d1d7c004b912f83589f38d009e2f64e61253", "1", .Okay}, + {.Gcd, "a1409dd3da90b28f223217bfb76f7d4d07b61565cf8ad88bd1abf037f1fe6d28140be5392e700cb3af9d977850a2407c030645475b0348b38677c2555b6be35dfd614bea4939550bb1ea8dbefa5fc75c8d3c18f11bb6f193e671c703c4c91b12a594e53ab1f1a12cc39ac2f724ef89d36a542bf56076d2d0918f0be2c5dbdb022c68c88392eca2258990fb43c3a8edce2820edaad901", "819532d46c8579d2ecfa8eae92f965091aeb3a14f5fd66f05fffd022be8e7f957180b5be491224b687c079c620182998f0328f05ad8e8f2140c2dc65202cc3f14463795bb04f94e32c8e3acb8cc25743c3ce993f87b23540693f223a4eb14f83ec2e9855ae8d32dd5270b93a5a9537c0f4d5c57a6881ca726561b90fb5b563b34b3db22ef67ebb9e81d9965e8c393c68440fe4b09420", "25", .Okay}, + {.Gcd, "-52373aac920e3373c3ebc8b2a9669da690137d2de38feeaecbfb6ea7f7a79767a1bcb1c68946729cfbff951c81b87f3d5adfdab9991c89fc02ddce8ede077347e6fc466abcc1d950ff9a3631570f5bff8e3f9dfe4f7d6e1dfc0c3549481006394a10ebc89b1eebf4d146a270baec1651d74f885139c8e1467c6244f35f959465dcadd14f81a5e70a0a2bedcb23e648ff5fd4f09fe45c", "b4e70408a8339a40da2748dc5ab99cf3639d22f836d4dce144c6df18c55a22b922ec04a7549392cecc6eba7f4be4f09400e755340695fa1d9d41c4a5abdfc2c7c7a02a199d493cc88a7121bed98777fd70a53a8b273b3eae392f62879dea96cf6710bf4c6bbf756e18c1acc9c2b4563ebe5a87b401367aa3743c9dbaa29966b356c2091c212144c1dabd628d154655ed8af9d151eda", "6", .Okay}, + {.Gcd, "-28443d629daea3ec6a3bc189e5684d6ea8d4d20bcb3f1551f4ccdeeb1f97d8b69edf6bd2e2e965f40a22a74771f1dae3dfac4b71543bdda22d80f1456738b47db6f9c3a29a106f2d11ee9f676ccb8d549766b36570f575e18c1b7518afb8fbb6690b3f81dc93e390df9630de881d05986a3d035720ecb2e04e452273192d0b15782cda068676bb7c8176691646dd31a60a6f0e51b133", "d19a673b82b510adfaaaf211763f53336e1d69c32fc50ae49710961b8f2ec10ecad408dccfd11417a88971226fa67511a5f9410bc1f4ee3060d8b50f472127cb0f955e1e8c918bc4cdbbe8140d51f42e4e2ec26db8c477b934eab238b00d6927bd5b1b30d87b4cc30f11fe4d364ee063667d613dc9fd4b328ee34179dc63235ced7af70d3991d413e49689dec606f80e3a07c5d380a", "69", .Okay}, + {.Gcd, "-20e3ad61e323e97d467a55539d9e2e645b60586a94f1da49a9a2104a1564d0b48efd033bc2069b32b17d178e1179efdc674806b3d69a89b28ce592536a4cc082d9ca6e3f22ef457006867e53c14b52a4dc894e5681d09cb43362768f13d8eda4be0b78027919bae9d7d7633f6fed97eb71ccb002570aafcb51350acd01ce481eaf144ba9e14cf131623d10903be6a191c60a978cb899", "b07814d1ffd8f1b9ecd39befa34646cd8bc26023c01f5c6a53dbdb4d3fe56f64d1bf3ae7991e83c90cce635fb29398206fa5fb3480830a19ddce7afaa919c15e09eb4aeb82e4a86ac0692715dd1a927ee3855d2fb3628699b3f122e202f11e36562ecb7061b870dfaae9d9501788005d6de01e34682bf44e0f4b5d1b76c2c5a3350b2abc2b9cbcfdc4c00769d1016b7a042b79da90ca", "1", .Okay}, + {.Gcd, "-c3355ac049b7350d0617d708de886bca77cf8dcc4c2d449892703e42cf9a4dc7e9551fd5102c637e74112883cd0ceaff77fd5541d29087cf0c91fb39f8335d5f87d5a9a2062a000eea83f96dbb92531c03031085133c20d05c8d3b211d732f345b2907bae9c17edc80e33bbacf7a96b17e65ea1799bcf5559cc9c186e276273868ecb1663bb8bae9c986e1939aa6ea417f311d43fdcc", "b911bedc8b70626be09cd15f3e3cc839dfda24ecc1b8b99c614b7730d3a22f548ccdb4689bbb447306d9de62043355883df8b100a696b90522e8f82a42f530641ed52fe9092234c82048c56361ed00e55f67155c237bacbd6cd6cb66bfdbb7f0cffe43e094a24e9f42968608f2ceeb2a5623e20a4be901ff192f8e0f644dc19d94e646042cdd95045bab95a1e20ca058fcae99f25642", "6", .Okay}, + {.Gcd, "94d4299123de45d074aa5a894b8705ab5a2e0feba2f080eac29399bcbb38da712f30d4f7113b0a7a6730e898b462288159b3533d7c233b6127b5f1c0781c8487ea184b587275378f84004ec687ea91e35812c77270b6679d12197c82626ea35cc02c74108cdde8a7e6c405d9e027a9a880c4c874df34555ccf61485bcdbdbdfe8de71bba4cc84e4db6649fd4468cd8011be34a26a997", "bb963d80016eeb3eb62283deb55e58b63eb7a1b22c83e30c58c70da0750b65fb2258a2c5cd27a74bf839fb4f6fe8a54570501ef76c2aaa7617c89f1466b9e00ed57d5895c0d64df870c4642a36f7395edfa9e8d41133072cb138e408f211ac5979119afd3cd3010b562ba258d9fa5b44e7deda0038d8e898a5d72d07866c4e0c1ce51581af8ecfc61aeadf1dd372a543b46655499452", "1", .Okay}, + {.Gcd, "44813f0a07384409988b54aad7512c4c345334da5c111f3f92fbe3b2c9f236371ccf41b0862e4fd40d03535b4a48ef932fcf1c30cdc3ad9a1f8530258cf4b552820262639230909d2be6734dd24fd00031168a862945c8a3da0dc7416e6f3a8a2ea7b293a65ea962ea64e58e705b7444c2805aed227553ab10190557deee8818677c456c7aa73d16a4a27fed6929a90b35aedc83466b", "520323b29ba68689ba93ca05e1b6a346e6dea49e42d29d31090a53a4b63eea044d69c8517e23d5ff36b2af50f35ba36a88cfd4f78b6ae19c9f5972e98ff327ccf7907add94ba3ed6831ad474e78216d1c64463b4a1bdc6ec3f1f42aae17f210bc72e8d402c029d8ddea3b8ef8fa801152865dcba0df97d86f29387596f407c836d84544906937c8946cb63352b5151645b5e89d0168e", "1", .Okay}, + {.Gcd, "9461495e5708a82f803d20a7e9b7f850a6c08f913a2357b6f460f53f055847eb8787e3a23dda36dd15ec86099373e2a60df8b6751cd17114730b660ab8f9613545f92de920305a0123c719c2fe0bb405a58b94ef2c611c6992925ad40963aafb0f17b12f47dafb75a35cf0b4ee3275f058c83906be91925caacb4af52db98b31183a3e8ab4478d9583ceb44b519cc04dfc6cd02b6e93", "8bdf6e7b2b92f74830dcc3fe7298bf54607c67ef03d07fdbed225e8645fedb5c3f53cb088d2e1ef9bf03d35ce5c3ca955b332f1cec681874519e251cd4c09462009df48a55bc3ad152828581756a2d38ebb0b39f487892d630fd35a7ea910bc7c2babb6ea6a51f5feca1329ce1a11b39e0a895045f43b416209b5ad6d953af2059a4be979ff61d0e73285f222b0411e49e3c8810a5ae", "1", .Okay}, + {.Gcd, "-86910d0ce0cb64a90223b78153bafb559a10bd0317b03ba733e0d04b3ec1b3139461c24461f26a92f6aa9c7960d6c0300074a4cae8c9c57585dcb6320d34e80fa902c84c2a40ad5fcc2b2b9b33eecebe175577a86347b16ddd0ebd2f82fba501177ff7c72b54ade293d69bbc74ee850f7789b316f9a6bd932d64ee3c9521958ec159c8db9986b8c34038cd324b37c64caf494703345e", "a6fd3be8a1efe25248ecfd03ad83d52a283700f57c491f49093b48af0acfa9a9d9492c9b49bd7f9f63af586c26b89236de04d9264f68e7510df04adf96e56b83880733531f9d303008156bc33cb43b892570ff23ad1426491c52b7280fce0829f4594d3b59b33b53844a15eb40ed62a76cf18df913b37522a83c85992de237a02271172f7264509dc70c04bc4c1e13e6a0aeccc1c232", "2", .Okay}, + {.Gcd, "f70e3a10d99f547d0e531597c85fd6ad3efcd19c4e0e58d52dad789ae898b9adc063748174311817e62769d5a9e8c7184954acad681f90b15a4efb4466bdf7c3bb25c11fa1a947bdd3ed0aa5ede302ddc18dbad1e0b578466a2fe8fb4aee18b174b4c64e72211e6832d6f8ec0dba14bf29a41cc642e39ff3c2b4f7b7585985d24b66d84bd13fcd68b2e7fd63a1552aadfe3fc4b2153a", "431308e643369245c23caa98cf853ce624d70bf282fcf14d148e2f745c10103661fc0aae75d37305a9638ad5803b312612073112b3e66cb5a3f7ea831c0fd6bc0b950517f2bf21ea01d20e2afc63ac35988ba49fc36b9c63e5f06d6e8e0338e97aafb88471c6e0c0bf87b8c2c510ea2c15798bb4e7cd727e4d57e9d96ecb8a3312b090b005f936d70b828a3cf9cd32d68b6c27104901", "1", .Okay}, + {.Gcd, "28a0ba1c6b9312e41b560eabce12eccd1fc245a4757a61d56c09362cbeaf9c15281b8b5dc220f2c705e05166f52e183816dc132af2a4623e6c61e9da9cdbcdcfa5d4f4e716689bbaa95860cabfcae4cc09f89e26fdde10f8457cf84717bce38fa26f248e408263e948f5d03b2c22fae2757622e7d3581109042a36231aa0ba8bd24cf35d37b7011968522043ef6f67ab8a53cd668132", "79e3232d22a8245c6954a98ad2db1a45f09d181b9862f62f31a7a9f0c789edc3839d3a8022f0a2f6732b44d9a18c75125894b76165bec4cad4a1f83b07d5c5971fb998bdecde03fc7e2f6d6446d1416a96dc5715c10d9c92d2aa4719c418822a91f742fe26b53f1c6c23de0c8f27e390018f468b59bfdb3ff9381b06f3d16ea1ca15d62064c11d4a03c34b48f431b6d224a80a1b550a", "12", .Okay}, + {.Gcd, "ca782e2a42d712828eaad39faa2a1c688eb0f172e3d713d6459596cbd850b0967432c9d2ac024012440cfc220d675c6cb982eae50c5eb712dcf531a3f7603bf65e6269093ff607cc440d5bbdc8021947d68173ec9a64aa6418fb95aa77ed9ff7d5b994aa5d713758cd5b38fc1d650627bf8264d4d1cd3979e9608daa6539570f8af5670466e8a7e60ab59ae89ffc432d012417255844", "a262d1f941814114c3c205cf92357275b34ffaf739f84480a6638933d480b86dd3ec81248204ec3d7a2887174fd5404e92eb94ddcecbca2b26835cfef516a9c4b4e85ef6bfa4f9db0690a345021d9d34301d5f6cf6b6e59a80e6695eb45dbc1af759019a5d3cbf726e7a35bb20a73248b8c8af1d339f44247698377c777a7c94ac7f5a77df76c8af64cbcad8d02c5005409cece4d0ad", "1", .Okay}, + {.Gcd, "4437b965190acee31edbe62452021d28ebeb45e5e18757a7d86b1bb7a55b74126c8e4f7d03cd9d11f46b04b0cbcb17ebbb5cb746c084db6a5654e3ccbe2f9d4ad6c9f6c95ca4e88585437ce282114928f7a87d83c5b39b78b7ca64020a11cbfe87fb13dd07c674e3bcc2b15a9f253a91bec405a120571a387b04e95a99701a13e55a43c5f4aafec585401bf08dfd0ef9ee28521b4332", "dc787203768020d421e549ade721926fbf303e280a1d966f8bddbe9b778767ccadf4e400c9830fec0989cbbf94608a9bb307566a346b3d4bf0feaf39c1787066ec6d9d0d537011d30b489afc0be65a3132a1dbee4e6a3025e5b831116940801efbfbd630c26205bcacd14966e640995642d82a2ac4ec579059635bb06479c4a55712b693ee8c960eb25b30fae6527b53910a2853db01", "1", .Okay}, + {.Gcd, "a4cf46fbfe586c0e5428ae8490a399384573e102ffd0c11f2fc6a421cdfb8f32b50115f0b6b04b888fbecf836e3bbea56ca166420c226c837ad56fd02de271172395b1fd9796ae7aa81682c9a1ddf9d3a371bf73a670d5c86af324f17a3f9fc4f3dd61edddea2b5d0f5ab95797b551693659ed1525bc2fe173be963b8796813838a848a739ff76d2e0f7ea44974d329b3d40bd371b51", "e14fd8321c7927eae750379de834ac0ebd3bbfb0749b94c987a96f09d3a41ea8bf1569cd73021276c436079f9537ca55f72d38b017f1dee26d1882e4cace615c60f51af64847e1ed74b15310813dffd86eb1897e3452f161eba75fce3fa19e8ac00c4dc24d08e2faeb8f2c2a0c5d1ec670c06048995880af892ef0585d1afb652a5940fa000a0f584fc348f1da890df4bc45896ee5c6", "1", .Okay}, + {.Gcd, "149480e02284e5aecc1a0f782bed06cf19cbd8e0ab09c8e1f407212af65432bc84a386fdea1cb43bc3bd217131978e350b40761b57719782040b51fc57671c6a13b020514f12db50e60730a9acd89344ac2b2b18d090a3279e180eedf929e83134a772a56fa58ebeabbd14d60f1430dcbdf05b2c8186812875a1f1c428ba0be0801f33470f237c43b67353ec99b7a7ea309a4e96775", "df631a9fa86c3a9752e8ce54d52c5decee7a1824ad33f41228580ca4c576678fa42c4e8b3d9b8df430b58b5e02dcdcc50a32752465c7d50675754add4e61aaef848ae595efbaad44320da8025af94d544498da0a01dd2dc57337a61100aed1fff804728c51b968464aa5c2fdf5d57c1b37a6e5ae3072d7ce45d8d03bff97d50d57c7e048ab15e03215a4bd9099d4252d63e6ec9b7c64", "1", .Okay}, + {.Gcd, "64487b494e4e359c07504955ae8783c936bcd64d7c93f2384b1951cf6e2b030b7025b861586c933fa066cddb5fa0efc68a58533511452da23aa3bf9c2b02703f3b22710f35c73d70874b1c898ad0114d6123ff7c289a3a410b0e85fa60f7b8d034105d51d8f9cc5b20040301a5d128c0ff85646190411dc79914ecce310dca6ce6b886ad293163706ea9a1eb19130f0f96c113eec4ce", "232084517d58b7a3f28effa0075797081bec9d5d7bc9e66e34df17e0fa207c01b9de440f9dd176e3e76515e90c431246372c5b7057ce4b387936e6d8e2e552eda10aa5c13b9c0e6555e380ba5de0724882c2f16845659a827cfa9fb10155524667c841f9a51eb7a3181847ee497d05a8034f9fc972776ebb0615b754dd4ab24611b6919c511c1f5ce1ef79ceebbb9891dc883448578d", "1", .Okay}, + {.Gcd, "3cd4eaa0141277c2f0ab86f9b76d08ab5336057296426f6d88e93e89772f683d2fd20e0faeb23a45f796b075048aa7415797f248e7de875df2a3c52283b62f386b12ae6ecf3ecd644c12a240db69f4c421fea4bd19c4ee86813458cc8becabd34d824b6baaf779db780fe16f1be999120ec0ef05ede72bc946f5a91674e39b3618f753b6e3e6cf842641ebb9350358090e38fad3a980", "82b2c5cbea29ae53b96ce2a0a462a92c0448c0a55764497364845b1478f728c9f543e41250c42c78b4f0233af7cb51b6be76baa95aefaea3afd621d4d64fcf724c40286715e86faed95476599def71d588a18f94ae29fbddb40f3579216ea0e1a22500d498ad8ae3da4f9c2199780b56fc86fe8ec5095d5e2777bfeafc2a276c5b5b0e488b5023f1d37064ca83760f5c04f76ba7206a", "2", .Okay}, + {.Gcd, "a8e5dfc6f3e736be0d90100dba6d75a1f33f325f8848d7ab2d68e66a3339b5060e2f6c3df034b67b435de4c9f4d4e343b0f910c85788d6f622851546c0c91a4dd0ed4e7e395be6868dcd85c27426db9caf7a3665a53888e271a000fdc8bcd58ddf9ce92b55104f1821d55eda1f4bc2a0ecef12803aba12dc730e692de3d517aa1527fc7ebd0a951559e406a20c2f2a901812cca2c4cd", "d049fad33a5de3fa9695b23ad87bec22711da49e45f6a4694dafbc0ccaca7d49aa9ab74f8fe36cbeaa27f04a854c40ff48d444ff869750664c7790c9da3ec141e4a2a6a592fe31c1d6ea40fadce697d77aba435500bd381c9ea2e7067ed409ca9d45add3b60a8018f24c57cb4418e24cfd76129109668fd4a299fc19606966f7a21fd876bf1e73dfc9b390863dd67d9fb3961060cf37", "1", .Okay}, + {.Gcd, "bf2578d2a9c35116fe6a2bfc838c20f282ee9e290b33261fc8f234725a3a4780f0631fe0149bad4d2c323d051b71d884ca839fb7f56a08f5e1cc81dd2161a21edd54c80df972d29ba2915cd43248382f442cc6b8161d670462d494a38fd04a34f0d8c7a0f54500db8bb85e6ece865a75b1bbf946a2ac1dc63a894d16c4d12ee73821551d2d9fc60f633953cd0489d690378882468e72", "b0bb2e20682d55d10c82e06e7efc96f8479b3828e053ca798a0036deb1b4169139d67889a53d98bf9e87c2fe252dc8332a2875c22130369f196439f9795a0585bd7724c6eb0b0b1be88fb4395a7cf3541a22edcf7efb3bf47e263f277aa801bebb2776fbf446158e1af8f2b5e3ee3b6be4e23b872c95353ac4fc5a1da0254c74c38bdbe7167fd9f38c937b4bfd7f5849da30053fe73f", "7", .Okay}, + {.Gcd, "-662132bb018df2007ee1620c7f3df2045a92a1b8a564ca39fde90d0aa75670f821bef9d91de6efe1b3423716aec9adbf2ecd2080a6274120b263a4ac91b78f8e258673cbb95aada35483691138f412643a2108e204d4b89550eb671b3e6abef2110d625fe534fd457e5f9df1abedab92496502b18d0f31d53d35f864cab9ae417ba34fa327d0e377a16dcc56046fac68ead9aade3af9", "f56c4fb6a7af7d72e538bef7418f6d5f2081d3991928bb67bd6d42e0cdb247d7f9cc8db0687f242308846e6036b92ed0e1d3fd124568862f5b6825be950d66d9536c9bb3f151581a130f5c28a2f40dd3bfb76f7f2618de0b2dd63354d91acb389a12a0c6a9a3521c4fcf4adab028a1e647fb72a526e581f6e10ad32a01fa6c6aac45bffd9cdd8166b98303de33be0ed4c0357d66fed4", "7", .Okay}, + {.Gcd, "-4a2e6400f62075fd351cff30ebf58b7bb80d22d74a43b61ff451030ed902373eed72120313d7e636baadffa0bace3344449c4d265f1bc7451dd37fee71f5b8095b98f824f9096884f2f8e4667b44cc75351fba0ae46766650c482189429aecb42c79af8469389dcd10135730498165733f3e336615ceffa09add63c36efee942faaf22f330f56f853dc026d907fb44317251d69a96df", "2f5a64debdd829f0e1b9e2712fb6c94841a56bc29e2ea402ddc0a5c688c43aa40b07536a18458075e9ff48e08714459b6446d422601228f37b2a387b6e817ebdad5a5f30bca860ac60ad1a945adbd3e49a9c3bcbc1df8ac39e174af676487a47d25287be98eaadb22ae68f8a15bf090cbc0a7a79f7521a68bb2ebc239304770f30e2c7291e1168a45838f8c4b2c545159d6e1a2d396", "1", .Okay}, + {.Gcd, "-1ad752ec95c86ce1847d7d5efb362842d55b01e8b83f4e6eda06403d616eadc4a5e3edaa8a61557a5b526ac8a1388be61c29853cba2003fb092e28218280c74531b9e4bd01db8cf7c05ec5c71b91a777c2c6a94c523bfee5a4a8ea9265759ea49e2c1e2e05cbd31db0ba638e66602f29307440adcd42060856038292bc21743711f0a639de4a2ce69c7873f2f92710f26b0cd7c16d46", "83f484582d808a716cb6ad09eb3616b7c9fc866cff964773309e651044160aef3a59a828768c86dd8bebe86e481451a7904b985d67c59f933c350ac4a5fad05aa4b003372f36e3a816cfec9b51bfdd5dcc2725ee72dce679d378d14a08fe761922d5b4e8cd464ff0ff467a2e13eac466c3be5fb8d3f6dd34f53f971691779f40225f1e48aa04babd818ebb63a0d706b4f2da179f87d9", "1", .Okay}, + {.Gcd, "54d58cb61d64c13d101be2beb8d128c8a38df8e87e7ae72b670803ec7cdef0947e37106fa8088e61776fe74e7cbc0f93ce20abf3fb66f44e35b4d14666c2dc0470e593e2ed118c4555c60aefb46b5112f54b8381f6eeee32ee5175613e0a41d565b7adcef3758c4788b31e4312a63f31a45965d88a8d4cffcc8bf052bff885dccc32eece7c98b61ff51ac14c775f55061202dc92a2e5", "88d6c2bc186c96baa73c932fc2126e1b72db4921644dc7600b619f9adf082c78fbdc3865536dbcde16eccf82e71bde968371e94d202c5a22ec155a510b1ecc17107629f80873cb5cab002d17a08bb0c56a0f1ccfa594d79feb96cd7ec425b249cd7fe05069c820d41d5e93477a11e85d949ba827decdb810b7c5a8d62691fced4fbb03f2ea4e7d54fd06b720a508c9cd902f400eb31e", "1", .Okay}, + {.Gcd, "-38e584d52447f6cfd6b31f520974a52837dcbb9f70de88119cf9e5cbe2b8f495a3a74cc6502a8516b2f041bfe17fdae50cb3b6b4a8aa7db5a6ff708c22e8a1fb9cbc0ebcffd68dc35389de66dfcaf1233663477fc58b1fd5a0b5d2d93668a675803f11fa2b43e117a19a10cd9f509304e1e8514b236114d5b88d24b163ff2d6ed0f1a44eebb5a895ef58b1e74d4203816c651254a797", "770f8e7204634841ebd6e4f069de66463859f52027d0d6d1410a29624b0ba85721bfd8e8a2d9a52dc7d3288f318e3d3b2c0cbf1a900fa874af6eae250588dcc3f10dc056967c66ec6e97543399b299b1b9f0f71051c7e84134e45eeb58ec91989514738132ee70bdcc72a768b26db15e398cc20801e85809c99c5e0dfb5894cbe39e78c3bd462fbfcab847b4409866de65c4543aecc1", "1", .Okay}, + {.Gcd, "-e8df61c12115a1cdf860d6195c9515d115bcf532ab9201c48afb3b62088da6d3ee5f179da588372556a92dc933703ca787e4beab4b4abf7a1a3e1e03f4f6822c3556e6e2363c545d2ce051c19a6e2ec59c80052b4496f9f3d9e56e16f125dab62567c738066b7eeee66dcc95cbb608393b9734a3275d679375e005d248e6a1e9a97f8eb532fc5f92a39e5c4ae0657252055caf5f7552", "dfb5fe60cb769a0992c0c3c1309b607bcb4096af05f1e22b0964bca91c84f9268e814719094daf735cc441d3d1d398e2069b0b39496ce81423f45dbd559b11dda52172600e52c7982f860947cbab714e02b58dddbe7c76d864157d9312627c00f7b9ced748039676aaf829f53a098d84f5e1bb5648e1fc020f63ff2898286de8b507b8557401e1e9e646b8b35f1dff06f8eb0f408e60", "2", .Okay}, + {.Gcd, "-6772861f5769c2bc8c22e76d2f0b8694a62e521ef8299b6bd2230dbbb539fcb95bbaca62bb9aa9996399bc2f9d96cf0adc9bd3b13105295c1266eee6a25ce5e3aa919a7cd2302c82864fccd5337491cccc768d4c51682e9568e39b7d7e86e1882417f0ea2edfe539b6c520a9c8c962fbaf3ffb31c4d1fb720fd8234e01a9f069346a9edcbd94bbc0676861f8d229973b4d9925f29191", "16cdbd2766d56ec89869371bfdb8d65b951418e84df8c6e20ec8e4ae6b655e68a5927809f29bc93cb01a9e7829a94b888634db0ffcb49990afd67527566434dc0e6ac8ef7638b3564385d7b054723ba82e0485fa689aff57a6d606fb4387639077a06efddab2e72584eaeea6f140e78df8197b72ef9d0c672e2c0f39fb8ef71c831126426a705d7a903f2ca171e9ece2927758b7bf2b", "1", .Okay}, + {.Gcd, "f2d3b137c7d977b90eb113b57013acf4c0abf0e73183ecbdaebdc9be6876f2c075e1b312654a9933b14ece1724e92ae739ccc251081c9a0c607a8ddb452cc07e50e738e4333c97c34ef771feac27c64130ace9b47b6b52e7ba42e34d731f74b1fa6ed7a7c6e363533911e5979f61d2f95629c81fedafb0cd8f4a677814b532b1986899fe265e9805dfe8a9c0f65011979fa8bf9c3bec", "ad707dd4b9320b9863730a1b3a7b93b2d2ece324cbce6ff0e6edcc4ec2f709bc5396984f6ecc21bc3f11d61f4da657c35d02e6013b6ca44e2f60c2da4bdc38dc2301d7b123dcac128502a970697fd795b6b3349f38d8b6999e16fb8668331af94880a1e336ba873d37c5e45b95fe3e9c374caf06cc934de3cff36433e140148001bcad76aa291080adc9e39af4294e72a5cc2e42c7e4", "4", .Okay}, + {.Gcd, "6423e74c8dea39a6429babeab5954c9cdff91d27fd995e51c38889ed46aee1a2ff09e0e60f80b08cf400836a1ac4180aff499f77f33a0a06d159d6b6d48353f0b861c68240f41eabb74a8478978f53e105f8fbe61365696da2b659929698bed6fefe1309b2bbdcebdb5de9cd6da936dadf4cd88caebd1fab74291f4c50a6c8f7fb2781b2607168573e6283af69fbce64e1116c2a8010", "d72fffa7784cd7eac7178ada08ce970c4cf3a84e1323bbe980809a5b682f219396261b9053026b419419332e2d124fc55576e1e2bc3513d6bbb7fd8b762647d54bc1e5b9b9c935c52a50f01a2a89930fa55aa8d90084adf953fea17174a6a4cbeec4aa6a2a6a21d0e06eb6a7af4ca0bdb63f72c5bea337c2a08b29ede240dd2c8d41a0b6d45fc9d67650a049392df395d80b966fc773", "1", .Okay}, + {.Gcd, "20055d0f11850c76a7ad442ce5513ebcfb21fdeddad4eec0fad9fbc16dd61b1ed277d33df6b74a660b77ec78e08b257fcabddbd0f59bf86258957931a5b51b4add9e9adfcefbd996e0ef3119b4e43d6e7541cacb8b2c4e482a7e2b129fc31aada67b0a29399ae9c747b8cb65d434427a8e25c1d0dd8377843d87e85f6ab93d6489f5cdf931b1d551d2cd5a047d9311beb0eb423f9985", "755375b3b1f933348f9558dafc558ba1905958be22de0345b39c2099126a98bddd41522bf12638a8684fc09b7c53296ee22539fd5955ad06f2b6e36e4f37349c9e34200db88833a490eb68281150ca6197c7643013de3afe84ccb38c9d7f61028af35470caa04795f8c940c6ff9d0a061353446c17de89259af143458a6c751d217a1c3798240d39d750bd44d54ecc8102eec730a4f8", "1", .Okay}, + {.Gcd, "-9a24104bf2387a0305ddb3d856078e6cbe18491d3a4e1c811c2aa74da96ec7be4e6508d75208679fb0c6da2372fdb8fecceb92cc065084253ae0479f1d1f7fa962a6f268d0d64fae8e7edaaded6b6e835cfa831132e8230e418e26d1b7345333bb55ea1b8ad6a44b81567ed33fa2aaed87d86e0423467ccb61a03294da8cf31b0bf86ca751821030719d3c628eb5a94acb9ce7a36a34", "a2d847b987ac6e40780ef84e4570d17973f21f6d1da3297ff3bd890a00a53bff31529eeff6339ea131b0d9795bb1950494cf54b67afa7150740ad8e32499b296a5004a266edc050e74381093339be23cfb4bdd070aeb6ea79960b42f0f200bbb49839935b092b15695e0e2b4a6bfd56e84cc95848996aa6f55d551e505203f5615a269cf5460f24b7eb0bce5fbb8e9a55d67cc147f3", "1", .Okay}, + {.Gcd, "-3a67680518dd329ee2def0b0bb9964b59f4cfb1b51011e8f98917407cdd90c1c1f1e4fbd0ee462e6c6b174f5c2ee66f559734f6d9ee8e5f5bfce688afde414c88de9faa9d6a7633a2c535636621cc5153e6de22932e70d89fa79e43a102b4c7509564e85845c6af1b89d321a1c05edf9b82648b2bd694ed0de22e55bd787aea7c4aaf38e9a9453b7b598861e1cbcbd29184045abf5c3", "15ed2f5b1eef7a8f168008b088855f942900a47e9472109ba934ca14d4aa3f78a30faee30b29d937d8a493bca98d93bd6ce6d466d7eeba03a5f0b10a883c5282cdd4e1464b19619e1f031f4a86e6b4659979142024d1d87b3ddd912fe4089e01a7345ccfe5e59b62fcab6ba55f0c0797a4cda6264d9acccc61c36cb65ac8fa5c071118172c422689668f5d19a61bed38b285013081fa", "5", .Okay}, + {.Gcd, "8c970403f46d3db44be296373f6041c8ef2b53d187ff22c7d0957422e4e9ff5528ae930555bddf55609a1595d0edd2841cf9757121b86498ed442a95b9473ee226d2e71a3ce59581cbbdd329f744d116357e53827d8fb59052d4dd930f245ff3a7a0cc3fdfff707c5034aa544320a959a4024b6ecf9ea165f3fdca58e89a92b86288fd84a501aa19672362188ecda827e001a9c2d4", "b7a52ed03ca6378b5e762840b9456536f77ce18f3e8a8dbf6f0651f60e1c654bf3431401584432357245bcee26a9317b08a901e27073e53d37a7b98c00ce99b53d214d8feef55f13e08de8254628b8c2273c3585e482f9c86ec58b06f1552f0e008ac69224fb07c7bbd520877e0109bec7a086ca6c59642055b62abe70bd37a4173ef812b8b97a1fde9fce892843d0d6cd686ae63b7a", "2", .Okay}, + {.Gcd, "6e7eb1b6930538d44df3bb06728596bce5f56f6381e4897b2a7b670433140c25b8977ead36e321737e5fc2469a1cffb24ebb9f6d7c3faae8d142d7e2aa7fd1cff7f33578b57bae39f3e11bc4f787860a8eec720a388083ea9ca315cc0b23d7e6e4b49454090d60ea6924a1671e62611ecdeadd2959f9cc3138394eea6e8a3b3108be06766cb78ae79f84b22f381ab850bb543027ea71", "336d1ed5d79b4b00b3d09c1281478cd6c6a8b74e2022762c8dd6b428f57c1b2316fc157deb5f2e5e242578a420271c315a6a3ed9174ffad71999cbb67ca1be855641cb275766c1ad3a303f55955a9bce9230f1f1cafc0c83f35554b5d514866e27ec5cf1492464bca1eb8c03c3d60167c4805023e0415c4dafb4c1a5e0782461173c853b10539ec6a0410eebe947325eb7284af278e8", "1", .Okay}, + {.Gcd, "38358d84d5dfc2ad33028e1d841bc4978f3534e6fe024c8fe33d23538f3ccc618d8a0348ef0a2db3fb5be6e01b3b8bdf3a3a4c5761864246a3dd3c07c632780af0b23c55ea0b886544c5b0a4164b97ab8e95020bf5269629f315c75fc9c73a55a2cda5c83d928a617775b56a4e43fde67a3feef1dd8356830015ed1295b408f8d12b45c1be73491983848ae0603d7693baf9e5a11004", "d7b1ccd6176c4d5066d004ca88f49dd309d6f5af8d06d35a2a36d5127248a0316613310d8a6836b079e68d6c89bdfc0f4ff8678792ff066f67fcbcf3b966864e54d2899f69e728ada3fd6f1ee2108c4fab47c0c5df0f18461a4cb8ecbf76448e2427f5091fd5bcbf34349398f45964e6433b04abc7406a63cb53b9f00a2f9a1f2915cee1f0091de9440b840a279c47381f22a4d2807e", "2", .Okay}, + {.Gcd, "-5affdd6bc1c60087fa59d941f9bb4a022dc85e66ddd49403528d8ff756ca174b11b0f508905ca90cb70ee422c613ec5935885c2130238b8be87a7a0b3e8b2c3498916d424f5bc7b632197ffa1cd6cd0c03b316987960553d68fbac1b80f6aab2254d05df7bcbe84441d92f86fb0a9d0cfaae06e3c977046033440139c89eaa9b45a2d151bf68178c24c470279722e3bcba44592023d1", "47136ee9582c66053fff488180ceded19c61bcc2df7ecf45d735301f89b785cdb1f9a8a4d8bfe3858dcbf7280e0fe010b5b6e64b423e5fe6fc554d61c65dabf48db30e9a13bb9cdd9f953b9352f560942d4eb95f97a1e8451cc9b46049e145f76510e7f2aa0cee4d8a1cc57f1ef2db6df1d0777bc831fe902daeb789a8087a01d9acb384457d4da6009e156fad30101f3f298f9c6b64", "1", .Okay}, + {.Gcd, "c0e62185123055fd5d8597d68c0a0a57784420188f3143ffa8aab8527a09ce49bc4d31f9720f6beac8ed843a6dccb81fe223caf12c1a98a47bd41e530005937608b86b6443b3055c923adae9b4a0da81538497b69bd344230ba0e1704455f151db552d3da04ab14f031c69d29660f42bc892cdb606381c70089162c80adabbe79d0bbfea0e6ed1cb82e1f40cbda00a991daaeddd7304", "6d52a59d09cb9ba04c2083e581c509e4f3dfa90a4900fca25e07f78a8f866163792e08886dea4546ab171b7afffe0e2f47e2997b8ce69f16f1336373fe31fbde6046bb2beee3c57eb86b788de042d15cd4a58e2da4349764497dae6d8a3ff0d72be6d27639b1d46b083fc25e9a1b58c9419543a3dda590b500a72a98e4d8562467e0a05ceda1d13799a08d203b2fe65ff883671852d5", "1", .Okay}, + {.Gcd, "-91d550a9f870e1624212e77564d0bc21b68568d97b992c2a5ebcd5d4f205d54db266f4ec6b025b2abab73522b71975aa2675d5f61acf2a73baeae05c4d302b47bfd87d556c893c72e8633af03b46afa5e7fb3de165b520ee993967fce7e5aa01d63afac9eee3b5b790ef754ea599f1dfb2066531d1a82b071ba2cf6de5426e3bc69cd6a32397d8367b9b80553364db60fae53f5607f8", "f347d00e7bb247f8f4923ba1c54bec2a665457643555e417e0589781aae853cd9f71aea5115dee69c0d9fcc76c3a13eb9845fa865749c2d661b82f60b042edd7fb71422fad73d6d88d4ea1867cad51e2199f6afbc43a2cae88b135efd231c75c0c490519410b631dc81195fd41f7051ec8774b10b193370c3dc36639106c6052baf93e02ee9580a0f583bace587be5f31ab71d510114", "4", .Okay}, + {.Gcd, "-f02e3e358e5aa318fb104343f660954fd1cab7dc70022026530cec4b8837f297676443f9287bd3eb129d206d0982e0e9d7976870f6b58884cd7dc5016d186f168bc379debdfc270ac7c922aa768627c9a414c8e382f69402d1019a31c18c530bccb4b6808ad869e02a034a33c596f3bfb01aed5f571ffa2194ea2d5098f8e904d244663bee39eed1943162cdf198aaee6c8c9d9e61aa", "88cfe99f2cf0bb80f16581cfc5234f5b85a4eba225863af97cdf8df1e59efc76a76e1f69dae62f1e6c709b376009d7a54125783e04b70c45ca01c48eda3224272ab8035bb206013cdb5aa048cad0b81cf2561d4bc9ca2d37294bafd961f2ebe64dfa3c4cbec1d3c92c796409044ef1b2feab17155e624e6505f10e745657e1b3ccb7dbc1bb35a5115005bd03fa89aa74bbeea50c3096", "2", .Okay}, + {.Gcd, "-ec9239c0736e61a2716253f532637ca4861388f17e48a7a60460482242ab136812bd6fb6cc01f34d4b3151a1a7f264a5f24a9aeebe835762c920d2a8eb68be31b5ce49ec70afa8cdd0eb7da199d1efbd6c70b76bc4d765605107ea2aa5758db2c2bd8e82fadbfc90d5f09677d9664f1d381a7984a88eedabbe8c546a929c7aa98a26d8b4844ca2897c557bfc407096d47a51432118c8", "c909512355760ed590dd5450ce8897f56cb15841c2684da4ad77ec00881beffdf63b273348dac66a64b3ade4bc998baf64696e3076083b4fdff86d92fc7aacc33452d2848a45e9e7029f24e783ef62b6d871bbfa6c1c32aa973ec269d3b34adab8d1b28873689fa643dbe780a1f0bac2d23d0cf8262a35cdc0f1a19392c4f2c35fcb8af1e5a25fe42f712068aaabb4ddbfaf0e7d2726", "52", .Okay}, + {.Gcd, "-26b016a38d60395c7498d811f0958b55b45763df2ec6ca9ba7388c2ba3cb7f17dcc2bbc2a0d0d734da8428c75893aac7cd5e3f1df70feba2ad13d4e2262b617d18e643fb7c94d25fc16c052805019226c3b8cf7b310d3ed4df9413621b0b4d4cb9a8940f512a0a2cdfdc5e289143ab3788d08075f89dfc8aa2ada7382470fd5ec5fc337585c895e1fd866f7c586c45a85369b6cab2", "6f5c264766fec73698f1ddac334127522a1e1cbfd44c60f33fc7e3432257b7bdc89dd2781ae12517c77f6180ef61c845fa44bab11828be792becb1648289369464062b3fb5aa2bed575f022296f3b568847ad3e72c28719a23d24f30ea892c81385a598068aea4ad76c77b613a2c87da411fd7a40d28f750177f09f735f7c4c5a10ba8a62bcdcabd80a8a52f93b988c9569b1fc12719", "1", .Okay}, + {.Gcd, "-24e5c071d53c0bbbf86074df83fbeb64994dd8fc2f84ac86dc1587d8109174b94863962e09152d2b0adcb2452cdecfa9ce6d8c658d0cf3cc21d785fef5138d80ce42a9e12659d72c5f0cda0e9de0f06153df4548f95ceedf591fc439b5fc694260d087f3898a70d0b3a40fd302e6cfb94d54fa218d18664ec65b67951307283e25005eec695e37407c50ce3bb0f2486ace0a508091f4", "a217def39c23488d06208f63303aa22c8c1203e8b828ae5a87eb97c1e32b49b21134a9d3aed896a6ec03ad4b9fe7178f12585eb00a8599c93f99fa78b8c974351e6be2751ef9473b5c9f373a25fb4ba462448498381319acbeebbd19f539dcecfd42d6f974f5e7c02267cef95ede13a14684eb320506dd669f3883e39a8077e17484efb3aaf81bbeff21dfd3d85bdc65553993819878", "4", .Okay}, + {.Gcd, "-77b5d609c5a2e531ded5fed6fa58d0dc452df9c529bfd00418f0b6d62d9b15adb4388eb8354f94105eda351aaa47a259cd682a35e6b6c69ae3b390657beb0a8409d3c5edb8350a645c306d4395102fb787bacd2a9efcfe660bdfddcf3531440074fbff406536cedfcfdf168c880acd58c5c2ee663c69b4ba42376303eb3a3fde4feb08b34a6a5bbd0e19cb06b09df4150b3a652cd9c4", "249fff44e785b8beaa064e76109971ef4303d2b6791147eddace2de282273f1e52f50a45fbe1141afa74c66c8775a06fe7b37e1a44e59782fb9c7875a5124dedd077a12bfdc59131deac2d96569f8c81f76febb82dbcb8e9c06943c48f675658dd64f17c7dd23834106c93a7529540c845a9d534e76b3003a10ac5d15e1dfd9748d36d240b82bb0bed3692cd252ec70da750a9b5d86f", "1", .Okay}, + {.Gcd, "-ae3d6da3796ff86efa1895c85fce9c805c78044dd4d1365f80c4d9a872717c3bc8b5ca3b9973dc13cbfcdeafd08c301820ab54cddfd2c2239d2aeb0085f40645164c29d0b1c697e73ce4237687b76462dfa6ec15b6a44f8b4a1ef388b0d77b763880eb8c1d5da9791ec8fe14580700a4e27a8ced53a0e05024af6ad033d2640fdb046662bc15c1fedcc49a9be2c0347308458101dd74", "b296e134857f88b94b1115c58f9ca3257e7907f2ee60dba976dcf09a33bb3c08bc510b2146d765fd94f72aec23f1889c982eef506f360e70a26079ed32a0261b93dafa19296464cacc62749c022330dd415af83f0e7ec0cec27d4b398b8f41e24a63d294d57610dd7d19519438a5e7a22418f254f2ffca32058afb172bd01adc00a7872e96d1fa9535634862d54a965de62d3cecc68", "4", .Okay}, + {.Gcd, "-df6e99c23ec21047f1f7096c2186bdec94afdbe5994863124b4537862212df1b631725e2701d4138cdca6fb37e230e110a2ce882a19240cb31c45d6c33a980eedf776fb56f0911b06a294c9f4c1620d5f4f036db059bd5dc9f9338a74c29723617cd00dbba0869c14a93f6848e99ea8e494679b12f3aca16cfc144636bb0fc1f5bbab6a7c95fc2cb1bf50f638733260717e7447fa771", "69fe9cd5385605942d4e638b1d9c214ddaa6785bc7488ccb31888d37b585c620a2bee3fae06106568a1db7c6cd0cf16a21edfba538af027bab79737f6873f65a909133e3a7f51803d0ea4d46810cd3a126d0a6625e29661971a55df642ee72eed75566eb327510cc395706420379ded0a69a134400159bc9eafed65937948a5ebc084c11721d915a3c3848b2f0370416914028453ed", "1", .Okay}, + {.Gcd, "-e6960172ebbac0a9f7fffbdab3d230b2d91104eef3d04210e36ac2c33957dcd4785347f41a35ff20d052b885e1fe420b4b2adfa123beb48ee85f19772b3dd663156a7c3a90c51a1dce59554d871209eeefcfe74c1ee2429fa35028fb85128fb39ac7a5c64490999ee60e47159f01c1a3d04946817c714aded6cc2b1464e54a1d0e0b59ed86b5098bd5715c48fabdf4f90fab11de52f5", "6506ba04035bb0b4c0d627d0db7b365e17f497d5c5270d2150ffb68f7344cc6975b7aa27fdbcd8ab14e6c6abf480ef6e2ae41768a506275727543fd8f508278cd97a36518bac5d5bb5fe48195290ac764c0f947c2553c9bf0e8c213019d37a5d653d7de67a7a6dac4abf7f9a5b65dd4e7ab351efbfc602539ae7f4ec30c8d919059cd594d5394a5178c9e14acfbe8f570df53f4e1193", "1", .Okay}, + {.Gcd, "-42759fc85224f2c0888bdfbff5009a6fa497cfbbf23f8bb310d075703666394880bfbc8ab81ba231a172a9625a0ec8678e8702235f8540f7be6b17fae8b5c514fa0a34e6a6664c4b6a4ee6e34e462d70b54d99e1b0a475983d98e2b917662a3cf9e2783a8112d312fe278a2de024ec05900ad73c079b6a649c3dabca57abe88553ad364206cfd06c31f0afcad66e186b980ca8d14507", "74cd487ebb25ae8bfd06d634729df459c968e131a02b87fd6d78e2fe46f1c19c4f14ab61d1959d2f95a449110b0b412b80c963b63188e3915f8b94f784c96ed943a948819338adc06fd45d45aa6ea92aa701f10034e210008562dbc79bda46b3034dcedf041a669f942540ab85f5b24bb701af48ff51d64b13fa744e656d2c635b68b0d953d6f665bc8c82dd6a8c900cd6b88732d315", "1", .Okay}, + {.Gcd, "-ef9a7fcf2912e28760bc5e94068b406fcf9b2105ccd4a4757e42c352c7a5e8a1b2207ae1eb6b51767cb80ec559bc6fc6bb9ae225f665ab7334429b4cb769d4667d0afb2c0a297734db4c4f8b094ac12923a73901b13e05fd32d6dbaaf8fd98e700828638200dc64e4f937846135bea364b908385837f60dbb1f67213f482a88649e9e93a10b52f834037870b10a0f177942603b7315b", "39df2553970a143cdb14dc3dc0988405f05505414f8946f044bf9c987d6830576beceac4c1c242951e52e6bc40920a6d7909fb72d8c6f70cc148b44f202edba836f4beddf70d95f70d1eb1f9a9eb91e6a9f1e2f2b3a6ff984c2cb8776c154284d87d2a9c3992578b729d78c56997770f34d1890c713c58628d46fa5d7a574180438b6d163e8a2a691f2f6663af8402e3e1c7ff52a007", "1", .Okay}, + {.Gcd, "7e0976f4a2c7aea57d024c3ce0a1b7d9b85f40a490a54d96c2182e59c6d250d880c6102a0df715d94aacdc37a0f0d8017020b6f8877d2ba3f4c1d832a5a0d10e13fad4bbdc17ac1acca0bf5350d3e4e12eb248ea110d0644204dfd03d5477d3bbe1e182c68c16902b52d1a73a9a7bcb9758b16dd26476771f7a0b40f270cb564ec6e7a315d0eef2bc8433d0937eac455a5476effb96c", "94cc98f3e2ea5ace5ce7b5b441155230fdd882a9bf813abb1983fd9d2f768f6ac47976aefb63e897f28d967e984c6cbbc8d832c037038da5c35434f5262fd4a59dc2f4b5527e4399e90fe31036eff2fe180873893240bcd52fdf2df779426fa70da8c428c1215cb2b6071c7bdda3c73ac2db75d91b975b7c992f9e436a1fa1e495049fd874839d97ad4377de60e19a8fbbaabd9d668d", "1", .Okay}, + {.Gcd, "-e9d144e63fa87830747e5f3538f7283f772692f13922e946a127bf7c90df6337722c97fffdb98897db7b8685bdf64daa7d51577f5f6a63bc298cac0f936cd41ed372ad543be3e8bf9229e5be81516582a0f98cd3dd3c24d91dc1dfa7a7e361e6d710e2463988855bdc3d380eab17158060b5f8ff206b1d85a86228af9aad935662fccbc89b266c7d50e01b49a97f50f444386b151e92", "4e8f43e5b2180378c1fbda6517b2461d066370992731fe23ecb801359d6060c3473275ea2a9e0e15ac39fae48dce822fe053bdb189c6a00737c2d80504f10fb6954c1593dea1db48b6b8b8893c4804aafe9fef3969b0487ffeb4000e2f139ddd1de0dedae6794f5b0b98af4ce31275350de3aa4bb783a4d7952962f4957217c024d61ff9fc8b9069a45daac4f7be525d835fc20da135", "1", .Okay}, + {.Gcd, "-b64e6f214a8792981dd2e583dc4dd8519cafc5f989e0175734656c240cbb16b5f4fc714fe866aff701a9374cc9bfcf9f0638308d17522427c13f93424849cb99e169b5ffcd001131ada96eb02fb94c009866fbcb5a79904bdb64dc3200ba0476890acabdeaddbe4049010095cfb8c5e5619ec40df3558c5313e7c905de3ba5abe0438f00a55e451345f7dc28b474cc09f15d6cea5402", "69108a0934fa0b387e5cd5ff148cc83a99b2026eef701746de4529020559ff47e0e1949c6b7d4ec2bc0b8c9902090fec7d16cc4b2ca8b2414c33dac04b9afd220ca4294c47ac4978acda9de6b129a8c40572f4393c530f45eeb7d0b9ab146d45a8e71199cfdca6694a804cc53af0cebb2d6d64ea6139f6e2a9c5b01a1672f116df7e72992866989217c8c5d4f72de88348e7f27a0eda", "e", .Okay}, + {.Gcd, "-da5f644924dc0e9b9fd224e78ecf349304ed4aeb23120c8275f8b8d8d7fa191c96388a7ad058380311e40826253db32c81383c9d8f1fad1aa74c0861ce47fcdca4be954bd87e4d29c2f788be6bd7a3ce44553f91fb1a5ebba23ee82e9715804b8ffc6ae08aa66027d13e7208bc02b8e569436fd55cf6a3a45616c341c3b18631a567492c6c3e553c316d14ac9d470a7cffe27092d97", "c9ec35266aa8e019da7600bd4d97067ea98e858d547bfad32db3a19c81d611dc4d31ee4c98989c879aef82c601fe68337c492c20dd82fb8ff2d47ef3e61d1c1c286d954869d7ab88c57faa7b2777b01cefeb88caed013f0108624e7a17c3420d5852ccbdb0b324c23dff02d9974f2feb856e0ee82ae6e3af39e9b31856e3b35a808f06d72edadb68083378956efb77d28ab5cceb49ea", "3", .Okay}, + {.Gcd, "-d0b7d4397f7f48ff0b9386afeeba7c6ba5f7cec57eec110de1de70ab9029e860d865b6aae3361cac8deceb916d273d0ca13cef8b66542e4a91ef32c353b335eb9ea6468d0dcfcf5b678f1dc29c07e6a8c41e97de10e0b3579d66ddc61f6a0c7470c9623054c804c92ac97dc5ad8b559702da0b30e3dfa240a899f1160c3cb46bc148023ff7ba4fbe9049233f51f78aeabc79fe60b7cf", "3f8a8618de09b02f410e69122d94c640cf5d45299994aac120aeaea0cdb58acb48834c195bb9e3560e0401a617bed6fe52bf3513917000aad601435d467a34566456f600ae5bd28abec600ff618ff04b4b74b3860f48cc78305f172f63d7568abf8068191601eb0139f3a5392a9bdaf69a1c8ae86925378969531b89e56db4d95f10742f26b2249c9ade305912c79315f4d5f2e76d33", "1", .Okay}, + {.Gcd, "-88ea1f6d345affc93f1c9f85eadf20bee418688684ff3f13bb60641ab582f161e6c6c32676b47b9d513291c71b5b814726f0de5121fb012361a492d5a8411cbed8dbc119defe864a76af34c4fb462e84f7aaa04c13dbbefb4b7335e162ae1751891d6fc2c9ace7dd09ef2a27aaccd0198d88609475b9c3c98f1adbe4d202a3d92933329840d1c5a0f029f9bb6c4119c7400b914fe397", "60bd8d978ac1b50c5f8474dca929be52ffcf76b89b70ef60e40085f8939163ffc2a77b1cbd71cc322d29de08aa4d0f74d690413f2f832dd757212d3f358b4487849faebbc1ef15e05fdb96012209e59c4b669a792fc540d54e7f1c452bf50fdd39029649b83009a75c5cfd430b173f1b801720c2fda94519fa3b1ee8930a55643d09ce3f6bb57f94cb479fdfda250fc121f47b93778c", "9", .Okay}, + {.Gcd, "-41d6118d55d0163e413f98e820347f2d627a27188523d7485dabf4e7581467fa69b7e8c3245a9d6c26b95856c080bc193c716d21f6a0cfc4a64ddf9956b35fb75433f5515c03de1c1b75aa12d45fe94939877d0400845f522916048ff608f3a346294fd002be1dd6cf87ea331d133a195e60b520b0fdc3633c84faf5a75165c5aecae09c3662a29be7079979478fb9dbb30fdc947abe", "331781eb63b3b92ca404faa5e80a9f2f948358accf0192c6b041602982845f73438874b855e6d40f121bc97ec73b28d178a3d2da8f410a607e7d7bca56a0d36d99c2a836b9db2daef155984eae905e58cb19be0f9c4498f28e83cd116d73e06b12312a1cdf8d2ecf94fcb6334ac471c14077b50b5d5ca269f44947472289f692c91f5337141bf092cfca8b2e8691d756a4a6a3bbc46f", "1", .Okay}, + {.Gcd, "d1ebbb18b09222b01babea5a2062d3ed3344b9fb23aecc5ac7bf301963184e7748843d63cb87b02b37ba6f8bb72aadcc0137747afd1500337708346c8ae83481fcd30d3a6c273e4c86e01e0c4c7433071bad28ea596e101797678e3c9de5b34f3c1bccb6ed9556929faaad96f89bdb267f20c17fcd03d03d067a48c961fd2ba2492fdc32435d639db2094dd68773742ead251fe59ff3", "7a732bab648f084db0447f8bd7d9bc5a4e7d84d1dab234b466cfeff516430f96fe3412f08442f4583cc6e7eee52e8060ebd27782cb2620e79032326461d66e15b3d1dc753c721b15b8e75c223c866b82db7c6f1170dbfcb8484933211ab9e022f3b3b36965c4becd8507ee5f819050ce892512cbd5eeb11316e526a407996bb5e9a67cd5b0fa2aeebddd1c20e2081bdfb9c047b53acf", "3", .Okay}, + {.Gcd, "67c853c2bb418782bdd8657f159fe50f1f85135741b7150e4b7f662005b34124e40b9e675d26811509afd8f3a435f81cc06aee3aa6634223698a8cc3938f919ae551c84a8f4569f2a5ca15a5065e6d8073a27bf870cf58e9c2b3e164525d42ccf568fc3107e590bf02ae4d6f5aae04b6caa637c6aaf8fee1b821d74c4b6447cd7f66184ce6135c92248df5e0f312fa0c9d0465d994b6", "2bc5972ee5c7f8f2b97bfdf228fdb566a1e343251e252a1f792274022f7d9a3289e91dee9236378ea718645b73e849672d284554801532d267fd6a8578039fdc525dda80e869d08c5feebc0a441e99594b757bd5eb100fc94ba4392acb34b3f788e2ce4a3b68ece660afae12ce8bdb1f5867d4f41bd90df083e160b29e8faa2edbabfbd033e212321a198bf002979bc6ed5a48dbac2d", "1", .Okay}, + {.Gcd, "-45516f004286392cb20e560fbccf176e9831935f4c6fd16bb52b2b24e94e3b6af1ba3a844e7cdc4205f6adb44fe46a96e6ba4d01f0c01dc7f906df46f3738aa5540e8bdc88df2449e6258029d8c5d55789b06c6ecec17e1e20c4be71f4751f4189396ede4a8b3bcc158b04776e3857236d6139b6739e2c7680d398a50bd318cdace0fab947b7de2ae17195e7bf12c2b53efc91f060ca", "e1891c848d54b88655248ae02b006b41a76967b56d10d46dcdb063f1c1c6c8cc66b030f3fe45f790e935e286157e8053ab3503e32248c0a5d278e6b313084330632a88f53a7552014447334546edf339b5c66c6c04844f00c33ae16821dde6a2ff30e9a85acb2726a7f6cb89981e25c97f453143dd96dd9cfd691ba16b0ff42c5625d896d0606bb9939a8072d940d801697f1fc8e72e", "2", .Okay}, + {.Gcd, "5c9d66b33166d7774e953d31c595de7fc574efda7c2709701afdfdbdeca36e80af77cec7106ab413875cf4c264c251e44602c23ecedc5c10c06996b496f3dfea35da43525a1b72d8ed76782284845d786cc21262b319fb06c6cc3d0aada6832ed47cb7a6a9ed40f7b1614c7e3b456c4dcfb2e25e49761fcb6b278f0ac9d08827d219ee19d0c05713d642644f6a3e753f5356ff1609ca", "2d812fba37c7ea58c31c84434c9e1b02d1f8677e02271ff5556be577fcbe06571db93dab5f1c2dafca2a986f0478ca2847a6cb05cc1ab301c1bcd02d09b733bb0d14b65bcc5b8c3a39939b0ea23e08e530266a2e6911313517cd77e7c546509c12cd424f954e2cc8c34b718e86e9ecd54841cb755359216239883978f3855b260fedcdf0afe1d0f9920d06818b5810c4da855aa2a80b", "1", .Okay}, + {.Gcd, "606adc5a09127b345fae9a7ed3251660ebe52a0c5952f51bd47fe8f1c19569626d6db398f77a0176cc144819228160c91f8562556172e0a2ee67da0d0005059f9df8d825b8d5625ed2e82a1e13cbe3ccb08a5ba06d6a4f27f26100794ac70224eb28ab481f3dbf1de8009012f521d2795ddd4228571d8194a43c5489772ce66702ddf2e99a02ff9d8efb6ab33799035b7a7afe580ab0", "bde048076eb734cad46e805af2875dfae51269f87b3c41841076af0a7723e799f8c9879b788f71f11845c3cd618c6d795794110620549cfd3526c91a45421c4ab8b14948306aa0f3a69ccf5c5818c58c9728d3e307a8b6090c2c72d538fbea95f4b3525d90c7b67b5dbee20168e20b33710a62cd17a3318c6fc2c3ddbc51209ae24e8fcb243fe1eaaf584a347f1bd21a66b69d574484", "24", .Okay}, + {.Gcd, "787f34b185d5a8e8a3452118747a9aed270fa57c7ce22835184ed72c9eb444e64c86c6fb97aec0c4a234a5ad1a956d125cddb6a5317a2cf75cb5669177ec954288d68590905496dd3e1939dc9ec6a5622c6ddbb0bea8766a52895c35d85ce29449b5f1f85c4869eb9dda604c2044e8ce9b4b65bb4e2f460c1b72e661ac5599cab7b98a29f9707aeb2ab9d0145aa2b1547546dee9751d", "d89016c82e2d8749f78e3a11452c3314c548ee65e930334fac8cb6e431babb6ac73e8bd34f89a5d3d94f3786282e843ef0cfd6f8f24ec252bfab4f680c5e4763c0718a020110c7a2991ca471629fbfb77c648abc7bfadffe5527b0493f0daf4264a88e9a36257c43e3f85c54c5a39c7716f2136ab408324763f65bfeb8a54b81657f324011ba2e8b2c62f031c1bb4e65d8329a53634a", "1", .Okay}, + {.Gcd, "-e37f059e54591aa59baf9397da0852018261e912de17b24c50391d23b9cf4252afb7528e21880d8d5bcde9946fae95cf8c1956a87e53bfa68178465a0b89646af33658991acf175f4ccbdd2ba985d76fd8ca444b16d91f6bfed938e08abf6eeb2a76d59a31710f6f0931b1fbd55bbbab4c77693c2fe058f09ceabf14f03d00be10fc1b16a236a99d52560565a298edd703c76ad91d11", "4352441e894e13489fa32e99db47ad2bdd743e52a2b1845c33062b5069327f078eac20ac7a4b5ce79010be6b9894839a458ec6932e8190b94ee1d7e476ddbae24bcbee6e0e063d53bf00fd0bf8f76ec4bad322974538d629845da0ac570de94b52a6e181444b5d3f98652c73b2416f10279821134a2d4e3604f4671ad045dae58591d8f4bd7b84f60761894b89be18cd4b18d804765b", "1", .Okay}, + {.Gcd, "bdc028bf20f2c96c550ba10df8f32e73bd9efdb9c4bad45f4c05fe37cebafedef01cac32bcf6a12b4b1f46ad3b26d05c75475ed16ff62836c7ff7038d1ba08b868b61a2de005d50606f4f94b2ac03a12ab910d096f4cc4467080a64fc1751a507447e6ed017b6a30dc950aa5efdfaa92b7341acb28e46137829af5aff0ab46e3bbfbe8a9af503d06c243cc6ff8bc60d1451145089707", "ff7d57e6c7be01949f0985f76560d36101e3e46f422d8223e8f7ed251f81f538772a31c9ea7e2e888bbae4359198d267bc945f3adaa2372a99a49a4f855702adfd7b50971f8883467bd55de15149fb6d47e37d7752de8e4aa817e1f50bce8d42138947072d6a72235bfd48de612b27621351be8eaa30ab18c142ba588a8e44a88fb5580c8cca64a21b8fa2043c28f8e3006d2b06eca5", "1", .Okay}, + {.Gcd, "d6567e025db029aa7af668991440fc19aabb0eb02dca791c553577e1e54369e5c6c8e4840eeaf12fa9f937eef87e9d96137102a5d775a83e1c284577b0d4861f0993df36686319b08de2a1eaf2d8c5c2ef90c58ede5d7fc6c0bdf592d3106c56c521cc433f199651f383aa0f323a6b7e42c8af12f49b01724a0bf9f4d836e1082bbabf0ae3bab00e6455ff4d31268548eb9d391261bc", "fed2ab619a10c19381f8d0ea8df264acb7d276289d5c3ec9943dd68bd5154241d2ff20f13cf7053a505b14805dfa87b7c8c8bd6b424dfe6d7c916e2b218c3f230b9f32e00d86033f51cea1fd18997bf29907f91a7eebda414629f485c2fe6af0c805ee75144d065943c1d795ec8b9e6843a89cda310fc92d28b972f18b0c11bc18d9a25888c9982f07e030825ac1dfb9d7efa37e3ae9", "1d", .Okay}, + {.Gcd, "-7bf2ba320678f2921f07e1688c25582278d0bbba2e9412b3474c3984604c82cff75baa3c14aa675012c0f9352d23c3a9cfed1f7aa35363533e024279dd692c2059ec637d3f93f8efa762adacc9d49b56c866baeb4561cfe8e2413a086cf092509da1b9c4d5dfe3b32d0569a5f8b7dd1102d190fd2c7f5e685c3913daf5226edf4f28fcba6b1c0b71764d2ef445f9e0e1c132721a65a8", "163155cced17bc605ce2751a6a88d1ed5c8e49b7c82f6e86009c289f6e2c0d53dfc91640354fc7ec4d54122d5f20cd3f0182265b7ea727cdb06f3a4a01fbdc6bfffba6555f66a1c6424bbc9d32bf05b142341fd9d9dc795cc711c1eac28558ad26afcfaa0cf49969146bed6cac81f8cbcf3ad658391fbfc06468963e3d6ea3ccdc8c8d3de9bdbd86af3c1d354a64cd33bd0feefd348e", "2", .Okay}, + {.Gcd, "dae58c4c89a385a16b7f85085577df7ef456690bc704bc4d7733bbd6f65869d426473b0b90d97b6d6249f727e0dfc8788994854a0fc57de9f2ccadca44059f0cb26efdbbc9992125fc1a8528f3e073c4806572a8c781df74762868f5a3a0bf88583b275b3fdb4171732bea620903fc4de68926a2ffeb095f4851169c180d7cbcc4e092ead9fbfd0176db68cb7c5e77eea0e791228d03", "49b94653ef7aa0bad905ee5db4b6b463d63f377553990e0425fa49ea95182372a6a144aadfa75135a9b467a4d94eb6af5702294d38504e067105e623cb9c43199e7459531b7617116ae563a049221771257773d84d66472ed0227c7a6982f694bd6217252d41dbc4f098809f5b6482f892252c190fc25cd21a61696c9684d5a1c81e6868d49af4b522230b837eff34ed444d4f7526ae", "1", .Okay}, + {.Gcd, "b3a848c54186b45321f072339742ac69b5c7dd2842a5b07f201b18fffc0b011bc720318ea2a70888e4039db176d0542437beabc17efb803df2fe92e156508929d1a60f5c885fb6783c379635636deed53b55b02043b5b2b58281269b60be43d506eaa524b1c9c053c363365d042669bf344f7abe59b3fce15592fb44ed35966e5d212ede077c8a51f110c9e75f6182d987ce0cb65d69", "431769b46aaf1c7f34d787ed0d8b4c53a812efa2808c07e3754f42a7dba4e121096419bf275dafd7bc075da9b31bf08330de44b544d058234314bb9aac4d779eb4a1452ff200762d639900e2d660ef6290f8fa3a0c61c3286af6c6a40d10c31fba7d501b4ef899bad61ffb58c5d9916f45338e3ed740e58e913a490695b4b88fdd1f7868c890862de2bd8181502f6cc6b5071749cc88", "1", .Okay}, + {.Gcd, "465383316b54da67fd783ed31ed9e1bc1252c6cb651be41465fcbcf4426cf97dbb0d1de0704bda1daee247e9633071972da7ebdbf391b4305e5bf8dd5d3fcd8de6539580f5574b05fca64a8fcb3fc6cc4463a5b62c848acd9cdc7c038a31c36f15934a5b53474b320fce88fbcd7e0f9a2aa77adad90a87b4abd44941ab17b3971694d6b61f72e639b2351e005e770ad342f726b7eb46", "ac1167998762d6500cdde44bd887d947fbfa9a873f23bde6f3e932ede949b8b4810231cbd01d55aaa06581283e04d159539bd17e9723872fbb236bdc1f3ec96ce2a9a0033ed051bf791545f590d9dad6c13d1e1a0a4d93f213ed0dbeac91e7d7022b3841e6e2f108fa30b224841f52ccb710c450431a1d58567b3a1ffb92fd24769bfbdeaf00cb18d3f1bd6d3454b4f3dbd75b444a02", "e", .Okay}, + {.Gcd, "-9826dd3ff4a2882c8127ebdd5fad16232e48a60ac325dcb8b8328c983a672efa640512e896c11c56a054488f3887eb444b16436b83ed244a768f0853db8eb47b90319e228c1f208c630633306f9428dc82f3ff6933cfa3af2f04bc5faea8a62587b158cd1f572a9d1c19bdc23ef7310603ee0992555c8402f95d1e3e3941feee046a48974f0e1ae09338fd60b7cbbae02b008bcf3ba", "5e8c95debbb83a086235786e757101485aaa3c7e0c9498a8f69c5c64ad0269c5271ccf87d4ec1e41e7819f2f7eb3a111b74116a780c1c4abfb2ff0e5987208dfa28f052665062b964f409d2e5d02b5d6241bb84ba7c38fc38eedc5301eb79628f1baf43308a6dcbe38a287feddaae8a95965e9f5f52a6b12dd8d48e764ad4a369f35d53ed6e94ccb14fdf0bb9476f3f3da2b7f057b02", "1e", .Okay}, + {.Gcd, "ac6e4f0ae1bb79ba7067d4db99a25aeeb91765156c9e5437a3589500f28fa7a9e9dd490b13a27543ad7f536e25af7828c8dc139329709cb4e2df1daad51e6b7f0fe4652a0c2c38860e542696ec1d4e90608c1201a9fd784df8b354439f8e0d8994cc4b1a2180e6263d1375af86388a70b591c684a9a4099a677f0731ff35261ad022dcf0b9f199e70afe74ae22630c08fcbd9b39b2d6", "930ad98fbaef1dfa1e800bbdb2b6dfd08324bc9c51117b3733b689b374bb68ba1c03af8a828c272bdb50b26ba4dc56d947b79f23568f6cb825e12d7fad7d1d682acc4ae3e1cd27a8d247389169849c2f4e63dce488bc2051a8ad8d76dd741ecd28f96da12e194ee5418ca00df9e66a69e4ef0d2337f07d2ad636034e1c5c838d692da64aa8cfddc25629bd56863639f74aef852d87bf", "1", .Okay}, + {.Gcd, "8c51aa8a5b423e5f9a55b4047cfdfaa4ba036a27180de4590b5042ee6bed9ffb61ffc26dbe235287962b9c1844c106b686947641f9cd021f117acf64e519d836b05be9cbfa575c1babd4a47d0a3609b9e5df381d255abf68c05a4dc00f0e9b28d98c7a8e8b3791580a3c233fd8446e482327e3a5f5110c49f171dbd270744a2855c0699259642e5e9b3d6920fd27f055914d0b201cf5", "e6a1db7647c3a28e7d1e70e45ce90d7459b2922fab803eb28e3b22dd514f4e3373f996046081c6222e0dcec52f0792c855a262c19a6edee6b330bf32644b53b60508b84be72a175cb97f8f0c10c97b41b8bb5e0426c0219abd77d41e3e728f826881b92a05b4fba7173962a0273e4969182323fc7d19b21f1758552956bce76e9f2d1629fbd695cf5b496860e69e77747f1a612f92dc", "1", .Okay}, + {.Gcd, "-8edf1d804738cd29d1996ae9a74b4aab48c39b0313fe78e77743fa8817b42b70840cef06cadeb8d628aef2088d8cf7ce275d4b487f2da8cf632c7a3e4cf78f820355d74f7657704f4a1063f4f3acbec856766682d947c95a17075e40a00e71139e9d0c33d2981c9c3f868cb209739e88a365a33940e99581841c48d012e8c1d8f17974d34e365ef3b149a612d7ec3724b0127a54b790", "a4c7305131f4d2254cbf7702e5eec7aa0f90bedd9839b77365c830c80352dc5a84651e5a2e44e9c1b9e5060314d166e8da79113d168e555c7255c4ab148dd5e6ac1246ab364e671d4a6cc51196cf2131d1138c492c6cfcb6ed53d6b65e457ba4d9d06cf1fc5607753a5844a35502d257fbfb89c9543dce6536409f5854881c08d0f2dac3ef075366a1a3859b0e8baf6931e71a3ac352", "2", .Okay}, + {.Gcd, "bd3d75d47ff102093f727bc9292889ae0c837583d76ca2747c0797e24bafc976adfca776d45f6e33d07ffeb3f808f50f044168a91899ad08fcdb5668822410054dfe0e4b1f1e3a0efa6064f5fd89a71840625e83a2d60e34f27b46b70e3391453b646332f2edf8fa93512c0327afe6e3fd1a89bf2a36643cfb988e7d788d477e42127ef9d9c80eeb60283c49691549b61430f438a672", "eedcbec160e660fe38dccaadaa368b66755bbc9210359e8ff033877c9e8efccb03835ba7966a2e2224db9195187a95bc99f0bc64f1127e88153dd11636586b01beea2bb37971d9e7c8b5e887bd1fe9ee780eeefbb366d8884c159e4f2cd062c7fe884054119fc862d82b8dc34c95a22e0403c646b7e3166b78594a91a5d03c1cb696da8b78e9782248c852f7734bc316d6fed725d4c", "6", .Okay}, + {.Gcd, "-75fd9b631b8269dabaad0e88c4fecc4161d7e1182aaee23bab22952659955d6898c3137e17e0bba23c59463c865cffb6077977ccb24f577e29889e059e0287f078ecaef0f8c0dc078dac0f82a14b8de0d21884796a413e0274f9503b406a2ed429d39a5b3f0833ca0d800c4974401eb9e44fbe25c13c90b3e348eecc8ed01e7fec23a63dbad311ff2c1e26de3411b4894cb5bed66ffe", "90656f9fec4a33ef23d1841b376e8374048ee713d2bb034dad58023fabc92428ffc820352b14910c27b242d66eb2980b5d9b50fd22d2b4dbad2900d228e7de0d79e6c1dfaf821d155489e09a32080666f25db7fd5cc2c5861f7bfcbf166abd520215a267fd6d819aa1beb85710c8cb4617b7aa9b0d0dc771204d0c95f76dc65831df4a8fd55aa673300d697cae52bcbdea496c2fdfb2", "2", .Okay}, + {.Gcd, "f96a4e9f613db00d7dde91f3b2cb29eb30fb36e921619596795c92a3d6d321ae538db75dd10544a2527afe5feedb24ba6c206ea864ea0cda54cae4b2ed7abf08ebb57697cc6a50cad040354f15674c4ee241a96589235004b388ce84d0ca53f6cdc6e64a298c7fa586e11969c45e7affc0b22a432a6c48282918951fcdea931b6a8c46ebd20d1962ea91a6e3f65684cd03d98e536021", "950b8d428df5d7b5a6a09503ac3b2845fc4013f582df85e1a3dfc0e176da5dd4c6ae7d5014b3e67ebac606b0808a4677c1d57f29edf143ba9f3ac09f100a2a204e148d79ec32215ef941607a1fe7e2c053e94360d5acef259bb7ec21716c1a8f0f841060660b8b1840e5bfe624f5e7bb40ff4cdc8cf5511460bb2d51faa45dd7784b4b79d9c175404eb652d0e10fa053da83f51495b3", "1", .Okay}, + {.Gcd, "71e9dd8f0668bb70975fae6317bbd143d263368873c54d0dae88cbddd7aea5350fb72b47db17cfa5927627a28d2a1c32ac6864f103e7599ec867151b5a79680ec5211570dd4edd62d1a573d6ea75b83607c9c87310ab5f4d809484d746d1735ced462c4d2e50a5c4a307b760a3e2d0e4a608cd974f7a324274e1674fc69ea7c95b634e911362e63a424a0722c1a19d92fbf60306e3dc", "5a144d1562a4221279bed809f74d6a8ca91df6df345c17b86b56bf885138a7a3822a4c2d4ae084e0368beeb728a41dc7c994b2f6deb872894f13a7d61e262d0552c898e0bbf5a63d427800534e70a6e79dcb47096ca56bdbf252d3a48aa5be498f51c8c54e568d1efd70cf8320acf6bff41bcee68d65d504878f20d4124ab8d79e6924475bb366ad3052f7479bc45d230e058e0a2fc7", "1", .Okay}, + {.Gcd, "b158570294f7f9ba3ef64bc7b346c1658899a30cad76ebce719c38598c04c7d1ea22d03bede5b21a90172dd75ad1a0a89a9aa8184571e3bc2d65ff88d2b93b393fe8d66f395f30b957f4cb43b2b5250613265190b30909b208be68430e8a0cff21b82390cbd9bb96bff3fc4510e1d9cd89323715ade70470b4562718a6cf8a07fad8eed73b979d5b75ae8da22ce335ef41950513252e", "1ab88b08e133278b89c141e5c95ad97f11a767c0a5130a4b2707d3bc6b10b06806949208ef1efc0ebe47a426ca62054feaf9aedb0afd081bdb837f54ff434dfa090185cfea3301942c8f81dea0e7d7ebea229dafa79b1eb39086b43634f625cdee164be008ac8fce94fa5be4ce5baffa5148b5accf319e5ddacc124360052b99451a0b6a569249eda3b086c7f2b0fd5a27cf3ee2be4f", "1", .Okay}, + {.Gcd, "-b9474a4556e0bbb10fb03d7a1c97aa7986a3e17799dbd3423978f551d7e995956b268240602be369f45709c164f1c80a2a3907b99f4ebd1623795b1ffcaa88ceff32dafbeb4b9f060a43d5e4ba16d30f3c361570d50e9ed29a89b61ac18845d1233cce797d48d5b29c6cf62b8df3726eabc01eed77c85908a271ad71a062cd4cf3448d5f9f690e557bb51dd7d3bbd9d1e7cf03049fee", "101fc35abbabd48a4cf404203be0c0bb899ad6191c0e9e276ae4097ee16390271e8089aed382d57060d536060c59ea7477d4340c3c5423202f930e268f64dbb7fc0c10848471e260709f6237cc3084395c15d6dfed3d14d0772f4b912bc9e9809b5b131082c8c84e5a56064c94892fc683f64999c9280d48de409547fa8e2418c4d547814b8ec4994e6ac156dfa3ce0ce60eeec93db4", "2", .Okay}, + {.Gcd, "12537a328fa9fdd0a89033b533eb31a67d1a314595aeffc9c001e0743aa9993a481efbc32f23a9ad3327c52c6fe14dd57e67b2757fbe5609d3f7496cefdaf2c264fb036dbb1758c6be5381e9aaee0aa89040ae0f9ffd1438fa96eb1775a64e5fdf29d4fbb36b1c7ccde799c9ae645b51ba98cc6b5f1dbcb894b084fcf06de175521f6830884b9df467ce25d24f6670fa50b2fb5ecaf4", "be7d869c45da06b90c32d0396dd82184b680a32fa7a9e04c0fe01c5deb9483a08759e61ad79526e259e48517e49b8b0657e4d066ea4a559cf4283e16e0b51a6f5bc6ca88e33e4d6458a6e2bc86393489aae215439759f46eadc654578173d53509f394f0c14ca39bedb0be647cec57ad3026a599c528235bb51ba38cd831ff47a5ce86715c1565b13383f980db2f692edfb77cb82e45", "1", .Okay}, + {.Gcd, "cffcc4212d62d267101c2a60b389f2ce67fd1a4a39445a99a668117878b8bb1ea907aafdce1dc33c393652fa3636c20bffb07950b6d4bcd719bb80d6b964e06fa7d9092980ff71df48d6e2efcdb5a5222a1cb2abb64ce9245e45f89f837407e08fdec1a9b551d1fb5b379209fe39eefae04d69e338d1b1de381c4cd678e9cd3d8ac4006291fa88d60728d8ee2e1dd4ba66426f0f1a23", "d1a07b4605c10a6e6a737104350fdffb8deeaebfd619dac34a0edd5df5821e4737d8a07ec14200694f999de82ab83f9e15cc61d5e86d88459c2c92b45dc1e1155e27f743202d310038e0084ca87f0466c29537af703c9a546f63ff02059e4c2b42876be45f994e224b8e9ef0dbad1436f806c9e19dadacd2f5308cd13afdf344e3d2216731ade957878a6fcbb0672f630eb3ce5ba7c", "1", .Okay}, + {.Gcd, "-71d751ccab13a80bc9f02209fb61b103a2ae6f60cd3a0ede7f396f406b4ce8a6d413fc1c9e37fe43678ec368251fdd63ebe59601e215948570f219f75b644ede5d546103c98c8d42550e1f179acd94bc704fd4d0fe6902c1021da20d9f160dba2fd60767cefaf14740f063be25523456c9c0c2836d27c6b004794e17ae1d52b4337ea40615036f64e05bb4b840c1e0047a0aa6f81aad", "592694a6a7b1f6576fe233397c2b0dcb3a32b52f7035b487b3c39751e74e2f0d5f480eb1f8a5f07ddef95923d64cead6c07d062f8689393ff9a8073d5e176bcd32556a9da7fda105fc96faee7ddc817aa75cf6a7cabce630c7f138dfbb4ac1f697d6b0d517bd12dd9dccdc1c49b87fe4698ea501df99bf275b345fa19100e97693be3d143ff896eed28b3994944cc7d046c0328b8c4a", "1", .Okay}, + {.Gcd, "3a0ee3051eab1a012949c411778252caa789c413d0338ee4f028b9e1d9b49129d307e094c3138e6fc6a01acd75358de164a4fa928d6888e64706f74fb35379616b62543fbae7531603e7c60033f6d24261c1c06085552fbf0aaef13177b71b2862842cf4e4e04d3b7d685b491d35289a4c0fda265876eed11c0d74c2b4bf8b1bd2e2c032b2811bef6a89909b5d539fa4a17d70757c59", "9390640e1f650782dd26fc0065aae8e142cde8b8b6c2c6373e1d2d4fa6de4c941f5f2c738c1d1327238b65260139edeed46cbb003fd3a8d8202581622d05121f91abe3baba6201d88982f822d0d3dd270920197e5b865d24f2710dd4f7513f2892de65d65a6a74fd0f34a92a85fcc9399baaa87bf68582ec23731c823b543a5e45d02af26a97ac7ededf66c1656d736d00e40ee2888c", "3", .Okay}, + {.Gcd, "d3053519435a5d204d9548467d56093ec23e307023211be2d11691821702630fbaadb20f594c96ac3b2dcc2f1959b8640a000ef657d33bb44434d7432aae97d4e7fefbfde9458210e732c17cc7e44cbdd826bbe2662850afbba52f7bfc98d4731c8d1b3be147686f6a9cdf26cafead9fc1c89ec10635d4d828416506ca8a2f255f67d71c75de593d0f9ff1566eaff8722b7c9062c898", "f40b6ad067d6cad8aa47a0558de2d5015e44dffe77547373c18516807893a3c256e102a4b691731686b8e73b4bcfda3d234123efa18b6faeb2c5856ca77e6b4cc0d141df4a4fc244a6dabbf9e5a11fa439e5d0155f59cef51413a5e4a1eaa3bb0e563db35f3bf02bf76502428b067038b6146c94ac1ad4afd9accf3c19053842c2fb73af13fe863f5b59c8971ae9261f3157e40fc15a", "6", .Okay}, + {.Gcd, "ba34edf81c6a88f751f1bfaa9f269f82cd494897c2f5fb8f65cefea7bff964a88476085b8318772a7f93a62ded8794129ed0ae08c32c43fcf136fcfa8d2993c7ac647dfe82fa78a2fd96fac15e1d79d147942668739722b1206665282b07e332b070812538d3bd796e0bd51d7995df14fa17fb87ce2094b022e17805614be581325731c3354be2883fe719c27be13bcda5ee07c2a7b7", "8f7f2b8df82e11660651a137188f9f1b41fcda4e8d6d50976d1cefc87f2d9f534fdfc8c084b8ab08924435fe7cc8e93f511e95565ba87aa150ded73b51cd3987d2fc054b908c3ac2552b73677e66a455700360a3c4488048bd2480676cc63851077b3b9230ab3451f8b6782bfd6c11665291c28aa1a3a0f0b94528cb5fc0ef1506841974b2c22ccbf9f2ebba5bcd2671234324654c20", "1", .Okay}, + {.Gcd, "cdd8a987716341476821d120b82f2f1ce37817403931b4feb66c1eb81efd127d2331d0046701c59c98e43da508043bcb2d2828a5b706399c09e55ad2504332ad908105be85cbb951a6cf24f60852e3393d370ab3f89fd8226138cb1e505e9cbdcfc176a949d0ffc5ddb42134311361b2207069994e86c383e5e27a6684b31dbb7b24b801a4884f32b3d1c5e7f157204257c39819db1e", "7d64a45c0ce3a6b1d7e28c63cc4ed631cbcffe793c005fe1fef7b3bb442eb63256f29eaf64eef3bd276723a49101cfe13859f429f98aad3d40ae50a4f9f17698df9d9b5d416a51e598cd25ae5d2e2f9a5c95af0befa8d28e2205bb7c620fa8c7378758f959a45cc027df2d1e7342a605ebd972c3fb880a730c25f25760b12c5b58cb93089eb882b85db7a655b09f97036c0e7ce41f2c", "2", .Okay}, + {.Gcd, "e910cb52fb5d8ab7b8327bcd248f6cf093454e360481f6795a6e07437ed29b46f9f10cd9fb1dd33d192378711764a55c14fe46c5bff07db42864a28b6ee1758ae797703cf9e8706afa740cc305482b9e1621a5ff42dc402869c4a35d661830dddef1a32e0b6b57ef5a66a9a5f1085b0a351ffe1b541dc96cce6f255ddbc7f04ee03c4867b5597d1f35b7a19d79c2742d1c7ee47ca84c", "38549792c74240720fd1598d1cb1f38631230751012fe0f5434bc48612e83f1d5aaa4ae04e168f79f82eb092cee30737744730655f04c9a8be69c9ec9f08e6a8a377eae824cca7c8ef94a50aa82c8c8aebb4edf43e5dfac8feb8f8d77aa83b1a1b18848d24aa08dec5679a694deefb84a82851823e0b819835b732e5110c479060e98296722ce447e779cd14a51430da2ae64839a9b8", "c", .Okay}, + {.Lcm, "aa41c1e69ad54302aa32a34b37664baa9b77e5e06dd62055b4fc8111db31a6be273a010dfe6bcc0e39274d7d99a03ac706aa34d1b3318f860624c56c52443b7127142d8999ff6a2710f73d2c480b5905ab17ac5e96317309d62a059e7e742314d7067abe531ecf2f0fadea1f2fac8c55c6c899c9bdeeb3db94ee914cf82d7c659877b1a3f5f46637d5f3381dc3548b90295c68e8d532", "-1808477c9d3ecd6fb1c3c16d9407fe0ac59307a763ab83cc9e332cd1effa17a3e6648c4cb98c17876375e3cf060f3144b896e68c82bbd7770ac6ce01fecb57177b814fce8be5fcac6303f2fd5b517a0ca74f202ac64e2e42985fbc25a4a570aefa2d89948799e6491d4cfa926bda14fd6c7440c575f31f91adee76dc3a009216a96ee33d79d79f2d78e97fc3562b1cfbf9be5570f87c", "7fdd5e36576e707685e78f3806d703e9a46deb2d2adafb6a7b935252d6a95af8129df3f8dbe856884a6d20a586913579d3e83527d807949b40960c1715711546d74e1ce4c2c57e99cf4e0adeec5f2b788f3504c9971a669af2685bca1ec03e699e811538059f2fbd012591aabc7962344f3eda782f420b67c74141d6980b5bc0905ce49494f66cfbf7f3ad26eee3c49eb2a084ce6774fd8b74c5b35855b0166fc2e96666f87c625104ac6554bc6caffb61fb1e0de5c6b2fbf7399b483ca5e3f3625afb2a1dc16385399a86d26a3e84d426f67dd8d52e692de34efacfb3a29aa73cbf9d1f2702d01682ec1fefb29c3eb5b29191b35f8818eb6ddc81701c072bedf073e1de6e57e5b0fcef0213b6d99a86d54975dc2a4d626f296c345d962b0e7058b7a4aeead50139f97da1c", .Okay}, + {.Lcm, "92188e73ee62cf9071582e2b631ff5eddc01b0c1536a12b6479b6bb438063f7a927953ff2b74afb89edbf05a8c9fd7cb84696410e57e6fb1a281a065654e27a71c2a566f763d3779899e697c1d72b59243e17933bd522e27bf270456a2da6830ccaabf5d61a7403d638719fce31acd96eda678925a022c3448d6a9d495ab760eca86c294a2c57201ca1953f8a32c1c806a1921c48baf", "2a51c536f0375ef9bff21949e02832b35eae3f9be73e0049426439bbf86a3be0c7ad4c5ab0ea52d52c3bdf9d3ace91d4a7f0ed3f06595e2c715744fc192fb1eaf4ac532f74728314486c39bad93a43f5457d57041d55dc2ca4ff722d3d5dedadf27795186217c96f095b3eb29a129817b9f1b3bd00b828e75d9cafa3e5834286c342fbb615b8adc2e8e0bfdd972ea4bfc0237524b3f2", "1826b1b057ae853e87feba355e061f42069a8c127d330ac28c9221da2c3dc04c1e52f3bae48889e90f1be6e489e70fc95bb26c195ab9c3d9295bfc2bf72d8cf883cb647e0ad205a66c9c0788bb4c6383cbecab3eba02d04ca8f25e623122e3ca62079a230a01760376872490466da780eeb324615229181bfe781a222d079ddebedf5638407e99be9974c539d8bc03463f2070955afa2f3f827552f80911066d05d54955a1469016f9aa941b03cdae99fe18742f0058290992c09d8523b5168788fe5fd48dcea81791b8160aa082b0ce5cba88566f5a5078248bd691d475ad79f550e30bbf6dd9765b0b9d4d77f18e2412876f1dd825762670569ccb61de4b9f67416d6470e08e9bacd57c51e710295439d0bcd0f0093e96707cddedf8369ed4f4a892827dbecac5f913686e", .Okay}, + {.Lcm, "-7abe6aeb98ef94bb8d0c524f272a591f2994b84bef8a51cb5cdeb94b78037e3dbfc0a108c9b21b41e8d8b0ecfb8e0b5d5905edcdd9ab24d0d09c8df404632b248e2d74dea49cf4d13e8ef808734476eed33d106e0a56fdef1ce6979bc65723e6b28ba545b2e6f8ac50f74941fff4c474fb2364f7ccb2ebd79379359c7254ca6a6e1d3ef9f5cd37978e8ce7c5435d022b47bfd7b7294b", "-f8da8c801413a532e1c2fec73c8826e0866a09fb10979e18a759c06478c8781ef48208e44967a3902d717f6b2de63010ee2db78744adada4a4448b60b2ce3691f9757a9037b772ebc9a60c0246b4c3b29cd4831dba10a9f676c9902b825adc245584d9f59d62a6aff022dd6c7c04e20d5751e5a155c9d80654705bb8001982df9638ca888c489cee489fd781a8dc49c1128016a5a896", "77514118d416ed3b4d43a28f90326d4caff7404f7236833bd62c8a734389ee02e298c6cc7b269ceb84cab5721979a8f44ab6febd2c8159a8dbab2670bf87b22d2ccd2595a0745e39e91aea8385305cdf28a34d36432ce2f26f90fa852c2e6d43508565307157b7583907f5d91e574bd923cad604c4ecc63ba7f944f9bbc987af21fa4c0bc144a4fd05dbc7411108aa23fe7a4e75500d2e04603f6f0b384f78e1e244814f52d03e838d3c2c2a7297fc44fc959bbae5c74936a4f81ff3366ffb26fe5b75265f5e192f87f4c878f15297876cc37f996c7cd3d90d05dd5dafa4a26ad04dfdbb5dc13ede53d0d8920422fe1a1a21b723ad0e67f617264a2a985034f16fc0f0849a17df9afe110538776ccdcc6ac756664d8d42d7df29661e35695a52f80c8d62a8a8a212a7c269f2", .Okay}, + {.Lcm, "7a3167da58990d75c23e6d18adbcbf2e2a771d95144b62a4c93723367108cd91f6030c1ae8d1276a3d98fea812b3ca0a84bece3f8bceb8720a861f6719cc1fe4884761d6dd21e0449c71abf004c8bcb82dc1e5059cde728fa6a1a341d8148da121dbd5773fc6a42ce312e4e4769dd4a1e2f82e90eadde6ce7fc6f4bea8d89a58970f3e2a2f2515739e23825081749e2bec0150901d8c", "fc3da23cd68af917a8076c30a05c602cac940a41b415d070ea5b5a0829e25aa06208738195202222b60f05d591381cec2c6820e2cd6370770bf65cb7f67a237d4a9154598cbcd0554eb2725923cbe749b288d6658063280dc894816f34ca44fe2746471a833f5b2effe64663c071030aeea5fdbbef78d44db207c52e616f829aa7a16953034097b984bf1d001fcb8a2287eacd8d564a", "3c3306b87df8f5a6cc89e43d830039149e8019d8801f5ebd83c505e7adc802eee0894f4260353658ab4476d95a47da048738d28f2cd4c3f891e5efcdb88202924a069c7a28b8a3a851ec5a88f3296f1e5b96d096d95b740dcaf01f4a5aa3cbbc74a25f7ab66382acbb3d7ce26faa4c070dfbd1824b07f4e05606b6c9d89d625184a67bbf7fba00a57d93f2b5a90d5700242a25818eee57db1f0a9bedc6f4c15a64258925519fad6f6f3ad14c747474444ebd9d560a831ea5e6526e7342995d2900a7069173ab0036ce00673363e41bde3214372b608be08138bf305443746cf571325506a6e76df4953601eb74912165e9d824a464125c60528843721e66bf2009ad2149e11bfbf4e471fc1412ed7eff3922b0766fe1c42ed1669d2d38c3a0dab1db8965c60fa3398ad8c93c", .Okay}, + {.Lcm, "2eda975e16f6fc839a5d44d88333103a76308fab2cdbc8a0f119e6a0279f83750c3c30f0efb171527cb27d8fa8d8f0664f3c067f9da1849fbcd446bf26794182e9bd27335a6cd0599cc1dae970dd4123c7e518686770c2eadacc340f42f26acfbe9faf99d9e3b37a80c9763a73b318cb54ffffa0520969b12e854200017aca51594bb83d649a2e7675f5c4ea150c780b0b341a4f1738", "b1220bba948a649546307dd106a37f8633ba40f3643503be83901a125f00d7c12d8772a7cb92ae4c94f4f9c48512b13d53bd897d5940c465a50e81d5cfd2f924283c711765fdb3406e482c757017b040398e527ce6b82c103544d18b4a4eb40a991038982e0195668ac48b62c415d8be90c9eea447166ca1820342c84aed82565b2e0eb96ff77290cf61b8fa55234ccfc57b7752db45", "206b5dd5b2e28a7e86b4c7802745f960ec45485340ea54cfee40fefff092f29e8fa5a61dd5dee6bd4204abe4c00966b3abff7674468c5c0dc3c0c212485ba3a8189281429e90f33ac8d880637dc97c8d904809e5fae145116a73a9d363a114299efcbdd96c3dbb194221c9b08244da6ac6dce6048a8ba7c7c3d392ccaa2518b8927d2ef656c8cc17df6f0751f2ba41d3772972ec3ee4152cb5dc7efcdea50e5f3576cb91d070cb5a9349257804a3217fc854dae760b7d531c51f69a6dd9c268582776a5aca1284eb0fc7844de37b8c11d0c9028d99856dfcbcdcd8544760ed9a5dfabe2647308158446b53b185fd95b6d13f24d7f67706f3be38978e528ccfca4333a86a6e5acf33522b00b459f86a638e659d5d408fb5f48008be7fbebf6e1658f8ec9483a10895381e2a18", .Okay}, + {.Lcm, "d39a7f459b3e62ae446cdf20bb0d081ee74f60a52d472b6ff7a917f4cda0db424641dbb7179494cd02fced49d9d0b7265c2e0df3246464a3ceaf1074e0b0106353e5b033799109ccc74130afb94debbc96c03819cabafcd7fe5da013729b97e69712afc22c03aedf00663d62c672eda93287cad172867434ad1dcd87ea95d67e314eb3dca834500e821371351bb0d034fa5ab29aafaa", "a3ed42e714ec58dd28e6e1228e097adb3e010a18e0db181f750246e0d9db456185eb3ead8e258f9eb903ada6cdfcb26f8dfbc804ba893d1d4e08575121146a3ad90b8b0140cc28bba88c1a37f27b4e838b9323abae325ed64561e65b093589bea19f91f256d313c76333c63089dec85e20a7810bf44f130c2f1b954e5868f244dcdd35a56395b87ec18d52977e3fc821c4fbd14787dd", "877f7c5dfbcda93e29dd6835d784c27d5b1f73f0aac180645f2bc6e62a4b2b232adbb8500f7f920010825929f4d3e84403754a9680fd30d52046ab810b49fe7d92c34dfa9737fce5f4a50fa51d7a1dbfc19d6982701c3b0bf912d34d08ee1d595572d62c632ba740679b1bd32ed6e317f0a26b79dfad999b959ad310d569bdabae29f19c765be0f32a9982ea558e81abf5920f50271691ddce3d2475d9cd0ff9c91958b55811a2fa319479b4353a23f52e7095c5251a77b0d321964ba9a385760c7854606e8e01c5e98cee539a34dd3aef904e768ecb6b53609e8ede615c3036ec7ee1343140166a5dd058c7dbb797ecbeb2ab391cf5bf130654ef78d2b78b440281eacbfb6b60b62b96ba31346c24e0b5f49d70ace3de24bbf94e2fbeee1d5fc11dd23429cc2a7a44524bc2", .Okay}, + {.Lcm, "d23408baa4f7fc4e52cbd2672082451462da680bd988d7385bd4e81db468e4ad101b1e2a6980dc87c039490c865bfe97bcd1b8d0e82093a9c6bcc4e2735c177ce875a7da33077d67e4a2e76061990cbbb3438e9a788fc6b31c602e0627e83ed9b883b55949d45c06540ca20dc325cba49456968d582caa74b96f4831b0d00c0721a8bcfab6599699c99e105ed7f51513cb0b88f8f00d", "94a6393c1e5548e76011b105148f4009561acf0b73e3ea58df77cf43db3b19acad9755ad93b1f201ac394d089408ca5699f83c07f0746c20d0a81af657f55a46bcc4c2d0fea299a3a18548e7928f9654968d7548dc9e78232f8591b7f827fab1b45f0fbf3df878af094eb02144cc4bb8db2338d7a8d43dc88bb1f5921a48e72dc6ef787d8442d14f243e22b542c0348d6238b6b12ec6", "7a0e91c88372114e278c57661de9983a1fd30395847798e93570937abe19abc3b0800fbde4679c31e765aa907dfde09377865113b4af3afde27e5ad90bf36012ae8ec288643ae0c9af81631798eb1eccb8341ce7f6c40265a8b5bb35c3ed59c533d5ec62f3ce1c5f1676b275b2a087d0b8169c4791db991f35f1f6f9532e5d76d3a249db585ef45505f144a2fe31cf3eb71203e48d3a6278ecd087a5b944581ba4e71d2805f33b4e3af1be3e0c4ffa5737e71f1fa59f129bfcef96f8e48411fe03ea0299cf3249ac9c86f3ba00af4e218bfee808845bdd47006f5a9f9316ea5ad563fc2d13fd8e91ca7c390a03784c882f1bad2af3effec7c35cd1887c1560761521cf48d116b43576e052e5cb71d70f59ce6fa1789638dedcd110616061e820fa9cf0f58fa84927e2a9000e", .Okay}, + {.Lcm, "-dbe7e8e492910165e31cfe6f299ad9abf1c0fda5fc1c225ef97531f5c7be67691c5fbb4b2b0131cbfb3d07a728f4bce3f619ebd0f54bf76168f101239a25ceb7d66d0262d7749af63ec6c2d23fe56043522eceb2a092c546bf3055335af7bb7f793886a57d01adffa5b826b4499bfa947f39f066ffa6ec1c2af2f29e096b330ba3917ab4fb50eecbccb64e6aaeb95c1b9c8a46ad4fb3", "da1be7036a78c30d5b8b5d1b605fbcf59efad62fcb72d281cdfbdf32721c0fa031fb3602d77d9fdd816974ca16a2642de2597fab2e7aec90b86edde1955363a587e2eb4f88e72ed6ab92669120883aaa85da4600254dd5d250bea14d5491f948e2df46ff4ae34028f8230499905bc4cb6fd4535da478409d5006002baa712577bb01753711eb28a8f436bc367a67c7f99325c3f8b311", "bb5b7439673eae1b68c06d56875d9df20f06a7ec6dd0b5888777938aff3dc75032f20d0ea4e1165378c38bd544195eef9a403262e2b0255987142a1ede35b9ab9e9dab34908f31c40c6d5241d3b13bbfea12e382656657857d5f02b5a89a74597f9828e8da17f2d0e61c059554b6fc0be1debeea575885d6ede77b87120f1e7b1e06cfb261d586f136a51d86050e30b4810d77598c54fa80ff5fea7ff6ab71e016df05c80df7a7da2319e9cc2ee9eb7101b138f7d8a87af5a71eff317e6ba5ed7189f44cb812382cfdf7eba79f3f8241babb3dcfa98edd1271f92e11dd5b96e72d85046166565daef535e53f1ac1777343b17f3e039d5872f89945a7d6c0e2ff0eccac898a8953538f5536c2bd25828c6d3794c2eee18e62f1e9fcf7516c85c277c455d0cbffde136ea473e3", .Okay}, + {.Lcm, "-9520ee0f259583e98468f6b4912b2cfd421a29e33cfbc53246e08bb7cd009217c7d551423f4a1dbf30cf4d850ad8b6919f330673c030537c282057d3192aeb80f229e0b8871be50cc28cfed289b447008eaf055eba697bb6dead54d4400be7e32654b37784dff945d170eaaf33de122e1e0e5de1d3749cc49be43c05d8acde243a07d595afe4707407b70fb98fce32f3371f5d81a537", "-6994d511f375dd43b0107b545f83553d14a4279d46026031fcd5975070bd7ed8c43be4b4a074e3d583e0b9ec1c1d1c5c838607bfe93232382c2292d9a4608f010179698468316976657dbee6ed9051749ada147be57ffc1ba382365cf2caff27c58cbcfd9ff1024be9b1d7aeed372d619e51b882975700c4e2bd9d641c0c79e3febd095f35d7c8951b1b26bca99c95e920a042ecbcbd", "c4d0a8f56d9e058cb751336c9708e225b0e00f976ec154393fbdf6cbad498d6256a3cde3caa19d62b42245d32890a40fe0159cf4ae220979287af6c653245dc73aa0695bb763d0fa5560e90f34309e2520e28031ecaaccda89f06da9f9205c4cf77c7f1f0849d85c172e3f06ec7e6ddf0b27d0ae40b29d4efbd4da10314b765dfeabf09da247199980545e1af88187aedb52f669ea780a019a4a96e11588935654d020f39888b9d4a5c2a666ab540cdc53696cadbcb08f66ffe8dcc9804c7bb0f62e5bf1e77e333ad0e51300a1887204faf9b2fa947db8534a7c3b3e8f20e3ec23c1d11da478cee5e5a09d45461fe35e88b78c9c2b1ab68d6350e6f4bd4e1749c94d4dcbd79da6dc555e8f46ebe147acdfab52ed8237448e85b7e39f968b294ab3b70353b5c4c432559791f", .Okay}, + {.Lcm, "-906430def979ebafcbf54a4074398020f03520fe89e7fa222e8d135b3fabec63b8013f05f432660a44b311ea0bcb5d09775ddd2e670c016a2428a089ebc077ecfa11a412787f84c84f3e289b5f32dc5bfc3d7f3537259e41b6f403f61ab843018920ecd37768ce0a973ba6323931d46db1e4c139af0d1526df1cb3820c2fa5bd111255d4047374c57ac1880dd9e790abfb5c00cf4a22", "1371c5c04932162ac87e81203078a8a183cbddbd38857b4ee3bd1b5b5ecec592ec855fdc029ed4c0ab96ed12e47720e1caddc9d2fcff9c70285b75638b7ba0c965d60a7877e36d2ab82ae577d184300ec8ce62ef90ff477c46197486d975a3cd01667c891804280b91a204b20861a5c6009038273217dc1b2f34d1f5b1017f7e568f985424388c6f98422e14dccfbc0b6e38c9355e06", "57bcdb1d67c9d43707a49f96009618aaf84358aaba758dbb4ac5c8ac034d7e4cd9ccac458e7c33f5ef5d570cdb7d506a862909f57a2379a5fc2481393e678124bc1c3a4e562db1978df5510ff59679f67b49f86e5b690fcef61bbf4181b5a24361e0a91893d00ebacaef0f29fcba5f6af136d8d93b49d36648e2ac51d12dd449816c85493f4591d19f6303d7ac4dd63774b3d4d05058eed2cfbd94cf93bcf1291b898da4348ce69e18327fb599c95aeab4219ae255f2ccd051010edd9b57bd606cc4176bcbb987145e0de33ea9efd4cb30ec71989ae8563033437e70db817e4ecbdd1fd089e6c2f255e49c09c75cf53f08083348baeee110f2472717490ac15997cbb4110973516177fe9b106595acd30e1a08db1961e78aae1263f5c074b4f678287e99bd5b601968f1c66", .Okay}, + {.Lcm, "196b311bb8c1ff2afc62e28d99ce547827260a23f3836ed4e51d9eebed687da87bce807323cf687c840d95949535ee9c5425cd0a2929c62c17191bd476483eae74b40fb95bec1032d472ba9bdf6355b8c0f3f6c304b87f2c9268a72bf3efb6a19f1edb096facdee9db3ef953cb086f2f73ff4bb9a60ee06bd102cfd6cbba23434f9cb7d632c36f310f0451e2ed808327a59d99f6d985", "a359a7d3d057aa706cc6fb9a73c3c5542a90a1732aa6a31f8b55947d387e060190877b38de5f6041049d31cc68f1af782e25a44105e3af4cf2382ef36ce8eb1dc18bd04c1b913707c1133a6065b1bfc5543a4b2c35d1c84e0e7a88212bb52938cf3e80da552b8c438c9e80d3cc2d38156813763a042835e8316f81b6961aa3bdbb8eb4b3776150beb5a048543a17c67df7336919df1a", "10382732ae591c8a78d75860dcf54c77e991bc847bda177edfae7959e9f1f7e15ecf44b300e96690f5c6eb42b61c00f1bf7f6a70b7812128f37eef8a5bc633e920bb2c1a7511c5fc8625ed7acb5203feee60058b893cf65bb190296bbe5778cc8443dad6c2c97ad4f05897b3cf7742632065927958eeb34ed974e1db9d711f77b110f89092fe0e48551527c073c807a6f7b3ce697bdf712224af1c7f246f0d02d0ded03268b4f51860a89123b9933053b101581fcf36234892f08b93d1cffab49998f7538ad492feb899a8922d5969a3ac4c0e99ac0e57f292175eb6ea694a7f9e532e28e132f55b3c4515c4a33bb28a0795ea3fe3aadb9b9af243300a67c0559394386c06bf226cf84ceb3248a380be0ff7cd9289d06a9d3e3944cf1681e448941af7c497d30bf17589f282", .Okay}, + {.Lcm, "7930d64b18c36509d675f391abf3a763b8517092624e848db50c18ce2bf04e2f166fc4e1bd34dda4a9e4b88c7c9a15a7c1013916f6b173a6810f34c95b0ee2048e822323459403e863316f6da03b7a5c841574407a1c58b008a71b0c391397fd035df1945e85d479a7e501ec59cf629f9bf58630a10ff6e11a5b1aff840d5d14239bf9275aeafa5c0777c3bad18c8961a051b8bf5c4e", "-fddfc060d5f271a5af74faa1051bbc72e4cd83b55a4b6d3f821570a94e102cd9c7355e4756e322b92bab7f1da15c61b1503148f4c43396ff7472ee38928f5c59d159422564c8234ce0a26e19bf7f58fe1edfa5d2d7ef45ba0f6c91c90d33290903fbb9f18cf188f522089fac4f73410cf2e2635fa591548402ca30611ef217d115389061b93615c5efa0ebc812f51e122fffa9a7a34d", "782f30655b34c40f9e4aaa5f495f7efe8cb3eb503858dd5430de21f28aff956bfcb991097de08e1b7495995e2d9a926e0e3f0cd134e2a82e00cfa6238c74cc7b30a7001f9a0a5e31c7ecfc827255a0b336b3f4b9b4d893bb034073f165beb46477ff802366201a1824830bafa07c27c83fc906b211aedfbfb7d648540bb9801e14fd0f375fd4d15f2f7f8c85097c311bc1942262d57dd8c9fe9a8ec2044fe727e255d152bdf0fb0cad177206f751dac2ac63085cf62a8cc59221c7d7dd4a2649820df9ea647450295ea03c2d7194c4b9df5c589fd247e4f00e5db4648dd2ecdcb4ffd9088248fe764aa90ea0f8407dcff98397e9424644cecf5af61591fc576229a03a1b9aaf01e69e36c133f7927a36957b6e9d71cf9beba179b0687641d4e5e4a08381cdc25dad1e366d76", .Okay}, + {.Lcm, "fa19e4dcbabc7e0636ac4e103a89fe75e77c9542c4a3201befebc2385c94c371454b41a9a867a19db810def185eb41158c2dde7c4a7567f0ff2ebff4df8a128a9e82fa135f08057f906e7bc5da564fd96071dbc49a9a8f27c2e5cf007ce0ed04b03c8d292deaef0f84bf9fb7f11c5acfe89bf1fc82b37d6142407a24bd831792450a8a1a782a7b7e114a64e540d523ea826ec0ad5d7a", "-403b1cd2f93ce67444a7c8b86ce7b1da26dcfb3e656318130b2c518739edf754fafdec28b86f1bcb56288d09cb3ebfa17034ac700361f4ade31a021cd9c45e4108ec631e9aea816fe9cf3273fd62a6eb28806f5c777710b65bc3efaa98f0e81c81c3f0ddaf2796c2111ca7589292463701274d4be9432abc61de18021983a85cd78b564019cd8140667266fc7c97bbc630498c58762", "1f601cabefa95ca0caa5d3504f768003725f931706350d212ad058286018456c1db4d20c929a8feadc967121706494218f371d43e957d1e5f4414a3e55a9de2e58bedaf4041494725b8826d8b80498136bb95d4a475e4a502826c0f7427ceac823c04a91c621dc7476249a9dc325d78ad1197cad427498b7fb967d2d6ae24cb1466dd177730df791d3029d01edc53f9af216091dd03d4d226fe1c8f8d827d27cb38b737b833d617bd887979094f8d4df26670a3809780b732cbb4eb490f3e12e7880a19ff9633d904dd682f3b1e5b75b8d1c8ae2ff012c5b8ec32e7aef3d0541c702b898cc33506ad395ca79a43ca48b3008aa098e8ac58f3295ef390a02009513ef01160618e9d41f5395719094738a4109b922fda5ffc225d313fe64aacc8f2fe7e596ed1976946c58f5a", .Okay}, + {.Lcm, "83c19c81be3225670c67004a4e70f9a99a01803a6da5735ef62b03f9b4e1c71e54ae328da9f71002017781154ebebad7232373a6d5e2d88c0809b4dfee696d436e2fad72db4fed9f6925c2e4381852dd5733d648bb1dc32e4d76192c90f45d1c2be75e4ea15e1449beede8671b784356c6961321abfb242065448cb5e8ff455585ccd1ee32316959e225e943f16f4bb5689827ef3cdb", "d51fd8e62da09a982b46fae7b1273f34726ca061efe183889cb88e86349445e0942be727db483a8a8008c220cf3c6f34839a4dde68ad081df57c6d15d68d6842be9b02e13f45c86195de0508cd9142d9f1706364fe7052265fd99082b338dab8e69377b878b60f4d561f69f121c0e59ce3ab178cd07f08424a3ded4b6161fd6e7183f20d263491b5f068696650f4bcb19edd2b2d7329", "6db07b4bba718751de4f777d670ced77076da0e1a2a3510924401cfe9076f487211fba0136e80b7ecd94da5405adbee1d29e6639d08d1731c59be428ac7e2e7486534326c0f1eb2bc68b66bd2aa34b8969be8a03267bcf72a2614988d293698e1f6f8ee1facf1a7f5a710d2ea6e273d9ed75fc4fea4435a1fc82bdde98f713278b10f93cde09d501794cb11f198c95b52cca5554ff0837ed014d53486f5448a4afb02d8b8a596770c78e1efc8fcd2ccd6888508bc468013d77e0754d9b528e566e31a9f29370163e501f0ef38281a38f75a81dcd6eb81792c2b4c1a364ae7195de27322035814fcea0b5b0f7c367326d2f81bd2cb9d110b812089628c6d705b45c65c2a09f0a67f653a14be3714e1ebe4c26b1461b15c0b57a11df45d9b8a927499b6320980001a459262013", .Okay}, + {.Lcm, "2ab47cb20fcfb64e02741c6ef2d111dbddeec693682496a816ab8acf03d398d071b023e4095aacfb2e5c27a069ed33aa599a7726b09f21616caed0769373ca75bfc2ccb56c38fd4df2d0ffd0ef78c73e52cb48415bd77340ea1ee54d91fd49769e6aca7fd66ffcb505256b35732aaa1446ceaf3bda557094c12cfef4186563b11730b4b57fe80c6c36d1ab112c5896ce8b9c645533e2", "8f8b32adbb9ef23522f011e4be5f2909ce4ea04368cd71692bd9ba4aeee7196427f4f4a3ee9e2b8be177859d0bf122e56d45129e4aee37785872c0acf5d4d6dcf6d875d06d82416c6c462c45642b7ddce96324da21ab6919b36c0df4e24ca19a54bd1931d95ebc60082894a582100f9cc35dddceeea498638ebe819ffae04b96d925563ca24a167f1b0680be4b3bbe57c24a8a0c595e", "2650102bd83804abb85a0815b662513244c9442a12e0bfe3f12dceee86562a1d09b635ed8c751a241f13ab351369b2e17a707831a15fb681620304a546999434e1f1af7902e7a0b0221aecb530916cf23791f446838f8790b5289e3e9547138242afd03faf5b13e0fc276c438a01d155a787292ae8ad34b70431f3537466358cfcb3210fed2695b2fc67828657161d7a00570533db9ecdbc32b30251898943401e28af56a2ee4520754819cbbe2f1b4cbaf48f91196234e002b33c40d618fd9e40f0a28b035ec227d39eab2741a0e6e9f84454345c63e87655d861603734bfac3451ef2123e7b6bb8d4f53189a1909db398f6c59463b516993ac5d44fc4ed2f79940a2f9ad3daa6b1e99a730cfa264b3581e188708d5211819a7136dd2d4a7a7bfc62f7ff278d8f45b10fe6", .Okay}, + {.Lcm, "6520a11718b18223ca50cb3a74028febc03497a999561d598c1f9b57a8f2f00e7085c69ec35117ee793cce0c5be7e0233a0314336e1f860d3fc108dd6f98e42446b15d00ce6f3e3c4a0d309a62011a64c20aa3e848018780fc911bb5eec014f410fd5628b8776ca37ecd8ce9afe07fb2891dd40f2b75f82b31e0f22031e278591a960d34854fe9fddefa6f3557016222e321585020e1", "67763cfcfdfb13d65261fbbb9fdd73a25e87c263033543431d2c1416d8c70b16b2184e971cbf35842f26b216ff425a22cc22e3b9bd9c6bf137e31323147e6d86cfbc6a87ee673e430386084b9c08fba29ad763ded85780645957f65800b797eaa62ffb385834c5e81041bd7862248a42ce7d35aadde77a76987c74de1a020396270097927beadd52c7aba21255951ab4cbb4283c16b8", "28ded5f221c937bc26f56ddb9d7430bd33185dbce13ed57272e1dd7c4ec6a29380dc789696cf0edb0d9516139415e2549d2176d2f10928e38d1ac7b5968e93fde94b4a6701c0be4a195b50e650def1c39b55d395be1480c9a6c87aee43bb6dd8facfdb1b75d0d44c08da3ceaf6ce8e4c122c091b2677591594b6a0d8d90808c058e96c5016616bfc7d208ac8016783768bf5432008a9286ae6330cffadd5a994bd4ec3fbd2d2687e32ddd9e350af103cd2a77335cf44ea0604c7a22282c38fa1c10a825bb70a64b2ec48a459da1be921cc51904291c7ccb9ae3f3a6d4e043916c08d9463d6d7e05bfc6449cf004a5ce05ff0338ba3e074003605ae000ac8b78bef43dd7d8a19fa2759ad06878c96c0713608df83d85481f81e7881b6043e0d8193e6533494d2dead3926f7b8", .Okay}, + {.Lcm, "-ef29622b4a8e8d1b76fbd36ad3c5d912f42ba2ada0932d92d4ad888598981faae7731c6c379f7ae8133a65fa4fc7dd96d6b8701d466208528245733c7b53e0d4d93e9ee7eb1fc9b1205ec100a20e15fd2785f48800a461ab4ae4380b4c6137bec30be043898bead0e2e73cb0277fca147464dcb7104b74f85764fbd06b843ebc7f2f3074bef56452c15e0b1ddc55ec4ce003a4cab10f", "dea574793f7e007d19e728e4510713a990c551f73a32794cfce595f3ee0aee810dd211728eea66490e51259fffde6060fc1617ee8b333e91f999532235ca639abb331e300cfbeb003f146a6a936f00078ccf5dbf80d8b8a9e2222fc62ebfb6067015c3f4eabbff6e1fe34f3178d10e40e0408fe8cb8852b52b142f4fbbe9bb8f1a93fc36314e50175c0be8d2c586146f1395f377b3f9", "d000759dd6ea96797142eab370f7eec7168742fc557fa0bfec0bd392615fbc4c7a4352610643a8a6392401cb343aa2d8ddaca53ee1711c83c469b61378df41c2a74820ad64fba67ba4a56be32bfb9396fa60f920507eb8dd38e13541dfd84046625b96e1b58388c28682a5e50bc8e3aba26969e4230ac7c620eb16f387140a6449a3fff3d3f6e9954282477071704faa35aa15d1a3cf053198e91115a21a6be929f2ad016b7bd87d8fc0d77919619af3a30cce9ae6400e00b3aaa30c2179a785db992e66c115459088d87565c2c53210a34df39ae8cfe442bab56bed5aad3011e3ba8d74a2b503c0a375374b11aeb4932b6f740f32e20ca57cf4f4c4d2a15d4e2648a8fd1a77aeba6e8c5df4b5a88d9c7151a1f818f8295cc1cc0bf2f60f5cbf66d35e1815249ac98decb497", .Okay}, + {.Lcm, "-9a0c6236a9dcc8c8819e5007ce13f96d8509ca11bb602606227b0ae1142d7c77902665323ae10253644a685ceb012d2e9a43e2c653eb5760bfe04db2b50a334a423f486abfa6bb26d658451ea4d5ea6cfd5691cb2a69cd84797a4be936ad335dfc6e86a3feb48736df2673dad59e2307096dc87679f90d688dea4951724c23e3c1ddb8243d70d94a1c449930382eb0082ecdbbf6cce0", "-80d1701e8f682778f67c2c44ed8a5eee8891d3c4f1295c7fa5e73e1eb423587838f45da4f2ab2e4c0e5a1d2730056f5418eac1b43fe425caa30423b74063f04cbaef88338d9a90c79969e773699be3d0b33409594a5ebd8bd60ad9f99b975621296462eebf0a67d8019938ccbcd1554238ad9899908873f675d3d5704ae82cab575a3cda1150328438995b1aefc706f69a62e3bd764e", "26c21c57a9230b00e433466a9cddb695d4b24eb2ffa91efdf7f472a234a782afa16fbf9b026e93049b7d853ce784301f181e67d3fc22461688750282491b6da9ed33fbff37a5ac96f90a03fb6f4b79f1a1003287fdb26c3e19435742c18a40bdccb3c503794a76b2064f16a4851188c8eaaabced378fcc369a323fca66255c5d78338894a747581bd8026556cac06071f0ef43c9cb0e7e866efd0a782283d4b3fd9827dbc001e7ca4e7afce5b56398bca908bbfa92b803a83b83cf1a7cc15c26fda7e42084f66f8689f0fc07405dc45f3932e25f5a11630bc2c83db14cebd008eab3d98c8af76398e4e288a6d2af4a2fc6f2acdf9073fd5ac94784f9fc75736d50ffdefa6a2c190f9c9d20f3dfb64edd1e776b5a0d014192c971ab6aef75df6a6bb42969774cf0f97480d620", .Okay}, + {.Lcm, "-2e1edd81ef47b34668d671dd617d19ce2d9ce285f138dd9f824c4292442f21d30780cec52ec688e43ae36ee75cc04f49a235abd58928cce0c160f07bd24ff2fbf6cc4292f65988b39e56c484f5bd252a998a9ee5ef0c793d541e1c01716a2d0ef0e0f25d3bcb9d677b3114bee7dd88171726192c1a690bd601e310fc28eaaac1f6e412b6961486d62d9fbe8807b886eb634dc75579fa", "80d822c4768c087c1d319b479d7122987ddcecfdbb516724856bfcb86080c01b5cb8fdb0368b247a95a384e79b0c2d349cc7601552317db423f71e8b2bab4d0079bd67a63a3aea9301effbb728a524870ec654b3c68bb172cdab0986902c96292a3579f560954549c2748bbe02eafd77a0a42b1d9228bc613e837ebea49991465fc741a0e142e21613cfd3262b9487c761a6bc3efe77", "17365f0f5bae0be78b03faefdb04f0b002b711fbcd8bf8b274591e78a0decd4ea12a973012da4368a0c84bab8634188ec7fc760e902f65c13c3b804ecdd63929d0d3617a1faa0b68607faf02c3d9a4e2f14ded80da6b937d927fb314b5d7d8c7fc84955faf48fd3a20e06b01cc7f33e13725fa0c8011d3b15d8173fcb24001cfcde02174c501835e4995a90269183489c598cc3f35d88d77983c1924515b2bb713cc8d410da42d1724733bac7f5514dc906b900051ab6736f04237981ee6aef0658db35235051aeb03b5951b51ceb91981a20c75dc841ee2a8bc60feb1bda6734e500ec3a48225c2ea817038588e960fddaa8a84d4a648716998a40f9c1fdb5e232face7716072964c914dc604ea6cc78e31425f1c7450f9ccfb5b970a6a60da8f849cd6bb2633519a4dbf36", .Okay}, + {.Lcm, "-332dff277799c9a3cf5c1c2ec79e317caa39bdf70fe17f4e2e5bbe7109b0f264f21fc4647f9152040251e0d9fd8565aad20e478c0f6a9ba94c0b2c2c38dc68b2bb86b7deb3a522cf1b6c4cf50444f6e488870a6454fe2e3a78190b7e25c51560e5d25a7059f58c9e20a1a47ec4e79c755574ea7f3ce6aaad10ea484c2954ee5e6a495e037e123f6f4cd71c6f930142e063057880bb3f", "-b49fe36162732777d260fc45e045c704d4faa7ede5592419057e2fd4878fc911883aaa0662df3e0804c4872ea6a1f465270fb64c53af408c6637d40ca9b39e461a533b915a550df25c00f8d921f92f72603c97db6fdd480232a7a7c2d11b779321a336bde37fea610f8aa66836d3d74a5a4f692c61b78ac9222e81db5918db24636182fd29f6bb3b5f32bb232fc224de9b8ed087510c", "241c4e6e7af7b887ca6f8ccb42c94a92ede0a9f8453f5d3da977995036b876a69897c92d4d8238b7df4efb72e83d0a25bdd2f45c1e5cf3031db5cdb4e9d60c32467e9a39f9c39151bf452f2b2dba182eaebe77a94bf0dc2db11b66f620bb6e173da712900bb7c929f9276d4dd8de8b3e2788bcc6c6cf7ad5aa21c1e904586d21b23c1712c3aefcf0e7bb206edf89d55905ca460a9a10f3240644419618390ef1f25ba3daa29a89b763ae6a083b5e0a4dcbac6dd6f0eebe6fb88c168155838e71f8c8f6d243ace4c72ec83e62ef9d3f1b7a0140a13923b15d76dad5eb263f0c3b6b8705d5229b8f330ced9528af65926062606ae692359905e7946aa1fa604443f41ac84e8d4916e8f7c08e1d481ac129f71a0a3d4664ab07f064aa085d9bac0359662cb4d10d855a4f80b5f4", .Okay}, + {.Lcm, "b6f5750c42532fbb0f660bb3dcded85e86a46580a0254d9434ab7deb16c54b6213635617ffe59814524c3852c0d8aad8c280c5dc459bfe9feaf93f757abcaedf0b7aaf8af6207d651bff5898198618710dbe89f99735c6f0504c0749a8cdb2fef2b6896ca1b4a023300470b33a0f0a47b17570e095a4aa0ac0ad55030b8c8af2ce4aa0c45d6f3e774947c2f919d0089efd0c80d0eda2", "7c47cfc4f5300a3e061dbdf845dde192c54ae20c1f72dc9fbdef8bd46faa2f1da00328dd19c5a50dfa5c2a7d4b85b418011d20579090386c900a90622a5b7a7f5dc3b5daec855a7e22bda197cb4558288b4ac792f4622c66788f0d7d4dd63b265be3d70a4ad4fcd373cd14148abf24964251b8d7f71cbb1b0a2601501708b27a74214216aa9d133a7117939b163ad7581649ac9a1126", "ecdb3e0708e13983f4c3af73139f0dd985473001d317f316b2dcee83d5f97204442e5793de70bff902b9a1714cf3a56f9bc61864f91bfb17dac5545ba80c3efa5369c768c1bd73abbba24984e9a189830cb8266104e1eadfcd2f5e94b73962652f47472b09133fff85917935dbe65a479f7586351c26b719f5d13f650aa40f7f40c806eb2e17d1d35c14640f1633dd8e8d24d5122016867fb6aecd1e7be3270776720897cdb1633988276f3369a4f688f3f5d46fab3c5c0657fe3613fa63e9f4870f7143d81ddaa196db2c54851dde304bc7ca2cc829dc33b172020aaa2cb417fe4013fd00ce5e4737efb4fba65628c8bebc6afa63ce15cb7ddd0a83493ddb7e7b7562996ab289b1c8774f5af8cc55e8814f6ef54e1e242b275f627a011b568128190cea606d2d321b52c02", .Okay}, + {.Lcm, "bccba8d2867e89f4a9dfcbdd2144e1363011616fc60b9cf01f9f2092cc9115fb882313d5cb4c55cdc1bfdee6ccdd83888d3e2e1f4f139321d6b8e5a7ad7148e79ad295107f9203006b1bfb475f598fd229ed4a58c09fc3fec3af67e30b387969e8de048de6febde40c24bf4a558d66193a2926ab81400a578c2d0afe8d2a29ac3d36e2d1cce292bcd23d1366d69d61f406ae4e7ae81", "50ea9e408538159d1308d3f997971368f94f867724f0494d33c954165c640a8667b08530ab4faa9838cafb4c628a3d7ab8bd35e75497d794833aa9f02ed67e2b9e4f5f2998b67f401fc93d25cc93c596ad305621770b4c429b46d222b5ebedd3aca55aa82c716f9b0374ed8aca305d016706cd0535332cab1f7e4c3062b53daecd494d75a1988ac2978988752d7fcecb057d73e41f76", "bef558646c38eb906a4a8cccdeaab5e4d3700f68bad76a806f2e008dbe5c2ac6886029fa5307190bf297e8eb48f13a320dafac0153883f9fa69ce4860556f122a3800db4c55ab0118a0383e72af93e37ef597278f2969a4cea242b977e29f604e6f5490cb14edb2b67b0fe0b73d635497e507f29eacb0515382f9ed72d94e7fd96db3dcbd108f574876246e8d0e302057b447c2ac9e2d69815e59af62304c6235bdc1c7c5cc850ac519a124d8b9b726440a5efc02f1403b61a1ef591d68eea5b3b0822e4e02281564e5b06837e8832f4f0216074d90649eeb2c9e403aecabc255a9fdff4f43ff8669cfc406b4e08c377ddd2a377ede89ae051231d738cd23b0d06dc837d38b5013a2eebcf35c68f67adfbdbe364615a88a30e3936385cce2af7f75841ab69a95796299c7e", .Okay}, + {.Lcm, "e32a4678a7695a50ddfbb4120d557100ae2608f1cd1f86b7b0339ae278e631810a1703c59a59a857b322722e087a03e6f57984430592424176eeb623ff8bc9192e63a385ca7c41a08469e4f17e99bb3ee923fa850d3cc211083fbafab586c78cae7834c6f149682c8fb3449bad35fd295c97077fbb11a9f991ef13f1f1d699601ee6498bea2f011b6db7c511f9fd5d1ebc3e23842b03", "-209f93e3d29c6c9503a24978bf4b0de303316672cf3694b92d6d53eb5fc88d759e55261d19e66117c25907f45eba8ea9f60c26b75686e46df0cd2067c9baa5470343b7cc3ed9bf37f409fad5675ee42c06196b495f16292309ae65c64961189251953faedd22377d3f4089a98f1ebd4a3edb99ccc7566ebdb8d900b2e03126257347c3c043bda592820f0787eb5af28ca71f5c1b1e0f", "1cf2e34c49b466c320aab6ecef3c2ef9f44f8f66796bdd3fc0aa7478855a5ebfcb5db6daa64983faa19ec5eb7239c25ef4d4a6ffa05d1130a17a90e15080001348d455fabfe4bfde9e5b698b68eb4bb8985d650d582ac54fe11385e496164f003e7a192889e0af8c231ad2052232b3685e1ef1d8e2bd146c97e7b996036e18b4ea3727a439e7b36c567af1586b0365f1a17424b493368e58588ff27414f5d71e4601d989bb5f31e2b119c03873ad1040861ff75a013fa56aab44d783b01384a878329fb22f18b0efad54956436aeedd3d5a98ec1a1655e89b80830e522f1652dfee62cf4536c80458f4429d7edec70743a6d9041fcd50cd3b2bea10c09d3663d6b76e3fae2cd9b77e04faae8545be2fa33aae2e324a320de6a731e1149275947a924c6561ee1b8902f19df2d", .Okay}, + {.Lcm, "4047fe322c0588da3823ba47cc968f7debfdc28be834e0c6a88c2a333ff7058df926f1644d30d8c747d906ede36d6bed8fe23090f85bdeaf1eb0dd44bd54cd814709daceee9f1b5b11e45703f8090f044b111de154bd61e1b7850aeb371dc01b2d2044c94f3f7dab1e344cd936febbb7ce3e26d78cb2b179615b8b5fd130c3858a73c7cadad70fc1280ef5480bb1ede6b7aa5df6cbe8", "d6cbec05b19e6bf7e3e634f75d25dcce743f122ec003cb9cadb00efbc873fe9e2ae7e3ef436f9821cb663858abf3f17f71c9125173b05343fcc471b7abcf9d4ade9da8d49d6431040f0ed8810a79484c4fde2b19d3914fb159ca141d945aa6a185813b505bf1dc90a5f52ff8a59f78f9a31f980ad6585038b9e52db66a380eafefeb206e7b5c9a13730d2b29604b29f13c7c2124f38d", "35ef62d84eed4ea5cf93184a80041712473c3d337e062a017c7a7cc3e8ba127e642a23ea6a06c916ef360a43dbdc167e626a94acbd729ecd68369104b1ec7a1660ccece1bef6efa88bf0c7c707ced7f02b3cd196e75ba39bb75618f884a951efcdf8e31faf816454c23d7218ba3345f0a096084387fd44549d7c4532c153907f212400946175bedd16373f94cb021346b0167c72d2c92d9329c4c0143b31af6fa3e8fca4677dea909133c6b44b37f26b3798053beca098bff8094cc7486f4ed3af85cd13e361158aaed8ba90e4c097f5b79e35100697a4cf96d8d3b9124ee9b4067db90b65b73e5c7118070b66b829bb1e63a8cb7e8fdde181fa2ed590ec6326a53ce55a070cf817601b61c5556edadccb7fd1f9a09922868abc31855e4317f743a125724b390b64991b86c8", .Okay}, + {.Lcm, "-2b2fbff7153091018737d727b4b5cd09ba77e2c77563f67f988cd56c5ee0c271efa4e8cebe10cf160634310c22911c554e520c385b429904a4e3af5ea765be51cd6332c908a06264db19ea2d53e04c0c6b5b1269a39a45f06799b94ed4a973ea9051269c124a5b0a40f09d22ef3902f90b1418d6eae611ddfbb2f7917bd99df9fed1276d84aed1455aee9f7d7a7d1492409bdd229a1b", "-81f6c7d19c3dcd56cd9c58153a8e14902f1048f6b56eb04637b072b3cde6a7f91be8082833c7b142083e44e7985faca0675876410b64af386026b5585eca8271db7fd87717b1b4760099d1ddc81400a32a865ff1b175c9be09cc689e0031870c3663818bd02c8ccb936a2550accc413c2a2de77c012c6daa7b2077a910ea9c08fe99173923e464f4d87e544603c507cb642c88343d34", "15ecb15373ac25ed5a364005e2913cd4ec718f940695803bf86c6e678184c7f3342c419aa0b4fee1ea7bca33b1b2ac418db4bf2deed6d3119d86d01e893299380a30c71333bcde39eb963e4d46691e6a08dc0910c535e0692119ae3ec7b58987a51e8a690c6d66e9ab95375ff6f6ccc94d274e79735822fd95bd99a21e69d29ee0c7bdd35702b605cbddc922290a208e62cdd368ed282db9aecc91c70e6d8d1147985d328b90fed47fa33fa43d701124b81ea7f02746979456ee95f7a0c0a54b93d28c66cd1c456482824e48617f107cb3be8d03375622829f3fd57af4a9d46977a705e12c9084454abf46839a0cad07562711f4b4783c8399ead1933634d4890c52a9b479360706935fd23a3242efaaaaf2a3df8b64ed2dc3d9942411639b285bd7c0f06acb98e3cf3bbc7c", .Okay}, + {.Lcm, "-740ea4beb555998a6858574d3483fe26dd319c7cfcd1a9f558767f6d67af45adec510f1acdcaf4f085b5410e8fe6439ddb01d51a5c2873e23c3c7ecc12f9a3841a2caa03c61bc7b8c843ebf24934721d274c09cde037178d9c119fe78995e2375091ccf13afb9e948e0a12bf454b5bc0d6f35c1095961066f9d464fc303a1626bbb024e5fbe674f776ad9ebecbdaa26507caad6c8455", "-ee63ad79ce06ca7210190bf526138783ba20f7420cdd04c46b11d6453ba00323f56f42f933939b75353184983b1d8c5a5b41da8451ee691fe2049ac041492e8a8b00e1170cecb4a5918913d235e07cc3b9bb6edd9e079ef65dd13c11a46adbd4cf846da365398be0a2820436ecd5baaff8ab76d68499f6ecba6d2b7936391f55cce020af888f2da6ba3a7078ab218aaccbb2047e6a44", "2406447d5fff1abd65fbf1a8886881f1dfd3d6a68e3351612ccfb8e252ab609a7b91753b26b09d4a0e2593c435b6efef386bc414137585c6e2824f5a1c1fc7aaf7b286002b7b454b222d690cf2727abd0a70610962059360190ac40ca008cb45079cec0f02f1b70f53049ae9a28fcee3d45b02a87bfdd3a918ffba9760a8c6d8c19624f8bf6d9691994b502da6b963869d885d23982aa825f62fb387601cc50a79328ea2164beef5feb8e0b6e50ed80947aaaa7434d3ca5f93fa951610fec10e6bab295835d74d6106d64acd1d9a9da8ebbcc7a587d6bf2e941f7f59499fa7485d979e0f45dc6bc31fcc7fb9bdfb942fd91008d7b362b15079b6714595c1a045638b905618173e20c88b333ed9f81effa1db24dcbdf91d705e463f7a982bb399d52eb9451cacd1bdd1d172dc", .Okay}, + {.Lcm, "333392528a171bb80f23cb2d298d5dd5fd260e1f4d6f9656f05c81fec609e92dac4bfff0fe9bcb99622d742aaa0b1c9c0f66601a58173fdd8b254b59b3150cbc90096954b366b0c311471c012fc35de2e593232a0b7c0a3d015419fe1631424ff3e71b3723382e117ad7bf3cf9a82bc55f4d5d43778c6128770f3f40e333781bcedd5b3fd0431d44b8c2499f0863a39e54374b7b1f9f", "87ad5bd7ee803af9cc567c585e1d8e739cc60ad81368317e7c6cb8e1cc27195f5f71be48bb083805ba3a16e47e74b9bec17caf668e1fabda02fd073af3adbaab1e970ac16b8a4da3fb285e8da8bcc79c944076d8ba4bcfcf476a26f7506b5b08058492582e7bec04bec570e174a53cae6a7a7f1c9632c3cdcce474a113e3c0c37d5d83a0d9d7596a4081e37a62a894dca19437b075fa", "1b22de61eda053418675c1fbaac5c22213410a5b8c56d651f78d55980eedcf9e3db24c4018c77c84cffa187d7921ddaec0ef68ecc429b4a9572617c8ff7112e28c3d973ff76d20f291100e2d7bfca8437365afdd9490db34e2f791f9eb58afddfe1479433974b2776b63e35fdf37a6bad97eae1d5c5d279eaccac985a87628d44a28ee985eadf1d22a12a9897d09a9374d0bb1599165088fc74fdbe1450fbff9e652ca918e699ef00ad36c70c734743c215d21d31614c1d601aaf173b1f4e405e54beb7857f791658b7b47c6bc284d42aabc6a56705b16ddc3f1c955dd0e7329c28fad14f92a5d1ddd1c5af4cad3bdd2e7c6ddc45a7935fd5ea5739add65eeb91f38152079d03ffb6a4aa53697d0363aa483d113aed9adbeab15d2657b95edcafc205ce6170c22dbe2008c46", .Okay}, + {.Lcm, "8368fe7df2a321e58aec622b9d3c25e2431827a76ebbcef887fb220dd6c06715e49debe6213b361153fa451fc3e18ad0fe072b474c19968e788c6dd386423bbe6d212b24e056c762dd9514dc9062a9cc5bb4d2839e33e842dcbd08ecbe76b99146f8d3523108062353a987c724dc88bcde02802c36bc69da3a5d40256cee30f5dcfd642bb7094913e642577a6c8ca183656d0dfffcc2", "-ec8c07b5929b15f5fea2b98905864d16a1e9b63423def6c8da30776e5608b7a3050a87d659ea0c45528ea826711db491d843f81531e2fd3130373dc832b1457e19a8896cc70560a07dabfb71550a63b4df898c239b1670bc38ca8f66c9a888bc6383595cf898e83841f17091ec5904118b81307483b692f30fbcae9b3ba003e07815e960f98df207aaac387cf7b658bd0ae557063986", "3cb655fe2e00f9107b4955cbea0deb1fca6030babde242b094160face961ce8dd6a1096fef5b7aaf2cd196e6c03d7dd67dd8a8148ab3d5d0fbd692189a2ad259692b6bd0d423ddf20f2ef30573f38c7ccc76da64f09b5354f9fda40007fc4b3e30ee42d00338f7e924fd88a17ab1648e0d4ab0effd23baa91b8ae60f69958a3a448c366ee5b76766f51446b18778010845d67c9b069213db4de1202a2b1c4568d9da9fbdd5f3241c4ca02fd94ac1e037a755dc1aad6ef975183c316b4d038b109efb23c42d7c901a956df823bfbfe11a3ddfcef96c5d0b3aa8b5ba2828d08b18f28aa36d3d14a468387ca72cfb4288f7fed26da8418bde17d556963b660ce3e9ba769eea92b55e380eeb5864786968e8f8b991e78e38eb517398a1a7b6af5b4e160be20286e1afd196e8bfc6", .Okay}, + {.Lcm, "26c162646e8a562ac27de52f49a30f7387dd1e5565079b94db3beb558b50b13ddc36811170323ad28cac1138ea3a5f05724426cfbda34e986e252a1ffd04885fb0e199d5fdad4850aff15ac32623c1486db0242d7e502b08441b6694223da04882d8e8e345c4f691d50e928679e642f626e684fd544e8537592e34fd5700dad37d24b54c886877ae8d6bd7bd60ff6ad8e1632bffd6ee", "-be4bc94eb66d282c3369364f839ce37412f5fa851290a8af30335c0a7ccfbfc8cc754b312a7e0090b4e20aaeea6d6b9c3188b027d6247dd68016475c4bf180f7913ead4875e19eda61c9e1d3271b1f483e738bb25139462e6841ed78ff11ca773118d25543fbf2b6661777b77a2ef71b168c558efe66c3b571b61fb59b166748b035bc6259d5cf05460889babce9e6ac2c91d941a292", "4cd2ab15a60510a69bcc94235044098ee83e9c2ea1977183613ee76bc1d46802e8c3aca863dc5ee301d509085760351ac4ba8a76f4331d78fe63495844d803533e1c2d5c04fcce982c23f18b64125ba9ace76acc2985e0e3a700bab0db70fc9643570702c94b3d7452891ee58a7af0b1697b60fb3298ba9c353ad95b908668867529a5df069eec53d735a150a254c0001fecd5d197603ed350da0ca138bbf6a471d4d17e92d374ab1f744b13643d3e28546ed7c6e98b9f84fe08be843b690d5678b84fcb8fc0e50801b84ac2eb0fb180e5aab0f15bf1e4f416fafe8516ffe733eda28a88ea4d55272b2ef728152c8c6a3c1a368873ca483e44c2bad5efa9c51dd0b1a8133ec4d4995fade4c5db676b53ba79b95ab67b112868fffdaf5760e15220712f519977f0f0d0edd4a", .Okay}, + {.Lcm, "7a91211ab1da028f472bbbd25d722d7f68f5ebd3b6913634fcc727e481c1fa4d8a3b9a08a328eff6ed2758fb0e6dd75325b7f8fe5e1c4b64d03bb4af5d9c88726b3f34c41f9ff25d89ef98db429e6045c83622902e6fabea98cf4d0808915a5ffafdb26d244ac8a8fbb8b5874dd4f2e56865e89b9c47c5deea4df1d3a3071d0b329880d81d7bbd959684d82b24949d759bb2549bbb6a", "9f149f7d985ad29ba8456240a983c904b9f749a3eedd85ed8181c733d99b7f009ea1c684e688d405e2c3a886d8164d697a0d795f4a2edacb279c4c6279f1be961a4c3d67595e25d1ccd46a84e6ebbf9990392a2957c229b53f5999f8a4c13958be658f3659aadf1bbb15b862dd3a7c61e3a1acbc4aa64bc1abf44a5c9107080f12eb42ac29859604369b8033e22ac64ef9a792e6aa00", "261501a137f55950c001aaab589e0742c5a8a2f1fa0ea98a575d47f5ec8216ba94d1a27147fdf17cbb40373c399da6ec9a80f4d8885acecde80509db9ef389fd6a9e0c8ecdaf75f376e67e1576d8c1fb3de8ed2df8d780d21a5650e2faf17d4d07071e74e64e58ba6becda7f070b67275f500720e7c6a5f3a61784e860bb212d4efa68a8377029e3ef802950fcdcaf2ff28ce4603af4d3a34115ea203ad8cf2a8093ce6e9b7bea04a247e2c8f856439f5cecdd413c04d81d956421ba5950cf5c682efa583b583be56b5d0df4d5698a93f327a66eb24b5fe06cb7a62917b64e17d212a161d207e27a764da19079470ae478b02c4100497a6798346efef90afbf8908542585ab1e9b10f5df522eb24ceb64d87e35293bedff1db654fa5adb7f5b239556738b8854e911fd83200", .Okay}, + {.Lcm, "-dd8e21e902844b7b4f94e1949f410bf7752c18fcb2475352884d7c93419eeefe696e1dd2a11ef496f26696bd72901480e61b8ddab85839f1bc1cc4f09668d05fed8c84c0aae337222dacf8bce02f4fee2abc13289c6a45706c3b5446251015d23c1b4f62e92b3c293f197b6890cd332c57ebd89aebfecb012e297fba44b29e2fe7be25fe28b3c815cdf967d4acb1302fb2627dcc8a8e", "76e9bc5eeb11187d84bacebfe319381937f8eaf72038da3debd0dde89023d643da7082733008ae01f10606e0793ec7d0c3ee7e1d50f26de71e9b6d16c4775e221f68ad168f64c3b373a2de84738fb3a742c360c2ba0a33ef826f49aa6eccb1e3d45d26bbf3d025e3ed4b8ab830abbcae56db57da3ec2189a88af48346cba1588ae6d19aea643165bf9a27539556c4faaaec26de948a4", "3374e68265620daf5c14267cb8317ca5034db1b0604e807337f6a9f7f49dda9c61ac11f492d009bec530040e3f7035bd62cd9b1c7f3740f9717d7ff078dce3f439198352ca7f59204c61d21c94bcd05a848fe0ede0d502fa8dc7df477576e379f788cbaa5093d156d78db6e7b5e3eeb42d9ff86863490da7ac6a26af2e80e5d382f3ce6e56a2131ed40b6769b7ba8ba2039b892a066d526c65ac8c82ebc226ff3d493df897a194761a727273bdc34c0678c336904e24af55e33dee8cc46e2d181d75e5bc808e91e84c5e53bbd4f3dfc690082615b6d6e89119595e3133dd081bf1100fc477de690e5fd2db0850fc9e5f66023ff8c9e7e329be9fa1848938f2a4194a6aa9cfa5ee10d5ff8814e6d289e11e199b89d56c6506681b6039bcd1b56f3c908207e1b40a1f579f597c", .Okay}, + {.Lcm, "570a9fbc3b406094602126b8e1d425800443818a49a71ee1c05ebfab637a2b5b6fe313be6043c08a31ab3702232ffcef959b2acf122ad1102a021ba57b86bdf16247a6d7ee2c6f96f8a9b04e387304212ded33bb3ad297f2b1bb604ded5982d4677cbb95db53f2fb4fdeb2343b7e6d5f49943614b1bc234c97c1eba0f5fa514c205e5e1ad27d35a17e3d7f3cb56e0afc9637c5854369", "-9fd35c1ca26fb9534721bd522381d2fbc7912731540e2d3f48a9d4b486fa59fb125af83193fc46ac9818be6c06eec96560778d624b54531955b1d339765ea86635b1a2c23eabfdb3cdff6dc48cd65a67fa8f29f84b9e2a88080c28e7ccef4a5a716021f07e0bb6583ea04cd447ba1f1b9022e8db79926938abd98a21203d5a831c6110e8d8c1d67d481cf780aa0b39acc65f0bc0c123", "365776491ebda5a0bdec5f113e1efd06ec9c3c4fc24bfe593b8f8f7e0c5604ea9fdbc3789888ae85af45dd1141830b5f7b91cd9660a7132accba6872e6661484c83f3b00859f12b746216fba4b351d5018a7bb13b20e4480fab003d1b0ba074ae41f64c9321ad7e924ca83c20420d7743a7031372166b72a3edfbf1805ebe97edb8599db39c46ca2026066892953d4f7042ea864cc95a69b98a060380e21e76085eb55600d31ea3b9dd19558d0f239cde7d59f30eef8661ff21e0ef5bfb18d0580c6b27ee6f5d60d279d9e54c731668ac454da341d3aa058b8edfd9bd64731528a9ff809507bae7191b8c501061b165b47f074c1b4f3b44d3a2b9d0eb7e4275fd725591ee56b2cdc9379d6486a1e29509442183a39f9ab9c8a3832ffdff373ddbe71bebf073cad588aca605b", .Okay}, + {.Lcm, "a16556addce05947773271ae303dc1cc78197cfb049aca21107de19528afd7c2a0c6a93b722f5279c6cd6598154fdeef27eb81b6b034c99fc6e7ce40bb1e59d2953494ab932e4b6a1b1a7c3dec31d4f0262431e26fb2894b3cf94230a91660b810a6507acd251cf40a480bc5c7d29348cdc45bc2b34d41f55a437580d2a38143ec29bc3afce984a47948efbb34eead24206eceef39cb", "-ceaf2faf8b30f8cb8a8e3187bb90189d52fcecaf5d4c0dd3d912bb97bc65e2c1a9732638f36c2743698cf073c6e0eed41eea818cd7f5334a78341a8daa6776a3dbe9a763d466bb013cea3f41ee3a2af75256b9ef14a9970b13ac47fe1476e2df30be9027238891527b559e2a3a67c1ee16aaa9dcf2ecd89de51ea491fa80a74b15289cc7079853e7a7a8bc360c7356cc2b3c2c8afc1b", "824dfe166f879786ddbbe43e6c8b71ca8539a9bb060a9c772f1d73b16c3bc67dae7922f7a3b68235a498a43f496bceeb3ad4d52a0a64c097783f453e14823ddf8a43e931f6f658c26f4011a829058ba1385b21ab0466b5e293a00f7a12de33976d5c2692edcc9ef2edcd88fd5d567b27971333effbbd5b3f2dfa2948f4d7cd60e7e4ae2ca8ef5be11e4b48155e640b0eb1c2d74b2c06a752e0f68115c8ae16d17c5bb1b3bb75590ce568fa3418746862161c087cb0883280e1201163613254565d80658c897e94c297fded8af75cea8d39d7b526a3a8b856e91821006816b2d088c627c59a9c50b5f284f4d3c7a48566de992c1020dfece44c6548d88d56dc1e1fe03445743334c561eb7e5683214adc146bbf26dc7ffd2e95e0a8a550580bff47ff07a04893cedb5b8cec69", .Okay}, + {.Lcm, "-a3c50dee69f0813555a83694d2580b46eff4b60c6a9d655d213a875b771bc2a162b69b6f8fe6e0ab17713528a9791d80e572dd660e47bb9420288411ef8691bb183f6fa0760a781c97b700a80b18c7c18b4810e7b9a7c4440e3d9d0913a06727f7f0a29544907868379eec573df03accabd169bf181abff483672cccfb216838b87c565fe326e5e8dc2716a1d3c695baa82183650e3", "-f792382ca9db84d278ab9e18bf8c4239fdc3662d1be145f1dcbf72bc5a1ffa4eb700ee5a3342538a44f26618e0c1aa033e861306725d0601ca6a1494629b765869390df312a293fc7dd02901c9c778102d33c6c9b668ad11488b33078cbc435c7740c2814cafa92ee5f5c25e2479bb324461fb944b02bc33c1aa91ae46858e5eb8dfdd634ed3aadccc6818d43c9ae9e82e95dfa0b6b7", "34cae39637ebd83d8231a5adcd6d74566f0f42303d3ae2241d6416241d9cdb5382ebc27a077aba1bd75ed8ca24fedc831a0c279f14d736d50f37f41f268b955605cd06dcffe97744c7af57429ede072b2542d988a59daafb2cd9cf915818106861bfc8df9761f7f118fdc4f117546db847d3f58ed21b5012b72650db3930d57cd30cc43dd2b3af8aa131c670363f3bc7b01f519efc5f247bbf1ec91aaf8fcf6b3fad7cd4ffc49cae52e182934c3e158088b4350fa57c78fc527718e272dde69a426e4a1eb4616b530b2bc21da531b0a341b9b7bcbadda3a929a11c63d1ec676cf18f419014bc1a4a14381db7e576722a6d7dc0e20887b82d8c050db1600d003185402f5730dbbcb7429bb385435dcef5c0605612144976fdcabfc546e0535d43b3d227561013ae9bd11bc17", .Okay}, + {.Lcm, "f43139bea292a6232a1337a426f2263c25df9ea0dfe5096839d95a0da6bac72e787729dd4c34e54b98987aab2c9c938f37f5bae755b9fef41f06c9faf11d6feb90fde8455cb55ce21391a9963ec07921a18029a7e54ff6c6a1063d46c38a09a0ad33032dc9e249066d727388971057b033a86e7fe91204890e91ba41705f04fd17ea73968769f5920d3e69423c6abc7ce1d9f6454ec4", "-287f1415ddf83c214568ed0ac945af761a8bd67f962e9bc2f213d4d0beeb07d5e2d0990a0c2c92593cb25c53b4ab11a9fd8e39724d94c170450535da987f92287f2758198b8b5fdd9ce4e8ab1c292c0088a675681c9f1e4b5c3e974f71863c5b9c85e7c02eea82dc77f23cf7abb3da28f3b96fe51c6b8272b76702b964b7a9ff20057a6def6c425d4b5397630b4a84c49cab0a6f6110", "9a83a2688d05e7c5f88f48f2253bf3c29dc6532e470bd0cb113c3538879f313c888105b6cb7b46125edf88496b0cb090e89b56bd68433680fa663a6d59147abafcfb3e8a8f3dea1de5c73db4e9b38d11520bdd9070ca6ba19be1eaf1ccfbec6e7f82bcf7f6dc9e3e4888ca97aade714351c50d099e45e0f72298083e16165f59320f12611bd2cb041a0f05cfc77395a27d696165a26a4b47eb460a4fc8ee4b7c2d7c4920651f57c92bac4664eb9cae9045cb9df43c7d02a861793e5c33de7c44eba0e32c138be172537979653dfeb7af353261b93432a465a484ca740b0a4bc6cc1d1b361ae4255750f7745a1c2352b17bc8d882a908aaab94726ae921c63caf4d76658804c7ee7b7145b819e45777d0f7b4eb2a963cb83e2ec696a7899221ee572ff03a9374f7f1d8a4c10", .Okay}, + {.Lcm, "f5a09ade7e7ab10832a1542f5d6e496a28b9af651dab8f1f96fce3bfd088f9208d588ecc9153c61924ade45cc0345bb1a2a251d43ce118d554da63d794e28dcb10af0245d2f87a92b21a431caece17b12b4a6742630abedda3c3eb05f5bf09ea9c0898e8d4fdc27e424305c08b339b4dbac040efbd12f5f3801898b339505fdb6731ead59cc376ddc42409e39cbfa16f403f9f211bd6", "-41bc689d0c87bf3ba9ed0ae53ee28dd4f1683b3f398af8410c09790ca1efc20a3611735570bd54f8bb9eed580aa9a130fb070847627cee3e7e0d3625a31f2236c26f6396dce8bba966ebc5c8de69b9a6301198c869a69f5a3daa1be4962a562ccd8fd2d1758caa85bf72e7433ed62c038f1d57487f01d178c1c4b236888a8f7a67125ec6ef0bacbf7a6629ab5b973a8c0fd7fdbbe9c0", "1f8946d213f896a955f3533bad9da00f9e6268006ad0828f5f671d868cbe400f051787f95227a18cde90dd10730cd70faf75b96b1717e60a130ce9c33370d0bce2b253c8533d0f8dde3d162f64264f970b33ecd52fe3501ffa7eae2c5eae03f4ca9bc65375cd77c6fed1b628123eed26f0e062d8a078337ae5acc4c9ec03638df9ff984c1b0a654929bfd89bfa641c40e348805854ee4de8b37517dab43eb3461ae7b91edacc24e9703232e2ffad93dd19938bea11512f47626fbffe27f384811dd046fe399342e2ac7c12b3c648d6df9b3240c51852b6db188442e147f25fdb057c3039b477d53cffae084e032a97cffbb639d33db4933938fdd14f73b9054383f1e34a0914088d6b25965078df1fd778e6316f082de8c2bf75b1a1221c4f774e27c5e7b70f7bfc273e5340", .Okay}, + {.Lcm, "-687970a61a8c718b36744383ec7a0d9809b0e39f41e7f833bf54f56eb8d1bc4f319e159b5079729ede91c941668b201280ee88e37e58a7387cb802c556957083e85e9c64b568f4b2f5e1b20512f0d21fc9d8b0c1e5de50274a1ef69726a2cd664bea3e9e7fc57a664819848935fb55bbf0fe789e8598d831d2a292ffde93a0b602cf5c6abf307075f86c439a6b75a7ba027c8438f7d4", "b1994865cf2e71257cd70cc562f4e42ab2e67f17f86acd7928805eb7977071c73f7336f8975e285c42ea8fa27b8467f00dc3979b1cfce7a4547969186ad8effd0811efb3f116ebb297c6d9207ae4fe49b33d2d072d4dcab4175473ffa618a6398ac6f9c22694d3273bd285fe71319319798ac26d87d9310f51537a040470c926f15f31bc8fe62a6439fae76efd5cb88921de52c2f903", "1f579376dd4ed2d2658178313c2bd2d469baf43519e636012d9609f85c5c5be963bfe02791ac26577ee06faa857e27e316a31209a0c36655346939c039cfb40dc0ac061a5d273397d188c453c3ff1036b0f7ae2fa807bcbb0304ff20a1f3611d29ae1ad16c37ce13bc5e79e9cf98867fc48a349bfb8cea0a5cc8625de0c1b4c3ee63bab5300bceb8972ff7cd49c276dad3a7e0361eb4202d459c85d76cbe28323d9817e0adeae1e202ab0c74f4474696a413ccbbbbf65e45203d2d3370f2d7efb76547ade6629016e41e9a3ca66792b4f6cc3f6810fc2fd80c7f36091a057a8b8c7aef623360a48ea11749a3fa1235881f253e112a1bd46f01d991e88838dc19682f14d766367708f0268d26b54816f223e2792e9f4d0880cd13022d33c6f75a5d68298e8ec05be04a8a6cc", .Okay}, + {.Lcm, "17917e41661ed4c5ce51bc7768d922eeec7cd1c6196433c0572118cad1fd7e86bd8d44e8a52d955850aa398c2f9bf9feab4b98f589ce60f985de4c74e5844c105094015b2bb5e99d3cd33573fa2dddc687948a32137a631d878e562d72afe0414539c8fca90eeeba5cac0f171856083ca3925a8032c0c512054687a2bdafb0ac7ce767b17659eee8e1c3f8a66186723d14e6fe7ee45d", "-a37fe4f8e7f5f9c04b2974fa02976c2a8657de5ace7244e2c6f30bf643867296bc284ee77a06752ecfbf96b641766224cb5eaa788baf6ef9280b72dd04cb8ac4bb26605a49c488c50e4cb2c99440920081b65bbd0cfc524a473895663408fa41d335e0e86f343af1589da8179c3989ada4c8a1e8f1247f46569a4619981cd523fbbe49aca7c1325d0eb92516ff8bdfa6181df66189ef", "504788c97124269a67b5449bd2b978142328b0529dacbdbf9fd75e24da14dd99e67b503a88da6398539afd57e14a215fde7ff626174b084b19d7ff4a5e780901cbd79d2f6a70554bd0e1430b0d5c6c9a39591347dbe931991812768f12ece7c9b8ba4d51458c8aa81804f3bd3d139941e5ebec9828df170966d42e6558b2001a542468c05f08d7cfa75fdf70ca1e164fd99d51046c6d93b9eb3b8e86aa3c0a3cb297d58c9c41651a70bede4cb07f72de14c6c1128b3a23aa3af8bff3ab9af1f88bef9ad30f8b80849910f4409c7d689f4fbacfe7fdc8432e7205703a944faaab7d9901685a9517ddc6e86f0a39e5cb87ae25cf32c1c21d7456f6b7000964f9f7b38555b0498d8a1ea88d4f6fa23dfebdca9b8dd074de17e43d21fb13a3c26317851bb345975b1f821f8a7f1", .Okay}, + {.Lcm, "-16d6d7f0f4977d524bafca5ac48b8328116de6269ee71ea2cc0c9a3ac64b69fe10c504b23db33de9fff0f7f5e581304960d08fd035f5cab5afa5e4e43e68c5119c8fc291844646a1bb4d0f1e9c4fab73ce48262be7720c2faac922869cfa29c821259e943ce904bad5fc381f3924555cf588e39b53c143d99d3685a88b37d58eff7d9b463165a052a7277e5da9ca26dc3979f04fde63", "5b3a922f6eef9f0dd62e3c7e4205949566d5de5a2805bf17e1deb3201c989ed92654c41082b7257ab616992fb401ce2d1d8f3deb6c66d0aca7b78c67729024a4d234a94d8b07a4f097bb59e2421a564cc930c355c25df56cf1a70ea2d999a88114e74ca81fc1f62e4ea8c247ce1d093d8b1b7378cec13169ad37900cc63075d641ee3d9255f2fd5c4e30485dae939dee624cc077299c", "2b68828c758020d40acc9a8a8aa506c35c4af9c1f3cceef8c0d6ce532329bdadcbdd56c0b5cc4a2938c8a0d4b633779e838ca60e52ee6f2a7c0ca54cd67235ce434a7e54bf9a67b7207c6c03a2c029c1b08d617e365af25c83608b2bb2a9f17fffdaa44e8bf869151d62843ae84de2e66fdbeeea7258bdcc3bc49bae5589c5e29df9b8409f0b639368bbc93c7bf57b4b506f2373c34dde6a86e14047406990c07ffbf2606f4babdff24864db3040946e5b72581d4a777c7127ad3f787e289257f6ba6b762e9f97756a659c834f4296921f9ce0d9d82265afa91120bd11e307543f4294ff3611cde0cb6b83b83cebf55b5f6fca3e64042fbefd8fc6bd9c7a60b8d38403667f532f2aa0e11103a92da75995213a7f41a47e31b7646d642858dd92bd46685d5bc07089e6f751c", .Okay}, + {.Lcm, "77ea5151aa2eac886f3087d85afba75c70369fd50a9c2e340d87eb22767837acdca30e06634dd910c8812b91762db370e81091f8f71036d4b3770d9e5618f26fdf56579cd25a8f0b7af9fe8c59d69b32d9c8cae24f3f038142293112ea51e857293033b9a646cf731345c14af23ef68237765bdfd3c07d903b27888b403b3d8c61219b66385cc423ec14a4d904a0f4a9edef7ef940fa", "d8da9a71a588b19ded7d43d1d2afd51bf234cd8fd94b56b3d9bc100daece23af247405418b3ee25113b24b93907a9797e9a163eb1d3f06c3fa684d55e8acdd78ea5c4632bdf1c2654d65f3bee5dc904df9a963ce2f62cb2de97383f08016b92bebac7b0c3261d42a1a2af4ca0e05b5f8fedd2f268553e89b274f18c0256f1b5c2318c7038ba360e690a7d5271a144ce0d8f1899d150b", "65941a7e580560d60ea24b44a8e81011c17ebb2f055dc7280fd7368dfbe9572cc3051f55d1c27173ff723f9ec1f96172c3af96b1129efdeb4b463162142b2a7cbffd3a6c9c8526ae3c91f20d589dfbd5654cccff502b7c95e7e62262ffc8d5b63f8ad0f01e2dbc0d906ed840505304b016697cbc58fd43d9451c5e1a71a1ceea3777e065b6e41c5e54b4404f6b532b4b269973f3416a5d524d29c41588f2477166720daf3eb2637170d9efc1b6232944a5b1f4e7ad1191747376fe10f80fbc0cc25093fc473b31008fb43b552b2b10171a26d0b1699de736f21ed660e8743906767bb085d16406bf1989d7ded93a27467219388f933085d658ec5aac869f93ddeee82f34b3af797617ee41e030245a703074e27d0f91ec7986cad7a863cc6bfe007e060c74df3cb18a5c4cbe", .Okay}, + {.Lcm, "fbe717cd836a6620360d9c2ad699da36250a5f17098af3fcbd3436630653ed71785e02540d6669915dab16fe6ab793793060185968576151fbe3ff82ca80dee40853eb9626230d973d14e1ba60b69b0939e0f28ed68abc761883a606aedcf2d58add20b679dda54926fa87b7e652689408db5252f311eed942134e83603e07405bf34b72aa675a0688c6e0b2caf9eb931b5dda311af4", "-cf196915a537549db9aa9b70d0d8d4badc45737bac585719ebf8ff5e3f11da7d115bcb13458a5dea1226b2ed10871cad4791c3de2682799bbc886fb12e15ae53b0b3792d0732a4bad844a4da7210a37c0152440658ceee8a0de05c9e496049c6eb270aefd3681a4898e807c1af92169f782677f5aacf66e3ae7d576464ad0dce10856a882513632978152819a19bfa478fb1d42efd8d", "cbc8dd37959f80fb0a8d97df5ddc74a8e4d7dfe918ef11f7009aff022bf9a337abf003d7cf9415cafd705d48e5590632d6ec947a0735ba986eeac2d017651eab87d0b9267c440c89d765f9f4a9ba06f3a71ace3fc3c149bb3f29b50d9107cf15e93ec89eeeb584c47100fe5768d8729bcc84cc47acbeaae13b7c950778e5abe42dca02f3e8721015daf1a8ac01a4e3420dc916300ee2eb567c2fed1f78142ec39ef71af84cd5c6f7d30a05a1c853d67f21b6440677c91495e7b221941a0c25a1da42c74301da0ccc50e16a69b36117a26f514f098f842f481fd9c6886fb9fb8016bb3c9328cbd8a25d6e065fd98234e579bf0235264c6fb0f118e929d861bdcec6da1663ea15e13707135c62f97c400bee79c6d61aa0c8e717c9aaa6fb3b6accefae8701d14da12c9c86fc64", .Okay}, + {.Lcm, "3901d0bc4222e477af3f7d8ec87290240b3c4f32d0ab9751a7368e8a32380761953fb131a4e0b4e93dff047000902d2aa91ccfaf7cb57b2469c9d1460abd12e276c90060cd51c952bda69bac9f9862ae174af022d8d4b4fe481ab79eb76b3734582bf22e81591da4432bd31702c7da1dd6af5093e21d87ed270350dd436589dfb84a325bed844ec1251a4f06b7069f9e895ca502745c", "-a007f9bcb897b7f66fe7e329055670c79d53c72b881b4ad5bf4d8db024cd40a225b160158b7eda95cf9766c2fbf3e29ebb3d8a0f4f5f2b2a7b26bd7fa77f3f9503b9802b6961241cf628d4dcd943f0789f64b6501bff9b8555e3c34665bb88e5050ec35dd60ac548ecdc87d278222abb5161ec94076aada5d49fb9bc4f9d8130c8e4702566233c82d48fd6259441f7847e9a5924f4a7", "23a2e91f28f31b642a1a56432074b92a33dae0ecd90668e3ab5b6f326a9a9f72999bc2979a76125987ad6a1a491e5cef923c43bb0d0d9d2e143dee8fa58ad147262b318e58636af1ed4f6edd7debe13eb4e982f8e5a4e1797f11973a20ab742925d33a64feb88a50a837ca24d2b05c74de2c578d69cd14c105120c31194922d67ccaaaa84377f22ce96d8ed79a2494e001ff4621320326daccfe59a112c9dbd83c984f3eba46612f09fb5b666b1785ee2d619affd2e2d0016f652e6a8f56178a70f231522559f1afa89e787570f57c8dd87ae735e6c005d72ab3be77baf2eeba500f984134578a9b59d0f22c0ceb2ba3751de366c7c335a5ec9b146cf812ff9142b9ab68817175e5774f73cdb545d70612ab8b1f31b8ab2d48880c67c685e0d14c65af58fdec3eda54719804", .Okay}, + {.Lcm, "59252dddbaf7ae29583c83e93564e19625ed86fe01b9ccfe4aa693b18caaedab265ac00ec021d76848cc5c88ef794fbbab7401c2f3b704a112725ef18aa222eeb7b3229ca04b55877c8204721a91b34b947833e56289edfdaa1689b275d4567767101921ded52c329169acbae11030b273af6ebed56e2ba5e70e508d8e779a18d323bd22538c0fcf1b7b4186196e4ce6ba26b74abdd5", "e0533f42379003cdba6515d6835bc3e23e4c6a6cf1cb79b420a86347d60130d7df332a71957abe9b18abc1365216d42bdd665fab4350872c5e20c98f70acfb5d0d5f26fc2906d2ac62c4b08a4470af09582d0a7d00579c24b2dc889f6e4f1c3f8e14e56dd5daba14a4d8f2663378c106e14f03a04c363f51c05f30b76339caf8a59a1e34f99511337b87c26a751877222802bb48931c", "4e1d853717b4ddf64f6f8e7fe1e4cbba03bf47cefcb71046932fb0a4ac10d101fcf1bae4867fe413f21773ce11f7335b76e85cc5c44731dfc9431cf261af0664579a24004404bfbe5400be3eb4c157f40bb6f6cd082f27637e346d66b8f155430e8149c397f2e97e2b7ed6c649e5018a354ebb162a4feefad7f3d26ddfe90ec09aec76d93da058723833b6176193ee2bab5135325c789fdc144971fd1fa9e876c03f30a4bf253d41d04751d23432e079ebd20689636dd77fd606ceabded934844aa164ceee50ad2c80d18f760a211bcec08e43c2ce278d0aa5df108a63380c367886002bea148910c445763c996a60e8742f2345ccf5a2d8b3286042d7995039ec0186cf7d19e3a957b0a81ca5359297cb78e98dde78fa2825f53398241330fa9fa9052bde7080d5f216124c", .Okay}, + {.Lcm, "-8b5f09eb2bdf0220aaf8c2a6accff2b0ad36b771fdb11f0095a06a9482548dc10feeac9f541ada42d1d78a7c99bf02c1817af9752371cd4ee4c9335e6199e8885238c33a4c607b6a1d2b9209f5f81ffcc8fab6efb6caf929b7b9cef593cc12adad6490e79d6af7071e345e9e725f821598deec8db56e1d223cd1be0e316ff271354ca8c91a9f072cfbb2937d7a9d745cea50757737a7", "-de4e9058262fed6fd7c11b94745115f05ac6e980eee210f238932349d7582d65c46e981415f46fb2c26e2c5a70a57b839d0b67c640f755e4a386cac3eb540682cf237ca6fefc56c3f870f89a21efad805a6efc3a3495ef42b09b18d1903408505f141636ed8e8d87d2f72ab4eec806f4c44bfdc1934a896c5897f51f65d57460791c908b06a68159b9c099b577957e1ce69eebf8154", "7907302468bca67f1a9d0bd518253e56b6580c070ad215d06194aea393b001d19adaa2577be079d98c0862c7f0ccec75d169239a207e35cf3c7b38b301390a1826ca489c8273ecde673629f2d1b76bf7876ca94a43064a48977887b7281d03f73756fc613ec0ea7f90887cd9e5cc25d7939a00fcc3067261df4ea7dd8d4defc8e8bc6806c0ae1a19f08b4e46c0e4955cfba9f7ca383b60795b3cae2d6d47a1c547758df77728d4860050e78667b6b1f5532e1b316389e554fbdb682cb516c42edaf28bf507a1b5106cda839c9c720ade63a34c4129deaf19617ee3dcfe0675b63ea6c92938461146650110364c72104e19a41fc7209fb6a3e0f0e9e3c423925b6a2771ae815997fd2e2db74e33ebffde3adfcedad3fe72f23d7dc6405728be4df49709d67411cc665c269cc", .Okay}, + {.Lcm, "-f027928b5cd2fe1a2947e35a1ce1b82f07b94b39d45d6a47b396d7ed1d0ad38e05ef779c091eedb6659cfc68b454ad7af760653885b6faaf3d083508cb1847570f866bf688e2478924b2f7120a4b8d46d155bea1e110350c541c7bd3268543951003e5fe9653b3adb394d1d9eb392a4e1e1dd1e028ca6fac76e26cbe9191a3b642ae7d5d9fff088a3fa4ec7e06a9d3477b01e048fe6d", "7f5811f0872bd2a0bb6ffd76d68d2b7c1d08da5429fe7d4b09fff0c5294e00dad3c55663285240e97dc9cad63af93360ada06b2d07126f3f76b33aee88c97596c508866d2ea31815c732f174e5a1f0c66e258e3554ee38a362bc9efcf5b74305fb0b003fd054bd97cb45e446db7ac96d9a4850f6fec8fc3970b3086a0eb454489478ee2787ad7837205430942c6da95be9ab0e2d335e", "27d2156097dd10f93cc383cf9c9d6fe7064bc80c414d899d59c0e95254a866c0bd4311f63f9e5b535593a95fa42b713442746e2695ecc0e8358109d7a9c0d1903d148a0f1e9210905082a2f5d6c612fe26b5bdb73b54c84c44580b16b5c105ce582dfeb562f2c1639dc00b15284c77779748e2041dc1fc42da14547d2b02311205f40b622a381cafddf365f5bbed4151735f82a66d8eddf09c0050dd55faa5eb589cac95744f930b0084edc1b6178f5edcdedcd6ba8bbb1e6eb2af9a93371a1b0b55c5ab64203cdc91c202c20079a1791790e29205197c45286011af9b3fa6041f33f344be5847f588e4f16cb2b2fcdd4f836f6febfe5003f30da1802d910ba7e2899ad576bbea71dcca20a6f33ee7c98af32795aa1bbe51da8bd455681d6284b516b9d0bb23b44edc376102", .Okay}, + {.Lcm, "67b20120da59e64a9f0211ab8ec9003ef2a680f6e485331403943deb709a6959e464962371af5522677e73d0639fdc75fc8b9632a82525a762eec2188da3d46ad42a492b9e36325b8831be2e8666c08275af957b1526f37e6faab06e24b2964da369173caf338badf37d1ce6f8ff55573ae181f4fdaecc242cb9f5b638ecfb4b047579ff0d3cfd09033c9a9cd69853a2db934b907c26", "-4e24e045943b0700944c4661af8b325f34d3b8b83842ad361445f68fc47b2617cbb9d396e9d2002ab3c1a10b046473dc8ff7b0f287c85693d2efd82593e6829ddafc90dcbb08fe0dae7c1c899278329598dbd21d804238fad5aff956bb22cd4cc6d78da8b67e3ed5f870120b762fd034cf426b80e44dd80c16b32632f57f70d0598b28d15a656bb03696ee0a21f7e82fb7404722b6fc", "546875eaf3153df54ee39cac72739ba2f70704c683f555112d18aa8cf0d024a8e3013ed37fcc0211679f0475e4570c69c0ac104d2acf44beeb00192b97193748c728a7388dc9ef1cc8cd5e6b7eb3e9271a12991dd1cd5a373f7d585cb97cea0b70c93793b2f4a6361e6e31042a81cf0318c61443d34c5bbd1439771b80485151d4da15c35caf9415047965f271c0b383c59e735f5524c4c7ea1f25a318f6eea362f4330418a3877648c9cc2c6e8f606c7c839a032b5ab6b8b0a37769ed7e653fb8c7ddbcbb38694c55cc8a5ee5c375b864830b836355bc37948a601ac6d3741711417320fde071be66269f6859f66c2889e246ab744032aa599e7d252504b00d3cf45126fb6f96b76dc1d93b7bf0081effc72ede35ffbd43f40fc725afb47250c141514414c074e5aec343c", .Okay}, + {.Lcm, "98a5e88fd46f2aac53cc687fbc565d2436aef9c07d6f892adc477f8d35a3fc05c8149113d2624882e77ec9b6fb1668935db587f52bf6867c172a3f80c2bc4db8db110d4c523cb55e5ab4f706b6ec0dd4ade6e978a25c39f28022f5d66a690084b00e3a919178f1d2d3d3d41d11ee5a8e769f0da6d9437a5d6fc987e72bceb7229a9cce366b185129355261f4bc4b6a611e7292ce2def", "5a1a6341e814774e6feed708ca306e2cb3448d0f95b6e5a3d8216cc0ea1fca252eddfb0e7926f0aacc10f262af3f7f796383ca810f50fb4dac9b358b9d7560a007a0757866b35d5917e2dc8efedfeaaa6c549ece6e4e3a2212f503bd6b8916398db8b0d5436dd3048bc1850fd06e240b2619a1022cb904c0fa3731882cdab65fb5b937ea0c9cab774e62a757cc520b1df150e43ef0fd", "7acddaf60ad44f99b8c9bd76a36d6b6302a3efe7921d9cfd8dbab53d7ded3f72f8c97d501beded1bfc73e345a174241cde47bd621adba97cc969557944204052696f546693affa5ff4ab649f853027a74789930941b2fb8ab77d9ad996431aa0caa94ebc50ebe2738d171cbab929508079b45802aa2f7c4dd71ace939a7320b98d5998bdc8876ff514ee8b55a00b77d0c76e95c98959dc41016b66956ddd860cae6c0daa75030028be593b99569e831ad6204afa6c5a9f2818ceb441386e44eea8484ca5591c7fcfd119628c33416a1dc9ea2398f3d36fe0c9ee4cf504e112e56ab70b9639d2e4fecb0b60d1a7c5fbc1b1f74fdf6d44f185553974ea708da64227947844ff60053f9daefbf9b6306d00ae307868717e1d3501110fce58d3810b35e02f86f654a7c0d3e7e75", .Okay}, + {.Lcm, "7582ea3567b65b615f830a77579f918ed8f108d8f40369445fd0168c5adbde27ec35c63599c786b1a32eab01436f74469d2e109dcd942f6149df16243f866fe1722af20ce1804a4a4ba07e0cc8391859553fd244e6b225a831a5074b6929b670ede31294230011a41d73a76297873e0e679ed8361ec4efa076562b334f38e08cb66e52ef3f24634c74ecdb846855902c78592708cece", "-35081bfa6643996771a73c334a7e6c3b794a8d41b9ceb67f4f2d5ee30d0aacda9a1866145d1724673235225be48ae82558d17bb0a46427ebc1310f24ef75ffcf365369a4a7689151cc489e9bd9b7875fa1e57d5848732f35ccc852a5dca193bd9cc880871e1b5f18ae3603602235cfc8f0610596d3356317de3060394f85d0e405a69c9cbfc6501737881204cbb4c47d1635e205435a", "c2be9b60fd0c4da6a541039922079d8e583bdb1c3696a8e646d77c56372449c022f5fcd071df3a9dcc79bea54a971c86f5363b7e8902b37f4472884dbe063ade47f937bce52d648c365df6d4ea954c8431d26c5362adc27c635f0f7b242be4172dc4bfdb3c2ada09b223b72a29694660b2f29bb3843f73f6d92cfef30543a93f562aec2e365c080f468f817f0363cc13d4e7e94e8c1791fd6f966b5e3e5d0631df510a876fc9de15d9dc21e0fb0b344644eedf0e06b452c5a020e009ec013a1ed11b53c2816d66d892f66e499b9f1cb149b46f8507ed761bd1ea19e1784859d65f50af82427b872c0b7b44ee44dabcdc4588b2ee8f32c4fe88acc5e112a6655d6c8299da5c8cb2571a13612d23276812b485fca537baf75e89eee88f9f2ab909e96251bf541d979769f4f36", .Okay}, + {.Lcm, "86a1f7fc4ca77bfece050d517a64e072e4207b2642aa0512af5d98cc1103d7fb94f72f6d7dd9c9c45db6b7a7220dd41479889b419e7f440d4466f1345a46cf819e431785b59d39b09044d0ffeba9e97285e11ab775bf2eb5d9f4897cfd66533adb3de376fc5819b190b940b3d42f011285a93aab9aa58b0cb99184824cb1b9c8133b69a33f6eb84458f2c1aa009ee40eaac0df28247d", "348de8914e2b88471dfeeae379c5060e3e80f6ebd214e49cd599e4003abaab142c235d7898c958a68771018257c9da670456d37106edc18e6b6dd19651b42515f1adf12fd70b3deb7562e7fd6fae565d02e632f233f6efca9b6264b980ac76f720f5fd9ffb5f4230ec51fd753441241d299f45e8ffa3d7f720915f184ecfaa4c76ec3d6f918638e9b4bbde72c34631fc0d8fc3952fb5", "1ba387e4091e973d3998c67329e8e549e98b486ef6b2d6b8fa3f42532630013ad1c17be6b91c40d3e7658b2b803a4e4037f70f5ae4fd27b7ed4736c223a04dacc385815fb4732a835ea692e87a76e2f6c8e158ed0b5336b99475f597756dd82f66da8b5a51d14a63c042dd3507dde8220c3cc1dc25f7424988eb8252a169f9f526d51de887fb3c24e502f7794c5fc8b32e288171a59c42e4f4df1b7e4adbe5cf13e24b25914b9cae14cf72cd04d5b3ccfcfaedf62af3a5bbd082cc7447881bca97371e42931945682306e4abf62a38103484f03a806678e2d12ec61cd380a997ca71ade732c0bdfa71a4615569ce76da60ebb834daa829f7d06aa4d29796d995bd0d503e782a455a32c7c135101a0b591ffb04191a71ea308317490ef6bfb89de9603d8fc548545199d5bf61", .Okay}, + {.Lcm, "f297ed6b52d96db4a83c753af93b205aa9755a491d2d8d452dbab65888828fc02e24abfc003027d9ce8c03a12541a124ec25d089f6d8e9f50a2139caa59226e4473c17a9398a812a04cbf82095033c08b18ced123fe0fdc5d863e03fb63ba92ab26383278b5de8016113f1666299824de2440d8ef7291d42789725baf05799e527e571ac6de8b7a707f081297e2b89aedd083209774d", "-a4ec05a4a721f55cb1b4c0267770dd7448b50e7d0ada9600247b461b621ae5c2817f9d618cba9c1b8ef99f9ed84b0a78caaedde74d2e864b193051524442a48367580d986a1fa16fe349ff48e06c5ee90acce63bd5813018c23d4fa000845f21c9fe6bb8e7c084ece74078cfe5850d902f0ee157058cfa74e75d791a217db0c13896bee68fdee4c6004418fb11eaa708307e944ebd40", "9c48fd809f5c26120bd9835f32c33b9126d1e29bf944dda8d1c7ab961cfac57bd82b02b62ccb410101af70d587f20fb73d11101260e3d8ab79539d6b298cff1a91b164c55e1aa81e3fefb2b3c261061938e8d84c92a136b4bc9b0dbf88b793eebef2a83f3564072e1bfd9c82daa439019e3086bb1146d385c7a6f8d052f4303aafee3d3d039ae2192c6d685d09c116bf6bdf0bd104ce3b5ba83087354a99d15222c03622695e161c763eb7ee0e2289223cfe11db9067e3ac8acc9a8754488a5ccf86a98fa014bbddfae8033596f0c05bfbb7c901c26b8db8b07eff6e24f9cc193eeae0a3abe6749083d98db01d2d6e3a1054ff5c50c06f197ef210bfb922fe40a8dcee1aea0c57267952ebadd7c28b3f3a1e5ad2f4a9998d0a15d5137922bdb2e5dcf483f6c22ebe5ce7ac40", .Okay}, + {.Lcm, "-9da34904a60a48e0b103c6506e9f4c0e41ebcf0395d0bdfbfd746e3952f5912c273397c75ac63e2180b396fdb1f6866ed5cb95f5d0bb5b223b8fa6a2e574d2a84cafc9a3947847d704f87b0e1e4d636b4e08b9289af845317b5ee83a39f35a0563192a75d0f86ba612c58c4362a6d11f856ae8714f89bd3b931af862c658349052e93cf7940d937bce3f8673af5a3f4aa29666513590", "fe606c9d1d2c2edb3cf8f67a58708f1ba815b758a667ecddfee2f2d09a51888d353634776bbf3b187aacb87a37afaccbd532f545042a1a5021546db6135e2b4c7e10031158692fc95b4b043df4657c4dd28770e472a525ab3b9e1ac368c26d289a128eec118471fb9c2e06d4fed412f1e7d51933635afacaed6c48a1ff0301f3a4976f9106e2e711aea60c5e559eaeb6770bf87e7014", "2728d8a3e8193a903679cc2410d4a83384dda1982e86158f5c52f47a4ba5c52f2d3a2ef8f542b376f15b373aaab5dd95db041f53f93453fbf35dd75c45b9eba97c56d401c77341540f25f34d36139bc4ed26f4c03f4a61336733e7eaed8024258e2c03bd1555d7a0a91ce0c9ff8e8c314c5a0d99f49a9f15444cff5db7bbb318d2324aa581f25d49c66839065ef87985e3ebd559b2da1d3e5272e561d4bcd80cb78207ba64b487a75559f48ac61d0039eb313195f86026b581eb29f29f21866eb87944f7dd7fd339f2de5c8185a983ed260d4698765f3eb6e18c5bad31e9f9ab105aa83dcdd54686a7619ee7346f45279d8bbe9d00e30d85ecd850166b0db6ef9709d8e8883a821a60264da44766783015ec951828af386685b77d28fb71e83de6e156015af7b163d8a9cbd0", .Okay}, + {.Lcm, "-1d00fcd1cb2773ef89221ef5333548a98dd6b851643f056a5df38ff0e5f55c261717051589ea3d6e4df2afe78c206f723c5a80a0e99e7405b3c302f6683fa2f3ba5d202ad598d5869c095e1cfac884743ea3447367f4a3f3ae21f9564471aadc42ffc4eddd26feb868b0bcfb99a9692702992d4f57e4b701b07bbfc4025ba858b09997aac8907f4175aa971e2bbd66f2570ca2a4690e", "44c25cf09bd2e1e2480cefd3af1f967431a00b65cf25caa7b13fa2bb9e27286158f8cbe1be1368e70f30e7e3ce259a675079317d745e1c450dbe0c38dfb1c38b73fe3a61a43f602ff7adbad736bddeb48610ff694af0103874e425aeb7f39811945ff6c7ed9538ed241ce4b754365a7caa0bd6680f3e993ed4b3afad35e8a3b51dfcd7247a20c0aaf64864fe2e0f74b35d1d25840d8d", "298c2cfa4cb71f4035034db71d014e756ea6c533ef96d8159f018172e445c24803738294580dabd921c1afda6f182e0ed3d06d735328e73698c2da5d3ba8a29a1e40dbb34ec6ead7d3404d5ad3b0851d5aaae42167920d433eaa6f8c4cd4596b6c3cb8943c770dd32feabdb12e199bc05f092b071852cba6767b7e10315970812e0799578967fc4c74e1804b1dca8b7626782c9b8b9c42a2a2615f9f6b696b19d2df8f3d77ea684d234a36ce98510ea6752bc7214bc168ba3df78de53d0df9db253069f3aa3753f8cad3a171ad9f6ee5ead602ef5214e9edffdc86c2cf696ce8b871d9baf3312a2dcd01f8ed16cd23cf4d61288dab99c2279e60a28b1fe94c085d9da7fdae2ef000dbdb92dd18567880558aa523f771e4716328dda08df6c70eb7662fe8e7fbb965fb3db92", .Okay}, + {.Lcm, "3a55be124322f6ef5aefb4e4dba96dd9266a56d6d4a85f1117c54b0190b82a5636d44dffb16615f26bac61b5555a35bcf8afe49b68282fc2dc0c436149055df219e1316d6ffafd08a867b336329078b2fd516c08dd38381eba2d96457b17594ad75e010e260cfc8bc67e818cf49a6ec95c2e342d0720103cd44a6ae467b72fa95cfd6d3b40e2383dd991f17143ecefc62730a15eb709", "9938c7138bb6e29c10b7f373097cee9d2d7bfc5b6f89a6c64d65df0e4333b25d3069f4817c51c7da2c33b498d5852fe1b2b02f1232bdb614b5792eedcddd91f8ee5fbc95929f35692d6ad38c98bbfba99d889829f8b40f8c6870aa1782afeac504b6166cc7fb2f4ab768c3b9503cd67634560eb0b3a92af2551e367dfc4b3b6a694d111d128b21b695ec83ec2ecb9169132f28dfdbce", "22ea2eb799121d92888c7afb57f29a2bc7ea1376cf625213a8596f7db87fd9d4999cedd9967b2c080eea9ec76125571681d572cd2a67e9b412b5d82ff5a1b9f14a09fce91d51ffe8a6fc12989f135370a85c586b0cf5c823fcef6982691695966402f394fe2680e118309899a166279798821b61b5e762728454477eeac549a7b508a62e32ae6904a620af476efcc7d712cde29355a337caa141aeff3737a47cf676fd775372abe0a4a3dcba57c81b764c24eaf0d4a5cd425fe68bb5426b46fd1403289efaa7eff41299470d5058f4b9b28f881a8213ba6a902ed57185566a1781d012a3d4478e24206a513ac1134783d24f239c28943e78592523dcf3a631eb210b4092cf30d5bc1f03c2133b6187c4a8357b886064abf90e779bee386698dd0a0993130537c6efb9a2fc3e", .Okay}, + {.Lcm, "-cd40f05ee536ca354b0ce8192129f52253d0f824c580ab62ec8dd28b8d6747094e0073a41a265866aaaeb64a1497b1d0b28f3d87b62d253f277b21d8a7f0b1c869e5dac74480cf3bbd090c9dddd26f88f14188f38bce8ba7b31370a587b614af6377f5195cea8fb2d9e6cf7f987757962dcde8d61f9e2934f389793709efff3379d58c78a2053adfab6fe59b02314d1a51f6a04515d3", "-18ff095fa3243f6aad55baff96a5f4f8543b9263e2bbe2eb16246ac83a65375be1b77a2b2876accd9ea7b3e5ace8fd70ae1b4695664aeb6ef608f533fb971297df86882fcd0026c3b55b6907204438620242091c7a2ce896d173881d3d7df539716c131ba401ad2dabfc6b9f3877b5e09e1107d034716c920d380234202e9f2bd5acad0b70b48dcd0120058922c320a769e56d68161d", "140a91bc4a5d66d522de801da8573768e045eacd1fc13f35d4f38dd2ef13cc3221bd07660e2f804cdb3db22213225c8cd3438b5d0d697c5401cee849c576689f5452ba41b3b36cfc02c1e57e66f974933c6e9fbf7c59681ebdba9c12ce746a475234c52c78bd5763fa17c54876d9806d7585c284ce7cdfcc68c9bc70d32803cf4c9c0782d09a94ed6df5cf41dca1f8d7a4bccfc7713833f2b26442d973b738dc87cca98a237ecebe2404e0e93338a6de3933f4890e380771044d1311ddd33b22564e7392ed7f41ba25bc8915b0642041ac62e881e9f2ffd95220300c29f167cac77d800c9c2f93ee01ec1c833d972a8ad0b7e978688417b29f6b95a75f2291414420da29ef46538541239a0ba429abcb1034539aba2067d6d3b19dcfa461f15f552052ab9dda11d0cc6b9ae7", .Okay}, + {.Lcm, "3eabf6f215d606151c28a8dc40d95815ca501413051f1bded1167937d61e2b6a9b82cf4ffda76781fbc9b3dc618039e926fcbebb0ca7d1cef8a2e5f66d239b06e7aacc6dfa315ea7ce45348dec2881c6c4a23d55b1c3f98926eb6556624eee8cf3fee15a612ebb26d42e3aedb59512117e02972328db62c52572dc76dd1fa8cf7d08f97a772bf069bc45dce2ab6013e03e0da1bf9874", "23a8f411dec55235bee7bc851be3427d72b0dc9e6f63ffea830f771e1f49e7253c0d19d51d0aca064ae804359250a61f7a2c93689228e9ee59580a70e50032c3091a3f93a8df559d21f3efb668a2710c403119f025425fb200e8df5e28405c4dbc107c76763ce570ca48427ee3700a3b411e42d4b1c5d1b8da8e06ba16042f606ef487c93a8db0ee019b03a4e5350461ac140734989d", "8badf5d6f2e28c78660feb2fd24c37944dd46b4319a35f2873057d63d6f2ca9d37a01676200ddd72fd55035e6d7fb9f8d0970ed77ddedb8ad21cf066baeddb56d12a355e1e6fcd6e4e9657d1a5ede2f1874fe7af431e19328f964aab354921501d514dfaeb6540600b933935bfe30f4367a360215a546e55f95426dd51ddcc7e5d268e44709342069ac03b082acaa0eeeb9b9268d88291d5791ac5fea2dfaf879090843d118a746fcb5c08312a8740a93ac22b1bb06a6fb8891fcea9739d90aabbb2a74f9baecd2b1d005d7dee067ba93aa1c0e83fb290e7ee29bdc86362c20cde6ea48ba0487787c8c328f000a1c93bcbacad2bf153b8e3a5763fe6555ce242aadac8de5b5835fdbf2b1420acee1db8f687ff664e97aef1f168a83256fa6cb5414eeb440e9178c18955f24", .Okay}, + {.Lcm, "c8c0b1e18c3aa201ceb870fe0885213d92354389ee7ef821edb2560d437444e22ab4dccc562e1b1f274c2a51b1882bd6e4dc45d2ddb0d23f45aa233c6246d1e8cf509ca7c610133dd0ff0bda34dff9cea3a70000edb3bc062b591360ea4e1b355b089451a065c254149cabbc00c4fbf5c0020b87522220b0ee1ecf58ac58ae152879c8873192e1d08ad22f1ae9b3f265500d68e8da47", "1a3607c3234c78bc9a6085ee4c13f775922aa192756b419517d9920914494d3aa4c301c213bb87077f580d1d4939c5128cc71072400f0df8ce2030953b44cbed99fac37670ea44bf9fb2bcba3b8e36b4105df69558e34955a65da8da7b248668cab9641211ef3936bbed4a1458b698d48166b61a566339f21a9ce7762e97c26203ed9bdf7d19a54f04c11e03cf4728a131c5e3c78a7f", "148df0ccb92482aaa58d67a150fd03c6e38c206b4d5a7d80bbcf094acddc159eadcbc1a03f68cb01ce526f1066583520858d0e828df074701d15e254e7af557db74b842e9819c2f6082966f9ec6114b6fd05ac573cfada6ab129740869b6e56248cf799c6480051fc4edf3131cba6cbaa169d676c393364b4dd2c66fee6672c32cc00570778b4a35a09db65916d08ddcb888dc31b11dd62192d810efc2a9fdff883b50cc0e3b98c25bbf45271ad19f338e5a7e6d0fc2eb29c49a9aafa8367f66f91594f4fb528fc1753dd903b2d2c3685e5eb622f9e728a8cdb63b6854fcd96000d701a673447657f1954af74b2117c8dd4a44d0b9acdcb64312e6a1a46773f07eef6ba3f3993145fd2ffec8ea6476145f7014f04a3e42515e4e25b3bb14714aba2bae50a77b8766335f8f39", .Okay}, + {.Lcm, "-ec02a36eb36479183de09de956c897348f8ea090d093b49d68d68a9b7d56ffdb1e484a0b8e6e4c59d820434812735dcb34dba96d77f9dd62851c28e1bab811638143e8bc5610d0d5be025523c5df272ec307f052218bc7e2e0b6a04983c00f9ac2efe8073f2a195f6f2f8c97fb409380800a69a1057842aa4d1cd62f15069d4ce90a17c7678b5475036e4b19c72830001b142cf9c2fb", "47749a646cd9090d40fe708075dde017ca89682d07ee68dde912f656a8d07e7e510aaa6d483495c779791d9facc42dc4c56307a38a42029a4fb9bb6befe8a95ae9d785fa6cdf119a32b149ea522bbbe393c7591d7e844a0e8fa12db90978091da801a1bf543752b45dd13e9dc3275423ec208b57591330734d99bd85b866c572347b918372953c922aacb820732882cb3c6f37b98bef", "41e03adbed9bc9cca88e17a47db73bf7c78f7db5de2701889d59359e266280be7da92496311892e62efb324b65d2e2ea44f62446f412fbde36f96ce76e45f42b2a736ae2d4cc0889f8411fd84022eae2bd50bbf3c3ecefaaa028c8dbda62b18a646150ea1f3d465f227da23f9ac67e57c583313159d2fc9ae72720b47bfd0d29d04c7139a8056200c493d3c0d93cb27ae5375bec0e77213dfc4bcaea6a66bf92eb58f2a2036782e20a4a2e8e412c458f93a9c40b6cb3ff6e8d2ea5f1a4691cea11c00464c083297360dfcb3a9ea12b0316b71f44cd4aaa9a4b10ba408a575bc20e07dff92aaadcd0676706999e3f4216b2ba2b970314b2ac3d273bb7b17abd05b0f9855bebc69b3848303f57b79acb18fe1d82bfd6e4b4a6e191abb72704670839c6a60ce312c4786e6e5155", .Okay}, + {.Lcm, "-aa1203a5abb686c9858b6001a0553be888879a82b2a4688906a020feeaaaf2ba12ccbb4115f4e60dc323da5060e773e9f7e99c4f310a108db03584350645ac0bb1d15b60cf1a7711dc7257b87f2ad12dd04384f04f866837421920a5328c00ac7bb1f09427b40251ca4b0f9c3a39ff2a90d5a9540424ccb87db04282d3c7aa2fc13d6f010a4d4678c9a67feff0962eae6323f56ad8aa", "-75d42d382fd52ef44f8e88651aa3b829bdc8e3d353418d501625e99ee7cde442ed4e68154adcb44a54e8fa968bf7eb1a4d4dd886a164a744c8254674c067ce69101de92866b4762e6f86c3ecf7f162850a8ed373f7ab989a51c46763ab0791ac5ae4e15a47462f847c092bf3402a90d945aa73e9d5864c154ba6951341ae16c8664e7b8df2c9b9a12428687faf7982f20a9b8d88e381", "4e4730a03b0879085c9612f573ff04c6f1257a6c0d33072bd4b1264d5b42db2848d105a7cd9b1c34760a566727901fe27971261411666b9fd0cac7b2e8adc288082c3c66a5e6a1d61bdebced3cf62a07772fa03c5f0bf3aab1750511e85e7d793f11ea4d38172427c6cebf2ae6aa2693a3a197cf7ff35896292553e5e458c721e7dcdf97c205b98af2b2355cd13b9452e32b73483a677f5cf557574c5f3409d9286fd2672ab68998a9859f8bffe04ef09ec1b7888aa12e8e97b954118f4413c61c0747c9cdcbe81861e7641acfa3b8d5a1ac4b2505531f719d4badd45386784eda7d571240d6beb4d0a27dd79b3b5b0f81eecdb93c0e1072d3c5a699df1dbf4746e1ac5317895889ae27af764b935d9abf5c157c9021dbfc2bbc5d8586c0f29f65c28e0e89eae4c32545ebaa", .Okay}, + {.Lcm, "726288a13efb07378e5af8390fdc801635b8f80d0e263b4edbf76cec302e534736f4d02062e319e88eb1d126c7905c42c2a3fe8eb46bba5a8ca22dfdf577ae99f183ec64a5b0926a328bd293ba9ea737252e5bec93198a90cf457273b0a5332bf2d227d3fae03a7aa4adb7d4c1639e0346aaa30af069e06e1e398e91258a0676f297efb9e5be6bb011e6971f7188feee96dcf8ce5a2d", "-c54897c0e4c528640886ef6b1b8b26076ac69a9eb2e4d2f064eff7be0d6d08c3f30c3508c9fc59a5794236e25a9ab4e2e00a7cd7d1a881be104627b0f33184959d214f08e03a8c4e541d94ece07461493826c1cd4a8f2c34f45b1b1260f9b6dc41a231350a69af4fef540ba3768ef1009a3714dd6f5abea6ee9bb226af77ff9a1fbcc3c7891015cc08856c0cd093f6fdad7d066659f0", "582642a8d18651cbed86327c69090e7a0ef033f6baa700b7d9f1c98cdf084e347452636c778f7c3f6191fbc9c123f67a06aa5dd1d183e739a6d3da778429ac857922268bc5d34d59a867cb747cf78979804fbc801fbdbc54dc772aa54af6e4c0075f93d49c8f978c5bdf38e61a637716c3f9e45a137ae944864356e36d7bfe996722410d04df92c8d9f471e6dbdca07800568838b83812b42b666a1bcd12682b5be3935222073002113dbfef8ca37956c088758f33f6dda1f293ba2cc99aff735b9c634d851517f594a32561da8a358f0ae374e5222114c2d6d11621548bf1eb467500c2ed7b410172b447fa8b28f8be6e741d71d699f8345965bf684238815a6ef297556e816a15ddd3814673ccc84345a777978c598582424c0f4663ef44f9f24bc01f882baaf6fabc2f30", .Okay}, + {.Lcm, "b66ff2729bdb4f58715f403e15a1f7a01f3a561ac0c2d198deb47dc3ad2bb3728fdb60a60608a4f5f7519a78340c8a320a25d42b88c3f9098d88fa1a025fa6c5e44d72eac4d87559d9f338db42570ad94eb6febb13564f113ea98283ea8fe8749c78b967ce67b272ddf7bcda7b470e475082aa443f571e18790d9c87f2e46c2e82ee819a8bf33a1fade76bd1969bde07dcdc9ed90910", "f60de929cb9bbd663eacc6b5db6f0dc90adc8514c9dac6f77db63806681c792fe880757dd06a25619a5e0e062aa1cfc9184b7afdd7c84540baf9358510448b1f4de40aaf1310ad189cd96b49ba58aaf69041a73839690ed0d684021ef8eaf2c2224d913a7db2523ab24235c321fbf05c127940f4ddcaf529c11cb86ddcfa0072393fd6976661367ce97fb1612ea4174463ca452cb688", "15eb2f9a63c911d338c0a6fcb95bed68d3bb94a1f5c1538ac924523cd26bf0bdc90371c0717bde17c3bbfcb88639d66df7cc6fedfe486d31244f60eb62854aabe0ec112dd13c13aa3c3e946713ae1ab22d7ad9cf31f03972962d929dd9aa2af8a3e90b128d0d3cfb956ad4e0acc5d7030754a43fc6e778ffaa16d41987be7c964b4e7e811d9b153a131c7dc95c1625798738a3a646fd17b2011ecea9f2e8e58ddf62afa42843adba741cfc6092679c325e737dabb60d444d88116bc5bbb3e50702a4d22e6db163042ab306fad20d14e20b1b4c77ca431cffc59c71c40f80dffcdc7ae7c0890d05f122b0025a2f6cb5cd034677a59e0262fe3294829bceb73c2437f70a294bfe1f4daa2d7fa0e3b908f453fb71fe16675bdec69e7dfd5902c58a0528a23862be0a3031cfc610", .Okay}, + {.Lcm, "237752ff8b5900a7c3e2bb88e671baefa5a57e868504608b79ad18b02a528c5001b6c4baf08ee99882ccd56dd86c796986dcbf9394c58d05429ea0c0e95d9968a2fa51e14c67b6c8d0a431d7bda900b61dcdfafc34471ffc9c0b2f919e4e9ec049d602cb578373ad16dc8bbc9412031247f071d78f178cc9264f4a1e7751ab49be108c49feea29c90d6ff75b0b3507ebee4d627da812", "-9708c46b5542bc023638a0dfb297573d2440bd595828bda284c183c7afd99ea691a4eab7afd949ddc20a43b4392bdb5c3c6911ff97660a3ac2090af7236453e9ad273e7b8d72ec4a55d4b01c5ce8c240bc6f265d556bc31116d41d4d3ee491e1e23efb05ce71482dcbe22052412b4d2bcddc864dc7b1b30bf39701be093b36a35a9dee4fc74b53bbd016a633c9b2b6d129d1267d0d67", "14ec98e58d690f088b08623006dfadd6a265212436f8f01f79dc5f401b41f2a544efbcd685519955ec223bb2e9fe907715b6d8bc3609b8133ce3c6c09cda86913d31649a2f8512201e7fa2d7c3b597f6f648cf75ae0aa872661452996ca99fea20dd21463d1b03930f20301ca5f384f592e756c6a57a41551c21ed3e8893b12814b3311fd23ad6a3d47824d2c7a036e0a54b50a987482ccef69b56a0d5a133cd2b99ec6e6bee928a9d569e5b67d60205a0ab5153865dc2ded3997d8c8a75e507b3851ca88898f6b83465782dcb25f939244065004d78bca66ad6340d45a880b4cc594cbc79faf9f040d2477eb98b6ac467542a0306217724044f0d5cfa4f5c8bcec986d0e5b3068bdb6b2ac35bf196e673e50d434a0af2ad13fd89ab25f2da069b2ac5da8ea1a622bee1893e", .Okay}, + {.Lcm, "9d8357453c84e486635ad5aceeb9b5075945c7d027776cda9933a80c443d0a46ab66bc1ff5341c14b45fe2d10949ebc341f65c70ea5e5a6520a6f02d9db4a738dc9122bba55abf6a018493e4b7cfd5d8c214ea3f005d3753080a2c29e1a05cd4d727b4f45fecf37c18f5492a5dce5c3874e4bef215914f4ba17dc1df7e3c65b1662f027ad2188825b8ec1889a20b962b86fd56aa9837", "-418c30466af2cc3b08f56212b9f01cf8c176c2668c66822cbc02039378a02ad9ddbee67c9e16847a179b5a1030e316b8136a85643a24c899d04c57720be0db5ccb6d3bdf6a8be45faa3f04aa8caf018e390270c1f0540c88f25886198c0692d9388dfe60251ce925c380f51e0d696eeec60c0ee8afd3262081f212cd65f014d20f396e5600c43a02da72f466c7e1aab2015ac443589", "d7188e56b6fd1a4e794902afd111225b6fb263c0224ac7fe0c868405f64bcc6daef8a877a3b370810409f7dcba987e1c732bc1b60fdc2bd09df407e6e0257be856278fe4f744f74d458a586e8fc8bbd3244c4395281b186d1900689a799d91264c25afedc52ad64ee0d0d359869999de15fa38aac0dc0e97f3cfd41df9858ecf967864f5886ac604e311fff1331170f12db0b3305ebe952f51105685ae203142d6d24c0fa2a5687921061254cb803523dacf45f142cb57bca411e93c8251dad308f7cebfef01fd6535636847e27137693a67af8f446f3393ce6f2724c08fe0a0cc767e39c08251e0169b160792e290773a9b00a419b4cf0831ce0e2643b0ffd60f1ce27dc1edb39bd46b0ed9fafc65dc6c9bea3ff02516924b4fe4ef0f88b27c49c6e1b681e589b1ce4825", .Okay}, + {.Lcm, "fb3588370a6fc1020efe57980957dd99e44e0e60274ef5688d0c30e85dadf3739191bb345e277da0fd67fcb9df6cc4d97995f9c12098927771de5dbb83efe239a221cf1f14fa97e128b28b7b3ef6680afa8453ed0d5a028c1b8d78420aa318569387c1f0947869cf225bfad1aea35e5c70f0cf69f010d2e1c24758696bae58be53e3b515184d1cbc870ea7c101de620c325177037e4c", "-c6ef800486a16b456ecf3ed38355db9ff88029bb58eab2cdb787c8d78d477423b3f7aa8cad62a27075a795fead410a27396d3f34e0520fc4b5a820992302931f556d431c091a4b37e72deb11abddff200f4845b7d830fcc9efb55f719f69b8f92ac63e22608fccf3bf17ddf2f20f372c6614ee2940b7321d4317bc7b1176b6605e17f07fe66b4eaf6892217ed066e9e7514af95333b9", "c3366bf3f2833eebcef1e8b411da3748ca4ce6f8b9a6285c3531f3b1221c65beb6f4c90e8fd13412d21a31310656b01971832531ca6ec04023a1acd12c983f8a64d644b03054c688caf8106ddc38fd3358677d41b85cd1e4b7e6e626a5a6ce3ffa3e3c58317c8f0fdef116595b494892e5cbbc0438edb231c1e2fca87ba093bfd08d0192182b93099f589c590b70c75a93367af8e813811c266ee8b7d4737068de59ed4dd327638adb91a4b261d89fe03185fba4a163825124a64193b44dc51c8988ccdff56ab17b046c9f63b1682e286e4b88068cd49e314acc58cdbb2010753e0d8e96fb794db4b87b0739f3ee9f1d929e6c292a8ac9bb8074f87932a93cade4a873598cf5838e7dc9a6dfbeae9916c07c0bf29ba2442c3baadf510bc949038e0244b97a8f2186925368ec", .Okay}, + {.Lcm, "-8f153dc327a287c0474d64fb5ab1d40458e9f27fda2ec9b7a08c99a04fe78eb31576f036f58f7cf45df773fa7e8c7a7734ba5dc5b1fcebcec6cf40b557699e17d7e2158540dfec8b0ef03e65e9baf54a5a90b2ed4743fb9549d0644e3680bf1ba9b927533b7a3f590761b363367c6721c34ed432d21c752f92d9c058f535612ea77bebcf3f399bea149c5b6a2143ebe7718315bffa07", "254589e4c25cb48c0ca39ef98e8c8fb0c9aec600955af92c8eeb88b71af807fb8c6a7cad45dad9b86fea54b1e220900bf98c001ab7b9295d8e4364457cab6b78b31ce597613b58670ab3081176bcd1abdce1a468878abdbebb4c8832f859e0546763ea3b4f27af3ad1f8aa5208cd62a2bf9263ed1bcf7b27bd38ca01feba63115a1cfadf5ef682fd6d2782a3030f515d7a471a59a54a", "6f1a53db14f8299519a5a5653f457a34d79e1d4d0310080c40c42eca5a504cfcf87ee7cc36f94c4ce6aa019be5b078a65498837deb9bb694b03fa7b6aa6a1f99ab227de80a05e43cf6e658bf42f8f1a47870252a53768485071a40667894c518953a93bf59a49f36b6f1cd341ce66b6c93a80abe41793f301eb43dd627859f225bd1e4f3f146cb4e4fb01e18bf126480c5640bb4adbc9de97bbe8ff44542c2b2a6911e69d5e415e9fc7872aedad0644b2c29f05c356d3f72420bb197044003fb15d07cc4652773c5774a04cffc3c771d7c083646dd520c880b33582c463118f7b3cbeb503a8f84007516b9b36018005b2c4efa35fdd906f325fd59647977caf953b298207430c50d8520b4810765fe0b273bf24a7cc6a5d9e66ef57dbbd2348ab09bf37e6edadfee2b14302", .Okay}, + {.Lcm, "51a4e45788176d5ab6479de35dbe62f5ebfdf052e68e70496ed5c2643b6acd43e95a17773e0209cfb166f8bf28c61b7b9c702f64a13a543fb004a250352a0ca1dbde71fe767720b75eebd954cf9249c906f64493b3782255d5ee4275f2327cb2b086ea138deca8f026ee77a6fe213774b311d0d8b35126787e3420f94233f0a61d2166b920ea6ca7d543bb0bb8d2bf1619842a9ea768", "7ca74b5f74c79eac5c70d723518a3d5e2d4eb268dda09b15d5cac01dfb8e966fc13939a516b1a9a3c35f1cb3376908e10ba0891c75a43d6dc0a60cbcf9f6b45f7099da317c6ae5c30f8512f7131c97aed1d1624fd5ec50c9f8334cc94511fb4e6e7cf7be1b54456fb0667b8048c3939a8854e73c7e238709715c31af8c5904d75e94daa03c7aba26ba5c1e46050892ebf4f3b5fe15ab", "27c139351b59e2da8b1ad8a3dc6d2126810c728ddc4f15f51f456922106e4163454b1f675529cbc9e6253112f7da0276313247b3a472c9b1dae71ca505e2e03a7d7a946d3c5dc81c29fe1869227b4fe8a3a44c341d026bc324e1fdace1d321a907f9aad25f6405a194898abc0a1901da6353a14a5a9fd02678ff1111dc50ff2bc3a27f80662d69d2ea09134d8f3f7eb9b4e4ecbfeab36d2fcfc74eb66345df36976518626ddcff1c6306d4c5f303029baa96116e24c5d2ee837ddbde1ae8cb6cca4c610c10ddbeb2ca8f7cb14a15aa4d6b83eea2857d319b020d64f68ab7e38201bdd4d1067aaddd8796047079133ac5fa25ab7783d613d218ea7fba049c4352ba3455067441bf05a8238d37938742eb73bb889bd4ca774f3f1bbf1a462e8d3decca05dadfbf60461ce55a78", .Okay}, + {.Lcm, "c0803e31cf326bc4de269d233c2557381213eb010ace83858001443749b7fb20e6fdf4419e85b46fd090aaa2594b672bd57a53917a242b36ade4eeaa5965f405583e9701c60953bb956c35dc349e27056617f50d292958c62097dc3d6b48261daaa05dbee50955028edd99f75f1075c7daf896e462e07c21e193366d4a5ab13a588a6ca5803c0e3e11cac541fbc53f7d4a630adebd18", "bb0ee271fa5c6f1d46690c1d7d1e0b56814cd20353f882184a5829341911872f6456eef979ade8cb925d72f3734bc79a4e80f8f6cb45400e8c6c4a605d4936af6a3950e29c3eeeee49ec3b077704ac5c5d84bce4d785fbab471b4a35c4b57c32d261ce58a80afba5f5f1663a61b7f6f4797677f3bd58776811c681ccb67f5cac4ba87f6aadd631ac266952a269e50ae5cf44a6dcf2c3", "8ca8deb8b4d954c2481e1f791c5f81c910e7212522ab122b4cf42434a397d31b8f0b319c846b5c022a2ebbe2c7a1b97a4e012c1414055946d09ab425fcfc5983e8146c1015f6ebda6e84ba772fd3cb2862d62ecc36e34c4b9e51daed475e50058c89a46d2a6efadfbcc5c2922285c5d5003ac606edf9215de2f4c4c2003b8ae830c2493fba129fe3aa33ba03f60f346a17dee39c51ce550debf93eef81e7a1e36ad528b8bec8744a298ee63d758ba9b421f19ee27a373627c7c6471730e66c66259f0144c070e0b16612db8cd436ea8f00ff13054015d5d46b0e29a25bf585be65bc679502a33a0670c8f2063a8c685ae24245c678590846db0396ef8e64244a7ee3f6392562201870589c8df61b4d01abd9a9a080043c929184850d1c971b04e9624e5f0773b21fe70ab948", .Okay}, + {.Lcm, "1c7d9795b984f43eaa62141cab1ab0a8f77ea73ed2cb5fddc3805c791e796a3bbc1875d3dd38bd29eb53c936329ab631e8a825b43d873beabb59cfa451ed0a5aa9e1dbdd3f48f4423b8e5963a471501f125d9305997f8fc20702f40970c67398470df9d220186847c3e0480918994abe1fcdf73d10772f1a375903e029a176e802e2a6cff26e51f9aeaef20193d01c20770c1474196c", "-fa21bbfaca0dd6a42df884c9cf48cd28437f161a99a376c22a39f16a8fcd5cfa962910ddc3a5e4b24e6b6fda1b7b588edb23c47bcb208b432802a85b64f4b216c364fb367eb34c12960e5d3d532d938e94ca8f66421f975604b12f9f3d32d93e004544125e429ea35d416b4fe166e5470fd03f2d234e5dba42f069fa9da02cf57ee699d91a98e7e977acaa8c0ad30aee72cc84b3e2c6", "deb3392342ae5a208ffafc0ec5d48855fa9653d96126e1d8de8c90e2dab96df77246913ea458ceb8f9714f831a01357312cdeffda03137655a5dd61be510f646eee0ad93f7e3bf316649f55ca9680e66ad6df89e609e5d880f2318971dd750a7cd46f282f6ce38c594bc80b539fb6cb2e84d33de79419f95bf2067d879090ca9a33787de7404b0d7385ae422b1f88d0b0f2afbe81696c89a19d97506b43f3d3a3373fe07d922d936a4d06beede17cac8810f34595362fd6b0a8452eeba2cd03f430ea714b2350bb362039254e9062c74eda4943e534e6118bdd11da423452e10e6e7be6110069cb6aed3f7a7e504edffadf2dd3b99ccd4db294de1432cbe895d34594ea104a2bd213016b5ae5cc2f5598c664638e3e1f60c92b874793674f14a1b1b5c6de38a0dfe36080c4", .Okay}, + {.Lcm, "-6cfba29e8e42a04380b0e3c5b4eb5153302f97522e839b9390bf7c4472c206b20cd79a72e1493a1cae5bf3100941289ce006d055221e8c7eb6b6db2ae4f6600c363d2d09ac42be740fd8e392c0b5d88f221d905c48044441ee0f5e65acf69ea067e6df5c3f17ded2f398e78210eee290a80252f80f881f562298f8f63bab2047331ffac6df5bc32ca8802139fa148406247c63bad798", "-8e4d28d3752d636570256a5849d88ce488c1a2a0ccd244f740fab26776dec24e3ba92b4946d1ec304110e37179ef0d42f79fd37e4d557125bd7bfc421da3d1c4e7ee4c3102f9ce123faf3294c291088b2f535f10e7d597d9e239665e5fb38906e49efcf8123554f38f9e064b4a7953df11abd05786011fe1f91210e724a53ccd78b84afe9e9263777efeba0fa5744b3a3a2c8e11455b", "3c946d45334be1b7db706a9b7293938693a74ecffa4a9ee26b071545a6db33bba1de4d17f7b3363c591b04dd0f92e541e3659f04fe8695e40b0d1376c86981d716bbaa8c852d39b6ba6eb5e90170bc572b5cdf941a914ab1f7362fab3d265caedda180ff80cfc0c779822bf8ea36e987dd5062baf90f7f0f8c13b7dc3f00095377c44b9fc52f3db8566d1050c0151b1c94266d4def592cefa4967241ec80db5f809be3b4914883f5ac715e2274ca82cdcee4a3d0dbc87770c66d5cf0c4c326231c11faca22fabe39842741cd69c2f44e0417515c5aa9e27e2c6781a5438700d905938b0b5efb9f733630efe31c22f13aa84272f5094a110ead57772e616569e47609b5d571a624e1ed41e2260267b04dfba801151819f6d9f551e948666129a1e6db0bdddafe4037709e9b08", .Okay}, + {.Lcm, "ff14e78bd5998365339ae7b14a1e3af883a408d60ad20bdb00033e3c5ca9d644327b8e79cb63cbaa6bfa1e9c5a35c95a423cf3ff35298e7c60e26787a4f21f8d9a1cc75690f3d6d7d93a1b6764c0724de13003c05d88e75981fe59902b41099cb9d6b4170437c4a7f942fce0ff7d7b1deb3e25dfd18c8975a8a47c92d458eae20ce82af8c50a49f6994e8b0fb2fb9acdd0a95100907d", "f0eabc11c4182c2e0c74ebd1edd36a5590eb0f2286e69a5256d498d90c4a36bd9a4d8c8384cb6dc2510276a39af2546673545e99642790807c9de84c8d0cbf11e9ba0f1f13b6cd19742e96e791d363b90882bc5da431928aa95f14244376e9ea07a4450522364bb1873bd328dc29d5e38ffaf9a703aa70fb7896b797c2450395fdf1316c2abd7be600601bc6a4ae19eee9784769b8bd", "f00d7d93cbe351e9252f1e8d951b81972a58789531a04abe6cda30dc1db53a14adcda0518897cd2faf2bb03b9176a4673e55608ad4bd69f0ddecbe1ca3a9b2a826fdd8d2c03737ba7fb7b42fdd44a886c118f17e4930498d491ba1174dd53bd99f3865db42b5df6c0fcc818c9cfa368360158f4c2c3d17902306b4b036b0a40346dddfa6f2de25a62f4381801569543061c662c92f4014d0006b69555dc4dbac132a33841918122eaeed48f3017dd46b9f1c4b6d58772d38b25cbd7e65d61347ff223e7bb190d8628bbdd732ecbf05a797cf635ed204dd7f24ade13c439718f46e485fbba31ae8aeeb3dd79ed64ae9e3b0576f22647cad55a3c0d4929f9f3f99a7cd8128c55c087c1c9f1b0332bfa7365ce4bb2222cc1337b41482f683e72118e8b41dfec7d1a01f23898449", .Okay}, + {.Lcm, "-428ecf66cdecd5adcd9ccb3269b8eacfe69e3366e78d1e33c820aa0d108fdc4cc293203f365cfab6c75ca2b5685d666fbfa2bf9e2c1cfac7d95976ec05e0281fdf7344fc8480ade759707ee61928463a849f79148336d2204798cb729b82485456af78946add9377f13e854c5534fc24816e4347ca7fa46c1cf7063f390547c8c1bdb06ae932669d3cedf30e42e8fea31bbec14535c3", "-bf2bf71b62f9fe79bdd0502f00d1433d21cae494ba23109879cc151b54cf513a616b63b43e2f7b0f2c6d6e60434c9fe627024e9c993d4c15048262b5b19e173956fcbe3b5e2b6774e7f5f7010954c839def9eb0595ce6ce2108327a33ed4263037f8368f6c2e1a98ada7b29e12db982c737dd85359c6b46e3a048bd78f263be83d7d540688d77d584f661037070cfc4bba0b2e41511", "31b3faf972d00532393354b8a87406812790c6011f17210da4b815ddfe2986c37bd656d9c474a964a6884ee0d2e1d46f28138a7ed67d38af7f594f6d3b0f391bb577911800b6de71f274c77d453903abffbfa4abb47555b300a7d563ff4dcc813b1292b037d4914526ddf7c056e6948721369077b27949aac28aaf5044ef92b1d28eac64fc73bb3f4fe5a9e3b298630a911e737df5cbb80dc39871d86da7750b526799220f13344be078da862af3c9dba96e045415b0f87e0bf0250d14ad743c3b21a804925059cbe42aa9c89ee4ccb56e3266ef1c0063ecaca9a3a84f522d245166e7aad83bd93cc63c8996578b425a44297407582136bca2072fb6e15a577f4348fbb4eb9db569bd093b850c0050faa5b17a4fd48e6aeb5feae2787e01a7b099e3417d234c96afaad90f3", .Okay}, + {.Lcm, "-8648a5ac9c1ed6058f2e4d3ffc746711bf825d46bde945fc96d5f4d164fd1a9eb0ee2fba9d34678402375e0740384d6293920bdff55315f8f8fbd2ce5502afe80d35e6e81fa7b1d497d96ddbbe4b4694bd627bc28b6238ab7ceeda019cf09025fa3e1b9102baab453bc774d91472ad740b78ebfb9ab205a09b3d02f434ed4276c6118f97f3d5f0e2f210fcb47eb5c6bb02f7bfefd2a", "4a23a34744de5ef50b31848ad54f02b0bf3b757168b5e59405ef70493d504f5cbddfb068a31e1a7f77ab6a2526b1b18f8727bcd09d17afcdd229c4899fc33c1e485c298a0ffe440f14c80fe7208b736ef93e89c0ca2527547a2da440aa48bbba353404948550061c65372ef0709a062c027fd479547baae385bf685dc7eec29b5e062470215320a2f7db0ef6067a65fda09b2fd35251", "26e3b1782f7d0d2c885b770677ed1115a7d321574232f31874429ab23797ecae146e80bd12a3436769621bda51de76d90b732de4c9c3ee12401265f7d7d00f1a3d0ea6db2ff1b574c8aab84ff80fed39e52dcc088bddc0d1a612805f93bda818cf2a51cc1bb454ebd8b914381d1f373f73f23416d04be2a1f1ec77cb8364b1509e974d48a3b74f92004c3d7ccf6b9a5b965d3ac78cbd50fe91065562c8815393f9cbe3ae1be45bb96f934765d93e84abddb7bdecfe9ef91d475709078b180546a9fdc837fa3d35507cdbe8e3ee45ffa7f823aa28bfde455d31ed3bb616e53615ed94943a01a15b756f69fba29d74a8efb150a73f857460f10f62165eea7b7e22713e73812aaeef05ab14dca2f047de8949b01557c07828266cfbcb31aaa94d05b4a3852e18880d148638e4a", .Okay}, + {.Lcm, "b2250ca0b9a9043aeb4dd9c5c288ab396b209416685e056c83977ee91a28fc1a22ebf88c286d4b0d7a474321eec8f039828962b59a105d22fd64f48a94c546babbfebbd59e59c860b31d74e10697229e7ecfe37abed6d2bd1f4dcef29c3ed76a7d9bcb0ce711c52f158cd9628b25f9e43632737396863e6e0aa75b634a18b3a32dc65400fcc072508a3e3b48248edef0d9a3ee9a9d5b", "-e2e1e48283a1a8c4666efaeba5eec9921e66a325da01edc81fd211482ff0444f04d58afb61fbd1ff001b65c8715666637446ea3086becfd35c43701048ec7f813e66920d9c574bb200bec602c7e5f17c55c2400c4c2d0f0930e07abb0a8462326a61dd625ac955fa342633145b9de9bb92d5c32e63e5632f3c7d960b53bf33f2c99ded0ff58e438ebc20d4afaa5aa4585b8270c72c39", "9de1e6b9ced36675b7218c145086c9e5f8040bbdbcdd3a7b8e124bd9879e4d6b26a4fb1d29100e24395209bbcaeee053ef45d9f990812f912f54e3416a87d14442fcf1362312b781df3191af2129710a76eab8618ca086cf9261d76eb222137d5560144a2824dff69cb8beee5e52d5feeeaa8cdac73045a981a6887827d6cb43212deee65950ce9798a923f1b23f825cb5248d980bc8615b3517a826756c5f9ad6fea064bd139cbd30230fb874f85f5ba3686dd48195cc14c2117a9e5d3abb6c4fd1ce85794eb5155b5156142d4513f4ae8cda1596385b0a1571133d8665a57567c7148883b3de07aadcae020934a80a043285c3eefdef35d0682b2f572b855ea8ff2b42a149d7cf16d805e7062b1fb65ef1c493a1d8ba5ad29cbbc525c96c98aae0fb94739602c0d535ad43", .Okay}, + {.Lcm, "-6094e1430ab726040205a673b1a72f7f261608a56fdef6f04867f598bc58da23a12c417fe0a45fa8d3885cacef7af9fa42c3fffb524c5ed47411307827ec57ee38f7100f08e1bd660c4361c010be5a69698673a817558485c21286f720a88f83efb15d5998d4aecf37d64dbee5ef6c98e1659bdbe4ebac1a2df64b9e542e37e5baa1360d2effee8d39803b71c68516db2907b1e26c34", "-dd18cf3f7779616a3a82ce234cb36cda01f0128e81a9aaee0ce52c5f3bb4556d54e6e1fa053c4ed624568d4a58fec03b31ca645a43bf7ef838a47ac922f9fd413a689a6854f17197da2ff70df8bb2dc6a6754f0676fcacbaba17ac168bea7269ff7fc5212d0400000199a613f9ec7d497fd280c506fabe415a98984572b52223db4138d907a1d3bb3a069abc561c76b2093e5d0e9456", "29b4f14e293260fdf0564f27f4a5f45b89dfb20d56efc1f35e557ab9b824c2a74ccd504f15ca347cbe5e0a2d9ece5333d89940c75667fa7f020280f0bf888ada9230e2d0a8d15ea2e8d425ace9ff94a22c17834c5f0f77cdf06e865f3049c13f119bc103d07c43aa9777ba8a95fb465c97d12b47be0bd8b365b8842314d2e285b5b4e12f61a12b034363b975f45170b5cc0088f3c99b00fbcc80d4d24b117c36cd75d8ece3786cafd2db1eb0b447694743c40c17fc2812143933506e8dec422e496b1375126471b01b54e8447f4dd67e7aa47b10c5a6aef4dbe2ea47e0a8e4e139b30539bc5e3ee01c0f458274b8fc5958ce8766719ed936ba9da4323c9993f827ccce7a40354ab487bef6588cb37c54478b6074de1c6ff9b1628bf1c50f77a743de87f6d5179fdabbbb34bc", .Okay}, + {.Lcm, "4cb938682b344f431426fc70b3428bc8cf5ef989b05bc260924c028518f41281082790ca3e2d5e339d1f2424277b140891bb54d570673472292b54c17619fd0f88c758b107bdf0af99f159eb68d77ba3dfc4aff9d12489530f592f5e381e0ab20152b794b004d88bc8fb2590b085f98bf71c328f2ff324b3e64efc42f5011ae4627a7b329329dad46aa50ccfb7ae8f11a829533e5956", "-c12b74dbbd2bd8547bf55bb012b5224b9203fe3c204201d7c820afdd4dd7cd3f2ebd51820d726903d8bef036886af97f54eec3be1f139215668a25df11e83f63992371512288dc375812ec01ac564da726fc677df5559e04eb0ef9698ba322dbb00bd3fd71f90b645dfcd68a8b0fd6e3303bf3623e5028d06943053640e02b5df7e18e559c5a9ffbfde158e53a8c6016b50d7dc7eb01", "39e4a9a8cac608d28709c8291072ac74539ef0ab892306d876d0d2da8594663fb344373c51594451f929307a8e795beb68f1c80b585dc2e150c410491fbde52a3a123959378b106d57666f741aad08351a820ee9477df5c038faa706f69f266edea0875f33095fa25d996dc7e3372adeaa548fead238e7475d4eb47ff49e213e366d9f62fb42fe91be9df2012d3de5af745fc35b9fc5f9d86414c0f63ab35a43535aafa92864048d85e8a638c7cbdcd35e2d10d32b6d1a59031c202853b089662630840c5c8dadc9b241108af0b79f2ee05482ff85db2e5264a6e5d175d26a753aa558f4573afec0efedf67e709466b86d451378b8eb15d37d2f280e1daf6cd67df3e425fa2aa398b6d2e7a102ef01a486b5fe027d38999cd73bc552c118b4af91cd6cb1e6ed1607ff1a4b56", .Okay}, + {.Lcm, "-993e1411be78b39bc2a8a18bbb5cbcc1449e7295eba880df6efccd5d2a2563a1b565919bf98b3ef76448673c4f0266ef8b1625f8422bd2c410e8b5616d86318a07bf39a888f4a6f6380e4642f76a5ac9ccb06ab3b19927361d7a03a2bd5c2c18a1bc5f14fd3b1750ea8248e244e7d688823935a4e023f8d4037d8f5f55a45581a46be0e928f59e10d816b3aa7d701094d50df7c33810", "fb9059bcdb4515421d42c3e3bd9175e7258b7a08bd7210bfe2a948e7271ddc38180a337b5e1a50ccf900a14c98ff0366feeab47b2e4cb0875cb1138b8c3932929a8267025c1803abb9296f26c07f17419a88cebef46228e8944b7dab29fa240aae137eb8f609aede1dce54e93bf711eae93aeab1c0c0c37264b37f9183f570f1595ba796faf6c36ea356b3040fb5973bb74f68d68393", "161109dd2bbfcb855371dff10a594a3c501f4c0cb1660359d4f3a2fee88139fab42ef9458d8525fabd5caa22ded5f53eea740331ae527f456ffef9d78c3fb21488645e43162d77ddaf6ab3ff7f3fe67b38fc09b5fffa615ad6f12d8111b7c54577545f796ef407a6c553f47117ce510c605a622c7534733ef7c0f6ef8ffd76fa4fa2c83860860cb188a1ff8c67c26489ddef726ab5dcc0d4fa45da38a6b2c67dd18e80edca11b500f274b055b6208d18d4544f668b9838364195cac83720040e3bdff98aa1d50f784bb23b3d6089adc362d717868e941db11e66dd34c67f543aa2acb38b36b75e837218fe76567a1f02017bd05ab1db6d0ce8ee45e3c5bbcb61b824639cd429d2f19c7274da1bceca844cf322c049c8ac3331e8aac6fc40af62f5b10ddca8a3564482bc10", .Okay}, + {.Lcm, "-f1160b7ae15e2f51c49434c976eb021222aefb7dbf2245f57e21e3f2a0dc9f32abc1723672bd43e53213cf9cffff54ce01fbcf738839d4c07644adb02a478cc035bf0337887c2fd552b3dfd2d150caf291dec1a03fd56973781b7147dd1153da478f105999f19b2ee1b259943282566c2f09dfd9793476d5154f746ba21a465f9abe4108284b0c4fca3ca04888d27cc1cd9ff9f1a9eb", "-3f260b504a9acc1ea44b5ef54016d41167a1dee6dc9cd7424aaa89b41095999671d173852395b3b68ffe2d651f7af4cee28f3324518536b448a82af98c03ae3407c40133a204237596a90508a7716e695eb2d0fff97ab1d32293d4d3b09a1dbbbda6568a8082f94af797bf6821b7aa5db906c97870bc0d4b8221a9466081cc623576bf24cc7eb11d2bae453dbb34e978d4a073503000", "3b7840c08157a68478801e8deb8dead806a06d2711d4c777822c57384bce80784160ddc67efbf8e2633a4117abc63c7d4488161d5a1ab1c1c8ee9aecdbcbc9a57ed0f8fbe3bb38925785126e669fac235b545f5c8444bddce4b2770e5f55aacdba9a03744ea040a0837bd671226581becca1bfc6ba7c73381b2e633272e4dc3a95e6ee932bc6ab0514ae2c4383a5770685fae7273da345a95079cdef6e139ed810f620ba4daed1ba0dc513a4e0906d9f0ed12e7a39b9c3eff7d902b9649d886ad5528b763bfc68838e1bd3ef83343e009b4d43962b16d089ac23db3512ce36ecff0a3be92470ff34de12d925ddb488cb4d91d4dea35066efaf9f7a41cd724951541255a8d39482f1edabbdadc2bd6f2b0f268e0d7b41161b883cf4f99432043a7e90cbf656bc7896fa4c1000", .Okay}, + {.Lcm, "-caab36ffbbe70a3443f052addd7452db8d1341a42cf1dee210383b8b98f3ce1541bdb8cc7e90e53dac3e7cc17b9da8ca32161ab27f4d3791156ee57db8e5d236e2e1c4058b060bfcce34c7213521aac3fb2373065ecdcc11bb9295fc06902f534ced476d835e8615fa1860b5cae1d22f14186ac06210f0801dd588e120af72b2b040a921276977dc4ca3d9a55fa3af6a33aad43cfc56", "-9c35db76085d7def128ab258ad894961e88f14d05d2ad39a9139afe7681f472726cf7c8f48b9865bb11cdacf25c0789fe6c4dcaa70611128a7b582b6ea6ea0fb32b3d18ad5cb89bfee377c600bcc10a5f33f7558dcf92bc7da9c5be87c6b51a4cf0a7e91b7e254e21627136a971172a1048588c6ceb658ad900f7fa2c998c91943d18b21af85dc832f9d04c57739a0242df78f24a6e0", "3dd57c5a1185172507ccbbba36e4bb5d62db30dbc855291bf7f60557ede258da285614e9fa545fb9b7392a80406990a7c1c9860bda80b9076c10a9e77738aaa50e128bb9a89778fde049c72c4737f4e1bedf6360ddf8a3151961312a97c88d65fdb140e5e73aeed5118625d390830fabe45adb371b1d8b223a4201ec7f4233284d2672bdb7171ad4a127ef8e96a197b9df0f846b5186a1d526465d555558f5a820ae17888b42f4549e1c082ffb1e334aafe965b483e41a5bfd0e5913a07f97ace7f753e8ffbe9c334ce42f8fc421544adace841dc348bbd9afe326038f65c26bbab61eadf2dfb63d278ff9c530de1d030817196f706bed37a634760f15f491e0dbc27eadf88c41372c5cd1620aba4698336cfff59d409a263e0f3d950ba30ebd517fe8aa63263ccd638a47a0", .Okay}, + {.Lcm, "-c469cb681bca57abddc154798922c19276bb305b3abad2424169723d8492a83c96e92ed7bef8b52e639d1d525b4eea5a8143c62fdc2e4aca14040d1f5e93c2d370483154f5d9f1c749d2ab01c5f712ae58396cda965559a754f8ab65ef3acb02395b2765e5c135007798df4cb95ad7a47fe859f4d879da2876aa8f210ae389000368fa24cff32ad8ad619f6aa4d628ad6329bc6a0403", "db095c5d4a249e0c42a8da34fe598143e21c5a4e535a7186512b8db3d5297a1df3a063ae6f691c0640b9461f6761b5bbd5bd008696f13c6ab2c9e9a153102ed1eb2de1c57ded4d0e946810853e4d54a01a08d4029db83b3cef472c4ac45c13f54850fd812e602533f6bd4af8c91a881e7fe1f96685eb4e247eedfd77b6a19e38097f7502bfee4eb9fa5f02de747de019b919cc46a7ca", "a80daf97ceda0edb5213cf4e3f612fc155fe5e69b6b0865367570406b1fc7dcdfcab0f8ff69b63b4d211ece2b2920e0f11ab19d0549888393f56471783a42d4383f6b909b7577b7cd840e8c097074571328ed7e7773fc6befb0f853e86e0cff193013754a304ac6947eefe8d5c8605d0fa471b81551a7225466ddcbbbe7a98ae123d9711073482dcf883bd848d59a7d3f3b6c213879a1ca0563d46e31c726041b89f0170b147d72860ce2a8f11b72b8747fa67a39615aa03a773a91b840c6de3ecb16bfaaaf9398a592cb9e2f6dbe8f5457fbb7025afaea262417d377104eb3559baa0884dbe22b1a98b568204be5ecd4d3446c9c68db585d6a7847428c0d6da69f3ee4a720c79222571bee18c0d1e6850a4d3cfa85c924663f098dd7d8894621a5e63839b9a085251171f5e", .Okay}, + {.Lcm, "29e81ad0ffb5f176fab8ee1cc70aa99ace6d299eb3c20ba2e6ba39e8d6591acbeac36d239fedfd34e26408d7585d7eb8a7f5700007b002ed093ece79efb4d3d6386dd9a17eaa7c10bcf337079f0564900dfe40235ea64efa7842e096276b25beb190d9fc733d69981e4054b328f5516326fbc35791a71f00045021d68ab0a97ba5ff85eaa67f1e643c4df7f32572aaf7ae1b15b38509", "-702e928de7a8894171d90cd68f99816e2d6e636a87ae91b29a195c21ae1c324e776af8f141dc3928b8085b7913f5ba487998a004e714bef2d4f786e5a86ea85341fcd0161fd30e945dc41aa7773c376669b295d5b3e4b596efbe4ff868af3ab95acfab49d7097b52f06d4207d8893ff305010afcc80779e17d5b15040e06132b23cd39bbed73526afda9101ab3d7ed3492deb4215404", "125d2b6ddb7b8a4428ce6ece0a76707b04f767c0afcff1f1b9b784c91c6bf74200a6557e9404621a9d6b9ddba307ed7fbe54a025b956396bf66f28594a46d0013330dc6e0a5084b6ad65afdaea0854af133c0d88846d39d700f181e2bb2f82d467767f4407ced27c04af80f282663f64b97396faea5c8cf294f1678e029ade3e12541ee23c439d4fb636d029f2c3dc5a1e0c3214cbe9854abdcdca387b81513d0354e5bb00535c7277f156310c6b73267cbd72339d81037a5a5813b8d0a43f4fb8f92d05ff0dbecea907f20e253ba5b4530c1dce8ba02beb31152189b425c09b9c4f1cf3879ed46232248e2ef2200993aaf7318a6111908f251937c7d9cb3a988d53cd620dd5e6dc4e363512e688ad68c9ff3c4fcff22019a397b18f4418a618e3747448fc202107b89e0824", .Okay}, + {.Lcm, "-e04edb95d0e5bfcb936bf1f17c67b4c3ffa53c050632e8df37d7fb0b0ce8f730650734e0986408ac96bd2586df9a59a1e3988d47bdc103a24bd6c4fe833a535f9b493aac5f7e05f585cfc56cacc11be31dc25c5e61ece9411e51528ba2823b788e0bb6302d72c9d5392146bbebcb29956ab3d2b0a630082f1d8813962855b2627f54dce691e492451e7ac8d6485081d848a0ff1a7f3c", "332e9428d4a0cc3d184d688015e8bb735655dbe9db2323a27ee699394e3c996654bb2f88c8e43956e706b986a29014d330db7d98e577daa043c2ba895ed77f31ab8be89bd1405665bf282c62bccff809f4df76229e3100b6fceb54369dd12d5f5c325550c44bdbaaf9626e3c788ce95f6327d3c21acf6ef8e36b24ccd5c117f4d645b63a68472e733557be076ce220c2cd9d5227d24d", "2cd885bbab1c6cc1296c6716b24b4cb0c58d268f969ec22a4960e4afabbab8671585a939ee528cc986a49141df9f8eb1567ccfd47335aa4775b6392a68e12f3a4f6ebf04954c75c9a8f2d454ba87b072e54e2a140e845c781c46c1a9be4799b156c20f0db17a6fede9b42a4595304d02f85bf48070ef2aa3e4d2eea041be0498200241b52f42f54a21f4a67983167a50d88b147f61b5c4e38281698e3dd9e4627956732032d580e15e337e94bc2872be0603cab3bcabd23e3e75e0383feb8f2908bc806934f0b5cf1125cbf10cbb05aea355a5358699b632d5d80d8f82c27da983854be9e4f158b5568bfa3baf3692f775b40b39cbc28f3d7422885278ea212f0900e678d0e9c01cc7f9c9bf6dee1d2ac914eca57418b81c693bb72fc301b71e610895e9b27a5747117b7d0c", .Okay}, + {.Lcm, "-7e628dd84fbf8c6e1634ba9ed5a0ffb3526bf5f8fb4f355ab8fc5e6457e76d376df6a8c044f78f3add0821fa129c19eb7756848c375b987f26f85872086a9feb1b550fed1a540953100db7b915a2d410b1198e1a149bfb079fb07080c34ac1d39297f8e86ba53351ece0894335e87c1bda72557785c46a0a06ee6c020bbdbc7f5aca4cc351b83c28aab398b213bcfea6ee33f0091aa1", "8ad86ea7ffb5a581f20eebc55ce39d2abd04ed7b6103c6d177763f3edb890c1041aa6537261df409927c37ae15be322f9ace0cf30649b84f3c3a39927149d9ed0a95445fbccf1fce761dd6e5fd4e4d3e652681f1ecad7bf1768e5865664ae16113db5d48ce45ad23982c2d43de5a15e792a12f16ba6b2b6a3ac9bf0fd1d80801262120a7c54c3511e2e7548a64dfc6feeba767866b6b", "448bfa3f92fbde60971daf08f5dfe9e54ad947f54afa30ab8a46a74170cdb750cc06381a34b7c0345802a40c7449f79974c74038dba3675bdc7edeb17fc16f9555eea8590edeb460570e86be48c6c2907330aa69f0b3aebe47c3134b39a943d7c97cd46c4dff4050ebc3dc18c4de177c114bda890f386aebaeef09b871435bc5e50fb0ab1f7ef1c3941e6732b602510dc901e28ee0f2e486941129dcad1b3a0dd5be8e5c6211de2eadf7d3f34b842ff07a47eb5c66342c5803e561c5910e323f97acbad73f807496c6b0c91a89fca93feef4f430cb2998bc6ab89d6e3d4f7ca4639483484f90475301e2fc46f45f4e2b6dcfedf351e4a9453eaebbc268bf70e8585a0c12383b6cea1425e558d8c6d4fff217a02eeb9e4e022f81f355ce2f74e253ee0ebfad38bd8ad9356c4b", .Okay}, + {.Lcm, "b575ee715c128ea50e5be0e1e26ebddb8e081d8e342bc90288a474bddac895239d4331bc40fee2fcc0d2aac4c867153ebbf42f876b9b06e527ae4134f6ab33dd8349b3229c081e992c055045f6f7f396698de93bbc0c0df1e5db825dcd96f5a87241d2ca1ba39773b92049789eb09d6ecd6d9d828cc3a5d0b20aca5f0a4025c146c77fdddd2a2f5f9f4b6c08f58a4f4d217055b86daa", "20ff453b20d1e96c1abb928afc5cec7f58740bfccaf082a85f9d74f10766137331949645db21920b342143cce2f322e2f3f63af5f69081a9793c106597c6a1beecc16dcd1c3285a74a79459a402c7f3e9214202bd7278abd44986ee0f1ca4f31aa87100f782e74b2d4c449f46c87790b959f3b305736cbfc30e139aaaf73867e7b0f768923d364e054122f49a4af63337a60c0cc82c8", "bb1d7acb09189665edaabb0cc72ffacc609b1340554f6d7e6edf763933b34731be7d8f1906c52c745664b702c1a1487ceef52552119df26c59dd3666b0f13a778bd7a9412563e31294c0b4581cf01f143ed9fbf5f6d5c7542f6524b5ca2055c11a11dd23ef74bd38d528ca9184aba784d242996391a3d0dedfcb400a5964a46749388b7c293742343d8cf36b313cb66b40551c049e0a7862677831730c5a6de5fb195b3048835db4a35d36e27a05623bbbf5b83a1662041f3b5da0129603b1440ee2739daec4edd31ee7f7eb3dae4e707d180e28cb30c2d40df732d722bbae6c4bcfd21eecdf21fedb9320fc811c4651098ad0481d70cd59c1119835b5f314b3284f22863f981bc575a711b00971e06dac397749d040b5ccef83a83f8f865b596c9399a52aaf820c19f0068", .Okay}, + {.Lcm, "-48497e773dccebfe413facb43cdd48d7d0ef8c72f6be77f61fe0d5b89d7cd27bb1740598987d3efd01f649ed1bab0a720232624cc30cf63cfa9a86b632340cb0afd70f0a6a030047ed5d035e30ad95125de4e7a392994ffdc41c30de35d1eb0e6979ccc2fe8eed11a4322073bf0a1e2e33cd1ee71699a3abcdb1618d9d85d74a007db161d54017502501ae05ea0b8135704ca2dc9347", "5b0e8238d6166f6e842e1f265af796a31b2dcd45d1db298824e9e59d310265b23c8ee327055f78316e921a9cd29c28832a7bd0ba643f4cfb11ccd1c0815c2ff5e3c7d561cd43309a06150512b746ef5d93049a835fca695572afba7caa8e99c4295de091adda13bb250db9132b9cce1df33b0e38ddea2070e297fff831be55b68dd2f9a4b0fc0aace92ce62952182f6a24963114dd16", "19b638beac3d360f7c6983c14a18814f17c0cc40e88d64ee6b87d694486a3d6c7c4f345574e56d7029f2a613585dcb5342289baed80b1a1585c3fcf2e50912391a5f417cc77fd699cf72c8e6ab310e2e3e167d01a5ac43673df1ad869424a853c76c749ba7f1e38f00dd8cf3759550066a360d0948bfb0c34f2ed38d3d6fdfb0800f5d10e19689a487acf9ebc7d71f4b92cbb00a945f0d0aa68ec4082cb85403302d52ef51578783768ee6bb4df5f2678602458d2b2a95f218bcd06bf93ae546c0bd05a3a46879405680e63191ae10d1dc6e824c34a00c4f9d369b3c19d7a9101f63e2e0a467c4f18b95425d68a34b062abf24b146b97925456c1d68d54f295520082d419a2f56d99e68f8b270bb936aaba2096f4d544865e1581703c45fb07da3256d09240d083482a4f31a", .Okay}, + {.Lcm, "eadae40debf6afb836e768b180394b716c5b9278f6606b1105b526107fe288331b16d427d1cf1c72fb2d6726fb96cd4789ce190c9084736a7dcb16a9f80e888797d37eddec7e3a28de4d2bf76e89d9d3e16e27370cef255ad2fb7be41004d01bfd9071f290f453b87114ab242d92d53f1edfcb76ddb8f32bc31bd2c03d85538d65fc24fa49fa4e4a9a5e856d793f2a81e29ceba540f6", "b78fcffc499b4f8cb8a5a9d7f2c44125e509ded4569e8902fb217d2727532c0663985e7f6daf480365225905dc3df03c3421d09a35cc7531dcda0a12f5704af499371b6df3762467ef4a5c207687d00fc97b78906ecce2daa12fdb5b4f2cc8ae02aca83898b62221a3a3fab1fa793f9596c02e42d39906fac198a6e68cd8e991c742545331ab82cdeaa739d013cc48c9fa68805b41a7", "a8666819c8dacc7448428d8b3a416ab100de145942c2475c0f28a398d52fbbfe5e572c0aa76eea5d8154783463d88874884a34b31758d9dc82b281ddbf20567a9850137ade8ffa979f51b58336998d77346bccf61c456fd488bbad43081d3611b1ebc2177a807faa8c92a6fc4c6a915d73dc7858be7a0fe10787c542d3032226b2c97baf672327cdb347a45e5540fe585cc286fc86cca5e6ef7f12e77fad375c709a24f130410adcda2f51147d24c365463b041e99bfcdda3aabd8be60d7c1bc12ac625c523c9ecbe2d3bc9d05a16acee170db8f065301fd6d283971d77aae2df85c5fce8cd18880114898a750b33e47f24dce229276faa60f65d07bb807167eb35ee982b9a561efeb494394bf874abae64cdf2573516e8504c4a38084106fb549d702660697b05bc5bdd67a", .Okay}, + {.Lcm, "-59433b5ba9cf9f44e35f6768758daf1d2a8b7ee37eeea18c71cc8656c36983dd84c98d0b61f1d36811d9451812e8253e13e92b851d631cb4c3ff0db929d58dee28673216733d564f78991cd4db2b594266a01ee50c16ed167e7a38e4b3932dad289d221791e9b39f6288bf4019adc9fa181226ab4543964aafb7c01b34f2cd4b15675a9e42555aa5994fca119611853cdc97fac5500c", "4defe87c31e7e8b48a67e607f5f684613d44c2eead32b6a3302594e7c38ce9b1c14f0cb404da0ac2f348fec698223254e55a78b864e70f2dd219ff0e2334ed9cbf50052c26a9c920c89a4111b2b481f9a5133d530b300cee7f04508f12a8b3899c32f6c329051b24c5c158d9b9c288e39bd8b14c1cdeba6cb88d7454277229b3ee22537d8567b193ada39707fc19be68383743dc842c", "f875b3f8df329d3e4159803b4a96b22440029ab2e57f3c7447de8e9b55e312ea6768f12bab9608eba3dc4be6cb7dd9e634d2a7495451299a48337d1248da53fa1d4335a8d4d6a6fd9418ff8bddf67e6ccc4a3061aa042c688a0634a719edb2637c1c4129b6dfd17ef464fd098016c799503944bfdeefc18f807c684ffe2ae560ff5580c92caee8639f8081c3c5e7b8aa35afa2bbc70531921a194448fe9ed961efce737c901b9102614f3e8be61eb0ee1706496d27b63168c058dada410e6378f379c325653a26ed65e8a98e6fc344c484632d2311fac5ba1d044aaaf8cb7fb189a53f849500637c6063ac946b00dd6fc0686a237c1781e2d7a4ea4d397c2bf8b4c770bbc7297f2ffc189b1c189e589e888dd1f37526ab95075840a1d58e7c4f6cec491c4b26d7070db65c", .Okay}, + {.Lcm, "-2033cd28efaf2f6530c7a37891bd7bb7a2a42ea6fe0a72cb1207fb066dfc7d3ca17676cbfa97f2f7756c462479a33f2efd147620b6b21fa665b0f7e1110ab7c98da04bbcf73eb7f685305c4cbb75e29c87e9aae3c02e1f0ce0eb73df084650182d64943b2b9829c05e46a6074063cbdb268bc4346cf828b1ea67fe166de8cf16c24e66e5e910a7e83c84422fae631ad0ca65ccac3263", "45d41ecf1980ef6ea08905c20a61f1d029cfbaa27e48d72611ca4b18597c48175ac9247eefb74a8367f7bd50dfeb4e22ecddcd2bdef1ee57c89336af7c3dd07d64a6d5c17266b0ed16d301b991da82835eaa66652bbf0d039a9ca1e6d9f9413104643e745f85b3050d75a625f2cf03581a9dcb63d80462af93603d1beecaa94b0c1ff7f38c18977257f58a31c049362f44267bc76c9b", "2ed8c5b59e1395d3d0170b98af50e9744684141d65f69ef12764e5d556cfd7c7f0c7f3e2c344089988a9d90fedee7efd1d43e8483925a0ad066884ef1ee361c101dc2b9e70699c236bd026139e607db6c8de91ecf875742125bf278f2981d3b0d2838d7cba083f08ca187c581e33f3c68e995a53025193da2afa41a0fc79810f1ac752d05a519510765f1b99527b7042c7b1fd91c160f91d18e7c085d5a58bbefac75cdd564d944a5a37061100d0e57ef2df333c6000dbe96d4b46f1e0211fee1e75e3e78122bc1d5581ffa135998de1c9fc016553a041306dba8d1b0f62806ef0ab5b858831fee2e581db2bed6aa85e55de215ae002d6fe9f0c15a930b1ea8985356cf885d5872f63f5e1903cf1ed2ffa936efa68fc52157b1ba20930df7b451f0b8459b21b394c47dc1fb", .Okay}, + {.Lcm, "-51a57b3eb9a49ad593092360b416e7644d6dfdcac1e78d2c037ddff033b164cdce73dcfc040aaf52516cdbce62aec182a3b5d2f0d5d5b8413490e9ce0f81995918cd143531b3a71c76c8b5111b8c2168c5725028069cbce949600bf8b67b0f1732df9de411b481c8244d0dec39f64ed8ba768e221f5d574201cc9af36e57f3264347a9b98a7165eb6b26eb785db7bdacd76e3cbe1931", "17ab7c435a59a94434ffa44a4356e1b95dff9d06ca28fe0471a747eb0765316190a368e72a9040ce00e3ad38d11bb8ecf4ccdb0d236b562c1a38562b8b18717d964cef9be67d3cee1b5697b858aa6548560350d9837b77c110795547361429f70857a3d40c3181f10941efa41bcc4dc754e17268c1ad79c0b9daf537192a4d0e4e1b161c93f1d20af53772003b4c9ff1cbb7b75b83", "78c8f3d9866340ad33db58a51a315594aaad12220d78d40664b7e0659e87e5a5e02dfa60d5095fe6f15bb514e9cf7d0c5205398a3e069e0b92838633e7011dc202dc2e30da58de64836f32572f265055341e3bba76e4464fee573fcb69d6548536d53ae7753f5a197820461bf6a68ba9fb0cf8a5550604bcbad8fc74b95265cd6963180399cdff2bda2c5424f20033b87feb5cafa93de55d480a7ba3b84a67bc59695977485c9f732cb67aa34854a06206bac103cad3733ae65f00b9a3ee76ab71d1181518c44f92c513ede4825180276fd3540b995dc578b4ab4fc4e8ba9de5ee2058832ed910bc2982f3b44cb32e755cfb28a07f20feddc73451480db25574779a02c56f47e4981f68a2e63a01069e52c10353e8feaa3962d85bae4019703d6fd709f23d7c1b1424f13", .Okay}, + {.Lcm, "-502d5dde855fa47d0e30d92544faa7c0fc5d727fee19da534b9567ea85b80e5c1c2af70649b6c85a48f0faf341d7378165aee0b92bd03cd8484f41c593d312b5e7cf208e05240e7fba9236115e59ab59870acf5a78e9d650f40b3676b5aa007e9583e33e4ebc653b33cce151bfed05b311729d946052694d9359cb4b1623f221411b33d7c87997a84fede1a01f938e0d9ff03daef97", "6f0c668aaac222f8bf5281c14c1965b4c0fe228fc74a2c7d19ddb2e05d46ceeb508eac7d64c83d97a7939129cdaba9272d6a478b862b6b223b0404e642e4b26f07091f91e98a6a5b28cfdeaff6829252f1fac40b0c3907b3454d35aaca01566606be9c176e26398b81d24d65ace4c38c6a9b4c0d9f99d9ff1709ef18c928f128ce1b7bd0d027487db1a7456b3b8529713478e8f98c9e", "22c78df16398e990c5a51ab48b525ec99bfa8ccdf66c88637384946ef186f7c8dbe429f9ae78457a644831e364f9608898040675351f1c787f0e11d689d958fc0868a37581cb25ddec33a445d2bd1d93eb14123790eae055b25e18ae20d6f5d4a3f1c98ef4d202c3a3c895e91c6cdc6ee62bd6594bd43cfd33d9c5ff3616ed3ed46c3cae759b727941d2cc719cd13cb3215e2b0cda04a62e2c038efbbd334174a55e595f12032f21962622958a93f256455563762578af5cab175a1ca1f52d8cf471d7a90573c49d7aa90f401b1717b5fe9d679a87cba1831d19855ed1dfe15f95e19cd9d37e73c161dc80b19e96ddd349f06e339a9dd06f29826a9ef10d39cfb3d0d23b3561de84484040e956b0428f8d44534b6d536a46bbaa856ce21135ac805a1f76e79255bfe057332", .Okay}, + {.Lcm, "48e544d76a3f31d24c01b96193c013d739c17bd4526ff7b79567445ea49ac8c3668f16cb50b2941476599e95a80bc6099b508b0df6c35ebcf343f50d87cc40abd3f1841ac711cca57a5d34a51de65b02448ec4838f0b521b1f9543d04fc9a8002cfa1e1097b49e759ece65592ce9cbff1f7fa2411bf8ec075e5ec5fc254830c164101e9a22df08f88322b27dd878fa28f72e0d5c3cf", "-de0f72ef55b45d7d506ffe48c8de35add717b7d03003f68dfb1096bac2a7bd686be2865681a72dfcc98824747435d13fa88517d4eeb3fa66571412b47956c9fa009d232958df89ca181d5582f7a3fb5f97bc7ace3ba9da34e88cf2c24c24c8ed7c4e4465133b283d6faa204f47bbf5f241a74e7e6c34253018d63fae75bb1459683090daa2f607572046c2487705f8fd667476fd0b0d", "3f3b37dc15dcb5038505342044a6c9459f18419f689ff988d500f880b56b5025bcc193b970b02350767132f85e640f80d869795529cff1be6392502092828ecde334220c11c6e4f2a594843ecea02868aac986d0a78a5a0ea7bb9db190e3f16ff7783a44e24417904145b23aac15f42712e671166cc82e439090c889cf5454d17af828b771897be4145c699cd1a6d71d13ecefd30e582c59c30d5589df14a2f9cf5fac0ac7afda35f33a22ecc6ec0c4caef9bce21ca0b69e91c88eca8956f57df64623e8ec6ec6a6ab2831e0fae44c873a343505e6be69402b311a662ad05a408a3e2b390095bb407b5f789c11896655277d4b98db3890a5d510920b2c8877c2fcc2a961bc484da526275a9b17c68b81c937e594d043e7762b50080fae2c50dee4b0f76180a27ce87d7d683", .Okay}, + {.Lcm, "-7f5ce15d7190ac2d04c7112e48d82ca313efaca363966fbfaefa626d83dd74ee40b67c3efb86a567e221fade0089e0588d29a01d31a2a1afb6054f81453f0b6ec8e819ba0359f32884528895022121b4dfff4ea53388feafd49bcda6d9fcbae53bc7fc2c3114ce71a22767103722f934e8d311a22cc8ba168bb54479fdbc50ffed2782a98fe70fe930e5a69f0669a1c7a748147282ae", "fd7d6cfed9829559af866d6fa8f76fd96bf655deb820a80813e672396127d85454f42bd6169a04f2d6ef6cfc31398c505ced53d533577bf6d41b1001201e046084332046bcc4dc486f76045f5c5ceea6c4666fe1d1c322902c34668e7f6f066c345f6afef27351499a167f87af2d85facf3d1a8f4502e9c3452757ec3b1d2d3ffae21c7bf2dcc67fdba6ee8fecb932acc7c24b466cc3", "7e1d314d5d4e26ec9a624cfb129ae8dbdcd1aca7186e139bbf62d2280b62dfa393a6d34a0f62f8be581dc32398775276885c19389a5cb4f07a493072761ee1547254881b45006b1528c34f513f8a4beeac2f893b7a72b7ecb3ad18e0db19387bb4b4503f2b3796b47a80aee2d1d9f6f76fe332cbd6de1e89648e4ba79330ca8412ef618bc37f01ca452a04efb00f8e66b88e6c8afcf7ae9417de766c77a2847e94c409c9a322d82379994b8152eab5d951db5c2250d7473564e21134b6f7d2806f797c561bcad81c65dd6f1b7f24d7927be7b51de906d8d5b0c032522823232eb96a8aa48624bae29de95244d314a4155b9ecd5d23ede7279e338ca7643b331e0af6c7db8462d103d1d8ea844cec842a4610c2aea0cf504f0332f89f050fbf6e144aec089c9e41fc97eef28a", .Okay}, + {.Lcm, "72f09cb6494c610c37556cf81e4c7d2e637f04f472183c45584aaaa824178903aaec9158601931262e77fe8f7ff6362b7166524d72943f4ec62e6eb427d4fb2d87409c6342f4952eb55176e0b284814453a1299633e84a5b178cd8b36f4e8743a6eb8a833951a8af6f2a0a342934f3a744fed094aa00b45937c2cf5d0ff6ecef1afe437c65ed71e1aa46a47ec2d312a25e4521cfcb75", "505c4dbdd0706219d4177e4132b546fb78e401c9772179d36ce70b187917d12805d60959779c959ea202a2da456e9068c786bda52786a3f7ede91313aaa9ed28641e54522e1fa578d66553fcf1a87f285d07516b51ea63403db0ee2342236f7cba5b6e4926d1520c14249b89e2afa5da30aa8a431df9f89cae4ec9444e5ea82ea8519bdfca340cc0e8e758ad0d070828ac31675d46fb", "2414a258e0c6b10b2847eb9fc2765f60606e9ce80d985845b0fef769f8225d41135b6972d6b08661a75db070f40a8c27a0456afeb114616abeaa3a44db960ee3517b133704431cb1f718a45923a2324731d9c0331af21202ee225f6f57bcb1a256a07bdcd522510ab895dc9f696017b904d2d58c0cf05ca7ec15d07354a2e14133c6ec0de29767724494f4eda870f3cf3c0b3f0d7d90f76b07d54534d46cdc148914d3ece76c364f70c8185363120d89eb77f4e568f618d97db5079fe44d9da701c37025048a0e47f1d395ac106b37f10c44ef8c6e1c492414e45f1c0097bfa7c1a07f93b651cea52cd43abaa3805f152a2fab6b37068036f810d5c2fa17f65a4f04560063aa8b87605b98684f0616a05c0ae48c2adc37e4ee24a96475971a7561169aef4271c5c4f4df79b7", .Okay}, + {.Lcm, "11d3d23224bc5d63ac4b175414d9412846412c02a3bd0c6e8ba2b2d27a6daad3a95ae1d0ca22676646f40a7caef2fda3bb19462c149c0d7372abcd0d55b7af45f274ffe09e4c652b2330c7eca5b7205cc481419e52da146279a19dbcd3b3c923c0a52c2f0c49c3bf91c43ac21bc7e4e923038bf5b2b71f0b9fa8f465311e2b23c083f8d898b491274152a14a015640c8782d37f1acb4", "-24cc4bd5d90c51f63e431580397dfb8d8e0b843ee9d04ed84943338cf13d5a1bae72399cc07fbfc095ca8cd59a56c20a667480b1ecec303e39507e86ac6d80a6af4bd6593662911bb047b4ec613139f3ba717f185cb4c53cbd2648ecb788fe9fca9f5bde71c6c314b235410ca487ec9fca87494d10cb64fbac9c9b55ba62cf8ba5a1cf15f0f979eb37dd37eaccd8180530c56d5f861c", "a400e8a003f021eda7be4abfaca62c40bca4e6b91b47346250b942ac7b6e2b21b6830bd5f0a0882b11bde2379fca379cbb18bd94070f54f61f7ad7c642db5158e706a757baa62b7f2838ea2f2b564eae1f0b960a2ac8f902f4d75cd4dd08d2d2d9708993fcefb8fb2634ba14596e5205d76811bc2e415823db01e8c577402900cfdb9b548a5faf65612a4448352082fc9c00a5428726dac173013ca32b0cd15cfd2c86a05488f5d7f035e04453ea4d5d0912e5cffaf2153bebc43f712f936e59562e28f25e00a64001c0924e1518577d6c33c5a8933f409666caea54e96e044659c48b33cc3747215cc85d79b91accf05a67a9c4f8109e1cbfaa4989d18ebacbc0c795bbc8081ee43dbe7a0cc70422ee145df8c4c12ce89b1da465308111953c98637e9ed387fd966846ec", .Okay}, + {.Lcm, "-36d643d8a959c3e1edc675ec1cf2bc1f9f7f42898829518f7b29af15ce1b169c8c04f14d3450565ce668061a460f057d95f05a685adaf96e3ce98305afae0a9dc70d1bf357b10bb8d7b0ac3e9333ef679740241937b23542cc80c4ed2655ae8fa0907ad632cbadd0e5e91673420477f785943bd7352bd763137f465b3926e4523f68b15d5b6bfc027afc58691e8da4bccc274afea499", "5de3f646d1870d9e8fdd271f833d3e0e80cdc19ada2ec43e912b1f5ad5a78d8ce2b044979ad2174623abb8680cd0bd870f297ae6c850b1971331d8bef19ca24e9100aa15e4b8b6751d7c6accaefb6517950cfd9c1c1b5a74174a26269a3b7101134a4f188da825f28253e4b607d27f7e796497768e1e47f6b7e9d543aa243899af050ccd6c7937f7d10092de8f7307389e3ae9f2ff01", "141cab64ef4e6208d78220e8e11c176ac559a2f574386c1eb5bfd1c48748ebbb57681a3913e9890fb5f349ad03e457828ae1738b26b99d63af0048b7ed54c3dbcfe87abb4468f40501b0571efa468a8fce40ff9135d32d8fde9865bb69901e4d327bd4b915a3edb526086f572db3c80d2395d252552d12f2de25424482b9fdc786603f8b224d17071601b0704c91d95036a1b425b397bdc1508dd35986cc1fb33587f05287987f2e392f7d7f2199ebf3837ed85db2ebcdc850b03610131295e29219622bc5c49ee624e67d664e25f7b0e3d47fa785ba88384f5d28f7df45dddb9d5d9aedb5994720333fe45fd0f9b64cd5b79fc7203f2361db8f7ceeb100341e4c4dbe1d32c8c10d9ab834214b485e4688a351d5e84f8f1df00c18b25762761d5c1d0d0dcc3e510bca950b99", .Okay}, + {.Lcm, "c34de193b1241d701d23708f74c178a9e266f6e2f203b1234a60f6340b2262f86382f559a45b41fde5ab2ac146a63a0475ab66793da854d390de1ac92f9de9f9af89edae4347a5eb651f6718b6175bddc421f5cb290fc9011cb8e11a1804fe68d1709b9f1c397d9dde63b5ee04d157ffe638ba4753831e6c5f9206e0e023397e4040ec63e324b0892c02932bc4d2dd59e609dc91fb2a", "a65a63ce5803743ab94d348a78baf178431f42312e18807ef0bcf10f1e42e144d1f114a9da6cc55e1439204da54b5f8dc5e1b14b7c04e707bda75b9a89179598d37af05ccaccad258248a03b9f606ca3c12bfee3472e863a7705260887fb5a53a0e678bd65f91eb161c2333f9f5eb26fc2941501e207618e5b53dde3447d6dd0efaef4be54fcb9c032474a871a2f3f982bbfb789a387", "7ee975cb9cd6bc430f9af8ba2b62a7d6895f310ddd18fd57215ef263c2fefa9db3aa1426ed645603a83ffa85393a7f7b6648b6da81c17b5ac2fd7ca48995f748d186516ab7c38d3a05f7fd972c68d3d47c001778659b543ba1b65f14763ef635d092c7b13bd664ba2135c079f8747ab103652564d8d71cb073a1cfbc0fd81cbb89905b0a31848cae31587d319fe97eb45d621341b5574c7534602206257000b0c3d6810f66fa25dad119444ff6c5a7f4d48cc0703ceab652e685c4d915d6851007f59d0d0f59ca8054543e1130618459c2d6f7ce38c90355913cce64fc812a4c0f8c235705305bb66b22ca665bab4f74027a93b703b3a80ad7f442da599e207e2b94cd17cbbb4ad83755ac92cac8906cf1d7f322e2b92404d7c307ef1433531fb7c9544aacde6da4b3613126", .Okay}, + {.Lcm, "-8dd5e024cda985ce89c7718054daa647fbb4b9bf3d7a7c7f5fe3f3f83cece9bc735178c4e374fe6194ce3d45ca926973d38e2e725ae75b847494ff6d8292b4248208532dc81dac0a00537cae9a2a26bacee9182e98350e4914a91f0e8752ab68eca7d6c318de096cae6590eda755992ecc4a3af4655ac67371aabce0fa44f4a81bfca09da0918e828a53ae3162a2733604bb869d4a6d", "-8b7aac41a29a861576b8c6cede8807a5c40421783d1d513c60ad5fbcc30504da9fd1f998ffa56ffb2d8f115f3e7a9dd9c1ed0dd9b891ddd833c24ca3013d0070bce5d7ca049af9a35988a1709d9e3eb9aa4b443f73709774b5e02db8a5eaa3ced3fd2fd15f9d09fec9eca84096b3becdcc01bc5fe49716f26d517eed4a5031c1682ef245c9dd15b184e8c820f07eea0f33e4ec6e6a73", "4d471810dd32a6c0ff1d4c32a7840161a137b66fca8efb381772deb7603ea94eb11a36ef35c6ec0f989a423e7c761a768b59a6a9ae4dfe924450edb3b284975e514f85329bfea5551a1efa29654fc06c1d899d81630ef8f1d2c3590df7db3cce9c3a7bc6aa273f74c7847c37d62200b3dc4cefae5d6fd12c1cf374b46316e18136e8e395e6d17ddaec1151dd1721c7fa21f31c42c72e5ac0390bc2b119ff2e1dfcbe87f02d4351399f45b764250b3a317cc3e2e1bcec17056907df663aa35866fafbbe80d99a3ade0286af941a05f417ba07c4f7a405401c39b15d537b0b740464bc15c8d6129d75b13f58a78aef2f71aa1d1abf9a7c3c254fc6a27232edfcc7d51821b001c9e63c4e3c94ebe8ebf260215150d6da9341dd1ff26e03d6d5ff1412f0edfb40339e41104f90f7", .Okay}, + {.Lcm, "-a210c162e0faf829df5d5515f42bfee0dff2bd59152fed7d070c4aabae5c5613fd74b7b5ebeb2527471c0c61ce7be0705d92847a7b24c807da8f76dd7d0ea36d7186c702851a9c568e3b95e05509e72e2027f0471c2db7c4203880d5eba6d17cc5c5ee399b34deaae00858a1409bddd17ddcb80a2a9dc1ffd50ed8a2da8df4d4f673e4770a325bdb60f212f35367b3665a7dbc238b71", "5e06879338227f02f7cecc76f74b76eb7c547054a01ba126ad496a2a457da213a11baf31d4f91417fa513a28efbe908bfba84a67a087a7678124cb6c1a2b7818fa40b0671bed9d5b1413cbd7e1cb93ef4082e1df0902de4b9d6c144c09582f2358b4d785ed2ab62475d55b457dfbf160d6b301b161f2a45c84b57af9fd1e1b26598643eb5ead55da11c205f352ba6cc647a2cceb8579", "13d76dbe4ab05f7413c1d69788620e0deac8bc2f0615d50809de97b2b3c121ae9dc1a1fcfb2ccd0131fc955c60eeb10eb300b107df1588ba384c29595705e0e9f839a3a2898f8ba7505683f396d6adf43afefdc2d75b84d6c58da087e2455ed6c32534b517ba69e0a78c1f31c8244814a8b1c408667584da8dfcaae3a475a187a2c0c703eff8695f51daf616f39eb4576cf6583e439ddf91d64024c7f411112a9f859456c2be65f138346dc4d454501987ca19a1650a6564317e30192b87b2d5a86d4aea95a3ade839d4d0faac67408339ecf91caba8f3422abbcd8f141e4008442564616a2d5bb17dedc5d30aa7f8a1ee14ae9b55e9bb1d990a4ecfec66f297c739ae627a90a7173bf7d331e7eb9211480e91038d1b2774e0253a79e664472cb8e93b7be3c43c247afddf23", .Okay}, + {.Lcm, "-316f66135baa832ab033e4654f24d4e6d097abb63cbee9d8a52f45f84af4c04864980aadbae50cc6f2a316aaf5de94fee64aea8787db607544b89250219c3c79c027aa69fd286044f311b6ab1a3920363cc8c7725dc43ffae83db5dee866520efbfd44f794c61783fb0c16223069e41221f796654a8353d5e30959f6d698f948d47ea071ddf648bedbdbfff0d47c7d5cb37e633cc7f2", "-45508306260654684c1dc6fc4dbf4433b4283e52a44bb600c4c5770699d3c49fcda1de7f96a96611e7bf3c15e2eaf7edcc02b7c260e1e3b167664a65ce04cfce1f24a67b5a6a9f35dcb5bc7727d90842f83b447f7b52a4c63788e1ec969d0631b68f0553fb3517432a856d0f9913d4ec14cc574421438c12eb10ec373ce29d3abf4c911fe6fd03c12cc10a60ec9037b8f5598a5432b5", "d6292a04ef1a90fdb7511b32792e13da5dc457f0ee88ec8c9e8f4df2e1db22b29c7559c2487878c3ae0567c4e368dc8d351a4257b9c34dfe5db114476d17f92ec6930a312462e166c0e911ee800436d43e048a0056f4f5c577b437dffbd866ef551fc627fc8ed499ff056c24954c8703c9121edde058f4141ced7ec1fec3a6ffd0aef97c2a9ed7b2ca95543be438dfb2a5f33f3a13a691baec0ea5e652439343370a6d1f5bb09e0968852b39c93c0788b63e9085cc5287a5497c35537c562f0b3c44b2d4e61748f06f350e695bf14448bece335ea3e9e36e2d073c68c4498833e8439dada6fe49ab49708ca31fb7817a4a458df6351a6d39b59ac71dcdc95bc5e4268cb46f8d263c096cec894bf049112069633991483c13fe4fcb2700da72c93a2f65c23fd089a186ea21a", .Okay}, + {.Lcm, "eb64d6c454ea01aaad148fcbce6fc6f04f15de0067396b7a25bbbb03bc558159da8979c5672e9fca01b7ec1e99accb74e22ad56e708966e1424820b50e5765f9b20abb05dc7694f9fcb2615bd3fa35c0712b0078ce4858f7505966ea821498e41d8868e4f6c1b70e7cd33aef6721c9e832f4db627551169f280a23f9763fe7ab306ddebbef0ca12b68ad741c6c2ec34c6b4e860d2308", "-707a8f57044fb4d3a4c7a375be02598dd8b48f8c8414f80699c0e42217f675d0d1fdce72d1527dd4cc920a1e3080ec278de414a0ca7f2ff82c1da8f5fcc34ecf70a77ca00ea28e8729e41d47890ba6143c321cb9f3ee8393f0f99e8d1ebeacf2b8ca626564d670f94d53a7796415fe7b4bdd82e0c3e20d6fa699b047995d962c34a8f30988d01bfcfad9bcb5643b3e6db9181bf7a92b", "22799a9b31f8ca0ca15b287a4c9410618254d6c12a723728fcc7203b5061347a376d82a483ba5791b6e18ad96e324f21522466aebc86958b1ec797b01c8cdfa8c1ed490a3e663ebbf41165b040967fb149c0cc8dce5ab37bbb57962b9d49afa021e6e568af0f59600a9e8cbe07e4216ae9b23ea3ff26215011f1312c787f83604567e46480a80cff6e4761a8a2f2e95962c51eda1e4c8ac0f3ec20dd917dbc75db4483a94cb0c6b952ef6b639e9d2d6b0dbdc1422f599abcfdb5e90f3312f69ca7619b6a7902fea724bb0aabfc08dcb29ac9775ab10611265fae7242552c2f3f38163e552413b5287a4402015a10a42feaf70a88e2c86db5d5c46f321ff3f3df1319a0ab2af36596f7f4a8730949a3b20b70fbb399cbc317abb46278569659a3d44b995453d7e2449c59b8c8", .Okay}, + {.Lcm, "41f29d70f9c0c435f7a18a15bc60d4275df65fb0f6e67b8f308133f52fbf428c8d55fe6e604187854c83905093b723021209be866f3cc63c2c8d40d06dcb8e83fce8112c1173683837174deac0aadcb51265b9a19ba012fbe6466306bcd3e172601513fa2664118fbbc10fa5935522daf6f9d7da5378b47d190b608ae27d34483d35b9daad08b545d0276c4a08a6217a34b24f76f797", "-364c74bae00d6d9807e2f82e5cdf92440e1754e5d186a633305c15569f34668efafca6308e670d02a44bd5b6a759d0570e42e8d770a543c2a0bbfd7adb3163a676bfde9663f86e9c6c52063b60285f520bab018e89f1274d8e5474e8df34362dc10362ea88f289a7bfc71f64429bed103aa13ad35373a950e60f122ff98e0d4e1bc8301ab41edb5e21a6219dfd704bf78ebdee12d592", "4a99fc4e1da0bba40898c45c4b76683f1996fc4623ef1842ca29d91f9b7561ccd53540df403576fe46b3f0ede3ff97c0f3f1a6b6e20136a890f790f9bdadc80106d9c271148f3e1e3c4c43d1c6a017b3871d191b0eb45956dc28c2fa1015686f4625e54a354d739e833a8d100068bda4b77c7ee9763482635f00eabd5320d4b8afa743ff778936a67e06eed54bc92dbf70b0241d81026bd8fdef71e72e92ec1c0199cb1cfaa3a143e363c118b4caacbe581fca75e856a77119f468e8fab0f1f07eb03b82065a900301dc6e1f9b6d1cf9636a0117d79d2fd9a596caf25959b53d06cc0f04f347d776416fe9111c8913002b27cdcac32faa2d7793402219f54575e6eeabc16d6f9250c90bb0a4b6daea6db05eb88e268ad9f0edbf24dd1e2513e8c72566e029ab79cb2d29d0a", .Okay}, + {.Lcm, "44303f044caf28e10428097cbf897c6fb9f8c980cede1718793cec601d3b7093ef6ae0349170c19f3aa4e4840e18fe61d682b0e963a595f9fab184d36d02296c558b763b6d84010d660483f27f153b581d5c21d50cc73ff68bd3f1bdf22f886fc157f0fb4dca7d3dce07092ad6976f7cea012557434aadb0cd5c95cf519e04ff4605941140a80d35802c1b74eaa7d6184ca299b8699a", "-f1f7d8064076ac0d0107161c16e68adda1237f3905d303ad20eeab4d2477ebde47b6fe98952fe8ec85ac46ed54224691ca80a8372f30b081e489c629a7926795525129c2959a289b8cf58c728b36090e175b9be62d0d8596d84399796187124da7706a0ad8a96e95ad97982ab47ed5ec73b3b480ad8081e63c504ad73ecd8cd35435a091dfe71ac1cb48896240c13f81337315892160", "2039b7b51c67d48dee6a68bf41f93f116f5ba9f60e7950c3048b8f5e237691b620f63548354e4cffe3fd248f89652f85214d9e8e7604bb42721c0ae0bb64b2964117bfb902bd9c5cc1cf7525d7d31c6e71ade4eca01a1e14846942fdba917e4c3fad5ea2c1fc73d83b2ad2654398373d7186edaef7fad61d7aaf02c8671aa0a8020f993439595c7c538a5f95aaa656697ed2a88a2fe7a55b7a2f50a769e638e17ad67851187234c4f916410c3e0ac9320b686a11a4481f15351f2f410696e91d765b403a34813903bc3a2bc17e2303ae650fd64bf1512b583b8f842105b4fecf2beadbdc552436b21af68b756461358286bb0908ec80161f8a4e7ae8ac3b6e4a08fd4faaeef1f933edda147573e4f2c4fa048a6e7c2097ea77365bc36555433e18e6fcc1560c9aa9481739e0", .Okay}, + {.Is_Square, "6ff9c7204336d7279bdd07e4bfbd8b19dff529168513807a1fdc9d24c3a771d9506f70ed36fcf3a4368afe46e50db88a42127d941b7eb3a36ec700af096440dd9a95a8c1f548a995108a5c93d6c1c54cd56bc0575cd16ce2a5d978c5c9df88404a34c589339a58f4ad14fe67d5c2635defb742041c2072da15288e6955b016e491621de821cb15badf1672e2a9f85ae166b1e80ef9e8", "0", "0", .Okay}, + {.Is_Square, "482821cb825d8809b59fef6bc6c769682a9fd80db94a25a0fcabcf9be270ee97f9ce265c61fa98e6e6145bb65f79961b8fda88c1362b041cb5fadd81fe9723f445495a7561df1bfdef24d668f1ccf82df1b6d4851e4a01e1d20eb6babcb47a9762a45770c65502e2fbf71772af63f96d2d26ba816f5597a0fa5dd82b5bb54160fff8dd2ee9611eeccb0886f5842f80d87edf71478230", "0", "0", .Okay}, + {.Is_Square, "9590ed552e02055973196f228c6496156786e33a16e91ca1cb3fd60654a9180a42a83b333be5fbd031b2d634c04abe8aeacc60b8dbfc53d2bea7ead7c0cc7570adb413bda2273b52b1b490f2dd77fef2fcc2336ccb4f4be3172709ab875f55cbb2e8ba161768daf62a903d4c57dbc492e4e7a873e8e3de2df29329eafc96ea2285f43e255989b01644886bc5ae98236ffefb357a22aa", "0", "0", .Okay}, + {.Is_Square, "fd23d6ce100d23f1123c60d19aa2e26c8b1ec67eb6e8ced4d2cf231b559fa0386f5ef8feab9acf40888d5d20bedc9426c62e8148091310ea14225620dfbb3bd6027a26b0e9f52591673044f9334fc8282acf40b094a3dfc1fe9acb3bc4e3034988f47ba7393ce2f050c2bbb5fa175dddc631487114041c553fb1a9070a03d613aab4f7eed1a06de1b814b7334807df736fb99f7e7752", "0", "0", .Okay}, + {.Is_Square, "a72d043c84461f66469400daeec066a1281a4a1681a8d44fdc83465ce30a1688777685831f01df27bf1ed0b3b74f0486f68a9d6e8c7c5b4fd84148f9a3ab2e9ae154596b6cfff41f3a64efc609308d9dc8919eaec01b3668dfb52990e1cc1ad9bef421d126d5ccf4a55e91f31a3c82cd800e03064c47301d73d9681ca7172b18e67b43f1fbabae809f05382c9fbaff4a463eb7a7c411", "0", "0", .Okay}, + {.Is_Square, "bf42008656f02755dddfafcec18e4fc284630a6fea977763001bd121e0515fa390565151978581f2c6c906059d9e497d05193ab2afb2d068c73c623784642121e87af7e09aa9441f0a9c79aa8bdbdfec4d727b945ad2e5dc36216b60ad153e8ce8aa800f0df3ef32750f9ef7f970dde2d11109493a242b64421d5ba142118e98fa44f17cc3ff6684a4b32a4ef2e1597c223c6fdc6e08", "0", "0", .Okay}, + {.Is_Square, "e5c9c91134fda852a06845d7dda66a33fcc178605b31483e87ede27cdcedb6b8a75f94fe20b904fabef6375d5130e2c963dec2d6fd7b99dc843b293b43e638b53169f80486a1cb0099288334494f7719425288f365ff3870913b2cbb6399dc9a5a3f0a721ba5e24f5532fd0b30d4e4f580af2a2bb8cc9c94b33351952dfa261987449560a46921655f6ad7429a0a6dc56a4f637659de", "0", "0", .Okay}, + {.Is_Square, "f8eed9e715c6655e9ea9cb55f812f23fa406719d2d53fc24ec7aa6e97f4692123e99c7a15a1de16dd7fa1edb5a3c68f81e80cab6347fa97df9eb7738ddc2a0b31b368a2634bd89a4d83847d582462d44d23debf5554f3f18aaed1ce8313cf5085eb038149e22bd930b5e20e82c203b45036a5928f21c9e5002ac64ae82c5ba838cac4f55b4064d14a897e03f285254173fcfc0294a34", "0", "0", .Okay}, + {.Is_Square, "6432dff0806c950e23785a8c764fe2b3102eb313b4284f759442c4f3c24e80b857feaed0d6a9cefe7daef1cf3b71dcc721010fc23dcd842238f0e8766af4e1484504f06466d89d52a50761f09da2266afd3fca19663af11021fee78250ba151f0c691e4d5bad16cb08a28421df72ae64fa85ab16f95f1e0bf8d17ac3409e9895fd2adc783e418d206f54ee7c8f27128301f228c5c5a1", "0", "0", .Okay}, + {.Is_Square, "748b6d54320f760c2cbeb0c153ae572940e89be3629b2b70544675b2773c5e36a4cd0f64182877430a6c6ea0366888945b3acfc9b440db0e1e0269cdc600a9e02397a167d67d3a7c6cf473adeb3c6859e1a410ec2e8ba1484d81d96779a527375f5f49b0b425e3df220eb7c2417bb981105035b3e742bf660ded6d1d63b0f61e20c23842446321a9c374d13f929b652ce2d70356796b", "0", "0", .Okay}, + {.Is_Square, "f91a460aef6fe78563dab6e5b33b1928c7c0f08cbb8c755d4988a571ef32eb7039421835c5728810c73ca7f41392867607d3c710a9c3a15f5267adf07d379937f4fc5b6e02d391747601c9dbbeb2a723d7080f11dab8ba0d484274062e94037eeece713dede30e62a1398ca78048447a02674387e54ffbfba80e0cf7e65be33d2b516fc998df4d2fcd18a0d49eba027e437bcbca22b5", "0", "0", .Okay}, + {.Is_Square, "3eb5906544f6cfa2217431bc99ad03161844bdb3b53f5e98fc7ef5c620d6e603100134f4dd5a1d9ffcc4eee645eb25120605623a247fb05d67753b9e1ad493392c13f298ba68c189477fae9ef7e3962c35b5bd4b718630f9bcc33dad7c7267d7df903af7bd9c4448c3fade5342e4dff9e40c9526d7619a640de6c31a15e8172b59e7e32fa814a2f10050559b74a6ec389412769fd216", "0", "0", .Okay}, + {.Is_Square, "49dbad972992e0f3fb681870b77d7273397d160bef10fd0ab51116881c45fe7c27fc249960d097c1fdb597a2301d03df30f1eded48c33f447c88cfce10c0bed5a097e4e75767ccc15d7aaafcf6b483d1b68b8825420d46e3eab982ae87ecf2cabc3adaf2805c1cb9ca9b0ab4e3e784c74899a8cee088fb0314c359cd65a24abc14216579d6f5199a0eaddd9da366f5b06c829bfda430", "0", "0", .Okay}, + {.Is_Square, "d39a984e4814cb09aa2c5f440ad5e8d26b8de1662d9192ad8e99bfe537ff91d6155d6c447439193b36a39da83568f321b93ba893b16f186eef29076bd75cbeba72e47ab179f1a6f0c64ad629f3d3a9f01db5d05b98180d315e7d2ba2899938e445d1bbf1db91a1ba2b4355f25524cae54688d07b119b5e53c8d153612646c3d5cf9ff4721ff9cc1153776791e74c075e96346d21d45d", "0", "0", .Okay}, + {.Is_Square, "9f1c5ca65141ade394b41e007e6d4ce3cb4d8ada3cda1770e157fce4c87b447a2e3e8c30bf5b5502ccbdf28e74aff22672a584a55f4eb5e629f16ca469ecc9e43db2293f46fd8286a5778b9ebed973b5cd11269c0d18206cbb58c7021b153bc2aa09c294953beb60e4aa7870565c0ac638dbe5c47edc77ba0d796e646b17f4f2d9189f6856f1a24be04782d0329f065c0e05aee4a6d4", "0", "0", .Okay}, + {.Is_Square, "92e892ab51909c98af72be0edc132a621ebee6b08650e5a3a60e33f783aa2f5b7f1c1c140c6a0d02ec73221f190974a3484c43fd64a51f28b95807c66072f26e794a9da79892a515e8ae9835cb70ac487408f95ccc3f55afb279ddc7f8009daea492122415bca0e8c0424c0c0e9cb1eb8e00e1cc8f0db7823edaaa21b5e1c9da5acb2d4b923a2c1d6b9b70bac0311d1fc31760daad39", "0", "0", .Okay}, + {.Is_Square, "9ccbe47988e852cab4d763d5ba2ca7ab363d43943e8f4808e49e83dc8d17de36fd91dd365f54a1f35a6ba7a8416979fd8085f175d38e3a936d779c05f5b5f7d0ab2ddd6e657e467dd0fbb498ea360c4655f6618a2e3fa8e20bce4b18688a04ce01e4bb1012bfa6daa64ad620c0b544d12844891aac424a241134fad9332f86f8e8ea42b6a8261c9db27888900ee90abc6a06fc8b2041", "0", "0", .Okay}, + {.Is_Square, "aa31357aa4cb65524829173c430015d90811cbe389925baaf94df039bc83dcde54922332f539606a449ce76c8769df443f0293aac6ef85255106949d004af7ccf69a8858c7be0666f3157f5fa3db49fd469514575b200f707e7c62e287f1025bfe0116a4a9baccf20a6ffa879066686fd0689850a920f2859b69f4cb4ed2fba1d0828755af183ec2a53ac6be136b32789d13ed482452", "0", "0", .Okay}, + {.Is_Square, "22b7492b2cfb5cc51583016f7395818915fa25c01ba7f8662df3354e899a46c0232acc876282d5a3384cc666476efe794e985e9c98f4f9dd36e43c92c1a79a0598cdafabc69d8a9b0482c7d527ec47ce2f54e46ac031291536559e12157e2945c66927b4b9224765e89385526b76272b3baee99057087ce4fbbeeb230abe496507350dde7c78e803329ae533da21b646e08e10a7ffea", "0", "0", .Okay}, + {.Is_Square, "80c317697464b184f58bedf038b0c26c6da43b660f6263d86943e36a8311c93c5f5287776534b0f2174ceb5be46b46c360e1aa27ddb020f2ff4fe3234fd0db9ab5ad0c279943800bc3b3cab01789f3591d41027442c01b19a74a17c6fcc1ae81b40c653fd2614798f38b37d9f234dd166ffd7ad8fc71ffa6361624523b67f671c3748f690db777d3ab8ef5bb4931bfd2346421255c0c", "0", "0", .Okay}, + {.Is_Square, "20a765661b1a4ab7961cc82b1e0f89703f149f17abcb014951670537fb2807c15a85d022df8991fefd3cef1b8b48ca6a5aea717b8757a5455ac92fa9247d60ca57ad406be8408f40f77b438b61070a7292cdb64a1252fccc0234b70b6bd20db3a4b8d3c133567e75e5b0d0b09c39066e6330c513d3c177a4bc507b3ed76c4415c1c1e432fca3b4c8cc01b744b4672ca118d418fe258f", "0", "0", .Okay}, + {.Is_Square, "1a8c55bab29817d0bc26364bec2eb671068640d333caa754e7976dd87b76d89800b117e818cbd653d5fbd5089a395dc4f4f661576000f5df3d5c802732c78bf4630f22d3e0d831c11af2f0c4781c55c0f5bb005baf6b9c11b8091196fc6c2f25f7fec5919889d31d56fc5f7742ee720519975ece4bafe9885f157acbafe7d3e688aef6715feade2c10ed4fc149309790faaf9caff93c", "0", "0", .Okay}, + {.Is_Square, "d03233a594aa8cc1d840181625e9377356ccea3f70db0575a307599670ae7ffdcf166aada68f06dcf7015bac70b2f40558abde26de9f48fa6fd1db366c38c86cb290c96aa6c17ea410ce3cb0054367e1c67b588fa915bf5ca79f8e0d665d60e41f02775652b6a2d01a56073beb35e534a98f911c0f4f2d22458883aef8e066745d259b3603219b7949f18fcd792c3d15e699eb647a9c", "0", "0", .Okay}, + {.Is_Square, "83fd2b9d13cdbac767b9297014c8686edde1bff46b6d3c3d34330c8432201a0769d998a51b6856386465ddae9ef513ea16a38882ac27eec84776612c25ce7613efcc428b0176b2b907d205975aa730c44613a67747bf783e226bf047682634735871aa5eeeb5a58cf9da9fbde5398b7ea4a814385950bb953d7f0110abd1d5fd97f7819e3e9974ba5ba9dc1ccfe5ae90eefe50de171", "0", "0", .Okay}, + {.Is_Square, "f1e4033516f827213f8a2a2c4f97945a92a99564a8c5006322d5d7f515c36eeaa31f0bdafafca554ae744ea2cc241331232f585b8fb12402ff0b3f689bd6c20f236bbff2f4217d6b08919208044c127e7c09528b28893ce0cb3a92c8341e469493a930ce02ad3adeea0057a700d14cb1bab5f1e4eb94d82e41e1f0e3ce969c4df861e878cd2aae19e890e7e38bf3f4369d411694c120", "0", "0", .Okay}, + {.Is_Square, "48c19682b5055d1d31485af53eba488f5f171bab98686153d6ac3d05ff37211a4d4eb9db8a9c276b0ed6c4fe05a10ec02184e26f42b3dee597e99cd4219c3248eb923adc554358ec0f1d780e0fe15e9f1e6546a3af7a0ea99c2dc68632baacdcd70830e6709a54645bab7d025685633a25a5a9bd30536dbb5c4c38ac70796040f3971a03e6d1a5bcc7ccd021c36cd29b171056a00fc8", "0", "0", .Okay}, + {.Is_Square, "a5848a470ac64c177f266207803edae7acddca884e1070ed17c0bdebebaa9ce50b5849377e670c4fc9045919dce6e10d48048da1941c3f13c2c8f60c347b067377100fbfbfc4c3041c35193228b874509ad621d51680d6beb41911dac61d1b0c0ac9d32b742ee47fb7b10953b79d7c2e55842c9cc577e99790df4b31b36bb683f6a610582900d25b0dc5a152e9d8318e76beac33461", "0", "0", .Okay}, + {.Is_Square, "ad2d753eaa9bb9679de844bc024164d5005bf47c8f2997dfed4ba3235268e34ba7193334f3c7e5f5fef0dbaaf25d852c13cbc21cc2c14a4b75220d9197bb377007af12e01e82194ff6f09c1427842007f42c40118131599db2b87a7d150d61adbe200c0317105425282eaf9a21b6117b81b66bef12919666dc752f436eae4b046bf583b0dcf2c1a6695ae0c156c44bdc5d394e76fb97", "0", "0", .Okay}, + {.Is_Square, "47681e6e1fb0d7431ba09e259370961874f84fa51727f7b2c7e4eb7e4b7ab84032bc3b3c960bbc5c4fe70fee167a27e8b5c7b272092b546357a98f501c5e9fdf4b648627bc156acb8e5d47a79b71468435c965275a451c0fb04146ea38e21fc8b7ea2e60f9b5d81cec6499040e6ea7b3a37a372497dde6479fb8652b5af1d3c184b1a3077e1bd4f65c7341d92dddf82425cb41f070d6", "0", "0", .Okay}, + {.Is_Square, "8aa402fd487de4359ee438cf0098ce8b41589834ccbe5fd92756a2bef3ec25071b28a17f15587cb3d0696a5673e2b67058594682fb24c3a7c28836f07242ae3a97fb013caa38ccc34c6af59dad9fff97fd548c8e00967e7eb7a2e119a41041b7e804c0e19731b44035008732cca7996df09edf526c687cf23535008aa2b8d4a364079e8f0b24b13bace6f4d1ecf216b0533af80e44f", "0", "0", .Okay}, + {.Is_Square, "e8c49aa76374f32a08b9b96e1acca9c0ce508783ff9c90fe61e252a37b262364b127bf1367aee443b874c2da3ce34bb13a5260f4d3887d23665b1dcab7a95e05d1789cbe3088a2527afd8e8919fed41945f8a4146ce72246ca4cff10078aab4bbec9d40724549a3d2ab6ff81160c9d0615cac9380851b9478cda38f4aa461ba5139192ab6e12ac828e236f80ff371b8abd149e9c72e1", "0", "0", .Okay}, + {.Is_Square, "5c343d96fa37c521a61b65bc455318ff4a536e48dc8e49085fc89c6603934b125368e04ad7d6891bd5c47df716fa14b57cf8b44c31de399f6d07cbb7ff96b1483e251be2764571b724ece4292a125f3a5dc79e7785c33df88c84770ab9a6be97bf4503e1c73b3c9916512f1973415341f50e8ce5262f0fac77fccdb168cf5ff4aaaabd26ee86b8abb47c7339ed585df218ae707640fc", "0", "0", .Okay}, + {.Is_Square, "e97509676bac9145b47d1a4d9d38ca0c8eb039cfcce73c378b09d0242445e07cbdbf63090845675f528a59583b7363176371d66a359dccaca5a61171a277848991bd9e5699ee0c1bdc5b59832bc423f3070057344a441601f21b8b194135945642cd2f01ba24bbde4e43ed8b094c7957eafc28db14a481aeee74d1b60969c1bd038a0385e3cc1736ae2950094ffea0b3d9d8ffd1868e", "0", "0", .Okay}, + {.Is_Square, "9019b34adf90db9c3444420e03d89b37a0475cd2ab3a2b7dc84895f1965275150dcbd1a492a6b95de14dc137c6ee83f652b35f640bbf865f80e9c724705dcee04b14f62f5341da41ae9e698a179217178b4feb5a6cc80ad8ae6be75bd58edee4b58d67d492d9d4a3584dbe24d1281a536e3f83bfc986a2fd3b5e6fef2e8e551b2edf777c3304c2863e22766b561bf0a0636b2d3a4a3e", "0", "0", .Okay}, + {.Is_Square, "ac5135863a0ea24e5a2c1796b05d760eac8ababc50893458d294969c00b7a39fa043ce0327753101a007db83aadbc1f72d942d3ef9959ec81241e7ba1272ea05268597a0d4c37167ef39516bf1a68c3bfd30418f7c162f5babda24aaf7c448b0ce5c93f17131b1f49c2bbeddda1e1de3a0861816bd23b74a57e03c683ec49e60d4e9813b1896c7862e7b34c87dee96f04bcbeeaf4a22", "0", "0", .Okay}, + {.Is_Square, "f1fbfaf87fa8e7711013a3754ef11b286762b52379bd2ccaf43f35abbe9bdf7e652bf7e5b93febdcdc21fba6b1810f5f739cdc4168d8b41c66e4b28d1cdf5df93f75e592ba922fcdac5cbeaa39c3397e5d580ed80d69e887b181e8b2aa8aca6dbe0331d7f308368765cf7a7d7893139c8fb9f2ff89f03a06a06dfbdf9e68002b34f8ab140cd8cf5618d4d424ee6fa09fae750878f97d", "0", "0", .Okay}, + {.Is_Square, "95dc33ef1e7aeabf7fb9633b91351208b8bad4cfc45310173d0619c71494f9252c9a925a9b66105f451bd0d9e9cb334aa224fff386c8701795a445f45d96dc9cd610a9e69b072e8ec0b27d6d6c44f34f79c1488707602509a1d5ec5d5cb53caa18ba48e1260cc5317312713090c212c9a96ffb927c145d7d8386c97b9520d259b54187419d9c894d873128f25d0c9ae906eee37802fe", "0", "0", .Okay}, + {.Is_Square, "4f281bfe58693cda7009c471434cc2eb242e11082524531908025d1099fcc296c1b0e527ea1fce71f278adcaa3e25dee2950a66419a8e5b410fc3f0ce64c618378222a791b0ce91166f4c1fb908a65578a3b045d42a16d9f8bbc02d79c367f430cc43755e084dcd722217cbc45fb708be64ec5755772485e8cb7784ca0e012a32e27e5587d403591cc5386dc7acf6ca36dd1e5aaa1b3", "0", "0", .Okay}, + {.Is_Square, "9b324c170612c394e6d75707ebcb069ee19b44ad0200f4c49ff207a62441cb8b37e25c3d3a2c5cf7c444a1a7c33d2592832252e3de0c234bbfb38c0f92dcd244f9120ffa202a92fb2433c68691e4687fdde83aacff0f4a2c0241bdc1478131e373dc294970c2c52c290a56fe3e7df35718920107be90e14b2e0bf9758a886ff9a4b1efb48ac75280bf3907e70aa2d11119d998a6a465", "0", "0", .Okay}, + {.Is_Square, "95283896b7a2b1d66645542f4a81b67a71522d2f56c5755c4eb9ac4d2d5e3e90d7557d5c359b917bfe0172a6cc2b41101a174385b9c6ddbbfdd929fc0e16b5a2b17f7aa261efd56173088d1fedcf2b5dc85e7b7850eaee8948d171680a8743c562cb49505d824050dc37e81bc0a97fc30e162a4e510916c2cb5916ece97d7b61dfa07d8d9b0702d25664f8054564fb35a4f836f0849b", "0", "0", .Okay}, + {.Is_Square, "4d8522c478457a5d590bf9e455b75adb2ed741c3ae55832b4ca3382113fd8e932de8a45c3782a47ef7c6834de95449789c6cdb1e009c4d2e67ac719a3dfb5ab75e6b18fdf81ac3be2d701d55e80402d1f9ab090ad17410a92c7bb542346f9a2de9ae8dcc76bd6f1d3050036b842845b3adec695c21a7c8634b6013a11b04357cab4db6044103e72751989e73285f9e6db5634ae9a986", "0", "0", .Okay}, + {.Is_Square, "2830a0a18a16324094174917ef9aace9e37747e905ecf724ecb5cf0935f4c586c31578ca0784b6a82469bc41c8d285e629956706d78f501b36ce18cc8951768598d77ee72c3c99975811e4626c65d5451a436099d3a3ad29585c3133df0f430a83fe236b741cd836e819042fc06087064c9e909d792ec992a841956d77e3390cc11fb8ec672d5f5e30e6c33fbe825260303a57b7024", "0", "0", .Okay}, + {.Is_Square, "7ca88d74286e154178750c3271a821285ab8039303eacfc30f61b50921fbf485516388674c99b9f7a6761c64c31828c0ff7d7df67c83b577ceb82d9c6b0f3bd90451fd6c1824b62f6373951ad7228b4b01946b74f8e6a53ea3f325f39da837900b0f6f7167f60951c14f82dd47fe109708348069827f0cb654b3e09d44b95c93a271615c6c345202e1d40cc7567ab751c3a6cd7c86e1", "0", "0", .Okay}, + {.Is_Square, "d847f54550250b06ad725b69d9ffc0e61711cef91e944366c65514a889d6b457e2680c51a1b42f7210737ea7a82bf5707c5f649b7fc3c6af4bd19c134fce3c3782684aae8de9422b476f6bcc8c37894cc37989cd0205f3be56cbec7b1b6b3f705f16eba0baa48e2958f84be693efdc1209e4d796a4df8b7d9950fa12a7e87ca8c2ec9718b723e5ff744408823511dfcebe3b7bd22b14", "0", "0", .Okay}, + {.Is_Square, "8a50c5e9467432abc01942870134c40bf2fc2101b2d64d506e71ad1577c85ed1071d24cd9983f8dc2a5c79c959430012a129bb9742b186e07a3cf69e288005739bb7b748242f457b8ba8d06ffa419b0e3eb5dc29abf268b6a9e792900825431aa4ff6d9f219bebd02a8bacca28dcbc980f65c7a100851694673a0cb5aa041d507406ad97d73fe8b2b53a7c947524f6943c1f3d6be96", "0", "0", .Okay}, + {.Is_Square, "74644fc22ec4153732f68adb3e5ebcb12914cacb590af6b58e23b16836226f07e2faad9957b874cc495d4f53f79db4008829e152a7f9f7e72340dbbd15b8385b5723630134e26457b7a61d9f709e492b0e21b20054ab161e93f97629231acc473db302f2618ca09c32d37d93bb179d1fe364d6f31d3d83b779c07dbb349232d82fb6af7b0a175960e8c4a0750ac003fb7cc75762d230", "0", "0", .Okay}, + {.Is_Square, "fe903cdd63421dd95b5a2c4cb0909c969adb04fda6aa9b6dafbeeb3648c82e82c3a035458419c08c9bbd932dc74ec41383c439e5fbae089f1edb035295104ea22e12107d46e332908dad2212f8c06e56eabef5b0e966e0ac5ed23d9ad109b592c56711f813ef9b15a6d28e2b37f071f06e367a677bdcb8b8b115a4a804e13d8f9907ada2369b382accbf5d65b0a8ae6ba2062166b053", "0", "0", .Okay}, + {.Is_Square, "5da4040704c65d597d5c16b2643c998e1e51cebdee97b82daa2527455cffd1ac0d3facfbeb4e13fdf8495bfd39253477952b13a5742ab689458f404b5555a59f236366adeef163b2ed565c1c0a05ec13bc8d415b7c50fd14145a2fe06ac99408a4bc4a0473a7d6ab7eff55b848c7213e15c7f8cbe1eff1570c90dcbf389bca53fe6a9654852a9b0f3625214d316850b1fedd46960e88", "0", "0", .Okay}, + {.Is_Square, "edbc43a4951116038cfeadbabfba04dd835e1b91aa21935fd68fa75395a4877f296e3f9a47e06443760b496e27681498e15881665de9848ab6365d981d16bb3ec609c00b9a6454813b7b05a426459ca129352769f755f7d596b28dd98bcac5677a5158b6d7db0ce328535a2921ac4ad4f14892f1a4b7a9a815f182e863d8079c5d2aaa9edd952028bedd1ea675b30e53d411f224e306", "0", "0", .Okay}, + {.Is_Square, "fc2f361467eb1edd249e791aa5f8116581ab4071894a3f547e9669df16eef226d47e0686bb15cb141cd7234f820855d96411a0292e6bc15224cc97e8df4970d93fa9234f25b3d167e3b7f7c77a646de7997d953715814d6d89152de4ba6d303daf1ea613f19bb1cefdbd937836c1bb5a1bd661b930c55797410c7c60c682acf396f1774e72d86bfecaca3d4e00caf03c322af9294b1", "0", "0", .Okay}, + {.Is_Square, "744caab8579e67b264434c0468ef79fcf04719115fa2026731c26329b22990eb84c1362bedf8e135371c97b2d293dba90f4e6107372fb29815d12f8050b3d514a26656d062b5cfbb4b1cdb6bf5f1365620fbf103ff6970e313f46e1b16ed949e16dacd75bec2bff407f3f086274cd2ac7ff5d169fd84a729dcf3151b2a1288d58cf5af9d70a0718be209e3c8978a82ae2e26233274b9", "0", "0", .Okay}, + {.Is_Square, "51d4356f4eb8708ae2254a9a3bc17d15648dbc687ae2ba2280a8b5fc2de80eb4e9df377385730d0f4e996885cec8da14d65b177a20669125f3c822e650b98be6da3758a2e1428a7bcad728b54f7907aba2161d8b0e050b7ce7417d18b5b89700805e39a295ad1815b4d64a4d983c181ac08ad2550fe080270a1076ea4219e578c45b89fd2052f46759b613b1000d7c5da3280af793da", "0", "0", .Okay}, + {.Is_Square, "da00f6e7bf2f1b3f5f402b9a7f386ed38e0299179c5ee7b3879d62a9c4388d2a4183d15064552f2809143eb06086e78774df4ede84a9f705df9fecfebaf044f26647fec640c54ff46492a8caaf12ad188025c2bccdbd954ff15204dd4163a14c49ddef2b210ea23377bcc64c9e725168d22a22bc8d5f64e8300f80e43c1f43f533448be183c34568f9b19c001e8979c3963de151d230", "0", "0", .Okay}, + {.Is_Square, "2bbca79d957efba0b9ca8b5e46456b9def72b9bef109619543e671e26308ca65bc58b4ed256ac3cae55e03f831ec6016cc6ddccf95d57c3bbbc55fcf435830034f9d35293678a451fe10e6fad7de4e0c87a63699ac0ccc17dfd72afd5d46a30f11ffa07bd764e35dcb115aba68ca49c385d972536588ed69ecf48c6836375d4de3874fab93cdf19456c9ab7c4bd7e9999507278883ae", "0", "0", .Okay}, + {.Is_Square, "617a2aedec43cb1b66bbe9f1cd50e412531a36dbc5d0885234b183bdba8b94db85e4182cb0f5b2c920c011e00618cc0029c52b64423bd42d1ec0b2e3ab73e5a5f49d44287e35963c45456c2f3bb94ef48d5bb9512f89973c25fddefc168e522d1b6c4532e7256c7f035a6a732d8ffbabeae8b8e88a26425723a4e243ce7889404f2ef9119cb1382d8bab62eaff1b2afb2672c72d951a", "0", "0", .Okay}, + {.Is_Square, "b430c675a8d7f6cec688335c699d12f6595e9684c448017ac885b49430a736f33028eba2996ed067bbf8f682d51c8498fc46616c9316037a2e244af7e1a729cff0c6f9573a33f2ed457efd409eef0df89e7cef252b590a0a86bebc29d0b8f070285194296f126a7b9e202f3bf0bce508f16dc6ba4169e0707531da2ec975d1b8193cf16d32b7a0447ffa47f861f286fb8d75968a57a3", "0", "0", .Okay}, + {.Is_Square, "78804cf1016e25535cf02f597d05273864afb8b2411b1cf03cb5c817873c38fe7e71be8bc71bb1cd2fdb58dc5304e703c3073ac77690529259f6c1ebe7ed859f6036468858e8afa19a9ac093ff8bd073df8099006672093da2d544dffa88f8ab8b46f3e7625a1a5dc542245c9f489d0b383ac0098080a7605ef8f16127e36b3a315058fedaa8367ca10d90f1aa0f746838712b8790d9", "0", "0", .Okay}, + {.Is_Square, "4b43d9e67778c35d06d92abb5caa85a9b224091707dd9b72c0a89c348d56704109e4f26ede0ff2119a85d2f9dc9d096fb86104e21f4fc38658866140b2bffa876afab41f97916aa70ca93e7454b361058ad700cd2d25cb0887db45d59772150b2f18e36ee087e7219d982b327aa2f74cee69788dc8668c4699d40dabe391b3a4d29f83a744c6958efdfa083e802b8d0389d04fc1fa89", "0", "0", .Okay}, + {.Is_Square, "ae715ff449296496e7bb5543dc07f224a69b836d60eacc110873cadb4ef64530dca78d50ac571f0ea5e31c0c6c26c69fccbc0dccf019fb544c8640b8347c0d077ba8c1f61fde7b1bbb76920ce6deea6d4da75458a5021cd81e6d4ada2ab7035748d6916683a42ff33b14a54c0c9647641645079567d0585668393c618470de3bd903ac2db1de5152796c8c120d609a775515224fa281", "0", "0", .Okay}, + {.Is_Square, "e06509059ea3351e199f97c4f78083d8f594cfc098a0a391f53c03bebaf1c9e80ba3d082be56c02527ddb3ed7942e6f53c1eec4253bc67f2ba763aedc007600c960c6d001b5d9f1aebb00fcccf53a912b52a73dada4b87884b0a4cc5d55bbc3fcf8ab83d046cf363b7b248e4eb683f1bba8499ef3fa3a00946f03b4673ea2fcd95776f4ecbc3130e75df4cbcf698879e1cecb9020041", "0", "0", .Okay}, + {.Is_Square, "e200345ff6d1b0873ebda1a453244cdc39d6c7f121f69be49f8324772cd4b76e50a4ec1744e9ef79b26cfa0437d709862210a7af4521e5153e0bc4de28496d10bd2a492cf92a6fa0c9f588a52e738d81694b5737b0807777be191329759febfa507bfa8da747a87551a66036ee4d209a88b845ad78495605f769761e098ce680591ad18715c57f72dfb688fcf6af8b7fa997cffe505d", "0", "0", .Okay}, + {.Is_Square, "225cef3034fb73cd27784fe86ad80872f5879d41e93d670cc77b7b3e1a1cc93273062cf372b7b0afc591da23f18223eb9381b4d2a2953038b386c6776b9e7f307252baa293ba8965e47fce5634be7ee72538a31e673ba3ddb0dd419d88766c77908194fe233b6925672057b5a9e7e3849f7ba35b2bb077c1a14ecbacafa136a9fc9d634872c9998905bd7e0dbcbdda03aab005c2808e", "0", "0", .Okay}, + {.Is_Square, "fd39e16ff1bc8195904695c8134046fb918cb179fb69c3b673f778f72bdecf8d6b7def4b3dee485ab5c9b4ba3a0eed168e6068c9bcd66e8bf1d700f05cfefae1b1dd99016daa84d33a8e7f21fb8a7f3df534f850421556f88705cfe6081f25fea988510b29debfa0850e424d2c61b24e51dbdd075e998b3800d7b7c8618c855195bfda906dc6e13531d9b423c89bcc9b20e2c615d84d", "0", "0", .Okay}, + {.Is_Square, "4515398e3a90aeff02295e75c20917c32be03b80173833545c19924f0c2990e4f9bc73f4a7028757cf69d0037522db8c97d811cda4aa51383241b71cda3b27df4aa60cdaea84b4fbd583fa2ff839f51aeee39ae01f41aac7d2517b3a5c0ac34f36cccc2e5079308ea945e6520cc99818cf19250047c2c7a3aff7d3f794a245c40e48452c352487c59cdab1438ddff41b89b1e7754ed7", "0", "0", .Okay}, + {.Is_Square, "3f7e0d64d8aa0bd222c19f5aed400ee7ef8c28166c76c7bc00c1e0c135b3835eb9d9b446c9dfc3bfd6c8735c8672fe0ce5653edd3ba582bccc8a1e0352aa259354586961c803944f9901cd3da4f12ab2a2261ed32bb9ffb725bce41bba49a2d705485f384830041745005ee6b83d29596ef600fc8411a2a61f0567927976c741f8a15c5459f62da82ab10ce90aebd1fbd101aa661ef8", "0", "0", .Okay}, + {.Is_Square, "98b9f6b17a295cabb6b75dd7a087151f870d24223d5cf2c6d5bc3eafb066dd8536072309b59a6ad4366fd9b8e29753bebc330737f038657fb4e3d87cd44b32a0dff6cbfed99f15bf1329dcf713f5c700863581b6dea30a315c6a1108f699fb6f84e794601f3a221f0e27599b3ce61a5a63ed8188a417befb45889cf0a69db42ca5092acce78c577a0779c3e555caab9dd7b83fbb2983", "0", "0", .Okay}, + {.Is_Square, "fd5f70ba19b7bccee9a5a7fbe77b2d6aaf4c2346d13b65ba7d6d2fbbefacbb2091276e0a10a6702b914a9f7dddc452de83091bc252ddb5aacd832488e677baf2a31577f4458c123dd278f6348bae29a42fcb51ea34bf27a9ed77c29e59e23d5d988e25a57efae60c43ba1689223483ec6cad7ca378dc2cc5bbc0300b23c0048bffb5a2696800125eaa03032e509c873ed2dbb640bdfe", "0", "0", .Okay}, + {.Is_Square, "fa4c2e5ef479d3f347824b36437fa37de283fff7cc71023fcec29a8f575262676007be525ba29bd91fdabaec26ada490183eb43143cff808c0662ed0e789f59044ce04ca52944793f61aba06649c9794382441ce22bd41d48b1cd18811f86fe35b6e9e5badd2508ab8260c0ce78e74dea1ddd2dd5faa3fd646f767a482c5365815022864e725fafd58291e95993c45e336a7c29709be", "0", "0", .Okay}, + {.Is_Square, "708d72f38e2ecd3b5002059880d8ed42b88942be9fcddb4581a20ce3fb8c7b302cbff0fba017a0bd8e42b30389b2407bcd6e755d33d1f0e4dd7e3be4121de5455f1e8babbc01bfa76450c80c7701d19342363b8fb9042dbc1769031ae89428da4d2367f09c0ca1d81e48efa6ea796a697e7e2fc9f04299c7fbd17ea52ea6b4bae882c9edc296c7fa957dbd6ed441b4989f225640bc1b", "0", "0", .Okay}, + {.Is_Square, "acee1a10e79009a8ace296c7ae8342f9f041dbea3b4614d016c1642e380d3751a841f7a234462c1cb5f57ef7e73b4e03da6c3ad3d16ca224500c081d803b4a2eade91ddeb16a8fdfffc031129af8e31bdbf7b134bbbb08e808e9129591f1e7eaab652c1e55ab37287c1ddf4db7e0be1e985c79ba98605b016d455f41a8a3b10ab4edbf89901c4768b675205ca4bb1219be87d628b1b0", "0", "0", .Okay}, + {.Is_Square, "10763eec02bdeca853586ec1288104e6a40b2b1c92cf26ef6e3b5ea92873cda1bf3685b73c418cf71524386c34927503218d829c4a67acd65cd07c20551d19bd86d621ccf763ded072eff0453abd87b0ac4d8a54bfab09a06b2c1a81f9cfd33445e1e1390c3bc2a10a1fec7adbb10d4ba311f0504c75f158ca0c905b8ca9cb2e0dd826fb92ed889bf91a20fc680d8f8ca17d2e021559", "0", "0", .Okay}, + {.Is_Square, "c831eb08f746d74bc9c9fe339ad7d04f619910e00b84d088f5eb4a493226df117f95d6e2f9367f875eaeeef34d8470c12880cfb0a83e08bc158ab34885a4ababbc0df02b1ab03a4d0de7d148d5fca60c681ea24dda446832b69ff1497258a149d1d08a0db58d48d1abeb378db6b20bdfbb2350a8c20f86dd74693740c547362b2adf03775ffbb81a7a151196bd29675f7b45937ceefc", "0", "0", .Okay}, + {.Is_Square, "2e28c06ce693b341399ce652d3138bc954c8362d7a2521a719aab51ec9fd1ee7af3af6c2b6eb34084ad2064f0a604d9bc1b26b35a39840e31589d662a5d4093fa6ce6c546a4862f0edbad1481a48dbb85597317c94b297d12b2220796a21a857f47835d309220237ae3de5fae75740da48af65677ec4aba1fe9250afae33cbcce851a252024f768f371b35cd7e43d6a42a4c460ecc63", "0", "0", .Okay}, + {.Is_Square, "d99ba19034beafcc03f307ca00adc8a8be75964b24bc1777c0b6d6840e975c535da402134477d93e19ff4d702fc1a8d5246dc9682e7c011917bbfa727aae392705ba73f662cea7e404787e9a67e3e79219a12bee26cfe1012aca99610b742b7fdd1c2bb3640c1b3d69c591b4c223353d04b3d54a96dcbf42dfa17ae070df7edf68884daae210699f59fdc0846e92532ad968b9298712", "0", "0", .Okay}, + {.Is_Square, "f6741165d3164a21fac07aeb7c8d008348053b2d63a3bb5aa069a9555f5b4d603b16e6b7f390e9f54a25375b3f2f33924b88651a455db27363c9922e135e3641daa26393f4fc3b56e9303bbc7f49eb505151eed8de845f425b0e32a78fe89e6778652e39587c2f746e578eaa4a17290f68c53a649221857f4f9a6adc57c9007780550eba75d97d9887d00defb0b5a15338dab2d0f93a", "0", "0", .Okay}, + {.Is_Square, "c9300ad56e264b8cc24e0b38909086fd401ad1daa3dae97951f98d4af3686e1503a72461d756a2e7884d36d35816ce62fef0621881cad4c25e97ed967f6e8b3f27e7809d77c7f6d961f1d9dc9caca57bc6e1d82b02082d22a352bde99f0b03c46208131ad6becd8f32203769bdd8dddfe984260bf901caa27db4454b1a9999ed31d0de5a94379b72a71aa82e7956abaa9544eac7d591", "0", "0", .Okay}, + {.Is_Square, "c44c51259adaa23623a51eabbc6df6cb18d3a9f60be3d45c88d087d1a4d6b926157c7f2a8afe4168485f6847bb8eeb56b83354b5b93cef159783e6d8692a7cf986ed91cfd7ff3a1bfef6cf08afccb01ff7d476c2d2f39d8e07acbee44c7bd439555f926a69d09a58dacff2a3ecd31b12ef9644edce46cb308633ff68206000016353d40bff579203e3b82d20c8d5fdef2f08ffaf29d9", "0", "0", .Okay}, + {.Is_Square, "d1eacd12f00bfc4e832f3a820d0c3748020fc72de3581da4c9485e90729285e66fa025c42429cf4676c3e8d1a04ef3625664ac55fc5f38d748ab905b4a6c3ec1abf1803fbc38c91ab8e9199433777b688c59a4faede1f64ce0d89d75b195f29a921daeaf2d952630bc2302d24dbc2d3c99454db213b706738f82c522ead616af07ab157b343e7a8cfb5329af6920fb5c9afd15e91cc8", "0", "0", .Okay}, + {.Is_Square, "c6b250d22299d587dfde8c4c72170e7d15fd8b8bc59e989df03a402587f3c4f5d18010230e5b6682f3b589155f8b66b62c1a8de09e7b319897417bb6e200a307511f62871480550c088cfdd17f66222e605d3e6900e328537d4966ea769238776a8828a15efb62dd632493d48ab32809c9001a4f070fd8ea2216f2ec12b8b453dea717259e2944322518f9f31be9baf9891468da0b48", "0", "0", .Okay}, + {.Is_Square, "7882943eb26e53aec894fc63604b8c3ee0855642dbcb8546ad99cdb7512f06172e8bce7c31efedb6658abaa426b7fee89cc294a70f0c072cfec14bb4faffffb689b80bb7cfa6a71e182cb1b50ecd46449aa5bb97afc73cadb4138631c3897357b8d20a6fbe07d144a2962ba3ba89d8e6da0283c3400d6fe42ab80278c14b5494cd798241dda22238a7b200888be0536b3dd6c3698994", "0", "0", .Okay}, + {.Is_Square, "9ae39f912f82e8f95abf8973dce065e4490eba4933b8c85c9c902e465486538e96f06aec07619e3a883413e4e24703f0760657f8580258cf6fcea8c44b01d76977e319128edb583d4c9972aa9e8e7d426ea2359f9c327cd40b0ebde117bdfa941c65a9feb045730d21fd4846a17679b9e3ec8170f23259c72ce7e46dfbaea369e418b345d133790671b6da6bfa7dc8e9fe8494a13ab4", "0", "0", .Okay}, + {.Is_Square, "1e66d5a0bd776c12b116a731b18bd05f0f02fc8c28f07238f8a8bc00b348a717abdab4c2f36751eef36491ab51315fd0e458581d4249e9d99b8da9bbe8669dfa8512321ffb4ec5c70bcfddb64db4c7167da243369caa778a29470fda8dd7ad0f817399cc9f77829e068162485f95d360adeb10c2ed9b463b7a97367e2ff03714d4a61962c0a65259d853215fbfd96b84ab3d1ea3cb9d", "0", "0", .Okay}, + {.Is_Square, "eddca602c5b5c0e9f9b7b5c751d9b7ce411ed8dccabcb12e085c6dda7ac47cd03276711714f5827d1bd8d5f83e2c2f19af4bfd4bfffeb5a4814066b5e945ba27720362971e423bf2b680a6d394ea04215d4e6ce55e27db81450465910572d6e1712e9f6ced7d794f7b86c42591f49a8ad405fe6211e7e59e9ff34b87ce0db46f06e2abd3e0606fd169f2147b8df478771ac58a7b489c", "0", "0", .Okay}, + {.Is_Square, "35dcd09f053cc4eb3b559668d2775bb57edbc9cf8b9d21b07dc9adaaf058214401433e1c4f5bcaef1901aae78250ab9602559dd36caecbaff7521f686f881ed520e3fda917e586e0e086ac139b72280b452927afbbe2349f9fbc7c2ce649fc3b4cab6a780889d335dc9d17277eb77f26600b68d21288a1c8053f7d671230799fa16cacbe91ed49c684f4e8d96d20140ea41a5b5a74ac", "0", "0", .Okay}, + {.Is_Square, "ac2e3b7b04204a04575f7c8d47e6c50ab5744b63bc17c265ec2d3728e3fea24c1bc60fdb4092b3d4c22cc45b0049d88e02cdee86074ff13cd07a13734ad1d60cb8c75e86dcaa3ef40b10a88fb228b68823431fc7623946c9f6a8e44d0da1751684eb65795e9cba16187ec0b11d75c648d6d6a02c5728300e104712075b4178f735bc8ccadcbf9cbb5565e512b2ec216c41d3fac65a22", "0", "0", .Okay}, + {.Is_Square, "cc0f0a71b79ece1b3a3466296aac99be72ce32f4d3cd4632f6fb53a61dabd079381e840ac496fc016fd63e5086d01acfa1ddbe9178c734ac907f47d800c3188a51ed4dac436fb024f660fa4a470ce54e05eea61fd653684269547ba6b2ecdd7c15863c6c8aeedf45b9f2279751af73966c1df05fef217eaec8b227aea89fc18057a9632b799fdda4e709e8ab2aba199a72049d516268", "0", "0", .Okay}, + {.Is_Square, "210c86503a9ecb22b48c189f90e59e5be20d73a3696e54dbadb08ab07255d276f22ae6fedcc20f6dddbbe7dbbcbcb111ca1fb2d7eb7012f0769987a6dcc54f756c2e54d52fa11a57c1bf7632553470ce7b5466e77ddbda36859c65d5324c58070d74c97d663f9f5022a310d333c28da173805b97a823509f02e8165ccb55262ad100d0369f808a87cdbb10deada55a28c65dacfa9a80", "0", "0", .Okay}, + {.Is_Square, "ec70a1e223a2f798765a4b7a18ad7847ef1cffe8f610d56c6dfb5921b061e5f9139fa22ef8b95e010868827ee3ddeb0ae64ba0df18e293051fd3293da3a2e78a4b83988a4794076eb86b9a9ef7292beb45fcf3737f76c5637138f6a59496372aefeadd37d8da9f2e805c8bc88dc6ff0f7d17c2afe552f1ec1e5ca15c32258f12bc8b238e4084debcd89c7f09a63dd3a2d14b6206bf91", "0", "0", .Okay}, + {.Is_Square, "dcb7e12a2abf233428c4a75b0adc7a3ab7c8a96fe8c524788719262d04b5ce7eff64adc6387b2a55e74a9d923ade48168266d313194496896c2be61be02e15c6e24eded3b3583b4d236298c64b336d73a818d072047c61eb8ea223b2f988abf7e4a3e8ecfb3b95028ace63cdcc549296819756f0a168c33bd3c6a7762a0aeb190e7c409189a9c2a31a9cd3d0b83e5148be10cfb75b7c", "0", "0", .Okay}, + {.Is_Square, "472814c670ff9be2cc3415d8161feee7a20deca763c52404cebb155986500ed375f7411a473c6a11579ab1d57cdb26840a004078ddccb939f650b8705395250b74bd34fe2a0e3677a273758a1b0893b66f059d087d11fb151fc3a325d581e1b863bf063770a24c7aa569e0156d0e168fae344fbf266333cc02c37c5feb8152f5bbf5b0af5d9781662c772d043079d6e36312354d91b6", "0", "0", .Okay}, + {.Is_Square, "f7a58ee6c6771536da75a44f752223a2a99300a73e0755f2b6d01eb6a8718a9682b51cb3ed8e5dd768c203c596594da54b9d19a9098b2d1ccac6d24e99f5d1be775d877a03902856aac8c96ae91e3af5829176268da1da107ba6b479794ebb9a5045a20cfd1cec0eb955b6f51756f52e53cac1bf72c13099356b1a86ed2f3979697d5b08660069154415e362084452ab4fb6f6803068", "0", "0", .Okay}, + {.Is_Square, "787b67144006b54c282d90f158421faebc8ffa0b75d88b8feacbb8612ffbea8fa926bc193713b914774f30a88eeda6f623a2b9d540e25f782eef571f1d1d459206e3227082fdfe50903918b6fc923148db74989e85b4b7f7d69c3fdf7b6a37baf9a988697d666ea1e590248b1e285454b7a1d23ceda3fb949a473b4d1a7dcaeabbdf9a3ab6884de8b3b4f794ab9f3e774f9cb5e05128", "0", "0", .Okay}, + {.Is_Square, "1b9534d0f69542f736a67333628ca3fc4f347ddff9e7ebc168439b443ffa645e63194ff22c98fd5c235c0fdc3c060c759ed6abe965a7182446111490370db6f5faac1dc29753a81da0f16920ba72dfad49818bd176078c3b57af2579659f4b1f6a5ae221ff48ad911e5ac864abb4c2d64a4a65bf5e63e99ec37d0d9ffce5f5208bbbd51765003405fe7aa0e1576039af57c0f4e28440", "0", "0", .Okay}, + {.Is_Square, "8be5168215b53d1d3b8d255ffb96883800933ff244a8a192d700f711a74d22b061b89c121ae16a91f4b7cab3ae8c4a08452cfa184b0a2259cc52d846589da129dbc1c4c1da40743afa41ad952d1468e8430cc2a94301f750a37cce6de4ea40135f61388295b4bd7590d4ee6a0993d53d40f685484672698ab57e327aeb4509b9f8dfb91f43b4dda9612cd49174b6cf900d0d5e5f56c1", "0", "0", .Okay}, + {.Is_Square, "89d5d457bbdde5860ec03d962e9f8d154f1c9c689322bf319c72785529af3581c7aa0d4969ce92e4224499b1bba6d05cd629031a313331468617c394cfd17278f9a6a1e692c3878968c0b6179808e50a8da540d2bf53085d6fc8f63240bc4f5d9b776b13c5c3332ca10a92831f8f2e9f8d8de956ee2eac05a4f74e6aaf08c25f57ed290ddd4475dfda6b9131620eb62b3a681508d8c2", "0", "0", .Okay}, + {.Is_Square, "4c802c8d1efec16539fe96d00b8143e482b0ca9257c82be76eb346f6911ae79472fd9d84f6e3aa0a339624025e9bdca4d7ee6bdacda262727d93782762ba317aebdd48903675633b1d0859487c999b8721a74936d672395bac6709beb3e195ea77f1f31e79654e06a3f31e60e4552fe13e493f174446880d42a60a9e7f4b4ac5ea8777c89043f45f58fc479a9a42940da710896de892", "0", "0", .Okay}, + {.Is_Square, "71051d08296b4c74cb7003871a1c8e7de7811da06349bb844c2c50418794b841b7b66c5b46cef5f00d32a9ffee4685bc219269914666c9233b88336c6e48d2b2c4e6ef5bf1ac4afd460096c7c3e66ac4f51076d0e98c70d0f43c4e22bb34b5b4e53c5e90823b560a94d937fe2321cd09f88a8b59e800ada0334f1bb5b1b4fc13ed73bb6723bd0ce0fe9d078818561650561d2b27c291", "0", "0", .Okay}, + {.Is_Square, "f2b988e44502defcf4868a4a7040c8ccd3065906dd1487d9245dcd4612050a8f10532ab2bc8e1f2189a25e0f851236ce32f58825ce7de8b92029a610ad6aac31d4503c2d4ab9638e216548489bb7a31e4289a1c02d7fa52c61dc327e6bd8e87ff85a34e92401e6981f1a0fd3f9dd0e97cade3049a37c9c6bf6f4164789bbdece00745a8fa7404742ccbc4b87295934f8ac454c2b56df", "0", "0", .Okay}, + {.Is_Square, "c526a267b9e153e8d7a4df53b49394ffa7f7c282392aaa8ac103d03932ca2584d4936b234fcd82f74b6ee5471ca28d468682ceee6af8767ba8a9e0faf4a0b6a133bd1886cbb44e90d46a8e21d017c2a378e9f22391a5a77f2b2671c913bf71bed8cd18b76ad7cfb7c9444e0ed40011215c1b9caa4c430250ed5490bc1e09cea6e6dfd3353773d299275608ac5bb6846ba01b061b280", "0", "0", .Okay}, + {.Is_Square, "4fecff4ec58236f6e6a6e274248518da9dd232094f18d3091912bf21f77da27f5033a0d1793bbe0d8a8f922b1639f9a71d60b4a66230628b2341ebdb310fd5422d5272e77fd4c161f5131922afaf81e270c289dc57fcdccf9b26ab4e93d0f1196d129ad83ae64fcb07b4ad52dd0494251cf951bb6b13204057c36e81ee6e9ef542c5a0009ffffcc04b2bf832c0c1e58bde86cd438d2", "0", "0", .Okay}, + {.Div, "4d48ccb6821cdf7b0f795e89a7de120f1a56b7360144e48ed88ebbafce89f03a9de3d86ff7bf458eb91ef4264d5493a3e0068d4932ba6072136cdab7c05151dd339ceda345899cbb04adf90e5a68a6d8b3a4b37c5e5531dcef6c34e75531ed908a445bb6ec947e8b0a3c70cf0941cc2d235c58ef178b72560752fc68344c26be6fc790704c73c4fcee47874690ec9a94f19accf347b8", "-14cb31dfdb91ba33bd1d8d7ceb258b2ce9a336f848f74da4f81b31d02ff469827b16ff5927dc5e470feb5ab4b5ceadfdd8be2b1ae5f8cf4559128ba5e12697674c7887d77742f3e3368ea97d4796ad64304f6cdeac89a0b95332", "-3b77aa776135372bfd0c38d31644fea17a8947437bb5437db262ed830f31253d5a01825f919e3e7e002e9e362fe81edbace0afb788a1a78f63dd1fcb1", .Okay}, + {.Div, "-6ef982b1c2c2c7a3dd3c6e9ec9d41392bb5a04b7c04dbe3e39867be3d10c7c6506425eb39cb42920a571f539bc6af001a11d5233e203e74cd1c5c4613dc01c24b3e611963d49c30401ced3a2fd53153e7d22db0d65a6414f12df0c9efec82b0200033c7209aafc4f1f1887d5ba57f40711cc21857c95d1c257c3649f2f33595c660b603d72c2e83989a38f3db3c008f714561299a74d", "7e542a6f62cbcb63c1d1a1396fa4dfa9c84ae2cd1e4bb765136fae43157336af5dde486db8007def56fd2036de784537ec1069aea38f0e6f7b9b064b666e838050f23a0751478902f38f73d73963746f22b808ea16311cc04104", "-e0e2b0d4b8a0257a4d3ad076fc7ca233bdc491482f1939bd114862ffffa6f2e424a91c984e5ecb27421381e577828b090daaa6aeb93a7b5dd5d5b192", .Okay}, + {.Div, "f5b9d71b696e7a3b0cf522b6a3be8beb7111812c00a08ba77d2706b52eb72a2d6b894586a68d1e93e549fa688cf22836cde352106095fe543b2ff36daee93a2fef712759f731f2dadd0d86414fa7da699e11ff7209ff1d31516275cb161e44ae8357e2bffdb155e4b71fc21403d4e789498ec74311c61b17b508dc47de13d013c55bacb464291abcf5af480cf5240a2d0882cb574bb6", "-90d827e52657675e67251b54767d2c51f44b73fc524c1982663465225d725c885f81590b08f40b35ba2881c36441de9aa7b01443ad598a0d49d4724b300f2d90040a27e9e4655f0a59785e911848c79257063aa54cba8c31287d", "-1b24caf81985d5deee91ff8af531597feeba2fc07208d4ead824afb2c48ebb383f239bef949b33ca5c9ff1751719406c7159d3f7bab6e3a6f38d2b2d5", .Okay}, + {.Div, "-533a2721c4b12a0f24608682da1763bb889d44a1a6d4e0fc3577cc62307f06d0904ff70b6a7256341acdc8e7099f78ee8546f00d7759b30dd07b491e8b39b3fed1b305da6437d04d6c68dc1148cb49a781af2169dbd0979fbaa88201c7d85f2ac76f26a7861255f59c1a01425b94f2ccc51139f3cc20ecf1b2217458664b654d9308fe9f1bff69f39750f957186a6b21fd850a9fb434", "336314ae47ee6639409b4e182413639dc1f3d476a4cf462769e8735919b580a86eca8b8ad29a03adcda42d0b65d8032869a278ef02be9f11e5b50a1c9db389a8d2425b464f6a2b61621df01be20da97a842d837abab999300590", "-19e9f05b90a8a2863943a0cd6ac46beb3158602f1fbfa558fd6b603e5471d99651ad1c7b321efae63bfc09c9b27a6d786cdc707f437a8c26fdf436b30", .Okay}, + {.Div, "85d7233d42501afc8c51abfbdc360e8196360db1465f48426c54efd646181a70e234fc290a35b6945f916b5ddfa1b217fb4e2484ab48dbd6ca0c52bbd3476c7266a138d9ddf8c23b529d18ff1a2113f86b9087bb521e820733a9be8302af588b12f3752ec11dfa72ffcb185afe64016182fe8a5a203d5ea53600ea703044ffd59287971cc7d35a63fbefa46b58a3ee6b6214b1e5a5dd", "-325b11645b468e6e5a6cd6373d431a281ab18f1fbce94c7e3f10d76daea102f8e3a91ebf6ebd06ca660101aec671216284f9451ad1f1199ce0ebd8f66d77c28286bdefe47b357058961c4729ae172288209b9a14072234d00465", "-2a86bf8ff2f8fbfb9bccf1b48ae913ee142d72bf2eb856d7305690becbd04331de1e5110874bd04c087bae9a26468bed87d40568f66bcc8837558245f", .Okay}, + {.Div, "-c1268192502ea94404c26dede2f7aba4345a33435c1703fbf1549b569b4f91934414853f1c30ee5806c31a2caf592fe3771fddec6139d796fc1a1f49b83e02e911326b630a243516975f2c1295c7dc8b154fbbe751000b1d850047e51806f2315ea3b20c0c68515429f576bb71018c1245f19cecf59e864e98ad8dfddb34acc447ad0bb9bef09efe7ce851e31da3bb5825c9f982567", "-604b77adfc6cb0ff54baf0f894938303a6b871e3d79527b3653762888261eac16091cf38b12ae8efe897cd9d43c3b8fd7103415a767f25853c3992334fafe40d78cbb211ec14b23e030bf5b5df9802bae64123b5c6ae02950b82", "2017daf2ee206bd75650620b230aa0d56be8797ce23ed47819cb97113964ca61dd2b488a5fc53786fb2b57ed4683a87f2f763a1ffe9ffb4aacf377c2", .Okay}, + {.Div, "c18766b4fb019dbc1604178ee483366b12a682240b1b19ac8e95236ef866c48b788c838dabc28547ea15ab4bf8388506b4fce692597dcb83999fd882ce01949a3f925d639ca1b6df9548802634dfbed39371bc33e83b021362d580f618fbc09f1e78f9b356268b1541f0dcfd5828b6d63807342ffbe2fd67ce9d6eb2c9283c92f832e73d7c9afa4d9eb2add075d93c3672b5f3346c17", "852f605f437ee823e1763d3fb1938b3e5beb129c420086b22bd7adbc382be8e71d8b92ddba0441846c2a2932241a291f4bc9c94a9d8d023e16d57ca48b9bb9ce1b855b23f5a27c44b12152a06ead98cd78a6d82d35dc2e719ca2", "173fd3a16f64c202e3512df55fd25b88e0300377d2a83a30025303f0838b0892234cd7ce4551045f91db1f4c726161e28d5ef81ab152b6e5240d31a6d", .Okay}, + {.Div, "-ec44f122de998b05cdfc8424cf294bae022f83f19a0fad6382b8329940749aa70e8ed858032eaa0097e648105e277eb3a1202a85e3cad4539436b06d97695073a8ff819d3c61a79b339ec081d9005c5b262dd1c79f88494e65747c66108f9aadcda679b5627282e5974506aea41de1f11a0870f580d186a91b37d7b820f74cfdc662319a2d5d490272751c08361eca725f4d27670f9", "6c00479b57e1db7b3d6e7f7ee06370a5d8e5ad85fb7b30ac642e11430b4baa5b4ed6e325cc3342f565d2e6a25f12db6361c25a82c5e2e457cab98610b7d73d9d11dfc74a8069028f925bdc288848f89db667bd9469f8510f3f60", "-2300a43852dfdf55db51bb3c2e3c18fd5b14146217505bdd5b8fc216f83fac34d10667f9ebdc36f74e80c054c563d55f974a00401411db6410d6b19e", .Okay}, + {.Div, "-b7568d6a2c675b1d9733ab12ebe25a40254a8177ab4233fd5cd2b73896d19a91ab9e869055f0a300bda295157912f9764d8f1b7aaae8ce7ff3a34d7f5d800ef758f8afcf416dfc794ead63d40e1b4b5a307077484ce135ff1d9156cba779fe41971ecbdefcc6b15998ac47cbd2f7b569918f4fe1a7eca428862efd4adc17ff1bf7c8962ef5df727103f225f981979216e20356ffa820", "8b7b5fe5795935851c736ad3b53e7285b512efdb590a22011fc090b10d8731d4ff56971dd0b6a3816b0e80e9a7223344337f5d0db75dcf9d5d4a50966c360e236a12417139cfe5964b6cb8f3896f0294ad3a601e9599c219d468", "-1507df2d5e32f8b7629125508201f160d8fe745295373e21db655f27fbd4111200408f79a410ac0c3c4770c8c3982745fd1c1a3889152b3cdeaad02bc", .Okay}, + {.Div, "76c08c2fa414981123a83eb0486746ccbe3795ee83a5fbef2f8dadc4b7d6f1b78a06ec5c0026a6d31d1cf15400d01a106e2a5e88179727ab7078f01d4e3f23bf145e53594784545df35be9b3574b09aedb1e157b05db6c641b2fcf641649e52b230757400419826c0b8020566ef8b872071ce9cf73ce45d08189a86daa5b65830a706aeaa3e68c72f2bce14070aa2fac17b1b5cc3ab6", "-e1f830ed29d133cc3ccf6b8f8846da064900060e8222a7057718dbd3c46c2e94de462026b32f11e3389501150522a6c34d9d24755cb37efad17c318063139411e7c3a78f44038e0f8500d9ea9eb1ca286948b4a22c055996912e", "-8688aac160f8961191b89842352b4d751a006ab45cfab1bee31002b2e1d8f8b34df912a6b238dd69c7430b68e4d704cc733f3e7470a058205e193ce9", .Okay}, + {.Div, "a6ff6fb92b4c24a2cc88b8494b0f045b169cec653b93d03127554b6d338fd4af5f276ca6c344cb30d020591a5cde4bef8d9b5fc13987e0d908f5b66cc7441d3f80d519aa7d0e6233be06c4bb3c3c39537775108134be3d585bded1c88c2977281b70f419e2546cfd5ea78bb50c45edb76e14b3d06eac9ba8beb130121e4eb0cdf55b57165ea15b8f507e2bcf061b0e7e96ebc4264bb2", "-b6d57aea20562fe33d149e004dfdb0d06c1b5edd6092b495197ac9d0e2f9e293d82fd3f7c27ad7e954e961d94c8b923a4f35e8353153e8dae3ee74bb117500afaf9562b672ae5ca474ff2013d523c31bb8b181250b5729194393", "-e9d39e139e7c26624684b28954e698dbeb381189065ed7d3737bd90137f9f209be22e26b8de79789691ed270a1c42d69adf7076658ba3ec60aea078c", .Okay}, + {.Div, "-1698be2103f85fbf89a1e09d4564ad1b895ad1012a40f9c2839609f1eef486f673c4b2a28c43c03a049abdc534291ddf4cb424dcaebb76888440d3e6460aba17d5e5c1fdb1c100d291146f1028e63a9c7b94d294df1ccb83515c6223104834948d757eff3189c9190af53abc1a138b3acbabc6c6852db8b7b1afe54d3bcaf214f24deb8d3da8a57f4741952a75861ef919eab2915583", "-8e7f29d7b575ba298eca68dde03dd4530b782b8386b0e2d415b562f1a31a7705e039d21cff01b6e942bdea83d608efd35ecd2818f22a5872a3249767285b2b82982e70c3df1a4ed65d21ade31d5e6a650ceee80d6321c0986118", "28987a526629fbc9213daa1a4eb2afc0e1784736a07f4d5a8de0a18159fe886a9231cdbd87bf3ddd875fb65949f3676881ba691d9fd6ea8c40a124db", .Okay}, + {.Div, "f5ab538c07a146e55c4950f28372cf49f0a20bec0ccce6cba8c13a7fc2a8802e8ffbfa8939516e9d0391e7aa0fbb568c4e6b7d03210a96b173ffec9b015b694594676416cd80c619c0597cf7857a3e004e2707ac95e642cc4a1d9e759747113a4a315bc1ddb7012df3203385eeff0c8460707d0441193fef59678f8565bce924406626963d6fd593a995dd1864db3e0b1899193850ab", "-1960565825779e573216179534f4fc8b99608dd70ca99e7daf3cec21cd7f0a90ddaa3542d930d8b3902f9fcded652993d91ccb4ab6d6a41280d8d008eef5fc4ddd5b4de5ae5c3a68a7738b6b5ca65e9209a86d48d211b088c8c2", "-9ae58e4723101566602fefb319825e83962ea19ddd23f6d8a8d26ae48d3502a994a5e50e37a50965ba4184a4ddc98a908e65b4dd1ae2aa052820d90d8", .Okay}, + {.Div, "-b367cbcb2c0317980b940db13594d80f6e59e96b749265ff437ed03a16fe78738c8d7264aea597465ae0e23890c5fffb4e3a5bb0f93af05820bb24efce5df1ff87261051481c8ff43331fe35388e2c9ea91fe302fd2eadc54ffdab7ea40a08aeb88d18648c2ccbf6491545d5a8c65ac61942b08cae23d99f461629dd0d0903b825349e5ad99c014d0f7e55a53ab29331d70602df8ea5", "636d1d97e126b483ac45bea04af0eb9a5a106880d0fd5df680b1ef084379b53ca54e564eae50d7565d01f7ad235483e381d78705eeb6db60302e2cb9db5583b69f1651eee2c3abc103f9d802254240916f8ec055ed1df2e2d258", "-1cdeda89c339bcc80f5c464424d165997d9895a8ff13e3216517f37f58f81823f793fa2b289a4dc4f37af4f1f5aa1d7f8a46fccd0ad50e0fce10b173d", .Okay}, + {.Div, "-67c1fad32913822f84edd18ea3e80806cb86a16abbaaa43c25c9e696aafb5629c3087ae410c9286f72947b022b002460ea9ac721d27ecbd42917171c0130ce82510dd6a200653043bd6df3265ecacdb96688718d39e258c3e23194545e95611a55dbbcf95263772703c9b825f5e30972f036afde45bed9b852ea1215e8ea2733b0c9ea3e0734d100c8b780fff1117d10df553de9ff36", "dd45bd3d38992da050430eec329170fe2e3c79e0b6e0668a6ce8849768e88e70cbf91f72d4b574c8150a00a580df65cf4d4820d4b47417373a6f92983b4139fe035c55cc7b4a9ec84aa6ffac88589358d07c51481be933acc448", "-780abf5a49676f1d95bd3f93b918948be850df5c29d25963310b1394f09ae56e8f3794b433927feeb283937f14be8d179174791e0dbbc026fe9a085d", .Okay}, + {.Div, "1e72a3c2ac1c622a57069bc46728effbd6fbcb2bc477242375a040044cf5ec506af4ed67f1c77e51dbe6e9071533a3d8893078541f52b586938668a478c4df9652b1fadce33026d25b00ddc12c2a3af5d4ec2ca6765f73dd032e74dc2539a88b16f0ea295af091d4bcb960bdd90af79e2119260d8b5d20d3dde32949fd29ab4ef636ce83ba16772236dbf47f32aada26692cf07be99a", "-7cbb934ee92ff0400cadf2362fc926c5c3ea010ced738903402d2312d02e8a3a0a461e8db38d456bc2e2b9c13b3c34c1803bac8fd36feba1989c5aaeb1427c8efc687ee7b6a381c9bd52ab716a45f8b39ab073f930636f376ecd", "-3e7da119fecac10572044791eae9983a2bf06954bf4aef5d9f8e1e5e16899f76acc1d5d59a542e6131404f4db833ceb68c9c649935098d1e506372b9", .Okay}, + {.Div, "5bb9e83e28d37233e90580a6899c976c812ee3f911aef6418ce0d5688414968bc572707fef73a37cabc359a663bd1b96f7dfdbb2d7e5325172a704ff887daae59bc4e6d269f427014b2bdcefe13e24e462c6c49f6f81513213c5b53ed46f96527bc5057116925bab99ec83853061b3ff23dc05b213d030965c9a7c98074186abca0deb6d608920190ed6b0e0a1bdfb2c195709c1b2e2", "-a1c475dd302ea2a8d2debf72fa818e4d878d8779220d71e6514d8e66c6afef486226482084cffae6b38f256a8eff10cf1f18f22d21a3723676307e66abcfdb1df68978caff15bda4af832d1e405e45c737851c9ceae2174235b3", "-91288fac0ce19670f43d78f0baee2c13c873c1c97315b9c4710f902ee4cf13685c671f0d37a925abd33d18632816b05b6ae35c38a92ebe87d3f90659", .Okay}, + {.Div, "-6939593c976762e93a78b960debc6483b53cac13097a998d3d167e1af9176d213f5048335aeb50df5e0f4df9109780f18ec1fe0748dfee7e8386bca1b8eaa22848dfcf6d6cfe70d30c0bde07d0ae94c2005d9d35f0d058f5935e81fa016dca54225c7f95339e076383024ad1b29c35df21d2e824a980c63d04dd68d497c4f28669c87bd78ff899c5782daf639247ee6a2f0572b2f02", "-db9ffc5079249bcdcac3d0987f0fe9d97dc05461e906fb6b6f1713d940eb785507972d72cdfd9f2d8e569d16ef97c16255748ec8408b72654387d5837f45814c7ba16ab08924450afd8c6ca1d7cc77d441aa2d0e4a8aa4a9c15f", "7aa6ce9c11715c1de16001c46d0bf72d72189df594ecb8ab30eecad652af443f55aa1a39085bfcf55c5fe32c4d75f9136315736212784f51bc8c748", .Okay}, + {.Div, "e19513aae2677b9f56f649f3c42bdfc6ef927a43e42fbc2c290def6f5b01b6908c2676b5f1dcc69c5e5c9f32f7f854467fe207eea3550a0b023cc126539e3041f936863faf5721e9c48790b5a58f4c5d2b63edcf75df8133b8d6b09669461b30e3eaca2d817583bf472089f0418c7b4b4073299cb834af1cab3d8628968086c57ffdbb8322e9bd41bd2b0278dd0b41c676eb3c3d0c96", "-cd3e5adcf6f8fd981839056d41fe323680390a4016dec11f4165d2d6a865ee516a61061fccc8e5091f375e3c7c38867f4a55b23ce85cb93103b5a47e3a1aeef605228fb3f27ba91eed83478fdca52576bf4a7fd3b0e3c9466988", "-1195e561b7a54c4d3b240aa10d27aa4608d6603cfbc645cd89262cb54a0509c5e1763a622332691517d0ae10ccf84ac08fcce1c0afaff8deb8bac88b6", .Okay}, + {.Div, "-add630ac1cd48e62472e8258e0238fe2eb49e2106bdf8d0ff82dc006b272ea8ad865e8a7437d8b87148e19ad760d08c7ca92d6841bf87fcbb1e1bee14818a08622a4f227d234053a636cc0d362469835ee46f1da715d17ce948fea31d99eabd4106d072b46398b840b7e9f2dae9cabc061bfa307f911f71df5c2d55e04127ed787d97d9ff2498df928cc3103ccf6dedce86050c3b185", "c9101414f4681599c7f9e456ac5c688057a25313d3ec7417b3942296d3b1092901e801ae4c3508771cdb562444439016744ca420cf7964addd0c26ec89da2edd6d8d90ea1233c446d6104b02dfa790c1972edf5941a31535b98", "-dd55b385d53fc6484c10e16e21aa77bcfae909d654e676945c58d0f78c3d5143d49814737fd1d8f599bed195d88d8461948b31f676af34f4ad3ff9d13", .Okay}, + {.Div, "a02b6d7aae794bea33cd5dbe7d035da8bfc4aa7b5e1e406266d28427b3c4dd6b8246408cfa67a7c5a841f88b79b1c64a2eacb4e7d1d042f58f14a77f2962c71342c7c5f1f456404f55833d7cce2fc7e65b6b602194caa1f81d9035eea2acb29f0fada3eceb3754847effdb2ba75121575207caca4f50513fbd2f53761578b75e2225464af804f28c264ade5bf011af719a6a6a484759", "-b252e5efd963faae89e9158e1fccc3f9ac9409763acd5d6a01f6cc70771ac5044f7d8b9a1c6c2ed3fb3550959dcac5f5942a12d56e354438095c502afba102d4aa8bd4df5b9b7d68897eda43b9b34aae258ca6bddff661a33654", "-e5f022905a6b446e9c56a1e158cc559659f918a5c538810748f8513a89a514f347a178a31004fb1e6490995be35f2a067ef9447db0c2a878d611ce52", .Okay}, + {.Div, "5c51f0bf327d7e025a530419bb64c6a5b12b98ee35b77b236a4582ec78f639ee7a5ed4d540cba49d3cc738ab3d949a2fb253611f26dd363fcd4b18d0322f02da15145fb1e3085623f7d4633cfe62ed3d7b0e46ea78e3c271a655d9c1e7a7a6e928b27913bbea9e2e510feccc0314268f5bee5a5ed48e8803073a2751f176e26bed786e6bacd370696783add271fa22edd27b46d49962", "-77326b4cc071e49715e934111d0cf200ae84485fa3bedc5fadd6eee9ee5cee92b3de7189d8a60dc67dab20d5be53db46c31c0f46cd7275762b0b371510767b79acd02407e8e200f7fb2fc0d03e201093ec1435deb3608f4f0af1", "-c646c13b06c14ef662b7abce73e11abc54c6d8037681200c51a26e7762339714eef2091d04b9bc8eae0737a7ca894282784b3d24ec509a4a244b5c91", .Okay}, + {.Div, "-cb471c2074bcdd5edd15262b46c45915096e3a035050a6477234ce9ac5d98bd8a38b884e52676dd68e59578fb394f3686a3c7448d2077c720dba20aba346535d2739502597958fa7d843ff68f54e2d52a1c19cef315498cd4ef0d28e7cc27495d02d8e29724f29fa93293d55a3c43c488e45bbb16595c27a83eb1a612614db23ec91ea8140a70a9f814102c67e9dfb32ed52191f3f65", "-7eca34393814976b4b4b66a728aae0d1b5989835bef91aab34b61e8abeea11e51f76987209ca1c50f2d007b183fbdfd2a99fed543419e3178d32c35a92726df5c3ebbd9f063c9b0c767ab3f08906aea11ea8a44d5aabffce1821", "19a6f970df05a0df07c9549c6f5c5878ebc18a816e0db504c525c1df1febd915755186c89215d0667d6a37f852c3efe27ca8bead8c167a5678aeb909a", .Okay}, + {.Div, "7b40a8b3b293dccd311188abb7d3097a00b394fdb7e515baf893e199a38e4d53a30dfc0fa746f6fc5a499f076c47dbda6ae075018945b001be5e36e79bf56d960c01c171f7b689ca4f68031ba385cb5c181b470ebd569ffdde13871b247384731d0fdfc15e7dcb183cea0a0ec0edafa258fe0374e6c0bae9f1587984d492d40b73c774cca55c0e3f63172c6f63eb885f0f4117af6199", "1bd6f0b6c23878b23940c4ea17aa05cf91e8a57096993ab5b9532c0837e0c44b818ab49b4b3d6461553cbe658c642e8011c6a33dbf51869e6f7e2f801288acada5643f44cf3442abfafee7cf19a204c6fc6c2b0ba2222b45c9", "46d5f73c9fae4970a4b17107311f0034652d35d09a7a978a2758eb46f296e599fcd85ddc96dd3a94481497b7228d4d0dbb39a59cce68c9f2b96f158c561", .Okay}, + {.Div, "-cf4c50a5c346fb366f256b67713fd7309d11cf4b5288f38815839c611ba85c831ae32c04c8965acb45f04052d0c40955c001cda27112ce00d03de774364f1b2a6d4cbe9cfb30b0cd55ed148bd2f90ad03039a301a7fedeccee83a22e29e4c723743d6bfacd1218e69fbb9732d2be6d9a844bbefa6487bc8f971913c0998ddf32ffed90063045a598b2d36f10339cd86c1ea87da42a5a", "94daaad6f7c64091d2b0e9cf8e75d31fc8925dc3b2b95fa337847df16b62f6b0ba38c617eb64ec392c1f08958fa93c6d0db2d5c983fbb31ef28a5cce581b13c85a6ba1b7b5ffad11b7b0d7da1e8d8c6810833f29716adcc60bc7", "-164831a1a20f0bc859cf81ef8ad1e6b59865dc10fb98e638b86709fb03d78f5fcd118f268d61842ea3da78f25a04cc1f34dca62df4459f2ffa5f0fe10", .Okay}, + {.Div, "80099afd5281f655b527b589c9ac971c9ab3536dd303b1e0bb6fbac62762f059aee4c05fde981eaca5e008cbc465421fa55c1eccef577a2a4e6021b77caba4056708aebe6c64444f3375122c88542916eeda23db1b6742e69815c8285b0b4d746a10f38f41cd034cb175e7adfac77161990d9dce4e8f42350504a09b3067923b8924dc5847861ba8d07c345f8d3a375c6290cf1f42b4", "ce0d88a579d53bab1fb7d22e60d46b1f0fb098ca84ead2ba87b15a6466b6ba1f07973e96abc76d5618361ea6a829b1fb630fd181bf41c0fe492d27abf79439b8315de2ae2776cc143a1e948aae6014eb78dd25f5990b9f52d0ee", "9f12e2533a9e694fa4d0531c09a594a1b854242733df0a1c620035328af391ef2d56048d247fca31127af20f07517e5c5d03f3c5678eb3c43120eb71", .Okay}, + {.Div, "66edc75888c27877e4ce8033372f15ce3132192c58883f694564429bd2ec48013c5330296dbc7081a0574d8a8dda1731ba91c2a0d43e5225731621d674134a846b9e299cc7187473f4783091dca849546489efa9de84612af0b313dbe46d702f44eeabaff390aeb9da6717fa5ccd6573be7c7db31a4e29d18586a22c47859d5de59344c5587a47f60bac61a31a8194cd274c0af55e53", "f49d3a03d03f66820e1eac19667cdf38ae68ae2a7083f03538a7727c9c03c774bda6323b3200280d937ef1e19842f297b65f47dfb178c54899c3dd816d6d9c78363fa65066d5be71863898c305b60f0acc37df15f0ac90a038ad", "6bb8420704f0fc2b89037e11c57a5ebd04a1631cb4378272dce5ba46dea35a099e759ebbe94edf2ec27ed6408c9fc97efa2eb2bcb06895d6ae0a1d32", .Okay}, + {.Div, "-62b810910feea390516aaefb3e1bef4ae0f5b849027bab92cbfe3d9740eaa4047411d3fd4266a6d5c47220d7962479eb234780e9fe3f30e81415ddc7ad930e237578a30faa9f365386c4b41902fd17d0a3a6eb69db99ee7ff51547b3b62a8196ceb9f0d885b425ce3f74e99297c5461e26d9167832ba90097e9b7d07ecea035c1917d2dd5bf890ce623a76614a17bf2c8e713c4762e7", "-e20bb46ae9528d23d2fc1aa8f7d3fb22e8629adf8faa8d8ef2be66b7e02ff2004a155ca5e42fbeb859dd4c5b88ca4f39149aee753eaa0093809095af8ef88333b0d1e4d876fdb69b8a33a6dd5ab0a1c8f5f978ffa0e6fc560d86", "6fccf92a86f4da045c8ad31044c890e9c811dc8bbe2d4b3f99893f49d931a7ebdc65d0cae9b854ef5f84082c03bdc2a462459add24a232e51626bdea", .Okay}, + {.Div, "de1b022ac6b4148405a73ef9c2b8d43866cccc05e71a36367488ff394d10d703b1fcad263e29d23f2184d664215e1cb8204f92d4c0c514175d35c19ad4a6f69ad6bcdf55f6eb41a44750eca2bf10f11f18381f1e531738b157cc86f065850c2a7ea3d4d29c285d84937ff61efe8c058bcdb6120c7f067ce8106bb1e5f3df6f83730997f665e32e9b92cd13a88c1011df7767daecb085", "-d6002112010dd02a76d60d8d3d9a06f72a91dc07a33d61dede0ebbd109f7fc0b75f633ca34df99e808261c2845ade33ac43d3089e0acd8c0d98c8b41f02ac40a5b706450c00d6eb802cde3db9459f49ef8bc5ca8308735190e4b", "-109b217bd2b191d469fb22ff867ac1908e8d76691e1658a3da2d895d3e66ea86658d440632feda4348e2277b17cbedbc2062c753584907e1de7af7779", .Okay}, + {.Div, "f00ebe6063b862c919f07486899510eece1c38f4a1356eb8084b45adc4850f3d4c2a81cabd71adbbad2dfaa6b71da926c342d24238d6b72ab78cb82afd9273beb6166323090455697ae6fbf40a680c21fb792654e81f044d2acfc33557a5e53a35537cf910cd072996438f26d916bf357cc69eee1f114a5bc0293496d37111a11239f13f2a439a70cb470a4cc1d7466d5f0ae76c19db", "-cbf0c89eba3b19549f79757118ebe8fd3ba8c9e7ac23011e1239292f1ca839d18160a96d6868918c0793fdca540e09f617f74039d3e4e150552b9d2c13cbe44eb3f3070d5ada87c2efad3b51b9ba3aa63866ec6e663c460942a6", "-12d5627ab92e80169f7601a8310ef0c7a4e60fa7d5131663a4dba07f9f614cd4649d92f67bbfc8e75fa3c097025a4c3b44f8ab6ed7abb13d2a70a4405", .Okay}, + {.Div, "-77ee60885ed71d86680ff69248701dbcde5935c0e30b072b9294d42a5b53c0a09c78c300d57b664c35ae26124f1bcd36f196d9632cc4d151233d695f08b47831116035d9df8188b00b2d2bd8f01985fe85a24d04eda3056a38b16e610419a7bf8823c1415edfb9fd743f8eb2feeafd50f493407eb3e3c729e98c93aad799d9bddb10281bd51351726f883840394d980364b8e53569e", "-aea88f60acb860747629f18ae2135c17e1de65b53c5609dd6d98e83d78c90bdf25bb293618143d852789551ba5faa0459b4135fa636c917d0115b1bf64a8d00d95af0ba94850e4a5bcdb08ffeda3dbbf23e899e81f6eb0a4fbf4", "afc9061e6d908f081b68e38382581e027a4c62765df994d1d88d592e1e0e4217dd72a35a3de0875fbaddfea5a5bae0f6dc4aa3351f7caef7d66a446", .Okay}, + {.Div, "-926cb26ee53c4c6db3cd55aa4d3ce80f07b5ffa11680009238706c7348a1fec4cf1f779fdeddb7f5302ef2c9c61e3dd452c32a1fff8dd460bd351b1fb5601f8ce3d5bf07688fa879a99d65913db3cab84f6326b12c8ab4b5cc3333bf8937d7f36e380c65f2286f35ff6a4d6430f6360c9bbd6e24e10345b17285c1efac64b88cc3d43314df5b59d58cb520ebab37adf92f4f8a99b463", "-67a1a1a4df2c555beeb01b575420bb8e18941022b6bfc8053864ef3bdafecdcae7861546e3c62899b0e980071d6e0ef2bb8c17604a34ded49e5e01f5798f0b227b1c56acb7eec971a5a715b6f306b58f37f677677b3e510ebf2e", "169b63cb84844c3fc5bdf8e30fcf9050f11e3396e82b44f899f4089319f0db4b0cdeed4f8b6460ff2d1239cda29cbf0e5c5d208900b61ec7e126d6402", .Okay}, + {.Div, "-2f6f6cdf85e42ddc5dd088f470bbf83a6b457c0fe6783f491c85d962f7566b8888a257c2b426535a5480bb1cf0704895833d4104034e26820e2d5d2966edb3a7e9b133c6e4c5a9c23ef474b78d3dfcd18f5c090636fe8556db4bb659cb213ad26a8e47aedbcd8ebc6189bf301e5cd79288a96be070b16bc46f6502bda78f628db6805873b6d0eedfec2ea6f1e4c1a01d1fed46ee9027", "2ad43403cc3e9817fcacd04b302d4def9e9730bc882bdb91a253acc5f8cbeab02ce02cc752e29ba6b9564e414afe3ca749926bc056d7827079f64947d4fa21a25b3719b04a490c6b917f5a032f525b346678ea6f554a47f3c7ad", "-11b88875269b7f831a75a93ab7dca9734345686e474b6b49b2cf8f467da728e613798d18a8a8ad813cfa8aab91cf0f2664daa36c7e35e910c24de483d", .Okay}, + {.Div, "-9be180024c002e8c636c80abb4a9d96207166f9b6be32b9911e16d26643985f29fb45f7cc286fde2949c6da90178d6d199d6867d56f73014ce84398b7c1506c1ba08601fa1a158b2955a1027305d4dfb30480602af68e6dd4d187f34797fe1957d4373787e74b1885f180dc05954bdb895bcafb73bc1b9e8024836272bf9668872c279d39e5e227c6cdc7c0eb8078b38238301633ff2", "-305a8cf3fc4d9b6a0109d24c1b063e7f1c587f1cade35a1eae71d09fb4253438919ff9093bef0664dacd619543a651fab6c476b60bc34509aa26f6ca3aa54824a4b3d7dd57acea8928df189546fbfde86db70f42d59eb93f3bdd", "33948760df214a8bb6c66fe30baf011c1d43ddb75144895098a146b5c53005adc7b2df38ef9aee8835fcd01a944578df6ca9802f98d7999a777736fb2", .Okay}, + {.Div, "1e5d585c229c387278471669df6eb5e2536d4d48fec10b6ffc893be1ce0864124dc729c2d628d54d6eba15ffeee6f17375a02cca2d585ee2db70f4907674befa54ffd31013c004136b4e7358bb749e856365c78191bc07b614845fcb99c25d1622d5808bbf29b6b80024136f4004c648cc40dfb973c8896b08d8f0829e8583028e2499d8c46600bfdc2497da728189f88ccac2a69d9d", "-e1dd3ceb457b0e469570ddd477c18b440b02d9058c2da05d0fcaa169bbd4d0db276c992f093ba3b30526775bc0fc8a0a30736f88ba82c81e7cfde8242cd8f20a680958cdda63ca16d2e86acd8ea40c95e876d210ff71419185d7", "-226a7fb1d83b9ec2f39dada1e7c8e0bdc3134f9d6339ed7c8a28b1e66ba06638853712f27286bd797c52cb8b02aee166fdbab2d4ebd04e87790f298e", .Okay}, + {.Div, "-1991dd006370f6c988249de600fa48632052e5936e6692e761ed53e04c4408ae7d1b2236fda9998ff835044227bc5f29849e299347c3301730e89cddb2587e791d299d81757d429d3a83687e153d0dcaf881e4854cdea23805a64f0d864f34da47625eb8bf7f6a908f32668a41a5a8f6650926c09538de5c786d4c082fc8be67fc019a617800cb1f121ab65c735c826df2adcb94224", "-abce4d2f87106d883904c58565f3003351ffb9e1917df2aaf79bc1069530e563d450dc3a450876f33b0cd022cfa7647997fa590ebd70d60974b441145e7029918a691148d90810211f17bdc0b511c56e02a724dafa1e4e72d7e8", "2619b06b3acba11c88cddab7a3003a1f72aa3507a9fe80f89d9be9a0fcc06f0ff3a6171e6fb3b153798011e16816f72ae6a87e9ba552ebea8760429", .Okay}, + {.Div, "-fa0e4c39e732940d5d3749904df475400aec30a4ccec5673d9f453f3fbcddcb00a636fda918bf362e99aecefeedd22ad8d4bcc05ac056b4c0889ced31e6155c38710607954bd899372d224d6ae4a354e2df434683adae59ee53abbe3c9d7850c7f3d0197bb57b57d3bb6da906c4970203084792f04f03fe4f24a3bfddda9cdf2ecd12235b2105a687e8b59248b7337d50e3533c21d5b", "-f11a48b945205d02b07f10f90732486fd769b026985067dd3dc5d3199857759eb8e2dd5028b753c8998fad45d4b087d7fcc61ce2a8fb7ecd99e02cb5a1ba27e08a09c848e3915c049e0e04955244ff8ca129988418461aa9fbbf", "10981a222debb75b2a5dcdfc4a07718241aa64a1e52bd249c96d8458c07f1ce9cdae1e9bf7c2a2541c1813ada59e8adab49ca787ec082f676bb239807", .Okay}, + {.Div, "-773c719b469db24efff95011cf4cd0b2db12aae9306aa07bf47c2897a19085ce82e2d394d7723baeba986bb9fcabbf9b3e5d9199ff13b60a26c50dc2f5a1b705ee8376c5bdca7cc425c0098bda2f21f0252b89bf32aee14c5f655febf9e5353ffd967c5db8c3abd6760613626cad2fbcb342ce1854662b48fddfe071a9c837f58f8e5e0abc7a85e81815eb0f9900fc6e81fa5975cfc2", "-29138ff3a4ab2e6dab3558ec6ebf25ecd42594f1750eef53c3b548d545475ebdf3cdfb50efa280a9e0250e73fe4681974af45ac283c64266d69f47211b57e2cd16f866d933cc9c7f2ed736915e8470a88134b2587d50007cbe3f", "2e71d1664a8c28010822fa7e74cce963b276a442ba368d18b7f725abe380e26516f20e868879f0a925c062fe8b573cd6f1267df69f0040d49efeb40c2", .Okay}, + {.Div, "-c75ed43a73ad36e440ebc8ed58ed8ee926a0b1ab07b7e4fe345e12b9f3b152ca32fdc272b3fe506e9a0bc199bde6fef9d1a2cbc129fb89963c5c1b1f4982e83271dc18d8a3d0aa53f26bdb2e9365bd13c1f31e51c45face871103a90bb433690eb69bc6316f944c6f2d7acbd0ddccf0bf65bdfbbc8698bedbea8d04e88c6d9238975d31604c9ffd82485a0c8f01ef9b032fac15cb3c9", "-39c1fb68f46b80628220a976a89a48f74cf8d7e5effafb4cb83d359b3d61bc24626e129753007fe795645f783d616461b58b668cda8fd450693670da3c05be8047c1b70bc8e69b5af8c4aa36378431ee64d1014d3b75df507337", "373abb7e1558cbd63b97651bb37c652d66d0ac9389eee34a2523864c8052a6554e2f18d8618ef40c462ec859452a11360c1595016fc3796f2f7c248ce", .Okay}, + {.Div, "7fc714867e3d1ced42c76062c5a9b59e7e8de04db275df70099b22215c342c80326b75603f39561a82d095750066cd73737eea77a49dd56164a4a09672a383bb6b812199f99d1d308a386a0bfda4ac81ff9a3520ae3ecae5bf1eb5bfa4374abba9014de5e29d5ce39adee9cc7ee78056fcea7acb3f5879c20cd9691ed94bd2bb1db915c3a6a9a7a35f30f3833000a70f16c8d7bd07e7", "a28e0d420207368bfdeef355ff2e28fdde9fc8240b826c388e8bffde0016a76edd23ed66a03d29bfdc16a8072b8eafceab7d2b39defc219f909246f4494929f309fa5f4309a81ea45d25c30b8e1bd3b4ad2453c400346682ca1b", "c93b21aa8e5b24ff6ed104c8698d553b499d896aaf6e9282fdd7922de74246f88eb9b828d821357c1d736ef3670f96484fdc75c39dbba63fc51293d2", .Okay}, + {.Div, "-5ecc938f7ea6d026fabaa3c87c2bd1c3fe26c225c4bbb75abba1cb5877d6be88e93699c51ac9ff52411ed1cbe3cfa761e059a0521d17bd6c0b18e1c5b6df950e6d6497fe142dfd95de8cf83ad0fa82fb74e7a8f98d413150b52ce4ddcdbed0e9ce23d78b6c052c3329985804895a2bb967330da1b0bd5c8bd186d1eebecb5b0980a43652428fd409c10ecfb5f6541d7269338841402e", "-7306a8e53b54e9de96363a260a4488943bdbaa9cf2d928b7b6d5e79ccc1a43b49fd06709355593773983ebf15ed911dcdfff03729b419b3440a330e207eefaeff78c0130923810de6c568ef3657cffd7ba650ac3f7998e22e896", "d2fbbe40597d53fd8492fe7df4aa040987ebfe8997e7fd2b200b7610ac772ec2e215f99510e332cd1b4a7124acddeb1ebd2ee886d2f597ade9e86f80", .Okay}, + {.Div, "15626ccbb800b2c9d709278b43b832fd8821c87ff9f31a5c368dc26c6f7faaad8eb964c249e0466b077b0524ea33ac90149c57e6aa9ea595011dd1a2d5b959e5ed873f13c404e98a9bc9ccd1f63fc5bd188993f30f4e5014278f682b837d69278869a59a78de9159000f6c8a8e98277d4f1a9b4f2db748d449e65a127e0426be8a9970208576bce9d409bc70c8efe22c37a6be76ad96", "-e3056681cf3c8b675d95efd44c829ab283bd172b48c345a182413ced0be3f02f107e7df52b9bfb3f104a3b3515b559283ffc41ea6f1dfc6fd8b4eaf729abc92608d3d24545ba5e07d9b7a6b40741d547f2694ec3cc9897ac54e0", "-181d3a2845b0a977cb3b9ff3378402b45bbff26d6beaa41c46e15576f8ef338f5a2403e966a68be0defe361e2c9e7294acc22b9e81e290f26bbc7179", .Okay}, + {.Div, "d335ace1653786628996ed1d764cfbe89be13480ec8dc7c1906ccce018a000aac00ed5ef1b54a1f99ccaf6759bc8aca1d571ebed2a9bbfe9fcdfbe69a9de325e4417542e2b9b0f36fe5551358508564bb7a0445c96e57e3f753f106db01b068600d68c51d63500a219e9f8a188cf4a804c078979549390d59f6de4f19712ba1c2bb92917b77f1d4949578d6df66e0705cded22e993be", "-9baadc9251b867c121c77fdc64c6b3947f0b8ce851c3b48197b2e074e624c8bb20373a72beb11da0266fb18022761c8f8e4060f52c177b6072742db62dde2115303280fb27a2cfb4899375cebcaf3ea4261fd2f35dea471b08a8", "-15b5749bc1ae283b30dba04811a1821539dc0e55bfec00412e6f6385dffbabc48a5495c3c9732c0399c29abf1a6a698db9f99c0a7a53bb31683c64f49", .Okay}, + {.Div, "7e814706d631dbd24eda2f8901b41dafe72db52f4b3f10ec75412f2666fa279facf8cc14138b857b904b68021bd52fe8810f8eac8ba3b2a903a84f8145fdc8b52352aaf9aaf45a05da1916314e0a070c2103f27ed0d035992778b1adfed3858784060cf3a023959e78aa5042710cb25529c147193d9206ab7d1d8218449b2af35b2a95d779a59621c6ff70f4fdeebc7c876d4eca8543", "-65b50bfb340b110ddbab68af19bbaf65190d9e2a75b430303fae3164378310ff3c5dbc3af6a7a8515a767401abfd84f30ca5bd53dc9c62919460f1d6785127aeb4adc6a6bca777e8fd2832e59e710412523310d74660fc7c6295", "-13e6aae202a2edf78a456004b2b94ada08184bf00b95cb0a80c44df4ae3b84dd97577e74bbb91b548e507cf8447d54f7323963415192ce6884aa47801", .Okay}, + {.Div, "8042944270859318db832f84ad928d020e7e5c217a9a2dc22f102116a08ba9662f1114558a597d7bc01034864f5bcf999f264a499722428ed2b5260d6c90dfb0140f9c9255a0520a1d217714887fa53068e2d0c63aeb532b030f542096453c87e88169c7bde017d917ba6582fd8b29248ba07686fbcbf7b06e36f8eb08bc0c722cd2c3d25235df41996d77191261732eb0c19952c806", "345e8790de151714ba72bf97cbd382806a04932afcd822c851f3f624a29749fe047224939ea381a5b6ef3eb288898e5973e07b87639024cdf584fd4c4f4fa9b201511ec53f909595fa54778c945b2357b65288407221dca4fcf0", "272fb6222a6111b13da72fac49cc620c5c165e7a38b54c60e3e2bf782e1702b10e241ea36e0ae233ef28510614deff728b86f9c52a0e5e37b25b8d582", .Okay}, + {.Div, "-df952e28170526e602e392931de2c8fa85f83c02d2e42a31520507dbcfb50c4e08e711b586d838ee05c6c6a5fa40c3335942df73baf918a1cd3e7b0447b489ba6b518ddd31b53a74f65551bc5c8750f255b784608e547dd638e8cc61f4ed7c18a963dc6b000ae17352324f40c7ee0293220d172b27932cfc56e8ab41339c32f8348d5f6b5793eac508b9d47b28f31d9cee88b40ab4bd", "55937508bf9fcda6172d12b420c686d322dbff0c2705d5fedd907c498e43796241bbafea5d1ad94f31498184c95f9c477cde919e9df843b957baedc02da098ac2ac7c32b2fe1eb87474a9e15829d9e14131b99a362c7186736c9", "-29cd89c9d8639695cfd66db80dc95d02b33b33a7faeafa39a29f70911d0743b64f557d9f3bef2cae904b2c20d0d343251336290c8e51c409576b94216", .Okay}, + {.Div, "-d4a91a1583bf44621d84540217b47c52b3c263fa7de41e84b725281e6e42b8bcf95e6f3c8868b0c01e50b1f0c41a7ab10c2b5fa5f725dff110c5a28e13f5d5802211869c6c670e50f11184f64c2fc7d0f46e75122ee2501c639021e375cd59898337650a3a2d3e30916de5be8d223545bcc2e99dc70335dc13d28e9c152f0b0bbb36d661f589394d400028c0497401f125c8b544c395", "25e4807437eef2fb447459bf6439c20c4236f3da4d938bcfda40aad9a3be8b58de21aaeb9016086bd67637c2a19f81abeb3c30dc3dedcd99756cc71a26c27e6f387e6dd5d10a77171d67757c426b438e0c648e85abe90e31ebd1", "-59cb8c5f628cb9934bedd8c24ed73e53410c97effb541c98b95e550d44fce211986c176a59e8cebaee12c69f7bcb66b710183343102b50328dce96e49", .Okay}, + {.Div, "-814ba60a998045cd1f98dd402530b8a2dca2e000042ad05231ea6a04d697b2ee5e1a523eb39f653c708a69eb2d7ba18903aada44114f46e89594626498f0fd2ef564d90baf12d6f6c271ff31f312de71103638178e2fb9c3aca2fe94496cd8016f7e6a3e2339e285a90951849ec8aec96ec8d20b4357df6058b657219d9b7baf230f18e4c72847a816dadc1c0f561e6ed9cf5206c238", "40229ab4b2e243ebdb50de91a3b5b6740116f977e3e68cfde9cafbde329b37f7da65160746857d447f2473fddb1c850650f4d50bf310f2ef097b8d0c9e9d0a7913763931dc9bf3f4ee70f37a1ada9d125c5356760447214e494d", "-204178c1e28171119e6e9dedfc122ddec0e4928a21c5219333204be7943006903092cbae1ccbf4e4aa1621ecef1db7be51b33e05ef0704c868ea16534", .Okay}, + {.Div, "7b51de201e5ef93fa220c1de45385628af2d071f4d72743610c37ceb6796f00d42e1ce70d42888a6b90b8948a955b193dc4c0d8f70dcde4bd54255b1a1652f0ab3a078ee77227c5ef7c342cfa79793350c0e5d975f8a55180a0dd8bfcc6478c67541fa1f3ca0be20d4f7afc80c453c4f6d32bc3febf37ee1a5a6d3cb0c9e2663b16fbf30fbfaf464b0f8b5f6e729308001a834e10aef", "-60ad9fd67d7e3f60037ea480e93028e7202498df40a135bfb9ba9a5686c7f950dd72612d9a618522da233b138b4f2fe1d66023564b716b1d3537663b5c7ce092f22f62027811aea2184bc7c62a607dca853aeeba7ef133c034b", "-1468bba2d20f7639991e11977da90db2392f7c93ded5da63ae0c0b47bf6344453c30a6366cc85ac42530338b39242c8f93a93d009fa6859cb4a1f46e0c", .Okay}, + {.Div, "404f937accd5654eb0800068f431eb811e7cb852bf0b23f0b51bf1862a0ad3ee6dfdba39c699eaea355579ebbb12a7836157d146bc98cf646068867bc1728e3ed9e668202107404bc3e759eefbb6d0d15774ff25bb976819260ae11b6ac9b7ae09712ab71f872d26cc156ff6cba2073b1c1945ab90672e77406a7d7ffdaf7109bdcb9a186dbcf9dd010e7dc659edd08981a6b770b91a", "-46d3d1daa2f1d3b446a9da9e76ce1ef17db8cbfaf2a5d69934e8ea3900087a8a576cd0a15e5021d3b1065701771044d4bad47ec57389bb4805da104a74418ed9820a27b6d7d5183356ef9dc5015cf86dc11702a71e590650f285", "-e8724493fe9058cfa9f1bde46393cbcd509e335a37bdfde629a0bbbaffb025733ac3641087e95b663578f3e95a17b13f1e2e0e9f8b9e60eee7d25f6b", .Okay}, + {.Div, "24d3609498f0f87401f9c8ec62c88e4624f44ca80b7f1a87edd46956a041e9eb994e830d5a83db1b26b31a8ad69e633bb8d6575dca68bc3df3ccefca9e2b498f76ffdf82a1e1788a66ef8204abf23aea01cc7bccff331532ba2d3687b19d10c7bbec75ff7105f4cb78cd2fd0f3552219c95915e375ee32de866bf8172cf09077b417f3e6fd74c1c7b7c08dfa3f2ed488bed89ba3062c", "3c4984bcd0bcdce23662f9d8b687bfd0152de5b1d742a56cceac22026e661d55f9dc21e074635d723d700fdd84b63a54bd2ff8783a45273b3fb7380e1089f3272e36a3f36c8b85c1b5adc9ab104c96433c2ac559b999694282db", "9c5fde8e5c821527a3e1edc73042ae4d2248aca9aa14a526f91f9d510954ca8192aa3673bdb94e065d4b781f8d20b5015fad39f63b40f13460d3a7b1", .Okay}, + {.Div, "ce9073b132eb4070927634a5a816ac65f8d9ba14ddf9b8eb7fb7d2da1e71a7f717379c1f41313e00868af2b32def5c5a06351b31bd4536c360942e5dbb9225b5ff5618061c94ff85571c54493370c03485851aff368d34f0e791bf472aa9a6a3025f9c96c458e8e974455efb1c03afae75732ce1a4ada54a6a860ddea0d8e1b498667d4fe106320b75f78cc46417660289640c34a74e", "-2d757cea705ea4a16221bb2bc1afcaccc170809fc043e6e84cabbf72ee0f4d73b6b835ed1886f36dc0846c4f795755785566b565a58689f2a5c56a1936adaf95658cfe553849b5fb6af823ebef52eceb8a1b75952b2800d91b4e", "-48b41ee9ed770d624b067dcd3684e65e63987b21f5735767573ae4ea1c79400961f99b1bb042a1a74d21598104d3ae881a2f45837f503e1c5b2ad4930", .Okay}, + {.Div, "9e77a512a6216c82b487af8b5693bcf70896733748e424b6086dca5d84123b19a6a01ee29b59f18a05b8bb88c8e6efa69d385601816d1c835afeb1894d3de9f77d1e10bc444cb10c58349d8c0311fb3f2d5a4bc3a6f29385f2ebd88eb9add51d7f5e106428ffcab03f74281afbe3887466b2a03e3fe08e27def524161b2905daa77e8c0b3a014c4b016501e8c651ec5bc0ba9446e00", "-59de12def8dd3cf350c44be0a437a479d6205fbcd049522ea2b005f00c20c1cf4f368174da0fc199cc1bd6a4f979fc02192c53f956c8dffa1a0479f38f57e259789fb92f65d0f5fa30fd4e1493fa23745b4ce88c740cc3060de0", "-1c36a93c5fc873170029d023a036ff4476522395084c7479af256a7c674c38c10129c9b05b53c4931aa747e239f67c26a677fc91b74b8ed45a0b849a", .Okay}, + {.Div, "-8805dfac585fd13ad29c1bbcc68851c32a7cf6bc42ef42d4c04c89d2f245e9a5c9c9d8060a8ca0be6743985c13b5807b6b6fe83059d303479353e1caaef63204dc93c8514994f935c6d36e5f026b4e6934a9efe575c452a09ab2a20e47292300659441ad0b6b2cd448ba18e523bdddcce52186771a61da411d4ac412391dfa741adcf9a98f31c49a2afb4f106bfd51692365aac80a58", "f41ab7f37d3728a2bf09ccf2c2631a120d92da61721369526a3692ae95ae515f4ecb7117f0e08b78a792c88c8fc0bb840e18064e72c7a2eb5226dcb2d9ac7e3fee3f6136198ec1595819a632129d4969070fbf9e74c492834542", "-8ea6cde1110903a9ec68a1ecefbc0960fac7813c0436ac3bc56df4db5466a8460a02f0dab9fe9a98159c07d2e1228f3083d82b6bd0db95a43674293b", .Okay}, + {.Div, "37e2d9ffbb7717ed5aef0db4c11fa6344a18cab081c22850b9ec429f90836046ad05234085e1df91ff0cd6f73e1ca1ebae3a2c7b49415057bb34b18183915f13e57884474b259927eedc8619bb8de169aa2afd420b0a658a8aedc96a35653ee8291313f5434f6104d3d10cf6862eb4fb698fa6afe664a5fcf68e44633a37cdaa5a31f389500d985b68cdee8dda89e1ab570771195854", "-768020ad07a07c1513a1ba27dd80d484665ba482af62730d62ef495047662bd1eb43ec3f824e917a60f39165c0224c47e1e8424b91fdd921246f070a9a58e4c3fbaf5909b39801b46f06900d61f848d2c076a7c68b3c1fb8b910", "-78bb7fa6c2dee22415a6202145b2fa05853a9b57116474ef8fbfaab9f9d6b1be788b7ce242f93b5d4fd0b26dc19189ab8b5d38d8598c5fb61c376ca7", .Okay}, + {.Div, "-391ecdc31953ef5670c94b136d9c3b5b77d5b4d3fb0d6e6bae9e0964d1b71d8e591307a33f51647439d7daaa1cc845175805cfea8881b1d524c085764ca8b6b234089a7941a5c0b3cea468f0066c981e3fd37b79c1519c0e56c7532107820e3dc61a857ca4589e3847c837734e3e7a38965b6200a0f6c2c7ec4b7c34af2f4ff965a8bafcbdc49f17f9ddc7797a8b2a58c3caf4346617", "-d288773370fc1a9bde1632e9b663224075a91d7ea192ba3edb70425a4238c3fc7d0a58d78abe7e9136b7bc98b2e461f6edddb16e54f4f250a6d2269a91d5502c1af7dde1bd466022086143ad09e232584aa614543a2526670060", "4574c24ecd13b53e78039ee311f9acded75db0effa5adb4b4fafc56201165f030fa3dbc2cf6647b0e1450745cdb11e940f4dc2b784a0de97c878d53f", .Okay}, + {.Div, "-6ff88c2e252ed363160ece65ce6b7082bdbaa0c5ce06cf5668a35ac07d1fcda86f2d209e873a9ca1c3133661e2a739f83d6d9acbc2cc00b8df82f14ba4ba4ffb283cb18de77f2d4944404ed1b6d28acdcd4df37585bca60d8dc8ac729940b8e01e5dd75cadd1b04550293218eed8af9276b12654d2cffe22592aa003acff560cfae211940e2db2d85202f517c1f97c50540131febf", "744316096924a901ae9386f126c8493ccf9f9cd26f27a6f16e06e2fa7e18137f3e1455f5a2e2a6b0acbf6089d88412462cce73c8e1f8ec70898cf910474a44d09b56eb86e75a6e6793d1e5f19ce9b41fd0c26e08a8c5819ed3e2", "-f68d1a8b0ddf2f3853c69e5b409464254d7772bf4b97ece68d0a035d4094fd1bd0eeff024d71e7e0033f90d8cbef075333207cbeb7bcca13ad0617", .Okay}, + {.Div, "ee7d0434eeaebf7cb57a4ba6faafa5152e2acfd1dc12c70013332a069f516fdded6862bded70f62c696dd8bf4b41ead03e830d896d56df090ba71fbb6c2dc122fc379211acbeb4b844f3c2b89fdfdcd3d8bf9c113a62dcd54670ff212c3e1de700458fad860987a62ef61e5b2eb81d87932e9cf57d4031638edf197aeabb1c74134f9aad4dbfc887ac64eb7e8717f1909f0108b37a6e", "-ace779243ff68d6a390090435f5f52ed8014cea5db6b1b8e02dc55704bf2a3d0ac7f35adcb214dfb5ba429441ac958c0daecf64b1ce676d496cc0651c761737aa4fa72e239a9b2c488a8875afbdc0ac2f8619143632afd2bd856", "-1611a689c5c9659256415e510bf192f5639072a5c66be95dd227cf1d1a569e5e9742b4657e098c059e2f814c5b91dec28d06d5f39d058e389fedf2788", .Okay}, + {.Div, "1fbae410c6f1a438de5e53a5cef9ef49bb6228740f16210e530bbfa465dc692ca261728b6d053feb35652f022033580119932336119c02e173be0bd366e9d3d4fedf0f435f37514a154d9cee30afc18f9438882233525c348be58b3ef549695455c2b93c815692ff69d46186cd0416e0283cc7ab02943c9a06bf7009ba390357bf6a0d6a3f85fd5f9dc32ee557c933c7df4f1b983e9", "2ce7e974ceb7c1bee6f49a8535223c2a83db07c78d7e37546328d9344e52eeb168718eae2aef935fbadf8544152a060bf528fc1076451231a9a4847ae48df9e35a77f0f80b859049b146095b543f2604587c0e530c771f2cf485", "b4e30cf9804db7f3c3f7180fb5c219ce63768a72fe0323b780ec4ad3740924d2d7222a7a7d8f5d6b3566295e579a0ccfdd1604f9ffbeb846302f4a8", .Okay}, + {.Div, "8dee910300ae09d67893b205a6863395c3bc8c260f085212e1134aed3d68c757815746ad5af69d49e53cd492dfbfe9c9ef38caacfaa1760ce4340c060c336d76ead41d56e5c848a89b11e2dc52800e3c057e1de56804f5d15c831c696be82ec1fbae43afac856079978382ec9058a13240a2aa47f04697a29a55d0a48fb936399a3d6b626f8e46968cd3c26b0db30561192466f039b5", "-21ba2385cf493c037bc814164f864c71f045ca0b2966cb278448cdcb7b339ac909f992396de98f5fab69ae320df89cae8497703225052900acc1ed1c95dc058d9223188e6f32a73e6e8578ed74bebc50dc79a548188bc8c1fa4", "-4354f81fcc6d92876d6f83082894be34d20de490cbcc0065c3803e37f1c461bff705d73939f0457859e8a9f28e57fba9a6009e0fa37b6938d8b9acde2a", .Okay}, + {.Div, "1ee83070fd6583f7ac49231e3d40f0102feb93d86cfb03d59781b20769e191d7aa83f3aa6fe1c6d69e2a1e7807fd2979eea4e2f4974b6a759a4de8a764acc531d0a09e0be6a577e8a4222bd0c08505451e56f669e4d86b40b77d025f58e4e9985989d7eded8399dde8913c66c177e2a8db8f83444574cb3281e0a0bf6508af83d066c637390eac4c1996428ce991bbad2c79e2c73e28", "-3a16d208df5f0f47849ea02fe9ee35610c7ab3ecc3d315de08b0c59cced4ef7290a99b40932405d9207b39cdd3d820375bd89358ab2b881b3653fe07a345578248e860e7d2e1e4dc970d0eb564d2b5d3792d974c84ea01b90625", "-88352cab4d588378de831f1da0a691b5c69cb5905f13494bcd8ad6bbbe16dc5f79d2e0d12a0e5dca4e399ec3d88f701213e4b9924737272c9045ece4", .Okay}, + {.Div, "-669908670f3522a82109430b80fccda45d232620f43ce68f4e04c6710e3f229b84ec8103958af86ee30eb71fdaee54f35ff8f5344aa9969748f855a34aef068dee5cbd67a2249cfbd6090a017b8ba0fd8189756d5beb4ebb8105aa9b14aca6a9db46d9a8c42f32de8cda1f3c53dc2c672ee0c3d0866411fd4c7dd49082b481f65080e517392b08d26b22df11f58bc8dad5c33cb00a0a", "f3524317be42be2992c87e85d89697cc41acf898505a41dcd5a7e6bb1bba8f546cc3fcf82b890408d824b1be6942abbb8bae6a22cd5293c2fd88f3ae6aa9b9e42217acfbafa1d8003bc0119e5a455450c087a9fda53ee24a8070", "-6bf19dbac63c2c6fe0a357bc03ab87399aa61b2d36cca0164cfc7f672b8a88fb114893e2b302d48b3c2916de0550777cbffb105b8817db6be2f254cc", .Okay}, + {.Div, "-fcce312a31783166131891a8ea5c5cd35b8137efa99a1c6cdd7bb1c66287bb3652002e207d0fd9ad3232e6fedb1cac74f237c297617eae8a828400f137d97d96ae06c58b220a60efce7e0d4f28c99bd73b662a36e13f664f9d00deecec4ebd8afd81a21d8ced3cc239156af28823820ca3a106edc2c32b89d58b1ca834aa681d6c40b7561315ddbf89c035a6c606bd05b026ad133217", "-e541ee0f241a9366f7a6ac51bf7623235661373df288ade0c88b53495d71997c50478d75eed5eeca162bc5469a34cf0c996ce6042b2fa421f279a9e1614ff93cb0e6f4c44e4465282a37a20261b98ca106149043bc3739744615", "11a4b7294f92a41ee1bac78657e182d88d6230ec2d6e96dfd75a3fb8d0df8823aa56483d75eee05815572cb033d96215b99c7376b638fbef1faa9c3db", .Okay}, + {.Div, "a416846193b299d542e6516725431a6db57c62c123d4e911655e737013e5872e241afd26bb6215ea9e9220e13752cb1675db0377cd1ea09156b061c8eb3e237f9e40f2a0bc5450704aa6b7d54a9b67a658aa9759aa69340e42d32d5074d1228fece2118f88ee5c4af0009a6245ffa6ed9687ebd86731ef7eab4571e407ee24723e8249fc459d89ac83681560c6feb1f281c5ecb699a0", "f5565afb6bc1c74bf84f5a983b58d187719a79b73937546e917d5323e8daf4fa6c4e9e6a3d65e8d8ab57253a7f05604d4790b49be05d7df0caa7c50ba7df8685223a4750ba5121c84f0e85c697d5204b617a0ca72ce6ff7bcf3b", "ab382c9303a609c601ae0e8c7261f8aa6928c1cf1eea0951670ccbef48ffddc072a6e471ca9db9674c167ad43089f46b6c4db1228589dd257fd5dcf9", .Okay}, + {.Div, "9b013111b1469bbae7269e69e7971a45f885823f5f54c926e990c8c4d1ef52b89e8a90d0e19d55077b4372ae450765627679053f913f23c7168b14ee34393aaba1e8c1ee5eb957ef0b65c1fe00e37efa087a11a5a0abd82aafa575be87f227fc7b3dd60418b36f6c6620eb2386e014ccd7e41af5b179d20e3bc852a24082f3c29c01c9a6a7cff7da7577f7eec98be14e4ff60aac64b7", "9c5dff5662de1f4c0575c9afa70d06e8ede7e09702511deae277c3c776bfb7016189d9f847b51a851a8657092a14d3e246dfaada5039a7c938b69f8795e2c5a05248c78d415c715dc5d27e6cfce452b0e25aba868a1ab1f82c4", "fdc4f1e7643fc432a8820a81cd99ee4400ad0e184ddb6b19ad8fa3fd0a4635bfa8fc33c5e962aa2624a310122ff1738118a2ef50f9ff205cd8a362961", .Okay}, + {.Div, "9ec151bd790266e382c777750ed394ded2e220e101cafdf57cc7accedce375e67f15737466b66f805b516232667de6fc786dd8b440050a88997902cc659862a36f6e08e75b4557e7da9f9d2d71367d7cb83ae881e1887520e52b96b2e1b3af602d319695bbf3c5d324413055cb1837d2e22e91dd6aa83ffc0be0fb11160cd91d826825f1ca960cc54c495ac6bee616d0a25d4f9e85cf", "-479282067c0658ed4cb9c2a7228986b05a524c12e8a0b4bb0eb37ce13ce2e2d886e4d9bc68ec5e8007c5ce3738fc769db2b8e4d17f2ead76cc25d336862a4248ab1211eb90f094864b726a96b9f8308a656c2c4e521537d1f3b1", "-237d5fd6f5c9c5a58c554369a71085346a521c334f25c620dc9b250c86b1f47e26357eb360a687f53dd6653f08a0e8c27b586fc45ec176ee8e7ae7de2", .Okay}, + {.Div, "-d4762c2d07dec977f2c2f7b3f1e4f1e0c8097541d25351969ed2e8df8b48001670c2bff078b8099998af3a02dbab68b84ff398c7960f533e6886d9564502762b27c041436f16da744e7eaa8d46a91f35d08e31caa1851ca9aace85a8883988a9df63d5712c41fc28a400f03ee32ecdd2bdcacb740a69c6118ffbee83ae099b5d2fdd2033c435a76afa5cf827082ebdbe88fe07c61b26", "-a5ac374e5ce21a4a5ffe373f0cb90805cdcfd8fb8699e44cf71577f83a2a0488fcfd6c444b7e115b4750298a8f98b30f4ce99dd2a14871d12159a94c89088a284ae6ff64429330134cc03ac318b57d42e8545377a69a18cf4ab1", "1484c852df3844aaf2fe7a23d1745365b9f24087677e96504a556180bf70111cdee87304f5c2e776cde4bc7d091c3fe5f09e0c739857b4b63766ed19f", .Okay}, + {.Div, "-69c03a763ba95ccfb7997ab3fe509dd7219ac715096098a9e14a46e4a62dca09e57efdb5a90e7cebdc9b1b766ef14f19f8cbcc0512ea58446954d71e299a763c22f761c1940a57970703e6c868469c0979539737eafae4f43f48dc2c7ebc7a66b07758a9225dc09241b79fd2b2451af28b37193ecc6d655104cda73258793ff40a730672cef2e300d1292dee56e6e11e2c083648e6d", "fe486ff76e54d0787e35dda6c42cd6242a02e3d5b90d50d48ab1abb7f838134fd57880e313611327f0ff7d8357c364a0704d2f4f0e351f86a5e6c2fb6b569064c1f3b51d6455ac9e5a3b8b5338f80be8a76a52f9e275fc723657", "-6a77087c4de5be92779a6d1d7a846638a388918e923371bd7289d394081b9c2dbc8e8607701914e9a51dfa8a534c56b8192a4c684637a83ac099b5d", .Okay}, + {.Div, "-3dc7d00a261883ee9c376426a99a55adef02e5d1951145480e31ae0b1af872232963281e054b1de24c423de1adbe9ad1114e85e45f471f9afb1fa48cbb8ebe9e18a27c56e16a6d76830a676612e5a84e5fe4be67e5e7713de53d8d173cdbfc290402a024485ac097d4565601f4bab4205715d356eadbb78b2d265b84647315046b7b8bb2d7a1f62a7c23221ce962e2359c3786e1b55c", "-fa4594848c33a7174f39ef80374745cd211056582a22ddab8c4159e089a17a50a144a9a3a54d378029962d0adef728249f962e8505b8e0bbf2463333b383d0c529ac39b337374c5b9674afdf921033b8db192f2cbbb7e5835df3", "3f31cdc6d53f7c38d3d0354189610e890a077a85cf37f6dfc482d8f42802fdc466368249f49829aba1c7a1166d3c266d028c8bf9ac7eb5df00cdbac6", .Okay}, + {.Div, "-44dd74c0503e69f2344831e3a359ac07dd9840d186d1cdbad9124b980fc60f54f911acbd5ecb73c8c327ae49d380dc64001d1fe8d79a8212efccd75ff3e8b512ebf556747aaea09864d7ff2a2ecbb77865cd5c834f9cba9e392ad76c9ee74162922f477592761c0cbc5b76cdde4f608947040c75b0d68fa8afb6cbc9cafec1bea76f7b9b8cf917a324f7f6071a84805002a909fa5b36", "-8bed512f61e0d6546250847f1c74a3104162f3f64767093b79e500003c2c9986730600a50cba7341ac801e40d67b1d6e4f17156e017408f4ed370f3eb1d5b6ae44c62670045568c0741f5ce26725832896ba9b401b71f889c997", "7dfd886f5c90f899232a804fb8514798fbbda5b65e6662e15d51fda378faa9451f7747db1c4b27dadc66a29da2dc948e8b88bc7812968b5996e6848c", .Okay}, + {.Div, "890fbf6e6f0543393aaaa360b1599cee4f1214e2fa094cb8e27d13ae8a8ac1b6f85cf7ed5e9a9217b32f20b3679446bdd45ab310427da3e10d35ab362fa304016e6038e7fcbbde850e93424cac40cc9bbe28ba927c4c42a4184811f6a3246cf83e54772ac9a96aae6c8530e800968631f154e2ecbd638292f654732e1b79169b5ca244514908ed6938be02a71ad54f341e1c61c8eec4", "-169677c61a97af3d7b33ac6465365a6081e86ed14af18b918aa8504cc720db30c23b3a3b34651fa0d8effb288f3c8dfc6054e827d4261e633a1d3caa1fb64d0c311d2da7f5e2c99922c77323340627387fbbd7fdd52411fd6f6c", "-611656b551c8e64442069b886583e9f74b0fa8ba93a5060168cec1a39bf20bee93e974091f64968caf3000f8dc5c822ba1402eee3d00826dbf94250d2", .Okay}, + {.Div, "f2bf0bf22db36444d62d22622eac750c3ecbddf886588b276e3e6d7a086f65bc7fc96c78ec7b79bb8677ca45e50f85f63c9eca52ebe8255eab5ffee2f427ca43898da6c4d7b279c92d68e5bf2c78f9eca72e60616b7fa0f5777d351dffc5d210e577dc6d54c33abb2c12e3f2426c034d12217cc41e16f17eb48acd78bebedf1049be7c9d95bb8c76d74debf707f58776d78eb7c5da7c", "25d94c4e41dc377ea2e155780e97337de9ea59b129bf82bcba08e92b0faf2ef44eb26ce315ce9ac1dc166acfc196ee1010edf915ab4f43a082a74f01e4f4b676f11f933aa7211ba9d69f1358dda21096c6cec232ffdc1eb3cd26", "669e018e1e5611d1764143fb240bb2757704c30b8151a8be0d7d9b9dac31dc2da8e4d424cbef6d1a7f622abf5f60d2afa500ebe665ade534c89fcafea", .Okay}, + {.Div, "-da9c84f16fcc454ee8346e0fea6908f3b382284661e6ecff49dffa819b1065c439c83cedcdb4b3ecc3ace4744aa6295987ad2055b4433be0a94bc592e5e08dccd11154ec48ddd1c11b481ffacb8e53635d5ad4100e5e0fe5e7ef9c3c0d8d992fd401154c7b34be5a28682cf3875012f70dcce80eac912992e2fd1a63b679697376c5f92be350e4461013cc3c74275ea1e7bb427a3b9b", "7d90cde37b04d99d94bf75cf6c3eff52c55639b014a81983ba9906bec67f1e88b0fc8627561623443e5148ae4a885925f33e9f996477b5a230c3ffd9a6b4308755de1aeb418d7a5fe5449c45dab1ab7c91e922b78e1edec7ac55", "-1bdb305b5e7643314d32dd8e94dc32aca9d9c85a00d184e80f1780f6f7c9cd7e2107365572bd0cbf721cc4d4fe25956f348dd841d0ca4feb5374f42da", .Okay}, + {.Div, "f6dced7f9dc6c12babc9799ea38e4df00e5f6da895a8d99ddb2973254456848f9a66b28872d3e3b082a49a90d6159d9dbbb3134543b261c94b694b65c4334f6f0ddbe5b760acdb5cf101b5d4f34d2453a38e944159c518c479ad676c0f28f72ffa6fdb83371376182bc9d742a3d99d8c56ceb14cd19bf88bbd436d432137d865a701629dd4a4e9211e0707807412cdb684a8b28e1bba", "-5358670c452bd114ef62711673935e50c512d617861ac2756d5005ef904b7b564091451b7bf530597b10a7d3d7720769c546e4ecb7113c457389237c0d4a7b0a8d6c4c60472fde4d01a53bce55ecdf56f7bb647b7ea64d347cc", "-2f64109031c3ace13b838d500a8c883fcdcf24ee33039a0afa9dc858ebca67838fdf481f07afac60fea14718a2df79d6ffb32e14d485f3f400618f67b0", .Okay}, + {.Div, "-e21374c1f98a38d393da0db8fda7633f1c1efce64dd360e66f5f4160529121d9c51c1d832d69336f7e00f922d7513ee86444e715187c091c2930314bfd7d300e53f331c8744b7ed5acd85c72661680d98fa5bf758432910b1673a8962f7072f6e83db7f7ab33797893839b357eb6fe7339c67ce3777c1ca3e81cc69f17bdceeeddfd5de5c5b995281e6fea04f6e7361c9e7b0be6e73", "513d00ae584326de143442537385474cb262be5f9b31079ea666a6f069aef81fbc734bd36d21a5274897fffda3904f8241546cf656ea1d67fe539a130ed087513528a6cc0d8081d7949be139e31d9ec282ad24d0373b288e286c", "-2c86a7ccd9c9672b30a1ad4cc418fa72c644aff1eb4e5bfdcee856328a9cef01e3d251cbb03a1c4f709f0d0d510c84a26c23c448819e3a2a5d62e764", .Okay}, + {.Div, "dfbfd1de70afa3447798ede0ec222bd8caf0112417eebff73eec5a3a41e6e30799cdfbfb0762264da2fda34e802b864de14fdb8f9aa06d1d944b50013111ecf2a63b9b4f6fd8dc73ce15e51d9fe67c4e4b6922d0688585bccad1731c9e774c2dba5084b7c29334ebce23c8298f0a3a6c02ce5aa2c3b2d8a31b286b33b8655e27f4bed7d3797bdeb137992186b2a70adc6fc66a5100d0", "-efca09da6db6108e6507f1964342a0962af16abfdf38ee40566acda0d7bc6fff7ff2b418c52728a417d45c9e88b49cb004a2eb2a2a299fa2229aa7da705a34b03aaa3246452e9e256a14eb9a6c12d057472974e092bc83ba59a7", "-eee02ee4f11f1f9334522f495acfd8bac41f8d63d7507d2cc5357b404b8384b444dc88aa011f33ac52ffb30c93ce80fde26b749c97d72cd12635eb8b", .Okay}, + {.Div, "734c2551b638086e309aaa285f0757b28526dd69bc2da5d5091ffb7df4679d7a1ab08065e7f4808deb3374ddfd62f5088ced11aae0418b40ba6f91d2c8bf3052a90f2e78c0dc082d43eafb541469e0c3f6410e15f26297f5b116cb69e571d2a974ab3e766afa56e54b35ce167c93b282a0909e9d35e4277fb8732035a08413cbf6a53dfe1f66a32119071740cacbadbfa09d41c76fee", "-dab3cde1872a8aaff1c961c490e4dba403b67d4bddcf40edb0bd0ee4ec3916d427ddaf0df7633866c99287fb3cd9367e8d6770a70f98aa0ce5c7a78fbb12c6644cc67db49ae262a2e4b3cabb907358bdd8f0bbfd6ddf292f3b82", "-86f5d91b2ca81c898d3612f3af613a459862106582c31d5aa1f389826545ac78ab2e92da4b8e9fe926ffdc99dd2a0643725f1380bc9adb30e9aa813c", .Okay}, + {.Div, "212f90b4de369145deb969b88dbb536730034c177512d4784731fee92939c4623a2750d05535bfb0d20a2101672cb78e335fb52465c7d6cf1a761f2701ad0e7696540b26adea941de29478df8e19bf7c76ff252d93a5707f55d4fdb9233ed68f8c9361d9a107b4f7aa6d978a75c2e9a2df5011974004a64f863bbcd3a531d5ba6a5cccd06af001799c6870ddccfb4b6557515db4e040", "52124f9c92bf501772399901cd00497c0344a3d4bed375a324471360f34621210b0bf79cdb3b68c5bb86d19289f05c7e9576d9f0bdf2b3dcd1379e63142dbd366124095cc5c97a0ac19f0a1e0e760fa41ca0f6a16c7064f7dce7", "6783a00862f0a1e13a0a125fe055b405482d356a916b4573d506a134e81711db1bba6b35739921f38d28a1ad6aa1a1af92e1fdc5a188083a564ea5cb", .Okay}, + {.Div, "5d15443155d26a92e660cbc793d6e401ca78cee65f40bea3497fee6d93ef328c6d4bf191c6411438b6260bf10df7d95f4b7a67b1b8a80543b6b05bc1811f191322f0751517afecaadd63d2aab21719708a4418f099e18b9427cb05e5ee5efe0b0962b20d927ec58de151a4b2f399f6134d1805ce0e44a84f771e9b1c0aa4f6deee45238ab8f24ed75d5b26475fcf605c512109bfc3ad", "81d53898da4fc3588570523eadf21802a75a45d724b2d0952ffb0f35bba74ec2bafdc23d1111543f2830d22b9b8e683a53936bb17df0765cdc5a921fc3d8d4d909afe0aca900fb2791d0411631352d22eb43c63899d5ab78b9bc", "b789b89ccfbaef95bb7c1130338877ec7926a0cc88291fb60f40f99a5b39d8b1ed4aab89525bd301aef7f55a0d6a28c8afc6540d673ca8d05aabdc4f", .Okay}, + {.Div, "-71b55cbc18d6008d48ec3c60312ae9ff6c0838ce5c6c6c3a0930fd93a927f0b884dcc16f1d73d0f5bb5fec65a7813d0bd28325ff0aaab2209c02f5539e5a79c9cab88fdc1f508f79995b8981173d75becc5759990a52bb5d0d0d63cedfd38fd24d5844870bbcd9ec63d65de3117feb54a0c6e88af945e52fe378786701ecab7e760e29f11674c002831d459def87c0c76402e8f9832d", "18a5f07c07b7f8c9241c0a90e4774ea45b0980d583cca517712a4607f984b49aeb1864ded4f4b7d9259eb1cb99545927653342d155f6bdd2005ea544561148b1882e8a0e6cdaea355053865cf5cd7cef9688c5b4070e30c09019", "-49cfe4f060b60aa8dc42fa92cf8848a286a45978214bc21ad19c0df6197430a5e5a1dab7129561e3df8448ec557c8e890c22c0a0e577bd7ebec5f7d8c", .Okay}, + {.Div, "e3460f0ff785c5ed542f079b80f0b5fe9cccae51ac096a7bb917234db05f2ef3c616f884b8c37af8f76b1a9d5e9196db20b3d5b0a6ddc8b3408280f27bd7a3c43d1636ccda7f361694d1d41c1a23286a2c00352b35c38b2dc7b2b15150e395201175540a36456bd71bdc66cfa70abada00c31eca3b963491132af7a2b47b13a1d6b0b3e8905ecff27243bbeacfec12b8ba897251d834", "-4734cf17e1bad697fc641b5cbf334aa78a6272577692dbde4ed968efef0781174c3f90ba5c5a9016eec100a5935ed30c9549cfcf75a6a2cd30debd1ddcd557708aa6744875f261e5ddcb478931714591a666b124f763bea2928d", "-33117747b02c3ddc36fbbcb0ae9ac7ba1c04db8d4f34ada8ac251df0e07b8a588454ffb7c5cfe82274340b30cf190749f041735b7fb51679151ef407f", .Okay}, + {.Div, "1405014442b1ebd8a52d0372584dd7f3f2e9f49e8d81eccebb9419967285576ec8c8704cf80c9441ad004c7aa8aaa8fb251d9cea95a79d646377d067a65e5e6e9d91681b7eec117fd4a4e6a5e99ac647fe11425b095219626b5ef66f965acab2fc883487f0fcee4af6d0d78ac2ad41a2311beeb87f1a0ba5fe080b648cbf861f145a5a147cbfc607a8d54b2fa637ce5b6c4b983ccee8", "-e2210939f377f1c93c4e7d673793f0d27a5bd9a58029948c9fd369a57be7c62c7314b49e94d9e1e0c6c791a4def4f847424ec6928617be964832e6072deb5b16925930059ad107456abdc521067a9f8a33eadda21033f68f4f86", "-16aa009b4561dd208a2fd6ac6c0ce9c85f35369ff35151c45c2af81047b80eb3c7d18a7314896d9c0e0f49b1568607be4142947f5d592901fdb3f491", .Okay}, + {.Div, "9e90478c05ac26b79100596de883e9fa6f21b9530972cadffe5e25bc93e9b885f6c17fd07df150e83a0c2e388846b68495e5a455f7440b91a0061513678a67c011c9bf52a1de31527ecb613bcb571cdcb7367da5144aee6e5dac344da59a3c48fde040de8993b9d832d8d9f883083993e258f9b57a34cfed0cf1fa362b0dce4e772f4ad1efe7d345d10fff08903c9fe649451c2e5917", "82c5aea4834c284dc26a8d9e4889c7b1b3025e69a49efe0c2a4080aa7016a15fb468bfc9010418e53feb63c870796ff95878565b136437e98ca88734bea226ce192568f05e5724df4d74d20f7b8481efec029ee10cc9acc030f3", "136678dfbde24de01aea193e9367b76bcb50d010879e67cf631761243861b9ac916e6365e1009c65916f670cf790b7f1610ece26511bd5a2398783e62", .Okay}, + {.Div, "-66bbdb636202ea0afc6ccaee7b5be25990e37a7b529ecd4eb964eee2defb856cc1132d03e53fbe7b8154d4160624627423553cae89f7705a8f4a705a3ba633e308458ab260c9d519c6897b353c35e58cdf154fcbaff08292e40fa25c8b3cd3ae086d12109e1218c0a7ffdaea8bb24e821a0de5bb53353437f24ef935280b62a648a7c55c108e348fcde8fced9fd97b26f0403860ea79", "b85296a15dafc3d300c62992425577ca5aecbbcf699f37377c1a6425f94ffd3b99dc47e5bfb7728438b34781acfa9644f632bf895ce1ff86674b7fe5f44a74b95050c3f07e5d0fc5da5a10bc5cdd414b2d3985d3a607f7188d6b", "-8eaf0fcda4f65f6aedfdee0b880e9bd275b31186926e38e0e82943fb1bc38b07d9a6af86bec1ecfefd95b4541f5f821cf1cd554f53823ee4aa8d1ead", .Okay}, + {.Div, "-16b6b6f2cbcd07433b5c4ca557eba34de9e20077956bb98828236c29fd44c9299d06437350b8c94c3fe6f70aabdd87ab9978f365c1527d5b7d747173dccdd50c66d79c2949ffec3294d645d74beb4f68a91519d6b9316edb954d14346de80414e897159d0eab2ebc4a78af9ed8ddf3ac48e126452c78bdc132f04f985a74ce4b058a3999ba4fa5f4158e24f8f39b0d0b2510cc02e87c", "-5227c566ce1a36f0d4a7c998537633e2b7ca6391e291a46810c6ecbd473b67667e34058944528eb9da0ceba9d95577344083da3381c0d39637e7a2a43bebe8137beea67b6d987883690f22c617ed9a6715a5b79e05f99a8e7d2d", "46c6ed7a1cc0bd49f8dc20dde8ee802e7d34c452280f07d74e76f09ff7ba4229e5aa24cd769bfbe538a61e57de356b0e3b14ec5a8cf73b7fee590679", .Okay}, + {.Div, "a1ed981b6bb020b1abaf61588a94e9cdb82f2cefefa4f73f5c8ff6043f7ac74e3f1fef4b28b117d9c3e74c1b21e7496bd1c5755b9cb2e423fad5c7ee3081eda6f86c076f7577f3588767f6e2e9e40e754b9911bfb1093250883018c8108c446c51dd30b022b55e1d0c4fe270a35e738d7a860e440889bed6a4bfe027061bd6ab590dcae948ecd19a93089d66f14cfbc59f940e30ccde", "b433edd955375f16842395a1b89c8c486dcf975bbfbc052ebf6baeb24e2a9744c8a39b960a85960cebda809149f269aa4deec26bc4e432e3dc067ba2846e3c26c285a8fb78cfa38f099fa305f31c7c4cb0d91e4721492feb5124", "e609db9ccd18108b88f710b8e681fb2df41c9196a2a00541038a5324cb595d6e46f9df5890e543088a19bbdd0cbdab8ddf08640ac728719cba74f31d", .Okay}, + {.Div, "3281f9ab9ac1e8c9dd2922ec5fc032d25ccd2b70158bdaf1f21a50678f702e06fc8ef73eebca28360e2684bde31cff3e5b21dffd0c8efbaf0ad62ed9d09d15a7f9e75f4064ba84b0679d4e93ce72e69656dfa3d7c87fcc37cb48fc7364dafc320feeb8000ca8832e7b3a685515b9782cd12bcf848c8c8fe0a970f24561b60667f6405cbf0ec6c956a9c69975f59b5e6cffc9dcfe1b4d", "f34bcabe5c95e836f5f3b2ecb496ab8006e5ddedc4f396ca49a845ff6c3da1e2d5e9389669b3ceab7607e8c007591ef50b1bd527b9d40ed7d5c31cb180a88e34a5ae68d6d8cc4c9fe923f207ee9bf017c9fa99cb33a7c5e104fe", "35252058d3288c09d18b37fb6069ca01ff7e118bb34ec776e17ff74698b8e7045f9c3044ecedf4163f3f51e54ae97ea9b16e6c3a291aafa13f567140", .Okay}, + {.Div, "c16802ccde42b8249b0e59677e2d793f1b907353d9b529b18b8e5ad08fb535e323de2035cb33a920fc4b9c37e146312168d0af2017d68af97cd6a46ba9e8145b2c4fbc9aef64ab489bf50b7f7ad1bdf18f8d6a59922deb3578af4395b92b9bb7f94e6fb4e8be18357b7151f0afb792f79691fa28579f770a874b67f2da0b944fe811625f2d17954ded70e1f99a75b7a4de95938abb82", "-90574c6752228a86f148c99655c836dfdfdd7a06ada1bf721d5a8e420950833eb0611455a546438943af3d3b1348e845105964e0e882c16dbd7a347d3d4b23eee5a518a1c5d55e39ddc8a0d0bf721340292c826bf2db7ff5be03", "-157056661d4409a1c709de085392eab5139f7b6baba4f64da8c2855d1d9b4dd694517780ba700e766f8efd4262baa734855b6919f1a920bf67942b7c3", .Okay}, + {.Div, "-b3e3632c6a4ee402e732e80721e44c314551f02d2a8089ef832e55c8d84d88ac76a9eba58dee41bd590ace1ce7747a0a5a9ca7d1eecfa39a9b6c0178a9778731a76fa68837e43496539390fa0a5914af529ecf1481eea72b6fbe3e6e0abc6c2e09afdb33a88eacadea7c89b85dcfd03adce6af3e284c4978c3765db8307c1fca44cfbb40d63003409760cbbe263490a4f6101271ca8", "-5a2e55b966e85e428cd0f0510fab131dab47234ac45909492ab3d67a685153f1b029e073d742616deac271f568fbe7d953fc61f614f39adb86d1670b9a0b11c8f01e1ccffa401f9adce63b52df25d363cd3fdb5a887e72ae4079", "1fea7b6284d1e5e877ddffa1a2fc4803110936093520faa192771d0ca5959214a9b6eceea0946daf8e001fefab8ad17df63d21f842d3d34870c8208d", .Okay}, + {.Div, "17328e8f55c82fee89ff64855e3eded9736096e6be58b955e13aff16100552b1c37dada5d0a298b6c165b97be5209d618352380dee5fb981b7e9613a1ca861705487efa5ab9b3b07dbdc63e63500756859191a9026c314192f9970fa75d3ea1429b8d27d82ad9d90550a4a767ba477c5bc77ad9493ad72ccd35827be63c04ca38930b9cbcb1908495ab2d7a0318ef25b4bed5668e9f3", "eb76099cc02ff217636edcd3e3c83a7d691d90d63c87e0260fbd8af3aacf8e78c70c1998c9eee6c783e0e497c6d2170c39f4e8427da96aec248bb8ae667f13ce8f7be23a41f0ff5569f89c640c58eec05178f255cbf7af067c91", "19389178c178e206b46e1553b5e1d8a68ba0b5cc464c6abbbcfdef40091d646ac4bcadf0d2b883b644342a4d81761afddb6f6431d4324973ef1596e2", .Okay}, + {.Div, "715954f8b2366bbfd6f67b301bea30c871c4cad13667bdc380475ea6ee2207a416bdb3447b4a3fda61ced153a6d082e0f5fff9866eb5acb62e8c12ded899839677b4ed4b6e7b11cd90217b47415e4e111c5754d57c3eef31ef04147f32ad4b8605b3d52e62348ddad9b7630e09fbe2947e6c9d4694e79d7eef20b10b677cb91e3872a1fe42eb793fa2011bc751e0d9cf55764fb7f819", "-8a2d1eacd20b84de8b7423ff510c8374cffa75427cc633815fc5085aab31015d35c9a0cdb601a8764dd8fa68be55a891a4a72f16179f6fbbfd27b30e775e37997d761357142641ac108b8a509004cbdfbc2bd5a278e66aa65f5f", "-d200979118914ed1b74040fb2e93906e6b9b9c51ce9e5548e96880323bec870f2793df411a9faba489b81cd3ff2e9b2222250df8fd7315d8e887247c", .Okay}, + {.Div, "-a081220d6d9d990c8704ed00d1c2613599dbb5bafd2114703ec3cc057ffa93f1e4fe5bdbe2fb99c5e75b1c8dd3dcac0b4d520f2e6e361eeda0d5b7095a3e008fa8f5d537eb5fb41d16506693767af0865db5e6730780f72835441f311a6c97c374717dede7dffc6eec274b8cee7bc2a69cc314068c23f9668641e71bd5883148b6fa8688412287234899f6ccfe55862e7a2dd57377cc", "f5f61f811d634be0471ded8f142b43c84110cd9078215771e08131d620bafe0e89f82899ec283622cde71854667d1f5444e13a0456fc404110d75a897887185e05519fe0ba505a3aa917ae913910d86fd452d60dc7035a108430", "-a70e21594046ddf9788b5a51d72ac9924904d9c44d8c22748b4f0c37cf404aa9abc9c48dc24f6fe23d83eefbc9c664704750ab702418538f3d0d9319", .Okay}, + {.Div, "3a2a195163956c231e8d92e97b65ba0725c586833015f4fb4ba37df1d46b1beb377100ce435a0a27fdc76eb4b539d1417dbcb33f1266c21041b00821a5152cb24fa2b9232bb4fb42d033d32c2541ce8e44d1744d42052d149be3465a7ac1775a2a658be59d75c900b305512660012f29fd543a3f104673b4de3f5362a56151c34eb1f3ae1a878a030aa47c50421d6406c0857c2236e0", "-3081538eb5412a409e74346b456cfe5d6714deec62ab0eaa20cb63033374338d7202561afe14ec56e7875ea7d0b34c3195346eced1d0c5d5f44462a0d7333f7b3425db3d8c56c4f5d37aa89b6b9f3dec3f6932e8c8ec030d449", "-132fac40b93f4f1f5f4b82253a5ffbcdb0ae1a3bc3eaf4d3f3e14f2b176866a937b7c66f0616bb27b617a058e8f3e49aa6e9dfced0dfb65d2bf27accc0", .Okay}, + {.Div, "-7fa83fe1656300567bc5366f5e18ca8dff71254691a6db062f44e15a9328240a765ca637df74f0e23c51242bdcc1e000249fc565d8bb98af26ba23ffb54f07bf2c48142b951005379b8b69d02162c3cfa5cd67f59aa23035aa2b2bff2978b54136f040e9b27b476cd893ad47122f85a3650ab50bef63271a90e24ea50c2882bb61df376d33b1edad017f75188d89f347686718c83e32", "96bb3fc300c3f485def84136384eeabd6c87c8736ceb99ea69be45591fbfc2782dd723750b3c456affbb7e87db4376ba8f9a071f4438338c159e2f0e4c25779052d6373a09ecd31715359c524bdf072e7dcd1f243f98859853ef", "-d8cfa430258b712b9b422719ef56a34e8c6ef5bff6f980e0927f01527bb502a6fabc2b18562861f16edf6b3f2ba6c4fd59a5d2fd23cc3f051f2c1163", .Okay}, + {.Div, "6e15ad962bd60644974454fc6df5224989ab4c0e41201192878fceb9606e1f40dcd349165820f2d5f942c46b10ded297d77de30adb54bb13cde97285c7912a76ba74690dd3bc79066a3c28b3c1fb49a592af49ec7585713df118cef07d3e9a2555f0ac68de072708ffd1c8d4cc52f477f9377a08667c3a6f07c2b8e5612e8581c69ba2fae8d81b9c1712800677e737aa0cf238ba767a", "-6807261237ca050d1ee89fd68556df983b013fd748842602d7f575e392b2a58befef7b495d2921eb6fdac7a92af0a4966758d1c849cfb4338a92872cbe4044cdc9a08ac5d57b78a9c89913498eca1926fb2087bc0252719aa3d2", "-10ee7a9c22002142d53cd71f8e40e275443f642f7a9a81a95ea6676bc4b9386cdd9d7d16cf368895c20c55e765f796cc568d9ab8b8d23a26ca618c713", .Okay}, + {.Div, "ff4ee60165d07b07bef2113c0defab5910545be7f09d060c7faf2bfc157f8b8a5099a2881a3f175615fb4965f6c4f2fb5b900f5d5ceeffdc5782f219a4d2cffe514663a1bba24f680a49e01e02c4d25a183f673371b597b6b6db876fc9933f4a3175dd198cba64505e6a167f620431a80ac766de356be3c11f32617a2fe5eb55b19cc09f981899d64b676b96fec892f6671adea8eec6", "9d594ec550114bcc9a5b68373a608c99ca025aa661350b8f85cef7bfc1fc6cfc6cffe996526295ef885141471c8a7075e8e0cf55f3c3be2302846b9449ebd6f8f1e1d1e8f9b608a6b67c12177757a7777dfeebf759681384f095", "19f6030843124f2dea420723ab75344d2e9efd53a687c54af67c44a45b75a42b166c8dc0699ac50cb453a045271506ae6ce720ec385bee786b615f0d0", .Okay}, + {.Div, "7cb0974a6b576e1afe657d3ba5635a8473ee6e66cc73dfca200f47ef7c08bab42b867be6d5062f4fc188faa58c2beef8e38de4e9cea52dede61dbce54f9d2ec6b837abd39dc3a302f9afef9f1bbfa9fc6963c882a4c6c79e1665ae1d4ffe024eaf8582dbc22d6a00fc692a40dae7a6599bfff9f14ece2abb0519297b378bab0fd46770b01367b8ab764f4708ff553b00672b8bd81fb3", "249930559e4a1a0f56b5f7878e671279262e9c04981580983e1a868935cf380c18b3638d5ed116900727d543f4c134d627997ee2b6811d41ac6399d2932e96dccdfe3ab42d2c21569a73c9cc607365541ceb2a2f31a0856a1a30", "3682f8197e4faec96f12733fb98cd7f50b7f40840adf6c726043dcf66ea07dc34fff3a1fabb883e26138a0ade9477f7c040dae979e5b762f31e01ba5a", .Okay}, + {.Div, "b164360252211906f6c0be2e4f5aed3049ed59ae50b71fa90f43b1adc8a471c24581816cc27e7f3bd80ac9756ee1b7208ba2cf3d2f569fb840564dcf6fb66591f4002ac8ee815e79759071426370ce58c6e307f9bd39bcf5ccddda6ff99b9c774e579db4da78e3098291b1e494488d3ee197beeb091e79bb52c2b09e19f85562c73ed8b9a1fe92fd04a0851db6ec18ad8461273c5131", "-d6e32cd4bff60d9e96684eca91887b17c6b936e126383aef618218202f24bf9d5628819b509688463780bfb8dedd6b990635fbbbcc36c42e4c2d9253443b4d901dbb2a39ef9c6558dc0093810df067a65463d2f159ebd91cb866", "-d3548c0006a78b319c4a0f7a3932f907c702e42030d4742628b31a6efd374fd7dda94aaad5d701973cf9f4242fd95c64ef73c6c8fa6abcafccfc9652", .Okay}, + {.Div, "-a7efff55b5585e2d772b9044a75e0911316491c01e6b87c218b28482fbae62b617a4d276ab4851fcb6171ac9f32effb0f1948ad282e96c8e7c2627ef45edf8b29bf4bd880a3c90a02dac84a0bc7604bd9c8456e5a1b1fe4aabcf158c0ad62f927272d28bb1f8a53a80ec8932b97c5e1203a42e13e7eb5fd594c9f7cc520d40dd59144c51d56195a41efa4eddd764438119f33595c760", "bb9eeb3b14380272556398667a3e743a59cba9bc9b9b63d47b2a92d9fbb5d1c15c815119980537f666f263a3f297e5a26e58f236fd9f38b4e014d0687f295c4fd287fa192b0a2baf7c3b02fe9cb7bd19cdc525c48b6689cac88e", "-e5249f0c62c9c1b2bbbecd64960d7d0d06236aa2b27927481f2c929c9017bbbd6d38a7db7e8464cc71f973ed6b88242ee70305994eff2e45a46ab18e", .Okay}, + {.Div, "-52c6e1f58bc4a8644d71fc01d630a9aaa8bdffac03e0f1b9dd991f138ac681a78caf005afb05890ed31d3709bbe95f234744113f5edc61389ab9a80a5985b7888d34818c23956a019b94a136ec3c9ccdec9e2248a544023c192250594d466eb0e6721227f22aac5e8762a112aa87fc14ecdd35e5a0c69d589cf1114d6ff3e7e17eb45c9806383d28072d8c7aa84777ec14faa1687039", "e4bc8c252ae530063d4ad49377eb93f945d05e913c0a3e449f40a9183c9331be0621cc8d0bd9c5b4b6229cc1c04b5b05a524ef717cfe4b480b2c671f6abae6812a4f65757cead5c45e41bab6cb84e73ce41efce63a5b92789bb", "-5ca4a8c7f8778f18b423c5d93e0ead4948f1ccf3ed072eaeaaecd5192a9db38c54cf8c7062a672d303dd84c29f7c791c27de4d4b219fea32ce7c9a32d", .Okay}, + {.Add, "7ba20b06007eac36cd40bf3a7f4576075408448dcc813243823502b2fadb5177c2be8594b2db66b3882e0adf4771d794ea2c0c42378f219981d8d5a19a923bb92696355c17107b45348c14be9e8608517a52e230930368d3a5f64258bc83469222e0afc092daa57496628800e96f807a757128381602b411963c33280c05d372a7edfd5a30b2102f6e42529e0592b6c45da35807b3f0f4f954ea909052fb84ae4a83ba8515158e1a6420d5be581c37427825bcfa9704b825f6f3e9cb56cf3ddd7ab998f96469e368d6ac96f9a831bf2abfc847bf35e3984b65a3abaffca789e2edbb68591ff7d5423d3674a84a35e2d3c48f52364916dba99e0621e46d2f9a6819ad38c274661cf8c607c001e5db0c5b6906751624b38814ca01c0f4180251efec35820a9fdc5bc214d17c244bfe6fe63df1922c287a0e72a49cd01feb5e5783f000dfccbe17f779d4a998567119de4155d889c2b955da2852e1b3597633fd51d982ada09126b99be4783d3324c6dfd1db0fd0340339fa0db4a619b3873a2d4836965bcce46137960785c2b2735b77da70c515910e0869a8f9da291eb0b0cd0bfd43e1f66aa6184085befbddc828ae33a2a94ec7ab7306c2ddc18e59fb88fa8c676ba35b8f019c5298034d41b7ddbfb072f82b9c310b11f6f5aa96b6beb3d1e10753007be135988ed8610c95b864f8d51cb243e81dbe334121522c52f6d601e1", "ee31e196b4cad9f78961237b6ed0d7622d7635b7b6b0bad48fa66b6a832d58c1c8732bece52e48a02898bc696b593bd08b3beba56d923cdb8e392fd7e8798c4cb1396d4abf5c3c26cad30efd208d03bb3e5ad56d8010f83a98d574410900b843c892221678c4a0f3b3f1d9704ed87cc91514f02fd5451bcd53c13d0bbaaea3726a1c63ab0d1ec973185f2d37b3171d23c0c85cccc89ec0243bdb7d9dff9f5dee0735545356fd87d20b6bb1840db4ff2467690cd250c7ed74aeed357cbdefc8128f05dcec9ccc04f4db3476e08866bd2ef6fda3ae5954423baa10c561407c1462562899a20b0c156dff5e40779e5c6dbe7b6eca5e57d8e3cfc1cbc919e7cbd8e7bd321df7c40627cbfdb31ab351466edad2afe171e6f9347d2d8e92864951c7f8ed12b662fa8873712b57ebaffadaae12b02074b10bb7ec3f23d623b62406c2594f8a16746522c715b1564c6f00b944783cd84bf44781e630e85c04fee0822ad5490cd038c9247d53ab7abc0f4dc01ab76fffd535b959433339cde9de9ee5007d8a1d993b3cd7f78c79721a5ba2c6e19fad507a3060a94bd615831d640a480c50aa03617f74c7a49dc258a09280ce8421f2100f249e776ce421fd92506b387169fc0573c317d3d98e82a0d4550f241b495b296f2ad9f331b19070269f73c5f28377b07e91fc2b891904cedcb941dbc22b02068440c91676885a5f765aefe1306d", "169d3ec9cb549862e56a1e2b5ee164d69817e7a458331ed1811db6e1d7e08aa398b31b1819809af53b0c6c748b2cb13657567f7e7a5215e7510120579830bc805d7cfa2a6d66cb76bff5f23bbbf130c0cb8adb79e1314610e3ecbb699c583fed5eb72d1d70b9f46684a5461713847fd438a861867eb47cfdee9fd7033c6b476e5120a61053dd0d9a286a17fd5b8a9d3e81e6bb4d47c8fb51d90c60e2e529ae29c51b90ed86c1315ec6f8c874265d13666df8ec9cce7cca59aa5e11f4814bf05f009bf75e60135e85db1e10dda30987c59b6c5eb6d8f37da870fb471113d239e4543e401fb2b03eab03c94b51fe89250923ffe1c94a0efbf795fd1eafe54fb734fd6df56ba386c44c4c3badab537217b363bb656880bacbc91f790537a615419e8d948386d9a64cf33402967d446d91df8ee1206dd3431fab1c872f3d60f6519dd3f8af641233abe8f85ffe4c571d322b992b0d5b700d7c0593b3db85856b62827228f7dd95a4b36ef8ff2f9427286fa894b0fa569bc933d40ee740392261f2dc5c0b3f50821392f2280f7dd0e1622597a1e158fc16eb1b57f0f5d4682baf8d95ca7474375df6dbcde48179c7048f7325594b95dec49ea73a6ffbf20aa66c16bf66371171ea6d575e11aa42196c701daf9ce219ac70afe43a8861abd563279c4647f037f0ddd6121a7dd2fe94efa40bb001eb8c828e6d4a9c97bb1a2ade6b7324e", .Okay}, + {.Add, "-ea5f03bca86a203008300e7387d67cc6865bda267f6e81772b4b3359a88b05bcce79f5bcc6d4810d1fb5ac495cfd480a863c210d5ebacdcd3c7fe19d50e2744443e848710a2fde36f3878e6f90d6c59c81d1ab43e12a6f60fb04414cc92c83dce0c9d9200c4bc40fee0c24cf0b2b95e57fbde82036fe196d6ea86d424f70593136ca547eb652a828e7952031810f101a251663a618bb5de0b5f97806ac4f42b5241d7f5c60b9de775f5bd7b275ae1389fc6da0802c7bf82faffd3528f54fde31e092a2b8ea73beee3c05fe5d6f8a4b0ff4c4f0f9d64005b41dabc1d8b54cbd1a55cb3e1ca62e5529034f38f1eee0ac9badd9238b2a87a80b820f68f7859452738730d528b2f121458f5c977bb8adfb19e1d35aa46b38faaa872cd92a9257f64582cbdc5b538e0307f99255b15968081d2a498bb093120e2d4e0f5efa7893cd4dc87c93fd2375a5e71a2be097037d42810b77834263f7f05fdca503e1d16415649728249339288e3ab360c178a9b9a3f623357fac9a8bf7e9cfe6cc043e1f3b676582a03d0053210119899b59396675de49a238fda3eef8f83514ed93c38870acfee186290d4412f85440850eac7d31ac248e75952f237425afadab892ffacb682490ca7a611b5deca6f1b2441a6f3bb6887d3add0c8c43b798acc22fa2a59c2a6401e0d70abf06544fd996ba7ad10dd29234d114f48af29ceaf0030a60b97bb3", "8aa27c5cff2fc0c8ca4b8d932cdb98c29719613ce4fb7bd923cf05829a06dd36abab647a8ff67fba9f516a42435b892cce21a5a776bbae2b3de83320e4d8585e8c74248f29c6949a4b2141cb7f600c37075e494bb9e3fd9ba822cfa4bd50b20e00f62f70f73b173f0ff99cd93275145b429e56b39e53b11c8d8d78e6fb9a2d2296129da8b6eab6404181089f89487a2175845bb16a65c9112141ceb3aaf835ee8bbd0de9057238394bec105b2bcf7ca7788eab1b633f64c3f809c062d75216f1d84e2e99137372e901eb83b50c9b9a751166dea120c4a309b73fd3e930c3ae85ed5c70d15feec1c0a160dc6de5c4c892bc7932718e03f519c7091ceea02d2a6baf5da22c78e142eadcf94e02de033907688ab274df801232a2663542ac7d111904448f1c165842a8096db543b6d2bebfbbd80da6eeac1a4313c02e260fc3c5c927c619c585905cc31fe2242137b9ab68cd0003b0c3c5e3cef0602bfb9d04f36032e8833e268d7b7264b1f3511351386befd01ade51522348447917db23d06c08f7e46213bd97733e05cf5918f45b3702cd3898b12cf0c08cb52f13bb8235993adcb4c09f9cd3738cabf761aaaa19567114da44c87dd3bcbe11697f480dc152cfaf3cb8b9f8d0c61b77effc82e53294fad7b998cffdfe82e1df9c0b1ab0b7711498cf9be4ae775bdefe7b63119a4b3ac12362245a1bc4103e421ec42254571425", "-5fbc875fa93a5f673de480e05afae403ef4278e99a73059e077c2dd70e84288622ce914236de01528064420719a1beddb81a7b65e7ff1fa1fe97ae7c6c0a1be5b77423e1e069499ca8664ca41176b9657a7361f8274671c552e171a80bdbd1cedfd3a9af1510acd0de1287f5d8b6818a3d1f916c98aa6850e11af45b53d62c0ea0b7b6d5ff67f1e8a6141791f7c695f8af9207f4ae5594cf94b7a95301570cc6986071735b47a63e136fc75749de96e283def564c93c936bb7f374c61dfdc7400844741fd7004c053a1a7aa862eeb09ae35e1258b57b62aa666bedef84890e94686ecd4b463f936861ee5c84091be408f15ff1199c83b2f1bb064c08e5672807d7d332fc3a0fde5ab2634978daaac2127948a82f8bb8e877e4c6a3e7e5dae52c7e874d3f3d35c05ff024a06da295495d6e717e09a465f3ea3a4f30d468d00784a0b67a379de54923fa49bc75cbc397183e777f91a0320c90ec44d7e6345f2204643fa155129b12c84eaece2796686b8a336564ce4939d4a18b6db4291a4ecf5e6d9e3e2942bbadc313ba4240450b3edb7c69a04c76fe386b7fe5d9d84152d772222cc58970709f6ba84923640263db3b0fb430ccb14fb7679e442c4122397898755411c0684a97d12f01b5c1353ca6bbb0c3a20d0e8dc0d5b910b714f1ee2b15cb3244f25c47aa75515e33a8e085d3116ed2acbad8c6e25ea8d13ee80c62678e", .Okay}, + {.Add, "e2d3e31f8ffc8d725112b30e51e2ee565757827f305d23411da302675e9624233a5f698060a7a02e2f154dd4cf1444c72cf59b96f98bf66a614aa1a475e23e5b5ca72a3e79b9e1f83f8b91e5bcffe6ce8f43dfa7cc0dba84f0aa397a1ee36dd147526c2489d89fba2ef9e2add2b6849e853fc0dc68547ed94ca9ad4c0427276e131b2ba25f59c87384f8c017aeb5cf0cb71858e51362c8ee8e6ddb5d13ea4c8a581bd6dac66b5258c02a69b19c930e8b1e631c1af3b7b79043058baba905632830fdadf3b3ccd78b165d3adc25afe94e304ff3d3f697a5b0545ceaa037ab86a9e74f2edb505f4ecfe56ea8324e19ed82cd9048cb70d85ce36fc300dcbfc78a3548c241d6350d919f1a3159d74b3e77b6d6bb2a4a13ade05d592814e499ce38495a132b6ac00e66e0f39ef6a30081913aca88c34613a828f5d8dd02263633027288f36b81855c9a82a58abd2616a3b83f91e928eabd8aae33b7953961abe891fdd217df954fdb0d04ae17f243c5d72c33c7cd1d875b853627776772c1ed0d9757dd75514266dd082e97741964095b79893b82c70d437c2c64662c5de8e4e54d110a894bb67527aa6fee5143e93ba5ff1379ee6967483a0079a9cf4fda3db40e39608bc92ebde5185ee572202140f5f852bfd3f305a4ee41bf3e3c0feae5c0c59bec1ed60f3b08980626bfd553cc8d3349ea7927ed8c202d10422e781ba1059867", "f8d145ae805f8fb896c58fd78764ab8a157236088ee4a538e265d8aa9f6935cd14f6ca739f105421f83ab673ced49944c7216806b633866bcb5aff32285ea4516212e943fbd7a988562a4cc261fb2d985a76a8ec769ce295ea7aaf6baaef45a0af2e16e64524f873f09e042ad02867668b375beec287e78c0df59d4c77a1d17c450b7d449ed82a3c0cf74d8221f9ceacc471e45777cf5c99e686ef8f7e57f433464a0d2d8d9933e111986a772fd62f384131c7eb88cc8786cf4be536fb06cded1702fd7dcde98f6c216812542b6d8b7eb7f0c46efe4bcaf6656c46f78a00a8a9bf971b93c8ee26d2ed91ee822e67061e198597d2284fd43efa5556bc29ab9a79f05f09ca428bacf87b70a74fd02cb1d0f85b33b47ea98e4fba9d8f77ef4fb755b32fb4dd66d5efe6ac3fed2abd7ade25ddc1c8ff7cc7ab056c9b82a2f4f460136c58e2bc674afa4b17ad3c8f1adbb47f989ab6d74ecf2f823a965eb2c460ec22d345bb51f1bc08e92182bcc8c144654197dd596460e1b97b6bdea9bd3d723858212c2c904016cf9ad83b2acfc332ac32bd3c84dac0d20ef6029e49cf2726695fe39f2c6ecd30b7473bf7f3d38b8eb4eb2209867d0a701d163b82dcd88f46b582031014d8969732953bcafd1d45cc457bbc5b528c107be1873fb9b0451f4c2b95e9fdfa073280cd69a550ee7478af9c2864055d94617f9e0fc32452daf11217cd", "1dba528ce105c1d2ae7d842e5d94799e06cc9b887bf41c87a0008db11fdff59f04f5633f3ffb7f450275004489de8de0bf417039dafbf7cd62ca5a0d69e40e2acbeba138275918b8095b5dea81efb1466e9ba889442aa9d1adb24e8e5c9d2b371f680830acefd982e1f97e6d8a2deec0510771ccb2adc66655a9f4a987bc8f8ea5826a8e6fe31f2af91f00d99d0af9db97b8a3d3c8b32258874f4caec924240bd9e65e40854048639d1c2d428cc693dc35f94e4067c843f17125170e2a40c31154800ab7181b666f737c54d30511d74cce840b842f4e370a6b9c93197c1ac2f53a6e64a6f194d75a2d30096b47c80f3a0e715e09d992831226a185798e97324af39214ba077993e9795a201271b6b2987cf165dfe92576ead13c5a45c891def9f0d42e04826e456c79fdee3cdbdfc6f60a84a8c45906fd3fb457884c92b276285f54c4e3deca794cdbd37f9b5317f6cbf2a83dfc20c59ddb5f22b981470497e20a55d9ae7419715edcf9aaf0c871b91755faa76ebbc66efa2e3461c7f2a7fcfaffea17dd2a6f3d7c96faf4433cc8e25bbf8bf4be8044e3b5a68caa7b80c0bb670ee287825425861b72a4937bcc734b3fe9bf7efe452aa1d8fe5522cb2ccfac3bb639bde07547c4af4213d1d3e86c23dce7c2f4591b56a23467df5c030050cf131d61cd0166d89656fcc10c3c8453ccf724e7e8581ed9fcb200552caf69217b034", .Okay}, + {.Add, "5b39993dbcc14be9a36918b4bf677d7f3aee1f8c54c093074355ed04e76d1206241b28466ff2b248f23460c86ebc50f16501f1a6d55f173eb7cf6f068941e3b1108dbd677b1a84025e9c9061fad4bd4b821b08f6509459ebf773b27b81caa313678be22912f3a79a387db79ddbf689cd0a7c15f1100e206f2f962a11531b6b7e88d09cef51b0f9552ea6e7c6e75c3ceab493300101a091fb2857bac7c0bf99a3bb64e2da8a5d9005328ded8788595d185c16fb7db5400bf0b656af8498516b6369a61a3fe65c22d310bf3c1b40a8bf2e9fe45527e84b67305b8ee17d5eb217606630bdbcf0d0726ea55fef31f96e3c71b58743e0042da1fe8e1e923d3b38e4f4bc66da55bd4472c4be5bae678b2456418470d5fb64a1d56e3a7abea9fc40836b8989a541b6643fc448d827fc1810e116e8cdf4f0388a57a95e160cc3dbf10cc1506ac7d84748383aae600ecd9e35339007a0482c35cbc2369354471454b3a9dada4223f03d0ac9ec7e7dad8179ce8bb35090f407afd9a37d49087e9bf762d208d42d65ed7847a7fcd76cd938c949ed158d2bb1eea3d687ba93bfc123a95f7d9c2de2dbc4a9824770da2005987cb1b4fdabb147011b51035b159f9b49b1272f9bf7a2d2ac7c247ec76c1c580025eb647719ee2859cd44df86440a01d7f29828b9846e063a8ec792b8848403451726edce431d80cc947fdce978e60c0db3495456", "87b86efd52e81fd9e53749122387aeedca091115d7b6e6f99dc41c3d53cf2c70ea444516d2a32d3ae04d81a9fa1c1f78bc029ae7670d0db657f9643ee2102b4470d4ffccd9198a08efb024421b78398c3456c16ab9a12bfdc00f79a91c0aaf08f6bbda34e8f5d003243c6f10bcf8fe87702caae141c92374f6b2b4163480e2618a633f3f000d7955b29ca3662ca34365f6717110c1998b1474bd1fd1234d9f6d86ea21e32430b63a6fa6e686dca6399f3678ed04b5e16989f5458b66b1f6786d0acea531cd91c414c78d664c696e65b43ecf746c0bac4e06c20bd129b00a64c5857728e4f4cd535856a630fca7d413e737bc4b1410e16cd674d961115e7d20c7847adf6fc37b0adea3958fcb616fcfad3c8c4cc2e96dba1fbf3e221482f737354aaaacbfb8a593d6d6788f90bf15b5464a4aa7ad716cf31ec45ffbdbbde6e852064a5cec6367e7ee3b2e25d6b2f74d7ca0f43c027730d3d27aa704823f04b41524265f5a750dcd085a2e2fb9f4d2c20752e0c5ec45fd924f1ad7f04d8a68183fc06d7295450a94ce9f9fed68db29c07e277768592553de744eb96ec93d2768af652e1bedfea2160f88d9911ceda392ba0e9b82afde580ecd28de42838b521f9cb486a3d49549bbc68fa58d7d07a8e84fca5321bc8dfbcf7494499f49e509d364b22aa14d4133d1ad65c04973cd9429ee2d932a122be9a6a1160d60578d52c43e", "e2f2083b0fa96bc388a061c6e2ef2c6d04f730a22c777a00e11a09423b3c3e770e5f6d5d4295df83d281e27268d8706a21048c8e3c6c24f50fc8d3456b520ef58162bd3454340e0b4e4cb4a4164cf6d7b671ca610a3585e9b7832c249dd5521c5e47bc5dfbe9779d5cba26ae98ef88547aa8c0d251d743e42648de27879c4de01333dc2e51be72aae1438b2d13ff8050ab04a111c33a1d0f9d14da98e40d3911424f04bdae8e463fa234d40e64ff96b7928fe8826b21757aab9c3aeb4a47e3d07474bf71b3ede6e7d84ca267aa1724e2deb3c993f3f7b5371d9ab2a70ebc7c25eba7e6a1e59dc5c6fc06202ea1425058ed438ef4150f0ed502f7f34e99b605bc40e1b9c580bf7da361f13e32ec9425eec0fd22be4e0f8f8df9b8e0be7f37baa0d43452016f09d39b1f50b78cd726965d33189c9da9f74ac82276089f99d7f51356b524c4aab02028e98e34a4512c810ca894842eacfc96090dfb4b9693b85deffe68834ab21896f4d8abdd3b6ea14dbaa371b9f3f5d735cc63e06ee981caea48949ad882bd523ccb770cc6a1a473ad93b4a31a47c92a662ee2792fece686e64b9310f7b2a8245d8062f996b56a5547b7ba4cc9b0f9a912283e7dddcd3c794f38ac297681116e3a8dfbc1e57d2d944cc6e4414a165b40aefad853a121d7a1fc1e3698a787cffb6465ea444cb8e4bb17bc70b0aadec069838a8ef36c65409c1894", .Okay}, + {.Add, "-6fe86391bfae7ec2fccf1721c62074ef635ec35c4fb5fe5199b790678b6cbc858d895ee6be739ec957514779d88563147881e081c0cca0ba129585268c681003c5c64f6619cddd217bd02da012e908378e4a2438500b32d92343f312447668755b01a39b790f6bd3267cd978bcf0c7089b49dc2757eb2a29e58b63f3315ab994747dfc16022948e62667967d86753e8357bed88752c6ac448943066cb614b1694332b4aa471e529b3bd8872f5aee664351a485b62bbf52692ba27e6e011340441455bb4c7912c476f5d2c6233e8b15ab525aabd7b1471cb9f79d80770228d3cf449c3c5d9d9ec2675b13bdc5e5a302115934b5d9c340dd24f9c4a14fe4091b49ba859f4a2dbea43d116ebe44354b9e9c66088d00909e1356802ccc61f599053eb7d95c6c33f073f8cc61be3cdc0bd23510d78adeaa058f2df0fb87dc1d25847ac93b39eb440aba9187d1e008b17e719782c0eb50c7ba32fb711eaa1f24c234f24affb2cd12cc2b17b99dc917c929ebc0fcad27bfc85dbb05012159681335840a487ebf2281520195194d46b85b226006d6374ccbf4bbdb700636d7fb9b66861e331f527759304a7da081ed1f654b154ecf323ad0bd89b86c850460e315c7fc1ec0b72f03eb86260f7843a1375785a6d152936f754276bf133c44f77051750c8538d6d4a3d515fb507f42d5024e19baf6a7b166b7a67dc16ae0f788706f05599d", "847d7aa4e7431ef071cf506a3d411847b9e8eb7fa2dda437025e16b86092da2bae7a6ddcf042c17e4e424170ca09bad5229f33599415218778df945f0a8eb35a2749c9466cc6cb51a343f4ba9df8f719fb9d0840f3fe082853465ef83dde0feeb1a16de214d7367a0bf09ba3c90919a5df7b967b7bc2167327cba56cb5c900bd3bc3a066890510aa31f57ca06224e475e3c0dc4b7f29ab78d58df2d4caf41ad505af53424ded45c315b3370b280f3357cb9f7a98f1571d5b91e6ba15f209e33478adab66f0b869b83e8fc51a28dfb6d4b2cc58e9e588e808d7efee64431b4cf8777ee9b0e021967acd084108c4ad4f2e5668540368658069be001e528a5c01fa5802b4c1edf427b3b49f17a1c5ee4dfa67f2a012c39a8e81cd05c1751b6c77ee43ae038223586fd04e7feaec95a44ec9ec23438d72f0847362abfed4ba47b94d70c2ff606bd366a1d60af3225b6232dbead95f029eec464d15fc30009dabb108b2a5ef12539e4dc83b9dc2d8510d622689e50a8a0a4f5822099822bf31f861da62718909fcbc64adef6b7556430f7239de802ab801e4922b21d3b838b0e6a970cb42dbf27f58a908e11acf5d5e10073fbdd55c8e845ad87b55c9861422fa74d6bb702491979f36b850d6ad3b1c765881d8a39ec1005f0d1f19bcf9d657b5f8b54f947992a08ed38ccb6f0007c9caeb0959687da40c07924c51d4e742a6b9f385", "149517132794a02d750039487720a358568a28235327a5e568a68650d5261da620f10ef631cf22b4f6f0f9f6f18457c0aa1d52d7d34880cd664a0f387e26a356618379e052f8ee302773c71a8b0feee26d52e408a3f2d54f30026be5f967a779569fca469bc7caa6e573c22b0c18529d4431ba5423d6ec4942404179846e4728c745a45086dbc7c40b8de622dbafa5f28c0203c42c62ff344c4aec6814df696bc27c9e9806cef327d9daafdbcd20cd1479faf4e2c597caf266443ba7f0f6a2f06457f01a77a5a54148bcfef6ea54a1296071ad123441cb4ee0526ded40f2792932e2ad534282d41371f48342df0a4d1cfd339e29a524a344c43b7d02a652e6b09d7d1577c0358376a330595d90a2af5e01ea131232fc7b2b4cd8f51325d372af8bd4a715ef67fbd7821e2cafb9987c94db4bb8aec8eaf54571b076f89d2234d2a787c57527c8ac104e391319a9e3c144681873b1d7321351a4dd85e178e97c1667a63c4540d222b081fff9c087e376658d37e2ca41f19d1d0876c9571ec2ddd019f2c9e77b6a6318d61e2e9de7ed12330848ddec0d28b6bb1b9ce03d158023529823897b26285e8b4098e23df8c4f1f0eea321bdc6d1200ed0c525310d3278b7fab8f58dac1910a8d8930c03c4f0b1b086102f4bbde84e0bdd7802660640ec3016bda4eecb78d83c4c2c2b057bb13012b1b716ec6589d0e170dd5ed237b499e8", .Okay}, + {.Add, "3c0bde6e000598876134f2460b09b2c3bee498553863a9bce6275f1993356b643911f3d2b810b47b547f537ca76cebe316e93d35c61a53a01dd5f1df93e7cbfb7a1aa69308e45654a4edd5e285ed1796bf7d08f73a0e2fbc90cfe37cd504ef1625fd54836865cc67f221c064d5b0ae1b376c1e531c4a4960dcf3960acdedd4eeeaeee9bbdc19cf34cf5594e1fe7b27beac3e948632f88544076877964d4f5522ea764385f49da9cb9456d403d98d8cdbcd10c03fde65459996799ae89a4c332e48a5fd23f43630ff30837ada4c37bbe8bb551596c50472f7c0e5522ac25a77e3bd31b79894c55a0e36ccb51c924636f8bab7f78bb4d7ca56f42da349861c4b8d9d95304ccb01b2cd9d3390bbaba94f0042d6a94015b489059e1d71a18cb06f86d7aacccb29a5082934d0d0a002914bdeb542dd9284d029aa5f04095d0a15b1d28ac420cf80496bc7e6dd87204e0774e067c5362b3ff343d553091830f0cd85554e6feeba57134ac3dfcc07ee56ff4299a1af27490311dc7d586d743fc6fce806d499c21844c025b8aaf638d2c74b751836cea5bf131a985c7f30e948fb7e9882c66fd8ff06e84a07cf861fd1820d47a02fed9346171224a0a15e03bbbd4a9a3e315ece1bcb1345bc023dc78e48f3ef274086209c2edc319e725d108c12fd9171dc44555dca3d412c0957b35cd2518267612cdfd91cd054c82df6fec2305cbb3e", "7c1eaaecd09330ebf0d2651ef300fa2b0d24624e03f20bc6bb80ddc84859bbc2d786e1a20990b8d586fdbef3d7f1f16d30cd2ac953f7398af2a95bc7d3cd0e2b216c10badc1a6530039708514debb37cc2bd57f40e46ca246002b0841e4061367c78e5c5ad52337bff459024c4a850be7f49f1216082ed620a53f04a9a5f791e2cfea460ec5bb71379022a8c42cfeb84025bf6ce34537ee0b387924654a16dab0333ce05029a0c0de6ba02aabbbbe0cd0e986db9c52cf4c78b8284ea2c4454a2ef1f877666c8a2f2a695552085bd6b3d90bd8f5264592605f6e7df72aa7204ae429294a8d8155bee553b04fde21761c9aa5395a3903f5e41b6766bb655d75557839a0b0d31b15ae16c7fe59d36cd6b1d9d6c36d2c9ba42f70110f3229f47feba841c22e2465b48f3dcc404c6c5ca8c2ae0b16d22dc3d9860a69ef524621c00f516f759242d0056685ba7698a9fb6fa66ca37780c6a7a258d04853ffcef57d8e237ca0cadd7f0b504a87f0ddbbab480b2e698ec92bb160bab136f1633c182e8fd09da0ac557c2cb88ea38631d8b79503200aa89c15fd859ad241e65d2766fbd45715a6faaf4bccd054a62f8f6b351a18f7488ef55d7229304495323539b8eccb7be1143448aa0ac570c2f362023c8618d35926568c03a0413b9b0dd92fa9a91ea8ca0a84a31373fcc1d39558b3ad69efc2f532d7e1d1e019ef88ecb1f76f02e1", "43cdc91ccd0ecb9620421897fa39c2666fb6de7a18a2ca7951df6cf617bb0720668a61ecd8a9c008acef2f6be4ec0af9e9f60fe25b59c738cd00879c11249cde2c31679eb6a5fca7a52746679acbd2ce8ba8de767af29c5ed6d00e8516e8f5298dc4e2dfc33aef9fb216196721fb33271f60bd6532527836fd98d50f7793cc80cdbed401eadf8aa606e5b78ac2a82676ec6453f3163dbd3212a0f0bab2996bfd9aa9806644c74a8c72c2742e85494ae89dfa471b7ab814e60f31c3373d1078787797f59b5aa2bb2e5aecd02c5493929c9460ee8beb4a05582053d021ed01982ea15ae0e32246afcd1c20656c7067ad15555d30e5eddbc03b0f950a04eb79c0e315ced0fd9e1cc87bb3fb8f157f1625b21cad6cad42502d350e2e80d3b6a4ef727fec8ef94e0abcb8729d10ec6eedf4a1634df464b2940330696df8af503771e1dc339661c319712e6c97fdb8f802e486d468adac069ae62e23516c30bfc302e371ec8f85349256142a53f8cc12aa8aa4d018b6122ec33d3809a465a303151696a53762c49a3c52713999bf04a0030a1b56d94e5b29181df75172cfa622e594571d857ff9b63416d8242c4f60ed4261b92736223b74844dd0e5f335f0f7038709ad3fe25013bd50817300baf04b30754013df46f2badfd1dfadf81e6542a73a90850e5fe26d50b528cb2b48b585feec57242212b0fea234e21d7feb7427cbbe1f", .Okay}, + {.Add, "4c7ab89fca4650a1cd0ada6eda760fc785da25448fe7749b810874c123e2b973e6a64c0b11d311bfc1ab6350cf957a0de1b2a01b29141d8ff187c7bcf6b99d85e539c4ec6d794fc9261c4ff99ab247bb9985168a84d5731d9f82e64bd0ad61ca422de2a299508d1bf8283fa20832e968b876db996850b0a0dc37e47723f59cefdf385232a2faf6f89d96552c4c3dfe352f5ec194b1321703fa8eea3af4a15a226ff34cdb55435633846b04828c84fa3f99236b229fcb85d9ae2cf1704feb98e15afe01271c1d5db36f5291b8d15de90064a86c44c9c04d540c29b00430ce446f7a08c3bb36de78d2af5b0634358aa7f184be10b25af91402069e8ce66d1fc0d345adf272d6fc3ad40f7bd096500edc28ec43fc0817773316159750d0cd67c610912f979eceb3b52d26c500f0833c56e1435e02b68e76e4f4ddfdecff835929d509a984e4346f8d7e5644959e387f12b36a9b8d60c99c51fcef85fa398d5edf0a247cde694618612652a632a2dd6c66269121bee65e662a68f81beb4ee58173eaa59f6716d8c1a11814e9bce96f5c8343f08c4e751b68bb0fef3adf78eba56f60b859e05d204969d05661e2c19a277b767489d8564a1496fa2eb1d13b388596d800a38110d16182a6907e85971babf906645be27742f987d417c193d5e14fbccd1fddf55c1bc2c0829fd8f513dbb88dddd3fa185ce5ffd76f6105a14c6b0d8558", "d52b8be41be4ef9fc00e40264036a2a41be4131e4bb3ce18a28601b7c947014114e602ccef4512de27cd0d912e53f64a070700935f5206718ae2f19ccd93a6ff63d360334237ff78a8609ffee29e1a0632194c236a760a2a1a2cab65dd75cc74864ddcbe5a8f21a5dd5ee7e8655169e23195f1ae22a9d02c1abe402eff3d3c4f4eb873c205ea9bc1269c3d0c4b599262eb66acd5700fe2ac35af573080fedcac3a01f3da627f6f9d1adc862e020b2fcc1e9000df24132a524a61537ce075172eef16906443e84dbd2b428402e0973e6685809cfb23f5724e45c871eefe7dfb2ec4524eea23d7ae3ab31e723e3e41758b3923000f505e5273bd83a6ed68cbf3066b8b873d6d1117f6e791b9e3ecc1b4e1d1ad01472b9d38cbbb3f0fc47f229c53c0ed8c639ec7d1401c681fe077e522f34905082a85734173851d2dcf78892cedf70127297ae3da6fb98c89e8520b3a118fc33327457bcb0e354aec86d12062b0e35d134402aa50b2e59afce4a2b17fea0c31c60468ed80a4f14c708593661dbbe00b7a1a8236fec2a028172da96003d02c4aed011b51651c23d9e534e776365950d2ef14b5ac2c30a52b10c37b16edb2387d61741a2a99a1302549fb9d76d8ac461201dba7e9b6dc8cb08bc30d991b597730c456a577e7e48a57f6293f2795bfa863ce5799497260606b8942db541268e44f2dff9024c515ed615b85e9aea784", "121a64483e62b40418d191a951aacb26ba1be3862db9b42b4238e7678ed29bab4fb8c4ed80118249de97870e1fde97057e8b9a0ae886624017c6ab959c44d4485490d251fafb14f41ce7ceff87d5061c1cb9e62adef4b7d47b9af91b1ae232e3ec87bbf60f3dfaec1d587278a6d84534aea0ccd478afa80ccf6f624a62332d93f2df0c5f4a8e592b9c4329238979790981ac56e6a2141f9b0303e416b75a036cea9f540b5b7c2c5d09f478ab08e902a0bb7b36c01c3deb02bf88e44ed3060b0104a14918b6005ab709a9515bbb1f52766ea29093fedb5bfa251f221f32f4c3f9e3e5b12a55ab6270d6279787273cc1d7cbde110c1ab576675c42233d3d5ebb3d9b13979b0440d52caf70d8a7a3cd0910abdf0fd4f43146be1d0d660954c8a6264521d24026d7b866d432d20d0fb2179d48c630ae113ea2668631b1acefbe256c300aaac0daf5367ee0fd11f868a8a4cc4fa5ec0880f181d0b24d0e6c05e7f41bb07d9f1ad48c2b1d938412f87801de6109d5384eac753ab0de9685bd478e791a685aae1315af89fdab511d41718bc87141cd73b7636ba202c1314c4add31ba5ba092ccf71d5f59600fb8cf385153e6928ad0739ca643f309b5ed71b36d5fc6f8446b582ec794b39831d2f115a2945145fdb8ca6cde8716fb8a21989ff2077528cc841c3b3b50c32e300447e56b70ca046b849465c76249c854e66fcd254bc2cdc", .Okay}, + {.Add, "9180ed658f45aefc914c814467dd2d2052a928245c7147b790127327659a366b5594f3b4defbb50934b5a1ec295496f110da223c555f996ef27c5f46081fa80993b8da9f6f8838c6fe013f3cf76619af740b3eadde7df314db48a6ebc4f1950b173b5bfe8b0789fbfda8848a783222c5cd90650de33e39499914e2193e8560e91a91126819e5609e4ab4a7be37852690b98264602a842f3815dcfed38f13e89a72c85e0b179c1c349e9339c5290941d2ab9403184c54e2c0c4ae9371fb1807463547743f458fac8e6a5ea613c4e5efa41a4e9c28aee343093c9fb002cdbc246083216238eae4172d3ae4f5305c05c7f6af203dc30b04f469345fc5b5da3cc9d4862f83bf7ef6cea900484928dd061fd7e1f259548082b4454839f69e6b6e5535d827e79ab57c628e7d546a8327eea781a5a98a5aa50223dc75ead4677d68bc70f39c6ae1e7056ff59e3e18b73b8813c37be3da8efdea436aa0471e459771f1f29ae91e55e88e743d8d91fea64579a5cb9d123907fb5d80e5cc04f7741ee07cee368afbcc738829622113234d8d066778dece94d7924aeffcb9d4abaa382f35a069989c9d2ddb03491df76f867fcf6c4d84c55e6c4b248c8af361e3d0b74f9964f09c5ecb3d6788de9331b4bbc063197a830ea3ad14f517f29860e4d5534bf9b53577dc6a47b8d37a769c9225eb8c896b021a789167189853256890784baf1142", "81461d4de1f983adf4cdd01293c51e38a248a681b996f0109d648a525dd755bc41f759e65036dfff04f1c2851a4d514cd265a4b10e857801a49bf350b966edbd890f05465aec0542086073e31875bc9529c08b159c7211238ec3aedc83291cc08eb682fbed15a55ff256cfc49e4f60e75d11823571659f316158505373de5357159161b8a7d4f19a0ab26c9b827f1ef4ae6d867882d3df27291122b47bbf18b8613677184ed7eb7da1ef352c08ea75926eed838adcabc9b8905c9832abcaa68e872258aa7a0c36722a45e60cd777593968bf271a56d5f8a4244ac29115ca196a48f78c2e96b1c620727a141e1261257dd3d142db23039fc720a5d5f02ec190059e4c52481880e874990128a09ee2cd3b82dff9246406ab58e9c1c01a9df233c253546977cf08b6f8b18a00fe91e3df12e2141c1f6a1e189a954c54cfa4c60223bd376f2f8b203f9ae3849db9539b60d697b9f976dd5fe4f501d149c9c3b2da635e349ffd16e31d9de2b824fd65eaad9efe70a0120bc2619bc3891723cb232e28a4ffe257a6de5570349cd910b5cd11f757ca4ea05830673c012c9413c38ee0f9427da3e8b80e573e1fa4bb7a4a3ed0144c2b568c9fd6748980b86e9599fb25275dcc25e17722572c2ed2eea3d4a85de10b67a9865295185e6a4f69b94b5257736b7303d2e638c720be3da708916512db86eb358bf4f6c6144f476e9c7984443d", "112c70ab3713f32aa861a5156fba24b58f4f1cea6160837c82d76fd79c3718c27978c4d9b2f32950839a7647143a1e83de33fc6ed63e5117097185296c18695c71cc7dfe5ca743e090661b3200fdbd6449dcbc9c37af004386a0c55c8481ab1cba5f1defa781d2f5befff544f168183ad2aa1e74354a3d87afa6d326cb263b44030227420c1ba523855671459ba04458567efead8ad580e5f3eee21880ad30152d3fed523667407b240826ef131f3b7651a8186a32900ac79550b2ba4a6e2add4bc69cce9bf9be30094a48c209c5d48dd830dc34305b93bad60ea7293e3863dcacc18ee678195dd4dad5f094e6e66ed7482f1809e2e08943055059ba608fe59da247bd6079777b71d994971c97be8ed1364d25278e4895f9e31fbb6b9096088f82b7c5112848519872ede6b81b9d2869487bda67a0f203c770b372937222ebe94b0d3da117225af9081c2b6708f23749a139dd405db4a285fa218680f5b24cc55f91dbe52ff7191db704a23a3ab64536a9b82d91a071fe2818f8e0e97ea03ab16db8ade241a667ed255affc5e42d379703698e377ea7b5738bb013fbdfbbe1699ac164085e5e95a873d9c2b00ca0e3c61d0f0b4f8eafb0114741a5266514abe8c4e6884acb489e00ac204a35f950b775b8e764d33678a305102b04e8e9e9e5128a0eae03d2df19a9b34da392e7cf19c468905ae1d5c0f5e6774afff14c533557f", .Okay}, + {.Add, "cf3bc8ed0fa52533dedeaecac0cf7f9e0129fe87c3920303055be680a4edd7befc3913582c2b5e7eeaad13ea62ae2c122a4d007d320ed0643957394518c52900d2fc7076ba083c04180396461baf1e8c46d717fc5807bdb147d5fed85aec5dc676c24c5e335713035d303428a2da58b2cc94fea203a250770bfd913071271916f4ba99f30cf612feafa48d71ce9306468b92e14f153af3a4339741f90e4e7343616b7f05819dd286e52e7de775e13d4a3b52d82726f6ad51bd2243b007af9a763213080e9068633e1cdee84b09b083ae7b427df690ce278fca163bc15e1c07a6d915d7f5815091dfef8744e638b7a4cd2b57e14053c4170797a3e6bcc872906106a2d027041185344694fcea03dc65209e8bee96dd3da9d2f1ab2a169f4116b6d71b917f2613acf9b38a39d5285105d430f66f8b1c98d2f988a37557622d49d3ad0ca3f4d9d338e801e0f60b7ae2130d8db49b6d0802269b5557f19c6c05dbfe1c62d5b12a4dc19bdbf17438e706bee2306f7dea0f23439eeca8e66b12cac05a5da4d56e030c1f1f16fbd0b014968ef5a59f42924df875c24dbb999e453a14fae3452a0a703a4fb02424e542bb0d405eb0de4ceeb6e9a8d74f89b4dd0469ba07ee18238828fb4f1c78e467cc9933b4149d22694f29cc05d8c959c6cca17f2812080046035ec101729aa8121d72fe9e411ac4c1f2c99a09e7a49424aebc3f4602", "5aef8b79a4ded6476611f269305528e182b7cea456162aef8e271c53f4d8599a7573c9820d462fc9ed12fa0c199d439ac4fd5b8a3171be2a890ee469240ce5f9f87bb78b7b95d324a0fc460ac1c7a63c7ff350d361f0c439f65be2eab0faa8353439afa69c0a7b58fd7c8af5cf3e65382453fcecd8c093efe68de68d02dc8f8493f76140373f8fbe77086a80efc1506554499402f3ed7e56aa545fcaff880c6e47e494f080a70f039008d798c1ff0308cf4a0316ede3d1b3a17471db662fa3b53dd6aa8d194feb927d728e447a9330301658a6894aca30ef7234d8ce6a66bdfd57d529ed893e0803375cd670921264b8040c0c630f83f79ef4ce926f3d7e7e3a0f4e5a051e5a98467149ccf437bd6f728821cb83e9a8a528438c0ae519a274e05d9f1d2fbbc55c049aff97a2a6f85d3cd9df3ecd47f66ad9d2d290a334e820a61fe695e1aea5749dc877a052a4dcb01fe0516e986f1c2607c37c0bd03f3857b03958d56af7677c9310a42c1507de002a32f44967e0d4ee9ee92a012994bc1e28d0c2026c6d581325fa518a42e1896881a90b15e94edfcaa0515cc01a6506d5197c4d2548e8365a19c4e3a249e1b5e4bef9b7ee8d40e942ca30f987babda5bef43b299682db3d5da48cf8510c1aaa70bd943deed6f7f30fc2a170213a23edac02aeb2f31fd97baea6e3a312b089eda69d05c9ca26230ac30a4ef9c0b56eb4cae3", "12a2b5466b483fb7b44f0a133f124a87f83e1cd2c19a82df2938302d499c6315971acdcda39718e48d7c00df67c4b6facef4a5c0763808e8ec2661dae3cd20efacb782802359e0f28b8ffdc50dd76c4c8c6ca68cfb9f881eb3e31e1c30be705fbaafbfc04cf618e5c5aacbf1e7218bdeaf0e8fb8edc62e466f28b77bd7403a89b88b1fb334435a2bd26acf7f2be5456abdfdc7552092871faddeba1c40dd67fb1a95013f60244e18a7537558037e040530a9cdb3e14da7f055e96b58b6ddf3e2b6fe9b29ba9b84ed09a51768f8443b3de919b247fdb98587f3c4b148fc882c5a430eb01e30a8e99e326e41b56caca09852f63eda363480ea68c72792c05f10e9b15f12a2c226c1d7ab7dec9de3b99d49326adba1ac6e64efb353734fbb8e38b9734baaeaee1d908fe4e89d177cf4963110ad5ae58648f3dd35b7605fa97156a79ccf339d68878ad85ca58965e1fbec32d6e060a05771e4ca318d3fd6cab3e33ae55bbab1c21b53e2eec95a04deee4bf0c6363c751eff8323dd5d2e794a786de832e66d7da70643245114d5af2f61ff7774eaa587b9cd840629f1859b8aa40ea145f924f535870a9c9e908878c9cc3251daa963b7bf7d2eba180833c97c20f78fc2941ba0b0438acc105dcb8d8b3de24d23160582621bf159b6ac9e806c56cd414b6b33923383cb0197e4b24cdfcec44de208e8c18eca4ccf1f38de5642af410e5", .Okay}, + {.Add, "-6e752404d704c93ba8895b8faa357f90728cf101ff1f82ff43f797e90007b6ace26c74dc0586a002d2d01345c006688d1a247c91a40225b39631b272fdfadf0c4d8cacd9c7c3dfcf7d4822f537ef412331f20fc968bd0d44886329f4424dbebcdaeb90d7bd5d9c4f2221abca0f5d2ea23f72dab79970ecd9a06bff789f55a791cc53fc80fb453f446812a28eccf4111d21a62c70bebb635cf07a6b0c1c9f0873b26d0744073337641bbdc09c5d602875abd5710ea0ed9ede9128d0e297e943f34db2dfa371b2096a03ee0eb31c1158a2a84e09c0280926091db8572ecc436b43d81e790b849c96b3c92b2b3cc2f04defbac78db030b3c1977fd6b5a279fdddb975ad38ed0cf00e165581d46a47d4eb1274a51e8e783e255d20a98b9f35681e82379774615ee62bf8521596116bb4f8a64c30608ad852985902be1a94aef00addce0a164832ad654733cc3ebc283dd90845009f2e2844c18aae32fa7c25fb88fc359aa3ba0a1546d1e8f93536d6c1f9f4dd4514d835a394f3d0ed38c22c58b59c23c22456db6422e4fbb1b3c857382405d23e62be3a4de735781f6ab8f394f7700956f1231caea7e3f0cd22f69168f83c3a22f16be7916d96da42412656b54c269cc05d7d8a22cd36e550ef6abd525a419595b65181a3c944de28a1777516fe714a599dce371a04ea77b8cd54d7f4ebc76ff0010e64600e25af12afdd099c2ea6", "13e4db1d2a07fbced26259e99ed0b98562f74cf18e63ecc04f3edbaa0cc1fd37be8eae18f82520afd103959bd8ddfa6be569b8621d2b0a15c648be257f0b09cf6e2527a193ce803a87fe71490289d8517d530342cac347ad35d5a8a232d142dbfcdef85a858c220a0a318802737a42bf4335a2528cff7239c873cd672fb767b4c155a53aed1290d5b0a69680519ed7709b743f012092316421db506e0b48e55c75a69482d8743ac0fc7a4f8bee86f03b982208ba55075a7d29d19769ca20ce06d65b07d87d1ab48bf4591692f8db4bfc07eed1dcfad611245a52de3a83bcac270235f2597dfa600ef7fb83bf90fb00e15f350e0925b3cceca083e8333deff79bf303aecb9f344aa65442662af99b9c7d2c8988da5f360144a6d1217b3d0d60bda8c43be47118d7a7ea1a95e206dc2560d41b4903af67ebca4cefffc633fbd58d81444ae33cb4153580b5ecb0aba36d1245b0151e70c64f73b29a5375a92917ccdf0aedb1cd12618b77a77a69003f8d4bb43a1e872a5454aae0679598c53adc400e600ff142849b81797183a5dc23e62d1cb65a76bf50eb39c32db0251b17b31d94afd81c690956fb48bd5260419736f5842f06e8114b9a91fed5c41789c36913ae6982e2f0daed3f1b9dc78bfdff4846b414eec7613db216655c0d6c1331177abaad40d936d11cd0994e99ff34344b0bb3fb10d695567ce84c1c4445b4869ef7", "-5a9048e7acfccd6cd62701a60b64c60b0f95a41070bb963ef4b8bc3ef345b97523ddc6c30d617f5301cc7da9e7286e2134bac42f86d71b9dcfe8f44d7eefd53cdf67853833f55f94f549b1ac356568d1b49f0c869df9c597528d81520f7c7be0de0c987d37d17a4517f023c79be2ebe2fc3d38650c717a9fd7f832116f9e3fdd0afe57460e32ae6eb76c0c0e7b5539ac8631ed6f9e2931f8ce9f1a9e115623173cc672c12ebefca31f4371106ed9383a13b368544be6446167573978cdc875ec7757d7caf49754de0f94f82023360ca6a05f37e32d3314e4c36578f44886bf1cd5e886b206a236a4d12fa77d31f54d0e5b927fa70afff4aadf52cd6f3c0de61d82a98a216dbbc370013f6e3f4e394e95481b95b41908241879d86a23f85abdc48ed3387cedcd545067fb002f64d8d3457815178728eaac8eb5ce1ace7af435504cc5cb64f5f95011b316520b7c9a6bf5ff508a0fb77e7216fb98a7067cd2712f568fb6083d02e5467151bacdd6826ca9290af6510b4f4048f085a329671dd95c1562146598df8763824030227b143dd8b58808477afcfbfbb4f1ba93d87d445274a71906b3a550e8a80fd0964fd1c146b5f3ea83d645d304db6c7d0eccf1e312ee56da9a9947dff7c9b327debf5311fae180c78a2066172e78cc940b61e5e6f68fac5cf50048e819de6a3355a3c0a0bbbbf4f037cf09913d62f66b9755158faf", .Okay}, + {.Add, "54c3de28a345dde281ea9b0b38c8839e6d604f00c825aa79d3a7bea73e9ccd4fa32f1d37b7c7efd8fb9ee4a7f2ca2ae0875adb7d2e9a7f55b2de43e8c1cf7a85172e3302948c1af11b9e35fbbed067b8fc2d249b55ea7de48496419046c0937f3a6c32ece276bde7148d9a8d0f7e3d9fcdacd681f4a85769cf508b423307812ffe2d3207c5763a9fdba8eb5135498d7bd034ebb41c63a1e665f5addfa0d35e6f986075958c43efc1a7bcca6bdb6bd2ce95bf19055d058e7c0690541775113335cfc473e5cefa1dce660bbdbc642b93a44864caaec42e351ba2e207a7b455c519a008aa623b9abf6890a30d2733bbaeead18f9841cfe86fa0056db2f38b54327e4f3f46c47aa05fa6de94a3601488197c4b0326c36cf6c6aaf1d8f50b801bb36d5398e1a6d3306148a0bc2196f1568c30f58bfcd194ea2d14e41e38369c4711069f42d82bc0a9f7c7ad2239b67f818940a0f31b2092962f38ae8cb7d7de0beafdb4ad4f8216aefa6e536eb831eabdfd3f29b6d3b8a5098c9749cf499977266932e935b93ff1adddeede1c473f049e9b286cb1c11490871a6358cbe8b91a35278e952a33e7d77873d7342ef01003bc1f46220308233577bea8206e272e9514984b7b3966c2748168d6629e23f97186e4831fcb7e82408e08d3fceaf189de803bd30a8ab5652556637c3a715a7ee56d90efddf91c20cd529dd15e966c1601c0946c", "5609e2c4e7ab2796a26bc4199e158fb856e8b19f0e6effed6b0f3c6c29ba24a37a73d568933e1f2bf6092a116eed44e695b17cbdfa70acb0f91201154952a52f9a66dd680968350bea282108045c3b82ff276f07f8f465005640f725e15077cad2e06a0287eaacddad6706ce92bbc30d865e601e53a0aa9b5f67498515a0d7e71b324254e7b8e1f27f93e7606b1b780c23dfa056ee97fa06af106e196513121769732d4f25a013d0917e27cd1bf9ee58e969e1765d8decfc260e8bdaf4d6b545c56a9834b25549aba4757761f426f5d55bc539b3d4810fd60741d0256809a66eb3fb28cc96a4aab288054f323f3b3e61e5fa7e217f2f59b46cbf6166a395f99ca8b5b591d3e15e337b712c228d1223fec15ffa6dc313c44ca67aea11ebb7887fe44e4656b8ac3a122e3f1a266b9292e383d42ea7211b6c0e1e8ffe4d35f9c4764bc338601cb9b14cefb6003f21e719f8f8e438dd56e0f234ac8a2ff37fa7626bc9b91293eaae795314eeaec7ff4fc9da9e8f8f82c18d739f978dcdb3043f1793a0c37d04d1db02ee1a6461b151efdc4670e7a6e28084984adde39f8708e936da1af3b42d92763a00c7d012bad3c73491497df62333ce98d35d5debf67aca6102355e8cfe80226916f877b35ab6492f11334f65b1634a3e63e6ce0c8b4a9a312d4f1ec167576b3efffc2c8985eac248e520f46515d371e8ea49dcb262a2e64133", "aacdc0ed8af1057924565f24d6de1356c449009fd694aa673eb6fb136856f1f31da2f2a04b060f04f1a80eb961b76fc71d0c583b290b2c06abf044fe0b221fb4b195106a9df44ffd05c65703c32ca33bfb5493a34edee2e4dad738b628110b4a0d4c9cef6a616ac4c1f4a15ba23a00ad540b36a0484902052eb7d4c748a85917195f745cad2f1c925b3cd2b1a0650587f4148c0b0afb9bed15061bf905e6708701d3a2e4b1e40392393af238f765c1277f28fa7bba937b782c9edff269e7e87b952f0c1a814f677a0a81351e58528979a42a046298af44f1aa23d7cd1c5f6b885403d32ed23f6a1b18a85c5972f6ed4cb78a16634f17c954722d145a2eea2c1af7f4fc564e81bdda5a05cf82a19a3d7b0c632131300a8af79853df1d6bd33bed37e727fd8bdc9b5acefb3bbd5ce91f1479602b78b605992302ae3683d240d57ceb06108bdd63a9149cd839f5a168a33999d753fde977216d5b16e7cb5db34d697e666216015d73c1685d66f9ea0dc719c846633b66970036e15d174c7b6580c689f93644c388e0dcf880a8f0568e776edd9967f7110bb2ae36af8840231e5e68b01de81569eeadd7fbff02cad78353d76b80fe466946577b7dcc13250fdef94db097f3c0f4a3d1ed5b15d75427d01394531ae433a3d84737e3b8fe15291a6d0059a976cc7cc1a27c369de404d02fd9d4feed8136a0c486bba8731e78a4a6d59f", .Okay}, + {.Add, "-2d953c698297c1b7d945678873e8051f61d45ffdd76b9035e0f19ec18af8a07e3d273a22d44683c3eca58181561692e250651f9d4060b4a3ecd971046a3d8bc9d7f862a769afa8640706fce498c711dbc2ee104d72900712b7cf5b66e9240f42d17f87450b16f570a6d2580c3c75e4b1d65d9b5a972aacdfb8bb4a8d9cc7711c3128ae7e83890115e971acde571ad41b34076b204b77088a8982eb66be85655667daa07aab25f1dfd80ebac5f59996636abe7d758a86fd0ef97a24732c5ef5995a9481b6f68db8defbbeede4714df304db33e18f81daea343b5b1fe3dc1f10002a3a2c139ccfb776c108a7d6e5c11778a229adc75aee144a7a75ffb660744acb484f47c3a594cc1d371cc95e8501a80d7d97112c6b83d379380f0346b5b472436c77f33afda5fd47615f1eb3821e7a8f514adff8c21363904a8c173585d6c85beec7dfedda02741d36bf4039c6bd549b9b7d7bfd0f3e58825af766de1408d02afbcb7c51370326d9f06c28760aab008ae7058c316c00fcc40dba5f5149cf1abc84ca7f18695ccb105b4c1d08184dbf41d67333acc9aa21d616ad3abef7c75aa11fd37732c24e44a065070b93c8452cdc89077c04919593f0b76fa52625451e9145d69846ddc8f8a36fa4af0653ddaad02e4273db72c6afe9fe72d054f8c10412d38a35af66f36d760430d4aa3ade0ac66c7bb6ac7c4d9b1935b53ea8ea6060ff", "c149a250d3000103b80c9a8e4765cb3c445b38ae5785068b505d42e79a6162676a4ec9fc8a6b400a3d814dd1820b691c7a80a3ec9182050e05e2218b4e5944e44a836db0af634e6cea749f6f2b7641998def8ca4dd553df23861bc8d893320fa1773ce18bf340109cc9af006dc7ba59985dd406b84b1b22042d3ddd62d4e98ad7408f319445c8f69516ee05f4cad01fc718b12654c5b52964aa271d07470879fafdf3064df535576e20c334ace786d8d7635d065ef7e26eb544392c2a49e44646e04ba851d7c816ba830682b57b796e2ab4b4b4ac5b9ef7c22792e90f5f4f22000abeadd95d7c061deefc0073939c892d0600aa39e1b724c2f5d62b3ca3171e49135a0f3f8ae60337e6abad1f0f6f75a51ac6e19d0b06512132c830b97cd76294dffba575665083153c6b8d52c760c3cf25343c88a3deadde20f5ddd8d4f570df13ea36ba03dea13558a6c5afb096237d9f0b15ad1d5a4f540ad55f22c4f482b5dfde3c5131daac7f96f39ce49405810bf62186713120d6fb7b82493d56d539e7fdcfa1b3cd96e6c215252b0817d4c3278f892d0bf3e460eda83cd8f5bbcfd7941777b1ad364eff44aaab2d03ccc165f770598fd644202c7cdd09764b45c81feb682528a7e4f49413abf57cb14f691a8d1a69a458b35e9a9a79c0e1c2765343611494196da5cfeed4ce918b75dc20675b9c1c00b7009224d095ac2d873a988ce", "93b465e750683f4bdec73305d37dc61ce286d8b0801976556f6ba4260f68c1e92d278fd9b624bc4650dbcc502bf4d63a2a1b844f5121506a1908b086e41bb91a728b0b0945b3a608e36da28a92af2fbdcb017c576ac536df80926126a00f11b745f446d3b41d0b9925c897faa005c0e7af7fa510ed8705408a1893489087279142e0449ac0d38e5367fd3380f5922de13d83a74500e44a0bc11f8669b5eb224948048fea342d639709fd7884d8ded72a0b7752f064f729dc5ac96e4f783f4ecb137038ce26eec88cac717a46e669a3ddd01769bb43df0547e71e0ead19d5e21fd671bec9f90808eb1de718305378b11a2e365cdc432d5e01b4e762fd69bd271948e6593053199416474df1736bf54f4cd4155ced652c9198db1d7fc4e21903e5e187c71c58bf0ae9f2679a21aa5791ada10863cfc82a874d978346a807788eb20276c37dc63b75f61ecb2c21344c0d9c3e73355dc2974c72e5b5ef141846780062326773dc1a83ee090311583e955785d85c8c35a71110aba9fdc5428b9e38e1fb127b02d37ca35bc60635a8692f8cf0a2855f23f5942438c3d692d063f5a2d821a403e81116ab53e5a3a73c7486e982edfe1cf8d2ac6ed71660f23e8f17636d70abba43a086509dcb1aa8c4c118e6d8a364266a186f39bfa9293dc72ea430233dbf0be77369917748b8440d22e3fbaf4d46095ef3bb8733d3a5842f894927cf", .Okay}, + {.Add, "e950482a96f9beb227c35793260d857d6380f9588f9ef8e589b68416e1b33d3836ac4cebdf129c81361dc9b52ad26a85e1a86e9165871491cc37747542137f488e392782cd9fddf5f3c8b4f08d7b6dd74a858a07640f61c5dd3f50a8b6936bf7af028a5d6bc061f55b7460eaf82b238c3adfdbd5b46ca816697b6daee022c07705134330974e0a8ee673c5093cef6378e4cc58d761f2d307ecb4c41bcd7e179f6f7c8f18bc5fa9c5ca3c91750d2b799554a3ac6b1c0c2d490b2fd2c9907ade6114c21ca4574cc89366ed9b3af3d6142d1686d36249eda8a409f4fbbbc855fd9ca8eda3125486497c9ca02fc50c039b2f1caa7b393346c91140d91ab70284516549c2f670f6b402daba1bf3f7439fe8aa8cd16f8f10d72557c75006f1fbc2bd32770d59caac1148a8a8fbab3b73a0d3be9b6ad21d6c8e07f2691e2ffab3ed27e6ca80459e9a1a9f76f8544250483e12db047c90882abaa6871c8b6fafb5a604554f6004583b8d690b48469fdec82e6d6dffb6fe81b5b89f3f2eddaab23b4f2fc4e95ba247c9f547fd32f631dbf74b3bb28974b9dd65e48d69c9da050a1835f4fcb5b0232b17c0fc5c3b02253274dd7b049f7b9bb06d6fe0307f600985bece6528b057e7231b8488a77dc695b3c145f71c7d7c51ceb33f92b372213cf2b624ba38e96f8bbe19ab07d5e81631d1898b90f6a0a62c3255cb5cc8bc41585bc4d2887", "293e13fb18f8d4d880ae773fc720d48802061f749b100768dc436569fd99c8cff05ed2765e1be69da293d9ff04f23884f5aa94a1dd21a718c7e337f593a365778da180e01310fda7a36a0e0c6fec22a2997a5a4639f53d290f65c24b5a247e91ea5732872576e28faa90f1ed38801ce551490ca06f3d4edbc4598bf274741cef87662033cf0e6b5b7eeaf885a8e76787127ed46267274ef823f24d0382853014ce78c9e4d054293b29271a37c1c60190932417df843c6ef260ca6c69c84332aeda6a3fa63cf09e44e45e0c5786a8ccea639c1bcb3eac71c383148a025f55d14a84b662c91c8130f324c87382cd33d539752daeea55cb8b3cd2bba02075b6f5116e7a7ce61cc309bd13131eb638231cf286c944d6c8b636bc9d20ca19a30597bd81e4f39c43424f6fbef43f0c61780c4b8aa48f55117f9c09dd38b92f990dd3fc91b852e6c92476e9fa0c7c17bc474469665ca144450095c269d1ee8977d20e899db2568d3e4924208499406b8d365f01c1f42110fcb12800b2aed0138defb0b98a00fbd01f91199dcb25f86e4381c1e1c8b23837f64b46713f6076b13a9edb8154e10cb9f1c882cdfc8b8f04b5d2fb03e14905bd194b966772f823d1929135f339d16bd244e53d72013f274df4e8dad71ed30874e2ced4816547e1c03dad008f523c65951e63f208146a74e960c2232e9269a272712668cdc408c7b686a33cfb", "37d3187dc26870c3a32aacb8f981acdfd83e2f0a2409f6f734decdab6bb4fca373c997451c0d1065b5f5b69a579f5f2d53c51b8af37a1861e4a6af3ce7c49d6c168513583feafb8702a6995b78c3d9800e22b2e6b03633456d39b755e58db55165475b2cfc32e8af004837fbe802cf1e14f70a5dca84195d2af142cd627648f6f7b75466d8834c046d5234d63cb65dbea0cb99efdd467c28a2bd99453f5d118ec57092d65c1a23d785cae34f1298b929e86e52a635fd31c6f17d6996614ae094ebb6617082656ace1acce60b35e62e2d35048901634b4c4dc3b3d9be1bdb31244f453cfa41c9958aee92767f1df40eec66f8569de8fff7cde6c931cbe5df3a27c316ac4d2c2e49eabeb4ddf5ac5d1b7d2f965bcfb9c3a9121995ca88c2c1c390a955c938ee0363fa4983f9c018b21987745b3c76e8487c8903ca9c2f444ca67afe605740b2c620e16991c03cc0cb259716a46a4cc7ac402adb9aa584732c6ecef2a856d2c201fab1391daa6979b945d8a1ef90f9180cb1f4a59caabeb1a4a3b5d896b5f49c306e1d9e555b8c02f6759cf14983d5cca98f47dbfe1701dc223ad1203c0eeca3449293c03bb157dd20d2b42b40bf782022946a7aee2469ee7e1c45c4d6ea44769d85fc791b90a930fd3a48e6aacd91ce02cdac9c69f58f690f4c32e0d35e50fffea28572ebd806795adc3dfc74053596831e9a4fccdd3c42f06582", .Okay}, + {.Add, "-c1094a85c214b6586dd4b8655d94f50732c68cd66ae47395210e2d022d41ff833785fdc41ed3c4550dc245f3142f8665faba42ff76186a3d6267c4d380fcfc7be8e81bdb2b43cbce5c6c8730fa86c35f7cbd67a4afdbb506b747a3d15cbf9667e2473b58e7c36c00ccd44c108334cbd8847991598bc65ec8a9a25c45944e102ee7949adbe3d1050a107ab44d10305bcca14b02f20927ecaf5efeb8eeef73a44f08e6d9c546913a5ea08bcc954afe6527c39ec1058b5cbcb8b74cf584b728826c6e63c6ef7a9ef4f857b9f82d9c22127d274765e14e48e05adec6fb0cfd11a42da066c9eab47fa819a8064130b07b9d7e830805efbcf1c826e18ade4a0eb00e9d00f282b832166090ac0070f155a52c198d74c97e09e8a60f1e5299edc9bc82eb52b6f75abeb960d1be1172244110b7f1581ab11a6800dd8084b435d46e3a521f093cdc90328c045f8c40e057264056ba003cf53ed0b5fbeba33089094a78550678c93406640705a5f5a508263060684349090d6c27acf044ad293998c3cbd986b193e348ceda5d2738872524f9f373a826cf88c88a0548fbd1d37987c5a6310d606b9272415f9c78f8358076e2daff76a72dfafcc49ad5c74f6be5179fb7461f1a67b62efa0094b00c333e0736af8151f77e7ba63680382d7c141a513d96d67b717caa1babdc9654903481d0c0f5f811a7e06a9d91f3bd4c0ae96cc157114c32", "dff1dccad369aab281cfef17c381b00ba47526d0389b660656d0ab436e9bcfc92335252b2345f7aa20e565292692c51d0ab574087bdc2b59afa0c52aba49fa944da442e54d7409061275db1c13bcf2f28fb4b1edc908101ed5580108214d872e47633ef2dee212381baf7d1d21242ed1ba1146f9f9b5feafa317a4bf1abf88ac16d8bafff9f2a8fdd6e282dcf7965233bfa3fc4d186a3e548e6664b8b2119dcade60dcf81f487f743bfb5a152af4ff0ca2f8709600675cf0f7049e0e27344b3f1521515012847a399728e6fbe7f77543bdd68c2ec456279eb21449e92f55205937a13b0b8ab827f3b25c565425755ef9e38b2bed8d70e4c4f5c6d0a2c1ce7930326c1bed1f07ad85af93f04b5d04af925f8393e5b76c0c081648f03efb18739c643c0ece9b7e9360e07959abad51242a7968d0887f80b4001946c75653568d5225032529388f0ffca019aa47f1026188cbf81c0d481dbf3e6e36137ffdc81efef062f832fd024fb53972c78d4d9a75c4b535496af633077d8a2719595292390bf0ad50e67aaf2b3a6f79df0c120b9f0a2299d89df2dfbe4dda4f967e5e192e816140853b8dd153ce2cd5447737e76d3f2109e2d8562c962522ba0688481cc4c4ce9d818b6075870a56d9dc4e1158e975e0dc1d6a7f737f6a06c86a27bd228577ec66c9b0bdf4b11ae0b483b0de3d682f02c13e3eac7cb8a082bee9c060248ac", "-b30a2cb914de1bad45b7b973e15cda06787f3a69675abd34bba1224df6584286a552ab716c9f64da6bb3efa081c65a142a0eebbeee5aa787c76db880d5585cd2a40dd7acd66c8b3dfb45297f394af43053c21c85d34b3404c9f223c0daaabdf4fdd10769b9d54add4b19543eb12288eb68d87ce9ec2afeddaf70e1f9a2a217a426270f2be431da7a330c8c1f40b6f6a96550c32d37a148ca161852a364528a725b00cbf5c49cb2675ccc16f3f84f1536f96f39fc2b5646e9a7dcaba3d4b53db87d11b1da7976ad54be4769bddda29b28eb69fd1e62037de0f3a5b66e6a1c52280cecb639fbd4259a6ce07bcb6e24478ee4cf5330e41ab9da922e713fe2932709fdcbc0f96025e5b8510731ec9fd4e120677c903fae71e54e9cee0ae9da0afbb18c73366dd501779bb009dc89863ba5aeb0842411e008d240831fc95f0904e949e6ecaa3d9f03135fc23f45b2a73030a1737d737dfc341ff7bc4d27d14a9bd31689c304833436e0aaa20ddbad5b86c0e6fdb5b8d57849bfccd486c8032ea2b5f5f2890e3a672f6a73918f873438d2b9b784a5eb3eaad74d16f42e801fdfc49e254a578a1e8882873c15682c2f6f5c88a2b51d5ccf3f380c64fd4044af1b3579d2cd7dde1643f93c3f66c5a0425599f2ba9970b9cf8e890036dba793aec1c4ae23f2b63d809ffd4b42e2293995b312218eb7b456b9a72bf1c202bd7e25510f0386", .Okay}, + {.Add, "-669405ecc667e52292de3555f38bcfe02f22e5158527c6ebd264e3358b64b1b938c3360c47831c6a4f265d8762becf461417656acc6974f82d72f1c5d4149c87ad204c4ca1dfcf06c96ebc88d2a43f2f5983c4f72bfff2b45659cd24e0ea4efcf05a4851431d829a880c30748b733c08f83bfd4b72f2afb07477147ba39d90f735be28924f614f96b97934c1dfe6f3f81cde93c3a6f7359a72b6ea6113805de719356b845ecb851b5e78fad0575b6a823332f8f4e99dfca924c04fd519f9c39386791b4c47de5f547fd85984ea59840caf895cdee2bd5a47ba0cf14fadf9bdedc7b26157c33d4a6b74ce8126fcb34c158e434e182e7f3178e21fd06a51e8cd46d36422526ebdf2517cb59c094f2479a5c614b2b3838ece3d919578a9552fb7185877634205a75ca1f7bed87dd5b5e0ef04be82f14fe9ce3e9f1aed3af82182240fc12fcae809a280a0382af412507a6cc0e716798e6a950b016a5d8ae692ecb24e397d2786f3016aa4185c4c65a78721c53ad7ed81be7b8c0b3dcaef9dcaf6abbd6d34b1b715eeb2244e399378fb16c3e5448f30d63484df9e88bc1844731b8fc5200069f4825ccc1b9d321da00ff44fd4ca4962efce9fecaf47cadad59bc0ab0e847a69f1ee5f9b59f71f4598033b25e692325877479f73da366c4a2becc39be1da41dc14d6f75d0a18856546cae6b9c7cc45f2302cf6a36dd1c06c2b11bf10", "88482718c95506b036648b1d696868908487f067159547c42d9d00b7fbc4e3bf03b0a49d590c495dc03e682f8c1fa9d5c3a9137a8cea0c5ce0127c599005b7df7510d1ca3723be64c52ba89f1bd94c1fe40d26387f721e2478f26b3f64f08c696a36abfe4e1e96367ece245630af45fb49c70b7052a39fb8c6146f8de70c81b150befef5ae776edad1f9ee49237f832f0d89ddff5f690ad6cbf5da58a671e77b5adcd088e3e63147d7331ffc770e1ab70d98fd2f6f4795ba2bb18fde95a68341bb282fa4708f84cd36e24ebdcfbd4937256182b0676c0e502123cb3d9ae2404b6e921bc277e5acf9ee2264082201f44e103584f15980d2c5876c671066ebcf02b7a03281541716f706496a9b36c11e235eafe3924a2466db9fd30f5a0f66d5a48ee4dc80e342a93b7a473f9fd3f5f4714c3a6a22cc6922a322ed9a28a46c30a3c2b032d9f74790d77e9e67a51514c74ce9d3b2b21bf24a7a14ef9b9abd0964e2055f96e7127fff45fb27509918aae5ec6654e05f05a037e6d0145dce5e338923e82229725c47d78eb599cc3c8ef78d1d1c3ace91ca4ba7db021c9b7e83fe0fa76aec8f2843fe5c8338dcd302e8c04f0e159cb524042550f9fb9d586aa51266705d0d0386d054f213fe41e780cc4a1145f871261397eada8ec66368e8b6b582e838ce05834f618e4e1da33628c030d978bf7707f017b3694d934846609931d5aa", "21b4212c02ed218da38655c775dc98b055650b51906d80d85b381d8270603205caed6e9111892cf371180aa82960da8faf91ae0fc0809764b29f8a93bbf11b57c7f0857d9543ef5dfbbcec1649350cf08a89614153722b7022989e1a84063d6c79dc63ad0b01139bf6c1f3e1a53c09f2518b0e24dfb0f008519d5b12436ef0ba1b00d6635f161f441880b98743988f36f0ab4a3bb871d53c593eeff792f1899441a76504851aac2c78ba252c1fb2b034da66043a85a9991106f140097bacbfae34af145828b12578b709f538e563c52a75d825d184aeb4086716d9edece8825da6dfba6ab4a8628e7953e2e1254ea83881f236d92b01a14ca54c96a6150301bbe43c102ee55924a58993ce91e79ca47d989b30dec695989e0e3d96b0ba371e8c366d793edd9b4c9982886721fe401382477be7317c7f546483d2acedac4aae7fb2ef030f0f3dee56de663cb102c44ce028ec9c388d87b56f13853e0fd676782fb72619bf8b8cfddb570ef44cb3035ecaa11a087183e1bc5ac4d692dec06892782ab4f4c0a531e8dc914b92a915fc765936f63f60f41722fb6393df663f8af417a5cc8ebe4f7bffb71d3fa0e548b05abe40d26bc11456b10d4c558d8fcf76a5c54e88891cde669278a44ac83b3446d62011def3bb20a33b1aec2cfc9e8ac8bf4c56f3c3a73a8a96f1138ab0c37965f2bef7aac1fde78672aa257685f46e20169a", .Okay}, + {.Add, "627b0c117af9eeeba4c49605166a9dc716ca84b8c73f8e452f642fd48a669d32c5992b66791917c98858988edfb64a848548ea221c4527ff7b62b3338e81e875e33c5d40a9942f0b25b60114e1e93cd2ff29e45d18ca9a601d4e5759b479e5aa9ab4173d617b6be955fbe90e02ca1525d45e2d88c2f7986ddcd6a28f088b06e05f86325809d5098075e4009bc5fcef14da2f5a157f6b22a0195a34c482f4016d880a7cbc3926dfc823fa6fc9b5b15bd3b93e301fb765eb54b094793f1dfc1b31d91a10fd8f58b2a26d7b3eddd4fa052f9a098a45ce9dd2788243a2e300123b66702c3f9341c7c604d1c8a2850c337948d8f58409e191c37caeb2d3ac1ab991f0fea7ce6636ec779a6d006162f9121513321504d3fad97a7247c5d47aff7c6f91f007e7d05a7243a92caa92140d7a562bd7657379c3acc985a2f2d0fc5c67e4e627c5dc10260c4e6635bf8293190e70e263a163f01ec48dba8b5837b2fedbe081dc07bed8e7576e32ac4e6727ff8ced20bfa9d0d6d1ecafe419abe4c3c60d3fca4f2ae7892c39731dc0bbff9f37b3e22d0b3e2fb802b07ae02f0390c0a8bb5831f97a3a5b5fa444434d0c81b3030f1ff05de85def4f78a63ce6209f4408667e1d1bb51a5e083459e5a66579bc4c799831034e24a5e47aac55047e8d6c3e7c5ab62c40f0ce39f71648e3c3f8e9069f8c0d43c4aa576e2a5e48fe9f338fc5fb467d", "47b2165f1f63b9881e7d41bc852af73f9b2b29ac7c00ae106436980ce31ed3c95da3347368f4ef340b2736df767ecdeaa0538e85e7f182a141fe504b37088cc9e78081cfffd31dcb3b376a45484c268630d0537f4f4216e4fc57e86c8f88545976c2ae118d4d456602fbb34327ab560adcb3d901dcdd0af614613a18148863da4322e3baae166bf0bc2d907f2df553b65e1b8c7512bcc7d559f77734ae6ea9facdda5d6953559eb9ee4f86bf7bc030277d760b81159523a3544ea60e1c348ee9891f8c06981a36e17f9d36c03e6ab07c17f983bb48b987d68668ee05f675c679093205e1cd647e41ffa78c49d9541119de5accb16447f409fce405a34f9724815eb3b6953e0d62617e98a4ae1ee3ec01ddddc81d01f00024211ef0369eef8f84e4cdc9824c196eaaa746ae696dc9f7ffc250d5672b07b322f28e9330f5502bfe9a1e9971252bb399d651e696d22da4b123356dbca98ba62bea0d46345d903123fcb3ca159c93e987a2d6ac695266d52bedfe465ca7fb2684515826056b9e1026edc53defbccd23af634c992b267bc7d609c8ac8d5b15efbdcf078daa618202c5b668b70f36689e543161346450bf3598bcae131792b1b4337f5786f3817d45f3f7df7fa7dc68edb7dea876868e66ff01a1e32bfef04889b5b79bff62b1916c3c84d952ff03b0eaeba968be6ee38ab8f7e2223ba1dcf7b7741ecfb65d39ca8e31", "aa2d22709a5da873c341d7c19b959506b1f5ae6543403c55939ac7e16d8570fc233c5fd9e20e06fd937fcf6e5635186f259c78a80436aaa0bd61037ec58a753fcabcdf10a9674cd660ed6b5a2a3563592ffa37dc680cb14519a63fc644023a041176c54eeec8b14f58f79c512a756b30b112068a9fd4a363f137dca71d136abaa2a91612b7eb75713211911af3f242cb384ae68a9227ea757351abf93162ab6855e4da258c7c7e821249f68931718bfb36b43ba0ccfb0ef804e31f4d3a30aa1b62399d042772e983ed18759e1364b5abb2030e0117575a4f08ac90e8f68801df795e45750f2c4446d1702ecee5878a62b75050bb45d9b786ab96d94f6a50b6725d5b84fb74f9d9fbeb99061117f601150ff2ccf0fcc97a9668e4c4b19e6bff16d4d5b152a68bb253d3f1407d7b444e2b99b648e0eeb47ca89581642d51b810e4c1e475814b3802000c116929eb3c159386d6d1acc85033e675657de75c6c11a5d8bb88ee83eb57ba4f25139151f3c24cada8173379e7d6686b040ac931ab4ff13cf02578e90696cd240898ca5e2faa031506dc455dc66a9dfe0b1e6b0a3d5af7afe2f16a960ce2977e6db61753ce55891a967106e22a5a706578263789e3c41113949a05e49d479d850df042dae09732a53150a4d4c3360abc1a8ccef00dc6f2b11a43cd3da801348d2cb757ea2a450525e6e5f94b2215bd1d6ee9ecffc5d4ae", .Okay}, + {.Add, "-7cb061450657afcb2c2c9ac788e1092ef6afda4a10ab2238ca02e8a460dd9d5c1d793637f1dc1c9c6d8d7aa3216c3c567d7b6135b6c2c3e010822138900ffaf817d3b70f4205983306fbfc323cdc871315f6ff857505c11ef4fcaf955e101160474adbc164da158f5259153dd03f2f5507ddf9fe54d31c85beefd18fd9e837790614816d570980b504c28e77f272c1398b611ce1f3652bbead1358026967fde303a36afb79f1095af94d55fe98341c5982c4cb8adb7c0cb36bfa71c290687455e9e6164f46b1b7f9eef9684cc7ccd21421f7d76855d7b80f5609325b40382680fb6c2ab66d0011455e892fc678eaeb47a9d6df11b8b96505123a17f2dc8b24ec111f8f983a08e0c7df6052ce2a1e7dea2f84fc05c44f9fc6ac580949fab786beae3ff071fe8cff2ab2a95108f52f085fbd78a3d7268012e5c22d51b6925d153b97819155244b0d8a7836ffae018f78415ab0c15730cb8846839e5832bb73aa8c528c38250e52a8710c00dec10096f259007628bea87c723c31afbb1b0b55dbf7c135a45b27b4f48d3791eb93688a37234025999fad90102f10132b45e4eb6da67abbcccc147f13ec0f1b2483579361b7a3b686b7266b7dc2a056fe6d5da13263a2f3be9add6e28ced841e3d710c26d299030c3986bac8d09000a30b03be9a54640198678de7349dac3dc231c8e78a11c5b008f08f11ed18e092c9c99cd959c0e", "fe78947feba67fccace557040b3d9235e3e867fbd112f9831e82a53cf79a25d27284fff2334e14a515a02242b2354a6e0ae35af76804c0ab650639dc340512486029445acf99db27642595abe89aea1a0bff16b0a35b7e90a39107aa5575be482695f7418504c4285296d2e60bfe25d7fb180c81e6eccce05cc4f5ad83e4ce00afacfb37a99662e66d8f0bd9a5459c18a87e81025cf11c47479570e654706396cc8713d719833296caf035b063fd967b6d3f00c8d66593ac0e02130783c0bf6929a1e4ad097466cd4e044d08d7dc746bfbdd7f39065ad3134db8457b6477105fde348edb2b6d3afa3cf0d9c0ca5a623f12e8bc236eacd6832b02f2eca929f27876d61704ddad414dd61cdbe8fac95e2740a56807db400eea6ad1b22ce2bc1de5a128634efa708ec6b685c437bb1638a41af34646b3116a4f41f1693ab3d9584e0eb8433adaf03a0b0d0271c88a04b7c4e493568d4981323267f45ea4d52dd1f2a16ad821861a228c36d028bac86971d2c94ff44a1fc97cbb29065626a55550f4d8d1572f57bb0d6a3e09128b1442f18520edd5fc3a2026c654977b2543ada55084ce03cf69a06573457c5649221a3c7cc430f997cf8a21a24c065e53a34702c9066310a0dfcd55761af2ad52c4f82649810fccc03106334d8d0251e69fb0e50a059e5c240a964552df2195b446503dea4e456244f2fae722706e4816fa92ec14", "81c8333ae54ed00180b8bc3c825c8906ed388db1c067d74a547fbc9896bc8876550bc9ba4171f808a812a79f90c90e178d67f9c1b141fccb548418a3a3f5175048558d4b8d9442f45d299979abbe6306f608172b2e55bd71ae945814f765ace7df4b1b80202aae99003dbda83bbef682f33a12839219b05a9dd5241da9fc9687a99879ca528ce23168cc7d61b2d2dadf1d1d6420698bf0889a8218e3eb0865b3c8e3a8db9f92293bd1a2dfb1cbc97a21ea7a353dfae986f8a207a144f3584b133fbbce5dc2c2aed35f0ae4bc100fa257d9e5a7d0b0831b03f7af1320243ee9dee2c86424be6d29b4de67a9fa516f76f76911dd11b5f3717e18c8daf9cc9ecd8c65b6876ca3a46085f6bc891ad0aae03d11206c0216f06f23be79a8e2e8049726f2e872dcfbe38f9c03dc732ec5e730445d7aa26f8c9157697fc41784217c43127736b1e5b6a52c8094cb721a88753f8389e2953618b5a9ebe456067219ba27664ede9ffc77c77a1b2acf49f9c7d27f79c8d9cb8b774d0a7ef7569b0b99ff74fd179bb2d4300618dd067726f7abb8ba61e0c83c5c8c90169744844fdf5ec237aa0a12370355215187366131c5ca86dac5207a72e0a91ea3dfabaf5fe645a5d065636f5206025f2ca742b0c97bb435b91ff0df0927c559a6448cf8213663c73fc3c584d5ab2c22fb781b457297b7d79ccdf344d33c01dc15946741ab7d2cfd5006", .Okay}, + {.Add, "-42b4a34d05c7964937fc5e14a30757b354a7a96cc585664935f99041fc61db2024233ed287b723dd090ed9a9d4cb33abf855eb99f309352c57a65f3bd7fb264ea6b116ca6e4dc5491da2ed4fd2e185148b5affc4e9cbbf9541a2b6900ad57102639616f94bf4b5598a6ac7fd16178755d13a5002f9cb0665fc398b296599e6822d85f4dd3f9e29fd24d150b87a61ba96336d84433cf007d905af23590b8ff1a4b3e6c6d352d4c2a82002d35f052b31703219158d5695756ef3b4b87e23acea7f8bf72198fc92e4b0ed71352ad88c59fd40124eca8f6095e3f3bdbeabc79659666761e0a9521d4358153e5784c419591b0bc3961a7dc5623efb9f2b76b217914124ad9c0964ccb15b06f57b3ce8682e34089939d3182e202c86ff1e0ff0a8ccb5b25411d11fffdc9bcb9780e8fbe16650eb7be670e59ef6ed93b22d17f2f35b5f73195a6073c01297417850af0eee2c7d1311f188bc25272fd400ed7b683d156b33b173f5ac7cdd52be35b4c8157de4649e55cdb36d7f3d678388b0ebbf5ea716f674de8dfef51c3e79511d3dc16a66453e2ee99d297f1b41605ca5e4698fb376e7566ba3020ecbde426d31d6dda66ee222be2569dbd67ea2f11b9176316de3675d52206cb44dd1e07156528f8b81b925b36a3840c361eca1c608630181934e0b7ecce2785f8c3f3485b2686805ffd5decea6edc5a95712dadd10b87fd6b4e5e8", "fe7533d1eed92056f70fd5523935c68b4f6342691b65ee78b5feb685cf4b88606f951c8332d56e69a52f4a690c60cce7a4c97ca00cca4e8ba577893afa8b0c156255572c38c42d2c87432c42198ec6819affaf4ce498951473c508d4299b72482b495baba02ad1662965a9eac3f78c7d7f6fe0069ea7a8713c6e174ba76f6b287be6748bace0584d8e0eae9eca0e557f59e770b0c55156d5dad1969a09bc8dbfd636b9e802b73fd91144c49ca2fbd67ecf8e9d7384e7c1eb7c9ed05fe0135b8504275ac9147667a1f0fa6cb629e0607e316864325e1ea3a9c9319894dd3a543d4c4a7c2cc9b8e6369ff6064952c8ed120384156095741c89587e96c5918e3f8f0775b92f02f3edfa8db48ec0d9194141bc08c2064f54b97d466e9d162cb7b843b570f879a9f3e9f1b9373f685b2f372f2d321be9d0c0b32b35381bfefe91170d1b3844d64908c9d0ea1b345e7853de93554eba41cfaa839ebf7b2e93c40998c49974902024cffb19715480d11ddfbd24fcd5e50ae1a1ed835061fda8b98c58f8cceda6ddfbc4e7bb20f46515028a03cb41c16fc63c7de85b780df06952a24b28010e481b55d5b53ac7bc46ca9ed1b45d3b6b448b947d17e3a37816e416d86676ef6e2da22e6407666102aae08a34fad55a87123a1b54a9e2a85656f01366b1e79d6bf1eb897f37524d20a1bffc2f27ee78dc965ee21f272784be37bacef0a3cf", "bbc09084e9118a0dbf13773d962e6ed7fabb98fc55e0882f80052643d2e9ad404b71ddb0ab1e4a8c9c2070bf3795993bac73910619c1195f4dd129ff228fe5c6bba44061ca7667e369a03ef246ad416d0fa4af87faccd57f322252441ec60145c7b344b254361c0c9efae1edade00527ae359003a4dca20b40348c2241d584a64e607fae6d422e50693d5de64fac9ae92679ec6d88614efcd5227340fe2c9c1b224ff314afe27d30f141f13d9dd0a50e9d7587e62e524c7c88ea17e1bc6671057830393017e382f10389378b51540680f1561567cebe0dc5d573d9e915a3fad6e4e89b83779ba2de8ab7aec48eaf93f6f7c07f4617aeba4a5cdf6b4edf76ae4de2c81d259e273c9f86bf1383f0b1130db36f883337269950bf6f7f063c0eeb8e031ce6a889f40d55ed9fbe7f5f4dd0de41b63578eb21bc3da185eee70b9dbbada81eea75d548b739a8a2e3af6965b216423cc8b913855c6eeb7a41185bcc835965c31c2a78531dc6b31ecc090861d8c05e8017577422b01bccd94cbcfa2db1e1d678c84ffccfcb7ca7a347d7411f9d860392862912fecd1a17b14a84e91297b119b7dc7853c6e95c854f14f3c12b457b18ad1f21b8a69940b25c856de56a830f921c0d357a163585efac5850feb341afa71cd9f957f2bd40e24df3ee91d363dc1e9f0f7329f2f81dc76e3957f62f520faa35a89938c8144ca7ad7f3af83bbde7", .Okay}, + {.Add, "48a198f950472fc86538026a3ce6d8b379b3f4ccacc6b1362b8a0bdfa71c3ef81975a2f764247d767f43283069530727d6fb56e2e77f6cf41d7a04d671dc6d44a270fc451b891f4e6d3d09d5a1439aba9ff02a1abe052d7eec3c35fbde9ce4f382e33cc2774d80bbc7c3f2f717b2e51820903d18c2edc0db0b6c2b600765baa8e7cd9b3414eafa6777482518b991cb8805e6715349b0c99d0d56583c2ab1b6fa803314ef3a1feb6c4e4192bfd896f9661589b89b6b3f61f7a5886a2f1aea8e69a5d698c2e91dbd66d1f88ebda58dd8da763f0e7256ea6dcb477c8ee9db4c897b6497d09f5e6d5bfbf8346aa151c5a5d2ec389d1589094917a3292e31c02962688f3c5fa850abae82c6d641a20fed77aa96da68e1c753f4d19d4cb7fbb934b89096e4bd88f77066bf5cb00bc1278b7d4107ce3a63d8af9ab9b85ca5e6c6ffaa87a50699bbe545e0c5213d88e52ec8e348cdff2bb3a9d040393ec67986618c649563076b6ccd0655765371bef80b5f677876b309efbc758c87fb006d85b95438b22963c8e838c38b06c82c900b5e9ca57d7bf97a0e2698871e3fb067cdf666ab4669c0312124bc6f6edd939abfbabd392e8e0bc07e9c1c097e4a092f51212bf10e38d72704c1839f6d3f11c752f1662543b7925caffd6f703cb5648e82f47c1e5ac42490ed36a42aee1cd60984bf37b2abff0af0e518bfca007a8d4a3377e9af6", "d36e0d49ac1f21f466a0014d180fbb02e70698bab9c5f067c6511cba02f341d06a5a97d06ba7b79f53f2d2ff71cfc72066ee7834fb2950403955e7c241ebee53a15c615b8f7e775c88b64393636893c02b4af56733f9960704de0e26a8ac73f5dbda4f1ca4c8387f9aa7e04a286487b4e9b280f3285e0829f42371e3ae584c669ea7a5b446092518598819ad0c3061e739151e215a9a53ed8b52cf7979af481e178b1a98631a9054e610c28fe85d1efa0f876867f0fe94898a1eedf76f239c1a51adaad7256c5f744d349aab0ec6c7902ff997aaaa9e2c08ca7f5f01485f5c781634fd3027277c2ab39723acc960f851b3def693d473b0826e6e7f868445c7ca72d43df292cb6a21b7ce3ca1529e5377ae27fac510682dba19766440982b541692cc3429bba7c6a9132531fe980cf1d9900e8d3eb659ad01bdc07fdfd35c748518e69cfd117e9009b8c3cc28d02422b084d116520aae8ea54d6f5314032fe5d7e29642e07963e234395233ee3e1fe79bcf8fd5125fca99385722e55c61d0f17d3369ddfc80c55048f28e73ef80fb918e01107657ec51e95cb565c993b643755b9d1d0758ab1c39af3dec2848aab8fc2f47293abe8ba51033edf0be46ea33dd3aa346e31605f1630a29e260eb5143402eff5da0739085a5c74b8116c9138e2608d1d0cdcba790fc133c95a5b026e38f2feac2a9ec89549eff50b1d22b91232dfe", "d7f826d9412394f0ecf38173bbde288e1ea1d80784925b7b2909bd77fd6505bfebf1f1ffe1e9ff76bbe705827864f792e45e2da329a1470f7b2d880fa909b527eb83711fe13709516f8a1430bd7ccd6bd549f808dfd9e8def3a1d18666964245140882e8cc3d108b57241f7999dfb6066bbb84c4b48ce437a4da3499aecea8112d247f678757d4bed0fc9bfe97c97e9fb97385368f3560875c2834fd3c5a638dbf8e4be756bc8f0baaf4dbbbe5e68e9070e003f1a7b28aa90477749a60d24500ec0b146353fe3b4aba542396e91fa51dd75d8891d00cd2e57ef727efe614250fcc7e7a3a1d0e51ea731a6a56de7d52aee2a280652d044513e8a11269a0485df0fbc803ed17d62509e43ba0bb739d2af25795a1532cdd6d07334b2fc053be9f9f9c3a80024b1ecd1508f032baaa85a9ada08b70e4f3e4a6ad59464a3e3fcc6f2d93370698cfd2ee160ad7a4b72310b0e511b1090d454b92a8e15bbaac6948ac2138c6b9974634478b9e894fddbed5de1356fb05b15b91f200d6d2ec34bd66350856001a8b045188f95f113cf036e55be5d8d00df8cebb71ce9960d01095a9e01003b90a6abd6800a62bc561f4a664cfc23009f6c67566d0cbd291513bfc469c4b86d4558652099d00fdd37d608059a2833ad6c63e905c9ccb16d75fb142d5e7ee7e1316da7afb3ec21e63064872d70a5aaab358fadae09b9f585aa6cec8a1c8f4", .Okay}, + {.Add, "-442f25242e4d8896cfee96f668b6ea491f5a00165ef822124e26d2c66d5db98efc88b046aac2060424187e41f3ec59bbfa9414bc53dbdebfa360c90ad799f9c7023f7e5b6a55e39bb1e0bcf47876065aec4a906938a53f6c2eac99123b791ce4375abbeb880f12b49de2e93bbe77d8a5b222b538111b9305904d2cfa7fe81db7b6464352692d7ab1c8ec64a0d91677c9b7241a456de6996bd53b6b9718aaf7b7eba3c81e1839126180cc27e8acc0f09812c0c9ef37ce9e422a4c37a63881f476844c85c15433df12c392cb49504beb323e2d0cc65a01521ee7ec3b0fd5d5460a946d5adebcb9936968fad7b0573e78c0c2c67920bd401517f8eea1e8e396b71063d7a0ea8c5df086ef181e3f0b688b23fd436fac05eb2ce236f0a20a0d169d7a2fc5fc480d254d6b194eb00c582377622eb7fdb7c7b293bd795659ba61cad511419770fdec7fcbbcaab85b40f1cccca23a0b3754637da926925702ff006fb1a2962e264b8835e0d4f566985aef9a285a6d305f868550bc1395dfb493e1de164ff00f110c4c98f06f2650e4fae3f49d291c1a22bb7f024e5a5a9914ba2e7306e8719230d974b262769f7bf1e3eafd5ef2473c6b916a1503202830901168647acf0a0aeced14a2fedd9dd520f00ea45a3bbdc2f8c774b80bfb58ed09a841520faeba62393bd008bb1c4af5176cead8bfac3834d25d046de0d9ea9217cc9fcdeaed", "5ddab85507a03772a4cc44ff3840df01e1629ea0764aa9d26156188c618cb0b195106fc99f0e2ac15082e3205fc498071ec6a72111b02edb18ac1f7c51f51ec28eb3f6b25b0b8b3d1621dda8489f93a2c0a1e9942a467de219196706209be6cc7e20f032e01cec33c4ac5f7c54e593647f3a7e6fc6eaa4de6605bf3413b45930da0f0e9712d02449824801005dcf4a58b38dd71a1e63a60f2f14e7b84966bfbc1a16af3fa456cccac35349a2b2faec56a242bacc5ab5ac5450dfc8676694a71b4b16466c454bc9b865c741d5cca99043b2a0b10b5db462314684fc1e060216c92245b725c7facdfe632e4ba21fdb8c0f0483a5b9925b7fcb32b463faed965c889bab06c8dd556efd318ed9e80f4cb3302bec39eb9669cdc498d103e0d04dbb3e7bb7e6808f54e9f3856021d4a57f168a8aa3c7a16b50afdbc4d996b06935b632a9ff104208d64a14c7dc51a280e67dcc7c65e40c77eaf5489b660116254599c4ca37468f410a56ce6b331a780097db414bcdf72fe7e91347d1bb7431d61aca5410dbbcc64e7be04ec40effbd153a2a5df49f8d6197fcf5094a0119adff75b19bbda0890477485477c6d36dc8dd84eff8ff011894c9a4bec954d96e06c246e0daa9f9b90fbe948d1910c63d1e2c3f6cded8a9ca8957bb4548c37001af552ae6284d1ec57f5856374de80dafee9d0e6041cfa8fa86815fe43e1c294aa03545f6e", "-3e51799eddd3851fa5a1d2a67532dc590143d62c579377752811713da744ee83e337a94a10d123580f10500fedf0103b88a7aa4a42c0dbd1f1d60713127aa7dad9543ef044a52ae7e07e9f19f3ec0d20c04071cff600d78e0d1b02a1d96f5e776f78ace85a0d43f161982343f9297f6f6a2f0d5114ace8b7a9ecd1073eacd824a8a55268f800786d30c7e490d33983242beb3cd3cc005f0ae24a1d1b94148bbc2a025d2a1df3a594d496f34e819141d2a89c9e427223437ce53e3b1fc218aa04cf9b215a8fdf22773d36572bf381522e030301b5a4260bfbd383eb4df575249e0248ff6c6039e68982c7f2f63540bfffd27e3ec5241a5d1b45c35ba934bd5147da1cf07dfe8899971bff30a08a73bff0fa84ac0d4c849005ed6391cc0011c1c6480a7de0042ffecbe0f8adef0dcb85f9860dc13db0fd88bfbd08c04f5b3779ae16f77ff9cbf2671b5e3a9626c9be64c57244d9139bfef9d208a0a2ed9e1b5806498ab1e294253b680eb366b36f90aaa65873801386d22adf18c3fd50c47c69aaaf01553fe7b1326a3a0ff4ff12a0fa833cd029e565827f09c5f9031f4e7babceb5b828492d3ddd2f230ebb075d250ff2b74c5a081d7ab73392e2f930fc400cc15f6b515c18b9b60c0cc8bd1e2be0636dd0385c1edf3c57a6ccb6098d4bff614c35904ce3da8357a76c743c6e0107d9a81b3a42b49c57e29608cf83229c798b7f", .Okay}, + {.Add, "20478341ea6dfa9f4887d38e95b1c45d1fd10c731c71ffa0ebc9570f601d25a420c033f432b3b156f6f21effe7bd7d87f140e04e9b9fa7bed8a22b291d7190ac87f7e6d20e92ef36b61490e32ab3f2af66cb827604bb9b9d7d077f2287f333190a6c2fbec96550e9b5125ce6748013ed7ca16ce51723768c2636286492a9144805048e4ce1c68fce8892167a061e42f85720888c62a6a30e5f452a1ab2ffcdf7891d7c3a486906d22c47e31789320d2728d5141bf837f3f7a26aa42e88083538c4464adb35439f23e12cf2192a0435ab6e497f443e896ebd424c6117566d12666f98b1ee204c763328dc43a8ddb991c68a6e68883a742d77d2cdcbc13dbdff7fa1c2b81473788e0319692cb45854e5070262b7bafb7fa10f0801d45d252a5aa9dd20f36cbe13576151c86d2aaaa383799b6746bed9e7ed7821b54613364d03e2fed099cf0e15d82b5719ceb078b08e06b34313eefdeb6d14e361796ba2cc62f6d1c2f25c1ee91e44e8695e94c4502b9fc632182d5fa924216c014e3265b8f0c15636aec6046d991438a0150b53e1307e99e1dc495d80e0601698c587faf0bfb6e86d73615b1f62b5f3293d6b64cbac182ece0c8ee08dae67f92ca1c1766247f03ac3b9a8193afd841d1779c16e43f60660e8f0222ef728ac903f6dd985e90fc0492081b473b768803c340dd08e88fe39b2cdb04929ea7d822a9871588988b694", "45c8ffdf83a565a5755978649808de55a352f50b8b3f7ec3c7ea88ee4d9d146f96419598d80e5b8c889de2a441d970af24b7b38465e938037c64a91fd947a4a334ef14975a1794c53b2313832ff804f8a903b1154afb34a801344cb3d582be2ebe399db180b47b66f2dbb816a68740b379f9c847b086ff8620fec99f47530d4391c1bb08fe0dbd42acb2a7b0985494a0a0410d90e735efde305cf4f60346f31a2eb1a7d3a380d59791130c24ab087354873a29ac2917599085488a651c4e34fc87584f618746f922f4a5ff9f6057b0047620f55ae0fc97cd8c204a170f22c18cc6176e31505b1cd0f25591b27947079269455fffa2991af9f526fddc15b770252ca40bd52bc81eff32d688bbfe4f7cba24fc073390daf2e6a1e18445b8d9920fb49ddb1ed18b7a724634a3f94c4b002a02603249b674fa2496ec93ca9e81d21c450c8d9fdf4b285d2a39854e5c99dbe1209b431a142bd07a3dc0f5f5c9f1293b524dd0b5a4c823d8d18cfeab3ac4fa6d09ee52ba755fb760664f349a9d9de5a6563611dbc9f2a80627135423f0616e0717a1b10a6a718a5c031fe627f910311e95ca79a8cae88fe90cf62e8ea34a0c9971260670965336ead58c4ced4d64e0c5171bd133165d6cea591a40bfb42c4d107810777c149f2dc74ae78d1c870007fb7e55f3dc809c7f4623982512e7641c4a825487571640a7791c46915fa2a6c3c5", "661083216e136044bde14bf32dbaa2b2c324017ea7b17e64b3b3dffdadba3a13b701c98d0ac20ce37f9001a42996ee3715f893d30188dfc25506d448f6b9354fbce6fb6968aa83fbf137a4665aabf7a80fcf338b4fb6d0457e3bcbd65d75f147c8a5cd704a19cc50a7ee14fd1b0754a0f69b352cc7aa76124734f203d9fc218b96c64955dfd44d113544be2a9e72d798f761961d49dc92ec8fa21f10b646c111b7cf240debe9dc69bd5aef3c343a807bb00f3dc8214f4d8827b32e93a4566a354b9e9a3cbc8a9846d5d2f1b88a5be5afe46a749f1f86068ace6cab2e658fd3f335b0201f70a793041b31d55b57009958f3b3c887dd0d4871c7f4c99d53756fa4ce66c3e99f40ad024c3fb57056a461c1275ebeee8c5a93f5a9e358a2de03ecb991bece8b8f9ed1d397fd1123f6ee83a39dc77908905ce79cb8a1d9ddd4ced5ff43dd276eed610088815353fed54a69e7d3de570912173d8f21226f616cbd8c322410c311c3b1421db9f65d3fff15260cd0206ae7d508db81d25082cd0356d667ac6cc0a1ce60411a5fb3692f44429e85b1838d53c7f26abc19b8abaff400f0d57e37ed0a2607f29f001f6bfa0815b8b19ff412ff76e0e552ceb8eeaec3c728b551df8adb2f986a6e7631ba8122704316d8f9679e43965673db26faf60ce917bbc7767590f453e7c65fcc32e375ed1a84352237a0402b24fb46df02b82c2f7a59", .Okay}, + {.Add, "dd48c4e0e5980da3c32a12c646f1cc127f06eb08b22808de32e780eb4c2b2a79c8d66e211a55b0b9533a22cb04e244c0b268da207d46c60a67dcdb169dbddfee6ef44d71189dbaefe9401d7528a3d906ce6968e66b5539c09ca78214b1a8b4aac01995b8639a52e1b724e3d636ae330fcd927ce0170adb805c86d5d32180aac877d18405e700974dad40344b2f3f8f560e04c976c79d01587e2711afdc57de6ee53d771696847b163e1b44619feac9b023df3bc6a23812ae80f8654596e3a43dc16519fcca9a7b230148d430a629bdf1d3587952b39479c72d4af3c9daf74871322cba60d45e18dda2e33c8f5e885ed341fcbd5788fc3f74deaba726795c63e64b38b0430734d8bd52b7e623a770ec40df9660d1da6c820e2593cf8dd2462f138740c32a58403c79f41f1f851a9c618f4bfc0f28afcccdddbfa5fb47fdbaa78c117196049842e306247cadc9095e2b8b36efd0e723a03ab363d0109fad413634ba57f76fe7ebd43c61dcd2738a94dd3c3fa64d45eaef7a5a0cb7b557a4af7ed9e0aef6035cec3deb5b754865f999d2cd1651fbc0c76bf88a6931002185c6f0ea72e22e41d0fa1d29d65f87705a4900d3778b2f7e1da3d4a183028bfc438088734d354ba1e3bc8d7e0e311e46d937b24850ff58b7988f64ea1c24c34097a15cfd760fd99359326eca211e5f180c2c7ecb2af6975f3e09d94d26131e4b326d41b1", "5da68fa0b4d5db599ddea413d51b3d1d16837f809e2bf731f17a9473c91304c128026008a1c41d1148d8c40728e596662bb789d2af11092f0ee180dd5f707a51ab3a99b727d6328a5ae823c3b1bf610a85566ca7168aa21e5e27efa3dc8ab7036defacceea5e5671ad6b399c2af4bdd58f6d297e25683a19f07d97bf370fb0a68eba84c42bd009beed92ecaae65ef7f28d4a2c0a6b5aedefd6d8c7fc079fe36623528bf7be248cf65e776130107f0c9bbc3a000d2973c1e2845ef99402fcd03dff1bd73368e6a217872205e99a16a95ccec86b300b3617b6787f92286af08482be4a67680f57cffee5498c9861f030667ba8b79db5418ae69ab94936db0e307cbdbb3e53620574bfb50fd809cf7958c497b63dfb7cabca78e26bfc4597d82f27792d0fb76fad36e218f7a6ea7e1e67b6f6cb47a423cb20e6af3d5f64365f1aae6e4cea73c767880e51424047262242002eb6bbd995908d18d828a3d3420dea51bf19b211453f285b23ea6a07af39ef21d0dfa2f71e35a61917e5a78a496c92085382fae505a63e74c914090af129d0e66b5823fec2b9d4ee8a5953b605621b0ab431d83cf7d1066620f4183d3528dda215856bb290163467b2b2f7f9085a620d23de372ef8c999bb657203d930bf5014b07f8ca1dfa00bfdddac1af71a8e95a96b4de31f59f68227075bd4fd9d4683d1bc0f75781061fb2388b7f7079b384114", "13aef54819a6de8fd6108b6da1c0d092f958a6a89505400102462155f153e2f3af0d8ce29bc19cdca9c12e6d22dc7db26de2063f32c57cf3976be5bf3fd2e5a401a2ee7284073ed7a44284138da633a1153bfd58d81dfdbdefacf71b88e336bae2e0942874df8a95364901d7261a2f0e55cffa65e3c73159a4d046d9258905b6f068c08ca12d0a10c9ad320f6159e87489b4ef58132f7ef4854ffd9abe3f7c1d50890030e54a9080c9c92a591b069d64be0193bd3cbabd49105575ed999e0747bc080f13033811d3a886ada1a4040674ea220e482beca917da5ca85f245e7ccf3f07721c8e3b5e8dc882cc927c0788f39bda574f53e3dca5b7964f05d546a946308f3ee96693a4d7d07c7be2d76ea4505774c9ecd57184c8707ffcbd36a1e5e3b006dd2e1c7ed735c0d16c66f98bac94642c756ccd397eec46ee35aac3419c23a7fbe80785faa6b1475beee102f806d8b65a68cc0b930c7cc3bf8b472ef4f20867971a9812d2afc9785c73c7b39cecc5e1085f03d09252073249d5ce1ee1c10e23431f0e862927c6024895170eac3a3b381aa1fbf8a25cd78f38a53d78b290bf52714067ec8cb238ff7539fad8f71de758d109b30adba090935b583f54bdaea80711382d0dc86273973a3222009f7025d017ee559782f70e7f9d0de37b22ff2a6e15dbcb2b328f0f1287a3415a973029ce7060cd74e6bd470aecb1552cda582c5", .Okay}, + {.Add, "-7d741da143140a735ee4df72effe2287bb7320d152c4a6f05142afd354408a6c8bed4244f9d50022c8d14d4074c569c3f92cd7b591e5054ff5bddcc53ebf85578b98a4bc87e4d1c9dddbd6e0cbf251d1e37040498b3a888991c0b6b35f3c6864f0a8a905d5bdb064ca1f1bcc44107e47149211d6f91e6cc6b5f4e33771323ac1713fe0fd48989f008fb0d743b25202207c67c6cf8443a393dfe1cf1c7df3dadb59b574f1a40c52097be5e24dc1365cfcd93d31ab221c565b3b90b680c5efd1b946e38a386c63b9450429a199ec8f0f4b72182382bebad0328eb89e9dec65be8facdf04ef15b37254cf187d3ff286069408005fb69a215b6ba5a5279c5f6f3a8318f191775e7cd5159cbb2c04e491eb4d774e6168ca1078f8d64169d94567aa69b59e2b7e349d751addd2fdb692684535dad4c01141257c8bd56fb7d27b4dd5bf624e18ad17030254dfcdf1f449f4bc1bb1707b1a23d7335e702794d0c564235aa4303a234aed60e629abf0126cd5a403d684648dd7aeeb620d4f52256da5782555ef05602e839c5c0ddbfbb3195619613a2719ee6c68e54da9d03a6e4cb34d010eb721ba1162ae725aec387ef0de5d64945bbc7eb94d00547380f25e7948a439452746c071d8b2a63709d6ae10f8eeeb7233d8f31cc9034bbc7045bf889d1b4b491b4de40865c3de3df4a7e5614622c7033ce89146c48d9da07ad5c025f7ff3", "e2e7319afb80c28d2264bb36d6603c18d17b1e9f3efbf1f48cca343262f9c4e417748d2904591309f74045708541afb16f4a75f646fd0db00b3902941cf234a591cb727d0253369fcd0dc1c85091928e096926f9a89670cf9097182440aebcfe47d34ad5de268dd77a18082ea51c368a491c7d1fa3b37b438a853efd8746031951ca8b03dd2e359e9fde7d51b2ee8d9f08d4b52244280a6091592835bb65e8826379da7e1366d91c37d27b4d7ceb3509fcbcc44e850e4be0308fdaff0c96efdbaba8d48809950597d90cb77bd4ff80525926d00cd29d15cd91fecb53c79f75c6a7659dc4029ac91c7d575b98be67916b0feead6a4c8dcc7a0f6dbab98aca7de87c9740bfc52dcf410acf1adb7a72c930edf6832b6436d4094b32f30cefa512d0d284b14df2dd6d4b9cdcffd50994408bd2923cbbbe8aca2f69f096b3292a070451a7faed96fe14cb1efc2f91d85a54ab22e7115a5359faf3b81d3670fadab84a180b81ce623b328c50bf3c69e8135477ccbd4ead834f7f982206be946ac8d128ee3025485ee4f7b5e07ae2e62f8a901690174cbc10e89102af069aa92f6de2a55efcbfe71f152e90126a0006220980fc8e2f48dadfb8ecef6c5689fdb85818fc1a6de1e998a2cfadd7488a2d9261ae464adbeb260421f8565b0f899d4c997be9071f20a7f8fc4a5ccab9a91a8122f8271097f9746760b81d555121c0bb68fb01", "db0fefc0e74f81e5ec766d3fa76059f055c3ec9229cfa78587b609352db5bc3d4eb5b904b4bbc307cab3309c7df559152fb7a87aeddebd5b0bdd24c7c9063c501911e83139d4e9832f30045a43d26d70eb3222f50fe2c846f77b0cb90abaf677f8c8c04580cab2d12d761671e0db2ea5d7d35c02342194771f25f0ca1032df6d3ab68cf408a4abae96e36fdd77c96d7d010e38b54be3d027535b0b43f386aad4adde832ef92613fba0141d28a0d7cf3a2f28f133d2ec867a7cd6cf970037f2c0173a9be482ceca0388ca1d6236368f5da2054dd4a6b168ca69134169e8d919ddac97ad75113f91f73065d3c4bf3f3101cf6ea76ee2ebb6c35513683fc4d38a404b0827a84f4601efb103681b2c29aa7c16819d14d795cc79bdcedc6f5b4e982a372ace960f9395f9eeffcff9a06dbc3874e4f0baaa787266ac999b36017529a85b831962c58de4a5d0ff507293bb08e967d009a8b11c87bdd11abd23ee8476146dc87e2c2d8c5c7dee247d68c145fa378f550864a5d490e20131c97213ee79a698d134f25bfcbdf01f9d232afdf52e807c74db1d2a2202add46997024aa2add54e114dcb7dff03a8ecbb3c7e32fb9b2644e98d12f4241cea251e7ad7d0c38eb8861b6d7d9185448373d7ecc2b1521f5793b8ad96d25568219f488541540faa34528d6bc9b875ee1ee6da5e9c2b0e95faa0642aeb52f46f437b497464b9097b0e", .Okay}, + {.Add, "-74fc4841ac8f1adec26997e0b214af6c4ffba4511f4d236d087cec9ee9a00996d8352b8a1c411d8b2ac5995cd07e8e34b93adcb49558d857ce09ec6e927c279e60673fb411c845ff354a9802f2cd7688c30f8045bf5e5bbf259a3d7fa73dcd078c1c018b2f24f6be1ab513dea0e9a1d9b64e7be5ca3ff083fe36f082ad2c369ad5abaa739fd5c975cf8f138061d6c82a43bc959c0559a8747c42288581ae29c115fdcb10b530c1200a3eef70f5263c5cd2b5fed33965062ca31a0a723fd39cf650cafd601181653e3c74cb8ad498d0849869641c1474b4ec23a250265808fd0a55c798d5b1b73192517a459f1221e801db7650694d0c308c8193d8e3e1f8910d2fb38967e66fe5f17df09b3a9c23da5c4645868474671693a5d61fe6483d03029105a28ffa88930e0cb9d28578caad44318af56dd1af0210d49ab907571ed8d99cd9c7f82e82512281fcc93fd77e3a432dc6d6d6c87106cac4faaf7e9c4b1f6cacd3244608c91c5e089f9bdebe4bf50f16aa53736148bdfa71967ada01208959b1ad326577a45bde192769aa13404458fa6649b072383448beffd6249e206156c9ded34c188416d4448a839a5e49174546ddb3e26d3143e9566e5f0a0e98b4662782990886a27be6554bb0351785dbd0fe72f42a6d0b6e9f7a1028de43919a7b0911d400f2f4b5e8bd33ac7a2c95a6836fdc5924d69529e1269f45bca5a09a1d", "811cdb4dd53e3478b97dbf6eeb15a2f7681d23221b0973ddf2cc8265fb04ed105b3fcefb20ca30949cc33e59c210b9a5eaced3ca8dfd0cc634e7261896295900ff46beaa114ab4b1ca1543598b86023bdfcf6822dca0f50091ab25725a3157b0f21a99b0db62c460c1f8860504cee1dc3d703c71bfe91e45910a44197ef6907c8096df0a793f8ed30d18529b75cf1d0ba4ef722715232bf14eb31a97a9fa562fe6ec9e1b332c7da926f1a83ca7855eff5b57c21dc8dfd2695f204f3c92efcca94b6753de65eaf96ac939f1fe770221d3a453becd620ea7d8c130e951e70c98680fe95cbb851cbf24079b0f1c7a0b94a943d4aa461d759af0a1f9967141cb478bc1463393080cef8775bf2b46394a9fa3dd3cefeff62a54b0da801d07ccd3fc5928f42fa3d2b436f4e061fe9eeb12e81e790f977c57b66837d224af57048cd82bd45f9139e83c13c9e65acf36e95139637188d2cbd7960a5ba7a3134623bed3525a63fe686b1d253d389d239801355b523dae5f5296233d7b7cff86dbecf272532d06ac89b570ea3ac2a4569ca1b9a12d32fef88b1141008e3cfafe4236ec59d38b28f19398b163861efe6ab067fe64f9b7d03c52843f247c77e3d4c6a415e0d3df2934863b8849061178c12783d404c133d73cad184eaf900ed3055a5b3a3d9ea9b141b603ea40d47a3e93babbdc061a134b4073fc74ecae204316ec129c84a3", "c20930c28af1999f714278e3900f38b18217ed0fbbc5070ea4f95c71164e379830aa3710489130971fda4fcf1922b713193f715f8a4346e66dd39aa03ad31629edf7ef5ff826eb294caab5698b88bb31cbfe7dd1d4299416c10e7f2b2f38aa965fe9825ac3dcda2a743722663e540028721c08bf5a92dc192d35396d1ca59e1aaeb3496d969c55d3d893f1b13f854e16132dc8b0fc9837cd270f212284c2c6ed0eed30a7dfbbc891cb2b8cbb25f22a288a1c34a8f7acc3cbc0644ca531c2fb2fa9c567e5469942c8cc52673a269514f0bea5ab14d99f2ec9d8e992b8f039b5dba21c3e5d3658d91b620c97d67e9aca7685e59dcd0696a642065bd8d5fd2b67e9192aa2b219d0995f7ce900b9d26c54796f7696b81c33e1d34a9fd218496f95697ee8d13d82ba3e6d3a82c1972483ada4784a20e86076626fd89f64fad6dff523785c941b9b9c2a7645e05f711d2ff2043c1fbf50f250390e2a863c78773b3e5ad90da22625408df2ffd87b942e9664327040bdf34da7f810b690c01ebd1e8f97b597a243dcc8e5ca97cecf28e795cd43898aeda9f08cc457dfb281d98cbf87cc14a1e47802d4cb1da73e71609b54db470f28870170de093217575bc957d2c6db7a69b7db4e5cd1fbc2d10f26c4e28f035644882ab4340f094c2dc7c17a8a323a09f6db510f58aebbd0ae7408f465f96a36ee74f25dfc2ccf9a3d12f6cfbea86", .Okay}, + {.Add, "9da234f611325c2cb9129f62ec102b9b73e9266644f2d5206ee51447803dfb9fc5caaa6c914fb10ea438e24f3eab303d7823f7b9787418a0a02bfaacc32cce7dfbb1718f1509f4dfaad965cc581f080038f639209cce296fc1a5d2c7b73a928ef43d27a22d9b9d3d960e852229951e929dff8bfada9ca6f6f85a21a78fa68e0709e268e1669f1cd7b875981d9386a064e781740dac840a100945d042a8851f7f2ee76896baabc113233736f31f75c3069e43b1b968a758295497c3c58a1dac2bc7908df9147ee36bacc0a1278733c97da5008ff275e385cd1f8894262138324e3be70db1f456b4dcf840ae6053946fc8d9ee283b7eea7b7f722746637e3d681ba52fc54cef78f1ff01290dd5ecb450bcd3cccc728b7349018af7c291869f26f82a63c369adcff32097ca42a3704bcb96c40441e393f381ccff2a4ac76a08432eab981f7ea6d71b83a62a7bc16575efe4f0f35ae5c7ab9206594732bc74a1ade3d36de87552d8db7d796e9a5e6ae2975514ae570002b825b66f4a1a1b140520560e119c87c9a97dae0d6f07ed1d9a02e013d6b80c825ec9e846dd285a1b073530513a368ca412c8acb6b4145ff55dd483b4a120eb9523be0524a17924b55616e6f8faca7c4ec60856c382cca3564d815a14b50a032181fffb83f0781a222b77b0a3c4b881a000d1efc7116e1276df29d0a06a23119b6724a95c5e3d91dab7b7ea", "5222b360275abb2be7d2860727d1bec5fd80b6bbc58f45e72af94392668a4e0587bb22a27266fe329c4215411731ba0d61cbb73545f48de78b9964cbd3fc71c2d9fdd0602550adedd59ac52ac683d9adf1bf9bfa8cfe26a667db972e88af6a7216ce827b3a68069ff7e9cf3772e69bf0b81eb22fdbf5b0469e458c791293b12fb4d17bf95ecb6ab40a3c45c370bc2ad214f72d7808f5c638f8027ebb2b690187841c2ab0d1221461d6eac2a74bed29ee707580357c3e86bac4a6f310099e173e16ec44f3a2e4e7f0bdf009a296f03be17708cb9f5c73ec7e9c723f7493dc3000e9d01e4d0780bce55de515f0179688c5aec2ee070e5a140ddb6b4103f57f86285247fb1fd9b18f57428af74b04815fa8eb912f3fc5c96da23e5115d6358dd4bc1ce7c45a9faf3d3de491199c198eda0365b8e1d594f4eebcf84c0a6124eeee9cd1cac6b9af0058a614d6c60c24cc70771af876641aff6b8f25ce756680b1940c2acf9666ddd35fe435fbb7d99af6b57128c1eef88af20463c87eb812f68f8a05a37fc9cffe11399f3721f357f27164fcafd25a1729556f9b2135ad8c84fea723a0642ead24545d0441c7e2b200ba6d334a9d52bb44442c05e5be2f77415b738951ef173a4e38dc470b7fc09feca1c091dd8dcae1bdb43f748880ad2c87e077a762633e2daf5441c5b3112c48fd28f1be14994659922a18694ab6a014c4817b1a", "efc4e856388d1758a0e5256a13e1ea617169dd220a821b0799de57d9e6c849a54d85cd0f03b6af41407af79055dcea4ad9efaeeebe68a6882bc55f7897294040d5af41ef3a5aa2cd80742af71ea2e1ae2ab5d51b29cc5016298169f63fe9fd010b0baa1d6803a3dd8df854599c7bba83561e3e2ab692573d969fae20a23a3f36beb3e4dac56a878bc2b1dde10442cb36fc78a185b579d04901484efdd3ee2106b30393478bcdd574fa21f99a6b62ecf50eb931eee4e5dee4193eb6d593bbc369de7cd2ecb763cb5c6ab0aaca1e24055f1c095b91d257724bbbfad39ab514624f25b72bfefbd771c25625c4506b2af88e88b116428d448f8d4d92876773bcee43f777c06cc92a815643b40520f135b065bf5dfbb2513cb6a3c948d867bc2cfbb4474b87c44d7f305e7c5b5c3f89daa59a29bd23b928e87089f77655288ef731cb7d62e63855d77429bb0141cd8a42605c0bebd149e2aafd957f15a822f55341effe3d7edc30ac3b61af6a523805d94cc63d7045f88daa2a1a37c8d22e0a94aa5bb1916657c7bab74d4490fb45100b67dcc3a91223abb439836812d5e6a005dc53f19e6539c86725b0f87bf711f61841b6ff3e73a6d967ea0b0a5fa89bf6b18a704ae9e1b69cfee49dcf028d4342ef41ebf242d4e4df363f700c712546aa0bef580627f6af4f5513b57a229a5b74081b8eb503696b2d913d12a714dda69f393304", .Okay}, + {.Add, "6c059a9d8de81a49388654f2b25be047997812f4806b76a0af16a2cac3cc7a1e63b7207df74a09aae8786e0348d495d61332863573e5be4b2f54f44a1198e07553badb98cb2bb62a2a74074fd9bd4141c2effeb586d5620aa2073358ed690fbf52ad886e765d800c82c636f54031934baa011932c2548ac2eb4204118e529099931360456b34af1beb60aa5679d4e1c44f3f1b1e2c84dc67531846cfe386cf3a95cf1dc9527deedb4987e6c0b6afd3cc5f58e26f24fae03a330c68646c0be52c5ec455693646ef5c8b5f11df3443419e6eaa488b230c70078291ddb932fc36a1bcea38dbcc68ee55b2d3e5b66b349f86ac320cfc6857f04b681bf78dafa5e5ba4ccfbada61c52e98a7771ff4af08cd1943733ff778ef1d03e7c7280adae4cb241183a655a0e69dcdeb0d97ef6068997d847f82b6d688eb3ca256379653293d889193811b617e4f098b67d18b56c5c33aced2469b92cce53f7ba2ad23a5aafe9ab49405515096f0e55449c266fd5261cdce2ae9ca8493bb28358d47e884befcf146a95f2c3e47200ef9b81b91c4b1d28693a352891ce0215d59e2423b6d2c671cd44e4ca4daf73aacfe21068c9c199b0a2ccc28faa4b83bcc97d933631513c76dd64ceac97f486405102258bb711209b241f6a9315105ddf9817a5061691abfa668d4b96b042ac39af213f099b0d7a292902176d7882db6687419f7fac78277d9", "36d6c7210119db6c1e4c70f9ea5f9ed6ca829413424654de251f3271a15707a73356fcce233991e8984fa790af7e62ee165a7f3fb77d2bec2d5b30887f93645ca6160ecff6d6da5220a8274927608097f252085f289b32ce9143cde3f1ad8bcbbdf4203f3ee3faf5d4c1545a199e9a166d0249ec5ff73c323f71f0771ce910bfbe219a4f079fb56c53d996a6988f394ee4486579e091a706ec097107902431b273df2848849ea0299008b079c59426aa5ba7a9dfa2ecb0773db29cf6c844cec2669dc3b044f02d5fdd1609876608cec63502fe86e821ba88da07b651467dce10777e31d1aa8297b1dcab98369369b7ad2d3d5016e704907c90e18718f940ff9ea27363c37835928ef2e815539c27b0fa4ea7506815923b5d9ddf07844ebf1e471921da79c5c2277adeec2c4ba82a2017bd471e137c2668b759e0cdf6755ffe65b596e3414a3f697a03299db78500bb23f29132efc7f94125201909750d7e20d01e597964a3370e3123644cd7c4cf098c1b276a8638ee09073fdcbcd21adf4c5cd1faee014fa7ac752ee107bdcfb0c713d0f05b935d40749fe17007790e2c2c7e57d8c1da74992473f83606434e59eda1b6fa4f537f973736d28db9f5e50d1ffecaa881e7e3d453bd38996908effe052865265ed804818be7727ff2a6c0c789bc7d785d5b6aea57c1c6b2438a79c11b16188c4a2eef47de7d7f5695c659826929", "a2dc61be8f01f5b556d2c5ec9cbb7f1e63faa707c2b1cb7ed435d53c652381c5970e1d4c1a839b9380c81593f852f8c4298d05752b62ea375cb024d2912c44d1f9d0ea68c202907c4b1c2e99011dc1d9b5420714af7094d9334b013cdf169b8b10a1a8adb5417b0257878b4f59d02d621703631f224bc6f52ab3f488ab3ba1595134fa9472d464883f3a40fd12641b13338780980d16836e3f21b7d773ab00ed09ae4611d71c8f04d990973a7c43fa76bb008c4ec7e790b170bf055b3450b3eec56219197b371cbc68751b669a4c1064a3ad47120b2e2a905c99940a797a04b234686aad76eb86078f7f7decfe9e5733d96f5d134f5c80c7f8fd7ea6a8e6e558ef431e9dd9fac1279a5f35484b307e13921a905f8e81586185a62f8f29a3e96b2aa580cf66a8c548c9f9c43b0892b99541c6a0ca52af53f3fc37058cc8893bee472a645cabbdb8838e916f42dbc67e5ec163798b5ac626649bbbb698b3291f6ad2ed7eb5f3cdff1677ae0f3ec2216b59e9525450bd81c42f756a04ba9f9e494e18a44d2d8deecc842899234f9462999a6493ae1c7a2095fd3b5249b47b58939b2c270e7f4f905f20f6570ccfea7388abe3c6784e244f73036a66ed58fa20e76ca0f56cb1631cb7c248bbc1c461100edaa71d0809558769e0f3fa430829e24962e64d16c66f151b5cb8c634242a98bda8a8adc106777594e5f3708dc12104e102", .Okay}, + {.Add, "8e3853f9c080aef42f28cdf70a7fecd2678396d753769cf9f40de45d39af57562f3261973fe662823eebbf8295b4adb86bb067adf0488bae9b62f63fc26c86dc86c1d384dc1ceac458e46e596293cd22e724a9f68ef8283047f8237cafd7c39ee898a4e0bd72d8129b48580aba964cd4c92e9d1f215f4b280f123b8f9e99947e0ad3cc0eeff423b8d0a6323451ea8edd1a282e82890a3a77e1197c241471bdf2ebf3dd8b30cb87c17736ff23147e197a939cf10bddc664166d7189dc1d3ed52f4969f7a466c8eb01c65ec572c29b8961bbd8c177f66ca95602889a837ca0919d72445b0352568c1b0dd54f1975733315073691f28738c7f12e52468c21fca66960f06814b9a66cc764cb4fd3d1d5d4a9864b55a3c7c56de9d6c3d778902d5aa9bb931a7eb9c79ffeb69e4c4787fdc8eb39eb2f5515f9bcf86822cb7cf1227f5beb3bc748f20a03725b40a3a1e3030ace5a4cb9e318f2d7d76ab245af7e88c8c6db73cd7eef48814ae5b106c1506c27758f2350576d7905250d39790ef3c9ad930ff9474300621bdf8dd54657c12c9f42453e6b79e3c29da8699c8a46a8b1548259bfcaa90b37cb413622e2587ab3420c2db28cd4ef29275c5895a6758e0142d03fb751f6fe8c99b6702b5874a3a4bdc561992ae827f61d0507a33d4be5ff1822abf492b6b9d404ecc68160abe19abe051fee8c6b7dd04157880b323e50a304e4", "3b196f9ecc4cb03900f5db082ff27c1c7376816f29e16bab588300b5db98df4a8f757130dd88884f86cf48790d900b4a970e06cf4a8457f7e5b4f0dfb02227aa1694d5fed917d01847203f1a5f4b0373cc60e8b78cf778852a3b95e45c5795629552a181731708965d8822bee058c81bee1eaaae80466782800afe900fc00fadb0f17a853a069c6fa0b7f917ccc098b1c9e0d605d0fa91b84f5d46c22d6707a5d6ed36621a7a5fd4fba86813c78e4f8c2c1b0a8035aafb5c07935df4c803d8af3d6b6859925a6cdd3248d1bf76226a322382a46e3137e7f4a51e34eff0d75b688eb38ef1742eaf35714c637021b400e386027fe913eb95d2bdd922122b137a7a4859bfee31cf2fd55c60a27d5e2c9bd0e54300fc8408f5b3694fc2361fb68a6499547fcaa51319fb57c30ce6ce3368727bd5552c59ddbf71a8389da0857ba74b821bc8335459a4f8f4f93e0f580f469eb86106b33ebbf40b5a1863eea32b8985f9fd26adab41b608c2ba23f9e53266a1797478e991f4aafa367449906af4c9e27d46351f88b3065333fca3edc1dba0f3e4ec7777fb6dbc1de9d4466442a6a2f636cad3bcc1f6703a2beb0e6d14e6750e4204b74f42437ad75bafde86df5ed3c69323967b5da8b434da63df893dab615dddf31da5f8e52170afad68fab19f9915a45917d926735515b1cc29b4e149a8091f142dabfe5c0d58c0b366a32261412e", "c951c3988ccd5f2d301ea8ff3a7268eedafa18467d5808a54c90e513154836a0bea7d2c81d6eead1c5bb07fba344b90302be6e7d3acce3a68117e71f728eae869d56a983b534badca004ad73c1ded096b38592ae1befa0b57233b9610c2f59017deb46623089e0a8f8d07ac99aef14f0b74d47cda1a5b2aa8f1d3a1fae59a42bbbc5469429fac028715e2b4c1eab278ee40904885a04cc303076c2e641d8c598c2e113ed4b45e79672df6736dc0c6906bfb7fb8c13715f727504e7d0e542adde86d55ffdf92357def8a7973238bdf393df5b65e627a4914aa7a6cf736d77ed0600f7e9f4c6853b507f21b289972733f88d3911db9b245dc3ec2b689e4d1020e3a94a2802eb759c9cc12bf2513002707a6b8e56a04bce639d401399aeafe3e50e54e79a495edab9fa0e61592e5631315db5c084816fd77c6a105b691d769e26a76d578f7c4663a86b5039e1b13b12516d12adc09657aecbe2c4caa99e21b4524cd570f42c9a8a3753a86b2abb359e8e170897c940ff6db01f43adc29f5ebe77758d3f7c6289152232c1d1ea45830840362a2ae2f1df3059c65370d0aaeb57f778908a9e65cd2e3b7b620df0c58f99b71a6fb74424316ca233b44584fc6d601696d2dae8725c354deb4a8f37fde1501f233f8c488e20db3e75b750a646979eb138504daa8fe0475a02784d8a60c2e4660e3f02ba177c2c4eb048be98e173044612", .Okay}, + {.Add, "6f4d6b8370ea8e2876411fe878598146ab5e11ee8c425b4d20b86522a2e2fa9ef65e5b184832fe9874ae1eb2603ce555a465b7d31b372993e2dc3c6e05073cc6bef9adc2c20865cb30512ad64ccbe3af0d2af6f5f18b69710d97ed185f24312acbe2ac281d4284240922827d01447f8cfb5d043e0f398ba60a289ff9e61a4a6b750b7aae1110647e5f9f9eda80f82a82bb27d020471d3a115542f8981569421c866c488adcba27af2124090bb77a47818ff754904a2162dc1a38cba0bc507a07e797f4a945f9a0c7e7c3e7f43c60c66e0fccf2c08a07b8db955e42206b6a0cda55d0536a5afe582d4c8728dc8a027a8de4ea380b2958534cf7b1a9d5751363ffeb4b3034af572f482c8b8cd58b4d548a9456de1d869cfdef3840f2ed6224f105047e0a1b805bef8086608493f205e43645342620d979b78174c4f79ec7f44f09007e96712ed0e3a64cbd90cecc22e7b9d05f63711ae69250640b5182e9be74c45673ec8b9b852e9cb759466811a4edb2df76a775748126a3b9599d38096580d8bb8399c4d72738e7546db3a114260e66e38e678dba249c78325da7668236d648ac4c49390cdd302d27458e4d9c1b65e492891162f990bf2b06528d562b73a95b0c9f65491b6c87fb525651576fd0247057ae9eeb427351f290fea0d6be4b632bd04e100297b0a51a55fd779059770a517f2c119a064ed096a3d9a2396d1a35d0", "2dc657ba03e738905b0d360e01deb38f6f0ef373f68c721061e931edc73f5b19ff0e8241fb726eda0463b077b1e70ca9844307e981b2e12bf94dc925699ebfa28ba9d753c66163d1d62d5e5b33133b02f2a8f1098854b5890cf42f8cbfa9a72edfbaeb71e714339805dcad4cc5f59ca73b11a4efc6e5ed0c867e08d67a8d25ee0f4141396396ee1e8614a2516ea3399e516978d9b7bba93a1b03140204e4a2000efd5ef23d93846421a0e9bcc433e6cb522608271aa81cbfae66e9bbe120a1aa32554bb86c57331142ac78dd89ce12192cf30dbcfa4c4efe96c6f7ce6325457617c6fa05312658a7503db1a1f0398e33aa25f9ed4ee6af1d5295f41071c4dd22c5947111452cf7687046e95fcd7c9183fc42a24f495087c8823ff9ae0bb160c4985b711dd18bcd0ef28d5d10a47470c9ded9d74aac469ad1b574f58449136cbb8c8b1a62ad2dccbdd4e046569bb7997cc158fbbc790a0f5f1a2d5282f34075382a6d3f187fe761b98d3f364ba07de746ac4fa2c205d02668a65128b06b4e0f84e9bf9ce06d00ccc70d53a5244577c5e3f677f6110972a48fa6b04633b2d8b8cc4b63d46ee69e16579562ff1f18f41c952a58e7376c0d9b3f2e314aef6007190df76c85d2f76ba29adf2fc9e9a5dfb2e2beb0a0dbbd7ba3b6338607644b77d5f29b46fe80d101639db44b051cb559e5a8c10a92b66b4a422bc414a58cdee7ef92", "9d13c33d74d1c6b8d14e55f67a3834d61a6d056282cecd5d82a197106a2255b8f56cdd5a43a56d727911cf2a1223f1ff28a8bfbc9cea0abfdc2a05936ea5fc694aa385168869c99d067e89317fdf1eb1ffd3e7ff79e01efa1a8c1ca51ecdd859ab9d979a0456b7bc0eff2fc9c73a1c34366ea92dd61f78b290a6a8d060a77059844cbbe774a7529ce5b4412bef9b64210c9148f9fed8e34b70460c9a1a4de41c9569a77d1a4dac1342c4f2c87bae2e4ce21d5cb764c97f9bc89fb55c9d711bb219ed4061b250d3d92a7060d1c62ed8873cc0007d845407da2c2539eece8f52506d974d6f8c24b0d49cc4da7e7a3c08c18f1031f8783f026a4a479de5e6d84122b0dfa145f48426b09cd2763558c9e60e9099806ccfed85b7ba80ec9b6dd651c99cd97b3951e7bc8f78ede1a4967a5500240dfd6b85c052532a39ed231107bbc48d09b0d3dbfeb064219dd72567da813691b85f2d93f0a1af7e38a405dcfee9fc80e12ba41b6c905644987cb3b222d4f98bc64a377a514d0c5faac5e874b3905da54336a5442805ae61c158c5599dd44ada065d9ec3974107d90ded9a350f8f14f7b01da7f37b4684bca88d6cb50f8279bce1f89a659e5a6a3483d8458b7ac269040beb1c12d82a9631861b4115afd753165f3fc6ffeef5a8c484a83b09c3391e6b950e8368b208b80a487cad0ed0effa4036a450719912c267ee47c64c022562", .Okay}, + {.Add, "230a96c71bcf127332a2380fc6f09941b32a7fc56447fb51de65784c3fed45db66709f08b95fd8cfc1a4ba09356bde59931e2fa8becc21a6b71e41e45a48f83a3b326762fe259f62f7d2f8b46c9725c91eb1bb3c073f16ff1052103c07c2907fc1ab816019aae4f0910568c9015164f1a408f01dab92285219c664faa77bc93fa0484e0ed1f5513fdaf967b790700aad66509b128225e85ae4505a12f6e3f28928fb325bd4c8da79db089160a38cf4b9e52c7c9e4a150f39288bbd297c64d425ad3ad1360af53a8aa05f8b4c9c6f39f19de6eca9a223270a96b7079a3b965c1af7053f062270d1cebc61991c4cc52a0997da99b4df20c550ff6e1a6d5cfeb96c18c42b3481fdbd226039e1a85f1d93fb481496f83bf3bd5bbfd6cdec56362ed123a6a96b86c2927f25baa49c1da26449b022a3296fbbb22886170169a98dc35c41139f5ba78c1be2bc21e05026250545091c5d92e45d9ba8deedf3793effca98fcbacd6f8380f363fa6a2166085a9f7b83c26e6b8cfcb167adf88e821d25df0e4bc4e0f131ffc0906baf57e6e5e42a6ba176a19a15d93289a4be887b01a787d49cdca808ec35c1f0f4230ee3d8f2e5d3f60611ed58db112ba07122a384eb5588aa8160ffd46d84212c1982ae71d9a263d624eeb5c10d17928faf9b54fbeda5c99ceddc976783dddcf7d80275872141e9770301c9b075bf55a9ab0d4ce0a8cf38", "2679b15919253b66858838a3c5925fd4e752aae3116bd6cf20eb7fcb9e7000f7cac29cf210e22b9beda02c2de776f13a05ea8a301965101fbb68dd50e633153e195042fd69f8df3836fa296ec03683e86d947146bbd8ca3b1eda17ba622a26f5135ecbf4353589c0f6f305504ef1b074e531e872bf1f319186b2d688fc5027363942da1f84897335d4cc97422aa6a95fe3c26d8c097d05aa99ca651b2af550cbbdef097fa1844c1f5295aef545b85a86182619dd8cb240242a7eb757f93ddfd925c61a55118f6e4895ae72df518d0e640d7dd1df6054e001b1ee22b2cf85013f2ccc2e2f4d91866438f8568d95d2261fa54236cfd0634785542882045ccada02cb1747afb951dac3ebb6f8bd5f5fae9129d86a413ff93921863e7b2a385172c4801453c36207c8e0b6e417dda25211b4d4b11be4782604cb26b7d7726a7c082ddd45b7cddcbe470c75a5346f0ec4bccb53c3602cf29d7e097b3c30ba284f12a2143c02b9e987226c26c87212c705fa816294619789650888da95e42e91024ec0d4cce986a209609a4b75ecbd0df612c81266d68dc6c231f452b39f4daf56c0aa5b119b9abe20213ae3e3115d00f1b70f7cf6b59a9de0d23ce400e3a882bc7c4843d5006a716680d698de3f47524ef1df86e67a0afee34c90cbce2945e813819caf9b72b44c0ecb36af7bf1e5887ecffb716ac2f7a9633d1a56a8ed4808031427", "4984482034f44dd9b82a70b38c82f9169a7d2aa875b3d220ff50f817de5d46d331333bfaca42046baf44e6371ce2cf939908b9d8d83131c672871f35407c0d785482aa60681e7e9b2ecd22232ccda9b18c462c82c317e13a2f2c27f669ecb774d50a4d544ee06eb187f86e1950431566893ad8906ab159e3a0793b83a3cbf075d98b282e567ec475afc5fef9bb16b40d4a13089e8ba2ee057e1abf2e21d94354e6ea3bdb764d26992d9e4055e9454f3ffd52967bd6c74f5d530a748175a2b3fed300eb8b1c84a8d3360dfe2bedfc4855ab64be890278070c48a52a4d0b1b5d5a23d16d3570025832f559efa9e29750293d1cd084af840cd653969c71b9c9936ee3db72e43b4f97e64bf0da65be7d428c71ed01397becf67d461549168e87a195a3bafd2ee8ca5b5fdc9ebc79bff475fe84d3bf0de7e1b6f3acced8dc1409cb8a1e595729844a62ef31c714bf34e9c2105cdfbdbfd6fb19b25a2a2433674edd3b10f6d0296d0815d021329378cf6099fce656d0031661b9f0888e72b0ae282dcf2091ca77d409212ab72544a3f3da3d33b3dd7827dc9b647df77227c8b0fe487ef7ee43a3aa55e32bd8062040d9e49ce372fcc787f6bbe3688472064c07a7d1d0ee56616a45d404f7c4f7c1f5c42894435d0b68c0bff064235b7dc49ae40127664c894f4bb392a913a753f45b0fa011e4e86dc4c159d8fc700053fa94e8abe35f", .Okay}, + {.Add, "ec798d3aca1a51a01655c32a2ae7b9e5e02a6a697e2b0afb2c1260713b2aa083d4d853f5659cd33dfaf00451c4661d8191fe45ea69731ccc52fd7eefac388f47526f264f5b7b2469a9704214e106732c8839eb5f9414cd335a485f6eae13969744a5c40b88f2758565020d9fcc32deee8d6ca931e5cc73828720a50248c66026463a08d3be8b50eb4756ec105b28f9623789dc11e6529f9a7a45f283a7bb2f394ecfb007fc9eead169f9e4f47b344c8b575f9bc4d186576b3a41ae65136c59619c43a818966319c0e04ceda6ab9ba198c345c6552aa8b6d493f54fb6afc56b88e05eb950b699406cc358838e543a86ff7fa53eb44937601a43d56810c591ab9f7729b4567693878a7c95d3a79654ba379944f7423c2f6daad096464f1072a98c9681103b45088f30c37f58ad08aa2b02c838e0dd30737a0079051f64870bb35aba66b73ca67db74601485e59de0537cfb325adf07b3b0b019f62cf387006c139a6e793a719325cd089983b9ae1818e988371b03cc0822bf3b6b1e051d52d2372b7b474ee390cbcbf986895532b5b05be6274f7064f6b2ad8c1f11322329b010254af392f9c2fb3f3fdef5336b6440099e659e087744bca8cfcd3288e0874bcd6f5a4b6460440206318bb4ed2660ae8cc0a64da21e1a39968942a7177d852798a585c30535796f3600ab77c5f01f52bf55f94ea920a69d7dc94e83b9760d12aa5", "e84f528c96d65d0e81ee51a5896c58b07bbd66b3e59af110be556393645d6aa1aeeaec94a3bbc2a7bb9f2541095fb57916332b33d5f5b16526401a48bd985ab1cdb339a5e81a113b8853b83aadabdd3b41dcba891a7f9aa31a042de08ef8203d678027a696a93c65ac4139d66016d497c6c13113f1deced3b4ef7f73d8a2597febca67292f3a3b1aac8345048adedd561b37b5ced7054b13e49f0180d094abe67dfd36c29a7f0693b6d5d6ede0bf1729ce267faa03214ec734f861448adb83555f8869ab7061339d59fab3e283f266093298e09d9b616b735888dd92113c1b148d0bde786887fc1725e54717d70bcb21ae3c973c3f341d4cde9d719d6223be55ad155fa08d801f5572ff442f9f58dfada04ab2a1eab9a9ce823bdcee172329861fd9309dd36d64750c361e6843266473a5c10fd09dadc86d5bfad27c3462549b47a140d0dc636e0dd19c89285acad9770f2a871b6e53c5fdac41173fddb11d13e85904e69d39d5a004a43358adea84e3014245471efadc1cba9a511f468d5fea9db23a441e73278a90a8a11f3c0b1f6812e8520b13d7bf9e2f765abc3f3726fd03bbc0e72e02a52a8852a3e42fb2cefdbb5217d06361c7ddd39d99aa0b3a1fa3e6e1595aa886c60b77d4e19a1905bc2fe098046b65f649dd9edfabd7cf78e4d2d4938e7f2ab6f6fe6b9796a5afc4e10383e6d7103a53c0a9047ade461c2471ad", "1d4c8dfc760f0aeae984414cfb45412965be7d11d63c5fc0bea67c4049f880b2583c3408a095895e5b68f2992cdc5d2faa831711e3f68ce31793d993869d0e9f920225ff5439535a531c3fa4f8eb25067ca16a5e8ae9467d6744c8d4f3d0bb6d4ac25ebb21f9bb1eb114347762c49b386542dda45d7ab42563c1024762168b9a632046ffcedc58c05f3da3114e607d6b852c191e0bd57eaae5ee4f404784fdb1fcccce6ca971df16520cfbbe25bf363b525861b6ed4a7a6326f3a0fa99e47dcb6fbcc11c406c44d5e3a47a1892f8e07a1f5dea6f2c60a2247ec7e2d48c101869d6d6a97c91f213c83e93dcaa62b4652212de1d5f0886b7d672272d9ae27b569f5243f13f70413a6dfef9517d735ad99e5398fa9e426e9177952d2233d2795d312b65a40d91875f3a5cfb577154bd08f766df9f0adce21426dd4fff1e0bb6e07f60207f80d82e12553d2e4e78238d01146c250350be98ed0ff4ba3e6784db7de4d8f40988db66c32708e3c6ef38f6c137b84b3f583df7d0810714c31711bba835d5566af32577fe44a2911367267662526755d49116342ea76f1676dde71d227ff586afa16ca32591e8641f71ae5f6cf97a1abf857d7ad926ad070c23813aedc7adc860fa0acc6e66e9090306c7f10a4fbeafcde8d4799e346330a1d4fa7cb5e5d2cefbed2824dea5e764f1304b1ba0cf8e37bc1a244bd9885996319dd7cf59c52", .Okay}, + {.Add, "b688fe131296494edb08ee3c0e425fa6ac0e35c7a2962dc271cfb00368f02de80aaeaa7c431140c02723a04c0e6e1ea9b3c416baca8af8a480bb32ce2b33651fe48be5c080a0993db7427ff76da94ddc180cc222a510520cc2ec46434f7718d9aee62e10c4abe08046bac21cdee4c0c79a2ccb22604c05c2f97b61d7a95668205c01a9aca72853cfdc3dcb9229e34d82ee2fcf1325b19f4b62c90d0db18edb12e9600dcefe9293e54bbce2ccee48781d07514f64265d5222881bb34943153882cc9f5d91179e512b197a6276581bf3676a05a27fa38b9b414d64e3e1d426e52c502ac1cfa7382501853c808423e64969543df324d5476ffa211c9e479aafc63c34bca1f83157a060ea887befe8d692c1cae20b8b516d98275dabb87f281a4a9f077371211c73215f72c483f95290026ca25749701814149b7bd853943a06411f8cec51a441f5586bdbb513d5205a1af905c4ba4f048205373dd93b98c11da8d09d4afdad9fd1f2c8546152359793f592491444cb0425826ebfaa32f8eb340aedfe64230ae7b5d5eba5ad02b45a13e2b6e708ff16451045901832fb5a2e228c90acb8eaa82db59640510c0dbcbad8bd7de870519abcbc09ac7cebf668206d7510e6b19163b3a748c11512a277a0272823875a454ab971b69aab7b5c5c53ad981154f5c92233dfc723d138c14c0f34287b125fe7721e1836750ab592623d875133", "bb7c90941938fcb24dbbfdd6e6d994dd1879c306df8b6c434f101817f3d00080aac178a37a2d5a8d42cca8db73f6e74541cd995298cc1ab85cd661d9dcc17d37a4b6e2141bec96bae5dae3a7ad09ee077cb1f2250657f6b677958fc48321207c9f8f5a03ed5bea405ff1ff68c40e54732bf2033d2c08a6f201acc59275aa7c0ca0690673f3d54a4f5b79c13052a43b4cb4f18d39d461a3780dad6fabcbd49b5e0e7d2b169a1166c49e2810075737e14799b037a4ba92c49701f63a499e16bdee9ed9dd73733ee2a04f45e4cfeb1a305abf53e119592ba8a5951cafa2395880c448ef6cab8a0c8d2ec9891883f9e1345aeb8ec1f97bac6c096e7d543a0a70f8dc336b8cb95ce5fe58feefcdb6c80962e3ffb99e1c983d53941d39bd9fad38fc4ae5df763611e403fd534a80872e636058604b5499eb58470f90eabc608d49aad28592b509b25deefc0d9ede2ec7755fa17848c9866419abb952f4d8402328b063d9212935c6e7eb717a6c7ec6c018b16b0c19a75bd8f6efde423659c32c4416910be7ed991999cfced8345006fb0d3682cc28f8ac6aa731fa477a70bf6fbdda407102d87678fc65ae3fd0cb671a050d63982cdda34ea34265df134a184d10412a61cb8ecfdb0f6a8ffff67c8f7833446dc20907154924a642d746f289be18e25551b54785bf89b3e2731f50e8f24534bbbfeb70b80db94f506d2657dfd2503a1e", "172058ea72bcf460128c4ec12f51bf483c487f8ce82219a05c0dfc81b5cc02e68b570231fbd3e9b4d69f04927826505eef591b00d6357135cdd9194a807f4e2578942c7d49c8d2ff89d1d639f1ab33be394beb447ab6848c33a81d607d29839564e758814b207cac0a6acc185a2f3153ac61ece5f8c54acb4fb28276a1f00e42cfc6ab0209afd9e1f37b78cc27c8788cfa3215c4cfa1342c370767cb97d637670f7dd38e598a3faa9e9e4f2d445805964a1018708e0f016b98a11ed92e12bf6716b793b048add33cb68c04746433623c229598398fcb743e6e28193840d7f65f0991a2e7b3144b2304ec599081dc77dc43fccb51e50f3dc038f99f281a520bf1868282eb18e3d9eb9e97849a6b0dff5a5ca9ba9a7e9aaebbb7ae5761ed55346e9ed52e7572e57255cc60f048080f362c502a29e0a036c5bab0cc30ff4c74febf2127f06adf4534767e953f203e7cf7a9a7e0d83d5689bb0f090ce13d8e4465934766c26e366b9de39cecdd0fc57aca6fd552dec26dd1c724d01e08cbc1778217f0a4c10a4014fa5ba7de152bb55211939b331f7c2afb7778a5fad6c199de066d11dbbc31ea6b1fbee90dcd923d4ddcae1809d2f3e0b5f4c125bff40806d7db63b487d20338eb6b35115091f07185a6c9149634c6002965cdd82c24ee611c67a66a6ab10a7f3697b064458123501795d36d24b582a2bd185c577dbea420fd78b51", .Okay}, + {.Add, "9f9ec4580a906e0c5a840812791808bc59f7059e13c1faf42670500b9c2c784d1e712f181ea22d9e54c76118b54a09c62a7bfeb863dba9c28fc40ba3a5a6054a5b09249ae5dd5f5f10302485ce4fdd75ca627b51545d59eaf09f19ad6211a5a477ab589bb5819c4530b0c65accbe64e53d1a9e376e59bd56468829bac04fa026b6f7ff1748e1ade08854166cec4784b5c62109cfb92e2e3eaac2e08ae2d6e6ee45b587b109fbea24f85e1306d2d5327c249032a47463eb54ae01167d491551caff3c031a1ce8b4cd4af55b1e53a20239ab5faa897cf840f1e2679b61718f0597e13b20372bf0b30e9cea8fd2201a7484ce6df1a05a49d1c02c9338940e05d7ce02e7543c188998ed259eeda94fdd1608eab16cf2047467a165cb7d88f268ad134c11287e08bcc709bd1b48ea3c52bcba8fbbc0a7652820e9628298885c609d965a038363b9bb995fcb952800d20f2b29429d8e0a3f606c13bc31db6284354c4c8e59cd1f2e038dd4f54cbe5b6035bc6baa2c8b63dc7b49d4a3207ace4d8522cbb95d568f1130f79257d6329a4d218627477c4da0e22f8ff5a54cff3d3403d3436eeb4289b0b88d2cda495dfb68a1c517cd0d3d64f972cb1fa2654705d888f3572630c9ad7a759351d943efa9e4aa088b52775f7ce2295cfe2ef753c18b7ed950890be36a632b4cc4b920c6e3cff1abaea63a3f88cfde071dd65e58ac2af0d9ee", "4d88b342efc122f8dd66a219a80d98fc25b65711c9d83d452be2d2f5baaefab95b39ad0956aac03ad1cecc551b0c1c38c96b2755c8754b2348e3183d2822524ddba90adcc7a60085893d1e8eaebab910108ef981000d796e5b091d8622cbfa7b3a35c1843ebe3702629304bddd22eca608c8e00ac2cdf35f5e2e1ecba76c5616addb4a8aa4905f0e7383cd8e932b08ddb2c59818d797e4c9663d8982e338069bdeedd9acc0952419ed0a411e566f0059fd88920c8bc96460e13da8dff66153d010aa41cd2df618d421413454373a68e3e9d8d29ab379e45193e867c06c1e51e9ca3165a25f01cb8495d9a6fad1b6c4dd03620b30009cd8a767e05ce7d938c9c54f476529665b65c5e19fb81d10a079fe205e2a0de94ae13b6e0c33a397f5f9ab18a06d81e298ab09ad84292a2f6153f8067c60f7cdea992eee3a8611176c30827908d0d54af8ec8d62f785ae5c0dfa5c25e49333b9263e400592fbb50938f7de195537c37dd68035dc1adf93e679a1e478492c6c8d238db0c01c4ff4808540757add14d73f92693f9a09fe9d754a17b8a2e3d41b19a93fddce7afec583ae085edd2884101098a5accd326ae41413c2ed8a5e9fbf19e651e030c2c7dcb1a24789810943744dd9d664cbd8b92c7023e1a44f4169c687e51be708629a37987f965d6ea9924e79520dd629df5d510c96de6d4d698257d01d5f819c9bb1f905c5fc9b", "ed27779afa51910537eaaa2c2125a1b87fad5cafdd9a38395253230156db730679aadc21754cedd926962d6dd05625fef3e7260e2c50f4e5d8a723e0cdc8579836b22f77ad835fe4996d43147d0a9685daf174d2546ad3594ba8373384dda01fb1e11a1ff43fd3479343cb18a9e1518b45e37e423127b0b5a4b6488667bbf63d64d349a1ed720ceefbd7e3fb7f728d9378e6a1e890c6130811006a0dc60eed8a24a3615dca910e3ee5685425294432d62218c4b1002d4fb58f3ebf5d3f76a59b0fe644e74adecda16c368f728adc6b1d95387d243072254376500321ddad5781ab6c85d98af27e9332c436ccf1d13961d1cffcd05ae6aa679473957be73ea193522eb9657ee4feb3073ea5c6607d90070b0f96ffedbf48dcd3d7b12c8a5ea6be64b195ffeb5572136a9f72146bb410b29638219f3312ba1850bd1e9973ccce18d30c543904b485ed2e8cadaf2e1d25856882213df886aa53c1c4d7178d6e442aa7af04e2abda0e0ad1679def46af5e502275b7d0699ed785633ccac2ce0a6341343a6b6650c360d1f1e03137c26b9ddfea6021bbfbd8cfd373c7fe02b7b1dba24c13c699c15132d9a77bc8df7cb58805576bdd2413591cffd3280ee28a2b3ae0a73a0d21c84f69b6a51ca8d654cdea2fa1b8c9436a0e78e53759edf923fe6fadf7b575b8dc7d5a9ae3002434dc888a1bf3a3c1e09ffb669f72fa0aa530b6d689", .Okay}, + {.Add, "de57fb86b663f7f7194429bc8cd7db4c3cd710c199f954036715c82d59d5b015e4a9a6182b12c84484f7bbe3bf28073adaac741e6b5b13bc289b0b199271fe8ea7517bc4103988998ee20d2ce293d8344c9cbbdf143174c56da2642bcbda3f2cad070b55e3e2e9854e9d701d5a3fe281e401c359c965a82bc773c8fa69b6d3267c2e9f38ae1989a5274e108ddb15f78359e410fdc5d7e2cf63d9aa63678694b5c61ecaaab83a78e84d4b6cae340f3ba4fbe7219b4b52a05400a62cae0f5f6e0f5d0d46101b89270961154fb6e6cd3a0d1aaf40a783f13d26be8ed5fe219f36a6aa3c768d0aab2e8e26d279e2644c0bf40015be3e3f534bc575a1d6f2db52398057eaf9ee6996f71963e29cddd741e6c811b03f4dc77599ceb6571f0236a97532b18f5a0b96ef7ccbff3c880af2d278629632cb74bd98bb5b51f19c77955c01d0b41507fd1f4beac3549197c0d28f8cccf4189b5e5ef78ab67f4ed55f2645d4c06fbdc7a7f744ac0d9c23b5a786ae47aad09478bfa0efc8d5f4f1d71540e2c5197423b099f0d150f8b879314b2eefa31b735c4b831ec3a21c14da9f6a620c23f185ec51dd66284f24d454f08bfbd63ecca948d3b54188c77b26f89522003b0ebdd87e5e10513873f39dfc4937204dd4da2bddf314af30458112735d736bc123fa4df8f1ccd7cfe0599f84d3a53f11573ccde2e9920e63a085baff6c2b4ec38a04", "f35cf9b0b6ce7fc02eee2d91237100c9e807210c459a9c28bc8cdf4a827cf18d9c4eb2da1ab07cd5a7876a52ddf978a71f020654cb4f10d037be0b28cf6fffe42b8bdc524469993d47983b5dec54bf1126d029ecfad9b6a9c23d80f5cf0762c7ec0f353b28300495424299e76a905a41dd4cdae57d3292ca858fc1e7deb3ba21ad92cd903dd09876e4397628f65f5681be6d00ea88462610a066cfea7fdcdfe8fafcb2bcc6d0cad9cf64ddb9e01cc3cb2f16246981e6f5c949aecd78e1b073f3a83b1e650f12234218b76719af536a6f06c2fb57ed849d9bd1671ba08ff365fb7682bdd401d001d5355c67b84adecd2fea9d87b4ce803df6f3a7685d452423d4d4ceda1183d02fe3bf98cfd6c187279ba45c2e628f135b774a558b9312c94a7e99435c26bd3b1cc90e22f1901535242a0dbc993423644e32ebaaf2277e9b3ff7d0fa75971cf6ffb65147678aa44e7b347e265fcf266bab430540429a2efc809d8faba065ca54c49e492529b5c91fc358bfefd82a97bcb1d032280955b5c05afd2aeba9473c3ed767683e96dbcf3d19a3fa0f7c87d631eebfefc890d0fc55fce8f971f66b6be41c2eb44053b7e9c5d73af1894ccabcb8a1faa3b210a8f3cc7b42becf3666943bcb2cb044728d1e597ad85faa888d8817e90a7d7cfa0d412bcc1a13ac802c5cd4fbd354036eb7a6300988a5e692b9cf0cfdf2405105d7e6f54838", "1d1b4f5376d3277b74832574db048dc1624de31cddf93f02c23a2a777dc52a1a380f858f245c3451a2c7f26369d217fe1f9ae7a7336aa248c6059164261e1fe72d2dd581654a321d6d67a488acee89745736ce5cc0f0b2b6f2fdfe5219ae1a1f4991640910c12ee1a90e00a04c4d03cc3c14e9e3f46983af64d038ae2486a8d4829c16cc8ebea221c0b8786b6d1754e05185111e84e1e08e004407a4de763749ec11b7d677f0b43c21cb04a68142bff702afd4604cd39961d4a54fa26f10fe203054864752a9b4a4b79ccb6d09620a47c21723bff7175dac28ff5f19eb1929ca220bf34610c7b30635c2ee19aaf2ad923eab345f30dd389bc69493f5020765d552cb9d3ffed6726fd237b6cb498c90e63b60c6db05688f54600acaa954972bfb14ad2b632542a99950d5f799b08079c8ca3ef64a8e0fd098e3d9c8e9f13f741c8850f7d943c42ea79a5d8ff4b76de0801723efb2d856335f9848f17f95542555dff69680dc19970abe548df5d4fce0b03908450ea38ac7aa62719e06af6a320169f0f59e12d10286020b7c826fe2cbcbf6d6bc80af4f590dc04a3303b5e6220da7f5e4848d20c6b5388954443e59c16079ad2207ffe416975caaaa5caf4078a00974d9476e5743f204e40bbc43ea74fb28b887ba237482e8b8ff05780acecf01461a571f934a4dc2cf388425ce54160c573c97c4bdd709e77fb50720335b8d23c", .Okay}, + {.Add, "141a0d868ca156dd370ac5df9cd5b4706a4f45b65361a3ebed0991da6000873797c9edc0a714be632127a4a4d7a68bd6c18ff47cb7c28b727e092780cc8863261ead69a5afdeb4de72e126204cd4e76031d9106f55e6db47940c287d936162fbb8f9abd667bfd259235783ae22148a92d9c86ab6856051978b170d95b8c8a72952382dec81b4d3ca67dfb4e16a3d0fe2485c8b46497393e581db70492e45e3e71063abe51ab47656c92de7be60e6f0f547f1825ee78bbf00b257fbe031370797f8bb79c1a4cb3a679113fcd33c2e81b55c9d9a47b523883cd7abc962cc560c450218b36027f5d7eb3c7a834c8797f2b1c8cac3dd17cee5630c2c921aeb3c5d725bb6098c0af8d046bce5781029787741e549fe5fb897b468e2f96c0a9b673b20934a40bf6823ce0e1fe3861626e37dca3db9c63743a710ececf6f9dceda4a2c9f018765ac3b1347b577a16262ab0731084ed44ae24ecc5f499821f204054a0ad315ccd65e6f05e273b4f00fc5fd7ace3206a256da19cbf46c84c95a27a96c5d77ddbd5a86d9762384ac8c51d0a3e3ef7c7d68b4ffa604259a86391bde6bfe5c83796c8cf0e776e744e9cf19434859cc4b5164ff446400b621836eadf4dbd12ff6cf699e7e9253fcecb3725764a06e1da578917095daeafe84996a626706180ea885ac287e434c921c7e182eb97853086f79351c5902f9557e9dafcec1cd5be5", "8bf7a382f1837cd5c0b7777131af40997ae43ff8f3500229acaae42d7f6c3693fc58c4a426c1fed27a4fece204ccb3a460780cb0b5f30b6538298fe41cf3c5b41943c13546e856e60942c3a08327723e65560a2f02bdb0211962742e080eca385411d3af525081222a1e192fbe0c0982cf677887c1ef802ff6fb870d7c9eaa68d827ed3a69d12e25dbe4cf84dc4719ae4deb320b5b31a2df7e7f9367a18f3d8087464042b9bff6407e76fd13b02bd3f5aea6b3d43ce08bf3ab1caad008e323c7fa9eefcf78961243495bca16ce7aa881387bde611e06e7771487aed1d1a581088d76e5db73de9cc4df8349fcb4bf4146f842b700ab0926655700afd101100f56e566ceeac9b3fafcf3bce55dde5f6993ab4d60da883676f3db5962cde40b1755dc1191e03e677662f12be9e87be39f5ce8db28763238f1485d620856f90dbdffde8fd76bbd48c874e3a17ad1c82a56d2d67c7c69d2d8209be21636ed5fca624c9bbf28038dd23726753b5d68324d0405c88b0e6857c43cba2f3f8227e2abedde98b66d3ad514cfa2943ab54977b5335a0e0d8a5f7126087c89ecdae5d200b67dea54aae8d289dccfeb6a493150e7e9163c0e4854b02bee8896451f153259d47132276601373c90150818b90344cd730e9b57f70a844b87a45d4339fb2e75e945163fa4d10e6cae84b0edea034985ecf519782e074dad554e69ad33aa14851c4d", "8d39445b5a4d9243942823cf2b7c9be08189345458861c686b7b7d4b256c3f0775d5638031334ab8ac62672c52471c61cc910bf8816f341c600a225c29bc4be67b2e97cfa1e64233f070d60287f4c0b468739b35f81c1dd592a336b5e144e0680fa16e6cb8cc7e47bc53916aa02d522bfd03ff332a4585496facf7e6d82b34db6d4b701931ec7b628262cad2f2eaeaac7270fabfbfc8dc1dd69d4a6c34739bbef84c7b010b6b3da5eb09db8f963a43050325cbfa2b5947e3b6422a8e0bf694417a2aa76b92e2c5e9c26d09e4023d909c8e45b80599591ffae2026b67fe6ae1ccdd987111765dfa43934af2317d38c07214cf633e7c8614bb87c378f2afc3d52e0b222f838a6388015f8b3cdee0f6f107c9a200c083bff23a6988f98e8dc18b07e54635ec34e9b343d32a2249de51d7398cb6c4d9a67362572c3177f4c7e8082c7d915ed16983dbbc99191c342ad55e03decb50b4b526ecfb2bae58df63cfac576ed4f4d9ec413d08e8f04d77f84a7ed3fa91b0bf31de08ae9bc44b820a555a3c10942a955bee45c618e7419b485917498a8af31470cc0ca224731401b06cb4da6dce1775c37153b73054184a943042e2875fad53f48fef3eb7c88dc32735a5a128f6cf9fb5cee411f4cc2b5aa96de12c40d0887b1a2672a2e1dca45d957c0153bec550f98caffb16cd6c023202fe3ffd88f16323a6b04ea3e84ae378d6527832", .Okay}, + {.Add, "-37a33a230089f625ac21852f829b8d0247d418d586ccf795d594cfda016705dd120fa9559bce80b4c197b8cbf72d916549dd511c2f53a14476079f22c49d6b667a614762433dbcae1ff3d0a0acce3972b08997d3b2a21023971d72bb20eb7645c99e16f306665659b83c096589b8aa41f6ebb201802524c5ecd9a28aa9b4d13be5464d5567fe4778b8afb55c3cea9841964a464cf60890ee4d0c6e10584d1def5f94946464e31983d2075dc3b7c61dec7ac62e5ee435018e2888bd05ba886f7184360d4b06871e3f66be4797d7c8b9140cfc55d2e4fd75e18de9306c01a0d92ae234d733ef544ec359a8480a86c64b0817871e2d6d67a033d31b8c7f96629c99d12efab3f3afc0ff552e14fe4223b75379ab4ef1cd8c76a82d81cf8d861cc2719aeae0f97c1ebe3c479bffb2aa66cfccc21aa1086125b9ba206c69dbdb5b3686b563a4f90f31b0eca3f621973868983ee18cdfe231a4cd935729033e828f98f98e354f0a9cc89ffda6ebe0ae6a5fb5eac2140fc651c10f79a6aacc377da2c6fc75394dd7da2257fac541586b1ea0cdf3d4ed88a3623d7671c0b18cb5a7f68f8718006df243e90fea9b2b8c8682d2a571fbbc396483a7b13e6d3a6d2a20d0c47d17b6d9e710ae58d4110f69a3a0f42c7efcf5d685aedfb995ff37a6644abbbcf278e0ea68767648aa966a97fc65fdf16edf1245febccbfc7db632c7f0c8e597fc", "5ec1945097b1e48503efe7f897929583d5f16a2890153af033c8c84a47201aac2cc587e60c9090fdd2b65379c55761ae461f29600f8c2b77e4001b5f42aa8941711c7e8ffdae7222c9e78ff1369724d1a9af9e092214eec2e029a0539824e8d36b460150d878c8e1d21e26a6ed68cfdb0a48ef2386e0bf62821acaeee3e26373a5d250cce01731643d0ece4d37f990762c800c877098a4b417d612e4783d0057c574d07d03ae18d4265c5ee589d2157ac701a1e0f34bce9dd2dd9d5f63f4ec314b2a8bf211b017ba80f4eb2840c9a706664abb22331270b8c2e60b41a604fb6d7f81902feb8749cfe47d85702eda87a204cd9d806aed1966ca5ed33091db7f5ea5b135d4675fd406cdd195c7a34b01a3ce93029d3f6e09c824750145e45acfbbbb4d5050c6e6ab3f78da46a87ef39a9f342c654f53ea2bd9c73884b6afad4da0e2e7814c1c13e2ea5aa4d9e87087cbc2e9bf2bdf5eb35252828b5b692b8b97088ee14885029348d02029ef80e012ff446f269e41b98f7b110f919657da374b5d901c000d33dbf59ee08b4695f35a9b995578f0e95e22d3269c90dd9f00737a6664374c75452d736482e255c3b7f3015c02511fc5c189e52becdda3355a006a438d0e14d0b6c16c36de5843129793ac43d054a381f1bd30bc3cf18b78f9e63d3b00d3e2e9beac3a8aa9b8c288affde8867adae7bfd8f60e0703ef69cafe5f9846", "271e5a2d9727ee5f57ce62c914f708818e1d51530948435a5e33f87045b914cf1ab5de9070c21049111e9aadce29d048fc41d843e0388a336df87c3c7e0d1ddaf6bb372dba70b574a9f3bf5089c8eb5ef92606356f72de9f490c2d987739728da1a7ea5dd212728819e21d4163b02599135d3d2206bb9a9c954128643a2d9237c08c03777818e9eb845f18f0fb0ef8349635c63a7a9013c5cac9a4d41fefe26865e03c189ecaff5054550121d20bf78e4c3b73820f16cd0faa54e059a96c7cbfc6f47ea70b28f97b1a36a3906900edf2594e654f4e14fad734fcdad5a46422429d4cb8fbfc32fb0c8ad53d65a8143c99ed467f52fd857932f74346b0fb78e2c4d4823b2073b0130778a380c961274a5054e7b3ab71e1931ff6f331b85e3e0d4a20626f574ac7ed03313e46f5d48ccad27211c446f2c4721fa6cc1adad452171a2d83dc530ce231fdb6aeb851381f338408324bfd2d0e84bf2b62582aa8fbfe0f00abf97a65caa8d2793e0ed275b34959ad128e7b67ce6b9768e6ca205c9484611ae2b23559b99da41b49ee2ad4b9cda5808b6845fbe55cb4dbdf50e9587ceadf4c36de8301446379e7b6c93d35205bea0694e6613de233ed7fa3360b392fa5c675573ae9a6131362cd48d96ef69f7fc4d35eccfc42dd77263db9e514af2a804887f2f8814835f1e0134e2a8c49fff7179bc8a1c11c2a11894dbca1da357a004a", .Okay}, + {.Add, "57a32dfbd5335c0b73bc91da7c2055eb7d89f43f602d76812ee98bfd3bf5029506451524d531be72da463eeff8a94efe415652632e9399cd3f6cb95c8a6e99e496b4face6ff36d8fed750875c3ddac03bfc70920bbb2d7a6afc1c70bc5708a8eb183c1644f23c205b9ff185d6fec15eaa2dba459f479b7f5bb010c07842cf20f477cdd3d86da4e8be20cc79bfa90ef483572d0ec5ed93fed5e358807f0420ff0af8299444f5309783b18137979b71c8ab43fe15b3a993d553b5655455c082b46c97c08d1d7b207012f9a9754e2ed7dbfbfe748e0071a7ddc1c7a4443b39d810a8457efd4ae857c49948c39f715953aceec14cea09ed500a83b18d242e2cb0257931699c08bb29cd48341537aa1f6ed6cf5ea5dc050aacb1f7fc9d277d7ebfcef43c1d8e4246b168fa9482def8724067a70424cfdca3d7bfb6d567581a297189717d91762310174eb92d63208e1303cc6ca676d1a05917b39fbc97143ac4d19490061c80fa4083abf9dc8771f071549fddcaab77b730070d8db8f57c6f0c232c48564fb8d8fa92d45c625e95023fbbbad0efccb2401b70de4e48654ba97a202e7be156de3c66d17c72985a13cf44724d887f068c1e087b3cd21d3254540deb6cec49bb93ec32e37a81b009abda96ddfa93cdf3ea95fad1eb84aa989021c8bf458b24e397af4f0e1bd7a5edb5b95dc7376a51e4ae5ed7eb7f61c4b7082b7461fdb", "b7beb79b14cc958ac65f3b87c178a2c64540b6d17dc4579fd9c29088e7ba3cbf8e90e86d4ddc27f96e8da7868979d84ec41f0f56a9fcfca78fbcdafb7e10d1b6b81a23cd568ca96861da5cbf36ee776cc49bd29f7931f63d3e21c12abcd7c4a4fbb3e29473a807cf7300641b3bb2319a996028bfb5f2bccd72f5233c6ce73e862152f2b0357ce19e735b06cf2678d3896fe784d5cbe173c3bbccf6b60718439720c7e882df1d234aab9698803fa2da7454b17f29fc30da66dd6fc1a4eed78669bbf3ac96bd4eb332f9e798150e7e8bea549a5411e8cabbccd7a00baf2f1a1a32675de91d3c86428e4fcd57f1c5c1c5564a0ef7a0b28e400133313211837ccde20637ccc0e3bb48b8193817b2cd3e26186c3a4ae8fdc6eb9d4beef4cea1b833e85399dbc99dce791f00067fbe05be3b4c82c3a7f6decae91d651c666d446edb82486812496d58c4ee64cd9eae5c2371f6217b981eb2058a483773026d4b666eb0bab673954828336fe3d726cb2277daf1d3e183c9683b61d5a717aca1cc2137875baf74550ec0da4b976c10a1995ae4f4561acc0fc4c0aa19441f59a81496930f711b1433f8d38ab8fcd02916c86168c3111d755f8249f833737721783198728170c222979e67028498a4d52eab7483673015f041767c98c66e0b3b5d3f36636ee7254da6939456efed6399320aed1c74c989faae1960c6c0bc4dd75b852cb601", "10f61e596e9fff1963a1bcd623d98f8b1c2caab10ddf1ce2108ac1c8623af3f5494d5fd92230de66c48d3e6768223274d057561b9d8909674cf299458087f6b9b4ecf1e9bc68016f84f4f6534facc23708462dbc034e4cde3ede3883682484f33ad37a3f8c2cbc9d52cff7c78ab9e47853c3bcd19aa6c74c32df62f43f114309568cfcfedbc57302a5567ce6b2109c2d1a55a55c22abab3b11a027ebdf75a5387d04a81c72e702cc2e6aeabf9b959f6ff08f1608536ca17bc18c616ea4adfb1b0856fb5689500ba3429822f69f16c09aa14819cf1efe539a8f41a4ff2e2b79b3cebb5d8f1eb0bbed7e45991e8db5700253623c641516340a96e4a04546647d039994e66816f6de58c9c796b2d6f3513856224a8a94e71b6bccbb8c74679a430d7975bb4adc2398faea94eadad8ce241c6f305f4f4a9086518d272dbeee705f419604129ab9e5a39d9f7a3d0b73d53aebcebe30538b7970582333c73b0f7b387f9bb183ba4ec306e2f819f9dea298d24efb08c3b44db3bd2ae82a70468bce36a4be1146fe29e6a07915d91f9f1bd56a0a165179733c677b7fe28a5ae62ac3895f72f308217bf40a2802655ca53bca88d9b990dde2162d1ac00954a46bd72772950355ddbd661953a2cb3a56fec54e263106cf52eead629b77eb8b4c45f5bc257c799738721888538ad67c2748da0c98feb6ea8459406df7eb6d89947de3c72d5dc", .Okay}, + {.Add, "93a654ed6d5e4c64e5a4c9729a359179345dc03df84f66e308ee16db1d279d7ce7a47389635d28e4b1b1566c897dd8ecb45862f222151ab9f6cf89f0a8016d7282c98cae7ee9eb6369f69d0d813ddae1d76d445bed1ecdba8c77f813a7825cfbbf6021d46cd2dec465196381fbf69a9ec6f918882b592900796523e63a3ac460df4949063fbca5b8193abcf1da750bfcddac1a5d40001317e52d700896deff8a4e250760d63eb5ba0f220f720f20c4dc3b3bf1f213586f83437ff5415af310437458b848178fbe126c01772187c762213e9b067f033a09205b6b7d29be04df46fbe3ba21fdb8ae96c4317e29c5d115620d0274e3a2e876c5b3e5c88616e0fa5e91eb177a75940bfaceb0e2253c3f2b8f6cc171c0b18354d253efc457fe2c9e03e8490b6a82a53cf7ca31dcbd44aa6a136a1dc9255d48af149bb13a9bc5599306b0cc757cc1932d89403bfc8e94aee9bf0715c80cda44756c0376b1da0810a81c455acf5584ae906f3dac105468a6f159cef6e3e79eed2695221e74552a65e658ce507580b798faec7c499abe15b695e9c7b0bb5462efdd534bcf4c1c3661c33b98c438c3fc9b939d20579c71d5458e6ff665adbf4bb1e4100cfa9dbc4b0805af1506401f24f3bd69b50753a46c9e214319a2bb84ffd3bb11a03991bca762f2edee37e75c84b30cc9c41233aa9b1d66cf11ae55a08114086b58f6938fb0be22f9", "cabfcb98e9bd941a4c4d2b9aeb73c0b1f04ecf1dad651a53252fdeff39b6d88c86900d367d134e6bab11dc92ee5609b33baaf4d55916a0f896299693241ad480856b6021762dd6e01aeed741aa9d4b394b183de41af9314a8d65554f36575921528e4961ac2ca8d9b27388815535127d0b2bb5171952a47fb8d18642f4efb7f05dc912cbed8a96300a95adda764e5dc2294af3f1fa71855487e2d8e3b685fbc9c25bfceb602f17c971df68a4e68283c69dd95217c992de2407bc0c7a226aa0d765d45e50c3f1cb39611e0e246be3914649570777eea07ba528437e34b5eace28b9e064b0370986f7febfe0201c5de4fe19adc1a1ecd59140016d21093eac121b533b2ca2d78afeef4f4d7251a479a28b1fcc386d90921bf3e198f562844986c521aec9a06dd3ec863c9265ba6f902749be5205c6234ae1b2204f7c6107d48009889844223594ce7ff7bc6bf81615a63fdf8c37e058a47a2b31da2ced1569069e140a2491f79b538b299e731a8d4dda43f9bd18bb91558429189bb7b27494b1498961c28196a0018feba961e3ba3847043a3d3e60741e99c352c92b8c1f0ab908941fca67e1236a420266df47512dd41f371ce92ab5b51178068d58d1c284624e25cf71fd4912dfd3ec5d1ac3a04f42598173720e0e382074714b2511b30d7028ad6563d3c821245cbc614407a8b877ed895a286e42ed2d4b35245848bf5367ca", "15e662086571be07f31f1f50d85a9522b24ac8f5ba5b481362e1df5da56de76096e3480bfe07077505cc332ff77d3e29ff00357c77b2bbbb28cf92083cc1c41f30834eccff517c24384e5744f2bdb261b228582400817ff0519dd4d62ddd9b61d11ee6b3618ff879e178cec03512bad1bd224cd9f44abcd803236aa292f2a7c513d125bd22d473be823d06acc50c369bf06f70e4f3a71986c6d1048ec4d64fb541081044c366dcd8381017816f5a348a2d9154409dceb4da74b3c01bb7d5db11ada2d1698db81894bcd1f8545f3aaf36787f20df6f1da84c583aefb5e73efad6fb5c41ed234c2358ec2f15e49e22efa6026b036858fbe0805b552e98f558d0c79e526441d4d1f0aea1dfe5476e0b8ce1a8c8daa2e421570c63588b9ba827624c909f7d50af079297e06c44277b43a915d286fceeb809390c6bc00b6fccd2e13103964b99ef727fc0937f86886aac48ffee6a1ffed32e8ef973550dec71d79aeba5964f3e77c49e3fa674a836ef5f4cb9dc8b3fca33042aabe3aba2c079efa97a257b238024e38fc7c67f2fca1cfeedcee01edf9b4d70e77169e9877a8556c7c442ce4032bddbefddf22be7bb92673628f2d8296ea0166f5881387f68e0d8c67fd3ad5b21c6e069d3da1646e680ced639c9b162d930e0bdb861184b6ce5a7063169b9d4b304cd43126807377b243d5debc9b087e0ec40135b68e1aebd870118ac3", .Okay}, + {.Add, "b73c9a3eb4bbfab7ec4167c24aa43e7290ae9a939aa5bdfb15029cddbd8714dc3af52ec7bbfdb0f294dedbfdd36c9c0fdaf6f53ecb79c1159da27949fb52c306734ec9c681d71adf7d46726b29e9b4919a08165fb446304cc7c4ec8cd656a58373ef3ec0a24436e68ece052e1d8d76571fea58039b901836548a62e60a52b437e5814ea5c34d98660ee3d54f88c0d67ef385f2cc0c429bc5db1e9a626ac6f35ca6a7117d0e4026531eff704d7f40717bc983def6e088fd46b3e261ebf509ae7990c0bd5e2f3710401995cf2150bfe1b5b56d4dcfb6527c74e97456695f8d953120490d2cc4bc4da1938c7fb262dd739790d9a1d7021ca385656036df13f2a348a46d569e0f064d9b4838ff08e1f0ea1aad1a143c3f19dae12ec8c01eeb477be6a08bbfddef2b75e802515d7083c9d8160e2e38950a6b55b66f914fdc635905ce2892660a17d4abb1816c5f19ce672950e9f83062955a8135b2a75a5d4b31ce6cef69634459916d9b2235425a60adbcdd445accc56e0c32b5fab377bee98d4e5e0ceff32ebf4fa0fbb9f91483e0caa1e672d0349bca8ddf43cd1d3d7851467085cc3ed7a00f3fd06cff351910fd54abd5d0f596717665484f76d3be2aaba35f138b3bc1ac0a1b6299c457b238601ca0f3b7d54285c2abc6dc2fe09265f41c164238ff28e35c0f8f48a52a858e0f6977dc8618dfb314ab7d2533951c49b8cf6c3d", "1c6aaec93078b5ae35c62d4e8442f8dd719e25e68f9cbe30d2aa04313ed5beb277ae497bc61cca62b7714c4bc29b7768d0692aadc235e399352bf0249e5ec1feac5a619b94ba3d8c03582e94bc5ee3a3e303b08c61db4afe7500f1194296bd4672420da064c1181c598356d67565fdc0c3a05e2c91e6340f63b1b6b446ebb25575462463b834b705cb9e4ee366a0f10e8012d3d3a6ccbf6d50f6f3fdb889932dca4eb8e31362fa1461353ac173b739943a019689912cfd307effbc0ca29b1d93875bec32f2d89e141ff137b949595b5e7949cab436710544a509a281da53c3cf0271b494b8651cecf2fa799b7e5f38c30e18f05017f0810cdf478f45ef64bb7d52c1c7e502d647b820243eb73c69725e412c1e5de20f24093f2dacf4b444b9678f88e099714e16b7d4b44cde554d2dcac2af9394b37491ae0b4451c7a87b1baa8b24420ad93c83f64cb6a09ba9af77cc393f4ecfc2143e690a04d02cbd272eb11872aad324bfd2f43cdbcb1093e03e7bfb7c6f16f99e4282a9f5bdeca040d0ec1fa8597f59443908e91fe9889905358b947583ca453fe71df11a4f73883590ffb927bbe90b903714d1c8391e44b1c9fa65fd8f97cb1c961dd5b87c7f03dce2af7694f21fadf4ecb7591b7fac8fe031935d1ddba73151e0dfe602d44594f79339d84f8028914b3ac02bda2fb75f5b6c2efb27c5e061e43e8e2da705adafae727b", "d3a74907e534b06622079510cee73750024cc07a2a427c2be7aca10efc5cd38eb2a37843821a7b554c50284996081378ab601fec8dafa4aed2ce696e99b185051fa92b621691586b809ea0ffe64898357d0bc6ec16217b4b3cc5dda618ed62c9e6314c6107054f02e8515c0492f37417e38ab6302d764c45b83c199a513e668d5ac773097b824f6bda822432ef61c78d7398c69fb30f5b332c158e602350868a70f5ca6021a320678034ab0ef2f7ab100385758071b5fa7732e21df897a4cc0d181ca991220fae54398706da9a193d142eb71883ecc381b98e7df8eb39e1590022bac1c17d216a8e8686f94de13cac5a9ef292271a0d249244a7c62503575ec5f72f1e8311dc9553685d3dc01e5a5c78ee46329a2128feea6df66d139f8c354e3014a07760798c9fd705aa4ed91705e0d0ddcc29bddfe7647ad5a1a40bd42178b3b6a814f1112fa7ce22ffb57816a11d23377f32576ebf9ebcac2a8a0858fd1e07dc0e177e51408f5f110d6af48dfb593fd73bdc67aa7538a4a935ab89ce1f4a2c984cae1893da04a318fe0c79cfd7720745b8660fcdc661be378cebd97c0185856693891ad00781d0fd522f420675d036f326094181de6d4c8c3aa9af8041c301d0b3cbb8104f511d7331e4effcd28714f31e2cf3fda7bc15e366ab8913a97c114ea90bed5aca08d104b5456ec4e40b8140a593768fbbb3613c21f7687ddeb8", .Okay}, + {.Add, "39e0006c197e800dd1e7c775daa9450b00ddf818549dd37e05882d78ffc24fe653c122f2e9fc9c55d0cf180fa833a21c5c187edc135bc893a7dfac3f3b101028789821dc4bbb4e69ccfda4d45ef96b5b9e0c89c9622c2aa1c50aa772e2274cb31859c6bb00d8a0a1cdc8045b6e5100d1ab9971ee76e7fd98d38a2fb767294d4cc278c7feb1c16833ef99780fa80e4bccdb92c38d48ddb89eab5da876d7a1866704a7110f95b8244e055555362679cfe0736d35c6d71065c135ed214926fd9ebac81ee172c053a384b9f60e0c2c8f22c8bd5fe8f96160efbf3d160ac310bc223a80456ea97ce2454b63240a65c81e5026975596de17aeeb7d03465c6a294b78aa30bc683041222cb5c335dead50cb14d4395fd7a8989564785ef79cda3fcd893838719be781d4a3826b0b99ceb4edf8811c33a798ec067cad42abfc73283c1574c36b34053ce2b48cfc171bd4d74262652e40214c9efc7caeeee730c89c907142e1f2fa26d8e9e2780cf1298e2d9bf3d1dea2c03058a57e77553b432aff117951aeb1c005db71cb6cc7da2f9ee15c24541b835eb1033a1af5653af31037302dcc6d55019097b7630a6f2a2812d64fdc4d0bafc48707cc5396563433453b28410ee9de542443f10b3c3fbcfb5c1d11ed1ff1544c7c5e9f3370e8fca39060f2c59df809010063454043dd222c3af4688c081df269d88cffac04575eba15f684d9e2", "8fb911228e9b5f29a05f70c48c81ba9e03741f830d6aa11b0cee3c72b219c1e19491dcea305c644d96bfdf381c64b2fc435b5ed386a117e0dcf89baed9a814465f4ebbec036b1d09670656ac8e6254d2cc703ae427aab7cb96f10210f00116bd908b6b5efbb32f330f00c7c5edd19956aa8b72c0c256df743123510c4bba27f5bc4c33ed46d956993c9d88ce2aae8ee80bc6c3f83778fee4a5c056ac644f4f8dbe89f3950679ea17f212b9ba413bd733210902b0e78e24e91833a53d0d72db14feeea07b7f267db8adba2437c2bab50d125fa916f6742d75b6d6b32d77f0044ba7ebaa9f704e95d484b8f43da43f2b2db9744427517222bfa4c5d4dd5faf77e34f5a90ec8a4b5eee4308a2c693efea2008753fb40a3af03b27aaaf525e081e6b9bde473cb9513133e5e26a4c10ec7dd6afb540f239e002eabf0ba291a723e57a779bd79e6482c4c1727c7a8d5739c3617eb3be4818723d403eb9d739a28780fd991a9e7f213abf1840c2e4658427c4188e56149c9320b52884cbc5f5286414de43be2ea92f45f58a068c8c03a56cc77bf849da531d5d46bc0fc06fe5e3b0eb352530e59a079a1fce541ec0b34266dafc4867068622312205b3786f23b3431d799d10f912218316038eb94e32899e84e92aec64ea3cb3464a914aaf7e4bf75f33403a4472a994ec74f0372c24dbe64f91797cdcdeae357a8351df29758af66805", "c999118ea819df377247383a672affa90452179b62087499127669ebb1dc11c7e852ffdd1a5900a3678ef747c49855189f73ddaf99fce07484d847ee14b8246ed7e6ddc84f266b733403fb80ed5bc02e6a7cc4ad89d6e26d5bfba983d2286370a8e53219fc8bcfd4dcc8cc215c229a285624e4af393edd0d04ad80c3b2e375427ec4fbebf89abecd2c3700ddd2bcdab4e75987858056b783511dff233bf0d5f4c33104a49c320e65f7680ef067b5a71394763877be9e8aaa4e20c686347079cfc70d81ee3f7a213d67b03243ef49d7d5cfbf921057d51d34f3ecbdf088ac268628311948ed30db1fe7dcfea36c5d7b5450c9db0569210e3ca80c314788faf08d8016f91ccb6d8ba4063e8173e4bafef441d5175ca2d054b386a24c2c9dd5a7a3d44fe3243b25d4b650ee041ac5da7657cbe8e88b25e67f9801b79f04cf5ffaef3b070ba3a165794e6e9396622e7c25c6acf3df94b76eb9ef2da108023f17f2407b0d98a5fa24a1904db40df3b1c3b7ea6cf8d4ccebc6339fda07092027758e2ff26feeaf0ab7c0f6ce66bba286c8ebd013cd3904209761b174fb62f61ae119019285e72a9f5182d8c348e8c618b6b7495416cb0d29fd759c09aca268ee6b5e8886ef4d366574213fce76498ea6b072091c40b1669b5279bb7a47530eacea24d1384345730cda2cb8cd59585fd04edb99976f46b73b352687a93de38b817b41e7", .Okay}, + {.Add, "-566481d2a275f5c9ccf3a4d9f978ff7dcb722eac4a4b1a16347532ae70020e5d354929135f15c3d033622ec271c3041267ca9544786f186fd323541e7909a2c190da9d1f7658eecc5e1b62254d2c2c4f5fcc14177ec7b3f8623bbed9fe8df8436c60ae8a601ae126ab22170d92ee371826edb1c6639c6c727ae26dd3a8652d4887772cc42182c4a5fd592993f0cbdfaa8138d292bb0c624c5725cbd3e3dcdfe847643ad6764f413222d25e9f4b45f3e4dd0bfc57f7b00925779c572ea89ba77e5dbf4b9f1109bb8a55d4f08bc72b323b2c29bd63a8fbee122850579fb82d930427e0d811b823b50937cd4baeb9e943532517a9912088f1e73d55241fecc0a62e1bb31bc9f914a47cd9c54da97a5b3f2bc704b050ad18d9c4a5653f5dae5c6e2da9c27405271ccab06e63fda468cf238b259975654db5d910deed4bcebc41412a66e3ba92e91fa6805c9813e95cc3b614172035513de885051cbe3d1361ba64d63c95d2b83b91a6adc7e31685c44287c4bf81be19b503ea181974d9a69df28f0f8e9db1838a2912c050014391a8df71808280395234070855021b3301176c10a7085e153774e8968ef1a5e09f1388f795bbc3377b5a86f55394164358c60cebf3c557129c92dd3efea6e933b6fac59bba9c2db84b1bdc49ad61096304eb626584b238f9671f9a3c924cbf8315153e86fa2b034c3a1aa4ecb7e106156b2a449332", "422d753c36b51cf8d839ffce808d353ad59e00d41a4e4184451ec0c6c7d4c0bf86ce29524859c43265d08606bf23545353e958757b6ae056faad00ad54bb1626d70d3b76ff47f7e7060ef3149b4fe5b27616b5f008d48b203d2a3041ef20d2cd084221edcbd69409f4a2d58e2b7b1ebed3ae3dda8ea2a602d2067f57ddc62924db6011d839feee494ca583fb9d975ec0e169472f11349b75de8850e89daf391590d212ec91ac10d34d4fba2d063f20336ceb07b3ece9bb8ebdbb5e643c6f33e2493678355fcf1d17d581532a2d705e21ecc6e4574205b6fe8ead9f8409375326da1f84037c1da84240a4c6bfc3ba7e201f26fd5b565f747d35b914225344271f42c05d0b694a10ab87e6465b2451e838100ba556cbc4fff53d757b7f42cb9aea0a913460ad526bcb84ceea9012b3b5b4a7798190f9cb3fb5b6d76cac06b754005de750713a4d40cbc9040048d1acf6304d50793689a66374ade1145f04a362824b8ed6039fced040196675a43fd2d322e352b9ad3db9c051d7d405108af39fb2ca8b7e420e47613891441ac9a15ac9c0b8ee288a2d492727e3ca5240a59b7a460aea6f2db2196573efddbb236514132891237140108c03092d532348c7b2b5100df7a5f00e2e3abe6975453b8a46e1997c85313ce70798eb0f351fb926b07670dbf22782bdea4c7c0c3ce09c382973891feb2c5f86180240a6a37e14ab172227", "-14370c966bc0d8d0f4b9a50b78ebca42f5d42dd82ffcd891ef5671e7a82d4d9dae7affc116bbff9dcd91a8bbb29fafbf13e13ccefd043818d8765371244e8c9ab9cd61a87710f6e5580c6f10b1dc469ce9b55e2775f328d825118e980f6d2576641e8c9c94444d1cb67f417f67731859533f73ebd4f9c66fa8dbee7bca9f0423ac171aebe783d65cb0b3a598533480e99fcf8b63a9d7c6d6789d7aeb462da6d2b69227e9e4a3305ed582a4724506d3b17020f4a40ac64d96b9e0f8ca6c2c739c1488d369b13a9e7280539d6199bad4193f62d90c66f6371399a2b81baef63fdd4dc1540e3c060cc6f72884eef62ec53305f0ac35ca297d6a079c0ffd997c7f0ed8f2bebe8fca93d151df074e560956f3b6f90af9e153d9cf67efc3de6b90d3439f313fa479ca5ee4e9951314561b6dd67e1ff3d453ea995b2815df22b589ed2a08fc6a21aed265b4939413a08b16bfe3c9cfbc1ab44221906edd28b45d170253f106fcb49bc2d66dae7ca0e1846fb4a1dc2f046c774a29c641a0d49612feef5cc41233417be1b187bebd28c80784a7bfc99210c806bde12d1e50e0c071d09660fd73a609c2cf311b01c8257bae74e46d2a9fc63b49faf24a66c3200ffe5a36e3b75f6cac84af04403d73ee7b707eba211fa8870e34d4b0c251d4434bc4b1ef13d646d1e461aff0164082a278dd1513710b181fda948cea773a6297567f2d710b", .Okay}, + {.Add, "a22e3221ba9fa2d98131afef2c80f622c62ae567b3946ff1bcaf724e066bf66386b0c9c1cc15372ef348f29232391feae8e7900b1b3678e0e2a40c6d2a6118a2014ca6e50384ae64c307c0188db85f978a96908a41d2de29e4aee0f411a3cf3830963a59ab43c6ef7c5b0cfac9c2993bac958c4166b2995332f2a135351391a243fbf3f29aa130134a0556bedd0306efa69e549d5072138813aaf84f6f17c02c55a953ad6b6e6790406a113f32b819cfcdd76250466a39aedabf5a158d61636d2c92a84b6f82d300cba915d12e92cb60eaf5245bcb4954cb9bfb70dd794b4f11703b0b693b9a4aaa2dc40f87591b8829ab43338a617658c4b4f68d1c3d9eee6c1b425ca37a9d48dcf101f6f7a93e16ce34f896b8045bd365794b52cc4f404f557df0db501fd10a8f84fdc5a192f7e494966764360229369847cbe088ab68f9c9dc73dabc177071907c849c1c0bb7590363de2059b2c6d27fe6d224866696600fd89494a38406c22db87a65e517a2201d4e2480781fa5609fb7f42786e869feb55c5c3629dd42e79016e012a5e9ffd885b81369c2e01c27bc1e48d1db11a0907115da6be941836e7f86be1602f2031fabd63356ec178becead46261dda0112b5d1971daf4a49df4b12c8b6e8a45165461f5d6f03f7e9c6089dae87096085f06ba51bd343368f0dd846c04bfecf61fcdcf644a928955336bc2fc6b1527c7ed4165", "5a4c206b6c4bef89d7777355ea17d08309be6bf8a7b70a4c3ade138920a85a5f2427ee5a5e89f46adb1472b11d29ff8fc20b8881485a97f55fb90078d66e42139dc1c96118e711428ed6280219a640e06cb14af6ca4f7c8250417368d5e4c14920a5b893bd813046d384f6cf7d4e050661b078ea7392e79e21299b6484bdd3a3a65602a4612e5dfe746ee7f6d50808084b31b6b34ba527afad726e6c5ebba0b7e8f496c12ba0f6d54bac9d9700612cbf7874849f30b14a5dc05c1dc390a562c868181492385e296e41de826fad061904e612c6f6def6e7338abbf0c4d58639fe56cc2e5a932e4ac3f45d0284a6d3aa020cc6bf49d031617edf809ae692b3025a1c5bb7e12a4aeda2bc19605e05b28380486cdfb72d97b2d41b4384a55d4127b3068692dea5fe8ffab459e57342c2d2c4cd2037eadf8fa6c84dfb80597e1d6000c9078d2fbe347177c1fb939e6c2dd01c66976ed09c3151b09297ac9784a21d9ec4f9ed9a7ec5d20c5e791368705659f57009db1acdb7eb9d710f6fd46647e712dea67a65129a204b10dfd0e2f0542a4f45e3fdced12823a7cb5619083c0dd8227d15111cd77a2eee2c763b0ed4ce93a48e2622be94da6a496aec5422a981cc8639b5b4bfb0cab51f9a590df1b980e5ba5d13a4dac6732222239d950f8b7b8eb51c66e3623dea0a4ef00c4864f7ba0f1d5a853a03d2ead7e9e2c9c836e038b63c", "fc7a528d26eb926358a923451698c6a5cfe951605b4b7a3df78d85d7271450c2aad8b81c2a9f2b99ce5d65434f631f7aaaf3188c639110d6425d0ce600cf5ab59f0e70461c6bbfa751dde81aa75ea077f747db810c225aac34f0545ce7889081513bf2ed68c4f7364fe003ca47109e420e46052bda4580f1541c3c99b9d16545ea51f696fbcf8e11be743eb5b20b0ef7f1d00b509c173b37c11d66bbcdd360e43e9dea6e970f5e658c16aed63319468f464be6ef771b840c9b1b77d91e06c63594aabcdda7e0fc6f0d879840db98e465d107eb52aa403bff26b761a24ed1890fc70739c3cec8956e2221120bffef322bb809f2d431a7ba4394772802d051f0c6379e1484a4e8367fad1b5755aef09a4e7d65766f31f38639948ed771ac81770884776e2ec5cf9a8a3957ab14d5bab75963879c20e1b8dd6095c760e2298659caa57b67ebd5a4e3083e802fba77e5291fca758f2a4ef824307969d11deb387dae9d8e823e02cc943a16f3794d87f87a12be2e5b92ed5d4c3d2903975b4eb1e5c83b02b08eefdd07db27bfe388da5402d4fdf76791b1444b63e99eeae34dae689392ef7d0618fd9d6db3345111c6d1b350645979aaac6657343f4eb6004992f7e353278fb45568a9d0c6e47c7bfe973a1c52ea951a450f82abfe8605a593da956f6e241795a6dae7d35c110851edd9dcecbecfcc8d281e43acdf34dd5ea825f7a1", .Okay}, + {.Add, "ab7c37d8933c370d72491a3dc37ce2284664456eb09f47e6cf3e5a348943c1bbe0af74c7f6263f56d5ce02dc8783a5af8521280252b82414e2270fad33cd7d2f82926fa1984d130a8dd146f090e4dbf161d87f3aa3b840d71e8bc60c91d52fb7f941106fe01fe1bc72094316f835b9d4461536f3ec0ec7c486c416db60da0a94e75028fdfa191fc474b4cc6d79f380301396cbb0cdd9fec1ad05bcbe33c542e8c6eb820387f2b8a75fce18336de068bae20c4465d94bcd9f05363f9f3a82e720c6390aba51e92cc71a5da4dff1da488eac0940d9674743f396f7a62f2947778c8c76d584c34dd767b1e5f88473f49c63a1a1066ab1174bb73e49a8b5e4abaf875121148d3ec3c98195feb913a6d78d22f3df455ffd39842205ac7c0fa223cb1d5b1425fb09efb93085d36d368ed035bf6ebbc030bf96fe06c4b9039a42e83726915b3e5796d0f87b23ddf8c68f316957cd74a70ef939da9b527e037f88098cf2d60d8f5872571a925b7e4c63b80bace7178cdbea40e994e647d54a0151884d8e5806a2d9a78e40a9b76659d885726870c433b6b2423b9ad9dab930b80680bd22cf3ef8e50c7305c515750e45891791c1c15ca960a3631228d5c9dcdd2cd42e6e816ea900f407f3e78c5c1662dc2632cde79dd63dc4cf29ca646eec84b25a789e64d9d893c828ab5aafb69a1042ad83d485325dbfed4231e6852f56de77ee3e68", "e9765b2333e2118f821fc97410a27713866d32c1a18cf40a5ac6e467f9f15f9dcf45a7eb85bba8d7be965906c140f05b8b7809f70aab48cee06c2c69ce401df12c4d661aee92fe74d65d29dd66fd82d8b67be2307b50f6a2593f233bf8f41cd7040470da91637671ef5b48fa670e722c870f9e4422aef99ad34ef3d0c03cefcc6424bf9afb35499a9156dc55869c756d36feb35fab396e4ba0786c97f60c1b9c11730e874803a2a228e97969dac8f6ec5b907dbb8e60b652f287557e4c19faf1d8a469e8f828c235dbf29a455448927287b2f7fcb3db5777f0e015fd9c4991cd42ab11d68a95fa11e669664936c8fbe5eabb4254b60df69966db11cba2da6cd5e768c2260c3546c3ac85591dc2853c28320b55ce95cc5db98f836bd3a147412cb4013c51f90229422bb5a21b9d56e8aed0aef099d2faa3df8233324d4aef5424ee207726ffae87486529c50be3f27ddf67acb0258dff438524ed45971cef5cdf9848223ea70491b90819bfc27d772839714fcc079c09d89aa7931a47ef027d43ede123052f1c939f687210486051b785a0289b7f5c820265506a95a701deeef9b1345f9579be3efbd63bb2bb0e041d4af15c01cd95b0775ac99be51ae0f9e9a11e4d6a97039ac1e22688313c1d39a31f0d1153321ca6c255278cc0c21ed053b3b9fc6fb6d9522f57cab05db21f0546f83f4c7dba718e2a030f76646ca0d2f31f", "194f292fbc71e489cf468e3b1d41f593bccd17830522c3bf12a053e9c83352159aff51cb37be1e82e94645be348c4960b109931f95d636ce3c2933c17020d9b20aedfd5bc86e0117f642e70cdf7e25eca1854616b1f09377977cae9488ac94c8efd45814a7183582e61648c115f442c00cd24d5380ebdc15f5a130aac2116fa614b74e898f54e695f060ba8c3008ff59d4a957f1079136d0d4d7e295629d15e84d85e908acff65b4988b7919d48a95fa73d9cc22167ac83f1f7bd951d869ce2129edd74a34a11eefcf6503f254622db0133bc38d61b229b6b87d7bc2cc5910959cf21e75b4de3d179984f5ecdaabd98498c5c48bf67254250a524ba8187861c5d3889d6b34af9104542841231695cc94b25ea9b2e9305e1db952fe7e3436b0c4a0f15624d02f1e272b1890f522c271e6e3f6ab0ca9291a1e646ec35e78dd78b4b7f7bb57e967f7fc38907bdd27323e7373521573487391e20776b4916a4f8e9d26e55b197195bac4b63980c263582d52088dca7f1dcf36d80ef686449408acad245e7c5ded6aad4491fd86a20e5c41ff6645c52319ebd9d3f2b23c65f085fac1c8073587a863144c0ebb0c100971baf0cb2b8ab2e391389839f65c1f80dce180f9fbc1397f7a2b5c9b2e4479ef95fd5ecf4af296fe175ec1f8bfbad46d12acc521ed6484aa17adab27a66f7c261b2caccc47edb7a5ed05be994a5bb4b18c13187", .Okay}, + {.Add, "adff4ca04a1f49040cb8c46a8a3d8addb054cbc506080a2841fcbd540e8544cfbb060f5f188c9b851a95ab03e3cd8083afb103dd9c1b8a42ebe09a1de6c4fd0bd53c6ce7a6c97a13c4d89cd2b18417978b006ba14154015094ee438e0e34314a71abf0304c6273ebadfbfd5519f5e98d27de2d59961c3f9f5e2650690bd3c87ffa219913ea0c6d1e9275a4bcd859aca5d7b518abff6f2d4b983d4b152ccbced488e6387dafd2b798e685709a87a20b009a8e757a6a099d4c95712b09aeede02fd56068f20db00c3badafebdf19a91158351a2689ab1dbc879bd45ad083f44a4d1957ac7c1ce769374b52a992a8e386bcd6081446a7770c93cb7945d2d83a4f094a57fb64a6bce86f17154b2be47b262b0faac1d4c7ee545f303b81d7befb21899db5a75d3be97e96e2f2363d6123ff8cbc271eb863ec5d9ea746ca8c11df4784ef8d733c92fe03b8f6946690b3a98b151970470190a39b03f2927aa506e718a73b828c113c663ea9d6d3200b1bb569a2821df20805dca60780a690f22c56fdb2f628d34e21e715fcd1331ea80a88f3ae6f0cf1a5ea8b846dc4a460585efe08e4cfb1f23c6ee22a2b2404c617cdaa02120aa0440fc787029792636ad2073720fc97f65075cf617060bcc984734701dea33568fc7915a5d996c54a9e7d74736b13d737cdc87eeb3e091c0659c7efea3658f5d33d5e119cb778f67fb9882a615e39", "44e13d28b0ac312806893ec4e3b70b1ade6ef5aa7166287616c57b0f55c70452b5c7c1a3ad00b9c0fb2f0741d43fb98998de07dd97288eb6840068aacd49ff9481e7a5f1bffcb586f743e115c8f8c75654849b712a01d73171f714a1eac57d0525fc37b8fe80de06df7cffa4312fda76b196646735569468f80363ebd04ab2647d42e8751b0a093346130aea7c2e4b045c5ed3c258f9e4aa242a5835d05567a3ca2c2e9571821fe2f8f0272e7e94029b711e5cab1fa974a4ff8fad93087e058fa442bacddbddce79c4f87ede5110525545f09f2b7bf96eec23e7a828eff60265f6fd1c318658a3d2607226dba49b7de39d82a0b7dce1b182d66ce9d90a80dfb0f58af21d3ec28b9d3f68557456cee833adf0298170c589fe749f5eacf8f54cb493db13af3dcb140a7dae09981fdb171222e3fbc1ec503e459c1978615972714397b27bb0c2246a562c77ad82ed81c0efb8412b3b124fb83c5900ca1a48137cf8997d65316458f6ddd3a0a966f7d5f60b522196a03ff1e674410056d040c4d8d6c6b416d09e26a48651c6c073d938dd7046d4543c39a6225d1746195a48bb7197e4761d8274e37f559ae3f998486ef85d92480c0f2523dedbc09ad9fb2341e35b636d9a5ac853c83bca94d610f037b68c00f869eed4086b260d0513946b9fce4bd1816251511568690de271e32075e675037109d3b7ee9559f8b1afea9b4f9af7", "f2e089c8facb7a2c1342032f6df495f88ec3c16f776e329e58c23863644c492270cdd102c58d554615c4b245b80d3a0d488f0bbb334418f96fe102c8b40efca0572412d966c62f9abc1c7de87a7cdeeddf8507126b55d88206e5582ff8f9ae4f97a827e94ae351f28d78fcf94b25c403d97491c0cb72d4085629b454dc1e7ae47764818905167651d888afa75487f7aa3413ec6e586911f5bc67a34afd213678531267132154d77bdf7597c906360d9c0bacd22589b311f19500d89cb76be5bf79a323bfe98ddab572a86abd6ab963ad7b0ac5b527172b73bfbc02f973ea4cb31054c8ada3400d09abc4d06e4d7f04a0738ab4fe8458be16a1e62fabe2bb2eba3fe2ed81e57f740c567da0a03b4a0e5ebd9aeb5638b3de5da4dae084b7f06e3e3190bb0c79b492a160a03fd580ff169edf0b1a7a503c9be4436042ed6b51b8c8873feeed55226e0f230c1413a12b4c04d1b1723ca2f353404b9344bf4efa959fd4fff142a0bf3587aa73c972138b5fadd43f88a845ce8c7bc1a6e7c26d1bd689bcdcea1ec00dba8322f9df1be3c1d11eb5e145e22431a6cadbea79b2a7b97a7cb4280fbee3c5a980bee8bfb01618fa6f9ce8501eecaae17352fe44cd2a790457fb63ead097b5389c875e5a843739952f36616667e9ae44bcd24fb211e013395fa8b93019d000a67229e8cbab10601ccdf9444731c98b4cd2ef316972c5b0f930", .Okay}, + {.Add, "b7393320b47f6925da595784a4d6b3bf2ef06f71e98eae58170a00df79d045d6eedcd7b694bb7ad364a60e0ac2c7ebf249bbf070bf1061a242812b29adcb761bcf85cec12d9180917fb7750dd098c0d30719c10f228ca6ef54f5d0d6b857c360a40711e1ba9ac6bebb9cddcd252e2bcb25dae91abf2017e80db14c3dcbbc3f577b6973787b458592e5478c133b0faa18fa747ae9efb95b3ad200fa0939fa15d079ca160f88b7e30a2e3170982c30455ba81c490ba1e85b4eda3bb64e97f3ebc123bce0c7ed45f067df641dc96f0a11cea02f76517ce6d56b14fdfc818d89b0f98b38c03e649c4c0588b7ca595e2e11e621c26ae785f57725ef4ffb6e224ff689b86e036c91a7e34f2de00e775ce278c15e797cfe09326e5bcf8ce44aafc9cde2d37f887f55075b28e935d05bfb630ce904bf537992bd07a8c93d577c2c9fd33735479c797b30e4006deb0bb8f6dd1cceb27834369f369445c4a5946c1a8c02951d9518dd0f6a98286800489424e6666d4c13dcc9da260958b50249246f0ff22dce88fb66eec08f9b9a1ee17ffc5e00008c86fa7e15c7bcd591c2f3226c2f663d9d530edf66f27aa0968a5568edd3902a45670a5e37f5f72269c609b6491f69f5c7b3f8f126077103bef60917f8c87ea263f8b5279ed9e736d2db9c4e1c7f588e21fc893065e19009443f1a2804eb6d00d94be19cf53e82ba5fb2f0112a6b9411", "f4280e5d09cfd5bafba4e31b804f0522ca28d3369fd2469fa224e9771de1208b20197002655bd9761ad3d4959fcaaefb49a7d96e04adac6ad4f687ab6bbdc592f32198f6119c419e5242ec7dc073c765dc170a1ec3eaf09cd936ef65b39577702cadcbcf6f9ed381312d811519ac1eff025a231a2c64e40745877b5b69f9e0e251e5fa700da58d906b4f531663fb236839882f6c761cb185fca4fdbcc8d2f19b4f0784cac9191791ecd5d6e17d1f0e3f25657b4b999de129419440525f2595a047ca5ae8d7c260213b484a6e840376501755b1485b2451bc25ec2de7cdb2b57222dc30aa71b9f4579ae82c92178f62f7791db318afb7b72c95eac20135c0421132afe5885c82a3a4b778d7c75e65f7fe424f8e6b15ef7dc534241c36e7699412abd2d71578564ba719102a3a9972eaa9fe121dcfdba5f1e1d2d8c1219b16eb8e8e0e19715572615c85822bc7f78cf2cb628a466d30e28981b71661d46c40700e61befb423d52f437389b8a751843571a7ba22bcf0d997eb18e5af6ee1b2a8468931fab48d9a85e6fbc6b89bcccbd42303aa943d3decbe94fb99cbb16b58819b0a4c096fbdcc581461fc25589987240a4f319dff31edb6be8ba6c5d4abb71ceec279a2eba709aefb793faa5de17b1a1fc1d1871ba66055f11b421b1e6b50813996006782ea27aaf3a9659ab1e3532d2a2d53b84e4a250e70a1e5d9c591c844f71", "1ab61417dbe4f3ee0d5fe3aa02525b8e1f91942a88960f4f7b92eea5697b166620ef647b8fa1754497f79e2a062929aed9363c9dec3be0e0d1777b2d519893baec2a767b73f2dc22fd1fa618b910c8838e330cb2de677978c2e2cc03c6bed3ad0d0b4ddb12a399a3fecca5ee23eda4aca28350c34eb84fbef5338c79935b62039cd4f6de888eb13235096df299f0acd8133fcaa5665d60cc0cea5f7c602cd076bc8d19ada51d0fa9c1b074779a94f539acd81c4573b863c781bcff6a0f71981616b873bb0c50850891aac6837f30d881eb7852799d80b27273aea2a695b3c666bae14f0e8d656405d239ff6eb75bd74dd9ae01e0035ad2e52853abd6f5810389aeb1de8f4ee2a86f3e558e63ebb4870bfa0c90b691f21ec2103b10081973361f57f525f94cd5da6d00245fa9694d5f79302d171496e62f98a9c16189dc7b6bec5c355b5ead0a3455cf36d3780ee6a0f9a15027aa3d0191dc77bbbf64086cc72a37f54141f4cbd8c5fa09bd3093d29bd87c7b60898e7bf880a435d40128a3a769661a8a6afc868ee0b568a6b3cc91b4230c7303e51f493a6254b5fae3921b77fee4213a5db43b7fbe6b64caaf28645d0cf3880ea5156d1630b24326701049138e1ef4e27ab96a260bb52f0aef6107a209e811126e204df464886fd4e34d1876c278203015f085c3f43da98c5463a1e3fa3ae876681978f69c47e108c6a46efe382", .Okay}, + {.Add, "e8f845ea17d555feaafa8bf7d0c1f8a571a9b0668a6cfa24d3c4bfc743283076ead959e7f32173de7a6b4363f23cbe7674a21c1e495179677a5111ba69482fb9688b3b4d15dfecb30c71a9483118062e10e29755945e66d56d62b849076d88af2d3bf7621005b19b8cca8fc0efe98edb33309eef715ae8406006fc83d716728caca22fbae885c9ad9bcb8c4b96349807f13f8691451450fc7173e8a799bb746964ac8daa433d092e44865522a4d70f22646fd66ecc1bf79e6856cd4c1fb83bb90b599824e859104ad7a10e751bf610cd174496f715449f3ba62206db902ae57812eb39bb6de6a20c2f86657bfeecebdf1d118b91a0de53f33b88afd0f21e9e55296b00945dccba062b41ef86ddeb6cb3544c9806e52e2d484e5c9f884216f258166b4c8a6b7a00244b8bfee330246b55b338765f85f54ef7b0ad03e9afa086eb6dab6cb4fd5b5e053df0216b11fcd3096dcd8d0178363ad21f7c402665e0904ec00afbc2e5a3a04781b704f5069b3ec6dec2c7a83c190d8714f96829454942fa85c1a37e7a98b570d0aac9068173a3209e68b1201468e35a1d448196ed1f971a8dfe59c5fd075f3119c984ec75f305528daf906aa636079c843d7dfbc5d17ad01ff1d99b09b6cfa2a07c5adc7ed864f6c4137d8bd9def6e6986bb540410d456472c2407c9b77acd87eec3aecd185146be1e97cda18012c75bfefb6b28f4af117", "7b262f3ed06c83ffcf91c0d1d7900bad64690155e4e1e63de0eefd036f118911f780c75af0fb2f66467b08355c292965a8e400d600d0ae07c6565a7ec9ae99023f7ec7fa936e41a37e012288bd7d77eb4292a7c33e152fae1b6d99f19966a43bc850739e89f137f56ee42787932ad84284c21069c0a3ad772e0ac40ef1a71b37aa4d0c6b025d6d268c7f01e0c28ed2fdcaf90f717d1fe96b13751434fb9d4dc22a9b752e4d2f46ad5befa6b4a48a4eeb916c2db902142b117f2db6151fd98bfc4395b0b1eb0655bca73a8cff5e8955312d5a74beecefe00f9494d7a577d9036cc0746d65a7eeac1d42d6075aba5430f4738688b86ffead5bd7f8f25607743233207399f42430ae5b92b0559387932555f26339c6c3908c275c51813df6f6a6975894dad252e1690cb09e769b1cfbbb5cb666724946ca3e37e10bcf4437e75131b51c34068cdb5c5be4844dcaab25edbf0a04e60c3c84e0ae408109fd600b54d3cd3610dc7f78fd97a0de88b08d7009d2f5475dcc6600b633bdecd81a29fdc996246821cba1ed8eaee249f5c1b2e36dd6dc3216aa48fb913e2d1133e11c479dd87680a8e242180f87d83a78af72c36df394e1cd5f709374f6513a3d233ea623412669594c6c36f38f8f727e828285f735462a582dc8ee3fdeb655ac25a1813bcb50bff7e2eb06ef21c9c0727b6cfc69bd8d4b77874a188dced2b8735656861653", "1641e7528e841d9fe7a8c4cc9a8520452d612b1bc6f4ee062b4b3bccab239b988e25a2142e41ca344c0e64b994e65e7dc1d861cf44a22276f40a76c3932f6c8bba80a0347a94e2e568a72cbd0ee957e1953753f18d273968388d0523aa0d42ceaf58c6b0099f6e990fbaeb7488314671db7f2af5931fe95b78e11c092c8bd8dc456ef3c25eae336d4284a8e2c58c36b05bc389602c2343a6784e8fcdc9558c22b8f4802d8906c4fdba075fbd749615e0df5dc0427ce3022afe78483613f91c7b54eef48d6d35f66077edb9b747a7f65fe449f0bb602347f4b3ab6de810803e8e4d35fa72115d54e29725c6cd6b9411cd39098144a10dd014f1381a226f992d08849de9a8881fd6861bdf2451a657e920946afd1cda8beb96faaae20c6390d98ef6f00275cbe5b6930fc2a757e4d2026b2699ee8a8ccbf8d2f91b8d32de787d81d22c7a0bb8a36ba6122746f35bd22c0c877d2730db4bb1b805ffd4a23c5ebe5228d410c9f651c9ddf22958da5940b4899d40a2574a219c3bad2e640436f470c90aa29c54a1c86441fb2f4bec8345710f77a9ac7ca5d6474984a55b578096734f3047f02a83f1f6eb8f203fd9be8b6734622915dca16c97c92d577bb1f04779e11465b32e775edc3322feed95f015e5c2c0a3dd5b9a2cd36c54ec16165e28e812fc382385f867e9bfa48acad683e817e296f34f4616219ba4492a82a08e5d1076a", .Okay}, + {.Add, "-f36967358682f98d7c768393854a50c2ba7e87977d1e4372918159a1aa60408fa23a546ce207a4d0a26d07bd48158b2d9352c5a01111ece367898afd37ed0af736b83ce543190f3e8b96255df4a776f79b42a55455481564e3531d96e9ef6cf83c452c3ba4c81c926f333c72f4f2b2496b30f1926aeee1575518f80aa3edad4f9dd68efb49f9ceea8c7bbada85b0c057403467c8a5354233bd23b94b2f89d46bd4c6998639c85b83b94728f6cedbe0f48ee3237308a1e427e7a7af10288bbe528ba587309d738a2645c69c09e6595f4be578f2b4dd0fffdb960aef54760e33f5b5ac29074972fc0417e8b2cd72e327faa605f98539d28521579d5e4792e03ba8ac8b06d41cdc602d1b08b310f582eb8a47dd6d7cffb7e2e668c13876c94badc3df61b648f46870406c00222b444ca2ed48ab0d1dd59b34af0940363564a5347e98f1fdef983c98223af4de64c0140ef190b6f28549b737efce5454f761f6d1474a71c589b07e28078d86cbe4576944a57f7513e623512f93a77ac88e6c221308b67d10eaa4262a13b7bce2a3ca376ae4710a616fd972a3ca3ecb8d2e7ab16af769688092921eea557996959153d96878ccfb520aa2c218e35916dd0aebd886624e5857ba7a7056e2c4eb0123f7bb634fcfee26a9743571ddf559a209c2927989aa8671f2a855106588d612338acb3f587e0410cf4bcb100b8a359f0c91bdd5af", "e9d1761ae144cbb7e8aaee06f3ad65c19009d943845ad61ca4fb9adbf727827adf98d077d18a2e50993f4468ae2b50b3dd667e99699360089740b40faf24943ed6e2581334cfc0fbb21a6dc386fa73f58972f219e9f493f5f84c403f847b4e31f18055ee40bd65835af3ed33a6dd12998eaff65925e41d9c376db9bdd412b08d6cd6e433d5a618fc24842b97453ae57866de6e883ca386607062ad5529609d96a00a9761a3db675203a6e559b316aa05bf7d4efe4f518a67f7708212696d10a5ffcb5b836f2ae859b6d489bbce2addfbcf5fab6ab4e90802079f11ee452e1fe259bd496ac3442c09ed30962826892f02d4c2b7c003c9bd1aa5223b2b92dd58cb2e13606ef142d698ed4cbe95aa6254e69fab1d6ac7ef53a7f794911ef2d86ecf9df39a13743574b15468bdf83c8c08c85db2bfc1143478ee6cc4b44acb012986356b559ff8f62bbdb9e71f9a326a31a610b49a45cd8cb217ee95335b454e05edefd0d977d4b8d07fbd41cfe8fa7ab34a1306fcd54d1306c079fce074861ea96f46c0bd0b1ca82cab39b6bfdd785c586a8548a3ae5081234dab9633c5a8fc5eb8f02556b4cec7b3f636be6e74d99ed07cd728d7d4bd34b948e97b44572aab99f2cabad0513886845c31d6b3374d7aa39ddd19c70d32c0e475e761d34ab2cc6c58f34ece1f942b426372cd4091fbe6b40717ca62d7c20dc04082b53aa52ba53f29", "-997f11aa53e2dd593cb958c919ceb012a74ae53f8c36d55ec85bec5b338be14c2a183f5107d7680092dc35499ea3a79b5ec4706a77e8cdad048d6ed88c876b85fd5e4d20e494e42d97bb79a6dad030211cfb33a6b53816eeb06dd5765741ec64ac4d64d640ab70f143f4f3f4e159fafdc80fb39450ac3bb1dab3e4ccfdafcc230ffaac77453b5ee67f78f434075daded955f9406891bbd34cc10bf6062936d534bc022495ecf431b5a0439d1bc536eecf65d474b95059bff0372cfdbf1eadac8bda2bad2e48a1cc8ef2124e182e81501619474a2826f7d98e6bdd6630e014135beedf9c862ecffa2ab81ca54c59f8f7d14341c53608c806b27b231c0002e2dd7e77a6652b9989942dbbf47b4b2096a3a832501237c88f3e712ca757d6733ef4416e1c358032fb8f1797643307c09a24eaf84d5cc166bbc09c7b81ea99a40af86386a84f9f466c64810dbeca8da9dd4b8002583f7c2a85d7dfbf219c1ca8cb595aa0ec11dbc55787d044fbfb5cee915b6c6e1710d63e28d32d7de819e60369996fbc53df877dfd687e0622c651db1279ebc1bdc188f1807c93355968d1b50c3e794329ddc357365f42d8271c7a3a97fbf5d27a35e58d5f9a6f9b98b3c12cec6f839d876941e9d28693144decaa40bfb1f2d45f9c41748d680df7cebf0fc60d30b737a3d31429ce021608d1a18ee48b516639adf789bd4fcb0780646766189686", .Okay}, + {.Add, "c2b2525d8e08bfab63db213f637f92d88d0bbea64a32742d29fb8c276a9f23e07154cc1fbd187660334741781d9684971f55142d9f220a693effb65a9abec6741cecb385778f52889e332318dd5cc8c9de32957babad772ff427e30053b9e2efb75153ed24596c8687f14cb3605b200342aac3bc1470977095a37133cbaa18e42c8ca5e66ca37d40e1f0b1829744e6612cfb92a6b75f7b8a77a0b97a234890d461a88fa6e160951d12a685b00190b8b333b27e469ce06087ee00b91129fe1969cc04126c3b530f027c13454845449dd8bc573da314ce549d9d8cd007ed42a4aa87d043be5ff5035f68e3f1d2131af4838519cf2156fb3e6b4b6aa48a3293357792833b67632bc6a749a696280e4d72cc2c3a598a5d0b3294088b8026b22493c38339d227ab9ee0f759e9e9090a0f55147ce83e299f854aa62d108c08ad5e2b60dee8d27ada03427557e1742e794f600f9e52dd3a8b63f7f173155032e2f9424817ddd92d89fc15aa7167a048a86b7c0f9fb104a23ddcb293fabd25cea3d18ef8d9ef8567a984780f57e3fd9486c8796a0cb3072e014d18ef46ad1a8a5d32f05cd8c91870ded49fc4ea7ad952389543d378c18710b7d68079cacb576ba632387c529c3f6762fd15fb740d5c9600113cfea7e442e436731b58753372043d9f2c59446c5a7da16688feb156b8962e322a40d0475ad4d5b2a1e581b7a45783e6ef6a", "461a307c7ba6fa1e9b47aa00deffc9226c9b436378809563065ab4643a86d098527b59b353b923dc091e2f009f6f439cfad51e952136a9ea134d071ebce9540f4303e977bdc96db2815ece24f299c5c87bdd4cf8f49e0153beb8d886230cb35b0896a58e859ee442346758c654448fd0d929ba797b0a71be7a00137c0ef6448356133809d9af4f7ee4cc120274fba074375e1cc409be37d45ce27d96ad455fd39561e59828d3b92914d3a7f90413d41de936ab14895de77ab5d80446a59d0ce51e2e11cd5ec899b64e5b3d196c8f04fb24f26bde3681197b8c02e3bb372a6945c780b233aa6bdb55efcc301f33640ec4e9b8c39fb9e1412b15c8820df46b94bfeb4182e0cb773bacb379d40861e38ceaaa08c3be0ee52da9015b024dec2b3749a8692a759c6d7404d6c7d6d983eff9db46526a692f7cfdb04b6d912b3a4926610e5da02d349247467b31b9cea6f2f51f74e3767f4b6d04e901dff332f3e96322c618afa07f0a792f73b02b3ad83fed7a8cfab54b5c2efe18a4951829abe021ba901df6bef77f399c5c9bed2f75ff02a60f14eb38e70b3273c394431532cc625c2b75ee7f49eddb561bd31512f113ba5bce0817b83179a153ae6bfa0f5900ab90e4f285c31b4ea4312d7e07fac93f0e76257ecddf07f3c4da2707fdf0516ae74bb9b113b02792a8c574ead167862c89b084d1561c9bf0fd2660c539d8af1c7f90", "108cc82da09afb9c9ff22cb40427f5bfaf9a70209c2b309903056408ba525f478c3d025d310d19a3c3c657078bd05c8341a2a32c2c058b453524cbd7957a81a835ff09cfd3558c03b1f91f13dcff68e925a0fe274a04b7883b2e0bb8676c6964abfe7f97ba9f850c8bc58a579b49fafd41bd47e358f7b092f0fa384afdaa05d67829fddf04652ccbfc6bcc3850c4086d56459af6ac11db35ed4833710d08df0a7f70a753f0a344e46277a2da905a48cd11ce9295b263e4802a3d8bd57cf9b264eea3224399a1ba8b8ca6e8261b1d3a2d3e149a9814b4f6e19298fb3c3246d0df04f50f5f20a60deb558b021f1467f03486ed292c110dc7f966133269826feca377dc4be482ea30253fd206a307030ffb6d6431d486bf0603d09e682749e4fcb0d2ba2fc9d480c54fc30b1bfe28dff4eefc33aa892cf024856787e1d33e7a751c1ed4672a80e9589bbd3132dfd2042552f133653b9d6d0fcda74f54365d6e2a56addf688ce09068ed9e517cb8380ab698a2cabb9ed9a0bb0ac9f523df84fb1b0b36a0d7c26a103b1abb47feac3fcc77c101bc7f266e8584b630a415d9f8fff52b9043f06f028c27b1b064dee6529a8fe2f46c99ec8e95021cd7937517aff32e40d378ec52a7e4bba2ca18b6490c9504b74cd6310c33e66e0329c3b6ff48f0a13a4fe1d6e2dc8f931c4264189fdb45eb3f15518b0f171a39f0be27cde3033036efa", .Okay}, + {.Add, "-2e34b0dd6ca6923dbeff69d8df9513813a85a3ddfe3f0dc381185c5dfbb41f9fcf7fcc6bcf770953a00ac34ca128f7dbadd7aabaa45ab2f2735dc637c54fcda5434cbd5c285ec07632dad390b667b480e3e6a49c70a9677d4e6a3033f95f0b102f488e6210c4e21c50ed7034b9f41aa914c452d3ef04f1b472de3a16f66f1b7fc19d974e8ef594de776dc9e80abeb8065b509694dc49af33d1f4e1fd71b16976dc76a9773e8e96fbb6c874c717044211574f5890932b7ac84b458d4e1253da8925f32f2a7e753f5ddd100310a87f2929c9259017164eaf3d75310a53fa4f2b18d724d43b830e90699b3aab95f2c19074c0cc237212d44b15a47d49e73fc79e8cc72349cacf4f854f504eff0c757e6d1eb6222d540c2944e3cdbe97f5f8e1996683bb3f647d135347da66a71cb6f0ecc284d7d25e626deed5feded45e733018e3ddb16e61d44df21d74762f18635b4810949262f20d7bc9fd7e1cde9987951819ca38d2f973510d82eb8322f4535a94294d20da0f468ed4d95dfa49adf6fe221e73ae4fa711ada4a24750e8bfa92506f105b0f1d47cf2db0e0142035dece9714e6a1a8f925a3d601a08e3f4fb024feaa2abc21ffaeaa304edd4e9b44ea5e04741d9459170695c6273e11cf13ff14d94582987b93c2b53d5756890fb0f880c2a20392167326ccb93f858dce58b623ac0dfb70c77f88b05a288d27da26c14256e1f", "bd35d845565647b0872a6fbe682b5a4bebbb134b90440cfc45a4655290218491136ad933fc321174256ff8fd9dc4435f30302ca352d9e104be72fa02253ee71793384e58127bfb90117fb6723d6d3146c96c77389367b1b3ea9d24139a86e302af01a2f4d882814ff724c80159a7662447b700d26d84146b97fb8b364091bab9efd5f456463b6338f22f213854c1a0184ec53a4faabf35b0b2e2b871c174f220cb34ff51315a45c3f8e26add553f8e7afbc165045dd2baccdfed899c1814233250f70737591e1adb7f1aed4149880e8e052a1bba733fbbe1aff21f8c2e0be4702cb570c658392ec6e45e2945ba3860d869b5517c22168c48a83f9b3a32a4712cf3fddd40c362a229f47ea1b91f8da483980a82040501062ead291bc995678f2be797855aa74e6e831296e0506073ab198159cecafd57c5634f32d299b8a6361e3523dd2f6332dcfb0983dcd272137e70ff23d6d87306855c172a367193753fa5b9b7566bc0d2d7b1578f74d4357b2e09e89a206865b4b36a1a3561858d5b53e8186e960440fe2e5121fdd1748816b7dcd5b7a14246aa8aecce05deaf915bdac81031f9f8a6ce54b1abb2b42d458150a10526c7dcd8430dc074948acba0da397a2059cb37af5403a9c44e24fc02f6b34b77638b3c0141551ce518f73caad89050edb77331d12374cf11e201251d4307b8bd7459f96301f5731ed35a156e7f9d40", "8f012767e9afb572c82b05e5889646cab1356f6d9204ff38c48c08f4946d64f143eb0cc82cbb0820856535b0fc9b4b83825881e8ae7f2e124b1533ca5fef19724feb90fbea1d3b19dea4e2e187057cc5e585d29c22be4a369c32f3dfa127d7f27fb91492c7bd9f33a63757cc9fb34b7b32f2adfe7e7f22b7251d511f4a229f3a2e385d07b745ce5a7ac157504a02e811f374a3bace75867ce0edd6744fc388a9eebe55d9f2cbaec84219f6163e3b4c69a4720c73caa7400494a7fc4e05c048a92b03d80cdaa8db7da20aea30a108e5643c048ba35cf10ca43ac1153833bcb95755909c8ad52a9e5d49237dafc776d063a8e92e0a0f42413303c25152f2dcd2a02cda9375f4131cdaa42fa2acaa0f3764e1e854aff8d7c14adf6a83d39c85f5c563dc45f62a3b1b3b38303933a982be56fc81fc6c9ae9d68d5053fe3b45761d3a57726ecd8ee4eadd950dadba0eb836606a9173e6658abb5e990d57d80be0278bef7e83724d81ca2e6c0c51dfe22099e09b7946591f25de90bc3b17d7965d31c9a4c0465d2f5089aedaace8b4def1b0ebd006af6dc9b7afdeccc3db51a4726979a6176a664c90f497a2cebf32433165fe5964a7e1eda008d29faad67cfaf9f238471439c745f7a135e33133bc11a91ef34ddbd1ffd5ed7fa77c87fc2d22cc6630b4960bff6457e0d6b9051b99bb0846d90667e200d7fc52ea4c55b7a95a5a2f21", .Okay}, + {.Add, "15663616c6c5c56a27451bcedb2142d8f56b833facb9909f7beb54d12b6b446329c79f096fd726bee67ef9556e91305244b5187959702c959656e192b5c28c8df57fa7bab5d09d6e7945d507df7216ccc457643eb5ea16d1e0fa1994110d6dca5ada14cde53ff4ddcbb5742ae5987f968ee72042a954b45ca4a239dd07cdf058569f7bd7249f3753489902d590375ef217ee6fbe7c5f26d3c506e08f0b404eab27d10bb1e5ccbf07dd15c4d570e3aa1eb6f3c03403dc62fc8fc935ec2b363fd53fa543e0eb0aad178fa6f35cae4813989465b232cb11f1bd6b9471ec1ef60651d109e25925df92b51601bc6fc0b741b6290338687071ddd63c71bd1a4b65431a06acca41b6bfb498c10a513d0babb9bf51b4c9205d385e94e5e4beb1c31e98e008f40c98f028ec80db570db69fb428857276bfb3373db66c0d44d65c5d1c2a6ac2eef2bd5e3e1961e7f2135dbd78dd750ccf4af2dbcebdf87ffdbcd6a3595e3a8426e5799b579945c628373b2e57fc02c43147ea800f59cffacb3be67355ed7050ec2546ad5c94531f272ff7c78cfdbe8c9957f3d8b9a2c36e38dd9184110c1ec8bf626c7f17c73a17f0ac5a38eef7a074d8e79842e3d83414354fb892fe91948846fdf91de7c62a75fe8c0f5f6a600dd2f91c98fe3e3bdbd40653fc61dd8ed6129a6787d77fb1120ab7bfa4ce96881d13c24eeb5b0993ce95ff43a79881c795", "b444ed71a2b56035feeab71724ce4a6be70b6c89d1df4cf56562793f46f250a82ae1ae8fbacf36b037ac819262d7b94af15b2124020f5a43b2c48663e111818cb21385006ce6a31399f186002351de1b05bbc39e27d1991a9bb784caafd43a627bf68e0b9b1d37fd30a003f185a3f1c41f42a8981a02d7483864824aa2d1b3497f73b90899ffce928604f02e4b2cf658c7c16e8408a548f2650e0b629352afa93d9fd065df10bec36fea648855f637c1c84131015d6f2aefb6f0d0ffd97f60d9e4fa407ce51c3217d58c3f0e5db192dcd8274b9d997456d2f77258a5e0f04f6b0ffa48810b2a7a64571ff5e2bee6e01b7995dcf50be241f3d4f22cc9ce8cbefe59b6db3155e58bdd92b073775f2b3da6ad290202340247aed116465b4e3a34bf6b126f9587e85ea2f98294511361b0db4188df420753576585724955113243ec20e2825ec527bfd264b68e7c21f683541237008c9488921daad8da475d41dce060ad1cff9c811937f7fd89fc1e2036f7ce305f5f6c3919b17f5283cc21864ca0c2daf6de7d9950bd87b37683a07955f50c247a198a517a6ccd760d3eb8690b1ee5f04f52a00db5b85d4ae0548d8fde1b35a2c8b13fa32f89703082b0090ddbb6686a687ed1a190846018ee748c03a9654e21819e3af81265a9895b071f3b1abd2ac984e084bc3814835a045139f41d5f71a207a727e7b1a661b795be71a17117", "c9ab2388697b25a0262fd2e5ffef8d44dc76efc97e98dd94e14dce10725d950b54a94d992aa65d6f1e2b7ae7d168e99d3610399d5b7f86d9491b67f696d40e1aa7932cbb22b7408213375b0802c3f4e7ca1327dcddbbafec7cb19e5ec0e1a82cd6d0a2d9805d2cdafc55781c6b3c715aae29c8dac3578ba4dd06bc27aa9fa3a1d61334dfbe9f05e5ce9df303db64554adfafde4285046fc62a14ebf19e92fe546570dc17c4dd7dcb4d00295dc6d9e1e07f34f135614b8dec46ba06ec04b5a0af249f845dd026df2f6533326b0bf9a6756c8cfdd0648648906306ca91ffe655bce1042ada310a0d196d21b2527f9e21d1a299155d7c541fca1163e9e419f202186063a5730ca5407653bac4b46ad6f765feddcb22913aa643b6fb050d1158cd9f74067c2e78114b23d4d9a207b315d960b3ff9ef53e910dd192b71fb16e4e6e56e3d1751c2365d9344ca8a1d9df6f60c91f064b7f705750162ad6971e009b3b1ae4d4027937d8b27dbe25c1374c7832fa9261a749ec4873817a1dbfb294dc3a1113c71c252af5e510a6daa67b680653b398bdd20d630b1d303baeead03c7a173daeafb1bf1f257cf2753b8caec67ed5bbaa7bb049828707bd8465d2689c0c6d4af0b16677ef8956aed6177a83eb6e0973211a9e3739364e417d8faf038118a9933d63ec685c3be9268e11c3f6088aa57c8564569282f14574f7b6d9660a2338ac", .Okay}, + {.Add, "-f61445ce3bcb5d04ff920e9497667ae8935c3de584dae64f46bd28296980280ff48a2a3d3f5f49f7d57517c95cfc88fa6f502bb178cec36e26f5810b22a38fef9c371423b816fbb8147628929057bef68695b0f284311eef59c7693025c37411c85fd2e5a102bb93e44910d48d7c7b357554536ae4d7e273a856892f8f5ae30752127047c99d8a6e08f02c119e084c47f99ce01e1ad9c867ee495cc8c2701ea67606c1d40366e22994ad6e6b05d49dfca25f95379eb041502c729ac5892b69f54e02eee1b0a65a1865611b28f3a4f93a28ccb9a9bf87bfe76ea91aa5f4513aff6c26361102ae98b7c326d4c190413a2a20b4144311115ff6de7e8fc53b2d3d6f4dd4f32b0ebc9c09e36d7d4db0ee2fff0016cb6dc1a0a05c11229f0c8e443ee030b83351be5722322e9d6bb325ad1ce59b954f44e1093685ee1809726b677db68ca4c91e8e2ddd836b923b74444e94a8a5cc45addd4a3f9aeb05a9d31f455a5af4c9dbcf812d86152e63ab0177bd750edff1d36207fa8c4160c12c23ab61f180690d4ed35fd06142b8994325a9f6155671ba91d2b00873885d78db46ec5eca3a7ca465a557fff6c3066e7fb5ac078f70b43ee4f753500b99dbddd318a550f8e003f70231001bfdb2ed5a5df8c39c61ecfe181f4eb9d6c58c397d447d487e3d927cd782298ee3a58e281d88c4873d8b66a89cb11c30229a9546a461c5971e34bb", "d96472ad07a40a32eaa833537081461152c53299f8ac3972d9daff730e7e6eaec96a2d876c2da37ee9072f1579bd7900e75fde97257e4159b2cab40cbf335b06fd8033e0d2acf8ac511169d860393216bb128b5832c34f25f042c646927fc2b5976642ceb4a48aead8a38e2c10aefc7e66d968b51cc1e90e40d5da95060c788d01f49c879efbe5f14dd037b67eebd38745228579b726b480345b8f92e3dc72c0a85130c8494ba16bec2a3c158130988055d68a46e0c788be5a2c9fa752c932fadc7a9555e1d9a85ce01ba7678083b97dc7b53aa41e96f95c968a444efb7521cdcf54400e6381b36195b97b242ab736def78804657b0047189af56e23ed6db80debb91ff47f849a53f6666dc10211c65baaa6c5d84467121287e0277619aa9c5b339e2200f2379f0e9a0a45b317bcff1ce0b4a6aa82bfb091aed09e86e9b9e8a8d798583c1dd01c4be577879d4feab38aef339175f1776d0cd48d6498359d7c905fae4be2a8fdebf7315fde0bc600a4803673e9cd63533fd0598111e7117673563e9fc5604fc2c4663a224b137ab3844fef29e59b1dd70012dfd9cb550365fd6f85f727b720ae25d057a2cb64a26340d06a94388652e36e23f5f9c18486252e04a282c9eaa0a73c8c7eff0cd7e6bc0380a5306bcad44b887600312c417df19f5e0b0c95e4d3108b9bb4f9053335d68de5264a0ee459cfe76cfd80d5b6be0fd8c6", "-1cafd321342752d214e9db4126e534d740970b4b8c2eacdc6ce228b65b01b9612b1ffcb5d331a678ec6de8b3e33f0ff987f04d1a53508214742accfe637034e89eb6e042e56a030bc364beba301e8cdfcb83259a516dcfc96984a2e99343b15c30f99016ec5e30a90ba582a87ccd7eb70e7aeab5c815f9656780ae9a894e6a7a501dd3c02aa1a47cbb1ff45b1f1c78c0b47a5aa463b313e7b9edcd35de93abe5cdb5910bba1b40bda883325584a4057c4c890af0bde8b891d245fb1e366236fa7188598bceccb1bb854573c173213fbc61177f05a0f0c68ad81ed656f8dc19319cd1f6029f2ce5562d6d599d658a034b292c0fdd961118de438921a14dbf8561621bd3368f3801b5ed070f8caedc69a3557005957d398e49894277967499a284fd1a1150cc1f8323949326000df01dc8bae0a89a5e4985f43f476aeb81ad950db50c70e2705dc137861ab3d6f463e11db698b437ebd2d28e1678453ae9a7ddca951b8fecd82f9a1dfd03ccf5b1bcd08ea97de994a4a74c7107401a3c99eb7e2a2a6d8973100d9cdc7e76f8122f4291068290ac37923173757d9f0ff1e8f8cccaf6ad3dee3751d0f2aecbb45109a44ea049aaac71006c9d75e5e411941f2bcadb617438465f74c1266e5b5120dce05e6c58e7b383e58b3d16394c183bca8c9e3471caec44bbd319f2732483915166fd818252a237d652b32849238c0ed90e5bf5", .Okay}, + {.Add, "-14ce2549615849d1822b0b63c29830db6b6cef4a505e5afd952eb0f42014826d4e6296a4c0e1508d3e16dbde06f9a4d01da97cf85c44afbd65dd584cca07d4a7ee20a7c8c6e4b9de14f69aa20afdf55ab4cd9a5e779533dc345cc25064471ce2e65c5d1deccbf14a4b900d73bdee1330b81fdb653ef4bce96919ba401c7ab62218aa03bb1151073742e7e3ec49efd528846bc78f481864ad5896d8881578d79810de4de115780f3acd0777ff9722b31e04597d5d583fb587e67b8945e943b219e2c24d6e170666466ddb65505535ef7eb194f4acfcab090cd1bacb63c683c04b85f981b37df418c0b2d2496042e87a64409950ecc13dc6aaf1bc7bbdd4478a5873215a257272b04b12cfea4df868602979adaa4659e0abfe6a8364b32ee08012c35785d211057e24dbb2d7849b9b095df3a6aaafb7c0bd898a36fd3a51dff92135195d8e98916d1a63a4c87b4abc2cdba8adc602fd403219837fa7e421df13638ce2a94c8ef45630babed02b4e6c455f1671c2461b9e7f460945c22cd3aa0a0e6065cd74297f57f4249b7373154d562a11fe82e98330edc366aa6adba8160b0c5fd924c2d4ce83357c3e3c17bca817014ce52c0b6bb4d5ec55418107ab7bf955769835e2701dd90c2eef37c4eedd8f7a606897c78ac311eb9d15075846addd3cdfe02403f46816cb26f5deed7cfaf57a1283ecbb8b72cbb71f49281b86bf01ab", "e8afbecd4616c8761747bc5dcb1e388a4c2aedc5786b9d4c100137fbb2cb8e0e596c0468d15092395969dffb7760295042d5322fe2c64f799b8bb416b33b69b45a547488dcf910e0d10a4d6aa9aa7ccfd321af9376c4b98801a403824fcb7b473930651bcf7bd67fe53a28c4d2502e4d72f34dec8eb6e194cb14cbdd76532e4b2482215b8fb4c348a5ccc4d9b80d2898be54f14468e224cc8ea43ebc6c5a992402ccfa1e2ea1b5d90b13629266860fef5d92130da76ee56fcd69dc6f2dff28cd684e6d3a25263b903b861e76ea738b015210a2be89c2b19fde0074a57df3370a3be8ad716c3133d82fa7896265f0a50d737d692b4494c871366f08dac373f78ecb3699ca10b2f3dd3aefc2d31aea2714f2131540d06ccaef3a4af5075d384555bc179195745720390b1837df37f3bacd13bd3ac178dce7fa4c75374cdbf76b655705d516be3f328bc2b3c0976103e2166d5a3e1ce4d79d95da5704307099d43570c365d3c0ef818a9a0edf179c5d69d1673bbcdf3ac2296cf84d606ac4945f641144e25db4588ab0a1796b2940c91a9f3c404f2dc977c5a1e20e69feb4aecc71f0fbe33c0c03882de244a1a7df822f2ba669b6a6e7f153844e00219b8c641e0b692416908eba9615f5be384cb49c1863f051093750b26b1865eff96f9efb704b0b66b31295e94400854499daa9e831ea295db46b00c05cf6b87282b3a101c0f3", "d3e19983e4be7ea4951cb0fa088607aee0bdfe7b280d424e7ad2870792b70ba10b096dc4106f41ac1b53041d70668480252bb53786819fbc35ae5bc9e933950c6c33ccc016145702bc13b2c89eac87751e541534ff2f85abcd474131eb845e6452d407fde2afe53599aa1b5114621b1cbad372874fc224ab61fb119d59d878290bd81da07e63bc1162e4e0ed6e1d537039e929b520c9c01f360d663456e1c18bf1eeac3d1929a69e3e0bea92cf635cd1593895b04f2f2fe7e6ee532944bb76b3858c1fcc0e1fd549cdaab926953d9b82a07bae118d17a8930c45a941b76f76beb5ef2bbdee3d1b177cd5400223082aa932e4183e835701c644b28d1cef2c6d3658153fa49e404392281fd8852281c6eb78656afa768c1ef0cfc790542e57c542f8c00bc36351a2142f65605a9c58b16f20169011c11c2a70c23e3a128a17724421ec778825adc5715f0ef81c1647b53ac4ac7819e7976b7c56d75c4c4ebac0d1e3e0bc8731fb2b59df500eec4df1247250c9fa991f23aa26ef079e3df0ea5555b0df14e98ad932bc7cddf7b62b7bc4752a41cc444646d7de7b63ff230c98c1659122be79373504f86606659022da182a59848a9b7c3c7d97f8bea093e0e824b5f28be0ae1e9cbd09c6cf0087c5be88e98fe8716fc5ef592cc8daf217584d930e2b868f0ea1812d355e4ebaed2ced3c7016d9c7af754d913f99295a981a42bf48", .Okay}, + {.Add, "92c7df32e0953b659bf548319a4dbe797782713f871370313cdea5d250fc7cf42143245e08e6f82fb5de4d9c3f533b5e2edadf15ee239115b5157f0b9cfdd0269f9b172e488a3cd7f7e786226f16a89c621d11c8bec3fc5381313ee5ac1cc2b4a1ad3e8188b40e3b8f3a2e2d0fae2206c819a35ff7403e693e7be16f73700e41b3abbd2ac9558672331dba908163c7d8f461d2831fe503cb9c9ab4ab36ca6bad400292c28a961ec45df19055926aec7bf1d9c97257734417653dd8824a0a313b4406d3056334b1f91badf42082bd4cadc4d2ecc00d3159873e49ec4399e212d47300a574881564648cd5e4d518c5261a7e907956bab9e66a28eccae6a228a038843949dba976c0b11b3e5cae25907dbfffc6fa96d434261cb3dec6f3dc2a3f08f8789fa34e4c6ac8d23d94d39c3fc8fe6e11bc0235412eb0662dea29f37b1e68d80fa28f9a689f468223687ac702fd93c9c4f7ae04da81d4f389aff104af47b50f36c332b1646fe48401967deb46e84aabec4a28cf716d4c46ba26a3c5927efed2ea02edf33ca03075644aafedfb7d0f9c1d51eca4a87ba2fb5965e68dda523127116e2807fe292107817a5920c45750aa3684084185406c24c0456fd08efdb11fc36f45110b67d1e10c2312a8712946eb6a36852a1d87884c28566f68bb7cb9b044238d98bbbf6184b20a12367bdc2d22c08862490ea388f240155088f41ca4", "428db20c1de14018e892622174f7611b008879522e6d47555fea4be144cb4a5a7b082216ceb280a275603713fccff1add1bf213c6b7c1c15f1c16c99d65b9d994a719f369c0b9dd5de2445ab440d02a27e049eecb248dace311094eb49457760309596716a5849d6f7cb3b456468420ccf14ac1f98e4da19f85f2d43779b40550a7fbefe1efdfb67341da563868e90d7446119e1352c7b60d3426b6356d0f7342b326aca1c0d11335570770d2c44d2bf2567749fa5a3684629535e8d1d4fd166ecfa61e3282405dc3b4c8650695667c20db0146434f3f77bb2b6141c81895ffa3556ca849c47fec643b825f8c393dc4148defa50ce10974a416e011fbcb69ffc06b95b5b18539176eaec5e40641ac5498900673d994094825dbb3c598cf1b7997d155f379b8d4108889623b2739b5bfe167e13e971c67d16d93c294dc63d4c258997228add71a5697f4a64598c3ac07591818daf1c31f3b38de9ee7faa6d2e48fba6929c2c7e9a21e8b5a537a31e56c05957eef5cef3cc7dea2a3db363849e52ad83a66f6c67eabf5a247617bf3942cc20a117a8743941f6f858eff662701c0901be5d1595db0f8a8dcaaab30bb6bf196a9eac805e2c966052cb6446420828e9aeb679ea5eb1d91624f8cf37a00d76bbcd99f158eb6fc16642322e39cb8549affd970eb5788f01d80583cc50dd5ed4d976639e335cc5030402d33a4c91700d5f", "d555913efe767b7e8487aa530f451f94780aea91b580b7869cc8f1b395c7c74e9c4b4674d79978d22b3e84b03c232d0c009a0052599fad2ba6d6eba573596dbfea0cb664e495daadd60bcbcdb323ab3ee021b0b5710cd721b241d3d0f5623a14d242d4f2f30c58128705697274166413972e4f7f9025188336db0eb2eb0b4e96be2b7c28e85381d9673b5ff407f258b038c2ec6455117f2c6fdd200e8d9b62e16b34fd8ca6a32ff7b3620762beafbf3b17413e11fd16ac5d8e91370f675a02a2310134e88b58b7d556fa7a70ec13b46fd283012442255102f10000601b6b72cea8576ff9245d632ad08e0acddc59025bc76f73a788ca7db46a5acc065edf40348af2a536c1ca5228062abaee89ab430988c761d46d74ba9f119a034d691bf6a2758dfedae9d9abd15ad3b8860fdb24fc848fcfeba707abc73f6a1377b9b86a8e61a6c51a77da44b0016dccd4533dbe095b46855d210c758881739e70af1c75fe0add55cedde30a066cb73bb58e653f0b0544391e9e6539ca30e4645729171d51806da95d5fa48aefcf88c0c7ad34bfdbbcbe699518e1bd99f3b255dcf04a6e3a28cfcb3d9dd938ab954c250c2c7b166a14d530889fb1d6cc778ba9b61297269ace79e92f6fbd40e80604f24a487ea002b90427de158d48ee8e5a84a93440c669addb3243114ac1398a35d66313dab10699242695a5d3a68cf5134f9d1a642a03", .Okay}, + {.Add, "-e3241aeef7c913bb930aa74d697e40018f2632604fd16e7b5a307eff30b49f39e7d6705027bc92bd2714d8a54159df06159c03187c7d50f335e72259714f9fbf4a7965c7c4c6db60e2213293761597917491f89d76a3fa6f3575a5e06bfbe2a7e188126fc145f27d4213ad2e327f550e898af700904cfd05a3c2dc5ddf23a500624a7e67cf5588c572f21bc45a8d216ebb15713ab30faf369653b055befcadad88d7583a1fa22319cb50030b396f6cf4c4d0db45f52f38c9df218e1e0d5ae1333463484914399c6e1308bb5ce0f2a0a57577af5d43f08dc11c5e72f6506d72dc13d6921674b6d47f2f8784d4375c343e23aa904fe0683d8662a4bf4d7bbe9b8440924e6b7764585b4d6083123de069aadbda47f624811d7273c7915376335bafdd91cbef90e7fd75985f4fb141523f6e5675ec40ee1d7d2d810cd9bbda13a7f3d766a683ddc6e35ae6cc905d07651873d6c9b448b6ed7eafcb8ba942934ef2bf9b389425c93864443af3f303e14f699cb2c03eba812cd87168803951d99db27e1b87734433044d3be368d4de81cae184e2eeae04b6b8eedc69d2d4c0ecab0a774cefd5fe0eed1e2c0015eb8b45e12dcb3d34918f48589d6e0e460c67b92b60a0450d0f3db49e00c74a008fd7af7880f092a19604d0c8685e8465cdec866e94cbe0b302a9003ec72bb0123f5ef4bd5bbed7d8f814b4ae7a92310391c1d34bfb90", "a19576ba4704967f1c2dcf3d296afa7ec81b8256ef965f7de87a2e8ea6717eb381b12af7000fdbf919ab38f34bc7b92dcc6ef161a3a0416a8d07f2b77bc961499c172a19e1bbf2dc0f0e7cbe778dab9d4f0a4a4c67791a1e7c7beb1de8267828ebcd3dc91286a0a7cedffb7e0d71a93588e2cde514550f11556da549d3e40e1e01f67e9ddcee16d268dd2cd556e86d9c9ce3460d3da74ea2cb49d98d9e5740e3722b0cb68d9ecc1b68b7cb694360b47fec7539f8675103a7ba9d8d26026811b229648ca964066f4934518c827cca5ea52022b16edda98dddc685438b08bc06f693b20be7509403c7a2399a8d2c269512c846d01f557cdf92bd9ac8ef64db37bf872a92fa86b191dcd807a67216e9a038b8e81ebc61bffd9e9a73b0bf55d8defb8af87f6ea5b69a3e047eb58bc86468c6c86f814c2703b2253737cf53421aed183bc164364726cc84d339015b567a9f78f07e3e60e418f9aac50614108d03f0b60333b2f150a16670b71e8ee5239c9b1d645c24199ad76ea210df318e32d3174eb495519a925c6c653c7c4fa4f632a32d920082679578ef79d03c2f8297c176d9e5bd8284e533f552546f2b534e3a2a75b4327e3b89fbffc7adc15c3b49cf027874fdbd994131bac5c5237f8db7b468dbed42f65cb6985063463a06a61dffa1c13d07c1527ef5cc4ea4623a890b5d89c96b731a64c2b53d2a135e2a1b5e86a11b", "-418ea434b0c47d3c76dcd81040134582c70ab009603b0efd71b650708a4320866625455927acb6c40d699fb1f59225d8492d11b6d8dd0f88a8df2fa1f5863e75ae623bade30ae884d312b5d4fe87ebf42587ae510f2ae050b8f9bac283d56a7ef5bad4a6aebf51d57333b1b0250dabd900a8291b7bf7edf44e5537140b3f96e26053ffc9f26771f30a14eeef03a4b3d21e322b2d75686093cb09d6c820a56cca16ac4b83920356fe629837a1f60eb874d85ba14d8dde3522248400f80af2cf810afebb9fb0332d24deb72eda642842005554fdee6646ffe355d92f6b47b16be58024862f2422d0b78d4dea470b359f2b5b63c0308aeb5df3a509f65e16e363c4b967bb70f0b2c67e7558dca026f6c97222f22939c2c11fd3d953e094205a7cb452994c80eb31633793e09a2578edd6a78e066af4c719cb0849d50a6897f8badb9ba5424d96a016d613938f01b0ea78fae64b75e7d2d4850506859532064b02099804e1347896fdd383d5641ebdb2ce7f4e641aa0e65569cf57a107c3a6ca9b2f66f221a9a0a7e0d6a6ec85398b983e5750ee2b9d213fff629996a53e54e9939d6732537929b928d9aba6c037f7a7035589021353be5c9da66084b02c6f5c5e27d00f51a4736c460184dd1049f7c41814a55e9fa81a3017fb3e2bc746686ef30aa3ab41568148fadd0bb004d5e95fd1f56c65ddaff1f93d681da567a674c55a75", .Okay}, + {.Add, "-e31119579857340c5b32826075a7f763f12dd5dacc26d0ae5fbf193c0f7152afd3b902dce441e50cc407c0451cddd59baa576d8c530f64cce4b498bf9c821bb4b6bd337b0404db24bf4c317068130a9493e3b14ffeaf6f4694fc7f9f5d0b1052cd4fd1971b41870e15a0e5814cb11f3161ee5812e0637a8784d9a247fccc0af61c6f1734e82c26babd3fd52806ed68ba7715b00672bd526f9704b97dc515fdabd59830cea09e9915fd863d34f11451b57b007580fba3301502c597390592b3e70fafe092488f3c9f921616e24b1be2b49a4e3b152b280f9273e9b3dcfed339ee0d4f2a63c3a7abfb8feadeae42900b52013cbd60146e18538c8e6c152d2ce55cb8615b0470b1efd20351c2307d8a798262b3f2fe6759cf3dfea79c812a5d772889b0e45b8bfdd3679e69948fbb346195a053522b5d3201ce7ee7c260cf97426e1210e201ea4c9980807b2713f2d95694af411c635a17cde722c426eee6a5a988ae5ede6a3134a9c4049dfdba2291827d1cee6c37abf19b16e0e1b972799b7c93d9cfaccd8fb9318807712d79f8e33cb9ba62f417a886cf70713974918aee67891342cdd00019586e9a95cc23bb65b8f3631b6f576e445ab18f9b71eb63c52663cfcb759d4b8876841d2214c83e8859d252abfccca5d52ec53bc6f068367f7227ab1c613492bdc5c23a7043cae54776a95695352e70e0f7e22967eaaa22d0957e", "2dc122a54b86114c5850c2849da6a5456833d8231cbbd2e4eec07836037bc20dc04a1fdd21214f21669d095123195725c1c3f239a485770f9bed57512638912d9e8179f3191ee6e423873c1b323b9a275b06017115cd320e7b1015637934685df99642cf2e75c064b615e5edb20dd1002aa1022f1a27b6644fb5ba4383da7e94d4ed4f8e354fff75e2937b3efc12c51a30c35dac9877fcd5e38b715654682657aa2718927a60167408e20f5747b5c76719135474dc50be5f1a56377523fd3ac349cfac59a84f5801a5006bb3544bee1db58801293dfce6bc8472844ba8d788ce6e86b0ea37f1b088e9a3299cde7b03974173462d1080289e42f36b66be7ea5f8160bcdd72ef6db40b7086b75ba758abc9819c9f0a9c17af9809b716d4d1a7651c76e84b08ed1f3932b21d600c0b5919898ee8032e0babdc49f3c06970678ad16c5460f0369109604f4fe9662f1e5f0501d372b6635509aedc9149f9775b17e3212c69cfaa0172751a6adb9365c75a1efca087aaa4a7dab30e4f0f8fd9e9301520631c3114176a046e790d13f42880e9ed53de04445bfe42cc4b06f88071bb46a99c85f191edae4dc0f702ccdf174a4a79e59ab7bb5f64803d765b7294071886ea74e51992bb758f8cb08bb6adba8385ed83ed531ba00cb98330f32226d744e573e52734d210836ccd66a94803cd233256a96f6e8f92ff0c6520dafd16b1f4734", "-b54ff6b24cd122c002e1bfdbd801521e88f9fdb7af6afdc970fea1060bf590a2136ee2ffc32095eb5d6ab6f3f9c47e75e8937b52ae89edbd48c7416e76498a87183bb987eae5f4409bc4f55535d7706d38ddafdee8e23d3819ec6a3be3d6a7f4d3b98ec7eccbc6a95f8aff939aa34e31374d55e3c63bc4233523e80478f18c614781c7a6b2dc2744daac59e90adaa3a046525259da455599b379482770add7542b71183c263e82a1f4a42ddda95e8a4e61ed210c1f5271b5e86f5fc3e1957923c5e03438a03fe49ded15ab2ef6cff496e4c639ebed2b28d5ef772f9155fbb11f9ec879798bb5fb72a647b511641507babfc9773303edefb5499b00ae6eae3f64a2558d2d41bb14914c4956bac314eec5ca9a290dbd9854447e0c2b13dd4300d6c2425faafd2bdfd47347be8efa7ecffd0764d1f87c774409dfabbbc9c91e95574ccad2fe813c037b8b7c90b100f366449209f0fd24c732f959af875770f42b569b98416f911d82725df04483c61be08d52e5f18d6173efe5fbf0c074db087b41d39de9bc4e4291411fe05c3ab65b2e1ae52513d362c6eb43ac89050983d2b31e797a6eb6e13e73928b259f55c9f1144bc4c1c3dbb84e12adb835bac223539df5287d24041fd11d8b5219595d62e021737a6d279aebd4632d08b7be45c90b23d06cc9ede771b58ef56405af4aa8754383ebfe3e4577b1071bd75a3ad8b7b14e4a", .Okay}, + {.Add, "af19a07326df616f4fe2fc1964aabdd2049383ec58ce926f30249b391e060ca98e35cfe9ecff62d5ebe889e1e507805e8c83123e8f8c7b0fa2e7a29c32c2b741a91d71144371646051e996d87616a6949bc4d128e3f1a1116d0519122221c41c7f841efb9d925611e66226b60175689a22bf577e174699af48c8ee6d1a96d50ef51e47b4fcad205786ee4ca11e102d4ede31266bb76e4dcc8b9f81efd88bd142bc9e40f284db55680a64d5d64b0b0d3073a8ae994f2dd76fe0c55b3d89ff4c4d35604956db8fec33ca684b3f01170f9d802925d68aca85105bd706bd9a95158e5ecb0b9d39164925e4570b5c6c81050dad9a79a37debc25e6e7a79b164e93d78e4690217ea0def6154dd1d051d447a33e01a3ebada7bd6f35bf0abe70ed5fba3b87af69a9bd559e800d670a7a1490ca1632e92ff681e9d683c6dacbff14797121c4194ea3007e26c57ef5f82d448062fb86083c94094af03c010072a90968253e1b59d0b1c469e85a971ec1395fb45bc46412225dc28fabebef82ccdd9edd1a1b5d3a22f690f52b2862e9a536ee950b2a8dd6e85cd2a1e15d7632a5e679c7a3dabc5e7eeb30e6e9792f970c4a40f6f18d0c8c467e7641920b0a9bab349dd57130dbfe368ad7b81572c34348aeec6344e808a5fefa89a4517b1b01f9c03f5ae939a07556edeeb616ba93dfe66e30febb64348f8043984248f4e87b8ae32abba4f", "8e04373d11d962d8c5984dd852530641a059af70d19e2f79727fc43b7510a13a5a57bf728f0bb411755afbaad6a87cf7a68845d8df58a3d6e942933822cf5c572b51fa048244288c5c22bceb21601d2c03a8181c31276b71ae56bac624abc38cf444df894e5def7d03da7817c4fa4b186de8f256b89de161b7aea590dd608af70b7e12e946496487922d0c9c6dab08c29f74500400695a54893d9f92cfc6f0a15cdcb5dd5cd0ed72c670b9fd90059ac230fa8f463fde8c8694063259fab1835ef494587b853c45987912ba279e237a50a25f2e67f5fa612cc15a7bd45357d088ba15993bc2c09ff0799f2a9fa0b14ded12d4e0271e3a563e2d7aae87273deead5cca0dd7f58ffc087c24cd79f49efb842e8159c134259d10f7552b38c208b63dda9ebad0d1c8cd748bdcf7200ad83dfd0872b59d9d1d0dd08eeb1d97135b57c6da824f085f5ce95c0a9c2f0706d1daf9093eb5316391df5f3cdc83d53dc7abc6b21e9bd9c94bcea853e9f79ac0160b3095e1bd2e2a039c8a772a976502756f7510c28f76291c04acc5558ad5e915ef21a9f6ddd49d221f74f9ee3dee926b6c6ddae45dce8ee2d21e382fe0a696b97661ea2c787bb3f0064008d58cf6c941d46572761367771c50ed530e91912dcc2b8a0916f1cb7ee987288466b093504a9470380e5b5131051b0882992585b7b3f5d2031c418a9bf2008b74446716f74d1a08", "13d1dd7b038b8c448157b49f1b6fdc413a4ed335d2a6cc1e8a2a45f749316ade3e88d8f5c7c0b16e76143858cbbaffd56330b58176ee51ee68c2a35d455921398d46f6b18c5b58cecae0c53c39776c3c09f6ce94515190c831b5bd3d846cd87a973c8fe84ebf0458eea3c9ecdc66fb3b290a849d4cfe47b11007793fdf7f76006009c5a9e42f684df191b593d8bbb36117da5766fb7d7a82114dd2182a852c1e4197af6cfe1ac42dad0d58fd3db10a7f2a4a33ddf8f0c63f674cb8d9784b0cfac29f4a1d260cc31cc437b05669f3a89ee2288543e80c4e63d1d318291edece61718e0a4d8fbd6e9165df635fc0d3252fac06f59ca9c26189c9bf528388c272c2641330fefdf9deb69d101ea7f11e375b80e9b987c0ea174045345d71fd0deb1e19319b16b6d9e275c8cb367c7ac214a9e6ba1489d053bab38cb58ca5704a2eed8f6c3e3f28f64cbc8628b8e89db19e128c19f38faa4268e62fcec8affce5e2e1a93d438e4e5926d2dfd5be3ae561150ecdc22df54062c97493622c432dc634116c69631a5922b575f4b84252957ff3fd452d44c5a6a4c3d8ad151684cfa07e6ab86aa45bd41f140b5cb29516b3ac8e57abaf53ce39b541f60b97f47aa131f2b788035f6d02497d2447f42c61c1c925fd889a151bb2783cc403616d02f54404303d215b0c00ff07c742bd723ec9ac3e1884665398ed576251ac2cc1fc529f8d457", .Okay}, + {.Add, "-ce651cd7600fc35bee0ab85815ff5cb13f233ee259e92909e8f2a7fcf7ed0356df517995c1ecb5cec38a054e5f30ae02776362cc2d4ad3a4e91effd3a85ae6576d57dbe1ac1bdfe3a1e764b880837fc59354d55f67ff231f398a284d67ce2443bd9c20ed6c9c5b8c3d8880526b55c2180502ce323e22a6d9df2fe8dd22c0ad653248a1bd264d012b7142487125c0d02686f9ff833e89845c7b37a528dbf8d70628190af4eb6c130cfb3f27975274166903763cbf3d22d8c3be864e35a5f97996a4184bbf4ee1ef73717c38c4e5cc0bc74b10ebf09cc9c01ef429bad93ad4bba372575bbb483eca1ccb72430bac66e69539225c089a096f7dfd64a30f57b043e85789240f850e61f645d73a70c9c6ad5f3a843ef78ad6afc4ac73ad097a24e5c204bc92847a86bc33b0fa0a381aec341fde20dbbdc5dec37eacc25d941705a8ff18907817fe39a890093c8c7692fa0fe92a2f208cee7f77d084cc689ba3eecb5dbdbd4dd0c7181ecfb7f9f53827adfc0cc83e2076ae8e2beb14557c6c7b94f1f387758418a036cb6dff82171f8999cfaefe23d865928448ec4881d131d85ac5f0dcdcec08aeac93833119ac05170128c7a5c8b539839caee91ac49bd741f9ee1045befa3388c8b7dcc0e619e5aee20b39017a067488c71a3e66ea43d59e33ccecadd9c269f9c6ed6c82f0cc4a4716cb22d5ea6077bf8a44ac3d70c4739a24b779", "5fb75dd2d6f2081930d19973f4d8c0ed2c169d284afcd40838b73a33b74032f02cd3fd6b09ca017a8abb65faf60906a412aa0a46aeedae442386f0c2cd060f87d555dd815606e8dd592b1843844c93a40aa671146cff8299b38b66e855db0bdad65fe5c9ce1acc62c1b85e207c397e43f531375407da13b3059ce4259fc6310c98a722b0bd72ce6cb7b0ad507ae94a9c2b729b4024b4be248491f307290b19d57c7e23df1f2bb9c7fe433939110da294331e01e727b45e454991bec92b718e99627d8cc0bba78ac6c31a6c18ee8990064bfe0fe00c472b39085faa12c04e739178cbdf1fd386ffc35aacaa7e3a2a855316f1d561edab8483db452c7e011cf7fb6356bf3d44242f9c1b586facd7e97bac33d4873a9720cab5019688ef62a412441e68fd068607e919b68df464147a3d6b611e5bab163c82bc00664da2a463830693c42c69013210c5b88db66b60ff8e4e3d19bf1147416893768eb3931cfe026820e766185af825be9179bd42a6580c02a4ae7cda02a9d1cbd5cb535d18be9b2836878113c8f7c283ce6ca71964b9c5de14aa37495820e6285e878fa8a1c0d24595b0e8a58af0d7018d9cc6ae9cbb36185fd9362c77e1b7c5ab621d24ee62180bdcf34bec08951ce382c77a4e357d433f92308f9acdf9006b4056dc56e1db24d418ac0d95aada9d25c99c48ce8a924e06041c7aafaa73136a7b1931386c97c136", "-6eadbf04891dbb42bd391ee421269bc4130ca1ba0eec5501b03b6dc940acd066b27d7c2ab822b45438ce9f536927a75e64b958857e5d2560c5980f10db54d6cf9801fe605614f70648bc4c74fc36ec2188ae644afaffa08585fec16511f31868e73c3b239e818f297bd02231ef1c43d40fd196de36489326d99304b782fa7c5899a17f0c68da32beb9919b20aad7858a5b87644319d4c637f6a5b221b2edbd30ab9ae715cc405944fcfbee5e416673d4d0583ad8156e7a7e74f48f6c7a87eafd419abefe933a64acae61ccabf7427bc0ff12dc10908294e5ebca10c67a864811f98b7c9b74b7ca5970c5988d723c6142223086a6ac5deafa221f769156934becf43264d240ea325a2a7ecac3f1dd31b306afb7bcf3b5e50faadd241a1780d37de653957df47ed319fa6c15d40671f6b47d028012afa240c2ac5c0ff172a225f884cc4baefd0797ca50aed60b31fa819aed15617ba73e0f3d0e3db50886f0c8f59cd5e7b86c1ff911268037f58155f00a238fa39cabe45a1f3e8a290f62d656cb50ee0304d73f08ea3115700624e009d0e979a11c3a6362c3e9fa41893699f3ab472c036323bbbc81a37ce5567a45f2af45ef7f0d0bbaf7236f627eb25397d60468cbae4780339af93e1e9f977964c7f96f4976d9bace19d32693677ebc58a818952db4d44eec5046b954837bbc847d1cd1cde5c815173141c257933b2d8cf643", .Okay}, + {.Add, "5d6c230556a05dc6627ae5332ada8287e14ab432b20dc00b4bd71322ab669a0f589a916208f3dd2d24606b2fa742c0cc8bfa66ba5fa0eb20f12b7bab638a32f261003d0aee439011e6825b57420cf15405c49d82277fa1570805fad15d24f976bf0a8006c1c961b7b49db3d30b9e38685cb5e6331e9a7eea557175246e2e9e1261a9f7215388bf69c95d12d84faeb2931c289691f1bf30ad8bd668c94920c7fa0bd4ef55b6e3e6bc915a85ecf3255e7fe647b08335e2db7c9a3bbcde3f07b13df455e18f0e5a86a4cadf4aa5afa30f7a6300e9c73ec60f50ec6802be89aace2b68abd9cc35e0caefca85de0a89626477dd4423035de40d731b3936ff12b751a237a413f9fb20a4649ac34b82458ee4f068108f762671389011640e9e732c74d2cb1026a83f69f8179218429c99c5fe1dc00557460b459309431bc41baee4bf5272b6d78ce94d4df578239a33d9546c85fcb5d065bc3d1e05c514acfd0a3606577cc94ebd7c025a8d144da047c537067dbb95d7566ba49a54f8b6d417e609420d51fde1500a2657bffb786e09c1af1379f01e529a80ee14c5d6f44a0fad4afa96c73df28724c9a48bc0666805068ed934f0cc85ea22edffa0f9a879946221bfd801ef44b8a6e0487686586cef0d888d9b4eb4f6bea2ee85599d6a00f4f3236a152fac8c901a72fb0792efb125a7ba0230e1557dda8fbadce21ac6c8c1a2ee446f", "cd2e835870aa91b8a1a9c4468cb4d05c4b39fd7c988ba6977ffd63151faf22017805ade6144f7d2afb1fba827ee15f7d1c565bf8f57057864c9efba85860ef310c80f5661f54bb3ca693de1a098ec4986d7fb4a963f5d9325fa2818f752b93600a15bd74457b5df369302896a8e918d6e1cfde35541f01152d3c82059966ce0cc2dff40e3252535ae5cd7411a3470e90da5e3ae64bce2c2c2235b435ee3e599f353185c2aebf78194d02ddfd11f5d34ece722a85756d1edda0302bc519cb9453d1303a9d156078a9b42b002fce99a7b3220ba4edce5c1633b9faf936ce9239e3f0fcf24916b88cf16b610b2350cdef17ef95009b0b0d7ac56763d17458f3ca4ac9cd2e6652cbcd8c58e157f5cb1f1530283cc35c364371ed311e5df61669e4c6de99dc9f2a8a593688b09b36e2d2bf046ba3001289ebc8531ecca3f1c9e0684bfeaf2c2e001d25cdb383e72ab5ec75949c67ad2fc682df3ea137c34d564f13ac878fecad2608ffd59e3ea8db9dd2379799a44ce87c7a967ccd4463f48903d18020cfc0fd1df9a9623fc73aee8a65d64dece6e8703f19409518b09db282b947ca3b5624d1e391d7808e70cce4053bb5233b489f34eb2dcab466e5b2ebffe059d3d0290d406a30a765b237eff29b7353810f30ce1661da809245f73e04a512c2d30540860917d13134f52cb807e5c5f8144b942e292cc2416be7c47ea93e7c1f0f", "12a9aa65dc74aef7f0424a979b78f52e42c84b1af4a9966a2cbd47637cb15bc10d0a03f481d435a581f8025b226242049a850c2b3551142a73dca7753bbeb22236d8132710d984b4e8d1639714b9bb5ec7344522b8b757a8967a87c60d2508cd6c9203d7b0744bfab1dcddc69b487513f3e85c46872b97fff82adf72a07956c1f2489eb2f85db12c4af2a86e9f2f5c123f686d1783d8d5cd9ae0c1cff375f21994106751865a35ed5de5d63ea051b31ceb4b9db08ab4ffa5a3a6be8a358d34591c5861c2c23baff4e7f0a4ad57e3cb72d850c8eb50d222584a662fbf5583d080f59a8cc154c9957e135e6e92dda30538fccd9239e68f18838829d08736bab1bed017142604dec71f0f3a4a37810adfa20904d52d25cb4aa7d42826c9489965999a9aa034769f4514e1ac8ddd37c98bd222ba8575895315b5c61e8680d78c5279e716603bae96a73c32ba7815e8f40e21a991d7d9582bffd44664c704a60851a0404593b6aa20b5a62b28c492363093e15553a243ee81f30d1c5fb380c6f0d138d72cda24d282001223b3fa8f84c14e9c7dd053b0ac007555aefa4e7c23004426102941759085b7c0c4ed734e90bca8e582c15251f0e1bca55608e2c80620219abd21851f91110efdc38905ce1a8fbe11c5de5c4d504c905ebe3613ef998362ce834ed129932442c3c881c692d8d7ffa452ce9ac03bc7d1e4e028b476ae16a637e", .Okay}, + {.Add, "9405aa859d03f2216c741f71d4a76e245b48da9c7ec18320333150ae06cade5173de4dd2e59a5474fa4f16c9b1343210e10733949d464791668df3c29b89b5e3ea6582d25063a0395f58d2c17c0ec67c638ad4fb4de9fb4d7da025bb76a23eb919b279bcb0d7334e06f70ae8b1aabb938bb0332d408fb48daf2485ccdfbc7beddd81accd2a2733a5342f53bf0d09e2a2a0dc852a46d4148144e458ac3bdd09826b91771150d0d2249ffafc0d762355e8f6ef9b69efa6e5c6246c40a9b68c6e1d0f60b6929a29d8e51a80c3d87cd27c7a0aec220a5c9e5df1b67a2e222d632b6aaa4f885d3870a9f07a8297e3a5e28792c0f407ab11e326e2597e2008a7b628674b3035960327aa5038b84b3b87a391859d784fa8b4c8741db012e12a433adb40e4f6a13de0e075144c2f84962103c0853ea58945179a697fea65fc52005157b024157970beb790c164769651317e13c6740de552fe47189b0de3a9c66f868787ec44ea32b9341ea6e2b7c8f5112d48655c15d06a958928b90027cb74485b61c5a1df77872a948c8dd9558ac1af35e45ebf1e6f390d20a1d1dbb96f10d4bb865b646f2fcd53bc45503fca8ce0291a5de48d3918a48186015db80ad0471468d5ee45a11caeefc6c0e630546a9639980b0bcdcb031c4bcd9672c28dd6c34b45a2f34711d19188b6817dadfd4002c6fd2e87a113df3597889b9aa83a6ff65be31e2f", "3e2d604189e743991ea577d0cacd6a522288a384099242c42ff11c352e9f3d55451e41c475479b3e891b7acd08567a6c5d225e6d2f3ca024f37dc4a708c230113baaa3fa90a4be7ad9f0649b2d5aeb155d4c253c19cb0302dba28f35ce1cbda247b40b5af867bbf20af864ef0950e136c5f8d85f6b374935500f65bb75389268f5f1240069f461ee203c1a2c45175fa12a286e4b2f1360e424e141a1c2bae934cd6ed19690c91cf33b23e36dc4f63d4697c610dcfa537ef4c1e8a3f459f061ee801b3afc707658da3bce18768bb22d1370ef3b14f772101e71f745e5421c62906a4e82f48e878d5edc9284639775c0e754d8749fdded609a36552e723c4e9614604fb47618d24e0ac024a34d4d788ff3cf8ebe42eccb2f25e071bb8c26ca3cc0f2bdc865b8e679baccb4ed60cc1677fc0ea82dfb6d5e0ce18d289978a4496d8fed7c1639a266cdea84e42b93b6428381c99c52b6b4a268a1dd9a9a52de4b2e54d6c3bdb023d73c9a3028da7164057650a6167f52dac6c1a5155561cfb1be20908bacd53546fdac8866f05e04f41d3d254b5370ea3c05a8154848e7a8a4eded641c0aec9c961452e029ab78982c38480d5cadfd36b7ca9c8e4e2ab065cd93f1ac4f7d09887a0b81fa29b398ef33b243e36806e52bc840a2c448fd5626d025d1041cccae681fe4d325d15f20ab2f772a0ba837158a7e831c26a5ec7d70562c1380", "d2330ac726eb35ba8b1997429f74d8767dd17e208853c5e463226ce3356a1ba6b8fc8f975ae1efb3836a9196b98aac7d3e299201cc82e7b65a0bb869a44be5f5261026cce1085eb43949375ca969b191c0d6fa3767b4fe505942b4f144befc5b61668517a93eef4011ef6fd7bafb9cca51a90b8cabc6fdc2ff33eb8854f50e56d372d0cd941b9593546b6deb52214243cb04f37575e7756569c59a4dfe97f2b7390048a7e199ef17db1edf7b3b19932f8eb5ac46e9fa64bae654e49e107cd00b8f7bf18f0aa031bf564edc4f0884a98d7bdb5d1f54106e10287174076f7f8dfb149e0b51c6f8374f57151c473d58487a15cc7c4aefd0877c8fd34e7ae404be7bab7fea0c1bf9f85af8dcee88d51c21796d070deba193a34390849cb66a051801d7b469a399c6eecf18e471f6ed1a38814d4db74084f87661778e95caa49ac54011918faa611e5eabe95ac1e4e7c097483daa3809b2e9813ceb7e44194dd1b5dcc308a7e2dd0b5b4112e0a3667532beb6022c4fbd704fea5e157d2d43fa1982562d8c4cbc719239164045e8c6a35321840a71e023492649e7240256b979a973bf807a1c69e9d09830697605785552a5f1e9e715db39509dec063580ace1fcc79a951e263769d242e05a0803856d4a4eef35d1e848140e39370b8b2cea1b6b73f763de7ff9a89b54a37f5c60adf6745893494af4c0160bb7c14e26ed66b20f31af", .Okay}, + {.Add, "3135aede611cf049b0470c157c8ffd385290e83e3d7f65612eeb1e1ef60f2db493479843cdba1546f26a6309324a4ba6cbcf023a6eaad76e37b5d674d6c50342f3b36a29acc1a0b9399e89a03c1cbcb9253cb7197209251bd9c7136a02e1ab920f61067f1e40113e60e057fb839a66732aacaa7ff04b2148ede2ee8e579de4af80875ffcf2c3a4dfe078dc2cf957ee80aa7c2cf6ade322ea730d6ded76b99b6eaebbd605081a1a49830036f665fabd2df15015b2d891461ffbb5b39235de47e8c1b16437e163f6f09a01b38b6947f7747bbc7b379896581841212578a39030da9258f9a581f3cfc451ad8e1aaf51b5f7a0ed71fe9a1c6b816d65b05968f4af3b4f2e506cefe5e6fd9b84c95f892d85ff851714eb43135f0ab00a84102cebade2da8f7b400f35352a60a458eac5f713949a6f1d7e7d980db0c64f63bbf499ef3f2bfcc222f558f1265e72d10f96e92044568945eda89f475d91b66791c53742b9fc0f4c282f833c2b72ce04a9bf2736e2ed9a042b2d53a3dc2ac0c1c739589534261c61908cdd3eac890cb34dd1d6f0459a85ba6c871a0c09b8feccb20cbeee53a91542f7e537f8e282a3cf3fe448b0f3a6599587c9313bdd8c2f51a38895d0fd082621717c58472f1a4353daa64c159d99f0c44701a370c13e2d543abc6949684f151ec03539f2dbd796a8d91b4f5a5d14c8caa705de0693710419e029b27b8f", "1101649b8634e76867837e9aa33bb4b4f2a4422241cfa28610e4ef78b08d06ffa8e0d2635fee5de19d3131aa921bacff18b7b4beef37c4d18efa91a7c554eb54a8364475912a3433b5c3615aad99272fa0b459df2f7400d6e0c195beef102c24e470be31290cdff6791f40f269668716e4f0d11609f2a90fc5b376687da7ccd102f23f684a08b7d78c04f822652c065e9dfd20d7ac4900bb9b06e3a0684ed09cc1c74fea48d673f7cefa3a3a72008bd477b7a420c4910da4802628b4ee531324fa400a06bf6c3b3600f08ea6946a0fd7fd552350c552d97bce2c61b8087c2061dedac84d2a8ad9e61261c2b5d6bfe7705f6a8e5570b495bf288d4fafeb705803463cdc9ac424b84444c321f45cf836d8686f788068712b17997562cc469f690bc6aae10bc432d50b6c2272ffa946c1de7f5b2e2ecb56ab40841c5520cc48382122eb9aa13266dcda27a2824a210a118a4b9de7916af1867f2d345f8983385e9f2cff16687a48169924f14bc409a60417e73f4ceb1ae672aa7e6ca344e3a0c4ffb9cc886a8e51f17df4bbd1bd582ce0bae690ebd32333c51a14ae91cd595d48b1cc1c4d00299e87424cb13963aa9a1324a37e0f386191fb7d4611878662abf0c6bb08e465152fa9c054a342cc9f150b84b0870af58fde3db68474d024faecb36a7f774f10a7953db277b7d3ac7279103a6aa5d847994ccad8448299c822a43dcc", "42371379e751d7b217ca8ab01fcbb1ed45352a607f4f07e73fd00d97a69c34b43c286aa72da873288f9b94b3c465f8a5e486b6f95de29c3fc6b0681c9c19ee979be9ae9f3debd4ecef61eafae9b5e3e8c5f110f8a17d25f2ba88a928f1f1d7b6f3d1c4b0474cf134d9ff98eded00ed8a0f9d7b95fa3dca58b39664f6d545b18083799f653ccc5cb76c7dd44f5e83f4df48794dce5a2c23a60e14518ddf086c0b708325ef50f08e4151fa7130d7fb49026907b9d39d2253c47bdbdc4724315b0dbbf16e3ea0d032269af24231fdb2074c79119e885de931940f4d8730ac0c513c7133c1f2ac7ea9aa640f50d086119d68005800540ad1014095f300095465073e956b2d07b40a9f41e047eb53e625bcd7ed868d6bab848a22497fe6dc738b16eea13a5c4bd3680a35ccc6cbea6f3dd57319ca4bad48eeb8f14a6bb8dcc0e227604ee85cc427bfce0086155359b7f331cea2272d7f1390cddcbeeac71b486fa159290e6290a9cb52c497bf506dc8cd3afad4d95116483a1686a92d650c1cf95a33dfe8e9fb1b2f302a7dc8850b2a03d1008116a63faa4dd123cdad5e7f661c370575318ff80ed68024cf5508a38ee2c41849d7a4c02ac3375ad240d929eb41c1c3c32f05d69187f0ef6ee696a7456121224a77cf3c9181ae77c2a2245fb755fcd2ce8c6dd0dccf308e4f4e7c858dc86a977f6ea2ee9f2ad16bb586b3a84c56b95b", .Okay}, + {.Add, "ef95cbc6aaa1f3184bb1d55a51139d8faa77a65ef9c22d2a08a1a93a31f8ae3782d4157deb0e5e9c6a1f8d74202edfc320eee4c9a13a27e0341ca863e7d443a9f67030f6a46627d25bd14ad2047455cc34559c1d3dea3dc1030b976a10c6d89654768a69892d9adfa81d21b3a1ba19fc86cda7b61a884177346dd1c33284a9c3e9e3335b1a2ff6f5bddc39cd5bb4771ddac372219a38a860fdbfb2f44af9641d686bd93248594cc432e11bbfac32e069307379c6e8a21a950e57453d03c9b7c7df4accbb5f8c8f5e9a4dcd36a535847496acfc0193cd609c3bbd3f1cb037b6364cfb6b604b27b3db7edb019463a461b5d17272cd0323db6b4d8142965fb98a9f73fc5994277bc90cf50617abdac1d9c77d69024334170328868d9269b827eeffe02fb681ef3dce34d04baf7ab03cbc66037d7320092ba1161387078978eda26795370540272ee3dc55727b4f0d212c65a9990cc4fc307d46c177146fa24c76c19829c27d5cfb6700976d0f876f61dac0a37a4b9edb60ec620d199b8c66bd02f768a3bbbb7567dd39d05b3190d4afb91833b8c13a1e5229af5ae19c2a04576904d44dacc0b47502e80c072552da6a5d271ad6c11c3399a0527781d57341c16907017602c6297eaaf594f9a84982e86d64925fb7a72dd9144a6ccaa0c6cafaa0ba4d8b2605d08ea8e24b26e17a52c75917787a648eceada7db0204b4bcb04a35d0", "1523eb9d2083088827ae5c86e661e526d6a974a400c431c4b91da5d7739fa5f2102061671bdfa069447f052890f160f85578f20b598f53c8b52c7b16f9c7e105ea0049995a010e999b99d19a3531119fb0a361d76b0020c37b026e98fc710516b3475305a1f4001a36e2979b37edcac5fe10cc5719e74f8f7aa6f51517f16080f2ff9edc6c7855fb92e5503e2bfd315cb3f85a440c170120157b48db28b59538008bb8ac6b94138afa1770fb7a193cec6a7856cebae082b97da4a3db1f39ac8d99eadd139f492029f0d116c2f83e76482f25a07677737ff30f53457faad9eae420ad08b2902ab9e848f84399e66e7853a5156feacf7bbfc000dc61c928d880e6c226e5cb17586b2b98f826c9d4394e17acb78e6494604d9a2677baac0b32465ec6e4bcca78107eee1837e50824c3fdc4be6576343f17e9fd4d3f75f14683d6606f371d82a8ab9517561785d2e1466d8a69ce5ba2a14b8670d0e1da3fa422451f2aaa34d2df4a0e7d7372daa8796b9d55e9b5d993d8d1bac4e2dacd165fb4c529e4a49639aa6297ba9e1d43eaef9d1319df7aff92642408e411cd98ae1a725e0ffb197c71b1838c8a9a30437c1d2f89b60d9c045cadf962ae3e675d7813e7da3a146a1106065cdf86e035462584d9307cbbbaf90456134b61737417b24fabe3e87e62b07557e98a6962a2e95e31108683856d8a1994e6f98c703de9268adcce5a", "104b9b763cb24fba0736031e1377582b681211b02fa865eeec1bf4f11a598542992f476e506edff05ae9e929cb12040bb7667d6d4fac97ba8e949237ae19c24afe0707a8ffe67366bf76b1c6c39a5676be4f8fdf4a8ea5e847e0e06030d37ddad07bddd6f2b219af9deffb94ed9a7e4c284de740d346f9106af14c6d84a760a44dce2d23786a84cf150c18a0b87b1a87a8ebbcc65a64fa981133afbcf73aef95568f791deb3ed604f2cf88cbb264c1d559aebd095a3829d4e8bfbe918230364557935a9cefed5af888b1ee3f99d73fabcc5d29c780b40e08f4b10849c5b11a11a6da87412db526dc3c7d3452e4a12da097687e2b7d29f9b2b4e5da45f88920b8636233f5f3ed434388dfe3e75aefb27df2a2090a7c87750c2ad054d15c35a355ea714734c674e4d22e8839482d500ba2ac1e2e95448438b1360c67d7abf7178c8046e22c2cfda78f3ab8a0121ee6799f0136768679d7c03b79258eeaf466ebbe0c2d3f7503c45757e0adfea2fe8cd78168d302532b432a726eff468a2c671c8214d4851f51fca74f46e78757bc44ccc321333c0cc827632936caf34d81ec9c714cf67293265f88f72a63768cef799e6dd2872c578e1930300b5e932eb55a9434115e013cc2fdb8a7c752eee6f07c19de14e1ab0ab83ec5fabe03eb8791aa684a2cbedd67b2878334badc9cad883d7df9afde7eea86394a16772429de33b27042a", .Okay}, + {.Add, "-690654b2e764ae24e8499cecbec00e88a5480520d7da2b9d55f70322c2fa82f0b3aa7476c76b44a00952be97ad11854c5a8f0d70b366f0465f320bf9f7186e6ef4c5f963b52618e75cd75790f71e87b3e46f14c2306261ff21c09c02e2bc3e96d310768537f80ec1ed4b2250c7034ee078e4b631a9bb5f52bfc6813863a57947f9c00cd9c5c64aa8f4a9e7d13b05b2564c12493d29cf844c8e16577890c7a5b75fdf77ce99a47e52399f78119e7a8c4e092f425976bece251e653ea92944f12822a6f9eb1ff55c1eb5d5ac68da3c7622c1742e5e9dc911f3c7f8a696cd39c1c66c9d6889322cdae9d5ff3596db0ec425d169ee9275548eebc299ffdeec4241976dee6bbe933a44a12582a9ab8fc6a9e3796ac0e782af74f8652427131359e589ceb079e8d8e3d01502bfdb0fdeb89cf967723a4a2fe9834fc83a243d72ab5cb31ded763c4fcb6cfadb2910a49482a177c9aaa229d46896a3284f71b7004d18cda21fdb0c18a41baf3a056e8928061f420582abbcd27bdb20cb991590e820d0a582973cb7e2f8d46116a95ff253cd67d4d47cbdb620dc68edeee8bbc5ae64ae33ba74c1b3f4eca862ac1911912f1a46264110d551879cc7826ebe362d02dd80431ad0ebd9947c370fee36a7825fcfdc225def6c5c7d1b79e575f98ff63a90bde230da05031c567bde403428a49efd0df3f81a1e9fc2b3a3dc7e761e2ff69bef3c", "e806c9f58315757424bc903dcf0ef48f962a776a0be8e9d6cc14c7ae9bdbae20121faeb70acdb7772159caaf90a9d4bb6a7e4f0b3cca162d0bb056da572c309e5b43fc47a7e70f9ce3f78e9c1d0be2c6f2c2549e10df36ddf71dca8d208b0fcff092a9d816e3802750d339a4ce0f4473cd55acce791b4a4e38adfad8a59a5ad3d1914d908c3095e13f1baf1a864e1092b170d0c6aa4f2b086ea4af9622b80b511070eac9b491d907248ffb671505ffb82616bee06e51daac1b14dd810ab1bd01b375406ed6385f0ae14a9a7ec7edd0ab4e688fddc7d012669b8fae507c7e336d1740ca1689eaed9f88684b7136457ab8251c5a046a79acafbb128a4e559cbdebe30aadd383681f1f66c3e18578967b17bb2991400a6468c4f8ba90764245e95d3c93152c6c5a1d62776aba1b0a750dac1568e398981b559c03a994dfca65a1da068dc8feed289e9c94a3cfe88b6a0b233d5bf0c42e140e73aa22c97eed72a40a771052dab27f6162dbb2ededa0ca73cfe3905cc7e3c888ab951d3c77527d33ad32367d167c6e31bba52acf355ea671e524c381e8cfe929bea51cfb670de63c5c178fd2a9e56ac25b5e0ced0e871b80c6e491b92cd7bb25964f8a95297334935d94273c83026faa43f2e42325743d664173ad9cf3bc8d3c96c525e8280a6937bcf1ab1be6c07212a76643a0d7abc32d072e47912a95395a7ae3dad6e22fdd0fb9", "7f0075429bb0c74f3c72f351104ee606f0e27249340ebe39761dc48bd8e12b2f5e753a40436272d718070c17e3984f6f0fef419a896325e6ac7e4ae06013c22f667e02e3f2c0f6b58720370b25ed5b130e533fdbe07cd4ded55d2e8a3dced1391d823352deeb716563881754070bf5935470f69ccf5feafb78e779a041f4e18bd7d140b6c66a4b384a71c7494b485e3c655e8789807fa6bbe08e581d91f06599b09172fb1aed5ab4eaf08355768b736a1ce77c86f7930c86fcaf9ed7e16ccbd990ce4683b64302ec2b74ee15edb15a888cf4617f2a070072d39707b9af4471a6aaa3618d57be12b5b26915da5b36b69253b26b71f5251dc3f8788a6f695a7c54751c4214f02dda7e414137d9e8cfd13441bed05887b4f3cc939669632eec03d36de29b4393764d4d74aadf0b2bbc70b2adf6a94e6831d24c3b6f70a257ba4526e8a052c29d5d31a1b97abf43f6e769ab73b14e9a59ab77d081d357c7ed258b3cd4f077ce99db45b3a1ad7f6478c4548dde0db10b114cad8ac98426e66a5c6307af9f405e99755d5a8e816f430ad90a105046c432af0cc0d0b6343fa15f818e285d1b10f5f07e19f8b1f3db7d58013aa0a380e3db501e5e13e0cc5efc7057131a795650a96df3733404ad7ba3146d8a1f15be30973f71c2b14f2c5831cfd879dac0d116e3a41b96c9260f78330cc61f13362d728ad285b69e6564b8b23941207d", .Okay}, + {.Add, "-f4eef6099cb4f95bc2196a2624363cc4e3213532aa057a8bdfb931973d5158b4875cf4f953b5b2b7765de3054768bf3a712c0202fdc0b0c635f9551efc1df66c4298eefd215d1cb30eb7ffc9de8ea91e34a21dea0f9f85003dc5df9e42e38f1e0a7dfd670fdcd296c9bd89d33716220270bd93f3475a6c520e18d64d5f09ab63fe393bee0593a217a554ade8ef1667c9f5389ceec98f72c9deac9d3f1372259501ddb864e7d54c69a09d1addc8384ae50d8d88b148449eea139b97eabd3a170addb1cbe88586123e1bb4dfff0b4c9cb019435c57c1d87e20f30b174f365ea462ea23201e2f31122b7bdf915d7821280a9e177c71cc70082e029195b65a944b95f5300dbd84518037f53652fb59e5c84d9d4f99b491a783d444b4867e7db71f275570a2af7efc1bab5881aa701ed5b224b2ecf2172ce48888ba50b84f4a9ec3c5203a23c532bf708e6418c405bb970453293de80e5a2e4ae57836ae857bfd5dde0e7b778c106a283a2183d77381431a263cfdacc212ee651ffa5edfb959ae8a41d1ce5232412cc54ffd03079d3d036b056147078f6350c71eb4f9f35484edb29e6a6231dac094b5c9f99d3f3864adbf9d144f43c646f19a2881dc635cbad66e9d0c513b1cea365071eed598f27c25c0b85df52c2fafefdae98d21781c1d1412c3574fb5a14cb4d700b66367c03b385a3507726ad9ad662e0de316d35674b36242", "c79c5e3bfaa332e5de814b03b685155983f982962c47767ee939739789f249d0dcd897098dd0e90fc087246d4054eaf2982816e0ea0851b3324e304b181e22a6ea30ff31f7d4cc9ed88d6fe7e8f8b148d5da49acd7db77d7f565c56619174025ab94974b60b757288929f03987141629c52a5f7d285c825b01866748b1372142e6f05c22db039b64f42ff1ebd26aa7a6bf2ca9d2c4ad56864ff792b4e68ebfdae9df153f0acd9c1b6dde8272e7c9bdc1f4fcc430c50b667e8e25db82171e628adf151a6957143e31c2f90f4ea4cd3b26a8d91ebca1ce01cbf4939396a00f4b1eba6e2e478bc862c5beb6f47f701d59043fc3a0035e8596604745c465dc82c6d4f1a6cce848479744437a1d12291f82a2419c751c2a9881ce0cfeff1e8b7a9ab5722d3990b09dc282fd6848700cf933ecd3208b87bbb744a5a6ade1b8a2f852c2a461a2733642b471bc424c17b89ba537191ad3ace7fedbb896a8857df5c70e10d11f984c13fd3f95e92c9b1ec33cd5d2b8143e9a5777f0e9a76f60c92bcf151ddeabe610823a9a1af98e6155f09bbe9236d6add1ebdd09e8eb2706a9a32095f6ab06512b1b85ed5a3548e0223464ee29c5d84615f2b133980a669fb7233cb90eca820bccdc73b07e92e69b28bd7f7741a4884e3e018decfd3dc8e6dad27fd66b4298a5aa5e03ed89d750b6ff41d8422f03c0e9e2f61b03b4d6c862c628a3a7cc", "-2d5297cda211c675e3981f226db1276b5f27b29c7dbe040cf67fbdffb35f0ee3aa845defc5e4c9a7b5d6be980713d447d903eb2213b85f1303ab24d3e3ffd3c55867efcb29885014362a8fe1f595f7d55ec7d43d37c40d2848601a3829cc4ef85ee9661baf257b6e40939999b0020bd8ab9334761efde9f70c926f04add28a211748dfcb2a9006b2b124bbfd1cabc023360bf31c04e21c438eb50a8a2ce365ba17fea325dd07b04e32be986ae06e8d231890c4808339386b8575bc68a61bb47ffe9cb17f2e71d40c58bbd0b0667f6189706a3d9b200a7c54fe7783b8964f59442fb4f1d6a368af65bd289cde0803cf065e53dc6e6dea71cdbb4bd1507e1184c1038940d53c09e8f3b1bc35e930c645ab5bb32498670f020637b5875ff23c8471e343691ece5e59285b19620011dc7e37dfcc668f712d43e313a2d696a7a671027bd88151fc7cbc1ca7d677ee02fb5f1c10231461722f6f2ce18e290786364fcd3d5bdf3ffc6ce8a438573c54be06445384e96e27bb76743652ef7ef02ddf7523f3226c21bef22b350374a6474c67ac732a7059bd7773bd35c9d2ecaae1cd1ca7bf5be0afa50ec86fc4545f163048d1734e76fdb0544066907775c3a59799b58e41cf2f500dc29ff35beefdc9bea64976b96cddf1ae61edec4f5891414a943c5814b70ff6eeb0e976df12b0c0f960180603b180f6b74b2a590c4e70904c0fba76", .Okay}, + {.Add, "90abeb9c83f3624c1487317953d0744ea4a336801ac157cb55385a813d575b690492d53acd9614596ab3a955a809b1c60f8c98975acf80fdd9c0c7c8e636c6c5517da0bcad9ab2e56d9c5ba879df80e34ef0bcfaeff394fbcf19da7deb69bdce81f9aa54ab9fb91c612fee1581b9cadfedd67109a96fd2f75cb1bf6129fd7f0dfc089cb372ad73083734db1abe7b37b81214d8a0b8e087e51ddba5ebaa412c2076327e6410d16fad7fbd4057ed79057af22d3220fb8494726c143fce58955e6a6466c95ff0347655d84f2a94e67e583771dca90b833e2386aacba2f7847547b718da153c3c7297956dfb59cff6c6028f1cb29cfa1656b47518b1b9a89a07c4e417a043102a5369f27e186b2e4df3bc5d7dde08eb7940d280afe3b9a3cb17f6e1bae0287d1921ccfff61dd704b591069d8656849c7d982b98d5ebb8f1842842594de027d4c027d08ce99013e1e03a1ab44305b261abef16cbe77c9e231c43e892ed75c9f249d19e6463bb16ff74408182110b9019af173b73fd0a59dc3626ff83596a33e689132109addff43decdafebdcc4f744961acd371b0567600de823b0da5486186bec7d6f42fe98f4b8a745a7594ff35ad63dfd9e57e21ead924f923a0ae88eb17fe9252f3258ca30f639b41a43b71775dad2fa9318d46bc10476ae4c917b29e150441ded5431e96931305e26da700d9b5ce32065d612677f35ce5e973", "8bee867b003980bf460823b78142dd47768e202cf22b3f111a2d9fe9559f47da8350c72774a5d6f7d1c965717489a10a87d9e2657f965e1d1704bc90827fdc065e30ec59b8dea62fdf475e4bb31cdc52c1b24592660db641cf3afd7796066d716a627ff5a00989b0117ae80c9f0250b0b85450883d077b90e1f4c90bc16903df09e00eedebce7e3962a704d7e2879c5d35c152888ef6711456d7a3aca9848f81f3b3259ea3a7af881af9ec73ba19c4261af714c297dda5df06844ad26e5cfec79ff0ee2fb7fb179f29ca603e3954ea3a865d41ca3296e36e50a29aeb35206eedcf1e901f45a60eae9e611ce73dd59d7f9e216440ed775904510fc5a5bc0d19bb90ae582a4a5b214d43585a9f62a411152b7749fbc763781c919fbff447541a81a31a45c4e23972d1b96ef897547262a764a0e40f9a970b94d218d5863b09ea60bc3af19d202e8518a91e7096b6a7c901570713459dfad9a93bdd342fb09f3c0725f538a7b560223b4bef050e0a28eb1a3192a16b96b7fa0f319f6a6ef0e5b20db37c891142cc3aa2d899ea54650a38075b3fa65e6a3acdde19f52ba924eaf7b0f9c46c59ddbd9240e0d05fa35c1417d256537cef1999dc26d276f75ae766937364702f8759c354f7b4576d50a5f0aa73da3b38c42514abd95333585638f739b0bb114ed3aecdc1298f54334f3868b44768644eba9b310392205d66d08a73600", "996ad40433f6fa5808e7b3b4cbe4a2231c0c1882e9e40bbc66db347fd2b14fe6acc7e1ad44e071c8e7d03facbf524bd6b80a36bdb2c8e6dfab311391ee5ec485b760af8249289d486b90d18d35114ea87b0be1541654705fec0d8a5564ca24a5989fd25405a051b762479c964ba9efeaf95bb6122d404ab06ad10bf1e6140f4beca69da2516a5aebcd5f4b683ca3b17de570edc941cfeef66349202674d97518956db0bdfb0beaa6016cdf1f291aa1bd53dca36d25026ed05c7c847b7f7b2e56de65d842ebb427cfcaebd098ca13a6db1a427d28266791bd8fd5cca637c74ea5f5cbfe3e30ccf88057e16b9e6aa35c671694b33e252e2a055dc2b602f5c8967fd0ab2892cef91c07524df0d8441dfd6ed0957d8b35b70a0278fdb5a30f8d3889d511ccd96745642d11b4c68e2ad82cc7fca092dd77419c52230d4649e7d8e0ff59a3d6ee922ab8de7421faeb4ba497445876239605cec4667b3a7166174ddc535fd51d7cc527a088187a075054e31033b424ba306882bb14f024508325355aa434a1fc779d3fe4b3db6992e3332ba23e42036eaf4850804f91f5c8bb70d0ea88b4e4a84c5ca3b0183df69545c0359bf2ba646d7c557977a7eb495a4ed36f8cd7e4cfee10742e8842a0d219e46dfa4c4b79152ae9ef80f3ef2279f195aafa58642363b3023f2ebae7dc13d9c8068c6db21d871ea177e51696832c4e60658d1f73", .Okay}, + {.Add, "-45757fc72f089d26f3039cdb23c679b5259ef55bdcd411c982830a955fb61949d3245c6935c37b86f3af06875ece0ab0f8212248e4df36de8cc2b641f6691703979254d8a0c465a91826b9ff93501c5faa1dc4f11f5a0dc2e270a1f5bb37ee2b4e41bdf17aa89d8207b8ea32d59c15d9ddff8e4bf37e1714b88e427815c0cc9f415d8bb0783a63e2999653da7e0810d8f57fa001951167c873d185546dc0a1e8d41010d433b9e594956ecd3523cf0325652f835b176e17e3d716cf15da64cc8c8c17ce0c9b1033f67a2a8d989a0083d309919cb76bacb829d66018a2f3c0cb32e351930ddd063af42d93e1db1d6cef0b434736d0780b114779b8f0d182128d7e4cb1cbb27b9190e4ce4e0a60ae75495719b0b555265ceb92b132c8516487f389e2a30dce00a6028ef31d86988de6ad4b9ecf9ac76229e21d7f0a9ea5acbab31f69a974bc8d1860f6f9d29f25a92bc7f64d263ae1ae32c7321f82ed7538c081bc93c4a3c75ccdf12c0adf5c57e7346ea7e957f6ed770586dc8ca1c4c2b3407374939a9a210660d091c507b2d971fcbc511145676b2b260c8a6530ea3fc354bae20c3ef42eea72e72fd8fc6449277eca233c267ef7341d189e0867ae179b1f795f50d88acc51f7fcd9372bc9cd0438a0521f772b9ea543e7cd919c5c42262ddecf3a8dfe67dc85d65c546da77cd8cf02fb4d5487269705884f766f0867f438d49b", "f8113779f677768ea0dab7bab51e3a6ec0c0bbb3b01c21753b1515c3c4a88deecade0f380e8d83f86760157e11ccaa425f9070a3a2cfd3301925dc784ff2d857073a0a4eea1548df6c744e5cf1ffe4e2f514ea9e1d4ffb7d9dc746b36e7b499e7b8f509c89e46346e99ada81386f6db8cc38bdcbf7158f89123a18f135ec5730ba489344688829a9544136fce28f9ea36c9e96639e9233de9a50163db76c08278e558194a093ad0d37183c8083fc5b96a7d7c33bc9c518a6b79512ac4246ffde5545d3c588d68dcc3e26578f7d4387803e569cd63571664660b2b18390b676b0d67d65b4e33f81ae26a0d87c90046c0f9cd62ad249e36b0d7482c1100a000d35570de24ab3bcd9a5de51d79790f95551cdb4977941262aef35cb3c88ac6d85782f15786f634ffdc7aa7f2f86ea985da43151532beff02a8b132c2a3bf58036637cd3ee9be016b2fd65f544abbb9832083eba48eccd13a73360ce1f6a790335a23addcd8a929329c830d01c613d584243403187400acd0ee8b8943951e6d227a6e8f130ec09a4f4dee31ed23662c67392d57b7c9b106c0ceb5e1c9d4d4bc6a9da9e8409d4efaef355223fc97632c71cecc71f4f3f7ce843cea0a886c6560b6b0a4dec6c55f92eb359359993205e873aa1838c84a9c0643de2b5aa01989a73dd71a1bbd16afc3069f0c26cbfa3f40a2f64a3892bef5eba415d127e6de7ac978298", "b29bb7b2c76ed967add71adf9157c0b99b21c657d3480fabb8920b2e64f274a4f7b9b2ced8ca087173b10ef6b2fe9f91676f4e5abdf09c518c6326365989c1536fa7b5764950e336544d945d5eafc8834af725acfdf5edbabb56a4bdb3435b732d4d92ab0f3bc5c4e1e1f04e62d357deee392f800397787459abd679202b8a9178eb0793f04dc5c6baaae32264878dca771ef6620980cc16267e90e949ab663eba4570c06cd9c778a1a96f4b602d587142a83fe0b25700c2e07e439667e23351c92e05b8edc659d5c3fbc9f6e34303ad34c5001ec9c4ae1c8a5298e09cf5ab7df32bd2a7063946b9f90cf6a172977d04598ef401d1d859c5fac9d03e87ed7fb70a5c1698382b48c11003cd36e2840bfab403e2241ac93f5c8498743747e591ee4c726aa162a9fb38b761a8ee5cb1b0589281b8648dc6486d94218b9648c58344132a79df52fe52066c22a586126c6a11f1940e0b1ee0e001414b31f54042b3e5a71929c335c5389c25f0c0095623d39b56d9905293c7880c2bf2748f3391b432555696cb0344244d1e171f5cf0c9b741c436152fe5460060f8ebb30d8871eef8924515a6053c0c254943652d0b4852c98af8d04848cb2b309840d8aebaebf1aafd13e189a736b67ffe6dc9535a4e9a4f6415590b1b205615240da5567445fea2672dd3031faa93946dff18271b3b2c695634a4c8c7b4b90d9c0f657fb85eadfd", .Okay}, + {.Add, "-4c5548252a67bf22c3052beea0f7696b5bc3f0ffa704aac1d56cc395e146cbf7a4ac6181325b4a82e847a68faa688fdbc1245343ccd78ab7f21699a923c9503db9206b6bd2044f010151db470ff213ef67bd671dc5d5a0449bdf6c3ef21d380977a9461f85c07ab4ef496bc149ca9fb6a78f0d88e8d848906c483091242e766aa4375b2553677d4bda693daebbcd46f4ad6ab6555126f4fa23ff379ea3307eb08403f7418b51283aab1a76f5f4228ac4a89de2c4f6e1502999f1bfc78002e031fe9bb30c100056c6ca7fa341402138e92565a47fc7bd19f1f09f3687ab2a22755103e54d42bae9260c7f68168f395be20b463d8d94684c936cdee1a2926af3410741e762078bd10707a5ff080df38eabb3d80e1c3724483f272316979df176b6cadc1cb678a509b5b0b3fc5d18e9a9ae56f276be8c4f3b899ba3986dc7a3bdc44c86a5ca99dd60f550f9b3b04b5da576ba1a9b5b2ef15a2b72ffb4af759ee5df77be029b31482a1e2dd77a2ae967413a39d3577a74d2e5222cba0adc3e41429baa5a392dfa670ecd6601b3b816c41d20debb5153c74017f265ac4eb6ea80d5cdccd817a0f168e2f07a4f2f03f2a768aaa0090f32440c65026743c05763d372b9d28ce91c3ab906dd6f951afc4ef56ae48bedc371fa3cce729c90fee1b9bdaecfd6ba87ee40cf0822036175283ba0ca6b9d5834515e99c27d4ff121e451998222", "652c5b0e2741b5bc0bbcf44f7dc5c8b02a3596f6e71f40fe088f6a8723e6123c672609d8ff7b07a2625a5ced41ee0c4ebf9fda1b1dd646ff9a4a230865d26e10dd55bd9b45327e4b8bfc60480e966eb01293b73d36a9088e348263ab64818161a2bae22a46edd829fdacf25ebba5a5edb7cc6de5b63678c5a4735dc160c42e283f8fbac5195f9a8f9181c66ef8b0899ebeadd5dc5f8a0b8fcf96e0f1e3a5ac9e4390d92f8185d36771856ece8424d56dd28fc712eecb58b6b0ff2f5f557b298d21cbe8557fc0dbf989a63be88b04e83f0d6f987b0e99791a6bb4b1f989c6ec351e77ed4d62face20643898e25ad0a0ccdf56c58d74099baee65b62bbfddc7e21c5ad06ded519bc2df998236ea96e8d40bba137df93537664bde0b448904f0ae1385cdd4a54cc6d88b181464cfc7be5864a002a69a9a181e00198b9e94b55520aab92e54c07f7765a330aa4219cafd2fdb8e8d2d57f515e04dcfe6ee30c9270a31faf6f0b76675d7ebe2bd792d559fe564884df768c3b976322dc2bdbc90147787d0675d865fcfcce23dbf5db98ef39743654e3bf82fd56cd5119f88d7817b6514e07d7104f6f2b4ee0166a4e79263c9af31333cdea53d0965403c40e7fc45adc770669ff4257a1afcfc929f1c66b5a36678d5280197a6b8e3d589611cd87c0470ddde5e4c25053e5f58a551d38a2d05b83bcd2d263629c895e1b7f36048af2e", "-4602827447f3a3c702495ca9a91b0ce0592097903892b6b1f4e3cced6f086ad3de3a00e3a2639a08c22200c0d649af16d52a55a21afa2647f871f7789d6c295cab4b0f921db1271c489215428f08ad0466942ba9f26b0fbbb89746043bd51ff35d7d97fce1519d324f6e9c9b5e104557cc1246aa8d74e1041200fab50e223388203e5f7901d183a2e1512147cc423e5ac17fd8f78b2e54412705c98f84f623e69fcae9ae9338cb04340220090be03d6dcb74e653c7f49a9e2ee1ccd18aab2d992c7ef486b804490731e53f82b770ea65348eaaf816d3826049e3eb68128db3b1ff1c66786c8b3c44063bde88698c51d53d50d134bd27b2d87e792b76d28d2b5eeae716f41a3a3544280c7cd1235ca5d7a81dfa9e3def10d8db450b5314ec8608b7564ee1d35842dd259be7f84921eb55f2527417f1b5236b9b8a0ccf32ee68a3a1cd7775d95de98fadc9096e3192a846de8c0e2dd6fc444b252fcdc144d5bed545c30baa79e1b44641f4bcb1bc11a154d54b09830c0f2babfa8c481e81b12e242289d1d074073f0083c3f45a5d3529899b560317cf104285909aaf2e12ff5a68b7f79a2fec71f03b8c4dc85f0b1504e0f0d7dbf5656727f9020384167bd72d0c0b1c827c46938cc27298885d328eb5412574ee49f8a527b9b8bb75809ce532cb65dca98ff4aa02e3a408cfd668169d65e51c6724386398b4ba0f69f0f150d2f4", .Okay}, + {.Add, "-cb1e1fd43ea9f88f7bdb7a540172b371a3cb26589c286a90bfc51a08169032e1ebc58f3961032761eb15b242bc463813ef3ed68fb526ed72b631f287ba965a0798531c7c9bb4095d1f47800378db05e700d86b41da764ee85b35ed5a14b0c71beeceb2bbeefd54c502ee2699951e4a72eb407111e8f02262798332d3da4cc983e6295bcf57257d93add087a72206043a2a40d954fc6ad99d992fcb8bcfbcee3ef89a53c528faaa5f3a8b390c28a9927faf137f5b1de805aa88dfd251130afda3b767005b16a5d1d13d785a2489df696ee72191501438080963effb090c5ce58ac83193b9029fce562b3bd20649399e46fb29ab461cb54b21bb350f0cb51ba1ff0069d0a74b3449ba12ee15d239751ab3551f4cb40edff5ee825c3fdb75988a323bc6be781990e17fbae660cdf3a015bf58d49a14f63cc3682ff6f6c7b456bed9f34717ac12f7a91f5c5e0888b218dd5c3e5b20db722408e52409073603793a73a1f420d75fae09d286bd2c9c24b0aaafdeaf73c2983b20b46af0a4e5ada6dbd93063bcb868c1865d1278299f0d5e5142abfa02505999517a7bc4912475f2c022e8d8bac85db91b63583d32e5412df7fd65713a19653bed44d11fab6aaa91c203ce0a3f0c3fe52cab99ce80601618c284850542b02f845d26f4bd50b6e743fe0a1e275fcc100f7f24a5a61272f455d57ec4b9e8c6ac550c85b7f69e5406e71b12", "2cf19683d846d0754c9bb1febc9c8f5afdd26bb4425a3db5a9bf46f4148c3cec6f93aecbad8a8a966c580a7276d471ee9224388ba07367e0d6f0b077c798e5b666e9071de9497a41a7e7e16b93440f18168b0f12aafe47b898bd0f6405d48210cccb9cb58a26eb7e9ace0dc67dea6bad482225547d0df6d88e25407e75127626e916b60c99844d3d6c78872982d520036170bef31d8e0f287a6c8a7930c43531331ecdde66e05b1fe0d6651300e2712971cc215f79b34d5397da0670d671a32efe00149ff7e935319c669851d006c280fa7b735f2cdf68592d3dc9477f68b4bfa7c4027f3a50d310d5a9f0b2c64ad37c65bd39852dfd7c6be67891228281a44ba5dd7f9fda6b49f371037fbb3fe8d43bce0f2757edef892c7b641cd177f0b842d547d028ba485673bd039b58b2f30f157f5dd888c84c02c610b265832e6675ba8de59af0131deccda6970ebd2a483a9a6c3441d825e6641aa49e7c96623dbe03173bd5fc4b98c36b34862805cfeb83d8aa0c2739d055087c1b441fe16c1c91f8f23ee6ba0148b894cb7c4d3eb34df8385ba5306a395cb90731e8fa8c2811b3651e8146946268cb5fa51ac75695ffa4e0ca7563422dcd67fc20c849bc5e2260ab2030bb3957c45aefa274b40d19384fdbb12aad35188cc53790b6eab7f6f3068add5dc653f71375e66ff0880523a03a0356b2f276eaa4ad8377a235120d7bf791", "-9e2c89506663281a2f3fc85544d62416a5f8baa459ce2cdb1605d3140203f5f57c31e06db3789ccb7ebda7d04571c6255d1a9e0414b38591df41420ff2fd7451316a155eb26a8f1b775f9e97e596f6ceea4d5c2f2f78072fc278ddf60edc450b2203160664d66946682018d31733dec5a31e4bbd6be22b89eb5df255653a535cfd12a5c2bda130564158007d9f30e436c8d01a61dedcca751ec341129ef8b90dc57b85e6c21a4f3f59b4d3f927c721563d475dfba434b856f105cbe03c995a74b966ebbb1ebc9c9fa111c1d2b9d8a6edeca61df0e7589fb036b231c18cf430cb206d9139c84efb455591e15382eecaca956c71c0eeb7ceb5d4bc7dea3299fdb35a8c510770c8ffc6a1ea9616f98c46778710255c20f06cc206f82309fda7d1ef667eee4f5f488b0bfde2c57540ad06a9d976c18c2df0c0a21f44914485f0491f65617cbbffd9bc51b5c6f9cb87d0a2c1d226df034c3da4ca7f6a8a9fa13b7c708ab84adb141546675237049654c526d734a34c88c7e618384fac8504418a49e03e24d5fe6778cdc846fbdc605a10590a5054d1e6203c987349db96984de10cbdca577433fb505003b3226b8eab2e531c9afbd6d7376e8548b05761ae4c6f6158add983d2e820d1bbf759cc52fce072a8d3da957b16f797ef640665fef050f77f40c9997818fc093e35b58a6dd0b59b7b6e06f64fc1b05f0240546941f96b2381", .Okay}, + {.Add, "8bba284db8d86fdf7e9b836a654f25e8ac4122988e5c4bf69c3557b823f534aa1d829a9034a8336f480711339ca59e6384b3807fbf5bdd78f0628ddfe11a6b9ccdffc4c995613d04471aae7138a0f5ee3ac8e867112955692d492b12a21307808253e68d8700168bfea87f5860ec1ad762b13cc9c6d5936ec44aaaba7e2ee10026942a5e46789980c454496f9bd46a8fd80f8cd3ad56a80a648edeea4bcd53f5b052ac9a7547aa1cab535890ab88c91563b6fcafa47c57378cfa7fe9fa0b51ff681617410ed594758f893766d04aaebe41006c043e5e84b9b7032f87e85cb4c6fa649af2b44088af17b56365e212afbb7eb4af8125e00850a304006174782da5ce5c8f27272e10d3b08c6cbcccb4ed08b9529634a555296f736ea9afc18ca8b46ad7e5672e393c8b123dd3d789b0d92b903a19c88a47a112955421216e31aad427e67097d4eea6ad8cc70f74c74d1655a857295974c9267f9630d459d640a4e2da7c11180da3bfa25dedecb15ef8f97e59f553d6cfba487db3507688aa9b4b916aa1123a48b3562a2e1cd12b0737dff650c4edd679f1b5e63498e8d72fee09f8078003438fc0b217cd0f8a9ae193a7835a126669619fd9af448230bdbe64102e5090b2a2b3fcf8c3acad09f09490a165037f793c5030800734a02b7b2253d10d95102f1f2e2965db700c79171ccabe09eacfc058d22901a9256241078e930c7", "b84e059fcc909c01717880dabc3d5d1f9d4b85dc1351c5446a84f2fd155d2337fb40df517b9d2f1bc4a925e6e14e6f33ed7d06186e93006b2e168bc1a9c3e1e828eb67f2553d9ac8ff32c11d1ba1656a4f4159e10781c635552dcc65a525bac9fe79b7daa00ed5f9b4925ac06a54ab89dddefd2dde419295ccda1591575e4efd6132f671f43e11bdb119a77a11d5a390a57a88373a80cda601c0d9d3b177e9ccfaec28d935819908220fe4b41184b495b0fe5e696d92e6ff63c592add9774f4ac4e52613bba7203444483dff720305ac7181a2e69a197a8aa0d0bb4ed4cd22cf383f526c71e8d1eb1fb202dcc1f416d3c293dab2c9d475a79e4c7b89ac8ad006f08882b8adb01de8a7a432ce96b1a71ff15319605491547fa85725cb62400fcc35f348950893928fe4881fdcbba32ab9073c88cd95fd7eac2ae682a5203e380d0b2d458c6efee07e81cdc4f7ab7d1b7dd1145e7d20afb39af14dc71384eb126112a9f02dc6d068f1c0d802f0f4c0faf0ede3e64051f974eb260be390c55461c62aea515a7ea2ca190faf21c2353fcf21725c27b3a6974d7b96b6b72e2ffab9be5d55dda7116aa0e3fa14b304b34bfbb8a0eb5d00ab53d8fd37d0639d1152eed67ddbcdac6b5e8447905e0728935c43d6fc4c315aea5941441cc18ba48af1c10eb67ebc4f6f10d28d6d851bbc9e543314c79d12cd4ce12407adeae2c6830eed0a", "c109a824a81e22ff6962391162924f7e280f98059c378a03d4484878979c76829d1908fa7ee7b252b92996fa1b18c91a25c83e206a88be42bd1cb49fa7d588a1f5cb643eee93ae9943a46c042f2b74c932ede86778945b8be8025f16cf46eb42069ef643787ed762747ce2b5f0636d37540a10fa7aaeebccb91ec03cff413d0d639c3917d8a59b55bd5eec110b92ea39a2fb810475563826a809c7c25634bf0c55f153a2dcd613a9ecc51a3d1c3d41270739ce3467daac72dc953aac7918046abb668787cc94797b9d40d175df07b0985591a9a6ddff62d63c40ee475352ee1ba7e59c1b9d2cda76112d5913201541cf7a7f25aadc32762ca87cbb8fc3d252e14d6e4bab2022fef5e2acf99a637cf5f07ce842c39ee6a7169f8e10665e58da577ca0c6eb7b77265895abfd1a343e384bc0402a6a1ea1f8bd543bc4b7372152ba4dabac95ec4dcae95a9a35eef7f1ece32b99d112b7fc4602eab0d459224f1caf4051b13f47aaa4ebe6b6e1bc0ab08a88d3833b7dbef519730140eaf94ffe167f4194627e232dff7bb290eed4e5b34d20d76876910e3668d9fa0045bba2f99a5dddcddddb4a66ac0576e5abae61653630d68c8367416dd6982c1886a8ed392fd962e4d8d6969e53d3cb28d7c79ca54ded4c8428eeaf5c4944900b8e5c3d16fe1f8fcfbf4161f368eb2485e34e1020def5664a0ed2da03b422404106d6fbf81dd1", .Okay}, + {.Add, "194061792e19cf74c36b256b51e67c7471a7cf99d300cdfa9de74e66fb3701dbe6b554c17367c9d3a171a0f3b9c0c0df3d4cad01f8343bdedd2c2066c85ac649ad12f8b58fedf6cbcec35ee7120227bc8423f8b9e6fad89f27b7c9fabe6dd680f6011dcbd69cde1eb7968bf9844d7ce1e5afcfeba8e59819524b730e51720722679ebc1bdf38e5807a85d2fbec4ec5c109c2562737b3446ea24340c4a2d547ff3febbf3b7bdb62e4a836ca52cc8ddb24064f9517a8300b3029cb679ac841cc2b6aac35a264c49e7795e00510b4e3241613ffe777bd54ed8fa354378ab955ab582dc2c1c0b6a022a67385876b0db9566ef8cf3141be25a66fcf4123b7a31a67083665ebb93232ed6f15c4dbff560ce4d263645679545d980f47184f3d9f8dc23f1842559596422cbb14bfdb39f5dd4ab10eb4286d90965d4f75755ce90f1b21010780a2094c06dd953db9300a57fd78b9e4feb1bf5b8326df45e5b9a0f89858cdbe4ea646f0aa2a22f44dfffe66f97369313580bdcd5154c8d674f14e745f38353913687311cb2ec634af3d765c80c74172e71d48682e2a567c9a563163f04bc97fd49d3c3419838d4bfca9b4a18797b994d9822be494173b15cc1904dd64d9b18c9cde383c36c2b672f35afa8fefda5f3414672608fac3fe5e1e2ed8b3f19312ece0f8289a86311f1ebc5b6988887206ff20a1b2d1cea87166b784e2fc4ef6b5", "ac620e9cc539e8a2ad530142cf234e76890fe7950bdecd72f6a89724bd132475d01842572bd9f0336f318c943ef57aa4646e9a40b9f107041183240af3680a3ee9fe77400dd634488915a94bb99ec1badb0cab549b37193143adbf40d4e2fa66197ef68be36db00155c5e0a878fdeee532d36c18a770f02b691d7a5258a3dfee2bc568553d18fe11600ab1db5ef7ad46672fd75b68ebb080c468f20be044e348751c131cee7ec0f58a017f20367b8aa86d1cf97e246b7ba344fcc080be59d35da6347366690075cf3c7864caf791437fff09ecacf7ab8a94e60c43f8f1e512aca734b8fce955223105a711617cd3f532329c0348e505338fb6a23765cd70947d1613f1fd8e10be61166680363bf460989deddaf89971d8932f2326f72ec999471d35572b2777798cdad2ef525ab75f3306a9be8722587240781e6c5d83ec03778e56ffa51dfdb2afd32e37ebfc8dcfbd409856b34428d948f4b2aad64e7fbf982e037b415100049cb03ee6b3e0ef0d5d9e0baf2cf813458a1bfa48c08da5ae5042c3a2163d46c902f7883672235319d75bce5ee3e07229238782592d844f6b13094371488d0703d66e4c2a72510182730a5925ac53d2c01f493696b3dda54a3ebcae51db47694ff8474cf6008ed3d98170821b42c1bb055ad062ee96706eb36ecc9eab9b66db77d30f32ebf25ac604162f304937fbc1aa89c8154345fdba7f63", "c5a27015f353b81770be26ae2109caeafab7b72ededf9b6d948fe58bb84a2651b6cd97189f41ba0710a32d87f8b63b83a1bb4742b22542e2eeaf4471bbc2d08897116ff59dc42b1457d90832cba0e9775f30a40e8231f1d06b65893b9350d0e70f801457ba0a8e200d5c6ca1fd4b6bc718833c0450568844bb68ed60aa15e710936424711c51e391da9084d74b46730770f22d82a09ef4ef66ac32d0831a2b47b507d2586a5a23da32384973030965cc736c8e95cc9b86d36ec8281b869b9f8910e0a908cdc51446d25869dbac7467961309d424b500782489607b83ab3abe04d4f77abd9ff544d7792c98cc8a8d4ba12b6b348aa32ad9ff85e35b1d708afb854c79ddb6c043abd02c2b5c359201456b01523171edcf70a2763b7634ce575b863577acc0bdb9a647ef92ca8c5094a9e4155de6f4b2eecf8fed93c9469307247895d7a1ae6a04904510e767f6548b4877259708729fac00283a98647747181865ec52218841aa2ebfa48ce6b247e880c6cf412feac5649a52f26f3a0f0204e6857bd70a894f11f7c92c3773e87fd3e118ceb57c2c48a0537a041caf5ee83fb6dc89180e84c1208763ba48d426f2891a2c9f32a7d83866d75a5f02afb8bb0a23f0494b301383a012aeba4050fb1ec3b3e0a4968268cab5c9592e811d6f24604681b97fa3c40161a8f22def475be34e761d2e50eaeacd9052fb2eccc828fa097618", .Okay}, + {.Add, "-6d227b34ebf55d3067ab563cb3a31b653b5a2c26029991e937ee41b7b9cfa90ed65884eceabe714d4f53e40e64f564b9b1f51bbdc8897fb4c2783d783ba38f296eee1d7afe4d8352f778b43d26ec43e8dfe6f56d01e7bcfe6998e6151701023524615a57ff79619d3abd81ef4413d48e8c6a20375836b11a2bb77fd11fcc261e44b5784edc6cd6470b9226cff4b4db39e8f3434639ab161bb5c61a19ddbfe541b52aa67f0312baee244d87a4c8c1058fff6b8752fc2a3fc4013947923bb4f2e4e18453be4ffd0f923292785f0ac1d4f5a9960b365c184a7ec4093d30f4f0bcf450d848cb3799b23bce191d1be73d10facc28b3f68c40031791453cf13f1495ac844b740f4b647b51f060b1d3297b46d4dfa0207faa9b3f09373732b8c715e13e1d2f41334b9e0aa3a6f1447a8d0fa6ac2e5a7e892f5ae9f3d35758edb94c6c0740c35a41ba5e4e998bc4cb31a38cd2cb92870d34e99b091065797b151aac663fdcf69f6a27ba5917c705dae90f27830cc7d21f8f23c7989dd39ebfc996071f06d32e3e88a97502f98bdb8723608d74f53556b406eab12d2a539d59fdc52db4e275feeefed2a2598e561d32c8814f743c776971c1bc0715242a55ab0b9e6dc344b14f51eac7dc4325e52c14eca8a6c29c043f242ecc2d681e9207157ec2d3ec94bc668664c4e2f0c969a78c50c7e53d53bdca451e2f6565f143f0bc1ace33858a", "bc8c40c8b00bc545199b5c3f3a8b999fa2da74d85a23c9081961afec5fbc4e671413400a08af9554399c75ebd9170328c4610400774451a7fa4def068c525154d5115af61818de5aa8a07a63659ec43d9137b4331256d566c72e5a45bce040ba60e1e557d023cf646fde2bdfea7d134e419995a1e9f42e98d6e251b518cf6ef9171e2f01ed0d79d180e6cd53c2891bccfd219cdad20c515c693d288d1e82e925bad0a17d17b7427d4a2cc018fc59727ce193b0f501804ef5eee56ef7c7ddef4ca1ad9046f341d5269087747dd028af82c75c7295c7c0a3761ef23492ba6bccf50194bbfdf8e2ec09ac2bb0a2441f1b1c45eaf690d20458f93b3635d406378a489260b98d1951b39e25b4b721057dad8de34437e699779512d7fc76ceec24849483a70d8f775a4c79266d0e0ae862c5b39be1f5bf66d3ad63a86dc715bdb980f5508fc95558d6626636962a443d9297b050810496f2f5d5f1a808448d8227f1dd3cdadd627abb122346fd18e0942d58f5253f4f3b27acba4772500e1a8c5f39a27426272e97079123dc7dcce99afed6ab70437b13e8b9d49f687c197febb9901c78521caa20a538bfa6fcfba2e6f614a2f39a54e3e05141eb7889710665021ff8915995398e447e562229144735a2af26ad03b5a418aaae8db4e0e753cd21a46e6576955ec1b69121825e0a94aeedb122492ddbe76b19bd8908f1e9b8d2f4ab7f", "4f69c593c4166814b1f0060286e87e3a678048b2578a371ee1736e34a5eca5583dbabb1d1df12406ea4891dd74219e6f126be842aebad1f337d5b18e50aec22b66233d7b19cb5b07b127c6263eb28054b150bec6106f18685d957430a5df3e853c808affd0aa6dc73520a9f0a6693ebfb52f756a91bd7d7eab2ad1e3f90348dad268b6b310a0a38a7554a683cdd44093142e599498613b40b3770e7340c303e405a5fafe14a4878f25df387433986cece22829a205560f31edac27658c28fc67c0293c88a344c5945df4fc1ec566da8d1dc6675f6ba858f75ae8f761c57b1000b0bc7332c14939cdde1293865ce20a2179c2429a45c455e1a9f0f8e2c722f49c0e15457dcded384c3554054ddc0266b903a41766eedc5609a0c54416250ea3566677cc5c2bbc41d57f7bc9905b531f076d8777363778c36fd5166e28046d14ee0fcc6f139e7813ccaad15f129a05c4e4bdf9f762095acce1428ec978677b8b9d5fe43df85300b90b7ff73df78505d5e85d6d2fac03e521a99eb14e50f6581a9ba0f7e8a5ed928e2a50a245c63a7161b63aecc70cfe08a77514debf82268bdb3a02532dab4e02df3150dfc8da65a6a0667c30e322244a2cc74e33c5fac6945cb3e00a434ec6683b303cfcff5a8cfbec8aa8c491754c7d466f22d9d1d50a4db7d9a9100ef9fcd3a05818b67e43e70873ce8b6396c93bb45797c5012d9e04c125f5", .Okay}, + {.Add, "94cb787ad143b689a40bcf1a511e7af0cf50371b48707f3b0a08389c12178b00c6777a9af53e0a80a553bcd2d96fbfd25e8aabdf36c9c2f473f3712bc4646b827ae64ca1ed048070737b0867864e06c7e50fe96a0c5ab4c6dff6c83c0d2937f08b309844a79360225ef09c32186d87d669fe853c2de37d627ec7232c0bb69a85b4cf04cafe11399a59bc2f4123537333a441a5500207894d781196667670819f1c6676e384adec5f583596efcd11eed5c8cb7401be89c9ad3acfd0fd8ab1e387106d28aa3384c06ed346cf80be365b6468c5a547791db66e4e689781af73587796e540a53dd33dcf55867f946402ee1f61882dd7973fb7dc57abd2e6bb1d0b0e4346154fd0e23060ea522082634d22d18dea0d27c7c9caf1f1cb1f5cdf411cd8ec1dfd4bfa45ff3d2ac96e1f58414c4cccdc1337f20ef46e05eb69d992722b604f3ef3565940f98b8ac7c32494fc30188fac15ad1ba8704c0230aaee6c5ef18dd392ffd54008e663981dd1f40b7ae348c81b1914368f363d5415a3346e70a76f9ee1f97b4ac03843657c5d1fb2b03222f8c0cb29af0d08a9f0ca2102a0d80ffef345454e58ee6739ca8b5e2c23a2b942f5ef0348ae05d5848964da26240522a91545f54a6672c64b1496eb2cb9ee7a7915ba83e287d285366e3b97281203228d8d78a02e1eacfa4ace7fc72df9fa527923454e2d53b4651de120c13dec5cdef7", "b494686fc67b484379820fd8ba1ccdfdcb4cc13d6c25d2aeb3b9e64d8e12b1f1604b271aea24b3c35223fe59369fc3c9f75dfc02a7719493e34ba5381544731037ad752a08b862d0a92fcf72bcc65d3a6e4eb3ce551ec2f79c576951d4e5a5ae11d66a884f6cf4b32fe4fef9e7a80d221a10abc168dc8b706c3ad5b46c2d71d32127a87719308bc15aa52f35345d2cb1fb738152f2f63b729a1dd3a0fb9cd094e81cfb326a4b5de208ddf09b2878cf34f2d9cbe9c320b34dc4a04a12bf7b1e9d5bf33bfb0ee8f3a2a1dd0cb00b900556547462b2d7b977ab348a6869d47929109d9370f7ec3045ebc1e28584bdff6baebc10f4806ec5de70403ce9c003a544b30ae9fd197b4474f3a14e32b34cbb2a2150df01ed74182d07d896016485afa8ae0997da2504000990362c4f19399ac5e607a11949ecba962e53b21de9a3985db0a4c3d31e07e6e9bf08aa80a01a24593cefe9e054ebb06bbc4b401e2978f923a8a0909d2d58d97a0ed7ef745319e5d8d766b5df4a2f70fae424384734fcfa61e6189a115d072e7dad2c87efb85e32191025ce6aeed1eca3b289236c57f7edc0df3d8389f01ce3ddaed09d091497a6a549c6cc4d5f18c1305803351364be24e1ac3956c85096138328a3884d2b741e3711b75d02a3f98f18faa32129508d2d76457780456abe513d239983fd9497c84c73964467bf8ad3362d191faf04b3ccc21b", "1495fe0ea97befecd1d8ddef30b3b48ee9a9cf858b49651e9bdc21ee9a02a3cf226c2a1b5df62be43f777bb2c100f839c55e8a7e1de3b5788573f1663d9a8de92b293c1cbf5bce3411caad7da43146402535e9d38617977be7c4e318de20edd9e9d0702ccf70054d58ed59b2c001594f8840f30fd96c008d2eb01f8e077e40c58d5f6ad421741c55bb4615e7657b09fe59fb526a2f4fdc4c0122f6a07720d523404837215eef94a416113878af58abe0abba53feb81aa7cfaff701b104a2d02246c6064a5426db4117523dc30c9c660babd3a07fa50d72e1982f2ffeb83ec81883478b19d2a0383bb17690519220259ce1d9922580605964c97e8bca6bec24fc14e3012694c26a5548ba05335b0084cf2dec90f153be1f7f9ca6120c164f0c586f5b5d770fe4608cd60f5bd3891dc1232d47d2c81dec98a9c599d87c3360a8910f402c6746127e34a937243c4af2089557f95f6020758dc084d70c917e558153674239d0298e26072700d46472560bc202ed0f85e66003121784dea696b6b0955b77c0ad851eeb5f092044cd810e24b331e8f361880f9ac5c79ed8d5a98c5d0de30c8cf3e75d244e89b286740bb495e8cbcbb50a7c6c705dc8c99ed8ae22a04554e9cbd9afc864973b81f38582e0cb18acd17868681619e31115cc0789f3098d304f8e598dcfe376e6803c4c291c29eecb989b5ecde879b4afa407042a029a112", .Okay}, + {.Add, "cd7dd8549d2817a5d93a650da58c3b873ed9b4662082efbce5e44b8ccc19b6fddda5b10e3af2761cbea67afc8aaec9779ea6cf2a28e8aea98f0f986ff5ac54ce7bf39dda3abc504dc53328ee18de42c09dd4c90eea8e9589292f51fd288789887c98eb60d8c9970e3ae3f46a3cc83e2e18c4b87561e020e854f866bc429f4e79b99289c8e07b78aa2ab19a6b5a2175e67307911063f5b40883eceee1a322120d130dd5b265704c8461ec176bf416428922c1d3e2b151d020079d32fd83dd6c7c662c65860d8e9bf725f2c825e0ebfb89dea472e425cbade3645f410a1ca84a410421696206dc92840e6ceeeab5aac25d23022a8dec8db70fc473accda9a30fe47d59327b155ea4c9fdc53644fdae287234078ba7466b7cdaeb51bc3cc3e48fddf2e705de5b1aef120b2d10c56f06035c0ccd4a349357ad26c45a5b0a6595a3a2ff25442a568a896f0b39350bf84c71a2416bbbec5f5df8adfd06fbbf4c9a41e251c6eb52a2e1067106d8fb541365edf624121ade20aa82d6b8ef2c0c2830a2f27d2a93675fde858dbf4f2946f8363fac86e38897c937edc4a83fce8553c1b28da20fb9fbec35a2851c244f837c815733b816c6e594b4efc3b57fba4a693bcc4509b6121e816fdf0d497b98354dfe692e6a4834fcb52821df0dae3428913ac0ed9d62f9dd69f992d95d81e20047347e78ef128a0779735c282b243c9e374816e1", "a3ec8a244449d090207f3972666c182157563655bc35c6c8018f1bf518363473d05da73139a387ef72158c17e04d19401da843690a195f402f9f1a890d2e336a27b8ad2d41056d98f6c89a5b0cd42dbb861b1c002cea7b730f0907200669edcb4b8adaf12c795012464be88a969cf56e0ccd6ff7fca0dde167431933e8ea36d2e53f07fdaf8e4b4bcc8a6eac45b8d1735bdd7d24d1d17d62d98b47ac006097ed2f99586e5509d15f31a26168c31a9e0002440589fd501481735825ce08b797c1585598d4071c04a558255f119b6f9b5616868a8bb04ed07c932d4b8069f1eb147c51776fe66899bd7651de0483b76f626a1bcd7cb66d60bfd9086ac6eb04fda4e3266adb9b233b73778b4c3e1accbd5f76e12051582f1a5a4d6e0df1218b9df598ff3f58fedefcc13ad072d8744726ca31587f93403ec91b77f0769224ede28362a90cadc1624b9abf3561967ed0593c51efd2e34b2e5a1c538641c1d6fe259a7786639cab0ec1db4f050c0476faf9010e08ce9c16c62f87ed29c284d347724e0d82c90552a152882703f982125c14f33fa7767b18045170a5237bec568712417113d8ce76e5f20ebcae069995a3eb44a2276f798ecb961636562e9fd93eabab59c819947c43bd29b397df8990495bb4672bd06a1c2f6589793638bb947259a964acc131ea8303afafd56061953832090cb6a5238be068f4a3e68a2f6ffa10ec", "1716a6278e171e835f9b99e800bf853a8962feabbdcb8b684e7736781e44feb71ae03583f7495fe0c30bc07146afbe2b7bc4f129333020de9beaeb2f902da8838a3ac4b077bc1bde6bbfbc34925b2707c23efe50f177910fc3838591d2ef17753c823c6520542e720812fdcf4d365339c2592286d5e80fec9bc3b7ff02b89854c9ed191c69009c3f5f73c09179fda4759cee50e3535c7316b5d78368da382a9fa42a72e20ba7a1de3938e78d4b730e0892505d96caea1e4a17af558cb8c95043dbe81fe5a14aaa09c7e1827377c5b96dff52afd6fd61a7e5ff78c8c8a869a35558072e0d1ed452c4184beccef396231bf8d1df80aa2fb17cf9d7c179494a80d89607f9d56b081e03d75508283187ae5d1aae8abf89e9a973538bfca2de5702dd38be6453759f9ebd345fd839de34d2a263e25c9c7d39676423c4ad19c8a83862661ce50d817ecd509ca6e96a2771ccade935b8ecfaa8c52ca508d3d812398677cc94d4eef4defc84c55de07588a60e6f7321ae97a3770b25ea618ee90fb7815408aad5c6cb27fd815e65322c90a92549fc68aff12e13c3f354d634a71aa48c4cf132392ca631b9493d8d2561d122542785a3e365f238085d9ebd5e8ea427a77f0637e2bb2fdb39c36fd1377bede47c4e2d1740566d157876886e46ce425ad1a97020fbb0f547c96890d574261dc6cb081fbc92f2b0553c51ccf0ac6cda74227cd", .Okay}, + {.Add, "-a2c37285b556f94a0854489a0b4ed17e62de0b894b67ff8b9720c734bd9f48417ab7e4551a371a0cf01e5a0fa45bcc210921194287f8c5449ba9a834c062592bd4b9c39e965f36c6b61a67f9d44ded7d916e75029db5c3e32eacfcfd7d54933dfc1c46f572e535e7443adf797368101b93256bbe304c50702d9933424d184b7652113ee1be34601ea93b50c9e6c8a0d2ae9bd28e6666b23675779e8e87d58ec3ea5007e8e7d46a23b4f0de8365750f5f21cd98ec33c4607018499112110968b2a7e9953995ed30240bcb0fe926abe7a4313a6dbad4e7d48784e30811805a2864ac08cd8e893d0ad60e2583beab2ec6b521653a6a9e3c84de145a6051002709638002436b82b99a0540274659c42990e21917589f5193c73954eadc5158dd551120993890f63a14bccddce18d842f0b02cb5fb7103ccfb9156a54152aa2ad20c19c538b34624863b0a5ccfa4469631e4c0230f5c0a9c55778c865ee8ea3878e30a8d9f0c36cc0ba6a76353d2e14b9efe8e418742123ad8ebcee93f5909dfbd949e6699433ce0c77c690935e88c62c1016c461abf6bd2e293bed2d2842c33509db6c6646a5f6bd809d9f8eab8c6f6d5b0182e83caaeb1aaefd727ab5a23fa8b72c3b1228562381866ebbf185217624f262ae8c72a24d63424baaca492aca5bd42815f519d3e0890b0b72f3da68c8052e432041a313a8dfd9679dff6ba72fb29988", "642f41dead514562e3d74db2f20c495f5439b6b6fac77435ab83f40bc19bfa963d122e6b74a03d8714095f5cf009d90a56a380f6e08216bcc336612bb83dcc5e33c2671eba4f22cc7babd308459c2e3eb6052cd638bf30f74ef958438c40d3c41c286477d6c37e976ebab914a5771013473a7d15ff742d64b0ac5c78fdaf168c11972204cac363479c14a6085ecc7c58ef4f19618086ba1b0d001c288ecced844995f2f56ea0afd6085456e2a87286dc35dc4a87a4b7d363425ede7f6dd4a1d5a6ab555e27bba1fffda2f9605397d2349948e0ef17600733c5a493216f88dcd17a0d5951d2e413b777404869627f2de65a5275416dec07544f3e17923f12d383fcb834b1a018c31fe83c2e93175ac792b9386461401af7f1e61c4b9c51c185a45e99244e5de854e22f1c6ab6534c4a69b49ebd95117c0e34e70f99e571b3587418734f87da86f659e0d01b28d4f211d5ca48a3244d925bc5ea50051128c94972ec2d4cef478b0f573d882e25b2840569d6c0533ef13c4cfdc34bad0e0d7831b25c019f1a7a8a979cb7e461ac28a88df2a9abd30972dd72f35ad52f79e07dddde68e3dc55e542511f419b39b8adbc4670b2d472b4b3acbacc0842216aec2aee1ebb1453ebe05bee296b6b0fd26ee6e16b1fc73ad6036b10c622e98e289114147b604dd50f8508c1e408385a53c91739baf8c558a7e901c0485ab89fbb46fc8f3a", "-3e9430a70805b3e7247cfae71942881f0ea454d250a08b55eb9cd328fc034dab3da5b5e9a596dc85dc14fab2b451f316b27d984ba776ae87d873470908248ccda0f75c7fdc1013fa3a6e94f18eb1bf3edb69482c64f692ebdfb3a4b9f113bf79dff3e27d9c21b74fd5802664cdf100084beaeea830d8230b7cecd6c94f6934ea407a1cdcf370fcd70d26aac187fc2479bf4cb92ce5dff81b68778265f908a13fa0ba14f37933ba4dac9c87a0bd028882ebf14e648f0c8d0cd5eab292a334c6dd013e3fdb6e318e240e281688d314156f97f18ccbbd87cd53bf3e74f010d14b9331fb743cb658f71e96e53b5548af98cec712c52930507d89c51c48bec11435df834a0eb9e2a0d6e557eb17c6accec94f5fdef43e1178cf476ece90b5071bcf6cc20014429851bfda9ec076d730e2c09916c0f97b2b53aae083447b4530f9c84d83e03bac87c16d56c4fcdf1b94710c7637e8529c5c32fbb2de15e97d7abe44bdbcaca3d42535ab1338ad0f086235ea7f0d5820e2327141bf2b4848829083a7978a67f5195381e029d8aefcdc9d8382241ab5d8ed4a50b6489257f8c8e2b72bfd03826a50117b2f7e5df371d3c1b11490d013c9f6376df4316a389437537dc90d7ffdd46a432598455086754f073e10f78ec537cc49f8318587e0bb023947bfacb5a744c45b8049276abb8014feedf488277c4a6bbfde191f4346cbebe8b60a4e", .Okay}, + {.Add, "-f6e1ebb1119d2762de95ff5517804126487ff2b0bd420f253cf99a278604a0bf196df80911786fda4d8c705e730cb026165c7b7441cc4e0afd5c7b69200c837a81d5f030b6175fc12368a211dec54c5287eee6d2f6ec8afa3379f9bc44d392538ee14824c855cb1a209e888e76c8920404989bfe1819043764ffcabbc26ab648c53d8ee1d6b457967a17a45988819ec66e01ee80a4a1cf8467c42b23ff024b5c26d8fcd753e5ad187f27b5c17a619bbb18b403d05ebe2d5561377a8726d37d9818dbfa6ee7990db0347d06be9e297c457e0d9d65f657635fb0f2e91a54825c5ea3cdb73886a74425d9736b96db6e1f229f8fe0067751e2aef93f37c4eae37280f1d46fd7a0aaeacb1273d74ff41f08736cceb804ba68ea758974438a273a7b315c8009d9a132ee8ee02c8586fed076d1ce4d39d10e9a8224599ca6234adbeef2fb1445e68ed9fd5a9835ad69dc7d28261a7839b6665271993a97801d34d21c618998777c95b7c7e0328ba2987cd5a30cab7ddd4ada71e97b2df07f3e6e85faf401910e8d9c6ecbb12f3dc93d0eeea368e882812b9a7fac4215723079b08f186c10fe800bab519ddcc24e4c1cc72d7810981cacc686af04e2774ebd5cdeba0128362ec6d27ea75a76bb5f75b0e993f18e134688ed34ec606dfa1601308c1e5c3b5c50ed34caea3ac5aabccd6692583f7680bd411381ffac31449fae13b35837d2", "ebccb5fef5384d2ab5300e4f65c09a1e151feab5c3d38f649168b762626856674e7b66b6ffdc515fdf84d3be4a222e8f5e6b90eae9b87f6c6b293b948c2da17b36b2ef9f8f69a7a0cfe802db4e96574694b7d765525742ac84fedac9b9cd5351d854382ae76d9d3a2fad7243955d6126c9780c3b6622b4cc4f5989ff798e48f9ae8807f2e34600cd50b109dba2c75d253855457c5362a0419dbf78f564351aa523ecd42385e2e0455e3eec524ccc3dbe6e935c23c24e285145aafc7c04374611a0f88197022ef683e8087689507f6b603144260f5e5b29ea90d30f121e37a60851911732f52a826704e42dabd7eb6663208ce754d339e7f5e582006102b78b116f849f42c37d88b3d751063bc3c92b1b26a8936d4e479cd889cb3dd9b29d48ebdbbdaf8a2d3e6fbbf1232fba944ceb3c37aeba19f6faa7c1916dc5b525fa3132b31aa4cdbe5d1d9e9a992a3aefed67c52513260e223d93d30fcc6c3efb9938fe77d7c05a599c3f36033a1412488d85a31bef4c55b9ed5259d5f8bd8e4e5b50dd7bbafdf1d5327c48542eb4067e328f21da5a6a235c57cc300101e8fe082b7c1fa74fdc4f9569fc75d211b84e58e436ffa6f26d3b2b144b989922ae9d9e6653e18cdd71e7eef69ea55272db6ee50331251dbf4eb8a1390c017d740c7047c16a74cfa89ec85f747b1e4a6dfffe55a682d34389f13acf90f7663895ccec5381d59f", "-b1535b21c64da382965f105b1bfa708336007faf96e7fc0ab90e2c5239c4a57caf29152119c1e7a6e079ca028ea8196b7f0ea895813ce9e92333fd493dee1ff4b23009126adb82053809f36902ef50bf3370f6da495484dae7b1ef28b063f01b68d0ff9e0e82ddff0f1164ae16b30dd3b208fc2b1f64f6b15a640bc48dc6d4f16b586eef36e56c929669a7de5ba41a135aca904513f2f42ca04b22e9acd30b702ec28b3ce02ccd320e8c96f2d955dfcaa20a7ac9c7005041b8c7e0b229c378677e378d7e56a172c4c7490354daa10e54cc9775697fc3975201fda08364ab656523ca005917cc1bed48f3deb0382b8bf7f02f8b1a417fab913bd3763e82be76f824fd094dd2d62173b22d1143055dd58462624976c214d9cffa905b0749d324580c25a4f73f47ed2ef0955cc6a838b95969e7fb7179fda62c82ee06e24e1bdc047f9a118d07cdfbbfd9c832eec8fc060f56513a84414ddc62acb13de3938e36311c0b7223c1b88aa2f518e8634481d698f8e90f52084972157f7c1b0202aaa1685d6109bc73c4f68db0f153690bc14470e2817083e27e0121470477ba8639c4c69aea3bc15e7a166f03c93ce6e494110f12a3f8b5b9ab949de2c0ebf4053ad46a95154ea8fb0bbd168ec9a420490c068f5873a3493b3546c7ca1f4c0445cf1c68ca84e6c6b75bfa7604ecd683cb1bca33d334fd8b26eb4cb0c09e1275fd66233", .Okay}, + {.Add, "5da33fb91bdeea01bcd974a4343febc575ff70e9299e860b7ed812061abae380b79d204abf848e7950e2d801052e8aed415a02f0d5bac59c7dcf2cc447727189fbcbef13b00fc6bc66455228b3ff12fc3f1a1f44b70464e5bc5a00b580be5618b4f9bb03ca94540afbac5649b55e08f3285488a6670f5cc518964cdf5ed980c9b989d352bef17713f8956ebea1c7b85aad14688eb454695f3c9ca31492fe4395d7d31949822a8a2e4eb051642413120700ff54dcce054d38a27114e9a40ec4bd69ad7f4b96dc4accd8a1995f99729a09232f5f4f5ec15862dc34bf249de9cf70e5f50a04a38a71e43554439b423945c3fa0c45de5cb44dd7e1a987ecab6ed103b2cbbf4e3c3c755d0d9635e80ac7e0fe0a9df4aded19c8517f85e05ceeca0e4a91b2d0ae6a2e306bdad73c63e8646619213215e595947ba5583db4dee9449aed4160b95c93468ed75e568f22f6a3688bb54596393672fc2a2be9574331dc14ae14982f2029d3d9179dc7253e78a7b00edc74380ec768783892a6e018ee427499315af69032fed345cbcf850659bc4658a45a89b7ae55c2890c8231af0b1158633a7621e2187004e1150663e70f7911ce1e5d43138c3be2af4a3f22892d5d3b5d95620480d5b7e483a9b2a67e2b1f540eae1bc347b7209557c4b81f1583f33e6719bffeead611ff50f4aa928dedd934ef686df86198bdd6afa2a3d2c1a8bfd41a", "6f1038900b63e89b19d383fabd8efccf77c7498c6abdedc49aa7cc751b3863f5d9bf21347eee89dcb343bf3c7aaa6fac9b1e693a5e73ad607221f7fa47d23f083bd75344dff52271d487b6de107409bdb781c32f142193582135fd5b8c4816b39b726b624bd03ac2e8d7be0c49baa2698e85d1e3b54f7f6edc02aa4d9edb24698ed0f83574855cce1b82e1577236480171860fc717f4d3f314b8f2c4e4ee1c48831e87ca5722c606b0de1fbff73093a13535759636c081c92793bec8507b0e0db1b27e888a36ccebf79b25824ccbe4a6fa6562f0e5b569af66753bd08429fad98bfcef5bdf69e94ad0435035d3ba73e62b483c9fa8c53df222141bb3980e7bf55f0c1e8482f6c289b7e05111be6085c3a68dcee4a327c742c1a1bc3a370da7b341c3fffd57ceb7fe46291d2ae99b0a9b942d4795f0f0fd258e405b1d2236a9b9f0a25a4a8fab69092f645c78544db1a84a30034feb6f672c5b2a37bbd24d4a2ddc31986ab1705385b9ca1f7d374f32d870f26e9d261a0a66f14cc568df2a805209ffedcca6ba48ec41f9b531257d8946a2dc5ee51c83b249fff5cd67f9d8d54fc8e3cf99cca2934710ad3d41cc64cb54787dddf322bac8707428ecfbb4101cf2b4df1592523d59a89eaabfc47f5fc291f07e84521a5e4be0c14f8e554fbda70bd23f6c3d23e315b17ebcdc5f6323968279de69d8f8ddac99bbff912c5b2ec301", "ccb378492742d29cd6acf89ef1cee894edc6ba75945c73d0197fde7b35f34776915c417f3e7318560426973d7fd8fa99dc786c2b342e72fceff124be8f44b09237a342589004e92e3acd0906c4731cb9f69be273cb25f83ddd8ffe110d066ccc506c266616648ecde4841455ff18ab5cb6da5a8a1c5edc33f498f72cfdb4a533485acb883376d3e21418501613fe005c1e9a7855cc493d52515595d977ec5fde5af1a113d94d5034ff8e71241b43a5a83634ca7304c5cf01ca04d3b1f489d2cb1b5ffdd4211317b8d03cbee1e63e7eb01d94c2404476c21242a9faf52213ca4a71f1f96082f45b2f059793d115f3b9aa2554827e05798bca03bda3a0437d4cf911d7ddd2bf3337e6c57686f9c92866c1b12bc39290418f9441279c9725d7b5fdd376d0abc1fce86a2100598ed1ff70b4b55f5d7b868578cae67e0ffc0b7b44a7320313a722f1f7e08dbaeb9b4af11a33ff75998921e2635687138eff04295edbf0c9c78adb442c9d579144bbaff6e2e74d66a6abed82829f83f3a581cd6cf4eb3b5ae45cd9b91c320dc93a377f39cf9f4736e89ccad974d30c77ff1704ea2db30359f17be512982825b3a128dbdddd2296db2106aef6ab1fbe680f84e16d58504a411a1327f53e2c485d6642aa7f16a09e9a4799d17ee1388607ad6ad3b0e572ebff6b27f9f5150273676eed50fccb71e24c623a919b83495ea363ee03ee971b", .Okay}, + {.Add, "-4714b7e6bbf1ea51565ffa0d6580d8842702266fbeedfd4e72e5ef75ea246ad0b59c5f7628b86d9bfd5075f4fb4a6ac82558a98deff895a49a620003fd315c9d621371b0fe17eaac8a71684421560b8fbc3db36b623f7b346e28d65979ab5d9152de0b473e945743feae8e0664d1c1e5a2cde8f194750bc0ff6d989e38ce4cf297e7ba6d9e8dc42bada16a0e3593fa417fb2816299d3768915c567b2762073f1478bf4f3f68661523ca7b80516a18f00bde3177adf90834c0c71f512d61b36acd3e2819e0f6b1497539d854086e22d6027c76a46003705ae24fd775da3f67ca6a1c944570e73cecfcb0b741f20c83b6f7b03603355d301d00f655969ae227ab81a877cb5d7bd922470aabe82944ce85acaec527c064d1d28f6d9b495353b9759d06e7a3a0791dfb1e1f5154e55f0c8318b6f79489fb4b504dc138ae4da7f6e8a8049b684817e6112ad3dfac9e1c10c5683beabb502bd9c80d5d34235281822120a79a1f19f04eb63926c9a8317d1b1314b960ebadd9a1b1d194e6106547d9c064d5e93fbe4e62e413838415b10efc4cb144e549b3828a583ca3d4b3e122d2eb8f243298560e821ae97ee1c617cacf9aef90b47dc4e51cf77624ccc14e8b935cd64bdaa654ce27332831576efc6b4a34ee247906a84f1c0ae9e317f09195be6ffa4dc0035ea8ab0ee8de6781a4f07220c0dbe3f90cb2fed74cfc502ee23b8a7f8", "5034b5562db14f92d3de9cf063189c98ff44a350e3d03e0d6cea746a65afd8e29315eca029fb83bdbb76da53344842380192c02bf5863cf2b2f942518b69f76c27966799bc71fca5c6d84e4b3f3a39dbb59d34c98aea14724554399d41fca37a5c4b36e30becaffc0592cdb286b52343d194115efa5b569b612f111b444b07219c21a44cc16c87568792b87f58c15156f3490e436d49d570d7c5c2da471382126449c2bd80cc14e2735e46f783b578a039ea407653ba3ad751d5e2e72ba151dd1f125fe42047a3dd4bd8155e9d2b38b91c8a968b0ef42c073ccd9f90cb6715765ea203ac23c1967563caee7528fa932f8d4343b936f849f587354b86736e5c27ca6ea0938101b70aaf166273f9ffa68b0bb7fe23f9d55dd04d1cfe3c43af312ba5cc63c71cf7629208a90af6d25e168fbadf5bdc0d0438de0374b650b6d2f2b19a61f0177e43e8a8cb71fa5ec522dcb4a7cc5fbba4120cd90a6aaf10781bd92a0a7af7bb1096d569b898cdc5079768b6608d816529e6a173ff65e8abd59f05bded5ae6ee525c6f2d0a7a16d9912649bc438fa5bcaaae7f70f7225e509cb5b6fc5a12d855e1670ab2e1889b4945c5d17f9eeae5f583d74cc47068eb0aa4faf9a9c8745fcf43afe4254409e136db19be3ffba426f2ddbd62ed405475617725ed9c4182e3a5767b84d11ae7d478bdd4b4c2700bf0d90e7a4a4546bffed52e57f851", "91ffd6f71bf65417d7ea2e2fd97c414d8427ce124e240befa0484f47b8b6e11dd798d2a01431621be26645e38fdd76fdc3a169e058da74e1897424d8e389acec582f5e8be5a11f93c66e6071de42e4bf95f815e28aa993dd72b6343c85145e9096d2b9bcd5858b806e43fac21e3615e2ec6286d65e64ada61c1787d0b7cba2f0439e9df22dec32ad9f14e71232d571573968ce0d3765ee7c2005b27d0f30e211cbdcdc98a45b39036b68ef26d13e99f7c0728fb7429b78b4563edd455861b304b2fde4610dc8f45f83a901e16490b58f4c32c450ebd265917d02833277098cfbcd8bf55154dc7a598bf7a56083257c0123fe385e125482577cff21cc54be16fafe723dda94424e63e6ba3f165b2be3040cbaba7f38840a7564349a70e7399d1d55de98d156582e026b3f5a87c6d4e5e2f6fe2936d4f83d927612b6bdc5384271a183992fcc587961e33ff94e361d05e240db406a154705834976cdb5003b718000155c97191ea06262c3341efc5b78514f772aa4c4c8656e61787a5812169b79ffc52f26d7640ebd241d57e803684f12f4151217285d9ed2ce513128a88884367cfaed0807ee904499a7ee7c918d7d0a5df9e1935857d4d0e1c1ef5bc41c3dc63b6b569f6cd70f2c0f46a4714651af1195c968858cba23ea222f6585dca069c9ca6e36f8bf0d3e28d015c5e6ecd92b6624db148434a5cd076fafbe70a9f5059", .Okay}, + {.Add, "5305a95eb26833b7b0e05105d58a5aede70edb7aa1dbc8b70930b4fbb83c368599e21a59bdd0101c685650d281b69d47100b2c1857a3556161b25e2b6ca92f6a0fa0b2a66cbc9f9073fe1b45b1a6aac05dcbaf5fe1efd59b113f6c5b84d5b36cb0418d9c5d5a7513212e5a87745e40f6cf1c6112bf0e206bf2286615e339d42e67d5ceb1885ee7ee777b13525ac63236ffbb9a914dc462c1397d33b92bbd2a7e1eda82d89597a65ac33cdb1ede35af69edf64c452a6526ab1ed1d0c713383c5f62f3ce16e95023f6443f8888aac88d07cf7e70601d0612f2fe6415e789ea6ee8de1f081a696855405960fc377bb7e721c37a5acb55232b756d7e687389a6e2f7e4b05fd96801ed91ea984e3a4c16a53bbd1a14003a73775e1b4728a3992fb1ec40a4f9363e733dc1398440b8a2525245c0884e33224b4446a04b81046809d637ed909066f47242b16fd5ef34e9db7f6b44cbd7d3c361123fd09b0471b1eca692fafdbdd3c9754140e61f18c4a23b507634dd6791c6e2825c1eb6e1a9d3c113f21bc7ba5d499394a94201c45b4996d5b3035e4b2a25a949526023ffa63a1282f41ee5a674b20a146ef56895b116541861d3e8694f48562da1db418737a0f94767914d46e4f4d5f2fd5f3b899da8f19b964480470c59d1b228aecca1bb2da3d3cb403e158270296e82967da487b5b658db35da26eddbabaa4ae13e9fe4e975e1a7", "942390080eb062761faedfc3d9c4a10ac6e5002fad78d41ad5dd37e2498c1e254cca004771a252f56202beab4f3990f53eab81e841bca4e3d851a2b1d193359eb7d3f67722be5099496a5c4c2df5d3e4bfbf857cf25ab6c5ac772ce4d69faa246c25019dcd625b62df47c9933fee7b140d24a9d290615adce6eec24d8e9fe1474f0b01c85148836d9681a3bbaa3f769390d16a2d47faa0cd6b75bd462dc86c0c8862ae74534e4c010f362268ffb6c7426466625eba9361da2812933044dec2c75e22f9cadd30dbee14b2e80ac31fc87acf0411e5de1ef335e79583c3f95a73f89524c71e053a23b3d86d2b439be5c0dbe27192decd85660a3bbdd0afff3a6c26ee84f3a21f319a9e3298841333167ba8fdbb43528b1a27080c3add01685bd3bb1142a74e8546cbd4c3a17e8132619522aea2ce66395fab4cd078be9d5f495daa424489265b73be1227b357dfd1b852f212b2debff849035c2412b0232ccb168578ab5e5def1a09b494711b02bb0dea6261bfccadaccfb3e7a9f161c594e74a6c1a3e1194187aec4d6ccb77fe6034c78d4c1a476d6cb594fc787f5711c39c631a9fb695c6eb66e8401611f47115557c1abd7b3a5c23f1454dc1042db85ea5fd591c37fd9fb5a97fb0a5494454e4079eca5a84461c4e0fa3fbb93587b1d626a0c5d07b9f32fc2cf5a1daab56f55a8a42d21f8b781fd7d4fd177ab2b775f7d3efc6", "e7293966c118962dd08f30c9af4efbf8adf3dbaa4f549cd1df0decde01c854aae6ac1aa12f726311ca590f7dd0f02e3c4eb6ae00995ffa453a0400dd3e3c6508c774a91d8f7af029bd687791df9c7ea51d8b34dcd44a8c60bdb699405b755d911c668f3a2abcd0760076241ab44cbc0adc410ae54f6f7b48d917286371d9b575b6e0d079d9a76b5c0dfcb70e0505a8ca908d04be95bf038ea4f2f0ff5985968aa73d314ce8e5f25bd272fd87ddec76ac525caea3e4f8888546e463f75816ff26c116c7e1c680ffe458f270936de855829e828245fb250628e5f999ab8344e2e17343cf386ea278f431ce277b179da7fda5ebedaa22a8917fa93c392388e14f1ed335537b873388301d30d24d7f2d20e4bad55752c58d9e66278205a5018b85a751e7a084c3ba0995fd25bf39d4b3e7686f2b1c995baaef9370c43fa1c75333e22fd5198d4fe600c397894714bb93d25d577eb693bbaa159bf4adb494deb7bd1873a91c31b88f4af57a9033c75d493ad8969d343f73b23643c8a8436f68a85e5e3605cbf1620e80f6aecd3c59a9cb9d404f789297925ede4ed8a356b7fdaee60ebe9c3c3b9d70fcaf0b7a8a222ba9947c9163a3ab6c4772ef9c45b4efff9f44c0ad854484aa7f72ae0484cdf28cf93a609f048d28a7e156246802296d03ca749110b9b4b56c5664247128fb7d10409bad55659f0db380a7625bf1575ae149d16d", .Okay}, + {.Add, "-b14b264dda7b256ac9ffb0f42b83f66b49d9a84c3d9d54f60e7c76c06e1b3189a41531d214ab0bc983314a94e349411682b2e8886053be54b1d57487f9a00988444b71ac09667be3fc57f52f85e4b34cea11491cdb048f332d7331f326cdcf961ea6ec19c6944eec0ffbea48058d285c928a85d8de7614dc607e96336e0f5c47e33a0bae9764e00b18274209570bf10fa854207ab669c9ca42154b0590ab87a2b0d7ed7cbaa9e8be6b56dcfe98d59ecb0aac3f2468bd14de89dd589807f985cc27f7990ef3148114006e1f807ab4d5209da98f616b42bbb6fd60530d3230bab1bbbea77bbfcf0892b6ae52ccb3fb7aaa27dfb581bd64f27d50a1b24e8ed3839d23239692db24225b7c69816ff75d2897231ecc92ac14a40bcc67a84360dfa730ad963a01314644b5698f401ca590147d5c946d2c7475a75accf2c303463c24cea3487ef6714216713d19711e617d562bdc10e5a5dc38ce82df22c7880ddba37b1506006a93efd1de324ad93d6ae7f0a3524b4babfbadeb2b3c31909b27c1ff54b59b52a74c24bf3f9f7eafac008fbe776ee79f2a19b19bf6f7f23916421c488c2213bbbf2b7a00791122b8c8c0f697acfcfc002e88c1f503b125884ca091e1a0177edd902baa9e25abcaacd1cfebac9d0436a15eff7707ac23576e178e2e935e18868860d2fdd666afd97bb167ad8433fb80aabce921ab3beac4c2e849df28a0", "893c9051a3561662058ab5a3dee378a020351a92579dde22099fd9467170804f7877cdd25ae392a66e93beb384bc4a18b5889eea19c9be514a9dabf281c7ad4754da40767a070a5294d3edbc0bd361fc44f489187ef3320d9d4179668104facaa72e09349105010a436c64a453ce463b97cd0d2daad163faf61303015f2eb18b61798869e03baee149e247960b22df61b47e9ce2963932d646e9fcab92f638c0a8b137d700359a5877b9434aa213e90cf556a89ff39a5b7195de3e48f05f7dd2028c0b73fec5d07101c7f25acb144865733251ef3e7aad354278a027fb6320f1acfd7aa62c39c8630224f24d598392f684538f4b22eef319d46b5d37d45603aaa1030be7c4f7bcfc4c0cec979504d8884d0eb363ed86d2a82cdb2b6680f2b6c7a0d086c9440bef3a85c5fc7aeb6150760682c43ea0da5e75c672fcc5c78a29857df3fcfefcb0a6fe44cc1ddefa2e435585824947a62526b3dcffddf87f408a871a23b293f0b71856c9b56eeb4d4c9beddecfe44d86004048f74dc2dc59b2110f259a18554ac3ea1bbe49c3071a06c36a4c313a470fc8fbd7ae2dc92726ce98e664dd1a45cf4d3c741dae1ae807cf06d20241b072b2a36a06e9638b24511c1d78525e6f02d6bf0ca2feebc79925bc3df81c96a5664b1e05d5490a4c75a752e3715eae400de9b18acaeaaa7835f2d2a15645e658d37d2d5b4168df6ba34d507698", "-280e95fc37250f08c474fb504ca07dcb29a48db9e5ff76d404dc9d79fcaab13a2b9d63ffb9c77923149d8be15e8cf6fdcd2a499e468a00036737c89577d85c40ef7131358f5f7191678407737a115150a51cc0045c115d259031b88ca5c8d4cb7778e2e5358f4de1cc8f85a3b1bee220fabd78ab33a4b0e16a6b93320ee0aabc81c08344b7293129ce44fa734be911adf3d58398203096f3fb2b4e59fdb54ee20826b5a5ba744e65f39d99b3f6c1b5be155596847522b96cf3ff1a4f179a07fa256b8d9af44eb0a2fea62d25afa08cbb2a773d722cc80e81bae7b2e536cd99c00ec12cd59395402fb489607f5a77e7b3a38c26369a75ff637c365516ba7d7ff282208aab162c655f305c94d86258500ed610192ebe8dd1639f8c7cdcdfecf0690cc5b337ed3a557ae3c943a1ba2ec4075611a8edd39b48e5067fc63d7eb1fb49255481f774916f72f84d533f674f12d6568e9c5e3613a7cf0222e98f8e9b18f3fae24dd6a338b98768956a521d9b54b5737b675e75adaae244e3cdbece0fee4590013a520160d523e134eca4e688fb0d22b664e309e8a01f49c46fef1b4dafa5bd36a1795c2cc404f3749de0b92790dafaba4fbbd61e8afcc7c1fd284f75c427c5206e8d54eb9182acdee538aa2f6ea4e79ffbf8b45901d6da4d21a1e6dbafecb9d84852e94c4b9bc52f037b74dae2ddb59a51e96bf44ffa81e55744fc8eb208", .Okay}, + {.Add, "-51545152fbad19a0c3c2501b9000ad33a064d170b66ba647558f7b8139ef484f83a71ab4e4d46ede10a4e88ce9dbdc5505a786c196e1dd1fd16f175f3596adaf11160ea8bbc2bf5188ea466d325d0e9f236e596532ee5b8a9a69f86795fe02d3b75855c21798d7d5d571573e396658f27cc572ea827cffd4c62e333111ce60ce1c1fd5c967abf34221237ed21452ec9a9f67ae7692bb5ad6111bfbac3bcf351c0aa7f8218284e5a6bb9666819c9780dff39672bf9ac6410817d7394d0d616970e34f38c15b3d37c45a88389ee19a51aa7d1c1c89185ae069cf113cb684b3830d47f461d5d66616ebd7c78fca32e110ae2f8e0ef983f5f1c82811beed7088a5d52198cc4446ba6075f8b980a67347652730daa7dc0f1e11607e40132e01154e5ae6b7cbbdfa95f42ec1bcb9ba62642d7e1b7013b0f47795abff16cd0f5d418c9c279ff7e45e235a45005c30a92b12372ac6c4a360c91e485a64d46384405a16d4640faaee0c9421f1be2fc9b48513bc02790b117c93ac39ad11359f14dec80bd32fc905e1e8f6b75ad3074fa36acf0ecb6001a1790f81f8888fd36ded48b79e10f333db8e6f57286b3bab85b01e075bddeaea85ec0744dde075ba7e7b3f3cd9da2ae895a686b5733c57456020c8b67e544682dd480fc19658c0e789b8adce7081d10c581b02eaa93e1e8ea40f1b47d8577b6b71c2669354bac8e6a4563971b093", "ff3c654c83aeb5c9407bad9b0039323cc03382c8738cd420163355e872acd2212e0769adb2a601e859df381ac33ba05cd85bbf03134f2aa165f49f0efddda44f11f180412514ebcb6cb6c27213c8173634616810061df38a21a833fd09beedf3b952caf3bab0fe36d387831114713109fd85dd90e16693b9dab00a5c14381c341fc7b9a98f1d599ff68eee36630cc94d48697e2e2c07b1efb72700d0a575429c881dbf858d7d4bcf8edbcea9594d856b15c8093a2c23b1080aee85ca6c564fa5feb649acc094bff0713708a28bef6d56ad847df2ef56eaffe119a7bd17de5d4b0b7a1f0329d561923b8f004ffb43c4015f1b14805b75e4791c9104ba538d486008132e315c61fcbd57036aecbd913b84792a76e8d9ca16e41f306bba9ea66f93c20bcf2edf11588c9269c7fa36e04edfc544f3555d13fb352279bfadc6965438d429d731319398fe0111f80e638c8aa32a83663b20b6d33882c4ea673dc00580ba4871f132d70486ac957c194f24325ec3aff9b0fa755f42e9a130a185dd59c6e6a493fb18b3972ed34d85b5061abfa693840c0ada09b247a290ba9bce17c773ec32de497877ea3d3ceb6739ac9b82b5ce84d82a5351ba420f1541b2e3d8f05ecdf82d956b19e74b4979e859a332437928896ab5247014a7a31c5b2ffb23e28884e27a664b27631e7a5f6db79bb6db02948c68de09726a7d9ebd6343cc9172cb", "ade813f988019c287cb95d7f703885091fceb157bd212dd8c0a3da6738bd89d1aa604ef8cdd1930a493a4f8dd95fc407d2b438417c6d4d81948587afc846f6a000db719869522c79e3cc7c04e16b089710f30eaad32f97ff873e3b9573c0eb2001fa7531a3182660fe162bd2db0ad81780c06aa65ee993e51481d72b0269bb6603a7e3e02771665dd56b6f644eb9dcb2a901cfb7994c5719a60b052469a60d807d75c7640af86628d3456827bcb6048b2231967a915d6ffff3174c7d5ef4e6351b6710eb6557882c16aed003aa551bac30686169d6fc0a9612086b06932ada3dc385bd2d536f4aa663c77085c862b3532f8d0586d77ff2b0f47f45cce304a28ae67a61ed15a79c475e49ea464a49d65d484fcf0ccaac0583a0f0588c9d912138db540370e47b645dd0ad0e3fd47c2161a9d4dfa4689c65892362f29e6954c79cac89df4cd3703eb900b5c765387a537863bec2da57988ade1df086e2fd65eeac5638c7032642e294ee65b264ca10765c4aa4e83466c92595d86b918ca7154df3b6db8e192fbcdfd4004636119b4bb0db33826a91ca87b9bf12bd4cae85602962f8ff02bb0920c1d2013fe1898e9426d7e39a523e4c0cdc61995ac337a49c1684a30f97eee464740ef2348838da7bc524e2068d6d14ae7e4ee234d1774d557206b3d6224b483cb9e05bd0c9a8806f02ab1920f71ba2df15c2d5d6beed931fc238", .Okay}, + {.Add, "e8d597771b690424145bf4afe8e4b28e48250fe8707223e757c7ebe64e41acae6012fcc09aae807e598943ec3feca976aef31e4ba47856e2fd39f766b5a3f6896cccee85fc8790da13ca16ab02ceebbf8ee5046629549defd611c45e1a50efbe2bbeb7bfef6a06eb5b515f10bbd949c1e23b099e517c0a24905d8378a5b1de494bb9d1b1108d465ba623155c7a723388693de1678d7ff6b348391238d057a6eba3f0ab8076fa1e53e2ddd4acd979972b9991cd30609f83cd0600369eb0139a9dfcbcd251f76dd875457542430e48cdadc389f048f44300c85bdc741d8d9d0cde1d01980f16f218aa374e339fdd15f2fa6ebe418ced04819c8ceed826e3058f8b1c922d0b5ee0b449e3eb73e396ac24be183674a4445eb737c095bc92a5d23490312e5e90d776600192c1fb9a1bb8e9ed0f730078a04f2fc3e662ab7f2869289ad106d20fa0ee05598cfe16266925cf50a467014ea8e0a0473890f41cf6bf5488b9c111212a3ea781478e56b4c58bd5892242a538d63ce1618ffc94d3ef9e20d3fcd55853d60f7c827cd7958b655ef098119d83e8fa69e06b5d5f9fea60a696d4ad0604970b844036112d5b7aa23fb2e3df8d742640b69a5c6063065f0489e58fdb8c7fe16fd67100698cfc9be52ecd61a6391cc9cdbf2e5fa342c9b60103c8ed350d0a18bf34a08f1270118ab7334638098353c133ad958e21d17ead1ee4313e", "1398ac65ad7712797a6c4f495de9b77c293b8671f2c14f50a75d03d55b088c455077064e5e8be47e5be7c8aeb8367ba9f8706db1f83dd88fb985776b8a91f8acc9d7ad22abb1de87a2050f2d6170dab8e56e1146e4484efc26d993bdee4cb9acb0075e313b48406e57ae0a110dbf61ddf12d0095bcc03d63628d88c86de132286fec3aead8a1555e5c0540d2f5d47b666951ce6412fbd8dc1cda0336b164e5c0663ec83e747c1d09795c36fc66bcf15808e14684aa24d88299d30050158ee960d1a7716293570c086dc6133600f3ddb4c9f20c803c92590e29b5ecc09467261c2a58dcf356864462e32019cc1db19ee51e8251d5b6c47e1e1b575aeaf19364e5eea3b72593c41ec2b99ad4c31b6ac926c33e3f1d2aab90fd7e3e91f337041beb3b1dcb9a93fef6635849ccb8d055b264f4589d7b9e72671c0da53d0190856cdd0212103fabb0fa6a9a03f38f4ea938ebed5bf5d49f76f3826d32d533c2b0213b88b098e3ecd58cece77aed98b3c1ab4fea6550d2bd1b989483a68467fa81525e69a00a45e06a2805da18749046006ba99c0e9f4b9a2021c30cded075f9500dd7ee14d6c8990aefb6e766519858fddbc37405d4f100c6e190af9efd33c0621ef1919bb7588813c2c5d57613025193d876ae043425d485561d5a9d5f2e441c3fe7e594ba02d3a33c444bd2403ac13c69a207c7768ce8e664aa266ccc10a6303405", "fc6e43dcc8e0169d8ec843f946ce6a0a7160965a63337337ff24efbba94a38f3b08a030ef93a64fcb5710c9af8232520a7638bfd9cb62f72b6bf6ed24035ef3636a49ba8a8396f61b5cf25d8643fc678745315ad0d9cecebfceb581c089da96adbc615f12ab24759b2ff6921c998ab9fd3680a340e3c4787f2eb0c4113931071bba60c9be92e9bba0228562f7046aeeed28fafcba07bcf8f6513156f81bc8cac0a2f73beeb763b5d5c3a0ba940368883a27313b50ac45c4f9fd336eec5a283fece6443b48ac4e47db33b55790f3cab628d7bfcc930d559d6859260de220432fa475a75026d785d0d1a6e4d6bfac791df8d409362a3c8ffbaa8463311d498f4710b35e430f2a4d30c9d8648a6b216ede4db74b3c16f0a48353ed44e85dcd6507b6c4c2a2b6b755664eb0bc852ec0e9c5203cb9df43ec196dff407e880b8ee9577d318e24f4c9effc4270209b5b7cf083c91c2f723485793c9a5c3c950b96f75c44271aa051714346e2f09444d794d80d90ca7f60b935879f613a3193bea1f733266756299b679a48856f00a1bab5f5c41adac2334948a022e6a3e706059f6a4ac9b1adb5fa48f2fecf893ad12fb3d8ea753934917417d7bed10020392c4ec04816d283739f7ea33c63f030f9e36c2a5d8543d50efa244847cfde028e4452008d51aa1c41b92d7dcd35e4251c5786fafda114aca4e1c93fa38483e4abdc5146543", .Okay}, + {.Add, "a63b8d38eb8abd40155421a33d8b53b6a019ddd68b13699b2a46a57a744e657b2b311d05387e15f939734aec2de5b5b258f587832b218afa0e505b27aaede60691ba4f9b22240fef2a22bd2b2f934a302c2f69e78327c3fa3eec24d671259cb39a90622d2a79068175a725011e0250390a0e39bafb2f18f5011e04aab76f036929d9dc50046dddea605c72ce67baf227bdadb89fbe621b363a6f6916934a175132fdb4f2c37b97efdf4cfcf779560c0bb8d17753877e5e114def59d81a8e94f216f262a32452b719e6d0a89c326251d482af4e171b858f20b5a28be7daa70d520d9d3c55be1851055b85aa945db4560f790ce5299f9fac9c9eebaa611846289188903271618c4ef4aaac64751c85361333b824511bd4b86f54d50af05b83db6a6a63eeedf824ca917bf8822ceae819c0624d3df9058fc49055b70fe6c9d0f607585424741b54c4799a4cb79dedbf7fd6131bb3a94e72b0467b2b8f524b36bf912205ab5e2cb122e6debbcb12473c0975b8c6679a7b4919c7f3296e4df7ed4cae61770ed8ff61afc72e049f55975b889e570d606af2c3662827cd83b0c7474a2d43ce115fd7e20ea2c3d685f741e9cfc313166184ed2e417e1e64a207ad375e7bbce3a8e933ea04f07ac8105381c5e5b2de608637b25f1f6d072ccb847b1184dd00f95db11b0353f13589482476efe6c4f71e6b00166c7a49de25e9a1eea4b632", "6024d02cb28d0b6d3fb1c801a69c770ae9af13bac2920fc0e654df9b42d40225e41c6ba40b6db74b2596552b284dc39b58a02d504b116b763fc9c59e9dba3b314fa1b254eb79e31716efc3659222eec1a4c28832f498161149074fc8e684b942b9b100b25cca47720181b8995b83e69dbe0d7553cc48bd55a71e05cd774fa7884d09afac7c15824fa91f549612679588b7d309c697fe19cadaadff454e2ab3081254f521f07c420e929b1660235646020a9ef6ad632b07768b94c600991023c633acd286478e7cefd91067f1968dedd1da0901f6b501ff54eef21e699c271fe0ca94df8c0639cd963e9fcfdb4cc03e81b5624d227a361a57fb4487a9f9340c682ec45c7edd48acd72a62e94217a7f52cdf79cb185553cc65d6cc0edc138aff5f3af5b3b62bfe8b2a9c016850ccc21f3d5c17ce8808797a9ddbabb245043e3a47f6635520820a1e8c5542a2916dfda60a55864f7351f3002eba7b10defcee18d447655500e1a1ba0be5ac80598825601150254870432bda582bcf565d75eeb53a8ed5f61c64e3f4158e86274db03b53e56ba262521ca58fa332b6b67efe518e8868f3f2dbfac259c656589c78f39fce8cef950ce29fc641bbd35d2b08baf27c32ee344e5eb6127b7f15d90583acf379861b8dd5622996c98c0110140c7466544103e87a96b626e7237d9c09311b38acebdc1fd3ee68f6163896d0dfaea5e74c99", "106605d659e17c8ad5505e9a4e427cac189c8f1914da5795c109b8515b72267a10f4d88a943ebcd445f09a0175633794db195b4d37632f6704e1a20c648a82137e15c01f00d9df30641128090c1b638f1d0f1f21a77bfda0b87f3749f57aa55f6544162df87434df37728dd9a798636d6c81baf0ec777d64aa83c0a782ebeaaf176e38bfc8083603a097bc7647a2287b07580c26656603501151d685be174ca594552aa14b3f7d9fe71e813579cac520dc3706e00eaa96587d9841fd8b39eb8b84a9f35296be13409bfe1108dc8f03fa65cb8500dd0878e75a494aa5176ce2d32d8321be1c4521e9b9a257a6faa7494912e6f324c19d5c6f49a30320b117a34f9b7548ef03ed4fbcbd50f4db7342d2b401331ef69712884d52ba119cc6f0edac9a559a2a4242355bc17f9ea7db7aa38fdbe650c810e093f2e3162c22bce0f304f4eb779949d5ee305ef8f5a2f5bbd25e068a2031ca065b07535a6a0314824d865696b005f0e52dcf2c4684b6bcf61698708ebb00abe74f4201ef8c4ab6ddc01e8f04d04f56445a3dcbc8ac6a34796dc83c2afc2bd0f68f5cb5a843a2fc598d8b5acc2043bd2a468691a2f227035899e5002ab6e678cf48339f1c1cd106829daaeab17f747e9fc806f90a115d72eb95f38f9ee5b99dbf5e8f9083cdf90ef77d91e04e1d847d12a3b14b3255155922893b0d33e3eee7f62908274f6c950948c02cb", .Okay}, + {.Add, "-f83fe53c8ce1b7357e24f40b6c650ba1375ea8518385b48c30cb9d80ad3937540a3ef82ed754f8d93da2fcd7dfdcac3d59f44a123aaadbc36870db093970f09e843a867050d3e33beba829a38b5348b69f010df9e97d5c6b5bbe6042291570e3c992acd16db46d73e4972cfa352e7d9cfe2fd4c83b8758d0ae92ed3d3d646953b4841d341bc1d8b010adbc4e6ba9f67a97cb196660b574d2c4e37155da7a6ae19925d332cc3bbd2e67cd051bdc230c2c712f8e9067301e569a6c06ed81a454fde33a1011aec03a640599f75dbea26a099c2561cc4a27359b0c805b48d3b095fc86b9ef7b0526b293e0106932dab3d6afc2d58d7522e98afcdfc6c4bbec3b8d8a6440fb3ccc01c0fb3077b702236b35efc2ceefb53d56df5b1e5f32b7b846fbdbe9a647462c1a473b4c84cba12c352b39b7750e0f48cee4d9b62b496fed8d7c7327e7262bf136dfcee03eb1903dee6e4a73c6b701d76f54713b57c846f40e6f67393168c275892840e76040e3106b363ac86dcd4e5cfafd753ca91c3361795d46f033d11c0d705f59ead98b1715c7336d97dc85dc2d70fd89c4ad6b2837403930c5fece134afb2d6cfa0f21ec9188e1eaeda6a894a8c63cb45667ad66091d80541d6e7d1270036d98cb7bb15adbc3a4ccd229119d60acab6c308dd7d5e91dad9aee51518e9e18590336133f7978d9233de8b5803be892cfe31e6f19f525b562ab", "56cf4ca78965203a613142bead28ad3127e9159c5eef5cb87ea6b25680404377c80dda9dd4da3e06f92923aef2c1f14b0221d7f56381734d29e614fe7a666673d81c08c8791d7b6486795a164faceeaf865c104f9867ba48844082d8b0aadbedf24bc484081c57a43033832d484cf80944a4540de49c76013beba51069672d18f280c34e00a036a33f35a378954ba38aab948c4f2c05e42cb7a2b426074ace53d4876a02c8328c9dd62da2e19ff2442ae8b3d2907bd767941f423637b8ee1d61d1bb1ba206533ef206a0c4c361f86e9c8b2fecbe25d531b7a26328ca61de9704c98d70edf21946cf190c6746972eed29d8ea7c169da6b96a471e633fe819bb84f15281836c6ea39556c2fc5c305d12a4ef0bf2c757290f6a94a4da333b26b32acb063ecb375c835007cc71cfab8b497fe21f41faa49016553a4e0c7ae90b7e5bb7852a81a1d29b3eefd9edb975229a89b3eb01ad8a901f9b7bde0b1cd66b1ccb41bef91ca1b442d063d28295dca1afa7d21e555751ffeff4d76b59f9e3167a3f78ae3359bf78e489ac3d986173d1aff1ce24da6a09dc58b8f9f1870857bf6f0e885c1daa24f0fd5b05d13499e095e52fe1d358d0671ebe6f7a2b2cbc247403d2149a44a84b9c91f0e045501e24b8de2480d6c0dd0c322b8700da582ef6bff5d5466a8f116ad9d1beda1feb4d60d994c51378ebe3433a7109e7eb2241232e33ee", "-a1709895037c96fb1cf3b14cbf3c5e700f7592b5249657d3b224eb2a2cf8f3dc42311d91027abad24479d928ed1abaf257d2721cd72968763e8ac60abf0a8a2aac1e7da7d7b667d7652ecf8d3ba65a0718a4fdaa5115a222d77ddd69786a94f5d746e84d659815cfb463a9ccece18593b98b80ba56eae2cf72a7482cd3fd3c3ac20359e61b21a20cd17818d5d65e52efec368d1734af90a60d40bd2fd32f9c8dc49e693004093090919f623a3c30c801887bbbffeb58b6c27b29d0b5c8b6379c117ef46fa86cfb71fef9329a5ca9fb6d10f5750e245203e36a1d327e71d1fef7bd2c7e8d130d6bc4c70401ec4384e985e9eb115e8542d19298a8617c0421d20572ee79b95f931d65d9b4baa5f30e234ad3c2fcede62dcff089ba58847d2048b11ea0087af4bdc3eb44b859d180a9e1b9d555cc14a43ece847bdd3cf50481fe177061fbaa4f64448ff064c3d6c8cbd3c0bfdbb5544cdf34d5bf79bd2a1da3529bf7726fa5d3d4e570838dbe4d33c98692f64f77f70afb0d80653dc2397e62e30777859dc24df77ad03e9bf2b5a1f5837bc9b7ab722394a4d0cabbe41fdf80ca223da2b069260a3011f43ded52b0f2fcbb0bd34fc441a77e44dc3c80a9e4a97c8208d4386a2466dba7eb36613cb70ac6a8515250c0547a7fe52fb37fa6f25db7c5a7e6c27d333e87445bf3542c17ff8e78d53c9458a5585ed93683f7b402872ebd", .Okay}, + {.Add, "3fbe5e45fd57ada761a11b8927f8a7c780449caca0c5bfb425be0a1e610479adc7d22007599bdc2748bbbae951c716ebf678a44f1bda88fdeaeaa53641e8221a5c346147e0cad7b39096daa7de1ebcf2ca3c6eb42cf139ff8ee32e00669f93a81a2dee069ddd58af92675b77f1601fb4042cb9c4422210a8e8bf6755940ec3c94b2ea19025a7103e042b63da5f043efba442566b3e480e231ad2b343b0bbd40fd86df209644fd0c4d4c1dfa94197e00bf6bfe7c1aca820e0de9d9ad58b4e333c2421fc1f0bdc2c9a638a9505a11b6dbeca29437cf321350c1eaba9c6fa08fd81c3f62495411c943284608ebe1b0076b7148b470f88c203a2fd0f7d41deab7efd467bd68942072c32593af17c7c1a94518cddb6c28d3fbbeb69abb0d2ef7c367265feebe59c73c56a608369c0c0289a63c4231d9297f5b7fde0e686323ef6618b6d954e7a3e7efbcd11e4b4d3572725c757ce285e06937dbe80d517d4a3d301908258e59bc51885777f7dd261305dbd7954d230ca657dfaeaf5cd84a7126cf2bfa440e181c7f3800b97315e69f5fe9307a8ab0741bfb90150da7e2a1b378a4e27a3f61218ae7cc3b2c3128d22b74a43073a2cc40622fbe347decd8683b1327d1d89f04ebce224e828df7664314485758ee8055b31881bda9a5584c1059c4024e13bfe6219cc467dc4a00b4b9c1a3dbadf38769403fcf9f4d1a1a01b85e36cee2c", "427090e47c12c1d1cad1ede5c2c7814a0203e51d6be5ab44b9ca0dbb9c590ce42d64a06591b8629325f63aaa583cf0a6a64f7558380fd7ce64ed1ee6fd7f2633a634ed866e2919a58b0bbf68a696cb98ec19514ad7cd7d9ed617c5e48ced0c28c3d21e631640b158b62e8b0a804ff0b76b0bdb1e1547177cba4058d387452b0a56ca719cb6e3ca535b18b7d087ef0f9b74b1a90d82b86c13f59dc28ba3f4219502ad28dddd37c203310459a36740d267d4f31c2e74f45523fa3d8c6579c198824a57e66228eda6630809932be201fefb148dedf323ed7bb13802105ae3dd2cc2368873bf9072e811384006b272fbc34574d6c0907388679bf6d2a802ded42e621702ae4daaac701047823b18e516a1b70f33fad7fece2c508cd8dd6ef7a8ff1677d31aa3f23294e4c9c3d1d1b3bfc164801306c1b6553f65d35c6b8aded630b3dcbef09e5bba550b0dc75b968a83fa187b40e41de926d55423d558632492f1fc0c03b3d92c3660742ce7b4dc2dc4b905f433f2bb5a21746a414cafc7c7219354de3a2b08cafa7eebb364c908d7d20417b3a46a56ec8b8843ff3a1991a38977256c5c8dd7bfb2ef3c37b9b502ea0284090b65f8500adf528c6bc522a7336a2881ae3fe264c548e4f7fa57a70b1bd02cca8080a81622f72dd30b3ebfc58badce5b71f567d74a35bada983ef8fac8f359e702fce8853aced8e02c85eba23983aeb5", "822eef2a796a6f792c73096eeac02911824881ca0cab6af8df8817d9fd5d8691f536c06ceb543eba6eb1f593aa0407929cc819a753ea60cc4fd7c41d3f67484e02694ece4ef3f1591ba29a1084b5888bb655bfff04beb79e64faf3e4f38c9fd0de000c69b41e0a084895e68271b0106b6f3894e257692825a2ffc0291b53eed3a1f9132cdc8ada915f441baae6f34e9718f3ff78c1007a37107075cf54aff5a4db1b1ae7418792c805c6394ca8d8b273cbb303f0219c7604d8db273b050fcbbe6e79e28134c9d2fd6b942831831d6cb9deb73170170eb0bd56adba21dde62a43fa7e9854d18f7c43bca095708dfc39fc8962079ffc4a6b3ef3e22544bd7fad5f5d7e84d6ecb39c42a0bd2c95613136089c11b19a8c0de83bf6848e41e7253588ddd206898ea65a4f2a473b9273e85bc8443624544e4af763b442f1bd1dcc923f4a543f189a3950d81fac1069e1ab1fdfd30f0c7befba5312a4aa7037c865f38c8e5c9974f14ee5ebac65873d5e22767f49062385bf9f6f55371a346ed98e8614827b0c8a92edfef74a962772cdd0971f5c4f7198ac448994d9b843acdb13c54d10529ff06e2fb2eefacc4225a14cc7104592bc562ddb35d44a92a92ae49ca59f38303121a76dcd20d9ce0b3c6055a25968860347ab13086d60c380cb27edf33cadf3c9f1167c389f384a4496e33114c63b737c8937c8cdb1ce2607281cf09ce1", .Okay}, + {.Add, "-56d36005cd2d3326787f369291edd60680f4c78572e2508cc4dcd5aa210dadd5ee823d3cf97e3a4198aa06d996fd569f2295ff3ddecfc63bf2c6927209005752aa5a26a544e1a140170a6ff7e88a43a4869d059f377d4c99dc48b286b1f35d7741b4941cea5b6d95784e9afa53bca43f55abcb38bd0f44509d2ea6d4cb25588c528407f5c36c04e18acdee0e19b3eee01f460697f02cac385cd1cf5f2066a5c2a45353a984ab15e09a2435195a03b3993943132ff8210538a637e1e342b6260d079988c34748a474eb1b018c2678616f9463945795c2b17594ccf3b3ad9a16b3897d0f51f4295d0b730b51a6d3bcb1bc849d2e0bd63d4404ca8704105655b63520ad23fee4e13014dfe15361578d0e4563ed90770fd7c6dd6596b3a6acf4ff37e00827b361fd86dd9c3d4eb25e7777e9a4e6606809bbd47bafe11e8fd731686221813dd9d4ff679b7c9bd9d8844dd5c0f7f73e602e0080253bc6777ba6ef273c1d7a314d5bcd176220f266451812dcaabe870a4f938bcfdd6bea568b24b6df70d34651747714cf435f2cb99ad2a5d968ea537086746eda5301af780d314fd9515860e2f186da1db5e655b52dda2d0c0fad645e125e7888779a21f10d0a1f7cd03bf08ccde404ddba751557741902e7671e38bc5de32d4cf4f150f0c6d20fa945213640bdd1a8581325ce78e3e86aa2c94b211aa642242ef559827671785d0708", "fbdda3b305430ba9884cf82b4a815d490e3777064613e4be63a0a4bc954fc691a4fb3c2a96d49a75b1efc84aac15ee760bcb2be5e4048895f9bb44544d8cdfe791330d797d630100f429667ee04e5a496daeb423fc74a677e8fbe23a162657de821856bfb0b1e823c820c0ee619b15c37bd43ca0574270c73bae512f8fd217e94e7fd630da169cc7e6cd338a875b586db8be2ab8c97612fe296c01a88c334a33483a1b51d20a0c124de561e932cbf28617c17aabee747914921fc1c9af518cf6d36a92e4bbd25d2321bb9ba30c4a42303c923e8cde09aaf716dffbfe9319e50873352805010f89023d2a23fe59dfb3b8a40b312ce33b5b6530771eba88df561d07e5fa3098ac913ca3439b61857da7021010dde731c212f4b9b5ddb0cb23a437bf63f46b0403b1ba8428d253f5a1309555e47cd7047fc338f0a3486bd5b7a9ed0449572ed1637756448dfc9746ae32af3daaa37df7f01732e7c81a6d45ff1b0d7c419d1b58fa0e7383cd6b354919ae571aa3afffb882eca673e63b0216372a1d40504930393867db93a2751f5ad77272bc63a4dde8a87d76f4d530d8f8c00cf58e04b46dc55adfa70288170b53afe4ff397aaba43270159bf7e7ea253259e2d8bfe3270e4df44eccd18b94d2dec3ea70cf1d1d838aee2fdb0c430d28e6a350577f2664a91eb7951e2cec3f11ebb2ea50b5f1bc8f18d3cee21021f6c5b48794c3", "a50a43ad3815d8830fcdc198b89387428d42af80d33194319ec3cf12744218bbb678feed9d5660341945c171151897d6e9352ca80534c25a06f4b1e2448c8894e6d8e6d438815fc0dd1ef686f7c416a4e711ae84c4f759de0cb32fb36432fa674063c2a2c6567a8e4fd225f40dde7184262871679a332c769e7faa5ac4acbf5cfbfbce3b16aa97e65bff457c6da7698d99782420d94966c5cc9a32496bcca470a3e6c7a84d5ef631b3c12ccfd8c83eecde7e677bf65373dbebe7dfe66c9b66e9cbd10a217489b8ae36a09a16e5d1e0c0a82eaa354846f9818213084ae57fce54e9b818b30ce62bf6ca1ed257862301fc1f6e03210cfe176065f01aaa32899fe7e738d631b3cb6127c36248002df098bcac234d7021ea4c17541f2a0a1e2ea4ffdf5bccb7a2062adce7eb83a19729b8abb0fe1c6efac3eebd40c229dbfe86418ae2c81954fc640fbac7f222bec2605cee45b3651dc9ef970dac01a2f19f0ff3d15ec76bcdfd2cf71162db04f03106d1ac5c1ca5b024f71cc907fbe476f1804aac6d09f7bbc22398983475bb8488319909d21034577439a323f325b8cbc77033a435a3d17c3e80c1f11c3261dd7982d8ef8c164d91d3f78d245dc5f918283a660883f29a4069ef71125c763d5ec5c10309b0e46125a7c0e2e61af21c621493a7125df023eb4d0f3d0b071dc62e034847876ad0a1e8d6af9fecb69f80543c2a8dbb", .Okay}, + {.Add, "-9ba83e16d702ee2bc47258247a8e0634de3245c34823b8dc0d7d1f6796f1b75cf350122e6845c32c571107e11a2e7d45db14ab33d34337af7c1ee8c49998d2565757188532a86cddeab036d6fb1b07ee7f4c2c2adefab2dbdeedc0e696773a218bbef41334183d50c27ca669fd185e1ffe5353631c2e5f466757a061505557d8d0c5ed1f23826192d2fd5cdb802476abf4e3f7e4cd6ec3c5e7d2bdfadec50c722d2be1973a26a35a70e95696c7b90455fbcfd6e439f56f82022add0ba5159bc854614fd45e59a06facc0167c5eb880986ccf797cce47710e8cda6b2006a2009c1e079df77d03434fee9f797f8e534afaad522b991f0b01a7c2326fd4f98b1ef253edfd1129086e4ba37f95ed0ded2cec65df094404012284e1fb2fb4d5d9b8937a039ecddcac114a7e97a68702f29362440fcad2e564683ebd5af67ce36b1b081880ff460d50373356fcc43e67a973cd129668d109f34322afa1435698934c3c7835a2d24ab934c50e71fb3f74157ce0748db93dcc6c9c4809293dea6b87b3087a6503f4e7b58659473235bc15f6aa039306e254668acda064d7528562c268a390d529a3c3d6cac118f35e8a101ffa0bd8a38da35ea376e0a8208da83f659a8a240edab9bf06611963fd001e5ceb4174f0f9c051eede3352c2798e458e32fd7eb56e7d50071befb891815f0adc1e8a48c95fdd2c19fa556720410eefd58b314e", "2fe1c742d2076efcc051e6c8f4689d4c21306f2fee00c446d9cb1a18d2d435c21b0725c47404a3560dec419148ded5550c0230401a861d86892856615a47b65a57b91f9ded6eba8a14ad9732b333870960f631229904801e450d1cf67b5984afbaf50be34b820bd49ae3cbb78db9911d1659522cdf8951a5b86433904f0e6994cf36275d95449f00765f94eef9809a0d5305bf2cf2eac3d4e3006c1f90be7b0f49b1a69aac6c26be8814898bb163edfc7d4a9b762ec388c0e81c10113ab2a4b6e9f9cd0b8c42b1cb09ca8ddd82fbfcdb61c93b37f903dfcbb024357ea7056b6d406afb1cbe40599cda9b5140fe00fda2d7a302d727c63ab23fc63badca52d4111c8aec60b3224142e7257700dfd24481499d6d93d9fa36c1ac84391f059aee7d6d06bbcabee9daaad54e1e1ac283e327adbaea1fbb70ff6391580be7a5509bd455e367ae6e952171edcdc2c4fdd1c8b2fd6935ee1393a94e775711d4525cb2702612e2a5b1b707e8389e48f80d2f61e2d7e95ba6d7c2d5c91e7d113b81c9e0c86e72f845ce6a8413c35f6ecc8389e27d193255aa6ddd9232669c1d7b5590e32dd0fd25119f0a2969a4b4b630f1da9ed0becc62cd4a1b7e668dffb674291dfd5fce8fd0764d1a2db3e8dba68caa5afa8738cb117dfa6d2345cdd23c6857fa10899be95976ce82e6702346114f144e3ba66d27bb5e2560aab5831386caea4a6e88", "-6bc676d404fb7f2f0420715b862568e8bd01d6935a22f49533b2054ec41d819ad848ec69f4411fd64924c64fd14fa7f0cf127af3b8bd1a28f2f692633f511bfbff9df8e74539b253d6029fa447e780e51e55fb0845f632bd99e0a3f01b1db571d0c9e82fe896317c2798dab26f5ecd02e7fa01363ca50da0aef36cd10146ee44018fc5c18e3dc2925c9dc7ec86a3dc9ea1de38b7da83fff104d251db4e069162e37a3afc8dba7c9be8d4cd0b165516597e853b6e0b31e6c11a0eccfa6a62f7116a6782c8d216eea4a2f5889edbbc83bd0b063e44d5439142dcb635a15f9c952edd9ca2dabec2e9b31404283e90524d57d5af28c1f744c6f5826c34272f384ae1376310b075e62d08bc5a1eec2e1ae86b1c419bb02a06ebc33576f695d03eca160cfce3031dc2369fa949886c406eb03a9654e0b329f368db2c02ea953e1a7f33c29d97979ebb15c1692f017969d7ab1a152d32e2f65f99d4384a3182463699cc5222c02c99022cdcd5d3b24766e61afd9ca45d96f4a9c67eeaac2caee9bdd2400bf20baf194b024583d2c6ef926cc78679d48ca9f8ad3b6dfe3b350a0d318575bfd8049224cca157743ea8591e455b3b19d72ad61487f87a1a20d73416479d2a557f0a4371ec33657b215991b29046edb82eaed3f471100cf4a751dd3638ecf5198523d9389909486e3b4dbbc7d04ea25c3821cdf499aab19d2d8824eb40c2c6", .Okay}, + {.Add, "-ba8583674a58c30df3fbaa07ba911c2a75abd917912bbd9b8c601452e5458f8f38b801224e458f89d9fd52c8a73fddc75aebcefa40a42f17a1e6d5e4a290e8892237e1b8ada17fee362cf5e2acf2c49b176caf59054fa93f2a987259f13368e0207dbeb8b2496ce5e8b74b70e48740ae74896e95bbf801361c1a3969d18869ac9b39b8964f694c385ae2ee9c218232ee3fa68e51e63d14398e28db5cb874c097374359acf56c5bed74af69572b9aafa6358c740f53aea389a299e713f331cac033d158044019cd52b93b1c47357a9426f1f851a7f618e9ee4a9fea05c589d085e904c9614fabc608ab1298ca0e8d8c892dbf9088c76e21a2c89d68a316bff8b7227c44eb027a515f9f602069bea01249b6b0fef96ba719533df7e03efb6e034a0cc6249c6eeac1f14d15a59ab668d015f109bc7fa35178940ec7df0da100efe42b44c8f5d46bafbfa1dd5f68f876fffc37af2d6f6afe49c46f479279d30013a9f151c27ca8614f72138e20b6004f32262ac5cf49294c4a83ca6f9fe06d2db67d09f97f3fd38149217dae8e9509e19a26caff2b997488d01fae2f61c7643d7c19baad8a3882e1ab4154f4e5a78cb3031348b1309d1216ee3d390ef4278bbd4bbfb5ab1c7416cee6cbd6f616cecfe26e5c171a46815e83fa384a2278efd66dd0b09be9d93fdf66eae06c82ff4f4a2bf159b6033bfc01bdca6190eae96e92f4ba09", "be888cb0777c972d8f783c11479c18b00db5681441579140309c7740f3fbb5962634174d40fbfd7190f0ada45c1730c55a70bf923bff380e6c22513388313bc08fa38e714c03f112c6dcdb6f99ef45679314d118ed4aefac8f144e27a56315a77950a5024c3358c0e54ba2e2729d6760a140ace3a4c1e89185fa042904bf02897f1c31891fb76ce0a62c19c859a9aafc49aa8d12bb7e762c48f4d79dc0a2d316929e0d6066aca70e1cd9f29f083004445c9eb086d3804f490ab78e1939ead7bd275ea091a4f42e7b8b0d7cab1d58d127ea25658054ffc4ad6b4c5f82ba70abc521cf38e83f7315f92badbeb9caa368a498166eabc4d5efbfcaded35db2b7a381ab19c9b46b12ec970ee8874fd49a310934fbb63547186ef52ca01955782fa512e05e04c365842374c3ba4907de38043f8639b2343fc124de75084c07d3262411ae85774b4c42ade3650f5c149076cb0a39242af5770fd72a5af28ceabe4e95b64349dacd752067267c96a1ddd580fc67ed63319992600bf5e91c49b749312756fc9f5552fb70447831ed4c42a4aabb721f507de46dbed863e4f7adaa6e89f189c03a03693afaf6c417ee7c05738ceae86a8a13a5917e18b3cad83856820e23cb5af6aa0c0a6b561e8933d7345d37006e443d4d808c145e3e40a9551e8af068c4a95f9e9b1f711495af5c7c26e85ca3f2432065c87a5da98e017dbf67d4f73381", "40309492d23d41f9b7c92098d0afc8598098efcb02bd3a4a43c62ee0eb62606ed7c162af2b66de7b6f35adbb4d752fdff84f097fb5b08f6ca3b7b4ee5a053376d6bacb89e62712490afe58cecfc80cc7ba821bfe7fb466d647bdbcdb42facc758d2e64999e9ebdafc9457718e1626b22cb73e4de8c9e75b69dfcabf333698dce3e278f2d04e20a84b492b2c3827780e0a03fec0d54161f2bacbfc41082e127f5b5ab3b371404b20a82a8947dc95549e27123c777fd1abbf681da70546b90cfcf38d488d64da6128d1d26063e7de3d00f82d13d85ee6dabf20ac757cf4e6db3f38ca6f86efc74ff0809b25efbc15dc1b6a56de22fd67ce1d02416aba9bf7aaca889d84c968989b376f8866e615fa1ebf7e4ab73bdb7155a1eea839167cc1a1c8d397e026f699618376a4a36d27cf3429952ff5b49c6fac4a66406cfa3225342d8340ae5577d6fe23c331fcab97ffcb0e0174fd860c118d65ebaafa70eb4e820c51f81850ccbf17b469088127d531ca41c29d62506913c1721eaca9d6dc0370d9f2a5d61327eefb56b43ebdad9ac9214b5451524af936084436c84be30a4c7570058c7930b8194b82c2f9965de6d9e7d521d8e3087f672a7691c9442ef650d80ba54b8d97f39c6f52b23dc0658d5492122d2306ff2d906405f686dc2eb48298140d75c55b400a29b542d97cd79e30b2988d1d29cc789fdf2c7092d5f942027978", .Okay}, + {.Add, "33ac648921982edf0d02e383878eb5c12cc8b6e81e91d26945a90c6c0cd78af949c356180cf469eeb956d637b8ffaab588f5e144456b5ba1b2de1c038434a462768d1b506790cf558cd76a99ae1fa065420bb2ac4f97f4ad0dfdce29f69b0a7b23062c92d339a396d57b6253d07c3688c494391173eef0cbaf65ed79da5bb027625802299a077d770ccf8d916c86390613ba73aacedfa7bd43c72bfa5dc119735ab525ee81c4f08ef58e02f87d6d5ee817c88c593a02aec5c1ca80a9c7c632430900597ed45cbcd2bfad5c42a2e232cc38a6126b97b7ca9f96b1be1001c710edb85353a81f7dcc446f6559128d40e08b8ebca8700ba3e0438f1c1e80cdd0356853c41840e03c745b6b6bece4b8660348dc0a3838c6afd4b38ca321dcc704868191a65f2df5d491004ead9cf9e89c4e45211bccb8eb8c0dead3979d850a0a47970b633e5b0cc05e7f6a8699bb9e99ff047e9fa3e562b2846924a980f1ada7a21f0c6a720b7dcbb5f6d010c6e8d135c5a16d05d560c493dee520c90bee0787c884abc592909b2ac67b585680b3e46f8630d0b6d514b88fa6f407f49e62ae469087ddf048273bc7b8688864445b2edd9ee63010ebc527b5627b91f858155084a237fab086fbcdaac0323bb87e914e428883967c753f8f95098fa85ebd538510b94ef49dd5635fde3e002cfb2834b8512fd873ff063d1f7593165ae15fbea0e0ce16", "e413cac52a5760f7c94f3d4eb432959d6132ef8709f3d15c420138accc704241cfc83195ce04eb05553ca771fb9a615e4f6ef6e7c1f9279878cf76ccee62aa8f85116ba5b0956ebf550716b1ea6138d87cf6ec50ad1e161b18a243f2a3959a7e8fbc8622b187d42ab74fc4c524818196fa4c95f86ca383cadee7668773ade4d89eb88a3b5c94d06731f5f793d673ff6e829527c0ab3ec188a7708eea77e1ca14ff4bc59dc24ac97880479a7f847f4618ad6c483421f0381a5b51c8b7f3fa81bb7ec92584a54057cb84c0a928c1f663dc5b4b6ec8de589719aa9378b8e10eaeafd01cd63a0e529e2f1403a1511756578a7ec14a73944738745413e6b8522ac6a2dfc3a633775e5220e2a239f241e8ab8eecaa8ce9224f50e0c2c937ce0303faa47723ac6fa1474de86df20bf110c1d88abe8bef9a91eef82310e18d72da45cd809aad1046ab6546d70cb0ab4f047079317d1ae59de75773666655367a8bfada1078a7548948d30882884eb959be29a8a4fac795e2633001158a4c7d8ecbccee44c50df2ae5cac8f3c51b71f0fa0a9902a41f040e800d33a226cbbfda559fc69125d7aad706875ed739b190c74d7abe87a126d980998780fe53230e920e2a2190b499166a2f7febccf3c045e27f3755e06ac0f74be93ce709ccf1f16c8155fd3455b9a25c66e9a8739bfe8eeb7dec749933add312913a897198faca06e48d5867b", "117c02f4e4bef8fd6d65220d23bc14b5e8dfba66f2885a3c587aa4518d947cd3b198b87addaf954f40e937da9b49a0c13d864d82c0764833a2bad92d072974ef1fb9e86f618263e14e1de814b9880d93dbf029efcfcb60ac826a0121c9a30a4f9b2c2b2b584c177c18ccb2718f4fdb81fbee0cf09e09274968e4d54014e09950001108c64f69c4dde3ec5852542fa3874964f9b6b7a1e6945eb37bae4d5a2e3885a00eb8c440fba0775d59d7801eca500c534d48d5bf2e6e01d1c4961bbc0b3fe87c97f03799d149e446e056b64d896a893f18134761061b9414536c8e2d5bf9d887029e22dd06a738368fa63a49738160d7df2e39feb18b7e33005391ffafc0b3387be74579ac67c4e0e26d6fa4eaed7c8b4c521e8ff25944f6c59aaca08812608ca0b9d971bdee8bc9fa8eaf95e26cfdfa7bc537d7b060de4792af7e4501517a6104ea1b825a5567737450aa30a7835fbba89834a09f7cf8afeb76c39a27c2f8511c694c69ebe79585f80428f5f6e4667cd6b4327c3dffaab15897cd354b6c970d3853ef7d755b7aa0d9fc38519165b12a715fcb962e11674b09c080842f99a3b6af597a43da5dc237d50d006898760427e83cec02d7260c42941363326bb434441ed9ec5a97d0177bcdcb941b7e68a428be9fe23637a2c777dd41b9a708c945037fb29ce78c539ece416ec9718796baedc3766331e2a2fea8e002ce9b65491", .Okay}, + {.Add, "7dedaaf11cb19c8c38458ece70f2f5964d94ab6565db0ff0c813a5869e7300443751db664fbdce2f2c7acf70cb61d4c888455e71b4403cd880911dd9a4dcac4bcd1593857cef1548176255899be597952a898073be35f548ecb21d0525e5395610379b6791562b1c4d01e52240b6261421a9cf9c49821a9a2aca65c1f50c653d88877a0977d7d5ee6c5f4d46c48203724ec62753c7aadb598e50c1106fe818d2cd8c56b506215b5013945040aadcc0e11cec0cdd25d00dbe19913d1ebdd7f4143962fdd17c8762ac365c3231f44decf942c55981f28cc5b9ca5cca4653b74b192f8952b651fba2dbd3eeaf113ff4ed113adf8f0382370fe2feb2785c4a570e7d1698b58513de59112cb58ce27cb697cf238a797188b82b8a7572319496b82839bc3a13229cbc9708a8f1768107a69a3442e83da5c6f5054b68639b077a456fdf309c5f1ceb6d827d539dd857a28ddfdd1c2e6019eb8e1978796fa73cb90bb1f3909aa79a1c708d711c020456f1c13b1c3a8a21f0a7cdfdf47eaed3dc9fc6fad6083ba68f1e2888ec8139df47dbc4dc8f8d231144334244f4c77bf7c54706e692d2c90190bcd16bfc71b44482a76321f6616c2269bf8502377829cd774eff6b84964ad0b12dffce5804d2500df9fcf84dd43e1ff2145fb5ab4664e843c9d93217414d287b28e345a12b7aa5a24e5066c182893f23a9320aedff4194510043093b", "34180b1e34ea7fcaa531aa4796517866b916c125749a4812a33772a7dc9e8848e0b9042d0a6db1e31ea086ed381fdbedd52dd3aa50e72046cbe5a41f87a121e2505439790fcc4494fe7fd4582249c76c1793fb8d1bc2d8ad5871eda3195450e47de13f23b4b7aae6636805bafb7445e5d3be286def8d7789a15015d66e395435d99b4bf8bb8d68d470f4f96c5434c974d898b8633c4a0237e503cab305f991ad970ad1d6427613af1f9ff3b71c45dedf81a221e4d92c1859d3d29ad247d1d0902a265b1e62f99551b285a52bbef11cc95c27e3d3f041a7c4c1183693785347b6e76dccb715f14b7f0ac6f52010e0e8d77e0a6d85ddd234867601429f251c9cfcf00c02fd142c959a9fd9520363f39ebd2b5a9c0033f312b58579714ba29ac2f486e51642b0253255eb4e7632f8f3548246c01ac3e524c451e2c90b37477ccca4ae1d8a45baf744ca142cde6d14b87819e0dc0199ad87154f51e33f71725edcb39a8d72d01412109778fb09ed334dbfe719071537167c5073cebcdc39f9ac2cedf5a61bfb149873f4401a07a1f956acb3a434610dc8d87a78732fb3cdb80d0ddbc63937a176b5770eeac558283f028617a2e735c5ef0a0589db2cc484da6bebd70d836f06cabdf25adfa9c84ce89a52e20e47743987366bed6f9a9bba64c593b7ed2f675df6e7cb2b173ed09176ede9b92d05cce3c752568b662ebe4c5ad479db", "b205b60f519c1c56dd77391607446dfd06ab6c8ada7558036b4b182e7b11888d180adf935a2b80124b1b565e0381b0b65d73321c05275d1f4c76c1f92c7dce2e1d69ccfe8cbb59dd15e229e1be2f5f01421d7c00d9f8cdf645240aa83f398a3a8e18da8b460dd602b069eadd3c2a6bf9f567f80a390f9223cc1a7b986345b9736222c60233653ec2dd5446b318b6cce7275edfb703f4dd9173548bc375e1aa806497288b48976eff333443f7c7229fc09e8e2ec1fefc2617ed63d7f105a9c4a4638958efdf80f7fde8e1d75db33f09c29eed3d55e2ce6d7e8b7500d9cc0a92d016f71f6d67ecee5adeb5a43150d5d5e8b8e9fc896009446974b3bafb6f73ab7a06a4b882280aeeabcc8edee5e0aa368c4ee51571bcab3e3ffaeba2e03952eb2e431f29654ce1c95e943fecb40099eeb689a85869ac19c99d4b2ca63ec1c23c83deb9e962a664c74767cab6c4b74657f6fd0a61b399152ec7cb52e6ae2b6a8ea72b281a6a30829e0894fd0e44250efb0353913727be4a4e684d6bb016997327c3fde1c28a32c0fce0c153e6e9d51b894331577251fc1abf6d3aabab92ff13f46e990239323386e30b5c799caae665a80e0453582fae8f07c1535691fc296b575ba3ce3fb7f8bdc0b2e47c185ae2974b2fe285942b9b962198b5ff83fe2e9ec5cf2e7c8fd91fcb10cc42b97633c53e507aaf8f0c07708461796570529d5b178316", .Okay}, + {.Add, "-7e9f45972a5149ebf27e57f40c89cadb18f62cafe23fc9068ed06ec86ca7f556542f0d4247d285541fa22fca38162d6a58279c361e308ed590b36bc652581edde7734990d99484687f81b058ae63343898015f40d6dc8c41864914245ee18c9bc3661200b01a9545c5b31deb2673da1a084d2d8b221eea07843608a31f4daf3f60b7dd0dc3bfb761ab152ea4b0d071aba737d7b63019618afcf218706ae600abe0279cbcebde9a4c2d354cdaa9b5a765614b16d8048036a608a520267392dfa22472ddcda0c3ef9b256724f5d751bbd58398d28ae8035771e79361999ee2e944bb630ede5c1509c5b475825321ffdfe6a376a9eb9dd259bbcc2cabef063e31289a54ab235bd37a9950bf665d4874cc9e8cdd9db10ffb50476c8f170278cd6f1a98577f41221382227fdfd6232bccfd4c4d5a167ace26794a32823fe07146cf85e63edc338f31338e5f141d084b1b4a3eef0b64a9d368667bab12f54e765e0a397389442389beb1784daee0409150b524d2913556c31bc5d83b356db3fbfad3958b3f7196b77df18771683ba5f100e721a6a4e83484d80b53d81274b096a7bec581a72df9da6cffa71fb533fda3b020e6c9e876a6a5a65076b9f256b10ff660ab89efdd6513d4ac60ab4e78fc2b8bdc10156a05fadb6ae4a17f6e273dac5d9165eb1d6e5258cc073883422c9e613cb436011fb443a9029a5dd068bd33740684f3", "9962c34c5ed7bd5731a4e33d9aaabaf72cd68e3838e79a8503e04f94f563acf6c3af6bd1f090351c8c355ad97dd277d5d7103055c73ac9b148bcbb950d5dcea891aed34ef9f604df8110355afa76c7e13f89730aab5d1a4a142e73990ff89ddcdb46b3e94a4e2d401264b939153cacf32088801018770a79b206479ac8b46fcaec2488ee95443802dcd56ec4e35069f5f5ea959a72e174d03632b87f4e7187f94b7ada92d5aaf530d3d4e57ba51a2cf845dfbc33fb7395c6880ebc124ff60dab88efc3f47d60b10ce80a2f6687e092185f2e9c242171719a1f5ac70b98dda2513898b30fe99dac47b66fc22c3f6b398d2b3ab933b573551b4b2c1d9f45c7d0d6fb3791adbc794d8b4fd842a385202754f4482f4f1d21ab40143480eb8d3b76c78be6ecd6835c5e1273ff3cdc8f761229682f6455529d24a9b795b00f09bcd5299330a1cc9fd5e84ba0716131f852a456b43b6b479a8dfcd3718bb6563358a4b969c775982fead4cac812171a00faa1a902cff32cd60ed2c54963cae896d26f98e76699df0a2d5a5e076703dfafc74f7731ccd060765bfefd847abfb8c444c6b9e92424da53a21481cef420092818c94e1c5279c7893745a72883f6dffe8ec188e5078b9d96a5e277bd916bf1cedcc79cd4fe78e71b38cf2f5f076f6396a834f3bb5e383c50251cb92b3ea2f9052f6eaf6d2e3f37854457d400a9facd382877e6", "1ac37db53486736b3f268b498e20f01c13e0618856a7d17e750fe0cc88bbb7a06f805e8fa8bdafc86c932b0f45bc4a6b7ee8941fa90a3adbb8094fcebb05afcaaa3b89be20618077018e85024c1393a8a78813c9d4808e088de55f74b117114117e0a1e89a3397fa4cb19b4deec8d2d9183b5284f65820722dd03ef7a966c08b8b6cabe0d18480a131c04020327ff84a4eb2bde442c813453940a00ee38b874d6b533dd5e9cc5ae4a69f98a0fb648592e494a55bf6f35f207f699bebdc632e09647ce626dc9cc171c2a30a70b08ed642db95c999396e1a2837c76571f9fab90c7d35a4318d88a28201fa3fd91d6b59a687c40f4817a0fb5f7eff71b03f899fae60e2e68a60a5d2f1ff18dc463cab5ab6676a919e0d265af8a7a569e9146e07acf38f6d956148dbeff41f66b963a914dd1ad54dda8476ab5f8513702e987605a3acf1c59910a4b4bd415d4429ad375a17c530069dc7259657c678c107bcfa9a7ff63e3174a62c23527a6336d96fa9ec84303ebdd612f30ced0e2e5d349ad79c035c27284852af68d695fec839bec668558b27e82bf183f3a9ac684b082d9d07f4677cf6e0793514daaf3eec0b8468a867526a0320e390f5306e91a02eee9860dd5b17ae3882d136171242f2f5a350eb8cbf9472ec3fcdea8ddf994825ea4aa38dd040c9e9f7591580a7fc765aa3f2ba796c0e8af3dc41bd7630413d99c421f2f3", .Okay}, + {.Add, "30b7ebb65902138ada803a5941aa4f6cdd06296f43c3c39fbcc531cdaed23276ae3812449a52a94e1b36a5008efe395aee5dd7041c8a68e3b94e0fadf21a02811e1c7ad0cc5c95d9bc63db1c72f28d77f33b469b1aa7fd05731ac072530e8fd289ca3eaac26285a7c4f52b6cf2fcdaeac1492ba62dfd22b0a5493318ce45cea699154888c89dff5d0fa9d5e68dd33c7b39362d0f70c269028b86fd872ed98db35b3726952450c11ee25d2eb181f2ac7fccc310758a0235fd07349420fc2df5746565f20f709ed70fae21b00e8d878b20748f6e45f024278b2e58f62face50a32f842a6ee420e7f97df30c0b6eb996711cf53447ddef176716bf172f821cd92abd806cb3974010164292d9abef28f8d25ce2d1cef5bec075e26f1cf0388fb7400370f0773733bcbdf7f9f84c9674d8bf308b419ea037eabe34624e38a4fba7eca11c8f196a8d04fea8f1661f260ae8d57f591f34a28ededde65e0f2d87000aad79b73ccc3cc96617cca52a5e816dddbbe0dd9656646cf0f05a0b1ca316b809c16e8caa6ed2dadeeeb5e8be1d2d9c542278bd606a588854a41338645c1bb9fd2ccbc34c160a61cee289cfb9f4d12a72ef81e789b888c9151dac9f8783938d8f62aae58e9be6a251a44ff46f8b9046a4e7db6b52d5d3786e300fac24e87303c149141c978c6a8e2dacee103df27d9f76f9d0627c85ae1522fcff3df0230c18f033d", "c34641e3101af45ba05c187bd28a94eeb5973af2532092653ea4ade3ef44aae97b032a449fccdb34b3eedda96cd61d29261e0a95c837640ccda1b4796a1064c2c4c5bc81f9b2ba5168866c70bfc2f597870232646d23907ea356e4380b272eeb1e9584cd6a1a013824627b7417a1ed90725f5ece8b386291cad512e20533044e1fb3493fcea63f7a65910c7277d32d7b5a3b9ba53440c99cb34b6c5a7705a668f3060da1c688415dee9b0be7e17bd7826146b76932ca5bf1a98c0766c902b7582c4d8329e553bfbe99b3429fb7ab045c8d819396eabd0b707dc3b03b64f4cad926913c5b1ac42b446dc71186ffd16e35c14169f1a2341a0e2b65d8959f2a022102e8fd90bb0859a01f6732554dd130ac33fb15c7722c862d2eda6bba263fa15b4557be82c2ba7adb592c0ab8d158d9667817c16891bd09b13a69a73de5927db4f3fc6cf2cdefa0319b63748fd98a82f197f8b98e3749e44721d01df4e2394c3b4e3b2a211a75fb03f1c3c685a9535106508a234981bc73639ebfd3753a18bfee59c528ae425e013bdc551b4720c304ab11fa5576b802e6624e6d0aaaabbb5ccb3aa93620b56383ac6ae61268614c7d5fb3f2aa2523e622cca497ef6e842eb4501637ce9fe9e64c6a8fc4c6e9bfd3edd18b34f5da84662cded03d46354cd230b4b610e74d06dc3024c1fda717e0e111f65265d83c68643a2fef3e8d369dbd57c3", "f3fe2d99691d07e67adc52d51434e45b929d646196e45604fb69dfb19e16dd60293b3c893a1f8482cf2582a9fbd45684147be199e4c1ccf086efc4275c2a6743e2e23752c60f502b24ea478d32b5830f7a3d78ff87cb8d841671a4aa5e35bebda85fc3782c7c86dfe957a6e10a9ec87b33a88a74b9358542701e45fad378d2f4b8c891c897443ed7753ae25905a669f69371c8b4a503329f3ed269e1a5df341c4e3d3436ead9027cd0f83a99636e84022e09c7debccc91eeb0c09b87c530accc91b3753955f296ce47d4f2ae45328f7d021101dcdae132fbac1ca66b11d9d50c1ed3e3495cd2aadc4cf7d23deb6ad5479094ae6f8125907f97574b8dc0f794ccdaefc8ca2f095b044894cd144060bdd2022832b6ce188d8b55cc3abdaf3b155b7c66c5f635f646bad8cb8f8238a6655980cbdb52953bb594808e8ac8354cfc7f05c55e8976bff01c2a79d6823a3910498d8aacd86037d22587b110cd5239f712e9aef6e4e70c5c80bc166c6dc0312cc45e6388afc88b82693f719da6a5995c05428fcf9b700bf0273ae0fd19fa8846d29dd05c1c408830a381f3506c675b2f97f6ddf7815b8071d507e1b1b573f3ac57d26b45adb07774a76e9067a7bd07aa7ac490b85e540b66af8f0bbfa2c43e3c4f41ea2337bbed0fdfcaff94bc7d0e4545f7da6013afbf0af3a301863fbad88193588da09749b669ffe31d8f675f4c5b00", .Okay}, + {.Add, "-89edfd184e3c60a32e1838c2bf4346915378ba9c8cdbd31dad68d195269dd64b817b40137f52f545214bba5ff70413801b7af8352018727d5ec963133fe363ed607de6bf43e3014d7cfcdaf0201fcbdd5fdc2b3cadc2893621b2be5835398984ca635c6123a1103faf0ee933add1a399741f612cb3a41e0ed52419217f26eb971c11bad88d4c8439d049924dabd1b1203ca5e9158fdce4583bc79c72e11d3a1e8e29ca37ad66566eea4ee5200ae7eedace5300e052b3ac933fdba2b780746b110b2d7d3618293c1d90266949c150cc3408d7733ee341aaf95365a67717551827723a4e52ae5b211af2e95c1498bdb5114db034c7ab871c4f7f5eba975e55aa6c4260358f4bca230251395d12917970a22a19d2ffcace31b98367af144c2e836ff3d93faa641f4b2c5856d30db115393676471c23307d5931b77714b579f9c7dbcaafe423d38657754bc61f20c0412a5e169ca0f1ac473a59892e7127ffb4f3882e29d1dbc5adb59430f329ac3073e477d3d7a1ee3276d2f643e0b5b1275b80a53ea90834b3d582a8ea0b9510f792a44bd4dc6c92dd9dcd51d73a9da45e8aadb8937cbc40c0c96f69f41ee11218ca457beac730814c9f150ffc31ec387e34fba70557a5d9e0a6b73db5cc7287621243e2e10ac282a5b95025981a78abc58fee3b82d84cb04dad834f67c7d54f3c99e39ccc96195c363a9a2aad98d101c00bb96", "35a1da04b19623459374e8886778c59622a5dbce82e0ef464379814885c752f75623ecc207e8e97815f7b08b6f63285b14e9a86a512404b174b8a9c37f514cdc854a19fccc82f88a5cb32435f9d32861155eaedc252736dc649ca40928b7c9ddd2764a6f21c0cca829a2333de8587a038893e4d3fc557f4a3145ed0f0676c2721bfe8752e7262903328109bb7840bb2f36c13cc73cf65fdd44ad2f80680099538cadd1155adfd031e9fe54dda31b473e61125551fa66a7da825f4b16ed9756caafc98b3bee441388a2a81c4f7e7a67ba10b8125148aa2dd82f96673a63ab2456d2aea5a24ea1d7c6f395cb4fb1dc37c3a63c10c100712502c4bfe4203a932b27b339d89929114524907d80e27117a7bbc08620c3e8fa3c7bbae2337ac46d5305d5a3ed990fb711573e8435ef6f26902963806d502106df9fca0145c88a3e81145b10a2d527c5e1e133e12eb36745db3b086f5e10e2f801ab7696640f47d78d4cf07836f476fe5a7f2742aff4cc1bf3eb5a18f35e084b83b5fbd59730d24561e78f5c0687761507a982c5f3e7626052695dcd2edb07cbddd54dded044867da2d18d1de93e65469f3c2d5d362c7428a2e46bbe416fd4e0c3e5101c83e23503acc4121a0bdf3013394c33aabef25c719fdd91b8e77b912200f5b345319f9b7042b8629b4948c7f5dfcd95d98fda676591fa75f5e7b8e50a05834558d8c439c10649", "2d02fa332cb25d3b609364fc3b84912d0d6e5024ba13321468a2f42f335d75929e0c38c0cff3ba23c3e2f4e56ff2e7231331f8e6ff227d899ecc13924b53169daf423b90d844c87584e35686f7d12ba33f60ec285a4b0e4902817823a564314585d014a90f86bba42eb144aaad7b5fc9f151eec1311b3d6943f3ab7cee8453b8aa3d6ba55e5160bf957c70969d83a01d32f6de35e3f89197c0f0b5b939eec5b1a3cb3471e0096acafb59668ba26cc850b42d2543f53b6d114e6190eb759010199f16b3688cc17fc6c9a5b5bae2655af6d02a9b1d5a7613289a600cd2f235d2d45b8b00bd23bc25b54467358e68505c7291610d7485b8b33dccc9f876c4add080ef13d5403454a2f46b69eb11480010b19de48393ec4d596022abb8897faa6aced666599e69751ca478fec8be94153c95fc1bfb8dedff0a0cae89d47d329ee4969e65a492ea8d7c69df24ccc15b41c89527059401c8338e05de037cfcc7dc3e146d9599d6baa37f25e4337d5a0914b5a3dcdb793f2524168697978bd5bfcfa9dd3b7176042ad7af7ef4253a9652e72824a07f6811d9f20100306b266a4094f7f603e61d7a593a08458e1b481b529bfe8cad11ce67c016d2941059651ead205d09a1c491819208cdd8584df7c9e6507b9f63a83b5366c66bf359c38a14df1743d4aa6dc47dc31b07989f5d1285739bf3c0a92c862321a65be09a7f4bb41dc04ab3", .Okay}, + {.Add, "fd1a2707d410167470e25b7d18efa935e735c6619a4eca15f3b5f6a7d6ae2035e5048b348be14ed89a2f074e3f41033e594d7f10f5728f850f880b6e24d31857f3fb24f708bbf5c5b5b9544e19bdd3e99658a0b92d4adeb6bba13c137ad61486176af79db0fe3613a1fb8b4dab07a09eae4a7d703fc960c6b6e733a82c2e986e7ece218d173ff44a5cb4d952124a24a0281e3b5a9fee0af111d0a20b3bf5f4f13257b64937af7f77ebeeae6302ebd8d306272cd956dabb154aad4759dbe5b6bf71de3a811292d20a61c5b2a030b3936cb6cb0a62c1919ca9d6a42c889bd55df1f91411d4c8e1ee1c4a2f62d8c1ca412448f3c2c9a5b0d6aebe442c24862b74726c4d605ffab9331a1632c954591fcf352e70fe35dda55c19d230e91d3281488d8e6625352b418de0cb840219fd8b48db98f757833677a1ffa04a401bb56053d2ce463e1e564585911630216f18f8986f8edecc3d07ce11b0b4a1fe0abb342bd0f9e74d9f22e0069c39e005da6a4925900f7816365054bf5113443a6820669badd7967fc09943cd8d463b9fa7d89c61ce673c92cf4fc40e3a5358518710bfaa64fa764e93c85e721012cf1395c43974fccb320e1ced829bbcb533ff64e81dd3bebc04e452e61b804ed1d5ed736751d357163785a8c0e85bb2004cbce4fe097f4b54449a89e01b37fa3825c4cfcd20d78ee2a7b28e59143a371ff438336b21f7ef", "d19d0dab2f99df642ca7a0e9c1115bf09f3833c0e482c4e61e3aab2181d154039b6781223fb4f176e06de35f2513123550ea1ea46c51a51975d78a8284f6f67190e9c519029186207ad07d439e675f096ed0fb63310ceca2bf4a0de3b4eff2c027141b5be6afbef638a1c9e57c7e91651984da92374063e48d5545029ac5ea2332bf40b5da766512dee278585b09c0be0eb24220f96dc83a2830319b68c0095398cf43f2cd5430aef11775209dc087d1c3775d30bc7eb9d843e5a2bb6675c0548b02e550035bda7d33b1c4a321aa498c50e3ddb73504cf718810de51e7501c5ee4bf506338fa3b4a4c3c212d251c3fad8724e9f431701be40c51d4515462040669311643d3352d81f1dcce7fad98d94d5a50c7109dd0e7c0bce1bd0bdff6409c787193e900243893f84cc51d935b2cfbcfcd54c9426fc8edf672dae5b5c98210fa7027f8d861ad947f52db8bf72bcd697ef43c9e1bfe744f523e1e71dce395fdedf955e1161f00eb8ca4ab77409d2e2bdb608b7614c46d0e19abb0bbff3a1bd49b90301957e8c9a413e603d0d4a453e313363656846f4327893596d4764c281f21a37c54d0fbe13c051b64afa97d52d9181b16ac6d46d44c9481e076f9ddba90a2da345861fee1af954a593db03090dfa39d42fc2788c52b524ee44cb4b99380161dcddfd1dbba0613ad8a3a9de6ec5ddc168c1cc59016460fd3e60c31960d68", "1ceb734b303a9f5d89d89fc66da010526866dfa227ed18efc11f0a1c9587f7439806c0c56cb96404f7a9ceaad64541573aa379db561c4349e855f95f0a9ca0ec984e4ea100b4d7be63089d191b82532f305299c1c5e57cb597aeb49f72fc607463e7f12f997adf509da9d553327863203c7cf58027709c4ab443c78aac6f48291b18d6242f1b6595d3b9751aa6d53e55e36d07d7b995bd32b3a00d3a6a4b5fe44cb26fa3c0503b026dd062383a0ac60a4c99e8a0a135974ed8e92ea15425b7713fce11fd115eeac8795777743525ddcf907aee819f6966c1b5eb50ada83257a50ddd3623801dc2966966b8405e6e680d1d018acbdd720f292ca960075da8d7878d57e76a3cdee609c080f97d406b8a88288c1c5467b7643da8f12a6291277892a06d7b91e2b65c674c3d0c73790e675d768c4ac4c78e76aed96bd1b016b29d5e3c8b666172ea733259582fcfb102465d90dd308db23cc860006e01c7c9817c1cee7e0a38038ff0787c684b151aae653bbead8a1ac65192c5f2cefeb241fa0b7827326afd9f12c97315a21a378ad40b5b17a72c925d4335161dc8de85b870bd2841c19cae8995a534c17ea78456db6c7d5e34d24c95ac9700949b5dfdbe1fb8e4f5edf18ab481a61fe672046b117826436b9d4c8a4e87120dd529ba131b2c312cb6a626869b1f6f2004bd34f0a6b07c3ecbebe3eab1ea4507d2fc81e3f9cb80557", .Okay}, + {.Add, "50ecf936a0593795304bb5c753425c0f737ef2fbe0cc002b4828465efb6b45fabff5989e2fda890c575acc0d9250e24a685fb8061878e691883e0c56fc07740b8155b093c790effd03dfef2f63155a443112b1ea779c2dba4433ae9882b73efcea239f8dbbc8df476095714feafe2886fb21274450d914fe5628a6bf55f4c1aef65e64cb981a33d1bca735e3149887c9be35f37a44625233756a4f7015644328a77d9b8e2ada0fde63e6cd3d0dac656483145a960bd9eb44c0cf0cf460d94477e6d433905687bf893ef5a78d3ae2e6bde857c4cb7fe0a712debf8f751efbe905d93717c47694afa9f026b80f3f79484df3fe7d2d076e10a3a10f398797428ec711d7b1e1c7b25021c12023fbe521059155cb12a13db0049f5a77a1c9a696cffdcc5b9375d021d19968675e1542d59c09a650cfd7acff9b2220fa7bbda156cef5c8d1bcfd07c53773f98eeaebf8cff767aaf52cebee21b48dc9cccb9e460cb4093752298513170abb5430fd780217eadeac253b1d03546fd15cbdb9bd5cef6097e1bc0877768b0cc8793253fd93a7b2672327d61b143c622d6ad34af8ad3c5218fff0afb9c13c004eb6d03e811d4688e0615d71cc61c373dc39f85a2e39b2021025d850eaa71c6256acc76190d63b7bbbf5cd575e9a2c73ab913b3562ebf0b236a7f5efbad566436193b6837eaecb358b27a676361a88a98d739f1760bf7e34c", "177f42dc4218dc751e2dc21f0b8db3e7d8c1171b9dd01f448e97032f12bf2e2deed58fa79f4edb89088570e51a53211b72daad0fde9d253d32e7c8a5ffe461fb70e380f7c8a06c663a28ec37041e8c3e7ab05ed1f3444306a3dbb950d6027e3aeb8ce777e31cfeb84827eea5fa4bdba54b19710a26f31f83d315a81da588b8079ab4190af6074be23606a88974dc82bff1773cb30218f0f109b5a117e994f62e68372f8e1116191b3a978e1f580ccd78c00d7bbd007dcf5abe6dd2d30ee0d09860e187790835196aac97aa487e718b447dccfeefd4a02a442d52992fad6588b6bbc6b2cf991018cb640d9d9b8ed6f63cf29b55980397142591ed03122a0356794d3d928e5562b8992500429d9e6e2973247370fbcef634d80f18fa1b3d6f2b9a1cb49ef897cb39a3fe8efd0a2e536b7cf705f8cb216f685a696b7d07f810009f5041d189210eadb0e7558e4f6692cb4b705a63703f1e69d7ffa4dc604c2c7eb3125ad75c4a7fd0b74dac8f380a56a29a01cb971924025cf4525b6a38d6d6bc0d16f582508be1505afa5fbbe8ca31ba6c85afd1914f6bba4fd1fcd6cba8c8d8de5104fe5a31ae5714e2904181b15a361922cc428975fb4bf2a2cb65518889669d64c37fb4ab6ccf164d1334cac85260899e720f01e87af1d292c3c094cb6d6cdb20650171081d58dcb79f17ff3be2818085ed1c425a56f78b91df92727e98897e", "1c8e126fac1e6fee71327d7b80c1d9a8cff9064b5bdcdf47431987950275e28d9ad4e931824c8419cdfb1da5f3782f401960a8904024b3a64b6ba96b6fa4d93c28f8dc0105197b660a66eb29fa4fe1e2bdc189f09abe05e2481ef43a5e2df22aba2f2170bed98cacbe3145baf8fbbe2dbacb837e6c00b0d3b87832899ae804228a19ff57af88ef1f51d11be7a6260b3c8d5a9beaa65f1614410c460eeaeb3a60f2af0946f3c3ba1920d5faf328e793cf083ec166613b6e0f0a7ac3a254ee64dfdf4ecab20d9d9563408704c1521fb9b05c527b3c8c9e34b55b3e9226ff554747195a244be07963c60310091c82ce8ac1d1db3d6ad40df52fcbfdf6aaa3777f65be5b0dac71dddd9b411244dd5cc039cc39d02225e2d1352204c07437d7d89899f97a582ff4cd56bd951572eb8280c53d916b05c89c3f620c8b7b24c3d2256d8eacceed58f18b012826ee7cfe261fcac1eb09b63efe008520dc41a91a308d49f3a5cff9f49bb1416302ef9f0f8a782147ec8deacaf437a3f1682745d4aca5b216951142d8034a012781f2e128a36c3592f7e24ef300af8072a8aa0b7b339c9dffe1040955cdc21719cdfd4569c32e9ea728e219a63c178330666aeaf46c2486be672104c355de953bb7dfaae3d5b618455dcee477d21db90d4bd773eafa2c77fe8ae4606cb573bd12d0da803726cf34d9386783a5bbff8224691983e88a906cca", .Okay}, + {.Add, "e4580a140e8d972f5bb9c0561a63223ed1d53dd9f24017efdde764bf5761f624ee283760b93d4147a7c820cb84a753b11165acbd79b4f6bb34a1886b646f04f56300848a6d167157ed78a22975e26b9955a0815abd4a974f2c71eeb8ad4fbc80febb3e5d4f979e23ad5d7df6c21398d5886d209904f8b86d17bc87097478bbca01a54714b3ac4c093770a8c1aaa2c0871300d6c21acee92834acdc2f6656a07e86d0f09957180e5f8ba5ec0bf0d2cc06dd8f250c1c4b32bc6da4810ab6438812f2c3e235f79559094579fcab9e1fa6fc3b01444efdf5673d11a7e459d97358269150b1fdbb75ccaf014908424dfc7a2a47ba1bc01c7f8034f28fec5d5f122481bf8d262e264418e030fd7125116dc33878803bf86b3ddf1e7a5f8144cf76c6c6c41393db03f2ad06a2e2da3cb10b15bb958e87e9535024293fbd6bc3e44743c064b9e1207a4da2cb3ddc83a8b412c3d38b08d369245b593c9f78969456e9c8c34852978f598fdc5d904596e6420423693a5611e62f4d6581100a9e78ed228be501b9958f3efb278f815fa28db2bcc6888ec86a0205df98564e1a88312a0d2dab7b3f223aa25d87344b8fed792ac0e9c2a0665057e0f8e70668bb96d73aa860808dd1c34d5ce1d3f9c0e6635fe5f3162b6b698bfec1283bb7868bc3da9081e4e1d65a6113a73c1e61d0fefd869c9459f72c559f63933839a32faa57d0244c3d7e", "2552c6c2ade73d23a8783dbc02e5ad299c60c765216097f6239e2db386b801de8df9782ecbad63f72f7f6e8420605ab54bbd5934487e6c4c39aa8a567b0bc4bdfac04f2d37df19db6e0a5da1d032f89698fcccc9c58702e2c8b20bc49e768681add1530778d76b73b1a5977a0df233a9317509c5ce6a5b54399e3845e609adcb305713a1f331eebaf215839815b4bbbf7540713105fbf0fe3fb17376de08c2e630a201a623019b7eff727bf3dd391812fddcf7a8a06156fc944fef609c3af9255452fb29a5fdbfb163a5347dca0fed416cde6f5ffbac810a687228d2dfea39473c9ac62f07af87395d9232dc752d988775644e3b055a51155fbf56fd6fc22da2ed78ecec4a8e4c4bd9a5514170dd380499c49ac7fbf504393362c8f781d962b6826088a123dfa68174a249cc4b9c610681e9abde2bc26471d98cf51ca4300e0702df2f306fff8dd00f9e92047356b7e76eb856005a22aac611782df80159c912fdcbf97507cfcb5c88c6aebec327b3dc188a4d157b2059c1a3da3aeea93b8cb67e3624ab7437811464af4b30e792cde187ed8012bf292030a0336cd5ff637e34609b6fe0e93bec5323414d192a4bbd01b409208c1994be413fed4b14fce188fe52922672719c2701e43286594d90f43d59b295c901f958efddf8bda815db010f5517c0a71f4170ee98f9c20ecef6477b1f3fb7fb0b4dc0bd0fcfc8b69cd326b6", "109aad0d6bc74d4530431fe121d48cf686e36053f13a0afe601859272de19f8037c21af8f84eaa53ed7478f4fa507ae665d2305f1c23363076e4c12c1df7ac9b35dc0d3b7a4f58b335b82ffcb4615642fee9d4e2482d19a31f523fa7d4bc64302ac8c9164c86f09975f031570d005cc7eb9e22a5ed36313c1515abf4f5a82699531fc5ab6a6de3ac429862c59c0577c46884147f320cada26745e4fa6445f6364b772f23f7a19a9de8b1867ffce0be419db6c1cb4bcac89b901f4706b527e81384716dd5f9d9318baa91f3129682f943da7dfb3aef9a1e8477a1a0d2cb95d916dcdeb782cc32553e85edb3b1ec32a12b1bd1e69fb21d9d14a524f435aced45224ad06131a70d2652c0aa2c266824afb3d1244d6c06732e357adc24a3c5150297d46741c7c27d2538817852408fca776c2177833c77f12889b194a60e0887751c767991050ea4d309b4d7b15ad27697bbaf9c129697e7e0402b0f0c48c584391d6461e9104615fa7ba190c45a5052bd74552e05efbaa6dbf42b3e4d967965e189b7fefba3ab332a8a3e60eedbe9a4f946a16b5ea14c508b886ee4df5072970abdfdbda921b8b9973876ed13a92550ca6c4546f70e3fa8da547a8a8e1ec3789e97ee063e9bfce7dfafba518e9b933840a68c51c21c7c32194a764848182a65ce5f12b7221bac67d8f5069f8bf956b8aa1724b95575e9e85fa603f7a2086c11f6434", .Okay}, + {.Add, "87e91a58bf66558ba233d1c8a62ae47ac946629e242ea8c4896fd8e4e4da0133e244db33a726ac16feb7c3ee67378691aebe9acda6d54248056097e76ea425af0499520685987abec366d45873c026a3c3f3b37f5067b37aa40ccb427af8af9e245300b4ec2fd9f7786830634d7831331268f05b5a4a54329d522d0e15ab112cd908a55373bbd200bcfd4c99736dfd1928ae6694363a7cb3e0327d8bb72a171bff3169cfd13befbb9cbe246b08fea51db04243a7bc43a364cd65f7dc116959a74ec82d09d63382984ad8423cbfb0650aea90d668950821cd471666d99fb4cf195aa4e58f355f142847fff75f372894f24679b06ab59b62c256b9c81922d79b337a10ea803a495f8a29e3e385e32944858ae5949a2684684ac3fbfa2b5445962e68630c5e154e64b1227d410c0a19a2026965612f9f304cfa2568c4bbdf23d02b52cc986b861b3095662bbb41c6c1b776f892e2714b8fbf461810a6f8fb52b570f953885f694b96302a166723937f5e884019ae96eeb1b9512ad332a4c6944b5bcb35fb96c37cfdac11f563148d05c3ad62546ba181329a61621efd796540e2659eb004a07e4ea8cfb7310d5296a87515d6d2c236a5d5acd2b44bcf832aa109e9469d62d23a5b7d74b2536c316cc85a0a4b68af65c50692a1c2d3f4785316dfc476dcc7a7cf5be2a24f31d20fa34877f07c792b850431c6c10167d0779fe318f7", "4f398697a1415d9e41697541cb338f2ad7272ea523d69c99b264a096c34187383bbcf0f2759adfe089281668465abcd2a0c697c17f4d1f699a724f940fbd11310f71aa9b319dc6b55206d46800d34bd33e5128fec960059e26917fe6f10cd6a11c973326e7ad1b59a2656cf290e2c5f3736c7ce736d07a0e7443eb3e1fc914f976444fe9e24ea12a5ec8c5f887d956758ae0a113ed79fb1bce14feff80d7dbf36038d2a67f893f7c0b0eebcb2b0550a10b1df58959c17e4cfd477957465e7d7342816d16cb665cfbac49c72729f99b9a3f8dd33fb1c5e8de3ef2f113432842519fbe23b53eae1fd5a8718b1d3468023c0b8b5f39fa0bf089b6e9921227f683986434b07ada494299b2b9d760a93ab622efc6d7df88235f852a0d3cec3e0b1c0eb4bd43d0dffdf7171516b60e55fbb7ee60ce1d1344df23e762598c79f5ca6792f89651fdba6c7e65552002d9a336c7e4ee335dda70a6614d9c537b595afcc10db3283ba7ca89aa6d3b4c5d508082b01612002aa03b0232ec42d451212bf5752095d7ed0e64211a8a1d2d5a5fa06553d7a01db5ee771b54a2f77cf0e1320593a87cfb051b6085b58092013058d8afdef1b3e4637e52c8a75282ae8bca0a137c8d9a53391723114d385acc4712f2ac323537177c01ecc07916a70c14202b4575f64ccc92e42aaae4341208cd24a3683dbc04e1bd16efaf08478d7ccaf57b9ab8c9", "d722a0f060a7b329e39d470a715e73a5a06d91434805455e3bd4797ba81b886c1e01cc261cc18bf787dfda56ad9243644f85328f262261b19fd2e77b7e6136e0140afca1b7364174156da8c0749372770244dc7e19c7b918ca9e4b296c05863f40ea33dbd3dcf5511acd9d55de5af72685d56d42911ace411196184c357426264f4cf53d560a732b1bc61291fb47538eb38f07a823b477cfae477c8b3801f30f5f6a3c7650c52f37a7cd10363403f5bebb603931160521b1caad713357c7d71a91499a20a199df93f7220963e9aa00a52a1ea9a846ce0aab860957ece2dd116afa630944740d33fdf071827c6b90972e52050fa4afa7534c0da35a2b4ace1ecbde459afb1492a223dc9dbae68c63faa87aac6c79aea7c7cfee0937179250b23d1d20502ef54c5bc83793f71a601559f0ca337e42e40f70e187c25135d4ee37be4b62ea694087aefabb4bbe1b69f87f5be6c6404bbc362093b4642252564f767eac7bc40733d5409d6562c47414020e9e5219d93729b3ec3d6da783c5f289c07c610de8a5279e18362f22bd742d6b17850272218ff84def04599bee5a9746760e1bab09bbded45e5049323dab6f5854078ab725b4f89e542536fa5b4d34b48676e0f09be95d6ccaad0d1fb3445f748c3f82802b67b1c70bb869e008987e5c55bac3a95a8bfa06c6d6613a9f3446b0b5ac815ae89bf3e0cf088ee49b6d1b7dd1c0", .Okay}, + {.Add, "-bbae0dd3c94ff713fa0e416493aa4f1209a572714098999734e87356dcb6587b93ac94c3cb5368d25022181a2a94b943fc84b2ee7e03d64f6dbd46bc2450e1ab845bd5076e1b487959e51398a4c8cb7627b311b32aa53fba1a23636acfb1bc5b2457780bd680a35c62d0119dd1570d22326cb65721bfdb7da58e12a8f6017d89439bf14cddfa9f723f1c87aeef87c32bd73819e9768e9479c124152749ef079e901fe012ca7a9e55198e11c0423904ee87c78fafbac48ceeb0cc2ebf71ac06fe9743999cc84807b2345f2c571dcd4ae6db5c1a583d7e9e30788d5b62e807e1c280da94a9a96ae03054a844b5fcc96f9060515820b8ca6f7baeca3940272f272419d63ffb244ab438300c504d144b812a575de02f59b4186a048a4d890dd9ca7ea6cefa7f5400ea8e3229dca43ad432d01af4ff00dddb9ced8b7a3f5484ee21de00d3c8fcc2801fd9e4b1c043a0d08e00bd8852820f07bff6ce3d7ba766227d0d0942aa5251d9e160b9c8d8d29e22b0559d75f62c2162c14a3058984b170ea2873bb9bdef2fd8435b194434e12f7b660f9f0cfa043eeb8a6130d1b8837dfa6fa62231be906ba0fae686812de177de9eae1cdea18b3863fee0f8e09780cb8948a24228c7d4b688c5b8840bfed4afd29d12eeba7ecd6a0e95b48c438f00bdc774c65d64014913cd1c3760f2bea79066e9be2a964c1dca81a1363700567aa243cc8", "476f865fe86276cb09b13909ed9ae4f71f66e4439e2d6e3c16b846e015969df915826340b088b34dd82fae57d6aae1b3f675a58467cd502763830ea7737d68434a188263ff5ba8f53cdfac01f943aa602af55af4e20a8daf46b8bb4df3f25f4cd2359a75627ba9612fa2fb363a941fbbf7e92c7bb73ba97743d9d89dd2671d861a5f6358e6b115fbd74531096d42b237c928f0ed89bada2e6ccf9cddc944b4a167a62152bc66c341503691685433202b0747ed1540279b3412858a35bd3476ccf31c386b81d2097299e1b1286477006508b4d05d7bdb6d77c54c497f1d17614d1fdfdeada60fb65fd2065e3b94483adaade55167372dd271c6c8e7c2df173930f378ff668d31fdfdf55766d3aaa031b1377e1cebc24b5b2a935609a36a4a0ae5cdc85386c77869db8497c3220f1e42d3e4826f8b312afe9b1e5a846a5e9e9453c23ccc3c4fea40590bcdb04cd73c10451886191e7b398e2d6c9466b4ef96be0d77ceb6ce52636d2f7f82e967a0462c96624d2eb848b538667322a3bfba83f5affd7491a0bbfaee450b34e088fc0fc43047be781d1ad23b11fa340b24eda187260807f292d9f9050383abaf47be6c88e142a68b28c547d653b5b6ad55e79acb0463f9214a23374807cad6c91f5a099f79bed71e69e13d2355cb43e8d92e93783723f096284a591c94c502b184897a9bb98587d91ace2ceb256996de8ec5e5635b", "3bb4a582abcd7759ca1054f3a4604005fecc8d1c8a23e4a2a369bfaaa7cb38715c4799f473d37cc0b32d8cd63401961fb6ad5a557fed12c26ca73a3bb1385a2891d2c5138879f46da7415ac86ef71da8c87a29d9af6039b3a516851746f743871ff022f4a5139f2b6975fa1c5d7eaee9d4c26116451fabbf6980f773430705ad8625a44418d16c04b353688e7e4a36050bb56f4ef251f0e6d0bd5b8b54a5c4277ea423518fbf195bfe9db04c500f8fdc1ecb741a447b52652778c749c619b65d09a7fed1b54d88f7769bbe62f29a2bb69aff0eb7f8038394bdc373c8ee96e330f7d235630b79085cccbbd9f0347ba3e1a7e03be52ba12b7a0bdc442edca446beb1db9b66daed52ba7256a1ced95b799e92083ee8ccb019a3f30d64cad96c6e3de35b63ded2385b32a1752557cb70ffa6e2d31f9b234d44cc45a2e075164fb235e22f8fac83c23e5b6d8294489d2f07650cad93f65a49122dffb08efa7934963ca73a8c292d45cf1973e65bda766401910875cf55869f0c51d01d1a3b09130b8789b8f5c1c8fd6a0f59a09d3ae9180dcf4dcda87cd6e3826be726ef9cb5c1e02ba5e4d6a9d33ef5551b439c69a6ee9ef660d8a11011c19665a628a3dddae2367a3fd694ccd7cebbac429609320f0c75a88feb767d0a9c39fa827fafe922b700eabe1a5613b91c4ad14ef3859a10742d1da2de7458f184d1120626d9271bc12693", .Okay}, + {.Add, "-59f96a42e1dda55396c4939d3a22167b465b5a42d0fc3697defde82bc64e7b363da2bbbc58cdedc9ea5f462f3aea841c8134c096a13c0522578f7aad943b73dcbc2a2b897df56764040659501c2c0846b7bb2d62796b6107d11181f5c08d3240d6625b76dd08799889de29c41787612182ade5057640cd4cdfc1ecc445998de6da0d94a45fbaebca44e87c8ebeae654f120bb989cbe59f9c2cc233d17f64b57eace5e682ebd389268d488af4e0553ecfc6e244d1e4cf6b0d1eb119aae22a742a2c99fbac765454ad90c9617cce6128d1ef7b404cb3775111ed3039917bd1b821faef44d8585e39ae6379a33e4ebd95296d0508037fb9f5cc4fcc11b79b8081ad3784fe3ead7047088c0683559c4561f7af0805f9193b0338b8c834af0a2d403fc83679aef45892c61d6d8c844598f5f000567da48ad7e4e03e4685a64afed8430f042baf4b731332cf77c0491c9d56c538ed2a6cf33bac0eca39d2f7a810b143163db785827d86cc7d3522982b234e7686b9558f484946765eadeac5e3b66fe45fa8e03167df13b8ba45ea3c279ef1279477b814b109b120093646bb5ef603530bc038e19d39ce3984dde046cff91e817a733e7c457fdd93d1ad93afa53bf1490ade314fd8d96742888b7491b272b2c49dfb7f1a65a0c7c18623701b868bb8efe524c643b42ab0edd7e1ac0b87a263ea306b5cf2c51924f43be6c88e44fdf022", "52df629c26329c3992e35e839a2886358816b8c9f384218875b828353797d145fb87b5ca62fb6aa3d6e46e29b1101f59bd7b55c5f17eb2c7415915ac5547070ba1b0492e59e94b63f0bf72c71c963e1a44830e51e433f9b314eaae2d6a9dd5e4e54e87fd570ed2a2c44da3f73864d90f048cfb9d887070f2ac1b1d9e120de4ac9c9e9ddd6970fda6e48a6831714e9516a1effdd7d2b6aa31cec3199a2be5076c718ca34631c82a82889005be7de56c135d1f5d04e269cf37bb1bf1db27e2681121d10e6d8ed4c9ac71eb7239396169809fd25c8946acecf320c22419ace7f06bbe0948b5d890cb266982daf7c6d22b01ff29a59629e0bea4b9ee9922fce4f81853234d3a019715e94e8f49c1ac6773355a64aa0e7933ea2b011df46d776ceaa6958f052559c506cea28b5dcb5da610dae54e7cb70ca0320ffb26cb86f554459cfebf7dccefa1ec70aa4732a870500c51fe5eaa0a3aa0822aa6aee352a363ef6a99641dafcd93434484ee0fcae707772fbf4b462f14276cda91d1355aaee7cd0c58c3ecb9dc44fbb8a71dae07e81e77d8b60f1113acb6a15868aa37c4656df82cb6445b76234a1138867571b31a4bdd8f3a23f42e125e6417c0d0de6675b7e2f730cb31c9183f3c3eb91d9fd100339411d08a7f4ebbda87b2d0edba17660d9073257ba6ab1935ab339c6dad75f2f5d9ce78054a59f32b41a8d4c929162132b637", "-71a07a6bbab091a03e135199ff99045be44a178dd78150f6945bff68eb6a9f0421b05f1f5d28326137ad80589da64c2c3b96ad0afbd525b163665013ef46cd11a79e25b240c1c001346e688ff95ca2c73381f1095376754bc26d3c855ef5c5bf113d37985f9a6f5c59085ccdf2288127e20e967edd05c5a33a6cf26338ba93a3d6ef6c6f649ee23605e145d4d5fd038701bbbb1f92ef56a5dff1a37537fae123b59433cba0b5ea404b88536626fd2bc69c2e7cd02659bd5639527cfba480c190ac8ed3ee77f8b011eddef4394ffbf514fa8e3c36cca641ecc6e1577cee9c7b63ce5fc227fcd6e87f9f6c84687eb6a276ddb626d55d9372795dd78949e9b8994e461b104abd9311f3d773993efddeec254a35beaa007190db7aa404192c0559932a774899a938bf77ae22eb8e7f2e5151b0800ed7e37b2d0431fba1f55aa92a61044ade25bd126c225308da0ac4d4a733a8e8062b89b29e4238aefa504acc1d87cd999d5b4ea4387f84712cd441bd746c76e0f603421d99bccdcb56b34cea2d806e4f3778b9a180013283c343f80794ede68a70104530fc7a08c0ef6f9880b26557bdd6b79efbd00fe686e93b5ad40f2404f4a4e3321797c10dcb5492f840e51da12ff86c09a2b03cf6dd4c0b23f1eb2cd70ffcba9c6400eb535b604207e287cbfa91f989af505ba3b73fe9594ac8a1bb8661298d1ede34b671d9f7823cb39eb", .Okay}, + {.Add, "1139a138c3e2467b6007b1b192f0d92cb9ef67a51e536aaba4a591c83f2f398b5f9e246000b8357bcd511521fad91613ae8d030ae740d0cb547efb936e96ad059803ac064f01f57793f3769c340981c5f22ab83f8048563fa9ad52c673f9a362647fbb9644313eedf9c552bfa9004d538d89fa3f15ac81509206770e7ff3a1906f3833ad31f815db46d05621fa9be1cbeb6e74f1f468b37fcc824df01eab52b9bc0b5cabe9a9c5f9f218bd0eda1e1c7ec4adff7df17c6c756b6349b85662af9cd0228c7566cb8bd6e119298aa39db8815680ff096ad2a9c38cfb5c1947f8d12a59804c8ec7a77a3d435edf1a738b9a12c37518debafbd87bcdadb5e4a82d3ac3a27ac54077bee11f52dc268ea65cb7b141f23a0150a4ae9fea669808a4a666f63f3fd3abe470a82077ebb59d9249b2ad6e8b7db8928422800cba5123a29e6f9b4735c9f230ed8f6036407ef6b12958b19b6307259e08ef39bd277993c05470eeddf3f256eab40ce6b95843802461956218a4a1d0a5e0289fe9ec10735d63f39b3763600da6049eb657ceb8330e93fa86132aad4cfcfa799985b33c8273e123c1dbcd7253b99b802a7ccae1722710bf7d57df1b9e193fd70b1d66ed65d36d040d8ecf5fcd2795478d643425e364210b22e5f861d3d8a08a2a89e25da0b8e38a9570b7384203e4c979ec322140cd1a94ffdc46f61ad6a4cced79134782970428f7", "f586b6e2a4bcdd2cf029c73870ab60386fc50b24c4233e237525912137fdd0e79ee3350d6fbdb078aabd97c7259bc312e055c8053694966a870b7dfc6482afd1b9ddfd8fb8d399661bcb19ffc74c84d7f0ce0019968bc0e89529ae747b90d65750add47019b4a18213e4c6d235c099c66bf25f4788a4166c2ce0cb31d8f004a9d38c919ca55e7151e3c11c2ed56158e809e5481922f6a63fa0d6b27656e12b0b9e269ad9e053b2816e5578f5cc55826df8fb5a41f44b5204652f9cfdbaa966e6db8eefd8f7513cd89a930a52b7fb3a94349695172565f3b91fda289dedcc7ffa4585142be28bc731a954484745e8cb74dfe829d66edda233979c8d9060dbd1f59d4989963a4a2ad24f48b74fb16be715650f232f99e2f499b213dc3f3333bed993f57d22c5e65e41e29e8d0e89d096d778cf43d3f9bb4e4718357e2b5440f48210dd21a736408b2667025aed91de635979c14c9520dcdc32283c68a8688b9ae62d383f3ca4f54a58e3b1dd127874a077990755bc57d3ccae30668f3284d636ec13bdca4ccc0bbbda83c73052e35abbbb50bc6fcb6442ad94c86f8192f693a730ca290665d6bb0b6af0b405dc8b8949aa8e34f09d6c7b6d0384f3147063d97650792a7af29b221002bf0e98f0a060400c81bae7f5111b1f0efc43e62db9052c21d4a8a1d4629efc85db4dd9378e2d5df9aecfd7a5ab71c745ece9c81fb2290c23", "106c0581b689f23a8503178ea039c396529b472c9e276a8cf19cb22e9772d0a72fe81596d7075e5f4780eace92074d9268ee2cb101dd56735db8a798fd3195cd751e1a99607d58eddafbe909bfb56069de2f8b85916d417283ed7013aef8a79b9b52d90065de5e0700daa1991dec0e719f97c59869e5097bcbee7424058e3a63a42c4c549d756872d2a917250cffd3ab3f553bd0b175f59bf6d590066758c7dc55a31f785c9fd787b606e3604a6739eecbda959bfe5c7be79d092e6b6110c1683abb17c4e5e1cc8af7bac33dd5b98f3158b17942090389d7cacd584b735c551249f0560baaa33416eecb32761b9746587a35d42b529d97aaf654a437509090cb93fc44ed6b2090bf1a224ddde57c89ec6a7015d30ea87a3399c7a7447d7da25cfd33550ceaa5706625a8a42ac1c1a4984e75ac18c8c3f70c724efcf4ef6df641d5812eb99672e1a869d42d9e44307bc0b152453babee5cb6be563e23c28e00bd50b2c31938fa9573f9d0a20929cd635d9b1abf78cfdb3f54e1a529fa5e23a2a874b212a5a72105a90db95e885f1eeb64163e71d18613d272e4e22be156a74caf2a5f678b990568b956d7ee74eb29a0927e6140c3b85bb440ea25a01d637467a5e07f9dabfc2b757902342bed404814b2f67b349c8e9bba939862643ce71e8b6b7455fda166683c5ffc77ffa785b47f2f98b16cdc08216943365fd0fa2492d351a", .Okay}, + {.Add, "-6f5d5d06496022b0a1696554b02bd360860006810394a3b542b8618c7a72934c58b6b80959aa4875c9df49424695174982873e01df197063634cac78ee761ad4a0a3e0749eecc744110207131ee423895b7575a73498fc7eb500c9457c37fbf0aac1d4ba65118130725da87864decb88c8a4c03106b7a710f2ad032953955e1eaee869b88acb3b048e1e8ca55b03637c8f8f9fd5550cb1ab1e508b868e48a506dd1ca469ab9bb518d8b6760e24a12cb90d124fa595b95bf5b8c30b14f8876f18b756ffc540e12d226eb6a9059dba5ebe0de13ec97c45334c7f91f9feb5ae5f80632134ce7e59e53caf884a149d33b5137bffd54a12eb5b2896e9816c871b2bbfd40d45da0f44b8c376e2a5d39c43ccc1f7799d1f34258f527ff5e766bd8786692bdf99996463b3dcd0214d115034cd0993e335d91d19f9a717df5b68f7f291a5db124e3cb43a90af7533bd212d2984136d64077f90fa9358d1d78813b2039186acff46d5b86b66a2a6af3488774e8575c34697030b218b54f802c3e85c013c27f0bb4ae53f9edb2b346776856d10043845d7de8630e0ecec928aef6d3ab94cf0cf0bdb8d3ddf4b22ebb5cb1756142ac185f10eaf20b633df9a67f39ed49c88db6aece377848aa126feba4ecead66cf593fde22be738618167e9a868b781748b619629d6d5b0fd409a52656f1b680cd527d9834921a069bab27169f2cb07385d2", "348642285a6e3d97cb1f6acde4bc1ab3e03735e1d9f9ef402b3ead30c3ff9c1845e6a19d6ba1e4f0b3dc9e3af6608e6512c2bc41c78333a1b0e060062a1d8e8b6ccdadc9e5c1e536beffbbbf88bfc9fa1b7def29a1c88c9b28383ec6d3fac8357d68a17705ba5dac1b3d7b1d39fa175bb00b099138146af03b4e71badf192815bc13cbe4ef35a70bb6479e80a88dfd10be667e284689af44c7b964e4c2297702042157397a31ea7ceb5558893742c98b717116aeccc0dfcb56d5d20fbedb3720e0855fb85787f44c899f5638ccbdae3b76dc295d26534ee9ff96b59535e05acb5388814beba2cd5691266ddda8f4330d5b8bd82c522a16e809be46b4eef37b763c171b0daf2760dabd273d126fdf2fbf1d25ca2e29eb6096716b27fa5ff29ab433370cad0f0b8258d30b2a96520f3f783009ed399d091cf93f8a1fc474bf0080adbc520f13db028a47196801ddb21dc646fedb1cc146ce64d3e4c61bc2d417e3e9ef5c834522611e557dc03795ba20a5d6b02df50ce0788911e2fc8b8bcd02ebaae899d965ef7286ea57b986fb42811fdba409497dc7f71c9a05014eed817e610e5706df6e02d423746b8df5803ae415656ce410721b57bca54d437a953b9c1e5170c4410a5eddb444b6ae67c1a2f867013b39f9e09b57a69b2f92828afef55bb32089215480ed8c55ecdfc80c4e21d25817329c6e041a9326bd0188d285da94", "-3ad71addeef1e518d649fa86cb6fb8aca5c8d09f299ab4751779b45bb672f73412d0166bee0863851602ab07503488e46fc481c017963cc1b26c4c72c4588c4933d632aab92ae20d52024b539624598f3ff7867d92d06fe38cc88a7ea83d33bb2d5933435f57238457202d5b2ae4b42d1899b69fcea33c20b75e916e747c3608f2d49dd39b9593f8d7d6ee24b275666bd12921ad0e830266569726a1cc1f2e04d8fb4d303169ca9bed611d84ed5e632d9ba138f6c8f87c2a61ed390539ac37f7d6d1a00ce95938d5e51752ccd0fcb0829705156c55f1e4627ffb44697fce04b50f98b38292b717e61e61dc36f43f82062073fd1dc0c144408d2b3ab79827b04997f62acc601d57e8b9bb68c12c649d02da53d2f10a3a2ebc0e8abf6c5d94ebb4f8a88cec55583183fd16227afe258d9163d9489f8010dcadd8553ba4833391252d55fc2da05f8e252e1a551f4f77664d26652c62cfb3c4f3fdf2c1f7ef2f79a2c30fea527349058451317450e19464cfec96690dfe4112cbe61fc75cd034393c45d2b10bd9af68a44a0fbcfe71cd83186a33d53cb318f5cff885ee1e4d37ce8fc0b4d4adcfdc76ff774a3d21d5d946ac20842a9eae9adc22f51ab0243f60ecbd197c1f367a2bc372ba03a066ebc3d6f23ea2e8c492eac06fe36af408ed18535a6642144c068ee67d4f397729aa32ab80258101f5ac02811800599da3ddedab3e", .Okay}, + {.Add, "-73079a427f7284bbfb1fa3332c40c125c0470e7cd5b8f8307fbe9408c517ccdda58bd3944dd098a1054727439901c2fecca1b8c9ac411dee0ba486f75c36bcaf24603eb675a9ea855464a7983c4d68214a5fd6463863997814da99b1a29d6898970162f221d98cfa7c5793340094f32ef3ab713391a7c687b9fc61208260b412f55d9f807f42f9d5ab515033fda0dabc149211cc41b7cb8aac769bc76d796e5241797a0177d45b2472ba0c501c59cf1c4a35d7f92be1df9a0f5eed9bdf58b8100318a91d7347478a4910978e54563b251b5b39d6a9c2b3a3693c55e2614f187c2a5c1c1e18d631783e9e51a222681cbbbc69142ac0cf7eba24e019db482f182ef2b2b37659fda240e4ce8bbbe1276b22516d830ea889afc805fd2878e3bca16b5df6b4a5f802d9988ddf5d4d7d046ac869ff7775969e60ed217b44d87268dad9c90cc42e2138aa7422e25c31446b4c7ab17eec2331179426b3904771fedff292a47503c21410cf2075d56bb70dac36f2ebe6d9ca123c3204d94c0d1eea9d114e146d292a452eeeb0c175306e12ef951cac25fa43349ae5a87650f31f3b6b5221da6e0077782b2b77a2f8b375821906daa9305e63f1605df55f2bf255e46c4c9a6d43f7cb71ba0168a3dee97672486516ab2fa6ffee570abaeb4a5066180128b08a90daa30f8d8005af55b7cc7ca19038130d07df65f694f8666e5f0224928074", "aaf511db709cc3de156dceb66aba11b6e72ab44a106dbd7bb1a28246697cee81eafb5d332daf2c79606669552fd4fc598062914bf5553b64c100c577f73d266ccc74eb434153c8aeadedf336a6d30dac691501f8f61325c071b5ac8c0179b4f42ae96834f057154a62cc09b16f0378308686b80b68e8a99d976ee36167c0ee998a1f8f0283ae9ff5d4ab5c1af8bba02dfb1b2cd0bf9f83962ce4cf34d06ac1858625aacfc8c6b8c3c9291df0b5ae7060ec76b84174055644eaa31f091fe39dea89842205936768dd6dc949b89cc5dcf1b8d4ce45386e9d16e60a03c074fca4d4f56d4a4e151e7d76a7d8b879960295c6a778a19e1997d10f4aa8ba1eebdb3fbff3d08f2014d0a6537633cc0877a64165c7c3172002d02d075a1bfa793e05e35f7404baae880c91959602f875bd49cc8d88521be37c236f69fcb2921ebb091ceb13379889b0fc1fd0290d7d1c83784d760deef89c28612d81a890f42195fc581da7b13726d6bfc00ce7a2e5324cfe85ed5c486effd6dd0cc6d8fccf75a9c9956d24509dad157e7f12d6553446234b014a6e8f35a89e94af87e9bf936aa1d89e78ac5486291da9739c61c9d3510005d2e960803f21fac0f54ffef9d2547f2ff91fa9791358e18076c2847ed75ef6fab4c8ba7f3134d7cd2db8667cbbb4d2c81004e9e2dd60de8334410727242d91877e35e4d08a3558130986266bc4a9ab08fe8a", "37ed7798f12a3f221a4e2b833e79509126e3a5cd3ab4c54b31e3ee3da46521a4456f899edfde93d85b1f421196d3395ab3c0d88249141d76b55c3e809b0669bda814ac8ccba9de2959894b9e6a85a58b1eb52bb2bdaf8c485cdb12da5edc4c5b93e80542ce7d884fe674767d6e6e850192db46d7d740e315dd728240e5603a8694c1ef82046ba620295a0be6fb1ac571e6891b047de7b80b806e336d62f1533344ac30ce50f25d9f566f11a09954a144a240e048482376aadb44316d408ae5da866b78e82020215324b8b22a486fa1cc9d79946e8eabe9737ccdadde13ad8c58cb112e2ffc484bfe693a66d7739a790aeb0f8d7358c8525525c8a043a3ac2791011ddba9bad304129165404c967ed643765594115a467d3f541ed2005a4941f4160e06089009b7fd08239b28404561c51e52a46de5850e7cdb374d4648a042114a2ad45b8fc3755c062b20eb3f0d00fb5c700c78f749995af500acaf971c658b033c3364c2aef0ec71cd797b3f524efa70619535c4a0dac1ffb0c256bf2c841f0fe37482d04f906214e003d8105b6c2dc2693b6569f9c9df736ea04b666d4c56d1e685b1a57e4824bed11fdb7deccc0eb74fe0be0960975a9fcddffe9ac3ac853c351b8d6fc67559e09fede884b24fb20f4f8a34e97622fd7b326b4ebac6e7545f5202bdcef5b43b57d16c6114e5edfdd1c38255f21c748dbffd65a786767e16", .Okay}, + {.Add, "-2f7b796ae92a00056ebe6c32e1f3f218a101dbc5f0808deaf6faff81fc664b6fa2769e7cd48d0cd1925d0788d772c67952e0b7431c2b49541456a46020a48cc7dab86367a65691245128f92af7fe22b822e56eb0ca34500879d47ea9b3c8bb95361a91ae1e843c72d487b9d66f676544bece2cbf71c3c78b9c45ec9c0cdc04e3ef8eee1629a2ae32069e450c4fba1ba1d3eaa7c03b8e1a567b19a67fd5963ff7c3a90f4f5505ee5d692db5604e4300387e79217dec32e70af0a6fdc98af3936f1f7804c786791643057361291aa6625d86479aaad84a22bc0014bc2dee3172f58fa0ccb5960f4ab983dfa6a66fe8c2bd0a2d6d517eaa3e935534ab746a2c8ac55401964849e944db54434a82dbed98f5b0d2056066dfa0aa6f1e8bf4d7f20b727166f5ca37694cdd08f00e1bdc76f60e587cd8ccf45dbc1b5aa593b4ba7e71fa6f02ada79cd63305ac196900939cac5f6300120c117e6b2cb55a7e4026a7b367c20411b54280f22dfadeaea0f38c32e68dc34820fb22954642ef91918e249a38b8ab8cf090941746adb851135c9ae1b7b78ee155a862c91a4bd18a39e20d4b0ca05c825da0c31121201ac468adf4dcbf99fd15f5c0686005f5245ff09190bc6f056fad70a8e82aa8d6f4d9a4b66d08c603b9ae344fa04aee9c55914d768fdfee34555d791fe1d738b5dd2c05a71c4e2c1545073efb1eae2e40242e2c3e17c678", "2647e880c46c977da159f0b22e2a1adb20092d1255a1a3a2601c892f58e9fab4bf4c88075bd3b29c061b95339fa9a20f774fbe56fc448c1eeff09288ad33e6154e17ab572c1f10e1fdb8915aaf8593ef96d7a38f6bf0460183341795dd93bff4d9b8edb04b1492d4390663359ae4eb46570335cab71b7d6c70f9b5703d7eaccce20c10fb36c1bd03747a7a19cc3204e7be555b895b834c672139f31986bdf0f481b28cdc50f746465f92f36f9f86381037587af8bf62ddf6c1a0457d19e2d7b0a98ff6940649f04ea93d4d680a217ecdaff2a36519137ef49b76be1142586780f3a01736c4d8d177327b81c1eb9e7efcc5c25008bdcf91536b663699a12801a956432a092be5bfb889b95fa7e46e1b6c5e5a1d0e0f9ad3a278e9fc30580c8fce29e9867b93fb2203b4707272aaf8c57c853bc3edbd7373ef658b5e798a8e54c1fb65d9217e24178fe3f50caad5a25faedf8f7bd21b39eb8b8b037b16539676dcffbb5b4d68d27f0d9160e1e3b8e1fea0a25eb805c4711f00e9068090d4a32b9098b498faff8693674f901feb0bec4d51cbcd092ac61bb6df522da13990668ce5ba846bd13d6e0fe31c75274aef9a948d1a72e342f8ead9b12a7fe9a441dc94aa7bec4d9bde1e5b47d4586dc1564a33432599d18f1952357f603b69911d25270cc0d77c3e18887fa4cb2357617223cb2a94c510374e7aa0aca7395e4da77de2fc", "-93390ea24bd6887cd647b80b3c9d73d80f8aeb39adeea4896de7652a37c50bae32a167578b95a358c41725537c92469db90f8ec1fe6bd35246611d77370a6b28ca0b8107a378042537067d048788ec88c0dcb215e440a06f6a06713d634fba05c61a3fdd36fa99e9b8156a0d48279fe67caf6f4baa84a1f2b4c372bcf5d58170d82dd1af2e0f12e9223caf2838816ba15954c36e00acdef59dfb3664ed84f0341f68273040ea817099ac1f0aebcc8284720a6852cd009142f06b84c7110bbbe75e80e33802f25f45c3613c11084e38fd654f745bf36a3c7649dfe1cabd90b749c00b57ed1367942516424e4844a43c0446b1d48c0daad3fe9ce74dac904891bfdbe6c3f1e038522ca89eadaf77f7d895277e8525744cd07f6348fc47fe57ba4477d6f4ea36e2ad9547f9ba9317e3091d34114df36ea482bf51a353b2ff01d38739cd4861eb21b75c8245c55bdfa4cb083709639f6447fa12a570329d3113c8ac248b667d9ae7320697dccbd3aaa3445eb64901b36b1764559e91100b9816ea81ff6f3f5910d83df5e28312850ae9465ebc1d82ae247123af9a3e90051a6be26e5d8168c6355013e03a59d1dbe5a48327f8a32b2c77d8654caa4764c4fb427c489835fd4cac9cf61029c6be36022d582de1fdca5364e156f3c1a27bc596ab8e1737de13b07595793eab9d4a434f88301807ff707aca40d8198eacfde9699e37c", .Okay}, + {.Sub, "6cf2291bedb2b8caae6c28c4766592959e47cbaff3648af06c5c4fe72175baa93586ff9138c877fd36b665705eabdf0db7d6fea8eba8ef0168cca47a87fb7107657e1ff44469ba7580469d85b7831dd0912ef8e46579929de5eeb143774f82a03c86d63edd67743e54c206f670662b9bcb9ccebac586b5add4b1d8460e7adfbe66ffe3e34a062e27ff14806b509a72d42a47ef88fc7be349814eb962eaf68e5ad058ce1d97c4927aaaf111f17fdea27e12fea0ecbfd97c29c3ecfa4d48644e2ff19f3a483553caee72e02815f2cbb04183f7aaf26c11eec41824faee300e6ac4be3354006245217afe7f0470d118fdba1615875ce4d32b40f3a5a55628a349992c531f1ddb66e6a49bb91834b805d7564f6ea9dd238a6e359d4939c2ad0dcb7cdf9fdf65a0a2074f6109da3bd495f68f406ac6663ca88307a8547aa57eac25ffe3179d04c3251a485ba920425e4e3d4810eb526695b8410e192914695b2e1183c277c83ebafba3fde7615fadc173d849ba09fb4e3b096638162dc81ce2e69f8e8bde8ded1150383dfed38027ada965b452ca2463cb4a1c99b4cd4244eb8b814afce2f0e4dc23152afd6eb7d1e3d0d134746623fc877434af6a0cc7ffb434259e0cd341eb5ee634b52cc5bec37f2d1468678809855fa23fa6976e1ec97158cf5f43377a270470df6c0d4469d7e6caa6d5ccd2f4c6bd17b5a0d8392582fb023a8c", "1d906cd93c741acb49024f2ff7006fe52884a03ebab0a59b85df187b82656427bf984d87229c73cf04a83ac04f3a9c026b235875253d374b5306d50783c62032a33d8466320118442783cba5c7510a603c4fb74dd85d805a45f205fa21d03ec17e1d96eec5a73e47afaeed746f1f6c6c938e6991e1476a3a6429359e2a99e8fba2a09e601baaf8caec677185cfd09da1a92015c033d9d915e64c20d0b8127940e1c92301dc708c2c430d6f2d0c2e516c1518cafcf981da8b0a28463072b8118d55bfe9ad0f8c97170289218d5b130388207062a260a2abf9d759f05700987b2e3fc18a3f236800778737c5772ae8c0dc8026853ec6a9c2c7b69501feedb429f9beb740ac901ed16a2d02ca29af13870945d4948eeae76165c199bcdcb2046703c858326f4bbbc7b38e9fcf1788a92882f9aec69474c740631c317f1921b7052ee9d384ec4816f53a57344b252d41ea5c9191a47e3e4194ea7c193e45ea4d95096abc655678ce091945a0c7ab1194506ba62d84944a6f4ddd10179a7353c3a7aa8a7592b52a4fc9bdeea9861f3c7ccde813fde9eb487893d4052a24391e40d68b6e2113420aff9349c6129179d1300831f63bedd1b491ec15f115c38f0f6af6371ce96a4f93a564de42ea00ab88c96fbf5cdd96eed4735db744bc143f5d476f0125c71c8aab4dc33cf825b082f9fea8f7d81ce8341e43519de258df5b64994e66", "4f61bc42b13e9dff6569d9947f6522b075c32b7138b3e554e67d376b9f10568175eeb20a162c042e320e2ab00f71430b4cb3a633c66bb7b615c5cf73043550d4c2409b8e1268a23158c2d1dff032137054df41968d1c12439ffcab49557f43debe693f5017c035f6a51319820146bf2f380e6528e43f4b737088a2a7e3e0f6c2c45f45832e5b355d12ad0ee580c9d5328127d9c8c8a20a339b02989232e41519ee8fab1bbb54064e67e3a2c473b05111fde5d5efc657a19eb9c4b41cd5ac3ca29bdf509b25c733d77057068897b8acb9638748500b6f42ca40cb0a972f75ef967e71c9c13edd210377473ef9a6303cdd95ef021e1e2968793d10a3573aef1f9f6d9bde714b48153a6eb64e0b08f2504d099a154e38a30ccfdbaf7ce5fb0964791747acf654e63f9bd26a0b244becce0c46bbffd1c7e142a48c22fb8c5cf520d0f94418187b0e250e0474d51d310c52eb7f59ade85776ac239d0fd62370e07c7a57bb62e8422d9ae4a1c09802afdf87de13dc76b9f09a185b06162da98f22f7e40168fb37e7006e801029fa08712c97cc3ecc3a7882d188c5afa31e0bcd4aaabf8ec1dda2d12381e1375c265812a0c9027e2a362ad2e2489978f70470a4c92f66efe9d79bcb40cfd6e9dbbe17f663a4a90aaa72968b2ee1ef52b20a8a1411605e1d705d9c59231c2f151eb954eccbfdddf4b60c929ed46402f5e046279668ec26", .Okay}, + {.Sub, "a456f4952d6921e419f3f69cb7a300c7a0eb222e0dee06e28cb911fbb8e49c6dd5f5cf52cf774a1a17cfd27339c8b3c55aaecc940c89911d79c36a610c846c9596db70ad0882656ecf044eab0e033f0b2d88a20afdb73374f6736f115d211819746df3537e71df7dec8121e3fc12aa94952e3e1f7368ef71c7a03490e99dbc3dc94cf746d2dde01b8661b5641099a68134704aeb7d08e4ef5738c0c53f9759c2093344a8815100b5a3413ed2ddf473716c2d71c1f43d290eb0beea252ec795fedfb3b9d1db6abeaabb1aeaca6500ef2f5a1f888cc658a7e3457f1096f81f62676da43ac622cfc89f3835aca4ceba521bebafba5803a81c4753342ef0280f629efb5582e1d05a7d8c770af1862df2d1f5ec4ab0350246b6438cfcf01be0ebb6dd565cc07d9dcca35801969a67eeff10bbf8d523ddc1fc277729c9f8c3dfb86aaf6a12cdc0556c97e3fa87cb87ac3fd03704f7a964065ad9fc73fcd29d6d5f5cb85cad2787d9f4a5faa185c9deea98990cff6f28b565f32b7e2919f3f3cfba35cc410b8d9e83468516e5234d0874cd11fba4e5215c2316e259e43e7a64cf275fb13dc050f578fd2beafa440ecfe82519c39c41e80b626948bea36611c101f73574439577b31b1076ea05f9297025719108e70d47d62c98489072f71bfe729e06acf99575959a597a519e7802e7f0be00b28c722c546d7767cd7984b5a1923e015", "f054052c53d041dda4c39770e01f237d196e0cdf174f683e26b2e42c66437802e0db395ba0d2db0cdfe6f04bb7ce59bd0477b2ef82a17c9ff2960fc84a196d9cce0f813432c08cabed39aeafd3c36bc914b6570507d750974b5e51afd08ade87af5d579c4db4da65dc83b2b9f40ea5a003bbd5a87a0ed64a2108cc481a33a944892c809f4cc9c2211f8ac1dc25a0e0421dce00f27dbeea2139336ab1b7529e679ffa0a0ef848db3f53440762ff0b75ed37482c30885fc56521ffc3e87669e344cceae08238ab7e8b83db8fe8303d6937a86f1fbef84e10fa03747a9529a69f4f46305d4c453d2a3870e68c604d806c204965ccffd2cca089d3ba16bdde4eb0b391b6e1f8a71eb29f385cf545e57c70016b74466f69e16edcee5d41edbe13523578343a9e05f612d35150461acbf2afcd4f93c725c9885fec1c67b4c06a1b6826b9951e03e8054beb1d2b7fba422710098408ceb82b9c08cd6120a0d842abdd367409654a1c7f9f6e21ab17c66235770ef9b1725b50a9ca4756e3b799d9ddbb2d3cd6006677761f0b564c6d7d41e565511c8bb5dd980864149bf30bca86876ee6105dd7e1283fc9c3724add23e187722afa9126a63d51fd86a03262d15515c5663c9a777d859f98663106bca4aac22f2d18a7c2324e83debc6898779f241ef6c2a2349d6e428797569315ee11361e2b8f26adafb737892dec007347e9e229b384", "-e60e95e300f9afbf6324580714a4f3709f5f5abc367087cffde7530caab52e3c037bdc6673db666b3e69f3248431ce80aeccc62641d8e38e1af9d922395126d374a1ca2962386655004969c522e337d861ddcce457fbdd5ffbf71abebab8cd061816786715cdbc6dfdbba09bb44d7af6ba68f1c682d84753048ec8ff0b99cd80ac97b12adf9be41f6724a685e49745da0a86fc43c5ee5bd243bfdea5635928cb7f66d5c47033cb33f90ff375d12c2eb620855514691bf2d436f3d546237d69e4deefa4e51af4d2a0d829e13b89ed5a44b2cd27362be8867bcf1c898bba24a928cf56199fe3102dae7d6331960094c6fe8aaad15a52921ec55e86d3cedbcdba89a20189ca8a190ac670ec462d829d42e20caf9b6c19bd0378b58d72ec000496c7a2ce6e962c19489dd136dc744d02bec1900674e7ed689d74a9cb15342c1fe17bc2f3f127e2ae826cdd830301c763130613b95421eb365b2d99e0d3ae6bd5e76aee3e92d19ee0550e7792bb28738bed7e29ba7fcffa4a978f7452185a9ce217d078c5478c8f41b6b9e7fa38acba989431623d63c7d5d6f5eefdaf24243994f8eafc81d2d1d0aff704c2a69c36e305208ec0cd0825872b68fab5fc01b544f6520ef861200253ee90f790a72a0da86b161c8a36edb4ebba5a33616905df3cf51657d29b4614e8e1ffb1792e6de2b7124b83fde68cf1f0b1b76f28dafc8fc905d36f", .Okay}, + {.Sub, "66e62cc7cc21690808bc8f83a11a712dcf333d52d87baf9e7557059473eaca1367cd29ca25d3ee8652fda3757888b028278e23926fca0e330f429a6dad03e26e2fdc1e78e1f3373dc2795f0eeaf7aa7815f1603f49bdd004dd259e21f285c0ec98ba889ead1403fc51683327a06b16d9ac7f0e819c0f660d593b13d3e897b3e163f628a1fdc5b7d71433b268f9647f96299aa3a190260c61d0485edd9975491bd525c35a2de6e958fe0e82623c68568e62a96f5e52c4e48f9c2de4e5b180858921caeee670467ae5da45c6d8ecddf8ea28f4e815f5a06f37685d4e9f83a5fefbd2bfa8a0d2cb06085eacf0ccde9885980be5631887909f4ca916a1bd983a9542ce2c24effcc33cb4cd62d12fe25ed5a381590e8c613512e1d94f4b01fbbeb12c6ac2d383154ccd468dcba4cbf39d10ad6f748b66a73e4a957a57a625d97de8f1096b796fdfd4e458674c96f9028560bba05aa4125a0c95c88a7f607902099afd5683e36a8973a06a7db9ab5a3b26ddc8205e76f02ed26ca6e17e8303755192662edf4ab76c324d0a22e3f51039c1a8ebfafed351d654b98e7cf34c881a4de91667461d0b105e3296845678a9eadd7f4b2b4b5274fe88ea7f80e4e46c4da5b55340851a6a43b84399bc469cdec9ec23e213e70121c7bad11a652ed18a3f400ac62cbbd58c1a5fb0c987fcfdf6f6dd41e58a7747c0bcaf814776bf2410947c9f37", "10f540a8a8086960bb5399bbc231212c6904febf7b7687bf735dc750f112df64db67b481a8b2014cceb678e06d4ddefad79d1d52a44ff80089b04938d345b0f2e094c31d17678f21beda95399aea5d491a930f95ae9fc89f4f4e2350c41eaa331895e5cb4e2a9981b4c3f17346b4beb136d378e4e54260bb9e47022be0bb2f549defae9cd1a225778b42fcfea26cf741dfa111bc46fbdc647c686ebd82d16217e864b9a83119bd6f3701e835a36125247ff929565c893d92ccf3b97cfc6832b32c699a4a4eaf8f11c5ca7c23a3c106513d4d1a3b64afa011bca86a400db53dad33c83dfcd4093e06bec2378ddf41a5b47fbd91b18ff49f1ab0d2c35533ebc04b74303fa06a421e8ceb1031ab6cb299a577ff83e5b8d9127fcbf4305304a5758519f2921a2953e4947912b85ab55e329312a17d35e4d4bfcb3bf188b160ce6b13d2a3bc4967e11b5b4cd58392e8f1ba9d8f18acc7eada08ac65cdfde7d5c637ce9f3c0403839c4cafc2586edc6e2d4a8bc0162bd042d1a57e5c2603938f1c135df6c6195099498f98a3d12b1ea90fc676872198f1891fa409a71b103d597b68304e16a67795d2ca7fc04c6dab7fa8c72b315295cc6193e97fb9337b585f4491ef0c7a9ebfd264890d1ff107a384d300ea2e61149a6fbb292dc2550730dff57bc27b2af18313e498031972655fdf7122b1e95c6fb994368f4ad80f07382dc6a178", "55f0ec1f2418ffa74d68f5c7dee95001662e3e935d0527df01f93e4382d7eaae8c6575487d21ed3984472a950b3ad12d4ff1063fcb7a163285925134d9be317b4f475b5bca8ba81c039ec9d5500d4d2efb5e50a99b1e07658dd77ad12e6716b98024a2d35ee96a7a9ca441b459b6582875ab959cb6cd0551baf411a807dc848cc6067a052c23925f88f0b56a56f7885449f991e5492a2ffd53dff02016a3e703ecc109b1fccd2be9c70c9a2c99073169e2b04607f63ba6fccf3a2b68b51852d5f561549c2196ebd4147b4ab5491cf298eba7cdda90f0cf25abb4e45f75f0c14e9ef76aa3fec1c8019feab93eff56dfe38c27d166f79c0031f843de68644ed4f759fbe54f92811e27e2529f8475ac3bfe09598aa6a85c00620d5b1aaef7193ba750d04168ebf8e8b214b8ec713e3ede1a5cd30e30c2698aca3e661d7478af7ddd36c7bd2677f3c8fd1a7713661993a61e1141f74a6f328d1c24b162912c43632eb747df6705d753babb613c7dccf9933c60484b1fec00c72885587f6fe6357f0838193166d2e8bd717f12c9f190b1e27573dd3a604d351584d5d83c4ac0d280e6192f76937a8b6816c40a0afe6b34b81ff9f8bca89cf500ffc7b16913ee612364340a7baa7153ba8c9c55953b451922f7e585ec8757ffa7eca2d9ca595f4a8f03b190e409067b18c66e8a9897176c1f33a11ad8072878f1fc9eb01cd866b5fdbf", .Okay}, + {.Sub, "b2968d3d146eb63d44e83fdf80fbc77b1cb67341d8b00f5971258e67b4fa0fa9d475a686ce3b3035945d1116c3c13dd9ee7a74efb2b60c7a65d12ed59c84d93c3f02c678031affbe38d670fd9b3195324a0750973a690eee5506f61d77e8dd91b995472d85e21391604aa0224971a2af8f573d07d32591533937abf600e3e0760ceece4aae18083d79bcdbe621f20c3925583a8cdcecd1a24b4800cf052346d98c817d11bd929cba6a630819928bc6be9c1de03ff84bf1827fbd34d0432a26d1cc419d20cb5e9a3683df3d58059da30991255a294adad0fbc53fe06bbc83c8378f8f19e172a2980da4fa5ac2745600dc5c4696990bf0ae4edc59e8713ec82b4deb88eb7a8956908d3000d4df9c9db128ecdd688ebc67456a146f290bb10bd5197aeb271874b8fff781124167753966179483101026b8297f1ff3a6daafba9f77d59d24e1cc27749353435403a1028550bf1a955d9a2dbde22c6b0a1b9cd575f2d4a7843a66f18464f67d72d6e2e5b16bce52bc41fe13c18a7ef7be56ca0ec583fe3bd36a571af65c1be4dfa2d94c52e43ca70f425ca3135590afd5edffa811738e44c8ebd2c4ced2c9423397b8886935efc3df014f680ffd54c7fc882f4d75a8ddc8626d54f159e3bb7010cfe5fa13f4279dc42a2295a0d5e1cef8a237af762bd363f316008e68dbbf1af55e05a0d717f805f63b148f1ec7a2d077446d296a9f", "36ebbfd490b2b4fad3d33a3781f6c441b1b3ba1c88cf8b90102ba8458c90d7e876d5b77b115efe8cc18c231bb5a46901c4238d6fc854e8a0e49c0ff40b90dd61651cbc64953a4c52f37fb36171d2c85745aa6de4a4c2b1a1db08c45ba1f34d70cd7f7a15abd78f35b8c978bba8d3b1424ad2ee75657ba84d829a1a61c78b9b4cfb217231ff6b269e4d93c9bd0ce264d251a541ab33d321b60a4b9d5cd3b067758b6525a4397fc40e297798fb3a542cff986333ae7d2482619bfb14b6acf3275aa2ef45ff9b8a9b4b20c7808e692fec627a07950c60e70964a3ec96cfe32269c87ce691c4c1b95be633f9b7dcbbbb406c4965f99e6141b40d6f8fb70623658fe5f2e15baac1b1a0dd230edc3db2c46c69c4f1a18c1bb66d97d60c782fe2289cb6c1155fceb7f4de4412fa15d78466c93ca06cb54b8edc0163923b7ebff12bcfa9e99c713302493bf0697a35e620d004a05efc83a5415ba9da33fe6e8f4e757a541606851a1403e0c36f13c4ddf320d19ef822593a0ba2afd8916528a7d5629e20b847d874b5e2fe1b401416bca64f219c2981012ae71c89ad252fd550426e53c7f86d7fd5822dba05bf17e5a6886af453e5d33a810a4ea0347f151fe60b954c5ae8b7f28542ff60fea5a0a701010aea136ef81cc7d0e5d5cadaec3d63ce601b3e0af6b27452475b08b75ed2cd736955e0e8a8430cca7e03c540797e5021ee178d", "7baacd6883bc0142711505a7ff0503396b02b9254fe083c960f9e622286937c15d9fef0bbcdc31a8d2d0edfb0e1cd4d82a56e77fea6123d981351ee190f3fbdad9e60a136de0b36b4556bd9c295eccdb045ce2b295a65d4c79fe31c1d5f59020ec15cd17da0a845ba7812766a09df16d44844e926da9e905b69d91943958452911cd5c18aeace19f2c291229150fa766d3b2f8e1a919afec40fc63723172df64011c576d8412d8ac40eb6f1e583799bf03baac917b276f20e3c220199636ff77295257212fd3feeb6317bcc99c6db6a7171dc51ce9f3c7972153499bd9615e6f12a8881cb0e93c277100a2e5b89ac07012e09cfaaaaefa416cca316b1b629b67f8a78fcfc7a4efb00cf1f8a1e9d944bf27ebc702a0b0d7d23e62b0dbcee33862b9d5c749bcc421b36e182b8ff0d29cdaf4165ac497dc281b8db8281abe8ecfcdec00b3aec9de38a2e9c91e1d803280b0601e11b858d21407f86c9b8c4e5ffb9ebea0ff2052eda3a18769adf8efc4dfccd6306307f27111b1ed9295aef4ac276345f3faf5a137f840dbd0c8e632fd314813260e17758689a86b80009dbd39bdab95d74916509714cd0a2a4df1301d74e209f0a48045196fc8d5b2dca223b8294df5106fe811f1f8e515cf69cee4ef29e0b8a5a76251afcb0b06e2bb3e694f5aedc86d40a1ae470dd307bc2290923781370f5db32e4a111b026256f8f44b3b5312", .Okay}, + {.Sub, "-69754fe6445ae268980e1fd38b16ea3336af4704b438e11d33953e8483ab94e44270fa7331df78d171dfc2f3a65dea51fb973326e01224dc94a925fee403c00dbd75e28269160dc0e5f30af7bbcb89b0b1ba0a1c19cbaaf627cd69ce4b50cfb78a3d59bf6620c989c73d1d1a1ccb952fe704902686856c28b04a2961aad12fd972f032a7a3e7ae886408e85fbe2d5207b667b92c8dcbe2434091b2533a7463e6c901bbb10e087a1d6eb74df15b8aa898274e19f3072359d7e77998d3e37085f051ea36607653e108391a8f172847d4b5c088a854429c663531da72cfc9111653b4fb360f7a8bbdcd54d471d3e3bdfde799a0c67281333f43a004ee86ee31928045d4b5eee97f2dd0ac2dc6e8ad9d4ac76eacfd46b58d09da911f587f6c10d6c618acbbdc7d120cfd39ac9a2e30298935c809f297bd325bd01f1c65524fb8f9238209c01dc97631d6dea481eca1a7e1069f5ec7e342ca0f0ac0a63c348c8db57bda61e6ff2b0d8b7560eaecd2ded2b7291214bbe73dfd72de7c84feca9ad23888874128daab198f425cccff10ff35996faf3182a0c1036f495a3411aa1455b142bd4ae2202ad21622420e7d7d27816d7b631a572b88fb790e03bb28c62595ddc5311084e15ae8eceff18f7b432626a230b28674af48ce6efcd8b3679b15e65c369a4f82213e652720ece507fafc6cbdcfe834791ed161835a9a40a4ecd6409fef", "2f183edf65f4281e8aa2e7311a283232b2f8b176cca9b515c7ad4e4910ddbd6ca05e4be7b9d4ddd6b2c241b8f2be79323370a4f8fc516f086fa6817865f9cb38777e7f8d6ab66ea65d41c5c35da903322288ea98d0a7416798bea223bc6366559bba4441a457cfd533f295be6f56093ef3ee19b7684a25825e1f1658bc96beaac8790cd46ded175d63eda2764b65bc80592f77acad06331bcc3fee596ad7ba2c7ecf8fa25c9b858da4aebbaafea4bc82d679473ff1e78cee724445d6d5b9814d50dbf865e48f4165d188ae73eeb2ea196959ca9905b896492087b91b9ce50514e97f2194eccb8cb2ee6975473f51f5b2d04407a65cfab462f546430c990134ce9fa28ac45f2788de7ed35d898c057d46a93900a53c946ee4df6263b7d76d0602d75de24d56a1825b4c117464088828da23f60961ee46b1a206e89598056ff17e6c1fb1712942b1026c24f250410763cc93bc5b632277f2268fac3a5d85dec7fa13713e9eb39680bcc25a32e6bec03a3ca00924ddf9295fb5aada783152494acaa5b73d80e9c37ccb5f6fb87d331a4db4b908de4ab47cffa8be4ddd718a92c595c9973dfc0ef563f45cd67f101e36b16f165a88f108afc2ae3f25e941eef587b5a9e1e61b4bd3e79b8bc37658fc5d3d8ab238e1807eb995c5ef9aaa8aae1cffdfc9b94fed31faa9072217ed2408f5e2ee4fdee61953674592be93d1fe0f6cf8ca", "-988d8ec5aa4f0a8722b10704a53f1c65e9a7f87b80e29632fb428ccd94895250e2cf465aebb456a824a204ac991c63842f07d81fdc6393e5044fa77749fd8b4634f4620fd3cc7c674334d0bb19748ce2d442f4b4ea72ec5dc08c0bf207b4360d25f79e010a78995efb2fb2d88c219e6edaf2a9ddeecf91ab0e693fba6767ee843b693f7c11d4c5e5c7f68ad609930e880f9730d93ad2155f0cd1a0aca54c1e1347d14b536aa3ffab1366099c5a2f651afdc76132f90ae6c659bddeaab92a073da2c62ec65ae3226e0aa33d8b16fabecf29e272ed4854fc7e52622beb65f61b689e7a57a467574a80433de71b230ff39a69e4ce18de2df3a6954b31938732c74ee57740b348a6b6af2b01247239a2c80e17e5fdebf22178bf7081bc37437ddcc8f00a9e29d3b38f5885be0e9238b1b20febfffbf9ab790d722604faea5528eaa1ee29718ef2b8e2d94ac9743ce2af44d3331b23466542013150527692126c7d75edd3259ddea40c3223451fb99d92f165b21de0c53726d294275f76fbed1b83532cf8665b94dd0c0dbc3cb78e324fe724683a60eb75806ef21881ef1b9ee876d886e2201c39c77a169ee4fc8d45b81eea7974e01c91ab3bbc42e11208148b657adaf26afca6bcd48b7d52f19c2283dfbb64bf562fc78804c2c84e1225c4035c166408d20e705fd0280efcf51f0562a0be38135f3824c8c8ed58d476eae5ad98b9", .Okay}, + {.Sub, "-b666e2d9f03d80293c3cb449b8c13452755049eaa52b518c1179d26b9d27d88252dd29daa174deee7588e25e23182de5bdd929957c5055c5ec6f84349fa60f9430deedcaf06e791be13c75de4fd4c1eb9ed39e39596d0db06c664e9385978d7fb43b691a58cc9bbe1441ff42bb24e0c8f742d9280e9f6dea2ee2a0fa8dbb86eb81d88c4de312f74f4a86424d5ff776e289ab429d8e5d94fcadd6bec33f89a7808f73226dd566063114e9a83ad37f21d375d44a5bc06369f853a3eb476a1c95df9c43f9c7bab53879aa727564ccde3e91e0e125eef2d0d7f6b5fd739a098d241563650441c707d10a78d9d13d2df31d24728970c531ec500d4097710d50e533765016c66bd91d91bc2edf8375fc074b24b2383d5f61352ff27de45ffb5f38d5113d01f32324200b493263da3236f53b991b01d3cdb653a0e07acf0fe1eb7053a863239d483f1f959a9cd6260b174ff72cdf9dfb848c6c08045c90de349d91650b401718702c06fb4f5f564f4a5b8594094984ab2217eecbd06f35e53a5aa899b72506f11ba99376ca7b31c512c4fcea3de70bfee12240d25a1c74126ffbe9d24a2a62dc4d2b75d8632034758e9541d2d3cc6c0c5ef6e12542890e8c015ddc7313fe59e95db4afa880dbb1e1ad2c4cf6b1ba28d25442af1ea6e09e5fc928ff8c4f7903e208f9b3c375da5b3ce453600fda89af33530c25cfdb97c0294825e4d65", "5d0b94a91b7c92085665b7ce8514e52d6b554fe39f1a8340352cfe1aa5d3f4c6f2aa2fa487f9c349bc88d8c1de884c1497549cc737928fe00415f9dea5021786a2d4e770655a2c56fdcfd3b5ac6b592053f7e9d650ac587571df157ea2bdf39e5f30577f73b90fb7704b77e4b705d200040da80bea3ffe52c2b0b6885d4b30b61a8d1e46ad894bb09cb2948673d112d297b2c7b6e8382c190497f9975275a9c543ae2d47fe3698d702824d0792035f815ec73386fc8f01801137817931a92003c73cfc02edeb34841ef674356831b0d5223406e55d8c6b6422b66a48cb2476800777f6f71049050eb40b781a3297c45c0d651c6226b22a190a31547316c88f58bf538b0a0c1652a7e9625ddcec24336b5777abecde804d2c5b275630ba4c386cec44f3f2514f552c7b70cec70ff16db377a6f8e175d0a9a25b12d2e0f33ae86462e72abdc3289bf205f52af28ba395d94629762d8dea6aa2264af033c51517aa6db9fba6ee4b03dc97e22988909ae4923da3d68d1242b72f74fc8fba94180ef9dca15701452b41654c4e15d8cfb088da2b8bb326f2f971dabb602542f236301b7cb1bb2dec06c5cba40ec4c5f99d4a9b8a987c7c289bad96568c389567e552eb4dc961e86d4fbdfa0c8404974706d833c10968c3fa5d3493839a2055bf76751cf9486ff607529b4d5f3ac5a438f7a3224d864e0bd26e9c372c2c396ebce64287", "-687202d6ba806a0aea29831320a0f87292aa5482496d3858f6449b415fa6724f17d8024232111138a3e166e7c0b9cef2f3322f608f57953c62dcf221eefc787fe5e2d64d146113e8bbe39b139168a53f0de523b9e643295078a57a67db176c765a740e111945d973518f97d8e2b8200c9381d59e6b29f531659ee0980626e924d2aaa70b8bba7b25915af8ab49d08a40c04d7be0c11e0568cf756583866e443d4ca55f6edb8cf93a13d0e78b3f3b519e9624782cb895381f9671c02da84ae961c1013b9f6996880bb99d9b8bb4ff94be404219444cb978e38e1641826bbd48c15dae473b2cb9821f5b99152e0576f62e548db36e79d0ef19de3acb83ebd6e2902454f770c9a82bc3ac5056144be4a81da29b2fc2d493a02b83059c30703fc5be00151324839155e10e970c6a3360c16d0957161e5135e3b062bfc3df11f1ed9ee9196492471a954bafc28d533d18954c142355e5d6b12b226c13fe170eee2dfb21bb6d2df10b73918dd78e7d36533dd2d23c213f33c1a3ec7befee0e39c298954ef1c612ffc478d1f4013229fc00577e09fc7315051d7f005d276669f1f4cd401f57e8f2bebe2351d6120c1ee2f167c8c75f3d421809bfea7f1d21557dc31a1c8daf007e489ab8821a3f22b219cba79edcabf5e93e88267df1a4065252066de1f0d8ae1696edd784bce079727e2da41ff62141410330f934e5a83c033f448fec", .Okay}, + {.Sub, "-cfaac95ec1b3f53197ba2e440510ea5d294a37c166027de625bf927592961303e6185a85cff5cd139c47967b55e20fab318bfca6aa91253e0359cc117719658620531d8febf2ad862da3f00217d2481e795d057fd22c5bc12be470279236c43cecec538b0df0fd30a4cea23c6664bff353727d81e685f5a8a131f10049fc3a868c47c00441b4d8a4c8df33c74b232aa3483a565714d2676bfeecc7d2c077caff4eb9e5405c77158dc9836449a979fe275e811e9397762e9ffa96fbe00e248c99329eaed5c72b903869a1416dcd0937fc5db9e042b50c5e9023ec7fa33bb79cd2e047d507102b1a82ec4adc59a1a2cbdb0dd12a2670e1a2cc3744265fc32b46906873075dacf5ffbd49f154e4ed4a801002b16a7afee310e7a3279e0a8647f9e4cfc11ba8d53b7a7c9e3b8797887cf4c7dc9ee5583430b29ef7edcb5164c7151b0f76523165d38ab17bd136b6e43fe209c0ed181b724071cd9450879dacb621f9cbfd84bfeb7b7f7a75e66eb0892dc89454a3d18774ca100aa826c3678ab274cda595d0f038af277f85cc84af47a8ca33c696a72f8fa77c894596c05be23de27f5f23dcf7d017d127c783d167bf3b2d97c4946494b0d26dfab06e72ad90df32e7fbc6603f80956bea3fc90a2aa48a1d77aac32dedaecb5632530a7db6a69cd8ebe2e8ba1a013a22dd034ef59b1779f777e4e6599507c4b44bc08e3a8ecf5d860a", "bb6df4a412e5b6d30063cc63b91026de38118e403ac0d561e9518c9d1af5ca29e47fb565588db18ce0f80d4222355bc652081d74134e0a0e3e08709fe2ab28e0808e3c8e01514c5f2d96e8a9cd68ec0fa5b424f67bed068a94e7260af6d881fe17f7b0410a10787893a28370d9e26f3bb708dd74b838a13a44da338d8b0be38bad062b5781a9ae50d5f0d074a5561442c34805bd56ea340dad75f34b8ccee6769e67c7194dd00dc4d5321fe46acfac4b2d6ccb72bf83ce7cf91576480a5bb7b0f3e0ddab1be51777b4d57c50b8564841a7780211e5b3a75907fde4b3cea7d0468cb0b1759a0a2474146699a3b0bed95f8c6b852c0447581333b1394592ee802207abba985288b84cc300dd1af00726e4f3b726e5c58be8766d9fb151707a815dc090565da5b4e58470a7be4bff92a8946693e7d5740b93caf56d7c11daf9517c60bf87af8705cdea905f603dd06f6abd3a70ffbe6b0dc5453b6620a59601d7ced602eb64fa1cbb76364ed2e3a9b24cfd4edeec61ec569705ef3603661e08e1a1ef6e99f707620527400b6ee76fb7dd86b28077de985a4e3cfa38402fde51c64702fc4a54363020d0a7fe0a2700df025d201e94b97dcd1276428ebb12512622bdf140b04ba05a71d725cdf9b1f1348933cbc5432aaa4570a94ca7249e2d8988a7bf1a8e8cfb3931ce4e7868d4bff8e76a85d5923f6bdf696e3cb3f45add24c8c4", "-18b18be02d499ac04981dfaa7be21113b615bc601a0c353480f111f12ad8bdd2dca980feb28837ea07d3fa3bd78176b7183941a1abddf2f4c41623cb159c48e66a0e15a1ded43f9e55b3ad8abe53b342e1f112a764e19624bc0cb9632890f463b04e403cc180175a9387125ad40472f2f0a7b5af69ebe96e2e60c248dd5081e12394deb5bc35e86f59ed0043bf0793ee60b825c146bbc9b79ac62bb1e4d46b175ed21ac59aa4723529eb5842e1449aa728bedea0656f9fd1cf3ac72281880444a267f8c80e310a7b01e76bdbe855f803e0531e2549ac005e92bea64570a5f6d196cf8867caa353ef700b175fd5261a53a9a3caf527528fadf6af55fa55619c6b2701ec1f5ff7eb80a0cf231ffdd51a6f4f6689160c46ef95e10c74f5bf6c27b42905172067af060010ee345e3880f9d5c4332cd2da83c4669ed5b47633fc066977035d9e0ecd9589c0c3096f4b4af4cc6fb5e17d9dd4e3712cfb6a84342b7f9c8a2007024e5983af0ac35419432e01591a382bde96120a710975cc6cda8bb566f95046ae740112ca6c5d7f396b760a7ba79171f0e2801cac63fcf008bc08fa8c66220274c0647f1f86f81db8ec01a2ff4e4b2f94e2e9f8070f2fd2dbfe20555a5ed07108b20efddc1659703dc95bea6ab768871185910c6db9fb1a254d4266193a20348a6fc7354ab51c75e6fd772dee26abbebd473a41db9fd422ee9ac824ece", .Okay}, + {.Sub, "cfd08aa075190852eccb163e3cf54c657f98749aa2e4a5c5036afc75f3d3a804b63283e9893fd0cd18bf0d6459b4cdb8e58d70341bfd8b102dff861c92ac0d9770ac387477283ae3fe010d3825cbd1197650d55e6634ac622de856e11317ec047a3ea4bfec4b38615f36272e5476fc20f3c7cf4c7990ad82b1678f1ed0037422e7ac01e0b07ec3af29da68e4029181cf79f22e7cbad7e57b284006463e0828137b4b33b14f8c7a5527ab19daadae8c185be84493ea3cbfcfe8b2942f10ec93da27ef108ab974e85e469be9da54a02e52f39fcffb48be21dace5b5f9d78a84788b3ce5b8e617fb12ed850fc76fd5d3f7d72366ffb1920779bac7959e42965682580412c72426deb3ccc3374c5a872a24b327caf5ee0e4e421cba18401431abdac5739cbea25e494571760885b6ccff6f5a97db1cadf07c7f32005b189f81504443fc0656f697953e3aa3e127a54009e46db7352efca5bc6e5a8caf237a0ac611f51200ca8a85d9566555eb5e548c04a5b934ae12e5a04c1324fd9e17dcf67963dc4d5536f15be20385ced60782191298934aafdd0aa7312f14eaa2ef5071ef25e1cad73a93516f6cd6cb269f7280215f1cbab6eb5254ef4f4379a81d248f1814f08f49aa1aec5e5435f53def01704943b7618cf12408753d14e5e29f7b9b68a990a59d4192c4056fc46b835903e2dbd0d0c52c30505f5844901d30ecc054d0e8", "46ea30ba87127398d5bbf698d7ae646d8cc8a2159a843eee2e288d65d695204100ab2b9d4f254dfa83c2ebb3cd9c21696d1c3b1d6c9e225cc5deb1c8455206cfd9410975a3e7392569183a6b0af2dabf9e86fbdb860d19800990b46cc44d9e091183e2e65ea3c73a9f6c87ae929970608b888e971ff2b4bf84ec5616ce873464e08ae6857502a705ec7e8a50f6089cef621a1b5fe8e5691a667c2aef52aa375384d367bcb7d48c978ea1fa9bedf2b121cf11780ee34b144fa468e8148cfa95af0229f2b3ed73c707b3e65b7423f163afdd3c8a0882f5dd0ba4a5df3c367b965ec9eff28938a49ca62f28d01ea4b5ac9ecb99e7cf4a6eb6d90e550d60fc4e4d824fb92496a574c70e5aa4a095ab4ad8b4235dd22d81e8aeabece8230181c2e70c64560fc9f8d1934aabbe9a566d174b5401fe26cbfef5975696c40e951593013c47dc93aaada7d74bf8dcc020c17d9b1e54933b61754af0e6c989f59c2eeec81ba14a479870db91260bde0dd469a62d49cf24e4a191958c9ce59836712e712e6f41564a480e15fbb17c46955934b4263d03abf89eab79546577c7ca7f27214c2900942f6c1d61098bc222b38aaf7d9e7ce1981f8f8574d58fff44ebac87844e1b40ba5ea7fde621f2fccc8b3d3a4560b11f51422d587f42fa72a51db65aad2a301762458eb21e4e32eb5f47127e3ba0ac703bf572a45654efa5b1e9b8f3d65e3c", "-39ed28107fc0e313a6ef4534f3df0fa734cf1acbf055f491ddf1dd9e7757e5c0b548035eb69150edb236fadd8800d48ddec3641a2ade49abc2feb9667c2745f6623645ee5c74b5772938299788961dae0721ee859fa9ceb9e6b22efeb31c1f48c9dff89a5fdf13b48979253bad52009e7c4c11a25859a9e759d5dd24e186fd22b210266769fabacaf9e0e3c2b5df84d26a7af8781d37eac2b3f82a8aeec9b4d24d1eb481a2dbc4f23c2748fe4317c8604952f3c5a4a74852a5ddbed19bebcc715fab01ab41dc7881cf7c9cd67ea760caae028d08ce69faedf7c029425ef111e63eb30cd0528ca19341a3c05734dfd8a6f47680cf98dcaf5f538d77c2b9b7f6fff7b511cf814de85a8de1694950c3ae8f7036073793da6069d02e0ac16d913b319ee2730b56734a053a4891d0b64a4be4a7664baf51051ad764c3b37c7611b0f803e08d53b710420dbe38def91c3d9139e6dc063278a534786efd4678b4e40209ac3846cde655b7cfa6882276151a28a415f0368eabf54089c09a9859517ab50b6508f5111cba19adf677bf51b29b13a4706148c1a0d2233662dd278fd6af5d031ec958318a0f9a1eeb578ceb3cfd7d1dc4dd68a4331fe640bbcb438f62f53606502b14fde2f9c39ec6d74d4e38d5176d67efb53c3476cdbd5dbf3b16df11c18686bca84d1f5a48c326f3c3b97a58c4db9f76c94253f6fcab1594b8cc33818d54", .Okay}, + {.Sub, "-40a229173fc1bcfa139c5162e6fcb528a0df8300a1454463244601c9b400cc0759e7e29be5d8cda74899c957e732ae854997baae1331fd104c69e24fc818ddf8d7b60fb84b4cae8c252b049749daaad0ea824768799dc9e7541ca898c18aa976ef01614ab3b3ce302f626043f50cb8e541742fb6f4e0ad5a08344e81f23ad2840ae13e801f705b595632e6b30ff5003ed695743dc41b02f5d002b3e256c7207f4c8f74355a1bc95491dae8462497fb816892ebae8cc3ef4f1cfeab0e895322134365ec2250f3fe4a10f9839bc139447451a3e1080c0ccff847747fa878bdb89e197f6b8ab4488e371d3e660a5a088c5736317ed8881811ea30e748851e61013776071fc75b0dc11bd195163fd46bbeee5fec6b29fbcad5b22c90a02366f2e348f4ac2ae6d93d647f42e8a8f5ec567a53f6bd843ac1121fcc6faa7a4017305b05f716ee5a8dc90a12b1487d1315439a37c2e0011056d3c9f01b9b09b5318e527fb2da15134a5f83916f1f2330f9e6bd4e15e603f242b08b68d31783f657490773f38e63f122e8d953fad05769514ab07c375c580d929ea52e26a586d5281177b839338bfea1801cc9a7028770647dc81ee3d94543941dbdf48ea40db2a46415ef3c1b90e1eba8f0f3d2dcc6a7fc090ee73a150a06b46bb074eeb77e69fb58053ef0b8d0aaa227fc66a1f1ed199b862e6e5073bd85e753df1d0a28f089fb4e3edc", "5c0890333522d07f94b4b2af585be709fd786b007ac2a95defc110d53dfdd9df437e9862d30469f724aa4ee572a330e970bcecbe4fdcb122ec838178fd6b1acb4ba85233fe745c42f374173e917076926de94547875343c406ecbb0285dbc2c1b60d6ea8dc19a08f8530a644bfb14e2d81ac4ee4180d110eadb5c48fd1ddc6506e323ce96c8242f86d79959781ae97fb8f075e3edecb882a171d145954cafdc11eafa09f5b58bd7e75bacff96aeda24f5563df433de2049bb6e8fc3878d41824625dfb81a4be2f6d177d6ce568c3f7d9856fa90399ea6fabebfcce890b6d6feed5f9141f57ad4b5de34d690d767e556ce8e8d859e5a661cd1629e191bcb092a1794b1ccb1608419c3134feb7203dab44eee132aefb2ef2309d26b58852aeaee909177e92524398c9403208ef15cb64c3677a68be52c4fbe1ae2d5a4ac36e59ecee2beb93cc9538f5b0d2b6a8717525560d5fa15661029b5602b3ea4e80b990365206871945e5b2c90b8f820cb7de9297b78fa8d9914f347ef067c6005f159e40caade5d377a92dafbed1860722412977c8252f3611e38565d2182b050a4e401a56bcbdcd77d0c1a5f05529c7a9d4058d7d019fa8ddd6123a5975952f2744e2706799e3bc3de3c39e0ab80a0124140797c79584116718f1146db5ee10353591d70e5ed67bfa70f84001bda8ab18c67a1bbc6ebece5d36f76100771b251b73362", "-4662b21a7313ea020ce79c8ddc82739940b709b0a8f16ef9034212d707e0a9a54e1fcc2213091446bae46e463e5ce193e0a38979f82fc8227b321a6757ef8fa58c7094db8b33f4505462460b32f1b23a1160dbbcf212fe23948b7448e9e865a30a6238354175683927b56aa84107cdc8198ef4a536617e6af30faacaef58aee911c4624eb6387f88dd0a800c880fe9be8f85ea21b207bb7871748527ec13d05b5e7a6e3f4fd1552c79369545bb46d5a65de929a2c0a20f98d86d3ad210e06395898bcbda6b3fe140e2715a6a17c583f1e9fadb9845ab76f306344c9109748f9d06defccca9c362ecfb733c9b317071ae04c00c5e267278070249e69e3a2c0a618d9bd1940c6e453594a8662b466f99a2aeda7e54eb7dc4d536630b7bec1dce37853da2cffe619e0bd6ebc984ddb330a02d352ac6a63e6f8a8a8d4fe4c36740a4c5f9ad13ca925da20c55a87d9c5aec8d23b5fb25bce3f3a57bc6485a1999eb8317fa7d84debddebdffd81b51c564a677915efe7fdbc57eb0c21e00565d3a61580039424e5a636c2ef6bd6fc9c36ec313b3deab00f3bcdd8483c7098578b65bb9de9f57db78fd28e40607da0cdf1b0877bba95f3e21fb1f18343b670596d8641642952f1daf872d2db38847480e4a4f60b68e6247cadd3f863592dd4afeab5e5c619ebe1261cf0beaa20dc7a44d1296100c3aa972cd274e931a30623c4d05723e", .Okay}, + {.Sub, "3d8c6ea0f3c87958ab7c29e5909953497f85c1648cdc2152987acb1d0fe5b4f20c3df942b29e59addec17dc56c4569436d3824bd898fb03bd4c3968fc6cad2de8ecbd960a67c1181a72bf9a1303b86a0911f9f7da6dae5d9d2725b44357ee2bb6abe02efbe080e051da9ec56312c72932e3054c0ccd76c82a7e3f6050ed254c281e3801fc3fb84dad01cb347e3cbeb9b1a54a261a3de67b6a307e6577a68b2b649c06674e3eecff599a2053aea7db160bbf312cf8d3c1adc618d3163d38950726a0e42461ce44ce66ffc7c2a344b02a5b7a1025d80dff4d43bf66692bf8271675158b938505d4cb95ec997aa9ac9ea3513eb260a050fdd08e45dc419e01d17de4fee14839250b021578934934aa1000d667abb5d858e4f4e8eb9ca3ea874ac07d3a3a345fa5f7bb2a4d317e37234bc1229dae2cd8513c1ecfdd9f2b0d7613ee5f75b00df05e54955eb99b769d694f2fc51b7da997d948c54cb7d7d39a1861f078825eb35a6889b380dbdb0468616ec99d1d1e255f608e35f86b0516773fe7b3e01511413aea6fa2bb26c475fdb8a850a46300be5ca86b694fcb6bb21c208e3e0351fcd340238833458cba8f74403b6d0dfd6ad2e17780a0cd3c48b7ad8958ad2f419e54d0008f601b9550f2dc215f1cf1249831b699a1bd2c8f0a1b1b0ca090a23beb991e1e3e82ba5d4e517daa600af09d0d2ef7565c9631c62d04737e7fcce", "3d19039f0f32f405929093bf00cd761512ac8e2ac6aad96c9ca8ed08c741a5b1d423bf77d8a9c295ace3c9b6befb2f54dc6ca0593942223cfd176aed24c151eb926c5526f662fd090d0ab9e27d49c7bd6c458070c57dfc1935984fd7aa055ce961478016616fb283e02df4df4fd9bc22e255b9472db45e0d87efea975e863354e959b5542235c41f0ba78db6de29cb89b131a9ea593e398a0102e6632227d66e8c4096f2f94e67feda106346965d49046acd3822776f6c260a1a22dce8aefeaef0a61689ad7cc5638ae4609e3543de9a384fddda49612bc06867e41512bdb50e714dabbfa6c96603ea054be9298d5843efd1e2ca362a65486bf7c93984440c7a6470868a3dab9f488f97e5800fc95d548802f7c1ac8980f50badb411d4c042df9e28d21ba87610bb20b7f0138e3325d6563100121fad7b63ac75f77a685049170f5e8a26b81dacff58020bfe9165ade369859b0a3ed31b9c6a5c59b57496dc16f46ea06b9ec2f48c2142c6e07e1cefccab1a058ce6faf3846c60110b7576c197f9d691290d59e024f66a07f2f9b38366878cff278c2dc156895ccd3f4948dc3f7398aa086257d0bbb2d7d3b9b0adc2e382b70556263fbba311ab7caae96bfeeb0a87cc7445d36756079749a6b4edb394f695b8c01982dcafac03a6ed71f42152d4b03729157178e14ce8f64342a21d05b32dcb6290730fe8c3d0211cdb2e9f51", "736b01e495855318eb96268fcbdd346cd93339c63147e5fbd1de1448a40f40381a39cad9f4971831ddb40ead4a39ee90cb8464504d8dfed7ac2ba2a20980f2fc5f8439b01914789a213fbeb2f1bee324da1f0ce15ce9c09cda0b6c8b7985d2097682d95c985b813d7bf776e152b6704bda9b799f230e751ff40b6db04c216d9889cacba1c5c0bbc475259105a220116922f8774aa02e2ca204fff45840dc47bd7fcf81eaa067f6bf91a1f45420685c5125daad15ccaeb657730e86eada51c379682bbc6f678782e5181b8bff07240b7f512483377ec913d38e827dacc4bc58e00b0d78a993e6b574c44bc1713c91f12419433fcee577c07865fae05bd90b63eb7d8df954a510d8c7f14f133ad7a2b8de77c39bd904ce59830c162cd3b46928357ad12a51e96af7841b27cfe401963bd3a9e2bb656646895163fb366f10f5cee7fc76b84dc79c569397ab6b452f4518e8323f8f3ec170b8612123842cef42f093b74aca07c5a6abec7ae96607f9fccd26b7dcc90f0defdb1a50405bfe87b9a6077a82eaa14d1a06bc023f6ce1d701a3bea30cbe3e58f53e7359ede278c007a0c187232b9fe0b278a5f3d53d9355f3ed5d1fa7d7f1384e69c2190ecfef298be7e99218d8ba358eabb1bdc5870d283e3a1bb3ca5b50173f231cecfac43ed5e7b74f0e8268cc726f4a58ebeed49803e3a956a3078ce4f2b97a5892af2a5cb95d7d", .Okay}, + {.Sub, "-f47554d6a46881514702be5d3271221b9e10af36bbc7ff28874c8c9de6c8442761be58526daf5c2e469bc34f0898ff169aa640572597c0cacf352b5b2643b93d14dba3b25c48cd0565c58ad172ee6d24c99ef4381714cd4f6a60209f68af61d6c6defc9a4505fa3feb46ff5b3058c446da7f727d52f8bb0b33eeb2686371ae006c3d61f5e48636dac65f11c163308f61846640891b1cf11a92826c6123ad5b1b95b4146e5bdad8af1af28202828afd5ea7b5532416434b831c7c56ad48fef28107e16cbe694d6b9f95229648472ea8b113ecbb035d4c369043f24f671b7358c059b66f1501979d453c190fa85850d56fc50766eadd07633b351f07f9f5379d0173d7554eae21fce81d665cca8ca9ebcc4692ffa8658a7c409efbd13282b225617aed34f59c2578d031caaf32741ad86fac37424e13481f420b9609574a8ba89c12543becaf244e6dc1fd8ecddcd5fa19adcb6dede82f12e28eaed8ffff08da7d2e71bd9c6083295a5d18118e8b6a25b2278731ebecc1ba3027eb66078729b58e51d2cefd573746277a05f8ba446b09c6ac4602ec516a5f37529788c7a03eb0886e91b34c74b9e7b5919838460aaf27a487189674a68077f49c15c8d1c226d1fc919302016dde304ec65abb7c99fec873010cfccea1731d97d5988fb6859da11fb0bfaeb87e7fe5926ee91e85ca8467f8a3f761c148e3e91af17529274afe85f8", "c09385e054945f4d626475a567d8b3df58900bba5b5338e892c3e2bb1e58c314dae7be79c559c8cd99d48c70ed8edea383dcd42061d98b2216f720d811418b6b1249897515ec9ad3beb51d4ac6cc9c49b89e4d72f9b845138c5328c2714a7d73a5dd389a237a7fa2b8d590f54e7703938272485f3cc46230b4cf19ca98cc96db3ce5ecd8eac988c8fef62e7fe38b70a5540a8a953b84da88bbb191e31efcd7de7553ffeb31bfbaef7509cb8ae29e24116e181c1b2967982856ccee5fabe8f350c8154a12d7b868d3af2d1f7a07215d0db1404e8fbc6d205bbc855351f7a2a0b2ff2c47ec3a76c4b5c1364dcb56dd3e355915af2914beaef94ffbeb9ab6b1d148d9a42be51c5379df91009b384b17f8fb868ee00543cdc038b44b2d9e1ee6589fcec7934fa8b4f00836cd24bb79b2fa4289b92a814681ede7e9cae9293bb570e0b3feea88823468282ec93f2627f377bc07de49e13afad44070ad2025789f44376e5104f2512bced14357a595a7b651cdd626afff23d5ddd4910ebed973085a8e973967d098d5827b23d14b7171090042179e30ea3d65f2ba3fce9f73da37427a4ddb37ecec1ab7984b2b0d1ef5e47c31e5081e3e982863295e5ae43ba18d3f6b69d37194d73dedef1e52f66e2bcad9d82c6d941abb0ca987e0a0ce9e985a8074e17c903417ba9908800a1a8ad749cac83e4d29e06e933aae83947df0f437fb24", "-1b508dab6f8fce09ea96734029a49d5faf6a0baf1171b38111a106f590521073c3ca616cc330924fbe0704fbff627ddba1e83147787714bece62c4c33378544a827252d27723567d9247aa81c39bb096e823d41ab10cd1262f6b34961d9f9df4a6cbc3534688079e2a41c90507ecfc7da5cf1badc8fbd1d3be8bdcc32fc3e44dba9234ececf4fbfa3c555404146bc0006d870cb1e56a1cba34e33fe4442aa32fa0b0814598d9a939e8ffc4d8d6529217015cd6f3f3faae3ab7349450cf4e7e5d1cff6b6d14105d473444fb5c24e5005bec52d099319b956ec0077a2b91315f97358e2b7013c0e61fafd4f5d73af2e13a51e1d1613f1c61234851af394abe96e4a4d7b8133ca7576c7ae66f802d7c1e4c7cd21dfada9583c795346fed0a1987e0149b4c84544da68d86897d3ededcdd2b235f06ccf59ca0d29f560f2808641197cc65326753158b695f0c6cdf404c971d5b5a9b7cf2329e722ff5bf92577a81eb49cc2c28eb1aef82ba06fb7243320777ffdade1eb10979804b8fa24e0fa32101ce90c36cdf00cc8a29dd7442bb5740a08c3e433d68ed051f19266283b7a75f302bc6ceb3960d49f4ddcc345650093a3d66c20b4b33ea8db1dfa70ad0d63b41167fb667396451c1e3de4adb1eac5c9a24b2d7a90e95c7fc71fb6395e551df82194923c3eec963a7e9aeef33910a1ce32c0e2448ba1b77723c97509a7183f36811c", .Okay}, + {.Sub, "1cf4a39b239ef3f8018007d2724a52f669bca50dc5545b2f4ff0e804083899682413f22a67e1319eb4301f137c709d795f84ba62611fbe9a55db5aa8a95f1b1dd5a0bb9dee0efc05a5ffd18f724d70cdf4f18989899bfea76cec623c6fb303efa143e056c5c26da022c3735333a3714eb5894219babca64595e7249167b562689ca5ca5e24e14c86bdf572849b20e858772c07e0abc93f6df35276e2e41174af2555e547dac26aa4b896f34c7a9932d54fbf757ec1d08f0d13359e19e8edbaa1aebb66a72e254e42c4a7082d67d09dc9a78e39b01724b4a6187fbe605e89238633eac0dbf4eac1027e0be37eec82791df8dacaf4e9b9568258e27ab555f89d4d469769df338d766bdf4bd66ecb5b4f0e4ccba820ade5fecd1d4a7b7f35fe1bbbc759b5e1944e897d633d2f008b1595be6909288817ba0626b3ffda7ac04c145dcab43b336335d4de01e5d60176dbe98568e1452cf1b7761aec2240c2ea9d033975cc68f5bfe6f1dae3ef2fd7015a3507939b38958068a041aba80f279ba15890d08a3aacccfb226fc203b484bd5d1a08530d85b5d8fe92178b76a82c59f4d96eaaabb671e1dc1ca9e68f51f510239a31ef2428810984f94e1ebca9f12e268d56a0fe201f1d6f5ac93b0e4ce88cb819ac007e717df74a990860635336c8bab3fef0478249fec211b4b814fb0797453fbf592099d3e9607ceec16e2b407185323b", "1eabac5af458b8082cd2459c0be4662242ea7f3469500d713a3607ff42dc77e4ae21faca820cfa98cc624a656e99c1c9d48d6d632e76d48a18d6a387094621132ad5d424eca73e2f893832d0efecf1235ba8a5d8ef9434123e02de1dcf771bab6b684c7cfd9f8de2b9a46438d5364441be9c6fe2428b300f1716d2c030aa863d85787336cb9f50cf28b6d91a31fafae258b2e455658e768f1d92f9e3e00ddfc52563d4c405a942d8c57627aa802920c995a2ac0c09c9f6807516619c1c21d70741e1d29e79cd1520b18060d6e99714734c16f36a8b9e22b0f14f6bf47fc6de80499bf73cc1692093ed17337dc375ab9905066ab0fbf0241e9f807c8c21a92050b093fd04bcc63649cee67cab117f36f9e9cd95e4cc8511b8df930e119e8c78600257c8e4e4c3c9a8c4366348cb68ea93a6a42f0c7c68344cdfb10fb5f249dc1afd44363b6b59261937e4d8a9a8e3bc380b7724734536f26ee88ca45a3b45f5e032bb220ea7d8bc4319a430f5d068fd53d4b1cb7d92c0f99e98898023bdd1fdb5cb4ed96efb3374402c263f54013fb86e9da0a1d568c80ed685c04bdcd56b421beba88c247dd64cbadc68913fb13b2ea1ed46ffbc80ea1d9812aa42a99b4be3eb215789b4d4bb1bda65641a950c4f0a6c72375fb9de413e87cfd33971c086add6ce8852a7898c57c3e98eaed24a1b38f96b5542ed62e45d07121e5d743c718a5d", "-1b708bfd0b9c4102b523dc9999a132bd92dda26a3fbb241ea451ffb3aa3de7c8a0e08a01a2bc8fa18322b51f22924507508b300cd5715efc2fb48de5fe705f555351886fe984229e33861417d9f805566b71c4f65f8356ad1167be15fc417bbca246c2637dd204296e0f0e5a192d2f309132dc887ce89c9812fae2ec8f523d4e8d2a8d8a6be04486ac1669596da1289e186dc74b9c537212a408300fbfc6b16000def7c2ae6d8340cdf345e058fedf445e3368d47f9677361e0c38233341c6593266bf74ba7c6ddecd958a981c676a9a488b9ba74796e0ad8cfad94213dbafa15b13660cc7e5f916f0b4ffed6f3327b0c2b9fbc1236cd9c469e01d6cbb0830369fc93258938bfddef9aa63c4623e7eb9d01edc41e9f12ebc2489292688e5ca43afe13035075402b60f93448405354d53d9b068464ae2e262bb1353b31fdc7bd328ffb080823513b35ff02a83207d2b2a295df46537f7c53fc6a639750a8f2a6bceeb918e7f1ca6835b5011ecf0ec84c411692e81258595cece170fc2230a524fac49ec22e3851d06a228acf43e29e664a931c1f8fc97cbefa49a3b07b7668ad40fcd5b29bfa3010f5d93f4aa117946ffe22d73b77652449f3ed98b86d25569480596995b74bc1112a55cdac7f96f0c071b8ee3be6f6a57f6f6fe63af7cbf9d7de40d05d8aca460f3179b3cab2d5f93a1234a9197983e01850b03233caec5822", .Okay}, + {.Sub, "-dfef9871b6d106a1eeaad28f2773e99be7b87cf7b410bedc72d680db2bfd4ce4f4d10748f3c38623da1c14bd21ce36329e0d30f3bc658b1c82d6d3b8fe0379c638b94b5d16eda9fc7d9ef3a7876e45feda6f9db98d5397cf7fc6368fff637e9dfbe9db99edb255c9c6961d8d448c8b8ff94ff0c016da456ec181d2cc71c0419519e303a6e69659a290056a263ff220960746be6bd54099f9f3e8cbe89cc7995261cb355e3af77dbdb925f006502074fc56a59dc95f26b52a24fc98892cceee4a8d78c3ca9e643d2a8c312d7408525728e519b994d3a1a44af5981119f3d7389aa092ca7be43cefa76824a0f45e0a39bcc38f6988eafe98349a424bf3ecd27f49948619238df0e319945ae775022b1313110b38600229fbf69482c2ccb0c539d781f7ae988c61fd742f00349dd0010cfc9eb42a4ed2a25b7b6c0c1359b83decdeaadb1f085ffeb0a0f47a257805cd1fc63ba5eac0680137b7502d9efd8f2a52378aa0d21b875d48fa53a7505cfe2caf2f7de797449eecac0d557238be12afd45acd32c0da59bd6c12609ff4d584665f1ce3ac4f6f83ab31f71c3cb6b03df6aa40d513314d7d8614ee19785e610f31631d02adebea23bf25309e0da024b3c4f9c1ea6c241592e9c93c2f287a91ebbe89b592ba946e26c24a04f114a545554ba1757295e3a685508e12d80947c1bb15732296583092e992b66fc3429e55fdc61cbc", "c0f556ed79dc37ea8a19c335670ef1153fa791df10279c32cac9a33077a3bbfe8f034bf435815667ff43654bf45e528412f01a75584c1deae0017e11a0c78b89dba1e7c0f4d122f9f4f2164ad6b1f5edb794d14e6ab5ea18d4c2ed0a732e8abedc90174dd0198470d9abf0e1cf968d43eb150dd63b9b57f81e001ecde6bc89d4d0fd239865210928a7c1e5bdca13f489f2f9c3ef85c1a17d5d7ec286609aed66fca288e31067802eaf79059430daf9667e6bb5c2d44c9e8cc63c6d1f8d3ab684995a558aaa2c7ae156c364d81f69d14bd9f23940133974017705adfbb9d69f926a6f1bfeb7693e8074d91e8f08ee8acfc63aac2b18e8c1d6f67df7da142ccce6adf3b6f31ff321c64fc3629a32f1f0338c99c8c15a8808e8fd8d9d2a4dda713df606f07d3d3bff662adebdf242b4998238d85142af7d079ed059c906898980bedd48405e3d3cd06b43b7e7e82bfd845823e98c8e0a8d9aeca9986c6c1ebbd1f0101d359516afb8b04c8f2324553b265ef4da240ec18c92a5f73344804873a0e8a9b8446cf694ce3de28e071f3bac30b8e85c0e14ebc33242e0f4e81465e5b415115f9c647c69f64cd908f2931976f663818dbed0aef8d99883d3402031bf12905833f012e0f2bb2a670dfbc2c7331ca79d1430f5e8aedbb5d641c22314ea8087089510459d2260f196ef99be5f40b879116ba2f06bf302070b8e7d72133ee12", "-ebfeede08e6eca20974c6ec27de4d8ad3bb2f615a513389f9f831b0e337788a4ddc13c08371b9b8a5a104b11e1141b5adf3c329b11ea4cfb30d6eb9a180ff27ed67369d9263abc2c1cee150c34d9655db5e8eace73fef6710d126560a6966749e9b2dd0ecab3ee10d430dc9b6185f4643801419d7a93faee4361d4b9502c0a3266f2d5e06ce86a351a8188821c935fdea6765aaacd9cb411c9c0b81102d14828d1955dec6bfdf5c0a41d805f932e2492be8c59258c6b7f12f1605f5b25a299b2d70e6923490704d8a19d63c18a48f43da2b8dd28d4d53b8b0d086bf9af74a293c739bc3bcfb3838f6f7232dd4e992269bff3144b9c8d245209aa2b718e154c17ff655492bff01535f9571d9ea55a321649d4d4ec17d27c85245b9c9f55a2e0eb61581da06035bd6a91ae207cf42c5694c241af62fd9a2bf55911afea20d684ea98afa30e43d27da7a8b5a3f6888cf80bbde4838948aa11661ac725c451160f568ba2a574d8c844855870428f438061956d3539858b057537b4e56d0617370e6957ce45212926b8f63ec8d5477821222872321050d267651b4a4c05318455058226292b13c54cb452e708ed8a40c8d2833ac6c7d72eaeb2ca264ad426b6e0eaeaefef6316c0f8f4eed5995a4e1831bb800c8bd77d854d37c04e78c167869a497de31f34aadf22b421f178415da1097eaa276eeac1f051e69033fb862d1efa0ace", .Okay}, + {.Sub, "-66ab9f307de190346d051b2ec9dc6da6d761764231ab487b609a42e664a6fbd1a7846dc8efea1099e6f355c493f7875f014610c63d1c94a04b67dfd21f543a8cd439141d50e6456d70cdd2c40f8f5ab1fa50a1c33215c00273b2b8945c9782f13af3fe7530a14a1cd8e5e9f410594a49ae49790630bc7f5e5377a41087428882fa23c2e3d6e65fb4a679e84b12208063c538dfef6f043376036f1b18a4cbf947d173309fb49ef6e9dd7ff5c7f8cbb432ca025ab3aff9b77630772bbf96c301d52ca94a993a3be652909b9be7051906a9c1950295761f624dcdc169ae09540a1f6d50e6c627bf90f365fdb6431207b97585ca240a1a2752ecf000f552fd3f5904b10bf08e141e5dfd8f90f73103088073f838452874a881a846a360450dad7398f2fa067adb64feeb413c130caa38caae50ba5e5e16ead193b4523c392932d7affa4e40b0533db90009b2b9c3ef2247fd9727a0fa50d60075872c72d23aa6fc79909446c0d42a8cf57864e1768d5600ab08ef32f586d42c024d2e823070ab9e024d4941a585a2acd45f1c1fa62c1dffee8821299f92acf38fa7f738ee8f260ccb1fd2b1c294bcdfe06e921c8e44b20907ddcb34771c9bfdfddb37ed366416906d4242b22c3671efcd71bb8d3acccca6201f2e88994a427ce47c15e4c0ba02997ba5add189ca6d92fa123a6fc9d7cbc58e1d8a7e2fdda7d7795cbf8757df200882", "9fa771031aef20a4956456e981dcc85ba16c216c61a33ae3154f2ce0b30a6f712b8e8500417782b002733b0a1931bc1e49be019dcdd5423fffbe086f40f2b2c8414e2abca5f1227ad03a3b3b303535f0e11e2fb7ae3f6c06537397bdd866f100de034146c910cc3ab34dee120749d99d5cc0775acfc0b0bc4e35f279307405630c5ecce96294edec036b508d5d88305953db1025619f36b8b9184c915631b349a879495b476189cd0ca0ba0145167e34860026cf6ffa4e3c13fa7a05442b6bc43bc82fdf83d51209a39c273bb88aeb0a0ac772e2a40fdd1d6eff86f2886feaaf790b43b03488c21a55dde390de3e6321634e56f3bb696f391823a7c52fa8480ee0af9391f640a9994b28cb4070a5743367cb9c9c320cd944adceee3fa5b2c5b0533298f8cf434f4022e99b4ae3b4f61cf2fc8b06b424b3b335f7f3db4ae9ae20b17f9c7ab4f20f4343c61b35fc3d9a9f30649174aad3eeab4255a646137d08aace2f6fa4424de2be99056557448d8066a7c52be97f9e50f0e89aeb8f9aea76f48a1d871bda3b6173c272a43a46bcb74abf472daea805774eab1885e4c166340233053b24737e516c6a85a0e2150bd934f3d57688e1ce00008d051161c9deb0a5a33b350fb76faa422bde470e7b2916d1c61479de45404a72493a7cab89a0782a9ef53e52bf0da13d44166611d3c2274fc80f8e14d1b74672792f9ffe27c48f04", "-10653103398d0b0d9026972184bb9360278cd97ae934e835e75e96fc717b16b42d312f2c931619349e96690cead29437d4b0412640af1d6e04b25e8416046ed5515873ed9f6d767e841080dff3fc490a2db6ed17ae0552c08c726505234fe73f218f73fbbf9b216578c33d80617a323e70b09f061007d301aa1ad9689b7b68de606828fcd397b4da0a9e538d86fa8b0bd1913f014d0a36a2ebc8767a9fafdac9179ec79fafc0080b6ea20afc93de23267500281831ff405b24471a5c4daee6d9968717a78be10f85c3437c322bda3f1b3cc5c75781a2f3f6b3cc0f0a091c3f4cee65c2a765c48530dbbdb99d3f0461c96e9187afdd590c22608249d182ce7a11391bb84200a5f0796dab9c27173adf4a76003e1c4a6b55aecf4724e84b3603949462c9f73aaa84e2b6425ae578dedc0cb43b6e964cb0f8546ea4a3014741c85d0abcddd2b082fc8434d78d4f9eb5fe29cc78c326efba9ef20c98219184e2405245ec3b66516786fb4116a46cdd1e38111b0b45edf06727cf335c96dc00b9614f6d766c8c15fde0e48218ec3e072dab7394768574e3ab26ade530fbed3508c40cd52d7ece7083b314cd917bd7059bde23cd1a0aafffe69fdfe683cfe982df54112e57de73bede19a0f9d99d44947f5bcf1e54302778f82c756c550616c43a311a644a30fdc897b34375650d5dbab8decdde59a0c44af5f1debd5ef275606e49786", .Okay}, + {.Sub, "49ac5d5774fd3c67e29900dde42823dca05519d91fc24364663eb02e6287e84cdb54d4ef378944845e2cbc3ceefce023f3fd52ffa6bebcb03ea570e7669651bf43dcfce5983698d33b94466d9064460b64495e59a76fc3c575c8d3934cbb04936aac8f34b6675369867651e5dd7542f2ce25a42d80472353500e7c1af71fa92025a4833a970e4c7896e7d7879c2b7660112720b439f53254943a4379e005b51c66b6105ab82d8204232d42f9bc2cb1ba287eae7bf71ec9a2bb932c72912fc8807a38eee52e0c48ea65200c8b6f51f6afd02a7d7807f703233794ea05d9ce420ef3e7ba58864d49061d0119229c7f5f233aae21888b75033a1bb99c555577092ac9207308a0f5db87fbda0592ef2db3191557ed3dbf5cbeca0bcfc4c586670c778d92304e47a1b40cb97eb353497848795bec7977f88b19b34bb4a6af2970bda08fa5ed785ee55dc0af0d266ff93f786313c2f7bc805eaa3f3440815409089b83fb594432b4517b95b2f1092716060ea8fc01da36b838bf97436b82c8042f7ae6b46e1887dd0386f1f26ff2c4998602d8f0cb3c02aeebcb58ef2c72581355457725a8369a7f7594ce4052e08dadb138ed5ac74f15649afd44e8972e96bdf0a1778f12c8f4f6de3e509e850d0c6268140bf658448b55426b683e0dae4230b0fc97405b83fa0df4d4c075a36e34bc544ebab066b49f68657061b11bb577da036c04", "2a32b079498e9a32b101a684c67334c84a15c2c03e9dce48832bbbbbe8cf3e5d2b2b94417f33c50ae359d0b067079d00dafe02d553be6a1e0118e3a6a97d644cb9632b4edec435d12757d4823a469a453835d3c95f4096cd05dbf80e0e9cb82e6c46d3a9fb60d7668d1550686a8e004c89c061bf03fa70753cf82ae09efb2d9e74fb6f4f49799313fd6313cef4d226b5c5629045c78111d52bd51ccd837cfd63cf9ae524a994518cd7473d834d3d43f174d56b545636d812d5fb87efcdfd0e71ce1100f93fcb1567a8b22ad411fe78d25fefb2b9fe53584b9d306fa997158e1c4d73d28232c0f661aa46a128789442b72631d7eedb5682140897f70a4d4dfb083c35a43dff147a838552334bb35785bb10adbacf18fb7e293eddeffeee515947041c5579d80b330f117e337639961aca907ef774309d7a2db24cd85368c0821b15338ee17571bc26d877edb26642c52ef0f8a1095fe8af8f5d3451a42eee2ca832292d05fcb4a86533c2eb3407c25ce105b85a8621c5ca4ac5836147445e093668be66fd67c512216403ee0d427b69a8cde07d36216561e3e09e8e8c6c74b0ed0b54d4489d4fea6841aa70957b60b0de7a7c2cc0cc3ae355f8e9c3bbec9e0f3205739d500ad4521dbf8270b3ae820c9bc7eaa4fbb0ab666adffa80b822f3c418ae1e72e9c169761e1e6665f27663c1179543188efb7c09eed31b1e666d34844a", "1f79acde2b6ea23531975a591db4ef14563f5718e124751be312f47279b8a9efb02940adb8557f797ad2eb8c87f5432318ff502a530052923d8c8d40bd18ed728a79d196b9726302143c71eb561dabc62c138a90482f2cf86fecdb853e1e4c64fe65bb8abb067c02f961017d72e742a64465426e7c4cb2de1316513a58247b81b0a913eb4d94b9649984c3b8a7594faa4bc4906e7274207f686526ac5c88b7b8971b2b360e9930774be605766eef6dc8b3a94327a0e7f18fe597a482c332ba0eac27edebee413382bc6de1b75d537ddd703acabe09a3aad79a647a5c42b8b3f2a673e7d6538c52a472ba77fa23eb1c6c147c4999b01e81261321a54b08290e228ceacecaa1e161047687d2473bd62d5e04aa326ea66140a0ccf1d4c69815b3308975dad46f9680fda8007fdd0fe22daecb6d8203c7ed9f859967ce5bc0b03b857a725e96e973a199d69538bd92fcb33422ca56b32075faafd70c2fafda1a6edbc930172cb79cd3307f2e1df30e43b1c7f6497fb09672f54c7de82180bfd171b04bafb18a753e74d08e6c04b7570a993022eabecc8d8669750e8de3cba6e0948a1a536251e225aa65fea86ff83250880ee04b2254986019eeefad6adad1529245899f2ba4ec09ec32df029c58b3e607702e6d9f8fa49704fd5e132d8a0dbd387e923d11104c8b5ea2573d084245f08da31b239c106ce96672de0097116ccee7ba", .Okay}, + {.Sub, "-bb0cd04edad39f1954aaf1d5fd35106e6b74defa572b92eb9cb2bccbcc4e77778e4781662f23e949e1bcf92cdbc3a60b10124d1818d542d674f4b2e6ba6f529d5ab125a1b10273f14939ee73f6671701caafc9afa14ec3c1b6eafebd6eb011a31c5ea070ad7380ca3b7df54fe5077624929fe8dc38159286ba4791e2b4092718da879526246665f9f61314267ac95ec78747cb4e4036ecacfdb590b8552772150f945727de1c3c0b0703a827ecf9dc94925606717ec620b0c77aa6880471558c96f49aa258c814ededd0ac4e2257004fe861fd3ba67e546f574170519dc61980bed9f28e0f653d21e5280419e470e35a1851f04a852d1d9ff570b38d5d36e1aebfb48a8eb41eb25aa13479790558a26dd90f4dfedd1521d3633045cbea3e4b77af8bc3ab216efdb9cfaf683b34274c00c4162450d6881b2ef1d106530e72780178931a15f73a98e68435e99ab36cef54e4f63a643a1ae7faa2df5242cbb455e117987ac0db02161f42f29b8642048c70937390e781756e4c194eccf748a3de90e85a03559b7e89b2ea0a62e8b4c37bd0e8d8493da6938e933136778e9b2b840ab6d9a1459cfcb332c783a99e0a9a3cde2193631c3554d0f58520f3088304b50384da9b03cec43ed22373be5044697ebaea4de69a9177d7e0f1b85c3331329ae87686e2a04d841abab561f27f22671fbcf63d4b1d82aa222bdd63fb444afcd086", "59232fddfb0f7f2677ed8a3d814c9e1e560a8d91a0b6acf45ec2cad66f31aca5ed9a5f64d60bb8e7c452e5e07459cb22b377b97d630b1442d667e5f1aaf282b688a0aa8d09c1d0f73ed4e45c70c635864a16d1f5b15d6d3b1af463ad8e0a018223f2a9d375613d51f6f9fd1b7014bce2a2824281c8d0ca05449b5e4d5096799b456e4c732c582cffdcb1d8185a3364e503e527bcb01f051499c76203bc510e775f2c5ef3f79c04001be0ec3bdaa8ef80d2d02893db2e9f50a28353ad53aca8e3ffa6e4791827135d4168659e8ed89e5237539d291bdd6d4741db470cfec1a0a70edbfb3919938947fa5dc664f1f84b5b6c1b042b35766cf634c7beacdbe3879cb7bada3d5c6e33639a6a8447f15e97962cd403ab201199983d79b3e613ea19d4de0ccf60afe02b1063140f1a70db9ef9ccce8d0d30f22095c63465511fa994ab6ee4955dbd986c03912301251b9f1e137ac61abd56e9089ff708f9d1691a94845cef4c4906a4de9ecc8a2ec88d1e53db01832fbac118f3711f78d280650bd61d93db22848fa0b4a7ba1cb918050fce5a8ceabd54a9906b167e297026dfd0b06ea659c5bf7561f3813db364b71fc6b4f2f5cdca8ead6c7647d9afe40d9b70b370790f942d6e3b6f35f9080e64224b3e2b80aae75fe9df2911a3dccd57044fff03ce0eb99855e9a03218d9077163e7502e983d3fbbd7738cedac3e03b5c40876c3", "-11430002cd5e31e3fcc987c137e81ae8cc17f6c8bf7e23fdffb7587a23b80241d7be1e0cb052fa231a60fdf0d501d712dc38a06957be057194b5c98d86561d553e351d02ebac444e8880ed2d0672d4c8814c69ba552ac30fcd1df626afcba132540514a4422d4be1c3277f26b551c330735222b5e00e65c8bfee2f030049fa0b41ff5e19950be92f9d2c4ec3ed4fcc3ac8b2cf30af055f1c1977cf2bc1178808c6ec0b61bd5b8400b22e49463c7a2cc1565262f0559f4c00169fdfa35581dfe70969b7f1b70ef284b2f3911ecb12f9ea21fb59a64c25bc1b6991cb75e9c87ba27cdb5edc728f8c669df85ca7ed6692eb5846cf475baa38a962a38723a391a694b776f64cc108ce5be3b9efdc0f6b73a0405e351a9fd26bb6ba0a9f9b1fe28654c8d98930bd14f28ca32c37755a502eafa90e4b15e077a3bc4b8056ba42e1c0cace777af73b4d304ea1558eabfcf0c0d685fbc55219103f09a99e84c1434ceea657487c709e1a6f4be0f7cca4ecf22e04b94f6c0a2428e61bd38c79f77adafb4ae7c3525da2b1f3e5aa4271c00b9d34a2b75c306925023f9a9af5fe7b57afc34795d336705125ea6b405370e552a60f1d117612daae2c1473d5ed0d7161e756873fdea2f313cffae081c7bccb466b4bce66af8cdfa7b5700f29595298a358299ec44959c38a36dbaecce3af9f0864e6feb8e7a8ad95a1daf1989a1fefa0f054749", .Okay}, + {.Sub, "e0eff9ac67ec9d0b2171bf8659c7c06a1d6b96e847884a046cb1d0de4204a2d5d71204da36b7f37579f462c3d81041838293ad9306df1b98caca3f3e011d0fa523f49419bd6215c3d57cdf6e8e9ed5a95e0bc5d0726c5329761fd2869d811236e5873bd3c178f91ed70997bc962b5f50bb14f6805c8dacc2cf871dbc72cff5425ff18f3dbd1976125d56dbfa22ae0301f562bc6ed2014f219365473c30117c34c24864c1645e32c3de57c1de4bcfad895355c7fce0ebb809cbaae88530cb5df4c5389ce34180553807f91c2f40145dab2ac6b6c2af2cd4bfaf49014d2b8ddc532bd22774fc129a7f7d9a2c1e8de96269f2a38e9b385af3ef446417d683a3fe9db4a877917c190b7952f442aa0a03aeab3daf6ec05a7d8d107f546424661f45ff4d11aad2a124893b926847881d57c101559d7a0c34412a0f4f0a2a1f40c700035eafa8e949ecbc84b652561da9cc3e098035061283f5aaa549f6c8bcd6f4f267d481c792fea81572014e1b0ccf92aa5d87a3a3afe07b7df87218bb1f605941837ea1fb6f366f5fe43fb6d243d82366b36109a47e580df4a9ecc914fce430755c9677aa29ef708be91396191df7a484b3c3ec4bfe4dd83df61bf5067bb3687c32f149e69c82c36bab67bcc6906d255459807ed779a5aa0a931d31c70c8ca166addcce1ff767252d704731c5613af045fbf5d10beeea9e292ae9a1b0f8a306ad54", "9c20483e6c4b19d529719394938a18c769815e11795937783adf4b28d0517046259874ea84ff38fc461cefe53afa5544b0fcf4dd82c3ab3b84f560fe1a9587b6de2b21c458042d914dae374d356a49ef8e37b70ce2726483363913fff859c501f8e590923a6a413746783da8d5d480a74ac1e1cf2174208550a6788c57837ff356d14443170b8abe3ff5407d742c57450636a54f991d31e453570b57d6a604a37576ba78a1c7854bd5363c012c767964ed7bda6c8e0e24f812414b016edcd42ce7a4b0da56c9c196e6363d53dc2ba7697756a09fc9d604f8bcedd21751c323f6a92c8b44bf65928427823b56ac2f2d94ac9d8b566edc0ac4d3264052a0fd775f03164e60f4425a63d4926c4d843d8a989b1b1b4c2da1d2c5b87b1b0c2d030b765ffd8c35422aaaed6d95828495c57177a7c871e6895d22f59efcff011851c6ba66ead1f86a023889d56ad29db6129a9caef25bfef1d8bc633988e3e6104063af41867692529a76e03ab2f2db1c8591817477dc60d9bfbdfc75b88edd6cb0f478112233c4b203e8c7619eafb48b116837e1faa91047cd812ecab480e81bec2f1d5e921460719b8d8fb7e23370d88b75a00635d14ddc145972e93673d512707e1ea186c22952128357b058f6ba3fc5db531942c24309372286af12f2841b0e94b60f4fb9c265fe3a0dfb6b66b17f8e2b90aab261819e3018b0f14c816d47c1974", "d72df5288127eb6dcedaa64d108f1edda6d381072ff2b68ce903dc2bb4ff8bd174b87d8b8e67ffe5b59293c584609c2f3783de452eb2e0e5127ae92e1f73b729b611e1fd77e1d2eac0a1fbf9bb48310a65284a5fa4452ce142bc41469dfb75e6c5f8e2ca9dd2550b62a213e208ce17464668d8636a766aba7a7cb633ad57bd432a847af98ba8bd66795787f24b6b3d8da4ff5219d86f7c034e2fd686b2a71bea8af0f919da41ba6f21045e1e390845f3047e0a56180ad5ba4a86d3d519dd90b1f6be51d59c13b91e9995b85a0251a33493514cb8b28f7470237a242bb671aa13c13f5ec0b01c41573b22086923266f90a7d9b5e5d16d3342f731b3d159942727c47712ab6cd4e5d315ab1be531bfd601b3fdbd0b97a36fe423ccb273a34f1547e711d20f4d01de8cbb8eef5fd3fb69e9db20f2edcbab57dff51a5a2f2f41e397b840fbc9c34c98fc18fba8f3ce6b145fb545e05294d81edf165e3a7e75f0ec2ce0696029d97e6e03fda2ebdf1dca5145705c25e9d2df8218aabd3231898e323bfd8fd832eb4f2157c99ce7488f72502fe2e9f9ed53911c97001dccee6271b26ac08e88e3e856d3101817f5e6ea1bcd59c388eee97016f85eed619f3e6241745107317a79eda24375ecb73724c928f6a44eeaab557516986ab24097e44af07d627bd9245b40c549cf677b0ef622f76342eb25e5d6d0bb279fda8ce8e1ce8a93e0", .Okay}, + {.Sub, "-da301b1d0027f699329165124ed8ca8402f899350de52460d47478b2ad38518c69c6aba8445a14be95f03c87a73a0f1c5a1437f06f5cb3b1484736eb81494c7d55887f6c6c39dc277db9751356b136675c195696796b2d5012d820d80cf0a03dfd85f203ddea5d3d73f1e1cdf291be61273fb387321134b54dcb0bfde5a29a991ae584bac11bcbe4113f7494c9fc68ae2f3e3d0fab9acb4f7e0135182b57342e33d8a1860b05c3f7898bdb75973bdfdc940700549956f18460571093b0c7e34203d436c307d0f5a3c484a82f24590175c69da5a9a505b4083b07bf7374852e5393aa2d79027cc93d4d16ac929e08caa6a1ad6efa2b7b54af1d8423da4288b1440f8278e8fa8a8668a83284e2ce42ea577da0137936161ed9fd818b273fca8bd8fd8323fe181616cfec20bb7830a6ed843677d391dd214ca1b7da36999e2a77d97ab6c04681d3f41368e308043afe8572b10666924fbde24fa9030818cdfb26134b5facb7dd6bab62b93ddac365c0b38cca3d25a3ab40fe27b6ee64b9bee35c6da08a664b07f21661db27944b8054a0278d374678bb97a16f102d6da7e50024be04166c901e47cda1a1035c24ac4f9b90b11bc29cf410292680efda440cf59c555224758e48e355b4faf338fd66731d47d6b373523d151f2877a91a93970a922f0e62ea4981e2c2f6e03830f32b3d9a79ee556ca15ccc7713b0a06b001833a9c9", "200492eec73958992318002a4f2c8ad0435a109aec8a61ce62ba6cbbb0d3def8dd8c0360b6f17a0381e311ca7c0f59f02e9dbc81f54cdc1a0e7abf50066740159d6d36a642561adbd3d6eb81218f02cc9ee2a3ddf45a13cf9d5cb512d58d0d28d3e957de1a8b13f7093f48a04fec33e0ea35eb643fff4dae3f17081bafcbe393cbc714a359732d12aafb31703a2e4432858d665d4cdc1159deb28503563949e3007192e931cc3e1a9144589ed734f684bb47060cea6c59b8b7d4ab64e216b1fa2f3abf53b96dc9fcc7740f4616e048bac9121eef6ddf9c53a00e7a4ff75799268a0f4f0c4d9e1607ccbb89f3bd88a013bd917895a93dd7967a4776cb7790a4c81f67df3f2af3cb1473e43ecb521ee9d0549057a1a6ab25ce31d9332dbe64dafb2d1c6f52a7b1ee34e4470b8e0be5cd7eafd1b3c4e901562001d0236d902f1ce7dc5dcbbfd9bdec174b80283ae02b6a08343d0a15c6e4b107667e7987ae30fde725a7802a49e3525c2f6ec6dfbefdf1fb018b2d8e9aaec1f7748efebaf2a7a17b74a252a39f45324ce36aca2fe27c3e466a6476b45b827c06938d8885ed6d84de01390f2a033c34b0e26fe57a67e552000e5e1799e97daa0ddb09a2a35bad75e70190a3264c2716270b3a240ad118582a9ed0b6c2dcd14eaead6bdff261f8bb042b6b96149301518f54acc685bee96513bfd4f87bf4b86f2209b63faacd6f1f2", "-dc30644bec9b8c22c4c2e514f3cb9331072e3a3ebcadca7dbaa01f7e68458f7bf79f6bde4fc92c5ece0e6da44efb04bb5cfe13b88eb18172e92ee2e081afc07eaf5f52d6d05f3dd53af6e3cb68ca2694260780d458b0ce8d0cadec293a4971108ac48781bf930e7ce485d657f790819f35e3123d7611299031bc7c7fa09f58d257a1f604f6b2feb53bef27abcd9f4cf15797137580688c651bec5d6860bac8cc63dfbab49e2287d932a020ff84af2f44dfbb70b567fdb71febd45b49fee94e61a6c7e2b84367d24390fbe92385c70601732ec7989be3adcd7508a71873faa7e5fc4b2269c756aa9dc9e26531d9e154a7dd868683860f322885289b46fa01bb909178f6dced39c319ef70c8cf8364d8f482e918f35080d136e09f1e5a1bb0d988b054eaf3429135b33a652c3111654a5c2174eece2bb16203b7f738d0772d69a7f87c9d027f6fd2d4dd9b0a87e9013c13344a3733ac2c2d601f6aefb148de35f1bdba24ba8209e0887c34c73161b092ac7a55d87c94ebea472e3754a56e0dd68557d48b7541e66986a95e40ee7e7c640bf3dd8de4014fc92f7966463043d6fd0be429fd82be7b90ecaf2a5a7c52cdf0b0b201a41692a803c75ea0746e42b073b3c23d7fc0ada5c7176ba6db3e1384a2ca80a07ebe6ae23413627fd892bd2a1ddf5119a3aacb12d80fd582fd5b872c30cb2a52bc291c17fe05d13bcefac50a9bbb", .Okay}, + {.Sub, "-d26953349b43ec19e5c990688798f7b7ab4f8ae8c9358cf648e48d4038fda351314347230372c29c11ce744509e72080dc9b6d9f3c3200dd100eb7b90d41523cb7c05647fe9e57fb09233b4fffaabeae2e7bdf7fa57f02c20fd22bc2bd920a945fb61fcca9c840b9593bb101b8b6e19a44c1e10e267b929871d2329c3ee3c5bec2ed5ee749f848448a030ed2bebcf74987bf56623d1ebc7492dfca5bdbaf2741a689fc02f7bb712848340d9c893deaca4ebad9be91823ab94e24e6054b6f91bcb7b5fc24d478bac1b2845e8f8de3e6548e9486827e96461e2aad904215e4978cb4c38e7087db22c5bb78b14f21a72dccb8b428ada9fc4efc56c6ab168f49a009ccc360be455f743cbcc22a41d04224d62a2b5fd4f249a5bcd65d3a02c20f7951e72af8e0c08c27396ffbbe981912b54058856801c270c24d9d50657c6477be323bb43556d58b3f187ec258b776c3fed7f83ea089e8c0cce675af43882cc99cfd0913e55867e84cbbabaa12110bf02a395c420d81b86a25bb9e0f89c1b26889106da70d8af84860e166dd87cef89058e750868cdb5fdcffea38f8173e51bb7044daad21e661d3a8f2d30170b37ce2cf08f0d750049b89dadce3f444b3ec5e98bc256e76392a691649ce05de9fe2479233eab913a3b2a93bcb0e8f9b6a51c59c95e6210fc96c0f8847090460889dbdd04690d92bdc52b75832358568e6835f3668", "a779fb5329f2a52e971217ed3fa069820e93a547f02f326a20ce3dc6f0a4b4e26e8f6b6c143c06f320184ee48a6d1111a04adcb5b497563ef0d913983b256bb9fd2ee248f528269f14a2c33be9c495723b561cd1af633db430bb76643355679ef7ef60e28689ca08965aa29efb3ccf40fb71a0ef0b721203f69ca7e8a1e0ea8ea06dd6eeac8340c9173ada04e386c178d9ac9656aa38facf28ff82a373b5f4132d00a7f4a4a73b01da637be3764b260907798296216afd653ff967cbad2c6333a6fe454882d3bce377ff3bfda81aba99c665d8f53249df94830d97c382a52b959f2c444bdaf1a2a3266768f76c34b011751e7890bb2ade1d0aaf795e32b1cd6cafe86fbb332955b6efb8ab4b0f9b721d4df2f79aab14452ca28d19d0922efc2dfbc0d873f5294b17fa0c6f51ba2a59104a8263d29766eb720dfba611203c53ee79e5e6e73bb21b431184c030923316ddeeb154e2757308d9b3d156c3b781f62684a8dce144981f8b859db7077234c61fada28465085580965ea9c8df411e5b908b31daf1c70d6e5b08cd0f17cfaf98a42875cadbf891eaff908c22ed8f898ae0e6f1b3c5351bf607e61aee120daef2ef260ddef12350bc9a2808153b6ed01421d8fc32286d588fad691867cec80a02a5ea9cf988433bb607b77cef999ede502218cfd20b0de3ca3c3e997f5b342f8731bfab7cc7bc9e15398e883a5527b1dd38", "-179e34e87c53691487cdba855c7396139b9e33030b964bf6069b2cb0729a258339fd2b28f17aec98f31e6c329945431927ce64a54f0c9571c00e7cb514866bdf6b4ef3890f3c67e9a1dc5fe8be96f542069d1fc5154e24076408da226f0e7723357a580af30520ac1ef9653a0b3f3b0db403381fd31eda49c686eda84e0c4b04d635b35d5f67b890da13de8d7a243b8c2616becb8e757b743bbdf4cff4f651b54d38aa3f79c62ac2a2297897fff8910d356345c54b2ed381e8e1e4dd0f89bf4f05eb4416d574c77a52a839a8d35fea0ee54fa5f77b0e025b2adbb28059889c32253efd2bc62ccc568e1e01a468ddbddde2dd2a13e65272d1961762474c1fb6d767cabd0797888c9f3ac7ad58cdfdd96f3781e576f9d5deae978ea53d3543e757fe2ebd154b5b572516a082de9d33d0e50a307cbd459d7adbfab4c0b8d84b41220b59a1c3e113d5a5b904718e808f715b5e6eff56c5e33d5c029809a4be44b93238dbcc239ac806c473147c9187e24f05909e491e6c0bfa651fcb952a0f386e4a0f8d8e87cbf55cf3c6faa96e6c83ff18b78fc57b7586eeae9c9843a2be144fb25c19ed5ab96ef9efab91c5ec58a91c1f816e52ef5beda97770bfc59ef5b2eacddfe6aa86197c1a5f7371e466eaa5194d9d5560d2bf5e4f1d2c60c8b03f0a3ecb7fef0e1d479f35283479ddfe3d1ed57785084a8a40f556d6bc40da33bab1113a0", .Okay}, + {.Sub, "730fdcd434d67519314ad2a60daed3177ef3e9ac91e0daa8c37335b05546ea1abd5cd13cc0b61c80d8cd86ea145c768bba52683f6ceb644eb8a17cea5975c595b674e47e7898e43b4fe6b05a1db1c4d9a6a64bc23cded4e02648609a66189593c5a80ea5a62f63c0a5ef8ddb8a830d53ea8edd6e34fe7e1c62f7b49c90fd442565903adc061bb63647c6cb43ab89fd6986522d49215b8864f8598d908c0789117a79faf5537be968bf09b3aa86b401e98aa7ab9beb7f60018c4b3a73915d8ed04a9184187d5c1ae7bb6c745e3c4ef0ff8af986c421dea41aeaec1d31f3d094fb87582f367070eabb7aab2ec1eab6677589bb4825119da9b9f4f13997bad419e97e99cd6074bd1b1c60101806c113d9ae83ba84ef6dc5d210f3955664fbb000a20c0ed7ced0c7b6e25d72ee82e45efb0c3806cf3ae42558e5bdafa6af9da4d1118f316364ed6557296573934ff62937ec8efb07f9c81900fcf3cf097d35523eccc8a4c424fe3ccfdfa57c60d005b19404496e20b5ce938dc016d1252e36131fad351beb0893257b682ff9fd1b226f3bce6d443e2022581d8e3f5f01231cba7a0aa43070a327d5e377e4027c0a0dfd69ff43ee039e6f7d24c5039cd994bbc73758093f00161664835af7306c7bf3f6ed4b8c945e5b83f4c88691683e3943a5743e29dc9eefa4eb62a1de1d5b87cd29b47681c70bb41679e9bf06ffa02212b5a839", "af46a95c7999a3c3e28ca7ba2958709dc25f571691c9be859fa125534ab9f8d86b30c2e6ed7c5d7f60b69eb560f37ff7ddf10c7d4856469e2ecd85ece31b46eb717df767b1d371d789ee2fe59a6f0fd98cfc9d0f09b376f5c50f5abf8849b856cff7f6fedc2e23d787cd28daa37b10a19eba52478560e917bfc0fd79d04a5d4b7fa4318d88754143e537dcef18d617e7b97946eac1e15feba7d2c6f877f73dcce843c28e7ee08db6d38ddcb43547d7e446e4739582ae912bafa15fed11f238a0561a048f542dc92549796b650fecdfc2103ca153be33589ddc9ae1e02dd45f3243e3272126c89d16562ee51a63e7affa459e5108c19af2c62495cb73c6b1ec799409297be16ba9418a421dded3043612a9de183702a7d08b7cdb736d8d27b072c559508825ae1d5667376936bd40b569aa633b61add3eb5c426cb24588facb1617db71fa8a8d3a8e01e910ed33dc1fb6d2c0ef274bb05597ed0180333278264417b2240eae8aec851b72a9bd1c91897e3effaa9f1733c0cd7c92be2df83e4d9d20d8d3c94529299b564ab50778c69cfddf868621ab5776dba37a110b3ead269afa561174360b97b2eb8f2390db15352ee45321713498ac4dee9072c0661462c0421940d6c62cc955491868e9fb6d53bc581a9a742875799519532318f842325f24e2ab96599f901a883a4cca0f274fa897c0bb6de0c4bc417a9d66f65d051bfd", "-3c36cc8844c32eaab141d5141ba99d86436b6d69ffe8e3dcdc2defa2f5730ebdadd3f1aa2cc640fe87e917cb4c97096c239ea43ddb6ae24f762c090289a58155bb0912e9393a8d9c3a077f8b7cbd4affe656514cccd4a2159ec6fa25223122c30a4fe85935fec016e1dd9aff18f8034db42b74d950626afb5cc948dd3f4d19261a13f6b182598b0d9d7111ab6d4c1a7e332719a1a085d786af793967ebefb4bb6dc9c7992b64a44e14842909ae93d5fabc3cc7f9972f312a235625798094a9d00b888076d6d1ae3d8e0cf706d39deec285431a8f9c54b482f1aec4ae3a03ca36bc8af7eab657b25adb83b65879314884bbe308e3affd490c2fa491dc0bddd290156f5c1b6cae8e252a3205d811f05c642623934794e1fe7a89461d089177afd0b94a78b954e6667409c47ab3d8e1ba5d725c6c26c9ae927684bd0b95eb55fa0488aa0e959d27e3649c757d9d3db2e7ca43c5e72d8397549af93276b5fd25e7774f0d5fe9b04e1ca575f648ed16dff579f59189e948a0330d65c198ffc22b2defebbce8c0b203ae332650b7ec5657612f7242480188ff594d641b0fe821f2ac905625a0d10e35b43b078ca786cd17cb2fa0651dd2c51b8788eaf3992baa4d2b6838da40c0afc845fa51e7fc6e07766670cb863c18a480b10e87eae4dfb49cbe20fb060ca6b4b42d78aa1cf14241fd9b3215f9afb9ca4ad282739dc6d44a4f73c4", .Okay}, + {.Sub, "db1b7e09807ac58fba833aed1d4c2e568c1e7171b62b1b9d96e55ec88249a443e81ab32472bd83a696f30f014ba72c99067b7a8797617f7817e58e03f3d670b70fbc29f61b7081b7a861cbba608581a0c4cc5de544d9b9e7e40a759b70fc4ad1f6996076481a9deed9e223e28ae542d33e007a2ea6fd23da00cccec101760f39f9b30e338ed398c66b5c185a85830e14972bef88fa560f08546b6ee6097593e6938365d68a385b52027d9fd93c605d4bfdcf32b6b5447fb1015bfd58cea4d6cb71157de9ece00f0d995277afcd3ee85949494cc89cdc2d72768a1b327eac9495ebe4ad08a511bb33c0f71cfa936f9201b8c8572d22f2adae9fea723f4613d5a55bfe39c02f2d8137414e2c522c4cb0e8677093a9da83d5e8c63ac10dcd8e27e6982ec9247a6ace63ff20839cfc0a8d8bd61076bb450c008708085b53ee90cc2755a060296c824b0f6ba7f782f2e42715807782abb0b33988c8b0e435344ea785b571907a26feeba68f901133efcda220e556a6bce1eba55fe3d8491436235b152152528d94e34b757b3c9ccd22f329d7dc84cef868415255ca458dd5b60fc7792268a4a319cc21b3db21359052e999d872b118dc3d2697352791fde941e078b8100065af72a8fa8f7eb0067a7b6013bf9485df365902d8a85a6056dae9f6404cf51256016a73d09f55b6e93d59a02500528cb9d48ddb4a5c7b0231f3f597e787", "d01a1aa75f1491d3442a3da40fa000651b92f93ce385048d4983a6c3f371587aa86c6def801b281f1519de850970f6d7f7a74746f9cd2c4ff919209ca9dacc613aab5ced297a73b1eac03ff0e03076f304fedea4989c0b4372537ec9b74b1bfcb5016d1c08057cddcbc6689e790ca3bae249957bc7ecbd6f81b7ed041a10c23d086180a9913801cb85def227c3a7a98bc4789f6b8cba9bba6b47dfde1b494f5b4cbf7f815be97660286fee0bd62e802195e7bb328908372e3945ec50cb92a468962ff970398c0e5f992fe767e818f7c51803911ad2b612c047353622741f309aeadc9fa788508dba05ed657614fca1634e49bacc02f6e41f0e84c2cf81d51b8e3a8c00909720f6cee006b44e8487b1e96b5b07c18c0e8ab6164cc8d1dee4d74fa634ae9ed2766dfbf7c002945cd7778c32c6646c48b85f823839a6eab2af480ca7fcd24792f185779e651d19ed93ea40d302af9bdea7c0dd8dabcf933b256c0e016e67a21756bd1bee97fa9dcae3820c3830c02b639d9218e551f4ac5ee2a92206abdb9c26c72760a491082912e669517cf393f35bbdb2ad206f09f3676cb7cb48e4d38e96c1017001bb18ffb9abb3ed6f4334dfc7fe706f51884df9491ef62f68a0dcee3dde0fc5db11ff84e233edc09ed82de7cf6efa92b492424bf94fba8080354ee02798e29df6df113b9b285f1d7dc6b45117f1ac722b9644594d3bcfbd", "b016362216633bc7658fd490dac2df1708b7834d2a617104d61b8048ed84bc93fae4534f2a25b8781d9307c423635c10ed433409d9453281ecc6d6749fba455d510cd08f1f60e05bda18bc980550aadbfcd7f40ac3daea471b6f6d1b9b12ed54197f35a401521110e1bbb4411d89f185bb6e4b2df10666a7f14e1bce7654cfcf1518d89fd9b96fae57d2632c1db6488d2b3501d6d9b734de9238f07ee2c448b46c3e6552e4ee4f1da0db1cd6631dd2a67e777842c3c4882c816110803123262dae58479b35400ae00229047e525f0943145bbadca261ab22f54e5100a8d63fb01080d611cc12d79bb09b7847e72f09e6a7e9c611ffbc98f9165af6fc43eba172172392f980c8a6861477803a7c4fefefc158be84e754b32afedf83beea95096f1fa1a85a7f46068076081089f3315ffa34a124efc53a104cfceb4693be1841aada38de1d990c597cd42da6905503cd4ad74d30fd20b78ab3b0514a1f9293b77b40328d80fa82e8aa0f8169624ea2014ad25e6917e4e1346fe865467d740b1f31aa676f16e1c2414d6ab94a4100cc0865f913b050c839fa8a9d683e24ea30fadd983d114830b2043d9661c90993de5eb036de3fc752826c5d609afeff8c18288a75f88c134caeac9a39e06f5992c25fef5adb14e8993de15a5ce148ef0a685cc74dd072142daee015ed7d801be77c5e2d4c6058375e99dea4f6bed9aa85c17ca", .Okay}, + {.Sub, "-65029e63f44f392514b2090aab6fa5914614036f68941f579ba77c80c8df371728ac97f962f06da2f7d6999efa268d84b2dbae5bc5d434546677ff50fdce71c09c1f0af317b86cb7f4261aad7e25f9fa030e6a84102a0c539386f0a535c15ae6125795bab8b8e4e9a3050624413c1a40414fe1422d1dafb116dea92a78a37b6b8947960d2aa09ff0da6a6d4b1424b7096a7dfe75ed0c2cb6d20b37ab66583ffe71e0d4f755fdb6b68191b9533d6b8e2481d20dccd45537a8549ec30253e8e6050b6de3886dc4fcf7ebf28bb91f971a5d8093e41c05ac9c7282ffd2347bbd1703fb4c4f35c4d5ea051aa623aa37f486756ba9f0f6eab08fa647bb12f13dfe7931d79c77bb37850ede8d058c382d5e531bb2709ca621725144a0f62e087c86fa9aaf469137a2ac8b4064191a84a459fa8f4755dff5c48ee202e00e8618866dfe61685d678d1fdc3705f75882c36eb269108e6bb571086506bc8a4a1f677e055b4e81d0e9edc99ba732d42ce74a142f938f2efc521c500ecd18150f55c24a33050a766a95060dc619bb57822200e0ae31f25332569f2fefc9b44c99b70d0fb20e5240ae7635babf1ae766d8d564bf6ef0abdd29b9a0dcb2a4507a8ad4c9e57a675eb58b7f3dd1b34a34b3e47f75572828a1d620c02d55a219beffb905fe44465351243997b06f4177bf0c0a03fbe6721b3e5c0b220018fb1b31ebb8d6e67a239296", "d6b8cc52c70479074a5f72b88eaa07f7a9d0cb38f4326e09a7e98b20188e7e2eb0b868fe15c520361477aa37e1ad1eff732601d110ae3cdcae270fa20eb06871fc9a07f1f580068416b4df154f20986250c263f3e02f23af874af0c9c7e9171b3873bd2c512eb2c05f2309f764b119699fd5c6f774844fd37cc8798468aeacb6b2477fe2ba524269e38ca6293bd687633395c4de55bf925990a720954b3259f62ef0c91cb133abc20e5d011f720e2ccc95147d63839ebf33ee3aa63f58d847811dc4bafa67838501fedb87827f6123830cbcedc01bc68ea07646526eeaca7c30c2c076e321de0e03fc5ba5cb96583666275646e3d90309dfae6cc199ae6d130910595ea8d80ac415564f18d2598147a92c78114aefd41c2fc4d6ea8186fa575e0020f7a52d79f5472de5a2cc445dd7ef51a6a777445de631c09e13fd69c96012fb99f13653823279d9925b38d16fd4e1e9993c6f17404f31d9e355cf415f4c24e398d5529382ba57eef3e1a7316151f614c7bf6afbbd81c8f86792b660dae34fed0bfb98b34246857499608c87c41866dd47dc09a262b2a92813099abf20e2b7c6c0fa4d10a174f65c0e350ecda39a198d4a7235e4b73f24c96106cfd8927c7c97736ec0220d6ce9b0b49415d1222c50e532e465907315438fdde5e0c2601363a6d7c5bd9e4ee7c787751fb554d11dfe2ce54fb2f6d4917da24050b68b4329a9", "-13bbb6ab6bb53b22c5f117bc33a19ad88efe4cea85cc68d61439107a0e16db545d96500f778b58dd90c4e43d6dbd3ac842601b02cd6827131149f0ef30c7eda3298b912e50d38733c0adaf9c2cd46925c53d0ce77f05930031ad1e16efdaa72014acb52e709e797aa0228101ba5ed33a9e125a839a1a1ff8493a722aee15228223b8f15efe4f2e25abdf713744ffb3e6c9e13c35442cbbf1062b25840b18a99f4a0d19e14073162788feeba72af79baf116e68b3057f3f6dc42d96941acc12d8629329e82d54881f9eace133b9ef83de08d50d1dc21732b12f94624a366879334be0cc618e6b3f8091701c975ce4cbcdb930037dac3b39985f627d48aec6b8c3ae7f5d6640f8fd2f3e354a50a86df9ac4dee8adf111466d7465cd188a038151f8af6788dcd026808791febd50e8b7d27e98fc876d08ecc834a0ac9a15f0375e7463f758c3735e697fd0eaddfc40223df27804f1e01fa555ee642d7536bf64a7736569bf405d1e618ac320c8f14590e58543c411874bcc4ee10d76e878ab0de85a6376909ec1086040cc1b828d68724a59307a32a8d2527c5d74acc0a7ced2f10a076f7082cb608fddc2e70a738d128ac56a742bd6c169e37543ebdb99be0ce3db4cfeedfdf3c0b71e6499138b284a54f2bb53a492e6152f028f96ebdf06a666b4cb115d6e0d905f86937f23b13b43393c88f071b30fcfacaf8df9279d0566bc3f", .Okay}, + {.Sub, "-3ff359934570999c6c6b9a6cb15140ba86e59e8c2aaf7ae7100c6cb518ee4fada532221be845d7ca7d0d6e9e7dbc0da579646681a674f2973a38d597d05964abc6a7ebefe36c5b539f93231dec999bacee28e2af74a31e921400878efa66963dbcde79da1cdac53d648575ceedc043dd9266ddafb7158344ef340ef0aff924428946cdca6f13a329e38919bcf3bb3f030ba10c70bd9ca9a5d4255ca2539f5fe59fa99e869f60bf6dd1ecfd2decf28f4abcdbf402d298c976c06ede5a2452f0efed56caf2b72b241c119818318a88bd9cc6f041ba5ec4fa9f4b0fbea317398809510fccaff569e4babcd947489cc3a4b3abd32fd8a6c2b33f19f65a08b40d7b00ce562c0a424ce852135294374df52428e4ed6d93704925fd4a5ff1dc7512acef6628233f205acd13722a24141d8b28766f645a3938830a8ffc4bfc02b5fe28f9b3a2a2aa728cffb94e122ed830d9953bb62814e478e9d441fd9d37f8b88167ca19f863e77b575344fbd6e7d705b0268b9700086d36f7d0be56670af84702a59ad66cc213e03d148a3f2537a10a8804a6769f00dc221b1d2635df44274300f27c11fa88ed50090f4d5604d4f493b84ec247124ad6c0155d93421299b1218bb3c5f55c78c73edf703ee457e5ebdcfd45998c8f1b47f9b06afacf7f0aa08801580ea26e16d0f3918965c712fb67edcd6644d86fee292836e13b344721cbc543e0e8", "fa08624f6d64582101e33f5e35b14e29f0ba36a6d88f77818181f64324bcbfdfabf865c89f250b60711cfe94be6e44b98331ee52bf776927db8f659ef39d245aae49b0ced01ff0b37518d84debdf36d64be8fec693eb812acecba49023e80f3f72152af1dc3722d69a4a477d1c849231c5e52af3a8fae2eaee59426d77eabad747a21e34543c7bef19153d9b430b60f704167d4a012290d24b33bc82e8905cfc500e74f8cc5981bc3a63fe0b7b0075252c97efd159ca6b367981566cdcfe7bb29810d7c3a019f5cbaa9922b7962d66ff09cc9b945c8143795b7477b89cf207af337e5287628bb7d37e17b142b7d882472da6e9826aa689ff3ee75bd4e5fd3f312e099caf9bb9327eec492056eb3975aca853c2d1e26cb57fdb2654304c11d5895f809ea1c06b0b63687060df9b3571f6052aa234c957e5a8639f9efa4e12c4685e3e68882962841ec91d93d184349b5594cf22a7bf1c46b1dda89e11a5ba985407ea8a82419c85e72725a452ef049c87d81442bbfd90ce727fb71cebab2db05f4aa90d16d1f3bf620e013aef3df79105506e0ef5c65615cf185571a62b9e7222e71327ff4eca579c2028f2357fc75228b29fdf1fcf1ddd51375aa83556cae754ddf5682d3f2a1a55acc5bc1e7ef22455ae0385956500729f88024d6405921b4769680ec8c83c584eda15ebfa160a3cc7f656dad8a9e7678e865481705efa8a5", "-4f93dfb83c46df1e7c89ce6294ac559d25f141f69838725f28248c194b3a1bab9ff1a87872382880841f3e87c9a2f1f111978566d26c6929b7f1cbf1bf9336f1718c86fcd06e5a5ed6e4b0a2cb578f1a52e7729bdde1d6a4c0ed41d7fca51731b3ffcc893a9e376ace2a1a46bf888d00aec5305ef1a531739e19a3178777cfeffdc0efadb4576ae8d51a6d96a7ebf5127be274455daed2b2f8d8986a822865b564aa85d62c26578995933d0ea4a2969d0fa572ffe835702a2806f3c0f222d8ab16d7d86ef12cc378cc41aa5d03eb940cb78d0b73a48d0ed6e0c7061ea108a8844447b1d86b92a037f4bac25cc8412cd81ead9e70cd6d1bdf0de4cfc6026d4ef3e136c5d53c087b7a0217263cbca8bb83af72a9c08e6ff1554812571f79d3ca47fc202d293c617dc9a8b12a22173e7f95cfb7045c851888ea8285f5f25adf554039868932f52327fb3aa40815491cdef10f75070ef4db98ad1b77c1d9d2dd114f5a770c8f9f711ba36e49421c34a0705414814c98f6d0dda57e627cc701b580a0cb1752e54d5c508060054b4ffe677db6cba5e1cb7e807e8327649b41a5bad99e406bbb6d44f5b4c718076417ebb4c3e4d23c48c8bd073b685588443476f8623b433bcf4a12d211e43f2441adc4ec67dee76f53a150007224c7ff2f76c85a79c3190497bd80154eeab4b45a278f2e0a1157d55bd6b2d557b41cac69e2cb33898d", .Okay}, + {.Sub, "-f29f3b2722300462664cca3fe1f492ab1933d924d01c780ab18b1f4c9ab04d114e32c9b5d088f1cd7424edf9a92909dc0a96307c1631b147773037f07419c5cecfd59ddc320902ecf5bc0b95c835a25d2b4c953ee502c871c4e6a703a219652ade7d17ff3b6ae2c30b035bd4406294b519a6742661eb9da768dcb2c3da91240a246338bcb85d6ce4be4296d23d321348e6e7eb67ff6d6ae9e0584e8e56545b4b302c9f15a9c929d27648f0eefa63084375f049720349607d85b5cb738b69fbd5782b83a2c51bb1438d9a924556d002487a85a5aadf43500c031d60398e6bcd881468dba0faced1ca58238af75585acb5e6d9d1a4123cbfd876f5057cdf3bc00176762b936e1d3ede3e337369c04e2d2da3a7ec78386828894c181b815f9cf6a8d1a8b95f99c6762741c9e7ecbd23588508966b6914215d653e6aec36a05491943a03bfe40ee7bcb947093cdd3b7d23269a14118cabc63ba698f0db7700ef22addb497c48b036d93e4f5286b26072bfd8a4326b5df10ca0b820f203f24f84e6a982691b8d84119829dc7fa7bf344d19453d4f740d86b992b2c0cf3097dbd470c8f51e0fb82ab294ff036940357e6028c1cf8d76fbf4571287b456e3815085eadcca08632bdc9a97dbf94fe1cc799947590246bb500faf125ab77f2f3a56beee30e0da1e51d6655132cb62b94549c982976e2d2dac4b68bbd7ed2317ea18c450f7", "87b5a095b6008db225062705bbf99c36a43515dc20df778dd44a6d41c9158da63cd125d9643d7036d95830ae6337ab8a10ecfebbb9b0ef10b876a468c17bd4c4cc452e09ac2dafc2331953ac910b154b2dac36058b1d344adace046d0fef3894b4706afb9df11623608dced342cd2d0a7a47c4289392cb559ce29a139a947e5dabeadd41cfbed0dfa1947105f440c2f01c221763e9d66dd8180f3cfb6e70ef605cac77e520d42fb06ccadbf3be2dddca6522daca92f0b26d5b596f001576ca11098f2da2cde313f57c1de5001e299a4cdf9e85a88887987ef8dae51ed46f2fc700639b16f392c973a085c6ab05fe3ba786ef618dac7541965f0832e9f737f359ff289a451dd2b8e06da3fdefb33886e1b8a503630442fbb4764a3487e75151cb9b0b0a4b50a1fb8b8cc2553d3c4d5dfb886b5dd118aa62f7000a024c91201a8246833597bcda8839a25af3d7e9f5d30ac14ad1889b9789d7b20f42467ebf686cef47c922f085b1cce94850422e2ce7afd92aa797e70cda4dde70f2258c43f665b98761a39a65874aa2f396ee4af4c21449097312a28a6aff1735631c44f239a3ebc9f17f5d87ebfc5fc8d274604ab84f859762aeb5b588ad05b05fe4fa652f5ea465c4447fbb4866edeeb5a5ccb53e99c3d53b617cd6bb7ed38c90020a1d4387d2216da38f56134a6ce938065e6abd7e561f6d351df3d8d79c56ad9ddc196161", "-17a54dbbcd83092148b52f1459dee2ee1bd68ef00f0fbef9885d58c8e63c5dab78b03ef8f34c662044d7d1ea80c60b5661b832f37cfe2a0582fa6dc5935959a939c1acbe5de36b2af28d55f425940b7a858f8cb44701ffcbc9fb4ab70b2089dbf92ed82fad95bf8e66b912aa7832fc1bf93ee384ef57e68fd05bf4cd77525a267d04e15fe881c3dc45fd707d83172d639030a02cbe943d8c1f8678b89c4c54aab8cd916faca9d5982e313cce2b890e60ddb13243c963a12eae10f3a73a0e0c5e681bab14592fec53909b8774574f99c955a242b5367cae88afbf8455862dafd4f14cc76b7ee619b3df8a951a25b83e85d6dc93331beb2016ed5fd3866d673b35b759ec5d88beff7beabd771597386b40f5c4cefdb3cab243dc262500946ee48746cb3c3aaea6871b2ce8c3d29f970b6809101c93a2ccbc05c3e74ee833174ac168086f57bcbc244f2e96430b52572f6315b5ee315475dc57e4b001dbd7fae8b1aca91456ba0bc8b0b389ad6f48e9fa7887d5d12f5d8197b05ff62f617dbc8dd0f3bf07d311e771f747f733ead7f41db598658e7202943fdb1d80493b420c6aa6ce0e80137883a80fb633212a9deaae1115524d9aaaa0c9b34ba0743664aeb1a3b6e6e27705c55e042e73e9772464e85f2c61bf6b18c85cdd98b0bbf3c60dc31b8b2fb8bf565bb647d384bf14ba8344015c44c9ae1695c94af8979c587f4ddb258", .Okay}, + {.Sub, "-60e0777600e0e24219209a206e7692f64cbdf02b46062eee7bf6e832954d8820c0fb9478bc65a8c2f3b420ce28e82e7d2b90ea415c946ba64ea314167e1b0e557aacc34a1bfd9b3a13d896e23c4f56c1eb164e22f48cec117427dbf9c530fd59accdcdfe7cd6e7ca760ccea5ccec0c830f3928436d48f3e449f67067ff8770e74ca6d7634e57e99a97316f61c142336dd4f8729adf6b46a4767d7d282a269ed34d277d8d8d490ccbe4b569955f71d9844e97b5443476bdf7b8fd6295daee59efdb8b7ba1171931ba0ca11ac633648619bed47042654fab5a4c402ce47092c67a8815ea323e27f67b945c3108a71d356745b514d9af1fa4035dc0b6cee211d3a62b8a3725def9c1730a51f6f3834fa92fb7cbaad0fe68a8251dd8a017ff209e440f59340295b0661a1532bf010001f02552ab2f84acbd543948b4bebc50f61000fc85ec13dfef915f991cbe41cdd05c1900f0d30a8fb1a7aa362d2dd094c178d26a8068054c4a4bceee96123cd10743fe9ea268a08517250981fb307979aea64f3b5cda45edacc2030558eedf579958939bd931cd714ddc8f23de14135bf550bde255d1308b756b2598ef2f171d72f0b5310046f834a74ee5ef52a4d3a6cc3bdd64228d340fdd0f1de6d0e5aba332bbab60ade37ededa869ec36c9f533c53bd78600580f56f93ce5f2a7bfbdccc7ccb05fffd806a4eb02d02db0e12401c07c664", "b5f7913f6fa05bac01c6beda4adc3b877fc7e522fc1aed1a4d97d119f26bae3960a6d8425b7f89818e793c5a67fc09f2485cf249262f182992d8d785066bc9203e335cbdffca4628c0c6b2f2248f4229be7e32b996c991aa97ee726d9feea8ac4c95f6bd8c86dec9f6f04ddef986f98daf28b711c3d225684dd7dba59e4049c05aad470ed73728f5feee932ad8dd279a18689365851ef14bf8c108111f37bb5299a55622a7e3209b99aef20594aaa3da689361d15e7d243877596c9cd1fbbcae9233a0f1c07331d7bba4786b91976c832900a552d08283ca0cab949393ba74afd616764c33dd6480be15696e8fc57ac98eb85436c14c16062d9a19ecc204e236609c98f5cab406556039bd7520bf1ad89371130e6dbde351e216f73c4cca26e1c56b7f3386b2c2b4130e865c843a59f9c3eed7d1234b1b1435a03c1a5df048c018932919a74c33feaa9ec9a52431982f037636768a7b8ad5efb49c00f0d90481a37eb3515382cb87a00abab80eb0dc2a15cebdcc8b0869834374b57307046a7f98ebb8c690ac72bbba0ad7af751097073a1e9058043f6d11154deefe02d1ba60ee5aede07bf1a5fc92761a4228ffe44586ffee792ab40c2007b5a753e3607b7340c8f6be6bda7956488d6cbcbd5a761e39154ab297ab4d098dfa9dd154a84d2dbf806a73e54db8bde4982bc518115db61ff4331b189e598d68abdc9175624aee", "-116d808b570813dee1ae758fab952ce7dcc85d54e42211c08c98eb94c87b9365a21a26cbb17e53244822d5d2890e4386f73eddc8a82c383cfe17beb9b8486d775b8e020081bc7e162d49f49d460de98eba99480dc8b567dbc0c164e67651fa605f963c4bc095dc6946cfd1c84c6730610be61df55311b194c97ce4c0d9dc7baa7a7541e72258f12909620028c9a1f5b07ed610600648a37f06f3e8539495e5a25e6ccd3b0352c2d677e645b9af41c7d5eb72b171592f3e2303056cf32acea169e6dbf1c92d78c6391c8459331c4fbf29ce7d5159535d22f2458ebc178044d3b2a5e2c607e72055afc52719a7736e2b030d46d6910706bba098b5ad0bba416b5dc8c26d01ba9adc7c86a8bb468a40ec4084b3cbddf6c268b76ffef97544beac525d4c4b3361c6328ce2841455d843c4a1f169a0755d0086f4d7e54fad6aee658c11519152d873bc55e43bb87e6f201f448046709811a2d328025e1c9d1859a7d540dff1b569fcd17568ea0ccf4dfb82028b471266d101f8e8cc56fe5ec80b310ced448930c7e5934bebf63c68ecca9ef9ad5f7c225758d49a0392c03115ec70b1ed0b0bf11076711222b6549594672d4fab80035715f5b5b05f7084c278a2cb750a4eb83f27bb788742f5e5268608d31c999c32e317685d3a851673d2490fc0aa61f85eb6954e1871d0f1427a1e48e28bc1ff1b385674e869043b9eed1916a1152", .Okay}, + {.Sub, "-80558825d7a2934f08c973c4e4472734ef3e3c5c8b6a8835da38a8c88ad48f0a20f5f2fcdaa504c238e8cd66171e4ea59e5a3cee6eb403d71a72fecc3f98a426c83c559ab915e48db75e823baba044eb1b66a8626d09c982ef8122cf89d63f0277f81c763b0a7c1498a08daf707f85a1c820f913e0c2fdfe34262b6ae3ff9cee1eaa82fdfcaeacadf74bb166f606525e4b9762a18ef4840447b56214f524a5559edf5300bc82f7b6a5a1d9373b3a865d6466913ddb5dc8fbd9761f711702f3e25b50fd0f2061a2a16cc8342b19ede919c3447a46cadfd7617bbba0a6d95d9ad49b8d5c3cf5fb711b54b437a4cff07139b4c2f48a2ce6f807345858150e4179c1ee4f38138326236c0ad0dac1232de3f90cb6b1f8b0230e102470bd8bcfc84f3ff15c250e33b7338939b97d4121030f37290005f07cde37c5216d75f075a82771eb5a517025dd23d0e4d5856310bd5abbba6a0a1fbb53e9b263a45d6096224dd9de38b5d04eb96fd058c7fd93e6cea85e86bb9090410937190e41d75ad397547fad5c21bd45fd67e0b46a9bc001dc6db3f2014b9f9edbf19b054e535bd39c0f25c47486ce1606f5ba1fedbfaab584f5b2fc3908b1a07ad361ce22d53d3cd2c5614b3b4d3eb42046d9275e48005c266478b4bb8ab2b4576d25a53def99108be3081926738741c616668b17cbc646b576d952236184387c3ad1e3400e9280f64505", "87cae9b4a1f54e7101af0c3f85dbeb5e2b3ecf8bea98acff5e7999bf5883783da8d65f8ddbd80b8a75b5fd9190c66959d7d15ace55f3567bc872dcc1645ccf097800d6eea9bf78bba5a4081630d72053900459654c90215f44dd6da23544c433511011fcbbef70b8333b8e0ec35c0af21e74d1bf339a239bca3cca3cf39b23fbd30541fe77cbbaae82b1b2d2c8be2b3d5a7e722fe2f68f9b5e28ac85f82fae2146d44fd45f992cd31e439a08ac4fe13bda93d1a652e25aebf85757f39cafd448c8452d83bfa6d3d955a78fec7535ca2d4496d6686729c6e6ce5aa90d5c80ea6fb511d384b0b31e3c530532e485f02f584339489b94f6a8ba7ce8c8008d0780d34f682400afe2a1293be25f5eac5bceeec458387a377ae9c41a0cbdb729710c9c3b86d649f3b999d1e3083723f35eb8fe1dfabba83a787f1dbe40e5205faa89010135707214537914c9ba12d6d37f3de3704d31d376793ec77acbdd12e658896f0d9579ba7934a53ae345d105a90bd5e7af1d0640b569699f96f7444f25e5838bf623a70255493c75670306e5e307501f8dc77361a1b146ecffd11369aa1d3cc538e25cdfbaea336304be0243df961ebf202ca41455df9ead31f6f33d546847d2aa8870891b84b9e16cce02234d4751bbd658ae7a92681401e1e7eba85c6491f3cf208d7bf523f859a759aa2f5b3f87d69de51750a91b6daca1810021d278c688", "-1082071da7997e1c00a7880046a2312931a7d0be87603353538b24287e3580747c9cc528ab67d104cae9ecaf7a7e4b7ff762b97bcc4a75a52e2e5db8da3f57330403d2c8962d55d495d028a51dc77653eab6b01c7b999eae2345e9071bf1b0335c9082e72f6f9eccccbdc1bbe33db9093e695cad3145d2199fe62f5a7d79ac0e9f1afc4fc747a675c79fd6439bec47d9ba615d4d171eb139fa5de0e9aed545376e5b3a2d51c1c2489c3e5733fe78a67993efa62e42e4023e7d1cd7764b3b2c82b23962a92e008767ac26fc4178f23b34707db50af32099e484a1649b435de8544509f2fc1a6ae8f57a7b96a8955e0a091f7fc3d25c1dda0c1b14120159b48fa953db75c143308c49546b33a1fcf89b2e7d10eea72e79df7d43e7d7b42f9395bdc2ce2fb582770cd5b1cc1b4651461c83546fac198b756b6e2dfae5b10d552b072ec8fc1e23a309ce5ae8f9839e43c989f2ab73bf331cd2879de703a737c7ad748ebce2f8ac7ee150b3c0dce998fda7e4635d896d0f672a0b8a5391ba9f97cd80ba37fc8bf9b46a4561b6da2a5e4e3bdd37fc8bf01408d3888051f66c57db94beafd56e3add0f1291d24abc1ee951b14721c65acc5f65a720f0019c87a913b0d33f5c3bdc7cfa500ba942c4a23a96db6348b14392d46bf81278725db416cf074fbe847010336ea0ec0327175f5a1f4feaff00878d4e197a87e84c10eb4536f0b8d", .Okay}, + {.Sub, "-8b7d16479fdbcc02f743afc63b568bc37c714fdd2a878ea58e58e8a194bb97310d7ebc97759e4b862b631f3f621605c871162ec69623d1498b8001bcc8575ca4f85f265e383baf1746020d391a1e1981924c71191bd94076d4cbd1ee7e6f5a16f44740be1fed6cb5c1bb647ef6959c7dd4710dae0028a6af6e9d5cfbf8e345ba8d0d8cdf892a1ce3407db9320bd302ee0a255d5cb9caa4b60056924e7316cddbfee2fad36de5fa10c2b3e547f2dfdb7865c56542662c9e21038eef5e4b0c0f8ad8f870e29fccb862c0dadc8aa9070c0ce7c111c803ca7311277b2d32f20b63f98b4c4be34a89c22edf45c957f91ad28b2836cdc6eca87e81cc2f279bb63a960a4543fc411f9f7e1d59223060b1f5bcde1a919395b0a3fce2f2ca996b06fff6f08ddc145b7e909603ab02ef6789bef9ca4cd5d0d6ca7e0c2d137870b0aaff6115b1c6561864a5c63cfa0d811f1f28c7cd3bdaac2fee2bcdcac16abf8cfbd38c716e644f3561c002a542b38e15232f35dd86d70737d6752fa796675cfc727ee65a8f228db48f6dcf79cf9cc41612850bb4f84f25f19cadda250c488b8ce07dd92eeb2b02827c13e11ae30d2723a0fd48b372140288d3c0db6885d7a4bc2b9cda158364dee11b878a4e279d48ce307be4bb7c237e37a945161cfbf782db165ef86944096e74c8bfba729be04b34a2cf865447b7412d1dc3ad0a1cd630820b60827e", "9bfebda938d9e0315beea149812e66b63e1d9dffe970617fbcc552bd5cb5e501a5d15826439da8889e7c47244538f8e015cb94cb473c6ec9c31e0102a664ef46390bd7962b58df360c9ed4f7742f8270fa61382a75c935384e01c58f5273a42652649d35bd401e3337f87716756ba8d4c95fbaa857327f97157a284c17e271510f2144de464450911de772a562b19eebb55e4585e19fcc7f5f037e3cfabfb327420e5440599bfec601936009b621831136da2659752eb84c158d99c75f0ff986b6361d33155ba1dd0a8c0459a8decdc7e37251a221899339f88419fae63c3bdbb1beb9ed103d81397cd119bc19c6fd3c5f5d636d7e99c6c2a39e9a98b13b43961a01800dbd63566107c2e4f858f7e90e4ac8ec990060a17aabac8f98c85d1ffd5214a1cc3a4be7b719deef605a119533f4302a12bb98140b5785d6d2b56221f85e0ab17e04e7b8f9f640b172cdc3973438e48d3f4dba2c2dc4ad4c174894f49647a0a52942bc8060039d1e3c78bde06455dde350ef7cfcc2181381c836bff4025c838497a60a56c8175669af3ecd40e07036dd4647eb1098b52647e0f8468f86ca19fa7956bbb042b7c7bfb0978832e6a176820cdcc876f0fdac269e27c2ae4c06391c6511c296d77e49db9b368ce8ed183af3bd8faabc022f10b70b341ad4045fa676eef06d6adcc08c1f6cad392376ea21bd80cc3026bfbe553c450ac53fc7", "-1277bd3f0d8b5ac345332510fbc84f279ba8eeddd13f7f0254b1e3b5ef1717c32b35014bdb93bf40ec9df6663a74efea886e1c391dd6040134e9e02bf6ebc4beb316afdf463948e4d52a0e2308e4d9bf28cada94391a275af22cd977dd0e2fe3d46abddf3dd2d8ae8f9b3db956c0145529dd0c856575b26468417854810c5b70b9c2ed1bdcf6e6d745e652bd76e84a1d9bf83a2e29b6a71355f5a108b6dd6810340f14f13c781f8d6c4474551a9015e899c9f8b9bdb5b566d191c8925aa1c09118f2e8e15b5285a3fcb66e0e451e5d9d4cb33636a2554064b1fff472dd8479fd53d0b05d05ac743685c16e31412e1cfc7879431346b4245446fcdc2346775d9a05f457c4edd02d47e60e515590aeda5ec655a802eb1049e5d9e772903cf5d16eddff0b627b8dc7dbac4e1dec7e3d08efe4105fae9861620386afe47836061830e0fd10796698d7f36f04e3291ecec5f0174bf396f3be5f9f886180ba444688107b604f45ea47c83054650ac519bed1641dcb4ea88c5f22c69ae7adec4a93eda5ceba6124c35782641e6f32dc551524c9568860337e498eabdc16ed36dd8c468b5b544fcfbd2cf915d9ad4e6d438857b9a138a8495b08952598383cb5a535f8861899dfb462d4a2125a5e724696708cda8945e71f538efd21f2b0839e64a79cc6da3afe563b92d254f5c6c6aa15008a9cb31d8feade9f3d3c9db2b6cc71625c245", .Okay}, + {.Sub, "-a42e217ebdfbbb22e460cb9fea388948ee1c25d78fe5143b13a9238276cd508bcf46a9cb53ecfea021772d6ac4f7522504f43bb7f721584f52fe0d736fa9eeab16c2fa43d94f6b7dfb1af781a994c396eb19ef1b81cbf4d36c47cfb5adeedaf34dbcba43d499100a3ff87b54f320435ec533d88503f46fc5fb2fa1ffc048a58ae2def75961e0edfc1df94aec53813df0d29d0c7552f3611b4e85258133a96311b1dff728182ab9cce7985a3c8014e61390d3a7066cc49c3b6b92f74cab44e10880230a0df33480dca628bee6fe13f13676917122e0e35106b5d01c8d68a509bfa17731f1858ef63026ddf2c075608da1a29cfdbcd82dcd7fcfc784a5500edb83ed714bfe5db81b99299b191bfcf020f95009d7a65c68b2fee4e558dc481f2d4123e626dda719e9ef17a0c9a4385059146c10e2aece6807c186f21a7e61bad07c7ba12c159b4b03c2a7a7c32790e5ae4b9bc7f3782240fa76c74eeb5243e721c54c18846ae7b68aa2596f8cc36bc0cf6436d926374ab68dd40c1a944c5ae66fe98258a3cb048c133619dd245f37f942ad214640c361b85fe8404479b9da6bfa3fa9198cc0ddea0ce9933cd9772d34462f2e578e307545d9c26ee35ff0b583b6c73e6667a4386eabd0b47ad373c1645ad9a38da91ec477965fd26dcdb515e14c941af047f19e7833df049b1fe9136069b84cef8eca918b9cabba4b00cb37961ee5", "96d5588d23fb43d964325bee9048cdce3014dafac75340bbce76f4bb35f9ca5e2bda7e942717e8811b3dc607d71931f0c2c639c4efa733016739546c97a05ddd5a40ee5bbafca6e2707f37dfb2200720089e338ee8eb45c32cc43e9a09a3829353c963bf36b218fd89caafd8cfb5b909b96cb0e1e4220f666a63aab84b0389dd413d7d165a005865f4f8d5a246472e67ef50589e2fb1013d5616f59a1f70b924e43ffa66ec674ce688042818eedd9d351c433a304b00a1e5fa286410a0c3270333a27a515476b50d8c77184a5012bc745505baf41f85b46722f954454ca4401d0bfcbf169d66075b6bbf62d23968a12f624c35c69f37d0bf64100871e86c8b14fe43a1517cffca3641cd9a9e2eb83572623ca7a633990b18dccd334314ceb32cff0117fcde105c7d38305d7844f535b5f92461d70f7c6bd8ced8d5b27de41cf13576b9642ab93f7635d3190af7f7afdaf3c75dde06e71cce9fb50f87cbae5eb5344ce6133139f44844d23efbbb2bc2cca75809d5728a9e8500c4e163064145724c4880349bc0945dbfa2400a0572eb89dcdd7a8a52e75acd870693805a25f4eebdda06c119568c4cee6e4f7dba1bae957170f21cd2707639780850e89f070513646216022f09788afc378722e4fcbbd736b31439eb34ae789b3f03d671783f517b7b9228139f52d2528e82038a496cd073c8cf3d9143dc0c72ab380be59e4052", "-13b037a0be1f6fefc4893278e7a8157171e3100d2573854f6e220183dacc71ae9fb21285f7b04e7213cb4f3729c108415c7ba757ce6c88b50ba3761e0074a4c887103e89f944c12606b9a2f615bb4cab6f3b822aa6ab73a96990c0e4fb7925d86a1861e030b4b2907c9c32b2dc2d5fc687ea08966e8167f2c65934cb80b4c2f68241c746fbbe1466212f2208e99c86c58c1ed651382a46258a49c1b1b531a1c36961ff18f049206b36f9c82556ef28348ad16e136b7c53e2165bb5b5d4c08080bb3c5845f47ab35ea329fd7314e26adaacb972c170069056dd8c970d2b54949dcad73f10822f4fd8b929d5592aec92ed104e9338377659e3f33d78d17387b6698ebb4ed4fdab7e5cf6b68b3ba2ba8566bb2467f4c9001be17c1b28c1f5cede06e22e73eda852a466c4fd1271c7d458eca65354485dde4739a55caf030df9eed6db117e579c6044338dd7adc3288dd5e268f8f5156292817456703fada0f95807a80656a7e18f07eea9e41cbbf26ec9230de31300cbd412c590cdf75af6127b55bcea123ffa04ca793d97f64693d6c2e36fe23bb4db49fbab5c74b0d3a3491ef2e66f39381f740993681ab28f4e74ff4c49fc8804d47b64ffbe6ebb0d9548abbdaa2c87da66778245bb0b25a96a66116b0da40bd58afac44d86dacd18b87598be5966bda19b21786b15729a1ec9da9d688c0b85e0822cf78b82cf638d71d345f37", .Okay}, + {.Sub, "85f402ad2e6f348d6b2a46af5a4b1d30985cc1102e92c4e41b66799312307bbaad3630c275171c4ef0cd759878b1fb8f51384ee51ab968e315cfef8ca77736c16155e9a33034990cfad75007eedcf0cf6013e0c8860900b4a523a98dea8853b9c6a83f89f74bbbf3328f244433192ab2dcafed773f3ea92ffa21ad4e9ec87376055dbf6731f87cd45a85d2ab866d91828fc71f4abfb8a74ff758a9b48c5a69f6a5372c9d94654c716b47aaa04ba28c30e2b491c7cf634000959dff90463f50175ee19484a07b5bbd066c36fdbebdf49b9cc769991394826eb3044ec5d87c1c49831acd18b71dd9d07441fe9ff2dd3b521d3816143facf8dc5ffebe71a0d5a9ec14c2d803419aa80863eb8e718ff40b037e466a20efbb69b8adf24dc971b088c4e29d571875bbab65820667ce05d9412653078e6413764c8d38fa57658f32df05950845bb39ba5fc8f3ce693b540a8820c60af696d1074417f15365dbd3fc185711286d12eec92b29d45db388c302d912f191cc65c7108b039fe8d3e202701d101869137169ad3b550d23cc0ae14235fe2cab4f9bf77796c77b3517f3f4c07001339edb39614489e979727f5787b8f6e43b9c91d9e34605b62b92c565d5445c1342de1c4e775e54dc9e45fa15b9b5c493579040baa443b26a6783792081154b43818578943b2d94f29257ec22be96b3c683e27ea668c3ead29ade2448454527e5", "f920ec584a8d3d76c0ddd93725b3b228d7de592f60f3f12273a74517b94e73af9961a7066745bf9593bd818d5f69087179f53b25b62cd83ec7f6f71ee6aa4e78f1452de5b5aa37661a82948ea410b67b5194993fddde3c9a1425a97b7bfa184e55e7cd45db3977bad56791ef357ca1d520bfee471ce8e4cc9f7754f96864186468f3b2a2b79e5362e7af8a9a73ec9662a44039ac6f0bc1831a604bc601d6e9b8bd495632195d53c1a3105ce9e713a5f8447714b4ea4fb114ba6adfb89bd61a897c60e1cd5d68ea660442cbddf5e96a6afa115ae945e575565adebcc37fb49878a6de4279b066d31354693fccd502aaa8e0fece58b62920f65c124fe952903e99478df309456f2dfdf1c11bdb7f37f6a6b617e73b49ffcb9bab4477f15222b2ef53aee331da074f61f73bba31e58e294c815f38021def64f33fd9ff0228904b77b39e508681a4602f0b9d49a5b58c37dbf5d1d6fbe3dfc84cd8d9f355357bd75b6a245c45b80cd173522a663a9ff0a079b2ac786a6aa6bf5570b0f4db3733e5717aaba134348ba27fb993f8eac851f3678d8722a9606a4c4a37b3d9be7cd2adf47131a8180af14d8d951c7bcd0e147ff499ae59c753cbdda8b45ce5af53e0c2adbc30a6a9f216218bd8b89358bc5c440303df6d2e86a01c85736ad33733042361b4e62ab77f01599efcfdbd8ec7ff1729ed2071c05415cd0473567e545e2db74b", "-732ce9ab1c1e08e955b39287cb6894f83f81981f32612c3e5840cb84a71df7f4ec2b7643f22ea346a2f00bf4e6b70ce228bcec409b736f5bb22707923f3317b78fef444285759e591fab4486b533c5abf180b87757d53be56f01ffed9171c4948f3f8dbbe3edbbc7a2d86dab02637722441000cfddaa3b9ca555a7aac99ba4ee6395f33b85a5d68e8d29b7eeed7f04e014791a61af531a332307a211757c7fc21812299484f8075037c8b2499b7119c761c282ed1aec711424cce0285596ca721d7f4d48bced8ea8fdd694e0372b75cf5d49f1503250f2e7a7da6dfda7387c2f23c37560f948f942e027412ce2256f56c3c6b844767c2819fc139177b1ba94ad32cb1b0603d485f58dd58d69ef43eba337d17d1a5a4461e2fd522a27e0722a2a71118c19644ba3fc75355263dfb4e8262e57a99e0a79186606dfa79c995d6c721e960acb47ea006617cee06a6181afbb2fc6e06512d88434e7868d79617fbf0458fbef32c943a6497dccb2b1dcedc766c11aac04a3963451d0c820f934c3c86162428dc2cade672aac702cdfe70fbd6960dbd30d68f2b582bc7ec1ca88123df33d92ccdea9acc3a41ba9fc75865b89105e11c7ed7085d7f288ca20497e9c669a79528a5b7ab7ccaf3a72994302a67f6fac4f2c73e25c6a1b0be75a16b1eed81e3360b22343d3c4ac6aa5d16c09686363693df319eb51e231d8785a0c18e88f66", .Okay}, + {.Sub, "1ef5e0b335dbab250c19ff95900c6fa6915380a6382dffc693a579197911a4a2ef7a1c205a7d762d3f3937780c57e9ca33b1b4139b15de221ae5dc0ff65e9680d6ce2764027e86e54fc99705635dbfea3922907fd4bff8c791d664663c372e8b4e9f3f4c38fd75cec1ca75135f8aea0d196470f19f5a429fce7c3fbbc45b41185e54fcc182c1c5bf9df9a0c0cd17f8fe17d9d2fb7dc69715a84d60413dec9bfb2f82dba6a71db00dd22351fb2fcf0708237e7ef0ea657f1b6ed7573be263acd6873d0ce8955c4f526eca8cddf264fb21e161730ca9dc54d5ef141fc13deb83a5fd090bc0cc9110745d18e0ae4a8436f1d7f11e99193fc487e8232172bbff5018d681fa180440f27db47d291c936567c0f9c1d4c70848511fc4cf7f11454a37d065f4e934a0917fa12879a757ae590f0558763d8d43645b05db3e09f15a984a490926fab99910c80b5ec5b38b22cc90932dc36afe0b2a6b83bad379929d285a27cc5084a9139bc8cfbf9f433faf019f2b8e6ab5fcd152879d0029d79356a437a56a62b631cbbb77cf2568ebe04ce150db6d5d9ee0126efccc90e70f55a4c31e04c0665a39b6068d3a6b74c53f900810e036f4f6bfb38e84f0ebddf89ad4749666b7211d39078cac93a7c10bb606fd8b7652ca24c0082f7f5645fffbd17c093109334f206053f5905124edceba2a8e82ba407309d78463797929cbd7378f9bb66b", "59d3e3c22b8eca332e92c86df2e145cfcf98908a69d195a256877c76eb6a33d7a56177ae44c7709aeddeceb5e1a7516544e6ce453db09a8dd7e9662443dadbc5c65c49261cd8477ab8cfdd3a9ec6a19ec447748c10c51d3225f9dc972ef4c32ca8b751442108dea1f34d3745e4302ea8e858e49557f9b937cfba060e3e31dd8e3cc74577da117006047dba660e042115611d0135b591ba1abafe1122aac7f2c6456f3f79e36939d03ed5280c1ef8625a91050d8493e7ae029450a1d279dbe7f1354dd3d3d4403fdda82aa05049ba32606d69bb98429b4bd7a2b7da33090b3e7c41c7890518c0bf1d97874a936d2df4ba0009e2b3af6cefc653e3475777741a3da0de294060bee4fde5b02bab01c41a9041c0bde651694f8d9d26ea1e3fd0fbeaedf535cd47dd0157889974c03af43b17aef65e3dd6ae798ec321a7e9fd4118f5acba2465001a989297bcbe7afd4db715d767ab752fe56e18aefb707121b0ac10863b1c12e10a331c30848ba07ef188722dec22e0bf7483ba9b5977675b33f7f8c3154486441a746494fa777cbee4f5260064de30bb53db9b0cfa0980e15f5c0461d61514df0149d1f9e13c6161289e710d36a5964565c57a988dcf2903b1a1d849e4eff01c8aa371bab3bb85e397c081b57def53a74fc47a2e4c848b12c36e12926f8adad75ae310bbe834098e3f24e43718a25965d0517cdf31dee678dc9642", "-3ade030ef5b31f0e2278c8d862d4d6293e450fe431a395dbc2e2035d72588f34b5e75b8dea49fa6daea5973dd54f679b11351a31a29abc6bbd038a144d7c4544ef8e21c21a59c095690646353b68e1b48b24e40c3c05246a94237830f2bd94a15a1811f7e80b68d33182c23284a5449bcef473a3b89f7698013dc65279d69c75de7248b6574faa46668419a540ec281749432e3a37cb230512b0b0e16cdb56cb15ec63d33c4b89c26cb1d610ef295b526d868e93a9822ee725794a9697783b1aae10c6eb3ee3f08b396013725755373e8c08488b98bef701b3a3ba71cb1fbad644be7d444c2faea93a6e69e522a9bdc82818c41a962d2b3e6bc025e4bb74ca24ca5c2f285c7df2803133028e6e5eb2cf47fee91f4920fe6dd8576b0cfa86c41a88004c98a74b81b6601fcd688c9b2c12568020b0934a1e88e7e39df8a2a8ceaca39329ab6709d08738f70aefda812682a9a4407724bb0294f427f6de848851e8b9ea9769cd6e6a4c70e54860cfefe9469f816ce3ee21fc1d9b2f9fd4048fc05358b28e54785efc956f918b9c7203a44a93073f50a8e4dece7c12fa2b3c9c3dffa16fbadb28fabc978e6c7721d1208d90d641aed691d74089acafd68e2f3d0b7192c3d2b714fdf6de12f2afcfdc9a350b62b3ca939f204523e84c88b996ba3d095f206a7a836552bf96fa654f63b0a229f6a59881e16cd803b56607aee940dfd7", .Okay}, + {.Sub, "-536e51a30a9fbecf168b89cf5970b4828572e4ee9f1536efe32a498fea2f71045c4058f72df91e4e4cfbce231cd4bb70017cd09530de188449aa726b42330e1f6b26031278f036c48d8131959d4ff4d1bcace55c5cd062d822f6bb23892e1e5ab627702a008fbb02cbdb4ec124585861bb8d12054bd05cd56441ddc88c5b2ff5e48cc4b1ef747576421bac2aa5968d4bac8e42390339b2e330d274fcd56b0d3d79b0b00992118b5760d2507a4717d9eb8de324c28bbb8dc26ca23cd64f0e01b926bf6e7f812b1c7812a6de1d3b07361405ad814b331967545698e6b9e4c7ef67b63accd7ca0fc74d81e572696273f7e33975b890c056c3f4e2b5361aa2f1ba1d557d878a4adf4bc1f40c8144731f5b5e75fbebe8c5f8afc2a0a20d325fea429cd8ff41d966f186cb04da5c13c0d9436626f9bc8f51904235f45052486a6a8351751453b562476ff83b6c4a0eb1c4e53d7dcd76965abc5909d8f9a3ac825a4ad4e465fac1dddd22c710caeeef3cdcfdcd1e0a92816dbffdb441f480e3853773f39ffc8bc3ec4dd7990cd66d09ff82c5ccaf8c37ba7356e6c5b502723830c16e3526493a57ef1adb8af97b336a7d4c281914a02c8e7d6d51b4fd7aad05744204764240a71d401435789b842f3ca23d1648fc72a92395c6874eb187ada41bf45eba3e356723fe6e7b26a1189f61570a29ccb78144e48cd26ed807be03c4b43d3929", "306afba0f17a931e697805f1dd95b07f3f517eec3d7609aacb5b3b5ba31beb62432342b14324f8ee07199f424d8e7752d2693d0abe01b158c3a073c23e429267fd1936ce976d90f70448d89129f93f70a8d77e78711735871a86b0d488d0d7d1e058f2bad40afa9ecb39bbd2e1c6ea3a2d92cca64df5895873576bd68c95aff8b45d30d33c93ffac65080c3a9b1b098e69285d3b3c9905630f8dadb442d577f289890926d6b26e26c15e19f1f2d214a695e900cdec1a8c879fcbf0eec68e69e5d374969084552c6e31abe611f8302a77f53cf5f39064acf9b7b5eb815f5ed0c91e2a878ebf17f84001e4b87742d7c82920ffc360135647570ab4a25edb8aee750f50f50ba9d19e38d5d116770d4411d77e9d4ea4705e05c547deb53d282e6ffdfdcc9af47569dbe206bdd7488666a3dc70a3daa3f540b3ef6700214ac4f16d0b1ab9137477826d9b9c29fd2ab5eee3c430cdf4bc3949b06ffca1310d8e6a3319489e21f7a529dafcb9fc217c73cf0b842f6467dd578ff0064eff1dbe211e0bcc04607f6bc9641b15eac7bb36fc55eefd21c931ad50f4c7d137c531c5eecd67d3ed1e8eb09fdee02b70f8c332532cf2488be26658a0706fabded3d703d94ce4529f644cc2fbe6bff8f23dbeae1710c842df0db5870f7b1eb9c501a78f476e2e93348b01e3fe2689143495109cd7488ea3997ba298c92fb0fb4b87c8005f421e41", "-83d94d43fc1a51ed80038fc137066501c4c463dadc8b409aae8584eb8d4b5c669f639ba8711e173c54156d656a6332c2d3e60d9feedfc9dd0d4ae62d8075a087683f39e1105dc7bb91ca0a26c7493442658463d4cde7985f3d7d6bf811fef62c968062e4d49ab5a197150a94061f429be91fdeab99c5e62dd799499f18f0dfee98e9f5852c087522a723b86540b196da15b69f743fd2b846406022b1184085300339b93068c3f97e22306a6c39e9ee9223cc259077d61a4a0c6e2dc5159c6b9efa340510058048e64452c42f3337608bfaea773ec37e144e0e4ed23b4426c030d46554668927bf8d83ca2ae0a54bc00c5a757bf0d3ad0b4bed69d8797e7ca89264ce7c95f4b0e9fac9dd97bb80636d35f4993a8d3656b587e880c26f8818b29ad6cbdccddc5b62ad0b98335c473fe742979d973346d0f6255b5073932f5bf05c8fcd6729d9c9dd93d796473967b3c901ae9b6b5294060979d59ad4ba10c47dee2d041cb98306fdc3cac7106bb0ac09514d6efa5ec54fedba90f39ea1a6557fbfa45d0b2fb5b1f2aef79e2840fbd8b4c9d1556967c44bae96ecc7a3fe1f8ed6091367c9088ef9bbb66a73f69cd0791a61a08292e71dddc160dc4e84094d8ee8c8e1a4f3e03bfaf5718dc1edeab94dde8bdb805eaaa541a6087689553363628d4d72c06907fc95043ad5adaffe2e52b87050fce77d56021fd35345cbc5137f576a", .Okay}, + {.Sub, "3005c0ae483d4861549269ad76d9615e2d3668c44c2e0bd7f0c30a69b32f81ee16668f1a8abfc9d6e8cb0fbd8be5303ed26082c57a2b6ee5b6ef5c3ae672783e862abc94daba45a84aa9a5d794fc8d7a5ad9a5cd95afa3bccfe7a18404849188b1bbfbe8ba75c44a6ddea4a1a4355ee1f2dc4fb4f1e131ee49430be7962f34293aad228b288b37b9ac5f7cbf6b128e0323bede48db4aec405baa26f23dd084c3b5a99bd1c04fb9a1ea789497b0a06bab14a16c9952e60be4b7f521e6d2a7b08c4640e9f3c49c32031fd0ba800f56cdcf9fb791b28fb740991f3e1cf9d69c399e67d32522150efaf353de798063ea46b597c54ef45c7433e8ed37161c67348ea3767df3f370646076dc37a7cb7ab7c5e0452e01d07fb354e19fe89e84ca16143f43a61b71c332f0946dd617f6ca6a8b7b48b252de2993938a25880c6cd9e024d3d0d167a5923a4df4cb191aed04153a996e023b69822a045f0a306eb5d2c3fd26263fbf8fe8bc656ebcd2514eabf43135e9ddeca27aa99946d0cee6b0bdc591fcc8d699f8d499f6dead29033d57c6ba59eacd568b7e221f0a134ab01d6ce48aebe5d354668a1141626c1a576ba4b82a9f825187820fd1099e237e0a62f14615a365ccd1adb30ba2d41fd1c53dad383da72a064a604ca3d9663083fb643ad963132abd57c4cc1768ff8193ad3a1edd60540d645ac771abf8aa19b7b80417201320", "c993c64ab004a2acf3ea75b51e6694ed873cb4e8c66ab1a1d5972fe9453ed12e2d8b5de6b80a878bbdb947dbedb762c98a0957956c7df72ca5aa2cc3ceff52f6d151224d8930ad8255980c2411e532f9499f2b43514fdbccea55b95db0b49b3e734238a2b386a2d9da34285158eb93843623b6c7c00ed5e6e7cfedff65c2ebd32e5ecbd2af48e7ffbe3df0081f87cebef4a03f361285774d353dbce1778ecb59bd146a94fc58b9bc0d616ced1dd446a362b520881d364486eebf4b7c62219c30e88a8b3613c5fda49222bb5e42945fed2aae7aba5e198da0d72f3e26370c44947fd7905b2c23aa96d90c63043f606a78adce3eeee6d8208ce0f367ad7791afe82df8312421333b858a416b39539dd74d1f1f2926015d28b30b2dce48ad0b2387d5f5774781405cb00bd7f11c727148abcd2b7187ed00ba0e75f4aedb27864751c8155ae2d68529f9a66fd15f08a92cc03f944ce11ecd3d6add4fb19cc5c2c38932078d5abb96a7481cdb7d574d24aa69e1d6f43725c4fc88ff1eb0f2e8f09dbd4da6dfe88e0bfdac097142c43cce073c7b525170b4f0136c24d68b6763881018b1f06acbfae03d45c9d2a0baef3bc68b2951cf6c5a9f9f385dc83f66e783b4a81f47775536710e0d8b83a9b9d6a21b3998296dceca90f3d65a8d815368012f89e40ffcaebb92e8354473378660e62bcc509f1743480886d796f0f76b28d27173", "-998e059c67c75a4b9f580c07a78d338f5a064c247a3ca5c9e4d4257f920f4f401724cecc2d4abdb4d4ee381e61d2328ab7a8d4cff2528846eebad088e88cdab84b2665b8ae7667da0aee664c7ce8a57eeec58575bba038101a6e17d9ac3009b5c1863cb9f910de8f6c5583afb4b634a243476712ce2da3f89e8ce217cf93b7a9f3b1a94786bdb04611de7348b47540bbd0e160ed373a8b0cd99395ef39be4696076acec33c09001a22e8d8556d33daf84e13b3eeca5038a236ca29958f79eba4a249a1424f29cba1725200de333d921d8af6e907ce624d07b7f1212c60700af618046b391714afa3852de983db7623c31608effa8a63eca3f3bc5191105d2144b77a3d30b0cedb0eae09c36dd8e6116cd9f1275581a9d3d16b452fc3e2f50f48924f5bd5be0d6c1b9e01d925a806bd3084791ea9c36d2684506ca26e4da6227df743f33d444adc04db56b6720493f226d19211779ca3390bd31f42e6f2fec6630bc7cdcad2da41d960092c08a1307933f7f90794ab1b63422e4fca422b2b0bc084d045efb97206cd5c483f86e5074ce29084fae536cdf462118bdb49f6a3852ccc1d166570cefbe35db8494f4a839beba70047ea4ace959a3a4a3503f63d9f04b97aa5a783656b396bb1e47c2969dd926e23236e7ded1a702a0985ef2d27cc76b952a4e9ef7b7f35c2df8a4c4208cb78433abc7bd65c8e2d7d393f6711b25e53", .Okay}, + {.Sub, "9b27bea11e97f83129d5913a444a8464417c947d9bb9181ae4dc5571800a1f74cbcc977f38df8b155ed9e6af39c6a3b5233a4fc393da2493ad146bc8b1cae98c429c8411e9a68c066a2367bc89c42b763c892645bb3b7883e16ea0076a763eb313b22d8ba35e86967eacc3a5f6b6dc3d4f2e328484cf5b4d8ab547bcf66a9467629b784934368f536cfbbdcb802a4e4154e2fc16a17921e90d8827c7268319fbcf74b6552a936c5f7755df17027891e89c1c78072f44f883904fdc455bd30223321cd78eab936a43d573c5f445c1194fc7242517098f87cc383693b51c1c2e786c06c385cfac3fda68e41536e77436f043bf17e167ec0f943c9aec6e23ed85fb5d8b73559c9ae828c181f36dfe2d2615c44a3939743644494e0da55fbcff45da766b52cd00ba8c2fe04d309bda02a79cdcd58ec81f728449ef95fe5f94903eb2cc5497c79851a5c581932a0a16ed34ebce0fe51cc3a287c75b66e468c681a0613a9b5e791cdf7ab34ff96b56c58889df47ef6a24e996ffc6dca9436c8048d514e934fb3754cb2cf92e142baa65f07d02e8a72e08d085ae3021bc2b8e4367835766f1550582ffb9c9b34c85637327791394430a0c8cb64d430aeaf4ab885b0be3c6be9fffe655372a97003c2835c2e5c655b75dbd3f20c802fe2b1bc3a3b6ec9091a3f98f1af9ec2bbba75ee631a5d0dde4215feb866a189f2fbaab547ec4c5de", "3addc67066b3f3580ff571b7f3d190682f62d67d1f3137d4aa471b194f6668ed48a05e70f2d327c16f2b93e753223a5207b705bed23cb66a4749280bcad3dbfb796f905fccc65ddc024054a3801730b69a088df1e6272c550b29b30f945b371a06562f5342775930269143c315b5e558d42e566f6cc3dc3214c09a86e62f93138774664b029c3c3ca42a5eb28ec71d21b5a3b59eec17d6438067867cdd73d93b26bf37c36d5466a67d3e14f8535b40e4482431ac7fe70e2702999303c83ff944a4837eee88bf73fb7f55c1af4dbb0f1ce4e45bd49747719f32587262a2ac6829f8492d920335b6d624538a8ae11a7352a4094ad958214e020b2b6e548934495ad781b6cac177373ddc10fb64c4f3793b632b3e51843e4289da434f1893c5d2742e1a814ffbb7857aa2f3f81c92c9f893794c2a0cb08ba579db2976c2d45f340d0dfd72876f291174955f2fc3e64da77f231f33410a1f4b151203e59eb2450af1ddbbb2d793f0dfb22322ee2f133d8fbfa6ecd22b8eba46ec6de04193601c570aaf15539efeb6ac118e319724e60c8212ca5ac3af56984d12ea7d9cb0173c908417d00c81ef674730ac756b51f0a6a6a08adf43154f6e9cf26a775cdc03ef2535e208b81869d720c5cf4066d9836d1428a1a252428b676a92fc3cd014437d676243971352eac1035f8daaf771b9f0c5ab71b46a70f0f6f1c909474680ca7bc64", "9779e23a182cb8fba8d63a1ec50d6b5dbe866715c9c6049d9a37e3bfeb13b8e5f742919829b2589947e72d70c494801002bedf67a6b6592d089fd947f51dabcc8b058b0becda2628a9ff627251c2b86ad2e89d669cd905be90bc04d671308b41734cca966f3711037c43af69c55b7de7c1eb4d1d8e031d8a69693e1488079b362a2431e4840ccb8fa2b917e0573ddc6f3988c0bcb2b7a484d581af5f58abdc681d08c2d8f3be25f50f81fdc77d42ddda579a34ec674687a1202643151f4f028ee7d49f9fc30773041d7e69d950e5685df8d5df59c01b10b245110c8ef1f167f5cc8230acaf78e46d069edc8e39628fbb197e8333d269fab41be83588db5a4165b01357e8f08374b4e3c0e3b7b1ddee820e1785545bf26020b069706e33c2e8b33389aab800ff13d8361df11a10d60813a540cc275469c9f251e366f3674a4b71fb74c09f215f14ae383d370dd8885a73dbddf1e8b30093160a46a60edb5d4fb21cbfa34ba3a06cb82dc73c73d454b0e34d809d0230ab5b5815cb3f534a470fa43e43a5fd64dfc23815311238178fb4e1bc0181cddb1c295ef31451c341f3ba4f2574543d64094556a8852eae541d0ea98b9515db37bf6373e4437eddc81c1990689e147e5fb7c51e3a0c35ba9d8c1483cb9d3899166a5159ce674ec25f7f161a6d6a8859ec4ddbf5c2ccaf6f1606c4832d061944775aa9829f2636ec721d097a", .Okay}, + {.Sub, "caafa58fa5e3461b95e095df309c5051e61e805ddc3a0d8ceaf8d6f4eb201712c4a4c0d21747b662a39916ef61117a61b985b89b35c7c8889d5bf88a76b87b7c3c96c968b77ccbf90cb57dd2cac84602827fce2ed6910b02e8f1a6fe44daddfa14b99d741adebb258e795dcaeddebb2c203975a5915b5b0495fd5141e23c8b704bc31f5e6f5bdc2761e7c16813b2132f9d7e62d2f4e8450062931ce3901b26fae2c2e5ad90b188ebc3c739a4324e746c95ade5547cbfd985466d4e1533b15237a0df2f18958913dbdea24c272930e1fc3bc256b0d89012ca377fbc912d0c3fc87118ec5ec98a3826eecab1785265bbc1e0c72bc048fe7fe2d16c76f67f71fff26785d118afeb277fb29b8eee08b03c78ab30165af26172d1163bdfbd020ff652da1d97385d9a9b5a655f89b628c783875d4fa542a22b839d20c696b0a9fd030987aa23c172e968e05fcb28e6b64191d52b079d51e5ef59337eb08bde0fd792c2bd18315977c2c526b309f93544fb0671d90f838c743f253d53037b63993bb0fa44f49d0a87f11f2bfbe483cff219f65c7c66ed8cf56c4263555f295a52074ee04997ae2682f34bc7fd9abc95ee0617d4e5c6ad53e0c1b6243815be7c64eeb365780d6fd2959aba6a7c2055e4904f514aea2ab06406c3caece10e23c1c3ed5442df1cb28b35541599c3f46bb77094b4857f6d18cf19e82f341e3a13bc510257c1", "7d39b74c9796ff3adb5b607b171c9aad1e105467efbfad96cf974efa47a9fb84c9aef8b9f3c9a56c8e606c64b523ee6ec5f91a65e3edc69010db7177ecdb174a5ad70c4db8c88f9e53507e2d5b9383ca87f5b972365bb0bf34951883704e465697dd582f8380917d8f77fb8bc0b736b79cf27455ac3e497f36332eebcc0c21ec10f5bb84e296d334a3d648998022e772b884ca61754819d8df5e9d7f68106cf5093108ab17eb879c55dbafff4b05e4714ed7cf75fa91a54c28a63c545df31a8a2174c4a82408db3f7ba6524f6b6fa9bdf547a6cd487d6fce65ee1c4e9a5a31cc71150865b34d02e393d6ad3bca274c0e2dbcae50e4346033429ece7ef1a05eab9ef6d6fea55d05e644815c419c4f3dd8401438fe197584a4c76e91de90ecb5e7d404b1b2b928353673a9f1bef7974b3948c0bddd80432e0d98a98d42ff8c3dfb2456f46df9c4d8979a9d2ad09dd5a0d002115a5b695bb63062b0593b804e9abd9e2602bd30625d91de7d4169518593f92064c72b7a6f8bf55ce1ea2a0622db06e57431c5f3be57410f574a2e6c44b35e148c2c22cdf85548e500abc8cf57867a88e2f7ce5ecdbf4bb057aca787bc0ac68c00e451652aca43f6d569d0e08170de32f9664d6afbe1d3a4d79891a09b4174bc4c1737523170921a4804fd60e750197535c61409c44c7a755d7706dc428b61f662aa81200ce396bbca42deefe0e88e", "4d75ee430e4c46e0ba853564197fb5a4c80e2bf5ec7a5ff61b6187faa3761b8dfaf5c818237e10f61538aa8aabed8bf2f38c9e3551da01f88c80871289dd6431e1bfbd1afeb43c5ab964ffa56f34c237fa8a14bca0355a43b45c8e7ad48c97a37cdc4544975e29a7ff01623f2d2784748347014fe51d11855fca2256163069843acd63d98cc508f2be1178ce938f2bbce4f998717fa02b2783347f64280aba05d991dd0278c6014f6deb89a4e7488ffb46d615de822e34391dc711c0d5be37ad7f6a6a707180389c62fbf9d7bdc1383e467aafe39012a2fbd191a04292b20dfc0003e3f9163d35435af4043c883e6fb3b30a7d6f64ca1faf8ecda8778dd1a146c88efa1a0a8e21996e1a32ac6c60fea06b1bdd5cd8ebee2c4ecd4dde7123406b0618e585a4726623f1b597f73130384e148ee76521e8558f881d096daa70c50e63532f5379249048c52dfe16186bf10528f642f67c93a3031c0032a28f88f8051ef22e9c47606794d48cb7cbf3757278b8aabc60f9cf9947f62191399318d5f35f806b449432c7eaec8d39a185d542fe67dac16a2773ed1a705e7d9182afc865c0b4b65824258c7c4d430fee664a0d0e59c5c9027b96ebe0414054ab846d4287451409852a9ed896d748bd52efb40fd62dde992cb4925a5ac6c61ec46306042969e6ec772b8fc91f4e96f4b094522923890a6e4df9db4b9d626fd0dd61216f33", .Okay}, + {.Sub, "-3c85ae6c60a8305fdf5d28a153c34433422222a51f35e2610b5690562ca0eaf7d46c3fb8e3ac0f8b36473b4ba8479945b6091d2f6f165d89dc5b71ef7eda9dcba89c1b133356f0d61cce8031eef8c453d47cf818a2de5978883cbbc43d979b56b28c0228dd3badcd4d446c2528141c51773bd74753f965e500e3d68cbbb89d7caf109261a8c88c1ab097f7f470a4b8a297eb0fbed1491e6250e970e478d689aa05ec257137e056dafe4fb3eed2f087769c0f9da6c3a80a11ed0e95f762a1c67929d45af6cfe6332bbb79509921fdab5a70ab501950a337b08bda30fc84702701989813246aa514459315f4c16f87e5e8cb2eb9a0b839ea8e8b8286e92fee2197b2b752caa0d8faf35d18c396d2d5969516de3d15304e88fc8a611eac37dc44e28203f19d9dcb21e26129fa8f74c89f69b6a8c3f10add29aa03e5eb12d46f7ba53e1a300684acff49124b256974ae0cd84e6306ab4c1330e92dd7a68921bf12c2b272d0c0a47ae24eb45a7326f3df489addb348ae45aa27638e3d6938ae218ac9cc2d6ed1b85ee6c924322d20cb1966b4676ab372a879a255a9749b7359eb140d5ce06d7494023bebf3940c3d71c15af37dc8efe6088a973ad8a8eab95753aeb824dccbd32fbc7f2ac733c80a0f469e7ece6057aeac8a5c219edfedea91d88ce92ab156e2872972430a266af937ff2aeb0ba6c34d823278d2ef04799b71880ae6", "b5d648b835536d0b1c8750ec0a17d452545658c0fa0bb2aa5e5c37e6692292368e19e086a1511e9b4a65b9f18ad58355d32234f74aac690171715a3d6555a4227a8e230d49d8fc31f89f775daeeba385e54c9e0ebbc551696b52d13743688de35897632cfc0b75cdf9e3988105780f27b78b37effc82ab08d6fbf807b6403f671c76f0730570d46c7ed35198b53f37a00d0c330b562db1447ceab9e02fde11bd0c22aad245924cabac1243b7f095fba14b8158048284678c1f311b64f6223e9d95a76fb3e82f5fb9ad247dd811db179f74c9f00da25c169d9529abdcf76cb09e8fc2ae14dd9500b5c8e9b405952d1bcf99328051294baf819e24a568fca199e1ff7a08bda27626208329155a0f38d09efa22a0c873d5888fb3a39ef9690fddccbfa3acca9df7d0b355a0f3b651096bd6979d895e29361ebe96761193614d91586e1eca7863608e4a57673f598a80a36f03eda80c6e8af215646f5d0f525f5372237185ef8b61dcb4752e8fa149dbd7ea12212c06fbcbdc669a4bf106f2aa1d309c3ade86ddca93de0a59a6634d5c8bc3e82ac48450e97f7887b0181cf6e89a6f6848cb530a69ae973ad8f8a4b1a911e5b3cafd97e52e48697dbc7b56ea90f265ae769c61638c7362bfa2100147e3225642203dbe01965c53dc33c17cbcf88155388af28c073e80024bed9b8d2ba096cba34877c0cdebba09263356bfd1ceb23d", "-f25bf72495fb9d6afbe4798d5ddb188596787b661941950b69b2c83c95c37d2e6286203f84fd2e2680acf53d331d1c9b892b5226b9c2c68b4dcccc2ce43041ee232a3e207d2fed08156df78f9de467d9b9c996275ea3aae1f38f8cfb8100293a0b236555d947239b472804a62d8c2b792ec70f37507c10edd7dfce9471f8dce3cb8782d4ae3960872f6b498d25e3f042a4f742ca2776cfa6cdd42ac4a8b49b67120ed0437d72a386aa61f7a6c3868317e790f5ab462c719e0c3fb15c58c40516bf7bcaaab81592e5689dce7133d8c2f9e5754026f2ff4e4e2103dcd97bdcd7a0285ac139483a14fb5bffa8c704b501b8646139f1e1859a1029a72c522c8fbb79b2315b88434f2113e041d8f0e20e67341100dddda424118c3e04bda5a0ec22af41a79e683bc2f295b6caee45c5d20b404e464d4f341348689a5bfca635bd0cfdac38fa7ee80d8d9369b264c2ff2eb0475250aeb7ba9e22fe92470398741e6634d5e456b02fdcbf03298902c83dbb2084efd474b5417603ca28895a3fa0cba7fa68684d5896297aa72e8bd3841875f2784f9577f6f96321ce3124b39050d3ae7cc52938c79e6bea832e6d04e2236a6cd93193ed7dedb8dfa45665661041e4a11dd35368349348f28d86d5d80b5729c0d51080956cae20b8757b13af674ed10e3e633c496e8e67f24556140686639fc1b6aeef3b0e501e32dc1537d05b4356bd23", .Okay}, + {.Sub, "a095f1044be748ccd5881761e682c1907f9fbfe838ea0056450991bc319311bb21d4cb07318424fc418f7689f55b7483cf55fbfcad247a6491494122e3b3074c3ca287f0c96e2e3904aec9de10e8671a3b2119ca9add91d8dcb2f7aa8fb25911c5234167fb9c927f78c14e54e8f3397eaa85cdda664c872c8363b6ee773d9b370b4f34a1b70e076c8300247e8fd1b0463612f0e054452ce7d43cb9195115652318c83f63b93d4e995dbe906d6c5fe18ee0b1f563e492a002e1089ee369be233b521153b94ba73f3f0073ecd9981db13be7131d4a6fdf09f49ed681f8dd391e092fda68372527e0af772828533dd804246c2de250386fd62e98f519ab73874d158861d238c92df35686ea1d339de5d248e69b0de627543e9df7d7a747d1f13942cf48000eeae8b42d59f0a4dd894dbf5650cd2aa80da68f2381a0dc6e3643f3e61da3f69b6fc28822b76f7d8432f668c9876e0c2940be4ef48dd3a3a2e1287643ef90343cdaef6346bbe2ca968bc7e448e6309f1983a402619abb9faa572e0842392fe848c9f4b6b293e160ce1072fd3929108ea2d3bb4c03069a9526a2b15122ddf566f687fcc1cb375d70280958db7ba91188d1d03ab701a390f0c4f36b27c760e6b2259575b7517e745903797da7b0504124ea10f654e0f5ce38588d37260da85a10293ec2de9f289a0319b3a7931737b97d9994513094dbf724506a31c246", "4a01429bba432303062fd532d46aa92ece2801e28b2c41d06daa485b526263295439fe089eeb89defda637a27f3f2707b1fbf44d6d1a107fe36ff4376d34918539a4a738cc74d485ae71938788a4398c5dde51286e8ab39a77005a775d7b292978b64803cf41a82df40bb3cdb262c684323a93eef908ea99a8b15a817493b2fc52e0d4298c496dbb247f5570d25d93f771344d1d6301d1090a087f8eceda4e053444c68d4638649bc5419fc6528c55adac378605b0314fa5d9d8fe53ffb29ab54f0358519b79c54815a8634e7b49e0d48af966c2477d0c10dd76b8323020c733770ee8f35a032128b2559ebc5ff75cd7d9851a78238270d997c4518c37356be7abd11b25cff02b6ee3129f64bfe733207a8d6846943db2316ac0a357f61705741d8d095632a10631c51c744e4b1bca45c8f8429d32fdb9190f6255c43ea0c3aa93c4d56c6ec21d7812a09ba80148069c9be1a6bfda7aa9ac52718e619be8dd19bde078f6bd2523c0400acf81c08c72cf64806746df53a988bb6412e340e07219fd702b2a232a74e7500f9796a6a50d271324abfd7240ecfdf59e7ad02f23afa5bc668db35893c5f5da70788983b5e389c695f611fa93a6b4ed1d9b5664f0ec2eb2a1a92b0ad1e4d4bd1db11bd464c3af7d98092606b4c19bea889b8f923f9ab881af5bc900e267a6ccaf68c69039967e1738d6516e4b2b243d950b83578b0454", "5694ae6891a425c9cf58422f12181861b177be05adbdbe85d75f4960df30ae91cd9accfe92989b1d43e93ee7761c4d7c1d5a07af400a69e4add94ceb767e75c702fde0b7fcf959b3563d365688442d8ddd42c8a22c52de3e65b29d3332372fe84c6cf9642c5aea5184b59a87369072fa784b39eb6d439c92dab25c6d02a9e83ab86e60782ac499b15e80cf0dbd741c4ec4dea3c2f1435bdeca34398a823b171de48378d67304e9fd987cf0a719d38be1347a6f5e3461505d072fa08f6a0b8886030dfb67b02d79f6eacb898b1cd3d0675c19b6882861fde3c15fc9c6ad1856d5b8cb7f43cb24bf86c4d28996dde0a74c92a8c7d814ed65550130c81f3c51e12ddc90b712f93dc7e7a3d77dceddfe9f286c0da59f93168c6c8d1703efdbda33ceb1baf6b8b847adfb94d4308f3e31f51087d4e80adaa8d60a723e86a9f7a3303b89df212f01006aaaa4cee1dc31ae622ceb8c65696643a5483b621541453f992a31afbb461dca3f867bd7fb14cb3b717981b037d2a45058d8df578cc7164d96283bbfbd1ea6ca41cb43d1c93769cdf01215ebe2a5617a5f0510fc1a56738da17d218ed9432f68fbd55cecf79e85a2f7f1e27b92bfd5a7104cb673556e8e7a3b98ae4508fa8aa3d27cc156a7e7a518e400d2a91bc40a4193450b459cc8faf78b5526aab4603de076f85bea9a53236dfc992080a748260605709e6218cd12a6bdf2", .Okay}, + {.Sub, "f0a0db0fbaa540b12b193b743b13d539b05f3a82fe83fd25e2c307153035dd81140b7e84f3840314e4b4e2a6dd8806eb27ba9c6aa1c414d39af048866c2dd2b4d41a84d87704dd3497edd9f5ed7855ce7863f76288f149132614a5c88f2672c0be37e5f160a91da89afa36ab6d4f80117225796bcca49c708c2ee007e35f3722685b9a31e45d455ec2b1540e041466383d94f70ed3e011fb14d605d3cd294be6a7edaaebc2b304f17da4014f6fa8cd5c27613fd00c7238658168a51ff3c5f44e4f96ee08cc4c653d53f2a31f22370cc6f3613e7cdcd2b171492edb4226a5ac56b6bb18450be8cdcbb0e4ce01cb656e1e82a9939ce69c54af805cafa2204562eee929993383a32b0cfcb6043f3ce8c1f538ab61b72913c6cb4fefffa5d128f4c6d5966f78dc9b9d4df810311ce05b8a9babf2ab9ea2c2023e295745b76e626aa8ac7026550705d9a742fa4dbf040f161f93676026362641c2b945861b279af6c8db342ae44bf59d7c13dbc5b504942ec8cc7863260192d61e4a0cfdb813ebbf4c1cf28c08e4b1444611b817e235fa6d227f504624d783fd0b6dcd16bd2c696ae6af3f415fbd157b6b08aa1312eafda64e3bc0c915a56b50bde0f18b2e124f1338301aae72c7c8293c5023a7013a815aada1d2398cac4f10ea3d7fe8781e9c2b7f809336de1a2465097c52033f2fae90ac2fbdf54bda82d9795ce46df898e01041", "c4d06bf05b0040da9401596a64a3c35193b4c2348076581fce97eda28c0170630a3ae4bc870f865289b933b1ee44265104c47554447ff3329beb96d37e8815492911f1e402d34443ec930e57cfdee88eb0f5d4dd2b5eb8c61f5f975bc7082dffc2a5a42291116cab373bd36923d08e8ad8701d46eb87a32ed60af2e4245e9e3ef7c5a5e1ddafb57999d96ae1540c3900bfd4a7bbe94fef521489ca16be34aef5b14302e5f7c6eb02914aacf00f1d68887d42e453c6d91afca5a893f8b27be1707ec5c06817e6a33ebfe854301549c5f3bb38bb3a480107edaef9cbdd18ab1b140838e91b428a80471f15a26da3d25f2214b78989fb09fe14e38e5fe7e0e61b1d4403d2c487f804b39216a049f84718057eed772a76cd0bac0fe0a9786a68115c49e8c0e96dccae1ab31b2b3a6b33585d080c5d654b9ccc8a7d6e376eec47055daedf57f03cf3f69feb221ec025c86d8dbc25e14e554dd47f3ff2cfd6ea4d47268ccd22b8177ab67fbd41443e1fd4588b29f02ba45c5372ea5963e73c48ae150e49429225c99279bef2ba80fbf373ef4d4071e2f5e7a338697bbf3cb6c75864fed8dd1946e7fa76e3470bbafb5a41b5bd22ce0464e1cac157676a8d2bd4232b8fde5c05280aea7839d89fc5ef88baabe0ca5d8fe2db32b3951937867f1bdc852b797f410a1e707aa64d243150b332bbadd2fdc858c6945fbc676966aea4f3f8cd", "2bd06f1f5fa4ffd69717e209d67011e81caa784e7e0da506142b1972a4346d1e09d099c86c747cc25afbaef4ef43e09a22f627165d4421a0ff04b1b2eda5bd6bab0892f4743198f0ab5acb9e1d996d3fc76e22855d92904d06b50e6cc81e44c0fb9241cecf97b0fd63be6342497ef18699b55c24e11cf941b623ed23bf0098e37095f45006ad8fe528d7e92cb0082d377dc04f52ea9022a9004c3bbd0ef49cf0f6aaa805caec19eeec59545f608b64d3aa1e5b7c45991d68dbc01127414a12ddd0d12da0b465c1fe940a4eef0ced46d33828834294d1a9839a350f650dfa9142ae822f29c95e4d8491cf2b9427930efc6df20a12eb92569a9cce4fba3f5f47d1a525c66efbab26596a9f63f544a1a9efb9bdea8cb246bb1f400f562d66c0e36a8badae8f6eceef3344f505e27528323ea3e64e39572535b3abe90e48821b654afd90ce64ca11e30757d82efede46a891d7417ed7e0d86d437952b6443d4dafa24e67082c347ae6fc569a8176e4bfd63da2883781a53f6333f0a9167bcb3daa3dd3aff9e31b1eca871efd96e642867dd53ede632eefe0c4a1f20dda06651105e7d6622818d51b0487c19e581790bbf09118f2c4b0c3a08f667986fe023e2be7a851bea94abcddb1027783e111b1c6aeccd774a9a9d11c5d55244861f902bfa6540713f5d3fbb3ea632f2dd1ee7c7bd4fe5cc02cf313ee79bcf57b0749f3ec1774", .Okay}, + {.Sub, "36f158817a97aa5aefdfd3bb002066577c41a556e02a733b529edf5f8446c44a8036406a43b829c8297eda2baf2452a26293fcd87f984eeafe934323819b2fb16c95a8a6bc046efb98efae60b278ed4b435acb17301cc61d25a82f63feb54eede45402379a6549e5409e0207cd51957c58fcfefd87bc57f5800db6d52c3ebb5acd3709a4f508dbd0a539ffb9a0a0c4f48627e61df93062f18573f453b9a5bcf55cdef870b30439dfb7c1240b0f765212bd9db863a16ed44d3383304e3ebbcb417cf68a9c86115e4ab7e472462f79f827e27e96e6621513c3266d9ad398de03d36cd4c7cf409f230f67ce60e20cd59d9c47baa4489f020fd1263c0c10a8ffca7ead3d6f8a5d94d03d316a08ff04f39cf62397a95573f895e53c913d70a5943a56c062702186daf566025594dd14294903efa4d66d8820f5efd5a0fd6e452749932762df872bafc00a88e6bfde230fe678297adb69d24ab71e22bb30e261d92a5a1e9e2226bbea1d047250fa6b6fceca35670f56b59b064709189a3216fb7dc34ed6abb04e9f7cd70cd64e4e554e6e2828161d76ba54677334fd0157da78f000c2e5ed27a2ae1da59d857d00b79e012ee04f076c4bfec0f69d864625fb0e42aeb20352f7be4698910e118640948486c0cf4494d115f8164429a5770928dd6b80a57ac310fa475b9b3be9050baf18db971a4dbcc0192b6f1b53884910103bf12b2b", "b1dc7ca614a1ad385aac218858e5880d8c724330420eca56df03b466b7fc87eb0e4392534af878e0a7b320e4dba8e006e4235fca7115f030a59a2f628b71a4c001d4cca6c974edee8b5507d09136edc26d9ca1811e3691ebd67508fb82c775f1c23f3ee96d76bacbb91439a38cea1e2604580bdeb69d2038bdcc1e4b0d2bdf54661bb536a58ab99d964d93b8c23e37dffc8ca037b7b76278f3a07bde28f5d39fcdbd2214cf158fc96c1a97854679f8d1e1a3c05317941343911a5a2eec4247589bad88ca6ba92e00265200cb5366e1d2602e2917530f16b8a24ef41ee18c7fc5f9158203aba68a8cff47786865ea0e02778486cacbf69f457a42491e63364e265d58b1697d5607e0df82fe785d3c3258f1698a93361bc1b11b4073d3fa3aea07721504f28e2042f8191fe309b8f427fcaaa2afbb9309840e98a9767f32e2241201d7ba48cf1ce3bc5dff18855025e07655763506ed0f6c601c6feeb23027b02fa55c2b24bb48288457528cafd05500b4cf12d42d392e05b0595d23ee0e0bf807b03093f1c3f15ae84d84d942b47774082786fc9766d5effbf4f4ef7db3c5cf5b2e81b0f1de419b9325442370b034ad3e5c7aa8aa8165edd5817490f63f39501f411fd0e4bf07806fb003c2a1c0e5c21d15a5e8e5732f215aede0c0ddb948306f8226c3463bb88a3c815381b9857578373c1957d382eb93bfba8db2def0651e12", "-7aeb24249a0a02dd6acc4dcd58c521b610309dd961e4571b8c64d50733b5c3a08e0d51e907404f187e3446b92c848d64818f62f1f17da145a706ec3f09d6750e953f24000d707ef2f265596fdebe00772a41d669ee19cbceb0ccd99784122703ddeb3cb1d31170e67876379bbf9888a9ab5b0ce12ee0c8433dbe6775e0ed23f998e4ab91b081ddccf11393ff219d72eb7664ba19be86ff876e2c878a6f5016aa70de29a41c1155e9b459737a3703a6bf240607ef76253ef65d9729e0ad867c171eb6fe2de597cfb56e6d8e8523ece9aa7daf9230f0fa02f57be1594b48ae7bf28c40ba346b07677d97791786591470662fc9e2822cf48f7454063d0dba3683a7b01b41df1fc137a3ae18f57958489562cdd1e13dc2232bcbdeaf366354a6afb0b1b294d107454d9216ca4e2ca4cadef8bafdd94e0ae88e1ec3087910edbada7eda74dac1a36d23b1d51858a72d15f9fe2bfb599d1ac4b541f9b4bdcfce4e85d586be08fdff5e0b7fe50192446086367f68037d779e27bea740c2f1d7128e34b8d984e3a3247483db77368aed66094be0116985dd126e7cc6f7f397a33ad5ce984894894f3023f5f59fc722b912337e5e0d733c5e82a4f737fb2e6afb30f6a16d3dccd926786eef619e7d820d3c5f014dd11117cf7b18dd314869b7b4dbdcafca0763b24bf45cef00984e760a6c99e11cee5c97ba577c786c3244a2ceb473f2e7", .Okay}, + {.Sub, "-42f1afa2a4a57b53cbf4b1c62f2761987884347a0effede635bf8304b2b3cf27d1519b2eaead9141f18fc0732912b85ea18d693a18b3f6a9417cc171bd9bb3b1a6af2a5e66ac8933c6c1696df4d8d6262f43bd12ea560343ee02005d5052d2ff085f9442319c79ea096ebf23701ed123d863f2de6d8615d9e0f3bad4a442f2b7f44be568d50f42e28269fb091252c51100c3be71ccc7869aef138a388717724177fc9035d876041df8c839e373d9c943f8d920060613f95de8e261ce28592164931772187250489719a855ea484051e87334e3f7821ce1ccfe9a09d5317a2fd99d9701074adcd8d245da0bc87c98cee12ceb83c1a6d9e99ce184f03af5dca32d595377054a1a2c0de59c9277d617a769e1c85314f39d3efad06561d0a1b5857b76a51f87eca5c59a1ae76fb070dca06763eb471acadaea2d7a6f83e87cced081a867a78f080a1d3b08e964ce010bceff35233b13b80d3eb89f87cb7a06ea6a70952e49e9be8ad36b727e37635744a3e699cfad2eb4aca8b849fb349e860d96f0c8d5c1c01fcfe8e0e5fb82fd93c2d280fe363223a63d1a6617ef785b79e8881b077b864b10d98066b13a480faf9b4206f7f9257e46644643fbb300c1f0e6be18ecb48d59a35d239e1096964aba53006c36f3c9d41cc34fc976c33ae1106e5ee1c572641bbac6d3960dbc8bf10f7e59605624852ba6dacdfcbecd62eb569d15a", "d2be2986e918d547ddb0dbd632d42a7ba0e365bc2a7a9b92d609ac89ea56b1fea712905c648002c9ffb18120ef1e1a850b682e513e0f338713e8e270bcc9809a9e74a191e35668d6755f2e9a8e056b571c0e7525fc9f4a1fbbc68584a67a546cea41f95c9fdc8a876ccef4a3641f516b806449a4325a85a62ba650ac43e4ab819b571ddbf4f816890a78f1e15d4bcf6d48dc2acfee02f7e9ad91a9d532f1ada3f973ed7fdc25b4a6fde5f2c8cb32fa46868e1bee40229570ca02e86e3ade9fc2172d31b555fb09d42ff7cbc5c0695c19b38e1ad8b0c899cb4a7aa8fc204907e1f00927b63d078641c1eaf7db5e85e845aba93a29529c237840b7585da71c5cf89a1b088ea857e819c0f874c621803784f690141864c8f3a65efb4c31d389864147f3860799e319e766889557167e156e8cfbe6bb076bd1c523760f287ee6fa660f1896a0930d5e60973b570e093f94954b8b2e4f9e7aceb3be6140925c4a8d1b6e723f35e259c74f48fc634bd8e9786ce1593d79e9682d6bcb422957d275c792c37e371eb966b392399c9bfdc8a8d66f17fd16c871aa1fb48084c1fe1410070556cbc5920e7d822346cd5e1a404a0be49e8663fb4a4af67dc24ef4fb0688d3df177abf20d16ee44164b38d9a848e7ee1dc452cec3dcc58db36765622043327784a8ad6812544b7f94877bb07c8b3e2f66af84b8d6fa683b450bc569c871b7480", "-d6ed448113632cfd1a7026f295c6a095286ba903cb6a9a713965a4ba3581eef12427aa0f4f6adbde1eca7d2821af460af58104e4df9a72f1a800ae87d8a33bd5b8df9437c9c13169b1cb45316d52f8b97f02b0f72b44aa53faa6a58a7b7f819cdac7f2a0c2f652260d65e0959b213e7dbdea88d21932e703c9b58c598e28daad1a9bdc3282490ab7329f9191ee70fbbe58e866b70acf70535c82e278bb6324c810f3b68339ad14e8dd727667027096dac61badeea083d506a8910e8b1d6431d8605ea8d6dd200e5da192512464ed61383ac1691828ea67e81a6449997360aadf89e297c6b1b553cee6489897e64f7533be77f2656d09c2120ecfa761567a272b6fb03ffefcf98ada9f523ded9ee1b1fb94ac9949b402c7960c01a24edda4de98ff5dd80018ad764108370c521d8bdf75033a9b2cb4198067fb1d076706b3e76e299f1119838e003447c9ed5ae95051853edd6200d9fba29f4859bd49fcb933c277c523d47e427486002446c20e5dc2ab4af6384cd4b2f7f74fe1dca1bad6a101d00b933abb63b22047fc542da1e5039727e079eaac0df15ae203b983cbae8f8707437df6bf8b1a29b1e1029b3b43c0050e05f6532eb13ae2020a250725973fc0a64607f66ba4b67b45bcf6ff3033aee89fb469897f988dd7cde289d0153a0d6666e1fcc2e0f12532a95383c6d9abc88c705a93e02a1430941ca92ccb3c8545da", .Okay}, + {.Sub, "8e50ed38ce4d12df29029953f479208d04039e8b1cc26a76328e6a1b50bfb2d70d852fe28d1fcb90247e8ce702db75cbf5aefcdcf3865434708760b0d8a69ffdbba048b27c201d33174a964caca3af2401d6519d82ca8856649f180fc9f07375b03753fcac81b9e912eb12d1c0e25eec13901c9368adfca79926dc11474b474711a1a3e3a7f6e4022fce12145317d86f4ae984cd563a7bb50f72e77d3e996f0f1db004fab23c6dd2acdc56bc9ec77f44098887d98c01f6d5a1bf5d284e5f3205b74cdd549aebd2594aef65ad774617211b24caf48c569a8d44f95c6af3a7a4cebeadf94f9c952c95ea034c5f425ec52193648c6c1a44fe115ff17e95717402c69f0de535ae87ad4d6289f3c3df766f4ec0d66992567587a0d7eb753872d4f34e3bd23301febc04469662e5e8c7e9b08a58041e7d2d5cb79b2457570e5b154cd00153d555efd123a0ba358793642bf8bacdb7d6eb99268b99cfae0a7561c91b97325771d25c8765d4f3855052b91d6e6cd8debae16920f497a0b5f5bc87b180cdc700a808ff3122da3b48cef8dd182028388b4000b6c6f3f869802c724b2408a8d45d612a408e23f0170ac05d236b4c10d308c9d9f8029650686bc1d55f6e9e4210ddfb296e46c48502c43c2b5768976b253db30bd8a2bbcac61bbee1eeb3d9be09f754e05df82676ead4e476da2a41f69692234e0f006bf6ce7a22945d0a0128", "64f65ff409e21b21d46a3d92fbf95f01c4b4adb21c5c578ad7fd473bd15e2ee53c2eb9fa9c61b245a812622f956a24737f3d84d4b80fdf40ca30c807e6acfcc953472ed289027bb642a6b3f332ff826031d82a7eb9e3930afefc4476bd2ef0dcc5e37d6d078fb868bbd840101a603eaad464daddb1217a4736cc836f91547a9a433d548043084650ef3a5c9a3f613ef36f55d0d5465e1b6c023290eb1aa2941b254fbbd237b5be29655ce5b85e2534962dabb69bc419e3254c35675371d225342225ab3a9182cb187a6d9b79de8dca7075d759327718f45ba0efa33c2af87b46eb99851546cc7fe5a53f39796486ea729ef1bb179632dd751746424f250115ba576b1ebded4b26bcb8190427b6834c3cb236a8c649acf324fa23ce884f54c65e44f95d5f93a97a575cfc8ee373b6f26f58a351fbfd1be0e22e24202f51e5414f6983499326f1833c1cdc56e28530d98ef62bd545fc1a9852fe8b76255eb53b85d03da2a189306d16c9bb137cef4e16e2cc3ac995f214ba11afde73a1842d194ebcfd22aabcbd689a11da11e218e8288a57a767c3a1e88691c9c319300d57578187f98ba84e7ddfdf56a8e5dc038ab5d612e4c3d74a41af1bacdfdeef8fa42694852edd2af5f5fcacf058c4274e5ad3eb766e30c895084c71e77ae3627958b950cfcc17fe3071d4148ce18518a014a2bdfcb6fe69790c6371c50ed2ca365eb0c3", "295a8d44c46af7bd54985bc0f87fc18b3f4ef0d9006612eb5a9122df7f6183f1d15675e7f0be194a7c6c2ab76d715158767178083b7674f3a65698a8f1f9a334685919dff31da17cd4a3e25979a42cc3cffe271ec8e6f54b65a2d3990cc18298ea53d68fa4f201805712d2c1a68220413f2b41b5b78c8260625a58a1b5f6ccacce644f6364ee9db14093b57a13b6997bdb93b3f80fdc60490d40569223f6daf3f86049287a86afa9477f710440a24aaddbdcd13dc7e813b05589f5d4dc8d0cd19527321a09690740d081ca3398b84cb0a54d71c2153da631a409b92ec8af2987d314743a55c8acb044c412e5ddd7daaef472d1548412209c48ab3c464c72ed0c47a2c677c13c8690aa70ef9c28f323120e9fc0cc0cc8947bddc7a6b023802ceff6d8d5a26b1289ef396657055432be1aff60cc813040d6b8f63336df09300b8097d08bc2c8dfa0649d5930b0defb1f2bd78c01a59d0bf346d12294500313e0116219cf30d356f8be29ca3cd5c9cf578a0ca3f14b770c3a85f0d7821b0384677f0a03855e4273ba40296ebd16c42ff79de0e3d83d14de6d669fbd13423dccb1274c63d581f2104410c061da811fe0963ac0240602adc0e734bb8be2e5cfca77ad8baf1dfe7850c7d8126b7804090dc37faecf8243439a6f58dea0db7f755b206d3a2b3ce22d8652625df35f5e3a159f3899db24e495f40885096b4fca26ab5065", .Okay}, + {.Sub, "-f0f23ff8afc955ad8a7d14d6ccd8a60a6284d5e31550efee8b32bf5301ca0be65ef1902ac9a831dd29b0741abe0522bac3ec6b76d7cacfdfbbc7147fe0b13a71a468264e097b88bd7436b810e8f03f844908b6e74eb4aebb8356904c96a4b08613371db305eb5bcb6d07cad109b0cd90ad44fb161c81993390a6814aa6feb9e5f4c4292a623444be8bea269bb30c60486d0541521d36b70b3503a50c138c9b618ce27e6b5cfbec769e02f0ed347bc77ae33b3e01eb0a9135167685831e7efbaac97db4a2c9f85b4c5bf40a4c1e483263b2139925594ae63a0b9ad46bebb182313d869e4aa02cf51f82636484b130938d245c87b2351bbdb0eaae9380a489317baeae6401e4f4a12cf7f0ab172d9b868636f944ebefed992402078482bd5b4503efaf13df923442892fff98efee1550a5f45a1e2e78c19295a78f6aeb628366c96538fb1a2c9852b8cacc367178445dd2384e51a2a42bc0524e72038399c1bd6460e970263674515291cd7ac8ff980c652307094ed13a41d719db0ea8e906c79c4494dbbee50f147242e2032bb7fbbd93fbcdb8475c80bc5f77c56ee40c5a86a927e8eb4178b45d8243aa54fa001c8c61dca52ff23f060e60d1522ac7c74b18254a67031591a6e2cfac000971fc82c9b673a5b1777ebfd9a727859930fe6d7d6c2e767bd532b5ba0122f0cb95029b80b9192412e3cfd1f0dcd813ace6b71663b2", "bb933902b04ca9e7351d95ca0bf679731beb40d19ed417dfabcb6bec804a3a586f82f706b0fa3cfacc0bdf2f84ba139a1c6623c7097308ae7c29d2cf2c35a82f4175618c361eb37d641e5c84c42f60d486774ec1d6bd01836903658bfde0d8ce6c4ca0038c4c16ef42030e078bd4b9cbbe666154ae60c1a3ae65f8c93008f77a35da9b68b961594bd82fa465e320376e28dac41951f061d4946270be13b9d8de1390bf7d1497dd3d771757841aba510cd5c553f2ea990cf053b5f991b994368738b70dd4d5da7ec5224702695ebd0ea429e95c7561e680eea4f95bf3ecea4e5a590f4d402aca02a42f07b8f666842d03b3deea4dc3b344a14781a6adf4c4f50c038fe3518dc6afdf8237e34a9db281c7795fcc94513fd7a004c052f22e18a3fdaa24af75dc4bbde9360eb5f6e947693255e1d857c6cb863264a1a37dbafe25b0e574bf23602ef7ccd55aaf72fcb00a1b2749779f1dc0609d283fed37af4e70cc57df07ae85568fc0a541d819ca0a2b7d5c2f0dbc575bebd64dd340e0d7abc31c7930f3ab69645b58c715d373e5c49760e7824257ef645e13ddb72aff2145edb840a5b97f81db3bb3c3f90f1bd0414eb2ba97f0dad94c115ae7fe61e71382922c70b2315b8a56448d26c038d4bf22f0bcff1dab030e9fb2d2a67f4ec77cd4ee3a3bf8ff7b8caf3f823616eda6f2a7c7767f3fbbc63699b9e2d4f8f48b6180270", "-fcab7388dace204bfdceee336d980da1944389f02f3e316c85ef7611c9ceaf8be5e9bf9b34b7d5acd671320db650c3f465b2cdb34862006aa389b1acd37494f4987f7c66ccdd73f54a789dd93533359191702bd36c207ed3b9e6c6a55682be12f9fbe7b33eb01d3a6127fbb1826e192d692b612b6767a54dcb8ce0d739ff495d9821d2e0edca5a53496d20e2113e63bf4f92ed93b255bd287e49cc17f4c838ef6e1b8a632e456a4a7574666576276c8bb097934119b422041bb1e51c3a183f133d09258017560338ae187a72b434034df4b22eecaf694e48f5ea6a2b2a802716e317931ea2d99549c553e0141798d65d5f9a76571156f1faff26adeb83d580cc6ee76236fdd10c2af014294bd776aea2ae8f41b53501969e025389b1e03ccf43ca515ed6eff8fe67c360844f5ca9c73919b83bb3f52e4af8cdd985233e3349247390470c629b42359821e168a80f5e73eac2e91c9607c65c20f6025714b6a471266760a11ec9ba4e9c21984a9c38af1cf8c9fa2a96b000947eb842b6f68183ce0c27eaf99ba55a27cf536062f658070a0a45dc6cdb770240b5a0e193fe6ee584abf346d970d2113d7fe9e5ebbd20a14d084eaeffec9acf767fd210e6388341481172262b4a4c47187e6c0cff4874f8c243978c27afa9d4d451ed8e1d763acc4fd2360bcceb80adf946523a6f71c5fd3081180ea0333b8c7b05633c2f6d2e6622", .Okay}, + {.Sub, "-bfa0de7442d6cfb16bbbff1593cf5999b6f1355f9580552e4c9950279612fa50f8efc33f8f502397681ce8a3ebb5f24aaa4e3f4bcbb7b38de32bb33ec38a6196260baafd00c0cf3fb61dce453603c312b5a596d9a76c9699245bbeb88030ec158f12a9d3883c17224949937e3751720314bd54e85337ebf21311ac26b49a4b107143cbad5cd6e33d7f5b9df83487a497d791184b6b95e0e5835e1284f96435a00dd481ea003f1a6e638f7c84dcfb38694baa1936df8b284556afe25f3c68fde64c590c39e76e02e7753dde7347574e456f757d0ba5ba5cb48d0cc059df6aef4c7fbd917cd4e48aecbe04c3b7474c8035e68d2af33fe8d372073704b2f86171bc3ff0200476c6d6f3165c58d2cbe63ee2307bece671aea52b03ed715ccb11aa54116b89e681ea6f8e96470ee13e7ade75f91e5d55540ea02fc8da3af5c6f9c12392ef0900c37427c1c29fc6442c577484f39cebd88aebdc550cb39f1be9867916102e1ad6eb47f2ce529a49d200fdb56cb7d9e6fe422663e8a44c5554ede95681a3dd6055ced4992f9ecb27b06403ef581a3714b5b485f6ac16b2c26ef50120bb2f39a562c67b328adaf348d6ef6d3c626de4fd63b55ae7ea1e03c1135167b88cea9c23ee5e130471238db1853eb245840ad847454c3961fd43af0aca523647c52578417b4261077704ec0686eb61ab13caed5d03f24fe356053454b2e86d69d3", "40bdc053a5f979380230578127867e23b6af677faee0f432c0e93787e229dc44f9ab53c54f488c3e799cd0932e245f45726c2d471bab597ae9adef99817d3453354024b057b357bcb237d6a3c95e928c2ca38a3d359e9dafa8f471b3125efe98a116ce55e9a37f337bbd5fc258cff75adcec002b2572e1ba3bc822c174f296911c470966364d64a539f573b90e41018f84761ef79f8d5b65c0576cb4311e092906198103afa7436de5f6b8cc7998809d55a024348ea040cb90b284403270465a12fa711cb754df81a48f3ead9d9395f5057b6398c574cdbc61c0bcb967968f55f00658cac5db99228993d04a1ce5b5074b1cca240204252930510245300ebf2cdf92541d2e6088b6470722d5912fcff3fefa58d1a3aa4433d0c59440af4286155091210d8e5490e93f917246aa7ae5f5bc931f409ef6cdd4e2be1bdb26b4e66258780f5887826aaf0e36d917bcf9c6b0410607cdd6d4b28be9b5f13efcb4f7cc76db76bd01cb204ca1964e0937bc270c68b1183c2b3d85ee4190481e14deb4daba3b0ca2ecc8e610e48fc40e8cbd3695da973d39a56d93561ce670cb051c1b01511557b53a55e136326a5f329b2879243c6cca3f5c3d3bfd4dc7deb6d43ee866653aa9d8a6f442068dffeeeeee1464520db38feb50e06267a867e13f8055192ddc25ee513093ecd7c3bb9179364d68fbe9fd73e55f2653993cd37f71783b0718", "-1005e9ec7e8d048e96dec5696bb55d7bd6da09cdf446149610d8287af783cd695f29b1704de98afd5e1b9b93719da51901cba6c92e7630d08ccd9a2d8450795e95b4bcfad587426fc6855a4e8ff62559ee2492116dd0b3448cd50306b928feaae3029782971df9655c506f3409021695df1a9551378aacdac4ed9cee8298ce1a18d8ad513932447e2b95111b142c8a6275c0737430b233c4b43b57f392a823ec913ee02edafe65ddc498635515693b906a14a3d6b6e2b6910e762669f6ed944405f537d569ec2e26919cd1d20e4eae43a74f0e0a46b2f2a70eecd7d1347017ea26fc3ea479ac0240f479894016432353d31a9f51741ecf89b378806f8287030e91f827421a5275fa95d637ba85d160ed62f7645b81558e95ed4b3059d7a54306961fcaaf4103f0077d5d88127e8f5c46bb5b17c95f3056e04ab9856d0edaea785eb6718594af69270d0d69f5be9513b3534a2f3a661c08ee0f669905ae63b70e287099193ed13131af43097db38b9dc79208aff3a6d63e9d6e5dc9d7302c80b5c5e186cf8bb9d7f40835aebbef0c125edf4ce51ef59f38a0233993339fa1d3bbc804efd1800d113c10d5da8098a95b586aa51c7a3119823e76bcb9fca25a6a0f34fd6cdc705074677b18da0742cc6a9d6188bd7309d19c464ec16ec09d28b60f3019e2fcc72f4f44ec8a7980021af140fb4ead0e9517636ef4207d42460a870eb", .Okay}, + {.Sub, "8fa45ad55f98a02029f10e226ee0db95bbeb963c6f5f57bc3e36a11f10498c3547a5bc08ae1888ec102459a4621ade9a6e6a3ed68a96d1c9590e8306032289376577b263e9fffe31629c4f1b7c2127d5a736b10afa4037c5d6b7113bf193c75c976a1f395aa8a0bef937d62f406f48a514d054b1d86d00aeadbc7f4750137f22ce9e05f5539a76c4e2d0b7afa42fa78d30e1e16663e1d5f5c0f59b6207621a71393bce02dc5ec57024229a8ab94021ffdb4c59a4c2a3c99409b2ef8f1a290557be872537bd717a823af6a2512d5c5a92b8f36b41e3da5a66b6e71b02fb24d3ab69500f75f8a64bf8cabf823db628923f8f8e3fdcb47cbffbf30ad1479b05ede7426693a45c584ef152fac9420fff46c92290e0b06cba6422bfab8e49dcf4f362fc5c871ae74545383b14d16da99282c94ac8e708e30ef1e26c7c82f630ff7aa4b3d96e79a5020bce488f054fb0714d5886e05ecb98e967d30c7cb09d7b396703c699ee578c0a41a9cdfe6c0269365b5cf652e9cf35237516c6f934bce34a3b6fb73bb8779b8edac05dcc27063c1b49da4e19ad5e28b45d30db6ba10be408566b5e0db5418567fdc4cdf150cc43f82ace26f5f8948f981fbc24b7e9dd5a94737aa2f97aeab56843e753617d1dbe1fe1e929bdd7fa46fbb7748bdc758517fb103cdb5d4cb21bcc6905d8daf40c416e8671975c14f855ef09f6396de3bee18eb10f", "111231c9f4175a00d286ba161b309ca719b870dc8ecf3188550f2d642e8e17ad90dfd9b2b301876e44cefa68cc54f02be88d5f36471cd97bc6a0d6565f0fc3f32adb6ac23f931d214a477c247848e2fdeddb2c8f647fc6649cbc51fe7ea62441b71471693d808df4d8873e79c22d279cd3df3ae7e23755676c42f7f324697ecdf774c4d2d34ccb1601f51eed01e642b3b25f83a2a32002e8323392ce21ce7b9198006d29c2088cc411538ecf99e01f21f6d32e47e51fb120076d3aaddc84069e203fd5d15a2c3015d187986e97c5a2ba517866646c745bed66dd39f3618daf3ff5ce17870e01a1f7aa82a8b1c08426f330d982df51d73624e2118281168e008390cecbf5910997c1d890e3ce648c574760bf99ccb72dc08d38d32a70b7c63d35de48ae377da0079f89213885c9f92286576fb2f322b93738b469e320a5e9cf94e9ea8a2a3f753c21790af5cf2a4bd0297b1a5b8ec6fe2be111c25bed151be4a219effbd91b41da62016fbc1558b0c81386db6042f29bae25f823906964847df44a0e0d81cac1b087b084d9d26ebd069915fdd0302dfb446eb70196094219282a2773f869c0fcb2a2c760d2d33320e42857cc01e59b7cfed408c843883d71b7c439a07d1945094022698d59ce728c205066df9934199e3c0a561400383714d63c12bd1c52dc5867360c35770c901c712cec04c562886b2f42eede96b61921f408", "7e92290b6b81461f576a540c53b03eeea233255fe0902633e92773bae1bb7487b6c5e255fb17017dcb555f3b95c5ee6e85dcdfa04379f84d926dacafa412c5443a9c47a1aa6ce1101854d2f703d844d7b95b847b95c0716139fabf3d72eda31ae055add01d2812ca20b097b57e42210840f119c9f635ab47417987542baa0054d7294122804dabaee0db98c2a24964d97e825dc3c0c1d30d8ec20893e5939edfa13b60d91a5638ac12cf0bbb1f6002dde4792b5cdd8418740245b4e13da4feb99e474f6663454a6c696f09e29596b7d8677b04dd7765fe795009e10f9997246b7381f7eeeaa4aa01203cd98bf5a46b4c5eb4bcfd62a589d710f94ec68477ed63b197c7aecb4eb72f7a69e573ab72ef81c1d146e3b58ca39586d863d9252eb62d1e13d8e369a53d98b1f398e7df996042f3593415c055baa9b8129fd58b15ab0fc9eee44f658ccfaccf840f8086257d2f0bc6033cd1eb3bf1faba54b0661d8261aca9f27e70c86747cc8eafed108593496f77898c4287c6f0ced5a4537ec5bd7b6d2daaf5d0cd2a38ad474d33cd5e4341381bdd2dfab918c2246a0b02a1ef2e413699bcd7c46b4b2206907df910d746a5cf29f6aef41b20e81befa6551d22bbb66958fdd1705f03c4e9d4234f4b93c198c2de3ec62d5d7b6a35c8754ce0e63a00c8a0305f3f7401cfcca57cffb1521544ab574f95cd83dab34a8f4d08c86cbd07", .Okay}, + {.Sub, "657e17ebcde2e639873c2980dde02ecfacdf48c4b5242e2504a897deef6ab97961c2d1db961bb362cea2ebf48854f97f46e5f28b2f2ab4bb3b4cb314e36f7d6e3cb075f0f3cbc6c72ba95c30b9a0ea4b62c605815c2eaf8894e79913fd5a905cfd1f09a0e04d246e8ebde566889964c26b1bc40e3ae1c462494dd2535423a733001fdfc8dc9ac8fe72ca66c5ca55419730aaf2006c04d4edcac36006a8b0403281672ac864023f534e0a7fbe4b532b38f0cf06f35e408d1cae4919db988d8a4fdd26c9ea7d0d36deeb38a20cfb35c7b6a19326bd10e2f5318b990000a976d8fe7f2ef2fde079dbb59b52c3bf628a84f435c5fe4ea6255369c48e831f5dcacdaa94a1981758ff93e10471f232ac8d9a76c228cc6d2577835f4f77bc7749350cf14022f31400466de406a3c83c6a7a9297fd7b6d3d46d11859aeda550ad5d653c4aa88738af32a9eae5b76a9f78611402365c2d8207c582eb860c303112165802f1bf181480396d601325bff74ca22f4b9490e9773d7cbb508a5f7e3d4ee5279c41a975594e3527034afb18a6c7bceb09a7719ec38feb81050d7d693991abd9323927dbd45c49ad29b5aa141f49b690bb14f4c7cd0ca0316b9816c0a7d1c055ba08d2514e38b3f6888a3fa35a1e6e9d2e7506d65f667103ba8e8b90599acac1df38b8c263c9116185a4240ed11e47b1a00b42bb50c00602798b6c8b9dbe7ac2384", "1d478bb659483365834dde84742ba85ffb07a1053a2ae90b6e09631b339c2bca0707ede2c4e1c85ed117b3902eca73440aa776b378343111acfb319757d29cbacc7a90c6aa29b655a5a5c5197267dd5be91df69aa35b784b0f2674643d2894dd135075c70c4f9ead04e27fe0f8c0baffa59ad87dfbc9a8fd3daba701b09c90891fca1a13834df5a6f050b55d9d4ced399174098a6f6f7722b8fab4864f34aa8410124a7e5165c96b0093fd76d02f870c1a027ce49761030265d052bf09fa55cfab70d2b5b5ea7cc63fa32beee8ecac11a6ee51a6661129486cc86217a20ebe42699b2db651ee3bad4c52ab378d9eece2f068a74533c6c59dfab8d575ad89cfd1666e7c1c412ce3633f6cb46690455773bfa34298b12ee67afc0dfd274674ab4a51521928ec67d5e7b4f55dc71a3b4f7daa0c9954292602f895795a170327ec12e334ef403ca78162b0a6e6119c5d0a86ef1527ee70197c64b2f922f1eac90dfcc4afedfcb0637da90db8b4bd95cbe7fd31188467235d9e9dbedbfb37b48a7c7eab33dd43a915665f09a44eb5df50857044840ecc4872855e41ae6771d5a4b318c337f00dac1d552cac805ff9e992c2aeecc307eeba15b9c659e3a61e34929d579e29a7b36feee072988242c5259c4676624039b1a4e7eea144407607c1e6bbcc98cd1a083485256010d5289e909b7ef17664bcbda21934e488f06aa504faa567", "48368c35749ab2d403ee4afc69b4866fb1d7a7bf7af94519969f34c3bbce8daf5abae3f8d139eb03fd8b3864598a863b3c3e7bd7b6f683a98e51817d8b9ce0b37035e52a49a210718603971747390cef79a80ee6b8d3373d85c124afc031fb7fe9ce93d9d3fd85c189db65858fd8a9c2c580eb903f181b650ba22b51a38716a9e055c5b5594cd3578279b1682d08545d9f36e875fc955dcb11c8ab80597b95ae7154e04a129c75e84d7682477b23a42cd6cc8a0ec6df8a1a4878c71c8e93348031b5f734c722ba18ab95761e12491ba4faa4d516aad1cbe91ed09de907681abc1593c5478e8ba0084f001887d4eb9811455d5709725e8dcbc9d5ada9b040fdd92e331bfb17d2b07dc5053dcc1c484303028589d474489ce45369bf5002c061a6eed0d9eb13de97fc51ae6a75503f431a536ed3e91dab15611960faf3d2ae67b1c753844ab6831d4baacfc3e5e9b4359c76adb0320c3eb253adc9e01f369c72325741934b5333585824a34ab734570cbc17f6130cb46e166ae71be89d39c7fd456f6378513a3d09d5a60d3bb69c7e2b2a3295dd6cb6458af296282c274518e00acf45cd38187d7d6eae20e1fab1d64902628974e20fed5cf32788645ee772be48eefb6d301b5088160b77f2dcc14d8c70ee2d2c44c2284d07a4788f91eac56226f2bf0c345c90f2fa316bc47353df9b0f3dc6f84e5e46f2b42dd84f36e2b17e1d", .Okay}, + {.Sub, "699011e70ce885841f5b34ff1c7f2ff95ee8b2920e0dc27cac5181936fedc6a7af45078dbdac2a5ee1133c2bfc9a4721a12df2f7df383641113dea80c8a2e73922d7e650d198b5282d1300b3ae2273e0c00d27f4268efaaf355b47cd3c979cfdac99af0c524b6d329f3073f32fefe8a845feb548d02d291d0411e2d7f6470246bf01f7cc3b5e69eb7b238c476dcfbcafb341c38c4f21c7d172211a4761d3424aa9cade3702c9e64aff3555f4a9b265de0022499e7078c5c193523abe44373c3f9eb5517d5167f32c9253dbb0bf2974f7d3e2b293d08f9dddeec5fb03ec37479e5fea56076e876dc3ecf063ac7113e64180226efbc2f1ad5b2322f4bbbe1b090880cd932af0d5bc9cdaaf2778756f116b7c9faa403afc2234bb8561caefcd43b14dd614ec783bb13af18892f51d1f88e45fbddac565fcf099324566c90a350ffbbfaab3987f0f472cbeb9ddd4fe9bf322bdf6b4f4ee4d01f16984ea0a7e7cfd32f2597e84a3cf927547a960e9dec1e6b2a782ce1ef29930936c15e056dd00ce8b2cb05449e6368c7593f2a33617e395da0330b34517e4bb8d15b1bd8ff8237c6dbbfba151409fe3f023b3d2ccaecdb6e8f64f3c20782cb34b3b4e34dd982a9eb3dcb6d7583f4dbb1202a8c5a592fe24bec3c303a90520116067547299d1e1d7414332e93a0717cd36d3789e7ef77b6aea7d5e2c6b295a379df2427e8cceaad687", "f880ff7b339e70c56bc49667f4b244a384dbf629e31883a75a10d0f822af0570b78b9436703e62afce56474aacda982f755d18fd512eaff45642e86873d81e5ecacd76c8ddf8cbc137da09138f682c23ae7827b51faf46679c784d06b327498768479bd90f966e92a6d53d25ccb98b3a47716feff492699b79361defb2dfacc2727fd06f73a6f849be2a90e5ee8541555be218ba4b50a23b9d7ed0e2a1ea9bf6447610ef8debd3ba550f3fb8ad497be9c6d1c54e72583fe6e31a376e0c7f74e314f6153d999792922eddc0ff1d96b0ce9d522e6599bbe13ace2d9c6a2e638813976ea6270dd6142ffa77f60470efa92bc448818f9f141ddfcb69bff747f503fe9ca46a81bf9f590496798d896de16f24cf533974a1d620a0e5aaedcb2f9153df149afa637dfb1579e3f379bf8933e5a72e1d7b3c617560c70d91d81baa022a172629bdbf894e50df80b3b58aa119615ae4f4a9ff23659ac4352160cb9333a892566590f51dee619694be0258ed5919d1acc45e7a0c1d68488465be07e5860e5897452647a1b443b7651dff16b9f992ba1c575632e5f3329e4fc329c4b2da45659105a63d159c57e280c2aa0ec16c0db17ec2c2dbf322b796dd2aa115a4ca42af0b9c7bab7c2389a795f704d69b350277d4692072039c0fb63d9de48ab50470b7028dae39daadfe26098d144361cf9796b7cb806f607b159f9f883eece1c2dff1", "-8ef0ed9426b5eb414c696168d83314aa25f34397d50ac12aadbf4f64b2c13ec908468ca8b2923850ed430b1eb040510dd42f260571f679b34504fde7ab353725a7f590780c6016990ac7085fe145b842ee6affc0f9204bb8671d0539768fac89bbadecccbd4b016007a4c9329cc9a2920172baa72465407e75243b17bc98aa7bb37dd8a338488e5e4307049e80b584a5a8a0552dfc2eda6a2b5db69b401759ab9aab32b88b21ed6f55d9e9c40397160bc6af7bb001df7a254fc7fcafc84838a37640c3c0482f9f659c89e54e5e6d3bd6c96f7bd1c92c435cdf67a166422c40753784501f9f4ea66c0d879257ffdbc2ea44261293dc227084a846cb3b89d9faf61bd6d756cec99c67bbca6610f8725db952b38f3466d9fe6c2a258c003fc4102dc6c4e57705bf643ef26ae6ca6c145cc2ce5fa076fb78702ddb4c71529fcd1a1b667f0a270a3f09b2c1f9d7b5a27d6e3826fdf50a351898d2cb9c76c114b6ab5f640c12707a1ecf214d14a16f0e97331f0541905b198437b5184fddb108853fcd6a94d1fdbb7db741d12b5be0a215fce01926a2edce0e77113a116c34bab6c8f7d50a04ebd4fc73f25d0ed742129e56c8887386bb7af6044ba1dc6c380c9fa3fb2ee5a4533cd5ce95934e3f310836ddb910a61cc8fe7bfe55d64971f0e3229975bf5ac4ffd39630ef361475c46a542cac3a6d54043720de01ad45c0601318096a", .Okay}, + {.Sub, "-4c6d5a6ee05a5d828303620e9e60f0fd9a3859ef8c4c12f38acb7fa7a2c96c3921da62082eee1bbdc6ad2cd41a6429612301c3439d638dbe85a9b7d6dde5c9cfcbb7e095987f43721fd19cb9fc4801046609fcf08462836b3b60edbf9d9847034e1dc64347b574d05b5a9503fe81c6725288a3295e18580438135cc84a1bcf93395075ac74cb8b49c07de278d523009cb268df8d4680cc8ff364faa01a60a845750a66bd1851166b6d3872e812e51918117f655d312581aca3e3c9e9da9ad657cfb3fc3e988cd5a5fe6c55b9b89eddc976d18faafcba5cf95281637d94e6e6bb525465df62ae892fae27ad8dbc2cac03c086eec896095e8880db67e79c9eca55557a633bb7a824a148ca99100040eb2d7842ec475e93c16ae33f314805775a7c6447be85f713fbd82fd92ee7e5c3cdb525b0cb94c5100dea07e57c0ca71beeac85725b8c222e2218787c9f451befe3dd4f8219ffbac52c39e08fbee2ac1b0739d3f761dff6b523b927abb526166b3d3a35194bf98acacec66027263599e6fc3bb6a9655750701bebb5c55070e93c483a12df21d1e1420140a49970500576d8542eeb8b2553f185f671e66f29e6519a50e2d09ff8a4fb333255eb11cc75100ea040944afca975c6a9b8f1585976cfb0e27a06f0bd06ece4755ca6a6b1ce526979b8a6f748e71155d36612113c8453e8d2c9af56ff97bb3eb0270f9410ea673731", "486bd936eaac501bc9724ea52c7f567d673608803ad5e13ef56e2a3a1ac0c9aac150fc0c787f2bf9b9894810592c8fe840f2d9e5f2432f3fee8ca47e26caea8884d91bb742235d556205ba54c89f0f40541cbf0981d49e22aa110c8caaa0099d07af5de7b54ef014ea6ffbf35b1a30e195f71f5ef93caeee8e3e66bba04ea3f1050ef3ffe7b600d4b76376dfc2a42fcb0234733fe7ee8b1e828041b99febc92b65dd4887df9dcd5762e80ae4955e83fc90d1c86b1b244788e8b9f81fe2d74473c8163d8de36723d14f711a653987585c511c34c6df94a58a7fb82f06adc160c5e8d601b853adb210776b0278faa223c51f321826580a392f701b536516d71fac55fe23eabb3dd6b751a9ad33bb81aaa3c1d80afd90b19ff07fb0657d9d6d012beb9638e97d399b8142b6be3d0a0b9b5b889edb7528e6d80e915b8d37cf70e84b4b731933207587abbfd4a785d7041983010091ef376c63ab23fad7b053dc6792c1362b2af2a16dbdc70edcf7eeb42775992908b1ef6cbe040ec76a0db58ff41e4a38e4cdd4ffeb6bacc45430c38066fe80c9ff4495c829a2cabc4fc106dd6fdea5a5ee292928ca3608e6d10ac345192f1b130ddc1f44355f54af3f28dc65b37c45101347afb63866e3dbb3afbf399ec9c58ec99b65335fafee44e5a31c27fd3d0c2468fdb0d3ca45c24e67639d96f2e8e66fe75235eb33a0da296da8ba44331e", "-94d933a5cb06ad9e4c75b0b3cae0477b016e626fc721f4328039a9e1bd8a35e3e32b5e14a76d47b7803674e47390b94963f49d298fa6bcfe74365c5504b0b4585090fc4cdaa2a0c781d7570ec4e71044ba26bbfa0637218de571fa4c483850a055cd242afd0464e545ca90f7599bf753e87fc288575506f2c651c383ea6a73843e5f69ac5c818c1e77e1595897c73067b49d52cd2e6f57ae75e53c59ba4c7170dae7af44f7eee3c2d0207dcca8439d14a2512dc84c49c9358c9dc209bd721acb97ca39cc7bf3f9774ddd701ef2263625c7edc471dc4f0283d239928442a847813b2a6797b65c3b402592b006b6cecfc8dfb906eeee1397b7f0f6bb4cb375ea01ab78872672e5fb589a744643bbc295d13a1af744ef45615b62ef96c5a2e45ba84fddf76f744d9759728fed24efcf6910ae4fa709edf6e5f899410944768cd6f7d0e574bf42a3a9c4385146caf2f3fd605082abeef2318fe5048a9692fff76ecc952d8d0ae9569176eeba921e051f64afce4254ab7a378cca6eee90434f76f05a00e24a25257007576289a4a1acbcaf3893a92116770a2ae36f55c0110c544832d491794e7d1a502c7acd4034a996b37ffde3add4c43f6891aa9a50f55175c21c85a45e44592bff109ccd0c0936094fac3f95ba586c2044254aeb8c54ea7a66b6c4cb604697e52019286078a021eadbbbb01f3e51cda67251013901b9a4ab6a4f", .Okay}, + {.Sub, "-f68b7d1fe347d729331db821796acc4024eec604222ed82873ee70f4c84a3bb522e5cc76e7333f6abc6119555b2ebe97e2be5e09be1f56c74ca09183de972153044343d66a8e002d3799ee71c2d89d955ab95d0072334ad340a5302cf524f8ca49a4de73fc919b425f641b60da5db14cb21c849c55b069d96dbc8e33e4a3c1f23e3a2315414d6f39c39bf42ded18c4507fb6ca9dae778628e3c915bbf2224dbf6217e14190a5031c2607d8986fa3ee6c42931f674caa0c92c14586a4abd36935af30d0b91fee8dc9b6d945e960b3943f2ce03d4b0144be54125fe9f05553f0a4420ede529404a7757a67c9e72cd4b9d70c8e72b0bb4e7961a88c2908a877b82689d90f880f7aed37d9b1f68f14a57ae283a70f9069c8b9297dec23a3c5c3f48b5d44e11ac6f8bedc86c0b68db0316406fad66c6098e52ebf6a02b114a35f0bb33f50bb94de7d74ae8e31334d001e4e901fc794a6d78f32b0f3ca05906412eaaddc2cc89e8c573c1d7f7a3eb849774e287bddd0ed49ca67c9488a988fa4d2cefbb51e01f119936ecbb37f86b4556f31ddb6de1c4db145c46fb3fff94a9427c1dbffad05074037471e3c33a05e1068babbfd95cb8810793c4a587104aef0ef7e3857d21aa890602490a5007a53d0a0abea179f64bc646d5117f199f9ee4fbf7c73d8c152837d1acf1a11e85f1d6edaa58e10da11e0dc2cbfc43c5966024f7e2732", "a2fc67f6037505139020049f235f295f3874ba473ecc1bc0d7e948489487ad25bd1b45b9d0323829ceb1c2cc1264fd04af9057441356e955862f6649430ed462a6b1fb37faa913ad35df8e0cd84f0d30913e04a8962b2812d12d91504762a65e056d06e3e1ffa9fcdf383460d8259aec8b43af2bb67daaf473f8bbbbc2bb93c053f0cdef1b8a31152e60ed77d46bd5f1822a196e112ef6f14e2dedad54b6477f76620fa30d1ff08416371ff64713982260b767044107309a64b8f8c2f341ec1839d2e53ea42f0e517f5eb1f5a59caba6b68118e0797218ef672cc700e0b68141af9b8a81c05a5e35e728a0d77ee3872cff2f458c8fdb6c8bb660a82c60487225c49ec5d35fda4205c4b9ebf5170273c5cea05b4947ff1ac72fcdcf5df348a4255828886b7a32d7a9ee25f51fcbd595177fa81ee3abde21454bb7eb22d13a316972667b8d3c6be7e3226d9f79b8bd0904cff5e3d10ed8def88806a8494d53f642e454f822d2a7900e860e1ac370eb5ab626ac5130584b7e00d57a0516f0157e85c69f56a849fc01ce68c32a4bae5b4757e39f60706c30cb76f3b2ba075d6cfd3633b5523511832da737d29b1efb5619de4f8097909d633517b4c392d1e5a9e2c670f1ff41d517dd332d5a857b8197ea5b867c3c4e1e4772a944834599a0bca34a75e88f18241119c9a4d0910e05855ea1169a215845d86b6e0c6bc0cec0581dd8", "-19987e515e6bcdc3cc33dbcc09cc9f59f5d63804b60faf3e94bd7b93d5cd1e8dae0011230b76577948b12dc216d93bb9c924eb54dd176401cd2cff7cd21a5f5b5aaf53f0e653713da6d797c7e9b27aac5ebf761a9085e72e611d2c17d3c879f284f11e557de91453f3e9c4fc1b2834c393d6033c80c2e14cde1b549efa75f55b2922af1045cd7a04ef1fce1a5c1849a4201e0e40bbfa67d1a31f7036946d8953ed879f0e49dc4f3a03c3ef88eb6b7868ea34a866b8db13d2d25fe7f679f15554de903b5f7c41d9c1b3637f7df06503fe5e361562b7ab6d743798cb0f1360a71e5f1aa68d4545f05ab61906abeabb841040bbdb83d4b29e5ed5eecd13508c02a4c4e77d55b6f552f3d9e6be2842ba7eea852476ad9b1c7d3f0adb9f301b90c98b0b56d6986412b968674e6abad7c06f91e7a7e8b4444c35004b5ba9c3774993d1cb1b737221ae95c91b09ed2c6b8db5794efbd7877e66811a97bd0add9b166e0f0c081c0c15efecc2c0588597bba62a8dea28a221da215e5ca1e049da694e84d817bbd5899638f709a1c42b10003ca79359a7d7cbe1d768fe6a7b2b351f194bf123362573c51ba74c574063b7d0bbed49a4d166318addc71620d349780d69960fec8c419ea657801c3d25affcf523896459e1ba10a82b4c3c1361d3f87f07c1fbe4ea9e19ba12be8e3b6b8f02b7460042f2774333922052b3248c526d10fd6450a", .Okay}, + {.Sub, "-12acde336009dd260309e0ba1e94bbf1bae3f89ba6db5783b8a5f30cdcddd24ad407fb1b40030c435d331ee3e70d12e249b4e182f71d2621da4f62fc7d1c45289cecc53aa5488f1e38456bc64dfd7fe6af71027b638e8e0a0601f04ffa4868e3c9e9b4ed3b37989b2530d687cc6fdee4fc61bbe4098c40117c713c6482cd4c89721a76f1cb9c0328064fd0b7a5dc4873b7ed366fae107e62603ecd0bb7d5a1ed49ca1a7df3daeae5b26994c9fa653d9bf0a982aeba0200d110227ae65195ccd4a64ea96951ebb89b0b0e99780157a0a2195ea45568b8970d0c08f593e2df8fd318e54eb097486404373be13b7e55c7154d59d5b8566491f4728eab354fcfdbb830d332256d67b36adf04018c77d061b97636372668cd7ebffef0ca2acfa42c567576e6029d19ae2a8f427a36066c1b0ca88b3fc47c98d65057765993bdbfcb983d08da00d1632d8ca9081ff689e0a9ee8342391238b16ce20484b30e625b4c8431470a9ef3f04249ad926e75f8972c8c38556d292aba156b6afdb08e5ab4f1fe1be0e043ba5279aae4d3725126c1e58abb809c6182d50c1087eda53b29252b3a0601509dc485ec5f81eb468f9dffcd4e2927ffdcfaaf4796628da9f73e53b0036433df26f7f650732727b016116ed611b57c3c865099cf90394fb5edff6bc4c76fa7f5c7c964e796e2070c36a41656bfcb2628a592768ee8e4080822b2c1f682", "bc7e49cd60ec036c7c2ef03c6ddcb7e3a4fc732ff3daf381286b46236c7c5bd92b6f3558f0d86fe4c678a19b04eb353824f5f542f9a6662f7faede73b9799f82690f7908d29837186f03fe83ed1b21a62eead43e716aab28e82939517ec07947be5d99d3dcf989a20ac703f825b8c227fcdd34731440212bf5afc6668b95e2af22ce62aeab975900ec037216f1e84cf08d14004d4dbfcc94c59a5c535baecb068396bca92b4d50b5b715aa8c6c6280819503000c692e3072b37fcd2f6cafc2df3aae4a9ca5636b2aa57d91c3ca4d594552ef1b0d99992751c2ecdd16e23d325195568a276d605a2ee66de88ba305d7a26025e66b6ba669ee8c1f9f8154287df3f09a87572045be23912d7ba0bb3db889570b4bd402628dac4af93ca00c9c1ece450b2c64a6776b2f19870206fb4c778cba7bc153a347311547f5da4ddfc86df7b43d75b58654d06053975e576fee8a191019e403ecb2acfaabf0c0cb701b89162da8ccc38a94979c77f6661b254deeede96528bd0bb1c3b03476ab78ac1e26329613b2ec5b3b8de11277f17acec977107c472d537b0d027abfa9019a8dbc84843ee0418aa4cbc784064e85361003f5469f645af2bde4469bb80b9c722c7931db704d863c620de899c4dbf84064ed6554ea39791a72e8f3e53fd49181eb01e589ebb6d14bd16985e41c8581f29bd609aa299c330d28f8b6d7173dd7f50ef28dd1", "-cf2b2800c0f5e0927f38d0f68c7173d55fe06bcb9ab64b04e1113930495a2e23ff77307430db7c2823abc07eebf8481a6eaad6c5f0c38c5159fe41703695e4ab05fc3e4377e0c636a7496a4a3b18a18cde5bd6b9d4f93932ee2b29a17908e22b88474ec11831223d2ff7da7ff228a10cf93ef0571dcc613d722102cb0e632f3894e8d9a077335c28f25342ce97c49564450136bcfbd04af725d9295f13846cf3cd60d7271f283b9b697f3f5666c7be1d85ac82bb23303143c3a24815be458fb3e0fcf405f74f23c5b08c2b3bcba4f9e76c4dbf630251be5ecef5d2aac51cc224ae3bd8d804a8be331da9c9c7215b9eb7ad7fbc23c20afbe2feae4ab6a3f859ac216db97c8dad718e70317d2d330e1a42cd4182fa6b300c6c49ea06cadc404b24ba82126743911959a8c97c3d01b89299630701181fe007659f6c33e19d88398ff1464fb657b7fdecfc9f7e4df9cf3407935c1d16256419dcb07573d9d276d59a5eefd7627e84d9e62588d4911de51b7a21ba95e6366bd91b9f745c0706d31830b1f49330158e078bf74b63cbf58b5c9b37c7c9b4fde20e8b4796a6d5b6e1afbe44e192286951b3e38839cbc5ae03c294c88c5acfb8938e321a9946696acce1ded48165635a04390cec03a856765c3b669fb5b5a0c382c3757924476fea6daa515b5ec7139ace6d7afe8c8e293fec6069f4c25bb2bb6f45bffb45e017c1b48453", .Okay}, + {.Sub, "-c10de2825db799c1d699e84b57d5d17756685169493e49aebd91b3689d6c72f21a44a849ef10803e8f5fb6e3b44402d68550a4f4e913026f0a24951a2a3a32801df0dd519d97afcb50dbddbae309a754b062e7d417495e08e7f31d9380d698af815bf347b3072ea6ec7e44c89ee4fcfe3e7ea730d3dc17c344594def2decf3a28851e89d82f930ac6d32d035ac7908a1067d7ee9b96784bdbeb541e584a3a0fc2f38aeeae4d1a759ff5d218ce5d0dd34d01e7b17d52ad765305f0b28fecb90f327912f93b8cc8f1a68dd765fdc13ad24b23e5c6dd23353fa22a087faaf81c5bde1b1279c84f28c2738b5c18a5a5c4eec0d7d6acfc342de1baf14d9c06a36659dfa47a71b55993154dc01ab245f086cc01d7591f6f0f674765e0d73196e2aa968f32913b6538519789a55fbcd129c42bd91f7c496a06348cb6ac500924b16aecab2cee3200801f80954762301db2c41f3c6e2e2f26a26be28417f4c113a97af818465d3b7d67b9d0bd1ea1ff39eca59df3c68e83a7afb1ffafe50e273019688d2bae02a7a450b1fe7480f0cbf6baa8800494dbf0fbfcc261065e5645c4b520f17d3dbd1433e6830986c32dfde57368fbbec05065cb162bebf2954305ae13ca3a6a0729b21134da118bc5c94b134e9a62482c1da029c084dee906fd3ffde9640c3b5d2bb31f9f3fb5c96f0c3f036da9332b7c0dff06ca85adf580751117b05da88", "abad104b434cd85517347a0e9ddc874f2dc324393ce6b15a4deda9907519016f3b73aa6c03dbb4de070461459a7669a653c1db06f23d332be2beccc069f4a476e0dbb1c2cf8fb9f170db5944e5c28e4171d0a1287ccc5de53fa1395f1d70912c5e2404116a73476f38676858c9e239e427b7400cac371d4e14b1ac14182c55c76227a15aeb6a33b61ae10d280e16d2db39526d45a7d423cc09e245f083a589bcb63b65464f8fa7c65b39b285c75b47320d65308d4cff76583dd2478d887c2c39102996bf0259222855e153c6deb0ae4d591edd48e9ae927e8bd64c906117bd2a8c7c3972c2741fae9f8d3718d2d0da12a2de7606c9eb79ee7f77cda583db2f2a0ec87da5d3f627905418a120b8af4f6c7b5250d7938c2a0b655e71acc040bf468397f5202975b9068a70bcd83b0ed9223f2d91de946ae24ff623dad1600767f0487d6e8afc57b69ae30a39ff1aee48c0fa23119601b8445f7e4ff10b51a8ca3fb9de9db06184cfb4d8d03c52ff603278d4f3bb49af3d8358306a79e2046053a849fa4e21e53222dd386d1d20162f5388aafef4d57b5059f34de11101d4af121a8b0e74fee19776808e093ff11ef25c33c2edf87a4e0c46254b26e712ea9271993b663e27c3c53530213cbdc93e3662b77ec22a07c04b03e8f003f19f226e297379506b1b47866004cc5b0b11837fd5e2d3cd1f9e63ef445c90e7dc0645bd68ee", "-16cbaf2cda1047216edce6259f5b258c6842b75a28624fb090b7f5cf91285746155b852b5f2ec351c966418294eba6c7cd9127ffbdb50359aece361da942ed6f6fecc8f146d2769bcc1b736ffc8cc3596223388fc9415bbee279456f29e4729dbdf7ff7591d7a761624e5ad2168c736e26635e73d80133511590afa0346194969ea7989f86e6364628813dd5dba8fdb7c3fcfec2f613ba889c89787d608492ab8e574143134614f205a96d412ad2c2466dd83aba5222a4dbd6e3152b68747bd2c37bac652bb25b142bebeca26bac45b720b5d39b6bbe1e678ae76d48b109982e86e2d610f4766abd5d842f8a32d2d28feb05be0d68d2e580a2e8ca765ee1194c8091024c1298f58e5301a4c4517b7bc2c98c7e2ce84829e81c36be4c62e6b68af76c108d67cfad27f24c6b8a54dab1bdfd125567534ce2b1b60e8db63ab1e16bafb4c51ab0459aea437805d00f61a8ab4c105f4886bdf0287bfcf3d1c8c4079c13e44716838006cc0aaba5c469e2a8c58115ca3842a38a3532ebb5c5505f6dc7b04da789c2a3d42c4807c29df81d9db88f44cb3e53b1c8003b3c6755e200121325eea46421fffa718fa3c1fcf7628ebefaef2fed6ff6f04e4747b176dcbcf153fdbd8d948d712d648dd99527a732008dc0184040a5c5351d78073c59f01046a372f23264d417a5b61634bcf01ba5a69158b8dff8ed0979f3be8ef2d17c0c34376", .Okay}, + {.Sub, "-9fb43e9964fed17c266093794e38c5df58f3b5d0eb15e4cea7d77860814a57c746023e2fe9b775d6070964f461705bd8452ca2a85026d068b12cc468ac387ab0a5e5a7251f7dfecd340c9ee9d7cdcde2ea9d85bd11cd39d462aac5f6cca32f7fe5fba01f197925592cb0290df1e33db5b7a176283513f0ee82560821a9f513cf8851e8322e58a93b2a8f946dcd51c943e5ca65f50f81c574cdd0c579f4e0cd5f17259434e8ae759ed4e9af1141610efaaa3acdaa817307fa03375ea681769ecfc47d7995802d5e302d40f381c5970272d1361a06a7effef20a5df29b517297e76a2dc65b9dc109f616bc7997db471f9d5b96387a9cb2e2cdb2f4065905ff511edcafd99dbdc9392bfd6058822a9c814bb01990f5f4193acae5ee79afb5bd92bb55af200b0abb2fd22c35879a50e3352b3448affa12650db9ebfdb1aeb49c00e9675b65c1378c0ce627f71d0d4e98355e1110f7fa6c4296001dcdfb5c6f9fec9b46f072470cb614be86332be08808618b76c0580eebd389f77aa39caa3865343d0b59599d611a73cf462f8557c73897e6f1b1107133c6f4dd011c4ef9204f8a8d9e7993a64066901d090fc954c2df58194a0a393b254f2af38e6e5a0b1e3d09c3333f7bf93e4d5ab2a498ae5b98406ebf1a8702c5c9efc295c11a9c7c12de06a7cba8c8b73eb2624f96d0c269cc58b36762e440a5f69d2a36230a2e776cc9df11", "629912b9c4bd85723cc947abd1d6c15661846d831b5510ec073f358308668ee79e04a391afd2b4e0a4487263ec32bfc22d0267e1ed9d1718ca146b5f16236cf04fac6e844357c0fa3cf72629e7551d48e6fac8f8fa6f678c3c43469389f799e1513a843d2058acf771424f7a671c37e764ec0288de28ac8a561e00e703d4a5b3a6ac4cc9bef0358b214da2f776b9a9f688627ff30d3aaac94ffd24e57b65ca63a3720ad8afa43db7cb944a6a3d894eb40c459c3b812a150387a99e49aee6df5d0dc64f990e2607346610e537dad7b663d1136d166d30ae362f6ed98d84ed915ece0dfc280c4fc23e9c6f2fbf55aac23fdd94092fc3bb6572014e5cb7753d570e0eb13a6eedee63e6691d7948289ac6ea1e1b66f6f1ec2e2f11d0a5c7e1d7c4d5d3b8dffadafda3ca48fb236c6974f9977ba7886d031a094db6ced460e51897cb7d445dd6ef19177735287192b239da8285faacc9fa91e5877d0825f8d241a8f3d9629a8da8b1447e07b53653bbace7506218492e1442b8ff9f087bb32c3f5c80f8a2020494fb0412e09e8a5c01704428b20cc03faee0957bc38931ff2e21f2f0c70c5382880a0002dfb819771335ca1f4cbe837d40670ea77b2d2a88ecf800ad945d36cbce84a8fe536387b2f7b98df7a307fe412620c4d613e9d1f514d3a8c0d370b584458ccd6de10b3bd587136b2a25199ffeb4d6545d98d9e4bdde693ab", "-a5ddcfc5014aa9d34a2d27f40b5631f4bf0bfca91ccb35dd684b6bb8b1d0c0b5bfe2886904b4a124114dec1aa03387d467fcc9266f00a1da3dce0b1e9d9ab17faae06e0d63b37adcd7dc114c76431fb7790d324ca174304d266efa600542a91dfb0f4862eb7eb028a3c44e05985501342df03650c2f67bb727b7e8301a325e2ac2bcacfeca47ac93dca46e9d44bd63e34e508df44055702162d097c84c972a05515cb4e273a8b97a51a2f3b7e539a3e5eaff276e3985a94a3bb1f88b1c650cc59559de8f110fbea373a201d543447dd90e4750d80ec309d56d54e03429c170fd570ea61e1e86061a00836c93d0a1cbc1596f790d98ee9924d308ec247d53268fbd9aed44aca81f6a63f23016ad262dba51fb47656337fdadd70b840c33db0f08b2eaae0ab86b0a0ed0c539d1177a84c4ac032880e296ae4ec76a9ef4c2ed8a661f2fab9ea67d9e5d9b49a42679bbd3063970a2c70bebb458959e7dbbfcc4072a84869befe741290666ae7f45c3c330007ce1dca1cd17b587749424656b292a051ae379bdaa6a241074396dfd874f9c297cd1dc752eb4fe34bd54e2191331a9bcaaea58de68e7301d370b4aec3412b4bb3ed62172f9559bde06212cb3ad0c89ce0c854f65fb35a54289cee6d6c7bc079e94b782a9dc51cee32259399b642b4133d8dfd40f830b2f2674e1762724c9ea1a0535daa5e1ea8f7bfc97ccc34ab072bc", .Okay}, + {.Sub, "-c92fce2f880349268668b4f0a2fcc8ca07e97db6f51bfff36c1ca8e3887a753acdfb5c8e1056a50edf95261a58c685ff08210619fddf59631b1dec2878b4d7964c551140d9c0a16a71e1ce46bcc810c16e4c103e613495bfa9e280c62b7f70cde998ceb374f37835c1c19b751d3481f013f076204e72c5bdb13e29b4c7bfe0eee1a348ecba8f8973b7e7952cb48726b93b00fbabd8ed0e194704e52c04dc77450d8474cb938a7a3f3b17a386ba505469f2d7b2e45b1db32c0f0bd36dbe8c6c5885be95fa6c6cf677655123e7b8f362dafa3407c053843bcf98e38a5e3300120234b577583e0240532781c9c1b34c11299d3a5e76118d93086aaa0e14897645b30106baec5fc8d167937c480defa59989d4ee7732e0602baab61e165b3196f1660293c73b5ed75340ea06bf09f8bd3be28541e9d357929104a18efb15f26590b5848ef0f50452e26ac0ab4f7e70451b9d344f95e0fcdfbd9e6910908dea7900f343f6e6f9d563ed31c039b124718fc616abb7a59f8266e424cd83cf650f99e6dcda087629b8a75c8144c2a5ba850392e82c12edbdaaa32bf33d0ee07b63a3c6b40a44aea4d34e5782d50ada2d7c1f056c0a7ed9d5916080fc564c65b21a22c3b864803e282976ec197272b53a2f9731f52f6cfaf6e20eea81bebc282a5a55eb03394617c03399da983c4cc95f8d1ef6a76e72371e36cb20e8bb49580fec1ee5ff", "80eb9b92bea923f11e16a24ed0ce1990db9e1c8ccce3a9caa3fe1b46c59d936b23f1fce573e2b5a4fc01a1de7a4f918d16096ba90c4d78e52ac94c2034ae69924dd439b25ec6c55f2e489d884da9800989d10e06d48acceb817ff15b03c0c9b5682a54ba97c97f744d9165d90ace992693c1e63e3de3e488a52834c61cc57abc98fddf22e3edf25c0eabc0a9b971e875db4f8e601437a78a862f5dab7647f155f7c8fb8a67bb8f13c76fbc80f0a374f602b55f93cbb64a74ea38e8339409c5a515c7f30ba82ccfffbbdf165eb7d2e4c80b9a4597b33eb74d9d8bf38d3391b3757406173d58d321d6096ae9035dfe7958afecafd08e9bef586f23b7eac777cf8420ce30e516f9e3169e35cc8e2d9514548a7405e839aa78dec47acbd1ca654a64e1aa33d0b7c1b7afef25ca39b7564d1327547ce22cbae2f63482b5162418a5601534bc250ea1bc4d50e905095868469c35a665c9ce09cd4e9e6adfca6f86365b76c6d0333a482c275b81607629b1fe1cef74f08ceed61ceddc15b4eab452d7b9cea82089542d633703b5a4775c25467696a39549fb54197bc786af31778a1cd64755fd2ecb50383b6f64f2b0be3e15b647d3ed1c234dc43aec8f6e3dd23e55c730dcc921ca5a8853bf7e2902495f4ae3510d3e3c4afbc63bcb47ccfa49a194fb5029a81d0db41e1cb8ff4e533ad735038a2864ed1155d3cbc85ce51be8088fea", "-14a1b69c246ac6d17a47f573f73cae25ae3879a43c1ffa9be101ac42a4e1808a5f1ed597384395ab3db96c7f8d316178c1e2a71c30a2cd24845e73848ad6341289a294af3388766c9a02a6bcf0a7190caf81d1e4535bf62ab2b6272212f403a8351c3236e0cbcf7aa0f53014e28031b16a7b25c5e8c56aa4656665e7ae4855bab7aa1280f9e7d7bcfc69355d66df90f2f16508a0bed24b5a3cd3442d77b24689b054d7055fb46095302876007aaf3c95ff58d127826d3fda0f944bba1529631fd9b8689061499c67721303a4670c647a305ce4d5806c2f31d366f7deb6691c577a8bb8e9596d5622930ecb2c5114a8a824d270e46a0298260d9cdc5ff50ee153721d4ebd176c2b47e31b2149c1d3aadde5f627d1b1a0aa4897a98e22cfbfc3bcae43dfb0c16990af0d92c8943b01388f5ac9666b5844d73fad611b02c167e361599c3ad1a12f49eb811945487c8ad623969f5fbaacae98aed077b705859ff374ebabdb72d0fac19591bbb119a9b41c4339b2c962c713d0112a999844fc3ecbe96a8b096b30cd4bfb848784a31e128d95ec2b68307a5f7456f04958facdb2de38a519aabd39e9e8fbe446fccde3a5d1b225252c6f1b4ae453742dbd3efec61197f955d0749f3d1746d31f0de3c78f67cd8807a39332d0ab0bd8a03f524a3f77ffe896fbfdd414df8b4f54c17b2c7f62baaf89a9c0b4820f4b483a63d2bd42775e9", .Okay}, + {.Sub, "3b42cba3b71c18e28cda6bc13b4b3b9c75016d4cb8ef4cf777f8b8203e6bc74b1cc07e7fcfa081411b7abfd67790cceb79325ada158a417a48902252b800e3bcc5a335f7e0e3f3fa746369f2eb05277d867b1f4a5779670401241c1cad87d4018805e8465a1e1ee5af0e06d36f85ccd9e030cb719483f4c28ecdb4abadda9c75e901ac3ae40af140c7631388f793ee6b75ab2d78b6ec921cfdb4e17ac8bb544862d158a7482594aa3463c2decb58115603b85db36dbbcd17cbb7f5d5a848f56ad040f0bafaaea604d40ac4a479415dedd86c1e184d2c33b4108c8b8047a1bfe57d3fd4284286f69b2e99b8de901133dac02075adcfe321c98d18f91112fdfbb9d9c096a7fb2ee242d8486333c3ffeb56df9c91e5b4f85121797d3f71ba8640f34ab503106aa854e4a798dac688b09824eac175727149834e3e778208212eb2433b01dd89d7aa7a40a0e1edbe58599919d39effbfda066ac61a099f5c8fd6dca7e94826bcdd8e68046404f8e5ba8d74da99cc63753044e829b7d98b4a631d3ca61fb781bd743792ced88369783aac7d20b20fb4b014413756b998c44e60d6c95423ea3068ca6f71242f692b7ada6f21dc278a7cf103564c565bc35e93031f5e92b83267304f9bdd5b3e107e562aadf2bd58b6fa436d9596cfc6424c963a465c55d0d181a56057047bb23800a605412dacf4f65d0a54631a07926157bf377dbea5", "2d3c34f6799b0c201340b106395c4b66891182d95d498e4c3af92ce6930bc10391f6adf2248d63896d7461ffaf29d76592bcb496001ad94916cdd5ec1f2aa68b930c5c8efaeeeebdacbb23e613fb1ae487feca1bda6853c9f880f8f7a0aa082207043208dad71d0454418fcdc94bcb29b964b1890a0544be9eee630676a99a101df0696574c7f2b2985f9ed7ac2f0e5de69fb6ce861336c129ab9d7f53c7767e758c1cc14ff763430b55624efe825a4be48a9e8c95ae18b958e9ec27427e15683acb2861b58c4b0436760e47af357fe319e107a6e37521bc79e0c441fb7d632f94efc61e22cfd59522e4e1a08821498ff94cd92d408ed0d481dd37c213fec3ab17cfa42bc2d89b29cb7a9b7d2d259fe572ba2c8159ea6c2d1ff5b11a3ddba0fd38234253ce387dcde467407ca3bc6897c7c238ee84f1623d3d1f4d2930682cdab1064198b16b150a7f13b7efe240309f7b6fae645ff5d94330f147efa720d6d1c94f4ef7d9323683f5a444b242e1f860f0c6aec80a572529bd890a39c996191e3b70891b689466287153b8f2424f82604d15ae4235409fab401f0575fa4891063150aedcaa25ddf34f812ddb33ba7dc1fc6af2e00b739e21621f35193515d7963717926c201b67b33a2b419a675aecad4154529cc82caa52bedcb4b2c60c3d0e55176b90a0a7bb867786d134e5733ecb9e03aeeb49d726ac7d78125c1909a585", "e0696ad3d810cc27999babb01eef035ebefea735ba5beab3cff8b39ab6006478ac9d08dab131db7ae065dd6c866f585e675a644156f683131c24c6698d63d313296d968e5f5053cc7a8460cd70a0c98fe7c552e7d11133a08a323250cddcbdf8101b63d7f4701e15acc7705a63a01b026cc19e88a7eb003efdf51a537310265cb1142d56f42fe8e2f0374b14b64e00d8f0b76aa30d95b5bd40943fb74f3ddc9ed453be5f82e3167290e608fccd5b70a1f2dbf26d80db45e72ce09ae65cae0029575c85945225b009d94b65cca0bde0abe8b167169b711f796abc73e4c245cb5e8500e0a1fb721060bb4d73e07efea4ac6d39c808f5450f50b3bc14efeff380ec1f0f27c385647190ccdc7b696da4b716ce265645b0de4f459878e577caa9ff61291c0bc9c6fd716c3319a49e4f42f8d22ff3c83ec582111015834def0c6856889fb9bf1263f653621ce35ce7619687a582f515b7a109182e918576ce8b605d61ff8d7c5045c31806e60b43377ab7c79a905b4ad25edc2fffa50811099872387e446f8a20ba32ca6672fb085f85cfac064fa066ddf0097ab7979bed8668e384df299818c20499330dfe7fd9fa6b4a41a2b1f8a10f7e2ae34f9a42979ce0986fc811ad4c42f8075a803e53cbbc35306101762a7a6a568ec7d076597e3743a1f477bba1614bfaf48f53ab12f711fcdeee156f2ae1f0a8bf35b14e945631e741920", .Okay}, + {.Sub, "d729fb048829de10559077ca59dfb689fe23dccc9a3a731e94c2bbbf5f23b6ecd1e3ea51fb43eb9c41e79ad24b788f104169815585bc0f0db2d552b94c33ec0a65f0118150a252c236475134d550f2cde923ba53f31e78bfa05a48baaaa71f9d6a14efeb338015193f9a3f8b0301b47fe7d9139b1ba25507fc7ba9a0abe724874157ec0879b8548d286de17fc763abf5f0d6f6d4c108bec22004f83b9f0f5fece22fa07993e348906a0f93db1ebd5de04880e98cb34e4c6a26b25deaf9f74bfc13ab95f4c9b09869ede86a3e1092db17d996f518209f5416597a6878d70898d7db8d55483bcc9b640e3d1b9c4d793df43a32587e57339971e67aa0c9714b3a2c1ac5368d7f8a11012d175423ea4d75bc8a5320402ad93fcdbc533e41c4f7c15fe761a6463b85aa62c9fd46c3aa5a1d744ac8b18ae81d24fea029d77f1c978e9d9e25cc6a19844ad894db6bb1e951d8f832037def075cda1314fc2b02e28faa0d3af5432f2cf13bf07113e92e15429e105ee1fc3e0c6bdad63a7b0ea07f81ed495d386970b0825969bb8e28f76a3c88d9433e907755c12ac56f068b250f536611cd900db152d6b9c58753bc1b3403b1adda286db97d3af8ee11cf809b69dd9669536524eed3ec36094c341ab506f36a810136ba666d0ce8618bf40cd99faf4cef284204510b065ff4509ed9945ba556f57e5d5a751aaf3cddad1c0ea748972b98", "5e6f9e36de15684225ffb0dfbe04bc5a49eb12758de5da2f835c7dd121145357a56e2ba1c0c049a475b5d03550678ed73e9a4116728539d61c351f98f397c2108b1bb36bc5a6040910424d589904fa60fe86bfeee3e54908ea756c8b3afc3bfcd47509c2f6bb63e2fb24597e65880bf5f5212f0f4cd871cd87eaf573b884ac5cd94f93272a4eef3afca093e7fe5a4569bf3c430721a49e27a3d5b8acef1306929f1b4a4fd70706e1296e4906c85c281fecf9dbb30de645edc3c36357a745a87e245a37921239366b2ed5869ff6a25466c9eabf8276afbe0f369640353bddc3813a027fea2ae7c95ba3c2530af19fc30d573be61dddab3f6904e7629741e4dad9cef55f8d4b519d1fc3404de4799f4205a02712fbe1ba616e4311944957554446f30f45291182654e6737aba49145b06dee5296faf9b74790ef0b1193f667e9e62ec221cf5ba3dfbdf65fbb3797d2969597747b81791eb97072d6659b4a6b4f36113def42ecfeabc0716a43ce8ab2b8458e5530ff4fe31a9fb744483b380f187ab88de98b51e2f2170d7688ce630eb2c705992b54567b8bbba87e6c6cd19372bfadeb1bbcecc4f56edbd669abfe41001912c7bb265f4651a402461f7473006c19fea21232bc3dc85c93e359564fb50bbbc91eb8abd39166f6f4bde8c1026db74d8cf1a39dfd39419fcd9e2565e2d88b9857b8280ebfbca575a7f823c76931c35d", "78ba5ccdaa1475ce2f90c6ea9bdafa2fb438ca570c5498ef11663dee3e0f63952c75beb03a83a1f7cc31ca9cfb11003902cf403f1336d53796a03320589c29f9dad45e158afc4eb9260503dc3c4bf86cea9cfa650f392fb6b5e4dc2f6faae3a0959fe6283cc4b1364475e60c9d79a889f2b7e48bcec9e33a7490b42cf362782a680858e14f6965522bcd4d97c909668c319ab3cd9f64209a7c2f3f8eaffc595a43145629bcdc41af40a14ad4566135c05b870dd9a568067c62eefa9352b1a37def515e62b77761febf12e39e19f086b10fac3595a9ef960722e428439b2ad556a18ad55e10e4d2086a7ac8915bd97ae6e2f6726079885a08e1933e322f665f524bcfd700343873e169d7063f70ae33b6ea2c0d44491ede5f7941a9f86da27d18f452611d2a03451462c59b1f19146d065c761a8fee65dd6db11ec5eb262fa4b76f63aa9abde06b1a9e7bb07a517f42629a8f026d8e3e20a2a225c56798245ad729b753ec3ff2902fffa9a55f8a8fe5cad08ccb3ebc88c0368336c6654772d4cea4aa7fe55e9f6752ae17a029072dd6123da56522ff459f09c6881eb83dbff3521fa4f1f46611c456ab7d526f35c2b194c760b2931df4a74a0f896126f6dd2a4f54c312bc17ae6dacb850c15eb73e5ec5381801ba997b816a973624189d4195a19b5060b30dcd1e548300b42e78cccb5d26a532665af297680523eadfdf65683b", .Okay}, + {.Sub, "-f42b72003f6252607fff721b3877b49f94c43ca90b79e2473b03a8063987e5c396486cc0e82638a85f4718b5d3387444ec50638b3553a0aa9e2c7be2484232d637eb5a4af8b85bdac4e1fa153a93393e4175695dd5c0b105e7e512da5a6a185c5cb1104cbd939b402a2bac5c280afca9b6331ca5248a2d7d0e7a908b711636bb44823b4baf15b3a9150fdf94733c7ccbc0635a05361b9af99c056d67de508e5bb5976f47d1e19dc530c45d45c667c02b5195dfa9779867f622a6cf7896231db85667d938e69de8bda0646b28b2794b1c1e401717677204283bc817dbce24f6c47e4e18dc510ff77a7a523625bd1bb6e10da9249a46ba60e3618087a5943fde00f557a7040edc4b3e9fa4ef3b2e7ba4184016385b2db74136f5deb02b9e8a648014c3188c17fcc2ebaa48614314d76d0806921f1475641a285d08495de6b5b2706ac5ea971b4f2216f3cc8fd351238b897e38bba180a9344960136103983d0ba53b67a67d6dd004b640b5a72c044847db3ea38a0f3aba73d79e35bbe22e79da8c6af02d3ca37e74b086ea6ac3f296c513f65336cf987f9a482512f8831fa3e1023027a37871df8d67f980d8268f8eb6b388e3e5c0646819e6ecce76f9f6c4f55f9a1c038c81e08715cf425743f740f91de552f313b95b3921f30a80adc2352588559b3c56d884a86b212b6db360ee0a092769034c6e0da4560f5d3d70d8337f70", "6570a280c20cc0043c105a7b98ac1573b4ed9e3f2f84112c7b5de850700439bb8eed83dd42bfa1244d1434c6b1c71987a5debf56635f2bdcd3b75f9ee2b6dd876924b4c5d45cc30ef157740abf10abc06f9fba6571c12d3929c44b8492145ad17006bc60c2fdd99cd660549f2111b709a8b3369f83df376f2af07811c823f88a6fa9098aebc4748bd7f6adb7309353cebf9425234ae01550e21cd26b3b41e671e26b1e59df7e23254a4f98c4dade93ccbf757705cd62f797119756a64db128d37c74c100535ae27c0511fba666d6cc3885529d9eca553cf383b0bfb86ba41ee04310bb701798881fb144d78966d799efac4da01afb05a63ac36d1005d3f1d2890925b174a9cbbe27f1334d1f8cc55317a5f33c1bbb514cf741f9c0183768c9e98cc759579f599c8654179d0f5c8861796bc4da1acd8006c9b05ba7f34b7ffc0887a3ab55cfc7eb25b89efc1e4351df51ba6a91c780b82e123b309d2aef3672e221ac88ed69a192747241181d9083431ce349c523c5662a26af514f146b1c92cd4c9e85bbb3e6b1a7c38f46b7c433e4f2bcf2610d1b23b441d0a3e9d638d6f2ff271368e29aff61c130f8b0c1498a5806cf28c98652672c7ead0f72b1e2ba2d7852d2d66f0116828af5e26d42fcb81c5ce08913ceca0ba9b98267166ababb039cf3cd17033b421a329f866ada3b99094d93538d01386a8248cb86512832265cee", "-1599c1481016f1264bc0fcc96d123ca1349b1dae83afdf373b6619056a98c1f7f2535f09e2ae5d9ccac5b4d7c84ff8dcc922f22e198b2cc8771e3db812af9105da1100f10cd151ee9b6396e1ff9a3e4feb11523c34781de3f11a95e5eec7e732dccb7ccad809174dd008c00fb491cb3b35ee65344a86964ec396b089d393a2f45b42b44d69ada2834ed068d4ba3cfd09a7ff77f2880fbb04a7e223fd3199274cd98028da1b15fc0ea7b13f60aa14653f8110b56af44fb5f8d343e261ee3d4468bd2dc9a3939f8cb39a57666cf19501754a392b4b631c7411bbf78d79439c915a4c15ed44c68a87f9a2b970daf23f350d0b9f6c4b541c0071e24ed97ab6831b089fe7d5878b8a8096690d83c5abb40f72fe6097476e9088e2e37d87043d5f32e69a18a71e3b7565f71fe5ffe52715fce817256f92f42e420f20d63f1513235ae78f26995eceb170d3cac6b8bf194756adb38a34d690161625b9b43fe2e87737e875d142f6ad771972ab2f6bf4994cb8af821ed4f3300209dfe4d870af699966d59b78eb2f8576526584a79b17bb6caaa06b34597dcb3a34e89f5b6e259587ad401573b0c5b0cdeef292a7988e7d9190eba580caf46b6cf466599dde9abd97f22d7eceed9fb82f709a0c524c486f3f9157ac5dc06e28366e2db757197187cf029254968535a13c6c29dc0b1d88d9c871356babc904da678269edae38e990a59dc5e", .Okay}, + {.Sub, "-78b0b7f32541904323bd065b795b14315f763b8c453a26e1c98492ecd88a133ebac080b95e10ac59f17b19811df2130a505a908c7995a0373ed85d83da7a31bfaf67972c27fef1e3e5744689578059aec01e2ff68c8532a6186c364a42b403bd55aab5f20f994f134eb11957c87d8d9c2a5d6babb6ad525c8584c543416e2d70b5d10ddc8b63d05de4c41ddde12b448faa46c8b9417019c35dc1fc2ab29da5c78b812648c8e594c63e2a6e469389d150085347110bf4b38be1de1a281bfdd8bda057dc5a30920293e59413953fb01b50f6e702b686b6f09540a938f29293bbcb6e9a92ee5d844c638284181dfdfe2040ef4b00a8725fbc76a7e105335dc02aeb6fe95d1672ae9c7133042a69e021f95b48b74a57d0edfdd3c4a5d1b34ca04393dd63fa1c5198c71cf43fc0a9d6664110ab2e6bd53f7666956ba4720a1e778aaa0d2fb4a5b83d2079b65718c15f3bb0c69ba055c99e408aa5abe49b89e612f55ecf2b602a734f111fe65c96f1d6e6695817a2f34dc6a2fa72cc25c00a3ddb83c5fc4755a760554ee3fd512315cbb6d2c331129e836110ec739bbf75d2abcfec06f177859545a575c208e7cbfddcd4e4df43ec0f45aef9d1cf47281482ab61b6937929948c69d934953b9071ac6bb9c70a7f02992d5d9fb6e748b1c757a48d1b98c0ce51a061514ecf4fb1b69185ef4cf945e4e9bacf831fdeb5af8ac95effa0e2", "ef6840df31ff32c6e473225f8fccbc10a9e0419c2ef396ded67108a708e8de615c2735933c9bf997d07ec9286a9f180068adc65c1c6e3d5889867a2338fd9cf0f70e46850588c5109b51059ea691a10fcec3dfed9246579ff700e294094ab0ff7990f5740363faa8e8012657094b48e55523758ba589346d53c959fa68b5723f7c1b10695a7d02e965d8fe00f9b4798d1babe62afe00efa7af635d063a76ba322445acaea00c15951c501bdfe55ceb0b7c11db670948845e09bc61c69e9675b6f9b2997b640a84b886bc8b44261b54bde863652e1cdd4be85195279c9fa065b17f33585448012ad3fa91ea1c4fd09208d891fb20fb5e973e69b403af28b43ce1d1602b65ea78481f909473463ca0c87af78fc61a97aef354d3173dc3ae006573f50d375d98dc7fbca84b9dd5039a3c6a707d37c04f119cd34b0f802c433b564cd03d93788b271cc6a6ff26f07c6c4a7a5391fb2f2d7ddf1023ed5f37fefe07b0a87aea8db958112b76d140be92422470ec893f1d71c6b393e09db89237c0004590979decbd29f2abdffe1decf7a63b75e07febb2fe6b5f8d5dd0eda1fd7e698b56f654d2f1fbe0f9bdbd5091d7895e6059a90147d97ea8295fa2b14207b3548eca17724ee634a83c9e1a9270fb391d40762f8955b9b10f4518de13e1b99fcb0ffab94b619cf4eedbfacd614af51dee9a4a8fb796333125adffa45ac92ade0251", "-16818f8d25740c30a083028bb0927d04209567d28742dbdc09ff59b93e172f1a016e7b64c9aaca5f1c1f9e2a988912b0ab90856e89603dd8fc85ed7a71377ceb0a675ddb12d87b6f480c54c27fe11fabe8ee20fe41ecb8a460f6d18de4bfeb4bccf3bab6612fd49bc36b23faed1c8d6817f80e1375c3686c9d94e1f3daa239fb031ec1e45e5e0d3474a9d1bdedadfbe1cc5f2aee43f71096b0d255930ed145ff9afc6d2f768f1aa5b5a7a8a2678e6bc5b84652278153d37e9eb9a7beeba944e749a0a75d5949c874c6c509ed965cb700edf4a67e4a3943c7d923e608f3234217cedcdeb42a58577377d16023a4dceb249c7dcfbc96dbe53b5119508e2867467cd4149887c5d26e490c3989db01cc2c1d640471072689cf12897bd0f76faa0a907d2713179ea7546d99c8b5e7eda007d7b1baba3958e880368b6b3f23661b2e0f6dd6d481e43643d405d563fb1dba7fb40ef3250f8cbbe69b5cfd1fac1e510fd0f77a64ab82ca7224b5d2dd7b069288dc9042c326b3869ae06acc3789c759b840b8cdef3941d7f418fdd4f4102c35d0e3911928a365f7c4c00f9906374a94e5592486dda6837a156bbc6a51c8fb45e433f9d95108d887879f8a6cac5c4b3150b22434106db500ddcd1d9ab041d66f2e44af53222831750c62c618fdb395e2ce6a8bb879d01fe463dab4a7f17dc7b0d3b939074a15102b4458cb553e59289dda333", .Okay}, + {.Sub, "e2bb94013d1f66b36f4c97393ac9ccf08c6500dd09f097a5d746ee3a7b18361a1a56213fed7ae7b151a8f514216cdffa5b9ef87a1c60cdd276a24d86e7856f5db88fa58667e835bcb91c743be78713e28fcc9aea139bb70cadd6f55fa85851a384e4634a898425c2868044f17c282ad66a529aa391a878b97e288a1ed8f8a6123036c696bd7576b635310c7b22b9fb5a2b4efadd1581ecca9d8e5ced23a87399ee2b0719307cabd10856992f7f0a201f3d0590302304b701bab69b13597dfb7bf340e64f6b6f9e19b5b7f5eac18ae266452b4f61d557fe2d78d0e1f359d32fc760835b420a11e222bfdcba57e449d1f0f9ffb17c64cc68de84e25ed29fb1ae54bbe5cb74026dbb5f3eccd65dc092bbda1f7353b7984f7d9653db05311811242707601c177576693f21410c4a22b1d37e3ea1ad212391b09f9dce3fa3f14119cce32fb5a1656c88a142d324fd72ae197618900c77d7e0308ad16e052af2bfc27959e61be80e573f0f21c6623430ee47722201a57bbaa2c388434f96aa903cc559af3e5eb0b261a5b8cb5f52893033179ad4c86b42a08d383854c9f2ce2677160a3cf48ea1ce63be40732c9511e83da4830315a349d4a29374e7bd3d5dba07205b6d384d00e80f65f15f2d7ff0d93839c1acbdef11a242a811d9f15c11656f58e04b7671ddd853941e377ad940938964888a64344adbf244140ade6213cee6f159", "669e210d3061fa5412016f6deb8c81c403c7f6b8c5130f78a81b7900fd6721d82b4b9ecf46ced33d5d54b87d326baf5aa789474c759d4033ef75329f22b0372deccf22cc667c930f768425ae7e12315e98f5235510d0194a2db8449fc59b40f933ce920ca1483d5f02772056370b89ee4b6da9dc5fb82b1727ff02ce1b7030c4db50e1f02d542552ef4f2ab6510b48c6a02ab4271f3aaf0314155d2facff37ab4fb3284d954463bcdaa650d8364bc26d4609af22d0786bb2d5e9278f56ef2307b97db4c04e7247805c475e5f3be6cfc5e0addd41f7d478be4718631b846aaf70b8a7302c856375ffb1820b91b6469ec7bf05407c203e4731197cf689a873f5a4c02759ce05a406b1670a3a9fc8d8a8251bdd09109920cfd6b5dbd78d361515c7be515802932275c07523c65088847f8b5cdf9ea4451f065f76a614b43deb88bbeee19a434a090f9a76059f2e923af8c1ca09fea2e7d9d82c93c335b12e395b804183c3e5eb619a98b1ab0d705cdc5d13f6f35ef7d42574f859f5f2e3d494cff48d2a25a3c54eb52a6dc9c483158b4f8314dedb0481cf2e66f6d8aa5209229365ba288b4703cc2d5577ae87f6b6d850078fd13556d9c84354b755ce52242f4715fb57440ec2e1752b2d0dafc1a80355f36e8176c0537b7a533d393130cf4dcf52a1105702700591b7d6909a79642d1c3e9a901144e1087516fd674d2e22625c91", "7c1d72f40cbd6c5f5d4b27cb4f3d4b2c889d0a2444dd882d2f2b75397db11441ef0a8270a6ac1473f4543c96ef01309fb415b12da6c38d9e872d1ae7c4d5382fcbc082ba016ba2ad42984e8d6974e283f6d7779502cb9dc2801eb0bfe2bd10aa5115d13de83be8638409249b451ca0e81ee4f0c731f04da256298750bd88754d54e5e4a69021516345e1e1c4d1aeb2938b2446b5f6473dc78978ffbd76a93bee9e77decb9b3848142db0485748be5db1f6fbe10d528c4b4ee4cd7384028ed87439c3318f1cfd56995970978b85a412a0647d721fdd83856f31b87ed7d5688056a7dc2b1584ae6c230e5aaec62e0333293afa7100448e21ad6b656848f73db8affbbe71a5fcc9b4add7c29bbdf7ba13b503964aa6ff2eadbf9dff2da3e1fc0e5f490ec414e253f37eac1d45f99a2d53f2e1c20e7cde72aa4027282aefb3559110f44e1b5e1b637906cccd85cee07320b44e860dd4f006585e3daacf79c48666f91862580222f5a476701b54c3d411ea5e2b0e4683e67d4e8fe959a3c6bba7f5652214390ced12f08e5d958e061aa7c817bfe9903e1ebe09d15df1487c1d5482a482cc035aca9790eafb7e0d1b3165547b73446df2fada502030676f0b95d7d94571e108f2252df0c6321fd02f3134e3ce3e3c78514ec72dbe9cb82ae09621898daa661adb684e026660ea3ec72f5c4849efd42305fae9cefd0d7714e5ac8494c8", .Okay}, + {.Sub, "-5e94907f3857916bcf09a7dc1221b1b7fa3e2edf218cc1d841868cb6f9a178565fff4276c7c69f98da86107bb71188f01f368a419834dc57a01ebf5b1f06bdfd17c8cf02490faab688d0b1929b1a1d8cca75ebec7b35c464bec7197cdaabe8005a1b5173b67eff9b38236053f46c267ea969bf39e91021e9fd55abe85918292e0df715c21b0b1ecc7f9aaa972be84742e965d601f2bd274c452177f0f356f4b2441db784a6dfc69a886f0fd954f05aa7b22dfb8ac08032a2eb688f55253c05dd861c5491c8d4aa37b72ed7a641d81a4c779b17eeab25ed40fd1b794c49624b1a2f68e0ebebb2d36f62b3f10b9d868a9452fb3b3b15bdd48caa9e9450356c1562fbce268311078bd0a4d18e417f8c4e09a3e2406d0a6dc656b7a58c090367fd5bf4c9ab31c82860fcb880e59680bac34a1d1fdad27bc239fa808759603c7a53f6975bc534731ac24c31b29c58b2e24505c6a120a9a4b42b3954400678d36a4afa46378e81cfbbebb14e8be31003f45ee1fd09cb58283ceebbe5ed50d55549d2db8c4caeb93d6347860afaba19de5ce8f830611c307e16684452e9d18220e3f8dd20ee2d9ba612a73cd4ddbd37741a9d2bbf17e7b90a0ca948ca486f50be47e4b1d7e45880795af0b4a07f4a193d226c4ddb928c25b653f6f61ab17a3cdd017ee4fb098ef94edbecce9ae503b8db2bf44834531d7c659352a22fb6dc60aae5576e", "64712b6ac833d9b53776426b83abd38ee32d39f37981d5b368b511ff31cc77e3b53309b1b106815d2e183e72e0ac1c77b6640df985a2d5646a477e6ba4ff2e417958d20ce6cdb5d257548e5e2faa795223e12eaa2c2feecb47a3b420648f9585b476787e56092bd9a11ba9cdef5b83e2648d71227f7fceb9b7aecefe4cb3257ac2d5cd6de3150a7158d70b071847217c91118de13175f6ead0b249550aa01691387188ebe695d8f65c459f52121d9757962c0b061bd7ae3e3b703b6092ab33b181e05680d58871107d469816f3de646bc1ae19e32191a9d525159389e3a0b6ae9ba5c8be3bc51899ec2d8a5c3a63e8fd7c3323e21cc9094e320ec317e45b097c6f243b7fec11b9cbc148e4a282593495bd54dee5e65b372d60fda1c44661f536ae21b01dc5c1b1508f1be55a14a4a4bd88148544e230f047debd3133fe9ad24208f6fad6a204eccfd242d0291fe9701b7935110770b90f09ed4d5b0902549db6164638622149eaf56d887c554c913161c259614967383258c9f7e34288640ca19d21958b389acd0426d15861d6a0ade10652adfe3b7b4e6bf887fc618e7f80593b760e21d89b165692fe51c1684666dca6e967fb5cabe4e70bc9d48281aae04830cb832486023644a39de7f813427338952967b60ec4a605b82b6f6760b372e3dff9e7033197592891f039b9fd87ba3f202aa2de5240bf5fb02d58c940dbd57b", "-c305bbea008b6b21067fea4795cd8546dd6b68d29b0e978baa3b9eb62b6df03a15324c2878cd20f6089e4eee97bda567d59a983b1dd7b1bc0a663dc6c405ec3e9121a10f2fdd6088e0253ff0cac496deee571a96a765b330066acd9d3f3b7d860e91c9f20c882b74d93f0a21e3c7aa610df7305c688ff0a3b5047ae6a5cb4ea8d0cce32ffe20293dd871b59e442f68bf7a7763e324331e3715d3c145fdf70b437c8f40708d759f90e4b4af2b670df1ff485a0690dc57e0e126d8cab5b7e7398f07fcab129e5d1b4834756fbd35b67eb8394931d1ccb7971622310cd62d0301c8cb0ea9aa2777ec094ee17b67d7ea7391cf2e5f1d3286dddadcad576819c71edf6af26202fd19459c661a72e401e5829f61371f52f0c8fd8418a32dcd49c9f292a2eb5b4f8dea124d479ccaf0955f6807a53460175df32a425f448a943b152638a052c00b151faf1c03f56c81d2cbb5213fd631b1156d3a43418d6181d5bee8b05c7dc6e3f105d6a6bc145f6550859043bf632ca18f752114afe53417ddaddf7d296e444475fe148a31cc127bb4fd96d936b3ca2eb991b6b04b71cde3af6379365c643bbd7eadbd9367dc0ef8dc61040866014fb466b88e2fd61243d33ff2c4fa08afdba4ff5d26f9441d32115064df8670bbf3dbc5189cfbd2dce9a43db4f1c8db0375fc807345f72cd53d72d8b3ae87547dc05ab7d41201dfe43529ebc12ce9", .Okay}, + {.Sub, "-e7699b1366ecf0726aa26321a69786b7bcad434baece16b06459e17e63021e4b1896f941d160c9c9156610cff9ee25a17f7a74cbf6a83199a5aeddfd0929d56ec797be37b0118a25ee18ed29c7f1919891f6a60fff79dcb19886932c470be1cdbc408041daebcb6f336fc5274cdf68ab106c539ed423d89107af5d3d179078e6f034d059f9fc1b1ac48c10c87df957ebbe0c0fb76b296106269e0b4f0283c5676810620280ef78eaec08afa68d5cc6235fd049defcf7695b9a602a15246e8d439535df8810c1cb49bc411a9020fa4afad73037120a9dc0db232922f3fa80c6440ac03a134179fb0925f0a62d60018530177b6be48356be338cda33a87fa15ce64668e54ffdfeb409f7c9b15f6699b1c26e38da3e2b75a0248bdcbc8c335e33e81386548d17c87165e8e20cecda814ee00fa5fdeec9348e99ed8915a15e53756d8cb2fa4d44babdd3cc2f485cd9075ab1e7a9fae0e905a0d1bbee45cc6210555b64bf54f4fa33ffaecd0a116464acf6e333b38a600ac773643368223804e515742c3974d3888b2b29a9f9b5f7facdbc0629b53d7fe7dab679202bd11c2a492b8be69a09d553fa5eb5125c6dc3246c5f1972a8a5d505b5c5a8799a5d048ce3f7750e35331a6f88201cc7364de8e59e4977789cf057f749de0c26989ad0d1a0b87492d066c92e755add8619a3d767c5d6c7eac89fb84eaf03a6888c830263913433", "daa4b8fde43d1aa1f75f249c46dec51dd15ac8b4df3882aac91de27d6625b498462b4d8c8f4b0cbe6726ddb1c697b35cc8bb08251f0a6d628199668bd02f25b61db470c2f9bd5de3d4a65f70c4ae8462398b60762e790f854c0f687b1bc4ccea772b6e13dd15f4d73077b640abd23c504a2f16a892b82f270bc361039eeaee20ae74611656ad733ce8bb75176fffdced9e16162d1132b589a13614024318e18ad351e72aba11485b0a2044212fa06358e399cf9d9b0faecc778ddf5d227de1cda9e3f575547f88ce9db13bc37ed34423a8cf2ced47989389d55b51f20f95353b08438e8c556dfaaec3696bfd983cc24dd6e2a0d5d017a9151b5a45602f459e86c75313efdc8e1d5f2d7e05a09194e3eb638c3da5a9eadadd2e89ac816b5cbc98537729dfe88a5aa7f9a33282a11cef8550482236c9807446a4040917fd9cfff527259890b6ae584ef89f3338eae9714f9ef760dda0d1b6efdfeb0458fd00583c795d709793420495a48a8e2567f94c9ab3504270e25597abbc230db354a9d375088f78be3d6e0050f429828525e9565c5bb2ef6a1f0530c6fb4f55ed398f81566d9f3937af624609bea8f758e9aa5af9179751cbd54f26566259433dfb2d5b283d27b9c107592fcf78cd2baf2b4e72cfa676e6358fe849ac714f865fb5d4f776bd3ace31e8745764ecb3fe7d74412de89ba3019c0d4aab789917468a20a16aa2", "-1c20e54114b2a0b14620187bded764bd58e080c008e06995b2d77c3fbc927d2e35ec246ce60abd6877c8cee81c085d8fe48357cf115b29efc27484488d958fb24e54c2efaa9cee809c2bf4c9a8ca015facb8206862df2ec36e495fba762d0aeb8336bee55b801c04663e77b67f8b1a4fb5a9b6a4766dc07b81372be40b67b67079ea9317050a98e57ad4785dfedf934d95c2225e47c5c168fc7d41f51459ca6f23b62492d3b00c145f628f3c7bcfd297c436a197c9807182811ee097246ec6f113f19d4fd6541541859f256539fcd8f1e7fff63ff52365464f88474e60a15fb7f1303c89f96e7f5b7e95a122af83e477dee5e0cba536e6748a8347908aee6fb6d0dbbf93fda8cd1692547b6fff82e95add1c517e3d5607b01ba66690d9ebaf08066fd7e6d0052cc0de2853f6f7b9e3e655fee202592b502e0918d1eb95bf07562b3d892ddfb691622c4ce7b95c3f0cc0186a15bbe89d757c19bd94a255f10ad97de1cc58c8d76044471949f89cca6437de703ccd0ed1d0b0fef8b2feb598ee8e934c8ed91c5f92b7a9e23387d20b7126285682cea06dfe7401b7b270963d8ace25439430d035ca4bed105651c0e16ba128a3ff7a0db04ebfedbf3a0428811529d4b5cecdb76e14fec4003799810ecbc471f13d68d873227b897e821308775afeb500b34fb16e9b24272cda254dc0704b0866ba1545bf9af1f21a3c98c84329ed5", .Okay}, + {.Sub, "1447b95885dcfc72bd80454d540cf4cdae3d5478349478f64b290dbf6570a5f2c35ca063106ffd86344fd9385e52a5e6b54479d0e66245ad6f027828d71d1041affdcaf1c16ae1ebdd1665c46cf97608f2cb6eedcfd4d11a743d21c69a046429646107fdabc4fed80f2a176aebfcb174767a5b0c3269b085a17f6c424c2bf0bb815047266692c23b601386109d82ac08354baf250202d15ef89a6667803568a7db45256e2db28080468c68d30b37a1285ab4a2cb8109268ffc83824375714fd3c8ad9c06a6980a2b1f2790cac83271af01145d76c6b1436793e1062d58ce1550f73e32f696ca8c11a8715daeee0405bdefd8423659215748d7670794335a3095e00221ce0346af5248c9bac369bc9555e713391a228d083213bac2b81e723e7717f3b4b849a410cc8557411d00fcee142ae53d2507ed279115244566df7409bc6668b78e233d485bcaa8568c81ed2d8db3741ed9f29d5986144f42d7f0179b6d92f2095971afb3a7deca3c235732dcc411f5fd363e65ebcc27b9e31557540b3838789d7f5272d21b7482ec2b0a8206f422630696c926b2fbc5c87fa65eb88f8c7d2bfa1ec88d60fa398d7718906fb5555f4780e13f09f904473171086463c7ead45bfb7f9e78631ffbcfaf863cfa35c053e8cfff72468169494b4e062267f4898af3c18a52ac2ef5b88745d5ea5c68adab4591e0ed044219568f2fd6341fbe89", "bb432a5dfbe0b210d12924dc49a404855f5dd8fd02355f2911031bb67407833f940124962d81ddb82b0df0443737b4423a7b9be697da6120e3ce8e8e0cc36e4ca9d35ba78fe62dfc3ea6e8336c9bf31760b3b3c12aa15b9731bb1c7d0dff899213d95636294b7c59a976df70f8042c716eb524f73e43591ff26f4050d88419e32af31565ed7d2c2c88cbea67a1be6f372dc3d3417aa91e384a95ddcba582d57d5be573d17a5f9c1057173524cfb14996a60cfbaacd2cac943dbd24ac50b2dc9d0cfa47917b386fe28584a96753b13797fd67d9d94beea66d2c2ac99ccc04b84a7b36a412ed053ef178ece8461a667688944288c78fbd918ca834a9d2b7198a19cdfbe7ce5c9fc74c6d6d9f807c2c13071ad65a3621a8cb79ab03385ea099d439ed1022f6bef5a2e40965c72418969a01e98be1db357ad3e8d00a4b407ea98e42988252a27b2fc3816f2e74313f805574ce726c1bf3b0bb67e1b95fbce36247aba714680d403ab514b656030b6b5539dae5638365abb0c6d3cf821b15abd3d3a16c68e509d5897534a61f6d02114c6ca51b57dfd15f2ca5ac2b0af6983800d0bb2be7b0e63d2ede73ec603234b0c2dbb8e90c94777924b4c2f04db3970c3f1f7ba202b9f4d573aaf3b154d6f67dbe63ec086d50ad546ab2ae727a69bac43628764b67b479ceb45de8f048c5897b3dc8822e785107d829bab94229cc27edc2b1b0", "-a6fb71057603b59e13a8df8ef5970fb7b1208484cda0e632c5da0df70e96dd4cd0a484331d11e031f6be170bd8e50e5b85372215b1781b7374cc166535a65e0af9d590b5ce7b4c106190826effa27d0e6de844d35acc8a7cbd7dfab673fb2568af784e387d867d819a4cc8060c077afcf83ac9eb0bd9a89a50efd40e8c582927a9a2ce3f86ea69f128b86457043bc32ef878241c78a64cd951fb7764254d6cd580a04e634cad1b90108acc51c479a86e4b5858df4c2386044139a268db418cc9444cab8ad4a065b7665d189c8b7ec5e8fc537c62853d63059849c36f7336a2f983f8711c563ab2dfd07b8a972c6270caa46a4691369c3a43d0cda23e83bf5983edf9c600595917fa24a3e4bd126f7db133c3211bff1bc347974875a6822795c2d51c6e3e75519217840e86071799abedbea6a4b62d8dac57bae605d99f35848632199b1457f27b25a4861da4bd9327e71afe4d42011361e1cd6a1ce4f34aac3e14225eb3ce8b016cd78bc6e814225d16d36d862f6d4adb07a7c83800547fc86933f0478a8316a319319c80d706ca65b0f8f4d93a9605f2b0654276f1d948412eaebbb6c774a17d79b2d2bb1c2053266389c513963a1abbbea91c428ea7db5790cda6be7536fb47d3b585277040c42e2bb48480ade2243145292f1bb4a1ce33ecc073f2ef7c082ef337c17fb390e15fd48332bf26eb25789feb9a9c51b9a2f327", .Okay}, + {.Sub, "610714ec9551586b9f083b72a49f29d00e17e24267799f8c48f64160ce35e4d27d0fc43d072aeeb1e3e1f79fa13f9a0c1ccbb47874c75fbfd5aa444ab7af68fd70ac63f9b0fd0dd2c096cd1e604fdbd60c36fd1da140298cf1feea8498e4392e04fdb3b5113597442363de9aeb5e6ae270cdfb1ea484922b49bbd5737b6f94a29a75e2617b6aa4708be3936b39f7c2253796dd7028f8e8198875ba4d919037b5d4d6d4e964f4d236d7690ba4128fc796d5615732d030979d1cf22769d1b3b7103da35c053689d62343d6b6caf990bbc8fbf28e508e8934351294dfe07e054692a32106ec5695685e099a98c973b812bd2b26ca8796202cead3aa9ebfc3af3da4dfe3a089181d761a7d65cc7524b41e47c2fe38782af39128fd713c980e8e986975614103cc3ac3c5c6b7f5d44b2e42a4a6d047cb2253b40b7d17f8f959fad7f8b28cea453ba281cdb70e40675be1412912119cb2c998958184d5beedb5ada3eac6e3a26eeacc0458290da6fa54ff4dffd1b58a8f78892fe17683b73bd4b62eb14758b65b59f9d4e29140686d11b8683d9b3df7ee0df6ae833ff356c24d1bebdbe80ebac0fb9f5b6cfb1aa7aebda5b0165b363d07b232a1589adaf762852af213b902a35be3a98f62a77c19d6621b094d70c9ee04cf60b13f8fbda31e262507a0f2a540b7cf2ad88787833ec6870bf43e6585d3d62def2476be9b0115221102b6", "db274668c3a3046fa62308ed5f7dae77bc3c033d5f7aeaad84ca1a7e98da0291322a0e9809f915598a887efc148d3b4f910757566de935df830d6ce9739ae14ec9a16fc476a9c610122f42ff506466d012b1da44bdffb6415896d644c9b0435d4ac081f24e55786b4ac9f7564395f738c45b5c16f3b447b340ff11aeaf941089cdefff8da1a37448ab5271e5bcdcbde37c5d9b8c5b2f4e35fa365129f38cba5da7e810a1795e761e6e77f802d7cde2bb20eedf56fdd04c1826091ef683bdb6bdc38972807040e106ca3965200c2203c65a86412fadacd6187abf8c03b76a02f2da42aa32238da30362defc075c29e1113b29fbe73971e0ad3aee78cd0154ec21027e888a7ee8e18476f2f9a498d918580e6ce5906496ae13aa5e92af2c995783307d2fe091850e9fcdb7a16ed6049d0c05f34bb17842d55aa8eed508197450c6b716907503b8a16d536ebcbfc20a8e46d0ae18f4e62824010eae5e7a406628e8f896fc431b796b0162f92122c71ade366711571abb87f886b6a59ac4266c473704564bc8d507291119796b4773db104f1f23f428fc6e029d5d4d4ac4d755ed176a4e5f6ae2b4fd7fccc2cd2a9496aa55081b7495cd3e79fc39342d3bf010c15de5e823988f2fd8d3deb8b2ded2cf356c6e44e6c6c3c5a3f391f386a62d839e96fdac82d66ef6743986e8b0033af7cb740610f6660156eda41f3fdbe50c5743e6", "-7a20317c2e51ac04071acd7abade84a7ae2420faf8014b213bd3d91dcaa41dbeb51a4a5b02ce26a7a6a6875c734da143743ba2ddf921d61fad63289ebbeb785158f50bcac5acb83d519875e0f0148afa067add271cbf8cb46697ebc030cc0a2f45c2ce3d3d1fe127276618bb58378c56538d60f84f2fb587f7433c3b34247be7337a1d2c2638cfd81f6ede7a82e4fbbe44c6be1c3236661c71c096dc61fc82a7d3113bb81469a3e7970eec5ec53e1b244b8d88242d9fb47b0916f78cb209ffad85e6167b39b70ae38662ae55129147fd5e93b2df1f23a1e3682aac233964bc603721a345ccf83aa55944633de871ce541003315fa351b3c26743da0d3da5ae7c229ae80166cb6b69f98d2d2f7424fa104b6ead1839a31ceaaced56171e0abf19bb1beedcc54a4ada06ffab9a8ad65a675f2303e655ef214f2bd6dc0ebf7978ce0489a62fc8161f9f9c607c5866294d1dbe9c7c421c8f8e7f89d89f8c8ab884fe31b359d430ad66a939eb7a28721b9036955bcc8b42fec8a54021e38851b61885bcfd956d7b0d542e883902da6222a81183e5fc3aee77541a1d59f4028a3a013b823fa4a9e715a212d1a8257bd6f0fa3eace5378e1b0bd8a39e5935d96ae5cf4a2ce5803cab864971373c990870b42c1efd7af8c1f464f2b40235e388075e96f60b07421e9fcb9bb1ff65713cb3ebd735a08b228fd367c92d60a4dacfea464130", .Okay}, + {.Sub, "810cc5f334ff377df039d0ebbba9cd43cc8e0c27b3d4f9d379a41d1580f990dedd47c0cd3eb90fb221329f7fe96b53485791d66a0f98793ff2dc3ae1704ba5ebbb7b08c2cc9482bf16bd992f7625820144b4289e8feb7aec7e31b14f98bfe4fef5b8b1cc9f0d82782fb8b58cea7a6d6c4c34da095246b0d0b01f0f1ef6b2541a397387a1cd83457857142f6900ab68dbd5d6ff1526dafc7fb6ce5a64dea1331e62f0ebfb88cdb38530d3167a766c580a39dd2fff7d85a8e31a2354c52cb49e8285bd75f9738a49ad25ab5578064fe603042011e4517bc1d52abf0ee8dbf85b31360caec9f1a0dcd565650ee4d1d08dec1739ba0024dcab15fbbeed36e64fcfea4f0f46c8c7cce7e67fab2c6a6d443894b27a57d225c57d5de7cbfe96d582afba07f399d7368fdbeaced22254dc90a569a562f37b8e0c1ddf38c5bb290b4b9edd6f92767e258c30801988c21011a0eb359aae324ef974d4231eadcb8d4e9f40981783bf4a28b2de45c8ad9a24ee3751ce80841f0321c416cb40269d85a57518d553b0ff7c58b02b961f90431df0be0ff8a7a57a5571201ddc566790e5df20610b7c20e84d1e20cc6cab3c95adc971556cc0357b86676bd46e78aad256e78aa67147249cf448b79c4c868ed230a5f10ff50bbb4818037907679aa7049876ecff321193e98e5aa361684d3313e32b0c010bf9037393516926e5abb81b2a1246b6f0", "7ee144e1af27d1a53863b246977a97fe6d28a43342862b320b17a87432e226f5122f4a6aec3e82dded67ab9195fc7359e753980b5169b187feab334fcc141765d52ecabd0143979659837914d146064f3642da29dee981fed6f81824411dcae76d9d808bf3cd73ed3a60eb9dfb51727994657a0a33e8a023e98f7bc32ddf72c0540259f4d8e2749fd6eaa8983eda73687a9ff60dbbb5a14f0ae1d49744452b64fe793c243047aec9681ea29e750fa9054182c70888637cfcc5bc5519f5e6c67c5142be920bbde6d37e6022799fd1dc0ad0120eabb8f3573c5f131bc1012e125fb3af668127a9cdd1fad1999071c76e595e936eb5b7471f7d13e13b27a46f8227370ed027d75be106963dffe6365090559db67d3080ede613e1a9569508566d9a39fa29d6c6ec36884f96ba03156c7d6bc2df08e299e5ca13b360093a7dad7cad42a4f0f8de1f1f05f0cbdc77a2c47c92f86dc3ea52e31850e5bec5d1ef4a9c2f897512a44d77284104689a7463349107f4da2c25f67210bf529a5a3ff5e081fc0103210f040b687f53409a02babe42b09d476c8b10edfa65f3953e57996688c5e767439d66bf2f8bcf8026004a7cb1dc07a7cdd18efd407dfdf23c212729a573583d77a4986e89241452c6456578a2d80ed6c6648164229a7f1b3d616618d9a78bcc48440a9b4bec09607fa5e6024f75ccb2879c094f258bc62b142e086a19fc", "22b811185d765d8b7d61ea5242f35455f6567f4714ecea16e8c74a14e1769e9cb187662527a8cd433caf3ee536edfee703e3e5ebe2ec7b7f4310791a4378e85e64c3e05cb50eb28bd3a201aa4df7bb20e714e74b101f8eda739992b57a21a17881b3140ab400e8af557c9eeef28faf2b7cf5fff1e5e10acc68f935bc8d2e159e5712dacf4a0d0d8802986d0c1d0f5735b3709076b255b30abec85cd9a5c07b96477afd7588604bbc8b473dc015caf04f85a68f6f5222be65466ffab36cdd806347ab76767cc62d9a74b32fe667e09f8340e033898886a98cbabf327daca48d1825d4848c9f70f036a93755460091f92b8a64b4a6d958b98e7ddb20f41e04dc3180076a0f07106dfe96d2c8436f3a83f14c3daa1a4d7974a0622a801cd2c421fcdf970006fa3a5627f3b6851c72427fde283ea98f42653cb8565b1ee8d9e22302ced8585476d117a28bce5986edc6ea2a2406e64a691bbd238ef05bb5f54a4688e0eaca5db3bb604c444ffb08b02c0c68ba9f2dd2b52060bed8c4345af9496d952adde6d54a4c316cc4fa91b35ffcd480a5e0dca6032237662d2528e45b9d84594b9a4afb7619ce0dbbc6fad7ef4a390b88dadb4d86e93f07ab89635c06100fdeee7254fb0491328723c0beb40786d1cfce481b38214e4cd1b8bc73710d4258a85c7a14a5008157c43d2943d4509b1962c50ebf7481a0159e58d06fc09dc9cf4", .Okay}, + {.Sub, "3ceb133b422767d1a0b553facd09ad28be576d65d5eefd444f31e50f57d0768ce8b71692b1551a46e80633b9027030e27bef2ea9073d8e432fb97dc52fe341e7ff39732fce62bb527747a3393112234b6339f541be27bde81c118350d96b085c830282feabf92683a0e45d83759ab157f4ae3bc22e2034bb3e343450d4d3a36b8b20a4100c54096662975dc42a206c4311f4449df42f40fa17655e3159d9fcfac1a91223f81e56a3f9e243bdbe47ca205f2b523b2c23ad0e4e3abf4fa33f26d1191eec12d5b0f786a16b703e7ce4e97d63baba3bbce330df42827955280c13e7ea6cbe4be72f676957710f771420fd6124684d69e81ce00e07f12b71b3d89a37e2a232fd64014adbc149a07377782815f077278a6e04b16616a12c3342d486055808eee6ce7df7e1a16551c946565df85e0cdc18d7aaf52e488b64dc555c6dfc707c2449e8c94c5c5a060061cea7eef992a96bf074dc843aa6f8aeaa2c1d03cf7d4c3d65a73f78615dc46835d45983bb10e8bbe2d6b984af2de055a41666c5e51290774fa85001e843fe62655c5a0060c8d41a1f246a3d77e578b3be0ead1b7332f0c2d40ab5e5544c00626bced68bf58dde078d46c89fbe625a23597f00a4629b3c05e3cd13466db64a43cb9715de1163695c40c1a27d169c67c0c7ca71e5d16d49371c0e383e5bb433c5e4fce5af980b3ae9171c8fd3a3d9eba68b94324116", "af4a76da2f7481e72294b9dca93123eaab8e4384e258c2ba6879fa518dee0eea5887bc5b62c709c075411736ca06052baf1aa40a8bc3a25473895204e7af7f7e741dd202fb025472b990bf67e15f9b9d4db32d1c7ef718d87d3bf182a9a715ab838d39ebe935404e78f3449dc9bdd0276fa04b5e734659ace6e41d732cc61e4c75199176cb1e0c6652cc0716057311ab648209bec36d4a8e61570dbafcb170a401ae09d24f31b25c995f0449019075e7ed03f42352fb6c4b4e8947769eaca57125fe678e741b3631e0bd23c7c4fe6f90f8b597872b9f70e75a62830c17263565163bfe286c30e2ee640a01ba1ab4ae4bee335abc827b9af744af17148e38e8e114281e4b1503f157284db12cddb94130d7d8c082433f9e69fa6f45bf4718a20685730abc7ef3e5879631f9e2e0a64564804ca955e135c748e2b58ba2c37f77b1a948409a0b50d000e392344f8fb5b3c0be9590ef66abd0283afc5b532c3486fa12ed43dec9c911e7a34c67f922728c21cde12df49a32af2ef945df091fb0b51a06f6ba003f07234332e28d699bde1ac4dc56a53a2f898b4b3b431e3045a20c072b065000491df0e8a9ac9268f68ece75d5d8cd12aa620cb041b11deb67cc0fb924fc0be1f9407ed4fd714c46bc217cabbadcadbbee9d08da29e5c99ada52e4692305c9893694e28f29c858602ba3727c491e33b6b9334cffb97641052e14be06", "-725f639eed4d1a1581df65e1dc2776c1ed36d61f0c69c57619481542361d985d6fd0a5c8b171ef798d3ae37dc795d449332b75618486141143cfd43fb7cc3d9674e45ed32c9f992042491c2eb04d7851ea7937dac0cf5af0612a6e31d03c0d4f008ab6ed3d3c19cad80ee71a54231ecf7af20f9c452624f1a8afe92257f27ae0e9f8ed66beca02fff034a951db52a568528dc520cf3e099449f1af89a2d773a94004f7ae57135bb89f7cc08b4348abc78dd8a1e826d7bf3d004e8826fb6d7ea00cdf7b7b9e6a3eab3f51b3894819861394fadd4b6ebc400817e009b6ef1a217d2bcf3fdc85017b850c98f2430693b0eac9cb0d529a5ebae93cbdeba2da604ea93185eb4db102a67b670410b96641191ae76198f7d53aed03e3ce198c04441c012d6a1bd5b075eda5f4cca8199a4fe76c223fcd3d098ad21a9a2a26c66e2309b538cc1c50228783a4898c33edc10dc4c72bec24fef1cf4bed9403aca90017832a95a10679228999864587ffc34e190866bcf87211c3792a7fcb6589650949ef34f46642b096b7215aeee42b043f841a6413828b1b0b1f4dd355ca6a7236f4f093f8158d2c3e680b945dac2ffd27b8428047fac58563996cf1df56fa91e8cb6b5689c005fe2c2d38674727087b250b9e9a5773517b2cfa8bc38d7e08d30fe0fe97b5bc926d285ca4337594927b2ebdc2e43de34a9f9ca3795bdf8a9a7999e27cf0", .Okay}, + {.Sub, "bde0ed38d73a1bb75b70fcd32b9e02a9a80e5f068924f4117dd6482a038bd7d5d2f07d40411293ed501f855832c2daa53f6038c14d6424fb8591424571c3225eb1727c302edac5d2e2ad5c4374940244a0f50a562674d8d6b0c11cab5d3bf43cdcabb77fb9aae2b17da24eb264e3f43ede447b21b91d01c53277c25f1c47940c5e7a24fb2e68f25ff05328a7c31118869689f7c998d9d6b26a1a8b265a072178413dda4dc5de1d9154ef6eb4bb764f6582121024e17e0fdc0ba3e06a2f0a8bd3cd2656ad63fd8ac59f845bf6bdf0d221da419291da4d5aec8b9c18c3d510b3e07e28f16d638c1d3b12a5cde9279b2b9ac5294bc6bcbb1034c65e1db86a5a88e0e13dc70b7e95f119e5bda5412cc20741b6e2f108deb285cccbfbf55f4b79ab95b012877a9bcc034f52e3ef3bf419237c7c9262e4f4cb0e2f12791490a7ea40696a794690ba247bf0b7a8320a9b3bb1961576c98b13f8aad6a4147cfd9fd00999996bfd07c7aaf796f4d379bb990d79a6e7a928026734d16038b4e6fbc5be2aa6eea888814e7f2b71595aaba8f815bb0a1e1959ca6d68abb101cf41bc0e3fad34479105ab03b0714a09bdf2b81f4458009810bc30e461db1b7f2541f486319e9e26f66a151e645ca54b00716ed1449376b1b87293fd7839e27ec7a591a21922732ca6144f435c8e6f7e59df051773d4fd6d379db56025a3f911e60db47b7c51dc", "6efc6a49fb4a0e0a9b0dd791c29432244757f258d19fd58123538e4e66821431f25ed469dd42918a2930d0aa22f39021e57a969f97cc7312a9603751c58cf0c05aaccdc85fdc237d89e3c966822a07e8b873efe6a1bea1e53a5c66fbdee62c419eec0f94971aeeb4d4c593742c906a3905d45c3211882052a4ebed21daac0c3ad6a9af57bc930b9f353349544ce60dacedb0172f0ef439819952a91ee16aabbf0b69e786aeffcd737839b342753bf5dbd003dfd85c4bd41d8c9dcf08cd8b2575333afd125d9d173eec3da5b2d7364c089eefe34edea9bd6ee84b345b37db826321a4e4be8ffe6c4fb0506b8b60addcef02dd55d4ebcff484917b14d1b3ed708a54271edfd359d507c644e54e7337533a0035c5ee2d3a629ca9d7a700a3a85264440a06737f4ae073778c7e07a6eb3abf3021787e3a39f7d7ffc9e33b1c64a0030839b830de31517868499718171598b22e14a3f4def17c8296aedcf1a912f51feab940fa7cc25c97710c0cfcb82c054d050055eb2e06e4d2b37692bcb9a690f1c32a9c41a6b128939dae4afdc5376c78bb467aff20f54df341951868d7fd74a8bcba9ecb41467ce235b542d4b0fb5a1c236631b03441779b1cccd8923509e869bbb90ca011d361ca050d907200dc40f3d18500250d618838076e77d767deca0f9061b71b546fb0e4cbb5ef2412fbb76e2f834b32deab93cc3c489743b6db3f95", "4ee482eedbf00dacc06325416909d08560b66cadb7851e905a82b9db9d09c3a3e091a8d663d0026326eeb4ae0fcf4a8359e5a221b597b1e8dc310af3ac36319e56c5ae67cefea25558c992dcf269fa5be8811a6f84b636f17664b5af7e55c7fb3dbfa7eb228ff3fca8dcbb3e38538a05d8701eefa794e1728d8bd53d419b87d187d075a371d5e6c0bb1fdf53762b0ad9a8d9e09a89e59d30d0c7e207789c75b935d3f2c716de501ddcb5bb72463a5989b20e304c85323bbe7f061161617f665e99eb599b06607386b346b643e6ba86193b51af42fba39d7da350e4689d35317d5c840caed38db0eb6255625dc6ed4eabc24bf5f1d0eb1bb034e308e6b66d18568d16a82bab3c1c121f78bff2b98ab407b6ad2b1ab178233022244e5ea7d159316c0881071c8122dbdb5771344d2de8bd4c70ea66ba91165712af31558b85a066623f8e5fdbf32a784f5e9af2842618e3e762259635072e540d65a00bf6bd1479aeb2bc0d4ae89aff83c76cbee0e17459e2a8d217392dec8d853e543f0c1799b52b7dec3fa7ce02ddbbac60ab32de4e9162d2decb4c735dbdc03a29533642388b8ad666dfc269f467d408afe36e48fde474aa8a80b0206380625869625127b6346b3d5d750c90fadb45f2e0fcd0685282e033726ef016b1aa77592dba3a3a58639c445d33eeecdd8ab2a3efe104781d8f3db45282817a102cd59d7670c4a11247", .Okay}, + {.Sub, "ee322db2f08ff445c516b4aa8c68e48ad17c7212fa2e2608d097e55eb130cde1226e7d715a8787f45ee7008e5380bb7be878a8cc75067b10259e9d3c403c44716e1c0a6694444fe0d381a15c2839d4c8a20dcc8760f0e1e2688e08006ea5d8343f514dfcc93767e446a86ac200f5004f9a7317855077c5202c62aa6a6f9255395716f3eda5474fd24e52343277d10ed371849d9190e30855a36af13415daa4116c1932cc63ac44aea25e08384462d2e4dcc23f50476f941291f9a3374b2d00344adc0bef3de09b8c8afe9964f1c3f067a4ba13beab85d07b10b555db167daa6c1d41d82d0b91b9e1429e1e122aee042185c7f526bfacc3c44bb531ba29d62eef761202654b07f19a7c68c90a935dbd0e2c9b77f6cde12bdd21e98aa1bb31044995e374bdc865a9e07069e979696e9e0765b65757a2ab19952a76116d5650562b90ce50e331275490b0578360d31d84cb55e9b6b713bc68fdfc7f35524c1f6b3d9338a6484154419be8e79234d393c105473be7b9425f68d49a0903fec2633b61b938c521d6a78f7bcaff226d3438eeba4193a2f0552e6053a8c632f0d45626c9d4f15d8f6d64d80a6f81358af4ee2885fc9f085971085ecc0158019a897726d10a13ef1f215a103f139c7344b779f34405c7c56c46166a93381cf329fd70f25b57ece2d09f8aef4bf5c856ec71ebe9237108fc7877f51cbd4490647539968f69", "818687dfef4db58c152ea6fc8a50e589c76431d64daa860c2e0682120b9010c3549031142925abd16dac38c64670b508cb99fb0cd89208875c7cec3c75107e9b06690b486cb883376ee75116bdfcfee1168ce87e0e2ce57bbd73c1205238a444a24855fb8f403c37a5ad6aceb13d7dadbe5534ed0a672f9a4018c052189dd8eb0ce8e303dfcd3deee970b9af0ac26dd899f9a6773adcb1ba37a5da63a921efad883dce8d464d7374038b5917c435a185ef52cb4e04da7d10e537d5bd1fc8667f148f9da290e49622178adf0ee092d40763fb2fc56bf1c901c2562511cca44cbda8dd96365d49e9a715c3ec513ae9e87cb31c70c5dda67ab99309f22131f5fc1c679a66ebcaec898a1c147bba0f000d3c0657753c03a03a5d2f2408ff50dd1f563aff4c51ded31ff40a6b54f506cf4ab067ea95dd6c58e895a3004ff413463cf08ee2877df260dd70111eafc669e3bbd21e0b07f790a618d4fcf0551cc3fa6239f15d46050b579dc96f39623b9f98055015c0cb2417ee5e8baf139e0595d552e337e019b8d4282e532e3b9b4cc0ca4b189ff6907da04e3a7aacd46f5cbb4c00d0b18c993209f57c88023045fd2dff0a5e5d5537fc705169c7bd0732b816766a2769245b75249a219a7de197a22d52213a09d626b39b6c062b91bffe2a6ed032a97f050b61baf462f1a20b09aacaca51b930f9b72b4688f04bc83eb8a6885a180d", "6caba5d301423eb9afe80dae0217ff010a18403cac839ffca291634ca5a0bd1dcdde4c5d3161dc22f13ac7c80d1006731cdeadbf9c747288c921b0ffcb2bc5d667b2ff1e278bcca9649a50456a3cd5e78b80e40952c3fc66ab1a46e01c6d33ef9d08f80139f72baca0fafff34fb782a1dc1de29846109585ec49ea1856f47c4e4a2e10e9c57a11e364e17a836d0ea0fad78af71a5606569b6bc516d06cb8b463e3db643f1d5ed13a9ed2af20802d315eed6f740242951701acc1cd7a2b6499b5364c6e4cacfc056a7373ba5611311c6040bee3f93f9407794e5f30c949d95dae746441f6ae47d03a2cda31c0f0041ba4d2ab8460e206490ab8ab3f98f7e032d30e779b79801b681060544d50845dafd2264402baca40f17ff2c581a26a53e4f35ae4286be99289ec65fe9484629f5356fdcbc17a365230ff8775c179430a193b01ebc9653ec677209f38d39a6939c8f937deaebf83165028ff8ee03588250903a1db604335fca3d279ae2ff933fbbbb5317b1c952a710a48eaf565f92c8de87e8158ab69027f61289cc38720736ea3a1a19d1272b4e025d8fbf1c394190a25f92364c45d636f5b826d50ef8dc6ef1e279f49d05d00b6f5044450cee27300bca9a0ef93a9fcbfeea495badba28a27d209fbf19eb8aaaa6467a65cf4ff8ea0bfb1d8e7d76ee4968c5a53bd4d41a721976a400f454d316c2c717c51abceb13c775c", .Okay}, + {.Sub, "-e9dcd8a7acdb388f26b865bbcb9498a51ad4a4bd7a168469356ed5aa07366149fa092f5431e3943c2945cf3852de993b099f01047b2e51b9eb791277f823f5ae1f17c12177951db4784874d686397d0e2017dbacdd8616b56b8f634bf7501a723ec5ee487f47ba9c433e194cc575fcf4420570d4cb5cf988c2beb37833d881dbe28b3a4edf17cba0bbf2f0bbb07fe8c685bcdabcf09ab4a4ef378a6895963b504ae4f721a3a54412881f179b596ba6d33ee92e498eb7d017cfc2c8db1a0a8549648f6276569cbd64b3de87965cdbfa17a4b2663d1962825c5331527aed803be829fa80d03c57a66de18845e388d9bf85f1e838d2da5570ac08c8bd7b68888c42bb53204c99eb8f844c61f91c5b8a2985adb454f66849cf43c69d4d584641aa5c456f42dac2670a7f05bb5149ffe4cfd9902399cd6f54586c31326dd90c457fac102e6610ee6cf2940b48da8ef07826b41b5b5c4d89dc084515cae399b80d386384c213905da3bd9a49b54bd97c171b255e59d4b541533b8f75ef087014d188fc2bc59e2d2cbab0aab9308e117b2d9803b1c568d3ed55736b25e0182b4df2ac1513b14c8486e9ed63f6b0f19bab4baaa34a25475a7a9903288ce0c74309c77442bf9ca5490662f6150b51c755a5440a3599bea14b40030e3b2006e56d62a9afaa180813612b19a77b661c3d5d59b7f6b736ebdb89384f416b5d58e7fd03f86c5b", "ece192f61c8cb4a666b84b15261f8f3de18743976dee393d33200b765947632fe19b99dbbc9bd8bcd1e7361ef8f6f11af5f5f83db4859c478895de6a74972471cf297726bec6333a7087f1e436afa6051185a0f5159c67b94047e9c51471073e169ccac00d92147dfa4cd56b1c3e65ef96c8a0ed4472cd41f25f3c1854869212a799e90ffda10a2cd8e702cb69de62878641a25ed52dbe20463e3669c480061918354981423d00ccfdae83a60826ba11d462881f45f301ada4c9b5a2c480a16848101247d3440421fe4096445456f690892163da5be3fc645a6818d792ebe56743f80ebdf91ce708ea3efc388bf6221e041e0e125c0afa28e0eb330a45328382a670ac1c865890a03dae0136c09d2f125094cc792cd0732bb75e351f3e9e3af599ca9d037712b25c6f4c201f08503f9e41c794295b526a4c48c6cae5ee94a639e38e797c9f14ae9d9e34288233a95427138dca2cc5a92c5a7f695204b24d44dc82ec0fa12eaa2babc10b44580dcaf330981bc688b9b22972176d4ec00f4b1833d08bcb61cf866b71d47b78084035cec5a9e74b4b6c4495fc2ca23ac0f7f174ce93a3fd2cd20c4f5236c7bf85f0e18fc6ad21874d29e78b442fb72ad656df6c95c3024e3dd0a7407eb36ca0790552984343d558692d985e7318afb83702626fc5823a83fbb3e3b748e85410052c6463a2630ab94aa8ee9b037508000d8c6a3d56", "-1d6be6b9dc967ed358d70b0d0f1b427e2fc5be854e804bda6688ee120607dc479dba4c92fee7f6cf8fb2d05574bd58a55ff94f9422fb3ee01740ef0e26cbb1a1fee413848365b50eee8d066babce92313319d7ca1f3227e6eabd74d110bc121b05562b9088cd9cf1a3d8aeeb7e1b462e3d8ce11c20fcfc6cab51def90885f13ee8a25235edcb8d5cd94d9f3871a5e4b4e0bfe7d1bc5c872c53575c0d25a164169631a40a2e5e244df85cd9b41619260e5134bb668d4aad1c5748c7e7dde8b26b1ac9f74be29e0c186b21f1ddab132f0a82dd3ca1775467ec0ad996b52806c214f6df28f8e35748d76cbc7421c14cfe1a3f60646e536606ad4e9b3f085adbb0fc561c3cc69204420248a0ffa531c275897fe49216f951a426f7dfb827784dfe551df39dfde3979bcdb7507716908350f77d1eb2df6caa6c2b879f938befada25e5f3bcdf8d8d81a131a97d031124217adb2ee9267a4f85349f9534359e6a5a7d4007ae23318c4de9460ac0903189e20e55f6759b3dfb0565018d5c5730241ca12ffc51698efc411c1c8dac0619bb6366c95bacb41f599a0967528252ec45e420e3a75549b158f63cb62d78b1219c2d3a69f746cea7a4808e6cbc97f21960a6e0d8829ef386d70a3693bebe67ceaa96a278dd93f9b46d9b6cae38b69da4650c1f6f9a42975cdefd5ec44e704d62861c5a5999f694d3e13ddc6ed260e80a9062a9b1", .Okay}, + {.Sub, "9db30f72a16dd7bfcb1efb3722ff3b19998d745aa8a896d45bbf25e6bb0cafe66da7b014cc78d16168a8419b5c339d11e1812ec1c3f78e46bf7f4c03d467677946a92d2c4bbec62eb30d10eb5b93ac6b8d00277572ae5dca5203934a346ae0be3a9db214bb8704d3eb516badf16d64f61839abb728d6eac3367f9c8e2d6b4aff64d6050d100b917ff747a21a5e89f76d56a09eb3aa2a942e610a574e6d0aee976fdb080e5509ac2c8abd7955d0cc749968384af5db9485b0e7ae4c0302ebd2f995fc9df523ff7ee738efc0ff61034cbb0fde404bd5df0375c4ca6b66af64168527c7a00b86a8dc7e44f9baf7fb87ea364cb86ba8f8d329a88d2887fc8b72a8883b54245f01950c93e8816ee99399d275a26956a4f2233f020690cb3edd7edc721327d97a862ee396eb21f45130351208d4414b1aff766309a8e136a7214db5e536f5a3cd9db239e82f42f74822d7f332d3f2118422d4608171bb9eff159d525b90c73c3526f09c31081d99e918c6a28586748f08d99771b3ae72b0d23bffcf8cae0bfb67f32ba28747486145eb4d6f1398241ed56c9b85b9d20af41df1d06242fa59dd692d4df54a91db853899bf8ee77820e925591868ebe69da022de51aabbdb394b056567a90f7a3dfa5a171a3f6d4d56d169a15c336dad6289306ff23d6d8d40863f9ac241ce44985efcad36571551ce5a4d7d6993b5a4ce6ee609313a6a", "ef5f8961eccc8e72a5f156263d370d7ba7a65fbfe4e14fb7b036419d338c2551992d148a57f6adce386b6a14cdfe574322a873b50836fdf7d07567732b23ab47e60696024f7492bb6ce426950b0dbc4d8fbd2424d28e0c3c7a98c1670ad4cffe373f8f45958f4e8662387b74e6fcfff61ec0fa0383958eb9145dc01f3d723e0a10df00fd32bae9fb137fade021e9eb080e6def004b32101cb962adf4e62438dfaef0aa9fd95223eb1982067ca1736ceeec32a18f429ff190a179c401c551bd639de726382bddb61f03d873e449937a360a1d74911cf279dda6bb9b19344222a44aa6648002028770a828f27d6bbd18568888836468819c37682fb4d739eb06f9e8374407dd83e59e93eedb1479c9c0138e6a940d48ad14d796058b7ce557c0ff46209aaebd9f21b75c5022e9af2663c1d5c86d801f9d0ec43e26cb37fb7fe58d25498111ae2da503a70a56b8b0b0dc14f4a2148b3af3742cc814d54671dec9832754e78ace5a3432449a90eab0ad5a33645b21aa7a40e5da1737fb0730fbf7221ae5c2d5a8d272895407db7bceedc5b3fa6e511a6b271281f70b4eb6fbcb7e2d1b0905958ed2f26a0a59b2bc875e3bf34271aede760bec809cc8d9535370373284f37c5fdd5b75c46fe80fc28a0c8c9d2651d732b8260c0c97630dd0eab1cf7c50ef463f87401323d510d60f6b3bccd7cb67659af7518efab085768f0b36e751", "-51ac79ef4b5eb6b2dad25aef1a37d2620e18eb653c38b8e354771bb6787f756b2b8564758b7ddc6ccfc3287971caba31412744f3443f6fb110f61b6f56bc43ce9f5d68d603b5cc8cb9d715a9af7a0fe202bcfcaf5fdfae7228952e1cd669ef3ffca1dd30da0849b276e70fc6f58f9b0006874e4c5abea3f5ddde23911006f30aac08fbf022af587b1c380bc5c35ff39ab7cd504ca1077bee585856a679194a483f15a291844877be8ec48d26d0a6f85583fa5699670b6bdfb9cb77fec265ea6a07ea884307de3737cae8b2e4e8902d7afa3f344547137667e1f12fb284de0c1f22dec4747b59aaf2632f378570352e203bd017bb6fae728edb072cdaae785e71ace31fa8dbeed90aab6d6c2ae62fed9dec013d685689d5d58f74c03e07d8e48d32f8c13437703e20712e2e987ef151b9018722652026abba95459490da322fa7ee53dd44107b6b1b77c75f708dd8e8e220b00307181f13ab565936475c417727968dab55a76998013c7cf70197e6b7addde692a1a0a9742668c54a34f4fc27956cd9c76db5a6d0020cbf7a35e3a056a0624a3244fe8b8cc825005a9909fb1bea20af282c6184fd1f787e2d83ed9ead0bca50c5b91cf38394b62b3930751e8c76a9ba315a77f3ccb4f5aa156872f24d2fd8fb05c916c9d89eea0084a07abf920ec3aebfffec7dd15590787712be0575c279990b4d79e7fb450bb707a90205ace7", .Okay}, + {.Sub, "-ed272fc9e4e19175b6c2ea9b5e7ce4ed84a10a460870973c08bfea0b5afb408447894e64091ec4fe4d7289eea1b89320ce34bcfbd4ab6c2c61f2b50f00b82ab59e13606e53f03f88d3f5de21118bc0195ceb11b739dbd44026d9f4a46448f3ff463551b3c8f84e41e4d2097f0ee26e404be2ac3522ae6042d8b350106d101efd5cff6cb67d6693f28c0969595422c32c66eb722451e49faa3bac063b247a4ab2900d1ec42eb966d638f3ece4cf1fa3795108cdedddba537dcb3478308e4a07e0668f2d3120d4d6f042789f9dc985ebeb59af186f3ba95a4fb57057eb5f4e236cfecc4e56834a666fcba78719521f1672e153bc0824299c107dcc3b2f521e328f1a016de45014b2b807bd51c6ca1f6953dfc2f20d8f97be2344bd6c6d2792080756e2017a6fac795617cde0ff4ede49ea726649abec5efcd21d2bcd9fd131ac7e242354d6ade1458d517a8be4372fa4c021c03a0dfa7f4768fc13fb9ae29a49a880cef17fd97e94f453ed53c127d60555c639e627e32ac2f4671f0d4b3c0c3763030121c96ff00a780fbb6936c5e08926b2c3f2aa1da160b0db703bdbd311da9d1af1418130f61fd997543075a8f544a427768e9ebd3777478196540cad6f64ad148cf8c8cdf55a35cad509296ed0cc5ab2e81926d24eaeb31d1c79719948180c4f1d2d9b924fdcd0c293f4be057b7bb3e9e677c1ce05b280b9a283e321719f97", "2e3537aa073d6d8d1b4c8d4d71349a2ea33bb321a9f2f2345d2c962c2e8b30af4c9c4ad75639fd43b307d0c9635f7e5070a7a8e27a99132744f3e6a214e239d2f5ef4b0e0c37c5cf8a812b9cb41576889553e8af5301947e6daad8dbdfb2f433c1f50cd0ef9b764ea737d728332c2801c543b732bf7bdc99daef9e9c6b0edc1f3adda6475fc4c99d7ed02e1a77a929065fb568b9b71fed81a6bec58b381fc7a552559ee82eee0a0c439797d096482ed863bc746f14cf1e5ffa627fcd7d5417544c9a952e2e909ad845ebe0a8aa0162707d552c89b304bd3d251cd6f111f9a47fdb629c7512dc0a90c1a1ceda64e49338c5dcbd599450ac190805a6b4732bc6830a06ef896f117526dc28a3adcd098bd748e8d162d02ffdeec94f1bf162fa1fc4526001767c256f68558b717db4900d87da4443cd68589fc505ec0dcbb1decec24f5f86cca95d1de9df49b263ef52862e4cfd83b7dfa982920286697df8c5ed9d33c1fad74abf8073e3dde5921df57e9f8d0136de0a6889eba16d303bc8a59ef226deb7487af0353f82d2d9cded741c6d38cccda4d5ecda16a6b2cb44dd435b6bd54c9c84b86cd33b9e9f864cdc9dadd14c2bdb1180bd7a01cddc42417d5faba8fb37c6ca03949c056b532a471cccf21751d50f7a57492492e14f06c4f163c1c1883cb62145bce5b9c4a8010a78d4c24483663835c75310e38423afbe0e962b69", "-11b5c6773ec1eff02d20f77e8cfb17f1c27dcbd67b263897065ec8037898671339425993b5f58c242007a5ab8051811713edc65de4f447f53a6e69bb1159a64889402ab7c602805585e7709bdc5a136a1f23efa668cdd68be9484cd8043fbe833082a5e84b893c4908c09e0a7420e964211266367e22a3cdcb3a2eeacd81efb1c97dd12fddd2b5d900ad99773cbcbec32c6a0dade09048d2be26acbc65c9a1257e262bdac5da770e27c8b84b56567d251b4c5425cf28971ddc596f7fe0b9e1f34b329c25f4f6571c88864804673874e5bd70444f8eeae178cda8d2edc7147c7ecda2eeacb962671008d4955f3b703a9aba7307961b87a482985d1e1e3c549f91224085d6dbf2627dee3e5f5749728f52b28abc3705fc7bc120e0c885e8a8c27cba94202f0ebd1e8be6d59527d036e57724caa8d7954b79c972317db6b83107b407382dba3573e637730c43e4826822aee6ebdbdc5da28c9fafe9a6518db603745b490ec57243e156837cb395345cb83f5533b1d05ed934ce0088c3d8704b1d65529dfd911eae03fb7928e4304b354a593eb90c04ef38e3ac782230720b0553608f03dde05e962f31535f3b6c28592f27573a269b03df4f1494f72964e2acf10560fc4bf92d189f63b362833708b9dbe7204bd28a12997d345fe6b80368aabd9cdd759e3bcd80cc28a873bf5c87e503df86d4caff79558c3643dc633a13007cb00", .Okay}, + {.Sub, "e8efd95283f5685c6db20fe14a31da90ba792b8d4bcafa2365660bc603d179928d59449e153845bc2072167103fbdf9eb7a4889da7bb996f7e80680650f2cf8444056ab706cd19bba46d643fb1739c3dab2ae5f540f22d34f1a11376ab5c29bd45bfb9c64b97a71d043161e978f097ca28dda8471af85e9eed2f7cbc5c8190eed176e9f0e38b6ab406e13fdd42e40ae9f310223e06232e2ad2338d25050d48eb65ff4e60b342888880c44c2ec3e642f2aed0b4cbacad6300af04ff613e7f25096e976ccf83a59897fec69f486e6f8473577f67b732ed656624fa9ff63ecd4cf6eaf8fe846ee0b2cf60432368a78498ab925b8079aeed096401d9bac23136f94452fe895a881aacfb86544c5081333a60edc840b9ae99f71f8504b0937e061e5403558c861deb705cba6010c122752a95a4e0515cd9bad462bd44ed00a9adb51e9a601fa6be041557ad8835eb43326bc1f08627a0496d2841a2e4519bb71b62beffc5fd507926cf3e96ddf5c8799494d3257aef0f14edfb641b9c43de5dc817d0d0e8c8eb9eba1ef9aab3f501142a9439c0a33f78266cd70efea38988b91ec5607c025e34ef750e421dd1486b3883bc8b98a04b008e2b10850fa10b77a3016e53c86edb338879bd3373b4a8d46f09bc6cf16754fdbb4588c41763c3f6609ffae2dfee905b8d5adca1d8ff001e485de6313d3b8e8966a243d4e82d833d9cf57562", "4558c09236b53171c735ba40bf33a0d10aba81611154723cf47f2100d5ca90d369d9aeeb2ccb35914d108ae610df72f387931434107a03a0f67f41e2ff35a16f40f5a41c94060d6b73c66a79c68260fda4ab6f2c5683050fdd91c652105e4826010125be5994b5f4d998f63f515730f238cca48156c57e13cf3a7349cec75bf8fd3d4a904c5cbf3d9b45c0ccfaa33becfd5bd153d64ca31772a49a2e8c04c5737856ff46acab5d2b3af7034a2358be3d5bff97203f7cacebe2bf3e41d8e25d3ef22e273d8c76ed5af84d1013e312b59458a256b41b45dfdc502cf471312cb6f15da79ac51d472cb52b42a7d2b097ce5c425658a3c214985e5fab9dda9e04de27e12e8a5e1db16c7cf954cd2ce797201ee28e03e62280ae6b9fe8662f71ddaa3cf0dbddc3d080a0c1f02d5d35b0703bb99fe83573d751e79aadf40fb0b9c06972c48cc37d056b6c814b4421917c68d0435904e253f8ad3130714e1e3cc5dbce5eb21113d8a4d19adb7b0822af283d4350a6918d886e7478925a2f8af8abf8713a1de78fd81396a7635b713e2b855d7040754e04e4c54f265cc9243db8d8e9284a7ceece738a485c54123ce6a1b5e3fb222fbebca4a4c942574730768803d0788d95a5eb3f0a0dea872e7278377dbe4707f3ecadbf6cb04cc79b24953eea09747aa46496e5f3d69af9aab5c2bb37f1c9fdec3dd012811c2b4e544367488c123d0c", "a39718c04d4036eaa67c55a08afe39bfafbeaa2c3a7687e670e6eac52e06e8bf237f95b2e86d102ad3618b8af31c6cab30117469974195ce8801262351bd2e15030fc69a72c70c5030a6f9c5eaf13b40067f76c8ea6f2825140f4d249afde19744be9407f202f1282a986baa279966d7f01103c5c432e08b1df509728dba34f5d4399f60972eab766b9b7f104840cefcf5b450ea2fd68b135f8ef2f679088377eda84f1a06972b5d45cd48e4a08d84b552d11dab6d30b614cc45c11f659cc7ca7c694591f72eab3d06798f348b5ccedefedd110317a78589d4cdab850da096058d5163bf5199861a35007b95f6ecca4f500527d5ecd87105a22e1ce793321b1c71cffefc6a69407e8cff7f23999c1a420b3a3cd38c1948b3e51c4a640c2874171279aec24d6acf9aca32b38b7204eedc04f81be90268ecc80f50dd4fefed4babd5d35c29b898a8d662441459c6c99b7e9781454c50bff7113196335ef13f94604db4e977d45534631bd5d319515751827ee96186a67982d1c16cb8e5b1cfa696b30139138b2377964f42b6d58ecd23f94b553a93611db0b2357f4bcfe0359d15ff138fc1652cb1ee0b9461c9829fc16968e18e5be961ce2dc87094ef9f30f5c632c8eff47e6bd2ac4542309cf14b7564fd7aa73e4e953bfc7c3f2eb7769686683b89f975998441a82e493d63106c1c3350fdbe76e586188693ea1bf510e33856", .Okay}, + {.Sub, "a968f25673ae8d3118dc6e5eb4639a4589d93f717f99dc552136af75499a2560c9fc368a90cdcb670a85a8035e81e64e071fdc0f01af3b850ea9575e2259f08262a9ec304b21aa9f6c987739bf7e92ef0dd495e4777a5433eb3a05311adcb977ac4c32870b20557c716a116b52fa9558ad58c490b91b52d0426d1d1a2308520f1cc7a1e2ae86010df198b6038781c85a40119cf370be7c7eba6e5bfca32fdfd8e012fc5192fc706a2a2593d6e26f49bfaa229c4d00de486d866e94106f8b6283e3867bbe439769dd363b3c6f6703c7061981aad824024e6d59ad5547462325aac5cf3fa7b951caf8770a7fd8fc22cc2e1b256fd096457d95625948817e3c89fd53c502631cc0a4461ffdae1c58758cb38049880aae66cb18a945319fac35222509a6ee5b87883fc6d21fd2ae890593d76331edd1b68f1ffcaba202f9401a63db546eaee566b8a96cff88c44e52995e41eadfca2bac51e5755c78ec34b5f47e440d0c5cbacc633c34ff283169f3ae88a1f1054942d260478f7c21d686d567182fae2fa63d26ec0702fedb64af8483bb33f81326e06c4f3edb7796b5d3d780c6aa8221f63849d3f864bfc426aa637d7ab4e478f229192ce025a2ce3b91edf0b023ce36ae01dacae12e92c04101b1f598de7fbbd694204ed16dbe192b5cd7cfac1a82b281ca0b0abb2beb05624da0598c59d013f1cfb87e7f9db0d233405de6bb41", "66848cd9ba950897b61081d6062dca1de233b58eece1d8035a5bf2b4d95328e7a6a1e18ae28998d9d487005acaf130632955dead623594f6fe66ddeba2af9f1e5b50d91b96685a6e4a90229463c6b36fb08acf7e5ff0f591b49c8d168e5e72ed223e143a70597c51479cb8f33bb0d97a5c5a953a7ecbbb84b0d1b8b0a71d2e42a3671fdc1b486a410a4f2d1af630a4072176c43b27adfaf176338f11d3107114e733efed0d55beadf5e6180cbd2bd49dd3c33217b364db07ac26d6200ecb73d638b812b0bae76d085a730cc8353f28f6919c992f5191f1c6874284b8629bed60cc2207cbadc3d6dabb39361d281fad1a249d79c5d5fa4be72290f50175a538a73517d91d1d9556484b5f912fcb61b9af94108fe820ce89dbb413a3b316fa884608af9fdd1754bc253e3e64f43eb33231f21312f3d1e4fde327074aefb76273637f12cafd0457e901c97c66742cd87ef5afa49947b605ff06bef01573e41218e72af1fa9123ad818f3a073241200c57654e61563e6bb5cab4b27f470c3b039b91eb4e68a920dbd216bb105437da08684800e2b060550dd4fa7a5c2482ddba1e712f00f72c5f6b89eae840615d0041fca7aa2cb36630377d6f12657bbacaa96893a9d187c2ea501ddd35c5b7237d0025dcccefce840bc771ed3de316aca047360dd15e276ba16da132330661fbcca60af826b7a5f9af9de4e84ecc568198b514db", "42e4657cb919849962cbec88ae35d027a7a589e292b80451c6dabcc07046fc79235a54ffae44328d35fea7a89390b5eaddc9fd619f79a68e104279727faa516407591314b4b95031220854a55bb7df7f5d49c66617895ea2369d781a8c7e468a8a0e1e4c9ac6d92b29cd58781749bbde50fe2f563a4f974b919b64697beb23cc79608206933d96cce74988e8915124531e9ad8b84910818d443accead01f6ec3f8df0c6485a6b1bc343f7bca25437521d65f6a354d796d65da47bdf060bfeeadaace690d88affcd4dbc82fa731c49e0f87e511a8d2705ca6d26ad08ee3873849f9ad37dc0b8df41dbbd149bbd4031f13f687f60ac04b31ae3fc85380089751561ead2945ff2b4dfdd49e1cec8d13d303ec38f8228d98413cf5318dec953a99df00f74e7e703383a193e16dba4a5261a5711edadde4aa2219849ab80988b7f077d55be3e86260c06b360c5dda25c0df4c3b3b30e3f64be66e9d88d6c0d1e2655ce21a6229a8b5baa5c520ff28d3a2313ca2a3f30466aa7cdac9a28f7a9a637c9dc2e13d94061034ec43cb1077aa7b52ebf7307680174169e0fd3a9150f9c6a8395320ff0bea686e79d783c54d633b7e0d3a4c3ec2e8f562b69068bfd7234747902465263ef07ac3515cfa89de34f57301b2cc081014875f80803614b03788760cb1545a5e699d19f9b7ff0051d3b38161a95c4bd608e09ab56205dcbec531a666", .Okay}, + {.Sub, "-f1190f400e3b4056a7f2331376ca8853b3b333df32c5ca688a1710a72b5fff367c9a83b3440a40c1680372d27727cf0fedf710ea96eeb6b19bb69aa6270663cec96fabeec72e79729ecf524d53d6f553b549ae9a1de83637b40ce7ddd0ffd63864ffe5ca0a7f598063dc6484dcc03b4be244c325dfb00ac37e5b9b827c13a3bca105c44f59fdd658143bb2328449ba29f79c0bc4c423a6089cd3fd7a7d7a6753aca0614f30b30941db15bdec83c13b2aa647a5a28374b34cc750b1d9b0d6e2ada556bcd61909571749126cc08b8f712657cb103cced74d363ef53a3eda5a1b18a613741e477d1b0606c27174b818076dd8bcefaef51c7aa97737c8180e26ff6538f0cade1918e85d42d655d473dc518d6d98c7753fa25cb6298722cb2958493adb5f2b05a2bcd4ff37789e95864685b6d845422499ac66ff29d6e28ca670c142549c430bcf244ebd99b17d765d34f57f2faf8f6b1f4a4ad77916d2795772d592696fcbbe7841697f3b98b293a9e094961768a46ca053977367c594b450836a3ae71f9778a970730bccb92f41bd1a35e0808a26a8996c443557fc69f39a30c901dbd591fea6a52a55c86adbf879cc0e002d8896fc54b4a00ca771495677793024c3f1ee4e83def1a0979bc3aef7eacfc39b17989d286060239254a926ff3299c81aaf7c55a4a8ba62535fcb803a8595c23f234484d1f2d6969ed93b937e56596d", "8f6c2104a51d277c90e5dd979b6cb57f6eeda78dd577e9d93ce1a02ff9770d3feef6411fd0c33d5cd3fcccd7934b94e69f6d8cf0ce4d1488c551c1d33a106ea5a59953dd45fcd2bee734e3a7bda02292d9d936c1f48b32da3800657c3b244348c443e3f15be554cbf29e0df194415e0aeb8cb6005f3d16331147560e668d82c76fd163aee8bf163d9cecd2d2bb7db7bbdc0ae436c0af4bc1d458e5446b8a210bfc90314c91d1bfe50d4975d6bc854ca310ed85722ec4470b99d27320967efd7dbd895e3f09d21171d027d618dd8d31c00f95a85a3076eb72e6bf23f1561fbd08c36055af634c7f9f78363bea999c4001cdfb696ae026ea3237dc0bc6e8adf021e3e9710ec268a007be76f0bc797a265bfeba7f2b8b159da5734499a374b812856ee44bf3a8ddeba991917608cc23c56436184cf611f63014476a8b489fd01c942355a912a482dc1f8b31b43ec621808f626aee4c2431bdcd60bd931006fc6913d629a2853aa25f5d34f3f59537847b96d72ee8dc996ac36da27ffb29c5e861f76e05e63f3f5d0f0b6a9f3273a4560afe42e32acfaabdc8afdc72b9aa541b85ac1cbf45ecb81b51ebb12d5ce546ba15bfcea4a9d956badfb1f5c72ff7077f4a4821bb4de810c4cf62d80e37dbcdbd41d1995b78eecc0e01e86ad5f824948f9ea690d337b7e663724f32ce0ee5aed2b0d0f9ee0e91d3799da53997d3127ff35132", "-180853044b35867d338d810ab12373dd322a0db6d083db441c6f8b0d724d70c766b90c4d314cd7e1e3c003faa0a7363f68d649ddb653bcb3a61085c796116d2746f08ffcc0d2b4c31860435f5117717e68f22e55c12736911ec0d4d5a0c2419812943c9bb6664ae4c567a727671019956cdd179263eed20f68fa2f190e2a1268410d727fe42bcec95b12885053fc771e5d3a6effb84d2f1ca712ce2bee904885fa930929bc284c926e85f33c3404687cdb7352b14b238fa58612324fa4755e02b62e01b1522db6889193a42d9691ca2e66760b896ff4e38a925b45e303079d8216973c9cdaac99aa57ef8ad5f51b4476fa6b85919d54364dbaf13d3def6d4ef871cda3becdb818865014d4690ed5677e96c5346a0cab7fa5b9ccbbc6e9e105bc04a4376f94b9ac0a8c90a149e526a4b1b0e5d8f1aaba2971371416dd54640ddd677f1ec1e73a72add24e331b52356760e921a7db7437c08a4d9d465895e6f3ea63f996e43b2e3c8dc708ca828e165102cee978d4939be5ae10a458fde166bcc3255257db7e8cd8217375861b5617040dec36d5178442a0ce5346f239dee4c4eadf894d7eb5ec07c41799838ddc08623bffc2d40d5ab6f7fbe9d38794d7ef87a6ce5ad3c3694a3c1036fa9fb8ac5a811953473118bf46e620bfd2aa14b93c2386eab82b40d8b0c2cb1862dda65e958469339115316a56c743bd8710ea5fe49aa9f", .Okay}, + {.Sub, "-f7491e937ea3e795f311de87cdc34dcda3ad75e3e660a95678c4e5a211658744e5f32e96c0a978a8a24bf2c9aec0bac66266e9e0c2badb04b38c7c4f6d276e78120e8746265f0207e4c44a624195f02c0316a1af161a9e19b771f2c665fc613fa18bf3c9458d62b33401588ddcf254fd96f0160fea784b5bf82e0faa2b736b342f3d1862a135b64acb33d5d4d693223c87944edc883202ecf63aee84bbb628cdd1514e3cf5c0f90582a0085773dadfdfc0c54c7a814321461aa5c6d0748852ba6d6d930d0c75d5af93a5229c3e4d7500bb195f91b1302434a42fb129d612c1af73e8d13a37dc2e5d076091cb3e0f05c75774aacb8e1ed47972c20ea815dc62aac0146d86a220329611b3a53373c17d7953e8de222ee837e80c1d950527739e90efc03e0baa02176fff0a9576aec7ba4d3676bade452905f7d25006a512c76cdc29a13f42d881955b28a454012bd0b145578421498b8b89f5a5f2442ee5b0ed46043cf57da7dc97b0d450237edad471300d4c40a1644cb77748d7e8ef94e8f53c18ad2aa636e2909c460e8bbebf8c14b2e4db4731d0f3ade1615b5f425df44d411b37d65e27cad4e88329693843e0fce5c11593df0d536131125fbea6e10b2866ae3df7e8fc3deae2a922a507953a3e3ac4498e3298ffa55e51b5a8164724f53b4d111075f7553251e33377f8bb77c5ed1f5f4a2c4cb2ff84c60bc8e770acad40", "ff51f0a46e95c9a3b4b9d9d42b101cb5a4e59f5e998972b3739a8a090d3a84b4c71c1cd7bebe92025889e981784923a1863e7902a404edfa784240fbce98e7b36e86337806c6781a0c55a45d2065a8a9851480fbea4d2bd128329280741a315f4e2a52688bdd3848fb8729bbd09d95e5969fc4b4fc9de4e5afdbd802111dbf9b8cf0c7aa58a5bce8d4041714ea08010c07e2751cc2815a94516319831cdf78542ef9ffbeb9e25b41d7c2a0dc1ef12b6905449843539d8e6ee5cfc18b746a6a01ad184b5b7ae1ea511a857a0e8bedaaba4d2ba211c90cf9aa45d9d6247f45952b3b3fb0ebaffe5778004dc30bb62bfcf2225f7d203d5997b20efa1c0eef4d1b61fa8ac7196a3043200c97c021650408f01b7088524cb90b85fbf48a427ea346c1b3e870cacdbde25f256e1489b2c677c5b4ba762e8270eadb0eaa3a149ec78a989237c0bba4c92d54225356f53c658dd8e5db3cb693ae0a58480442ccfb1d0a106593117b41163df6d7eb19fdf016e911f54fab58aec55e63b32d9483562450369eb1c52e7e42e3afde91e8242cc33cf72251c5bae260ceafd5d943f07ece87c869b87e4b8fcf0e5980756bca7759d66cb4a979e7e45e61c6f88147446ec34234b1ebb0fc9f22bbbe836115f8d7879afbda2e7cf1c40f2272170aa795db1a5f1cce8db2fa9e5fb106fb9259ac15eaf5a474e6a7b16d07861e5136e48acbde29da", "-1f69b0f37ed39b139a7cbb85bf8d36a83489315427fea1c09ec5f6fab1ea00bf9ad0f4b6e7f680aaafad5dc4b2709de67e8a562e366bfc8ff2bcebd4b3bc0562b8094babe2d257a21f119eebf61fb98d5882b22ab0067c9eadfa48546da16929eefb64631d16a9afc2f888249ad8feae32d8fdac4e7163041a809e7ac3c912acfbc2de00cf9db73339f37ece9c09b23488f76c3f94ab35d81479e0807d895a122004b4dfbafa354475a62a93392cc0b48c609e4bdd4e0afb50075885be8f2bcbc1a85de688757c000ae2a9caaca3b1fbb084501a37a3d1ddeea09874e555856daaf288225e7da85d507ae54d6f43b02b979d427ebcb786c2b81bc2ab705297e0cba9f34a00c5075b61e4b6554d8c586696f5966747ba1436e08121f47a616e552a3a8aed677bff9cf2478aa00618e3212eb31310cc799f0d2e0fa40b9b18ef774bbd8fffe7d4ac2af4af7aaf668363f1e3d5f5e001f39944dedf686fbe0cdf75669d006f8e8f2d5a7ac3b3d7ccaeb5a42029bebfa131215dafc057d72eb0d4572b75eefd4b525744c24a073e2ec4f51aa072d0cecb3547c913734a332dcc2d50984f054a9b799e342039ed502bb3ad35275bf0dc6f1b1c2f80ae105eb4fce6a9b6029a8e59b60a6a12c83bb006cc1d9369e780b245d0ec7d068c04fac223f54581b9ec37095b4e358dec5d1a4d162bb919445f1ddb9ba85a31742ad723c8ad71a", .Okay}, + {.Sub, "9093fd5ffafc99296e10de629c2c9f5857985c21211393b56387273d59c9d36681d138f140436c2e19f055f8b1f4f647163cee9368e160261356184e8bd4d6b4557086ee61d868ade7ace4514a499ce862f6454c693087cd05bd81b4fc50bb5566694a909d5b6b8735a7c942c7fce2380a7daa59d86cf601682a80365d464f0a25fa189fb43c24f50483620a64c1601a580e49783ca3d1cdb7c5fb40e1e19b47f5028dfb367e0b3eea05be5304dc224727b7cb2063255f7d5d335db66031c98472e88c7e574090578b04d424699507d064ba3354177f604e7c6e6c81a21d66de859285ed0eba87c3ab2809f11a06eb9db05804e98e076236d3a4b8346fb7db979e8db4e30085067b4e1072aee840b6bfce89af80c3cc910d8276171ddd700daf376be62368f019dce5b928bb475d56f6b073bb613f831c9b6b8dc847e7106f5bfb8af64f45b9ec981781dbed22643e3299a89a1355c2182e70aff4bbf3ed6b6e5f33eb29eab6cd4fb5045ebcb928cbea92e13f30cabd4ff7c93084dee95968a13e601e34042db99c0176f171897162d20f79665f295894615a68dfafcf051477969fa6a076d40981b718c0b4b241c10c8a07722dacd0b9e8e6ba1110f39b6c6a8b9dedc46f60dd5d55a8629ecd3bf5ad8bf879b4e96e491f901478d535393fc3124391d455ed3d614dbfd7a5f1c5db04975447f02fcac2e82766ab6f45c613b8", "c4b1a0240990e2c59aba5f57969b0f0cdb34e2af9c7bab2eed63d0a154f1369ab3bd8ed2179438137fff8cefc2ffb516dd932e05063b958fb2fe05f9f9bb00f30f20682abc1c3223033653b0515a48276f6359dec125c39db09ad29bf3eea27936c9195264c5972d582bed4aaf94caa9932330d5b53edc8aeb16af62f38dc6a6e40a5eec1099cd7c62da242b5ec58843133f562289f95dbff6ea246b1338052393e4376804d19022ee1659d7d90b0b82f24e88e278dba0b349568e990c136c6f2e750faa4206034ffc35a53e43c23c4297dba4427e1a7e2d26d6f9814307864bf33eed4087de9fd9c31ef38ab0128d7ef68174eac3638b6983828e59f68117d28e7d1096f160888da68af800b0e88100b280be9d4f239a615b8e7e0b9256b30fa7c7cc59373f64eda25514b4c119e7138c2a578d71d4b7f8f32fb36766d7870a0b3ce2ae156c2349180f57e18c94981430e61df88019318b23211c771f5ceb1ffc3c0cfbeb1ca9532a8a9e59580a3d762717a0bd241c6cf641e12efe741e2e2d843b539aa51a43ea5876b817c7aa02644d9755cdefeb7a49b88f8e3b9a8b6fe84ff98c9662cd90638061cd309ab3d10f7f95b862060f8c5bd244f6e829c915405263ac21dccc1e55f4d9694e42ff823b84acb5df87894a8c0cb7a0e431cbd8139c60246dc5fc7ecdf655938226ba0a97bc4182d84cf630083b499d36e6eec0e3", "-341da2c40e94499c2ca980f4fa6e6fb4839c868e7b68177989dca963fb27633431ec55e0d750cbe5660f36f7110abecfc7563f719d5a35699fa7edab6de62a3eb9afe13c5a43c9751b896f5f0710ab3f0c6d149257f53bd0aadd50e6f79de723d05fcec1c76a2ba622842407e797e87188a5867bdcd1e68982ec2f2c9647779cbe10464c5c5da8875e56c220fa042828bb310caa4d558bf23f24292a315669db9ee1a96cce5384e404109b84d42ee93bca96bdc215b64135ec2330e2abe1a2eabb8c832beac572f87130d119da2d3472332170ee669b1ddeaa688cffa0ea1f6d6dac67537924181617f6e999960ba1e146297001355c2932afddd62586c93c3aefef5bb3f0db8212587a8551c8a7ca40e3f70f1c8b570953d91866edb4e6a560705be635ce4f4b10bc9bebf979bc901cdbb69c2c32519b5d87a1eb1f7fc717ae0fb1ec5ecfb236b1008d7bf46a3059e1973d83e52a57195cb27127bb2b6f7fb19d0821d20065dc0375863f9c9ee1718b9436618c595f1cfe78b0aa1f8ac4c58c45db3566a0ec8a4e56ffc6a63e389f923e1def6ec692e5e85e26ae8bcb865b70b959e5f5ebf986e1c9490c7be8721002f58e4634593ed272eb8ae5d7362da8d5c6c5be5d6d6b40f89f3106af75c38c8df8b43c2a9e1b016c7ca3280efc9298508a1c9299700f416ca895bbdc34f42f9324ed3ae81d2b6d2013e2f1c7a128ad2b", .Okay}, + {.Sub, "73aed0069039c6c52b47609d029dfa63c66844b3a96be03b1b7892449059e9904092396becb2dc2c57bd14cc2be0ca8ec8408718421134e35f5cc72f53508528fdf37ca1c574f16d47971fe9b57b398af5e2a506b36f613dd808787be47766a6e2d3c30f5e4ed2fe343be1e74a2eb6cedd4f3efa19691648b4fc8616fa9788dce91dd56893c5d6d7b8bf1a22fa7948869e4136477cbd5ed1e1c24fbc42000b3b46df7990dd90a10f85f1bececba89b3bc68986293f39a4f087583c24a510fbc6481cf5c5449a83f2d21cd7c477fc19968580fe0614f05f8ba4029f882358686a3ef2015a78b35800b784ef4b5726d45d1913ba90d1cd58dbf0da289f47be68d8e5fce65c0e6c2f70f22789919a45dba12618bcff7e8b0a5aa56a9e658ef54e907274a16303b23c3850cc6e3708a4e23c4f52dc3fcd3a9ca1e949e0596515de32200ef352f931bc073ab6fee032350816e134fe7ce2d72361c481b34b852cdacc53f36684150e75de932b5deddd219ad3a323b8902be9625234bd33d83cc580283d6f0b4bad88fd11d3fe1fc447fe3c3458645250583bc0df9cae44b6ff5848cf6a198dd2d7ac37a9c7b8c259973d77a03904962bdfb7b4377c1df070edc25dd5de7451449aa90b9bdf32f5f9e216291ac13ee195d25635fd4424b55a645a42ef69021a298f48f709b166dc7e562bdfb5aacecf97caf2e8b1301c184c5e120608", "72a9248e5947a9013767c951890b3a1eb76cdd5dcdea9c446e3f04682390a9c351dd05907a0e4a0d6917fdb136d9923861d16563e4273ec76f5e79af882ab04cf86eba631465ab18cb63725c316de2e1fc408e31d334a481a7b598fa3fcec18eb0efa0f89bb613f39d391831b50d202de4eaf43cc35792114c22c83c9422dcd05ea3775abc10a9d116c95ccb0b6dc83fd65a35da29132ab3fd6f993fb5618d90b634be218750acfe2648df3c8b7a637e70662c747cc4f004ada31687d40e61c02d5da5e940c1a1064a2f57c25109b142dc29cd445def88e5cb1468e05779a50265e6ba821ae7d8c7acdbfebd718da0df5e874ddae9001c63109ff11f8ea29825653c51527cc00a6b3a8f9c3eaeacbc87b2976c3107e70be0cfe3d7dd237b1c29a772c59191607ca1c904dd842b30ba547ca573a89d10b55087ec468d9107897a998bda57999425f7ac8e43c94c5ce0c72a08f068a265e1af4113ceec06ea4eb539c4f70b68afc80eb9a821c0bd1e76283fd3e4e4e0e00fb109770f2bdc711fd9deb1334a43865d54d32e1e9528516e8b4850b1d9a5cda8dcd0b474f3ea7f7eff387bcb0e4bf93c50e9f647ecad7ea02fdda3ff04d41a43991268216cbd67bc6d1cad37942ea5f4c56815ce792857ab142ca930ff56dc6cd0b8529c9d066137493a0da0e8e2e8672b1ac897d0c2123ffebb282f091f888362ecabc1f1f90e5af1", "105ab7836f21dc3f3df974b7992c0450efb6755db8143f6ad398ddc6cc93fcceeb533db72a4921eeea5171af5073856666f21b45de9f61beffe4d7fcb25d4dc0584c23eb10f46547c33ad8d840d56a8f9a216d4e03abcbc3052df81a4a8a51831e42216c298bf0a9702c9b5952196a0f8644abd5611843768d9bdda6674ac0c8a7a5e0dd7b52d06a1f5bd57ef0b8046c7e7006d53aa341de452b67c8c9e7daa90aabb6f563ff4115fa8df92402e37bd562359b4c274b4ebd9b5259cd1029a061abf4fdc03d8e2ec87ed800226f26853a95730c1b700d6a5d8ee36a7cbdec367d90b46d85dcb7f390aa8f08de599337dba8c6cb5e8cd3c78e03a377fb91bd0b380c0950991ac2505b797ed52eb991f19738150ce76a3fe79d586c6886b7a3266cb01dbd17251bf9687c790b2dd7427e7d2ad68973029e751615d99cbd40e54b7868318fb5f9d960f8e28bb16e5d8274fb72c0e14407141b2836de45f7e428c171a2e6f78ac5eadcfd9833c2d200324ab634fd3ab4b0952a12b4624ac6054604e5ebdd8016a029fbd00d0012f1faccda91013a076b26e1802cbf9cfc314d8c9d0319dc2c48bb2fb58ddc27a6ce9bed7705b6097270b9d709e69b5cf04305aa168c1c719b06c0316d6771d2780b9be7e069495b0967b79c92c8bd218bd5df90ba62ef47940ac608fde969e44ad94199fb6efa6a08eab6a654e4370565a6503ab17", .Okay}, + {.Sub, "-33f5d1017254321e17a7c1579ef743bd0458ecd6da7b774edc6da68e2351ab03508757ac517f85a9b6a70d01bd97313824a170a0d6b1e954cd5aea24ec656d07873565460d78d5fbe86a2aff94a809bd264bf78edc1c74d92491315b8af926ce6d7e49adfd366faea19b08c8a04b604c72a3b0be677143342972cb9e30e39767507c338ef7f866abb5af01c731a103e79da90d778925b2e97c95337368b85912c4782427095ce29280d10a70a52ecdff719d7cfe931b3c366281f89626d48fc388a234c0536fb5f97c094bbf38b956ad6889497d35afb01eed42aa13c5b518ca5f8bf9f2996dbf1489d45f2deed3d9122c7b3172c36872583994af7ce9cec2c363307bb0b4095a9b58097a9e984b385cc7437b08765bb487ccf9fc2d6caee5a904cbadc1cf37caf3d9fd1a059964ae21e17ab7385f98d485f6b780698ea61b80de8f833a08358b79d77b71b269e1b1ae85c0f0bb7472dbc917a08cf0583bef966a02d1e6b53e22d92e90c60f0af4c11b7a9af4f142970ad0d83ed7560719a0837490ab66214e116d9fbf4b40d881a232b41c49c800b8e694b6ad646535e0e3f573ef813a5a8708bcd98bcb133277699ae41aec8dda2002d31f44db59da70f32aaeeabe95e66c0c823f1961e360c54c63c886509d6e2354350f32c5c0dc151229e6897c0226e46b1ddc1df0753bb21cac8bf401783f88e3f83a5071e522a1e970", "dc3e9c1b02a6ddc55fa0df61ae294e94587551034101ca886ef0f476023d371b56c8854c054b4276bd0cf4325c4cc0cdbafd83f5da49c3281c7dce35536f02a84da8bcad49af08f66b17bba8756e558c3bb8f4446c1ef6ca060221bb9af248465eac296ef5ff98197f344ca043c1d17d3fa45a8c255e73d5f685f1c0d3464cefae5bf107e5b457df58647fe1213f93039ff06dc27fba6c74c417293881cfcea1b13d765db85c6f25c96b7e738fc3b9f117c4c876fdf0aae255b28a4cd7ffcb586448207fa417dbc11233687495a3cd2e2c5c0659d3fe427a3de28cbf70e0d4f11f4348ccb8391fc536e2e5755d6aa9bbc0e43c7a55c0f0950ff2e536e1f06c4373148d4771bd21ec3059e14e2b479a2f153188e9f8de84a8fb0f8f69e7aac26890531424ee1192cf1d2594be3e69fe59622f5248afcae4b1ab983b31896d6a3b4d279069909c5f518908cc46974945ccce1f889a1e8b16e76508194a9dc7e2f265ebfe740485f92fc851ab3da3ca0f5d815ad4820113db011cad666a29a8f58fe8b129a22e236d5dbc33208de24c81c81a410e27b98f7ee185d08a2f392f808b6216fe464014be8aa111d4996e4c681c982e334a2d1bc29eced250825341913a269ce1cff69ef11c446a4c2cf9ed9fdbe9ef401cf1a67dd17c779c2c7496d844921646c54e05a73f13a4d5cff05a4f202f6b3200d60a355c041b48bfadcff541", "-110346d1c74fb0fe37748a0b94d2092515cce3dda1b7d41d74b5e9b04258ee21ea74fdcf856cac82073b4013419e3f205df9ef496b0fbac7ce9d8b85a3fd46fafd4de21f35727def25381e6a80a165f496204ebd3483b6ba32a93531725eb6f14cc2a731cf33607c820cf5568e40d31c9b2480b4a8ccfb70a1ff8bd5f0429e456fed82496ddacbe8b0e1381a852e096eb3d997b3a08e01f5e40ac5cabea8827b475b59a84c1b951b84a3c88e434f287f089624575910be718b83482e2fed45b1becea553ff78791ba8e3cb433ce5d23db94e54fd709adf2992b2536d33695edbb7ecf42bf51a6ded9c0b744a34c3e82cded5f6ded192962ed498794b3cbbf2f06d64508f825c67c8788635becc392d28bdc7503f26f3a3930c8098b975459a811951ec1e6bd495dc2f722aec3d7ceac7b43aa09810f63b937a24fbb9b181385bc2bb713a398d1eacb60843df9012af77b53e0795592fdf2b07ca8a63af603d288cfeed05ab9c41c08f6e2714caebed078fbf5c97343aae5d1f4ec3dc030c296135d41d5084f717ecb5bf26bcebace23face5d57efba4865763c7dee946f106480d6067f809a9bc7477a9d9faca0c3d1b77c491fd8073bc571ee172bdc2db28464d587a065dd0afd9e8383ae105ab2ec3fb27590ba5fc9d2068baa61ed50abea6e789fc2c774ea125cefc2c6452c0c6bccbb5f3379159319543e6bbaa4d071deb1", .Okay}, + {.Sub, "d15757526be23f24fd1a60d46a412415b7145149561d835afd83f46bde70fbf4b9ad833195cec03ae9d20e3985e3aafce8fd4b1a9454d7188490a9c06f102484b4dfaa71f72e1d2703fea9aedffbbd3af5c9a07535beaee29cc6e2af9a04c55a6c2ec10fb456eb5c073cee206d98bd8081f8baa462f80c750a3064de9f2872a751a581a63bc4437fceccfa17a8e31b668b0009d66a07abba012eb54c2efe7a89c4745a58b8af3262985dc45fbf2c827235e78e3ee2f298dbd8bf1e3b0ca4048e9fd9e6c7258d93dfa42d5abc9e7aae2915eaa67a2f73631563c342356d5b59ac1f0c0ed1ac84250abb0bdc14595e13cf9f49dd47926859b3e04dacaa87849e35d035216da534e48480da9ebaa08ec4147d2905738b717b6e836806d623cac61c4e0d86511b27e7acacaea236463bc399adba0e8ac9d8d11cd75a2686998ac72d9b44e3620c7a90fd5a1abf0aa71702d576954ed9f79d20fcf9e713a3854cf7fdb7f8421fac7a97a4ecf2fef6cd7a4b42910ccbcc86360be0569b3c5977722df73975db6651df9d8a661883bdfa781ab4a3bd75b3afe157cff7ab9f3dcef8d0b3740687205935c4d0807575e129008db7151a4948436abd24d69a9ef9ffa724d1b9e86e30a23245378c68b1716cf79b8507b3e09032b0fd69742b26148c91c1155cb2e5161474d694c433a871ae71fe0ce481ee28d514f5f3816171ed867e5c4d", "9e9f8a245d9344115a70cde3599ce43e9a54fa4c55479cdab748f1782cb0008c024903bad4a5e3272100b9ece62c16782c26d61d83a8fa214f0c2288458f4947e0bc2bf61447be3005d321570945aee6fb4b2b71bc63fc7b9132fdfb35a428b9738235eef5e7d96a03348a98186b83816ad9ec2c5eaf85510bcd8685b023e000bcc768886acd932cf287cd76fc393efc90a211943428ac4638ad114fecab53b8ddc61b8268a4c6588ec8d04c93f5189eb1df0dba55e0ac1cba9da66350d4798a3ccb84e9d4bfaf2b9c583ec361cd78b1ad5639a01a66b2c13f9ff8aacf1e1f8fc240ed8785c233b5d04e54c2e921c72419f5977ba3d93358ff7376d226d736b995701703e4d77b9d60aa6153378132932d4e4e47ccd2f28d3c33780eb0d9cf82090812b11ae59b6b60c2a621bcafeb5014b4e6c5fa3c62e007e93ee00c5765bf72c3de12ca8948eea4ae8a2ebcb62c99eb669dd2b5a3b854d3dd12d46434b414cfd974fa087b95f347d2b599fdcd49ce58ac69b2e6b7fec6f84da6b7114b329b3d6314df17d05edb6580680137bfdeecb3b8d915012adbd1b1fb5ee8ecc0d337cb0f0a3d0fa28f5cdc7fe6eb6a6b56a87a8e88fdbf4d86370cecea316f08898ddee6fba812f315332c57cb4f2d016c4c20f6cf77c8bf9804c3a82265ced6a83cd92d2bafce5f75a78156542897820879342d617796939d75db2bce136ec6a704", "32b7cd2e0e4efb13a2a992f110a43fd71cbf56fd00d5e680463b02f3b1c0fb68b7647f76c128dd13c8d1544c9fb79484bcd674fd10abdcf7358487382980db3cd4237e7be2e65ef6fe2b8857d6b60e53fa7e7503795ab2670b93e4b464609ca0f8ac8b20be6f11f204086388552d39ff171ece7804488723fe62de58ef0492a694de191dd0f6b052dc452ca0aca9dc69fa5df84235deff73c881a3fc425326d0e6ae3ed6500a6c0a0994f4132b3769d3840880848d11ecbf1e2177d7bbcf8b04630e61dd50cde4b407d51bf93cad357768946cda150cb0542423498a9e3d3a1c5ccb214a26c1f154eabd8751703c4cab855445cbee8f265ae0da35d860ad677c3ac50a69c05d68e720303d67690d91814fdab72bbe9e88e147348ec772f0f69a450573a000424c414bebfc14898bd849990527c4cf9c6e3ccf70e7a68d33616e2881054f41f1480eb56c34dbea60d63b8b2eb10741f968a8260a00cf211843e8e81ecd25a3ff01b1a520495ccfad0174386062199f7e0d195e4d95a26626fb5bfc12c6873a0f3eaf00981bbcc2b83bc7f0049c9eaeb67bfe45b04054e237fd7ba8f77ce349933573a3f58ef5be95370e9a8bc04a841d36edc9adb4c8909e9b43db0172888f3f30046010e6223ff62f38e6bd111869f16564b08303aebdbb18d88385b966461560ed42dd544916eff593b0548cb13e81587da635a3da17b7b549", .Okay}, + {.Sub, "-f2ba93f4ee89da6fb1b2e7a1316f37afecce9d70fa0cf36877804a4ae9190707d16fc9f327f82872ba385172aaf74e1f53e835e1655a3e84e3acc837a1a24819f09cb2b5538e186b8a59bd4e3f52552c7311516b6f77b0ba1276280b4f0aa6bb924257602b72c83ac0578a5e28c85fd8e4a92376afcec170408ae7d24a4aed974fb492b0a6a4ed40695d017603e793fb128a82aa2df55ca5226b07b67a5127c89b1b05b68fd36106cb3b8fbc9e62a2f567f2286a9c100e4ed9d552027a874e9aa6feeaa120bd916372b9e5150d30ae70700b8736ad0d255747a1aa21cb36ab8041626c6c3628e07db1f631409438922793a16a37a00fdc42437e1c12f257117a17ee1e170614a6af1fc598796edeee1f5870046d9978b1c1bccab021ca43f471bbfdd47abf030bcb6086305c7fe4c24616a98a368ee80d01094520566b22b087229cc911aa4f05f76cb63852e0c20b7e5e9394173b519f4b22971817bdaf57491532678aab883303381ab08c4f5ff5f78dd6c9867ce90d924c8d104b33ffed4b1a639ab6885710d0f3cc927227237893e5e931b5128f7cd40d7595b8d81b1993bdce41c3017a73eefd8551ad66a4d9b0968fcd45b97401cb3e73e262e1c5b854f1f0c6c700bcdccffc8254d12e2806ed3d785129c421b595456b27bbaa92ad37fc4bcc9567081ea74a407839abf5d646ac3a26573d12b094184a021c56c8ddad", "87c18843f3f2e4b014d81b27a7e0821bec5b89b3a828e5f89b6004a57d07007720c7bef1d89efed4555282fea2afe44ec7499b89914f36a8a6ddf38ca142675c47df54d1fd5946ab43390dda9d0b5ce019268234129e39c4bb434b8894c064fbe7eeb004036fdfb7284e7cd67e0ae482785fe080d1f17dabac0c73d60dc8830a789a447c2c18c30f8a7c592a892658e0dd78dcf811885a52f493291cfae99bfc6b142c8e173ecba33ba5131024df6638374f7caae457a4e76172e68dbb94c535944004600f36b8d7d5fe9b77e45b49d5cd42eb85921ff1ccdcef977c1e60b9d30288a1a5aa26b06a31a06a768dc1b5b7f10d978796c98a08e732a1053adb07a2a3b7ee95ecc0cf08c0c81c3f17073ed98fb71a84ee7880c46532323635e07b571323964057834f1119196475d6178cc1a27579842ba3c3ad7b22dadb9ccca85330517df8fc629427a419610aef4b6c3399fb9d8a029d5db32eef785a06ec3f094bb796d5fb26461c32f42f287f374f6ff6c5db4c361e98841ac5c41c762408d835d39a50589004cb3ded0ca9031558f1d554df7cba053af935b69fc772f70a1c784000ee1781e8edd243e6de45c0672b53237bf28709aca84028f015ebfbc95fd2dea1451f3818e4292e957d363042cec58c17e09c9304db48e77cac7b0faaf9b1cf38ef9b320512dc843f80b1fb1d70b826ee5cb03d916456a3e9ad03952c7", "-fb36ac792dc908bab3006953abed3fd1ab94560c348f81c801364a9540e9770f437c45e24582185fff8d79a295224c64405ccf99fe6f31ef6e1aa7706bb66e8fb51aa8027363acd63e8d4e2be9230afa74a3b98eb0a194565e2a5cc3d856ad0b50c142606ba9c63632dc722b90a90e210c2f217ebcedd94afb4baf0fab2775c7f73e36f8696679716204c708ac79f98920621079af0de24a51b43a4849ffc18861cc487f71474dc0fef5e0eda0b09958eb6720354a55889d4fec806b56409aee0042eae721b0fcf0f019cecc8b76630dccdfb5ef062f24741570a3998d1cb71d718af68690cb4b84551037e7fd14ad8312b243b0197c74e2d1f146234604c1f442299d0064e0b39fabd21a3d604f620cf16b7615e86039ce031dd3452da1fc272d300ddec47b40bc7217c6a3dd463b1230d0e1ced1a2493be0f74e0424ef7b0c55a1e0f13a152f39e6f7ce638fb6c24198334defdb7b752655860f9d5e1e1b39a9ede0f80b3a9764fb49f37ed7536aee8d43273b404af71a8e396c8cfb622dd89dc0d45b8de0111da7ab633cb754ce23033e7facde2fd083a0d0ffb54f4a8a35855241d1e2f2927ddaa9901b4b00e0234bc20504e1e49c95c2767164408574eaef1eb0db52b05e5e3f153e29018b0b1a29d112a7cdeae5e2f9f99f867243a7e79768c02460bb3ef87808bc31b715881db7bc953d081689aa5db440b727023074", .Okay}, + {.Sub, "-6087bcc733d7f8135405254c3dcabb711a2274b9b4429c2e7947827b3c3da522760c3910c7990fef93f11dbd2f791faa9cef8ae3c0fcac1d9de71ef7bc84173729754feb4b60c685de52840468e050c2450c6567242ed060c11fc62390c96ee0de326ba0b4a75ec3133afe635cefe2d89c726b897c806240e4bcbd94f6881210fe545b5143fd435cceaa0f9adae6879fa9168020f028b31fa397fc64c50e8900bd8fecce1ecb2801a57a8e003093b18d2da50030c4e16f325606c642ba9c3e972e3876ca44b7443efac57af4f97036d1fbe79d3495cec577c4ab9093cacabfd094cd9f70fc6df181f4e13caa4c6132e3f5340ff1135277d727374ea9ce81e3c1ad8ce379ce776ec9f2643aee818f9f1818a3f32acefe75b2e9a5c7389e6043f45e68318269947be1b738fe1da68492b2ac0dd617a25a8402f5193ad48f5d60728aa9bf42b7ef3f62d00a818e4c6bd83c0b926af595be7580e6151d9c348862307aa079cd6d584307412e845ae273fa079093e08e9a760065c90a2e1119d20d796b4e268233aa20c8bd51b02cba6bfc4e75cd14696f8eb3396cb32b9442136648c7029501f5b075c39fee5750ab53863f1036b481dd5cf56ed4694f2be0d3b09c824724c5ced0e4295ef6fc5c44c91764cac4051398ae5940887334486a6f0559b72d517e5a25671c70b11d15c6f4053b62aee39300873c1db201d3f04c891609", "629b4192931ecd243531766e9415873aa0f3726f7ae890995900f3aff6b7e85c4969961e66eccd2b7ce765dbaf327fd69a59a83c936e2ae628c923e6a633b7179bc942f675b83e93824405f2580c2a6ce18ef65cefc17fa1c15c790a1b68a1156978fd11ea68d03b55f0199acde0c4eb9b7aa73da5a4bcca094fe3fbf191092aefce57c49c98bef60fa559b867cdbb7b24fcb69b732726373921410c0d15b1154505de13c514263ba69e93da6bba06816cf6083f5f7137c2f614d6a77f0bcc5a36f9e17fab1069818835c94122ac764b3726a5607269e017311e810c4ed8c6d6abdac9c6dc92f26522f7d127bfb92f51bfb2ccbdf552482f4d55cca85b73013b9b3bb44dc1b82189dc893ef3123e153429d702b7d53d221660a81f0f8d6c846dbe8ffdff9a9175a1a62c1acb3752d5ef50e68817a26840643ee9529a6fe0b8b875caa33ac94a8ad4f14ab4ca28075a01411e96853617ffdc77288dcbb6972dac2b4156092da4f6131fce7dfbb30b2cf244a2f61d35621379bca8f51ea53abaad2c35c2bbe6566140d689d159332e0f35e8b72d24c8c4412a6934cde02dda08356fba4899fa7f880b0363a1aee20786c33a2502519ca5045c3a168bf2c6a54903bc2c41502e22929e369182212b0dc183ec46c729315a7fdf69a6c8ac6aed53008ca9d80788c011047d96babec4e36e8faf8e84a1669e7b563366accadd5c6b6d", "-c322fe59c6f6c53789369bbad1e042abbb15e7292f2b2cc7d248762b32f58d7ebf75cf2f2e85dd1b10d88398deab9f8137493320546ad703c6b042de62b7ce4ec53e92e1c1190519609689f6c0ec7b2f269b5bc413f05002827c3f2dac320ff647ab68b29f102efe692b17fe2ad0a7c437ed12c722251f0aee0ca190e8191b3bee22b315e0960252de4f695342b4431ace1336bc634fd956dcb93d70d2243a160295cae1e3df4e3d4c1921da9c4db80e9a9b08702452a6f54c1b9cea39a80af165325849efc7adc082fb44361c1cad1d330e42950838a58ef5ca11a019a386a740a86937d900e3e717d90dd20c1a6235b4e6dcaf08a4c006748d1b5229f4e4fd48c897c7902f9053ceed79e193cdb44c427af5e2a43b97c94a4de6482bccc8621cf82f820425f1835d6518e8ddd768a1fcf45e2f44c2c46734028d6eff3e192b0074627d8139ca37c15536587473323d4cb1017acbd6755d5d3dab67eb1f8fdca5e1cfd69afd391a60fd0256957f26f9d536d6abcfd813df85b3232fbf0cc8269783e93e1a00820993db8185ed9a0b845e84418e3852f463d5e7f9746fed6e7e36bcdd9bf02ffdcea351f8ff8d5b0d024a5bb6d37a01f9cb0e7fdb1ea778f9a03e736615fcf376c795887e7d6fd6d8e8b70acc3cca08d91ff219fcf4d55c585a43d72985e2e57820ee47d7d48bd773cb123d68346725b773e56880bb29e58176", .Okay}, + {.Sub, "4b47f06b065dc4c9e7ff68c52e74986bc14c34c379329331bc4471afa5a638a1606aa4b3eda415034b9e2a98521af5b9143b7a2f5ee456a2d2a2834a56fd0fcb49244d789a2282f0bdff9de057a017bce3fdc6dc086c2ef06eba32d15fbc03dcb2e19ba40d8e6742954f328eb5c558311f999b6c2187c423fb113391cf9de0de55b3f06fc2c73ca9c7b3d13fd4371c8667a78a8df74a21b611b82b8d232ce6a8a381f4f12cb68832547d475eb17c83c9a288f1e44584495ce5fe60f2193d433e8ef19457e3ac5fb943523af852935c2bcd0b0cc747be16a273bb8d0ac7b1d7b278f40684f925c3bc1d08a9ea04899742b12f66a12de2b3784d17bbd4cd9db100478f6e1c5321380dd8d15019420e35ebb5241bdf63b366f9d35509272eddeaacf3af8dbe9cd5ad07ca8f4e6a55ef977b047888d5a843ea4a1958d82fa1cee77f35c49f34b32eebbabe4c852dd69ff10698b3155ab63190b7352758a422a6257aba2de078c11e7fe94bc89d055c9cc379b77ee705fd3b2b85150ce5a83e9f2ce6f6a0242fa1652d8842485aa3492289c0278219f06a70152b30fa28b5db9389b4734a94116732b3d6abcdd7c9d610ad54e339067ce5b4f744dcfe3e8d30274a2996261347abe0a7ed5bc16c250a419e679f94da1c371d19006de1d119c311928c0bfa59715eae84807a73ebe8e0638a89a0c8624fe64f89c1d4ebd1b0acd12f15", "9111cbb5543a0cc44703a417bdcf4ae2e01419bd3e687ad762b3621c8b9db3ec05f354a787752e380ccf4abb295034686af33310987d892f7868bc84dac4811fbd0c408f0d39e42f22ea4135e0e8e54e0cb37aab86e2a09b36d00853fbe4338f21860cc0e2af74b7b70d831a5e06a8a891349b13a32cd9a2bc4f573a3f231775a334f0852226d029e8531b418b5bf3fe9a59a8a7e2edf1a562efe534b131ac0935db56251d9895c867121ae5349d8bb98e926d33a5b5b994a1666d720f2af9611049486dd17f20f59939651709c367b5845dcb082138d8da83db5e60c1164d95da6012ad360f524a93f1b2fa4b8c2a69a217ea1a454f938d72625cdb5e7c2ccb95922e6ff685ca46a10c3d82cdda3ba141afa6362005b5fd175f4908616a59dcdeea331f247b3b6fce7bb7fc160a75f186fcaff099061cb8eb3842d5befc592d3c9d87f2e34bc697f1c716c65f678943b952dbf2cf4bc7912acfa655182f5d964469646b2e62736b26160d9da978a1778400abf0f663a324bc90779fef0509532ceff1e266db128c664a6d3e7c76422dacb4674a67a37ca9579fd707f98de6c315837f6ae5cebbd672675c58e6c2dfc0ccbbed7e5dd55b592e969b536cc52daf667864573435214f9a4acd7e2508c9d77d1c06e96b667f6105cc72cf9ec1994455b5220c75a31764d680f97a7c5a896271f5ebcfa5a2beca565e47e57de902a9", "-45c9db4a4ddc47fa5f043b528f5ab2771ec7e4f9c535e7a5a66ef06ce5f77b4aa588aff399d11934c1312022d7353eaf56b7b8e13999328ca5c6393a83c7715473e7f3167317613e64eaa3558948cd9128b5b3cf7e7671aac815d5829c282fb26ea4711cd5210d7521be508ba8415077719affa781a5157ec13e23a86f8536974d8100155f5f9380209f4a01b724d77832b21e19eba3cfef5137b9a78e04c56092596133f0e20d961294d386832107efec097b4f60317037bb680c7ff5edb6228157b415edd2c13c55e72a1eb7300b89b752be40d97ac238101fd155f96475e3616c0c283ce98e8e76e9091047029326f0e88379176ce015254aa10690de7bcb4e02c053a3649238c83aed698bcc05b58c8b8a56bc524f03440a3fe1328c6f2feb3aa56087a58e6803ec6991c01ade768284271af0c2326ed1df6aa61d2d71ae06d8e8be301cdadd337a919888c7983d209fc698191a36d9f5a84db0f589381b8a3b83f26d43f381da4d70984cdbddfdcc81c4eaf928779fa78391f7b065dc6c364fcdb2c575e5042402129b3353b86d85324d59fd33677e26a5ae521dfa5d0ea238eb597e9c07ffc699848f10b2326be982e7017820641451985cc63c9de385d052510f885479623e8961591ac72b6fdd872ccd3449666097eaa1b5dbb006b849bac89b16f492e45c0d0d919bf6fed8d12d897fbf53350881727634d117d394", .Okay}, + {.Sub, "-eb64dd92838e1ba30ccf5a531d96ed4f3af6ed95d6bdb131c92ddde7fd74981e06e61959ee40f19e902797d3350381bfbdc722ac5d862a2b34a00c4cdf40f1d19a44c71862f9cbeccfab4f630cee3a4ef017b6878988e4ccd3251e759f908f8e80c31dbebbca4cfd6b900b1e8a734ec01e73427894e2554652fe5f0088912f49a14d17bc024d580354eb3d611bdcab2b811e7729c41070e354f87394ff7c47b7d420fdeb7e9955a37c7447a0dac4b6437d27c2b8bc4552f981675c257bd397d9595ae9c4424112fcf2c95f88b4b7a8a22f1f7b3a150dcf655f6d415c8cc25357fcc13ae3d4b506c90fe49f3318f3c07ae44a5c550e8087bd18c739d263717dfd2f570fdb42af9fa722b57f93a6f8c6562b6b7310344fc27c40e3f51676b65aa16320ab7877dd7b824dbe8649b70d6a0e67b0fd65a5ed540b830fada3543762814e2b61c5ba2115cdaf2e761b3accab284c660eae81b6d86fd5cf6c43ef6c011ee5f0f79718db7209f761a80cc7e6ce5dfb78620b9adf9ffb6cfb52562631429524719cb23bbd2c0a2ad69085ef494bc595cbd0ee8ac953cbd02dcfad14d26a52d22546383e29e3d84449acf1b96f59275b7665a4d9311f1d40581f631a1c27681c2e4ced75a160a35f43a5b6c3ccef846a6e883035331ea530a5bf54f51397943ab1fbdf61f5e21e998ee8384feed92ea97e747883cf9381063601b2a46b8233", "32512111698c12fa1ea6e193a6a4e4291e42e0ac25dbd251d34611e56f983e8da86bd26c0976a27bfa3ce0aef5f32043faebc974be11080673de7ba9e8ca0e83c0f7f141377d99fb14c6e4cbd3e014070b1fe3b64c5ad6de7df487b345215566cefae88e684269795b7ad7482c82de646043d423806676acadfe8871c495f987b9a7e1369ecb5f445c88232dc4790c1589af3bab0b8207f5ef7a39ff4c0222f580351ce1e3b399d1fb9bb38d5a7d5433d2c69477dfa049e917b30ae1eb97a97b86cda1b91a9a8502ec69af0e594d50f7cbefec714568d5430dac4f95627fe5f51d050428fc6cafc7bce9c64c3db16a9026cecec660a22a7ba1bf24adf6aec4e9461190b679c12e8a1ff6f9fdc3162be8da321214771624cf187a23eac62b29bbd79c7701c4c2fde5f9d1e194af59bb3560fa06c0a3a5f1856f8e53ba779d44d94dfd69baa80c379295b72854d974217c493a6ece7d37361826309e520d8c3ab49e54242fa823c319624386aca2487353b1fa0cdb6c0879e10f2dcf02f1fbdda8a2c091704d4cc34ca73f7c3bc82154a86983c0afcb5d25d2604b143f555ab7992514eb1e60fb58ae667d131b7830df32ef0ce8abc9b3c93ff985a2060b58273c5f710b354fad02167a0e62ddf2b61b22b0504484a1936a6c69bf284ed1e533656c057b32597118d482475f74e15d65c05bba6c43dcf0880641f0310fb70e1c85", "-11db5fea3ed1a2e9d2b763be6c43bd1785939ce41fc9983839c73efcd6d0cd6abaf51ebc5f7b7941a8a6478822af6a203b8b2ec211b973231a87e87f6c80b00555b3cb8599a7765e7e472342ee0ce4e55fb379a3dd5e3bbab5119a628e4b1e4f54fbe064d240cb676c70ae266b6f62d247eb7169c1548cbf300fce7724d2728d15af4f8f2a118b747b173608ee055b7410acdb2d4cf9278d94472ad944b7e6aad54561acd624cef75780ffb2e35420a774fee57309be59ce2991a6707676b4154e0288b7d5cdb97ffdf330e970e04f999fb0f67ab5a76a4a86d1990f1ef42394d19c63f0cd121b690ccce657f56a52b0b0b192b1b6f22b238ba865e805a2042e67568a091bc70ce3142ac79916a0ef23f059d8524ab65e74b595e19013ce1845d3abd227a3ca07968479067de66672543c8ab042649934590f29e015dcbd4a75a9c28cb80622d4d6044e59e701440cca495a07d7cfeee0e87fc000a95fcf83bd384451bc6c0ff352359a52eb96a2f41b1ad726ee706e819dc7c292159182d203dc7322e228909ef56d2160cc1b76aa06dff4f919e5626799e3078e3ec6a2d21ebf73a31569f253c86aac6c00d31a0385a4a834e50a2e4e85d39ddc16925744ea47b9f5822c54e62b9d9520894b6830aa71abeccb4d6c689119a64e7a3c6f8caf9a6b77711bb66faf31bd647ad314c3eef0538e0bc60c01b87482632c25b799eb8", .Okay}, + {.Sub, "-2d6ee5945d0d6132bddec1de891fc9ebe8e10fc2d538119d96320e38b9b2afd255050668d3684e59cf0542a2750cee546eeba8b44f800a7f6445fcae663bd813db1b746ea1e05aeabbd6d4a9270217cb9c26e7da851dbb60ac52277fdc1ba6023f834a2b9eb54d3444a36666495add00efc5d974dddcc5c45b21b7cea401574b742ad8a6058c8f0575378c1dd0ede8fc9b224658177c026515408cfbac54d9b29d121d299343e89ee68e86a64d58d2d5778f43a791a6057a03899cb5cd1a29e53c0ceba8164fcd7c354081133639e03906d868a05df2673147e7924e2f7855b0b37efbe9a0c454b3aa3422abae44db36150874a173e0f66c3222fd56a14ebc2c02c359c4d2fd40af848bc19fcc65cca402a6975c1bb02ca2d0275f6bd30c8df7121ebc9b0d570b749f866b82787b6882b5f10ca511ec1c6ffe901fe9525ac543e9d3cf766ddc372f60622a13b863ed3aa84f1a3ce8a1fec70eae3871fa01ffd44819153c28e79167b22eebfa5099c29cbfa398ff21d0ac7b74520a7445bf3a6d399b1bd062da757264d40c4bb9cbfbc0711e9c3d8435d7cd8f29b4a1cea459362280693cbaedc8703f2d9afaa2e4156f2b1259860176824e3b699fac5a5bddcb81822f414f95158557b8a173980125719e8ea5f76d09d39084877d1828fa52f1fd3825d5ebbf0d1f62087b27b010cbc11d1e74f5b68f0fa6770e0fc3f571ef4f", "9e02a7fb1ef8312ee78aec5f0befbf3027436db1d7e451a80ef8606e6cb4d87d891f573c1227e9079c099e2450294d98cd4fbdff5b882c4a9f96a83d4bcbdb1060584473748c6a71769174c58b54c132e34c8d05a02583ed000ade3f93a2957d08dd31f99de6120a1d24ed6cd32f467265c00f4dc166c2d12cb0ec09335caec2cdc6c250309814997a5cbf5c8af1f14ecd6264edaf930301b01c054ed8f2f34ed2388270a2f0412946477b3788b143c6bf495ee3ae7ba5b69f0707c4f145ff0dc76f8602e8d93bc853add5704ec0e030ac6bb47337a50d53c4d0f25fa069f963bcc86b259fadbba90ec8f004cdf1a37a010e1ba0f07a18a24edf0a8aad2e46706f44ebc2b3d7f5f3c7a84cce1007bbd187c1008cd13604e03832296765a61e9ff2322a8124fefc68f805250e2fe8d3f267e8e3166ebbe1cca8e8dc2433d8553350bbb5fa0fdd5503f10c0f0eb73d7c79e8203ca4092ab89513e3168f7315af0e9a7ae51cd5db99861989d5c0042139a762975dcbaf56ba53c281a96540c2fa6e5677e3341c0f2246758fc5686f2f2cc18e06d9a39bdeb9c39e3ef299b15ecb8ad9ed1486fddbd0c5aab38270160a05b1bac91d804b516efb42f36c34fd9b9aacf5a5132f378b8249e957f52c61c4c1efe1451fd3f96140e94d1bebbb572d9f3e17b55c00197e4f376fe324acd4e3a8edc0062e115c5e559944316aaa62b54953", "-cb718d8f7c059261a569ae3d950f891c10247d74ad1c6345a52a6ea72667884fde245da4e59037616b0ee0c6c5363bed3c3b66b3ab0836ca03dca4ebb207b3243b73b8e2166cc55c3268496eb256d8fe7f7374e025433f4dac5d05bf6fbe3b7f48607c253c9b5f3e61c853d31c8a23735585e8c29f43889587d2a3d7d75e060e41f19af63624a39eef944b7a5bdfda4b6884ab45c70f0566c55c924a8547cd016f4a9f9a363429c82cd601ddd60a169c36d8a28b4021ab30a290a47abe6028f3037c71aaff29094488ee568384fac069b3441d13959774850cb884adcfe24f147047670f4072105cb8fd12b07c367eb016169042645b0f0e810207e14e7d029c7208458786d536a34c340e6ddc6d88758a6797e8ece63183085988d338b2ac970450e71c325607dd978b9090a8643c751dd9efbb80a7fe3ca778fc0d86331a773a8f85707db98c33516e39226fa169b4906f56e0f1ccb75c22914f016d17aee2e293fa58fec32aedcbb8c1ba54bafc44223af6cad12766cf36d3b3d9868234db9012ff047ee997b8da63d1b428fb2881ff2575e1201491912d68a73b800324c0fc6d7dc3b8c99935e9e11d6ab8ee1b20e5db77064cc7f1497e5d0be157f7787877274270872097cf4110969ff9c5e7617fd3c5cb666b1479d1a368d38027f23014ed81d6053d5c56d1eb9fd484f474aedd24a30712ed653fbb3f7a6e582738a2", .Okay}, + {.Sub, "b822ec85f636dba5c4a4c10ddd5716023caf3f4a43afeaf16d20ff2ec2f7092bf0d6a1ab25c4b20b679680f8efa06633ffd3afef8b2b4be328caa66ffc6ccb60c148a5ad17510aee9b93816a8538dff267e3778810775c9ad890d94b82eeddf3a6f9ad0f7f9f41604e786c7fe089f11014873fd77b30bf2ced35648cfe982db3a918a59a8e6dfc0e3ce64ea038c71b0ffd704ca4a545b8fb5e765966f12683dd29ec88a1ebdfe5cd24ee0e7c8f625e0071d45f413ee67ab1cef4b4b5094fb7a15645044038ebccdf75f387b0825847f3bc995d3509b9989cbfcebea8c78be1a78f34cd5d35aae2fb670724f72c6e687822cff681b926a7c3d3a1f41daac4761da72cad3df6e48b3ecc9f75e0f051b1cc5ff4e21a91f70239272aa6b71c1e9948a348be9002dff65424ec082ec799d2d56b61ab69e826bc8cc9e077ee9193e396ce57cce43bdb4b42efa4364bf3eb9baf7711ab11cf8f75da334d75e8889ae7961ed3c8e84d84851a02d26e164cbcd23657372343a584259d66b748849b5c5d778bce1fe393bcb93ff56e01947b832dbf06bd9c4045f29e119e4dc6d4fc9e2a609cddef70bcf78f327df9d8afe27a3604519a2f2e9fc6db5a9afc02b1e873f23a5b2c55ea3438c1411c3beaa9796498d55b37b5922dcf13fafb834cbadb422fed5007ab752957767adad7184f10cbe1b2404da936cc386135025bae848d4ed96a", "93f8e2bad2f7a3341495963544f9a1ecbc3d0b3046658315fb39bd4666da020e7573cbcb0a3ee7b9429eab4298b8bcb463f6e4f45d7152d56bce0d2cf48afe1f8f535f804369bc8e36901c783cfcf1cb8938a3e505d033f21077c47b60e689784d94b2dbf9165f9d80b37119b66f1d39586e1c4243b4d3172a441b3c1dfd6d6381a33473f77af008d52897fb311da1253412a943d9c508ef388a1fbace05d461ce20c11c665e3f42247ed2ce61fe75486d830d928217d63ece7948d854414a38bf22ba86b65c8c89807a342cdc30c958b7b27ce266e31b244ddad64a80a41267c00eec89668a54c0ad1c1a5e246818427a08e8229bdf91878cea5ac932f4bb6e3e574a60b62b69e6a0e7658fb200469105fd11d5fa950f80453efeb4a4593274fd9f18fb35d7088e2bee29c7ceaefde3adbe228cb5958a8e2742cae8f92ae5f6eb308e7b998ad41668ec61aa60d6dba6f2655dcd4c645fda6add7c7cd5606f3ddedd2067e366ae4b77e765eca138a1e49f5f56b947e3b9e0aa85989ce2d3e3c18f0c4e1cb01a0b1ef95848d83716623576c01d1cc17fbdb59f9f1d60ca81ed018ee2c24ba3ed017347c291f4685a9ee302e730b48288da6e9fffc9ae80113043d7d46ab2089870e5adb312023d58518811989f60cd334755d82da0cea9a33b0517d773d14b378958f27586d026e08f99d2a52acd068617e41f169614a40e0f25", "242a09cb233f3871b00f2ad8985d741580723419fd4a67db71e741e85c1d071d7b62d5e01b85ca5224f7d5b656e7a97f9bdccafb2db9f90dbcfc994307e1cd4131f5462cd3e74e60650364f2483bee26deaad3a30aa728a8c81914d02208547b5964fa338688e1c2cdc4fb662a1ad3d6bc192395377bec15c2f14950e09ac0502775712696f30c0567bdb6a507a979eac95da360cb80b00c25ec39ac2320af7b5bcbc7858581a68b006f3bae2d63e8b8045151aebccea473007b6bdcb50e6d68972249b9828f4055f5795383a6277e9b04e6e052a2d67d7871f3e85e46e7cf3fcf25e0d3cf208e3ab9eb0a9908065035a8c70e5f1d47163c46b7995477cfbaaf68d562dd40b921582bb810513e516b3b59f7d0449761f2b8e1eba80277c566d3a5a9a594cd08edc5f8fdde66f8ead4f1bda388dd329131fea29dad059868fd9fe3273e68a250772c86b7d4a19314c00884ac4d44832b15ffc86ff96bb33a78583ff6a8806a1dd6ce8aeb0829ab843051b7d7cc8a5da06bbcbc31afe7b88879b5fcc1d1c6e3a2ae20fc15b8bc446ccb898ffd7f238472e05bfeaea974321c3d5f0dfb2d25190a8dbf363746bb7a1f97214eb2fe7a1d3e00ebfafc39036862c1f68357eb382ba0505b6e88d8a73c0c474d499f1631609bcca52355abec319ef4e8383037a3de1fed21e861917ee9eb52186da87e69c5b24950e345186fe940ca45", .Okay}, + {.Sub, "-70156de89de3c5bfbb8deedf66a5187ed27583aea378f593cee4384ac8e87d96b92c42108e1cf072889d6ec302a0732c43f1a3494d9348f6e198db6be42d99a3ec72fb470cd224f49f5cecc485013b0194a46de8d6f3bf3bb1a0fa4a156325d9f6e936e5806183520a02a9dd7dc7e5f0c0000a6228eac01ef2cd0e1bdcffa6e671e93c40de5bfd4e5c7b02090b22ad7ec3c4b41b7bd3383a4d791799b09c9c913a12258408bdf9c8d918ac7cfa3a63d818b1bab35f383f922c8d30a74122c93689bbabc48ffd6be1ab27d25b77ade28f6381b059d6c3bcce344731cec74726b64498f15464bc1ab6c5b0a3a308699eb08687f4b660c4a2a1464ccf38747b0997f9040781954378f2a787a4f4c78d066684f4752713ea82807302979f11f35e1affc0e7eb0666eed85d88a111f39f789a61d2e7f0f6ef50eae5bf73e68e9756357f05f14ab839204a9e4fa7ef3b5757866cb1ac26854baad62dd7911a66d84966158531ddfe23fce8f9c9cc88d77a1297e1cf9d7ed31912a16ffa46db713781977d4f55d9f790b1f70ab21c1ee4b019fb391f709b092ded1c74c9a927b12337674ffda82b01d4c3bd3e7a995cddb1ba2d00923addfc64dbd2edf81fc0535731aa1eb6953b6f5bcde398477fe1294b817a88b384fe3b3c3ebc5dab4167181926c0a28e2f9beebdd783f5e5a2a9c9ca8af66f6d8d0545dacc9772e73899c38333d3", "1e6702adaeac3b62510d18f7042319eba729a29f7526c93e625b38a14dab740188ae89942dd22f320cbb6bfc947fce7156af42a83d8990355d949d4fa6f467920de5101e5248f6b07d7613a4debf92316e57c6d926087794db4d18cd4c7a6d8ccd45529a048cd4f602956ba2cf7795ee0432340f621872b6f7329b679f5c90080f41d049abe72951b9ab8b56aaa80b86f41f6cdb339ce6c46da929677f3ec753550f597e6720151a66f63db1a8af1394753188350ab1671e9149c6fff11214250c10ac0985230ef7e3f22eecc6f8e15dbdf0cbfb33664e9947fef35b5fc9e35a0ad5cc1e23bdf685cbd56eff67e004c3e9a87de67d9ef2c093812377811045f63029a40ff4545dcb031014d5c70a8daaf3acf3272878e529f15eb1cbc267e7a653cb75ca4be5b83e1df5f50d40bb16901ebb9474ec268845d10fda475ce9319ccd3d796c54e1701296407baa369b037fbf4afaf0f5b47ee26efaf61f9359a068c9ba9179234365870e00e5e7473909ecd8df248360402aa97b57ba71bc11edeaa3064d2ec697f2b4b8eb31f6fd3f54aee19fcae05dd9bae877b54db02090351911b21763f4d44b638540dba3e40de378712cc388b34f8f5fc45b33ac7b0d75783dd2c578270d14fcf830e9c272b08ad1a6f22d2098d9e4c3ceca003d5088b337489a18fcab4440b0939eadf653bc0800602c5882ad408f26a64be5f65212bb0c", "-8e7c70964c9001220c9b07d66ac8326a799f264e189fbed2313f70ec1693f19841dacba4bbef1fa49558dabf9720419d9aa0e5f18b1cd92c3f2d78bb8b220135fa580b655f1b1ba51cd3006963c0cd3302fc34c1fcfc36d08cee131761dd9366c42e897f84ee58480c9815804d3f7bdec4323e718b0332d5e9ffa9837c5c36ee812b0c8a8a4326a016268d5fb5cab905b7e420f6af701efebb2241012fdb63e48f217f026fde0ee3400eea2ea2e9776c8de342e869e9a6b0bdd6f7a73234dd5b95cc57ce15207ad98f1a01483ea6c3ed21727c550a2a0b677c46252a27110a104f6ebd72887a113c918612a27049a3747030729cde639561d9cdf2aff58b4f8e292dab918997d6bdaa97b9ca8e97941178a1684e3c6367aa6461496ad45b45c1538c5db5524ca7167b7e961f345a8f2a808e7c65e315d930b6cf4e2deb8087d24c436ab70d1a905d3490239971f25b062bfca7177b0029b89cd28739fa31e9cedf3fc3572167627007cab2701eb31c84baaec20233593d4aeb52014d2d496f822055a308be28a4abc39d4e15e1ef6eaa1abf3b7b6707a804ec7ef6d7d1b36c8061afbf8ef6a90f20c3bb7500c1bf9da571befe66afb46b32b253536cce64a7225c895ab39668e2e0907869a39bfc0c4c2fa5b21ed41623802c7541a468a1d9f7eb2848989a021834898450a01d8692f6cf99e587f31b5bbe19331e901595eedf", .Okay}, + {.Sub, "6906a75641d76a4b3de054cbfd901c4ff834b1984f96989df9f44e00832f3ef17c95e0128b50c22e7a0bf4a649cb1c00ada102cddbf9535cce07044f595e81727247086ce7a6136f8fe3048e11a35011fd98fe2dc08aa877b7edb5e7ebcab38b21d5d031fa57058bb4d23b17d811893a76aae068708248655ce45ef2608d220cc3f7f1cf4f0776b840e583d786369d1594b37a3dd524cce94b9ddea638356698f530b1adf85dc1f6e1abdb119e3e484fc4d48298d25f865d86fc8786695d98959e0bd5332db1b744958964d95956032ded94d1ac1cac993bf3e839ec75a0ba81341c85ca00e63046ef182b5fdf386d4b737ecf6a09affa790ed63d69c75c312d47462bd1dd041c6f3c0a4c9e3bc8a8b375fb1b7ea39bfd7f4b4ed16888dbae4dc946ed53a34eb3bc00a75091c1fd0148357e923a175aefdc94df439378181a73472697f3705d83e24b634422bf2c99bdc4e51340c15f0893c7c8efa94c51668939beee1749db5f346766a437076c62ccc6482241fae7ec1ffdfd794abcb98c5fe5b1d0650162b62497a810fa5b265230a0fa3fdca94ca71129b28ac80bb307ee41a5c32624d50b05e00b0e5fa0fb8d4575a7d8c9cc231c371cbbde607d5a3abc590a3f6bf6864fce617a22f9c21d35a91454678d0ea3abba8b371015fc33cb97428e6733f12591d67f602eac6b2563410dfb780dc19ae61b352336d6e75d7db5", "a7a7fbc24f21a47e38fcb0c3705948d6480e5006910d01386ad0609dba31c4b508c60753890835b16f39f1a5faee5cb12fac9de267743a9e3a18e401f60887b5cda5362efdb5c72a7e5e02046b86fa375ba3f399035fc53b7f93b84133a92fda17da19430722483d76330367fb73ecb6f6a013e0d4fd1f63706ab5357a8913f3f62a392bada2590097391af11efdd5e07a02ec5ffe7c0d0e79bd397b64a187ad0a7545e7275715933d25bc14804d7f973c782764ec820e153c0a64fdc92e076109cec61928d9fe4e8fe8cdf898a739e924a1237566977e0c568f61e4a16363d65600494fbfb095beac6b6e740e1628af2ef0d4ffdb8d859283c480c67f8649b5929bef22d6f5d82947eeb747734e617b4c1cbd632f5cd68ffb4de08b43c53047e3bd0d4fbfbfdd98efbdf20c3b59fe033c3f6b2269accbb3d75b0b7c15ddcb511796d8b37e9288b271dda9711edcb249be6f78f7a8e3cbb490bd5cce3b08c13158bcee26b1aedcb14c7a60a56a925cccdd424ef5374794873439b0a7c3312117930c193e0f81cab1daf855e85769d9875339d7a8e1ab2654ce7633370a61761933e87391b7d7c6f5971315013941ef60ae0499707374c3046e6c64f8c0e917e6546a550821d9a962d601a4e79d4a4af70d7a822e6424d347f6674af0a5b6e5a12115f77d804e47aca153b51084e8f8d2973a1af81c6cd94132b6a6a126d0126d", "-3ea1546c0d4a3a32fb1c5bf772c92c864fd99e6e4176689a70dc129d370285c38c302740fdb77382f52dfcffb12340b0820b9b148b7ae7416c11dfb29caa06435b5e2dc2160fb3baee7afd7659e3aa255e0af56b42d51cc3c7a6025947de7c4ef60449110ccb42b1c160c8502362637c7ff53378647ad6fe1386564319fbf1e73232475c5e9ae2485653971998c738cae54f7222295740252e1f5ad52c6c2114154494392ef9539c5b79e102e20f374777a3a4cc1a2287b7b50ddd775fd06ecb6bc2f0e5fb284709fa5f691f3f5136bb370c51c949eae4d062a727f82bc2a95521e3c385beca6577bd5343142eddbb63bb720595d1dd8b1974ee435cb82a18884b55c350f9f1bbba0be46aa93785b8c7d621a1e48bc0d910afff0f22bae981fa1a761ffc1c7129dcef16a17a795cfcbb06c0d8e85251dbd7427bc7e89dc5b0ddd07040c00e3504d0267a654e5fb0188bf98a65b6e784c320c8f46d24eeb75aa81efe000f67d37d7ce513bc6e6325fa0016fa2cb33c5fa867363c375d067794b7ad5a48d90e1f148d435044edfc438756b23f97cc385e7f43a4c3a86efeae6e2af242b06b9302bbefb70806a19846621b385cc0a6a751a6cd51b08698438edd29fb60159c2b535994748781eddb2d154df9261aa15581278d6b303adaa9831a09de8790498f28b5d621f3866419c39591893ea2ea5ad1f325fd936fca3f7294b8", .Okay}, + {.Sub, "8c224c0aa3b75511c4d5cacac9c5707200affae23411971c5ccf8ef23e522d378cdba7e58514f17f19b2c6b3361a7d59162df74a6182c1f57cfb2d6c6511d9af69660260b73ebabf0fef646e0f50623aa633eeb7febb9b28d3980437484bbfa8fbc0d82969e15cc1588c4f7308ed328460d78613aefca4e26e824d65e1b2d2d614381c12bf20112a0019b3cdfe5796a989fb486bdf9ddbc63245482e4517ea6d331f76668f62469487f4c730643ceeaef2dd60c4eb7237b2f56e972ffd71b593d1649a2671e73c6fb1c199b80224de1dab868021f963a6d4a2d101e9031d63c5293aa0ac8b4ef28915db9b2f5639cf2bfc234cf7ee0bfefcabe4abbd113016e5893cc5c675546347929e1144bda0c0f52a30ab07467829e90c191386827392c3f011ff760a05d310d2121b7e4e82e37ee6574b5ada0556252d2505f17c488708570b3f428a722bddec1097268c4228eaf979c8a56a28921309cec17bf97c48ddeb0da4c8f82140ec872378f94ddfa42b740098dbbe8f133713cb6980e2ce645a42d42e1e458142d9ffc210ee1f019b9310cb0318850ddb71e3656284e3f13990db9863711f6c23233edacf72f64dc5273365f0281e6a3e88844207c8aab53ed08dad12a1c4894d569179c2a71c108b597f4c08916b652d389465de7883f037b9fcc7fd340d2bfdf01d07e822900d8438e676c2da9de980830d4a0abeaf1f6492", "c5c7a871c783984b31baf258f446d413251bb563804ca4e82a54fb16c6d2d35230ed4a3ef8c29a8c965bf98ab60bdba117b927944502cd55881bdd3f6f06984753393d2c3f59c8f97b55eef9f05c557200dacb01a9fd1ebeca4a11ce6475d718ebc48766ae09afda2a6ba5257c64335b77d65bfde51017249aaaddb2a41bd59b22002d5358797032d0009f6f8819180161c8342669450b4d83d82f3895a424e4cac4f690b2f9320bcb65454dca41abb79a70112657256e1d662efe6cd7bb87f787d3a0dd9dbe15b378d04b00d75e5d2b404f85e49f7bba3215ebd287f280282b843478e474eea058579dbe35b2c4c080fe00881544ffb1c76a3420d84a68dfe591cee9df1a7296b74101f7479b222ed9e47fb6219896269ab4aca6502da170feeb33ed97c87a80a9b13a3605044fecb5e1ce724a71a888220c1ee438e3e8b388b60d12cc1f2bc9c5d6ce7086a4772df599ecd3cc620b6145d913027a6bb3cbfec3a89520fe2d1bf57195e12c8a68f2b691fd0d10d8810eb1acfcba0af7f678aab24d29f425be3f6e9e167539924961d028dda94bd42cbf1401d7f99f1ad3fd728e171a065a1cd5c225f44382b5e5a19f2d010b159d28a3fbf74b0e6d8b95e34431d20b4fc2b0cd31f5846d22a475c77e9a054e76919dadf4a48a27b8853a295f76d46bb70d9ff411c335771ef3d0e56ade80a44c97fb20b03fb169a206eb65da", "-39a55c6723cc43396ce5278e2a8163a1246bba814c3b0dcbcd856c248880a61aa411a25973ada90d7ca932d77ff15e48018b3049e3800b600b20afd309f4be97e9d33acb881b0e3a6b668a8be10bf3375aa6dc49ab418395f6b20d971c2a176ff003af3d44285318d1df55b2737700d716fed5ea361372422c28904cc26902c50dc8114099595f08cfe6eba189c18157d7ccebba89a72f875192e70a508c3a7797a5802a2396eb7743707e1d6604bd08a792b0616bb3366a70c0673cda49d263b66f06b72bd6d943c70eb148d5397f0d94c905c2a618135d731ad09eef62c4665af9d837e99fadcf41c223065c8af15501dd3b1d56f3b2cabe4f751b3938c90008922418a51e336fae63e602dd816de4ba4f0b1a521dfcb1a89392c9ab2dde3afb21ee21be74ad98df281a86b5cd0936fb7726ef97a331fcdef9de4767a02c805f01d38994b99de7eabdd9601835050aa0730b26f7e2cf32cf4440fe72378320d89af058060bdb08ea7268333c894e8b1dfc743519f1fb7a9931508a152814506f78fbd5e03cfc949e54644b7347c63d1812a6334f1ee3a21e72971a36e2c3e1b27eb6953ab0b29ee719740fbf97dc77f99b1aed7ebe6573730906a4e0e0a473a424f8adfe277fdb640aaa7b88653c251ab945e5263880bc102449400149f1a57a0c6e830073f621a62d8efc63c36131f809e171fa11a02d32675ee357cc0148", .Okay}, + {.Sub, "-b759b131095167d85de6e0319752cdf2fb253b47974990f7cfe95378f3ff04c11773856091b06648db5a68065b47103ca1ffe74ac179a85729cb4fa4143041ddf2a3d17092185667bf80d60083acd38ee9805be169cf4ccc08771657801cd48fe9ff1d932d85933e1a2d6d0accbdea2406ab3b44524a7c2aa19124821ba60963e5954340925853617d4796f0bce6f77d357ea0d95a2e2343cfc1bafbc1bd172a2f0566addfbc602ac45d28a9013b839718573caafb854dc1af4e5c5c0dad8047bf396c4e0891c6040b068d1435cf592747dedc0b4dff14b11bcbee30ea13d683cc547c454140f670c0be3e9456d0d3625ffbbd94a554e66a292b1263267f5e13aa3118a71dccea999add3aec944d7b145bf76b34c32f8922f6e993ca9973fa9a5c486757646795ea7cc6a441201318875d5f098fd5aa516d27ad2e064d12aaf1bfbe29b5ad2a6c6820d278c0b856ce69595219196fed9edae2b96464d5c2308112bf76f5a460097caa9f3e71b309d77b75f1bb41446cfa2b39d0de8f242daea850d8c2cfe24d15415ad1e20aef31a03ef8b6a70c6c7880f9ae395137d0967cbd184385d93cdfecbbfec73a783384793a549d627dbb5135e1a5f2327e553cccd9a82ed3c740f8bcdbb8747c65f8b96983c63a2356099e5d3a91ba9d1fe07d964dfa11b836ba6d8c0eb4e31a4ddc90c8f4fd10da678573210ce55dc5fa69dc3cf4", "e51168608e4f233ab252bfe3eca725a06b24dc868924364f955e1f95249952dbcb09d00f18fd9cb6faf7499fe60b59b5a3636b70b3b35db867feb87d7e192d1915613bd1f34b4f48398e31a58f558e80190a1eec338e1e98dac0d85f0c3a518e8cc87e5739866814903d8aa43f7386c757606eb7302777820b7bb4e69a497422a178f613de497d8836e54c44749e7f974e296bf44da573b01c3195f278ea948ddf07f6a33a705131f905520c366b47de437bdc7e4aca8073b8c8945704709f09d6f0073b8c83a28b2c168179380247688b9ca6b8ffa89254f4f3d1929a5c530ed102064883e7ffd34429a3203da8b900b48cdbecffeebce5c5752666413b55c03027c7de53d471f648283cb03197cdbddc78ef492701dba25c055a7efe90401446b656de7d3e3dc2a6b05195429fda3e37b9ff6ec3f5fdfb6ecbd99263916762810bab1c747c1e5ca960e8901b9798ff458b9b975de08be54897f903f0e54cf6ce698c5b460e0092a5fb84a32aa2e2308bcb3f777a570113df3393e2080d16860d97c9dd03231d0eda690de54db152bd943d41ed51e66c2f7be199a4258d6df9b037d9ab6e698040a3763395e906f8212b6c4a66a8772d2470d6355f29167ddc1876a6be6283545e0b23d30499ceccedad14fc951e344d6ab44338a15c0a1394d5c0e8a3086268e04c974ddd875c9e1347e35ede60b702172979422f64ade61f", "-19c6b199197a08b131039a01583f9f393664a17ce206dc7476547730e1898579ce27d556faaae02ffd651b1a6415269f2456352bb752d060f91ca082192496ef708050d428563a5aff90f07a61302620f028a7acd9d5d6b64e337eeb68c57261e76c79bea670bfb52aa6af7af0c3170eb5e0ba9fb8271f3acad0cd968b5ef7d86870e395470a1d0e9b42ce3353185771483a80ccda7d396f3ebf350ee3aa7abb80e0d5d511a2cb15cbd627ab537a6cb755bd31929464fce356816f0b3121e1f51962973899515688f371d0e8d6dd1a08fd37b82c44da7a70610bfbfc3847029929d56828dc528f64404e7e1b494798c6314889981a543a34feea038c967bab3d3da58e08571a15c8fe305779cc5e548d238705a7dea3164c552eeee4998043aaea2febe35e1a5d3ad2376f5d662b2f2c5951908fe99a04f6896790798b0a4125440c9d4d221a68ac4ca336150d3ee67689eddb4b0cdce2ac02b515d68c6a77d77e1290350ea6e0a0f509ac314ddacb9ac01bcfab8bec3fb3f190472712c3ac52e5e708cace5703250353aeff03ce2f2fc8cf3e8f9be5eed292a1aeadbf623eab6c87b5f84ab496cfca23d6e0e1c8b715b8009ace463c8630616c867dd7e534ab5c0a57a85a37c1139c3984f6a92883671734f1feb27d2aaa545fdd5c13c87a9e2cfd2a0d9c2cff4ef017a682b63ed670844f43945e62a23240ed70829ce8a2313", .Okay}, + {.Sub, "9c89383f948b14eae292999ac5a05c2c6e555c3c22beb8e9cdf9dc3d045df9656ad9c207f55edd802c035063acf16f82011513fe2038579b94d3686f155c0b13568447868eb3919ef8f88c283fc5b505dd3f54875e094d58b72a48692321d127eea2e7dd98a09789aa8e7eeda9fa9bc74a1887fe670da1ac63a0bb0111a508a0e291d22f1744a7abbc35c162f55dbcee3164a70f607dc8a08c937aa74f8fc1c34c38363334bb997c0ebf329a66a439897abb5a3e8e3827cad69a0b785a577d19e2a5fd1ec7ea8b99d374d89e7d76e71cf6c63dcfee658c65accba084f49244904b8473f29931c9069fec546605fc2642b0e74c3cb4836a98eb4ae0b1cd120191735380ded22f394208471215784827ae7cd0c11b9e52403a2875269bc8e8f62da6ed372f9aafce9763a9babf411586f77794856c1d9f54de8d9345f14d48d2f23085a02f019bcfdb3197683b12c06585118bf5cc25b10ef6d4509c5070ca5740e6920c5acfc91183725a0a1ec56cdb09ce71514f23925cd514754952664888890133fb83256f189d668efcebc63313a29e5a8c11f0aeb54e143925942e8ac4cbf3384cb2206ee431c5b3a8bdd8a4fc24ae31238d28c5529ec948ecb5689311331b2374e1b297c8c210b4cec2baaae6336c3baa52392a53d6c1503f5822d84641d3cff24ddf27fcd390adeb2eee2954b67c4c492419d1892b8f0b82c1c0f20711", "b5122c7e72cbf035d2b9ad848064be91425549493697bc84497ee373f0071c02b6d3616d5aa0e9909ec7f759fe1c62248d55f56875822e76e3d3e967210e41db7aa72ae48fb959063d1f513a1cd5a3fd572dffa6df4534ceb0c3dcbd2ae16594cb2c6d56e185f66604f34005198a927586c2f8e7c4836f0245a244000b3cf479681498a5c38ec773d06fbba513d0214997c480802fb3c931d68e235c993d79b932e612a25785bc6ebfc93da301b310891d817412f1ea07a4dab97cf2d1037b3a50a7ce87a959fcdf4f9431629ec475294463f6814734f1052cb59828878f0051b22abf06a582a4bdc35da481fb541c7b120acf4655b0d418cb4fd1a6ed588d9738ff8a65538461f07d7b6a0f5fc0d45e61c6f3d0184a13dd9982d1a11afe9f4011615b8c47a7398848bcd839d600837cb00a2480e10b2dda10e1bb0578e0335cb43f32130ec363bd133ebff31622808d352dbc2cee882a6e583d2ea7aea2a35c6b2853c406256ba9602ffd32ddb6420120d123b7c63df8ad753775940815df6a03815706a2a497a16279e151df31abdec7ad00d51b570f6edbf64b66c252cf0de21c733de3ab6ede7625091472c88a33859499e1b4cf6ec8826f6a545df67d8fd2c271c66d6e090491fe73390833da2a75c6784bc6ed761dd6abedd129d15e2629ce2d853d927816f7b1f08e8d526b855b594e00cb4bb96f499596ffa132a5d5", "-1888f43ede40db4af02713e9bac46264d3ffed0d13d9039a7b850736eba9229d4bf99f6565420c1072c4a6f6512af2a28c40e16a5549d6db4f0080f80bb236c82422e35e0105c7674426c511dd0feef779eeab1f813be775f999945407bf946cdc89857948e55edc5a64c1176f8ff6ae3caa70e95d75cd55e20188fef997ebd88582c676ac4a1fc81439fa421e72645b665fd970cf36009149faa8b549adb7f5e6addc6f22ca22f2b10a0b089b0ed6ffa2c619d463b1dfda041f717a76abfe206e01d168e16f71457c1f58c4214d8e0c4d9db8b158cf649f7fe9f7a392fcbbc166a64b140c50dbb72371501bf557f63861238309a12d697fe004f0f520468c05c5ac0986815528ae753457f9e778acafe4f632b479f7d3a3710dab055215a9126a74245cacf76af0e5131d7a94eafc8538759f14c36bd8fb834e75142b97606a83b991e40d2793e1e1a757b803621b0823a1c660c8d71b7783ec92573dd84c1b84964769365c5a25edd5f314184966f7525fd268a2ab9bd860c22c41a1cd56e1024d5b837d357f03fbeae46618fe983c295274c32aa85a20c7bd25d293c80a41eee4268bc33c8aacb07160569a238e0ed76376548c0a1c29b9267d9ef5636c5cb79efce4bad640428149a4764d88f3f7098acdf98dc32247155bae7906f917e455fe3b375e6a7b436704055f9f2916cedf0d04dcb17a3043ba8a143de0409ec4", .Okay}, + {.Sub, "828ea4264a145e6f66fc997cfe7e11246fd7ad69607fb00675eb9d007ab4c74b66d79433e890b6aa2a71e7f22fe580955e003d41f8227bd0d22108ee3beb6b990dc2ad8aedae9d26878013fffbd427da959f3b60e4a053cb38a92ea97fa7b9e7e683622f2b61f4a1631eff536b9f690b9e9b4374e9d4b3a75ff86bf0a6b389acaf16facd68ceafca82271f7caaeb414bf8f413986e507d07f111c8325b043a6e724e11a6898b27ee6df830fa7415a3b5e76c20192ddddd682d086f3b5ecf335e3ab69a61a90330a73dfaa708b98b739b32ead17aafac16fee81177f57ec21f1f36adb023a0629ac83eeee56af9562fa983294e42c73427b2c9528336d3c48f8c6bd3e11a922cf6045349c9ca30f32a01d582c59baacc2ba5485bcadbc79993bc344a786a60c217bc61ea31fed7ad64c2947680932eabcee5d6fa62dd4b1ede271746647496cd0d14ad30c352fa23f1c497c83a38c3de92360543c05cd9aef0b0d63efc43e43b29a7b4b25c04ac0aebda2eb36364af854c5d957c974dde4f1873516fcd66400b69578865044d99233890700c10be463a3648a4823d369618f2849d8609827ef5b5aef82112c4b848eda98c0f7cf1389bcca5e71b0745c904b273a8c231491de9bf558c47a813621c63932f66f9a630561187a10141765aef4f46b25a5d46dce465cd9b2d7f63f0294e19e990b866a446bc0988a6c78b8eb23d16", "72af3eb8e625494dda65a6463e046ff5c49101a14adf39911d1833fbc41fe4563ec2b2dac203c37a5ef7cbff3acc9d1f5caf881432bb3b4fb27220d752800b87c5deb9eed4e9cab271809e0d7e2d8d13af96b316a4f0c4eaadebf5a3d6540fdb3758502f5a1df8b78ec9d39e281d394789f1d549a126bd55a8f9f461642157682d6f71a62b713461d8389c311c6c18bf5f82fa29de0772e8ee64e043abf8e2f5f54e6f73df683920471bed9427fefd687c11170730bd39edbe6347d84632b8421ac94afb06ee9193e208349165168a4d3b51384ce53410f647491be8a35a317d4c9b6ed65b10767852f0ae16a447a9ad7361da637450f9f700cc10196b2d65b46d7a26036942499c88b8c15ed65013b041e111032be11999ebcb2c9016a8127b7366d7b51ddd244ca434693ce36c397f5bf0b7901c12312b99b1234d6c3ea16864933c11e75223310871f1f14663089c7d2fa823e81d889b7fdcfe8d7df8d59d4a15d7d013862bb821879193ea7b0fc53811e00e0eea2d7b346e67c1c67d993ba42752b8416ae5c374183d704cbda18ee59bc0d8256fb1aa4dc96724ebb7f40c3e6b91246f161d5ba291449f72c01abd361cf0b44a7c7036aeef5d838d1294c849f3146976aab40d11af4c3f70c29e9aa52b24a6124f290411fbaf6a80856def51527c9117f0aa83d880e3d9e7fbfa6561f08c9bfcee2796b04249426a509475", "fdf656d63ef15218c96f336c079a12eab46abc815a0767558d36904b694e2f52814e159268cf32fcb7a1bf2f518e3760150b52dc56740811faee816e96b601147e3f39c18c4d27415ff75f27da69ac6e608884a3faf8ee08abd3905a953aa0caf2b11ffd143fbe9d4552bb543822fc414a96e2b48adf651b6fe778f4292324481a789273d5d7b68a9ee834b8e7f288c9971196e90490a1f02ace7eeaf0b57787cffa232aa22eece26dc43664c16a64d6b5b0911fd20a37a6ea52763189c7b1c1fed4f66a2149f135bf272775474e94df799992dca780608a0c85c0cdb67eda1ea12414d4552244febfe3754550e85fc0fc773df52e32dbbc886731d689729d7fe59bb1728eaac67ca91086b5aa3165193a1b4987eeb120b5c909e4bb0f18140c0e3a0b542e4f36fbdb5c8c1f4412b433885c90312999dba3d493f8fdee03cbeb2b32862af7ae9e3a4bed161b3c0e9281a989214dbc1099a8566c1cf5bb61b138c292473d0b4fdef932aca70c18fdc14f6a18356a09b1ee2610e2f8c17d17f37ad487aadfea08394144cc6dd4c6597018a704fe620ca849e56b8d611aa60fe785f1a785e0fdf9853558fce254588d2ec55f28c3cee1f5c6f382ba9c23bf21dab5ecf1cdfa73f0b487a985bd3f159c4f88a3bd5001e06e8838f05920bda69e1576107e0b5c4f3bb49c2ac9b8a082d53b487a02bcaa7589472d8647e492461a8a1", .Okay}, + {.Sub, "-aec09533ae110d961697181a9d498b519a47788a06d4a6192e794fb2d098d05f075255a8c8f250642c25075c230fa15ff0287b306fee785928429e087da11f142cd209d621e9a6fc549107d086f65fd638fbc25e8da8c7f568998e570858bb4d3c02a28449541d3c952ad112962e191196e34a0afd329b770daa2d0920a90cec0a39623e8271c31b857c47752962a6d60a8a90c417ceb182beb544d344c3e92ebef48e396b72e4faff86a03bfaaf85db3423d6a6b2ee1e66914144b05e8899f888e3d16cbed8d759d1cbaac8d96d1c7000465f736450845ff02e7a5cf8736964909d75012b64b022ad34f6f5ae4ae8892d7348ff33f7c0d9a9e45a9d7a86e412117e478a3fb7f4e0db0f0c5e40e880d5ee2cdb85bf531a7a3997c2b97592b1091a3cd8f663aa29f43f3b599c9eeb7a94c0b6b864c330b19cefdeafb6b3e76657fd4d65996a2cee4f3c6748f35243dfb29cc94273f48d6970a2a1f2e71d3d313eb8de4063f5ae4f96d1c9495ed7cdbd26a5f6263e5f8bd6f75fdaa72af3c46ddc980b000c31c59c36a258ea7347b0eb121cc6b3c75f4f8e03ae58e38046798bb4b88508cdcaf444071be3b36610e5c9fad0c97649e880867b6a91d08db8f3a350a881bb506dcc4b28c09e3c22ef2335f8145802eff94a885f913129957105d3d9e916783b4a1954b41e1727c1efa3ddff25109d88562e84ddafea0a033e98120e", "fc8940875521288ff66987b7d31e74c726472332263128562d9d4d6eb76bbd082ab44ae1b3451cb39670df614fd9c524b99e32732737e014da74f2ed88e7f4515102e7512df6fca1f52339b6b50c625816e03ecf2fb3bdbb9d1bd4d5eb3922fcc9f162ecee53503908861d89a060060d1f3791f321108d5cefaf4c397ed696debd3826748320c8a70ac421365c7ce49533e8954528a144461020c3ae894c31a780ce497413485fbde2c40262b64bd5c23d1159600fc0e32e0c939b8f66afd58f9502268f03d56f63301f15317357dced1f1666116ba646dffd7fe3121abe901af1b8ec6e1d1c0155d6481554e56171da74ca60cac334180fedd0b8c82156ab84d96d10555543b87d671f33369d8305e49da463b15f4d161b019abc4ff35e41cea3c08704f7036581576d3d7b6b20c0b018a1ac8365c054edb7d8bdc58130ea5e1f4588411969e3056a1ca11b481bb13750b18b12975c8cb7759b7e7e2446e5cbb96c4f4c18793017cb3091b2141dc7e53fe770cfaef25c226e92f3f1c5622b820a3afe93304551cd3ad046d8f8f3d3dd334271de0cbbc71adea99bcdae27255c81fbdb519beee4cfa7e31a733e734b435d16416f9597ceac9e11f57becff1a19bde94d485e1250c2baca8ed05826005c925da543f93570539514c78639d5f4cf04bc69c13c03e8369204903ac22eb6f2a03a94f4c2b080f625f144eb071d6a08", "-1ab49d5bb033236260d009fd270680018c08e9bbc2d05ce6f5c169d2188048d673206a08a7c376d17c295e6bd72e96684a9c6ada39726586e02b790f6068913657dd4f1274fe0a39e49b441873c02c22e4fdc012dbd5c85b105b5632cf391de4a05f4057137a76d759db0ee9c368e1f1eb61adbfe1e4328d3fd5979429f7fa3cac77188b305928bc2904068ab85df8b6b3e732609406ff5c8ced60881ce101ad63fc2d7ad7ebb44b8e24aa29eb0fb5b9d71353006c2af01949dd4e03fc5386f881de5f7fbc2ae46bd01eabffa4cc4f95d1f5cc584cff6cb3fedae5d6f1331f97f8256616f4880b178837d0c4a93ac5a63a23da9c9f72bd8e997b513659bdd8f96eaeb57df94fbad5e422e3f94de6b86ba8bd13f371ea030953b327f0968f0f2d7bdfd5ffb5aad8f7596a897180a0c3b44d95864e828f1068aa7b76d7c351850b61c92edda8396d154a683ea0e9a5f90e9ed7acd868be9f628183d71654184170a724a8fb00e277fae9cf9db10ebeb850be5dd970e0e7e3319ce6d9b1cb926995ea245fe9f620aee03dd29314c40a4beef500925a56c0b551e8d027f4df4a0b1113a80e41f66e328d6c3c6cdd94f59153e2ddfb7b97e18552808a3c609a5f2bd6a666b0898cbde9beb7b68caf347493654a6b5a833f27ff8b32645f11baadbc8a8edd2e1fc861d3ceab01bb7fcb1d294f1c54b327d18df05d3d5db4eee45b57c16", .Okay}, + {.Sub, "-a6bd6492ddc201cb5330e2a6c64dae63a30140fc607b8b7b7f3ae1440fbd0224c72e39d2ba686e9e17eeb1ec19b910aaa373b59b1da77191489e0a7f814020be94128b15d74d62efc5a771adcf76403f263c8ec0d32090dba8847423b1a4692f38c31aac9f02949c2d2d2e2e021cb5b37aa1ecf52518a4dfe693911ab951f37c416ca07478e6307b6f3f6dacfd9e8163494543ef5a2022a225a09c10a3393ff88554a7c7cbaae04a5feb51cbc4637ee5ede0ce2cc1e0a09dec52f59e7c24496de6f69fd2fa10b0ad48c1d542382b3238877f5a2ad280c782b5d7cb59c686ebe84ef3ad0e6bc0d056d2f924add5811896661d1855f67d46372cffabc3a3c7b665d55d47b72de426e6759d0c82a6fc8ae9e4c4e80806ba82a3dbc3d1ecfa4ae6b5d0be759b50a4e795419e38602b1cf3822ae3a933dbeb4e259de773752c9a04fa49e07637259a8bf207a7104604d4b9aea1b6496243c8f388007d52ab9c68279da9a93b3f017932305cbf4c9dcaa927cffd64a8062a7ea3feb8d2e2e459d889b1ae7dd4eff38e67f1619f8286c09856e32352d4b973a80dfafc9039c4c6c0000a67534714fc45fc57de59fb266fb0cbf5dd11d96366e2af7df7e5b0d9dcb3f9a03ae649c87c8090b48d3775bc08857f8408b8fda4a7ae1dafe9a9715ce8c4b0b234300f8b6a7d0b759e55b4dd48da026c242ff5ea1a8f7313ce11eb7103a6ab2b", "d6341ac96a35e648f960fdab63ed9d90c4cb4974ff7db15cce3be79376715bd91c116444551af72a7782fda9f6bf2e369211bd89d6044ebeea3bf8bbd6ad4f3778f7b73e736c1639c468f6f89779f5f76d72fbe9c4ebd8be40edb28103cb70715e82b9e95d046ff0db0153a8d8e4b0741f5a0aed29b54251dd7552315886f2a36e0964ed82b8d41156ade1cc2e8ccc4d081da9014f69f61ace56f208b3f47228d9b401fc19ad5c475f23d48cde4a0bd650b2f5a64a014c47203eded96d6758e138a3d274c14cd87c7b95da8f5cc05a7ad3883b5e3fb8d6af7c16198133111a23ddfccade6e2c8aaf90382dd3b2d57ea66d6ff7a6a614f5ab2d844f5c3bc4e88a23f8c4bde8a5a38e997ebd3c7197b3f54cc4b5d0c4f7be941e84e51858d39c4dd6ceafce2efb23e12ace16f39f6eebf00dea8ebac2c8a0035c37d87ab2dbfed74141dc2eeca608271a80c43f97c6ba119d957194e4808bf072601848955b60ef1b53a9084b0a90d8832074b56fb4b98f8d42c601b9f399eae9ed8e5150ed0b6caaaa7dd78efd7ba65045024c8b4e22b9be57331a92fb7bcf6cd3072e603b923110c944dd980594223de0c081bbebacbe57ba2966c7be4d34758debf36a65ed5976378c1bd44c05ab5e9993dff217e6fab6d4f2b11ff464f3b4514efc5b2ccf01cc286f98c5214265d8e70269a1314919cdd8f956767ea05f0fd1c4992946bfe4", "-17cf17f5c47f7e8144c91e0522a3b4bf467cc8a715ff93cd84d76c8d7862e5dfde33f9e170f8365c88f71af9610783ee135857324f3abc05032da033b57ed6ff60d0a42544ab979298a1068a666f0363693af8aaa980c6999e97226a4b56fd9a09745d495fc07048d082e81d6db01662799fbf7e24ecde731c408e34c11d8e61faf760561fb9f048cc5ed4f792c2b4db05162ecf0a98a18bcf3f78e19572db2215f08a9c3e5583c91bf0f2658a2ad8abc3e93c3d30be1ece50c91d477e98ba24f1f9a7247bb5d8929c457afd194eb8cb35b07958912399e3231ede4daf998060c2cf077ecd9ed5b06633152818856973cd38d0ffc9c923be25a83fb1fdf8c9eeff9560c751689ca750f1bc9bf18943edf31899dd8cbb24137fa48b705531e8303a78d25697fa00b766c6c4f53ca8bdf7238ce37ee9eb3ee28fa1f4befdf7603d18b225266124094192227d4859c9b73c03f4bbaf728497f7872dd6af431c3888cc4fce4474c83c308dfdfc1533a5de15f8aa76e07e4723de9a2c07135aac5951e592852c7828be397b1e484d34be6799ce1aa07d406a389ca696340f326fb923b781c8bf2944b907a1c3abba82b9c78b434cc02ca2ea0fcb26d739ccd4719e6f9b11dd5e450cc965febd1099bfa9d667ebf8df055c7a282a39dfac05943f17fb400587f242f9e4ddb773cb746ea0b4b85f208ef40910e1372dde3b00a2ced6b0f", .Okay}, + {.Sub, "-daf3fbb135c60765878cf59daa988ea3b544778c9fac59999c347ac076c6f7e5ad832c9ea1e9e2093210d53d71a9f180d674e436de2e6f1df66a69c22589308847434379ba7613bd69cc9bae42eb1a05074ebf9d048ca394515e7652679c5d57dd2895e669b9e8c303f753c301ddf80cc1a95d8bedd7abac9339f59be30424b7074f449d3dfe4c85bd7c773dc90077dec8db1ff6c5cfc76ac8e349828d659b8e87187c9f195f33774b4fc4b993b691bbed2bca58d00b2f40fd280b5d12e465e9f9ae65c14e46020a8f5da2e83b8a1e010f6d635eec2317404f0a27f80fb692b5d203398b650a71b39e762809108b4347e7376645bde1e85f5218823e74286dcd54f859928a7bbe13c94715205e8715f029a87a5e7f6be971d6c2a1b2ab88dad02467b15f4c998126ab908f294a13087db0bac560dd1524b39733fbc4d210541dece54a75aa23a0f5a73369e411c4c870be6adebc7d58ef276abdab14b0dfb74848edb82dc695f638a672290768840e31fb2d5fcbe25b4ac2f9b42eb90a7490cfec9cf638ad649531fe79e5175120348fd77b4ea78f6c1f863c9bdc3517970565c67a9510cc5c5ff5c87f51a5c55652a036e8954fa995ccd0e5cb794553f15eb55f77f254408e0e7e5e1679eb97539d47f2ad5b4df8aa83de1ab20d1d35df292d441529b2ca9439dcd40bad10d0b8a6b1d5f7f7af96caaf4ae859f1942eb4cdf0", "2885de29fe5a305b0f8fc7002111dd5a3a026e8165f4ace1eae37300c9132e43d2efd19a1497a39b36a1402c253e736a85d61b6ae3ee8ad056f8983d69f65904edfc5cda5e12757964da014211a438b17194e2bfb3a2fddbcb4623a8e302c16ba1e5c9bc7ad54ca8db6b6dfd06028c65ea820e2368d3f64e4bd208e1eee65de86a0e4124fe8e37a55e94228e78f9713afe5b3c5a29d10847ff4cb31148c5b336a8fa8104c9d209a449cc04f6d5b4ff872d0ce41b14b7db37a30a18fac6bc9adafadfe79b3a4af569b1e5f6f0216f52d6fe7a20acc51c00256db332382d171f191b4096e04747785c1cc1de8a85a4bdec3715b7faadeab401e364b49c90f97c4930744f1bfadaa63590d240ba1249c1ae47e4bf5f8ac6f6c49d6eb93c3ee5508372aca97d21572052d7d03fd58ad95ebf44e902d2a8d47d8b986dcb790832382f31f62d8a13f7c9bd2b02ddc8929a7bbcfaaf97bc3f9065e847b144554a37b0f5fa1f8556fdd3891cf284190e833d84510fe2004212d527b3d4d061fd34e82499c8df74e2d1a6569eb19eb92ba2c7bef33e171d0f7224b866e715140742098e3a651e608c2b5de5c365ac5f90ef6e1375ed611bab0602ead9469e562c60787c3d04ca7de91379f42709037db906ef2fbef92d4bf449ac98569299434c7761df44933581fa53db85805c3102682c6ea4caca2df8414c4167df2a5fd14c01b6da6a", "-10379d9db342037c0971cbc9dcbaa6bfdef46e60e05a1067b8717edc13fda26298072fe38b68185a468b2156996e864eb5c4affa1c21cf9ee4d6301ff8f7f898d353fa05418888936cea69cf0548f52b678e3a25cb82fa1701ca499fb4a9f1ec37f0e5fa2e48f356bdf62c1c007e08472ac2b6baf56aba1fadf0bfe7dd1ea829f715d85c23c8c842b1c1099cc41f9e919c7365c50efa0cfb2c82ffc93d62b4ec53012fda3e3313d1b951bc9b0696b91431a38ae73e4c30a78a0322457d9a100c4f48e4d5c8890f774414399d85cf970d80de7840bb13f1765bcbd5a303ccdb1ceed43d06bac51ea0fbb380693963001341e4d1e406bcc9c61357d36db0521ea16856ca8ae855664495a1955da70d0d79e718d39be0a32e03674315aeeea6e2b5397145adc6df0a1798360cefed4ec673cf5a3c83385e9a23f2fa1c73dda428c4d1edb77ffbe1b6ab2d23647aca45f442db91a7678bce9550fb26eef69fb17683e430d3d84c4697f5598f64215ebc192830b0f600df5307276ce8490b63f5cb569b57c6b1b7f0aebd0b0189e42f3e7f38315926bb70190d7ed23b0f03c59a093a02b98f59cf7ba45b92e2bb136b4c466162449b0faaf98b7aa2c69cf71b469daf26442703d540802a56719f7a49e42cd06ebdaa74242571c34ad4b5069ad410871d74aabad1e6fbf5d303caf78fd274b7ca025eff0e30c172a12b9c2e0306ba85a", .Okay}, + {.Sub, "-e6f61d98e19955f458c29fa62230a4f83884a7d4532cf88fbdd47aa3188aa23ea842f9fc56b0e5e3d12929ac17e371c850a2f480a966d850996ce5ac9dd2367f9de862311b137e9c2fcdc050c964ac1fe60eedb701b3de2a65159558224f631e171267a8df3a847d97a9fb1c5c513f5cbf9fc96a1c57ac53dfed35fa0328370e75c348157a6fd5eb4d359599e6f9c1587d9406d28ac41bc36a4f3516472ae5b9740915717136d90cb77df32f2c0e4f9c095a6c8581fc34b3246719cf8dcf22c7b64cae675c37a964240b175253a44f4de1ea7eb0f81d79faeaf25dc5d88089834f37dd3fd6681830ef2126e0532243deff0101ca482f80477ce6e62ddc1c9d04e24ed502522ff288651401e92c0bb20edfa2fd193c6910ca55f927a31c560c71d11c02e6015e396ad77c2dc668499c40feec365ea967c0674df1a35fe2d0016cfcbd5a7faeeb531487f5440ca38938fc6620fc328a4b10529b9fd5a4c90f51773d0aa5f9fa5f656106b317d95d80a25446518d8a116df8728904f49c8a47e756c990ab2bd5e50ed0a7cd59a5daf74774863cc2c9d6dfb7bc494f49970587f395c2d12c82e2994d75e0e00a0850f0faa8f9d722c32b9acdb216f799b555bd1ae65180d583e9cc4e2f77e87601a6f1ee924f7a456c207fdae0b7839670673abbf9ede41b6ed4b2cc9e3a7872f11e50c64506ba93b1d3eb220e4c5735e3fcf73a93", "f023e5c1d94fe2655ef35b1b5ff2692bea9c149e21b9266e474c3b274b8cf5acfe1480694335a5e14a0a85c7180f9ecdf64a135b36f42b340492c911e0ee57195dcae167058012c33435d6b5dee2a5eb5bde16bf59a1387b8cc3a6c3948aba85895d2780971dc06753135466c343e85ae0cdcfba5d019f20e913388cf5b75179aea7075e1ad1140a89acd0f18ca49203fe9be56ce4e3978af7a0432fcef5d728ba58c4bf955fedd3b185664a8cac49aa16dcdc8e6ebf60f6d045280647afead9e02301489cf01b7e8a095a206a390ae25ab43a2f9ed4ddb015eaf34bd3e72e42e3f544c09b58cdfbe7573e7a7419520bae36585d0099b8cda477999d34b02151e01203b00c1a66d35b0e0b40e14201854f5ed03f30cd9a3dd66469dc93caef0603996f3ec7f7cc8a93fc508cfc263bb93e5983a437f3bd4026ce21a8d5110511066d10481d3326f3f1e8fe377a9cfba425a5a638274e81cfcc1fd770001da8659757ca7fdc982d9a88c0226f5da79fa8c9bd5cab399e3fc55977acd57edfa66592d87388c8db8fce2b1c7904a49949bf592b5a3d5f1d3de9b8a0d3ff37fb3def9982d6a67e0aa159bda812ff3b21ac8ed44bf6033523d46807dfec304c5af811d7d08a693cd681fc358a63c76c6b17bb7538c0ae863f2d2cee366c9d14be6b8fec3bfb1af4c37cc379aca5851514a932b0489b594ed8115243bacc58b63392fb", "-1d71a035abae93859b7b5fac182230e242320bc7274e61efe0520b5ca641797eba6577a6599e68bc51b33af732ff3109646ed07dbe05b03849dffaebe7ec08d98fbb343982093915f64039706a847520b41ed04765b5516a5f1d93c1bb6da1da3a06f8f29765844e4eabd4f831f9527b7a06d992479594b74c9006e86f8df8888246a4f739540e9f5d6e2668b739e535c7c2fec3f6fa7b34e61ef78461620bce22e61da310696c6e069035979b8ba994620374913f0bb95a9f4ac41d5d57f0da1966fafaff927c4e2ae147172bddd5a303c9eb8e096f257ab00dd5111ac67b7c6332d220071c0e62cd678655ac73b95eaad375a2748c93915215e7fcb10ccbe56c260d8b25e4a595bc0220d2a0d4db3942f01cd586d36ab082c5d917fb020fb77d4b57224c95605f56b787e53646fd7fa3d45ba02e15b7da774bfc508b7e1067e032a6ac7cc1e7a0879de42441e2634a08bc6a26ab199922267bfad14c92cf9dcd4627079d6f792fb8f733a48bb2841fd100eea354b0c3837e27ca17209278dbc5c691eb49ec09e9ed2e9d2aa7f909133df681d0735fcf5a601f01d963d8331855c54032960a3eecf9e881d078c12a737ce2318c660bea21a1ed785e5a21812f829515fed26a2d02bad72d9c9135d064dc4b3061aa6bf080da5ba030d7bf92789da201689c9764961b425187633656f77b7032f0b22c333609012023cb32acd8e", .Okay}, + {.Sub, "-7c9c4c10642c1af65f6dd1b8257ac40ff3eaa62e3dcc06ed26035aa8110992f5dfca7f2b723bb21fed636266564098ec54a7f19405bbba2c63fa5b3160017e6691e8bcf5683365c57c184e0785f1b3193c4d855bc7f134ca4153d2f281dd5c1bdbed503cc2357c6258798e9fd0fc4c24bd16f06d3902ad5567b7853e4faaa3c4b787fbed582eccb47f93196709a0805c55e22743835a972ed71775a660b32fecd9aedb1f4df42fd2039a0a7beed0cbde3e663f179329ed3001d9b22b77b40ba8fe340b9c3338a61bf693a8b85839672c9c685d00bad6e1a47bc5a7eda3f361da2d2a3880b09c89768c569a842ace484a7faab44199d24245f9ca1fd62c2c151cded9d670267129c0a4d04efecb7326398202c690abd54ca1c7e11cdeecdec3230f6c7077c55bcae6da9eba8a7dc8cdbc8765e035c2ff1bb995ddf0f524dd6e2248dac8e0ee6ad87a9c4388f94b251324f53f0b894cb965976371c5a696b2aa5005ce3a411e41bdb9d5ee234ed8849e192ef01f79a9f83305be31e5a85a9a7ccc3702605934fee7158f30b2e26b35d4f373628f4ec08a248b21afd07e0dbfd96036893e6dbc5a23a361ca229f42ebc0a1cc6c2ac644fb30f696ea6c72401df1afd34f83168c220396f4f4e6f86189416756fe16c477556a81f7895daeada8e41d4b9b85f114b3cdd714ef5890890d580ba62ae4cadf896910f1dff377bccf636e", "cca579b06f8ee6e88b935ebdbd326b86f486823e9c8cde17d3ef85aa0ebb0410c87a9140128dce8e097b2d5758637f9626db379c0dac1c9c42fb2de76b497a0cfc79e86bab5df041dbb046903b7bfea514437548af2461943ae86502948d1b5a863b53dcc049b9b3ee16b5a98f4dbeb775372f08fd1416d50028c653f4369629e602438d5aee0385a5419148ea75015ae425d7c0e18d8ac6b1b1c5bb859c36e3bf9a79b7e97bfd436bd83ef185756d15120cef3abb1ee3567cbe150f62d75a3497879c58a38e9dddf8acb12740279d9ede983bf6227270e570fb4722cd4b33f3fc71dcd721b430f2c0851e13b7f68a0cca95984bb25e6269e3195d57318ddd5ea3eebe0e85c518b16a11034f7d395a0a20b7d679ab43ccc6e004fa866a8c65faa9f11d23b3c7870fcb6e72c24d5b0844b8468d60aaf0eb5b0a5f624e3e565c68f83d574e51055bc8e9d5aaefa6120963332b2f5bbbcb2f52b27a9eb70af5f886d5c6dce7bae3eb784850e785277b33e56b959eb6771ead06bd2c97c4ed43fcd3d94ae1c9293ed228c820fdf68afb6c193804a16680a75589b82a04a9d960ed7e5dc700f312b4817d824c73b54d9aa877a23b97d01bc1ff8627c2ea8d16517061529a4acdf5e96f3329c018d6d253dbd89063cf61873e10a3b9055373fa34112129a24dc23cf6d0148e2cacee1cbed59ed7b523d6a484734f26fdd74fa210a241", "-14941c5c0d3bb01deeb013075e2ad2f96e871286cda58e504f9f2e0521fc49706a845106b84c980adf6de8fbdaea418827b8329301367d6c8a6f58918cb4af8738e62a5611391560757c89497c16db1be5090faa47715965e7c3c37f5166a77766228a419827f361646904449604a0adc324e1f763616c42a67e04b9243e139ee9d8a3f7ab31cd03a24d4aaaff41581b73a07ff0464e821f588c93b61e64f66d0994954d737702d156f72496d744638f350732e524e48d0867e97c73ada8b65dd95bba7f4d6c743f9ef4059df986104cb7b0098f6dd495289ecc0ef10713e95ce299c1557d250ba694cdbb897e2c4d2574a404c8d4c30a4afdce37d2d5db9f27b82c8947eac3642720ee1524e48ac8043a2ba9d0a57191968a7e61765576b291db95d8d9b792351f6a60d2d4ccb23d6013fac6d966df00714a03d53436333ca8b4118202f3f703443861933e8f1371c88286a3ae5088494ea15ec645da1a8a2d6db951728d925a9321e3f0ad3ffffd1fe9a85be302116e00c7b5e7d6d47de79a0104d42225e3db93e5751b0d8f631410cab6730b541317a14d9d9d527e720c6de94503f60cf0ea520e4169654908669196ea7c29660bd307cbead56ff566f621125e9cde4820b72ca1eb4ffcf33dd1d3fe761e625fe937b25b08eb122a7dcf53e753dd3b351aa9deba31c057ea5cc2daa7de008a1840ddc6018ddcac75ee005af", .Okay}, + {.Sub, "f19d95b84f1131a7503860a49daf9b571986490349c764a0fd10f34bee4e0a5a8ea7da5032f74be491bd3a4372f5d20600f36240210b403d097950515e2f54e4f854a19ce0da582b09820904855631bba0dc125fe8de62ea387e4f5870ac953fa15bbe0a0d60a2c89a28740d67721a9d5a2d27bc5976b4520703c6d20bbf1e139449b261bd757da265d867b29df8352d7673e6f4765bcb7abae8e00dca4b436f98917a912c6acf071f0fc464dbb5f3dc4ba37f82c5cf0cd2c3652b3a7bf1d0505c8a1a0bcd4952b0c2f17aa03e241ddffd8e37a117ef75135fa271b210730c231f51e9905046a86c7fb6186aeea367473df62d8c26991ce64cffeab1b60f0f5864b6d405eb1c44e30ad9f20c9c76a21b2e2b56c94db87dbdbb4431e132a9514257efbcbc94f524de443c583c77352ee122b13bc6a642d4608921a7f7aac9a5aa1caa409f5ba2eab7ada8bace04f26143d9169618e51e49c8cc904c75be317f18ccd36cef61b52ffeba9a0f34d9331535940b6fd387efa045015492e331b6194ad895d5aade04424a4cf35640278cd7e2201e7d5fe64784eb2b4aba1bd448038641414d30deac98f6dec811c67706a49f49d197c48001bb39efbaebf7040cd3286923e9bab46b9e715016b6817851ccd7887ae434061e1e0edeaaf2cb64a881dbfc7121f24cf5d739bf281f9051b54a30a44498832c5d2debf6900b4b67fb5525", "69d01e3d5568f74cae625592749ec4a37f72d558a420dd919944bda48374c7dd1f32682053e84ed6c8f3c807de13e092b609fbb012e9c1fe5363688194f0dbc6a4488c03e2140f8826a171627d055ada7c2f0ab449e5358f3c1af113bcdb9335f7200953cb3e14016d47c2dd3dbee70ae666da7ab44a2e1fd886e0b0a9f04ff58ba92204ba755a3910082fabd9a8fe7a20bb415a9dd16e94f85f992477d9f98d4832706bcde4e9a847dfa629486e60093cc6cbdbc229c1f90feeed3dbd723c452ee5f0fbb40fb1d506cb6c77e06072b88b71f824d259bc0ad926a31b0276049743e669658971bcf82aed3b97b1eacd5f5c66c174ca6b4a037061cac5415101e956c8748eee70f37c8577dfdb31f500d47619133320acb2d54091240ce1b373c68d8834b0734c89364368128aa68b91fd9f25f2e69bff6045ce0e89436fa0da07dbda19c48211b0694c35edac41d9d7020e5f85f70dd635b8b296a7e9c11ee7aa21bbbd7f3f33fbe9d8d845bad835373ed7ca40310ab7b0cfd7a2f95c2215b89bca2748e19bba1f5d31e1a486fb958fdca2b4371be04586d638b5972520c893b8a04bc53cc5d471f5160ce3271fecdc41a4cfa597bda2ae43007a4b04fd53ea01390119de1c5cf22784db62e9b719c5bbdc54cf54707e15061bdfac2786af2b8329e22794ee1cb486a74224da47675c91fc8f7645889794807ca5e14f5044143f", "87cd777af9a83a5aa1d60b122910d6b39a1373aaa5a6870f63cc35a76ad9427d6f75722fdf0efd0dc8c9723b94e1f1734ae966900e217e3eb615e7cfc93e791e540c1598fec648a2e2e097a20850d6e124ad07ab9ef92d5afc635e44b3d10209aa3bb4b642228ec72ce0b13029b3339273c64d41a52c86322e7ce62161cece1e08a0905d0300236955d03806c44f36b355b8a599d88a5ce5c28946e9527149e2505f0a255e85e55ed7301e3b934793d30edcb3a703a54ad9b3763dfcbe7f940b2da429101939a0dbbc260e285dc3ab27721c3f7c4595b908867bce970dfd078bdb6b802ac6d4eb7454c8dcd33cb899e7e18f6c175c2dd2e2dc9e1fec74be0d6f0dee5f76fcab5166856212316a81a146b81243962d0bcae87ab30dd450f5dd7bca67880c21a89ba800d445b1d0a99ce3838b48e00a43741abb131eb43b28cba240d026dad9913a4e6172cd21c3188a41cab71021d748141019f9a48bfd12976eab17af7022813414e1c1c97a00fdddf6bc412fa27d37ef7529b199870fa060af0e6e8cc9424a22ed1b11b1b92bf748057d6a46440601fe14f29522f6b37f6fcda0f587f418d82701c8bb2e9f5719c85da501f22cc25f0cf6ef40a0f206b8e9273022cfdc980eac49cb3b5397c138071bac2614df95a00908c2cb46a3ddf95658d28efa5d5ed922b317e5fab60a4ded9ea7b5223da3c5996b79ea29fc17b740e6", .Okay}, + {.Sub, "9e0803a7ed0578b87d47eed09dbb4b3f469d46ac31791d192c5c06b336dea4dc8372e68eaac51b52b3b9fa846880f7d9e7d3f2cb49fbda64fd8b16fbbea32744c2e66b61002cfe97ea30820dfd91e7029cd589014ed2fc59160d7a9b280584201aa486467a4de279b277f1009a9dfc898ebe8dafb938c4bd08c25e3786d5cdd38a1d061a67fa4a1828306c6f01a0f20d8b07154bee450f162dd64bba26b46c8929a3cc6e7f974371c6e0d072c667bc153e2939aa6d10ba82e4d2dbbafd07e6103c74696a725614c5f7ba39d40b5b319178af5b3ad76c57e4aaee0f1de77f1ccd3b05153f7437ccba3cba01fc88c14d903855e2c0718b218a853088a361e765eb2d93169ce6bfedf1462802cab7e967688f37816a0ba5b00ef16074cae3d5acaf6ede061db0e0879008cda2962b4f2b06f0237113ff21e153ec44ed9e425cdd764384c451e3cf6add4935de8ccfe87a3874ef75acf23caa26165d34adac9dd140529fde4aa15b99f607cf60b7ab7b3ce50d306163658aced4a8f120e401e9d45f56be814759441afdba7e30cbf67e10efb563ace23b8848a2e1233a48606b448f58ad72bf47712ca91474a41cc9098593d9541245a0fcc2ee28f5825953f81bca427094b472f555a74b698b5228ea544d83d9a0c86fe090697416746992fb39b66c0cff6b298539ebc1cc3be8f3aae5fcc7fc6bf535eee49e91a3493a87f9e373", "7de5e44b96461547dc6df9530c1a623d931536680824d63f337802f8e7eafa3f245641d58c2fb855f593720fa00842da48147b1c6ef80bd2dd5df9b99cc940278edc53c29c6e7c3ac010b6085769587687a8ca0151c14cedfc7bffc4926853e0e5b7cb923fe846676afcfa4ce93efc62434c89a2c9a1b6759cfb545ccd2db335b8ba3801155970e9fffeb54f8c4a3768ac2c7621b45c1bc11971ad5c946da536b947502f633b6c4895125b933dfe3c16274b1e6effde11a7a70150a0dbdf8edddbd4ee876ea36fc45abddd8d535523d521a0f435296c1780ef3c9beff6fe03b23396fa75f8836385a0920231dceaff7daadd1594fb98ab05b99cba23832d7ebdef496be5868c4210b36606e5008bf5a342bdab2d776d0f33d781e9e4f215917d6446c85a9e5dee0f5b6c82236fba6263d2e459601f0c0bb204a03db29fb014a210af8dd68cfcf1a1467d916b18ee6ae93ecc96e7256ca813c8c1aac8027d4e0d96d57c01ecaca5b97f006484d02695c96653076d2aedd36093f7bfaa266f06f408320e88d5319d427e626e7a3b0ff652249db6013153a1710ddc355cc16361b224fb35f361d0b9fc3fbfff7af372313e187acf133dbd2bcd9be1c8311ce6f3cba3d7aa556df8764341330fb5537a24357a32730696e7fba44fdfe5ef3e525edf2972bfdb3d1ce96040c5921afe97432e46666e000a4181d05c0d7cf85e27e76", "9629a56333a11763ff810f3b6cf9a51b6d6bf345b0f6cfb539248683a85ff538912d827152021fcd5460c3636e8073ac4352ab19830c59a7cfb5376024d6934249f8a624d66616d43e2f76ad781b517b345afc6139b6e78a3645ba9ededefee20c49098d564f5e133bc8215bcc0a0cc36a89c5158c9ea955aef2a8f1ba02f2a02e91629a56a4b3098830811a08dc4e9700444de9d2ff4d5a1c3f30e45d6d9235be0f576b89638cad3d8faab99287d853dbb487c37d12d9686a62c6b0ef49ed225eb71a81fb6bddc9b20e5bfb3625df5426954bf784d5966c9bfa455ee80f3c9217cba59814af9681e2b0e1d96af29d985da8116721d196da2996bd0129b48dff4e9e7fde8e5729d03af1a25c67e0a80e5b0ba6b7342edf1bb3e8562c94b453979899999806faa8af1316da73f45384e0b2f52b7dfd312098cbfae9c31861dc2c2279cb747aff9bc334ce05761e599389e102ac3e7fe5dfa4d9d11a012c75fc5f7932868a8290cf9a6fdf5a6f5e78d38876cb30ec92dbf19e9fb1a4e95f82e3f0163b605ecbf10129929809e452cd118a9319d18228730e8bd04576f294550e74365dbf60115421095078a42519d2627ff7cc65546d20f0314f3765d64229ac8d88331a0f1c15ce4317565a56d3b2b20a2c367998067210af2f18760a9f1613c87975d36d75b36b55bdbfe2c743c171c9e3960515354acc818be2716b021764fd", .Okay}, + {.Sub, "-18273052654e8656ad92028b3267498fe3abbdf14d849af56cefebf15948fc24796a56ad8b4ddbea91a1fb2269d6fd3647ad13c487ab99ce9ed4453c947aa747fe2ed91853f10e9fa37c642735b55af3599d8a79b71c486c18b7fc7717fc506ea9e460c26ac937d69938e09d9eae6f4ff84e8b1f4e158441a5f2a8c15bb846d7dc46a9f79f911f8a793c5e6517215ef5ab57c42ed7ff41250e6b11356eb6ef8962b9cf867d0dc7486224d6d5b5710973611133689be8ee622cd9662ed743234e4bdabd8d9bb6e7bef622b3bdc14eeacfcc8728e433cc0729d95b3e2387f751f0be80de126f4b1fa16bce640e58d76ac8988de1520142e9b98c35b776a30ef36c7384ebd5ba2c7491906de79a27f6bc4f5003627795589addc6b53972d4f71f02c36326196ff4d8007b174155d08b38fc9884b4891ffe7c6573dc27cad5609f1b1dcd3f7d5c439e0c841237d719050627e0ff2677375fe0609e33b090f0258297535f60cbe37419b2a6e3277b7f90af46272fbae2934cf71684663d64b6ef466724308217e3a52f207627ab0d05de7c7ecac51aa4f29c1ee914f05858c5b39ccdef9e9db6e14420eaef666363d635dcc30a0171eafb949153e02ea2e622325232f3338b119de8220dae095fb8011927d7e8cc85f9f933e422c7331267cc02934840a1b5e75f9a46ea6521313d3160a815e880450a37b2f8b38ff4c428f24a5275", "9c1a75c03190f7b0d7df523d6cfc88468ea52ee26070d563f8cb09344e6b3dd0c74e28efef86eb7ad5fc92ae2651d25ee80df037d92a1d3e726cfa73e241ec6e540f07a34196e0607f89f2afe91ff859b76170770cae581cddaaba4197e0396b6ac9d3348508bc5adcd8d6e3a04a1eea3bd3e2c20cd21467851e3f71322ec14ab360de26cdf15bccee79d8c97c551644b8d0b457caca6700803d5373502f53ec60b2a9252c397aa967c1586cc2fcba147c9b570d14da448dfcf47e7a91a840f5fd27f8a418afa92b3b05bc54862890bda57ec5a6765da747632e0f6b22cd3f654f1b10379e41cb69d6fcbb32e432d6f6ab9fde7bb65418a9cd691819ca9d2cacb570dacdf5db0747d6055388394dd49a8cd022ec9b08692ced73273255f84675e3e9ea280655e07120bf65ebdb38e24c629cf5beac84c480f2bff48cd002ea5f536d8698b336c2f3ca3c7223c054a7b6e25399a5adf10373ae0aabce282f7e64dad7cb57228c62bb2226e6e1d8afdf04cc396207e0ba09b313cc76d6ba0a32f3777e59ebe6ee5ebf31be9cbac9c220ed94280f251a3006c934589aa62a535e81e74c20a0292b34b5de9dc8f3e172d1b78e26d31488a83b23c0c27b3755cdd3c9847914d8ff6c044fbf3ee9d7655723da1a1f0fe314a7d68746bc121c9b2cfade70bfaf4f6fdcfeb02907ef9a852cf98b33327171fb5fa5a5473bc3bdc4cdfd24", "-b441a61296df7e07857154c89f63d1d67250ecd3adf5705965baf525a7b439f540b87f9d7ad4c765679e8dd09028cf952fbb03fc60d5b70d11413fb076bc93b6523de0bb9587ef00230656d71ed5534d10fefaf0c3caa088f662b6b8afdc89da14ae33f6efd1f4317611b7813ef88e3a34226de15ae798a92b10e8328de708228fa7881e6d827b5767b6372e9376753a64287886a2c9a8258ea864a8bee64375c36c78aba94741f1c9e62f42786dc387ddac8a75b0c332f029cde4a968eb64444902b631b46690ea3128701247777b8d7205ee8aaa29ae713c894d8eaac491560d9bee4a0d8ceb0b42cb1f413d0a41bf442dbfcdb7970263599ecf906dac201928f5c6a3b0077bd966733b22614490e9dcd385643061040ab42860a52aef6578a74d1041764ab8719bd6a741abc41b48fb21aa47cc8340e6669c1c57a563897a713ac6160f7a61004e4ea9fad959addec352c01ce550e3d44c3e5c5f185500fc2e372c2306007c6dc90a0e5d58408e4af3691cea740700c99832b43b70f9795a9baedc03ca938ddfa7e647c7cfa09d6c5eed29ca0ccc25b24948f2fef006fb4fd6eabe570a6f55a0ce042c57b7a8ae7a982844ff843ccc77a0f11e1d780025fc77ac9fea9d54265d6d48498f66704bb202eb95dd0ddbbaaa0def2484672f8e26b1616536cf77459a8e2920d7b68da1a11bb2b67c33129e58d73087e6b7184f99", .Okay}, + {.Sub, "57ee4a47ebeaf5f47fdfd7ffa1d63685e46faa97227a1e55f5a023565002dfbcfe122ef534f6e44d4f4aad08bedba38dec05385c01ade5b1dd8406541d851ca3db6232b7dc39544f1354e39af6ababe1c91483ae86761487b4e3dfe33ec79635cff59e62213b918f0fc97b05d589245858c997480df56c79daf921cc46a67347b037b95b14e14dd22a06364df6e0b2d17d03b2b7aeceebbfb42ee1f0890c7835afda5694a38e85338d0f344704f0bb61468447c66225c5dc224bca36f1edbb46bef0f754ce651836452c4d9a77a95b71b4667d3101f938f05a8dad25cdd80138c189b7b83680e7665c01e1726188119e6ce40866d2c41b66e6ac7b1478c4b8809a3d26edf2055605b3273ab976cea2c6e7f13d64cd73fdf44d90afd4cb89b3fd2e5f65b9dc0e2771e386370b69150c31ac5f0399ead4b95cf6a30d2e4dcdef4d277e93214ed1468600f2429c79bbb7c5cd04789a4cd39380e98d5ce3c5dc649429650102ab1505fd18104aab4feab04aba54f495539104c9b3052560e625585fc6de2d5410c004a2be2d4819f1ed0c48a6873ef1875623bc8d37f5d1c536a84a64bdae665e343dd8d4bbafbd064f9bc2b39045826c212ec851813fcb47f44fa7b4220bb49420d30d8bdc73f2da8c018bfa08ea79c5697059fc42e9066e964f673df761e67a28d95c13c0f8af081118b56fd2e24787db207f5f7b1c57b7ff3f71", "5b89a2d4eac56d5acf8d95f56cfdcb392d87f71d45b1ed4fa00b973c62853dbbabad3c0e29b8dd111a21048f89127acf2f5d273082d5978a8eab796b053183edd57e0a8144cac11f9ed4b78e6dce93d9d0f499d40a48294f271725f573cd10c803c5afbd78c07004d4962253dc2b24624c98dc9d218f103bf03609d2d657701758317c0b8533572a4680258e828e54d03d2c3abdb351d1cf7b0bd52e3b55105e522c31b70ac0175ae801a8f1dc0941171fef5924037c2e646f4b9dee95bb136204d0bb1f40da8af4f9464523dec654e1731245c14065d286ce867e4a8aec3ec219e99fab7d1f85186e5bae24ee958bd92affa17d87eeccbeebaeb682dc102fa614f777e9c3d3c15f652f73924608f8efc9cf732f4bad2e329228aa1af1a34d27b4f70482d4ae3b55edf42c913b7e1381dd77cf0c18b01467d91d55bb3e0ef997c241b3566168be7c012339aa0d85251d683b00c10598b23a3e275d804f74bb20ff69cb01d374719e962bc5116b8b47d6b25770a04c2083ff126efd33e7acded42c49b32b8f93f0cd0e1b9ee8615ec795e9318e483ec1845354a79eff37b30df3b24c5c13648f1e1906ed63cb9e7a49d65243f24c3d77baa864cc5b26e9725deb1a4341608d4bc17253e76a3af22250f6ea378dc7a479524c1812b35231edabe6493b3ff9108daf59356f4b0bfca72dc2ce8aa0aa36563344ca4ea252ce520b62", "-39b588cfeda77664fadbdf5cb2794b349184c862337cef9aa6b73e612825dfead9b0d18f4c1f8c3cad65786ca36d7414357eed48127b1d8b1277316e7ac6749fa1bd7c968916cd08b7fd3f37722e7f807e0162583d214c77233461235057a9233d0115b5784de75c4cca74e06a20009f3cf45551399a3c2153ce8068fb0fccfa7f9c2b0705209581c79ef408bada1fec02888060482e60fc6dcf33db2489828a251db22673192275af274aad71885b5d96b115da15668884cffd3b7a3cd581b45dfc3ca727572beb419f789671cf96fbeabc8903e6c999673f8d124bd143d89585fe7f3469e9db21259ccb28d0d7a3abe1b9916b52ab15805023b6e634b77257aba50fbd1ce6b59b20838d8cf3a5628e1de35ca7e39303e4497fa462619992a86979ec8f8a013e40a6df585d26907503118cb722ddb5b0ae27a488cf0410a4a9ac32035129777f60030f70d93c96d579b368826b8c51eb9549a009c8998568cd604c9ff285f6ba17e1b7a661ba0978bf8027c0af88f7f355f69d7d301878674656b85d77ed3ec2a4fee56ce6f71bb4d42aa4f56b76b6096c76fa92d727c65a94d8eadad065ae0403231b40e982aae139eb3acc9d1568be0134b1b5ba17e0e43662135abf92aee64c80af64817964f6af02ea34ddf0fe1f21bcfca4bc3575c7f0b43de129664d5fd21ae525cf496150d5eb7be62ae7b12c56ad385fb1652cbf1", .Okay}, + {.Sub, "-14af623e8566ea4b108e9c4bcf6e2110c87669547f2fd4b3444943a4d6641b0a7535409746b687536df6e3f31517834a5a8aa3c8ebdf793202f1b5024ad44540efdba138f4db7a42f724cf788cb01f442e5cc86c5d25e3853732cc31ab2530030ea31b7fdfcd1db0db6fe360260a83527242e788869af16b0ce9cd1b5ab34a220ed62afa0376595fb1821dc1887d4d478506bdf12f4c898ceb12e429b6d1eff87b8c0bfbe9ecd6d0662f813595c242d30c184cdd763bffc47273cd327d09a975a9ae9bfd6eab8f8c3bae0f3505e29a131a18ef2b87cd107d39c45d6152b7325d8187a133d0bc09e45205999bdc2e8cff35267ae52d871b4cd99fd5d4029f88489dca5b96d5af7c623de57cb00be66ce5cd02c6098a3787bfbd4f70e5a182114be30802496956ef2907ca42ba9600d3d1ad96799dd986adb34d438778e12406814759acad884ae09eeb16e5fa47e0cad6cab91cae7a881918b54d699bd337f95e14f7c85a20eb8a3b21a6de591bac7734c5cf6e6eae7717f2791b787348cbb45fb21d6259e15f04b41ab44f4e53cd5952ef65ab8a0246bd9e2aab1e53f0abe6c5f980f94e6c8b859277e264c2447cc414e636adcf01e304fc548a0712ffa572fa2a7b9666f3bdf8d5296a8126458abfb2ab5040516b3898e51d06790d4e8a03b0e466be5a0876965f6eb359305093b1658b566925edf92f9534a254bafeb36800", "c484f5c742e55057f811b447aa55efb69dc9efb9c2af73626d29f55fe0877a97e745b4f5974d039af4185949647c4ef8c7b17ade43b78de5414a64ebddd471771cc471805b684dcfa2d94fc1b11dcec924b7b8116a7f2494e330e110b8fc424446dbf1cc09ef590c325715beef2bf806d6bcb14b45855d527a661620fee52383214cf7146868682070c4481a34054e490f5c0f7207cbd2793d925a7af443957941cc8303cb30c779a25fce9ab0bdd4d79c6ee9db5160dc05051c9767cfb50d256304b528bd3852dd526bf6c91769ab773221c284e3bed9006d76dd80773d41405f64ebbd5b380678be95cd271aaa0f2ad1cf27d581a5f6f95bcf135c3b3089ad15efd23bb7f7af5bbf57515bb680caef95c7d95c12d25c6b919a67e1bd89f8fc6df0f0c2a54d35a912470b493a9bcad1b613fb20d569ddb7e6ca05e9d60cf63e5fe6601e9148e82004fd379d4f95ec380b3734ee3834245caa13e40ef2ace235661410420ac98469e7261345b09da1ca0523bfa77aeef27d558e7f36a094bf098edf01374b7df564b059fc0cb9387d8f47b7f546d0d47145d9742bcf09837eb3f7c4f05d58f7042c363aa2924d9cda47c0f54fa95720881291a06b93659b6f91d845e877e82eb034297299ae1acbf52bda537c83d178f6b9be0f89aaf735dd4cb7a5f5609a6ecfad465f9a1a42ec8e420b644a58073c9d47d7f041769200cbad", "-d9345805c84c3aa308a0509379c410c76640590e41df4815b1733904b6eb95a25c7af58cde038aee620f3d3c7993d243223c1ea72f970717443c19ee28a8b6b80ca012b95043c81299fe1f3a3dcdee0d5314807dc7a5081a1a63ad4264217247557f0d4be9bc76bd0dc6f91f15367b5948ff98d3cc204ebd874fe33c59986da53023220e6bdec180224665dbbc829b909462cd6337185c0628a53ea4ab158571bd588effb51d9e4a088f4fd0468017aaa88736b8c79cdbc97790649a4cbeb69b0cb351262be3e2698e1a05fe1d4c458a4c3ab1b06b8be97da73b3ae1c9f4739de0ec8cf12bf4105d109b66c2f6d89c2a06f5a2baaf2d1246356ee9303dd011f5b3ba2dd28da72bbdfd3cce0bc26737d562ca9f659d09e42b4ee9d8c75f0c0a4850f8f30c0ea424d21a114e03d09c9ea363aa74beaef08b6b340d8d62b730fcbfa7400ccc1993c8bef0141d979776b70ed5f0519cb2bc3d755f614daac5e4db937b0bd89c2bb50ea508ccf19ecc4a18fecaf32e1629660a6fcea9f7a9e960736940fc63912cdcfa18cb0e4b5b0d05d6e2371da0d0d31b2ee4041f4a22fa2f6579f145e9abc58289beae1d075492199e5ca72bfd7859038d0ee62a72a66540e28c02c17ededbeca90952dd1ad46056b4de85a3bcd53cb18f9edb1602b845bfe0fd9c0cb3baa2e5660cb512f34a93803fa796bab37df535ccdd0c92963190b433ad", .Okay}, + {.Sub, "-48111c5891fe2ba159f91066f45079cc6f9dec9fff837710c8e7e77c24630ee004951fe7c8d8c7feb34ea64973227b3fc1db1593b56b78085d8c77f9ad754249d598efb73104bcb4c89e8e267d4e1c63c5d7852cb5315fb8c7cf1fb003043db74602ee39aa038ddc036535bc80a5251d589e133fce7b3a73fb5ea01b31752e4c0a324c3228cc088ff5e2d6b1a34fce1b0017ed7102289d82a8ad0d3683d18a042ffffe21af33fd9474853571bd1a2103a5f00c3f7f47912ddfb7b6f60d78a269ca8deadceaa5899d536d877887af7ca01013cd960e6d6a5513c5a6f9c3a2b54f01552ab023f3a1d208b9fe3d8c65bdeabfb1b6ddc8f77b09326f66519f4df5b6cb73f83b64bb84ab318048de6d0b2bc21f97c500a375e6441c970862a1483a263ded7a1dc45b59ad66d58f308486fb20224c705ffaa8f853240144e2d943a19e4f6071cbde28a27ef69eaee6d279f5dc2d02661c758c90ef855f29af019f3ec283c425d5d3da8aa94e3cc38f169f3da1c8782c20a303a2e0cc77cfeebf20359061a20bd7a11f553ebf2921f3fed0249a8f47e4d6e41c6736578d41d547766e0b0a2f3c5e3ff7cc77848c6badfb959f9c58c71a1be27f6af17cc426b5904abb89ba7d403ddcc3b851c3cd95f26ecc42e931a92e00ccbca077c7d8104c7c0e559f6152dec0b6f10f11d9e21c625d401579c1a6eabb4d5461463b02ae821e8a56a8", "7a9c83761b4af5b9ec445f988485531d1370c2322f16ce3445d4576f8a8577f94a5ae5b5f397cfcf421b0d290b061c19dc510eee85983f77aa8b8bc43640437a5032c9099d92a4fb390b6899fc0138e36e4647c165ff4589e39764ac020950b9793126185fc9eef116616877e642c039be439ad054ca7d6b4d05e348b2808521d1b0ae305c0849b55204f49b51c09a4b635c02770c8912b7bf2fb840abe8b56d1dc3d68da7db689602444b921dc85ddc79deae845fa5e7072d36b969505c39a06396a7c658b1079c0023dde4e8161ee3c1f81446e921d7d8197b453caa8dfe887073468d1b5d9caa7f09e48b306da4a4ff35ed4dd45114cda64bd8927c293bb002fd7fc8deaf4c8a267749049bdab77f23cc73102c9589a3c3a8ab73682a726620c11153b4b8abfadbfa3db09742fec472eea60707a97a3fc65f3ffa30d9fa5cc9c6cb1df003555e6c307837ff9ebf68b366e2a68d771e6c7d90f1cfcb6394c09ea5d5524ba7b6a192c52441241d468ae3ba83fca7174bcbd6caccf12653d90751bd05f5878b5bf84233e25de7d687de158ed6b72d73c402faa309530a50850c700d67f86d08424876544b4e3d1198d58e340c9fab145fa93d9b410ef9403bbe8181f6821c54df85ee3a2f4de71ce48c7e71d989ac5cf501e1a2425ae71de31e724e7c20d27b083f0371d4a036d1da904d0ed04ba2106c0594c05bc6a6fe5c0e", "-c2ad9fcead49215b463d6fff78d5cce9830eaed22e9a45450ebc3eebaee886d94ef0059dbc7097cdf569b3727e2897599e2c24823b03b780081803bde3b585c425cbb8c0ce9761b001a9f6c0794f5547341dccee1b30a542ab66845c050d8e70bf34145209cd7ccd19c69e3466e7e55716e1ae102345b7df48648363e3f5b36ddbe2fa6284d4524547e7cb4cf51068666373efe80eb1b03a67dcc5772fba3f714dc3d4af570f662a76c98103dae27ee01fcebac3deed78350cee705f5dd4dc0a2e2492a3435691395391655d6fc59b83d20be1dcf78f422d2d40ec366e30b3d771c8713d3f513e7c87c3e2c8bcd3628fbee7a42b9d488fd6d8bb3ee41b773166ce717804436ad13557f791e308e5e34143643810d00b6fe7e03fb3d60972ac8c5eae8b71791405a842cfcce11bc9f9e4953b166702527292ea6084dd0a1d9bfb19273ce9ce2bf7dd62cf271ed218b544e06948c30303af5c02f01b7ecd02d3832269fb281f82414ae101e7d03abc842cac32b01d4a1aeeaca3429cdfe5740e97b35f11cd28aab137015d0451e6a6ac78a4d6bb8e11902b3952304b2851c6f3177a3ca456ad000ebffae0b6fc38a73871e6fb26bb8d93ca9aba5f67c4898af7483bff36bff91897d7b207c54055e92775b01b078a79199579a97a52a7632c38bdd3a15ae1896c1750dd53f1029411f00a0eb5bb06ef64cd4bcfc30a48c588b2b6", .Okay}, + {.Sub, "-55afde63fae34f10b9b707d4c8bd9305f7646c9995fe9454f81aed22689ab65541c5ee6fd69f37b43bb14c043dcb940370e6625160e8e499d9be1996670f85d57db59892cd630a13970a4d93273b0d1dad7e8fbbdca3584cbdfd0c3b42de5ca3ca76af550d391770c4e1b185cc98eddfec8dd9c5b5da19ba2034e5cf1f029b953201004fe536481a17a99a96c2df5552455b90933a2c32e7db5d2108e132cbf457df968170d6aa2c6687150f1b6183f127c2396641baf0f26e4a7f76177b8e3a21ecf7dae2e865f8fe488fa82469b7af940e7f4f9d30cdc375f265948e00d13510e08d08044fe06789fd8951bae77b3a5d86d077fe4a3a74f3451f19875898f67bf2abac98557fa8097d597cd9e46f7aeee3ff7edc092c39f02ea3bb35e6bba37809852efd74220145610174fb8db28b304fb7425bd41827c2564a2f8a0a6906f4671abe8c51e7184d1c118039e7f6f07da1ccfb1b957badfe1e3961e591e752857079a953975fa7cad38e3bedbffbdfd155dcebb29c8cc9598df5f8f2341bce45d4d33f2fffe1d4f08c2d71a2eea5ea2b952ee6a75f2409e2f384a07216536684a53730edec375f19bcaa95cd1de87b0ce20bad53848d87d7368e1f53af52034d1c6deef8bd5339144b6aba3bde7dc6dc2c3899cd8e35975917aeda2b234b600cbd477d74110bd258d251c09a4edacfb0fc09619fa386ad960dfcbb7a80969a", "c20384a69e6519887872e13d48d24d4e18428b6dce4061a04a4f968cd8ead62d06b376214887bd48cd2cfd820009c3a619efc3fe6dd4f1b7124363344278dd94187248d4bcf99d8f686d3b693b6736e616a236fe88f15fca9996c3c2c6ddb638cdc871a047490eb468a7994a30e5c05ac5322fb1196001a16bc8bc0b7a9687a3482638db2e23fd20d76a8f04834801f1fa550b62d52a54e236d60cfdd7079bae4ab9419ab05ba43a565724ffd7429634233d8bd8b56aeb300698e49e66d390a5b8b238976806765ff7e6a2ed9978de6189f9a37ea2f506d625466f099d4d02954cf154771667f4f694d6febead4e427efe58c2f4a2f515c3360759d3a4c034ac82030243e959a15043010e59a5e8b82262aa9f5f88b98c6e6e5c62ab27beb16499b89ee82fde75196a8c0be4cdfbdaf4e3395874d491ad32dbb96bfeeee9317d04dcde5185a64fe05dc28762d8b416ca06760f1165f0c16a3aac5d46efa02aebc1f9f7ab696692d7ad9f823433addb630e3ffbf0d90e284f12ae2339e2144ad92ca60359b346f696fea0c1042ec78e73de908356c1bfd19d35d7ca66c9d91118107eab89648fa88d7aec44fc917a12570e7033feec57cbcf7edf6df5e18e88858b4508632e0ad36909698885df0fc82eb842aaebf02ffe84b4b3329a39deac18c1fdee395314eea1f9d026849db3938f36e9dd751f735a035de1db8813cf0e00", "-117b3630a994868993229e912118fe0540fa6f807643ef5f5426a83af41858c82487964911f26f4fd08de49863dd557a98ad6264fcebdd650ec017ccaa98863699627e1678a5ca7a2ff7788fc62a24403c420c6ba6594b8175793cffe09bc12dc983f20f5548226252d894acffd7eae3ab1c00976cf3a1b5b8bfda1da999923387a27392b135a453aef14299b462757443fb09bf60f5687ca12332e06b83a67a2a298d81c21324e66bcde3a0ef2a41a254affc53ef725dc2274e364147e4f1edfda9f30724aeedc58f62f3295bde296111e0822ce4025d4999b38d49e2b4dd3ca5dd1e17f1ab7d55e1ed488106835bdb95bdf936ca13f5038294c78ed2c18cda2fdf5adf081af20f84c7e67d67fcd279d518e9ede64c2b8a85e8b06665da56d0811c224172d52971aafed0d59c9898d8013890fb73065c55a9e0fb62e78f39a83f943f91011f836f8aade98e3129c0dba8417dc0c81863d1838ca96a8d532123e476a7154bcfdf27f78731070216dd742df95d8dc8baab5186c3c1932d44866a7727ad698e346d86bef2cee75d1b6345e0a25b23d691ef5a718cb4f073bef647e9523e2ba527bdfec94a8ef925e97fad21b523fac3fdc59575615fc15353dda88d861765226c826a21db4f3401aee45f5946ee385bdbe341c0dcae1746501f778cebb35b6c725fa7452a2784538026e5ee7e5e6d6bf16e0b0f3efd8438e4fa49a", .Okay}, + {.Sub, "19d91579fa54e15f95579b76f8b064de28fe85a1c8cd2e9812af1b96359e093191fdc512493fce2b5eb929dbe385979767702e09a83a60671f67c5c34029d66d7733d2ebb4defddd16a41f8ac1a1a3a87dd3bf62f19140ec20df93f5951d3abe64ea3956575d0c689e0c6fec2da453aa918dfd48a6ac7ce8d237f285e60987a6d8f887b962c31afd0d88abfcdf12593179993fb485a7935f2e2f3a517ae3c37e217392e90c8d5ce6dbec40b858db14f74531b57606e7d8af8bdc6120f474f74fa3371ad4d17aefda86e0e133d65ae708344ceb08a9f3f98c0c6129367757735d4917ef6679624f6d94de0a1ae6362d8136d8a58c673000b8e1b2258a0e49f78f215fd24e07b1584038c8925e858429a8bee206cc74eb79f550e45b75e46a9efecfc9c33e8072438fc07640681653cab1f8fc6dce1f1a2ee13570c2e18d65a1e827402974972862accc9babc65253837df384eb6b2cc78d3267affa20d3f62db916c16f458999ffd6a06d3129c566be9b5facc4daa442e4a24dad6932e02b01bc94c5ac11b3612cf10bc974d5a112473deb205a42d49139edbfffd50c7e8c2c726ec65cc6c9994b60f87c3782dd7d2e992549ec7c227a9646ab80516a1979b13f07f4d34b42c298140bf0a1585924a966cb095d0c97aecf3b5b107eee7f746711bac2b96629eb963adb0c0a014d49e31f8d9bffbbd5ec7f45a28834fbcab38fb4", "5ee36b90c7b5bb3d5d0f48d4f7f4adb1a1e67f369509b07cc0e6ab98423ab302a1d126d60b50740b5c93564287a267f1a1c705f5f4b7c91b6f62a2b52c0445028d580b29dd8831ee41c1ed547b2f5e924c61c433820d585786d0fe3a52bfde90da34d5bf930b0cc2daa26a13c2203d15261145d95d1ddfafb62ed073d1be8c256f5bdd9b1860ed1ac4bc19bf2889228ca5d156e972192bd65b5f56cdb1958587938764602d479d5390da0c042d328e963b605be0d917ec00b24006fd479ae3eba31b8311aea3158b54f35d6f1c0ef0af0c2f19798f937e7d1f82ec2292c798317e4c52291768f2415a837510e314d3dde2bc6381b815a33274cd231a5b7439ab9737f2aa7b8f5ff4347e8ecbe00d5a7965698c29ef8c7435e4b5da5a162e96ffe4902da39b6a671d208cd2e3038ee43bdcaf823516a071d04c89fa90f45ff0460b6756758280cbd32b3229d38a09fa44e50ff003838b7450b1df5780af9ccd2f3c4ce3493f4bc1e215dde52bcb8df13663572ba6b66cc86fb38593785262e889e0ca64831d4f2d876d547f5083143c2702474d987ed6138fb57c035aed03e5209502af085c7a14adb5271d59e12f119324447918b8500b39749ef0037aaeab71dc4f6009fc66eed928982fa942deb0444035da8eb02792807ef412e6f964edb926b0576eee42dc72f21c8b8429d5148b0880703f00a2099abf106c65caa98f85", "-450a5616cd60d9ddc7b7ad5dff4448d378e7f994cc3c81e4ae3790020c9ca9d10fd361c3c210a5dffdda2c66a41cd05a3a56d7ec4c7d68b44ffadcf1ebda6e951624383e28a934112b1dcdc9b98dbae9ce8e04d0907c176b65f16a44bda2a3d2754a9c693bae005a3c95fa27947be96a94834890b67162c6e3f6ddedebb5047e966355e1b59dd21db7336dc24976c95b2c381734ec7198772d301c7c36b1c2097213d17720ba406cb4edcb4bd457799ef62ea66ad23013512663a5dc5325ec9bffe4683cdd2825b0ce127c3b45b409a6d7e22e70e59f84f11321c2ec1b7024d4353462c29e06a2d3c5a56af5fcdea65cabe3bdf550e5a279931afd904d2a421c75d8205c73de07b3fbb5fc6d5a8930d0a687855d7aa0fa4093d17ee431c3f80114c66a651af8238d6016927aed3b1989e3b31466f78642ef171937af66fa4e5de4272d00eb5869265e967e0d37b676c6f18b049856c3e71e4a2f5d5fdba69f76258b7403b5b1c20b7570b4020627329b03aa66cc1229e3cd65d82a457237e6cd4c04b87169ee0096618b0a7ae201f4e91726f355aa44d9a1f57c2e4e6e77b8ae263c524192e0c94cbcaae5d703b1e2f9fefa8c9c95d574f2c91e9e996134fa32d45a8cbeb9a456c51ca78e50e9ba06dd752c7d821878c34523e393f879f086a76bed9e08c457463817108182dc8b316b7ae470832ab58a551c883769fff5ffd1", .Okay}, + {.Mul, "-71a24c24302d22152d0bdb15caa26ef6fdb4823351a0b84f17d19db69549c8257413d2cf0086f6a1a9b0fae4157d45b78d9f95daae2ec9b14f866d4e69f3cd48816f38b6129e4497949107c77ee856e20a3ef0d3c4bf955a31de5cb0295bf4d1d6bc9b2334e1cce37093dad2bf69cb81054f251f8966aa4cccf3b106a2e53b652b59e26bbc6aed1609fa24f9862e266c1d7e88b33c5772b113c1a551b2c9e2414d4abcfddb9fd31793c1eec2d7b0ce5aa85a2533eb2d14e8e973a1b6ea4804de4743bb64d6b90332c27177b2ec9da6f9b18d0ec21810c1c05fa53c3f41c5355e3f015a66dca9d3c0590fc9ace04439d17b9693e061a1cb677b008210dc2afc5102e33ec6b273ecfe590a8feeb3fc3d9eb196e5a95ee0e22341df7e08713b6a2999ec7af3516178fc1a8616b23c28e08ecc48db32206001163355edbdf33ed66fecede81d2abf0a63bba73f7411ed1d36b2bb0f9e2cbd9e6a78d9e317047c00a663ae7135363367d9533b216c64a2906f59d32add3bb8790b35049ff4d253f04d62f83583ad2929925f95fc0bcf2e7a7ab4269d1e675dae03c5cc5434ee910d6e2407110620481b610466d6ce90df38a2da38f2409c69b3a0edde55c53b672afbcf46b8cb138cb971e706e0f84d6bc15576402b222f379c147421f6b1ee649e6977e7459f5099861bf7f98d9ba52c83087494bf9823486a35b3eaf7e9a934d2e3", "b290bf0ed28fc15292d9ddcb5166ea558321de2d3f4183ef72470c5fa175738540bbfdc98586919030fc38781dbba20ccd023d01d51ec1a314838accbea3a340f380270451b68b875aa4fe68741736390badce051bfcb36b9065c3457591053223234501d368eb9c827f4086f2b02b0a31f1ac3de6b96d79203cb62f5f6771491997df33520e4ad5e2b9e496795cf3107ddfac1ae914a42104ead0afebe6fb215b19dcd3e2f70287240f4d9417767d9ef1bf52da99a610ed4325755678be2c5d6d79c364c7367ffb29728b34dda2707adf3ee8f63ad4fa605a727bc9bba19c1ed66d1afec7c729f4cb677637bf856da20a517e84409db6a1ab74e10a6e830d472e72c6705de0a76f1b50d71049ca095b518a1717029820c34fa493f6a07551b3c03cfb6a45781c39c050f75ea248a4a84cc468cd0760da9ed26def9792ff3e2cec2703bc60560797c72218688afadcea6190640f57368f6577d47cf162cce64b62a188adc6e5d867d8b6e67d629a81fc345a2a9aeab75e6ac863e954221d8009bd2c8ed0dd83171c656f30d12487e5567c86bdfac71f4eb2c7781c102160dbffa5a7efff6c5a36c16df3b282a20a5ed9e4aad31e3b672182ce72e74082ab11ad496b0e9c1c07ffe04dc62aec7778ed6a1a117f0c7d1902d37fc4647c34649f2e0953dcca5dd3a4f824a7ae8371c0c674c9f5fdd026c7e9e0804bc50398aaee60", "-4f43190aa90096f06e701e4c19e729bd4694c75e36c306a072200f2816fe88124e704332a1be57aef9494258c8b5ea03ec56be94c04b31047da2eef73b34da48d3a7a220cc734fd5fdea5577b4aebf1c075b6608c73e6529807f60e0246a1126b0621b9536abecb431a147061f8ee302f4f8ff4291e25a85c24c5d05fa529f3507b5eab740cec237211764a934fd8fb2e433dee6132bbec83e3585f18aa4de6e5466b7f306e032cccba2dda5e8e14b4897a15993d941a4798ad90ca3184fd77da5bdcbb866341762bcbf766430bb4478b72887e5157ab166074f6101a0ba1af73f7da92fe54f0768c87c2dd7539cb904870d2988eadb4395bef9d3d42a28b5e51eb9bb4ddc06d6d3164acb94300a3bcf32f86c5c8e51a68281af49df8e32cdbeb3075559c0b87e1efc131393e331dacfa6a6af7ebde2c4669129809afca421129c521754ddebab8d4d289af668a2ad76ac99684f237461b3e7d9c20bedb21373bdfa9dc5c86ae02c180ec3cd9cdd734f2a76c8f1f86a8b48dc807209cafbe6e797688666d8732e37ab1a710ff925b58efe6206d4cb44721932e6725ae91816b9fd3a323ac8838ddc044668390169071300fb8e8a2baee3e95145423eb4b36817b3d852c91940a79912c7303a99abb302ddf422eb0e88be7ae7906c28bf13aee69b13a4f44b91da062afbf16abb5534eb2aff29bd13566cb62751f805f9114af1de3f1a1daa2d899dbab438a53d50670a496d6350881224350008f5ed998210e52be50dca2250abc8d277866888e7a38e8204ff2144cd696df96fda27c0a92a881adc3810e501d994abf4ad36f20a7a8757da97610c3019c902455ceab2d9b4f5e144755f13b8af7638d89e6e394de8881908c68b33852f32ac88b8f7ba6f3f4ff6c87126b15ebd1cc647b52614df9e83b53519ea6abb067249576c9583be68fd9f0e7231a6356c75869218371a873c90e03c5a5b5d00626a905104450ebcae1ee839e13da1e47e2fa217b443a2eca76ffaf9fa91fa74552b0609288ea81193b09a34ba94be86b00654bd0f2e43e225ab8905c5889836d64c29b825e88ff5c36431eb8377e6cc6cc6429153f55c7d4267f52fc6a5b2f8037eae450d7d9d48d95d9229b581cd52cde501f14577b7a94afe1d50bcb396b8b55ad1c706974914e4b10be731007e929da041a4437c5b9e852c9057b51f47e3feab71ed8814811e57bb8138b3e4f409a3b281229d5fde3397fb43f425fd9cdae11b2c1ac2c44ce069bd0f430160ebe87a095e1b2c8c005f80bd4b7e737aec69bbc29e154bc54bc9b7ffd7e4bd088747596f021cb2fa337576ab1e09226106631e8324fdc276368bca582e1c2ea24202bbce7a3b2f39ce307fae0364b9eb2349f6e26ecd28cee7c8517cd42f561f51b970ce85e24e57b6e9099b19b921241d97932132a214e2629c1f20", .Okay}, + {.Mul, "90bf11f9aece73d6308128f58608298bf7410cd7ac7dd5b5103a98d72f98ee966f5f71564fd9ff8903b3b10f2b8bf41065660eefcc9f9048a464dd23fd18741355013031176124d55af78d78539f1af4784d7c9fcc257013e3664eebc7b6df26eed20c739c167a3baac483d8de7d7b5eaa895bc73c733b452616b1357c908f822492c80cee612688211037af9e86ff09672525d2f18191693e3a68a82e261239f7f1c8de674d4eb6ef72702f689e467e3d3070f66a952128e86d6731fdf1c66eabcd1627726d26ce58a99ecb0bbda1a9bb011eace8b14b471571249acc6ce129e97f2f4cf879a0eca215bf02ba14fd1d0d501bea37e227d39c66a7f01219506c542c2e1010b8f0dbd52f4534300d84c3a63635f4cdf9fbef33163f0dfbb845cb8762b783cf853055b5fc757e86106ed84f385c12a3b90169c6a76df4cb727f7663f3ef20decc7a625a950a80ecb82b2f1fff4e29bb686e549bdd5dd7c27d00c7255fef7dcdd3359e73314ec35a15f4623b8f564e6325e88aabd2404c7d52ccc5007bf37bfc7df8a9064e42858cb212ca1c611a7cc2a487f22ad6f7575dce3945c87ac78a260200efa17d4e13c7dd49e295f943f4ec37ec2912504bf755a6c4778a0c86e42d13a68b117f2d8818d4a0b30d45f846f7822043a43e80997ec7c13eef0bb85bc896490a9df09a1586c9a94eb7ae89ba135bb3aa156c1deaa353a84f", "ef06fb7681080089498754a257bcbd7df54254e38b0c89acf76511fe16b973a2943567c228973c8a9fe9af50c8a9d33c59cbf1ffd505f1cf1dc4235e5c5fa704c9bdee07f36c370cf0fe3759405411c212381ebe28cea98c1eaf6856c74f0c76a16b29c6405b01d4db914080f37265c9a5bee8527f6c7b06690e47780955944e5358028e8e401afee44aa8cf998a0994193282c044707d1eff4ed8c5011c5b1baef994a39e3db17cb2d6fdbbdf851c3a5294575410f2bd2f90b73d1da7327060566311d7546beb3c0b472fd51772d901e79149da51f53b0bda0be26350f6262f78ec89db5e7c471af89dfb763456efa4903ba87599c169b139d0bae9a5b113643c650af8bd317f1b40dcc7d229e75216ee5f1d37837bc8dccc27802159de3635263d5d83ae3747e324da561d3a91d9e625aa70b97e620998acfa09004d155df203c11c246490cf92e92e1ba3895f6c8319ed33970872e2e4042c1f1cd4f83e40072b91a3860df4cf4ed0249a190e1774c9944f977fead3b72b53c4d0de7a372d8343a5759e85b5d217edf57033783d5717d3f6f730e761ee2d976021c36e15750aaa1ebf179c4d9852ff0063478ba4fdb7c68b6a592d820167c2f12562d36ed0360e80cf22a7acd42b5f3b294de712e9cb874af93e6f3eb00f1cc27a9a99bdb858a4f54b2655add9305e0fcbc3232f13ef5bfd3ae513055220e4837742724a2e", "87265470ddb3bccbadc13cbb7021f7b23f6422b33796b07a44e3033634b3ba9aeabff34592de8e606d27f7bfc5101f51fecf0fecbb553fca811d4622f3d18e25959a700eabbc8e74bea026896192738dea3f5ba40e8525718e05ca2d17752ad55021c339d82318af10330183261443057650762aa81f2c29481dd9b1afdefdbd68a020773b1604292466560a253ba06c3749e16cc56ab9c20d66282a1820e8eff01bf4a84a243cf4f2bd78ccdd19a57318ef21d18654eda2931f7b3a615dab2ec03e1f11655f889ae88770c279cc93b3d9dd63f91f4acdbcfc6a1692b2374cc87787385f4b276c41d72788f287426cd554a13d6c60dae413cd878cc21e6ab68beaa6cfcf20df71f2e43a56d2b5727e94bbab183f6d2d5e88593dfca651ca141dd863f754bcbae177351f96a6dc17af07a802c551e1f787de3b69d07cb0ecbc2fedc6595b55b1fd51b8adfcd4cc9e4e2d9b413d67db3ce7ff32d087758d902b68ae2810768d4586cc0b91765dd6f2c4f6a4e2402bb2d66f8a1fe67082a5c47024d9e5a803a28c32d6275a07b1e670e0c887b424b7573c39778385d725b5715d22054fa1e4ad330cb93204da1db032af747f0522c7409c3634dae32fbd61d01c3650a8b69c952a271265afcf0db4c00f9244bd002e10194271ac15335eb03052aad4cabb90c56d7f796198fd6a47dcab21ccdcf3da7086d9d18c51f8701656b0fed6a7613b56ea68e6aeff480c919a6f12b7861dfd81fdb9e5aeb1a0e406b35c117cc84594aba3a4775fb81b4c84565684fa3e234c63b2291e39c96e6cc062e24d5a77b367b29b220607dc8d611dd00691f8ca08ce0cdb2482bc286280409134b52d363f12663d76c12e18316a1934287602df4489eb29a32d1fd1f7305caff914838cfa264e2048aaef08a1ab464271fb2e947e1f4ab7d285238d3b962bfb2e4efaf4eedfb18f208f4ee271df996d95b6fc8c601fc407bc523b57f32f2012fa0cb8263c90b45675d3d04fb696d109418edc09e63979425bc5b6731bd109ea4792f1a972db9f0049bd24069e57df9165d488501f3ecab5a66147e1cdc2b975f3ab5b3b8fc0ae39a5e7651774500d3fc4b89bea421e40505294f9362dfc6ac7330415a5ce9ab6d69b97236240d9c7100b11b660d06e33b989861423e445b26eaa1204001c548462f2af548be21fe14aca2c4334a1ddbd2f8c9c9f8703df92ce7d80b2a9534020323c96e2696a0a2fe16560ae51cbb49a4756a1679a41090446d942acdd46155f4a86caf2bdb7db6a57b81275279bfe44a6c99f6fb2fdb1cdcb1ce7ec48a7898d811be51382ce860995e759760e69627cec057f7980b41bbe711a402b2cb9e983c70e9306f687d5c37cc063b4d19d9b2c866b5c7941d9a5b83f4d1ad27d5bd35eb699c0714952c95adde8fe4eda45413594361c6c0b29bdd8dd1432", .Okay}, + {.Mul, "-7f646351591b740a6b868b7057e53216cc46b55a42794b8aed80b51b80336958a8338c13ec260314788debe0881a4707b085ea73df250421d0712d07dd05a0812744d41896e45708f6efd654cb08c3f11811167d785e35066a43baf6146f1f3d881f6f91680fc5c0bf0b9534c5bc5e9437f229d6b7d85cf1bf369e139a0553513de52a1b460b24f03674785f119a7cf369e753d3581f5721e07d881a752dc63b77338a19c80401885e13a7e70604e10ba64c68ddeb3749b99b1cee7ad00b33b094850cf7ce8a11682f88163772b0b823c974331d57f60b52f3670f156644a940f1031c153c65f27013a4a1e3ad8cd3062889fad57deb41009c9e92320c68c78e58d7e55dad8fd22842d3e51f7acf26fc56d69315651df772d2b182c2971bd49d00f30f11dda63ee3c69ae42d2474cb6d1aecae3961ebd8af4debc3377bbbfdb02d355324cc12ad29e8535f01f470daf35da8e584399da300840228a48df970f87f01bbc538dad38029114f39934bfa7df7929768b66e3b16baf6b27b87cbc59cc9f23acde136af80756db49d90c1872eed38c6e36b5e7ab71234011459985c1571592054a1e99a46aa7e63c4b02db08ddca981762d9e342f78c89614f0a01d8d5978d120076cb473ede6bd7c23feb2441d8b7af79b045d3bede12c9ecbb1a4e719ae7034dbccdd59743025a69125ea1d745726bba1df1955954eb7c6295384a5", "659669a3b8ef5149fb2995e5e1ed8a9ca9b82a3351a4e5d01c980019d0aa964e612006625c805a399d905e85f689099a2c91089f9c986f10661e03b19c3ba5914ccfb395dde72aebd3ad20ee3f89da734b5d2057e9e0b555d0a70fc237f3f391398a84f55e95ef197b7552f0d0f406d7d8a30a78ed610ecc70856c0471c052678f8f31599587fba5726f89df62759cebd3dcff69da6173a3662d26582234c114c6603c3f9665f0e2593ccf86bde5e8cd39265666b92f5a2fe3710355bff8fabf224590e172eadfd5a8a0c9cd72d9cd611b116c0208cc1d68aa01b1ec9b150918c52c752db0f701dcbc564c38a398d5a50e087da9e2bfee009fcc3b8f931180ea20f73edee30ee500ff88199a5668907f23800e2dfde6d4b5dcbc8a1684e6c6297bb996542fa4ecb44e0435f6367d65d36192ba87cc003ef86658eab5065907fb6cea5d2e878bf8e5b6031158ccaf6b4c70198cc58ccb749a4d4a58882716c79bb8d242e23f48e22585175f28214a77c97aaacf338c4ac8e2bdd524e0b169dfa527399dabfcfc37121a4c4ca8bf020ff62d22ff191c7455e15eae5045374aa14696c2dd9eb8d8a8b0901d159cf354ca38f2bd09c4ab5fd609ebd02753309b66ab60de5dfb80d3c32f9fd94a3ce9b034059afc678af7691496ab39f5e4168018c725e8be22e55b62abab2fedffef45f4660e27353c78164795ea9783a57fcf1b2d", "-328d7492ef80e3c4dea1590f155914787af5da006d297d42805bc89dd483f351479a677230185cbc045867e3440538ff42aa2c29c3522cdf43454341f1230e18087abc0d95c7a8ea3957dd5f9561d9d28754ad9d3851c2e792b779bb240cf387169d8ae45b8d8fa3a0a3b07bd35c9462b272982b0d9ebb00b77608410ba8339d5b32b89b4edf118b7793aba80efe18b0337ce1ece09a82d35c51fb724f4ee332adcf07e6745eb5846386d0a5a35387f7c2fc510968bb48e849088d980af7374fac28116b60aaf167875cc3ca753b6fba6bf6729f8a1c615bee71170eaefdd86613624b2fe93379a96445efc225255dda1272936afbed4acb5820b34d8208b6d368bf25386a0be4087fc40de5e4fad6407002c977a5fd8cf82bf62fc514da7afefd7357349d4a264a09049e0674446f386ed86f94c5789d143c66d1d65ab9b316cf252e908c4426e14f1506c737bf5600554366f6a133a89c9d435c824c43d93a3aad6f2ead84b304bd1cd728848ca51cbbcb4abd42f3d61a27250ff0df9192a2e5a1e8573738a9c66fd319ba2d59a0763ce0fe3ac703b7c9d967ab8b67ccbc2ee247a7fb99b6e17d13b23e2c7e05980f3cf36e475fb91f90289062d70861501f1aae05c0a400cb0dd3e23ac84978d8390824f4e9aa90baee47516b56527b3bf14e4070bfba27be659bdbdc99f0acf412f64f545c5008c631efc076eff17143b5b624bd9cec7f4af6bcb0ff4eb6862e0cc083b98222e99a5431adf6813043f3d54248e6ae13fa80e23fa2c67eb6f493c8e177faa2039c5c93b9abeb5fc0bd36297a25ff9bf706d012458d71028c11edc193d4ca5b52c9837e5ed69ab838656cdce880c9113e533af6eb270c7f551b59f3b04ef5af2429b9f8e04911ba271cca352570e28989dcc0d0f56258346829f48f0cd380c3aa437b35b21e0e5fb44978337bae745f699d08d4bd4af456de6748e943434d13d8873ac4ef269b775d8bcce11441c841ccccc6ca45d39d33d2bdd4189aaf41a3f730d6c7b06ae5227b4068067689f5d94be3bbca7ea2a5455864da8e48f7a65e407d3eefd0705f71316d06a49361a5f7237b8552e2b9dee5c4916a91a1a7ff863e6ac59570161a1b0ff03054a8394c6b0473eb9ffc2eaddb30030aefb4bf02c110323b43aae077718474b3d397475a364cb8c917506427c2cd8bc1f896de9f85fc9c9c8cea175b59ba7177574c2b971cdce2f0f18e331e4ab4a3dbade5ff13d9a35b8233519e50506bf9487c120a4077cf88344d64a92c9574dd5a52a0f9293c0948d6382fea2ba6918fa151bc484b3cbe5ff2eedc49477d884bd604c4b4475784bd1ab58df6bac7fcbcc51d3cf0bdaf5615c385b3bce6765c23cb9a62fb589be0fe0fd685c834af29587e38bf743166e0be117d7c1679ecbcdb3d8055802dd1ee2ccb05e2fbfae02f16b801", .Okay}, + {.Mul, "cfc22b13b75a7c2acd3f7f8d92584ff0bf8312af001950fdc71dad2d83c70fe9a92165104bd6216e97d1fa465922a943eea24c4e577341c85b0dc366c7ce60e1ce0879e59d53cd96a51d2fe9b2cc93b81d09018e2eb0550c7a378547242ffb647136d46d751f67ecf9bb5fa86437993ed36e4cfe8b434942ebe7bf3acc5bdd0e004f22f8aac920b0d7e6446233c0ae415ade4785aa48588c99b97adf33e26e2d89a990f107d572c5848320fc43e47473ea86dca0fca41497f34ce18ce72b88642d755bb0bc89af7870d15b5d4870d5f15481779edf04436aa430eed5d720b142c176bfc506fa13dca574932a716f0f2d041c8a44156099f0275366cc9d3e8dcdd34886be990ac70f8651f604472254be2d40f0de8881256c6411312857761759522f924655db03914f0eb10d0155cc099173e3a9f0e8a739baad02fcee7e63be082a11c0faa96fba64fef60f96395c30ba0139ba793e4ff65a4c79ec2bf812491f3f1cbbee55bb90ce69ae12c2b0d1812747b0019c0502ab80267e2bebcecdc60b14467966bc85f1ce7cd30b5c3ce87b7550a163e69a8820b9600f539cd14047fdeffcc35644d737dce1aeb149df8c7ab91073d3c4dddbb033c2730d63217f4d50ece1535e3274e4f43f109743e49494f293c5f7399d124d5358cba7eabfbbb1ea48d26578d8cbae0f089cef11d84cf53c049aa7e85e8bd05165cf381f554a21", "cf72b7374403c2037dd1a63da4b98d6a3fec881244aa20d1cf5aec179691136459c62eae68424ad46c2e48132bf0cc4368fc0c29da28aa78d6c57f6664dbf84df33b2d682bdca026d2be8a077c45558abbfa29c6a146871a4a5d5f57a8de33ccbea6f056dfd5d38186b073e2cc0a2fff404774e3b68ef713bde9344ed59838b7373bc5a04493d747034a65f67f15d079f19405b5049c7218a8623c627c6cec30fa739cd958c89d208c6f98205e61b72cc1f425f5a2ac0198b427dff14ec7160df556f43d0e2d846af757e57b20150bf7fbd4bb31bad08ac8be7703cb52fbe49f48476dfc3057b3746d7bb7fb5d1a22036e79ba94b3679591377cfc3718c16b7f9c21c45c6828a4615c22a90d83d25ffc27d362d07124413a375ee4f79c341057ca817de26a95824e14138f54d1919e81522fdcf62da0c52a80d606271009a4259da273155483549098ba4585993456dea8a215371ab93ae9e0defc2c61096ef05722e24478c079aa0eeb7fefd1eda32d13c9ecd604ddb8159a49b6beec31e0fda51de94a91b1fe8d40b69441912008b9b8328838233d8853c1a88a9c08f9e0b05c59985f9c128d5d29639ee75be055540315b6b1241220e62bb4921b25784cf67bd64d2daf76b24de9348d76363c6877d5bfac4913997bd4de48cd46d1d24def6c21f0fe75030ba544d01ceb8de64501b9bd79b0a1a515529d2d964a93745984", "a85b19fcc6beca2bb22f990508e23e6f07114f74fb8b4acbcbf132bbabb030f110a671710213dbd730dca3ee6e2d0bc23ee20042b1e86caede1ebc7cbe6db35cff3152e7208188e479db28ea0d9fddaf14f02d5e8313e857261414f4df887c35af775ed6358757dd9574c2ca9baa44040b3fb8d4fa59a6b8ee9a666b011e3125ea13a5f14830a8a294ba5d1723983bdfa3c9e5c0ff26b12f90489acd6b61d7f9c97b52c767b7bda8623284e0d9312c3b74119377f6a73ea2f10bad878552d0c288dc9d5aa8b2f8009e4c09f4101b203b4bf822625ef6a1d423377567e67994eda8c90bba3a5af74608b21eb78a50c6dee76e2910bfd69ba02d174cbaa3c18b6137b841e7f8dfb20e8f3e8530b4b006cd9e61515ea31c0b9e771059072be65d2b3cec2c2907828a3ca371455e085c61f77d12bb8434714b5093dbcf465e42310dd1a19d41f3392920533820cdde8b447ea06ba2a376432351157f4947fd3e24b2e1bcd1e372e75da6732b6956dcdb1707a2e70b1fbb8b340864c4715f59e8b0e062432d5b4e5173e51c60baec54d2c5d36929b874b36f86fc9ae89e7623f24c02b5ba4341a4d43fc9828a3a45525d70669236848fea8d7c8f49f139eb94fecd59bf74e6021dfe472af522a7bc2438d4b991d3a21fcc8617e88b5634c397cd1118ad3f0dd4e9c01f52c9107122139b60de948707c5e186afd9f3ca87069ea8b885ad8f4399381868942a55acc395faa8352280b96e8814f6f1c734e3f0483e3994dd909b7bd34b554a8cf38c4f7fe6e9063b89cda2080aba16c0d67ed7243362f5e6d8ec7cb3db00437cdd80eb5e54906cd6e99a1762785b3f7aa341ad854e5a79e918f1a4a4c3b71934ebf8c0366136f69a7d50138ab2322ab2b3b179f32c5a29b1d66fc1e22507e162b899eca9d106fc48e178f83bbca4a99a1bbd14136fd3d60c3cba3021aa09347c002d7c724af9909ad59dd199e314d42e54b2451438820c620347692bd72847e24ee0ec3ef7fcabf426bf944913b5936823276263c4235ee2624329065b8cfe19fb775288e9cd59b6aefcf27c71c65223d112074ac17181b3205f3d645f5959325e1e1ca5df5705104b9b416e2bd13985433002e594630172a3c306b351a81ac4dd70ab6b193725dd0cc4459195c93e27971d30a126118649ba5475778507ecf710a352eb8aa7ac57f4d2b400219ed6d42b3803df460e7506ea693628b8f70c15e78d892f34d87588b820c8c53e777b2c551c2f6ce548c3416f8c67c78c624c11b9aebdc7cf03a3dff8df7e8d613380a1e4eaa7bcec9bbd2f176abc4e50597829a102a0715e2fda190db2d26e6782832c94b275683e9c73a5c4beeefc85042d708c14f72aa20c753b4499ac5664aab40b701b3928681b40b9b87ca972b30224f97a261e1f0800aaa6f84c344016e870c9d94b9558b3b204", .Okay}, + {.Mul, "8dac17295e1eb87327e0a2913945338806c87d1edae6e23b3bac9c1544ca992bb2d59b09f80733c58a45aa9273260739c70266d615127ced10886eb4059632f89b2689ed31c64e3678ce7422671f3e87d7f551a6ad23c20182d98119ffb8bb7367c05b85de990347c3d48d54e1b26a1c0069e04b691f605d66f3703b38ea02958232a59f7fb299e04996211bee5fc63dce3da1e671fe7afeecd611063832267bd4221a52b2a595bdc4da90a63a861fe798e907ad6cac44423465553bbcd15e4e8f779d26dbc6b1c961e692f93f2a0cf283e2c8db60c6a6fdd28671a63880545e364540a1a9c3f06f7a26b324e0a9b51e85fb8c9fc832d85bce08e3de2152e0eb87f8c73a7ad069556d6952ef32b94d2128cab72bdab944ca4c78844aad535dbc8fa0730e2dd95fb243d3f9d6e20e1f9e1ba0187770705968b37ddfe6167c080f30773e4e0cb2daf0486924898fe9152343e747092a32531b92e141e6cdf4983f037b3077323fdf110b6efe9003387362b1f3dd6b9d76f6f72f5fb4be82b2840267e9123f13b749c6896936a1944ab63ea825d491f8740624df46aca705c1a2ba325cafe4336057d7afdd460fca049e60595e4723d44512984d86b6b5ffb18ad3ed3201713c54a02110960917e2472892b0efe2a4fc9cede65a39ba2b15847c0b46f3236cea5db1314ea5226d62c21c9e653dd028306d534e204a5e3f997eae81", "21cabbd3a5d2eedc7878ec5824e18e96a7016c00c87def111b6d56d3fa602dd89c62de0aa55ffa98b3bba44291076bf745a78daadb260dbbc5102dacc6251793cf825d62391fbbc24772bfe1a3ff01bd183f5d8e685a22bad74ecc67f0a43739f8957ac1132b1409d887a5c28ef15cd42b755035c4992c30b9f881f83a3ac0efac62a8447ede3d750625f26842ee2c172f22c3de59c7a2e758c71eae5ff4a6ff3fde31f2b1aabbba56a55328e33c0cba992555a370d96e9e5cc386a637e1a3fe7a095752fd39ce9f872b3e490e1987ba6cabbe2e147927a85c7ccd4c1833ac8fa67b2e7e34b18ea24b0ed3ff4260f07b34e47887149fd98bf08049cf3e213f366e7d90c1cb16e8e8e517640fde93c688b8d5a7e0997716aec774d6db51ef9204fa33599dd40b553493a03fdc194cf448d5d2a063879fe9105d4bee149b7d598d782870457c1ca7ab562f76dc83ce2b44bdc1c75e0d36cb040983eb739308fc130fc7e5d3eb29886ca5dedcf8f2181743f7d336df2caa054515a93c2053ac8089eaa432eb0f1a2d787a2fe8ced2ad6ead0471fcb0ce821fc9914640cd40fd59e057aa26bda32736e99beeb2be22737d2d943049f4be75a3e81138376ca4011eb0e1dc622015ed2661f63bad252a6f81f8d9e7eb4d8347cb99cb2259e3bc6aa0c74fca06036d13c79aefb2f3ea14c27ea1b148acefba57522d7d77289785b964d5", "12b360b8714d2f2610c086b49958e42122147f34ebf651c332f6dbc5c68e4e4d32e0f484262e0362cb8a2e36f96fd5ec697a3f1cde924cab25094ec9dcb8a950d65a655545602a1ce5b8097e9ccaf5aae70dc49e7d5dd457a8bbdd50ffa64c5f06b042354bacdc320f6dfccee108e0b88690f735de45468d1f991cca22998d4ba2a91de4f18ec59d769e79c3a2a03a3f660186702566c95d95160c5d80004bc6359e89d08c454e7ac69edc4ca704e089b803798e6701db82631ffdd66d84a9c74b65c9b77d76a0b4bf9cad0a5cc866eef7fc480683e8b34f05d63350a08b776710d661174ed586fde9f473244e3d390fc441f631f1de3a0ee9dd3956134d770d2c068e0c332013cb3dd0b22ec84480edd15766f4fe6541a767552111e26049c24b8210425d7318e6337dd401b7f160e2c2974ad7e10c4d64e758fb60151b0f356d86eacd0f8a6a27495a69cd721d2320d96ad9c9b68f569f1646f2009c675914aa81d0ea2ac38ee4436d1f5a5d3e387d67cbb3f9b747b8d3aa7be65e6ce02196e43bde67919e5a2385f6685c13f12aa2f2a6f91fb916cec54d483c5f3c4e6abba72dc2bedb5cbd3b9539670dd7c15c0615b9a55e5b6651340178add292c348efa6e80777e4272645595eba61f5152910b782501783735e3eab4c358270a2c5f014a5ac94cbbe424831d2a52a15c2eec9ed7d0a7b0f2856da4174aa97f571a2f98deb2dfb70a9a224aa2ce0fdfc71d52fc5054502e75cc624b07ff011643c4448cd987ab9160947665810a3aaabfff74ad65ab3b1b9918ca5e826f8014cd2886a169d05b479388f7b7621afbe8ef38c358658db44b59372e152b054eea34bc0203c0d51eb57b59f197b4e9340d229952b22d687b38a923ef0257c2589000f127d935e67950745b04847d074c9a84214286918e2ee095065364efe630cc2960e1daacea53bed57d737343a046665a361c339715162778b3d0f43d5ab8a75988656fee4dc825a0a9a39d7c546b5b58fadbfc2081dd1e39836f5aa51ee1bf2e0f59d7d5e1bc24f7eae656f1310235037215ecdc31b95b078d47095b4fd0ac52eab21d9df70d0972e8869bf7dcf48511f023ded576d96bc50bdd3a5289db60f138dccc6c45e20d716cf5f3d3e66b7c6fd366dece48544c042ea9279149438d1b77fc7c841825ee8f78456fd7f18d9dd1f076c7b2c49dc0d5a41e0ed91be88bdf284dc9b0e2dada9fa1e6d167dbd5d7858a5ddcf27396e042335b6244bfc4ea7e1e0a9017610a43bc0559c075e3f3caf9072ed86228aa3b10a1e88b32aad4f11e2e387bb27943400fd57f50f4bcf382940d70f7565d52f20903d12408b078c24abd54c0d5e3785579fbef3c4c95c94b85db75ff53fde27b0e60f1364a08d8dec2fba360d5629b9cc6aec3a256e546b210f4ea9a0b915f9e8d88897815a162c52ca9555", .Okay}, + {.Mul, "9d566b3b798c2caa685f305481c3075ae8743bf3848915b33428b5a86f726e7a38e829795a6f91ff11ecc46157d76eb0c18ea8c6f1ea19287c3301b2ae291df38b1403e725301876641730ebdbab98089077960a8f43040caaae8cab2f99873f0c9dcde3da63e4c035aed240feb7065955f1e2bd2a8640d0f063e58fe57a7d1dca1dc4a73f5d8c6933bde54affa5dbf44956df90650315c623c7d06a8d40caa1ef212c0627b442e1fcb9f675e79421c2099475492bc95114fdc80512b6e6c10b34ffae2aad37b048e7efd4d14df12439a6d0e41b4fd8e5d5added367c6ed3759552541b5aef5fb42d9486d07b6a5910894b3d4aae436bf708c727b192780c67ff42f2b01f4af97e918603af6e676a67f03af10ec9b6c1f309b89545d1c06e3d1bf5c080e2eb400b053b0a901944aedd792c4c013644b6d724cdd57a9d0986070453e2a412ac74be1696e10d75b5df3386c4044885402b6cccdcedb9211bcb576f13a565a752b3d7196242aef4fa1c664b2193bc9f381ca7b8b07d6c560b00810810d467f4612ef49fdb31186566736bf6ce5be1656e3453f9c000c96d4ed4bc4c4c41bc729ef4b2ac71b1425dba31fbdd325ce580bdbfe912ff731f27d65281042de33b7c60dd74bb3daba0a03b2e89757bcaf1bed9c7cea8fd72f86b1de0400d866c74b22c528e16f04eb486a60f4a6fdee212f361195abbdfe96646fc08abc", "6f1a9ade3c8bbd57087c80d76ab632c6c08ed47a595af1d2a4484e3cbe6365ba5e2c5609fbc14580cf8e5cd11e13fd963f6309827b0f42855d58e48f4c59d9cc4e1cc332383576b1b5b8c708e48f13db4d92f25836ac6353575653a06f767e3b8977099fb0d240c351d2d73fa9a5c57fa86925129b54a249b6b2bc3bfe0c7aaf0648e72ee9c024a85c70176303287d869099a44cd446c6b5f5530331fd4b4e76d055dfe393f0ddf9d42f0fe74705e80e3c8157386c16d0a021e2739728ca2fdad2c9836ef7fa5731ead171f992aa8479e6e9a9b2b1de4685fca197fbad3f157dab6536b3e38015dc8b5f6ff0778bb72941ffa5e1f2f45685d4adc8317c73a507386c5e3a5f1c8c90aa576f12f345316539830a7f883270ce5f3c4b2fbe510111fee9fd2dc638c1d29726a92a93c58e01ddb35e30c6ad355c2432b821a04adc015965feea0c8d89684d73d7a29e06880b1edc185b68ecbdd040f042ece2e7f0dfe27b61ebf855651c17168f321ead2084c276e746947fdc1a05077ea1a6ef41c92c2c40418ccc42817e60dd08ee54b5d584b6ad6327b6e5202aa2172422be6dd2738c21391cab988c9b1e7d5b7429b00b28f44c35dc2bb484004cd39724bc8fc04d3f21337aa6b78b0b1462d38964f413ffc85b3090019a2ce10103f927894021c27f7d2f26deddaf6fc5ef8e2121f6046f7d2607104db19a1ad43b9bc15a2605", "4448d274406707b89b858a1bb6744561d480e75d6a4488de16007ac1d8575508e0f91ef44fecd2d92239882dd846d609f9ef791785a06b192a31b4807477bfc1dbe87ca5c8e721a59e3cbf907453f850e0cdd73f67d67b5f83f20932df1b1f86861269fb2e3639ba754c6d0a1569fc1f8e5a52cf5a8f880e73b8c300d8b210e34003c6bd9ddbc700122bd5aa30151713cff241d769884aff844cd34678b52075f61af29ad037f221c2b8a7434acb41c6c2b4682a1745c54e0eafeff28a990d8eac4d368c4345ec5d448ee074326dcb8db74595afc5f39b8028bd86d78a7d6868322320075b1940dab6d020f71543bc14bcd0785f5260ea14ce8570d891625366b9e95751981a220aa38a3c07d5c2cb3d6306fc98f640cfc49909ded4f48d9a0ed465efe516036e22c71ed287c53203f9a6f5f347fff7633864264c602a2e3994d02313f42ff7a0a54b6d84940b3ff34c5f98aa49a97f150b62b09f31bea03a02bc671c2f2b909a29b9beb37564988258656610ae00f591ef4c11634f9ae9cae9b32c0496ae9e3113368b7e92483f05a48409dae3742ba216fb1b12798648bb7e922d7b5f392251db944de5b1052c25c3b534e028908baaed92d851917e13172636334bcc63b75601e53bbd34405237b3c4e179b18b03ab3c26a35d30697f78e8f3b430c4e73d3b839f3e7cca797f837ea98e83eb2d9dc62cb682c2e023ce08e1afdbbd049de656b01e585a889a673f595d3123eeeb1653c484f82845bf36e9a3a57b38a1d0837e67e7c3f70d7b88729cbbf96f1d7a44cb55e9357ca6429e3f4266481b2556ad4736cb673c52f25ee3c5c0ea561be94fbab0461619b1701f0d962f04567bc76abdd61ef27c3e192e326187d733904e04083a890410d897ead55282b08e1cf650003ef5e46b6db9585a69cc9a2feeed54c1fb85df280020806bb0becac88857a1401400f409b08368ab34a769efcc0157d837247ccfb98cd8546885777c6a2ac456442b4094a9d1d0d61fd58521dd9ff45ef351c7cda28617d4a3813dc8d71ee1c05087252ba3d3a5d1e42cc591b1047c136bed145c43dc6f4031c17d5afe1640deb69cea88d731480a2bd290511482880b255d9697d93cd65f90cbaed0eb42fb6e5d03d2ea278001871911e48a4e95830637329225672d0dd4a034aa4f8bb6a619675ed4ae491bbf7e8d9b689ec4c7b7040d548c0b63fb705b4fa05ebfefa68e24732002a8a8fc000c23fc00130e357ab0d232d096a4ec3d1130e912ef23aa07f87b3589484c54c0c8a4653fd97069e0b0dfa1558826dd23244d1ab061515f32f1434c1ec101b195d3393e6a62a337ea5f4a2b6f0e8db2350ecdf1eb66ef88c0378a8af5ce83ceb9694ff9aebc3339b78513e7859da15c52574d1a3fc78730df685b756631b991b4a297779494410bcce4a41d189ea945729dac", .Okay}, + {.Mul, "-575f67631704556dcd47d0c18feba923fe35e3a7d236ca82030929dab87949d1452ac382243b35822813c7d0cd45fea485342f7c3fd17645b5d3b68817d4093db8e38867d606011ccdb81dd2f3f75cae7f28e7e2ce4362eb23f4d4780d12de7e6622b788e16ef3f87b1cb1070ae0161100b2316f06b7fd576d9023a86483ed17aec0fbf0cfd3b2dac673a818e1b15c422e4242902e1606b662b47e99f4ac278b45547f0887e16e988f9b6f2f9d136b43cbdd33ac56e59775ac78d55a456e7edb1979fd3f2ce1aab31ed08392e24165de428d3f24c6f5669b4ed9816909cc135e727ec819c8dca942e31d47207f7b24690eea20a694a4773ac0ec3806217c5c44e8cfc0fcec5c0f0a4199fcd551d4939d07f86e75e4221b3f1abedaa07c1e89092ab70b8f4e8c82b13f019312be48d256d3a2744f28a1307fd124ddce5afbeb7bcf15c49eeb3afcb8ac7dd3c110de27d4136d45cf1011aa0386292b944bfd63565e918dde0f017facb180f8d0f544022f36220c1f0fded1abb50a892b121497813e1c735903fa472958c87df2b181eb49fdae50e80d5f7108aa1ba9560d4e87c7b46d5c3555918dacfbb35ae94a2f87d6976ac68bb0bc351d784b38fa7b0df1cb741ac09af32b2f929974af0b0a95b8aecb5d5544ac9425906b42f19c647b421a02d7663baada1669bb20756be2ded1efaa9af6cce84da69e9910712f83c0e2a0", "5abb55546c09919fa2db9fec4b2ee2367d3e3e450367cd9056cdd35d35df15335f3f78c55ba65d77bf399150548503c5f9e2306342c8d758f26f1cb79ea25476e23d5e94df1f565f6d5df12dc5b76d3a42036576331a8b054db14ed0b9759c24afba67aa75035c0c5989b4977c1c2b45794bc5577b480df64128e4da2946010b02f675cb564d1cda8d89ea4caf48d5a10d7caf099153e600ceaf4a800faf6fbf976f95de9038c63caf2202a06fcbc06bbc5db21aff1b6680fada15a1f28f9da63934e8a8f739b7999a058f336fea391cb3da2545cca98af7a932f9a6e1fc0adad3b00322d06a92ac6fa0c983362e74ccdf769a8a060e5a26b61a72acb885e2a53341e0bd8262974d14faddae18e91b4cf7857c3710fd636fdd30556d8f7354d10d03cb4665f733d37cf9f868f686259e59fbd82f3ac0f2cc194ff64b03dc5888fb4f72adab6dd64b5a00d7f354c1439411a61c0b9b0b9f4afb48b12ffb729402515a4bd6a2e58bb2318198b9925f83c3048bfa505742361de371242a6a6d1cfba732dbf81eda0752f4ab01444f5434807291fb534e799a08e41a09a837830109b469643ae8627b8cb075b8c0fde3defefc0ac06f9d98a83e95eac679f76aff40bbfbfb7620c5a7b8f9f071fbb0f5b256052679a82178b78b5e09aa1ef683628d3167ad1f3d8d371d013b27f72f0d63a7d6af5d96e4fc1eddf9df2258aaf39354", "-1ef77a28d8faad06f4c0fe6ede90c004c118631fcd523f126d813191939627c38652b1d7a4513c5ee1d9553cadaa74140b0091f3a04bc600e6a39a7f2dd9f0c533021e6f533f141deeb0110f245bdfc9dbfd7c567ea4c28379ee70d09231175017f59073e038bc74e55bb4f79909b214c104bb539870086b9245c4dabed797c828721ad3ff2f3aede4abbd64afc6755f78a699320f066bc74454d88a4724756353fa8fc50d64fc0999663bd7de04c21d2698dc91964e2236c13d852a51bea0a2b588e9e86c2666e87a84152cd08c4aaf7f8be1321c8c67eca7adec70581e35dd30a63ee52904ef76595a257c778b81e744b5b7ca4cfe0f1c72dd11a82d02764ce2a318a3027cf656861d544de9bf8d3d39c72ccb795d7b6b4712fcf799e0fe35106505491c11e8f1af8f16193c462592d87c3deaec42d233e043160d32f22123cdfeac5112bfdc49d72281268412eacf40d9af684c129599109c1b5c3c8c71a66d9c2469342636000d7daaf9297762db776e718d6fb8d64396bcff40eaed749ff5acb7bfa209c423cb87e86c8a1eb8306b40b4e943684c4c0188d277702e423601dc61d9af97b71e3242a7cbb08dc41a35f58cb1ad82f39bf831c69707c549159c29650afb58751b4214e7779666ef0a0a3bb40e098538de7787ba7ca55eadc87c840f204180a2af5721c0c3f841ee13698be10c082ca69d84489aec28eaa673330a4907e22679f4dafc215d9ac283c13316aa5b757178fc07724a3ceb825673e9d5fabcb35c32ab74dd9ddbc4558a94a7b439556870ecbf94f26b342ab804d1c306c726d67da5c53fc452f1c09b6ecd2674eb800928e4aaee12d86b5be934ec16322e3c852f8199f9e50af98e33ff1ca9508cf7209b31a6954e604226c27608081bc99f9665725f7fda3bf8a90a403371a1bae038be9f8291823f83bd06314d499f65006783f328ea8b1093b03c70666fae2d402daac94d3cea6a3424ed5db8a1ec5a889f348cfa221d73b0086c8885aaa5ff1510dafe76436aaedb4c07075401674b38134f4f32939840235a4f518ecf88538d35636b0bb1bc9c63a5ed1328419f0741f96b6301fdbc091a40b0a16bc6e0a63b4da819bc053a5280a7e9c6002b910a0ec2bc82a957186ccdd3e3fb2332eacb3923cb716d5bede950112918004565598f2167b2939bb257faefc4d1526d7ae88eef86a3fa4fe4f301760a9cec9ef24450a1c30eca5cb52f993ac047915baccced0d945fcbc4e869b5ad9d722d1d7b85a495cd30d534015760a3aabbeb58e54586b837448b0f8540cb427d10a1e02f7ca31ebb2056948100ffa34b8d0cc885d4cb20261118df5cbf0935b2b81ff6f68ebb495d9e99794b79135930dd76e60a3b40208c35c87d6d19fa4cd97e971982d6dce37bc1266ea100bc6be8a1ce9c7b0e28d423f11b99c2b9d45b4c3c80", .Okay}, + {.Mul, "-48f213f3cec5d943512e8a7096c59efca6f338d8dad992ec7ce7d9c28d787a8e9f49d810033b2691105e70958d5747b385bddb722029ae870472d98ccf9bbda68493c3aa56640e366c2b44e5606b190fa7dbd61400f1e9f88daa5c5f4e9996314c4f79bddcca0f6fe1f1c72f6d65b1605f8073a6012a3441b1d54825921887dd1c64f8b90cc1791d8df6dda405548a57a6f2697b0fb0099de377a981dd86f3174120e83f8d3a2d9d7db108a66e97827cafb721b2bbdaf3bfc7dc4527f960e1da6bf7103d34d275877a05d8ec45fb3436ead893adb8fe7c0431b7366452bfa59b1b83da4125fea5ac7ca9a5c02698f617586d9c2a467814dd63a8b59aa92ed37df3c64950933475335a3e918a38bedf67c1d4b70ecdd6245f620ebb0f1c1f4a7eb40787eeceb6761f064fcaebfacbe35a43233ade0560aedfe8d075c5fd239bc7f4e5eab11dc0c29d3fa267e9b958976e79ef19897e0f345be7dc1a3147a730e230d507a599b1d5422cdaa09264d67d3ada65ab9e3f34956e2093c9e426f0eeb07208f9627ad85f3790d3e3e63ac37acad7a56f2d6a1e0ffb061cda3c549477d76db278434f306ae073a858aeac225ea7df5171c2deaa834ec2d96e280b974cc68b7e0ccb5a1dcbd1898b18f3edb789411468883a2f7aaa1e83be20ca11aa810efbd7b558cfc6f7588d2ce524463ad04eacb1b6c16a2df588e4b9b35ab3bcb906", "985699f5ca41a20739c70e3040d5505536eca2829f8a575f47e3a5917cc76d383a1b3a28d510ec859e84ea5e1451cfb752535882a2f819aabce0b91e74f8935cd4006acb55603d96468f27888e7020bf5fef232b0b748f9f659a8f3b56c725c42d47317400931c5d94a90575fb1f9b1ded6f227882f4c2de5213012f1cde87d8788bd2d59bf2ff24e9bdcdc68874b125442c9ecf17dd5873ecae3e7608f625ff01809292199a8773db6a737634c5de6acd9ffee08ee0628fd48c860a00e104717d62a91b840692c95f88a27d0652e6da503f5fc241c0a23a151643b9ae85fa30e6cb123e0c76a5aa1f1d4f5b654ef27c7d091e3587874b162fa72739237b6a5909afde26d34faeeea6e2b7e17fb7bef02729699d3892ebb0452576f0ac26dbc0c1ea25c0277f796e5b0b398df4920e5ebb14225a85f88abb2142823959a2e71c4ead6d087c8264128b2838081888df064eb4632b1678ca1d2ea8391497710f438c75cf7bf064ff5b2edad587afd3def48e29129f2c25adbfdccb12261a9c844ac09790a3aa0f4c455a66cf0a1d1360691556357a30ea44463b3aa9c18bf90f70e78c31d04d3268d3e881b067483b501cd3f9635cc5dea3813299eebf25565cb51a8e91ef1796114dec2a0cbdd5e6d55169f2546f4a048c106926575ffc1d904807e36a6e20df947d84ce7787588726e8a199b843a4330dae4db0b1124d56f7dc", "-2b68690a2de875c0c8c8219fc92fce676fc79965aa1b76eb52825c066f0cc04493146e917a38ec13463fb014e70206a816b5e9e0a24058370ffe3611a26255feed778fd5516ea6a3c1ce2774c8d30c86566b02e261f0996be73b3da80bbf7c40e7bc0c569e75df86d6a958e18902b0106131fa3805b92e5312c970324a6864254e9665f41d634a2290957f546dc03297672e4f47122dd18e120ce38f11acbbdb2c8fc8dcbf7858a3589c0814f68e3c2c753f701f4665f58d08be3ba06a1c3020eb7ddf417d24f53e8f02ac6cf72e18368eda03fe21d0f6c5940046ee55d24dcda856e257d6d0215c888a0b62fc3f9407b4c35d1d1d350149a0ae35d27b21be968c0f829e20f2ffe42a5e8fd5f2b85e09bae064278326143a3a845b32559a0f2b7abc914c004c7ab97cfda00be19372904d555bef28d649bd8ec307c9de4f67eec122c54b82fb0a7a528d76249b7da053cb7de561fbfbc5968738b29adbb71ac20619ad4c1ba5c5e9162327c800bff94edcd1e480599bc4be5e638dddb109a6d0b2085ada5c9b866a644813c39952d1057b28667f4b5a3cd52762ef96e81b8c3179c6de535d7370b40dbaf3f1ef3bc02c99ec084ce140147fc480dd1274ee037061a7765ce2a85eaae9eaa574038da0457029245e4819607f40d2777b2218ad1ef9a2f41fa2b3b16fbc60ba78501ae362bd8b704539f3a55a4c1ae75f15ad308053f61b060703585fd2f3ac7961860b8d7096c2abe189e139955d81e2eb85f07be691bd0c5e1f381069d5bba2463a7cb01c1be09ee057881e9b8c32cde99bcdf4eb3c665b8dfebf10195c7b501b522e6249fbe0d3ac0f360580456115f1f17865c7fd890e967d0c71504e1fe9b013ca595ac0d896357390eba99da99e0585c470d2783c32dd13074d1dc51c48a6116f6c63b633dbaf6d08dd0d29566023596477215d7848f5ebef8e81183e9cc441cf9e2ca1f159be02f63419eb29f52f36d64d5fa1e10ff580cf1df9128dfef92343966f22802bbc43fa67a0dcb3ca20a5fd625fc69069887f9e983a5e515d80f377fc66b701fc6b5424e0cfc7cba2c59399903830f70634c7b47cb9071380c25dd8a95539a939b82195e91eb0fb35194875254e6f14a79ebc88855659dd1abd6310e14c1b8d990773bdba28751a2f3dd40b78412f40ed5632c69056471c5ed3b1536590f31cb812e57e524af59fa201c3e8ce5c9bbb2943cd5ca8e9006bc2abfa4f2b2a845112663d38b57b90610937117f47866e94c5dde7309b0faf2906833a5a0a0a34b406d0f98d4dacf4bc8da74236132451b9daec64e24ecb9dc2a8f8361c73a48f1ee70c4f012d280acf79226500b5c987e97efe489ad554fac15367e252e4c7a6c8d2ae64a4130d366b5583b24c574723db4e7dcfec3a7ad937e7cb95f86f6f6022cfc4877fc8657cf2d682b7cb28", .Okay}, + {.Mul, "-84a6c8bfb7ad093111f7161ff950e6ceaefdd30b54449cd7a9f6ae184ea9a876c73b80a7f381caa93b6262b0b74d8add48cba6d7d870ed92512bed126a1d3dba61d7d594651ddc6573771329b9fb33c054db9fd7be12572216f588c01ee35d8cfab3c28592c3111417d86606ed958caf5c3804f4d62181e4388ed86552472346700b6f166d49a539704eb1ac5d54dd2fb90c545d466d151dd86c46f8e87d5309d79fa450364e767ce6d810d3959863c103fc334fda64e7c82387faaf086def584fbb80a769e43eb7e676b0d01318d7698d146b9f2c6be89195faf49cc2a49b4de4343ad3dc6b7f2084cee2c3c5e93609f656bb9c2e9ec79af4de2f26cc7bf683c9c39e0c262ff8f93901a0f0eced3dc576078ecd0bbff59cd937247694f6645387d851bc09f6d412f500de2105db3e6c9596376925a051b814bdc70dfcb75bf4927c1f84fcecb8152e9b576113f7272011cfba7293e0ba63d120b66685cb2cf122080e243d3a0f877f9fc35bd92c51f873af1d67f55c05f52dc6cba222493fd74d134b0489ea64d1f2f337b5f3a80c524e2148b729bf55dd9180ea380436e25ff1a87db376cd4cc570f1310e7ea34c4bafd35e1181f41816cf57216b42883af618b2d50d0bbdc2db274e8c5956dc34f9f644bae66589551dfda533fe400c0ce608cab8f7fec826a29247c42ab636f778af0727f4a3883478b8d1104a29b8e9ee", "c4c686d7c48c6533f8b1e18af4a5e6afc72a75ef9c6bb8d20d1a0281dd1a452eeb1561f5be877df2e114d73122cfa56a3ae2c6ac65fea339bc9aa6e3d5224cabf7fc8913cb33cac3f4f635aa069d8c71a13c02d315055ad241f04322f7a3cda7695fbd850221cb49d5605cc77782ef4249b287b0c521232a61cebcce912ab7b8e178b28fff22c161ff7781fe336e5488363a6197d14591033b5f9b4c7c0a9253cca163b2ad5298633ee8936ea4468bcc0e4474c1ece609b2c37f9a98dd32153400d02425e907d9f5974f88f2d5416361794bf2510364f25ea0979f41a0bbec581e3ca06005379253fabe152c00fda6110143fba9de2eb2feb39888531b0a8e8750d326767b3b48271dbb0e158d6dc5c5e034e03e473693d2095d3cb08f379ebd3a316dad57165410790939668d5f5b0865208d8f8aaac189078b0829683750e7314e8c5144800431d80f621ad7e028b534707e5583312e888ca9d925a8f7b8a0b04290774c18130770eebd77219872869d2e69a53bf867c051c591e8ff49ee48fe2bbc47cd119352d4dcc644873f5be044f9ff6b47c6dbaa937b1b53e0a39dc9342c13ca11ca914b1d31bf88425ea311c501009b0dd9cc894fa9820db8612487f70ba059da1beb161ce58297a39c5f48d3a53383916040a5de46c57f98a43b14829a3589ac1e02a551a221d091ce58c2120fe47db4c66dc2e7b911a96bc9a828", "-65f6909127e7ef5fcf9bc7a596008d432acf522af86ace932fd354d3bf3a186483af2d0327afc738188755557c2fad7924147b11b9452d191604577e9c812368b52e47fd5e11cb22e03e66170cee27b1ef8b87b9f3a7fab96201252bc7634db72a087c5c47f2fda6455af515d467e94c82bc8bfd46f6b0123adbf91d05b124757d6fbc470f411ec966735118295c3df2cfd5febec7d66c04c44d81a85fa038711fa193d5e5ae65e6f256ae8839c4d9237945bc1513e3af9501bcc14f9db1ff5d01244d2fb1423da36f3d94bc26930c82bcf3c4e936e8f23a560e3eb7181454f209164f9e5ec894191e72088ed4839681af5a82fabe797e014faa8f56ff609e25de82e4f44bc08b3df9b6ba0d241c842d5919833d2a0728359cdce2ca4d0c3b0f6e7887682fcf13123b807ace7108060d8e6f2b860c16c6c158a75d6211e2988801ff3369d888ce651170121686a6d30ae6d525e3573ac37db3e4f812798dde8494f4cba86002e4608b4e55fafd7541be62ee9c2ef72ca296cfb431c78e866216474ee6a53b596cc3ed4deb36717784fd4fc612151167c8eea581af3d9eb385c304a524c6c94cec6d4db816586a948fca900d5855ebcfc286aaa6ff63597295ed3d20aa57a813944d23ec32e717c7548ec675e8416dfa579850aa722b930ce89f7a7db8ecf6e64d8e2c1ec4ade714f904352baa28bbc760e396fab1339560dbbbffd6caebbd14b6c905ade1acb8aac3bb527a6dcbe47ee08a418ff1dfbb6b909180435c8b37659a77574a6cf8c556216bd3cf269e90502081ffbe39e484224764b26cc728152778b9a9de27a0bc7283fa0bd7815212021d85cb068c610cc56c28abec078ca0f672abbb5c1b1d36e85d67c3dc53c232f93d095445d87bf5138b5f5ac03903d1f87166ff8ece7926a5d240f385fb6808a1f8517b51b88529c5ae38d9e65265eaaa895a1f216b6875baeb090bdb691e1f660b07f2640c8f44849c1f7cb97afbd40c51136714febf635974fcbb1075fd4d3119fdf48dd3ce037fe89f398e3ff153fb60011fe7b82acf26447fa081163cb4ff21cef259e617442a4fc4c38f388fb58e6e791dd8ef68502d6dffe4a673bf5ea7afef7f7280bc07ac84d7550e29e1dbef76d9f4a9baf193381292ab463fa91ef1acd7a2a779018b23fa0b0440f774857477fe70cc7ff56b6b1f303dcb9d819e04ffc24d90abb0c097f0ca307c85ddd58909be85e3f1ab8cfc95efa015fe43fd88910372dd5d1279e18f3e84af8698119ef12da803ab7a90520c48a1c56bbfdce92c123c9c46436fd76c62ad053835aee47198381aa96caff25fb39d69128e9162ff25d7a20e8c0b3fbdf5dcf2685530d344d1c909437252d28a4588f6f3cae390e28e5031c99af28af54fcd3ab34a1885ccf9eecc4dc82770a183d6d260d7cce635e87e9f7f0c0446bd30", .Okay}, + {.Mul, "-8620c84aaadac9c06ad0147bfd0f020b0ef6985507efeb4d2def5bf02c87ec9381a4024b90f69b440df3fa93d24401cc7fe83e2e4c1344eba3faa7ce95b2bb236cf083b307bd9d14a42abb50c277cac88b61741fa71dca45585ee12e9f4e864def1b0e31d78dad238d401ae3388ce756c16d9a43cc02789f2f7f73378fb72cc5ccf490f207d61cb365ab50921e1bd6ee57df52776a351e23dafc23386b86247817dff50ccf18dc67094eeafd8da4f411b7472168469cb6b3c25bff7838bab3e1de1f49174fcad3a24e7fdc2ed7ae7c6bb93db2d57928a65705c5d1e2da5aca2be35848648c09bfd7321fb62b015e8940d07ea17206a7cf1adc9c02f5fe3086afa2163a279fb1a4b4af8a6d6f5014317fb3b72a4ebd33a6fee90975bcce4bb4c8ab8d5cee51b55167acae7e547bd4c96edaffa25f41f627e2a6d5c6af8a1ebb5208d5f1ed32365ffebeb3a05818d48115721b94f301d4b6ec1ce688cd74575c197baa7bc3eb27368c97f367635bc7bd74301e4a432226042b88d1ab4870f45fd9e985ab95d29bab83958f32bfe5cb51c6b98d2a5c2f4e57da39300b3afd8c19e0ffbdaf2d4898181c395e6205f9f1870426485427061fcf1feb947d94abb18f33a767909326860d2a0f62404435adcfb6ebeb80735e366822abd32b8c08dd1b2637e8f4ca395337cebbda5efc8f91e3192294bfdbdcd1bc4cb80123e49bb738fb", "4d38a0f7d4adf171018d04c5f5f73db882c913d73b0d9e4e60ba3c836d24663970a3031995877ad8ae17d906fa0f7976272e58ea265d4031f2d2d18b866fa816820837cf8fc1f82e21e22cdc12dbdaaf7b7a1d1e87ac2af718385383ea9d9c86282a69f41db7a937eaf18175fb4d72a0fffa25aacc8cddf44a1d8ceccd585abf8e0ed0c93ac0c0c4ac395f53bf91a20d36be1cfa649540c189dd3303b36aed172c91d0a69a5069007482781f67d61f43ea0464023c9602723c2e595bd388af404f0cc7ad313c3a1d779e1f1a039bf162ee7cc634937cf165fb9e4dbe1a29d2d6f5f53753897ca8785bb5043604d2237fbd1f0a27e51c00dc7d1f5231c95ae54f121a0235698a06ae1ee70c2ee868fb8ca4bbf822a3ac68d4167602ee41f766bf31b557353ca63c8bc4d95ade23fe20c5617b634f5c2c97fe244f867ee0ef7fba5f52fd40068c057af702471f4dcec25087b38f354dea07db56a6da2779a1688c0502dcfb88be57ca783fb62916efd01d203ae5140a9c6f5811a1f4d4c66a33f3f86c1978412b9da951c9982733fbdd0488fd5106baf36bcf1680780af8e978836195ba8d8a082f311ab76654b87d8b4c520459947bfcf7883c76278cd4184844b8fe2eb9a867ec65c6f71a89a241249f54dce8b639256cab6ac1f7b36d34a1ba8a7237579ea8106d866ffbd3d36d5fd3cdc37b44ed1bc7e719e333cb48283fcc", "-287587c09bf761e3db323b28cad0fdd4d5716c68292f8c2cd903b7f1202527654efbd906deb71bb5b0da254c93a6c622dba93bd4ee9b6af0d58e31cc1fa8871507d99ad6aacde2fbc1e9c751c6a51c8baa373c9f941308ed473487ca7b4038a80925e4201ff33a1f18b52144c571ee57abf905e523c1fc8053ae80c443be507f75ddbbd830c6490280c1823b5a1ef9396b0caee2f5b2849a303e9d067280602afc0eaaf8a77ab1492e3523ca5853705603cdeb65b9c8f06bfeb3293c4ca249439bde00b7c692daa9dcca81fce5041a7c0a0a1fd0315ad2f4e06ee121b0b554daa6d83b68ed3805429b62c41c023bba84d3a8398dc485a8e37a258676b1585bf5be9f5a769a95cb894e0d06335aceb3406789400db252b40a5e8557dbb61424e046ba930e7715af1f1e0d232bd49c3f0610f0ffd473ea8867ce00b2c095311a336e1e9e98bb9cd1d317b67a6ee4e1290d3d0da3577286aaf22b4e3e25bb7819a83523c580743381224c3b1507159f95889a8b6a86d2c5e6d5c18e2190eb5f148fe43fd675f3a183111e5dcdc2608397a0e9a85850387111a924e86194ab8a7a93a1d7ae96bb2a64f86c38dfb66fbb4a18b65b15f86dd5f9edfe5225579e788cd8bd398d1ec84a0ccb33c6954a8146dbdce1355d6bd528cf783eab041df52c314eeb32c635711c3d2c87b7bccbbe7fc2c452ca1d67d431a3a604e42e93c2a031c3210877e3b783390498253c2bf2f1e118baa24f6c71295f734812346dd0209efdc9b99077298f1bbaf49f5026c436bf623c74581eb0a0aac794435b7d705f68c6c41396166bcfa308cd50ca7b1bc35d9353bcf90dfb8e83e406ff32759312be5b47cff43c29d0d2df694afec74cd86c59783a895eb1de5a6019442356a70da594c4dafd0405c9114dcb48d83f04f4d8a350ccdafdc2afddd664bff731b5e113b5fd305d5fdf2a0ccc29e6e56856137b5ad722b475b85d572b24e0477ab05acefbaf6e6fdeecd46a1d9786499860d824435d69d45667c66d349b11d4cf458d15fcbf28a1ed3cb29703998b800584da043b3e96095a9db1edb40a38c3d13d962262742f45cd6fec6cb5bdfab7e012f480f916dd7b98230a0786ed5b8cf1c0469abd9b8474d0c97174e67fb844ed5830c3f17f3b157e435d6e6bebd29e1c848719f798356d46ee6defa1e83cc1bef7b5f6f56dc45925b14ea8918fd2f1c67ee91eabcb0f4781747028b3717e99638800a98a7009fb92d3c78aaeaf8ae79678d26bf04a8523e98ca76e99946fa932a848a57f4d2cf40a0bfa3d26c7ecaaab052f19f5ae218445d37533363ab1ec7aa50f36f02274185b5e712173425245a17a88a7958a3eaeaa63300e01066e79c55f51491cb22f0808a13882fdcb9de0f27d469e323b212bf2b832edf4d16dd3a9fef771aa77783b5c2f478182d476e92eac3f2d04", .Okay}, + {.Mul, "-642e924269f05f58a0c992a248a001ec33e2d87eb4fa47dac765e8b1e754e0c02c0a82531fc997ddf2aca86798ccfe625a744f6d12586fb471554e244774eeca8251cdfb33bb5703a631c06fd4147d18c06c6c927f6f43135107f0a2ae88105e464328360fd08658209255e4f393389e1c54ba23f017ae9ac5d8d1cabc1912ab77b6405f0d1cacbf7bcca54e3280a77271b0df3272d3f671013709d673d207faa4f14265fc8587c185efb2d209a5ca7757fa6218c3769c862d35c9c0c60755c989744fee3b7214c6c60323830d80a43ee4b91bdb0a260a2dab67b071f1cad7ee103457fee039c9c4c90a9c165e2bc7500087f050a87c77658ce52c08517b8ce8f1b821ca062ebd2733bcf2b9cd478df8207838ece1dfccbe5a246a5af176aa86b49b483993075cbd11bc2f45da4daa571002586bfd6a68ff151d78fe611513b88f4dd203f1afbbfcd85bac7376cf99f4f29e320328c88d42f041bf430891a6707205e8114e4f09bbfd483abf9e7168ad546200edd8ed4738fc301a004a075b85dbf7f37c3a92222bb9da0370684530e0b3108a120d31f8390c3c807c43839ac5455634c53cc9842e40b7b4262eff0112064f9624b1eb52c63b2c6a3c876d6672360c86137419d42172fe0554a016eba194a70b59a4c790e8f9b4481d1a712d0657ee8ce87e23e2e9077f34063625e5f9c87dbd6691885da41179abe494e853f7", "a9af5fb4a33bb1d5ce1d3f8bde614e64ffd50f28f8e362450027f18b0f332350c3f1ffc4219234ed2322a6adddf5709b85610568a37b354280af1b31296f4c252983554415ceca54c4a1ec1a5efeab1f556079aec187299ea62a87ad0b35705777addf10fd4976081c18f87de41b290d8737174ef0395ae4c76199d8d5d36d6e1c3e062fbf0836c5d76e6a50a42fd4caedb8a4b71b161d7203e88eb773ab2a6c8ae71e68f24e2db2c2346ff57bd522d7f1d4e07b450966089d39136a29864adf9e25b9367ad90428887cd06aa922476488a27ae205a9aa4dbb0d5af2e46404c2d3a7ce2f20550b0ea72a34add9e8d88f596d723da20f4e06025f60dba3c6b8334acb1d7703951c5e7c9b5683eea3745b1979ee490570d8c22ce68a7ce07614bd3278476c0d70a6d24137a994e727345f9d1c0a41c872aec371ad35f93b53ff7db75d70182174341ad92d361242f3eabf17a2fe41f227e4d16024b117b6954a34f662045e133fc7b3163be448e57523f5de1c89ce59f9ee77ff572303df57d60bce13bc70163e96a463fdf82eaed34271632220c6bf44bd442dfe3d9abcffa7a67f46698f73a490a453e1a9483488071495f86c6149562acd95d9148b917e3729f7f68673c3b411cac4064ea73fd31d64740d470f20868f4c5e3fb002ae712769351e41be959e93afabc0d52ab03261ed3b77fc1e903b460c0280a6932a4c3399", "-42675fd7cc3c99b93d6ae9072dd342ae7afcc68985366c1bfb9c9e7649c9f11df153c49efcd185fd789692db3c5018475eb36a7c7cf70b2e95945a087f12eef851c27fcd5bb86baaf9e85b39469fbf2785eca7b89db022471b4975976097803e818c1b3c7f57551ca8d701acf32786d29793a51d8bdbf522d344db02aeabf88d1ce814a8b7e96431bd181baad96cc2eaab1f0d900ae2f4f65411d2d43d278a9f8233f5d63e628f198de616f3ba9333379dd195ef8036d89979e3afa1040a19939c56275973beb3775f35f68ba2e17c917ebb9d5fc2388a24c23d2ef3d54c3f7fbf00d6d574c718888d32691992ab9c5492d9488cfd7a80e163419ce15a3795235f4b21ab9826f0eedc744dc824072de667b2c5e20548044a82c1e5b38b39d633c8b57cab1eece9194406a1407118b448fcc7bc03026d4ea5557d09679b9e38e4f96804dd77c7f5ec066f9dc843ccd7801f0b6e10638ed492e3b52771f87423dd5e55639bf24f81999058623811deb18b87a694b035b6646a92c3f974df6ed2dba78b9539c36e5447a0c37d683c406d37ec18fc0f16281ade02281bd1cf06b742b88f746a0f2f49e049ee280999b5cd90a69636da9237b2934d23ca5da617de7e9a16759d00b16276586e39dd897052cfeac963d503641cbdb16084bfc94136129dbbd0e8e751ebf83919629a91c78a5ec7c1abea26b468f8170b4c8901a46cfd17af20601ed711844340452aceb57cc9ebc9587bc7eecf6c662454c36918543c9027dfeef826f6e6187485d97b302950dbf3a3cc07acd8b765c1ee21c03298c4ccdbab3b5e29aba70b3670864a8a9d1c8c54917eab8341efb6236611bcf3b0828a439ec4f4c8a115f3c56aef5a44c10a06f56e5eb792b9e6d7f63f00b9cbf0af4449a0e3bf243eb06c9da8c97d8606ba0268de95d97ee8ea01e590eb9263dcd6900ab78b279c3d43f368e81ff2de22d8ace2b8d1bc9673a42bf194cf7dc0b5ec007faf1b2c2188500b20dbc727cf739a5937c843628048b7e6d209ceb7328a6558d2ec32509c48d3478d5c41ceb5c07345b58c3f3911f1f313d71262f82bdcca35f10d40fe0a8d761ef6347e4135214cf7d5e2838a4a86539c5c62e0b847a0c823980fe3a8ec85f8e7932389fa48446ed7ca9ec490395d861ebc716aa14c14f07d7eb9748e2cc21b9ef2d2e4052bc5a37fe7fddc0fc42cb638f55625f860201e5906fec343be7a516ee00f341efa17351e7ca83495b3f61e563df3d955cc68bdc2eff0a9b1352bc8e685d30320116cfe34350c3e1e2a11ef63f14b71a4c512b97a41b59147900b136b83edf9409b5327313567de0a8eadb51c4cbf59a36ade25253632505b9bc3ef53470b4a9eec8d583a4bf907ed9b398e4bd0c7920aef0ce41e7b818c50ea10d0591d883ccec56a64693e990352497812489af8dbbae8639f", .Okay}, + {.Mul, "-e40f360bfa3f9fe909e22068133c584b124a251373946f3b88ed108f709454a3fa43f19723da084551c1afd4a90216f20d411852d8055b42495ee770e2f93f7881413bf156c50e39fad7002be8fc6a0ef05af4a0b2c27df1307d9d20ed56866d387c6ab95897dc7b21f25228cd1243ca9e3ce3c0a436de4a53a05f4d3da0a192f08911c6304fe9dbfe1274903468b7a7dc8eff1663839032ec1b7128e9b08474a2c103d07bd2ccdd76aeec9a9b082338fdf3878d071b7397052dc3d8ce06dc93d190ace7b9efea77689883cacea020244e7354226d9c326173c5c79ba9d81ea2b6c6db42a5aec3a31555af6d4228aaac47ad0dcf2cc784f5d69bf4a6c245a7a3709288e0b2acafb7f4a7ec846a8821a01fee7b084ae35a0bcb2d2f0772f69cbb9e41ebf59c1e0489147eed882f0984eb82dc5070144bc060b3cfe97b90d2d397cd21af592f9808fdd0e669498c9f88aa94c6fd076f3a4a54b9560f4322dfba371c095e49235d9ce32a0befabfc82496300cd2e2a6e97532cbe2922812da5ccb581c3b2368762a5b4bf171d6ce7ab40f639627f197331de5fbaf2d5dfe44c5474b65d3cb1db03e12b537a2287daa0cd35f76ce5abc9479462e84741b8e858d0e559dc9880650c63cd90181a8ee047d69edbb89ec27bad94cc5ab51c93cacce0d018ebb96fffe2a3a6b26a4b5c281982b1ff64753fbe9add6c3e610fb52545617", "1fe0a28ba65b927285a8a2584d5ae3e5289b77c5dc575018d09eba34b94e9dd7311dda60afcc9be39b8dc88a213221738928400bb6de28ad3fc595a646314b8299047b28a22cd092e52f857919c2c9cf655489590afc80ff9517a138c79165f86634266ff632050290da41b1bfaf3546d0bf5295aa2676eb2592addf93003dce9eb15795d99b98b9f9d097c8f8e242e28d31d3167b8ff2b6c4048c2c5a7d4e74e37c7984fe516ffe92f07aff073c7180248d1e6489e4a63a65237953a988da21f3b3aa5d1ac59330979720d0c03cf4e09aec195f91d9e9edc4243400bef1b0e44cbdf0f8ab35b37aac4264e4823e8ce94e0f6c77c15c9ce72aa0e109ee4bd368ec21cc40e80a0e95214d128913a1d9008e1a2468b5de0e17b57fb5bf5cde82e0728ca8b81227532cc854426d6949669778288c3801597f78aaa43d0b71c6ae7db08cc0fe2514ab9797cb1213384104ac9336779924a4122fa2e6daeba9701f2f88a6e7b12a42de402b83cc9e3109650e4e875d33e5818eb26d71b9617264fa26a879a50448100dbe519138ad4af56e899b0cb43807da385def4e82cf20ada61e894dde77038e4588a187745da3a19c1e763e68b78f956df4d3cb51827291cb4f8c6aee3ffbdc7ba83d2a72b677dc042d75344c44fddd553fddf33d7dbcde8fbbc9e2ba4ca40b4e48f01c517abde9a20f8c0ddfa408d639af877ce86626ced078", "-1c65f5a8c67209d0f50a919f14acd5eae2818bc00a1fe13924af169023a32923e7777e3b1c91ca412ef86741eacd67b82e38b6147d9e80f695597fba0c63b5a58f37ee760ab540b7e93b81bc897a6330509becab23c54c75a33a888afceb1c7714e4a29ed458dabf7532137c3a313082542ab04e1e2727aedc7b74ad38277ce5d828faff782ad49c83510c2ab5422e6306a424dc00dcf9a1ef48fad81cf086880b45760a9ac66275a8ab7d0ddf772167af39c03a2d78da47a873b254da8c22c3fdcc6b17b514f330c1162b3fda893f0a461e0e7fb45f156f147fda99b6f28bd76d4740134bbff16f30b1437d418eb3d9f02fb82d3d6c4f6b56e37a616b54cef1f953f6bea3d32766e068542c7bfcbe865018a62467fbf0ceaae7e43052011b9f5f39aa4fa242968098d8427bc49fe27e71ab09b1243266603d176db962d07f5ab1937455f5127a4b6070fce908d53faf701b896627f54bb32b5658d8d99f441c7c3bb21174af4f3d472824ba02e1338ce6b43588efec005fdc7de1e8dad3aab17e30b7f39d00a630bee7dbb640ba004236845e034468a6452350eb82b9b4f660249364297bc49fff1e73859fde45443104755ebe15497c4cbbb253db7047ddb1d0fee389ecb5e81e548fb2701eeeda25d9d70d4a50631097059e1776a4c286e25354f486fa97ccf76170a1edea37a982cf25daae7f4619585aafb78958cbfb1cd6f44d7c3962ec93b0fb0f94ea27df6b4d5f7c012c9244c62e4e398e6bef16f722ee98ba2c736f1e9bcd387cb8bbfd23ca4c8bb42362f071e2df6b0291f75adc24ae8ce780143868f25d94e5c53f74166e3558524abe707a69605779d718686b40897783e6cd5c0eaa0386b70afb9a0bb6475d34c3598e8f1bc2ffef468956511f195a43f7e855dd27ea0014c08a0c29c2e9611def5bd0ae7ac3381233240a1ce65f6c71f32b49a9ca73bc01c201a825d82206f78b4ce054a3d86456b3ca7c4aa2e293dea9e8f1fae0ac7ff158d9f66ab426fb4af1a588e290762ea1318075ab6a092831d5f68511b5b7135b0f4a3fa5a57ed20083962358d5131e2c588aa20f9bb0f0919cf0d4791065f2e4590b3f272512faca67b0b76baa245b5000918501647856541963df60cb2fad9bc2b9c01e83d8b6954d4d7bbe5156bc45d592c374abcb3f10617d91194ba65797d4f24a08972223c67d1cc214325edb8e551e74b4b1e1654aaad3e21f9d99c6242a2eeefcccc09f77ba3ce6411bd5775f4d5dbb40c5c36c3ebbb7a3f2ce06cd371d05b9d4259f499b3357b43711c2eac1b2d6df269414af33b451df9b5bd8d3aeeab1250097be795477ca9077c9dce7fbb24a34baeffef0a102a2223b529f75817a23a08b3a123ad2b5493cfc7cd7fb3cb852d796155ad4dc084be47a788ccbd168abb47e5416371c3ee9f35c9dc1281cdfd0ac8", .Okay}, + {.Mul, "-309087d9b5810b7a2cd5200a7a551b2c3926184c1c551fa73ba5422d47cdb3cc2b6685c0f6e77ec4ce8884503f6a134e26d71330b8c18867762ebf55251298bb3377d70e2ccb6566c44c1c6f3ff06316cbe47f89a7108a59b4f6b85cecc14199c86bde58326581ff9f521f3fa4eb281e6eacc035d9c0b02fbb20be63f6bf5d0cda940d2d870b4a9d69dce3d6162bf73a3695cd83385af1949e2588ec7a8534d094aba300b488f9db604427394ecc6745387e921bb8f82b1455660fa83692949001f5fca2b21bc4048e0551de4524ed96c73089a49cf8aaacf92cd6c6ca96f40e28bae165f76fe8ee7b70940e18b08ea60e12d3fe2303c6bdec94fc0fdcacf79d15bb2b77e46dbd7df56e5cb88ecea7b04e5a0f259b6974fc97063b603cba7a9a8792c7821280888df9dbdfd151bfe21dbe83084e2e5dc4194ddb5125f42a88edeba262440235683746e1c377ae6c41483adc3293c834b0685c4be8dcb0a3ebddd8e4537765fe6cabbfc850a9812980465231b92a30eda8a2f855da909ebbf06638955845a40391b223f0386938752ae3b3549a62886fd4e296118e0182871c1d03b2d449c96bda5d1495919b9596e4e6b1f10c4ca4b28607dae576530d86e4e5eeb279f202c02e18791e4d78f4b383d36ea199dcfb43c83ac97267c15910f0c4a852302c8d9972c64c4c4ec942773a474e69ef8a47e45a0791ca948c1928a507", "46d248d1fb60d986267718dc4afa09334f2866a35f26e096c0054158393e7d39f84c7b0adc3dc5783b09a473594c7a0014c2198f232aace578bda5511749ead806c30ead27454318f603e61913676c1a9e451d3bd8219a5b3ce817c43f36797a2cf31bc1c132bea975da63643739ba19f61f3041a8246093bd71f754fc8c9316cb3047530f5412c73ca5a37d7fb67dfcb52a64a7f80e2370e5845f2d34ebb702275ec8d6a9bb67171853c9bfbda4e980f58304b360d8aa47f7241ecf414484f53830b049932be865ed086b2c0582d0771708c6c53e6b140d303e635f22904487341b363451a063b2a68c603616b76861b7ca56da37b4859c1a204c53f25ab2beaed93e14954a4a5ad11e620d4e5b24909a574e513f9eed35f5b197b5cb5d0848303e6fe6acfb551624d1017586d924e34aac08b4470358e6e6b6674f9c0c6fe7401e5207df48b30d88858a7acbc367f5e2df71de39f90b4384fcd0e776e26a3eb8fa68f344f9c208f59dd6d49c3db2a67e02c5509fa561a487e0ef7cd8058d385dbdfca869c78c42b9a4ceb289b11726024d164649eb4977da933086c976dbaa57bd9d184783382eb5cb6c8b3fd4facf93880728c9a3c988e36d26c713404f20cb411524e37393b0edfd64ea6a78c6c93a68c18bbf5458eeac506a38cfe7ab2b4214db9da3b6e09ce5e8dba3e8bef1314f3abb75d3295cac00b5fbfe933a341d", "-d6f6985741c6571a8c41276fb68f77390b237e6011dabc73ff7ed8cffcde8e3acf9258e06486268c55a61f9bfade8eb085d5c6a8205a2619fb8582c199b98d8bf1b0397cd9382f9fd330773e71c768b337fae8349ac01f11891a8941564cea4fde5d671b789089b609afd9e53009f1f417971bcdb0563d466b7bf9617e3b0d0f53aa06d920480a55da46d50abd8583f7065dd767e860ed32f913b3572bbf8b17df514ec5f3cf6e0d5de74c3f96a4543e11ae599a09917cd3ec26103a403b71f25d150056cf63f583e6761e1d3af0e2b8681d95597c4069cdc2b10fa452d54cb0e0ee836c113f8fc0e83d405426313b4187f188b075656c3e5da84b5a2fcb88d3cd76c53b4712ade5b64ee358818072fe1c2a9b4332f0dd67b760eafc881fc137e6ec44a47a182640c3744dbf191dbe76034a4b402c49d1f830edeb6c5186def7bc198546e26207be5930e7cd5433d965f6a9747cb5f4164b11ac0ed9fdc385f20c265bcb24319edba74c8683aa3743c1502834f90ba56b15f1b8eb413b26d18a385e58f1cf479efdb7215cc9d6f33aa39c6be5f0093c0207ea736e027dc8dc55f27867881c27a0d39ab10ad001dbe2f709328cd51a85bb52adf4d57a6bd4dae32d36b40237c99adcb9e66c3d610b93c395140d4456772df562b391bd702add2e60d0a1234e0206678ed0c3c94240ee1508834647805a313ec0cc34f9742d2b55d5ca7e162ed91add5800394c9c213ea4e05b433e86e5cb999729e0443637b7bfda1b682e07022a8b5b92288141f313e65e82caf0d1c446d3a935906c6ea48dc80baf9e898a1033b3933cd49dad8e4acad566a01d72aeb84bd0a47a07905bd175620be776a69a6ee71a4ab4fd80652d54db1691a7a3ef175dd48b116f82a0dc79e64f928e1d9e83d7918d25bf46ef9dacae26f3a8ba6fe13f4f754be4b1a34042dad031875084aafa45cf28294fb14f7f4d2280ca4201bae26d2a442f9d495379678d5889c995f04750f86d907cdb39a2c6abc8faf6abde790bab7a1fad7e6d902f191beac4b8d0a97fa11cbce183dd40c2dbe777f1f41031657be464a5a0962a01e71f75c15a529f7f96b632c146e9cb93d93c02c5fbd8aba78386d2a6c67a80d565be4f96d4b19efab14ef5b5f9260a0875dd61717e68b90fb7d77a350395538f9cb33bbed22653437b6be4db25eaab0f8ea768e3493296a85a917b152992fdde5426e6e41199e7164583856d428b2234173a647a6b5dcf51c821c19cadc9b8360a1fdf45c913d117b15f35f6377215d6bcc25c6a9ca6dbdf3d84a8dcb63bdf4d23795bb50dd00cf66abc8d126e0c265ab521b6231fe2c48ef22d174b62a7b42b7c4356c5281af7b3be44b2b570e3da055bf52779011aa11890dc752c423f25871d6e43c94347b888dfb335a59efefb4d5ae48490505c74263ece583b61dcb", .Okay}, + {.Mul, "-2f983e750ef58aef47c1cd39c7de0746f669097a5cd53f24df5fa07488716f8d9aed85fd7986c22802ce15c5df1f83a980554d49acc894972c15cc21b98bff634c88cd5a3b55ddc3a3459fbf8b43c55d7ac2aa73bf64f518c66714f816687c503aaf216b53a7be2779ed45b8aa74503d97f37de65df3ff6d4dae6e4cd681cefb0f9aad9650dc95cc6ecf43efb55f981b009b2e43c29196c8d9bd6b18fb26eacf84a93e50f6d293f233d226e4b2e6709b8df8c5648593f6e968628a267d36d457584ab4713beeb0ede81d13fbe76f182a66c360747d6989ad91cc289bd8019f6842cdb244c87bd3189155ca8ba90c4852118763447923f3e36f9eee24e0845bf67fd73a2ca31f5996d241685cb610924f214c46a8ef45ffe796fa8da7d45a53e0794760b2d08b1b8f303df440ead3f89c7448709f38604f945dcee64826073bb2cebfd2d3dcd7f8386f691ccb9f7afe9b64212b8dc02524a1a543c1f6afbf255a4e43065c0ac18999a698fcbfdf918ac3bf600f1164f77e23d1e78cdf4f324e70cfefbfc9ad39195ab85950b990495b8766fe918c0c6bae6d8b5d41753d815e95475afc6a53ded8da267f977ba346cf8702862daeaff6bd48e8cc78e3918b8f45a95890da323bcbfed94b4de04bb6fdd269e8816bc0d2381168672834fbcce2b3642098194ea8535caaca36ded62a47847ed47c868746e0afd127f3a816724555", "6bde6cfbe128f4436dee96ede0021b56a579ed4d84f322e5e6a4305cddf027c35361a31fa27d547c1a8cb40d75201f970d426c40141570de3c5e42d092321817a5c7de78e071eaa44529a87d5aca88dee0b1128f689f8ff0c30089fe3e499aa29d4ee8880a02f7149f9826e9442c80e76fd42e9fcba9625cc9f979f676568e161bf58bbdd18d357dec76a2db30b704a8878f529ef5654783accea2b62e95453fe919ce8b1a1819a44a9cf39ed853734a759721ccc15c99ba70f36b6eaf624b2e555906030e71e38bb56e1ed89cf79885d2d03b7c4f08f0cb0942e4bdbd7b0196006e49ff410824b8dfbee91aa7f705a9c56298b9f12e3f60c858a9ee2b3472a93062cc5016d08ea185b00ecca79af7e0d982e4ba5d751211ecde9773814c6db5d202b0adb4f8871f40f0a16cf79014abb3da2a101594379c8b4acc304b4793611ffaa413cf16e91c0eb5ab0c3738c2c7eff527d91034bd0cbab033fa63b14298cc8d50c61beca2191008ae4bee5e71758961ce41cb17c6b994eeb3f60a8c651336ed6a223509c68d993e21c07a023f3f8ff209c14ebc36ea436de2df179c2c2bf124f9027bcea527bdedd6ab44e03d603f65f484af5248ede2c593dd9f60439a4e94e9c15105c61c31c7ff0ee27bf8af86f4a63d9eb706052cf02cb607caac4a98f9173449be58507407216924613622652de7ca49f225815c09c0fe7f4a14c7", "-140dfc64253ea52e091aa44888c428b7cc8bf521cc2f58a6ea18d862ccf9ba86d54afc560e2b12bd9c4978ae557c4bce91d47dacbef4c2479310ef469c0bfc1594a593c27a4b3fcdaaf2aca1df6cf46c5f5d05dbcf36c8baaa61cad320d090655b47ecb27d8af8fc541d3975167e0fa2e5baaa9241da147c0a6e276c92b1fec24f48e340cc37897f6ca2b51b96917920a1828e4fff4cbb308a2ad6557938f79f5ae49ec4e0f7af57a8c501bb8924882f8c5832f62b0be65485ee9f1e9ab9656e070d1cdee57cf43fd41c60169c0a34e746692f1f6bccd5c62c0cb38af64601c4971e2bd8a58b18e3b826419bb3cf15e0a4d77bcbb7c2afb4f2d26f9b40a9347d4654087a4c00a6af2e29a3ef0185c139d2ae8416853e94b8185b33a42bc873ce19eecb622a90a68eed994d95f3ec822ccbedc56fd60ff5fa35f37f9ad713a3708783ff5f85c44f1aa626240fba308df4cc588e196f1dfaeab3e5fe506e8c0a68f7e10edc86bf92c3270899e185a71d1303cd02261fd8ead965c680796d50598839f36dc1c4ec75fe568796f9bc93cbe82d1f00a27e0b0b42df27f58c94672b31db113ef916dad9c1e8d156d3f928f730164cbb4df021a210f2ac046d13ba79e1f3360d1ab94bdfe5cf2c9078530b9809ee2f3e6d38dbcf7cd9ea868b6516ddc1e7022f5930f1431b60d53df573c37828eaf7fe136c054d6d5e58daea4211958b48a6c29546fd3a600d9bf762b4624ec3f621ec98d1be98f225ee95ac4e30b0f6a3f2436cfd5daf513ae072f863a7247095752104f17e3f3edbb36bca05bfe89dc9fcaa9a5139e1dfc313e58bed5685b21e826cff0c5b7ba9efe27b22fe6792033bb5c802317e591111541a30c66c3b01716160922e40828f571f1bbb7b334cec1111732e6ba236d38b019f1642d8d1dfc80b8131204f32a57310898ef50967e56dfc149a989c2e238de68621aedb84972e80366e2999d8a54cf2e2ffe9f879e255a02ee851258801469a6d4923f13002fc85c1fe973e19630c7c951f96e0e997707f550e3abce2c968bbbc79a00c51469a4fcaf31525b3ccd2197bb72095f32ba6f17050d846971d8dd377ebc55051c5be80d393cf1889d691efdd02af5fd875ca65a47efbbcf61672196b2612c9ff578c8a6dd973b794f5be2255bc223afde1a68761e3d5f4e415e46f0a6bd217aec02fa033136da00335449e6770d8d5d5741e4c7e67fe441010b00b8cb3f73c0cec32b4aec479a15dc5d438b43adf5d058349cb63f7aeabb11c77c79b8c47272c7a1b5dc0393dccd4158f617fa60ccee7cb26357f346e838c7f803b9e4615fed73a940e22c5ce34d7f3f46dd94121ec274571be2798c8d1c9b393fd32bc420d207034421998d557a1e6be0566110cee07cae71b7d493798c390128da1749a1189f65d665d2eed8b91cf7c2e412d95d08913", .Okay}, + {.Mul, "163fe1547e298a190ea9ac67a805854a4d746de8d209f3b4723e55727f074e9fbd21583ac665cb400a8baea2e0fce7d9377f8b13b3cbbc7503e9a2e688724024caf8348725bf448a04acfe51442c4cc33b8135c3a6c6895eb88cc2a493dfff4aef1967b5c77f959f34d380b14d83c1f7f4ae8d86657d374b1ab5e2fa94414d69a77742344583e7ed61a1fd694c7216096b49247dae2876b7d1ebba844764aaf67b550ce01f8a6e8db83884c0c794be6c3cec8a58552ba56def0b10da2dda6fd4d4d34278a2a472d2a128762e4b6ae706cadbfdcdd46c80aa4736ad631c1b28cdeea8194efb3ba285b7d2a24689b1c89033ddece62339bc61baa45a6d39b0253ae04f2c950ff999c2200002d06a2fb1720af3d683c8b2c3b23310608759ab5c4d30a70a1f070f7854026f73c9bfa8c11b6d4cd4b77cf422de0d6383205605ea00dfd9fe53415b31408d9d8a4df0a0ac167305b710ab3cb5e4b8813dec3c3d2f5090f78c6c68ca412420e2ebb7fd65b9ada4f244502fe1d7fa3f2909837b1754a1d2725e6703f01801f872d2a390993b5a586238a84ca6aa1d11f8cf9097913fe2dbc5f9b38583e340c70a85178abdf2f64bea5750eacd3be2ba402dc11ada4fce31e1b8251356049e91735fa1be0c2f1f9f3dd1d639e2f5aee836c07698ad655ede5c49a1a201cafd02920712a955480a663e92a070122a34666848bce814e113", "124a8a2d7b9542cc22a6c195079185f355ecb845bf50d24690234dce70c0b9a48b8391a970b78683f97e4854b9ac6abc75dbcf47af526375328636a320adff07ebd86e28b5b32b89a3c022737aa3c95a185596406d5bfbd5ae12808bcc54f61961e0d294e5843bef9b42ce0488b9cd9035a2053b9001713f6897983cb386a3177acc3c1ba517707609e87bd6b6c370de35e25595a61c08babd32ed2ef9b905175be98e144ef4ed3b631a6d817007d2a4e1b0775280f02e45a54799c0f028eb9de7ebbc77f1f33656c9d3f278e29933cdfc02fdf5a17a78fd6bfb6a7bd1749413f9571672a692cf870a8d4b0f90176bd7b73ce5e9f207861c02145bc14b250acac134e2813ad0f86dbbb5bc7508c9a352b5bbd5cc24c146c37d61f8cfba9d53505a6ba342d464b36f7f19bdad3252bf4cacb0457f9d6660f533b644f4a2500edbc50e49d790ed8f17806fef15e0d7a95b84ab8bf316d1e878b91b2721b4ec2337707fff32e2df582084b9c526bd45c0db4cb537ce84bc6e5997399c604ce63929445473876a9e1963a8e8c30c2132a8fc8c69f39017883c784e99c176c3205038c67f9a899c36a9bdd14177eaa129a5fa49d91246745cf7759c45163f14cc81421974c987cdf6184d1277748793e49927f35bb62e3f6f6a800bfcdd70cab633bfa845f2d995290906e4a337052d7f2d4811f734670d04c5fb5a7aa7248679e433", "196f85176bb35d434d2a909462245a7bd6d16b41f9f1a6047bfb0e505cf91bb159e646c05224d309166ec81e64080810952737c69d653f0e8a452fbbe87b0f665d5be9b2e62da3d12b6f2711cd12d5e1e709b0774d8a531de88ae8f8445224ac2533ff7dd216683fdc92fa9ece9ad06474d374e3fff5021dca466602c870bfa9d6662bc98a923e5d978edfebb53f37b546484d497fd9eacb89c979f75099073a491003ed47e179593f10ae6483f8dc9edfacc7de75a424b989a398efb9e5ebbc3f16613e2f2ba24983eca7a14b2f6c7a5afbab3b379a8d60d9602ec5fd586bb7badf39360e056930669a7faaa8485beb79db60db81af743f609ed33895e1afed83b5e9e93765cb1f165e474bf4de0bfe4c174a3e6c2b54061ddd7e6e09e20480ac1a89d248fc6d2c933e89afaf2ac96de06f8113535a900b6f0ad31b33dda718779fbb724388a4dbaca6201a14fd7558c1bb5841afe27e0d77201aee573c8abcd9b6ffd045caf210e5402bd18f15c778508cb7da6d98ac2327a7a66b866c7f0aa8fcd9a1e7c6eb01064829cb6479a15383020af1576fb673ce8cc2ffe2fb3d88559fc4d2b4905752b811b9344f579f28b0d353523e9d086721d580b7316a95811f857632e96ebcbb40648e38c1930559d028ed88f0b53c5a55f36b1d9a1c9b602236e8d91061a6f4bb99ca445baa13bd64be05d2f645bc660d51683b14fdf76ab755cb1d3ba8d373c9efda1fda605d5bf66908206d0d49ecfcb39acd1d8d7779628ce84fc683911dc2d6182311a5f3386850905f9822804c398be276febdf4375f857e83cf13c1b223dded315f65047556030338cb348fbcf03716285589443d5c8a318976984e1cdedf73e57e4c2b0dbf323953d23e7888f08a8bd7d1f1fb42498b1424f2e6ff1f81a4cda668573cda14dc42891b55752bd9415a73f0b6e7b0738e55f29d53fc6463c4105e72757d2a951e9b242f8802be60801245ef6cf6850313f14319d1ed485939199db33ee91572a081b5ebc2a35c7001e09c116dcb85555f0cbb84a0f93708ae8bfde8781f56d3e991814769699cb48558a217ab219512e8ffff4a380a5688507bad934937390fe5b5577b654bae0104c93bef9b631caa8f0f0cfd33e1a9fb0ebe5a641ae0081dad67ed5ae5df220df6de7d4669740fa04faeb0552ac7c453ea5db704c7c94085fc1a02527e2d6dfd5e93cf95dccc284e7a1151a11c9de32d7f0100b503060f72fc888c41a5e8511eac130589772bf17b70abc786134b0f5f4d031b2f53cc76847ab8e02688a4a89d5f49a2aa1dcc4b78b43e79339da805daf4d66cfe8418caa99c41420dc42a1a4062043266a41855d3a12cf9aad6445166a46709da5d1cefaa3c96a85e1c4472185d0ce7c38645cbb2a47132fde236c9ad88b99e478f4b5f404f41b7c47c4adbd2467af2898c2c9", .Okay}, + {.Mul, "-ec1a0d400259d20b86bcb3bd3bdea317aaf5fb639896249cf896c9507cac5cbdbf4a165d73019bd6cb814debe490d1088eb8624d190b85c02ff12c823b985c996437856441012e5846d9916ed999c5f8ecf82b0846c87b25289d0e1ab2f2dba22c839a5278eaeb17d1d6a4528f429183a543a89b591ab458afc252ac114dc6652ab734f3f919b02abf10a88e63a2e11a137f141300828a446faffe7819dc636e75038544b66e9ed280318c7a5f63959d881ac9f16de3bce3ddd51dc10f7677b3d7e2e5ed137b315a59d8a18cee1703830f5390d407c82e107e0f6e54324f53a492915f65892f907a8e01d1deff79829756668bea1bb037e4c4b45ee61fdbe9bab60b71c36e2be28ddcc7454b35c97e2402d59408e2723d3426692df1d8da1d1b49f3ce5762cfa005660d3b513acf15c5bce14cd0612426c81172259d6f4cd00bd1d748505abdc99b95fe9f4e5f2357ccfb94b2aae3fd101c13e3dda88a8b6c86a5d9d260e26849e8c98869206587c1083837a67911b49c09ebbc524754c9da170b51cd88fbf24b022a55a2d0a7dbe28fe9bcff5198fa0b8737d6eccdb5a38087b4236ed8313a7c6673cb9a6dc3b56a30901fc62026de1ab46c20a774e84c248bebfc8e3dbf57ba115c7e4f26c75fb94f01f3bad2b56cba9c5aa3bf58754315cdf4a432594a814e453ac93111ed0f77a2bb9df1d73b72e0a8487fbd7eefb0816a", "3c21313522f52ec48bd22d6d39f52dd04956547a7021b4ec2ccc552f957c084b4b72b346e43b71d14cbbc15d65b807492919cb186fa4bbccf196a98af46fe7f1507042506b7eb68d5cc1a771cfb8ee4e06f89b12a93874d3f8936df918ff4714cabbd1e758e6995601c690aab4b282dceb45444868c01b0bb4c18a9b7e6d0d0a8dd92a2e68e87f837e60b72051192988ce7f39ee29068fa229d2960dc0c5538c5c7c55881d74fa668a78f7d867adbdc0590661846c8a0a93900b3f42c7ec981cde475daad335ee4af3693fadd2d5f695f15fa6c5b276d2dbf85b305c37319ce7c35d85651d93a07472f75bd89938cf12268c120c4cf74b9d778a3f6ad2e6416dfd3def0940e86c2b66459f358e791d679ecd6496ca11391c08c0f1e624c7dca0925e6391a6d8b8b5d6000bff0b37dce2c5c73aa1246e77412c6ed7ef5f2389458ce11b6a80c284a3a09268f8eabf64e83db949676630049addb425759b85274501814a54fb2d516cd5919cfc468fb4e91a3d94c538e597806a859a01c03427be91bf21d41b8d99750b28b27541300e2753d8d1125defd1f70f0df1a40759816b7afcc00e2befac57e97cf54c02e2f1ffaf852813e3f0df3bc425a207382dd2ec7c26f239377635e011ee0ecec2fdd38269c547c514e90d620c3298e12e47952ca69ca1ce44e5236a8904f2ed727a0ca7fd946f200b60734130e69317ea2b5e8e", "-3774b7d8b3f8ef5596b7195ff6fdbd97c0f33a317bba04b517aca0144ccd94f40e3362edfe5f0a2abda3d9ca474618e1ab59fd7fcb4fc547337df9989ab7f8450133e5b201a7230872bb9b59bee6e156df809f37d6fb59d0ae2e548ca1b64ba6ad056afc7ea64b9d32d05c5dd1fe914f42512e31c1e458d761ae08a1a6274ef1b8aebdf0c46d9801fa253cc9abac636e0b6e2b3a7a461a131ef38ab98dd2b053c41a7a10849069da9b6c539755da5eff73a159aa9e00d04c359c482cb56713ed3a53eaa697d417a20c86243edea7cab9f08c68e917515a57afb4f6eb58934936f0486ec8d358d25203098117828b6aa951ec19a39e22a5c55ec1cacc6aad1675d8e7fbb59869d0f5d0dfc30e9401b3cfa8aabc9f052d7a5d7a6d292bd6c15193ab3cf184e3702fd0d47e6eca5501214e04e155182fbec4866bc43cae24e40ed226e8eda81e5d5f1a4081e62fec151b8cb6f5fcef3dffb02245d2ab647fa2183099ef791f8aea53ca83f54e532c07fe86aae339b199e4298bafc80c7c3841df57eab8e9601fa1982bb0ca4b1b47fc920a4e59cd810107df93c9a8aaf6e64b948ee0406c564e72812e0fbf9046398aed33981f4cc8de0e187c8a785de45d6e0986f7985acd006731fbaa08a46a8aa61487ce030b8e756ae6a351d3f9901822f121f54e5e7494b971a441f72d8c718dca41bf1827e1852a1c642230b038a0416f3f288309df1431b4e8980deba5ffa948240d91c845b62c80d3d7838f75c3cad85b480025bc30f3ca727c20d16c1510eca2822bb65adc28c75b2e1bb36b5f476e8ff8a5f378963d2eb0bb1fb8d1249e62e11a42098e873ed54d472f9e9701024fbd5e88c11b4ae2616167a6d7fcff9bbc6825f56103d36602264bb2e85f833b5fe4b85c8a1e1096b066249d84a697424264c80f680bfd6e53bd07d79bdf31454e918dafb496f2def6b1e3175f72f2e72c22a3389f5a12934289341f76a4a4284fbc00fbe85765a53a4f9ed2290d18b75fbb5dce514c81d2fccc37975338f390152c97a267d217d90a579f77fd821b825b59a767fa2b4b33bd6e30cc28376b569ac53b7ef243ea4c182ee59c052806366d636365c964f86f4abcf0146b6ef68301fa03a3f3c5e550be176bfb64555e15392c1c9a4c487da9b8dde74f87cee23453df12869e82a742d2c579f7387ebdb53ad807dd9fbfff70ec5239d555337adfa5fcf9687d47c1c7ba68d8da7144d59521082e2643a075c453eee539fc42876bbdeb4bca7e9fe711324fa3d065fa3dc1c41f4984381a7def6e6806a70cc01e806e11d6804fa93c4c68f9752f8cd605adac1818670af513aff8609728ae296d4d94e3c04fd46c90694b758368dd46c48ab4f478c8c29803d98895451669abf5858a3d6562b4af2d5fdb79dd580f255758b4c67eedcfcfdcb92d6e0240cfe2643ab4cc", .Okay}, + {.Mul, "-d41833de619d251456ec18ee7b2ca671c18754456aa257a3ca24a6835e7cacf9883cde4a684e22e921a50225b7ae2351acdc762e1a649854725bf18c8d610db47c56139d2e7a574b4ddaa5e1e8eba8ed0889358976140bdd1bd5623ab6aebcfe6233a2decf7662151e842bd5a4b7afd9df73a72429ec80e8f5a4eda04cefe1f34e199a09bde60888414ded341049567fd0d1b87fb48dd7ef755c5c8f9782b38bff09a80565942fd96ae8065c66b6e37e67f50b374cb0ddf7937924c66845dbe047f2284d67a874fa8c7af4546d8b55af42e93cbe3b95ea1c4cbcba90525d03b6e75732de9df92f777d58fdb7ebbb9e39ada87349342787e6b059c2063bb53b52bea440acf6131720a030ca44fe16454e1a11ffa96db0e40abcb70b937e2e7b58f7457da2105f6e3f6c2ca6406485f90ffe8b195bc965b39383a66afe2c1ae6335cf1291278bca19e41bf954466601d7962a744d0e185a8a01e55bc6cdc5c178b4aa2a8a55dddaafdf064531649f59b13c871a27624aacf98624f8aa8932e4aa997668bd138bf999cb67c8b08ed4fe836e31d91cefafb23ede3adf618d33855bc671a076d7d1e8a8087f267806cd793c6ae02808648cb9b8d577a6ff5db1569e38b48b2d7e299175a9766bbd8fd4c3f1cb0b7feab8c87bf64b59f2b89aa9ee5d6b07cadb9a8645d052492c40f2b8d7d92e9da80661817540ca218c4e6a4855039", "1c64f0ff2bc4e7bcfca7a54a1075ade2f61941e55fbe694fccedd8c7f64ba8fccc505061171936b6a7c58bc1bacc386a041e4f75cf2666a44e62f76a7baf46e92bad7ac1ad7d182848c7ef0846738147d540827a3141506623795d9f2bace41c1a7d70352488dae5141a644afbeeb49f56adcad3f4cd1bc8e69b046e4431565ee0e7d3779f820a62d9abdd655c1aa5fd785f38ad8ad58e5044a77cd2aed9c42e81af4c586adc41cc983f017e431a7b55a4bad1d0fa602ab932e1d9f36c267b9a27ee06cf98596cca9d10ee7f8a3ba9ed3200e19b8b7c7dac3d0e39604af733f65256b733ba6294fe091ec083e6cbe9a3bcbad92663e71ae1860c3c2ad5b906f4d50b290e18ff8831c403c6150ea6cc0d6519bcf23cc3bb4b03d503d199fc2d5dbe550777872cdbd005aa73fb25479b2e6be9bd1e00945b808fad617dbbeb93b365be5d7362925a157d85f86484b175bed376ad4e08a573066ffdc73b3eaa128e5eda3199b44484319dfbd000ab313512efaae5030224fba57c73f3671daa044d24fed13cde7addce196bb8596d062796cb0384cdc5a4bd9ac5ac6a39853bd623f8c53398dd2dcc8084e65327ae66015c750c8be4a9ba513508aba779ddb5f791c0b145f6c1b677a977fd77ae57d5fc976a58c0052147a896cb524ec76701c5d2622bfd7fb92930fafffc17ad41700510370d9442bc11e6357e7b1480cc312fb", "-178646caae8aaab3be4d626cbd6ee691bd7ac5ef497a87a7f39b6c825d1e0593ec187be98888bbe23884157c0c659918491d22701d3158c97f1ebbc35894201e3d4115d573cf517b1d08630d15253c98a96ad22a954c3accdb0510388f2fc7966a1cbbf3fe6bc0b87da668a746d83f3621e4fdccebb65d1f62d0d82d536a99c5e8527ac17c909c96ce6eb591a1bb30db1c248485a92a93911110f097339e4988abc8f28b27db97914f205f7f1082e0d2524bfa643f987ba392f5ded581dfc4d62464bd17e5f81997a527e405601edcb2ca3e98b863c21b7aef14e8c5c6b7a6463e781f2aa40a1e2230a8a709e1d74bedae5dfe9bd6fb1e6d96f5428d717e8cc778a48e2cf0a5f98cb8f71444f1dcc4d8748eb31c3c0fe6b264f5c4398346433340e4529df96714576ce808aecc3e42d30d3557a47ccc8edb0b5c0e5e0e7a80c5ba39d24b727ee1405777b51ffde41738689c2743b831edd46a4005b24ee85e0c06165f82a70e365b1178ca35d96db5cb0ce781023bb1fc895c33720424591c37101b10d51bcf51d5fe1501f70d0a28031282d8451c22f3613635ce5887074f8b61d20cb77be738c336904522554835551e2b6924cebef66bf5251215de2774d03a4e376bf6118df5feb993b6cc4d3c6f9a96bddd5e86af23d5001db698c2db8860368932d81a294dcb51e23014808fe6acafc1ed32315c5ba77e09ffa4ab3b5de919abb703a4539b2457569b49924f3a77e42f30e3785835306b1e662af71ca5bef176ab8116c7f424c62112f940f62b8464871059110a69ca9e639f41f36d5870a3a5da4152eb7eb4a6b3d2828ba2025f58119733fd6367a9c3a1c826db1ca00fd0f5950ad4cf196d21ceef7ed97bc4b798b280c8f2ee83d75b31da4708295b6b5ef82d636c9073f20a04493e6dae1ff5d149fbbe710b7bc0b2cae37b6bfe81bfa57699c9028807f79f590a8ba21f2974dbd2af1d7e792ff67695dc760cfe986e3de86c08ffca19c80c5069e5ef89de78c056a86c5241ca68ba3dea86aa63ff4ddb7a81415aeefb8cd3cd85ed4f134e4a39d3aadb56b93d41bd6f7600a057c31fee8f6ad5bc23ccb2a5211549fab1361ed24f6e4cf37c9df3db559d9afda4a7f6313cc9fc9033bbd1c64cfa94349d11bc54ef32f65b88b57784a956263711eb424ba46eb97b753f439a6b8fb12ea0c09a1755919f881733646b5467928a8fb5c69d7ab22a7e7e0ccac1f8c6760b390133fa81950103f8b0271f3a62de1e761ca56db9f2b343b332c4495838beedb16293f32944c26ffd4f7703f25db2ffaa06f2cbadde449e5c22eba91a6b245281edbb4754f654bd77907b6eb77fa42c5377204819ffaa5cc42a722d5b555ac144181fe8bf0e34e6be4c2a42ee4ae249ebd8bca699abeca63c664f5e5de7e35459385d6cbfdf2113d19abebd00b75c4a9e3", .Okay}, + {.Mul, "-fb5e6fbed4868a4ed491f437adae3e7d35869a4da3cc7505f204a37afdff0a1ba2d0a344c98b4511a6dd1e958204f7d012d7654b980971a0230d529161d64a2739eed6e55d31343cdaadedc18d18ef37ed180d6c089e838df36baf00383ac269a5319ad5b9cd60fed210bbe6121a92b144ad1d4eaa064bba5e84071537a7426aa8ddecc57ac4898393d73ca6d47701b4bd079bef7ff57334c74592c3bd68d70e7ae9f70693749a55d9afd55aae680d1842d1e24537b42e4814fd3116b286720e522ae887ccfab297996d3e6314c3a682aaf99a10ede78a0024455ef93d408782d7350b82ef4becf9dc1421461708dd1a44e96ef0cfe0f3d11ea144b7014950b84447383ad9a7c970916cd7d8b83bbbc8c3a5fa2bcac4d8d61f9534cd216094136ad0e426b24d78c26369e4283ab2ae56110f3c1ef43f12c2b70b828e792852fd1489e4bfb5ee3b0a8412542a5148d2345482fa961d40f6649ed1f62bf8b8050f03a9b3215bd8cf7f7660cc06bfd08aa76320ef369bac30d1669acb2ff1cad5eb0bc4193d8d5c14f8812c22c4a794c292c9f7f4b820b09a8d568bb2ce98057317bbe5770dbefab2a765ae2b79f453b203750a140d97c631df0d7b058536577b91e4e06754f56e1f55b2a3d9543e1e31c7fc76409b7802d47d18dc29a8b151c4668e8f3bba79f6c0b1ed206b386fe9647dcc12ab0ff1288ffd17059e6668262de4", "112ee279a1132cc8dc4996678e53ae6515cab4df166d1fca20fe03e10458272342a19c7b882fbefa32716cb734d78566c63363d2e5bfc1ddbdd3f481911a8a648e718ed5220e7701dc528f5f98fe0d18a1b32c7345547831393a5d907a39502561280bc47de43479819f3942fe51ba3be656bc001ecfc3115b50f9119817aa81c7f37afa33cfa85adf812ea8e8b56b511a952a4b212483b7930128b40a874c3f7aa0fd564950e0bae246f3a3e7f37de0f713b91484e82c2a08a82d626034f850415fe3be35163033dfdcb34ad9cbe898f727e9733598c4ed0ced3bafa9242bd663078e9b1518cf68455252da2caf1408cdf98294e48e322b7fb7aa5824e715cc1e2573954921f6d54c1ffbd6fc98631517f72ade221acdcaa3264329b77ad5b1073ee3849f0127eb105b677814035d299d96206fc9f4451cb819be117dd69b7e5320287c1800c32ce2a37b1db1df6abcc9a06bc8deb6155df0003e856711fe4dcee3680354b983015168c7b6049e22127da62dec9aac415b4d6427f77e38487fecfffa4f104d248ea347f8ccafa917c2c56d32aa04f8bdd583b8a29a07e6b5755eba6b537970dc3043488267b33043aee006b62b355e81ec43e006062811ab636c3762d9ca56fcd36a16f7a201b91a97a74677ac876791d418cf9815072589f3872fd9dad043fbf94a55325c48cddb5b84ad00554b1226f6af9d3fa7cb20e0f3", "-10df4ec48cd9a0701414c096c7d21504cea17592b4de23fb50f9c2ecd935a24b81936b470bb2e4a10cb8252064204efc9d9b9cd28a27ef49a5bb43f969564878805bdf50c6943b715365069bcaef4454c736120ac88b28cc1644ec5be99b98a19f56a446712ad401df7da0caf6d863f36082b53f1eeb8efe343ec3602bafe7939b91ed381b984ab3d9e7552342ea35f3354315d0fca82c607178825894abd1490ea9bbb996d193c8265e12ecaf8dd1ed96ac8311981123f56ff8c98fa427e8a09b03856b9b2a670198eecf6aa9973cf51609731df1b171d613e34d5f7b8b4142f29996bad353d718561f6ff4ec0645f3c4dee543302267cd520b267b9ffd095881d3585226f8e7adbf309ab7a0f959891907ae7dc44021ebf01d92192f458d0632f2936c9c686a6a9ff84e90f15eb4945c62de18f3dc2656cb09ad3ab604c562bd16767c46e9ab610849071d285af4f2d8c9b7087fc5277524ac2e77e45f06861c42d8251479077ac28e1f905908708b625c063e9c015982e1fa2dbd6f32cae115a48a54af36385d61f97ebcb9ca4d23ab313cabd101f09b026d14b9814c5552a2758f1cd73ef33b0cd57aa74bf6aac0177fc90377f5968a76c786a380ede77a3202b9cabb16615ca28477ced8b1b7cba8bcd6e22ae2deee5e4724a1026d41dd661940f244a2659f5e15ace6bb369d5245ebe37ac3b3d1d50d865e84f1dd96a99f25b26f699304146980202c0f41c91dcabcf2dca5d951b314c7454a5600abcca2c4d6dea154ff1e75d693d0e2761df3b16fae0d3585c3fc29deda08643c18bc2fb8d12abca1e58c1ae508712d9334361006388a2a4a41659ce0c2ae5d18ba3eeac517959683a46066d3b0c5483d9bc848f3f8ef7081c20e4d5517449a719f393da346e197d98046e518fb466d775af8a67e0a8be32fb200fc74fc1075b840e67394a994e61b73199a7253068f941ce6f62acfbbac63e63f35f24dc5205ae69b7f7cb16bb8312a61125a46b20ece9dd072581dc7982fb3f438c799f556619a1c94a6e148b2e241c82437918ae2f010d163d8989dc2f83fba14a91b03c258c17710b4f4d93834208230db4f89005871233804d56cb9c01fcfcfae787f65c9ed354cde3fb73976e8798d484bead5b8dfa584ad97efc3114e30b74ba4a77f97f372f5a84a1e1cde4fe07377318c56f56f4036ea0ffe3a565aa6cdff872b2d4f4ef2f52c01ab7a44ef87e3220760f9edf619821b701d359d372e3691367b24b6bc25f38bc83ac8884430cb1c6423722a49f50775b7aa07e22013cc2b45ec731272b1911ecd9935f30df40d0fe93f5d2d89dff858d06717c5e21682c02d3e95f4f39f58468ba244162c90d84eac916f738e66beefc6e5598c56f6cfcc0d84d4cbeb8591d2eb77038121c0c8af92995dff21f0efd9f7966a8fe9011d594d3bcce50f6c", .Okay}, + {.Mul, "da65fb48d7651bc1cf57ddb8e4b49ee574d00df454d46e57bcac5119341707e3e04e6bcf52c5f20db51da8e0feb68a635906a756300f9bc528348b37552ec5c4bc4e0c243bcc4f24fce7f8d28d21e2fe21da8f02143185be684729d1bff97de4477e6762163aa14c18c4c5134227921645ee3f305ec66fb33218a5e80dd8ee7e96e0fe0c7117e75e43ef5c6c494ef9cec7e22f81a7162ff8092c8591891956565f69053739281adcb65a1236c2bf4891358977bd54c11468789b47e9e8b9c8db38eebebf8ab474701ed5ba12449a7c9218b9e9e93d3a36bb6b94b18efcd71cf7a7774d98cc5a7e79d6b46ad8c54464473b82e99041254bdb338591b58106b5fd04e86d59968ccbfb56359aa2dea88fa980fbc8e92f2e4469b44f9df2bdcc34adb28771ab3c4f3ef1d21c4e3ba0c552cd518b90e37f1816eb8d463c7aec65d6116c192041a9d93cbd831836850265889281ce20047ab3bfb797f7e887b41062f96dbd3fd146fa168812811c6c5fe07342ce1359fc272b4c8965f51a35fb35e53990648ca212263cd4e0d65b88987983dcc7525a27a9e692d5d4ea8663e532082e3da2f94b117bead8aa6e0fd0e1c56b91f10c20b7e6fcf186fa512acfb0f351bf4d107b398af77a3b500eece6d3435e0701f3eae45d3f44010322ef7248f27b8cf7f5ada90cfd3b71acaf047f62238b5d8f12f7c152a39f7d30c4c4b504bbb75c", "5392165669cdb008e09c46b106399a2669d5a0f2d92c1d1652dd8ffc2c77b7c7a97466039545c0fe8baa48b0d5899db2b995417e43f64e6cce305083dd1eb6a01cf24c11074ce2ec135df70b202dc160c562a138189d8e9409d6c7542966784312fb60e194b2510a97611a48ed93e9ffb371b1d5908fe8ebe2c4cb17bd026f00de431b1dd8095e5876454eaf702d41eae6c640d77cc9b684a699968508a3d0cc2636eaf1fe8bd547e711e91820ffb955a6aebeb8550584b4dc89c336da2ebb3c7a727399ee3c3923cfc53e023105e7c4a27964cd98ff3c22d6d5a28695acf721cb9e83e4e40b2783d61dbd54a3baab18787cd6d12dc30d55c1b20f79cdcca2c27496550a87d9b72d6739a9c133f57da0e915935c23711e2bb90a102de0691dddc6328eea62c1e7ea68abef06226e2b208c6b4c3aef83985c85ec603561bb63d17dfbbc19e2aa23d1d1ad8aea47e272d100248ae15382950c4d66262cb3902f9ab210006cc1c16b38695fbb8b2cd70dbba0b1e10f29d9883aac56d426fa361a582d3502ba06e8985a63e3f3f01715afe5617382252037a7e29169bc20baaaa0f80bbef9c6a927e5a52f06c762619ec58a663c16a361bd96a4491afc8e8106a51bfe85bdb76e3ecdb4c66f70525f57d35200d6f95d129c8174e1213f576336c0ae65dd4d7b776c605d348752d8485304cf7279c3516ae41eb339c5836a317f4900", "474bb1b0697e9a8d805928f6560b78777cfe6325a40c912c962adce89503ac65b55b5e6fae237d05ec2a78b8207051d8ca87e7ce2131d9428be49dbd218a477058c7ae0f8d8a381d003831de1e28ed68f7364b5db33f679f2f0e6cd78dbfd0402bfe5e1b9990e4a7ffa549260d351aae3e57dc75a275a3d791f84b79a7b8aed77f5ac47d73dcff7b33687bdd94b439d50709986a881678e77393b4233da82b33c4961f96a3ab0541cf5daf60fb44b9dfbe7cb6ddab4fbd277477aad595b684dcc41f6b353c8d57b11241c3379443df87857b1efe338dfaac8029985cf869e3a7d36ac14dd92aa0701ad08d044584895f2d46973958c2b63cefca08a4471d48d55a367817b82256c14242d5d2561ca2bf443f3ad49e884199a52be7009461175c2c7e3b76fd61c567d27d7d6f2b45f0baf8384bb94470aadd15346018eb9053ca8b41a33e3aba2693344eae97fbdd78aa88b60fb90a23a214f46e2c7993638af8f309baeb62113b33100b4c4c9d427bc428004cde4f975bee6e121c369df6ed1be5c76c271b595fde4f653d039add6416e7cd54c34e557a7c644f679a14d6324c7c877309aad2304e5a0b490a4246dcb8612d150b350e67c5d673232212a2ef8b5e6c91866e9813016c2f35b155284c7e6c0d1d765b024d0e60d3cf05ecc2660dea77efd54e2d3e2cd4728aaad957bc20a1ad260ec8500833e5d9e5ef913b6c3b022b0ae3f577eb2753f472aabc179fcaf09570f79f722405acba5dc27e25f1e9ecc77e8eb864b325fa502eef65ea961e679d2f283a4114a8fcf83ba23ede1d8cd07f90ae9bc0691a3112e94a23ecc26f9a0516203d136f3dc09abc1cc066b6f89a32607518dbe41ddacafe6ef1b9940332a0afcc5c43e322ed90609cfb0b88d5fb4eaf924f910a07d1d65dfe328d356e9c906690955e56cfde72f60a37a5c1db44b1aa335b4c33a6476662d14a5ce49315ad3386773987574ee2ce586e8e5c44daafda2530dfa9dc574ba643b7438c83f4e1f0363890045dbba010335ba25350878c813548b689e8c0e32d8ca0f781dfa99570b1cb73d9896538fffd78a2cdba0b9c50111f29c6603717fdd5802864fcca73398e162b3e4fbcc31b9e56e4df10290d50c174e0cdefbfe238d949a24c541cec2c15b05ae36dc756f92ee967802224e1ba7e9057107f8eb6a014243badbabe6ec5260f8110bc450978a12da958c221c7b75d1a11f9794ce2ef3263c597e857e490cdca584d99c83f9e38da4e6028d1a6042a681f8af961d274bcb624a379fb64022d94ce768712b2a15837f7c0512a20ff99c249a7e79fc7042b4277998984a317dea83af7a549e3029730cab786ee2d538ec009a31d085e4f578d179f41420495528da116fc419d5d36bf5e287a902c464a1c03166f00d1d97da65f93fc4c4bac9e02161027f226e5aa19ed3c00", .Okay}, + {.Mul, "dfc46c252631a9167cdc7e0577b94c548bf550770ba5e67fab73a2e2f30b09e424b916b732fa2279871cff1d76074d68038adf01c4ccdbdbb8328c0dff4fbf6e2dd746c84daa1a203104479cef2117753142bdadebdeccbb32f9ea1a07d0ef7eaa106e423486ed570629e62560dc790c455a7a9d7587e4cd7343e40139a4580ed88e593f8b6a1c81dfda879072dfb9e7492a4ca117d5fb9a813719dc5eea6704dc5316b865ee427eac9bedcedb43d7d766896723423cf5cdcfa6069613bcd68fbe845dd508d3c11e8a485dbc207ce9d2079659dc6a049aa377d21f87f8a51c823d2c8473aad562cf64a335be2b6a531248f10714db2a95b0a622132783553598cb33bd6de2150f729c3fc73f1ce58452faaef16c7a143f99428f5069a529438d7d7b800d35433a24fd63c8a5cda461261623c94879b4079815abce8d7289f82f703224fa5db3838c522d867cbd8516a913b67bc6500e49b57bdfc22960f6be6c016e96e18ae51b3f2f1a42bd750ebe5f2012473d705bc529ff906795637681ba34eba43766d1accdb0c16376389f100cd8abc3f8ea1cd02e35ac714681da1af2b00e435ed06dbe3e12d83693e6ff4da333ac543114a3e025731d9686f76040a2edd543c93a32a2295568c220dc00dc576a48714df55d5332bf2d1a91bce4bf0f23279ae20756bc0200491f9efc8c63516efb682f2bda275e493d07b1e5eb61ca", "7429441398ee2547d1d07e39b0de07d00e1d9886d62e861552d71a84043854e62b569298343f455f687c6e11f5a82bbc245ee5da9b04304a3cf03ba44e32807c9210ba15f1b8f7dc0a52acb9d688c5066cf871f88764f2223886b7cb4861e29a212e209a729a342c9ee456f786bad9f66cb6bb3a99cc265706bb611d0a59f9e2e33675c98a9790ddeea726f38ebc9d45fa0e8f25d08693769975e9de13e49fe9926447a7d208165717ad4d8689b2491f5af7b157b51c81b78b313b56088e0c0c9a0d87d693194e76068d22579fdba3b5922a7f68524d7b6a879326773231058cec183342e7e890f799fab4b2f41b2975c3cb4ccd43c897594bcd587534175a99122004c74834ea0d2ca18e1e2e1d2554c00b2eae2a41d9acf13eea97550d0a5731ceebb630b59585ae0f9dbec85bf03fda466b376e1a78928232a7ec7fdc333e3d2b5ee50e6f8eb3b00a8be245b70b5caa275fa9ddea998b3a7ccc19e4d126b153231daf3850a9a7c1254970ba58e3a56d59aa0296f215f0899bbeeef5f8d4093cffa22db1c1c97dd9b0d82512c852f78b3fcf10c01eac57910cd8d7a5ff851039d5a63597d727634c56b13095b80a12da872e6c2bb2036cbf15793692246851613a54242b182d89cedf16600a103e684447ec992bf72a65115340745dbe3d05572f5c8b5a7663a9d8fd4570c2a875dd89022782c3c99bb0e624c8f37a77bd32", "658912f7753c4ce20f7f63db1e25248bc95fb322f53588e7afdcc79c0692a1e5d7465f3e43f1344dc8dd18d1c299307e2752b7c0b52b857fed73e1178c5480f018ca56ee0feef897d92908f81b02d4c02d3317f0c935914d6f61e9c7f82d93a060f665fff22239569660eecba2054b379f1d3546c6d8161f48715e030f3562dd2ed7b6d41925928134d912507f3b5b542520e032c95e398fcb08f6a4335d2d05b6b943a568c9ca75192fc293db58af371d400f06a545332dd36f4fe5af02fbb8e0ddac8c2cc7ef44bba8e161e45618ed013de93986ef0a17b27802e78962735d47d7578fe535608970c639c44c8d5c1009e578c25a85b214bc74f6a58f2b9eca624125d106a37e5d4a11463687db0b72c264306e76c8b6b647beb35e52fa3483ac50d8e6665f4e3982d805905edb8225657760f6863a4d6afa0fd455b4fa1d0f3a6fa31e6854465e9f8b428ff37169ed7f848f13b5b8bcbe10acb6866a50b71884e53f9a493cb3712b20affa5439bd07ef1b769ef2bc84ec06e8b4fcac6a8cbc73975803e988475959aacb01a20167aecfa2975f55badcbdc1b1c83473161b963d5f9f7b68adca46caa9b863ef55962742a07d120586223da2d786a7d71cfaa61189517c8aadb235bc8c2773fb67ea1ae965e1091e8d855c4005443897ce72570739cd09e30c2c72a47276f04d79aadd23477500b22a9c9ab33921c1b22ea5b90f7ad9c5c14870b792454c3c2d4e831a38e1680bf5ae8ff2440e30d00f90e89cc4513676998825fbe7f487f4c5a6f6bfc28105808ab77b69853fd82aee0c0aa7243789fbbc9e0e1fd16bc28b1ff83870e0cdf03d4823e584c0c2bcc63fde121ddd0bd9aa4fa5f511c2fce90f852f1944fee99f131e9787f9e2ef93d77959dc69d5101e4c78f742e68dc680011bd3311157ee3b7dd9d00f31d826c87663f7da6a1ddb66c17821f792e95771297750c4870f56b229fd3e60ecf205760853f509ff9085015e81886be6da846adb0370819f264cb258b0eae2d10a455a8cd8c3ffae6f22ba37c5ca1cf4dfe53b476674231e5b8fd76c89eec7e05875ed846d31415f95fdbf970aa9307b49c8463b9cead1bfcc5208f79b2e84a48e2cf002036b4c73697ad62eeb28f9550d382621bef7f4c2eb8ed26c56eb2714a557816fa6c94e8526ee4168384c10eba35fa54b1f90fc735a404992d425be71bed392f82282077c76c8eaa978b26fc4d16f7078eafa3f9fa51d875ae13f22c39510fb547cb677766f2ec9689b7f96e1295685cdd9b61f3b2e0704c34327903e46ce7220a5df983181181a07d4f83e3b9c76fc02e538bad4e5a5c78cda6adda60c26d052587488319223342410d2b347b1ab3e934520a59b652d17d8fae48e5073388e6024e21247847682d5cc46a93aa7200a8bc43d7c4dd52bef5c33910ed81719874068113b74", .Okay}, + {.Mul, "-37daeccb35bb95d7e37a2dbba8469e12e40541d4ccecf60605e3f01ba4637a48bbe3c66735b7ea5677f63fd250a94a02a64af6a6a0903ba99b1af6a4d24183fb74ac239968edd398f774caf7664206dfcf310bd285d5a8942cb1d21ff4f3be8c9f1ec40e5caeea6881e55d3bf6084781d87fb74139c07f486a51de9ca288acd2504f0dc3943d66e7a23344080b9dea7106a0aee83f844153f4fbbaa15638cc7929963dc9516fc71d9b7c68a106d7ff4ada5523bf7b215b54d1cf2d2f87905bf81f891ddc789a3c074d699ae9857b69e39b68c79866644fb4dc81909186624fd4c8b018653c7a4298d7f10fde0301aa19e250edbc077daa0a5b5b2051d72af4ad4dd58d5525952e0ca7d308af5a57fe3e9855d100cefc3aba7fd4a35731d69124fc86e345e1365874b55a0f60ff592229b2353a0cbdb56a753c5d85dd161037dc479686872de96f75f9e67cb4b5c0748f15d021715eb7823a1f09123b75bcaf437beb96fb0022a9a2f922f9a88cd42f01b50bd83beed16efbb0577ca30422c465390eef380a73e07a77a8eba047ca5cc93093c54553f8c174473371f56477776ded9e63f47c9f5f5a1753570f62f2d12c22d7c014fbe85c906e8a780ae4420ff8750f31aeb181292f62b70fef96114fc73fd40be1fffaa93932e2914905161c2cecb6d58532fd3bafd630df93f4d4d8226537b0b4d970e1480d5eea8bbee70b31", "53abfd58b579c87e38275cb814d5eb1fb8d01c58a85252a937c39480c583a03505113ae1bbc1755b3fa2d4273ab4b0965a3c3cebb7ad19db9fbb6cef3c41fccf4113bdeb513d248e519411d41def229af6d0ab5887c5c4368332ab60d60f17aadae8e7fa677e8576de4b59513d858fdd676bcef3525ad2df5ef68ebd587f11a9d1d99f938a0ec357441515a99916d276a192d03c4c11a5ef6387ccfca8d2755d7b742438d907bbf38b57a915429222eabe059e6d07f2f7584d2f74cec1091bbf48a2171d4d944271d2f6e6a5caec5b2c68a8b33be07787c95015bb1c78e71ab6629059c36165dafd2ecedd255ff0927dbb8d60902af7b320a1936f748f626d2566f06765cef1ef02258e120c7babbf4cd1e80bc32c8d3a98b67247b3e219a0b737662bd069d6cb9b0d2c8b8032861cbe25ac9b0bec9bfd0f0329c273a4262e863d508f550ec30e33f2ee004b84ad081f953611701c63800dbba7d0de988402a05d04c2785a25c9ef2c439fb721b03fd6a0490da5d3de2e992ca2682fa73672bfb72cf817e532f06c2e2da0688a7d0a32a35963f63297ca22f32f8c4222b3331a09d0d0625151b7bc7019f194518488deb24f45d1976b5c8c49044d7d47190bff65b1fa3de711adb8607f4f21f04d893dd2ddb52553fbf409f45702225dcec595d231e50c5008091eaa580b2b957a97986bacde6b54c64ea400c58a8fe8c051af", "-12418148c5074b7b1d913c72291403f6ed629b2d04c5f877ef1239da3e9a4025a3d5531a321922dd58f6d88f7ce632cc55bc5164ae76ab684abb79603fe9fa3620ada181dc7fefd74c5e6ee37f83e6c3ba68c2a7341b9deb9249d10733b1300bb882bb5482c8ab3b1216146516baf9a1cc7376d579e79f8c3c70d887323f4373730c2e1da192f585f06d9f51d0ef8f59caaa4f016b2f597423051faeba9ab27cefc558ac67bcf231296f2dcab9985f64e169da51753211e3485719d99ef1906f51e3970b8eed8bf402af52b09772385c27559dd5f7602ff22c146189ac54f812772d505cec3932b6e4d8511f4d5131957e8c18364ef18783f4db31ec4a0b9f010cc94685aaaaa146ceefc45ac6d6dbbda314fc4202c81977c06025684543b0ab8c27675ba911db111297795b33502a60e996bedce5795402c3602451d39ce8ccd1550cfbf80ea9e4163cd5fe3af7e04fc8d294f028891c020b1766ffbfe583c34b51504ffd3cdd3a6b705e78ad112b8858d40bfa51afe1b4039f89123b1c1b3f7344970d91223570d0c92e1c68ca60c9f6242fb7c9f86f6030c7fd3ec3992ed8ba4c3862ee1ef60294a051496165b930a53898b7e49c235a1b491a2f63bbc7237840c76fcd39a7a10286d47aa630be633299a6f959453904f770721e949e8fa4d4858a794badbf0dc18eca189bc38fba2d77db39bf9b4db35b1d8450afacf2dd21dc811191af06d4cd0765c45164b4d5fc98c1e5e8e543b01ceee403c02efd3754afa0ea1e054fe623142ac243935d34e70f217123e03c9971fa50c30cdce7238d5036e67fcb51a6f3d455ffd75fe5241f110673444677f137fba3d4b064f13de9dd2c7de1eba5b97afd3727bb4a81fe952d4134b669a6c69f815a56a2f87b6c39beb34f94c5e61dda46ac02887450a6eb7160554a6d8408bdde798e35e4b1283622fbcd00cc2b684c9de56651cc66613eb7dd2bc99adffae0cfb12d6d01f9798bf0443160f99a74be28accdbe39e7836dbe9a9e3430728f91599c6d4a4f044bf0590a9c6db95332925d4406eba640a07a8bf6f51454991d89d32373ccdf2abb1e7c5cc45da94d13e11c177273656dcf942ff755dc2d4490eedfd0f6053a27b2099dff6cf21b284facba9f5b41cb15889abec9407efa0c7d7df33d39da8132b38d6e2c78d0a213cd8871f45110c5a99f57c0ad2a3df3455e7a6aeb88e49152d07d972b2b23849c6786be8ed8600f81e24faec7cfa9c7193b136275113824b02303c65039f7917315b126c4a07ffa33c4f295d283035e6567786ed70bf1022c0c614c8a3d750f9583f179c5efa809232a5aa5acb54e4c0ece6e5907fae35e579e3e76682987fd0aa6dfcbf41d41912fff52317fbcac5713a114653b620218779e768a278e17713f6df5b1460578e5e51ccdcdd5492aea326285b5c6ba673b277f", .Okay}, + {.Mul, "-8bcca2230f0dc980afe20c88ba18022639c809a512e0cac37e4e1866b387fc62628515f91edf966b86f7d5acbd58d9beb9e093f09126dbf619bf053a64523cc2618f113b2897bdf361a71263299f786213fac5845e8fa689cd0898bc1467b613612efe66244343860a875a550b8999f0952461bd4d44e6a26261927d97986cf18194682bab974e504bf90e2ad0c4c9c3871c2d3c8f5fc7bfa06af52c70cfd87aa1dcce5e49f91e3e64aff27e8c8cd1b20eb24d5810fe86685b4863213f1450617e276177c330a06483f0099e85318c824b8006594b7231e8e29ea96856cf09ddb85da7608e7258505fe08538ff63b661d14d83801e6b35153b91b9ad881b90e329ba34ebfbc8c2f28cca841da3c8d8ce748b711ad0b02bfb8678d02ac66c8de00215780f3e54543d0d54045fc8acc4c57aa37b7813d31d03094ac94949ffe59207656e3b61162f34bc892c962d7f3361bb08024232432e85a5985f70a337f71ffafc7d8ff1d46c91185ec57eef84328d30a398dfff760899ef381eb2abc3a6980468d71791a14dbccd21eecda9c142848fef39a7a7a32fe55c43218c1337f4a2cd4462c303e17af1d4cbb58f275c471004678c983f92d3c3590a82b3d7e9a9668fdcd65b5c4457c2a358d1f86d9f54ad00934914cad35c581ea94fa87333b4d5bb14e42323a7092ae7e7ed75843f2bf5419930840821a8caf161f402a4bbe47b", "d6903e0a011c1513894d8e4e85ff148e499bc30fcb7f525640a625fabcba37be241eb76b899cbf0bad370d708f2b0519a263a52b9064ef8ebb5173fbb5b2006d455b43e3a16f79e09990850db94d79b29916ef5ae1ff1c086b0f1ecf0d637e4a98abe0fbc308d59fa2f398ad37c0c9a1fc05215765834b63b56817eeeb163e7b3e00edae9e9211ed540c7ad7744119f9fd4cf032518264a4e34dd206dc2bf2326f4bbe5c07da0c41b444ad11b0b7db0b099368fa3b3bbc30fcb4f51ad13d2f201111a0ffc501fc7ef75de812366afa77fbe63fb8d6336a0114863a2c97320352fd34cfac9d82df3a1f8cf4e5568b595b04bf02cbd18c67c8eb672d32cdabf7c11e0a6d28e2837dbd295d2f240ea531335c6f3b9e19d23c9510bd7b213b6fa0fa9603c83edda5cf3797fec46501ed4d26e05a7ef8915e0ff063bd12efc5721972c5f923ec9ae214562ae3015098bd0c64b4c638decd0a993cbaa3a5bbf73307cbd582c86f7773cf1859263d0bec56246f9548a5626d8fc5147dae40b1aa0d7b7c06ae4b5d5b8a62a0cd7cf50ace1122887b0a96b2b26f21b42982a4ba376dfc96eec4ae16fd5ca6b753d5d0878565d1af20aec6ee3a64c4a558a83a8afd4ff113b0ca881a6d4c3f5889ff0cff5e64d304b1a71d7e999f8b31f075d4d1b6bbc7a0d3f955ec7e84226b57131c198161bab0e55f3f64739de325278d4871a016435c", "-752bd485882bf3bd2c1d686aabb658c5ddaa8d48ddc845e3e10c545010973bd28026a6e1ce4043ff3d10379253835efc131397b316b1830dbfee2756eb706efcb4e2837f5b715107062d3a28f3648f917da7579f1425b42b5ac4624d3f8ae888497ebb58829c6b3b4b97c6c624bc01df068abf30f711f1215c3fc9309170f79a381446e734d555a070725214c0b43f23c21ec5d72c4adfb8b9455d88411bcace32dadcf882fdd56f611856e8e44d8f647646d9fb8d94bea583ad16eb4903c0125a95282078df3dadee6b6bb37859b66e8b4f88858661b94fcd2746c2379f87949bd13e543d6ecd77db885f95acc0a4adfb076de504fbaae34e5f9c51c7470ddb5eaf1074a6f7fab8d7bb5c6cfb1aaa1858eb74a42d475a63fc681dd64bdf61fa2f167aeda4d921066dc32521405b88c7141a6ea66d1a7474fe874c5c0891cd10213e83a2d31da4ccff9c587712164730635e20a9f9065e17d912f9e530bb2dc6df7d305409c4a88bac3f298e59722034dac7b6372cbc63594ae7865c0ef2165235809a5ee500b2661a0eb0fc4a1cc444ecfababa474aea290703815a61b864467349b8f50546e8b27c5c0d55949642c4c03b7a725d87af221cc54eba7b5b7346b35060ff71614de5bd8120b6291380f04d2bcb2769c5cfed4c19c950a990f4dff3852023c7407a3509883f825f312512acfbd706cf5e30957a7e721a75743f95b29fddfb8c118f4784a851c5bbe63d7f2c7a07728ac18cded7799d11e7e412bc91ee10b1cd75ad986f71822dac19b6cbfb1730eb22e62abcbdb4d607e59c3daa36d3e576739850b9376b6abeeb3f0106257d780242c29a45c58129f35fea83fd5d59b1fcb0977cd829c1ade4fa38c8bda59cf3b4de158419c95c5802295a9d7465c0432b7a411505a4bbd51a2c80e841a4b59fd0bf64c0b205a85e5fcc75dbaff4cb39e5d7b4097698f1e3a085491f6bbaaf29884063a6eab0b0c07566b4faa3e2705b320cd221f03fcf16d6721536eb3c0f20aa2dde20896bfadabc510d45af4805da3cea34c5141d98646d357b94936eb7051d567a211efcfd44759eab9ff5d64f10afdbef9531b58a2b77568646aa450d359eb9d8b0d9490100e83fe16b5a77fbc2e4ad6ef14c370470f4f6f26f9ef8c4b569590cd38b8bd46d5c5808890ddb415a01b1dfbdaf8ab781b0f267c3a8029498861add59e843de462ebfeb84f146822aab982331bf24e9379c930d2d10a4a3dcce468fd1c127ed94335dafe401af97b3ba8c9ba187c6dc06189781e582561e9885aefcfc34f3937fecc7cc4eb4d66df3e57c5bdafbe24f7ce3c4ddb2432ce1863a4bf8bbef042743c9252bffce433631acf42583a0eaad0f93b91b0b896fdb639d8c0d40bc7f305b04fdbff7073c932babd52b87aeef649a20566087ea4779beedc42ea29a25316b4de2e44d34", .Okay}, + {.Mul, "-c12faa9799af82a86cfd4908fc477f2630a6c243b2702e55dd22c07291257bb63127759067fa18197f9398e4f17eceddbcc6b02783b721aa44b8ff368032b856e615d702d030245e4f3bfee30aca8b81fd20eba831a6aad78884cf0d12b6572c291a9a370ad6c3090616b5b3bb55a1b4eb5903553ccf72df8e788ade6ca5b9a2407aff44f6ce3293074fa87308c7d14ee538df732857271573719f7e1ca5a3a9faf083b45a2d6ad778df46c5a630dbc058ca98571a54646f70c8988ac56a84c559a06d8272d7ca6c4b38406f8b06159aeed0dd6ac811e0ecccc90079471ec6a63666e53b5bb1fdde0bd3ddac92b9133ee502885a739067cc74cb733441ce4ba71b0ebb077d213589f450f5af85e7542e0144273b92df9b50242aefc8f5be525fb64c46dfc282e8311069ec734b398cb03c25429bdf7bee3ed8d3ef345763b37f0cc0204b115ff988c0a36092567505ca96a67516d18c90bfb2c14dd55e94788349d581917c2d08fd4cb2645be756262e46b278396a52d9ad1f42317bb91673270570909f35925258a934c6d90b7a9bebad5ef476c344b364e44727ee8ae5bc42c8afaa787ef012933687c1c79db63aca653dc0ab3dd7e579c7b9dd0f70cb6511725ea950bedad9798b1993d7f972dee3f34cccedd988630e88964a5ea46ac0f5172897a05d6f469236a734103388fa99e7805bf84885f08d51ac562ec00b399b", "55f5847c74cfe6d99f59f52d7931d77c2123c7f4966d735a9863fc38aaa7e505f1125ae115e65c0a7ada45c07ba269e4b43c3507aa8cfda3d0ff7dd42b5595e7aa02da3e44e901813ac7d6ae10bdb7e404215a8da63e1084327664e1a2aa6a50f2b1affe08e3270b13495f70cbf0fd1e8dfdcca0ec41f976258537dd17fe2408fb7a79cb492ebf32c93497aa23f826739894cc6c80f6eb29f996fae46fb4cef21c973724d77c4e4d85be75d68fe60a291b870fc0213a08d3ee51cb747ae9b68b60ee7d8eb49783dc23a9245d529f19c8f9dc85e64461a93ddf067a2d21f92bb439de4ca1ea3a845b1a36fd5aff744283e191791b042b80ea31d310cad98c8c847f046109e37f171714c974b8d76c2d56a7ea4b7c0e4634813f8e981362bb04bde2b97897e235368ef3202451473f9fb6836568243e3147fbbbfd4ddee976f291cc07a659a1e5389375aa565b227293e0d71f7abfc416d29727c17985e224ae563d3b23161371772ce8a1949489726d3c0fe6e972d86bfe824ee5df7a1594b91ec9478f27c20d708694d4eb6ee9c52c9377e1c072c6de8eb0970cca6a0cefda4be6177b79169362ed95aa2497e9c47af2e25973731e9158ad9e482656c5cef4535283c0bcbafc0a287f5601767dc78b0ebd223e6cb4bc23745c83d060761120baa33dbc735d6d58dadc18650660bd3adb5dfcc6461125a7f65dd20016b0c5381", "-40de1a3d1850a51396e7a1ad98b2cfed87f568f6a0917b8e1bf50010cc7c5158791dc2cbf886ee075d095921529bf6de841a39a59033be65fdd42e991533850e7d26e7355ce773f8aeb395336629e76e765a63d086ccb9a52151fb0a45ddd1fd19b4693acf2b6645ee8048fc3039beec640bfa4510e3be51690851c43856d6d8f7d9848931f8b63b28bc8731ae1a5df553f67029b448614fbf65b81cd1cd8fcd1ee7601890122be1f16189adf2972d00fdf7e2501fd4da43101f3acdda625dea477afc5eec8f14fd330ace409d1feb69b4dfdac5897ca77672701baa5f3e08a05a8ee5c0539e91c9a37b1e490d5a27e0047a0b1f8630b5fe8795a20b203a44e061988f62d5a3307ce0fbb2ddfe71cdcb7da25b069820c8b706b7d92495bc707cd70af29bcad2242a04e0d4fd9afe1ce128a64d9b72ce9f5e02f0cf09e82e6c07af21622b23d808c325f6c7e5fdabe50434cdceface51a1ada82dcedd9840b66b3f4ff0da73e22860630f1683062c91d01d401be4e4e52a940a30910e3c8b1508f287104fe46f67b2e23953817b614dfd45d4178313795000b0a2b6af0e94bcdc5c5098577227036b98963c1d59970122fe65c4a4c108a0d332bcb248912d76467420ce16fac6cd30fa1d0db326c35c7c61b95a3a1e5b88f08d5e7ba43958250120985f5dc428c0ba212f09851b239c207ccd637cb8b289fb4dd2fb215b6a431061162bdb5bbcc7eb8ca84c23b5e683cd0a17259133e68bc04d038f1373b3a5b67e505aa83d6ff42f9182a4dd732d1ec58da87702d226bc927d1d345459825c74352d73700adfffd086856f2bc2453843203475fa2a6b6b63bdfa91119d6e10605edfb9cd7ce0cf702beadec02487b1e0bdaa6fa6d49dab65886713a16decf8d148b25cfb0165478a49bed5b37ba184a4fd1ceb570acdbe7ee9be00f77fd8335c95393ee5a8d2580e57cfd9f985e18fef42627bbf853520fbc6883621745ce2ee1c506745a9c79c7a0264efc6dfefebc8c3a29e310e30d9b831d519533d167eefd0ffcc8776f824a80f7ff0949d8944d3a871f6b3ab760ed2cd27940c00b0eceeb7c2391c3410b0977a08f422b2907eeb0f173135e6e689fa116153245f74153d9d7d85ef85739b670b2a01409352b43ed4cd3daef46fb7171494aea570803c3fe25d85d94f199bb098bb511564219f72484e479e9d4b52bda3839e919821c02cf59141f5c5fbd95a7b0ff493f55f8d5d006cf262ada094b085b9258bdf99c568d10e4d4043c3675f3051f29b19404175007e5091627d6e2ddde4732057053d9e7e9b0c96abd7c583eb4fa776a2934bfb861970d53e962508c570428ca768cd8ddb9e1dd064cbbea8054aac46a11ed5ac82d17656baccb77124421eef276d42b130f0ad9c4c6d83803d5d4fee85269c7696b4adb04895c4aa54be107e599481b", .Okay}, + {.Mul, "-5c7b087f66e2110e4cd1a42a31f986eeed9a0bbe17d12d8bc7b26fd048b864cbdd46809097b346a7046ab10b22b72bab5418e06dc833334e9c02d459ef333ee1c310b57f628567b7a9775a7ea17882f3fa59f865dd23fdc8646372cdc1d6c4ab8dbfc30fe633b2a19bb8295323d0601c214561296cde341e9d4d04e92bd2511b582a72a3f173c2da9c9b45ac8380cc10f5ed2a09253aaa2cf9d2d3ddfe32fcb23fce52d945537a1a8321c6f75796ab9eb659bfe0a997e8f2bd8351bbab610b74127491def99fd18e96264957a12bb17a4c80e1a3633154dda1a430d1869a06be51509ced055c3790df53319383dfda21d082082cc00e157436f4a8e514420a7afef8ac2076ce2dfe53e6eedeb0a19f3addcde319a3a354d76cc058fc7656d8c3caa84bf8b59fcbd3d362fea5997a89031c3419c22be13a70c7db1b456959ade92601b36c26a10416efa712843ed44519b875ebe3410a6a092e0f706a003126a602ae813f2bede1c2f49405f208a5df0ec4274e596378eb0c35a9b59bfd3d944512fb060f1ddd4ac89b4d1dacf1c51e4a3658ceaed07504f5a95cfa5fed547ba14488b57f1fc95b9ee399827f4d3c0236c2bb5560b402abf1c54aba99420775b6572f30adc5400adeebc7661758aef027568fdcf7b4f0130428658f8f21314828f55ba40371743f307bdc6770e97a9ee89466327da486340b32127919fd405d3f", "eefc9838af0fad8c8623f7c7c54d842b65d5677bfea47116fb4213b18bb2134c85d4b03d4468bd067f65eb82511c93e005f56c3a20d6253062e1e39bcb04750f1ba0c99f4428fcfcafeb72db248b3f06f4a9b9020f2ac0e19db2fc6483cd82116144dea318439c584f6e126e3c17bba8837b4d2e522c1c41bbaebfa119939cf87faae40c3879c4f0a51a4a8fc097ed6e25906768c6a814ead10e951739492c938f460f27fa037af1be96d36a99c6bbf639e611ef39d4aa1967ef133601320deb82387444694ea0e7d06a927d723d78fc7704e1ee3a39e990c1837127c20f64fa1b81b69e7f6576d92d3cdf582ba701b081281513a657852b25345706b3dd76207d7756ff1d38aba0700cfc84509b38da267e59c86f2c5d91808c68d6558e32c23fde64bc45e3c0ac6cdec8614e1cbd2500a6a8db2458a7b31289e1e5bab9e0c3c2feab10195d556c55a66b36d752a7564c3faf1ed18f61abfbad59538b015664c9ad231d67b0c0b918afd406bf9a584c5cb6967f4a8e1025d78bb3d2641caa7603ce62611d42368746a103c46d935960c7fc6b195f213f823b6a688e216c956d624e792178dd95b96529d8b9142923a42f38b2b2e4a93da0c35102ad127a585f2e46083ddd7c66e0d2a477ec2f2b8e0cb202ec3097b4a3a81257d358808efe7daad27022c361fc07a10de93f4ca798756dfa77cc57956c9b169b58ef3878f9f6", "-5655a2005642b80f505a719ca4388ca4cfb13c1b0b95e1f48353dd5e7e7adbdc0e98be2dd3bc5fd49329fa094a031d648b93dc77fd47cc31a47b3f0b9acea822948e44a33bba1cc82db0f7a46265769e8ef011c6482639d6d78862ea19b45bd3a30cc2e74949f92d586bd5e91d4280ce6c55ceacb1cf830fea933c0ee48957a2c620f9dbf2313b542b4ca8adb286e32367600e075af6c61bd314acb4edc54820b5187dff40837058ab05f6e823aff2b31737ef8b887437ef19bdae50144bf2e738dbb8c5a3fca3d7f5db17c53250f96e91631d9cf39a51ca9ba1840ac4227cf94c9204912c1ac2dd6a7f781f23f17a8d554b8e163f76f6972df4e611340411f9f9bfb36f1333fbf4c3e747154a61707fc5a1c9ee18f49bd88ff7fe8bc74a1f4b39ba0cbf22dbee7ba6b08ac52dba7fdbc99b5ad5d457923f5c41cb5922bc694dff23ea803176ec20524bacd8fd6d46fb9eb9fad0ea389699d0c868a73ab057a004aabfc821e092488e11ab3545276612b616bf3b56d3c3eb37e5e8599d59c3151a8fb4a0fa2987a19429820980b1c529ede0a96191fe6aaa8424c87d866848ca2fe409aa7a0ae63f14260cb4afbc5474e65bde73bbe42557a76399c41ceda28089c60fcb695cc0e233695bceffca57beeed1718b18b5d1eee691adb150a3eb2ac7847b93f7cd9e47dd5e7f313517447304489713e84ff6cbfccfb25ad8010561798dba1be47a72d645687d2f69d152c8a14eab8a2f3fffc133ad6794f86ad68cd5a022c8c4288419c03c67b689f8ae8d256514065c329dcb584e9b6bd20cc1abf711c4321f47542653723341b62f1fde5c0b812f462247e357842c039709fe98c3a9a3e2fb1a1581c0ba8b584423cda4719f29727afe4673f7527d889708dbc5636b10195f47c3429c46c1fbd84e9cf02658707472bcbfe4494f55eb1200d2ddcfe8bfaa8eed0c26b3c10e9b4606312c3df9364451056ac604cc129c5be8eda5d33cdecb25743c16188e826ff6673760182de371c3d139fe6072ac15820dd44f903c1e628005cb16b542d814e2fe0fe0254d71e0ca356f4e49a699974703695c57500154e2e3de3ee393811323c87312680db8dde5d0f747538f9ba736dc8eac548be7aabc04c6b20db8a3006e652ab38db38080a8b6a038cd41f25e3dc00c55efeae357c0f6452795bc7dae372f78929b9098ba75b298a99a27a71aa0e284721dfacdc397edb4991c8d3acecbcf36b9367fd68a13611449d8725efdd5fbc61c3a44c4db9f4b7d50546597b4d81da05057120ff0b774f67077b63e5cad39162a8bdee29671e5fa669a45152c23e1fd786c9b4fd4ea8fc3b6ab7ad3af1cdc2c001c3970e9b844b3353773630d00a2c086bd72a49475263ba338bd55e24929efad15c0ff549fab44d6e01531b2abb44bf66716b23d4d224f0ef76926af7413e18a", .Okay}, + {.Mul, "-cf2d9cadac94de08e5f46399b2a7bd9779facb54b662ad728cc985e363f6c058e6173f71e58aed017f889ec7fb9cbf862c7886e2515942aa72d4d69f1da2ba8564c26488bed9029b52fd46a75433ea5c0dae3eda462275f13914b7394b65797a4e04ca96d94e60c229b1f79c11443317725def52874dc056b4221a435f1810649a57d80818c191ec383b8d92daee75ea0a59e0129a97793e7c00a87759a0299892d0f7e84ca423690d754f7d4419c0befb55acc6635ad0be4d21544e784b4bf0687e5b6d8cb1cc4a8f79cc5abe63d0b68c429dce667f841a6f2a1125463457bae735258656614a6821882db35edbe5abd61b1bcadfcaa01779307c4a1c57166881c281343d0cb6dd775a3a5e10b90ee65020a345c64bbf7575af9e0e0be6de4c7cf7e7824db1b4c70fdc054a8d271ff045ef60e27c0a7e225e6bcc74cb0be19104e0306cb8f4933bd47fd1b4ea25730d904813dc2f7b3f9ed340214d978102ae2ab783e75655ac3579433c4c6714e5f9ed9f38dc6c761aa4b41a544a6c38fe94740bcc686c94e07e85221d80bf1868834c24dbf551be77fd35602163ed60dd16b3dac7ce4ecbfa41fa4b73beaeea05d9dfd32a4d70e3eae775ce2a1901928585c24399556c00e07ff46290c708834b4c44732b633c23172e7ef0c8c92c4601071a17e0ff380d74087e3133f2197b9c2021fc9a1aed0cba567856b4b97a43696a", "5f16dc0734b5854f18bff751ecf7a12a23e0f0a1b70052038634057b94f24608c009b6285a5c7c46841f6578ed06a07d4ddd409e51eb53c98d37e4f8e233e6caa471251bb4783444532d02d4dd4003a781e7ef76dfbd50a36c9e4dc742aa01913cb59862ae776c074609f96b8edff6bce096aefcef15348fae1b6d41e3cfcaa2381a643c9ea611765c319175e67a74cec0c22f3ffe1f5f8c1a968d55f38a45758db8ac6df91e262bd4ec15002d47a5392c60839d7b8a3745002a643a434bd43e2f0341b55380eba69446bcd8692f59b80b740450e2cb77cc8caf01149914f9acbe2150b4e2766273a16e6c02765f5f2f790febe49b63a73d26aadf42c1e2795381dcfe0dd5185c9515dec237da3bc670cc7a52b56b6ea5256f259297d884df76ade092d04238fd0bc227f38db5118a00714466e3238c487325c2fd5ea9ee65d2f4e14f9484314ac4a61ce67ed9bfa78f8c1add15213734a719352e2f98022e3dc526ee2cf2f9ea83ad4b9e8be686217623f9c5716070cc26137d3c32e572b097d5368b3ff3466ab2a24c3893c033fc6c23b01c642a79ababc676dae6217d64238e95fc9c91a3dfe3140a5ec88cc497a5cd4e3bd31473d6d8810c665d3513c924d7d30f5eac04e493a069c3a77d7ce2036464b4bffe0a2eccd2bbf9a2312fe29274082bfa4ca86c7eeace24fdda28eb95f7981f5b9b478b1c1da904946570802a", "-4cf46d20f184c735cc55a44ec93616f7e92c291dfc69a4458eb2f46690e9a1fc189ff13d92a75cdc8ed116bccc07c015012aa4a16e195f29cd7c595d72a1b431266bbbc52fd858be094e6672a76c466a10d81f6e0447ba82dfc14e7061357718f33772641ada38b8617f3b037601c02973353030501bb9a7e488ac67f2eaebb4273f73381e6d8d209085b47ec016556c8fd0a1ab1aacece9b6d8c370740843686ee852c7011c4bd2585f5fe1c278489a69c62936c1f9201caa4484e0a523d2c587e526e1857d121c8e01a45783e3edd5bb5a0f995816a405fd6c2f72d47ce650828b36b68a5a4943f483328dff41f0d6cd7b406d7f950c02f118a3a81ac3430c78778f4e082d1d3dcc35054002d2e7a7ce6db80cc39b0fe3307d94e64c56fc27d41e1874e14d661a533e4eb585a308dbb820ec3daf4398330ec3fe32bc4f3bedd10e23fb1def34e4d01b7fe8bad6286a308cf1b4bbbbee3e539ffe9f155da7c71cec9bcb11e39e7793bf6db29de4f701b28d6f5dac627d5a33ec07bd718d97c8b8fc9a3ab8b82dc4bb2c40b30b7b3e28a763e4c54fc849142abca05d835029b20db8f0224984c1fbc4d649fd70086c497b2a85fed45cd985e36a370f8c26d7b87fe93672c98e5b63c46a23550c3d961f3777190b3750e7a79c706fd3eb47d1f9b118a7c93f4d30af98361339ab73de6837246943dbadcf1d738b7eac2ef703ff3795aa6685fe38ae34e55825dbc81e784e5ccfafdefc56b714e1dcf1c0e790ef200f8c4b77c3e74c80270775e32612ff4ef85b843dc984b0286c75077076fb16c7760b2d63a6a797836d5ad38df9a0d07be5978bcb51da4b2d8c5eaa6a0440706923804843e963fd7aea21b2e580cdb88da37294da0855da6b0576570f0b40b41935eefefc2208941fe457133a2b0d5cb6e2124eca0e780f0de79edcb929fc6e6e8eae5d0d6b432ffee6e4cf0a6ab05c9bea386a675786b0efabaa8ca6880cee719210d554654302e997756e81d8175bac91d8bf5cd5ba6f4c3a36a39c6fc768eb8484c94cf96f0a17ff3aff77b9e23d2ee1c7e6a5924230b5f927a1f8617f402c7dfd564d3da577fd6f0864849ed3aebf153f1874a4fa841e0cec5997cd3a6151ebd945953377efa047c738c91a3068e3d48af42ef811ec1b616f1e0512f6c604ac65191991b0ad6e39397c9080eba15bfee34cd2161bc2753b2ef1c25f91f8cd24308d8859432a4e81911707631f0d1a3faba0a1f05124d7b51f33a87edeeefe0e5f2c1012c55c72f5ea1933d0112547e379eda4dea393b7cd4aaa6cebfdaddb6ccad1e0aaa3337709353be993462fde6e739771a3b2bcec5b0a8a1f281dfee988e862c1b99c098f0d741ec4eb3b47971ce8d1e30b351d43f18aabde544894ff42ab5a0a67449f8d0516df89a7dacb1f87537b86d179c4ac9112ecb4244b64", .Okay}, + {.Mul, "-d860efc975152beb63e497877a0c494d4338211659f57ca3c971cc7c18b6c0b045f51632ed5bf79f5f68f578e1d4bafe5a8621bd2ca05459b9650706dac01e466969c8f7159aa94b847adeed6829eaf369bb4e595a5591bd6d9aff435eb1b692726d99adbb78eabed2aa7d0d224ced8b194ea8491f01617e62eb31e39efa7f72f09cbaa8ba8f15ce8b266af48a78b84c6a72e5474eb770759bba9fa13ea542f82b43b198a72c3fa6a985bb497ac85147ece84444b676c3d9f4227cb7cd0d226075025cc96a581f9f2a3be1c8887419f75575aa34cb374c636143cd18f9aa609ba4b5cf13a25f9e1bc564c71d1a3d12f65dc8dd92f5f7efd3a5f3e59f98f7c73687566de40dee4a015b1624978f6162a8b9b41a40ec84ea8bfe96499eb4e8c72afe258d16bfde947c305935a977fee37562e2f535bcc1c835f211fdd707547f205713b00015fcad5acbcf0aa554e8fd21d0e4a4a270c946a6542d13fa1f11d70feed6d0d8a46b063d115a9b05a93228465072b98a8e3a6ef6f8a7272e605f9b8789ea62cb91755cccb54175572ca2f491912b0d9e51a58341e5cf14333efdb34a06db26dc14a16fed264f949f304bb90d711e9642ed0349759f827d7201e1ab3edfaf893c53599d33e3ff7d367bc4d56873a92f184f6f0b083ff6d209aa02ad8723578ede30e4d9e2da732ff1cd4b6f317c30f8558c5bd8e0544600830f6b0ca7", "6d23cd8e6de02323b261ce53147ce1589b6c0410017728669a15e8d4d15b42c7c7837ea64bd75bca6d7cfded946ca7dd24e445ba255324427a6a9a40a64edd3060585a47b4a6fccbb3a6fc109487acaaca4ae6185e6bc4d288a1807ce02c1cdb077d780ef5598149c0fa79a36a11c1e5769720af271d81fe2ae82f8675e6222ccc4502f1c4f8f8dc5539fe47ee3a04b8de9e2c8ba6e64dbc16613cf2d76458978a924178d79c0df5e207bfc01797d1d08018f6e42878f70b91687a89546e4228f3c8b5de3c1fdfadcc2cf031d9c5582986f0f8b877109ce96d9f2672b0481fd5673a1556ec999c681a9914d271376e12c520d6fc4a1ab8c2118a0261bbdfcac477add3975039911ff863e85069dceaf376892c18a3f49c8eff228c15265314cfb760890cdb4811852b9705b13589017ce02a82fe1ca56021180edf630b82cf16833c925b9ceaf2f3d86f45458ba48b0825ccee55db747483b0c6a7fe99d9017548c4cb8a00dc84ab6ece2bcc0fb600d7ddfdea52d2186df9e9549089d8350614ba457204af33a1040bf47f480927762abaa60217720178458a6b99c4fcf49b3b3ef0390dbc686e1c46e2813e51a9a199ee38befb13265150fdc0cf30eb9e5b2587b16013906b0b0cb94d0e4a02186dc86103f6c21275582d0e5d28b9fe04d7d5d3e188ba73f3d666c711944282aea142157612b9e23e79bf21f81ef1694869a0", "-5c3f8917920d12b72490b3f493777164ec322ca551c7fa2497531af84d858fe74295572c7274611c9649a4535895c813c271b1a153643b605778e0584904e1aaf1f73a46a81a02520fe54701263b5737e3b0e2f77f4390b3626c4257a29d030320e1564f20b5b89d84e74af0c2265494932369ecd3b0d6c86183e1750e5da8edf503fe76d688bb617cd3d6bf8247f8aaba76a045c9b811173f340ff3f5976fbebe4ae9ea90b13f6f8ae61b8933c38b2de812800f751bbb1e5e37c5e9b21cd54d8c39c4d6e2cfac60f9d87b9bbadc88cfad43e71ad475111fbbbac529378c40f07a0465eb166333dc9560bde283d65380137e1949aa8485d7c81cc96dafa90683ab9098c5ada8b2052a9c54cff11d88a180b5dc4e33141a74ee68a33e9068b9e25d641423053b43a98b97f2c25d9095e94a41345c8813f2d20d65f2cc138e71790fc2767a253f308da7b96c34b3673bfb115c90bcf4cd0c6c51747a272cce467d5d598bc1d7e905ad85b83a87496e5e535ee07b261b42bcd36d3e8748cceaad40783e730378f162455044ea7f99f227336f7a9b45636e1558eb74b51d2d3f6f06dfbc3006450a2c2d9c8e0901a10ce9f5a2f1df8bdceab65f7ab07dd1c90e5076fbd0c078cf3199b6c5c1e8a60986c5675dba1f687d3397b8632b38f5755183efa39221a8969d782ca06077eb67509f3b8cd9bb38f9244e77435270aea8de4d73f5abd1d09835b32572d67d1a8c458fc6479250176ae41af8350f59f81b803347e18c90b123c0418c2ac784f84a7c836552fb1dd8960d9c5dd620bf05245c72130ba21d9b96541517d33f9201704807a9194826ff14164921add3c405c177fd70c86328a46e81f96eed6b6354fbaa916450488ddf1f9425d2b0830975bee839d4c84b79ebe9fe9503ef9db836433825e5e11e6fe5211d4cbe46bc5e93279eefb0f2e2fbb1d7b18a3bc2b7aeee298ec9d19b6d302d2a235f46d985f0fc5105d9ec7a138e5ee154cd76fa42127cbd14bf7ee586f92d3adf0ffef57d2ce59690edf9e2e52203c0d64666bab640f83225eb49ad9cd91745644ad4c0aebf798ee39a6de210fe8eb49b9974c941ec7ef205900e133cba25cd9c6ea1894aef57a771632fd022f7668fc50b5135d95ef4c1ba658d029d938d97b354192ffb76fcf7073d97db371441bc566c40e56f5ddd43d36805f3827dccc219639bf6d91a3d20fc8eb95693638780c7c9521b383a1c4424536e377245235194108d4d277e72fa5aa93e668934b26d240c092d101d21c7b6bf4d863836f4d666be01425ae60bc0333efa7551264fbb19b38c86f943a5c9fb8dc76f2a8646ed16a232e4ea9ec1456d033b6d59b29ec61084a69dc1a67b89126e51bf4260cf661413010b2a6bf4ff9430305f1d911fabf1f3ef8a9f01b048e73d408a34049ced38ebca202fccbf99106760", .Okay}, + {.Mul, "-c8640cfd438f6082294b9c4d884e58681c525938864578c418166039dbb4c1040d22dcaa76e4b60f069af25308e5029cda647b9e37caaeffb295f235cc0572182d8f78d6c47d67b235e2a9adfc06b9812d2cd5c52f7c4ba10c34cc51d3650cf85e54df1864581057049e24ede47b93b6133f50bcf783ed2785e92594b69b4946d8bb02c2b5c56b50a785c3f2a183891a8f3e8f7a62a01c82ffd45d7f0fb36f67c174076f5a8fa549cf7462b906fe37eea81b233aea34d34c496420ea249662343d13a4d1746b9c1071505052a9121d56b37eed8860aa177850f7a61bdbf48f22cf3db1c7205ed38ef546d07ddece5c550b28d755d0e129cd376086680e4b5eb67b362b4c69d9b57d0b527aaecfa59ef47b003ac3220b25adc46dc784d2ffde66560c963cc96aa1d3a258d5f92fec6ef82b90a6dd996e1019683edb75b022829f0690f3e5d5caf51a4e94ae1bea28373f7d2122f2833399c4065c0ccda671ed858bee8582fc948e472a79a6a8a4c6e5c06b31bcae2ed85884c44ae0b29900643001ff688276e932038f5a62bea1adce31d2c2b788ea7dfbe304a2de35b2988d1175b9544d7090e1f46a292e848c247ae7cb8ca969050f2d7299c58d80abcd516cd28a577feebf341a8f2be0b33e0016ee7fe4b827aee9f08b7d8e405cdf399ca755710dd7f438741a77ac9f3f08538e95ff5041c4fa722117369b32a5196ad53a", "290ce27c83e1fae261e317bf786bb775ab99d3d62c6bbbc587866ad5a13178c309a09177199a04cc75a0609ae897636292580ff2851373d1990646430462a7f67bf48ef0b744ea4bf812efda8c51c79e70895cbcbfc11a2584262c702e06177fe35dbcb271b302b24e8c183ddc1571c225b8a7c26b07e9fe1cd125107520003609afd039af90f082adae75ccebbb4f57d92df186cf4ecd732f945df527ef75caf9379c00ac150008d4cd11d35e1f55354f72d60ade81c8cf1e512bba2574c014b44c0a0f317dc941faad13bb61a3fda6c9472d9a7b57b42053e68c335f7da63979113da4808bab73704aba84e036d3ebb01141bf1ae9f07753e8061430e61b6aab4430f29558572826672b70ebf04366d0bdce4c593f3728a2193f603cf4f6e694d8b597b6f4f1331dda6c8fc1e3b1c2a8e9dba7972a1a3efa65a9b70d0a9a5dbe1d405c59b8862e8ce95c0fdea64e435aa7172266a17dc5a01b9639c4c73a27f7d382059c2e1851a1c8972bbb2149b1e5147fbe85790ce8156010b77da0fc4fa9aeb7f21fe3014742ec2b9acd7a6ad901a29bce31a1f06f7b67fe1a9700168cc23cf7b13029e788d69caf52c454f4ce02a055e386739e74f294e58e6b19e03ea7d8b536849fb3833da87f9c2e61d3dbeb3aa333514f1969e2e16e8cb8aeabba12ebdfe189e00eb1cad9502e4e1578dfef4a7761b23f48a8b5e320bc71682bfd", "-20221c0ef6db18769929ea44eead48a34f4379d4d1098da34e5f08bda99f37e60592575f836451b8550463571536d060062a6a571c8404d0081860955e9ffbdf610b060dfc860c80bab31d1866ef864a9e6f69a5c2bba806c888a9d768eb8e9bd2d359efcdce1011cf4d27c2fced6e667209f9429d88967b4cd9f1e29e90b0fd710e5bd097813f87ef4264ece4de584a329376becbe62bfe9e7f79a1cf121baa004275d81d5f2b03db09f6f3a55d1856f95e29986a094ee1c9e2baf4197b7f687674310df32894667e9f2611c14bd573b088adf99b59dcf295065a911a553aae72c0159e4d1fac9da1fbb8486ed7ef0087244f07aba1ca3cb4337751edf3f4670a6f0cafcbc2e36ef2c1eb92fb3b49b7ac873ec4a6d6515ab511bf2e9db7d233226cb9fe69c29ee82d539ba2cc51eb4b9dbc04d10f2ac8778f180fc6d1bb830d79e4077e05b0d70158aed9a6d980c1313eab6e3bb75c1b6226b1ecd5580fd86c4156251c280d48ad6abe9f8ab9ebce0f5c17f473bdaf0c60301d18942357ff271fd78c08f5b5981a1ff660a5e7044e5ac24c559c0b0d6c9c0c2102b5a3f5e5ef9085d78756a3f12fa15f3637969bcd6259f121f4b8247129045bb53e6239b09a628878e5f4abc930da734eca68c388da40b336ac1a8db32204f1d7824e39c7898c88c600bb407c9154cc1d559951cd4b6b481338be878aeb6eb29b104a04d71b6b84941c2506f0e8950e9907c23884188f17d7912ecedf46a57a29569fc3d2fb466089cb9a885d10afc067d808cc623f02bc1aebde7b5704d4044211149cb0c6d2587c62e8b1fb7baf8941c796030ab329fd3516a3ed8c5cfd46f1394ce112d486758d40dbefde3dc5c39971327fcb4878e826e26138d97bd1b83dbbaa69304288f136f417c9c2d8655ff203c3d8669d9b82a171c5a5a3e9aa73b95c587692ba0e392303ba01f355f43533bae14eb52069370166f6e1cf0cf4fd8ecff0d06ae0a1060396a69c3de58e55f1b8d92e7848a48123fa628067e855e0d64656c6179fd3f211698216bb7dac37342092e746675dc23e7cad6fb4d7cfbfea5f75f287cea1ffc91303e6c41a03cdd305662d590619f5fa1408bb2cfbd87bcf50a6f599644612397dd7f41b6fd11ee642b8c7e033202877e1c8f60f2d3c982b49aa8d5731c564714d14a59e835638e497eef41fa8d629704b95b45d386d32f645da37bb26265a011eb7dce74463f7103c8457bced212cde1b2f385d274235a2cfe257d016bb0d6614b781fdb28782ebbee7c7237df550995a87ef90f76c10e93951273e8e0b160e72b55a88ec3a1ac9592dceb2882b70ff93505f449c45cd7194a93f28a6d6aecf97735065f8c1add9830d86bc5f727136175d08446279dd5370ad94cb266481f77f38e5b81284a4f7513e837d293ad5850709e86f7d95b71a8c49f57852", .Okay}, + {.Mul, "2f4d50cc9b366746cb6b266d9f9d6711932e094ed92854e1bf8bc24674578b6bd99019a69b23f03588b516be8fabeb14bbea6f6c811b63721494186fde1b3148bed3ac0bda0fe081b639ce3f6100df72826c52971c268715d21d2ab61777675ad9eb1ad3e82afbc64741f06b2eb9b88a5e351702f55740c174bba703de1026d26d561574597e9af3cfb03c9407fc5cffa3eb0499b9bb148b2040f475c7a3e717263a4148b9da13a1a72736935585a84c423b087b3dd7da8b01670d6af016d750a73e3aff20b5f4848b46b05c61b01f290083fa71c300eb975cdfafd9c3e6d62e47ceb542f795bbb1803527bb3e9a733afaff2ea8832693a824b7a8943cf5a64dad6f023e28145f4d16a4e4d0c53a2f9c6419bd04ea562447636f2eca2efe8323740c55c4862d0e07a2445d23285b932463d1ed0bd03b71b734973fa35da32477340b2a6711a33dc4291455d131b9a0d35943f4532b504460c71634d682552155a08eaeae35bdfe4bf2bec10300cbd30103862b41cd95769bc82ffb7b107ed060b288706db6813ec53f6703bb89dd781e426ecacf3809fa0928b8c3399b6d593cbbd61515b0d2e72fab38315aef1ee103a9bdbe660f002917244d1ca89455c8cdacfb52a65f4ebecf25eb9e6c8d61f56868dd91d34350c392fac82d77c02fd33e082a28ff4ca559fad7042ad60fabce0a31f60b0c6963198d890a46550dcbf175", "59c701d0860f731b9cb3e557be7bf9883389b31072381b76a229c4c8d08bb8560b334e81552e06ae8074b066a5e05bb20c9b938bb589d74a16697bea64bedbdd414925fe4cc649ac0151e84cfa57eeeeca5bacba6fb32c09265a40a735205c3499fb630b4b884aff58e15152221252ab8963bfe275740ab4ff93b97fe1c95af931034ca805a0c5be4dbf50dc2afc79f13f1f8e2b5b32cbe01619ba8e42c6db9540f958b6b2f7a6d3806454326351a9dfeda8f8890cea76ffd453463dd7e0bdd60f4f25b6ccfe540765afcc01dd17ce07ef1589fdd2f5def3ab8892a6feb39b95e05bad8adf7169cf7dadd8139104d52d65987cd4e343047e856c46a6bb3f0e3dd245e4f46146248c4c836ef3b44acbaaf760d5304017615ce8cf8fe449dacd79eda874636a4a43802ee91176d508e4e1fc298c6d3b32125d006fe3642383170da24c8367fd161b4a6fcc31820fdf35021f6be8e5130850936126c3a29bffdd43381a5e3087e019a4797504a3ff59f3e12ee0a7f3001d979cfcf8b0954fc4afb52055e484b15a86c718212f7bbc4374be01b87056a6501da9d27a8ade16503f809ac465df2ac3a84c0d844be617a7c004b385ba569b57eb264e3484e3a76e26103c0e1e9409abcd6e3b6473814d68c1f301f5615086065a46a9004d9536d12540fd90d7ae1b2c8e29e0a0b1a93025fe22e549d9bf6ca261df4d83a49f7224e5f4", "1096a686c5ea5722e1feed3126119ab190adf4b07b19a0a7fea0a537383e64c18f0d32b78410cd8f5bb197e3c0571f2ca2fdcc6746f5455dcfb75b75b27b3d1b89ea0a78f77cf4496b28513a851e458f50d5dfea959fbd4d47d7f6d0116fe6df5f6e763d4b5cdb634b3715e609c714a11b2fed6b5a4d71b43ab39a2894d0adac62ca7257fd27d39a529de5513e0b47f8168027dd0cc8edb5aad6ca843157f2f4e1bdc10d8780e31a045d0ca41f146bf6b814bd64228b558b8adaf7b33c23283d82a98b984dd574a4f6c1de0075a5575c48e87fdb696c2ec853f6f8f349edd1beb8b10d1dd0e06d8369219a369073d32b19c1a76af9af04366b868831a0a8f24f8b7100ed1e5326830f1771f75488ee0a08a14a488567221f4ab01b7d4447d7789b14ca58bb812daa64e4ef9ad17ec226e435b0d733680ca1afa59c9531b880762c633af89d24bbfc45856d454c3a2d44ecc665e8b901d72e3b57989a6f4c51d5da307688f7c6adc57fa4d9c42f0822a36ea1a8dabdcf2a0889d1bea780c7cd879ac05ed589a17a6bdfb95dbaf45ef6005fa4d798e2380d73bb6c9b3ae078e7f5b10152c2da7fc5ed0f9cd20e7175183c59f10b9563e3c67b37e3feba2386a55a1fc0946d4c4dd724286d1472d64f0e4f2beead7b2add128cb820871ed3f4f1ff9c0174951fd822740d9a46323ea2e835275068a677795546fb94e1b1ecd7f2f64c981c6cdf8c96162224739c034e3114fe0e7ef6a8730fe8e46c15166daa9653c4d5ad52d7d31ee8ed1c280586142c102dfe9193b5c76687601d3134a746165c0cc61ee02970139e851f055d33f3716e35379974241c2a107dd6732f3e54b58e6d20df06e11bafb8a1010efd94cdd4c4416b8549f7129df411859ce4087fc57e35fad0827831162a45e205011ad8f47035a322b210bb0109edc92a1600e7fe89498296abcfceeae1d2c86e6d57535a3bf6141d7102e3504efd9c6491c98446c759263b1a08caf46dc2771eee3532f3d3c0abbb2b2426386bf7a7e05dcf72ef083b515e2ff4f59ab21f8042a36b7be4faa01130dae5965f6973d68f11c510c3c5cc52062144a29ad286bf1369929feddbfba78835f2b73944cc2adeea22143bea47b47ddf5fb4fb01a14a2bcab65f728289344207cf2460fe728ff8b5ccc8807576bdd3dca379595a6a67bccab2010403350421cfc16d9d0f4ef1e98828557f4511ce61adae426a20a6ff7b49837529e337753812b7beebf7c6049c189f4da28303bb7cc36450d0243353d4f2a3e768252c32dd766e0500ee7e6ea87572167e35a178448db2abd677d079274c019428900b7b76c7562ed0ade63040a85eae035d4241b0c2e5c54f374daf5a22a14f15af6d7b45803a7dd8d10dbace285cfce2b4dc3ae99d0b6a5472b86b7c568484adc6b812ee0f6f890bd28b08cc47a3d3cc84", .Okay}, + {.Mul, "5de641fa705b388ec3db0329415c872e0e60fd1b7c35a909ad9f1c161851d90c45d9e147c7989f871341a93fb5ea8c5f4e841a3c3de325873b61e708ac820a22525e68ba5d8837ff3ab95ba29d6dbfef2160ff8d4effe770cb5204d9b451294fc6b55fd4c2c3ba1ef7642aeaaf3f959c75586ed2cd70d55ea17758211bc3e76f1f31cbdd51a90fee136b97874591420c69af96ff684291fcd0b8e10cb3cc8b3fa42687744088af4056508a114425c4aa98917f543eb4141740e94cdca442d81328a539e07c2c6781c12461b5f2c0ac1f1b55c566651f0d5dab8e81868e40dcfafec1e9587f05362b18aa27bd788ad2e39ae0a36a939754c179376925ca0939414162daea4a46e6f42cd93c0b9b39305dd5c8d74e1cbdb8cd30d58289232e631e8b4235f1263ada0eb6b655ceb147f7d9dbc973891ce2c7f3c114333afba8cea547064deb704dd23733bd586635a94beb782a68d881dc108b660085024e41fca89e98a00000cefca2296029b522da83a4096881bca91bf9bcf1d5fc6d6e603d3b4b007844e940c79acc68a7d4bcc12944bb3a321d555c898649d1f2c0ddca8dad1ee7146192a5303275491d30c2315cf841f2bfede8752982a14575ba03a31b8eabc21929cb4d9dfb34ae460eef5bdedf3336356de5fcb56bf45f2c45f5d448f84299b64b880678c214d9b12b551bb681e526af99033d6957cc0a3fff60452084", "fe71cce979da88d9bf398155125038c9bd7211d49425e7fe1cda925db47823758f7c183f4fe68a8c75b1ad16e74536e33b053384c9950da456cadee71c720691896c3bd521bc389c5db17ef74b81a98b8d75169058545b1efd8ceeafbe14054c16b87a5be60e6959cfee19052dceecb61559c3d4f14beeb2ba5f6250b0fcbda7b606aa6026abe8a0834077f03412c8d80e83d1949b3b153f9222231893e76bf60a655f9b58e1ea35a7070b66fb1b6533a56ecfebc0626ede2184393d4f701cadbdcc6035a69fde71472cbc4c71adcfa9d671298147f18490ea978aa325d885b6a5abd123f960b2d8f9bbda8b2dafabef4a6e5670984a2de5a9b4917dff65b62afd76d008ca1bb04e5e8d695e20b52f5fb1bd6f6ec11e7ea1e11f9cd8647eb3a630f50b79d1d4a5124caa9d936e39ba8342f59ab0d0ec3904fe501b9d08b1fcff7eb86f38459b39d7fd899f333f88bce5dcce2720b707373083b807af814477fe478e75a532c89953d822cf87eb66754d54687545a72735bc5fe1dd0034b3b43f0f7fc319d6eedb075c63a65addc510e46f9e899042a91792d3b1647dec296bd8c02b6d25b91c48dadcbaebe53fe1d3b667d2995ecb38c6b6e02018bf7e1435c497264a8df7663febd6f37c5b199a2f2a29431fd900c8939f60d4c24a7aa4d42d26a60d9ddae822cff3cc12472beacaf076523d879a690949106f5ce96f88a5b4", "5d543342baddb650512da6243a704a5d1f74fb661c1fd0be9f07730c5e77c1ff0a1b569368d57d0ef732b453333c715168cef7e8431ee920b66f0d51f6e8a07803d6db81b478b28f0d08eb5dfa6da1a0025e99e537e4a4995be1bbf51c43ac3aa98408fe028debb7de65964285fd00963f87051fb8bc2fa928eb3416dbad1a19be0f63ae72aeccaf3c4290a6a21c0e7d5b426fa178dacd4b15542da199842b22587f9dc4d413812eee9d1e53aa366d2612c366ff76b6048a870b6d067cd35bece4ff3a6b6cf0672f428317dbd55a0890e2f1f7903293d2f556e016ce8970d26987884deb3e274141d171565149457fdad0962ee1ef5c143c91e30040fe864434004bf80e9b139fba7f9d13d9c8366270f0bc21788a491136f5c64e73ead569750ee3e92ec07add871a62fb1fcb26e4386dd84ee49658d083ea0c4377796547075dbda1a4974f264a117a37d5c1f5b0216603d14e940b0bd5dc4c2da702630e684a914ff1e2089a0e4ef48e63c9935578dcbf3525aa355d58d13f39a736ff337a0ff6bcf41ccf93f8f1b3edf2cfd4f9e21f5db80d72bf99875008fcfac8e977737a0b3b3016185eb8ad1c1aab62a0706172f87b23248e8cd3d507d21c4a90d1ecab958681a01d64b81512fc08466356931f16b95b572ff9aa7f009b5f7aafd739b97e94ff60371b8e779f78d48e0a1e059b97e2977704f4abf5f6b591cca62f8a308757d9121f1e842cd6102f3efed9ef573e99db977a9d74df610a05c539fa68098ff05342fbb3f5d78467fe55eefaa7e245a8c999298870d352e41d47257d4f7342d3bce52279fc91a67093b8a7b189af508b8133a69545ae9b0fd6fe83bc19868e9534ba4266827f0ad06e9c496307019a7064a4929d64bc51bf89a7b0a6ca34c8e59243856e06c79cad963b0aacf6e167423677f0952b3e4534d4dbfb09aa5115be0cf86a182eab9164bb7f8d38c95aa155398b47fff9c20ba7c2cb5b7d832e2335f38cef1f068f5824e918ed89ac3447bedf65a630978ec54af87c62f7703d7fd042c1937b447308bdf11c615f769978103c68330666fcd409039e697d6f2d03e3e2252815d439d1eec1e96fba823b44e04a4df8e43920d388b79d4a00bb56fdbacc99d68fa2c1fe3686a5f6d0b81ee6406ca555dc07db3ad5b2e0339bfe9c7ae2e9c64d44f44d0c434910b78bb8f69448831eec897e0551eac8bce8e87c55139940edc621d8a17e4a09cc6ae96f52ca00e442a596747ca2e1d1c7322921bbfb3a3d08aca8ee1f42baafb632c0d577660d427566184db168620f7fa8fc008f58199f36fd132e712962a5115c14773734437fdf9657d838ccc5dbc65ec564429d19c3493810fd2fee6c4861a05d119371322582146b460f4547244e69a5865f300d2213eb52d06a8efd25334387c2c8f4e0629e427f1c9cb3be92c0aff0d0", .Okay}, + {.Mul, "-d8b2bc30f5b32c97432e2b2f94a52281245d30108b6e2e927a52a98be61a207e779c7d7a291e07cee6d448ec75a0ea796fd11951c07c69a87b12f17f6607a619b307cc011ce66d276c9fdd759efff345de611e39a5d6de145f6714929395cc5fffdd136eff1503630a4574dcbffe48704a960894183b7b0331d0e03b1cb8893f3833f1c7b3145b7896e22d814fceaeb44f174e7904e33a10904fb73b657d8f646ebb162d35138a1f248d8ac11bbc43b4c489d02eea231a12bbfc331a055875daedec2c0787535502158dff95f79f1087ffe1b1b174b0811362c5dd03a32b334ea5d09b296ee8c7ba994a5bbc5f62971f66cbb7a347011655b4d1fe55e6a35007b1a2a810f64a18c91081f0dbac475251f47a80723f99a084bbb667fad34c208f4b0b2bb47c3a4f68909d95ee74fcf8ef381695f91a917b21f5a70feceba0323f5c9e9b22690dc86c52d2c40aa3f1435333b1ecee9c4cd8fe04e06adefa8d1dbe9323bab139ee9b1e887e6e90ed8ed02a705d2bc91d3ed16ae6860fb26f79636fe5e1301fff8020ba217f7b691b91237c5045b16f7fff1cc97666f0c681186e8ebed74e4c16103c784f216efa1834f2e77e8f99f3efeccea3e42a0dc314e0d7df5a5cce64dbb1552c03f70c3066ccb4ccd7d921d3f4d6a7b4836eafd61dceb74e5e0171dc73d0aaa7fc2430e41bc0caf45e85fe7f859fbe17aff0acd8b0532624", "84b72af38354b5bc067d36f21dbc67f76ffc50395b1b19904f70f4a60e5a6d2a5996bcb4cfcd7e3beaccf7bb85a40fb95bef1b22cc83092d0065fcf2eb6d5e56a814bd9d60012f1af1fa425ef898945f1b4ab6411641f1a0632aa3afbe9e471069cee7e7b4fe2a4acb24415566beb13a95c36dfca6459d592465b2f77910d44e7f73f14a7e2e44adc0105aa6be91f5487c4e9960a5979dfa2f5c3376758395c8cdcfa7072a59b4978ab49fe5a4427736dadda8186e5d037324d2a151ccd721cd8308177972102de9b4f424d03f9ad308c7cfefdee339c6265b668e0e289c7e930bbacbccd0a1882840d5a9b267f74dd732502a3f5cda6709bb6c8c9c2d6722bb3dfcc6f4fa5da4442b36233c513f3d465d176e596d756883ff380328f33bf7524e51a5dff779e3f85955086654ac9951612930661945b703fddfc024b43b4dd3f0b07d42b6e81e9726612f49bd797bc3b2303ca4192a6ce47aa166effc052eb4ab65955a89fbc80165979175a201773a012977dbbfed5b7249fcf7aedb93c4bc92879565f8ca4d2b799ccb9bf566ae8620e342317f3c95c7f0ab3dc47f31fa9a74c4fa3c34d3b10318b3ae38fef9acac2c5bc0bd20c72fbe0542a3a52b2ed70b6ba32f1edc644deb8855581d1512d7bf667e475baeaaf26cc5ec702543bf2556cf39c8065f92205be356ed0eca102a23356c6597b53085bf2a1dffc204c4bb39", "-705735293963dba3d2c34759962db1716d8ea4b862251266d6b8451952e0b6031c057dfaccd288e973c2fd54b7bea9aae2d876bba5ddcc8e94b437b5671c8a82d0f9929db003446cdc2f67072a34876d2b386e619b87bb84a4ef91236bb17eff3705c075eca51824a1602bac724981aa369339c4865d391928949cf6aa62eec3ad2653d0191fd7d9342333548043e2a1df6260461f5adc023aba3a7c4bd0fddeae9a5796ed9367216be9e7a7ce51c75cb655fa0fb5199f8b528e0ab90288042394f0cbbad93014d42fd8dbe6830c6f7ba2413c2bd87bdaee1d0d04b65a900cca52614ba8f73d2a74489cf2228f09c3b2186f90917e9bd89928edf96883a235c4ceb24386a2ae832431e3b0a2e68779240336a5ed8f14ca2926b8f060e50389dc09cf68e6f401e0c7631ff7287dfa93a58a31e301ac463ca3a0aa32e25ed830bf25700af23d0b6f9c699e0ddfefc3845f83390ac240ee465fc307c474a4b6747fbe837451ba286f89740a936472f735894e7440ce71cb1ca10c52776272daaff5cf4bc9c3942bc3e3bbe3ae7bc9da7611d14e769a7f295881589f101004583e482ec3971742e847f9eda991f76a5d8363a278ad00769ecabe29916cb798a1a4a30c0c30b0b0158c8047e0d2fe24fea66eb730b824d92713f41d2caaf5450e2d4f22b5a121353d7a9c03e931c966d5aeb803519c45abad00358e4010de3455016971d3cf577759eea3b18e32333340f2b76b63a532edf683e3a7c8ba7765e46c5b38697ca1307f784fa9536963c6b26c879649dec58c56062dd25d6c9f9c585cff5f5ef31c124a03ee18e80271dff2f11bebf6161e1aa37a29fa28931c5f042fdb8efdf883c3d8eebfc9cb2232e8c3017094fd63cc84e25c7c5a1fdc354bdbe4d5c8b13f379d8d8994c498487043bcb1b75e7b54bc6a517928d3b20dd0a40642f901ab421d64d88e69a8c13cd99e2bc6212b0faa5b42d360a7f14e33ed1dd292deafcd2383ebb9b23f3ef78fa4dfd09168348312fcd093d52828179975d0e03fc8e2e4091bf9f6ec61686b0613fefe2d256298edf6a4b35062374b9f6c5ed1ddd967437ba92b0ec405431d8aefc25ff19e9324348e8a04a8981e8a3d46f54a7e3d23a7b0597b4dd45d9f3a7d56f80137e6206d977cbc134ef8f07aa9befe230d215dee417f1b476bae2f2faa423f6cdca91a41eb98d5b022c4dd9bd6f3669753cf16ae6c67e94681ea7613f27176e361767e059ff5f337f7489f292f8813cf7aa6b5613a59cd89c75d2392cf58da8d74d2bf9cbcfba16ff8e12689ff2e1dd2dbfee1e756318f1d2923544d569165452d4d6677538729681296bd202426e2fcb239e29bc9bacf7f42e7f8a624f66ff40ec7dc7a75957e12d96a8f8577dbc2893ab2eef3a1b58a8bee0c5d688e8d31e4d6bbd75ac52ae6f1b2245f95d495c2efca04", .Okay}, + {.Mul, "469a13452fdaf61254946c0985df44ed9825c55d31a49399e798c703e97798982cff90741ec4caf67a8e45a67e7dbf479fcc923e33afd02d492a63a60edbc46093934a3abd52d90bb1eb5d30f65451b179c0c21bbef241216d8a3a9273e1f38064d581245c704c16106e6627b9da028a1c137eeaa052073d5ea9d14c2842ac85a6cfdb2098a0e12dfc4e897bdb0cea5c17b35815aeac9af4b4e03890d23c2d944b30ade3efc578776e43cd437942d6063e92ec667a2eda7a997c4cf6ba5454407033be19cd739e997000d4b8c9bb48ce6ab6638b7f96e0e116bc8eb467c5abb59475911f88ea98b954c77ada1c0036c684db80980cf0847d58937d3bb544471583af3dbd54f87f7c43331cef1cdeecce6dd9ae80e2b2b373dfaef50a6c91e98fa11d3910a4577b9d745638fc54a164dac51577aaabafb50c637e3f7243eacf789e19df5e9970836375548b5e7f683fb3624207b536c411109d76768a0cf05cbdc2fe2809d383630bbafdd7bf1aea7f024cca4c7d800e4b4490849c92023dc7a25a973264ed0690fe5eb6e4019f95707aa73cc993f61e8132ee0af18ae1e0934ce6dde4808ff1466a9efbf03ce0a9c7163705408c2646f771a1a39ec57c3357b562e1e95aef39f35cd6f07bb3b8b806c4e520c8dabb530bdff6aac4da8440753a262d10a5c75ee92d91c989e085880c36eb79c70b793c89e205544930a45e1fe6", "95d2cffb239a02a076d278c55af41a060abaff988f75df249ba0e576d57b61edeae65bab98635f53a33e81c0194d86ced6a28bb5a248abce3b0bc4d2791fd213409f57cabd796d45086e26ec648563a8bc6902496f3d7b7c5a8c8d72aed3ce8d2d23bca6d3fc580f0a62f80f5fef24f955c5efe5a235b1f24651771dbfc3e6d8748fc6d8bed01d0b720d70b4ec1d417cb8ff5512ee26412c6fa332d2be63fec0398571c8b3043045ce73a898cbd2a216492baa1d14496a8f3fb8471ce471b0178e79effad0788034abdd14024b7d9d51fa41278e41a202e1a7c37bad52ca6f4b17f5e877259990ac7a098c2d5175de070d42367f5c1d7b815484a5f8b64477a4394eebfad9335b4d9cd777f11fa5210e57f7160cbbaf520062ef8ccf474164ed92c7ce96c8e9f3bc1972a6a07a6c8fdb65a31bc35f7bf013e8a21adc7b87a03efe5d3e7764b2a990ca4d1a61dde8ac65ca8acb3368e6dac6101b297ff4aa87eb01d679884f359e409c1b204cf011c53838125b1534ad104790f8f0d81606863ab4097d607afaa3443209d5e15f21c129fea39f7f179a2cb44009c4967194b070b4ef02ac9281c05c9eafac7fecac5e863ca4734810495795ef4bca95a1906112743b6e75677a7411aa1f62559c85cbc948076514a528ade79209969f41d022b98777dedd38424b24af975c6917970055f8bb5d7b2f8ee84464e9d4a1937106d8", "2951d0f6ec13136a014d3a8d9c786f8bb5e68dbf7cdc037528f82b7d992a7f0af66f126dd66365408cb362523b50f49a34614e518ab51db4a2b58ee94049bd994c61befb933b60267b30ed258c7bf0f59c1497a707fcc21f6190d3d1c0dc186ff02a5e89db0f69cbd81291fc9d7c2ffad63d25daba8130f163c8fde7a88fc7fdfc4925221c698e356e9a59544402ca7773e7c54375d127e57c93acd54f190cfb2359c78b8a6e9bef1247a53eeddfd8ad39a3570d2abe23dba5ad653668d773df137993e9c108de3fc9cdf2aa6733e48c28ab688952fe643fbf4de300535b43f5f3e8cdfcf6c9678cd82a6bfe148c7b0bf8a5c0f8eb2b345386850e838a8fa329a7d10784901d37092b7b802aea502a2cdb887824dac376054ad1a4360166e8a421a2512ba7c0641b65a889faac7d138d218b7c79c9bb72d58167cff876840f2de97a3c6c6d34a06f2caaec90a4aa1e1b046c5d510b18b6bcc14e60611a688350e386778c607902d403f4958dd0e310b3969f70546a95f74bacc350b1566f4b0c4e9d201b4ac31abd299ba5c3ecd97f6f202ff456dceca1f88a98061975695427881550b576b531c7495e276b8bec9a703d71b1f1938c56990a8bd482b27fcdb83904581ab509b76a2b6b5356cb09a6e27d626475184cd1d99dec06229dec172376f38c6cac1051539d403b7ec4581e851d100bff9707e9bf3f06da53e757149ef4c1a9df552182a27dad4bc34673f8351f9b58d0a6ec0bf7347b13a6d2e27e53b1e0c87adb4275c02bbe210884150fff7c55f3c2eee1f8b7faccc8ebebc3011231cd7ade4366debe8a503c475526a667c10b862a2aa13c2703901f09923406c49fe3c34d6c1a8d79a0f9bae19151bb0e22aeabcb9e688463de447209a967ea0c6f6c9cd07bf6110941764e9dfe843cddd599b044930508a4ddecdea04bf63ea3ac2ff5615b2861b8ab407858f7738006b4a62a2f21442f1e8b1420bea95ec6c0b55e830ef5bfd97ca4d05fe42951cb390959b3b0b0dee2091f2406c75bdceb207209392b0f357b862a5cdc42183e33ba1632285ac406fb1ca0d85e44012c67f20f0a19fe207bbfafc29859bc8880e2836bac11cef7054ff7c55baf1716623c022e931c39526f5af71c38f5aae499f108f2bef765b52bd8a5d49928e5f0c83e0f8280c7aef2a7bd38e8ff0c27c486c7cd37684407133218ff36dd7e6d400bd2369472936b99d96b4ccbf8e06476a357dafe33fe57aa2311a11fe4fbcc414c3034335656989e350768c98e13bfcb2dc2d2e204f0bc8c009d93ba3d8f70cf6930bba62911a45068e621486b920da3efd33b9d057efbbbfa68cfd37f304823dbe12d7926f8da8b38b277b7f3ccbab07ad7cc64b552b4fd565e3e9fa4ab85705082c11fec4126d7105ed5aaadb1743ae7b2a4c1d802bc01b8f9fde7a206680ab04e10", .Okay}, + {.Mul, "-6a82e7ecbc54a79cfc94d0ca2941a4adb08f7a45f6dd6d70860034e89fdb58ce65a35b878061964ab589b539ee0d6de2cd34473dbf4a57e0224ec51c6085f99574246a39beb858e94f97a84f4a3c4715d23e2cce5ac91dae2b002e2490bf85e6a6a1c2b3124e21fb4de27964fd16be3a3a148b6619d25cdd6109476f379999d0774f7d4398270f6d175d22cba2ae03cd0ca7b4ba15dbc65390445c0073a3c3a27a72dc8010ea4a87e201c48579b38d799da1dd5ff71a702401d963ff9ea37103a942dc96ab0e0ed83262a8237363368429123c53bbd40985e9eb87730cb8c51f4734ac6c60869e8c141e47b09e7456dbfd248ba667183e9260e162bbc129fab05a3cdc77d687ef059c0a4cddddea4a7bb29ada22659b1567537698a4858a6b9bbdff5837af9d4de4ac4527214867a2e59f367c0fcb61cfd492c5b230fabe4ffdfee8f1fe05470ff4d7c22e0c92011212c2a62c023b1603c94cce641c2366953969f2f92c0d7f61c3cba119cfbc5873ba968a1890438ee9f9803a8af41673d638df442e57e72649a84559296cdccee4385d9697e5b8f4274844a164d8c03b74b2cbf261c9abd753ac7b6b4f23b2f0a85c9e2de2864d7c90c2ae55c49e9cca952762cdfe0bb7aefcefb26eafa1efa61e0c4e4333eaa88a2b1603b1e615cd00ba7b42d2ec7d164603c2ab0bcdebbeeac813212d9095a6d6f2f41cbf9970c4bbdc1c", "6a5114856d0e2fdd632dd191592e4ba2d5ff6281d74e35f63200c67ea3a4b747927e467d8f5a81da9630f7621884186ad9139a00085544d6bc94be35083f721703995c98c10189a7ec7dc3e0692e8478d742ef8383882c868cc7baf6f5d6a0593b781ef468d3aa672baf53de1fc9255bfcfaeb13101a05fa2813335680a3dc6f869ebbe9df9829bee8432e85a010046349d12a59e4ba9f16cc7eea939d7a7d648812163f480dd1a51125cad7fe672b83bdabd2355b488115a977c0949bd3cafddc9d05eda451e391d29d951e4d06a3de3ace7742e34b1701cc2b4938aadde6cda4bb6b00a430a10b141ddf87529c6d4fb93b441bfa5ed2d1c5dfddb976d1159cfbd57fb0f74c4e7fc5fd2c8df8d28e3f1e49a8d802ae67ff3a8e92c4bd22d2ae3dfe370b22ea5d1da0dd29bd48291520c1d3cb9d808120a482394d2ac8e3db9b1b0cd28e96168bd12124f86dc02449c244ae4f10ea795f69a3bd278a7585d383d09c951e208ad622cbed5751c823eb9e89f845abfc74bdfb3cc53cd52a73ecde5ed00b6225e2361bac56b6adfcc49201855a630705c62ac13ee93856fbd5bdbf2ae429bb602142a948d8d538d9cd5fabe83ae513fbe471e614ac5781fc4ad2c9ba13e10dd1eb38dc704122c06db493f9970fff16da2333a1fe09a38ae03e976e39273fb66d734383511f6dd452358b12d5c10faa607777bb7ca4db7dd9e5a36e", "-2c3beffd256344b71e5197aa6ab2724e7c5a94b475cbb6a539a1b719600734c1b51a7857363efe7a6f92b76e8a93e75ddf48fd9c0cc0437d430686869d78a08fcef912aa50484b02905df7275a2477bf0c8af542733a6faf2e59e1e0fd77a0ff883b32d23a0760c396b1650e60814ce48565f82947e5859f1adc71ddef157f0348bc2282d846cccfac61f976a69b804e251a5262fb33c6717ad34f6eb46ce2e84d90cf27acb401f5c2bdc55b9493e942ca8c418706fb31c61e5d314364359e503855c33e09c95db0562e556d7add9ff83ec1465a7f19da37224d2378532033dce4f8f74ca148062ef4cc93dd4edcde04a148d0b136798d0fb6fc0537ee01f5127716ed0eb1f5ff67334b3d8421853e1554ed93399f8f724e261fadadf050a01e69fca05075a65be20d53a23b9b1a4499e7491551aba5e54d9a5318b7ec3a6e23d11ab85e6a7acb7d639d452759f2031b9560446a1cbdfc0747191ab96fc1f1de369b89d625c04b3f44591d27389528d39f03f6af9b947ae7f396d34fc1f5d3501ea4d3329cf6dbfefde9005f3ecec08f64707b999525300637eb31dc7678880f809a8e898252a3ceb1372be789588e556ddf77992b94707ceb2b1749e05c5673895db66b276cf99034b7c3c218b52f925ed48cf2d06f4282a36c0a87956beb4edb9a2b33bee78afc90d47c2a8b96d870f9b9e516593c66c9a8d7808a098d7351aed8e032f5c8d92f621bc3c88f885a9702d3ac228b7b9cb9ae5f60a70b3c183317e9d53f03128b7749f9178d033241ab0543f44b516d2b675b2b1f5bd54c9bd1750fb9e057eff3360f69ab83e5363c176637a592c95ad934b1f654b1dc4753fda3d06a2423c0d70614aa621dfaa5f01a831128e82659cb295c2df5fa8f46f7fd4fdbcc04755e9272a884c8b203ed9dfd1f874d6ccc632e1c6352cdae0ad185df8766b7fbc98e3d5c88eecff692c294b5514365d85d984da517f91250ec01d34cd4b676254244f057157bc133d66975cfc4ba6d632dfef473a0b573a37be2e6057c9aee2f5c613a7a460e7daa64b5e28f8cdb7c8a2f363ce3fe3ca42a2627742e6d4634cff1212292885a2172bc4e2c0d1aba9dee058a14678e8d175161e7f67496d41470a7d62c647123097c09ed0d37f87969af253712ee46325721d8c8c155800952868b8da46be0130aaa7c0281428b9ec54890524caa7a5b3cc66616c551cb6f7141290032810a90497e92ff53a55dbacef733bf035ddbff41424858f92d19662f9f258638a3866d800380316c6df0aef25ef8b991cf9c8d3d969fac83d71f7ee00754868d7612fae25b5395dcb48dfaf41785a32ab9c9aa7696fab1f63bbaec439c0b5c477795ccd75977ca056a04b3bbdca5704916350e4aed5be3e024dbfbb8a2763b0b065267f48d77c808464144bfe484b32b6e88a06303c6ea6808", .Okay}, + {.Mul, "81d4d27d0869943e0bd15db5cab911c1d4d218e6a46bcc47ea15b507a33cacbeacb25903c9b48c1df444dede8f1722595b4c0cabc56c97770f1ac834a3ed5687f3e22f304174fd3cb22a7e2e91ddc3e15288afd0e994d1b78159e104ecc395099ef95dd7b570744f63cc6c457db309813dc432d84f651b7ecbf08cdbc827cddf36646cb590ff715589d66b5be9575cddc8827d895572fa04feec56f9822fe332da292e6bebb78a7f0c62f8d873a034733d49fc5dbeb57c1e622607d396e6f67141dc2d24fc9322a278ca71eb5b92e15ab490afb16f660c631cf92026bf1ff0e4333e7f71bd2104870d25c9bc900134e264995a639cc5d70c59597da66604b39b2c9d4376c0a62ddc16a230f206c932d414f752abebc4f90e1433538492461f9f86d210f61037ebaa9e0e72d5fad264b5579222bc552af5836df056636f51b3a740acb0e5fcc6f6b343f085d3bacc00f89d9d67fee9c18405188c4c5b2797e92d8e057d44a3a9e6af7d8e6cdf5c5f3f50719814248445cb455037d7b05ea7099652b60338d1d68ce1687fe6ce15cbb8197dd7c052eaeb71649bce2353fe47969e5c4398d74679e6e85618e782501702079a15477379cbfea74beb4fb876afdbcb267e08f019bd2d60bf64fd7d90f38b8688b567fa2d152faebf72772c54b5a6010522bffb72c88ffac97837fc968d4ac53a7d5e506c68341debfa845d2a24f7ad", "513db981fd60d7b794f2139bd19fda135096a3478f8bb562bbdb479934936d14617f2a39e9e101ceae6585f6d220d4b4eb56a417291f2972c5f244c06c22bd4b01c212c50b29b5200bf0b7168621868afbde60a338e55a44bbe1eb244e1f544ec4cb3eca8e57989eeadd0c3a836afd84d1dc0d7b957d5a49fa5b89d677b39aeb73fa954cd88939eb2729585bae7b81d3c44ba5e35eab0d63328716910d7ecc00ed1ca24bf98f967a28dcdd52ac36b1a467bfa22286fe177bf9ed4ba39472804356c0f0649c0aec8733cb3cc88c0068232556925269e64046690bb665924560a549fe3042556dfc0f17d7064480a4529b671ece50d2b9dca48c69b36142f91d74f5aaed8e68a5f49eb4c14545469b219f0ec45834f5236c2e89b6561c58b39d06511c8cdcc96ea60b1811f4d7bbe01a7838de411421a47ffc7711678853fe383feb5e55bb6d33db5ffe139a898c5c89f64ac1f2cc99513f3681eb5d71d36a8f182e83dd45215267862cd477384fad9f8738768fd6c4b5bd22dbfdf8a10f22b8c6995d86ac61141e30bb627a608d804758c16365e1db8d1c1fe916c5c20f51de4ec4986c8b178f5d2a847931e6edf57c9d3f467d10d91b262536f6314f5af3dc5ac18a4f784bcd85ec284bf2987d86be78d4f614bab735a67341d8e57afa1d8cc6ef7bec168407190245cb400f0fb56aca132f10645ceb47952cd25277a6d99785", "2933a464704f4660d58160b3c77369af5058c96f62d50bf0a27ef59da1c2a8d4fc7126c3007cc3104841138e314237aee8b4a630c90f7167326bce033aa3016345dfaf7efb5d4a1da4996ecb93401bbc7f3619da30d6383a6a5b03b92cbe5cb5b981c9fc92eea2ecc4bc1e271234959aa882028c041a8092f95a27cdab42dd8352a5570e6aa70e601c62917ff15242a3fcc01bd671af36de98e2e96cf1c2ec1f9636424a46e95fc14165f094f736b81c192a46ce9bbdcf8b006984a8b1d9c7e5c9c6035affb99c1d9b38d51a59892a78784e7faeb53947f08a3bfc842fa7eeb8b64d9d950dea4ba30f40c2aa395fbfac04b5383f0542efe71252e230dcae42442bb4d22e0116815813bca3463c98e047c4e30e864e88abe8f078df2a9ac090918c8fcc6e0fcefde7e6791a7fcdc30d090e92eb2ce51a8c6125834ec0224cad8116b1b302ac8445519d4e3f2a022dfb3fc6ea26113bd3ebb5cd6027f275ead882c3fbb8fee9d6b68dfe414e1a3272d44a358522b3c62663857e0d9c6556805d36cfec9fa0982f5114108a7384bc08e5df99c4619f0ab73d4fc7b3201777a6445f20d8d04ce9c4da8148831708d394f6f821b8ae11a97154de7956345524ec37e824bf46df5eef3ed0befc3b2ca979b420d54ef8b5fdd33b9af81e8d1e33a679e34753aac446ad594202112ec45ef9fcedc5dc56c4b429b2df6353c454ef00a8b594b2565bbb8f7db298b8acb1f66457df2fd2fbcc97be7fbf82e7e9a1c4d8802723a5b2460a5e6e7cf809845a837445b8a4eabbf598ea21fa176b85374790b7e95512f91431a5077bc1391e04d7821e2ba8584bc2d171a22630844db0f60ab3d477bb5ac1a39a90c82e37057b71f28ff772604b0978430ab28ccacb9c979530ee94554cc627049fcbb09ce82f3bb0205562c6ce8c6c9565964070ccefbc2bc727be56037622dce6d9f87f2c43c6be44b0e561050b28849c8178b9d4f7508c74ac79013094d5d9b6caabbfb348fa2f21c32a2ad0988172dd7c4fe20ea25e3fcd3e8ce84bb7704ca27858db4b53ef416d06c85f3cd20be2346284fcaf28ef1c6807aff614345148601f5f6377239ddb4126eeabddba99e284962fc787b27b5b74cfe949d7d2f0ce2b5d5aa1f9b4cedf1bc2a24d8d6391ff24b8f79e22aac86b0691a3659ef741036a3debba16cc31c3d054e36e305072ffd86981f4364b1ee7b58521c471c7823c91ad89193268581c515899855aab8866cb157cdad303d8d11983cc1f4783aecbd5c08b0606555783c14a2a60bf0e98421364a70db2b515454be3b6ccc0ab9453eeeb537240f46894de6872cdf42ab85365083792dabae9b8393ab3c095937a3419f24802f6fe35408df759de926e0fffd1efad08069829599fd7f7e48eb21ff4f086f4a6d202d17cd909fe55c10834caa14f4ff4f59dd2f0b7e1", .Okay}, + {.Mul, "-757d12bdc587d3f899bedc3beeaec3cc9bb1df559e9703924dd446ad14fc7bdd669063e11af42139c7b949cae7630f497fc580d2da3e627b0d01ac58e4fff0032e24dd76fe515901fffdb55629e59129992a03c8d9670d47b3863028ff72fa4f58cd962245138c958901024b560289a7aa3042dc9892c23a651ebb42c58acc4b32d974392c972174a9d717204d448525a3664259b36666d747f42579048340090a2d15289bb54045d462e38042eccbbf05ed25aaee25a4918c13e7507743a96c03f8a820230fcc5a493d6aa5ff90689df5eafe4c507f99fad9a1bab51679b11934fe833ecc8cccd140716da5195ceebe02dbfbb2c71957568661dbbb1a4879fe50dffb0c753c6c5036cc89c4dc0a1db8f180084f5d23e256b6d4ac2ce5e2eafd394da6ac68c5db3256695ccc9a0b410bc9b8618f81292eb23123d895e5e7957b6c61ecfdc4f0985df181c575bf9eb6e2390cd6c7eec4da45b55ecc09a8ed30af193c7a0146405b9a7476d717be0c82c086c377f678d6cc3f726b9d762f8aae839cc99fffc12c29761d4fc72f39b7fa78e5be8841c430188c6758d486f9d0250c46901a77d03142024883ac2995fbac77b7d9033f41d49c91bb8e257591b6245f67ebf8c1eff804a0252c536d82dddfdaa18e0a416628195f916ad11a6419c016f1f1e66241b2d37e6d398faa391948808d8fa8bcb2300bca2a8a105508409fb1", "9bfe214c8a02912586fb09c4e61fea9125e516104a4b19bb5044c9b3d6cf68df08b0cec0ea7c73ac50b5589785f93b230dcf365b8ae31ff748f4c622b1d3ee125e561a12bb53ff053df456be7f98d2c5daee8e7df58e4dc04ada4c14dc1fb7c35b1773de016ea6d950531fec93e5962775d0f63f673ba348a16dd30e02dacbb578daf1dccf396936e15bc96286a1c60730be3b86cadd32305ac148c2be3cf9a479287f288448b0407efbf0f8f3fae8e0304297e46d6c0b1f5980374f68a59b60b5b2d94f8e9cce66e745e406333d56cf6a931a83f83e3a2199024aeab3e22d1fe87d8d84c601e9225d5537ac49f847a1b06ddbcf4a18149a116c90bdd3c638c42623c5e42e9c9e7db4622958ecc03804aeda3b303c9d3f45d4ca505a1e4571c79387928f8f3e5757c3f78fda80421c58d8f8cfc0341d4a85590c53f7390630769b37244a72376a420bd8286d2bce422389baf712f0ff4d6c9b25d78504e21a42cbf8fa5f17dd9a555d41e13288b8268b3ac32e6c2f423198f2ea5ce3bbd860ac4ec9992b1c9997bccb50dd3fc5170ca3700fb8c5f39839b18a059f5bed9143104f8f9a27ed5e4a35a0299b8a5c3ebb75517795742ed675f95842f09870e54e9d54e7fa3690134f0f040d0c738d28b42512f08b9c227f9d35673dd5d2c8f094c3b31c8ae16b348b3608517393476b90dbfe18a33b6b148d2dffa621f02784bde1", "-47975bb9bec5da9a7effb7e5ab0914bc91577316179375adede220bdad2c4f26c81b8eb4a2c0daeb9420f4d3d3e72f974ac5395b880ab3ea4dda42f7d61ed6c30a6e4c58344f0e2d32e2f8bb911484f1ff93475502bd4d0eb0b6bd3d74a17f01479481332259f2a32a89310c83640fc1049baf18dc4f73868fecbfc10c21b4da7422afe2c73c74846975386ad760b398c11ad4804e6c0373d6e3fb6524bd31418003b3be6a40e01fa93491685cf2c00e96951e21742f15f5828d072831b976f384b4c47ee6ca44b008ec9611a429a8e1bc8b223cd4f7bb685c3343d6bbca9864ee737f98b88fcf3f19d3b3086e1a18f5c75869c9d809ce9ad1a41d50c5a0d61c3d11c34dc50dee8036f3c6057c13322ad41673e28cf2fdf573c6f8b41a88bf70bf7777a8d55e14abac30e7577bbd1251665a1934f47586578b5c652d0262e4cbf170c28095bb8ab7ca471fd5b272871bab59ebe98b366d8f34f4a34011d4287e7c3810946ad1c8996ba6bf726124b508c6cf916161e77363bc1dbce98645e9200c60437fd98e9f64510f3bd6b23e03f1b3cd23108366557eb7813fc890d5fd9941db97653a04c08b9a169ded9ee544dd1a40f6b689efaab6a730385a4954ad351bd920bdb7766e0411f2c49ff01b28b5ed3652fdfc743841db329f8f3c6b0e4eac02e682a254fb4682289a887002996454ec3d5e804b41c8d03bb19575fc01b1d147cba145cb18e8ccee13a7832e5b0a9df2afb7819b95fc9c6eab3242e977128e7fd5334a74eccb45f1dfe54abca4e3d2bc30b51919c05a69b82af2a6868bd447d65edc4e3ca09a1b09cab890e249b64e50284f7eb82d40408dc03d4af16cb25348e6762bb37b6d942c88d4bcd7ef8c134e86aa065c891c478e0e298eaea840f8cb90d1578dd87bb673a2d74089bbcee280e05861291849913d065008e8c096584307db81c0586f307e09ced009e896c0ceb9aeb5c90be7f12286ad95b1ecae7429579a06fff3a0e65cc81afe7fca5cac1aeae30ab5e2fa2b4cb7ec3b0f4cd1ae7dbaefd4de880b2829a80cdece6a73e69c513f0d2e886e6ca9c7b31487a50ab59b0cd825e1dff2b07cffd468fdba69d203959d5fde0f70f0ea1b848f445211a05b7b4b2d65c5fff44f905906037672d67485f0eb18fdd2e7fe7b5a9c895eafb68f687b1f7b38c2f87d3d3676bc515555f28677bc6069cbb724b3de5147af52685b1a24c6249f826651eee3a9f473763b792181594243820c06f303f00f991f61c2f74a0a826e7890b4133fd48a11ca82eae642fd75dc7d01494fb175c4224ba0cd78d4c89eec6e6c2eb33e0a6c5425c87b6a33c0d2a66217530a1c915ddd9edabb2f6069c0ab736366731fd9be92a9670a949ecae191794bc3e822c9a0d3686d3302e0159a15c30eaa0efc7cdcd96678d4e5db6db223a29e72c26a44f60791", .Okay}, + {.Mul, "-b383e0f93819a070fc3323e745f318d75c094972dbab5be9fe3b5acef4e8f4968e56b790a7be05923548daf837b0e350f48bb712f8117f572a9836ebbc7ea262264b0988bdc704631f17ae046a01d7b92c5e1ebddd1368e9387f832526f409b670532e1efc620b71189f2fd7480e6ef309f3d3c22ecfc5eb1f856ae449679b3b6fb46421d57eac5408387bc032800a63b600bf2ab53e0365274c9bbc3d9b4a095e2bd486dcdd41b27cf58354ea16704d1e8e66b88887abd0157e4c0957e3b6cfa4e37462b7efa66cbdda7b7f7ba06a8688fc9901f204f1bd44d9a7dc05c5abef58e797ad4baf98197c3479494a31c8f32cec0f7f5c6e2c6568d0a1333923375d9a00846f719c96bdda9fbdaf1ad424578ab14dc6ed3dff13b152520a5379442d188fc6140fd50286c87183a5c3db9f1289db28070ae0eb9e4c3ab377be81aaa65171d024a643644efa3dae7d5ddc8ea94f4c27fcc6d56bbf0d8d83a9b9b365269d41a19dbdb80fa9e5a8439439ce321d3f63cb53265358b5fe9b324423ab832a62916390f0908812144b6a4b0f7d60ba77646c9145cd421bd1af6460eb05df871a09f22671f1eb16f8b09871b40a7b7f3b7413fd4ce4ddfc50595237f41117d1aa5dae4d741c4f0ee6c5fb0eb0ce16d19a41694992836718cad508fb3b7df0f7555b6419bd9a733a95ff47f19b06f222712325226ce0ebb63cd4f5e7c82ea136", "7c73c39413d504043a699c56b9133f1691870ef6c886c9e06f656f58464bd9fabb0927c19ae79cb90bfa4ebf3ec21d2220727bf95538e5a8768624a8ea23cbef5de41bce0ae4793bbaaf86be42d2704c21be5aefe306534f46567ee8d5ffbaa816bd3ee4803ea3c932a5294f689fda42696cac958b745c1dcfd96f795799ace33782ca88f387b646c08c5c3f657a51ebf9c56846b63f7696812190ed7fb491cb9d1fc20938f2c1f7167af70cdc490e402ce6730a5a0f94bd1f4dfc422a88f18c3084ab463efd8dbe4c9a532e78dee57f35116d44ea70b5081dd7731b7c15e95e0f00c02da796a38de730e471b3247eaf2afc92bc215b9ca5e70e7470db36675b34a8320f9144c619fceb5156599506f24f70e36a8a73bd55505a2cf83881ce2ac58ff29a4ef4dcee0d1231ede85eb7b808339c5a939a511ca68c4b8e9bf6b6a17124781c223555bd5dfd9b5bfc7f98553b69598276c7bb18ea5e8c6c1e9ac19c84812ca6122db8950337f38f011c4b8f2020f5239cf926f8f8afd3d01f91aa962d3676144210b2edbee70cfe26ab335557ef1721779b4ef6c6c52ab8d128e4fab8255ef4a84e3a8c78bb02a19b7bfd5a62fa9c49af513fb68f0efabe13456b932b489bc4bccd031cb1bedb27db00095a353238bb2644c3847d0f3c067bbc47fddcbed56879fe72b66736a7afd4a52149ad13f07ca90b3608dae5c45f29d9dd2d", "-57450e5c11a4ac4775ffce7afa6d0f84ce683175367424ac58af9a5da615f741792c97674936d2316a2f50ad0ef33c7ac4a4d4849c2892b821cd3a0986feeda67b9a91102103944cbcabd3aa88bee98d81f0d6c7fffbfa4266ddf228c0aaa9bfddf40674fa0090836a4df4f0a33561b396f1a20aa4ddeee642381eefaf1f3b49ee93e05b644ab14fae2af4c53c47617aa149178c13dd156fa9aa577e0f378b4c059f526c3c2e25a6634a3decd09bef033f28aee5181574e39d04322bc6b142ad796dfea0431170580d8141146e7a0972adef7950f20794b6e7cca4172e1539813c3d82867536e3ebac329f161be200b1b78eda9c17743b147eb0d385f7f892ae3aace091404595c55125a2642b7c0e0f1b38ad06bdd618dfd958cbb15247a5fa387cfde4d16a4e6d1fd8d2209599a5678c22d9ef113587a15bf560c02fcaecd523f4f006d6e6b8eb34e8e0ba52ff946b3c7e775e0a3cb190f9d433a67396bf7e99701a748ea78e7131e24ffda309ac5abb629ae623814f9bf13a01d9ee8ac50da46c3dd318d5df24a7fed72804e721c3189f17223ee9ef55b8a9f2a91bdca689dd1054c5fcf326ee2b689e30238fcf2a9aabffb3daae6fbab21d77d00b4e0891c3bcfd77f320c753f4ee9ec528b625a70f2ffb34ba6456a1e46e9639f4e04fb61a2a9c13daa5c13e32beb2f8abef435dcef693b0e3c4d8081c6e351742491144cbb193cb74d3ede8a9fb6a056a4a6ca32249c69a4ee3fe76beccf2b09d87ed9b000f2e746796b022cfb6e719010af832ab72c21cf03e2141485ca50a745fa8972b4e6e8342ae43e2ac2900f9693a8cb9dc856f83b8c58edd8d69968888b4e57df164b426ee0924d55b7d98499d69903697cfa705076a5c8ed14936d69eb4bb7f935ec75a37d5a677ecdf53fabd64a9e63b35d95b5142f7dacb8bb5d1886c46efe957016c96bee367f9d0cff55d08d9d5e93d26963e2bd70c5a6c6dd8e935472f1f25d043ba169363f6ded3086cfa9856aa81402d6a33e10afa0387fbaa6ba7b288e205b0c4e438f24b1b781f5fe6d3965a60b426beccc46329e96972b86a199c92069d0cc03dfbbe81ec8325a64c9dacc8c26b88a65f3496f441a8a8824694b63e6008ce3dac136ef7b6fe5b33c7af23359391b412cd909ff67c5a9ae5005f7dc970e40ae0c3f32d0759c24478c382d5bb6bc44450c2ee75dcd5f8e922a70070ca02e51d1b080f2f7d66d7b3e759f071a376b11700beacc4f8ab3619481148f2e89ac5211cc7d5431fdca22fb1c586e64b1829c2a8488901afd2ab7b73bce5306009b55b1664b8585926958db311146effa70fa6b51eddc22047766e37a3a08dcc66fd0ea69e3fca200396fc0c52ebb458ce6d595707c5445d932cc1cb73952ba6d7be1938fe94fbf29833666f579b4666f8fe9bef2058684849a3f0be23f47e", .Okay}, + {.Mul, "5bf7e553ab6d8b5d51546f9f42329e851aa261642555a30a63882e3a331f162ed9456eba81288dc7b0a293149e1b43eab4b57e1171f75528703e233906d77c0b6f241765a7bffc2b2b84902c0d5e6ef7e456af95d751a83faee9324b745c9473139dd077124b9e2e91687becf9289cb96aa96d5bdf423c672a424e8dfed8859b6272e756c5544886233e61d0c4e445bc99f209f61fb73baaaf48e3c597809de99db869bb7d5fb125f35fe24dcebf9be483ea7414bee0651ebe687389017ffdb05a4f95af0bf842f00b00f7518ddf10383460695a3d9c8aae3fb52f35c0e6682f89bef866a321d652a30c10b957773c67d959f1f904efed357724a422145ca3a240c4fcd14481bed1a3cba52d1ad0fb50506387a0c4f3fb2db68b303ed484b653d039339f2fbb670627e80f4a8a107ee605c3051be6e986070f928357b08bffd01b40be0700b4adc76d869bfcebe5c27df24d952fbdcc3c6f2487a321f4262dd6c2871e2016dccb14f19347949d28e6e3498093d3a61adea4e1eda0292e112c8037040aa6d993af77d671fd2a6a1d792973bdcba26b1e95a4749de4563a6b85d0a230610e7185d1f6fe6f6f181e3c5d9f70d7edf4499fb20eca2daf127b2c4aff039cae64a3cba3cb091627d899fe1dc586d4af948ebd030e658303b53205675098303f1a5cdfc3f2045c97cefe54fb58153629a912fdc202653069d72640d9bd", "db28630150bdc3ecddc09eb3ae2af3ccd5ce14f444f1e1f689346a5ae9523ce6d727026e80428de7222a7f233f7176ebdf9561fe7207cca0695105a347f0a97af91ff6502752854a5735d564d579073ea344f4d4eef74f8bf55dc002eb8cf9f640a3ddbd9d5b08e01b691c24b2266940640e9ba59adb225ecef1415e8b9c452a96ff25ff3109ab318b11f9c9b5a776c6498de877c18a4aa745fbd65c79e7a4e90b381a506964672c8a43cfd29a064f10f2e71658b871fcaacb6b3f1ae55e7fa5522f18889f8e293e063c842c8df193d4e9fda4e168ce6f347d84a687d81c2a44483dec34295fd8304f627f31d729bcb63793715aecedab760867688b1e3654f5e0a47a7f91a340a554ed13d9929e52ed3dddd1f4229b3f8044406b3b125c545fb799f065b61de664153785e127f29464be0222aebc0d0ef04f9b1bd71192cf47f2fd9ea2ccd3df016339f24db2cc5231af3dcf232da49a5a7fb97c0c0c60b3897b79551621013375266fa87a507989150644da06ca6c1b3f9eee9abef2a1e94eda68cbf78de1f80cb61fd80750eace2ec056910f202a18a27e2ea4ab57429a5e03f4d93016043879efb27635abb9658be18c34dc3185a566477733be9b71a264f24f9c96f1c4f1af3ed465e3e304e0d5f7d733cd9fa82ed8f92d6a3314ebd32bf3d233c759cc6078605688cd30672194a7ea50a84d98057894ab28e51c7e5da6", "4ebb937bbf62640703b2b68bf4a5b5d6e24c09b255802303347854120c2eca8ecc64699ccbcf19b2b521c72cdf91c7f51ef6dff5dbb1f8f8a8d6af022ef8a9213b4121583d8b12b6e45eef1a1fb76a518812c6ccf0ccd4cf37d73ec17e73f9bb357866006e86eba6d6c17976d8408633911aae747a61c7beda97cf891129de8f42bda9e78f4f2bfa1666890bb490400519f372a7d8ea3e48b1d0b64fd5af9246af4989a218a83fbf67bce93f7a85c67c1c136d21ccc7004be77cb8b8d9a7302001d13947d6fca86943c93dc4daee59e0eff260ad6e28bfa339cef95155e54bf4fb3c2615a3f3aec5313d85267327e69cbe12e8aec674b6fdc65eee9111a44c3d4d5b5a52a31e4cc8e9cb6c77c1fd61f404d312903adf0d475c5d3019d3b52220ce9fbfb3593f3d91120bbe34fb5911cf232f4e934a437b47e1e9affbb7921862f6ad56bf513511c60f76062c8e751414b793a0ed27c3b0cef9d940e7aacacb201ba5ed421abce0f49ebad5bb5bda8b5a78a206095b1f048d767b72742465561a0cd0e90229eaf226f37f2472529abe975aaffe8655ce19eb7c9178ee382c01a97884d2bee5434b6095e699a256348845163d3f9be1f654fd4b8950317587121fb265a28db7802d542cccb2d634bf5ff2766753a725975a3160177936b1cfac19b176f14a46f2269db77957a67cc931576f849961a23a49ac27de693e6c98565c8306dc89ac562688bbf27a5004f07ecfc8521065a3038bfbf593a88e3203d3c6e90a7ea3f36ce3871a596e63ca833b7f7fba915793aeaf5cd9581647ffeb045c0614ee3d4eaf677a8819b7284d569e89cbd3da38f9af106af05d65fa635178768d56d5f76e20d7957f5963c50c94c05bebd8ad7a46b45a37076a12cbbd5552a00a559fef0eb4764a97b2b9717e5113b54b4efdd494825d16a5de321486ccd72b408798422e3bbd820d89efbbb4d16f23f61285101c3a0b67655ec610e8cc26270819a40ceb54fc46ecf7d69d8a5179ba31bc5768fa10d483ee3ec0bc3ac0dd977cd80a70b633d20ee8a857642bb6c2a6b513efdcf5edf271454f33369037b007d31d2530576e6b442725bcca178d784c701ca39be5866970ee04115ff77e5dd863ccaaa84463d489ecd94471c5c1f653648187388fb488a512547c03dcd177bc7a8fe4f3621c0d835ae46a0c7c186f81bbb8f5520786533cbfd0e3464c5a43a7cac82890f66d18faa03fa4204911b26e8f2d13a31b034b0d82593cd55949de8a8241c53a5b183a9d05b4bfc2b45da1d3be1de6d38dc4d63793bd21a493f17c8159ac52a282399949e3cabc05018c62ea580f8942e31bacd2b0c46bd4dd2f49f990015dd64ead37bbde153b2dbb049345af618cb2ad22798ed5f1d385eb4076d81bfd4c25589253db72670106109f4151aa5406c1bdd0ddf1e3330435342cd98e", .Okay}, + {.Mul, "d1883da32186af9cdabeaa8888ad6d46d6ada991f65930d0da3093d4ac2a417cb024c5c44076e5617ff28b53a07ccc7b42dc06358cb13bd6bb26a0a7837167672370c4e53f24f8af962b10e5e44c0cacaf2c3ee5328b95de61fe0c41279d369d307b64a0c42ac0ae4f592f4631dee28006b6632b37e1ab753cf9d8e66e318bf7f2a86f884c586e1f1fcde4ed1a011727c20f8e456926803569bbff71e2f43bcb70c4ce3910b90b30bccbabd6d7e46ccbec01e3e0ee13075ac146fe57faf6b8490d9e1cf983582556521d5e6dcb37680d6af00f698872c7d0240c3978e3785ef3f4cdf586e5182398e2db503a239d16c6ea8208e7ca95f3a4a3f0c102c01d8b0b3cce9a77de751f5ff19a0449a211e91d7e7f818c10b2f81b9ed4088fae0871d78fae141572a977fda7658b60a50a3de2cfce2d9b48fd38e33d3f633da777d76deb0e35a489d7a0167faf937d95b08db5d309e35d3e117e2837934f4e76623e7206b3357c13cbb65d84a16c68a7ce224dbacad41decd75e7047b710e17f0dd0ef340c767e7681bc233a0967569434d5a458139692c2fd97a79481988076def9d791b3cbe7f07ef36f08b9dd6875dd3150944bba7e82f6d600f12c39fcd1b48376402ada089503cefc03c812c35fef342e0921e0bd5c6b6794c9ae772c505f7174951fb8c8bdd096630c019f9111e0f69aad4210a50756925e90e25ee4ef06540e", "4ef236bbcdeb96c01e6551860086a146ccbe1fe10556ff7c6176796abc02c38e8055d59c0073106629636686e7c530bc98df22bc7f155c806d7580a6d1fca6178691dbb2c943899d2ec8e1db3b58e4b0b777ecb33c27775c124f2c3d16118075695c0f50cd45b7210b0d847584e4eb0636404fddab13d99c6508863357a2c611c23e3e1b88bf4c5037377292954028a7a50a7f9dc0fe9a82b6906596ae85bf197122b9946f68863be12cf2d79d9ff895ba6367060429b555d1747e69f97b2867df2012ce8f79512de422337b493d764b8a689d609ecbce0ff6d65bb542cd2441d518485524394302892243661d1185f95fab4eac52f5e3180c27798eaa1dcdee5501fd45e82856871f87eedd70732f0643295af77416faca5017c72f9e9513e50bb146fd04994c5e60f5308ec7dd94c98bfce8a47c546fe7f1539e1ecafc0889f6d0e6369bddfba267c3962aec84e91177f6f357079bbfceeb200fbb9797d668998ff5d5bac422a6c5fa68b510d472db3ac66a6863c5ba17e09f830fa277502fb797cecae02442402515a776fb4a795bad16cfc060ebe24ea328cd34b59cb7cbde1b2cc6c7a5b4a2b91552db530eec999382bf9d29071babc5fadf9f6d2407966c825da7030a53c37cfc745af15b4591cfe8a4821550c016b9f53573bbbfb82c12c3f98b43cf7e8b036eb3b90d90703b2c00e33171633cecb738f0e8542d58dc", "409dc25e6c7d16defd1f93dfe88f983aaf613c17b3162f852e8533295d4608906478e7f5a0dfd64959685a9420f0ac09299a934ec149c048668f4218f9a415aed9c94fed2084d3ed8df473acdfb2d2b3df8e08432cfd1cba9728f87f9f288087f26a23e5303ea269288097df9b202661f3c32b5080a05e42beb8ef7574fbfcd2392d0cf593382a2b549668b0de6f47c905680d702d0f0668fab851310194d956a6cc3d17513a8d034a6ee254bc4ea792a16da3f59dfdf938133a164bf6c499e8f5018a4cf601c3c391286e4e1431f328b5e5dfc9d080d2d26268fd98a54d7a116ed31dc6a1e4686d753d4c1d0501858c216d25997de256bd156c0f820825836fc2ba02cb604d166d43acc91d193de478c44852b19c235ff4dea8e3110285489078801a4d3c59e35fd056971834a0b5167fbfbbbf0fd584be114cad5e3abf5514daa29910b2127c7780fa80152534f2718b49506179bdcb4fbd983520b0fbfc8f898f95f6dabbaea0e7c3257cb2f344f9aeaf74aedf526937603906fc50c801b77b3db1369fe77b9859e6b7fbcbb88c05abc1bdbef12aefadc18d05e71d3aab93efed6ee86a6c8fcf029148f3ade15ffe340f72ba7d7f1a1f91ce0e94cc3fa6769af5cde3511702adc2aaa8cc5a856fbd371abb3eb784a56c927e190451ceb3c9756e58e978bc99d36238b1ae4838c8299f0fa31cb81c4bcfe1d0fe3ba08750f46583f1027c608f3fd38b090b7eb83e5fb822a01a9f18677c873bd94e90cc4dd726afc4fbeec84676310260d462b9f73414da4c3d8cd613680e99373cd513a3e2bfa0a821b3be5a281c57b265478bcf8bbb9234f3715c6c2bf3713dad6f7da121aec566e40ab76164e64c71ccff470a4f8da972fca3d4b60043419ea8bb31237679fb0cde994a6d8bca39580e5ed998824b25f98b288488810c6785148852a5721dafd58ba7252e4a942fab3926221aecb7a0006c8729d26cc0d9e27b74c82f8730d69ae2547ad60f7cedec8933d3edc003185278a1815fbb7643fd363d1f0739d009cae2d69ad0a55b666ccb01e244caebfd3aafc42004a2654087d20880f4a1e6710ea708cd3c46248d812b6d519dae6eac80c9f6482838fd5fe09adca6628d00c6af803ff6e8fb5586d5c61892ce097ccf45b64c9f4eaf9852a6a2515c07103a087f9a0cb9788d34c201c8b41b9742277085593f1c21ff4971df94ed7234f34d08e3fe639a2aecafc0e8b2f7d0d979a87a56e70c3d103c2ea667258df6623945bc979d5065f35a59bcada6ca8c5a4add82a6bb2faec561ba40338e01069f207b2f56661846d42ef733f6bc0ddb4f3b6ba1ac9948abe933e278e5a7c73d4c8c5d965619d17ba6f233ceec66b28d58404d75a037bc8d373996b2a21b64be1513731b532665cd7a2bed73c2566a4250913f8e69c546e13def116da348f4cb0c08", .Okay}, + {.Mul, "-2c8041bf43b2c31f790ba36d0e7415626eec6410713eba047ea5264e9a25a7b722fb1f62874de7d1fa9c550b7797a1e33eae86ad700b3518a7d481ad16cb81bdbb3dc787faae697ebe3b1cc48eeca5eaaed42dbeef12613e9d87d687d3e0a16b7335a8f86163a30686eb660bfac07bada122a699b8f84edf83c82bac22a736816f376a9c0c5599b571fb4354f13bdbbe95e46fac7c70a608038f8f8b9c630548255fdc3f54120530769e2b2c648004b19e7b7f5b7c935807bb7b5e50a0f020deb29ad1e9c4fb8aacbd566e432a495bedfa938693fdf24cb42cbea209353e9532c9ba5512bc59e007fa089c703468236df85a7c5f0bc45d84e814aa9eb96371b08ef21a4606d2cfcd6b2e1f2462183eb5ad189510383c60d16c7fa20be8a44714b435cd6a530834d0ec16f69517fdec9aa8ea92574ce8e69f3adaeea30aa9b8fd065b0a541f1a41bdc5d7832cf5c7c900a801049ede5a5f282343c6c9367a9f0b970c14765939ac94c0a2e9ce6318c94fd6c2e5721e0da22f698082768007e9010c32761cbfe74c9c9a22cbd46e2bbdd2f0d962cc9429e0d3e49ab842bf4c3e333692f041c22c8edb47c73cbae21be7c57cd528cbec9e83b2831011c33f3c6bfd3d4bbe9304369318dcf8262fbbcd53d01d9373dc6b9ce7d0bca02556d9117ed51498bc6fe15309036dfbe266dbf001fc3263210f550ac3d7736807b7691c014", "af69ce8eb989083fed42d5de1ff332aff330fd153939ab78b28b7413a006671fefb9202dd0af311cca64eaf3c28e426c854a66e92882e331b1136962b97423e28da001c3d856d7e159c84b671a4b7e8001772523f9fefaa64acfa222708acd8bf003a8254b42ea975b0405942a7bc3197b36419c1208e0d6a9510fa6a5d7c4d1ded46c50307cffd0662d9309dbf420e694dbf627978b06f2abcfa400eb4f47f10729460bff3e651ead64ef8afe9de271b3db988b6605f767600a8e15fabcb768003e2e96bcb0cb07cb5bf68f60b6cb1417c51161fb92b378e5313456fcdc4107a7728d4ce0068fe821336a98f0f86793bda975dfa3a729da257869b959fd023b8082bd711ebd5a83287135267e12934b7eaf74391df7f4426785ab02b37eb3017b29886c69fe76987899df0a14971f4549c37f97e5e2edae1150b2af3591adaab77050c7a63ada7dfef0b61e122065d8be01ad6b7766cbbe7c909398d5883ce101ee31ef3e3d7cae9eb3c6a95a2706ae41d3a9e0c1da1e1e33bb68e7fe3b37c32643db42074eb8ef221e4fed4215ed85b19ac2d01781a0168524da07010cd7de444de169159fac3bd92f07694c4c448f443b08205cfc25db13ec76b3f120e6146a7e50a829303cf66441be1f553ce1fa3616f03fe3d40a857d1ab2e504e3182e44ff6c449529db9ad06de455c2f10d34f89cd80c73f5b84e92555e3348573cd7", "-1e7e1174bb06d9db77f71651d871c9a4ffa9411f14d9764a728a1e7747b8f8b1871cbe28ea7ae6122c3db8f9931e9a86ac3300be37f9e9bfa600280e2f1fbbc6536cd2ff812929596542deddfe0181e5c7b70b777b963f4d4320cbbfa7f0de4475b192b956aade71caf2efcaf8ec35174d2962be4074aa038feea5d13a0276fce38c08ab50396864da885806cf4c1cf1e8ba589e708d1b03a38bab7be3015fab094c07aaa558c0dd6e2b82252a8795056bbecbf80546420998756849bbfc700b7e507a16eddcd040d21f8a23df1285aa0cee9d6d7e0224281173980f07e5c57ae526fa3aab6bcc4cf64985b058894724783980237063668c3c2e6e728e56f2bb36035c29cdc1f9b649157bde35df12f354f0d320b26d30f25e455a0d730bbd9d720026a023fbf27d6c766eaaa264201d775da9174bbb95feb8e3030806d67c13916962a25a68f3fb584038fdeed79a684c692b75dd23f7e168a05dd31fc4677e01a5379eeaf562d5c33ebe3fc1a8b0d12165705f71f0eddc177fd598b8eded0ff051c02efbbcffe09f45d175d375c7758646cec8e901cc84c3ac6c2656efe55d9309746a07065b98548fafcfbd5865fa2f5f0e107b1a42d2a9a5148707b6f3e20f9f0885332835cf1eecb76b21a1df616d729db19dedeafbe41f2573e61810911e371eb5bc89049b5e1b42ebc128f2f6646934f4b8c738346b44490aed607b58b18f862822a109205a9bc8b1a7674cf235dd7746f698749a76abb4a4b578ce2a2f2839792d24f2a916e63049f1c49db52ac7d919384c3a31750be7a7bd20d2b4c5a8317b756a8ba079debaaedd159688bd86ad69cbb2eec7a265d2cd11ec5be671582cd289046521f450ac54e00434ce45924220893128da1820ad8b94f522f8f4a70b263b92a34e335842d9a15c748fd368769316c75a8eda877ad3f83c0fbcf01db6b23431a3f0f9b3c90cbbf49ae9e2ca2011a50d76fae37a55dd6e5496c9239695bfab05c10ab3e97480a60e69839d4ceebf1d24a6958a143c451b93cc99190905c157c0598dc0771cdb5af238d0a5abada8f0e8e2a6ac2fd124cf46ed3e0ee40c43649c3267938332e70fdf8b55138390ae0a592d457fd68d19d9a70368f85dbaffa3ebc14ce36f345b5b267459ddd05dea007d8abf8b617d65d2548ba9a12bdb32ca5572157d77b19736471c202256c0ce1d8478cbf3b1282bcc07c2db3a8416594ce2e3832e885793a38b52b800300ff139109f20c5d5d8d6142c60756739d7089fee0e7ee137127d5cc0e2eb54ffe780724a8bc8b43e6c636faf2d7f4aaff25fbf489503f6d461c7a175706a2f552ae7da167305882c8bbc8738c06a377599651fd7b22e49392268ca6928cd0d28024b5a57e5080d6f9f56e3790ed35c52c3730b26dae5519d9e239a72e053ebe578948cb39629a65bd04a43900cc", .Okay}, + {.Mul, "a2f8d230a563e4a6a376e35720e6c2ff104e31bbf7bcc8f18fd74f0635753dbad079e81fe80baf6b5874e85bf345c232d3fb9d17e838a746c80fd308a1f8cabc295b347f5e12bb6906124164b5a4ed43c1ecbbba1568e29f6aff62a11ae518691cc538ea2342f563ceabb1b2333a6fffc984d0c394278a155054b7f5281d798e8d63f814af83bd31270185a4d0167ccb86eae2f3fd43c66069076fae7c64638bd2b0d2db5611464e826169758a9f36c7a4a059351d60358f74ad8e43101253fe7f421bf27fbf9002e55dbb51fd130cc3df22b264bd43cd876d95d361dc88ec3fbe184b1314c010439a1292dba32e89be80b8dca8fbc1bef9af89e7487ecc4b1cd7d525fb0b7e615f66b2f8358ae3ac1cc7e990848c94b0198c5a62875142a750149cd3e712227c2fd1d067587d81a8cebcfb5aeaa5ad9330d09a89250a41f1e08b9f1631a680aa8333c0f99497d0ae85ade07fb4f0288fce1df9c780f67db3c757e2a2440ec805eb97e6f1a48cbd256aebf65d7821a66eb8a38253f4e746dd9e1a110234a2c72983a8123c468d51530921aec947dd456138b976c504e1a8a84c451f55a4fda18a74e903c1dc41ff7e3d949711f373dc6ed8734993e29579efa5f50c73660c1c03ca792c0f07860d40412a384db29c98e93766378f1a40ac80e5d2a084f98732794725d5f20f4647c9ab7e7aedf3f28dc2c0e80025a62b35a147", "6393b2c7e3cd1491dfc05940544384bcec460c940ef07f10c011340eefca7ffc71248f14ee7d4dd5b7aa4ff76b7db947fae2b888110116385c4b0ac2e16a3eb5558551b64662c023297dcf3f127210938d3c0c9d63e01820ed02a98de5bb38ec9b8ef481cd16e294c03b9e7adf82b59c727b1f24d04763a24afd6ec7c33510103ab678c230f282cb299a40f1d2cf3219d94ec02b09510e1692686714bec1846dd2aee0f4d07252377d93033ae75df992c633ef80f67af9a069ed62c834a776a3e27dbeccea6b129c4640ed3897fa9f6e439e5e64be8f035ebadfa49a04b201f66dc367edfd69c31813be40846947595b52829c1f3d337c2b92e89bed5cc2cd75a8ba6e1d5296efa3f710c4baafecc2fca4671b945d211017a169874b17bd420040c6e832da2777128c408e62d62df2726236d7d1bd3593d846b69c28c98ecbf47f38298b3468880fddb445da2d067e63ccd6a14a6cc2bbb65d7312b758d8d913fd1c6eae7988f395d76001be7095dbbc2d737e59e6bed5694df933e15215a8a77f13955027a3a207a8731d2d9a1e66210d0b1e8b094d76cb62f9bc0648c16fc22868347c1fa5ee3a75881709f733357cb5c75ef3a9122159b212a93fdd3477aed3f4070737aa5b365bfaf7ebeac6b6ceefe80569b8cbe706d6c9193dbe4397dcc8f36d498685e4b7fcfec7e7ed9bd2595763d17e2083f2bcfc81da577ff29cf1", "3f643ff9c47b015283f1841fc98d6dd11522cf099a01a71a0fc349881282b195d426091e171d51f431ed7c004bb2bbf3de5f5d39196e068b1afaff5f7b2b0fe458a9715f22845cf88e8b4bda943870000fe1bdadb6a2e36cef88484bc3b2cbc2849a98d628cdd8fb2cf72b6405d9fc7a71151da4ac1ae7b46605a045680e583a809ea8f20e1e99e8551199f0bf1e7bef6bf98ab0f1c628f9cbc4446a9e056a382def4f1066b58996521321e4544eb3d9ba6e00b3a39680d441c4782c27064941ff3b362120044745c80e6af5dbff210a2f6d1016430b4a1d9cb06f00a46c722929b9ade6e7a553d8ba02aa9d110170f4a8628c4523e8b818c24c860c2f2c4b3301be949b7de35b7730edcb833527cdfe90dd3a2224808a73037c2039ff929148a664268d506d262c4e6e9a864189eb6cf60a56d8c259d1dc657cacf494fea634e8126c88400a035b704eb90d095b21d0a020808c5094e71ade2bf1838f9fe1b258e694c4ddf0a602b46d95eb5647f29e09d22d352fadd0276ba3e3a59489138a8e65a43334561084fe898c8a600d477ffb1dacc70348c5ee681d29891c76c1fd0a4b959c7daea4e04321d2e883c55782d561353ef3667692c0d1754209832ae695be313557fd008988eaefefbc9760188c4dbb04862f74b13bbe6690384f9ee0800d7abffe4ae665334d838cd571bd5a89f23c5809119a4ba8b986e3042d4f14fa51357889c118c9210ed8ed2c15746b49ffd79ae85924ae9169f6717ab677193dd85634ae174da6cd1719b74437e9e847dd95c649bbe10d55d05bb8cfec9b53e72c67f6479504ce3164d4e633ff52c64b5a499b4cddeb810c4411acd262f852e2c467310e4fe9c3f25beb75fe4f2a798b864d067a0c0d11124d593f3dcfed3c3e7ab2fcad463e5de9a45c61a4a719321b0dd8085dac0a2da6850b358e4873fa945e7ad106dffbae97647600b86be9804d31d2b6a5aa559087dae9c709538d8722e1053717e92443740d69bef2f80864b88ba825e5ce872c0457108cdb220dfc6d099baa216b85065894794c63ff2e3a76d2e22650bada499b4292f7be7b1b6b1fe30aaba7af2b6b3a6086a559a9e84571a286a5647e22d82b1116a863091c9426d29c07685a9f861e4f21d2f558d88c816ae7caffe6f528afdd3219bdb813548ce83135e54796b95f1eb397d351ae83d19af12cf0c2a8ba130fa01ff974502ead67477cc22a832ed71ba30362425b575b49ecea645496a0e724acba7f909f07f193ab426eb87a4f0fd3f8001ea11f4a01963698c460f2c5bc6e5959adcad1f40db826fc59f5b76517551ae7c670708339d247f4f0b5b9797bbd0c26beb489977d4827dbe668c504a3a593fa5257cd7e1a7da913f85ce31ce22d26042baf794016a741a6c9eb39ec2d9bc9def90ad56d37ebadc3e022b2fc08f06c9909e217d7", .Okay}, + {.Mul, "-3a61d557d5a47b159550bc4ccbdc3e2cd32987978da10b1559d25b9aaf4289fcb5fa9100a2322bb2e20c949ab1707b1c7051580aa4809278299c3337b8489c92d55d00ba00c07f3840eee30fa7fbc84db60c926ae7ddb660f6d6c31cf3a57bf5f9e6a257d2b7f5837e189abea6d59f2333ded2a2a0ebeaa7835cb0bf27e78971ee16c823d64953ec70f0648b2d1e1e9c18195d85a559e5bb47094df1ce2f1e68c04138f4e6f53c7fde1376741cf03e0ec61339c2160b74a6801161d79a60c0a97540f1ed31a71bb5c269ecbfa1851c7765d4b58d1455480391fbbff778f20df227dcb3404c5a26bc829166f61bbf6366fd20693f6d754af2aa3ae9cd71cf06a8f9a708475be050bfbb693f3aeacd4d9bf2c96f4bb1cd9902a21b8b62830fefea5d50e878030a20c60144d1a1c4dcbdceee023a210fe676c95d161c663b8067da0e63023d1aeac59deb4a10e2c8d2d9df82b86adbdb69e2e8c65cf56f63c496b5da2a52350b9b5e0b0e55fe0f4adaca00d8fa4398fe6c6cfda49b7819a14d843409e8bf37da37c01f4d4351c4dbcd230f894524ca656009d738cbb98fe6dad5eca2f2e3d0ebb89b08af05c4e742d3baad15e4e662f699694bc3f717d57c6c6786e06be5830a8b0ba11338116f96ceff03d79d11c73c50ca2dd055e920622d69fb21db1624277b764165dbbc107173505390c1bf3ccd1b1bc1000821aa89203d12", "f04b0345cc2b978e5317ea3ac1057979d18449b4654d1f6abced875aa6dd8f6129fe14cf451ca81e0ef46378e5924c66a87f6906d7a195e0190517533a32529937820e4142b471071b29d715d4ae6b0a99e72c196b7afb9d488f8f96cc58728e24dc39793a6884bca90bd7c317a285d8b69444372ab76b8d14bddd12d035a63ece2733c915f902e10d560bbe7ba40f36267add6ab41e6ac7f4b3ac2831ae48fc07e70cafa3da6e186ece1e2b02f7dcb3365338068e9e350fda36511a08e98c36b5c6086cbf3f4e89b34db845085ebb827bc9c4c04b962fcff926d4cb5c34fd75de93e44aedc1e98f49cfc4de7e5abb43c0d3182a339fce54e9a69a9630b0c40d9b822a80f48e8fba53c6eb3a260c3f36c2b43871a269d1d839f6ebefceafd0a02c328b5d2a115b3fc8c1dcf805910eded7955fe6c7f29087edc1465aa6607e59d022009a1ef63ab7cfe40070a2947af4bb019d548b4bac46ebc07bc9074ec05367ae2715a2fe6bfb3bdd289754c8dbd24613a359c3a7e80b18660a13ab3f3db0ed995e37cd46d58a61a9c6f7b10040acf2b8a425a84c53fb98d7d3f042ed5340cd7905688f9b57c87ff86691e2646701c71c56939e9b5185c02e0d1e339c08e5150b1d1803341d92b6156ba61dc588e1ee928b94a9c0ee47c82e94f05f3b9d83650397171b1fbd3254cb32ed974ef28c8ad408331e38f28e8352d6138da42277", "-36ccd36ae97439c2cc23239338626ce1402759d4f359b542a4d20cfe87ef4f63620fa0636aea7452cfe4945398ee94aef08b32ea7ebdd4a3e1845f4566c4026654562fb10fb2826c0c29e9f2620c648b858308560621b1721fb05479e03737c48d78b85f80a3e424bf9c89d447c47f0ea3deb7cef76be042619e090141296630bc3d4394e58e30be04ffdf5e48319bb510880d24a47e44fb2163106fd4b620fba2230c81adddcc85cad09a8c4f7dc35d3527d263df9ad1646e51b866c7da0f4854380760c9adc85bd7b27b5ffc311736813c976772824dfdb93015568e86ff1dad3f2efef40e4fcc75df9b8acddabecd96c543446789fea3bcd0a138f50bdb94b224c99bece4e02e4c61709a6bfa4476ea4777d7066d3d9e5d1e83c9db1c822a50241f9051dbb7507c9c773fc9f51b92370748d164472e10a472b9cea29156ccd2265eb4a07025751771172d52a1d026d0c3014895c07673587d1af8213b64c780bdc15d851813b6d0bec4666ed98ad76837472b72080cf9439e3f866630afe5ed4de5b0620d18f7141f37413c7d0e624a00a10239ef268d33c84a87f97897e7dc1db034ebc037ffb4e82b60337c0d06e7a92087b433cd304f4019badf9f6609e074389da3e02c765003535458dcc0272e82f5b1d87dad1346951bcae03a8cc5f4743d6d82b28461d7862369c714bf151b22b7ade29172121b049ebaf804d65d1e14bdff3f5486ea7244b45195455735b4a78d9bb64632ebab7ef3a41364f40401176bab42fe013b6d60df0d52987ccc1d2df29920ace4b6c8da7ca8f03e3f8228e04ee237f57ab92c36a3a98a4152f1311db19438973b5f08135b4da02f4c9f4f38197ac4adcfd118c4b35c083800ba437b14e8f26b7c6a7db3e4f261456a98440fe92d4c9629147f096cbd5932b88234eb9de0f6c29336cd341cf4b74bb05c6b9ecfa749f38739d5387a9e24f1caadc9a61809bfee0b9f2086ab064d2fe22da273af3ac9fec1cd8773c3ad139a70cae7f3e13124ff1db2857bd9d68ac40c2a4354245c2f5dc20a0c11aabeb436b599c4f95cc5fec1a1a12cfe2be634decf01f0d187368829fd20b3dcb379627302da25e72f888290184bd5775f70d375e0233f009da4cd2978ff28a57d6e43339672f757f3631ddb292005029bcbfc84b574a95a5a1c025233621d1255c22c252fb14cc257c64f38dabb6aad19139b965432f64cc83ff7ae9a8d272ea46eec5e055559eb602002fc319249256d6c1f7b41ecec3852d7eb81f272666b11955e3ab17efad1c5b05fe1a8d5ae6903fdd1edbeb7dc053e3d9de6c06d04f78960c3cfb7001c36e75ff9f00ef8d6ee1d311f0f247dd22703aef4c39502004596105610373373bfe167c175f35926bdd6284339f947a78c3d100056cefca38c297b745da8e73660405ae10966517d3c7b1c0fa0c75e", .Okay}, + {.Mul, "-4e2fc7dd1399426302e1d4b2e12abc548696f5e3e26a94e5be07244b4fae540329e11ab5cf5d2351bd02b00e5e4ec4433e1475e78cdaa18f588bc9964282dcd77b7391dc9bbe37dbff448f9405fa66f7136c9e24c3001c01d5c2e16ffc6595af0b244a69bc574c3c7291060ed3573eb41eb4a6e7b5cb8ac2639b7a268549430d943d08372d9f7136c39cdbad7153085efe35e60713caf268b64a078215349039e1bcdcad88ee85d7c9d4b91f18cf7f564b230d041c1942d27b15ec195c02f38a7a7f2213e273fed62d05e26ecddcc14e74a03a3e75747bd627c10ce7f3535ba502deb2ecfc8d310a913ade5051826a5d4ce2937856ce3f6841bef9aa61918ab002af6e56da7588623de1fff75b09b38c9a1ff2d75271f2384867a43e0adbfadcbdb5f217d8ad6bcd7d871507ef208679cda8b1c4677b33f41b63fe3a215d615530b3567de2cf06d06ec7ab31afdb64d3ec60f93095b53f80ca2055df4b9b5447d36047ec802c2795a5c5175dbb1372f5ba039aee353f588a5ce12b797508cda3ea58010ab3537dcf267aabcc035b30262d8687a8dafbae9a036f4bc2c6b4bbc140bf708092779794ef4ce9c5d1a1a847bab292a60df63579032b4edddb372ed01bc90f2fc41dbfef2fb649fcd1ef88df496e596a353e292ee6837e19b82b5977ee77b408c14e8fdae0baa34bde39a6faeb7a6b2154be1b22b0620df31804e3c9", "4abb521db8c75f7cad6426a636e1c95831b82f2773b14b4b8f05c1779da43a992d33034cec0e0a4f9969a9349eb25840cef888401ab31f968a604707bd119290a502235cc44625aaedf168098208e70c2d9145a6ef8d0341ba59c17afbb927643d22ad2de947cee18136917c5203942ecfab1a4918bc11221d6d55d8485bb0b3487067caea1d27901680bf5f793adb6e79bf3a1d7bf4f9f481e8de42e87387077ba6c1beaa9d547d0d93042b4c2811a8f9533d37c913c98393140d1f23c4f28f8c214428de9d01613ee897ed7552d3affb2e5572fbe1853880de0bad72d84ada1099b6968aa298a3e36ba79f83145784147262042b51d8f40659cfc9bfdb72dd7c16fa6d41bacb2443c33bd31d5668f37efefa893e1ca57aa472acdc4a02e5de1e74e561e32a28a3e073d48f248cb8291d23ca4f006fd43a0445476f587f5db3e0b92dd0b6b2a0878def14694aa027e69111054540415ce696c66e926470b8a751cf1223584fd9304730e0b38b9c053c4a449a4f77054022200cf9c655b5c5df2eb16754bf8c385d6c2cbca3d5aa2d51fa57157147b7daa4803e85fa85f78ef67f404cfc076d7f7e6db302c6305e69b3cfa4a7b5afa1b65d1a4cc689c6cb71c1571370903b7d3dd1a29419af3d4d30ff80053352cd89c1e6be2972895f9a816935be531b26390c2d428b2d7dc6814d1209d6c07121244fbf7477d574784b6fc0", "-16d305c148054e6b7efdbc5334635b235ada3b7d9d3edf2f7ce519f837b53a9ed138cec74e3a69891abb68b38a6ef1507b67fbbfbfe595a8a84fe51c26a39a30b0324a4809030f469cb113c336fadfe1022c2c22599eb34bc37c3816a14993e5c1ef650c07d1f80f38db8c5553c4454aec65e8fc69199aac6739035f465c573b1266e53e425ae961426c018e365f2534e4ffa087a07d7a45eb5ee53bae014f48d54f3c58e31f8a614b18347014a476cefd1e19c2162cdf16f3ea23af6e34f017148d91e04fb4fd1bba9e91033263b92c5af491a14d3ae735811f0a7ff1a860ec267376f9f6aa75317c3509bdfba76ab56e4255e91237b71cbd92fd24e13361c57a79d7f5c281feb7e20dd33fb457a1cb901e837e893896f3179f22680813299edf66b575ab9eb99dd8e44db957f4ad5681163f10e7dfaed4cecc0d117e4b84e7bb090f7673ff2a8e98257fe1534103a4daf6977392c5fa4f959113dc6c018089cb17e45e2c6cfa50a3acb6bd5e01bcf964e017aae2e27b788d54d35c3c2885a07f660dcc717dbc9c90de6686de7994fdf3ddc1be8d4b2ad2c667ceb464450de9062b73ed66737518427a828f6658a04ec67e298c03c4dd8b71a8916193caac2795dd745badafe3676f9d4a59f96c4c1f77d39b6426f1e2766c7146446f4c5fb10493aa10dac38384bacbb60ae17406cb40bf17a60fcc2060579c6d2968c2122d55af0e61ef66fddffe5f8bb2625d2c8aa6b8b48a1a6095c9f6280c71debd9063116b4425964367a755aa96c6da771e387ba745134a46773e1e921adaaabc9d94e7d2707a8aec492311db2d21a073249475653e178ab659e00153ffad7396eeadadaea000dbbb215709e000de62b128ed7f02d02554d7a876d5decb1ce25b101a1650c2aa4ef8f12c4b0c9ab807553c532db959647999869fa1a7019d22e966028fd4d690482546b4020be29261f2c29c8c0aec20af790dc593ce3752011ac1974fc52af3ea046af16e05e690e2732f4cbb4a88c40a5794096e6ecbe99f197b81efa0bc5c35a23e5ee1a312279ee7b8865b3327b1f5fb08e4a4d78bf91b1e4d61132af620005fa1571fa4e484c23a3d4d4b7a881726f6ed2b1da6abd3e8b0ee9c87efa32c29d25d4b1f9e40683201b79011f7423113d8b4396d85a36ca7b1e21c59c79d9c84cbfce5b3411655810f3efd76c2e1e0e9dc6d9f290aee5840ea8ba4fd449f6a013eca4437c231577bff3ef6e92d0f474471cd441fbccf6f8b756c1f99b82ad62baf5f2e84131b0d993084d318da57f6c42e8773080c4a74494b53d61740bbeae5a29511d8da548bacceefb6204e3d990f9ad22cb60d33935785dd4b59305e91e1f9a8518fdc0fd1f470f1f9c4ca4af035c0ff4fa19874605db783d08cc1646058cebfed9ac5ede6d9cccf1882490c16b650f859c13da6051651fdc0", .Okay}, + {.Mul, "732720c4fdd54c9a140dd1e7771c32e3b21f7fcb8ab0e60b2a01a375c9516eb652e3cc5320067575a8b49010f6af63399205b7eaec04c8e000adfd414c290c92a19a46a33e6cf65e24c6590ff0ba09353bb53bab174448edd4f158614eca4974ca3695e3805b21b90ae7309c8d907016ee9cefa7f520d5a0cc746e44941905b26b334b530939a49b39b9af67c538235c0a32091f367a18c9bf63bbc14b947298b3c43c1a786e3dd121c551bb191cdd9303164956b4706f2ef62feaa6fa66132c129dd609e1ab7bc2338f0920a372bfa3232e4cb5e52e5dbe12ccc687e26723652b695c9a9fdb8d592fdffe695d0670d95e2c67294a2c68a591fb0aeff5d5fbddcc4ad76a6bc242fddb39d1225373520ea337ed136821eecd2803ddbf9ebbd4a369de2a452b2d11024995b054676d761adf36e082b65dd0f85c749ce851ca7beaeb6221d076b5235a394eb84d80ae816fabf595385ff6f8ddfd3f47f0e42bc117d3a64ff84ee4d976aa1f9ce9bf7a8611218ca207e708199b24fac4fab99e12e0dbf974826880a5bd1f340c0542b9bf874057cd0bb55c2ca61b46dd6aba43b3fd368f2c5b7ef8cdbbd13da802429fb2f6ebebc59930432da8ca763acfc46505b93a720410b32fe4b8f51c574676a469760ac22071e0e7a3178ef9d3de43b9f993187739a09505cac30c4b607fbffbc7fef6df4e9b4363c1deb4445b6fcf2a30ec", "ce0277e9fa5bd2e778d09f5a80c9d0e0fabbd0cb2ff9d798e37a6e3c3a40e61ca6d6ca50c7e526a093c5ba8320299fed60a4ba504aadb9c6b84a3e4f4d88a9b173b66af38c9529b3a1c46b4c50affe423e062a465468c3c6f3b0bcb544f4375ad182bcdf89eb1cdb942deb0878c184d3dcdd512716757218c8d781a887fff6d9d67472461c9cf67f043decd2ca214c5bc2cf8dccb78316d1bc6228644708c3c938b6108491fb652684b5745a028f207cb4103086436a1ba2a2f59fb125bae5ce7401e8106a1b44a30ea0183a90aa59d34a1524507063aca91848d5622010a9cb3a9adc8c26310d4ffe6567664b311435a2354532d44a627d70e41138b4a4429512f0eeefd7ecb4d8aa42a729567d65ea5a2ebd91e90cb3af4781c66e848be2d02ce2259ba44ad65d37b33d6de9d5083295905a9af0b508b22067460f7cf31fa77187a6f004c29c252921931faa395b1c79dc28a2214b1b091bd102c4f9f062365adf00ce03fb6275df76875bf774fbe070f4dd4dbe7080d23c4a64257c65ebfe9d599f83c51150d4e13f88934e5a9364d9d30773f5f8f8a22dbffad3f2e18ad4db15419e284b4d029438e64b8177fb0b03487747af6b2dbe3ed55e5ebe81e175e033d925b7a2b39ccc3137a2c910cd30faa90947eb8dc1a68dd0981ce98650fb117d2231bc2e034a8ff39eaf3d1c406c67313ba28c7f50f82c6959d514a689a2", "5caa989d3541885f00867f02438bd6c59f12d389615ce2f1799f7ecab240748d953e85d728d944f59cd824af526168de779c21b5c6ed370d58129c58bc7ffbfad5998a0d58ce7ac15825aee3759e019e69ec40712ce749def0ceeedffac0cbcf3207de361f8c28bf6202e4697d5a05aac90c2e2dae1db5c8675f5058d736d57632634f195db3b2896f1499d71d888b250c616b60304895dd4cfd67416945238473369bf261de59e9c6646b5bad343744d5fcfe80b2527b624893a312b2de7facc027638a1da9906abb175f05b7e501792cdef75b1d00f0d3c93fdc80b892a4cb6be42f81ffeddf7de33ee7e31251b9d2eb227746ec72a8fddb867696a75c0163c0a79c7319b68c54d84d259f137657f712150a2a8f0cf99ff640e0a22ca277793990151abb26ad51a74c13636950976a33ac590bd42020dc1839aef67e6a66bb1765c22aa33550e234b9df5858c9107e6da579ac09b8836e5c0796d4a6b1c2caa05ee37d86bbeec98494edccdb2217f68ec096f98d4e1c4e474a96d8d24d8faf4a58ccb8e671a71fbf3e5d045f75ffcf755f29f9e1a3051bc316013393a9d3817d20615f268a713ddca9be1dcdd2728991741bf518af8c6ab29e947c86ebb7bcb8aa5d027df001f1a40b29b6998b9e10335aa7d6c269ebb8e8f72ea548f1814d4e67bd3f0df587ed225f685ac28902df20ca8aab340b96c8b36f7b94a8606761c2813f160bd65dc602cba573bf8e8b0bce91e73e480c3ff83e42fe5a31b688aee08d6d34bbf71d0a9868c3a978043bf1ae8c616d189af4c595ba328602f5c1ebb78a3ade95f2fcf2190e26a4f12c8af341cf6312a20dd1fefb80022abcfadac8dc2035f2d6abea5fd5bfcd15b6a5381067ccbc5d72dd91ff9e58b5ce34e521ffb89cb328ab9a5e05b986f1eb64b7123616d60c307955f184e3513a3475deaf34db50f3a475c4d49e440b15eff60f8bac188e715f1ddfaf1c723cb535f80bf63b3730a32018ea8bbc79785c39c80db8e6af73a665ea2ce9426611eb1da8165d8201899493f73fb1f90fc0fe485642ff65d73a05e0765c7a9e7b578d06ed2199b2de64c17606dd5b97d67b80a068b07bf823857cdae2955ac0ae0838a8b4fd8626c8cc2a6b7fcbf95bf95d6d69246766dd0ef36ca214e502944f8746abf584ee1d86dd587c9131cb4b98af64a87e8aaf90b653d2a7112005f83f099e9dea11c6ed5c401fe3ccd596d8d5ba6a28419d2ebbe8c56a536979a168864e17bc7b4edeec6ef7d9698f57194848b1890069481e59bc2171c912689a2b0cbf6dbe385943dc2bee1ea49ef83aa8659d0040a3e7b6923c144293f2167400b8d224114a2710a8200efa81ae345b951324c1f6acfc2b7245061283c93b3d16afe3af7d17bdd3915f47d003667df411b148486e1394d11103c074f3d2bd694258c91428d5e94158", .Okay}, + {.Mul, "-ff4e14dd1a5a194a386ca9cf3dcabb6abbe983bf540a84c4fb8284f568bec53aa0c508eba9491924e8e580a73ec20795ff26e4a57da9f6cc38b0e514e16878485fe0418f892aa875c23e4c501f7c35a7bce69838cff4804d2ae61390e6a4e47a58b2fe469806f75e70a6f09e9d91db42ee782fde4dec5a0114038c0b9b2c81fd916570acffe4c7a79af7f0711bdeaff7971507fe570039ca3836a8f1b391c4cfa80de59b6551aa3fcb3a00547ae78c66903ae216e9e956607093db4ee28754f671b1dc9ca0790590cd7d8bc8db5b9abbf5d680a0dade1c6e0b5ff965407e1e3c48da7c6eabc544291eeeff1bc0ac5f9ba8de57eab438c2e17f31f133e7e4c5923246668a070c92257c0454a4d4b43c5184b9458888308b48b7b322559985553348e184b8a0476a68b3596cb5b35979c490d242f18d48eed1a2c8f0845fdeef65d91f13b4cb4e128bcabbb6d1c16929d866efd399e1e9efc1be13e5432df13c3ec9728558a9c34e70efb01f0d793df99dee7d3ddfb1ac43a45712d66b9dc6d3ea14a6031392116f60478ef9b2b68cff9db59b0412c09a203915c98a308fb52ad30d51d548bc835b9f4188860da32151b46b3c712055ff52e6754be7c96ec6c95cb706b1f2e41079eed454cb38dd9480f46616a2fdc4fba9f2bf31a7d3ec67b185edf4cd14468b6c375fc75755f6b1e1e860eb8bf06c096d05bdfc9ca3d4de18ce", "ca1b92001cda270b80d5af7bd4550ba00d7567cd083f43e14f4d95bb2433539cec6c454f5c010a130637ae71e9077a1f1a0b8530aad08c6f993bc87ac7645b6fbd443d452a2882670f47c321a64a8d60c503c5570455428e9c74a4aa1cab9b0cbbdbd4238f9b33abde75279a01996050e1a3d06380b08e57d8826fe350fda21f7e67c8eece8d55bc7baa10b760ecf24d997228cabfcc0fb51bbf23e245e66f131f725488982c1eeae82165b264cc800efdd855ebaa4589f62260a6900273b3e795e53e1c912eb4af4d8b55b0675482f2da29a5329bfb62f4eea03ce91591d0759e098e2a32852a137a75ff0a368ce1b05aaad0223ae2e344ebdcb557213e8628b9a2c0474c728697fa7e1c2bbd7d54598193fe72e1ff8a51b22b5f7a9a11a3760c2abbd9add29f871a4bf84a389430751dd10517b82ca50975f1f6c0e14f509f6518611ffa4939d63d711a7f84448f73c94830e1ba4a849083555a35340451821a2e2d29c4351c118e094cedf18b66a21abac89c1dd0ed8ee9ced072d955dc09c6f8a798da70423fa4b671b93fe12be244b18ec1befc43ce22ca17f631c053b9a3665557cbbd568f1fb3f5ad49abfa4e48046b8d48e1eea3b89b453dd23e2282685099c5c5d2d6df252a7cb08f295c3cd33f493bb17b6ff2377bb2a39003d4e68ad1b5dad76ba4b53718a27afbeaa0e4086021ff1969ec9e78c3a6e2e5b4705b", "-c98f1b4d4ec91232eef50b0ab33ba00d4317bb340241b9ad932d5514f985218c7f1f6c1903f6bff513dc9b9e50db9ae12a5d4c4953e942886f0da36b1d5e5df67ff2f25e234257c7e71b0c2fc4422522e0fb53971f87919f02317883841e449fa649dbf24fd07b63625f7c6175d7bcc325a9631e564e4670b3ea91751737a4060c5104be0b16394cbf970980ffb05a491b18415eaa9b735dcb62a4e3f52d606243037f53e85eaf45002c17229e87e54610221238fddcfe76b00370d8ce917c07ee7e0496eae36a2c573647674d44e0554d97d08151f6bc470c7e39ee8999cc2b0dfca3831ca2dd060fccb900c2ab0dabbdf2f6a3909bb9412c9284f54a2d39456243f40ec1223a77bd4d2fc8843451a2db813c6b3b1c31702e7e5e3a8bf67931fe3053234115df1c346f203d3a05d62b54731a073857b462ad36b497934eac1360683fd94fda54b88c2044425cbde725dde157171a645ca45344301b89d1f9f0b42a06462303ddf1d858f1548bda91638ba8503c3999ace47df033748a16ec9ea93c619c26cebcaf156ecd3d5e5aae5fc8152651f76aed15abb49a194f85c759159c710f2a31b765bde037f6062ca3c8552f1439a097dd2241db376d63678e45bca78c08546c690b3d55e3093816516ad4e793766410a7127b682812bbd641cf237f095a3706341d35d4aab1aa1bcbb041d1158076fcc1fe7ffe540ef6a36685240bcaf2cc8eeaf19e7f51da9be0d27fa4511077f82ed514e82f0dced674858322f9b5fd0c7ea5dd6d25ca9374deb886ee6ad86394daf9bdbdf29d58a95e13fab4fbde8be84764548363229262930971d35e7017e605f1dadc7edb6135a208e34972e8025071c958a43e0cbce38d10030f101aa9c0f0e4881a2b27e41e4fe8d0d60cf6d8cf166e02fcf7ddd6e6f493d3f984839b5bdee7e45c55f563616000149c1001f50f8fe8a76a451f6aed4afd3460283f11d8d58cebae8bdfbae049e56ed72aa11c7dec27369876a922440161d3e4d084eefe51dcc39abd02a085fc4d63a4ffdf5d956c7e78f2a525652aab24cd0e1d06f8e5257a109e6a20bb24947dedd51cbb878fa0105e90528c01d5bc6e6f00b71197e67791fdc3226369ac846854408b1b135b778be28ae62227e9952773f4cf7262d63c4aeddd97358dc5fdcad01c95ef8e37d73833fc100a82e59384f359aa0ff7c79c9733ec64fe1bb98c36d92c4707404dd878095deda13a9ed77e738e5853e3e6081f532988b3f207d57b3ca06051c8e6c78db581147232e680efe08ceb65a23121578f3d97ffe050bb69576afd40a02116e1483f550a9b24f269297e5a6a38241148827429a233267400232b9f82d26df9f75628681906a699c178c8e7bc6744a11be53f35b3baeebee7ceb9a0db95a7f39e6fe76cb8702d5be625f90f640d5f9fce8123012d938ca4f13a", .Okay}, + {.Mul, "-fb3178e3c630c6aeb73b1edd13f00f919f6d9dd40cf1c2ed49b826155be096349fc7f5ca96336f001ce48be5c07b65fd79a16940cd6f683c91dc39ed04198fd460fe9741c9187a9863194c6ec372003fc19f778beeb2fc853d9e81862ee7265d15af9930333c57c828d8226e983dd409f6142e048217cfb12aec236fbb4fc5edc6e9bda9d32ff20b296d79f7600b6bd7fd9a1a7d07b03679a9580359787328996ec4b00ac8ef2aa7a455106353bc91352f3506aaebe43e17bc22f2378e05521f4ed6f9907ea5861dd22d50d73902bce1dfb8f01229eb9aad9be80f7316a62af83f613b915a355cfb93daea8ce9aa465e6ddb133518ca91cd98d740ee07de5d67f7014e145cdb6b39b5f0e3136c2b1bb018c2b56e0833a6fc898297c3a133303a18fb1689e7f9d341a26fc3d70ac71cd27fe7197882653574234ce1b0ec7bce2a3f5aa0d5b953d18b5c27e99f63e004b8b659f0c5d33406c3afe9c239c888a72c27b4a005ff1e59b51838ed94411ce7d009190a63f12a498b591d2dceb4c65a0fb46509473be9a45209a52f3214d618f40be9cfa04634e56c128bd90c555c342e02570e21567b0a674a0442adfe61e36831af2665db15d20c19aef05b65924dfec6e44e56fbd509e56c352ce494d13f69078a8c7a3f9cb0754b475722c6a3aa170176de2eb4230517d664771cbd2a548a35ef89475760c68ac86a92655e7ea339", "b6cc9fe7ce52bffe9fe4ebce6469fbbb5f514fd8f49a2eaa1db91b4db35f94700568525cd105398f249325d084259a73bb12fb35c9db6eef4c2a9210c15fd521ea5f214df932a494c5d4f9a9e4cf1c1ee5149de48956ae44e153269fcc0a4c647b1659aa7949a188da3ff9bccbbdf93d683d32ff614a05f75eba3f26cf905f820b439f0c66925f186d41a82d8821cae3debb192c770d242a9127bdc6d7b8afaa37e35b0c32ea2e9f3f7790bc4c9f944b27784beb5d0ad802719cba9fefca18a30a8c23be467f38acd4b6110bba46c2806869b45bcba07a5081ce5becebcc252ef9819709252689aa561bd002ffdb389da03121b7f632f3ed5903949d9dbdba05bea6ea34ab5c6dec39278d9224364465b1558cc46062546a8bf2f5c278aad1aae3aea2d7e2e430d58edc16f8e07082b7f5cc5f3447a6575782e42df30b80425539aa379c2efafd2b96bfc103b326f5823d77a513bc73b8662b63bb5e3ff824fb5340a2fc9ec8d5cb39fc8d8902a5cd34641b5e48acebe6d1d36d35aba64c09b7c21892ac68dcca39c764489227deaae18ba40b8eabe60f757a46ce8bdeb6e0f1f2eef4558dd04789696f1ce882dfb3b7568d9077ba54fc3e666151fd732f750ff1ebcdd256b7b65bf8235c98ad97aa8228197801ff83f60d3cfdcdeb579c9bd71615aabd19e46e275e2f63e351010354223be3ed04308521dbfe0bcf3f5441bb", "-b35df44572952b426e84ce66282af5a65c4be26c4b6189b32e1195c51caf876a79cd4d1c9dca317b7d9e0f8552fef6f58163d7fc4848af0cc1b09ab67d85e5ba782d524e6a5a19a2785ea6211a753ea41f193d897b757ed23706bd0477c51f21c4240d6978b9ae244c9defcf73ebc0abbc2d02f3dcf51afc938e1b53cf5cf1247735f684b6213a53b8ed99a4724e0d750b9b5769f0ae661c389c8ac656b1887bad0885ea342e8093f8a11d5723d1a0c49a8fb1c0b636c81823a28d6509749b4b373fa416e4894a187cd7112a9f7cb49fd16bec8d28cd5743c1ef62ec05de94079160259c62ebfaadaab727b124fd8de122eab9af8244f2e3465cbeab1c55d9137e85b713e9cd9f8ce17d05ee662ca95939cfd2ad3254750a887e78cc9908ccf12044cd769201cb0de73230cc479151edbdebb88537af43d0e968f6194f02805e4f1eb80524246cf0382f6642de8836fc483764b2a320a5d633c550aa0a5d26e1bb068876a4bd68133b053674cba329bcbeed37835581ec83322fd123841a550812a29365e8ab901ee8fee02c4ca8cdb7ec67c4959e782c8774e8d0e673483ba3fe34b6880a5c4beacb6ecaebbddae4914f55ac273ae91d694ff8574255b9a4b5b964b985fd0637ce7c6ec974a19ef02dacccae9ad79a0f87adf0feb38e0f5fdb216a5f0b14ab466160277a46291030a4435c756b72fa7833e55380434392a555d71d7e32da73e3fb7bffc6c3c029534dbb793a8076b03336cf38e0c9dc459c65eae28c1b4fc7ae7b2c257e0053ffe4e0eeb765b62a0063efc6f622cdb69becc0146f6afb03f8a8e65dbceef797458ed602ad8a606d551fbe84ede7d36469da6c40138f511bc3f58f88338fc490d8b7979125dabffa2a1e26e90000f682f8aa034f9a4fe9726ae2be814be974c59f3b0a325842c46c40d7cc9d2f10ce8e09afe9633382e4ebf6e02f9849890040ac3e11556eb27aa8fd3c75fd239a4638b3bc0b5e0fc56f78734eedc09cb845a6a3d0fc4e5138fed11bd418d154a4ac53f056b5fd6db50e0ec9e6fdf5751e74270577978d2a85bc4c9f6df1d7446e7074a2d1d0137e43eecb8fd0d7df843df689b51f554998be7339b6fd4362db1025c525b47a87fb8c826c2e79a8e6de110afaa46b33e10d5e0fbe99b27366b32b6857220fbe93ae22f893f1b5e7b369e292f06a88321e79e9a7ee18fe14c782df091afb957d8676bff1fca226d9c9d0ec46ee68dff89bc7e841c70dd74b15d1cc371292b078066079dc32fa6113845d3fc7f4e4bb519361aafd3ba9132218ecb0d2756be3ad01e3b8bff604871b7bc0ae7beef13b6ebeb3b68301e4a596426b031d7a0d4898cd8b9c8dd7e56dff9cdecb4e3d2047e7e385e7e66b8d908cfbfbdb027abd9d5e0dd7657d8d77afd3a0c9d2fc29fb38d38b0f48f1c5a6bae9ff8046d9c3a6b3a3", .Okay}, + {.Mul, "-8f629dd437261f696146fd9d88e79021f3231067765c7887655a41766da37283debb754f6ab20e3924c4cb4ecee9089ef700fbd25413c5ca8c501d7df9a9f4d7111c3cea3525f28fa71499f6aab7bf0da640773eddfd9a646c13ff88029f8f917bc25dfe9653f1a2a68bbf8537982507b97ca2520fa75f573450a3f70b24620c85d239dd814cda846a4fc60958c37fd286ac67e43431e6bd8bdae587dd6c0d4a1e43f3257008aaef28776d45a9cd685b7299291b1cc659607a533ddc258ab5c44d66873c2b291323f40dc4d04caedc90ef5d81bafd6a0abdbe711a24cadf1752b3d090efe2aa6c1b9b777c41c8a17053c0b479d3ee78719ef051a3e14e8ca61b05ce1db8e2335224f4d3c62b223e249f6fa81ce967972568430d5bb4965403e4a669bb4f5f44f0e63c7086f2dcbe00d813b5c33dd7eb4f5db9d1b67dc1383b0a020d3de5f4b3774629ca169a548ba3ce48b21e24f2ff1c4b5c12d01d95145e39136900ca0bca77a46a20b5a9a6203f06a9e740abece1a75e41f30815acb05f29301b80b981a1fb73efb54fd63b5c0f509c99439280174e408458fd34dda5a7c953dc76558065070a595cdc22942dc3fc16ff2fa235a630d7176b70c4a9c3619c8c88825e9082856749a75c989d2092a155312e8d3fb1cbaf156b1439abb0cc77494d39ada203e7ab26c83705ad0c1fb5632e330b110b919deae2cf1b5cac990c", "958df6ba6dcf8d65220eaca3dc91a3f26e87ef73f0456176a0a699ae238f2a65064e153e7b9b797225af4a5b46a8a387cfa87f420bc2abb3626b975be6b14c32a4be0952494f0cc39b5d45b8fe65fc078a2ac0eed6600295fd0cffb15b28a68890c05bf1a567cf24a0fdea1e02c520e8cfb4308f042d9c6720c7ced7e505454e1e6697f544d5439ae233301462317a919f05521ace1539c8527b0243f5222500e281ab4bb7aab1276b2d7895770f4c1bd125c9ff1fb1f2e603817b6fc5c6ab3dd212ba8d45df2249e46a4aa33213e110aa5c6dd83bd1bc7f9f0193a68d5fedd3096327061152087798ed7c4a30126fdd656fd59070853c3e07880aac6e94b33a13c348992064a068f0b83e76f75436effb0278ed9cb67e30801e110cfb601fe219f48c85e2f150dd73ec95a26f60b33645102617044d0f985ce96150ec13dbe3c646be73ec8b1db9b8356b2702d7ee0cc477334d8291f4bcd8606069a796229a92874dc348350480b5dc2fde4b975a956a0007183a990330188df3b60bfb37d9f3f0b52cb27bc8234e2ec86ee40296d6f25645c23c7b3013f02086e5c75901e843049ed2e6cc6e39dc23cc26b74c86cbadb115053fb269802f54ccf82730b9113d92582a8ec8d8b4968ef6485a4f9a0de8eb09164e093b20ba79e14487046a5e2b6c11e94c93c8c7ffe14ae1adced60d1480d41b05e2145f1d8289342585d8d8", "-53c3e95ea0cd66994688471b26029fbc8b9b2b9ac362b500715ab488c0960f6a8a9f5f94db111ce5011de041f32566b9a690780214c7b64c0b368834139feb1f6ed515f52c7052d9fd40053ef0e77a9cdc0c4b955668b09c3863edc933955943c339476b9c46676702fcb203b8e3bbfd45ddc348fb76fb914638b23ba417285a541d0d58ea61509b6b95b6bf6303e93a9d40e17c1965c3d14b7c5710c3e07625f665afcaa2e7e5ca10a79b2f64e93d0f1978590db69d2e5ea0688af8b685565e73064e92972f4362cd37db2efaa49c7569f381b976102dfdde12217d1e96502c19a75085fa1653543e07ddd51af3af64978ab7622aee18b8a7a8f99706f15dd1053d462c4d0ed49cfbbcd192543ed0518e0485e82060f0344a77bedb1f1ee33ab4d5ab5b84019de023144b147fd5c04f940dcdd2902e6a8986eeca542ffe2b6ed14ade7176262d078866f558cc0621e1a291ec499385ffc44e152f57e73fb0ea9e6c08f96603e58b57adbd5ed516984c0a813b25dfc0140f1d43a4364a58b1a75a9aa1a6b5616df5d4412728814d51cb93a44864ee3b8e915db56c21562f3c7eefed3b1468a2072782da995c76cab1a0f624ef108e751fee74a0cdd7d2cc2e164a25e56b35ad90999916395313b6bfb11138ec76514cb8c921d1e0ad183f829a4edaefa0860029dadaf8c9997c8b688632970f3d3cfe9bd901e58feec9490f7c580fb6f359225632d47a41838e02c0c9b4a44e3011950bf9351b7c35c9f2a80610a73c4795f516a49214a6dcbd7c567f0036f70b9483ab763aee43078150a4e7e93dd531d04ec8042cae364efc444499de043d9db7492696d3e538bf5a5d7d33c1441deaaf3711a9dfeab7896036bf47ff1fe2221fbb62569644ec9f80a03b007b8fd131448b10e7cb19fd545591937cf48b8a63abc31f3c6bccf7a485b4225b9dfbe53e6930ef97937e6be7009a7e2f0ae1160a2b2be1b7b8d8993a34399fa9ac3fc89bffa7cf54d8a5c25011e14eb01ca9aa2f670c17619047efbcc26c96b9c36fd21c1011811dccb11b34e495b110a2396c32958a7a8b820a53cd7adc3b0bf6b0491680867e825215b543be6f1cfdf54156889a3395713bc0533e986118996137ad5caf7050e183ab2ca23b72835bc4fba5eb552cc68a2bc4929c8909671c676654209a858ec26907ac7437dfac232c9620951b211977e5ed720b11f8b86013da75c094668993dc9029fa600b70b7f13e3a818b8f323122040c394598036f448ae110c9f315bb6387fd05fe892b52538a32da2c1ba5834cbc0840f023b6970fb3e13bfef70d8ab9953bb8ce2eb321c5e956eeaba3f0a56465ef3331fa39f0dee14802e005dbf7f5231ae8b0779c446f3e5a789e6c2315fb705d0c0f5868982c9bd86f8c42250c0c38f0d0612f8d92b19940363383f9c960c86f8211ff4220", .Okay}, + {.Mul, "81bd20780ea5fc31d1aa0b2b205c2815e62dbf90a0e020f113fb4b8ef2e6300ba16be48996b9a316d24e381b090fa117b700a82998a69e8b58a9fb78d613e950a93a3e5edfb2ebdb9973bf16ffe7c54a684a7ad83d06f22ed9b8b43fb150a9028eebc831797dcf787d336371f089948a90040c84b2e12892087a98e09ddc45bf31b1171fbe6b19219d5434b7861bc00a57ccbc3684a5963ce90bbf446d8b8abab462b53b7c8733217025378c504888717cbfc8d678b6a4899b9f60e81a2d8a11046cdd251384046d85d2f144b4bb606c7b0e514a194230d8804eb800a82e80533e1c9a81e098b808b5f77f470d709cea1875e87d05a156b07cab465370176599e1a56d2dbee601ca6d5ecfd1b1dce1c3d76ad16f9c6dc46edcbb31ee3cd894e727b7f0b0ac256ddaadd0f49b7010bba6013889da5f66886e1f1c2a94853b735cf84fd561dd87e57dc6a5e8c98bb7916cd46848eee80e348063ab8f0a3609b3766f4301397027c958d29f12285b0f2583ddebd0cdb3f8a7af6b451e61767fce0c0f42a240a05f1e5ab9a7a67b3c49c9231b3d6ad4b6e946e30703c09d435b5f1f2c18c618c8d55286e44135a15975abb515d909dcca7d709ff585b6e01f55d5b42d5cdde57ef3322144916f510aea0ec5c4ad272aa27a2dca3aa254e13b019848c3417fbd6208b7947008f6f79214fa1babf7bd7796420b1d4f698a79c4d2f004", "da085142aaaef86a075a90dd3f91b2b101da0dde0aba74b734e45b90e45e3c6a2ad2a66b3bca359c9b3a241e7a16778e1030f6b32910d4a2920f9ae65b785d05d6ea2adf1606e852668398849d442be63fdd1706dfc88fbf26259fd4ee5437d5c8ab6e893d80ca90652fc70c2341610f821562aea446891e58a1475bdad1d96aaf49459afcfd4d9a3a50a51c5d13762efa8f30f9f7835fef73735036e7ae18b02b22df671c3363079c2c4344bd7ebb9dc413c08d0cde55f0b6f4c8cccf2c44f063fc5a39af613a36e6c1875d5c9f65d41b190ab8a45ff0284b1efadb7b1f319fe069c5efbd3d05f86cdd21f9c5844fe4648068e00d2bce642e428bc23d692de3658fe7c76a66b9fefc74131751b828df88ed30ae58cda98bba4eb5bffa92123e074c9eb41d2c6fe46847b18445c570a37b75ccdb01ed0bd703aaf02b166c029b509547ff2137e565692ef1674544767b1744d7e8d23e827bdba94429eeab5fb606023f52facccfe8e2df5b7610e1943c2ad982f6e789049016a711c65e07b5261147e91454873942203e78b0651265768d78f69a6f17553a9a2ea9be2079736b55536b0e12d52b82fe6810903b29b55e8ef7ff9f75d7bfa8bf578fcbbbc7e7914eafb1ca8cc1faffc98e70fe062661d66a3e2b60d983fdce0863f39e37d8fef299aff8432727998a1aeca7fd5955e0ce39e469c08e3137e8961162d8b3ace069", "6e7f44bde0c26d89588222fe7fc4c1e95b736d02141857d719bd21bf38bc794fae2c0ec6fb4b0466fb70f0d00da8ba2b35e8b1da6c034fb884bc6023b2643fa83db51a85ff0346ffaf3c6782d493a8b605cb3f27a86ac9d8dbed2338031824369bb7ea633c857cba654936cc87a7721e6343a3fc48e1148c684d5a0b4f192beb1cc990bc5a29bd15ed231b0229f2f0ebf1c478f3808be27368121b6c64d0c59471031ce040d25c76741ed05668a596812d230fe3e107a586de6c2c680826275aa661c182e51e88ea7372d59a89a4660e2d86dc583b24a85220560d472dbd7f8556abc947bedcb492f39ded23d21b442ae99f5db7ba24bc8d5614f0c7bc4b6ef76a45bebd522e7e04a0aedcd03ced9d7b358c69eb8cd22bb50c92ce2045e6d623e0549765e5faca1e9380c6d14c1d95d776658be923f619644d8a1241374d6059c5c1fd535adaec7fb441041668a057cee77dcf29de468e2c2fac1aed501e211ad741da9c39f74e75e6c020bc143516b4f0c5f154f0ed70a662dfeb9682c474663a6b7d09b08a382e802e85251ba842745b88299e39665ebb83d3bcda1900df948a3f50d2544ccaa7ef3797e0fb04e782205464fbf9f3079859c41dfee12dfa37a4b82e09685cd7778aae0da80a74b116393579bdb8c5570cf4ceaf4cd18696ae1fdf3566b32b25c76f0d4e58388507c3c0582a98051d3b760171547b901d8a38a2e7c0faf1779d3e1fe111461b7752bc381621a5d42cbe7351db4728baac8733fd7e7250553ec194b90c4ac43832f297604f3bc9141e32a454a0f54ab1953be3da533927541e6d1b0e9a9d6e32fe16a87f9b7f5e95083ab0d17501f9cac6f8bcc06135d15e4ea9921023ccafe67d81687ca3e97adad8f1bb715f973f17e5560bb94829aac5367ddac20f0a8e7b918262fef15214e1b61692a52bdb903e1247db689ab5865954926ed592a2de1056f132bf59a689a09f1f3cf6dc909308bad0b509fcc84c6e5f77b0ec1988ce4833e41d317dfc29804d1ef893965343a61147caa0e60bc9209ca4a1329ae027a295a04c5b132a178bce4af3d474b20e5737619114cc0d247c07634f05be5a6ea2c9947b995889d85eac0069c822a8fa06cecbb672ec16e6e7331875f454863d94c21ac70e189b0b1c907c35b1ff792dd3bf89843de314838548745a1a6d1e964998784d86431a3c119070403e3b9d7a0141d4a6f8a49245c2c7432005e235a56854b53ff6d67cd3d50f14ce8925f1910e29ea9ab51ec1df07cd6a7b44132d22db23a0b644ffb9594604c5a8816ae7bc8cf9b425d065c0fe63592be70ee6f37e4e022a507d140cb3cedc34490596a5bb8419997fe1ae54a0d3b2829932bfe5786e0e71cc3aca681c6a90bd571f161364ca70c73b49be8b5ebe2f10822c4ec9795208b149ad5a2e182dffd99934041f165b37f1a4", .Okay}, + {.Mul, "1759d468d0db0c48e85d2802f763473433693145e81d0158b036ec2be7261eaf14094de9832636db6ca9041611c06d24153a2aa7676a842fc3d8c0324a3b3ff8dee87793c57a77be1b0675c5addc7edcd4b337cec033af93d41558bbd35f42cdc74d2eb91b2188aeb51eac0bc567466aebde3744693f98d77eba7976763c983d7c0bbd2d6a600c60ae1bfa7376af01afc0849d0763351cb21975975fb29e78bfbe43a6d4d754097aea3aed81d5224e9d43bfe60c8259798c98267a745901f26541e0ff0533398d81c744b9743258b3541910aafad8ca21d89c3bd703cad6997f21c30f0bb4dedb48a3eb2452a0def5739cec6e6a9bac57e6e86a6cca5d945ab6da117272a66e9e54ec4887a6c4e2edc569af04f88d5126fa3d3d5500a9c0b1a4bced15bd7afd5b3fd27ff3ac8cc9d4d0d2754ec22572d911bc230835e2f7aff44f1f80f02a6f44c553cdae851da003dd18927de916c16aa769cefb092fbb3ac2ca948bb09be1a528a9c5d5911b7f89344bae0110a0253ec075dc2d0c264312dcb96d262bbb0229712b790e3f091657b538a8f027e00b6fe119100d40de8ec1bf0eb9b3f6e548e725381d5127a71fce10f907725dd648b234fc8ffcf75791bef23457a1f8155320cc643bde240fbb72d81b654c039bdcec062d0afecb047f0149d2c2729970bb0ef1dc127f06fc75f204e6b610b547bd5d8d8d6052ce7b8f09d9", "ba378b2df95fb73f33b8d68d2df9eae8c720a865af1fa62fdded320f9a4114e6c3437a830a0d7ab9bc9eee8b83a4f34cb9b526e9fe1b9f26cca63ad222b08353edb196796e9cac7f390aab5f9de3ef3e607f87122f52e637ebc52582c97d138b8637016068babeef3a9aafe55c39b08588577c6ad5c2df84c4db7b71e268270eb3417b5f5f06aea182a0ff6bd6851a84e4b1ee31bd79f23e9ffc7815e23620e97d2cf5274070e4ccfee02f32388d0da77b80132c8ff3d1c6c80556a25b1d496fef5f0be75e8e6e276253b2d62ae2dae24ffa670e8cfdd9c1f9b9c7920a54747f1aa28f2fbbcc9c08c0abacf0708d12d61bd94706f3ad44f75888d5bc70e630611f7874e5a7d4117eada174e76fae8925dd9a45938291162e72619bb733d36e1fb57815e223a905bbce069aef02c8de8360a560ad71c3777459c47b68c5c7dc6910af7dd3b5cdc2fb7e3594f40c5bf9cf23fe9734f995d9a2f235acab26d4eb16cdfac601bdf4645219ec3b3932f684d5f568a79885319ebc685d1fff014162f5adfd9868c4e387dea24ebf1e170569e4c0bf4a9aee78cf7ac57884f665f4f6b243e92d8602f9aa373926ab35f4d509f0a71b605b68da7f605f57ab23ca1de1131e51ae07c1a40b41f5bdd938b9fa5b507708587bc340566e12bdc676e8ca4982adb31115cb8ddfa8d6d987a2083bc81108c317628b004a01b71682759f99e72c", "10fc5552c2226077035eded92768dac9fdeeb64e4c8d52c1bf38bd9af1d9b45056b550cb4558b957b3b9336d042f3af54d74607368e637fb66485ceea4496afeff0627920a547c5f4b9eebc3a17bca3c77f948bbd1319515a9a45f40fe6757a734ca9ad578e4dd615f9d36ec04048d52d332306e5a042c25c3741624347c61bbc3f00a3e3b0cdd3e5c6bfee78904d02cdfe277dda55e3d007e7828ab142a3bc1970bdf56800934a6950d2926afddcb2ab4c7f3bfc8957028e648660de16ecaabdd6f32079546d514a074e37a1de9763fc274f82280e36bfe2269fe05730218043f5697ac49e86638e7ae5ab477f6c45b1fb59372d79251eaa108d6bda813e7259c85abf1648104c19e193c701d8c9ca8792251c920f74673e836408aa0d078f6697ae518ef0d166080f7803c97b2a639984b1e09046fe77d7569c1bcb99f5bcdba7c2161f6305bddc276a600fc0fe8cc5a72239b48d67ac76e6e17a9c43ac5f2f0c9f2f504261419cd1d57bcbfd3b40c63c8de263e6c96c23494c421154e792c30ee65b724dfef71af513e3a85ddeb8595019d7c3218017073aa388e3b2273a6e108e3be5ece11bcda79bd80cb4cec0f5484880be1f05e22ace75b414ad4bb4dc5af4425e3f0855385cf99319e9ee8896056c9383e12b8906c0954cb6a1255a61cbd80d06f1c204477c7239143b80a7e0235be4eb095b7bbcb45563593558e0e040970dd395dc37e40f6375e2748e7b944afde7eaf7ab8f2876585699dd77c1d5308b3693d6509a1285730c636ddcfd33c369ba96f96f46a7fe628cc34af129fa7825627411a03d76471f30dd2cf7f770515dfdad7ef5231476b36ba0ac77b7ffc2f04ec0fd3ffaed198f8b02b61960fc0cbf6b501099007fc3589528ad6202389560e031f6fe45ba913a3d6a4c1d0a8e7af6dbddd61411f852da2d61c82abe46352370eff4f17f0d2b6223bdfa648a6fce2bc1bc00098dfa539ad50370f02b43bf5ac9a5e1ccacd28eba71d0fff60555feaaf83877cf074d0fb3659ea61ec1d6b1ff1dfcf95e4c6601a50cab69edd8cd8643f64c23c25626ce97e5a633632ea45772028897916bb8e290cb95fae8e5ad4e6eb214c016c0be730ac6b62b5439b7ccace89d3fc008c6d3cb3838a9aafe621e6b015c9f2f5b63255464b7596c651e2499c73c201078204cc3af77a0459a1acc548d6be908f0802575738d075a98306227ad5b26e4dd93c496a3962c45bf70c0e28a5f7556c5868e51e6c076fd451157324f56b3620b836e51e09d607b29800f8ada9a7cdff8b9f0cef81389f9d199ca9dbc5059434021896824c1e0ed629cf0696d9803ff26ecfd757897f76ce2b2c8c85a52620940913d85ae31b0a5a30dee2f2dafee4e241cc3f086e10c8f4c5101bdc42f0b860c603bf4aba9ca3d0d7a2e28611eeeb76310671eec2f829804c", .Okay}, + {.Mul, "a7309feb68a3ac5fc5b6d180546d18913e1197ba19da0bde1f40ae24bd4a67f22dfb2b68cb1e115ce176d2ab982af6e50b08ccb423c0416f9cc9853bc289ef2f9c5ff5d7a883a529166ddac67806b6f7cff886a9bc59b91563e5244abd2d34858d0054d4b2d855b5ead30581442238efc13ee052a729d66ca9329a5578251834d4fdf313ee3c853da949b4f00a352d04bbbfe0dd8966162eca9abf5c3cef9300eca1577de35b7abf9ae27086db4a2c430b0a697ddb1b3e5ed08d3c5cf51b2d9a7dbccea6ec92a85932944f9668652b68f2796ded4796478440ce1baf789aa85affb7b10c5161f3a0048f180fbc927a08686a83e71ee1bf0ade13cdfe89ba5c4de4f5496400e60aa55ebec7aa7ee60e5f73df4006207deaaa49c43707004394c6ddf0b01c8590bd4aefec88293a16e8be6f5b58a7979bc98a8142d146f30bd0bc58c437d18210a08011644726b89f5965ab62a26ae9b0e3d2d2d12c5b85aea3b574373e86022dfce999131d4c97a9cdc435f600e7f635a1362c07bd37e2f982c54d3082ff73152204a53ca215f85cfb7f5f5e9b62626ee1643ee0b910ab7dda99e53a98d603c31a02580cf4b090cbe7f665da9003fa06a3a1cafd5d215f4e2bc365915cf001081f1686dfc3636638fc4bc391e6356ced54d4c7352195c2891ef950a2192d0b463d109a2e195db3b16cc7c1b574bcc6eb4cbe78ce7c3dbb4aed76", "7edb8b62dc7885930c437661068e47727b45d5405c12ec85d506bac19b200df98fb032ad6f4f71df5fb32cbfa8491ebb7869a8bd1e3ab99531e67bd94649054b6d2ce56a082479846017e424bd1a36e33efd482d3c3220b901a320ffe4d4056a2c87ac21c18d439bd41a06d479e1ae8948d8bf22fb0b8598b4145b10192b6e39bd4a9f510df972103fea2e483d3726d226f870ca182342f3aa7a69315a21afc219594afafe8af85800f830a6c85b58107400c5173ac03cb36bad147edbe0358b5277429f13c32aae07480d65e1e8d23c9865c6c8108a41eb1e7088688c1279429d9aafbdd63d12b1d93ad6ec3e26926e77de42a14333df3684103b7ad578f3edfae2a704932d0ad0e914794c8eb2dc9d878d98ac575fc3ecdac6645f0209774cf1fbc4f72f074c865cb6b3cf3d8d6b77172764d8350eeea9e0bbe88cdc9704ce14657c9a485d876b02a51ced3686148fde568a0e09f22e3fa69696f5462cd5658c0349645af7dacaaa0f8167ce5078e16a23e90fdac78b9ddd829e0566d96a57f0cfe8335a856c0310178db81abe62ab1e0ac0c0a462a1f76f68ebad66590546e9ef848bdca58c99d7d9a199db40b569fb41a92b57789e2cee5c6295b1642e358a732049ebbf8af27f76a39a809230295fa4578dc249f1a81b7bfd85d2baa87c66ffacef533215a0b41ba03e75ebdbe2fe3f7aa81ec5c3cd45c16a1a03aa8842", "52d95056a3519c4016c748743a598b9039c772d0c6c7e330f812aa867fd5512b7e42617fd8c7c5b2ecd2d31144ff922240b9708926fb8f0845bb0609c05e589392b49db1a0ed16cd1994d8b9b7832d8edaa6a09dc4ea99760943fe6835a5518243471add9d28b67547a70532897d929fdbb3d8a1662ec366a9dd45acfd471e327118e52074878e16c2f83c7bebc2092cde9bb75d11dc5902036d592946e430374c75a56794d93808b1d0dc3229db29b3a51c4a217223b6f7cb1486e7646ad677178483c5f5d96a6af184d04e21a9fb97b20030e99f7e7bdb2612a977e741a451d7b4a2339cb69db53f20e9d6d1326d827f73ac250d41e25f724656a3b0a76837ab4f56e233ec1cf31ff2305a3bfc9eeb9c0d92f63da17dc815ce6a6a2aa86b78ae8e14dacd555048952b0c3fb809833ab5a4da1e0b9cf81856db4b7e93c9f5c43f7bd862656ac30dfaa7bcffc4835268b1a6aab64f9ae0795e77fc2698c8c7cc28ae184c96e78faa6fd8a40d4a2ff5712e18294d57e9246a86f66011e306d39941cc60f790d3e1c4d466b8e20b9d7d3f50d72e1df0c6de42f3f493edd9d63fc820e953b5e7bb2917a94b68379b4183401dc18c33143997ffb7fbba6a9e654060d937c6b10a2ac94b433dc0a931eb40e7048f9ae57d55876fc50912eca27e796c23b11a31d96314723c2b83956624393ea47279535bcebd616c0eaf6abcb400a597eea8b59121d4dcc09b6a6c58fa9c25a6ad85abaa5d5be1951ddbb3b3267772d9dde046c319be32dd9341b2c7e75ac0e55cd0af8cb9a8e6befea9877838f1d5c26e88a26dad90ac29bdad5a6b73420fdcc37766ceeed7f3f78c13fffa99799d5eff2b6ab8cdb5c21f3ee44d3416e13a3d8ed5f800b2b6802639988b216d5148c33598881966fac1be34c77e0fb9f4c89f82d2a7b8a043f92be6007a02e3e6754d1e27c8bad83b1dc751aa1c69a33365fb5fe409971aeb3cc8b242f5d0c121cfde6d961c6193021ef8488880c1281b01445906c7e9ef647c65c84dff47eedc7215ffa702594e66ba99c53d1afadf7b0d99b7d262cccecaa0e56caa3618cd16e1030993cf8359df471f639bdf87cfcfcfb26510f162d9173017ec5d5fbb2b5094aa35fb22d426b67fab044e6cc945ee6ef4938ef263aeb9a2067bfa26e319c5a382012e3b8013d79b54f68b3e20391153a770b26608f36a1e3352f906f5bed966e8b52731a4f96e53d641e60e81dc94975c743dce5fdf03878dadd20041521e45e80ae5627bad60820c669267b9cbe7b19b761cf3ba646b031066ee5d87eb3fe8f2e4d6a817953a18ebbe8c298e32ba918852ab375dc2f140c23aa0605c9374bf7d4f095f0fd2e3195486700eeeb8b9affad87e4d2882a314b47dc02f24b77edad109548df12fe71d57f0047d9f1c00e0e6231e0b2b743aa9f1520df029d3e86c", .Okay}, + {.Mul, "-99b6578a9a06db00f77707f104369b3cf3d536c7356b9aa08bd4d19b0cc421506d85d57e90091e5790f1b3d06f16ed509d78a2bee67ccf4c21cb308fbee8fc1feb7b0cd72143f3a2a39b86d47b862193cfb10dadce8c6cd0a3815dd2e9c748b86a89fec6e68f1251ea6e1cac84aba8c75655e59f8b2e008a93799149ef32b5bafccc7d147d934b73d0a781b159db0ea6cbd1d544bc2f87eff1b39dd21a77cd027e8c38da189f491bffcb67e8e1e6e69769ff637f4d4c69dff51779988cb01cde9f8f1e46869612d85350a119fecf9a9e229b25fa53a4515441715d32a5c78f054b6663f8063b881aca314fe7afeb5cca5e8d3413b145c72a2648c38dccfeb4a868baf3d8d8f6220ffde030fa5811643301eb7a0d91a0c6e738ab860efc4d8c0aacb9e2684dcee0bbc72779c8184fec0071c4a22a9bd92667b8c09758a2a6957644890240216efbff36e413fa64c55d40c09141384183ec8b728121e6a9305767e1c88c179bcef121a2a819e63d2004c23672aa668d2d45f911743e29486a07fc667b2547949ec20c43bfc52a34162a8db85da0264c57a2e068fc9a0925deef79ed131b77976a50169c1d5bcba8d7c95efcd2598306d450dd0c92d74fdd91894732fc0858ab853aa263b6df18dde7d830cea8a7936fe56a39a9526fcf35bfecd7bdfb88fce793e1c9c5621d2b8dc0b04e559209e269da1b8070601aebe0655df8", "5d331733c59123ffa4dfdcfd42258344692bfa18837a488a361c9072972034eef5d92a7dc39f0afbfbbfcd0bdb518c368f0fdb8b60c7caeea40d2cd9063acf1335d49443d2b6dcd8f20d3f8dcf5faf2048db63ee296208a035bca87a33c45728c324a275956461893722254af4f56b84c349fd3241076e0c243bd6d06bdea0dbbc533213c8c7c5980335f4169e866f96a7d79fd45f9d14f32f0a66c09cd6d938ba228a1e650555ca50e8daca71eb74a9b24777c144b7449a4ec67cceb8820f491da315a2f7376440ddc5399de62b611a242ea1e758f26180b67c4d76961139e53bb335e4a36717608246a9c21ff5c2b9d5b37273ef3880451f7e6cb763e4928cd5b736546d172806dbf7304ca1df6d9e058673f2709d069812eb49cc256674503c946039e9d6c98de6e60d6026088b4aa721d8bd520508513840d2b6e53869262504566f697e7a38e66d1e6e09eb2ee1d2177c8e671803603bd789b75a97efc857163b86b707811a1ead1110d9b424bfc1d57500b0ea00bcd173ce1e26c3d32f39117741adadc80d254de87f4b6b22ad6d67301fc24186cd5f41aa7291bf8ed4e1acb7b69d69ace1fbc5d5cb9f8b4dae05a42c6495a464f44adcc1a8c4c30d443b48ae251420535ba5bb00752fd03f4bbb214076f18987db7c78cdfe2af84d752701848060ff549ab388e12db0a586785477dbbe13fe5787219c625ecf2dd7a7", "-37f5eb0f426288a2f3c3272a1948ae59d46f31a6593069ac51a6bdf9801e618c0213cf3418fc86019030e402b70b11d55a99796b34e37e4b8f9d11f46406f8f537eb79160a6459bb924569abd0b732908e8f34af851cd4a9bd7b326940a3d4d0ff01a2f0393c9eb9ba317aa884d34557ddc2fd39fe79ac9f1ae7009e510a90d17999a680d2cc5bbd47b7cb4f97c50a1ca64b670c8ca41ec8172b7a481592bdf8f8748f77e03c8bd56d4d9938952ff27507738504508078814675e5b633971760092b09f681416ecc291eda9443a073aa65d58f5f6e4a378a3bcb1b2fe4745188588e8ea0a33a2e2c6a62582a27d039a1c31fdfae0d2be128ac11b26ce6c7c9508c92ee7721a4a4eefbdcb288a91aedd605a0f0ccfa1735f7d7fcc84c3fde01a8425ca53f066ac6d6e1553155528a32e98481a30a592a55951a8458e267c8400870d518751183465d2a2843a0bef922ac94c24db84799e4ce4e75f5b382e93229ba5a7a819ce386682be6a6a29e8acc96b936f83e5105e3c59154e7f6dff599cb81d0fbe86666127b1cff776811f9a3b9132c6a693b3a3de3bb3f71e987227a3d8a316fc7019abdf03435cda8c96d644d2f58ccfefaff0a3d2ec9eb90d6599a02505ba980c3170c9a578c61c1c7ee1ef863d8fad2983a0af3f932be8fc9e0d00c3a6971dd44d7914a3870b37e162e4d674049258b7d66305280656908df6b7b015ebcefc1a90de3cc8ca19afd168e2cd7d225db3abdf2cdffa83929e4c6e49081b1880e64b1777eede80cec26e7e552644dc52a760abbb90780a08e260e45bf6cc4f43fdd2e6336f257d58e02533956cb6483c0e699303628f2b33edbe0f714bb4e3a964bae9a5803074a46b93b384037027271d58843b726a0c5a237fd1644f4d94f2e34a210bf64a8b59e1b8eb88edcdecf6c4b32c2b95b96dce5c8b52b97888ff5cecda3477a385cce4549858872c35c8de1ba89bd0af76e9b5cd8255543724da2567e5875f6ea30f00f542244ffe214b2c9978f855f73240d2d5993be7c5c580c9863956795b19ffe6c0c52f37ed0d3c29440b1c0e50d95f709c81caa43174b893889cc23634073a41c3d55d0363e4713d2193fe9080abb637bb3ede88f0cc95c6c600a61a6ebc1a0955bd465a36fd9ab441f7e802e846cbdd5135ae7f4dc1794f6d7322577cbe413fab2ca53b9b21057a1741cfc9f6dc5c95c21e5011837767f0c9e18ee1811ab74c6bd3566942a64b6b06e9aee4a4df10eaa92f43aad22dbaab7deee72d639572f747cfbd01c7f3f749e45c6a48ab639d73504655eddf6983feb953dec49c39182e02fa391ae12f10e94e1c2187b2089bda62cabe2e73c2e19ff1c67c24bfabdb5c3925c6a0c0d6b8355c159d822c9b618c0643848d80aa332bc17f3e22c90a83e5904c512d43f6abf1fa634881900e987833190a394c8", .Okay}, + {.Mul, "5516485595b0cb80fa5a8564a1af2cc37a2361b239ef5f734779c6e247f791b588d3aeeac5acdd7b07aed14f8eb6e43d82c08f73723ea6f31efa57565b088a682c79c61a54323b3963e13e7479925a64bcf303e2ffcbbacd848d21c2e69e30b5af512f31055e063353b2a04f2641b182f04142415cf2c71c8839d1eb93654b019813c24b6813056e6f11dfe1ea86665870772357ec013b5616058616810d821bc2f90d327ed68f0b901ee5bbe342771f7ff0e58ea8a633e65d6ff3d94a579a01f935433cbd1ec4fa7d3828b60b67669776ed828824aadf300d2272ce2a10267302f450b831f88d4e5bc647e849b954e02a5c0f653d66d4c477cdc1d21f7924e4b8fdb35131ba1d3cabd94d7ed9658d24b00934d7be85cbefee73e1c39263fe2b37aa7d912799b1d67d529939394204ef4ee741797504a8d5e795f0e16a7641e7af2c107f3eddd7765a4360b3b37b5fc92356e57e5d21bcdd5b54b6fd3fbba96586169ff77eff5aefa12bed78a350b2ef9c2c0aea2aa04f58ce9827391fbeb5f338037925773befbc4e5d9d06467820a0d21e9b25eb0b7528429eef68aa9bb2f5f97b7cff5efdccdad373506f088210da8a076b75ea94c30edf474ea655829ec582d11e7d279e3329a067019624d7d3596dda7eb8f96d828651f8281b57ef7c960c2f767791942d9217daf041c2050d153064a05f9cf33c82b395664e5939efa0", "a69ea8d35ead1208c2bd95869023a903d91de097fe0c3a669e570b3daeefb6ea2c39a78d3efd41fa16db4a13f3615ad30ba44c2995e514b5a742c5ffa18bfe47b06163982e1468fa7854db63853c915550a9c1abec09b17afb1abe7efa96416d8eb8cb647afa98c2d19b039faba1dd9260f5a228c3b76974a07ac1f686ea108f7797c438659e15332721cfe8d85dfe05d3dcdf17b01e0c39fb7fd28b73a77c5eceafa455e6c7de2f1990e4d39ddb444f793fb8dc12834d2c4ab6c164ae9bb65bd2135c3cc4ddcee4f390af0166fe0a4b8f38436618de0379af7d44ad1dd71e01a7b24a1e485e369151854edcdc053e6c253a0f591b484f6bd40398895da56648276b9c8adf9113cd971b9e5d069f14f79706c4d95e98656a646d49330a9af687a1a8d074a3312e653dcb97268f514b197a27e62419488dc063ec638da46bbe7d222358d5c08f123be5c19fdc711c6eca18a6bffd3d9e6064e539912994a57773c8d07a30e7d56099c9467c58a0729ca0e238eb640ff3a7ef4a6190966c7a182ae9900d5240b4613969e9ebf0349f3949fb31ee5fbad6a8b2d9a1b303b2e423a94f8be5210511091c570f3dd68482dc86702fbb2fcac78066a926fd1b0b513e7bf04298c8ce3d8afd0d1146dd6b0126fd992e71018f8f8c6fa51c449b3e41c0997fecc20a35f1e1c37cc2b60d8c1de51b3deaee20f255a356bb2cd64f2f71b5ee", "37612ec5043084766b84d6544750c48d25316de13794dd77692b2abd770acd56c3828bc69e61fa6c8fe5f2dee5e4b58882a094497c1374edb5998af86a04df929eed120532c859c60bb9d6a6cbd3bd85b89f14388ff649a3d257d7e971e60e03286eff6ac5e8d64b40a72074e9bc4f8f02240da2b110b3796195a7fd64c60f0f4fffecb4e5af3c3ff765c328d4d1882b5aa5f67a9ea596a7e7b2d049eeb29f786b232e191b0ce4fa2dba57a0a4643caa0820fd368dbf68d7817285102bad6d5cf30138eb9c53887d5f7e72bd8ed8154848c5839ddb63b30eb254fa52d04a80d4ca72fc8fc574fd21f150d322b2d726ea1ce4675421eb3b3da95dbe850dd44bf7e066f13b9276dca98953690cfbd52ce04ce7750bbf4bdd236f9e2afec54ad191bd0fa44c98d3cde8517a11606b70b7cd5f3b418fd3409b59f9899d1fb59c782211c9733a59d5eda65ebf71bbd59c0776b936201f5c188b6f2fc9ed739d5ff89dfa7e5882914526ab3053ae32d1a9c3c15ece12371d56ec1c3656d93f9f61ed478692ab3af1fe8aa5c4e500abac9a789159e44b793626dce9e4281a66d00e992fb9ea1a3aedb9c44bf0c29f263f04b7e2e1ffbbb6fe77603f382d326d9309cde39b6b8cffe4e2d945b9bcf6a96cccc90f233a47f4339ef024010b9afdc5d5a2f019fa690806d19fcbeb4be5715e46e5f32710533fe5409e4a0f77451dda036e95e8e373dcc861d48a3fbba1b8257048ef0c03215a4647eef3164cb42877529b31044126026118ac7f57362a8a5edd21446ef674643f0d148de11cd82ec779b1b09b841d829d8bb448633a2baba7a8646b1fc0abbf709ce0e7c592749bb2af881925e9e618d0afb4652618b4595c403f570566cd2549a32a394ec4c170ab79f54dada9df729c9ea262c80442c003353199eab290e9341c0998c73ca9ebc0bccd8188723a69cf1661fa8352324a1380bfbcdcb7015c8640bc79e5bb9c0cf18f63f8376ea580bc3513581e134bef62815fa055e6a7d10c876438bd2f3147facfdd88329b0a69d084914151b29a4fd3208525a55eebe79e8bb5e74bc8a47074d46f752c7acdc3432176bffd329052bbd2941f95a84ab1ad1b54ddcc3c8083fafe1825c0d72e7c315a5e70bbfa6a4628bab38a57acb391c3e25c27d2294dea22c482937cffa85e6fe9e2ddefa8c30456a175fc7d6013a0aa92e039fd1b0dbe2f68b42044b107ddb26d2d7285c253b4e70550784ec184466679b483fc455b6a23a5d0336369cc3dc197fbbde4bbc739d1fbcce486c47d3cda039c31368aa0e025ec8dfcbb4491f2d5461196d3651fb8ee621b1cc016f2dcfeee3df25773b40e8bd9a38c65a0cf31387fd856931ac6c7a4dfc4c95d202bd0e8d5a1123b3c7c4715e8f815b6a6c33b5fa10a77eafe3570b907d7bbc734ea16650275b927e239de0fe8e6c0", .Okay}, + {.Mul, "-efc0dbcff1eb4c76dfbdd3ce147faed7292b5953cf945de1b42e97fe2b235ab11d1925c3eb6d17934ed69340896cae8e754b3119dca3dd3191bdcbc5a93a1a44f7b7f0ee3b95337ce9b816f29e28d7a0a47a65c7039b594f8a0745acb025744ff917b4b1322865175313c139ee854ad18d57131ff5944905ffe3950b5a8cace9e60302bf6619a04260044e9d1976743bcb068bae761a36e31ea93ed29641ac0564300af5ddc1686331d59c6ce522df56bf53d8b466f4f111bdcd390a93bc144590e577e336be3ec380926f3f91acdf54454700583615a6ad31c6f4a88e9a41e1e6d440cc2ec945f33ae7245b91f5ba7a9cc77de33ae5f811908156372e2de299d42fcb63f4073c97c880bf427391d58c9249ad3e63e80df01788368fa725bb606e5e14625dac94c3e5ff176175a06cb6fef5e5fe654179c3b81e8f02a362cbdd9456e3e3c1b12fc63b8d21e671d06b003f8fd1834ad407cfaeb9f9da46effcbb5197e628a175164c01a2a3cc2bf954e76a90c425647cb5f3e70d01e6d63ed6e338f633893cc063b834847352f8215561339f5707f56edf3896c5c650a652418bfa2f1e9a822cb4a7262e86e83ee0cc2bc80ab5fc4b431f2dd98cf0943572c67393c2ebfb3aba28901dbacc16cebfd51213521480e0602151620090bebfdc3e12007c4591e2fd15cb0f9efde03281a4c9370ed09bd90cb87f195cd04eb577a0d", "207ec700f95272ef2f7edc147cf7a58f39530fb3c57000b7885f56affdf56a0db0539094bc38ff6bbc36318a77e18b13b02cc5dc97fb454d8de286143833eb0a85f5f795a5e662419dfac904fb86b6ec9b950a3f4798d35329301a86f9ebece124b90748512e8573e7549a7b5cb2097965a758017b88fe9ff6a43a8b10f94f12aa7f3d2bf4f5a7718f435d30f2cc54c59f1ff52c259bf494844106b23633d4e0825c65d52c614326747a9dddcadda54acbb9af02558b2dbc65db2597366f8fa08f8b4cf3ac505e2273a7387b37ca128db54c459369d4de54a3d5a0c826d8fe43939f41b677ade664d0c9cb8ca62a744087710d2919b9e5223d4500917e92a4f0b9742220cfae27a04810dffdd4d83f4992d7e3181906d872b528240bea28a834e4a3a1f2bd1dac70c4a2da524cdd335476189af9dcf8b3592ff8d938747533a08862283066b09c6bd1638478dd0d2fd7b12e57f820e3655a2a35b03305d49bf8ff1a4a4de1b3497f8243c0c6cf8e9b3bda75c76416747ad7196c5cfe07f6670cb2f51fa6dbefbb3209a40601fb37234367d85347310b855c3b36342b84e61e345fe24afae536120a093f3ee3b3505d4e376401b43e28329498006b1c47d3747ca15ccb6bfe408601f2188ccb525d7feadb547a325e98ae7cf6867f8df7787725e13ca278e1cf1deee991ca0433968a952026024e7d4c45fb11069bd7973351d3", "-1e6ed6c602f4eda3f53ea4d49cd45ca9b9083d307d6a9a334aad0b8c63b119204f22c8c0e34f1879adee9670d2c8deed23f7221f1dd3aae01e48cbc4335f7a757a1952711289b15a9dfc1f850bd3d69651ae3d2f448498f4b60a24278d0fcada0b2084bab40675f464e2a0b3af1c380c122972f7750e7af3daf59ee72ff544a02a2a346fe0b8a58c26dd84572e519d5c1c6f0d5ec99e2f50a0283fd2b49f17985a00fca3c3c3f3d685b4cc82fd4f8baf84cb5e72589014eb093c2eb23c05089ff4c77d75dcaf7ff120928f6e7447f7c6e86934467b6204fb9e67f2e2b300776c9a82543fc4f0c82e10f9646e6014dfdbb7cd09b7f3b8e016688ab3de7cf0d6223646d2263a0b19c6efa5c8056c576466b344d3b778a695e9f03debce3ea368b1b485639f95744db777360ccd49cd8198fefb017866c7e57c470efd8a1424fdec0fbd5dc69d36b02413a1d0ce2ede51d2d3d0d994a580cdc7242495ddfe464a89da7db6f7149902d4e270203622e5748fcee543d1e8abdec0cfb843e86460dd959755928cb440009dab7fc4cbd8e77ea509f718ac8c3a81154fbbf4b935fc7b7b1b51494badd53c51c8e385fef94d2f53df2dc9a44c3c29c9165ec5c89ae4690dfa09240f2d9f75014aa56a77f556ddccf26e0f6deaf4c96ce5358d1382e13ed16acf533516cf13523553c821b76591992c63f3ae7d55f1d64d48574f84feaaa2bb8e7d64205412c39fb37e75beb6b3b86e3778759278e07e1c7c7b1e868d626997b66bf8eaba1a7cf832cbdada08e10fd13a859bb9dc74a26bdce35215bab5fc03f7750a55c53d868849c5af85c8c00e6c03249a764ce6cf658ab49b03997c74ba05539e46373b1684e8c3e27069fd2409acca3f0eccd5aa9859fd1c6cb48e998b70df2be4e79a5073d7411818f3488734865828a3e35f2edd964219e7d5aed8d0978d428bb26d141b922a17d5c20608a3ac65c9017ace0b4798c8b6170747566a36d54352fa73a5e7ee3b03992032e476568ed93e753cda025cf05a359c75f14edb8726fe607159cbc2d03b3769d0021f5fa3be5d9e8c8fd51412fca35aa205d17274cb0ecf16943d90c468912691416c1cc20870890fa3c27af5599a8ab9f7ac1daf2ecbc0d5965fbad3009c887ffa4453db45c94f0d63ddfd86eff604fec280095598d097544c411c7cea15b293360e4ce6c084a56c19abb270939b7a23eaec15f026a7438307c717ea82fa8d8b2b93d60d4e8b2dce835f72ef9c544c171a55e96a4347cfc841298070bb105aa1cfd6548a75c7e49a445366ec5768453c0417769c9829766d8fdfce3eff00ade65dbd311882bf3e5f8508b22977c9b39950c348e48ad3275c518afeb23f7ade00310c9fe39c52af1097d442b3f0ff61b6546a1a3bb272222a8acd5c723daa2661288f0b0416b87e9c899cd64daa24eb5b7", .Okay}, + {.Mul, "d412cc0887765db25007f825045f31a5f551328d72b927a2422ba9014e9b265c1e340a07aac0a57b3c744625b8ee333e0a9524615aceb0fed2522715278c0caffa46d2063d0352432c7a52c21883968aca502200494ee9508c577ee380ade036e9d3d9b591605b3fb2012b56425d374fe4acade34561374dca02c329a0c2c065d16ec17b4873c111706ad5b73fc6e8708591e3a133867e428e5e392ae253fea9ea3afdd77766b01f45988a31087a99f381139774f3e889b68576ffa297c5b13df1342401e2c3ef8fa0c5bcee7bef25c62d538a604ddf9b33af779c9d832b15eb6fda164404fe12ffe107243885440fa5e5a5b5df27bd8689c5af9c35b7702db1f50d5285efb5148dc64558209108be0fb1f37cf0d26cbd2108b2288c18ebfd224ff56614107da9c2b13b6f3c6bec56e3b12295f023a1636b6452b8603412d4f1d1ee19c4a091e3aec9d6cfaa58e7d8a84794bbc9df7685d07277c128580cfad5d7d35b7150068019b832d517a116fa6d05fee53b9e3736c44e9a96f0158b6da7936b7c03ebf12966902d444c1c59bfd5e75d040dcc1c7f5f98b4b6e86dbe42ad3490c984638492fc7173b605f4aa9796bfed42f10b36b786841cb76f0e7927749fbb76f963208a53f646ec3d57d6cefb7e66e74ffd8db539220f55f55aa0ad9b4f3783014586ebac6bf73af2367d3e4a34ad8c771938482113618c44410dfcb5", "a91b079d62116433d50a0a14552fa55ee39d8e4502bbc19124d9fe1d6fedd99f5ed62969538417a5bfb579e49afea1150fec316d845e7a88593a660d646fc9ba8dccbe1148c7d3d3ce62d2d470c48dd71a945be2286ed005c132b3b6483fe708e743bc9693dc98cfc8169522f4420d729a1352d9ccaac15c97afd70abb19d170829d3862a28400e15da5d98f8fdfb2057cac0694cebe757f1053624c063f48ca08be042455e751f67d291fcc994a396a3c7fa6ddaed94cf398b457d52dc46981ec9c19fd8adbb959a14cf91219735d967a8a2f5d505e623b8f98d23877b1c5577f91d77db1764b8b36243f61caf77f00ed5feaed20ee7258558cf99b54751f98f43c5f298d1c08110a9ea38adce06b9df8dd0bb8a453776144f4c5c5fdfc7546318f50942abe7791f74ede3b4ce0dd72115a178f098a7f6a8752a55a31190aa46054fa0f07ff94da234f3cf16dd6019cc92bda988dd9dc0c67de8fd76243521009eb8706d41b201db25387d1707ddc7aa8745ac5da555f5a86932167b415d2ba5ff52a153c089cdf1d305699dd6559e59ac5f85a063330e200933237f53817ee95f0e9b372ccb7f35464036adc10d8bf055d57d986d84e3995096b8f97e2263994ca1263ad273aa93f2b4b670421020e09d68c181b6dc68f5be0fe0ee8111dd90e98f4fbd37be9b03ef73ef8e764e3bb857289a7eadc98d655615a6700dde69", "8c16ccfc0aac64a301254863422bf1ad06cfe8410b899e00863aaac58d92c0d2fb60c423b73513bce208a253cc591c8fef9d8b735e9dcfba057d6d2d70c3937b974fc3423e0a22c56495f58586a56ba1b8da62f4da9c4744e52c0fd64a88916f019659202828e2a74d6667ef27a9177a94641ee752cc30ad42618a1ad1f061099a84296fe851bcd153c05494ae650f1d22a41d3824e3884bed9298fdd21712d65f63ef057c6b93c36002aa80a4af0866fc3f7034dabd21b602ba69625f1325f2455bbaa858483396ea84c41093b00f4b80d3cb7e25414ab4fed1368e94a85ae07746ff30fd27f7925a5818af22a28128938d384a987a6680dba9d32d2aeff86ffc7b960fe05c8cbe0139673dae2dfa6b97e456a87feaa142f862c9df352ba1e54bce07ce4005a5a71c8655ccd8bbae8e05153d08a33d18a732558abf9364065f7be94251c9afab70f68fc3ce0cb4110632dcb4e4d3cf74f73ecda33f9e497f7966346f9a6b0b13d39459f0444869716fb1ce1358f5620b4bc7d4927d28efc656bdf99f8b6584b7246dcbb768950ed896a066a8fd1ccff997d676ae584696645193ed960a727649ecc236502bc6209b4f37b6def20c40709cf7b45403026df779345919ed2d5f661a0141e7a0a265a958ba2380dee1db59efaac109f91c26d2bf04162e705622825d599be6a15266a8c1ac4af1aa57f7c58671b95e177a9250fb3508761199a6b30249a2aa16a3580cea9cf9a41b3029ce0d30362b37c021e597b20129decef20e360afdc7ab6045ce55786f3112c1f6f45fb7b7afef84cf1a245f0ed0d03f89f5805f73b2fb19b100d202baebb6e509764e36ab44b506d2c578495ac15b5002b9a254f85c98e2d6a761863a57d26d9fe8f1af08942a271b54c60c7c6ccc9e3585791ea155434536737cde47e6bb91315942eaf9bf175e907a0b89ed5135e904d7e2e2ea3037c09255b9884dc816cfae61737a1c24a6507aa28f2605769eff6bb16d07dfa9527de728530e62ca1de79ddc8687d431856b84fc7757c360cc401a0a7338b08731cf8ab14655c78b4f80bd35ce798df2e9494b112aab2a623f153ef267b9ae42e35132f5e81446f1de576d1e62958d19b5c0f784548f7244e928f058ba601b4904a6b0cb4953fadbf942dc7c792b173e2e6981ed809e5f65c1fd51488e7926dd88ce4476ec862bdc536168d58ed3beb83fea96464bd69f0b60bc5f2959c91fd9361bfcdfef355a3514850fee97bb1496f5cbeb070df0a82ed0cb8b06ce7a7c8bb7876f6c75975a53b00e483549817f6644956fa4d5a2e32af2cb3eef0dbb8780715cbceb6b63c139daa04ca1f4476b5dfb3dc9a5e7918365e039e1d3e4939aa9348dcca1b862420e1002e38dbdb17db213727ee2b6a1ce575980cf4ec4916685905f16ec389a845aa93952761292ddb0bd5129c3d", .Okay}, + {.Mul, "f76c17c7cfc4bd578e8bc2bd2c1d0760ea14c56a371d469d739371d1881b1aaf92c26891df1706c701007e9e13414bc4e19586054aa81476efe00ee7e2e7410c83027f021434f27d2df38aefbf87cfb580a7311648cc2b7b3915d540dff8cc9b5a03be3272f78f4fb91712113ff10108238e21eedb852389b0beab851757e9e7b4836a5a2eea3ea36a8185931e9ffda2173108b6336635078cc851ffc74b206e4c8ceed3ca7b7ed0be2dd1e2db517e50cbce36acb74ab3d9a83028d9f47a4d964bba3f76d797c5bdcf2b7f3e0b524ba48db50a924149b50299825d7acca0bed065f808e9ab7e43dc8e4770ac622a7120a3af5d9256472b7130683be69d5783961f2be49cf58ccbc0eb900a634edaa3a2186b99a2ab898ccc37b5176bd75c8807b4470cd2b5ccfa82a0e4e007c7ea9adc1e38856f1bd3910529d2d9d4b7e89c1f9b83b7467a6f3fb376d14c8103c6343068791f498b5a8094755bfce73db5298d087911a6929b4694a5b2578b6bef95dcb425f8c3c33bd25b462b654b05a4e251d839b969d5e18fd3322409bfa30ea751caa7af6036fa2341681ee9e3e5ae8ec9a898d1d65ae7ae33f167df983c1f2c8364beaa33d236761333a068ead98d4a2f7af28df02c4de5b576373443c69bf8c9b2d27fda172d8dc5714e407ed61dd75c127ae0b06cb431c3189359cbca9ce8dfba526f541fc7e797e202ab3ba3fc1b50", "308d00d5e8da43dad6e0702fb0f98053e6b2881c7ae5785e39a0bfb51b2e384985bf58a63fca81f9a13c6e1643b1bd253f9708b72aa17ee3f6c20093162d4db3d16939daac6fecbf0ee9da617982a33c7b6a16c3ab6c3e182e639e5c724ba6ac08dbb4342cae4755abc1ee0cfe46ad32820dd9efc487b08f5835e632a7fd09366231e29ebec9180125097faac73bc6a114ef7d0b994581f0a1cd60db1ef0aa3b982083993fd17c8d3d1281b5a7c3230894dcb6ec53ef8e650060476368e553f325052cbdad2845493abda27d9465d6748bb216ec6aebf0d0b5e74d2bd06ad946604e36814c37bf67aca3aa8f3f732f2544260d9ad3d1328324b0e88d32c992ef12a21c0d677c34e5cf36b89ace2ca91ffe5fb626b22ed53149de4ae8b0a1ee749b12a66140d7eaf0fa241a034706dffaced0fae5beecf25767333f8d9868469029b2114a2a59a5ac32de729c324302c2880c712ba0583cc6b4d8edc47581755f5b3a6bb3a796790cd729f31bba0b44b08f87cfd6b8c27f19d098f2ba73f7bfb0c4b52d0762a9cbae4a2921daaa0facd9a231d55c04d31859148a82178c5a7761f3eeef7f1252d91e144668177f82e8d70fbf367776f92a607d29a9092be2ab14ea215851b5f742945892915468b37199bc394bb638870b44a1e962143cfab52ea71be4ef5f4360bfaa5bb3f6ed4d8841e68e86dcfade19272bc29accbfc849ee", "2eec8bcd4dff054ab3094ce28e6476a7e54b6deda12574b509e34d049f10356c8fc30e838a29d6ecb466282a922c00ccb4e202a9fff7aec4d22d7c6440de7655cde1204204cd7bc78f6b89ef9789feb610d4dc79fdc3c9cc24810ccc1d19e581faad7b850049a507bb9aa3d8885eecf65ca02575acc2ed476244c9b8f0177938e9b6c1ba3640c1c6e2b8639fcd0fc2e621bca9c62cb88fd709f457914fc55577236b42fb75a9ddd1d0bce42eeaca87af8084833798b6835ac469ffb6733823e062936d99a28be157df8f4e77e5d07bb53754340dccd9d054d52914537ea657a3f602f4c8d39afc21aab4cb8d5fa14afa253689439e55cf09d1ba933e386c2d845c44d8dad2e4bef0cd11f31e605f3732b1e3ad980b0de5cc883c5a3ab82d9ba5194bb8813e50ddb198eda616d0970a44acc68c5e24af8da2fdcea10ca03006ae7c978eda59253b41ffb86d7a22349fbadf59674a426522537819757ec3567a5cd6c3d2c8e7bb1559f1e0ebd0b69e4cc2a1a4e7c2d100e5dddfb26b1fb45296c5f3ec3ba74aee1eaa195611ca002fdb45d2c259563b200671e665e914bb8464077c79b1d3b68f0328be3e639f089ebfee975502318b7730040181441d3b5fd521d60caf70ef63e431fa2a097b49fec9241a4b3e5496aa511675f72535cd08bb10b487bc6a5a6b4864548c40fae6d75614479661f877b3a5f0c8a77ed5fa6520e3691af93679fece0750585bb50e07f1efce163eeecdef65745fa9653030cd705f8fa468a905b192fc4b36eaa74dca8ec6032226f2b9f39eb1b5eeaf9d93b61d4046b6f9f3cff84537f371dda80c5b5c7d63ca7237a30742990c648117ac767c2c684021a378e4065c725ea93edc062a8bea328645d8d884e388e2e0749364e6ae3dbd09064f37dfbdc82200c75b6c7fd404f5eedce60eeee42536b9b679186ab989d0cead7bceea298d323f485aed29b48472ec2e4aa8feaadebbe555f5dab8e0828b93fbe0f439729f8da3fef3d41be4dd6b686e75e1bde4b3b50d06854d8693c2b83f5863934994f9f04a0ab30ece7a7d1a034cc0e4017d6a2fdceab2eeab8d762c3d948352e8ac89249ee079cbbf1d1335e36a3d1ba9a0918f03e63b5214a3b47e0cdd8025cb270b8cb13297609b593ab3b0cc66e1ec18c974f43d6aeb9a1a029dec22a30ddca3ef06b6799a1affb8b365b88490b28166f1f3a9aa76ab0c0ed19960f5a5957c616838948946d86b8f7cbc7144e16e3247def70e58a3766dc400b1ba6f290da5e38e1d12dd4a9ed61f4c6aa59dd17ae897dc53d2a7d98d3c69a5a766e396d62f234aa2649d3a75b42f5b54f1840c3dd6bdbeda8d18d57c64aa0baef4912b9daea8014f2e753f23eb65d8b340019d442d9221a877ca4622bcd3937ce7fd63b2b18c2ddf76f2153f54a966cfc428b37f197d9f344c4b5eab3460", .Okay}, + {.Mul, "9500339bb6f5b769b350008201532bb8d3c8c9a8b415b49d0714d9dbdcba0fc3cbe8c28b71a54e20f9dd1b21774af81392737772d1b13b5e4b005ceeabda66611e7d249a4d3a281bcebc6bed3a4a0eea24e1c6084ab96d74488b97eb9417125cfff51b5812022e868b16cdab32eebec229561a162b7f9d5bc69356e1331631aa896427dda3df10c6869c52ae342a6fd581be0c379af4f8a566a8e38c8a9086d21210dc64c37c720c794667ae68a0baa1178c16aaba04430e9807d3e83ecdef56b948966760ac052fbe809fcdca62e31cfe6e7eb236e6d35480eb5f6b4198d096bff4a51561837a8666ba5a9778ee7a5d042286794ee7366b89c57e3a5dd637a4329b287fc67f81ed2c94f9a2999d42a22d60ed34a0a6b53bd1a8d19ec163dd36554baec23f12db3bdc0044b5748df13ba36519fe39cfb8568fc0f6c68e999e49485fd9f0625d84ee5fae0b26f690b876008685c016474b48e946f7cb92a8ca43335c784082a20d43d1bc406604068570112b56ce2bf58990d4f635a68a2a2638281d068c01518f94b648b007ced8c13fc37e8b0f9a5705d8b5aa9e4be647e986ef81d92e01a22a1e54af135d70745acec4794a8e1dddb2669b1cb4261b7c674e79762d80d22bb22544d139e3b1f220a1f98915375c4d93ad1329c9bcf54b00a75b419734e0d691d85e0d50dc92609857f9ebc1aed5ce4ac5962b4e0e928af796", "ecaa81dd161516155545c95aed33576888eabd35ce957de9e59dc02bae8cc52b2202daea2971053ce1b7c8d5f4eb541efb9324efcb97a8956c915eb8b7156aca4016e201d7b80d006be853deba94becaf655b531b7f439a18c1993384dc04bce023cbfee595e1a22160617532f82bbfb31445bf1db66061ef5e301260baf753c7fcde8a564774d59a1e2f26e924650a1b3db60ca261fc19e2d72d4112aaff9658149ef795fd7cb505b7213fba72f04d1cc00c6605af900b2a546844412a10c858cbe7d7b57df1a60482285ad69cc79289e8322c38685664948e8b9933156224b4cb3a390b4f37f84d529de52d333691129afd30f76ebe45fec2322ee3d25499c854ae028eb131b655bcf2d194bf3288438f69f0d83414e306d544b4c61334549a92280fe6f80dd712f17fa007edbc18e7b5fab5c9b797e99cf4d51ec0c3e9f907c5f8a04faeadc0154fb639ac9016bf4013a6f0ca4bb494ced63bd9798bde8c5028996c6d48fcff0549a2bcf2da886b537f123b07f2ac7b65a2e67c2eef9e5a838248c1fc603cf5ed366cf4bda643d1522759f090552e5e20dc94da54f4f4aa7b263710853e327325b61d91c3ae4d71ca53ba1aedf9023b744b3a50f7e303de78e326dd7deb0222119e7d10d43b6ddb695eeffee9c713099115626620bb994cabd8dcaf8f304dfcb75983d50c9053e5cad84bcfb0e8ad639f920a454573d987b", "89bf6d4b9a1a532e0d9eda003e3d965667530078eb12d4b6d8372a8b90c1b34699693b2b037937e923fc40b6d6dca9e0f8aa0b3725a58f4ca0ee91131961ea56f121202fa7fa5a26862167cee509a0842aeb0ed57702c202e205e4bc8a264162fe57e1ebde8aa11789acc4ea9e5b50d9e72b7d942a101fbb7748e3cc4f627652f6e376bd8e4385831b2481ff406a832caa079aa029f5f187c47702072dbe37e2a5f023e495369d4dc65c81514497de64869ed77c45330603fc5d5ab8d626f40f3d2806338155ac23effdbdba820bbdf1404e0cec4a031ff70568f2027c8611e7d8595bfbb1589793d2a5fc9c26d00c1c4b6cc75de81cf9b5dfb3f753728b52d18105c81f3a2091a6f0fa2b8925091246869b3be43f523b939ab58b6554c589e2de44c9daa2f1212e6eacff2f1f14a8216fe709ead2a39996fe12a848fb9ed85f8aba826ae2a71125db76255c4ba487fb58f5cc545510c3282061272dabde0591e45ac224febf488ca35cf1f49af30514bf969ee3899e71d85126661fb227f270762ce70320ebc8c52ef31dcac3ebffbcbea082773c0e487113816577db34e6a4ba746cd3f80f2898fba344e380e1cbeb55c263c8d25ec2540bca0186874b383ea244833c6856eaae76906d8d5f1b120c8357848abaf7f491a9a8f80b46a662c9bafa2b9a3f4c026d3096dd7cfc8c21bee8ba03c9f74236705d3576d6252fca26452f91e2ee05d771bdf3c903c28655d29a0fab7514156d390307db0de1d4833fdf606567b67e3aaac82e437778d5c3b9ec64363c757b146b35c9b2e74405882f28b2be862ba5819958898f57c2dc873bbb401d45d33f926dc76a3e1be39f152ffbf4897dcda75afe49e1960840b4232643ee0ad32075b37c2fc0e95968c4c599851c57b91aaa28e1502767815f3fe14e01f80767da1d1f7fccc2d8a53e98562f2aa92c4414f607e7158ca85b97332720a6123de031c6129283574069ddae270a8129fca137389993b94ca3b536aff3e9dc9fde212afd1da8fce732e71234b1b50fb842fac328d146c2b0d59dbd351eab43eff0ea88f07c114475a83d8fc63f68090a397d7e2539af2907b44f400662641c881c111dc3d4501d39d7da82fdad85846c4b7536b2e4fe67e83aeb1a0ac58557013ba5c29573e17e0ec5d0e94eab93bb30a94ffadec27898b8e6a312cffff7acde644691b82e9e800cdff08c3579c37928366ff36d93a19ece225f0e6564b169d766627da57cef2fd150b7fa2c3477d7c5bc261bc725513a857e0328e844e93955acebc9eb85396d16e5a2f52212682e14d63b488f0d4faf6b87e6743748ec546d563bd1adf867274c48f03c2c5459647e76e05fe07f1cbe4c5d914830cac2ff2dd58073aa2afcd043c53144c3a0591b63f33f5f47a0f7a242024169552f6dbe1ffd2796f7b1305f62a27be4840512", .Okay}, + {.Mul, "c447d9242e9514470b2ac6fc79645e6943705e41b17b7bdcde89157a5091addf8e4996a90b9aac90353871bcdac594a8a8ae626fd1bcdaf519506c050163fd29e57ba72524539d361630953ea9144e4fe5847f610de6da56da4a0934fe0743414913d647b409e5f5ddef835f902454a207c6171b50e2c2d5db4f085d96f33f7c2557755adcea35130169313b3fcf327bc98fb799b62de7b7fc62f300a6c3a9b5520f5264ff8acfaea823b636feec78d58fd8cd2bb4786dd2c35020173b060e6f0eeeac1ea663c44aa5386514b31eceaa7a2cb0ab363aec154933be4bdb90c322f292cb68de09e268c11d002cdcff2288ee18cd89e1b9d958ad879e4a7309fb7b52a5cd5e193f720cdd909fcc049bd9ea7d094d56cc65c9208d764ef935aca950fb119d28867f7cee782830fe264ec8897642297e8efbf525053ada88bc3669d3adfce492ceb490912b9ba6d61f66e3788bbc11ec37a7990fddb88aadccbcad04bf2422dd0e81cf20598329b9906c1cbf3c250240b9e5817b4640b7906a41335ed4c3554450724bf356af36f47fc4c50dfc83935ef7cd872076d334521d6ed6f8d27f4aa207fbca00dd9d87f4c40d501d5bd234724e2957422d7d5056b49982563a6f143fbc4f44019436c4e3b8f0c11c85803b05f8a0901102205c4b99db79db427a648faaa73b8e7d5fcc619b8e0b87976f9aa9d212299806b79b6ba0cd2511", "91f1456e41f89d325204e3015ba2870f5792914758029b322618bbe2d0fa4658bf9d69bdda56c72ee91bb1d20b901e8cf6dde11a27b4edcc03dad2094eb16a0b2b2fb7f78d333d0d5bf37ec2212b97882f0e5eaaf31bd56ebe63db72b1bf50edcf7512caea6025796666d9d4e092c7e821937b0a2be2e883d5515b9e597f0fd06c5ddaa7b44b8d229f41e067cb4cccbfa1545512e087b7354729fbe13237d7b64b843589b00719b4eda1bde703612dc77ee747e4c8d32916b05f6642c01f432e61eaee5b46cb1395ea6501401e4002ac6555d6891c128a9e16b8f44b8c30b8c2a679e397eeb95ef161fef3904eac11f6be868ac04c47c1436f2837662ed3928eb22703fac4d329738efb9f9f82ca558489a2c6a0ea333b6dfef67df18c2813b6cd675b9cffa4ec35b94be47bacb651bd265f96ed5dd6df0a8dce773d743294205b895866efef4570c5c4f2d6a47304876bd42b052dc654cf139759e7f2a40136ae7808e47eec048d378793d6b87f42ee867c22a284ea20dd0e570c69b23e7f615c2f225637165b91aaafa4850a5f78d1941899f4bcc53ff22e07cac775fdacd9a2609a5796ff4c60a9ef487d241d6f5e0e5d7e1fb86661219793bbdf0f16873c620c53034b1178b01635e47e379b09fe3dda0394fcf2d40c9ca3f2595ab09963ecd8769b6f0203c56915dc8a155ace6304731abcd3170b8a696f258061e857f", "6fe5aedcd06d3531b6b1f171993b74555f3ae08493515aff06be425fd35a634fd61c37c8c10f2022b764ee214e2e5cde7016a2f74d893c870e7f1cf6dabc4e1e60268a319694eda77fcf2576ac4f9ca51babb64020485066b9c3842008348432fab5e043f2527f1a14ccd7f5ae95383267dc0dd0e5ffca778efdd2ece095861bac92b4fb62e41a7fd475f90b4fb668b02e601992cdcefdbd5979787535fb5c1a70381c2a40480747044f8ce0bf327e6ba153b89a6e5846ff44b6463f6b33bcb4e8000ae2944cf5478c95ccc5891dd627d4c446a1f92444adfabcff12ee7abb419ebc46461aad82ad3f92c7adba755b79493bd0628d6401229f24939432ebfdb633aa7065770109e0308985ceb52cd66b2d3737f0ca5abfb6bf487e5e9dd60793774fe09c639b65c0b4dc63a445a63a2c1ec95765a5e5aa16146163ac4f52a0faf5f25d243e8507cc8e86004d83e9fd653427f375f1c78141f0b63e3e8422bf5003b5232c44798fbea8486038dcc9ce7f8ea7b284c1bc88702497b7b8711331463b3eef652645fceb53b6519a23632ff83ec80e5714ac5a07fc9e9681d8a58acdfa4c0129e03eadf3228ca7903365969ca1faa38ca7c3968152125739b8077373ab6e1078a4af4ca99b8617fb0f95e59a7bbefd24c324e9d84addfb8a6beb8d0d41303a16faea2442a929e83bc640ae0055d8a4cb1b6b0960d49186e23df1dfd45cefccd84fa62e7936201279ebc2599dbab93bcb245b7470534db393ef70026e3b54b34a50c96d457d1eea75b63ec6fd567847193a3c5c1449a610475de954acbf98e4c09d93c2d5006fbff2f0d20046e8efa9d269329824d041e4de5cc8236f3ad72c5864d5dbab284b2cb2482d113e395a7d0ee425f48a1d636f78db480a16c506769ebf6cfa4b33517eadb968ca37009afba7e4c0db4d77ad48e064400d351caf63209d0b1d7b45d63636ca9aac2d2564a10679f8b06000cc0e407e328ed4b6de2da7774c543f32173c38f3160b39efefdf4be260189f26c6fc51597a1c8b6443ed4fc2e04f1eab20ecf602fbb3c1e917a2a9ea753da9e0ce19c63968f3b4ff2e2178571e32a637c0877a806915a5a41f6c549e23a20fdf9dd3a54543e75eec8e78e074926eb89c3250c476522cfad7ed877ec54876024549e537c2684926449968730aeba1b87089e011dcb5f251a9944bfcc2f9315a08e85171998f809c3a1008ec4d009be93d519f2bdfd26007d7e181c55143dc2947be132a31f9d89c85abfc12ac7d86431b117ce9c44d98c347699c60d78e03f1a913db45d2a28a83dd4136703a6d58dd3f8cd2b872fcd7a4ddd6dcbc79408a55b8d0ee00df5056a1208314d156917b5fa62228045e1afe1726c79bd23ee7428ebe88a945d760f83014ffa85373c477d47e5c6b0a52b03d0c7b5dd78dae1328766bb7bb01805386f", .Okay}, + {.Mul, "-c83c2b7f6055c7c13fb5ab82600dbe97dbc87e5a117710aabda88bc09f496ebc2b542e9831d6461a8d941376110fa06b617327adb9940c27bc2d2ab67fcfd8cfdd010a110487b364bcbb59edb6184e72abbc4c626ae1c4c399af15515010d18244e44bbf896cc790075703d7fd7acbddbd3f121d1bdd3aee1824b2a26143a30e1fd711606d92521b59b5c7bdea6a5ba411aa1534802871d260d4f6a83e274f75a92088f2fff6a6117d95bac8af3089d1621b4d787615ec08c906249a89e6877bb2988cb04fdbe9ce9e8f9ef2e0621c9252b694571da7712693e528a8ffa96d43d968f4c4dfc743cbc9e6460c4b21a4900f42a0c9dfcd06a017858b6fe6751232b2504b7e720611f5b12fa7abda08b4d40d170f8f3a46f50dacdcae670756cf2a1f88c5f9e2ad1393ce44b4f1866bd1ea0c69e16ba6694173cb3f27c9d92242da6f4a14a8f539b08d6b2b36dd13d9d329ca8988c4a1be3667fb0328c848cb65c0ef9e73543e12dfb49949329e2e9458d5879b4b00020b8b51619cac518b4b6fbe1ff5edf24c99ef19189e024f8492add9c01ef941665083c988945cd22fda1acc14a11e525af3e1cb85a5680c05d6aaf0706c21028ed0079db69b23514a19b0b3812c10596ae92c9be483113c587dadddf6a70c46f9b4cf93824a30f26775746bd8e47246e404760d95c63d742c61f65d75f6cb0ca00348d06050968f5fa1b9cd", "302ea5d8a53d89e4274dcbdc96946562a47582b3398b93f24c02a6b365eeaec43f9cb2b6cd291f2fd39ed4fff6492963b9b5a742ba58020868ebfa9567827d93305ff6fc58a4dc5aaff47a0fa973298d045365a0a29c6135ae818546a0aae31ff2949dadcd9f07c6ec3510f9add01d0dca2ce9bf4bd457fd216072b77080b2c3e5f9bd5b4f4a1f6a69fe376a89d5020af95a1562df9141540239d2209597246215e0b2ed31e6509e1490312b0287fc08759a83c123e7a8e0dc114857c1c7d4d238144f75fe860205569d6a4ce339eb330d56cf6ca3654d5a2906e954e6d1fa357bc33713e311be4783db04be58fb0a69306a98ceaae16ebccdc90f2daf4b26dd81a3dc545858032f1f48ee761edc52a28bdc1cf2ee9f196b11e8b8644da691eb0ba962e5e6108e0ed32ba8065070ee4d5c38eea5b2085c47f7e953741038a6a59f9b88dc43e5e9b4d969006e60d65c3fef44bfd4ff5179ce3000907db1ba33d223ce80dad7d53725273b604257d8b48251af5378110636d365482fba7f8f8f7fcf52bfc76ba3387192482e4b699d4558e7cf5a14abd022430641581464cc29d9049157c2af96c6b3730b6bf9dc10edb000a4e1f166d3e93db0b342100a4190d97dc9709fefb95e86be26e2d4b55fd559ca1696406e95e1ebc96be741abed7ec3751fab58e2a85050c92b0d55df85040460f47c733cf2e21f878c26aa6ac17564", "-25afc4afef001ba8d0d8c648b4a3eed17e5c1b815dea221842c9e02a22aba40d3629de74eb675bd882474c5a86657454a8341cbf14c62e0b2b5feca9d1b1e2238e2e1706d832c698414ff832224e3434e604b40a78240dd32bf82a486c150e294a4edecb8360a125a036507c1119df198d5577b32cb05254cf25a3e5ec34f896d9a294cfaf1572e977ffcdc19bf35840350d9730e43cc6540f16f740fdbca37ff42d6251a4c3f7e001acec654b9ed93e7ef8c8beb211d79efcbdc1cb999af00274ac19ddf9f045940c222db0d842e71030e775bae089a63134962d72fdfce2d7132308ae387f9f1a3be33bb6869168ae7ce7e2ee2d3c877101b66a52b3bd08071ea8ee7daf8b23e22da15d369ef91ca237579d0827c4c3f582f2b5ef17587165199e485f745e30a13c21964c997e1a1086489559a997d53c7aece6756fa469dd46a0ac048d96161e5b294b81dc32d1dc66e3c8ddd5fd009feedf7c30ab13321604366b793d2b4d47522b803e86467b13dd8ba571764a03e97a37686d671335662f6ca9331797665d5a21462c04960ba115795cfe4c39e4ef8944dcb116e1d8162722d73df0eab5889c42a1ba7db3b7a72557ada042598e8d82610d9d88a62567da88726a74f92a784f788fcbfa86b6108a62dd6777e4513e3de9c8496a3c629b83dca4be03942335797c8fc5abe50bbc39be028b99315ad7c3a90827ee600ed476f90174b7f5f34d380d35de441b92fe6382ba9d8c6080ff9f83116f1a34bf8c37c29ca51197c23ee9b08f0c6691eebceec9eaa0df3fd7fb287a9fe1565a4e63552b78e8cf60b5ea9868c497d6ebf63c858a9cee04710688aaa7a99e6cb04d2a318e9faea0b49962fe521ad7b82a892d7f8ab8c9c94d3af6331f418d8af4e0876e1616cec6bea062cb05a060fb2949e489f8db86f058ffd9cb768db8babec034253306679db815d5171d42edaf88e935efb3ca655306cab680ffabedb9991323598fd1e8e3ce5d5dbb6e737b76a78c588cc4cf04156b8cfe421b59c34811759d8b87311749549e4c9e98e54d2a09377f9761a017c105223583853c65431e5f2cef4cb3f33d50dbd53a2e854adca5ddf6b8be935c436f7bcec78b7c72959da3ad99931d09866f09f87d00c4eef5b7df5b75689c4db00530cd62f382536a6ff78ab76cf303c66d37b192a7f556c61a22fc4996783fa822a3742313ee401134cd4b66bacb19c54f97ef624c8dd913c58f1dc1639b2d94f53e98fddb434a615cc2ae930a716f8cd4abdf04103b1eb0aa70242f78d423f970957aec79ba7815007003c16bd38b0843a4896a8765b15a3e0a723a153e7680e3fcb2480b63c11f25af57450a7afc24b83a132fdc175b05295214139e19978215220c38f3f32351cc57cc3c0440491a512631a771f04eda4ab75da15f682216a3fb2a8e1036b43aa44514", .Okay}, + {.Mul, "-c50fda512d0d0eb0c2989c5c2ccab93eeac8bf6c1231dda612da144954e84962bcdfd56d2a85e46b1d8bc3c5beceef0af8deab5013597c29f9601733747975340c85619ebd277576db0b366fa5d465ffaa2001819d664844336c00c58252b04ddd58b7f53cff7a9cc260db3a29a129e2a1b5b27e95cdc1fd2fe785f40cc0f4b3215329f8e9e78ce88e5f3fd50e94ba86e2492ba27b149599b0ee7463a0ec3d3c732e34d399dbd08e30b5e09f6c56d5f70b4b6afa8d5343aeef9eb630fda9298c4c96d14a92b7e6f0fe50cf9d5d30f610645ab96416ad54c709bad6f717e599a68463895c16213809d55a43b8a50363e213d9372a140a68c165157a3535f45a74b70c60d4487c9281bf1c412043e3f93e6526c009587c1f954fe5335d9e599af80ea86fa2a97b999f0ee9476bc71b22b2344bcd8944ed3e516666ea6a531b85fb3c11918d3bd717a66dfd236f24dc3e590ec7fa0e55629b10fdf8a15ef34a016272329e620b96a43b15d8de1ca9c6e9ebc90d13f17c2c3da3e4f48581b416f43b8795239a5046fa9541daab756be22b4b6b6c3f7a051320aad41367a3b3c188458b5430da1616aced98c38d8cf8f28906ada23371020dd4cb5550c7ec3b26701dbf4cfae17e17876f9c551f6494c365ec0be5dbc2fe5fa45390e4b7e5c1392a9b4dbffc8dde7c6056f8220f23602a170d5e4ad8cb37bf29bb3f71e4587c05c802", "aeadd5a4de5e08e7fb740981b6f8f39b46c17009c04247ca0af8d6d62a1808de6e63a13e88cef9595d3017aceafdad19480400541e4ef2949be557e4f47a47fffb7949f6fcf345a0d44999afdfd284469938c887f2a3dad68978c5a8aa6a9c927b4f3359b6ea0dce5e7be6325f784af4299c62669c93221fb102b4baa9d297911deba693d43186dd2bd272b08d5223d4cbccdfc32327372e6c14f7175760646fa2ee11f2c8b7b0d0d7a1732351d76b47890a3e5f9f90e067d62e1e6c951455dc98323657308955b02e5ec101054aa534d4df818c5640890bfd4960ee86542e51441c16f55e40606fba6bddd7087e4e03c4ad18716bf0aca46f570ece776e703b94b363eaa8a6876139a6e58350e283d189cdfc04eae572b645241bf51b26e2ef46b2350ee70b834cf0acb40a96ebc0397068ad3b087ba7c7169e667d366e936ebf3ed3ee94ff4d854289c410dd9b8b9c1234fbf2dfc781d7ccd52cd625b3e2bbd682738a0617e6cf0392906df2f67733ac77af72e73721f7cada3c61f0e593de2295d4dc4ba889d367a8ccb64c7bd77285c155c971f826ae26e969f10020c14666a1dea909a1448c6bddf2def6b8a779b4007cea1e9e719981e64a23f51637d2322470ae16faa440e340e02d8e64f6d0026d45d8ddeebb62b20359979c115d6c0045bd2bd95706600188770eef9cf7b0cad3697971986fef975c7f4a2e3c3d5a", "-8676968ecf73da4b6bddfa4c9df57b54ee542c5807ca924dc0e743374135d3610f0050fa8d3f9f1eb01e5d5358c6526245a2bc428786b7335b0178444d285e9740ef4c31ab452d0817ced02ad2cbf917286c34328a0cb13da263c810674f000af8a037a94405b3e28abd1c09c62915c325b4e2cc56160543dab500e0d8b448eda5974691f779b4e55815695e3f4a08007de66f8203111e573ce41ac6f54b082f1b284bd8a5751873cb684c6656cf6cfe4e9e10ef1b152ff6a23b54631f269a7dcb818b5ca2c0f523c3578a6bc207d4b3c16567b7db069959310c180ba45fff6365fc561a8475b2fcf102e3c7e6680de84ec21d4ed10b9066545076ed0069d289924c06c8d8deff518efe6fc42b40d2cac32940c40c552c2ecb2b94f0c69f0e7fa8967c450c1b13bdbbb35363ba2491d100f35271e475351dab3cfef14bac5a6fc03bf2af7ac13463bb17d918d79ac51af4ce1b35f3b4f2a69e31a8e228a61996b0be230b21d8e6be2eb3cb4fef19319e239f95b13b2abecced03799f831c90b1701c3691c416aa9c7c9df115f01cfa2067347b9819a1c4ad1fe4d332bd7f3d9d6b89fccc5d7d16a2d90ffdc8e878334ab2de5551581506b043926aed9efb7b43e2d4d41ceaac955809d56a8094db2d1c1a77d574d5528a4a0a4dd6a59fbd8d1391e8677c37776ecc5e5ade8a8c1220f8e4be97032f2c9ca48d1adec6a4dd9b2ada8d7081d6ddb95e894aac10b486a965ddbe26051c57fa57d37ab688b6d04d2d00179f383ed89b03e8de570eaf2c8c60b586668d9ba34fa5eae56d1fbe75a24831576dfe45c5db30b7aecbb69f1bbbe76af3309433375b1fdbfc07a365d025fb11ba61bb389ba8956d0cba27b7033c81ebde0d86ae5467ae3e46a78474788bbfaf5aca77b6d7239ae37ffbfb0170f98d51410dfe3d836cf9b1afd436bada827dab2150c555e37e6eeac24269fdf05c80ad601376b143ad7daa86014a1028a0d05627f2103901269279f7fd3d9069a5dc6b06e2770f775b80f5fe1b6e3a96a4fedbc2aa93e3c89db983bd79e8576bb9719fedca3894570178711d9ab3fd623074e6b2f198e81c291840f7c01781745b4aacf43f8b5cbd3007d9f3783cb9c911ba16b3668c0d834817d4a1224f548fd56d1b4344dd633ff57f5a9be22d13c7ea21c07f0613dbe4779305d6bd26b4ff947e71d8a1de1cea2b506fec12027f6f003737fe14ef00ffa1c66e57a2451141a92f73614904c05658122d05ee584e2ead53ca3307d136cf8cf6053e92ec575f5a80b7adcb886678af2b8f13f83b629c0978ea57d3ebdc8001283eb0a557f64338cb8ba90045d6687d311b833df3441268852083ae7833138e3bc36701ac381bf40007bfc725f2c3ece54e35fe99244baddbc05d80664c7f0d96e7dd10057ca9a4c46054154b99e619b1a31646883728cab4", .Okay}, + {.Mul, "-a78dcba2e71b20afa5d852a23173869946f28ed4b942e907795fd8ead225f215473e99c1d3940e6fa00ce50b83de9f6efde5ed09ca244226a69a0e25408be18909a9499d8a57c43025183e6638ed36e002162b5ba043ceebe9f492276c7633bdafb05c471258396272d2ee67a134310c7466919df56608da06fe01beb8057ef2f775d729cd50f4438af7a8558c9f214ab93ab4ad7b47336fe23b16cc9354b9f499bd6d90b8455aeb81f244189843122935bc5db584283fc6e89f6e6c6413f6c3f649d4b95d0d4dc080089aaed836602efe3ee85c397fcd30dae57cc653ec9505120e7d5c658ef5368c478467ed53b11d223eb29d0f597bc4de6f65712dc2cb52545100c06287a5800b6e42e8bf3eb5e4ef095f2d92e2f78b457277033c4b699e5cf9b7620595c61a1bd17bca0aae149af26e1bbc1b22eee6875a6157ca8ca06239bd75b0921d55dc399ccbfd5d3ad5ee90932f4570cbe30c5d8f012b6fdbdc244356427860e1a71bbf699cd652c32783519bcdad92c2a9f6500517a99e06b2b2787227aeda191f2a222bc7333f91ea6626d6f6930750fee4de6be5953b6cd09a86be6f904062caecb58efeb287f80c5cea8adcb68c85dfaaab57a404320c8947dc4225e2aefd94d4e798d8f5a13fb961cfee39d2369b4e1f2778a70c186f83bd9e58039092277bcd686a2f0f93233ff896662f1c2b1e079f11129c6237673392", "d94ba4e34bf3526176491becbdac2f665323f0c47d72cb948a97e850788c69a69773460653fa945dac2027bdbf550d732456203478d77da250bf0313c73b3126bd830e7d5ca70433c84c104876a83c75599c3dd2770b7195bbb844969a7a1c1b5db6102ea6e66f8f1242889897d5f294076416e9c04ce82bc7c4ec893f12d9e09de0bb73dd3e6ee010bc44be67235b664ff88005f1509ea7d896606b456e50fd6de2d78147ae53087fb5236c2ada6b03eaeb7caad059afa2f9ecdc0774b3f46f80ed09143af9f65b90f5fa718934ed892a84e09a817904cc76d0b608d49603e0adccaf32bbd0b7e370f0fb82989dddfdf6879f70566cbbea48b5f6e8ef5c7b6d45aaf6c36fa72f6aa6fb0d441a59122285b39e22f50abc9467128e54ae281666ad0a7edbb673ae869012262a9a1d3b2c716b1bf3026bda6c1c6e13256f4ae9cde2a7d02cd0bce3977ed704b507d984a5db1087541ca0a2e5fc1b1ddb56b8fd118e82fddb8f19600ff2fedf09c290aeae262ea020c2d267b0865de8bcf4f9dec9210da02356ab75b73d084df5668e7213867585163131cfea2b5703edb5af0c01fbea5f1ace701d5ed85edba2ade036504bef92ac238b303982f9ceb0c737edf43514604fc3a210de94052347f0f990d36e8385071a4840d3d1673af12083e5111474f959055ba68960b59c7ae7d7878f94af5b60e291c3bf0fe006f0671d52b5", "-8e38b41359856d53ffbe54112291bba596f27cc3cb54db57c23ddecf1de18de1ea3140389c85165624ee41d9923600236c9e9819d4f27e5f5f39c2ac4bfc38f5d1370bf629544afcd50334c185b3fe54677a0cf4768a27d724a2346f26e7759e9b41ac0a52ed119aeb31c4806ce3e8a7ac5dcec3d786fb597b0cf29cf6ab7032f50bc1bfeaa2ee61258b8004f2966b6e0cccfcdfc949d8631d0694a0762e008ca066513164e663013e72ce825aeb8df145a5f484267bbae84dc81d8926129852d085ae11a62e98e9226ad60f3019cb00fbc92503575ee5f1eb8f90458e345c3dfd3cb220b06c72cb3b62be9d9ed17818d1fabd039a560456f746f19b77707b5f7b38560d0986033a2b91d19ce85b96063449962592e349ada8794486e88dc5f460dcee2b1e69c1ac5f9a840013c2494ab7c56cfe0d21c24f96dd342c421b8609414f5906a2eb555850d454cdf1ab7ab09baf62867a28ae56d9c32bab7c34a73a36b08cdd710c269dfeae88fba4bf1fc7d62a904f3a6f57a73f6c4104191872ff7531d9495d36a2b940565900d3e3267f924099317414e3e8c8fde3144c828cb875ce57364799ee0066c84648e8d297dcd02a33fb67aaab7decb015b2ebd28f20445ed0a424ec4204f9ec15cbb350be05df36a99551c2299337f40ee39383e951f9315a1e5287a4868f1bd02f1c51468052206dc8a1224df2aecaa771995991b2a1a981164b126fd5df3c6e8af75a01ced9a031c1801ad09202e37ed42a30534469cd8516b8f300e6fc295108cb918d0bd35b2bd91a732ee0a767cd3c446107de8cf153f2eb4d688223c256a13f1e8b134c7f8c36e1f0eb11764e476e070362454f470f461cc2f996a48814a57d60eaa2faef93a074366d2b19f907490a9d0f2904a27fd5b51504bc8c9a7fd503c749dbfb0f0a2c722f5b0fe1540f52171431f0a5a64dfcfdc2a03c06594220ad1f837e774e3edf438e90560aa6a5aefac36c09954c3958e552c71892feedf0353bd6caa5c62e4e5a8275ff6d13c911a05fb068fa9214502829e54517bc8d5ae7424dbe329ce8eb3897972f95ea330ba56cc4e86a68b847822741c48dbfa691623acc2406dfef0dd5d4dcf71f53427d6976189948f97977f69f4cf67c17f5abf7937afb1c0db824b21c065a5d5deec22ec2eddf8650b78dabbeab0f0cadd963a2e4ba6693f67ea248ba2d3c3a0af7ddee9e1aa7c1bec25d22a5eeeee9ab6a6be10ebe629104c86763509c3a64a017947a39cd21f3c801edf8febe6e2d59460ca8736365bf35a3f28cfe0ca2cfc14c1422fe24f5c87cc59dea5fea0c8d68460ca783e00e5968a6dd475179dd35a43bf170a0121ea430dac21e9379c0220239761da2a34d1284941bcd5730a0f0e47a5a2ad4785442cf866d2257f5352be236eec3bd29542bc66a610bd5e2974d609880d0063a3a", .Okay}, + {.Mul, "6fc1c716c9ae1a98732aa6c42cc42ef6b50ff799d7a21432e3a91e7f7d97c5ee28f053d7a7c2f98cb1c674f3092eb979edcf4b676a15353f3ed37c1c8bda48438255074bf9b1a3caeacd16b86f65f80bdf8e8326ef8b53ed9e4105139af2c2db579d0a57c51f1c26f4646a87f75489a3bf338db9ff1d6199c78704fb2fc5f184608d595ff34592c8e3e4bb715afdfc972061f8a4707e927ef375da12910bd2298a8005291943de8f9a5141ceaaa2c3784960c36c9d5fdc192682d50e7154de2dcbbd59bb7371249d12e3e0a9cb0b74f2ec30bc26fac09dfd1a0bc84512671ed7bfc6a05d82e0292442fff351c7de2cfd0326098b7f77c1887be28b1c4972ae55cfee257a38db0a2d79b31f8805d44868448b059ce436a4b2649c096e3eb0250a776037dbc24f8892e70bd1524ecfa7f5967c9e939fe57d97eadc869621ca582e880d18bbea284db7de7b7b1b52365657a05e98dbe9276fe1c7e8569b81120d8f9dd753b90c545eca56abca4af2a77d62dd5bbc1909a06447e73d371b0abf9d200edf99af7edd6c77a682bb6536f90ef48eeba5729109022089e533e6e1a3fcb3094543901cf0c2166b12b4e80b7db1df84ba494bd5fc7bbe45a65062254a3a3b14b7f0695fa7a023de631c34250a8be6ad101af026f72e83a66d6a55c339a38e9b5df1327324969c6dc64ee83fe2ff205f35cc22575540badbe56ca511b74614", "575e82d14868d452b0e850be1172060b99545e9a1ba2b7af9687b11051276e85fb34a4481b1d2b5e945d546da3a949fb1ed58dcd8cb36f4db7d910907aaab28ba9c9f219a5e221d50c7ef710244373c6a21a6a45d9804aea005f921c321d4777102c7e2e0830732b975bc3c508ca43886242e95baead6bee6ac6c94a4fa596c11bbe6db69ce750a8c67a651a300e9a39e0e3a053bf9e5132fa3b2b1edc06e79efe350438458ba3994ef631c78637a7ef5c3756b9a9a4bb92b67f9a3adcb439a17157ed62c387fc4562693c8dada95b306eb3f4a66215b49740e43942c1d722656d277fe71d645ba071f81c1f6c282fec972a0a9a87fadf7c90ca55d47e5f84b975a9e56f9b08a48e53c19a31a74c53b757b9bbfe07beecb5287a3b9addcd3206d9d140fbffbe381fb4c0b8fc479b9620a5ea3ff67e456afe5bbfa110a462425f6e94b33db0938da23b8e8c35ba4a76c0b9a326d8a087ba08e1806907eff24f8360265572ddf65fd12d7694781dd349065010abb85709ba3c3a50ec2c370aec1cf7bc45b88eb3f6b9f3838a1ed86aefe96fc5fab70d5190b038b64fd47f58581be3586e774d40460ddf94b916eb517d0026bf4beba61a631d49944f9f81eb5855bda2e842885f5ddd5b822c929e07bdbf9e10039798cf8f618d6f7e69caedb272fe4ca7b70978ba324fe2d928c82046761be7cdc78ab322ddb5cf68dba4fea3ac", "26241ceb9cd198647fe91789aad36c7a2b84f27f4a241c25bbe472dc01c019bcf0d9a7dacc232dc08155213004c5ba00cf295fcd6d4ceb9aa5f114aaea5b92c3158bf6dab9422804b716da89e1e8628c06b4f407a5b6e3d464239170fb6bbb778c9f13e144bc92c68a40397ed8d8a0f3f3295e9d68fce0d3a306582ca727dd2a9159829763f9bbc6fad6bb455a817c8f81c4ec194f6fcf416a5c87ee1d499750e0126b23a84b1628eee16748ff1b3f0689ee4884badc53546630964fc7917faab3da31335134694f022ed4b501796fef693016e218f7d7d39c68d5b993f5fa036c5a50a22cb84829f4bf089090b4ecb953ca473623d771cfbaf2ac488685a34e74b0ad6e76f8be139bdcfb10dbcd4e102baa32a1a18b7a64e6d7ebdaab7c87a9fa8f786685d922dd17cce07049f78c8ec10bbf505c862c7f98e787db201556df54e5655884fdbc844d9cb6f2a06ea719abca00473c26a863d3007733c3d433e6426d2ef3306c0e1f026625aa554d040f6baa2bde01041f9ce9409419e3a13c6defa7d867f2be4ae3e77b76923c968dfb8e8994a2a08a20dd64808c0bcbb223d0cb8b969a223519f1432f0ac1c1badef14186baa3e22d4960f5a3ba30befe7e77bf2479c3fa160375e5771f65cc37e583f3c204cda581504ad28e87f4cac3068551c5ba8582537b8192959980790f39d613a82fde89a852a11b54669a9dd4be36bafdb13f5c4b5a1c014af3233d4d6e51591b68816a3a41abf3da6152dc2542e6c0dc4010bbdb76ca65f79d9eccb7acf63835e4074883eed815621c9ebf07d2becfe83161fb9349f98ef780a5e812cdf4c3405d808279d2ba2e70463cb67969e40d6e61bc4dce073a44f8d2a0c70b6eb4d62c6996c71a08680fa18ef8aa800122a312cbc02d33c254e7dcf3e4f8c79c7986142525487aacbcad23a1fc8593e13c450f5280a13cc0525141c905507fc83b0b2f2a6405a34811ff1c390906774ba550f0ce4c9efcf92ebc827b49608aae9703b56054b83532a1c39853afdf206a65361673080014005ba8787856362138aa61e569506713b5b87d0e43e5ac637b5e2451f06673dde5fc85861587ce2d0aa4e487a93a6658ad6feca2e43ecf44146fadea32c1d972f7fb881ccd437ee76b5105130d56f3390331b7cf50bc6129dd0268afbdcb88fefb91013f1e24b01acf38b7772c0ce91ef8a2b12d70fb89ee77d8ef632582642f1ca7fbf692bd111063a73aad6f5b23b8341a9f47cb3c3e617019b8b60b3e096285bc106f8ff05f2a98474073a5b13bad05f790c579f8c4287505469fb5339714e80c7e1cc491dbf998f6fee3201397be83afe0b4933daa8532310dbe8291a7b98d8fbff6a8a1fffeec3d927b0d0fd8b47e2a38cfccacc515178b052b88a45655d274cc5904de71394811b105f9922eacae34c7e02907f099d170", .Okay}, + {.Mul, "-ae8e1bc99f9fcbff298e76c139a9ab09777c5e7ad9e812fbb1bba754b5f42a83581497c0ccb3a7229e64b6bdcc7bc3989f8c20c13615da885ba242a4b610b0ec447028d37e6dca40e8c9476cef57c54a01dfb135b053469dcea15c2ce4692614ba6a32ef309785ced17e6a5dafde74f6eb61cbd1a9c5d122a0de7aebe084fc80e7d3b3744f53bf0fc5142ed156fa03e87889455b5eb10baec21fc0f98c5d2b2fae2c2c1d75ce2b004e81f96713b1cbf8184bd248591b451eff524762b10e60ed3930c6bf7c12162d46d2d98f61bee546094677e168d10ad52a1449ff5e24e4217fef2000386f8adcc00bb641371b7b2ff21484abbab2d8da17c4377b4a651e49c421d60e3c6dabc56b7200e29482052dcc83112b6e88ce1db28dac7e6d70f189510cb682b946ed615172135fa85d862dd3f2fcd84324c3915961022cdc7719324f0b6868bf0f64be83f15de376009116222c959413cf77aaef2ffb67835250b2a16b9660345f0ec42a01b231f679f0714da466edfc85965406a85b72990769b4d12d24ad32f3455f0e5835afc60ef6766ba81f9646e47c85e2dfa0e91743c88c3da4e712ed91991564d9d0e9e053ba595a27dc4ca534f831b15a4f14b43f3f3462a9c9175899df44a137c0c3e0c04052467fd0967995e460a6b83857324ae73874104406155d8ae3eaeb3d02f5d44d3b7783f74de4d7cca5ddf528a76d4ea61c", "81fbb01e04d787585f1c07f31320d0a0c6fd986d5cc8b764ca7259835744a8ab1e5774322743ab213aef3a17dd001ae784a94daa4c6142e90f00cdaa2fd2a0dba5ab4a5a2e23f4fa7c83c6b9944d834a1f94df5dede33b5153b43c378390503a3d7e8859dca53bea26d961426fd9216d7ae0acf68efa808300196ba77ba4df354f6e0adc09f48d541b31d4c84ff59c704d63460d01e4727a95c0bc6ee60dd0ee7ef0e79a16dfc1649c269d4cd7d61bab0357fc8efcde44c121fba37b992395bcbc56965416e3ff771131be8e06626bd84a355ac9e049d36d5c517c19d96dd155a827e8fcec550a79f1c6d988a8cb993014e0ceefad3bad423135fe10852b13b244757ae0c34dc71d51713c0e8220d56b6ccb666b3e1b4f3dcfccae445e6afc60de4234246679446393e0a4eefe50f451ea5b71b965501848c1e54361b1fbab3125345ca2f084dfc0d8fbf223f32b55f8246c382157f2d28f91bd3a7cda96a5c7b6f76a72486dbe581c3e40f72a8b2d28184fb3ae818f45fadef0723b8dc2038fd918bf25c94d3f11968fad131dd5acb04b4b78be895929f8bb7b964dc75d64b3a37aabf37ed0a5c431c159bc6a12e11fb276661286a4d02bfca4abbcfa9f36fc4272d8429a54753673e347778dd8cb6039101d7ded36c562c6c727190d293ee42608b69cb554e08c563cfd37e972190197a776d82524ce1e5fd9363794d31e9", "-58a1396c032e14e8d74625258e482bf77475067c8eb8e3c53d94aaffa59958ae7a9a49e0020ac4c078236a93a3507d360536978afbbf1ce2569913d8caf28c71fb60a26ff0ac63d72706c33cb5589b64fafc799dc45a89ecd49659afb69a14213d5c2c4f44ff949e40efb597fea08c3bd892283a46b9e62f32ed01fc20534495e0faeeec7b64d9809ffc8022a879d3822d6378ac09653fa9bb3230fd444c0aec0d7d46216b347e1ae014cc2bf1025532deaf7c433aa4e48d95b68e8aa749fc93083a5f7dd02efcf336b3999956dc8eb9f7f90de7012eb5667660ddd1360ddaef0546ca75029d76758a92bf8af856ac76ef8e5c5b94e242c2078e85e1dfc1f40ff495d6fd8c74874b4c9e9c67b23bfead6e4f12ad20ccdb8397e12c45333d2f674e932b11e4a0eb7e9f722a7122b91adcb432f0b336198ab0004a25bcae4f70b8bd94ebb85702e862d41afc3a85d36646fdb13459ccbff94a2d58700e91e9673dabd3bdc4c439ed831382e5d230e733ee6e61e7c86cdfe53dd6d3a486011a03ab006c4497faa12267f596512271c4cd5d85f8f31b11689d2e91d43c5d0846b5b1967679d61ee89fdba8354ece4b70ba8d3d0b2966f04b8113acebda399fe8b3cc7326a3a527238196a5cbe273f8f9b31374d402646cd1e244d0ab7b9d2ced666f5ac6fe4f0e196c89f92d2271f9f20a3baa80a6159f90e82f50eec5731016d0882102fee07fa9f74127666546841c7d893539365bd96d8c692fa2731c1fe8127087f1abcfc845ed3d9d0c77f7440a338ba50f4650c8d2f711b77a0d8a7d0d3c8ff4e599e22f436fb8368e00fb9b290c1944f1fe2b543eb52e816d678e1e9bcd0061106b291f94bfe1d71e190569a3b30c67793342a00d2e4fdb634c73aafa4683363cc0c7de65512962fd814debf485a111db657f94d7ee3884ccb17cc41e010b3ab983e54e72cbe4c88263a8d39a9cd5b77237d5883431b64bc9c8215b986109a56e21bfc1fc1a8d50ff0ecc45a86591898d05d810421552f995092d5398e879b9025a7f7ba70901cef103fae89513a1abd78f7e8a251b76c5e8b7ca0c3ac89de2ae199b87085c9869cd9e5acf306578bf843baa82a379368cfbee95f3a7bc35d79d1d9f7c58c432d31fefc4f599f55fd81322ed4810b06cf56d273c07ce20a51f5bc1b8af122804618e32712fda23c52e749e247634a0f2fdd857359a1d1c9dfa25ed6dc094fd2b6a6f4ebb1b1bc29baf9f664f235236cc4fd6ddae38b4812f09e22eb42777b30e2fb45d52ff5296a1b40cb8322599d0aa292db1fc0fda4a42caa2ba1946acf95f5229c749320453162991f951fa658743c6600c6f63a50cd6510cb99c3b6395b1d5a94b4c2934e1fd3796d0f6194e8515fd0e012bee87201cf453aaece08fd32dcf511ea594b37d82d32ffa6f12f31d7f2686a4dbccc8b7c", .Okay}, + {.Mul, "b3fff3f26275c8df287cf1ffbe9e26c2222672adc2632a4ed1ae4dd279a82bc5f09887bf305f552b074790b09591a2a97af1230bd441e6c3e14573ca3f4c417438cfdead73533e89dcd3d6191908a69299c7ae13ca4d23a2275add58fe16d9cf4659e81cefde1a2f6e3f21f8097e7be8e3a3a9a34663b1d6c2545e5ab58df9ccfb4739dd11fcaa97cb67b646ea728b4d01ccc45ffe087728e1fe93464c425db7ad89093dab023d87c34bfdf2ec60db71aa0f4c9f961f877297a83f8b8bbd54dd7a6c3ecd3fe9c838acd4178eb21e7d0d34bf406750162815450b5953e29d31413f52abfe445a96d6ad1ecf1bcd2aa9138b218ad002483c8e755cbd9f09a16c3f76b9ea5f4effcebe4cf995c2dece2c67e1cb0bdc06bbac4e9b3b54d0b4b6b403843dbbe49ca8823ca27dcddc3397665ed73914d003ab94a90c1cd5888ba62516bc3464f400fe2ec8571fa647f611d6df8c3d468ec4d1eeaa704d0f8a7150b8203d6d72868982b0db53ccd80b824bba180bbf79bce5a8096a6452598e1af3d4b39d2aecc2d14fe0ba7be98dce06477ea219a336e338e4c4fffeb89ebff081e6852ae12da62142eb27f5da86a0415ddd291db15b1affb9a0c591edaef0c27ee721acdc9996c8d18119b7573df53a45f4bfdcf6b17b5d2d0b847c179b1b3069c447371977777157c25f4eb5678786f037fa57854fe6f4d615c47455329812dd1532", "ec077e97caa29e26fb695c7dd2e2dea38cc0837a920547a661e63e5b9e91b453198d192596a38eda842e4fcbd2541dd2d67e84d27e0bd36b65b39b01ae24f22af39eda27726770b009aa934cb977681366e3a228805d9902c29ade517adc82793958dbaebab28d49be9d6344ef2ce5639d116e1f881f074eed4da93afacc7622735ff62306d5b9e7397a48ea769e768a91d80969b20e15b9922da8254ca9727573059099fafc8c334357db154786d28d7a9c0903ec6622f4c87791ed18aa0d1b3366724f6ec08c9a56fd31e11a6de5c5c8df64a31457528fdf2652537caddab49499bf7f432b3432259ed91b31c3aa6e91f975a8ea793ed94a6fb1b55120d7123439f3376afbd8b078d6c1b355f11f56f5e8da6a12b0a2c774bfc85b9790efb6fecb8965cbb5bff5d054649829bc6cbf4440837d1cc64cb675d04d82140c1499777354665286e649e36d3870a0d14e028667a33e668f5077ebc692015839964edd5650e2803babaea9cf4c15750deae771074ce3ad5fccd1f028656ab5ac09dc23e4ac40c03f723ec72db334ce65b21ae974c6e2ea8d601acff9119959b756f7360d9393ea2ebfa6f49ed20b8308e5fc4ea1b7e8fdbae8cf903ef2809e777ec63bf2812725f47a450897030c94ba4f0aa067266f57e54507580a83128e4f5f46b4f3cdc32e7e0dbd98c635bfa80143405bf04a5b9e7afb4c4e3c8966092c4b5e", "a5f539e5d2e9c47d462bb30b6e06f3771a76c1af938e9f725530f59f3f55e3c67d91b05d5eab78eac62c607f247036eedcee1ac6b587da557dc57510593abdbacbc65b1235cd26e5c6be8def699f60594deac07525204129d4f37f00a58f594c316687f1400e8dcd2560f2d3d716be03bf0d0cbdbda060c1293db487b9e9357296fdf3c4a35804d7df57c131364d056217a9207cda158b0e691d81eabbd1b4535f380621a708aa484d36dbb45726ac72f35d7bf82241bee1eab788b591aabe900fd08abe5062112077d2e7efbcae1860f622499535033b0cfe8998b62e4510f4de0b597d82ab94c1d6a0c1e769de3fa74d13d5e5de8e1c0c2f7b5e401646a912098c156365e237b28ec530ca219323e3fc7d6841f7bf35132c6df38c298f07a4181a071be18d964fee6babc3a951f7a5c15424a93e7f21878faf9ec433409d1a3ff392454a1c3abd4ed311948b08acffc02f6f28a2f9f53428ac89bdc9dec2e19877b931a8ca267580d79eefc481585895b196d5ad54db352e3329ea67964b5fecf3bdb59a7fb835af6da141b518bdd84844501cae5e1955e63221395c8f85d520e298a8d377e6ecad09deb82a6be95df150cbf969030d08ba6688a028ff7a598e87bf047a0d2e733d55159d195996174c55597b3ee2ddbf9ae16d9559426fa177c5fe9a37c8786679ae53edcad983a92111d5d1c9e9c38c3d03d32319fee8ec8fcacce0921b052cc43e3541c447ee1be3b1a7a1bef4493b4a38732acf6a96af4e35dad7ea8b8d6e6d622e0d9d4a8701912a29830fa501e1e36a4b69abbd2f08bdab4ec42eb88a1eb5726358503c14e201155203ace605480715a365aff4cd79dae4c0995282cfde7c7f8d908b19970471ae96d93fb31bd200d4bdec8b8cea743562d9a56bf25e7163a8e1c63a52becf913656eb2295cbdefd98774e272b80cc1abea402c01ac63c1abfe44639e743521b52547032be39f81c235826ab09a61fc8780a38f3771d757aea5652b0e8c998f37d2c09f89b54f1f0a5be7bd9072824f74a3c7a46fd2b67073b72b7c4d2438a9995ee6d569165d2eeee2c7a8be42053ace317b65b235694212bd942e7e9533e1b82b21fea6ce912537ac11645f3af1ea79082727ddf964348577ba78eab8b38e0a21b98bdfb0de2498461f4299a488a8879e70ea2fe8c7c7b912506dd3d6c6e6ab1abe91e18f976218edd3fb39857fdd0edec502e9f89d63b4fd21263e540c0f137d9acabad60fd597b42e860d041771cf2adc9f2938a077833f28e6ca2b041910c00075fe344065cf65f7806aabd47aa59800cd835b808cff171aeb93cf21d6e6ccb8ce9235460412d97cf33dc2ddc28f9a9504cccdfcc6a1bb19331a291c464f6d9cd5761d24013174c389ed7804e796417d82f8826b017866327cfd560296bb430ddbb7f2d71c00e590818fb6e5c", .Okay}, + {.Mul, "-9facc8d4cfd1c2108e3d71bf46120b3455071bde8ffff63fd443b332979234247a6d0f377dd37e78c1a4e3ed48acc6c221ed01572e5b2e593159cdc003ed74a5ec0dc2703e11a4396645880cc1287a93ba97d821e3c20a22e01705f91b0cf4283f34c04d8cdf3d67ab2472a3917c86289e5bce473735631416c2ed99c9acb846be0b8a2118e165f92f095cc7b70678ebdee6376e2a943113494df3a7fa7370eefc7bfb9b3b1feb9204e7398ce849c27840633de60b0c92acbbe430e8c900b3386371123619dc280d7cded50cc6aab8c28ad85ee4d3c34cede58103904e361e5162441dcefbe2a195720d508cb0d7a13986edd6e68c7638f441b2685426bf4488563be4f7c53508c99e253aa2139924e39d34bb3f4b06121716847c2ff47b552dcdeb1387748fac7cee33a115fcf78d5c50be24a925ee847261bd5b289baf82a72360874dd2fcf482fc941d868fd80bbfbcc1f6d76700f19a333a4c62b957cf056fa66fbe949874f02bdeb1427222083acb33974fbae6a90b21f48515bb38430df2949f197da4ae18d3a5cbfb4797fad36f58bd956e4451a98e80e7b1fd8d8d5751763eb4388d9bcef6c56017961e030bfa85990798ee0aa72d22e8cbc5e86aa5b3699feb53f006c7df9c9f56f2030d0eb07a9a0ab055618b3343de4f620d00961a08f19c0e7365a48c0b288e37f0e4b7e8dd7240ae7ccaee4fe4967823c1fbaf", "439ebca511bdf433ebd050574584542df34be4e23e0ba70c10f44ec09515bd7bbc728e246561cb6aef1933f49af538746e7fcaa3466b376c7028c9805a1c977d57999b0861d6a471b1a9447db6cbdd5c9225ebd1571b96125f0a445b1bb8e3b3ebe575ddd9a10e2b13ae702c625f3ae7cf824ee70394d7d69d9481541c498b553297b24ad1899c2195e5f11fefce9c7b893f734c29d36dc7b5d52b37eeacae64c478e77c19b7bb9999e8e7fb406d1977ad49743f34c61d2a80917e88c690adb11b185db6b38ee78772fe1b0687c4bc1278af6e298dd5d40d1a41fe9ce1f540ca8730db68fac0c3d3016bb284b91254c74fbc4a6324907f7c812681af5113c3f99583099b614c2fb1365f84da9eaa84d3ca9407cfb72670080f89fbda28493b9d71786c2e882ba9097b8c60ca82ce72a6c91d5b13033df99592e89cf165ab4c8f0df620a4761539f021832a40a234366e499b251c72c118da14d25d50abf03490d713a787ba4f1a069ecc78ace6bb9e8f377b4e6224aa0a4f02f6ccf2fb72cba582131ec004e5234848d1cad9c2e0120fb78e0cd662a8c7ae0339556301dcfe6dbd5f6769cf6e91ec5e63b0b8c6516f8167feba24a9138e3b9798128acc15ca8178638f6af5c644b666bd971ec1969ee4fb7f9453986db9d65ecd3f4908d6c834628d6b4036a29178c39806adb63663714281129091791dac64a2d62c64331589", "-2a2d3add7ea6d73f90fedae5b9788d29eca7294da5f3f0d6c4810b74d5388bd132fb2ce483a1cca2c5a8c7c7b804373c85b127cc9cd2ded7e16e751b7a8a80acb6942a109fc2d49f426448bcf559eee49b538fb9e3297670633995796a66385fc9bafc5d853b49dc181a3f8c37c22ac61fccc1bfaf118ecc1f655c4f26240ba36e8cc94a9b743af7628cd428a63229b5da27315dfc24508b07a6288405364bb0c69a1a3b42999beab97463cef56a3574fe4a3512e6861c444de535ce30cecee06ad930fc864819ebcc6379a3a839891481b833c260fce090d4f6a2ce24babce09d63e643e0266d5914cc72e19ceceaaa2eae078660ab7ef6ef9c9ff34ec0fb9e9b39d43e484a0d0eb47dd9d12bc44d687d3aac0a8f47fc8642281387bcf1a5531d362fea49fb7ae909d0dcfb13433d8e4aea7a415af636cc64aca74c2e632aca398ce5634ae8041005e8ad888ce4c6e8f49c678dd138a5cb18c6d24e633c9f3a2b744d3fdbb4d4a2db191adc24e2cb832e77e70ae18d8356d0556fb4785b1fe8ea30cfc0222c0c0e8756cf8ad880c4fae6f97809d247b10c9963bfd8077ee5957500212aa8dddcb896711d022d5568a86e08274bc2d0a317d337ce00ec68810156a46a74f084ab913992a960db6d973d51eafcfeb600e60b4918f08a68f2077fefd66c1a767c4901a9a28e4ef156f475478120809bfb1e708da9ddfe1a82db87c495879e8646dc2e4aeeb833bef695b4eac8be538a9a18e51688ee531cbb4128c552e0ac54c328f50f4444d86b19de77ddd57ffd42a820113f668f9dfe49bc481c760a70b315c2bcbdcac09e4d729fe59efaa079883f7cb1b6eddbed7fba49f81711b1e44e43f87d557c696a9d24f66461f81849d0d30a11d416d6589d273c990c66828954822c6c750e4c9c4093b06ae9dd0d8eac3454feea82044236364de7e397ddacbf6c1dd8b26727cf358368ee1542b22cc5d92788cf360c2473da319f66820e7e21e82befc938eb1aecda4c5cd08950902675c88ee11eab13aa5e86b2d6995b8f6da193b2cd4793abb0747940d5aac4f39ef3e49fd5525f6b24c050c78087192b7d94efba5d8a1abcd271f6eed8904991296894b91b3c75acc5dacb36fba67ab254e434b68b9c1a4d4a221a869bc711be288095ef67c682c9fa861d6d40aae9f4470041f32ca486cfd2f79513199346f829ee475879931970d84f102f7411197e91436a03f68528fc7e71859e25251bfeb044e7a7e9604bfd99f67d1a5966a8a32d31e7bb88f4f268b793c4abdcf42ca90f07b73d05e3295c2b440582324d8d07c4918d40c2102faf366e0e41b2b42cbdb4521dadbbf37a9d2bc5d342ca31ccf5441c632f9ea8e808b9c0a8bff195170a84a0965d8818cdc6806d95eaf05ac2dad26f1b021f7361d53073b6e610b041af2dbcf997580cd3438c520ba7", .Okay}, + {.Mul, "4aa4bb17efe73a4c8d530233b0a5394f82a9a720ff50a4b14f0e6cc66f0384dd739c00a6a545a56472d6bb488a2066dfe38eaaccf3e3a2cd92aabe9334d342ef239cefd4a313c1e46288b68906d5f940def3b661bfc2836600b85023bf6456d01fd4fa16c58f547a678141a3ea8ec5529b45e39c9b0921db68f84f7a2f5b344f0fef3ecb05311fe5c124b911e6760d3007f6a7c7ee0a6408a77cc94d226467ef500182a1ae7028d6877d36b5cfccf8310f8c647541e38782a647899ea8459939f0a39bbd410c07b16f89b1dc7a113547b3a47f8dd86d9ed4bb12f0ceead23bd5433dd54c88bab77613eed5ed76987ad455556a589b0d154367c761e21616c842ba81927c05fc81b1bac743a0946bf7cfd0aa547d5a72024520ff077a83ea3727d99d53ca731d4343b38c6687a457338dc240ffd389725fc6050fbf679e501259b23d02cf4a8dbebd7b782e4f4b222b19ddbe3f15aeb629adfeebdc9223c7e27e384c8d3a1236c15e233d4dc2b39b6f0fef56fa7755e579abfde607dbc21a80a7617871bc6bfb087ce9a9304dba632e5614be628bcc3fde0b97ce036bfd0fe98a3add1ad3ee9040783d657b8332f5929eebe5aa33dbf82102c8a86e4dbe679caf842c28caae74aa6d50d796c4a98d0dcd1831204447ed889fab89cdd104c9cea43380538d3a7d2365ff9d1a66dffbfeaacd70de3aa0ea0d208f7f51b0413da1e9", "71b036f84afdf9f01c5e6137893de884496d0a8d8486cfbb4f55cfbdf0280cf013593e5e3225701460af9882963e5db7375dc343c29cef85d6ef1a55fbb4eac0d0b86510619a4f63dd5289e9fda60bb42aa0e5d05cf015340d2af1237ca46be652ec965a9f227e68f6b154e4ab7a4ece684ca4481759cf809e007657345a1cf410343fce9356ea789f485e62c0e189dc0e75b1ef145c497f600f99c78b789c058ad32c76804a1191b0a72770f1c10606126a7d5e47b7ac6437ad8840db0d80e15c0a6fa4e2a5100c30288c7f86536b4c32fad36f0b6cabdddf8062819358a86c9a692134286d6af0f5e4169d8ad22dbc717048258cd2776439e825cafd374a27e2c4413ed3e250870bdd36afcbe16baae4118a4c032970a7c846c94a2e2a47e6f8fcde3b2353715c65f81532f13e6b35bb95e2393df77d3fb7183a5d6a4b0d1c0b27cbbe6de4d0cc79804f245e47407f069e45e22736bbb185396f0d09d2a7da979285d8cd13d98ee3b99d4e9c9469863d967cd2dc47ffbb0e833f3ed5ee7888367c267ea02624ca0d46167ae8d29a64d2727c9deb3c560b0281bb8fc8b179c1d5e46349f4ca8e8759b11cf47e33f1fbe59d9616172b526753d69fee66157656ae5854b450558de3ce8fd540011a55ec96d1d5e86978110132d69cb0130c828e4c487e252c0beb5bbee97046b7a089d6a08b4e591918524ad15d7fae091d79bb", "212617dd5643f7411bff93763bb40a9f01ec0675562910f18b872a1d371d3470b56ffb996c65c09c071a6569a8b8884ebc11c9570e691c7c5ba0153c89c15c5a5f268d0512a45ca2864cd4fe9be6274c3784a2f1995c3ba477bf2350b9c96b24cb8e658d38c9e3d59a873903511c36b7edbe8d3bd45eaa1b00ce03de536ee8454a7a6df4a5ec3054bd7f35565520c0991dda1cf4bf6a34c75f751a81241617913d66209fb4e492aafc2d68357bec40e7eda2f2139f252aba2ff41ea74669c0b3607b3142ddba636de28f705ecde936d892fefdd215caf9fc0f85d13a857d732fd356e1c4915537caa2b354e2844982f6a55df7e579ec9031e99764fe1d6934fbd7b3bf2f56ad4601b92e7c4f1b69c1acba0286b69fc4daf9c1081758f7b0bff5556aa59952a745a825d3ea6399238cc09079d55793c8f6a1bff225edf2f2a2d101ea8013cab729e985024ee63c550cc4cb03ea7e0b8a991b81c96d2e403b6b413e2f121070b63a7b5fc65127fe52fb1645cf5e27df5716ed80449a9507bfde95f62a327237f175bb39c45f9a8e817b9673601d4b20f3540ac84c949350eb97aba01c0d2bb9d1ca262900075bd72f26ddce3a3d3dc9b88d098affcd7c0008d8005891825333c35d5323caf24d9e12aac7a0c47ae9e44f9426eaac5e0a7cd07d0701f54870a9a7a9991c5dc470e3850a88314745b194525dee303da42f1264c0f6655bae8c0fc37bff91e8110ae58c86918aeaeb9099338076c29ac15c833b348ddb8d805a13766c344231ca22668d8080f2af1f8a9f81742a6a184aa2a1c83531064b95002a019a6fd5016b9f06487b75af24f702c2377fbe67ff3c96b16d205331aa7d196ecf08aba27c1c810d55911696436b9da24dc56084da0fd8f016ef169178698b2c4b2b1f6bf7d4009a1466952ed852afbf683a70a2d50c6725e4ae133db82bd0178c948c5e0d28f7d5b63f7c8c71c48593aa638bab465f7fdad51e3f0bca20e0f909b1ad27c458efd99446da215ac2a256624e9b76ba19d5633aea3185b076633f0f4206e406f513a1b5b6777ec740fb12e85fa736e0f69d8f738152690ada386f40790444c19b0cc6fd88af5d723cb4b776d5b2bc75e53669139f33636c7223672b9f4f4985ead2b2ba194ee8abc628a1154c273dbef5823b06f64388db1bf7ad13acef271d24109d3511849c8d603e5aa1f06d252b100b01ce6f534a6f39848f2115e9d7335ecca05b3112fcb81e9668e80ff82c7ae25594bed98f8efa3cee82dd2a11a18677aeecd3a72510dc78519db0d2e173b2b7abcfdf6fe26ac2990a4153f84154ebbdb9c2d9295660b5a74c054efe85ede27101baba1632d124a5d97818d52c8fd8a8ad14fc58059a77e6608cb33675fbe3c3dafe61e828b15bb8cbfb301e82dc9b561f28fedcc39d7e228f99c81ffe68bb2ca051f16633", .Okay}, + {.Mul, "-abb763a2093c671b76513c82d12a1834aea001e9f1e8471dbbfb94ef62b3aae5f5ce6ef29636738f35fe4d5463da6d469eebfbeaf7091997490e10e8e3ac5692327a32906d64f44bf3d6d9120d651d492c9d621204e13e9eebbaae86bf35174771666ad67d4ca85ed7efe58c1aeb730d75a6c852e1d4294745628bdd4e47f6419beefc70b4cf311cc9dfe799099a1194623d9a570c38188bb0aeeffba0bd12665cbdfa4e980f44bad65050b8ce496be80ce029fa52b5acba300a0cbfc8ff26489dfeb0c06eed7e6a98ffe2c6c8b9e49b893ea8e454d8e6832e4490a4427b790d36ce5bd00be197462ca2e81f350d1f6d078bf18cd4e170e22cd7dd8761bce9e35e45e48747f2c758158d6193103fcf351b89df0f0135343e548b574fbeac83209be37fed48cb0f38bed97b1c3d7d55316cd2dbfc79476502c6a9a11838ab50b5b63f9b2c69446ce48e457220cb828b556adcc27817c623b9d8ed0befc4cdef22eac32ab0abe10463f1363706ad2835ec3c1ad41c244fb30f787d880465f2bc0be314168999bd00af826e61cae8472163eb74315ebe65dedebabd5dfd7d853d854d26ceaab90f563b2f46d19c0860c54f2d3af8ebf9e36617842fd3d97403ef47f6a2cf4e91d74b69e94a9f521d3df847e38df885fc75b6679a623f5e10eb679aedc0b8f2325389a77a43953322e4780f202133f11ed0a75eb1b54e5cb3df8a7e", "c114ae05472ee350343585a57aee0b98e06a494d25131d0503936b9c2daf06eedac18e0d3a2513e6ccded80672a32c1efb280dbdb40d690aa68c65bf510b883d6825206427c87acd107bc6ffb3c4a5585d10f9dbaf1b01ce5ff532037fcbcdc0d9eb309866b96d086a89e8b54894ea491724411c84d7372c426c254144c111bba3f61f7b530d930879615f8917d0ad0869bff523334a1185aeb23aa8ed64b52e5ca4d41fd61c0508499462e288dd2ca9597f6dc123636933407fd6b3738c6e7597f15e310152d16627db808a0d9c05b4929dd80de396ded678460b019775a5e5fe8c949d78497719a1caeb145f97cf72b8926464ea79a7959c0811c88599f155633ffa8ccae111755610947333336fdeb2d7aa056869ee99bdf1675886f1b635870afe03947bf6b4cf4763ae0cec18ae8621b6fdb70fa5e590e9e09669da3441224c47c49226d462b7a8853698cb5b73825152f7291621a30a334d07c795bb5492a31e0d9de2d5f9e57a60dad0b5a66a62f7937e1fd61fe3f74875768db45698916815f317aa817e30bd3280388bf274d6c56a43e30ec9dadfe8fb3fb38bce9582bc10699ecc02359480bb10093ce342919efd6ace4f704d906bb864bbd7d4f0935423d3a5f3a8dc9f1f21cef02b1b31056d2df01210d678324df7710d35e6a39654ced3ce3c9f7b9990186a18a3ad1aac28e7d6be1f05e20890d4d6627b8c20", "-8183212b21aba6f43ff58c0c48852f92ff8fb0c000c933c8aa0f3eb8025fe0eb6273b74ac930d1e273c17f1af9b7505fa749853f45980b58ab015ba31e5c30ed9aefeffc9d904abfcd5c37798d8d5a77a4afe49e14c30b97f81f0d49cf7b36c95b2927dc522267d810f8d9d65db603525b6384bd572c26fae8b323d243bf27615b390d0d20f5da792b8453e25734994add2696a488b0ec2afac5b0675b31c17e911b35cf3edcdc334c47b98569067071b1263484d7001bdfcf34c05cd330a580506626f06161b89f4110fd1938c9dd81121503944b4458e52334b731eb879b9716d556e179ec24e5c44bb7e11b5d87e059e380236d8bff6d8dddbbb632b476f0fe1a80a2e153c6c5e61071088193bf48defb65096eecde197128b14ead300950a9fd905940badcfcc9908c461c2468c305d9c9df98c68795798b673e91082d67774582c3b95c3bf47784e043abd16ac99e4ee4ecf32fc6ae85a177a8e5b1834e87c6d41b841748f3c96e5b73f3c2904fc3da5f83f7be4733d807aaf971318e10349114f3ebac66419bb26596216eecf6817182755b96c269b990e4c1734133e7eb2e327d528cdf7b2598386fd313d8aa65c1e2ac725e60a3464b25465ab5320ba3e1c5bf30572e78bf0dcd4e799e530822b49e9aa15d78626d118ecb2a6c6709f563b19a8e2a6670b9e32aada519dd5bf2f3f0dcb4c037458df3c93df1c0e205d720c102337b0f2c094c68256f8c3cb547848b17bab2672383699ea48f96d5d366a3f3bfed2d570d40afec51bcd3d4516dbbf0efa6dce7472ec7caa0f5ea7a301eb1c5f941ecfd74422f9f75d34ed20b46ba5c63b8a938bcea7ce1c979516aa75771187a653b2889fff1adf1733aa8e6da9ac181fd8e1496f8bc7c92c7ba4b7808f441bf6679af4e43441574669596f944917b4e6bf86ed82464c8c35886076500f852e8fa9a53da55ec78ad4b0d082c5ebf3b6f4a52e6680ed50dbef38ba4fe8fe6f7a723015616066f9c967229d458a99250743bc2eb557d2d7805e62628011f1bfc99ab3a41ebf240795968892a579ad112decac645ce8856e1e74968551a8de499a7195edc331f38e96587bc05d31da9f281eae16da28c3f8d84871d40740a8c32d8a4106f4203b57e8cd781047ff264789f4dd1f611e1a618b99813424f0865725435c02933fe6b9efc4c77f2b1cabc64fdd1cadde575c716a26ac05ce3da9daa8f3243e030fd21eab5eaf171ac82da2f6e3cc7f112f58f9aad587d373a9bf4a4791133c6b83186c3963532bef28c51067f930579837e72f540d98a7ccfe3d9d4a30967a6f40850880376d31eb6edf881eac8bdb1f5a6d6334653931fae20d5d0a559f71398fd8e9bd2ea4d83f41a1b367db84dc016946279a6f8d1d5a4ed63ed5ea4e3eb0fbf9a2ea8b91abbbc2ce2239bbeaaa8e2d3589ab4823837c0", .Okay}, + {.Mul, "2847ad33d7a8b43a65bc0808d6e108c8a8e7d089ae9c6a52c5d9c494d6f2b438879f566361e4fb563413d724511ca5298439d6bbf5d03d555cd98be178a2ec1f63e97908532c2044d150636e5927eac2675823e5c3161288eef649de5c3b3a74fcb6d51b0e07772ac8cec0175b7e37b957dc3a2624bf59cb80920cb130dc5379850d8e766724fdd5f6ee517e031b76566f8870baa12b105d1853e644998cc2bf5d8bd1de7bc70836b129c80ac203b167b108b01395ff1a184c36e1aa0aa2f3631bbed6e389a6827311bcb1f51e1d1fc76e5cde4d3e7a1b0d6b7371dc57a4056f6697b84a7fbd3e317d3e637836f2f97d2685c0ca53e90a6760e339c271b101e649e18dfca643bde7825cf6b3565b4b19a464480524b018d6299993425b3e12a31b80b9675bd57f500c84c2c8bb18edec86c2bfd902f770afe56c862a8b7e150967c14dbe60a06a9f4174c8dfca462a548193671884165367be4e2a2353ee75339756d100a2cfb7374e1812be6ccf686e095c862f5d7bd5e99d8129699d0b2a06087e7268ef03dd82d0b3be4c1edd1b2aecd7e884a75e2ceb5e284c18aed6522ea397e7cae6816843a1ef84bde38cb1372c86e9e84c20f6cdb4c234995ba34a1f22ea3e2a12ed5c1117971070a20577d95885e37d05fd1d152ee59369c29ca6eb8933472d1d2ab70ef4d79b28e9115ae299975a669cf6f7574559e62e44e6a6a0", "94516cbcb5af3fac3d6475b2b5d7c41d0e10978f7c8f26cdd59feb860b9e6519e2a8b643fca57bb81cbdc63ead0986d8b09f1728b56993d90ed086c1b0ec0f55c96668fcd642955f932c2760dd11149e20ff499a1fe007632b45eb1006639590576c48f43044bfe6632026e72aad7baa90f261df0d183a4379a9ada2c6e2343cfc8552442d9161c8aac763bc6405022147cb413566ab9c2e2c632d2f1407d513c0c45831df686f425adf9258d7fa73da651aac785d6ca85c6e066357d317b0fd6861346f706cf5054f1d48f7e1fcd577dd0c394c9f2c1182d5314debb61b0f39f5d1ae8c79c7dbb077e55208e3ba459fec1802c4e66b75ee17e03139debbd0e45c50709c5f5a60ff23fc8a98368a568e2dd96f88c1a50297d01d18e9fa2602f07e4e89c063e9c89dc4acc41d71bd96ab7001c697777f7801920ea5dbcba728fb3bbdf5c2ccebbca6f0a5a0ca56e2bbf9ab417a8afb5a4286f09e8c00ff58df296f9c2aa5a9448bebd4b2415ec040eaa600e021ae2eb2822042de6f339e5a855e67d83f8c630b098092993a1cf557c57c6e3fda4a2a7c44346fbc8ba513648973faa2c6f40a77eef27c86b7f13a3d06ba272b1de497d29b1e8d00d9c42225761fe94b846206e52dc16792afc14ec3b25b4a65d43b3e891b12e7d9154e4df89bfdb4ca639ebbf324edb45d167407d84fa30b740cf4f816faaacd64fdf339ca7c45", "17563febb460161a20939a637b4bdbe1d410ecbfb9a5861572bfdca0fcc82fb8872e12a07fc6876b3e7c9dd48fc2dfbb3976dc0eb5195ea9becd97927034b587c40e3d440798a4c671eae5a6283958d7570898187283048838ac900f6a644e2a66608a07498c8894e9bf22ca8ccc4ae6455c75a8282b4c9aed278478774a7920c18dcd30dc686a657750fcfbdd6145ecea6daecc95f40ec63adbbdbebb9665b9fc92b651199f222ce450a409271d5c7e4189505d28859ea22226b4b282b43e9cc3fb489b65fe51b7d0b068cccb3bb980a4bbce4a7bfd6ad0aba8b9c0a9a8ee8554307d59ec607dfb1260bb3cf43db04cc6afab3406adabaa5cddb720b95a86966dbeb41d800be6d4ac05515272ffc851cec877568c2a2e5264c0b9aa5ff01124737f80b946c2bb6e57e4edcc56d15de4ea1dd7b799b61601e3d37ed531cb2c357f9750810309b663aded82f58c08769bb82f047d571253a7a9c624fccf8698645e3e6c9acdcb14fb9286a967a9a0987475bad0736cc6f2a05b11f6105d9e15d4ce4477fc55ad06e395e68e48b06b1196314b16d5e10d8b10643500583d197889fd056e4eec3d89b7f8b33cbfb1d6aaa9d42442c41be9ed4475b838d8d6d7daec7ae1b2cbeb3a890b09136b4bcea8f5c45b342bc2397435836aeb3fcc93a20ce8707279c13173e15de46cb9fdb1c4108d30aff76e3742c438451650e0249505f36921e7a95d04fcbd9f8bdff4b7a406e1893f2935d88ecaf5cf703bf92374197265d6df4316c4d3e2bb61309835c42c32c26de7ddf9663ead2d3f8271010aa1c845e3f88a85dbc286c6ae07abfe2d6e9eaa497ddb54e8b85c6ce3f5015dc6b1848370ee9ed9b9c260d43d3b789c8a32f9f659e3b2f32d9d6197c9d95c469da0996dc32d6967a977397014af964e19fe07cebceea0cb91f07c6d2ebe53dbc4d8d07abdbb1913b4707fbd7bbcfb79fe8a3b8144bdf476e47e0da4f5993611ee8f2d62d2f1f97f92830e525577611609ee866f22cd886334f83584408bfed40981045925b2d586be3d7b456742ee7e82b213cac0421df63411e12efcbe94515bd48d5adf238609599f8000148f7069b3a5fb96e83d50b8946b4bd8528d21b7baf00fe3022da47ede62b9589d5cd5b79c0b9b844f7bc726104ca3ceb1979093b643ad91be0e4d217df511648211718f1d617785fda6c6f08885fd5117567798e2a7d25a80cff8903a4db47f0b551daf53e7e07e0c091b96f0379207b2082dad7a240e9ae0c7d6c87ac4c266406d5a4550a99ecfcb9c6d3108a3ec37f282e7c51096f2ffb32384fead34accd5a9b4a753dbb663203f38938074b964e3eb2fcf0b5066612b7ae74362cb5c3c9fc1446e1cd02705f8732deaa3eb4a8efd8a832fc1884b5607d2d31e41d3ed9bf9373f51365225cc459bd337d606917baaf76d165206920", .Okay}, + {.Mul, "ec00a75c9225b3c506a9465a102cf4e4dda091c33df7ebd1fd34bc35c80f67778f16d828cc34d769890fc30efd78c75c14c4dd9b5ec4951c0c1660d4cc6bc9534435de5c2dc16e92c596abf9f6203267ce687b1c65e5e75992c60a122b77accabbe6c51fd7b509fe62dc9e46c36bbe2d0d3bff7e0f99c950adf47710865761d34749c6839a8d4e3d04c936db9372122d3f657177e6514e1421a456eb5dd780d8e3bafdcb29ab323a26337d3cea9131511343fb5acc10698aeca572e202ca0774ba3efb49308680a8eba434ee832411d4783e8be9453de17ae8567befbce8d44e8bcf62c9f645b9a0d21ac030296f200e51193c6e95038ef5d0399ce62441dd4386855511abd8065e20db63ea0edf9cf2b2c380dd48488cecccaa9dcff3360e0092d89782e06a550f789b849cce297b892f25916205e9fac3a67303731d04753dc4b531467b688f133c8de6af5cd09403b067841af5e483d94d132ba4a75adf54b062fdb389f0eda4c7de1ba7e065c26cd2880fcd8978dbe0134ff961e41480b4df9d5a4e0367cf89864ee1b009aafb7bf3b5863f80d97431be86c114bfe61a7dcc9f9a738ca62fac45e281170509eb3c1245b99f7f1866b0a70eefe73d2b77ab2b130a1f8b844e8f07eee0793d41bfed348bb3d5ad72e73d2947a969993630ede2e5076ee8dade397db2efc2a537a4b67d9c98bfb72ae8804fe668f958fe37b", "7d8746773aa711c41b49ba9d66da034eca388d47f49d68ac306e749b81220f2699edfc8419f1131b39c100660888d4f03c303b1152ba962befdb874a8a9956d7e03dfdc7ef1c92555cb5c242858ebfc69c111bcee7c39e613543da6512505df9692efaa559a4db544e6d93ccbeb675600bcf8ca58c9df1f033985c64f7c81213ca5224bfcc5d31a8f62d2a85cafca03d3c68ebe6aab3fc798595a4370c107c02c2c56e8175c31789f9b0bce53f9158081739fb030a0da3cab4c739c5c65e24aae243312310617a43bb94b155c9ca2355dc2883bb586acb38dc0462f59d1ce61b2ec94b2c77c58d1a246f17cecc5469898c50ef97f99990c6d79b8763169281cd599072866d48d0a2057b8ccce1bda2799f37cc0b39c59eea1fd2c23edd11d3b069ca4fbbc8a42d3ba6336b2890350ec0bcb365c412e0410288fd4da40e0bc019997144d9f72ffe79c8c790773f189d29924ed2ed50d73499fad40f90399ce3480cede2b2d31f59ded679663a758e82d4997530f930ad394c18b6dab2941173ca97c18b46673461805c12e8342d8718ae70d9805ff19ca4e0a8098df09da9384b1d389972e4dc0e3661875b10ecddba8f48138881b16179eb0b487dc55a7b415d5265de73c4717ea6bef9b41b10d36465bf9c7f9700eaeb459cbc40a4d0968de7d05e9f4e6efdb589976a45e7d4d9f30ef13d078bc62b44b5cc722e0ee6a7b219", "73b907068d50c1603b1acecdd5c9052f74b9a222a5b085e77bc53a64e35e28ed39673e7d93124c3b4303a8724dbbc82e903cf8ead6628c13e2203b4e72dddf8acd0c9e5acc735a1218510e823bde84f5ba161643c1af205501481789a7868e0351c73a047e700ede81a3f6f4d32169fae66690970d3da53b28d2a40f68424d0c8145c3f6fc047624910956d664d034578f6ce1c9b51557864414673c200121e543775129d9fe2b4511ca31676dce9b58ec06ce8d16ce279a07926ca351d2a4fc2cd73437c1f0e2c4afa06478adf5c4a7701a05396f8c19605974db1e9ca9527ac2bec78ea6a71139a2c702d7b81d31b282d88749694b15bd428219ec43378bdb1d189b72e5e58bc741fde22824c424556bf1e8cc7ea55f6b185033af144e3ec4741957ea21f82d3cd52c5da701602a28eaaa183aea03937832a907193d5192c16a68d2cac2d520f8d506c23624ebf0b5357c4c9b5180adf7d26a77fb5457462e2c7909eeb56d4e97a326745f66aec44833696548b9a3db1c0ebabb3e8b9daf85967703413ea0d8da45abf6a53828cea7d56fb321b5153cbba10855f74cef27dd8daee6d4d337f941b37ecc7b051be20237ad4afb7647a7d450d700e19ddf23fb543fbe8bca429947bd1735d1d3513446b71eafd41a607f263b55b032464ca73560c545104401328fac118cda32743815a737bfd758c9339e778659fdbcfe0229c95539ca4da6504d15cbcac07502c91d9be0ed25e27da220ef88adf52c5ffc264ea488bba3cbf3b3d7f65b2715ee0937e73c0774617ba50230aeb6051129b4aaf799245f2d2e3e57d68692e3f5c472db3901f8b6dfc1215ed5fe482445c29ed90091bf73a05634b54d831178dcc447b3825bd8b8915df9b7cbee34f2b8c7c8d7f034b0727a90676d4bb21517b337ce9296d82197d5560d94ab85bd25b9b72b50b15c4c560c3ae8d403d339993dd00a312f3f951ec5de02aa0fb335aa66c157963d20604d51ee2e09e97cb559aedd9fc131a376e4fc9a4a5bac0d154643eb7fc40f40fc906b57b37b3830c7b66a0e3dab8e7d30e1585af7e1aa6f65de02397125db01e85dda3e964f987b6d75b7ac847d1ba3d49f1583fc9ac04c556c414c0742f2fa423aa38bbe50fd31e0b021b8ca954de36a027826ef73c5492ce6fd2ca9205e67d507b3206c0d74bcca5fe56bc01d68eba581b04756121d286f6e3724c93185391aea51b618e4a12f55545c23a626bf45734d2bdc26b82cbd2b5f9d5c2308ad8a0868e74ed45a6aa16c19dfdb71289cf38ffe114da6cf0f99179fd3af82cf82ca1c15c9245356a9050af70257ae03536d8819470bd5906ec27cad40df2eb4c48b10507c82430cfc47a7b5879b3c8dc2e13559f33d7393bf80c540e960fceecb24a7941104d1f130c9b184cac5b79cf60f49dbd0d9ee5a1b63bfb8e75bd03", .Okay}, + {.Mul, "-fd2522e0467e1cd90c7f224dcfe7ad4fff0bc87c7f4b12c1ae280565ebe3cd9a81de346c5654dfee8c542100058b8926769aca7bc79431f19162eee175faaef4ca7e63b60d29f4dd81edc4cd95394446c5fab49367d9713e39ba1b86c73f95cb4913ed3e1374a6a0007b84823ad17860f189558eadd59513ef893045ae6d7f1bf2c49eeaa5b26ab6799046617e6e4816607fdb544a9de847b4d6accb523a3c56fbdb6c71793e9fcdce8c3eadee31aba23b25358c865683318e8783bd610d5b02dde0959d920d19663235fff1341f70412f41c2cdce064ccc0c76f8aaccd094c059923fe991d645780ed8c997374674a19ef60d12264bd0006fda49bf93b185da948fe97e2f67da18ec45c409d41df18f5f4ca9b8fee4d7916411c8c1cb69f2dabf1caf7aadf77f66f4990702520c678e7cf8e51a8fc9dd5c1de0fe5a382dde2750eabcc9837f2d974fcab22e3093023b109d8ef37868c4f9195774ff88d439ec3ff2304c9bb57b795f7531993b460e5d87205fd3550f9086bae15534aa242b7547663ecdeb5b6a2fdd4915390ff21fc3495f5300adef9f27d7a32c903749be7fc991521c1995f430d77de135595c50854bff54b8365f61bcc19872ecbdca5a740b5c0ec3903a4e28c8eba3a83e61ce5508dfc682706afdec25d0be73bcefbaeb868d2056a9ed63a00e14a98f7b4b225f2638618ba2ad74f1801440e202e0bce4", "a96027fb5066a61b1d92d527933003e62900076f9db6667037bb26dcab43155d6073bc8cab51fe13c4b9949e43795ab502461ac7be95207e3b7a8645234c95d19cb395d62997f1a9e4f424360d505adcfaa57dd958cbe19a7677362ead523175a28bf0cf828399ba6bd350059a49e10916b44e5bc57238819161bbdc24cc280d52e7bed461ad14b77c4ec53f324ea6f942fb5fd784ae0f35e78d76958e96f9be1dded06702ead6f093c7fd7fcdb9071d72e6e94464de3ac18114c862ceb12a2c5d23084393aafe2b76d53380027ae02b62ef05e52b40ab7888d418da1e86c6214ca822ceaa11a17cd1e1d6ad83b60ee8424fef63ba48be7abe37b5d4993ce3c0d5c3b6b976e52256e9caf2e52eb2a39bdd133289d1dccecdd8e3e6a91ae58c59d128c9039791db4b87f8adf5e82c674a1a6d2dd88be7b508643662488b1107f4c2972d8f9038a759af66fcea64a39ff5b9c64f4d739e58c7d2a714abfc1409afde73578cb956dc06c8affefb4d1e7a53ba1f19689c62e70a1b7c012ad44f307b97785453bd388fd01110ef21ad3f762457a29daa90bb19f6db1fe6dfb9149ebf4115911ea1101d90264734627866630be50d96ab5fca5bcb7c790db8d75595d74e99968ce68801f3720abf34484b50d8a05a0963516dbcf4bf8ceaeb429ba190824e0953301123abb0c4a381f26cef5c353ea242c27ea9d095f44803dbcfd091", "-a77c997c4dde28eb4ed9f891b6d0197bbdcfeee0a8dc785282b41a20bfc0a53a1b8e79f9fec473f837535ef4a756d5d8f1f42eb4f38b3145bde80da774280b75494e078d4a28ac75aadb3a9eceda2a2b5cf3b8380cfdad398e40a8e4d1c45d5595d8f0c1772d20493a4adf6afd71ac0fd36f37e98a9eab439dae63119572f875181905d4aa60c2cf2f442d8edfd3d87e325e61fe13109e3e2390ccc653f2f9deb56ab4b92635f7e02905aead2a759e9174997808f780e5d54359047a938e55cc63a44a449dc70c4d57f4196bfbe9e1aa4f48d3aab73ba3b4636051c399769f2c1211b0943cb926855ae515e73743a7b3383983338228430d58da89929348bfce46ea2fc302e254efdf8390ba61bdc5e758362423633861c74651a4af990be148704a2b5772006bf7583ef8ef9be9f45d045b30bac4720f752f85f82722ba4fbdd42336b1c692c27f48ee3a33d78e3b9bd4e26da1dd9f8fa184a59d8b0db769a892ac85d52293ed84c3e7c14217cb661b72445d3d4c4e012bb30fdc3e48f682990ebf8a83bd844f0e8681c657729c126b6091195871332be45843e77da5b2f52ecd4b9ea4c7e66dc9a0bc01054444fa23f93609dc6aa998038eb49540c39205cb3e0c2edd1d96c8b9632fd2ded1193377c6be38b326333db3b5f558ab47c93fe5c0a6ea96d4efd23f2faccb28a251314354a74d9a8f15ae0911525884c76bd81141a94c39d7a78af7d5660ed62273b3f6953f0fb69e56d024f1d500968887d76f5202d8d6f60ac30b6c939e4ed7d3e53a4f4b1decfbd3fe0df1a0d75ba3c97a0aba8518c907e4f536c90058281db8a7e44625b6117f21a64ab7bd46ee54355fff64859c0d1a758363c1f36736a4e44b20a5752c2313aadee55e720901285ea33a61ef6f93b1fa69cb30d0109cd224977e99c587b74906b18b66b82f93a28d0bfe817eea95509511d9b87a3e53df14b3a98d8fd0be3dab559dff1a7d2ceb96d2b51a9fbc44930ab3f8522cd3ba3496ad9ce11fb5b208c8872a44effc6b0e15af9936c4349e533043dc2256561b55fcaaa0c52bb54996e452b000468d6739a1a2208a268850965fbb1af5e46fb83a05c01e5114fb51bcd45d651f81bcb0d263a2e5d854b2d67a29395b22c87a982c32006d003e63693037718d3bd7add189345de421ba4467f1d6a0e0c871e0e4f27b4892f6fae48bd7a7395a21ddb38580402ac8bc8cd0e095794652ce4ccfe4067c3a3810fd815459e0619a798846a45b5f1e0b4f25bfcab0c212fd7373f45b261288585224b1d2b5b6de273930af568efef109ab2ab7acf4b789ecca2bfa7ca4717e7088f78837993422ef374785b8a6a92b75a7eb0b2e7b59b4982f8cb2202a7207f4d8faa2e8b4f75d6e52968638966b4c4456d17ae108b38b65556278a448f4e33c0d50698e44333595ca794e5603203d24", .Okay}, + {.Mul, "620ad14745d1ebb5b900d8d7cb50eec9116c4f40ae65ad206c9446ede161948c7821725dd3db46fe2d259c93b5836e53cb42abd769ee528ae1c1783e10af89ffc1d4398cc68c536296155e5d54c6a16496c56a54706c0e15b2a9592536b2008f0a168792275bd5590b3ff7572794391de59fb5289b2e92985ab4a15768900f5c8ed7f454656bbeea922a30fdcd6d5fc54183b3c4cf4ec39d4c08532c73a7d54cf6a08bd497e2daa1dc6636d807b036aba5547b5e955a8d5e9794e6d4f0a2aeef85dec46e86f65d265d3983582285671757bfb626ac2b7c52cf866945c0a0fcb11c667836b1b32f9c9b112925f70af4f60ced6542de57a65662ddeb81f1104c6f3e3ea0efe3ca822d3e3d9a95db2fb647487fca660d0611050e47a0f6a3e47abc587fb59f08b869b67e7286855f3d494a2c57104f4593eecc265e89349ce8a144da4e3d53eb5aec4bb2f9df4e2ca2a6c5b140397dd440d08ab88aa593f2c6c59a215328bfa2cf6df1cce248a0a68dc4e34328ce68475ed64cb8ed298c3e881d58ac779c141be2263d10104ad62f55172bd560e7812ff5c992b6952ffe37e743385ee53cfe019b7be01b069105e5b6b45e7ce1fcf87feda3eb1b6ecaf7571b9642a01a618ba5c369d43f2463effc26a19dace31e395b5f7b4a003823ce3ba42bda24fd90a4edb090723a3729ad77edb7afab712fb99d3a6e70ca1119e5bf104ed7", "9203c71375833717ffb90ff193322eec944f16726f7d2c333345716e1581ecee1ae719867ab2aac361653be6103f1edc6a6156fa0ba8dd9f1d0b1fc8e9761e15fe9df2334b33dc96dff9fbbfc298dbe032dea635d3ff7ba4a9c8e2f66ad7c96f04134de05184f9c3b82240109d4eb5f1fab2a239f90d1eb4399ecd5a241695046e21eb6da7e3cd21111e6a06303050a8df8d410e4ea4f4c504aa9939a24939966b229384ca7820683d37a3df92de0ffad16ee3807cd5df96594c5278e375ad68003bf209bbecfb1a9d3b018b1d630be2233aa8378c318dff66f06035bd0d92c4997ec128463d675ceef8dbee48f0de164c1f43c66e4331f09ee5101a535b68e9b3734840f9ef8464a094739e26293430a1ebce92a042b96c93deef67389f312373d5c6001a338f77a2e81dec43183bc614215fe9e2aafe2ad857db1ac5a511ab934b437546c53039999bb74e6fbf9010fcc0c5b779b94a9efb91f8227ac77ed5d7cf37ddfc3f4bb7819435d7277dd11243e1245fec9cbffcb1e39c50c3d530241100107beb9dc6d53f444d46a8a274d28d0689ee49f057f0979a9f76e4b1618729943597566695939f192a5f7b651b16eaa46c202dcd7d843900b0844a3976f1070748100115a2b89a68343fee6c0aed1070e70f0ac3a82fdf1efd233ba1ae1bd76ad4a41d067526e4fb11b977f224d51404344a8ae0dc51c2c420ddd31ea423", "37eb9db8f624abbbf1b2d6e96d05d5bc975a6898ecb80256e5137fbdceae15ce7b2359f1f29d928109f322d782c17e7e10fde87621df33dd563bf1e50f6e91e632171214561b52eecf559df52b6c864b989a14fd66160b551b930ff7c54b6c0aa9ef3a29281ad968d09226c3a5e190ee23f6251f7cd02260db574daea5fdbd7284c1e41980b32b7a57418aab4531e4cd143e85403fc6d0654908856c2282fff5069e8c52c2f385fff9c4ef83f0b4721fdcaddc554fe29d9835dcb9cc91d773c5c36a6da62abe48f27fd509b0ba4ff69f0fcb9ceac67b691273c3ce120f6bc15a161ffa18e953207df2b89e258b77dc81abc8c066d1639b4947297255294d06dc588b4019dbfcf5924943442d1cc9a9b15623c8ba8ee5449de71274701221e184f7fe8db094057b7bcc9fe58f6ced3f4652b297d8b4861741670894c5f354988b9d9c85b2e671faf35cfb7cd2d0a121855f7e90bfffbb389d26fda144bb07f8ec572191184b5d3a9281a93874b8cdf3897e408b8b72e7113029fae17336c2f149541866772fcd7bf64e24f455d4fbd28a4f826f9dbf8a30a3a442f372672846f0e7fb6157c41a65dfaf939438e289f078afa362b001b1a3b11bb4a714746d0718501b9b1848b17ff3435a46d9635c224eac26ea479930d48cc5b76d888a6b10f2e9e4725773fde8bc3c87bd3187af644611901eac2ed8a8e42f4d892014407044774890299437d560f6b436e4a27caace1f50984487a32dd9ec32d460db6a818f005bf089abc3b8b54084f34428440e1c19dcb429f40e8adbcc6e890f27b65a6cd7e38a13cd55717866a9a67fbf0d94860e157f279d048ad83b03936503de6424ef81423e3e7e8d01ff8e2b0fb19fdd5d8471f48925dc689f2549c872678fa9f75a80ee32a2a91d6eeb7dbaadd0c48e954c3432240d2d2ba7c676e1e1af91d77042740fb172540b1c4adef221d2e4ed8b6b21ece1263ab2db8eedee5645b6cdb5b97e83a16263d44ed7abc2969cc2f166bd456e6cffbf654e7cb03973a73b64fb7d45f0805dcfe7aa286b07e950468725b12f903584baa5751eaeb5b580aac1a05409e9d701f908b5e3ba6090a7146d7500f97080b6da6de1e4a566c1da3b6819b37130023a6e6703d375ee0b8d033a981ae4c0a457b5a64977aa052f847999fc76d7fb06e0bfb3d70fdb7af087542243f7286efad07cdfd3411b6569549602445401a9e815fad09a4f3ef84a672eb2d5c6d26dbc309d3c00b49733245412eb2cf26ff88171fb739dbb0d56aeb333bbcba193ef78f45a205979573beaf805ab0baf72249eb3706c62debf5eb698635a597d654a10759b045d1f2e5ac443b4518da46a98a334108b1205e2a1a07b819085ec24318e233658f6f6a078fddb588fd1e932c9b1b50efbc91991b19db8a33c8d4de63120b23b8eb23fdf7d4f03ee8365", .Okay}, + {.Mul, "2fa133766f3eeac19efa5204f1bdd930dbcf89abe69deb19d9ce21e96f2972d220dc944b1dd56f400b5189ca4433457ff0a817f5d33be1189bfb647107fe5d936090e7eb1b400160362b06b76566d8f98996d679c304d8a72d027437edaca3c26d243265a6d2bda9c7244bf6c4f1ef0d3043048c235ac8d6888752ce1cd9f69931b2938fc93fb0474db6bf6b920cf98a14c16ecac4925d50d29b53d98dd7a20d03de953446312c79b12a7dc0d54c5c831384a2ec91aa7cea80452e3e6d52d7e1cfdb15b8d190b65311bfc81f06f34a85a7ce2ba059e9e7d7525ea67b384c2a11d94ad91c96bc40b94d0fc02bb8569accd5804fc51ef9993210a91c43b78bcef3274f392a55d97438b98d5a073756386e813d95a15f6cfadd9c68f7db80defbbb02947511617ee0c189677cab88969a9fdc4ec7aa42dd853b8d3acf0e950125aebb1130ee35e67e188e9e7a1975b42d099d4608745cea72f798a1be777c05358da2c05c05a269dd0c0413975c7071280323f407aeca0342bfa905c2fb1ecd04f7e972a580b5019de16d3d521d0e26d5f714b7b4f0f1ff5c9b43bbb3ce3472669b8f322745923504663e8e17421275d978e4337f80edecf2dc67cc87f78f130b79e2f424944af70b11eaaf093310694c79ba8d8cf4c89cf853c5ac72d0d70ab1ac312261c9fdaed6ec87fb74d76b524c0a5d7a7242aa43793e9dcdc183698aad29", "6c1f53f6facdf04eb2851cd34552e20bfc83a3e65682f776407bb3d76d41ea114a0b0d48bd057f65ed637031e425cf7f384ee749cc223c931bb4c8084b6c894e26db83a83e63a6901294971ea2ccdb774c2a6a87e42d629679d81469d3309abef041c6f621a58ca00c8fce1ec0b20cbaedc14a64612893f714fa132f14368833f6f94f18a604f3299783b0b718e9b03a5b39f3c2d06af3162e5291dc4aa8c76f3f99d27b08fc857b1628699e240ce816316361423782400df97998b67e609b14ac45e840d4af95adc5a0151b96a61e6229d12f5b64e0458e9c0c42075058bb5598d60cc02623c216036aba72d82bf129407cc96ed583362a4ac9eba647a5858f4333aed52a00784c2e6e475c4c60ecf80e394ddb40312dca39cbf53dd53981a6ac8e8cc480f99d28c1bcb723a0d572272ca40609c949e4f703d53a4d1293ab55dad9fa5631a28658281e4e55db25857ff65af26890955323966f0a22a60ad79abc6c1ea4896f542af589a3ad88254a7ee230d774e52139f302c5eda4b3d73faa0c9b4f9ecbf3400dcb3dbba8b7600e7f7144d1b33ee57cc39dc75529a3be87d88065f679322a0c5e527e2250d22e5bc13814dbd232c2597fcd76227ff31068e51a6eb8d11752e0a176a726ff4a2e0499d6659c6e00e40e8548e846b910f849d6107fe3e6259e878b94ab2283e67d83de18228fb2e4c5409ff730db2845c6288", "141dd5da69869a960c244e6ceb8b5f977e9f2c1d8efc6cb0458edfb79bfce16632105c011b08ace29116fb58f74b47bc3e77793029df7073e145c6230426e875e33d9ae46a2e289dd1f5f0dc4f16a82a1b67f5f37ee85599b90c27b18114aaafd9c45e7a3a694fea2ea869e3352283d23ca4b28d179ad53fb2607cf606d6a1081ae5d465c9a8847dc6d6673554b66707b81aa21472318c8b057b7cec1e3b58c69cc8915ed81c4acb2954600bbc3ffaa12703a772a8a4cd69ce1767a4f9e3b68439cf53848e26215b600a51ae3217add6259e1409512350aa1aa436afaccee2733621d3c3b1a643916fde3f77ed9a3d29491f6879fc83624ae503011c11bfb55fbc8b3ddfb5c9a238a15ff84fcdb06ee2476de039210051f7ef23e04a41e6751b9f8efa471181c15c30c3583ec080f3acf1516cf1da73ac467ec1047ddb395237919b613263dcb204dde3ec25953f85ad7ed0365a26d13852e0540555eb88971fc7d6d18998469913dadb2e9d0f64a26d146d0e597d3541e754ac5545004f04c896938c3c421daffc12f48755a62d89f35ced9e4b7a2c1e0e804fbd45f919ebe6bdad59025ef1953d5fb837290ee1a499a6ee077feb6de98a7eba2922dd52a69e08e6d30384a80cf8d03749970ad26a3f026250da7e5a4ea73b3d754941334635a8cc4fc199f869385ce6b125fdebcb9a435e33ed031bbc2d714fbf13bad5910f474b27aa0acf34c805aea6b6ebc3c1893aaf31ae853eca1667befab4b55b6cee03afdbadaf39fefaaf08ad9da719a06f857f7c55b2510a1092dc7beb2fd8bb30b6f361f98f5802f5aac14c43fb5a42bdc24b41b209f38282ea3d5633c198ac32ec0be91feec223a724d443ed18b85d9766e6547fac5ec0d32b602d05c3c7ab6a4248184ddd33c412c436498c62a8538353d2448ff1f1363add1b45f1d298c4d4e5ac5d3fbef3b9f63ae8889c94191a1ac36fb4741f59dd19222eaee75466f0354f9f2cf0dcaa5f2c03f6acc05c1f518660b59f000959281a475f93f7883af208b9cd5e7546786f41abdd48afde4d229d0c87e66d7776e7c01cb4006332d24033958f90f0913e6696af05f042a7f45101dbbfc836cf837df7b51e57392b6cee568db3a4bdbd73898339b9acfabee433d3275c03d5fc6f98b2e0c5439fb5b879082cd6adf6fc9a4b736c47b6cc8309ec6b815ee372e1e843d444b4be7751ca930a4bc3c57cdf4f2717c37790af04010091902f02ac7d88d9a324655debb2a02125a2fac68ca4001cb4522d58f3ef777ef5687f10b5d58ee991d3bdaf67aaf311f4acfd8660e43e34b79e53696d19c8afed39581095858f678b947a18ea2daea85f8a4c68663488caacc29bb8d6bc035d2207c8f266b8ac298030f49a9165d5e7970bd9d9a03c85c0fca5ab33ae773d9d8dc7ae1d5210c7f59f4ab06d886b1afc8", .Okay}, + {.Mul, "-c0029f843ebd9c4f1efff57c782c4b58eedc228f66e1689e77648859d57b603a23ca391d481069d67d840247bd7afdbcab4630672111db04b84f8bf971c5a1311611270dd90972973f3c557dc054b95e3f8cd8dc72d87146b63f034422b0fe9b80c7b16b7df2f36fa4859bcd259a5b03fbcdfc41976732297cbf103a64b29d693450e7f83fab505a9089d33c5d4c7c6aaa6a7c6702d0b34831b047b1149f7743e2f27c0cf08ad9142ce61ebe66ad33366a2475f82c9d52e425926272c96b85976cbce7708eb84405b33b36aed7cf53c99a85b8f8fccda857e7ede59e8d47d0d3c5910b24ec5cb058ed7fe3879cbbf84d0ec69b7b5de376106102697f358304ed61055c036106c96402f42592311bccd763839a69f811a7ca6c1be4c0cfdc201e0cdff5a9ea87804292f61a9511de1bfe7bee037c581f6def93d8f1e54e42ae982a8f7fd8f168996a3d54bec43207c418f6c8fdeca1fa474193cb8e869f52d794d2719447bd5db5369a4d256fb2a3ecdbe47a17c12ac27f3107b74899683ee281d60e87e9898ce957428fdce1ff434c10c813539631efa4472680237ebd6cbf2190cdef71471ea353fd4a77820f2c83648dd19869801a2acdd29536f60ad58a1d8044e7e81d7bd219beb98b6b6341637e3faddd5f8852a2df85927e8b6a623d0aa970bd13f0dd80ba65e38b31f223247be96cfb7f85cffd79ab983a1e9e66a26", "8c2e413d0a6bcd29866124ef7df2cd2832a58ee10f1aa1ee08c7b424f07ced0b9d2931d82d7eb7faa82b4356dfa361ae3d758074e984a06a9c252875119aac0708f894a89ccf7af68875f820a83ca3a325f496a9458cce9c5d7cd9cd6acf339f285be66da19ed08d7e423b7b33f001986b249714f518df88d613ac49274d87d9b86405f600729d1033311397e247fb818757ad4c3206522aa808267f3d8c4a7597076dcb65b8c445bbd67f3767de609da4d6c0455ba519c736c26407449fdd5f38ed2a9c1ef2ad74392c41f0fde15eb7caa56fd2ef7e988496b16c03ca6fad4f4003afa39d5a892f742541b64169c061b33db4f581f31a19fd6e5b51d9ded757513a8402ee79fd9f6eebf033ae6da88b9493705e98b016de4c1a0a8eba29b6050dd35d66da2cb8d0dec39cb8d74db59f28eb97b3103bc62b1d8495b21b911bd284da83a19695143be621902c2214db42d8ad38a32194961425f047ea4628ce8cfce6f59f5fed3e1a3dfc096a5de6da987d8aeac7619de3311166e5253b57d9b6a8078b22574648233c2f6082be203a62e6db602de72367a7f5c800aad2ff20480b7cea3a71c23e2530e623aef207c24914b86edd5cfbafa4ce7658d484b6afcf3c4d4b7409bf357252d46bb2eb786374d67d3b68c613068c5f5ab8966099517e86a8b5f837bf4513e5a638736894042cc323314be87117bbf92863f998947914", "-692420a36f04833388b631f086853298f392f91b2a12c0109c5fac6f09b0b0bfaee55c2d006d4e11c5b5c4c2c72c5e658177d1f4e8f260f3750fd8e43e7af2030fede98c797816343c0268b11a28474631c9ca2dd148075f04112c7d50380a390332093dc5e6373e38727516bdb5c1c2c426aac2581b9a6eea63b1f4f264c9f7c7b004b0576e7bcd49f032bee2a18cef38b7edd10881bb39101cb0f4ba27e8def16c7e0ab0912667a312592fab5e487c65b1a9ec698a640b849e8d51edfba7b7403a9a441392ef31818c1012f2e89bf32c8f355988fa101bb8a8c037dbde3bb5d336808f8a9f1d0fc1a0fb8e68466cba1f74e2245028be2cdd1b3ae73c2da35935147a0482ab4ae86693a3e78e7efc4957c943c74d2b188b03b1838b13f4814c4c08804aa5fe72f81f0452529962f4a2187c508c9c915ae92d63a545ac2f1f347e4e4daf344a6a1ed63915b680fc98dca991db9d1d359b3b041d10b4915378e70db436b7584161005fd3f6aeaa3d1d9dcdd8e957f43f4d14a5986867f53d200b0d90a8631a027e7a3278cfaed445ad6328d2f09ce72bc1306090ac3802a7a59283761b7f3bc319c7f0681d52a938949ef32123d9973b5e9d1aaf4668ec15ac4450956c68b048628c3ba29d5b923a4089bf16eb6ab56ecd85bb93796d5f371f642ad3960dd96ed88b79638bd26c7dd7a5f7db21b33ecbc82d72c398b7addd6bd1aee070ad08cd42dcea488c310d94a8e0613d9bd45d7a2eb7e6b508b8fe3f11d9d2592899cc710fe27919058fc13015c0e0334c546b3f73b26641b829995decdb12d55c8d15a52d28446133a5809e53909b60b97f16b694a4e4ff43e5f3903f7c26052fbc57e4f6ebc60af02c2a5ee79b1c39cc6c074b36cd3479727dcedfa28c346128b5f7a76d694b9bc30477a4ebf0d265edfc292cfafd6cf539aeb28cac2f71ad8a407fa080ecf0c8fa0e3c9f392891a79539af4bc0dbe99fab8fcec1313b435e6f6f486318668c34cb837a5d53c156be6e6722e3582f2a4a0ceccb007dcd4b01298c86758587faa70bf0fdccf053f552ec9e56bd8c36a2b49df45169ce763b53d77d35116ea4f3218664d95b53d49eb9ec5cd16380afdf8e7b315acad7c380277b55d018889e69fc405955cf53a0262493e9ddaf24458bbaffcf57f8399b38b5d5d3e081f0b9b219be393c1da9c505e1949185ae53915cd2cab76fce34432413bfc3c88cafbfd10b18e65890dddbfd7d3e4359a662a5505b438a44ee885c406dc13e093c8ac5f9910f6812f0c6f903edca4d0e8c280067f34ec4fcea11c5d4911142e63081bf2e84e12e602e655665896acfe6671214c1b80f1ba81af26ad73883afecf05ee61c71654c37b1c7bc1ad586388fd7593656e72ebdfcb1f714027db25a19e80da6e1759533acb923d5328f5526c79c1542a4bc9661c2440f8", .Okay}, + {.Mul, "-3e8ab6668a52321d0e0c618589642d7452adae656e4889251ff52084524ddf92f0d49d596eb8ba22374f5ddf54f65ced45d27ce13d1cd947f4ece80fbeaa9211eb27504f7d3765ffda8628c6f7f2e25cc3d88c14a834207e1feb8bc67d781d145a6b97dad4d3e4c5fa5f56e2a4764b2f7be28b1f668203b3f628d70021014e19975fb8fb24ff2d85fd026e481b16c8a6a89e8ddd266b72aaff267aa74d8a17e198985433de8d82ec2975f626d3038a70b8868b12d926a332c4811640593a7482f89c748a4925622d60bf4942b475e086e6cf21af732b9a0079d6c40d5e455542d48f193f8c4de2a15bffe81f0b89ccf59b56d09b5598a41b4833dadcd7d88ccd54e57a280929cca315b0f9da1f412f4e18cd1babc9aa7e9de0d8c85554ad3f50f8f9c0b769552c2e578df610bde8886c0de64ece637ad34e7a9602f415a3905ff1600a2c1e13f729df25ab8c9dc070e7a0669dc59eaa9ffd8855323a0ee664d38f9e8ed0b03eba67927406f6312e2a7256b32853c50474328951c98c67ec2fbcce85e9c62b5bf3dd2e6d76cb2848b6f230027a9c4ab9575595d243d72613c7361ccd5e58ba682d1d66d5dce4b68344ec96e585c020e8b4aa760e13b97f6638fbd33dcd55dbb661c99b7fb8f63de270439417792fa73988c0a7ba65409a15a4edd35e8809bfaf47abb218757db84be96c2847c063a609c05189c761052a503466", "477a82bf96ed4bdf82b8bee73984b6a53707f1d83efd155f0305a51991250b5af03230e704fd94f089b33e30ae341a52439e6eb678ac500f7f4bbcb754c5ad08de327fd26ae480c92741ca8a89e90c3974116ab63c3578f7cd93e6214cacb26e210b238fbc239ded7ae4cb45375e02d40a419f6b02e8e2130a69566c9c9ea58858d213a04afec281f1127d68513474ed9b2f2d9ca7525cd68baba89c1bac23878408acef7f546da116730c2683e930c194c216eb9d7007babb07ae1e1a742d372d4d2fa3217fba831b2fefa084c45bd3e8d2ec48bb23b85d2f581a9a6b46138716cde65e21e714434912a46386d6144bc6ea392e9f2d4347ecf6245fcc824fd34cf72285bbdcbae84230083b653e49a1399dc920f86c037e64897f9fd6370f5001c06db1bd8c691d47e2b060b0860eaba953e4f20f324f43fb580c2a0adc17fb52aadc505f8cf1d7fa56a94c172da71d8cb85bbc3f080fd27fb4beb1cedc2f259ba656049917205685d7fdab874789bcf214264d61e36580d1df3b5fdbb0b3186b0052f2c0206c5869bfbad80b2f6e1f6eb1e9c80659c7796ca99da49c58aac63d421248c1e1f8d7b24ca0e2a8a32e27070fb2a775aad59227ce53a34a99e060091cb1f6dcfe1b0ff75e222c83eeebe15994732bce8ae1c21c80567832970752e27fd15c044cea5da310cdbb1b7ab208bc73e62fa1a55d98c9ddbfccf5fabc59", "-117666a29c381fa511b2fe06e1736a3f253f83f57e754367e30fec28f16c336b6cc7689affef06e5a6ac1721a5a2f282a148a647d00831c42f7facfe54f1ec75d1049b4abc1f4ea7d6be0367370337b3d9919de963ed97d70a8c2a10817ad91137183405ef9d928e4d0fc9ef894fa197dc79e901745d6ced7574ff3128ed81ac6ac251aaabb4760539ab85be9a1b28cf0dc289a2a719d255a7cda526a2047016fbf5363651cb937d22a8baa8d66da980b47fa9e3ace64345fb12f2dd4197ac0f96c3ba7df3fc0ffd7aff407ce00b09568672cce5206e506dbcba621f9f5c8963f0ba68e7b0eefb5d3614aaeb7f35d297aa4a672c91088ad93e7bf54008c7780df4ed0c836ae5e291212d99fb72f2fc08e110b53986115adaf69fb14fbd83976ee102786e48963e747de20fd529c0a6627b665b1b7f15a21103e579fa0e5325c3160fee29fd2369ef0f4d1a7a6c6bdb2ba285aa28686274f599b4a3839084c9d48186367dc83b7da396d831135b755c11a034a0a93b64bbe80af6b886ad76f5d23e948d9dd9283f35cb3cc10c3c8231bbd662ae01930d1712bf5d212249641796df692b6562c686dab6ba914f2164a5ac4515c8ca9987e2c760afd4c167698d09ed737297975aab20ea92d5d59c7cc094768bed5a52e3e7971621ac50df4d4418fb9d153a29e15b8f96fc5082278fe13312f61bc775b6afd5f04145c316e940319e2bc3c851157ee3b69e6d90ad0c9bb356d7e459ce3db138406c28e0650dda3e6d045d920dffdfc72768acc2661e3b77260a5f2e72bda034586ce2cc4dec21e9c480b696888c0628524215defb3f420c55ea05330cc3826548b3410a45e496cf4d32ab5e7ef11f4a4e18ef9652f4c1e4247f52c63fb6740a9f78b5e10d62e2d38d256d884fc14e1aa313ec9c32cd8d4d1fc1d587ca36f6baf672fd0fbc31cfed2360df77db57d65cee15f8b52a2eac8683deb64a076968b20864d4907eae83d0c9efddab657288d5dceea7aea195624327be42e7a708c0b677dd5c4ecffe223656d0a08778e2aaa827f910a200c0b6e0c736ade056c962e3c71ab6ec65ccb8393e78d29b9cadef5f076092c2cf6d2f7ec24073fd13065821756c199cda7a8f1c957d955110859106eb1d4d2c22b0a5ac1fd0f6a11b4201092b7e5f203d4481e1126d584294dc36b4fd3296d415428860456727237663ccd81343c70688c26b23d88d3781989abf6202371eb253bf6d76bc908950b829802e5dc79e4a801e45bba1af95f45fca0b8e725d43e27ac7118d4a5c9a57fff04508610de32f059ca8d4cd18f2d393a6c5dcd7a26b4cd5d49a1e97675b016f628c6f801f35987b9f45143e9aa72a409fa9946d4efb11c0b52f6d97fb1338bab6db321c763fff5437dc56516002549f076a291aa545f138aa28badd7693094574efb6e32a759f65f91f76", .Okay}, + {.Mul, "d73e5a1cdc92e780308dd3c3be7f79dd7428e4758b3734ee299f3cf8bc576cb0cf052eac4dfa8dca8b864a01a9ade533d1034bf547a1bd87996c0c940ce96b07440e21bc96972ebe06cfbbeea9ff4f4fa6cc3b3330dff78b44a6334685995129096ca59485e90b6d24b9532b626a1251d56e0a1ac348016b33eea86ae6dcb4efbff358e803ac7f12c83ca96f7e77490ed4e92305a9bd4edd978460f1ded0de434978065cd306e63625cdc43bf11ba24c444cd021d2a31d86f01cdceac176227e74f73578e2355eaa9b67cd6f7eba3b0bf64df96f4871900e9f91d46a2cea2a1d72bd92577a2955f87b78d8d288e2e79fe2cbdc6fe9aed525ca886e9331f22da3d03434396595d864bbe253237e8f16e38842ae0d67351777290b3baf0c88b001e6aecb9711985910bb20beb9cd49548a147170e8801ddb41fafb174d77788d9e903e0fcc410fe39072187038e4363a8a0301124e113bdc6b2b9ef05d300d69d4e46826e6d18a82afd55ab4692723855f1a069b8c0c5cc25efbefe510a72b0281c469c07f5ad704095482073bf77d7450d1b8a69c89348c210575d7bebd4a454213246af08e1958e448833636923282dcc69bbd4502a6632c22b0de2d3db36e2b5e57e9c21d2a454c246d43fff89490cc34b318cb9e34c743b064ce8e0fcb5dac08d1d015a420e304535cc07f2464b1abbbd2ace910e54fc0b59cd0acc282ccff", "614c39cf5410f863a46370ffe011779a85e869c99b6c052046109cc12bbb47a99f3e7bbd02984ad7eb4b243a104bda78c7aba2ca47bcf870fde8f432422e795f8ea76cfaa5c0d897e834657cc8415d1dc7f89cc036959761a3ad851dd53364dc9f50220ed6b70be37ff90c421ff6413ceada9bf4cf4ed89e843fd77688a1be207d6309545905f6afa106995e5e3e510cef5fa6c94ffbde4f311f62a36b64cdef8729a6585cb7538155411f19b9561ead45094bfc5f12f4f842892680249cf6eef5a9ba71c83d888b0dc4473394ae2a21df321330f3c97cb6d9f5d27a83a09ee01cd6a4913f52f3025fb080e377ab41e6ed0ac6d6cb72e27c79035b59a4840d1f521abfc4640cb623e06c8a8f057585c2e6229e72e3ed1b04ba77c351c46426d8404d9f83252533b7fd00daeec40c8d2d341029765ba904b23630fc130c7036da715c3a75135dc8e1fd878a92133cfcc582783b4feceaf314f49cb823f4943a50f821124a2639a68c7e9ff5b9c230f5b7448aa5db1761d8199afec092cddfd79dcfae5e7dee542f4f41e696615d0ab78fc4ab72e9d2aba73ef1e56c57f1e80a71b81474a390325724ac1927e4d5e11ef3b155dc66580ba0463eb9730aaca826b77e31159a28fb2d55dcaf5a4b65abbe554c587d386123e25f7994e095c9d8f27f46426b692ecb9dc6601da5596dc9d66ab3185a6f30a4de809d1d9be1bac56ae0", "51ceb742e44f2a16a5973ca4c689fe96eae603c0ccdef3f8dfbb64d8c17556ef89553618b00de6767918ef5385b6eed3e2c9cf99a91340ba50999b56c0ef2bb728941f25f8d2c9d8ab455939e4439dbf127dea66276c66d31b9efe59f334e1d9539a6745e67894fd1fbcca80b3164df81d497ae162db79486e01a9edb82ed9917f02c84a30caa8e478e041fcac6923ed2b959720b57a06448e4bbb37a5f6cafc64746dd8354811f63d3f7bdb61f845a9df8c42c9954b901e73dcfbd52b5c3a8e9e08f0fe91a4e36d05d00a78427d9f636121454f5674e0044789be1721014123bdc6bd9812ba38862fcae243933bc374f03f43a6553327e418e29fefe7e6c3f84f658c09164759290a7fa10ff1c87b14538eaf13963c5771c8460d0ac05bad06b20d2fe2d6aaddf57b808b6a59b215ce806a9cff7bf4807b66197eba4494557f9ffe7fc19eca5ec49d59c16e2b43ea6f1f1fa7085c026b776043a4a8851499dcfdeed32fa3e8f3141ff2c1be545a34446d7ee4b4e4f134cd179be1c5caa34b145219a93c5096b1986b75e4d03a440edd32d4032550449f9fb3d8e072391c9e45f29932ecb0043ec852a6be24fb85f70c053a15975f2e415186cd294c4af216c1860d67c353f92ae9d2da89f0216264fc10dfb3398198c2b56ddd0964779be6ce7c2cb52f94c9a64abc771e35bf71e2edbf1f4ed52bac86feee2e9eb1ff35333670ae1f23b831e85898becbab7375311ccd808291a8c3ee4a4f15c726c710250a8b3269d218814510a174c28fd2b8e76563bcfea17f659e0744edf97fab2c3179c5903b7e71019b3b72788cd001cc011fad19ac38577bf1cc2ee4203c7cdf514e125087b9e6eb6bd25b9236f2ee4a2a1172157e3628d492b3dd9d48a73d677724223b2621949c26e4791e01b7eed1eeab59bb4a54750febdc0216362c618fdb784b6f56ba254d1629e6034a03ea80456066903362c1830f746e2aa2b1d9583b7977e2d0398895fd940456c3cf40ebcd3aa12f0835c4963f7ae6456199adbcd649a287576943be95d9ea1739c34216e3b2bc812dbbf3ec3cbc1d73ab6ce1c3fb2273bbf0fd482eedc80b6cc5a5ee29a2c231c44021ff98f87ffefd621842403ea59733ae1a090d5971f643b386085e9d09c25d6426d73b9a7f9830fdfbc50857d80ec653d5409542115963c833b1bf82477460aefb3c53be76aa356a4eecb306f73429819e00ef53ceddf19751dfe0d768baec35cf23b41c22206bb0c2fba7a54f50fc78614cacef1fa073119c747f867445b4b95bbbaad0249c04d9e04d342e2eb6b6c6432d6933ebb2e2e5a92e29ec876e11fa298008c326a370b166d5fe4660a33c98c5ea86f456114efe2498bae44b886cefa53d4713d2c9b9df5f29424565330e1fd584cad501f6761c495e8880a898cec044197b28c1b4da686c618ff520", .Okay}, + {.Mul, "8a53e3a41d12ac712c413851c5ebc9ee61625c5c60bb3187e0584233a4b8133dbdc6b9ee3751f56c049965bb65f30efa7783dbeba8e8e6f74285abf8135d61e87a5cd667effff88e391c99d560281971083ab7117ce10b155f475cd8e1a6002f6973d866a71889bc753db1aa1f7fb54f1014cb065809a11a9e6e0d34e945f6365ba9ba9c09e987c28e8ccd6b12128a997c672df891d969af7b055e79e3c834772d2d2a0e94477731182aba769f61fc6404ed22e9d7532142d4630a4b06a289eefc7f77171f6e98904bcae96cda80a1d53f51b4d064a56dcbed3acf62034ef5afddb05c13245edffde1bc214574cd8008869a25cc696fb60027a47d03fdcb57a3494f404f3559b90a6c54244720faf074710d0d6e9b286cf9283a1d8bfc904e4405c702341bcb9fe30edcd3c5d13fa87d54ed42beac5f62a1295c13af164de56fb788edbca51ed83b4edee9b43871d323bddc2d45a06d1d7b1ff0df7b05bb197bfde0db17ba572f9db42d91b1f060f164fc62125f08f12e49bd597585e8ac5990f49654980dab6f2c9334ff1516d06d31fc6ebe13581abd081db8dfea15649842214998bb73770f32d37cfec17ca6767a21fab8948176bef04a2fa2e894c716e6ecaf29b927289ff7e3c30496ddfe47f96921f60ffb8bc6bedc3d5b13faf7fc3c69fa50261ec54bb052cfcbe73990bb6cbac2d9bb4ae91e89de3def839d7493bb", "9395549643d8473c3b7ee81dec1d9f54ade8b08fe2b93449930261c12a51d58b1f6732f2041e59490f30478518c79a179f724d973ba0d7ca652efd36d8540359e7fe72f60cd2a6aaa6739ff0eb421d3457eb3a2eeee0e69601d891f62fbf37ac417fc5393c175ce654dfd5a0f4627374d6a889d389de05259512e601794a5f7e2755bf75934b8088c662ebad9ae2f3bdffd2be4842c4bbaa632d87bcb15e45ffa7c48090bb3500241f48141d5bf88888aa735b9e3695649cabc43f0f7a729b1b7307e28c7ce631e0a3e973df5977a7d58d29e34bf003a30f0a429eedd4c0ad57766bd86b360e89a791d439cdf382150053c37f2fbbd1da47f6a27d1699d1b1d1571f2daf4bff6b4c563af5e5bd152e5b094f37ad2e32fdcecafa12173624be94bae48d074a180135deeb60da9f6b0cfc8d38c9b02604867a9edb3b02f387c18beabe2efc51a148ba9220416b29e06547aed6b2836bb7d6b10d0d5ee3f20473295b8538889af464c5baa7cd43b80b8cb9f12d3c447bfdeac8df770f506516d2b6c418aa6697a569e7c3d12501ebde975e4de3b7d40d5db92fbaead0ecad41fe2c9d28437d02593516a5e4a49e929c38c1b61ae1fc90a67e5fe16e626c61dee633cf49a2910c94ba36aad06f95a65ab34d9c7b42ccaa1ab0cc55ced4f074edfd03cc1f98ddade276a7438d11401578ca5118a10585d8febdabde0d815249735cc", "4fbedc3f73b8b27059d493b93c131af03e59c0080085e96967abd10320c7c936ba5518cd9eeba0efd70dc8d0189ad4a0cc3225ded16705afb099ea3ac898bdabd8bb87faea74fea3884859b0e58656790882a8cee83d93e70edff6d45fa1abe5f889e29029f4cb9ffb25d3a4cd008e9fdf97d38e0061018d4883ab1e9b9f88b78d938f5d2a2a5ae6c7158467d0e06368171ee923ec245cbe2b6d68e2fcf1ff769a994bf25ebc49ed8d577db19e1c3b6b0e1c4f9dc4367b543e46c5674c7ff66a8a33820bf1abf5c9e79908392a4b0678191280e858a182ff8f839c095857742b8335609f641272e6992a1a92dd6f6e3f10558f8da7caba853d3917dc9ad5fe53d1ffc6c48aeb004f97201e462901e19203bc6fc2fcb8459aebdbb0dc857d948b733892aee17ba329d96e16af496d2181afa3d1b7d41af851af6260d1e9ba4181d197d8e565e0f67453318963f43be3108dcd6950ab3b316cf326905365de4b6e2592fbb4622ef35f31ee2e77678f203899dc34d8e0e267c383d3db1878908fc59ce1d40008cdabaff5651259a8b537b23cd7f74495ccaefc992ad3a4178bb1461f741bb30594dd9410a4c8852c808b9b6ef16756837d477de487217b1a60d3624882f23485a508aad756bd3b6133766b5597ec278d375cc6ecfc096c1a57bbf932e34d5ca8799ecc2f78660d99aad39cfa83af00b00987c56104ced48e8c34448f16b545979c85c1d9da34672377aada6b1dc123bc2af99e21e1c82f69cca66758d9cbffbc3fe7107f5511f0054cf2af65c682782c567be8d26ddf67d47099997172b04ee350e2f458435fd0d46602d661606eed03fe55c02741c958b6aca8a4da030a98ac4635fa36c613cdbef13e05af96749800f61620aea81de7a579d904fc8558728c6b13197040111ec4ce8e2fb50a5cb7e47ca8ba5ab00f22a1d3cf105beca742ce214a09f89576d92cce533aaf75cd53adf956f2d5636885230e648e08210c5257a5db5f4a30ee964301573aa4cac58ea9ad8bf88b77997b2edcc5f90371b43e8c9c95cfc948ec5609148ae422bc187412b096e830f5a330e23ce7d345cd0813cd4f8e898e31b8afe7545ab48645395cc90b998e9968eba168bcaf4fcbc1a903ead3c64af8a8142c9bd70abc7cb20c6b2b731b1057ef90181c54a208729ec6070a08013094bc76145148ff86a4d444390f7f9e7e76e9c3a77ea4fdc64e60781b9c1d8ed237f20b49e3fc06bb3987b68b596708b1ecd3fd2c787afb87db9be7fa92d75e5dd68658eb1c30a3436bec63e950a46bab4b163ba4ffe561e89a64cc51a19274f5354ca3b2c9f654e73f6b68f6a3065038314ce6fea2dc7b2467e026d76c68c66fa94c89c362f9041605d336ad355f3e856e13c0cc73f391419dd056043fcce41f6f07a876adad63d7465d2172495ad0d4e8d475b0ac87004", .Okay}, + {.Mul, "9e940259f79d4ef1f999d00f6f767b962985aac85c95df740f5f959a11aefde216bdc978396e8442bc6eaa4d6991ad3f3f2277334cc7b3f26c323740a228771ebc72ada877e78deaba50e97477dec3a70363aec0340ea9749b862e0479312a109a24fb17c956bcc1bac892db07d78cf5a4b712acbe61e133a20947a37a022e33b7ca5b682d16cd154f7ff6d51e2dc529d40a8bfc51f31f45a77e229258a1c5cdca06ebc7fc79f0acd0815dac60269350cd8b2fe9d278d3bb4b4973ff53dc3e2d14e50d9250fc978d607c58013fb2dc190119ecbf5ecbcc88286d25a5bfb4e7651d79c8cf73fadcc99c0439152d374e6b310ef09319ec7508a7cdea7770add498f032cef0a29f30a48df29ef0e4a25bd8e21822c9de9fb81b9c9c04acd5daed58999c0c4f2ae611ec0b787c6f9c176ae10217152b0aaf818285d9b6fa778c2ec9e8c90b5720629aa80aa1c14a0bf925666dadefa4aee8ade0ae2267cf87e704f931c40aeca1b33a64c1b52aa521802bc8638ceedb7f2654dddf403653b1b956212d4c0fde1b6f02b6dba0f24edf96e3705af1b9046e3c177dfd927d62caba15ea06cdf3d314ded037188198d32fbfb64b80a57fa25b11dd82d58991b53cf46a31410ac78f559207b1875db7a9f7bdfb40152ec5a56c73b3add8c00fa55a80a38622724961d7ea46ca698186bff4ebdc4b1f9a3b25e24141968b51672203d6436f", "f9bd42ca9fdae390c387aa3d239bac675727b5304c9d0a59c0f6380a09f80de6d78ac2b68f26343be83629e4bcc0d0178b6f9c17adcb8b4d3376e023b3a8a6f5c5f5989cee04161598a990b8f277a92e3725bfaee91f122884c50c0cbf82354f0edadaa91ca2d915c95a0538e7eaa4d91ff509b3fe4e5a5f8a850af9cd0cf36ee30e68a1deb0314f5c5f61d11e3c8ae83cb2aae28a3fb3dc7cc7fbea85c20ae70731652423e443054c2c00ee506e12b15063d526232c9cc37ee74e56374c8d264311367d849a0f1db2d068b345a81e9cee593f93466756ca9dcd9ccf9ababb9cdc280e7db59ef3b2cdc72a443508afd76bfb9519aec35905fe0bcd0f5a967453a9a4421722726a3c7a21cc579eaa527e55d231d81921152ae6f680db28299d429e53d62d90bc75c39d35336ee25b813efc0957ebdce8c6e3aff9c4f18b2ffced1a6e5fd4153e7d770d3894311a79831dcdcdd089177e499b9599c793302202b64d1f5e778a5678ca7b0eba3cb2bc11728bb7f318377deb780207d3313c567518b9a2b4ca6c5463e4307d64473086af672650e5a472078829686ccc04a5fca9e9b4caac8e963bab176d50bd838353711f1b7e8a810acbd4b4cf0bdcecb6e30b5a778604cd1648541ca70a9ae16e020cbe2481e847a0f3e6ced4a506e264b6a5dca057b74907d306c5cd94ee71e157ce990d3609a470e7ad6ad537d74ae3f094ac", "9ab332eeeaae623760c3ffab71551cedf111215a3fed64b46565770cdf973768ea08c38f5b059d0b8de09fc23a8e64cb7fc9d5554eac3fac5678e33d81a5661a9321793ca7fcf7ccd7d6b65da0d073054194df9616a7694a4c67506822ec52651e1df92cb9663bbbd54e80b6ebeb19d03dd00f4a598e899f280f9dd95cfc7643196dc492ae7ab527125279e851f7f230b7286ab1c9f7b50ffdaf42a77102b5a2506b9f163b65267447b7a43daa3195122b2a83971bb6653e5c29b3fb50d8ea45afd10b791ed93746b3276bf802f39f5e9ff53683bfabbde4c01d6100563c6676ef4d2584907c9fc5c15070025e609e032faeddd0bfbdf8df2128912eaa8f9a78998f08b5d89f72fc901941b3157cffb05f306af5104bd097453dc6d1e71fa30218c17e34101fc433864e7268a1c9c1f3532c6398ec60baffa4359c8119d61660427214b8860fc73ec16c52b1b654e9943732ffa311e0d595aca22f2a0252ce66b767cd16ad3320972571122f88a6708312501ceff5a8f915bdc0aef5ad799c5661ded61fceb8b6ef9cfde870eeedd4607ff750258ea577b144ae3eeac40734e7e585db2063c6ffd1dee395b1ce1eecd955939a855c9e2e5ddfacc9672405cdf371ccb13cd93c600484945333d6541f927b26e192d084ff0fe91bea26274eed5998b231fd7967930d90ccea97189035f12a224aae60c98fadd149507cc6dd57e031247dbd48ffb4c0198ab4a6e7fa7e73a187505da5735b80e0b3a2426a74f3b7b9130a98faffbfd339d9b86ff5db46f68fc57043605c81d2f3bac6a31008e83298a7cb6d1e0c7d1e93249c0fede9487a5bafcb70b0b6f86c93f08859ce7efe7849dc2497e25363239fe64a5027b2483d653ece98ca9fdb68065767d329b942d688fe56dd4a6846dab25ede2f845eccdccd1ce51bfca79af925e66908bb66c91603fc178451cb93907acc7fce66f7fd640f10592e950f28e1082172fae36008fa87e796c5e08ab2c4b85148a11f56ed2094fa93f57fe671ebf3bee98111eb276215ddf2ecdc2084cae82d28e0140a5cf0a54b9076c59023a36591f6748fd0a924de43a125a5ddb6b0fe18f7da1690687e3c9ca13da07b88ad8d2f197555017d009ab1989f9bdddbe9aff193ac8e44fc832d0694bcc77d204d90c457c3aa2b00076fa061c80ab67be24486edb5a32d2ef447e43f257c57ad903cf43bed2ab3729b7f577ad172812d83926cafdd0c0641c6cd68d40d4099592ccf90e883de5451c4f1ca540624841227c9cb40fccec987f15aabd7a21a8db1df9d397480f2474e4600e3834104bec2cc61a0c168cfe358517676f1be5fa9a5d8b124b396a7c083c124d34c212c142a62ccee4c02cdc6b50416ca888dad246119ba3c465cac9fb66dd54c5f84c8ad48247aa560098d3f71497cfcab0a9c874d9c6a0642d318017a94", .Okay}, + {.Mul, "8cfddcf7faff8a3446b9785dcb59ad2779f0e3eb6ab6cb27b5d2e2932ea2a9b8f9a7144013f0caf760ff55f7a0f93e16e8a258f16afbbb22d1399cf749b7a4d385974410845d3512ae69b30793dfe0d84f09c46d6bacac1e4e1cb9c7382d84020262649dfb2c7b06511dcbffe7360e99a800baa37f333556c1ad7b4612a753c49084288cbfa561d07bfae6425ea19aab6c2d664df91114669951adfccd35051910824c6df99c53acd4aaa7ba1a95c086ea54e278416fef7b26881787486ef7edbc9df724463d80cf855458e0fc709f64d18f3d2627607aa6d7a8099416e3dc86969e3bd98be73960b9f7afc46adc10676fb3f2ae3cc660e3cbbfef2ef3b1e1d2e3ee948cda3cef840a8b5d4d2e63aba1e4cc0b73b35e49101088a4f9d993fcb0fcc798d7622545fc4674a3d283727a143a0e0b2c6bf763685bac552bcc307d1f855aa4353d2fa912a9f2e51aa15016bffcc5c425bcb4c4dc2cfa0f56475250fce83f95b169ef47d2e3093ee49a503e28c9dbeeddd1b66ee2e63afc03be9a03da378508ad64c6d35d3cf8f220db439e4d81f66cce5cd45ffb2f1ca2a9868ebade68d26a22a39b0a50444c175e53b50759e0656c95d0a9a8c43be29d4d6c24de7fba9da5fda5e1952cb57bdcbea10a27f54a5694b48e5f302891fa9d2bae43c4c74557737b8318cf13d7092db26fbd973132778a97d49a43e44605ef09a0be0fea", "aaef32a1916ee28e670621ab3f4c08175810a7789f60de216e5768fd86f43c74e3bf19da6a3c220d179dcbad20295c17ff67bcb70b04b58153efbdceaf944c4bb8b0609f59b78930638ab73465d1a80c5243ff79fb9a02cd07de837506aca97ae1758759a68bab2afca6a9465e53a2c92f2ec287428799261bb61b4dbf6b6417e3ba4e07699209b32ca1612d60ccf04c66bb1a4b03e985d77006d24b97a8e30a74d0c8cfd5ae038b7be6dbdd8bcffa9843047926a8a40dbea1ea958b9d3cf5393194ab5d59280857c1b1fc8a466b29a047a278cd69f9a4a7fc2caacf4f5d00faccf411bc65dcda5759ec43d0cef09f8a6988915741ecebe433c0b3f7e7696b677bc6850ee05ff1479219f249a9384ddab5b4de998b5e5ddbc0258ac85fa872feb368b1d765e6bf536698e0f0e1c74181c0b9e018fc586577f7c47b8f43858539b2a762aa641e8ba1e679d38ebc3d63330787f25d5337156393e86cf3c30b827d9d1ad650b19d75ef138332d733634f4408e03cefa3a990bc4ce2065bb4952cf1c2bedabcae2bab97e50eaf643bbc4032d4abfa2bc10ec18d1fe62cdf6a62d82633aa1da76ab45f2ef1f58d128e81a4eb612d763d1b4842db6860874c520b18e546c70a8c789d7ddc8caa6add8f566d0289eb5cc3e065b096ad42bc37fd112b8c38e1cd0bcd575a7925a17f41a4bbcf7cfba644e5e1eebf54c05b2813e6c5c334", "5e2451a0891a495773d2ea642abf47825f75eee9cf9eff1220ed51a17ba2a70af2d8670fb836b3e541c7f1ed470f0fa26327a72feffda4ac4ab922f8127e860dd8a084dfc0659bc2c934b13adb1ef0edccf498e00219b83c4705a6040cf61a1442a70c1eede5df366801fd265d2c6a6fb88a17eb14ff1d7548ab7be69dc8fac129944f3e1f98ec137ebdfc6ba561a3269e46fde034ba61632cf0cd198495f8f28716d6bda00366877be76cfc2f43a871c99e04179255058ca61ecc39f7c813ca5d287f4f8ae39bae4a78ee5f4cc58c2ff029eac54713d5426b9afcc5aceb7b6b5eee4ad5ae23f5cba31f94d61f581721bb21f9f2ae9169e958ec38943bdff77fe57081a7688da98ea6f551ee1ff692546a42fe48a8f85f13f6ba047beda5d7f0a4a842b4e350f5489b1a3177dfd12aa53ffb6b6f13db7281969e3236c9e1994ec6d9dc02f7c3f01ee88b1ceb02c6540d32adcf4042ceef56683a5b1b22595544caeb722dba1c3d191664d0bca49560145b111df7cb2ebf608c65ee0defc5106d696ef7e726798b248baa06a35e1d6caf1413433f246c0f974d8186c269af3700ab40377f71ce929d639bc807ff901f916b18a432a9bfa759e4951469669bc28cfcdb4c85138935d6a69f2c0c9639562fa36174242b5d61896807febe1a8fdd988c1fd9eb59bdb2832c318957591a9715f39ccb6916926404c2e6099deb6926b4af923ac6dc3b8f21860481469ea8e4bd8bc04997681671ccfa7ccc6b93393ba6d7d34c7001e27c8e2f3e3b1ce97460520607f517e85177900b34594365075efd24e4ec3d4e37d49f575e89839b1eb551aed7d59e499e4a9c65c8bdde8e0b28cda32e1a1ad880c683bbebb152ee375ecb92d468b41d81d6078be6cf76af5460819db901e98095bc67388d5ca2823e87c43bef8eae2878a01c9d0c0155db5918658a045162743c2dcca1b88ef0efa0cefc2683a28d168526c052199f9466f54fbc0ddb99ab2083dcce0b0a183cf0126e67eca6784b55dc0a5b93161528cfa11594480640e83282e87d175b0c23c2b12a16410a988a991ceae32b1602b2cf187450b2d1719b0756ae54af6ad8a034860749bd19ef41613ef2303d151667d93504ee61c70cadef0a93f7020362824c08f1e015bb91660aad164bb6951a90b97c5327ddabc3d87c118e5da09409eced26bdda74ab9265c0f56547cc15509e91f5f6e450e322e19e58d7e873f06b1dadc03ab8f75561f8ec7db5878189056ee5773ccdf47dcebb86ec2cc74cc5a7aa78bdf48eee13f493429373d6887815b76770688a8facbfb85ab17341ce098142f5e8b140b0a92c0c828c1cd009142522684dfce07871de128c6fc1989b6b86e3c9c955cd0db3bafeb449d44dedaf7b59224fd36a28710da14c9b09582b3d7bb18e5f7e70b5ea8cdb592da0241fe21651e7cc7988", .Okay}, + {.Mul, "25c8b2392bec17896fa8eb2164e783a98667a14e4ab540cc0de75b73ed569acee539ce3e943ffe7e960d454503728df0f22236adbf8fb92af5b2c98994ffb8072a808931ecf0bd964064c2c96d809665cb9ce7a8e58a7ffe9c1cd784c548668bcaf0259e38e8c27a72effe3347390f851d9f18e42bf9c0e84ef3f3d80e8f23704c9566b7a22aba1165d18d3577cc93e144b70c3b75987db268155bf3dc53c67abd7f687514c21043ce320d8efd1d9df396848f25f8d6746267a4c3ee0dab3d734553054f66e3d9780f4505230a9c5cfa78486453f17378cf22a12f371b8882e135693294074b7b6ee9a666bfb654d54036670946bf8fdde526230372ad7e392974edcd9fc5220368096df1356bea1f2cfed93ffe99ecf9225f37c7a0198237f5e5efd730a91f252738c59264fcbd4460fa894f7d26419036b09833d472bcf317473a448fcb1e92b64f9d0f7d37a7be3aa1cf1ef53d1d3f91562dff398fc0553c6be55b988d7cf0d16b2c754c36d38124f0c91f4c0837623fbfacadeaf2bf47ba34c18e0084685aa8f4287d29a47da3f6abdc6ea66af8fe60a915fb00d9a8932b95a7e3f6658fde311f744f17a55372ad9786ad46294b13d610cf7bf879a81a46fdb191a345a3ee43d14a53c9e4cad10c148d91fed5bd146c659f34fbe7a850a74e964a7274a4ba89438d3eb46f28bfdc9c3664f8aa3c8f2b56846c6d0d39f20b", "d6a31d45efcbbdc2af29727ee376f0d34309a4d52b38e3374c2fcf653f3a385c77bcec81621926b466528ac8e46ea947e65b035c7863209433e3db8c8f528d440739b3212caf2d2ced9f02607e51535a557a4c365b863db17c8ee3c498ef10d37d222ea4ccd1bb5fd69fc27b275dbf0598c75bb1af12d48fe9ef640b768463143687ba0d860a7cdfb2a3f076e940f7e7fa480ab227d4f1993f6ee7bc272254f69f1737349895e8b6d0d22b1f7896b9330f14cff9303a33e8c7c24faf87b87fab4917a14c01e7c8970716137e07147362b2402e39f5c3c464abd822b3880807d03652485e0972eb3e3250e908c8c52f18923fede4aa1b28dfd27fe5f474eb720566ba3426eb8c372fd86367c039c33611bdd6d94672265fa1badec94612d8bede41a30d263796c1f18aa2aca19f3b95a5ef8fea4ed44377fc3f6de04f8a05d2269c25305e08fcb507d3cee4e403a770e4882d375da25314b598b4cabc077b8dab6c194e5601197c2c364d2384f47c875bd76d2bb1c4815fab3a64d0c8c25e4e3771948b48ba76c339a172d7a011f64c76935e4040015621bad2cf31ce4eacf0b17115e37f799c6aefaf391c4e4699cca9ea6c7590e0fc1d683d4d2ad37250b18b635aa356411199a9b128ea9ec2b03382be8ccba554a0f6b2c1a29f95e1496de7409d1fb1eec890e4f5f0f86a20ae5e615b05c8ddf5794fea9032d0bd893a96f0", "1fadd81753cb46ed1003099d25319aa3929d11395c4b8fe9492d8c5558430e23e30df64f3e6ccc1e3bf582f1bd43361108c7a804f7998612d34ad9eecdb036067811c2d8af4b31b7b303764fbac51d13674cfce87af0036a2de1bbff2671bd6bea120800a19f21dcd3ba2ca0a416c84cb7f5a6fcb9a92050b0c59c570399dd9470e38406608ab95bc1794d21a6f3aaa2c6defea93dfe6b027c84f146609e97591407053946c3db405783729d9496d277c0fdcd12357d033ad48b35c83863310ef0481c744c5f478bc16ac3d4101cbf9ecd3f74720056e714465cc3f20d2c34b2f823c86ea945cc979ea3fd76b23960a685e65dbf6f0da03384c72c1b846be7b97b72fc63dc0640c9e14f5a2ba4f5dd986f0b6d9206b97519a86d41fba55c3a217bcde61836f46fc7a55b96058aa4c170849a6fa0470a1f4c33b245942c129cb62fd11f42be12646e1e352557b1bfc352d491341920c3c699c873e25d1d70ab577d0628de7f80189fcee5bca8410dbb7314e16d1565275cd23d27109dff8bac47bb74c10e7e302cdb338d0ce9967a6cca73d2d904a4828566c9dadbbb9a0c157eee2c50ac136784cc43f2cb5909868957f915ddb7598c87c2ea3ff5c78003891a438db6a695d8a74e55b083b69ef4c83369f9bdcf4621d06079a6f0ecfd685fbcb2ffa5840f9d8ac8588f5feab0b036e2229133bf1382bef01f74f96662ae62139ee256bc62699cadde7d50671a2fcc6311ae282cf6125ab1ff8262d93e9aa258ef89ba7ec661b1cbe4b9f0dee9ec0fbb4882c105cb1cc83d7d86f32ba14648ca106ac17de4c7b450834ee63258498ff26a8ba4175bce4bcb96280233eab6723b4084e75ec9eecf1bd92a98cc2c045144c07f214a7027bbb064a9766aa7e9caffac4a4a19c5dbd297b7fba97abd27876d0a8df0196ca39d4e40f2e5eaac0f702621b097fc33df9d9b2ec82bc74885ff9ad9bc6324ed8759a640fd102fa95d95fa7e0fa5bfd4cf81e9bf992843585dac604126b66c79ab9792eebe2b212a0ec9ceb419c413542465b34565200879df88e22cce0350fc563c8731ede9e2a0162716f7887aa993b8eee583e850768f80bf7f9415f941cf8c67a153d3a2fdf7a9eb6556f058f573ee065ac1efa69c2ae8d6878359137e05ab35506da34c4feefd691270d80c398b37cecb4295b614ffd1c0848a9906d3dcf4e189fc5b128ab378855b0b66969e093d655d4d4b78927146cb5b044f63d27e4ae4d5558a43dba41b4e33686cb809861830d5465244a8972d359351b4d272c150f5236598f6281e831fb82c3cf807cdf679be2cd69b30522ce33ffa3c98767ef04c6c7fa80ffbee8e64e4a191e78ab38697f65f0db207a7b528921396d4848f2a9380be76a85f7ce9628fc99bfa5af85107a72411676361b5ce7562cda6a4993d8d20ef0d2fc413a35c50", .Okay}, + {.Mul, "-82358a80200bf56b1b342f20d159aca9f37bbe640702b0aab6b46e462d2aeca98c516a19243b70d69415e10a8bf37f33522c4e1f6e80b7e8a30e992152c15711329ed11aae05a1a1cac708a9f72ec6dc09be52bc76fa39904269f87b8b932c901edcd05bcf3810fd09454d89c3dd87266e6de7341bdafae972d085d7151259cd5cb3274f8b97f74d2369ea217b9dd9ca0f2f7cff60ff38a8350675f568c982b463cc51171532c2bced95e016b19fbbba750b84a85aa2ebe31431e5e1a0402d3fac41d45e19533063cbc6d108efdaa8aff2559a4e55c7c708128acc402edb8c273db263891a7ba51a40ea72002b657c5a5a35f02b4ac0126bb8e2b11dd5fa83d75039f41490ece587419c7d6b34eb6b627ccaf41f28a900f793f58596765e4f72b35c4daa57ebc9efa5f43fe65b04c7b940de60612d54942fd0135cfc08a7d361125028e76e67d1577014e0c6c2ed2fb7997af1ec8575558e9556738ac62e2470ad2317debd5fdb4813e6c63664b3bb17529a8a9dd597386538fbe5cddf3df1b019b30c7711b99f4dc8d7694d11e9bd09bcba55a80441458076006e293abd2c5b37fe890102386f4adb9bf0fd33f3780970c33f6fcff9018c1d881d2878e204ff8bba29ef083599162414ca7a409cd33c39977287d8cd614e1e1d6ac00efb6d1c17c44ea9becda3b9321dffe275d03066b6b52673ac8b11d168c09b0f537a254f", "dffe11bc72b5f4a1f8192c50bd0842bd5871f73f34c969cdc338d71ffb5744c491789b66342d1cd1565553dc368b73cbbb1b7ed3ea4dcadd23687c649e9f0f984c45edbd8d80eccffae3693988cf607cc118960c37600e32a801a91d54288153553c1172ba36ea42471bfdbeba2815254fc3e121244e1659176df963b5d3659155f93bf856119211d7e1e95485d968dfeb73ac4ee0e0412deb51faadf30c4082de6fb6153c674a93be7468eabf907f3f8ea2324a048e118d6d31f9f7e8dc7a86dc730c98eaddf19185d17744e3840be3ddd835d689b93ed8d5d99d208a9d270619202fed626511df532736dc72792ad3fbb072856ed16e6cda4e141fa226d449310c11fb713fd5d5e86e90a5c54256b64196f79fe895a158ef386585cc84e1cab3b3d6770dcba5ea2fa42b1af434b3c3445db17bfd1a1e2f675cdd32f8df8e3bb88390419c6b4987319f84f0aa23bcea7b8b694e2978500681b02b3d1cfcdc4c1ec23504160952e84b32c2c9d44110c7d4db9e13bd6833bde69ec8567eaf03894af21efdcb35222cecd0408d2eaa676992e5a0946e3c77be4bb46127655e0d77c4a97114c45858599cead1c1be3665fd447ba709bae97fd8c461800b9cb2e3aecdb0e59a357118997d74fd049af3772a67c01078a993f76c7f16ebd828d553962bfe47ab7e234bf3d9d9e2ca9853b79ad46c69b665129d2dfd0aba9fe194dfeb", "-71edddca6ee6d2d385c6ab1978e544e3a9d320624a9abb91154102294461b86efcda39c6c21b431eb5a20fed7c320d196226aefd042aeedde28ad8cc59c927fdcb0fa6841a5dcc88b170bdb3b23e7a2d22440258300bd22e358cfadad0bf5a1c686a8dfd0207c80f62771710d467d9c7864ced2910267a00d175bb82b16cee2be528e946abf1a3ed037eff5c03b38e83f47155e4ba4a9663972a8b5f02bb26b4f4dd979fe5395ae56556acda023124f0ca92f521a6ea55bae00de385aacc69a3f2ea02c1d8ac529c7d7ea085782b4e6da4dd9b7f49daeac579c4b58d3299df1b59549ca1bf7f65c9c675ed1b5efe6f36ac2721dc58e1ba7716f61c11b39bb16650ebf86519919144371bd2b72dea9b3bf7449098478b3541b27ff98b706219ab8a27c8d3b56ed6cab83475082d52764b429f0a1cc65b05e6703ff1b6755ebbdb8dab5dfa67eaa7bec1b7fb909f41d8342c1300e496dd61c2d8c76fbad58cefd589a7901b6f4e0ddc93875c96423f92f3c154bbcb7e8528383ce5c9b0b5bf570da0e624e4ece9beb69307f3126b02ad1665eb667668c43aff2e2821c4f16fc76610e9637a98c6e456a904767fc35e04b1c17fc70e9b2f64bbb43da70c74ba31b64015fe0992da91ee41404747e06b527e5cdd1615b1db9b1df7b978a7ace24004358cbed2b1aa6cb6da8461ca60c23ba0e66f34acdb955ffb8d239315c2fcc9d0d59b545b5c64c1fa780f618e312ef64b42eefd929e938c090265f15e38b2db58225717ac6b634e68d3384e74461a7d578068127b7075cfb290bdba07a1e55b7935391d9c683fa73cc7971c4d433e109a56893e0159bdb14c5879fd66d1fa9ee7b1901e2deaa701af82c39887cdfd8799f5a42df517779ee5f2b0bdcc8280b4e6090b28b608b1ae3e355146ea8e29c776dbf3cd9f7d3de6da4e5e7c6529fcc0331a58038e2f338f12167925fca607226c15817cbb7bdca5dd6567305fde4d0946b356c25aeb4bfbc368b031aa07c5d1951ef902a52e20c7171c858b2c23da97d2e933220f12bc02bc625f21a22bbb98ff75230614fdfce6727c1397d8f6da9750d79b69c67ea3b642f1c5f7754189eeaba8e3583af89542eb018f5fd824f19de5c4b1611ae56cbbd4b2f3a7652714f678fcf12d24465049e6eecf86c9fda55c9087a4cf78626d9d7fb5feb069584c3c6feb268eda37900139ada6415897be8f2e3062e985f5fca079dd8f8e5925f83c8d314722d480a6ea480327c326bcbe87618a0beeb418cc6007563506bc4196728a0022ff96ba16c074b264d15156b114427754668aa0f91f977c727ebe23bba6bc85069dd56ac60412dc1566b83f98312a53e8dcb7319272cec16d767c47a659697d8223e5b76f3b2ab79ed7f743805d659b093f2c66f0cddf80620f7a470993125dc456d8769b09d02d29e042084c1085", .Okay}, + {.Mul, "dfdb0b75e7ce84161d1ae6d250fd85abfaf6649dc1c974db231dd4fd527081acb08f3f9560c7e1f986c07410817c831766b1d76ebe9eafc0476434e367196cf17a029b9978068ab19c2c4f3aae56ee8bbac7932de1cdbce2cc596b1a3440be7725e38d12e64127b2e5057670186213bf9f3a855d38c899560bcfc09d1696dcb32d0fa411b4837f652cc1760eadedd2234b8de7a5753f5f38085c57c6b218e4a4ed990078ae7f5ccde1862d7891c4537c3e718522239e81c35ca0d4f9823930ac20046cabfcc6a3ec7762a4040de490dbce5e1bae5701223c6ec0cf4ee82bea8634d581ce1ed8e184b912f753fbb17e0aebd5fd4bb03eaca1e02d90a4c41560aca1703c58cd46acb604a17f395c292b161ce947ec05da17402fd6bc310d765e412b1e89668315945d09f1bdcffb000d909229cb1bc30b0d8f7e8afbb917711b7e0d8b231af64454cc50dc64835028ffcc9df512c7f87e8dc66104874314e73980054255c4dcf7c4a4ba2db2ba6ba1823e0ff203268f2cce15573d5b6438a0c2a0b1f8785eaf9448e3f95137481e2a99e698c6dbf968518864dfad77276316c9c3cbe9deefb36434deddde7b34314c994335a2fec7fe729b251a06c7066a13c6121c7a754640f9c4adeaab523a82919edb947c6f036bf0f93da130c998e02b0596fda9ef11f9881a8af2be7fb674ae32514f18688664759520b323853f1e2b27ea", "2989f8a3d459304660fb4fb61aa79301f274ee0a906065aaf7b8976fa89bab2bf19c278dac428b95bca20527ffe793c270fee40d19b4c064d0d3a3891b441a7c59f48dbafeb0f0efffa829f66413e092c6468dda00825d498482ebb2562d0911d8d9f96c87e6be3d7bd999844b5f3e8e22a156f3ac713e628d811e7ab8c79aeb5220c0e0f3589d191454204d4ab882bd21a4bcef6c3ad78ff2a72939a14afc9d04d11d73b09c5bf79f9a6933989cb3be552cdb3c4b7b7ee1fca1ddcda1ce6052530605ccdbd653aa7919028d45c8bd6a76d773134dc6a81dbf19a4b6af2b4653f94c3cd1553f1145af887631c7db77400e8201ec2b0e8b6e6da2731da868d9d20b5e4c163ebb3c029f1c9dc4200de75bff857e94d6b848d4b1c0df4bdd181e572599329ff7d4ec005e75ef8870be0bbbe0e332539446439d0653085962f4f439019d3ff43693158ed2a220839e5162a82a8b42486f37d1516ae3ac013b5428d6e76919733cf78fe2e250a62421d0b27c37d98308af4caadf376782a7fc2b64a7efa65baed082591da7b66e6c35ba1bace8f5e11970e7c6682dea53a07b07558397e031d9801394a7f62b040a2ba86054b337481eb50a2db82843889204fa708c0f4da09e90164041bec17016b26d71a4c01a3491bc60629b9b1536cd1645afee64143874b17cb4a49f07264fc484e9e348b78d69cd3640c1ba1ca1a4dceb9665", "2452ba7a797b082a1fc0284a6d635a6fed0dbeb4c7ce31d0d5d4aff0455886d1d46284aff86b5b6f59c87a5be05611f396ff7f7451eb242c4763eff20242ecbdc397601399cdf5f457021ef81b87b7a645764ab658589f977e368a0094c401fa49eaa61ecc78b48b419bfffe352536bbe8dd2cba39e02f0a30ab319c62d5960a69342645ecf4bce2d6c9f6214f6b5a1186b958f4eb0512500564120368c3e610f80bd37a48d90e2ced55a413f3710693ac14cd76342473cd791ff93eb9e79324a9f5a33607650e0dc17104034bc4f54785eefbc3171c85f587d3d6e7c8f769ca5b6000f35cd9d36c8622b14166f082fd9e1159f63f9e6e8650dbdd6c0c3daf25c63c8bae2381d70a5c2b7dc2a47625c56db78444404943f286c551a05fc73f2cbb28ee41acbefc25a4f61f54679fd7fd2f551c9d997c55a2d38340838b762807ed18800e0d509ae81351d5c110a61014bf9f5096b18e1ef664bf992b94865f1dd5e95e3936e4c7864c8a4530f4fb537b8e7efa6761a737ada2224140fe69bbbe379783a445b403c260e0c293d6bd4ee7793635e341a3c0f8f81fde8cedbc0dcc013aea3eb3fa641a394f1ad94943fe8db536613b011baba4183de5b70ae88534b507bc829642646e1a9c5cc106498d62d846a58c502edaafc58b4d33b14bfcbdd11100e9855b06c54c9f884a21f010dbc2bc058086347bad0881083e8a9ad1a0b70c9c35c97e603f60597cf0d8912d41f079049e66d652dcb86ff6069ea6e1eaaea29f3b303e6ec24f5f8b1ec44378684381c0443abf9f3d6c3b89c9a6dad41df40091f9da383c82b8229453786722013d5bbb002cf10b4b76ef4303c4433baa2efa0ed336f2529dd7b6dc138cf1a647a381f7d57f9c6b31aa8ddcde217f18d37486b568fd50e3fd7fc506689f20556b54514327771fd8bddc45c6ffe9eac96b392c58f03b693835dfe492bae1fa626fabcaf370e7ac0940858151542b25aef3d593feff66eb779a49b1e7e8c49dad508bc5ac1e416e1792ff64a249872bc4f5c45431981fee62ec68c81eab88e21c8d971116ba494bd2b343ee4aadb607074ac291e41e46f56ae93e2140224456eabb8e868af94b2a5075ff0a25bdac3ea6364a87e4f678a512d8bc421c68a7cf9538e98d0a5ddaed4e0f1ca11ef75d9fba5ed51d1bd9051d458e4563d5df38533dac51d074559a2aea12a4d3ec9514aa00120d19561033a98234150d84cad0baee59290e33bc082db69e91b7ab231601d6f420838baa8f01a3cb213929da4b4eacdd93de3e7c381f37a776e9275b77fd880453f23ae7ee435eb391428a450d416a760174788b7b7c3908e6e863c01d139ef8d7b1b23a6c48c60a3b2a6ad8f6fa4855d88d155162ee4aa7d8ed724e192961cdb7862edfae105d21d1db13fed8f94cd865f1297464fc4485e54c1166ec37db52", .Okay}, + {.Mul, "-21133d83332315b73053dff2f4f818fc11b34e95a821a6efb6e9a2ea335dd9b91329ff159f8fd68fcf8d0ed20e01d71f3bd99aedde22dd8ccdfced53f1cd46cb4a73af922d9d954be65bdb1b5735b46f0c0f5a2ebb3a6a14b9afddbb40022506378bf1619e238905baea507e521f6e4e2b77f1e872244c8f73a4054b1a106e2eeb6e0cfc259f32ffacf5d7a18d3efc1a54ff345ef42c7f165a4531dd404065a76fa5570b45bf700275fe0632cb322d197cb921c73ada231a7f611ff1b7ebeec6c05eea109c6f6bb4b7af6e11ce16d4c4e7f17c139c7c9404bd2e9fecb4ac6663cae970a34525a51e428be005ba243bafbc9737fd939b8ac78e9c460ebec7c1ec6f013b57536a9be9c16d7ac5fbbc26ecd3eda5340e1ffbdb9619def28de4c6bf521d5fa0ca68858a61d2fa2c43195518b5e342cbb94afd79e8a7c4e372ae150237797e8e7fbc5406c0980cec12a5f6833768c75eecbe27a2092ccbe43c404aabf740db57b04a8bc05fd52524addc93632e9cb631de78a1c5c719ed761cbd56a491db22846be976858c111b7988a55143ffb7320ce2016ce28585b1fd3560ab1fb7ad5382dfe06eea29e14d969c894629ee8b2310703f12b5719e3cdf3e5124682f9c2991104fbf0cefb20a2303a4b5de4c3620b7179b19802dd186ef8f0ff4210a37c73594208f723f8a8836772bfce3ab2a8bf9e6db27b71aa3a93eda3154df", "b8553f2219989dcd34462e4772eefef02e8084bd35960b0fb81c84f4e29f4f768f07b7c6d7c2c04918b3a02cd68f24e984966669f7bf63ff96157c101c87b59738cefb6bdab7684b3cb5862e36fe4ea04f87d2ff144115772129bd9db404866cd955a8bae671f8a0da53c1960c46cd9c976b2406e6687ded6fed79d3528548e13a548605640c8491b53aef9a919483e38973b047c1eda637f418396941da9c769cc808eb9f5a375c7342f29569c3c2699f510bb82dc979c00b51bb4f5e1b3beea0598320749d5a86a50c79337aa5b3890aeed7082bae34eb993afb5677df5fc6edcecc657fbbb7a4bdc19be8660ac4d95a1ab734998188161efc2731bc652d4611fd094196c8bddd34a3a6cdfe5c22a92660b869be066d6e306215d2b536c9a6d18e4f30ca9b1d3cc4b7308447331c5db72b70e01d6164cfe712b81e86827d902d287dbb1dd8d4bc90eb962c5f8b04e81b02b317311a1378f3fa720357842a843d07377789e21bddc285611f970965ab873b9cc0382ab25a3e8692450074021eebe042e99cfb2847329329cf32f5044fc4301f0426247549a7e0fbc13fd2e38f0e0c3174b76f3c26f8299ffb581a5507d74cdd28eee2fff15bda488dc42d6cdfa17e61e90f26b1127c1dcf656a329f0b83434f85b1ad528c639c0081a272b02fa3d4d1d3ce1f23e67e4077943191ed7609cb3604e8e1790c47b2c9f2319870a9", "-17d0d7c1dd514015f357c825736500b0439161272eacbe13e7ae1338a085607c7db30f7ef0dcea2839b46dfd045bdc3c0d43e341d91d24b1d347c1e73077c9391c68d9411f5e5178e25f7abe0e7423f28a5f766a40d99b12cbeb31a86482b1ee6845b1f017d86cd469a4da800a3c6f64415310520d19acea50be38a608d5893578cb9eb31e08d4f273cf597cc6a93065a259ba4688a5fe94c28eca966ca24e9a29b599d7cc7987ad7e4156c57be8af44473ff98197f3320d3f799de3ded44bdd6e8e96abc920485ce9d748d00ca4f8cd9fd111ca2fde82ba1de4456ac5ab4900e4fc4b2982da636ba358d962acc662a77ab41d7ada34ff10663597a699a5943247ed2383ea0995a292255d51482b47efad97e91bfa13a23a11c8e10d4687ac025d1beecb531fe9d8c2395dc1cb79fa1076ab00fdf48a35488b0fcd79c862422f7fe525485aed268c874f919a5dc1d79594a2b16ea4c775d5784db06d8c926a8adfdb2b29a4f010622fbe3dab7e936f8b024232d34ff7993a5690d8bd34ffdb3cb8e0459f6e63fc8daa3ffc93831631b4f09d44ee3f88fafd55ea0ef3d8634c12a9508c9c6b75ef5abdf4feddfab0dca6b76aeb7bd143f29621b803570c6f8f9d3217ca67818dffe2cc551fa34e76ab9a8fa6be0972a1b2cf1ec64ef6e4cb5caae0ee0105b0fa01d993fb84a20acaba6c5545da10432d7e085b0c988d9a9eeed24555ecf301e4259aeef0c73560629a445835adf09c96dc718df2d51700c6825a5f70092743a0f5edfee9c1037e41807a21d81b8ea0ee2b8c2de81398e023b92b81c65786b8be6d4550da0e05b8c04ff7e9ab6f78227ff60b51c895588904c7f64233accdd8c3e23e018011a9e4c55d9179d8eedef2afc06d75cd41adc22d4a0b895e9ba995e60cc97de1bac41d54ae89b099eb9f243a5384e660b1ee8f3e91a9b477a3b86f58c438a87042f8b4036dbe2901107e63b38c7c64bfda91cf95786f89029231a681d2e30e5c24031c16b8da69904428768bf2f74b986eb218a6b973af689aa8346c5a2bf489f1e272f806f30ad42b8f2d9598349b815406aa8dd9f1ec2d0f0a4e2e0cdcb02cda8c42fdadf63ecaef16bef1f6883937ed67f64eb421c09f64af2637a324bffc858d6310263330e6e3999257758e8acf3a6b6c15f6fa402bb1cbfec8a16deed1244dded7fbe5da03f1a8baef8bf42cc0c21d3e96320f8ed7fee824f0edb70b259471c04d4c95c11a78ebeb01a73a227f9306711809c5884afb2982ea0ec0017dc5735c050746533c6fcb413d6c58211abd4c48dfb5a54e531c13952e71866b9e408f8d659c787406d18520d0217e14071c884e26f5d1e51e2e96115fc25265deb3ba1e4fd7a473cddd2227b2751d7f442dcbf68d169977e79e783046814d2941d25b1908856b86197645ef1a951f8f7e8a4ab31a9737", .Okay}, + {.Mul, "-64d9f129b812e4edb3e3634681c4ce8f452384f9e921e5f90789c970c19e5f468e1840a2b063f0bc644a9ae612cf814d20a5effd4c1e75652351ee56112d10438fd5f63d3f0310372e92a5d361a14c0a50b85a9a2e5d00cde0c65c7eb05697355e8f96626c5a3d114979fa960da3415704e94788874618663227771fe97953159e6d8e5144a4cc53816aa6df2863d87a52afcb6931e6acf0c10e58ea2c9a5ad7c7fea5732b741c762dcb77a0a8d17f14554f5cde4369a79b5f6c4f8f80375a88d533d542deeb5844b075cd716f787a1dc91c0ea45c9783370dbfae13168d4975c83aec54216d33c30ce8f6fe12ba1df9fe765f5b28ff14af5a86dd37601823cb3f14184cbb60a1366921c46bc7f794dbaf3bca34fbe821f7a74284143591c45dc914f2308edbc0f2fc1d7e698cb5cb4fa79e70d7d76d2b8071b56ec96e58ab847c82a4397c1d4dcb5df7fcb20038705883defaf032b6f56239d12aa1ff1308eabb845d3d8b46a0d80f457ae2d511829b149de7af977cbdabe0900c4f0c7dfa8f90a9b339ee7224d0b2d47c123c845b04f1f988cf81a28b7c1572c89741893477a06db8a1222aac6dfb1ce490df9fdf6fc9eab4037bd8bdb754348470a2ac4a26da21c0e2b3889d671938bf1551ca8b724d640ce79ff95ee1bf36dd21643a4448ada2b120ca5a65fae780fdf3223365f869d1146177f496b5c627d8efc8830e23", "fb082161f6335134b59242dc760d25ccf6449525a7f883a24b22dae7a48cd955a3f67b7552a02f5db3c4be2f05ba5df05e144e71d6c7da23329201db71aca3c8d2a7f22f92f1a42015244a4f315b257ff778e60f5a25a4136e8dfaa53392285eab365f653dcc1bc799a05a6d2a12b708fe593992b8bb28f9ef2b1d80b1cce7b9431cc92e0b93557f80e97c62ed0210b0877c02ad13772dddbe2d7b4f505f21c071b4a48824070eba3806eef04d23856f91380d0721970211cf3b3171dcb85a31bdb29ed306dd09c678567f99563e84c094db823196f6ea9b2e02c5a1652872c27b2279ec3d8ac0a067117636795e978ab1733b55fe97c233fcc4d5d66bc75bfe39ce8022704d47934a378fd9e3d0b2ef23fff07b2be1f92c3c2606e3e77f86c39f11c5573fdbf8fd591a7036897a619a7822968c98f033305c4546d6e96c0bb9b6e87c0886691a9b3dc147a3c1dbd367a2674d4c722fc51892c36379dc4589f54ddfb114797e6884a6ee211dd473ad6ddb544169bd324e6f05eeb3df59503290d064b363bc7e26fd2bd85c8c1e96071df6d5039c32fd962a58c63830454f0843d9231cce09ef4a104a0e35ca5eb419cb4fd8f793059bd5303f7c3b1fee2f15007a529c4eca1b54742a26f0919905a327aa912499d34cf1c742852a8eca07afe830b77118df29e3497e6baa08be52037cf85f233f7aff7560a5e1145362db4f52", "-62e4e36a2070adbc40c5ad4f2bcbc214e35442038966f5a939142fb5b627bd608fb53005a4717c5972838c8b1b9c04e1b06896fc9fcbd53cf1cd2b4da00bb9f32ecbbc9cfa736e0153f45259603431436ee7f1485bcab18bd77ba9dac8aed0f9a2565d03a4ea060ef6c262344d063a612a8936472db636d1da8ebfc705a19bc89ea4c31e879f56260e593a09cc4b485afac7f5fb690070ed9ef6d5dd597d96c5bc982a32119a9a22f89e9a01008d28a4d86b8da17964f3157bf7700af844029516cc2bbe39dd508d7de643a4db38c7e5e8cc80fb537831bd31996b1da91cb5e7d2364aeb9eb9acb9215088fb7b6b615004e3e73cdf7280621a7108c850323cd07d546ead0f96eaa0ca8a5ba0d0360576402b830a305c788f14833e01e6fd644ea7513e6adfc9fd91f96229bd61feb402f2dce4a67624aa143447c12b0f389261dda3f299d416c1e6d58c7a1318e504ded428a4fa4d8e0729f1888577198bde263d960209563fafb386b79487f65e8d93cb847522f1c0d10c3a967c732abb0d7925a175d91153d7d3ff961a3010b34c2fce11ae19c104b7754e0648d7a5ea2717bef0d09c9afd6eef8a3dae841f50f6e520b1327577827d9ff809facf6a6375cfc6a638535c88187fbf84bcfa52300802dd15d61d4c90ec105db51c0baa06808e9617470f09d74f27c69b159e10d205153bb36ad268eeab40ad95ab21e68115762c20eccff60e62aec317c5b44dd035b260ace0543ec40b8a497875fec27422efcef28fddf5ce0481939ee3c759e3b1523c94da8a815cf7f26b0eac76876a4d98df9f6340d82c222baa575813092d692a054b27ab993a00b417a440d3be26506d65f20010003522872c1ce2002b6807909094b7f8ccf78381eb51273cca2d8698ccbc9ed1b9a31adbca0077d3f97493df368719e13f7d3053058cb47283781f8152faf987d58a67e7e0a1088e0ab7541fda8fa7c3454bf7e7f82da43ae6c7f3b2bd9952d550bfaf71eab6ba029568d0a418629aeeddbfe16b64f0f8c827fbeee1534285ae4d9e96dd72182abe14dac789cfa93589f1aa1885c37af72fa80febca6b06dd8033c637ea1115e76d77801d7ee19fc659a76f313f9756ea41eb8ce6b92242dbfe9b1fa14e6d025dff494bb7bbf0c4ecffda120fc36c38cde9946f96c1c8ebdb5c499c889f0ea443b1017cc865889ae73bf5de7d25463d8c89305512d11c1429792d87546e847dbff6bf7b5369e9a600f4c44c0dc9720d0e9b144e0f619155d7ca5506565e61761ea64db0a3a55f011ac35e9d0100c41f9f5afbc6b9a09ccdcb6e204f6d492222892cff0d21d5a887c9bd4c3872466dbf3425d3bbfc4c47de38ab4d062c26e25aba528bde1038f229127fc4c81658f810052bc9d31df36bd3fa9b90b636ea6ab3eacd34f4f07a13c826e1d68834565ff3808e29485436", .Okay}, + {.Mul, "eeead6346e78a3a1c9ff9c135f3ece9267bba5ed30dc457d81656cbd3cf7839c83fe66bfef40618859fc64269df75d356fc3397f41a07a493571b9a8f83c67cd606bd2d5007229bc563344225594c0a9302c06db0a0a398b06e314ea6197546994b7ad1a1e93dd083b6dac334123df61fa4ee677d2be7df07dc547c098a31b1900038239b37ef1fcb27ea09c89f495ced2cf7b71d98f4ed773d4957adb24a9272c56fa564bb8da213749ef6760c04d3f69ea1d09768c89bb46b55f5fbc37235ed910ad517ee8d96d389bac68f9b88dbb28abc1c73a1366219b9f565d46e5c6ad1eec11834d20fd4e9af5892bdb3ffe9b42eeb01e78d7c9c891e7aa355cf71830db38d7ff163f3cec418a9d36c7891f53cc71d268893f9b8309a2f8a773f4d76a66e90f56982073ee30790e078a4f8796beafbad5218624aa7ba7dd2f0946ec649f383c45e77a4aa1922f699ed76d4c11943b174e73534cb0826e95d74ddccbda322f968c4f3ba8599569047a8e0591cada2d5275d8bbc7cc742287c975680451b48d165324c8c50dd0fc9c72d61d53d03d973ad234912f30735884ad7fa6c3d3c499a123f1aad263ffc2c9171555e308b917c294991c6ead5ec88dae6a3dcaa38de45d796e025c71534adbbc803992e920e75d98ea7a72bf26fa86d7b8898dfebbb9c6b49b65f7eb5585d0ded217a379f608ed264e90878e527cf01c1c84d70", "ad906b450aeba75afc0652f80918e57d3fde8b40c6eaeaa0d49ada1ca9349b4818d4a1873c38c82ffdd0512b96224b102c7a6820139a9363b6c00cf01eb664d80269787280c497fd9ba28a8d2aace74a418723be6fa355784317246e7bdc62c18b555ef847c41606b0aa875b5f1912f2f1e19747e128824cb1bfa2f2afb5aed2d05a1e4666aab767ba3ed1d0284efce8303783c112381d8da1b8ff179bc06dc38053e90036a983591ccfe4817af6a6f7662cc0b8cb1dc41922597787e53c99213489bd3ff228dfb7c293240150cf79b2284eb862090739375f85a3f73c571287985efeb089a8aa5fa5edefc272959f19eba11e4ac48a242044f2e801b156dcfc2f8583b25af36e237e19b8f277a463481bdd11fb9f01154b66414cb33d8ee9019482264ba9b2f8a9f92cc8b14f4ed5ca6d4d416ab9d38775b7eb03e2c1a497fefff1e30427cc7d12a8ebc322ca3688adcfc71dc4acafe3fdabe9062416f08231eef4cae80f7a4357088f7da2f83959e3728d14e916c2d30ec4935696ced78410bb68fe5fd4fd016e398bf7e820de269115e449daa2285579690ae43eb5744db0d9073197f2818388c28a3a8be9474b58e8f78b0736917177ade33c526121a98b86547c833b9905cf4350c2c447a0f9ab8682cbdf078046a3c01dee0922fd96203eb2b8013979ef052654589c0c1054d30f4afbc289bfaaf15672e187a6378bd6", "a1fb7af6832a6adf5d5ec9b79187ce267d81b1099c57459a7ad3c7367ae37f227666d5a1dc6c86d6f3f81d11dac09ad083118d59a0edbff6acbea8fe027c04573b059891078e6e603165b050d5102aed6f568c31170569c788feb940d443c0afe35e9a3b72465a2eb9dbbb9c619822f9eb708ffde5a67e3522167f106044a33011314cb932cc9f8059f80e41194029fea2558747b699c57fa904b32721e037a30658ebc22499e50aa315a70efcb72ce5957ce81d887a3e76a8efa0a4851674ad5b771ff8c1a1b7239184a5636f69a85fd5ed961390174b34dad55e8f42379b6f692626ed1030671c25380f9ed2373bff3bb321d40fca49e24a928ec5fc799d086dcfda3ba421d0883460b9a2ea2e98eaae1dc213311d08b67ab40415ef8e2050c12a1687df3c6dd953d3633b759eac7b306072fd3dfc611a3c06f67d4c591476f6dca87d6d643d204529556140ef4fadba3ba7d4c118243d8a01cbcc705e44ff4d4c45a760b6f51c490024990a36e7328fb66b2267957c602b75dbad3899d3e0cad9cc372365a634e29bdfb36c8fc9d4169d402511cace4513a939467505ac0f55b501a668b1f7dbbdc6850a38d7bf484f5531cd7401edbb31bcf358d159a6264a5354d46b9c4f8f2d7ae7fd29bce08747b54063e9599f27a88da4544e7c8d340f3ea2cc710da7e5f0914d1129fffea0dc3015675ec6c7079883aea572eee11939e08c8c57493fd43607e6dfa845790696634a85eaacdf9067a549c959ca90f59204468ebdd918d4a48a1e1045fe8931aae40b5c78a785915ffbef30076a70a3bfbc331d4f0c9aa9ff9510cc5d8e251819ca9f665012f8e95abf43d4fc660189cee0f669bb7c1b98e72a1713cdc3b98578958a41138e80b346bf89969e724cb5b1ea77d2115d9c87f21c0259576218d47cc929caefe351de26aaf055974f8948fb11160c12b08bbae88bb7c161efd432b78e636d5d98990d3ddd51ff68bfcdfdff7625a3f9c5dff1b16f5e65cccbd246aa2991d07cb8b8737c2ac5311743635f96f78f265fa306213fff60d449d3adb4073c53553bd76828171279696d56461d5f571820097401024a33d1e9aa2efe240c2fead115b545e1c5fa84106173e85e914a8a1db753f7fbec877a532bfbac8befd3c4390cd9c1145eaf3a1331468351da6bcad854add7dc190b933273749f3ec39032f137476c6668ff5f223dd7fc791f9028149303a58eccb2aa33dbf298a6b56837ee6e22175015920202f060d4c80453770edc454502b540f7c99494acb5765a832d0b728430a8bd15116b4e3a9a0ecd1cbb7fbab35397a517bb5f70397ab17023cf5bb43620aef9eef6da27464d6743b5ccc37291575567ff465925581edc8383a1bffe334d89e84551c5438e87735514de1d0f075e7e1d410d9032131ec19dec0db5556292245c9ff028c8ba0", .Okay}, + {.Mul, "-37aa89b85b8227da0e584dec1d3fb0fe1663c89ec1513f44fb7599d6d6c6f819d888468b6008e7146b5b0c1fe985f32a2fe8512ecfd14273acbb8efb10944d9d32e29851a8e9f76827046e1ee0da251aecdc5daca098d604fd3bfec6833f8c95112f53b12914fd518718b036ae546b087ff0ff49555a34a1c93f4d92183220e7ae00fc2162ed3d3ef8a17d7fc6b6723366803ad3039040688a610805e91c6d2fc981de3d328a6d77af74ef41d2208607db0401f309d28a43cfa953ac913415b08e83817db76c554383ed320db90091fbf11b76f3ea0281ad0b93c5fa8ea2ba0ab757052c092738227c93880dd3c41e0d0c9096f06d6c8da1ff3c5ca1296360b35f19a07f865dbae49e601e04726ba1d161439d54ed2243e1ac060d2718a38dbc5c87d72edee1b14879d13669905eacf484ea0e60e9e2801072858ba2bbb2c7ce1df9ab1ff85a008a8f5aced84c27a83f828dc376fcd5dce04066de155c938dc333565f28bda924ff060b6270552ed963432eaee5e68fa32f65d4bd18b1debd815a2ee84b522b2773376f6abc8e6fd41721dab6a0dd882f2cb4ebed57d18c5d0dc7fd0de5184640f044141d30f819732cbae5f3831fcf8e93f92a3e63ef61f14b93fc38b61b89d584eeba5e4a3e5f55eceb7bc8e2ce8aa106c669823fd932adc8fdbf6b8e6a9a5291d145064e1b345710c4ce6580849902f385d523c5e5041238", "5289e9e5f5bcae56416dd3184de5cf406d54ccc268792b1b367d37ca0ccc0d3074e38dc8e50be30b0163bea921df89736d11270773bb0ff82e73ee5fbfcd5d71c90fdfec3fd3dae11987fd855d19b3034ab2228347dd27d21f23fb0ad50a2ffa293729d7ca4a53f91d7ea75e7a9a0cd63e81923cd8c7f00249c683d633da863a7d594b3ef7b8f5601fa3fdd974cba30e550f63e1cc95d9a8e3285751649a4051985c5af207cd698d48aaf256bf2c087f1fe99afe6bbfda3db06b3694acba79f50ec9f52270547ab436fc9f4fe26ba635a1ebc74523f532b589f490ee91306f12bd95f78b79843835c3a6c4e9b7fcd7b1a254e683f852ea7f1a5247d38b4d1dbc42bd4431bb4d0e7824cd36613fd048756729f569bdd7b49674a4e46d16ed77e3b8ab21e8f5d9a2888de875b9f37e68373e4147fb6de0c9ffea90165b7df0d9b25d1374d50c7d8559b61f286cd614ad2d345b1ae9e13821f56b7d3abf3c6a7d5e9a4f9731b6ad25345b0a95f84181e615a8e10103f57e0935ac2020028bac22915f7ffdc5bf050fb8dcdd63dbd5e40a40edd09b65ed8706360fcbaffe108dbd7b9f33ce9d698586ca9d33b4f956c651a2acbf3462589ca93d92ec16cf22d98149d20b6b635e85088d0729d55c92554d64f8e939e17875c67d246ef028a9092e4698b4ffb9aee8d5bc2d8250ad5dc6ad4450f1db75fe4e65118b715e4689d33867", "-11f29d3cf94de391bc1397a9fc7b705202f82bf4cb3517a2cc58571f618eb300c820575518e163dcfce5ca8447118871f90580a8914780b7f44b474a216e448ae11d4b6a239125367d028b839b45e630ed36630c1ab7d3e4d0c9b80a1fbe00d2e9052c05a5af95f6b287db2e417b4238362003ad83db351c581b98f9b2ccc3553620df47b75b8f35ac03422676d8b208bb9a3704fcd702ae22167e2d59d63c943c08012f2ba51153c3602f4e388dd146688d37343689e158e0fa88e5037a42115870ac7d6d03d4188a6fcbcb40628830b19dc15943c6945254b37413bb4b76f9cd7d14658f396a646353583b8fb6666de22ca13337744790aed39e37c602e13c105e16cdfa2a7b5f02190eb5fee71e58e6cf1f86993e2b62f4ce84d7877cd3dd8110fe3c321a9aa1b6b6e8dc2e2af55a1755955e10d018ecb20e619526e39c0c90f4b4af13ae8a7cac92ad5022787b9739451b8e79eebc4c4fdb3b2956598e5b2a5e032b4b3d9cbf34845c23be6cff0b6326613a2d569144ca870e32f3685552d37cd76019e50f44f3d4f9964a575a85cbc60275df2978bb37abc536b21507cebd187f5afbaf3dd5f6d4277c556af696cad525162d059d831063b9fbb188ae978ffdc8ec3dbdf17723b6d9178a47179cc70b15cd269c802398f6197ac922a5af7a2283eaaa6979197699864ed865934eba38a4a52a8a23e6e93a50b829e985337d48af4621866d2f301cc45563ab36dbac6d1e85743ed4e3edcd859b37d36ca363bc5415aac2bbc40f543cd9ca978deca7006b29559324d8498ac6b6ab8f2443e02f728d8c1e99304988eea61c849fe9d902132b24f071e1a5e576c8cf634dcd697e0a9949750fe08ce370329af1d59920b20b3cec176d99583c33127478c362597c547d211d7e5dd1dc65502f90a59e19c6dedd3a5402dd29bb08b49a6be8c141d8d21dfe93cbe3ace0632c3bb9f5b5b0977a93a9babfa58cce1aa9cea60a2410ccb01d90bb5e86c46b229603255507ff25a302d5b4f1bf7566afecacf63083f1daa8978bca77fe26167e041e7de2074ffd02f2bcf5ac39252d62c53f8232a2736913d529a55ff22c6a43c855d86e234c9a32387392dc21128b1d6a25cd6fd100914f9813b105f19efc0c725a551bf537c2d41b9500dc9b0ab819e34dfdd77c77056817a5b6915e99405c64ca2398a42de23e0819d213e31f3bbc5761efd3a7527daba6b03a277362838ca98399b413654602df1bfee2ba2d8007fb5d93079f7b74944baf8d136dacaaf32ab00d9501f4010aeaffa0864d85c6412b36150a7ae0c49ab9026f41151643fc99b25b7c7c8d073bc30338d820c6f2e081176b8b2fa5eb3c976ad9ef400ede31ed308736fc806673b1fa41b703bd24fdc3c2e4fdfb114ae066de06ca99148f8c220b93a35fc42ba80c9a2ee0af6cc52a2304c79488", .Okay}, + {.Mul, "383d6114b7945cd884052acfe744c41aa0052626f16ee7c3d8cc00392f9e3d5c7b38ed0205d07c57a720229f6316ea474377463ac97eb4a9695908f8d624db4cfedd5485e35602be60aeff72fb06952aee97e3ac8571a2a18a6f3459eeddfe16272e0ea13cddabcc03dde0b276bb59d05b0aea00d6b29adf3a8fcfbab565d7a84cc3c931d5cfa72ad3ceb3cc47f2beb197f295b11df9c9938209da32033e02b684ea5dd12cd8dc56cf95bd5697e92d292b53f49c93a438e62dfb9cc5088441836a4a7cfbabd146445b51eff8d8cec39d594c9e37e64f3f300e412476c689d58bca1e6dae27ab93028fd8fc0d675d51efc70badaafd15aa4c442ae41de4867575f4567134077f02c6856d8f5c5785ce8492236c330d7b0ba4dde2435532bdfff0052f11afcf597817a1d1d83eff320b34476e4c9aef482843510e7212256b374bf761da6666464c42b3370e0e3f0c765eac30b8af224083642ca130758992f9e3fc0788d93adf8593a88963980e81c9e02c3c3a105e84a7ee898bce0e61509ed7f65b25f0a460cb12e8410dc3462e08b63a7247bc4d6bc8de5c24f51718da7ec062562622ec7b9544ec56eae91910a7acb3e4302040119ae6b5667c9942ea03b5ae432a650f20732efca157662aeb255fc7b0464b130fbb34f9266c47406bc078388db0fb61f64c72ad0bbb713ecfa299961d5cae19c4c0520fe9aaa382448580", "8134d59110578136f53a5cfb908bf9d6fd66215bfc2e67b388fcecbaedec611254aa6e8e7dbf85f58f0ac3a997934b795eae1bbcd81a96f88709043996b5b3dcadb49bf2620f8d898ba2ff8a1fddef318e2a0fbe535e5b602c634607af62e1b8e2a67c557aeb693cabffab6ff9a91753ae6e171f429570859d43313c662a5d217d2b37da6a8ef78cbe9bc657ad3edeae1e6eb235b5aac48473f966a0394086bae2a8df309122d306decea79745bb1a13b0eba002704fe25c37b0a276a4884354a0646d94ebb5c4e04a07a5576b018eeb8817a60882fcb71dbe3bb83b52823d3b97170a3a224426dc07ab5f00f78aa72ae0de4a69db371b3569d90eb3d200a389216943994389280456efb82728d4c41473021e9e61b2d5218ca3dbb6004cd06d52fe83aa1d377e99aca0c6c1c5367c3110611cc7a933737036a4eef509d7cd08ed11fe2c4a26cbf699e0b04eab831c5dded8462417cd73f06365e60cca778f230f31359ffc6078c611549d8290c2752227296168b9d0b3e6e59fdbb4eacbfce01d83ae74ddbbfcf7f0ae95616b05c82f9a2b77c1b3e962c692b5fc2c5b17b5c3488963bbc42dd049bf8050041653f4c9f50d3d5a58290ef7ef3c9d35491b45e6efb6a32e40d438d68b51447182f522910bbf91cf692c060abc62ced68ca85b8b5353a639dc3ae1884a228ad71b4ceac444afcf9437376c93fa771bf340d8b07e", "1c62894e18d855b6ad0b4c724070392c4f143ec6400eaf6ad2470957bef4daf49419001086f8466d0e3812eece5e1560da9145040721a4bac1ffed1a9b0b90ada5c1a5bb7fb8422a5d4f2e32e77a657cdffb6d940ff121b354c319a6e482a0b74c9990f5653f4785dddd81754882ce818b3c2695e70179e7b93002b44e631f2083a2f5bdbdea0356a23bb6fcfdd1b960206965d513405e67893ed410cdf1b83722bd288245f9c213047d94c835c373371315eda99857a2f61611b1d8af4e330d03817f46f25e089e96a739ddd68105a9f3b4fd80f962d627c5a9cbe130a6326614fe42006df4f185f700a3300f90c7d0eb877d8b86aeb1d13587eb0668d4ea568acd14d5e34ad5dac36f8dbb8ac17827bb415019311c44c3cf36f205a3ef747f8d81ba36a606acff2cf5b176a1e55812df94144b563aee15d14dfd3122d5fe63468ddb740afa19df45bb450bf3e003fe94311a1f8e1d3644bb50de1874bf7780c7d86001b07586d860a8efe5893127a46ce2143b217e040fcc8b570e2c29d3b9afd75590d9bb6cc484be4ccc754e94a111d112ceb070d917b6ce37375d6e25a8d23cf00379bba9aa0e18aa0b832a86743188bfee470a5184ae045c52bc9e5888c127d2942e75375d9997e5d60758cd11b3ff79fb1097bd8172b4bec39f370cdeaaec44929265fc52766410e0c9c8a686f7028012992b0f3d44c535d7522dfba232b333cb03305edfb20bb987e45d97e8205708eeb62975bc256ddde341beff97212d624bf7f9c67caef3f22b1f469740f47017259a78987dea61d4e6688f53c7a1ea40e3a9c6d1947775d1b5605771f1aad0121c1f65442a9f62f5b0c0f45f44d872249f048033bc504fced521ed2ece04599ae432b478e0527e87a24d78500a8e87848b6dc9ecdb91377f3dbd0b08453459dbd5162402f70a73dcd921026bedd2d38352221545380cc4218c6431221dbbc6b40d4cdf328900142aceb9f153b58dc206b302583dff4816a787ebe0ba0c4f6f6740fcc0768987e5b394995d96d6e22efb993fb3a503222e472f8d930ef8793af18e4661055791d477eeca3214592953f2b49f3d7f925ed3e7c06c3c1417dcd5398ab8ede6a6a6cf771e7af3d67cad1cca1ca9690cd36761461b62e83cb753a7f798f171ea000bd4f2b35e82b6333b5f66b21d81fe4995eaccf1507e1f2848716d2865628cd5b89b7c4f80c406394664d19e8978d8b6855cdbbd6dbb79ce5137e8e51002493627c83026f9294045bfa18353b2939179e1dcb8cf47fda02e5fb9f81bf9e8af48afbc054517490382f34578cf60d744e1a6f97756ba93b762ce1cf5802a7b6dd752ccabd7e609bd6d5605eb85e8e87410fa5847feeb3ec5cfa0d90162420a2dc58f006273482dc824d09e3d0ce857cd62b24618856aef12da069463935f7643d04478a9b9dd81b500", .Okay}, + {.Mul, "6993e836332617959e792e1a915da0f2ba68aef859f6e1fd1fe183c96880b0b7fed53b1983b9fb361fa779b6b88e8d7c2527fbeb2b0dfaed59a6b5a29720281aad23e23ed97783889c3fb5cb3977b0ecd115d42fc2c9291dbc36a905eacdfd9df131c7155a767175baac40ac484a4990c812c2565b204b78e8c15f8d8225df1aca17378ffba1dd7beaa978ef60b3fe5b5285cdba5cec7b851a90da0ac37fb245133e5d26234f31439fc8c4e9be53c666bbbdc3268495f1b2004845b0e23f500337910b94bfa12588b499ab92be7b3ee51199b042b57633881dee4ed16203aec877ceb4bc7553d0519b8319e220380470afa89a7e856ecaabdb8c26e4536c570ae12954f35caa5fa8b6bd0bc2dd4fed1ff956b4387c116531b5939ac1d9e9a890d64f63972bba12abde4cd5e03d1f9338b2f72371f729335a1dd1db42cecf7aae08e91c11c35d96e831c2765118e2a396bfb33bb8cb64e8277cdbd5e78f69200631ad2505e87392f23adb601ea4bb53c0d013be1e069d2da936a0cf7132ae7f7cb3aaff1c6386aa5e919e892d4b9d6c8362eca6f73922d7a1874a974ac8f8479d5b2463eab61f8ddc2a90babfa8c0120ffef677ba59ec61f6e38184eb52860db56e88f0775fc95e50adbecc0410c43e2db955c70bcc73b5aef6365e7c1064bdecb893d60d6de16c20a3dd5e015e04224776d4f144fca9a8037c2bf9c90dacc605", "d19d593cc92c473830cf62c7d26dce2abec23fe03813d6df5f7e87e6339dfe5c71beeaf68cddf0356814fa366d61a1cbb0232804fc12f3618532c237847f099a45febf2c60a429c5363e4a7593b5f615c2fbaf27c39e3cab9d60b80a072086229f610666f462e756ca54852f98215ebb784f557cb30acc9072356755e23083f6f57f921fbcc7d7b65884f96fae1fe55514d225bead9998909ec0fe866b4a986fe452e84b880e78119fe6000eb1e0b1afb4f766e4eef5cf4ce9c68b287ded8e69e5d652e195706b0c579adf60d7555bb055714057f41c34a2b55a99a38b25cc5e2ae07b59e4de97ab3325d79e047baede0c9b88762c50e71e5eb5e627c1a87671f9a2bca915a6c907a66d4aef05aad3aa29a618fda4cd16252279ed4e5da18e71c6ec63964f20bda4286ef0a64e554ebd53eb5e53f587fa711cce0e4327ab938375dd719595ce33a73a2841a93a76aa8c14f098795a9c78f329289c2c18abb75426bbccc2aa12eb89e1af70f3230aaa9a9677f7c92888080aba0e9c9f6a27ff4239e081822f53abc45284f29cf7bfa13aacfbe6e49a68a79112cb1c19a9b99ba5dd984b7cedeba8fa2db625ac54543c087fb334744383469778a8856c692a0b6582fb2656f968361147f9663c0ba19e0d6c338114e1789ccabc183c654a76bd03006621320bcd8d0ce1817fcf88ecd10781fe6cb059f304156ff9a370ce5d065f", "5672a517265c203781a07419797c0ab6ff1af052e1902f005f47641d1441e3f40152e1cb328113a5e79c727305906191e54868c4cd6edca056ff704c41b4ae0284d35acf1d960e646da21614cb72654b8638043104a9e5bc552ef25f29cf0d1e96cc8dcaa106672c77055c48ac435f6be1e8686a0b92ea9a11ecbf57678ea19354960145d95c6ec7537c110bab39878dc98209fa8f13ec523c5fdfcc7efbf77a11fece29780065a0586e9eb1079416b2de0ab3ffb92a080ada40f436046c18fcd78bcbef28f758d263bd2929eec21591210de2c087aaf6eb7a514d3ec9e5a6afc57d60966a0d162ffb7466808d380e77e1e1d52abbc8f742c95aefb0bd97be4d23566b771dd13c5dc05fabfa0ad19a29909233fab56f43908924bbcdb275fff837b5a31a7d1bb4c973a136801b7cea8c59cea12d6e73daa8ac02c86b8c760567c2f851d7565d6c7bac873f407fa51dcba1bc03146aa8cdd863b42b07d848082471d2e7b839c11e951b72a9cb3179ddee8d9b3556dfa743d6eb4dc4014c4f46a3396f3f848270ae87568d422ffb22ae85d364dbeda52dd7b181a7b628fb57f5171c6211421b2c03a5200b3e7b5944fb436c053882b51462d9cd8bbee9c781fd28f6f96e7d350e4723798c73936636f3cd621426db1e84934e1fd84d4648243e3ead7a92ec273faf988945cefa3eb6331854e674227cec4a1c6b9de8300cb9203ae97dfdda19a4e30b3d5ff258f4fb9e7ba63e2fc9546951fb5182f1ecece8245cf007c857debed259f71b280b1f544ccb19209bc286cd70748e91702bbe6ceb025664de8e94dcf89a72a48919689596bb3daa55a3a1a1ec4d3eef4b117eda36e2879483bb52c10188767147559c5541b5ab5979a6a8eb7f7a9f934a4856e56aa13de2b3b8995b7edda736c31ebc53f457d9cf7a9d55a9b8acc7c11a25b3a9f46e6526db5ffc8a7e71a37a596467fd33578a9198c49c0efe9789e6cf25649f75d49d74af8d4c8571003790c80c124fc04ceb8f57acd0912af5ba84176c6c6fec96619822b31737bbc56ac0d5876fd565d1b2ebfeedb3e7b24512ef92d9fbac138e031c962a27d1f4cbce28fada17d63514615977e67308d9b70c0c2dd212eaf3641badb0f091346769b91727c819c6e5379719d239058cec7078f07104f8a21eac390bbf533f1198a3a52d20e0ae70dc855775dfaf0c6d3bdff5d938edd938c58112afe97d8a6f2bcfe5c345ea214b5e9c7eed1cf418517e3983cddee2df84ae45859feaf6fbde444918d78aff3210597c7b45243cd9de931a8c49d51d22f4f6a6d9571de1dea21efcf8f0057d309087288e70a4f39ec78a2cf4ff1fbbac1fba84f2044633b1935dcf93dbbf01d1e31faefadd7b4a941e8a9165767266aa994b4b5eadc46ca6a277807a7acbf9df5c60e0e5dff4018edcc22a66c0383a159299db", .Okay}, + {.Mul, "-5e2a6ff115789ea1658e93674bfdfa5dd43db513a4f8a3fb3121a9088bc27cf700bcfb791b3d333383a2fb16585171a7bb3aa8fd4d1e8d96fbcf820ac46376605581049962bd3424879d8509c844c66c592245a8229bd36e2c2db9254bcd3999b8d7900bbf6456847db802bf68a1aa9e32e0b7556cf5cf370a11b2224213a662d5b5c5328bfd950daa1ea2fbe7c700c4e1ae705c3dc5c0f79a869aeb89951b1b839a45edcccf24485d2fe0e1a8fc48085e86eb007a4676039a921f7416ce21090d18d79b4b9fff05aa5d79e862799152723ccf4ea594231ba1d56719dac8456883971acb4c42e6386b717f10fc1e13c9a0514dc21293945f87a048054a670b7198230caed139eab9f48753db2227450ad9f9ed414fe32270f0b588564d5528a34a66fcca23c41c6edd956f1107da32edf74725644ffdd5bf936918d29ce15c117e9a32e7a4350141102366970407b1c8796db4f428df6ca79ce9d7c3f6187739aa0e3fdb9c3cf9a0b224425e881e8b94fc40b372519442755e913e5cc58de21bd4f3e05e42a65f32c1012f76f2ffeccbac4eb492647fc6c43b48b02dda54c9a255eae84090e6a599b3c356b2e5bee82126709e597e55cada89e5068e450659dd769fc2180c2a234f380ffc0587a3dfabce8a24d794ced1658c15b61758e11940698b50b16524c27599df6c9e694f9628bbb61818425e92718087f3885d232709", "444d03a2f271bdb3555da63743941b332ea395b650054bb347ff837476f4d1f81ebf042bb70f14f080b5c8c0be1604212ed69500d5f773c66b747e905e4cfecd28fdf905859b4042f74dd14f00057d283c62d2473d69d652da6147e96477e645f8f6741467f7aeddd07e544def8b69da8b1bf75d5ed788b1525e4fdee23eaeb9cbf63a2a26d819872fb809e509be64db4e5314df036aaff8cd628a3a58c2505cd4b4df22cf77d49fe1df14fbbc439c80fe693e4a62fe51f706c5cb2ebb15ae54e7b222dfdb2b535f6cbc135ebd0725f9312bb8c112e2ea81ac5e56d3487089583382fc7322743fa1a25e98cb85d367118d041cf9fa9d3fd626fb495953d2941b57a3a8f5cf140df093286b50d117cb4fc132bde70931ad1628171ef8ada8644fa67b1c680feae16180a62f138d4f7f3cf70b169dce72617254ead9d15b084f3f15142ed4a26d8118bb7ab999a6204953599a69369d504924c135ef1e181f48ff6b864d5587e06855d08ec2e3ea86d88aeb3a0bb15a3753544f0149919349229b77549d1542076ef2aad5b8bbf1209c1c217e0352106b43b93d4c48b6b93693ed59b7b4e93cf15a95878ba087c5a6eed7518db7ead5762a76be8723ff8a3250d9144a194a7d9d03714176ad38ec2b5f54c456774c7771ef3e3895df7af9438f3e12c15af05c56377eb0d91cb174421b01e772b80cb68f1ec789e8489b7c6648b1", "-191f99d624901d8f3123fdb4ed2d4d4d6fbe33a5fd1d8701d5d010b4e73f5be1188beb7aed8a81123fa054370777758b9650199e89acaf8506af5c395a2835c9f8405a02216f2e0c96632c43f8c7c40fc42207ed113e6ce0b21780c7d355fa2ec85872b851b1168608c4c40d76f65b249ea72c53d21edee411889ce5a41ae4594bd94b7335b7f865bdf65a8dc77f41d26816c3357dc8f5ed40f917c19c01d375902d7474d451ab960009e2100c42f44ca2f441d485a0c97385a438cad5fba618afee53e25de3678b65f6aee6832aba64d7afdf880879c4e7cc62244948223c59f47c6453c0d6a54ef30dde1a4c3d72b127eba4c5f217d4e0a6a647c8332df8ab32d98a6a89d0f3de9ded40b584ca29b6b8d0fe7c6c92afb43491e6c40535df75bc32e1d7c055e9cf515f267afeb214a29fcb24f38ffd9cc793cc2f935ba9b29c32e277c1a8f82a423a14e40edc94f7e03876a5a8fb6cc73d3fb1c28ba3e05a7206d5d0f22762b77885a7d77528f6da268ce3e83f30fec5e8ac964bc79ac2485439d9c2826a17458bc2a4f342b583b96ad9a8a104603b95ef6a1d8912695c80778c3eaaa1072e4782f67f7e8b8f613d7abe9e5c65d5d3e36b387773de4b1982494b1c53c7484dea1d69b3bf73ef90c745b82f928ade8adceea5b2b95a9a8e2b10bf092c93459be0a4bba4aa99dc4315ad76a74d128f95ab84539ab391f8c5942365f3188d0fdb9470d6cf9a3f2b01ce0e0f028dc51fb41b6b3660a02520b2001124de69ac4cb7c8023d45d7b0e99e8f73f6a1cb8b320928836162b9ffcee63a43a980c8d87652c6a32c3b4ae258e53f90f0ae16e3a31acd14ee30e531f1bfd134da5fe09a0f1b2ca646b3618ddb0e6ee53a7e63872835fe7545fe89f9e46d71256f6161a9c67067968fd97dd4b0ba825dd63b83e266559dec81da42693011a23086bca3b536c2949060742a624627dcafc165def19d78ca8d000de1169b239c952a7254e12608e322006e9767f295c411bbcef7492d28d9d0dd1e8c371f460abaad3bb567a6d5e4a45c22c379ade13de087ae1d524d74f2a0f996c775ebfeafc77db718069cdc942b2d35abb576c96283202a5d67c61183bc38c30b7deabbdb1e4b72173093067658f040b6c4fab81dc5797c50ecc1f638789498354a03eff82e1518bfecb09915f02be086004c2eac8bb13742f9bc07e6b703aaf4d4ee739c8c8755bdfc0dda7ed4bf15cb98d3680b7064ceffa09c807c659cd851ba628309d425e402440ddb009dbd563e59e94c2349b1e9aa04c78ed7ce959ee97ad41ff159b269a09438a6dfef2d25338255cbe8efb40b1a71f705a11a033dc8204ede98d37db79c3d2706ee60f6367365cf7f9e842722193c9c80f3becdfd878ad5e2e2f3640ac7cf54bc82c5df0a94dc0f26c03a8ce72a2f4536a841a85b08d731de8539", .Okay}, + {.Mul, "7f30bd14a4d457d7d88ad1143c9bbfabe57ca63f72a9e7fe2fa980ce6067bb0fb0161ab0f21442ef55950df038ad5e3a1260903ed609e875feaf929affa933e6fca7625e680e4b43e6c5188dba834c9cf668c6f7dd3b57d4cf49afff331bbf9dc48e5e978562d6511e004f319cc739b1f6eb3307e9f4984864ac1b377f6d79ba6d6ca883914ca10ea47d0fd0b6ec792752b5afa8b198cee145090777b294affb8a9a58af64622204162ae09e00bca6428b2764b49042b3a74f4fee39bba626d02e68982f77a47eac8377358aa0d585b21d1a943f69e23076ea2af93963368da4aaff2e96deb4e96069c6a45cee94700d70bef1a3e2c28fd179e741e39b2694a577d7322e15071b8d2a1bc1b7c128c8fc3acf3b72e49990279c8cb7430fb0028e9640d874cfe58d434526940dce0f97ec70e98274a0763182c29d89c2c02335693291afedb420fb05e80dd2a1a82e9e8113d936e4f538e8ab07ba9080f2bb39cc88b6419ac02bde5183a23e1954208ffdb292ca42c285a0719a606409d4142c174dee11e2470df53e9df180a5e32abcc80314d0b997d41f068e86582061a174b67dfec285e27d86eed325631d5397689744de6816d874ef47fb82bdba2cac7e353e3b7a773c5efd8c2b454cdd07471b96895d8fab33249bfa988e7d3d859aae2ecde16304cc3f2be9a11b46446f7ba8f76d4d29610792f871b7e83fe5eac94c6b", "fd2c6741e47c9b1c13a10537784785c3b5410732d178b9d6e158565f7c246f82fa4b3f49462a1b8932359d91d0b868d8aef72e81952b334989f6bf9f811f7e339cfe2d421fe08caf53568978c6b06c21cc5ec41fb45d9d1268e6c17b2ca1c03e051100e971e799a4e8dc2bdec85c717348c64251ed5b8c094d509afaceeaf75a7878fd4f6fc998d19c7a2c9bc257ae2d5231a58f4c43e2bd93c5f3d67ef40f7c94f6c0e743136449b89cee7beabd9ee44b2401dbd5930ad812b24ccfacb10bd91266e9027e576a9f500a7907cde2b5d5af5f949e67e9e0bbc68ab900e05bb9afb8051fef4848d5fc6c3e2f6fead9cd042c2004ab3acde166e89140de2f04259d599a166bdda6fced4f8967e70d1beb030065c26ac310b2956b2921f8b86550326840925841c65a26b99d4f91a872494290f0307da2d0c44ae8b4b7317921ab552c0729688ea9b2b2a599f0979a28152528c287dbfe52287ac49590f14c311507268560d0ba5be8b8ad745bf9e72e1b8d21fefb5f125121cefebfd11a4707669df6446eca38bb7ee5561663c6eb37d793d8d5ae9fc4b08d2e2346b8f8ce4453d96bcffc8928873de3b33e7d02567bbe37dc85449fd3f833db6c5a5e5bd95a6ce6820f1bd6593feb61962cc554765cc2a97db2453fd511c04f1e4b3f7d38aae30fc0022b492ae8844c70aecd98ca06bcacee15202057cfdde6122dbecb07d68376", "7dc93a8b3f6ad0f121ba4fd71bb43736681dff3f63ecff25718490247526756766167b91f3db25406318c0cffbd301973ea6254bef4e94ea05cdea98f09f698ccf804f422993197e724484b15a28d1575dcf216d2cbff0f912be7968bdecd0b58a664c07a0aa651cfbaa289964fa60768aca300fb1d1f3a95f51004840d08fab5aa6d7e6705d6a40da6c34a3a5fd03c180c77b110bccac3f64539c3e8d03c88223b9124ea10fd083838a160eda0434e4de42de8c508c90134a6a844614b4920764f869080da69037337fcc976b558861df71c5bb01cc4da7f43d68a9194baf84e65e6df217599f4edeff7e8796709a417ee8e135acb51bc605f877b600773a39a51c78b835e39a938a4bfce6b0990bd7487e40c75d4062a2ea8781db34507d828af43cb9906f7dc5a48fad20f7f0a04bd92b62d006c2b22fa323ac178a4304ba9fa81713f10548d8f86ec799196b94a812bcffd72d02ef6d20c412e18c118bb4d9150643948bd0ab1afd1d33a8224b955fe94d5994bc96739cd70433bbc6eaf5e18ed6cad0b10310a78298749ca1501755c2b9a5939b24502b6b045b8095bf4e3d8da4a64ab79a95dd8e73905e08c97455da24590b3bbbad1ab2f05df7677258ef3401d15f016f943915ddb8358e77a6ee5c309843dc0333d93565e5b30cb8bc7cac109bcfa24ca26567b511dac278f76d5fca50a304021c45cf679603f5e388a9d665ab3457a90fc971985d187f609e8db5e454e2931118f94f04cad089e61d31ac749ff51cfde3354907866ba69ea2e2c50424596380348f36155a5d788cc397d4e7306be281bfbb035d6be75a05e1f743bba835707766b56215182b63d5d655ed6e8a23018bb8e01012bf60a8c4ab23228aeece456a0d8814bd455d92426228df7453d8beee22b6df69e4d798519d2bd4c27a145f6fcc745f24fee8831f84a1aaac784a0d7da218b4d7914f9fef21845e1f5b7bb1ce417d6840148d847dbe45889209c5b82347778f1dccc7ba1070b02afed04564d3877ea47392c3a7e1ce6d52c8291db15261d6adca1b14ef07449da1d8a694381934f67adc220885ccfed48d96f1d4357de4c181a98cf3498eac58a87cf1b0256cbba5aaa6bcef4d2571623b49c710b7dca4d86b48a4dbf86765d0e79edd2ef097a874b5001c2ec1cb6ef371f24cb4c1061e64b70b4a4abe97c3629d81d30d373b7946caf0e2b9d1a223a6d8297213e1b643cc61afbea6e3a11d7b1dbce61c0ad28f02f7a64fb4c79218ed9ab0e167846f67cd78cab93a963406305b6a48dfcbd32871c78dce59918d1b1d4f2331e146562336dd7cb585ad0f85cea2bd9e0578687816138daffb58a1964c6e0a2262adbcb17da8db0fec00ce4d58c0803c311b3d723eee3ee8963b9d32ce699f77561b26902a4bb478bdc68975a5ee379af7d38ee1da83e3550955fa52", .Okay}, + {.Mul, "d46f2df95f88fdcda55e6bf03465eec7ba12b903c6dd42d3b37a1e6be7a67eca6fbe36a5a80fbd8965f131b3cf27106d5b71a9847cf52d985308b374c11b80dd12fe43429d4d8deaaa4f0957b6f62e55cc9cf6956fec699f54ef3a4ac0e17e722e503b3114d8d2ab30a6aba68820a82625998164bc12696293195c3970d5db60d2fd34ea8833c2e87195b1db86fc1b3f38c0a07d2d89e1f56b22cee7fbb5b031c1c05d8ac854f052482bb0ccfb188175f6cdb8a8e3794abd68dfeb37cd85ff73c1047c93ce8131fbf83a7927964a6bae4ac76a514394d8737af3fef89266cc43f156c6be5efbaa73b7152ac1a869d852be834ca6d58216df6265757ad547a4b2a2025b1920d94035df083a84e594d7f8b41e9b0f8ef5ee315905f6d319025b3d98680c575b4579e1054297df8a8cf1a046a469b11a6a7e24be4d24a2c2c920efaa9ad59cc51c029f15d4e83f793cf7d32b8edb8aa3d8011c8aa83bd5704df81478615a647c664b619c470dc6e9cec198472b4f80071b3c57686a665602819fda1061eb6a81fca8fb06844cc8f1709c4508a159720111ee5c01466d81129f1bba1f7591a4c327e67d19319579b3d5f7e1d9bd196abce895fb8bebbff1882c5d81d129948d22397c5121bcdeaa1e41f96fd3d071c1b9712743ffc8a9c2e502fbd6dcb0d7ec8a94e650d74ac1394b86250fd3aa01edd7b6ecdebafdbc13447ffdd", "bbcdef30c24bb84aebecff91de63612beb06629f5dcd00ddf54b7a75e908e2863a96e7b3de68e580c1c479f0e453a72ce409e47a33675477051e8c87f2d0b1b062788e57b0c6ab44439b0ba724dd9964dbd00b8359172b1fa3f5411726107f118bb91f447f7bfca9576b5d0ed45b36cf8fa11c2d7f111723e18f42224b4fb2a2a2bfdde9c435d4241fddf8452e32c7292ff7483c4127fa831e39f0dad0eff49585be85b2bd680b0fb804e9fffab8673b16d619e24a1df41cbde7fd27a8a736828811c06dd76d338badd94566ca42058f279486434e13b4df68737b26bbb226668aa2f6495ab3a91a9c2388c5319d90a2278bd0f4e4f27a50645d384251d3f64a88bb40104b47ff22942efed7f15bc91e2582f79be1c8b61a200c9126b0b8672e0c08b2c8b1976ab70c89a8b785fdb0b33190f4c95882637ff8d846f4a197929e3485a5bb125ee740af0a7f5df675b8ebabd46815b031cd5e99ae6ec6cb9dc8145a48c943d01559ede43c1333fff7a2850f87d880d65461f58c4cb3cfc715bd6855d0439e62feed8987b75348575c37218cfc1b7055d42f243d3b700c0409b01c03266d4add989f330d60474383c8e9157aec317bb4e37657ad89d4f685be5c5f7343b1fff059cb3d2873fd822d2960b90fe6b3c5307e5012209103746d4aca4b1a659da773b7d2d27967995a61d0543f2d783aa69124ce9039bfe3223ef9b646", "9bd81a193b7a1762cb8607656b963af2560b6559f7d18b5bb21adab6aa5d45c1c7f0bdcb3cecc9503375756530c8d90c754b9882c44b2bb1da8ac70b751b719b8015d0f7ead1d6dfab3ac98d68552e684854dae581279d4a33c64e8f49f81d8d108f4b3280fe8cc8970349d29a4fb757d5901d9c54b377f6431587c9a7953bcc808e599d7bebba46ee4fa556414d45cade4d1a538eb26630dc5181c9133dee9ff71c82b1fcbda25a783a219da335e282de18e2cf66bb30512d2b3d52fe1fb70a32bd027ccd98da9e3f2b581872f116353540b6276c005fea2b6e5cc4964695fde0a953aec7f8c3023bab0e02747b7ad9b96dba097330a128899dc82787a6bdd5c6f83de7860e0dbcd8228d3a329ace0d472e91419ac21bb29439e440ae81062030b3bb612362bbf11f7750dfe9794c8a48c723d2f8b139d7a1c72c46ac57150194ecb5a57fa5af4abaf452173a8c6ed3be7e40bec90832189d2ef31542e50acfd1e1dfbc615a512f44afda03fba084d56c47997c2d68909482a6982db35603899eda554eadeb592b9a470d2793dd61d6fc71b76d0727a6ad8579b20ca7cd57b7fa1ab51f971317926848496f89b84de5f28793df752793fabc7c7f202cb4efd7c3dadb594e07c85ee56b7d09ae3a9099ed257df1f7fa604d44ab7b8174b449256231a327b26f5e3d2d37f694a3804e610a0b73c470786dbb6e0c0cf4945a1eca5b43ad7a5c6a564901124dd65347121bdb9ce3d9ce9beb78f92f08d321183d6c87b740deb05642ad4ed97d3b59e4acc9a0be954f330e9d8fb713622f7bd4721bc451097128313c8fc20c1d2779c7bc73373df811749684c2f5c8b5c25a5d1663747d1822112fc899319fee53d3744bc312fefbdecc71da6386a4b915147fe2704473c1d029ba66e55fbffdff6cfa5ec4db11b699b07f142a2dd2e088ea3be9d9915c5c8843b5aa431024b13c0d6ff5be609f78c2b9b3643e1dd7e0cf2439d0529ba9df12c14b5d48452516730687c70bf315792984410237ee8bca8eb8af25ee54dae5a07a640ebf0e57cfa3c304bbd462dabe9e6d9a89871bbc12b4a80563d122fdef143ad482caa5b2eb2a56f816fa0a28d42cbb150858b102a0612f702715e50ee88b50b51cff88b2203f9434b18602879f8c6702c207ad3b21ae57707a06f103049bffd3c9aaedfe2b10390fe945b0e56ce607ce295df4fc11ae5f03dcb885c1727d419324aa966a159b28dd97bcfb5b50e7ee7ae0816f20424a1427e0f6107f09fcb2e2d6e3cf37fb75a4e7dbd9db3c5bd1f270426a369d3e7c99bac89b524a0af093ceb98861031430c1281545079ec6d63d8257476f9d7da4424d2d28744a8dcb40e0d6b1e0328ab5cee5e58827c88c950d667735c1921d20cf1305046da30e4869b6a9afbcf4476d5630627f1128d5dad5ed427e63aae58df8c146e", .Okay}, + {.Mul, "-3eec68f8ad936024d652ede54dcd833f95cc184ca4052d3db090d5e24af0e963764305de77027aff06e4af47e04961ff05c43173e8c90877180ebd4b8328a3cc02c543055b48b3a5d3e2a6d751f7405a3caa85a5ac8d01e354fc0feaead9ed8fe612721049d6923d3f945966b54faab7f3275a5f4c993b0e384e7a4f3c6f1091c19bbbfdc0c63f71f8f1892c793710594f81ec44631894e541f0718f816ce58f32b47293b7a62a5ebf680621de5a36c42286b4cf02c130bb691557a90b784dfc51c7c220fa0c79ea04b5326a8b011d3ab4dc6c012ed4602aa01d7adcfc94c50f56bd06bb6a98b974c0bdbe77654e33be1de3a20b1e9e042869d27ce9d9b593ce858e122dbcf94bb86f4cb677fcb6349199163499da547cc8d6e0d1e6d0799eb008b8b20c9875034430d0b4c9c9f51d0a1b8b76811f4f0ca985a608f122fc4b84dc7493a109993629fdb630047cc8f68ff547d62153ca463c7d83af9183ea70fce785c61bf97c4678260ee4608c7d65d9a16f2de77d89f4b19ecdb0cf9a7ab0d8a3f678ba14d919e54dd5a40b1a47df7ccf7c18c750cfe21f32b1b13d155063fa3b6636ea5419e438737945fc69aeacc1190c43fc771f9008c1948fae4b8b0d732ad36187fa3d73f5e605ebe2912efecf8cb55652504f01633af0120dcc1d94f4be044325783e933116639e287e64dbf173b352284683e7fd083c4b02377a143", "33f3f2d65fc43e3a1ee8e2924fc54e35460028f9869c59e9c63daf0ba54b7aeba012abf7209a5c04b3abae3ce4400f9bd18c0e57d29e9707b2f6a58f2ce1930e4fbdaff84480e661df7a0d986bd91b63c4ebb9d4bd7e2e4067720f9fc40c24faa7166d09e902cc624475fb0a3baff13cb46de25f532adeec116643815ff0ee7d32b8625ca23de6958bc03007fb0b3d4d3751c46a2ecc45eb55bdd26472be55f7e07553393bf10b8c5b6e52e13dba453425032cdf0acb1274a7fd88cab6d4e43b68527b7fbce7278339dc4775570303923d7b52bc9539a999bcfb4646d21666bbc407e5e1b32cd73ec4c3e67561a3ef15f93ac9a46e17bff6de5a2ec1eabdfd043813cae68b79a9dba16b2f9a41f5799498210a0b35233a3e2f45dbe3ff2c76332c3daa846cf12512b32f0e994b6ed8509d8d506136d14625e03c55e3608121abe6f98ff00ccb69dd5fb5ff0a80d7e8b211e6862f5d96920e0d30c732241d093f6fbb02b9caea8d6b27318ad2f6f27b8756dc14cb685a481d29a11329df9cc023df181b3a7d6b01180a2e08f91675b1b56c6b026f84b4e2aa57e0c26b7279c3429dfb09418ea7052a4649926e560eba4af49b149a6e8a3d527955f8ccf212edac0522b15341b8578e129369cddb00ec92231b4508f656aba120af6f90159faf9573ace3cb3686b63fe9d86380edc9bc19a41055974e93a86b336a98cd611bd337", "-cc50f015b05ea423522b1a34a976be8a06479a6570cd3a607a016478c720c2bb81f6c7146ec17e2aa19470738d88efade9874f3688b40671454163f3deedafb7ffa5485c83a9027929fb42666c50b44614f87567e319b27e5a3ff4ddbfc41327ab8c1c396ad310b107b4c3e50563d98bfd4f63761d7a953a548465d224a812e7ea27c0b55c8730e7ee5f5b9b6a0cdaccd43ebd3a46e2841982a738676cdc1fa2d0bf846db462189da5d99fdeac299f16f2045cad305cc38c7ae7772199018c92011210db4a41e764305a4af5e779ba0e57ec1b2f44ac6863f9f8a4024408a2384052d34b2a9d8997501644a36f1838ac850b851bfa19b065934b73bdcf60c9251cbfbb374cf16d9cd796445c53af3e856c27bb4727dc2db1040b396410f042123e0ea0dad43a9c5bcd6e079e654bfc5d73f8c15f3397dff89837626b55fdea0f500329e3babdf8aeb0277e6806c91b3fe412a604d88a7929a124cddfcea1e71fcd9c150642d942320dc8be13b8fca4114f9dbc16c16ac6b35f999b71d2ab74964186288f81d26c6c102971bc93c1109103e8497ad24b959f4ff6040ab0ed70d5ea3de636af2b18f35fd72075499a98a55d74636b11e3c2102249e965d6e39bbbce466c24db7ce80e9d3386b8e10eaea6e8222edef539f45bc73c4005c12ac64e24534d1b7853c05e3673777c81e3d1a89a3ced1ea472e55907791ba99e21616939ddf315a7462967496a125e9d83aad2100aa2ded33b7e9669265e241b39370327f0a3ea512309689a1000872bc08c1679066f30719888324fe7ead05878864c69bbba47a9fe23cb3af894269a96c601ead2f1d67daa22845f79e8eed89b9cfafe7563cba0b610b450a8d891df7916d391be6664d1e8a5d962742ca9c0809cfac212af1c7ceb36ed20d639d27414c22f890761631e74e4879f0bdbc90ff4b097248b903b83f6f1906f4cc743bb308be943b3d6c6111c5abf591cd0c2c4a02bc6dd836d2fbd3eb6b0679f16ff27cba1cedfb6c373dcb2c6538a3f999e32e7bce0c81c18e1828e592a0b220473b10de9ceb3a4526ecc2662e31ffd578041aa6a0f88c2bc4f6d755020949ed93edd4217ef524c28ed22a2c060d3a2520d6d43595df4bec4df5583b23b3da97a19380889b8d8cf07d9d612653f284f1c77ea92690b2a56576ce398e3323bf1dbfc470d86752bb65c4ab659bd7e629d47ed2f66f48ad66fb1b6e296ef2fd8c2100c03835e5ad7af4410c06481e6cba6f798c67953edbd0f377e02710480aab45183112dd6e0b6296c2e2a003d30d6841e81ad55726b5ff7013493c0d59eee6e49d6f532e7dd362a02bf8762464e5a2742dbca4106a2c33c7e8c5d2a44cad3610a8e57c2606e6609c7df8dc7ac5cb0187fee4d9d41d375ffa77cbc2a4a8621fa65ad21e94d9dc4d65e79ffab8470ba6b729daede65", .Okay}, + {.Mul, "5c375f0ab322556a5979b80f7f8d0755a92a8bb0abc4d3fc6e01588771206b6a1384e42eaf98a404269f8de4699d6afcb3b5edd219bca03af9ce3c7ed02bff05edd896b7b3434a0c24c6c1e17044493a6623fda0128dcd3dab702bf77aa0971db00158759e4fcbe1a864f97759b4fcd591ce8cee3413b0ee52e49a5a61245ea74f145e8e7a6738ad7f6025e974c774d6be81610e0a7e9b9967e8c42e05c4bc782ccda2f1bab15093c060b0a1225e2dc7ce9189386dcbac4a17476bb292e514d54805a163a66c133821b512131a97c6b11d338b331161fe63a4aa97f0c1bb3b3f603da83daa687ad6ab73f1e2113c0eeeaa034e0c6dd0957b89aa9cc57c11569c68e51f156b3cb4fb1620e8a55a0328b3c255572baa9bbe71db0163a56c503251e4038f78039a3a93d82352011b69516169b123feaedeae473f15b47b7edccc87fcea646f838e638a49a67879de04c79c12026dbd67785970c996dcc411727a8592bcc7b42749a17acb2b734315fcada1dc2ab6ab0b83ab7e677e2358d5abb3288eaded6d4b84acc72bb1c35abf3299e9a6b2c77256d7d173fe3086b96e504b7d3c891e83cbe75ad9c5ace290f7e9eed1c1228386bb3377d072bb1e8d6dd163ce4b45b5699fe85da1bfbe7298cd43567fd1a5cc6c072edfea939537288daed86e40801fe30feaac1f9f40994592bfd9f2f98a5601c0c8b47ccc6a679630eb41ac", "51443a737f9e13176961683ac5e3bc433afb70992eeab10c11572a08b0c94c9085a23ff5140ebbeb6524aeb3fb2e90bbc6f25fe5042278361422d82cc2e69ddc395f2f7faf75bb6529e64b992c04b788bc8c7df4fac2144c3e39da72c18e6d05c5a125e89fc99c924bbcb71ab939505704bbe2a1a135c32b692de8c75a7892a68202386807e72e1e37549e1f7bdc02e5f5866a2f8b3a4ab49dc4d1463f653fecce4f4b643a86dab55dbf18c6bbadee7cd0a8e4ba6dc74c8536339839899d2412562c3efa37fd013731b6adef33428f0122cc19e7a26785e052592299abb648f6ad28052e3fceb9f77600f0704371bafb30e8ec77cb071069fc11272ebe4ce0543f37f854d707c2a1bf786e0128aaf0d1f41156e535f89b61fea887f168cffe285d1e84d4debbd70b0921943a4cefde319f98f3e7c8eb475161a0e49699356da45358fa208b0258984de9c089669374fc8f8cea77ce77c0c51d185cf43a232be6d91688c7c81815e492501c07fe21f24bb04c3a52991bee2248cf511f20748aaa62ebef7def66ac4a00839152714176ae3e18c21e9d7e3a498969016963059c1f00487f99b58b669d62474c2dcfb6d00317ab6fad2e0f050425ce21ab9e2c4650a2c040dd7e9eaeafa7d303aa0169c0c119609bae9cb62b104c3371747c3dece88358b1ed43ff8d1f37b016609e9f9de4462375123447b5ea528af9c960fec9d2", "1d4618d5c7e5f9bd18cb77f1c0455a909213f7d0181a3b948c664c07d24a5c83dac8a9d06bfbcf2875243c5ca70edd4c546bdb5eb459566cc0d544bc5b91bed22828f51ae967b48bd594a0e91443bb5fbc3163648fb3df02cf59c5e71ae464e1d99b1443b07b2ff30898e99fca16a6fb5da818be5e12990e62d2e11eb630a27d8ec8a8d9d23d930408e9dd6b2f508065181d08c100ce4cf8c068cc616163d5812b41f577275beb66d848d184c8a1005daec8013e46e5d8730600e2270aa42bf30b0017c6fb8d6d84b74ec3141a8c42dda323807dc65386144ff18c5164304f12eca32f2ced45879717795872383726fb896b819324e5ece3726bac4e4b5c03b350745c8b52280868186bb2b1111b44f21c3ed0c0f87dfb66a69f1af003652726e0bbe8fa1705b9aec358e1deb691d66682fd70a428ab78926f3a63711338f4cabde3f899834df8c078dba3aff49f1a487e596c7fd59a681116b9fa0ffb283f7d9677b037bd2497a82957769791d5d52e9428a823c9a8e08cd24c63ebdd225bddddc93bbbf974431aa628e7d11334d37b3a96ed34b7d97bb05559ce58a3985e71a51d2d6247df4993ffcfe573390617f7d65ce612586337903f23b178f16dff17464a59a07dfa2261fff19f4d38275310cc96dc65a8b3262dc13140e7d787fcd4b645cd434f0631b37a10760c933e3853c0c2cba59dd41f6d4347331174549f8269a2e8ef3c49457559bdb7105ea60c958f41301aa14b8aefed2ab7d4f0b234c35a61a257e2b252da4f628ab28c5114b33098344fc311a6b54fad8c07e432cd4e12450ef1b469f18677b82cdf09812615fca294799a87c5d85e4456734b01fc94d860c47ee35a3fe6bfcd0a03b934e5bf39f9ecbf8e20ee42751d1dcc732572ec929f715a83197b4ea6153398647ec7641c64b2eed9d1755610c22083eedff8056853b6a1f41591c8bcb8163282b8304021daeec0db9926604964261f92caff10cad50e27824e47851712befbd3ee607be47ca5ff6f5fb3a3bfcdd8aee5f84e246edc5d9804aa62d391b3dea1830e97715a4e2e845068e007f61ce7ad713ee20a26b0f7fa3f631fd53244431715969a066684c24d2fa78c95f94bb58fa78b5b35bd7c8168dd455adb6d863e0ba691526b4aa3cf32fcc558bca7044d9f5e0ced049e5e04c21cfbcd5c00b7941cbb8bde742c5539285642a2a8dadd3fdeadd3a6a0fe735e3d1d9aade7edacc81207599d6551220c604d771812a8f5ea77257bf2f4a65ec0293be6004c762f7e8282fc6630b4d97435f0f770c63c0cc2c243fb37bdd7c9c7bf963113f7a0cd4d3672b02fa626904c33a20d4d21816554928475e361297d67c9703667fee07cf0549ecb5fe2bf32041819f8f34a47333f218afc7e577d6251b07140c343df45673455afe80672174c86beef8ade0e4983b48033eb18", .Okay}, + {.Mul, "-cd59cfa41c1048b96c016b952bdbf97987420e989882ce46ef202c329319024d620ff661b460509f743f0e2c3b403e06154388a10793863295e97b0ea48f07df3cd84d13e71134588fd532e3c1c7e889949cf5eaf53498f46176fd0c21edb7e3f83997ee5e2c46e729ff6deea6f8690207915a7f63e98ca4ad39767c802df158a649c2cae82c34e4ed3c2e6276701098bf637528b056460fdad090b6745945e5998bddab06b93401e878ae7a510c3b551d3dd6245d1dd6b0cd830c364f79184f1256b153f7cde54fd293192369a82ec8620dadce41a2ca2a24b1c22fa477b6ce7a0781f0fcd3b7f29fe517374e983d2a6ca6feec919dfd662b243fd9fae2748f63bb6e5c9297e48efb741a81bfa7fa720333f20ec5df533f81f05178acec865da07b79fc78b6348ec234cbe5d71e21c3d2b3c8b54087b47c0f18112a4b6115c63b4c62042c62b2c32a8a0f7c453f73957911f0e3f5800ba3aca597ed57f174cb350a64906f2885e361c9ac0a809fdfc15fe6f3ea7e427711341ec5fc009217c7e3f64890c2d8833d9af3e40eb315b9dceedaddf6619290ee7c55b6ad2539d6606596dd813f66d1ac069e557346ba0c78a7da36c482503746296f41b68d8e248832d8566ac720969d03f9a5368f6d9b00ced41c6e86da69a54cc120bd31d7f12d07786f6784107e8c54405a3c39110be676c3240ea7b74fbcb3e7aedeb275a74b", "80fd6bdf73ac58a83960d01934d6d12ebe0e8a3834dfc59886f70c25a3e87c973beb98b47030e8c6bd72be4bfa261d618b0b955be06eb6f90bd421c68927b6d350e6b76fcf0e47b31e57d276b990117522ac2b4598e75c3dfe3ad63262eb2f520f46ba99c881806f9a50a9a129eec9bea28c2c69f6c60cc3ead8933b7e4d639a7c0bff3d36e67ca11d0d936f17b5b0441f02f6d0afc1d529e65cbf2811c497dc70607abe19a27337d0ca043946137e0478716d340d2d50ec1c27ba607c6f2d9fd795de55fffaf446a773d02969a68e2f68b5dcb98a97b96733a20926797d5a7b53d2cdf2bd27a238490d8ea001c61640f47cf201be66a56e51ec586ea83eb922ea55c02ebfc5cca3270d4059ec334bdedf370aeb8f02e3def36deeb2e1c143148663efe838656d22764624b69a5f850be83bfd46d0d411f9e8060ffb1f06f176060865c865a79b2ccda3c220fc141fc061536e03c44a79494420403b1b48e857bec8bb7ac3b8c0057bb20cfd089367e7cc934984730f9fcd0bf93286b1839596a689b5b91acfee3d2c688d2d7a7e0a998967c4b7a8115a59488246aacf9eef3290cc5c8ea5e7116788090d6ed724c96d0a3a13146d34d0826325ca5aa4615412983ddd8824ee3c19a81ec0c2c5de225db0466b497db6a49be4077edf2f641287ea48d51a416b911f5bc97d3ca2732e8d4d2e27acd0e53ec8e9038ee63b5ad98f", "-6778301c0b06efdfe10acda659fe63ad60b8edd6788511d948e3557d17f076fb7bb03e99468652c136d8a9d7f902bb76429bc59e652a40565cd61c438dc2c2e36030c5b0420de0b517b74d66a007813b4fe2ac9dc2bc90713af5e325a78a5c68a21b8e6a4bf45f834a3911df8c26ec16ea5de8e7a01bf7c487bff3f68b9e41770622a2a1817d85520caf25e35e1c1a7f708f9a32f57c1829fa0be723793b21fc2d255ce7726e8cdea9c6cceddcc0f72a73e7da638aaa8119dc547262cbdc2f2074a78b30361416bb4a9f5261fb6223bd7d588bfae5b458a733cddd4c4d726d938830aa773ef13cbed7be1dfc1bd7bf7ca6585cdc0e5e721f8f54f15679f1d0679d32d21456f02a3d5062e01e1745998426d20c59224b91f400cdaf3e11132ecb8a3adf72b653aaa2aa86f6e695c7d709c5fb635624132036352de991ef9a1c71be195f4a1fb5792e2aa9711cb5fb6ac7b2f09bb00cea6a314c7c9ae5225cd857f51850e2fa1a9dfe8fa63017807248be2e2e63ddff5fe03697c7c1197be7d0bcd6f81abbd89ff9b6cb3ef090efb00078d1cdcd7e3ebb670f0b800e48d3d663d0860e395727d89b2e37364edfb7a07c54c2617048022af99cf7ac0a707c070cbe1ae69e2c12e1d9bebaadfb8a5cbd571e59dbbdd18f07ba46e6d2d39c323af1741ed7d297ae7c97517318f17b108c94d250ee5f030b947b4346064ae99ebf7a0e6d68fb952d3e6733fd0efd58597408c55fc0da92006e949ba8dbb601f2c676cad5c14ef0bf5c2fe4b0dd89ab6e8dd476ab5de4abe510ae58d57f29207c8d65e4f301d115d051c48ab0390daa074c04b5f2c41c03b300aa96d64a34c25362629b62937c96690da9d76e78c9e1fd286bedc991ec3247bd6e1b1195155ee58c566bd6e82c176bd8f186aaeb84aa991b5774f53c964e839247591c0a04e9f90acb5540d8b6963aefbb7b7911b03abb5efdd69b8168f822f933fa086aac36e4f07d7981db3eedd461848fd3bbacdeea4e4a1a0b62c07afcc078e21088740939bb4d30dcf3cfecaef4530b3d44acdf9d30893d5b876a0da3d90d68d3eeda0d48e2b7178689bcdedf4fe1af0d1949a4ea2fac95c1a5f5647a1c54c662a1d9923d815e7b4ca734fd142cd190409a6fb8acd5a31532c4c3e87782807fecf76945d8b70494de0f724efc2da1ddd105d2a57cd92a8b5791c880a86fb46b8ff44b5c1048eaafaa0cf535089b56309f3bd19db0873114fc88c2e704791b1c891a482e0b80f8f56141a92fde33cebfbf6c52abd8be424da63082f533a24a6165bc988e7a42be5a7389701079210de63a42da48d2a35a8f44bb40cbe66fba90a6b0269c70e7ed8d6bb87bdcf2697e6369f7f9b92799a84478a91d36385f000ddbc7583931fc1ed8750edc8760840a423982c60f0530b82453d2ab23fa7fcff6807235f883e505e5", .Okay}, + {.Mul, "-bed8c90d7c61490d27cc12583f397f60ffd1d460ac34cdeff70e174c662dc03849c97b87ee587f8911dab6c03275d3daad1c302f6df3879f24d2001f556ff270d1d70c3fbb81200d5995de70db243875c5ea31511a51d8e49e122af5e8e4f1e29cdb04bbc9ffac69c72ab7c008ef4579665ffa4c5091a5b12b7929f43301d6e5ccfb395d574e180c6b883db573137fbbcf9bfb6d3b51e6f0a99e4e62358529f7e276b3c5a5fcfe4bc56ad56714ccfd7912226bfb00dccab7bd2b828b10484e1e0cb076b6e601c238df1917a4dce47b9b3290382df683206bfa7165700274862a533a06560d4e380768b0e1866d1ea0561517a8436bcefe868cbd341c04d8a7a4d11fa5674058e814f88f6b978bd189c52db982439dc9ff27c65420c0239678db2a3e74a09caa41ef9695bf26acf20ffcfae40a76c5fb9ae544d93fda3a257b863705fb4348126bf024bd2163b6045ec5235898a69e4dbdd857cd2e29be3a14908a018e1c8db07e352aaa0561a0589a890c501f2c7efcfb73e9b0456c9cef522a1904211c1bcf5baf1444c201ca03495fb9050e7231f307d9413fca79528be249a959d63c914cb21b96a6f380bc113bc69f9d7caccb63724a287d3296fb989c68e1fc5ce76290b5e2b20bfad01f71b3cef9fa219b433299375ebdcf47652b663370d7b20e388241df6190db015f847874e05c1920285c485768456801880c4ea2", "b9faccfbcba160716d798662c1ac9c641d8a9a88b780cea3c3b18878e851c4cc6f96ccff54f7264d6251a5f2c0f8dc8494df8ab4d7a3acd2de4aebaa9d2ca36fe3cb277ff5c2f5902eb80364d956d66154bd83db57f34276aebe2d112aa22d41a151a2b76ba9359430c32f545b0d8d3540abc00ec00ee850e122a9d8884995e17ee8d431d06a155e35825928994bd93dbae44be0c1aff701e3a35c749e369fe4229d831b1d97abba5adadc48b376fb24ffde7bbdc8604172790f643f4c6c120ac825dc82f2e186c1e283dc61905c50238a9a5241105d9a9111687d12d53936aafb12879e6782787be72ade79d3a7742e7bb2951c7f6ae7fa2371864b6883618cac34b1d7bbb05e7b257ed23407c64cc18e0e3bd0a035bbe3645773b11a33695a12e6d96aa2ce9b4a3d01b0c885d1365703e911a8b2c069119c5a53cbf9912791891abebfb2af6ecbd9fed4f5cdcebd136db69cb5041bed2a9dfde2bbe0609c17f5d8e97917f033c96af4c1afa19f3b481a3866a43da3016f09d8d14d9fb4ad1be5c58ef96ba584e0262ae73f9836a55ca60b1d41f7ffaee22fc00d14192c4f65f8d518c6829fad921d518564099fbb8b9c16f12b2c86a0c3cda051525b9bb873d41e6b80abbd0a238ca6e055f9a268afbacff1deb43f67e8bdcca9d738be3674a6d07a044738ef2f7520fcf333fc14558cce877727b80da9eea1e17cf5fc4ec6", "-8aa5a1cf8c9fd9cc5003841df3aefbe58fc34ba731d12d020143b022926ef5306a45d1463de35f633206ccd541d590aea32ab4be170d224c4f648371bcc2c976463671303672da1056a8963daeeab8bc98470c4d4fd231e7bb0103bfa774467cbdaa0fde3d1018826c02bd2cccede9380dad936daab75d18db8927dcbc1f73e160c34f5d8f1c2ebfcfa80a5d1ad20c5969df636253156b6d4a305f62883998924cb8625d254d9ef0e8f9961657897160788e2559ffca480da7373975cebc97e98c79ba03f4631a3682e4dbb25814dd1ecf066d8ffc10854a8a8aa5f703e5da693dd05f1ece8a1bc834f629aaa29c19d8290e80257826c512169c9a48292316a939f0c1fa11607c0e08b81631eea5b10bfdc2a91a083317d4831e1bf6cd56d484268d6df68b7801bd4a789358183393f5aa7e2a3c5ca28dd040419cea236c65491fb670e8976158f7fa6204edb1b7529be490b057f4d538e89b082d56bb5406ebd0587e83a4a2262ea414b247f8023108602fcae3bbe1baa5108a4e45ab92c160a8813069c99a9355516a626e2556798d502b3092019e912397c9f785b450ea8054b634cb495adb58eacd6f45624b29ecba0dafff419226e3b351d8940b2a836446a0ec4563b37b039c523c6ee4c1da2d9cc0376953fdcd1ddb5d564a752be18f0555f9be824364332b55e39510abca73f3db74e4e22524e4ad58b81d15ad58df3584ecfc33a6ca5418579d79ce55adff4e05aeeaf4bd3f0de9af306e9f2dd2c81e5c650f42cea802e460f8df339f70e1ba348cea0811cdeaa4bb1a1afd89ad3cc2e78c5b59ffe0a3feb759fadcd265cb0a9cdaa187f701bda24aad09ca3a170c8a395916247d7c084bf20b4bdb7d70b199da3e2b905e44d77086b168f9f20e304eee351242dd749afe452a4eed46b038ff88e95eeafd57a425328a8a2966d4f4c1506d354cb0ccbc06792cf2dc741bce43fffbacd8cba66d43bbadf17e586fab974b457547de3128c75d31180f59fbf46438be1a3166eb66cc1c4e25f13b3ad1d2630f6ee2d2ad6768b6dbfbcddfd7147f6289845b460ecec7ac6f480d06bf01454b97f99458df2db1c8b46debbc6a6632c36b8ece0cbc0823df484c2cc5011272c443a127bc6a0ead728db15000361b4234f7dec72215ac8a0ddea67c56864b20950503bf65cc8efcda0d066d373158c5ab427b036034f3f663d0469655e9ccd3927b0a9f90f0eb35202f343cf72451fc6f8e032eecf26f9b7285778d8a744f648c3a7e61c77c1950e91abe837f074936d54d591280da2aa2ac8ec816cd1d996201b015717c490e49bb8954dec8256a296c53625fe19fc6e5ab1d7a39d5dd148ac053adb0a2b2bbf09901e021a3f53c734c20aaca85aa1043a6b70205802385574c2e2f44016207a48368980a1d38ae75d59f9e2c4783566b0914796af22d4c", .Okay}, + {.Mul, "-9175e298d26aa95da624db39e1ac5c820c0465095b5ca14c3c0710e30cf346d54c598d4e66ee20721f460cb23de9c66cb708eff33286df75e94e8bf3fdfb4934c73cb058a03c01fdba042b0e032f4db395bd0534ddf111bb4c0d16de756749e35d6ee20b03f7a0907bff3f9a4f832a70277ac19f5340dcf49a760d10497bda616cba8188a894155ac83a5e0aa9c0a9f5451b8dee15089b6c32472f2417fe3a9cea7284e1f92f82718022bc407b85fc98d51022600b3047ed84fac780058a36d669931fe120eb2b07e603f14336a2d09a7dfc840a572e898f62be7d12d01e86b885f77c086b6a394c095db6e88a34572b3cdc6f576b7c951868d7c6365a29e5b8cb52c74c2f34fba3befd818c55ba46ac776142dd3c3393010f81bf00acd52955b3efb90ace975308bb8f56021747e0a6f6059e7d12bf91b43c09aeb69d5961fb1cfa8cc8d6b10bb90aeea7d24e92e51f93d17d1f9360e7b32559db5ba4a35f420a60489790ebc253c1349419694251425915e39b7cc99f9832ce3643acef0372ee111d6fb7657372b9983692595d087fc976d9069b05980cd2fad742da89fbcf045acdcd86f033709914559c7021543dbc05e0859fa638ae04aaa57aa63aa7c29cdf8c4768a565cee397010b2e8582e877ace7f5fb5429c690ac918604c14e38c5d60793b3a54b35c3cb8cb94d1f081770f987f0483885df6ba3fbc0f5cb0d7f", "582c5235307d5926bd876e87632d45182d1bac3e9ca814e4925ad9e287b2d36ae54dd0008151f9014031d76f8d1e806592fbce4b26bdf4eba9e0e916546fd56e7e7d48af33f5a3e3e9a29744b837c0df2bb799bb13452237bd890801458334d801afc9d6b48b480148f26785c11a659789c369fbb0548ab6113daf9c7d954976911be2e7161fa27c0bd7db62d3e033602fa13d2e3f96fb173b89340d2263f741527de4d2c6a9256ca317ce449cff8101e071fcde9bbf259754f252bc08c896f732d598501640637fc0631c88b0cf089b22faa046449f8a4bdb46d5448f7558671a946a2f6273ceae3b11ff36c32716a60a488221fb719b8ff06e32426568755970dcb81822e9694c9fa526e7801e286dd89724b6b24f46ca2f42337c394283158e54a0567619a2c1cca7b4c455d6c018f34a319013fbb05bc1f82906fe6bf75cd6753abaffe864f795d27f6f6c35c30682407f568786d64dd24cae356fb463efbe5beedaa19a46a385f37d5f0c2164135826de5c761b6390ebb66c080962cc4546fb091224a49844771c3ffff072593a35bd013c3ff3fa071af447b863ff12c197f122749c3ad180a2bb8cd84cb4bbb75ebf6193d991ca6013f750319423836ccfd763181cae84f6cd1b6a0cfad1dd5528f07b2da429b7fcb3ea00a7a7c4a631b34a64f5b03c1abfaa8d9147a08b81222d798a0f8309e4caf76bac5b105a9b53", "-3219b4dd7623054b5294c73c40c9e05b981f0d4c3fd43f5d12372397bf4574b78924e3af15ffa8e47a42f592ff8c309b9ca15dceeac3bb28677900cd310c6ae5d37cf5a244bf72933f85fa1753f0a7c74e432694b69a7c56207218712e925e7f333efec5f65a0a616e423f92f6edf615a6d4d9dbd63f7334463d264e56480847fdc3ef50ad29cab4fe9ae629422be946a183d09ee4ffd5d4e94c1d1b6d04fc6379315141d74e1d09c1f8c0f8667acba6033e8f156f96196ce208ea42ede7d61212c2a2778dfdcc27c8b36e13836022e565de3b4838010f878e9281d712f77d0aa70b990999b13b647f331fde25604e804afa9294f095c714b4b5fe980d6d4178aab867936382aa82793bb38eca4cf307cc545c9d6257b21d628adb4ad995efce12ee9c29c6507ad14e7aff517c8fa82cdd5f8ad11a82284918429fd37e0d7a39e7d3633cb257dc38b7ed56b4dffaf3dcd2177403586a410d43508f823180819b86849b011dfdc5f7d265341e04712bc5c621a3ecfda1c469eca308604be35f24321b1eda8e76509827610e8ac9079ccda3d2a6bc0fc1eb7a72feb3270fa552f0cf24180b52dd63d1a13754ff7b02f96433ac119f1041ab134e83449871e1d2cfb1bed2e79cac1d2c63df7a1a20b03ff46c07325e05fdf55b24e958de8f89c90332091c04bc2c4d2dda4f62abe793d03c2b9f636d593147d15bb0d1649a98607ce8444d29801259cc7348e4029597c920e1bc6001edcd43054ca062ff00ca8736338d30863228db5582f4ec4c3532455dbbfdf36b59f002c1038c771d111af35d300b435d5f52411f07f94d127097f0ceee9936de8c099a5125ae445d9611723a8069b42703d488ef1fa0d65661da2ceba0923295976505781545b1fde675b164ca1426c680de6e35773d097bf86f8433dfe192938aa655c62f178e8d27c1cc3ecb6f610d98d0167b01138b34db6f7f6f9d6d9f4637b36e2770bff40fe9764440d3ad72f82097faf5ccf36afa8a4f0269436855a832e2fb47465365f50dc17486fd0f7ab080ae1c77a8b50c25fc9ae20539b38c8ff79333c23b5995d02162e63c6b73fcbceee1bea2a85044aad1ac4e9931556df61c0beda87782424fb71209f44c42fde1b635bc67c746b71bc5ef470656f6392265f569c9fddc4f22e40e3dad0f8f1b891468a092fde59b85ed2f79e922f93ed2a1b74fc60cf61b7cfcb2928f7402e7c54c7cf513c606aa1cfbb901f765f9dd4c864f253449a8e8650f55ea2a12acbd8df03e0d2dfc11b1b9f9e1971601c05cbea864bed8760e247616ec741cb2a1eecb4855b7ce2abe6b326ad7a04cef538d70f870aa4177b3c72fb9304df18079c6ffb65f8b8c7fa19e07c8b3a07b93a669e4386ecc2fcb7bafbb20f59696599130aae649471794bde69036a15ab8d3d8b0b4c29a4fd4ba1faec150a7452d", .Okay}, + {.Mul, "-f730598a2b43e006665d84438000a8587de12033b05e78b95ffdda414b9d2c5bb133540aaa5e3a0e99ea3e52195d837b19a4255dcceb88f87dfb9b6830591d9d17c34bf1d8d53279ca5eb39209ba4093931e41c723c59243839c0f211d08b8d7391dc1bd0955ad1fc2e0664a8596e8da6a1a299494b40c5a9d05a6a777d6e026c2bc38e77f230a6c2d3d3bc45e6d8c093ab0f8fb2ecf7d62a84e28d7ba025ae3151d6a5c7d8002bf042c26c47bd256a241b1cfcfbc989fdcdad4f868d4187e09c2bc830acef29311239892547803150dcaf2b595186bc8a6592aa2680f9d5d6c8cb5510c3bab5bd1882264c4029c2dbb83627ae12ba0e64adda3230563d22cc8db14ef1a65812d8be44689529b817af6df0168a406416da59b2cefd904baf8f47fcadf95cc00d798dd8681a544fdaadff97ab7f1591ff011630c7ffc96b2304bd91ba736eba0652b6c013798c4287a98b1a659c43301af056a7f8aa02058f062e0c335db3e948736dc2cffa6afcdb14f9084924b3ebcb8c612abde11e409d172fa24db4f8ccc580f4cb197b8b08cb0fd95eed2f8b76f9f619f50b2ea553cd98fbef94f445d1d127e9d6bf34b2cb5ea53bd51a6fefb56715178a8f22ba28719bbe178d1303f82c1bbe3424fb4805b624c5de7e1add4112bc676fb1b40c9b4a1fd1d46ada707702fa24ccc554501172636d1c4b3d007f63da72ebe42567395c967", "71848c9f8718a2acfbcbf234c9999c33068e7f30541922ad2002ac512fe15496f5784c721b4eeae1e26aa045f4d46814f670f2906e6287459dd7dfc2fbd34ba0c37b3dcd173207c23b692e49715fc4ba890118987cc12cd53bcf92d1b58004928e8dbc42a59a39a611f4d788808c8162abf3b06a18835997591fea17e8e3ed7d1f01d0bb72f20afebe45b3a7cb0225acf2e4f31c53ac1cd6fa2a9e8c3f789c2f62166de35c8e8b016c36a42462a31c8014f5564235da339ece724cc1e81667423aa9ffc3da3be24e907b56f9654779fd3a47abc787b68a6aca5673b2e57a1de29715bd3f8bf61af616594dc258dfab8eae91adadec950f38cde5ae60c4190742eddb015628fd18472edc64dfc5229a1425fc2a5c1e84a663ffc2c8160fc2d718ba0ce3ffc8585cf9bd11408c699dcbc879facef6f8276184a0fedccf23138614572e544d083ca1feec79ee86c899669516c1ad9925c9c4f1b41158ef5422eef541e81e5f16d1948330ec94c490b5083da223edb21b1776ea954238ff2d6ea573a0f112dee987dfab1605e66759c947bdf26eadc7211a70fe0816f8a4f11fa7f6b971805b5c41ff8238bd5fe329204d5605af0900be8089658dc26de3386d6033d46ed35a85cbca2bbf928a85ce35bf334647f352400d93dce8ff8a03bffef452845077e8b2c079c3dbd1fefe892b753e1ffb2f665a255c493745b7970083894c", "-6d9c543ca2c8ba3036337a4542c7c6a047197c454b388c4bc40da1f75d0feb3cfa49f0bc74ab6a85f49ef2b521852717f22e93927155b8442911843bf55b672b1c77f272a66d987439d212db624783de642b0b6e53f53cc88278617347cf2fc51f8a0762803cb22117dd3e4724c8325d63f8c8b335294f4efef8dfc1b01f55e3fb5c94307b0e1feb389ebe4e780c5203d5ef9e3097336289c03ea526f01b4259d38a3da9fecafc838dc8110ef709f699dba6c48457b394884777e3399cb2dfd254adb65fa070a323f811a0ecfd08c870c56de2dc45241ec543aea02ad88ea5ac7d1af2a2afa24054d224388ae858e23600cc8687e5418e100ae46f4b73fac9029a86e224e2e759f6d88947fcff529b0930599ac6ef92c6e27abda33b71f35bdd47ad6da1e75bc59464f2dfc147d8bcb96d926168bbe1eb9b0ba3e82ca6a7c289a5c371d4047d0d07ae9b04aab5125cb9feb7dc367d9c3e86515df75a768f859ba3c37461e04dabb38574ca4bf45cfac1618efbd6a7d52a704dea93974e2896ebf07466c23f5ed7c6a4792591831736d72252e61797e500c940cc35dde2a9364d96da611b892cdb66c2135c9133e2acd328e0486331aa5b8808d4de5f292dc14f7b1976ffe07092ebd88563e41e602759c4962c23d0a8024959135d0e2ce2b04dcaf6de437352cd8a7ce452beada40ae126d247e2579fc5c119ec411a52e692b1da2cc7607f743873aa049c1155c0d72fe19a87abac3757627db92031cc189c22d053c1cb09b79f42b0512e24d0f84e7617726c4116f7b4b8710f1f0bc9b714da240015c0713b66aefee38f395d21169be8b053d199d25543303f72890d62c0d35e04c34f5729c70ba4ee86467e9ba339e06427cae795c9a8ed12aa19736ea721384da721832287768689e67f4e63d6dced41dca320e7103e028a9f085cbc4157b0a99c7b0118ea5e0123777a628bfc79de11e6356d810c6ad19f98def792e28e74e31bc9c7d7dc867b0479441a6f672be47854560ded30f6987ea8f64ed40d856600208fd48e0bdb3c812290c92fedcc8908826dc97a8366b92d9773eea81e4973de752bc76de19ff2bf9375fb6e67ef61ba02fb34da9e354a8cac7b44d13e103919d79f89166e8cd1a2b5af919b5c3bcdcde4f037b8e4056890f70c4916d037678999dab1bb1b7f0c636a5fe3ff071160d3e0ffbcce7d8f14f81d1b43112b2929c298c38227ba686b1fc0dc5d05ff9fb8297ef22bed989ba576837edd9491c20562a05816434c9085d94882eb242f57744a30a9882093bde3633144bae18afe767cc0f70baeae51a8e20263545ea7d9ea3bb078a597235d30ef6ad7989b088d93d05f39b9d8ca27d40a3599ec21f2e82746da9d84297a79c2b2c1fe8c11452cff88fdc078fbeb7d475062f7af0ec55afd5da444d46766a34e4e87ec88f4e994", .Okay}, + {.Mul, "-cd0d88d3e283e53a78dee9a9bf4bf4634cbec0ca58ff55f0017108ffcec1999036fcc9deeb7946e38dfa61bdf327d1ba1fb444b6f5a91bb93ab6171a2f48fe303d7d25c7c66f96b5ed5d2670ff5ce4b4cf42dca4cd7df97fd9ab920ae8f74d586510ceb2aee5db005871b89cf5732872c59d873c3ea9799e537f250ec51ead8b3234a081436713f72d36e0795a2e19b5fc6379303f45f7e8c99a1a581530771d2fd1155c1a85d42b94f58ec0885def21ddeb05e5c8648383f3b65b5ae6d852c5d59cf350fae8f7e381395d11599a5a2b02d3d0baab59a1fed584f96ff0c890fc3d63295bc4b893be85b95728dc1f6ed84bf0df3f90df526675329b18c95c14efd8bc543515230a4dd10352a02ead5206671296fa2aa49c53093445a5dd67c9b0edef65e6c43f4a58da167f2629a883302e5a8b429540a752b486a7562a1d5ffb3457d7a42eb9be06136637e0ad2f940bed65218637e68887c9edbfe1f415f35ed25bef66777e67f2aec005bd152849a88e2c7ad7349674b0b989e1491cefc35e8b23ac153615b871180a49ddecc0d8374a896df104e317810a89a7fdb883620dc3a9cf8de4f4155a04a17be5223ab282557cb66f10fac22401dc37903c20367686709fc50aa559a0a38f0cc631d4f5388af2e3b1ac623e890caf8e3110d943cf4b4630c05635a638526eb8b47c78fa0a4922d42c5cecfd475df01904041d301e", "177eef3479c06d03dd5ee549d63319d33104b3dd92752285123bea92c6ebc82c73844793ebc7baf5aa1d178f6d98ccde135e3b7deb75beabb29f9aa236d9bfbbcb1c293dde473d2f15d1d4cc757750252d077614dcbdd28b143a9605cbac572005a07d26c799bc8960dc1d7226d58961b98409d3b0b72f4680abf7e29c7a63ecd9dd258421e565f9b9a4d48daadf526c5b159ae92ea8da34d81c7f8d05910c94a9aa20640c73cbc1fe4451d7d817c75517b666de1b01557de4b102dddc0755f187bbc929248aa6fdaf9b9973b44fdf6cac88f61ad5ef97ea594837156a84c6e1368448fd1f3b3cffba77691012cc89380447450e5454dfb189431d9082bed8cf129d4fb608821e51a3e610f92bd30d328aa7893a6e9a8a8d66388054b71d8c2ab12981458e8b7e6ce795e5553b6847c5a770a148dc522b892b040ba74ab06ace97ddc6fa09d60154105d5240738f569c347c9bdad0f8d27b5750921be55872c15b8a95c530780d8fd708ab4a70d1270b07382abe9eda4ffbbbe5d2f5f19909b9a37267db913d611b42873e070ea01a03488369e1c410cc30a4bb944620b9bf8fab0b5e2357db47d4cd44b432e672a2b0bd6e47dc318af6628903ff613f8b96a5151a3dfd6d45d8be9a27d46da49485e8b7e3d3414794de10afea78d4a9981cf6a093dc174804153de233ca80b4062bd2374173c76c1c4f22f1aa5abf11f7ed37", "-12d1e38e0ca6792ada25695fb2775950df02576f8431a1d7c4c99f63b217261c7b8ce54bb1959ca2cef313174fd1e215a0c25362a903405d876394ed7267993119a3542945e4cdf86946f5993a14a847511300ba22fbde7e413a26832e530d224b96de06f30450982d1e370710a337aa248473541f70e30da248f141abbf18e6c0abbb97e655b52360fb2c2fbf55409b5db39e117dcb14b3ff33c8091aba8d54f7a5aa6a0133bb9e3a2fd16be990d7c716853219c2986b9ca6e703770dd0f63df62d83d764f87c4d4daa2329cf913ad44ada6858a7fdf8ce5eb25a1824bd52ba3795f02de72c51bbc050b8c94739cf7d3557cdb407f0d66ca3eace6ac393b315ab6bbd5663e6bb1eedc2a83e676db245caea61440bf203863f8d71e8befa8db560f8143dbfaf8dce0c9671b96e44dc89bdae9b629263f934f60e32798b036e54183a95b4f330f069a0b3af5d2ec5dd276611c17b7d0da94236c0ee66d2d308519a15edc7ee82f6fc96ed6d5deadbda0e89864bade7f9a26051418038fb22fcf8561b66b83014920c8d469e42489f288f7da89e17d9e4c5303a2bf9bbc6b98e55847cb1c7d80f32d91f1fd67f8c77bcb0ceb2acf51d7c095d654e831b8bbb51919fd7e38a938d75fcd1880ef9ff4a6090c5c9e1281266fc227c3f2945142547658b6a2e0a89433ea9d3381b3c1ae17ae5c72e5599f1ee2edc0f35d8a059f97dff2cd63524acd1da2f7342c2925b209a017ce9d55926d64add3c344b975f0964b74ef0a9b463d4f33697be150448a9644852a05652a3167f9d39b863de5bc7557d312d43b0ec05267d9c11d62fdab8b22135fb8f5f7f6490ddd49e47257220a8d49a5c4b2d6d12edc1d4a235e36d50c79c22bbd3b35cfc5a7ca5a5f0a7f18a09466f7ecee2ad65a6c0561f6b954afaae118517a89b82f90841025d4fbb0c61f4fc7a7713fcf0258561d39f323369e93d659885b8de08570961cf02cbf7f3adb508908a475544c311e8f57e5c70bbfb537bcb01b7bbf19840479c133bddb8011ac667a794a680fb4d91fd3c2a897c393b6174343d388d058d53a938243b0d0bcbb7701cc3527ea7b3a54d19bddcdbd1f46b344ebffb0d81443c70f42895c30d12ceac3138955c00801559e58e6ef4a46ce7b0f6d4826425c3cb0faa5366010f2c5be69ae75710d306aa9f879cb775ff2db24b3e680d09cd1819f287677979ea76f7890b1e0f0c5c93b1033050d8e65402ad7b9193554012694dbfea4293816b9e77312ede5c9fe2b1e6c72ffb129216ec5f6a64094959fe7a33066ae2c4d52064074a0ce9f4127a24e9bcd916ea2361afe0b1c42123d9bc3d505f41e969e0fcfa957b7222a5e46edac8088ed4907d2f0788bf21f8c7e18498922a5010607346d5cc2c6398106ae2f4f6362d5d73055a21cd9d45b9e9d6f7ffb96381726952c31c72", .Okay}, + {.Mul, "a376ba7d677dfdec794de21fdfd868f164a3057f4ff02f319b8baa8e73c215804ec27935c47a9ebdf7b4fbe22a749290461cd31ac36ca99dc7dda89f61ce444bf46118769c6cc4ad9c7284d233baed6e4178aa343ed5283fbc9b7ba3a6e837b33a82fe06d5fdd1c6406f80ccfd70b86c1988d396ae5c34ea454130af6d7ddfd22cdb5efc82a7430ada0b8ff0d5437f3023e5561f21674f1b11a48e21aadd556506ce1b7c4e0a0b37a3e8fb04de097643f1a30f68b679805e3ac084a2e25ad5693b63cfdb44a41f699c4ef2d45a2fa850a36d54f0aeba460be2cc45f6206bc28a501369374596a3e0fee1bf48d102c4a8515ead41eeea18ffdddbbc49129575c2bec87ef9641fcb0f63594d66de5ee4d2429e73af8322dc2d03b8d56c7fb034850a3ec6c76da7103fb06fc83967f0726f45eeac0de4727369f362e205c8d717fde0d7b2473b68e5285ddfb8357fcaa904f6b731b73f33a77c2856a4633863ceca5331de35b135aff4a9228df3d84e2a9be7aaf7c6a0daa3cca7d0c371a050231066dfd410dd0ad00a1594236c6b81709a4a58e08a2cda940f8a84cdd82a6c1f0767fc1fa322706ede8cb15ea8c327c097802ebade54cd243d57d447c878a2dbc6890cccd13c68554c891032ccf7388f7314ae26582a615cee37b55e7cb4973bcefaf90ba860cd3601ebdf326ae56027dce0fc2766e450d2ab3810e35ca77b91f9", "97e912b1f3391360f698dac1bcc60fb07319b01f2adc93dfb1d323ed3e23287609fbcef3348bb414609687aa3ca8b2aaed25dbd814cc58fe68900a0da6fe21dbd209ead7bd32c4c3dbb90df318ce0410b7f40187b269ddbf3c3d0af4ab898f421dcc6845966621c8b0f4a02c35ed04274122b4e0ebbe04083f74b5c7d611c0f2a3b302935154fa488b7b95e50318407081d4408f779ea9247d22394f0054640e1f7964f247adf13cb1bbe56202af7acad0a20ddbe1e03f37669f974c04980dadbe6e932e04fba676c52d88a875b7fd20423d851b0c959afd5d187aef5afb56e3e3779b865e0fc94f3656bab131857a3fd5cd554e7526345a865fba0225e41ff2f70199ee6859c8046bd1d6a445be30779472ae6de8ee58b8091ad4013105c2bad61acd8119bdf3439b866663e8cce87a8a4183ae29135f488cbf655a23b9b6f61b79cadee78a2c8241eea7e4024b9a71d4686179593e0f729f7ead9f590d231e3157e0a9a3d7b01a97ad579f87861827498f7fe2710c0bd530a8330e25a36c1e3fc6caa34c91ec35a731e7420fc04805e59072e25ed77cc46dd15c8c9951a6794d5cb475583134d1d7fe3dc05a033cc1aa35caaa8325682c44449dbd81497838f5d9d7abd43f6deca93b2b7235d8d3040d8e2e06592d4c6f4a47461ce5bb6e02579ba88f4c5b27889ca431d51944056ac90d2af38dd8efa4ec605c37a574c6a3", "60ffdaffadb069424aba1b772a723d9807de3f19f8d15b51e3a6f8b39c87d1afeedaf2d9be616082e440a172ecd95432272deb9a3916bf25b46bc9769487baeddcf27a9e186b91e9f5983067c46efece69f83b13249a584629bb71fe52803659b3ef07b8a83b7016143cf2f0c94db929368f74b2792e044ef1b70a9b2ef15900854ab73f1cc468a3e07ec89dd01862a7d3116dc99588787d61e78c4d663c3ca3299c96c64ca019f8065b588ae2373a0d00ecfba3ee24d8317c053cbc5393580d50465b831c4042fd0c22c4991408f4cb6cdf70f6fcb48c66491829a22b5e08b324ba0ab5198b9917d6777e4edf84c591fe7e90da26257224916ed577f7dab0bc51759d7c8c03a66fc8395c9e5749a49600e180a85f0befbb9fa1114bc01c0e97404b951c621a6c63138952f1934f993b780361afe3c5bbe67b0f8b03a732b8a6b049b590cea23139f93ca4ccbd79835f558e1d4b9eec5ca022ea7d692c95e1993cc30faa170f176f6050da86a0900bedcbe8bff58824a5510b86818b0add41951c6702e931ce384ed79190e6b0832d055f9f100c6c27d82e1d26a2040bb8796864309f32de464a3d5cf3afdfaace862e33c1391e5799ab6a9316c3607adbaa3a8a0df1aa10ddbae13728edc7f7b29b253103a8e0b1f3700a3c991c89543514792c45edd34bd8e764c522d7d348d56bde44f0c96df1876d94a2096bc59ca694faaf0efbc146f30e22ead6dbb472c91fe7ebebab8412be77a65cfaac50142a7a20ab66720b95d9f213d540c78826bf6eef5ab48c0f3862a5a36f2a3694c019ce046c0ea5861791db175384d766e6a9edb5c77dfbc8abafaf6019562f548a1da8bb5ddb3a463f1b316e7c9b1d8e41077655402d99c59411333d2c7b023c22c62893f2805217724001199b6a6dbc35b42eb549e8036752c4784d2ad4f542fdd61c1b4e818b2a4b8bba0655afd83c196b8ffc15bb8801ff59ffab856c5b66f0842c8dcf766896351d7c4742e635ec237e9d26a0f533dd10a3caabe91972d61473f427ba4c8a2a006783d1731fc0c75458d9ff548a7b249f6c976f14a38fd852c1c8dca0c57b376bfadfa0d75c379ac273aeebb97994a5be5a6ddcfd06c59f919b9ab794ededc626128f4733a4e55cc8e26dd03b30a51bdda221e46edd100fc1a52b35ef9e3266ace841696294b731abba2590a511a90250cfb343431bb146c511c0a4da5a1989234f82651e0b3646e797bbcf740ac5ca9be76879f8fb81d3363cd88e2afa9865a224b30c588c5ed00449229cd8e8336a6b691404a1344eed1963d6a129cb54d45d10d68af8709b4e80ae1808ea2f536b99f38c95d27cc2d3c518ef43d5f96d0e2161cd982bd13408e35bfd9449d2fa78a5c6950544df8b80c2a544f64f468e028643695ac529b434570b84e61c2a8b1b7522b3182deacf1ad868878b", .Okay}, + {.Mul, "525737b4ebc7fc678d206480773072e344de98f11191d780d83fa986b11ef397f16f607a4d178134cfc7b0247dc3ba1d46e70ea0bce77d115ff966ba247fd0f2662fe3bc042f71dc87f134864d84bea038967a32ac4e74c54df6c3a112ff75584a61bda2348aadf6a890085a2c799589435550bd8359832acb625adad6bd503e55fcfcba8e8d4ad174b871c8dbbbd5ed3e233266c72c5f9284301088378abad922916dbfb0079c40bdfd7102fc0f2d2f9a65a9a3fda8fb5f57affd5b71612add5b59432d3fdd40bd797fa1c654df759de466fcc0eb41525ee71569e2b7840837b373bbd5fb04667a4ebb2c53260659e9306d7964924f02e95b42db8af3a69b40309f60269799e632a124236ad5254a2675961099d12dd826ba80319d64a5971209d7bbd5c2d9fde0d2e245f3370cf279419bc10b8960cae285f2a0697e616936649f3bd7a29774736cfebcdc2e499f41e5c280ec15238baa7ce3a9fe76371c46b05dc5b92a5caa9d7fb6883af3df43017e72d2c273fbf4906c4dd94ace2beb73f20e60ca8dec926f38de9dc5873ad832793aba033fcabc07799781aa394cfb6966055f61265f952b49f6bf37c02e44c2b32ed627c4ef7600a6ad20a503b12571dca20af409d1c4bea6959b2661aa4d0007ee20923b6a27ba22381fdda3fbf8afe58523a749e255a8485c3b6c5eced4f9e942cde3fd7e40387633256da3d05b77", "cc063cb7073fb7fa4c3aba4c1a41c632bae3f6ddea5069713ef0c8498c55c9db1ddef1bc2dba30426b83e25a84dc970d3015a15fc9b49aad32a63f3de82246fd8dbf440f1e93c20c26e7c73369252b73e2625f7e7d418139ed4d3569a2e67a2b7ae89a3503acb5011452abe1b06018a5040651064d6c4af3499174a2b333c8a14f3f902796032b219531c425fb5dcad9c55a1d296e30560380568d0ee31917359edb12565b8a6ac6bd787cfde949706ccf6f2db1c4dd45688dc92f92495d180a88bba26108b78e9bab36580525a41d88d67e392f09af06647275ddda2fc75bdc0c9da3eafd2d468bb9d156ebf7fe0d4c8695e2b4beea7b03227edb650d9db2dec95bda88afe96825ab8340ed700339f81c4703ba075dce200ce4c77d17a0c52de473ad578fdad641e9488df88e258921ab47438be4769a885db6831ba69aff7001cadad89b256b270cbaf6b784f704fd1743850d678d8c167dc16f5d6c1fc69c4ec95c2323cabd9b8b25db8e86966d2aaa01b5afbbdf265c966550c401eba746b1aa8615f984f47c05354df6fd99e91189caa0236bbaaf9d01573b349d9ba79b523991da65206a86f0d68abf64475c1ced5749e47f0f153475c3f3bebbfd89c28340aacc802243d3ff0147bbcb9f65ac06ea00422d469f07a48978d9517f30a77fb04554b6776e8a1b3a1334809ffce65662aa28c49d0d1a76546a48a3c63c79", "419f81f6c9dcfe935c7cd3828a9245ff185977324fd420ec16640eee0f26eb9d5f636ffa37b4c3480a0822d5e104789019b071b0cd80bd3f2d793142e0acc3d6f536a97458de16bc563c5ce687503bf7d825778cf38bd825569d8244a720dbc46c78c8f6adcd648802bfc36a0685fa2663f0aab53e946994bfa9a616a8c8f66b00a13a597aaa6c57129d8e0e78e988c15f630288ccd5925974d2dfbc9b0db24bfa98ba6027103af0d7ab847f2dabcdc63dec7d0315bf2b0687edd323408bd94bc949786acbd75d1ebb4967527d55de8802fef4e5bad5f509c30095f5223a5fa612416f20d173cf3260f3c2607ba4ffaaca3da9760b2596c1af26fe7bfd449e0337d1d65e021de22288dd4f0ff3b3a1f9f54e73778d1356f9d33f2e42b30c8398dde75dce90a220647cdf2a347749366680c3c16d9f96048eaa92c8adcdaee07c6113433caea7cf8a2ef6d879d24c3fc288fb7221f2b4eac2ccdd9c19c0240d69ad075a4affb7b101a5789b0f8240f25bdeab64603c708a24ef967b0250ba81e9bdf363cfbd74224e4a6d907dfad5556b585acdfde61bdaf9aecaa76e43513457db5bb80d92a51d6be2df305e8a3835915fb73047b656032a6272f61d014fda510bbafb687d21ea6eef981cc39889c38effa3b625a1a1bdcb9493bf397e88fcf4f92f802e34856096aae4e33916f7ee1cfeba144fdc36effdee6dfdfb53d907e32da2d13a76d0880c31953883708ec54c444d05d4e8f0d752bb6e36dd1a15f1ca84af2e2e874104d0403a50db2f5a4fdbe72cb3927fea48711dfe852087aec9dded18d3fc8b4e6acc14a7e323f095e747ff2925b41ba52145ac8d90f3f66fd0d638ed47998cdac9039cf8db9b0ebdea5f65d7ff2c3584de493f33a85f41dbb7ba3ad72cf3c6db5006a9b23225c1a0450ca64c93dc0d66feee8ca6ac25c14b05cd5456a8d05f1e53a7471b353be967822168e07194f6ae659d0b2c175eef046759f1592087d0bd4a7a72836d25a4770c1c4a0fb1f73c3dd2750faf7cdc58551d5b19e04a36fa4485eaa9254a352c67a11e7fbaca1697d60c7000e7d1fa062217aa056070c2681ebe01ecdc810a26d54e441d7699689ee5d9b24398a0505cbdc46d37c0a912b79add3b0605e1b103f19c90bb9839b53d45430d75c9cdb60778a07b2609792d8d08f1c5483f839ecd1b6451306fad00ff16db47b772c060c187ad0ec5708e5f7dc88ac5c860da6ba56ce7dd850734ae7d75782272a8a5fadbe9a202e6b380edb8f26aa81ae40c784dc19dd9f8a82e98812ceffa6da75ac6aa5d09ee28c85df49b0c38628f738d61129a8e9207939fe9a886745bb6af1a00510191f550982dc5d34f4772d1acb5740d4ddcfa6ef7d3c7440c3d92cc6a480f0efc4b837b3f636d9b65ba20b04aace0ff6194be6f48ab6cafce9f0ed291c012c5f51f3f", .Okay}, + {.Mul, "3887f49d1cd2e4734fd90c240bd9b31757524b8f903831687eca1180f533d58680e48fc080d21e4ea0c2e3e7ed29d2a2eb6a906259accb67840af603867f36b9459b7c96a865f980dba57350e65c6b9552284325e63bb3d5d774a191b878e733c0d6c6832b7d897807cf00fb5345e08cbebf88906c8cf6ca149e5fc053b4aaa7e2872f1af7cbc5d27cf3d598dbe84ac6197be9db504f7863a7e3e3b950b32c76e71d87ef234ede6ce608f1f07083d4a69ce6c8ee5ed6576cc9335ca5910474c2a48783bc11e2f63ecb3a50b3bc9baeebf9de8033430a40d33e8f697e7fa3a76ffe53d4eed2c4d2ca4e61179ae01312605b3bf4ec3f740f66b09d3706db47d2e42fa6ed0c6e455a09a7547e388f37c247a2259fbaae7546eb0a150c15199776bf5c9102e299d4deb81dd10caf0339a8af8fce1bd293193c20e12acb4aa3774a4d4aa7e47e3a9e48dc14fb9ec023b7c77ec0fb7861c701897db2ebd718452b91983f3ab14778a31f1fee6e3bbd38513389819fd15493def41ff7bd3a4fbbc65a759558002d3cd079af2d1511abf57c0f860109cc0ad89e1631d26218c7d3ed9b4bf7f112ee7af5bf06a51a2cda6472115b563dbede9b294bdd121fca99de22865c1e6d9adf98aa698741d1b0ee62f0254ae453dbf9bcdb9e5269f375cd5a7e130b0115faab5faac8351351c815f739442741bca514dfc8f7420b261484a973cf4", "ce8435ca92f811d77e7cb9ba22239255014bedfab04bc111dbba6c985154af3104d7398b7eadad8fdf90211c2eb45ae576e2dea9c4334524047737e6a1083f3595d817735f296bb4e7d35f0c2dd330c77f08c4c2ef00bc12e130f491198d01a77da7e1c8ac964192024ed294db489e3b02ed7d0e29b3532689205a39ed44fae8030149529dbfb265efb9484d0ef9df735972a1a978b930e2260df3385df733d20df5dbcad72c03f2ce7b63f95847b26a77a2807364e6848d2dae2077adbc85902cfe7c2aee7732ef637de1300f2b6bed610dc2662e2583291a348f46780fdf9531bbae9a3146f83c70071caaee827318b28bcbf58fd766f989a7042cead17b4c9c73348d6df606746bffd79ba01472ef4738e5bf65e7c614c789ae9162ba0fe3cfef73917146b470517fa8bebf6a78b45b43f136c0d5d408610adcd3f93fbc36a5177fdbc240dfd763648649ef97f7d5c6f7ed5da70770f3dd72d165f2ad0c5876e7eac57a0cdbaa03b5306e2cddff894b01846637f030e5cdf55f208600cc1a94a1008fdb2f036894614cf28829908ce31148b37c6a1c68c45b66ca8c6fada8f899d489badf6c7898e11610e7df4b35aad833247c2a759cddec35111502bd07197cad55420534d4f3d24a896e728120c63340d9b046a60dc394268d9d75d310af12eb4f0400bbea554a379dca0eae48cbb194c3e7956a44fefea9f8d1055823", "2d9a98d16f946caa2d697ceba8cfed8eb6a48289058a53faaba7f353b06cd2206e151299f707b4969bf76c419c48a5cc79ecfb05f52757d8c04d9df7a55d63b49ed5e7c837d7b210672a484b7c59e03c108a15374aced05cfb63338245752ca58dd7520e39616b98a6e9033498225b17304074cc8ae2cf8a92ece86f3b4d175e123abb55c2095075f7ebc7d308a6483a087d5ba270c7a55a691b9d17dfb5f64b053007ad0c69c7692cc01d6be59a5349dd1373281ec304d1edf8fab985ad0a35f0e5fabbb5dc879e046c4d49adaf2a39523b7b92530767a15ac135f9802080f8b677c6daa628eec1823244bc3c07e187fd80c26e23f9425e6e26a837df7349bb39d6199d76c64a191d59d350c722c79b5af24eb8c9f0bf80c9df78991a63dd2ee2eb6edba466e8ddb63fd122d30d57b9566f0bec03757b5aa95a0aafa1bd37660ce1a8f0c3cc0b12cca0ef805775f99e1022d77ec7b5abc19bdd40189728685f1ee5095970b3de7ffba8694bdc5f15525eb7dc8bb23791f91a079d03f03aa760b75481e1809538ed5d45c033975014d79d2aa070da1bf37b6042b4b7fc3921038d3a87fc42c4c87f62a94acace461445399999d4b56d403f5027745810e14aab425a7d6ec9e87f981b1342eccac60fbf343358f49ce45c46c9645f9fcc8d26d7f33552efd82aa76607a97d9f11fdb5a39fc7545b57e05fe88364611890544d57d53907cd84fdbe329547d32c433176dadbd2225f778300ec4315617c891c1bb1c9826c82bf3ad3e5c86e8df56e6bda01c9308389b464e5094300cf9bf5ac2358135218d193afaee1bc1285604e1b6c56f382e09bc7fdfb2519293c76645499c80febc5109657b4f7c54fd7a13570c3e2a0b2684fae3710b51f5fbba6a22aa42f46c68089824e8cea8b87cbaaaf06bdf1b22067774d58d2a37b62fd909a2ed9b2f975164c0f133091e8031ef89ec6c74361dbbc97aae00dbedb97ab3426f6f1d3b3a64c6112bec550e6c36eeb49086becee9a0716e01eebd2b3b965204bd95874a2e3e7a7b6b6240f88de4257a366b771094af78e4b2c5c93c473cbdd85d3126eef98d7e82a4d172a1f591fa6c1d16b6a558e6db9324e02fb8d39b9de6c2156806944bf425605aea0acb2d368fb65a78a653b66cc92176b2c71b5bea5e7ebfe831482820ba3952e2d3c58503c04e70b646cfc9bbd07c1a44c7498baea30bad7fdaaf79aa7ccef6490b241b9dcd9f848e3b586e92ee0bbf11210d2e100d1fa6e943284f2faec5c47cde29b93810218481d1b7018832fd78ce39d0baa46f1ccfbd5ba91d142523e947a271fd2de5e53f5e5360c659bb267d5e84dacc058be03ba11e2ef493ca812ecc6aed356ffc505a8597184b9f0019b9498044c42b63fe1844435de8905fe9abe72b59bc55fd854395ddd28889dafe0da460fb349d9465355c", .Okay}, + {.Mul, "-ad7616b7a448d6d25e131e2cc99c5eb4c0ff77bab00d60b5f5f72671d46fd504381cd5db45a0385a673f3e31d31a9900c4a520f543a49bfec51da526999f285a59045445741cd9419ad72d11549fd34d2a258b5c26a780b086114b540b4a5b2b91d517d2ea99aebc5e037194ebec0ca15cfbaa8a4304ad0d41ef8b31a31f718589af1f8039cea42d3c7ff7451f4f40b8d8d3f47b8e32fc8e23e8e9c6e73ea2a97da4cb77cdb5d36dea3d17c308501b644dd25005aee228e5bb5fa8e33db5b6d20a80a5f06e9a4a63ceb44779bf906096fce4ad2aa9fa7e3fcdb3d8e7d9d1224ca67869ea768fc410a6b0ceaa11b3458b422302357c13a4e6682cf1110cb2ba7998001384956a7c2c2857a62919c615a6af51d1f74511dae82862862e2b4308809349e8fcfd16534f4639bdc58f9ac9cf852d71811f195d615c08b321cb69c5960dcc362f1269a636ae549927c2ffe92aba8a1b82303f1a6bd599cd796221a4687e1618c33dbdeaeb7cae1a8928b121616723fbc02763af73eb61b2f783a96da8ff98e9cfe5f24ec5a197231ab4d0c9d704d9c0abdd6a33ed27f440b8f112412dd0ee660ec76c9644f480efb90f319d9aada0fa3f55d6993dbe50db71a7bb5555bba67d5b51538a98bac001f317ca7edf1556a2a502ba03fc9a6a28719b2b7f9dfba5f3fa4744a38cff8fa1e866b15133783474ddcc74f886daef948fcabc50ee", "fd2bc61882a16c21e6b7279208a3bcd4374ba9790f3a64718b414de86541d5e6d3a18dd43dffdb2f15d95bf8a7d0ae1e46c7e76926c16c9bf6a77ad830d7b53bae2f86cb397cfbc15f8f3f32e92a572fd7fc6e8ec4e9b95df843b26293ea2bc2902f425be389b7e3d8cb816ca9fedf1c26c5d499eda1e7067d376bfda7ee1c22be9c17791958ab313ff0fabafbde7ad3bb69739d70c5650450663de0bcbbaf671dd925e0025d98b0ed98429d5fe819343c7bbbab61ffacd7f2b9eeaf2d5c6fce7276a19a76244b863bec0421b06eea68072012cf12d87294b9e7fdfd18c4ded7cc71d5d394eb800f8ed3efdbcd42e70e2e7d4701443480c5d190345709b53aba2e423e4ddc363113be7d5b83ee4663d136e27d04838f695b2c4ab429bac0a97581e0e6ab6d9cfc6cffffa934c50786f0b45d7f7510e523c9424230fd2a37ba67119c998273380cc9f1cbb1d86828d0dc84c73d292f41f6f34188e2ed30f99a061a8827671da08b62d5063e96fc584700a11120dbba810035b9a69492ef87d9ea1cc9de13cdf778cbd09a3df9b26dbbffeedefeca1704cea3c26aae3cc609ea5f4181357582f23b822e7e33fdd280eb6fbeaf9c510dfadf52a16277a94028d79f501718284e4da68d026a9046e20fa7ed728b207b543585ffe801b80b1a1f2035ffde106d49ce9c4e05c84c14dd3ad00603ae646264d52ea7e74737abd5eb63d7", "-ab8b5d833f5c16e40e577307f187a1d35febbcecf689bd1af9a6f210c17c1d02de36e3c9d49d160f29b8222eba212f61e657df92ed98ca76417de6dbf4cee3df1a9a4429e88d68d236af148303df265bc344f5eb5ccd6b34bfe1e7197a94d1dda500942b9c0e3dd26b4fcf89cbb76812572f57b8a56af7b6d5573072778c6b97eadb6c8c0f550664cd872307397f2b18531e408cfcefa104e4e695bdb903c7d093f641b5379f6777d1c89ec9dbc57046f9e021468c8ed3d897640c2d8c4d15907cfff544fa0cf1c427b11569419caffab289671f851a3d4aeba1d66514cf362b9d3cb8a6905ea0071207d88a820c37f85000512bc77fa90b40e70904e287a8fda183e352f56297f2634fbaac239a0acf017ffbe17a4c5e86012db9fea61e9d08171d76fc53d0d68c0d807d2edae08d81dab21dda982253a1850b6ea49b8e0240601e4462267fc5a695bb3dc2e3e8cf53823fe93daadf0706a19262f38ea8beaea34073265247cc729b7c5b602a8e732ebcbf613e3805d68b1aaa075d330abbfe063cc7aa0d03b1f9a74d94261bcd6d17933a07c6e43198c14d8d711f08098275ef99a8d673c2fa38321d54e6e604a77a18d315c982ee50a2ea77097d1e4b6f552d901e6ff851acf150a03decc7692235709760a0cb8cba5ac4a9a714bfb522e1d9a117dbfbdc0091ab0bb3fdeb561d6082eda79713a0c5063ce8bed3db09a4fb51deeab8d198606230f5724c35e62f62f75ffa720f4338922eeed5036863926e3f529afd5d6be1a7d968d286f7c7376dfa1853ac4a5708674c6c98d098b6bf9e3cdd98defaf2f45384707f57b3bac65961865ae351e7e276ab3a8b4e72ffd56ebdb408c4c3cb1cdb4155c73c4e31e2b93b445c687fe1849289ffbdf24fc960b13aa445cb812a294d700e2f4b018c486760117cb506577710a75ee5375b4abb24383d411bc0b152bf904df225ea9c99f91de3537e465198d31306a37acf353f4b709cb581bc88d7b245a44f855d3e6cdb291514dc05037024b539274d7b75c871709ee0463d7f298cd0a123807454768254d3275fe7ce36ad8d5dff00fe1a3a5842cbdad4826bce379f5d5985f7daaa9224edf2be677711ce76f084a7a4e7aaf5775da8e2442af21b39245387375e2676f7b2fe5a53854579f61454216ca2b38a0df1eb34c01a5ebf7d592dfecc7d22c42043cb3d00794565327faa709ca2fb5af8d3a961c34dc8a523b3840acc219392220c73baa6069d4a801da11ea4a85426c10c2da20aab4b62595fa9543cc2ee76076fe14d2f1aab006311dce95076a13bd32f97d9f1c5221c7a51679f69450b6fad3446cf7b1440416c31f0ead8e02b2606603dda0fab5032122c8d91be04e0332d16e76868f386681e2a6e32557ef84b87e453224148dc6f33f4bf35c35e7a52fdbcc2c15a7b07939e865b5867ee01e2", .Okay}, + {.Mul, "-d624366451ffb2366db0c0064dadea830e73f7c0e220d50e6feae890369dd9a9ab06bd9007c07730edc3043dbc739e956064116e98e5d73bdba86b66669b96afbcfe5c30dce73835b8e0baac94c184257b12c1fda621e30878d923e0a5d97b1002bd9a9692fc71cdf05820d980ca03efc7b2cd5d32c336947dcc5d692def80a1c9b4a912172b4b6c1051169df43a12d94bbceae23afab97258e1f70c7c5303bf95e3a96766ab220b531e147ec0e0a5fed68cf096469390d8b497608cb75523c31278ff1101a18a26113f2793954f54a9469e4c8c0fa143c5ad38991e6e75a80bb2778540a07673ff42ff0252ff74bdbb887e587de5d13ddbeeb356b192b97de3d49acb62619dc4aaa50700b8cfc888181c247816f78906b785ab87e3d3198ed7bfa03f8164c7f242913461c8175cf315c8a1b886725d94f13c5f884819fbe1d2b34a24ea26d8b9ea4f5b1f14d15209d1407c95e3bfebfef172275324ccffc0fe833dd8cc5ede512c18475f8ab89e4cd4ceeb2b9e95ffc75a5750c093b1b57af4d478840aac937b858c36f080632bed1dbe1a8a130b4676851460f94e1935b47a454270dd1be9527576ff816859441523288e9d73383df4735f82dcad001238954c0b9e96eeedcee51b08aa653cca9b40e9beba8b296492f961bda00aac06233f66787e439c1f04bd72e70f991dea8990f7f208bbc256e8d55b9608a53d3e145", "bd85a21f77da19e10d340b8e7001b7e564183f385ad163b6fa5a050f9c90a73a88f212cef351a67df1da9af6aa2f231e923a3634e371960d631596e933c77b91f407b8b56b5c584acfc299467cf4c90807ba0b8ef50ca8605dcaf1f3b35f0fbefe5a412ea0990a08ab8c558f6ef4eade6ce2ff852239c056f7d393e96bd3274a39e1cc2218f85a72f83f4c765285e5f07cdbcf2c72e4f6b1c97632cdf5e04ffc1084c234958c8e7e5a7a59559bfa4c532b988cb03a0d97c1810dde6921688e358c2dcb86ee8127158cc4790f0449987e85f4107f9fafaf4d248ce97179291549449ead0b4e691f382b86cf3b025d361e0c5717e078bb184f07dd8d1b2e0f1f02ed8f498b661de0596242fc845a43386c4362c4f0f7d0d6ba7bbf3f7a7fd00bc42f53d2789f2417cb809a9c3ead2cdea296fc81506eeccbe27936c957b5b5a10408993a7cdcd5241880c195ea98cd8b5afb63a8b4d4fa1acfb81fd8a5211fce7b2af1fb0bfd12a0f74bf41b694c3cc1efcd5c35518ea0a2383e65e58746e68cf98aaca89e310ea597ea9934794353b24ab113a23e26d2cf23d3df7e26d0ff4865b2b7c083037cf9e89bdfb781a98fdc695a889ce3222b6704d663779bf23174ae90e7471c43bca32c5ee5d29572d26ef83190db1682d21cc336b38eda522f4270b8ac1b482a0df88f1ce9aafd69cb6892aa0f36e01e5fe13a69ea8d98cde6b506", "-9e8884958fb7b8383fba2a257eaceaa87b2e44d1e09c6c00925dccd06593073c7a8ff91c0f3c9d586f2f67b03a0a6edcacc6899be96895e023f1d137610ed9335d96cff3ae7de1c80bc926e4976cfc3b5fc9a117de6b0ff0cbf807386b78b84ef586ca91008d4eebc346d27605443ad5a6d350e38759e9458b39f4ffd63192620863359d96ac9a4315d5a83b2cd69c2df17d9bf06d42c04318826ec0227d0abedf77f57235a8dc628f2ba15dc90cb45c96eedadbb78aa5db32fccc2fbaf09b31f57bf85ed8ad9e5fac1030cf9ed20edeb392a87f0be19cbeb4c7d092327a2d4d29e1f5cd24e4bbc01d8250e72602a8d7dc5a51504c0bb61958c73c128a506533b6db1d49322042ff9f1d209fcfe655dbfea69bec020452a7dadbecb0f7cc943aae3948486cd82de3210b8bb8041f25da5c3664fc00fe33245dba7e07d565e728f1c9db7a1195164e9e3d0e6ee33199264ad4bf40a39c5ab89881bf62a969324d3c4446a16fc2cf109edc98f630c88372d0e440e72867c78dae43fe1232f3dbda081b702b5d7704fe9c4e5912d83be129ed4a7d170942c0860026a57d1d3764aa25dc8e0e0a8c93d93f20dbb9150e997af8fb1fbfe104c9f95957cb7a7693df4c8952b18504f7ef9f0de763c2d545221590f6e0d693f013197ddeea858cf7f6340f2bca1ec0fe3f8049028f4effc326ac4dcbe5a1aeb81b7c63f2948d0db4cf979fce4f3cd201c4d90b6aa7d53bd7a4d013894576d7bf41ce2b2d58c1b4e1040d3b584d6c2d72013c29469def2c1be903f9131177586f8286a565ac6310ce580926a164639d8e36b52399285a58657109170263ffc83089f898912d1b0d442d1262dac28f3ede75801db617ba197f262e3f8aa17fb4f438ac6498a794ccb6b9dba1086c70d4880d0aba66ed6dae1c69f9c454641e239cfe76178115713995b480704b88af58a261efdb309de66adb5a06afef19e5269b51b81c9466b95470f9f3107bc436770f08a1af5edce20f43b1f5b945683e3f54b026c618cbffeaea64195ff29d939e819a38ef1ec668f49bb719b6e98e035808b5ef25b4672cdb9aa50d22f1002c5bf16bf758be22de1aef11793fee4b08b2165126c44263e099678044577a8e8bfa99b17c64e54fea70c830e50319c17f94339a01f1e1c0e65fda9b5574aa6f88229ab73a80a0dcbce2b2ab8d627c7fea0eb1cb80fc85b65cc4ede54c13807804a28b88c45e6e76b7d3c0b94b1eda912e03339f026b371821587e54853a2c063f058beb09ab3920c4b0b2f5ce67b806482b4aac2a5bf0df614f390e68df5b7021310355edf8193f3446d71ae0309adf853e04665e1cfab5596f2b46cc2f5833c6adfa3fc5dacd7d8d47bceb99b0123a06636abd31455566baa6e8abdf7bd1a383215109587b85123ba3315862e9f800d4154b3c843f4ce3b6a3b109e", .Okay}, + {.Mul, "-b8c5a6c118adaecb367f8701e84c2cd8e1c881f69ae337fe178ec5a569ed7e9cb20b0fc4fbb6496f76cd188dd9ff62866b8aa6877e3730374b6c6fb1ed56a418bff2154af90228fc20114fc634c241d6d6047ae1d2cadd5b8a7d727d4deb5e6bade8177d7f3ab8a0d8145458c7b33ea3d569cd952d925bce8e5b04b173e72d445628431e3f33fa2b64c7d11fc71ee7fd2967d8248849e3277e67a16517bd082e0d88576e735e87d6e51969ad6411f2880e8cb75278306f872de99baa22542da5e1222bb8486aeda3692c74bce95b2837870732d3f09d5e065ac95acc86b8fdd20d7ef1eb6b647663fa6a659c58fb014fff82a50bc6871d90f5f9711f50b6147c7f26819d5da146244dbc47d1ea23ae7f78688c794c78020ef071a576165aa8b18e819a02cb34a14866d6879e9438c5024352526ed2d549f5230020ee1789c01a92e04f45db221598ba50f26c5582359c0f9664abd87a3ea0a6bbd9e7578f7d9bc81beb148d6b066ae4e18d481b6da8e972ba354e00fced0da63172cc3db412d8cad01e6df8bfaf09cc9e4370a71b5c2f4008fd1949c365d4231dc27358cb7a142b47443b123f9a73d8d63651c1c75a6bd49d6cad9f431ba2c0ed2598f8714e0b2f59028cd97d2c551bd176858d7d12b46bd8e21b2e0e970a3010e3af72b91c285309dbe1ef075d2470be75176aa203e003259fb8862c5d2923036ccc9f03ddb9", "5558ff89df20b98d32b9fa5badef6e2a63837ba51f63407faef040ace9c5ec848946778a76c46212636eafd700673127c83d8ea2119b383cac005546dd57e18fef71dfe3dab35bcfc6002cb8b0c921f0f6c684c5ad110fd5a10687b0c9ee5c06c23e0403dfc083b6f0732d69da1b648749d68ae1e1968432f1fae2645b24e963de7b80ef6185cf1fcd837922ec793831d51daaa978da71588a867557ee4afefa8942e0dc984d241e61d0499fd708b50edf14adcdd8bec890e0372c2fcab7846db371539dd3222e05cc5b4152f8926b827c57cae92c27c8c97c2eae1f84fb9e4544f81ff62b8619f4f2552fdf4bd7646f6e85839c75152f0cb2024f05b08fed1a6d9908e59360c22441d285da36a4d7bc55f9a5000eea5998a35e87cf061aa93c4dbe01538deeea6b9c3847180a41accf93e0957ea94889d368247333f3788ae4a331b15448a496381a0da4ac1d51573c7a2941728aedec589b31370296b6cd12870bbff18f899f2b03d2af79f48990e8e4052306ac9269daa5a02a4a8a91d81895d89af3a31b0a7ac1d18473c1fa9de31eafea5275ab7f711e0a55fcc5bd6e74479c834a14cd7ca843c4c13fc6d1900d8fa675da0f6d5202cd7df96ba9d32416b152c952dd0fb767858986c8bec061f39ffbd351b31ed6b0590d7f160f8e35739814a76e98737edafeee5b05128f1471faa963211e2824392329d5e24c17634c", "-3d99dcbfd37e868c909fa3f69e5f4e766b244df6d2b47933c7b2dbbed79f4bc36978081b6cecfd029776cd9c9e27513201f17a7df514c62ae7fb5da9a614c7bd28aa1916a7d8589c023baa7ed9257e8789ce7f334d6f6359ebad7a398d2a6fe00388d0d5f79e2af4ee09aaa91bed3721269bf0364f5a4c9836e1240fb5fc4d9717e52157bead182febf9703d21df3bd5c7fffa812b2144355b76eba50ec3d703b0fcbb5bdfddf00bfc32824e328818c9d4772638a70e2e0fe670b40ba6de9e17f80452e7fe629e36a8f66b48b4ddfc27e843ec816c395373fca4a90963bc214a53337c32acffec4ba17c3c9290f6a4d6065659f4ce0a83b6f759adc649112e2f37a38655d01d58629b2c7d1a2b3bc7869e03fac4c22bd4a02cbf34b97f2739f00998a1673fe3583f782c703f7f09f4d386f739bf739f96d56b711318b10b07e0d532326395a3685228d0a5c5ba219b5f529153e99320d3d0b0992c1f0ead88cdf3b378547def02293dc87036bd3385f0dd2f68f262c6f07c3ed88236fd4a9cc2ae1ff634dea6c30697aa98fd10d7494595bcc95c50e3d613a16a650786432905959f004532f83ca5bb7516b6af2ce6d85f0febcba1c784c50c750c456ed9fd8040ac75318aa9adc59f1adcaabeafe7a172e350b6d11acb48fbcf5571adfc5b1b88e388727b573384852b9741fa1a18c1c4c1547202f0f0e1389e0ae6a98bfc119860a7b07d3e20ecc24eb5c6cc59967276f84db431902a55be3d3e9e31d020eee20b911cc9d866dddb334e4c61853e50dd43eabd7ff7aa1f1cdf646e883e0c5c74d672477bde996a9e8535085c184d908f3e0beac1368148680df11bd415a698728390b45603da0852e51e465d262887154a1dbfe1b4118be7a1b7eb7b31b6b53b78bbbdafbd1608d41d6c2488089cfe8a91ce2678e897d920cd7f28e29d51ee7f30c0fb471c93f8b9cd2a0e33a849753f57ecdad8896850b0e49cd9aa37dddafca25a58bee50cbe70e16b70aeed18a050493985efc0e702722d6c7b402006f74b854e3ad263f0c58d70c18dd706b4567070febfefa2a14c620abf7296415fda258e58e65ccd3e0afa59f679c502bd0f5c2081609ebfbd1ab17afb18a79870a4703e9d41a523bdd1c6b9d849c07eacf2dec596e6e31552f5080f66f9a9bec037ad67b4d160fa25d0c281d39824a971d6737972364fb3d2335f0385bd8b4851066192097e12ede4b56c7d9fb697f7f242caead10e25670b935c4c16a7ec8467cc0d85c8d3de68e12ecfcd0a7c40676e61b933c6a92420e3656ec66ad859cc2cafe3ff4672753a63a482333d5e56855931c351fdc74dfc22e8c6d8c9cdfea7431c84dcdd15d3aa3c9cf5036afd0b0699cd2fcbc9c49165dcd515783c318b10916734f3563c61de241e88023366626cf2dfce70f88a014b686ea43487bb8b835dec", .Okay}, + {.Sqr, "13e081a11e6befb312caf1ef00a8660c8519bf79b7d245dcc73718debd072af1512a52cb68cfdd2e707add4ad859b4509410a033efcc2a30ee0187492eca5dc432d1cc0bea4755e7a0d6e1f04b0c28ed813b5513f4a5fcbac8b98cd7edbe7506bad739ac55f0833fcef5b81eee8e959db2f0b4789c4ed7539113ca0adba4871bcf77219f9fd367ba3ae34c095ea17f0cf8e86c46c17bf03b18c49f0c73896e71ff02f54e620a32e620b0fe1fa51519e6da138f6bedb1bce7621fda43cce51cae263326997f75a9ecd394f620b1e4a76231605faefa3fc40c263598cae3110be8d45ba4e1f24b2d527f41f21c5473292bc5d906cec96b9fe46c6aab48be753fd605a169c3e43257c3c74300e3de5ecf1a84c04a1a4ed361ebbc05c0486285d40f11faef7f1f87ea228c628062656bb6ade8b2b5666fa916710ccd6ba76448b5832cf9a51f7c9499d3e7f65d633a11a3f17820d7e25d13298e1b717534b20887934311f000e9dd6d3f8ed3ec4326a2eeecef95e227636064bd8ab09a4c13ddcb7da0a8557b8a51702a76fd2935901e4d67ba17266323c1da8e75b19f6be7dff5fc2307b799ebe5a9ef0a5e5b3b23759c37bfe6f8912ff438ef18983373c170e15b144ca97f56f5bee247cdaf9bdb5f0bde2f22d49ba82871ff5173afc1d90b237028f43e3d2022d5010eba7c9712a38e36cf215756b86d683ff116f0bbda5faa11", "11f90c14963b3cc27368a6e938b2f5641b39fc70123676527821b5c1b6482294070c3afc44d916cf85ea6aee65a401dcbd19f539f229b9ad08301e111631e2f5c5da4664e331bc9b15e1c1e3f6f8261f5fbb35535957ab31b813c54c84b08ac25ca223f32c73212f0c721e2ab20b85f7781f0a8187765a3f676ba5b4d240b52ce258dacbcb0607150633df94a0891966fe0ddd882ef1f696e2062052dea1e54f50b45485b008c85d9acb2ab3edfd890054a3e93dd005d77837fb123ba8903e29689b937e1fe7de323174522012d41b2365f2352ddff3fcc6e3309aab33d1ad5f33058377decde7514fb1ae5fa1c53649e0c311267044de222d176d7ab7d31e15ea20b16c53388f2dd7dd43be2ad28b5a0de36d5ad7456fb54e9bbeb1eb668b4b75f5d63e205f9e7d5f76ae2e506c4fbcd14e6d4a251d02918cf0b0ee767095fb53b3ec770424f9979ecbeca62821dcc1ddcacf89c2bc6fb1a150c2935fc3efebc087efe3f97e0a7c4eaf28722779c073a871039199381965d9e3e50a99f5b587715b39b8251befa36ddd26a30d31e98a33e2d6292b8970ede7bce06d325852d3dcac6f296b119b82d3375f16c327e8bec8202b753e807634c594c83cb1387ab09fd508fa516bcec6da4e9cc1bf0c57fad640f0897550db794d3de9198e44f0ffe19d20cf64aefad1e2334187c97f763af7ca6f9ee679b04f76ef286bd803c10b", "18b1821061d08881d1e74ef3ffa73d57731806c6942619d0e3b627ce79a07b16d2c255e3618249e2ba673519cfe38fc698db82f33f24eeb5ab6458e7945b03692d7875c86a2b7f57a20c7dda1303ca99c4842dd815476906ae4f3af7101e644c7bfa3b25e1d11580e741efdd55b068461133605972ef60f43fced5661ba1f9ad7fd7e9d00726647dd5349a99c2829150d771da8af549cfe44a76e0aefdd61b1afa7332a1c93c1f5b7038ecd017d2438125d1b9dd66c3e29645005a76dfe73f1daa2869d025dd7411f74876e932e59f700f0b9af222d2f1d186b181e07e116881d0734b105dff5972689d2aba4392d633090c4e18d2a09fa694c0ad6ae1f2900eeb82e601238a348a90e22f7b1f9e1a989c06856169e49b5e857eea2f3a1e3cd4b510a4a7ff112a6fa9d5ff0fd06f1dfcfb2d71e70e1eee596b183a5c06ac8db98a2bbc7295cb07aae2a2bde196f3340ba6854b12ca593985d1bdacefbf3689a7853c9b3918cd9008ad7fe2c5ebc800fac6fb12e2fab500ccf343a642fa19b9dbaa17e15db6cb3e9f89f1b25a785ccdc7ee77ecd59bacf3dccb558639c168f9c6b588ced3f0c4ccb77481962bf94f2ee3d7b7f2cc919f73aafedec7e9ba7e0c0a56a8114b55a3ee883c5efb1c5e9220cff1d7f0228d269907810742fbaeab010820a47ecc7973d1766c7265bfbe4341bf8a7a953a5339f36f9c5433be588889ed91a392321365bfcfe50d230385332ae0aa43534d74e8b46f3b4cae422d40685327b962889de587edd939967b1b7be4ed807fe6f5ee6d720e99e029f54730876c2b4cb4d215f36c85a363ee1375d49f7a217adf499f38e37d729905398f63c073f3a330a1e416d64f8bf4bec50b6bfe0e9bf6cfa4b1adc35f61430f3a3f3e66dd1aa650e9856642e5f5c95ea091f1306b9a6cc4295717f4db4f2843d20578f0b0e2c571dbce0702516c516b26991e5417589af63ce4a49dccfdb9aa1cde98762e9f5bacee2568b687767224c70a02304b9dfb8b1eaa92ae855ed734ca0424a9207bff27f297a654df7cec4b7f60b1a57537b194b489a2a3b23e315a9753026810834b95187f99069e009743abec50f53888cc695246e9b5b440226f629486ff70b8654f1f0b6c47eebb2c343594ac3b523e598735b43bd8330b01cd1e9adef69912d1137f9064280c0fe8ba6b0e55f6cdea5333e55903863d1981102ed464e317cb3625b13be10a686a1ead90b33945b96785f31d159e4f76541be42cbbd9a3ebbb7f5f6b722f6924a74eb8b9334822f7066cf43fecf002a1ba5af5379d45d147859fe340d4a21894bcaf03d92b40223e26d283e019f910b61fa31eabd25293e427b3bb6d81e6e908e0fda7ea48332fdeeb53c1bb0c76539a74242f89f30a54159e5ae4a1ef111ee7c94cdf880c354f34e109c8e6b8fee4f5dd5663a9d989521", .Okay}, + {.Sqr, "6f34d16d6ba1ea08266a92a26e036121b93d8247c33a30d2ce41f1142611581ec30b2e4d97964b5373f1cca40cf9a50fb5dcb088ad83420a1b1cacb323993e628ccce6f20f0967482320bda632fb2680e5e75f3671a20d5c2608b5ee27d908b375d4ad30361a9fcab4feb59d7074a1a4a62c336842f4892ff76f9d01cde711d28868ebb2fdaaa528a9279bbc030c7734e04fc9c753a04be724cc108007a9e583c0555e36fc5a2b1523d156bf5a5044db7e268f39331def029fc249fe8f2f2529d8b7397546e6aafd9f6d2d311941b898ff288da821fbe1f2fa741749a5e026398e9626063a4a606628d3610219ea5f1733c618ae47b563bf9473d1efa754196aeb08c05a38e6fa37281adfbb1a0f1d0ad3a696ea453f6e22dc605a29568f2ba332b372103371f6e67ec3f63c22ca3b6b12e1d4f4413ac10b1aeff1628b2b5b8866868fe7223017d1c774139c141a2551657dc2aea7caef2aade2fac36b56816ca45bd6b0cf263a63f6c332c1b8bfff4ff361c6b1edab40844838a1082787af8e0dd8c1e2fd091bb6f6aa318f3d44620426d99c4946fafbc1e0cd0d5bd2d36170b30654dae09a1230b27fad22e1641ae3f63f47d4eadd89e347e15f076fe108033a31bbe96aa64c629bbb817b8cdcdd7a957bc1161ccf8f13a7a7af409c9f7eda2528371b3d8ad004055d30f3abd17838a7dbe880e54cf79726fffdc9df5fb6a", "14320e021cfe478da747c1006193661dbb18e961edf197fa91ada3e3c9a4deb0724952692f13b5ae288f1d5d21fcdd94a056d528554e58ad9900ecbcfb9ecbdb6e19463b9143fb017a2b586bb3249de8625dbc34ba383044d4dbc1bf20aadd27bbb570cb077f6c4c30a5a6e7164826082eeb60b401da6ab4496cb63b3ee8b275a794050c88966c0f1c2630524c2822eb8f8902b1f7abfec2765598d159bb66898db0fe410d6bc500592cbf5b8f64d5562ba13b1f5b51313b4eb177a851b24e06f5a298f078156ca2b32a14e77ac2662299a7893890f8822d8cd1f60ce1bd1c68f35579473cf4e0be46971f610a1be6e9a444478f17d5e38f71582499ca85c6119e416c9f6b510dd1b521c2285f7431501e1afffa56cac60ff0b716b34ed3f76b01a41cddeec426f98a44fac7639342b7240d832cc1278f2838867b19d1545a4eda544bb91722a69f058641dc37768302aa327d463465bcd53331bfabd39a995cb7f2bb0f900721289f737415352bb45dc21914c7f063f5f09f0491bec7bc50245bd67f60985adb26699297e58a964133296f6f98b73df482e3d9b9ef7116f6ce257b74abd9fc3c4180e2ab60a5c14f2a6b6304b96d65be9855b8869379c865f859b5465e9fbc33d9a7ca8df782eb0cf056730cc293b27c4a10b06a4d35d57d55446c64d1fe2bddaf984658bf87fe75e58cfc098cf9b6438174b88dd4cd10f9f5", "304ed882a31dfb3d59e3602a2be204ab60937dc2bbc3cf0f828442a3221f25e5d1859ec6c54d2cbc4b1f6684d3d7a31905e71ed6d049e491b72a3845009b6d2332969f5b90e248a1f6f23525b9d7631d90455d79f351e32a262aef765a70d098f616cdbb1e1682813bf6a5a57f54b1269905e52263ebf0b8103c865433cdad3fdad6dd45cd920171d6b730c35792c6c566ff11ba0badb21f3787e980cebee84b63224498e07a0d15208956226fbb4ab7b04bb8078cd655618cdc7c4d00cdf41e8ba458f32d0ba7e7066c043aeb42ccdc47efde6d1429f8d9093a337abd2516b962c25fe2ee5fe273653f72c9e81cf9ddd1ed31e4e28a7dba7ac3b48e5fef40ea270031aab8711e7770575ed62bd8d3129104c6b46eabaaa10995683f508091fe28e6a0c173982c4a8a2518de033af8af8da125553f62f4c023bb5ab26030ebff52a1c10c47583f6530723f2ef6bbcfbd9b0fce2efa58b8f1d7a96aa48ac5faf455f1ce7bf33571853bd96dee025e87edbaed3f94f957e250f7f71d2e4e862bb1a2bb0669b08f418ef3dfb1a36e1c46001088d0a0e224cc18555469eba08e26a3cbac8fae79e3415537cfa966a18c644fac17822b02bf22c76e0b350fd241e8ca3bf7606067a8954eb276c6e0957683157b6f0a4944c6f291101001d74bfb3d1e5c7dbc53347ea8fa3b01a88b47ea2b35b67f10c16fb0f6cdaf6ac5ea1f25e411ab01f481301a5e5d5be16b11ec660ec50085e2f450897af6fc3ce226cda5146bd3f2a65f97a891fd75d13fc8622d52505b6b5bc8d7d81559701867d45477495cec34fe7fac439d0142f1d6ed001ccc6ea0e93b467f32fa5674df17b7bf3a2b4b3fc18c7804aa99a32216767051fe1f76f6013c3b38688952f4834ca117f228317c43a7f14d4133db9aca54f9a73a49608350a3dd3ac7d27e462af226fc565475df4140da17f68e9f8b4ad87a10d7ae55e2aecaa8b8f55c25bf842d17ee4e8cca5096bb95c4e39825061e3013a20cd0197ae2e024a40cefd5f29aba382496fa14d2acde5c533603a1ecd514cb321042c9192ea0e527ffdd1c9123439be77851bf035b0034298cb3e6029755211c1f2cee601b3bdf0cc2d8dd06f60ec10fe27f5cdda016972cc6cff3e1553625746314bb391c015b4bbf19e55defbbae206df49e5715018a9ff6524ff988df4264d463caf2ca18ac235dc24c0ab31b095a6132d6a3833ff989983184cacab2ff4283ff22d6bcead472d3bae467b14bd1082fac068e4358c2295b2af63fa338ccf48928ea008737e1e92788255074aaeb160cfcd6d3ccaffd70040fff6835ce10f5b2e3787eb12e4864bc37f9889656062148eb51e8f48d74310ef35782b4fffb26da2dbde3b3e624c7d1315e34f2a625e7040caa6c832ccc705d8da07300a4c6581ecd4eeda06e1266663e5908eceb33cd07e4", .Okay}, + {.Sqr, "34be48ae043c047a4db349acc7bf5ebcf3ae46899c504cacddd8adccc82998430b0b80d3b738942d9238a134cc6431462a6f2d02a3c9f80979e7e39e6bfc4745b53be2dc4c0cc681a7951ea55f11297a4f670744aeeb6fa57f6a7fe065fc8a36de040416556bd38c0c41f62b15b901df79f87ac110c3bd256f16dda8885b840270c6d4f5401b49aa4ae9cc292ad68ce9d3956a9a36b7930997d9c937cdf45b83b1a2e2590a30cee5d9517491ff42dfc91f5de55f08255b7ea5e9fca810bf8c65117c24e10eeed6f2da9c5e6bf27c48c3194ce76e33d3723e474640a12d5ed0927fa492589413e665331da0e61a271b6f4aa971db3872b1768cee3558067ad792b7be7727bf9b5945e39708bbd753bba9f040f1e7bfe9efde4aa1f76ea0f8a805b5439c9f6beaf8cfec5e2eb42e6dfb4af0d69c5581eb84f26d2976ed30a5751b9acb5398fbb9145a086525e96b867df1f55bf5a2e2cca4cd723500e743564d2ed7b94131a5a0d69e91638f0208684fcd263d4b7174cf1b9f713b8d6db473ecb2f6ff325a1975983c6feab59774e412a80a2e14535c50cc3c74556d3d224027a628f22ae939535d207476df96c9aa709f4f73631f1b9acd27b6e1abbbb52a07d8792533430b387c3f6768e99a77414959b499e0641ff1c7fd110eb2ff1c92c9b90a9cc7b7057716d142bf93b111a92ffdf603c529c7b50d127e7aaf5d1112804b", "37096784ef87a139f9dda41d384751cdf4172618e55490ce237599008c42a4be24f7034a2fc540f0b5a3ca304124c48d747c597a6a328e3bf4118b25ce4cfab95eae12320927a82103335648d456a5f63100e9d7209081ddece71765e43d39d594154d76b329fc66dda43e07fcd3e9c22be54f457a91241b598ba5b3be7a7e860c8b3493ef9a2bc0b48707e3daf66c4c19cecb3848184eb8ae40b002f6f415be790e34693be406cb7269f89ab7dd1e3b30f453972165f2f329b1bbc77904a7323b496177bb22efe7dffc174887a36af8b08e55fbd7a51e77d2553f7685f6abc58d22bc84476450aeb351360b5db7abffaba036f289b9caa0dd5fab2dbeb62de17c53459d766ca8439ad202554b869d1ffd85b9246d5f7e95ea65dfaa1e2bf9b1b4674a679048aadc5899d3761519b6af5f380570abf8e5ef19a2371e275cbe486f4178f6226b1e3e55d4fdc5be6e455bf4c58f1784279f53c275837473bce3d7171cb98fb8b003f4ce0fe117a62a3e76fb624254c709dba5c76796775f6cce7553879348fff619d717357b7c626dbf32dbb8a036dced351629f28ff8a3124346ebdc878165683feba0ecfc37c731f20faf08927709529e67f99d122b7443ec2aed53bed68c533f990d603cd0e7f5b8b6b500cd639d02222b356aa7a0f5c5fd2d00ed5ef0a286cdc7283dac61b4d2b8df3179273f757071d77e69ecbae67f4601", "adddaf6a8a90393d948fc3bf29da8fc40e828be9ee244151493dd77ff3cbddfe14e35511e652452de83de6b319c264a5063c9f2f372040105615e447ab694d9a7aedae20373c2370f6aab2a9b6015373a81595943e7e86a95e8cec56c1b71e9a10e17d991c40ad0ad7b9279a6ee995c394b66d58755e81f4c20b21a553a841f1b4b22c1049ea393d495a878966c5143e84ec95aa339a37b5e8331ec0063f50a491984532eba28192d70e37c468c87fed042b5fede7dd14e6ce96d889799340b44c8b0c758b6c77b0dd4e5699ebb7b404b293496768481da622fe260173f62da4c434562813f6d9b1b0e1d144a0a81cd7a89afb5bbbd8fd902ffeab8098bf5d728410e178aae062aad76927e98e7aea8dd20f3ed9bef1be4afc5286184bff6ae03514b05e8005528e9d435f07a28de6df5128794067af491baf7d79438b10f209335708ddcd72ae5fe23d36beed615c60c072a49d2ca8cc98a3d70013ff9ebb406c7928864394726d36af7db77c6aae522c0ec1abb6dff5c68a2477272424f028b0ff983b6ad6c58a8d09a3c6ec49ae7f259cd99d4251c511ccac50bd5dff2d9fbde8a926c63cc5cf9964da25cba2065752eab8b17e524ce465402ebebcda338cffac2f0b813054f340eb3e8e749ff5344b3e66b60ab4154f721910b6463a6b8ee37ef6d661d46d145786133549e131e0788d106f0b591b6c45009a41cd5259b753bedd67a47afd3d1c3b912015243b1a7aa58f16582e67ae49479d9ef44431996c9516e49ccf622dceb6c501a72ada84b3c75b5515ef8f210989b7a2775dd9b47242b0dbb0735af95d0edab1ccc83b7e0db8819807227f23d360183b9549e59cc664e3c577b9335a93ab384575a045ceeed714389ece586b45761a60eaad70d22534d3adac6849cb9d922875f16125487b2d89c57b66ebd467a409a63df57e4109b8e79cacc4b14c7bde4fdd2444aca2c2f6fcfafcce801a133fef60cedcd9b5755871f63c3047581a862966ea8374b932f09e02292392f2d93bf5a521b047c79019a335d3a059967c24cb771963731ac703dfc6340241ca412c47df02eb4d7ad243aba43fa399efa89a9da54553bc53b32835c11bcc5fd904a62c683412a147d8754396b4a6926ea65c4ed29e36358d591febac33b9eaa01190920a736f89c41765cc55f0d6736dc409999ceb3eb0c21c19815e01b5cf4868ce0797f2288923cc239f76dd9db5c2cb9ae7fb2018cd2dfdf2fce4d17edec6d798c1283f79cf78c5fcc0c06964dbab6491ed4b6a33ce093ad6797fb1ce579a3c9d83fade61e3c8364cbfb1a42708a731d382b2eee3bd01b79660d2cd931fd7ac9bdddac46109fe444fd2ed181a7524f778d8c0fc8702ad554ca30dc1bfe1b826cfec3807c48e0391a44522738a455fa47b4406e56f3a03ed489e1855283a4cf7736de40d715f9", .Okay}, + {.Sqr, "92624a56be545d5e8bac8a8530d7d7779170144aae660137638aa03306e5101e86f1deb736802997e96216d961f59a4dd779790bb40c9b00cfc3dc7acda850055bfbc203c1b4f0c0dbe37fce8b7b1689801b73f26e114a42f244df39f32594762044e4e26148bbb4082c3359a4805507da272ed3ac576327b7641078f0a2792a33565a2c051bab8410034b24cae0a6daedb4a965f09b25dd7cf6e78297381b703d0c8c4923a0082af5868e93da416de002c2ccd0b76d26f50d7866adf4516769d55cc3801e1cc70905343c8a51721b26f358ce683c7b50007b3ddd91064a749e59a9961403ef14bf3cf5e20befe940a67cf11294b5b9ac81582adb11d4b634974fee62818f79e1113acd75252a052be6142a72a93b365dfa2de6e7b15653d61153d6cca608e54c24b54527e0dc3c595292b7a2185661c5c1e4c534bebe1ff63ca41b97c040f48657a454f0e83eeff793a2253c23c0daae214a43b39cecf13a95be3c17595c5c8028ba35a54f964d9d083274b01a6d6e252fde4220d56f23712bf821b9d177fb73c50adf9f6e7a74f6ed583104664fa5435043eb878732c60433dff019c192e917b4ef74725a22896449589089bad1e6a55891f46a54dc4d4a606a5af9b89ee91bd73f85b064e2f01496ec4e39eb6cb3d334387c3fddc6d786b3ecd50694a0ba2077cb4960a27ca6c63b6a16287d6f10e21559a4b740cf913203", "e72208e6258996952cd5f21df421a76aa87f479eb6b21156ef323e739d6c21ab1b44082e6d3e141664f3059d878801a7ba5f9da6e4c9b2ffe72049d781f577d4f9131daa49efb6197dce31235bb931e6f6033807f19e150f76d6e9764fa507596dee231a079d5922ba6ee3ab1bbda3eb679d37e7f2779ba40e16b3da7589e98af1cdc2d1a5bdf81832457c93d81f1dc9cc02c05ef618258ed766ffa0a701d7d89f2b618f69295fac97017729614aaab9ca3176488c34a466578135dbbbe781ead202f97533882c536cefa9a60b24fb0cb009eb66991f8acf1b4f1c247f2f65148a2c135ffec1983ca2b6c026fbb41c1bcabe113c8cdd3b3276fb581cc2df882b7e0b3a77dcb5a8e153da7311681f06f1252d0a4ecc2235b05722f199ca1dcd71d0862bbfb96d97b80501517d9a73327401e9f96d9d9ae5e0b33792bff4a447786ac700ef4787478cefc312855a89d5edaabe216fa8e0076a39514ef3b4fada2f6b03e11af4b64dc5dee6c54b4e0990fb9feb8cfb68e6c7edbc476c895b17b750e3905395ad1355ec77cc066ec36a1f80d7dcfa0f6555e1a852b4bb27a69371c9aaa8700bb1d1f4036465bbdcf6af15b8d03ef39c40fe371425ff0cfeb1147694ecd6a763a8604eedb181b24c92f4c3c6a2ad93d9644f940dac69ed07c356214dc16a0330bc257ddabf525eea450351387f2630b8bf8178e234511f480d0fec85", "53b44287f118368487de78c5511f43fdca7cd8dddf837d9c889dc863dd6303d0c401ddcd9689cf005ba51aaf3d8e2dc1bd1815dde7a928bebbe6a62df9117e4f06f729cef4602a712feb8ea059b9a5ab16c501b8aa4776121b3c5efbfe7dd8ace3d3dc0bb32faf85879b0f93a254e96f669de066beab2137c63dba2269f4bc804899a4d2d039147d7b4a201fbd658a7fb98653e9af224a2a37ecdfaac701f73e3f93a2418a3652c41d7c374d3760fbb67ec12dab6852d32275f36495381494e9416638f510fcf3e7ab7fc59e01519adc01cba072097b31a5e3601c7003fe782469425e2cdd81b945173e87d2ae9e44c5f27f42cdfcb4ed7005b2397c0a83e0cfdf7c5ee9979ceacf536b4e58fe9be64e9bf28a5824d415b0ceabaa8e0f3666e6c4444ce789fab51c970a0c167ff4f1b695b1c89c1429d78e2de57561e4503eccd260511c9b7686a52d6edf125b6679ee73b29e12a5c81543f500f9b00e12d691f254637e82d068347544e1a5abd142d40cf679fc4f2ab1acdf20f0681c05ce50f0ce411d25bd312e7650dd73c6b4284181363f3866f2ce6f1104739a142e4a0fd7b2f5faacd3ee5cfc6efee8149218c1adc6a55a1d9fba0aab093429ca7684cbe1005edac896441ea880c1b482086739eca530cac69b9267c58a2a2c5583347e0dbe9564b59a40f044ca8a7161c727e853d6adfa1e8eed71f6ac4e207f7292765a9f7d5fea867f5a915407500d5b7dc3cad2d2b32b5fcba3e82c3e032bf68eaa59ad067019fdb117bc86214630461777b01abe42550127a24e1440e39911f5b6e805639223a7322c280c40c18ec84f1356c80b3d5030ad878964eac7fd49006d319df707d1160a2e31c904a06b4734c1d31e83156c733d3f5fe42c60c1933a9de020a1cb7eba7b197d5e9f3c524c65ff780b4b88dede09c1cfcec1da99ed56ec3627fce66972e6f4d6f440a723697e3536839b12c4e74c59c1211216c182fc865a5a8bb28c09566fb22329bd8e756a4cec0ceb1a49bb64289f2ca67ad4e1e82dcaafbc6e3b469a3dc49a6564e79b3d16379f1a8007cff7a225f603f8820352aac9ab10d1d52b7a3062a941da9637a9633dc8728b38bac657e75be32ec7f841e477fe8d4c90a999dbb487aaa378674f99a33e701204bc9eec4053e785408f86390b432f15fd145c54b4b1ce5c9653cbc9649484bf74e7c91238fba3b4a4da24104ceb594c00efa0c10f509866f1837d56867268066507dff71648915d02d792d9ba1b9981280965a29830fece47f720f450ead62feec155079e8c12ed01db99018e469e2deb7cca8c9499d16fa78c053f41c173b5e536fdb6546a10ec889309c531d7d085f88205b2aa9fc9bcffaa049085f47b93d6098b8669ab0b0790bf3d73c82799ec09e2008ee6bd0799c7669178ec0212f7a30a2076303d6cba8b2b2c09", .Okay}, + {.Sqr, "-ca0ad7ac5f3600db3bd06c01fd94ee1adbd0e79f77d038143bd190cee95d2c2d742b1d35d217c082de0570ea6d96f5bee6ce244c7453de8b0ec93d6550ef3e841051710eb525f2496a60bfe947603ebe7f8f89bec80372db987fe2af40d7fa01d592ce9d519bf729ffc6776b57a56dd579cc4aaa5c88b18bd968b8d751cfabd66a4c331ba7550ea7d116c86adb7753416993a34ed00627e73d043ade126945747637e0a663c2995d3174d76abc88c38f6772c661b32124c439a1fa95e4689bdd4ce613ef7a5b289b40df8bd04ebf67e26c489294f026272ef7832fc42751bbafcb0969e22969ab0de261e3648ab76eda8837bfeafde861006d89a848755028fd0c5c15269f2e009c878390f76ead37c3f091a4023bf63118c9923733b0f1ace41536802f491791943d7bf172a2789770eea9e521811e36f20cb911ecdf368fdd23b9e4b645e2e9bd26f49df05cfdb57cd39b11160b29eb068e4f1fc7c8343e53845169fdec6f97ff59d20fc5bb2bd3cfbd26ba697fe8fb2133bd887f4feb883e7f2b82a0b14fe3ee1bacb39393efa654dc630a49c299afc92b95c35642f54a84b236a99ccd57736fc8dc2fa7881fef295545547ac1a44bb17a9e6eab82ab197defdfc44e25a30dba6f90e8eecac8b6a517b65428bca47f99be8c571983473bdf56f6d923518110e8bd4771ce1a41750242f8503a30e0f38390d6f2d0fd5a4308", "d6c90aa8cef25878cda0f77a18cf34b5d7d41abb8ce954f122f11c864526bbaac9bc78409d5bbe1c55f1b276e96ecfdd35ac1ad667e459b7d62f5ff76b1f4a5d0b9d075701c3129d7f256b566faaf9e876e5239fc0b17988522e38ab3042ef691336e8666d8c6d653ad063aa6575307b9acbb3cec5f3393501b6ad161ff39ab18723e8596e193317869f4209fffcc5efab4887e635966108fe82b77b0189996448477b0695803fec6af71ac80f83878369bfc2298975d086e5a042c7b3400783f8725722b7b5a7354b10dc4d5ae32fabb89c8c6473cb6538be557caaa839c53a4dadd3eb5a8128b4ead4fff645b6cbe260c4f880c0457fb9cde7403ea72bf6ee89b2eb0a397b0cf4ad70f134e588a98cba061ece461a33276cfd1d10c25640541ff162b1da46d719b9bb0acb2903cff30f6d7ea9dd0bef6975f7318e7a5bc9139af7251ed20e5fdd46efac2b6fbc8c26196e052c00c2e629e2da4d842480548515017369907e86b3c15f79c392cbc52832c0147509ae890f7f8e7a194e091496eeb2b69ef31e5c595a54fb3e25dd50203b1012bbaf385fe343675507e2cc1d828bc133463a0e6f4ee04e828d8eb2ecca2f8bc7a2e38ef882dc30bf9b6de6d5e1ee91eef4d16b98f8052f01e5c0b4886054de19536146cb424fc2ba3fa3d0956b7354a68b19772489b5923bb14f83325cfaa6bd440f7b8913621f0a32ba07b2ed", "9f751cd1956ba58ed4f01bd31cb5f9d854adf596e2489e0823cfd60d08e22ef62dc83d3bbb128a87c3295227015132a5e1d97ae6c99c398f11bb4a7ad2018e998e100adbd70ec1050d17bec45b3d3101e9bca58f504c6d2f10152a547dc593c4c642a6ca3e61f57a85a8fe541d70fe7fc9a40fb22b9684ba1c2a3f89e82274f0f06c8fb147b2c8490310c6ed17029d3e8a8702eee0c20d4ed45edaa45c3df3040d8a1204fececde90cfa02e35a489e1e1e3f102241c8b97a976c273ad2dda41d79c9f0f3def352d6d4221d0673e2fe975b71945d3087631f57f53f4d45e85d27fcf8a02de7aa57a98b0e0faf8f68708626aa855987132e3bc8380331f196adb04bad1c00fddf71e4a749964db8158b8f66d44667494f0ebfa25e7c723a4028181f2375f38ceeb7e40903ce833a5d1aacc7e83233f028400375667508614957c335397655fd1dadd274943deee125375fe6371855f053fdea4a790e565f27eddabf0cb619af1732b4bfec1769a997c2636990cb4e98a1a6eacd965196cda314ffb179dc6fcec812648d97efdeb6e113d41ff9beb87becfe3ac21c5b811e33028d63cc92d95f6f9bc4388c751ab14775cd7a678d06455cbab1c9a1f010be21925826bac96197cee076258cd4aaffee610bdc0e4a93a2e90d229f5b2fe5b37e5ede8618e8d4fc3d9902a53e1039e7445401f325217aa2b51e294185638e13714079f73160d7f28fcfa75e68d35e70440dc4d53a924b23165f35dca3d33a434aa36a24951e0aa0d90ab5fd55ddf9cd7073af48b66ccc9fb3ed7d6ad0466218ff885175c543377bb433042d37021930cefddade00c87c4ac5ad74cbe3c30b6ac55557991c1f5ff39037b0ade91ed888d6a87477919cb6d66026bdee304b17affe1ba106a58da1e61666ee5e54d104ef2bab3f4a589b2ef26558d776a529c5ce9b3d111c6c17ef6c0dd18a8be852dbec1491690ba782e7b9b0848234d18bbf304f866b0623be1fb361ba1c15b8a94dc28f602a8a3a8ad710c8e0bdbdf7a09245304885d2c4f84ba68ae66bb49a032f2bb123ba0de95970c5d70826532fce149054c78c994dd07ac7b1a5a4b55e58469e8cca1e474e8f0a3344fcd72bbcc9599d11fa6f2830bbbf88ba483f2e8e840caf5398d5db15905d6f62bc93703ec5b1ba4f379dae3e146da54ded425ae19dd8fd0fcd9f22f4d0a71cf1765eb883b55aa75aed3f5a651563576a8101cdb6c648bd96f7279671dac28ae24f617cc5612f0a21c3480be2a4636df0daf58891d47910d8b32927b2e0118581b17711b092a53b4b01113869ee39fb69324951e56cedbc753f9f9a78d25d2da38c9727a5cbf9642d3429afc96dce04776358cfae36a0c9d3c89517233b7b1de14ee98936fabb566fccba18a648e98bc5f9a756d3e9f6b5a5866a21f05f3aec5eb21c65839551032d3040", .Okay}, + {.Sqr, "6cb6bb52a0d1f6aa5638f2c3b1deaf0dde326244fe05d85ae199f8d2f8e5c0add85873d70df62a81ea289ecd834736f8f76ac610a30db7117d948a31b2206b6f3a8a66fff3146008079d8c960306dcaadcacd0aa33e405b24f65e0d50fccd1f608583fc841743cd3fd43a138382016bb57bea121b84f20e1c0377eaf15487da422e38403d5b724bca47c6332c6938e41d3a7a2c6270377e91ca8c0fe52c82a6cc9d746ce033490e52b4cb68d1a7ab9687dad25bc9d6b8802db0c39481017032b2a821d0f324d09e895a631871ebb2bb7407b9c151be9b0291573f9863730b413c5a336b4129deb6dfac58160d3f2516785bbfcb78a39e0d882e65947f9c6967bf6f46bf8b4606e2256920e2eb430e592e2266458e784df9f636592ee46a1e079a479b7b3d3abb0fd3a0bf21fd6ac9b3198b16f4c9a533c1b9ee328ad7e57aa886cb118315737dc066b122d2b1316d85d125e08ecaf20d397fcfc0041c700dc5c588c7f03cb4140a85722d418d09568f06ab2d723c3e5624862eb96c603f0dd6458f1c78eb8a56a87572b2c8050669bbdf45ed9101e4a3c19174fb0a37129c463120bca2049e7ebc2eab8066c1914f07fffdaa36bdd9906139ed4a0ff51a65a2145005ba34a2fa68f7719ab28f50fc4583c5f17840bee82a97df221a647b2cb51121f2142d87aad2f2c7005e9759cb7234f65e452f11d48287896693c5ef06fe5", "d8eca20d446d82a06c416669f4bf0b35f4ac8101b2a19ee00536c8453b6c45564681dc9299f84822f347038e32cf7435ec875d42b957a7a81c9b2d59074013e2883212a9c9a68eed314ecf91f17867eee020d00fb4f90add29682b6f5a8d91dc18162d626dbb977b2255724ce9d3f8b4b54456ebe6149c267c4aeb97fea85350f7fac0725d7dbb2b8e220848b5a47a1b532151122d112f4e3cf4a5dea969edde8d752a26e4251437c8cf6eaa714c77b15b68bf95f81cd6ed4b723384705215511933a9bbed185bc1bca49b485124de49f594fd4313f2be3c6f049b95b62db35025fa4c52853e432145eba94d16275d050c77c5b180f680fbab7ecb380781eb0a877a856de4ced6f2a5be3026f56dc8e9a00330230f9974813d73fef2186242eb8acab5aac8862666e1900bc9b717b73a062c6fbd95629963b6a8847118b5ff2a1ea29593c033cdd720fb9e55694a3dcfa0504f96f2147fcbc46e9d616d84e8ad2dc21e7a9b0c983a7eceaacf44924747926842e92b9a811eea2e6f447bb73646901ba9033acbdd5ad084592afb9bd0dc0ffc22e3a1acd624810e5107d85708adcc508d5aecf2bab018a5ae99071952d467613b1ba9f203ee156e19d8b64c47bb84e3b696a20b61a6c0aa0f543a8564e95cbbf50140c0b49660210bbb77fb7986784a6741ecdb33c4c93c1b26bf2ab1983c3dfee79cdd9bc8e5fae1ec1907072f", "2e2ab07c9a3fa4489cd8a56e570dff0af6b477ffda2ecda59680e78f1c846dd8173f24fa50f1a54bd60295cb4b9a9319e084990115b7be8f3f9b277913eade10675cd741197c2409a33cf41d8407e32194e55f1816f9dd73dee0580b31fad637bf8a278cc5ab0851b4136f5134649f65624e282728f4953be1d473629936cce8714baa1f582017d2e64df27ac7954d8659fed2ae0500371ee2ca6abe50d6b56f960787a0564ab50d15ca73c938bb8112203ba80da3e91f1b15949b90c705032824806f5c2331183c196f838d64183c17c27f57ae146138f44417510cc896216333b6cdef464339418d9c2f4a27a15d5a94c5a46e2f4a3f6c9a3e48cca3a4eaf57c6838d8733e1b7b8bbc20892b3e220202fc29e7cd1ae1d3a74a13f380d6f3fa58918f99d162d47d7b2f4f8e7bb5be95699d2d32403e486f42676e9b20463b64b6c37d2cfe5e95df70ad79c094ca6f1d0aeb1119625c8ce2009236ee329e1405ff043fe2b18226c27ce5dc449c8f07f0ce1d65a522cba60abe84f59241646f222f6efd54478d35eafc9b930aaddec2c413907477983294847a0935a657d1d5ad3f9dc64cc481dff7dc63fc3bb02f15fa90126c254a8af028ac604eba2badce29be5fdb3492fcc610f86fa03a4befd48b543ced45e1b16b526a3b99508aa7059cea4bfd29975b8ccf0b8c7abc813d98a507859abfb0593838d22c0f44ce335680efbffb3d9810e357cd5d99639dc077b58674fe82a8a1410780be867e62d44662d69756ae55fb509cfc5b2c2e15f823b6cb9bb3840f4b468fb68f7db14b9c2fa529c883db7d0b26d80bcd20454e7f151edb6958cd44e60b5946a05241aec6b73596144d0f54d696e7f377cc5e5e459f591cc852ae90155bf2b6ddf67b112ffeb2076182fe0aa9540ffcc6b6e723b13604c541e5462d7c1edb7b48655112a41957f7cd21bc7f599c31f617215edcaf6ba7865a600d07cc5078371dbcdfe937e16eb20695b61bdf8f6946086885750e97ae7ee16bef736b225d9f1281bfc05a3ea42170dc5bc5df7f70c3677aa937d654a69823cd2cc8b611b8b8bd1f53599211a8a36bf413f73e234442b2b81f5025141486d0e7267df4339ed83c6cee05ccb56a528ee0d88f9e85cc7d50594b0f3ed4e8e59629b1e1b744b61847e0d6fc54bc776dd6b2b69b43d115a5e82f9b97eb81d925426642edc78799b2a318e7469a9d2077cc5c0de0c78464ad2d2cede11173cf1bf3437ba461ebe3b9378c9acf468a28c38d2f6999c31f14abf84079ef0a76844cfd88303f6d28e7768b53c96e35eda5bcfdfeadcb73bb95d71991b8be0271db2accbe1ea46a7d1da8272232a2f0bb0960e8fafe6a3fe1bedb532ca0b7e25a5899fc7eeae70591cc475ce9baed89df5da6e1073b01c47381b719a3f87f678fa0bf77ff2784f90657b00fc1562a4862d9", .Okay}, + {.Sqr, "91cdd7fc16665fbe6ba5801687b458782904999a51a3d1e8ea24016230e3fd032c33543b32c73520628d65eeedea7b24780f82eb9d00c2f738410767b6a16974ab15773e044b496547c9c4f2317521f92659a3a9ab782af0d3a9bac196475fdce67fd3d2f2f68aeccfffbc5143fc347fdb0b4209e979e0355d23bc6578a50fa3374bf14ecc9cf5008fa4d9ce2c3abf879e795bce123dcc2c761ca3483d7c5bc3d895ae7842f2032b4a425679ca546fde6fb08f4ccba72b8542ec113076a95e675b9ba17c62e07ea72af6d7b6314a710d2edfd01db07d0b0eeb11dc8bb7128a255703d3ac18eea81bc401fe968c60b1808eefe01dad8f4604c0fda2584d8b2c13d2a2b086c6302aede2168e7f374a663b2d43b6c965a99d157aaf7a6501264168d4818f0c70b33128fa3c8f7ea72f5ad3690e20046d403e1f76754e902f1ddbb12c06150e0230f22a24ed63a6b00a1d3ebf12c1042c6c2b1bcea36c5e25694b2a710a723339516efde72f2a4e0992ca8154965cd3e264a31959ab9f2ae7dadb2ec4c096c02cbe07c54068a49fdbc2d857a0b75f05320179617c95a5329b1bcd53e38bfda82c6574c84706538cc4b1734e9fa073c5f3622c0db4df39637eba1bccb1c211e4994b5d883a783617e58d8de96865def97cf9bd2965beef5ee75b8220ca75f2be40411018aae28963e59db3e908b9278a8d162f3827f58284f090d9f0", "decac61b36accfa5d0b0b38b5e9421b81aa77aa142613fa4a3e0511b43d55eb8c47c002ba6d0018d583f57f9003a8f2fd576f1631b7a0318ab3aeba8b04933f25ff321101f02c090d0152f9a224cce4609aab57b6da783fdf352bc0f04089999265617a377f03d426fa03216b02600888313ef63866d869e3352eff9860b2fdcae702dab94aa57797ff9b64874f97137084669f4b0c743bbaefd48b9966d303f25cb7d33a8b2fe6af2d976262003e90b436f654e546e41509f8fd805a547b951f4e3b38f03707a4f0c553d051394914171231c0e5222b7b56bf70aaf2f6372aa0e595bfcfafdf1e8b80bf3203d8b2a315b86bc6a5a2a8202698a6e86669cfbb5d065b07d7f8621e23de475e91583bb08feb6d971360cc9f3d75f775877a71ff018ccb06443945727837726e7db996dece4487b4b9737933d1a119ff4f38fb6de652172711d9fe19a93bc1c071e8a4dc6d65d489943a825099d314bc5013bfc6c9c3c91406810e73b50ebd9a71fbe848443424514e48f7f6671f3e093ade1edcaa06ccd0f2d3453cf0beb001bcbdcb6966d122322d302b55c1a765e7eb1f1c2f5414e1503e2f111d4f91c722809da57b800fca309ef920cf1f7a9a94929c07604627d74f4252ad292ec7f0e018add11f820e806662af5183689ebbf4eedbc23c6b3b15be3c8e7d553df0938c72c18149e0c5fe8415eecdc82ef695859bf881445", "530ad42f31553e471d3dfb41bed6c2c8a3d6a9faef6e261797c9cdb4e109b581cfbe86e7d9b941819d721c6fe2ce66af94ad3d1c949770dcdf5bb58553a71c8103e652cb82f5e88f092a719378b13b750146b372e506c6e79090d05b20429917e7bef71bac37e44b28173f4df5e2aae0f4fa87683419d459f9ee60ddea6a10f3aacafd1d9393ceadb704764f98e4626ced87f23dea2bee990ea328440a0f6f07b5b5efad0572b818d11277213fbfa660b7c49c4f5bc78fa5617c997c4f84743afb3ef52e93ae2445203383d1b08f6eecee39b09f61ed65e721a306fd44def691b12c910a4d73f66546d1df6b4c6dcf82613e50e20313410d81d9985b30fe67d5a72d4d4aecff53ae4416031f01768e5a85dce251d002dfaa53c4130529ac376adc8e516d5b660f37161b053d5505a50b8466dde958c78b5790206434e9b216299106691c14448c20e78cd481cd4014b91e443b64df1e013372d966178a4fd5ae27ef29f1d0947d11867af50b33989d13facae8259e067fa9b2d4d8a9557a70ae9f8ed35233a24d068e4da66da13ce9c1d1ba9906872d3b6f10338f47ec1c9c7484f37fdb55af71da181847e314758c96412fe256c7c7afec53c8c51c9162d3c8e30d9b5f27e775e746bdcc1518dc41a41628550cae3daf16ff2f2d53397f651669fc0ea84696d47c9fa96e5ab491710855f8159b7a55c83b54272c1ff402c2f64da9eee27ca47f5dc47cc06d1b416b1dcd611d9fbfa744220cd5d17f47858a20c50becf80d50be1e14b7e1a1d384ead7a50f1457ec1ad96b147b42358d472ae889edb729d970afa27d3a333a6dcca343391051fa097e8c9030d8616a4233c0c3f280eac264b81a40178098b4a01bb1f16ddddf4da821c2fd5a7f1c27fccca6e0f6d1368d9e2e5c94b35af13ea06a9051607b3fb0689b70392e976e939e2e27a202c56f2afcd0e2d370c65d18e7a267346d24c830948f89af525550ef4276233bc9f8bc4921e7d77c88d4ac9d18b149ab14c23c3002368b53a4f17d6927a54a81b50c806292f5b8b8f8ef5d241a73b67e03c92313f3ddd269440913799eebb4012a9cbf26e5bee7bb8b81fb48c4e5adcfd62820e3df7971e38454455832fa744bd83c58f15d610ebf45a29cdb43be79cb7065d15702165dd825bda74d2d29dd63bb386b55d781cf45410705865548f43114ead5d48e2f952981078874394fa3238f59bd40f3dbf04bbcb1f00a76b0aa7ac4c007c9ee68de243725f2cdacaf9bd6321776b0c878a6f56dc2e3b0e9189f2ab797f41c59aea637ea2137ac034fa683a5f4c4abf7ec7a089bcbd6af84631e5885fb0b4d73c426d33faf6ac4868d6dbf96c21be7e47a11d635acce1a88400e89b35546367e7d6148acd35be7027fd42ad778be61a20ac43b91a3b54200d5497002dda36ddaf15a045a286a17e788c100", .Okay}, + {.Sqr, "-e49ec6d89c2d310de878521daddc653d0e687c89485540c6982a1d2e943d9172e096f01c9c52ddcce90ffe811f47f86d2c0027372c8030fe164d004c43391bf9e71464177190debbdd05cb09ad9206ce4b307f17401f173fd584353553b8edecd4cee16febcb5495ddb5f2a12f50091b2118bdbb1219b9ae6c65cdb1c962c918bc27e01f2ed650058c455f02c10fa4c3cea62b5d7495ec1039d58f6b7f2b95365c1b574cbcab2fabd89e58ebae3fa6092fc40dd2f639ea9923b796ac5c78a4834934e178c9f43d1aea4bf20c58739b9973919cbec68d1a8e766cf8fa6a4ed9db7f9ba510cc8ea064731dadab0bd666abc99cc0d3d2ce41f36a7e4ef3b962e10014ee169e694bd9322978a360581406cf8f42e0b2d771476f88ab151d8c7642818d138d60828e0a340ddb64bba265ba536466a5b524eebecdf5031fc54af476f30faea3be9f7f8a880728dbebd003b8a8a846f0a4b81cf2ce2b0f7101386a7365f4f34b2b780129f876003ec3cb4a53655f9c9fb0e4d15f0df48f288628bd2288978b245eaffd6c984c7c047ac29f8c5ee3c83564342ae17efc212d425205a497ba9dafd330e1fd1c0b09f4cecbbcc5e393a6246b22aa7f44a375cf8f94f9b69652abb33f2cf11e9c68aa2ac79897b5ffcb799a8f519863d82f6e8f8f708bc2eb1f4c7754596fae8c11da59d3c4fdfb64585786ce41773d0c440f18615f04e948", "cb5d3d7d021865d86b2d04e6752b3516c5e5aa5bb03814ab894fcac858b7dea8f52053dde86fa09acefd711e5bd179244606d8015ffd34a8ab0f80b28cce67d0af0bcde4d058b98494f31e6bd1ba63f81de2d9c3b9913122a6584ec912f0536f793617e2b4a1706b565980a07f307df05fe549c2c0c0c7d90f9bfdb7554a51feb2b9298e0a0393a7ab752a62753db061b4cff48692556304a7f77cbff65cfbe91b80741a4ee11591b6e82633536948be6b8a302e800a5daf513b3979f8b534fd241ab54587958bab2071483b29caca0e8497dadb683c45adf0f8d3994682148c3ed39137de29d402f24567556c8f978e8ad44f0709ec6d2a56f47206f7f4144ddd59acccfaee02c27d4155c48d97f9a01ab53064847fef3e613c15b709058600eb3be8821d13184a714c6d07a50eb2fefa5ea36e6ccb3c710d64674066fb390e82600ce8594f80b6d0ce63aaa29d908b7c812aa4dbe826f9d11c45cf9f151f0febe5c710d9e071895da69af27a35348316bb4995546346ad09a9e4b31ff49d3affab628ff4c0956c9ee1016cd70b6e27fc32c4fccc79e95cf4d349990e9a2c92d48df4d9d791751ceebebf13570868389cc465e8001d139af81ab814d9154b15edc275dc7fc9a774ec6e9957f9845af97e35b957157307b42f1d0eb8f5188fbdb1b869045646dbb652c07e43446aa0b91c299ddc48f4fe65a90c1c2f60429b3a", "cc2b34abe405100726acad9fe0005d8892a2ebf31cb73555d12c72562a311663c09ce15cc14c184088ae15f8c5bc0b9e9de2da930c8bcf35f5a8fc094a85380577dfb338ee19029e5f77f7d42eaf5ee2a58047a4bc6fd0504e2468810953dbd19ede5f6b83a3144f587604332e1ded7de6e5427a0aa418e331107cc8dca9e9eb1661766ffb688a88de92cbff0a8fc1656949f453a1c61a5f6cbef870e7b01109d4dd6479a50d01eff46e0f2eabddec1013957d03a47352a7f31ae72aeabe81c43b27c0c177933f035cf1cdcac32b27f9d9439a2c2b414c1d78f2912e13ea86f184eedf207ea2e712c5f7a1ef316d8d91ba69aae5ae90563e7498493e692e13ca6497f6549ef339d638034af57c5cbbc6c96c540d29bd3b085d56736a9c894444d9816e0f7cf104738b09d98be87537817d9452ee15d70e231979e635798356365dfb3fba7edf79e1006728da2f1a9372fb9adbcf045971c8233d9ff7d5a0e148bdaf21a3880a074bf2b038aa4f5bc5cc2e42ed1b804a2344dae42f893157061e30da12a666856d2fce2513349d076049c84e95ffb35174c78269a24aed096817411d28e723705559925b817be90d7aa7057be244fb76b7dbbd1eed050cb81c49818a5a47b2f770b6c42f77f8828324373fc3b00f7bc1db30618b60909a36f26dc20dd1b13c3017b569847ee0c9e27264aeec37eca775cac64d68a97a1ec9270e82d4a7a6e0fe534f01e97abc97cfacb06556ef818412c4b9ffbebf93aaa4b91bc6de9586af3705a1619cac416d17c45a2c1778b34ce069b818b4fc346c152646bdef74e57b1ba609d41ef37d025c43d1ebcc4b8aac329313938c50c0d0284adadc18c566621f676f872c202ddabc2a40ddf8a4910876988511819a8fe4f576f8503841edf0490083f200ecd70515e9b6cd5a4df3027813ef2eda3c64bc7ad763eeb90d3492492b391bf2dc92a0806d581c7de60ecac52b28de53a5d8e4761b595031f4a72505e7aa14776eb282f1da8836a5ee3597d547ceb3b687895b960b2fc252b97cd0842d9bbbfddbb805e5283768ef95ab92b506b55ebc1e264d325774a0b7c365c10001da276199024c2311f353a879cff88d2be8bd800c7de6fc844d7d310a4cb7e9b4b11a776656cd9bfb3cfbd056366d8c93e0a64dd98db63c19987537c2cb13d565f2d473788804a5c3fe68726da9f3713ddaff7cab734c38066172eb2430526ce06924d8f000a46b8f6d2cfa1d7f9e67bf65c6fc3c615dcfd950897b455701108649a28ce5eac60e2ad5f65454e2f4cffa34b32e3be7c83e8d7906813b440dc817627f5f41264f2e3f773a65e09b0b36a3ddb00a0ef35d327ee6f0db9242258aa4219780133295fef5ef5bad4b61569b9517695a10081e0008822713ff2538b9d49d28296c8e19725b95e0f65b2848c8541ba72aedcb8ed42440", .Okay}, + {.Sqr, "-ae5cbf57e68a5670436d0a2e6300be0a896e48be00cab8fd91adb767dd50e2118c72ab02d9f496156793f41ea83f277aba824010cb72d421428c847f70608ffef9ded8492c67adf028bc0bffd60b698dd45f846af531986a5b09b4728591b9c989b0acc1a4fa74c94c0548fee5b542c7141f53a1dd3a88f32dc4e820d05c7f3569a2ae2faf3e96341e8d7fe70408d58d34fda8cb144d912a4607539bdece6551042ad103ac5a6d8060c7c2803f4dc00aa40439009ef897e938c8ad04635a163c91d02446b4ce03a64806096d59a2340c65aa8ef386d3b8873180fa4519e803a73975ace1a30921776f13e081ee2194fb67a13aac4426f8e111b576ebccaf60cbdc8d80e55793f9f931051e89453badf9ae89bb840f952fe22a4a9a2525a1954d2604f21e09de4209bab778ffaaf0ee7876a7df3eca4d3f4dd76db3a79319f6302e8ac0a95711a503ebdeff40c79cd77aa6c936ba5f7996f660754d78c4084ce26a8897660ccadc43c0cd955d15f25d4ef5eeded94bef9a620eb542d2ed9d55e6e7ab6a1316a9717cdf4fabc485e066717439cff741ec967da667c4b34967bfa48bb56016923024189e6e9e68cefb86b1fd6f10f5ecc387dd026c9cf9b153b78d8fa8774dfe80474d3fa018320b199cbddd382e8aae8c5e82ea3f218634d7544f2d55800f4e1c355e7b8d2ea908f94a8f85ebbfc48b202b7ccafa6c13819628ab", "896df3cf124608cf5074cf89dae4f992d1c13a8a1de9646d308fe2d87102efb530d94888e530ef7a080b30e1d41b2fa56de635492e3586e3268f22e588c6e951b30e1f8faff9c09fe376d9b843c4be37bec64aa3a1fa949728473e021f6d5dd2a91eabd9d9869b0a6ff4f88c9ca4379a589b9aa3e6161da6a0ec2165dae5ba346aed54f236110b1beb9f4b1cc2cded9694e394630f5458266d977927f495e39dd609e6cfbcbbdbccce8a1560b895eae3f9aea96d03463b1304f353f1e5d4d6d9bfc2dc6f38eae42316c34e580828527504b1439cd7f17310064be67bb7a6514ce937113588bc9b826f9f754dd86dd7f6527a76887b08fbe1030820a6a0534c681ab4658b0279eaf36a18b1f0f0ca2653cff04a7bd64734bbc84150a8f2646118ea4a871161e382efb7b76f209e23eca08261397f449f05f7bca0d06bd770acf67cca94e42a295957f4b2072ef080f655dfe057bffcc85b09ba7f1990e135172890cdff54e5dbec99dfa50570c67b23b9eb1f2fb7cbd8f41129b2dcedf28045a595f54d7e424571c4e5e89da4cd985b94d7301607ee85274de90a2d78d5cf0eda61695a77605824728b32f8401063b1f6d2b9c9d02947f3e7322f43644c5cda3944db3f084fd5a7a88845dca07b2fa8b1c402d60a04812ff2c214127550c8b51cccafbad84a8ea0e01f84d986d129179923b84d39e53637d6dfb0154ad52965de", "76c235b59396091faaf7d333f09a8c83f863fd8b718328ea0410d72752f8d1621333e24a245bcf06374fd1fc4c3a334d725260109f92182427c59e13e35ae78db11d2ce027934061c00b92949f31b7e04fcab7862036f0f1f8da80809e5049b117ede1a287e43ec7785b49761ed9ee24d7e5c39a20a3c0bea014ae6e3f828d6832cc9d32cf24009f2d1700081397a4c54f9b35e63ccb067eb4b0afa458ea49db7cb057ebb06428d7774f0a3fe1f0f614a7d8823aa1edfc9e5b518d3538bc4d05edbcb09a50de5755961254fb75a2192b493af3ac5b1d946b23a7901f4fb9ff0c9179cb9db33d794084fe244e2a628fcd8b1e88dda07145e6758a11525d66731ed670a0fd413cc0552a962d2e0dd356cb718ca2e92923cb997de1e3eb59ab1e92e85a88c5e7fc072925b930e628b98d819d4578581913356295d16169e20bb7535b162bcd5dfe680d6e4a060f604cf1945fa4645864c3a1ecde1f1b3aaad462ad6c8054da62195ba007eabadf5eed22a29f9cf459b1eca55d1e2d90409aeafb50f75090ef7601674849d86c825f604a9fa1c4c88bd4cf9cb32e380bb79e62b46624188e5ad63f16c360c4dcb14573b90eb49777d36c5bd527b104df6860160a75380b9c1090c8743321ba5b0dd2c43f5ea950c9eddfce8448c36f0f2fb8d57fc0e730be2e80d0a7f35a002832c05e5f003ecf08eb5ea637c1449335ae04b9ba43c555600d0f8a84afc026ddc97547c82e53bf6d6f049f4991e7ae3678d84a6839159ff1de4b43044c3cf537ff873aa742cc3a4743fd29ef21be2e1ec0b917f1504dcf37781124a8b36c714c135162e5b36ad9bee148f8c8bab2cf9d259a13f22fd5bb899185c554b2b8f2fb5ae94c848565f99340b14b492354c5d9316dba0047e41ee1f87c5135baa4348b5be3ae35cd39a30c55b3ef47ae7a64b6a787b6f6d60ad2eebb3a491f9dcfb6148e4e586a802b07d810288f0815a5c947c79940c9407469acda2d47f6a6c8e09af4d3955f3d466f95df6d49ad756acca5228ed59cb78f8e84d79c86541001869fadd5968c0f1002b12654f4df872641bd09f1661d209c37614e28df07b7678373e11151a95d02539174dee3133af725e050e467f299e7d541645b3ec77915637c867c7adc35a32975d6dc59586ef689116c4cf36c88f1bf61a46084331405451bbe5f5c782de98b5580342c976d7feb4a66e3d196ac14866fb66be2527a28a3e7cf399488feedff69b30f56a56cef5184d04d4177a79878db687cf05dfc84db9630faee913080d791404cb27627ce7c8f7cc0a73c5a88419f89805e9ebcfbc2e71d0d0308f72b77b1000852ed63d5113efcdf477b1178d8b0715d25ea5561db111fa0153bd33d21ec31c77f39b377926938eecd7af455a8e2bc81965fce0550406cfa1cad346e004d7fe41b5ff07a2efe7204d9e239", .Okay}, + {.Sqr, "7e3406ec1a670269234fa7d7720624f338f420d389036342ba9911388a84f3c61bb9c8ad89e16c35e25f4a54503b4ddd858e600b042c73453bb06a35dde02353d06a39967668fb7b73f16e3c854c174a616271ef2223dbc06730769cad386bc293a1e88bac27d75064a2ead658763f167b0a7b6945096b8af52500708bf85b5e4391a38e6c2c0e2c88d3c30eddaab7aedefdcbc6623ef34eff5f52bd18256983b4156fdbf115b42808518800ffc7bf9ba5eab94c8c0b2d52a25a4de0de5c42a91ecbfcec3e1e0efeb66de18e549382a816ec89f3e2eb54f1950af4a873087f61be9ccfeeea718723271783c544514e845519a1a152b3394a3117288c2af57776123cd6414ff7e4e3ab983f830b3aeb37951a82aea88f97949476173c8211d48acd7c730b220213397b1ce0c4b17efb007fe8966a5d6df238b7ab0b51e126e24c3e105c36c27de5479d2182dc07f87af3680d242cb3f3fae594f613fb5e81dadfb249cc5ba88a77134b9007d31b3be652d2af7413d23bc6f1a24994e168c9a4ab442e718665b9d433ce9cf8043fee65131f9b38f2f5cf6b30111369c9155b443f1f965269dab437277b952f0024b2785fdf74c5b6fb56b22fdff7ac7c6f4e63fd06613972fb451103b16fca363d419a52fb9867a27ecc7fbc3984e1f161b3ace0a4c4f715fa857ab577a3cfbae4c78ec2b1c161cb6a5672e3b9f6df8cf29791ec", "f30eb31b0a36536284cd9eb1e11e422682b0f6d8f7d7d6a0f08cc8c14dd63dedd2866b460ff36b08394db838c6549be3c1d32358a3b7d7b41bc9f3dee1d531ce713d0c5ff9402223518022e189b1a2955c94bf546a5b30669bdeb4804368be21ba0a8b314145e5420e0f91067ff985fd6f9b0a1657cdeecbb7841ecd2448a4810c95a9dc984438d1ac552cefc629ef4dca2da4c032bcfaefc6643e95d78b6a5a8131df860480d582ad6b60204b6ef19b3d6c24b8d232f361449ff2963280de30a754c285a496daae48e00baf565cc9f9d2ba9364c1de3ee04c0baac451c8471d89ffe5ffc836b48806ad2641153639b44a0cbd1f3d1c2d8c4c8b4a0176aa3613e5fbf486595fb6c6def93add9eebd83ffd089dd59d38335029eedd04dd0bebf693675d81db9974c805fbe129475ae57d04a5947933cc7647a1fd641eb0915d9f2318606ceff1c103a399d1bba6f3e18c725b626084d941adf454d9b32a7fe23e62b213dd02c779b7f986e8d079dc8ed5be3fdc456534ef3aa50628f681a53f990be4b1fff10d897407e9e5d0bab0ae3f0f1197d4876f7497e94b7894533fe346ae2e077c125cea5557f8dedbb84ff9cbdd3404a385d2454941d1817caa4b6130d136467285d58d06c9ce4d93ce4a123f27c16904fd112fdf1c01ea31eae14255dbd8bf8813dc26bcde611fdac6c7d20ec1ba8594f9fa3c8eeb27270f7127abe9", "3e3741633a180b35fe3b3705664c555d014be83eb78dd106c184910464a5482050822531cb7e36bdc7d8d21680c4368f98b28b81415ed119b38a88e3b1db4fa9f2477287f6d2f6356c5c1ac08645ac4f3c177d1637728e32cc47d55edfbacde5dfb439f73a303619ace86726be828e48ad2d009bc3d705cf13d15dec778bf4788363ebfc6f5dbdce236edcd6b64a140807cf3eeec2935edc2cc96e2443ef9ba81d3c3465e512e782f2e3fcb68f642c810b075dd51dbbb314f9c7e5ccedc434170f4d71490f8dae0d1208d51f268cae0bd232ee56fbffc96a94931702c698c1045e2c23ae0ac4f15411b9b171514bed40ca759e1dd5e2e0920b2c79b34ac82ebd832ab9fe9f59596cf4f98e8c444fef6235e75ceced06100db0163f2208b8d427ce8b867e38147351a1f60f2f9e9eb790577c3eeda6cf626e1d4321eb1f3af0aa4cbca7653ff6b8e987a7e7d1b4797af05573968fd3c947cec76319557052569674d9edff6079083dc282216b8d0ab898fdab53cb13c70b19bd9821c1b809ed2d4add71255b0ea2ccfa4ac464fee94cd6ab4d8edab0acb5cbaf08063563580d44111dfefbbebe13128033d6fc4ce060b51d75a581becfbb3899ea950b57924c86ebc9795e941833bd9216d08c6d5453aa2b1cbb5f97d7ce0bcedaa23aec129d7aa2ed8c1dafbede471d1a204d21e21b07edb1313c45b5fa645865d26cde165ee60fb16b77c074517f81094624067f7bc792924f626604c21b72bee5b56c64f5d744b5e56dbb3443e40829e451ef2d9425b753d077685ba4d9b6c89cc8553d3d388c37d235a45b53ec9e71e82139245dfd936d584f60cc899d8e77397abc4efe3dc12c4afec779749b8f1bc5ff8d9d3c169647fd7e9d271b74218e0a83c7609d7a5e52e601b1b2354524f952cc8f49eeed1a57f44c59273de9fe16bdf5ee196608c70bca8cd8ec0b9fcebe7769c3701d04395472579b371a2a0eef2674f204dd7421384c371d799f7ba49db24041d9613141cde0cd3b67905bb1f73b729ea2f5f9980cb8be175e9e7997198e98111f78f44370348d890bc358a395d1a87a67fe8cb5498804d171ea7cd11a078a072c38842b6dff4016a59a47c0855715925750b4260e168b2c672775c6e37438082cd72ac60593d8e7bffd8613282795ecf4efd908e6b1510dfa959f24f72ee74caad319762f088b7b0f226a29898abeaa483bac23907e4b95eff03fa6ecba88e8248416f974f3010e49e676c52d35be7b3f8ba2d435cb3e7e0311c1ad71e2a749d2245f05dab8c1a427947e4f46ccc5c486da5d1e9d3a6fe8c9a49eb8315a76e1ad1f078fc76ced69cbad2fafe0ecb60a19a9b23bac0c6edc696d8190387b69a02208fa2543c50f6ae3a8deafb1b0d09375f847153ba23c76cd306cab0a490b07feb29414678026ce0b20f9d573abbfa7953190", .Okay}, + {.Sqr, "80c4ae10cbea3d3bae5d812f2470f4e3efbd77993ef6c27d7616ed7129d973492bec95b6cb7d72d31cc672ee2ceb742d8983913c55c2fd9c228d9ead52cf08b86b3a28e5229d35bf9eaa47a57fe423986bec99543ade81d894b7d4be94766e352112616095727b86a3e1ef159d9b00bcfefff271a60064df669b0ee3adcaa974c221826a1aa8c593c6bb66d82892ff6026fc387a3c3284892b161c0a8a7d38ef80a3601230fcdef837f0cb3b0b565fe0f0c064414f4be3d2b9b1380f3a26aacec4cc4045a37db0da3ba16c2b75ecfcf07eb484502a82dcb9ad668540579c249e5a5a253789f31150f4d6bf2ae647cdaf3ce4f39410be858b45783eda184d6723e00c1141db21fea50ecc2a787939e24df6818ad46248e2be38de7d1fa46199393bb3fd3582c60366bcdcf05faf455ead6e6a1bdb5d876be389559df868c2bf724a80d14427bcbf955ac5057e5f09f20d70a94531dff7c7558c91a84928e90255402c575a96f597c5d9442bd955bcb23ad5ed999b9005deca95ac299f588529c27b191b7cccd8136144635e908fee0cb199afba13c47dc8798d4dfb72aa0de8833901442da4df27d05e4c984af3afaa8c15c56108d54eb7320356cb5af24555c09d8fa7a26e776ed97eeaa967d5e36fa173d9a89c750173669f1df11a22b94476d8da1dd1604d5d1611837aa80980b7ad78f2ea42309cc80e4459d0d2eb0f0044", "af89b2f5dda11c0a677bc917653f0e05a0a242feb37623a47c4b0a0b88812ddcc0d480eb0d59e47dc2774ae86c9b4aa087578fc9504711d6b1da3541d75694c9d7d8149d29fbe5079557532aa16d875bbbe9251f15828502258bc158d420fd43eba8e4e07c780fe3aac87f6441cf93a8aea1fdfc0874f7c79750edd0e80de8114134fc799d10c547cb87dac14fc8d46862bcb3b02792310d5243e1a7768d655e3d9d546b4112b9a7429707ca4587de0cc1d0ac630577dceef1063e53a2f484dfb013d91eceb36b2b8a0a3f52a93c187c0d15dcbc2fdde86d39a559341d9d846a6b24bb6ef339d0c94e6a1aecb6998b48743116d5adf0ffe54f181ea5febe1ad5a2cb12b63a2bad15124ebce6647c126cb1e11a650cc58dff7be9252278306733f5eba6b6d3ad859b2f44a0c810c85ec858954b467e145991495135d371562f212ac4ac88d80383b6e9f5e938725286ccfb052c89560a374ea178569245e623996142004486301d110486a1943535fe6feca4acf2aa72c642346884869c99a6f399312bca08268c1ed24f56384ddf6110442ba01f0be285cd7987b2955e1c04e1a52d8372ee1b0cf63d102d8acbed537e78e43968c0f073813005d0bba53017ab58e3c75a65736a429a419f73afc1e159f8918397367d750aecedfe1eeb401f9362e6851d52504d9556187cdb4454931afe4155b810a3b358e7ead8ebdeeaa0a8", "40c5452bcbfd5235fcb29c4a82358a1c5b300bd8ea8b46d314be91395002a0a70f7153c524fa65a72115d9b3573703bd1d94321841544457b7dcd104b02aa5b2bc49edfa41e23d500ae7bd8738420cd9c0e57f74c66881609b871f512fe31f35dae79c9a243922c12084045cc3ecd4d09090d662b1ea0cf544f91194bd19d7e6d5bacd2c68285d65750bbfb0afa1dce50672472fb86176d56ae1cd73cc32be73ca068aa2d378108ba7f5f80457355da298b3f8d0be1ec8bc352823da691812ba56709f17284f8d0157595ef9c0ca24aa5a27ac39cfbcdfe1bea005bbabe53c1347ed8a163b56ce9aa24f2774bd57b2d58810b1ed4fcb8b599e3fa433fdbcc7e0206322e51b843c90048af8d78123e3321abb6f9629452de078d2a7d99270dcf8c694ae0e9cb6ed6b0c8b4796a30dbeaa3ecd1199f07005fa8ad149e08024786003d80a058a26741c8b51ac3570050337e3b26add29c0623c92d19d114b864cfdd619f841f4c97ca1b72853fef0280dee72be5f72ec68dbcc4e1ce1347635f0e2fde074df8275bc96c1fee4898e3aace1ecbac5a7dc0b1b5ea328966cdbd6b948e91733f01e30845557786ddf71b1c30bec22367c0c653dc269e8cfa3443c01dc7a9048f4c0fc9604675fc42a2ef7ac698b6f2a0304c3c3c051e857c57c558a80ecbc78f337d6b9eba6b367f1cfea918021860acf3561417858572a9cd8680a44a8a102ddefe9f339ad13d76ca205ec0a06efaace1ea6c854950835d4abfc561906063bc6a9a2df5040dbd8a87d887c7a9d5865133ebab2715c0ab3079a5dbd649d49a7770abeb42312de200faf2df1f1e4e50dda020ad724eca328ec77e061bff9972967bc5b00031779d4883870f0a063f36f60397d42bb0e71962f835a076309d71337f11e6d8047e81e75a502f62ee71429c6e8be86cb184376cc309c9ca4a869c2d1d2b758f76efd44163ed33360f342949f8b1e567ebffb51838570c8446a8594ac0963aaa4ce2779f8052cf32bc44eda37ab06fb9e6332a85094dd906dc7ed25e4123c4ed688fe43684e982e43455e9b2a2756f953d78944ffaeee49ccda1b830b3a5c0ea2cbd20c3802786fad463a43781bda02d06f13e193dd17d4655ec1492ac5aa3b011644f66c4407d510fc201481dad094b9be661c6b9d884f7d5baf380842dfa583600fe818f7041ee60a3d171c785c8e68810d49ae39256e5e385e0ef6304d3e8840775fad2e389c9d2b3928d183124865e9fc05aa658cc4c9076ccd6171c1eb3abd1250d3058720c21cdf5d5f2ff68ba1222846f747e2e6daddce1f3a3fbcaa94049ba7bd9d58610aac885aea7f8f84b13111daece8227accd5f45fecc1e4357a7c4a7a43a5163308b5ade0e24ea034c6cd202c63284ea12dfed132be33be8965e1c6e453f336965a5c58ca3de2cd1bc12c277aeddff81210", .Okay}, + {.Sqr, "-c1dfbad264c2b6bc1fdb8da5c072b58bd4d3d079302562593f38989375019eabf6786db9e5c70ee83dfe9f7b6b303c62199dd352c7970f647816fc68e43a3de05f7c72e9f46124a43b91ef36fbd3bb1e2ae959530b6e09d346a7674915787025783696cb312b1323c2368004ca942b8f13c8bd480e816be8b19a339526faca83136332b1910e01df32295662ed5141b564a25d6420e9e18af6a4c6768c533c835dc819082c415e9860d0b0270e30dd2a425724397e79d79fb49574e8e6e0dd0d4b3365c2dfe9caecece6b7f9d2f1c42e61b0df17f0032896b1e03b96c7ba9eacf96e7f59a37f06f3b7856dfe8e3278e0ff4a88e40d3dfc9088e3edc8e3d41ac6549d2aaaebed2693ca4a17768d412fbb4cc5f0b43f920f60567d0c61c1e503bb256d5f8b60514d9e0fe68e7bcd5c6257c3226dbe39b68fa406465300f4dbdd19142b93bd7ac795c037f81a7cf04570f341c211aefb5b9d938bec1954dc3b77fca78f43ac2f109d491f6ee2ae0f9f6431bf0a6aa1bd71e17e505d748bf1a66d8945104ae6ac7a399b4a38124ab3ddd15a6b432bce0b7a96c0c14380c45720778d93db0d3b53c238ebe44b2a23a1de0abc2ddf70caa54625806c8cd8b7f08cb3da440ccbe9c0c7bd7778764a58ced5d64823f6a12a6bf918d50066519c671a62538da48839b04056201c735f661600d71323164d6c3b826b16085643840504cf5d", "fb4be692587dccb3c216df408cd8ef7d32a8e129f33688d8c7c1805294ae4fbfbd4b9b0b723f16fd2b3b4efbdc5e46ea2959cab9276abd838082495562787d51a992fd78fac87a943ab0d12b09f5ff62b4ad4c8d560e97c1db25d6b21659e2b50a9dff5eefe9413fbda42947198723b625e26b4097952e126bd0ce97c94768a8d8d74c9e96bdaddde45a275ad3aaa52112adef5c4d0265d4d361eca195cec2d8130f24b46a61731d0f4bf80f391b8e460967345b0e8cfd958a517a398d70e712f0e8d6c58394d597292fa1d6641db06e24a01bdf8a1a1bfd8850af7ed62a98383f0bef758a0b53d7ea2c2237f7064f5ce7d81298c6e525e205fb8500b9484edba85892af16672750053f0a2cfbc3338967676135cf7801f2f20250ed46b35bb48fab79639dde432052ebeb2cbce508612e02b8fcd6ed17a2c740911410aa2fe751dcc6afad88bbfb539dfc26e3c5a04cd2515325be417e3678c9f4bb9fe77184ebfa65bdf8524ed60fb9ea49af2b1cd051e621517abe7b6fb1869bfdfd429ecad39d54fd69f851ec6fd964065abbef186580e85276a48e735f0a4a67c9ccb692be04329475904320a2e29bf8d7dc70ec90cf3bae8e7446ee11465ac5bf41e72146f996f2d344afe3903a86a911f196935ed15a91b425a9dca92e6f0dc2c1dfb4d8ae90ac112e5068c5a24be75e0eb4e926c52a7c7ddbfc58b4e3a64a9b430cfd", "92d31b383ecf8a166c6e69e0716f5422b5ed2168d990f1a41d2ef6326b8239b0b9daba690f74254de35cc68a7684053966d9a11e699d3a13a7504fb6ba0460645cacac0f06e3748402e1de48a2ec2ae6f6f8a35e947a377042bd32b8a1efbda54594a218d9a20b04f7a8372ba4b4873661d1c058d7a5654bfae8cf38d029ac7cf2ec7fbc832766668a0d553c5d43c5e60ec8c30710a43cdce3926f598c1cd46ae7549ff52a0eb5a6ab0e79aa63f8b6d9e64bc5f5ba1ad4b3ff72d6ff7001c725f77b2cc2b2597c81b08e99174ba1efff0330722fea32a19bdc8bb94cb6f6565eef9899bd81b4ee0420f5006460f79ee3128ef91855f4e342b9f72f13efe3ca00acd5cc34eb6ab610e62ce04b8163e429b5693b0a76eca08fe443a3621b197889666764e09d103bc2c70558a0d4072695f5a85a7dc4af45051b0218f2f08db4f3c79829d6cf92d7e0a679b77683c89f748cb15e33f03db145424c21000fcac90324da42c66af1df4db49ca7a3f8c4000e7b9aa22cf895af1390344b57ba73e6c768915aae4b21786c45ed214dd57d746a90116b894cf66957556df583382d3559b1ba068bb90e29a1c8063e773b3abbef47b98b43db5fce3cebe5a4e76e8df3d594a3f2aa48a27fc3c7674298f3e7d82304011aab51c232ff08746c0ee7d5cc0565434e97fd508b67c7a9a599bc450bdc33497644d0ff5bdff04178f406be512bae06891e70fa69c3ea58e9e6ce0069de3dc074ad05571c962f12ea17d395b39b41a198460c882b7a9ac69fff4dde727ab08af27eacbb0c3ea1d1cc11e9ad88be3eb30d1fb762d6c965f5649c9ccf0d659533bf7629cabf1d68af11636b9400cb8e6fd9b4ba77cfabb85b4d49c17ddc60824ccf9bbdd439ab25572f318a7e5cb8ca05fd2306f34dade3526f00be5cfbc58ae1e3a94852b098fc6fe40c54291180bbbd239bdbc809dfcd7a82892809d21386e2d582caa21322677de1b6950fbf60edf5ac187a6cd167d683b3856d7b852d6c9017cd3489cc81720c4098208534c6c3934979af92533f64b6e81ac0c7510fbae2984a78bf0df0823ec76e91ab7b14f3d9fa8173f6019e1d6700446275e16ef11bc54dce5cf0dfaea10525ddd998fa1822b186e2b7a6da77004e72312ee4f642c22a8731ec144cc49b8ecbedac0ed602ec60100111cf7e2344dbf56f8ef6a8b853756b41a00bd7b4d35619219f3dea296d255267b4bbb39a8c07a97fb1dd53fcb576ff91978a14b525a35ab7b53387750efeec51c6ec5507a5d96c5f8d71fdbbb73b7e3adba037d6af491a1b5b684ed713d8488b31c39b8afcf2c1d28535a334d0b536c1ee1b1f6b6b4522c620ba73940045f681b133b672c76460bf15eecc7bb2c619b1a0d87b37896aed46d916c656e0b6e0ec8993fe30b8de78877f35572ab7b11c09716ce2d415b618c4df87c9", .Okay}, + {.Sqr, "-3a6650cc0cccff5204aa17796257af851ff261e59da703341ba37997fb058eaeb225107759cfa70a094c41523e4623604ecc15ad1c05ee582ce048252a84d467624122f79fe52acba44d0b4dc00af05f85acd32a52ee84bc53e2db341dd48b2eaaefbd59fbae86a4ca84d187d89ebbbc06ada4151ccb17e191ee774c299d598029f61ac47c8edb9f9fa1da98947763e2e3e44c82ec41fa7d169a3b18f9ac68ccfbac080b65c8d2040c8bda2da21a3599e166a31088a372e75690e3cb94146ce81e67cf57a876eee4d3b9e8284c2dcd48f212a12b312d760db0174df9c74ffa24d8159e2f74f38246d5f311dccbe7ab748fd5bdd207f36c0d49add54e4d1fdfd5ebf398937c7688d2d926f5b9956f2395825dc9cfb6c304765752f43bd5f1bea1523a0d5b634503b1d09d6cd98fba342b0fff87a123dfd14dfd678dd846e0b03826cd837e717ae4243d070b22d75eaa31f2e2a1e3833c2f31b037e05c8e735ec107c92eeaf4ab14dbc720e7f7b4457c5049ffa011712822b5c02ac22664c21ffeb991069ace3548e92520b63ca2e981b8a68f639c40462e07ab8c63ced9aaa0514132c5f1d17576208baf15668bc8b9d97bd02da3fcb97e32e9fa41a592d7732b7061ef14b67a1b0b2cff2ff2fe721e2768f9d086dd289ccab33e57f8859f29a59d33d54e727941bb7262b73b701969de2eb7df779fdef85b552c42f8cd38df2b", "13fddf54c85771a90968f5c2bc71dd6b7ce6650a3e83d2dbd2a2a6726f73e0e45775fb182f61198c761675fd5b2cdc23ed5c44cca616303da182d8c23dd585f3549827be3d65e332e58d40567595801e64c7180a61b0cd727fdf9a32580988db61d207088c3c58f2bfb1aed2a0a32202c950309fed1fe53d5b91d5c7b35bdf574a40598a6cb9751634532147578987d6844bb8f599819a20eb1d9fdb84c6f180f3d7388f3eecb959829555ac9d6aad21c9510f5281a4cf2ac3a36cc4a848d15d3774319e69312f52a2293a03b448a255de9e6b1b9625e4af3a76e8d78a16a69d3820d9f22f3debdddf03e1e7cc3f2d6f641b37be0dfd1b8cd6684728cbe7fdaf4f9560e275597c3156e6d6758fba1b4720b46c89dc2f3555bb8879b5fdda47e8825a522a7b8458dfd8aef38cee8c48219f0db5e6be9d257a2c50cb62ea7479f13237db45f90f53b4348aabddd011c64a83eac7134e776663006a854ce25c6e88286fd15f06495d101a55ef929fe7436210c356b55377e645493e3fedc1ed65da04c2db8517d68738f9873965ab8d2b5a426e1862d37d0a2e1d4c37a9d649e0f8d28d8314a29db0382ac21b351e88465f0f957da3a5870f0656313a3452eb0c18595c280a30da05f31efaa1244cf15b084a7ad20a30d2ca8b99f079d763e91cb3e24ae006e1892e3aeab6e1e685ea50f5c0909a1bf65ca3f5f482ed13912534d", "d528580f1e741b12666d3e70cd7412e5c7fcb4557568497d545f04f54498878aba812dec067f9a51e53bec11cbeb43ed300b6dfa346354e1cdc5741e2986a77e863e87f9f2168b741f634a98aa7f21ad1b510767b178c9f94b6ff628a30e583d32aab88a3638268ef091f6dabd42af615ce9aef43f4432b7faee482585614729a90ffa5054abfe725475428523b4f3320262770972e3e0c9bb24138464e70e8fc2b12a22d1739331a77d2e5ef68eb65590ce9f69bc93df7ea86e8ab18b3505d9834c6381eb5e23588b946b386ae8a25081d95863da17c0fde84fcc5f9194e0895e1619c7ec18227b85caa285347d4ae06860d0bee64a443e4b8996f76de7865409c49cf7de0643a03f29eec206a15631b3a50ea142536066fa4dc904e29f7ef6c8f299b22ae74f5ab2f9d22409e0a2ebbc03106587ada426b6e0ebc5349cd9e89d918eca40c381a73a0b9f6e80749a46761a7719f0869300c8a098e611eb6670fff962179dc74020eb4ca3afd982a3977fee8862380a5cd5f1c1cd1129723b34e4cce92669190bba17068aa33d4a2b542834ae04b99a0e23289857655c1bfd8706493086a4055da8d9b9b4b943b5f5deef5cbdaf00e6555d02b1a2f183f5c6ccc37f29e37da60f89f0f4331325d90f9399c3b77e62d92c5aef739e149f620b3d120858b6fcda69dc1f7c17737dcd2f5713b440cc799a352547a4f19124266e855b45c5c11b53519d2c69af76fc11ef7274d70202e99bbc493bd7466d97dac8ddbbe9407647fe7112e4f1f2069ad2e461e8beb6af3c58c0711ea3b14facf4a55f170f64dd3c7f9e4b40f989654039fc3c358f19a1564962be6beeaf8f7a914b9faf09973fe34062162e77d155de165089a7b6e2250ad084ee7685d6d5aeff2a78df7102a583ee4b4806441727208beef859b1e38d2bfe78f8db7f2d26884b79bba4a5d9db82082295529c25e50faf466ec21f2217c5ec2b0f3f1fd0d015cf4314d1198dbea33cde97ce3251ae4069f042491120b4c54d67f609f42c2df649bc1c024e282e74b57dad812026d5de756bb1dd766f8914f24ca524342c99d15c1ecc2be3ba5c00b0593eecb0aec4ce49ade11a5e7c1af94c5b9a2a4e6aca12a317f06dd190189eb229e94e1fa5d926a1968d9534c45f109890e0cb8fd1c9b6e02645a34a4eda07ad1f88ce5cc09796cfe93125ccccbc03846bd539a688019c4d0d994aa13c58bd1b0da21f0c8fcd13e605373f11c575e54062215d8edaf48ac535b11818370b36ac88aae153d86da9dcb0faead91643161fdeb4a9b2a727d97b1e077654cea107db1915386820e9b24f1198f14cbe47eac66b2c1ffc9165465b6a465aa98239d327571e6cd27dee10ba0b766bebf102191ebfd2af85d8d47cdff51556cb1ae34d5932e3f10db6a6489ae7f05270e74deb983f0da8eb15d435bf139", .Okay}, + {.Sqr, "-955cdb975a28108471dbf1f9e8474420a2b9073b20bfb0f9c52deb63dbf2f1a2e3e267519c07f0d6032d5508f95418127dd9285e225cbecce65232829eabb9b0b6ca9f2777e55d0d41b2ba19fa5f10d7e7e2d78a2a88b325e668067491e4746b8502e7edb62983b82f99f46764c79d26d95a9d43be2f190907d0f0b249f2c70139b734d795ee2d4712270d84b57698551ad149b0a410caa5ce5d9f24fdecd5ed532fe02989a76c60e9aaea0cce47103bf23a7eb138ba85c4fc216c1778d718a9ff10f8003e2b14a24e9e6d9aaa5fe28ddf34e9a7ef321d86330df57f992a5b44848854e915abc1c051ce13df8624b63cafab5a3dfe3bd4e48bc24d9e8bba262e229fd3c799ef3f696af348664742b60cd1aba9f9154d2707e06cbdd32c514e1ff21696ce9e9034f891ab304eb2f0ba207bb2b7b0a26bc4c6d326af7364bdf367985f688fdfb793faaad2b287265dd923840744e4476d5cc49b65e95f9f4ae93de76c3844354618fd6e364fb83ad511d1bc2fd26127ce421529e8f4d8c1bde30a641598176ac0afa08e91183bab7d72a8475803817b48a906cefd7f4d425a4de885fb8fa523c10429032a834a8d44545d0d8c66b70322223465d6fcfa56592bb0709edace81ccf659c29642b4d5a2f3b82fb39a35f5640c6e4ffe6feb6c44a546d6d1f76d190056facea5f5e772e304309ec8d6044271da5ba5b51df6568f8e13", "ce91ffaf2450dd1f7420312a26c3ca64aed33d06ef26481475e466671bd1f0648bb73aae91289df49281547e1f28500224faa3a0d87f52f8bf94028684d0a008f8f80cc3ab3e71ad2d7c40fe8cb6a79dcadb5819f3abe18b281d7baeeed143299a3869a8b30b6360919d89eb8b4bd3430e5336cfa6c9c5b2ca1145e67bd94cc79d44ec1abf112dc0f62d8d1fc94024ad3935e4cec0ea8782ae6b42baa54d0a550dbd4147e4007aa9487eb89e7f03aa57bbee3db1e37322910e6b5c82e54e517a050fe659970104fbc13c092025d048536cbafd7ee51dca3c28721053db774110f02a0a413f81ebcd7ee77352721beff2642eed41b2eebae4dbcc33a4af5ebba7e44d4d6561ea7dc7f202c4af1cb37a85eede3bcab087fbe16ea6562d5bb2517d2ba0100d617ac80d019c5e0f777b00f1b598917efcee3647d0d61eb5e1b6cf4feb47247e8603145ff25974af8730a726aafb68e8fe7875b539295560381f9bff6fdde6cd4b48fc7b7ec8ed55152f05db9a9dd4d2de5260f71636f7ab7d418a3850e49e36a9ada4bb39babf5ca1c2c4a1fe011d70ca0e03669faeb0c51ed8115110c5d6b79dfaa2257e7b9c48a1962d06dd6e72526f1d098830d2dc456add3e81d49b4de0099ef00c023b97bf421b7dff8c497bb248e21643e4d27324a967948f8d61e3aa576547022ae8e7edd4385ce09399d7b6dd36f13e194ff942fafee51d", "5725394cc017bdc2130226b1bffdfe6158a1edd3c33e77d88e5a2292c402b155c237d702cc8d564f1d55fdfa3af87d3f30fe36a3f16f8285caca6984f1d3466b57dc454ed3404e794dcdfb6c45ae8a0a367ab0bc7f311ea19d311ca335b99ed600d69f227611c49c34df632a057d2a431fee2afd409b790479492d5d1d7c075a65c0a3f7f63dbd7b78bd12b5d4a6cb920b8d83da28cd8a3bca24291a021c868ef2ebb4127d4e9ff94ba5c084f9c31ecc26091ada34605e2363e59a5f0923956df8036c22e3d952591460ff1730b51df1da133854ed2ad7558ff207be3370a1ee2aa7bbf512b9aeca46360e3a74300f73aee72d35c5e87cefe26cb7f750ae4936e11b64edf6edd1d2859fb2b3f1726d701b2847618ca4b2cfa6ff229bda7cfb72d5f8418333fb6eca2584d0414020d1128c438e4557d3791d5cffe18ddb99ba207826226344ef0dde3ff091f41d6b6e7c785bcbd2d15a98a04121164d09dd30ade46322eeb0d6436a2504e03f504effe8c36f0a3a5a3f611b449dc14be380a76bbc196eb9fe39933239370af6d8426535c797678a46f23cad73843f8bd8e2243a68c5952434eb6ec0cd5351c7b20f893f23a0cb40efd2d5396f8dc842850d4f30ec8322a2a19c0c62e9c519ab5547d81ce38f63e59f2ca68af37bda59db264bdf463bdd1568f70bc9862c4a8b3dec8dc4a4e743dabd28d4752ca14ab9129192b19057edd6b9a67fe8558233e6d396001340c1890b1bf73943467483a2c8541d697497f94e7e485117e61fa5d53a1a7c63ee985d8a76606a6efa95929cd651cd5736f29f2ee768ece95c02cf5d6f4b6527c15c8146accfc41686806466d2ba0839f8f146d1f8f72de28bd3969dd1aa8cc345c884ac24ae8956b9425482f3cb20d91de4d1a80f2e729b9a1bfa045253b5579f7500a266aae3d344fa38011f979d66af71147a231af64cc1ad22482fd5aa0d29bf3e09fb2388b60bd64e9adafe3e0662727bc963ee803d81aa394ab99c4de4b1b732fdadea4638e4afb694c38934789eb24cb44dadc0637c3a337e144e6e6c33cd8f9c2ac45c2cf807f87fc722442af04d22b684a63930cfbdb1d7de3e49a86db6a6ebb17233fa1102342f09377438defdad1dc83933847f12c3384ae8d712ea40327c6d9410293150fa5df3161115912b8e836df65eef0337cdb85ce3baf352a1c3e607c7344a0af56e5d6df5d3fb3ad2c4d434fd6456786d8a080535127d27b9bffc1caa1b88cb350c830eb2d9122641685e9eb53c142b3de67298beb4410beeea578fb00aaa49088c1554edaa85c0d19251651da47f05d7a4f6dce739e9446737991a3879975d529830b8fba64e242071a80a9b9712569a1f7a8f67c5411ef5dd459140f039918f2098e2671f5645ac7145b81fdb13d7ee7f9a7412ff9750dc75e62e3a8e4c64381e78cc131569", .Okay}, + {.Sqr, "-2503b2ead096694cc554cb737166b3dbca247ba2d0daae3fb1a592369344e24a32eebb6d1087b2a4a577c075775fbaae79ba48caf379b803499b8739c37236bea6ba8183531840812cb11cbafa239a8a7437af200c7e69b5e326142da703476f7ddf0850d9df31b21e3e3fec17abc7f75e250b9040e7c475b32efa026b1cc88e06cf26e4dec88cb3b5d12671cca72b2740495d7b24cef6d6d6bb81910aa50057d47dae8f639cf461196be9bcfbae547222dee10295d805bea619236d5387ab2683f0db4009e5edff449802eb06b9ac16165a17f65a1b1de3513296174f1fd0f8e8922c4c346ac407fe104fd1294b5f103dc829bb520b8f89a61ad516096437a772317ad19c1123f8e3a6fcad1d9390575a895bc49a4dbe507d05dbc081e007b7d07cbb86f011b05316c17c94b46c3521ac34811b070bd5754fb419914aa87a52e1d5b7f9939a9f8d60e2306566259ab8746959bc7face1c631815f7c98236f0ef56372320e6700629917d75f82ca47730401b5cef79cb5c2eac979e8f6e2e080745f7d02b75acd6bcd0cbc0aeea18a05e47657ce567843df7f21a5b61f6fe077e2ccc131e774a9fa2af27039edfb944d7bd373471d0cec0743ccfcfb1f9023cfdbdc985d005b5649a31e95dbb1b2271cef648366422675b387080302e7119d14b663132c3631d71c25cfbfcac6b60579a156226209a6529fa1c45ae844629efd", "fbfe3869c798762abe691fda0f40c1acc176b079c23b0472a1a1a9b48a5e3e1f5b74b39ad71c110c00a40cc64f7a350e61b1ecf8fc12f050706e7819eb60497febcbc5202b080072bb9177ef8f0962a06213ff29be1459a5e2b276f60bc4a8535783e56f49f8c48ac6cfed1d86f5f11e014cf3b79aea5cb5915a8ed09a7612f4b04ea45f8f0bc101239418abb6ef2757cb5eff83261702714ecc22da45448ec7b1a0823e245ac0a1c4c17424fa20685a069b6caffa848879bf26f408a0bc39679aa4e354f13a7587babcec510b88a74198611deed678a2f0ca45f7dc636c0d8274b5cbdc9d48b3c2f80af4d1db49633af362bc163dcf04dc4d6ca219fb540d149613346aacf443e4a19ad9b7a7b3e9807859c6d333d5191d99aa73c51bceeeb04a13b7e62822de455afca6da64f2bb1c63a9dc83d2884b4c3f82ec64806de6294a2c14c69308891ae1b0fb5f7fb55f1f733145011beba4a136942b6eecc4b918b371a4d254e0a8b641b6e9411b83ab20103fb4c4b6c2d1a42229b3d045730e5ad2478bfc6b0f3970b13bbce39297f0871a57ab991bd37fc202115f00286de067e6c1282fa53f6162565d15ae8f51210b386c60af976bac964369ab38f4b4da26b9c5723ed3e86c8ed98ca153e3a70ad4f49810daa8452c0b6e15041c7fc5ddb074e2b6ed0d6f050b8aa188937e9875b35f2ab70b0eaf26dee6345564f3267728", "55a11c58ed7bf69d033290b1f5dec03365ca0e7915c93ae154d054e5910cd90afac71970a45fc96be523a4ecb7a7f99682d6ab3253aff5a5435bd28c1b74f250a5c863f7c9227186632f580012116882d3b685fa4da79c5ef54a1d44980ae42eacf42aae5ef572c3b5752b22a1ba5c3a1ac2614b5537635aefde8c3d54c281a60e0077d2ae0a2e08b2e959a27a8e8861bff165445e0c824d75e90ae1147327f66afe2424f89a91ce496dfbfe44b83e1e8f1262cf7bcb7fa6ec0b32776fa40fe41196948f3187da06dccdfe424b16b42d83f1e3f69ed5dac038b05e77a60bc86d67d9b1455050bd91e09e4b09a37f256709cf6b650dc1f7a2878b482ee762b220ff028c59295a8516e40f34a3701a6b2f242ea425e804e46388d1030527013fb8219487f9eb65512746b2e849639ff72c772c5368cd147af396026d49df6e76934d0b62392357e5247378a642264d12ea91217922b23f6b5da8ed0bac35332155d69b46a5eebef0a03b6865f6177a2d261a710abf9ace152b4ffb82ff02eae4c63166787cc9280683153123a14d9afd9aedef616d7764bf8d0dacf97091570b136499a3cc9ac1a1813a4958cf5c3dd01deff07793a50cf560761e969535119e5d46b398eba7fe7cbef96958e8f3fbfd4b1e5cd17f56db8755e828ce4bef1679bf59e5134fe5def35355421b9b40aa8e3439ca23080f1d5599bf869dc4568af2068010879ae857fd1d041944aeb95e1ba897bfca8f2d3c47f5e3ffcfc0534bc635f5b31495c849790e14e15e2d3bb0d252c9f4dbdef047282408507916f82b534ca4405903d67504726132363e80e21effba8c44999b17f5df1bce805ee191e8ec26a360bde41e9b52424fa92408fa967436f682a91aa4255da721ea9283eabd35891b148b623ff87767ab1918c305f1624009e379a84fb6c916a83afe76f576506627061e5ea25da4f83dd5d785c0b06be5eb154691a2c0346cfd3e235facb5a3d825f978d252f8eb3467bae428adfa402abf5b53bd2177ffccfef568878d749adf79a38b3017dbeaeabb36e6e459c3301e7ed6efebed10c6e2e4d640a5395379f537e19340f8f69f7de9b45ef2e4b057470db647e9677a6abda71f5ae6d39c41150ae59bb4a888a00fb08b96a6d8a318118b1cb6114b35aa73fe15e7e90a0c098af0592f02ddb99c0cc6db37c42a64d149538edbc113fc201e0c9a68fe7e88c30b11b3b0dd28714b7836d53d48f0f22569ad4feb8d7d1338e99695e1d3fef6882f8c35e13d7d3c41b6db9e4c6b2a734aa5b2fdac16a2c391243d093badd7eb99dbf94a837e2840ee25dc2bf057a87f00ddde57576ba1cb60217a76f8453a32fb8216d7d5d0af2784d30753df1150717218bd464f99d65cab5a30c28239bd3bdd40bc22d1cacda32559baafda2c9b79bf61ed60f946c78150a36990484714609", .Okay}, + {.Sqr, "3b6932fb76a1433f6cfe3297a49bc4223770bb5d851828322f2156b08f74427133286791006a881ae15f719ab1634c19281d8f64e0bb991d5cdaae60eb21714440b615eab357b7711a7df47a49862246b969e6ff9b321b666ef97c1370cffb978ee8157f269d2eee1aa6973eaec36a22ec8d199c151a2735375f3f707981f1f375568c98085be88ac1a4cc2cb6fca472b3831f4ba7984d46ff1f8dfb7ed2b03617008b2cf97344c397dda6d41716b74bf9eca87c4397b5ebd20c441b58ac878d7799e551a3e8e93c57e0ae3991b03833c2614cfc4e32c5a0eb3980bcb2044b6154caf474a82d50bfabce5217791b59fa485db4dd8aa857de23afea96fbc03afe94436f33f8fd53318426990a6098bc1069609b59b971bf8aff4f99a67eb5fa10453b4a5e89be18bd5f2bc05cdd1e56a6db1319aa7c7c6ed3ef41dad9624a54af90cde2f37de73aafafc9b577104f85d01cbe9124655179c081e951a893087ff92177ece02092787eb417235d746e7f3fa7404b06ca189dd834ea18f061a97c326c15d40231c81c900e8b2942c1d56420edccbcf49932f89498d38bb4874f6b1358ac75a3499c0d88df8bd23a2f7e1ab6bbabd539ea5b4cb13aa0f0e51dc95031f146f889b531c660e3667689021f91d58ca4b2ae399a92fde2e97208a03cb7738d19b5fa1bfa1f4b0460a991b84e4f75c1d3c4785a2eeb6d5d5930be1009792c", "9a08a28c2bd6769e9d843843b13fa1e5469f69577eacdeceb6aef15b176e7a5c89055102b03b8adad1001167479247e02cba637df8656cc4e67a2d0be7b93a7373ce697b904db054f9f1252c6bcdf33c68017ab2f43ad83fbe266cf1cfb08332262aa20b068b65c7ad2180d61439dda4177bd13f12eb37c7e4e83b9966c3f880813e3c825c4d31ad97d3c1ceb954d12617de172737cf0f7e746210d7f165a4ee9d01de83bbd76509c4a74df338fdbf583d173b05eb0c426802a2277feafd67cc1f998179b3e89a28ce4ec5f76cb4e322c371e5dee2a4a216b37b5dc1c0e21dcae72d91d0fa957c77d53d6b3a1f1190d6bb5c7cc0637edae9dff831ca8a10ebbd158c464c7b0d23e852fbbb1956334742dc0ac301e9bdbbe63fd7eb1b90b45753e1b5b4d190f36f445f412a59e92dd3e0ec88311042f4da0980b5aedc8dd85a628a8a4872893085354f7feed55ad7030e6af91bd19627f89fe7e9db4036d8b8855ee4ae1e37a3409aac8ac7813d621654d39fcbc096b81ca61a8156a08a4354d2b07e79a2c89a153cc667d7c1a656752a20d7e52ebcd497cf1abeb91d07361f5a660feca8b961051327b1d2908bc1cd8b220e1a0966a3417f7bb483971135143acfa838ba9f444b7ed7bf72994e434ce88cc122a69dc4629f9bcc93558d80577e864d5777e2ea5d6815942c2adfaa662a53f1f8653c698ee50c38c03af7971233", "dc9a8bac51cd6a13bbc485e8c6af6fb9c2bcc38bb9804d13abd1f25fe7c55ae82a932c6e23ca075809a53cda698d7a7fd6a4291ff1964cd6400583de931be226beae92e84c8010bba99473f72ac9e9c7c2ee38e50ff98b26024b2715e4d53b9574592a39aac15da7a07f00e6ae85134c35d83ad5c7184290a54f6253fbfc5a316dda078bbd584c9701ed283a89fbefff0723815aa1b6530182f6fbcf231a557d5766a65e9ad9aa1106d48416ae0c0eda766822d5e9c0d3400b922624516e06e99ef7fc445c44b1602fe25cecb97d29a791958122ef00b3c60e438c07e0c8eb97e563b9fe760db17aaf5aec90b0d62cee32d524c867cd31764310bba54c5c9639453c7386c90ac2d0ce7bceb3b1e3c2d46531e3ba8ed106e1ade22e66f49982b40957ffca360baa32d2e3b9d69b8dbcd766ddbba57441d759b5d22e3fee5afa2674818ad2daa899ec2fcc99729cc9d5b0d7b8cedb523837487fd2778beca987c46aa8356ec83c0abb7ff6dffc741108ec6455ae431f339834a57eee9ed76a8673e661a6642a2955b4f970488d82f2e56329ff9d74d5246f21f19e15e7fbb2ba36a94199905b03bb69d7e0949cdd6f8c4bdde5f5bffc7da7ecea36936b953f4dc66e2ac15b4e74687cb7a743135cd00043ac8221be4266f19c4341acb117ee901fddd3b0b25b11910feb7b0a58935b8f916a00c05fc1b55db3b2abcd1b379fe7a2a0a6a5573661eefc3f4616e375b31817bb01dedb7fe885d829b341097e1686935b5cc2101e265ad743c59f681e5ff46785cbfd280558fcc277ce53e95b3840e6100d622c9c9890c10680ff168cca370f58a00119bdda1143af5b4f13257312e1253efb55696e78a2a277c49f8a9eeab54f65e4767712cac7537a314c188ecee83a7674fa26b2ba33fa788449896cb1ca75b6a2240d0a740567b1863eea75db943a23790caed320c0ec0ec73bbf21f58aacaf646a93372cf2297db4f2669320ed8672ebd942b3837ebefad04b5b36d8c7c68a5864a31fc52b9325956212117e23f20709a7e52745317e69289a6bc2010746eda6766da44e7d709787dda64eab4348fe926da57d4a0e32af17e5da5f80a2cca08ed6281f5f7af5c39404c9afdcb0f4a81d25278a9d805c76b7576740ff02af726afc7c4dc691554325a84f6c88e6cbd046cc6a26032fffa081f3f5a1e6531e3e16532609dbe68fbc3afcf1f04e0510afa0a524aef22fbc99aa346085505d3dd73ea5e7c5a7eab1b65213b0dcb5ab94356c77cc5afb6ed8236ac4a6ddf44c2e5ca8c7e9ceab53b84ea7285b7da79ae2a44fd397e5c39d8a1d0a08da409d059bd6906841f5fe21900cf87df58ba1dd0e58d405096bec20b5bc4011b7c8c8f3b58b840c17efa5b64bd092c3f83db24b697f0e8a173d825b97c2b8cf57197b52803c5a28d6dd33795198ccf3e729f90", .Okay}, + {.Sqr, "-c2d509cd90c158a125f4295e8c8f7187d5f927ce27f375a615bd6567fa422e0b726b48347f9e62e70ccb9b0e86bc9b416b27fc58438e9f38b00ebe724602d380724c002c4fd1057a84bc10efdf03dd909c59944785b6cead2d94df6479d8319cd5581a40c3d36e8647240ac7d20aa8554696a6b32cc8f943dbcc04a2d1d50f1bdff43320c04d56638a6dbf9829425d372d8019ce606bd1d6f0e89a9df7dc8e9bd77e8b3d4f0141b4869e2405606bb0294ed37cf9554952d5fb244ff33ce137ee05dbd9ea1cfaeed00074a35b908e5a811b20177b75382a4947930b7b60926e91fc7348e7eb9b0622d97cb039f0f6390a83d03f2d403bb6f08df5a3ed13665d5960ae3a603db6b71f2283be6fe59196032583a5f05a5b1c64196f38ca44cae0c46668109c3450a61d05a90db58ad3ca53b66930c6f75358d92176e732f0b67bc8d783a8492220be06ceefe0b9a87e19c4c5f34bfced66b150f2594381e8ed963edcc6e8e18a5ab3c62ecc0761df4ac740aeb9ce4f12804aabade4da3a5c49c44d5b1b172ddc93abb48502331150c64a02044930aff625e43f0268c42c55543a9cafb54a482a54e569761d5a1242bdbbe193ce3e30d6dc0e2c6542932b6d5f53e9dbf6709e665bfc479cd189f84e37272036a45ca46148e0abde3af8c2e1ee0ec46f7d86af7485099fecbe04a6e9dcbf84c243ff8dc724d1015422d6fe5214bdfb", "c6455c644c2b10ed37e4dc531f68dd047d4a638f10cf750a83af4c09e60f223e1e6fb7156d9a8bdc29deec191a6809626f4ff4da98a199453a14734926bda701bee06e67e66799c1f829ce7957aa813f454ddaf41322dc3e42b2fbab6730735354e2cfb4cb633157116501114dd533930d0babee30c024b37bf4d8c8f69c0547a47fb77f11eb68470b41bd2cb0ddd6941bef9422a1862a60f0bfcaf0a996c78537aeeff1c7d8b1f5fce0281339aa9ae6eee75783c766c4d32e3b93eb4a805b47b159fddb49d2a237531d46df9ac99449e5ab19a5e2770f39fad85a4f81ad016280542e29a89f3bea9e6b21484f03c50f936f0e1f1a5ae53bf4fbd84a060198c2f3e245dea420ba86931782aad15aa58cb57f82026073bf80e83cabe8a5eb953be51d22ca0fe0367069a2f27d046f08f27c034519f071be976e997168915755cf6e6154f10bcce39293df4d6f4301ebf1814bc52543a726b646f5e5691433eb089186c4b0367732b903dd5d01480ba7067c1c36295ec166934b667aff92fa2e4727732bf2388739317169b5564e57a950a134c572c034c41264153200334aae58fa2fde8e80c0f846540deb95d7a060eb83b0bf0a4432a3aa65731ecbe2478ffeca4cb5360efea4d93e6356abf52999b07ba714b34966896db0237beb1fb44ef574f0fba0a6f25ad2f67fdb317921c555dfc63d2153da227cdd0f36177db9d9bc", "94479424dfd80550796c937e24af4e4d5dede7ee8901ab0c21bb41e75b2b0ab3be179e24c2582afcd85eda6b0109cda312b3db4984ee994f342c107e9b0ffa75df430b833c167865b68f78081024909da0064a72a34f979a33194fbceec9e4f2a35b7447a7d128ca43fbb77670671fc0bef4a517f77ab1e766cf3377aa5b4fe6254762e53114d45fce7d1eeda61d384029ba529122eceb1f32677684c5bca94568ad8a3c12d073f7145fec04f1697423a0d94faca1c4c80d0af7effc3d7e2e38512ea655d677e0ccda3f058c55efa8f6d2e2a42ff574441850708f1387d578eee14a9eb46d15b080d1dc5f0aaf998d94fc54e02820a4582d2234892ce7e95ff7b859ab4629d69312d63fd1bdce52fb3871165efda667da8816ffa5879c8c71c98a99578ce424f1f58d20d403d767cb80b62e0f3e155cfb895c4a209e6ab41817413f98059d559e8f37f8d7f6fab3862c575a7aab9afeed3398bd6df03cfc3f559e8123c5d99b73e8cc382de89ccffbab33014ed3ee29abd1dc5fc4ccc4fcf84e83116a23c5a7c31bd4ea5da8c7d1ba15b087ea736ba08e4da90d334b7f00351cca701b804b559a89cf3a7ab38a921503fce203980bee9d6a896ab6d80c3f6a62653f11c283c1895d9a684bcc8570ce88f4f401315352cb1530b9667a2d015ed47a5b6e80a5b2c58a50b09aed4ebb77444871396ba3ffdf87284cc88ad6f3006c81c895d67e43ed39f126212bef856eb2739f4fc98985faffef95459f96c77a73a823a0b69e6ed04c20861d56dfadd3a774f4f9a6e5d5057804719d7b9a8e7add8d6296b9d300ab1eacd05c6f8e75b23c2af58fdf047bb35b8fb3b232d2eda656227467dcbbe8ca5b5f313c83100456a5754e0cedf402fbf0f4083d5efb643b41077c53b0e00ac2749ba5a04a37775afd0e5251d4d88f263d76cf2facd3aa4ccba9471009168e43bf38d0b0fff66316a6eae860db72cf163458ce830bfb06f1daad328104c224a348f92f4549fe6eeebd061c194909734259e7944f372f151217b0d0095053cc91007af134d87c9e6815c14d0d83884099c5531fa1b84e15f6e7129f79cfeaa8da052f480730bfa34e48938c330aead99d77a70ce18e0f70dde6cbc13880c98c18dc32469722338626dc4ea07021a3eee6800fe31f5cc6ab6839eadaf2c4c5618cc6ee7ab018484229bb155943af86b13a4fe695d73564af4f225de759c20697bd5310aa97734833f368bd07979931bfed338af09e479b175c000c494a335c2a9eaa20e1aed6c7a51d2696374f7ff04fdcbeb8984947a9bf8912a8ce8e5618fc3aefd2e8df1e78dff904ad442439a0a45732204d13c8a6083db399771cf7f7cda7986c4da5f578afc8d440dcac47c24565e5b80d68d0f26bc677c1d547851f19d4b0d4be3f229e4f56be1cd07786e0eeea06d7c5ed7708349419", .Okay}, + {.Sqr, "96ad2fdab5e5e8422469bd7bb57140116f34ab9e5da9a2ea3c446d916da5c0401fcd427b1f5f844034d42d5878672bbec1095bebf7c4706deaa4546c90907fb51efde00dfec8277212f988d58335505ea0d1a1c469bacdaf63e309100dec3fc6a9a972db5eb4fd6503226c9016f80574216edb1fe0fdd81ddb142df0e0c266ce8870d968dd20b286c14e783e85aee9d013771561454b25228e4430deaed0902af7aa3d2d4bde1321bfec6a19a3161d6fbad167990ee468a89ba508d5bae35928ca3083fa38f5ef18f8b223c4e01d80ce906beb7d25b9d49fb1ce4f9553b7cad147dfb792b06bd8fc4adc1d954ea1a5f674924fee58aa52050ac28f62508090497979ad65b9f2c9926d36164bd3f21c92b4f3e15cd36f3156f9690161e9f1357e5338ec4397a96a0ea043d6a21343839b4fbafa0ac11e65311cb47afe3f687a0b0b89524872eeb8c55c417b8e4c244131fd6eed00817131d177d4d7486ff77550a0839ac8423233c33a4aee80efc03604a54ededc33bb0e2b6e3d740fe1aad82df3c713bd6fc59e64144f4e8abeb5739b9f2e463e2c1ae289269e6e09f7ddbe63e1cdcb1f3f6e06d62dee557bc26cc1a6bd763b6b6a3dd37f67d7ad913f47f02092331623394b9ab0b8330aa78b4b9266121618d8f8ca309dd60465f97dba54fde20c119b05e1c2332f828de903ac282865dced4d48ab5be2a3513b34a96d8d6a", "2cc3d5ecc9b115b5e105162f49fad932d8440edcb96fba15caad718641ee784df34385dbcff4b09ff0c1d73b956502b74ab3eede8cdfa8b498f96f50b06f9e413f4eede626c62d1f0883f8922fb159396e4460126c174a3622a4310f512eb2535fb1813613082fada15cf78ac25f5eb28a42b37e046839031e647a52bfa54a47624dfde0e6cd459ce5f5de39c13ec2208f590c5e88e8baef819fac4da96474cc256719f0e18c3b6409174bbc0f47aa87c97ae2f9a0807c15b3bde206aa2efa9cfdd5e1a2354713cef9eaeeba93b119c463c0910636caa90cba9a2efb44132d63ce417b516305f831dea40e1e5f988696f64982bd770821bc91d23cc9220d3e32c34b0ce5b897e7cb8fb6c9d994d077fc7d3ee4140d24d01c7128fe22859d43c0e908399a28b29ae9070837ec5050693c23ff8742af431c18d4e4741018a4f5534c60f9dcb76c42fb273c1cac22318497af7be8a06ca762cee7b93e36ba2b209df2888f27c4ab18e0150253f08e3e47671ea78ca9075fe69d67b64eb2ca44c38b54b15f0f035c6c466fd048d89c7d531e47d5fcb748064be0f45f6786baeb347f58b921836af91b95b788d69234763718ff26de154a57c051b56022906c1d217926d0da13ac0b69f56c727f9dedb8047cfcbde5bbd224de1aa73b435ced9cd917c6dfe2915ef556a1a6090301e5b287b24c4a0e9f2c86de68ebc05f127ba33ec0", "58af693e03b54e8e2427e3e2ca08b3aa015221a8263e7a5ecf88c65af5ce400d19f37b02cb0eaeca159fb81d4de50e96acc719c81c3a7582edab899fd6cceedc6effa6a156e865047f0723d05abce60736b741be1ed266fdd8b63d54451c23b396e30a27d6e8f8e9a49eeb4789bce2882fe252f7ec3eec5a392e0226431d9070c0a84f7f5a3d645901189d0de69348dd73b4f98a28cf1c454df03f9c0b17298ba9eb2dc429fbf703dd234f21870e82dd43608bdeb76f1c76a683bff7e156fe2c6ff54fd6b688038a5d5193e5facbf279f22f126ced674b516b358e1fe4b548b271068033c67a2c5d7e692f5622471d4edfd3e599b77fc27b1bfc87b1cd912e47b2ee2eb4270cdb5bd88a5056ca3aa0944b529e6ab7304d74a118440c0f001ab57622bba719d5b02c8a22de3d46c85f64740ea3948121abc56d0baba0405b6eb7795bc4eca5cdb7afa2082398aacd81f6ae2c37be344ffca4833b6f4300fec15a0b44c0f58145abb06252ab992a62ae901a3afa489c7fc54c2fadabe013534724081550fd950f524ac05bf22659a617d723ce78d0b18c82c480d6f2e6cda6c0b451303eeab51d178f5a2b0bb328bdcc09b39535eb0a4189083c078fc412ef96eaa07b055dce304f28c70f0ff3d4b4a4513d4a4898111f1efb97041fc33ad3a7c462f4f8cf4022cdff368f15c8cf65d6974e434561c8375646e6cde8bffecbde23c5f181cd3b5dee6c80c743d60d5fa3002249354e75f3f6d2480a78ed4c357a13241fa7137bc9bff3a4ca1097a1b025b0dcf3906b4995698bab3a4f21754862e529694e3a051c0f7398241d2ae7c82cf43e04739587a5cc3b804e70eedbbc136ed45f79825ec59878b40f21318a5a716ae39d827cdd32ef131dd52a3f795898c5e164aadfa034564c55a8737f988ff35a91b8efe0e2ff56eddadd4431ce4dd6e28c62656042ceda7521a5a193cbccf51049c2258d6b22cd0104271eec0676c446b22b6f13494a16fcc931557fa263b1eeeee72c5e7c31fd919250c8cc69f83581d53fb36508b1a821c2f4181692e62e7737d18f7b6bce0cdd63700f1cfed84542b4e55ec139e6225e675be51a6f7986f433e25c7e6b3653bf797f3d6e114bb1ab51888cd20f19818c53ea72358ed8ab5bcdf1d95b17182c75b402a25d6f38fef751df08158fe6c918c77175f1b0fd2279d423702f8430aae878c1f75db42bb4bbc73f04de884d34584f9c912d1291881b61146e8c976410b8feaa2a64b351472153e792b8de4924f8bb0fa49eb0ab97a5eed9ef723f328b8c389baef399de713f1b0d8394f78f8e31deb492bd06f9a7fb2ef8496f10a765407d7f35a9dcf2aaf5fb6c8c4d519da20b43defbdd8aa7130daf9167c403debc5d4d3162c505b1f7d1bf3d7c1b3fde493bafb7ec55052cdef6b149d2452859157e3ce622a7ae61efe4", .Okay}, + {.Sqr, "-c49c1fa2fd441ed4af51b578154dff9c54f0592359630aa8daa06d8c44e7e97e28ec7536776a62aaeed1e698a1b9eb4a88ba183f61e9be646b6f8e40e6ecea6ab771616d032f8b59538c3011877f0c8632693f8153420a50ea35c211bff676d2b644c747b129df321ba7f04a3792cc71950a0e51fc6bcae5197a2524176dab2178f2d5f020646b3f1109060ba352558be7f8d90c1e700a3262ded7af9e9839419bc30bb6cf2225038c4c7c31a9545f12617309f4c6f9cdf01f42fa8d6e71d3382f2752440679fdaae69113fbf9e9a0f0086c3b5b38e5cac364e4f028fe0f1147e8216b63de304ec810aa00258e6460ed4a6720ab5ddee30c8726dda07a877bb07ad97f033d0790fbed3958f5669939259b4c14494e905cd9ca5d45e8ee99e1246d26252dc2c5bb2754488824cde6838eae3946c9c3fbaf3948b7b6231277b0b4a9bb3d40e4aaf8cc953c090f19c8e4a1051479326a35b306fa4078acc5654f7e8fd39be970390b08c55e4463df75ceeaf29006995eec1f1771c2fc82f6328c039204e33c679a47e32533b93b69ecf3fc9b81082caed3db554e3a9c7c94cf5fe6f6076de686e4540ccce4a092bea974eb2a288977786dd3af747424df8987ee3be17d6a4ca32193a59c8be0c6f67f2b1f1eced7c8f139be7c5911cf7259650e27fda13ae87a1f5f1e1a07c0e5dad3f2c86c09ce82cf560a76baa0db656525e9d7", "cec63dd1b4c413a59e1337f9bcdd7221f4cb647940627acd82b8f959328c12f502bdb464c5cf37a86b5a6b45bdf9598a6d36261dc44963913511057c5814eb5ad91cd89e802d31f309aabe45dcabbc3679b4cddd1960e81f1644ab1ede7ae3c065d8332c67e01ecb8a5e4ea0a094b0ad93c37206676ba6dec09aa0ef58cb7c32ed7b5e8a99df1b77254689f1b4c3c6c9ca499df2fd6ff969582d99b0d734fb396df0daaf609d0dfcf2edbe67a0c1d57ac2c65b0fd84eb27fcf6f67f8c0fd72b5963f46310994ab1cb27df4971528c5d393ecc092809676d22fc31a44c144088ea922a557ec6e59d4f0857ca6d1f55ea5edc57d415872483d4712fb5ee7c0440968496f11e9dfa94e51a6ba2b11b8f9e61ce50aa1b747124df96f92d4f848205139b5f7a806ea6cf2c9281fc996efcc8ef10e9be115bcc41c1cc47ac49b51831287dd71b238f11a3675cfa0aee67c51330f9dfdd3ab2c04462200a2eaeeed5d8bfa3d18ab362bf0a56f3aaac13bcf8ac84a8975ea8219e74cf830e00ef3d59c8075d76ab7596bc50e3d9421886fd472e8348e95275c34e9ec9acbc30d479ace492a712beb1e841b11990ef96cfc3f7b48d0311ca3ff127fd91b614424380599410de1f5997000511b61f66f6a8cf2b68a377500d777f1af21c5fc27b214981c20fc094365a366cfdd0389423eee72880a11f2561c8ab6b3d174acb0faf3ac8d94", "96ff6fa8265ddb5743e908297f91557c830bec9359854d66aa5299702b8f0dbb98e177d0ef4684e8fd3bd582cc3a39899a51dffaa9283a5b0aa26baa8b11afc7e9cfef7ffb66e903ca24d9638d8fcca408fd522c89864331d06938a93e2353e13cee08846b3d3423300443f5f65acdb97769d6cad5cf2bba407d0fa936e6cdbd417317745740f1b75cbdaba2f991db5c24bebe9e38da5d1112090c7cfacb023e6cdf49b17078b12704d717f9ea15f24f5cbffc678564ab05c1321931b9d6893ddfe46a1da7d3aa52562836e60d7d25ff693e50238011990f5c8922dc4223993e6e9339ec67c544272aa83168bd3406b65ea6674124d6f11c99e88e3849fb124b2201af982cd968657f02f737523eb20e9a2c8e66ee0ade103a528284941a0901ba6c6897b47586d91a2bad42761d12971039fdfd648c3bb3b92a94c12f31965328d93f7589359eb2721f39fb942af0fa7f2a9bed488dc39e56ade79802c2d92860ad1a90babd16586dd441f6aba142c3073dfd8a9cb7f56761fc15824fc9b7cf97bee57d81d3bddf91452e0bc3d67861190f8846a335fd9d13f1375ab788209c53f671072271a50c4a51d9f5eadeacb63daf7cff8790676ce06b91c4b16b4e667ec3fa8467c892d400b6f214ad8cd7de0826fbc9b5a5626e77f810493b840b221eabcf1eb7757c67ca99dc188c260c62acb1d176427336d8639f88308b9fc505c5878baba7f5b0edb156e0378f183648a3478a274a59c0cd27cf265a461f545c9172d746859dad4c18424459c9344110f88f6ea514ac9d0226b175704b300ef97e13a859a5584bf6357607777d39d57bb4a01e1b09f2ed53f550d3c68140d19704d7f39040d13caafee5850e175828d74d64c9e1032f4d14130e11e8c2751f3bebedbd24003c3a5c73f25609b8d8631fec16d5c822f03fa5649c38a0690cb773bbc82ebae160ce4046742ed8fb0252f337d118ed80af744a0e19e22f29901c9cb9b58522ce62419b9c304b3e040a708c53661ae4113ea57b5847aa7fa6c895c2c3435541db01032b29529914c3f772c8ddb06291b6ddb7d6496b2a2eba6fe2992d51900f5d9609a6ef180caf7fc90d7c34b303d7f0f3dc0fcae73e226f365acdd2e199d011c421758f4cfa1e4b980eec50694a65407c26f7f8e5fc6b2dc97daba7fcb0e1e734ee8db44b52c5e7465ab092a49f2625652830c593806d2d69a8272db2f13e2b4ca383c87971064e1926d16eb8632d7778e7aeede37475501aa060b371d5dca3e4f9fc090f505a69cfe90262191497e5fe273ae48041e707431acedf7b015507253826e2a326005199c7d93de49c368af6584526ceb910939a0060f64ed224823966e62e2645f3a21fca861ed71fce61b253b112edc71df6fc7053ecbcd6f5cdfe99aafbdb7a45ceb3fc321f251941556c889c8eb74dc713bf1291", .Okay}, + {.Sqr, "-6d7e95ae4c449fe6c58c8745782cd4873e73163f11579343d87c94f6c6cc176d595bfa60f411f96beef8513799104b04db4758042080bea17cb2104c012b3840e6551a2619cc60ed2b8b01e9212b92071fe9e462eabe211e07dc4b92f75dab51578a91680ca0a950fa7d4f302a010984af5fc294148c59bf4c3789e4460b8309741c1adec6bc840b184c64218aaacecdaeb954eba4c08533380ece31a929dd104d9b645d3abb5f5b1a3445589a9f04cb53282f973a6bfb2cb6af4f7b445fe69006356086def1969940e8ccdd08f365963283cb5d6065061057d7b46cbb09b51ce22dc2fe0d316a05bb4ab499c3bccb7d4b132c45eaf1ef0262e759c8e6f365fceb06ab75d54e72bd7f19dc24f3ced5d20aa0d8305c20f646dceb8b7d85a11c3737c17ef8b55adede20713633d23da6615d9f7389696140bab7454dc6fc78b4c2ec4fd7b715672cdf5f96dad591cb20a536223afdf7cc04a5537db2a14a044c957c2693de6d3e93c0e13b9868e6eca52208276d14620efdc01412bc6c230f467ebbac04ab132a444c56ff66550b0d87641e1002c175933c8b3d40c9ce8a8eac97b435c39200cd7bf03ac7957f6a28edcefbb8aae6429621f0434a8e4a02aa1059cd576096a8ed8ef927a988906ebfb8d8ecce58fde5da197433e84702f7cc159cd44ae6597469e7c807411f0eecce05bc2fba60b8c3f7452adfa59153eabaef53", "dec4cfeef98b7edd1580216b1471bf27f0ff2c99df840b23c061193e44a6c6f08931a9cd4c6983e82e4853d9c51c461f2445b7a630528e249534fb80b5d6fff80222908a732c075129cc743bf973a44aabca896fb8e9ab9105c2cdbec098b9ed05eaa61f6cc8ac3770223775744c7e15f8269f9b200ab3173566fa476fed08c62d014f0f5e2d1e4a02fa3dd6ddd078e121353ba2fe4263fa259e30ced26aa56d7145f18f6b2a393ca41a778880d60f8f0c8b94de191d82c80136206e978152607b43eaff7deee5f57cf4f5404e1532a257f65c9947b840e1b4980319f2f83c8639dae987b68de009c9a5a2601a5a6567870fab50622fb539aafcd61bf195376745b0038b502b9aa0dca2e8ba3240841eb9a4512a0c0d329b1b3d722e27be711fb02fc46eb68d849e8c015f88c0c47c79900bdd773cbba2cbc9ea5cd7f64971ab93538714fdd0e722c54e817ca97262d6eac3af551bc304b3a81bf8b32b49a2045e7e1c365237203f21363baad79e970ecc803e70c90a2c79b775190bf103ca5a76780d47ba3ec201c1a7db5f74be0232807a45bbedc2a2c1ae155341772700b9a850590f2e204681bd08ad8889ac19da4c2f352c0162a8c175d7d7e7549e6416ffa3b9cca374cad3be4bdbb273d64e34b94c842ac4ba4c7ac2f61ff5f0fc184eea7378eb78a721d6d3e4552e11fd08adac04ec4d916b4bfb1483c9156f4a904e", "2ed50a0e1c09df2b9188f286ccfc15d529e5383873177a32949c9487887d0534ebcbd1779c6eb61cddd08e86f5c8cae7186ab400344b60da8faddfbd113d112e99a356725bd260a6f3e395035de6dcab7b6cba0495ff858269f453bc6e7fad0fdcaea9afb72cba6c2ddf47c4a11753a69d0a8d9755b6dd600d78460dad5a8dcc73598e8b2383d3551cb767bcbeb9a7acca4a48fc584089dd1924590a5627245026d340fe1302f4f0cd2568a572aaeacb0d67c052d82fef5b5b80aba0a794a00fa16d533176333001156f2e5fc634f6996625e93dad3bb53e935319f2489a967bbf3a5bdcc60ead374cb8fb9e8f2db0770e94a0f5e2c63b6ad215fddf08e3ce7b4116aa8008910923b3b3591d71940b2afdf9819e7d34c81590717c7a19b4aa690aaa77fee039ff70c20eac1cd107d01f0e81c66464bf46b2d8ad625536eb09ffc494c3cb8fb16ce8bd36b4372b9484184415ff8b01eddc3e8989bd61c3d3505fe1d95d38ca43e314ec801db0ae4195f74b5dbfddeeccd5ec376e7204943ca16d221c8e6d1d208ba0c07907e4e7677222d3ecdcd19e903cbfaae6dd50ea6950ad78d8f0fcbb4d1b0a22e21244af7129eb5043e6a35cef24a8e95796e40936b1dac685877c274c52b8d02af96958a760020d483ff1fa9947b83aeeb36c57582dc6fdd2add3ae3fa54e063db240dea28895b253aaa16e155812c23758cfa1f59ba3d31a31209470af3839bdd1b509cc3be282cd81729a4ddb47c2693f70fc296cf5cecba67fb8c55b8fd04a426d6e35ca0e98c7976d381a4aba143a1107056fc33e89149d7a26868f119e366b8cbfe026e08cc799bd1cd932a947939fb7cc062292e6932ee0cb0b08f55b8a237f40afb50d9688831899f319b4444e274e945b2b3b1b31c3e7bfc0a6fd12ec18a584cc5d37b220b8e9ecbded498ad91eae4c196160087d4ea016e9c51db67518cb922426e4ca7e6974742e65d624994959c0ea3c9be2533aa6eac6ddd4fc6756dec2ce25a7ad00983cb9ee7371a30ea0ebed4a9ec38c37f6b3b56e5c81c97b2006400a74be351261e8960b068d555eba958bae1d5f5d7ece8b02298b0a8a4ee6647ec41a65e91ebf80289e98eec7ee0717e4874d13798db413e04288891ccd72b1f456c2a363b605234406b33c44d40a96d793e8f393d430389c15eaa64b9278ba5cf2b590782629dc36afb9b37723d7594fde6ab6d7704828fb746edd85e7c65ccacf6acd97acbb8f57911134f3548ab4714f35a58accb4bbebadaad23b57fa6020fff26e7b3913513946350b77149612a723a239530ed78c7f750f4aaa1d6a1096e7cf8ec5c5f682450be51e68a2c9b94f1c3ef493fe8cee934bda0fe88ec3cfdb181b8f25d7bbcc8de5f8249fecb040294b195cf96b2144ff0c7ce291016f21c6c044bb8c66cef8ea21b290ea8b7bd6605814e9", .Okay}, + {.Sqr, "-611975da87adb6282d1e7ee542a8d565e2c01bd4a0afc322dde9c62c0ce1d07ae6535c051cab3a9e37b2f2ac6eddbc419fb0b534822e1649c2c9915deafd59969a582efdb6d75b0de94545960b8268559e3538f31f9bb8406bcb063892a6651c5cd02a55902493029b0494f92e359cc8e531256c3d98f38b901166eb66a99ee54374771a863e69272dfc500c131c2c740d8851bc50616ae368a698147d6bc2d7f00de5d1457e9c2f089dfa782fa8d0fd727df51aa7385501cf6f59f0c4e25073d6705121458ff18c51a5b438fffe53755278c0bca5b388b70cfc0151bce32a438f00a7604e591dd3f5e4b061836fe2d8cf88efc9f766410682fb9ec66144a227ed366ddb0cb36a182aebcf9a30aa8c1e92a5820327c8385a6c16ab924cdd3d12272833efabb742fac64b834047984bf892eddff7acd97c3537bd197ba9c5fdc0d2a4d0b1b9b02a2764a89632099f8985059f261956ff0edfad284d2c88b45fb7e355bbe6119e9e2a588d9f471c2c618b1b883c684e272198ee48a0b6b12cb89c36b5652ac7a63055be0588f9a0d14909432c0e9a36dd5d2666e0a3915566e74f2155e5fa632ed1ef7ef85225f065a0539951b18593db71e12d56b5ca5dc3ccca0c275ade3a5d5a09111880e033124a40575e3d839d7e355562af9022e05ff5089812047e95c9210231ce583831e52ec65677071828b708188a49a1277c7dacc9", "8838d7ecee54c4314d035f5f63f729f57169b7789bf4def093a6c5cd54709d2e278a107cb694ddcb8206adb163d3d17cb9e34210adaf53572c75d186b03dd629bb0eb8c22834f785c789d4cad2066b14e444c2ea9ccea6ec1bd93ceb1a98bc062afd1e7012e2b172b354a95b50abd0a4fa9e94daf035dc0b908d83d0ee615219fdba8c0fd6dcafa385b408f8e43da208c7c27db34f80383c43c8ee27267f5b07976d05aa0bdeddb209f3697997052cb908e441b8a3f64fc92ada0c792f161b456b854d0dce87a9076c9b5a149ded0d70c17776d6a613d98579324139e51d49b83ada8da44613838cde71b85ee20ebd752eea5f24767c9b906874a413838a672632c7b0464be7ac3933007a806c8c0c8fb66ba9e3c4a15cd53fda147b98dc4b20584a06b7f9fa7dcd9c3278ce1738edbee212fff51c7e0895c2f9f4ee6129f2be005c9516e2e78b33a2600d0cab5d47fb368ca5ce406426880b84a24a1d472f14df3a5bd5ab974717faa61a3cf15de47a552b0f0b0dec98dc03ee78e61bca2ec09a957bce5cfc5b437238d8b7f79681552a7de92357f691648a457ec508660f59ba06d1ca22106957a04590102e99d4f669122d90c5642e4fbb3eab4caf51a6051558fc85f131ddd8a26131069dbfa2d1e93216319acba1f506a6d06615ae10d81118b800b7e01d9236b15c45c98d9616ac0344da3666008473cc3253e57d3a29", "24d44dd7d5c19e882a4d8dc750b8ef978a69f953b5086dfd1a388a05b9286109490c66166e45e0952948ed1d498213494b4d051e3a2813072f0193da990297c6d1e3a526fb9e9e7a9ad44f0ea26abfb846401ffad4848abccf90fd4f3e9d3e98f19dc0d6c4e1d6890ea7d633e14f6955e8c768e54d10ab08c13e928a371cf4583603993fdebbf00b8baff6003c17743f2d9aa68179f5b916afe2684ed225d7a68f3a5b7eeea001369b0c2ec7603e9ce9036132eb9d9763e68a36d47bee975e613bfb1300a796ebea7dfcc4ac65a7f888a6f447c165f91f6c9de588ef46676d42f271aabca3127583ab390982bdea7d12f82951ea52a767569e2f637ceeb80060bbc28f238a5051288772f14a4bab7cbfff1757ea30a1eef5ac445ae03cb46c8c9478728a567cd023bb7312adab2740c98a739eb97cabbca93ff24ada73fcdb14e8682ee7108b76e7605506d7e074b4901247a551e9d6a976adc41d694366ea98cc1b9ce4cfce0595be401e7925124b5b70f16610236b156ff159840b5d6645424d2361f29ba8a9d64034c86893a2b485bb47d5af77dd85da51c3bbf8df17c6d09872efa27266544c9b4d34ecd92d373e74e4bf6eae016688a2ba4a4d6bf60f20034fdbc3ba8617dd310195bc871f4920652ef7392ceb65f6edb356a45b50aed07b3ffba0fafebe0e9ada99ed1e357ac5a4a39ba410b16af09fbaba0fa3ebd26f9e784e321dc28f1d123e3bd6dd7897ac53222665e6b17ea231641bb987ae48fd1707fdb5a0fbc9a069a57ee4abc80e1cc0fd22af9db5db850144c824f87aa73d67c41982b286b6851b91ee12b697f08af5760362a7631834870aa0ae2a67b3eae031fb22a7dfd001e4a70c07811055ac506a3077d88604cee0d7705c6adde0582b2fff3b0664dd67d4f95e782e891e9f2f182bfdb537b023f85da55afc0aebcb26b800502853b7c6a554e47fc8d0a35f5b343902be846e9db56f9088406cacd09725aabe6c6a86a501923198d1ddb0c1dbb3607e03af9466b6b507e8aafb902036d36174883a90e1b2c48d529af1f0770c7e0ebe3205f26c50918d5e62adeb4a291fe10bc91788d22474670860639c6ce06e33d217c843bf1f5ff6b6014db0bc58e4ae92b03040b61fc86748473299d608109c1aa1315f00940329f0b8e894a17a6f211e1994e55af3d57bb8a6ec931ee914abc508dd72d5db3ed88c939827b1ffc1fa5c328d4a0b5c2a666f3e987acd0d6cd989b6beea6d1e42727a42b15477c3a7b61c785728f7b625c055172753f2bac026d15d9079f30295acd3d19d1d6375cba94b942e951392ab89edab87b704aa5b90f8c6a61d2c2df0521bb0807813c40f5f72bde62e67aa2fa6a2aa50cb35e4ba79fd9cfc4f5ede5c07485f04e60e47c0c1b7b53eb9976054b1065ba052af75d0cb76e9ea24527ccb7452e8e8b5d1", .Okay}, + {.Sqr, "-67b4228a5cab5a44c37139af8039b21a704c5001044e5c5b479783c03e42c1310e8f1ced943085ffa6186127fe0e35013f8a72502e872d0832fb563bb7c0ce55cd7781f0a4ec3cc75cbcce4da35b0df4666f29e3b45337c379890fe49bbb70f5c604103cb2f210674971c42aa2041dc77f6178f2ebf23da2e73552f2938ba15fec8c0ac70e67c522858bd9a722627bf00327cde601c36a322bc0a6e168a5824479edac356c1a901a3cd842ffa822e7aaffb068b2a180a05d6b69385b4006019214e6e7df6cb2a09cfb3620ccdc95459ff470d2de745ad51060cac8a476d416af6e3661bcc5525cdf7b3af83abcca2c78743131693680db755cfc1e0693291223009c1ad153760a3c9300c40e0df2ba18896427d7b9998a10ffd5e40e508d99627ce1e6ed04cc93aae89fa813342391cb31907d1a5118421f375d89231a345377a22fc827905db34c58b156eab3ea268ecdfada72a3bc772b24b2a2aa2e937bd0c8a8215ddd79a4225ac4648517b6f56884d204341761af84409d25e2701edc03f31c5651756b47ea23d15a20fc7c7fdb210ec6ff8a61e7f82d3176f52b6cbfe6a3d473a7c12f9b0e210dee1c82a04293922c4d4e01d106cd2687ca331ad367939b5327cb72b93e9de8394fd6b6bfc5b427850e04718268815a1238fb903b4e055b6c09395b5be1e652fd6cdfb5a15c923a762abec134499f54b9e57b5c44b0d3", "dbcc6ac5b9771dc9eee7b1d47eb2fdbf16137beecae6ef5ffd715627105a3562b9caae0216e726d9729b4142d3dfca5c17bc8b44e7d3fc9648ea98f7482b15ae531fbf17e8121ee76e99236246da82353ab9c7e587f0eda3af504a04c2eeb4828512e83d1acb92ad2c12c81775ada251a752c644a156da48f112c56a8b0a2b8e3419501eb8265bb61f8294dd5d01afd1c331271167ccf640e75453ba13acdf0ef321bf9f2842259282a0321c617d09a473b54eac2db3ec037cc015d9c6a8cd30c8c7132958d1204fea19d659854a79296e5b0116135fe27d09e16ca96cc70c3b901e4042cb9861dabf525931929901270278f9dd68daf9f9e28f6f62ea6ae1b04a3f421822e33b5fc83473599da600dcac705ac609a9f5913a34dbdab748da9fc715749832a45d62dd1c7afb3233ca5733f3fa3b834e8a2a2b2a3ce5479105d374c2c8f3b324d83421c0bae164ddeddf3e5c7c233b8a1f65ad1033777cc65c4d71d74c5bbe0bd9af7f92ddcac23f1fd056cbbf7111f2609c826265813179de4e06725e9dcc0860a3951444eaf9a047b34434d94e57ae8a504d49b25ce77ee213f0d3424efad01cfec736d49aacc8d1515bd10f1b20fbc6ac5bfb1d4f89e1e6ff5970d45fad50170a10adaaeedd0f97e9e3aa6fad64e1c3b9c1e2ccb3a951919a316108467dbbff959698762a9bc826e4b214928748313cb308bce304c63b224b", "2a02728bedcd3effd43b2544458a74568798de77a19c6ee379121fa8b4284723e761049434f86b01953ba7d697aa3a6c8e42797a32c5b79897bab169eaf732deb3fa5ec9cd5e17f0645595d33ad8ca99312e0ee6ccd4c26280ea99c66c8c55a3b7116d2fb9f7950b68aa7413ff2e2fb6dc0bcba0d17b68569099c1f499a015ce4d8e8945d2aaeb2e59ecdb6a63562e5d5b7b4d8ea9e59837d02871c9e48f9a160bef9549e9cdf61d489acaa5dd14b7f532dae4b7ee976134c79de6ef2bfda4de402daece9389e38a36450dd612179c352d78b6dbb87b7a9e85d0eb427a8b197a98a944172a9337ef38c9ae05094e6bd2fb0930f79e3cd33a81207b62a59ddd90ce9ea722a14070192a9b0c62b666bdbe6c96e3e266997847d0ec05cf55c0517e5c3c8dc7c407d65cce42788c9c2ba5d3f71adcc60e155192d974d5c139a79087e4abd729845855ab08344ac2f0b970d0bbd083d0d087568ae072916196fbb89cc7ad17f466ec5d50337a95dd710c8a8ff59b688fa601021c348fb1ba2b295b132e07cbdc79d19b8eee6bb1bb444facf4a0d0091d2533a24ec34b00b3a7f74318e03c19616a76e01508f68e188888802341d78db8c04e1b951c96b0ff7d54d66acf72c5a6ef2fb6786d57ddd81b67954a7298c7ca35bb3bbc943ce23535c4594303dce46d405fbea236da4583fbc335a6416d807fc15982902613026106577848d77d225aa8f74f2adbe0a02e009c895013e1bdd842703e525140fe7ad3176a9b3414cc85450f09effba6980ca6f5c79d1081059b82123782ce776ca2bbb807728bcfdbbfe208fa62caff6dcae4c53f6eb173b20af2874cfa8026e5c5e3a11602e7f7465450df49f6904626c3308bdf4841a828849135e4a5687b610706e41f2f8f47ec6bf9a450b34754276bad230aa534593c9a5db48e5694609a9a0f9ab45f35e880d62af15cf7765e0722e503f5e71221d5a86ac1ed184a49896920f33b49d729347cbd5ccb3ef34fdf5e045cb4bf3da8bb1b582d71ff973a10b83ec3d52874bb6c60645d4b72815c822acc82e36da975a7f902ab86ba0f92769ca9a50c406d77bcdd9bad46c55db6b691411f4752d584dbe0382028b116a3b3ccd61c750c145dcd631fc5cf3a246af2fa6f8720299fd9be2d4cc8928ee978652a399d45af811aa3feb6076fcc3b0b327a7f83ff69c06e0e651bf53ddb775d0335d332518d8af9cba2ebd51f533202e4d809a2c335b7cf3b337b3817079d545d90f016ce467483f0c03cac7262674f8b457f7d139cd2c4c100e9a28d17f98da34e5ef6efb18776b557223038ab3d8a3462bc395b88706b73b2fed5304d8815d134ff038bd8efc15534ce210de33602b2f5dd608758f913d6973af88681f7a4c3d5bffca65a762f081d0fffc7034d657c6bd7439e87b992b32c347259f0b892da48123acde9", .Okay}, + {.Sqr, "-ecef211cc6d4098c7b41924f3a0cd575d6938813fb024fa492933fbef812400ea065d9bdba5d38ff8cfe68fc5ff2745bbacfee22c60ebbffb8b706cbf42fc31f8e282f24968b3c5a6e784edc087c1f94d23e1247286e87c620bfc2bf2560edd9248d7c39b28931575ce4609421c5a0b9240f80355630221428ae1f918d0ae74d9747c3262e0a17c10bbb9c830b6f9b5870201c2b76c2e6103963030476b9118caf22664856b4f1b809f9da64011b0c96c97b28c399fd30697c3edf3bf42b3837212df539ad260186cbea2035514eed17ce815c4b543e5487c169dbaaeacd34bd996d95dac8473677bc5a66144757b8ca598628a9f3813d76ac0fd4aef744980eee910e924c1affa577907ac6032a91be6f517d381743f0b572ca3cb5df904db860f58755678b4e8a010061e5bb6a916356d724e59363439ea1dfab5ac7b4e12da0a25b028efda850d91a15266c35949526d2ee2d9dbb1c79caab85ba6231dbd2c8bb9c90cad07631f58b7c2787f213274dea9faa8cf3fba8b424936b9cd9fb43b699e01abf7f283751bf02b654fd39c7f04cac23e904201d6618d9118846d6c91829e1ee0788c913256fe616484204a50b651300f82d098284e8ee14ac9c63cea8dc073188771c24884f9595a28b9b356d780c9555547b5fa6f51bd931124d5fd1e560bbd4befbf238b5c6a325501426d76939dcef511484ea14810c0e45ce74", "f1dd339e958ac1f47fc449ba3ce7ac93be4acf009d750c8dad276c675d4cf6e63a794b366361dce3dd3d8753b2513db354bcb0fdff32565e3e1f41affafc032cc54b91abbb15f13f72555cd0feb419ae8263b6b879ec44e27ebd422cd2f7dcc2faf6362597afcdccc93024212b4d2649cf681b66cced1705d631f5effa40214b17775eb32540a348dfaf8c5f60afdb94af79bfde30a693e64bbc9fdbf7993b7d695b43eca297aa3618d2843ffbf097bb5ea3a1fac573d6522529f07a0774f8be57c94ad934e1eaf1aabd5d2eefffe7388907dce89e0dde86672717d343ccffb08d5ef95b6d3a22a714941e1cf739b888f95952d72fbb8c74495cdb30d6a905fa36b868622d0dbe9bd8e884c3df862178950e45ac3bcc536d19bfbee43cb221f6032dcc2a8bf9799b54741dbe2c2c385f9f3a12cc22927c4068332f34863293e50f375c55d2029f52a4d82b80942386a51566ad9c058f0f0f05f1424012c4f751ff177bfa906c3d4de58de9766ade48d7a1ea8dfeba9ba4a7fff81751500d52701ea4ec656cd5d3ba290b3831aab5961945b5fb6069c50a6a91e9340c8efefb9f0b321e2264dbe7ab5789d2b4974867daac1214112b2f6c0bf67d155b832711ed7d665d5b09e8519a1e6e449ba66a8f463b3934311a1dd97f8f698f2204610de6e0d92fe9ff83de80751d0809035143470c6bbef847943c867eca5fcd4c15a218", "db49c46be69aa0039ad4071840b73c825fdb6909df3b7f6e2579475173ebf9da7e914f65a375de396d70e51e7094783153600b4ba8096633dc601d1b8c301bcc91563300f14a3975ee35e2127b0f3d2bd9c77a53fe2bc12e6808cc86a33d2dcf0d4b51d0709cb12d1987983d3d71492463c7b9cdd74b0b049da783506f7a5464d354070501a00c718b3982bdaf6370b8a6d2f4590b8196120e76214babc7a883c38d7eb956df967cd592e50ede51d9960d77476473c5f0ca52aaae5a1db0a801a1e80adb919df4cfc6d5a74a97f3a0cf9fc44f5b0f3bc8dbcdc7190bb8912595e6df8af31e4f8e48acbab72c22b7a0ea46fb769030bac2aeed585c4acd2844cdfeea771f1da38cd393bb5b48131e68487df515f2a2b2477bc7b601519a0574c6689fe8778e7a1b218e6d054e8ceba0c4242804c0cb226afd4ad831e0678b2f21af0e7083570c2ce8c2cc81261b4fb283ea7f5fd17d5ba3d265443429e0a16a6bbb5a0bfddbfd77b140ecd49cf06842bb9a9833f5c9accb5fdc849ecce7d60a364fde624966b98fb0fd2347fcfd6459178c0030bac7f32d01629eb48706596ee24fc3e2862a2aae3a2898e7fcf69425dc949a94a004887ef4f5d10eca917eb17a9a0afc1b82077b7cc2147e797fa902a6c05bdd8123e2bb0022e68750437c29c16680f968184aa55817e6ef0646372e5c344f80f9878aa51abfea97bfa6ee768778765231a4990cd7e4bbe55360658d20a145685a1a5260989e0235e3f23bba850b2a8971c560405acffc8326c11c79551c9ef37ccbf5ab925db49e35af9eab517603de45e21fef2ff67dc802595f26939e07119c5a7f7b3f657bbdde8c7b88108b8f3135954d6b412390a5487a8f2090f8774a34810bd0d84fd5c2f1918f9d0af2d43bb63ad9d47844cc914c56f0ec292f743cf79b635a9ca768ec1d87e9987ee587b76dfd4cd61d6236ba9919db93ad28647f816a624ad2723b1fedfe49060b5b6509318c4222184c7b236121274b1196c47719cfb383e1bce7b114340639e4b638eeded3216675620bd14e496ec912a6518b03b367a6fd9e958c4edbf3a80e2d1d55f9a0773dab237da8243c7c5d21f19ab319cf14b1dd6b957ec99db6a884cb95207d1ad92a04e7087b816764ba847f78bfaa3b247ab9269eb97e3904c4f7020970fed328ad7afbeba8ad9bd23ceefc587d8e260e09f1dbeaa9e4f7b6ec49ae1301b1f2f8c1bd254878843d3089578e4e39ca1e0bb1908866e4b3cd94665e627eedcd6bba4481056ff7fba84786daab8655ee9af3664a611c0ac4e1b4b10d72a059ccac111e40f327e7e455d21445a3ae9a82d812bc06d89c2817bf7f4bf80a47c7f3d449d3fee1041eebaaf54f4acc5d91fbb85b7514d640f32961336a16b9db5ea496553826129f0b1770e0ff116cb2534152ae06e80387f87da106e490", .Okay}, + {.Sqr, "-71c8e43d7512f03032f3fe567b54eec8bba07a362d00b75acb3187b0c128b3cacc1ef96a49d0e840a9170c39e19fc9b3cdb07f0a3f4552bfc8b92658a69955e3981e1184c2ddad4390e27ff0eadd52f69d28245e3763ac86cc78c6927a3ca1727b9412091e3d97f7f99f127177cb5db936f135673eac06c6d6b32c2ecc4ee0037c9bec4272067d5f2313f1b2263346664874adeb7ceba78ffba2beb5e767b6c0fae997e39bf08aa8ea907fe6d843d564a549c428322becfefb2cdba4602c973d5a98d95ca08dee3213f3247e6192120a7cf665fa94db385a7b85095bb3ef937c3eb3d61cfbdee5db080730353d2fdceebd6c12dbb09ccdbfacc595c86fcc2295374596dac6154b45c31d7f510f2108f6bf1b6d3ddd5920af2c16cc5b2998342116ac71ded7d9b249880f334d3033a18bad42af7620e22f449992c92cfce7c48c3a91de1626266c880ac9c75d8bd3e933fd0dfde6cb1fd9c85ed1957c79ae111d49c29e33181583a66f9212cfa72e22778ea4ae110c2e008a0e4ef1643e6dd2729b5b18d0b5daa82291c6cd026cd8f2e564e06338bd4a254b7d6b1ee86755720ad67526b94be5182eb5d88af8c9e98e7b88bbb6137fa54326bf68296d4afb8a39c1cd33365be73620077ba7d2f4c85f871ccd8f935a19adfbb31785ac44d4f49acf68939bf84b9363eb51fc557e93ac74263e07c070a43d29d145119fb3ecd3dc", "f0c7c37b2279a7edab2e986e9df4ee48d8e06228b7e60655c951accec3919003b0e808ab94843a1326e84315f1d7abd2a818f7391f0048c5159114761ac2999c6ecc7af3ef31e9b50d6c868a31f7b072acdf11a205c1ee593de32baf0bbe9ac6a15215aba6bc0d5336bd97b0bed13690acb373d44820242849f856af5aba88c9cbe0d466563ebe24c8ef04ee7cbd972922af7c8da2c9701e40a9907877271435e838d7f68bb944cd3fe61250bebc2f7ca17e48c60d7deec4b777a651db9ac2a4879cb546b842023c49d0268b9f9950a7f18627913d3270f365ef50616517b80ee1bdde57e38229ab7d90b5d6267d0e322be1348e83771966c72ff520d3ecd8998e4726caa53e04ee0085510a5f8971f7000f689988e9046a59532b375617346bd692677db5c819d032f759ed17610ff97c42756b0ec3d4b36660d5e65b3939b1f93a2edf45eef9a79d287adcb28ff4f8036257c809c2d89fe6aaec23ab861a5473888c844018254d3bcbfcaf023a9dcd02f34f0b426af202279b8f74d84be164cdf4f6b9cb00b071ec929b41d14bbf7d852bb589ccd565665ad1744ca10390286b6be94267d0c45e5cc44b6a75a9e5f9544dd14f6fa64d37f0ffc024d25c1789d79e460891e7646ccb56e6ddff5e583bab783cb3ac77f67c4b1077002bcd8f445b7995a814e27a1d0d7724803794315cc2e7220b3039c03fa674b8ad80785aa9", "3292f723acdf2cec94b1a6735c0789cfd282ea4b38e3b8c8b0f5160042149e59c97e12b835fc61f53ab96fae2b76a129b506f255e7779245d0298464f97ce2fd6ad37550a2f73f79178220dba1b50bc68107034f358c1ed156d5ee70ec99fb1cab046e6e43258233b8937aa23193518202447a7b654218be748dbe90a6b3d55ea744bb5abeb0d57ceb5155003822374b6f2e8b06d3eed5392a7ac5c962a1f48904bb6cfe55ba0838f691d8bfbccce6965dab46a27e59cb027a8da169f6912845f339ce4f693a1cce7d0d315066d44a4ad917a2fc1a00a8746e0a1c426ba962295e0c0cdcd0f5275e9b19a547142011551c83b59946384f07bc0a25d168fa09a61f0de797b1b4182b56802357de4f347230fc0d0e6e408812649d8eb757767e9d1292a3637fd77aa21e074feacb58a77a9f7c7f01fa2629da4117fda61399dbc3bedc4403933e5c0f61afa25ae279bd2cccc8606d491030472597b4409ad76d181fc55252a3a9c88042885f50bfdcc5dfff4ed3c03f461eb578ce7200f6d68ad3bba42050d37ba8b4428f6992d85bf4d361085d922185ce108e673f7f1a84335389fde183c214d146a1f9011fd4f2e8cc0b0599a670562aed43636e40e83faabf06233166cf7ab3b14af4e388a5f445c747ebba0d561e8e378f3057ddefb8dd30a63dda513081d57248ee2c1a499d3da94eed60f9816876e5ff6a8b159334acb24cf7b44ffd0da755aced7d0b27105205ee39ad9649be7eb0a14ef4c34f50f6c00d20e9e5e75423984ea2d0e6b692a70519945d35a1ab6711f5b4e842dce0f3a1bad840c561af828ba5fd4ade3aa4e0dd0bb7f4e97a6de48890ecdc04b514e491529c441aac342c1434286123e65c15e6ff424d9b630070079f6de485a5e6471247acb342224bda9bdb233b7e58c30b859930f0325f1e3832c9b2bf871571aa1c8959d97646d2eb42b4aa885b2ee520b36ba71e795a6e1edc1868954d31cc6032abc8f67477319d3535fb987ecb68002c769a434466481aad3ce8a22493dce61c7e2ceb00222c7935f1081f52fc1c9742400f72610589775536321dfd35a6b423a1a3b8a4b088505591b6853b0195d082b2920937c0bf3149844326dcddbdba4265bdf6ef3faecd6cb4b5fb6c64e64025dee7979e8d9895a362494ed99877fc028eeee98448eefc7bee439981fcf8f125b65104526644ce977eba3eca7bfd742cd113b99e4d7c1b21edee1fa18f67763771e7ac5a78a02e5453db7f0609578eb342cbde639e56e926bb511362fb94974ae40282e2229d0d0743653450fb23d17fc1b1ef0f05bafbb38b568c7321bee8d1f54eecaa5455f6e58e6b8af52137ed426e54b3a6679646d1c93a8bbff620c2f13c4dd4dbd1f10e7601fabced2f400fc6b30fd38de748a591cc082adfce9bc4dab5092d1fb5c8fd95df5f6ea4f4f46510", .Okay}, + {.Sqr, "-96e45b9cd71b79b7f63236e892bc5c6783487ae047d3ac37c7846655fc7410b13b2d4e8afc6d0bd8645188ff28b8054d6b74fdd15effa1881bbdfff833e78fec4733482c9ebd83edc7058265dd83fc2f41fbb7637e9c8b4ff6033f536aef04d6fd44f2c343e9150b6a42767c78ccd3fbc4719bcc7ac42f7d17ff9aef5095199132a230db569121afc76cbb417011d127d945c456cc8b8ca0ebb10928faf4519c8a14cb58cc65bf7c0994b75affb1c174937fcbc6c76f6f098ee495d26b2b41fceae121ad717c1caa9dea36e4073a95554ec0205ea0c7af5d976017aa706ab0f0f4a1e58a920f827bcce90abfae0afa1007306f8df0c0c016199cdec91dbef8561395164a20edda9262fc196931674159e965425dde2686c00e78c86edb2f332413a05e9af2249e745d5d43cc596e6456a9788f1d33327316b2bde2462395b00e2586b4dc6e56c1c12c23b7530b2eb60ca3ad160456f1f446ce970de0f4cf58ffade88a70cef136e27819635fc805431f4101ad4820f3aa19e22cdb3f78f6a895ac9df89ecb44c74c32bea9661c7163829b3258688d48928319590b41857e57205935b5c4a5f48b54adf52f8a1366de490dbaa6fca43a6140e1fd37058a26bbcaef062a10dab3ad442c9050deb676ce0fab4a6ed7e2b0f48354193ddf4d7b6efd5bae37a4eb5e84e8fcbf84824b8a6ba58f2f31cbf041c923c72b26f3d3f48c28", "ec65d47a42c60194378ecd3178346344eb46f0d0ffab35131888cd253095c992b52ad61973ebe810f6ae0216c76e43690de21869b0185b614100f9bff0d5ed3000cfea5218b9d3731db0617c3ade7e783ff16c629eaa67a5bf39c0aac83486784f45ce6276d223ee51d392cd77849e8ba98edc988415497be8f87e3dea6862dbfe432348f5307c6c9b17ba0c8aaf6f94503d16fb3b0d5a0268a72c6471e478f0edb5f8407142adc1a9f713bb005d2f9520de706d8525a401023181765df57959905e68a376ded1f3810ff3b5106b2a85558a22c4b52f8257e410a477af5c3ab4df7908b5b8488dfec91469df27b9f34e85f930a23936bf0cfbe610ed7a3194f06e453ad026a4e4e732738e43a6daf7ae94f3a94ab8d82efa6f27509e09182447484f10339c72f8948c553b8c50b3f3845b1f780bf8ce14a01234f18024f01eb12ced877bcd9f51569e6d3b2f633a4ea05f0c4fd356c769588a42cea03d6cba3f7deac94bc3960a43b228a0f2d1bbb477f099ef38a9b790a6977311262a3d1cdc7956a5e88826914b7b7a36bbfe45a10737001cce2152b2cbd36c58e84c10fe300a042cbe559813fc555352d0fc12efc2e938dbfb497ea8b2e75417bae0b33e5f8fcdab76ccbefc7e184180186bca9528758c06ed585ee3a99c543dbf139beccb5825b785a6a2ffe78f9b96a047028ff19e7aabd6bbb6f920e89fbf6c56896ec0", "58f0670f1c3c3c98caf5ac6c00ac1152417b3c20e8fedd67ca8d9984a16f3a0d4b6cfc4b131daf4c8fac8595d08fe7398c1096fb9644c9819cd8cd4131dba6ab9960dcfb624e6f98b157ad3202f202a89b17ab89e469fa9d89c814995a842f865029cee3a7af7c6060dc68f3c474c9209737217ed8bd126cae73fe14e3a554720a8a6bf837681b012d6a1725e3c94b74562c0ee7dcc540ce49ec9f0bb57a63208f56c64c01a9a61c612951e87f7c08c5e37a57eb9555f9881bcac1663bb30ef10ec8b1bc15d51c91cc16452122cbfa7eeff02dca0cb57b76cf0c7e8907ade88f8f703c6f8d14dc7e823485702ec6e7d4480fb72adef67c77b692f689da81422de68a450ee832f26e00f69af311bdd7680208d3bab053454dcfcdb820f7a62ae6a21a09de2cdddd83a1642854abbbc6bef4f182503fff9367cda7a2ce3570fbad1a3e9967bceb60495aae5786ce3740deb4bece130fb2ed1ac03e97f636f665d3287bfef5b808aa93308e85afd1440690288d57995982e7db263b68110276714552c3d29350e660af0ff66156b4320a5ecb3c76967a77fadb66d9dd9fd1de649b4bc97d287cdf5b55a6689490f501e256a2ace36dcf3f65dfab35c350f52208c2f766d5418f190485600c0c845e2b189c82343278871999e4c8b57e67b0fbf5d3126eaf2d62790694cfb01e908923c169c7550d59bdb9a5ddc84f0766bf92160a2d98b243740c5f551e83ae122b9292a3ad7a98db86860f599c5c9dfaed0edf6f7d5462d569be0121be6d576cb91aa628fdda4b55e60564719f2c19bf78b9119e482520ff9223f5a85efb2c5e2ee9653ddb8b3b1aee60608ce92c804eca85e0b45cc305024ca552d052308fac921daf35ca9ada443f313e6ca4d9b8cdcaeb952ec7534fea43e92fe026a1f5c8b9f543a61b1d57724914036e4a7ba7296ee07e6a5b935976025bef34242429eb33af3f7abaa679b97387ee4a3236e9778142903bceb918b2b16882634436de3b9b2999e28ea4c6fec55371002b38acb6b1b62b9194cba485103ad923b0220d55b31a42c0fd956c090b091b20922dec5f215db1e10d12e6b245e3d57ac5534ccdf7874d59e706e753693a2626d7ac74dbf003841c7164cbcf185e7306179088c0da5d4beea5424384bff28998ff42fd0cdd3aaa1fb77a165fabec1fd9a737edde73150c8493713ea73089e3665bd40a8a8c104fccfbde206dcd98c82819ceb5d62dd82f44abd0f3cbaad3590e064efa3e5e4e3dfe008f5e3d7e9e8f43e7b3bad1d192f0c179267abd23b50f0099d1ea3b4a960adc6b2ea0eddcbdeef6f4c2b18ca03a230ede1f06759bd962c91e6c1c92b69b4b1ad361d9ebabe7bf44f36fb7b4b8d75c59012182366dfb98ba8ec1e209b745c3ee4f70c6535778a4d2f24ee24820d7827ab35567c154a1d425f0cafc9568fbc640", .Okay}, + {.Sqr, "bf3dca19842aaac2180948279bacf0729fa19936488d82bea7fc2780c3c371441f7d85f7e3365221da153443df9dbd75cda90aaacd6c1731b363efca711ed913e55bb1aa339aabb1d675afa0f8579c105051b72dd37386a7a71b7e18d0714d62234601250daea477d850ae8cfd4553f4543f369e3fcfea47729ec700c33cda587ee39ea28e86642837538920d76722b87a49d16a84559c17d60729c23e233d84a3ec0328f66c7f7ec98f04fe1cb65eb11783cce5bc4f1b552a69ba62de01ef90e1ffe0560144b40e3aca62edac39aeead7adccbc39800b82839887ea7662205ee4cf006adce83707ca36b6d7f800965852dc45c88381801a73ccefeff442674b81b0bb4d78214e4efe6b083b4ea6f32e260b6dad8ab01df71219686eb08fc0f1c1358baf46fc02ffea9fc3691bd880a44949f2bdc7d43ded33ef55dfb50a45a0be952ca3fe3b08855c17eb428a7bfd6ceda173cdea53d8d54f58f6c90a41c07289b67829a9af9efd7e23f3136ebd681e2b192012dfa2840e88a438a5b1f2c9ca997dd2bd7af7a439e24d88d871e07f6d9494030f4bc560adc91e333548336af7be591717cf9e38814844414913f6394beafba1ea2cecad5f9c10abc23e60c135d82b087875b9e17a180c1f545b063db09d78496a30710e77211403d1e01004e3309cd9eef339b1143d1ed4629086b8b66f2f7d491b56ccf5842048f08066a1c9", "cc42e40c99c52355c3d494eaaab7a25cd7c94fb64262d4cdfa825fd94936ba4e3a9d735350a518cf67b42d8572e2b4ed8441fe37f8cb1aa0830ceec7852b381dfcfd2230a8ac793029874897f45b67ef84ee4f5702ecd42d9c1b757049af034ac92acda8fd29735c0ba675654d65c147b6360f57b088f626f3979e9ac65a056695572bdc5dcb72cdeb1aa47a116b7d119a560e2aaf78c36c9c0eba8fa98fff97b642b44309a32594713ef3ef0760125ca76ba55a5dc6d364896db5d52406195bbfe7379cb187b4dec4ee368024da7f86ad16b8b36558737d7982faed91713fef2c6371047aa07d976b4dfb33398374e517a74ce84fac10051a6f58bedd2e95f595ae2def0c7c051ddb1f8ddd02b4c3fe8e12eaf39debdc22765a276b6788f0cd337ea9fe62cf38117788d1a095c139d775066d1ff3def61adb93f85e0f29d85a9386aec12cf56bb404fb070ebaa9e485d65c3c3a9a60447c3c3c47b2b63c5de159091c00d9335a31337406e62c11d4e238ee3a797d3ae3927e427b2376dc2c772f1114c3580bc84f759938ccada46c1ef2085f301098e2774d34b4163684046726c6da02e01cc3fc8851b094014e52cc4b2244c1a0b398cbd212b45cb0a3555862d85f7bc202efa7bd243eb72b447da576d34cb26574b00cae0d27b94cdc8ec89e0f14a64cab8b5857b5a3e6eeeb4dc196f94b26b2efea5e28425703143d189c", "8edd427c02ecee416a68fd23773aa9283dc0314c877ab1559722ea2666fe8ae95c3e01b9a0497840a34e4606a7d4227123bdd61d05c491f39a5f429d577eff1d0e2d3253f80bf3b0867ae081d4f1539c825fe8acbaf0051984d4963ec6cba6311e13642d2e373f61c7329b12ae3fc6034e532086983c66022ad1a5c6674ac1ad0ed2ede5f3bb00a414c0f988a21566b2b3aeb77ba25df184bd0b648027d6eee8ec66a9e22726b52ffac25e091c16253033f1589b3786c960999304acdd41a9a799cf0444fb9dd2ef02fce32d66f06344354257005c67b635b51ce09eb5111fdd0d534b00e5ccbc63d65d0bf0061fba81956a4b8f71821d53824479343bad078849f4c728026696d55025dd00fbd851bff3030a818d525b6fd742c9099d075f7907ff0175bca4da0f3ce766a0ec3611825cf4c7b7836c5c6590450164402a6c23be9a35d9f29ae718a4ed7c3d6ef98e7dc3931b2711234ed6997917794b6fd3466e9d7bde1d04ca1825163e475008ef5e489d9c60dc05ca804aa82de1eb65430f43fadecd40ef698aa7b99581a7b46aa0098fce74b0a8d93750cc4376781b60eb11e1008a9a260118e98ae1e9a94f0c6fc0c11eb44eaffe255291d6f8d6bae6c8e8bee4504e3f37a745d20ad5a2dc63b2ad71a9957890a811322cd0ad78acabd1a1cb9e8f2c86e71a293836206f8b452e2c65217e6063e3abfd18fcdc606121c112846633491e31e52c175eb58cffdaae9fd7a6a2d947168bbd9b83560703665159711a46dd2722abf194a9a505b0b32a699a2c4316aca814cf4da3050dc1e9b8e77e633ee6c400264151040f210d02e9e68d3597dac79fd52fe8b211dbcc2bec6dd8430374e27fd9c941381880f2c7cd86436c395af2b66e2406ae796738f9d22cb9256a6650527ecd6603b778e6afc5c7374a30964e57b9a9021e991fe490d1f34652be8f83748b791596834ae6e4413be5164ed58fbf91b62151c66bea634f2623cd747f1013a781a19c479571c7ebdd93efe9f00adb84aced6316b3dfc36c8f64dfd69473c6c98737e6d53a45dbe69084b14833ccc3918bfccee6a81e83603d19430213fae0b67e9d61ce2194fd368d2a915cb5448204c883383c7a73d6438347e22899e2c196aa677d9fc94a10fffb381aaea93ed5f8ad081db9243de2cc057d45272d2717d64eddc842c2c45589ddcbec0a85cd23d3155107a5bff14bac4d4ea275895e6c661d43dcdafc41f0363f1601ab5c433f0d2cc80407b8180dc8139543278c35ec7c5cf0a4ae53b50bb28f74afdbd30c637277b11d8eb299bdeb9aa7d839292d149575cec6b47876c58f9a2b5ae4c669676fa981c626cb69d208e079df6888fbc6613cea5db77c9ad562df4718a16ceedaa24a3f983929a888c3527930ff03ed2f6cbbeeacb3f5236172853cb1fac4a81d64761733ce526a6fd1", .Okay}, + {.Sqr, "abf6a69983f69f077836790fdcbe7265ee9e0f736d63b191637516bc67c2a74b2afbf6bd572d282ee933a7a68a7e19c2e0b1f510005667f055264b856fcc5156972f53c7475d8962b974431c97fe29d93ec2c880ac614c9663da589d7b753681ab8305d2f3deeeb767ca534cd70f4145972a51711ab9bb4d5daaa4ff7e7ac4f41329644478445bc7f9515a45dfa8925287b095f93bb8583dcf93b7d0fd3ab19896371c7c062ec5a163fe0d76fe0c05593a3c213b0d6b2c61c2a0854c168f0e227e0df19d0d16fea123e08789a08cd99567ef3c374b4de567bfa56f8c6ad186d2ee1d88ebd98db21ff0d0a09f0a7ebe44555171b1630722b837c2782949cff181a3a1d359c4e6e64beb09c64bef274d9c7b5812189caf87e6a045ecf8a69ddf9bae96daffe1acb9701ad19c5bff441c69f723eb5b2b38276a1f602a270686349a5a70d88e445783cb61f13bb3c71d9b85c814b1e975f23555b0931247ca22f13755aa708c81cfb0108dd0176f76a93fc6428a9d3846ee8d77cde634b6f54fb93ed8f8bd5b740824f809d6fdd8befee4c42687176bed3d0d4319832f4c5f249ce49a27c9c871e4960b9ab542510087b11f7d1fc2e544fb0675aff61906a613892627ad4ea6de99c40eba1244c1f3c3c06709094ce0dc0060e669c2a8ef507e37567c659b81a5817791a813ee77e78e74c6f2799c7b623209cbe4d294f41a8a90df", "f0f1413a1e16670e9e73f0ec08eee4374c61eb8db677663d57c2ed29913a4966fa3828402f93c6009de342c5d814e37cfa76323fef42251f95c31da662452b549cd5a0f00ab6d7c03ee7917033daba3a7ba7d05d6871fb52bbad8514f8eaf06cb66e206c6ee153344c459685d0f744ba510f61da1d31e306feeb7c52dc434f5e4b52a7c042e5d33d2b7107fbc6b42b0637e828802fc7c9e191674b8767efdf150e4653351016a331b4bfbe5819f65e57767e1f3022aa67c5d0f8c6da7dd1e2adcaa36c6a46939e1c19dc4fd89a2c328e538e539a4b0ac8ba1c40757ab4c2d24cb5aa06fc448a717a0ef307da06dbe01e9442046a776aff619d1278df7b9fd857b44266abeaca774813482c2a4d1bb616be41842d486be64bfed070c18daac6d202072a444ae097d2d5c63b7dfbbcfc3a35c8a715f2303766dd1d17cb222533aaf9293f6349696797eee7965ff5e763b9065c78b90d2bd75a3333eeeb38d00573863b2f8b1df0545d248a6b0df9ccf09d482342833be40ef02cc3c717fd2355697c07972297f1c372c25e51f6f1159c9632fa28d1954bde62da5dc6dd72be79280998d704b5f2770e53ae7a09ed8cb3af2204b12dd98062bf91c51fea229e587cde3dded7277bb227e7b8b1b1c0f560e667b2772288e5e91e870eb06d75fd175587e53ccffa9c7f8acb4537fa9c48d1277bd329bbe09f2f99e886b7954cfae499", "73837035b1c089a07401e997dbad02373ce546f718767b7838df5aad524f9ae654cf8bbe0ac5fb82304af008318ce05664e14d1395ca6290cd089ae8ed6d64b90397d4a4009fbd2abb643ac8f8c6caca343c994e3491f8ec9eb4fecfdc2a88a8a4e9fe665e945417c84f8544d6acf0aae11a6e94f399f7cd36dc0691e8123abeb2310118ae2d00cc5c06af6615e4e2bbe8afa98f3f7e019d0854c025679efecbdf84332caef4bae920e4d17c038a4c04086296512b1d5d19c157aff1d333ceb843b9f44281afd1bdec0fd3fbf880d20d5381377a0bcbe59543ba124fbb7d4a96f7403295ae38e78897f4782910b2b6410f35fe77f0474a383fb97e5e8f5246b02e0720f7d8422241ffa3a615a57a4ade72ddfa2bcda9bbafad0d9d17c81ba778da61dfc15234497ee517da0b32fa19f40d6b8ca591ccc3ee12d133f93e34eec1e9b9cc4b3caf00f28c71e9b32224e5382d72da9aa9fc990305a5a345d0689b13d7094604dac86a92ccce01f21f633bc2eb62c274049f75f61626bdaf358624a18b0df2268527bc497cfc1d07a6d3606af08eef1a7d1c5dec066d88bc4feb76ef810a21a353b92c33bc99c93e9c2d1938f738a50e00d1521e479a76ce949b99671bb02bced2d2d8e2678455bd60a0039ae8710834a54b271575ff3889ccae17147df2e42a1bb07bf2d1a2c2fd1573c42885568b975365d76ee35f760a0cd44d7005a7b303c56bf543b72589deb8a139850472643d982e952d5aafad4d86dfe16484c50f7a83e065521b585cdd6c2312edcd75d1daabec325b1ae8b2aaaa8a815ec0518f35b3820ec394b29c6c5809e24476a9ae22bcade6d01edcfb84262f060d5110c21d4591a0bb577c70686d55042c4ca4568ea6ead17862fabc49d468ab14ae030ef94459b590c7c7f332746d38c7a104730b8006f543ba023501db32ec38f6f3b7627d2ed1c6bce56f32961f5a9abac64d9c070db29532d5a38990973a57cec005981d537fde0cbf0c2f2cfeffe5fc27dea648b2c6104d321b2d6102ea26f0f4e88f9745dde28fd02409c5617b7691ee97d0cbca1836a68677b043b7fc5efb106072e26b7c2d25979f425bd183b327241c1566e0db0685b0364bf9b3ddc5f92cccc84da8be3493be99034fc9c7d0caaca19becbde913345e0ffb3121501d1de0a86be589dbc50f1fa2db449d05b3cd0ae01b5819b907d236d5ed7e4d1f0dd4ae0a0c487fc2550c879f1c7437930c22030814eba5e0c1448f60be83e6ba832cd91ceadbbe13cd3048142c52c17506b5760ff7f5a2e48d63e77a01f47a32c4fa74e3c0f603fabc2b9f826758b2c8ad9e24773c29cd2b9e980396b5bd475d6a43583f2dbc77e87d1533571af1737438b186e20f4306fc4f110a2528f2d146d8814eecc7c79173c853c72ae893107989852a9ee0af7af47fb8427185ce67a241", .Okay}, + {.Sqr, "-2a60e8338c8e2d83aefea9a32546ec1c68c0887e8efb8bd7c4ce9544a7fb17667cbbd40e106b7c80a7c5aae8c54f92939da937b67ad7b20cfdc0a341fdbac7675b290cdb0dee5022fa3832ddddb25dac0978f668845ba76442453b710ca3d2206280bde11dfe5a397e009d0b05be31feb12b11d0966c2d1b5017679ed9f936c82ae54909e2aa813aa9f1b8c57849d23c4b78cf373801a315a7d756efb2fea9e1a356cb603afdc54704e547cd3f89c009380c46b1c2faa013347f02e8e12f2b778049ed82afc3cbbbf078e4d59660780d364a3e978dbad0a9608caf6b3ad64d6f3b66bc10b3862f139067f8c4f5b1c1914de1cb2c6f1c7f35e1bdc448c847410d2f1d0e56fe40f6382c53951293560d38768fb3a4594583a087daf298a25557a262b4b769d2ddd082ca3259a8538fed48c502fceb67653c723e532cb6a1dfe141181b4ded5dc9987d0d2f97b1a26d5c7cd56e61e5855d4acfb37c7c38172c1346b95fe073ae3b3847b43953e819f75384f0c943afaad3e8b50186cc2594618c7d66ad5a56e983aea144ea7e22e30723ebc83fdf40590a6936dbaa5f642938bd078caeb67c24c5d72416e10108dd4e1890b89bf6ef66165acca7c5fb91e845c859c21ab34afeeb39cdf06a7ad90155025a6f44776a49faff6c678e37c5f4ee0e8c7dc3d764ed69dcf0851c5b9a7c43bbc2612277c49da95c8190534199dfcd8ad6", "3472ebc2b022b024733dc635ab2b8f39541852b66113732af9124df9d9e41acfcd5068d92e705797e41b54aaeb82ede93cc91f1aa1d36113452afc9025f84d67e433e13554a6ddd72078aeb82fc4cba048a9c11779ada2d1dba7300aafabd77b5a106611dccca6d918d3db68b3046cdd779533c15691b4f4a3139466c441cdab115250680b1730189581595d4686ceb01aae41fcb6c503e4fe56f58f406702647cd9a16fe0cbabcf97ffa3b2857494808e1ef09e04be1eb6569987a475aec9a32d3d5fce872f99cd79332ffa9854ea48b529b75fcb18d0f98117aa68b7e6568ba8c1972d058214931551c1b167ad2e49ac9749a2a0f1e53797bfdec9fe9aa1db081700803d781a94dbc3e016410dada7285855dcb8d8766b4a18ef2a86cbcd4024fcce96e0ee0617fe57d387e4d71d73892c7132b8eb42a49eb4388d742086c4cd94c10a7e4c68a54a79bcc35549a1872c5aabc2e8a94a1e133e5ce777203a7a025e2c6f5fe04c09c245926dfa8f67a3e7b9c7b21e83ef18b9a39655df2fc1bf36a5fc874d349b4d1bcf34e6d9e51df12306e8b310158110a449bd8d17e2b0653c235dd09ca3eef73c3f27350de8a7dd175b8d202197fd357e8744efbb1561db4d74167738b6257c4e3b915d02d5aaf1b6aef8f37a37340baaf2f2d05252c80517eb5371049c66a555e731410475ef2fd100ccb360b9c6c9ac6049f3a6da933e", "703f0dfe3658ab4587f6f0c9d1ac08c878a5f4d887329cc9a2b7a63e92f78843fe5954cb7ba14c74812df39c6adf18ae3daa8cc600eca82cdc5597350dc0418e62750f4bf4e70d7618b478eddcffbf8977a57a5af6c81e16cc9e28d3a822bdc0d16a2b13e369910145927fa50660a241271100c4df4e7c0c02f6cea6e2e76d783cef79edff7949139c4eb54d3d50e7d2bca99a49bbd864d50b9cd0662c285e0faf5be16eb540026bfc93567d254dab5ec4040e83d28c20d53fe239c7c26c16beff31cc629e1016e0b3452280b2ca9076774981591c3d99ad2c2951453be12a77346c4fe4a566b36be2f6dfc88eaa1d48860b3e8312af75b34e9c749f4214b2a7528249b32dcc7bdcff9db0235595a92b8f587bcb95aa04bf09d4fa87ac9b255f7b3b2ad9493946a40e7bd8e18d49575ffa1c0fc04cdf10e60bbd330bdadb5095c2fbb5ee9c4a11281686479028e8e7491343c2a49000050114076abd8284271e177aa1950a27068e1762617fb9281a2a72f3f0c37835ab39fbc2052fdc19e54e350d54881b1cf0e2262e7ab7368fa5d411ec5daa89a67b0474dd83e361f426846982686ba62c68641a73cdf57afa17601bb77d11ae32a739576a79ec795f28aae50cb764403691187554885e11015639a0b41957af5b755738d3a58521cb584c642a4748a6050cfc6f0499d9fb63bd8e1bf8d1ded5b34d9ec700d8b54e9cd8a2655d57667661b5a0b4171b3015e8db90f574b7514d8480854adc54d64838636340ad13e9975137cbf9c99b3fbce61988cfb304949844e472b9a014598f426872e4407e1efc47e44de77e89c5c00ca18580d5f78c8396bee155a3392cceebd054bcaba58c1263c545a91b7f5421ae4ad89dbabf7afb895415c3c26b0a231b6b535ee8cbb0478ad4fcb4bd65ffb696bacff8aa1ba1d3f3cf0740872607d2867644c8b97ecf591789251c31b170e3e90bda87790fbdbf631dbd8138a041ff4931e3dfd7b0a5a2131c28b60c273c5cceb9003017560f64d27ba5c01ccf019872bcfe8619ad96d45373fe3de10690081dd62dfd206e1be74b635654a58df0ad2aa588adf9c564aa04af36e2dc3a916cba6ae259ab4b82ea84c4091d310b3f358b5d21defb0eaaaeb699f90dfe7668c85c59abe20dd875a707608764b62649ca7354d87129f148cc50128360e2f2693ec971c6ffb3baed13bd556aa52a132e5dcd812f46dcfdc5b5ef8c72a05c075ce7f38576eb8948fdba90a7d626108ed0b4d57e4f379fc24d5b97f93139609b1c990b31882382e5004c759673b9f5dba3307072d6b87f0bb0b85b8419a0b3e390fa25d18747750df8f368145612306bea40fab352d75c98a3fc4714d7ba4d11f5efc704f9533bce83eca7058f4d37c14a12b7508d8d18ae571c745bbe8685fa416d5d588ccbfa02bc9d997486e9c5cb47a076ae4", .Okay}, + {.Sqr, "1c5610a9a8fe93520d01ab82441cd935d7dbf248af49b8875084e0e0068549f6a510d616e37619224c9d74d17712e0f01d68cb4c4e2155567c5774e13da66d81c04473bee88c8ae5a680eef3920e655dcb479b31d7930a1da1cce76d90b959b5ea7abaa830afd4b6464651c50f31d15fdb220e9143d6f13134d2c1e2e5b3038977045cc76b30cf0fe00be8477189494c8c249c56d2ae59824c4d6062bf64d31c06860d968aad42574f136790ba9cf54c8dbebc6e12fdc7f82f961709b57879f496584de6c280e33a3a5bf3f8945f4ed296e05659dc3933db6b56776f3c67e50445d5f954aaac41610244acd8a7ec5fa90a2e9978ea4dcff87d906bd36bb21fb8cf96ed8e163caf80e71aef9f8c8a807e571a67247c9c37f387e6cfeca75734cc0c723d7bc48d86063df6f292f6396fce815d30bed503db93be3b018f200c73c0d3a664d0a835dc96a5d0890c5c5f46070a27ec42cf670c7f5270fd5dff4cfda001ee7bb8aaa267e54ba29ee38fe7dcc80529e7e5584642d18c132f0b726566a6f48e39db1c7172ed2ddf5be3930b3f26752ffcc01a8151a9cb1ba5f684fd330ffdf27ed18716751d0e0c102679bb1a08bd82fb86ebab847e27869859d858a5144a326f23751256b90fa93a5bdc30e7e976e272b03f48fb96f53d8254eb6ba226bf07d9dc2361e7e9ed02c1c9966d01ca0d7a072e3ad83701f13d3c000bb4942a", "7b45d4796adbe96c96392a0762cd3a0a332dbfad5186ab283bcc9a38b6bb35ee119844b8fdf8109062b148394ce806f987a5f0c7fa12db9cdf03c3b2c5f262c3516dad5cdd7569b97f182bd6cc5e999cad9ef73d861246b65f9e2ec90b9497aa3dff63c10a4458edb8d7efb5de4d2bcbf1fba6ffbfcd8a45701aee10690ad01106e2763eee4884842ffba4e93effa180502c3386673d617a8ebf4e698068db91510a063b7c7f746ebaab9f03aba1da1cec7106d5f140d595ba074504e3365ce6f664c29279a25af3f6de3ec9cbc8f95f014d26a17571f161970b3a34bb611480c328b0ab06efd8565b40908e1d24c3d8b530bebf9812f4a39bfc6990b5472c9dc91982a3cb03fbb3db15bebd6bb9dcb71a7dfff82c86fd4206c454345425604bae58e32c8c601d15d14154be5a1e09e0dd334a30fdf6acad4da1e71327931f67a37d123cd810f07c06761ad34c12c5b0ddc73d858d5638bcbeaf4d708c60d611036b7ced17f29dd297f08d213c9e917be05eb4e0185855a68e6027e064600a33aabc60e44f965133a4149fb06e3b86f03cd1bb62d54a622fb39632f14472b9b6925510eee18c8bca5a7214b0da38b5ae052e0cc7f1df6984ad4dd878bf9ea8869c974bc3949c4190fbb1f84ff092bd44c181d4409e25f3941c625305bcb4dd501317740f03679164107849088b91f703f9973edc28451575cb02f4de7ce46416", "322f094500ae0d55010fd1d78bc230ed13a5449a8cba2303e52e592ed04a9baa704d53ac426fb7402366b84b571ce2c4a951f4f22639566c0a93cc9ab067ad5d9cf12eab630f26cb75b27ab6e37ece6f2a1c75b652b6408df95ab6f1fda00e5cd833da847ac6fc1092815b07fe683eb62327ab3e3d7db601fca12d78676abf193f1708badf756d527c19db1b41b68fd44912b492b120a94e19879314b6e982d5b5926e0b4db2fa43f052cd5329057728a8994fd0ca6e02a92e9a03e8e8b9b7862f96b326bc220cbd4e26fa334dad0f75c8a30abb2a6cf47cea61569b8ef17f55d3a1415bf7b048b0cc9eb076afd621463a2585890274cd3190aca66f74298758ef9abf1c5d6dc21abc42adb566ecd55b34270ed4fe1dbd6314e534e1a5320f7f52e2df9ec59232a42d4a5fab71d4cff0c96fb3688739671f1045c3436ac1d2aa63556a00f892afc0493a575cb9719b8bfefb0bd1d5624ec2aba5078d7bfa3f39118152bfcc6b7eba35ff0f3a2a549bb0e34d3683a6e995e56aa6b76fa77b63a47bd6691868a12a7064de390625a3f9a18ea735bccaf8483d98e6cfc7ca932dd204862c8761b80111f9e566897740666da9938be19cebba3573a3e551e54ff0fa04ff6b646d6a000ad659b3b7c94b8e607800a5827092f489d52d07aef44821d8459045566a3d4c8503ce98613b2cde0721ffe48145ce54a9d78d9008f49e87679a4307b41ef174b15332cd83dd109fe18821c8d2385a05854cf485cf7d7992aef0cbb6ceb3438a9e4e3a86a56a0199e42e68198f079d33a7be0914ec00c16dc91dfff5b6d28727dcfba1217588bab55c73fce3006c9c9ddba5632202c3df44c835054828288805d7428207863249707955ee64473342fe303757ea41d08b4e684d51f1adc6f0544663f4e06b02c4e57c299e61196e9097cf1ea0ca6904a1f860cecbae3650c3a64e7be39d0f48b50d9564aa20a984ba83158413200ce5cd1803290cdb243986a509e4f904af8a4e900b86ee8543140e921ddb699a1e41a68362210fec1ce44c15ba3305fa503c0fb8841e94620e4bd3fe3212b6339fee75746d04cc12642c7fc893155efcb2d1328fb921e426f343b1afc02b7996024288916846e305a29f01ba1e9d8f10c7867d7457be75a156197dfede589aedef8102cbad0604bb44d7d7ae1038076f05d05f092cdd0b9efee4ae5461fa1c0abe039d0238c80f901790e16639b09575adc71c6affa177cc4bc262efdba86405b4f85e23e8c6807515629a0e71307c03498a1fc98b88b18af2052bd01a040c9ad1dc329a4b3f055559806ca5d3a52729a35f784dbb7f4560f753ef9888681f9e5f400672af0a8f3a4a6868944b401db84bcaa790671a8ef5f1abb4e47f02f3d1e7af38d8589aaaa7e5877f1f8b912f96842d3e24aebfff59a7a12ccd65600b41c4cd096e4", .Okay}, + {.Sqr, "503e2c6010deb5fb59ae0c95ab4554c2e3dc11a52e173c7368984fb5de5551950f3bc5c07bdba37aa4c6907e28152ac011fa9d5ddf04ce6c8b26c827187c29fd35f5304765d32de44411d6de25f2219dfd0ac352fb7f08c8241cd0d98dbe9ad31450657e483169be3b3b6f8a0cc4e3165603588cc2ce356d928496d67a493251f56009e5ec8f31e7c659cc81fa89ec8ab4453662b9716c1dcde3b2e6f918966adb00c9a42d17622a870f5e4498c7e2a4e2a63c7acb3daab481c15fc0ef2467bd0b62d812ad34929a7f9261d6d8c4607f47b4a66455950b35f68589f7b77dcad0b0170c71144261589ddb564087e310cd2cba65e1f9c47e414177ea2e5b7b7cee7f728da3967d1db941376a81be956a89d6441f0e1be07a5ab621e92aa45f009fd5a818e9187cd0caa721a9ec41f2dbcb1b90805f351c3ab28e2366971580ee68529657487cf9c39b4426316ebce2be2c7f66c7c4aeb05a0440081ab55e471976dea2412e7870f73cbc7f679731a1076ff9781ff3683b15d1eac397f794d0b0c3b9b0cd9984d4b83789b887d6979079626dff042b896f9426142eee2a2828dcc4a82322656a7aade5c5efddaa53371292cc8ac42bc946918e50fa5cec3b752997e7246d651f09d9cf60a75095e6817cbba64d7e7a56212bac7796ec133fb879f9a8db3ac8073fbeb4a122427701dae0755c1833c643e86f132689039106b14abe", "2555cf171aed5be2d0a2509cb0e9f89082508ff5e1edd4d89e550dbff4534d30c77e8ad653a2e062e57f842ab977055f12459b012d05468c1f9f56ca801957a6c8623fbfd25c27f8855ab9d85ba79c3dd8fb6b3b5a9334febb5802497eaf8500938da8b56ea2ba58b6890f7d6df1bb3141e5d7a7e246584903e8f9396517a024fd7523202b49675847a7922d56c9997a383a5c2cd15bb396cfc4d2b3b6af435e8cbb69b1fa18fa16b3aa7da868492271ce8fb19c828831aaf1192cb8dd4e2282280ee1d27106ddb2894e6ef804e41426ae4ebd8cc07d234c8c6c01b7a37024d36f8c3f455199fcd92d252b9a672e4cb648146aa045dfdd1064715930894c941cc1d25ccd4dc41eda652cbd1b17b70a0a055ba933e7552d17ba7c9e37d7456cf08486913e844c54f9b1d80c59629dcd12a5e91eabc88d0c3f83918ca0cb1e5382cb8f9b56857b47db49b4faa68c9ef301a7db2a6db57f0406fd15a43c8665ce796a959583b9c6e61c571c56257cd849a815e166e6a09fc51e7379edc07d2f51aa311398d8db30bd57b4c390d7206e40c40b1c9238b00b2797364faf42e3f58999036bc7d8c703d2bf0c54fddf16e647623169d340d4637ab14bbbcbd3d8a97947dc50f2e834fd1066ea1254c359207a5b49723ad50e3cd2203e6e4ecd544d3adcb33c0f4db5748ea6365158d3cd27a284be0e3536647a290893ec77e233930261", "1926ead590c48776747fb40246e9dcb8c772fdb8c366c3c546d148b576e9a3cf373d3dc0ccd4caf988039ef10dc805e969c823c4eb1832e459283094ad6b810caa35dbee983c1b58699b22a39c20c14207be03da0459def3f56a4d4d9a788311eec9af9833a7d4614feaa069e360528d598977eaedfef54193a75c3b34ba370cf8aa080fef58ba59ddf65a911dd059a1f84acdf0b1f8709aedbc9d21b7f886a94513b6c22057d9570df082614143e63526b0f3ab37be99fbef6862c698ff14cb0c68168a8f6d4c80725fb0bc6025bdbf5a56a709966d924bb77585e54660a25b9ff8b176182d8f30ee4479e4cdec2fd3aacaed8bfb6e305ac84c8033a8b12d2d68efcbedac2769af6a489be99d3111128e5cc53c65774107c2a4af6748a374e31f79597e099b78647944febdc9c46843dfb8fe03143476469bc101e2c5ba944f511fb72931779c19201c11cc019d86594b2614cfc0f628c89fb252b2453dc4d23154b057f30d084c79b2f9b7b6e4e354c47d5b1a048edd7fbefc5f3bbdd0a6cb64bee7e847f7afcb489f6fb802a53b5495840029ff71f8bccb8f28aaea25bbc7652653c7c3992e8d53a06a1b542d85f68a5693078f68c3749e306984e17b40d6643a681253dbe18fe3c73169082456b50b10bdf94ec6a92920dd229456f63d26ae6532aefae389f126c69cbe89d2f321f493972fb2c7109d145e1283e800a9738b37dde61bed629cd74fed9cbb763aab9314e81826deccfb2c83a115b0e951b975d1164b5f40be40139e9a1ef3caf09dcc982b76e084465f14e94082a3e89eef2f17a8784899806a1c6da788c98d0b34089c2dd8e1cac87d96733c368ca948883cffb558ddd54da1a59035f6c7210f5ab3e56177e4b47d5a28d15e43474498b172677035df7834dfffe43d669e4330eede8714f94256a46068e86dab004424fd383082f14c54a5b72421d35001c6e8c523353bd6bbef10b17061f0af8dc8f858d75a6307a967624b6fe4ac2a6e73e5487b6167ff620701f747dd67ed412ed30147e40a709a5d1bf9dfdfbe5ddbce05061ee33771fbf684b0a7949fcd3c8539d947c836bb83b1ff19f03c415af765ef21691c8a5511070734758a42da38e334ae9b6559375a340453e8c9a97e23edb4ebe6bbf09cc7b9400808cd9dc988d7845ba8e535cd98d51751a5e9163c9c449b95f550f3a6934695558ee8d4578cc074898744ccadef61d4a63d6fe49985857af6677e1461d41989f6c09756fb850edead47b2a40daaed8ebff5d3cf1ac9c85d00660776fc9f2137069ba9eff7818b9175c48a32857f48db2c2bab8efee939578d2ec68e9939bb0bc88fe49462ff910a4bde9eb9a718c9aba8f5858f03a967dd4c4a5f755b39abbc1447bd17e7bf3ae9d344a908f4002624eaff77efdbcce3fab1813f821788c46077241fe985588e6504", .Okay}, + {.Sqr, "-4e8d3ddd2970ad1cf5eec1f960330b5b057c31cb148b572f7270af95f936e619092aa0ffc3217ee50d83c8a3670731c016786d329434792625ffb507ae1b0e1a24162464cf33fa74bcb96bad99c0420d7194be78f714afcd84114dd13840cf742ea3012e912c7e06a3f16e08637554084e5eea93413f6bf74bd3a0a03227b3af761f29a697f4a980300eb79b3141911ead9fa79adc70761696e557f7ebe74b0c2c8200537d453aa8b6396666f16b2f470b76d511e1f1238a0e5a4c1e4099b3559a4e1e94a24ed6966b223343cf5ac95a12c8e965aefa86b3c46dfcb6203f389282fcd6f4ce820c9825cffeac5941590ddf172b5a41034d5300b06bdaeb8bace8f8a8a48a5c2699f4db871874835fe6e5a278d544877098a7467d1d4f2fca4c621cf4d20c5d5d43a5e041850bf5d256529cfc01bb62821c16c2999c2f44499aae3cb71de31af71447556c5bd04ef77e96990bc7e31cde97aa25016abe393a2c108b6f9db9afd1c78330f40cda38938a7d7da0ae43ee9c3a126ab731933a5f8d2059c1fa04f0ba62d86d8747c64b8a52d9db751b00f9c1d6c1e556ad04745c73725f51d629feaa98fa6367e7564ed3e7e872fd2b0e882b324c9ec546fbfaafaec88a492e097c19b86e9d507cc3032e2bb646f5e32caa476b18bf9cb43397382121e65dfec55dd1932620ef00787528a7ec68f22f322af276565260d66c74ecf5a2", "2558528f27392c8a25169f1a7142748d037c35c8e404b8a3957b45966a8f0ff40048d03b5a4904c9588242bc9fdf06881f297d0d73f7ba88a0f2f42022ecfdec26fe3d0b58598e0aeaad9dfb5297fe493d2077c3d331cced27fa4b3f1e9b439c8d84b13a5cfe6d036c9c5818a19fd325159a2847bdbe9f2c3f7a3f904bde9213617283ebb6fafbc34f2a8b6d3626255bafd81099b3649b00f4558b0244f5576ae071cfd7ea17b4e40d093047db05016298ca65ecf240c8c293374831462133f9a6450a4631541e0bd37dae7f9dd298b2cf6f7735812dadb24885de30856b251ae1fcb36a7898b734d1c623410f9c5ba43c0a5fc02c8fb9af9491b601edacd63301f11b1e0e339f7ee6e7e91393a1db8a396c2be50bd6064db08c838e4932b101169f86c3b36753e6371044784bf3108ebdffd2a56869687ee4d9f3d6b454c46e6820d5da4247a45c161f91b465803a87e8acb3c360e7d76f696315fb283339a0bdf12a9c87781d7cefba50ab9f3206c49d5aed1d8c0b2a953a3b688e671e5bcd7a30dc9f578e0294543223ad409169cdf8a4533306b167e63aea41606a48f106a704f717729d921bfa540f01b926b87a2b6d77a5aa0f12b005dd738ace444896de0582c459347c4483f133aeab291641a726b5c0cb6cef37da3a7585b234e37829d28a6cce10e64d499f933290488d6e9fce4897f3a008a2e924677d302abe56", "181a5f9ff9d3746c9d8461753f2ca6456ad393bef316e99b152f6be36c484bf2e56d49be99281f10b639c3f63df34876cf7ee3bc7d87cd47ee44c22cdc8f63ebd421f2e32698b31af4b82e28b0d690a1d334d6c1c6c2b839677906b212d1ac923c03b15557ce4333bc1a262af1ec49cd31ba3d10f1ed88083760994675cd3c01e94ee98a24ac27c1fc03be40231054b51255fad749ebd1b940a6e551f06ff743a27b0cb5a14e67273cd2cfaa7cee2a61c4dc28b7b7acaa76fe4d1eddee0885c5a75a337c9a24343b1c2f43d1066ce8878f13df5599b94e1ef0baf990a53f6fb580a4dfbe48c9e2d1dfb3fedc344709464c43e92bf67abb70f32de7801429aa91cf7e5e56b0d9dc1079b8011cc58cdbea7472883a04886680d33f2314920ef748db72607299f4147ba8fb6dcc6280cde420774040919fbe9e7abb54fe4d68bf0a1d45619e9617ed000722797505561f15953ce330afa17bfc7eb81697ab8f6e1b9585b91b9b033281de2f32d7fcfec87fbd503aa0410878dade7f2fc6ed0a200767ead3c7405de4ad3f2198f602b6877432111fa88c8f0c7b80782836f400ff01983dfd802cdcfc131cb3ea7fa34ba3c347a436121a0e023fae8af0775d05205a661afb7099483a01b01f477e6880333f6a3d4ecf04450497a1bd7ed5e2eb3d075e6740b73dbb180f0badfdf74d1c057d97a84dfe5ec7ce321d77d4cfa1f384d47eb0a967d6de214927aab94f6e5da2ed7c2b2c9a28ca62f1230a25c0f015634beb1a7121f6c0010e1ff45e87c2fd4a4d3fc34e0a255dff43d665206b8d8b6c23df4cfe8c27ae7725ceb4175add88bc55d0b701f7f1b8aabed1a06912dd207a77bf7e86d023220a7caebe0b32dc0ca35228fdc426648f0a65d371b9d7317989605f297894d3422c82292fed5767a7cbf6fd804341f33f59fe9f333b90729b47ef620b6f84636254abb2041e33e2498a652e9b5be9fb7464c80f3995d817d76ec23fcbd38663f67240b2bde6e1f108de43fff3d65c1eeee4a25a5f65fea6b8f650771fbffbcd010aeadc8b65b2a9d81b2439bf57c617f2c23a5705b674d85039fd820eaa8c3ff35ebc04756b73686639c7a25aec33eebea324dfd932d1980299f340e2830159ce4f6fcae382d635c72b3a86839de595ac497eaf271fcf3f814e17739a6b641b25858150ca10e41d557bfcbe15ce3bdc5fb1c573f05d0f129780be0f44572a89f63818328323f04172742e22957e8156fdfb2f91b0c739bc48e120a5373a61f524d5b4c0cf783cdbdf1cf0a029e286e3118864833ab111d1f2126863c523709be0791b86e71865706d2ad6facfca07082d725d1de3fee72cdd340f47124468b9cda9f318619011971b4bc3580a7628b9c37266b03eedbea0d3b5cb5c02f675c3a246acd53510b5198aa20e69b27a898fc7615b0981b2a09e5f7a84", .Okay}, + {.Sqr, "-f77d01a2292041aec0c78f4e192ac9c4b33a87fb561c20ebc409f57bde964ba6738abf5483d30fb49488c686f2fd365b4247f903257f5ddac6779004028db0f28a90280db79d7dbe67af3999a7c59dbc69c6d892ba9efe3179705808880619e2e29880d5415559ed16136b1c6778f41c8d83f1f9790e58658ba74a252dc666a4e8f473109b1384c1bf30d2cedc213b6ffbb569d3193397ab5bb9f32d4708470b7601aa52186593cb7a106d5fe9baa4b0a1cea88acdaa05383c66cb6859e0b94609280e7275429db4bfa0bcd3c57ebacf3cf900fc08250ce507a0489d4ffc12c5fc852beec0c36befacca4429eb1ad732db608f31c1300a801ccd860545230b544220a9352aa0d29474672ef830861b8dfb099254d69143e2181e900c3437d25aaad4a1cf1590a6b87cc2fef5dd994bd14ff37318f396fc556046d70cd09152fe0e9a84746ee681c160fc559f11d4053183b7a96ca4275f00b5311f7748ead093d3bb709dc3317fe4de8e134162a61ee02c538d4ae5374223c4f36d4096f6fdc4a2c3b3a70c136f794d1efe41c63e9542d944dafd3fc2423de99909a60e2bc1357a5012ae3e599b5f4e07269d7ee1159e0ae425574e85ebaec3bd47d40a066df16366803c17ce583d9fd80f0d6e34ad9dd4b4457ceaedc3cc69ee3c03f957f617b22fdc1d02a6bd82608370c26e7156adf20de7a3f9199a2a2052b595379fc26", "efba4ad96429ebc74ef3100edb4cca4c19fe5b00a1a1ed5ff20edaaf93536d14213e6a948bed3edf5d8a29934a2c57e2f07d90fa8862483981b343866b8e5b021158ad03b9d70fbba241bd2d916eb9cd95eb8d3248e9a213987c44524807d616703a3042417f5f3f5a8b560a6cee861e7087113afad4a15189e752c50aa4b30ca5c259b3ddde00c34afe4db285fbd19187a5d3854a5970fcbe6c7a9f8294011e48743b98a1da597df4219f02cb29aa3a69ea0608f4482fc28c477b9efe83c728953c2b13bc7595c243546edbfd52c0168148a96d2d32292900d445fce9930ddbbdcc879d2bed554bf6161d7bcc13be486a4d2559a19e07bc95e60d5ab2a050cdd9c6ee21dbc0b82751b7d282e3ecc2bd80527816a87889c0333bc7ac1c1c1e02fb737443b5a20785fd07e6046e28684283735aa49eeae9c9e6d1761c8aff1a44b25e23c66332938395a694d404b91f33b65147e932bbe007b6be17367e45b209ba88b25cb73867ef33dee33c44451ec606ddc853cc284e765c402d8962992d25ff22b2e0c82795e581fd51a3473154788e9392e776c5855aff75933ee47088b63b2bc4b96e8224846acec0a507c351ba20e95d7881671a35e120d90e28107ccfceb426e8e6da1538d19c3ce6258d108dc3eabde5558ac9e00430182650d0a9a41eb76b503565f4ab39c057ec982625035a3ebb2f8e972b5e44fd278b9f2a016a", "ef42763183bb1349b09b3132a8cf73279a7b48b3bb59cf7a0e09b7f24dc6293fd73abd2aad174d0e6037569c51db6e096241cf46c63629adfbe43bcc57f1083638a1dfd0ab0786f2f313eaf1afd88fa1f0bbf7c1ac5985bb365efc8a0639b31075e625a4b74f319c7f2f9923b914d7dcea537d5ff429e4563f5c36920e2bc5afef5ed99cc72eacd58f742dad4f1bd19298efd50c382c50d726fc2676ab628f2e578ccefa3a526e4473db2209900dc8917b0b6b15d75601747cba05f0f65bc00d5d01c76190b37c318c2eb5ed58616639c26b9b68e97ee64bdd5bbd1df55e966cfa75b79d68b1193cfe13d24f4f81afcd7d07f319af8b6ddb8c323a6e2274da7ad35e12e0c862a95bf3eee053124cdb30c1368dbe432d7ace48807c12585d4e98b7dd17bf929b27ce7d14a4022a48da4f89776c24b56305924b3627368c1c6c4505f01f0ad0e8dc38e38da7e130f11852a31f856596e3b5f0a1e1c79d78d8e4606c0f2e9fe58d91383cd2b44ddb67ed40663fd9fd17473cf4f1a491b9ec7fc7411eddf60bb9b82f17ceba1d295911b59aa2ee2535b1f2a605e3c76577890c67559a8d67e2d120dadbc80bbd1750be7bc0eb6424a51b69c3d289c2dbc1eed8617c80b2c5b7def644824bce58c12447eb8938a4d5f97118cc19f9a749407b281b6a266630e21e5ac7be8e42ae352377f6001396655f03fa50142bf69cb07f1cb7413cc0cd3c44db3f62f6cb0ebf3ad3c3cc824ffa008de8a67a63ffc550b61518c67dd287b662cbdb844fb4898b84600f9717848fc375dc485a1574680f11c49cee1e8a15b032ea93aec0d6e3f74a2579eea6a3c729b82420c0b9f0b5c1c3a8d0256d1c38fb9bbe4fd185e86ce156c8d165d1942a7a5a4d2d41d36426a3a78a97b2500acba8e9fa03555bd8c378018aaebcb4295af17fa46bad3418d9c613bf1f44ab38b130c33ab640a9f066d588d0d0a1b05ac0cde958d2d0ae6b2b135dcca39394e0dcdf918053fb6ce408d0a97aadddfd2ad97f22edc1a4869bf9890e938740fd3777c9ba9138aaeff91c0ddeced80cb53fb761a417e00408f2731959b47d7368eb5027f45bc25623272c08afd192e9ed8f5ead2c26f733b4e2cf5f8a2f6da7022d6585946923f118ff91a97e6a750c64da1318c001bab09dad009168a55400472249a4d9abe2372ec0b66ebae3ee9767c2b4de98aeaa0f56198ea89082e1690066d9f16eb5e9f762f7e53f7424044fb43d5ee0e8b166c674e114724717bceebd5fc9f2c89894031bbf910a40f8f2720dad5fdbdf7aea97d1746f6eceb043d97c1b96047b71ce9cb0920e0360cbc87c30c8248f9669c9169e15f432e0e6cdb734f2ef71ea741783d73b958ec2050cb79bc748b294dd5e53b38becad249946b5f3357f649ccafff97c617cc5048f591443044f934f5332123a6a0cf846d5a4", .Okay}, + {.Sqr, "82088ce4bcbd905214a83850ed0c9536420417331e74e46bde25142be8fef549dc7619cafb112bde25b45461c7e495ab7db16e8ea8d7811db77fe3a3b3971ea6d4f9f70a47e9a4f9ff2d8be0a208dee4d392934b268e434eab0ecda345bfad224458e68f0cce3e8242640b430e898488e8896f89f5ecf330e2a3bfb18aa32015656e475d86ccae454faaa771a2acad2a7065d6f11847bbeb1fcd45077aa8e71a03dc21251c66d3e6aa44414983c6858fe4eaafdbd15ca42fcfbac9f85ca80a0bb49f3ab24a0c68f94e478d2ee3d6cf13389ab8b384a02949eedf042f9d85229e25a38942f3c9117802b41a1556047a3f2a709d564bc0fa7fe01362e7ba32a7fad259678b9da9a5dda3b73fe64f79d1ae310d173d2175895ba28496386abdf7f6041461d5a6ee5a06ce509dcf388704399ad86191772cbfdcdb64636143926c57c2b8b00c0772bd31579e520a46be72334710d5bfba7a9c78b84a8112cbae7043c791b7f2f20ed11f4161d0356b971559ae58de52b648540df85027d2d3e96312bd9a6050b350f3c88e3c758e581ffad0860c9bcf8e7eb084aa138b602aa1b8da48096b9517c1bf0ee5f68e4be5f55c5678ad9535d8ebfec7287cf1696d7f04bcc66950b2487e6f735476ac0d78388f7c8dead323e7bc1d120ff47a7c679e5e2f55c586546115063daa30685342c89cf3c2d56962b369e648cec09628aed22dba", "bf35268e536991a62732c6f4105eb31609b3150ede65538215bff041be069346a3fb8717e1ff9fa844c8e60087fa41324c444048e5e205b87b3d1acb790b5b4f06121c0389f15240716214e6a553468b4c8813c59863bf4fb0f0bda1d210a03a2452278029b345b6ffeaaa1b0a16ac190657a2db693771a5eeb432317d2b21c0e6f539473cb76a945fd78660a1b7d82fbf49752074fd7aedebc39157af3cc06f9af258535bb5832eb55e6dcca364198e08f053b2b8c34afe0d5380e01e02d28f4a40c5cf8b7848308e69e573ba4b509dc34619db16eca1b50aee5f870ad8c0cfe0ce8a87718d1522c6852a1e02980a846a712922b70f9ac3a52f0613dfe977636fefc782e72c84a89a4b9a3d09ed467803e764b6267f98f7b96c81783b4dd19a5b212ace8a46afb8b27381dcb47440bdbb3c507f3c2d3fd49a178e0bbe3ae9c054f892a30274411d40ff178699fb3c5e082303bc756443b19c917ed0690e144ed43d79d29c49b6a1fe95867734255f320d9b2f5dd01eac4fd0791e7a002d9a66ac09282a8a7269f003f4ef46c1de29e996a1415850f0e4800ecbfa768f4885d3e6f66ba80e82cd5893ad0babb1edc33cdec36af64fb0fa6baf8c1af992576a24a6a791a8899ba54263bb463fddc7edddbb81f4cf0c210bfe3f982da0573e253eb8287f327ee2dc92fb24144f202050558563522bcd765c9bafdeba5ef580c9ab", "420caf616b874d3c74c5f4d977f27068f07fbe44116e91ecff8401b31bbeaf92deaa429df07a9fc44bbe750394df6208c0890bc7b6af7b7628f57ea1ff42df6c10a9a130834a6e348dd68ef109ae263b74f69d987631933bf7ecbe917ee4c2bf0413fdca45e100a9767eed6fd31e923fbc9f63a046af8c7952f62c1adb60e236486e7b0a21efa7038ba76c53acb84717640a5ef64f8ecc4f6563e6ea101ba7c710f4e719b0bd413085ffcf06af5b2556014dbc87d93addf40dd0341addf4b6dcf058c8fd3283ba597ab682aa07ecc0185533869cb4a8542f797317dbbfcad9292521f8df320ad26ec76efa016f64f5249007c20b3a0482000af19af4d8676ddc3379c3a89063e021d1e7058023d2e9faefd18451132e3134d15de01097cad42058c21bdfe4a125542ac2ba5d62b26d6ee37b15941e3f38be87a738f22d7115aaba7f3759c7ac7e6f17f430612fc385884d66bb35c3b7d6e2ce449dc830b4e2d3dbf983edd508a16acef81eb6a3fc8144a0c35db6782f49aae7f66e788331306317e918d16ee54c04339d6a828e59bacb0c13d11e2a43ed9e3b2c980548998c951ef8ea1eae2bccd674ad50e48135c9697375718ea15cc7af7e5db48db68956b9316edfea016cea0ea5d829ae2d14ab725cde964c16597fd1ff8b2c6296cc503cc4bc812e8b9dd8e781e43afc1d9db9e01a3bcdc794f2c8aed197133ca33b98a12a8702566dda0d7b2963e1da23943c96123add3ddd749f0757a0884a510da38decb5813268a99422d7d747d3569600d1cfbcafca26b1ffb24e509fe9d6c7775a0f80bfeeeb2cf3e816556b537400be0751b084704071dd0f60200743d0dbdbc5dd56b73449997f4d511d25d3c9b9f1c64b022449d2c6d9b787d7074608412319c5b9507cd465b37c7961fcb43773154caa558672d3f9374fd8d8f649c9df9350663e341278b268ff2783a09e11d3a4cbcf3ecbc12e439604aceaf84b317e61c1e1b59d3ac3aae88eb4f2d3c46f196eaa1f37df0240c7800b31176042950456420a20e5e96dab84ab518ed69782d4f7d90593f679bdd29dd2cdf886780c26464c31082a8dccd2f3af49d6dd0afdfeb204d46fa2d7243988d6a4b8f1b9966e14491c3086f59c1794b229f960607daadcf92c3f4027a4b829506aa093514b5acc2bc3ec01d01c59b81a483776ce2a277e1da1f95078941234bded19b6b7209bd81d9f906d7a53f716ea647fd4398a23734c3fc0494da1228b37c244566da46e7e15e033458182c35d8cdc4250f060e279ab73e68dbc00da9bc9baf0f10cd54b961ab614457aaead5464ed6d5d641bd21b733a83bdd8bbd057eca0c46125aebc4496f102151cd54f40ef0dbfb7ba0a0214b1c22b407cf988ff085f91dfeb23651652384f6381aac513a169c23223bca920e754eafe52ad6c20d155a6a4d7e552eb24", .Okay}, + {.Sqr, "-c0b8ca34bb404a005cf709a260830574ccfbf1a26cc5d46b25a98cc91055df7c3679e5a6010ddfd92a9c3166810d4ff20590fcced35b6bd250a4a8a346c1c4ced170f17db46f62b40cea2d7e23ab8df2b7a0a223265696792a986a3cd0cc939d435a1e9a0e8d175fdf51953b15423ef8d2378e3f94db920ed20d8b3c68958bd37d364624761aec03e415e475285fa859fcee6fb5337245bdfd4c411365a45f7789548ad60216ec68cd43d8c7d3e0df65fbeda1cfdb042e0f65086edfbe6664d8921a544666dad923a6154c43c19773a3a66c466496c92dfda05055b615f16827138de9fdf22016e0c6d8e1d686fd59e48f1edfd2316bbb4c2ef155fe2fed0bfdc6b558cd495d57b0e29facb54d2ece92d9a0428c7e1b4903df6b22b628ae1efcdd6c3d7bc3b2d0e0ad87b10ea0d7e0774b01d79080869268df4928c361eac222c3b6ab738bf0b74bbd7fea324a1a8f11c08109a6aa40f4a22c49799986b12897671d66c2cf8536e826eac7adb69e7962eb39496f04b329b1a316cd3b4aa580ef4e268e533772da27159d317a91fba85f110c687d17f253fbb31d04a87fbb3e71ef84aa860951d1abd40efd1771a26b3e5cbe276278aeb5552f518f931e013d5f6d49abdc97230f34ccb980544a8fdb8e1818b01f3877e4501e83db22adc721aa45b695d26543d88197aa6f3edaf948aea19796af05d9b8fc017d73a426ef684d", "214611df0c6d9ca3ac517a4975df560815c05cb7bc88a773ef5d0008ec6b0d29c80d370d144d6c00c3f4ba29d0a78cf9769c062165f728449064f18a909e40b09c25682f877274fe4812575bee65d96b968fc8f65bf54abe89a27ae57669cbfa4282ff7bb399799a6f9df523caaaf7a8e1e3eaa6d0d3ebd44e714f6f5b974774a8f31843d64a635430c6f9c1eb4cfde4ac7a7af59ca049c859e15df1f0496a63511ad78111c0fc0c4f3b91b4373f161d8652964ec5a4624efc7c6e8a476cb7f947e30946a3e9a8fdf259791fe18c28f2ab4cecb9afdfd8207b611904ef695a24f1787027bedbb9e6861dda309ac91dbab950e36e93b840e3033d7819d6c1d8088e9469c1b76dbddced8135c58a098a7b9213f22ec18d7926a409410e0ded17d7c341631f00acaff73bfd361b4b667e4ba435164c96bd41a0de0ae77d1ed367e7dc606d085cc49ca88feb53af004bd63d96d60fb2003ca97f9c604c854f83a1677f1dc7f1aa4b54a2b3ae9930cc2a0d7582c2fed3980580ca98a56f208a7fd313e467d8c44104cd23d21d1567aaa44bc747d13ca64572fa6310a7db090215b2a82feae6b9acf81737409f55cb65692db1688e4a39961ddcfcaa808209f5125f31275a599730a4537009592fcf6080f5afd5554aa368b55d1277eb67a5a08321305d18ebc086aadde560af023837b84c3f59ecb3b9754313aac17f4b35b4bd1e81", "9115b4b26464ddc8fbd5d0aea723082402bb2827466aeaac353d713c50d91c5fbe7c45eae6ae7ebc2f6503d23d8b8b8a5ed4d9c8a55c8c58a519250620e8073ebf7ef1a84d673948af00580591df3d59aaf77812225e6bf259ddbf4bdef0ce20469d56f59fba19c851fdcadaa00ec0e77da01780a99b859f0cae9c3f5a859c08156f874656325b8ac218105982e5247fc992ed8dc791d469c439ab0efec4eff513e1553b9dcc1b021450619b9b6a9ccd966e4629455d2ab7f1892345161b526fd4213382615ecf05e4274db5e4d45a440724389b6e0fd55c6db7fcf74acf94d4454465aff64b0090dcef25e121f242dd8f927a4a73d856cd5c88425e1e7e29c4784f0c4d13170f50c4fd188dee5c2d25bc82088c399299875508234abcf4737b2d6a5bccc934b9766eacd092ca35996e39f508fa781d5f94b7a4867e8165997781b7918fe7a1066af44128d3f46b8a1e0377d7cf8153722f00a1ce5361fbd92750992539e388a3274ab99b64c74dc8dac19d5e728abaaa5716f0549c7cf213c8620890e3491698391271a4078b8facbd49ca6f0fe2903427f05b54481eda364a4e7ad4c68e2339254a351a43c8d904605bb4e45f46dd65e8e87090ff2d05d4b1d3c7777e53603f498bbfee5e0a78b6476a5407c6d3476dc0ad63ba40b89eadbbbd66945173e561cf1eb0cd091ae6a171ad36ce3d3ee768f929f548e4a08d5b2957fd8b119bb6a5adb1bca994c2ca6e602de7a7e6661f6e659c5965d13751ae6520f0d121b2efbf7736b6198c67be0dd819165826fe01b9b3a286d3520785d8341e66277c79b145da397577fa99dcaa413b56219c986ba79200b9db51e3a21725db0c5130859210d24fa80aef52559b61e521a15fdbe0ff6e4111fb1e0e55199fab5c74fdc6096b49705b7372a86c8984a8aa09baf8bc1f640da4dced2d60c58d4948aa790d47734cd6422006b0cd49cebd2fe16400c2ecfc44284e08ea5f72a66281b298b7af2c21b9b578a8086e6779f63f7fc5d9af1fd18b73f4eb277e61a9e1d75200109f20ff57ebdf1e376f00aa8c747c59017101203e78b6fede2ae3ee77fbedb39e3539d8a31616104473fd4d8d87b0c0456119141cc2f815a9f085a765b73b93de39959d963835c0ddaba02057d281b976284f2042d2b72b4a0eeaaf1d2706505eca1b5f531ea3fb75322d440deb8417570ef480749eb556374e66176ea63057351c5d5f452b33493cf367ece362a228d0cada375bad55639404581fafcd6192c16d6b54a40a1d7e7af98597ea843139f2788936360997154949a8c7a12fb53eb1366512eceae19070ff32ed82de188c703af5a42e66517458c6f4aa846534084571d31d71f6bbc9157c8253d8ae9908d705a48bc7afb61a3f11a7b6c97d32920fe5a8524ba451d48c8347c1696a0cbe0ca6d0717590c382c644a729", .Okay}, + {.Sqr, "-614bec78b75223cdbaa55fb11bab1401edc8d94fca6774f6e453e42a9706818f4235080a15839b0502da9eacf728322aed894d2f556c3a73113e5e56ef5854aa9a6d462dce121ac580fcc77fc62b257446cf584724946cf1e48a9c29f401326eb61c48522dceb108573b810bd5707dc25acc1281160d83d96bc19eb313f97ec56250eedf4523c0394c35fdb3255857c234b2ab6bba8b7cf167b1035df83a2b199d4823acef93e622fc13c4b0fa154c92cf78a9f3d7a4668084da7e9328f85151a71ee6177587d188439a51f43a65e47864c48d2792d4c38edfb4bddda3b3a1425851c572fa5b7948774214f9b69c5176e12a010d5503b6c6aaa329a65b475dd3a99a0da89afaf5893139d81c8ef47b8cbb05ff751a0c6cf44814712975b6428ebf1053172efaa7072def19375ca497aa3da856ed666eb89149c82f2ad68db5c25ab54751e9e72eb21ec52a2fbc9d5df3c3db1b9edddc892658c739bdfb216952f82629b272b53740b02457f19b297e5e194ef16b4450c879f77924510ffe5a6374ee36d27f09f91b3365590f0be6fad101171ab924781f3c2e3cbb8a06ab4f6e05839e9afc3a3f7e7f2d62de8ccb67d489b8fe64301314c599ef096af1101b7f60ed12fc98a4b72b39ceba383f8c0adbc882326595c4b147ba35f465139c79d8c88138463d274bd6d354b96ee75afe50b832cdaec0a5518af1590ae5187dd6f8", "d0f4cc86cb138163c878a2bb90b5b4fdf0a2ccabd010f1f717b2e88d255c80c205f2ce29426065c5c35f3a04d31a4fca85429a2ad3304ec0c353978b9bc1a6bd8e47c166b6c8f003f46e756b93db72d74bea9e972aba41482d1c7f2f8f34e92f9e39a76adae7a8ab308777a84e5c93335fcd00467eb530268f80bc8ad62a0404d5acbeaf610f503012e1656af5504d2611bcf82d734899b5a1166d5b2e83ef871f7bbb25136f75d70e5423abc35b82ebe2acc2216c6bd5670c36ef5c913ba91c300827ae962b729507badf17e573ccfa2edfdb2932a85a8318b83d6526e589ddbb54989a5d4633670eb80014d5a881afff88123ca0de13a9fc75842859cf5529580e15a9a900929f710d4a7b344971eddf92c3dc5c5bec42d1e598004c443864ed88468eceda33d205e46fe1b4fda2608ec2ad9d97d1538bd056fd8dbcd459ba46a0d256827957823eb66dd3e6c3ab5fcfb8fdf7a48e98dc9a20652e7d5d7e3511ae2cb4dec2f74a8346393fc04fc0ec61be92784d949358341a00c0a69502fd491c9f8f522c452771d465ec6bbe973da77425b402cef738726268d251ccc27c8c6a137f63e7ae72a1f46f1b806ce897f36a418cbd90f3ae9bc928ddb122cbf9373f5535900b1f9d6259e9a1efc28810a395639b21fa478941be26d2b316c507162c32984b36e3a32bf7bead17acd937a2833465d41b0e2c95c5e48d6eb24c6f", "24fa9fb7e416742eb44819f541dc0392bcb891e38e0915600258a985274e336232a2cc15c3b90662ec7136e99d076cf3a0b32158570d8815b974fc38250db6f7702eb70797ff31111e1b1a5b64026601d0cd88cc284ac25886926fef91672d9a3c9cb7e7dabee6de10a4fbcae55a5a0538368cabe7ea5af36e6dbc7e6053cbb7cb51628399692ae65be202929c24f52ba3152f55f134d2c48353304b8426f5314248913a608622e4aedcc0678c687f86e7d71329dfcd4107c00230945512af76da010af6f2884a4907985166427a488eea0a3ab473424ce87fa1ef9d339cc138f1b4e48f13eb7a55ca781852f7324ff93ed87cc68d3ed8da0a45f8991dab726bae1fac3401d095db02c221b2ab40e09de1bc16aa78487149b648c97d067b166e0ea7b5a54229e1beb5b5b1a0ae20e09f394694d4013ab78568709e4f327f75c6ca92fcde5d45c2d122d3da218e46e26057c40418d2b4b82b626d97ce61342508bf5c6bf605f02385cc19085b4b2a0084c7c3fa81a5033d430b721f7376940277b2103c876b9792409c6a3ce8eb733b01a92450a391542d82d82d328ef8f9e4340494a79df2356e5f859c18522ae42070c71aec2b72be481cf3173f16f013259b541e993264c95084b4f9bda44816dd5c57a0f8fad44778c64b68aac6d3e2bd5a3aa57fd625b1816e1ce3c05c6d727ed76c03c1a5a750c7f19a2693b469172f00ccfe93b1a3464eba4f7498b3c2ba85289b32efe36624494e44c3699c4ab45de0afb26893e39cd0f6582163f07f2a2414b78d89956bea1f505d25f05965451657c7024c8e4636baa73dda67527436ff21ed584da094bc158bb31be513bcf1aa25845dff79832c5068eaf3e41354bbb37a4d68988e66bfa8c1cc53ea5d16396cfee6046b637e9156ce313983a105545043d6e9ea01d9481be49200325436b00804a8561727d69422e6b6e31e93ac9a022b9a7c326250468e019fc05d54379bc7f9c8ef2805f078893e84729d9ab425e9579f605250a4250267d61ec09da1d3585bfe1559e2ba37c929e07a8fcc1a2a289c9901d475aca0162f7f8b6b4906945c711e48a19691216d26150dac82c2383f08bc614ddb801d2aeda870548aeb61584fcb9a90711a8d9fcff65d4b6542fcf94c00c6da4aac9d68114a84d8da61e9cb97723cb333e38ab6b62a0cd1f0ce9e8abf662278d13eaed03ee399923c71059a176b0adbdf6cc4a99887e4f4f23eaf07a2535b6e1005ba735506135754ebd8dbd4c3e3d02b52fb52250daa204e7afc37091a1c9505028d4a191c27e989ba7c86bcc193085e04a4d96c8e9fe52a5d8e23ea3c4025b11b3f49cbce511093ae2687a6d8304e59bd2b40d668c629104277dc42b7c4817ad2664fdf105a889d3af426a64376330e01ba03803fa6f644a1e48f166eb53bc511435c8d10b5cdda22b39040", .Okay}, + {.Sqr, "-c761f50f88259ff25e60b40d3749ad9d636cb2481faee948c6cb08133dab92de882013d85fb86e1c9d1aca10feb00a2f5cd1e7e98711b9cb3c1552c0ecfc1b83df5d3c28bfa31beb0fb12f359cfd9e27b2196c968ea9b9da2ef1a1e824f05bd6175a20fc8b593942c0f657053b819cc25ef744f4201c0c8b9ee3d4205d556eaff35063a99b7826e89516ac51b4256c2cdc248693867a5ad4ba9ca95659137ad8ffe4decc1ed03ffbde9601f5200a8d9d409dccf9aa61694b76ef93523844f87dbfe29787099631c11d75f2fa6e6c3304a8d045cdea1a804231c982f971a20be4d625b1cab0e370e2ade1a8308717f2ac8e4e6fe38098038d9189bd3e6c2a10f02fd5d6dfb635cd1708339229902b290760495274b64f0e7893cdef522bc062274fd4bbaf5759afa6566158b78d7fb6d303c137a92bb8154cc63d8efa696a1097b34b4159bae2522cd6fecfc9efe1c1a782846460cf2f8f2a46faab60bda2911fcfe71a967d921539d313cce325021d88ab39a6755d07e743c38fe6f2fea43addea6bf6cb848450fd69cbcdc58f32fcaa3767903d4193692ba307cedbc737e4475a829f48dc0d395505d667e9043faeec30c39184cb5f7ded1958726b7d0035557302ca994978e0edb5d9f865f4fa32c4ba14ae71c11ddf0d4b6627c6d1c137043ee0ada65894e24d6679e5fa1c9a1405162a14305db14a309be385574c75541d", "863b6e8bd5a807cee867934583682904aec9bb159ab7f6d33a30a4fa7b032258ce71449f41e434fb43da15fb6c2a9b293d7f5e6ff121de3921bbd96bf6c8ef93f5a64aff3f2f1799f6f509b7d8efad1e1a5def9bbff6fb0ee0928254d55fc025d71925913ebe64901236d5bd21168a1fb360422c7244befaaadc0c58ddbc799c3ed71eb0e6db2b793f3e476ece07f84e219e947f90df94c1507661176ca3141644261984594357da92a4b81933244db7f7da261ecbfad2af0cc4efe1e924ad9815c3b297ceca63e69ef33ded6b64f9ce2b04fd33d3ec8ce81bef1ab90911044fdda0774f37cb30d83d5c6ff194f148eac011b4b065f7bda244d83fac808e63d613c00b5ac21cef75edbe1630c6e1da18ccbf487a21125b2801e43626607c84734c13a66bf088302293c7c2a0d974e936a54d81796cecbde36de699fa032e7362434c7bee578a1d1e0716adc75279efdfdc33341f6c177aee42f9135772f28f76b89318d9bf3c140d28e5f253dfc02f9a218b162de8369bd4b7e134566ca2aabf7f060f344cf7feed6d34e2881f0a72b58935f44823b1348cac594379f044e5c2e2ba0d22b67cce87050f4522830728a82ea21e0b27c6cf6a7ee20336ff7aae8c5827b13b622c580c297ac1836e04d932e32ab6c52da742ff9d288f6c899fe7ed87670cff5aaaca657281d4bf2d44fadfd51bcbddf86063a03bc7a2f94ceba1e5", "9b497079c60666b7455c83ba4a33d5148aa22e79a323056da954afa39bc52491fe8054e39048ea836bf9a0509a8759612ac342e9be7ff89afd0c3f4376f3ded3066ff9ecc4ef0007b92be78dfd2757a2417989a3679ee5780ac5c87f2ea9f214d7406644bb8f8aa7d6038121e72fb665ee2cc8573bb2056b5ecaf3889dcef165af4f62bb272e48d91e84d9f7d39c9c881eaf337b8b198dbccaa2c36ea47482cc34004ba9bd4433ec69f414e4b87f1686badb52cbf327b7d8ab07d8fd63678fcdb1e5c820e43ce743584bd93bcfc5e36b3bdc6d0111ecfcfe4937a3084f09bcbe6f5b6781f628a5a2bd3cbc57de0b481d1d078a266193d95980c6842dca973e4579aaab5c069925723144dbc6998e1083a34043ebb72b4e87d60abb9e4e8e115f88ed0a94dba6c487ca52a7ecb8a54ded66838decb07404d85f4ee7e7cc7f4911d802721ceb8f5faed3745c611907103cd3fa961801dac3e610d23231061fa038e16dc41d71f89406223f4124e457ebe9ee9c98bb71f9a0d41617383dbab27e7c31f6b99f4cd05bea73427c7260c81a340ce08899e62c275ad86e7d3e2965d07206a8509b8fc6ffa2d21ca3e69a7c5cbccb52b3704cebeb7e5ac483085ec6ecc12217c06d75ea63689b00c7a8bd7364f88764bccf20c485edd4470cdfb791858fd955f01452ee44f9f2b7a4b9034edd6c92dab81b25c7265907bc2ca3805ad591eb56a14e7632e50ea74d13e7bdcb50c3438bd505bae67ee9bc59709ab2561caa2e76383d25359aadd6dab34d7358cbf040058360bab37ca6e43a0b5d49893b4ac88bf4fc41e5ba842f395e8cb4c7e72981c2781cf80de54523eab0dc0432a834602ef9073da04b554b7bc33f84018aad59e6e8544af9017ecf79be73ef11d5490e1580ebc99df4056deb9ecf09f85da7e6b2b42b16e435c2eca2a33c79abad0089100081109002973f6ab333db9f5f8b82472d4711b080101c46602f9543a0cbc173c7e4879ac34589f34af1ebceb0feb4f8c1d60e40097377eb81d63d7ed8264e2121576ffb5c972ecc80f57d2cd526e8501b5439c26d9fc007b641e3c2abf2d1f4c72e582aa34c69e121605b230d316b669a53a08f801fd19a7da5d73d7c489b474a5d8715a6fc8bfd0fcd0fc33e6b94d7040bf149f36d12f7595998b66b9058e45b1183e9ad34c08ef1bf5589ddc93108812e7b5933fe2350953baddea6b8f4ee4dc9ff9cc7902ed62905fce2cd9b4ef937cff08bfe90f6098cacf30147ce3672022582500daa0a40243dadb6c6fb0c308498fea6b5581a5a986ae0f32d0a7b598c512cd1355ad0d79082abe2003a82eda0ecfd5027181ffa20d36a9f20acc3f50b5861fea2fb49389b1999c3050bcd872395f41390c18196ec4248de3c2906f95839adacd08ab1a4a2669e89b99fc442d2d95795ce0541692d6d36250b49", .Okay}, + {.Sqr, "-85cb44423078c7b74ee9790f301bdda19ebea4c81c93a8864d730b855ac8840f7fddfc8a612a8e9bc841149070925ff17f6782f09f6899f367450b6ad5f1f33084ccbbf24214e7476cc24078621a155ff344ab9262f33b2d052484033143a5c7fc050c1492af3b5bd876efd610646fff1fb662ea5af74fce9abab7ce34cef76df886e9df13faa3875e455e7ac4d387d660146090a5c9bd12c22bb5e11d22b7dc36fcc041c856476429dd958cba997788c220eb7d135a3c0b0b585e8e37e7126f26a01525ba0692db8cb0d10b820c2b8cb4bea1551d532290e2f4b865d0c7fde05b4deebc5c5c363fb44328ef4446add61a7807c6587ca2b7110090afe726920433aa452da2818ceeb8a0d20d56fdf1b4cae4e1ee2a985d6fb331e1b795921ed489206c8626b9a68be46679cfda4ba4489ce8dd94b58817af366f340634b8795aee1b1a74b7510033e62cc8a394b52b9f63c731744414462a715d5447544a11aff038bfbb0cb5da09277df9f1de92ac9e810fd6f9cd3507f5bf1002fd3509ccc25918c661014042c8f064d226e7c3e6f9094c9a01f8de29a15507a2f09f88dd0cd88a6d2e59c11198bf967e7297fd11b7edf0eb05edc385ad986cd524b02fd7c3768d273275d1871c584d1ab8a8fe501dc3ea6e258c279cfd58bf1bd901dd855294ef36407e0b348f26b4999443633c92cf6f164b8a747f2725d4de62e84e6bca", "e7e2bff5d119cbb6cf962326297267ed4796ce847f2944af711c13f7b89f9e828da748defafeb286dc6b26e3bec2fc86be6992feae9208a1752a26d2ea71f99af479197620739cc55f70da45874af65d6185abb1a2a469108d311d002737a14d4b1dac06c66d59e28842823b69cce1b7677cba980f058f1c988ac6448275280adbe219e63c4f068a9a7da1bfa67325e4f44b346b4ce2302dd28f5f0316b862bd2fe1bc3a639666bb211bde6454de467b387f27b2b7ced52f41adcdad9c717eb9f6562ce94571ff07ee1c1cc93e12b17feae406a557a195964189b218483de5908dcbd2b7365cb77f301832134a369e00ef287ca78d5f5ac2abddb20c894a7ecb3098638ed2c78276ef54bd3155c7a54a3ce8e9c1eec847a1287e0074fa0c828d7a218f5b3306396e15c39490c3584f11e9814ae45a1e7a4970ac1df24800d18fdecaabe6efb4c0f511afd9d7330af09305d869053a3df2e68666343ebfcd575ae149686100dba70fd781f0c90b17bede425375e522ac919e8a9f4331d3b2c33060275edffb60ea72f4e814d9032161e8522ce4bd898e6452d7b5eaf0c0b740b97458943e017585bf7d61b27814b789df9fd9dc77c7fca3cc9b4fd43c670e05c5f8c5ade2d011631d9f88c837ae63480963742667c99602a63fb977c72dcc743bed698b30eb643528ed1a76b848f15095e9d210fe7f5a745d80ddc096a6b74311", "45ecd652198999ee66439e611405c6171dfb55adba906231cef3d3907c9c7ee0d463b7d63267f2cf9f06fca31e284535b81695d2c0d15a7f858212062bf8a2a56116bb79622a0274173d5e9cc26f8c90abf01490632b93720a9aca28455ae46ad2487561c7bbe98124bb6f0ce10ced8b98b6354d673c82d3904f8d059f2e52167c8b4c31fc6e27c5ed867e717ca7f5c2a042b06968ad20bb58287e25a3c4729675438780b96860c66f65389e96804b8f8b9511f300cbdb9d9e2a1cdf64acd01df2423f0814043861e9806c3cb76644c15739d328a88d4528bb150fbb2d4ad7bca5dd2a171f1863899ae93871d85b85bb232b9a1a6128d9c27741432fbbeafe9d942bffe2bd67e434fd3791a4af1cb25f17b4c30ff2d14f5b7bd4305405ca01aad577cc3d44251c5842e4ac83a498b8e7bd3457d4856ca71339ec65f2bf13458b8eb3e535129d4d4ed042f04844bdfcec5c7e57eb2feca26447bb204873e84383b354f1b5325560b7fa2cd19613dfdebb13aaa5fb89dfe06f3a0dea3aafa21d9f4f01cfe8512d72a649fb81f428bae1301deef0bbb8387ddb59d6f87d3c6b59a233881d023994ac8c8f59cc9dc565d7d973234033e0b4903511b45373d4f08764af11719adc7581bead4a35e8810055ee60feac16fcb7a2a4e5771ed5d1224e1ce4edd2f9adef958efdc7c6640ad43e5a5299eea0477c58a2495f4ff1997c27b0a6c825ce9cfe1c1dcc03675f0fa90c4166e3976923795f222b2a2d37ede02186e3e998ebbe10c7f01eee9ea2e6e1f49b72fd26f98bcd942afa3ea438c5bc50bd9b9373c08443bd6d12bf069d7d7b73ea3504a8e25b2a0258436a99ded0a1046f8accfbc72a63fbdec228acdb6705f8b6e1023013ba0f27a77e2377f6a93701964ddf140173c3fafbd2393306f4dbfa17961412e28aed681c8bbe34ae45ea97836fb3104f0b7e74ebb6125d23eacb39b38eb1b590084edd8bfe952e906a30b9f106657750411843e2bc889b33913d440eec9cb9c45436e343c54ecf05ce52f2cf59d1e49cd46bb320914386094e4be3f72bb88916d3b6d35f6e6c66ecf7a202c421f7bd528d9994e64f246444e30c4c2ea2b31b18683cdb037dad941aab02710d0bae40856b22e353df09ffd7d70044af0667ee46a1d1647082b1f2d5614f8a4530dfce88cac922e20c7407d3ccd549cb22ddaae84ce459566caa465846ad5d38a660ec947d5b137454c2c4a2c0c460ffee5454b5192d3b32cd2af17ee22f578cfbdf105ef1e88c592b9f6180d5de212ed8335209130a8834c04dc5de3df696bb74489b86d084622c5c03265911f2065d47d507eb272b165e71a8d2a052acfc3be794f85fdd2bbfb6443b98ed7d77c3980364265a36a64d2dd2ba9e18efd623a92a4cda8da6af682a9cd8ec201408dccdaad6118dba0e61b59c5b1a0bfc7a7b64", .Okay}, + {.Sqr, "-bf938fea7864b47603d6483599f75cf4213217d4c143e84c0746ec1e34b9845d930da515956c6f9a2a930b69b06e1aa839ac90fb8e24a94385290ffe4709a10cf7585270f06fddb5451eb2dad387d3b793bc2a93e9b2836546a87f58fa6de9b7a8762ab04f0205338cc411c833ee2d6817ed883f0d660dfb6f5356aca6a7c78adad67d7c3abc2a4e4e7c45900f57021638ff9f3ff75e96f66179cb36748e549a7590259b75454b200a7837fb67b513b7ebcd8592c343862c533b5f9467c7cb11f00049663516899123fe4e6faf1baf91c4ca8df1712ecb704e0196054f4d1a2003dc429a5f0ed3775aadc9dcddfb50b61a6e552192836164b6f6a94faf8515b99168aa3cadbee8f7d3999e5277319853cc4450d3a1d58658d7889c2961530d1639cbaa9f88f5ddc8c7d4f1172487f965c58a2956ab576956755a4c4ad9530f35b95d22bdd4cccbe49d41f06d670fc75a2481d032be6e31f75472cb2ce77f76ac24b73e8c3e0c0b4d149c4b07e7eaeab4b407573bcbf43eb74a14d6ae9d3a4c92dbe66df132dede981b0fae46ac1cdb5ea1e10e26e0274829bd661800328dc3a91ef809fc6d904342e0e94eff2ebda43dc2678637508012b089edfae4d35102d511d4d80880281745ad3670dd3a02752259fa407320e215d35c17c9e5d7adb93b03e80447f5dee1968a2f08536ebd2c075ee753c42d5d704edbb1c938a2f6a58e", "67e4a601bf3544eb62832f90cf5235d3d5149fe267a173bd66b007e2e424abb08ff4c86679d53786a62dbd328b164faa0a101c74e2d7c5759319fe1f41f591b91af92d76d02d0cdd4c9b1f22668ee6c186f31ee604653f7b3991bd1e7bdfd385b0bb5ee1182d5b6b4431acf429cf61ecbe604fb9b9d7904d97fdc6a6b73930474856aed8ac942e7ecdb6dcba51d960008d22178239fa754ad842831e4eb7b189f5cf97c96c4d9ba0fcdb36cbd7a9620b9af77ab04256e2b4185f17a1203bd3afa95287b9dd218534817ebb7b135c43b2eb8db502871653249500c902d0c25b2c677bd6d16ffa1b221f2d7df8386c5afb635d7e21f35dae2e86609ccde3d0e40d339a01f58f75357318661f39a379278c034bf65218390b075589a7dff3a4471599415f7556485ae093dbc17e36d7a86f0500765c2fb31bab2354dbdd9d4d8bd211705f58f4cf6d82dceb4932b9b3c7a9396bdea0a93a0c1f2fb9805eaa4a85a0ef8444d72bb532a13db7efcab1af6567a2057fd7c5bb2910af61dcbcb2f25faadc4effa716c63cdc010ab337d28fb1dfa2e3c6be2696ce46fc10ab350b1851517be93c902e346f76a707475b32e12f97e19bdd0139a84d3fca4e128f37ab65005f3362730f1420c28e0d94bb87720cd4c7717ba87f92fa0a45abe76568b42df73bd76ee96679e416028be98f02104f9d8708aafae45cdcb71dd174a3a5fd0b29", "8f5d85ce77d452302b9678ab70b7e1b0655265dad51dd641e92bb1d6433293627cec372f66271093f43d6a93f188b7bf42588e2a0b8b4134da045ac4e6c5d815b96745e6fbe1e8449790cb53173bf439a270f3d626122249ede8b1dde58ede4df419cc8072cf04e315e703e6afc5a7eb774753e212cadb048f7fd7a20b6383776ef89d92000568012ddf271b51384af2cd4a846f69661958d06b7747846e3b2d5ba6aa37863bc512274e3f613b99cba84bdcc0aa9e50beee9e134e6ec22153a0ec5e85cdb148abd4e8740282f3beab775660129a07eb6e6b455a0780e715ec5e2d150491c6435740b73c4ff00e4b0e0e2ea143901a93880e1ea5da522baf87710165c5414331e1d6fca0745691b1ddaef311cd8aabf7879c33dfd090ca541360ce7f75f61695a6c37e5a8ff9e24c4e84840edc24803093ee56ac81ae85a7c9f7f3801bd8faebfe4f12f0c0e61578b08bf4446bee61d6dfc1a50305abb034b6987af34e9a9501c0078f2cbd81863060fe33e25d59e3c43344d87fbb00b2fa5eb0a739dfdfcaa95a9552ec70ccd42202a948cab43cca9033ade9b28ddf54d6e3073965dd9abda412c36f89988c0c5dc0462619815b695bafa91099c4624e9b471f1cd6ce5e918ca555f4825be74dd6dc63f6c85dc8aab9c77b8be77ce0675fc0326f823f9fd6aea77a869494d18173d55188121c12d6048982f74449d53b6c03590cc6e3b007114882f53007ae08ed637bbcc1e8e9c380f3df515f53a44fba3d91dc413078c4160c3ad338d719b52f1f8686c9e30246aec572fa5dc5d7d29ff6fd985d4cf7bfffb8e3c0a35a6e521f8fa4867d8e0a83e82566dfeff7c1411b53cbc348143458c0afa6e8744a9d27d750fa01c4694169ba9ebcb13b38777ceea22d4321a816de9325fbe12d8ce0ec9ec7aa40fe3e721a74c840c0a7e995714c9b74d71f93242dd656a43d297f0d59152ee555955b6cec88bb32ba5b7de1069ca91c4602cdc286cfba0d0e887a9df176297589a4a00c55a602cdc6080c4c6426be022354bcf669acc0df50fc4fae1bec9ccb9ebab83236beaa182ce83b23d388066afd0d3cd4c4e532269335f78e9fd17a135cf31d429e0f4ff445a89304a27e972eb2a214cfea2c5443cb18ac56a119d69da02116077d87dc30afcb452743de8f0b3062d3e40cdc08346c4796a93ce1efc99aff2047a267d601a502353115f569b4f06d5582d9a42810a7ca26e3ff7bb7fac1dc6720cafc17b3195e8ae9a9c932068008c89762b6f11dc544e70dc052d2a88599ccaebdc3eaa8ac1d88b973b60af31bf1039299b8dee431e88ee2eda0a63f29f3cf9061dc85984c6060374b37d369eb1ce742792625b4beada7013bf01b647e13f2d5482fdd0b08fa5aef18a712ce804476b286671a7e90956b131e79294cd0ae89b219a27748e5fa814a4ff85ac4", .Okay}, + {.Sqr, "97577f7886012d4018b2e90cd3e36f753adf55ebb46c9bda7c3b817d91e7b71f460ad0d36183de1b687f3be560373525d74ab2a54b06f8cbc03c64d6d86607b6d0e20c166dc32c2a6680be357e603b4210dfd29436ad85220aaab6ff022fa4dad66e635da8661d309c6d7ffae358ebb2d201be813429187f8b65a21d77b21d01863b4b5d6188de0023458964d05b3b3ae3822b79cd6e585ff587f0a56cd6fbcb247b02612ace6144745f08d9ff764db118d3a09b9818089fceeea816005676e80ffc43fc76e1c8172649d693e4e100055cd940e73acc3c4268e985470b32b08fdea43410cb8e152753eb52d0a6843d4ab8324de41a7a67c7c699874e96d5669eaee1cd7271df5e4f2445a0f1bfd58718316fe80c6349484e758e3fb0ab8e96fdfd02fdd48b8bbdeb3fdc4318bc42aea265fe26e3161caa3ee8d09d7ecff92e2ece32bbba4b711bb72356c00fd79d438c1fbea5b3c313f68a24a439e1f74eed3693495e7cab32a4220fd3ede0a5e8800c84275b4c889215bf6684597156f04bb86d0cbd1d88b1552fa3076b982daffa0c184b5fb794d0b78e8766010fed3aaeaebb18e26a5df8b89e8de25b120f34b2a5b7f6abe0a3884ffea9ad02332ea1ef7016b80a82149681e0381e293a0802f320ff071992dd72674baf2bc75a837c1d3c30a37855863739ba81cc1ce40bd98fb11b4e94633800b167bcfc50bd33a47e2c", "80ab320cdc91e7fd6c00e9dd4231f5ae17013ca2b562a9c1c8bd550ca04a4ed71542cc498b6f3a87d61b7b4678908de45694fd15842fc9f36a626e86d0eb4709f8870e0a7217e62a6bfe4feedcb0a7d3c642608b97e90b02e20c15badc26acc6098876b16328f3b439b3d652c82681d1e3f57b82215d5ea1b9a5daf506a583e540aa14e312a0bcf96ff40536eb2af076e7fffc59136dd3c580cbeaaca7e5e46b13103abf1827977d5ccd6ae24311ac9155ec687f55925f372b5079d57a3d8ccab5080d194976b996e1f6ea3f53c00fe5ea70cfe3f172b722b299f740a24b434124d3fb5c2b9fb420753881c23936133bad091af933322648ce7556ecc5bcf4ac2d37aeb50e8b5c0e993c72171751c0607b3aca9d89e07fea0411ecf787dd01b5fc4a4524e6474e5cd25238584c397198c482ee597f5dfc37d3ae8e7003b71d3b19a21cc9c6c7bc94459a3e1d2d5878abb8b6e8ab0fd7ef05fdf2cc29a359d372abe3aeb3c15ff1504efabbba7aa3d64e5dcb2b5398341823a7487e0da7e84782743724c2e7f4f13969d8543232de0e5582ec884340fdd5abe9f5208db2d926035dcb8c7e0274cdaef823b145d4c7c632e2da5b250c79744d1a473eb40e3d5955ad9ff37a2c37b662129f9920260d1008942af05cfb3b23e19cde1e0089b8f593d56ac1152bcb0cf7ef98d2e7e393972f1e55b9ec7f3461e6e53d531d19d7621d", "59785648117945e170d91880affe9e6edca11b920eda08317dc2c137d504522d546fd2f9210b168e7b071dfb2ab351435d287e25b71096379eeba28976590b7fe7bfff18f741c35d0a80afa6919c75daa6367d4118560cd75f7ea73ad7c68e408437848283d2a1fda3fb7cf9aa9892fdbe26b2bc87c2241763982f42f4fb52a833524eab8cfa79c110b9ef4b702dbda0f20e9bc771d98119b5282125622d27dbcc6d9ee814faf0eb4dd90acde6c6b5ed47172b4f4739bbde05d32181c0b734cba7697986493bcf2c6c66cca4c6fcc80817538bc7b5a1e4031145214452c456dbaaa07667b6bf33936f5f2443fcc13628c14b84ffa3157bec44b472961895ddd5c06f9288278807b070fdda7d919dbd633a9318398aa0de4dc23ccbd9b5c44cc43403b075ec64e61e10ea5dd76c0e542c9d42411e093baebf52d5160b62f99a8641773b2a31b1338a675bca6b192d884b5e32106e9308db3db58d101e8a3ee0024849acf66e29398456b1dab6c5fb3dc2e598787028e8e20aaa16860fa5cdfd7ba77a2aea6e49201c1108a3d358c6e3c1907d4b2a6c00d60e4ba3470fc8b5e4cb9c5a73a3b31ddd10d88f32b8e43c5fcd968aebf913f4527cfec036416a183edbc010da4e4903000c5f98204eb559fd9648da33983a48dd69460f47b300487d47dc4c05d45c4612f128e1be44df83f130bd3b06155d2647ec6a85bec5d27f327561a22a639099f67ef7598f215e610ac4fbec7e183d126e3c293461762710339a3cf70a0e72a77ebb6c1c6da4c8bbc31820517d9e5706958024eabf9919060796f7ede5b93c6796b1000e3f71305ed9e48645930d4096536098e8a45e1f1602f3579d8a7ea30284aef62de56dd4d5e4f5cdf4989332a737321334be2b84e23f931e9734ad1eebb4288334f6bf525e09c28b85a21fa233340655f6b80391779bafb0aead157a9c744720cb3d3d3b0e10734b9dbd942a311ba1eb05b0d79be9d43d42bb505a40933dcf3a0883ac928490207b276dab05c817c39582cd9956e46c3f09aea2072c7830006fbc4e223d8f19b64090150d2dd5b868a2d5eb063eb2689ae442e89d8d194dc09d1292f17777facba0e7322fcaa8048a4f2c6b69882d58e1b10d26e6444882cf8e5b48cdd2e0b78fc7368f5cf9196c6572429eca76dc73b7bee76dae355b26b3423bece3e9cd225bd35cbdd260d6a9b3d2dc50b2f6931a40ec75a606afd303a4c831294b267d2b63dd9491bce89d5c26badb3bc0f74d4b9b4537bc6b616249dfaa78037d19346b2a6174d47f1b9212bc410a33d28190707d505f1450477bc1bf29e6fe08f92c892f94c754848811ca741414ac86dd2a7161902ad8667f3c590c67ba6809b6666c23db32f5a176be171559e0fa0f848b3f3143b7e525545aa7e4e804ec8fbf54026f9ab6962936a470ad20c8c0ef6e8f5790", .Okay}, + {.Sqr, "-75959395c06794b591c23a06544d45e2b8c9e7e71cee565175f61553f18e9ac7ff6540042df84add3359a28e2d9d6e7c86649f8dc481f9cdd3a48d2f994140b4ad6814f7d5c989a152ae278e184f51347dc2ce650573cd56e0f5c9b498ac9419b21095aaf3728f5985bde4abb36f9782741cb2e290af588691d6ecc02e8e29d30b437416e02ad42e5bd7b778b222c0349ec1be3851274c9ad41ad1c4bd371b06971f414375e364e2a732f53038ba11630eecf7883925f96ad4040eefedb4504ae6578e8f21b869ea85603ebb175ca4cab4b578060d76935a2a9186a497fe193b0097e4c80e4d4a361eb5e932e59f719e319fe4712ee5a8ce67396c238bbc7b9fc0969647d344f5bf3f5fdff89dffb1edce5fcc7c25f3cafe9f1e9315e21816a6018c484a2f629a0eb3c86ca6f33e78068d629a765f831e4bde33da683e4198e4481bbda4c2c5aa2b5e62d78f36cb6a059c1c022479aa96d0e56dade7ede9bb002b34fffe34f160d8726a824a8bb7cecbc61879fb325f32afdfce15eb1ea764a22e861c751cc40c02f2b1ba63c32861ce4e32830f1b51150dd50ff6ecd2e123c69df63f1ffb63875ab52b255e03112831d618f35377b204fb28adb207aed291eb19a5b7b363db204d104f6c3f3a56d848e62b834f16385343692800bacb4014deb86b0e28010622dcbd0892804bc6f5561df21f50a21069d544ffb0618b94900b", "9b62eb97143ab7f2ed21e4433110cdbd82c276b12fa96fa5fe888486fb0c5063877ba215ddf3c2c69800162440a4a6f42895dbd9bfcb122b7db3e9001b5b81f3e3fbeeff85c8690b352ed5c342ab0df518e34a464ffc3f3462d0416c9a9aaeb2e7a7f3c765fc1a9a446d27142d759f1aed12c15db421bfa7038237a4455ce5bf300f98293c1db70f9ca6866346a39d6893a4553659a70f5d572c93f841d4e73b220c008b103f0bde8f0e429cd1b276f1330415fc644c4ffc6f00c49f92604c7905c5b6f8333953320e2a0e12168d360cab2d7a0a2054c42ebf8242523742db5d349dadac0bab608c79e41652a304cae963e517783b0a135cb9e3767f57a360357a659cab7832249236a6bc0f6d7ff0df9dec2e9f4b41879809169b1b7777a0e56b5ccceea77185e06a571c1c859f2006ceddfaf264b9ba07b9ccd52db14efaad0adc23a40876e015902c0fce82a4ec5d1c5409337cd6fcde6fcf489e7a2cda6a402d26ba4a1494ffd6d21a690f91aca813078b7ca6aa6eb743a24d6a4af766dbbc75849fd53cb1f115fb4eb48cc2493ea71cd9a9b0ab3fca76ecaac8e0df9410d0e69e766876c29f8986f556e00a193a63d267604a0a71bd3a1a6f9a1c339750a5f326b24dea7c2c65771d5e5616ae1267ac05088173937e86e204a1a0fdc94f6f39f5fef95387c2e1a8a3e67fabe71c26384a979ddddc453dbeae9f425c3638", "3602104c0345f911908e5edb6a48a6a7a95019aa38c599d2323dd208f51e29359ed06e188751b23deddde92af43c376531a41819527d0b32d181887a4c74f3942a644dc2204021ee8790a089a0709be33816e207260b9f1a10c0a40caf5ae6cf6e12595a881f315198bc090521a2f917b4788d32b3a2147ada5abf372edf8d3caf292450668865d40b8064a439360bebbd9cd62ce8d0bfb49dd7092085c2e95d9696789c9e46d8f1bc5be3f64e3254a6fe97b7d37995d9f0849ce8e3886e8820df3791f7645f5bd02498e34fcb956cc58f6fe225d9b001e373723828c57f32bbd3191881cf28b71c9018fa07fde01e3ddb32758d27290fd7d3459ad7bffdb259b9ed6205e2109552b212558a70d56784b7f8f74f3ffb537ab3634d4b2622587c98d471a4ae4cc3a475c440ec2cfc500c571b4dababd30dc76162a840e042181e8b1204b387ddd33a1d36686c39712b6fa5d28419e45af23ef75cfefacac0c238b1b283c3719cfcc835d4febf7579f60b9816e47de17f474452c9bd327d819d137597a31381a753e96d1478733baca5682ab419020d5bbd650806d3d1a41f0b1ff656cbccaf6328d13a4ef28df3e8e7961cc728bdcfa1c3a550f807cbdbefe39cba473c1b3ea3313588e4649f12e24dbb1b5e15ab2502905f8323d9a2da7fb4906eb763e72b200d751172f0f4f0d0b58572c29b5bb229ea6adffcbffa0c25b644ba035f08852e7112d5dced6321119dfde8282002fa3e97768a4e09efb11ffb70dc7fc653f968fa6338443c84b551467016c0d5c20e028eb85eebb0801c2fe69c6f853e1cd03b6c31e1a51ca6e6acfd4727390a2ae2cf78ffd17426f506fdd5ebf50fb4c102833cde57d443de03bf1b2e9c1322a4b5739038385c7743e9da389ed520d92bfbe3e3828d2a3131b9d3caba7839715bbcb171e141cd72cfa0c6e6dda116cc6e4f5d5e7eed5d57389bb97fcfc900001e3f82d21731fb719e9be2c69a0d8243a562452bf6804ccb8d73c5a7851fc3e724807c73351c7014af068870a4c50359437690247e12b3761fec82a89b457b025b37f3db935d6bc3c7c21977888b29fd8826c7bf5587e74cde0fc0f05845a2a78c70ee648d463263c7e34c89e61416152221e2d26ca684d5f142c6cb4a5cfb3cb31d91e16b636027534b19d9f3a3de33627b990b7b06ca81c55da80936d1c9afc0f6b5ff31236232b6b50c888cfa21b563d3ac21ae66c58b5ac313895bb5301ac8ed1d2c9c90651724f6ef44e78870894fb0c56de5ac0386fd69702f5ee65d10d28d553ee0e8373ff05ba77453676f1bd625520efae9b07e0c6156ab7bb080534e8debbd0183b501165a132987f17dbcf437648dcbee9c2be5afb0f1deeed337ea9c2dd21808fb966f81f7244731805e845e1cd7841cf3b84956d81f232e2685a6bec1fbe226a8f2f8cfc46079", .Okay}, + {.Sqr, "-6f87096a80332a42f89bc1216473aae70163eec61a48a3fb9cf9ea06509256ec2a8a04d9ef15e5d68763791b7dda185bec2caca90c98189d19706bd07afba528a114be2a0f6a4e78ba83e596a6d32e76c9f1a8183194b4b93082a82f2772e1d81fc3368e66785549bdd41f3eb39d10b05472b15bf611d1d79d6b7362129787be39036892de144141d5b127ee61b25a20f29d1a16d741c390d2da089b8a3904f958380793ed406cfd9edfbb98595cf628648a685b6fdff4a01767420878c1f8908f05ff3b28acb81d8833da15ad9f4498bc294153e49d45f366b9001f995f836c92134ab3525b6e913b1367a6623f085ebf3864ca6e4b928ae06aa3904729ee36449b52c49e24b3448e99765bf0fbdb38595ef61e83c57822ffdea860f98cc10aad01e900fa62a6dafcdb1d23833eb1fee52cafa5c2a22fb5452c33bb2fac9ff6017825a361525b6d9457d7b57f7917cae0b893dd467b02b474795fecf315563c5b025ce68fc8bb2f66155f4ce4df9b6181db9227a59863bab9e71dc6223291efb5d051fe7e890bfd7bd41779160d0c3369bf1eacf9f4a77517e1cab4216a3b120d6a1e71451dea771d59c157541a27d40a86cf67f1a2bf510aa82abe7873db7d1b6b1910fd65676e0defd2ed98eec6b6cb335975e5e2662d8c0fbdfd68ca193132d9bb26d6f1d948fff744267af583707b62e75276be506fa6164a6e193e976d", "3c6dd14e97d147aa9427c114e2bef7595056a4eb60fd1f0f68567a58069d1ef8abb1b0444d06dcdbaf5761c3e204f495ca4c5d843c814f50239e64954035a1e6938684c3c6927d0159f4b06b9bfcd117a0cc6780c660d0b465b3f21d94b1218fa666c485e5254126fc7538ed3e1ea9df2cefd61b4f359b119072ba33bf0a6bde53e385ef748a23ce2ff5c26c2388e5c198a14c80a91b4d937b930ec69ae3717d854784209b2a1a70f6c24e0d884cc633ca3482e37d518ba6097f19400301369440652b342153f545f4a4ce4ac051c1f152052a40b72863bc49b04497076a027994bedf0da47272ccf27b8177e76adb9f55b8fe602b8fa0f45a8d1ad48fd58f91cf10df1787edbaf90e02946de744fe13f683b39c492bbc007af0abb9ef05da0ff87ed948bc69a96eb2f45984e9ee26a0c09221ea7915dab453fb2c7fffc94a4e83eacde4e9b12240407a1be9c698738d6c3afc90f7a716ceca298f1c30132837a2d58572232a9dd32fa79737d3a5a47c60e16455be1e9ecf674e4b8ccdd7243e1732e70bc7ebf6c4348253d306962b72b31ceaae9b30e2221364b972f7b458c4e86c8afbd591bbab69d7c23674a9346fd3cc1fa11eaaffac7a50238b55bee4d81d94d68c559c42dcdb31f1fb99c57db2c5976f0f43af6df989dad2b94cfecd22d99172096e661f8fe5b8c0be6960c1f06ad3768114f5222fe8ab2227411a8c50", "3096616549d83deea9c42f2e51296332798445fac92fe5e2bfa140b1abc37877e4d0998c3932f592401637fb21476e4ea78ec646dac3d773b4e3c6243101a0e047b25b6265df4fb417ee9d3e811cf3106fe4b08772945d42d902efb227a510d3379fffdb71c600b65e48d602750f7b9eedd6db9ad18b2299526f0d04df837deb4c57ab9ad5b3ec0dd81ca185d90333a75b1007f9fe454a701d1c6588b9fde88695e06b8b9517efb89c30a8d1e9dcb488650291ecc637aba5577045fdb03a3085fed5e86c40eb2be2bff37febd99e489e2f2906d35f8d15de602b65cc95bb30b0df52a124c761904c4148546d5c00881dfc85c30a57c32bb864b320940ece4d584ec51eb78b2a506fac8e6f4c782378e8cee74c2c477d57106d9b6ad3af8ac8b6835ab45cb5d29936aebe03e6d71596c75403c64e55c3d4332ebb6954fe5a6b99bea6f6608627378f96a4c2c28f81794d43febc6c6bac4f9856042011080e2c5c7c31e709b6469c39e27f3edf365be6130739576a4de3012f0160faeaaa3a403e7423546fb28d30a3dd9e45fa52ab5a8077afbeaef97b224f3e42f286c67ee678da758d5bc29836c8abad8630e24e4d6afe7b61a7da4de8907ae82ecbfc72037089d37c19279cbb8e9d44ef0d6475bc966d545a29e26b65f6e419aff81cde771a710aede77b3b14e69cf42fbb0b3f6bbe4b47fd79e4561d4da5b702d866dda849a788b1bad9f1b96a688fcc3e98b60142f34850393a84089af8ffebdb622462a90bcecaca523f14a98069d245d20873611d456e7ad62d70d04e6f8491bdd79b46bad60e68212d230e9fca51cf86e2d5760366773016a9b3db1e00bff579a7f183db5fc94daafa166fcd24e1967978107a8b1cc2d5621d325b766bf66742ca5b666edad06f38aa024527be597bba8559a7f5e7d0e70015ec26f06a6cb0dcc4f82e40dfbf276d736d8718cfe30701d3519f0768c0a06da2c4f3bf7179601f60cd582abc2bc306d8214dd9bd319e110b753c8d80192227d244d5d8a77966e7e564ab0a4c8524e7911320dac76051252b6b14c7a6bb619c1dadfe53f515f1a569e487e5097253acfaaeb9c1ee4ef4a858c15a22d91858c55382768ca22aaf2e54c1928f675c2f59361adc12eae4b24ccfb2c8a79aeee02964f6d6fbeae972ee3780fd11181c1265ee12a024e6a098b2e8726377180b46b38e7cbe85000c8bce1b42eab3659f41e5896cb6253b6b4715c21f5db9a305e350400466c4927615ecc2fc360dc37ca8cc299b11dfe67a511ba967535ad1ef4a384af4e8f2c6e41cb004063502f7b1754e85179b84c3473a92425cd95cd2ea3c495cf36d8e661fec3cc106675399ea16210816d8f3d508ea31459b0efa5a44a96527f326c3ccb6d9eb0d75e06e24a7e3fb2b790041143e25b5a4f5192b212a0dee04c99b468e6e8cfc5dc469", .Okay}, + {.Sqr, "-9ce48078a32a1eaed03eb3db7ccc5df602a8ae9780cd7d129a872f0972696df30e4ef15285144f44f87bf673c279263dbbeaed716f14d0f17aacec0fafea4bf9335b1612fa858108f7e93e46c564efecc83f1af074242b8a6987a485a023b80a944c6668d960b23081c7caa5bb26ca64d5818606eede45f14f259df4ad69092e78a7110bf8b1e357187e7dbc1dd6ea973586343c3fca88202cea5c0b5d9540440cfc13ee91aaa94fea7e83b825e428df5f411bb94786601aef3a4fde033f34a6fac070d3be1b6672e8e7664f5e6aa9b44f7ee3bdb856815ff3d934e983b3b7abf819dd7c2199bd4c0c504dd41b84bf05a875c3ab55bf142cdfd2b6eee50571f436f8f9d2becb9ce87e320020072071b4bf34bd7afb13b31fabc6dfce2b0d6a966601e14215d998dcfada8adaad88f1390b02865797f5c8fc36c035a5d90b344815e193ab055d23fe786f2e92b834e4508ee86017d486ec9cb4440c7a4ef393078ba843e080d3dd8dd41531006c46fd4b3f9536f5df47532314979a3dd3911887636fce70e7bb4f2f7faed9e2c0054cc6e1495d68533bf16da939f3192b83e9596ffd91c59620f334381235587a6f219def51b23f43bffe72c05646170a6beb03b282a8917de1f8eadcf5cdecc9e4c93f6b25e245d614c6ca09757aea4ac50bbf2eafedcb35afbb4678fe8145498952fc907e8e149a328573a10b42f5f10806a3", "563c8913bad660a58253a3141cb5b18b4dde0b97fb310573e399011c2ab38b9690639f1f6be0318a3b464bb4c4b11676fe8574e716ba2c46639f60476d4553c6b19d0a9ac83d3c750599ac8cddad3081a7038ec4d062a44e330010aa1d5d503fc612cb8f6b85c2572f8dc45703294f9d6775a2e1b7d3cf18b7e95287e339bc1c75122dd844b963ce4ece43bdb9dfb3000c6b4077743018febf1c23738e342b74a8932f5e90d8c503dd8588f938609643b1ec0e5a4efa90dc9f9ace81b7b28b04dc97fbd7e44f703974b0db055a1415d83e1156f90cdecd0cc9c5ae63b72ac3319396a3b52dc69207c61ba138a773d11e7d3b71923be356a1ee8eb5a01249afda34deafd4ab671127ea669e836281143786cd8f8c33812bdb82942a1f2b2ae374a5a55d098a953a582dbb8e0ce0c5805da8394d7b4540096fe7b3f17ffa1de5f50925bfc530560e3f7364e91ae0086e2ab2f7b2026ba3041890466fb121c4700de6b606c301b395b67bcc05bae334fba852aa7f1ee4e217bb6ddff559cc6d1c946304140bc220d17ce8e400594e15823ce575483f9f74e86a8a5eb788707e62bd79b461c059a1580972bac7c890c0946fa0fe012dc49a928c07b104400615e0a0c7de0ba97b9128630f69de08bf4f39f5990365538ee884c8ef9fc5ce09cdbd206eec2b7c2289615fa352555e1cf2c97e22cbfb09904ad59face841b5cd846c19", "602748881e36d46f335999067fed16e784bb807ebefd5666e6857524be2a454136a95a4c5e36558c437cc38da2a9198931d5d0e648063cb6089cf8386fd59189e3a94acdbc44e404c3fb6690a048545e77e4a9b09cc9c2e5724b1e1930c1fae3637e8678f9a9ac05a26df427158d1021244902ca8aa55bc5fd956557dc41e1923681318ebfdd9bab87adb4316e65eee1490216cd8cfb5e6d345127cb16556e81cd4711ed3bf101b42cc2cc24c135aa29522b560b510baf563ed78af0d0f097e49852b73a1f08650d9095f51329a13a6532300bd7519c19c9ee7959735db4aa789d9b5b139198c032b79c412d5933b687a931ae081c343f1f213c6ec6cd8441d450971ecd68c3700067814622e0ac8ce29f02f6a21a66998d5701b034b29cecd3f809a374554c022ecf50261f8ab7f1c3d3731c77453344bbd5791db476c15825da93f6f84e93d21d8b02a572636c134d776d15215cf9f494f25bbae043be4e9ce8f3a28b3eb66a0275566bef3c0cbe13d6695ca532b4ac5d9662bb51bf33ed1d096afa083a77ec8761dd794374fd5babc44816a802f7a7daaef7d92050904bb3136bffd5ad23aee3d89ecf9bb044d9005907501483746e4898fb3df5d3807d80ba5ba15ae03573cba9fa6ff1ecd1848f62c175d24352d1c8e9f2d568241d2e12248c752b6a95555b0761d2c34ae076f3bbcae9bf4fdfe9b9ae5fd3950c81499f60c904d59fcbe0a3afd2e466f5d1a42d0c155a5dd397bfb2f03fc510e0ac47d95e2d94fbb69e3c0b98af10317f79302b01e9704750a8d6b4593fb4b2875cf4289ad9b14427c877e0e87f63f1a0135da52ed1cf781fc1ac26ddbec6e132b9d2a84b72360a556dc9d55c6469cb2868b67b1a1e04a798256fb7826a4a91bcfc0b1c7d36f3d8d06cb7229f947076197cc0e570a8acad58860c4a1f1ff1957ebf45185e1fcf855ec89f5595c4045dc1cd95d3809d03e766a0edbe4307879d5bb00fdb4bd605abade154a595644d23d30c6a9a90a1ec0829af6120ed6683707ddbeb8e26739435add37f994b60d94a515f16651c85d1e17fe3babb6a8b40b18db822a22450af4a7dd12e37f317c58c20521c281cd8cd53324d888ecab4d55fe19b405d5c7c7c7776a86105d3aa04a47b2fa57494189fb633003affd01506a4a602dec001958b8b32c680bb80dd7c18a53cbea06db3a5c1e3648ea155212bb01734f8b794ff19a9a92467ef4c587afd1dc5ef3dfba7f61adff138ba118876245e1f2ed72fb5a881ff928c179f96f06e486b17dc980fbb2b4efb19e2056285d15d65b17940e86eeba9eb8496c33c0f9f6e4637267ddc4d8617b3d45b4da08ed1b2890386b643c229b2225a8bd5d88b453366653577783bca67061841b1d1e6de1df8f4a59fc91a8bc7aaa06c280cf085824ee49e50228cb7c399e00af7badcbd505c0bc9", .Okay}, + {.Sqr, "d214568f8b526047fe1b76f10901b1ba0780e9e91dc02f9ea3c25639593ad890d1a31bf2dda4c22f5443b468f1c10eae997755c85d373031d42c7220c2928069510b872ea9d4f806a37ddd0c4e4c56bbef7886741a34a6a4a89115a579f46052422c775f3046a08de7de930c07282daebcca3f17d0c6ee2d871ae3c6b48f4b0dfde98dde9446b728ff010eb8f1182cdc91f20a1d9282d0246d627384e46bffef2f865597caaa6e3c2430e2c444826fb4d584bb15c6b59fc9d44b761f8cf3cf132656a5c5cbdbe8cd9a7cd8de0dfc39a157065871945be537b8e0c20911e8c7584c720b1658c3b797ae0bd9f7b2742b4817b827d7d55dd6cfb3da88f9aaa01ac47654587bc0c317b898690e214b791e60f355f01b34b9b544f2e4894b7be051241ff6974fe7bfa8d3dbe8877533ab25599615814ef88289923c90019d71c23ec86f03d5a8164583edc47af92801314a2665550b387bb67b54ded57659b9d0131f646b2dea6705991cce0a5cb289b05fe79729c41fd77ec99c54d2a90bf397c0fdeafc5a51e39a4c4209d48720a2139f3b345c4e44a44054dc971f9fab7ed6d1de727a9282fdf3f1057f763d0b3357e74a1cbde45f28deacaf5f8a60123f569599009458394d3ea0163acf0915f3857e1a7964dfab170e17a915fab88249146331cb6d921bd0865836bfcdfd68e147e43ade905600cfadce898728999db2b79ba7", "b538f8ead1a00039a271327f3108194c52e791ae8f56443e38cb6447b76bca3a496c83316646dff4693224c4cc2b8987d0f0d238f7ca3ffc9fafe0bf9911f2c1a88fb086c7fbced45a25adfdccb87a30058d46d35ab69ff7bae81422d5fe30e4b3ad4b1af1416e60c89851512b30661ae45215d2a172492caff3522622d5004e1ec7db1fa1d0bca4ce50c19ad8e0340011325d44e657a1e55043565e34ed98b882bf0f6b5d3c7615692ca08bb7d42036543b8c56b8261168a79c494b443b7639029380143e56bc46579a7b4bff0e60e8af425634d855a79181a58f45d8fc112c4ad7cf1c0d3cf76f0cc5b2fac4ea7ba949cd13c8c8fbce8b830fdba3de194188bb9e711618ae89aae8f6b8ab5fc7b472eb0847ae5c618ac083071c23293c0936f84d3c30d82fe56f004e480eac6b6fd26585372b556a3d84c2c016177eea9b83adab9f64be78669e0f6d5977154209ea7e8fa26ccc5bde38195fe1d1dd4862482ae94042e5e2b6fad9edabb9d99e4b96387eed70a90afe3afc5c356b96a7c2f6f0ca6607d9dbf4f3e1e7f01104d3334bda6402bffadf19bdf278183a1e06293d5848d75fbb2ed2a38bf4437bfd8859043b4853640bd6140abcb58f92c3d65af10d52a75e9cba0f58458b1bb8b1666254fed0cef44975c5e121841b84277b54bc4d564fa5b9efe6fad4c444d53920278ae611dda2aab8011efd8c7a8239424205", "ac655fa12445aced72af41a65f4fb2c3a78b1648bff32846143930935a1b89da2cffe5c7b8f8412492cd129cba5ca6e76af40632c2ee67fa0acda1c4daad5944d671b7315185315d01fb5c0b451b62fa162105174b09bb71163cc9437d19884875a4c25cf930a02a0053d6c9cab7fae588f88382217175053455b92a84b37e4b87b3c9133028b5e76e8ded9c71d8a62c38ec0b560a237d694d3eb76cda5a851da5255b74db2202615fc8beb66fc9716ee40486af25ac6e79c077200ee1970b89a285f377b80b84ccbc25f3c2384e109222adf1c05fb4c26c77854d5e8369befd2b4d47e32e182213c79d916ede0595ec8b4f69b5f77f9d5ce7d77f4a331ce41441b760d299ada0f91dced7110d8604f46f6841331ed386279f11bb2ae7ef15be1eb526958c36105e825481b36fbe17e9e84d87815888be9537daffad7e27d64660b2aa838e7107181825046db68df0d620374c1ca5d7ea78870b00d0d9e146591245f0207ee30eca8d325db54f27e1850da90696fea24ec65965e507913d8f5d6095ce7b15f47f6f908781f157e103d26a05e09d89ea7d117f297d35dfaa47779a44e60acf56c345337b37a637d926270c57b274be73c70481dc4c4797c4e3810d8ee1a07448b4d1717d60efa96011354f927c7d37d4f46a7a5dec398db871e0b32c441765477445f4a03d5106c339608ce034d9a08931bd674afca05f0e8ade2c0f3ddb2bf50349783ffd119c2fe1e62009946eeb2a8128df73f237eee6f1797ab77d0b7403e948c3b4f370583ad25c3f32964281b774fa9fc392a5677d80dd34b0e83f4b65a9a21dce9a963047431947b3b112d9d622c381c4a19638e62833614e7742ce01d7ef093463d8a25c730156d088bd39f2e857f7e88d51b80fa8180f92498ab075200dd9bfca64be761110046367c44e41c20b1196b62ac0d0c215eeefc455916df11f5518b3b1ae080e65882d3fe1d9f689cede51bb95f98d0cd074b42d64c369bef21757523412500da60fb91324163a70cb8404e612b915f51551528aa8f608e4afa9db4f16cd5f3e9aec20021a64a237628facd3f7968762fc87ba9cd952da5ef3a7ad0f02b452c265f17567432193530f73fff5e103a8cbb7a51960c335aeb76cfacdae2d1de8b112541409d9695cbd1b8a754e0983e236b94858bb9de435cdfa7bf8b3cce7f191031cea92cd5805a98287b432327ffb60ef2cc65a31441e8f143a473d1f59e57ffc7cb14dfb8df8ec1576f78947f45000d553632ebbbe608e3e6b1f769dd418f9180ac6bd2abe61214561977bd30463aa7c9862b65fce4e66b7791305903483abdee177c25d794b473fd93b9fb4644c9d05f5904b6a453bc5b18c55e7489e8170b681583c8fa6ff861dbd893e597903163ea5b87935a3adb90ce45459dcbcc168f80aa6bcbde8aebd0cf03660fa2365a6f1", .Okay}, + {.Sqr, "-f864867e824e7f547d609c3274d6688ecd878be3ce332177d90bcfaa3c47d92ac5b52d564381aaff81f0ac7fa0d4087d94d520309a876cc5442966cb5060c4aa39a2c70ef5673fcfee1479bdb26952cd69c052909c035930033dc2671c4177abe6d87841783e3aff76a4b04e7465cc93bea40f17b8477425b7100c6f77c90939a5b18fee5808ade8c5de9e1c6e35823e03cd318106d850d8babc58b8198f9beffc36bfbe1741973e1bca62282a721d5e60e722db4dac8a23252c1e9b9496e3f36deb43d024e521389710d0f4cd0a00673dbbd0e7f37fd8de55a7549edc8df737e4be4232b6d5638c867415f645445b5eb418e283ded1ddaf6c646c441cd5764dbf803863a89ecff21a946b38510e06410c077dd505c982eb4c80e2f2add9d733d869ba02536a7a72adf9e4cca3d8888ed167d70cc2f29d96e03490c54febbcafcc55d5c801ae23c06b6d434333adfc8ab02685714ba074143dbb58326216d79dd0f25ab92f2d5e6846c37b5ea0bd84606eb79850b6ead13450faa31686b1cfebbce33d6b4c4d8b38292a0331f6413708f0bfb70f5773b82d8815d8e2a1ac075ba5c2499deb2c26bdcc731dbc5a52753476fabf74d1989084ceaef87a84fff37c357b9976be2d1c452e039b54df691df293b1fbb62e508b35bb5793cb49482059f9d8025fcd34808e836217c13d97577beeb9f83792fe43a913e2fe7081e00707", "e23e1f8e48b616d044582dad3b80f4962f1a02dd91e38b29ef24436174ae089dee1bb18e55006a986db6f10ff68b75ffa8c8327cf4d6e043fe5361b4755bd4b1c4d9011fd1d33c34c982fcff42448de6856133078016a8c48608e7d50a2993864d9d908ff3167c30cebd4f09ea3cf9e22bdc840fc3a5a5ffa850468a50d821f1720a722175bb1064611f49b2d66df851afb13184fc34097798817f68f7d1630057be64b91689d4e6aaf3006f6b0afad04bc831dfc1e1609d998da004c3d9c226445be7e29224b9b11848de8459cd8823df4f31dd91fa908b243c2bb5d0ad1cad5c6fc730848d7c89d500993768a865ee69813781534eba8bcec48c6f7128674c952e8320c76c0d6d7b48073b7367f50cff89aa3564f94af3c54d849d97cf326361ba1e600360c3ee6bb46fbbf1ddc7a9a89138b313e45620a6507cd6136c446825b0e3e32b67da5ffb806d34b34c3e73d30dcc05503f3eb003c79eaff9a906c13ced24e4fd9cfcc4119f52d85d3dd1288d347ee2599f189fda14d52c25558496288db81bd1f45c0f90f9cd7ba939050d87c0806abc200b9f8d65b1563de7dfbebddccd00dfb8a0b6afdd510f0aafc35149120094000c6566c026805b04f97c451e261b6fc91f282fcae0dbbba1b815cc26732ee1604c20fb93ff180ee376b6af0af7272639971b3de02a8618ca0fb547099c576463b3e0c56296e0e0002ddb00", "f102ec0e75f692f5e1d2bdebfe90bbdca37c9f8bd4d01a77ddd6aee1826bbb0cccae1d372fa8f03949203a0294b520c7757b8daebbcc3b8e2ac1052ae0498c188dd0e9064910a5b71add27f00547eea41efeda89926b50cafd5b2e77f563f4d8afdb7fdac7842815ca938e8f42760a2bd4382b791e93a8c494a508df123951837f0e7240b25548e7d69bf22c050f1d492c4e0c82bde67f1a0cde5e2ed3d3f27f4807b667d47b22976a22e9a208a52e9749a5795e016635333a7c424f6465a0a00941b96bc8c35b8a9f0390c8848cf21388fc05c36622981345afb1e656131a13fff22f5aeb389e8741c5ac9d24b86e08409785e49cc0d80087283de87d84d937f7621530c88802418f05418f7704de6dd18812c45e75d0bfc4cd605f23233b9914ccaf9e7bdf711e1e6f355d186b1d5b198c6c5b8dce6c8f5124e424a2755381ec8a29fb702a0ebfe6bf3ec66825232268645b0df62758af9a882a9a6efe1b8fa85d811717f08691b689fe28425c13dc3ae1d04dc22204872051ddec33be2465c65176c654ad3a2e1bd0cda5018f699bf5a08ab4d990fbacabe31e4aa35d87cb1011af65b903bde547f482dc477d7cf842ab0ece186a5ab3e16fd3bd3ab2b221269a399d053820c5197569969546dde8aeab6617faaaf737a25cec0f51cc45f2d787b5de14ae1be2e02353ba05c233cd86548256008c104437b4e2483bccdd5a12695e29ee411044ac1db5e3f8c8b6575646417cc328a10fc9a610269cea8caee38b3d6cbb03e289cfb0e517cce94611615fdf5961a02ee2fe8ee25a2336540ccf5a07d6e998d7bd37fb2f9000f97642fc568bc78da70fedf0a7a23b49e9706cce0027e03777d443f7d297dfb2a5701ea74f3ee106ea347eb608c43b37e197e85e718a91ed3ecf3ad138fc45523d9f136771d0bf5311ee581ba5b91f5bcc490d4b0897df60bb7824f3c751827e79eaf90bea7fe274a6fd55b31112c6a79781118ca54da53f5418caf8a083f8330037e95dc8a3e344f14b897dfdb0453efc7653997394fb687b501bd4bfd382b52f09c774be0ddc98a4adf08c51b6cc44cd43990eb23b64b486e4bd68a2e840c39b141b1a1183781b95157d79063ce817291c1f37c779442af83362ca67d6625da3a7148ede8cc8257139d9b46677441609a64b4f10899669ee6dedbdcbc8248c876d33e07b3fe2ae2a001aa43c2eede3bac46cb630c0421e7df5c81980fc9462927ab9078b9caa14047a39bdb01b1537a09af125dfb47fe889ab8ec57f64c2e7b56987c2b3cec92b248bf1a828c4908d72c3bffb0760dd87cb2dbe0d01aa210398ce2d57e7ce775d32dcd2138e8011a9b9c3e6724826bf451199249502e2dd225313dde309bff67a38ae37dd27ab48128cb3591f26c8fd6301e4a5183146a52aff664c57d225259a2af4ffe63795415a716231", .Okay}, + {.Sqr, "-74823bc745a24b759f5731bc8ebdaa7a420de8e7c6f32a5e118b6a9465337ac4332bea97e8fde361c9c145b550a2514c13a77067118304775e15934b355c777773b80673e8c052485d3e747fdae7acf17de39c3ae455574caadb40b8eaa9fd570fc0e8af54d8389bfb318b8393e8631a61af42c8914039ca8c59d95cf6a6172e1e84459d878a3d7d7ddcf38a7b728bf52ee8ba02e87ff327d0343c88ea7ae1148b39854370755c945af162913eef84edf2f8089c28b7c090bffabb222cca35639f7a00adf8df8da486d3a11ca6fa6eb259d133e9773c613d071143092eec586f23bb476e8859fea9d92e111fc451eedbc20e9b5e28233c198620ad9f49dc796a9495db8be7f9e623e154706e27fd2f33d6265c1bdeb7180ed476cf3c9a6ec38d1a1214112557735496f54a2bc4f8351abfe8776d1fd191d0f326639ed9876bc9b861649c7819e257a362b00abdf1d8bfbeea20e88ffac5f8c02aa6c4d49a37eee1483676056851e5972b252d8dd9ab1bd6f2b78d1ab35610b4156146a789b0dda566beb67e386a5b455e8921593568c678dedcd714bf320b2440d8aea4aa837846403a6a26fa9c988bd8f194cbdc0e1e8f837adea75d7f19df89b41a2871f7cb19557a24d18a751841bd6b38570b92c3c45a283dacd386c006237183ca01dd8a7ef0512b6f31cc3f46787a693a2c2cd55e76ddd6e374a0ece7b5bd1816e4843b", "57d60747e60b2b0d401906474fd77c143b287c668d46cba6baec674963dde48d04ef7f80a7dd65d9adb9e8fb01827fdf9acff0aec8e4eaa03a9e7710bc1b2d1246d0a72f88e3c38151d1bbdef6c3b1bf7e58da8fab3bcd05c082e35b5d6feb5bd5fdc1d18eb463194c520a4bd6bf76dff80a025e91fd9587ee36c982b984684212bf9fb589b72ca3354ed17b5b8ab9e067828b08f1451702d7272fde1b70eaf80b15572a764a5c6e8badf917db8b604e9abe140fa92c1f22def70dc69490fb492f4b8a3d5d4820fa5605a08b79f79be4606695fd2a6d970c068b8cd886f27441db010d04ce774bba78816e8397c60d7726b1fa831eb836b27d5d7f94cc162a2a50effa2b9039b45d43a865e77a0c92fa4095e65048ca4c0cbbc1cc609f53aaff039c368827b253309d7e4d82cb8fcef41504959529c37074eccac9f3af70ce9c696ce7a89a4241724e0a8c6b7847d396a027012ea7a2ec206b611268b0f5e9798109e75839ad1086441f481f22cbdfd4d9c39b55f2d294933e0597d4d5b6c546177b0c005526135b0fce1818f7a2da84c7e70a18cf67c099f5790430d21e861bc76acab178b1b192a7696d10304628b178ccb1f9528234d68ea71adabda8c903bba37e8d580b6888b85d0f637219d55ec11f9d2d85a656db069eb1961690308eeb30402a54f35025967e365d4766985ca27417a43244c4959306bb5387304587", "3506486d5b73426d5fe745824e59e4a3ff175b2209684338375b4ace477e6495a22f2229ef498b13b1537806a3fc0862d923dbd2ec66cbfd4a05aa44c23caca61fcf8d0f622083cdfcbd6554b22f92b618434e0c32da6f283f759fadd465714a119f1b52f2acc5b8e0ad7cdd738fd94894c8d4ab599cc9c13cb9af3452df13ff37029f993788613c862c541c4e2c321b6365dce4e0a66b49417a02f3127347441365ac2b9f74aaf5e13f5a777fc9ffa974ec4f6a5d66e85186e21594de4e33e29b38333312f02cce60fee70ec59d70ca9c579e5b1e8983769b6bc69d5fa4e4fc0a467456897ff71fae86987fc6deccdf2d0b78424a92d57e2b093a2f0085332ec3a5367f62739e679d7cc22998f4df7dc13e81564414c8cef0e355bea3156630fa183008a7cb096a57dc7e67947d79a658a06be8f323ad9e516551e813bb6217a37872fa85ce213b66897b567aee315c8957c977c76b08736f123bcf5cb3b2fe9bf72b6da549b9f8d21376b9ef1e8e758edd212040d29c5a60e96cb3947169a4d17cd21977cd93207c4c81478e0ef47a05eedf4f270fc32b5e8c9a3de6719e8fcfc77f9ce5a213e7276dbe661bce5ba91070227548e47292cb8e51135ddb10618b0f421c6aa23e3eb824f6be57cb3874d570e973869eecd925c5caaf21878fe425c76f2a122abffd30115d77ef92ba05d56048cf7b86dcaa5730ba9d6eaec31143d895ac800a8acbbf26b8f8c3d657e193c58d9dc3f5dfe0b2e27fd0033517e4837fccec5fb792eaf94cefac4b866de729b238a2267a01778d6ae3c862958351e3b538deaee13c6e07b73996ce68597ed70b1fe58dc6c8a7a1fb05e5f5c640481ef3736e300276ee4536bee54a5f756a136cd684248db591503f63b541ca4a5831dbf9442dfdf95bc0943a2b45f4bd801aeaca68d005d8dd0bc97f64928e09e7ab3aaf6b076057b6ef64b3d4022b70dbebab0cd9b196bf2d94519e2b0f842722e29e634a6e3fe0b7acf53d7ede8934641b2071f33f9c8c5261b3fc6ea7950cb475b86bc6dd1e04ac82c312927400c80daad9738caceec60e7875ce3d9f6cff4b2388ca5705600780e2747b3f75b27ce583dbcd91c93e5b206968da0adc901196c373923c3ea5f8081b56a45c1d8d5466a669d91ebf603a69d1077c5fc339daabf578c171546e1a608a6ea7e8999a34fe9253341b5682e3b31be915f124ffed5c98ae26b0c36f39158b7fb2f352ea752fdffaccfd2ad2e9a55c658b8610464c9b9ba4f5b6f6fa2ff6ea3e60693efa7eb274bf368109f4f177d09c52dd52dbb142e6b893c2291880f0f36f6ac39d4ba378c284e512a20b9de9aca7c8055b7e6a3874122d31c3f004f39b30686f12800ef1ce67b613271556a7223aa5afc1da545e44ae242d516ae7fd8c5e41e4642040ab58592f8abb22e69f2d91fbc5f164e599", .Okay}, + {.Sqr, "6d2e10f2da571925163e89c6c7e0f4687cf899100a7d6e17070b0a44be058cdb5a2e79766de469bde025c1495ba89f051f57ba0050a14a768731f9cc0f252dd8fdc778f8095c45360ed0a4d2bf3fcd082f52aa2a833adffd2f1ed300107925f628fa82665a5b37ef506fbaace965782781fc7c1b9dcb5978669b1c2ae78a1d9ab9b92dec5403d7d69acb1e6280c912cb46020ccf0a6b9c6abd000ce763267dd671c4ec6cac6f0840a709a1048e73ffc83f4f8411f1097a3fd742331795901eb49bcde52783b97dfee5f6a81146a34e285339e96adcbc9ca65e4222148a0fccb20b10cc87ff8056ecdd47bc3934ca6e4400500f5c1e4aa35a9085eace55607bd3a7f44cbf2858f0183c29c98249d06ff10317bf57cc71a953c77682ca3fa7fadb4a3c023e26b765d8d380a7638ac4b2e999fb92d83b0f5495b77f62cf108ed8a97178784f80e6b2b133c9101c357df422c65fab583fc2968329b74eab5dd219582acdb22ea11a14a209950c5d6684251fee2ea7213a7afa2d0487900f5b61285c9a10f8edb063425350d81c4cee6d1c370967fa4fe828e8e17f7ebff7e3d29a0f99dea5dac81161e162004f8a5d0ff4e467bde1fd9188b391442f4b85af3eff13dbfe47d718a6b8ba0b7e21953ab11af8afb9419bbe06ad26f357417f45b3dcdf925e506d864b7fa5dce72ecd869a276685904594b19dc9f8fb436da09d211187", "433788dff7a9a5c268168a37b997f1ded805a4c1e0fc22ae0f5a5421c27ff9b7ec9766a6e957bdf3a59eff100c032f4c00ebb6abe30732e375473f86929d2a6354a025d5c3b966796c22022c26809fe7ebdd316dad8c523ac948a643d3b81c9265a85ec4702e15561acb4e2caf7ef0f772e36ef177b11e5892d43c04c0b46ba47030c9d14f7a75a87d8ad60182e6a549ffa00d987a3e706a94e5a49abfbb1dd73f0a86a7262a825dac736b35f6e123cb909f8896cbde774a2225fd332745873417187faebdb7ac8301510ff4a22cb29c47728b45f7ac88b9831755cc25720e3648c42f02aa62cc3b6da3ec16ef6e95d4b3edd0a866db7a2f07cc7789e7a54805377d7046af6bd579460068817c450bac2366b81e62ebd89bf8baaa3c0f739e857842a63faf6e1c63da5c253b9a9f23544eea70b730b66fbc4e4a3db36d9c66adaa83c4f35b08522e40f5aa397a7f4bbba4343e56eeabd2a2a2904cb0cd96e19b7d8f14c0ac6d8f57aca477008d8cd709c6b7d94495634ee4998260489a00411efebb0e92c8e07f958efa38da56feb908ff087bc1e0528a91662b38d176e712289d9e540b99ba507e1e57877af94146f8edb2ccd3dff0cd9767aba6388520e44395b5a2e9579be5bebf3c7b03f6eeeed360566fa97c3c285dddf869a2e57bef9d212ac4250634ce37b6178a5475d4f8f01e39a5dbc2ea4c0562a1d033b3d38300", "2e9042b8e653e463084de127ecaa9ea6ac463176ff3f33fba16bc053dc840c49d6a50a6c2ec9c07fad7cdae60bfbc2402aa2bd1005f3ef31a1d5890b1061484af4a02930306d79a3f85218a6357c407d3edba0a9ea4c91b94e582b474b90c780f0dc149b3c59deb02e1b807f2cc9c6a4bf36b9f90a7d8ddfc6da573dc45bf29fc48fde54d0730e190c59b40e93068286b98d7970637c967e6233dedd6bcc7885b392edf0cf016476648ae2f8e26f214de9fc05cd21fd50dd37ed4540e7cec7b9c1c0bfa665b1fd4f1ebb49180ab5747c0cd604563ff9ba1a518382114f1f3b266f5c2e5ac83960e34f26acccf989f8c06def8e1436c81d5e7e1ab25b339ee83bf5a399bb9ba739adfc6e69e185ed40b286ca7835189c15a940bf3fffcc0391d7567da9b74b3b1b7d54dd6e10a0b687ecc8c1af31b76387f0534fd6a28ec7a3612107c22b181a7f510fbbde0c85ff5b6eb86dcc87f3dee02bbcc610e66777c63a8a4a8ed6c39950e53cae128b1600a17a7d98b081b27d75350a96f3729c68f923358d76f6e9f562e523cdfdc8700a691ca2f1601caadfa069dfd4a11e0cc1a7ea3fd97fdae684cb49ceab8453551c422eb4646d08d763b9f6ad615d960c2d02b8a59bd4a40fd09a90309fa33cb3b4471e2263f8f4d99e437f17588c6f0d58e6dc45ffb19ee4bb575632f84dd5771c50388d1dd87c59398e46a0a11145a24ca3ed33db7649f43b216a32992869cfc148645584bbc1b1e8259c3c45b19ef71d452c9bd8011173b798a804f1cdd1fdf514d9719c71181ef39ff28b95d17e8912f5b152843b5976449fca4e4f1f39da27b3ab26504e59867891d9864a183596ad254e9c65c29dcaa23ae7ac13eec1c5e53c5fc2f64134fd2b7834720df43cfea44b0e1cb2b9b2363986cb4e0ab206132ba298278d0a7d17c4611d95bcc601b0e2d6475449cc268faa1d2a287aa29e9c38bb1824ee8544f611a066f1cf75ea1e8a050373b1d6405a302d41281ad3a5a7514e44e78c3f0272e8b503cb8c30387ced59037f03881ecb3ec40f785697de70640871e52f34ad24b611488367e8c1c93ef415fd50b35411892020ead2e967d4c1881f5f12aab2c7514026bf5f4b43f5328ee99e726bbd9ba1842a96a7bcd0c172ac259e3b73ea39b797e924ea4eb1c45971e1b74d2aba028d290d3d78501951cec7fc650e6054fe2ade74b208cc52b2b542c44831f9532a32645ce92810dc2f9eaf89f9e2564f129357a775d797edfcd59c3fc2673ccd0d73775a15e1afdef321bc99697bb624c6961fe4fa75e1a36da011e1dbeb6a400e4306892bc26371cc84778afe7bc70947869461cd49a6e10e4a88888f1665fd48a62c5ac44c600c681f013dfaeea4e90e31e33bed32c52bd9495d0625b9d0499f0d33ded77e99da7151ec6bbb3f678e105135d0d95e72851c013531", .Okay}, + {.Sqr, "-ed459826f8f08df71a1c2802839f8cb04c3ae20611c4b1fb6fdb10363af854c5ad6361ca724d75a53c28b6d8fcad2a53b96492457e1c3ad973c59d1636d36c17b51b4529ba4fbb310c46edda8fa9bee2ab8003d718bc58c5beb4574882a1653203608642f26b420c987d1c6f223e294320c1956ca35254b3fb538c0e1d300bd12a09c5cdfe9192689096ad5053f35106dcda6c182ac398d9d925c3d7c698d9d7ac5f172457cb7473b40c07527002ddc3d3e996935afa0262b971480b2c91feac03b112a17a23d6c6a8e594e2fceb2b4d88c1339f7a02a85fcbf62c5b4e8b4179031fa7a79b75e376acd1e29507f47b5929df43cc7041bd15d6d1ec7a52324da8975cd72542459fa2b5139031dd8930dde4946b1eafa5103c2aea71b266e7a3bfd2f023230b73e5dfe209c9c2d451ceb030ffaa4ffde3d873af4a2c91c2babf295c76fd5fe77331d369da924505e0277a79b2c209e9455cd03c6de169f939055e4fe1e8a80141be4dedf3f196fa01f8f06a7a4efc3cfdfff4169b2036e6ae566cdf22d9151cbc2538be661c1346c7f12cf57ccbb71054fc44d3e40864fa858a0637b0e74b0ff4254d45bc9de12c58795ed9046162bf57ea9f30ccc9f867390c0d245cffdea33ff1bf8164d1c4a9f9d1934d0ef5e8078511905d311ef0c12d3089ed4b4e6a261a20294d5cf73555da5042a70a0446a6d731123fd1e61dd39d4cf9", "5c03b3f05f7d1ebf8388aa8935dc314b009da0be2a5114c2d08873f8b0b6e06c6717e8d06ef399c5d7d6cdce4a0dbba94d03cb679727bac44c8d5f01bdcfa44b706cc4db75a298cba5990956114e03cce64e5b50bf191725e4730a58e7efd9a48dd2bbb190ee253fe6067543b60b0ac8a02c61e8f2dff2ae2a61d3352561fd77b20806fc1a890c1677859ab63bdf0973514e07b0e4865d0efada5498393f863ae450514b4faad0ff3f1a2b3760df8756db2d216a3135e6484df9deeaa759b0571b2865f50e5bffe662dff582e66063963197e5f79a98af25c03e92ee1f2e3a38e473a1a40dd29378192e72ee0df6cf920e1e1b5fad73fb6306aafde19e490bf676c93dafc8272a4c3ef999f8a79ed1b6cc70e4c4ce545782fe0d1752e77e5502196a91cd2a4c2b80cbf21a3db986f4a4b4ab4d36044a640761c7cba082ab54cff3903b49304675bab28024280ddea10ae0b0db3415ecb33d2a436b6a043468a243e120a50266313cadc16812228da3dfb0b59f29d8a91ea7d0d5689b1c1f5ce3d3a2158b314d82d897822e5e5c08ed0a594ccb8539a2580958bc059c43b1da50a70b14a77c954d63d4d03a55ed422915e962976460b9c9223f8cc42d3c29db299d64998ec6632c777cdd9e0d6844749dfac0b3c25ac704112f29507a74218a253ddc1ded8221a76735129c7cc75052b3582274a1c32ea70e08d35e76592e3825", "dbe9eea3885de6148f9ebeb8a990df231b6adde808b4c59ca0fd2f4d174ee998c58640cde4b0719944400ad9bc5b9b5e3a71aaa7bfd3bbed907018f49839b24081495d0078f34406760e62a1b2e18a0021caa59ab77383e75d8828b2bb23e15ad9cf231b291242db30af9133aa119c763438f584ebe009cfb76f236b93199718a39fa031f77c10c94cd4e699735fa0ff51b624aca9d48ecbc50a813b12480254fa2f777807b077045a2990d27da8b8e9c550ac0c190b6417f3e21d8bb22ac14073e198541a573625e11260270b777aacebb59622642241f1fc977a7e1767ad2e8194515a6072653130a51cd85c2b71c12a66fd15a0444c7ab332960f0e0cc8c362e48e63c363b60fd352b123b6a162348570cf5f160c55295fda20ceda763939713337672cdfd965566cd77572aefde64a2c19492729813e1499550ee1b4762ef3b0aba213087d003563a8b0a0c9ab59bfb6983173893c99dbba8c8e25882f2826e70d440a4b44e150c8d30595fc60adf742b536212d92a93004fd78eb7192f9862634d65a8647064eb3b4b67467d3b266ea4f598ab7256d9832f38dc3459faddc984b009adbbfc80cb801d2e4bfae6aa3a425cc71a136d5b9e92cd652f24950f0880113ff7e4606c8ee9c57a2d9ceb33490c33c1cc3aa9847b4dde38d2ad36817e8df058c98715f0b40694b764cd0d95cfdf36075c20e6430bd74299b6b6b54e8da282e6d83da21f6ff371c9eda529db05f9db2011718ee0d81c934946c7203322dedf2003f35cd0b0f483fabd584c0dcd8af0826c50d4aaeae945ff2932a1412f7982a711a46df136c236606d8b3483256037c5685c25feaaf4d89d4e6b8e59f75464f10ffe3d2c254a526bd13e482356844e017fd309254b416a7f94670c19fe99e87e24e9c940945ec7529867af263fef01795d796fc29c674dba258a8c90bc36d27f69b356f75e799617384e87d8dec23ebf91cba8a5ed1293e5f3bdf7ba376dfded2cc5f7b56dec0cdaf43500b2a493b7d43893ed6a1bd0ac19b7200e662fa5f481804cd89172b8df157ffdeb67f57f212eaed3393bb278c0af596e67a77b73a1921af5fa317c31f7298f4528be89128564db53ce94c6dcb3c74cf08dcd1bea3f81f316ee4cfaa13b8bf9cc8096f4109982451e35de7b5f062beb0b838364756ed61c193480b0399bceb58052f3fdfee91b2c6ad830febaecf707921ad225598d9f7507c5bda0aa807dde148476811b4cf2c9813ba5cccd0f2374285407ff804497be4c76e3958fbe5a9977b18cec39b46d070ed43f36f0130d86877bab01adf4bb083c7066b01e46a511a988a860c66ddb25bd273f310bd0dfc3d14fde014b5c737064f8a4bcb81194995451add522f23d4fac7885464fa608d1ba4a559f77b3a324354f620a68ce35a8540c21df014c66988b376837189f3f68eca31", .Okay}, + {.Sqr, "-6b9e432dd4b98cefd5fb4e0e0d949161f2820f052f16b23328077ba42c5b24a20c2b7f9835ab58950fc2618a4f86d3443278b70983b8de500a579c6953c78d1d2d71470b72a12ca61af34dbbf36f56b788b4d3f3f132da8d1055a0a6101f4dfa87f513ce15ee809b12911100cf8cfde65bc4563edbc77e35e022f05765db5350f10d78468f5b3a30d669122a2f93a41fb4a99b772a18363c3d7840ae4cf9f3e4025009c73904a5b4fb536d5b710175f0ff699c2ad09812d8604383dd106564a54bde4fd858f40b5042e687335944855ba430ed73f741f9735af8e1a7fa6d5838935effa4b34753b879a97f291d269aa71b86d38a3244c55ac204dfe64ede3c539bed0fa9e7b65a1ba3435344ea9ca6e875436588022f0e2b44e3d00c2028d78e3b9c51fe4955f66426e6eedcac69ef6d38dd835586793697a51f9ece77ad0f4560eb02abebef6c87c56584fc8a19f314c0b27e69b0cc1b0f8e3b37b769f0e46cdc3f5cf39a0419bee40d2a2ee5bcbe4edbb639cd61de00691ec6610e6bf7fba743c58a32e62290c2bfd1d96e24689451e06e5be6f23151a7090e0117db80d3e0ae76b7396f23efc61d3608ada81c5bca12553acf1ed16223d4a27d66cb7c6ce1bcd82adee93395d7583adac292e21f665ad79e5fc5718ccae820021035a24400a8abf0b978fb38ff71420847f09c4ae4553d79e0df9790a8f2424bea443c263", "c4304bad8a520f3927df131875a28af4f102a6ec0047d182255954e7d947c7a7313d153e879b4b29e53ee99e629ebbb60536b106aba129cce3f114f75583175e3d902c32b945def5a94bb5464566463b1e5c161693f1ba26494cfcdd5a99d877483f5698f20cf087d1342d35859d4da6d4b44761fa1743e365fa31a2cd5fc894b672d9a3d15d033498609bf319af893bd70631174937ffbd82f86613147d7c0e239d79fb79103e93c3f90f0045c1e729b52ecf0d71f5ec98ae87a055bf63cc566b5a400005ec3c329fe05b209caaf2730638c4dd86fe9c06ed10c473f9d6de2b0ba472488fbdc203a457cedff9c5e78e2e1d2eb86c61d0a6168fb655bb8a70701f2ba4f2c57f8dc6952daa2cc3d11e0b14be6d9b13c8490e61f0e0b9f11b45492e46c643c6955378b0d31537321b7ededf27db390107d0c5e5335056b3e10b3fbeeccd215b45ef0c1652e0bbd3a210c7e85cf37f8cb7425d62aeb5f8e806ded90b3f26b1932b751fb9cb99b8b6767de7acf5d4ce73bd1b524f02ec0aefc3e33647bbbbb807e911a2a0e473089a403bd6ef7dfdab768b1c7033632ad3cfa039c15c25f8a754889128bc34b18693a285a43afe3460103a6bba78eaf5629925112f7b8f77614efea6c4348fa7175216f1e6d26a75f9dea581d0822a12fb66223f5ec0a8b82d09af2a167f244846427b0507af26b36aa3536c87d3dd1a196b9660e6", "2d3dadff4e06b6680eb123b1188a7232123967a9f2f002bc9dcc702b1af1e55bf77257a5e8cde0d0e1df836b2557dbf2d4ec4f4d7652fb64c68b00d0f4b8ee6ffd6c25dd3679fec5e108b9ea11fa0262cb0dc54421a22083c446af6f553ab41d4c80715775281db5e08f3349aa3464d370f6da4d1e4dfa3c31d19f6d05d2ddfe790bf23ac6030fa9ce839804eb0b124dc55c710bfbcb86c7b28a6dc980c15b54c27ad0879398051120d8f01c07a5736cfbcf20ce425795885b203e30bb0b4836dafeca5f24d88023580edfb6e4b5eb33e2ed42d3e7f886b6d485b7b7acd06ed2154748d97f4a232a071cbb349ed82b5a7fccc463d09df93db2d2c5bd3568d3dcc09c7d9e3109dd9846413be51e9d93efd4b7425dd8193b7856a6383f52616604636b642f8fdda0bbfc8b9ed99eca9507fefefdb3c6999f145899a0b42040d6d8799770bb4b384522537495fefb42adb369a70fa219303fa2b1e2aa433adda5fbcf62e1a7ded7369b13d4d9454dfe1be5721ebb5e515bf5cb944de1fc4a6edfe03c216bfe4573f83c9c321d036a13ed6e6906b5fc33679ef66ade2b5c062ad3f84c0c30d4bd3c4d8e713451f044fa38685ad76358403817b56160682d2991b6358087c061aee1f2b20f62cefcfb08e2e5e6f62bfc502b8abdf07fa0320cd1f377561823107ac5f015db7f8c7234cf55f1cc501396bd1e52888527f44407946c08a82c1e80ab97d8899c7f2d11f408152c9cbd1b2090f3e416072889b5409997f4c485c6ab6c37dc576aea531b0c1bc42740f8e60bed32ba7ee889b7d36ff12b6248eb9142d00abc646713abdc99d4b704d9d7b6e7b92b59efbf740a3763af85972adf2f3f893bb0e53ac01016a80355e2f676dc03cc742b871f60b59691bc9f580bb5218b6c6432810314e841d9cf3e8d0cd74bf22055df9ab42b641071cb9f47ed838942ea461a8c735c37e147a3ed7b4804a333e5322edee13abd677e5456f3d3e03ed6d43276d90f6649f7a1cf2fb4e0fbddb3b58328c6db49cdb1eeea26378767524b19280dd48cec0b6f1712ee21471bfb153c88aa55b304e132cfaea480164c3d1928ba69f1a2e4a9abff8baff1ba021dc5a440104da4493d130cff9c5752d86bd0becebed523c5399ca2f42622c08ae6a2b3fc7b3a749bbeec60fbfeb407afc60d6cb51e49e748852502a3578082cf835c16ffb5e4ab46785da135705ab89804ea187d6be79deafe075b04a58d015defa1965bf3b15f0caf3cf5d860db95583768d5834897e0ea80cc20c8ecb8b4d6b232e081e85259e1e542f20964dedab2934e52cfa604c34e3dada5eb2ddbc96e646086e29539d9d9af96d218dea9612fe88dde157757c12b4026a781a253d783b2f66095b9ee7e08f091467097b06f0b07363aa091e1c09886b38990547f7b26166c0ad820927f45f22b6c3249", .Okay}, + {.Sqr, "4c31df7823b7f67561e94cc5ccb52201f171d115717457cbdb17d3bc321e6d6233f908cdf1f0f1175d6e6d3dd631b426366fe9f8d8e32d7ba49d9a1b48f8f837243ad27faa1ccfc233f84870ce54ff5acd53461c640ac404836a43f9a184053d3678c3c0bbec6ac12ffb4b2b8feba5a5899d1b96ca36434f01f0f3128937ef530499e6b1d1d2de3d0aee5c0a37ec44e7bd64e287564650c9862587922423b1b47a10ffcc1d24c3cceda409fad4e5c832a07469f978bc97dc345dcdd01c075d1a32ce01743fd777164655daabefe37068625cd749e3ddccd07b01cfbb425a0bea4eda838729983d0b57c21b829c55910876c5010bc6f1633546fe4f3762ef8b5f03302e9a5a3bad902fbabfa43b8eb79d912d9983accfd8a1ba3a0c0b637bc1e7f0ed98396da2be13ae3216df508d057226fd8258c181ba2343b0f449cff5a35438b386bd523830040c9ee208cf291f18545eac548344805bba4eb2e5507fc0d5a2fdf3b7919dc8906ce1402200e70dfd7c6ed1b598b0facd31812b880462f5f520d4e2851021461b3c295d873135a626dd634b20472469f2c21ad46e5028901eb9fdd58b3a735fd39f3ca2ebc965cee6a7484a386b86ecc2674c2b13e27f88af72cea89b029c4b23eeccda8a35a621844e42d7bcefb79688978f26f47a8e79c16652fdb9d3c89f5ef25183b1902ac2af20a1d0e3dff9b48ad5ff554419c14ea0", "4df221fe66c3b7084f440e7ffd609f52ab2287640cb720ceb8c58556be5fac1c3f68012ff0ea59cabe930642cb482355110ff4abe8bddca07be13ee3519aebafb3753e16a1ded3b41b568a2f4db0a468f54f90e4623bfbf01817aa986d626e9b54a1e15a5c25b6cf2c53d0adb1958cd3f04f2184ba0bcc482cd665a072bbf2492c6cdba655b6869c0a0f8e30d34c5b38fb8d61c1026796f974e24bac527a9ea57f93806bc472210be53cc81dda18262e4ef2902a22be3cb8afa4d4f878f544f16eb591b2e185ef2b3c67ef622ee9b0bb07e298d94791a1cf142045bcf307d6eb9bed27b52ab3ee45195085d003580997f4daf9e30c149817856c5590049782d2e011d28b8cebd0580044df40d5abff38f32c0c8c897fcae0e8e9d4036d6927bcf856a5aa0a914e1ce13e64959613656ae31f8a4b6860c0c3f6770c21db0b43920ba0cbad9cb5ab4edd25abd6317e44cad7c3f6a7243fdf4cdee4069aeada3ccb44222841c9daafd2e2e3b9ac8593a208a5b7132da145028f00fb35ff95909b0d7d78c102636b58ecbce665f2bcc8b11d686ee0de769bf180ad361d6c055c51ca4927a0f54c019839d53ccfb6d781a57582ba237d26096de8cac4553dcc9471881e42ebb0e62c96c95e4d2b4b572367c89ff60d676f36ed368425d375269f1c0530d963224b927a3c37f43599ae70972ef7c1f05c300b074f63bf04d60a27ca61", "16ada666a4456d5e0be5611b759a1224842c6b748878f3fd8cde41fa7fd9f4b63e9a4f9a9bdf99bcff0624d3295e33bdc7d1ad882a10e8d561920edf13b172c63298e5b9a6821546c9155751ffbb69d1a6cb9e909bacaa94671c52e28f08688886f22e79042c90d0ae595f8a8ebbaaf3e6b0a1b0faebf1697dbb9e50b6168bf7a258bdf5c4a2d56ff2385199fe03738f8909a00a67eb0dd15140729a49f13711369efc6a3906d5a402dae63d74c9a86e8352e1c226be6c8d013b524f513dfbc11ad51d7aef5a226c8b15057f602bb0a78a2b5766f1f2468b581788c30803881241d440f05aed5b8555abf54735a00a78177017effe8ec59f14415b9e0f7ae479800625572d5d2c6f5e7c8497a13fc6e452d8c06bf21245d1825e41e7b04e5f278f49c2234b660f726a79ba68b6d7ad9ec0aa9f37988171f0530e95cb81b04c7c232b9ddd393e1ce34a0ed6acacbbad2c24dae46c17de6643aa52fc16793c8122828dcfd8d30e82381625b81897ae7eec66d2924c3741c545dc82ad4a0689626b4695f88683211aa805a13356ca330408dedc7d95798cc3033fc21d433d9e47df5236d58ce793b74b8a8cd04014dac4ff7e2c8a54c6e90021da5717abacd48d6b0506bee5b1ca3cec76d0a79404099bcac5ce13fbe65d0e436c4b38ff3ed1cb0c391b2dd0f650acb37962ce37afde959421abba08d006d929a362aa7619d1254d89e6faced92bccc8f0bea73300784aa63c67578448ece0c4de0b1c21d681be02118f53178230cb6f84ec5eb9bad6636a987339c1d50b9ecb2391e224bed437a71009e1bebf70ca92862f64fe2b8217769a9ba6d3a2c83561fc87020d9cf5c530e6004084aaa5a483e5472a0a530960d6bdfa72543b6bd9e0ed5e3d50aad4d59e418cdd3f83a76ac27f3d1af33d8e1f661b7d4dd5fbb2c5f0b8dfb861e9d5bc16cc663845555bb7d4aa8ce0415fa07f543649d3c2d91bbb17ed5982981c0a314758a5cbcb5f6af999f61c3c35b4d7becedac74b026ade255c6bdb24fe9d4ea5c5ad305514fc61959f7888a1788828baf7552b1a7ae60d030621d8e10af159ca7d5d3857229758fb312846910a0d20187ee86efcc24940fa41793d3175c30dc0c6ef7127228af31611bc2830b6c353cba80532ac2bb28e8ba5ce3e401130abe40e4dab0346894a88eb92450e10097bd13a99b23b78bad175f3165cdafe43f54c0fea676eead24a755142c44fda75bb0fc6345ca6017a162c63ec98f70fba6fae3b6875285eeae63100cd57f5ce51dd1dfa93b8cc2d7519f4ee14deaa66c5db5f72c89f3549e8521eeebb5be76138c2c30b856e9b1b18e193df6e4d6da14b057d159e60c98f3aa129610fa80d51780e3d8f9ebf890d5a832863e92a44fb01c90d6ac8d6213f1227d2e266f7f5d147a741a7af40e4f79b270ba8f23f5852e565e400", .Okay}, + {.Sqr, "-175bc72ad92a690cb8d9a247fbc70dc712d2602af00ad7b4b16ac5ec9bd1937b0ffa07c42198bdcd0a92a5a2a98718e0c8f70ede48cef728315c33986806bd60e7cab56d8e6078fc048e791857c5fcdf5aa162c3f03e1b8a5026a5b020ba56f40e0fa6bdeeb59e227cb7c31fd306d1632ac8a1a3b789e274dfca46e1862d3c9127e1bafec97642ff872478ce2ecec9ca009ada17247eeb88b4a30f21d36e43492a5afcffc5de54211fc37c1bff5694397529df81e83d2cf2c61bcdf8ac96684f1f3bc26761db1eed146d8bceaa6a5ff5396884cb88435459c9d1cdeb84bdbe2ab1b9f22dddb264945fc62eff583fafe28c70ca85948de9aa4fac17ce430084c634c77e034473728fdec0a9a2ea6b79c35258cb71822bf7c0032b294b580b9a87d12bf8b70bfa93d9d18d10ce6e6dbdd968eee97167f72fcbb367e2fa1ffcb37f05ab65295155369d8428fa7731fd11ce667222181f92627c77d9bc23c16d6e9ef6a148236a25977ddb91f5b2f9518eda8c5f6340dc36edf55fc757e0b84b5390981b4b0493220f4ae5baadebb24b3fa9f3d366d7007fbe15c78809d6c974abb4d098b3dad9cbc82fb80ea73ac002b3afb6cae9031339b16b8c3c8fde366fe9719effd39644ba1c14469f5eec9e9c97f99793a2595e09f94ce9aafae7b8abfe9d9c58e076c3ffa19181f31213aac01dba681c0956bf7badf9101dd7b135d12714", "1adde64bbd4b96f4f2d40d52557673133f5ac970b0b7c0eb24dc13f5e14da1bbf432c04a6a0e66cc7f458ecd9a017fe002ff932862ee2a9994ecb984391a4552d194e1e718523dcfd8bdcfd455871283f728b56abf823f8022b24766f61a1dd3373ffc1860d3e92c443fedac46f7a66c586d7e466da7db993f6a6fd9c1a8bcf158032207856485f47913ba0956c212b0c67743b5e0601da90a2dd4eaf45f5e5fd98616ca9540129f4a94e486a8b112f9b87034b0f0cd7ae8aeabebef3b18d529d8b5a75736e3c05183b042a72c9a9652ca84d70e71d8595f8fe36aff6cc422fac0939cabfdeb748d8f0a45b35fa1b6d5ed2c10cc57dbb53f242745711e52185f20fe719a6e0fd13803b36aad72ee6e38189b1bfb53e680a5a55a70efe7ada48ee9f98945039d28005e04d9c1c9638366187201d50d098c514fe6f351cf6a16ee8acad209085dfcbc1e165a947f0a9f14848190c578f4fa49c9042eb9c04c2b28ca32564084056c4c0618f00c24ed4c85116a9c19cbc69878805280ffc463380b1e903b562c7f1c1e5ff198e2b97b06da332590c6d90659b24f25781f5ef943df152e5dc30e7ba751c9b8d65aa0eb10a3e6a2c04805b56bf484d80d6a54593ea8cbe32e00b719aafc5c46392fad35643f44b7134e812484249d4cdae39916931aca0fb3c434cb984e2e885f509a5e278f5ca8812e5003a82d890bedafe9c20fc6", "2219eb0e66fa7d2e1b7b28f84c8f9d74f1b1bae3a3a801334ec41b43264bee1daa642d96a6fdb4bf5d03e11f9d4aa54831b8c63b0516eeb11698afd5391d47fc97d15367497ea794f9611d4fbb467c30bf6e67f49f07786fbdfdb46ae9e42bfaadfc6deaa7ba412ea81422d99f23abaeea91d938efc549bf77db5dbfb8be65ae51147cd3383cab1ba6baa0e0b67bd3c50f479d687c27e13ba0c462c620ebb4dce765fceb4f5a31da6bdf7022abada2170b4852a54d47695d79aa95a948347465606404914939edac8c06a675c02514dadf6b932453fee4934bcc2c05c14ae1430d77dcf9d9718c02bba5490a64a61f043db0f21502495109a168057303883a57e17c6b6758bac3b95cdf0b1999ac17f0fd34cbc215d3bc62405a1b2dca8bdcb111b5a3c0bb6d56fc954802b0d4035c8d04242c47b06460f7631a39b6f8a69d80667a27d0ee1fa927935dce939fcb43bb9173ef52e0104540de0522093bed6caa0ca9174ab18dce386b7eedb26adb34287536a0ef5202350c22ce6038c180fc241fb827927423f53445edc27ad6933a570a55cdcd2d4578dc80a0ca25a06104b81e2edd0b8b86dc02be913b57b5bce065989c996af4a37f05f92b95d1e66f5bd4d39fd404911db73224bae025d7746256a8bf963d33b8e6d9fefc5d8ee51b623f37a5f6dc8deb407b6b6ec584961d4ebce3c72e2ed2d64d7b99c8901466a8dac13bf72dbedbaef28d4bda8ef9976f56b34b9022f297401ffc0bc8bfab38e90fa04e2d74484fc6364cb3b8efc9e6ccf7d1f8b020c0118399f5bf509ee2f506762daa9ef9881d64b87993e1d7477d84917498ee4c57488e9f5023e467d30cde13da8692604621cf1a0a5b6c5c04d796978d5f29c6e65838bcae5423f99f481410521462c5f6f9db89a8d3947d285abe7f983a99e4faa6d45e8db49b1540ce866393354e31936c2f94e559e7bf200c22d01262d2fdd930c29f80aac4753647606ebedcab82937304b1ed3ecd334197a7015d7b6a58e153e629762860e4cb5f082460ad4ed5a1a1049102444e2c6c4e419209c087738bac79fcf7134cacc9d3472c3c046be22299278f6360ca1e7f4aed82ab85c18e9578697ca011610f3054ef282d952bf08d063780797350c2e34b0b6bdb1ba64e02ad527a7cb04863c4f564315667ee716effddc22e73b8f15860f97aa1681160a437d234ae402de9356f99cae70a9f9d3978f5b2aa50b803869e196489f25c833232d7fac463ad3da5755fe2f4407c95ebeaafd76496f14a9eb325cade168a742878970b3335b2c5814c53727cd42defef3200cb36048a215d421cfb252309a6564bfba8e0dc287d278010a4b6e55fa7a866e58b9db4ebd68b660e30f01dc4ae803c555a1fdd5de30935551aa749b21059061f30b262aa7e72618fe0a0cd450a37f82863e20b3e6b71c9f1990", .Okay}, + {.Sqr, "-bfa125346e0085cd669747bcebee4526c9a49f0fa128939817fc8dd0fd04569016315ed497d7a0297f1cf63ce4dfe37e791dacb8245152b607cfc34e67a3bd4835f1a7d6958fb90951ea6567c9f1499701340d959f58d0f96793e48bc43283887ddf46a2f8848d585aafc44b6b76d0b72c75025ea6d7f4402d9f60957c5095548140bd41e4fd33baf739bff345d86d3456f79406cd2b06097f7cddc89d42d3248d2e038fa43469a58bc8e5997ef77c02558d3c7d260a5c2a5b391c4636a3536b0b1a6f67760ea4ed7fab9cb86b89890280f4522759d94430f70ef654ebc85e04123828fad679d3f97e48c0b8e5a7fd618726cb22d1668da780b27d62df83627319f7a21e7b6586ff43e6ab06c56fc6b493a3374e9d78cc7f4ab2c5d2c465364c2123c2ceeb104cc3b9b48dd47e9e4358b9a11add0a3e90379bbc7f45b2e101bf463e6c476636735fd98e20de7acf81440fafea964feba3dde1779dc38d001c3b17503a24e2a841e1a84b179ddb56e6e03e8d78914321af3b25aacad96f3407bcab5b166812d1240374975481c33a79dc0a68e3d99299ed81bee035346bd2ae843b048a93263c33b911c020b9d785c860f955105b4b8be8e8145e66629e2d39a72e93054bd76673016d11332e461d159bfee02c8e898c376c335c99fe7343a9ab672a85ca50508ea76fba34cf8717d8debec03a92afc50ba5d972b7945713f5f5", "9be1bd8f769c299b2e160d8cd2194d0ac917126923274e3be46a8abaf3ea5ccc8ab7da1f5be919ac055a61e21f1a0a36c1ff360614b4cd88b26b6e799e6303fb84a5cd5e3d6b06321314ac52c184c9890dfeb57c4f89db1d8a35796c77ecf8c8bbf27c919ab52dbf6504fd3b5396455a3db3055511e8f42b25a4843d685ce5c799c1be5d4159eb972b755112f9607991b9b644854013f126f76025e2dcc0fda42b1b503c09ae182cab7051cc502612af2e144100525c17a179e4e24d40da0cacb4e34057c9c7b97034c9f7ee62a0824dc56ef6771ff237e2eb7c33416d15328ece28c6c356834d46ae1769e6768b59ed913cdea8d65e688899cbc9825d2223571a9766c1d58d0f660678f0b9f06bd078503289e99695db3407e9573c6db0dbf8212e84a5f9d4c9b90b6340205f928e5613027dbf3e5c4042dc830b2e301db8b178ecccbfdc8ba6d3449b468e652b9f7d2adf3fc10e5dc958931ac73a2cfe8b9a4a76b93b4f9a8da609c82c449c6533224fcc763b90c6c2607a4f910bb717a25f8d043cc48eb520c99d4279a601a77ab0afa15da272f2442446926047fdaeb8beaaf15bca27467b8a57ca83b6123349b611feaee450df16e2a85255e5d72057912ecf53689c1b5caf466074d82b8d08795afbd7136d21bf4631ec8a1e5ebffb26a4cee97d7ef0e8bbfca7f2f7af690113e8305e9f8eb926af94faf432eb859f45", "8f71daf40d7f56d9d198f56a55f920e297277029eab773053fdc43d362da09928ecad1c29d8c5a1f28879c81dd33f2b6f7274650ce6f686ecb58dde6cae667d6690739ccefc97c210913eabb5ce6b97ba424e7b0fd2239da9ef35f710adc94bdd20ef05b835093b7747617761318a368cd09e1883a053caae0dd79cf98c0b92eacd36a75022daf63ee03c7dade91d81bf4b0675d8e1fa406b4b34f29d20ab3dc7d44216177330e853ac7523406024d36d9286cc5fe1c552d63fb619e70bca1c24e1a4b6f3ab66a2eacefb6088e113c42b05a5962c97e34f54898a249234afc860aec2f21a53fffa8473a95939ee586c62f2a06fc5a857dedcedcd81f8315cc16824ec254bc93f248e08c10a6068c9ca1ca4920729c57f566a939ea13e67e4dd652a32bc27e64259117af3c1667848a4e5d76f49a26a31d10af2aa9942b6bc25129d6e185ec1d41d1889c74b0820dcf1cd8eef9260d19ba193132c258ca171a6fe80c2902ea865802994468c7aa756c2297bec3a1a4ee4d428a437555b49bff23ae781e3355e73c9097cdde33bcdb46391b24e227badd7e5f066fcd5e0d38a6a14e20240cf028bbf39ee2116ca470f5286f6513b1f3c8b734a425306196dedf6258c4e5a67e99ba925d7079de7f918b2c41df1c7835b53d94705cc09d5b36abaa3ec954ab01cfe456e3e884f56a7b17013bf4c1444d7befed86df00ef29514ffdb99fdca11bcd41764dab6e42728d720008d5a2ced914cae1d5adb643d5ff2cb2db0fd0219df4c52784df8e5bec18c68cd6549e63c66c218f64564eb3f3f4fc356e397a1941aee358881a522149a9787e24f1228d96e2dc2d66b9e3234a82d9ea177c012d4c04fc86e02e2be5b181c163c9d62bb8f15526f2ae88ff9247d0d5431dd36a5de8cf0daf92a5c24ff56bd8797910793850d035fcf62eb01baef0483ca1fd257a9c5865ab56ca82a757958f16dec8179fd4203ed3ed1d57efbd8c06b8dd4d7c3aa659bc613672240cb579bc4c985f5a436aa0a406c8af9fc79f455bffb9c4ade397513bfafb17a9c0eab153a85abe51b6eb99ad3a7e67af696990f3093a8cb169ac11dc7acf6c91ae54cb2489728aa0ac883bd8fd3ab3a6de802b9d347de4f68f847860880a2d6b64e8f5af820fb51bd30d851366466f1af8cd7c09ace8bdbeefca3233c15bdffc2d577fdfc91803201d56d514664cf02b2d1bf6f3ac148c44219c00942962f041b87a3b6be53f81fbf588ca02975796d5d80b3e0fc95284f9ff220e78af8829fed6f1d7b3d768148c60e0e569d6d783719e22e9b0b07ef03506c443ed42e590be844a53ab125871fc3a07a2f8559c1884f056824f049a6563fcfa1ffa5ebac608f0a0ca0caedc2b11f74938d21ff00b5360deeb977a7cfdcd6c4a14c296dbba974c8c920e4a356df1c6f752eb05be8b3c02f4acdc79", .Okay}, + {.Sqr, "-44530655c094acb036f2fda7623ef6f07f0412c7a1cc1367e741349e33294756350bd4083b32306dec4d37ed79c38e59c57d02fd403e831dd635d30d5b9008f15d3040bdaaf1980956a4d5fdeb102d8a4767c13ac86437877358ff352ba08927c4476dcdc3022141aea5d28fc1ab232fbba247abee49caafa341a006132870463e864a3087798c047a1f143c89987cf4a66022f9554e134fc5091b20d0fc8ca8bfc909e1b7380687a380ddc3a57b4149de95d57e422f63e742dc446403789dece8220123bcd98aec7514b6d92b9329f0dfbad014d20811118d536df041c462a69aa412a1acd53126d953759f66fdd292bf84692069cae8818bcafdca0ae7267cf82e4b9b86784679be45ea7f32ba307a0cab6873d3b26331a6959ee9be518c1ef2de0417e8d858adfe65e6790b9f64131b8583ebd51a66f3d4dd21a8ff23dc91f81bb12905a94338e437f16b23c3a12507c1153065faf7659913200df22c627a87e4045420777856b579d76cf0cb4f93855f48ca0ced12fe6024fc39ebee9a5198e8cee47f3b5706cce7a7dc25cefe178af8ceec5cbb5abc15ac86eb8fa37d740b88e238de31651f259f78e2f47b6d4065d168d57d30bf88896f0975983335274536a599572391ae10286a9363c3f1667c938eb52e56be554ed4cd7c1ddadceb7c225233cbf52d834f3f21092e5d3462a89a0c4b04c31c24d3ea64bf51ceaff4", "d5dba5d965c1c53e1e98158572f82b0e290c98c37dca3a3836d565372cc3b2f890bad1c8326bea93872456329e4dc464fb7e7a414bb2337f856812f719f6c896a96e78fbcea0333301b6d7c2b8e5e70c45411522ead5c4a52cc1bd10992be34c0951e26037abc58b86b06d2b75957d8213176651e8d159f23d3570dcab59b1ce288c65a3d867203452df3ccf9219ba3a1c673102f91a491735e3885244ba6535dd51f84d232829dda5085700ca617e47810efd08ad314b31fa64b89e21a7d2c98949e593818f25723de6e7564e7a1cb661f1982fd50c0a869d91916f0678e43dcd8cbc58ba8ea3ad1b7776179f777e43954bb80ea4218a5b76713e1eb2fdc802e194c5921c95415e07d0b10863e912fa15ccb7c2add0bcec270a88cd9effe6de0f8f9703698b6e04b4461d3948f0593559f42e5e6700b51dd70dec1769bfdedb3adfc4c9b3b7c61e7aa55f4bf273f40b27d40a31c99d52e562981fd766fd203a2c9ab8a1dc2691ac464567b439c10bbebc71e533e329f58ad4a3375925270c358964ce62e76dbabe14ecef3028dfc026c7a7bd69bd6264d04f583bab1846551843d2b54767fbf7d791b3d8e0840e6bcf48f07eebcfa604a95cacf3dea1a37b9f28c5137f723401c87fb106eedce5e0075c796422a68eb6219b6c8b547403ee0aaff7e74af112eb7ebce214bbcaf460fe6f4faee9ccf58cfdb437380c774373d8", "123c364aaa11fde603270149baa4ba589078ef4fe5396be22f3b480df149c4b8dacc0cd943aaf4e84044c17c5c906c38af1e0e2c7748d9c040ee927fb5421d09e58485cd3a4781f508a3600981f42041ea780c692198786757fa89c0e764377671cc1cf220c7a8d44e2be264c0221d874045871497de739902db8f640a8a17d99e2aa9ca0e93cad120d35ba38590a11003b967165a70be41ae747386348b4582b0cdbac42c8fb763c19a792feb663b9f1283b39389589ad4fe0d76b1a9a94f39b0f946d888456e75fb3d64a737b0d003c047d1d75ae0ff689b4e898e6b591091123af3c72f04912d555a9a2a7d36c410326d89f223eb003d950ba184c8edd77bdfe99e034105a2fbc24980f9ed86745c69584179219628155e8df4647f2ee1ec7157d2e02bc5e55a8afc5de7039cf1d1904c79a8dcdf175c8bfc8f2229aa0367c784a640dbbcffabddba22a06d33571b9ea573b165a3756a4a0f8d8d0b2e7cf72b7cc4c25dc88287caff90c003b02de5aa4633d0af219bda1ccfb62dc24e135faaa4663ab68419d132ff7753edc233bb63ddf4393c793fa295b9c9cef9b8ef0be303078bba8429ff6636c3916be98cfa165fa423b169154bf7ed4ddcb172debcd4d064fa1c1282a8f396a43c5b7bd17063a43fc0a9079f899ef82124e41d653c773189c1f8c74c165a7a7b783403886933a59a67402afd0d30bfce374283a1fbbc7a23aa1a5f64cc1a659f756ce782288d35c70c428c19be0bfab12306519e554707eda84208a9b8dbe07b64bcb994534f2ddda9b528b6cc0370de384262b295dff47ea532a2cf3989d8c0c7a2f9522de4307b71dade312161cea29dd5c48c0743c759cbf69dca0c43be6e4ad0a0e1847a33b02e99e56b1bd601381d2ae98fed27b81d8d543df31f2791eef1b643f2a205eb491ebafffa20825af1fe132957663678d7a0d80270bc061dbbef5cfdd914e2ff172e3b8810781eeaab27afc67f305c6c66156e45a88b7e563cd54b411ff1d7c757d258bb4f2b4dc4c3a55b726321e4eaf36455ad14ff3e0e1e69ae089dbb1333087271ede8043ea85f91b248906f7e8acfc070a464afb9283ad71cbe96ad627973235e4de7b29d9efedc8c6e503c194db318ad6138a923be4beca3f07fe5b1c1bc31014be0a5ea6e851a11ef8121e3a0e9528b6938e8a2d6cf193d481f99c1484da56a95f0d2b0f9a1b4193534865c09e7a98d4fbf33c8e608cb757c2ab70985c2bbca695b8bf0c6ebc92f9e6aa8eecd6cd81b8f23d2c65149b3d14a1257476dcd1dccdb80e976f603d77fc5897d51ebbc459521aa00b6f90563474af75768a502ab3436b80383165bd1ff1e8f12ca29c4360017b791f20ca7f3de5dfe3ac5ef3c293c0fbeed7f0fa9834e753d56df379f4afc5bbd7df0471389a12ac014469177bb9c99276a8815a0500d9f8090", .Okay}, + {.Sqr, "-90659aafe680be027189ab57f27f6cec06c158d092c34ef651a5d1675628297b504fdf146c2ed37e28aaec40b3527f43da06a460662055f88ac8f5def2f00b715bc94f4616a5e1306556b9d64bacaea4b5955e63150acfcfe036de2be387de2fe306b5d8995e25a5f64dcd2e3a30db933c116f642dfc57cba91f31e72be0c8c9886b9232c45b8840f60c70873b15b959ba89ce06ce7e4e201f4d58c7557c84ba52a8b4b92d299a18da02812c334a136e3bdbc6781ac2f2691571e260a6bb22241436291fa4fcd3424d100c46530b5000d177e9cf43ceb28469d1f86be006228ea983f1fe49fccacd81ce5fdb71ba796441f6339e2eda019d00367910543de45d27985442c789549c21d6133b520641edb35b7bf2134b9b3a011ddd96fe459495d9dcb43756cfdb6f43dd98c052bb37c0eb23c08cc89d4b40897f9015a3e7f64a6fd0cb1c9d1eaf8165527bdde3b2ee38faf93f8542f9084f00be88c29fd0126b495456c3adc1ee0149e6760053bfb13949b7dd7dbb2b9e6e2bef8e9b5027a5b1e7ddb9a01822a8941786efd8fe328f599fc25bdaf0a8030a25b980001e8c058cf35486e5d82ffbfe718280912315ad272600d2d4edc4877485662e2d47c0f4a4599832e2927aa2a91c89b4fee538b13acc7c62e33758a38a4ec13963530f5f7f8d3d408db82e59bd3751fbbad3c21f9a78e3b5aea6dbae8e5d54a0677a58ec3d", "ee4b239b1828172f7d5550517fa3783eed763a6c8179c079f96707144ba635fc2aad4180a340881ed980653a316db35530a28646cd018ffb3371783744efea5d016eba8e4991d86ada7ae68dce66df91569ed7e631ecd5be31ba7fb41a140cb12edd657313dbf522a17fd2b8f0a941655310c017160580a6a66bb5cd358344c7f3e5b617efaa064b0cf551f2621c7928fe03af15e82478caf843b3587c00cd51fd4d0959309208bcf54e2739ca9e27a358d248483969d555bf89be6862cb5b342b65659b8ef79e170695331b7bf52143d44129535a2729ac8370ab5bc4118970feffda75ea612995a5412589f8c5fc58014875db2779d0301570d51110bf2c4f4045b2c45b7b01ef2069e1bcc7d8efa80fc86499a4eedce26196a461211041bce6347bcf7b4c8f34b4fcee003a04df436642ecf4a603d85b2d926bfae9db2511337ad85c2b19e935d7018dec74d7747fa75f6d7dfb0d741f9a3c27290ef57a08989aed01c3b0904ee593ed54f464b37e242009a8579d281eeea920144e018c479977bbb4f0ea96536164250ff79224082427c02cf074ec21d18c8eca7f3792b09719202680a5a341efc391d091e1886441b042d256a6014238910a2c42e8dc88fbdc0ed5c416a64c358228a61d9b02ae62b749b908ed9a2e24bc33132f5e6c25ddde85c4deaa88242831801203445d6acc2a2301e6197191335d794c227b2746", "517276594f94d18885d2c57ff40f4f3005a13f13079cc60ba5cc67dff4910212c20409e588059c3f676d6e288f886f7e2a1766739bc88d8375316eb42a65c20beac37e989e15619f3d01753b9f630a6fd3017b89a35d0f647dd4d42a9c640238240689b2e0a453ab5135a486f88e40644ed911b0e6c59419fcaf658b946e0363418fe81fd451f91fc59e1be21406c7c487e91f714da431ec072fba67e2f5e73d104c070782d1f812a0d9d58539f06b6a3439be9106773e1d70a4bb872e0d115e39c4eb9c838649e841c603d61eec5d469f87d1000e29c5e1c4e4a1a24be38576d6b4abe2ce0c9849e4e0e04d4fb16fa4e3472134f6c62e0d1f8fddf2e2d07687c0f5e5aacac515126742fd64facf2c4fd63fbb64ffe2614411835d7aa5ee58018911b3401c2aa0832aa5b5a5b4e601c8e79d464801001ded784ed757692bcb9741104fce02571b2e21804e7d7fbf8d4da05cf4d50070547560c9d2f51f6edaebe60392567d1993025b77fe6a249f1d5e32a6f943de23c9721c2372b6143f2e1423c2ffee9da13dfb92bc9132b6a9a33b81fb88b6438fd3d3c74f4fd9f5c72a8d095e47ac6a55d6cd6a18f945a17827d058b55b3ee2d156a4fa385cd9e70a4f78c0344b6673f9dea5f8cf8f4ac5e2084809fcdd686e115fa08f4841a809c92fee78d4b57f1c86fe42011eb08ce3caf38135ffa643fbd2c8de8232d687b39c257ba434f1f0a2796d82172163a7c835d6b85bfdbda033ed0daa15b8d2e323372563acaa302f2d30344cca2b5636f762a719884e202271a64c933dc7add7d56f9b21163a02aa46d3aa96c19b2cfcd5c462c5c10562f3b2b0baf9f59dbe8a1566153e7b775c11780aba364647aab4776b87120b884f80d5c60996c8acb5e5958a1597b884a53662f3fc64e840d118f072bcdbc8aacb53d1d39e7038e4f195752eec217cc3ba046f9fbba4186742af738e9d88591ec7c8a688cf52f4bd886c1fefcb3534cd39d8320b2e84283cd3f9ed41ef6ca47ba38bf88aab83b0c26089281e63633200fd3b486b7c665d97ed0b9eb0471418ff14a0d37dc2b80198f33f2771784ec36b800dcda3b22d36d395680f3bcb41d6e754dd3954b82ad79d83841a0f74e779f4a597656f8dcf6a9a8ee1965944f2045eba7a9d46183314bb8d22cd069fe56144a8d9c3220f08e0f7a3ca56b72f3975231abbe47efeff7a72352da9a0a45fd9a572574766e4bf386a31cc9a0a099fdb7290fda156fabca438a9139d96eb6b44b376897343df6bbda12cf8cc6a2e06a214f81faa358edf2574d90678972707288bd7770326d1521dfc422abe79cfc3d1b87f669c06954217a6e71b841ef50afccfa88b7f0d89d42c866207b8f13c0ae57edb3c8630f8b92e73358971f81e810537bf153e5a9d0942700dd21a5cfb178cc94110bf75686e2f5b392367f08689", .Okay}, + {.Sqr, "2be5350b38ec3d12399a958ec0c4cf2b66d8a46dfd4a6d333fc8a21eacf6b2afbdd0769f86f9c30ef7591cd574095e3017f9891a1c36c7a3240a7f5ea91a626e403ca001480609189f164c4eda89cacfb32139260f692eea708fd07794d893b393111c8d28e5b9e21f9b7a0b5980fa54b265713dac3e9ace673ff8303e913ab767eaf3c80e335ae12c2189caa6d904a92c4d1810e7292aa94fa9efa010f4d775fbde858d8ed2a12007c9c60e69a56a006865ce5e49f21e9f6e315389faf15f9c78896518e0e2d41cd3443f6db6e192f08990046e27c55eca36267c01e9e312814368b81dee555f792887eafc3f5de7697b36339a06b140d810dd443ec0e27083a20ed1a2ad715a40d705679dda298b572ea32d2e546a4f5e49c5c31c5fbab1473a49ba7d58d68c16ee5788be7a85ba52028ebc0b10176c9b19139fd0838d2143f7aa70999a3bfc2d1c707a7c3358c14aef1647727ab5cd604173a273fb203bf38635cd00b8c0c820f68d36f63f94b68d31bee93c86e525a107193ce8e6832531ca6e6530710ce8fc3fec0e2d37b76de4dfcba5b96664daad56ced81a80f6034a884dd5e80a792430bf0b463d85853b97ac6e071c469ca29ad9c6340460384e5245d88601ca6c5bdf3017405bc31c5a8e4a9c09b0258b31a194fe90d86c302b3e9a3da4c74648f22f32f0f1eebe83292682f67a674706e43d14cc5b2d8783242d", "68214b2b6bbecd6d1a37e70febd4872b1c24d14b875b46bc88bee6a2ee8f992d5a292235832f76e0b3653091ae075e22e2c358f5222207e4581104b45a2f2e969a52615a385b81018911273e6f1095d673d6920ded910b4d294644397abdc960b567a955cc635978aa896043b130805315a139ee4da6d3c44ec05185392c37a218ced0ad8f85113be83fe7e44615c846c0bf022848923253b1899465a3a8bda083420b3fb940e0a5ce9040c61c05b1b09dbe5118f00180641c731288ff391588f652898ad9724d17a8f0e85239fa629d7ce4120cf53d73af0bf178334164a406dbdc044d30f1c6045be3237d814b35982a84538f964ac81389788b63a73654cb91424d52de877a2eb1e346f1152ae00a62701fff35af3be0fa0c6aa0db305f70dced1eb9da9c7146d5f4badfb5ba489ae10dc161325e24af1bd25cccc7045934f7e040d3dbfdd64e7012f40b05155f96a9b1bd88067496c3abbade67548e0aac21d3a00d244960385a0e9cde841eeb35eb188345f24be7752f5f15fd107b6e0c223c99125ed6bc5759bae5eaa4ae5ae8f1d876f39585e6068403f4daf8f588b0355048d744f3c788937d85e0603ba07c31e575856e8cb4549d7e3aa434942ddbeaf56c91fe7e9fdbf4c204349917f72fecea3c9087134471667bb90ce231d4a2a8a4b9ba0af014a72f13313f4939e749f19f8c623ebc82b15984b87a2e53d73b", "786cd09b630d9392433fcf11cbc7afb4c6756875ef519b241d39731d3821b2f4f2ed5a6c4bb3a4e25fb975eefd9a3b897bb3f5bb132c1697935e6536991e673ccd25433b961141f2e589b5d2dd0440081d6ee1b49a99a421fdf54dea1383c73f7da6c7d796d4f5476b50b8773ca3e26927f078d2fdedf325bbf59431ddc098f2bd059cd2a0b7ac8636eba81c51dc7f41e006dfdb3f8219ae0476247fd836224a84a2b03902478850124d2d2859057db53c43051275d2a9b5cedc3b90900e0a34b5e4eb7f98d57b05ea760f8d9a422f485a65f270fd2e066970965dd018e4a3dc9aa63ae253f3b1b69ffb928c95241de447d4e424b5c0a81b97ddfb1b5cb32b22dcf51bcfc6249b4999ae11bf0dbcfbb82f95fe96a5fec8da391f4ffc59eee494289c4feeca5246d567c25acc25dda7f9eb47af216e227b4fa568edd779e9c883339e6244abc59149e2136096b68e41856aa3c4e42737c856dc9a046aea96401a1e3bcc118c84118e4b8bc9550117cb00193cef4441c5a729f263ed54b5cc787b0242bbd598d81e02aa88a718e467fdd207c59231b1738b8b8e726e58e1edad8499816be8b9697ccde94ac796f41b42f6a460f1fd43be079cb855e00dc834e247bdb8e93302002b0400f6a1cbde7bba66cd33bfdbc7f7457538c6980e644555903f027a8aec086b14e8661fb9c73df39887052b2744d149ce86b10fff754c9b1bdae489f6ff0e391deb31dd1ea7b1cec4ee299825c1805ce2c46d8d46fefc9a73fa37158cbe505e1bbd617fbc3f82a747f5be676d61cfe3edd2c4d17e4d009ee2f3d7feb38f8b883bfd940a843d4f1429c1e99d1813a3623d60e5e6a0fa8553996cb5c51af47acbb0adb3a47f96144825787f5b4fb3ea772c12352a56d22f6d7f2761080a70f7addd8c2ba790197eb0e506dfe943c36d83dbcbf86838493a4bd58b44bfea1903113ce9fbe87510e1a5cf06a99c64d04cec0adbe87907487826b3adabab677f7de01eb4145790e0eb2dbc4a9463fc54ef3fbdfae216360e2ad4f47f2ceb3e8b14f3598e95f5249437de7de44e383f7d78d54157d3134dae93cd3a333c8f5b120d3bd12ad4df2b8b3c89d71c73c6848e97eba0f28a40685f9c556b5fe39b5ea2f25d48fd3885395296d04df19650faa1195859d1956f3d4e2916658d8cbb3523b2fba45837928acdb96348f2a246d8e50e68ab006282564ddd54f21e1389802a56d8a0de79f11b6ec20dd457de1c1bde416a03d2ed57321ba85438963925f0657d2d1e80c816b1677ec26446f60e01add6b222f38138969e637e092f8cbe0117e1bbf8922154b8194b80b9038278cc132477c12f3fbeba831737db23bc4d5e5d38971dcb34fa32675581cc2225429453c9e363af5373e422b0051c88534d4bf7efc0a4d41379e6af0bbb5b94836e16341428ad7464927812aafe9", .Okay}, + {.Sqr, "-64eff82ae2f762d52d9e84ba34d2cb5cb7390c00102c5a3165bd0fe7cc306d68b126a21ce9f6b576632e84d4d846ac82f4ddc6dfed5b70e2d4563ba3d0221b84256f95649a8447afd729b5357da3fd346f81fceb63420244387a5d8dd04fe2ae2241a5b6349f64a07a158b01ca4408b5a6b28bcbbad6255b88f6bfecf45d1e86fd29104baa0dee523a2a18c94388118b698f94f5015f2658bda2baae0c056895c29e994a4b3dc2d24a18f72b13de1b87279e7ed5337053942c9ab6ff2be69205710113446db7c2cb8469e6018c0b9be95d9b722829b2d521a70cbdd883be44d40b3066c69f1173b2ea96078dd9a1c74d2489d16a704f307a813e611a6b415b3a7a902836eb6306cc46e296424165f0bf98a74acf41abc4120956d1e5cad78453320802aa907410e8e9093ef93fa9f8be62e3c3722ff1291d7f4f2e7dd9c6e9104beb86cda872f8d8cf3ced7482269a84cefe6ba8d443185c0f31f8783cc277b45eeb0637c9a53674746d6facf0a049a0aaae4b6153277182943374704fee7f9b3d00eca2e8cf92ee3183bffc66c867851adcbcc9de9215a082a8bffcce407ef9b1992a8dd8b74b8727b9ed0aadfa6fe103721dbbd6e99fece44168e6d38fed0e0a82f817056d1c3e5820e81852c4e76abc36f9c7e0c55d520cb11179fbcc2a954c46ccc4c399a236710254f27e78614d86a3965e5545bfc41606e878f8fd1988", "f99c785a2af66f8e79a93a327299552fea68456d7ee08282675efaa131b9a50ea7c4962112da205eeaae3f488034e537721e78394dfe33931d9ec305ba88e77577ae9d6b18c9bfda7f31b1ad0fd35e86703fdb3cf3a4a2327f645bf144a427bf467c9a88963bd5dee7fc70c28df519b13cf765d033af39fcc257d060f5b82f68a8463e215a9877223b12ace65a9f5ecfb888fee60957d67e2200324e2b79ba81a0989acd0ce3df811ff7c1fba7bb17376c1f7c6b04491f2978af5b37ebdd27cf6efd445b14224fdeb88b9f3b20ef5454a231bda6a4b2526e6c1245cbe657cabf07ec84dedf5bf0d4c0e67fa435903dcdae8960370902bf374debff2f7cb8ea4d6fdecc0d41bdb25e86ea99de05ebb35ea901b3b93a3d3068619c97464e8fbe569be27814a1b178f5c399e09612532e6d21a12a123c4608a050cf1fc7a9614cec84ae268037079e5c7071a9d688babee9e945cda0f81eee06bd8d5d5ff76dd7f87a494683fbbf09b8cefdad1341e187ab45d39863909b9795ff6f60625fd80707e812751cfb7cf85f84dbecbf2029eebc9a527e33332b1d4014790a564b1663e403dff971fcf3f04cc86b47b4eb3d400dfa80640891d27660eefcfd301716a2ae5dcd01fec47158b9321812df48817aeec0245bc7b311c291e6937b6ee6a362ac9c429f70cdfd0815d931ccbbd8b88a5795bba422d3d3a1c62a7bd5b3b41f5207", "27cc5ad2d1f82e0fa7923593a8317699198fb44216d87413e19a2a967620786f3e6719af78bfd131045c289d077a5713d847eabe03e2d2b887152b3c6768a1643f13f73c293ecc068de1c21c4f510b405455c0c2e7db3e1aa844f7cdcf0f0ea745e4b675fecc0a74c98496d153d1c90e8224b8a0db2ec38e229cf5d0aa991e4f0b8d4a3f267a8fc41c890e802d59f6818080dd09f2caf89df75e353f17969d629d1ddde710f7ea4335d8a01a8c1e3302f85923d5f58271500fdf0cf8269a99bb5a47fb0760154ef6743e5a217718f89cb47a16b9cf48ca9b90e9c2942a4907ceeb0f6829417d0cd45a79099005d319cf7f7676464e74ea62ff932533a577990f0b25a9ad1b52e3e19cf685a13d5d3810c13f5e65187acb496f46c83ac6b3cc718e72f3a2e01670a369932e2a8825b455cff85ac933c425d9e824a6fe381a7b6532152e9635074df1b2d71ddcdbd06edca0a43382f0c47fe282d34fc4b93d87300452057e929f4ff3fb6e3d7d259bccc5864c0c2b6b6506168a6614d10dd0949f12bd7594eb07e2cf95abfe0cfa271afd9f7830590af3d09e9195edcf0c6a561a38c9a32ccf951bd82a7a34b9fd4fecac2cb97df9d6323ee2ffefd596f955789c2c5fffb76f0f4fa9171a2cf328303fa0bd96ffde5cb6b0be7fa2f7083692982f59e0fa0065d049d8eca4af30a6f44b49d97218b3620c037819a50f58efe08ec982f1146c925e899264142ce6c777920474881652f04dd7f10f70885988a1ea1a6f33be05f3e629210d066eb984e4e3e13cf11b8a97d64754cde9f10e6f900806224195f6bd7dad01a42e09dae90a5940ad0e2a43f848ab772a44add7b59d2c03d4a120ee87390d4a0a23e2ce0a3ece7afff4eebe6a03c89c374d55e1d3fbac966a5b54fca04acd1edb5a579d0c85aaca7b49093c8c37f5d174f697055fcfca6945ef693fb859ae341680b0318de82b1e61867ace910b10ddd9c9bbc288e6f179ff7202104ab8c30637f18674b12b448f96f3127e0c0bec7280e0761bcb677d8163e3c5d1cef6894838565575cb6b229a875093395ea4b9682d7eec81917266d35192566837092723d5d5d503f9814a7bd4d47350d0a25adbb378c22596bf2362e57c196177f5f4cee955faef2092e21e94dd27744f20a9899fa861ed8a47d9c3310a5b5db4b94098aabb2dea0093468d824b246d5de592d238fb66b5d659b35f1f244d5998dd39f62dcd28572174bd83d41b5657034c6a4a74a5e6a939e28187089ce150f599750d05de0072baad45fbfdd244ec1e6632626a081ae074ff5bca2564eae496dbd9941199c0de55c9d26be6c204d357345a33c11e55c5b007de6e0b86e406558a5602d47856bf3d5964a39c5ffc3a4b8f7dd94ed1098d5fcfb08cb9741dd6397cd436c358e7537f4b96a208e6182f868ab0f5b019cb32f95bd840", .Okay}, + {.Sqr, "3b9404e3640468c42699a4e33db6fed5ee626166fdc7decb4335feb97592491c6d1aa3c587a1e0cfeb7a9f4e63d0168a701429390f72ab54da5a3d73bfc67bc4dc823799454a3fe7e659b71b21c32c99f609b5dd22278f51df63282393755cc3dab23e192c6b7af1de4edce40a9ea1dfd8284cdf52f4401ff4f55e42d3cd2c011b9f8ab92f8c5fd4f7ca5781d2b75f2407081fd0a696314f3e2f6335f2bf58c6b092fa873c301837503ad6f33bb59e8f828200e93e23dac3a24bbe7c7d54169ea79c3e8e146cd15ae86603853c30244b618e95005ca42d843933f1ce8b1b25768a2122625366e86aed4559fc5d06d2b1d532bc317ecab4b3b0533b9329742c0f9c41ca52430f73cc71a6d287e85f68e48e7272d698f94ef7a2ae791a0250256842358327ca0dee1cd4ccd3b06bb4e9ddf1a3ed3c489067cc042206a0c5dd4e4fb156827494d76164bad5c3b07ff1fa0d486683a2719f5fd1dd22fdc92534d9ee1f701ab545f196c814160f610017e45df628841033dcce058b392f3cf40bc7192d740e79ac5a67b8de40cf5415f466633c9b81ceab00f65eaf4b6b3b6c57eb4cc82a300c37f1853fc32477b2395d1135c8e12a6d77f9320eaa5ea95376c204e18f3c4f0329cd9966fbe62dc29b1546d333cc28fa4972bc086751544d7fc323587ff41a058b577c4c2c511e0c0f32b79c49e7e3ce8a6ad0035458d5b6e7959667", "5ff69a50557aa53dbdfa4eb7336dbe831cf4865811c4f694f306ddce29a910ca623b0385aa710cef1a324efbdc2a605071bd7ed68ce0ccb4348b0bdcfe680fc5f756c0c21e4852040029efbea754295964f313ecff78c4b29a0b05dae939365a950f406340f083499ad30ef8d4976307e7f53d259f2838d8bd2c03c901ae0abbc216fc42c00a9b1087c6b32dc639348f59744f737fdb52b02626dfdacbc57a6aa25ac5b81440fdae8c2c34c1ab7b0336ee111702eaa5748f88538a4e8ca0908614f75ae8f25ab6a8ab171470dacee16051f458672a7ed4165711ce6d67f60f772d6ac710c6e94f6a87f5476624c6b53d6c4951815618dd265f59866a9fa8ee505ccdfd29cc5cf00e0a0123364fc3ac1b36bd17dc66bfbe0a4cf58d1dcabe02e9d23621589410c9dc828f7c45572101b536013a912371b68cc534759a40eb1a9d4e1a47c57cba30e8cd4ae7c428233cc4c4f21bd82933a8a7e92ccbc22e1c6a4b1bfb8780b1ccac5db341210fb58e8550b1c731b1a2eaff13833896983ffb651911093c32c5299d074a6812e4394b5d91d3a46eac7667ee5f30533adcabd6d55b01d0078740460aae0771c9d98a2496721a0e2799443bb75f763238d33430071858a35dfae98e47fc165d57ad5672992345f60b5c515db62c64b5795c8d7103b5a6b78e974916be4df3bacad5aa5bffcee655dbc1062ee306bfef82106c185396", "ddd8fd6771d927e36c2d2a555fc6d41141b95922de9e5fd2917e036bf75ecf081593452d10b2d3609d93c6221e02762e5dbb2f8926c350f1ccd8b6ea3833fcd354dee87c45e54d119a51f011cd15eeeb130040abd749e617766ab25ff30841d608111cf7abbe6cd5d9512a5491da0092389c19ea2c43ee8a4691540320545d4bb053928fc8da7c5eadb396d373b43988a607b7d143421539f41b421a40b873e50e1a69280ae8eacbfc9f0c5d69180a0102d73c10ce477e5bf9830509a91f491ef0f06a214ff8d52dd5ee24d3d1dea50e9fe78abf18bce29f42906c8203a8684bd66efb8f3935db1061a4bd9c643d2a2f538ece51a0ebeb434ff6c08e898d28ef09051ddd3ec0fef9529a693faf1406fbbd5bbb7670193f5f124b12ce8edaec4847fe34f6026d4e9ddfee39f9a171d0b3081b174a906e70c46939fb97031e543f649e68f8e3e8ef88a460a9a7e47098aaf7d4bf9836e53fab0bfdb85dea7147cb001fb7e0beb7c99b5caf87267ae7acccf92ea9b99bf11ab39fea9e7b52fecab0d36a798cc0b86c88608da23ddd51b0ddd68228ea94aaf0c48cbff2cc9b37fcd7ce4e223465f5ffb0ec7b647d403fd996a8800f80d2a4e58e8c9083a4fde42b36dc7aac5a72c1510e5cb488fe316e8f7c13d3997b8d7907af669c75311d26a69f3e6c1e54f8b7503a4a41c9db8e70a7e46ec6f7fbeef845ba30c08102577704f23421780cd2269e7a55bc2d9db598bbcca1da4e65cd0e72e9894e43bf196c84be5828395a91adc64a8153bf85cb4bfbd5f81c66233fc2da53985062f446409834fc14536ee286edc1bb43d7310799322c93d29225a6c842e4fd99b994ea111b7fd5712be4c0a4b130e46e617244f53b468c4c9c6612c9e1e5d5ee03f8bd262699775f79b65645cf4126f80d110cdbeb83e5581b37e35299d8a7fb0ee884e3f90dd5ababe52c6d40d99aa6b732b06c01f7c50233879fbb5f489bbbb7346a837499ec7e8c0a23e158fab85de966b0f500acf31651106e8c7c7a95c3ce8644b6541ad0b2e263e44af9196ed8012f0365e79ad4f785b92797d4c1bd394de63ad2f2a94cc0d895cb269595e4fa3ff0aadf102bbc8fdcfad44aa7dac050131c2db1807de23b9d60279666f96f5008f233fa63372946c7aeca9b189864a4a2874b641d60cff69c7545004a04419aed825b4f78d6d6c2f9925f4e47a0b0e777d6895e2c42a702e66f363970174269c11fdfa93354667241245d5a93ff1f300c86d59d231dd120303ea140603af7c85bdf837273a21b2807b3752f0c629c06bbcb542e6cf6e09ea4e8b5f41f9b50c02caf4bd657c3bf13b36e9a80deab751d466f2042510a1efece05f9ec16a3f6fc641a03bf59c7c5c6b34ec15cbc6b052b0994bce68c804bc816b17743ed7da9b15b2ba6d2969c7a86b7bc358280205488d4a4e42dd71", .Okay}, + {.Sqr, "9c8b1f1fda2fbcd93fc0036e9c48bfcdd0f53bc72d2656e47fb45e193482f4071550429b057c805fa7194d3e9b9d00d607e5ef1d50cbbae309a0c24162a4e82dd29ba5b29c38be340bc5cc7f7434c1304eaba4d92f5ff40e05a9779adc25f2a303cd512ae49b2debb1140ba7c4014fd0b4ddbfaf49456cfdb18f9ef6f80b9831c654122d594a85bb6e690f46544de9d8c558f29269e7bdd9a3547f90b1ee4865ceeabe9e25915d9989d45c4a60843d0832af348f80c67cbcd3e08337c4a6610b7d6be36ae915b45461e17fb8c74913755d71030351dbf3890789f9754d6377b5d31fb608908b7ba762dd911e3670e2dd25e9805d327b1546a06142f16cfb591adc056b94d0337215a24b07aa601d123ff605908d98efca1d6a65b44152326f0240df3cdba8336247298ff28b873179f5226fcd1572ed41f336171efea92d1b1580cc05a7e226cb83dbcbb4c8f4fb2c254857dcbd19a6b6dd71859f94cca01a2088c469bc4b3f7a0797c50386651012506c6a264078cb95711589e9b1c59617193d56224bdbc73ad61b178b024455ff1f0774f810beb3f1f3e5156f29a4edb5ab6f3a4ca1ddac22ead880f87cbc85aded701f8e25aa183f14aa106a1c68af80e128ab872d47797f259540a206fa47074004988ad2c549b21111cfbd9a0f346b69c310a0bd6cdc0c57360639971a80116086fe1074771e330601a37fcefeb8435c", "bbe99678a54b8eef89e51acd89777ea4da3ea99992e1ebb1303bd437705d4c81150ae0c0a97fe7cf981e8788d4d67210c76d6e4d93d6d84b057a57371881cb09779a69056fc93893c515a48a049e1bd27521128342a7554c3a65a005500c524ab5159244633f9182bc6e953a284bf52191d9fb81922dc8a9cac133be3625f452c6f33f6d05918ade47424ec0a83f18d83d2e3c7d2cff652e1d61303cb06cdaf5e04d71922b2572f9412a9cd36e077711e5dda96ae08240753001408d365e02ae09c059dcd5d422a37bdfbcaf4dab8a23106618a76dafa5df8de2cfc812749ae58bfbf0c4df7260f76e797c31dc7d0639d2ea94cae141d5810a1968eac8e63ba97aab96b9abc0cd957e601019e63589f68151bebb6db54fa3f2962a45fe3f6dc40551eb894035be913ad439ce724c7e5dab7e187b79f9b2828325814582c82fa417bce14dd0137f51f661329ba564a00ea6f88b25b7ff179c90b0bb740d5577be29dfee4305619ed0a9ab652242f95fe28f36bc92722c1dccba14c8786a02755e1a25bdfa44ef8b301ee165f953d5e7325a51bd963e6adda4b325825c57c4943b338c829753f62640e920526bfe034b90ed341700e7d3399c1eed1a38e89572ee5b9ed2a07b7b9d30c5031438a7de01a7d56ef365222c7487056c4c8e7368769b1d77a471634bbfb74505d256070c67df0b0af1b57175699b31d289f5189d632a", "5fb9d989a249d8cdfadeef495d943bbf6577b9c4029255600fad2e57bf24547217537ce06e94973186427691cafd3886c69945a7e9df20056a7b3853e7d0db16362ed80799a12e103bab930d4b2ae7453f5e65a061948ee56a499c4b8c6800bb7baa9d4804cec1bd7240d45a965d2a2c47b8beefa97cafc8cbd0da2b7d6c57d64a55e2a7e7bd63ab0d4e046b348567a71c0ab71328bb044cccab4c0cf87bf0229f0792d66f076a9c2a4616d5a0172c5fe481120ea49997adead7b343696afd06d519d3151f87b52c5b6d53bc359d7695e2b7d3e6e47cb1fae0d8e294a45bbbb68078ed8d5d0d77ff7d44bbcf67313884c8487befbce726215f56f54aa40cd1c9b5d351d8516c4c955036db34653ca3d2ce1c5eb8bbf3b9076ff705403dce6270fb40197af8eee7aec29b561f2cb11bfec02372c0683ff477871c1e5c20c0d507ef19043a80753b96bf570c1063486b6a8dec08f1aee7bed44abaa1b4829f13c301f8f94d516cc739a165131abd2fc329da22f0b2a05b2b8a509820897284944f3e3a7166cbc402dad8de20895486d2473b5007997444b243a3e0d828e3c69c5d9af2ce28c007a1fb4ec5f194de5399fe40171ddb82620c42f0d068ccf7f1df8b8eb93191d6792780308c68c6cfdb8af3fe2ed933074281e8566a771959768af8bd45de538ec204585aa98cd205afe6a90681682819b997e2c6d3749b9564cdfbe85aea25d65fe02a70714dccb4d988c5ae2dff08b5279415d43b88ed3a29e925a6618020d92d093ca55ffa85aef5cbe75e3292ffc069f14b314e4936218d2067ecbd3bb7be704d8ade3a4bfbe8e1a0ed92a2930442bc8a2112ef2fa09334534bf8649f232cec36ad951838a9e3837c1a9e29354445ea15fc6f30560b29f9b6bda835a80c181aa7a04d4c6b419b0cf763d040f7aa78d8d1e34933d3bf4e83ef7c3eb61c907e3814612f1fe88bb69e1913ff68abf629a288a6cfca44849dd98b46f4448126668791a71a731401093ca4ab95ccff38ce7b100020e0e5fffbd73d2c7ef70dac2e948d6656a463ce808cd0f10ce18d3aa8d1feb042978c02a19f3fb9010abed2aeaafd1c1754e7ed1c931ae5ef4042ceed7fd911bcca5d5bd722c3deb1066951f863690207e6cc55cc297c3b53749f0261b165d6476aebfd3e12130c0c7131a9a62e76be584b5c95abb37ae1addb8fd6b515397f389f5582543edb7ea29006143f27b0f6fe104cf4792263e93517ac64938d6b5c84ae26bd96aeb963483cce906fc811fda6e5ec523d6d2813c7eadd86314e86f14d2e33b5c021c6140f446a0d1b9c5ee983276acbef803676de20fbe7c00d0a42f54c442e1813bb121cf400e9daee4d3768687d3464d233be6864944e421d538402658bf314d6595c0d79f2740945b49acad26c7161ce948777e4b3cc4c6ea7963ffbda5b75f94910", .Okay}, + {.Sqr, "6ce076216b0a1a2f4b917abef8601b8888e3f2af00ab4a69e9a5ab1760765dc767ce97196df99ea22aa6f3a77a862f3aedb314d268088687adb34fc26bdd05a4f874d91bc1af36c4a4f74c9d1e98d2c0ce266b7a684ea5c5fb73ef8271edf56caec64be25b7bf5e842f057e17abdb738ef95ca836139306b05820c72fe8528da719da221dc247090bf95ce001eda5b2fa9c68ece1c52f2c2d986a8f5e84b90db866476d3cb85b228d78616e5deea4c9aff5f06c58e7623b76f9e2c5ee9d77a6cb22b8acdfe8609ff3d50a3cda36cb950824353b4e204a775c743d57382695bdbec41ce3303f58d55a1a2b24cc5e719ada2454e137c55be964bf3d430a803a047456034ce8cda459b4244958564b051c0ba3880325cf7c54742a01cec4f8712ffda9e09c4690e7cbac1a37e752578f647918f2ceb850246086e1162188305254c72c569a3f217c1db2af9327efa606e76231e13ad2470edf1756c72ae8df1f48a5898691fad52cbce0b7582029c3c1ded57113f05ee8f586c9858702cf6a5f7d6a06c588d607a75a82fb6911781c775b640527371d308aeb1ff65a23a8cffaf81f455dc4203eb48aea919b1b3682fe11a217f9c274c9d2604ca4f75f361a4601567dc818d66506e4e6daab994fa826ae6700668c95ebe2444be480e080d78000cc58f661db3694ffa71284f7403c417cd69bdb04c68ab3fc97c11faaa7de1a494", "dd67f9bedf4127208ed1dc5aec1755c89a9c75471ad452102cdf6148826279ff86d0d413c9a5f62a7556cda0aedf55312769fe13f6075f0b5ebaa4f80c5e66418d07a66f1d6d146e94ed3d0359dd8919fc76e5aef5b0ee8c0f749218985a20836f2c052d0f516f22a8aad16d6f24721ac368520de25e773019b13cef9afe57fad9d77ff6641feb82833d063a5e309582042ff672ff52e2e8a7133dd48a1c946de97fae319ac164249cdf05a82989f050ae970851a16bf67321c2540a60b236692de67977ecc5af4b327ca092dd08b5ece1e6bf413017570029fcdbe264e3ddd25f6fff4de3effd474d94b44ea79915b87752c45437f318565e711f3c2ef48ec395498f9327b2534d2077e1023c1aff02631e8bc58d112398e03b35ef9ceb00a48f07bb7c74fa8f30ccf0f39cf2147a5c2a0c8d1e830f8fe59fd12a5f626e97698fb3bbfe19aa3bc4718601399ac0630e4567f50560a0cb1f854da94fe2b49d9a9b977d6a32bfa1d5e37e3325bff47dea65494d405c34c62dc9361b8ea686bc507d441eb050384092fee95c302536bda17ae249bb254e3838a7b2c761bafbf7e399a44f874ae6794005942dc53c6e8345c3bf290b31300cbf31bd7e809150bd3c5e1dc96941ea0195fe89b4ae19ce866a1e556b1c010c620a85cb11ef380d6f827d6f82a1c5fe13b91387f307d190baf83272c6e0211332b1395e0a3187bba83b", "2e4e287b234eaacfd006ca4d1ff899afa1cd06c2f802ef17e73b5ff2993a7a7034c35152e3a63a583222ea8e43849b9850698933ade0f558296b68e85aba804e2e1ee2c02a5d6aa4b28251e84416dcec3c8b246b570565905e85da592fcc9f2ac2de4f5954eee6c714fc57ca56ea82a229dcf1d82289bbd5c5c5be652c5003e818949f235040f63873dc1247f75e4269d40981a5fe77f1fc1144149ef1c6b2e4ea3940c3c991dafc116c22d9f7591409b0fe07e75521a4acd7489f792e3f85247b7936934137e9592f58eaca51f0388e8cd1890b9325085c49f9714080999c8216939a79c08e5fa692e7d0c6bb04d2b2e08018cd23ecdc232bf17bd76e38c9ea3d064faa4c8b788861bbb98a5a1ac5baf679f8477a4fff499940d885c8f9dad346f8948afc3939745984570d5b23dc241e39d4d0729eec0d936e9de3e2fd8403148c678cc341b2f9e72dea7f5002f58008bdc41c8ca857d898e6ba3b9459375c861f8b3344524f265177b1df4c112e7a29aa03c84a9f91cee329530a0e6029db1674c2533d92bd8031f831bf8537a44080c032c30cb4b9aca79facbc871e9b7e0a08c3e70f61faeeba754462a77130a869f95d367b62929ad24dc976ffaf65938dcdfd1d98044e5c83cea718eb52b3367c3cdd1f7a1efa750e354a8f7c5f1210acd2c5e2071b5915a4de7f57a4a57c7828c30c8d27d37a58c8711469b5725c9c8d18e763ab542aab9752966f89640bb8184de4b24d9e689e21f2716b38fd8cf6adfe4f73ebed373729f50895e048944b0ee024516e53b5c441bbae77fcc1af7824237f3877c2763af3eb648c872f02261ddd96de3a835048ea2b25d79745d71f3a04d8b028dfb040342340318c32827cb472281cf07bec83db6fc0d949ec528bc9cd00292e1e20bbce8cbadee4734a174c56ddf03fc2da410c34443ba6f55e2c9f3e0e47bcb34fc87042d0a60ae13301ba4f924b6d361e268d4e32b4369ddd998c37de8d69addef5b49bf83573fdc25375a03cc127e177ac1e238d559573f39b186c29b8ce2e707f7aba01c72c1fdf64d811e4a51903200f49ea3069d32504dcc59eca273b87126de021e7f0b5ec17b88b1e3042a5aefe89b7612569f5849ec2b4cc1b52b19e410c9c40c74f56b6c991ed51ffb7a6d7bf8958e128dff74be2a30c760a0ffe6214701142970738861b1e8c71743b7fec14b870c445d5a4b1f330a024e618a60fe385e8ed0e7291ba5e0978aaff3e69c8fce1d9a497490d177f0809d7be110de3615ebc5196913d15010f42bfb232b37673690bb03df622f18dde9c2d153a50fe762371bc234bc25ae863723b21430ea80ad0de2bbf9769d595d5d6aa18085b9abc4987308c1b88e8f57903a0c8555ee8f17a95ae107eeec995ac26ff2b9ec05aa95e71a113f3fbcb8cdbba95aed1431607375eadc62b3df5f590", .Okay}, + {.Sqr, "a06ddde00def0e581b52b55a58b14ecf8a8a75dea2c215ce3f94c228ab4e6a820bb0f85a5543b42e7f0e0af1531fbc0c6e38b9e5da469300e2e47b1aba4b4b26029af5cf55d2860b503ccefaa1fdfb9a6221b869f55f6de0fdb280acf7c7e0ba21f481547f3fe189d62efc776a20c8b1950c184e42c0ec86e9a69ee149106cb0f792605940d9594b38fe32d2a58abc1057b0fca7c58487035ca675168f1fcdbd0da0191d657b232ae9fe32a20eed0c5ed5389534d542dfe3e93ab6f2f2da6f819d67ce4cc81d072bddc74ae3184f0677c6b37bdfacb6264186a9061576c31244051bd07d79bc55f061cab04c4140147a2dcde1f0637210721e3b9fddee37afb0b2dc0443843bbe56128d88323c22a75668dc303aeb85d730988886311ae00d4995dd5db2cc8b1f9931e6767b960c4473007905c17a593e833bd81ae38a08031640f852af9679793c0113f0806b5f51982eb3c254dbae7a455ee0b23a6631832f692eb89db7cc69e724fd276d176ddaf9801fdd19c4bf70dc8b77ed6e8f2cf3244c1347348c40db0687695132cbd387505cb8ad90078bf19992009517e11636e353d8878b6b1fde7f469acc8993252bc4e1f07a590bebf39295364d392dd1730f7e56937b4af6d65a874abdf03925bf47c89e582c3ad643bc570dda63d36edef17cca4ab0e5284c07ee221dbc3ff8e63d615407f5329625a1bf4675a2ab036ec", "e57740a1e7f0297d7175ffc7b578f58abaaf120751971d8c2b897a6a2b37e6951b54e315feb3acac49f4d0555ccbe612cbe03133af0c785a6973fe8b4632e916517c0edd7765fcbb7a7a6304da60256a3bbaa3d6ca80a5a2dc2f2101c93d4dd58505cd75eef99e339fa421eaebf698109e1897d90ce5d1f341845083d01cf66e6207ac8b19a95388f1cf3cf0540544121061d50a56a763b168366bca8d1dbd55db1666b237312e73415a11c8115664e3e42eea97d7235182be928c00aa493dc9ec617b12d1ac0022c5f8fe24cd337aca8caa12fcd07388f0f65f7bb16de707ba7f8c99a6e0f4e194241d48b816e5a5a7070613d63047998e8a7a43ab4346fecd0722f31e6433686338b9da2acde9967111c02ac6a4a5ac4fc263c4eb4de1a9d8f8885d505e01540628d859572874dd2cd7a72ab65a4314ba389c8fcda89e69c6411cee3f4ee0668f42ed4c2a2257bd69e2cac46db0f82ed823af9297281f9206754c759462ceee4e1efddf2acf98f05b6b214ccc63c58ed7a6a16388088a4c7e9849df5469732b877bef0c41e59dfaa051757668833a50c6da8ebe0b2e9dfdb306194b6bb1151b7f06b3ea291e53710dfa3c4ee34f67ef669ace5a8c29e8d286d95739efd9c941daba1d43f6b75dbe33928353f673db37d400898c7b16b64bf894d46d6d22845524030f75f1f4f05d096aae001f2dbd6a4da2c49ff2573d0f01", "6489847ec2834ba77b0e072cb7bfb0e78596078084049902ddbe93f1813011e334a34a959cc080aed580b45862d7bfc1522f2b49ad716ff0c45493d9857f2f1ba54ee71e41dbbf275468e171e171161566017c453326b212f90ee321e24d76e1d15bd3a8be54c3b63f3f6153c6ce7134a149e35d2e1d430d82710c49be117ec86bbfe8a9ceb26c5f0a4ad3ade5dc70312d3ad31c30a4317d9ff8e7ccf8a6b232db1b1c5e8eadb0fa1265c2c2806129712e00d8f29c8d674cfd474b3e3c83c25e5024f633415c24ecb8839918cdd289044a57af2819434e0eb5e42e6c1ae7490d9e3e14bd6c5c94fb35735a4d2912fda0a5284c1b0cd7e9293559dd034b1fefa2465edc7f83205910058ddcfc82dc789afeac526f5dafdf04cc6fce58c91b750bbfeb1a80d0d0ba48b6a645b5ed34063ec8fc8a9ecd61ef4316a4f833eee3d7c8a88dd453e377ac4bba53d5713cbe23a4849c502bf7de818c8ece398e1798057cb5c83ff0e1574403cd7052a248e3d6a46af17caf9eab95bf8a8b976345cbad95ca31aca7ef727b70832bcc00376f8d192e762055722af311f5879768f70701ff4ec5bebb3e4ab2a784d537575a159c2aa508c916a1f2384e3981af14ade1312f2dc50192eca64e8dd48c72f97ce09f6a775a2f92f7664cf4b0ab38ebaec385d6f4155df01de6ab6e794e774d59bbe1df91b2f9f5a344655187168c1e485b6833a1193397803994e372573d09c636d9e2a423788646b40ff3e988f0ab2a7b086c427b1c986806fdd95c6a5f1e727b1d6eec6e2fe0c64e2f90dae4ba9b148671b449398de0847bb64578081683aaa6aa30fa80380aadaa99891d04493d6c9c9c2aae55cf7a279e7035bc11ef92c8b7ba0f1b4f9d452e45269fde020da0e0c63a8f9777418fe0ec1632f5ba841d6fab4cf2334c537b618a4e965cae1a67cfc07afc8d24936d0900f7b58758c7f0580bd44a518bfb3f8bfd9f9cf475de20ed838a7535f8673b35d36b490803829b5347f014af92975b5e4f75e4a1e50c5a2286304172a3684823ee7abeda1e604b7d2eb858f45f14886687ba4a0d0d071c1440c36a532bf052fac277230c07b21265dbf40af23b6177361e58a6209191e167617fd459519762cd8c110e6834b2b7c407f444b7fad621eeeb890a51573c56e197bd0e794b7e4737199c94a0c920c00358e4a6b966d292dc0e2bf1e8b275aae3179235556495f28c2be510755610aa88a79e1fde990ed8edc83087233f0b470b0edd99bb8bf269edc4b4f1585e3d5dbfe53666a06184d75a7dbd472f4575f31e4a4108bd4e97822734a7d87ed2d218865bb2f7277668e55772b5436a5ad9282651521386d81c3c98b6f427d0f98be3ae4d558e926bcb97b2048e05f55d555ac26e9569ab38b2c99177a6dd75f8562c7c147e659b996dc027878a5116d14100486990", .Okay}, + {.Sqr, "447aa88beda3d9438dc5f83a75ee2b40976f3118b44eacc4cad73b69ddbabcd89f7537a316d4028688ee0500ac6ff84504e9bf306d42bb1662b1350202c4b876f6fac15a7cdbd076f77d40a01b5e5f8fefdc4d5dbbd1589e830683bb52f3c27dc4c5ef41ac699c3bf85042ed853da544015282879d992b34ac5e8a2fc0b1a2f84cc8e714e87ad7b03d24695fcea2e9f4dd24cd3fe1220a79b9c2be0d0ecc8532971e3d221990e398cf50233de49dab1557091d4cc1aaeb1a71e55fc44982f0d4a53d6f25231bd98967e7427a96580e5bd5ee2dd0ad99572157893872ffdc1adce5b963e691ca3dc4b4bb047d76d644b3cb11d5d5830aec45900054926e8fc4c78f447909aab8dfeffd3ca4a3db6b59d94935c1c91ff90ac504f03828d324d8e378069ab665d014a3737189c41b9ef8b216bcbb62111e1e0e803f7f97d486429496c4e0f3d0ec469af4476fdd7343d3fe1e02ccfab8f6f83b36db1c5426046368585871910bc9f0c1a6efe1bc93c22d38e3224b4212b64772d11bbb74ef843b807d385af5de8c654886f45505843e4859eaa15b31f985a252932aaeacce7db719e322978057bdcbe4fe8884da3e136221a847f52f8061adc87bb65c3626b9c839a402e010e1b3cfc601e2994cbb7aeaad85ed676e356712be926209bb86242f394dc300530a3c0910475fad0f6d84be235153f7806cde21b844146860365cde0", "f1dd1d20454e70ee593ed4c922b03a12125993522de3df35cd9f9112f03265c1f4ef360318c8dabb9222b4a507e76c19a493ee7f38a32b3639ed9616fdd324db2696adac24172c5c83a875ee3f44d12b0a9c5d2b2e4b6fee2791a1858859a5be49efc3737666f7d0df4abfefef1437f7d33be253fcc9b96f7919eba18bd06add12407a5ca5676ea276f61aafc484fcd0ebb09241ffc5f587185af21c1937b2c59a343ceeddceb78a1632992b18228432e7bb2c809bc8f835015b327710b620bd0489e228dcc13793bd6f75419ff4b0c3f03a197407ddf81dfec339254e7d3a0d827e85ed67748a8879e31754a6d3c745fbd2be4422f49ffd21bbc8c38de07f01b9e41373afcee655572efa037b751ed6440597bda488b2b02c37a2f70099686cf9b7e136d904d60eb84a9a5ea80d7dfca8183a27893367c85d5c584b092af07b98950bbefffc38a33af57f96938331929daf3a1726bdf51ef7c09496c14c74f3cb68d950ca249517e305a2cb93764599e1cc2f8a4b6e033f7f8445696f9f34be246ebdc8aaba87109b78d3a9cc2e9ea8afd5a2183b4f638b21daf6cf4e0f6e8b77e67c1a23625366bf23217def0f9f00afe2af68cb377ad32ac7777798583857be43a4a6720f139edcaf4c2d3d4b1418f0e387a27aacc9d0871c6308425ca1f20d6bd6f2d1f775854c0163c7f6a78befc55d6f0bca02166c811eba51e0db5be", "1251644f6a957ff9f163af24ea11e823af2f0766dbbb6f55228a4e5418a32401cbb190ce56f411f8d89fd4889c0ce27d0d07859f8f45d93003a006abc07998a027b681ab1401b3805ed59232fb85d75bb62af878aacd72b2a6632404e7ea1c33988e62175b8c68466b8af0d6aa54878f9bd87679784583611eadbdd306837f1a767ed93fd5be2a8c5e3c8598c73c1e97209668591d9bf778391b36c3dc72c236e509329bf2cca00e649749828a3cb893b3c1442345617526ecb318aa7d51e4e9a84f08a9cab7d8baf5e4d1e8eb7efb907b0900390aa6a0e5e712ab46d463961e8cb6b5253ad35a453ff79069b7f1f76cfb74c533819dabf9cfb4c4cc5312ef6990a0c6fec115c4eb32316ed77376fbc89328166e8f63edf8275c40042177a8afb46d66a817b0cd4414f5a6227da7632c8d0b33e110784e5dbcc4d50154c261d5144c746fb728db11fc0b1a447bbe32bfa3fd9efcb355b5e8f0cc624696c34762b970c854456c99aa5f291724c21cd1b0074d4aadc5e993bcf97eb79b2d49d146f349f6be952195902d045d09b23130c48b891dd063b15df70463f33ed7c85931ab8a6865a23cfb668ef6c63dd8ee0c43e043a41958d88eeb1daf09fb00752e0676158e14ea37127d8787501fb9fa8a234175ef861d5af86b69d5834f07bfec0e1aa113e7d5bd7b8bfbd75e02386a05f96342925aaa2d3e9a58d357422f94398c19adaa06d76e8561dec5d9bbb178c3bc4ef0a6b91236580509a7081fa40c54497a02d5a150fb73ce7c186d475e5c2a0cb51446629c0739ad979e2c79177e6802be3797a1d41dbe846e60627a1727e80b5c71bdd684264eb960bf5bc2c53260faabe6df9bf356a20dc456ba6394872c298551b452a7310edb05e59a6bc417a03b80e87c0f4354138f6f180dc9ad631ba0ae913ba8a2f91399428386ffabe3a0a3ef01fcef761cd90c56c598b1e7166201c4f91b889bc425b39ad7d6540f0d788de25610e24e495702e04027f73482f248956b8c5d83bc69555e179b5191de47a8ef3d16fa80cf32b88e9f015052a74bbdd7f4b55b923ab6e3e8c0cfaf6d74c59302813ddda1bda9e9bcf94a108dfcd37907609d7cfbf8c0557967e78fddb8ca31024124a2544a7263d8c1adbf9d21650053715ca471ef6b58378e24e991528d9d811a3069d5b510b7c937a59e6adc1e8167b7e046d2fe15738b56ffc27a54bcb32d27e2ff319502bcbe1e4aed3f8c89f69bc65e2e3eff06c899024fe55cfdb5d8170c862cec1ebf6c8e3d5de73e39098dce0d667c10829630ee8d9cce3dc9a73601937288890abeb7ad2545b629ac1851e3c7d8efdb5a8dd9865e1f103426dd8e04037da1e99b4d97db2582dea7fb42edfdf3eee1c9ef307edfb21d91dc2a4fa8a2e9540aa87c70114b050befa7011376ec5855c6b53344c6f591cf58508400", .Okay}, + {.Sqr, "-5475fd914a33b90be1c86323b3b8c56fde3c6102f56a7d6757b58816293827b9d0521e7e20e22ce0b9fa4147f1a1f07855806368db62b6dbf83075b45237d9cd9657003e5e4e6d90155aa31ebe2a769382aa07636f909a759b6525d08529c788b1646aa11dc143fb8fd75390258774a992b2bf7c5e5adcd308ac232c5ce5cc4c21f3f2a84128e229695daefa84c11e60821aabb141d28629270ebf2aa73f39e37896fc923fb3559b7a98f8cfc2a517e4c0a3013581ff943d8b05fdcceda6441615ab8013c4d4f6ffdaa98380438b26925ce3ad5593d41d363bd02d965b6d51cbef3c4a53b25814e147213d93509c1270c17b49dd867951c0c4630211655e7ba969c24f1af9c0a6a42e923f13ed570da2c1e20680dcfea26ca294bdeaf2c46690f6ce2cc63f0f74b40bf75fb20a8702b7f731a675034e4aab3d8df4ea9cb31e36116fcadfc57a30f68aca4faf0ef4c091c79479879a9240cce8bc40937e801174e7200e8af87e731c8acba17368367db45edfed8112f1055b819bcc765cde8c1ee14d2dce516204a74365e0e33f7862fb26f1120eb0bc676cd4519f14588cab2fc8da2a709f1a93d2d0913cb8663fd4b79b0b0c4fb6c9268c1c68bdbc30003e0501af38513b9f37fbb29d7c35c15969ecb91d205efbba9d568f1d9cd69b2f65b9dacc0a66e36c7f8e6f9b957f889392f9e762a877db7bc07d0459a468fca855ff", "fee5422cad135f0f6401816fc252d5c298e29eb90b7cbfec1cb9ef7b2b98fe81c8dbf73f3029c9f0f8442744cdb6d31762424262bde7b392f02c8725a0e6410482d2a2671d1eb0840299e050e5bf95a3205eb9c7f1e544a464da7f4a4123bbee73afe31912108e48ff43cffb32f7a86de5c42bf36a6760ce2d2eb3feed78d124a712f854f0a2e4558a65e58c7ff3e15da3ffae9cfbaebba238591cfa548b3667b1f20de6a07ab0fdcbcdd0b2eaa8ca2e4d3726f5196d79a63232865f711772d5843197f1863c0960165a5d430a8648cc2e8fad6d7f97d98813c22ac8edcca0eb1f5ccfae1becc5f46b7ae84ab701b61ab1be72637d53d89d6b90f58517adc62f267d0a418f912cdb368ccf34dcc7f756fcd8f0adc30b6164e508ca842f4a85e65ede4619dd998ca9280d860ab8ffd9dd0731dbe29dc00f89eec97ef2b91c44f8e197df52e95ac14bd564b6471481d79ce44817db8161620775fcf31371cc599112822815c36e343c6f2e6787d5db2d38480ca3784639b79d964739b6da723c7afbc7abecb4a17e87823f34d34c816e73b62cbda459bb593a4c4b6096bce1bfb411257ebf8bbf3376231559451a4df7bb4f5c66b9a13d43bc1a2fde7f900a19cda1fd5afdaead55add487b7dd16ffcbfcf7fb204add7c7ccba8e020741d4832016181978a47650ea22ebb8a675b3f3727df3830b8c7117405d7976ab125c682b0", "1bdda4c91aa843d650e2ef64048e642ba16bf08d5c4a4cc459d3625ce9a34174f170b8512134f6476445967dbe221e205ec603cea5d6bbd231742b1ade44341f74e47eac7f5887b9fd5d6b5663b71f5df067e565a59027d5673df53ee7f38da620109f6c9fb0ccfb4eeedf3ce0abaac48c51eb36934db81fa6e0fa114f0d617d213169e768e52d2ad617b6364681cea37fde14864b2a3786ed0e9abf6a189fe6108a56e616d4d41b003ab162e15cfe7063e2ed50c08ac1a6445ef2f2319fb9945561e04075427c62d24775597874c15e1be5ba5c7f325b006d72e63407d2fd00474955f00ce706b184027428f900bdc5cb7426b80c300cc42fcd6f2e72158e429df10f58902bc016a5dfa692ee8fd1b6ece2e6559d92fa6291d77745507a6c26af5f1bbc54d73ba0d53196212953381714794b5b15128212813e5c2d268072fc954a45c75cc9f87fccda89c8013cd93c209b4894f717bbe33ffeee7798b58d82684ec891e7da504c0697c617110c1065c95d390e5f7b8e27e417f75512228245e46b9c86f5e75d8e46a2019e5aea78474105081e1c8841f1c133562daf75072fb1ef880ecfca15593cca93588ae8448b68b204347ece15e30b870281962c705490c53acebad8ca3cfc7d8324884f07e5a3ad4dbf8c17372126318d012947956161f45eca3df5ab2ac902f244500952584dbdbf152b46d60cc1a440b73fa121c2bd5ab4a9899e2dabed56723f679a4267405f46cf7d04cea1e670c2b32eac8aeaf24212b0f35f2cbd0dd123194a872e042a94f7c6cc96d4f6149f6db3f057fca9f942d59d2d10226eb730c76c1fc159f58171ae3c92fa3b74c443292d876e11cac6a9d99855fa7f42d0d35c96fd8db28aba5c4e63194c4215d47ae7010048a874e5a43b36700f5ac6435f3665dc649dbf607580ae782039c9d83a0e95505d80ba8fa792d6a45ff0d4935f3018d4736953250615b22373d953d2e16cbb8698b4c9d2041cc70bef27dd74062f0269b031a4f99bdc3800f47d2288802778266a997ef590ffbe91dc40b65df24dc5bbdb3b4a9b6bfc4cbcbf6391e483d274f42d9e416b79c0aff1ff653bd1412ac4ecbc497a2f9ad14ff4bc0c2816e42b7692df66009887bcd026ed0c7c2973a41e620432e69560076fa9768656d80827e4154089a7486a668f22fcb2c131d37b614f94fd249c94fcf49a408f473fe81528d61e7ff227ba7f74ace68695779a7dd0035079bfd602bb54509405918177519470e4687a71fefc1b04dee442cc3d2429e398ef642acc1b3dd0fab1dad33b4f4494de79e395cdadc22308941504f09b45ad5117756192d117fdfb77d45ade011c6a94ffad91dd3ab9598f9de1248e129b8a949e008da045f00ee0205748bc7ad412dca44922936b54a101dfb22e47de8eae31585d320066012ce81987b39e6f2f03935401", .Okay}, + {.Sqr, "-f4f2580e44f5669f7a5ca52041ce74582ed61cf40412c3700ca62fbd23005ca069e42d100b9b30bd55f6db80013e2646767ed3018e4cc4abed1d147b5933f6ba27ba82ce29e5fac4baf346d771217f4592037b5713504c710ba8fa0e4d578f1a8a0dc8258da1838664f0e95dbe24ed85030a97241bac913171b65c082be42472c01544639fd9ec0a15a11db47efa8256bd22fbd571a5ba38dc36bc1ba2d43bc679044fb9ec7c27722e4fa9f7cd890348f64a24a4fdc1f6d25fc386931cafd85818dbc926d659f2ed09b01b93fb49c8544b14fdbf9ffdda1a246197fde6e2715c97eb70265e792c07d5d88334d5f7930135e64228d718a73ab6fcbbb4ed32d7bfb7dd9bb5878f14ee5fec613ab084ec2d27faa9530d7a2647b1b218e89c5feff072399f3f7d337b90e6f706668ad50c0db756a6d61293367d886a8cd71ec355cc1328942ace1c71fadf40b0c6ebec110983e9d9e0da2bd0b2800d1b189b8e0640eba53e1b36a9151edbe2da842fa5a86306e60fea3936ff18561c0db97befe880ed124a61304dac00a11802ba02779ceb1c149420a8a0c09b7313681c17a8f9837e254d5c7510db82c9d9051addb4136a40376325b9e22dc06f69028c3d80275efa62c254d8bf457e38cfd9eec0bdf0caa1141815e257114df79750f5094134485336dad17969e3d1404ef7ccf5bd3836f44fed6b3ca13565bacbca0f9f6a85d6", "9ef9bce13682772cfe4d1ebd4342df4fffb833405c3be9f53eac2339cb159fd9cc5ead3c076de2c3321ed00dfd3be0f033e21f9f5e247f2d374850bb7defca29e15a517a95f1988aead1bdde117059f529165ab96d442df49f3a3e6723c3cbfaa1f8aa980facb6a8d0dc2d7d04ba3a63f72ce37ab514d1a73b62262da387797594ac85e4c2ddd8e0d7867d9b962fcb131c30b940f79fab32325b0fdd44452906ba661e0d2b8862c210844b04761d8ffc91e5114326801781ef45a018b3339a66673498dd3532e94593f347f72b77f52d8886d0925cfd09d8022b51cb9eca90eb5e9e9234ecca0e0d6f8d9189b825a8164e51eb1074d3fcdd6e342aabc26916c9eafb5688d1da7a22491ffa76a7dfc96b265454860ab284e9b97123916a015efb0ad29122120eca70d0cb962e921ca307e5f78e5050ef03707fe53aaa5d127d533df92fb41489c6f1da35626dd25912922cb72c2da31c17ee3b8cc340df01834bc308a6264515fd09f87011a9c98a159cd9387bf5dbd0b5f62da63eddba42a853474c74ec73b708184fe1751eb06725375ebed69d554cdcb0e3aca7a1488cd5de89fc3490b99ec82c49bd8fac40717ce95d3512430287a44fec4584291e675ee40bac3233e26724dca3cb6ae4ca3773e39aa8c7ea25ad135c43c86204fcb297c80138a743c2b1f0c41c8ac81dac0e06e3cbdc55d4534968a99e11e686f7d0dbeb", "ea5edd45ccb7fbca5abc1941117b1ac9726cf23dddaf41c29d2a49bd623d6ada3df45805d5d0449cec66d0d51b3560b6102a5a104452ab71becd776a954eacdd3b49bcda59c1f98ae6a7eabf1f615706e83d91fc51e9aeded3dcae8705ae041cdef9b190653b95db720bf69a8f0133feee952d90df7efe9cd8c9484d9f3042eae2f441129130eb6e14eaa04a0c1b7e7dab688e97e7950fadcac73448964d79dfcfbbc6676372ff7e23815909d275d517b689c0f21efea764349e288f0cae46da04d7ab7d8fcd32cc6846d0b9e3f9eae1f860fc006f211d8787ee222e3c0ef3eeb36dc012c353ed4a49b1e2e8e795ff1965e8b789d08bd1509d83a2cc4f6dc59127f910ff60106efa73ff83ea2e3b37401afa21fbaed80f721fb2527140deee9d2789f0381e2c5109f8a754372642888ea4abad027d9371189048409bf0469072590892459197c7dced87f4595034efd991d43060f70d554faf0bf8ccefa1362b8efdfaa0a4767214f8b4acd74c5b135c2d79a41384a9e4ae81e8263351f37f650b3f7fce1ade26b950303c043a32ed2976f12ee43b1ad6bcc603863c3f5aab7129b4f5a1a698e4b82fa74db04767008aa0f72c53c83d9456055f6f44d6e20c71bff6d31a3a482b3f3dfd71055f8eec0e41cfcc4acb8cbd624acc42acbb2bc328eca3c0a7d69a68e8cece450d1efa2b24de690232081c7ac74bdac3af6f29a930fff1ee1eec86fddf330ea422e653f9b6242d70d5b2bb4a9fd9f17bde08de9b385cdd21f09ec33a02c219102784f9eab924ff7d5914422d6ebe14d59709c8d12bc94babbabc9285a8d5607e432f1d2ea14b77edc7ed70f5ad559d2613d525f12ae09c5b87841e5774106e5c4c5e25331428b4e262f723e9718a16a74f29d519ede585a57f0beeb15a518e779096bbaf643b2ff25aa27faddd0eb1e55ef97d069e5b0df38f0ed41196a79bc1ce301531133bf45a6138bd4fcf0e3639e9a1183707f7b70d8fc0b5b5b3a8319a1f1f34904d490303251ebc3ab32ae6bb0c7a9f17cf6136c03f3292a36ebf11396767e5a446d2eef051dd5822d8eee52139ccd4dffbdb557060e2e3481dce23e5bb0d249aae4c88ad64e08fe229f229f57c812168414fd27f2105dd2df51a3589ff7ff30011e3d23d2ff9327ab8bbb8b42a49ef57dcfe26c3947b168f9e52196c2cd1ee3d3aee4d761215c2fcbd41f139154c971fece4ab26911b7605307deb879fd2c599cf2fd72b277eeb594a332c538d5f98cf1273791cf105eb90ce8e70be4edb28c0e0ee29399f713bb7fc8b29115b6ac9df7545f23041cbf74dcada178b1d14ab26b17db3a0ba7cb4d3616cfb03be7e2c79853057d5c51973ed6f9d0e5b755389c1d4ab592f522e9cc0b46479ef256a113ea5c340dae3abd4008b81de5542f2252231d2133bcb548e7ccf665ae5a6ef300ee4", .Okay}, + {.Sqr, "51c07fb27f3d55d1c705d627f4814c69f04c5d61a3799ba4529985bdb2bf96e2a9b92caec69f0d991aaf2b0d187a5f448c267a3c1e0e4214cf6d2f80887babc0671e14b050c94657d79e85025ad837ec95d9235330da62a4c9332733d99b3f73a0b1cdde4e3c5ca7d306cea6f3a76d1e7e0dc5cb7c12568ccc0583e1d7cb5d14a321b518f261b16420b72b74f4a14a9e27ee2002426e162e3a1e640b41e66314d63b874b4034d764f9a489a9cb9170106e75d6a4a5cfab68d8bd51efa399f3399da72ae4dbe401482e09a60bc1416c3c100bc69ac8019afd987f3604315835911f50b46639de26256c2f48ab569e4c27580a80eba3a2cd81dd9cbc238acc044cc064f29c0f6ee55c76c512fcf3df6997effae5fd073dc9e2946845ea134ec1398ab02c1df09a3326f7247c65570ba686d3664efeca17d64a6a3bafa9b51efc4b5e828046713a8e2a8d0332d17ed443ffb238b2443161ab46d5129143f2b6f6552fc028d51cfb6175770cace37e0589e511322a70debd2411632af4144ee5cfd8a6e1cab7f1fef6bd20403f0ed3f4a4c6590fff2c60fa9da6a8c268638f6e36e8b67145cb35c5d517cd93a1c15681d46bc399136b9703a58464d99f9bd503b6c6de4762bae5431f6dcb8e4061e95b7021c24e35c38edca63539998276d2fd24a5ee1a5fe73728aa277ff76db8cf02fa16f1d26408f06fade3c820aeed47fc8c5d", "afeeac9d4ea81f37e776565dffa9b61e40c749778935ed858f9501dd7c7f249ea2f32899fa131790b136651c6785159838003e5a3ee675f33ba56440a09064ef59995e2862839615092123230a8a837adcd4635b90e008556df433fe1100eb2ad0cb7b886cc2182a727b5eb04b5faf67f08bff4674131f9a311ba794e99a5944ceffe2c8af9f315e8e995ce1ebe2671fe99decd8e799a3863f422edd7d866b559c43fb75062bcde939d89220d7c24f5db60d7df62558c0bac1a0f1a2f72534a4f9960a4367acf139d0fe232a6357da091088514bd1e0f3b346b1e5372d10c667cec10d2a409ca9c85c5828e4f92366355b4e9a2ec9578871d40575f9422b7377cb0770f29ce13bd5d41c15e1e58e896398152753ccb3d05a9062a14d2dafec3299510b420c2c19eeed491717701379f5f3e302176dce9352affac95ad287e5f78ba85ba5360cf76dcef7301479a689aa3b5efcd6a348c2b506937ccfb98b46a4e3cfec3db3c02a263f5a8e4b049d42fe41047b810337e578db289e45acbd31962445a296757fbf54caff963b04c170f5b092ef725594012a98d0096151e49cc696b266d14a80d2a223a61edfeade24f90ef7b9edd3661365f14a49065deb6e654e60f253d7135c63ed7191acad55db55bb9976d56ea31d11554140d0a7d72c40649f8d2e7dbfa39d7af8c820482e50fd6a4a90a7af156e8535da497fdfa4bcdb", "1a1b618ebff64303864b9f4f3977a5ca1cb33d80985db358281fa4e71d08764e728c93744c9aacf2a24ca6585f872ca8951427cb6d1af7a0e396887b5b374d86b85c3d32aa48e2f901cfbac91a7aa505f55ec361e507a2848b4712c56a14567235afedc736179e4930f89dba495370096b18ccec08d4652af181f8269f90b523dd2e5537e55837b474cdbaafda9f6fbe9e37c92724e0b6d7facbeb1182f133367a81192edda0e21bb8e0b532585879c4a467d94a2deff581876d7e185ffe49ec5bec499255cb6fd47a10c2251e34392c898f79a5ad56349ab1c3d2c1bb59a42cc6032dced98dce70c5c2bc00ad57243ae9bdbb4a1bf7eeee4686624070505ad73817d80ad00e8f54de3127a263869c3c59b67d030984286530711513c18e3d247d9806376c1c91342b6b35b44cb2eda0482fd3ee8e534a8e3d7b9d7da2d659db32686bca5f8ebec10a782f4266a6b4d2b5bd5537f68131280c0bce4c02e3a67bb411c14f3bcb1e7b83e1aeb898e50aea7f8424605d4ec908862674c985a88e737ae46a8aa17024ccf22a5b04d004bb75ffde0e39be962cef3f8c94e6bf12f360b2f592da01a296941d36f644913e2a8da45316f48aa1b34c776632cb6dc963432efd58e4143d9f32f97021580e943c18bb4d8d8c3385eb9f9da18acdf05622dc85035853731e477b7d202b2b66ff830bfb7f9c51c3e8462180e529be64e5056bcff00372924d6477fd09bd2d31204c415cbb6e71c2874a5cba9e7460c2fe5da17f3f8dacca025a60f47c0d08ff95aad6d681e5eec87023a1591726d22abd61e2ed160e1be6729afa7ccf7b0aafb2ecb0a63185bd3d43b63423e81bdf4483b4eb9eddd79a05fe7b8b11407d77b770154e306954dec0ef43864579abefa27ecc5ac1c8cdcd32943066f494eccc7b44052020fd235a0e93ef48bcdce0b53df6a4fea1e44c0e22f951fba1935a139d94591604a84007d4483b039d013dc7160eaa95d9dc173a76b00d00b4516d47bbc2c8791b5fa9869eb527b2831da17905ea9dca82c323aa6531fdef49f9a7485ea5409acbaa756a48b636715431d3a6d6e83604300c29b40dbad0b20f93babb601228c1a461ef42bf2b518faad8b804888a96af4bcdd7941b5fad34af255bbaacfc2e9be47d0aa635fbae3fb53f81c757e9c40b75d8c672ee5eb5823e9fc97e3b10af183ec37032e059339a06f62983acb57f745d452b6bb531fe711e3e16b3676fcd09e8af61af0e43f85884f3a19b22a2966c6933523fb8606c0e72b7a3e9e7c56439b53d5c13ccee3128ffe74d16a13ca02add724f9f4a21a1477b98da69265fa58477d46a8d7bf4c3a0c4ffb4c42631ec9b0bbcf68377fcf1af7d425e821ba68835551ab1b7c556834e3fe0b71c7108357377df26cf4e27c389ae944c555b6c29287b9963980b90a32c13e85f323a0dd9c9", .Okay}, + {.Sqr, "e786fe7bd1b1c904f1ca43436f5cf44d7ccd3e5d1dcc0e7918dad062646d33203a1476d1a07964ca76131962fc8a8ed9fb09913de550c4cb654f6f0fdd06f015c5e5816349e615abf20c2505495a3b843d0660aa20068d03391aeb955eba9ff0f5506f6d81914348412fec2888d621a2edc9b9ecfedb54e947e8c7948c0089163e6d1be94447fda685aa9894cde076f4d1b1687ee58c670c87521b6b6d052b9d1a90e23503d44b06c3539ba68ae1bc365c7fc56dc94a361a354f37b224bc1c22117f6c70b72992868cfb2ab53b8517592460e901e38f0ff34110423094b3d96224fe230360dbbd8926555bf25659606c98c731e162bea316848e0f771e039e28c38384c6464e5ff71ba5e9a7b7adad5c8bce5417a3e2b1b75a7e7871902b0e042d395145de3da93c4c460836c52bd304221c098d37b6fb88a2c1ad7953104f5a708d0be9441112bb1cdbf33e64111735917b367dc13174ad3677de9b1dbdcf73e6af3587bc871759b600ee8b1348b48aa3f149e88156fbf0e64cfe7d8d627904c0a0312d349212400579378e9cbcfe5d75b2d384b435930391f818e039726a016ff5fb1773afaa9f1a1c065710c435152582b32447d2a70478ef0ff56caaee520202eb7e985e4b9c647ef3fd3a1a32e28ab19b07335dadb7b619b7975479e935fdab1703f200bfe940c5d5ef9684269e5c3f8f98e4ed2187804414b6c20d624c", "71b15819e73f23a9ea0e3605ab1a7ec117696cab24ce5353a7eb96a37507559c6cec8df1b8d0728308c1c93500590d32bccc36a74e2014896c847fdd6695f174819acec54c8d8ff6c87dadd7ca8d70b6c6de3a201e6bf97154f21112e68fd2fed0c5c7b459211eb6ba4da3a4ededc24fc5d4e8746a19fb2d5a336313dac2554e560efe18bb1a420ab62741b12307817224e0d15520e245b80e68831253bbdcc294aae41df2019219eacd29ac63a9fc68d8ca13f2464eb1e4ad25342fb00d78c2b07c2a79e2956a6aa2de1daf39986545937e3ecd7cd9069714d64c0d18546dc7d14adb1f74a7aa060a0d6ec7ea81e9ed66b84e7062bd60fcaa3b73e64e3447ef0d53bf65637c40bdf08723939df12c97562f2ce0018c78ed9c96ef3d12bb5c52f430ebf98b07c961522bb9fbb266922f86f8c31468158f1ac09fc8af0b23ee3e3bcc7460b7f1e56ed8e9678d6fd2827b4e74f76d2fd73b84fcb249ec90b3463a76f773cec326f3d969db9f115d44381608f388819929f96b04e0e764d37e244f1f96fc9fd26c895da09d593887d20071ab8adb8323921ce6df74818ca7f44138933942f69590fb9328aa86889cc937deb31ee68bd528be7723b5b08edf7d5ab1f03631e6860713426590ec5a99b1236452b2ec940a21098eb577f2682535c0eaa1f3f145f0f24a001d75a8e11c9e070bbcda57e84180425582a98e1e782ab508", "d164e672db084ee55508e5617ce4294a3fdbca6585784d1d4c6f3f251d5a0ea2754a0a642db1a160c66222a65db88c21b5ea35ca410f58e72694b5d03c640555e6e6001b18cc069abb6171f63246fe416114a6831459cb9f7281022df90105cf3115fd60a17035852f4b4fbf9b8d70ff4f7ad6b9ec2ebbed85611f0052b852b7e959a55e4bbdfa6edd8c27a6196ebe85a1c4b4464417c1a0249a768ddf8f7dcbd9124075f27646ce72a50f18b6914ade2c28903a97d348da0548a401c10893e65510aebe10356c23ab4e076a21dbcc174beed272a273df3bef15dfc8e5ba611392d999c3f3b8109e0489fd91c8b19c4b1acb90718ee2cc8d00594d5c19d91de19511cffeb4ba867270af886fa650903bba149031c9f8b5fdbb53f84ae227ed7d260d528b684b9a875fc517010816c6cca7e449ffd2cfbc1098b1d5f6084de20011541e5058d8070d3a5f15c807fcfc8b267062e6e2bad13b144e9d8ebbed5876385c8d25342a22c3de6ad9c4b2c793d1109f06e76fac18c8d2aa55efae13ed70c7ac55b1ac5acf60b85713cfdde280b30f317fe2f744d571221b6d0c74449d49e941da3e877bce39b26ee21fb15c3dcecc5a06004e3b91bdfa055efc3aad50bc067dba9eee9051abde38fe5bf55c8a599fdfd6d3ec9e0864d59ad66a22a8c2e1be2a1e0ae03e1ebf5bb4ac49ec16b53a35a9d19b012ace3978072f69b67af641a0894301df99a1a577bea1f65e91faed41ed1731a0a0462250c950af4408d55fc24f85f4c654debf3a9d3b45a22fb7dfee322c6d5509e1739084e5b91dd7d99a97e8a31ff9b4f3ed4ae5cf2151adcb640123fd13780bb9237f23a1714dd5606ac58c9552f6c25d930049d8819b69981b3c8be6d5543e933d115826274dd5340df4de48a231b7fa5634ae042630bbd614ba6af9e0973784ed7e0dd0a8965b7510ac860b2c930c22f34cd27b5c486735711ebe4cea996bcc477cbaf35f6d24686baa95b6cdc1fc49f4520fe395a6d5b2039b9f63f66086da765158f8b244c747ba34178c610d6f7388fa0edab2a78467366f33ced49070874a12354c59a617aff5ed3bc374274af8ae5108a0d527b07c2f94cf580cf45cdf9a8e706fa78a69e7979432700c5a12198126e9a049091d4300718e54374a43c3e03bad829dfa190255516673f4b6a6f90da6439edfeb65c45e92d2504adae68fbddc157c662d53d614c906db0db6d75ad94476388e08a88e7abf1f8e9d82a8a3d1b721809c390feabad6644181538d301547949b7c907c9e0b085627114b89fb267c191b8e14950624a3f111471ce39770de512408af2564858ceb65c61bbf94bca4d70a90de6d80ee3baa44c373775f39166eeca9f7fd291b3f87d165cba4d031357387714a2e77549ebd92f72bfb6ff36c3e2414533ec69c5e91e3b942fece5acddbedbe51764690", .Okay}, + {.Sqr, "-cdcd6da48608a740f380a71993a40c8a4d85cb6e814194d66a65156cf46b4b5d0f24630e33d728a636ea7aff438b352ae849ae8d02c1355bc8fd1053d3442a3b90990fb541c474551427670118cb1daebdbbed7b381b9ab2d05d703f533685a14841671694a5a2e58de65e5d7221c810557d4cb95fa5e315238811ed69b295e3760973c7fffa6696093e4eb28cddbe9ca505285bace5200e2f05045ca7ad7424521b5533af74e3d05d8e887a956b63ec20769aa8cfae71f88097f70534e639975ae7f2e58545a71f35b7d2e93b9849b903ebb11220052ebf873cd7475a2b9dd170dc39b7b4c557f36c8ec35748ea3ffac75fe33a19ea5df720c7460bdaaa3e171181c1d33e39e278bc4a168f58a8cd0e834f40713e01908ae0a6356f5c77fe7ac6c158a7bced6c947a871f3857ae12f933fa604382fa5f5497be096f956922c38b43d3d06005eae0874234994a98acae8a49406d0941783e0fb5b9f9698d4e4bc2d3e8ae4eabcfe78c69ac912be33e7a4e514e52a3c10f4d3580c9c8954debecc0d8a5da800dcb1acee90c4dadc2bb8bd50c0390629447a6b37c88635d38dadd8926910d914ec6409d92432fda8e8ea819e2a7cd164b9bc89d91762de1f14ff38e099d97d4131e88e542fab2ef1be3ff7986af0c811cc982a7aaf1752517c602ef4641ada61347130ce1052201e6284aab42f2aa66b2ede6381f1c647183cda8", "a7b6b6987ec05137009c74cecd2cb3abdca449b44f6784815faa21b7ddb2231df4a619bbcbf6fbf24d466c6543717390fae3b1556849f1efea11a6ddcb0b153195f4fa5b67ffedc35761f5811397d28215202bb46bc14f73227d9736618136d7fc2df17c8f06bb74b2f7755e39dce669fe59ab6b2b17ea3cac0900af08c10869ef984ce82ecb0c8cf73246016303b746a1940ba1ada03f127189f233352fc2a8e8535dd4c3bf06b7f5c8b6bbac428f72ba3ff6785aa53814ef7ff5d8e566aace75e7a0322a0a26be345d63c1c07dbfcbd30ab67ad180f79eb4540cd8e28586b9196f42388b169dbc3349d816793de5a3cefd4921d55d11da4e4ec9b6ead1c849dac29a5692f5faeff8bf99dba962153c742c95728b053147ceea7365ba4faf8d9d262d821c0a0b17dae865d6380c146357ce0c0d7413815550a30947b40a17afde8420db823254ccc3048271683c744bc104f4e990af7fceb40a3140858e4c75598bb4082f10041aa954e08fc0f4869da15af4a3461651debcb9eaa8647108be77930092638bbc33f2aa20216c3c60e2873567907ca847aabb31bdab10f170d46530007dfdf78eeda14d1e1210d92559eb798b23256c85784ccdd9fa8aa2fe034ebb3eeed4db335e02ba17f70f0f22d16d359750df30b741c437a55bbaa5d040bf3d08e6a5e2feaac145d581ed5dd11b60f9210f20528923a3b36d64450f5167", "a572a672471e099943b2b1a100ccc6762ca3a7fb8dc5dfb840206d02fdc01071385646faf6da60768bde2d7b0ab7c3555db59353c137674bf9b8618b7d226b16d7f90004a6b952bcc55a5ef7fd2f303a3231cb0fda255a9f7688899734e43dd35cc1e66cbf470b886536bf1d2ff4ce01ea5fbb38175c970661989ef2d8cf0dd8c1b147967df39f5b5a2f2dda64b6686cb88afd8154f869e30b25a78e0eb33cf2a00782343f38f5dcb8f8ccca4c0cad3218d07dabb417f7f913114d50ef7848391769488627b6141689067b354e02d7da86c8aa02e99ac6291d1a881db167157434a8ca5d24e22dec33b7d9098e6fd596478d6ff8f340f8ce0b42873297831a6abfcbea9ae9261376837cad5a9ea8fdec6e07cc94a0e8e9a63243668267acabe8faa0c3a8ff6456618a4abb69c46995cddb1513416789c609cbc91cbf6d62965abfd15a31ef7bc6edf5722f18fc87eb6199e149156fb125728aea8cbbef591f69cb8d309b7be13ae1f57b04a0aaa2e1e565337d053a2d82c16fd7432afbcc86e9addeabb0aca038988baa00eab082e7a73c69445c5ec039939ddf46c728766acc32b8bdebaa33376ec38727042caacf3b618f295677326c86f9425e47954c8ed692f8a0168b4c1045119bd1b38d3a64c79ae959aaaa9bcab6d10578146bc49118f56a1c15b1f4f7c332f224ff5d44a44d9f1687e23a25fb1b2d5451783c116d39a2908cb70da165817657b24d6d9e124f83916b14b7689e32b2d8f54d8ada1e54241113680ef02e9965284f68f2e04a02be3f5fbd611a6f92f369662f3ea071e61a44fdbab9ed07a0317a5a71889b3d4eeab459ea8fbc0d5e25a9a74c7469c442acadd0b30843ddd0f35ec379566649c764e54a2cbbde8c4769b03133404a5583a31106d2e9d95b1d7e21f12ae0db98069fa3a591f2adfeb688b2e1e4cfa978b5b5b48d510d5578285cae3ae6f537d7827f03328837754aa79da3daf281ec0aa75cd27436f699a5affbb837a0212eb975fff0acc0b80fcd539f5f86e4a30138161fa7b0b15c7f1e6c2b89a6fd7642dfaf4b1c9a5fea06ffeb4a03153ead4cd258c5aa121b409fba19a4300a8b010e1fe65fed3a6ee53f03140909e22e494e840768fc9bd7b05ee9a78a57cae598c2419aab4fe5df17512c26f01d1d7052921cd358a9e2316d3f36af789ece0ff343f7684590ba0542ad44bae9668ddbe6b7843ef08e69ed5cc4286d7e9eb846aba36272ff47b37db597b2fdbb9dafe07e1e495f2a8cf4264fecdf58ef22f6ed39c22afa94a96c1175151e91d4b8c363f150116ba7e55de3dacb32721aae2c09e1e5e1d33f95b29191926af43ce7dda0790186ea15f43fb10c3f7082604c9f0b2886df1bebb0176931c30febe6783713eb786e705bceb7940a243d7198e2c914feba86ae73684529b661e20304fb0aaa6f267e40", .Okay}, + {.Sqr, "-ef38aec98ff0658b6bd1724dcad092d0770854a2e5e542924ead0b150cb15e84fb493d86cb13125dce5487ca73d6d9599b828f0307b9083291f59bb6825f8172592f19cb297faeb9f0b32fdd8b5733a9eb00e2fcd29ffb55de809aba1dde515f1d460542e979ce988d2bc7ca075075d34798eacb715bf815523d057adddbd482415d77319abade5c6d1f9eed341ae728c1139d47399d814c18ca219fde2f46b8585009de2e7d5f5fe642e8ceed74f222cc7bd72e0f3d657189a98ff44470c47710acf0720fca4b2fdc5aaf7ed52d1432918149146b17ec3504985ab35e61e9488ad0fc726ad1fad69eb79792d1d35af11cf674a5cbdc1a9293a269171851470f61d0c3b35bc19fd3c8bd51742a1d90bb7cb647764c5b69d3d1957ed35337a8bfa863befa5650f34f6a0a752b716d1bd18fa3dc7c5760323ff2d2af115645a1d6728db14b7168917d2162128baf48aab52778a3bb50f2d58c2d4f03c05300ef4be474684117c21ed7f853e96a3186a61a720d510a1fca290369746213d88d2a253da578b28fede4ddb20bbb05ce889c62ddb2317e377e35f2ef7d7b9a0d75952ea070e5b8094ae68775b11ca87e696faab457d73c97e9d784e929be211f49f6d899cf310750ba7baf489af6d8e148cf8bead8db9c737828ed44987de2efbdedf7b2a0f59ec6ecbb26600ee511ec4520322b070fa48ae03c83472467d5fa8b07b2", "5c0dc08248d199d76d1affe6595d2f081e352929d438bfa194affa8297f5a0ff6df593ec0648593615c0119c508826610aba1150c276ec5b76dc201a0fe44082da9805430a3ebfff6dafa3db539c7c1f6af3dcaa5a68cb69939666a069d2beddf7683a9df4eca454953ea10dda1ec60817d083eabd62e64709189d21a7d1046f6459ff11f05f8471fc0480e21df6b2a28b850f7391aeabc5e65bafa8b53b3d8952ca1026e7a566891ba0b3109ae21b9f294b2307617474bb990708d05d9745c3667ca4b047c0a35346d73a3fffe13c20ef25966246b0227e5c771031cc6aa98bd85e9d54df9140bed370db0ea4126ae49df79c054186ec40e9de0ae606333b5dc49654ff656d111ac7d5378c5c81f49725f3e00221fa6fa82d9e127d72f2b62efa2d6c76d4e9342f193f38df7c7896731e53bfff37c1b537abad26307a762a4d3fdddb96063459b2f32ece0129a54dbe48033e46879d7b4333d183fe51ecb9159992d5cea8e962c103250de9c54db958096a2554b5ba1f1703c12565e7720e12dfa829e93eaf629cba6b0c9e3f4cfb43238fa4d5341310d60822d0fcc10244404ab0b6befb12a6d7b027ea61a8ae2ce9c47e98487d4bd9331bcfbfda3de23516e05ae216bbf754129ed16af87a5e1a05531a9104ae0c6d5ce7d0f4314826f5b8b8e971668632bf50ba9b90b082ce31cee4ca52868a3e174e95ba8cabe4916e6", "df8ae2e94a487524e2c7adbf9926e0a83e0d1d5b4a744cf4dc4fb30708c55d8e357f6bc46b4c149e95a31c6e6468fae298a1773de065c9a066c9289e998270e1de2705b29f38f73b6a5f97fa6dbef77d82b0be26235d092681d0987f01c0f9d1baba71f678efe5b67539ef642d4bed38153d4756675784c3a8e042afa99d7e11a8790d9f97e557b90dff1d700d9fcdd79062fcf0414e436ed67826aa19dd8280674ac03912c989630381ffc8716ac2d51760ebe2ec922d40dd2dc93dadecd391a67de78a8cb16ec6318da113dad49af300eb7113c44176f28b65f060fb3f7009e1a3647480eb4f4b5f5b0eedf7b16691bd0c702a1f566fba9470cda7c5fe4a014ec423b5a5dc943a9fa8097005b4667942a6226157f94306bd84d4b41aece6cb81d046c75eb15b8415dd7e875cc5b765746db365807fbe4232dfb663abf2344035c48d9f722a105b8350be12af4834d948a2a9773347b49b15fb36b95e446ddb928eab64b8a2d8923a5862a33903f6237e61d2900ff43cd6fca98dd1ec6f946919b0d71cde9f7b3573dc56c5e57246eb13321c01f47bd72a0081fb5eddfe54ea6cd3ce4b2f530dd8e56e640d2d28ce13836cd64f5e449ed24c373601aceda6a6b6e73f7a1f790a338f100c788787cc08ba1a89c8648219ef0f970a6bb0c642024c631aead71c179cebba44ebbd2ff970af34889137bb2b191f1d8dadcb10afe23ab0e1af433144c938fbb6f96ab8c49e3ea053a7e54f3a3d61ef895ddb28fa033fb36d0849deb7d281cb465cfaf35c2cc095371b0d92af61e2e49ba65602a952d77e0904e68f15544708cc479e10b844ee18b346877930716c50efce82a04df322eaf76a56b093c1ffe7358b4a7552262b0c1219b9132394f6921b0822a8e7767fdaf68268e6edb2265a50e002d2f291b9f19fea93a03ce441893007d9340b2feb52d12b34467f038d531793a59d6105383a4f81d7ff29c03026d38956739a06cc7001bf9b53ebf17246ecf14c3b0fdc985a87364e5e2a29887fe7bb553cab943e1c9229915aeb3924530df03e1d3f87f8a55ed771ffb04bc72398f621bf3aebe7db8c4cf04aecea680ca8b48fb371b20c95ff975e6a7faef92553615c0920904ff1edc3918466605155ad8fbb3be699218a781b8cf0918f1b8cf074868b9c4497a99eb39701059a57811f94d19d9bb0f5c49225475c9014d599b1bdb5bdc90526a1623980808a3e073f9310186680a763cdb47a65d9c8fea32931cb389744d81c2548d6c0c3d43e851825d7c5f6f7258cba366a02b67a76e81b4ee24445e1ce6e86a1d6d39c5104142789a3d5bfd7b1ad5a12fe4a744ada672df8b4ff480bdd29eab98ec958c8f0342c599cb2142442fb3d985ca937f3eeb8088bd1458089c461d78af98de22b3da7fa7c0f6d9b9390e10cd8df04aac801a6cfe0bd038737c4", .Okay}, + {.Sqr, "a3fe25eb0a67dec358676942b6c28ef0e4dcfa1fd9df1ae99dca8ed313284a30c654fe8671c909619f1370f425bbdbfdbddb54a5603b5672725fe45332f523fc241cbef52b900aa4ca5c05b323f2d290c7f6fec60f2d6fa93f54fc221f88e3c269deb012c316a4bc4690e40c0fc2a283f246df434b3025350b4dd277bbb635a3c07227eeafef898148afbfda040fdfbae85fd50e13b1348d7e92e5fd8dd0cce27b46d102c73730739843adc132c5573e544396497ff840a66b0b7e1642f25cf0afb52075dc706799a72399dc355de394cab8cd214b6305b5d7cd6b2bd29bd02b17bae80f054425adbc3f095aa2e4e57aac0d2a973febf9a1ba64723d556c3f5921aca2d722825b26a220c5e13eecf1689602c55e6bb1c1b1b4d081b87401948ac4eee6364e6e18e59ce07aa464ebba49ef6db6d6c3726fa4b026fa1065110ddd5f7388cf8b2abbe4451f513ff569c8d68a18cb533fa508aebf7951018de1b766a6e008dee0552296beff01ebd230111f70d694d191747544d968d518c58e0df1e52a909e586ce4a0e0a9ee13de6ba8808d8c942a59f9013766631e55aeb28ef147b8a05e5dd8fb970b7dd28970c338cedc967bb96d07b3e7bbde96414d8759dfd2e200dc5cb82562abd53eda1e1963c88dbff9c1edd31ba051a8cfe3ca6ddaac8e901ee655952abfdc6b7f30d9e8dd6769e826b7043424c8e792375761cf0fcf", "12dd538048e7b086aa527eb7e066072a0651b3c38d263238dcbbc2f6a88a177e998ce51c24e5cdb4cd374d3e433fb08a8b4d5bb5a110453374a7c68266cee736e24c08c01d2e1e64d07b93ff1e5db5fa30d8394322f4dd33e6e9bb2dbcce3e9417a615cd9980b168a7caa63d7f8ffabcf5c19ff1ede114ed7acf1edd64ef941c01e0d6295740e95f6f9c7d9102f6df4076cb9c459dd926d966c913f46f0e126efcd3b4834e5308a9ae5c5a5e4477ff135c464bb64b0bd2e9678455b3b40297a0db114208632ff27f0aefdb52d0190609e675e1d6f03e95bc76c386f69263f29e3583ebeea118877fcf57154485b544e044e4c0ff5b9ef068decb0beff7f664040cb16d6cdffefd22c559409f2a3b7b8b69d34914e024f8427b0052d82c40b2c59da81c4b801b66f6bd99862d85c5c9bd75d8c5535c62a4c01e6608cc489e4c90de37c3e24ee56d3f652feb27efccd625f8a13cf85331daa2bd38df149b33d35211eda1174863267d8cbf2816ce2c85ab13d5d9a7137ff91dbb1a9622cf8314b5e0dbaf839e5bec96aea63af842852dd34dabf36b3ddbe0bddd2e664578176b3584d012eeb5b701d1f0f28fc5562e272482650a052c6877c1abad35b6cf8c30b635dc6d1dfc6e2413741b2c127183d272537ee0dfd9a7c78437c8219039a1cf376fe3a48f42410cb54e2e0d6f351940a57fb8ff88c9ea440ea591cfd89b51aa2c", "690da0989346b498efbad6fe4d578f3d409333ea654c79de0c3fa735262a8786567833dbae8c9b32c5557078cd754672c23cf427608e809d0bcc1f096425c3e6105a6cc04d5a7ffb9bd99a3652778fa936aa8c9883fbecb777af8ad02371683f656bb3e88ca4c84cc6f2256ee287176a8af050a51eebb40886bf236331da5d52cd2d6f0c102dc2654e608a28fc59b790d0258a283e5d5fe611000e482dfe0e640cabd84c702f7a43c8404ecb72fd7effdbf7ca1c32b1ac4d8e9e4375c6717a9f503094b1c8bb93112bee4c2cf0b11bbc1c1e82ae9073390af2cf415a6d288db89de243a8f1c6dc48beb97e8a50d0c5bab4cb310b0bafe0f97cd2911412f564af40b14f41add50a3a389194ab48c5e4e3fe91127761313ca2296838f5cf4e0defd7cd4c18e63c734bc846322d084761a63695f483e5ac3ba14b5ea86d7acbec9c25d161d351bc28799d29425d6d001692743d469b1c313da4065cddad2bd83a881a20cabcc1f6ad1b40ca68923742aa71d5f6dc3a44c70c3bd2b316c226e9873f188e2c1b02addc45faccdedcbe0f9738dfd77dd22d5710e7dfccd701f92440e2d4499a19634084a4ad755a3e930f1a848d47c7cfadefab0d2874f832cac59e657b68d3bfedca2cfe38355dcb57baef1b8399d828088adc5cbc6cf912d3afd3b2d8cc982a21389fc614cd86994ce764ef2006578b3380d44f822bed589aea4e0555b7a4bdfa77673975ceba2d12c5f30cba18d96220c8109fae9f4639f1268c31393b41b269fefa792ae3e06f3d0ecaa82442f2bab3c80a09d40f56b4ca51c0d5e8fdc3e867eda2b41d8542008e03e9df71856286c6771d6300a74c93c267c0bd547b9299d8e91adeacee65487e19024aa2bd349e4a1dc43cdffbd2e2e6805e1defd93cf1a3f5c7da2308cec2d663729b2a7bb3889033a0d39f7cfa936321e076c91925521d456129a52a6893dedeb2fe37db271976bcb43ac279dab59d88a9beea53db7a41e0860d4b1634abf47479a7de0722efc166345b56ae308d9dbf071896e953bf06b7a503b2c6b64c4c9f66fd49439936d47117aba619767eb110c87170decc22a4e456c0eae55fa8b3722369521431c6c29ec7683051fda8e86e5162e240e04614d923449ecb6bbe81cfe8d0467acc1417959cbade62a642f66dc047ac716581c61bbd6ee3da29056993176ce3294935e0df6c66d4fe040bd0ab62d502f32438fea524f22f3a018c01b3aca3adc5933a7d26a97f14af11288d1f267028202c0971fd6524c67e025af7708200aa140270b81cfb454060087dea087bd754294cdb58c10729ead6bda27109f6e6078a4b1037e5b95c8fcaf513bd6372e8e8cc1ae1380f68257a489f3dac3962b041a4c0d5fa3284ec6f1b12c5bd9f67f4b3f8f8191f3bee0e536a9913815414babff881fcd238d400330242276fbbe961", .Okay}, + {.Sqr, "355c93edf72cc44cc262852dab73cb8d2e6659d404eeab792a844acf46f565fbda03d76d8d96471685bf652d8a4cdf256ce8f6856b173d8710ab6a2002eb2aa64f38c6e2a49ce55477008068f1f366d200b472cc18e7715eb2e54ce4207f2772f0b1eec2295c9ad1e93f2c58a143ff6a698606eb214ce329c71b77db0628ddbbceb68862103f03ef5cf8d06f454ab7812f6aba9302a36ce4aad36e2f8298e839e1b814425543cbc146e6995d6759ca01988dd98790cddcc7166ca70c23e58c2651a6e5ba42ff004ca641bb4e24e2c4b938ef97f72219383213d390ed68c9d54f205b062d52128834dca42e113e1c3d5448ed02628355081016551692de4cc79ec4173f6ccf17efca555034caad719b4caf6b38db315318b5c31132aa244fe192535213e8a1671bad4420bf371f5b0230c39293ca5dd5d31ffe111f704a42249b5bb56bbd0fe601355162bbbe7925c5f929896265e018a9e25517f4baed82ce2d38b1ae15de2b32f3d0d7dfee3cb2a433b34ede816f9ae20512b4b0dfd123de7730615cb5cca925cf664ac9b7f45e3672505de4948af75c5a0ddc987c3f4f22c79b84d618f89ca271e5705af1592fd3b2af8a588d4ec102606d48e8b353dd79cd776b79440104056942fb989c62a873832faea18eb3abcaf08eb6e5b16d78c3ec6f4cf910f82b06835cffd26b9ae4521633cef0e29b5c4f07f70cee1546ff177", "a22d1b4bb0ac221a0c438284aa37c82e7cdc112ddcd34b3c1ee5670561907c465bf8f42e8710548fd359ab6a603fe48f6e09d19f3eba7c0a9d99b5fe04b9e1e28c25eb28eb8a2e37dbcc4f7f05971b787f46ca83d647988c7a42313e3581811ec056159a4322ef24630c306a6c9ea16240a05c1f93f9a845db236dd28116e9bf46d5611c72e44d3b21fd21168995857435ea65db222ffb1c777d2e104b3b5a592bec058e6bb452ae460410a71d32864b167692b98bfb9f514b8a8f70c3e67685d0fdf4799bf9ce82015c137206ac74bb478776a7d645d8b3f6752bef5812bb23f803c1cfd935c8bf4ce214ee6b006f1f84d4cd4d0d7e660a1e68ea907b3778de94d682ca3d261ee0729558c21c86973aa788f4cc1b8f31e935e45d982844045998c729715ad8e8adcc791550308545e973cf6b9195765e8b34b6253f7cc23f54d0a2ce491d33f928e746cdcb4f4754fa35f83ba89efd70e4e9aafb0516bc088ef11960b81473451aa3e9e3df1deb471abdb84d4b5b5360814872793df1be76cfc5e4b6e5977b1166569c0c396630b20e02b3b9ff8e32421bc51d650f92d17c44e60ba2d8d3e90e186e124688050336d1082e48e92ac266527cc9ea2ba2b9f29f0201f360e57fade7cdff418455eb9d7420dc0c6a2698cdadb5a07b3c98c05ce01a7169389ba44e84474b536d282da6af4ea794d5764c38a0fb4158d3c45b68d9", "b1f76bb30dd5885e0a389f1e130c67ff56d9d76c7b7efa2cbb508454aff7075600ac310d845f6e2bdd433f9bb046c2f7be4860977b49195d83537ce54d380e2ed09ad78d40b5c55655559434ba9e47d87dff6dcf0563f9f4721ce232b63c2cf1f026818b27be0bf215879e36357c2389116af801dab0c2a96fa93b387d2d478d2bc085d29ca5147f0ef6558d3d5b7f9b174361330fcaa43f64b868ecfe68aabb5ce12894f5f2c4638aab28b8a80dc7c1bbb8305694de5d21994566409525f4be6c11154e27c6897192489a5668791a9a3d119027ccd0e383850953ab287b5fceda431d696555ae5ea6203190ac79b19558882279d62d13c3aee2ffa5ed3deaf4806244cead5ea68252575cdc8b87a4ac489e92e041908d3447916e7c79169cf1335c50a048400c96e238134b04604cdd059a5adf5d7fc14c7206c8f4dd5f58d5aec71aae50a3b66a95682912a33ea198892aaf14c219f2e9e291489be1cc8b6edde55b179629e0bd24dc65eb1514340329ae4be30af8c205f747a74f583fdd5caf57b6e7d1500cf6832daaf66da37731ba914f89eba4db152dcb0396c960d098fa8edfb83e287d80a0b2c58c6500563cad684278eecb9af170cf6ca091fdc487a9adb27652b39591bb41fd7333f818341155d523a8f878cebb2159f3a6092e8458e1c4646760dd62645168fc92836c17bc288f9179880e899da9bed983ad3d98d5bf55d10bb6d405fa7ba9891a95af715c4fac8bad22a625e6ac6ccd162e608a1ff5c38d4a6ae9833b29826a331f4110b3ca1ad12d0c72dcd0285332855d6f14735700c60649d8807eb79c2f5e52e0d4280eb4d2090814a49069b01c30af76d2c41b5249e41eebabfaedfe379b9167c7a3f4bf3d88743e587f0d4aa3109ff467ba788169f98e2a87a07f43a137a7be0ebb8fc16945ef0e4722a4673333dfcfd30b3eaa1d7722baea2c7653e80a1362b9488581ee0484a1978d9cb14ce3b7e947a068266b882deefb8a4688a1d053d1ec7aae277cadb7ded5c03ce266200a08e32aa3589a3bb2caa64aac1bcb312b866a9b7f47127f5fc01b26156dab0f58bd616abcf12d12938bfb8dfda10c2f32b91a1f42e5480f53071691f3b6b94e30acb4ac3fce0bc43bf76c6af3d0474207e6cbcf1cf4e248e05d68036b0b2f59b4dcee7d39a0d89feae36b4d17e0e2374f812411a1cd4550cd10354878edf6d4259ca800f78d753df458c3ddeed8a02dd48c9c23319aabf0ca68817d1b69764b25023419b73e78e74ec0b5f2efa4f2d3d3a3a9c98544adc02fbaa92d622472498bcbcc8d5dbe53b007f257eb350ae028e1142c3898599f00ccf30a2b608a093b8c8da2e4a83653537bd672f2fd608207d4011ce268aed0ff06b8d160fe7c8a30224fa8444a04fddccbcf999956548bf6914224deb6a8a0954e10b5b9e9760f34551", .Okay}, + {.Sqr, "-a561a129fa1fc96e8e647b2c915cb24f37f1e584839320069e7d9ff9fd24314195f50731099425eceaedd2ace1f30960bc615b471ece92fb7fb32e73058a30d10823474771de2eebe34b80f80f947eba0a06cee5cede32191541726c7903e6c06ea8122999dea23660d25ebdffa336f2d91a2d2268dee906311d758dde2da8701ad9c776eb2616c77ddaafb393f7dcf5c611c78a46d8569c383f77010e7d13fb5a1c42c42da823626c9ead19c02f1b85a049f3ab95327911bd96ca0d5ba36e2bce4df3954f56cadef81ffb6e2d3fcdc3325a821b56ae245702ddffae6f3174eec2d120b782f50c7af6fe486cb279d1bb989b66a79dde13e1fac5e6067431d8d9325b6a1221e42ed72968fcb1a8e95a2c2173bd5e8828bb8860434b51f1b8c47e6bb40ab87f677e4859d6cbf47123edd08e4f9acfa599851741c9b31484a739eb115d27c27df8801cea7dd5734f2fd9363ccf650498d61b41c28d32fd16ab004d853e77585ec6ad12f70ddbc08f6d31421201446416cecc460b8d003b0f84b18d5ba89aa6ee10fbe065a7a0c54045cdd557557d4f7eaaa22c31856d364ab3e9fcb8b184552b2e0fd6db7ac4fdfefda368fc1449b4a79a9436550ce443f3416049ba0fe99d909f753661f2a08dcebc7def043f9a75ea52ce12ab33b15995b13f778e8fc5c34deba9bf379f70a981f98e9c27947f68c729769351fc1eaeb98f8e8", "2e9efaec62f2554c65e9aa9c80fd101d0ce6c7110b5342ab212bb257002ee2b515ebf354f572bc3aaa456f7111ebbd7c7d27197f24add8fcb82f82d4d48d6b38a3b62a14295b5cff9ec45bc14e703ae77afa41fcb803d3aed95de9d098cc4c831c250be0286dc22d4e0438382928a0b5507c6c81cefa88c3cc466b3b76054dbac6d73df9f6a693d825f517160c4d6146bc8e2419e83cf725a99a511d384c011c28a25f5941a9313b067af04bea3508216b26805df97567805a67e0a4ed1b704127a1798ae66ae22fd31654a2a5b914966dd34128b59b89967dc616d6346d2ca6e988b52b4760f5f404261d77c4d81e4c59deb317b9875507d0e99eec264d6346b80d29283f73512bc0d966d6b85bc3320bb10e934cfec9a2314311786ceef05d0b0d05ef321cdbc4892f084a6e572c453f7c3ae7dc62d48d55131c78660f863818b21821b23bf434873e4d4a3cc3180f0ecc500e4ecbd4582ab2dbd9d5a178c60b5fb2fb01a0ddba60b355a8d53ac0c30519cc54ce7464c6b219d104b0cf9716e6b008b3f2b264731ada8b1a09260decc6183589183d1aefd070398c84e5a938ce2f906f4760c4ae7f0af78118aa48c225feb4856e8837d1c27e5e0134b1965dca9000e4805eeb17d62eb8bfa980e7830ce2eca4bbb6ac145880135693c2c514c3c34e7e63d117f9f36a74ac66e1a9a7d2b6f7f81875577acaba3dee500ebccf", "6ad6fefba3b2593d37431ccf1fa6b177bdccb04739a9732ee3cccbb76ece917af8055c1002c00b02bf0105785b7c7e5d8c1f1a1e586ecaa933d52e530eff609e961ad645abdc64d08fe9bf8d8bb4b5f3864f9b1e33b720a40d2e55cd8142796d5be1d1356e6ffda95171e0602470dfb18f0deb432d80fcdd5a2e464302adf576fb2a65e29759eaf1a3d8d4b98a586aa9901323b7f28b3a890b6ce5bce87fe9837e7e1669b232b075745fa96d24755fd3b83bd832023ae9e51a79f98bbf9893ec8abb90c90758fb9d1cc89ab2c73e859d428a5d4ecd1a748dd4a1682734801c7b504e4da34260d720a3981aa5004d9d8f3efdf7b0819b1e1c24ca33dc79b13c6676a8a9d60268b6dee98fd7d6802173fbf40730c2a2389524c3d127094b750f02c189ccc63956f40b9170dd4f4a37a8e5db3ca1a43963b0c1ac1299fa0eee2551ea31d6bfef26c21d1a72e0424e81f92ab010143cd0bef97cc1839c12b58e26fc9b9eecd033ff591c92352aab38742ceeea84972e07cfe0b25a0bf62ed2dc6c475ba3fce7f370ee3c73455d2b271d6a01132f7a480f5cd4f2833d557967fc8454dc18a5a622ea4a63c7acfd542b783c3d029e2f3c5420a95a5a301a5bf2017d512f479a50f83761a5f01b6bdd2102f6bac0f1b8c3a58bd22f32945a9ce276631cb1c7537077269ec7323ee4d7fa0572752498b6dbfb1dd48723f1126c8fd5fce5c4f7c455718814c5d3800acf435d3eb43a7973cd0936b48e4b60465cd5ee93e715007a4181d1dc6e7f9f2b852ff46cf0b0948bb07faa7d3d9866e355d93f7485343f9e5b6d78b806ff9c507791e76e05f27d3aee7e2c7cc2530be960e1ff9414227ef0679398bd3b87be56e606f9bd3015f65e0e0d8c51ba8685e53e1f7c7ac0f9f34ca6331c4a8944e317b6b4405396dbb9c4886d914d07b7a2afc549ba17e4b6379376810bdededb53d62c4cd2c5b02e10954c2fa6bb70c050038d2612577f89958dec9fb2e32d7718a4754cff01305cad5ef2951d1e105a90544d08112429fab56ffadbd252f832c512145c9e8f75c39c6e00bfd4ddc58e3c9589cbeaf130827453983ef7e9ace4f8ba45ff89be09a46bae1bbacdcddc1733432a27bb68c68a4ea40dc2227a21586f8e1378b24dae4ea95e2b383ddbae104b1e6d8b42f8d889b62340fd4f80f459351827e78559c6cbb5104af3725fb089e2ec3404d37a02da0cc88fa32f597cc7264398038e954e1f1fc8e7d66f9e476e2750979a7ac4cbd6696f150afed10c2e710b1c20641f1853a8ae5450fbedbabc5903db608be9620e1b730365eed01dd1f9af89872bda6d9dbf397ccecd7312879fb2f311de121e3b50b3f903416caee789700137ae3ce2c05986ff5450931e1d6761401990b425c3dc8e607262c80b910aa3a55378a04c1e913af714533c8bf70c8275825240", .Okay}, + {.Sqr, "c0662f5aaf5eda4e07fbb816b2e6ffd10c8fb217d0c3d900eac8fd9e0e5e3baf852e3d33a8112bf795e9b52486a5ec0fdc346b03b4fb3efcbcbe1af0fcaa84c0cf226d42d3ebfaad1ab6bb025ced9ad4872b85fc0737979956e2e8de514a852fcd2feab08e8cadcf6e67a27b18ba696620acc6e3a1c6a4a39f0393e3bceb5c0a45968dde72b1308e5c41509297a76fe460a59e4110c4f32b8a902b40a03783c6ab7f7d57fddf3bb6f8e0aeb6151fdc87b2a390da3c5c71dbd5be0a6dc2c761825989f62dafc71af09f2aadaaec8d78e568cbe10cc78062254a50738fa04554fe3b59d6e23f54a53b034d31b70bb63381a763c7fb4a22caba5c3d7fdc7dc5f6dd6d17c32ac73d96460109afeae50f2189a1eb4c71f1136aeb78fe60664cc21a27de4d9d5107e6e88ba24dcd8609531006ed3a1b6adb3c80a136facb41fc1f2cd6e05e70bb0d214e57e2568ec5dc3eec421d7b879a979835fb75e175149323aa135926dbe6b548b387992f98804b90bc195ebac10c31b83b739b98b422ef983b7f22cfa281e1d1cddf90abe631029f7eede9c998c504bf128fe6b6641744714263128ca6af11efaef59488e81b6dc57a1a6ab6f72dc7f86dd3799e2e81c92b3d2d53164cd300c3b1ffc455cf7d3946d28b3a450201bb902842fd9ec2acbc6a5232a7ea7fe8497af844a6216d97542616528c037b9c95c1233eadfd64ca9909be06", "1452f5647725f4e4ae4c296b92f2a984971026d551409adde98d13f0498472bffad94982aae628cef3953d3c35216ddacc12c5da6df487c846d9708e92c7302887934a876b2c5be7a680a032273c4034392ac8594672a66cc906d1bc78a362948f111003efa94c56463e421badccf0a3529eee12f5b5dbb6c27548bfe97e58b552c3c8aaa7b46f332c3f7c8bb4e4ba44386c55dfeccf72b4a4e4dd1eef0afaacf550c9882996a1273502a7c4232ff32008e466e25e0a72676d11a7485116a1df781d2a5c3d10b4117d35e882b7a9343ff652c5e6c11bb41cb434aa72fcfc86cf51d183f9e1d512e15ff50992e41794298c44468c71d3af3cc100ab7bef9ab539e0cd96a2c23da47dd8128a38f35bf03719a12085b05fe596204f5f99d260503f1f579fa12327966558bcaf561804f6ce5c4d492a6982fc755858f751292c2b0bf9f1db2bb277d9791b35cb84c2a27d68b88cb530c1784e3705316fde326dcbadee0b103bbce8125cdb047e2d7d44cd5b2b747bda53aaa738c1388da50089488d2878b3238ef18abf07bf0036eb2d1fb559654d34e1b03e20d8ae15b0d50d33559e50d017c0255e99a8ae6642ee6ebc3d8b05012e9ae9436e53efa73b63a03d58766b34fd8b78337b4dec30c51d609a8cc0eb34edd6296400ea4e49a12c18081a76af987e200dc967b4d8a8f332ae30784a0acff99f0cc9433100923764208f5b", "90996fd1cc14738f9d24e8208367d55fd635f4bd185fcaeb1b2aabb6161ba1812d56880a187663b245a25f9f2b6a27301de01c5f035664721c44a10e6a97f70bfdf0c9861d6f51409e05c578cace64af3d01acc9ec204111b7a2f8b0baed430279a357c4b49141dd40d4936aaee5b5150e2ecf84c0e7f1a98d9f4f9a29d7dbd00411d82b3b89ed2686a48ed62f2c03bcbf438ed4b7c3271f90eee2f57364c80a07fd8e7ba72603e0170a4b53af8a12087101624e56e432edb278eda0e4b5deadd881587e9661d6b031a91168d189c1ada8d35652b7a890beaf9dfa87a3a2068445ee368699b03e40b62958f6a9656ee65df85de928d203e664459b7765b86316b6e671ee16b7738856bff055a311c324cf6286058457cc48ed7c0cd7d864e94d3c21b6464194efbbde2d60a994e8aa0a34346f9d2a6fd94694ec01a25d4501f7f17d3f9ba985bd1fff93213459da97e41c9d7fe444538f88ff6a8f8e54d0dcfe3002bfecf532a0af616a8537111b5329f2c8a0b10eda20583150604f5bc5aed958ff89bdad260cd8bd0e6fe01db23f26aa80d2bb783e35471a587228d6b44c0291210ea31b5be7139dce9bf23598d963f4f653ae0127348218277c20feeee9bb09ec0f414fcc99dd782451ceb6affb280f97b04f10d06f2ff8f386a461991c436cd8296813d9c068df31496b07e3f85a01fb7097aa1e22c417a27e571aba7b28020b44a9e416eec9fd62625aa82d5dec0fe9fc5447a8da4d73f4384745f4c759dc408ecb08ac4e7cffd8d6d202560f5e9846b94952f5139150cfa60822eb5ae1c41362c1b933695f0a63537ebad791405e1dc5b0b312125c01ef19c82b0aef2dbab94aaa04ed3d0919839e049782d920d7fbe3ab3d67caa8f2608cb50e22b6d12d9a6b76e915cfa60f8d9ed21574fc70d978c825496a101fc9714a69c9ff735bc924895ee4656be4c15b84048912ee0c11ed39a6dfbba3fc92079919bcd9005b05998e5150116a474416d4a0f4dc269041e58d16851db1b6073b25de19743c3faea2f03f18800d49d54f22aa26d36d865a188cff1b810b1af20aeae95d3242ea225464d024155c9f5d38e8b87d0c99d312d9b3788a8077d156c9deca7837e98df95ace58db39d656715fb9ff447b8b02ffba60d5bfe14cd0331eddd862f62765fae108c8d1c8919859fa1351965ff2edc6087548f6ebcbefefcb228f41b78235be3475044fba172e3c4ce833bf52fd04c73c9bddad4709188d169e29c91d5b182340a69a99fd6fbef84bae5deb1c11dcd24af3f9e01c2c337cc2a5164bf43cc65d5f8d66169b8fbddde795bc9f79a82f08419d865ae5ade8c46396c9d72e4cca0126b69a72b89a7cd4b54bca4c3c3ddc6b371ac8ba2265034baf950889fb291ccfeb6a969a3ffba553b74d44b0640a34baca20387eb23ee32f2d36fa1578e824", .Okay}, + {.Sqr, "-ca22c4b582abf477ee412e3df0a2e7e5435aaba8adfd7d65fabc34e9f1e497fceb62918521a84d762cc994eea6a046fe7bcc1c6d9238f6b15a7e56e02f6bd532199ecbc27561a10d758bb3944edf592f29c78b387b1c23582d26e4b44c56fbb490d7104d460509af9e1faf66652c8d53e03d99a7c17e76102aba21899a8b26de564eb4065e5f5f70e890f36ea1ce3b3a02ded29eaf5a995e6013d5d671671725946c43894fc821688a906b8d9c490104e0bb9e01211045f1fb98565923fe17fe7f1c3f9f052efaeb7bc0c852cf3d19917e5c364d0d6ce9a001150b4261fbe5cbfca5ecfbf60e9639e60bf180429d452e4e8ead764d4359e690b8e0cc46626c93c00a5ac1902c45c8901f4b5b892cf2dd32c4ca74039fada6c2a391bc5805159fec6762e61f1ea95f78e4d7c5ffe1feef144f2d2c4e960fc9d157060679cf3f925c3c396b1052ad4ab1fce8d2ab8b02b3cef76aaeb9b637af69c8e5966751f349c60337dbd3901e6a15a65dbd090122c556672672c4c0b4cb687c033dbf2788175ec1a666b559c7289b446d9539923297c32fe512838bdaf446eb92b8b9911920b90e04710a7ba3a63ddc2e5d174921f465e028fc3717e26562f14c552680f2313aaac263ec666899f513bd2df5dec84f314b2ad969c7eb668b69c18f1d9c4944d2c911613a91161fc0372a066476800fa1f25a3084c83d516859a5f174b1c328", "71babc02cbc50de465d6e65fbe5a2c241ea3f14201a18af69f10351f9a2a119fd6b5b70553ba56f8fa23c3a08b99507f24e3272a922832618eaf06915ca349421c46a878b3c82e61cabe13a9d2d62c055f6485b48cec8a19969b1d927537b303c2c20c40ff724e74a51448421325917bb0316c5beee8648c838976694d45ef5f03511fb9cb90e46076298aac18b9816b8b2e58c1732ea6e49b463d877ad882c450e3646755a06891407b548da15a183df52f3a6a43b3ad7939c8d46c9589a85fe929992207db54c670ff587b976c6d07d3f9dddc957a0d84ce9b8ecf975f04b2809b8e2982a5d100762e57769fe08cace11e97c101de69490920d682d5d9fa964a2ab4ff1919999fa15233551ec793ac1730b7be9885605b4f4913503f20fbce4956c253d8b57f862945c4b51495a50c83925d292a6cbca2adce192dfab03348b76813b4f344a4fd11d71c58e354d9cf3b526cc3c6630819c7732ebfbc9b511024a5fe7a56bbfbcc09fdd64022bb608cee687b7ef529aef41a32917681e683352f1337b2c96fa431e2f2ae81a4c22061730626202fbc6d14ed9637d18e63807cd701657b01e481fec6d12b48a4909907d20109e86df497d9f0e1e12911c990cf547a494447b683c7b292164e6308db1543e28feb0d934c40c464c94d19a41540efb5ec21926ce62c4f53622daade3ab0bd2cbd949b241de86b41fe4fa3e9af11", "9f9ae327499484438c0c947f0ed691b16e45345675e1648dafa5ab49bd381005cdfc0a9e30f3c0fa7aaf742bd7cdd271a6cb70c633f2053c2951c66069137bdcbcbdcee8e2bb113d8c0e1d1bd1cabc27c75f3f16bd9d361ba1b8ffa1b71b4e7b6264888fa4a196a75502fac3ef471dd54c6d74e18c5ef05991225fea5467952902c2c0cd64f4e1eb5411bea953492dc4940d26e0d48db8d43d1481bd2191b4c9e659be8dde27d0485363a36643f9fc7aec4294ed73bbb54f5300f0b7ab4b0403dbd57122e8de2a87e9ca3c29f661c0ad64cb488007ef7b1c7e2c4ee35bd37464616b386fc3cde2c50f994c805aca19b8c5dbb563b1249eeecf16b5b959ce149f249145ff770654103a9a994a293a39f762455ef9611babf942b0e0956e8321e308bf84ffa33f32db969437b467ad8829e4e45c19897ead726f7fe734093c0b9584cc2caaf89396161cc445724ca4962e2a756352691fdbe61444419b28277b56d599d6b63f1305e141444713ffb480844144477594b99a26944476c4c2b223c5bc29cf55f9d4b387ab274d6e62a51466e777ac15268ff7880d6001cc2fb141ee9c211af2363a19a9d64dda1e86c62f6924482971df85da68e37764bb4f99f85552fdb1a6af497d6556ad75b14e097fc2fcfabb46c6ade1ae14dc0e164474c9e9373be683a1c9d2dc6a7bef68dccdf4a6db13f8c3ce4cba04fb5430cd939559e178d7b263b34b97da866999a0cead4aec02b713b423e17799ab7b05f35e9671b2908366b6d17ef01977b4880994df438154a8fd4e25a71f07e5e9eb49c92914c40423ebb0c27eaa213ae5038e678f13e6c4bdb169905b1d7bb87f1995b00349465189d1791bd5f423c0fcb3b6353a8d514adfb6c4e5010abf2e79cf666b124d1e3d4510721351ff79fa68f2878c956b1d655578ed206525a400b30cc6fd7cd95b9178537a7869b086572dfa0b25fd12b8da6769a89bf831d1e362143297b2ef06a2016bda832ca02ed4b028905532fe21009f07afeba5d325d63a62442ad9b5fa0eeeb0d0d1ccd186b7575f3df20804757157b3d18f01afcca5ff8fdbe2e84fee4d1bf2eb7ba640df6d4896247699ae5a7d594cb39e90791a174bdbe4f52f4d62a9561385df5980b913303edb5cdcaac42c180c01d5d81c3437c8fbd0cec1e6273367c56f0b469f388f5d4740030a3511636eba61b8c1128ba3536fc9edbc105d02108c1c8045274de2fa6b72ffa4948f21b1e08efabc25a71261b625c7c4ae0f9ee4fdc4e34b8bedacec122b6eb5f342914e4d9ce282205db9671e5f618db9aa24ebfcd8987f870cd76d28263fbdc01a8aeecfe75f1e44d429c9da8ac17e9129c750d80c369ccb7a1d21158fdc989dbe786e58493b4f798bc1874a561394b4165c9731fb6739d0da5401052e05f07ba83d7800a3ba4345a44344959bb215f640", .Okay}, + {.Sqr, "-cbf3570d49823b7f8eac111c5a7f3baa4044fac56f6951feffc0f14df72a4b42c4eb1de409d4dc33fce12a16dda5581f5a9459a9fc3f96c45e1ea81a128cd6fdc3bf0611b541f157c4729239e16722615e535e93c08b147c15a3d7b1e84efaccd95587d1b5d260e33c5446eb07f634f6406e16af8cbba25df518e5d85479162c749f3f797177757e0e943146686ae77c439abef12086cac3b38068c9f521952acad5e146dcac8fb04a4fb1be0b87f62b1ccde6839330952eb34df0eb9b2f022a2d5905fcb713789fe9733e4f9c523ac9ad6296be7b5fb5bc2400825d96ab9014caf5527f6b105c5e14de7a42fc229c5c7407ffae94dd652f7aa06e1b1c3b6d113647bcb032e61b00f2d6745786cb98967aabbd6eab985d985d5b1b35224374beb8ff01189b9a58f8e7944314732e6789469abc7ca8b16fab2d1c51ede6bfeeb7c98517f522ba3b6f40c2a3f3962f7ab2e5e696a98d3e6c477f55dc6b3db582710f00aa990d1db5c2bdd3902ee169ef376535a3ddf3837d3114bc35d72fbe395babd87662e3f775fa0be7ae7695eeea58320607e8a0beb90b6b3dce2789976a625e1836254e00f9a32df6512aa47a013cf6faefa0564be2828c81c3514273fe2a4b28f7f5ffdca6acf143a1c6d131e09783287f353ff476e4a04ed31041a17d895734dff9a25d879e5b32ec6a615e8497bae248ec7e909fca13fbbbaa2b166dc4", "46364cb6f0b9bded14c0c6709a4d227fcf74c54382ab71ebd70b4181d795aeef8093ab6ac07b9282ad973c6d9d7e49493fc1f75e2992b8f304c7f0d575d09b86b278cbbfbd069c4fb2847d49766e63f05f1ae7d321307e3d1b6307d6b8ee8f0c3c89ac643ef3653e9500e980f5121d0e6ab9beccae46c776f825d41ddfe1bdb43f18e1a8973c9607f4522e6f65cfa107aa843a12c65ed44b1d20dc3348dc2746f90a92d055e7d78e70d21391160967d4661e36abd5a9e7e95c7d60d5253623afd05f4ac5c89ee766ed608b322382e91598d0c3618b7ea34908c0b3d179e2c701b0c31df497087f3bde6c5479d4a0487ce8f83f4938417af6a74621692256ef29e125b9ef1844928cf096f7a5850a00c39a296da92199522747093a5b7b843756149dc7cf6c3905b15d4452f9299a7c8dbc8928a9359d181a804ad6674d62821409756f0636781907e57a6bd9ef965ba3e754296ed2636bfddbf3b97d395488acdb03f59052b011e7367321e2c42ec983af55140f3ce483d59ee0f7efd7ff2554ee3ffce6d396888b4918147c18ad02b7afee7092b7cef234784a5f3a7fa9201ceaa7af57e99d3f4f190da2dbcf56049df6d343413dd14c9e948c60b5d24b2fc91ecdd7df226c60d5bdab87827a673e587df7088e469ff726f28d7824ff528f43d5067032d520ad19c45b999be878fe4ef179a37dc51f030b9915e49bc7ed24c2", "a27bd35d73682040513403e81f33ac64ad250b5d2fe805b3b20c778bd80e4c1f2130fbf3d571eab57d6c45b604e6b4ead31c11b3ec2ef7edb2873eb6d066fb84118f48bf180317a7052d9f8e1f02315ee86640f26f5ccc0d208c2f4e459411987fb4f478daa6250c4e15d9b4714be8adfedc77a9009b080f007ba64066368d4d9688522ea418a92201532b0d809772e318bcbce1cd1acc99209f7365f2a26fb99b5f1407da84b413c8e94d6276578d75bc4b1d3509a8239ff5501339f2feb3724a618737865296df16a3adb50581d0124b15ee159ad6678ee87fff3c2b0f2cb4c79d4066f2fde871c59b74fb4ac801476b94d5256a282c1066ffb2480292b65fd5a3c53489061d902830090c845295ca886cc39db2815d99572be79461f38d3584ee472a207a072d7f35784bab17fa41a1510069768902c7a4f920522eb86a780f1571b694101c8340bf94123b4cf1986da828d4302ef276d14761965027479575273cd462e9a0509f29b49d5bb91434c5e933c5beba5d6abe847bff72a2069d3229582c370cb6976d3cbc4b626a8c6decfbe51a99989089d39c2230ef7a1769f5895957aba86021554baa037cdc242be459c3b278d84a64f5c413e0653d7098e3b155369d83b00b03de0f62e1f1f6faf6f632f8422f29f85169915a716e1b51f7f9d56d5f91f21b27a1cc370ced0af3f5e68cdc688c1359d3a55697b36ce57bf85d841e03872538ac48589c061b9062d81576d5a0ca8edc9e7b78aa768baba36c74cda90b59febebbe1af236d6a1818c1451080ad30b6bf90c4e7114514ac79327d9323c6456097c02c0fe708b0fbca4ffc52c4ec0c24b89f7b39502853d34fcad993d25b8a87651a2b5a0a1eaff918d39f31152ecd668dc6a7254f945656103e6570c30868217d0ae7a8403d13e8ca5aeecc01b4e586d0de811843bfaa27ba853b5b28fd88957cd121706fcff8587cb80755152a911b482abd124c294fc08cc24a4e26ffb83f8badc48029f5ea230e5a7fdf0793be507cc28fe659b94986e4963a6835063a577c00a91e5994e8943ae76eaffad358552874e2a2274b28264422fe94bf07f9066b2d4e3ae17307c8e8cf63f25d2bebbe8e38eceb6966386375e74669bfe60b4e056e1d37bbec1df7c253d7c4dae0d21287f4d3272f2eb5a7ef07c1b3dd337f2be875340becf0863f88455c1f808635c6112f11029c1edaea08250679da2b678a3f209fc550f2e7bb311df425f05b0de15e5af9aa753d0efc2a249d6f4aab6c4b9432a88cd6cdc878a55c15076a1335a3593a681a43e466e9fd9bf849ffb37efc1e8d6cd586a9d230e8f549ab1f9054814a214f370fe363edbafbc25ce078ecdda8cc4239054b2170750def73ab3208cff6b75a30f4c9e2e3ea43018cbb0c9ffc63ec91d5213d18ee938cf40e1f13e68fa65bbeab26e4c07e10", .Okay}, + {.Sqr, "7b5681701a437a1e98d4a29040805f2a6fae64dbd8e32d46b05c412037c3fdda7bd9ad52538c8bc6fd536b79ee9ac87dba8b71cbb67cd826f9b50ed4c6385e9705a2d978140f8cd2a6320bd4b7a4be7be8b667c854b7ce2a2314b27b4be14c4b0c5e6bb08df8c4d43120c5a434be2ac31eaa950b038a886d1a06df1a7120fdbadebda15033361bc45f91498db6f5badb59bd574750b2413c6ed29f5dde8b82d3d68b2e9b8e614c665b51ea2f45a3ac4a7c312565822df70c75088150e3fa66f4045e6376ac2490ebdae4b3d1f419f260bcc34245a6100aaf347d3154e24f3793ad5b4e7d31e39e5baa792feb379b5d6cee1ef0634f85fcef0525d87a56e5010563895f434591e68a6745d7b332e52439f21db331a26a5c25a28fa0bcc196840f8bd7682a63ce25257b288edb4d1578a5055afbe37b1f94a0b659d11847e185c40aa310d6a9236fd115842f460c3367e81b41f7794095069f0600ef22d710ecb81567e4de209ca9f45fe5872263c18aad878e71e2973cfa4355582cfa7412921ff99004fe886dae144504afa062ce029fc9c714b0959c2b7ac46f3ae8707e4a84f58787a7e81cff21500148fd51e71a32b1cf248491c6d74573f3b4d9471e2aa5ec8483776bbe7756142db837a622550890f1762587d4620ed95e3816122a76fc8bcbf3d8e61e363d34137b7717bd515419ec367cfc4fe68b4dc902093896160", "549833ba1ef6675d96c3576ebdcfacb38ebf68bba01d51b496ec069fd571463fe5299c9d1b6376cf70ea7c18f476c90558d5e87b891397666ca1f41560a67a75fc9f4fa6ed4606bf60819010ecab8c0fa7bc4a157e222cb3bffadd233d1285ce4d10bbfbc5dfc3bf7d24450a9108408aca4a1456a8e459c4ee7abd9fcdee876d5e1755bf4d988009ed775a02bd7a7afe4f254a7864fd91d6dea2afaf86c3b61fbc63c3cb1a6b8f8e000e2c8c0640442219c1bdc060111f77ba5dea9f15438299c21283dcf323176d55e7e0e265f4bfe8853e9556e61896b328a566d7e0dc1646cbb3a13556b9e64ff5174402d8c92a56649382724aaf52057bbc7dc0ba1f43531063198b8107a53a63db1e4dae04bf4f6e6e2033a1f7b4c351172cf8ac594d067edb51ce7adaeff9bcff6232121e11cbd917c51a8429689801e96d548d0c7a0b9af7151b491f904e7c260857189b183cdf59878c7eeced7f4023380b2581e0fd73634820ea0551c3aeca2c076a77f932e0ae493c793a2b359dd77c1184247613d026b470cfa97c2f682d3f88f92cbd9904a10063aa2913c599cf9c91c1b3262bbfe362cc926b6b05b3af48777df7824f14364a5430b89f4baf8ccb5305d0021b4b28228ac5636fde6d2c57e91cb183f2a19e021fe03be575a1343309509321aef812e0df4817f8d22d9949b557c3db8f55ddbea668e20b99ea77d9e4e68b68c2", "3b6c3d9cf200a83e723a7a773a1aae91c4b1473f5acca1cc0788202a6bfc66ca397f27b407a1e17f3581ee03a51746c0db3a6f46b22ced6b3045cc408ed22357167442160834a9225c0917565472a7f6fcb996ce8e33d843040df2d0d77c966d505601c0a289f165ad2fdfa8702819868f544601a147433fddeb1719faeaf52002dd7497c1ad537ad0cd9f7e951408ba602202a391296261a5791bd56e6923d0e3cd419c084b41f479bfc278a1ecc3880fc6ade769a80b51b1a232dcbcd564378f30830be1914ec78303927bd0f8b826a2ee54a6cda53e802bbbfe704315c5d9096419063b2f7b7e41ac560156c1ea43fa9d2806f70400c660ca30e5a63947fbe796c1055b7afff3f1a4c79ea2b0fe80b7b1419d69c407fcb744bcf14e435c3b5365be4dc37afe61e1da987a532cee5140d223e728dfe70e8c34fdcbfbfe0185d08dba56907f22a70d1987117c444b650261c231bba27988503f1b0396f406fe4caefac086567220ff48e05c3e1f05feaac2edc37b9c390f6906ac48582e8919cc04b9f46cc797fa11e3732859d84e06881ba9d2aac55f215a53ae39a5a3c9f1c34ac91a9fede4f520305b7c7fe49e5f7b40b4b932bfe9886e5d503d7e26314057374f58dffe6010c77efa50b9fd295dc02ca544de78634623acd2e3563cb45ffa1b1ef0c8bf034c2d1836b709b5e9d00c6f5053d2f394d3381498f37b8fdbbdd9f8ce94f08e945389174c759d0cd688bc9fcf741bb079903cbe04ff36c541754802ae50f00f184173fef78be7b2cc0af6103084bf08aa95a97ab98f34357e40749f274819ae3b9f1ebb2ae5a2446c976ffca9025b4236cb19fcda9fcbe252fcba04a9596fe0d7569a91956e078efd810b72925293812af3af632a8775a4300d579de46bbe19894e639fb125baac40b4ed186c1afa6193010c99b90ab0c09e7ad6bdbda491b0d1fde37daa08877f79b3b04dd7c9c97d1d3e0a424515fc393b67ef795d820df05117b8aee26ec34359cb8621a4e3dd828d605d65441fff2b1fb351af2c3e9deb53e81ef29c4a40d0e73b114be131d2b208e9c92cc87b34e78eab58e4312cc2b8a146df1c1031cd1727da72e4321fdc181b7c543435eebcbd992853d73237547f1dd6ad2175b42ff3a452468bc63e199a4299481053df152d5bb20de354bb9ca31399f4328637eb9a1d198e69ad97184be644460f967c1a8df4e53e5ea0ec0f30bcad850d1b2c8924892a5d03be2577e6be70be8ad22bca70f965fe374bc0a64c51a33a55bee9ab7d716f665210b49ae346892613b31e607e6e08b2283d0879232982c919a75350d27afc76947e9c4ff5094c0decf7bd28c730d426b87de8600bc5a3b2cc254cc93d7bac78a1ea4d3bd7e0b0eb84504fa25ac1a7cda21595774ecdc863085504a8ca4b76db5908b0750d2e21eb678d9dc9e400", .Okay}, + {.Sqr, "-332a7846982641da4b08d05fa9f5c16804e151b2239d84377a6cdcf9cf4f7db053766a7cb748fd253d7abcd4dd74b8b283d3aa85647985ddf326fcfca1a5ad627af33cf06200f67cb6c6d923c8bb8041b453806a1f760305739bd8a4b2b030c3af6a508449558021dbf07bc2431e0a92c3281f5b2dee553666abc5e69ed0ddd2ee6b1eab8199e6dfe372066a844b3c00d8df465881c3a674ddcf46d4f6713aecece208480a0d7f209f190edf0a98f8b2bba6f41873aeaabefa37dc455f868ddb6ded85af730c6e0cfca4b15d102fc50c1ebcbad55c1c4c735415d29bd5d7ded3829a3530ccfa1ef90299528434965fd42ebcf7269c1b8433cb1da33f5715488687c87f75777528b84449ade9d7dea4cb1be761ee775245cfb91be8ea054725ff1c52b52f0a0addadaee7f6bacb2c345dd346327266fea1b795fb821f88169a470e5025db8c4f65aa5dd504baf98067609d1b390c483ee56d8d7a3a348667107d6908105779a70e6b07e79829d19900db56eda1df0d51e986925b0afc43ddaefe6e4a65417af0f19c891cc048cfe66b1b75ecad8ec2870b5f3997a1327c56473c009c223ffe3aef75181eaad8177c4dda5cb18563a9a358f843c23af93f268c3a5717ffc3a6a271cdf7ba501b0d90aef0b421b3386e1dd460a8ca62080f1f50f3de39363a6fd8117e911943ab8f1b1666fdf4d6f821d2b0ad243e5a0f32456f22", "a6d66b5ec60a0e666fd34f0717ee0298b230ad61830e4e36abf56b5f5250727a39523abcf90297a8340aadf2800e06052477538bc9330c55dbe612cc14b30bd5d7f8460262f866b28dbfabda28d50719b98b7cdbd1dbee793ce214e7b37dc5a10b02ab918c3f09826a7116ea20fea4dd4b934b9f93ef2751941d8a78c10345c31376de5925941ae0451dc550428bc4552ef4af27896ad5f2682fb62ffb77738b2ec8b3f18a64d21e3b4977c600a9fe6302b6d730944dba0cfb3999d6b0b2d4abd26be7a9aed93b121b3a9bb40b2ae29fa3a742ea266fa38807169ac67c2174290494040359e8c433cb0876621b362338cf02e99808e526da4732894cd761bd7734d7dba57d10e664201565e3f8ba7b6b5cda4a796cf4bf57289deee2f192c3f27dfe427778eed2612617ac9fb8f05a6855859a93169f02df74b8285342dd0ef33cb5d86f7902aea861eb7c7f5e425c5e472c7b0015ccb9700d9b3f908b1708574d2bc6c41b9260de322708ab7c6ddbc2f6e378e674b17f9db315d3624ed519d45f2f2a042577623d142af6c5026496a23a9cd6a530e76f9245395c93b981cc941eaf7d513b65cd89d8645ed7fccdeb964b963c0451eda94bb8efb0c197a814d26cc407cf813d0a4c68930fb420cc7eb312539836e53b26e61638ba901d0916890bc2a1c2cd65173415a6b868758738614dc2cff783383fcc4c3c46da6b0be13f", "a39f2f7d04b6ce6029c3f8ea020a5a810d69634a1119355225e627d2e2d2eaddfae69506ba9bd5a8a129d2dd3b38559c17d3879fb004e0386d5d7ac1ed80875fc27d55a801ea1b371e4ebd1e9e25f4501da3e6ff0d339d53a18cc7d57b6cc3e0a854a6b472c53d3feaccd3ba2c55192f9ba8f1a57ff72e67ffa8e57f69e79eb43f4814c2aaad334db022f0b574951a14e26ba45a72fd434fc112b981425a6bccda08a6af8db6e86306317ab7c7a17db9653d47a6a280bf603059482926745c4561ef362297fa919039b21d816bcb4bbd3896d20e204ecd2b9b793f7cd8b990dc6c1e040e32b85ac48e99c5b731ada6bb3ed61ee47c340084eae60e56b1f2102b9c957c5782e846f4619d1e6afee15b89913cdb3e578b05c51b5dbd5b0b716c6f54af182f76bdf9bb23091ccb569fbb013f94cfdfdaf7849cb32bca9118a67d77afc131bd48da084ea8aea97bfb2c30d473499cf961927aca78150f5d0401384004a2862ce7fd7160e20014e7f6d3208b343808c7651cb4f722a1332999704a02051aca0358f1debc84dea084fc77f470d0134f0493c79eee4747f2c9fd9c5f5892fce7fcee3ff119967128f17c674c64cd03e71b68c9ac431bdfb1f9be66c6c5b2f92ceb53c0ee2f42e4f08c636eba0e26bc534897fa94387d51684026797d879f3bbda7a3734f67c3c57d8c321f1fda6bf62a2ef0d9f16cee9abc39ade8783ee2f26cbcce549f6e03bdfb245a4da4bdce12cbbf98a94a1dac6a4fbece2d65c32862c330b0ba746808555506862ada3805c7be5fec3c64cab4026464e1dc2d6748fb14ee2e87d56d596e72493095015b9efa212180ca0f2e7b83867405a71a51e5b258dbf0c41e043cb5f1582464944b3923b9c16d6a587253d02210f1edfc9871af6fe61959790a0d6d9c09a34e41a0a93637ab84c68e7568a446441f1c8509907bac6886a78f3dd47616889765a1a5cd048043dcc25866d6d8f39184483a9c4c84d83c10e8aaf9f34dfa6e445b992a7e359fd000eb0ac6c1501a73f6f95e689da7ff04af6acd2b800cdc4dddb5ba7d5971961ba8b01191d99d6f86f47c53ae1f70eac76fe5090651c3124a22f4dd52a35810e2d60bc65ff59cc9205d465c9cbdc63656fa2f8827cf79b0f2c65c4dd982c13da284af64215cb346979dd599f80affc0272dff1107ede29e59345a75eacd6d476292e7517d860bc77d8f67b02d809e42116acd979ee153d87ae1af9e6f3cceaea0c9011fa048cc74235cbd823cc9fa22b4af1b02b5694974d344a469eebacc459594a90f53077dfe12c2047739abc5244d73bbb3ff5af85ab7c9576378b508aa8d786ce1464e739f08d0e6b5482d826ba870d4adc5a4beeafa18be4ff9957fdb8cf342793049b8f31c7f9b63fbeff1b7e647b35661bdaecd892a56f0df244c09e879d8517249e203a60928084", .Okay}, + {.Sqr, "d87d05183e691566cff7a7d688988db1a0a2642d1d8a05f74729b70a7eb6e6113f3a95cbd8945ec8bfd4036f7e1fddc09a12688918f624dbe50ee0449a774ad9865aa8d51d2ec8bac8a59c8f9e39c66c0b4fc30ce0d4e64818bb34f795414e64b90523c22bbbabde65c5f61119aa46f26c4bec3c8c488972630522f3bf20af4c0ba002ba753b55dd90b6dde5976f1ec23e77b007f5f1569365d144e6d1f889da7f421ea001e2be6f7e9fff12a4e612719c00ca83f4445a644f2a04f92c385c2ae29857a850eee44d63db773758725e9e23aeee830ef3b478c868d4d4ed54b493eba220cc6d263a7814dd0f5be7237c37f78fa2a7e3e034a65bff4c208f89da21139b3af8afeeac4376f4569241dfe6266d591975116ab3c4e3d87058c4b3463e2f99f4b8d4b86020bfe17d208e738cef66be297e7d41092978fa74124f810784faae6beae29ca89f50cb004401e934c3e6573762d7531a29346887663a7262f42e1198e098909c39e80cefa8d55e7fc72b819575018fdbe5568e4ac616d69175bbdc34e9475fbdcbb65ffe13316eb72638ee91fdc5c43b7df705c9ac8583ca921c49719cfc0ed0998fb935fd1ea18aee43c6ebfd49e387d1fb9d9856c358e3b4e3ed00cf9c45fd6318ef71484a41b5088b04b62ce8fb2f54e6478d2115df0c228909c1caa80a7a15d473c149869393ba610b61832a1d694983519f7261fb90ae", "65c0781dc493deb9aa042ecb68adb8c440531cab6ea2f08255c671ddb3a12329ab834d27b8b2fe832c141697d64de8cf25f1d97dfbb7220faa3c09c6397104379239e265b5def5d86d8286fe0d2f7d1c34c069eb621f13f45c025a75c85cf20f294afb2f5622b1bf0dd98581e4f9ecda65946431b8949d66af3404500178d31ff12d84ef45ffa01a9feec49730d35f7dbd76770dd2a4f018100bd6f096c1a306217542e948df571f641efca6a1ed6db928de3ea9e0297122e77b2d18f7c2f2ef6e34209e748d19e0b412f732fc9817ef7eafee8e68d9506d327427fca61a656acda052b36e7ce6b432e9fe68568fecc18e6e586620e990b9f6a689a567a67edbd609da572ffe03f90c1ea39c0fb0bcc775178e4d3ce270fd5ae2d87475091545bc057b3abe6a8382ebb2e2446097c847f6e46d11a357740367fa658b53e8686bbaa7b03adc24d53ee30d34cd835a7464baa38c54595297d4479fbb37528e6be48e8f019bf14601de0e1a5eaeda52de23e7e6d39b87d07ac15a5c5f258aaa856269d4286f1f2584dd89e19b5aa62c3a3caf2ed1970b81f84b68fa9c3c046c56fec3dfc485cd8a3f671956db3a0aa69193f57ab4bbbaa095dcea599da454efe97bb273871146ffd85f6cdb77074d538e8472e0a4a0809d2d188f74fc996faf35cf41d9cd7ee83e57c40eecf971c7b40bb676f7cc38a19c0de6f0b8ab24e0ad3486", "b71335a6e3183b78431a1bfaf5dd43824ca7bd5cd184afa1162ea90c486404cda389427e1b4903a46b107dd39a2e833484abf13afb7d4ee8525e1f7eb3275f5fe6baaa1eb690c81d06cfde719629de083a193fb3aa5185691da5340ef5a04404b75bb3539d65510e3ac690fd6284f0a8d9459bf3d779ff065889981a6bc143b39417e1425b07609b5a6e8d37b81bb47fb2ecd58f0258a26a5b78c84856e702554869ecad08a31b53f3d3d684886728afee193a45207dd2d557738a86bba413ff2da672cecac6b15b3a0da6cb1edb4b7af171be768b255b37c60f2943c03d135b1639ea10f74f633a8167cf3f627fc68c7e46950a4ee86887e57523a732df15b8ecdacb9cb22c0d4493bc18e87cd0c2e5e8379ea3e786d6d18957774de174f2f20c13d2ba51cf48d3b7154d234b300980bd20e0b105a63e3d1c31c676640d8a2ce607eebf5e436ab6a8db7c67c28643cab12bf1295f76097c71289251f6016a9b3898900857397f6d005ee3a80822c5e852aa16fb8fa4d5bf99bf7fa49f954685943190e7352d6cd79b883ec26017367eb2838dd734924fb0690d135a81e10f4ed951710ba24d83d8c35804ca2f574d8546b5d2bc31e277c239a73863759d956b85b5a8a5c71255a2bd091a9ed088f9ad21c9844d073e71fec2d346e9824342c19f79bc69e6cfb0169d1350d648d435e858ed9216e789199f0388bf1b3c49c1820157db291fbdbe5455fc15a20755cb2045d1ee9a8b9b5d324adf7d2e678629fe827394661f766550b30206476c9e19ece46e258995183adbe445e0bebc6bfd84678b611352554bd438a04a13db14c2317a372c60f56e49a53cbac73828521fc96f6c94a28b4ba7668d4c43a08605b4e85688c7ff2bbf5f228f5144bab84075ab80ece573879f4e109e048b3b58907914e9c6717721f6332c3c99ec1438a00353e063d97009ce9319fd9f1e1fa9eb8228321c467930dce2f5be3099f591683e43033abb7d143538e642d5667fcd0416b884d32357ec555ec01947ae8c9475cb40ab1a68c57440faf34ce9022bc01c68de1d65074ab426be973884e90cee77a38b92ecda61a3ec8d7914ced27644a5bfee610b75e8fa717be512a1a204417573cb15f2a044163d9f098eeb8afad89e732b334ae2270c0469fb9f3c9a1c27095f43ca0dbf247b79d191c45f1e279cda89babe19464aa9855fdf348a4d8aaec06001c0819daec143ad582e35ed4ba02467afd351d70032d651780e2791a723ff0f699fb0385b17e30033ea3d7675ab91a3eeb9807a141d854af41668be9e97368650f5be000d7b9a21d2a0b22004deb9efecc63b7101afa0a398776c1741426cb994501d8a8cfd1112387c602525d41a74ac3a0afcee640921d1c3c8ab1346f2954a8564df01f6a9eae3f64214dd6108e90ffad4135d778bff51896199d0e2f83644", .Okay}, + {.Sqr, "967634f9605d6948e24b65d1e1dc186d163781cd52c19f4172d5f350ad824bb6c204fd3375b1682058218cce595eedeb7ddbb356edc75f78fcce4dde51427be686584be1719c8d7965ae98ae057e33e74bc200d8d0cec5934f7c89077c33d63e3695e52f6a268d2ccf473992297767a4788e26c8cdc365c1a59eaaa9daa35dd0ab32deb08fd2ba72f004940a1b96b7d4b97f0fc117c7fcee7e2eb4254fb3bc95a91ee1c481e9bb521ec71c97ff2320f8ba030373c52cd1deff469ac5c9b71a2a27e2aa45ed439c32858ca8ee911f0f180b8fe6cba376235fbb51029ba66c0d920286fc2fd07cb98059e6ec715a1900bf47197eec28393a6124ed90c6254d769a7330ea234155a8843688110e5bd825bcf70e087b333e1e8c6fee1d953c86d39e4e6cf8f99aeeab99da06e1739bd40d443edf6ef70612d5d7ddd499ff4fe22480ceebc8d267428fbb490eb8661ddbc4ed8e96648d9c9901cf5b4d1b35b7a1a8250eb1d6b9c8604065a5b71d715442e29f4f846d352e14c09b9bfe1ae84f957c794882dc43b7fe8e558d5f898b8610654675500afef4790a5828436af225831b2f562b06eb8146b057ef9f82e284e586e07a9eb0b7f56ed66f918b895aa25678c68573fdc3871a97ce663d4bb2b5abb35c99616a66c2d22bbaa331b929ef5ddc0e6eb915a01c4dad073923e87914816631aa9e401898a2972d2f29d2932de1f2ef", "43abf9c2ec1cda62c60088d3b67d136ea5c54d58ec873352e805adec575bc92b94754daf19fafdc4b80a0431b05b361ece34866d09bdaa44ab8a0be1f7e57a8d68fa1fb4612c0bf6bea06d9ac2c1807413f45c78b65ec29e1d687751f7cfb589b459601cd889c8aaf27179fb94543c2f8176ee9b457b931c235281a12e2c497f292d556b73a7766990afd859ae402c5da913e2ef098d48c84868f66f29b10d840fba60784580d6acbecf28414a3778189dde03cfc7aa9a5f66d38a160dc45a27eaa5ab12d0b02b5feb280d5accf08196f558bf1ff936aebf60fffac26dfb9f1871ea65c70fcf5b084bd414e768704d785e4863e4ea21477db8a0fce23fe74493ad288dd4ec008e2de55705176371f703f8653b6838bcd130051dd05644f01ba10c837cd98367794060079d705c21b6ddcfabb2309b18f33ed1462083b6d71abd1b23495eb44a72eec10b1873a0ec65f22ac85b0c0cdb33c763af2a9790542670dbd0b66c578c3df0e7af49cf7b77fb6f1c1f9f7641837d5f2f5565a7f23134ccddd417370f13992719c118410d906b1bd3aba94cab18c0a9c20d3b18f2e31dae15b6f565df56c3671455e8000217879b2ae61a2f42c5611426142d7d8d33aded05146d14aa62a575ef051d5bff95dc6f2dbdb958c3048540f596be20db32469e8b2592a84df03870ddeb8834b080ca31e7aa2541b58accdc03b715ff6e824f15", "586ebca91dc88f9105239596fe2d4f187289301096fe55cea4455f5bbc569ca2f39500b4f1f07efc3f811dab421f67caf0be3010b068d5620a20bdc0365dcf8db1e6a50548120a5af945bea6cfbe5d008738040d72cf081311db7425dcb896319f91e90df0ce72a2b9fe858969ab20ea6f586f20648103ad544863081c7e513067f5450a224c7b71db85cc22ad7a5b7a3262b2b892d198c7d42de3710c4f0be99db3401181cd4e40744acf88e6a31e7dd4ff1a0098e8b77b0901f4f1b8f2986bdb2dc5223d94bc878c574f3af7e9a643b2c5fe3079ad9045e675094eebce7e85628b8c036d56a3d0ac1257ceda198efd7d93cd75323f89da5557db64ed4479f9582362808f320cf8cdc07a06bcc6d6c2bba472ac42077b92ccc4d82bd79b8c3189e3c532f998071327f98e8fff39319e9370f9d00379037ce489f97bb32d35b82c711cc194a5ddb7ed5588f6499ac39421e3e684ed6a1b56a992bf2c588762400dc9d69ea28b415ce30abb635ea34467877c44e74aad521baa3b9fb77ce516b29d64f7c31b33f7a47b9244c3b43d89954a840c2af45268c585c6385f807da0a0b96585f90bcd7cd053f1295ac8b536341001ce75872a91405cfba26f8261894736ac4f370a637d6a729384285bd9b9727334b4fe46c36855176460cb3613cc6f9caa33a80a70b9c850c270808a76fb6c1ea6521b5b7d5baf13b86b415df5e3f59455161419afad6a0b6720e51433d90980a8bf21df7dd59e3250c7126fa73b707fed76247cc79ace8a5885fdd710141c0bc766988f51ab3e7082485376b0c8bd2e6717669a086a761b7716f1d6c340ddf945e87ae2f827068ac1763281fa2247320b7b954eeb1280107df24070483dd6483402b899fa168465f8ca19d95f52e4e8ed47b1d79a467c00e6be165b707dfd708a35e0b37a6826877302b2732d87b051f482515762edee1e69aa568941f6b123df16996466fa92b17e3dd037fb607510795ebcb1a864d66f3a891d1e32063d1c7564a9ca6cba08fc0d0b8a3a16755f8ab0592e779141caeb5bc69134bc2a32b93d9441a205162e2f53bc0d6a8884f8a98a893b4024afa6090ba8bc40ed67aea9a19c079b5bf4d9366dbf76b1634d33ffd5ef543b8ca351f7cdbdb1f64736aea102e1e007b009f336aae596233f6448c36a40cb1cd89d671a5d29fea20546d1443045c26a09ba8c0702b109661aa1668c34c830950f637e5f5a5cd759190a9e55387590a9285fe13f0cadd833e85e3d410b0c066d142d1f0ae7fc33ddfe4f28f849190a365eb67105c14b9b6db09564021d45083fa3b1fc62159125fea828ff292c3a888249ce01d631eb85783b01c86d4ae7b4b467a0b5f4631a91752ed3f7504ffbd7fddeb0be662f50d03591ab32a64298c31517e56b401074a44928f02f1b6979491fb4cf7dfed4514ef4a6bb21", .Okay}, + {.Sqr, "-3a99817b077db04b35b5d153d8ef28973f67a0e3e1e86869a06a6afb7ee8cb181c349be508e0dfb9be424e4f4ddbfd9c43b1dc21ef81c755071d65c7288d87bebebbba8a4ebd63834f18958a1b1899f2999e04e2c4b37c3f47ce65b4adee9cee80c8def5b144600a2d545486506e9de319c405f3eb6f8c93bd39f528ef84fa4b450eb357d1242cb8509b42f4061cc79366b79af05a87ed4c364620d18ad1b3a7b638c510aed5b409b180bb33af9efffb25dca8b05e327c7923504c5e59b3d7b484f2ebea58d2088582ddf4986d34a87aba881d7f0308e38fe6da406d13bf0f8190ab3b5f772138454547dc1643e19bfef3318d3318b3ff00a148e36298bcfd234baf53088343cb6d24a96776380a361b84c4b5cc2800e0552d1072b4c6bc92efa5b802730e242da3cf3fcac9b483faa20ce4bad7839f9034da2fb35d884d13a92cfe87d4f587eb13ceae60e596b00433c15975a6fa06f6d75414ad546c27218aa85f1dcd5fa5970d6820295168434658da93bcd6c9384179bd820138f8ff6a07fbbf07d472dcf3cdbd46e48f6eb70ff14b57525cf2f9125fa0663d00b3193a2546d68c2ed99ff5328b4413d4ce9ca7f9779df42a2aabf5a6ae8b66e1220a4cea6a5638a9e89ff1fcd2f2028befbd3d235750871d99134120705c24b32814da0d2c2e87e9b74626162340c76ed45c738e306173ba0ac8a58f07992db3a5caca8b", "e994101f3f1803e20045023bfdc26af3067d29986bbdde138bbff112702aec004a463ce7bde128335ff1d75d422f1fe06f5cec2bf16efc05b71842eac1ddd64d0513936388f714188adf75501daf17e5cab28344ebe229fc4827c5f5d0da2eacfaef926607c05dc7d2588443236133887d45112041af89891cd1227efa03f36319b5aa070a561954d772cc1f72432080ac99da1c761204d7ae23bf1c7c9d7fbfff6a994392256c647641bf3240fd75f523ab523f48e0ba3af25e7ad8958997fe67af3e37f3999bbab691a45026a5e49510c8f01fd6ed3043e2ce15c5acbd839adab25b3d9295966c7b7efe9ddce85866ab92de0ce9dee6bdcd405e1f28c917da6b0c0cffbc31dd8c9fac43ca7e3a90074751c8bed79f1b3e264439f1526806ad3c782ab01e66e2d98018d939634c49c9ba31f32ad557cf0776979bd5e16a5b29fbc76d71227f9c5e9c1182eb57fbac216e15ff0770c97b072f5a0c5ad99d9625c3cb4db22fcc8529e0a8727e4085adb0b35e126b2567a33dc040cdf6316b173b6b3978e43972c2ebabdf3f765210896cd8baf1d3c4bb690227e4cda8157e6ba689daec3a182aaab5d60754e95e00fe1a80c82fc50033edf2e0b21bf29ffbacee4c0c3aba991cf2a643a2d35925f5e705dd321d805cc7243cf99b109ac453cbc27cf49f1ee04ba12b6929f0a16c0a20f6501fdf2ec5097598c1653ef254a9f42e", "d69eab7c5f120cbace7e7eecdfd386a0f9dd7013126be3c1ba7fc5923634ec559e66d54e678af35882b3a3e881bbb023a4b800717cc64398e6dcbdd02153fc65cd968f6dcbbb5bc476b8af1199997fe175a8b4927ae294c3ffd73e1784e33ff76136be97f2f9414eed3ee8e6878953a6365fd40eb88a5e71f2f43179f076fb6f38e0ef7863c24655777cf6f3543844f706fc9f543758cd142c8eab798e59bd6092c7a28a9182555493322d28f011f95fd70300879406eebafb31dd1371f3a4e62eb490a755adbd70f08db8d52b7add256b619173f5df6f1631d82b67bdd366fb7dd10cef7a8fbc0a507b45d8510355a61f612fbc5e92fb444c31cad0014e670c0871b0f59d13019ff4bf9224466c7a68864d3721c44c38fde03474f874426d4ba9767ea27fa1175283493e02da70ef5fd419adb2a9d91fc1a334449bfa987f4eedb26b72b57730708e61e887e0e26b63ac6bae668eb66167fdcb76fe9be732d44bf80fc82f5bc7a837dfdf41fe06cc7279c4775101af3c3c9f21e1f3020738cc931ae26a5fbb8d03a131f63d79b94c75d3f451b077cbbc577166d64feccc07b004f4d4f58ff9619f349d37439b04a24b8f21c9fa4637c30ff7152c8e754b87c03782153c68e6a6dfacf34701a088e574727d48bb3e0fd42a2377574be1eed7f15b32e8b9bc9688d5e033a1d6b91972439eeb3ca65891fbf8c371d3b77d5f7820a80845dafca99cc2f75a237b7255180a0e4c3e575797b7315f550cc649c9364525e11df19afa69cea895b9efa8825bb4957fdeb7bd59783c33d2c496fbd7d36f058cb0233bb58e3fa5444a2e0bd1ae057843d74a9dd1007093ca0d89b53eeeb48eddca9e3edc59bd46a987046971956fd8a3f5213985016599528973c40a28b052a96779b8cc9b7d7eb4bb7707e54c30a257134326a7ace2294116e860ab40eb404f15c383e9bd7746451fe4e71b2ce9d66f6940760d87095cdaf88cfd34c1b2c556c18f07735ce87610466f113a81f4556b968d57527a71a6d1e17ffd9f95bd30c3da881ca2e8be7a45beb696be5c782cc69b4d62531f45b369fe76b04d7b3b7f25075a2e6422c3f12bfcb5b7f09d04577fcb52e9ac4a4f2e5cc5626b13f567e0f8d0df1be215648a61ff1a46aa1f1baae3742ee68df5cb5a417a171120665a2380bfeffac6d6cd902bdb8b7edd689dc75a6faa3a1acda850ec5984defd051b157f3f80b7a39a69d4a0a5afef892a1d029ec2f713c07aba0e924c36d0b2b05b3932dfa7deda4b8e9b77b092f2b60954fa1b5af581ddf35430edbc405bc647a974d8dfbba9449791fd1e3ccf40fa25a77bdf75633849c58f2ac1f70d020268b148941db8f59439ea25171cff6690911c821dad5387e43d307742943e4b382d6881bb267a0ea6b20835fdf00dbf49a751de8773d72cb5f1e4451261d719ba779", .Okay}, + {.Sqr, "-a3459157c24358a2b1c25a12cb6a71abb7a0096e9a37229a6399e690d8a591b12b32dd70274cafc62903003e3145b82401cffb2e6603fa22bbe50b499b7893007ddc8610e6071d195709bf9a561215920a1056b9d01dc0f3cff787111963e82b41f0058fdce7fc911e28a8896d96911aca82c71b361e8244e287b8a467d9e845147c4c14b5dac0a993b1a6497d12e4594e0c90366d4e6b2074f19bed0a2e68a22c6bab3e34eaef01686ef03b03e4c005ee67056dc9d263d2a9cd57a31547a59b1f04bf848ac66daa091286c2ec1d61cbadb5ecda5a15e92c86d79a6c0be39e1de2d1db6a3d442cc7793fb1f17225964e93290ec194ea597094774c782e7025283d5a0bfeaf2f484f045c1c24e58f80e34bfdfc20eec61bc9e69329d7ed8a6baa680d64702c16bdfc53b3c8c196be5f9c705c2971d5f28f044d6ca674dc39361dba693ea59b25de77515f891da39a495ddc58ee3f9c1306f49db582a01ea327ee136e343c94ca0875533f0cad159244afa157412e301195a2ab25b2a6a0e40190e4ed56b82095c7455aab9c546875fa9700edb98977312cb874f2a4f720602f46fcc7571f89027b3980e35a939a7daa92c64c56e01dd63c84ae9652f248b498dfb0cbf51f9f85c963b4e46d5f75748d84ab3e6ed6d009b592b0b3897ae0fc9b0bc9188cf3a25108a7f62e001eb627694c78e72fd8be83b4becae9d69ff9ebe8bb", "b2e4ef014ccafe81fb2408459fb4d37308b1d8b429f77d8749611612ebb28b8ec1e40bc1e5efb86cbd36c4ad61f9c4e27f9a6188b2b72994c6cbcd5a9358ec1080232baea05d2a22f6074adfa2026662641ce24a6e32ca36e3fd53bd28635cdbf0344fac798415196e4761ba988277a03bb672f3a0c1d97a06a45367f3ca9779dd3033e9939ecbfb7bf5ab0ccfae71a9fe9835bccadc427bf385faf5f50849b90983d4d546875332b7c6e674f4dae600103c4979655f8bc3c4a0486e4f278c5a245998d0b364c260d4ca617f80696c5fe67dbf8b79637f1027a067b49382a0476cc1e1523f0470f50d646222d4e1908ae455546533875d5f09abafd5ebda9ae312e7d0927f522a510da4364c613de8e41c2d86b4cabefc07520b7ec4475a13d348527be0acfe1e20b7d5f5d9165ecd906cb1f92c9bda8f253f272f5f5679398ca115c305e699a0463f7790416ef692a7e1106fb9a63bcc4af0001321a50a625d66f623464e599aef48366dddabbf6758c178a713579348b2013bac6d1fff719414ad9d5a32b70c65e86bff1206ada305b7ebe4214a94a7232de1a1c877b25a3ca97acd0582c942c1c4f384bf4bd7292da1285e462b8bcef1909dcceb0c935caf918ceeeb3f6256030dfbce9a0e985290934cdad619bc7b9c9c83e660f254f14014ac9cfb307ecfd9ba9f5d7b4b4bd83eb697110f758e8e90c0bc3b7614bae5fc", "6821a9fd6d350352ddaa0179929195317efd9ebf0bfc5a375818ab0a3903bcb6c3604c4e0fd183833bf04d4e84b2f1fb1cc4999c870750b1fbc4a8a087b9625b37bf6fceab5fea4a039a31500988e161c949df7ae3989a5289af59b44fc4aeb60d5ebcd04909a48011c7cca7021a96af5d6d981b0b13684e26a1ca43af9d556fb84cd0e36ab771de7c6181cae15f0d08b76a5135343c6fd9700da94a3101cd2558f4fa0e23a7b9959eaca22fa97c5d8a1770aa5c59eef77131cff0b7220fd7dcd63f3e429bf036e7bf42f267382b91a1a29a4e28d7a94b8776d813e9932bd13bb400733ca489f8fb17cd27a27d2aa6f36dcba083cda42bade99400bd842c4237335acff5a55ddbb028688b90a6af45abc2c964d66994509bd3f138e69838c79a43894564d36ba6538a93bb4f0b7698d20a1fa62936ec8220eb5cb1bdeba7df0a6ec4ab8f6600a38bf2eb5948e47d0879bc3be4ffbb4ec6d15ba5888dd49de7d1446ca687040f36cfee4b7e9399cdb1c8a744e2432699d93e3cfcc8001eeacae64d7eea8b2e861a17816cee3a870225fad2bcd9ea532207390ff34b4a3739b14440799ab341ed79da82135cbcf8fc5bb37b35458b0f5216c096526a807120fde791fb3688754a172060197bd55e5cf750b2c22f63199c1175faad6c9e815eb8c76880c7a8b79b8ad142b981b2e774540b415671c765a247bdd7a206796c39cc23dbcc4d86f6061f6841cc9e575fc3e3f02ee8976c7c99fa8134eb2a6154ed0b1c6588879f8f128f9909ce2085fd4eaa278d349425ef683f62ebcd92223549f7af7d67c16645fddb32cec7d5b388bed8716649d3c81edb9698af2775a74a593c78f5ad20522f3257492de141d451ad39232db5b850882ede66bca544bdeb3ca862daa12e530f14808741b5eb84795e079d991dc57055f73e8e055d005007e50b4beb29332c432c2e75d7407796c52fe9f1c1e651fa87c590764ddecc9c5bc56668a27df138966bc1befd6a9dea35859732af3b6874486f3277ac625ad11705fca3c0c17e58804e10517ef3b8151da790ffa01eb406999ee294c67d519f00e1fb7b73ccd4d508aceec6d9b5a31609cec88a97eda4c15e426f1ec1fc4eba0114dbc841cb1913ce0d446a4321268c03e4dc8f731cb32b849a4d9c8942d018b6ad90f97f65484974c2b85275a0292c06fb71ab4dd0411be2ccf23f7ac5943246cb28775760090cc03613e663a8b7259b78b4b2388fcbde33139e233d6749149f351d5f0a446e4b59354015e3d0ad027461212d2db559f7bdf1dcace36c83e3d75622df8535a28ff1cf2647e5bbba99034d01bf3e5c41219f953b2afb2a26b70cd218fb1c5d7877f395793c99a21c8ab5e6e2357438916c97bfc006697bcae7bccc76081d76de26ff1b92483a730a5bfc745421777cc3ad566382179086806ae0e57899", .Okay}, + {.Sqr, "fe67a9f3cece862f8374450bc2434253f159b6568dca0947ea28fb96687a0c5b5a179208c151e3144f94da6b6118bd734be8b9c8ea9b119cc8ac1cffdadd4e7e32aa7801677d26ac91f657a93981b48f36da5966f909a59baf3e82e56383e0c7581bb9f75583fe83874f4b0b87399863a15b516a653961c48f3d9da465725f3b87f7a5482eb85d3d10eecb2c71ca8ebec7d4a3ef32483a07937bcfeb0129ea6fae719baf31aa29d459ef24ca4d8aff6d044d2311514a26139cca9215eeb618afd65dde8a6c548c635733f284203e7676494d70617ee621dee2577af661c8cb56f96d8dfd72e359be28d1fb21b617c65c60a22d86914f8b973cecfa4034b488f46a4a2e4a67a73066769aee7b9078f316a1fb28ef8fffbff42c7f5bb0ab5e48311a152f8bfa9a673bb5626289be1833961feae24150d3edab79332e0e6151201f1f1eaeca5133eaccdd9160b81411042edb931b95cc630d7172f8dad5a3d7576179f3d71bd7fcd9b60cf1fa67d8f5235b55105a6e46c80cd7ab5af455b7bd9b629d4a27cdcbfb2571f0dd4711f8f1309a9391c6be4844ac618f09d058c9ac1d71339c4077e738d7b33e9d34ab9f3725ac20cb473d407a9794452e0f135aa455c48b2f25e908256a8459880e767928f8855dc8ca151d1bea1a174aaa695654f515c24522b93f9a6f1ecd13f908df755ee4642c588a52ff93157fcc55f584fa2b3c", "250e1e7b4c5363f431e1cacbdc3553b0964b91114d91d2eb0d780951ff392fed57900b3c0509fcf3ac09e086896732eb1eb382d0d0e50086260735a4b80e879f8eb25e9b95794d27b20b15cd17851a72dc5d2d2b09edca43154445d111dd6cf408b8d377a7a8f573f7524c06cc5b24281d276b0ded6d05e1cb4ae1cdab969fa0e086e85d5f9e096f70cf5f9c3b5b4f7f46f610a8ca19309ff7fe03b9488e87d32da912ef173ff1b2409f278764091ca1f6b2025999b6fe0d4b89fc5901f8f4c3ad69b47337737ebdb8affe047dcbdb815851e1dc15becab3955f478238dad9ef716315632b05cf06538c1447e674714bb2c446383099ff65644d9d5f606724030d8fe9d7e933e0e363585ae5e5ae409b5a8c1d5725056f89b0c2e15111f90dbf6a05f4a060892495d994fd5480db1db1184ede238d21bc8ff051da54102abc6ffce8152576459c38ccb01c0c4dd1a7376cc64722495ae2c0d51bf510c65263a33f1d808a7678f7f6fcb92fb4a89eaa6fdea72b4ae2ca297dfad34e46e1062f15e9ebf322a0f0fdcbb19230d20e43563c642b4565035dbe21cdf8ebb603fa653982d23791cd84aa0bbd0e6a43701f9754f5f5e586ba26bff470e5b585cc64bbc5dece89a58ec951fc384d25520e2dfe5b6c72bc0f74c43c847a84c853be44e7e34ee2b729658a61b0430d154517967396d9894f22f8ae32ad6485a8238e5e2439", "fcd1df3a01660bb5336500e6a934d93ad7c7bc2f61d0b5edefaeb9a5bf4b425cee0ec8df73b630a3ce281c0c3f565ae6e224869d00e507950cee11385581a0267339d2519b750327de3bab49609cfa56bb8fc92694c3857628a79c44d8193ab03e64c9e10953df61723dd1dafa4dbf4c71152b1a15d0c971dd59f7ba7f9193b93adea56ce8cf3b0aaa391889bb35b0134c09ba31df0b418d46f8dee313adaca2aa73fab7bc91c04dac1097b16daa8d2cdb2c6ad39240ea523d40cc2605afd76eca6d305b5f18674fb12e141f4ed54fef277baa523c221f457a467efaf684c877612408c2b7495cc5c1d2db371813e2072ba5f2e65fb6b73a2f0e35f18dae3cc1775d552fc6972a37d32db5905a65a2f219c62bbf9c2758277c4e3a386b38f415f4bd44a8851a9cac58d57f77d3fa4973d88572cf2b5407f1067f751034a0621520ab4def6207867bc6e95e20fb0220f73a3253f81fbf3182750c2ad3b28129b33b47ad1d0b22b3806aec80482eac8f6586641308a18bd3f39b84a9710476840f9f5ae92ea585b931333282e969352ea7d416ae8b1562f747173e0ddb14fdd4bef6bc6fd96765569c5b28ff96b4fe73e016af55c25cf622328e8ce604ad09567b1f4e75c08f7aafafc7f70c116758a58cc0debe50c26b6304e819bffdb29e7a5a3323f1f59433c526301faa76ee0bc245596f899d705eb05ee69974102ff05b53964673edb5cd2d66b59e3ede5c361137c12a6777d8f579bfd32d3d1786fb26f0e65b1b0dfe1b6c97721691c4345b22fa2115c1cbb67e142b9459e7a2811dfe5fdd27f96e3440174b7b4572a8d54d2cbc28a1c0233624adef24510656c6de038eccdec41effd155cc2478ffb2f322685a0d0fe3a7fe6c5e7400173c55f74366282f56c63b222c8756a41bb1c71beb1b74a96eba231e8c2715bd4178a75e6ea7e1da61352d0c68cc535cf93e0d7d8bd80087de4bf5216129fbd2748e0015fb5a56e8c47f1f01f6af40ca9e765baa05ffa31e71098b4287bb62532b38ea991cf44e3895c87706128c318369da36c647336b94059d06a32569a6cb074252f65c344b9304b9eeb218e58623f5478c02185cf79c6bdc9ba839eabbd5e8e66f58a16e06e0c8ea6fe49815075cff14a3aabe970f67e20806630ed3ed0372c33900291dc5f7dcc24fdcecc35879b4089d27473359a210aab00537422d8b3f0c3047592da3eed30da41504fb67263c2fb28074b532dc316dc0c8d3828dcbf76ecf4fcd805ff9676544f678894fb3a627d6af8039fc664c9ad33b4e8aadcd25aae6ac19fa8b25c98d2f8f6e27910c7bc9a449855d4c6b1e5b083298851fcb3f39283779be2ba0bd8ac7eb54fa1603f1540fcdcc247544a2c968a8e030fbbd5995a2625f4821fee2efd92a49b9b624a3e08a6118e57c82697c2666531b385c3f89e6587d3610", .Okay}, + {.Sqr, "-924d3271bc6298b28caa7e08adaed689c8190341ce887c80d2cc3c57a6f834c96fc9c38c2056fd170cdae1957efa71794453adfcdb0f45b61ebf5f3218c10b3e94261ddeb4818620580abb83cbff8f500144697c6a09098f72395831043f34035dd9b37f0b8617aa072eb414c602a6ea087ef63809ff8d973ed3c94b94ca1b301a2e9006dd4b3ade31b92fc5327baf641aa64b31431701b90cbceaa91c2fbefd81e1e87b0bb8b0b0d09084fb223cb9ff4adb091af6e9e4a3f2c795b4ea8a242bd1630836ddc952082368c51e63a00ba503dd0d67c5075fd745df6fa8fa0f19e21a2d2550c3f2f9b1999f2d0ece56f468e090f3c86621774232d8301b8df803025657066edf78afb10ee76c877d9d06fbcba610205f05aa6f21311b072634bd32afe50cb9de9e76bc331749069bdcbd5e3abbfb7e544bc0fdb8bf052d055126e05f291197e5e566867c6e97723235a2ea9e7a5c033ba0c6622c6b3eed4e7f9061761917ced2607c33c32481bdd65a5cbcb0420f48fdb255103499cf375950c7d16cc6e870cfc7b8e18c5901b5799ec7aba564c03e2880d85abd044fdf020dae3e9d8de8650dffbfed688a60828050b245aa0610d59d4100a7b9349d035657b1b6dd20840809a2aeb814ba0469bfa6a112b3c10ea12dbe00f07294dc4ab569151a7b8c3d1e625a6d001fea9e8a9108f9d9d2a62dd90e1cf6db13af43f5d7f5d2bd", "176e809c1211acd20a624428684a8bb289604a855ec3cfca3b86df6488b0748ced77e9297f4bb4b930b6cf0466a8144c17a63e83d3546327b31569ce321c18e2626f75e27f1bd80d824521e5f750709296908e204750cc4ee7c8a0afdcc2ad1b0b24437c5af826133a34e89f0c724b9d23d87c022215a96d99df07f98a878d06db94c798888548b96b98b322dc263eae45dab843302e0348a8ec525a96b3e235fbbc020cab5b921a8fb53dbba575f242900af28f3fbd1f2fe00ab88d4a670255272b388eb9fd45d9620f8fadeca8b72e94f4690b940167ce7d1453cc62b19ad60e6e76c9e2659d74ddd76b5820d62c302682285dcba9a6ebcdbb7952dde8489fead19882a7eb1689a6220598d37f5b5333b645562c6f98a31e636192876f71a8b5d4443db65bda8fe53a9606593ecfbaec3c9b52d02c8da8364fc797b703f515f41f4225490aa11bdd8b3dec7a7d9e91a1ec84ed021f9dd3434a6dfca743f5f00f315d1b7cb785489a5076fd634b4764f8b22b660d4ffcfb5671dac6497fa3949ace3e9e95ea54a619e0a83b37ca8833d533289c633ba83815173d87bfdc26f879395c8a5dbff8bac9c6e23107d5c5b4d08df4e3fdf4de8c4c890aab0e333e559df994e115a4fe00633069d69d0197582539b5b9bd69b9054dca24cc3b1eea74e07108ed112fd2bd05b70b11fd6f593a8131a4e25c73d683e3c3c2f44ddbd004", "539c24d11d3c6999e12c992401752e9b7510613c5556d829a53d2f9ff689908cf866d38779034d93beb977cfa761466df140e9660a39e82e86ac97f490b730ca15a9e91004823bb78f9656ef70247c19c92131ad0eb9070658e6dfa443a796551807dd44f6235d544ddda6256c28773c699434ab320e1be285af62517793fcae3dcad6ad70a90e5b6b45cac639a158a0b18b0adece2dd8eeabf001034d66ab0377ea58e783d79c33a7c97bf101f8d1e2cebf43237b12fa346cbde89b32e68a48957058fba9e74c947f4a75232822009d4e158d4475ae325f60246fc8de3bd145c12227641e4de2e5f3a8235d6e23101a14813894c22c27a53acb8ac9f3ef95490415410a75ad46db5d8d02ce4874b6c97d93ad75cecf20052c805c8e6fd6e5fcb9c7b5a6fc275853bcc8dab95d0fc4010cc7b9927cedb2f9e90ab96abc09a81c7a89c35cfb86ed9e0347dc709393ad165ee696a55fb6807e70724d54da33386fa95141937e0ff676f135d3a9d4a45ccc21fe03d47462c48e0ae33800ec5c5c8252941cb622a2524bdd5e12bc28ceac3c051d4a15f7b049c8da4a8506d76d458ba657cefe5b4d517ee943972600e558407125a292922b5335eacfee85e9f052d9495ac7d572204c8ccc818d844ea71dba0c4f830458c1113faeb382e69a850c27671fb93f3fc633f57aa4fe439c0470bac65c9162503a98f209fd70be4134c0285fe0840bf5cb23813c46f60389bad4d5660c04886fd7017b6a2cb5a0645b14530c176b2a1fd5855d3cf78fc6da290d9a05fa7c49c97895b77b32f5d1bc4d2bbf4e18c3617c4219071c534e4a9177f3146537ed13798fa35f5109c5ca4363cb6eaf5133e87a16543b18516b7b396590206a136eaa7b2ebe1782c5356fbf6992db2fff1695da917a74b17d2522863d8dde46c14631396e90b011bb08be037d2ea83ba2d777a849606ab0a57fc8551a9cfa35555e443910cc3351d7b09fd720702fb113e8ca9682e0829b8896de136af322ba4768b50466d54e1b138cee98254e8113eebeb2d3bca28b740211cc206eb79154507fa597ec21f56dc64706dad9e67aeb112e900ef2f8e9fd068d2dcc53ec9a68370a38218883a4c7d505755f32c25e9720cbdbebdfa9b4aedc2ca9249d465033f4796ba9a5ba3f49b46b49714477c8c0ce511041222f00d8e66f0b7966c67526594457456bacb58a1214ee33a3f14d71f85a3a55c21644be81f6a30484f540fccccabf50c154816665ed4154bedf60d83c71b30321d901a5c0270cf1dc00866edb50e2f5cb474b90a8ad45e41e96bdf0082d4747505ee18b834529a50f576f02c66c79daee8a0744ede3cc4083a71bc5a1ccccfe99317e645b1b7365ee67ae1b25ae5965b69dfa558f7a80f0d0f5f141d895b907184f410917b224f2c932bf335614fd2f2825ddeb691fc8813c9f89", .Okay}, + {.Sqr, "-3e6eee3e5d0030a767fc8ddc76ddad053cc4cf7cb458c899fbbc660b31ced2ffb835cbaf3235d8c8b73644398fbea7543fd74bd4fbe030b84d2f1cac1ee5fe6383219a581bd8729fea329de3fdcfda8027fd7f3c37ca7ac79b0050895be90610f388708ff055a94cc2dc7d7acdd5bdfb4526f63f2448991b575a83d2c4aeed7577e3e33ff84afcd76d597ad6c360d9610f0fdf69e1251acdaa67d6ef9af9ee7675c25f7d5d52a7a9c78dcfee3b7652e6d5b1ec457edbde25ecf9f6076ecc8859c0d4165f83d13d1c4ee025d863b685446da7b0502c4fe7c6c9f179eda478c3857747c3d0263e2cacd1bfd3419120820abdb928d8d6e96a532db2129471a34954e2b14b9ef373af6c174780e791cc4c90c0b758abef7c6a118f3495ee36e9a351d4a8ba94ce096ee0c74ef0525e702a43d271a3141ed57be0808a023cecc062ad754fb0bfabbdd9c0a484108948fbb8d18b3158139c6e999926380103b3530c74bccc3f76f4da4811e0011461f387c5b4da6fde68b23e9516dc030bab1f95b4c0d00e07540bac9f1f261ff6c3b3024f48f60b0e469809c40982d37fda9869f01786d47b4d4335a4fd800e915159b1d1d9113e6d9857af2e4bc9dcfc06db46ffb28780eef21217173e6a55e9200b665f350495fccab2b20378e7b1d3de08885af0b382bdd10cf34abe978eceb348bc2f4cb212e867a5aa07e22a74cb4d19a1d25b", "b0b0523751d6926f55f69af43355170af6c0a306946a7802f76bff231c4dc1364f54bf6d73aed1ae7964dc0138723b0053b0e864a5167c4d2352c6b7e293ee99df71e2202d15338e56d08f9269c4ed32a3605900fdb21f054c86573a29af22062236e9848f59cc75c70e7882623b6a95e37dffcf96f5b3af8580989e17b9e6d231f5dd318d7c08676286ed75c04300e80a2abd067948def6577acae2773a6a6dd2e6211dfaff38460e013ae7eaea99fd7c8daa4aab4b77eeb76c5b765480636ce83bb3439f8579023d286eb3c7add34c7bc00eaf219d884dfce4f89fd9810823fdfdf9a97f168b705f4b80d4e1695d69576acb448ae59b86556f9c796321553c8efb2b0d822e9925aa5814a3a8814d5baeab9bb9f278bdca9334cdbce7462e10ffc378233cc30169108c85c877f9a855757784fe69f8233abf2991c9ff265812434fd6f82fd640da255dec67fb089148062c9d966c4013f1a4daa0c31661bed1928f39464e562e799cff4581bf310d05ff98074c55792153aede3af0334218382d0f528394703b3e8aedeb2efb84bc2e0e4a83d68ffa8883d34757f2c5b6849480cc5db09c12f14e0ba7a2fda4a54ca6791a31d0fd5b0e800f3fe08e53e72283d6d6c9aa109d9d262cbd0892165c29a36eb8e125691cbdb8c116c0e946c96a161008aa3ecca753836a52101a79f02ba32bcd87290d563312b96873bf2bf95246", "f39eb77d05c07d86e93ab8a53f0dda6b4531e651c340e06a9e14fe6ec2a7ff45927fc3fc6fd13457cd0b1922eb962abc527e2400405cba652c3b178bb2ed8bb78d0cebdbc3979ae3cf0ad3154347b63a2b671a57500d40c6cfac57893f07d6771ffa3c012a520912d892fde202cd281f6134d74d4afff5f7ffff00e2def18978d15a079ec75783a47a5c771c9d43cc121505b9d1b2a28b6da523978ac96d8db97dc4bfbe952320ce6d0280dd444ef8ba3feb445236dcf3ce5e9f54e1c70f0e2a3de22131e036987ddd58c5ed14b01b36774d1cc5f67c9ed9fa02fd03ffd80ff6c14679a368dead72391e44559aab9ba06b017b7c5cf9d7d437be627c4d22955e0de0a81f57d0f754f76cddc98803dda7dd2b20c881a64bff74bcebebd70287ae0ec31491f8e8b187932abce3895e5dd51b2b7861bfcd7942d1a11d72c2e913788a4f532d93c3859c177b58897c9cd819adc0219813cf1a82dfa3aa1bc32be27474acd0f6fef2a8315060dce7b5701f578aadd332f610d1226533599dbb6e5609286792fc2d694cdb30fd16d8de0836fc990a441a40b57ef442184df41b82df4939d79aa1cc19e56dea106a1b303364a5bd335c95adbe7774abf84468526c035f1cf5375bf953dcef0c1c42e55ea1a4ab694b7deec262a23809d762b14a89a1d49ddfedf8c8988ac8e03f7c91de45bcc18a6d011b654ed0febd405052016d6e6388a34b8abb388b0af863ca96c0c19630d0b880de2bb09b7d23f0ab19d718328477faea17e744006c9a9c7744f5dcab2ba4275bd1b1bf3f55edb2adfda1bb61357432ace636bae4dc3357c460f6ea71debed4130771ad8e2580668a317cf29ad23bd8b78493505eb029b4729109114384e02b57674d05e99c0e6fad27cc38b74ebaea2e1dd9b1473472d75ebc24669035744a88ee710a44e306c7adde0e3c626c6d149d27b488b7c57606bd10fbabacc8465014d4788de6bce6e23f1704aecd32a08ff2acd3fbdd66d66d11463111f8c6796642942b0a042e27e6b8e6dabfed604f21a122e4f182877a70253bb9360b896d9ae1ff81996e3d6e5fedaa4f1fedf8bce7601e2c2ad7932a7e8075454cf49baa5bb0d3f203dabfce5b90fcf2753cc667582c1ad5c8c4606e4e0af043bb5ac9ab3819b9fc0579b0d90fdb264d5033c5e528da9b4d6e86a14adce06083e1dbe798389589a161e4dce06b365524917b2c86f6533caa9a57d462e0308fce5ffb54823554341f7b0517c438e5cb4815778790d05b181eafb089cbbf374d4388c2e69b4d13f423597180440f1dc5178b22cc02983852d4162a38f61ade648f7811474b1edb4aac1de6f779d085dc4bf67c36dc45df1b6dc8b4778842fa2f2dc4a277f933668e099609d80e20779adc62447163937e88ab620b3949b97a075476120d4188cd4f5d014378ffdde1e094f6c59", .Okay}, + {.Sqr, "-1d198085b56df143f64ffec94d33672100970bd336e3b69d8ed2e20d34284b7ebbf8c6fb014aa9257c532eb987d54c381d36616bbb3b14a25292a9dff1913a2f7d9cffb347e08d8edc9772e1d35afb1a479db578f172aecda24c44fa1ffd1bd0af8c817f3197bec1ca4854803a222b79672bf554b72f9ced9175098234d377de509e45bd2abfbbbb1728bc78d80964fc3f02f5750b6cd4f2c697dd008fcfb178d2b885d06c64553c773c0080582636a1d9f91e57f5b7b42ed7727ee48881e2a8660d268dcd6ef462ef31508ac0bd4dbed739dc36fcb44abc2f9e4637992b2c5dd51b8b0311fb58daf36f3e83d2caa817a84da56c95a16501010f3cb6747c1db9736394280f829b002d3d6daa18ce010c0dd6c862636a8b2b9f4d74f96decbea67125fd67d5493fad555512d7eae3f2bd50c503ed7a74c9c0e598667badaa0bdade9b25875c5ca34018ae480c7b55875126de623b980f738f1756330ecde4771079b5324a0c6ab6714053476976aa48e50bc740e5fe0cad1c00959f5a277f1660d8958cad3e4e51ed419b69f2f15afe5cefd44e76e1326fea4b850cdef79d9255a8496f14282c51b5ba5725c7019021d68f821d23a07d588e37098f3616bdf98d0eb5e20f5c866e84396213da8fa5fd5b4f7061e5ca0a96ff7850cb411eb9a8f107d6a83a4a64219eb7a65800102c84d7157caf0d4c767f44e0e9c32c36d9e31c", "a845cd006b55600f84866a3c4f70cdf00bf6638b2435b77a4c679ab3914476b917a2f441c93cf219184da7185acb08fd8f5c335282ecf9636d180e03f13b710038561ee9c225845af485f837794f2e560e339bb935791ca40ad0b1addf6b44010632855e7586afd2a318e49780d5c07bc3b786d6b09bb10de766892b904182d0ad347774b44b7690b8c08770dad95b04392acd0daf79e047e4df61f7e8472c015163c6df4a0e68fc0f25c22a416e0b3ca08ebdd46402ab827e32cb5fe4ab96ad08e0e07ea00fb7df2bb79c2bde63c55f5e594ca14606fb020f36eb3e1236cd24cd0f02e4c7f6c12a14345a675e23a5821d66f314ddc4fa18427f26aae1bfbeda3506397b7940538f6ad0629e3a67c73d4476601709d25e50b7bb2a8c6e410aba783a8125856a129a2890ad952adc71fe239def5b6959623d16751ba5383e198932116871c7582966594a707822fb0197dc4ac9ceab5ae64acefb3deae13423ce7013f21e49b40b69d9270345cbaa07739f11d3b88e65d23c3fee31cc51a6f0a0bc6edcbd670d3aea77d38c3504b2b77d0d4c353e32d693c9652811ed6598430d0909c3848bf44c441dc7c0bd80d27544e9fa31d30bd6509309c91b76847ea37a16604d963a9f63c856a8be0f169ec49ef126e3d633d9f7f75eba21bb9c4852ae4239c6b47937f0b58ace8f3095c2b3f8e9b6e19635551e49598c4106c6194c7f", "34ec9a8a5be53667b2988a8be44a9fa5449240d9eaa8958f34fa44a32475996f905e74403edefd7c8d1cde01fa255f6b89cf52810e0ae3d2884f45d9ddee2e8819093f2ae7d9d2c015798a556262b1c9be677254e946df138a1d2bae091d879c228d7d8014bb42a39bf61273e325156ab98b3c0145d4a755b7d187fc1d7c7519bd0045781d5aa1480c0a2b8276431d8471b13e2c5905d599daf27dd97a998a8f10b975a9ff2c21ab19bcf1eee95c67d810b93e8494e7e5d2b4f20ceefc0ed41214cf1b04bb37d1ead2c302914c005fbecb3b719b01000faae46825beb3696cd81d09b7fa7b2971d37cdac78f862eb6022a8208316c02809af0dd6344627324bbcbd2f2942cd79c8b45c6252b290ec07a6d4043258f4c4e43e70252b691b15f3b98aa8846bd49df107fb405e267c5a8dfd381cc5798ba676ff42d68064433b8c16b5f7f5a85f5b4ebe8b4263abd8af4f2b1895aa17c20278fb8c58b7926a06aea2e32bb8c6b94eacfbce94bb24bcdcc7bbed1e0707149125aaba421ff6e52d7f43efaa8da1f184040c98ff04ff4ad09800a062999d66a61b0b4b6a0a2ae8627b03553fc3b6b989ba0b2fa78075f363ba08125a0dd6a9865311260895b6f1e1402bd3d353c0733a942ac80be1dd242dbd9e3ae3556a3f51cfd6901cdf3c71594802735713cd56054cec2a6f4752d521418afb5b65b37c569da8727ff03de3d377fd5d96526585d0ed28e8a9790c7db0b54f189cc9c37e9fe78dee815cd39f89d9ef219f12c91a1e712316b464a883f34f8a5bbdc161f563b18f903f2aa50164f51d2daeaa51c0f9dc2025d86e52dd3d0339860fd02ca6071fee589d3a7ac10392f330c8f8310ddbab65e9f3ee4db22fd0d9ece92c0e010b61367097062f816574d0e167bf1a0ea889897eefa9a589beb9f29b402c6867dda78e8b2a5658f468550342fa013faafff1244a7cb5da2f699997d1d326111b982ffdf649676134a5ea75eb6eba39ccc3bbfad5e1e888e277aac9c2da16442e134a7d11447a5fa738624254b9183a2217c7014967b7e8c2808792deefbe146656a37fe21e3abeba33fb4097bf2f70a86fbdff5e450223f7157b8e9491cfdd257b88f4140c7245a742d563ca34e19b450e4b0c1cd34f744b500f25538dd374ccc91f178e4147a96ee378771d023de63b63a50c93c4d207463acc421b1e62f0228ae5e079e174438fae0332c5cc61eec7ee9531cf3e5cf8e66acef9a6b10d1deb5e1c55b0babaa8916f63dd0b6fd57ea90b6a3a5d89ddac3f8018df5cd609d1117e52b5adb326a33cfc592f39e49ee42bf64136b4d88da2d8a4833d8a078c37f0335a69968edc7426ef608daad15ef07179edfc2fafa5a98ba1c7e0e2b68b2de4faae8f35cee0432f5bb881029307c286a2d548ecab81a2890dec7084c1798c2bf8233f9b5ee29ef2ab10", .Okay}, + {.Sqr, "-8cb4720f7a6d5829c378367bf657fae3cacebc8fccb47e3459b1bf3dd23f7fda3dd6bc517bae86f5b76f31610f5748dc58f2721aa8e42380b35b360faf453f25c1944086f95db5b9d792bac1d285cf12e32a5b1ed235b0f9c846f92435dbe9dabba0faa89b8ee69b9966ff154e7b6d76b87773f2cd048fd18ef8c35c092805d9e2cac67645388d678d150276f79b4aea3761a0535eebcad9e0689005760e73e0a223b13c8231ab3a8c86189ba81660e1d464fcd68ae3ed6164e7c275a76d422b413ddb9dbd4441ec013f40dba6df74a9d0bf561f652f87b980960dc22f9bc9f81b63aa3e73532f6b81695e70833867a95a53a014a447fa539fd1f81199f8b3b3ef6fe961aa114560f2b692f0cb074fbbc7502697459d0e12efc1362e24985d64b2a812db2c09a9342821bd90989e03a190a3525c45edce15cb0a0eccd6a4c694616aacb08ca57615868a24901e62c887753455de889448a96909c84309bf5658cd0a73c78877a70feca9310f711e6993627c6a9aa44c48da8d08949469c7a3a9c7d209d7bfcc87f6668ebc1a1017f1a07850c9fa83272e19429b721cdb82d95a18880250a973d97a336a5e0bf6d41329a2b818a1b909851d49b36d4a8554c36720457e4bf14928270287c5e64e1a38ea7d93e6c9fdf9be96728f7071eb4aba7b6fa4a08a8f737fedb68b7e9344c86906f78420e52d12439b43553c20d2187046", "f9682029b82d480223003398253884678f82e77c86f277a11405f604816d16b4dd15f412c1f526f80b7cb37e3e9e989a16103bc9a5761c57c4f04c2d5bd14ed320925be5e36fb6e4f8acc9430e3f456b011add562c9c2edacddd3e4271f9b16fb39e8712b0ee2a2e4bacf7af41c374343822c36a2a343335e159a9175be86ef0ac45ce2b68225b212db17a9c4b185c3b11244b020961e2891f3817ddd02822fc5c2a183de4faa84326236b7a25a2364c9867ef24207f377efeb520a7659aeea6bba531569cc2fe270651397d00e2de8d61b8caced12d7e06da4be99470d9459991ecb350e5671e2063db798cd7859273cb5598008c87138afe836e921e34e9dab58fe2c36a22b1385325594fcb47f7d0d6ea66cd569bb240e9f6764c463971e26080d41b469d7e863e0cb501cfb239c3f74476a3eed92fe2a24594ae2d4fc1d00aaf812e15b48778c8d10555ac3c8fcd1fe2d83c87a42f1ca72896380fa21e8224a32c998aab2294123cfbaccc6437564822cbe04afe11b3dc48aae9673b3e978296327f44758c92790a7afe4d69d02ed218ef5b3ad1907bd0904415a989e1b676397afca323e1dd4f5f075ae831ae0e4c513aba198562a104d69b856552644bb86d868f9a3bd939612c8cc8429e98465e98b6d2da6ad49cd1737913d2eff5bac7f023df689b01410a84514c8631e5c63df77ce8dbc679e6832306e3980ff874", "4d55dbf1867d8c2a9e684a5c2c9b358e937c42da7753add632a70be09e0e676eec72ed97dd6deb634970049288b2870316bb6c2f25e1e2c56606beaad3618e077e3fc8443ce7ff489c3e9e09f5ed845223f0681663554b7630a462d5dedcade0f08409c6c2e8ef3d6c9b5693a1a6482983052ac7796624d48f40925585572ce81f3b128a66dc6dcda46f5b0db73d8983897f8b640ecd59013c4fb85ef8e13f114eece54a8ecbdbbec0f09b7f81d549da3bc4d93c975935c756ecd0e462d93926e95815690019c6ed31302a32dbe4699601f706b703461d7304e3a648aef52322a500ae50ec96fefd76b732c5ed3200e026c84241623199066b27bf78c570d30cecf08044c457d3f380a0154dadce6dbe9162097f653cca6c12ef1fd3197290e35f703301ff1cd3df3cc8c423c48c429871904a5a1aae99774845f94c9a3a3f9d9614335b50043c9450e5e56cc0361f29d41258abf4e36496be14e4aab335810362d320b60d4c2609efebf976157084038534381253543f3703b6380c4e0de1d7b1f67233511f82dbc4a109239b7d485fab8a0715fb92dd3e1b8f379b70fac5de0ea88bc33cc38a075e1fb76bf7a265145cb1981c2dbf11181e978692069abe728e37a0d29bcde7fdc7cc35bac7f50f8ac7c983a6375a758a59df644834a39c6d9b94f0431f02c81b37d4f35dba0dea6b3a1844c22115007f196a526e9d7aab13f052b60b4e0c9bee7d4da7329b6acf34b92f3d0448dbe88304c5308944f96fa2862accf49349df816174d5e65c3cb69f9edcdc4d9c0e407663b1e4c4d753ca7edcca5ea18f50a91f5755be82845e0371d4f45d268a4bfb7b20489f66c65222e7c39be8dbb4aa323c76e3c7bdedde3f1ce29340cbb15b1b01fa3ec6dc381b1375fe4fa2a0d680b401145b06d770fb37cf3d81ee407669f3011623418a8ff2f90611206bc969ac4afce9bbc26fd90e891c6ef6f47bfe56b5c580921c46bb6c1be74b4b9fd176c60713029a3df6a914be638045d72d2878e7d2add9e8e4a2a8ca6e21508d508ce0e06e879689eea7ffa7d7ff471f7b02da4f76c2b8cd45e7318b96f3d1f91793425bde799439cf5f4879b62fe370539ff23495fef37e5ccbcf37609fc95805cb582e69444a84ea0a4a5d8e7770b584c5c77622133c9ff01925724cec3b2df632fc1c4f5742db0c3a53cc4fb8cbea6a02be601d076df02c43713ca2e957f738ab59f8ac157fa5e0d04c66718a8fbd4c59c1b0ee68515a544f1e9afadc3990a2c4b6925c0f4d47b54ccea5249089629eb64067a357ca96a872f66b8080a12437a1c1b70b7ef480e84b0fb13ee26671757d722070fa47c28d7ad98e50f3e20d3840ac417ff04a0ee32f4883ff0595a1e100ef97a12c93b9611c8eb8a988733090e9346fa6d05ff3b5c8c45aea0eda37b5c4184e73d9a4fc08165d5324", .Okay}, + {.Sqr, "-328f76eab9935444f4e90d778b4223506ae32cd5a0e7ee112506bbf2bbabdbc55ce2c83b49fc0be9c6e19c84925b28dc2d2d8e131a68edb78bcf6c2b0e16b5ff578940d0683008b57e2c3de10cd605411a226e4a01a0dc34e6faed131743ed295e1aaec969ecfc009a138ba3d59d0a29b6d300df1b81875b310bab2f27309ee23987e351a3efccb5893db40dacbffaabfc5933e4aa711f5ea71a1e4f109b1e9db9e6f3373b01bc33b27127dc5f42abe1d219da189c64c582674cbe106487b953ee0af5de7fc4ec620e5d1f26ae97a24e8221124c82ca04531836471e0fb0981d74391b777120231651481d45881b0720e121d70637b026798f5b337e998334b12a18616da89888cf023269b200f68d7f8777c7e9bb9c610387e21d0c4e5af1295be402c68d90cad8b69085a8a924f37fea883d7d6e7222d33be565abbf57af176d2be5fb3842d3cd1451668566d4d5f24e816fd161d02b2a6e99f5796db96fc47b50a3c1b34816fc28e065fa5e28b602e69d27bd342b2c39a435af566b0b5042e89dc35fa783916957c2aee99738d799a51c91f1a6de0a6138b5aacd3ea09c30fc635dec0b82982a2eee01d7d160b3aee4f7a0ba2a05bea06171606fa7a1cecb06961fa0f246d1fa19e34c573b4a83915536eb9b193607fab736de08b600d7290be293fb718cd5f54eabca52db8aada18f2f481cb5acc4c3a152f3e7de12613c", "49137b088773c3481a2abb0a5737d3dc17fee14d5b2e6ab99e18740675595656bee6dfdd0eda9b9cabb7ced420a7081a32895641f865154bc34fafea673f644144edf62ccfbae431854b40064cab81449d16ca6f3cba54af734f9e5ab8e5bcd8de2fd510f8904ff77e8da155917e59db55b87237525cec9e5654438ec6cd50a8cbc9de722f4fc0b522b7ba712269bd2f22ecab46207c194e72e725d3f90cc36e9fdec116e24f57a4e58fe3ff39b412b7ebc289c4a013384d9f89f02073354f9c0f1a79595d018ced8b886b6a8284f698890d5b4aa9d897fde93ed8909089e37367a5582c0e241a9ec250241d0b361b44d4387227c9cb090bee687256dbe825b3b8ca3dfe77492d888975eb3bac3fc08122d8218917aa099aca0b8a60fcf20c27d39a5ba474b5296d1cc8d60a26abbfcb79a0c941688d1779d33ae246a93d80105c2124f5f120255a5d146095f390fd088435c4b3a8ca10583a6aafff14233df2d790ff6f1be3e15e265e0d8ce7072b0ebcda8fecfa1a79e6443232195e1d4264c71349c61cf7c4fb7b0c75f15ef2dfce077a492f7835e5092007a6e2a2909c010ce95e566acdb9eab354a918b7e96a89e0b0f4e1887fdc430b34663ebc296a61607fb2ac0a42419602770a0eb7e46a016359f9abbeab6cb3be83683873c27be1d6c1b5084350c035d22cd73165ba6989c94db17ac226b236480d086f12271251", "9fc5ad9c1f619ceae408a0bdd51a902a0910e95ef14d137ce0e89fd66796ea649d49db69ac0956f047b26e87e3cf4ad58b8e474228d9bb4c3785d5d0ee8366155b54e3b0937d00ea1d12d191c287d526a8a2c0f99d44a377e3a3e0724bf77bb1f440657ca9931ad2690406c4e002dde6e3114dec5176b4a77105ffb9d9826057cd46c7d530a12fbe38693c309582af334592d8fcdf83b0c7a9ffd478059549182162afa710c3262298258cc9ff2eb4abab28a5e1639a8f3619fdfc3a5de288902a94e2be5fe590c668fd25511ef8b195e57bcae40778d25194f0111eba9b6a8685abafe1c06b97a949031cdca88524be5b76e5981bab0c17a537c4a686b4b54b590188e8baa402406d54e21f843deea53226fd7dfa45d81517720949272718cd8ed1c5d68d0ece38f3f55ec08bd19267908a1349db5edda74ca00270cdc62e29b7614b6ae51ba0422b5da0027fe6d12fd8b8cf4bb6bfc7c09cd9aeb49bca908e00375ddc90b56f9a61a6ccf880fab90c23135d1d8c1547e047c918eee3cf652d81c3a4aa5f5365a444e6336fe9e25312fdf91ec2620ce017df6115b372ae4d59827da5737a70a516b684d3ac1b95ce2ade93fd73a399bd99cb54b49b311ad585b5da17a5b1b42c986fe38b1939b5ff84414e6ddcc500aabbff003daeaa1f2e94665de85540e3d0eb434429e1edb11ed845a9ea1bb12b262ca48942c48892b71e61be65e87413d174cf3e7a82494526c7cd94721e08e899721fc8ff607022b5f649fe6ea2483fb8838b543dc86d7be6742902c5dd7685fa32a3697bd4a390e13a71feddcd737b77b335eb6a624f0f9b019d55247bfe45ff9a7c1f60838971f2119b9f5355d2a8d5fd61f2a4cd2d522a4058be069b98d3b66466bf9ae030d0a04b266438c6cf613fdbc83472e7b809ddc496d248fa46443674c166be4f9c0f676f2ba85faa4ad1168a82650f435ebb985fc32c6042264bdcacacc1280bef7a0d9673a1cee74b5119d9e58b6949202b7adf0536754c1e8542d702306f71d15691cc4979d6e8a82f2f69cdf4351369dde6fb78fbef0bc77b0de4a5026ae7faef66ada81d9658928972631945c1a47dc6e105769f9bac63f150faf31c0a7ccc202e0d4b9853fcb1ab6ced0086f11b4c908136dd67cf917c7b7fb873804584e62170c9f354158c5545297d230c73fd75f1e04703895718c64579d436aed702f206de7a0c069296d95437c79aa4a3828ef5c5e99888e7c168aed897d76d6feb8a0c16bd51514d03c09cec27faf6975ae3cb4ed56f49e14034ed39ccb9e7dcb74f85352c8c4898970f07e7c07c1d7859faeb43327d3b46549371545e4823d34f512eabea78a1fc024c3c41a6a7a5ba4d94b331157792ea72cf8502bbfa63a4ee70c8656ff9d102edbbfa32aaac4c5b9d409795f75db7c44c3c365152cd7443de15e8610", .Okay}, + {.Sqr, "-2cea0b33765bde1d8f8ac9f84736ac18a073733da6759375598667fa747265f96b3b6002492f1f5e4e94da5495231e31f9e3600f60fa5e085d97fc73cb6299e7b67dc62d33cb31c29a2028864f38e75af50bf9a69c2fad3364bab9a802e76e726c2b6ef28e3940bcc61e2367b2d523af84ea9f4159084420d00a48bf0677e447fa5a3228bda2ccd0d6a41071261ec111a4d5ac67b9c64522582d04aab797a6bbb9c3cbb9c4ddcc91c04404eefd75e8a283f135596162b9983abd17c9b969627691fbb72d69038a3497ac2766117d9b83c15dba278c812012ace71128444a9588f50c19f6d6ef1e03ea70bae285c841379619f662ba8f470dfa7d1e4e5be8f83e082e29806441ca13ed72c7cdb56a232fb9cd3a08cfd0feae661fb2cd3969680aa1cfb04b2e8b27926660b54956ce756f86e6a3b99a0dcdc525ffbc9ddb2c6bb631c3a0b96b624a1ce69427f08146f056986550c527da3263e2ec487e71d72a81f8e33737683f8dc5d83f275684fa61d5a27ebf4a75a99da7dfac52251ac8e863a0668ab866cea0ebd4f4db1364c21321efd3e46f4d84d0b7ff76394f83aed04b87c37520f82fb0133c47f52f97ec897a3878721e02429663fca56b477c31774ab4ccc3f68cb3cc0699458d6970dab9f0f78b0dcc5aa2af258a81bfcc8a4b416eea5d28e2b4f66837c699b1eb8fe9f0c6d3718722b1de4bdfea6bdea8daa942e", "be011e1427d96f24cafbd82d4ff4b03cd9514b671d2f7e6f3949ecdb477f9a2bfd14720137d5a5d8bd3b1f54f26fdcd65b69594fb648c766a888d2bb001d20628560b26cf83fabcda42ccf3ee1a9272bf96c0e49a7fe2ae9531d4c8d0d54e4c6465d78dd5b69eb804a9fb5a1598201c8211e75b88fc39e3e780ba306116bfabf847e71700ede7ac0a60ac2ceb0d09195881502930af6baf0a886a907f6a6b15694972a119f097c1c6118cd4653953d55495995379e81c4eb3fd1a1459c70e398cf2360dfddd3134199b1625d66f2c720c9b2437ea4b0aa0e86f5f40988a58e10d4c47c805883c58b83c351e14d22d3c93b81a3dd17e979234660c18f70dd37cb545cccd4745e219b748a3cabe309faf1d70d8e49803ab0d6bfdf406dbe7d04e13d48f8245f91f1bb2218065bc84e3b352d1de1120d034e954b87163dede0ecb5e12455e0d2b5d1928563bd053baa03467ccca4e7c06e6ff049457a456b89dfe04cd7e9a0bf6b1a6b6ed36c7097306d562d7a92e4519b2d53ab790192b9ead8563bf7cd1bc5dccb339773fe560027b9a980205097f721d9b70545867106f398f221683763745451db8035cd7f7dc3373a8726794be6d0e0f21902a702857a2e383736480ca739fe16c69e76214d2ce93e508bc70d516f79fb605c38eade3425bbf5338aea90f56e0466d0ca2308d6fcea2ae954d9a6a31736afd7be59a793e21c", "7e149d22b416ad07bcbfafe9b1411612b21706f78b1d080a5ebea200ce362323eabc1f414b3d3c031b142dc1018a4bf715f4c2bec25fdf6b93925d964362e768118bf4aca490756c7c98949300674219a6bf16a087498ce0a7c909d4dd150b77b3a7cd1a58a484b80f40858d9839a0532ac587b4322240f29ab58066f9e815ef2be955be6c6d1e2b84376f7f9874da1c1f776ed132666c75bc67bc92fcfef6d9ca8035482c35d009e69c462d6abc9a46b6a3d03fc7fb879a60e0b87bd47ffc300e9d9f7736c3f24938d652967680fe3a324014adbc27b2401f0affbccef7e1765f7e0fec8549154d181a14d2810defe8f1474c29b4369b3fc697e978f30c3e744c20613ce544065f1791b8541b488126c32c9b2bc8e80554b3869c66366f5d94625d8bface3dbacb50244f6ab412328e22e04170586d1cbcfbcd33ff3cfd61cc120198e7c2d394c06e0783a6ef3c1909ff50e9edcfbcbe0d2159f258aca614ced8c7c3a803932ef09a7cd1ba23f8b29f8738e7d51021e44b46e632e1ad8257d48c33a9d8327ad15b598c402325f854f747b7983668bfd5116abb6ce68803d6219ecbade168459e671ddc186b290b184ed0b03ea727bfdd034a303d26b45f8df6c55ebee35f7dd8b84cedc9f8cdb8be1a46780636bd40c41754594ab90455cd49623b549e7777df0938d573750f413a2c04c8931001bd0f74acf598c11a10f95314855f19ed8717d8bbba41c0db87b1048dc0cc9ac8538edab732f4c7753cdf6254bb825d6d75cac9f30533d872956cfb2607a5f11004fa99b0b6462e98fcd99b531d94c63fd13abdeb734ce7f5d3acfd0211525852141313b8aaf82438c25587f27046a7aeb2cb47a425f8716622fc4d8d0f6def7ecdc8740757a125b5b363da520329dc621eae714f17c2b84221bd80ab5abe209960665c5c917847c1e92e1368d50c726188ba171eda76231d8b61362ecd4e6c4394130f91c31842c7c7dfff3cd462d7b377f5f6a2a18e7e14bb2ff4df9502e98e1554b001468bdd29f2ee09246b50ebb16f11e09dec7d45ebdb73dd54826ef37c1f06ce8e2a1f4f8cfccde6bdf00dcee5d673944b34093b20927603172ab34c6cb2d46ce78a1c1cd8ebfa321024c203d1e86f7d6d1e99460c582e12ec903f46a8d0c9272c83869b3f45198da5095aa4ca69ed196aef59986b9a78566aea0e8e9dcb1f8685bcbfe2e200db758dd7833bcb5e7f58e2d6ea0ae7f67eeb269f51a0433a1c92d0379acac2c5cecce6e30fa36c5abbea557e5cb146bd47963192ba9f4ec718bcebc53ee6bc04f77734cb7379a8e9984d911764e1b031c6460b64b8728128dde8fcd44395d478416d33bb6c5ce183bbf6d85146ee8c73d99f81b7a2097f363eaaeab3abd0ccdda8d3095c35fe25dbb070bbcea31daf96fd401858a566f1f449cb028fbcedd3844", .Okay}, + {.Sqr, "-5a61ca65b64e95da5e2b2b0475931893034c6e5f2fd522aff6af5f1304034c0fb1777878d26441bf9fd0fdba0e4a75207c1407a0258a56978a2db3112ac17157cc4f9e3df3b969000993d7e0c94f787dae58608caa7ebcc286fb971071e06aa86f27736161287d45b2366719a461c54287b023d10f96ed22450eeed974e39a7229a509826a6dd4dc4aa5647965248ee4aac0c00ed6ed4eca30199109829dbe3ab453d8892c385675c16721a7ec33d1e43fa641385e27e8ed5637ad3540ba6ba14ae346a879170a920c54b5f8026b27eee3910c2f87b2f140f97a01e46589523d7cce78d932009a3741aed0ff09e29cfe6a863ff54ad29d2f80bbb39a6e6e979fdc3814caf92680bfde7eaddbad693a750509c856d2d54acf941a5afa57acfc852c801ab8593558de0bd36c45d46bab9f33208d44b41a67b01b79fbaa6b0a557798091e204ffb533242f398143d37023160f5fbc30bad5178cfbe9f77d9ca50044351f35a08ed8560e1129687e83f9d4e5295d5d0c879f83a07269d53b453152584ef7c2126348ed7d90c46159e4cebc77a9dc5c1736dd4ed436cf0fe55064bdd112af7fc97df30608616ff66cc7233675dd971384f742f79f6ba5c6428ccb3cc7c0e17bbeb1c4a0dd5ebc0311d2f48cecd4078256697f1fbb8f8d5b08e9cbac031402e53596b0f463c8d2aee150370aed993a47f81d8c13fc6f0480718377930", "df9fa8bfe8454186cbb8a62c9b8cc4debbadcdbcc1e37aa97d155d4c4a06a3260e444664b292a017f819cd3dea505771b311fadc568ccd3af834e8e15165c2289d142562e684a46de09b1fb9e0fd043b8adc43da554bb020d3cd7f96591776540fd52deedb71a999610359801838f66964c2e6118ddb019e4580eb538c5f7291c611353934afc5990d0b6f17e0b4018b8f0f152e1b455be28811896566289aa622f50322537ece192e2ceaf529be3de92a30946dd43f2ab4d874fac0d7362316a45d405f2b0bf5deae7c1b148b0718544cfa782335581f6c3a4644f560c3dec4fd455b446484613cd050a116551a7653684ca3929a7a45c82d0a2b8f6cfc0d4c71316e8ef8e96d1fd3559e32ab95e1b129a3037690b0134fb47b249dbce29d7854b0fdeac253a1102ff5575790dfee5f7fe48beefead000b027fecd9e0d694efd03106d7380cf3ab90ec915f07c7f6ae7149e9f221a994c255bf7d59a308a93a5b8dc154046f8d895edb5cedd4ed916dcf4629db97a67b6b18980b88e6c5bd476229742f13e9acfd986266faf9f2d644ae2be3e25116b96b91a71da80e7e2e1ec1cec555bac39597ad62d1a750f3aefcb7a100ded6cf0fef661d394dfc101ce0149476c7d2d566e758c0d4f810056ee99e8074d48b1a642debbbdeff90b443cd261c66d0b7d2f0163e145b0ade6f95aff7c29838ad610b40186e831a8aacd091", "1fe8e7aa854815087a04671250ae312c38b49ea406bb1b44d10b784e19c98a0926178e2e34c26262cc1fcd346c96083763657e51bd3a92032d6746fa0af0840b2e8fb47abbc6086dd9dca82d4b5215e5485b0af9228002f54421ef04142a693298955789758fb4e4e648e972407532b444ff38469ffd5d4d823dd6140c2388181865759cb7cc314efcd5ad2da8cdc9f855250dc26d3882351d62970ad99851b4993dc54df1354a5e21b0ae552725e9813091de3c2b8afa66234d49ea884d9a3111b9e51d2f1b71f7454e4151d9d631e9b7fce85da3217d8b559f8f566d1aa8b466cf2448752dd64d75b57dddd8df290504a8d1bfdeb404a171091297709378f3f17829b59ea006411e87303d8b4916cca5ab90117867a03105bae7c5a8a086ba6fcca86ac2a5ada86d9a49a1de25cbb8f9787b871178c61a7c0cf1410bf76c771563d159e856570fda89d7a0e8c5ba6ddd00666b46732993c8ed1a4611f7a6b08b198c3d74304b291f1e5eff234499e3c0a0e3465cc46d5366deaf029416d5d61a4c15af1a1b442d2fbcf29de35b0b76764632bd2696c889dbd967692fe8463a15fea81e81d7a415609910f2a8f6514c0c2d4964d8d7fba1642f1748e06ed0f9b1a6ff427e5c329195ba026cddb9f528528e9802b88afa1dfcf2723094091bc6181aa4525acce48c24c4363fc20ef0eba238d7667e609fce53e6a7761007cb2202b892c556f12f6108c30e6e1c0f4d6e3c342307d6f0bd718b0b76de9469a596a62cd9049322b8ca920de42d7d1a7a4891eaac405835585cc2add54997101a642be2b1b26c0416c64413cfc8351d8267132368f13a07ec09b3e8ed112b901cab4e9d52cf7bd307bd607b6b2843ca440919b18a035c52bb9c394a2ddfb87a7a9455fc46f51f3b4aecb22066f6aa5639f72c73000f7c2fa5b8fdf5c0e7c03c5a7c9911a5dc3622465a55da9c533d75c281b1637a25243ae1fd4f357407facd67a78b07ebf8894d842405a2149f721ba0ff5b8cdcc376d4113a203fd4abde5a66cf10b3db1a9bbca07b6c49a4b5d52869b8f028a047ee3bc7c28715c036a036c7dc1ed4126a6e604e2eccb878ad002e24d5adecf16fcf6aab5edb1bc26a69f134b95ac6c9679d269b797fd253a7e6f14ae7b495a8924780ca99312f97edc332c6fa18c08033c64fbc7fe8ae3e52973b24d57d209a9c98689474bd1c6b9f0e5c5e801fcf5f06ca645ae102159b3a831f372d48d1b97387d3f375bc69e56a3e5465f614755ef53e60676246677ec30d739fbe03e0d2fd64e8fe28b9abcd829313e4a71597f560bb5709b81b7cc7116816fb92dc0385c02ea35c06140cb501636708cb98de09c2bb9f1368d5bccf771ea48b5910d7ddf116e9e0e6842b17bcc25bc7dc7bee508b7e619ff09e9c4fc71e763e642b473a528c0f3aeb037e135e4bfe6900", .Okay}, + {.Sqr, "6b7a0750f691acbfc4c5a25b4473641a0789e60a9785459f7692484fd829806323beceea9161aed51db59ea23e90931bdbea24b1d6d82a6b2ac3cc39b939442d949627e8e76aa21ffe9b845dc5a88f56d922ff679d66135647fb567e9745f8aab73a7fc9ad669903f24cb481f5ba74d99fe6da541859e1b691ed30c1192aa9a742866c5c300e9590bf46d13b798305e5ea9f4925947a295085f97387208daac93a782db00ec10aedfa6c6070eee1442174349f4125d67c7d3bf1ed74242f4577b75eab05198c434e2f0f57fe9e3aaa94a037c1b99160caca6e4438ce04af08187fad41fa8b92e8e260954bcb17978400d2a755812a2e12d016c871d8691c30ec881781fa209ae3092824eed247263e18aa5bcb53a6fc59e9cee1a56c76afd45852216bb9c29b7a0237caba9c9ce9dfbf622a6fe1a39828408979ba10cb8afc1b1a07f06ba91c38b83566e8eb54cb3e3f7b9358a76526c5304430cc735e77fba4e2574e51ef021a394a8e536496e7b6a89ac87a30b1284e669e60868bb490993b5bf7710e80d00c1e5317788e0cbe8a52c774a9b30d396f40cbae35227960fa1d26a58ffdd451dcb7da195c31ccf6e190912304bb6aa92ba6c05b1fa920d67e324ee18227119bbc8b92e06dcb19ccfe205c919314667ea00c557348a8e8fed2e3abe29886213b2a2f02e433afa7d2de01f16ab0033c5b418758cf11e4f891a496", "7b860a94c0fa618175474cf11f8fcdacc7f4a1f153c372555c4a4f623e997e1b3efde001a383d94e4e3c1dc83dc6b8039297a985d120e5f15443543adbfcdcffe7e72def3d7dcdca86bb1d467df1b583e53902bd68eeaea3daeace39a157aafd31402bf454a617bc992fb294392f27c127ec1e5242e4e8bd2f5de91c141a92f15787abc16f8d16fe38b93218e6b737abffc16d1c22999603975ec0e2e44d90109b5fcb0afe8351342b84215aa5bad4620c2582d299e7e843b9d01095ddc55e71b4a16c6650a1df09d42cc446c7b46408e09eefa6452e029734764777b83d8a3ee8f69d7155f73c6864608a807b36850e876db0cb7098af71eccc6f923a55bf1136f438cc395ec001d722952a04222523f5dfc850d1938a82ac7461e544050ea52fc60abf84897debe1d1ba0817474a4ac30a71cb9e9f2013013b8cf2acc9953ebd720cf71df77ebcf54579e8cf7e74093d0dd047605ea9c6ecd9fb3b17a6985855b4cf9ab7382e978c803a9d7ee11140a301db3eaa7a2225ea43bade8811edaf38f9c2527d3d6f759d4920b4a9ea716e9435bec5a246aa6743c69a7d01da00f6c89f2497c63e0965f75b1e9e67782b7d98054aef5ff770f643c0cb778f0b7e132be52f023708e32d2e85df60471eb81619296b296069a11d965cf75e7a16b3a3d8a65a3dddc7a5438b61c4ce29d70be5c04d3426d68e1b9a327b088ef4dba693", "2d1f3c48a77e5057f53f819a8897266c5df7e2de0471c578d8ef2def5d28823ac67ba1882096886c32ea14f17570a904a32e616ac494c41e5c7c07587cddeed2c31ac3a97188bcc43c83dbe276a4016fc117c072823f393097678224de3e49edad939ae0e6f779b7eae188fb1541b9d2b0486a08992eaf8e6038dc0188e64a176ab6b06cafed670f8337d70afa6c005748d82ccf9a0e90c6d0833efe92ed1e48e4dd6705ce06b0a730ce35949abad06458ce69b2c95761df509d0520179a3e6b1b6179555c6475d71fc48d54b355ef19c65b8726fbace97263791836261181e33c46dbbc63ac657b3ea9944e441cfc3354235681699cf316a8e6c940f0ea0d80c07b29befaef5453b9250c8b89f6b8d9300ba4cb79d5d1f4f96f943b50eea2c6b7eb4c09e7ee8ab725c77c565e4082ae71bb4c72d282a8536f85d6f14afd2f3216a557b461e4594b813c68c8265178c47250138c97410f9aa8067efedc5b1ab346fe7c9c156c03d3eab387a573c11901853214375ffe7a0f2bf5b0117b72ccd89871e4b8baeac207f877de4bd3bfc1e5bdee0b6c8b7699a77753afc248ef42302af911c444c9e8c3b8e1f4cf2ab046364578b22755a13ff86896085b923d4bc4c321e5aa79427860936603878e2c4df8ab2a26c5f77e701639c1cd033d37c1f4b3aec2f5d45b3c07e046637b3bc32a88e4691c70acbcc04f0f21d63cc553fe81e374090bb02e399be25f176b0765785935267c89c8d4d765c2aab151c675395e8d17c85b780ce1411814dd2c4d0e145599714604eefe35e35dee6f0f753880b64e6a96f73aa622fda0dedd8cf9ac706f9ed5669f38d25481344c1dd6e9b72da9e434dc160c7ee5f7d5d1b90997c74957c5a95ae19e83fc3656bea6b6a218e86715767915ab787231cc8d525fe6cf59fdc7839331e7f37fd4aabd093879f8989e38b7e5f7b221dbc2bbfc3898d5b67372f018364820e1653cc8ed09e528a645cc793853d00244ae5c89a123ef57e7f2d2c20018136079fe53cfc0bb4f1e9c6422fe3bf8d4507444b44e847c7cd9f533fea96b5c65df65aa7e25bbc341158d0715e94e13579f94aca644b6d435b49dd8a91071118184513b07cf61df12e233c86f92bb5202ed913f62acabdffd1718c8f5373205596811d0bb11b1d0aa20c5e87057d0d7478fd7dfa1e591d22a532c471e043a70acb128bcccd6a867268854deae260b2706a365bc4b6a23c73ecfcbb1b0c160b66b3cd75feeec291a70c44316bb5b255c633cfd2a60d31f5079d0d3fa46374ed566cc7e6319ace98d800daa5379cb294edc232e51655c25dc1071c8c4bdbc4e557d92433016c0cd3192c95cf98a35eab4742553906db9838af2b51bebf1ef4ce0bb30f6464d72ed99a976065c4383764f902237c14c5a43d55c1864f912cb8741b8ce4214b2573798ee7bbc87e4", .Okay}, + {.Sqr, "-5b876359e67aacef5b8df33f1994053a5c013b4c7ee51fae66dd31d069519dcfa7faec33a7767d4d9ac1beb8b101c30d77e3fdaeb02af5463e2cfc920c03072a2f348bd6cba5923bc78546c10777eda4034d5b4a2f4a38be09199c2165bc6c763940bf923a7d45b16008178e12282a02f56df456a39b1a61e4a1b137469c4214023d6261cbe99ffdaeb84129d8b9bc94e4c19ef6bc280c2cfc107adc9e567ee2cd8df43536cb40e6941fd5f39d1b9dbb24545d85d4bde0db87b5a55917cd7b171ed097251d2556ad75296bf2df1a36f692366a57a8da935318fe4dd0c2cd483278d411253dc87fbb86eb9e99c7d9a3d656dfd48ad783b31a8a702ee3252ab005152d52b2ea928ecf815cfce2940f142b539f80b899a0bb2740772f28a41536712b31934a9b8849b47a4c64f4a919697598a93862ad252d47189f2ef6eedde1502799f20eb91d325d086426d4ae823b372dac17c6ce563694436d87bcf8de898b5414cdee0c0a97f175f0a10fa7d1de0798e6e7c939eb24efb03a3b82255c1df26a07b911ddd0dada8134ac7b17d4d2ab6b409164c91d12716673e70351bad67ff03659c0a07aa6c0060e418bfdbb9db46ce367c8056e12467f353a92e6e760545c4bacc2de9a9c97310f71384c5358d1f7a77ed5f56e950846ca49d336dcc2770b4f6507d9e694c7cb8beaa0f30816cde52e93163f867754f0231d056de5be9d", "9594580faa897b0b11074cdf36dcb3682a370305d77f18d24f10dc09157230b703f98ea333c918184d787abe21eec4eaec8bec7a5f2e0c4396aae29e2840bae901ba73d637ed8633be4f6ac7a6e9d566f5135db197e17dc6189654b748116a2b3fcdc42a6bb5a21fa77aba08d5935fcdea9ee05ed3518e23ab1285c14ee2e9ef99de363631c236cb41ff5de70a70300754f66d05f8914b5998e4fb9f7b4d17d8cba8b018245d04c3f671054426dc4678349b484c56e946a10d3ad741640123de6f3a321586cbecd8c75f1897c0e6cb4f222bac0f64105d5320da82766f76a83d3c5df5e3d6080e41cbdfa02407b1fa59d33d85f0356a0e927ed50a36c42622053e90833a4d7e517b12b772bd0785251ffc7988437aa8607670e78e7d4bbaafba516563f7d6eb65a1676deb9c9ee0c39b183b2d2397dd318ea1fab3c63cde16610c9dd7491172672a30b49de3a11ac07dd84a2ed192f88748593b6bab7de9667dcef402eb86948c44fc1358aca0d3218029a65f7ac41a36eea605d8a390b6dd21d1f50557efdf90ec7bba14335e8024f404bcfc03a945314cbeaf023f4dacd38082b9551ed83ad30b81056f6e782d1c37c45998ff23f49f0c165288119272281a4594824b9a125426f4858213035fc95d797090787999bbf88936232d1058f6116a4155dd18d640f3e3751c48ca1a520f33e9a1c099b05c5bb6d9ac9b8ed665a3", "20b9883bd93af4298217836a3d0afcb152ae3d8112c978b81ed2a9b279acfa3762697673d1234596c9ba29152b43c2c8d8e6d1a7874098b74a5cbfc4bc1066e8cce9e1bf8a46db0bbe68903eff39be3494e78dcc0ec098dce32b5cff8299beceb011debfa5fc5e9f37ca16d56f016782d9c08d9042fb073d55f55b16acd489120d97727744faeedeae59762b1d4979a0b1f67987a595b92823e2a2a56b0f3626fdb8ab134c84c9f50dc226d3f8ced71b826f97477f419c44e11dfc65640d658fc0862131ebd2b8c49fc48889fcf1c80eebe0e86f65db8a6655edd4308c745d2fb04a06a7f24bdb5d643acbe684ce2bb3f1c554cd0a7b075414dc5cf8223f3011f6c5e3d9a9cbc9c269a6fe762c679c57d94ffe189a682b6a143aab50aaf18199e1241c3fc4ea6d7fcf3153aa302a61c7ab6eb59aa5cdd2d54f04c3d5f35363c99510599c05aac72153b942465af266c88c128e6be253c4a362b36868966b0691ba7598753dfd1ad61096451863e371e8816a7f15f617538e370343a0a6b0bd21b21af64225e55270de8bcc3627bff74b23e224f512b1bb6fbb4eb043633a8deafaff2cd8f0fdf806868cf727961da29c4f6eba840f9059b2b943e9de65272116eb127aefd2b4f95fe7f06a4f66d67844f3c023a26b644145ab0a3911a13ba0a4bd6fc2f5f27b3c62f410c9fad4b2e80968fa7729df7d63f10a4ec73c99829135ace67adf0706b4d87388efda9fd1cd906cdb3344aa9caa4a69a6272cc3f1a20a0865bc6beb042eb9a9609e2fc1ea772cb2a12492985bed3ce0c2a73ea85482e2ee01b952920365decfbad49f84a5b28dcd99604f1670f0a61b1702f7e664fb856b6af28c1c3041f00fb4d192792d1cc41605a08fa31cc486352ee9a62f2bc620217c874772a4b40200e34f7a834863d71a4e8358d8e5e7e06db11d2b9a2e74789ea0d89b474139ff2f169f06863bbb50ede0d9dc323d5fcb42503ee02eaf69b37c83eef9695db8318f51e4a429936fae235756ae070cf674d9bd0f9929de7a3e64e46d7995be314c19a18f18a10e8f8832208e9cb3a3bf1f3f4289b1938017d9bda758f165b96fdb8d1528e5c9027906385c1fd7e311610913c47b7ba1a382d353363eb81d8a0abd55341b5d38ad69c4f29ec78711ed4dfddbf75cca37b37072daa16820c988de36033c258f1715d05b2df4956661016eb10d468a101fd2d98b42450d75eeee96818f8bdb5056ef34ed3a5689f1104edfda13ca4956929ebb23055430dc482d453a7af4384ffdb949a7434dfe400a6e93a2640ffcaef5ba489c9d4ede73d5e8d570b7576c18b4d0b9bec13e9027d0517b4b9fc41926fea072f85a35049b03ac92e5af409b9fd0cc48edaf3566f825efeeecf9d20fb30cb6e981866e908436091ede5c665a582730c2a649df2447a92c1a44064476a244cf6c49", .Okay}, + {.Sqr, "-1303cbf0bcefbe170db167c7f33ae0bc49403f3b43a759eabf6d96facc5ce126a3b8662a8e44387aada0c268cca390a9f48e8746db5f09f21c951d9d6595b766fe7541210d505ff96fb484d3efa94fb21b7dac0d0deb12f87d285852bac643049756ac57c3eeb6b1c10f07c8bd83f38133f95af2a4d8d9939f1116766c86327a03bc506e933c2b37c0de7cee0dbb775a456f865e98141a0323db8c70a27fb0f1073cfb1e462cb325274fcb97bc36da29c8545387b293737988b702a9be1c678a9e52109bda21d6570c26cc1fd2d57dfcb6d0a7e05f7ac049a021e4da98a58864858670f7ce2e58d261b3258af771ff2a9d9bb3dc57b2cb0a46a28d89917fda77f2d008b65366ef95d18ae84ccb8c07df9e8c1b014bc49bc1be4c93cc26990e599260a45284a61e25d7be967350d7aa14445538214bc3cff07d153ac62b1adb2e133372a474e50df9c0c80550d94ebafdf3d2793a817973a6d1de6328d0cffe40b77d511c5e0fe9ec0610d70fb58bb02c7af011cb129efe89607da90d33c8aa6c2dfeb4b1b8d3a357a90add9bf9000d76541afa7a9e4222633959209c51994888325ac6346a190dc4792232358bef93e9f078d634b81202caf9c5d11a55ec82d5aad60c3228f054c6902c0d4a1e14fd1d89d485c19def9079e41299a90b4994762c2f2d22e87262abaed08fe0a2a70d5fcb67a5389c81cf00109596fc90c41c7d", "fd9f1539414c6acf05f7bf39210ebc52a8466f45baf83a903fa64a703495390955254490646433686600477851daa0147720d4ec83f7f7c18dd2c9595df74c988786dec1fd2f4305ba6af62052bbef92d4f343a7f89658b27a02432bb21c607f5f49a483c47a18717bcecbc5da36b285c4e32a5149e8ba7288936a9dc27b5b0497b252a65e6cb2b51e60cfbc9606d0c317eccddbba3c4ce286b6a8e20b34f5c43ba97b4f7d8be7703f67378369b7deebde885de516d929929addf161957697642b821dcef8ad013f2aa20043ab409950410b6901ebb09b192896e55a1fdbb3a0f7b8b9834e4c39ba2e0314442ca10b02746e233fdfcd348ded312f0f01036dbaeb63dd02532fa69f3ac18892b86dd3fbb8b0dee4e10ffdbe63bdb03cc728214364613b7f2baa976af7f0e4ef6e9cc35f530dfb178447cf7583bf5cf3c657a11465d146b83362c5ed8a7d33205872e253dd015d465d353614b48462c0e23e9a62b46ab9c753766dfb2af4066040537af1d394814dadc9258812df26e8375a177767efb5ab45caed1c9943a2cf5b2f1b05a3c00b08588a09842462542f688604bb8b13096953f3c0807d6b312405af32d775d7f28dce2c5f5a734b0c48ff61d8808e3dc4b95377f22d8041a11e534e11e47961c93d05b2769e3698300281de1be87b84e881e5dae2890709a01e8b91d281a115274a1535307cd02808e2687832a7", "16990542627b1dce500a2377c527f78e758d291c4c4cf382b02a575d56a299c1e893c26059a956f8b93cfa7b08606b8d8da212f10b158014f02f8210d8dd1ede903a27b1dc9aff7cb67ed599cb2fb2e9c22472a0030edaec5eab5b453ba43760221507dcd6afe6070b106a7bf2d9fb29aedac8cd019f5854cd30d3c4057c889db900c8125eefc12c6acd7ba67ba9b620e885665fe2c08742a492a26d9194dbd22bb12d123bd82073447dd369a51174e0e204962fbe3a42f9b3ea7b8df62e7f387f86de6ff32bdc1057a1ee61141227e546619debd94d7c970419928fed9913a549562f41ce26045e1db5f76e14f2cf4a2013c9275a834b16257de814aaf1fb964e0be0b605a42771fa471467d0f71b680d84d8dbe475115c0510fe0061af4ee9a38388af3033961674dbb81fc64c8cb9f694dd5874c485926353e071a8fab3e91497ce1efb8c75b74a1c08323624dd18668038cb726990405b365d9b6473dae8d05a1adfcd02136fc50cf506764dca025868200dbf365ef87cf233bd55020581a6c597f340ee20639c23d1d9dc1c8057f9a4e66132163b730d76754a85f8559c73871b795340b563025a7b1d36d0de89924be35d3d3b0dd3a1a761d9cdaac9c353c76ba0fa5e5c3220815fb62d307b060722917c94195c2752d33e799a24b09bd2a65d54e6a7a9f41276106b748b8ead335f9a656e232877c4403d19e2872074efc8a68cbc73eb3b1c80f1096487933bf50afd644bcf8407a0ff663f380eeb73ecd6cb9036e85771b9e261352d24ac591176bcb6eef3f6f0bf1d33189118784646ed64840d15a5cec40175b186f778de7f2c39decf146710b904941c38cb652826d72b4be97fa664c242121e8209b35bcd4cfb58ec60fd8cd133a8ed40a65f509ccbe5fd2ac55e618e1cc2c338d235c43393c6cfde8a4181491b43450047e75cc6d7bd92516065b96e180215c79ae6268664e2739ceb9261cca9d4e703a2b508d5102bbea47b15a6672166c722a3ddca7af57c300759cc4e90053b650747a7426f8d1968205e855e2d896453b5994cab0e8cbfee3a4079a8e6fc5dec1b9160fc8254f712a96f878cbc098656574bfe73f30a812fe48b01d468b2222661bcbb8a0407cf96413be1f99f6fca36730fa8e5c46e44558c048b6e07c394e124388356ce32aabd050dc45e67c5b25a96aa39e781c54e7f44acf2af633946817dab5ac6d1bd7ef1516657e0cb439ce545ee0c5fbded1b20d79d06578b215e1e2d12ff84b3734454b0e5584cbb54dab17b3d7d3294ab36215d330be54291d9405c657854031feb75d43af19f6df932ca9d6c9ef00b9c4789b493b2be1f511bf44ac312649a9cb2ac2bd7f9f7b77189c10d479fbeca479070b45ed57fe589e52482d57c7771bfdf7f3a46b1fa4e7fc2938171c773353fd72e13220abeed9c86042939509", .Okay}, + {.Sqr, "89a176acc8dec4bba463e3b92431e7a2a2dbe3f888af6f82218771344f38d5a84aadcb43113983a62a785c2d84b5793cbefe06487a297654ed93b6190efd1ce433b3257896c1cca3ce6df67c3d7ab53fd8ea9331b02dce192422154b8ae4725a8749ef39ec851d00b735bf1a2a500d554b3773f0f91d8a0f0039d808dde3b5086f88e9ba412a71f4914823d7a0c3b5bd7a12541f47d38f502cd2090001082f91910bf286d3bbb581eac0336a85998cccd101430f90dbc21844c172c16b72997051bfb4cbe5f8151512626df8a10e9431ded99ec57f6fd9853e0aae0836467a51e789457edccf54dbd1afc843467843f6d5ffd92d5f143726d17e9a1c9111c2897b36a6c9317d860c96e7e52b25510188370a6d076fee7e47ef5a913cebe24df8e66b9cccdd6c51172caea5f1fdca64d4cfe276f9630125db0801ef08c1978523e1ca39679d6fbea1548f846e6e8b2517bf7b5ff1cd209fe658e9a885ef82e0de1c654d7d0e93be485cea83c3b6d5ee32840e103c26acd1217a746e237a246cde7e86b4c9864b16b540ac59b965af43c9a6126fb6ceb8364284d3d060bf051d8e0df73204d5e26dd7ba12d1a81fc56ddb005766f20060e044c5d2a6744a48375927e7732837f3f0c2f3f604bb9045648213df74e40b894719dcc2063fe874f32487de01bc46b2ccb137ef5564a36b0c64d22eb18c04e3907f522f6fbda967b742", "b576e8c15fe5a8c57a51ea71d4bc41c06693c1428103938ffa231ae2aa3cd3b955de181cdcb5eaa4785392437b05c6d9b83ea0cbf9eb6016968f62f37c22fa83c2f9c1d633b38cfe98d4cdda6a4d15a4acbae31e54253cae36edaed455e167f70a6748e78710a67a15e2cf3b05d2d9f9c3310da80ab898f3863357d32674b1b1738cac319c417734352832ba44e03f1aa3dae9b0c04ad1466ae8cf15874fb3769bb2460cbac698c98c48864a9b46059c3430645ae701dee599247d699c1c5fc8b14b80ea7f1cf81059c30dc59fdab212aeec22807ba1a65f6d8b31d11c34a963782de2cc1341bd1bdfafdb0dd1b130705dabb5784b9933ac22dcee50cec51268ad25fb7d588c16e8292f4954b956aaf7b9ca2d306c79005d08beb18d5146750ed6afc6b28687ad234cd1439bcd75e5ecb676f50385d34dfed06f3a1afb547b71644c8347e4bdec292c1038505df7d762afc0f89f6b660542205821c8dee97b3be739918fd76fa06552777a7010cf6bb25436457c280fcc6431dde49ccc574cfefdc9881cc29e2f17791071adaf4642aae8cd6ac2cf694965c8ae56b2405456f8dad292e8253f5e65fe622776e66e475e045e4639856276800133bbf4ad73f4c408bbd135411132396131b25380b461560dc36dd0c9d644fd1be7602abfad15497bb33debab18625608f2fa07c85db79aece45a16b973a4f411e961569608a821", "49fe36db6b56d4903049dc509142ad2ad754766498d26c02a98ab91bad309c6e587f0bc4ceb31228f421e12415c43a5fa1db9200b809729c5e56e930d5282c03f10447f16694619fdbfbeea7f6741790ef147ff0e1607cee6c6d20194edba67fc326fe1d8f09e1d31126d96c05ed65e0631a72719beae9bf86b768c60cc920f52275e2592627dda301b99947bb3c81d8624f63a6372cb76eb8ae6e12b070e9fc9549e3f28f608980aaf41612aa56bc7d59d6d3b40dda953f9317707c9e6c01ace2a733963f15ac15a25dd7b1e9cd16ed17314817396e99c65465fcfa46491a7d493a2834cefe98c45d804618d7dcf0d5b275833720cdb137fc9097a983c1ad43bc449e3c400f34606fea06c6a6a29112d2388de620e387973e116e2aea73d70e137e9685a853b52b78891fa2bc757199d1cebee248ea5bd0021769abd54be89264b53b0aecc354f7adaba35f6003012f070033e67f7e5b0fd2084eb1770227a72dfa80a4d9963a0a53799fadc9bfcc04e199d97053fde7b64a2faf4013df49433392d1ac4284b315c0fd18650ceeff55bbcfa115071bef6ecedede9335147bc4e9d3831d3f327a7b468165899365b482d66227e396cf66f1113558f4bf3fb1466ac328e5b87fa917d9bebcb5cdbea9c485bf205ea9b83ff110e3c94de54d38aacd0620fea7d2df4113be49a0888b3ee4068c60b06c8f1c189485ebe17f3fa8c9575944494067214a5b38e7df704aa07d621b99014c7ab6faaa0be9afb3fd9c25d68d19653ea32ff68ce9f9e924cab9b0dacb1d721f351ce1bbfbc95ab296922c8b83ed358c69286f69ba13f384c7bf988f90b6e4424b81ae6f5da688cd713b56659cda9878d7d39c6f1f1c815db4345746ff643f474c84f5418d3d6abeda99933b4eeb8e48d1a87ad2c1ade7450272f2666908263edcead7cf6a999e494b228d3f34b08a6893144d654166ed91049039e0d187cbd0ae16c1f253ce21c478121edb3c2068d5000d546aa88b283f504f40e2bd579e6c47a961be7302a4c86c2b4f0905262ea35a31e3853d4c9b2cd8c557c43b9f9b6b336a9e1af5fa2a3c84a3547bb9db8e2da8b8fa6ef8a85e6416318524ab310d9d68a8e0f7451280df41fd7b72887cea9e8bda4f94f781cdb599c861b92f91930a10db1528e8d08542c8e558a0c6bcabf48a3b408a89830de286404b1fe56edaf81976a7b408e1af19b29c00ab34a48b94339fffda0094c08fd012de76dcd231395072f75125dfeabc3911ede420edb611ddbe034e610d316cd5d918b34745403a9cb0b286292f5f0f2334d9672fb59aeed47456227de1344f34821166db931ee887d26b2637e69c3e0f92841ccd762085caeb2798d624242106a22ebc031440fdef3a2fa49aa499d079f7e6dc0e642a6b5aada62f2921c3abcb9896f36008fb8b0ebe631665ed6e1e4b6d04", .Okay}, + {.Sqr, "1bcdd282583222d094f687da14a5e2a49c353ccd1dd733760ee706159e4b782def11b0f4d257f2006d50139f556a3bc69b5ab602b1ebcce561143d6d55b8e144b2ee03f478c1a2ac4d2ae73b4430686120e2f55e06d3aa0bc1001283e064d4d28d1a902b7338c2bd1ae3f53b5e450f0b2fc695a1fab9a9bdf0eec93be87459f770189812ef3328bf2066a39baac0422df5871ef4ca083d82ce3d7b431a5dd801dcd2791c317f79e0c0bfadd01eb4e6175b94bf3c800b576fa3145a4e3391acabd907aa6edd8e92d0c22287a30ac5ced5421fd79d7e305fb6d921a7aaf712e57fc8d29ee934fa6ea2e41163d74ffd475995988bf3368a040cd03d3404f2edfec5241c1b12b7696df0a2d50e9049c4b9386d2fe537d80635bcccd6d9b203b3801cd76d92a23e485b8a692858980a0d5c86271afa5f41f6253c7eb519822c6a42a9c34cfa31123854a72258e658e8fd409bef67ab0e6cb0c72d59ba8d5d6b4bfe17266aebcdf8ff9d2966b980b2e42e348437ed66b3fc77b9d766aeff7f101b13839d503fe985ba7b26c5cab570eff5f047eb874bf9e98273e829916c74896b3b6c4951d8e94a10e273ae0f44495e1825c677e08309c771e7470a5df171428c9863d9a43ac560353b9e438a70ef4d687d3f60ec272ee652b097c6d94384b70811824f8b0d63222c120ec0d2ffc2aeb04e35432348f52866c20012bf41f358b8db1f", "14dd06abd5e52435ec68154ddda378566ea8fb74baf01e4fa1c67e5e3baa58b5cf9e0446c4f0c5d7f7a5ccbfc0ffb07ec52b0a4d9ffc0e0a5b379b6c8a3543414797c34dc898dd50a287547f193b8c63e14366b7bdfb0d86c713a5bc5ebca294c42b69a992f924366c6be57349cd497d8fbbe18df6c78b90afda2d05846f72acfd0139c49b54f4762800e7cb74a802340f1157a5d07c73b9469b8cba7319155891c02ff63ee3902f6b33522ffc8dbe2a1d5f023ba5ef57a6f062638ef90fc0d6c8bb6fdf62d0dbdc9380f46917e8f52d5fb76c5e0c7202c530bdc93e6bb90bb60375e95f928d5d6cddf202297047a89b4422fcb9a3060e138201ccf67818f2af5f05fc5612b8555e2a6523a888e62cb2a77d37af852031954b5c68db79a6d7b4a20363804f8c2aa9b3a9cfd2e080dbd43666a0d970d0ada0ec8df297a2fca6b1242eb8fd00c022e5a9cc24e4fa79e890e95bc37271e71b4010a3bc80c7b98efd1567ded8a506f3b1b86d498a69fccdfb9a9a107d76ad6e169593c616459bf91d0c721091c941d8be6357c61d7f25f40d0ccb4f4cc4295e82c71288a6c137d5fa18c7d48b63b6c9401c175001d3d4fc4ac0a1fa06dc34d0325170c1129c79b7cf5746840a61ded01aee7af22def73ea6f259ab78d6651b8acaad2146a35d815c99908d07056b54142a5a51dba7f4439ab8728b66075c60ca8f176ea877adcb46d", "3050fe25075eeb3b3e6a57a5983920fb7a86e857b2c50cb7ab72af1411f83c9b4fa61bf9ae99c9c92ba7687d3ec3c9cd0f01c126563a8b308373603fabb97c1dceee5a0fb3387d1e49169d06bcbafd1ee1b60bccd5862c572bf7e1f428ede01d9d959633f32718ef36d77f74fa875d6c0a50431e50b41f513211a86f52a3b5a4536fbeee0243e46d0dc2a85a6bc2a4f47d5e71e8245a6474938d65551dbd95eb4729cca6ce0a6265bca442a11b846c10393825a7a8a59cc0a5537a7ce69735ce788d69e8321230f908cac05d48b7fe47511f8d6f1d8b594fb362d40dc80fb048a2834f23d38b7eba1dc31ca76630551c22d1252290b8b4544b17cf4cc1d18f61e2b80820c4f2243eafb5118066b986fc3917c8ed25273989746449f8da52ed370a1b795fcef0cb0d725532fdebbfc95c366f971f7d1c243a2257cabd6f45ff359efbdc3d316028b83e407dd7933d72445d71d5f4e87529b53db205fdcff3d530ae779d3ba19d93da6e3aed0e67b5bd39e0eae6cd04762b6096935ce7c62d09ae4b1665eaf0512e094db0d942bba2f9a1e2e162525e8135c113f14976d0e29b58c0a1a6d5cf7c6394e820d31ea0e110f0d608af56a22ac431aeba6a4ea891540312bea31276ac1e6c7a4cae86566d0304d50f7d476026d43dc1857004ab307795534ab8aae3a5c7b26cd7b2ad8b89f64974ae85ae0338c9e111bbf9cc673e8265c1985701d272efa780e4e07831afa8999e415c443341c09f822e80b61909d5a8bcb261ef6612282976b45b748a19c6604b5feedff19e91ee9ef241cb6aecb4a8e9c90004ba46ffebcdb7cd4f0065a0b2572ae7fdff1981fe2b6c39c58ff2404d895d20ebb81f3798179e89834091610eeb95ac33f1591b624666691f5f352914099df8e292cd6b517b94da3bdd0dac29632cabf70e40091c9fe0420123548077b68e55d0c4e59e80dc3f167ae0a416a9295d5c1142bea1240cbce8135aa7f13b72b80ec8c33a4a7161c9f542f74b6ed062d1c5e21b4e2e6ada8458a9b59d4c82a60d1baacd7734341a8a3eee031d361cc89e1cde6d7f22ec3cb96220aa2950aab4de38525880963520dbdb30e72792dd4d7f1d7fff055533c11abc41a6c734db34a28938e167548c60a8ee8021c34b6e5b8d2da51435a1836441b35454595129c1b4bfea0eccfd7487f5200df5ef34bd826a067398879ab1400e5d105d43d20fe33e84a0faeac0c66444ec935f5d761668be76a88b19cd4ece6ac836a817cbf10cbfcf68530e23c1310cc64f314e08a246b714d418ea2029f279b29f6ba6da02ad2909624947300b910f8fe1429af824bc9e60a168b64e0f1420b4352bc21df18d02d388d718c46a05d703071517e123c696acb1cf21d8dbb3546f97ffb79ed0575cf2d7699b627c42b9f3ae1c893326c8797c02b64d906c13756fb081e0dc1", .Okay}, + {.Sqr, "a1416d5ef6c5b5dc924f8f0e59443250aedbc951f21a33682b92e9182412f4494897611bc461664ee661ccf5a46413c9b83a0247d177998e3bea9242bd01a0fad307a1e9e90f97fc5a434849a468331e3c0ed94505d054fec1edf108fd0cb70cd6bf1bab490bc5a832fa7c491f140432ec620bf66e9e35b0f474ba27d7c1bbb8ca9f85fe02465e036df5991f89be0cf69971694cde331979b822c3ed38d58ab42134cf4004856ca058bbe5700ca75dfb0d2259cc1531dcfe6879f0b3e10885a4fec347f8fee44270528eabec50d8c7f570947fe5964717c9294ab67f066f54dfba524d6f61831c16d6a35aaa1328ed61b27883e0fe2dc3dba2ba2198bd1b461931276ee5b2c149f7da1d1b563505742b6fdf8c37a0b0c7bda4196a09277ffdc225ec8cdc71600bd130f674e29a8504f6d0f51df4fc4b884c31b29a30bc9888a2cb94daef837a958648bb55e8cd918eac67048c9fd5c45854d9cfc25906aa06aff06a8e8da4225f98dc5788e450cfd317302b405c6f1ebe6a0cf374b7c96d8d44e0833d1a477bda25a1d28d1daa7b9e2221416bf1a76940ad022da01c44e5d2b7b01d2105eb44afe6eddc5ebb5f7c65808093bc757c9281c2f2488ac2663df3255c40beb2506292b10b4eaadc6d9a70b933274ccc52e9ff8b2cf77ff8b528342c3e8b7f7add8b1d3ad2aaf2e0d3101894a41eb6b2d434b20583b5acfc8e4984a6", "534d3009c87e2bfc4073cf37bf555956487cd097c28c1bc7e9412ccce1170991d88f30720f50901020c74b5412dadf1971c37dbbd1438378356fc43c30a1df39167023ab0ad4ea695c10f37867c2a68309697d01e437fe6928dd1c73d4e3e6929f651ed8cec820aa7fb75955ca9476ff01d8e4c15cf7ad97c71fbfb5d6601c0de5a13c57697646e65ab27b1c71c5c7c942738aa3e966bebab8a76a5d4cd859c60deef7e56f07b570e636abdf45a3bee0531c77be137a7dcbfbaf6425f1aa4d07b115665b3a48cc71ec270deef7621d30cd5e8f450ba8e94d60eaceb852df36f91c238e2d3256438d3175e57b963441af2c98065404ca67e265f5967ba3e97a70647c41ee2d64e95b0e01fc5984ea50db73f0cfc1fd482ce3dd06274b3e696a9956acf29baa02f950b19de90961cb72918607f44a0e4ecab9b5d3aa47971e148551e408e6ea4184fb9a7fe037dca9d91bb5e031e1c72c6a92221dd76aeeb83ecd7b89c21c57d2b623dd20c94e1b51ead3f1acb38ee303b5230ecf0c71778bab932063f94e49afa7b5b3ea3b17fc0138b3868574721c5795470b34ba926fc90f87e89b908d243aa4e08330f67f53447a262311916e1a58ba5bb2171157cdbe59497e9af13804eb6e4520943e5625c65ec781542e27af1c6886a94e660b692afb2197aaf332b5cacaea889901b836dd7a3999eb6b277de41fd561092f726dc9077a", "65935c4a2b5800844dfa531f33ac1ccab6225d6f362f876f0e9cfa5193d12acc78aa6e3f1d896ea085ab5c628c343df57b1cf6d4e83a129c4c3f63471a7af0ef3d961de520fd028ad45feb63be3e916932d3ebfa73a2f56615831f15a797524a32e4cd9b9584042b6daf0fb2be5d44ff65f22d2b933d25301ac195e2c5785236370a021418e7da6a2db5ca2542ea1c0eb01fef58967ee1a89ffc61adff9caae724834fc5aa4cb227dd27ad95df9747449fdf2e32d38dbd5cb001de73154fb5f582dd8e1d9eefb1eff309e0166d9f3e81669a4cad0a39408ad0f632a1e7a232fd07f01eabdb36b9c8bcb7d37dc698241134aa7828e33c3c3ffbbbbc26bed1db31045211900e411c03814b5aed560401e77fb345f2eacfdf7ef5fe44f6b27169b93b315fb7ad95377bc665ec0bd5d5086a166a414a75f70ca4dc43cf946048007fd720fc25de91203f38450ce173a06c06708f3cf22d6bb9670dcfc78a9cdd40f98bd3c322aa8bab69b1f24aff34f8292b3bc93aa37e42afa6b891e6b796e82504abd804a2053b226f941af090bfa4b47cd415c4a7fc1861b395091f5180626a5d1c0fef9406235a4440c69d1e39b118be2b6c0ae028613bc5c3695b34de730f8de060aa342ca5fb8e4a181cc6d908dbe460ffb24bbf4a97e57afb2b6dd9524fcfece8d84fc730cdbd9526b8167a3b4f6467bc2f2b7f5cb99ec040f3f41a9c5444393882c708c4af9b4f17692cdb01212f4ac81c713c07fa46f3006faaed390287d9144d1bc86c9ddba8019fc38b34a25c0c6509b98dbfb989695dfd8a9e4172b5ee766f99e5d6593e3633ea5e9f870489d629a4f294c754421eabe82d071cc8f991c461878e1d313f9edfe5d8593d9f628810e910fe05712865196504548118b37adf7125b351c83372dfb74899eded7640cb463279f6baa405c0252dcb0b37a9900c64a746d65d545f380f16c42ed19129912846cc65fc7be0ad9c2c56c014bfe256dfb5da2500a8d1f04acd421f6bb14dd09978759a281b5c44c5d287f525a33e9283e2741d052e22fa1f4fdd1a20fa83ddb7ef48115aafc3fe55cc68a8d121dbcdb5a9cc8b2002c8199672053129ea88ead89784cef2ce4473df4dab6b7f972ada8ef8db460f087c2f2480efbbeb9f7e370bf25bbd8932d10c5580eabadf8ccf5b590a9f196bfb16dea65c738fd29624a70fc40f78f2a6ee2c93125d86c65ca9b1e7540625805ea9520f1005f83a3e749187ca3af212cc38ba603c6affe7cad0d2089a3cec3807acd4c52e5c6e37f151adc02066ce1b7873e6f59bef7747235a7d761a89f416b405601abb72855614e0352d26291d276d7756b3d760209517f2ce96044651286b917ea895de542502f5bb3ef97f09fcfded1909fb4ceab3a1cabcabe2e5c8598050e2afe812e9c83dcd6f781d2a6ad08eb0cddb1513679ba4", .Okay}, + {.Sqr, "-aaa2b9b4a09135310ee2f6737cf147c21dbece6682f881111440418f9c10f644bb85320dd6483dd3c03fe7a783d54525cce4491674cfa26f78b18bc7b61aa0af81b5586c739e1492dd1daa1070f1261246c20f1a5323a440995af8869e53c54cf6b2b73340d71b9ac4f8d531e369f3c6bfb2938eb15a66f7234ee6304e5557fbccbd4a15a8834cfc6424e9af42ff81581c7dbf8ec208c6229f5633ff4a9df45211f43847171dd9ab30622073c5f01c6958be62cb1ba20cec78ac756f7b3672b4feb6877e17d51baba4293b06c53d0fa217b6aed8a758efc7246fdf145f3a678e08917eb74630680b02865136b802ac4b8534a8b0ab40ac6473de3e9488dea24b7da9f6c7bf3b2149dfebdbc50c153c2e5744cf2f2e80f9b680e8936ecb43c16f254afb3130c92ccab4670cc085cf9d15d4346271262d5e4352b5ed622d057ab6f391df5de539db5997cc31c24e60ccf515687985932cdb1e28e04d33d1a8093f051657955cc1badadc304671c0230af92bcd0ea90bbc9ffa9fac7a79102d54ef3348c99f97b59ce175eb5d5c97004d60ed9aed0b5a2d982794ae3dd62832f26345baa7996e996d83b9941853ddaff27ce9c8a2ffec9e419fde28a9a1a7588b52319f7fa32ad253a9fdcd32080e9434d4c843554511a2f5474673e05a86ab5924c831200f63cb15d42ce3eb041f25cd64bdddda8a0e428df0c34267ef1ad0b07f", "c1bbfc8e27538ec66b730cdb07b3890486d8d5b4bcbc4e92524edc10e7777e1e6c7db6e41a9b05c4c640d7fae42970dcaf9f5bcd4de02d664db2980c80011ef8781a6bb15fe00b2516331593291c437504802049cdc8772b3898876de198c2adc015103165dd7725ccb6f18d248404142db780ac6023e2ca9ad98cb0fff8414391db3163e79db685bf711c603c8d334a850a44716b07c061926755741ec00e59efef3bb1465e12d9326d56308c32eb657431ceab3c3c0bb8715f3fbd97ca2af8d05f03710787f987205c18c39cb77d131c0969ef678eb623c2dcf6bdfaa8996fbe69422ee23d94c4768f55d78f5b1730ebc4dd389e15475e9020c266d8094380a75c61599f30d934efa7b97d9b5d005cc451924234c358c32539080b3d8f64b97021234f794b84de376f2990b0343d5dd9ccbfd6b1f10060689ed7747ba23a4273a0019f340bc9ea1811ecc089cc9d96e9c2d29199a8050e0b7206c8cbe558238585a275e811aa2b48cfd700e181d646b2b4b4933f85d2cc75bb25a35fa8d8882aba00f401870219617722964903a571d30bc07288c38aed860ea4cb399738070c76dab64ecdfa5fe48a6f0581347d4b9b1d5414131d8804856ed9e3e2fbe4441fe20c91a1b497184db86e499849ba5a951bbb6d4d7fdbf8403e7ac96c542cd23b71cb8b9e1c27ad6f9a196716ad14fa639b63ee173d01c9c37c40e3987d4daa", "71bc86137492a1f089a5cfece2b3fc6546ff70b9584f6a3cda8329f4f338854ef60bd02ee518d18639f1b598ae4fd9bac3faccfd4dc9b96ac9b1e6d989cd09abfbe76a44f6dba20f19784a99820be8e75a0a16aeaa93e38adc863e05c56b3bd79f33d53f3ef2ed8d30e76f7d7611dc35aed38c6e9d12dfd8ed646deddd04cea60a15bf83fc58142563ac96d0a1f2e4d75ea6c642b42a53f7b433119d55dfd7266548af8bafd6ad08b29aeb136394a2f9ab6190277b50c83e8ad7a081e2acccb34f7858bc0b4581668ea112f8eba06d0d8ad898a982e41af0d96ca921011f19148de84bf8369b635d0eeb4c4e9cf79c5f92919358877460911dc9b90d89ef8ea8eb5c913ed2efa592efbe806d992bc08b444034838655cb3db4be0bbe03bb9501f85ade88dd745830f22915f48e1c5e14ffb4e18c17687f86d6145461df959491b6807f1224dce0c572d2d43b0b003ca547bf837209ae864887fb5cfb7f28a15cc53889fed09215ea32a72ccad568c6e0fcd9b3af2d809471c0bc5b513c2b9ca18ae557c356de6676c37442e89fb751a350607651c8e590d08a5992acfc692a859b1eb76d581763311aaf71f890c7ce6b5b48a019ea387cac137ad1972c3e64bb14cd221ccf4cfd2c3067085da7f45ef286e7dcc59f3a12fa3e87e332957158bc503eda38ae740e5066392f48fddaf272abd4a05f75d6963905e053d7f84778298dd6933df237fa50f1f74af656c96ff6a1be48e726ee0a6117ff881068fad2c456c6862de2fbc29999bfd8c56e28449805bfd086b60779e65afc85d8d53c1b69488bb323842259ea5b0e4f43b014827a0344309619444c7053b6db6959415aad7648f7cfe75ae88248c2e2933455786f8e853281b4d66966d07ea44f9262c17d0b023a4de112eb09c85c1f638af3b50385fb82aefe1fe0c0c248cb7e5110a25f763fb7056da5a795d40e51115e2d58f3f4e9b91942b6480a98d491cf8bfc50a319094c9e574fb4fb113b7294271c2ce24d3422840630a3a04375fa12795e6d74f2e3278daa9fe3af27961478622335260ba9d5c27da7ad102fb81588dabf0b38d68a2e45c00024d616d8184bb32bb24e85414ff5aa5969d2037aee529187bb7f549b89ce5a1ae8df78006512a3f8438b501a0afa3da911142e94327fcf17831db40d61b0f42e9219103b94a5b9f99a81ad994505793d3bdfe1a303356a7c6feaa7403299c01f905c57ade48e9c5de44fa632790d1d660ff75455f1e76393c9c917aceabd28bb22dbec39f75cded3b0df865491de99bcfe863c8a85a0f7b25ca5d0569ac1bc97eae79935903310b9f9980b76c61ff37924be99ebc51e47ec14fa8efa9c94bb98d4db67bad9d44d28104537adc9d6be4e3548adf4af8dcc6f6eb54c74b7894a58003aca06b7dae5a60cba2d03bb411388db837dfacd1b140edf01", .Okay}, + {.Sqr, "623bf2971db99189641c54f553256c967ff9840934cc0bcfaee63697963cbf2d936fff28c80421db68ba401c95d55b836edac1d6305683c72fa6be9c92f46959b47a65ae0f8b5d7bbe216b966d118313dde4c72af1800173ef286e4f2dbac952c749be344a6a5fdccb7130af405f3623ec8c1145c9b6febcaef38180f48e34ef7f9e6abcb28503789181e0d33b4278da51a3e261bf63479b0400d486e0e9c59c897389e2311e184b02e7ce83fa6e098feebc3b1f267f6dbe2461302f1d47ba83138dd3a2d25fbe9dfdf22e33a7b6a0eb86fb19ef89be5ce72a6c15709322d30b28efd78a1307fbce698790b60c53a5a4f979fcf21c6935f6a3c51ff0b8eba396b2f2fcb5ed38fc26daf16f63b850e89780e0ca0e3d640b38746d6e970ea679f6ccb9a19999dae3e8741794fac1c21063b0262831be11ac1a2c6b7ba7dd216c918238d62a8e765ab22b81653b2bad7d7c093156ad5b7b0b9883fe731665a5357c93fb869fc9196a19bdb1e398501ccc7685c379f7cd39bbc0d020d70f04c43668bd689384c7d3ad208886f7fbd2dd4c3e261917e494da19e88fbe4de155dfda76fcc91a108c30c2bbe4966553d419fe335151bab4ad8487f5b3d1744b24a497177ea1fcbc6b5040856d22920e2a73ed4f118d80d28d9a9d42109c8e9dbc6c89f7e662d57b819b1726ba451ce0e0e9ef20689a45c0ff8cb38e37b457c797660307", "7b5ec7c13c876f2061bf0ee19261833d6f56b12bd0e5ccb0721f3d88ff7e008fea5edad9ba7f298c2fe68a33e4043f5f056cd6e54f7592f9ce50e5ec8521a504b6e7adabf04727c2da96a4f018e1ac0c2c3ee1fd989beafabfe219eb84c3d7022cd2e72e3207e54f661f3bdc37659dbbca9814b3a1cabb3068e081aec83e771a101d49de19459e5f95e744e624f4e6e013b63c6d2febd8cfe655a0ab1fd39354cbdafd807ab538989381d6e4707d692e914a22065f2fce17b713ee8e6ee8228a4b802cb5cccc7b8078ce821065cacd7c00969f5ff0fdf7a5cad2411e09da0197601475fd66ca952ed5d262ee28a4988df1582e4c01d3ede60f4bdceff665b69e2fa807e906d309f53ca62d8acbc627cfbb6cf0c4a2a5b966a793f23779b5c75f4f5773a876cb4149910730bd05b01376a615a12f6c2e2205834269985bb076ea40be69e7af5f3757dc6cf4bc340283dc5013715f17f4087220e807ced39a7851108d9134c1ceb8fdc148f1b7a26b98f55bfda0cb1aeb72f257c59cbc3c242f1eff4a6fdf8adc542fac8b33b761ad6322c8ac422c08249db2c0d4c15dac0db7fd63ec08e684997e2679c175f2e9e211a0d6582dd2a966e4f1c5f7a53a55b86ae89cbc5d343d28abf815f3daef12dfac1750d19dfb816738fadf85038aded9acf0fb5134a2505fcc3fcd89ad3405e265099f7dc6f080a415f047ff1fad02548f62", "25b1f3c56a4bd45d317ed8f172c70e54e3ec4c8f670b450d3360927f814d7315036d0e8659400b48684e69cf87bcc6f406d79e95103f20c04757a8a96922d1eb518ea3ad5ca839ad4a6abbb58c2535b45e278443a4ee5e763d8cc692fe415e03fb74e60f647fd9458ac3da176e7dbc3edfdba6659a649c7c8cd6005b2af3671147c420e958e72730329b8761070b9bd3fd1da74642f4213aac10efedc77aa0f6189781386bb99eaedf4a0586c0e7c43f2d6d71ce7a487680f2e31896e1a517d36f265b52bdcc310a3795665dfbb70800cecea2b78bebec81f914c9c945f31b6af9530e6fd1ce7a6ff10088ccb603006ce43ff72db294ad0d754e7edfa162a749a79625d0ee6d94caaf2f658fe4f6c3862b95fe23cf5ac074326b1f753dc2bd303e093b80a87bd8137639c0fdd275a7ab846e651f8027766421f7e9d42a0609b0ab598de62141bcaf6ed644dac9de5ab37befe8fb99578d276e4937f90e16738c9e3b1d7f274182f824e3e240b23c3bfeaaae2dc5927f0243a7573f9fe5308ee4d8fd7dc54294b1bd29a5a41e9cfd82b37c9831fd8a521f5e38174d73148029dc4eca0bf47e49b866582bddc9a2c461df5e59e71b3f856250b663bd85a936db172113d70e8c5cc2a3ae8d22ff218258a89434f344b1855fd759b110f2f579eb866d97696c6b0cc6115695cbee1a761c8be62d1770f5d70f37849c438be3332adcdc58917459e6ed17ebb98bba43ad4f9a3ed691f39d21346606c9de5341821dc05660061b9b53aafdd5ad4b15586b5a460d27986bac6252683afe007477dd02c11bcb1c1b35337607b91faf77530bd20c969e64db85edb76cee7f2809082724c15bf6d4d8b222806420ff7980d118e6888472fa17f21e92c04d2cc1ba421150e4cd05e2ae226dd10598874523077dc94410f5b513d05d2640db6c7083f3590a731ed2bf7ba7d598c6985fe9e17aba6da0151b0a9d2aec73988dba80d2c367b34df718dcb72f452756f4858a4d3da31862525e6125e05db8c4130cc0eda06e1aeed64c4d97ab7f5dfff67b1435b1520fb4fc59cea8c2d4433a30bd5acfb96de83a1570b4ce49368bda06660a88f56109b8a33d90093a37e36a1eaf3491c39e5b2f2242dcb3cae381654e4de9544beae3762da02a5b4089e23f2f6e09114e97b17a81c7c223583534f4678fd75e780268ed67e9959e3a81f247d253caa49288f658ca3bb68e0ec0f84a95b8153a51e61cc3f3082f338ead856400879d1820562e12c2e48d0834e4e383a245fd3c10918431222e485d534c0edc877ba29e8570e060a4fdbf4d59b63b3a40d0a50dd940ab9e4baf9ef555ae7008e477555876a83700cd9904550d588a76cd3dc361eb56d7d013fb1048cca9db292d12f46048a584950f34f6ff6b5819c28b84b684d75684f917ee9e0330e327095408f71aab9d2a31", .Okay}, + {.Sqr, "-5549e9c4626bb45b7936b2213d21d035f9544f40ca94082d5339b287702e7ba6b7d47fe849ec32cb1ebefd3a2c65a749ec2e3b04e981bd1f09175e23a2c3d2973456257c9e9f0a022d29f7c7d3b7e315fbc975120e05d156a4865a20c22fc62fffecee4770f1a4d2f8b83f5dae6fdfb66b3e9af0daed22b8c8a26bec6640a8a2d86c62ca385a8f2a554107c518cb8aece5ebf340c42e5abf738d3ea26a4d4498c9c552ed2beeb2da346587ae2f0566362327226f74cf67554eb63cdb47fe26cef6545bbf60540113eb84892f431b9d55ecb2efee45e1928d4ca0be3e07d63b0a416cd70cf50631d645744f32d18383ddc0e3bd7022bf1123e538d14d37ec8b242637ba1ed63d1fd381fef6b332fe6e6f87e416dec940144e6a55009c4ee8d9498062bf4a65d9fb3825fec16f27c8d0e29e8c694ae3a51082b5fe76d786174197e3a0b5b98d84801a3388d0ba326cf39765f8e924335cc5e2a8f4a1985447835dc83287bf1cca26601a542caacf05dbab7c33ea5862200f5afb83b17c2977c1110077842a7d6cc93128aed10992514b8dec4d0a8ba4551e23b7c8b3dba4cf09500415ab9a90530ee332e76c930d9494ec1601587344702b1efd027636418a3045037f072553b347339ee7c4e61f2b4756c6e5393c2d69ab428e1911977f9364d0ec21b8a2cee38e59bb451c469207ac13038f57651ee01c7cff60d097eef896a9", "ff715e5645c78e3b72eb24ac4f354d5e6ca0b13c7b691a1808a4b57d8e0bccd770329a66c43e75ae4cc82aa7d862fa38086e8c70f55ffa4c000a2dfc064a364e7f1d3e2b846cb0db82d7d2085c0017cef6caf8b5ebaea7487417ec518f0df22b0cfd813c60015e15f828fded2b5a5062ae174c83aadf0abb7ff592e80c1760a1769b4647bfce62b5752ca361793175f1e02f48f9b326e2e82a5b7db029560dd70693009935a4a6b8761b990d7747db5e98a3f6bc29939b2081c6795ec061ef6053e55d55bfc441a59517d52f0388e118662cf376a8b6b8cfd012e3226223c110b8088e07a064248c4f5520f9764db861e53660f5e2acc10a1bac0a214b8a2f1be91e754d9393b3fde4e81faa2c2c9514de8beca3efc9f759de63b06a96ec8fe115ce23595d56d257a04e5d395e1bcbc18507d496fb7a3985892bef99852b0efd326a66ea4a0ecba212ceed7a85d21cdd8f457866e813fbbaef285e54026ce71825fe57ed02c2a153c8cbf2a77d29806a356a4d29a34c11ae5b37d8bc134ee024a7d79b3113d2f4a35fddb932d359921c8bc6dabb12b32e29946c97a2e7d9b9936ecd8bf3abd1ad9c1698b8fe0e9e6ffab5ea777c2fde80281687ae0ea99a1e783bb23c219b7f2452d1e95c014255b2dcb2521ce9e41135a8d42cf54fc0da59ae5261044d91229c9493dc37412b983647a445fd99e5fee31cb39bf1c82b442ff3", "1c6a2a9390d2b90083bac59921e48cf86a806090eb720662cca5b21f38463308bdb44e28f6380528398e35ab123471a89f9f855f756b3c32798385aeeac5889cb0721847c69d255dc94214810c8a098b74be067b91a1589f8538a19857c4a8d9efe94ccf06a16e9b60e1e386d20282cd300082b579b425e49082e1761e3c58a9b21f8aec35af1e65f1d137cce62e6dd09d8b530a710ba966ba4ed4c5dee7f6613026c78e073b776f4db730db55b4ec233871530148051b61fa6427a9e2a58ab7edf128095092bfc040600335cee251e0c0ed6887cbd5f56329cffd2bb9f512b407f8a6751f595128a7ae8c13b4c265c9e8447ac2e469ed2a254291d99d864d0e5a1c973c846027248d58e392de8dfbcfbcddb4c1b559852ebf64daf4807f747ac52f0d068d57a2a654dd593bdc6c4e528e947dd7fa981a0b41c91a0c116ae9c1d511b8183c85692dfe8b9ce1d8d1372ac0f808f0d12f4270218e0968773b0564507f2d61d9982d4bd59fdfc735dfd735108ae4a4577f8ea9e184ef17cfcb7ed2990be0853afcbc213fa80fb2bf9cb13d33b846dd9de25b1ad5be9c6061156ee4a5ed93fac7f30e0c519c0ba80ea19c124e9e81a51df35b25991a32224c3059ceddb3310973bbeff1a40ea4885df72615b785583c1760db162d6cf67e41361addfc8545c85f079ba548e619545656d9e1d6a13fd5fd561df54da7b2a8a392e475e7f40b928aaa2f8a49019411960e1431773d9b22e1e634829f3f6dd8ed79618d4b84cb156a381480619fda8ea5024ec11137d020f1d6054f59fd3b23f3f763281731d32a44b3170b721222c3928c4091b0f1d5c7f8252db829c62f4c5a438389f5e473e0637e47439b860122eed8e61d839d4eda9055747d57ab22decd08cede158b0163403112cb0580e4ecc44fd660c482854abe688f18d06f67bc1fb0a0e19bc85d01f949f2200fc888baf7082028480fe2cb1367d0e7f83ccc04b37d2a193a64dcb21d04672f4ba19208af586da5ee4ff4242aacbb18efd071c019e430173b71288e0948ee4d414c75fb7eaf7cb003587385aac6ea4d703e33ebacb8348989dac7043ce8d8d54852f8331b066f3d5f02479529e67d62c918a0eb2ffc9ef7760e554910369871af8651aec75f60eba24967d333d5d8f7b6874509b719793965fd14ec93f48cb99e7d7fd127d80e971b9706804f9749785670ab32ebb6aa60ac725e1194b583f80809e067948b352a2859ac324ed2a8540d51d89739f0aa6a1a29f0f1ac9814d8ef8a44a00af4ab741ca33a3d9d12170061584eba85f6e1cd7a45610b06b3afaaf7b363f327c94d664ba4bb646066596476bc5889e568d6f00cf67400c0b0933a6b0dd7fbd93facdf842dca526e61c635700dbd4601e59c21ca4df2ad587fc3e4591d67a997df4ddc056d8952ef84a0cd69e784e47c1a7b91", .Okay}, + {.Sqr, "-c4066fc76db20c94f14881ab1ec8ab49d6065c7adef5cfb783e0d5287f5c55bf0205022b0274c9f877f9f7aa68bb3d4f73843260b305541a0fa50e32deadb3e3f51f99879075eb2102f4363c0e102c9b4a6d72cd6484ffc9a432c2125ab29d19af5457557200479648cd6e3862a10ac61a8f18e9c6c59b4c8e20f05b0c9d547517cbec258f1cb7ed0b2f7f7a42564bb3235b13a694b560f8a1b88df04999523795abe7508bf9d83bf76b45e984fa0ad56fe5314b27e3d316bc8243ae4da445365fe10c0a934892930780971f115e16ad9e93cadda02450e252808a777cdba2351b896981bc08f5e10a7860e24d67fd6ee4c82cd091ef26d5d62d619754df853f4d823f0cc89d7ece5617888aa69d06f35f83437203e0de352daeacdf513e84f6cdbe6597fd6a606e2c29e42e89298defabe13260819903ee9ef604fac15f34a4af16dbb1e2a85c2c40eb5fbb7bb7004103eb6200d37c08a6171f0f659d5312e249027327140356d94ea5b7420c6e07cf7f7bc6e76dfc4f4a6cfd3e87f63c6dfb98bb4a34209e45637fb7cddb6388c226adc1c85aa34ccff4033e368a4eeb68a5b64f6e7aba21f1f715dc112bf125760468d08e50adce6e244b979415caf8a1a6e4017f0874684494528b9071dbabd6f8d40a7be78463e6db5631ff6d1202e1d1e1a4e5d37fcdc7f65fd437358438e9c4a7d7ac2ac9cb8cf00a37c7829ff03847", "71be957a122fc49345d11636707c73257d7799895a9a8f78f3f2018c5c38174dff3e7037134a1ddb50d243ae40ed5d82f4014c11bf090e1aec782884514cbb5ff5112b8e9ea50ee94475a1d5ea1e983e24a2638fba74f00bc23817368d81f0ad6641eefe70a2ac237851b88871075adfbe64afefb5f22a7cce62664a67aec134a9ee9ff017f6fe20df42fb8461d96a526d266c265d29f87bf7e921ae0117d13f7d91a8267f76c44ff6a5c2e2e4b53f36d99d8a4686b5273d4b8400c4707899d5155c974e88045d0cb4352aee9a68bb3a547754dc42ce8475e40a3a0736bf4af476ce93cf25830d0804337bdb13380afef1bccedf3908ec0d6a335f30d44b9fe61738a99a683e387c5059fb556353a4df430d70c93749fc0ebe5ed37ff5d01a810a0b8c3d267689580d44b463a7688479d12d6faef56817bcf6da2b9995329c4ca4bd21b567ea0f2a9b3ae409fc31a1d7153a3131b70919df53a88b67539fd01f724e12a676dab76f3536c05bdb3ef07d63e0aec046cb9c30c33a11e00ae9206b6176baa40f2b22aecd591c909021f605810b343bef7f5379c5b486a6cd08e7b819f8b7471f601620d25cbeed93c0e99775abea71372624bb05cbfb8be324f7eab5842573d16bc65311da03f6052dec54105ca188d3db69ac058aa92a1944813fdd981fbbbf599ea333a9fff76a7bc2eb30cbc4a5ec4a1ebe09947a9a18015c42", "9619db52ce205418c92c294c6f8a48f3ad495ca39a2a3dc9967f9dc7114156ce90482bcd2e9d278f29f66645481a2a05e481442b5745b1e5427081895e35d0699fefcddfd475a7e1b63ec75b54dc68deecb0a95614a0f83c50c0d6dd8340efa7ae5bcda751734fdc1550b379e5906645ab36b725d63ba5b7e85373869dfeabae66c79a7ccc9d036ec81be2bfaefd7d5ee678036ccb71b19bed707d9a693f29eff302e40142ac0016524f8348a4dd908991b37d5c9c436d846b7b0bc5331b3d1e14f4d97e2683ade5bc5de0ac702588a52e8fb4850b076464c03ab1b1602e404f852c190e21566c0de34433522cf2b10af6bbb9a09cb23df70125a6d960cce82c5f46bc58926223b4f2f99f48a8ba2001612c9be705de2cdc55789c8d8c1e8ad3cb55f29cfab71ef894454d25e0aa41dbe8e4247b836626806f814627547f7570960d2a7da356f4d53378b3dc147a6f55c24357f2480caa19fccb9fc593376b3d9aad9883ea9ab47cfdf4990eb109a71d593c7935b526a8b76e3d655c24ced0ce2e7d6d962574bab35d0f1ac48fa25596fa76c7213c15186950a6145d27fdaa0ee7ce51b549abdfbe4a23cfdc69fe8cdba76b4cbdbc816bf71df4859a53a959af276f7223c0b348745a9702a561c624946cfa7d26dc6029a6b8707e0013f68d6236550bfb9547488945ef0273dc5d1e374c7d9146571481722bf4f4da9abfc431b21088d07752a2ec430d4b9205e7ea3a016823f9df970ac6472392bd16f971979078db76a021fc11c42edb6856eb22cc9b96bf319bd3f1f82169ebc0e7934172c6b44ba3a035aacd66cea61f3b9269727005c06d2c58f886cbbaa0292e0ae56b107b46261b39bfd6822d0c4bd973fe1de7d837456820dd62c90a36104f4d4428d7168d62176f6a7a6a7672374815530719d5953bad8b1dfed08922304a9fb951245e1087fca49bb17d50ca21194be999564e48236b67562c36c4c2df7fad3c74086363413f5fb367969dca009e0b12e19418f1a069165564d6218c7b63f8d860036ee1d5a8173019b9536498d1293806978edf390c5e2c011b9f0346959b9e460d63aa112f73f1009b8e3a35ec681a23eacdc9a019411ea62e1f79b2288c9cd2a2a8d51a57dbbf3a9237557cb06b9e1fe985f4b9f179b4356393bcca5326f1873076c114e2a3085b3b0a07a3d52676c13927ddb8cd361dc5dd36baa0d7c62ccdd19472398fca294e387257b50251ddf690a5b370074e64b21dd9dd6e76241873d31a602e928b50402c468df8a8289d5448cf6a859b8db3b7060f1d977bab5778f50e1686153eeee43232860986e47c3547ea7cd6edb8243add23621331dc721adb0050c43f2c2358505f20bef020f50d633f126ae6d07aed3adc96c14d0e9741e5696f1c337b434cc9accb55a023af6c233a1a3ce8ad020c05e5d16dc37f23b1", .Okay}, + {.Sqr, "-52430deebd30c8632be3c7822b7a28e7e5fec3288c01e0d1975fc43029298ca5bf16109a673d3bf52770c0f2d1ed7ee726147b00afc26e1b6109fe60240f98837a98ae8e7ea1d4cd9c7ee18e5c21b9c960b0b2e6846ac86d05494111daf119cc9ed0619cc08caf4343f9134c0ffa1122c1189bcb4e50e6d0f05914e8ede6587c649340b691ad8d392cd90eb0dccbf6ab579727446c9588bb56e7e9456be7ade18dd4db2ba6cb5a86e696b75f367c6fd64b405ea2009e9600bfb5a120d67cb056f517ec36811f859c7f3b8f74ae24c56172d974a3eefad19ddc1e0433ac8a6b6fc436c3daed96702e819cf749ceaa3c8c8b66c28344c6e7a28412014c805a817c44cce86bb15017ce2c65a13eecb115e13d69b07586104e6c5aa61f4c1f93528c1af2fd9b554df32c95dc5e1b5576cdc4e5b2ddefe5ec6392e72dd80bf8b66f3e96c79f6357b07c76b0aa31568a53428caf9d49c4740949f2748228379bd3120d6034eb2deeadebb3f6287e7a69fdc65a05129c724bdcd6e6c70495e9190b9d5e13a141c79948d6f27bfacdde389bd9415b624064424c2329508cdaeea65163fba3744cbc9cf806982d4a86eac581f2932af9625e8ddc1310d44392908674347f567af30d47ec41e5d3b776cf34e34df0fdc3101548b2f753381ae29c00bd83f164c0b5cbe435d7fe26d063a3b27a1bed4199ddb117101d98e1cfd7cb0ad62eb2", "59d660e0d443618217a619952aca020f553af0312da605bee30c54131cba92d29ea102c9c46fd66de667cbf32668faaaf8f471279d784741d2a7188c95ad0e87b5e8e457e5552a4438b2eb8751829e675c82e1751cd3ac313ee2c520cdaec235197b68d3b2149d420727fe4073f7926445247eaf85362287d0c401ba67880ac54d83afc68e4ccd4918db1d3e7b58061aee46083959332ca5551811656b594a67300a0b451fa00aa05d55bcd7a2ea3a9654cd84516b23e02ade69bf7a9a6bc31416f14facb3cfdb515fac2f8376d124448f7be5c69b918e724fc2d8c023ce2f2862ce737d3ea45a89954908b21ea10993ff3e83c50aa2325d4d7af3516f5b759387c94bf8e05e666892b5a16c5dfbd861f11c2ace29a0f115c3600419651be4a1eb5090ed18ac28ee0403c65e089f8d09ed080e673f346d9cc66879d902b5685dca5c96645d936f235d14d29f5756e940d0f3695616a5241a09a88702e2bbe6f076e96f72debfe765372d3a41901045a38f54c2ceeec2db399b89fdd3aa6a14518e3384392d094df01617665dd3fafd7917eb3ef811ce26102be8b6c3dd2a0f46d6e72947912efb71b30a7e355cc9ca33c89fc2ed27bad5fe4570bd31f0f377317c30006496cd6da06ecd29757de64457b3518e23376ffe1390f9388185b70c4cb0d0ae71a08c157da460834643e3934f43469570ff088524bffdbc4a3dcc93ef", "1a6f067d3cec65c3b2e6a112c0a117991e75e56f0e55a736067d462c0a55a3d44d35cf78735e8fd4e620ee7d7889f802d27d306cf26a85611ab291014bb1de2f1be1c144101b8f883ea8f32d411a2a067e4a5e274f8f98c350becdd029bcee0e52afede018ac0046ba34f470937495b73599c75d236226405beff98cdc60e18ee2689eae79f41ef923c6cf6f6d88b42fc612f0d6afe5acb0e52d2f18863e222a5cc907865fbbedf385f923b5c23555029b9c2a5177d55c2a3557b2a1c5eb4bbd66a7b39791c06a1e6c03cb7ea5b3889b0626fc5674d3b3b26569942be2bfc3451c937697c985c859cd7ae64bff00e335e2163b2be3b39d334b163a4bab25f54065cc3fc233d93119e32240e4db9b8c23ad1c421f9cde163eae61f11d1e1ce2e736b27046dab7f0eda267d0be48b4f3f68edd2f2bdf196e6789529a84ca193315cdcc8f0aa7534ea3c07c980c874ded6b93497b8d8fcdf45ab5fd4b137c009ced1dab67274df092bee38b22c499aeada7ed0b6998642e6f5f612adcc666b4df884f1798864817cc9560afaeaffbc7cbf1af9beaf52a0fbb48a8356e97a2b50711683b499efab5af1d78c1bc8fd6a5f92721cbcac0cecb57ccfc5c2a5c28f03c9236300d6a48065c050934e5307a6f0dacc13d05a7bc6e18581c86c1bd2bec98c3cab9516b9e61505b24d09f741118d41d548ca4a76c077783c84480b1c5d89d9246b117e4f487aa1ec8504a6fa50632d6a5c0ac69a8818e33950f2cb71032fbb875baa7c0ae93154fa0c2e1ed95ee196b6680a57e4fb5374ab1b18d28044a8b721e680c493c74761a292137c1226f2e19db7c66efbfa30ba40d0d03137dcdca1a6207bedec75dca5ddbc2aa518d9676fba6fd20fc724919b8e6fae4a95ba65b6def900612bf43d16168949a0498e888ceadb011d70eb649cb2f2afab5ddf5d8ac62b1856f7cc095a8929bc0e371a2b9e28eba1cc88af415a21f49c12759e07294516063a5acf19589d0aa3db4f502742a2b4760573bb8ab98dbc2b2b01e83f761adba7237971d5b2e002fe70b82d07f959e4c4d201d6ea18499224b4b6695c67da62e7bdba1d61eab4caa3caf96954673c703144985b5f15dfd70b35905de0d5160d744689bf007ed0fda1aa5b510f8c21728d813a344e2e424f4326964c088eabc2a37121c12e575937dc5566b2c5456663dc2c3f0f69ee9e010146ae2f0ac5c7bb612fc43a11a222db05223400e5b34a9b582cfd51f146cea9bba74aab5fe2e3f78e77b6e2afe49302af2e69f0a6e88b32d253ab6ae07c694a3400e598131a724f191de842b68eeaac80ae6922b29c626bfb34673050626758a99d5e840a537be904a793b92c909a92b2b9a6728065dfc59b58a78716f95536c860a3d563655413352c07f14f993e5eff19e9f60420077c700f0d07a79125a6e7924021c73c4", .Okay}, + {.Sqr, "-fa60d60d155e8017b7a67c3dc0a79475ab7947117069b9a619c225d36b10ec3c81a7c9724740d479db39340ecb4aca807df9fdf7a8755dda34de8a7c8605bbcac4956e7adccd466c0243ff39e38e85310e4eb832d69f71e3534f775c42d809e43fa063de6b7c22754d9fa0acd3657750ca7d239218e8bf0e37b749694d9ed75d5de1b895f14708f88734a2094f578966399af814f4395f12884c59029d63cbe7d3e622e971a44c6b38382a63fc6b138ab0aa9a46aff73f286bc0d101e3a5ad01bb38c2123e3c7667d0d085051df0c2b70b8c6e5e0c6728ae53bfa2ac82c655fd1d9e3cca33492c63490d54ed87596e179e4998c1766bdef3ab90b09f7d0928afe06678da4da97716a704ff7852854851ae641d990c094a426ff64278af97a63a60921c5ef56b13387d712ebdbb4ec27f18e7fa546ac4b0874a8cc44fb2da2f1cea99079df54a73a201f89a08d1851be25f5b8554b03979849a30800236c55c57de44aa9857823cd9462442133d1363d2454fa75604a39758b056dcb7e59313d5ab54718f71a9a11d990e263c79fb013b28662077a88a6978af28507a66a59e346efb55c3b5df492ddd65334e9ce5f3598bcb20b56ebfc81550acf8894504adb4b5f160e81c8ffdbe2d6a1237f58a8a73348ad00ffe4bf7db3f0fb7a76c082285aae2bc89c95e248d2ee691f0f659fd90a0029ae25206d78ed17057f9b0257d8b", "1230ebfa5f4553e682b3d7b8fbb08950d8a607205ee72e37be563ad511254cf264f83b1bb9f677a294992d9de08e062da4001952f64880bd58af6f2eca9c6b174f368ac0aeacd6eec58686dd52029f0176f1cddb65d2263c9b0192aeb34822e73e426a959f3a4283f2a4d454135345b2b1d788a7544eb1b8cd9be925488558046f74a16cc1503b55f266a26edef3682652c9311dbd16efb55bb6f4c5e7abf0a6f166ed63511677fca417fa935890a9ec5d94537e36a6cda7ca02d4904a7393832ed5498329ae95cb20318b509b0106a555f4fd932833ea6a70f92b31b51c37c1c2461749d7f4243998b1f8d6ec2a910898fdba60fef68deb1788f59685d4ac87702e62b2f5a8c2b14802ebcb37d8fd78a6cdd9370bf70db9ee78b0036632cb5d506694919f33dd9ff76c072bdf95db17a5f14cbe2fce293b5777ef95585474426025af5ca4d5634cff5fe0eda48058f96d8dded665a27f75e96ac94acfd8120722ca505a57a10180e713bedea2b061f6af227efe703a717d4b088fa7746fd18a32ab795448f7549ae43bc0623084e20397c066bf9beef1a4e394b7f81cf178bc39161bfcf0488d70008ec1848d9aa2fe8206020dfb343e967bc2bf08844bb25df0b0e2d7cd3679fd15c2c34a1eab2360de6c37282b793167bf80737d870bb0d50fae027f9bcd6730d321684bb8f5af2e89dd87dc1247c78bc29adc112428137c", "f4e146b2ca867973900434defedb9081473fc777b6b4aa0d74897c89da4a7de1488db3252325ec75b6c967c356e220b6dd6e2050c2a3f3775ac930216e5538a046b55040c272e21a0ccbe431c31715aab20978c9b232bb5872342debba6b1e7bfef73012b8d29491f5ff536e1768b8109725d99ed130bfcdc4526468c666628264d37e470974b11c8939a5fa4cbcf5dfad530ea5cd9cd1715f35dd9f6158001e15e5d9558dbbed93f4f0483911e081a633855bcd99de00385dd1996f25a88081ddb4b19b44503b668a0d1ba25d92306a445bac1754c13df02ea3798e00a65262d109451b0c5bc2957c07efa8ff6bb17b06ecc8620b52c7ce889a58f244764ea577def86fecedbde23c34bb3a410d79fa76cf73862e1b2262eb1d9b5b8ad2940d7fb3386bf4bd9225c8190cff060e3fd8b3e9bb476ef7d53895b1d91d01132194b8b0129a37ebee0e1cf8df359d49273d59a85582001afb4efafc24a7c26a16f49d460fcf5cab58e495d241cde1198377c8fc0feaff388664049ee4b590dc495b27d4232eef269e44bdcfd69bbeb14cae15d33b858a66dca47a32fab7d9ae14a3af7f0985c879a344b48c1adff758003c65c6109e5dad90238d47ecd09dd4704b40bab82a428c7281596880f8191f69b5ce56b30adf949ba2b277522e657ac9c5c83bbac1c15eab4d9efa0b8b2a2b94107ecbeffa1be910db0fab55a2e57173f657b4f842f49cd5fd4f924eb1c05e4e3c6811d7aa6b1dc66f72b6842e6a926476a66ee9b3939e33c615c06e849b200ee812d675b639469db990dc5382442d171ef2c8ae15aff29941215da350fd9ff609200ae3efed16b840e71aca05290681bb49ae016714a3de9cbd9d9bee231b8ea387b3354979cc2b78e15f9aaa4b2e15dcdb94581ff579e6df0d03bb3177833470435ecd5a1827c5b9291a5e351b170dc4ffce3dbeb0fd7ed84c11f1eb279919fe779e255cfa16ba06db89a2fde26501bf5dc92f304a770d632bd20e6aa24d4779989f6270050ef7196b7f0dd140f21ba37820735c6bbba10cd53bf6961141e646ae83e5553d0718823d009c3aff06016a17432d6bce69ce22661b8722349f66429ed58902f94462c3d3431b3e224e44cc68d72a6299729e55b5ea97f856920b2cc82c07d55952ed4a4a715d3585654f1b6de2ee25929bec03468a4241e47bddca9aaec031d124f8302a3bf542f4864d0964d89e6188dc6b3860db0b14e75fc590016d163a32ff42a83a9c63cae3103b0b01dcec102ed8c78977d9a5768a65805fb0a658e3963c8087f24b7002fd65576203e84ce758cb15fd13266ea10eb9401bce3f853024384e669ef9455bcffa0d624414158cb922c65e7d2aa0319fadb8b8363ff72f7f9b361ccd206b25eee4faaf476793f6ac4e69760c6e632d71a051c39fb4cb6c1b4dc1406d164482a7bf0979", .Okay}, + {.Sqr, "bf61951aae9f2e30711efd708379b6f13e85b2a600dd16b99bd2d1a73f160e534113df50121055aae182d43a1fe3967d815e1e017b90a8a3fc8dd25216e65443c62e5da3ef1a48b9d385871b1619bd04350597d33d81945c5d7beeb21e2ce7471363b72be5531cbd9dfa5643e34f7988d78fe6fba3fd44f945b1954920ef5467d98c65b3c00cf743a253e1ea1f7bfd3b6e46e7ebf75754b22adc96b56f5d34955492ef4c05d78a992ae3a16938cb4e5df6f3d6f76a5843e8a4e27cc184e93a1c536cf2302a67dfc5bd90fafb6930ff33af4762da34f30e9887ca453f2d221686bb6bebe9486ed6e753f3143ef5c39a8db83cca602f2300dcc099301d6a0691bb269b72a9d292f80d09e6c48bf66aef323b992f6ab59fa3f343f457875668946596646a8d0af81a266d2c80a743b8e13a616dc9c55bbaade4edf244fd0008c8dc95adde93d63b76081fbb2787ada727f9189da70d034bff3072eada68ec6050a4c84fd2c415caa78d02f3d31a0cac97d14b8ac30ae70547cd0cab08528cbff1574cb173323650dde24ea93878f01c701afdf07d86b2f8aa9d69d81208b78313c171b936b2b2ac3ccf0441d162043dd4a68c2cce061d5563e5cc7161d35b4cb4a31663bf224ee51c3aafcf25adbc67f9cce199be964f63fb19618bc14357dbc8b3575e8fa4c9aa33709aceaa8909b84945a7564d453ae94311df6dd58e16856c27", "bb226532c37df5703e20ac7c7bed4c58b3e8f6d0a8de74794a73771f3601c3ed458b410e7c23d99e2ad5c08cba5cf1072c76413325d5a6218ade0078860dbbea9d00e04a425de8775e37812c3ac78721b2e379d9f9979df2ace45b6dcd149b0a99d3d286f16f4ec6fdcf179580bfd357a6a0cd70ef6912f62bc028bdba4a0e3f1b0c6306bb7661b14cdee9db31b4046cad0757bbe0128ae8ddcebca3fade69fbc0039b5d69eb58c7e98f8a90d0237d1aa21fa5beb5928062fe6552f70cd5cd48bbf62933ce3769abf100bbdbb7af0a68b7fd3cff35da3438fcdb63ce65de34f6f4e084a1c4dcd2304af765d70efe6f4fc34e81344d3782830e9a794a8838b2234efff85dc72854c91c363604f74cae74145c923bccb2ea4136b00b0258e7ad621805787833bc0392352b9e6c63fc546c6633ef175144bacda7d488f14204f849f9233d8f4f1fce107ee44b0624c372249d36e4cdfd73bc0c9c38c26f4de8866f06643ab2c56b48260d397721a055df081af396472b8b95b03a13b2acc0c6ce1845af3d126431d2682ab1672646b588ed86ffecf1800202b3af6d40a3284826aec36d567cb93d11e2fc7bd42b0dea53b0cccdc4c00a2ed03e1adb3a8081890d7ffba0579d152465329d6c6d288deeaecba856a76208e52087f63bdccbb730821b7d68e83de31ab95ac17a037aa8a06549ce364f524b8bbb595f4f99cc9f7ca5bb", "8f12c1b025a1ed9a84b882f3430bcbf486f77c7d5d98a564859cfe988dbf04462385c48063c311ac9db496a37f73bdc24d3504f9de318b10d027fc5aed71f0ecb167547486a38a7c9459cda1b8fac5058e6039c8990e1f061be12115f0500e9e9e504f871a1458783ea7d95a603e2606cae62b9fe800baf18ef29c76804999c595165f12c976b817d0e5d41091f735350745f4bd0a412f364edd6cc01b38263253b95b3c1b59c360ab1c861681d371e6ac5048dfd3e1aa33b916bdad353fa5213907a51de7cbf2d6ead9b7f67bf323def18696e3c43cbb5c52385efc16fd01a8031829d74056d61a331b47101671126093e989d58e3667cfbe78ab478b3c93dcac0ed33bfd115e53ecdc24d91a21874d451538c06ef5b584dbfa010aa4bb3196296cab172749c9e40728986491307f66cf93a5a6bfbca9ca99eb72c4f00e58885e80783742d452b81e475bdca45da8f69bc004c0ecd188f3ab09f1731fabeecb51e30f5ebccd2d18506d7885bbe15f8c3a0b9f3a61efe7c1ad14ed91386f4303770c6eecdfca0875d275aa3f9a00a314d43cccc88a034e3108d9fcf6edafebbbf530722b93f8b2a898c238903e986c7c13aba6ea7d6b2becd156b5517c9e067df03f88af29c6173acd40dd4a1e7f09495bbe5abe50f68652bf2ced17daa29b900b58f48d5765d2d9b0a020b35cdea717aa5cfbf1d060dce35c0cf9f83ea5e3758d1bdee96a587a12ccac50eb0dd5f552b0f7cf5765325f42fe88e9fcccf02f4c1f8f110b6c9c17ac5f16dc860b034d6196f580cc21d84d5608032b10253e8285eb6eddba0685f221d9a04ac32c2dd3a4be3228c1ca679e12c604aca02bd7d73de44dca01ca272da6251f347cb0db5e121154e9e04f9fdbc845f5bf90c93732e3c169d167cbb8a90978697d21a9569ca1a4b5b53af9f82dadbd4ea1238ffe7b1daa5847eea26a6179f5a7959574e2450bb5f47fb085164110b4603aca15e9db74b906aa63ab226777ae112b4f3c8ca827e7d6a7864fdba7c90bbdeb36bca981fabadc4eabd9b30469b69601a983ac4f59ee6de35ff206be40c1265b64301216a7477a9ad1425d34ab6394af1f0e6973e5101eb8d226914bc5b6aedee3aa667f089d485e1c5fe0fdeb24211b4c2b36e8c6d2509aec7eaaa4635a39f805f2e07234831b2bf2b6b5727e268ad3edf2baf26a0502522e684dd7efb82c12bd05fd93706b1f14746eec1cf54da4d6fc3ae39f804913268db2dc8fbab6548565aeb083548800bbe0f66a9fbebfb5cd43bd5b5f0769ca5126a40f14f5dffd703881386db32992c8e6bab6da41492d9d2e72647d8cf557f1d36c5c8c23e3a16c09133201dcdd2bb2a30ed4ceb7e41b7f209a819f5e89eae028a9f345f57ed8340d34d44d70f3a238ba30ae1b4fdb344ff913892ecfff687cbc77b4278f0f2e15644236edf1", .Okay}, + {.Sqr, "a5d7aa76cbc264b05d6bd9ffb3ee933275458438f203c9feb2f8e054730bd86267be4b5aa96229f09c74dc9efd0126b29ebfad487c5fde38da1ae4bef30ed63d4d2f348dec47b8ca1ba75d12987b5d91ffa6e5ee2e9fb8555f15d80ac1b876f9788fe5157a65b32f7f07dc5d0f9c009bb642ace68d951103b8a83149de4ea1b1fc538ddb0bd48812b7cf1097a2377ab354ab71ea409849f1473a82446913526aca964a0414a15e1e83c5d11d5285985768d24b106a5a296454c99f4306074bd67e9e6d175232c115b2cfd39aa755521cfed1e24e802626d09c97825d5fe53bde5ca1cc0399baecabbc8e11c01a5c1c31fce19e2ca3f862a0a954978b1fbd7b2983705a4b0740d200a2686e8bc98544257e2abece897ea36872c49aceb773d6ee87b718200a38067518fca9368ac1fb31408a28fe4ed111481f63848bcd975e0845159efca998cbac4849014926731a54922b43c9e7f6f9b46ad6ce233c627a99f90f9f2e32537a24c163dcf382540aae7f161a52ba11ece48508dd1456a2ca6d88de18c5f64edb323d28476a7eba21c33881cea363c6d820fe43ef0a13015fd7eb68c27d66666d2babd93a72156b2f9eca1b75cd572ff106a0260599c3b12635643b6ecadbfa02c312f9977a66e721e872cbb6ee5c68879d2dcb93850b991b71d91ebdcbc8bc784499697f3d1e14bdeff7e18496e5751bc238a92ace83ddb26b", "f623e091cfe40e0f363d2dea9b844462c1e60385c8c1d96fe7381f3a73fd4085d387ce46a81ddd9a02cf9c02dedd4c66279d078cfdb945ea357845ab924f13be132a27a61b9c76677dff498cada1b9c4d2a07946a27edfdf067b011d5d18b9439e396bd56a5d14c3ba9844b46c4ad852b8609c2d3586bdfb88e8e370c98ae3c7489dcd6f2d5fac46fe314d1594606e503f567ec9452668350456c47aab76683f9a6926a8c024f978d0f70e89368ee237d7e7bc3ef9e9340e47c183ba4a47ff7efd1ebe43c2cb065e874821bdba0d407fc18802ed56db6d2e930ecb1b1befcbd5c5f7cbe2252793b9bd856e6df078331bef37a5fa8fc1026d4323738c3acce511bb5effe4c6c7cf47309565efcb4dd7dd206bef69f7524b7d387a27f70528301f99382ed61915ec928c0f22f04f9724d86656b26622c11dfa6bf54eed35a3ea2cf79261bd6b407b71649a569e509b18244c4437e24e11f9d5d3bd316cf220d5991e95f67415224e906205296b9e467b8ba020a020b9b10cc96f2d92f50ba91ca56423fe1a04c63209e949d7867bbbccc03739721f9d1e378e7408e7c94c644da63835ae1bfe942b666f40967c3c9b2f341537a5f9989fe9c299d978933458909f972948a2831bd4f3fad90910a3a29d3db7b16aec819784fbe03cfa4af93dd1a917d02a4ef5d860300d0883f331dd4c333bfb8e433723fe557b730568d81d0f", "6b6fb76ce7b4d40f1fc6e0219d773cdbccf76e8096eff78e23fbdadefaf36cf05d3ae9b1e0fa24956b12a73753ff23bf2f1e54ed38112c6a65821809ebf6b88b5a32128d39e9e6fa75e84bdedefcdac59b7926d04e4787a4ce5a84e76dd2c0fde94b158eacdd7b8d12792bde566c0b510abdf2a63b21ed30be449cb1d4e9236dd1df557eecd9d2dd933f39721fa18966cd4bca7327237d85fa022940a48a911a27e92d5aa96634157c49edd8e9de097a99b36260640f266220826d32790525d128be9ee71dee5e3fc67818fc0f67137ff6e958b377ba8ad1b1a0f1dfa36094e9c37c1ddba8688e31351f95c8d73b5b877f2ea2d4123923f231e772e74db59a34c76d43ee56ce4d653a7c37643c20a01daa5720e6610f73c5b7e56fc20d431c7ca30130a1b81ccae8eb2176d1b670eb8e88281064780511195486866381228e757175bccb8eaeb8a191ab6f2a834dbc775a9487a1e7e1a9f899306487319f147aaf30fb08db3394c450b49378bc76e960947a7638df1132519c88d9567f3d1214c8fffa897bc1b3fb4a217db0bcb8581b20a904c35bf0551ed9e4fca38fb9456985b6dc198d51bb2671f37e687b90f547746d8e692752bf2d361e8a7b2c2eab624016078924ad8d761ca4b462be26426e3d17def78b9d50e7bd0c96001c5ac4b7ca1d34c8935b6dd5e64a24ce9d1260e21f5ef824c9340063c929690d5ef152cc25fea2f08f0df9a33f6b6f2cc0424ecb9d9453b4890f824e3c4769c7960fdb0fb6b0f9d9cfa5c722838d75c646c0d073fcb1b9f8ee27755c024930ba0cea7f1bd06d795380f1737fb81d6c2e850d9e7767348bc6f98d222838824161936afcc42b3eb0ab43da30e26a0a55c09a345132784e6e116989262027d19db7392d7368a1597bafb8aab6a0e3e4fbb9ac1df66fcb0049923d4db282985167e90a22ffb4e135b3c8d710dcc582a7dc0f0e0f1117024c1647ee60bd50f4c6c282202f7244118c0fd3f24e0e2af38daaeeae2a569b6dfbd2e7cdaf54d1a765a3a9107259346db2ef9b7b7cfdff0c17aec1c1474a5bc3e79306c7cd55e7b1822b442a28ef5f405fc936f69c518ed22b0049335472a369b746028b83b84a60256e47cc1f537f585c9e31539216b48721242fb55949dd8bffc6c67087d5d67f5bde336e4be6b8338764a6d244c8ae28acfc644f937217ade7bfbeab73e0dab9953346b62c52b8aff24bc8f25636e04d832863225122739be9aaa67f044d46d73153b9d3bb04a49573560f3a976e0f2b09d8832bb85163a203794e63ec5f4e9b16a574b9596767513b08758d10ff5b43490c9512acda2e3f73c54b7e169fc4eec34da7e44fb9c6bbcf384181ff79c0281a9afd4350352faf53dd99401b0a459d15742ed854eedc441ea206ae4bf6fdc8f832fefde2da4b76877a9108f67ecd9c88e4cb0b16f8b9", .Okay}, + {.Log, "82ed70a53d3a5493708cbbe2de39ce2eb050ea0b01c6fb9ab75b2a50500b6a9e862ca55a2f320e04c2cb43667ea40766e60da2483974d19bb73aa588bc0c54efe718e3cf25cac4a22fc3affbb34cb3c6ca2b929a5e6eeb5b9b2327b44229684f84d8181dc409626c0b2349a8d47fd226297369255a0ad2f1c6b5d1bb33ceff172fd6a3abb4ba5ed9c0f47c62d7b20e1cd2adb045c9880e751933f622a965bdafd0148909515d1ca072e908f402b57b773c3795a236aa5a70918e2f77c7a4d47b50f644b236a924fffda0900179011a6e9b4bffcc43c4cf2482ca7fd92657b65206b4401293dfa5ee41cc77890a19b784ec786f06f06f5f664786999ea81da65ab642ffde0fd965c7dd549063486935e23c3e13dbeb10b7aef9a32da7c967ba83f29a76963049b0dc31d3c5667e1abf27e85280ba0c5b03640bc61140ce5e76f8f254090d54fb51235f1e666f5fd5998786547b88e914a06dc7ae0d562079865548ac4b5d3b12582be15c956988db8ac8539091d2421da664baeb399d29638fb797e928270bf34575b8926bb8aeee6964864e34ae7df2ec497c9c62f2e84a7aabeb2af62bb56d1f700212c6fe9bbda840cca1f4bfb9d4fdc57ee85f2ccdec0af39c7514fb9cb44edbec5fd1088641462cc6e6440c5711ee8f61715e08339563b152917c6b31fe4a7643302dd8b6fdba62bb496fb2789c52b8d4dc9e7a45aaad99", "b7fddd113230a7e", "44", .Okay}, + {.Log, "6febb7ed1ed1090472121407b58a5173046537d4b6260088a295f1c4f2da21d37083d67b0c24668eb3e7e7ec2f1d8107ab76ea0cd7b442591e61ac4f2d65a64421d568a23f2d2d019158ee759889d6362eab1321225e09d7d5431691c09bccc473611eb156be134864709b1783146260e4ce442237cf36f705e5d69b5a08d18f2ed22598e52ba792ab43eadf80eaf756e8bf0a328915bd44b4eceda017d42300e71dcfad3b70b580ec20b49ca01fb25559cfab98ecdc403f0e2bb9371797130ac1b83f1468d6e9ca2377d50cccee42cb11902673b347b0be0c4ef006b7c88ef4a2dc3919377f3c2fef9ba4bb5c6d904ae9489ce406b798a53adc3f10e8192149dabe8ed1dda75db0e262e0c531beb8db390339b62f8d732ef1f1d858f6f6576ce23ff23b606cc2c19fbee679ea2641d9fd324e7e7fa6fceb0c21bcc12a018a93aa5726eb4144fa51d7b3bfda703083451e7341bedda481a11d2c558d4a5a0fdf7704559a50cbf0ed3d7aff7fd289305bbe0e594cbe44858205ced38f181ffa8e768a4c33796e486090e5f48480a029a7200d36780ce5d98b68d7ef69f97b42a319b4176893d219948569b753d7f7ebce10515133880485ef8e384aedad9ec2ac643d6d54d3591612b1dfbc131a94b58729856d9daaeee7e169195cc47a34312ad824573f6b8bc57041abcc62748db3ad7b50557acd500c142033a6e56cd5ba53", "2bc678ffe0d7631", "47", .Okay}, + {.Log, "e9a197df4ab3cd7f37f14d9dd6bd0d1a7c344fe7586324d741a7c2ee509490283aae15a35292e834ae43e31b1ab294d3af82303310042b68e12d02e72a7786b4da1103eb095c95ab7568de29d8d4e33139f68658e8912f53347219bff47e5cb8afa617d52a3708327f77634b8ae772fa2307d43e2f2a0b134e317a8307c79c99f53eb30975b32e9210edd75b0bf22c67253c39466095714169a5f0eccc94f69edff70f7619bc128e8c76811d7df955ac368d35e7fa9bb39bf1a7789e8d3a766f14ba27e01190b9c54b00a5543db624a25757123342dfb63cb9f4ff9944faa5ddca44b663cf0ac780310390fdaa83c6af2b796436f0cd51cc8dedb4a0d2a949100767485fc7341fa6009ad4d749fb3311e549f56041c690990b63f0259b50c19a61ae3f43e4aa96355a419269bf0a127044a2a28c6b04cc7aa844c79ee805b5dc73200f04ccb68ba5f0c592092371c6365f76d4ff7e7fb9539c9712719a2b279d2b35b1d35fd245ed70f9fd387d6f8f6a1bebfb42557f803edaaea321c7f82dd6919456ee4c96af6dd4f285a61cff13bfe8482342c47d54a4e4eac1023f9d8a78d896fa478b8b82f6121ffd0e20800cff3f7a95394207b3c0f28507714c5d385e296fbb7177636d3e914fbede4bd1c91397a5a3b8c5df847f39e7ee8e8d4d671862d706bf64d1532dfc3687d0722e020a27494c3804f95d08213da38ea373ffa8", "c62f8949fbeb994", "44", .Okay}, + {.Log, "e6fda3f37326c64295bb70a07fc776c09006c369e32154ed03a5a3af2752af5a36ade3fb1c98593fd5a2b5e67dc7e9c43bf6436dbaa36d831bd354379a44c5cfdfd23510ffb389c62e3701f61e5d374d1402b963d3f51a540f40f56aa36767083025ed206d26b230bc3bdecb74668dee28d9543baa5189243f467da6337047fbc9a7579ad0fc7db55deb74e0cd0085274901a847539acb77f7fefd53ee5cdbcfa8cf0bff3059d2cdd3b939d4ad7a1b86372cf60775dd3207632fcab32113cf8cb77d6e3fe8c2181a7855f306f2248a08f38f84760bbbe68a3f56d63b7f313038c49c6df9f723fe22b7f10ae8ba5ccca2df44f0a2fea14c9c45bb18b319a54a42e7b0b6bbbde4735e5dde2f12853546175edb271326005d367753a7a976bb1c61b7759518a35dcc0fe6983791baf308f4f9015a07c30222eb19601dcae612e59f637a25bfe00263a1b3aad02d55892f9f34f6545a3f02902988d371b2c974f5e5b45d8660cb938c639ff549ac935eca974e2ed4e5c70d05f3035f219cab36c0d1f8e61e0ecde2693a30678a018f7df6109da97659567eb42ca9f20b87935b0198515378735f9c5cef4e6a1e6e29996d512e54c2207e29df36acf6926b2a301a4bb0fc6ef9879d39e546fad545c47e88a36d65529eab57ca8e2962ad7ba53b92fb4a015c3f2472ea0f8a8a770b85461d2505af449433ac5586f72468cf5325f5bb", "a114a80598ef979", "45", .Okay}, + {.Log, "285833da5f2fdd792de4f9bff37b6243263969dc4956a4becd875c6b0f5238a3948a5f3d0d17b45ea4680c1f24d15e070048ef257f2d3afa12759906505e6f3d754d8fe245bdf9e174daab73e334e5fa921339760faed6fd4ff33431cef0f40bf201fef1652234b0111f533ed70a03a05f1ccfe0e0858165d70e8a12c7876ceb5118d01e5de3a6558bba33d2c8569e01775f9ea9fd765463e8cd282dcc79f7506f5b7633cf68644208229b9d94c7b6dd1386bc6ad8731175209654bb0ee3bd103a5d3809e7f048bc9ff79196f9469af0f7a7a792ff1e95770b4d3280565fe2dc2ccb148af53f1c09670c85c24659f351878fc54a8036d3139d5a4783ed926b85a3a021751a46d373bdf3b416df8d06c36005aa539ce59210c0646c72f5d2176ddd97842158d92562e5f1711882e013b24bb1bb805be35363f64091bfdc115debda704e0545411a6a2abf4e50ac89d95f7e6f7001393034816ae2a1fe11151233e0daf1cbbc11df25f7c5f9e979aa09f648aff57c75e55a9ff82b01713cff0d73693fc37551fcdf7fffbe9361b41266175f677f25b96f101c71fc5dcbe1e643bf1df2aa8ed09463d15a3f37dc16c6f35ea2b2806f94b7a123b63c863dbfcaf408671993045196b47d8ac2f74e2d858299d318e0bb9e7ff8b1c96112bcc14df3aeee9676fba675d59948ad31965877230d3e0cde46c84b3fbae1f987cefd7ff0f4", "bf12d4803e8b201", "44", .Okay}, + {.Log, "4289e0c8965018bb35250a766a79029519619bf71230f418e0c73f427e3d3c3f8737591361f8e9485bfb86580ea50283040c8682e63e7de1126e4937408ad1ff84be497fadc6b53914a07887f27f68cee641a4e492e3fe7fa05a604162ce4a32962196979daad7aef0204c6cb12d6975a23675f92a2fb4d2e078c23eaa4565d4c14558162019d033f93452e216e62e2112e314abf3960dad8cea8e3af12461ff257d68b253d105f0e52b436a95a7ba9c725ee552d7b90f6f411a00132566fa2d9ea534eef33836e531ff6d96e5530409e14d75e1c0fd0555fc8f8cb11f4781af5ccfbbbdcc8581ded28b21930adcc7dac47a47462ac9ae463626ae2eac4d32dfdc5b63b2bfed15fac65aaf78ba9e27872244ec01172e7e511539f01db83cb95f46f53498cb2509b3fd7ef95012e317c40f098bdb35b29113ce823e929487c34e32b64f91975647097b49e834ddab46b42c957fb9ca03f1a95d1326e93d640e1cdc7a4d3b4fad861123a181dc7f41fe344e55edc75f81aa06c23b838f4dd0b3af3b24822218d4484d629bc0a03e50a6ec66987debedfa31053f43f62ae608b3c13181399be81e24ee3f60a6c43ca08bd1627da175a3dd9100bed1873e458b6ff9f591c6591b623c64fd84847c51911545263dea53eb8185ae51f25770d8e7820298d479948a340fa2c883f0a2ec88f777e7876fcdc98f5fcb86c60b52bf03c4c6", "5002ce4a7876352", "46", .Okay}, + {.Log, "62b31a8b1d1385a473c532bc5adc9d1242a64358279951276bcf23fa624d8089aa1839a8b08399fabde05d89dc0c431dd9658b35f680b4bcac4ce9b35c673e61ed8dd306bc7d0197a0e91403b12d745ad146cf620701e9e45fe41f878570cc2fc3ddb2efe1e8332c3f037b5b052c433f0ba5f6dd737618fb4dbe6b1f77152a971fc284991ee51d368c052c1db9ef58a280d38b3f156fe3fe0cbc701991d664939b2cc109f7011f77280eed9f5b7f2bf3b924aeb89cae5a99f20de702c79aa10f32f385bd1b166c8ae2a0dc7b93d93b15990ee3c5e7dc4278e41cc90db96e83f4856d6f316f25e90446623c399c9ad8f00a943d347aed431c12b2676506af1c079539de7752c3e3a57cbea86802d5dfd7d63ace822258cea35c75cc7bce87b67f8ce33a99afbb43ed57a7c01f68a2f248e4fea155da869bc128d6bfa790f574e8d2af16d78ed82d11ab0ff64791d89de983a1bc2483e24d3abe61860db9e85276964876f52147e6e7b45a4fbe070a6a82bc6c43ca230c6fe3a50027dcbe80b1bc3f75e5e07f55f54a391a7e88e12e60138834b4354e9d5bbe86ce3b702f14e6f8d42a33bad610a49996316aaca8a5c1ce0433607f41ae39712a0d670ebd5f5bd1253fa92929e736fd0850eaa1828aaf79d987df77353b796fe36c2769143c08234708e98c6cec965e09b200728686914a2ac395f4943a4488a519c52a005c5197", "86aadf660460a1a", "45", .Okay}, + {.Log, "5705451c1b96d2aac8c9213621e4a1c92abaa467061572eea427e9c15c807f7667726ad9c618099d7d5dd5f6fa6318f35fc0242d2d02e3beb839aeb74d13cb77997b8f1429c74e788e34f84568bf6b5172878059278d212e510baeec0e72c40fc4d4505fac99c48c45ad4f9fa9853ab1bcea9e1120b7ab3d483f035b77e3a6abc576d28bb2bb4ab357d36fb6558772bd935076d8f40074e1bc9016bea74d001b243da6eb77c45242ddcca2bc3092deb1fd1e1af49c4137f7e4f4a071cc0e74f4a369b4607a37e0536359c3cea7facf17b40b304edcb6b3e12accdc54125792be9aadee27a24bb7e71ef22f583a0d3f8c82d751090becc4560bb4c3b43d62e6fab9742f6f1e285e51a406e02532195f1c0112f4c1a326605c8ed98d74a36f0f8f6a178e0904ba5cf34e84b123157b237a40cc40fc3d25ee3db146554392530ddfd3b15b03e503698342ff8f099f9724a49f5151982d159c87b227e7efc8f1d48fc850af6dc51df48011abacb8be78a6eb2703bb92e3b738055b99f89c03c88e91f4641434a516db841285304d66364747cec60cce624f1f253bfb0b8c48fee1a9e9416882db7cbc99efcee81b06f95dcd4f66b9a6a26611320d45603ea903317aec754facf347477ba1a359fc988e49564b31a5df5a3b6414ab84c316df1ed07b1cb3001d6bd72308a5568b5ba67f4ea567594845d97a61edb905432359db4e2d", "a6b6b8941eca370", "44", .Okay}, + {.Log, "198882901a1d49b5ccdaf8d4e19a0fc1f78e456f9f992757a143d1c8c67f5af819cf40313a3ef92b5ad4654a400466dee0c4bdec0f69e1c6149735e941af8828236f7a1860a40cbbc18a2ddffcca67180378dfb83438a3d1546299866be727f1cd7e62763326c06c70d5495b8fffcaf8e4814d616a4193a060b3a9a94ad6ebc73660f07c118a34bb6ffb008046331b99e46507448d251689478065706c6db82177bef79ed2affc73aa756530b4c3c5ea11f0b225de127dd2eeab37f7b8af86c964ca9dc683212b99166088c83df31e39d3100a453dbeb5cac18d1a09223b67ca67e3111d0a7a22d8491e05186422fa8448c821eda81fbfb3088982280b9da8a1ce8d477454777d2126bc799a36b36a181f2d79f6fea596b0f80159ca1d5a46932cd1a045a45f4c4bc8471017799867614f6f29a676a2ca70ba0b18ab7950d6adfb1b760d7ff191a49d93434940e585f7dcb05b0c81240b5d878104cafbe14a6f8827311ea74f466a19c556e5890660c2393ca0c3a3de930cd6dbb547a3f7ba54025ff07f79606a8b5e8cfdf868165783eee29db128aa828ad685b924806e2b0350acf6550ce6b15eec15d6292c7df6fa8ae0858a225c00fd6a2cca6458035902385886a3f76cfc03f255c203922a6c588cba660415a498b3a71822b260bb1439209c1cdb5758505f1e1e0a13fd56472bc72b7de8729c686fe291b161922d5c6d", "deff2c878a0a961", "44", .Okay}, + {.Log, "99c4dd996fc3a082436fed5f7714571f1612855ee0c3865c7230a32a33b23a83dfff0ace5a0b1e3cfe9b8c40400d8464613ec4b98a74226b36730c3c3a6183fbcca75ad9588ee257c8a36f163350b592d35112e96f5a51b63f65e6e0e5ef2d9c78e1905a644983f9e75e6c1f4013dff650ce1804898693d9104c019cb28e187a7dab0101cfde3d272c2b5cd950b1b5b8bffbc59f9304813dc1455719d37468e6aa5716a772dfa21dfc0e6e8312ec97f0cb51ace9bd17fb5769ea28e92c85606cbd99b5de1434b63b22d4ff45ca104acc5421f54b73cbf3ea8e0c8b506c1240918f9bf76134c3bfe0f1ab2194b236dc8743a6eb9faa324ea738638442d7b0b49db496cd2f5ac65940fece2f1e5980c9ac64734d9f15494eb8a8184b52022faae2687e3d5e588a718c9fed7310cfc8c0b3093e66d64ae19f5fc7b6c64873b8778c02387d81d83460d21cbe1f823e0e7f8a6cb842178e6704321a492fa6057ad2f5e409b336ad7b170c338b929c7b812ae153447079e9435af2eb1a1bb9ed00496ad541fd880499e4e0a9855f362c92bc006c292a5df697ace27f9b62840010b6efe15404a7aca506b10b6b2f4f2ece1e25882b3a7aa03d4b089ee500c7cf879d47808419517402a59adfcc213b4005d16a3cc4dd7ac0f6350352cf6157c8ec506bbbf60d6b6655612a5a49891fe7212085a7e9216fbee89e3a9ac0e43ef136a559", "23ea627c8abeb5a", "47", .Okay}, + {.Log, "a7ae7e794048163d82f1a894185316dbf220a6b64fb996c58e0035e0644e2864b581c07d9a7b332cfd2b0e5e48d754f5264635a17708d8fc53a2a655489bbe45051296bdb3f88ddcee3111df5e8721a218013ce80520d9f7d57b0aacc8a328648836d3b6d68cc16b2843f2572c77b2b50254ec8088e5e9682a223570188a2b024d82d6d1981f8691a98055ce49e76dea91b534c796bb0117a7a3bfe35c607e2422ac2caf20a408f0c2c4e4ec5fc0b939b772dd931d1e55fcdf6c1103506e95007adc385a81a79aa50fc465c92c98523907ef83190d00ceadefcb40e5b6d426b345a004978d6cd7368a41cbe7d67fe71030069943949e0f23a211dafa8ed43f90bea8c6d57a42ed0d676c5d9638e25968a0b9852dffeed4d34714205850f42a43434a9910c9a330f2a0774923fa6440b880d4a0987ab3c0cc95d0c3c6074d70159efc3f8f931d97fb691ffb8cf4f82e617fa65e2085d2eb6ea40f8f2ed13430e4f77c56f9e2197303b27e3e768ee3bb243fc3b08b08cbf8995d918ad63ee1534a77634473ab5ece25c62c947b5389c0e3b88efcadefefdd6363c37d21acbce5312fd502a1fc6e12818386d1586d5e6f71c3082b146cf01c4a0f7f0ca178b5652d493afdb792e08187a982fd7bb91cb0d556a95a3856d5877d2826daf35b5f018a33249ebf53174a56b8ae03abb6bbe9846a88e72d1d12d4d1c11cc74e4c841a2d", "e39e5f3bfff45c1", "44", .Okay}, + {.Log, "fb8b1ae34a56aa351b189dc78823e5129e3a1e3f5fadd690576081d2c666c96fdd1e99dca6e443846d4310dc6d2cad6f184958c58f3f632abf99928d33e704bf76ab6a0bbdeb15235f776f7ecde7918da5695a3a37ce8adb3e87dec22f4ea4c4ab83a1ccebed4b7beef133b028560884f85a0c3270abb8763d3cc6015fe2425d7f13cc027aba3af5b4e6adcf787bf96e53df1a16d96441261e633caa6f28e81a869e8ec3b4667e6df8693f63bc0f196c674c48b67b6f54f1469b379c2470bbf5d79935a20ff6b8a700122172fb801b2e75d4e757d328497c0ea7124b279a42c2564a124767dddd8ba3c766690faaef82388b81521f96b2d601a670ed89bdeec121374b670f4eceb08f3778f33ddfe2b58e15b72d1edd7dec1c9802c952d6be6bf434f5730e0b6dbff83f261b2321963ae843dcfedb4af4236a0835a30f01b074cdfbe0b8278e338408efbe36d53373714d4b243ba5cc4bc2079c6fc5a5ccad97b9522c36613851c6de6a46d4d61a3907708464c5acaa331ab2c6c350ddad372f0a9b00ee26d6c6ce2b1c1a8489366b80f3d7af5ee6a529b51040a478802cacd9cd089fd75f0bc0a9724e5ce44bcfa49645a19a877217aa65b19d15933f8325034a4ef9fd232d0d510c7dd0c1ee6656bde42a6e834cfc26555b55876e344eaa59e2291904a9a0c4c3613efd6cb45b164d560f65ab1bd6f1c6dfe3e316bf591380", "569b9593ce841e6", "46", .Okay}, + {.Log, "543be003ec903a0ea60c5931aec853021320c8d421c3182c8ceefe9fc8b4877c09fd8e791420c842b7e7d6cebe56404963d9915912daa05e8873bb20453a1962475f230eb96c8b34c86ff4243a59089b4a54a5db903bafd39c406e14109531f3415e09086fa931d8a4a14f8fe98e6d0485c9ea2ead581fd6228957012db2aa735adf6008fbc8a2271089431abd57570424be2593d7c08aaf511c25f071ac9245cf7e33535e5047e7e137b5e2edc960f0af8505f010a2658d7d50b3141cab472953a00d19e3c9e46b484f9b019a2d27a65003cf362da76d76070c6cd6f68224d6836cc68fe68155ef6d5ee77f7bec9f4a7eff53c54ec22bd51120f451df121d98b1c46d515e1273ade9a0325796d8a950fe588d0a2fe90b757aa144fb7d974fecf49352765f62c61dbc44c6998ee48c21d64258b516e2308b8b62a1acdaef3e1c7b890b0cd61fb9ed92d59ecbfa2b25a0817bb550f55f3a9984986ca1fbe6add0d2f6d3bbcc9cb3d6d7d910fdc9182d7c04442b3e5e36a8d6930c54a4c9b0c5fc392c1b0be8bf12d7b35ebf42bfb64da9534f26f30365f46b674c21dcb0ab06ae820eaa90e7ce06e5aba0e72a328fb82ff8e9450bd4e07b508c55ad90143ef5e782003891b28d22a1a74a35ad1778f98cd86a6d7960c801cc224ec532c90692d04f39cd30d42aac6b2532a9feb64fa7487236c274af558a2f0b3d094b2ebf6661", "d52dcacd4b8181", "49", .Okay}, + {.Log, "f53b2ffdb711552cd45c96c02d32291d5c729e5063c4702f69ad8cbc7860dc79b653568d4d2f2bbc2ae3c6992392d97d0123afff28d6adf4c3d6bfb2e26550fe6fc67437963649a0fda720f392ca7612d9d42822f520ac539c65070ed50e0e682cb4804feb218805fbf2bda62cae58cab756aa6b36ca9938f5ec21f051a4daa63f726754641637bb38bcaf376da2ac975c506f25200f58ba968aeff6c2d5817e19d3fc2ef9d239da14294d161e39b4ba05f17cbf1450fabfee0ac92befb908db16e0ebd3f24f768868cc178d9d471edcdef86ab6a22f2c17fd712f8cdb841d70d55455bf0f90af1e2e2e4c74dca28327175841c68b66f896faf0ced20c24f7560ca963e2f591a7b85f7f174c2b97e0805420b6947157ecac5577875282d06a40dfe85018a1c55a9a89553d466d32df06f5b2b0678b1b9ac3e33a39c8590b6dfd14d1c734a1631ae92d98145c8e4ad09a620f98211a6a7c9e69d03aab40f9675ceba48d4e03645e36b15b3648c2f34f31a5ca368f5f0216248f6782d92aaa3b9e3fed5626a04032316c93e8e8230ba64485bbf9499cc2fe595f2adefcb03438d97948b567e8de90b16bbda8b00f8b1492f4e04b4b029a3130d5b9ace6d067b6b82c72ca07ecec271c7f76f865ca2fec4b10cc0edd6b1bb530e9f473fa741fc75371b23050b8cb1fbb1ff0b690de50f9ac3d902d77b4a0366523da15716c042ba4", "6f0dd57b6ada5e5", "45", .Okay}, + {.Log, "3813912c915006d718b918ab6d0628432b7afe69a83ff50ef21d345ac4d9a7db69e764526777ddfaf098450b76ffe13ebc99e87c47c07e6ecd6ea49eaf60266a063426fadace0816788aa40ba1bcce8df6aa8fcf4aef971711eae2484cbdfaf0e90bb7686c08531643b523d34bb918ea91ee88c2af34e3f6bd828a9c44e8088000447759402f23d460985efee86acf06623f189340e3205f41b94d49b4248090db7b174ba6b62a294b1d2c7aaa434b6b09f896e1feb3f193babfcaf20051719dd1cfb4973b72ea4b370715a3904efd4db17622f2fbadafdf12137919ded099a6848a8e677df413bdce988ac1a98b2290109392ae06e6caf03c2cdb03544c57a5e4552c7b4c997567f9ac45d861df4b277bd388e4c2df64da5415c161a4d491615c2d1d57ecb2ec98fa381e6a639511fbe1312e6b05d558964ba4d4d14f765ae8ec2917ddeecf739131c66ae96a22fb52a1436a983afa065e6b21b63875785496c9a53e5c2927a5c2fff076f5d3c896d1080e348533152b26e80fdfa46594c41f032faea286bb1a2eae20cd71d23813a98c585c057d4549256ea52b351e6389d6b4ad2d9cde6509a8f95880e4befd6f665f6fdde57932becb2cddfc99a19d47369aa1b002f60599fb0631e4584644b9a1051cb0d99224e3451352fdef659770c0a3bd84b7af7ea9af17b25b709562be18999920890004824ab2cc8656e4db9698", "55b976fc345ca02", "46", .Okay}, + {.Log, "b9c51647a78125b6e552640064a1c9b0c6210f24b88ac5169bdf24fbca47700222ac0d92506c71ca25ada635f257e51dd6db6a24969df1385b3cfde64a53d5834122306f2fe424561872891909e84a6b992fee373f047f633686125066512682ec1f7d6b719c1ef4d2b48b0b4dbaa883c585f1211435af5748d7c57383f38a48d51195acf4e8c00af69d0b6fcafc154bfd25a52bcedcf306cf229efafb67d35201458bf30bf09b6f29aaece662fe91203cca838d12e03855c61e2d4befd47e2ade12c68fdcd243e7a6d3b240bdd3ed16335fc676201d42c62ca9c734cdcfb08a1bc1fd224360a7b71a07cffdd9b593f1f22103786aa78f9266e397046dca4d17a17faa845f14600d6b25f6637c1240504feb421a32e3316a58712011d2a85794b6d59952878d4499d408f76db33a441c83b30110a07d680ae86a1e248a915d59e988719ad1e04b0c7d9eb3812123e13d6489b740ff4991e21f181f841358f970d22134004152256bff4be7d009e0edebc86c8d43f77f8cc47e011f6bf84a4aba11b4f7bb6cc59c63e04e77dff1fcb51bb88b2b6b3fc1cdfe7291e3ba9fcaec7ba2052e24cc88cc9c512657e65e209080ea2d2d32e3f387e6391c1c350a9b709f782d8aaddfa575d1bd39bf3b94a5d0d48a5fa9bd8123d39b1c6f9dcc42c6c3f6cdd9c214101dee2f27f585c0308c44ac2458f9d329714056ec3ddb15f4ffcd1c", "5a86c81e5239362", "46", .Okay}, + {.Log, "f77057a34cba9d425a3702fc4a9f0ea05790c884e5b4f2eceb292e0bd872d71b2a399b835883a5b7cc8ae767a1b2e5dfd1f9cc713326998c25f6f105bc8b33979aae9e9d8e2a668e4228ea8b4042ada3ba14304e1eb365d6767c27e122edabd10a02ebea9fea26cba2dbf1962ca64720833ae01ce9e5bfac71701b06464815d0094864a6cd4a60acbf31cb29440bda7d06b615bb38df1bfed7d6f8cea800870e4b4c4171f435e165832f03733300708a374153a8ddf7ea82f1e8a79ef1b06599b68e53b53a924cb5f78c4032ffe7ad5afd082978b02f013ceecb264fbbf1a1e169f02153a40e94174a4a85767f9410202f4ba6471dd0e56d9ceebd6351335fc05d143e59f7f17fd6d3f7bccecf5d99013416c29a5decf9c8d2486f3772ad3beb056e0b414897d28926106ce50efc169f66b5e03d0420cb04d23cee81c1b32479225615a9c5aca8cf4afa036a259de6e9d9aa328090bc9953a7b95def3b841137946616e1d41834a0b31612b69e9f90555bb6bc8e7b93bb1c49d36d0740af1cb4fbf74b1cd8f43b88ed936d424a209271338b10e5c5e476cb7a54acbfefcc26e9e5ba6c89e186135fb3609127240df6200c5d4ed6fff6dc256f14af6daa5f3ffa773859ea0b39b2575a5421d37f43bd40a353aafa17950f23bc59be1199d9c4701b8fd2334ba06680e4ec1830ddb371a068c8fefe727e37d7d0e31105056289b5", "98c6ff2bbde91bb", "45", .Okay}, + {.Log, "8530d4f2a773279b9ba93997b3ffc4080a0b854a94875c52381bc7dee7462d9ff84cebb0038955ff59200fe80287fbe481b3ec152823a425edcddaf148ee5ee9f5f56b13843566dcbde38b84c784e01c5eb5cb6034c48a4eda88951a151f9a73e9082bfd6316fc01828e8b01cc113956c86a90933697824cad7edebed93f916d7b094312e012b05cc4399c30cfd750c0a1a194bc6d6f8a996c238221a1462cceaa69cd6a90ffe63119114d72996fab29c8e1d21f4cca305df4a04479fff10b1bc3a8227b6c4965af7c4a1e1763ef39b4f5f3fe3816cb4c41494f6c044e35e21c21ba05d17562418c2bfbfcd8b2c970c9cceed46a94a2dd09598180d25c6a70fa118a06758d8b4c7dab72decdaaae5f2976115f960a8a993e74fd081802388cc09fa8d7f3a99aa96e5a6a0bc417f6a33f219b7dd566bfc91df1a467421a68bf6929101a7e5b20ce1571ef2fef276afbbdd6d74115ac521995e204e6a4c37090f62cb56e252b757e57e8d135a6fcd439106381318c4ad217e8377a904e3262ed339723a48c7443adb745e3fda603b62fa883e9afdad58b7ec1ef58d84bbe33396e59984b98c0e038604dc073bda3bf5c3799737e031d5486cad1d8ecb7aaa123f3b62d60e4c3100b123cb128b624e57c0b1a800fa19dc8b07d263476b33db41df3025ae7161c67efda8ab6e2ca21c89073dcfa0ef6d1cbee3841f4ec29b8e7a938", "66cc301ed9d14c5", "45", .Okay}, + {.Log, "79547f7659a60082f60d90a64bf927ef58230eb7989cfa0a9999c1b7c912b8e11bf7ac0747fb196bc8bf6b4740cd0b1371fd0e985f33666924e89d58c97e1622336d456424ae7dbc833e703c6a8b1548d44fec1728d3afe39d41c0f24a166f91986b44ffd4d74001710ea0c11132e9f804b2091d18d3e92508a101d5f76c7a43518a84170bd0425b20e9342651d7a0f9883effd9fb0ac92fd8774cf2050f1f66c34f528687ca458050c6b10d8bbab77813a272b4ce9efb81c60e5bd98040bb1a194e25515c758506691881dfabce0f7e12dda9b10b7dec4e1ac41450ecbf92d6575d2cf251e2a8d09af8c79d0cb2215c8899375b8788a91a449f30f75b7ecef1efcb4fe13d09bf6d89a6be3dbc423c3b1a8a4dc45ee1de01a6298405d910a1b51135b5a301960cf415b3118bc2964ec6fe255d85ea133239fed659f9ec032cb9ca1d7f0ea6a7d6a857015cc8b6ebba7c9d18ce3eb1d11c3822b0a8f6d8bf2e1c7aed44a34926543f4b5a579d2d2ada041d7c4820f1a6acf89835a98008576e945c576151fb5c20041ca93c3ece937e4409b5cdda6e8b1aadadea707efdf5e2f5a3ff1c001f8c66d5b367675bfdfdbf1a08ee2fd42c2faf38d2e4f9963825df10fdcdacae5702c4c9f6a202c36bce16edd8e02df0f7be375e5cd1e45466d5e0be82543fca0d74f1e8cf300a13b874441bbff0ed693995bcbefeecfd88123e9d7b", "608086a17ed9fe7", "45", .Okay}, + {.Log, "2d8431d718b660458a7aad9f0ad60542113cda099c85c0a6db1c218f5e83cb0342fda7cd5a32dc67058695c2a46dfbbafac7ede987f49068c711ad58793db77ba29dedad4a4d415d8a9069e7d2e4fb5b1ecd87a4f354f06f89575681f70c1e22b8806371798efba23f75db092cd616a5db72f9251ecff8cf31552693d9758954b22b9b04064804eaef5baccdae3438e19db2008bdf2e7569dd242ee0340d9efe4a195ec19f781a7bc265e29f80ffbcd3702ab5233267ad0f9c2849c87c62209494edafbbc0684db0b522299f908c7d4beb6147266057c9e7aa60c5931b6ee7ed8add0d1b4a5620c4ac5f1d05bde7e2803b0c57b0a92cf89bf4e0a46fabf5bd7512b45a3652e15e73dddabe93fa7f4a5eefcbb05b0aca80728f33db3ea762152b53a0e47aa795c96b7345ddf32b7886c0bbb2372c6a614d9f3310c542c98f72cc831aded8f12f4c91f4b2da99df78837dbc602417ff17e3efee88bcc3570ad9c470ac65e25bf980dbb453b0705be73680575277b4ef1b7fbf85b62383e4b739d75c64fd2a848ef133e028e2995bd411c833ced5acf027a75c6518da100146232b11e3b8b016616e965b2390adbad6d2cc5f39123143fb12fbc90697c5db6751cdb7b4e5f61bef83a30f8312532c51013a52441fead7d2439a8d2ce1a544496c26e1cc8234576d8b065906c34b2b8ceb2bf94bbb4c4ba8a08a7de1db91394e60bf", "43f580169ecd15a", "46", .Okay}, + {.Log, "756193bc8a9e99cf31f71450c110312845a1b38139b9a94ce3f28587636827cadb728385b98d424e9d378381dd9973f7108bd50304361c815153ce85eca19372529c82030ea77f0c1e3ecb2da2383a009a5f0ae24e5c2f1ab5f86e333365ffccca4a47290fdc99123fd85d71c80b5db304379662c74697ee9150e82af55b178a9bf3984221a0d02cfe16c8c7039bb0bf021c3fe66c4bb06251b995729df3cac163bf2e2b6f66a788e472fc3238b98a360f052c2ae421980f6ad8b53340cdf91f534f5ff7305fecf5595f1f4ae3f742a79ed5e71a5c54db9484c4d343912e97a1f85495d9f4a848df310168bdf25eef05b95e67a970b645c657a6b47f9272d3fe8e185d36f21ad0a21f74cb89d8a6b3246820f20f4040462662c1e359205bc65de53a4c417f7185d7e59602e62f10a008cca6605dc1f377a0727b9694cfca1d6992161d56fb8d26c25f4ed0976022fbc969643a723fb02ac4676de7dd566e71d3e1792fba20d3ec0d130e20bc2a7c3fc7ae13faea8a84353084f748896b5c1755f76c0d384efc316125d1b4043f061b4319d35f9baece5095ce6af44f7519fd01046059d2ae3722e6dafddcd1909f72570ebb63557e199f2e7d29f4512eaa9664e8e0bad59e246dec893a0c218371bc5ef2901c2e5ce462cc704a16f7bc837c83bb39e3b450833d91130337cb5b0704808468a1ea3df74646b433362c53bdd0e1", "c0e75dc32819021", "44", .Okay}, + {.Log, "b34286af6d178032b1416bd71779ceab967d1d1874fac6cab5e517c76d71cdb296334586b54619e65014fa657b57874f6594dc5858abffa2745cd7fb7e078a74d2924593171c62219f1e31585d24bdcf9f93322435a408bf975edbc9230ca6ee64ee15a7bbe5ef9701db0bba0a0f90a650eacfa58f56b89c07f404567ca242505156a284eb8c3e979308f9d168a873342f788619ad93126dc50496f64ff46799f1ea170bec65f5723e435d1a4d8e5e1b5b6976f7461bc0f7409648522176228fd371aa637daec25a9dfefc82114f85e7b328077ac89b17dc152b2cad5cd2ed47c9c63c7d18ae18940ec99a1cd75214cefe7ec3732587f4007542fd1e95e0906a74717987c21a1f4ddba88c5fd2a93ed12fa59bd04224c5dec7f7483e2be12defa05153231c3b2271089fad14312fe5501ef8aef63357428da21284d5c1e78cbb70022e2871b2b60cb7c0c5c98f78fed685eeb1711b748d686c464dc631989f91bb31c5828c6b5f30a1fa6b339dc08cdf594ef9a5f779089c184d74ec6c3869343a769195930ce1d431f8cbde7af8c76b979dbb392b1f31c0afbba48476798b05df98d75860ce97430a6e29dbeb9ff36a1b69e8a42001105d3b73d4abb8d5998d4c5c403ef420797f2543df5c2578e6e27b616a24daa7db95f1306ecbdf43ad41ee4244b489c570b03de93e447498cf1dce7ea67dd132b0489de2ede04201cc2a", "f3ff6dddeda12a6", "44", .Okay}, + {.Log, "f9acc8ceb0e4a5a64aa5e0e161740a8a9a69f7ad8ff736fac590b778f7e82cd41ed20b58ffc846078ccb47603e23de6d20078410912ac99cd3f1e6bc652744d6f7cf3467a5df1d2303ace9a5208563c74466300d47930408e7d7889842abbcb3f54080aa8759a6bc3dc97d26d75a2d52b9aca55b394ef36fbb50711ee4b3748a8e5de62ff8ac5b0fad2a2375df4d74ccae2c5c970923a38e8e98812b6b76c28108fe60fea30676fb538a19ceadfa3af7f4f461ab9bb4d400792ce52ca77754263e2506d0c598d688e18a8a39f9447525dc915dbc9d0925f1c0a43e93a692e73c56b6a5c9d821f2a60354660ab645b6ba29abe9ef5962cc9ee4bdeee9304297134de75b51cdffea1a919928357cd0d820589da05b992d28c237bc4503f7321798ac2a9b8e9a120d84f870ab3a4185558f97d02ae6b5eeeb6306ea822071d7669e21ee75f3dc42b64e85afe4b3aed303b96b9b541d3ae2e80d2d0370c1997822a4de8ddd976ef56ec024215a9d1b02999bea8c031394688324247390ccea58cd53907dcba6cbf1f736f451831c424261b35e76e039dc18948f40c5d7ad7fe94022f0715fd9d1986ff2e113b3e015572aebe6475a6161e830f9e98267901ff3b17a8d647546f8768db1699c176d1ddce8f120b887d07f390b73748b9cbcb3e8f9c17e3e294de554f69bcf962f7b33d2a02e7f43d5b75fe9230646a60f58cebc3288", "b5e74580aacd5f3", "44", .Okay}, + {.Log, "32718d988c6e7b16354a7da0929eb24077664f9ec2e58d995aff2c6a2155487cd5e3d908f9cc0abd750487ebddb680350582ff10228d861d6fb6a1915446ed4d6c6ef4f20830c2287f189976454f665153b57726ef8b91bcf139f093cd0f67d6cbb7a0e315294bd595f35ebbe915e28650ac9b1744fadb076168a2b9278eed6c76eee77e20dfe687a6157d6d6f75d16567f740fb57a90db1e1aefba5ba59b457335399c1ff681e3672dd5f62153d7122c5edb55d6409c7a69c34a41fef3f95df84c8c6d3eb092fae2b75c054d41370ba78abe145b117d87691da7bdbf5f3410671b4dce208cfb8f2e7a65b976f44f4a044fdac6fe1f70ab159f56b9d24970ca25bc0df1aa0e2e2a3145ea4a2fac6748a8c75b7ebaf845efb6481d67cf111df0f776ac0e31b22e9cc2e2d809cdc888dae55025bf0f8e4c432b61c9a26ce24db1269522ab1552a8e79f3d8d62c6c6e5bde29218547b1b9f062c737fda6def457b93f2aa9e583433cb8d1bedc3535ec6744734a1996c7c0f93d809463980c49cc9daa6e6aec1917d572fa24ca085b0f6fd6fbc1a0c118179f1c3a7a77633909dd5872b17268de5dea4b4af5a854d5620fd89122e5683bfb6b8dc2628b61850485294a5c44aeba8d8455b259938d09bd965d0192010fb2545e0e14072205174c4a2546c0805cb0a2ecff2c03f18e39e06fa29cb4b6927d8a1a2fe086650fa3f9d8d1", "f2ec169d66582ac", "44", .Okay}, + {.Log, "a8ca8e6b21d0c23a758c059ecbca8f39f81c2eda46fdfd602d75d0173c74d50271c87008a7a5c30d92e83d987472666b6fbc55db24dffb287b2949066bba1008a75e6f91ea9bf16c92b7243163f56358d8c2d099f969e4fc4278c08a6552e58f6d2bfca5b4c4072f8d71ff8fe6034a0be6a7057d88dd5150a394c2d8080488bde441f1a6a0c7aeec2dc12a62b9231f8a927942787644ef9fc4e1c04c75992e2e98218e5dfed2793d15573fdd039510bfd90e539bc5dfdc1cb60aff3c9f38dd0c1621c7be31058754fbbf974f45ebd9295d88d3949dfc051adf700fe43630c3cf1af0cbfd328a2a7158c0e353e5bb49c184e8c5530df32727465b9a85046a79379598ee96b7321e4ff74b64a51ca5c7857f19ae6e6b33cc6e06987d0a0aff04563cb50f078abc4a1b44d0f4a170856e310829b66879cb650ff0dd2a353b4d5c709ed6385667474d49feee9b3602f8a502493c26870b0acf9e645376c4f1eb6b4f3f83b5f7676779ee3f86feb21c246797446b0bfbc5c43c5b15935602c240b221a47eac843c1d80e0e12417c53f116d4593f89d5f63ad172fd70e97e3e26d4dcfbbae22907488e0a9c3daf057bdf57735e0d52d018d14065e43370a0d3acb9bbeb8256949ccc40d1b5d999d87e8f3710566d95f0bb1b69353360c5b513aa6d2518104b14bf63366036a958c54363d7e02f9e1fb6ddbfac82a5cc7bd6c9c931ddd", "e86477349427027", "44", .Okay}, + {.Log, "8e55957fea4289f85b57f3e6381af26a5c0e05611715cc8fe8a0a39deefc78e0bd1def3112a5337b2fe4ee0405d90a7c1e784b5c07afb80d574e54bd6b075a6fcd263c1bee2ef9fdde3e18219d2033bca18698bda3b4144550eb0ba053cbc178abb01902df19fe29e5f873d2bd5eed9fa4b4ba0eba9be9dfe9f524fbcd190390ea35ff7a4767508c78d1a18607d14e13e827d8009f87dad2dab52e0efedf9012ccfca714c2cd7c6e3941bd36b317338dc3de26f78b8c63dcb2c5cc0a03a62928c4eea2123d832098f492b09f9ae6cdc1c4b563feef6222985eb5f5f938a662e3c2450ffa0c69059eed767bd90c3b4a121c90d2dad42e2c99184e401993237b20ca43948023519b365e21a46be9be634f98f9ed29b83da837e09de8daa0c076291060ca6d066de902a18aaf681d666389ac62725ce06970d914e00313a17fed2b1a023e367b73ae5218e2cff12d388844a6c8431c5cd44c639e0633745d37e7e07113c7e9919213abfebb154101154c63f2920efdbf5679f824ab52b33ed6d1ec13c655bb54c842f6a56101c8e85027b6e31c735ba16db695d6fcc4a4c0e8135719a2ba93aea1cef5acab4d9bfad01c9e95869940be9402450acc4eecca70f7d55e9c8f0652ec59edf70ab8c7e0025b002e1c76e737bbf09de6f36ae07668d9be734efc7781370dc53905523fb75a42646063bd55b562ac6de95c8db6bda93ddb", "6afbdb1bb91ea1a", "45", .Okay}, + {.Log, "5fcf9ed838a120f03bd9fd778130cbf97474c8b5e7e3638da564b2b72618dfe923884be033430ecb6e609b1441d26e47ede0a6892fdeb9bf20cc0878be9180993c948fa75e2f7edc99f50e4294eb3e12663e1c8a5d8cc7ff5877021ff432b41448496731f2319acc961abdf2f1d88953e6e128f2fc8bcb1542bf19bdcc253ba1d0754eab58b30b9e5c409109d3cf49427946ceb3a9e7ee5fbad967417d899e7e5ebd4449a220c0afc845c298298636c05afcec38d86dab7995bac20e553e4bbb49914f94bfecd344cedb70758d9597ccd6d05af428737a95281a3842a9dc7110d2c1aabd471d02a20808e565526200248bc6a80a79a657a74f1a73fd6b5980b6f273074917fb3aba49ff0399e1b7783712983a280876621e55323d26c16b6821b3a06af008cc1f12f832f15b4c06e0fec9d2683e62aeb80f4410283b05796db86426f743f23bacf5b2a46a119bb588e037d6c77d7b02c955d4c2b35511374d30c63ed2cd9cc7a774880673649ce573f6b47c764a66b722f37a18184b6e1cf3e8405c24e1614235e6906dbc507cda3c2d663b832203de7d39d188d3985cb6c2f4b4b5df3bf77fee7b4ab8f41a6456ebe37ff1323388a4fcb483eedf7cb2a0f8066be643050138f6ce2b83fab2ea289731ceb28087b32ffc0c54a8d9188d7b68da41e222d85527f771c3d9fce959e2d303443b8baffb80f0acf9929e2931509147", "d49b2be386edf2a", "44", .Okay}, + {.Log, "78a344e24bb422063e39427c7e87a6a51dbae5fc43002feb24d901e61320bebf5168aac415e1a8ba3c151846717967d97c76f936f76b81f122c5fd4afef36593c79f362b85668b6bade5f176ea9a1eab53c130b30fe3413acd5adfa6d6fd854a704a7c398cf8a90c995fc3ee5e0319429fc34772703444087fb203ab849da78bee7861be9dc27cad1694beacda922dd777979e24e98480fab89c2cf45ffb75f999f16a08df31885dc6389717251f7f985d8a71912020c412cd09adddc80601813e14acef589ed754bdc9e9b1fd96b0cbf93eb52fe049d3045e5ef0d08b984c0aa7f3f4f4bf047013c9729cc3886744b77b664463fbe9ffd1adc1c59c10aa044c339b1273ae238df174beae6516edae6a1a7bfe06cede24dbccb962967df902c8a752087bdcc8018b9ff628f92b93da50a1c3786ee2a0aa76d39eb1d2c081b710d20cedafc4673ec0ac5a9ff6fd263da8a90e0a3df50800429003c1803f14aca4c3445ee065d7200a139adc7c81ccd082d1d7f38e8664f8d4e147dcaf62064ddcf997d41924c2993f3920f3e16cf568c451f3dc1915c919f791182eb43b51edfbac53f0daed875d3df5b73ea0bd238cc38d1c48c9000d742d216aab51624829a66bc0db9b5c69ed9dd3431f20986b0dd170571f04864a4837ce23e06d5f19b1230995bf9a17a9c58f55ff1f6f3c3296dc016078bdfd87390ec1e1f3c5f139178a", "39a00f27cc5c2ed", "46", .Okay}, + {.Log, "a14c8d5f5291e7bb3fa95665d19b16c2942a365bb475610459cf7d55e1c5172ba1cc0d5c8c37a98666be230f2f097cc7e7f50b71fa82326f904848db134b96c1fcce4790870e6ac7cceabb1ad7e4ecba5626e08260571e1d107789c3d139fb99092ffeedac21705267f469a6eb428b0fa0fbe923112563774d3e9d93a90653e8fc0bf6675ed4a87d24aa6ad4b0f3306cb4b7974dd21ffecde6fff4d892371f88cc2ac241a51c3cee16b8abcf0eada1419ff6e6cfaf73b8a98428ed52fa0f2b4673faa78fa6add41ea861823738356933689f8a793abcca5a88679b095dc5734581ebd457c429def693c1a14b94fd0aef7229b3dabb00ca3da7cd971cbc062a08981451a79e731f9ab1c61b18eb7a0aa3d12b99c7147015c6ecd79547b416a3bd4983311de23ebf5ff965ede93310db1cd177f0cdedf2c8facd0dbf0c908e7d36cdebb0beb009ddeb88d3aed9888fc4ef51c980f9f7a176430e0f9a20fee4eb4bf0029c3364d0084f985e61589ca4b1a981c195d03c4bf522328359da5bd9d72c834d574842f7398f409286e977eb9cd70651b5535c2c2c91a762d9a34ac663e590353c6811eec6a781c2f2b39ac68841ba601572d3d1b4a1ce7cf4cecf350775951eb102e4bc05338e1d80deb360cdf88cddc781160a91aa7f7312dd223f6777dcacf53ad695655d083c190c1eada6520c3883da734f2572048b504e2751db2d", "98ce1e2300ee410", "45", .Okay}, + {.Log, "c97489a11dfb0aa926d7eb21960de81253a3216c3967931a970f723b7bb90649ccf46084cc8aaaf7ebe4ab2062f2c39d1b127efb21a80f972dc67a69d69dadb10d596113b6a67b2fcf7a5bdf4bdd6dde7289d7e37d2aa3a36e9a52cfea9fa725aa22816fc8bdb6a06f1b069b72fbfe5ad6c486baba23336d33628135e9b3b2d1fb695486df58155dde50b1688c599ad957d64bfa8bed942132a9222fe928b32d66078a570b295b0fb329c538d5c4f3469228782b6f6ca8c123eadeca533fd5d005f6e0615c31fa7616b45d9d24a9f292eba24bd2f6c78c046a61d07f9d21996975b88758df5dedc2b9165d2892e39d1b8929ad19a95b66c10c7f2a5f91af7f077e880ee88b8befde3c1f7595b9de5d9c1c3e71bf341e2b8cc64eac09e2c145a19a2803550bfaa980e71734b67b718be4c774ac9e8dc2fbccc5e939d73f0a58bc9ec283fdae113019620c59687e9259467f07b7b3326133257da50b4d38d375575d8c12d24b7fcb74683aabc791cbb7e56f651e03162d018f84de6965ef4c7824a44114655e07c63b41fe847f5d8d425ff8ca6e12b084c4e6859423f38124308ce6694db748890fa4de7e983833b6150bafa6ac11f9c529bcc628ba182e8c8b53f3f4f114440dd01cf745f5ef96db4b97bf64887e52bbc239aa6ba2e3bd299ba0225dcdb779be7a0e599e174c364fa5a5bbe90f82504d356080e7890a5a9ab290", "dac4086e1e9eb8c", "44", .Okay}, + {.Log, "38f864d447427a3a194c892e151a6bf89d30a1f3d8038ee61b0efc16c891dd34c9cf0106abbe01c12c9d3f2fe917df97f92907550a6d93059cb6d03081415a21ac5a67ae6a1836e8994c37bdf18c97601a42a1ddf1aa1c38f747593c35f57789680119fdb94fe028dec9a3b46aafcc79826cddb4805e67780b8305d7af07ff9ceb8d6b9891bec99f2e4b88cf4e3adc3525772aa10fc0a86ff7cd9bbc57e94885a09d19d98f8a4560ec24aac827d3f609481f00dddb1b9d2be5d6d5c339d7d5648f86798267e0cb7d3f3e438157bb302b219d0de844f8b08a9a1cf48f717ff62f48526577e71d7dc74c2041d81c2dcb6de4809c5046b25d3e54ba07f42adb52c1388d9d22032c7ca8021cdbb4b34ea0319e57e2e4d1db7a0f5f24eba0b06b519aaf278df3507a016ebb2ba87b96f0ba1e063e1d577d4e02f5d211942596ff91f9025f49d8f1b56c4d221d66f474849606b08dff0ef68e28b2c647b8b5b0bb227226a103ab7cb7eb94324a3c51164a479437d1cb0a7cd23a41b35e564885d096b68eb57cd29a9bd8586ca4b5ac6933b9fafce12029ea67e33bae07e390694b337a8e344442139dc39c13a6f66429ec661f8b5fab6b05b595daf376a0f5cfa4420640543fe5b09300c884f6dbe18a492b40d5d0d6187321053ac3374970f43e7a9e9cc8c9dec9c88d2daa690b22fd9e9a8904cffaf0d42f594d889042d782c2cb0a", "3b6af2bccc7850e", "46", .Okay}, + {.Log, "8ea0ae774e940d0e568fc9f4ba987d9e2c2dc1d7d27eac2ca7f3fb8f5413803f0d21ed3daf08367966b285539c7b998cadbe781bf315f051cd65b8a74332ac85346ce6172be44562bb951c56ab6b1d62dff22fe965a67a48aacdd683d80c76c22a7f04243f8906dc57c0b1642d6ad454adc339261d07f0da07d8df80aa0a3ddf581e3353ff0116ce4eaea3b31cb054763bace0463957faa072038f136f9ad2f90a4465e656e82596648caf65ed619a16c96dd017429178738b3890ef5ecc2bb4e9b6f1a5c487c6edeab2613cde4a2a72669711ec6f18bab32ea9a5bc04a69595a34f35cc82bd8ba467df955a3b362534121b775f114ab1c1fa1cc976045ba84fd74ff8648c794fd2abdc12dd7a76ece8f98ebc103380a0c866d43dc3c4021207e47c89ef1b78c538db9e050b51445334848cd50f5979ab79f820a3c733dced3d456478a1283e9e4574883171ae430418a1a11664acd2950f28e8f50194e71f0f40efe73481e4cb1a61d63f00c2fbc1d825ab3391529c4d3bb276ab7df19229389d9c2e3866887ecfffa6db70aa2740f75560f3f7e74478b051bfd9601159722c09bb2573e8f1f400bc4ef6eb14ad475e755883e66d53827220b829f39e668232a462b84ce13c6ba9b357376faab71008c0950e20b2c8a067652bda069323a6d12aa96cd11bd47bc6119a269ace81c238847f1b4a7e5120e7aef01c8deab80c5e", "367e04468644769", "46", .Okay}, + {.Log, "9663d72975ef5da23a678eea8b863f93ef46494690cb07f1742678eb0f87400afc759a7405cff332b5eb124e95631fcd959e7a966c694a4a9992a4408628d484a6572858505339f04914dbdfc34be673405506fdaf769cd2befec2a7c7c59a4fa10840801d3cec08f45aef7eaea772b5a5efeca0e59290d6662c11a0d18570882c0a0173396aa4dc3e0859a39ce7c311fda45586786b8a0fb44d6ae73cde371fe5aaa2668d5631da93ced8dc26028e2acc26883665c5604ae9992e71cc8698d2da3597f8032e65fff0d1c7df2e37e184609b3eb49322cfc1250b5d63fea35a1b73e91c655b6a4b860b0eb98cb96520b44ca79fccab17f6bf2701c81cf7cd775ab924e4e75fbf40aa3bc567871a3ede008274180bdcc26d5a74ed1dfdf0a8a010fc38a3693791942e8d6333d1db622a2ebb19ec732a330563fea4266c9501287326abade493c062f854f1166c628bc739c407573e4b5be27299d0e3c0f982bc47acc0436ef09b455f1b66b9eaaa29405352815588bcaf45207301a408c8bd1c7e4c7cec7a2ba55f324aca17bc4a947c856dfe566227d72b4631d70b09082ecd37c97ac61c069dc1426c46338f34ddee821554778f282757db0ae2d9a02cfefc6c2b8c942c0244c9ce6f83905a9dcd0a7bb2ea1e7c0453a0da1366e5c9f5dc80d0592b6d60702c3da7a2bbc34f574bbd5a2facee59c6b08e294160b68cd073a1a6", "cd2477fff399df", "49", .Okay}, + {.Log, "de72185c8d37f94387981fd07c6ec3c09d32214d458e4cfbef691c6acb8da78659d4c870c8661e686560996ba094638ea1a8f5c10b26259e0cb7ff081a86cd51585585436533535524fc176e254fcedada12407017ec6c53cdc5e302847f51db442b6450d60686d1db4e7b5f9113bfc76178424082295eeeddbc8489518d0d8378a8add90c56fd33f546868a0aee5bbc787d7ebd30afba227e96828f05c51689ad9c21fcd565e6c64575f2de28370011908dee94207689bc24ad326068fc27293d4a4dcefcf8d9389b411aaa7795705a2b31de0781ee6c83bf6feeb27b3810ebb0338c421d1c94e6a25857bf89d2bbc4988669ae76aed66ad2f2374a6ef7f6227a74d66169ada5646431fa896f438306a20f65b4e778658acf659d8264586162c515defe85035666f7e2aa2380977612fb3022a7399f98ee0cbde7c32f674030563ea94e7f83376f6db596459a1b7b6139f77973a1bc66f244aae3f581e5be158f9f7a7655c647cc96c566b78857a3a7b397f1c2bcc756f3abc36271a4f4e76d23df28831f24030ee2c2e2209850451525017aed2548f5c485e44f65f5075604cd95690c447f754638d5ee6f5c33848c5168454424026859bf36157308b97390ea221b666a82d1d5660b7ce3f753d3858ca3a7b1ebc90dab845dbb9c4b0ec8e34a4818378e4ff99ebc653fcd71bffc98f6b3a565b4c84920b4fef60b04c88a9a", "e0df80933f94187", "44", .Okay}, + {.Log, "95ca55f2afadcc17f48e9308fac43293c2d7f8c0f1d6678349f3c6542a510669b3338c124a7bf205679ea98b1293ee90df23b2dac665a12554bc1b2fbdf1b1aafa02cdb454b3f9c511739b75b909546adabdd4855ee38bc6829360d9dc52cd1661017343538c170a52883ffa348ff3189d0060a37e52ab51a352c3423498e890e7c36bed3f6c1ce7ba71f828f2967a17381fb762060494e7ccf92ddf88beba7fcbcea47dfc63b13c2818e6c1e50d2238de334945253fd104f6e9409287e2465f9a7ffa6d36d22c4bbd51c66434e9f1907560a13c828e1390227d2d211beb121b5df13eceb3c4b39490a3f6066c6743123218fbd97d17b8bc079a88959717aa1c0a2fe9a3f75a6a41b37310a7babd9e5a6c85aa5aa9b4ba2f1b75de594fdcb1366e829f49355101f9f1511596b5be970100b59c147c6926dae80f32b5b41a2aa355b70f0337878c43f9f5b7a2f789452a1324035edab073b2af98aad92ee911399088ed0fd0dea3d07d8f536ac58209ffd26e60dbabfb2e6a82ccebbede0150d1ceddea6ad7e04aabf968af9cd34864aee7722ed4aa5c5dbbdbe0a2d68a5ab080e628be737b3550ae96e6daeb3d9682faea0590e3dfc5be955623023c20e5a99f09d0416c3ee6450dc386ed559857f60f376862c43cf24dcd4a39679a1de1896b64053371f2de07defde84a39a783653871ea81f19863e9a5def6a94aadd74d69", "909fc3ef56ad688", "45", .Okay}, + {.Log, "bfe832b93987d1cf7fd66f1be68abbbabd6092541fcb5a26d12a0ecf6167c2f1d69ddba7dfd8a0715aa7d6cee1582ae2b7669d594676f1519f2e5e62288701556639f4605de6b2f50e67c701cbb910a91b508c4200abd9b972bd59e354e249569a43c530e29059821dcb3c3a37ec67a12eff1aeeb24398fc5d687a302baf1b13292e077b81195656f540e1e2adee75be2534dd713b88627abb7204d63160d64963f5c535e074a8eb1c133300a381fb7383bb98f84c9d86e80a55f7f54f7010f6c7208db36f5d6ad3d46ce28fbfb23e860bf6749bb8266d43aa523dee49c54b1cd8ad73a1e2ed155773d31f0757198b3670ad39856ced452e6cd62ed7e9ee54f2132718fa7ca1ed9c711c4a0200ddf9c2a725ebcf74e6a920b4b48efadf5f58c6e41dc0011e9995ed9a700a1c0a8d01e677d31bb003da001be9df2582902502fe61e21c4f2d3cc6a3bddbc47d8dd9bf2f67ae8b3651d2ea07167bdcdb7c13ba087aa65451550bdbb1557e09ea215aad6f2bc0ad07ff0f61567cb03bfa2af369b926afcdb933f1c55c44fc102c83582f1d49561569f8a026a2cd0fe8a7c808094f729598ade112ce63d5b5f0b696792cf4a7e0d4518a69754711809e6aedfe338e9c8793d1068942fb8dd83ebe892f763e6f5e60a420a77023a7ba4b9913c7a5a565ce3c175690d415510bda9951927bab7d767fb9c2e6039cd2076d354587717", "91240f8c6241cd0", "45", .Okay}, + {.Log, "6e97b82aeccfb1fb687c9a2a2fc60fa8d3183b3e192c05e181ac5e6d1434a001bfd90a44be60f0459c98e0a461dec94cf15e12751977dee241f9e50310652da27c1ca01e67e7b8a15affaadc29b3a46301f73cddfe195a595608ae46460e767fc24e399d5f94aa61ba9f09a019108b6165db81562a4b08d95bcc72befedca45d559f02f52d90c4a2f55dcd3ff90180d0e618e12ed222e62a478e97bd98a600a00c775634efef52f0e1fdf96ebc093eaf96e9f8671b16fcc35e5c8aa0fde7223c8b8faaada13fd61fb64cf39c27478280d861f3b9c24d7bf1e36863a76f9a34e3237cba0df800b3c1bbba376206832e4522dc3e65148b8cb486413c7cae8c80c79c3a7f4771c11c9acfc5f5b612e0f971c2214ec892a397ab69ab6569f51d35dfc18bab89deb00a1d8ebbc5976a9d5f2b8570fd421f306e1d398fac1c70bbd964442dd6527ba2ad34e110ea732b300f75f016ade6c7cafe4a0fabaa5c74a30861792c5c08f0501cc0b69dcd9f47f3ec939fcf903db05812c27af89bd9f8fc3b6b39004a7d35fdcaa2f69279721815a59e4096c9b3a75b4d0d7996e37f6ca662227d3a09aa016391c42aa9cbc352a16737393b6b80cfaa8745a65fff967ed027d205f76fcd8c50047abba0ff8afe38377a6c2fe48f1049596a0065c8a6c3a969ac4d05ebe0a4c360ed86c1a56050c65cc2b5373d9c1efd4860c43d2f073f481f74", "b88e4e3ecfff173", "44", .Okay}, + {.Log, "f41ce3efe7c13b0f3a61d18414dd3cb1078cf39de8c7e784f4610acc12ce3c7dabbce7064c9c4ce78e993f7cc71f8705dd28c4eb4a46271674a71458f694bd670409c64a95e642190068bd135064648fdbd1a78320e894c09c455e68f441dd72f985ba6a6d570ea50e64c6f2c339d07d21d3619edd5ee455cfed90fcf3cf296e897f66b138268a37625f0cf95e7d46af17840970b7b052ef28b6d874192cc4a855f05f1130542803537449641db8981301a66c9860f0781c5a295abe37f075746c93ecefbbe0d3b66290a4dc0e936bf13573b1cf49040239776a6244b4a705214be335c1b5d9f581a2f5477e43beb1f97638b0cb8998a327241dc3ed7057088b7055f4253b6093b53c85b7db268c6a4669feaaf8b21d5a274b69c18242310e0a9a8c37234a4cb3d459e108651339f8fffc43683abb7a77e7b108803b469e680b69fb021575e8273f0b75ec192d5cf28bbbf7236751693ccb525a362649a2767c901168b6f9467b1e6408ca2184fe6434f6323df4d9712badafd562b1427ba86eaaa17036777ad96f6084c9a70a6a10ecd71113eed7ea8d3dcc68c2c644af2a91d10a5f89db8f36c2fcb5b2e94583eac9e199bb9af80da00ae3131ff3ad6b445ab054776df515b92fcc29accea552c37e88c41c7a2973a5e79a839bec21472eb7b2ac305218a47e2c794dcdd18f2a62aa2d7fb366bf42390fe1f9861bfe9475cf", "d3f82c8db09f1f3", "44", .Okay}, + {.Log, "43b7aa8148a20fbbd8e6103c52530cd7775fbff855a467a986042e655d939ca8fa93af22a0b0e83a1b039c19dec665f61b388c197747c6b600c2f749851eb9b19c72667b8f31059c1cfe8d01f4fc8a37dd6fc6a7402f379b90faf4254cea5395b81a64575c10498d0913792fae61de4c7dc84d85b08342177ea3c4ff2ed00b03693b86468a2b7b9056ed50e7b8fd433c2a4f7ddf3e0ad93b9bca44b15d7f18bff1fc688f9e135e8d6053f0bf169ea892c07cdb580392e8ba3758cc29d7cb7f65912e108fb5846e740646bd778b37d8112f4923d8b6b084ba9c701f67e6cb47d4103672787c56e5117d556c07a1151a597c6312e1c681d86c0ddddf485c1b8dffd0fda7070b8bb4430558b24a37297e530bc6fc4500b03385793f75302eef2f2bfde04b3bd079cb80eaac7a064d8d0d54e2e04efef1a48e8e52fbea9d3dbe5a272a3308b25914b924a0dc278e40743ed52abb110fa20690dd1f34413c6ef3734d9195ee8421615a7af401baa3212536ecd0aa0a14ff5e7b25b2b4835ae542a4136ff59102084e0edf40a5ae2df97f6aeeea04882e06212a99636478fc42ce350aba67cb535be0fd3926a1048aec6ae469dba14e77e623c79e389858f1c8e5937cd4e40f4ff2119212920519074d87711f674fb5aa68a030b1a9879ae4cf35050919adae456184302b252317c339ba529ca09b04da3b60e721e1256b9a32920a95", "2f9a55732e10a1f", "47", .Okay}, + {.Log, "7ce8ae9690f6861ddbfee6be8e78d6a53f91896798eb5a331e08223fe29cdb8c69dbb8dd3742f0fb3b93ca299c895691e72d8c0e901cf923d604e151c3c3b0910cfa6368bd3b36d50bc6763443c14f8cb22fe23f0399a579e4dd913ef11d1c293055f80bb8d1a1fd3f68e527efd9a4e138f217f1356cc811fdec5988578dd3a84a3a0480ebbc0ad97a3fa8735414d5bc0cc79f3b0d717969e940ebcd8323616ceede704517e559888247b758f079f061f6755d9cf405c12728eef6354c3a71de4bbfc394f64a70dba4fc566c950926f4a655c2c6c921174419ce4d5a91145d8ae4e3ca4781c89ecbc39a7a5e141586337441bc9448efc50f32ccf479d789fee3e8e47740257d2cc1a88fc5f4e1c14b372ba2d2822f864f44819fbd21229c55546c39145d6d6f43ac835e6390b3ba47992583fb1f0eaa38a47a320464a348a33c32655cfb08645d748262e0ed02b7c50dbba34eaa1a4726eba60e8a26061565f84cb9afe894bc00ba13df68fb8608e30b7b7b1d590e9608cb59c821d59ea6cf1ce991aca1490cecf77b6366f60ec08eb21929f7c3b56dd39a6be037ab6e18b61ce91e1ff54fb27c774a8d4a1e15e5315b94ec68c1fd24621ee3935802df71efe907e9dcc83ffb2c465757fe76fd8724fc23761785c1f395e2e2b1cfbb02315e202f81e3f3ae29f12131cc339ea4f6235db84c27d0eddb6203c109b88a9eda918d", "813b45ed2f58d21", "45", .Okay}, + {.Log, "a9d3fddb793c0058914dc29ddc047d156e35090f026eca5b0c8a538a8080f285e082077dc134cd44bd6cb769b0e7cad8219ed95e6017d35d333fcf346aa1eeb5cf3002d7587a0581580efd330fb3ed7619a966a38d238d6108ca15880d17f00429a17729ae581b35f5175469093e94cc21d7814e20947e5f3d9ae5a4a994cfca04d9915bd4cb4668b9b74d72721fa873fb31762e6728262bc2442cbc4c67834646a643ea306b393ed1430c777bb0247afd2c29507fbcaa87d07a9a24bf8f9c8abdee58ea5758d1595274458874ab8ede31b3763d6b7586c4daa5d064d973b50748053469044f77937867f2aa183eb0bcb2db850110a6e6533ce83c11d3332b4982f6380344602f31f37989eafcbfed58d97580fa2644d3afa9d3eaed0b834a396ab904f9424b321031d68768ba774785a24d3355b432f2acd9f8470c5df293f66468158627e349f0d64ae3dc913299eff5df08fe174614a628fabcea9fd45f3127932f74b9b42cb1213ea74012e5248ac890084ad3871fbf049b47d6ea834378b1500a2ee3a32dbdc618f733b8d7d00f9190abbb55208ec800d5f36700d15a9a5adda7592deef68bd638d1545fd8c6154db4377ae2712f5151b3c8e1d548df5adde5d8ae39e749c40ae97d13b1fbb5c28dc30c345737d98d7359a35cec32fd50c96a7a650541c2bf9dc40c213b9f81e01123f5bad1ccb9828347509d7b73ecdc", "1c4c8228b62460c", "48", .Okay}, + {.Log, "5a26129151fe74b8998dbc886b0f4cbb4ab72c3464a47f9124af93049802617e404f753d811f2d5f290440b2be038f347beca2f5aaf626422b30366f814b6349210be9a58439b55d432d9e1480357a66e270f210ded750dfc3a45fae866b32946985ab88f4c9177a491ba0388af0dbdf37d59c9816de2074ec2c63890043c492b7569792641be2ec1c03d46a19ad47358966920f290ecb7dcff218742a1b97c67f74faf415180b5b52cf29dd2f4113e88b9495c98a065f861eb965da620c3c7d08b2829f035b2a0023469fcca2731d640ee1419ebd1829acfb68efaa57115827f8e402993734ab42e76333a4dc9928db622913c22e917ae0ca0f876019cf2315312d7ddd71a25ca700212fe2303adef21c47cfb19563acdb91e58905351ebc1baf3e02249e3bf5a4df8486230c6a48d8ee3bd59031c2193cf32acbb08289e815a6e33297ade85685fb104cb3adc24c4fca30965a5ece2bc39bbdde9d0f078732a3f37b17bfab166c24fda6a6aa719761b1a6d1b22c3631119cb3ac58127ba7e91c3785cf13d167f7d4a8264f53cd0c85ecf2e9b699241825ea94fcd67175fa9991aefb2200e301a1098bdc7f909c70be9690f8015ee35f0e944fb66d9eee17519854c05f43610b71692d848181dc82ac77ef3e99650c50fa8fca3fee626e136c6995e954ff164e0564fc04114cb5efdf06887a3f1f0562954c9859aac6296aeb", "c07bb11ecd3e492", "44", .Okay}, + {.Log, "4d21f4aae5d2a3aee422ba6b7192d8f0889a94f5964824f625a90a980c5adb950eb1cdcc95a766cc642836613c8d4b7e062c38d8a1519c47c05bb75faff15832d780cc5522ef422bc6252114f6c3aa7ef6d9848b1ce25978aa837062894c6f71b6b2aa9a0a5ec0a937500bdc02e14a59c9f3e54439e5081aeb6287294ab611da11da636912333f06845bd199aa523b77d05748f743fca39a4c98b04965db5fa59c1d346d8f3a0ab59cedc11481f83d1319671ae8439fc93c76e24cd036ed770e481b993672191cd424ffedc8ae9b0c26dd57c76d70a18c6d45a723c2f844d685ddc3a3f462e9b0b0279adcd5841e738788facd7343589e4582cdabd6fb7bbb6e8ef37c4570b57bac72d476523fcd7a48c2dc606214c3dd2fa1a03f9db46755ff629a2f8fa3f881915a9ba4e464e673e5a0da94ad4e74ea4213b5384875b4b1946bad1c3d22d9fcb1e099580b95b7ba8d4e4a751a927e5840d5e4730faadd55025e6635c7f42be42aef2477e9ce9992793136c11e232f31d76178edbf4ce9e1293c17828af2374b713028ef1d82a475862860f60be41ac1b2f63341946b6cc994f4017b0cf0c7fea8c7fd9e3b323675f29d41c5bf98fdf0f5ac338d5191d5096c717c07d2684e4da559d5660d2b5c30bb91d1f4a602111ac19efecab8812933c6d7537a29d5f69c661db591d46719bfea764d491765c31a950b4e10eb88f5890d", "c11bdcadebfdbb4", "44", .Okay}, + {.Log, "64322ead43dd563fc50cb95c4925c2fdece7c16587da9d4b4fb45b7e78c14b20d63446bdd05861bd7563bff6d1304891e5c2e3436d6120ebf5cdeb0662cdc997b39ad9365d15c699d8867ef2641a93eed0d932fad9d6df236c0d75096bb2a0e9152af86c0b73d0d830a0ab57c54fd2bc34acaf791918230db7f9859ae10dfc116a937ce7dc5b53d542dc7287c4055f36c14f53bb999ea5850d3dbc8a8375c37d0e52e842034541db1ec34af979752e7cf99c65c9530386b2924311bdf7d8c8f6241ddeba3532767ecdbb48f6a332031004636e3c08dfb80ebd9797be45988f96bef0f4aa079ddd3e5d8524492f5944de7dc32ff55faef3cc33f20562521765315e77c70968a777899969bc4f830d251d23ad26351479cb00c0b1019d191b5d7061f184a7927b9356db36625d7c78253158f87081553f35a1cd869125125ae71b2a0a67d77f4843110075f5d91338b7a2687437dc980eb4d005135fa2b4df31754e8e91ddd820e8c3fc15fbd9816b7ec302d2f7517129346970f4516a27598b88bd25e75164218935495ef6ad35e8c84c1f1d567bbdecb1076391ef12be220fd4bf9fbfa039dadc99244f3480fe7d4bea97cad36e5308e8c94321adb30a981a1b9fde6a87265d6225a76b894d51dda9051a3f5e670243309acc3fb417835752d78379dc66bebb98ae7ac336c5eba0e93ec7ca266fee3011e610d01dcf234741ea", "5769d301e9e8d82", "46", .Okay}, + {.Log, "d2a73f2c299ccef90c7309800e6321184bb36b18b586a1102ab85125a2a9b00970ddf384c5a95a6ebc9ae46a34b73787aa026d05cd8217f051702f54d96fadc5b5bee078a36434f236b02e01e22dbc123b2436c8a789a4e341b5ff8a40af2d70419381437452c987d811b5660d9f3b8b107ce5fd6c81e29e73109b57f1cf2e7006ea6163ab98804d79dc6462ccaabbf163540a3dedf08c234ef59c8b1101d615bafee13efab760c96646f695e902146c2371228be581a4fc5e5e6eba5f2b337e03b1057af904c2e161fe58c404ec5ff97f9fe998f23937bc66b50f843766135435f141b0f33a66f2cf02f10cff66b8a8b8d02524f28f75f8c6dcdfc896269c8ad66e9f3b24bdea684dbba0545aea16a5db72e1154b3a6bda3e806df8f6a644ff97523c4ec71dc0a8d967d32d63881f482e0ff3c3dd43debb2135304128c02d300983776665bc3e1d93437fb5e2df7fdc0bdd8d3751cbe4f9d80b7b30a55056ddbbf5e130c130809bc8c8dc1638f742649ec2b7169e9a0778c7ad93f2089b9dc51f0d97e6c99182a9938e33bd839ef0170332957c3841ea83953365f4bf6c302ba871175988e4e153f10f1bbdc8b15d2f8d909b206b0a0fe02fbd8fabfd9d8d690247653290e4713ee245bc19e097de765279f5992c8378ffac439ee1dcf6b4a8a409beeceb5b19bc229a8462ff347807b0a21780dc8efc72d10349e4a6616316", "c4060711e8af26d", "44", .Okay}, + {.Log, "6d832e9ba9fa9bdce55d9476864f53559c5cf2d289f3bbad128f866ebddc94e95fe2f4388840e0d1b735887c6f8893b9ed6a5b5fa6669e22d8f1928ae3dfde568fdd03637e9f879af8d5be596c0015ae6b0182e1bf9625c5d0a4bade822710bea851ff727e0a552e086bb21d2da6df6c7544b97ad8e3c547ddb3f5be89de29cfc3488bb3c16ee38b4d3398fb485902941b80920314aa26f3eb5b15a05bbd30b90ff6d3e4f2cda9f6036b394c6e7aebfdb8989631ef35d50289defc06681fba503a81bc55ff657b86b1f3e75ab5f6e3187019302496c4e6e8fc4d33f43acc73dd133ef2f0f963ff4f4d2e7f12dbf77cbed0890d1850dc415d39351781467445565a8eb4ca6bee4b284f27b52517a29c8f67a04e1302758ba13d77538be2a6a22cbfcfffac5be384637bd2901301cc97f2ff39f83b192809c47db1b1eb7b6b1e35f4f0df064196f0ad025a9bf47da05dc24ba1cad288d7b7dd5c719cce002b6c79b8f50884e8c0abc4c5334c877fc0855c1996617de8dccd80043e3f235138c6090b1270d5ef13db9a5672f2f1af2c9a6fc43f7053c6263e18c425985f2d322e4513a5b1d9825e4af65f492f62221341ecd2f3e61e223151915fa906ca3bf5d10586f3a1f99dd30436d38874efb70bc9f4ec3d519e978e84debf1b3152a30dc85ccc0da7c85617a7c52726899164d76c131bfb2924816b5a88b2b187ccc14b8de3", "9967cef65c24b47", "45", .Okay}, + {.Log, "a906143ed776c3ac7823663cd78cc3f0062c4f2aa8b885a4837f51c4ab452038c47bf6214e50c94278ce5d9a9d23086744194d63769f4bd3b26581f67fefb9f56817d08bd40365c79465e2e1dffad917064e359ec1e11b25b1d1e3d7e4545a151aca4802bf5a2e7e00998b6938f36f0edeb8fedc02fb228ffd67ab5fee226904ae0201493e1eb3b4f5f782e5c9d34302eb16f4012ae81f240e4ac3f10ac40c73c1c8d88777be728e168262f292af432eb57131e033812a17953d56d046538ecc638b8bb587e7a3a4f8291a4ed8eb8c4a41b02c0a341331c7b185c756702eb14e7fe84a4710cfa5adb363c122f08fc59018aa684efb64bd64ab669e66bd3318838543ca3a87b9af0b4513ef70fe0976794358404aa71d493882f31b94baace6e15270e43d46b40a8a81141b658e45a263eac1afcb1def6924e1081607f946be7709e4208399d3c709625bfde363a841340dea5e81c423d21fb8b05d2f63a4346e36121ffdeae9bad3e5e47ca4718033bd8542457bcddb85b005d8b416f7d09d2d670e66f98545dbfac8fb4b726a020d9f39662897ed96efc36f9c456e1a8ced823610ea686ea16904aa028bcf3fc8c5441c90923134021df8959c01c3568e1785f91435db610b15dc0c158ad4cc5584cbe7e6fd22fc2fff01125f19bf40dc9d3dc4e474d45e57571856f9cf5f949eeb4cb03e6da5c9941c4000c154a3451fce09", "a22ced81e3c4002", "45", .Okay}, + {.Log, "e8fd6865ee84fd5c85c8130c86578245e4e17430cd96e3ef0b2cd9b1e92494e8ffea0eea50bda147bc09add767ca7219085605df0ebca3872fe8ee6c92cca8c4bb93034d77cd9338242f45231435d3a52dc12fb279f0a078fd3663b9860cfe604db4811bd1a9e0aca71695bf0b1c79c3207e3bd061488bc7743085d5c28636b183c82f7cc729eaa0d0412409f346ab0ec42ca8698638f22a4e1fe8928e3320c1868ea837d09367f3f71dc5bc891af3151780abf8dfdb286c5b7ef8853f9e1d71007208d2e1e31b464be8b2c6532d104a7553fd5824b9e46c34d4f04620c2ee4feb677e135f2f928a84dd79a8f0d9ca4d10a09cb29458c0bfb2d7543e2005e0a5ad429228717db7b1e1fb72839d1c6b7028d5e54ca1b65765e513c3da0dfbcd2a777ab34f4f0d8d1c1d9278ce80a1c9cea333d1f0342d814e03d1b81e94be916d2a6d51dc69b6a873762fee3e842f7711411f771d7ec28ac251734ee9f7d590d60c610bd2daabbac8c6cb1805c795e4cc4bf9ebcc2c1f14e88b11eb698d61e7543f4bf0f0557233784a0588236540167ad3354588278743a6e8b0794ed7b75a07299150635b24db615781f056bdc9697172282bced591dd76fe775388b68b1007599efbe60e59db666991b28d2dc7f6037ba489e57b0b2f86281dc7c7d8ad5cb6c0995ad37517fcfb6c79a58f586ba6c31bb08b644d539441f8a26b3f50df7b7", "40dcb1b2c537b0e", "46", .Okay}, + {.Log, "ed429328eabd0a1fe400df2dbab918aecbf1631af825d587d53b892529c27bb26935166fd382287440b28fd758185569ae0447a44586f4c3e1a80db35fade33abe58bc9c2ce2a72ac96903484551ccf82e151d7023390bd87dffe9d98f609528be84d99cecad733083b59a574e29bde7bdfa17804fa4e8bae771cafe94bb2a271955a7b760d2278983b2672c551ab71ca7b3374ee48d1cf15d022ead3950eee6adc6a86a32f1f08aa45316f7f17addf412d6374a9bd16610f1a1e29c5bf48df695f4f29d04b9b7ea10b72a5689f55624d6944684386f3b9a327bd860428907d51be3433b28d1ab442c6b81d18fea9409e6eee9e1dfb60dbc1ada96536bd7a16965ff89c4f8ec2f1772c3ec3935458810e30d17a6176ee207d4c081910041fefa7019fa63b713366dce31d92aa7731ef6aa3a1405d46bd7265c1acdc73f8079887935a93df7e29146222c999f5f483f5a3f254aa1ee62ea4ad6bf825332bc7758232323059808b1d91a8ee69fa069962a84e825fed0d8e32cc38a25c89991493d0834169b0a833098b446c309e2676a201a8bd1d591c338804e7dd8262a8f6bb2ea6a9a270b96c2448f7861562b582321b5d6fcf56123387c426f957436c9a728165c7bf35274356a73087f2c8ca4570174022f01870e3740d5cc1219e69bdac58de4ba440c76160104c93e44417c620688d8e5b44f27e13ac7f61abc0f2da3f", "80ae9d5e8920064", "45", .Okay}, + {.Log, "16da8789ca31363283d76eb70cc8f38ba4c71d362c8c3e3837236428992e77bdf9e82389148ffbaf6a674ad239313dd934db5f4900933a62053937b2925b07f476c8b9c0f4a485feff49b51d4e207118622aceaaccec8ea683bab620cfea47cc62bd23eb0755b1b27e3e09523b1e59032c6e7c3f5990e7eb176735866176659c9a217bb4b9b908df8d9d2fbbb1aa38b7caba315c2634495bde05080e206d6594060d86a7392ca2fce4ce4d3062b7a047f6f816d552d91d71c02864c60c335913e955052022ffa25384272f1dbb95da81a72b1da36a4ee3275e2c4c7aa29490097341f6d6dc960b0009c09ef633a22c31fcc99c30d672faa5bde01522b1c4d0ed82acad251c3a27acf0d2869f691521fa0fcac8fe5ee27f6e300b3b9888abcf83d62cae5517270b4ab67326c1561783521ebd1ad3e105c2590f076d5213765d6f2147ccf3922175c06a198602b923c933d4d9e4aa601d16b62431e896bddb0ef164f0f3b05020f0e1bf5042231daefef1636a8ca964370d6c7eb27f07fc20b37ed68358df89d3872585b467011b57fd2e2d0e816425693339aeab1f83bcf7443700c51d0da76e66201772aaf9cc2932d29e4df0427d9f807b560dbcb3e3cb7e39f6abe3aa9931e130757aae8b32ad2dfc128a2bd226ae65e41409c14d1cba15a12e8fb002845928cc7d2dff15284dc8948f0e8b89139d56f7d9f93c79e34fd026", "4da54bc70eda06b", "46", .Okay}, + {.Log, "e3450a09d9f34ad2dd5f2eb21cdcbd52106271e4c132ef59ad2ec2c62eb261981bb48fa66a82878a7c48e2de3d7d654659c2005376d2a9ca668d0f79bc9e3438662998be1c3daa0ab82ee9cf15c0c21a344428cdba45fa958f04c2d11a0916fb708b082400be0993f6022b275679e204f896f087d2e3a27ebdc221531fd1077b8c6337a273a27c0173fd93ddf374345e8d0766f6796887263333e9b71ea5e71d765401109dff3dce329a0644875d2a592689fdf07dc6bcd353c89e869cce5f844d059f8b9e0320cb0ebd5c9dabf1711e0586acdbb9f1c9fd28014cdcf43ee3b3003916ef84a2e670ef9cc2f5f5c813b5f3a411d533710f7025a497a8f8988f7c0c042a70ad1c09ac50c46acdbae10c0d22548bc40168c9fd68b3fd14ac90612ac4922b4e686e4c92dc9835efa88f9c73cba33923803f0c22a9afc3b389f579d5d4661a4cbc1c954e0796487ba65e50d18fcc42c15cc4ef43faac68ab33e8212b99bde476953f2aa3a0d920c3736f58fb29acbc0a0f6cd5591651df0db42977d048105ee45255d23ec09fba3ed807c4cdf926c77273ab2cef3a4bdf15f75d3821f7e1ea54500e8b60b9552602054d7adfca9fcc4765ad77cbff593df6a035e51c7e7620a607c04b773da8e696a9ee69fbe1237b42998cd6d383f8bc8de6508ce347adfc81ea4384f0be98f32c27c949a5eb91b56221462b9d041a22199cc8980", "b9f7983564e1f21", "44", .Okay}, + {.Log, "6d51e5cd2b824749b4c92068c1a3fe33ac7321bc5f084beb03dfbc03f407746fca59de0a685db9f804f3bb19eee0f4af5f9483a822b58b6c5ee66b279c59a22e7b4d17aee053de9fbd1613ba3407e93cd2a909fbe9477934990654c2ee26c5e75a27245fe3a3c8572783988653f39bdc652f341bd237e445e14cb4acb58281656e91c334f83aa299559300c6ffdf64ec82c4aa12e3008119910d3bed5a46fbe807e009164cb8f40fa17ddb01c8e4e57a00811a61cfc514a0076359abd68c6ccc68b7ee68d902a8c1d62e8fa2cd1ea23364f908714d35b2c85cfe577147809a650a5ac8d4275f47d3385739e8fc8306d9bdea9409c0b6792f474bf74337b928283b527d69bb3871f4a79a8ddc86cffd45b8dec1238e9a0ff4eabf147ea2c898f52051c4d8c6a0c0a9a6d095beb006bcfc39a54b028a21c8c9c8e4b32544a55377fead64c835b9a5863b9c36ba0cec69be79f8b59751eecf1b9b0449ddebd38f948797a07b22c6124648e36e2e699385c2d0fc20e5a2bdd195f3f8fe6a4bf2d8b704692d3d2ce28ce099344f43228699592bc14bafda1daa1970560aeb9c2a95d43f2455da3066be690f2fabea3ac4cb3c20b73802a03c2f3cf52135ef43aeaf1d940081c0acbb26697b494344a90f2dae1d96a35c3134e2f34d496e4791585093cde362318eb82423229fdda935620f489ffcf135ad466f2053b342c89cf94b57", "3adaaa5c5dbb482", "46", .Okay}, + {.Log, "4dcb869039c5defe820420621580434e1c3c48ce5951826b96f4e760287d023e411d13919a3301e7bbae72fd4b0cababf45ec42c05eb0ffac886eb7096d2ed665f09435f19590e3892e681cae79912816a20ef2ea9bf7b31e97abc0c714cb9456d10e37ce237810b1ae3fba3423602bf036cb9c44bdcd2f62ac67a44eba39134413b366a3a8788b50822cb55614981fcd710e76897627adc20501a90532e25af655d72e3fb3a5df5180517f3a341431f3524b5ad0c9bcf6bac7a80e7207e9331958488a7d0f2e7fe052bfe64bddd84a467029bbaf0a650a97057b057340ed0fb7b9fe7d6a22adcf68a021f7da6999eabd4a8bb0ce22610901e1580a0e5f341daa7b295b9da7ac9fc5b470201dab362260e43457603d7c215c96383e69b4660d797c96b8cd4a66c1434941def46f2365d64249a224ad19ccf7ec4bbca89d674d9553bc192c0ba327b6114b8ddfcf5e80fdf7dc3509a1f81290b6783a3dfe49519f092f6518d6aac3be1c88224544cf10377cc08824b66704384c1eba4494013d25c0d6df84237c3e38bce3995b05dc20274d75166d2192a4c3fc1fd2a4d7ce117366e9a9b6306dd93e6dd8b3f2fbd065279316b29b24cfea95d105d60578e17f1b4c5cc3bc44c773697211c5cbdb12bfc6092b0cf6a41c143d0589d6403c8bdea26a33a3ef143bf655182bac66f4936fed768f0f3e2fb9bcd7a96243fc0d10764", "65b3dbf94fe2b42", "45", .Okay}, + {.Log, "a0dc64cbfd339981570648cc9c5fa3d5ac6788441f0204d86b5aaed01f0724d182f7632cc868d64c695524481befcf753d544e38667b741a2526b00360183cab96f219126e638038e822ab320bdabcc65201cdccd5070bb3999226b01162b0ba955473375ca15554a63e89ed08fa1b9fad0a9b26dc85de33c789497f1a28defdcc9cf6edc76a08dee3a74cd20cb153e8e2bacedb8bbbe761d678938ed048b142cd6e098bf23323d699a35695c6fa4f2f8ce93a8e0756b7ac76b4ab39b20658e510cca63148d3d73fcb3d89f5bb5343800a8ff2c718b6c218f247a45e8469028fedf55da5f77cf261b413db24a8a346306b63ca18babdc471849465c1d52d775939bc07d3c672d33c7a5e092dbffc37fb479e2e0662c79e7ce6a0de259fd4b564f629dc3352350cf8844ab512f34195d49cd01ece6e7997a62be0040e95f5d8a16d756bd271380a81ba15cfc5120b98e9a302c8431eb9f8423b8af350c8867dee10755892d10f1958071db305be0e9d5c342742333e8080f5a38beddf69b6e9f01a7de8ebc8d86e40dc7a07f89ed7810d5dfd0e55ae36c0fdd4dbb588bd24b4cf88c1bc67cf3ff51e11a36d45604e48a3860fd9f20c059c4a5ddc74617495ffa0cea113f5a09175840248498bed298975b1639bf83cb60cb9a4797450661e88a8188d6ffb6e2d388b91fa897d037eaca36681bc1c6edf417487419c9b889dba40", "123745cf2100885", "48", .Okay}, + {.Log, "ca402747a08340374139f5717f8e0cd3ba778942b6fa68a52eb98cd8c3b65fe973ce15929cda2286c1eb9ee2255a6e155257f3d4409155cf88071bdc8ba3598ee8e75acb733743db666df3fd0792964ecf6de452ad257109994dc9565ee308cbad9b5ea040c16436f414a95f26dbcc51ff51c8174664deb0aac11440953009d63b14aaa9c0165da20fa99cf362bec5ff890d6b9bcb27e0485b7cafbca3aa252628f7b916f7461e69231d95a4d819facbaea86a364a1a3ab51b9985d50dc252f0e6360e9888418bb131266f76d46aec0fd008be204c8c94cd744961873176cc8acae0277793d00ff2447a06909d8ce933b26d12c43515454921f38a67cbd7edde4d65eb3849ba717a990b5d38116623b0718f48fc14fe0e3ad5049a2243b6d311787b908cd441ecf014aa774cbbee73f08b3734d36e446283b3b42a9db3b711236d144f3bbc228380faf7dcaec4e5c560a9d90d43006a91b210d82013cbfd4b0886e61ef4fec64e3986d31676fba2c4158a412a7b034f612f4676062720ef5cd0f23f64a125cf2c9235ede95a7ce116852fe0448051fb48f68bc9b11c6eecee98f6c079226a9162111e207737b73e74e929d59e7749977e1151674e30f645640f7316da315f36969e2cbe6f22de512ba3880336572de3d21cf64bf43cfce0754613fc18b46ef9e2f0c06fb042f9d25dc69a04beaa78d2c6462f5562db049e57da", "85eca2d6e4fa835", "45", .Okay}, + {.Log, "ce91deeb7ef105fc8c08720e8d15605c911b06364b236cf8b71b66d931aa008ad5ec833b732ced9ec99ed17902e1836d61f1a058582851d3af0d05deef19a3ee0f99a3f649c5de026f5e96e87aedca7b2ef2d69cdb0c6ee9ac87c7f0270a6e2137de265bd6c76d7f5bdaaa75fb0e0fea769f0be756f0eae81d4cc1c587c10b6bc3d5dbf1a6c64f2ac120d9242b1eab028e95c74f51a7dbb9721e348c101770719eae8bd1daca4f364cc237fb827b6a82f1103b2ae8486abca6205e64b83c31fb6b935978aa4240786707942aff27b92c3abcd3890ea6a64f32f4709c6849083d69bd7abde30608bf4a12b0de96d15cc7d126233e5b64ccd72352f622d6dec2034fb787a276e559e472b474904d8a8d4f407492adccf78a8e8e2605d9eecef67e6a91e8b5fa79dc25cff186919c29f51d5047ad07572524b0be1975afd167d2b625cf505f3fbe94dc9abeba9e4b679956ca21b283eafcd5b42f403d44ab99c815da537327a61ed6f68ba421c19495c10bd183d7c344ee2a59dc06b2cb60b8096838104d3db0712a5ee5c04c637d9b26bdd14c63ae79090157ebb8a3c4353db7b7b4411d440fd6f785d806c449c5556d89f856a725bfc7e939284782a215fbc008a4ee7ef4f48737e0d5f7c71b0258792aef97807e7109e26b0314a5072b0820347d20f45250690b89a9d858d89344dc18a242683c7550d29e0ceab27b6bc698d9", "2561201b9b2843c", "47", .Okay}, + {.Log, "fb4ebdf9ce30441ad5a6e1c09acc6cab5163c465ad4fa84d4252d7e3a64d86e7f92b0a9fdf42ec8d94670297bc136b307c83518bdab4d396de556c0a0ef8570222c277f847b41b94583798f4ab9fe36ac1761234b226a04841693c0fb4a8605fb977abeca082acd5cf4ffc4b4e508003f445bc6d2ba7dcc2df7e5215784c4102119225805a8ff97b511fc5320dcd905d05ec19610b772cba105364ee1287806b8507afb3696051158ad278887651c4206e6bdf4268130e9c98e7ed2b3d632acd9b120b7db63188210e3b59aac20ef9f26c5d3d6d209580e428f31ee2c813eb3d1f29a184709838059367b4deac08fcc81a9270d448adad0b7fefe78d43e2d893d41cacb72eaa1c1a0335c461da16ba93d55e19c240972f5133b4fb3a1623610161abf3b8a06461a4f6558d869d4faa2984b57bc50086a9e1a0281a89e8f11cca287389a839c66fa5edcc72e2c56a0fc4af4fcd4c54ed56ea1152d125daf7b197a994d81bfdcc953cbf1add60ad97cb86fccee69d60c2d3bd70369e1ea983bdaa167701afa7609410a171191702c1d259cd5e9c2cd64337e17972fdb02893a8995359695b50827ad7015e200a58af3800aed66a9a95c39ee93484c91a3ba9c1289613995a7a8fa47b1c12d196200e779ca24d4d0e45ab3580d66cd5382894a6eb2b8878e681a306f7bd494125189b037f8f7c655b8adc998c4846b8cba27a9dfa", "ec56ea63de08b16", "44", .Okay}, + {.Log, "5025b63bc0c20a18c1a054988281034cf30e16cddde403a803ba49d2897c9fb3e98a9a4f7dc1995e24acbe9d7b5b45d8e1e886124e42a6a56a70e751d9347a961551e7a56ceff91b97ca3338074cc42ffe509c5a4593b3698112eca2dac7253bf865ebb7fa6b994ca99a0bf992a54084772abbed89ce2f944f58c917e2a7d07e2b3f97132896f165b0b65f7feb119e74bc485b896e4eb234b6ff297bf8db8d6e60dd49600b21a9b72abca90cdab9feba2bce0486dbda7aefd1a278d2472720d83ce65edd9042063af2e81ad047e92b161f85fdb84ef966077ee52aed195c5de0b30605656c93414ab328470151071b1a398723c9d5994612f1c21c00a38fd909999e1be060a10c689ebc6ec4291a177c1f54d8bd993c3435843c2f22a5e4b4e96971e3739affa0652d3a6418c81d453891ad914ac6b70f3af20718d759886a8f6f9265715239f95d4df9dc0c46541fc025aa4f971fb575bd907f31d0ee6f4091f0d62b16fa363ddf2cd212ebe6f7bf2c2609546035ca6f976c052dc9509149794eb4918c8fd7952a2de20fdc4b0dd03f67b877e77f278825848946958d501270e40e9e6549f5bec8ae1e0fa8b7e4a641ad0b6c532752dc50b0edd3b0473005c63db655b1e72b072d1680a51b351d76c0710d474c7f64ee0b04c20cb2f87aedd3741ed232db85b909c4ff9c0b920b28f1e1c294b94103f4447e83c4f00294b7ac", "e9dd1fbd619f89", "49", .Okay}, + {.Log, "bb4009934ae014d0ab769cc960eea184de421585983fdcb61f1d530861a7bd808699473a20e7a971953036b008080f4b1b6db33557629b878887803314b46ee4635def6f3f5748103e4b193cdf3befc4bde0213ccbf270780349330e74cad8e3133835cd2cb1a770fd50e10ccdf8b363a56a84709cdf8864466918a067c1f19529ced643821a4d25ed0db5b68ea19f41312b161ebb67c1187fa33ad1d465d85bcc2f2febd82195b088b4d1a2f21b5056c4f72cb7c9dd2f25dcde94b997233510eac721e22738ccf9e024ed85795c33f9ec59549b994ea745795fa76ee6e9475f20e15e5633f306bc952bab9a870df68b96934a3ffc83da39ede1791f9ed6e86822b85cb369ac07ac3c701ee86a8f010310c540769b714f6ce7d9b83f1ea65614641640ec740b792496fc0f22783455e49becdb13625ec1be40a20744bb8ecee74bdea215431d4acae97e94e51986c66e8c2f3ca8721cb0f026772a855fb172a10d0f1f7301f07521efa05065b7eb6c2cf3e11f8877d75f33255a296dbfab00d0246883c404501ef6deda76d074e6ad164476730a1f98db15d765d026af693036d1690890160cae4b81f995534dd11939bf45562d19936ed641d52ab2edaca47fb2df547bc2f365d1c2e48cb6e4cc9c0b12e089ee06b79c8e1ce3e51325fe69fe1c072568fb40da5d8239c0e972b0ac0109a0f3db8962de36ce3e52a2336e5c18", "f73f4dd3a84a650", "44", .Okay}, + {.Log, "fbca57e040df011be0da5aa40a744cbe0a9b4d8c77ef1bbb73aaf15598a251b398113218a8c21e4183f911a295dd2479f4d86668c7c2e7d537be40859a27579f5a8318e0418ea9a9d7dd72294efe2fbcbc5655413da4d5d8ca4026c85a196b48f1f50664f4d01e2d5b3351314b016f68e4a371f596e7a2bed55287918d8f5b7e7ea511f05047518cfc59625d62512c1c28f9a422201caa47ea03bf02dfeb32f5321dc76cae716cf0b5e9f7af1416ae0dac065dbdf02e631bf892787cd8ec4038da8e934fc7b926e31942badf80e746791ad32f33ede237f5e39f348a66371da061a01bde4cb70740e44afd08b82ede4d71a0eb1ca18599c0cedc2d67159b3943d277c8c4080de0d4690b414142fd378684fd2d478ec6e89a9c665c4a12d4493c42e7788dcce06d90949ec77c811b8a89f6cdc0456e57f0a345587b1a15f6647610fe50180c0fd9d71502bec7f65c0481e6ee82a3b51b6a40238bd95957234c163f0b184e9e9ce9ebc45f03b3707da2bbfc0cf78ccfb2b04bf59a71231ab5c7eca75c492f2e39a1c023da3cb9ffd1a376523b87df240812d6d6ba88b0519241a17333e91898fa434206c6a8e84fa0d0785232a3d4efd6163045043899fcbeb4ac479365df6f24f5c0076c06c76986e77ec97220ddf0ff85cb4d475f4e4d8a01789f7c0196a9a67e16b0e2999de799b58f0ae35272001fd501b32677db098564e2", "7d8c082f64865cf", "45", .Okay}, + {.Log, "4059a6820ad9a5db13e13550e0f32fee42a32cbc556ae2939a8fa24031c2097c5b7d56ac7e8deb54bf307eba5058e449fd6636a3b2195bb77c31f33ada707da1066aa10cdba6e89fe2adb4fece98e320de495e5460dcd78b6224cecddd6b0baa80076ac963cbbe61a8e7be3ecde4c1a6ce592cf5df7da0bb1455293e8e331010860c079308a8db617166229600ab3049947799682b51d6d8b94c5703d721b986ca9b4c7357d8345bbd0a1ed4bff12c69266a71ff7e5d68664e212b6f7083ba41587dc16a4c82ee46f3c7f2773c95ccc826fa160a8d674fdab1fc1cb07308274419545ab7d12813a15574a1581c81b1c199ede31937225f19ad7288bea795b886d8c09f7730fc601fcd0f04971e7365831ea45cefe6453fc0211610484d9650b65f7b3cbb2ea0579aa59bc14e6285ec3b6745b986c4fb0fe39d9f96a42bdcc57ebde93b7c844050c14e35243e668a8cdceda386a121790de8775ece7320bda32be7d5f6a3c1ed3dabfe2d164d454c64b40fa09ceaea0dca217fb523214a9334fbd612b0a8a698ff0d71d634945f806cb7ee689219b054e407bbb47a303ba153c3569d259bea7cac7c59524d52cbb8712d8d1babb3287902636a0ac1a2632b42c14377b814b20f952872ad98cd8e901704fda6472c7a4ba3f5ffefe94cac13eb16d052508183f84e30fecca5d03778c87183b9d67ba41d8cc9f5800ec8e880e6af", "5b61dd65c66f0ce", "45", .Okay}, + {.Log, "dd8bfee681c9e0468048c0d82d8806c3dc4825f93022acf3ce2755c8e79360fcbb1e41efbf64e556927c99f1c962d3864717b2e4fc0fbc9216ae924bac62a410a198394f7ccc3d74ccac54e2a23c514171fca673f1f53f2d76e3f4e21c327e6138ccecac66bdd0b1fb82b078b9f2f0ac5611648968f6ba27098e8a0f45ce5cb90b99b8d40f2311f31b445e775ed64a6fa4de94279d1f8c1c6de47033e8b862e8726017b1e0770f20dee9d305a95a79ec05a336c45a72d22b5f4381ebcaebabcedfcb76d37dbf8a5d00abb3846dda57575638cf72f9deb999f8bc3773c7d329f0cc17af7afdbb75b931d3249da2a27ee2449a1b9b5b3a86fef15fe30558a642badec068b08585345b406c5ef5d187d6bf85a88c4c2aabfa1957a9dc6e3a95a14f192a7a0089704fd5692098bb746f1a65c5021354acac193269be316bb5987912f6c32c8a54e0aa42e544142a843fbb47593aa115eaa8308ebb27d85cc1b7831374ddd45eda613a272e5ebf6c675dfb9dc8c4851ae26fc7afa07570fa89ffe160f694d5ef5624fff3c33c1b54be4f6648854b05e7f4e3f32c2a639b3a9c1877018f798ab9ca9bdf2c68f25d0e278302e1dece01ad1e19699151383b522a4890a7369bb102d07583c8c9078d52a487b4c6537d3a8c550cc30ec3adac1afabb2f736a1d2ad4e8aa05727a3f04863a7c6a22791eb55af0fd5881c09bf780659460e7", "8a7c6d210c2eed7", "45", .Okay}, + {.Log, "119ed34e853cff22377a9850c8c68788537983974af1a4e590d04bfb2b3fccf434896c6d8c6520cb3bf0fa5f8c2d8d90421cd0f6590facff5e2a4e9cbc77eb6d6646c7b9916b9b386e89b00f4994391baa4897804e1403f9b4441c8cbadf3a5307d0f025db4f297af95e7106c1ff68e5a2ad1e4c50a4c45d54138450d7890f3ab4ef8c09daab0a72ba242d7550cdbd5efb05a0d48656c6f299064162fff5fd73709654c7a333dd32d020472961b770fd1b65b340b7a0567876b4ada399db160bf191f196bf5cf672d51ff241b3e4edd3e2ed5987ac9ee6a59c10d5cd08793a8dd6f3b0e42dd121e8ddbb10677af91ccbda49ae9ac73a4c44f25957098f89b7d28ac0b53a3e89d8cead195eaa13e08f6a2f5182e97f24c0a73a82396ba084cf3d5ff886fa06043da591dad7b0d539874e8e3101abe53eda15c1114664b3c6b7e6c5fd2693e54530c0d0d67bc9ee42d0b40fd710b85b265a8b96411ed511447d06f136fcbc1ade6e4f0b529e10a7fb1c10b37af0e7d35cff7bd5e1c73c4bb32483a190629456936c59001fa1f1988b23645627cd392e52eab6de40bd193852ef550b6e3bc310c29ff31a278fef89a0844599e7d9807af09b503b28d8c41c26c85f9c582aebcfbd3eeaaf95b23ffd1fafee3219618f12bbf71ffb89187e77a827fbcadb684bc87a00d5b0f91eb99d3284d1ab6d2de4f9bc43c0ec7f58453e055ca4", "6b26de194dcecdb", "45", .Okay}, + {.Log, "1eae459e977c68323b4e74115099ebb5c231faaa7d3b636b508898dfb420acab0da9dae26e2e08d6acc57c6e0f341cc4a5c8990a26aadd2f898f7daa0fd729f629eebf686380622b390249c71cf02ed12a321ccb272ed86d953b4aea4d56c9faf394d7c658e8a2edf52a7ba0599d85d2bb09fdf4c51ece70e2f40c0a7f8fdf09062ddf14a5f58d9a84811e4e5f748f808ea463e0857deae873adaad4043fd08a76f28c1c4de0a0da7c6c7a2360ab9e9dc2be9c622b3580e667d94de9dcacb2dea062c7f77a9a35fe090bcf003b7cc47e5295446dde72774e76bc3808a87aa206ee585f5e5ec28483003ac5374475db2e01ae19b0e607eddd23ce4c103d2fd48c43dda49c51308d05c2f9180eebfcf53ccefc744b857e33838f2f7679d1dab652f9d574d7232fdd96ea4146f8aef91d71fe858ef3df0257458ab70325cfe079f41fcd8824ea38b3c24ef5908349ecfdd2473fa06bc5f575a69fc1a3ab0a3799818a45d9bd8a465b8d6c2b70b57d55620dd1c69120fee48a37770acdb08a729fb015a33b1a8fc51f1140fea7a7b1caf38a75359d875f54dabf52b5b5dba41aeb2cf7b4eb7f824955535513c4ae5c75dad4f601acc3e8b14a1aa0639193f67fe9a443f5a416e5b576f33e0e34ea0202ba91b6c65f5ae1c461252c30ab545f29775b78abd6fa2d07dd10fba730cd9664c123f28114b6043fd2dbf21db6eb74fc67d1", "70ee19fda2b7274", "45", .Okay}, + {.Log, "fc7b0efc7da3d65dcf08a04f3e9d39670532933a7ad86d56cda4329198c7f797cfb0852418cb2b57190a7011396b1fa8eb531752a05a45b226901844d9fd79417660f01016fb9b712d5ddd3c49dd6764e6a6154d4da3261f5d48176f4edbe60f9c06be28163cf4f200e0fdcb157686eef24dbbf2ddce8326c62495cab112b6a17e661d1e4cfdb7e2435b4c88930ecc78f08337380e923f2f093135d7c066cc4a0ff01ced0aa7af4172744355bc03bc66c221f09ed59d61bc131a69ae0760e42fa947216b82c3b11a06182301dd43430d73307e998abb99700dc237d9d4f755dc8d089dae1c0793fc585081510c4478446327cd101dc99cbfb795fb02c9611749050c67a9d749ff85c1125ce48a52bad5c765d3fc0b83ffcd8232bee77a172a73b93009674c2bd76bc08495e0e65348757a4d8a885e5d346e31b2598476829de52da5ce1fbfce36ea510bba2fd20be05b4275bb78bb591fb10354a1d6ac93032b67cba73abdcac8d885a6dbcf976317c0d3a0b66d4173028c9e231ac58eee388ab028879a60de8581748f6a18eecaa987f1f481004e3f97c6ae5a9a25377975bcdd304354705cfcec788389aa0aac3560e6929a9407db6dd4a084113bf028203ee09caf063f6a668739fbb66e5e5670d65ccd6e83c5398a9b60c5599ca0fe9896cb86e6e3d5e959a13aed257e8cc4165081056f75c4ca64ec417526380b3ec6b7", "e555b9dbc590eb2", "44", .Okay}, + {.Log, "de6470a87ea1c8832eb66d67dd7417b15b4312376d302d72e12c0e429a19979d67dbec846733a2cec23c7b087ded679f176687aa8e47435ca071befb7348b6941f4e28a0f2c81c94fd51d2eebf99cdf16d73e41fa42d57aa76bacaec4da974a0f7b1b6d3f5b1dbd1d2a3241688a8d8438032406cdeb3ce71c12313fcf32d5a1aba2e52f5eb8af1da6b9e08bf19e80f586e78be2e7592c9d0fe564df57a8a07b49a010942ce4e1a85237683ade125a1e471edebb7f03cce7f39a54a4fd43408746938d85c40235f801967e110e786025e3064e36d22bd9fa11c2414de51bffcfd02d8b1343a4f58ad7a0ac0a73c82d670c9db376d2d3a6fb7e2010b048970dc40a98ba70a346598888ca309f730f095cdb100f08e5db83d65d0f7d69d6c44ebe979b6f242ea95e770070a39436f9301118333009133db4a1aceba5a51bda4ad3289d5c73b905d1762de65fce8bcf75cf31cbd87a0f81daf1ada97d2b0135d72abf9df435deeca7c58501df222771f630a93ddfca636774d904abdf02a837f67c139d63802128fa0b77062f6e642681bbae77f36a4cda44ecb1a579ea02d3bcb80faa6dea8b3e3476b68277c8ab03e627dfedd9ae4c5af6c98fac0d33884fe1a3e592f040b9929692bc5d6f5ea037eb271eebc4ca147bdeb530a1bdb359dd336cbfadc6783f130b1e0faeec85ac130f2c6fdffaae69fabd111a7b9a4808814e75a", "18f5bdfeff6210c", "48", .Okay}, + {.Log, "77538d70a4ae8150c3b9f630101c8bcc1e49050647cbd6493348dba7b2c3b2bcf80e19ca8e97b7ea008b006f16ea6e551a44f9512da02387ceb4722db74d46a163e7d3a058ee6d2bd9b43b3fd35ee1946ce3f93ec37801538d7ca3f3a3d9d36ba015e16a669c92a10d4d27fee461db143a46405c485f4c7139b21d285c2e8c752f52ce46cadc81d2b39440f3ca21f13f5f4751968b979519c286ce7ba2080d4381452cbed1f39b5eb1f4dde3aa2e9959ed959d8a1cd9eb0ed600ee28de5af65b0821223cd3ee4027ae5b8287b2a40af5d32b7c92ecc7495058ad2362c4d6bbe1b7c93301814ef5a3766543e4d3441fd2c9a5f5ddb08f90608230e60f246804fdc16fae47cf319ad09f1c99996231443713a5a5679f92f1ea52024c26f68a48c67c29c976eece05c4de61cb9975a272ed404dce1cb102f5d40ab98743890702e84a80618ae8ffe01442682c7aa33db1f72ca32b6b1586310fd40b119a50cdfbabb53bbdb72877f0c03bdb0b096e87a62ef667d1e0fd7f9659d614e07c9126c0639401413b04f65a20f1c5739a46062581c1d8ab63229aff0ce743418db6b63ff5b79d0fb87e7cf05f05484e1a9d96f8a59abeca60d2bd1929d2131a49a44f166b7dc81186fb3d3cb2449109a45faa3c602c640e42ccab974b5af58f0b1ee0a44cfc32fe1ae363c7a4e9dbd404e1c01d05195af2d48f900d4b4ec1d260aeb6eeb9", "fdbdfeb0e382664", "44", .Okay}, + {.Log, "994da12035c96e318b8be1eed54eb4d55a52f46341485e8ce0e80bb272917f1dbfc6dad99e127bc9fb8b28226c6eac38d192b331f28be3d84f6c4de6c043c2223f9e1dc21a5bed2583d4044d6083f7e43c8405b6cb04dcf4dd3997b6f0c9f68c389ca2d55e963bfbde51d1d694f024f5eb7aa21ccf129c6156937560012b1e840dc6d39ea9834d281230b7e8c8a146d4630e099f83a61ad6678d6c7e98f0c99697e15c57405577978bfa60a8726c44d3a69c2b5076e905919214fceb2652189eb554be6753b724e34769d065b9c3652905f3dc5e051fc063b3086a2650ea54508032832c059c65f34211c1c631aaf916441b4c7de9d574c0843c542e0093f6d535dcca5ac4b0558b1fe203270160919e96bdbb6cb11086fb8df90db649f1dbd683287147bc59b36450c1603a589a916f849239ea66dcb63b017c5cbf6e8964653df7f8c2534213d758139a18a230453362bcb6db855bf77d6f8c8092a85d47350cb824cc4ca118faec72d6306b3ef645b69a1ec4dbfecb965dfb2934123ea8c94fd84ea6ed15a6be386bd20cdf200ee2153a2739784f514da902c1cadce885d1a7d88459d721bed17c4038415fa1695d6200b72d0781ef4e8d3609115e5fef4ca085e313efabbc21c9b592aba81500bc9131d768e4e69477e4efcfa6527df5e2fbf036e57ef7a17ca0ced706d92ae1dac797da050f459858f1e8d8249e6c5f71", "851f5d7804b1ba0", "45", .Okay}, + {.Log, "2705c678c533428420427331c879a8d6f99c44c044e131a555614e6ddc524007fe85c6c9555f8e25c32ee65f03dd9a93582310574f8026bbe2f5d920efea5de806a810600727e609a06d65dae6295bdce33343d64341f89764275d89082368800a44caf4e563eadc21f1362cf0da7d21c07235a17e4148b40873fb07aa69c19486cd5f586215b9d890d7834ffc92ea3ef71444448bc5e5cfb1768dbe33f00b93a4a805dcce877994a02bfdcbb40de79820fc9113ce48a580118f7f2defd93d593b3c4a2e8f7083d706687b8c17c9f1a2d3a81d61bb9ecf278967e4ba2c2b8c1632e7101ca028225329460f2124f3ec8bae4d94956e189c64f11bfc96a0b6e992491f08d7375903daa37b7f648b46995478ff30ed5a860030a284fc74cdbe003e9fd34511539720841793a062223212db57007f0682ba950e88d7f7858f18f4f9a946767b45f8981a32f745e6844fdb170edc07723706de10ef2d53476a5b6d659dabbe9c501ae2a8c383212e86767c4e885e0b3b5b077c947805af361f49c84ed96ae68fb9fb21865040868ac9093603b727775b455e667d2057b8815fb8f9e46e4fe9cedcb6c87a377b0a9578ed4ad4603b65818787e2fdf37420232461a85ac232c62583ce7273eff07025db207830b30245069afb44b9aa873d9aa3da9304e915b0b67aa2b17cc7fa56123eb94950a02e2d75c31c37afe6502243da9b34e1", "32c2e3b7ffb6779", "46", .Okay}, + {.Log, "c0e2774a322b9a9171553e426f948493c28800d1cb248b05ab6a275686a24431a1dbc7b148204cbffea5923dada7b351a47a87e7f609c13ac019c9afaba37baabd69663bdda13c760e0b736c0734ab47ccb0f54ae6fdabd4762bae23ca99bf60d6792f67ac4a4bfe79a491d177a39994d48dd8c6bc7c210c3c5193e7aa605adee1a8e9726163686fadbc7e5b42c7e6cccd3fb5b42e69c5f052186849b2238326c88b2cbab04490063735c3f11fb2ff72d151ab652e6c45c5af958ae9893243cfd20a90b710158265e943056b626d113c400307373ae013d0e1c01b2960bb5c5ab6c67182f863da8e47599d353359e440bf2244f80edb365bfbfee7bbb8cdb72bfde8a9d642ff94f916a3d9a490eb9d2f670bb77458c43ad706a771aee8c78fb208cda1fe08a20d1b1d6ac95c29737d196932ae42b32a5ecb43d49ca8d9150b124043e04c7b8dc6c827a8ee8b497a96346536bddbe1b6de33b8c7883f787b4607208f328dbf0c8aa76e7c773e4a9a4c45347c6deb899b422dac2f3dbd99710e265efee1252df16cb2758e288f3e88910c4bff1fe562f361278de7cd9692f823c1582c26a965d0920db23f8563b599e5ee26cb800e08466312e799700b53e7c6e19ef137df19b8d3284fea29b18b21f271626e7526a6a8893f5b459bfb5c01883c2783d6021a72c2a0f86a2a382b18db13f348070941c677b26d384c45474a4a56", "e0f1326f89be9c2", "44", .Okay}, + {.Log, "c76ca9ad078973b5c8c1e5bddd7a6bf60e84eab1a9325ca8ba12d5048d788e9bf7370beeff19a6596645259bd9de6a1c2d315b2aa7b19c99c2dd72944a7bd1ac2928a63644bff69646867d9c2e6c32e62e305544d0389e226f0838c0595480ffab36b57479facc15eea561cb7a7c54855a90df0331d13f5aa5b283790441d52e75b9d2464be387d86745bf62fe3be6865c37e1e2f85a3403c1a0fd580edace1f77db6bd6d1c0dd90bf84666db20cafcad207da6d351272e26f29eb02c38fa4c0043a267c13b15737fe4b9c2bec398638345ac4b387bbfa84ee8c6420873f57f1d73c6454437e48f0522f9926a7252f30f7bc832f534ab120665a3f705dc726d74a732c7c49bc442679f71b948a342bda20852cc3d51e78a96aea3a194b91dec25561d1f39383886916f8b4d500dedecc69d018ae62211d634bbe9ead85ad35fdb5209affba9ec6e5272b39a979b1c98913e93548f98eadfb48ca9ec2832fce5d2ffa55c95e53f3a5403eacdd00404094d03c1718a7e2f468088f7ffbc1f0f50474be11a3e9bd88ead3be53d72bdecd6b22304a77f7662434d01a1d7e74c4e92d04fcf236f4083b41b8d0afb2e0e40a234c2590b61c7cda497b8de8e5e47b866f001db4c0bdc0a169aaf688b472517a93108c02198933ebb258c69c67b7c698d58c401ad66044628c5fadd98321cd6480d77bee2500028890e9bd3f5e0ceaf5df", "1f9219d38f59d87", "47", .Okay}, + {.Log, "931ae6c442deee3194bd01da1780dd2cf2bdb2f37957e2e4df5a08334066c4a9a3b851ff5548fde172c267e750d7cac293a202e8042a59e726cef77bd4c2278fa4165cdae852ccc140d3cbb292b4cedbd7c59678a32b11d571fd5fad47fc4bf12bb0c5ecd43ec2f50c527f1e608cdd289031752e954c92cda6ca845f5fdec701b2cf9cfbfc9769fe180a05f2c0969feb85b4101b868739eaf6e281e1bf9a42ddd3a5daabc936e077acc13150703583d1e9aa6a5e23ee6a8dcd26724aa5cfd45a4d6d8c30226d355a07535cb029b8b001af0efa96a0600096cfbc0959c2067764f9be5af5b299c5281e65180cb7fd154e20810fabba587637eda1a171eee44304191305a3b222dcf9810f6ee3f6756ffb6410a4414b002da803c80dfe7aebcdaebb3a2eb39b12c545195e45fd2e8e8d92cb322483d3d2e60a7aac72b53e0ed8ea8849329dcb6a43860316dfb0c1f2d130d3e11fb1bcbe2076e2fd6de1f95ad8059e7e01ea59cd1db6d5edb7d030efacaa5cc4a642e86620c4e079abb98cb4db6605eaadb93080f09ba333a1a7e69540487b8ae6a50de6b7db475ca3e1aaee196bf2641e0f8fe3469cd7ee91a44c413030064ccaf54fcbed037a80941daae40732c0d356ab01af6d6d4bec4c62bcfef15d8122f031708b134e07a9e12851d1d9e2b5f4a62a70b59bba5298e733bfa1333f29d7975294458f850dc68a9d83329a", "5430b61ed4386f8", "45", .Okay}, + {.Log, "ee63bd6a8511d0b0cd0bade85ebc3283cb4e9ae0d7cf8db3eaf894011a5c7535bef117170ce3853ef952164cf5a097b1becead2e7d101d4017f24c55768f194695fe764cf3139d545a51b59430836937f83d0ed22a6cac0640da5b7a294ec948f18107d65bbfe29e5d830fcd3f6d94ded71affbea96c297000dac9f254d823e4a1d792ff8c07ce6062eba6d2d2d92bbab08809ae689013dc5b6906070178455ed183c639a8712a67e97172fc5e0410f924da30ec4d73ba95f334aa9c0ec8c7eacc7e00d0391fba711bd42c953e9023a0888c08308415e4b66ced1f5b1f31ce9426f843f1e28e3e769f2691c265e7f342b0e3500d199676bf6858ecd5f214896bfc038827b152e90295478a09329a5e1915f52fc7f88471c52f967d7364428b9a3a349ae06634f24c1b63d1dd96129d119f24677fc264226547104a2564e1b32a32775fd08d0a0a5e3347955af1c9fff5045eae3987faa1d7802b21eaa8f74bd30d9afa195f96e36d7be34e9140fc04a6da3ecb957aad7e1f2a3e9fb5f47e562c1f883f65dacf8aa7f238c110e2a4cfd65a25f35f9c4a9458c707458e187a06c5c0155a49bcf6817035d03171038e21e338cf051b54a5c2dbdbfd7886d0b0897dc1fad011373f6e112d17470f5ba799098b38dd615b44b71f6203d20e97a6df496c4ff0924e52518cff42a88d4234783332171214b598fbb0d7cb4f1f9d1ac4e7", "617236e107f3dc0", "45", .Okay}, + {.Log, "37b50418023e019a7dfe362597439bedb84f6f8418e4d53c02e46c6488255b7d6dac80ee12b43e63e32318955d6f57a10601a594d8d1b3e92f8e34fb2137476712eaead9b36a1bc08b63a131aaf2759d5e0fe9da682d5097dea9f1f2c25fce42201c947ce945984b755f9097ff482a1f31c74dac79a6b5eb1d55dc402443e0bbdc15436a3f3ec8654c53b6b2d674fb450346e77a2e55333846ec1b6de54c64dfa8e34c0812189c9428e34349a5786be5306eab8bed31176b3041b4c452738e226db13790607a0948c3740fcd75f2efa56537e80a7879aca0855417f72266645ce3c536bb041761ed43bff820eba43023668093fb82733c8b7bacc073d58d29ef49349ca13ba2c9c7b89b833429eeae01eebf8771cc8fd0f633b94203a8bb28db49448886df368186cdb263f7ad3a5ee4e32b192e10f931a3f0183ecff1b98ca39a4227e47297e2f63400eea6e964ba274ad168904542c55ee0874d46541481d136f1a85c60ca9b1ecd8cce46a76a1d79fbaee12538f4eea92411ccfd5ced5d432e5ca03beb4ebe4ca305576d54dadb3b420ee41bb02aa03379598a7d36e4b07f7f439127be4132f29c66a585948615a443d5c1203b625cc99129ed8954df126e5ef48852766a530bf1685b3fd195fbffd1096dba2419fd9792396148814a93a03e95b9ae78c56b342c2894eb68f7af52475421210950a04187ddbd496e5ace5e", "cb8c634430448b8", "44", .Okay}, + {.Log, "25d97bda00e34728498dde8a8f0e251a3eca7306868953d0ed25ede6612c63cf7093e10f486e6e31156375417edf3a1aa426c82183b81129e620d6458b259ca0f156bc7a6328d7dc8386c5b0dd81c6ca3af4b3a62e05eb6b7811669aace41f91cbd8239e3dd1c57074018d29d67e506b9bcf4a688b9ff6640f82358b53a5ca6083a36858c4afaf6cfb0193906fe3dac8aad83de5c137840bed4859dbedfcee40f573a79cb71e9ca4b09648d0d0e1fc3905e73d454cef68ac8137893ce72717648d5a55b66a3076e8cc9c750aa776af806981473fbaa666b1922b13ad406a85d43f4e1ab87a7769c74d530def6ce3d46c5f49e3eac685f1ca02f0082b0086d7ab05151a8bbd2bd394ebd785211f1f270130393eaa7227db2b8fa33b5f0fa48cd788cd978cd6976741c7f5efc6e38c4ab10e52ff00675b6ab1197d44d3dc9170c6740d7329c60a09b809ec0d795154adec7f36e2451cf2f2cdb8f5266ee05c4f2e9024d1f8542d3750ce2db1ef113b90fa1f60f0c2dd751391b68189da3163791d7020a92119de0f84f635de199159d1dffeaac87183985132f198673deca1d16a1fd7b0a2df31a0c2214d521be32f062aa0d8c4331812ae64995de1cc5291564a04687d2d1c5fd50b1a4e59d5d9f2634ee98bbcd8152859fe9b2571b8dfc07ec33866573c65088909ea144a248550356ca4efdd962347ddd2a0a8a9ffacc13f26", "7c283c7b1ce6ba1", "45", .Okay}, + {.Log, "e485abc295bca06a30179c43b02fe44e6aa840cd4b8615f2501118a6fabc8bd65692dc42d5bdc56b04a7a70c7822bc42fbe79b7fc36c29916356e42b0ce38782689aef32d2716330c21c11c4c2454e8a3484ca2dc708ce9358be0490e8a781e459c08b7ff7b772aeb31e8fa89bdfe9bf85a1c80e81ac01abba0658ae3e8bfca2f34553d5520943a3a13f65ec1c434829ca10a5782eacd0f08fbcb1bcc7ecb1ab52ef92902b88192fe68cb8645d821eb5b8d9b0a0949c2978bcfee796bec3d9f26d2a3972ad54ea785bf7848e3bb7cbf134a90832154cd1a250a9a6fd1aa778fa6164c03e2c4dd3d19e535679f5563de6fba26ba6af0831bc1cae8eab11493e5ebfeb717450203d96961857c29ea1d5ffb4a0d5fdab6654670712e546c964c335763f74620700604902311d1c0eb6cca7ee467a2fa2cc669b9fa0a3f541c9a7c488c659cffa202bd953a333858e9b6c7b79dde38e7f4426e26f529a6ef6b90ed55e873216a67842dac83c7e6f1aa79e52a11e550af7e207382f10099238ede3148c1ea8a57dd8d83044122d75c1f2ec97821e664cd751c308184df282e14800a10c303fe1d22bf3864c72c7f0a1936d8a7e1660ad5f1ce32d0da9cb0d7b825375369c7ec4c8142891cd9ebeed934c276da8c2ab72c3b94457666663b694cb604fa9551833962736d34439b88e16c0070bdd08218dc4ac4ed54e1358bed6eb52e6", "10039cfc31258c4", "49", .Okay}, + {.Log, "af295ba1f41f223151b4f1420738218cdc3cf44b80df97e563f59bd1adefccea89b1c1083bb2abb71dc9f3c1a092eedad5c4c87541a1370235966ca12790e35c540fe2cdb58223f6bb1533c10cd71ad8c5c99c3a2966b52ebabba593b4c2d14dd57456d7e24a12ab7deca589f6db9e5cc3f756791a7364f64d13c068a3c04823bcb4ea796a09cb67b5ee9f7d0431d54c6977d3a6fe3e86c3f9944700154383a379dd53433a901969b387ed34d3add6b85ac235cce50073143a3b404ddc76d9921b87ecf6f8ee696deabdd83cef2903a428eee669b22aeb4abad83102f7dcd609ad5664506bd78d7dba42db4e3124fd6865dbebdf48d7fd727d0b19c0cf1cc5b4eb6e77cee3c66aa40c864b96ac3c7ccc49caccd9b29960826594a6b6647b1d295b0e9e04aefb8de7835217bcb4fc15a00bef446302075b9c01fc4e6fdc4b4fa5f52bddbcceb1dbd5f5eafd6a2610043798a5c78641c8c4ad36def2511f0eb9bd519941ddfa81b8203d5fe1a79d5e8fdd3fc4dd6a20fd3d4d1d49e98e9bea70fbb0a8be5330b6a8f36ee398a96b08fa3de3fa513f597c94190a0d87054906613d0f79b749223b6dbb481add9cfcbd5bfaaf4d7a069d78d4242b8c02fd7cc40f29c87955260398682813697f9fd356ba51b68fbaccb1acb2bb42b3dd148aee1f3263cd7dcd5fa5deb73cfce25db4a50a42b067ef2da99a0bc977a05fe5364520d7", "aedad54c2cedbc6", "44", .Okay}, + {.Log, "a496fa2add673bc26bd7252ccee134ddbf5caf317e464ef20862eaab832c0708a793f05cfe7bd4b2aa9ed1240d24cf859d3710dea82973e0450ecdaf9aafd911f59fa29958389b711a2cad5936fd2437b8e35b63d46a658a8097eadb59bdbeac9c6c6ec54a32ee1781e0c2cebf6b1963d776622fa28c688bbab9930d1712b1cf678c2c38a337e1e9f5b9fd4a32b41e90a302076092ec32ace97baa4e500b5a2d7e10860cab4f58fa26502bdd22cf03f1f7727c3c1f13755026593bdb17128d503e4e76a04b8a86bb37f90eedf7cecd91657beea528d603e98a45a4fd18dc3a9a98fabee7811682c190b8c96a905825b8ffc44f24a820d70d7afed5fc8fcdffec1cce845664168db095469c17ce3c49309e08928644c3f21204e3a989f624ac46434a61066d7343bc7ed4a5681898d76bc80daa5b4ad1d8b0dd28560282ad4d5af82994eb878cc6e0bc3e565494e5aa18a181bbf38600b2a237a7fd30fde019a5e263be81a915b9a821dc3eaa6be7d9c26f837965e3237ad77eccf652f278dc9cc706cb73b9a13beb6d723aabd7e7b72fa5bdceebca82fd82e74cdab9793586efb9fc35a98190d8f26ab42c762144cc38eb6ae3dff77d26c414ac3829678a7d2998530ad201926b398afc218455e97344a59c4268e2bbb86bc4957f5ae528e16c467b91e087208a421e3deace18c2364dcfccf5c8d28dbe32c1e6aa06938a97de", "f9ab23fd46ef520", "44", .Okay}, + {.Log, "33a3d7349489350331607daf9e4fc8d6cf689dc2e36390db70d5c9dd74da894a429c38598d3db56c0cee94a4d91bdef087250016238aef321820c6c1ff532490e44a60ee608cd1649e034c916b7800fdbc220e34efc055f6e4b4d703be2145327995eff61967cd7cc1ab470878de8a7457dc9e6d4c44c85c8da1e797be935e04559293e10620fee36617393bc45914cdc6931140ed6c34a27ae068d73259bf7f742162c3667a72541489065530fce80efd23e30b83c2b1533dfe002aa7a6d426c88e8108a88a29feb128f0d447d60077badcbc6d47b3c403b288551b56c8d39d72c7601f86f75f71ec42533d21850cc6a8d1dd579d750261be9a5aa3fcbb7dccbe143179876e2426b8e2e0c34e8ef12507df54b1219b369887cd84da3f4f72f2b6d146094e9294156e8be17a6fc9764d54f5ccfbc503f29cd9b95a48a01ad72c9b2ec50ece8de6fccd28295be1dba5fc4721e4309242652fff592e0a10f03169f70447d95474ba11fae5285a9a22e0b11f8efb8b36480a15fb6feed823a9afa0bc2a3f31d85c92a52a3b37b0f9592d559946136000ebbf58a43ef689bf99659d9410b813494a2b8f2c583c23788dada26f55eb9d373179c1f7ead6cd617bf787c32d1ac248d66163d751a32ccca6cbf840252395b5a56a43e2b2183be4ff1d566955824049f9d8a221a5161fd8ac6ebe3c8ae616185107768e14691eb177d3cd", "4b9813dd3f0d04f", "46", .Okay}, + {.Log, "bbc4b5bf3a2e7566d15b629ae28fe748f5e446db09a1042e4685dbd28d3fd9da7e05a739548107fdb02a8f25c506d8c45e7a7abf569c00d2f392ddf885271029665a93e70a39c890eca4eb35068e4f28f46137a30974a3dc34db091a255757ee0197a188c9bca785f0b8191ef6b685d54ac798f3f9357fef8b0919a5104592f33b345f71378a1ac89696af7a09b6b2e923430bfe61e0dfa355b98922176a7ac6bc224d4fa5d0873067cfd9554d5835e56e522ae4bb5925c35aa1e5da4c658675abe7fb13f40b1e7cd87d732f6e4f828f1840993aa9fae41b895630dff02165efdbf0e4b055890e0cd08e98af5a4b372dcd108900c96390e9ef99c2ddb46e45f20e7c3c14f6a0a88b7f14b71a477048c8c9e1b3cbbe1abd4fdb9d12445f05391265739789ea74c620f11bc246bb6cbc110fa51403a7ee1bac4da26806c92c2a31a47c01e7755fff846aa64133b4c54967eb58129503af191d9969678345bd45bef676e03c5e1244973fdb5cf2d536c418843cf42f20cfb434fbaadd9a855196b335c66222700c0f95714b41cfbc141e872e491756f6caa784d53c8ee8abd4f4b3e30c07c406a5d852bf34d9451e5f64a5e85ca31fb99a0b29f36d8899843a05120493e1f31f83b7f3748d73bb4b0641662ac586835df21c4f211a9c75bce4ccb01193690f9c131896d15186771948ac03d1438ebcc6c8922e74bee01355d0c1d6", "271af4e05ec3f79", "47", .Okay}, + {.Log, "d3ef132243ceae8e83b4b07e0d555cab6a6ddcc0e42e8ef8d24a2881955806311a696a4cf289a846c984f4537fe584d89be30e3c0597304662cf5ada4ae96d236e78c0e59e9bdfd74c0b24262c91dc4e7cf11b0b40cf37fa6fb711d0b44bfb20dc51d3356d25abebf3e27a05e5712e431c0f39a79f0f6b41d77efed385efa8d25b4d67dc56fe5b0e77768eae9db923df8ce036b63aa3a8ad2c8e8f0f95f054255425fe3803bd8413813c98f56e204dcfcd9d9087f0340bfccd242a9c8503da10a2ea4adc7c0c833f61a6f45d1efa5c48752c78f82c3bc21302523ea83aab1547a1275726fb4d51bcfdda6dd4eb33c4fbf7de698a83f8c745ded98962c934cd9f43530497cb5a4b3a32484e54ffc0c808841747739e74975e7342d8cd120d811d81e46053204f97be1503dff89c75d3448e221898de4488bd187e07d36d89ea6edea1a1220f449415eb95064b36da5e04f54cd228db18d22afc34dead30e5fe814b8b7473af2032efeb8fd58e62828be4e1be77c2cc4815766b844e899444a671efa449c326a45b609107ec57c6829274c7f3f5ec83d54aec5b11702a6c3b5a39defad176ca6e689eacfc361e0a438e9d6252a282bc1bc2c1e7367fc3d56f7874a0b3f2cb88a243ece0f024cfceaba319790b24a86a4d029f70437253a49946bba3762b066a5360e9fc8a6d5e40f4b2df2b8eece5fdeff9621f3ca3bcd8d20f3d", "99850ef3f645a4d", "45", .Okay}, + {.Log, "d3518d7e7932a0e64dce892c9e8037a5014f50e90a2485bd9e44865473fda3dc2f4a824b5d32b4672650513c50a1bc6dd75887a7b76749bad753f57d0a62f749d2fb937acf669e2ccdb0121ff059c3f070c2e92573abe20ea89ce4bfe192f054bf3abc493159364323666acc0224edcd7f3d3ecbfe7f0ee84c7cd89875cc0215b842dcc9f28f22a6192571e996c5a69fd137f14fe1795d7d71c4e5dc53e59adf57ba45878e4858f538ebfc20bfefa1eb2343588b6c0018cf0da7cba1b99fc31f25ef9e79b0586c3f128efa2ba8f7d47ed1b885332a969635fc09bd786887ac9358298abc71638fa502ac96291216f6cc69b205acfb84cee94488db91ae099befef859b69afc42c776f65d2d06d5923f8e1f2557f5b152d97885514f9b8b14831f4e3ac656bc27f79438bc59cc3aa96700fcd554d817c61592c00d95a4e3bfd917202dbdea8993717412b251259f98358d426992b1a70c4cbd9e2f131495195d4d81a77980df7a3fe66a90f3475b619cdf7e076d9ed1f257d1a76aa32e2be49a773f3cc1da0b783113ef7256102c6ef27e31367edc26ebf04625e878f14dc2c2183d237a3d1dacee69138e97c780e763b31c50f1aa254fb02bf2dfec98b26ae1062475a69de6561843eb91118e755ebb270adf520590dd2f38ff053599f9b7566988b4e20d76d99aa5a1b61f2e25a3b1679f53ca0313abb2ecefd42f3a5f796bf", "2f71d582cf4cc33", "47", .Okay}, + {.Log, "87614843108a78adeb49bb82e0afdc206f2add1d92b6dbefb6f9afa14e033a1a601a5c4aedca0bd7cbfcf3b38152773f5d1ebda04811dead806c694b505dba23b7870d9c3c5bcd6c81dabb542937b0c504e613504af2fa633ceaf5e66e2ed84d369b269afc6d476645617a6aaa8d8752e5c6a36b3004533978492af594fa54b2863b78e2ab37f122976483129f1b58b63b1f430795029e2493a4f7d08908105b2936b18a7baae65e0709ef2325da33e9875f486abfefd0c9582584504a239ed617a156e20bf130e778420e5a667ff15dd3f0dc21053ac0496d4a971ee202576f755f6d5dd7ff4516047fffe18140816d375c4e9b24dcd7badfa8236bbf12995500225254e3b682c08822dbf6d75e94c08eb5aeaebe18b76a503823104746039d15ed6019f76b70ff219376bf928641c797f0dcc6eecbf0bea7c803d18c967110a819ee6bb0051e99a118885a1e7a5dfbb8138fc758e6a22a2b3094f75311ed0ffe12ea8a06886e1269dfbeafb55c6e3486875787ea29176abda4eb37ca64b12674ffcb6154b05503e3537283cbee408af84d3c988de423af6d3ffd06e82d6e5389f2bd96577e5f3b615eac0586068cdc76aef89a7550fb17998dbc57151f306507aa7f8edca6098eff3305525fd8d26b3dc66216afe1dd5b10f3e7690484ed725ff36d53ff1de8968ab2545a81a0840d3d7ce6f8e3ec2defb35556d1396e340f", "4134a415155bd46", "46", .Okay}, + {.Log, "19e84ca88615ac028699a3ce9ae35fc6d2f41569330a7cbb39b581e7b01f92f4ea459706a0094fb0bec03a554d27f4cb0a26f4091f500603320bd76698d3bb40657b7d069b74312ef7dd19aacf7002e155b49405902a32debbe0b8b5bc7938d57357e634bf72ff40216f9fa9aa3052d8e630ae8507b274f5e5523fa840a5c04853abe1ea07126eb8fe910a53a017b200d1699aa2aa56ea30c1ecfa984daed0ea7d29548827621f370a1da9f945c3e4432737e59517a21eb119c15975ee2d8604a36d9a4ab42dc5c0fe7f889faf0096e9f45e7d7c26c80f66b2ac4c5177aff093054454c2a678466e2bf63f889719068d855f73be1b9e315eb37aaf3b815fdc848dc2d9d353c27a2b391b10e894958329d27341bb6d147d16e837cbf781e903c07b220d761b5341c30f5b59b178a6682e0b187330f30515ec04652469a3fa5ff267a5b6e14d2a7ff07358f8b7b46b527a29225305c2b23d59177751d1b11a23427cfcf96bf619eb285a8460f352dbb11d0a71e73737c123aab493755fcdc7a2dac32a32aa6b9b4e18775eef4ac8ec8dd6cdc870ca4da17d9dbd2fb6e8f17e62fd03a3a7ff33b897f59466af5fa4015debc00f94b4f60461aeddb4f0d515042ebd298979785d8684788a0c3db968e8d2493be5caeb55a015bb773677b7df3706c6661de17261064eb5bf0b982823d7048144aef3cbd3914e5a07f0d98754f51f2", "bb6f3dca837268a", "44", .Okay}, + {.Log, "4f03d15b233d98299a0e235f2ce3652b89e1013ff357b0a970d8a4c188f8722749cd987e4bc37fa8e56b151be5b8670cafc829e73e32130c67a5b40209fa4f5788012499c27882001b48aa94633854a054bddf1f53748038236435b5c2fd82c6932daa14f4bb60cb4669813b35e6016196bf32c8fdba6accf6eefb03d04b315641722d76a4df6383048c609f9f8dbe0bc39863b9ac23bc1e11b92c9fb25d0e2a7cec88ee742ef24b409924fbafbecb4fd90a48dc9d4b9bb37c3d296ecfd9e0d2f491fa582a700b4f2c7fc7737716586a04964d83753b525e06fa1046fb2fc53c08567d4c67d1db841b30d758d71b734dc8ff15e4b5ec4b34ac06e1205227972246d51addbfbbb9057ef2487e583daec7c9003f6bd9dfb5d227428692a5dfb1b4c45561065e34c440a65af0038017a42aa5be2aabecb33765822bd959f79566216d2eb8b617fa2b6de5c59770ce6acebe16eb384cd6d455a5ea04b42246654ae65b22e024a5bfc416258ba77e373855db12b42887e605e4bfba9ccf4ed5fa81448fa260240c5513fcdadc36e6ef3c9e96200b0ba4ce979452a1bd34d2294fc74285ed412338b68612b68a0155218a97e7cd35f062ae67b52adcd3b62454e9bdbfec8d6eebed08ef15d1dccfa3194ef1ecda3de8703c0b992bf29b51adc24ac2fdd0a3db597160f59ff2348bb0d04ad2eddd63839fc79102807949f4e77539ac5a", "19c4d34a2927ac0", "48", .Okay}, + {.Log, "507831d9dca710a007c9da6313cfae49df2f2e473104660e2cdb39ffa46e6d598f2cc2072bd931e7971944f0116674dfd87f865cc8225c91db6a052600aa468b090e2f8ac036f660005b8ecad36107c17ef9338f5d4bf05be06e0e6446cbf584cf465174073466ccae98646106852533b2c3577fdceb1b2c7cf475e4209e3290bf7c213ec441ce52be4212192a94f87cda342bfcc51d4aacf51873a3bd40dd0688132a3a17b16543fea57b6d21fd6f2509796e8ad73dab00430908a2748a5c4f96a5384db130101fff56da758df04a41eafb08bd9978c443ce5debd3b71e05ecdd190d60330ea44916ebb6b872805d1b31e2216e0da40b34716ce55fef69ed5733ca448625795dc36931ed3a9c439030bbee18d98d1b32f3a7976145bd98681f8c13bc6cfb8a768aa6937d5d95e265c5d6d3dee21eb71436b41ff261fee334ee179fd0f03a52b3ca4855953156f4215cc7a40620c1cf32e48297d725c9df29036dff00e9c4b044b848e687c808c29d98d0c099280269f0a2aea26f3e3433abb5bdf76b1f719fa512b1fd19bec83bf29e4494ace8cc8ac7f86bc093ca8cbeb51283e4269cbac474e85f1eb40db6f9228d3d3a8af54c69fb7296fa054a2694f6f1f513200c1f61e7a0de33eb7711bccbc718af62a55311fbdd2122fdf02b693513b681af01bd4620cf04b6335ce0a23930b860ac5580345a1d55affacbd1b13859", "52bc6ee6a015686", "46", .Okay}, + {.Log, "36a5b58378f6fbb462ac549873053d53f8c281537f59087a3665a95c16002b124c355598f1dc27e9a91a1056fbfbdbe9970c65b4917f5aa6e4138c1660bb68b111bb1cedc2250526b661eeb89299d4492910991b5419f356192e8f3771e6fbb55f250007afe5a6bd7658958c446acdcd8d6fa59c7e12c81d854a0dabe87cf9cccc322fc8a8afea3c593ae2385bf75282bc40b741fabe16941297176d5d5c31899908b9d1b90bae0ac617fcc26790ad70373e96dc50e28bd0e2416c87f5718944e0127c599212af89d23a8f2d6c6d7e2cb84e83908f667686fa8c55e8251ccaeda1c0da9c8b3ab15275017027a3184ce6126f37a0ec791987d03287466a59de1acc4f09896c0ec36dd8a729ef4f0a7beabc8c8b9b672e0a3fad8dd876e2bca68aad8c18c481b1e0579a7ba5ee0228f05465f3f202967557b41bf371ff9320b7f83802fe2ca83f735af7ebbce3e858761ae3f72d400caa0693d95f2d6ca239c41003c01ab00e8b1a60044ba45d305996b2dcbfdcbbe7b3b9d1c3312fd241f872257e3bb0a1f25d827e9f24a71e8847fc3d90f7c28ef18dbace2a38d519b9457f53df01545a217615b104335814eab4712e6baa946cf2924089de62c9fb6652fc146dc37b34060501dcaba1bdc8fcc8848554ab6b163428065c048d7062c01767871f893bfd8c8b8dbf68aaf5d1f64381d1f4bcc0cec200683b225872e271b58121", "796c91b95855082", "45", .Okay}, + {.Log, "944c2d0880986a09bd4b2baca1d905930a95d4e3016ccd0b5238c7a0a2064a5a4a5fb0f71193340cdb385c211cc32df321b58bc33bab9ef168d5ab642e3de4c7453a5a30a1681225fd12de3aa070c3c2d77dbd8b9d55d1074347659b730c518893428f6c9acbd24451cad73a6558e390c0b866c3f90ffe43135b59d667d94f33de64f9f839ba928906f2be7ac8addd7f25d1e62cfb3bd8dcb9527cadebfc8150f1251805021eb58c7e83b3b8f3adbb899051ff2a38fa9125e3fc30a1811f70c9b40bc7746ada75cc538b0116e262e65c182fb38e945d444e77f2c18d39993e50b60b450aabdf2f5abd4eba9e37061d6a65f9d5fb91ac86364ffe291debed13ce2313e1a6c98a498a9869fb663c1b99c12cfa8aafaddcedf23dc8fb8daa5cdca1d19592a824c22b74aa04b3144886fd22e3ff37d170ee064ee816cfb28f7334f11b69e5d592f9ef0eaab83763c048670d9a88e611dfaca3f13e3f0ef1dd7b7c93f20d4acc9c983ffb6a7f430c65990af9c3d7511a2859f6f2ed088a7af2762d7aca7e3f5adcb4d38ba708a514d16aecbca3b3984d859d7cc0efe4d3ddf1a605c11f509c063b6b7f7657819aab305dae94c38f21cf23f1f8d00249ec18c0763374867e30a095a9df7b9dca7751f2f5ee234b30b6cc6a4a5dea2a0c27ae6e6ac9ca62a850ee69167330c8f78d4ca32fdeb252e09bfcf755e4ec8d8f4746bcc68bb2", "39cceb944ae15e9", "46", .Okay}, + {.Log, "bd79c26f5003f8524e3462ea067e000b39bc8427323888baafbf104841da142fa05ed621a5ce6b20f50c0962bf5b0424283360e4107d76a67cedb508e4362ab85cebf9588cfd3ae12bfee1add331596b2ec2cc128033441a0d37586ba182bd564f83f7e0fc636308d22c1267c85cd7b3c16ad0dce39665685e0e03279a79d83d3b9625d256f82cfd248ab1c7370ccbc74fc839ac540c5003fc5958b88150435c0698ef30c915bffb988c25133d320903d55c59f577454f03a4b2cf26ffef035615fdd178ee30802dfd99af6991e1e8b95680a4fd0e854588c5a9c3b6ee9c7521f85129d426cf7be2e87f82c38656d0ba71d987a40ebd2b3fb9ae05b4cb275318895b38a7bcaaf9cbf089007600afbef0832d8fc2dbfd5feb6af203d42429ae0c1003d0d35ccefc4f8f28acb8f9c2d2b4f14edefa79f2900455b69cc896e05d219be8f71c8cd9b057c87fd3bc5c15aad526780c5f50dd01a015fd588805d9834397597bdd576c0bfcfef9c19fcbab233c06d380172151003ea45dac6edaef922dcfdbf07c2c2e63625921fd0ce2ba1bb166eb108269ea3274b26bbd336e24d8bde89aa04c0288172e8d3d32166fa6ff8f80eebf0238a849bd486566cf737801577f2245e186779c7cc30b0656d4d1aac1f868fad920e4bfb86bb5cc19ae526e4bf2af1f1d704846355c6c4132fd979fce757373580676df81c94e12955c30a48", "2d3554b66833f2f", "47", .Okay}, + {.Log, "d6447d3101f9757757a980306b6fc6e049259905053811656c797997966aada867c7bb799b7bc817123694943ffd077403c4a7da4792f48ebfd646b2e07fd80a6d3cc3159f119c0ded8846b322f56675e1e8a1b224b8299c8f7fae7da15366de7da3c77b2d84905b2d17aa0e4c33cd84fa3f7524314e57d0d5e551b96bda56607cfa4f77dfec7216d48bfc69cb296a6ac1f6abb121fbc9c894283712b1ed8d80cf4b3d77890d92f4b3a13681fca8a538ab44b1e10577535c5f7299350f2db042a0cb1b4db1b8999ec6c7a0b283da729b6b33b1ad3c97b63b92135cd29be58939b77d854ea33a947136b6ecc8188ad862b3ba920368726e6ac2daec8eadb8773428f4cd1c1df7999b85fcc66931c66009378ebce164290187fc34a1679a61ff4fd1527a84b229960284ccac1a208236ce3937c72adbab5950c362966cb4533c75914d7507b1f352f1b7a4e751b8cb1daf148e9c1e3a4b739c92f2a64226e607659b1e8e75e62439de9d9c79415f5636e235cd027f127c9d9b2cd7f47f519044d65e9fc60ccb3acb4f583cf9099530d5159554b6e248a23d1cb91d153e5d207f96fe1163d287cbbc5d5a3c70e8419c4e99594d70b03a5137d20e40c8cecf54cb2d08e5e8a1126c275fb0d9ef207ee31f9015ad1be7876b0b93c4f90ef3615b91954896b29424374b75b53e17df3701d0481e6810e81c33439cab5a40b5a62f22be", "ab9c248a596f8a9", "44", .Okay}, + {.Log, "69e493e7b4a6a8a9507132229ac5c0201a21b711a25fd5ede2b21ab0c7a13d6937b79bda49c807c6aaa27d12a674637731466cb117da3af37af868b3bed6544ccf6c95ae585ae0081774f13f1a2f587a419f120071fc13909ec9913c576123ec32fba24b06f46a594119900699da8e100f026c61cab59073fbae6a71a62f12dbff0fd52c1807cfba24dbb498e635f98664ec4381aa713104733cd7f3e2b07e244ff52f19276622bef3f44f2c283ceb03e05d0d4ed5ffa594e267019ec19d42d7c61448cf49ba7db28df90b004d3404d2adcb8d4d520ff0032818d182c874d48b29996df77524a8cc63c92bfba07b7a7d3d372ca9bcf58ac784137d65a218c4176c2042eb2d966d0660d9d543a6c030f3ca259f1f6292c741dcaa58199ffe747d9296aa8e40f49facd178223d2194dd1f126ed0b1a0f2d4571e932c17c2be6e1d3cda51390bf652b2dbafd26bcac8c2b9612e7c7dd595714e42d2b2ecb314dd4d42f3d58b63a96b66c1f3b3b52f80361316a51998f0e9836abcbf757a78890cadc8ab3ad1950b9384331c654e5efe90fd7fa722ebb2f16302e8f0b02af85b8b7a1051f3fb6f2af0bdcb1be8598a67a7430d6ca802533f37d92c09ad67edb5f03ed059f92b8a9eb45d87fc4d48d588f71b86fbeeb2138a440ea287771d59fb2733f6bd59e952982055305ed58ce0547e7c578e364071fb3f8fcdf524d6829e3962", "255e436341651a0", "47", .Okay}, + {.Log, "f36039d05e94d669349592f37afe299df0da22b06cc74311c031c3ddcef3f6c6e12a0ba1aa39eea8b2beec749b42cbc5678488fac4999d1b7bb9464361ab12e18b6ad03452e517e9127a6cc616429d2eae0f4ba96c3704a5413bde2d0270a37f269ada1d5ed2965da04ddf778838238e51c827708f98d6ca22ba7aeef90c8a0978ebae9603416ae18978bc4c528b01150962a3de1ea9816e17bf08c988c0a7dd982c67f1eae65c4838220db2bde1676ff2a78c4ce7089b43bdeee01e5cb107c3a91085169a59a1c55e55db6ceddf501cde3f5c21ceb2a343a75c4330344119f899cf5c59badc20618d973ca55f1e55ecb5479092b60ec0fa2342ebd5379ad6eefa1103290830757b953b3a0c3aab31dbc7374109fcf8130dd467c81a894050d9374f63fcbdec5a408dc5ebfbde2a27ac05e3281dc8440bd6ae19cd7a106bffdc1cfdef8ebc844887ffb118499d67afbdae8691277d73aefec2c398f72628d0d5192e8952be86d73da9966da10f213b5c06f970f8213eb9a7c30aabdf6c0ddc630560fa9cddc626cecfdc6e5f22edf3cffa50804a6589831992a299d05b45d67c1d70de27437829c31215df4580f742d77dae416f5063932778d639697df0a73ab58f357b5b9138b5ba8360e61787bcd2d171a1354308b52a42ffc42053aa526ccd9c078911fc44f5aa1194b0ae8b572ad3d31c6a051bbefdc97231f78f6586c4", "a7fc41fea55fa7", "49", .Okay}, + {.Log, "8479d49bd1635579ec7204ffaf2d44b893aa93ff5be031af0b0acb3ba5cb4350985e5650adb5c0459e2ac963d2d4de7e1daeb511f6487f047a1092bf540bf866e8da9f04700751b3f4e8ee4bcefd34439967df47a93a2893b00d8ae4acfb184d5079d71d4ab9409d52538ca4c61a087bf4fe76c4b53eedcdb68a51d7f5bb4b433aebed0364be86c12e6274635ddb57b40520fc778efbed1da5b34c093a6d06fdc2b87417166f54b7c9cbb0cf290a540f7a04ab05387100cdf2bdf326a1eb0705d29f3995a7fa99591f23b141ebc05018b816d31a9efff5770ddebd54501e7b6e4a345cae9cebaae496502d3c08d4958dfc9fc95fb79a485d24f8ba374951725bc28a3cd221d1fa370d7d0aff5d00ef848856db26bd9932a013488a1868299fbf88adcdcc16e9c2cea57dbb12087e8951ef471ecd66de0f1434b4950e14656aa026060d09ef236ca91cc65c206f42cc164dcfc02d04e4166bab88995373bbc77f3a22b46d5dba4fa5139900bb98d59b6b3c4ee44ce4e586c4ec97efdd407af131f647a407730e65db47f0a7b77826e15e64ddc8295ddbf49645e608e33dcf197616d27cf051c33bcc21b4b993a3e1b6155f0732116d7113539c0a95fbc6e86878d202066da4aad7d546c7641f0213528193cf9ab00282856ac6d5576fc4e78643de2e66da0980b3e1c2dea2649a1d2ca86fb8e85e8a8cf176e000f2463b4bb1f3", "a1618cdea3b04a", "4a", .Okay}, + {.Log, "7252444ce74a5d34d8253851e9bbf9e035232cb3bc35c4f2a98d62603ee1fc292bb9aff16789e9088e2e831d8c0a479adc9201c853eac632621d713488a5d2c0f3c64196df8d41424c48d9df649c72613e4a10fa1b90a8999588273bd068c9dd9bf7e5ee03a0df494d52a7fc4ef5a1a36af90f270f2c90725b4b36b665c16831db25ab21a2f77e4615b45a2896ac33f5a196ba8fc4837156affd47f625f7f3552018b8eccf15659693048b248d0f7d2f47fd249bfa8c0899d961e77f1a886a34c8132d63bdc514fed7cc4fc91a93d07c718e28457d1a8c83bb73e581ac827fb8592c00e6c1c5dad8cecfe65a4178d49134eee7cee475384c84d173e2e08500291279abb1866ce0d1bb57f4dc2a9647e02170f470159bd95b8551a98eb9f0808ec0c37961a2dea288a9283f49743108639868b460da4801639999011efa8ea23c5c6d61e768f8286ac9d35ecfdfa6cc30b8b93ef6ba16d092b0ec9f1652308877e6cf45eb64eabbf961dadb082efee3dbdba13d7edd46fd8e1f807d808e7bec5745b1d27894c3760181c3b83a5fb8162e9f5441d720579632c239b5a963ca3987fb0dce8c3be9a04fe683c1490630b7cf9badd803b568bc34b9caa670b383fc3791965dcdef775376417b8202a6f14efce7cf723e6e358e11e68187bbcbdee78f4e7702c6e3e54faf213d3e3d9891c6ce497f37143880211b91937e89e8e945db", "8330bb2c058cda8", "45", .Okay}, + {.Log, "349fdc28d9ba7bf553703df9037a259facd258ff46e9acfbbd298f63e427ef7152a66201aa404e48be3cc7e3629f851bfb0cf5510bef7585515e64cfa85936e78dd4baf83851e1f5cc2454026fef709d748e9f73ceec02118d3a0e1713573cf1c56c7b5d4c5f10090ab95f00f5b538bae1956e8cec157d997599e76275620007b5e2b49c5936b04cfbe0b5443c98f45ec66144d0fb2519c0f9ac7e520a0b29b7f91fbd4e65a32d24f9453e84cd37f8c7691f743972eebfdc87d794e60c3cbbb294e695fa522183902d2a0a0c45f9a7fcfa697ee813cd4f5c193fd8a2fcc3f7858e86e2b1653cd01cea7079fbb5e8de7df4a4960b22498b166199407af6636febf1117d9bea74aea35ee8dfc4d64c2f73434ded91cee5075462577a74bee6cd803c05d64fd92b22215ce88ab8b7230dbfdcb36c9504fddefc05b94d2672536526c5579bb602ed561e47caf99a05dda2e6830c43dc633d4f65ffb888af72845c4552be9cfd78bdd86e11e5f05732afb5e0ff2dfba330fc75254ae2fb608823c82f96a349d3ea6aecc4230f4051625a475dcc57f247d0c6e56f850ce6a4cb55e4f45307f4fdca4a5767c8e6326e7aa86f6dbe2a31def95861ccf88663977537ed1592112fc1ee682cfa1584a1ef98f62eb8d9da4dc2b538543715e4285e653de0b893c0f2c4e215794e877f5f7e8a5207cba890322bb823bdeb299dc82acd00442", "1260060f4dfee73", "48", .Okay}, + {.Log, "950c5023f76e4a48ffeed94e5f4497cee00b6e33fd34d10af4153974e40ef9fa2d43256518d433c67b482e68fb834e4397ce479f2279f43b607b5e56429dc07a2c01baac389614522b75e0dc53142709fd92fea101c6dcf03d9c2eb01f77d6fdbb224b09d6e90a1f606b657705e02d71640f5455ee23e5ebb34b615fa5125b2d08ed4c3f6f0642b6596b190376e8deb1e6cefbb6b1cff4306461e42d620c03c42aa0ccc00dc71d569d770fd22749cc9b24bfaee8f956a6fe86f1116331a57c4c5a731a38a2cc6742aef14c4c6520501dc52b1534aff849f9957af0d277bfc3e5a6eb231dc2354b5eeab117ead3388a28c620066213b23ee9e59c2f146520dc57479f5cc9c6c11f2a085dfcc1c15acbc9aae33d210e1ff43e50025d35340b4430d23461e834771cb5ddceda0805145fc0cf1174c32d646789cdd040f897f3f93107627c5dd65342aa3d69656a4a5f3557e031312b1028453130ae505ed743f7d382fc8aa5a49ecd1443a201d5475a1629594c7c7c75f78f9ba29c698eb323eab2fa3095b01ad96cb640b9968ad67db32f4681f4f19ef2369a194c53e586f31f977c26807e364076a318e719a9c66e6a7c70c0254e55f7564f1ef5814b0a00f2a3dafa1e3815073f05a9787555496aaf7a755963ce68b3e8563a0b91e1db3bcd09a9b560a38f2e1ada0aeeb846d36b89b4dfbe782faaa0b23c3e69f66815e2388c", "1506cdde56deb15", "48", .Okay}, + {.Log, "2a7c2131443573ae5685d829470ddbe35fecf951cfb885d819bb9e4607576fb25cff860ce4ca76f2629363b9a6771a236e0d8a3103e236df805c3a93e15f780479d3a6b78ea59525fcd385f36220406d6385f97a3ef8201aef42f05e5487cd0635d6de1ba65b6dff4be90debb7d775c03111bab585bccfc6f64560ca9a0b146b1a1267f5c5921c9e2c663bbb5fa87d9b6418f7ea916a553209117391e66082c52900068904d03eba77c650ec6f53ffd3b821b4365cf32129c3bc5d832e4ffacda70d774a8c388808e05b809abbdccf037a90fe8e9d56b1780b1afd6c4696cccfa9a6814260ef0dbb2d4ad78cae1ef242934339d6f67a1de50b6b79598eef7cc3ccc1045dc89f701e6d1601e778c091b31f4e9181b38e5a51094ebefb29fa4a9effa59acedc634d52c10352f31e9fbeedc6240d61cd9082879c1ba57d449f89e4191ad3f91b825b94fa21a1aeade15e36eb5ddfbffbe18cfc49af81c9d72a2cf0b08054d16e3413d70a7b6147406986ea50c646d7b18353ba64cc45a59f0092007c8270445773af2861c2c54d652698d8a722b46378f76c916397d23a4b0c992a85b93c5a59fc91d365f2ff83a20e50e33f1264c485cdd264c4a820b3f0537111e09668833b534feec2db558e47838f1f5e2daf08a57ef86f9ae4df57f9b9301f341d44ef1f90d744d7535e109161fa92535c5f3164ea16a91a49f326617c888a", "838f1c69433b3bb", "45", .Okay}, + {.Log, "c2eee8f06e4c4c2fc29b936e186b7d1453f74b180b5aa1057e288fc69d3796d4b301976f04f3e421f5401c9d6ad2e97e929184ee84de9abbffa6ba4005c0275cfa0c50493768b73a9a3331fae1cfd1e641f0cea4579dba7f8d9d48a7c952781254bac1018c9246f5daf91eb4b64a8a4024e720a689b3d3ed2aa5deb1ddc71e31240c397595718f2b95395efaa64b990528f0b9f2d60acf08060892a9db3cf7b087fab2795927e2a3d62f13d3f78052a4a105c617374a6a1b51d2d6872a5f745c4913584abb71311d451c6872cdb648d29cfeb52f426c521326409bbc65f42b759d4c8e0b78db97a88e9cb113c404171577fb435a2c627fa4c6c06b707f01a538cfb8176fd9c75b4973ae43389cf2eaa887c3f244ff523768f45b1ad37b33ed18e135aa446a4f851d3f7025d5fe76a08d3ce4f42beaebdfa7cd2290a66ae4e071563feaf63775caf154575a9bb152d398f20e2d05e6e46c94add6bdb69c3575e86db68433f1f522165b0a5fdab196b7e7aad9348568dcf0d81f2cf98d93d87a58c3250fd4b2db0b608a938093a12f6583119eee17e980f0aca6bfd0c314c13b6c9f00a9d5d9411bd62e0dc42237c8a759b2e7f33dafaa8ab471a7be8c0d6d34a57ea4befcb1b271a849562c202d7ba7c7c63d2b0ab6f3cc7054afde993a087549466b3180eaf30fb6154812d2ea3bae201291872923be540a406a5fc75cc5b82a", "bf81d064ba74d2c", "44", .Okay}, + {.Log, "2f2d74bff4eea3e132d5afd1951afab6e57a049521243345ca33a773a7c953826a68a0ce9c52c4d60887b8ddf51fba6baa6637719f1cbb2b48a51cda8e45017fe906ba63fd6ddba2c7dbe66f7def952ec672a31f481b86f23dc27d6c76791c7a1530f91484645686b633147a1c3e68c9f39bf787eac23eb147586518f2847a060187a8fdadfcfcd33569095afdc4102528292556104f4e3b34d1d634521f800efa48c6be55fc80da38d605e9a92e817ffa90244faf2bd504cbcd0aed8cdfbf3426c9f3a5d0f1a83041a3f91b03d6b760197da0d925dcfa6ad15af638b35b2c4091ad4f1cc14e2705210ee01e7677aee15ff5dff527033167f7d2b4f73e5cbcae2f9f4cbc32355d8c18fca4ee696d0f63ee18981b1a2842c8bd6dda1f5467bf8848c2f85bce2f8ded6c2924932677466cc3e77ad3d57d38a46f468ea4d855c321926f9d0b5a7700a3aa4fbef4c9e1560e69d77012f00f7d8881d362614d77143877889b6a82660c8635f2a335e5292b8f55d7f23f9ea46a426eb76754ba3c7fcbe06e914f10ef546d5f2ab3665d32dd8bde8e5fdb9cbe3a3a0346c9c81a6f1b2066373bac1b6c4c066c6199faf2ed639d8dc4d7d32207aaff440e9a1b68b0e94ff89b76fef2ff1fd8bbf5f96b4a8d2809b455e2da3414a9b9efcbdd51f3c933065252b918e90a5d1a54c7c14a110d65d5ab9ac3d6342c5cc5b1c99ef637128a1c", "f465d4f823be2fd", "44", .Okay}, + {.Log, "a665f18b9ba0b89d4151c12c36ed46d6e21e0eea3c8aeab0cd03e11125e7a47cbf055e7311284c378c1687687bdb6e7b734233e303b0a09f8c0bf0e989ddf9c79c615fe6e81fcc517721f1bbd2d4fa784739cf3e04ad5e356813ba4ee86b3b798e1d3f9f8197c84942f2b70026524e55e5e8e1a425f98c97aed1e390b958f6526c2d99fd1c8d0e66017506548527488f0616560375c1bb483863e01ae409cbc0f9c38506e5752144af5ea69fb0081d8a8d3912a3bee5840d5da8f03af6eff6776396d3b1d56bb8e7877e8bf4817cbb885398d3328d32c78d3da90b84c9f792253ae29cc7fbc91911646d067aa61b61ea95ee5dc7eff7445cd8629800850d00e4f839920083e69418c1d6781bcc06bffe61216ed2e8206882470bcd62d41839524aacc8043a1a83f298c59d93f0ba6daf0b331d40ec46ad472bf25dda20faa444a9f13d1df6c6693988d46794663a9ba669371c70bfa6e46c1508150878be0ca373e0e6f073089d80a69d007544b3c65ac288ff039ceab674f0abc6e704c1817d7517f8aa555611a9abde3e81ffc1dbeb430f0fa11b3f0b71820567d6108d03e7b688ed6ff93b04c80779b54e83bf9eedb87ddf938e0b5f59308016ae1d88f883515509e8eaf9d335fab841661736d5736bf14b8ab05e8a70d8f5428b882d66741aec9acfc23801eaeb408d4bd0376cd1d8fe5d840359e99e867709d440afbb0d", "95104284ca0572e", "45", .Okay}, + {.Sqrt, "5b4f80009e280ac5a0a517e85e0c0820d042db9b94cd25697ed8245989d2e256f9bd60344db679a0b440f3568237e7780c3417635cae578e2f5af18ecb2038d9c1586dbfb8be8a87ba6bb529510f0a39a67775b414c4aa2859025c6858bba8a855c473d28bbd738edf835220a58514da7b128e6f2c05b3ba51470ce4a220e38c45f4768145c4d3e5b2e3e8f0d14d4d4ddc6a793af91127d8b9ce6bf2efef43e838195c11d09422dfbe48be7dd6909c0c2742d64237b4739c0a1055c2bc3c95984a2c5d8e19bf20465268ed0d6950321e5c29bb1966e6e20b10ddae146049107476a500a8b8363acdb20ed23fa22201fec4a58bdefac546e9efc709d5f283eb4c13e6fd33ef86136cae547ccf0397eda23a5aa77d8cecdb946b53cdac0da90c91c3335445c8772afa633ce0e42bc90bc3e9af61aeabbdc9b3ec9cb8819f5972e31fb54fa812428ff80c8d73732e65f91ee2cbbfedfd2b806145ed358285cc959837b96ba436f4645326f352cc3db03d537283b406f1fea58d6bee259497ee450d21e395b0a82b75683d60deb5454824f92f96f14d74ff106484a2da83cdb8a1e450baccd6524db094fa9f68afa27a926dc53fa307ea667cf1b5f750fc74b7a9e096d7865aff27ba8d0a032000068321abfcf208637269506e833c6e7a05a92a40d3bb8256fedbdc2c4bf37f6eb57478cfbdb9725693c909ac462600905165fc81", "0", "98e3f6bd90f952354bb3ddd7ffd5c1264f959438d4068d45d21453ae10dc3411949fbb2f0a650e01cf2a2bb3c2ce83766650b5f12ec8ac24bf736ef000cd46dce4895fc874c20b92abff3c574dea45f3b58f96850b8ff761d420e4647ac3a7fb6783097346b046330c67e1c177deb3f06c837fdb06436d41799aa24202416f275466fae7cf2471fbc7c437abdb41c088a7205abfad033c58f885fe92deae08ac6589f8311d094d9646e2215fb7ef930ebe809225dbbee762383edb0499271251a742525b8a37c4390b49c959b313224ede86cc37845827058096cff7f453850ace7890cf3b98274aa40bf62460dd6bfa29e361075161380a53a94b0e6774584d", .Okay}, + {.Sqrt, "784475be346685f6d2842bcf74b2760bbe17daf5fa91232d1036cf942962cf1ad4ca9c14fd352f61b551ccb03e834e618011bd7a8fc12f7e083ca8e8f3ea65b61f707894c4b9a56e0d2d4f8317d783270fc1cd321d9d7312d02e7a561c62bd3b33f0f277ea2f2a0a45f3d6beef2eaba24f78648a9e6b4d7102ece74ab9da9afcf5d9996c7e557a78c0e795c781d90b014714c35079aebb91d56ac3ca9ff71ecd75c425d03d28708e8c95f6692d6e56aaef9be79f08c99ad76f576778ee0fda220109006f0c052a56eb6d6837e3ced2326316ea1885465d04634e5a8e0d9cddb816b8a5c62e138b2444c87587011ce57fd443d7a01433dcc973eb09d90fb74be5577e123fac1c402d7fd0634dc6e1e0e64b0caddbbee7bdb42d5bf0d36a86fa888ac00d7db8f3bb4b1aecabd4f9cb8bf50b2122324cac2734c2c54b01e0e9cf88adce17e0bfb1463860a67f14f6e003c01633a413326746179776b121478904dd4f6bebf352d838763803aab7080765c784fada88357db308fee232c5a4caffaa46c9f70a5b2571e6613d02ef63713b08dad00bb1120c86e062c601de05869ccd27da6be1a374637732640d540cbcf8f99b34f2850c24df6a6df1bea2e8ff7b25e29f3249a6090aeec77a78c0ed95d64037461547c222b1d3e952eb24abea48e1b1d11f29072d6fdd9940bc7cee295230d909f58ce351e333f38fc26747f2d47e", "0", "af7766707fde36286bde65bf07ec438f5e7ca9da1622b56380e5db6f9c491cdf35dd82c4c6d2460ff5da3fa691d756dc82edf9a6a684f5c5a21dab6e7550772842b6fdf9dd3e339637ae0d63a9feadf38796bb8fbd24734cf086ec5cc9417f1562099c0fd2416e8553b068ab80a6e09ef706f452450c558d2f5b0cac3a28f97815abe1c82da88b1f60b1e279bd18f547ccf796e62da95b5cb2b26d0c2c15e0db1ba45408b04ab1f0aa08b17d9d8ff421e14512a5b729d5dc5c9bec4f3a4fbbd58dda04c921fa8916f748d398f7df6c1b0a75c088351502cb5531413c0d79dc6ea9ba40e7801f2659cb26e6d2f407cef08ca69581182b5a4c392d0f4bdc24b14c", .Okay}, + {.Sqrt, "c52a7547246837375605f07e9f08c03466a00650d623b03ea220fab1176fb66f9fb4ae3085ff8f22186c56737f5b6b246b64954ef5a817be38f141cd0fb60ab79649762c56e1ae1ce726a1d8aa8034f378fccb483d2788ee9797ebf3d6b9e48f34edc8c9590f1e31617ba46f76ad446ef4170c6df8816f8390a609385bd9b5b533bd07cbdaf5dd74f6d1fea8bcf3aa0f6eb6022d9858abade760704f9fab3c0114c8ce8caea6c92e5116ead5c0de0d6fc9aba2bd0ba87cc277e1ef98b82609664eca8a982202df7a2f6faf673d80057aaf02a21832eaa7388c724460dbdde4202005bca06b167d75b62b11c65cb994359abd5726d61a945f381f383442c879e6a819c49975969ba0976be437817b96414ba0ddb72f1c22b740622fa9821e08eebdbab5149d7a45e717b852d26cb2d198027c558395630f53ace1b0d53bdc8a10ce34931364f0e263aba1e81deec050ec630e6d948aca11bc3e76484fba6d04becb593ef2b5712490505368df141b593fa999ffff6264e045aa19bbe3412b6b258510f8768f857410ce361e109df2594d25b502f1a4b207680d92438056eac26cfbb4592ca73327b6da5117dd7849652c424bd7bcc910362f0def0284476d672dd9a1b99c02d25c117eadb1db0c81f149d77bd0243271d4666645392b77a3a5b1757ad55983c38e0aa62276c9630be6dd8f4646643c5bb23057158a84c87cb28", "0", "382a92db44c28c4afa1d4c81984bb4ef0d2bdd576a5b78dd2ef0a65faf00f0417ceca64bf12282e6a445495cd60f77e7a33b2c72c321655095752fc07570cc6a7087325231e42888769eea77d8aa2dd442b1b84aa2cf493c739bf54263c6a13aea715a5999957a125bf17cb2b9e390f99a8a671986a0491129fdf1872474c911adb8f3c2854ea0dd95276bde66e908c777744f45436c6a5bfa39726b551e16104139781f2aedd2b41d2f812861f486375f0dacd7648f8ea761d58ee642635336c9226ebdf772ecdc1ff278627a3fca2671b9c7ddecf2aa64ea86aa9c458f94b7e7f5888e51f6773d4ca31353777a1aac022f2d96d87beca682f1326b537df7dd", .Okay}, + {.Sqrt, "ba2e31e9f1213c5a8dab06a0ccc886584fb62676ef7cb93fc64daf344d960bda75b2f5b0ae26f915fe28c2bed1eafd0a4af9b4cae26e58f5d3ec3f5028fe37887bc81b7cd9acf84593dfb92efafa461f0f7c784e06efb2083bbb34f536cdc64d678a8bbdb5beebef96a2761c75069f80f56a9d1226d2022059bed4a57e53ff3880bacd2f5bab410d49ee9038b4893917ba506cdfa21aa647ce6e8a4acc5ef53c7d8111b7c77eb2b3d3786d835c85722872f6d4516f30a392cf1af6f4c81907aa921850d73289417597a5e88e8b67d8dc62e5b9e9b10445a0978de92ea27687bcca1bfe9bb697572d9025a654feaebf8453e6daa1cac471d61f10e44b2959eb4fd1a4e5c92b296b8c25d907122bcc44be0fb4eccf1fb1204a614867cff748924af2555a3e6a0836ac45056987e050f4993d5362071844b140031cf412b767a8963affbc0cfd2f5549a4053389bf218eb404ffaefe18d04644659f1f7ba65dc5259aeb7f748df48eaf83bb0765981fc857e51dfa89c455084ff31fec6e49df94034e569be6f2f2296c219ba00f7072c882eea6f746cf088fa762ea50843e04ee0ec89ba4bd29074835ad804854c3c673ecbd34fb2046d90e23673677cf856067cab330fc1bc2e2933c7673ce6117549d1e011e3913d52b4b1f7ed9a6ff3f6156b1d06439cc08966988c1596850d8210f5b16721f81073897d3fea0bb1cef758b1f", "0", "da5115462625e0d2e588c80fc5a730d03a189fa32f607a7bf928ad00a19fb2475d811b0aaa00e31e9606e35fae2ca00d4a9de32ab5fb3cf75973ab7f13326e09f5c8f57582e1877ca432ce367e73e46556f672413b379a0a6fd130429dbaae1a098048e5fd3d83e67eb50f5e7fa158fd7d699fabd168332b6d3b72ab9d28d3ca38bbabcfde8ba067df2a8af224208d2578727d8647839e1c05d622ad5bba2f0b07f9f5d343bb92aaad4b0568221d25dd3ae63aac5d2e192ce0466b846c7117eae8add5a1fcad24f1b0a804efce9fb104f31914f93169061a04fe4abdbd5f7912d0f0da9e645294df9cb1c4222753738575dc457701ef947f4a772c6f098f31f0", .Okay}, + {.Sqrt, "ac54862618b5795dd07105b8a27576e6e950558a06c756ca5e48888700e75a96d18456acd90317e434ccd5dc51a8501698e6481356a7094f8f9512b36f8ef745369dbac4a53d2e4554bb4eec955ba6f04e2671905263f7c3f6327f63013fc1b45d4256bd56920dbfb6e8c8f7bd3021bd2da6b0963c9263ec6df89d95d775a035d33d6665f03877bef0694bb721b6197470a1b837ef0bf834c32c1c8eb3c8594c584274bd40a23b54265dcea65937b192ca878f64900905f8bc6c58301dd29342f19ad8e15c91a0f0c58df546b6ed61641b3ad96e0c48287f3ee8c354ef1d6af932d32f73c4b075be04851ac1abf9ff793164eb3c8bef85bb8cfc5a0e5319820c505a718618e6ffb6dee3c70c90fbff28c48f9bcf191f6707f808b80430d98df58387518bdf3dd8bcac83161b02604f1e8c81fb87f0db3300cb90a3c01e4c184b2b981be7b4795d1e5437e16ec3ecfcd3f83a0e76b31fe6177c97ea3ccef9bfa04ea0412733b0b3783cd4cdde30804711f139bc19fe8c80a7a730a76c05049259b02fb7e8cbd8fe41d74ea1f8c93fe2b6073d47199ec832f6f64742a04e364b1d6bfebd9c06c03eef02a04826f8ba9be5c53d39c5b8c9d0b31f152988f1e140641455fdd2b49139ebc61e954278a6854199ab37a8d38280e3ec14d9467a7d7f3c281d3f4502f662e8242289f41b0272ccd407600a3fd3375fd80cbb84cffad767", "0", "d20a12228b69e0cf42300e70195a3cd2424e34759da9b590095236178ed764eb03064d2c770ce0c956e8308175cd39fef8e3cc00fcb2bd44be8f0948fd9ee91986dcee6ba4bc133e2c3947b121529eedb2d7cbea312b4387e8c2e10d0f2479d4eebb5b492aeac9b5833a00b16127bb54b18ebc1fd26eb662dafca515adca06707c3010b3a30315e15a6252f1e5a15afae7bc5f34f27526904bb6e46be299bb6c6cd75a434bd8892061409fa5c7e70d9708862f5f10fa732f4f98ee44fea997b8c6adc1aeb02d315384afae2bed97adf34b9808c4e65d9c9fbf3edc06d5bc281201bf73517ad1935d74d617077673db6b84902ebe3e563e8d3e9ae9217ead7f06", .Okay}, + {.Sqrt, "83864c0dd72376e5aee03f994670518575d286848d372150a6ea008fb31b7b9829a1a8b8633cc635ecce67f6fce80ede31f0328cc7df1f7a7373bb87c4e66cdc5344eae7bc23b0524b23e526f79c88b2c001032d05a33f418f06c8d47fa44f039fb1b32f9e9f63ac728f56dd57e0169433ca70ff70ac2246562d92e49ff56a6502b853b74fa941b73182e978234a0e206dc96ce7b10b0d71a8dadbd3cb18fd9ffcd9a6cc6c7e73b30d93c6f1e1ff30b61c01147b2f2920ed228b5cca91163474430deab638416a3f724a87810ec395a6fa6aae7a545646f38f96923125bc69bf5d4650d9fe3af5161aa246aeefa58809116eca19266955b01be45f3d14ab56f86283a9f63ce489d88f814138927ed81b9b5e78cfe24bc67dc0393cf9f7167ee3d211b17daf039a5fd886dd864ffa1024743f7f8a7b3c6f08917f2c8565e74c85f9f2d1389d38b9566ad6941f02d2d5e858100352a4de85d21e773e943bd9c57b158c62a7b3726bcc84b22993fa3a58d3603c760b7587cf261105df1ce0c54c747c104066a0b1177aea6fefcb79f7cb520cb046788fe6d5d8357954a466d39a42c865f42541e33688580abe5c23fe9df84148150e67fa6e0c0a139269c22191394cdfddf9ca4a2585299578241b5bfa567f8c850407a875f10e8ff02c2d36e547cf42e3a154d27f3c014c6c72387e28111183155bd885b246ec7efcd388261e3b", "0", "b77ea342419c48fdd7e2b32c088ce5fd9849e35834765a93c6068e2b7810cca9a6ca683de0d6735d9093a9cab09802b86383365746bda2e551d4b101db379ccb16f8af44ff8ad7376f9ee2cf051ca82290317885ef45a17a2bcc559404a62d4cee1a3b2daed8c55d370402e0ef226455281feeb735c13c590c2d6a4cd138c0cab5b1e8f40d55a59b1e0364bbe193a1a30f1b0acf1adc0295d3a17035deab4058944b9bee2362ac227726f3326acbf44bfeb885113cf9f6e07df8be9a4c1e4ba88c4dbad10d289bd1b5fd4015e92ed3e3de0e06bd3bd555b2c3d207e4c7127910f66345614028148b838a3f4fda3f8ad77ab2272498dd98222a5d4f21f06b4684", .Okay}, + {.Sqrt, "c8fc5ee304c172f81dd9136ce443eedc051043e6072e2994f2f7e054a9ee7e51ad99ab62f39a62138abe962ac333856354f604b492c8e453356cdd43d4ae710c16f400be7e07e393de3052ad0d627c544c6c89e84a580a6136b3bb97f10060ca2cc39e6a80d793823a2ae5107a1772f46c80a90fe4ea892f1cd640d4c5953a905610d0fa8a5f491319905618a8c00291facf5c0e67137db3e59304a7c59b250d3eaeef8a7b0797d77ad49919d98b1fb20ed066bd4f9347bdbeb3f8dac578e979cc0932563c8db332e13b3f5f4241ff8c39f1d6b47bfe3738bb9bd7c348d9c1827225557fa47a4be6995c60196abf291808b9c1e26eb1b66e69497118485172ec144abe23c8d061c43d5c2eb5acd9795f9cf7302bb0e605627474a98b461a22727c3cef52d78b7ee81f873d6bc8db1b85a87d2fbc3cda9c7806935a5ddb7dbe1414f74f26e4af587b57abd0ad5cdd2ef2a8c55e53832e800bd58e8400bbc43e1be97c889e1f60df57613de78f40294841f39dbd3c1dc4c98de5298c5147205639201f6f3490ce09e8ae1bdee34288cc2bcb78574f03297ec6651621c4510476c446c424c32998c2d9c661eaa7a43b80e381f16b2c9f2767bf7cfde567d9cbe7dce981657b8ed24de64b21cc796d867e51fd2867565746e856c60ac9edad6f696f24e1aec2eedd5e469e8e1648b4bb836144627d3e5c50c2d77d115ba82ce401d4", "0", "e2d4c6409a2e7e647a3aecbf6956b917879df84de6c112f3dba7718cd3f8b178472a479ec5101b7298ca4fe5f9aebdeda4f12704aa476f4bcafbc0ef93b7bcd7913693f6dfabbe33f24ae0d465b1ccb15e3abf7a5bbbd6c6c54ccaed8aa76d7da21a597dbaa2cfe7e191599d9eb311f5a7a970e74c93da0600a6cdb0feefd222c4ba0d480cbf4c93f32e0aae0cabc8c4979173e582adbc366b8ebd870cd2192d1f8c74483f5fe74296d87292f922017a9f7240f6234d5dd9405cfd2194d42d8fa44dc8a999156605b203aa614bbe08c4cd43875f77e0ed1ff5a8b18b99ae2ee28bfda10b75288a862ff74d41e816725f3d9d1e51c6ae8731a9457e0ec5896d1f", .Okay}, + {.Sqrt, "3c994e735278ec5fbb12c529d9e174a41d7d7fa9baf3bbf456d7f05ede960b8b5e45fec7bae71402d38ed14d861ad0a12a0c5c1c50e3cf907efe51add658247008703b8a9ff80e8f0dc4614ccdc93e72b7c30a2c6189f0da63ae0ebc8e9812db4bbcc9843c5d7f6ae8bf4e1655cf0034ba73a24d4d330143dad2f468cd7f91203a0ccb1c1780ea5c841efdc964c54d6a5f949abc6720651cad722a38480daec50a21e218027af096f7df9cb203d81d96b22633b448fea07bf465f49b8a5561bbd598cccf38b4ef62d6c773f265947afee124ff3106bae85304cc5cdcb9e1c15dc689d11bba0ee73080766b6f7fdc0e0dc185054325cfed14639220a03a2f3d2e275cd86f8c37a33edc07c780a0ff60cd9e5aad3556e75cae653c1dc4290c9983c39d61db374657a8ba8c2e8e369d2104a59d9e828fb4c35ca96ed35ebf6b2b203a7f0f0191caec342ba517ddca8f6226c7232d3fc24e06e50a17a4c4ad1a084aba12e3ca8841db6550ec2878a98073ebac357cffd8419a2b3b1b04c4aa18f4c14759a74642fe46523b791e7df731293951fd3e09116468605d4675143f2b5c86eb7a03bca1495315915b47250448881609a17ff83c0b1cf63ef4f29e6f8ecef7a38e21e3aec99da571b0a7ee73d9a5b131d191bf5cff28f68d538e18d7ca97cfb748d54c7165d61c1132fead3c1f48ae27a487bc3911d3388a1493d5606f9485", "0", "7c8d6bb10c87e2dabff3598d34e22c884b57e502e70ae41fa673c1353eace28e27cfd0288cfaf58b823a50fe66230556ed60752b43ad050486b616a62a895bb32ffd27a3b027c9658688f7fcf60cdd76d85f9616e0ef90582f3db937592593f66e6515a72bc69200524cdebf8c246acbc5b593cbc0b50bafb388f655f88998fcf19c85a13d8ab90b755104a47707aa87968e182ecfec850f470dea43a9eb365ef07e667990018af6a3f0fbebe2d56487489f044d53aef3e12b5bb9aaf6e577125d1ab60ab7b5a70d2f014a78a0a5846d8a7dd6bb0042dc57d444c0954eb96c7879d16db45ef849efbfd69e0193ba4157db432cb834e3ba1608660159ed2db925", .Okay}, + {.Sqrt, "104eefeb133dc7a174495e1ebd508e18b4e9054a69ffc4f3a54e88452eb24ca3cbd2b13b975f7090673f06a6d63a97ca284ee757b73c9f6e80d7832b0e87bf83e068b557de1fdc65750870669797f72a39ec4eee90aef73bdab8dd2f4f48e628622934aa1fda5a87ef4127167d36da26620d2636ffc5cfa7ded798eefcf654e8434dc2345b60dee00c1201eb8ac397dd7b84a3ef337c6a367f414b515956ab572cecfe826a834eae8c27f5200a90feacafc22541a3021c30e2fffdc8d54a26ab07df47b681f9b158ffad96715a3ef5f07032fd0d2673fb01e401f8d93e784457758bfb5cec44afda2e098ea549d876b36094aa5472a5214fae9d4262d67708ac97619e5e5aebe4803a59c0fb56ac397157f48c8b6eb7efe076670f5ace4c23998fc62fc796aac92dee3ac6df9d54fdb5d8f1e6d24a09c981717c2ab2fdaff16da51d1035c0046ce51f20ca2847681cbfcda0f4a2073f1db7e9015bad004d3d17a2c3a94a47394c364eeb420c063929b8a61535c28aff6a1d46699a2532bb26c63b971b67a54356eb443213d8baaed51484fa35d388b691917cd9005c05517c40ff4bfe6b17699eca0668d9365f47f7a57cfe66452922beb64988136cb2549e9ad509549605f2cb993e0e111e88ff5f1e503812142f941dd5794a59e4a58ac64ebd2f4af9025e56157715e4bd3cdb9185da847f2424705948ac63c1324f807823", "0", "409d1ef8263f886644253c26d860316291f647959e81579ce432a5fb94249bd04ae46aa623b6695aabf6ea0179fc3f6d6fd03289e31bcc48757862a57f0c6a73f64d71dd3dcedc31802a51887e6cc4633eccc50701f7ef7ca55c1439dcee060fc4b68708145dcce10d281b0ff07e35fd9a77df6dfdf29baec118c12ad1eb8d53cac2d0d059b3f345f7f459d49cc408c8b341d67fd7c2e729e5c09f699e9e9ccf3f944c312867c3edaf528f42059f38a231696acf72bc88d15efb40eb667ac993edd01c3e91ce8bea46e408d4a53b9d0e7a1975efecafba1986c796e6a7f014a2fa6bb10479d690ebe96a67cb18284ebf3809a95206d0c935a288688c6b75b562", .Okay}, + {.Sqrt, "2a05aa91ab21d6b289ea02d26df6a15d745f6f93114f7a74c4f1ca0cea1ac0d663b8c9da1ff4b85abef3a9c4727ad4629828c3006061e53d032f113bbf5b9437b9f5274b56fbd2b7cefb98938951f05d092b89665d06cd25192598b79222ebec71a398aa36cdcda798185c7373bc058252442a75d7677f1cf6859fcd0d040f525729d4dd3b2a8c7fddfdf2ce4a5ecf339a8486039fb073961839c4bb0d5ef96e2e290f614d4eb675db08e7a483fb3b712ba90c7bbb27c63afdfae5bddc73eda2086268708d82866957d9f68a09d64fadd1fcaab911aaa95e7c964d38a733bf35517604e8758affff2b816c71d0454f6a7298f63e1a253db30cad3c74faac9281c1bf8df16693d09d8f6b8f6c26bd8bb1ed32b8befaefa6aa0635e30838b64418a16806b90719a1bb9c2f463e1fe63d959865254a62d9355e9561d9975cd7ffd77f66121ee6b0a6d5a45001bf14fc90d3bc959ca86dd9b379d1e0a63b2c973003b72fc49fa4429e70ea22a26a45b878ca922e472dfd0f1e63538f2df3174a3ea5140d73e83d5ca7caa001a0078e862db9f832a5445dd3c6b63ee3873121ed870b64b086102101c02769bf11622095d2bd0fd58961cfdfffe51535b30c3f1e23c854ccdbf708570463b96eff7cdecb0b555faff648aee47253be091686ed846f7d0cc7a72c421cb2b2a102a48710b7992f4f2960dddecd0a5204251c1f132a68e2", "0", "67b81b8b4314cce93aba614b7b72bac80fa1ccd133162f1211fbd3c390db837249873fd9c4329904edf7f657f2f8e78218b2eda58eb2f44860dab5ef8cc15e7a19e1f2133b534897f22b8f0e15f3c775def9dfdf80a6c8acdba0758e48727416a5cd85ffd513c3ef1fb2f11430ad9519119797af8f58abb0eff24d71e0ac77ec823beee920e799fed15c6f669d853b9be6579eb3e02a02bc2aa7145ad6dc2e88fb2d570fa7874032685edbbcc90f85b659c280e35e7aa801272370e3d7cd8aed7c1d1c0b2dd17700d2f8bea949b930ed3f7034823c4960f6e7b1d73ac0d2144c93f006fdfe6eab231c288304a186a6e00611dd2daef2522da093ccafb776e570", .Okay}, + {.Sqrt, "b66b3bc4cc0ec1e4692faed6daba2cf295705f3bb5e559e3a89897c43bac347a75e482636d11b104551d1bec3a994bf4901ff36b107310adbf773d9ed2cdcc6c44769df6825455fa7fc9dc6b5b3449e835f0d92fb025d8c3429c4fe7e5c94ff122ddebb7fa579281b62b89f04a288f2b3827c8ef54227451d39a2233397a0f2a1aed6921e0b6f0814209fdfc158e2b546e0b8104229c75855bf9e681c7f7afd6947c57b7199c557a13b55b1097b5e20b41aa31bebc37dc924f4b0105bc0e08661acfadf5645d913d22d9e7964a61d9890bcd6c24f7769f7c5eae5766395ff7f04120adb3e46068af4cf84a5b5b8f21c55853e205750bd016b49759c5a421b2d13c885a4384be17457c65a212397701c1e2fe6b1756b058977d294d8fd91225ea9832fb3b1d33b9b588940f03ccc20d080f2b3a90fe9da9f72d1d6d1b57e004c4fe84f1e5438fd6cd3c3cbb2c52cefa6355da670aa3611f2de99942a4ed4b659773f77b396ff364930ae35222d8d8849f7ed70d836790845f00e1d5ebd2f937aa634cce6c7e74cf9681f68f48e2807086f2f0448a6a6b065c5638f9cb0927d862cca2d8d8d40453f90d4f66b7a8433c6dc44842eaad2bc7cf30e1692fa877100d624ef7a19bfdc029486b76295dac2a82f3e395942c60976d2eb7fb8c658d848242610a2160f3f61c1fc7914d9db010de777ae45c97bbd7a8543e5a93bd5bf7e1", "0", "d8199d28b9d9c41a4fba211140577d49b8023f57ed7834f35a18cd4a2ecc0cc01e7a758db0b471b93920902de53bf3f3e5404d46915b37a5398b8f4577cbf92054525b7369447f0bbf1a2a91143ba0cefbccc9edf0b53d7c33ed6fb7d4c3d7f6be2dd68f2d17d99fc7f741dbda35b795137a314d7a34c00adf5ae05d5e9120d0d647479abe714f2ab105ed044758d49862ba4fcdca38b097a1b1af3644983350bdc81ad73634341409f0f4082a1956aa7fa1ef3ffd031cc710ac2681ea4db3a67ec33f6d88a180aefb2ce7d2070a0a45339cfe8b6f4d3512af26f7d8ead463ff8aff70595b72c0bee7f606f85f0eb74d9ec711b4100e154581b9ebbe7a6bdc56", .Okay}, + {.Sqrt, "5833b2adfc41d68855f89dbb4483ead83e7a7078b1a15a384b0ad34138a087c90eea90aa52bf0b99c7026946d2af6684df6e3968c6f2d9629d436cef55581b93cef4fe949ecb7209947c9c0101c61f560b62f62af651d9f8e70c6fe2e1cbdb41c404952b6e7033d0c56f034029eeb4b335f0b191a1da8160be14a22eff7c76f8ad23e57ef370c6682cbaea197ee1b9795263b860cb0d893dd01b6568cc2ec02ef5f2c950fa1615d1e3942567c740282cde50be3a6ee254afb2d4fa3dfb1463683a78dd598c02e64604b0849eb6eadbc8dd0db6a98601682235f95038f54fe47b22220791a313acb3eb03d63b52a0f5d85686f42d47e5802cb90d089064c7d16921ffcfbf849ce467434fd28308f87031d7f4fff254f3f1e7e51afaa6f003dafc1f63594e07d3c45ab184d065dee94d39c9c416bb84a68bba54815b66dbf4877de81995a130e38c2e07de1f86c28621757b761796b3a4656094914e2d9102aea8e27f1a32c1def4014a41f6ad00df1a377e12347c25e0cccf341758e4a0e55594cf026ab5fd1d2621e3bb43853dfe10cf14c37b94057d9de41627b393aa7040e7ca9b9a1eb041e408e7ca5ef1c7d97a16f859ced069ce4ec944af82285ea14505f54e8337f6722a7b0a8cdf64649f979097d75d4df6353432d468cc0627d6f094497f57c7e4b5cf4abe5b4860a8194a6a7e8c6c8c00405136970a4ad03467ff44", "0", "9643f2e57fb6dbd52c4b3c2882af254160c9dd1030b5133a6173e5d6305b324a7874bdfffe7f1ffb69574fd279b901b96e1fa87942902d1a1ce5bca9c57cc6d433f1e4d4c1fdbe6f7bbd1f2797d92ef9b73314952a950bdf555dfc3c0d5c84f30fe0d301c7443bdd77a9c7ec3ab9f6d03864e1c7697421b6d61b343db0933bcdd454973d61eabe69e1eb7c69b7393ca3951d4b76ff3f611c3648b24a8754f8eb4169a99b8cd1d2613831d643e5d2da868d0c2c8dfec968b152ef2116500b46651f3d1962df179175bcb9cd67391e4790bd9dc45a44216c9cc94aca3cf7b81f3c0ed4362de3b1d928013758c7b6f0a63ac1c1a2b18053da23a52e773f40235663", .Okay}, + {.Sqrt, "949102120d36423b31016a433bfb94ef049823c5d6b56954b29f1e67ce6fc6bf7950da7d03941cd620222ff35c627535bae6aa1b72aa000419e7ce82002dc277c75b689e18b9f4543f9a248c405356a8687150aed53a0e9a626d9a52747b739428d06498c1fb55aa9e0fbbf91f767eb9c168b642d474b744f9b266fd795e9b2eb4d99816fce527519b7f9291a70d9a575c2fc6f8f64226ce9df03a6cfd807ce7ba82cc986c7b2e76d044ce622de0a78c9d02e9de7ee1fa5f5cf53754d2cfc601fffa4a08288e4166e0d252e535c4c3cf8f387f4c7c234b32fb8b8012167e98696c86fde3404ab53e198fd594320eaad8c8a7df01dfde780dc0701f216c556240572b1ce7a39b0591ee5f3b2573c1b7b8596ffc8e4eaf875ecc0d9c85c25f650dda231efa8f8911aa7650b5ccb7c086784439b0cebe0595413951dd5f11369a91173c0d7f9b4fb6b20c6f971deb96024f072934edc167c071c18c2134964a31c1b24ac81c066fc488a7ed66e6d1c7218a4b36d5df139e0d394355979a19d5a43e89bc15b91ee3a5d8cae6c29918b112905c70a18c4d921d0bc59da79affdab8a1d8c2a59c3113fc6b29f64628530bfdf8e42cff6740dbbb8db29edb6f85b0f1d19516220c017855388d2619dc1c5c4ab0722c3260c2037030043cff4caaf6a56262f1a956ee9a2894943b27f795dde247bc81bb7f583d273408f11b112ff3cbbe", "0", "c305419dd0e37f548d7e3a37b2ae8378bdc8d0d1066e9b59f260cde8a873320edcf99bdeb868a46ab9dbc538beb32f4f48a435bb224e2d6ca8b24f47bbf2f983a7e2828724b690320b95cc6a08b3a2cb2d96a8068ef86203d8d9c568fe4adb01e7317008f7ccac53bceed2c2e8692e3cb2296e2dea7fa6371f82287000e96510a0cddb7c9fa3d1d0ed99168a20d13572ad7b47cafe974d3da802a86ea8c401c918725d550fe091323c77c2e4196fdf531dba1ca2d9d46679e03e47c527f1867bd44994ea104fbdda8927ea5b0b6346da8f37eb4696d84f2871814aaffe935993569b42654d27f92e7b5945417caa48b0f96c2d78c52dcfa322a4b03428b1cf0c", .Okay}, + {.Sqrt, "cea7bd41405e39e9507e7b21753e3dc0cbed177529582ee73287202a988ed86e8da6bb27c12880dc7195882b01bd40b7cc28f1546a7f2f9cc8c6acb65c151f4a884ea6e000716c9585ecdc7ed444495294c6e750bf7a0b55025fe858173464efb69b79c1958c872cf29645540c13f929d83663222528c0caa2a6a5426ac5af96d3b88aad26e5721e1679d051ce90e084f2a9d12f8670893429cbddaf1c2573822934a72293e8ac4fad21134583b4c0419aeaf7c79decc6a80233d4c83644045612cfa0c896b5af40e9ed1da4637661b1faa1533ba7ee013f2423911d9fe272c0358db36de4e98ff74aeb0fa7fd6326f4e6a349894816f4dd6b2123ca2dabf6cc2ca87b2071a90c9e0cceea0e914d5a28a51e4540f1ac74e6c30b50d49db2538aa08a4d2e82f1095b1427fb7af6bf4b5fc25535d4e24362e0d97663f09f08e13e16011e238ffdce36ffff1d2da6456bdb25c259520dde9c69e0521ccd8665073e79eb942704b659338b5c7f3f6b1599aa6aeaf69cc6ca69905815890074b565f8bab2b0ce9b76a7fc51b9437866840cf9a6d8f7242857b409dcf14e54bf53808092d24cde6a699c49852e43104d997c0e6ed719e20135351e8306e8a1deb1c28ee89737404b5b38eb82f46d67480705d1af20b3db9957233c9a576df4e5a1e28c4ebac57ac99b28420ca54f44f3f60c5ddccf2eec0f2f487aba9ff559defc482b", "0", "e60214b9471ef73810f5f54683eb6b51d24d8e7dd72c91c4b1cbd9dcfc6c1620e87da2f7c801953174d74b94b85142b59dcfea57684e2a9235972c6f8b27569573efa23548729f6e3d6d958e43b4de0f15ed2bcc919b963f15de93a836b4b18632e4adf43b10e4e2d96c2a64ee7006bfe5b6469e8f78d24cd43450e64ea854d8ca6f8c0987f2bb0c2dc009a20fbafa30aa01be29a910bac97fb71d15b95f2c32bccb1de92026528d0a025d77997a67ade254b405d53ae962645b5027a101e8513c8cc00514457efb39e47d82b2b7fb13d03b53bbd561ecac2e1e897f82c1348d0a9208c905740c0c6312c2e4fa1bea617996bb196b15b6700053f37d027b9a2b", .Okay}, + {.Sqrt, "564e28041cf7e646efdc4f9e041d75a391ba36b28558ca810e7b7aaa67955f77f0a9979b8bfab587f6d38668e6a493a850c83867eba3148232215fd192277d5bc4982026df4aeb6f7c5ea5d81f3143c7bbf2fa6f8e658d8533f1cbccdbbba177c843b0daf0b670e6965c852ef51eb11f4200bf0ab31644db15be728115a083c652067465ef12f24f4fcc8c394b8483a347d4f2b07e7a84455167a2fc520b97fac39216a406fd312d99a828feac87a21fe9e1e3338843dde2cd444b67f5f72465ef2023fe9ee7d46e9d6874c558cae431e0f8ea2531f9bafc9c1170b37595c71c8da0dd862260c3b14fcc060b0b37267437e1c1ccd64b27a60142b27e7cef12a6cd60088fb596838988627b41e2d0c44ec6fd6b2c78bd8a3d75a6dad7fa115f43f215432011ee88a4e5da23ca09c3c94c1fe3fb2890c49fa11764bca79f5e13099978c2fb23a9585c343009623f6cde6fe2089fc4abee5d4da6b3ac67d0dd6361606ac6ab97f60ac80e4a3981158b2355996c8a7a44721fe92ed8065d9d1e44e090de7b190fd26846dfa43fe51e2460c7e85d7c4f2aff543868641323458dd58a658e028f5ed6141dbaec43af94239b1e5ea5215ca65eb761796e2f1a7935bfbd54aad16c9e5734a53de69916ba6502327495d232c1d1c3aa1e2961034f4246094760faa4dad3099c80dfb428e88851c6fb0416704abc067060a044a920f81317", "0", "94a41aa7bda4af6e7a3aa310b9c887514eb33d6c5304f2b6ec072be71246419a20aa9e0d348eb8b8510b698c3a1007a5e8e1954644fb55df92ce1480c13890bd976304a4ff6e9f793b78480f796a42044a4f0f19ced2b7af4006bb81cbd48cea1b628892bbf057df825b50705bcbe24209fa0ab824e679b4ed9d6b63c80726434eac2d6b8831895472618beb813356791f8a20d003a59af6f732a8759d37cbc198bbd5b891fc10ab636ed36b420cc41ec2ca287659e7ded9a078e7c04489cc644405444355194658817c63b7e9316a071fcbcfcc5d5e3442e4e6c943875885eb923c81279620b051f93afaac87e4d46f2c498ccf05608f1174399448ea6ec073", .Okay}, + {.Sqrt, "c01d6d04c4395fc22aa0e27d35de007784d35834f45b21362e5467e5ba9fcd042f3a15e76a4a76fddc1e6eab5aecd9ea20c5e9047108908d726cc0277550a6857fd6f42919de69c0ec16733dc06ae7bdcbbc0ddb968fc62f4e42553bfab21957f05b3ede9ec72ae172dde5e4a7dfe8efb11540dbd7302d6b8eb6ecffddc07257c3791bb2d5263e2f8903032811d947a22958e72d8c61d2ddd778d9e92bb1de30b8231c22fedf609547d2f520519518a1e629a2c1172a9df72c278337162a3ad026944eb61403a2e7c87210151239a20489b4ee5d17fa0096062812d18b662e0c905e42f3cdaabaa6898857c690c2ddd0527c3587a0526f256dcf3eca0ac8e97380b410d73542c5e8aaa62f924198b187a5a6730249815097df1202427cc8c14f05903a865eb7c7e02b5aaa7e334d080613043b1ddcf690017bba72d42c1b049788b6252b2c60c556eaf25d4caa7da95f7a32e05b48e75342419ce6a17699fc6fdc4d8dcc5a0367d68fc20c9d721cc0796d1d08fec63c058ff9e6942c5ef5aecb722d9b90d959cea18011f413862b38615e14ca79344becb8921cdf316d384de59cb6b25a8db9e5897565451f3073e0a9a5bba5693e14c2602799813d335ac7e3676cd880caad72d4245aa9961dcb66b1d7e98193a2841f7947223eeaf388a8f99626b7535b3e3a737bb578c49e232f34d7549cfbff1e0c2627e5a42ecbc0b0ad", "0", "ddc4d3cce4ebfbfa0590780aaf292a92f3abee1743f9fc8f1180286651a8a280eb1001630937f0e7de7088c5c9d97ebdd43d095a0c2329ed545ed509913348807c6ee018ce5851636f6ed382e1ea6e35ffb377b25aa2685aac0831a1f89d41ec53c9a0409e773bbcfbcfa4761e5913e9ccbc1b8240e145338f558347b2e22c790696a10d6116c1e8a6bf93f5318a237769a0555873fe0d86ecdd8eb36797a8f2ec6dfde6dd2e0f22568beddd4bc503ae65dcddcaefec494cb79e21c4b6df2b44e81a052bf587f1ba631cb6b69f5d8d46b1042cc1ce4f105fb8a2820985471411880969841188f280ed0f5f53879190cf302a3ce91671680e055b339ab0e467f9", .Okay}, + {.Sqrt, "862250b9ad84ebc8cb100fe781962e0f85716c7c22bb302a95d950983b25e4c928cc0b44aee62c9bfadd8deb5e6d8fe05cf5788ea857b9153f2a716e314b3de9e01b67c4a7f2ee9c2cfcff3325f70c529141c141d8757389ff2266f413e4c7dbf71cfea054a73181a8ab2ec84c77fdee6500bdd0b61df540da231d2c2a6621b76ba6da008f803c6c3587db690790f71ef27b511020357f1238d41acbb5a82e085c9fac6c83d49c03925792987c1d77767a1cb35f88d84ccef91e4e1c4fc5346dfb298018bab3b1075480ec8ba2412246c899beb1e4fa58d1aba4e62919c225fa43b8556adfb5053a6acad5fa831a1e4ed5a505d63f962da50220e6448787bd40280163026d6d745652fe2c40bbdfc4ddb99e14433dbcf86bdd48f97d9dbe317b1a3932af4223d75f8bd6a9d9f1c4eede192bb543e90661262b5896085ce022401727e8d71e36db9cfc03d0aedf3fa78595dfae7770d6a5ed3d40a928ae50cff930d526dafda2203358f0f31543ef2961d113d294355e16eb53c1ac02879155098d06f0dbd960ecbb345b7f686bd2c624737f67b554ef2e8a057263714d39520f8e24fc0c51e34e61e2f8d234d24e583bf2700898b8137af109288995e1895a609f04a0236cd5506b275a70649c4f79d775bc5480491f4227443899952354b8c47ac3f6984f311c3fe0488a46e764fd69427adb99292f959bef1d3b5163591848", "0", "b94e5650ed637c98c475f2fc7f704e94b585bd95ba5b8e545287dfa1b01805ffdb7008cd84a17d5c35014bd9d903fccbc7c36e2f2f2383b57d91a8848629d265ddc23a1be4aa58e223f1e98acf7d21bcd7da76d25d733a3eac2af9cf2e6e4888f4462571639cc6ea4caa9c6e8eeefefb6732333b478a39dc1f36eedf5f9e0ecf2d19c1593334bef2f430a7ddc237f02118f8ad47153bce3f4c11ce614a3d71c9544219e75588535400c318596759b7d84619057b6cd00bec230fe74baa39c3df4225b3e056851f3b5f3d69a80977232eb9b03ab8410032f899f12a536f1366c1f1b4032d44e8e76d31f2c1300d177f6efe2245a55c513707acee5e9c3f4ed92d", .Okay}, + {.Sqrt, "861eefc27bc1a47e1be2c4612800e882859c3a2e2cabd8369a040a7d2e25168d6e2c6cf9264c880c0bad823c1af36171e80ca3e79992b415164a08c9aad8227e36fb4a491e100ca25c657d185ad43c31cd0a7d74f7460c88448dd126f5e528857e206fe6654b20c5242e60a438a8ecf38d2c7a5c40e1a52be1e03e4bcd358642dd56e3ad61254e8d7f45a4c774787ca5adde74b70e1d518a8f16f1453d75fa30e30ce9aae9b1ad6d7df47129785e285e6b769cefdc09a0e52aa6b17d01bcdc18cb10cbd838c67e0311f7690890a5369f2f7ef3660705795a0e78ca759579d8d1b69af4ecb96a5b86d10cf3ed568990ced1edb9ef4e830e4a4b1312d104f57051dd1cbb72b0657bf6d9a84254ba98a49fc21cb6cccf6df3bb4da7d7e52d390e3ddb3cea2174272093970f6bea47205b3a4fcaf5c9ceb50a7985aef5823b5b5c4f4302b98984c9f0dd6d1f98fd8dee72fe20e40368e4675621df87a7feb37030f56fed1e6ed928d98830e35a71c1d927a242ffa22ab9d7a19941ba0479840ebfae33cf02d244550c71d06f06f0b428cf0fa3ecf56c59036d6fd8b9f7fef682d39c1581092afec047fe3219adb2c99c2026209630412dcc4c9221cfe7481753f6adb0d7dda23aac1f505d4e83940a9f4e647286a79d434315ae7757133cf30e56d49416ce14fe0f57f825512c70373d35d66b1e8db0f0018190e4eb282e6c5b83a2", "0", "b94c00d3b6b175a5c4e0f46a7a46d1aba565b264b89dd1e804003eaee6ce9ab96ff5e48031fa972d1d969e70ae4a1b3e077172af523bf27e17b48dff1291cb6b58cf6bcc7185983b94f1759aa86e41125e092c8767fc2548c77e5f60cf88dad625f3b37fba6a24a9ddd58ec52f2a3d1c96641dce31d581041a6900b638fac3bec66bd8c0afd8b015c9819686a320e458ee23cbc0cd7e43a7648fa425b270677c5b92b66cbb47c0004ddcea42c5830fee90932ee872a0b2948f8d6c2560d00104a5a4813a5f64893bcb23e30e6ded6b446bea3fe06166c225d72ba34ac5f34e59e4d5a391f1cf86936897f7bfae68cf8eb2dc2cf51f75bb205772345d4c9ab4ab", .Okay}, + {.Sqrt, "6ff7fbddc17d0ee7099cb96135a132b3d65c0a12afdc0ae3a088f5de8a39ca1eb633d684d773dfdf794ef9ec9f066d3d3c18679dd2be44d259ef7881b71300dbe6eaac098747d1892d577fbf9f21476b8d479e82f617a964efe57ab29802a803a85f8a083d5ffb185fe53fa77656a361e1294aceb03bd5a1054ba03f24405f360ed361d9294313ed097764b83297d852a924c384221df4146b355ea99b1ea64b553e370713b6cf21a7ef05a3671109b822ccb5bbc115b16a49294ef12628ea7d81550ac0139b5c56f1059eb7dc636e2fce4548b8689e2de160e24b8bc60d840d05a450cc3e1c590cd6e74fa9c306e8cf7a655deb684261a0accb9b755a9e417a2304c1910453eab1a5f613df7f044ffdd5d53ad8f8a92d18e879721abb1b73be8c036fe8fbda565e4adac9a9715117ba15bb4dcf104e3cd75c12ae1b6edc5b6e5efff71287e52af6030fabb0d229d8becdd2e0a74b4bd1eff3c0497e5e47b4a1086b5a9f9b3a07926511df7364dcac289d0898c9c0b135d40f72a0b1d4d598a017f1bb22d0ab3318f0b30855b28398a87da3edd3d8c5a3e4e51741b6f519afef7109b6e9e407c017ce482bac9c224fc26ecafe643d2c40deca81c5af5af9dc375a1188e6ef1b637e279b3ff19b02176d8170102e59d7893244c6d6b4960a46d12f6d46b569b64951b467706b51023a00836a57a9c82e74a602205274599d73ba", "0", "a94dedee6633babae08abb6975e086c9d6641f143f29c67d4acbccea9175a9c26a2958ced6eedef0d9d8c2257dbf92bc5fa8ccd2b2ace4a9096e5647588dfbfa10cf7c3a278bb049ef8a10714bb5a7ec207b2f3132aaea453bbdfebf5a078345d35e36c7c04e54860978a428dc5d4ab4e82c1ae21d423fa4cc3b6368cba2f34988b4ca4c2792f0a88ff48259cf48b8b711441eefbea88a94eae6862eaae1583e45b95083b1bc848cafb106075391ee04130c055153963b30972f3b6f7a90a55d8005143b4834893a0fcee497e5279c33d00f3af584f0dcf5bbda706e1999f2f24f307aee8e8e332b6ff92191a5646d824f61d3be14929a8cba231908d8ede116", .Okay}, + {.Sqrt, "278159bf84562ffb4af227efc86c3e12943439c79d523de2126d063270890d0745f3a6c11426837e7fd40eae87feb276594c7f69a487e4447edea157831b7d1c7aa01bc844cdb89aa130479fa5bb5ad546f1b26b1825f384f9f56aa12a283489bc3b8b940d4bc198651cd78084879634d0ca6ae5337138eeeceaf0cfe88c5ff7311c3c8ed37ba8033f029b1f1e2954f76f07b582e8ed0dead831c1791046f4579f2f9e07b3d106cec97503e3a463fb97e4424ee99528036a19dbd8a65a5bd5fd75176f35e2a2f7aef7e2854b5362ebf67d8ffb514a11fde9b67abe8eafe7f378752e4da8fba7471bf107cab5bce8514d6b3b5e67981807ccc67a811e6f9744aabb177dd7896f2cee17b050dac25a1dc441861cd8ab95fa5ac6408a3a53f9061b39177506a08a14441d7ba944ae3fd09160fab97bc856b7ce15e10dd997dcf8d2f4445739fd0c9ef62ad71ae096b12b853c456f360a3b882f8a00ef6876cc95627ac740d5fac715d9cfb261df779363ccc8a9be32f48e8cbef3b16a9887a18f4ec7b62af9dc26c68f04a4db4e64661335fde8cfd4ad9d17be087b0252fbc68871708e2343e46a1a965d883fd7a25c2d6cbf59371e4692ff53195c987a13fea5523b9bc5e2d12fd7d23d06713c5877ccfbc843f711c4ab1b8484ab0dfba9e3123fa30839041fb31a8de80f98a3d0f5acc51aba8178b71c0a3fbb9af4ff84eb7a08", "0", "6490ae0e6397c8ffbbbba191c9abf503e904c75a2202ef4351455b050839d560f6d519c4a9d36647e1c901f23186d52b69c86d6e75be65c744e6edb614fd0839da71eb5b0d55088c2cafee247237905d58aa22ba793040af351c0ebac735622808a8849981199c446fec5a763f48ea2bc407593f2db37526c1764b2a0dd8424b352cccc24e666259addee0149f9af88c326ff2a357fe9a57aeb9c1e3f20310d62ce4e3b5bcd4ac4e73d487cecadcca8c5dee41df9cdf242946a2cd3000365462cfec7403502ef6386ab16f3d8316d6ddb41432f383b2fefaf8498c1e55e8330f34b42d7d8180bdf8905b697f11eb267dffcb75e77e53eff98b4c8e58a8064353", .Okay}, + {.Sqrt, "8308b66a971a6f28adcb7b5e6048c305f24738b8c336a088b71979eb6e6c509f7091e6fdf79df73c836fe4ad1c971b80de715793565c3dfe6bbe62f3a7796524301213427f982e1c83786fadd9ed25e8bb3c32e37b0c2795c57c12a8ea487b8eb4a1bfc63c60542ddd62cf9bb488def8d78f471929a113af1b27a951607ced10de3f9b38f7d0d4e73d0a0fbd34ef1e320b2577b3c93b3a22e43839825b09a9d2c0f00ee27119c5c58da00cf8c0b5d542debf9633c9014036a11ea418cd52d1290dda8643f8a5fa81c21aa3e29248493277e66b61e078cfae330bf8e9077eaff8d7fe5506d291624585822d893e586eff1c319aea6d8dce0d5411f67dd6ca8e5f295a71cb3d7a9b109effd214409caa788d2cc756efda05324d274138b8621d6b1d4997111f87df922e809b32687fe3600347f2b0f08f02902b109f0a88e1bad7ceaa9b7bf178488ac463a5b26d3837763baf0a5d46fb327fc7be2e57dd21b2011194308f4347f3aa488603c404a9abec086c7cfd4c0757ef5396ac3017aef29e60a0121d91e3d76cc2f1b2a72c3c3e987065367ae87546f1496b3e90158a74d72bed9d207bd2a624fc79c9798a2e539c06b5851ee6f6ec17fbab9a643cec9a0c3b8a95818f8f6844748bbc573725b36cd69373ebe683b97c6970efebfe0d74d140a60ff4721122e2f2041ddb8a4f2970fc3f8132d563b154c2afc3db7819f6ce", "0", "b726f3c092c6706e92af293fe2ff01b4cf584c1ee0c4b59cb268deb7888d0033e1ce115a3a590900f6ae117327c7fb384575ccf14b52d8b62e1c6b8774887499b40b2990cc5b61a56df3174ddb8961dabfcada8ba2a9b52eb1b3cdc51e2a6e002fb7d9165e25c1dcf75e74681f2194927fddbf1c201ea67226b9cfa400da3df16db60a1f3c74caef78612ef7f90cbc520d2529686c4ca872ffd7b24eb649cbee078f873f493f710e0975c73779384d7cd6034c99c91fa51433ae0f7edd5c43eaa1456f6da269abac49d2290eb2e76cd43f99e84f86ed687052cf69533820bcbfb693733d850bbb08ce441be9c1071f0748b8108810d463e48515fef9bba9ce9f", .Okay}, + {.Sqrt, "e0fe4735b105d0661027a325e0b172a639f65047a38f7b33dc341eef4022b9ab26f5546520d659b62a6f4203a0382e342291842f0270f824a28e31fde50b77c0bb7b48d37c1f145b5416ed6d7112cfb5e71309b3cefb1681d4b2765192c4b0380290fb7cbc824afe49089231497c6969be0fa4cabad86e7816ad4b3df5973fbcbae02ab21b0ead6d79b2b4fe732e8150a220eff96b4e1f1162e4beff187c76b58c84a167a7b73246cbaada5dda66b1cd6be2bc5d49da269aa1260efc4e8b7dce79674c7396192c6186d1268ece3729e48c012c799e8821c5f91befb652ff17a829f70c5bfb65095a4e0a3d9fe0031d772f3bf46222f772fb4913f5f14ce14f7a04e459aac74b368063ffffa33c1b911a17b4250039e2a030aa13d4482b7e9fe2c2bc98b9fe8b40844e7b8d75ab8dc07da31122725cdccb7fa8ff42c14371845cfd44a026a2f4e79e106cc66d4fa442fcf17c43ea4007246020695b7814cbe943bc5a37b067f16a2f5ca81c78965f01f272fe50ef31886fd0a26c8f57eed1edee6ec7a2d6198003745eaa98fd2e27ddc64996856783c17f5108eb4b9f7be10a6b3ee1313b33089da82561d6694949693ac9a6e3006570fe18319f6def0db8f36605503506e37dfeac19210e39625e838eea8d4e52ae4b70e5a8ba4b3818596e89ae2e47ab45e67e134ad5e32345ed5322b66658b382432c555064234c8658dc21", "0", "efff14e8fc56b1ec925048ca18eb1563856bce2a38b17001a61a3fd6f61971d1ef4c70e4bb7e68a92b78fbe4b444cb4814352c43c140f0e50dc73861967f8775f8fc4f73cf8dfba508cc8d90a462846502416c7667ffdcd9327f34e7da449f52d36f474a09dc36a9538a2404023028d4be2831df44ce04ef69cd0e4fb2735d677fa599640e4ef8b6d7ab74d728402f98eeed68f9cdfcaa7add8dc9ba7d031aff71f716de2d6f5df9e3a1f1107fb603e7b45ff713cb5478a199efd153192e8d43482edbb75a4a1b6f147eb95de36a95fe0b2173f7fdd92e3950e8bb4b6a45f4d99423ac058cb0cecfa1dae24624925e11f99d9641996453dfaf522f74ed0629f0", .Okay}, + {.Sqrt, "4f31514013c93a0f62af8b2efc72bd70933d7ee390ed167ae01f69b5a959a3b51fdeec7f26bf24ddb7760d35a689a2706c7497407c28110c746934e93e56862f88afc6138d6ccc0b281e7becb7521cb385cbc5a84dbdd55e99554cf8d0b3ccee23938de1bcb459faf267eebbed3858c66f2eec581b7ad3416e2c5364f2eb9b19a3b3d4e9b9d73be7fa2fd6711c3c25b9aa218af466a3eee0320f0d4b7fec23d8ff5a962780538dd8bb96b8c3e3c54f40c8389fab7f9d5b9c7a493c42bb76b15e68f10991129d13bfc42cbb0e0fc9abf8eb0a67f425ce401b9ab47b2d8bc533a291124138286ea58c89d815f53384fc260d5d71add7291e0f3c0eb303cdc226eb9ca2af7d464904ff1073a8edf0492e31b0cf5adb66858bc73bc2dce562e02cdd5f318c89bd92b2994503d137531120714096767d69e7b7ae90105daec0f6b00f663ba1e4305fb6d4acc19b78e71d8fc06b17b6446e4fb6e8e02a7cf8c3f93cad23419fc3d66934b278893fd2f1cf1bd4d5055701975e9e80fc8572a9adb9f156363329070354bd9807a9271a0ac5eb69bce9a0de8fc81b9435751db3f70d32abe75fcdd5de8f2c13e708a15ecb178e9e31a9c72db60e9bce0c45c2e9f721bd0397cba0640bda16feb7e0a6596116e8f90aba0484b0a64d7e6157cd59fe001cfa4a7f10e534feb1726669957856e9978b3f2b2840f3cacbd8ce34468bf63b7c2e", "0", "8e62680b0bc206bdce21109faf1f5b7bf793d0adc61e2ee8489a4e90cd537206d41e6f3d9988035bfdf3530ba374086c815024d69add5f5f4dbd9b1eaf6bbca222316dc7a7c3c326f3853c9cb8c097b89f115a836c6482787437f6dbd0eac8cf8afdfd5fda5076e8cfc45e5b266997ff66e5a48f68dd89f164ec92f231dec2a4105859bf8cdc1564cfecc5fc84cbb01d86eccfdd83f6b247e0a731e437774ab426a443c07f3761db77527be20173ef58bbf51aecac9bb1db939f78ae27e56fb77d20c5bc77042d0dfcbc3a48af46dbdd9edfb9dfa8d5441b7553ae0df409d705133d524e16a7fa641032a8d9d0c6a39033b874321c9b1dfcd274dbf6f4ed0a34", .Okay}, + {.Sqrt, "e5dbb78508efd1b259a2aa5bf25d9ed366d0f8ea72000fea112f39fd177e271c55924cda1088b089742a9013ee5bc637402b9357dfdca1a482ced17aec2cbc75a551a7cf17bca052dfe0449b7a68cedcb237a488e35e4845f6a582cc5dfdd67c6cac6ccfb7db9bb7a7c3c56df46c3986b6cd2ec56e608cd8423027b45cdda840362b54b422b82a0783bc7945f69da490154f0b1c8742e85deed5ef239038ecbf3178fa632bf1e1d20deb5db64a0f8534703123eba165ce7fdce1006616bda3c0cc85b5115c3f5d7a5360fe5376c8bc24204cc9fbc214dbf63ba5366e68ddb3c030a836993f41d61244bb27e53552c0e5b2ff0a071484d21187efc0585b7fbbd04065101e4b1910681b5a5684f8bf75a76f9100e95460790c5af701de9b8b9044e0d9c21d0265ae3abb0660a3244205174bf80707513d97145cc1dcceb692bdf34ed233c491326aefd2f269b2a18ff7f92c09e15952c089b9a77d22aa5fecfdbe1e50321ce6bf051fff424f033067d8422bbd4d72b6f6dbe659b48345db766fd1b567d1a7e0633a9d21da89943fef016ad4a0472d01f198d5308c5ae99453701f7fa9610e03ca9826718e94bc4fb9457d878d7a5d1f5538146543b485299caf73f0e3a5ba198599584e14b545ff6f6417b2a1718306bb61b3b6396147cbd696120455426ce1837c105afe60f536f4c10c77bdb66b2ffeafc74716ce04a48a654", "0", "3ca4f17bc8e4e5d34df59e9b5756d08d8b935145b49975d0030ea2399a9e11baa8bb3e6f35925d2031db729725f66167da82c424b5dbc1d525bc1d7abf94dd3c4cfadb2b9f44a3c36316aaa69a9f07fd37da09033784653787b7dfa4304ff4288f8817918e2cfeb4aa6c2beea1bae2978facfd1f8c5793c30dda5913cca3dce17ee48fe0e3d042a272286ec1a33e2bc8520ec074b80a4be52f5aff043d64f6e8085f1c676fe6eaeebffc3c606ed7c708224c5572e428a2177b245a6048368351d1efacd92137ce201149b89493333a69b96bfbfd4df510e78a32b4ea692696cc10adaf0e54739e67c63bd5c2af10418fb1e278f254408c90744e65c679a3ae29", .Okay}, + {.Sqrt, "de3f2950b5de80c73a4b870209fad1084a1a37a3d707a154e1f34a0e71c6d2739732f192fdbd5c940735bc84ff78cc33e2226c7fd15c083535da715e56ff14dd6b758cce8bd4001df2d661675234d69f43087862c840eba7350d2aa95886b086d6df6d3578d91eb80ab10ad6d4680b0a9235a7347a45d404c38fa6be5de6074d8040629be2c996dc70ebaef67e8bb20f749fe7394ce3e405beb344a8b363aab5503e2cdc0d02175ad29bce15cfcef08289228742b44e9c6c1c08143eb0cf5b5316601c2922128d3c9ef3c7709c16a3fc8132a288d81883b63221bd75e07d7033f4341627c841d8ae2a4176ebf8289da1adf3fc06208612e6daaf131ee37a9d9fa513f0b1b01aa623085d0ec0e7e03bb7a4869c36bb95b215a44b12e5e51059087b62b8843e6150e1fc27078a2a653999c6e3f185e3e31feb7d22ea9fa6541aceac005a60c052f88b9a9e35b112bb8322c3c1d75aa2b874290e27d17e1de2d07d7d7d9972b2e7102af0c8feb1a0d307c943bab9fb9c783f66c22c27b9a975d375ecaaf850406f9b9bd35d061ae381620ccd0c00555227bdc7e8278b078c9b18ccbea558b2a8d49b7bb9ac187177e3a671a576b35456ab86fe21366c7b7f663e9fa36747824ead712be5f0d3c7264a7355523db9f6a923e3251c1ef93cc8468480bd3e9bfc02a8c46d8597d864afda426d16f78a591bdb72b6f8e94c85d06c3e3e", "0", "ee86edd23865681ad778f95ba9fb4ebb2fc65bef11d2d428c1ffc780b9cc62927e94f4b93c674dcc0af5be556059c8489cdb1f0c91f481b02baa83967abea0a5e0dc33ca4e469be611091be05451997164a0627af71a6252765ec6da0480a5bc681b46efa85ed9c3c5a82468d91f893d74c1c68b80e72cc2b872d80f24006cfd41ddacbf0934fec03e970f418d7827c180d83bccc27373b055be5cfcb7a09a790030abc45d3cda409eb2208f49754286f88390bcda722b0650d8af3f99ffbb42d315a9e966e8f4f595680f4eb2b986da83d16b6ea6fce47f3132a69539aa47b46ab021107878bb3f49065f4a34fbaf7d373b0c3bddf0ea8a6a63840ae22723bb", .Okay}, + {.Sqrt, "1f7a95c6f6fc6cae89156ffd2809124c73bc2089843e0a1503620ee0898f7f852ddce88dbc10dbb787791f4bb45940e894d77b220729b139d75a2422687481751c952ffa285363433e65c2f9349a7413d611cb9bd22b4b210f722ae9265c2495eb4a1672d033b2bf218c8cabc03ddd671f7565f3fdc1e150d34ed2688b49975c885b0c971ede9ed09334f99d4870695e452d652e89b82ec8ad0a3d2a0cec44acd32841c59b7cd5d8dd09bef84d3b5e279c5a85880e63f1173c6ddd70e4f53af1781aa05c2564864f806293bc2ee384cf69aabebad57161ced56e4777a0467057a4d6b9e467993610c99dd036066c8402bd4a2b6d4052ab1cd6923b850d96ab863d005d82957ba2e93e8b17b2516358a74481d785e775a03ce00cdea7795e4e87906577863ee6c59083d48dc7e28379f530dfd62051d6ed21a3997840de7da28ac478d30bd5a008a60e174573bf54350f25618fa4622604081352f1b9430a2a978aedce89a985fad2cab81f2667487765c43c744b270b0c861fdb11a7b51296a4ef25bcafc2d62015aa20ad62d1fd703a505b627644d551eeef5325d2238ecf1aef4f49283df383716d247e7ab0233bd04c902bcb02efa753e174ae06d95866213460980e36c6694c8805a4726fa88692fdf984c83b02beb7c67b912a8847ff40902938acb261a6823b8b713a71260b079dbd67127b024f11563f3b5f271849b3", "0", "59c505f5a23b49ef77dee6f3848118559864d24a9fb8a5b104058bd66872c2cde9baba9dca5a2a03a4833c7f2cb7af748bfc87ba964361f3b4d3ac287204635fec6e73d47b863af5f6c66411308670f007a657ba2fee790477e86e02deb117aeb94157e5e434cb828c814e22dd084dc4064a1d77c3c5fcd65ccafdc5baae8e8d06431218ab3546579ce9909a596ce074a90876b3cd3fd3caa06463c75c6d11f9dcbe69f4827fcf2d6a5bba2a6656346cb78e379a194689a83283bfb8fef95f1dfcd87a68e5c29c5c10a1e96b53191ad43c815aad8595b9698350fd199d2a8afc27e545490d3064c0610add2537319fbfcc318f8b488d3c2dad56acec2acf8c8d", .Okay}, + {.Sqrt, "7bbeb9b243ae299842e49c3bf75ef91035ad1e118b72589a1f2c392f580a7bef534a2d30804f6833bea2da72572f6cad80923acee0d7baa53ea4446a8bf2e0d66939a626c684bfd6ccce8d3a088cf77d06c726ee342f5a2aece4067b3d2bbd070550ef171a7aa367bfafd14ef33af373aa48ec50b482681869f3ea9a4bd55b3f245e3a2775b1f697131b8c0ec5ba6cb25080c412bb50c445b1f900de71e7b6beabc3d7d35e812aeb787ce135ea2ac8ec595d98413febefd855e28fec8942bdb530ee6d8f5bc8efdc200671dee74eeb5fb1425496b4d41717a789a3d66f7981ef222f9b458dd5e0331db7e59bd5d5909ad2865061c3eef5a0167d4dd130ee87d2e0d1c8a31b71903ef8c009a9b6fecf69cd9fa979c63f07e020dae4a701577885ed2dd60b57e364375f93dd9231ab70ac65450f4369a7e79a74e564f0f241cdfb3be02d66d292004d27f7f6042f4f43a131cd3e92aa7ec710df8a9e9743b16bab5d536321cfdbe985d5f8de8165b1739b406334fb60aa83d3210cc8a221a9e3d559761dbb94626e889a9d4ea5242ce83c4285497520c80112336762ba0ed56f342057dcfce0f01124ceae7197b45210d02e2cbf038cb17197c826a61cd5fc546c2a225d9124a170f7ae083c8266e943df973f4c3343ee1f9bf07b12ad65bdec35aa856491cb0134f0423c9112c9f429e7f88849ae06d8a3574dd3fe45ac493fa8", "0", "b1fc34f467cff7ca661fcbeb4d9cdfd8f824b4ce55a8f18f62a897a6fa90e5922d4269601de0de14650d37a47bcdcf2f3b0fd67d640004c318f48b2d240e284d8986cb3647b173432b883f2309c5b7f5d7ddfe3e6eeeff7f2d0279944b4d12afbe818ef23a24324ea0bba9478734388906b22591de60de5048474453e7e47a2d5cc1370def8fb213fcd268f16eda733648bb136583040d5d2cd2103e9a85b05873a55e9b11802ad453f3bab920b9c5bc86243f68a69aea953a2f614f1c5fc432ddb86feb0bfc7e61c27f950c5e876b45c78a3d68f815599d0477fb7e20f9e3b21576b608b6fc6153891c57c7b8e4001374488686f94cb77b0accb4e91143690b", .Okay}, + {.Sqrt, "ca10434d970373d1018324dc4f27fe21628e2a6ff7fb1303c60e240a34656d5e0158e0674e0ec51b7e55b8f6eb8ee8f296e8562ee4f8e0b694b706d027ca7380ed7694618b6a6859710415259df3959ef23daa88783345ced767b8c087b9883a1586cf3c90a72f3627ee4425bc804cdb35d191b38987bea8b9cda65d7077e4fb96ae52b040ddc6107636173344e07133552dda08348dd43f3f694d3dae280937160f9e81c48e9a476ccb3fced100c2f16e57ec7c3ec8b291f44c2ca3b783140a87def4006d09a29788c8af3ff9f60fd8eafccf66686722fbfced3729bb68014d391e85562dd3f807ea6e8b70b7e4365ef62107e1fb76b02c94f5796a7c5a5045f45652c7f91fd03ac34bd072950989f5661d3df748c4e5208d4d60faa517104f8320c813da1e884eb85e5e5c6dc5cabed81d8405f54c53101ea5248fc1bf08b3c6fe5eddbd0b97e14b72f09e718ba75ae88cbad54c43f39447ef98ca3d05aa3d50feaf9290b52611730fe3cbf159dcb305b3dd18af163f4b4f4d59813d22ecddeee2972ee92d579b027e43ea0acee9be74754f709985af8a390fb54fcbf4a27265fcd7383c941e0c4ce73e4a2a8760fdae7e80012fe1104a1c221613a8987032bb708479305cb235addb86a211204f89eb2a4ca5f07ab9381983b4d7b8ce28f61c9d8849ce08cfabb3bf008e38cfc2e9b5a76dd9f0763cae42d420ab44263102", "0", "e3704054270765978ed447a762ec6d6fcca30bb6c7db1596a46ff86b2d060becb6a4dc876b96d567df3a28153aa648db95874306912e25dbd1c534c7ca0e43c846497152bbab054b7bf2aef84fee2eb803ec8cd74ce5cccd3169b1990faeacbc0da1d770a7540871fd79b638d3417b90e8f8e40720b26fc530099e2b7478e6eb024b5d3a912e53b20032d48f89e6e05548129fea8a67d6957a94662380ecc163ccc0f72ae1141c8d7e36b5cb8430076520fc56868fe4b9a054a37ab44da421b10a5e29dba8e6b2c176a68b6f6f94e4552111a56589585cd42f992e1ef3045920a9cdb2879c680c2b15583aba142045dd1eef5d808fa9cc1a4751aae899f30104", .Okay}, + {.Sqrt, "55ac3acb806d698defeb668c10206edc785ca26930ffa60fc26df866306cd07582d0b013427e897d8e3a8eb64b432091e2d558a3fdc1d0d001876f23a507e068491e37ae2c60c75a59585f3fd3f82df7c626db569b343f3fdf077d6fb534f9661405d5a95931947f768673359232b1cc84347ecd6b1bc22a318572f8098168cad0f4dcfc573aa17616e9ab9b1f817237c87aa8064e2536ebd75b5bb716b35e765640be869de6b9876e555de39f6fb8503c30711c7eaf0257d3ee8f720212f16994bb1312c062962245b54603b0f1df8852aba21fcea3a80ffa0cc21a8198263d01d99fa9239c4cf7cdd20edef976b308013815985adde87dd5e1906ebdd472080d542704354a0dce2a2da8a5ee17e4d13f66257b075208cd7f1e1adb55cad58fc1d4485d7869f201a8831c6934074365754d4d2dd582541e67cf5ff809d80734b91da0456cd60c3919465967075be37095978a63cde3d4faf69e1601c9098e9e7c4e47b7514efe66aed3715e952a9d8a66097971d67e04ad2d2af14719f3d94aca5e7eb238b5f6c04271415ab3155aacc0e62ddf22890d645d54cb775ed756de11b19bfbc3b6506148420589628652963a5be56732e95a7a027bdf3b7a30e9e5c0bacc790589a78a42120f63f77353d506f6581596a3752603e9dba3c2e9baebdc892c852bc4e6aa2e5c229877b4db928f7c9a57f994b367b85929b08439dc8f", "0", "941868304292c0bc225656d5eaf8b76a02e909f1c6b5989820884510eef6f25d1c9531e33205dba3346652a20fe1a481e0e2b6a14534207066e7ae4f257f41d3f1080feb71448cc1ddff762f56cc5679954b11fa905108446a937e633447de516c9a115677c4e3921777bcbe61c808b15ad4b0000474c71f47d58489b43b7d6676e433489d86af39407b5b21c1425cb5bea9901e09302450c8fc13d0b73e9cca64b4418ddf6d8b659486539bb6cd442778bcd74319bf0f071fb66079f00cc0c1f45e5598f43fba4860912a47e39e5b04fdd90f646c3eac1cf2de9405a647ea31975050e18924e8a122203647cd7b9413c907a30760420a8e5837ad1938339d3c", .Okay}, + {.Sqrt, "b3bc60b02ec6ba4163e6985870282cf78117b83a5b38a9f11820073fa969c409e01218b6ceae28a29a05496aa39f10fd3b6b4c79a8bbb07980e9765cbb1e15cc69e857bd4b6dacdfe7641adb0c2c7c0f492e829baf4dffd308b91bbc84c6a17ecc510a071d7acef0383011504a2c52fc5d6124c6f00cb038a1318c0f8a538a56f02544775c91dd6bdeb5f8ba65f89ffd7b522a780b5195c850e0bf46ef17ff39abef36638404e3bdc48ef221c175c8d03f0cec3c4231ef65955a1948a31d8935d2022012c575a5a55acd9d2d58d2b8023ecc2128f38592ca8682e578db444d052907f109a0178bdad038c43e207865f2019e0bdc9a717c346fcf7ba7f6e54eade937f04c59d9931bd1dc87a9f9c804b301c5c523cab3ac9d1a5adce8ada568d8398cd4ecea063b6e3e1f3be63e86861cb9056c58bc50f73bfb92a1fca50c57422f6a531ef0d82e0a1931d11f97505209ecbcdc13ffb3c3cf91d78b38448f6cb92d5a4741b04c42a0adf842c2598ee794b174dd8c7414d0be2e4b897bbe22e4dc4c26d812b678ecb72755d9908a016e3c1dd0e786063734411b0062d925f6f30d242ab0c4a535cb77e74f0595c8b0f4ee42ee30064dea3a51dd5279af64667572ac3bb7f245d8631be4541c29e6f70e80d1b1771d390f15130a3bf2b2873de175d159d7b68c25c26b81dbba643887e85b19903b04ba084426fddd81df5afd3cd6", "0", "d6814508191f20f2bc7803d4c0ccb99d1df766232833fc0c8a0af5067cd7a807a344610c4311114c4009981f02eaf5888f865fb3950181089f376d8dc9defe56df8d1f4de2b4a7dd02678decffaa01d9c76771f56de908cad0287f7077e79aec14be1fd565ab0487618c7b47c7fc96ca4538786bed49d63bc53f331c7933f85e073fdd6912c799ecefe09d5c22cab0c8beaebb1f519c713829ac862aaa338de222f03b672ba65252cc9802c939f25472bc9207d43421249c3bbf4e83cf6e0975350f9019d98bd9033097df93878c9b80675d5c5a6dbd3c0f47af2185736d23fc48fe6dbfa52771e4447fc11bdcb97d0a8502f95801459b7a30975af19b6dc6bd", .Okay}, + {.Sqrt, "b04da78c6772fc95583876c8853d12d12f8fbe7ff5e45d4cc0964cb435c19717141fa471dbcc5a6e3753aadee4c90fd059c9c65f3fbbdd249ec70ce781bd74d3f867c691d031c4bad0835c67647eeffdc11f0fe1fb23531385f2cf58a44e3b58a86c2c5b7af1da9ed93a1e81e777e6b1049f66f9817ccb3b1531ae2786b21a0082b6d56a1b0cac482dfab45cfabe27bccf0e56a1d9d931a5c1262917729a8af8083f2eb4db2ee5abc371cf28cc3357bb6011e9b1bf5e1f1bc93b158076a4a9ff91ffaee50605e46a9653dcfe106cd09b3fbcfd3b9d1bbdb9b5e188eeb7251d695459c40c27f9b493b7e7343ae295cf21c5fcba2f3fad11faf3ba4b698a6578f5b4fe43dea5e85be0fc4b2b19c268cf8cde4f111c62bfabfe1a30a18529b98374329f4dbc577d190fb81a15dc8171351ccbb3de10c806b0cbd2633784a58de0edb1b5af4e2c264e0e881c749912ce29b3d06aa37a01526f82642eb156113608e4478c3ddbee2a226bf9590275d90152600296433d42c2f34afdb245e8864b2c5c994a40e9cdc07ef47a7d67a38904086dd308396f74c469642bd4a22b710ea48572fdd5dffdfdd780929e9f024f80cbe502e4b2e8237e8f99d413597124358aaa0f6ee157b6b035bd4bfc2d2c55805dc78c0f1546b84f6ba01dba6d95b97d9730d542510eba9834495050e4601b41932cf91530ef79b4a9a6c01da3edc4767e06", "0", "d472634859aa51912708435b1097ad33583bd1fa45bd034cb2d9a6f0b117337795f478a6afe27d1759acd7f31ef0b5ee16dd262ab86aac6cccdb55a6f65079ae07740c003064f71f0082ecbe5e1e4262ff56ece8840db12810abb0a3b4dbc510738919024cf36d07b293cde578e68b225bd1d07fb77d4205eeaaa4524570c13573fe43aa6a4cb44ec6901f40e33d2dda219e1b5ebf84ee368226ff91694266b5174b70aae2f71268cfbbfaa309ffbc3ca019dd9227c197aae58cba1a0e0a6b345988ba66c79161bfb259292d60f833e7db2c07d3d4a57b1b7d237c13d5ccc07b338608cac1e3ab7b76b61e0ac4e44eec08925818b8d754ce5a2918bd6ca05189", .Okay}, + {.Sqrt, "a50d68fcecce79b24a368ab945136b1e73c4c2533a08ed8daf60a6ac61e6a45472682ad7183e004406fc1931788141312500bef640eca1a25b501f6c9edb7c73a35c58477d4080e0f6b887c5babc3e88578bb4e7bb2d03ebf4ad0c1276aa133cb94719371e7fa591176d2af4bb6006d1fc82b0d33e8e28d67d1b8abe7e8a55c297656e1738497b79a799d68b1cc6ccc4ffe39b06b0c923cd8cf7611ab9932977ff1ea4c3992a8c344f64754768d64ae4ce6d26b33bc5988cb338f5e381237a703f618d347fbe3a6ba702e0765f3d0d3b3be2c3275af07b1c71f20457eeea19cc478a0e1273bcfb816d83df29d1594f647a3047cc7b2081f4a908063b3ce1f4a4b1769ceb19c7c1fe93166db0aaa9565d9c611b20136c7d3537db6be241d8c7fd4b7a824d5e6808464486faf60c5bb0a423b4943a32ce0d833a51508003511872697fbd020da4b3c11fcdb8d35e6b882f1072bd5ba9e94abffff00a04aa4d016b47e26d92fefe91a53de0df7aeb136912fa06b392e5d74959dab6cf19234b5d7f1c5d6a4824049b02a994381ea9d3c542b6c264fb28c8e301dd20419a252be203fc451dd070eda658d08bdc92edb42711ebb07d39c5a2a45de334e0bb4d5d24caccfcf3a21c3b19ca546c17f14e42b405117788985103cd5d83dcc8988a4796dd03ca9a317ad456a856afb333031dc26ff1447d7d56d4f2cf18a07a6de9baaa42", "0", "cd8e6c7d1f3bf350164cd3fb0971b2671266f73f57d6340a59319a85c2172403d6026d414c59d2eb8041b8a992f34f9b643b35bb33a6d13ee2e24f3f6c559982b77540a199de069d6ac3ab3f293ed2fe42505c79dbd8562c1f143ecaeaf7541ea019a492cdca06f994e37541b3fa161bd6b7582ae5381e2a7edd0ae199df1621a43733aa48dd9526f8eb00a0bd99374aa54c756fbf4bb17d5a634f9b51d139d556dadcd6204240da76fa97c6977a9975d716416b190336ef53a78b63044c29779a99b742d811d54fcf5d6ed8c04e7034cae027157bf08bc826d00a2e633fa5de832a8bbb1ab7e5603e85123ffc77d6e0fecb7cabb608bc3d03fe2a18deb7277b", .Okay}, + {.Sqrt, "13cfd796b9780f70ce090524ac3e5103bea693c17b832f9193076abeb3a69eff97740f110c8c61d75042d8eb6249685dca8cc7b11c4bbf866e058f8c7692dea488a397808b84b6a0610309226f9d7ef82e689bc605bceebeaed1b455f99c3eb0f8498d7595454b01d47ad004fc2a89a552ef9c0cc86cd02275466c7ffc4a06f68f8682a0e0b6de38fcc45877a3b162134f437e5e8701651ce121dc6b1e6b609a96ac8ea0b1acedc5399cf20d47741e445399603d040fbf336ab9f3b2ca7713d43129c94eef41bb57e5d2581de7397a1667af9e9538a7e1ee9113f759ead2077eaeeef600787fb8c09616a643fe326d34624f7cd6f8714a66676570441af0e9e76e668007dfe40ff84279055820133e16249938e8c2ad2adebb8800baa6b956c43db3d845a8a9a3b56c999b2c3247014fa3465dfb79e92edeca3950118dce8cdaec0d33291baebbf987654fbcf73372e22996dd3e3f629e916e4d8bb66764538fe30cd1fb3ec5461d28b973707d8e60904c977e5465e3dd7e21033a790ce090e9980ce4f86eb03b24dba4f83723f4154909e3399fb9addd2256581b74d57bc268801964fe9dc8c673b253417b60dd2c7d50c779e1f8c84be3537d49f7a11c61ace009b150c4c6255ee648541e696a50e570f85274d5c5703b4db4684fc84b7e22791056474a123dc8905b78c55a9fdbc207be064da7d6dfe18dfb2896ecb79b5d", "0", "473784984e25f8a5b3541d1c43a06c36842565f3774e7d1d063df73af37765f7039c50acafc1d432f1d5d8c06dd9d44648f3326c91a125b8f04fa4e4bdd3c11e5a71acb7dda9fa42d7d7167df1e85b19b1b443f6b86e8c7ef1c66abd716e82ab1b819a4889b16429c34fe22c6799ce838549fe06c1046e63585e676a95866b711b286d0f0627d3898dcd88b7a30eb0753d713447f5763f4b538594b13cfbeb75721ef54b94c8ca88471e7ce55c7102c9992a8416a9faad149dbc957060aea6129d17e52eae3172b1ba5064d4f2f1e25a70f78ca00c20246cf1b7fe59edff159c230e811463c788c1a1ffa2a478b6edce5e30ba686d9ad7ac470b008e75ca7ae3", .Okay}, + {.Sqrt, "1a1fe68d79307dd16669dc69ca5e21f46049ca50fbc3684524aecc591e478b52845cc7b16653ad640e6c43f93a89197d268ffd2b1993ff4cd369f8f9c3354776a1a4ae87683085fd445223942b7abc16bec16d549d7dff44d3f9d60bb364071762f0a4654bfe55742d4a3f967a9a64d52f4c1f2eac3565022b2cdf4942e68fcb5337b9d017d718db8474031a00c29599c49b789fbb3530d826dce87dfea28d7ceb1487bfc49809a813237dfdaa59a36ca1c180ca6a8fd2882231ff6994aa385f9265af8d9b68930d5fcdd922d7011fa42a19bb4c055ac98602911ff523457c387811a1d30201fa40a762484749139a2ea591266f745b1460d54b113d4dd07abf812834d5e57eac66707e9b86af082f193a8807bc1155732df1a8761339e00b7ac840e09d99d69c0fd240b3e3859e8e9d47175e84cfbfc97d41b9d078265d92bb2dbc48fb246191613ff379adf5b4ec2b19795d835ab18722ffbbb4bdba57d049973af70e5448f4f3df79e46b34af8a103b6e68da370755eb331e07c810c0040c9f2c60701f161d22108686873e97f29f76b530e18eb89e89e9fbb8754ce215cf39f58001a30eecd05bc774c5a3ae76649a6c288f0e187daa49b023150260d0f34ac46937250c581e3983c5c02f1f807cea901a83267de451185006c121e4c3a011e389ae107fcedd0988f9b7a3a0d5d7acd00156fc549f38b6681bc8926b0350", "0", "51c792e977f4b9d689d26fe1834d63e6b2c1f811ced8372eb84891a6fbe89c6fced49b42d661c834265f52fb98c0841393d0e16f2bb8b7e363b2e8caccd7ab8595a340cacf77503e8cc4d621771645876285f8f55fdd31e7b6c17f469f4767077a80cf82dd598616162d035d94681a064f8a5a7f6a26d2316fe00828f266a7afe3f94fb1690966aa0d894fd5e0935a7b5fabee6b48ba7e71fe6f03d3ccb863547ca7ef3124589d42374098641d30922e68471ba767d65e1ba40fc387a781fe6738ce3026dc3f49e6553a1582aa5cbe83994021d54d9a9a651a7a5e1003ed0888fd0ad16503caeed8cb1f6c31f29153a4c10f205a094733d97a6ee96c73570fb3", .Okay}, + {.Sqrt, "d63955c68b8d12e2d8e454502730209055e3fa61907efd6aac08334a8135a24b4b70bfa6076c1ffb2e986a484e63f96bb6ba2c518663f643852b5571f62f3898e429b202329bdf18829eb54b39a62ef3b9b43e8dcdea4fae853fd599d1ba53e1af024edf02e6dbdc6081f676dc0ec3db290d92c4cb62cb5fdc0a5fac7e289c7e9f999c1854e844a5bdae90628682172031f5fb8cf67cda63902e4ead8ac5bbdbb6574816c7baec6b816fe86b437d000b8f74794179069c37b87022fa0cd3427d1301583853f5c89da8e47a69d2288e0892c4f4363defa0ec5823cdcf308026967982c5543283e7bd20c87486205c6171a1a9cdb6583934ba94d347e6cab1ae3b5a1caa6393ac13228fd02ab86f1e4a5eb316fb3244f67030311ae4336febb773e014bdf33c3a20cb7ca6a8685bf79212dd2deeb9f0ab801fa5349cb0090e30c9d5c6a98e9c8cff9db22c4435f73c6c80d5ff4eb1568a0711b135612643cb596ba4c7d7d61ea6875f9eafa9efbf131a22a183e14a707fb004493cd5503f7910b4d2b7c7aa077e27bceca145166877cfb46387982ce9e7cc3133303a14031b95342738070b0556def14a408d0f7c8cf371fccd2473e14fdf36fd86c0c77d25cfa0d7329b23c9f05f80c34d7445d716f98142dba23ff371d623c7ee5c26dc4cd25f0ee4d3b5000c486b0091c216226a47379636315b2b6bb08738fb97efced3b952", "0", "ea2ea92c7a679096e35b41827453fc5f15760e6b02e6dc47b5f5c642b0c4c3a52b43fe2af10a6cf1b57f5465f71ec80f865e35a64b3e0897e1a5050c5aca4d5f0a12cff51dd06111f60a3195135e94e2ca0a07f817f2723a93a0c03c543fce90feb11a24380c3f2d54a63d7aa9b02d06ff68f35b9ea636586ea384a2d5ebaaf793189d3cccaa35f003563e528637605619762a49031a19d7af80ad1d02ce7e8354fae3b049efc462b47dfa47b53976188e4973db456650323f2fc5e2cd76951e79b8afe751e1e555ab77e6df8ec070af0116a255743274346630d5073fa76e4b8cb5c7a0e13c1d6a26d1b9989e696983a59c71725daa3570a756cc64a05deb94", .Okay}, + {.Sqrt, "3c11b4536524bb03783899504b6d94faa5b3f2103177e582ffa0fd6e7a31706d7735d4cc2746d3c0922a141da1d11a0ea13186bb5c1e31b5e10086545631b8cc5c607c77e168e2369541ae9a30a0a1dcbfa14fb1d46adeddef3c375e957b2a9f212dec8b0b3c8b3652fd58d764860f72f8afb99bbe1fbb2142860de885ac0d987c443f6639b103199424a29783b4ada4f09e818199cc0e8706cff73181e02036a7c5f9c1072b1ab3b1201a1ccd1d283a3a24e235597cd4b1a6e201f826bd7f4980ebd75cca8d76713570db75adb0334668e8346898597de04e1bdf8a8a468aea24ab1a433d79662efd03533bb33207f1119e9d41250e0d9274a6d163204d873191bdc65d447dea1e37601b6ec1d2a8532bac20e817eaac17eef0313ecc847af6ccfe94d30dc5d26fadff9740e7105e9736866d9e09f8a268d9cdc418cca376be3bc4430f210bd096c05a7d29b007ac03cdf8e8881697310f3fb4f2337a8402e5d26340c32cc0623958d269ccffb345b51ca2195cfa52060f9570832f36c39ed55beda6e4716cf4471f3d6aec125a0bd764d2d557464bf71f4b6b603a424f20fa1604172af2cb095a096b099c80ca66678621b567247641dff051a074b7a49975f5232d7703f2f76095bc2b333f0b3daf40f655189499d765e8532f26258d444e6acdbee7cb538cb8aa8d3c80fb6fa23657940dcaa2fb4ea8bc021a742c558f80", "0", "7c01c26368033461a477f4a0ca507b96c7163958103c14e69bd1a228e32ee03ab883a4ebb98d256e9b1206e32623ec0f4f9053adbdce0bef04027eefbcaa911efec8d0c28634b7b5fbef8a09b719ffee89c6241b336e617964a2a64683b32a25c5b4917439a4018db7a0960bfb393875f31a625218796d9d60aa655666a8c376ad5a6c04717c7dfc40da844b6110fc899bd06e144dcac7e91ca8a3cd3ef68f97388a3b25cc035bbd03435a3dbeccfe0822ee92402949829b2f5b18f5e491d29f1644b1b94651ff44e6155575457561beca195b6160674323186ff52200ff5dc69efe37e080f75772cf661e6b248d98626da46cb4f89c239161f3b1472414d5a1", .Okay}, + {.Sqrt, "93af604f8feb4299883dd7e12c847b106a69b66038e155e27fb60576e9d2e33a847a84f09597f73d3ef9c9ad1fbff88cebfade7043141b3f68af8814b9d4c4542bc4585e0ce842d12216cb74a9ceac940f53266f66fce78b507dedd30a3dc984331a1f6de7f2da6f088debc6118c73417d01d4c5600907f60775ea9f5db613ece2cd5207962a540bff3dfdd7e94bf6f22885b8bcdedac57b3eed47f6bb476e792b4f44f5535c91e1c10bf762e4816c364928485fca251d9670f5147fce11d1d7df332f22253b8559fea28c98fe1d8c8fb7cdcc949b8c57356b5114363d7f507401ea55bbdd3e8ff5be5728dbe222c1c3c892034c518915310842611b43f8b175243302eeff4604ae3df394485430e6d16ebe3fab676ff4241404da3da78d5a5411c498acdb1b947cc61ac4db4aa50f2b18a6de8b6221a3b1a106552b28aa61bf94cc295272a50d842f5be7107b4a0714f0971e941eb96b93069749efffd9867745f596a0609d671ffe764e1c7cf47e425b4dba18d730a04009f8b75d5ec8af789a2fea2022922c94259baef5afac75e012f2bb31d266b009ff6d91eba15e01f2438b9789bd09d3936e8bfdd1d2da9283aa0efb66e07b7e419c9cead71aa6626cb037b47c1b53c19e415e4e9be32e0e1016e37da8ed47827a8bec156634e736ed360139af75a5f4617e5f468b17f5a6323f5aed9cfe3436ee0f835820438ad741", "0", "c270f1cd41ee7e288ac00ccfaaf2c30735a9ffb538831d6e0e65938a50097f15860f6acac014149008fab6d2521706cade5b5d45c3a347dd2edc9a728d11e66d8496bdd6d89f6ebb84777ef8b7cb75998bf98bac30de17482cbc8cb56ed1841bac94887025604e703cdf1aba13214c441278ce5dd9a432ec9fd0697d20609117b660f55de5bc9d7dc7cb1d533e1e0f8ed3c227b026342305ca2028225ade412fa326bd6feae49d2bc26dd3d60092b451d8a60d95eec600a47f030ed81670d7a9c5730d3bee9e9094d517c9b5c36a88470c045b5ae7c4f4454e26f0666c1d9778ec3659041180bf077f3cb5c5894c2533c37134ddb893165a793b598967f63ede", .Okay}, + {.Sqrt, "3a3e1b082ff4d60843108fa692c2808e930d3b7f2fbb56ab3a87537d4e14e212b6e6ed72c922727e8e30585f14df27e2cb44e10548ee640019b33967a33606e8dbdbfb93a09cafed6b82542b2277fadb3f62a876c7ff5ef45984707f182412eedeca4416f60038b725e3cf7543c9bc4359964d62bd905724d0453483d30a0fe7e075a099e72bebdd808d2d19e2641360115e9b603c359a476f86aaf52e5dedcb1584a467561950e7633319ab5106cca0bb6283942da0791ca7ef4d6af2704e453e17cf9ce62e58e271550d513c031beda4a795aea864d36084274484cd3f4195774c792c9bd4bde73776153e65a36cfeaafe61bdfb538c85bc35af76c11b9c7f3677c1aa059622eeff38965f0568c89374e7a121e19f834c72f01fd9f84af09b543b41bc9d81c8f70f8410c4fc60dc9282916c2e4dc5e4fb793ace4db347684d423021d2b9812094a77e318f48043267d31cd4024bb8c1a30aa866d2aaa68e9bedfa3b7c0ea7f580f0d8b6ccf05d97fe859726dac712c63f16f33a5d0ffe692b868a495dc22ba9b4127bfe5bf4bccb3abe071ea179b5268e7f8c8a68cb002436e682034154e48b12bf312ef72078b79845bacdc4928bfd84024928c16997b640bcde8c624b0d2fb216a0ce3ad5b0d55f89cd3bbfb9c3b715623e906fe84d42216772509a3c6f727e3291c890e7c19965cb9cf7dcd379c6ae00f544932d76764f", "0", "7a1b60a24475d0c459ddb6660f1126106dbe95b6795bf5648bb627f62f454d7a3d767f10005f1dc8282db3fd025f3070c7656bac60185e3c809f9ee27152fb5d5682c59ec5a0b9752e7484812ca1545c74dc6673908b3782eebb7f16544bd795491a75e9284313885c8a304a0ea3b096aea1a59519934cd9724917f3917996a7ea181779b29d84500eeb0d4de8c4efee695b55d2778bd6988e8fbefaade4d5330e980cb1adf926f0544bc2febeafe21175c8434aeea803c914c87cbd554c5f771391aa787e6081358e46bdc865a1ea0f73a37c24a92683e814a20be5ee470204caa6a9607ad5e832d04dbf0951a69e63a84d8ba0426c81693d23d2e75e9ca0c8", .Okay}, + {.Sqrt, "621619e346eaa2034e40d139532d468a1d19ed04a45b4e619f1a261998c494766cebdf92a6471366df24e7a01c9a01fa7b0a7b68c3a8b97875e092036839a13a888ec4695c1e89c5ee4454a86539d88425725776606c3a0280eeeb47d2edc5cb8fef3d2647897c0b14837374bffe3232a30d50cd84cd47a921c3097e250092234c256d447de35f754aaad7e87c3f0d128e6315339f9b76d7cd2ee41d2a42d57b5412d36c8df0f9f49794c40f310d90c9b787a005f2cd4e184f2a891d0aa60cbd95aec63e7ac7c2e795c99c71f1913decd1af61150a4871c1f985384736344335a2d194243dd050187a221802dab9416d0a495de915fa4880dc1f13a58aaf06db8b5537f5455c8ca5021c812eeb20fe318656f4a6cf22fe98f558d3f8294e0a0e21257480c836d2d8b8e375749f09907eb182da121d9f877b55a5625a502b5ae8818e1e693d4820d6c3c11bc30df30df922c02d2ced2aad9653992d642d33a4796918bbe12d3b353ea7a8e020090f5a69b48d24df76851787c735f70b4017646e7c24aac630b327204a0d76e9cc545ff5eadb9912e21035ca0f0097a6fbe4e38c5c75e9f5c190e9aac49fbfd55ac1304f6df2fcc63d869c26a519aa0afc76f3dc4df457406c49b5c3cb665e258523c474fcdc6772a9aeaa8e258f8dba77591f38650a2abde593cb66948ef2176d4fe1a9a688815b1b6e9be7b03c68fab001f4a1", "0", "9e76300f574adbd3a22bee057836607ab7389e2c8cda468f446cad89113ca6572c95d0355d5d65723733cb8a1faf14f75d49fe6686d172dd9546b5c3156a1f15d4ed1d5ee0653290d366e912a5207422e680bfb05efeed31afd84500ff141d4f63f08a57a85f7ed4fdc0a62cbc9382e06659900cec568abda8ff49524c28b369b355f12d8fea6b7133b429046e63c3dceb88748328a844cd0b89a21571541ee91f6f39931ba8b32086ef2459e1a7b82ccdd402ed191f8245c7c9da3ab51866372f560d38def735387e207b49a9457050e35e2a6c432cc1c6db3948937ec28c98871277b1ad80917b95954b936ad07f66e57cb3bf1e6f7d9bf870af6df952be8c", .Okay}, + {.Sqrt, "2e0401a39b0db091da990d98aebd927b7e1fd148b4ea93daa95adbe988195bb8868b7f9890e789424e806b2b392e91de3bdd79e6c7b30e963cd49a2a3deb5acf239fc261dbae2f08ff5dbbe6676b10ffd8a3384674a44fe67b4d7d9b979d080a49355b100bd4e53296d67abe6383cbb29d5d2734a4fc9405cdef7315605c208db18897da682feca2d7538b45ee01cd3bd3d3d2eb91028d70c3afcbd9bf846e640c6a43d02fa5de3b49634ffeb01bc9e877f49d7b3290de656498d61fd52c8debdf012972510c23ec502e1a77d776d132c10c00298aa40a1088de560a97e8d3766b7a32082ecf711167b3827c402447b203ec9ea3234db44c0e7bcdb1a93cbcea17d9a671576eecd156e4bbe8aeeda0158194a5daf0f4a0c7b4fb5cb5775a0be040e6d15db26756eafacd72b42e18ac7262c5428f68c4f61459c71be2624dac6b5f05e71665468a16c9cfb8ab1f46ce4f8d47a1e37af95322a011323fe485c3b3950ce405b47ad489c93bc38a4d4d640ac144c5b5c96deceb5ee93c210386a2a4f480dea8b777b1accfcaea5e313eface4891a1980fa2e1279d681214f05784003571071b6152eef5f1fa36fe2e51aa6d2f61328573ab4ccb70c2452dcdbdea4488d9cf6bc4436156280b787b263ac8e48818c39a4d4ab6c93a7ccc1aced418fe13d6bf6a7273fb52b3603469baacd84b604d11eb477fc4d896048135ea648e0e", "0", "6c89261e8f042f63a0066bae765ebed4d6cac6430d784d50a0bad45f67f095c291c40625345097c9a5caf1cd576ffa0991d30044a7f259d7c07cdb6bd8821df8d85c9c2d728ed3c58800e5a754f3a3acc51af8edd4059d3020e27b44b1b25c5a57377d12e02940a5660d1a81aa2a3c45f0cae8f018dab06b500f9c95b20600c7cee3f59955e9d71796dfd9adff22afc79a51159044972fd97c4fbe3f5d0159276b9068a6981b1ff3385305f64c740567e1770b4b28f27df702c24529abe1701b94965a717aead35a4a137aef38a08ff8effc2d67129db6aa74ffaae197c1e7b1ce28d45a5877672808b90c8fbc79b98bd25db3b006037fb471c216678100f2d5", .Okay}, + {.Sqrt, "f762e9c7eb4574ecdd01c673503fa05ca2a259ce8797428db8e696d09153bad6ebdbeb094f10fbd0e98269dfd19889176e226834841f3ca4e0f57e2f5ec49a2066e5d55ba58219a8636d06bcef3e22bc6f417e6f483097657b8a620e54c46fb4c764b9a2607b0f106a54669d367657577e6bfc7ee6a3bf955218b2ecfe3316784b806490ac68cdad2a12e127219ba0c44e89d1421777fa805e7af7b1aa87fcc4d3c0f3cbfa4c8d22da5471e84d08905b84f693991a8aa10d01a8cf29716ab87473eb6e557d57a403f50a0fd7482eff4547a147b7514bacdea659ece1802a470f7c031872d1c7b6b19ee9e042d76546f0cfd5593cd715054ce4b248b6cee2306d6cab8368e88c29d71d121b751ece40015017777f4123c2a440b2f502130332bd7d6f532e1dc278e34755792d1b9891890c9c7412fb9d6380e6a624b380673e4aee9d336e17f9c3ad1ebd445f296704e1c324c6b39e4ea2bbd846646821a1272a121a64d13baa566c89ac9cf16069d6a658cfbeb3c246c59d7a5c17a9fc58e7a1f297a6de1d67290f3dcf4f8936b9377d35acc83407694fa9ee6f99a87777691c7157ca23d2675522cd616fa4709c9de975aa624d49729c44ad6e2c7ccfe16fc9d68a6290ab06dcc486a11dff764ab8db4738154aa3e1aa81cd49c393e8d6c2c9bd0cf675534e142c501659230baa23aa162e1cc45d7981002536251c5e5e2ce4", "0", "fba805dd6f6d8b59cf1235e4b7e53a8b92159ee65bf31e028e130887c4a13b41a35f6059087b03473c504140057f2118d9fc433a92aaa03fc57301d7a2bfd5f9e13cc2997842733e882f6403e5e78470e4ecd85e6afae186b4bc94704a969ee004fc06228c7f8988d5e3ad42f34721c31f111f167c34ac509e0953c91fdbf7a04f347e3001d3f59ce464dbd4fd8b7e342f17d2b6665f4788ccbe353fbd252005162775233e1455f94f890ead74340e5a67ece7f5abc9d27b6f144542e7840dda148b217c3b55a418389312997d0f6dd120d6740729b9ca898f232a0344334cf32ea3ef280737244d2e7a53cd8b1ee324b9dce15d7043c8c4e892ae010c09a0ab", .Okay}, + {.Sqrt, "d8631e4344a67ada35865003fe6b6d6d642dd6493afb1aca607452b348818682395cda759f4b84bc7d580f8163d3318ca2fba6ab443900b3bac44ab33ee7f148c81cbd5f080cdf82fe532e5a8a5f850d09ca4acaecac7ed0342ccb26575f4403aad0a217a256e7f605c67ea3d5b5f70bf74e30271c0b0cbf255284761acd11621009a52ab296fb90e75942870fedf6dd5ab8e506a8ece5fc4579ae3dc18ad8dbc8de7ab1f9cdbfef1a88d9b218df6efadd92c2203d21be02462d60fff9aefbaa7e8a86a1750c62e591318436040c4312612c5b97bd30b4ed028bb1ef887220e611415673f8f38d8ee86225ac8df79f2492e70f15a7c3be2efb82f04b6d1d74b8d0332ca803a2e6e00d8fd0a29eb7aa430cb3e35056825a779e6ad226949c5e8e1149ded4d58e654b396051945af6cbd69702cf319542e520b7143b66200f2a1dfce88a128a1c7678d5395ee8a702f1f330cd34ce0e4ecd1cd2f4f5e940d719e05ea24df4bf39bba8da0381be6ffc9f19643268c8ea4ca3480c489a5ee5b1d49b37c222b19e159d2f5c7dfcb41679dc9453fed7365edc48f62e7e76e43764692ecb7e0f2fb7122c510670b1a05841a401593d540345fe6375ad34f85886a6d6ecc97775bd15d3a57c90fde861e27ac4f62e41488bc5b1c32f6e5eaf646d48924b1a68847c1d84a9ebe0beb4f590d2d190e5ac314b1a1493f17086057242c4ec13", "0", "eb5c96c1202bd466c23fbe1ab563fc15d09760dbf398f449785fa484b99fe83db394ce450165dad4db91a1a5418670dea49f2222cc4d21477df6bc2771e4e76e64176177048374b3a6bb21bf81371ec574b309c97ec0eba3f9c93223dd0aa9d383e2b03f4373e12a29e84927b973a72363fd339062e903f107bf824cd802baff10f0621b5fec49d9fccd5401b55ed90b30274cd76cc7bd98c7d4e17c6c72ca3da75f8a5dc10707542e570760583eb4802eec46fcaf80d7c6219f29e895654855b6f1660b36b190c3c174e464c39c6c9fe75e2154a757284c75c3c6f7a60125ba8068fba4736bbc1faa5d77ff09c4589388bdc12af39cf5164ca4c42187c7e2b8", .Okay}, + {.Sqrt, "7b8e68f4c3a386fb1f73b72b5609fb887a19147d1984141b7dd37e4871c93c5aa761e888dfd0aa316766b732b024dc349856b642fffaa701c53e7a168e073ac945f8ced50010c83839645661299324f40a35fad5e411d82a9e377442ea64305d1d48cd1727f90573a2a9feb796ca95278dcab98e30af3951b147c7cda8a2318341f025ae7730da98e3dda9c90ae6cd9e8fd0e774d5f126b47a6712322e2ad1236a2bdb130725c768db1e7532a57ffe18b0e9e30203a11b4c33505a25ccbdf9aef5a68f09d4b19c44afcc4bddfcf0d6d6b3fd0d0368c69d1a1a91d2c9ca9cc58380bf9ca1083c90e2b52d9cf164108400299eca8a3f41e174ee8369582848a98f692b0a0a296110982af3184925b603cfe4341bfd77d65eee5c9fadc995fc9bc5fb1c3371edd226263829fbec77124c08d836d8089a7ddf0b56ff241ef508d726454c2665b4bd521030251699d1ede80c8fdddc557194471b475eb2cd27ab1c8b7c6c58d656fa6eb701693423f11752484d7d4560a3483977263c626e1ac7763d459d26993a36e0fa702b4164adf0c6f17ebfe2ca4983ff4b789b360d031adf3f6eb0291ea2a69e8b462e9c359e92a0a4f7132686ce74d05e84a2faeea491a7b90083cfb26d00293259819cedebc4e3755ce3ce77a75b156b64b56f7b5a3438860bfff44521cc95e75a3b07b396afc2bf74608ef15fdf2ab571fb865d1dd5f51c", "0", "b1d97271ee289313e85ffbab342875de0bc5ec9b012b372515b6743faea9e4ae7a2a935d14f93249fabd92cc7c2b4e576c646c53d84bd5b31dea8725e3293519228846097ae53d0335f29a6f844b4d45f35ff4ab162e38254397201dddf8d4939b2d68c3adba348a8af4ff4d8f0493f6bf7401969cc2b225cf6c55623197612a17aa252804f733c09382d0c4a6d7f3f6cfb95d38c9b23d374a424f201fb7c91214019762e23fd42062a1dddb1c1c4b922ce741d7e3a142990f7ec9a38c733b0da5be7af00f1a02569f745d94c4ef966656d266e05692c0d0e8eba519f07f885f5efbd006bbb4987b9e44b5375533ecdb48adf3947a49d677236f4741c5594189", .Okay}, + {.Sqrt, "b90efdbf64fba5d91361882439dd216308626801bf0156a5aa295a9c32bbc3abd2db4f6d0f8a206e1a138addef795a9b0c7b1e72c866d3f0987ab97dca5b82e7520445400fe995083cb8203430df008bad240ded223ad2cef0cf6182fbff1623d33be1b496912aad6d9d75b1969c6eab0fc65d3e9d52a6fb79d1d9f8fb21022a4adf3c0d5c4783facf919d3c69d91baea62de31fd93cfa0730823e1574530cf0059c48708b10b8826b3396c67a431b619c34157d1028027fd590801cfa9483f15cacc874e6e043f1e430156c604f0b2e4ee26e1e11d09b7359da602b1838d4c8bc470232883f2ceeaab9c6fd42b2213268c6f035d503fbdbc7c390ac7003b8389d7b36046256014907905c5db56b58494a81d2c15fbb424249f2b60a3da336121bf2fde4da51d27fbb9505699247a477928a9bec50d813d240bc3a859ebcdaafc6578f1156c7c5f1cb2bf73a71e58830838eb8bba6be10df8af515996648e7853745a203896e354e35c578bff2b2fe86ad0cf2a1407f8779b7dc848b0697f5888af827089bbf98c3aa1c050be468b719cf4a34aae58cc1581571132c80b7fa9df5a8f5b90d8e15da43ebbae48c5855695219e86f23226ee6b94fda1424cded810dd06fb17571f3347281a00f605d7c7b25fc89ecda4584435156dc2f497cbe4e42b8426ce7aef408b61f94f651be71770225ea59da65ea2d3f66125cca93cdd1", "0", "d9a8709db9783b5457d848fc608d0b9dab4cb6022eb1c957b217861c4e527c16def958a70f9ad5229f78135d10e4a9a2eeb29ec2fb25590d75aecd5ada7ec84564494cb2f1bf51e418f6c1563dc0eee197129f81cb6ecbacc78940112aa7372509172fe8834d4c66e4855b1fda3c2632b8c19f16bd5ed56b23eb9bd13f9e04b61c2ab348f43f48af915fad35775e2f0f666dfdfd69bfe37eec63ea8ed33bc5719907c2363e56b1de0532f39152c69935996750a68571825c11862956e959cd4452a987f79c6e6d5e5fe26d0bbae342d86df5172039dd6b06586b23ff836469776190b4951e73df0749a22d7a66c200130d147f3af61ff91bbb37b4423a258ab0", .Okay}, + {.Sqrt, "6e932f672d89f57198eeb25665e2fa1c34f8c0d623640a5c404833a23956d531465560361af2244446b0a431fb53a4312f119a4e209da303a31191666ab95e328aa0ac545816b8b12796ebf4d5a2b7f6f25e15b12255979a28c149b81e17c08a317d5ab19225b991fb58bd7a8c8f6c644971e8b11b30457b90b7a97d66a374945f1f4d96f69d09fa2a1278bf8acd49a5ea1502e82c853174938efb43a03d416594c513abc3086ccac23e878d2ade5647c84130cbad514258babd85883c324615e087c8062d422e891321a4194e94446c1c36731158cf7151f20f1e0ee2c1604bfa52490f773dfb093893611f9ed5569cb5a4aeedd24c12b7c163d15e2fea1aaaae546b2b428de1dd380e03cc7d500f1da0fb27bb91963cb86c6dfff27c33e7594d98b8e77ce4612e5b40e5b0755d57366956f99fa6cfce505d1d89900db6d18f52509dcbcbe3e6ede70bf82df4cab523cc783bdcb6c74fc30a761abe1f7e17282704887d0e6da37e8fe5522559ffcef9634087d95780ab08a4e1bc86209f3929c33a07413842a59880048698d5c06727d339bcc66fe51537eb3b6e1acff35fa89f716a4193bf532631dc66642a66ddbcfec24082fb027b5e5035face8c491825bd16f9f8fc6eabe4aadedc5d3196b34a832d304864afa3a95a8e650aba7e0785985e922b439c3457beded4df58cec173759b2bb6f52e1660e75a298c6044365c", "0", "a83f5521a69a5bbe24ba059378a92f7a634a87b4e8f5d33a9877a89d2d0409acad7774bc9ba2cd6ca9f60bb766b4a7d07f89c26138f700941f1b6090726a54e83b31b6ed310b0e955466d61a0c5ec817f3378d341e2c466e21472aad84c1ab9e0a660893957d3b087cb456506a1cd0319e69aad3ca4e6093922b7ab1c5c3c55e9489835fae0c54b2fc3c97d0139b3964fe18dbb44186a9863e6fa55654ad3e229c355a86fee5dfa1697d8538f8b54bc84d14c631d9630132f83d39fe422d33052bd2f1da60d88fa5e90bb278e0df12d98269044bbf855297df7e343de0ed6493c33ff7e4ed70461bbd35ac89d2780975d4fc316680fdc4c2361149e282315cdf", .Okay}, + {.Sqrt, "d1d25eac5fdcaa1b72f49806acc85e29d01d951b54553d8bd8c09da919a34915a50da2c06d0c3ccef22f82fa5f7f2eea969e93eaed31f76f8bd7f24edc7c3b206f2b47a5b8dec342a0b355a56be8f6c566733c8be7357aa789505058ebfcacfc6693bea40a3d55306e9f113dce99bea1ee3347c5133b769c79ee72a795ecf721c0f19603746b92293eb2ecf303392568396c7abff77a0c584c9d921d1e168b238851b56031f842d33e80e8a5666922b6ece2b6ba7ea14238856ff16d4b45a75ba3d0c6159816fc380f5c37f28b286fb59c05532ff27d6c27a876fcd81ff0558ef380b5a4b4307807d329008d272663d93fdd158e194737e79c5c57e845dbad1aa87b0a8af86cd686480977b4655d4b1722d9749bd7119b33a25a625d84efb5858eaa5ac59c71934a0c913e9c7aecbf09627dee87263f56b5f837d5b274745d042251076332b5cc8af99ca4650e3c48d1af02ec4ceefaa852fd682eb7abb78662d8a8b855c89f4e0c8a90cc5090a43c2e006282262ba6ca31f2f20f3a353441a38982a8c9d66474ddca788dc621be7866a3b7df3935d99a10ba66379c256e87cfe72baef8620d07a663a8d7af3e36fbc483278f1aabd94f66f1931867ca4adfc896135f5a3c29511af1990029b2d88c280a6379beb3c15e353d32d3108972f69999cf5c9db2a5b11fa5cf76710dcb9fa30a92a9b7dd025c188d5a8a577844af32", "0", "e7c37bca0140d76569e9ffc995857f64f9f9b7a81f6b81d1bf5c8ee2b83cbe547a6277324dcceca709b9509a94d1766e206f2f3eac3402a0aa0d4efdd10c432a47fd44ca2d0ef17eb829664ae43090f1ac84a3c7bb2478bf7e3d25d5afa4c52ffbee1b011286d5fc6d5f9d4c4588378f048369250d7c982b48fb7f5ab212c47db2bd70dd265355fff7380145447646e9701e35c957e0833ac74427360df97f5d2359ceba2f11236171bc6b4fba0f3e9372e77a373c3ba73f945c1278e6e5f79ed4c1651bf18f410dd9df9e62d8f090573e01685d6d28bc9da8460759fd733fedaf8e717db447188451d0decd1a3cfc5a8b746d613ca91d770d4742957b773d80", .Okay}, + {.Sqrt, "e34a63eb6cea6b4513d2295b418850d9837b3e18b44b470aa7c982f00568e244cc565e45214e111535bbb7c27ee1010318cb6cbcdc838f7f5418ed6f0d39c062ae1b1bfacb0859d59466a2deec20b45ec8038e68f204f9cb7cf8c028e861c8e32fad97f97f7ac9d65e052497ebccd2b32f51fd8041a4a30da24f617a5eec57b0ee8ff44f2cc080e97950ba45a761b995ba13b17eb8c24245e45e09de356d2b164888377f1a3ec7f7d8cb607793f1232449efc9e224e93ac7924a274db2ad08fe9ab3cf50f576d4d4ce909e01f8b9a69f1809fcf1f7463799d1aef60c82677634e2e37d720eb41e66a5f8d6fb17f231b920c3480c21eb177822043ed6d0748df05175e49aa90d77361a92618d8d3611a6976d58ebce7ee08f3bd9e25f7f6cbc65b92b499916537193cbd7221c0693e2432d75407bf4a012ba70a397f7219d5c123abfc1f9576f62896f2789be4cc452c58fb61d5d4b4e5ed984476903f734db2909dce43e6a21400aa23b1ad185b51845f4203901ccb46ef768196ade43f67881b92dbc1626768b8d25cb559707b86b547c8a253ad618fa9d7cb3f5879d7d670407977237636c56da19cc71b9ef1d4260a403e63cc403a7b1ba790d1c14e6827b2644cde559ff480d975c11729e3d4d448c48b574419cd9632094c7dc3ac6da15a060f3b493a73acd6b42dd1e52cd206cac698a8b41fb66049329603d722f9ee2", "0", "f137f316e044d792d2f2d21504e94a9e5d9c661918049f770dd9302ab2d73dca4d7ca121522ae36cfe29fc958cd3fff84ce0eaa27e7f25a853fde8ba2ee4d293efc00ea30a1b0cc92ab0172e5e29c856c957075d0ef06fcf01799639561fd184f4244e34f60b242f58c9f32c7ab9825a5a973e96f23ebc451febbe54589e3aef17367fe6f9b105869afab8ee3d2befed1f713a21404ec6e64d01df02aa855acfb703b79a6578b5aca18766606ad45619638146d815d07f46035c249d80090f4cda0e309384b92e8e750dd4290322bda68710c465b665b40da17a00b09ea1d42e7e7cc015d9ff68237d2128407fe01501c02f2dd4bb34c2e104d91f8ba00d7965", .Okay}, + {.Sqrt, "58a123c1e709e7a3472b128726e6a2466f847f512746a1bde5eb4f183f368d8c81d61ea647000aac921626fce176f36acaafe085a178e9c35a087c35e395cea09aef470933cf2a50971504ac3231d3bff11b027de25305f1434241299e8e626d116e7ac634ce8fddcfd082ba835b6dee90e49a165e08ffeced7996a3eb5c07b05a6d0c40cb3639d9b414ffd40db6d2e265abdb516d979d36c4cd83eadde0fba02fac687dca4413778904e77cb339ed6385a55dfcf58b8ec85943fe81ce848c0afcb64eafbdb80cd952dfbb61dc8d808782e00ae2eeec784ea6fed0f0ea0a74bc6bddc8fca5e5aefaaae592b7184ed9ba53bd5181515451d3bca14d7b28c4406a1bc62d899d659772fd8678631b47d36674f734bd5a4c0a3d48ff84f5daa9857bd31fb99b10e4747cc187d2e11e18f1133f22181455ebc46cef5229e5db0c82cbb61aa02950c03929dcce1922fb95680c501910ef5a1b74cd139da94ca92532c323b1aa8a820a5ab749155b1a01f54d4a0ab3fb5165c72ad3ec9e8a8d00d8ee64073795551189e4fc903f5f407fb0ee148275d311d625bde05628d88a5171b6f64644e2bf26aedee16058547ad2e7c2b3cbfcd302e92933cf0fe5952c2ad8a533d5e2b1d2c55bb9cf42dda34a4b14a3516bdedd431025be76aeac102b97a846f4f14743c9500de0af3b5a6b5363e5c7613e7a2b8586883dc3838d6c1edf055911", "0", "96a10fb946da11e11214979d52cc1edfc6785fba09cff10e4cf3ea93a4ab46c1d9fe985cb01bae519991cdee9e6afeeaa79f056edb95bd59c372eec7df995bad779e2e97d0cc0e624d096b866f926d54b29a4f5523e9b176a64abdcffa6fb232075579d076f29e5a8cd3d3e7430b9659bfcd6b55c4b27690dfff482d35c23a74d112ae30d14a28869bf65723f3d733244f6d4e9944c0479956b9920b325e9f28964b7271acfef6ac54ff7f4478d754ae3f4042423283a8190a6b19898be06e8277d81fddace5514171b7fc0713768e5048bb25d412309f2fb8dbb43f28c6dab471d1583915433b458cbf1065396c3ca0a2a980343031a127297cdf35c8269dc6", .Okay}, + {.Sqrt, "5ebb6d60ea600369d3f7d1cc1cb521e4fe68a00c1e752c989fa3f9ecce263228389463a93640cdb83cbd8c1696249072b508ae8cee8478ff096e38fa48a2343422cb83d72ad501738a67d663ebb71e18d55abbd8d806573217eeaf1cf55f18521de03a02d65d498cd14c70a00aa24cd9a6f7fa0eec428bcb1b2a676a068f674a80475771c8753b84e109bfbd8449df6c0704e8f3e743c2285a53b43af692afa8037e67779d90dcdacbdf90cf7a5508ddf2bcb3ee133b67b02a544e3dc0c50495feac0772dbbe93783261763d828abe68caa3627a5ce8d81d797a7783b8be5ff04304044ef5cdd52a9ab38ee5ae81ec625d48f6348978f444710ce9a6015ccd4be8a1ba9738d13aa0c110388dfe46bea63ecb1b2bb8d7581f73d04ffdcf023652e1cf262898620e79b5d24da4b61df40c8589019951eb1194ec3c057a391be81a5a548d976b386e5a49ac99ff1745854b2d19af56b467ae96fe90481de452deb13f0bcadfe18813aec1e9e1d3aa7aba527f01194457fecd38d7b9afb045cae1a00b1eab8f509f9427604467ddd227f89952f65bfb3b5e29fc0ce47d7416a6b1b2940393f1c21ecbaf6fb1368dde4ae4d20189fb0f805b1de267ca44fd416da0e4214bab0567e6455eca0794d107d9a323ab94ad59b7f1c8b1ffad3399773fc30c6655cd258cbae93056f572d3e932214ed44214c23fa70b0c6bc5aa1066193de1", "0", "9bba8bed3e0f261c1af644c2acb634bd6240a127dfac8aed6bea04b752f3454a84eda6b0626e5cbf78c11871827eb5638b9180b5fdf857fb9aaaf8043d54c345afec28df6cb7266d61cb6a7fb7e7cffe4828df6b7b425f201cdc3af4b0fe7ca4118dc653acbe4506f5dc7133e5e7c2cce85997476d9328c4d7f7316775fabcb5b9f652996909cffecaff2bd7bb01292a77db819d6029566daa1f096e5404db97d3c52eac1a798457202bfa32bcb21130c9e154d515af7992eec7486392786d05845ad28516208501753bb518f0eee89163b5cbbcfb64a77618af5f4265a2e0c5edc2a6fe8eb2c33d0ac58361ea6c016be56a18047463acf156be970af64b2c41", .Okay}, + {.Sqrt, "55989c2433b061766956bae1b72946b41df6a35c6d26d10134317a37b33907b16290fd7f5eba952a22718f430d80c3e2cb608eaeb714897d61cf4723ad087dbf2b4aa2850857a090db57c01c3826e6c5c7ac2f9b67f78a89f9e8de9d345da4ee59ab9cc40f59a22d7fe0ae2dc109d0a6d60ea416f72ddcb0c08f05474650c5f53735ecbbc73272a3865112086bbde282c461679bdd90c638a2f4905e1ec52255b1d14e241ae0268cd4202a4fca70b939adcb7d5dccb144562556c664f9d1f5ab99b5a001727aa3dc558e7597636e1019a66e010a8932685fe274942024574926548d6eb0d5ed32ec1e2bde6727daa05456d22f7f0793b4b8f4e96423ccd7c49874c157c45797c24e3a25da647449cb05ef5b06667f7d36127c840c96f6b35a43577880e0cf75e1fa9275e7dccaf2cbc47539ec5f88b6c81a881cdc0a48fcd27d2847a6fd2e11aee85927371f4a48324d2a13eca7a627601d45eef88235cf4a3a80c359562e846f701bbe5c880157fdf4cfc363e1ec488420f352c1f629f5b92e51c5e18893cf645b719d9a8fba531ceac96036acf608ca5e46181a976dba1fb860847ca3fd6d6435c7765837a74249493f441f98b8f885ee768f9733c710862cc670454e9ef12fd707413e6d806f003728598c4356a0cbfa94421db70e707f8443b95e36cec92bce1734812640703798cb430d602ef8351989c3f94d169557b0", "0", "94077218e06976d778671d913826b6325e72660e70043323bbe957839713ffba809c84f299a29b8d5dad38ad86aef3db08e66a25de2c43b25ff2e57e97c8a1ef87166d1b9b6ea4e0fd9745e8cd5291b3dea2a567235d29da87d5c6302fcf5e054565203892c556737a2b8d46cf11a0f21d04ab048caa7cc5e2c4e146c51e3d8958b739eba640ec4397b8747e46528f8abab36e3d0455f2f528481ced604b38697cec09eb5d09c0469e27ac664075552de209e1919b45ebd50176b7a434e7cd54eecf0598ceab74f180e1198682eec4bb6990edc3acc3ee05dec671c443b7060ca3ec94c890f967e6f7b9edacf5b2377844f2aa0b1a2a4a5378f3495dc9d40bfe", .Okay}, + {.Sqrt, "b198edcccea81f69c7e883c09777658f7941a16c3e6324481facf1b84c44b87fec3683b60f32e8483f71b09a418fcf1ad31a841c09a1b4d99e8c6a499fe824fc2a24bc8295f8eb4d2a9acf6565b19e0357eb8b2034a4bac50e08d6c0be758afea9a24cef62f0cebfa1cece570b54a052e2d2b6e0c2e6515e3567424059b0870f63f925cfa3253a8c798142d4bcdf62cef4e10f8457375a504b3ece62afe7ead41be8883afb576856cbfb60dabcfa300e4657f8265d72f5d896188f5feb23bc5debbff13d2bc0801d56e418d00e670b35a58d99722f3dbc37505f1d123a87fb3031a47082699e0f9dee4cd130c9ff451a8a2b6c474ed54145db35ebf9dad86315fa1dcfaf649472d8363c883462f788e251ca8e80fa27c95b061be021f37430275625383c7882417717dbe67bd82718ac2af1b7018cd94a45d2a250e0dea60beaff961ad21e06dbd7dd6ed4627d42cff22ec614c205f61e187502612377eb7f5f56a40c946533a374bc025b53817308f5c71bc230b82c11333a45c6887bb9f2a84f968ae208013c579b73d9d40c96997422e2ac227bf26149f56238ceffa0ec286288792fc27dfb471ac24f215ce58e1cf2a40cb0d862f8f12bc9fa3dcf6ed5aedd3ca13b3468e9227436e4470e4337fdc8482b9e81c0a5f16168e07a622525e986a8aee17705cdb2a06574b8571860c6a08c0fe6b931bcc66a3ad020ac143229", "0", "d5399df23bb232420d3cac1e1f7ea941c37a97f701523d3017a8eda50900d355a80baf4e4c6f773689c0bd4b2c6e09330edae2db8f7ed67885064930c248b6f7ee47bbb97baf280d582b4c3f629a2e9d520893db5034354f0ec72692defba74a735260c4894c66c59643e2455dbed42b3e4e04440b211e9307c3a6a141093a44b214798e820ba39af82c6367675d68434533e4274ea744dc4709da5d4da63ef1dce2d9b5d93993eab03992d81d8858673f81eb73dc9241a15c94626ef00f3996c001828d20e249d5a0abb1a3bcad60aea46cfed8d00b91873dd404ac3b4f563fde8870b522d826ed8e780b2974559f62c345889d1245b8c848ccf99ee92b0731", .Okay}, + {.Sqrt, "9e07045c74e1b3ce8d33b2c8df28701789abc7031fee17359b4acb094a0621bbf3b1355296101d73e211fb2060c9cf50287fbda6b27dc8133cce8728e22c386e8974af727dcfb5e945b91fa947c8162305a8c243d8e1a519ecda31b96a284a6b66e4b52fd3451151c052f4151192f218e00d614d5213e3f8632631be79f5da10ce44c79597a23e2c032582ef04205be00e87d64c05c368a9180926b8c9c29fb42520b909c81481c73b8fe28cc93ef9cd89666ef7c9881292d72a29f336b07cefab216c17f90d6b58ee16ed6342b1890435f08ba1b7d9ce69a97ab1a865e3668a247f2fb617cd528a20b4341cc6ef00b7cf0dc7730727dbf7cd6b103d341d93e9412a7b1d536df137ed20119ec6cf8826333bcd5c07641281754b8575cf7b2cdbadb747c2dde93995ec886ee379c116947855668e4ae2f3dac92d07abe01fcefca1c70ffd88ec5069b041b3e3311962208fe94495f328ee5ea1a0eab816f1f3237982064b3ce8298e6b818384200e5581a99fe29295ca41e3e0bcd9aff7a06c8bd67fd1729671bb48d04186237913cf501bee96945561f273b0b219ee7dd059ea1c1cd311153f302721d525e8724945adecc04a4bd6913be4f29c3a00187fce0c1d4fa894668d82f4e609d7b92b4317dba1e06c6da2e499fbf15c86f6927ee31393c91cf012c4149025cfe3389e952e2d1e64c1414dd93804bed6c5eb6f63bacd", "0", "c922632dd39ac21f5782dc30c9b1cc4f82df2db72997cdf8bb1dc99a5217ccd32287f9dae93e38f499a066bb009da6f266a64c818d80fd795b03af346540f52c05d6f6d77630e444996fa51aa03d589e5e0521b083647ec2a0d5f24c32864dd3049366ce16e38ac83cbdecde875dbc39e90cc4a8d88f61f351ee305a110584fa18b40f0646bce307bd3be761c90b5968c0dbf280f09f2a3ae400619a52510bfa1f96b4f272acb16d90253446d1bc6b6b845ae4e5632408e065f1021c10cf0d0052f840fdf7f1a23f0cac22a8332105364a80f71ae9062ee24223a68a07b42ae8afef4c90f7ebbc8679ad975fbeac3a9584697535e7c4d61e7ba81acfa813051f", .Okay}, + {.Sqrt, "5477cfe3d45c6d1df6af994b3d03f2475113b7c2f5208a85a62ede0c39801bb10fabae08628e1ea3279c178e9bddff59a55dfb033646a13987456c4f3bf799d83fd657b560a8cf108e32823a4251caeeafbc65882304830d047c55cf94143c6a7f60dab8f8f7c8d4c53049567aef830a02e3b22c2d39dade47b28d7d10132137d93fe037d5535750032c1f56799e3007ad8922d069e713e7607686926e29e1c093322136784a892dc580be7c7b328452dd57aa9cb7a08b3e7a908df36c449a7a67067f8bee6d6125823513707ea3e49baf01cad45e3f0389eb5d4d7368351cbe848206b12bb095fd4b6fe770f28b2d87c59099abe2a958eea3eaaf2e9fe66428b3914d74be531842d6e06d5f18b3555b3f3fae8da5509c54bf6b3d394d9b3b52ec89fe4820a1b09e0b4ca876854c93ba3e20e6ef08593b2298e56742c1ddc77fa9118e9087d9eb6b6421dda2f2941d6f3edd6c6068102d8ead2d2281eb3f1e50f7a79e09f940bed72ce07df2f60b1a43204a5d77e0f9353a9fd3520a43b739aac1512f197e6cd848ffac25423cbcc70e8524b4431b019f107beedaf9e4e094a016ef8279270ddc384502ae953f1ca71c857fdbeea8576174d7a7cef65f2317a2bdcb4ccdc99cf2b1f48a41d78fb72bf9f46481f24a10247490c8ed9773a332413703d913417ac8a67fcb9577e29af78a0ff53efb199df1519937b4a7e3e37aa3", "0", "930ce537538a12135fbb89840a4405ab9aab70f7bf29b00a56ee5a3f7da79e7c50156077eee087668e85c351ce1dcfb0b4fc36769e1dee8155f02dfa6b1ad77270067065aa62774fb14e125cec22302a91004b97b2c5b014cbec5c9dda4f6cbe69f387f2269680561f46dcc1acd5a721efa7dd0edbdbc25fa2d722df574a0bcff34f264a36af63797689c8a032b44cceb20dea00f1618607babd0e5f8381189c3991ab9cac8b7c6c12e0d29fd8960850ed83abc199c43510eb3ca54903b0f81964e74949cadf8f238145b7d5243481d8d191dce82f330335064deeffb6a02103cc45ffdac2c30f0287978864a676fd04ecffd4175b3891efdfc9fc33d3b06bad", .Okay}, + {.Sqrt, "f63cfe2ae74f11e5669913cf7faf510817126df460d1d4a0ef2dbd0770cf33c7aa933b14f521ba68f1c64f51ce8c190a868ee52cf850a2135bb3afd3b92141bbb69dd7eac40d3d4718bfb60108b1d76b809569d888045afbfb7522dbb5a284addfe02a05e6f199ee1fc0ac1a6780a144fc6000789f02a998650af3b7e733d95dd3310df673030f5fc039ec2884afd6aa36ed32688514e4c2f7c19457858c3bb036baba115b3f8b8a0d971403e1a06426e9b31c7c47ed1bf73e669f45ce73692732553a3da03398ab1106bec68b794299208e8869cc004f38729b9da8c62430782ce5e9f047541244cfb34c2d9719649503b96e5414c0d2a0ffee85498f7c2ac673413861d26a2ef751a71a714c9aaf0c8a4e7b883dc9a542103ef1dc9f699de92babe11d255aab61f0040cf43ba7a29beb5216c64928191ee87a008e69ca403bcc25d9be5f0ebf4014efebeb3eaae4ffb5a012741e3b8a0869e9d5a88f0f98b188e329aca51b49e87c710368253927c3d28cf7e7fc3fdacfaf12129cfe61dcf597239fbdc2beecd0a5253226a33ad9459241273e2aaf55d9d24d9a1e6bb968845028b6112f2c273e079d8df839347f08c6aead2733e73d15cacde2df36e0f154709729afe4408b558d17d7a58ffe049e11c5835ee728c09058ecc8e78bd341af9a53add851822f4cf1fca9aed8ae4a1604b4e8b274eedd6a750183523fdf4b67", "0", "fb125a2ffc528487b63986c1312113d44d276270287288caf8a28db55e48ba01d53a4b630dd920f39f528d69edb5827c4146a536ec86b83fa71d762b05cdc52e0fc8c42c17b4b1d82ce5374f5287513ff16a03341f782d7c3236b75d83d0acb5a599d2789802773564e2fa16b139db068fcf22a15bb5f2faa7836a83a0ef8dcf1aaa6b6424ae72e0986501c6f762dd63cb7adc0a695b25222e48187d1eca2734d69c3e2905b7bf7d0d7b700e95773cc3bea5845f2bcbbfb04d088828029e45ebb2f7f577eff01417d593249b69a0763bbb4d25059ce834114189df18ebd1525f60b906114a68db925b975157dac6a1a8b60cef5b8955abeb63f5bcfc285de4f7", .Okay}, + {.Sqrt, "763f7d997d72c09df219fec0f7f2b65de9aa795c344b3ec030b18163a8d1b6944e316bc01a2f0f0dd5fc1e8af278e8bf53b862757bb71ff302b8b2dbb2ca7ad3bf19bd872759717f61a93ff6e5636caf3db436dcd741e531437b172df04feda21d95c912678ca7be14935c71bd69159784ee5f8abaac9283b922d3e2a3eb73a47ca8466b860f9575cd5931901f6a87c3ae466bbecec7f5731b040a2a1b70bbf2125cdff24f896045814b0278e0cd4ac6100e447ae6f9b9d67b925d84cf5f55bbe2deeef48d766dda999c2bf9e53bd9bd69b1fcdf543e032409b247c27350dc540ff60af3627f794bf50c3b561f287c4c93363544d2cd284c8cc22548c55d1c2ba37a6ff55b76c035313908e8ef53344b6c5b5e05ffd24f2ffb0e4d5ba3029c49d47bcc00cc828d298fce8f3ab589e96dfb5e8015d9e45120fdae6956429b7c3a4bc2d2a8af30da49dadece6b330369df9bae21151ef19efcbb6f3dab2d953ccf52f3a624266f8d25c2d437e6fce499448174667ff8ff2c7f3eb780a2eed94e35ac8ea1bcf5ec6b5d5d7e19e71e410fb66963b3fa64a9f035f66041593ccd2209382c6608f3d2e398e15d500df06915a8a500825b43c7611bcc622e796297bd0d00a63113c07ebc44042da6ffe40da3b57675c91c19d3c606b30b555dc44915eddce9b24c7cf7790b1f9d0433ce9bd98f455240e2661c2ff4425ee55cb4ff4821", "0", "adfcaec117adee81a758bee8c9d7bb54c1f8036b8ed2d914dc43613f642d1ddaefff2b89df4fc3167c857a5aec946034f3e449d7cec80677174185bff724ceebd26b08613bb0ccfb72cf4f6cb1d3326882218202b3117990bc2fc7a3ffb179a88ad3cb5148cf3effa76a55568daf93188529e6092806010b803238576d977accf4c112767863251bc60914091752f530c4809098ed00819333223b668ea10c489fb2c98b8efc679b3c9fe3fe76a4ea3def5f0e6ef2589efc8ebd957d77b5e0846d602bb1337146ac27d02601eb753ea0ec73ff92f73226d84d02d6c50e8f01b9340505c3c2cc0b1476d98f64c431d000c5edf82f15f4733d31379453393f5797", .Okay}, + {.Sqrt, "1231b4e63edf624aceddb03decb0a68228a0dbd612384de4fe2f49bd5b21e7e89e43c9f247d33e6eaa44fb5e453137cc8307999f0a023b461ef9da3de490e7d93a9ceadd486edeee47d265d028cbaa8b1a4f63ccf22b76ee7078f3d33426c78a579932d7f669fe6a07e00c1a3678429ef41608714724818fbe4cb55e2c1e506bc9bb95ba99e71c95e90b6d1c8d3c075cc11324e714f9674afd87e10b6044008ce60cabd7b719bca266d070bf2f4f61accd7f3906d611a61c3984a1d5088f4f774918c58281c74b2335637554fbfd5439f6c21c99ae9e7e3ef158f47e69ced82d0ef49ec540f1d41ae6e530c6ac3e9b7cf4d187d62bbb66df0f8579848160fce373c1e3450d5749cc375b4c5c4ad6ff9f8a194c64aa755843273e639fda72087233fdcaf372706eda96109019d0bda0fc6940208149eae2eaddd359545c76ec638aecaf54ed27b21257fbfed4288e0afad24ea36c29f8174e454c4e6c33738efcc5d523ac0591f8fcdbebf6ec643f2ced9dec666f14bec461802b16a105b1a3703a4c4d12a15b74ec728947484d9c103b73b8d1bc0f4d0e7d0244438c2ea89ea595e93373c6c031023cc18194850d658567d9b21b0530d5963c7e87b98bf9cd83f0a95f50dee2321f1c41b477031c68760820f907163edd017a72c9ee109f6848744b4dbf8b781ad2d4a662b3425842aa92690f76b8f354fe5c4c9d24b23af8f6", "0", "443f55243255bf24e1729389431ef5eeee87996335d7b1bb7c45458bc469d7a73cef6251ecd6fd5593f52df9e490f739c768afe08c8c7556d476361ca3d11aa8d26ebb07df2215153cb2b452d56d7bb32143b2dea0a4b7d1a428e24c3a26ba2b66730b0fe008bcca583ce09e53836f38d03c6a5f30bce6693832cbfd89aba3b2879fc6f27c36bb8c51f9b180e14f514533a1dba6e23c02892eef94fc5e03f994cebe0e879c24b2ce8ed155b000ca305049ede7e3acfb1b0dc85259144286b3aceb03a3b3f6e3d1131bf785d314c5872eb39d5b5b9661f2ba76653bd58d7c088995dc32f9d7288c5b489dfb909c0a243d2ca0a8fdb2ce272036c1dd28ecb5a8e5", .Okay}, + {.Sqrt, "78be68e1c8de0a38702fbddc701429e5fa8c8eac3c46c44fd10ad5ba7b70e5bc12abf92eb95214d7e53ce6dd76ab2bc48c309ed06fd44ae65f2795493d0aaf5b7f79abeeafd329ac9bb4ad68e1fc5e403f289cfe25238656e464bd764abcd231414430fd23dcd6e491c4b34ba7b0586f397367b3c1528d9f1ca2f7659991a03df382724786ca660283ae2a78371b4f063a56c76a9b9fafc98d78b42a7d3830c9b823875515ad20bcab2857072e044f6118af04c070145104abec8670f6be5ee53e3012f98e63dd5b36174b7bccdf39963aebbd0bf6fa71cbe88f8a838ddc22448e77a0e655cb635cd60094064ad996f347119219311027ab5e03a3c31f6a34905cf2d220e742838796778357e520ce1678ba529775c421fd6bfb16dda08ecff8edcc4cc44d1c13f48d4d140aae94219b3760b4172539c397da56bcb83531b5f88dcbfe246445c14350213f2fa428b6328f1b1bc9f3f969941816244a220e9f96581de38cfbf53c50f1eec163c2fb22bb28498e063e8bce2e6c4e18adf31b3c32b4c71f59a51b4df56dee329c787d1071dc4fd07c3bc31b1df1ce31b223b6512e81b6cd493de1a1ef185ea18e6b1d6dd305bfe0436e55799739d730d5a9ebce9dd2bbcb0b5c8c8f304f10a82567194aa4334459668ca3cf6129ccaa717390a23839017a8fce0d54a8069bebaefd3039025b0c46a843297313a56240d8f16f78dd", "0", "afd045ce76bb5b9bff0efc9fe1653feaa8a9bad6ff2b1646492e6d884915d48df53f0c71a8b19cc8ff9391748ce52397728f566d973ca9a7ab44f29754aef433042c2f37e375f723e0ea13cf18212faea78bb29e08eba308603daf77f82132896686bab8713e44fcb94d8473dfcc2a10f3be49c48281995caf291e1c76dc202530277434e5acb5d620cd8e76c86f6d0c34d3246eafdaea1f9d87850217ad56d71b4c75c748d82ecb8d73e5d99ec416540c15ea68a820bd9cd07c82e183f6e6a5ec548e2e1d77ec70de5e9ff17567b07c4ddad1266c6913140c4b0af394a1551de045f4b4c1fb0981a444dc94ffcdd29c749a0d85247b4f2c3b4fcf4afe6f0a92", .Okay}, + {.Sqrt, "66b32d3eddcce36774e0ae7e205566d5163336dd5b7796c89c7e33a05f577e881be0b3f9864bbe22926978a9e35ee3db02da501bce33b47a79763c76172832f9632fa274c72d47ee6e451849f1c6e4f81b444c3bf4ba16e09c9a5a9ae30cfe115a51160834098340e8eed443130227d7d5585029486850cec26c92f05a47b71b316d5abba30a692c22836c5cbf20dcead58b22d662879a1fe3aa28817397f366e3689d7e67fa222fc26c3394d10e9a9e262d06a8533d8a827bb6ad14bb2197908e4561ba76094e9cd5f6568099bb6db1b5d001f8dcc30cc7d57fa22b0a8ba54676173a431a0db5d860eef84ed43fb681f8f80eda1800bacb2ed35d7d55bb1d33de05db5bac576a9aaa46fc6cb4969c231bce25bf190d45293ccc0d8db3e2ac24afe6968d271e018cf4e54b1180c82df37735c8906ff1524701774aadb637df774b48e14d61ddcf2dad730377b09913b0c0e3bc2c6090d15f6ab853025d16c8a0a67e44f4b2d15144797479f417c258287230ad4aaa1bec9f2257e26aca9bf26568eafdc4fec7a65a1ce890a3dc40a872054c0eeaadb8290710b85cdec671375fc77f1d088789db985c3faed67a84f8765816b01d99bbc3221f0542fc8eebc0400c86bb1cf64034088c43dbd931662af026a195a7b7bee29f32a028872e2617aa7d1382a1babae0145621000dc004ea83ea2f10d3e812ec7bf49f45971260788a", "0", "a225423afc89065041c04c88ebf8f54359d18e5dd8645e644c9979f35c7bf86894d2cb0570289cd9fe5b32acfeb393e72c59f5863dcc0967f105f87e2bc7b7ea0fdfcafb8f017b2361ae1e6975070bf5be017c747ad6c37c896d3ae5e83dbc04fed59354b1c489c6b64232cb3c55eb047835d366c90edd1374e696586150c1ff6a8506a94fc93d37aa3edc9aafc93d8eb74bc94deb92ccced64ebb9a8199ffaee589f2886bd1678690124bc8d239472a3da068598b7294f908faa410a83e67a4978797d3e09b39616bf324d685ae6d7582a82ae70d10761a80dc742e333b8e72a051776f0cdcd085c913ba7af9cef07f96b9dec02de42041a1cfa8b0e5e5ebde", .Okay}, + {.Sqrt, "a234e909871406e2b39e66fed15a9097f772e5144d16d3035ecc74163622326206e2457806a3f17720cb8b7e2b725bcd8b4c7a87432e77c3730fd42e418c9bc58965050a0be1f0173769342666aab67d612a0e9b5321336e6ba725022eaacc079f54bf988e3c048e165f0bc013a8f878c0aea336ffd9a6176ea0f7ff306448a2b9e952d9e2a4d1125c861b697cbd4abb912b709b37f684d5e1c64b9a8679140753574eaa415a79fa0b56ff4b79c87ff8e2591af7c25a103cdb1b99ec6900d89a95ed3947e8e6383d47eabb996c556d188af9ff9bb382c906fd770d21fc3783a5fad31ca34342c2bba00fed40f0ed379706a4a076298c11062280b0f89a4385f04fac6ef6fe9153f02b7d8b7d0df9225b1896cdeff99655f64696ba7a06f3b1ba7b23377a9bb9f5a0067ee5b087438c8ffa7e09e80af7edaa2873b72c6ba1fc04d46dac1cec3848d1382b86b7168929b45d296d3891a653a7720f0afdc6c2c55b1c74ac3b4b5ff1ebc5de62775f6745abe29d0cee1924db0a4f234e4be1296e03bdcfc940223eb979eba45748ec4d1f591dc671ca6d595f1dd3bb93a8ac95c7b7eec590de5594c68ea7d7a014b8786bab9a5c283329ac299e53668f17456cf9d505f7c0bf8650fe232a891324252596ec4ab740513c40065b4f3f623060f7f8fd02e777f67a5b464abb449bdd2bb6c32726b50d6c4ada9c5e98c751f0b1a612bd", "0", "cbc6d07a8f9524af8f9b24d985168cf7f12236618cd1f9ac449e19a90f43a01250732c19e7d3887d5464893c657fdf1b96ae278591d48cedeca292f9cff59e71a5832beb6575bfd62b97d12a213d1b10c5bf50377106643628891fcaab6bb327147f7e5b4099cff7026f3f1f615b2adea03aa6dd58215e554224a9b6517dd5b82edb4d1ea107004f77795e101a4c1ea9e60b98905fc3eb8eabfac7f3128d94063ec84fade0c25b8f4d3b3076603962c8dc8ca3beac8ee8988a20483b6acdb083b8f2b9d50f2b33ebeb1821436c4582f8249252d62cebac0e5cfaa876652482e2c0a1a425ef59a871133d9d1e3ddb27ce497af5930293e0c4dc542a927ebb2fa0", .Okay}, + {.Sqrt, "bd7994472ff15d19a0966649394287ba4ac411cde25769d802037a48155881534e4f58fdb7b0fe3e47b9f48e572e912b645ed3f13b88f9f9037e150d30c1e2fc87f953ad3dad6c9b056095abadc17bb42172962fbe942ada4132b60de98a55952c89fa66dc528fd8ba0fcd70c0d9653e00eac9c5b07ad0616669b028d1f0bcdfae7f7aefc82171062b7e2de976acaaf5a61f0fdef3717abfeb42429a85b7a66dd30098d36685999b09a047bf6b4bf3429b361d99be4738ec6d83673d034d90ba73accd46764c2eb50dc5d28a3dc49a6f50a33b196d86230ed42d06e0fa392221b8b0d7a75415437b60529668d7b6f1619e766bddd732cd793306dce7c27c02cc1c17b4d4642848bb5933d7be5cba8f98b3e7ec6b0bfbbe93248bce38c1986181552574dfb3d410296bf91b39e643e3ea8cd885dd38dee7d99dd615e92251069b98eb21f194edab2eb6e74da8b4b6d13589dcde8d532219e46ced7dac9d33693928c34daea5f5d479ca005f1659c7f32c9583e84d4ffa36f66a771d842602c8b622907c684d6a3573d898b2a2acae1770c4995016613923640ba6f436175791a57a865b4a7486adc33bbb10eff79e51e5233dd25d5eeeefda00ce49ad543e65436e8aa749696587fb0a594595a7abcef72bd8490341b44c41c19735884091fbf4138a992de7f4e51f38b4b2d5ca9f0093fac3fba36773d2c36c82251b3fc1ad58", "0", "dc3d64fa211ca27061b2429413971bf5ead613162b79d36008c384c3790c45f1a1865354de07be9cc290d2747debcd125e7cb265854f097669e3ac0208a994b0168b7824092e47508992caaed01bcee0e1a4b98a0a113d16a62f168747da98febe62d55164dd4cf9beb8241a0a1e56171de4a342c7ad118a400eefaa421ed55813e8f1c34df95ddf0cf713884489e7720d42815c0cb9371de0e7a49a1ad4aeb6957e81835acc8bb596618a6b7c527728398e7980ff475648d545003d9cf80bcf862687af4a541a28e5ff27f8c1132e3c17d7e6add9922adb9de9edb8d62cf2750abbbd6feb9e465a3a5112179416d48afea67cca9669ecab6c9c9a885dfa032c", .Okay}, + {.Sqrt, "de6623287f0b76a23a0ede249ce95f171373ea611df1cf37cce42203a4dc54c35625669b25ae8caf9940ab5e61b7cbacc65f299e20c721d9888b931522947044bab5af3728655f2aea713a790ad596e1b3b25f9b8055077288d2c02bbe317add33250ccad66da443de36730d810ea94813f267279370a98e8c4ec0a8f5096848f85500dd903d861dc23ff46294d564a74d12aab9ae87e40436728169c3703db2c8f4083d7a4c9d51f68810295596de42180ba9a8bb36e10664c1bbbeba8c404ec552649548c2ac521f49a91e66ec3171ee0b4287b12677f5a1a7f1c3146327d0503820bad1006410930702b24e195c9d04949aebe2c8ef096b55a3da9f03bec9718913262635d9f439125b76ee1cad6b8841ba7cff9aa0575b71a9b9268490068de010ba63d5c64fb44a80bf809b31cebf42fd7ff0bbc8961b4d72827c271b0502b22425031e560ddac2fc0ce6a310f0b6e943abba975ad4d75fd54acad89940845b389d4a67a4ffda02383b119f6d064a835fc2b19ef3c70117e77f05a3ba8887a2c09d3eec82661480c757c78994b64419b8359225b353205698b55e2497c99abda651f6cd891db3c729ef341f2036c17b8f08b2fec2677f1973cef31cfeecde1b0161124debdb8e351c2e7e37f2ae4a4eb54da1fd27d7dfa3cf3fef33f32107c6d4246da57164913bfd24e115e8220916a696392b156341330b681edfc89e", "0", "ee9bd7481e7acdaae3795e931e3b3149b5ca2581bf81809b67c27b4541a9a6e508d262951b1130899679d72fffc2d6773dece498300509b07e434d3a004b184a0e2eb09ae2b8dddf6b0c95a043484b8fdb3bf8e091953152b0a6febfd32a5856391994b4d15b5350d40ff1f51f3b678a56c52958a2f339d3c94b4d9d5331f4a86a34a63b5b5b26532c45eb80be0c22411bfd3f397f7c2ec6ee04d195baac712a3670b791a45a607284dcb7c88c1d2eb95182cfc8f8d09e21da18d867bdcfdd2f93085578ea6f3712cb991170b79ee2dd6826c70aee5803019ceea4c690764e329e9d5d8aa5996bf42037bb938ecf40c6e87a020ec104db407a4e574cb979a383", .Okay}, + {.Sqrt, "54e334bf0f5e731a9a67f4fab3f26f9c315183b786fa494fa6d6031a798bbddab2e669d070b236de7c2aab6c57a35baac10d173b77ef14ec32c39f5bd4af08d378b6e3532ad8236b7519270729d75b7fbea1e1f1bbf77135345219840340c15a397c8403075be31fd9f4740768734b15613adef55e5b387c0bc887188156315917d95b60fafed15a6c8b21feae1d92258ff249c6822f04e0fc93ef67afd8d3bd168974b03780c39cee3e232f8bb2bece124bd76a4cebf821b13ed816e90592c03e32e4969af91ae074b11b68fdd6371e7a57fc944199008f683798f0c9fb4d9830a4497229755e8d8553433fc611a14602d80500b78d5c64113ae34488723d1b8e263346737c95e3de0cbe1b9000d63db7c31240f50a096cabb11fe74e6366a49c0c2c2004f45a53f71a5411891d3aa1b111a96bb778837140f644fb53ad4e80ee2461774025a55644eb400acfb1f6a9b7e5ba8d6769130796676db39c8145443c9eb507e32d38f2d754d0546f68a3479960971e8bfcf2f9a541d5d204fe6ce16eb08b2d840715224e874e824824e7680c2875eb18d4755662dde2e64dd00751b84d46e624889aa2e1f408787eb97fe15efe9a3c627b86a3cb0510a35af61b150b74c9c5750591e898255334c2b2fb5cf4b11e2386572b6d6ce9da824449d4fa02d1617553e4b9890aa6f0d8a6926901c1b6661ee72a6758e01c7bf8917d7457", "0", "936a42bbd84e4d671a14ccb98d2519d567da249d8a55dad75205467fd9de2a1b97a9b42a36ab513bfaffdb5d4fd927f111ad8258e91ce1ee2d25ca06b586d7a70ebf19f40321a06204bcf1faaf228159e65276f2003fc072730670e9dc31340021c4fc3ed2faf69b6ad45a89aa7b68e0583b8d9d7aef6ea11603fdb53397f4a4cd4f87ced29a1193cce71fb1afa858c728e9d45e95456b1dc7bb0548c544007aed7d88179545283a29452c87442ed972b39b82ac7d97a705e07ff2a036e181cd66807e67801682d0f0ec025a47c506ecaa6729d049a65ba979cb0e79d6c61dcbfd34572409701a60baea4f8d7b8dd387b095828b06e548ebf0a749122b068d1b", .Okay}, + {.Sqrt, "3fb7668ad314515122607136c8f2621a12a613c872ac7e35814bddfdd0fa07e28d89ba2626a0ac8157b2360092c22ba2e139656452d9ee679952a31a2f8b65ca297e3fef9c449b740b7961c04495074402bc58207ca605b494be81c7592c4d05137e65cae8b2c741479b31107b36156970a3b9311e42e61c2a69bc8b37f031230854435bd8192a70910a0af20b99dee8026865fda002c61eda1e819b350d777b780ac54e010bb9aadccffa14e3cce0fa4e9efc507a692116656c77206fdfb4f8b5696efa18b5a59d3a47465caa5a6cfa04900cb2d229a70cd43eefd2c76138705c8aacf44cd372d56c4184e9b225a5ae007b505474ef650dfb94ddeac4bbd5605f3cdf3be5ef905245cc6e444e44b139129d3c38cbcc201cae1ad77f7f17e3954b1441a1e3fe24e048824dbeaf6678b6463830b37f475066a366ad6a11092fc6edea9ac3959c57b9c7640d509dc2de74420161e882db8de5ec2f386312865b4174e1485f6009d33f8907b7b6785cc2a31e6a86b0080d7099a91b70f4cbf3d573349a364742f1f0c0290c62213b91bc80838cb8a9a9fc2a99b82255a6ff629f36d0c77fdf5a90f0be8a3ce5442cf10509cc31c46079f9eff85ccb82c2c0c18ef14f2855a35b06c716e8b7ad35626e732cc1c0f001f146e598f824a0c38becb94c4ca4757d26bdcedaa56a091b24105ca7b554e83d78091a4dc4d01cde6d150744", "0", "7fb751e86f6ef50a81b0360268b7511658185b3a88d07206d659c89a0a69a39b26c3b8e98feb261a1817759bc6c9fd6c0616ce78ee60559ca392e8fbd1cabf63626d6978ab122ad25c872889bd22e72248c456c0601e98aa79f6dee02213a9627fbc2706adb1e5758bff4ca09c2b9461b071f38772f41201cc6db6b768b69a9ae92cdf9ccbfe85ec59c87b268148095cc33a22d951a10cb23533ea34cd93050495f714f62140880f0fbf9f885ef08e21e3cf1a46d30e545bbde1e5d39a649475d3f7ef64080e462b43d680153264b680ffb6157a652360d7f1c5fe06f200803391806a92a44e284d78745290f51610b6179cbe103d6ba3da66f1b126f431f4eb", .Okay}, + {.Sqrt, "966846a57fe6f46cfc86f557e293b031c396157f9916d685176b218b075728fee2300506002711b9982dab2fd6d49406b58f512b2491aabce252edd6c87e530e8f4c5366eae738c8b578906dbdd261484275b17956d68cf3b632302ff652de6a6410eeb26c8592931da16d7c3afbf0834beb0d9b86b31e4613b3c125d70e0ea698178f3b77b42380fc714f8081f64c2e4c214ff3d6cb1a042d2ebd5856634a42fc6ee48a5154a5afed9e4a8ab33af58850b4a0067a4e7a9ba6f95dbd5d875dce5c22ec945489ec63a2902339df9102c04751cf83d28d4b02dff37a84bb91967cd1f8b85e999a39a9ee31eeb561135eab3e27467d6d13bbcca91388925487e3f990735a0df0bd35405921975b6ee22e1a9d4a6aaaf2f7412b6ce101f41613391839252af0a6f741808046303e987cf394950a5602b7c2e160219b5f248375f0c1eb1c250a9ce105d6c0ec75216702415f44a5a486adb0b6926cb43b2cef8c8e2264c9c0ae66725951bf94632a993e1dd2440373aac3500ae5d6877bf880d364726bb203d8aa8db83eaed88e70bb72c72ba69730e742e52a595128c0bd2a0d5abcb3f44d5f1128f301009b7b3676565223159284801cea1db64530bcef7277b2c309250b5b4b63f92259e42c568d01472bfe64fc0627c6cfbb8e35e954df157be1cc19425a50ff76a8453263a51f1ba34978120f27fd4fb46aa046b09d6844c857", "0", "c4399dd4ca579cf6c5ec448a9d7b64feea16311595bf86c8d3b0503fefddbad2638ceb75cb0cbc0b5c4a21816942d2897c53a5cf1a31227023c37835dfc7b2984866676c5a0004a9fb5962b898e8f75a713e82ca102ad9824f02be6e6401c5a940f9171f8bc4fc5271aeae1bb3d73d4e5c41b15e0bf945ea5e99eecd972fe6a0e694dcec3c37000a0fef734d6ae5b8caf5539254794d52b3586b91edf438d3ddb7b7a8e2b2d55b206e8a2983038ef813646429a833bc84d6c5c9bd9ea8b0faf37561e249eb9048694d29a046909bcca7852d810aa0b3ff95a2e6e838dc3c7e22bb2fb19db4f5534594bed62d046e9cc2cc9c56d48299fc4cc6f743d8629fe384", .Okay}, + {.Sqrt, "2c4dce74ceb3ead1c405ea40494888fe5cbad56f4321eb645c548e7a8a5a702a715d1d09a57cfaee3140ec91ea2fe5e7d1fe4a34de875497b989f1e03aea7a6f8d318daaab419ff6fc3d14c44bd3990cb4714fe50c7612a042e120ef94dda9d1acfd3be98595d6042c092292ee6c6755135ebf9d70054e4c8feb2776295302d48cfc1dd0b7f5e482cc931000b5a363aa99cc55e01fab9ca57789f33d6205a26deed068037b4cc4bf21adb5669cf1017abee1ea889954100eb2094c69fc504a962be3142735176389b034de959f57a9dec2d8fcf6b67121efdc3b70f55c51bbfd005ec6023f5f29deab2e11ae3e113240624264fbfdafadb28e64212f85782c7f7b9462df27d3bbcc80033f7a3b1e25973bd80634f872f9ccbf90d69d30530e30cdcb569582ed4eb909928b98a78544808a8437a2fb5aa37b84922df9e2a675847979435076fa6fab7b620e36b377ea85c2bad1e94168923afe120086c4f51b567077ac49f54b455da22e0ca9eb310982fffebe888a81c44835f3fc4e3f308ced4ed6760263eb2fd6634de81cb10fa17253146e0d797d3451c0192dc63dddef7ff8b0c880f9de1e2a6534ee4b5d17d08569773078654d4ecff882407e9288054d5b24a6b6756f0bce394aa102f88af5f5e095e36eebc873fe61b4a05fa215a19d77a1df7b1a5e69409a9eb69b2b3f430d43bc67dc82724f45226a2e6cb59be3cb", "0", "6a7f778870ec5ee7755b816138626a929977ec0b9ae024ff80d3a3da830d095ce977ea76800a1407d6bd14903eaa443da14b90131016814449740d54abfe0389005048e4e0a807ffbb1f1fc1c2fb90b3df4cc7fad766a3d23288865f175a50d16923110e0a8852e081d7706a467a6728e348e69f2db6c9e8faca4e82ba7594ccb4fa1bdbad5583823269c8f0ef854aa04e99fa3775f1b77ecc7c7bb448c2c356fa2fb2d0506588b02a01b66b5098fceb90c89df30086f3e1012ced47079173af7af6d97a4beecd4f4221bb5d67f32aba15039c789b496eda94bd70e80c40e4219376f174185028585560b24718a2ba2e2c894bfc8dc8eaca131127b55684365e", .Okay}, + {.Sqrt, "cf18d0a38d22d917ffa20881d4c5afd77c815cab055f0c22eba2ca2701f622e3ecdd6e851c371c2ac48c92b7012ee97566adfaf5ad674e55ef2fa526c5bc66087e3e97f97e9d6d628de91af0dc14870de7c9d0eab1b66492225ee5bdeb2e8712b48e05ba77037741f484e2e0472e443259d3d7945241b23ed62fb2222a884f10079bd8cc729183aa9c7861ea782860c9979cb5b41b438d94415cc6c7adcb3f08c42d87311e74250ef2566af181dea2b4d1e93c3e56cc09d7d1c54d9dc54de771a817a4e75209c9f7cd5f54545e110aee3f7714edef13f9ed37f2cb38f326e105a9f97ac6bd2029dcb4761d8bfeb68db6143909cf364e64183140abf65a47df6392ca578aa2d6d448b43727a9639b0dfc95524c7b6c6229c806b94291018b3598d48b1db67bc09a2f0fc38de9e5fe81f9d9eb5a532f5024f3cf47d7592f07687e6368fdeba00ca5bb9102e6b029dd15d81c8bc3b1873f8257dd237ac52e93107065dd5360034a8bb33e5d3cb4be31b4ae3557343e12e9a70370daecb322594ca0fd5ea66b92613a3fbb67585d3efff9d60dfccea895a9d6f8373cb2f269bf9098d33999be8238a0472e7c3efebaf8e9fe9897418ee6b5cf5403d933e070402afd9dea0a31df87eb22366649c7c2d2e5a9c55ce9eb553cef24b2557ae2fa14b62a3e06e83433551ad16c6ef2a0a37897e4f125f781ec282ad947e7e561a8f382af", "0", "e640f967751bc17170ce6b43c9f5df762a7562c9ea74d473307ae0798f4e64e32c689861a27505f893ac29711ca3597a782e1eda5b4195b31cfe49001750a466625163f7fbae0d3cfe2e05cddb5f32f23223bc181b45a77cdd6ed9b3357d6e556e128214c0871deaa442d369c2ef879287971258d0a98e075d993374d19d19936d658ae13793cc77b373398c2900249b69a2787d04f416ef4ca0be177ced2172ac8761e7624eb45fe01f058fc3d8457476b5062730b6875a0ffcccc38f02eff0ce332760f536918b3165030932824ae1acbd89cb82ac5251257681805c0fe9f7d54ac116a49ed3e9d30be23de4e01696581516274313269e3f2cb750686ae622", .Okay}, + {.Sqrt, "83969e692fd4092cae7073f06040b1246da00202c45b128add6e4a01640598a6d3f20c579171f459d062147017d7d1c97136bfb9f1c7abd57466c58b0030e02bce4c4fae30227a197db7f05edbb905fc4241db155e5907d44355010c13b3de91192512f2362697a94d110e29186a6f7ab180aa08fe3737d3c22b066a3a8ac6679d585195f54189423510fc30535502f57013b7a433bafb7185517c29d5c9d88a0ab26b97829711425dc1c3d29f971d0d413d5ab2491d3960750467bb4616751698e253cd912fcf343a9fad3f5fcdad715120ce2df6aaa9ed7c9ea34c61e06aabee058b6fef7ccfa36c756ae357bf0b1f7db66867c66e67b95c351183032052279c00a6c976a275c9334d8f5cb0cc4c109f645d9fe7cecb2f441cf2cf4869a7ed587d40e755da50b3c7b4428baf4db6478cb265646fb8582a22ebefecf8f6325fe65d586beb9b25b04f7d33f1c9cd4be940a15f7e458c5a1c8bbc30b9fcc2d8f4b17e67e370783f8a7c62036c18651313bba7428cfafe4cba5c89e9fcdaba341590deb8ecf1b317d6a954e93dc4cf44b895b4e1f78804e4177057732ed9c20a3b39e64d151b7a4df2287b8313400149dfbde50b502b1ec63425520f150a2f53029e2b3b5b847ec66f55951f19a38fb67f4d01b7d7749381c4e48406ca6aad50a281c335d78999a7d57617610fa1238a1a8e9b94c0879e165800ea39faac7ba722", "0", "b78a0597e3fc78463a298d1ae5fc95df5f1396cccce5924adcf08a9bdd8e540c3beccfdc54e0a3b3eeff343836350a147aaac059d72cd92573a482edf24638d227f67b99a7b1c86ddf704f97d58485245138639d60212ab82eee64d14c9af8203aea7e8802eedc47bec864d026ef43ac473939a1946dfe4e85fa17ac6bcaabecc72d2aa6a3699b01e53f7a19033218cc57a6cbd50913898014053b772a6501fec0ac851f9b3863aa00ff0f614ab66c5a381eee826c78796eb8de973a0078cb0f3ae85177a2dc419ab6ff41e5664078ec82fd834fa38f5cea02e31749a7d1e94d3e390b6932a592380816fd0a77335ae96abd665cf7fb656aed024752f560c581", .Okay}, + {.Sqrt, "f62894209f9a1cfcc69a0a619f7709343cfbfb53aa970d7d3a1c46675c121a43e12de0b7360889a98d40de210411873186a51e7d60a1dd4497d4ee83b800419141b07e45ed58b57f32f0ec30f4dd0ba6232bd3f0791afb2a2c44fa0defa15382c75dad8ae5fc4d6b6123b6d31acc0e68255558eb19785c069464e509de630a94f85c8d8387181f3775758c9535eee269628b5f7c09bef6a30084ebca14faee1bec43367b92a331e1051c8d7b1bbff07f15d4c1743e543ccbcd6c4d216d9109e4f7d034e4e591425fe0501dc0332b198dfd4674729efe34338f6e1067be45b8989d238dfe7ecf7138511e76220cfc74ff51a49d165cf935e3d17b2c24c2a6d017941f5b9a404307586b2d8de8553a9616324ef2220a9b77a231c9a983bfa082ab7742080ce7976ee13c0e63b70e78a99d2dea45fe5dc40106400f15730e8b4de6ab379f3d16964c2e4c2b2d373d843ffdebdc48b1f890d0c2aa9668a61953c03ff5bcc18cd4934f058ab2cd0658189337a8790145786b5c9ca2ef8a84a2fc858e4b9f7931cf4cf404ff885d5f8bd2d1636c84475586af19efe2ca370d4aee8079f7c308e925f89fe0089bca35b76ef10e7d25df7e6f279954a11e93d6944c2626c4c5e9911df70db468f720cd439d796542b93bb1182bdf5f9ebe28a3f5fdbc4de9108f28f04843f98da3d60751b1ac44777113ff3821bcb67189b2de6b2e9735", "0", "fb07f1a90f6ad97b961cb60422a484b9a0273cf5c8f4520b471f439a47ff53eff3b490148b6f8a769000eac09ffd213310438e28b855632c2c2a4ce59107c667539742135459353c20c7365bd06c4760cb525df82001e0a98fb0f80139d46c8373629267a1e69abb3dd4dc1c17e68738d64c7dc1cbe36addec6b84193fb10d9f00dd6c051cb441a091755dcd7a4261f3d6a6c05f72a3d536c9aeb2a82affea8880fa7c1688bfb33c227d45c3945902c8a9a81f5d9eb8e1b35db075d1439d445f5bf6dd16c43e3e9b9557d9d77822269151c01323953f2de93fec2ba75c386f3f363c5401f6ca39265c8f4d2a430b8f3fddc8e7d691b54c448a488f7fc623912b", .Okay}, + {.Sqrt, "7f6a76cb7100840248eea0b25f778a23e6a2c54049afaf548c231eb76f0c8a1c4af88fe6652daa3274ebc5330b98da059da21d1081006b85065193186cf97eb9113f1fa3f06aeb9741f91e8aef7bfc8f51430660a16490b5147b38514731502757eaedfd3849ab1194d10527f6b47525869792f6f59d8bf578e742f727343b86db17493300790d0bc334efc611f2f459a92ed80f98e6dd9989441a08a96dc639ada15f3d5ef84006e0b9b4b7b977ad77ccebe66c1837d0a071cb5d7cc535a62fa68a9406c063a34b519717a9c44e0e9d5b4150dc0a5d1a7602383e8bf62c87131169f73f36e7370f59d89b021be8621db59fbd2d5efda21586925421a7feb7f029c54721e9561d2c12a42058679ad36daec6fd6769660e535ba15dcc461efb60eb53d86832c9ef19c0bc4035d8c8847e6bc2ce34818cc01bbb3cdb179c73447c64d8a77c00494d8c0a9eee3b0f8fef81c23589514e08cae5a9b8f205080a214db4637c39d87280891a139d0497b6675e4ca889a57809288b78b0260b76728e94a906a98c033001d07653a2e57fa23e1df4b6b8bd0a0302540107c14886f5b0e3cac59795dae53f97ce6c8f8ec4909f59ad2a79ddfb4dffdcd2371928ebcaa3133eeb450308e47b06ae999d57f1e35164ae129505eef8d7525d16d71d3b9cc45333d93504c521168f5b22663886cc16b09b43944e2176a6dfc003494970affb1b", "0", "b49b1759b6367d0bfed4eb9d8e1704ebebbb6257f1c1b3f8b915a37413c2881b2dcaccd9a50fd4873b11714b60db0f1aa95ce4661289423cac40f678a4653f6d6cd2f099b611e0eab38210a33b1be9ede54576adc6e574c4209442bc9ed5b880f85d0b184fefeb55e2388e65789a09475c1b7ba831eac1577fad248da6afbb472b22af31969cf3c2446e4af3d1245b03dab35ddde7d62a9820ed337f4b2c8fbb016ea34de75a612bfe391b6260d91547d349d04ae3b690a4519f441c956d954ee13ea5a92fe766187da17fa6126548fb024ed0e0337d3bb00387c2b30941d32f5a5308a1bd71cceb99cc71e366a09a731d070dd3b1aff6eac9655c1c13b0d1a2", .Okay}, + {.Sqrt, "34dc5748d1b89c3b872485f17fc949fb4fdcac79a235ae8b233a0ef6dfb1fd18ed0d51ceb2cf018165b0a08779113178c6f4713416540e5f4cf894b460d81620e06e3c11ceea74a1679e462c83291e73ac14f46f1e83094886b6a7b7daf947c825a172f36ae6ba8565181497ccf29a9b85b7ef1a7effee14b5d89909673ff3ab47b81b2cd847eb74f5b961cbc75464abe9e38d25eca12ca8040b923216ef6b1766cabdd96d910b5e2d7b9821f814f1d038619d8c4d5dc70e21b49790f7a0cd4852de64289c38c44b57af93bd478c08b0711295dda0241201b69536899e0212805620a8d963bb52369d3ca17be31fab1896ede44f7aee163371f26450938c6d48880d51d2c6a7cf971a0934e0783e6741293fa10aa8dd4348befa5e105efc7c85bb2e7a585ea1a1664f63341348b034a0bee50f99f80e7974f33fffad6eda3f73cb41069f2a628b90e7e0b19158ac2e750457b3518ad65e5fd3c57b0391959b7f9ee02571054ffd2615af5772f978514e0d1dfa7fdf5d56c952103e7f9992fd362d20d850e39521db2561d2835a2caa1146f84083359684ebaa741547101e4be11cfcecf25fc84374bbf5587aad51e6542b5a28174d842ae2dd836d8e08038553a040a18c547b7450bc1448d945f81bf7c1315db01ca1b4ef43fb8d450f6c723bad7940b68675bb42057dd4dbb9fc7b082d9eb498e3a99413d6f41873fca8932c", "0", "74541e80de5cf0d48146512c0f78f80cf28dc821948cc11f97d875096e4b8dcba574cfd44ac6d9efdcdd5b9fde09f336d2f4367107691ce646ad5a5d1c363c8fdb872cba9544e8123cf4f3fde113eafafdadd9b3e8b3014c5eb96e42901e39c53ce28519cf6a33c41232068831fb8c47a263983ecb9498c459dc516ba53d4cee8c7249cb2852591ae1d0763dadf526136dffbc466053cbef258a095d89cdd5f6cc70d5b8b629a8134c87598a5bbcbf2470e928ddfb22b8cfd9be431a6dcb69df8c3eb2d3fad654795fb34b286721ea427788f706b6395be52e99bd8a64666402b19c0cf7dcfa644dbfce64989badae222f42b42bd690d2bf8c1324c600a7a15e", .Okay}, + {.Sqrt, "1f942b75ca073e542cbd899bd8aa82adc6744968668ccbc3448fa1a562bcabfd2ad0a6e22a6a6732c7ecb02465ea03a75b239a5974412b47e248ad9deada98db6898af8510d769ecf40cab619ab65e30b154e127ddec28925d19d0ac2ca26d33c688da702e390c99bd737ead83a47bb259ff2463938b844942dd84111dfd37041454c14f6fc561602063a2d072cf154d45853415d798b862eed3f1bbae0397904d0a92f5066c6db79d2d84d5008e28282fb5769e85f36c71e9309bdfb0c997d50d47538b18e09852705bd8f6a37484f6fb945abffccb3d45265c319ebd582b09f5f7f0f97ee890773d70c9b4a6fdd97f52de56a633219fc046247468de5c67853bff2f3969a869117bfb0386d641ccfef001ca562cfe3d665c5812d8b985b03588c6e14b03d255eeb23268af50e5561b2379ed66c747ee64966b8822045ae7a70beb367dbd6e09aa6ff7b3cbf008b6e612c728b1f80b4164683bc42991547fbf8541539235c1b4062add4c754ede6fdf84a0579b454368021e72a1af6c3b2b94de13afeaacf4b4c62239868e7b7579f71257db82b93f0a98fb8824d34925943c9136ac88b2d7c3711e02c25ffd6276fa69573010a34b9a8f6b06a08315ca014efbcaf3506e7b394876270f99f188195dc1663eb2b2b7ed5e0a1d593410e460d2be3ad7ccea0464806941b1cfea0d0a6121a32cf3433a39ef10ba1042f9f54a9", "0", "167a5e6469693ec3a66324b3e4a760b1b544ad18e11eddc9230a983cca61a1865645fe03e9d16d7204f92206146670018ff92c2f72a0f0b6ad07bcebd492134f560955091956c905a68868fb5f03d3e8f87ce407cff674349c880aa4a0c5750301f4ba28314cc0d3aae379b55b4d1b23bca00a919906500c8ae00fbb80f0afc2dedd1aa57a0b71f1ff0992f36be76a600deaa9d520d18ea977bd6cf3152b3e305b496403a56338beb69d3321ee8bcb16ff6453062b914a9c73f8c59868f87299c2cff3cebdaf4916194759e7bc21c8cdeed4272141472bb2aac5ad67208840331147704d6c9f317abe44b666d16dc24d7e71553801d1c184bfb451897d7bd7c0", .Okay}, + {.Sqrt, "748e8fca7265702e710f809fdd1b609263f157138ce141b24318e1a9434e05cc937ddf36866f40cbe128a837a5312e87874c1e84c626699a3b2053012f0fc0992a0b463b21d03de93cbeb60adaba44b02ac07c8711b2f530fb7ce76ed9fdb72827c1860d4a4417a3e9d8b8bdafc238ebd5f6790303765ea03cdc83a39de151f6a16084038f25afabe6d9cb644d20c2ee651d8f864b8ddd0bd1883020389e7677e2428c01aa20d18e773e3fe90174c94d5ad6fe324fba8d7d0a00650f1d8d9ffa0f68d940dd83873efb5c8aeea9684f8fec7677b84f236c917426f7f6786e6e97ae116e6a3671ab38402560e7e73ae4802d17b6ea05d644598994f9d32aa42d47f41acc5a42dc15455a018789fa7fd700cbcc9790ba6bd50d313ba93b07adc57834a969c3ced7e5b6f30ff635794fc94b11d3d394c55202ef547dbfa8844fda3c72265e51eb72c651f1ca0320d3a7fc118e33ca81ca0d63ecf8b9db6c3676b6dd749beadcea57e85f0d7c130c2d2b1b8c12e03c11b156d947d58c0ab3a2324751505b15182e482e6b044def220e9f123f3e401644076b52e4ae4cf54cbda34f34b7a28ce57f80f0a69a9cdb32fb7a6ee9e58c29ae7077888168e9a2e678c0fe6191d02f8230b4883d1821d06f67d3cc1df1f67cf99565eb4ba32eb76cdefc8904bb30390724af4f3e913f99ff8f73f1193e59c5fbca73ec3b99b9ace5709ae8e3", "0", "acbd0914dd38cb36628ce08a1ae327184e814a252ca3271ecb3a7e294d7379ae7381bfb9200489262c8cc90e2aba47156b743ea8a8e546ea312e9fbdda6331c6d67a87d7cad0622f4d3372025dfbed4ab7c818435ccec40a9b2a9fa1d0199862628287bc027e9bfcfde6031427fb3d1c416286b011a6c6de8b6f22e998001219cda2f8d81a5927b0c88ecae4631fa6fccc65c69892e9c5635d136480a8144df6efcf15f3930b13564c4f2fe2c39f2e7dd4b98a686c725da5944078a07870ba5cb21aa61d60a054845889f81e540b5c4f5147a3af748d384217dd7e899b0b355373a376a3c0ad60dafde319ceab209636a0c72267baab33636f4f882b818e8f90", .Okay}, + {.Sqrt, "b67a1edbd011d9b1ed32704a62bb19c3910c2fbd72459e1434b282fb151a1a1e807089ad19e04db851f08a05b691c3fb4e5a83bec3d39fbdafb19192a9a756ec24f98263477370a325207439dc02bbab25d77c3dec985490cd16c1055fab7da1dab28ef69c0c337700ba6af4bdfb5e482d75af09f721947072389f8b7f358cb89a8e84a8b699ce81373b6097cc5044670c02da2a02584e8bc4637b35c815d1fb7ede987a29e82f227b945ee64caa0bc040d80f09083d38af96a0d05eb212c3a1e798fc4b089816a42d83296d178631a3c61fc76f38740dbdcedf23ee7eeb2234c1310622a555cd17eda91be6983cab7e554e1d059de8f342e4c52688d5658b6b5d2a42e5d5b743c664b5cc6bd449f39668016a8165ffe3b3cf159146a920a7475b1da43f93b1c1729ecc6303b8af365b46fdd3fda6b58255b469f0ef3e6ed854a0339a6d1b3d1cdf1d4afb088e4dee1d6597880b84615dd494d5c0b20121cb043304fadd04d4d5ca4da809c4a59c8730da7c8e1e69d1299f4a7782def961254cecee80d09701e5fd5a731089c456cf5174cf2f128c70ecb034d5acd90cfe651f92c846fa2ac94ef4772a8edb6faf37c2965b409b74533b0a6fc6488dfc8b9890a2dbf2591462458525d85990009cdc6cf58556fbafcc2404e1c7c225d84b05aa63f089e6a17528b22ed38a9a1ef67a2f0c47b703c3f2f7edf3d489ce3eb7d524", "0", "d8226e5b71e672ec8dae8dae81a825fe5117456060f65caf110f2de37f686d0d9f500b3e3f7682fb4b173509152fc8384b2b6e34a26aba7cfdab35069b6bbe1040d6cb24d26e146c4e7f8e0685db17defb88e700becd25bbcb2ec06cc74e861f7529de318b8567be358d868618cbd86e7bb698af65c0bb372fb231b8918413e960804ae9ca8cfb662dcbaebb66ee67277dd45047c21dbb6d36dcd6f6cb184b103ea56ef2429cb640d5a74375eb9fb1578dc144fefa7cfb94caee249038608b6f10dbee06707c633162d66cadbb3f8585f220b49279e49c9a7a1c9d30509e5644e1be2f88553d76dc3fd47c34f00b30ff3abbce5768831f520521e747bb264436", .Okay}, + {.Sqrt, "4f19cf68827d9e783ad7c3fcc575acce8f252fa7a4a989f79cee7104060e2a45c10b1d82f3b209dbcd36bbb728638be81ccd5f362126b834197de0116861fe00e2c3b6167f790dddb063c4da753040c26572b9684b5c21f95eca9466966be9d65d85453cd7f323051dbe27dab31c49885afa4ea67edf64b01b86538fa7c4140c5a04704c5d927fd9c0d71a84940892827b92f9846b3f4fdae980760341b92749dd1d16c72b3fa10bfd3daf839c425ff774a6b6e8e10f808e3da6a50ad2e2b26c69a80884c5c2387ae779132f420f65a6c3b609ab6f84560d1b765089611ec00c7827b9a9964542279743e4cb93ffe05363ad4c7cad165b9d2bf5aad71e9641b7a304bc179e592e390e15a0fe6aea4bcf49562669de582144507fec46c24137d2ba5f265bb71bd40c60279b1962f5e6fe54a77bdc23a89dba8035275d16b38a8708c7c6b1d61e2ed77728d57397ef57ad681dfce5554e1b96d79cca57ccf9e58b9619d04e7b493287c5ef5ea72cef57dcddebd73217d89796874a23068e5c4e5a81dfcac3a7ac97e48c8c5aa2b7871b8bccac000ea87d87aeaa69451aa509058b4a86494cd14cb5bd6a7acd1ecf716a34948b26892af624ff269c4c6da916f625f235e6e27e3d28ef0bb42cbb1cd067eb3770dc88800c8ca53f0b0dfe6f559a131cb7e64686daa8170884e63cea53af595ac33a424b49733190c1e80bb27189fd", "0", "8e4d4495cbb8eb952d95b176651df19579f3c6e69a8aa2286425440d03b2a7466c4e0bc4142ebbb84469dbf3821a57569995564a7987450f133c1f529b127931722a6c1b5e3bc6d0c5f12911b64db5267358bc014e591e5238c9f1b1c015eb1d092f053859ae4fd931c864819f98f660e6f81f9931aba6c9e3f36e93257ba8725b6fa20bdec60e5500af6bc60fcab9010295b69a7d643f69f6dd14cf99ca25f5d2c7d1f02079dcd02e9a7d25325f17046cc3d9a38fe8c4fe02d97db9ffcf87d208591e841c6c4cb008a87df1342fce543d8bae6192c1ab6c8c7b85aba692efa1063e30be1ec8fc8137d678cd3cc43e8410feb6d1a86482d620f54acf3859eb94", .Okay}, + {.Sqrt, "5bab265cb07053c6d98808f5d6c68b86467f8a5e1a7bfabe06d55995542964411495bfb49bc23a41cb4336fa89929f83f7340ea6522e1bf20b1306b03ea5d6a9a7d46d39f63a65594f23f19fac68ee8a9754dc4b1d1144606762fa3efa9904d8983f9cc1fdf13c2f3bd48e35b98db221e9a683a9f1ceafe95cdeb02ec2eb8f64cd84cbbf53c3b977e0a947a0b2ab0bbe7228bf8a4e718939fdfe9fe80f998c3cd8dc845d197243ec44791cac37fd3952ac3b4c42249715e089cb5fe0cd133bca439211d2c970beb5c693405629b76030a587b5edeae3e13ffbab1022ad9fa7b23d3d8e5ce9d749194a1bc7b5cc3fd04ee00b5331777a2410f2192009a3acc9a4ae1607e11c5f31dfebb8e5ce7078496be0d1d0ef41ef71e493c0eb3da8f73d48fa67d14bf88d8853aaa09aa29953eea9f7ab660d272dd5367262d7f4e14717b8e6b68a24d730b578fbb5cdc2c62759d8927351c4e0f86a6bb377eb371309de4d7a1942569589e86b3b082f040662f03cde6bad6ae5d4e0aa5e20452ced8b4554811708581f4c001243ce08b73f45fd9d53729df6deb53da788b8e9d408045641f619215ca901ffc73fa0bfd5873417c8589400bcc42d2ba451d2d4f2231763c0327104315f2f6ac915ab3d0ef444bf3f49642adb86ba2733780c903817c2b84949d0560cfb9cb993c3d84d1d134ad94bd9eff5c72e0e88d0a992c1153c71b20c", "0", "99309e39b3dfdf318a595445009bdfcadcccbda45d3db50fec3c8fff5f07b52681323d07b06fdda307175a3e114d560a12b9603f95a0e6a69e2e47a985ad27455138da7cc0848971675c9adc67e0ff0ac116c3681c73814a6b0da5b73b925ec25b372110d219b6910100969255369b94f5ffa95692a43ff73271304b6d85a05d693a34a2b54484c901a0c2461eba92fda16c5e4d1c8d14380a89df54757a587b7762f24a8fedccdb4395134b026a96a0740ddcc0ed947cd1ee1018864b68fa84cfc673eb236097df932c4882132242979f0f0366b643f1f61d671e8a30661dd349f87ce470bfac532bd8962a7b28a63a7612ec47fe30831fab9460f1295ad74f", .Okay}, + {.Sqrt, "9034c69ea8fa31a5687ed4407a64957862f63a2267007f7bbbf485852b60fcee9d9d34433be4c6e31957682bfef07a8fd4051a54c26247e577c53f4bffbfcc00b421a6174301e863d2d9205f45b09f1bbd889b54bbe7768655e0086986b2765ba2d59e3e461f3e541d3d323424dd2d46891eea6eaabbc658d6db423fd46ecef220b9ae49a3b2408e062fa45f9896b60cf27eb04948aac327f6a04515db82fe4f858b0f1abbdc87947b61e5b9bf56804eceb90087b5c9b04f0525085dddf70a155d54980936460ded7ba4e936970db58feacc62f90be4b8323a4fdcaab7b220e1a3b5a496ede9a7c5eb7d21e7fa030a4d7cb963f01a9768f3676bdfd91b2cfeec597c27d610c6f008592175f26462fe65ed6360ff85e3b61086a29c8733b31fac89b56880f3d34f5ffda0b40be79c853ab5c65859983fa90f7373a18a61a402047c245c954ec685dc267d0e13efbef451035afdf89f50e1201ebcea71f0eb51c220946922f7200874bbce65c13801152251397a96d28df8fa54d35c6d628b652ef81d9383e1546a001f50f14183c88fb52b71c0a35d4ddea4bc177232ffb55765f1a8ab0588e90fa11b9f24f0f7870c74a9abd8f83449f99ae4d2033f1ad1eba683846ad3e68f2b6c7816aca08120a9592606a8511d7abebcfb3904ce4f34bae2e838432bc902adf206b86aa96e8d371651ad8c3c446980edfbf7b3076de192c5", "0", "c0232bdbc23fad8dc20f1657b25c90160dd448e604e3cd6a0e787580bb079398d8b6c38b72f12a8e7458be531e7e8161bb38fb765c93a281bee858fe475483da0d78c873d2248dbecd699670a71bc062721a24836aa7a7cbd31e56c89ec319a86f6fa39209d45184beb7a6ca94bf6645813c9236b5c7d5b53180f1769980dbbdc28f347b0d9ae6c0040c1d33c214d2ec940f4a448132ef1691bf0026d31afa729c9808067c4ab5053854621a44995b51dafd04a3c9e2844546af27133cc3991648b29a3cbd243e31fa83a743821569743699042fc5af1e570119848a5832293223b988de371ebecc615712f7df14dd6be583a5f398f75d98f7a5640e3f6d3056", .Okay}, + {.Sqrt, "3440ceab38f1bd92e32ee22a788bfdf69efa96691f908c4d7a1824784840152cafeaa139023db6e606746a8ef6d8ea6044411bafe878027b5feaf86fd7f436116f30db7e85dd4099efae64223612598b45a30ae8cd7456a66489da9c1b9461c56760f75314b1548018aa4e1a82579551bd9741bfb4e7bcbe705ca44963eda7cac3a92657aeb1a62e55517fb25426808010224b6749c2cf4bbeb435bf1bb8f9c9cd7803a64e6311b7b4484eaeef6135652dd6f8497efd10528802d134c9b61e29685153c457803ac36ef2be3deafb3dfb793084d0a37075f2e3e1c212c2815344495268059434db175bfb7c95c47a815b7513a1c5347314e424c9d944c64244b0da6336214f8c85b8cd16e2a1b6bdd61d0fb347d21f5230c82defdebd6f79ba92887365b444e41b5546c357ac65b86687412d3971e0b7514e433d5b5e11e539e1254ddcac1210027d315bb9d2b4cbc68f650f524091133a6698b4768671663031dee9a1d861859a416685eeb431b034b3e607375bc816e4b021eb56c46f1d5a5f39ebde4984d7dd722d37a8786910cbcf5b4f2696f846bdfb0540ca8e99ec64be6ee0cfc05341ed6e9df09b910600a80c868b21ef0b771a2e7b73ac8a7391a33be2e0ba097b2f0e9a8ba671b2c7d2e47ecbd61b2df733e1152ef2463b3e819f1080591a20d416b3e1f2d3d3ce8b79cc4460a1992a113697b1e720fb81a87f00e4", "0", "73a87c6a81e0bff43630e80a166000bcbae2f34fc2bb3ddb278e39e11623e28f973fb16f8a0c744aec810409d04444fcdcd9a73fc6d41bc61498b4d36e9e94fe44c828c50bc444fea2bb29da722665ddfe01aefa663628017cd8311a4db4ba46318a66dedeb09a6ebb2d4ae305dc0429080e9308ffbd83ec59a23c3306836c8fe7a533b6f32f27afb3884c03796ec1b45456577da4f592668fd29b56df4c404a780ff16ae06e9e2ee5193cfd7dcb83ef164fd50cfbb085b27f9dbb83a94233e2f22b5b5d25c6b68dc1f0e68741e7b44c885ecbd6adfac5aed734fee151692a803f690c0b7d61854a7e9c13b6cdc873f9c7233e020c6ca891a971ad9739631444", .Okay}, + {.Sqrt, "844d0c64f7c4bf53547f5ad55668eb6f8a40ef2c45b767e1b752810236ad6ad6f7844d6e6665061464d13c4c5ac8a34a44e6a49cabf262b47213ff18caf7488e1c0e0d809d371f3a4e9a65c17f7082848d1b95a5303ae9502bbecac4290735ce80b2be1203190aa2c07a692fd444b38dd626e382c72f8c94e22db1ccbd85df21921a408aca5c688790f0e7ff8d06e0e888b7f900ff2f01203db5bbc5a9d922c7a3078475eb0bf76b62ce65ef96a0760ba74b4f811daca303e9aa77d44a4ec7450989257e1e9b6167bae916c1ea3d0ac086f376de4f01035851f370a2ff505696e184e570ed3c0bfeab3de22c94b5ccaa91facc73c05c0122444ca434a3290bdd4081d8b9b4bac7be533e52fa998438816014cc8338bc969d106f96bb54eb7ca7ac5ac626d7dcff284ad42259fb2b84a4eafbb6287ce2ad022ba7329f5c16958098716d530a024b69e30ecfeccdf1fde5126b900586f8fc9d493a246d123e5153686b37861b8e8fdf77b8a354b29ba1070d27446c156e355d18b7552d031fcf7ef113ffaff88f33adef17d824d95bc166270fd39163800b88cf57688d0b41f345037fc7769653f345e8b0e00bbcf7453534d76106b707d56b4eb36f8fd749e2d94bf8d5961a178eb48ea5e81d0639b0cddd1a1a895cf6a0ff928fd7c3098cdee3a2c73b9f8545992a2573dc1c76cb9abd7c9a16a00ffaeb1b2c39c4d5dd68960d", "0", "b80913875dbf273a912072172e7412c9009437845fef93ee976d759931e6f4ac3bfd4f7db40afc7e9b676a19c2d6f6d518bca30a0ed5d1a8196a2d3b49bb28cbb37661dc5012ed1e75150e1b304273ce51f20b860c2eeb18ce60e09dcf8f7ad6818178b2e06ec3e15467423571abf5d91f5d4900ed8b25d1ec79f2438891124fbef046eebaefa195daa75c02394d19752efc3b496eb8793850fa712ff35354f8728247d4de138b91586e629d7baec24eec38ff0fe26e7ca775b93589a9dc53b769cfb462f7d32bfb4f534ece0b08c3f9afbe2580291d567df53eee1f87917c6458f82ccfdc5250af07c2447531fd3e96d08fe53b153e1ad95ae30a77f1d23bd7", .Okay}, + {.Sqrt, "95bc1b3df0b5e6fc2f33afb09d4b3f1bdbc31a2f876489e5a2c155db3aab226048e99ba399dc836be979f2da73ad6f9026a2199e896ed8056bb7ffee03c2ce4cb56df7fb3cfe4f7989cad77f619ee91619c9abce5c0abdedbc56847f5b2dfa1390b51e3599b315393d7c1aaf38c86e1d69ab731642e6fd51c1a771e0343031c204b6a2911480ed4505430b0941553d209cf44e444282cb1b6f1836c62615bcfc535312f323e97985bb05135c1a948ebf3380c830533c0b2fc185b799d9cd72a56eb623134f23ce154ad305113da602b91b0caa43a4860dba3eb10e46b8f03fce3e42c9578392f6ee8787c29a04dd15bce4a84f9de93e3ebe1093db3dbc359e771b86d8c6e0907ebde74a920f1b7cfb54de1eacdc140842cd9e50aaad9dc67cf30c1ab558796200e135507d220ace6b99871dc84f469370c8cc365a819f98ea10e52fb9d7864092c950eed83a18947e3d6ac4cd3f4e299e2014a7f0326613b9d6410ca40c1d255bb7e9c76911b220d446ba96ce6bdd01ea049541730382f52d199700ac271deb6fb11f68adf27b3db6fbf445a132ba20322e4bdd0396c9aae9c605015f50ed56f1a3af17eea5742190c87f8b5c49c8f7a1c7eeac9e1b4e7660f21deb08afac91e39e99de853374bdc95ee6e3f4e1642bf589016de9d28aa2c73f8f3e8196b94a2c942dd614a3c878057a5b116d92722412e2da9a814853f8dd23", "0", "c3c92eb2446f8407935aef62053681646f25a12a5e1114df9ea325f4996c02ddc2bbf5c2b24eeaf27cc707c64fe2bbc4335ef6542b7bd4ec9512a83a718772a15f85d62992882674a7538b856279061a0f726375e8016ebb99b2e9e7f6797bf50c2c996c6f50043d7738a7fb6b37f49f29e6401a25de813949708e4f1cff687fbd11ba5ce30d79306f65b85338d51fd1793da4850cbe0428d70f4f2d5e4ee9645bc8b3afb5ca4375dc90f79bf9e69ea024122791d8a871a77574e7409f9751c4b201308fee53d2fa769c708e780f9064bbef1552486bdccdd6227596b973d98cc9eada5e12948f42937e1826ea6132cd39c5dc8fa3f2ee239e990a1b7e50d32d", .Okay}, + {.Sqrt, "87e766cccdf49651d1ce9e0ff7570bfbb432880e14474a50ea38125889f26ae13c68acb005119a0817176a1238b210853bd37d2c4938d7c9ee8e466bc97132c40b10f0a9dade03bd2716720e3ab52383dca18a29f856731f0586f3d3e574de081bd061ff9da359c4b8c182fbdd37823c1548436db5977d8723aa94cd0eda0967583b657e009cf8b513c011a77f81e37a8bb52ef80af446e54d53af06101aa61b9f2183bbaddd9c137bc75474a7b1e1d162137319af838be3a3248ac7ebfa989a64340f43ba0c426c119296e19dab640ac6c40d5d3fb28e6081d4ee0c4ef0c0e55ca98beab8e0b3f3e3c03ccce602dffd14222ca6ac6309db8f6e4f9d44c9efb58c96ff88f2ea5ea436040a90b45c510c5a1700ccdde143cf62779f8c391609fe9347575a397584185e68a5dd022986c449b0af6c00cb4f4342822034774cac5fdd6bb5bcb74ac8dd59f24d0e4549fbb1133d53c1964d74ac5b35a5cbeabc887ba75f72dabb2466fcda750f8e0fd24c208606aacfd77945c96cd6ba1a3390261f4b5017b13ac7fe061f3f7481c373f13798cfeb1ed6448ee4b8d715a7fd7e6e85501cc85dab72b9e2aafb0307f5cca7db99f44a67012f6970189ab7d16bc855de17f4a8d4189a2fda6f6313f0342e30d7fac68617ced193d1e0bde69a2c132871657694ae0d5ab7fe64122c03a0270c79b7376e8abd3f42c2b89483446ac5b9e8", "0", "ba8647d24339bddb4d7045c3efb5c94fbae276393d3c0a6cf51fb54902fc7084793784702329b599945a59e84cd603650fdc5183f4ee576586663e1eda9cf69a3e343a47186474693f27874f737b22915e8a3531923ba5d9b10a517aaa7b1cf3fd50f1872073b94fb0df5dfd00504bc414fc7b4149db8b7209f3abe3c4a1c5deb6919f59d8fe51c2d3329cc7200f338b1d52e618d4f3742b8b7f2925cb601b44bb6bccb7a5d9fbbd561fe6727221f690b535726d0b451d9b40fa47989548d1b025de1112b0393605d29b5f96192a59d9aa493a28eb3adb8465d1df2d7200a6e1416f231306c050fa75f7c765e2b2cf28e39dc83531059fc8de12f83a33eae606", .Okay}, + {.Sqrt, "85ea8d4596f6ea443fe069eebe403a11da52546c18473474aed26e929862dc6ebd2cdc0b31cf51eb56029c293af153c358886d7b0c3b678bef4656aa9d53c398fa6d4cd7184434c89cfe69146f72fcbd4078e2e4041efdd2272c66a207602a976fca11ea7dfbfc947854573f75c015f9d35558a39d07b72d42fb29e2ac3ba74d17c7e7684b8e973f11f46d9d5599290618be82ce6f051e3038be3c3850ac76639a601eadc847f13cacaf1195a2d5bb1e6e77801bef5b283104988c4b3947f5d19b68cb63757c1f313c48c69115eb8f06424e8a5a8a79c888907717bf7ea5d595aba7cae074ce5e33e5be647e59e6a8493f5f9ca6bce3ad3aadb519f6b59d04e695cb9e0da738b2c7d4d9e03e255e1bdc2b9bdd87bcce81428497b93514647d1dfcfcd183f7d83ee1f8a0cb8fb8ad86c53921be496ae6363a1211984a5a621d83079abb5fddd860f7db583e14f280fe696eb7fe7c12aa9b6d1a085cf35aa85f3fab21dfb08dd5d92885356fc68b3c8ba8ffea16f45a45dfc7c0f5048f8defb2818f32e8f396bf647469532ee16a1d421702d1065c8adfa5c90f047c47b6f2766506f9e2329597b316af32056674c9db8c982b449e59afd65c11583b551b7ee235e837ed9f415a2dc17fb2e7ee2cb09a70d2b83a672a6ae3bea6c2b8ef87034b911adf8c5854e199e1ee91b94bf10677fb5c87dd898d469f80cc7e2f6a7d018464", "0", "b927cd8cac52e583e3f03a3ccefa7b0e7d14064ab20ef868151f2106b68368de11895f143e4b81da18ec4567c82d3599d053df2cbea6f1b7b6b668529b22f5c88680ee3d27dea2b1561e87400c61682e640f0406781c648dd143cec6e7e814eeffb37bc4b8c0093f943227bfaf7697ea8587b093a88376e5abb1d2e00d5db0a2835ce13365f632be1bcbd7bae7f006999224d085300ebadee6960de8f34d36ad1968dc27b2e7ec0efb3a22418fc93e3aaa1aa20d7ff6195c53642cee339fb6dfda347dcd7c572e87f27c938ad8c77867e1baa9930378a5f1cb1f295628dccd02ac6bd45b47ebd785e8d3811a5cf7e7cc05443a0ef0c550bcb7de8ab2c8d27975", .Okay}, + {.Sqrt, "6746113a8f1359852db8d8c9f5004f28f34282588667eaba6fe614160de8ab85f279be8737a6f9f675df542be980d25c29b25287428ebd639ae6c00c1656e261820a26713e3fa6d9dee05782052295666baf11040692b4636e768b3e0edad4ee4b5bd07af1c4fd4342759498561ca82ff45b014187156b264f5c19aef4a065b60cfaf12f8619913dcad74fdaf640c6b4991b38d173e48babd54fb1d415b03d511d66814ac3dab7067a67891bbdd0ed77ff6d7f2e05c08893fd0cb8cb354c248c9399bad174954d97e9ed43180f6e62f5052a1363fc2d2db5998eb138fc3aa19332105e0d337480fa3792ec222654f261973066039e6446c98ebc9aa1a586a7581a537a628cae5d3ea61c937087d1b8e30d56ef05f6fe8bf1b322270a2c64bed3cb646ff4e35de8a0ad604a3bb90ec53191c899a83b7866de53aab413dcfd52dc745e7c73944052688b8e853b17c1903056dc669076b5644141b4d179c984a8819df55817b268926bda9e2de0205d317d02e362a47846ad767bffec28fe8e96b4414efa1db858bc4af55e506c4d8bec1a7804ffeee7bf33587a997c12e8e608cd0cd944dde47a2e5df403c0b25a6d229277045c21e2af627adc71592c0c361074a7cd93397e93e4d36a11740bbc0006e521224c15cd69cd44d8d97edd9da61aaf13f24ee5fe5d5ef573aff068ff73cc2f6da9ec1c8f455ba9fb02bd8d818c72b4", "0", "a2990e00a58f50acc36a1fdf11cfdbf571be3d181424ed41d4db13ddcc8f5fe4a6b797d14c62abc23ab74bccf8c2fc2379e491f24f1cab63482e78dc423e4a4d397cd6c449083bd276d1e9d1d3652f079c866aa8cd868aa119bdacfa5fcbf5b33c322a0412518ccdc2262e910af462b19fcc882be6404b3b26e11cd22d5587790058165d08f83440ffe59271439c5ce6f04a1fcbbe7139bbdb6954c19c3d034fa8a12be65fdeb7099a484e725a1035f460e6fc80403a9166b1b59ad9188428781fe1dd2cb3b7a5ffe7b5b8633e9d7fe3c598f2fc0b9d3c1cd8ebbd90a8c6787232f4036676c2064ff7be4c6b3e2457d6c58d75b93970764e7f009b3666adef34", .Okay}, + {.Sqrt, "77409e2a0396e9e2a69ace443c2647a0abd0a1d64c252735652e55fa2f47e341ee061eb89a0262c42335dc6cdbbe7ba4ee9e148f3c35ba0c7ed911226478b11b7e11124ef1b9a2d712e3d2f757f15aba370164e7e2f9f24e08bd2965fe60c36593d02037e45a1150517afa9aed3e374804e2d093ddbf7a51f3d0f7b612644f275c167753502100e4d17a9f0a7f73a8f4766aac3bcf15db4d458cf4c396655bfec603dc702c5b563013bbc0e2d3534ff46c4369b7de8816b163c6f1a028d1431c702f3b5d6032c8dae04e5141b6570d8bde0ad01e8fc71ab042348a314420910096a3656915f56e151b6d6402fd56c90f7ce111f91b69fbf0afdbe755fd52ea8a5d43f731f1f63011e60144a59047c78d97add7aa5b41ae58af27420e1d8ba930166a7538a543d8c4dc68b3c214df190ec9f9e0cc2e04e5393596587737ba03d06f5b903fb48c5de9bd18e0e799e7b125a70d55b102fa9240a927e44e624eb6c459b2085c6ed82add83990ee3133755f2e070ff4d355ec12111603acbb5a5c4f839d78b821a6225816a55b96d0b097147dc68254d4d87722fac7e3c9e42007c91a6be3b6296d248848b946cdc5b6fe6d2b21e6c2dfb8e6de5216a9ef2e5feaa653994d83de8c7e312213540a1beff984e09e2dec16b0fc12d9eedf374b1bb60e62d5901c975c412d9cd0c4c27ea4ecdd5f3ed97689529397e79a11c0f0a40bd60", "0", "aeb972a1346dbba550c3b818d785cba93ddca25fdf1593e06a273818342441d2af1d557550e3f81b1bbea29d07f5000d6f13b1801cc9ce2fb9f4f37870b455afcd73b83372d24a652a565cccfc2f6f2e896f9f8a06ae30035d26f1609517aa3f5069b2f6a50d89154375443f73c3452c30864f60108ac0006dd179803da1d73e9e61abb4b28fb29ea0651555d00c027184440340f3245906028dfc8e212c67bdddbae57f9950463488c456835eb672944770dcfa56b3b6148f1629018ef815974aa5cbca54ebb4830d42c6fd341ce72b0c3fb0ec9feeaf856129b38aa1879ab219a094d5cc2bbd2feaa27d47bf44d3ddabe73de388025ac7188c7628124aac10", .Okay}, + {.Sqrt, "e9cea52a5564368d234ba4402c9ad10cbf8afdd1cadf35322370caad834eac79d8e23acdf5d9f573ee903189241c61efaceea5ce2df9ec238b833cba284e0367ee2f090fa7d1b79b9a8912e625cfd5522f96e1b7bdd07a3a6200ed588243f95125b44aed37b40c19bf834f4e217a32a9b95d3177ad0ca1d0307bb201ecbdbcde8f3bb1ca3ea14ba2cf80296906379192d1125d252be772838516b87a78f924ff2da8edd98da0a0e8403bde56e7b9d3d315042c957e85c5175e17e1cf628830ff03e4eba8b7a35d40bb1e1a18d28766d7c7372c1474da418dc94485e456730dc594f7849ed4a46c839e291d628ab5c70d3ef57bb53e7be17f8b4cc4f0e8bf739adfd83a2f0586931b33738b54893d263fb51fd4f4dabe372704049a5efb3c0d41fa1d18ac978ffdadb559cfea0880e8f2583c608a549835a24766373686384d67cdde6d7fb3aa6719f8db8dd9147fcd452b0c6677cf07552a2ae3bc12261cc3113f85d3c7d0a205e0a6b85e826e0d2a1f022bbb2c0336b8a24256394ffee76889a383019c1e4106af45873a567f33a4c0158859a456ad92045708b4597f030b5f35983d3408eecbbd4a19e1018c828e9255435c1cb9cb3f97cd5274108497d1a0855b792ed60dca17c2d98940bc0065b2dcfbd6ee6b63dee096589f933ad10fd4a99a3a3cc96855783c1e85a050ea2042f33f2803c667697ecc112aef3d9618b5", "0", "f4a6ef6002a5f6bf9d26cf62916406ee7bcf70c24e48989a5361674eb45b7f318dea8f21c804b059f14103e7d6557712ec3e8497ad73b9f5a48fa6953e51cb00fb2679b12db5e46296f61d6b65525b75236c0b541729b2625e679dd42d753dca5ba6e6f7d7329555fe105c9e35eec2a6ebf31ceef41b48adfe76551c5efaace00f94a0563f7ca5fbe7ef17da517d1a6619d6f800007f5dfa4bc126723678bf633f4ef72b4023139c3fc543ea2f76079259744be0b91af90da94c47856100efb15b06cf0d3630a5abbd728ff2d3e899e26457f0c56f42647e05f9b452e84e6cba9f079070ace36bdccf62977987e0d9e30ce3e1e0eed60229d135a97a139dfec8", .Okay}, + {.Sqrt, "77e12f0499c8ffd06031af239eddab98c983ccc9d9028682df2e303d3f4478115edf6a21d28dc0b1d2ac1da9350400b822943680f50eec8ede96c376ffc4e4ad22fab7a64aeb1080b2da2f2c995c9466d31b871f7336ed59324aa9dbd28acded4b710c442aed10747b5999396d6560d8c9a65180b08e159611176c19c51bd374f22e6ad8531237e4bafe91e99b725328d54cfb7779e1cacbbf0a3ea57986d0cdc11e0c324f8d918263e2499004ac2c05fee0734b5cf537445a1514a63200c11ddc30fa51403ea856a3ce9909481ea4798d3e46d693f31b59b6587c3606b0f41be2794ea7302d45c15a4d4513c062bb284ac17c3b03f80e1d9b8d81ff04cd6d1673436f12a4d256ed17a51578d536c3aa9815966144a2aaf7005ffdc63736872ebf692a326370d6f28cc81d253a4e7a098b1ad3d57ccc9f3deec1390ff15c3d1bd30b2725ef11f91e6091c08111f36d85a3b34f8307782883359bea46d3a33f28a14ff535a3c4cea5d8022fcd26b3dd51f0876e9c55b7eb640ab6aef84b9454b67c64357371c656dfd55f94ba350f576bb4542dc0f905fda8eddfeac8b5be751289173fcf33839eb55c2390c4ff9b529f5c133cc493a4e4deac4dd128ed5f38306717995a3f2db410bc39d3af7d67e6b849c24ba0d91fa816c4771f7eaf6a1347658d6d6d3e3d93c6b45ef4fdf4545f772ac89661ee61d21e289d8657bc5d09bf", "0", "af2eebd3626f1204ce96720414d2751b98ada94a0336b2fa74f64b2e01ab02404b65f7b7cd9c685eeec70a7b073e63cfa6e8904a92c59b41e3c7b2b2de81e5127f1f1c844e501b64d55a7ffa1f3715a3b712fc4deaff53454a2c578de0dbfd9ade1beb7bf10c3457722d81867593ae6d90aa54833b3f60bed141fd103a93ab17ae74401914add1da037570537dd37ab50f310813b50d3aa964b7737cbb4a646ae225b7cb26344ec8bf96acd4747fcc0a8547e9e99243e9b78820aef14714cc488e8b2327cb6cdd5bd096935fabbe6dbb43662e512992508f2c1bf3bb98953807c55ea75cd3d6486c5b2497e31bd1549d368632c5965d62d53abf1be83938c72c", .Okay}, + {.Sqrt, "3c60519b9ec7d52446b3154b7f898f71db95db439ec1fc8e3b7b514f1eadbb7065e7dd36b2120ab78ab121b8727631d846effd2682423afc8a1275c3c67255283132dc81d41b5af9012a630a6a6b911991c1d3016fb1da55efce56471f7c4c2d30b3731d09993dc85e77e89e6650a640dfb0903cd1d0bd7511d1c011871c499c1c0c46a25a4863e2fc116a56f958847539f0acc13a8cc80e6029c461d1dfbeb5430653d7bfd1fff1ccd83fb06da3a906f6e57cdf03e2e2e2a06939f651bb99d5e7adc32d7c04c71ee1efcb5a7b447566833054bc5c29835cfeb8d00c2c244a4bbce7cf33498a9206eaa7737fbc5f7b21287c62b34d4a79258da687648634ed50efe4c6fd313e0812ccf154890b75bfaad65ccec9dbff2141ba24b1296d5ea4503742168ccf9e100e02bf16deab93822ab0b740b2859cf12984867286a6f5416c9ffe8bbf348e9565f1903b6a0a4e830762a56b585db17ccfdc7b93b8b27ed982f119cea8cf3502ea0fd815104aed271c165e643b90fe32a97b74533fec523ae961e51d3717e61ae74b1e22b125e11a753d4d3a89d3eb64eec1c74e6f47677e2deaec7a8ac1cd4f8e236dc1b88fdb21c0e508d87264816ad6d9071dc828e89aa7435bc18d69345fdd6d0e640fc48ee7218148c9c6944373447cb24a606205d5d2a5effd955038424ddfbc4408c60ebc315af5b911deeb7d17dc734048443fce1a", "0", "7c52cd3d6a36102cf1b9853db3a82509050973e0fd40fe0eb43dde8acf9e02c86e54016398680ac3b99612f66b399e99955475cf2df87be5636283444dc64e68d28d133cad87e8968acacb9fe53e4cb2d084b5a95930be0167aec035c0f089c0bbfad6bfa5b06fd4ff6b22aaabfec1549ab1367d951e8f9be2c7f99ab9e79fc7c2bf405179bd144e3dd8e00157431da34ba1db6ba11a1e08271961c52156b4a4cbb8ce51ecd7cc7a37c49c4ce3366cac7ef1e3a9e85a2abe511e8a80aaea8396fc5561ed298a804a00f970c2a4b3bba36e77fcf1599d10210aaac4815f44bfcf46f607be6c659189c625d1e2c3de0a3456db6708fc70e7dd7b8d26f2a1aa3b06", .Okay}, + {.Sqrt, "f8dda838987ca93abc90f722b03cd21f00fef66e2d2329dc0516cac84d9eb1462ba4d60d2bb65a470a5676bcb8cd6495a249dd3be5c5559b8cb0d582f6c10ee1d246db155de369477d87e1f6143d49db1f914315ee4a726edcfcc45aeb4d3843b4f3b1f72b78edf992b3591617582a86bbf811f0dc1b26f9ac428d1d78812bc6d270813d0834843a249972531b6918d2545bf55705b44af05de788ac31b9b1e2c21fddb00eda603be923421d67e9c51a317d8333842bd261279c3bc3901f7feb2f35daffc68548d8d94aac216f1b708a3bf668ce8d01691332d4980519935a16b3ef25248788d0f67202caa68bb72f3156de6926478be0c46edb76449c18cfad7b2c764b20b2d95b0ca402557fcf5b8816da5e01de600d4a2e9ccc9945dc1626b1867f6f58d9da495624253e183b204eff43cdcb666221e4ee215ca32e4d08f8b1576920e31ecbd0b1a676f9e2e80bd2aaeabf54110149e4946febf040a224f27e801f4999d582eaf7fec0b576f88caea7666112ff6bfbfa4f25087d17275350b8a6f83b8c884f0c6ea744e0bbf2c88d791de0901c8b0d0bb4d49a3cef15bf73a5e2ee45ffab899638d335b4b097c721e2fa708ec779ffd619f6f87cf2a2468148aa7b5647f58143c25f581a640f35cd561a91e1cd9c3a8b0f3c4d64ec91f8cd7f7c3e46e3ed3ded3758c46158d96aef7f9e602d8f50c6361c2ce39d358258ff", "0", "fc68605670c318dd96ebc293188ddf88bf67df114c7eb90deeb2ebb49d5d350fa269e7de17eac183d419fe05c33b4e2e2c08a03e62a61ad90d087f7499d54bfe013c072f302fdeb343fe6f1e1dd917384863245212be4d7346b991b75524dc743303ae83ce7621c4a8b8680a9b48a0b58f49a7a9860eea43631b0ff324a042e6920a37bc910e091be9059c560a90ccef66250e9ec1cf4e32bc06146570bc10388b49e891dd1b6bc2d6643923464921b4a0a6b0b426f7d6bdd62a413789c2c3b9c209c115ba302338b0a3a9517d3227281c67e4b287950b7eaf61251688030cd9d091e5b3a3c89dc51254e654c71c61e32c4c6268f022a97a1ef0c0b4139cf1e5", .Okay}, + {.Sqrt, "8195dbda3bc64e7029342d8a4ed799c439db4760db6ad2e9fc5cd9d2b2c3e827605da04fc730a0aa390874d8b2f67e99a96e963550ae4d878cf00d73a9ec4011da1435297d2454dbd6562081436d727cbe72c1ab0fdb0b99cae2c2d50c33e20d6a3622e6c760c853410175a7c9f2487813c33e7840104e3fbb8b534398254276d50406807fa51d61d07d0377acb0008df40792ab76f0b9cb5d2b406ca9040ef3016cc678eaa395409b19691faa7a843d8857c6949ae9a13deeb39753b1c0bb11b3e6aef87c2e3a49f65a9ff1b7e4af0713e6a50cf9d745d4d041367eeaf3abc328a43ae9ecb617dcf31c7fc3c31b364e6580372f587c9ea38b35efac197d8bc5f06302f144d23a0ccc06efb8b22c0d6eb13cfbb98a5b4066ff3f666611476b01fd194d614b6450d9a405e5d486028c70e34ddb3220adf05e643f941ddf68b7db09fd2129ee3e1160957251352099236b500c275902141881353d3051dd2c930e8794bc7b544cc9856f390d3b7a2211e352712d418962ab83bb9a9462b30231ad47ab14fd674aad20d4605252fe828fe2a43b1ae4f5301ab351f906308810beb859ebf988aa01f0e3b72c0d83737379c7d56ae804b1ace9ddacc2800175531e71aa7598fe933438a205af72d412284cc1a693cb7b59ad9a3b160adcc981a856f1ce8738b9259b0c9850bc7b063e7889af1f701d01fade80e1abc57aee2b18bbb9", "0", "b6230d6660685c4042ab3bc941fda14795ae04fd10320e9db9035d872771fd8c809d429a10325632571443e57bd2bc84244313699d0b04331ddac04425945d278143ef95be59bbf7c74df21be9809449dbf13f221fc6e26ad52bff12adad41ad87e706d2315d68259d3182ef79a0f076cab12cd53c4e4e505d8fc7e8dfe32ef50c17ba81e4c79a569ab2d0ce4df3bcb3cc9e11a8423cf72979e32229beb6525578cdbbd612ed23eb58c56c9e1c50bb6843a8d9c07b1f75ef1d6eb2d1995d5f097195128d341e23577d0a8de1f34d2ca6cfb1a2642c4b5309a86f6313eb32d9f969c2760accdd28c8988542aad11bb13ea7e6abd4b4c404860779f5f71a54ebb3", .Okay}, + {.Sqrt, "8e4deeab970be188f0c0595a5af2147f3d8430b4b4aca555bbcdaefacfc0bd6ebc3f261203742c9e675ffaad8eef8c062baa0853da342b029489adc85d820e57f8af8710189860f894ef39d00d831d02588146588e70453c242790fd25c1b7ae4e9ffdc594b95510c15e0f40a4205e4a16fb58989e923c290b9ea74065cebacc1637792c643c9a76bf5c30d30449ce3ed2b80b757db1cc7936333a9df8a1b97d97754d5b305eda775d8c372e28cea26308d523ae0fa497335ff9f55aaabbbe4cdff8563cf6bff529a2b79a184fb80fa0a2fc82fc37d4beb97568d203c42578ed01969f480c7408fcec26fd638e09f63b2dc0f777bf0fafdbe946385e7e431614cd373b6536eb91477b52ba7109e8d02db0d2f8348b5b97530a729d66f5d9f67d2508dd2e3daaafe937ccf1ff16751f89c52761032ba0c645655db81472ca59b0050cd13830a4e804235d8cda6730625e264b3e1f9a2950d98878831df9fc258ace84746b3f708e0910a8734f4d14ef7f0bca5325d604e666a7fcffdc265fc9e665525fbe5895ce08ce603335cbc034c31a4bd9e3b25c9fd5b7ee94dab8b44242ca1f50a9922ee646ad113b5ebb8869c67b76c3844a644627a67b82ea7045f206dbc9ed25977cf5861fd767a6849933b9c9a00286305722d426ed61fcfe44481dd8de6e82a7c8794c380627d9abedae6754285eb2f38af636b1866037c5bce3c1", "0", "beddc3bf5998558f0b4b71621c3fa69c366c15c3f9b29172cd61f1995a5302344daec8b758d3a8f6b0cf6bdecab1bf5ef7bc0943227d879265495f58c0becfd5a5693a50a9b728223f18fb212fa353c771504cfefa379c17503d2264592a95ca87257640d3c2a703186fc203e97ec601a9d8681b73701fcab70348f9f18137c8d6813fb525f1f9f8ba568bae60e5137dc31c1da9b099a6fa085850bf3c207ea51f7bbb1768e64714d112bdd19f01517bbffc3d2d71a80d50d49295573980bf454b428e7b869b039a2649b7dc16d8616b5d138b0ccd07b945dc3f7ca0e79d79c9ca3790da06c27df9438e5d871ccc2520df5d871dd20ef37d6cf47e11f79989be", .Okay}, + {.Sqrt, "6e7a927e1f4c609a5b8e816f756630c12b3911f50c9088da53b0313d24f4d282a39b4c4f84cdaff5d78da92ed179ebe6a75d530d269cd3793543268f911f8e74aaa12f05c4fa9fe1b44cb42298346b25633541d5d0a0003a6b617db284575607f3d06461556e8dd5a058ea99d4cf462c62f681c7bb98732c154061b0366d4ea348a5651953df2462340fb9b49dea5a3c2b608cf98c64af1a670d74d2b34d9de6ab1c2f7753dc1168d73bafb1c5b52b412a167812902c5bbcf4d9d848db9276e6fd699db8eac546fec35cc9981d9ceb96bcc3d594d5332beb71a988cdb65aa1c59f02a05a9ee26ef66cf90056965f2759ab570f79f9e57c28b03c8e4e919873868ce85f1a7f28a549dd83d0ac3dfa8396c1e7fea72195a070c7fdbe7abf9ff837bd13aa02c19e17243ead0fa342633bd8ed8d9896c3bc95b312ea9f5350ce675552a1fcef1ff6a892c9c0b80ecbcde36232f5674f71800ed707bc2cd6187b39396e76165b9ffd8cc1a9e8209160272048c4db6ddfe4574c247573eda997460ea225243406c7e3eda6bf1b42a0211075f584446d2b2e1cfc8f540c60258496f64970e8f5eb317f9d36070049a9a4e806328c181cc7f484db58437e42b1f85ecb587c1bcfeeeebf8770ced24e31d4370dfd225ca148de01ef2486b5e9dfe96f06847dc3dc204395114b2c6c11084bdf60a4b4a0f750f9a6948ecfe364dfd9f45739", "0", "a82c9a7450dbc23b49bfc8631682cdbd1027811ee74796de245000b49d6fd402896ef686fde03f6465ad453be16acf74633ecc8f1c3e6b92c5c10af9fe85801799a99418bbc19dcb86948753eda855b446ef3b66785c730eddcb6b6c9f67b7035e861e88a999e126aa04c3c1f815b17415a94e1cad7198228e63f202bb2938e09e4bad6969b6ac08ff06c615f944912f1d6812207064a5f51e8aa950a41fd503ad1112e3b293bde5405b3a94ec9765c1913bfaa9d391bd76ba8f0fffa2be09ab7f58eda37fc327c90ebbc3630ca8e0993aeba556ee778ef520bc2fb5bfc3c627454ce4d91bfd6dd518d8d945dc492d9f01891952c54f07863fb3023f63e34949", .Okay}, + {.Sqrt, "99083a44c5633682023165d59060d546af84cb7e6c4d2d59c303171dcac518ad4fe1dfb77b638d2213a62a02700178fd4a1b0188a9416d86742e95a873efdd1db7b827cf075c14927beff932e89039d80b487a4dc25bafbf925c314bd461cbb0102b3b10fd40dcba45896db57633e78df032b438ee3b4bbef33e475a7eb5191f920d1bb86ff9790ddcd297fe231c907177bbe402c4cb992ec6d3b5cd35e8adffe0446d9043a7be251b2518cde943f2111564fb22b06f076d40a4d7c28ed92a67c2707e3b1928dce2e08e06ed6e4d9e59a1f9824b6e201446c8796331d992961c2bfc7ec65ce75dc80d1b1d9e8915dbb5282dbbf8c13326bd55e47c03b4f552c29758e04a6d4a5f499ac21888f078c3b635bdaf98a7078ed96e7fecfdb468866a2a63c2b45d60b62b4e604ebecabe15da4495231de1b01bbc255ecf0ceee3806fc74974690231dcb1b611c245d965ea6021f1b1c2906bdca50cc215492e9d52daaf41df1c8dcb2897bb12d812bc57d38780d7d106b027883b49c27e18ee4459100fa3f5a4341fd5f1c8dfc059dc234978602e385c788ba0353d69b02dacaf3b2b50347e9c73e901fd5e942f214f8e3f97e609323ba0ae83180cbacaec77d93eb424c9502fba94d59af722e5a6052d6e11aa96a10227a9ac7e702796c2f4cdf9be202e13291b71a3af8d29d9b43eea907cd18efac5a0b870addff0c843a526eb56", "0", "c5ee0afee9384f1d295069cb3d3a4a381ea317f9c9d78f65c68173b0c46ec064c78b2ab0f5f2533a4bf7c77cec92322082928304e59ac692c378fb026c536f1c894fd939f49efb48f60810873f261d164364d47bf76efa3aaae1bfa0d97d31e7558b958b164d1c3b323f98c475e26ce082aed788f521b1ee185de7e23ad48e202321784c19073e77a691e2ffcf5b067ccb9ad726eee695f3d8dfc6613575d82d25bfec1ed53983b4a3a983dce8d20d22f7681047a23f51ef6ee41c453d1f33d2049f80a4b537ee62b0edc8785e7b58b4a52ba989ff65886597500dd6ef2e98fa2182115fed768813e91b7094f8303407b4709705a6b5b04706d43097b8e208f1", .Okay}, + {.Sqrt, "d9d2f6d110ae297f6cc87079c3508381ed02046c7d653a8121a477095f55a94a9d75519fce1ca7a542da3562bb6bc046a7cc3cd6ecb4a9cdf9bfe800b1646eb4275f56e040721de53c44ab67852df3e3b0a0a9ea9ed78c8297b91e876a4b036d33afff83fdcc79c7eb6882d07bc7d7480ce6604900edd1564504eb4c80c1392876379b721e5cdd70dfb1ccbd8eacd2fc84a98838e5fb0a603f6b57a6eea3f05e633467abb3c6ee87026b05713f70b44969b07c613f61f527d8b7de6b0e260d24f3f1e0e05faf9637ab33777ecd7aaefbefe139276eb544ecd0e933671a6356460e01de20b860b11bae8284e930ce72919385900e9fac5bde418941749cad08f72201657f837fec5b074992427128f890c627df4b96e450f004ecf5324783fcbae854cb6a4686a5b062cf0b36f1fc569aae4605c0addd00cada232610b6c70930bf65c512466b9c68c148cd649975519fa61ad357d11e58a8288ed29355369526b3d481b4e5d2cfc0a2452aaab6d0de0bb8bf28674ef9e3013b0792791b31b70564a352b1547f2ba28aee28776fbc40eeb0483a1200de2b1a13ed9fce92b5b81673ea2c8bc5e1067d6ddd23e8285950665b081727c091297132dfd23b7f201711d6bc814dcd3a624739b4d04b3dc76f4e9f989be0d9a0cf6e191405610acfdfb40d9ee2161722485b53c54e5012eb07c85155ab07bab5fc3c6fcbf797d2d9cd9c", "0", "ec244f017dc3b9efc95e2cce607ad51e518e8a2714901e620eb3d67ead73a99271686a50ba73c2f53463214e1d79150a0ba7f4cbbbb09535b1ac1bdbed0a8bfb1114f64181a34c12b976ff3fb91b7d34ed8aa166606faa15e3ec30d60c8cc058b21e5dba15c6e0bad28edc556abb45f55521326041329bc78ffaef3aa3029a3ddbbf4f059489dd81c5acb29252aa362a7b9cd60dad32d255e0e649f566620d659d2f1a084929e52d039b1acf65b2d8e22cb64395c3fca2ea333cd32ff6f0437dea3364a91f29d7fb596b06407d72f602e330a7e088dc83d82f9a4bde29620b2f3c44418a093dc77fd7fcec07f3c40527546cf524d617c6a6984c9681dda8a675", .Okay}, + {.Sqrt, "e966aa827cdab4a5827f308173ca3fd25e05db594a402044fd53ab87c67b5fd8e8963335d155d78aae39052a0b2d5d88138426001c3f14db4b3a34eea4401b29c64fe5988cd9121321857b71a70d8d4ac2271d644397985716975d7f3d22e601e3bda6a191dd98c1d601b5399b57cc743c9f91708ad6fdb6ad2ae567535154b5bcb8b66716d15ede1bdbe6a465fac4c98ddbd002bf049b641f4e0e09b7574ded36005dd4b29b195de61d6a5f750e603dd45ec5d1877f73de791acddf53b5d49789b68d34edbbed026b61913dc300146304d4c67ea93d2500003f55a38f9953e8270f8e552e8d17a52ed66de4491065ddda1d02ceedfbe1355096ea89305b1896f6400455178a68ab45a29d787e4da6e64616b1d57bcad2439871986db2410b341e60e6cd7df7e66ca8f26c56e6a8279035ef19c6e6ac5174c35af4611069cb39101d6b3e59cec1e3ea76dde98c201d088dd092b914dc16bd507136233f5c34ccfe353ab827ac15efeedd6755ac9b51cd540c9635306c90f69ca5ea5c829383e4d7192584fa924f3b05d019dbdc5e2dfb71ffb0baec6d483095777c82c824d1607e620624bf29ce0c19e63a116bcb37e464f30aed1d8b4ef126d9ac66b680b318b73cb47bab2ae082d430338ba6cebfbf5f706f37fb888ccb7f10900559b7a8246ebc65104b261db3f769ab52d58f0be65853b218e3c2641926e1e444e9c7e40e", "0", "f47082a7d17c15aac73633a14c0a4628da159fd582d2efb8832e2c47e05e40b94aa01fbdc6e85749d3ef265f72e7069a5f3aac78bff8cfa2853f1e364197a0cc640a7a0e60d8d8748e17779580d9dee2f7325123458824d5ef4e5b3dbe114ba16167ebd26a93da564e259303c98d3cad756aa287f2a4634de11033c19f296a394efc2279de43c5f8eca3ef6e278fe4ff50597af7ab8418d7a4914cdd23d1c95227de83bbe7653f1109e0f33055b80dceb45fca86a22c1063f2ee5717315a1951c636bd43319a3018fa6929038c5ce2136e2cf8c4d4ced831d7b5f6c99e2623d16c0784811f193dd05ad582353abcc925014c6d55695ff39c2feaa8538d62b8f1", .Okay}, + {.Sqrt, "2de0b41865c986e681471a335b475bf07e0cb1e1abf1d0d513e2afee0fcee49d53df79913dab6f2bbb28567e63f1b57d33dc726ad5103ede8d1f0b87513f85fbb4cc7a7baf7d47f6e0744d14d8f23fde0439c9d82cb8612ca4461447a0ccc1f8aac4ff7e86e26096cd9ccd03e2f50e7d1b6bf7c2f8a9b744c65eb2ba1bf999ac0fd86e492de2f8f65382d8cebaed43487dcb6f2cd39e3c9f9e9a49340bba6505ca48a951a5c6b15f4322279ee827f48b75e081c4a144ba09b8a60fb121ccbf833f38f056ab0d81bc254d5b116f54022f35e0975f57690ad80b1f0c271139b37f44ca0b309fb6f140d36f2c00438380565d0e2c75288b767a3a956fa676c372def7de4586f75c0fad96409286b0666888095ca1adb8b361b4aa6a2dd480d3a53a73a8d71901a8592d9caee6d699ed155d71f248e614ca3e3a1e8a3e26ca260bb07c09e64defe6005e6fd300d32ffa20ab5318df558fda319f91e2c83da529e9942cac95f77e23432577dfb1b2c804b0794be6ba7e1e2f21d643bb3c9f78f90d2db6fe0bd3b2d4fbb4cadd72336e88d6e3dc82ae23673693ddd8775fc9e66bee626ecb65b08147f6009e6b0bdcd8be4d4bb2b28561bdaddc5683929065aa9a84a2a05da66a4ea06f530a50681d5271b86d3834e4c3b4e846b5fc6e171d6fe1fa2a9c2f682d55ea8f40705138747c589c943d4c1b16bc14856fa661de5d86644e50", "0", "6c5f7bd47465175b4f10dbba0064fcd8b8d73aec9960569847706e511023dddde9fed103f157d38d46b528aeaa2f75ba01396cca39706fbcddd1852beb0fc85dfabc00b6bb83c813cef180c02dd89a52bc84ec20bbe5eb364dca7fb9c799370de4010c1077bb98f8495acf25c2f5404786c2fe541c59df82f9605df113b445523d7178038db20b331f4b71039437b2a25729758d4b3682c414dfee8ccdbb603969d982bd261744b64342c57dae19853a77ae5e55245739318bc058137571f87634562aad5279e7b9896d004272b5917cbbf3938313a780afe402a0085b6541c087d3403b9595fd275826fa54a1da1d974b1df24b5d039e503be3ae4a667287f8", .Okay}, + {.Sqrt, "516202258628dcac77f40bf77484819c9c986a31738116e05ae3443ad78d81f6c66744c33911324af4d94204db61129f198998c5f5e90265d363303c1be472e05272bf3268f5e4e7ba9fc754b54c0e533a9c2df5dba420c13c68c9574bc19842e7f6ef3068121e93aa0917fe6235f1f7ed8a58f791dcbc9d246bef2e4e28f7190675d6ad9339b062953d914412197089660430f71dfdc625bada14c4d0fc28ad8fa1867271ab6ec1c7ca70e87c55c7bf056034c806a3b7758941cbddcf2a07110998aa83151759e6e1c14627a06e45f3bf23b7103ced04a573450d2b1505441a2f6b0d18ed37c5e1dd69898d0e5da4c478e48feff9ebd9f9e21780edcab20236f3f5b6ec1401e0a41ffb3e56c901ed5626e7bada09d6008e463622c1e5914a3cc1a1a1cf4927b4d96a596acdeb50aff64a5d58077c8120a26bac15d2a321043a5e0da50533f218058320aad4a89793c2ecd8d03727955e45aeec33c8992b835de52e8d5d1685db082eb5d97795a5fac143b4ad066f11d92d90744ee48e3acb863f14855017862ba48446cbf530fc93de871ea964131217ce7a3cefbb6fc0669e8dbda8ae13f93a8a5bf24ed4abbf73af5d7dfad2aa77dd40913a57e4b09aee1b09afaa87034d7eaa432456e7564a30c3b08c51a97aba7cdd97597f292131e6de705c62f7762cbf1062c111e018d8b24e8e61259a429986b460affb3155019c51", "0", "9057040fca19c6fd6d41a6c287d25518ea5e9614e3df52d111960f18ddc4196f6ead09c14d41a597a6e80fc2f821de7c74aa1106e88ac5566d424a5ba7685350f83cd6f988e612ebff35e9c537c51642997b19ab8e8140af8b852ee1b28e6e50d2cd044718218db1ad86439c5ce2909f4af85255d65514cc259c8ad16c9f36617018b01e7ca3c1934a1f271a3d3a8acfffe03ad667db621fd57182bfebfa7b66d823f0460de9df54eddb4c0b5fe9586df033aa1844f3c6dc3f7d2bd3472aa947ddcab354ed40b8fe1f16877482221095346887ee0128d81b044575b56b821f57386237159be87a17133277b539ce97c446023dd81cea691c9a484ab4629ecb85", .Okay}, + {.Sqrt, "a3e96699f0d0fb60d5cdad02ed0cf3591ef77be296ec79b28e595b6a4d3cd487fa7cfc6c2dc645d405428d8042fb23005c8234c9e2f9e403a86c1ecffcba09d87d406a30892557e190a8e8c9f7ddc29c0d0c17593c4462a7d875ae241cc0e89678cb18740657101c9f9f5b83808140633ab1aac9946dd81cc44ce5f40525d337227e412dfbbd65faa1fd1bcdf49964d0607f30c31292f3cbe118979edef8f13e7c5451de729a04522325a0dd1978ff176a6119a69703123b454abb70559d8596b1484d2757b1aec43872a31f1c37df5e5b16b667ae0388cbb02f01f637272b68ef599fdf091c4e285ff5c279aa44fba59b2a5e738a781f220233fdb0e0754dc567c62fb1a2c273447fdcd9d7c5de8a00dfe4e8e659aadf950e137e267a6892a65eaa5afebc6f386a3a079b63f658a0e1aca55d1c8077694fce4562ebfd3d89caa7d62cd3855b1b3757082897362fd4c42f162e38c1ad2ebd651e717e811d6a092a7850a6cd5c89ca3386361f4bd02658f2e15f62b70487d28c2d5931bddb72cf40118c74d4eb9bc55d861ce9493fa9dd5a567d71d2e37ecffd98b7473fafe9e2e598031d7a60fb3e7ba8a8207355a39f38803cb4c6602d91115e62a036973644da7e156bc1da0c079a37fb931ff568b390c0b8abd00b82413434e9e583fbbcec5604bd8f9d63e3a48822ae04d23f2378ff01842fb653b6fc662aa31c1ab2a638", "0", "ccd84634539da13a07c11b6f1e54c1e79b437c02d525f32053be1fa3f4355b6c418ae921eeb480b491c2c6feb6308d72a4979993ae517c37515cb530113259ca44f8cc076f4e90114b1b55a728b26dc0d891bc68ca8ef2ff1a581a616eaa5172a553ee95369b3c8623578fb1155c65e2dc697937786ea8d5f9dcb1c65fcfd4cf9fa908af8f50b0305ab3b9f1076d77f94677a0b809b5b6ba523a25ce0170a9a2d0f69d4292b38681bff4c5244b5d63fe5195a696db1143f186064a56b19ca64c047cec45e811e44e76ad72f1a12561ed6e0672f84394702ae107aeed5a3e8333dc06e070a0abaee0fd769c132e58c0b618fa637575ecf79d5681a56616027578", .Okay}, + {.Sqrt, "dfb75cd7b0d6e6e95fad91a9d3ebf9ee34671fef11bd0f55fab11d1605e5605676bcc03515b24c3a45bebe51b36305119cf329795fff14222df4857899283156ab74dd2e2425d3026e3fa0fe2aadc7bdfa16263b4db44f50222e085ac981a28bcefb9cd1c48da26637a3d239e5a455ce8e6dcc7ae3961e76b487732b96a87585a3f73c292b228a6ead60bb0432160d0c945fc6ac77046625d68f19a9eebccec295911d4b12158c4e5a83b3283a691dabef40068ec4e9a22a434bf2c5af27883ce12b53287de21b87ac5adcbc3fcb0b924a4cca3301d269d471c510086801ca746750a60790cb1c97fc2a7012995e82e78d7332c8019f7115db4f0bd69932b4f5c79ba3bb8a35f8dc9294435142d10838ad7180e931ac759b5f272d8e714e162d778c223f467698aff16c196404e30756413076c9e4cad2636fcd0008011c7d60554b17a2db387be059037ec9c5ea4b8f642383c5e826b65b72af645dc2e64bd1a55a9ea900c74a777d7d35a6675c800ea9f4f4ed4c7933acd26a6201b0113452944ae7918ba40df4cff3b5cac9b911e423ee9db3b8cbe7bd915427142f3742ef0c84d8cdf08b86aedc0cb93b160bc351f81ef961e1388066ee8cacf219139aa44cd7383dfa38e54973b9b769c20624880cf0188f93dc589d30bcf64516c29fac89e8e2319216bad6e049a066d8a10ddea181a4386e378063f823f7c161f93f06", "0", "ef5079dd5929df5dc9abf3edd8b4f06f210003a7edc2aba9436490e4cede0d94f32710596ae00ece14ac2efdb4a81ca104e86817d953dfc13ae35ba48b07ae95a011c0994d530ed081a32dd868a7f4cfbc1a18afc64d573e317511f86f6deff38b3c63055687092e826a624b3200d8144a0db24abafd059886eb6ad218a45e9e2f29e6ca18752d87cb05e9408112c6285ec4ed1fc66653e494e099964ea30583507e80fceab459f6a5907ad3743307686de8f13a89c6aaa888fb0d44cd408e999d8b3b916137a4fd059bdafe9397a2096f9082e3fcd673d20625ff73bd3af424c813de15678f8387e60f4ff6d81f5184c63c59a1d777ef30fe7ddc27d5b0239a", .Okay}, + {.Sqrt, "93fe21b68242675fbce147bd06e97ce1210cf618841931304af77b8e3b39e1cf5aa98a403b6b7bc11fb6b459b531dffdc60f65f45c2b5a2c82eef5646392f5dc33ec61f9b7a3c8bd9e119bb5f89d5b57fc1d70f2f60c65b6924e6023bf9dab5bbf8d82bc67d49a4db62cf2880486f51b8f06daffad806792a4f2e2c1383b4c62043322e7a1b22e0709d34a5f25dceac820c354dbe0329edd8be6497b9a2fbdd82c8facb632b758796101b233ff692fa343dff2a66ec97b8e5d234f6a6538ae15d023d133e71f4bb434f4ea5a4077f02ff0d2de5ba485fa491c738db703e30cb084de65d3a521bf4ac4faabd4b4a62de18175bb2bac220df9fe1c1f4cb3eccf1c5969e642f173a695d4f566e11a2b7a25ffc3c56a4c43c5fce2103552a29e87eeadbed3c1835cd9b2520d33bc23d30d01b5eaf4f77179ccf779cd63d631c76a78091d9d3993655ef4e77ee297a25a1dcff79f8f1761bf4a0c8a635db92b0a76ac40a50a1825bc56b6c69dfb835c2250d635da51ae0aeae1a646b6be97fbe1b58eae9211d831b9078e7e57a349b80f1833e021c489316926ee20251793cef7a8f39c34dbf920ead5df06ab2453af0b42b52673ca5685b87545608fc7f0e15d965c71866dc947c092afc29e62ecb30d4c7a1a90f210b3697261b8775b4dbecf7fa41d9fe90f00a10229136b3e5bfbbe9f3136fb0a1c01e8b97988be1139931af2e8", "0", "c2a4c3151971ea2c3104ceaa031388db2d85faa46e2d52e523c43d2abc3cffef0f939aea72c5d37ad7650793021f102b4608344d101572a91b3cbc30f29b73c48fed0d67641865274814f675c4187997ed81bb08d6eddde901c54fcbbaf04bd31975abcd5e77c0a1954d63d303e09aa5d33621b4744ac0bb6354a7905b365fbc1f42b5b470a61ade93f9bcf78b6471032a7d141f6491a5457a4a3f84b58fceadc63481744f6f2504c5c3a05b77a6c1b2c5a71f761751996774cbb2b621cc19cb8494c6ce752a6fe157eb3362dbe97b19308ec88c83415dc3a0e21ca57f89651d6ced34ce5b2b0d8a527d689928378243e92e468b8018685553e5f7cc4777f554", .Okay}, + {.Sqrt, "9cbd6b9a8685c0076e3322ec821174a522e3c1b073d79d1a3e0fa3a9748eabf214353bcee63464fd52bc7e700eeb877ba409c9907f63032553123c82c259dd8540f69870adae3332c062d9de133d85b21e55c622be29632b498d63ec4dc8038de2c8c65141a1f6d477412103306e22c84f837a476937de90c3a268b6c2f7a9af908a23160096fc0b97d80be05fdbd0742afbc4a14adb215017b96ed96016057f5beba4042e32fe2563c620c31dc1e8c42aad62e43d39dc72883c649ef595c3eabc09070a41657c0b3759215a44341839292bd2af825ba1a411dae3f78c06eac48202d8d400f7ed4ff7d4afb80c6ee3700a4cc8c267fdb5b08b0d9910a81d480e60043d4e5bf5adb26a99f1665bd500585c993e17ea7504e885e4b566e6c2678c0c5ba31901137741df7bdb2a289283f894e34b448145b35e72653c29fc13bfb99750b48e719392562cdedc9223a77dc25f69f40e3de8639dc69f321e5d982c1bc9eef761b4ec2a596865bc780ae9497607e6b5c5ad0c32018d7d08824e93aa511b604a44c9a7cba1983275264c061bcec6bdc96cff8cef9cc8fdbeeda9389e56fd6af64d0d11023f0daaf45372f70c6a1c30a938e7ba4f3c5a6c2bd8405788128fcdd3e96a38d8bf4c5fe95ef5d74e42dc840d093a97c09d596cce25d2ad907aa5e25e300c4176625d03b591b7044d35b94324a5c8b469cea5658f5a4f07faf9", "0", "c85034c8a2b6feeaf4c2be37d6fbea006ff90674fffeb4ea49eb3363432c219e18a21b666ec32db95e441ac11c4b97781ff8ecd7b32f261223560cb169f8606ad5e58210c3054f790da95626c7a9ac1f684bd1c0a51ca5a9f25a9292dff203c79f3776431a9c2caceb7dc13f6458e53f7127b517e55a31f631bae9d81b40ad4b0a9af411106214bb0f522c7dee2827941ce647fd40649e86ff59cc7f479b4d349598c113e8eb1a92df782fa855562cd08d782219789f83015a49039263fdbc6bc57c63c35fc0f4322a51a601b2c4905759b37e65415a81dbe524d2d6b945f7b0a5db6edbd659e3b7fe93ceab91dff29b125ef96dec7a3b03011e89eeb21988d4", .Okay}, + {.Sqrt, "1b3d91a254e3e4a873b20b84cf293e3040fce56740953096b6efc1c6c004eb505b1ce7448d4e726bdca6627781f9c541c87f7505773594fe3f8c4acd7ca4d6ec09339a14240afc455ad8b8ecd47bfc0b08f2e23fc63987c42399f62ea4e5edd540aa1beed5443a97fab4f2ff113dc6fe2c860a2bd4a10cc18a91cef0ad11cbe47288c8224af4a49d5a413466062850d9e47b7f9380da2fb6cecd188200fd7bee779859234788f0fd201e1d0203db4099fc9613187ea3a78e6e5c1690f2490806165039d662835c3b72ab2aea1072c82eab64483f714203d249ae99d4e7bafd9127d8b69dc57a70add62d9b676fb8bf11bd04f6d0556e750e3ff6f66de4089b52c0c4a1216296b142840d97612f271ac5c3cef995fac98629f2cc9322fcd7656841c4af63b580978d42af991fab8abb97245e345c6ca064c1cfea514195023ea04179451bacf5f8f8ef0ee41dc267cc08772250c775aabba4ddc3d42921d91b28b90b73773478b0ad021337219ad9651004701d30172f2e53371957b90a8cc7b48d2e44a6d4e02736cd90c1093f125f9e843eb9a9db7e267997bb72b8d1319c98abdd2855a12cf3ca83121623e993d9585c4f6a4b5a95bbcbbbf71cc9a397c07aa36d8fc0cad3e81d87b35dfeeb017bfd608df68af247de4f67a91789ab480c782a91fde3aa4567ac288a4805b36cef9b33dec5673c9d262d1b92beded5bdcf64", "0", "5382058bdf2be8bf99de16ea54e821a8a3de74bb9dee0cafdf8820967ca217228319cae4cb58279ee3e6361890f9a1d0e54b94cf1cf3833aad7467b78d804867108263fd4707391aa23240d74bf1cf8171f47a7acb690070fe3a5d3dc7b376b461cd6f841bc1590f226825bfa82b03062f03b84eb195ca9e3082bd0a654dd8c5025c22a8f4163a095889f379bfd84cd4cf35cf7fe38b9fe5c1dbeb5c2241c53575b4ac0da2fe55034e043dfdf31d904f85d2c16876fbcc07923035ceb96f4ef85a770e657663ae979a92c6ed949762bcfc974c93f75af26555d6a793962c1bfb5a579a92e15f38cd60a0dd58f5cc0d503495faa69df87f6362f32b563ec92fc9", .Okay}, + {.Shl, "521743bab8c45885a4cdfeeaa0556273298a3ad334e35709d84cf11f8fe1cf57f0e142ecb555450fadd4c6ad616ea0b828ff0f6581ca1eb22baf9006c66b8a8a2a9996247f2ffa1067d8ac1d4e5707211037e5a2ef86c304ae243b901c8e6d7c9af93b29f038646201151016f2611f1c8497027a7ba23bb312375a104ce084e5440d097f42bbb8108b49b8107c670dd856910199fa58026e644635883b3a1759d8aaf50fd41f2fe03adfa6d75a534eb223fd9e030f64feb19f140e6131f5dcd6d912af36299426bc0a8f9c152ae87cb1fe9a0456a8a33d6beafb121eff6bcde6e9c6172cf6070953f833ab4fb7db901ebddcb3c38746c7c21b78b79443eaad97edd560ba587d509c6eb9796928c7053408633c3f788142d82e7e4083be85f16646764979710f238c56d5bdd9a08c031a04670e8904812ff54e3b0f463746213f48e04f39e1ff468d12d8e999d9ecb8d94f05ab3c85f40a0039e48e8ed1e95475fc345e29606434abecc40f59ad0e255c956e6a5161be091de4fb10fb961d94f98033e2dedbdc512fd10ca674e936b0f26e9a05ce10ea24120377d7b994bf08be59d3b8d9278f07864e0e5ae5c392d5495fe9a598340e301ff0926453504d2f5e03ccac7870162bf1d58adb40e5b9f36f859b37b6bcb36d8cba32d52f84bd064090118ceef9c594002dc36ea42b586cd4b2047978ef21f7c8e3d81d8fa96efbac", "12c", "521743bab8c45885a4cdfeeaa0556273298a3ad334e35709d84cf11f8fe1cf57f0e142ecb555450fadd4c6ad616ea0b828ff0f6581ca1eb22baf9006c66b8a8a2a9996247f2ffa1067d8ac1d4e5707211037e5a2ef86c304ae243b901c8e6d7c9af93b29f038646201151016f2611f1c8497027a7ba23bb312375a104ce084e5440d097f42bbb8108b49b8107c670dd856910199fa58026e644635883b3a1759d8aaf50fd41f2fe03adfa6d75a534eb223fd9e030f64feb19f140e6131f5dcd6d912af36299426bc0a8f9c152ae87cb1fe9a0456a8a33d6beafb121eff6bcde6e9c6172cf6070953f833ab4fb7db901ebddcb3c38746c7c21b78b79443eaad97edd560ba587d509c6eb9796928c7053408633c3f788142d82e7e4083be85f16646764979710f238c56d5bdd9a08c031a04670e8904812ff54e3b0f463746213f48e04f39e1ff468d12d8e999d9ecb8d94f05ab3c85f40a0039e48e8ed1e95475fc345e29606434abecc40f59ad0e255c956e6a5161be091de4fb10fb961d94f98033e2dedbdc512fd10ca674e936b0f26e9a05ce10ea24120377d7b994bf08be59d3b8d9278f07864e0e5ae5c392d5495fe9a598340e301ff0926453504d2f5e03ccac7870162bf1d58adb40e5b9f36f859b37b6bcb36d8cba32d52f84bd064090118ceef9c594002dc36ea42b586cd4b2047978ef21f7c8e3d81d8fa96efbac000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-40df4d8e99f4c7075cc8cb3aa04ded5473ef1dc3982e7ab8789929dc680ebe107b818ec57e00d7a6edee3b65beea8ed02448c789453cb3583ec80ca387ecbc3b8cfd3c0da7a156c41acbf6c7098b2b04801b5879e92775802926803d2394d644fc05c49a79462adb93f76ee76d2ed2ae4591750608efc69e34e4c4eb21ecd5f05d5448f39d152f03217187c5ded64e8f3126d33d70ad906671f29be31f56ba33f63e5f929ac9a0eb5f67b6bb23aaff6b2fd246d93b3e20207a7a401d36f80e33cbc1f0b39258994c20f176e24c50e1441616f022de6be4b9d4e8d350e8a7814842e010f8636cc443c3928a52972f3ffa3c24b9a20fb9d6c72ca36ac9329f84da9ccc04b8d789a9220577542a3f85f43c34d01848ecff412674c22562949de006751eaebe141717ae85e739ad38c6fea1ad42bf04a5d0a5ed8747c6e52ac088b0347cd7ba2e7cfb6419f4169084d6eb1cd0a99357784e526d552fbcc9626d995b38c33050828925d8e4ad43ec71916d3f0428dd9593ec3298a1f8244f1bfecd4bf9748f583e98eed1c8a4e6000f8393590ba19e0104141725303e71e13a1489e6489623fcadf7baee06a4a7c4fde976d11fef4cd36205c920b85b3dfdc515928873d563504a9bd9136446a716dfdc0f6bd63388b2cf15176194926641af9cf3af70aeb3b724cb738d98327a6daa5fa13513c26be869a847df6cfe0fc71d78e050", "21c", "-40df4d8e99f4c7075cc8cb3aa04ded5473ef1dc3982e7ab8789929dc680ebe107b818ec57e00d7a6edee3b65beea8ed02448c789453cb3583ec80ca387ecbc3b8cfd3c0da7a156c41acbf6c7098b2b04801b5879e92775802926803d2394d644fc05c49a79462adb93f76ee76d2ed2ae4591750608efc69e34e4c4eb21ecd5f05d5448f39d152f03217187c5ded64e8f3126d33d70ad906671f29be31f56ba33f63e5f929ac9a0eb5f67b6bb23aaff6b2fd246d93b3e20207a7a401d36f80e33cbc1f0b39258994c20f176e24c50e1441616f022de6be4b9d4e8d350e8a7814842e010f8636cc443c3928a52972f3ffa3c24b9a20fb9d6c72ca36ac9329f84da9ccc04b8d789a9220577542a3f85f43c34d01848ecff412674c22562949de006751eaebe141717ae85e739ad38c6fea1ad42bf04a5d0a5ed8747c6e52ac088b0347cd7ba2e7cfb6419f4169084d6eb1cd0a99357784e526d552fbcc9626d995b38c33050828925d8e4ad43ec71916d3f0428dd9593ec3298a1f8244f1bfecd4bf9748f583e98eed1c8a4e6000f8393590ba19e0104141725303e71e13a1489e6489623fcadf7baee06a4a7c4fde976d11fef4cd36205c920b85b3dfdc515928873d563504a9bd9136446a716dfdc0f6bd63388b2cf15176194926641af9cf3af70aeb3b724cb738d98327a6daa5fa13513c26be869a847df6cfe0fc71d78e050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-20136d760352f1c55186495dbab35164d757886fc16db04cc995179c5db5bd8cd16ee87fa9d580d1d2117b3d6a96bf359f655b4feb14fb2f264ce88420f292d8187f9cab4bc67b5a134be2d47f56d0acf315f2bc28beb6eef8553f924e6e96be1c8ef2dc2a335bd4cea39f27db584b462b99b6b77b0b5d07c9cee5e89437545af2e997a9a579bc24a3fec36c69df1cf87f849f853896e95ae45f48a4e4a724e3344b32e47e60c8be1c24a7ae23cdd714e95088157e23167a12cf2c69a4d2ea2a4ba7740e0b6783883d031d75bdaec56e9b98c09dbea105448b874ba3d209838886931c203ca3f9c83b85255b5ccae7c177d52a5f46f5cc150f46ea56e1a373bdd694df4c506c514926d0659c3eb56124ca657f9334fc35c5d1821230499ff8ebca91a1fffbf5c7da17db59b863ddec994f0b09dd6339807482f9b00c92c57a5933703095767c2415b2522ca298a94bafd965c820f114fc5ea895703b574f2ef6ee2b7533c5f44b46b348c9bfd3ccaf4558d9caff41757ba57ed8970b9ba3d2527a76422e92f03b4134eadacd29a1c7898e4e3d134d8f3fa813ff724db96dd50c40a71381e3db8cefe42cfef37f9eaa915320ecf94449343234a060c8517d290897f5b6c00c9343f1c3187b7fefd2752a0ce6fd45f3962a7940cb4ed41715fbb4237e6cbdc3c90e3e32da0deda21c0af3912d7e59d8ff37119fe8f861fd54e482", "168", "-20136d760352f1c55186495dbab35164d757886fc16db04cc995179c5db5bd8cd16ee87fa9d580d1d2117b3d6a96bf359f655b4feb14fb2f264ce88420f292d8187f9cab4bc67b5a134be2d47f56d0acf315f2bc28beb6eef8553f924e6e96be1c8ef2dc2a335bd4cea39f27db584b462b99b6b77b0b5d07c9cee5e89437545af2e997a9a579bc24a3fec36c69df1cf87f849f853896e95ae45f48a4e4a724e3344b32e47e60c8be1c24a7ae23cdd714e95088157e23167a12cf2c69a4d2ea2a4ba7740e0b6783883d031d75bdaec56e9b98c09dbea105448b874ba3d209838886931c203ca3f9c83b85255b5ccae7c177d52a5f46f5cc150f46ea56e1a373bdd694df4c506c514926d0659c3eb56124ca657f9334fc35c5d1821230499ff8ebca91a1fffbf5c7da17db59b863ddec994f0b09dd6339807482f9b00c92c57a5933703095767c2415b2522ca298a94bafd965c820f114fc5ea895703b574f2ef6ee2b7533c5f44b46b348c9bfd3ccaf4558d9caff41757ba57ed8970b9ba3d2527a76422e92f03b4134eadacd29a1c7898e4e3d134d8f3fa813ff724db96dd50c40a71381e3db8cefe42cfef37f9eaa915320ecf94449343234a060c8517d290897f5b6c00c9343f1c3187b7fefd2752a0ce6fd45f3962a7940cb4ed41715fbb4237e6cbdc3c90e3e32da0deda21c0af3912d7e59d8ff37119fe8f861fd54e482000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "6346c48e0d0bbc2148c48dc3c7f0bf48b87412fab948f0b0a89dc87b67b4c14a05a3cd737ecad23b7e8b1a011d4c38cb5c51bdf3a1eca03004c149f09c5d63ea63690656aad97002fac1d3589bc81d535a49a7719f5d2c73582c8b5b2358efdd2033d16775e8ab1bb72541dcc38b4ee2ada25a6c759e50eac987cdffffa7b7c9d651475bf26337433a5f32d5b9ac7513f7e2105df999517b3ff00bcae9bd130f704cb6625eb4ac3441ab5fb9cd91bbc1177d9502998a31b05c0105ed13c901a582cb5a474b7d0c3a4e9bef612366ced058b7e5d437662a618161dce667ded6d242478dc07ef7160f4f4e6a34e1ded2ff39940142e49f4e400de424867f6202eb99cb911bc3ae272b04bf40aceff290f22a33665474c4f0d42779f9baaaa01a4c9c28c38d16a827fc81b094245a674bcfbb8d77473730d3639c03328f2d883d4e29fd74dd85bab8d117b36b039d6f7ede67b15db9b9dc21a9119b38801126ab4a545af45d9e53425c1fe11ac61be0992f0f1855f1ecf0af2e43932b7dd45ad9b72a65621e504db3e5f586cf7cc22a798e9192048db004192048cf29bbd8de1e17545c070948444a367ccd54274b9a0c2330c1f10527065b5f88d058c304424190242338dae8c01255c2ca5f5b2c77cf57594d4c1dc54c2f3f2208c248c3ae0a4e682fe4d2b87890b6d888f0976146881f5e3746e4c702cf8069e1748c1838783f", "1e0", "6346c48e0d0bbc2148c48dc3c7f0bf48b87412fab948f0b0a89dc87b67b4c14a05a3cd737ecad23b7e8b1a011d4c38cb5c51bdf3a1eca03004c149f09c5d63ea63690656aad97002fac1d3589bc81d535a49a7719f5d2c73582c8b5b2358efdd2033d16775e8ab1bb72541dcc38b4ee2ada25a6c759e50eac987cdffffa7b7c9d651475bf26337433a5f32d5b9ac7513f7e2105df999517b3ff00bcae9bd130f704cb6625eb4ac3441ab5fb9cd91bbc1177d9502998a31b05c0105ed13c901a582cb5a474b7d0c3a4e9bef612366ced058b7e5d437662a618161dce667ded6d242478dc07ef7160f4f4e6a34e1ded2ff39940142e49f4e400de424867f6202eb99cb911bc3ae272b04bf40aceff290f22a33665474c4f0d42779f9baaaa01a4c9c28c38d16a827fc81b094245a674bcfbb8d77473730d3639c03328f2d883d4e29fd74dd85bab8d117b36b039d6f7ede67b15db9b9dc21a9119b38801126ab4a545af45d9e53425c1fe11ac61be0992f0f1855f1ecf0af2e43932b7dd45ad9b72a65621e504db3e5f586cf7cc22a798e9192048db004192048cf29bbd8de1e17545c070948444a367ccd54274b9a0c2330c1f10527065b5f88d058c304424190242338dae8c01255c2ca5f5b2c77cf57594d4c1dc54c2f3f2208c248c3ae0a4e682fe4d2b87890b6d888f0976146881f5e3746e4c702cf8069e1748c1838783f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-58e4573446a0277955433351cc1a2b0e2ac9b00d1eb98cbe4c40e1c8a62a77b824a27b332b569f1f3621869d986f0eb92c9c2617836508d3f95baf87e3d0cffb75c7aca285cad0105178973a69c93ec4a5b425f314aadd7b3e1c8e9a454659f466007aa0a649b71d45e63974a7ea86f0ba530aaa30145b2a6ecc5773381f61948547a075987913ac93e9c9b7e27719d00acf2caa241b655b19e45667d5c15cb99219baa5cb2df4dd5cc11717d1926157abc4dcb044bc9db5bc53a1e1098d75bcc7996545974102847e68ce244cf430f96c817359bc7623bfed3d59d4d55992f1cec388673b9929b07472dba0ac24521830ff93aeb87ca670c161adc95e72e80a618359667649ed51996b8902376ae1e4645095579caefdac5afaa8af0ce825f5d4b64a2b58d336071a30121990a979fde1447d753dbdd9d28c94eec41352b3e9714b6dd436d0fbf8ba49829c3e1b74d96fdaaeaee380ba0cd3c65e0ea98d7befdf4302789596674ea6bc497bad74d91018f79741f244cb8397319db67f7284ac85643bfb7a9243a35d47911701dd32af14dbaaee84286b207fa877a018527540f5937fe42b459c45c7548e0f52cf7d252729cdb2e0b7791d74d875c4cc07f2d43bc0f10aa3ca54a1e7803dcb84c8e627ea3ea9fafcb60a7d571d9cf30890b4cbe5c7d73fc31923dcab4e0860eb35d5e60177e1d413a091df294166fb7ea8d0ec", "1a4", "-58e4573446a0277955433351cc1a2b0e2ac9b00d1eb98cbe4c40e1c8a62a77b824a27b332b569f1f3621869d986f0eb92c9c2617836508d3f95baf87e3d0cffb75c7aca285cad0105178973a69c93ec4a5b425f314aadd7b3e1c8e9a454659f466007aa0a649b71d45e63974a7ea86f0ba530aaa30145b2a6ecc5773381f61948547a075987913ac93e9c9b7e27719d00acf2caa241b655b19e45667d5c15cb99219baa5cb2df4dd5cc11717d1926157abc4dcb044bc9db5bc53a1e1098d75bcc7996545974102847e68ce244cf430f96c817359bc7623bfed3d59d4d55992f1cec388673b9929b07472dba0ac24521830ff93aeb87ca670c161adc95e72e80a618359667649ed51996b8902376ae1e4645095579caefdac5afaa8af0ce825f5d4b64a2b58d336071a30121990a979fde1447d753dbdd9d28c94eec41352b3e9714b6dd436d0fbf8ba49829c3e1b74d96fdaaeaee380ba0cd3c65e0ea98d7befdf4302789596674ea6bc497bad74d91018f79741f244cb8397319db67f7284ac85643bfb7a9243a35d47911701dd32af14dbaaee84286b207fa877a018527540f5937fe42b459c45c7548e0f52cf7d252729cdb2e0b7791d74d875c4cc07f2d43bc0f10aa3ca54a1e7803dcb84c8e627ea3ea9fafcb60a7d571d9cf30890b4cbe5c7d73fc31923dcab4e0860eb35d5e60177e1d413a091df294166fb7ea8d0ec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "404eb15f55912e856ae5778ef74696d9ec39e83f8596457136de5cbdf323540b5a3bdeb5bbec7d00c0f803d9db49c941b167b3afed663a78b5ffdec9a86f5f97d5b03d6529aaea37774470d1a3cfaa89092c3765f827bcf81127890bb40d115913cc2e3d86f761779b59adfe4cfe71fbc04062c6aa12351d80f32d54cff45e0a3da64b3fe0235fc0db28696bdf5b3079816142dcdd664a1e7c98b095c350f08f234dc7aa627e31e4dafbb66758d331e4f79cac1009dfad584cce17859d48e9be3dc4883db4ee0e7d81e777793001363b4183d6f3033e0ff24bbaf2269769685eefa99d0076befbc51f7eb2aa6a6c5dac2f2b424894f64f65b321ed295ce32e5e0c6b5687b2a3ea143dc5a0309c35d2805d76817d798c24c8994017f314cb06ca816493be515f1509d0b9d1781c0536c4554cc475cf2d1d4981f0d81827526850aaa0aeaa98fb622381e05626de68c58b01cc9be4229141d20e551e1c59ee16c0f9aa4d0e65661153e5f09f6ff0efe3fa621e67c8d3e9c5f44c89b17c72f4533aa94966f7b4eebe41be25c6a6ab7d9be85710cd016efb95e345ac7edef53b9c613cafb4c120e10c51cc7e0aeabe1aae508aab545801d893c584e886dda3823e473996a44665b87dd35029e9531dc88ab3c4891821c1334610f28474e41d74593355360a84bb86f903a8d98f14c11af97c461d0182e854708ceef6ebcec6ab8a74", "1a4", "404eb15f55912e856ae5778ef74696d9ec39e83f8596457136de5cbdf323540b5a3bdeb5bbec7d00c0f803d9db49c941b167b3afed663a78b5ffdec9a86f5f97d5b03d6529aaea37774470d1a3cfaa89092c3765f827bcf81127890bb40d115913cc2e3d86f761779b59adfe4cfe71fbc04062c6aa12351d80f32d54cff45e0a3da64b3fe0235fc0db28696bdf5b3079816142dcdd664a1e7c98b095c350f08f234dc7aa627e31e4dafbb66758d331e4f79cac1009dfad584cce17859d48e9be3dc4883db4ee0e7d81e777793001363b4183d6f3033e0ff24bbaf2269769685eefa99d0076befbc51f7eb2aa6a6c5dac2f2b424894f64f65b321ed295ce32e5e0c6b5687b2a3ea143dc5a0309c35d2805d76817d798c24c8994017f314cb06ca816493be515f1509d0b9d1781c0536c4554cc475cf2d1d4981f0d81827526850aaa0aeaa98fb622381e05626de68c58b01cc9be4229141d20e551e1c59ee16c0f9aa4d0e65661153e5f09f6ff0efe3fa621e67c8d3e9c5f44c89b17c72f4533aa94966f7b4eebe41be25c6a6ab7d9be85710cd016efb95e345ac7edef53b9c613cafb4c120e10c51cc7e0aeabe1aae508aab545801d893c584e886dda3823e473996a44665b87dd35029e9531dc88ab3c4891821c1334610f28474e41d74593355360a84bb86f903a8d98f14c11af97c461d0182e854708ceef6ebcec6ab8a74000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "fc7145e08d0989e75905d1747f3faaaf304261c69ac3f55b4ee5dd6134b893b35d0c808ff68cba947b39f34b269540c372ef7f77015868ef03e3acfcab1134eeb56fb11151df2261df26e8bf311200a4b1ff8780081dc5ad8a2ce7db28426b1352a41f0e910efd4d2b3017144b13f5dead67c11c900b68d6d614e290d3c5e2da170f975e712fae17c348ca2f6e16ba88311a493d1a32ea6ca4c4a3c5ac5bfb148f9b3a8d0cd692220fc8e8278ac6070ba9c39205bdeaa647b3eb5f88fb9961c173264e683b217c11a954ed56b3e440f58d2486504a2b623a39fea812fb0c1907679f0e8772e614cbeb8a29accd3f934f3575b1b1d241479aaac132124f3fb8573e3d935291283df7ea5502fd3b9082848ad827a614f6602ad6f84fe87377070a0a7d13b8d5fe85df1e64c46bd310d38852633b9dab9425f2d63e12f70c641308b97e162a6ae1bab5e5f385a46e479de4958622e032ccbd3429c509e568092445a6e4c08549cb618f13345b5dc44164a34361ec7355a24cb7b467d929ce6f33e1bf752340b08baf0353b532999cf9c56507d1c91df859d16543b431b47ba2c4b33697b3316d0971423c04ef671ceefec1be97d5fad67cca54cb6790e8156fd0c6d5d04b2dda0ce0f89633ffd38e07cb88606d922d43e5335d640d4fd0eade9e54ea759825eb4172df39d6c36878fccd5ab620924ca2f793e11d950913a441ce20", "3c", "fc7145e08d0989e75905d1747f3faaaf304261c69ac3f55b4ee5dd6134b893b35d0c808ff68cba947b39f34b269540c372ef7f77015868ef03e3acfcab1134eeb56fb11151df2261df26e8bf311200a4b1ff8780081dc5ad8a2ce7db28426b1352a41f0e910efd4d2b3017144b13f5dead67c11c900b68d6d614e290d3c5e2da170f975e712fae17c348ca2f6e16ba88311a493d1a32ea6ca4c4a3c5ac5bfb148f9b3a8d0cd692220fc8e8278ac6070ba9c39205bdeaa647b3eb5f88fb9961c173264e683b217c11a954ed56b3e440f58d2486504a2b623a39fea812fb0c1907679f0e8772e614cbeb8a29accd3f934f3575b1b1d241479aaac132124f3fb8573e3d935291283df7ea5502fd3b9082848ad827a614f6602ad6f84fe87377070a0a7d13b8d5fe85df1e64c46bd310d38852633b9dab9425f2d63e12f70c641308b97e162a6ae1bab5e5f385a46e479de4958622e032ccbd3429c509e568092445a6e4c08549cb618f13345b5dc44164a34361ec7355a24cb7b467d929ce6f33e1bf752340b08baf0353b532999cf9c56507d1c91df859d16543b431b47ba2c4b33697b3316d0971423c04ef671ceefec1be97d5fad67cca54cb6790e8156fd0c6d5d04b2dda0ce0f89633ffd38e07cb88606d922d43e5335d640d4fd0eade9e54ea759825eb4172df39d6c36878fccd5ab620924ca2f793e11d950913a441ce20000000000000000", .Okay}, + {.Shl, "b7410da582654ca77e87fa13772681f7e354459262d3a5e8e0a8cc5ed913b701a9b67bd4a240f20d5e5374b0d902d853390cee5d6938de22736e80adb9bce50403b7ae99e51686511c236ac102f14d0d8e5d5b30bf3272f4a87f3b8a8c685091c0bf7ab8e3404746e99bcf9555371d41bf7a4b3b979b1a707dfc97b4d14effa3c38282c1921c2e56258f5b2c29c504187cb915ca1fe8bcc129d750f6d826735233cebf7b4d6304482881912593096550583026d7a4c79cb0990dc92fc8c673ff01656dbd0e4ca56062a04a4a44c41db349baa57a13255da6b4d736d1fbc734c9d3aa08e67a28d129db0999c3bbc0d6b471f6667aa6ecff45ad8932273d018d86d718e9eec9593d3e1926fdd160c35ed577914da419b981900556a47a04635a2553c7ca759ff723809634f091dc98a341cbd66d099be2c51b6b29fc95fd9972caef3d57d2d08e2d4f975ec52e659f3b30b9534f0c83ce716f8e7e3d42e0b6dada2c88268590a5374cbbc54f16e93c21c9f4f117890f7ab008309691dfaee67ddd655150f37bdd072cb67cb2dcc6bb746cf998cf2c2d12d992133b1baa98776c081b455577180631efe15e00433200b684f4ca1a3c7d143c20b63ec4731ce8ceffb73a75098d9887ee497fd94e6aaa237f914a6db4c8deeffecae4f582e1006004a37b6ef051cfa7fa7745df16ac82cbc89d6d739b80f75ec506195a65279c6583", "3c", "b7410da582654ca77e87fa13772681f7e354459262d3a5e8e0a8cc5ed913b701a9b67bd4a240f20d5e5374b0d902d853390cee5d6938de22736e80adb9bce50403b7ae99e51686511c236ac102f14d0d8e5d5b30bf3272f4a87f3b8a8c685091c0bf7ab8e3404746e99bcf9555371d41bf7a4b3b979b1a707dfc97b4d14effa3c38282c1921c2e56258f5b2c29c504187cb915ca1fe8bcc129d750f6d826735233cebf7b4d6304482881912593096550583026d7a4c79cb0990dc92fc8c673ff01656dbd0e4ca56062a04a4a44c41db349baa57a13255da6b4d736d1fbc734c9d3aa08e67a28d129db0999c3bbc0d6b471f6667aa6ecff45ad8932273d018d86d718e9eec9593d3e1926fdd160c35ed577914da419b981900556a47a04635a2553c7ca759ff723809634f091dc98a341cbd66d099be2c51b6b29fc95fd9972caef3d57d2d08e2d4f975ec52e659f3b30b9534f0c83ce716f8e7e3d42e0b6dada2c88268590a5374cbbc54f16e93c21c9f4f117890f7ab008309691dfaee67ddd655150f37bdd072cb67cb2dcc6bb746cf998cf2c2d12d992133b1baa98776c081b455577180631efe15e00433200b684f4ca1a3c7d143c20b63ec4731ce8ceffb73a75098d9887ee497fd94e6aaa237f914a6db4c8deeffecae4f582e1006004a37b6ef051cfa7fa7745df16ac82cbc89d6d739b80f75ec506195a65279c6583000000000000000", .Okay}, + {.Shl, "3ce2a4183e93f604a6d7be710ef572f745f5640ba56c7dcc897e594549c8e8d17ff0b341866a90367f2624851088ffd984847dad9da6656b7c6e66730c8a2ea55564ab25cb3c46f18a972a29da97e89c09205ce4155480c0a7cfbe45d501d52564c73669703215edf5b2092b500174abad07d089b2edadc82c6ce2e4773626b364a1d03b81e6e2ad0c6e94efcd6ebf1388471913c4ab7d16ee0dbd8836cc266170742dab168db5135e916f96742705da80ef6f936a992534718f222fc5f50a6151a961da11988a9fb7782fd05fa701c02d467b5aa569240ae92e9091dbf48dad894901b9b9b420e8f4a561b7481796fea154bbae564b10586f0448f654e6d9d99097b25c6eaef48f5ee72d30f810bf6330062aa6705383ba66d1b5cc81fe5d3f15bf0142aa55c4a1c05cc33e47fbb3bbe4e2ea2c6d0a06eb04a05efbb3dea6936ed470c3d0ebdd8951c5065a1cfba2b9359317cdee176ceb2cfcfbad89884bcec4afee6c56169b3bb37d7309fb42356feb2fe8acd3cbaffbde5ef65543c5fcb9b87ae134b9b747e9d23b669a627be2df3977979a963789beb759a9523595343b31429872f0eddf8bf7849b988d908f5262f39d8d821a1e56d5342aae2fda6355e8b9c908b1ba68c28f002fc2bc375fb09c6664c1eb1da352c89856752679ce048f887e04d15ec8bde53a768c34577fb128b4ebbd7ac8aee394c0e9ea211b0242", "168", "3ce2a4183e93f604a6d7be710ef572f745f5640ba56c7dcc897e594549c8e8d17ff0b341866a90367f2624851088ffd984847dad9da6656b7c6e66730c8a2ea55564ab25cb3c46f18a972a29da97e89c09205ce4155480c0a7cfbe45d501d52564c73669703215edf5b2092b500174abad07d089b2edadc82c6ce2e4773626b364a1d03b81e6e2ad0c6e94efcd6ebf1388471913c4ab7d16ee0dbd8836cc266170742dab168db5135e916f96742705da80ef6f936a992534718f222fc5f50a6151a961da11988a9fb7782fd05fa701c02d467b5aa569240ae92e9091dbf48dad894901b9b9b420e8f4a561b7481796fea154bbae564b10586f0448f654e6d9d99097b25c6eaef48f5ee72d30f810bf6330062aa6705383ba66d1b5cc81fe5d3f15bf0142aa55c4a1c05cc33e47fbb3bbe4e2ea2c6d0a06eb04a05efbb3dea6936ed470c3d0ebdd8951c5065a1cfba2b9359317cdee176ceb2cfcfbad89884bcec4afee6c56169b3bb37d7309fb42356feb2fe8acd3cbaffbde5ef65543c5fcb9b87ae134b9b747e9d23b669a627be2df3977979a963789beb759a9523595343b31429872f0eddf8bf7849b988d908f5262f39d8d821a1e56d5342aae2fda6355e8b9c908b1ba68c28f002fc2bc375fb09c6664c1eb1da352c89856752679ce048f887e04d15ec8bde53a768c34577fb128b4ebbd7ac8aee394c0e9ea211b0242000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-b263ee20a258b47f4d26d623abc632aa0b793931cd3ab3c14d215862c6c2ae45322b8fb2b3cacac5d0df19e8f65d1a4385fab2dbf4e229b21c65172ed9d64560dd4bd12a03c8effc5bf6d744cf0441aa4ac04a5d640195319dce0fabebf2e76380645b18e3efbcdb5a4830505fe477f3a219cb8b912ffaf00a15d9d7faec62207104476985c7a0881f733328a4c0644e9e87fa1de37f155dda9ee9471518588c75a974a12e15c38f273fca9c269fe28eec63ff38e21c12c89e16b6886dd30dca0a21bee72bbd0612208db3ea56b95ae364e99257ce669e516df16db0aa6dfd2f0d7e60dd9edcb4b623ddf4931d1d2ee5126ac40768a62e652de0b9177c34419bbc9a3fb4c374055c1f77f4854142b77a9d9f91eed8e40d6ba5e6477fbcee815ef9f88ae3c8264462226fdd11989a8ace1f630019a65e6cf62c4c39c3019df95203db24b7930e95d6e4683264ae4169752bb2ddfae53eb8817f273e7b182bca5efe9d567739051310f34638dc304c25340ea79c1788ae08052b3b1a2850c852ccf0820ea2c450e9f98d4f1cce82398d05231b055a0e0cd99afe42e7c3800a71dd58f2d887e476f8f4466df994826e1cff6c5c7da5603bb97ed395b968b5701eaba40c76972d9ea065b9a3e45539fb25aa29b2aebec07307a89c68177da008eff4481e39e891dcfbc0c867a4276f060890177aa3a071ef0719168f57104ffaddb6", "258", "-b263ee20a258b47f4d26d623abc632aa0b793931cd3ab3c14d215862c6c2ae45322b8fb2b3cacac5d0df19e8f65d1a4385fab2dbf4e229b21c65172ed9d64560dd4bd12a03c8effc5bf6d744cf0441aa4ac04a5d640195319dce0fabebf2e76380645b18e3efbcdb5a4830505fe477f3a219cb8b912ffaf00a15d9d7faec62207104476985c7a0881f733328a4c0644e9e87fa1de37f155dda9ee9471518588c75a974a12e15c38f273fca9c269fe28eec63ff38e21c12c89e16b6886dd30dca0a21bee72bbd0612208db3ea56b95ae364e99257ce669e516df16db0aa6dfd2f0d7e60dd9edcb4b623ddf4931d1d2ee5126ac40768a62e652de0b9177c34419bbc9a3fb4c374055c1f77f4854142b77a9d9f91eed8e40d6ba5e6477fbcee815ef9f88ae3c8264462226fdd11989a8ace1f630019a65e6cf62c4c39c3019df95203db24b7930e95d6e4683264ae4169752bb2ddfae53eb8817f273e7b182bca5efe9d567739051310f34638dc304c25340ea79c1788ae08052b3b1a2850c852ccf0820ea2c450e9f98d4f1cce82398d05231b055a0e0cd99afe42e7c3800a71dd58f2d887e476f8f4466df994826e1cff6c5c7da5603bb97ed395b968b5701eaba40c76972d9ea065b9a3e45539fb25aa29b2aebec07307a89c68177da008eff4481e39e891dcfbc0c867a4276f060890177aa3a071ef0719168f57104ffaddb6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "e2710dc2c534ccd4890cb9ff74ce87020521a1549bad4a9c0b9e53dff76bcb9b137c7d901d2c8852e66f13324f8f757875fa203405f5f32f9f1740a9d5c0f03577549f18b5d077cb6dd0f13cdb72ff414bc962e792feff54f22ada1b6dcf223b4eb8bb4d82c80b1d16dff8fcc71630402a6d066883921e8defd9527862643bf26e32d5c1b96decccbaaafa3c5de8443454d514fc28900a9a26d2ea8eeda5565098a1766645f160c50e5667bc271d89d0de4423c71086046c8a5f9f1530360c336f5f0a517b2b98d168430ee48a0ff7231c9f0382c769f3e218fa734a7471e847b6c9601f074c0088dca83cc10dfb2d7c3803b66f68e29fe365d8d28a3f3c6efd74b3adc9d577ab295f054c6baac42da44038381c0d5cdb89e8d7ce28b9062222b97fdda44799310aa6a9918076700fce4ce9cea91269b15624993233d9af54e513eaace6507c27e01313bd4bc54fd590e41ba9469116d514734df96499df36fee5272eda529be99d4b60b9832c59db224590fef71f37c41487e63fab2902f206a57ef30e8e2cc2fe8bc2bf725a6639cfd2ecd597e51b70c7a124a5f069ab1814510f3bec75e515484567af80032038b0094b370e4e06e1f261fe0bb0c129fb91354803b8d827cfbb7a2de1d7a65accaba345ada2781cd6f51a12c95cdab964f4a31d5c7cc38c5db0847027b33430c33fa53dcaffbf53911899a2578bf5258c61", "21c", "e2710dc2c534ccd4890cb9ff74ce87020521a1549bad4a9c0b9e53dff76bcb9b137c7d901d2c8852e66f13324f8f757875fa203405f5f32f9f1740a9d5c0f03577549f18b5d077cb6dd0f13cdb72ff414bc962e792feff54f22ada1b6dcf223b4eb8bb4d82c80b1d16dff8fcc71630402a6d066883921e8defd9527862643bf26e32d5c1b96decccbaaafa3c5de8443454d514fc28900a9a26d2ea8eeda5565098a1766645f160c50e5667bc271d89d0de4423c71086046c8a5f9f1530360c336f5f0a517b2b98d168430ee48a0ff7231c9f0382c769f3e218fa734a7471e847b6c9601f074c0088dca83cc10dfb2d7c3803b66f68e29fe365d8d28a3f3c6efd74b3adc9d577ab295f054c6baac42da44038381c0d5cdb89e8d7ce28b9062222b97fdda44799310aa6a9918076700fce4ce9cea91269b15624993233d9af54e513eaace6507c27e01313bd4bc54fd590e41ba9469116d514734df96499df36fee5272eda529be99d4b60b9832c59db224590fef71f37c41487e63fab2902f206a57ef30e8e2cc2fe8bc2bf725a6639cfd2ecd597e51b70c7a124a5f069ab1814510f3bec75e515484567af80032038b0094b370e4e06e1f261fe0bb0c129fb91354803b8d827cfbb7a2de1d7a65accaba345ada2781cd6f51a12c95cdab964f4a31d5c7cc38c5db0847027b33430c33fa53dcaffbf53911899a2578bf5258c61000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-a3f4ba2b570125e7ac9c9e49d84ada02aba7ee4805a79602e23585dd1559f5200468e34c48032b97c3f93759c1d2eb77f029774ab8bd59735aa0d05c0d3197fec355d3cef263f2c76cc3e6f72d36cac2a469aea74ef6f47d76bd6b4a593376968f234de6b46659790b23f9e3608cbf6e6ab4323fe86c1b36a4244f55f7c56050ebc30728745a66287d30af967cb49858593185722da85cd2a80f330e886cfb752b467f37792141162b028a378f4c0b057cf6c6cd62bf551b830f983801dd75d26ce1c1c312e097e80b650e088241588b6ee444807261ddf692a8608b2320d17507d81c239c9f4a841b10cd8b660a9bea15a15db96c28f0ec4859a06eb501abacdf44c5cbf50892e67c8cf29277d3cd5393870f569168d732a29eefea7989c18907780af99ae8e362e91072d5b91d10aeea1a9d139a51d795eedeff65ae16b5391dec668fdb2258a31e1b4f5fcc4b5c7665c386b764947e069e64254fcb67cf000e8b0126ebf4b8a0c49f6c9cef8a49c1daa45a4c70dda74638e303a4bd8fbc9befe16bfce8fd9622377eb3ef62aeea91d412d6e8d0a9e3613438f66500627280ba5828587ff7c9cc9d45008b8e7ec4ba3b3b52f975283ce1d14aa94db8ff7c36d8c0e5ed0530e8e24d5814da9a0fdef5ddf043b3134bd2491f1ea36eecee32513e01da406967dc1f4a65580de1fbb8a8960f6dcd7d4392c4fb3f8ce02cccf439", "1a4", "-a3f4ba2b570125e7ac9c9e49d84ada02aba7ee4805a79602e23585dd1559f5200468e34c48032b97c3f93759c1d2eb77f029774ab8bd59735aa0d05c0d3197fec355d3cef263f2c76cc3e6f72d36cac2a469aea74ef6f47d76bd6b4a593376968f234de6b46659790b23f9e3608cbf6e6ab4323fe86c1b36a4244f55f7c56050ebc30728745a66287d30af967cb49858593185722da85cd2a80f330e886cfb752b467f37792141162b028a378f4c0b057cf6c6cd62bf551b830f983801dd75d26ce1c1c312e097e80b650e088241588b6ee444807261ddf692a8608b2320d17507d81c239c9f4a841b10cd8b660a9bea15a15db96c28f0ec4859a06eb501abacdf44c5cbf50892e67c8cf29277d3cd5393870f569168d732a29eefea7989c18907780af99ae8e362e91072d5b91d10aeea1a9d139a51d795eedeff65ae16b5391dec668fdb2258a31e1b4f5fcc4b5c7665c386b764947e069e64254fcb67cf000e8b0126ebf4b8a0c49f6c9cef8a49c1daa45a4c70dda74638e303a4bd8fbc9befe16bfce8fd9622377eb3ef62aeea91d412d6e8d0a9e3613438f66500627280ba5828587ff7c9cc9d45008b8e7ec4ba3b3b52f975283ce1d14aa94db8ff7c36d8c0e5ed0530e8e24d5814da9a0fdef5ddf043b3134bd2491f1ea36eecee32513e01da406967dc1f4a65580de1fbb8a8960f6dcd7d4392c4fb3f8ce02cccf439000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-e7aa989af2ccceed6813ce892084d60516efb4f615cf50748b8b522e4d5c7996ba464eaba550e464e655dc7f1b2199440cf47fcaa1ecd5e880399d556f181c0b3db4691211a401aeeca89119338b6f73c731517f0f794bc805e1126a46954fc9305a3be0b91fdc132a35c77bd6c2b8301d160810e8378d17df8ac2d94865e3768f7c4986dd14d90528f9ec53e2bf7e6baea6ffcbe096e67f55589e7003be5ff89d58fea48c3f8adb3592d3567d7854280960723450238bcd99b3aefa2bf42ab6935f7a037212b00c61dda4f193189f22d657643f39ec9356062d1e9e2a4dc3122bc16436db3ad51d1658223b65674dcdde0f60ee7fba9c2fb0c1bfba3bbef930e0e0763cc7db5a6936b6ab69d79cb6059bb3080e99912d2f1fe9abeffce58231d4da797cc26b702b7643a4e538d5c6bc9987a6933243c05fe10cdb40c2a88a75a4342a74a55466dae1c4e69cd80ad7515dcf3314818961cd643ac2364405b0c36ae8ebb0f8d00150a9ac450424f263bb40b47e1fcf101c4a28a7a7a7dad06550eb2a2a69a3f065c25a7f051cc1a16899f62e188c3a4e7d2300077a753580edb03f4b9a33ab20dd312717c8d1c5780cc9291f91655517a5c9df89d1ad031c76c980eeea510f377e1c5afa08cb397cdf23f38bec579093300686d97c13999f88c0d0b0a1d45d27ea8109301ac4cbfcb87e2c50bba2358029c40894310c4fb3f480", "78", "-e7aa989af2ccceed6813ce892084d60516efb4f615cf50748b8b522e4d5c7996ba464eaba550e464e655dc7f1b2199440cf47fcaa1ecd5e880399d556f181c0b3db4691211a401aeeca89119338b6f73c731517f0f794bc805e1126a46954fc9305a3be0b91fdc132a35c77bd6c2b8301d160810e8378d17df8ac2d94865e3768f7c4986dd14d90528f9ec53e2bf7e6baea6ffcbe096e67f55589e7003be5ff89d58fea48c3f8adb3592d3567d7854280960723450238bcd99b3aefa2bf42ab6935f7a037212b00c61dda4f193189f22d657643f39ec9356062d1e9e2a4dc3122bc16436db3ad51d1658223b65674dcdde0f60ee7fba9c2fb0c1bfba3bbef930e0e0763cc7db5a6936b6ab69d79cb6059bb3080e99912d2f1fe9abeffce58231d4da797cc26b702b7643a4e538d5c6bc9987a6933243c05fe10cdb40c2a88a75a4342a74a55466dae1c4e69cd80ad7515dcf3314818961cd643ac2364405b0c36ae8ebb0f8d00150a9ac450424f263bb40b47e1fcf101c4a28a7a7a7dad06550eb2a2a69a3f065c25a7f051cc1a16899f62e188c3a4e7d2300077a753580edb03f4b9a33ab20dd312717c8d1c5780cc9291f91655517a5c9df89d1ad031c76c980eeea510f377e1c5afa08cb397cdf23f38bec579093300686d97c13999f88c0d0b0a1d45d27ea8109301ac4cbfcb87e2c50bba2358029c40894310c4fb3f480000000000000000000000000000000", .Okay}, + {.Shl, "7f4e326de1a8bf6277dc414a09e85bf86d054731894070b2d79aa8cd13dfef4b405eff606431c0a45ba20c60354b4387490da7143526f252d494f0fc3d9a3261c47ac17de585f7250278ba180f942ba9ad321a2b81ec62e5f39e153b4e64e4791cc16b8037a7a9484027f62f8863faf4f9d51a7a95455c65dfd1f82c55ab750fbb9818c1a3fe8b81381ff023d71579f6d0b2139746cc3ebcf75e58d9172bfda098620dbd33847d1c828f01b8ddee4585d37ceb8c180589f8bbed3b3ccba5b1d45d2dd0189b5699ab5acc70ec2eb33348e18ef1077b68e479036847c9df8d99b15d6c36e565f467d087047a3687ba35d07cfd4263b10133177a8455b79b286f7db73c650ada8b089230c5c9c415b63f11e42f6ea3d26dedb2142184b6c7b33ee092c3031acb09ea4ebcb3826ba5aadbbeb88407d3648c73d695ea5f2cd14fcaef17bc2c9a8775a569c1efe0e61dc7e451319575aa584125fe205a71f333291fee5f936c43c4424fe1616da0c02a34b4ed8dea68aa8608e67f43032c1d1628ab23dd9287941a4779ac011ddb20969baa48770d020a001a6beea181abc572bd0a1208e1a473cfcad479270354190c675624e92d2a98588bbf39c5dff7dd61eae700d2fc142dcd8af7073344201f14b0cbd3fa028624638183ca07319d5fd5fc0e8bda4118478da5ac77b4c193ee8d77c9f61d24890f5c802153b155b7a9f2e298bb", "3c", "7f4e326de1a8bf6277dc414a09e85bf86d054731894070b2d79aa8cd13dfef4b405eff606431c0a45ba20c60354b4387490da7143526f252d494f0fc3d9a3261c47ac17de585f7250278ba180f942ba9ad321a2b81ec62e5f39e153b4e64e4791cc16b8037a7a9484027f62f8863faf4f9d51a7a95455c65dfd1f82c55ab750fbb9818c1a3fe8b81381ff023d71579f6d0b2139746cc3ebcf75e58d9172bfda098620dbd33847d1c828f01b8ddee4585d37ceb8c180589f8bbed3b3ccba5b1d45d2dd0189b5699ab5acc70ec2eb33348e18ef1077b68e479036847c9df8d99b15d6c36e565f467d087047a3687ba35d07cfd4263b10133177a8455b79b286f7db73c650ada8b089230c5c9c415b63f11e42f6ea3d26dedb2142184b6c7b33ee092c3031acb09ea4ebcb3826ba5aadbbeb88407d3648c73d695ea5f2cd14fcaef17bc2c9a8775a569c1efe0e61dc7e451319575aa584125fe205a71f333291fee5f936c43c4424fe1616da0c02a34b4ed8dea68aa8608e67f43032c1d1628ab23dd9287941a4779ac011ddb20969baa48770d020a001a6beea181abc572bd0a1208e1a473cfcad479270354190c675624e92d2a98588bbf39c5dff7dd61eae700d2fc142dcd8af7073344201f14b0cbd3fa028624638183ca07319d5fd5fc0e8bda4118478da5ac77b4c193ee8d77c9f61d24890f5c802153b155b7a9f2e298bb000000000000000", .Okay}, + {.Shl, "be29661bbf56d2720bf20cd3fa5240c399436500bad6a1d240fa7b81d9672c1e3181447f2413d5c8a5738d7afa84d2c48dd67fd19333655d0c6d1ffeff5f9252eec7cc71f888064cbc1474df3894be378f18fb5769440680c4b20a3dfcdd749db9a82b2b8b621f29c2e5a26a6d55afb7c0738269cbd29e63d64dac767378a8de6978d3d44558a60ad48948cf05cc57b01942ce2a9f91e74420e4dcaae8935d7ba7c320122df5c1b7e7e40a600cee7809dd9f0543eee8bdfb6cf4829913199b74703b89497384f11aa7fc000b65c97180d914c20cdab5be6ecf939141323bbbb53e82132771d6394e0e1b7bb5dbf233d4c6ea2572a9d147172a0091150f80b3982171e0701998306fd2d4b8552d8c36fa7620b53f4a4806e9ff906ef161a1778f1b908494227f0c791aa4c7c7caa6fd9d0ce40a1af8dd85867ec9f330655d850599244422fe885a6bdd16cdc75948d22d4f768e8ae14007a4f9769222937306b2e559ddc6464f7156632cf4f9f7352d7dd84200b581cfdeb1ede740a3264a67869f40ed721f523c8509c014f861457c158ec9e8fb4a34412499f46dc94f151bef45b61c4f15e22d886425b067d62379d63832d0db0fe4d3a7b374fdbbcdccdc6284c495ff5dd29fe4ad6e7147dc0ea6974fa17e2f8c67450bd908a3cafd6053894532d15a2f9c7d4862cb8da7c044f709435dccd75d8208632f8c4524c081d7f3", "21c", "be29661bbf56d2720bf20cd3fa5240c399436500bad6a1d240fa7b81d9672c1e3181447f2413d5c8a5738d7afa84d2c48dd67fd19333655d0c6d1ffeff5f9252eec7cc71f888064cbc1474df3894be378f18fb5769440680c4b20a3dfcdd749db9a82b2b8b621f29c2e5a26a6d55afb7c0738269cbd29e63d64dac767378a8de6978d3d44558a60ad48948cf05cc57b01942ce2a9f91e74420e4dcaae8935d7ba7c320122df5c1b7e7e40a600cee7809dd9f0543eee8bdfb6cf4829913199b74703b89497384f11aa7fc000b65c97180d914c20cdab5be6ecf939141323bbbb53e82132771d6394e0e1b7bb5dbf233d4c6ea2572a9d147172a0091150f80b3982171e0701998306fd2d4b8552d8c36fa7620b53f4a4806e9ff906ef161a1778f1b908494227f0c791aa4c7c7caa6fd9d0ce40a1af8dd85867ec9f330655d850599244422fe885a6bdd16cdc75948d22d4f768e8ae14007a4f9769222937306b2e559ddc6464f7156632cf4f9f7352d7dd84200b581cfdeb1ede740a3264a67869f40ed721f523c8509c014f861457c158ec9e8fb4a34412499f46dc94f151bef45b61c4f15e22d886425b067d62379d63832d0db0fe4d3a7b374fdbbcdccdc6284c495ff5dd29fe4ad6e7147dc0ea6974fa17e2f8c67450bd908a3cafd6053894532d15a2f9c7d4862cb8da7c044f709435dccd75d8208632f8c4524c081d7f3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-ab2664524db61d43bf656a0f4e1771210c6ddd38497e3d8b2f1c9f1ca847c8cf0d765926fda51eb2fba2cf99be0c50d265a479c61a629d2e3968b7169e1685ca1aa69f67761302e633bb42ac5a77b6fe562224f7afb5b55888a7378239652603e4b708e5902c45bd38f3afe6240eab5b64b76c09a059cbf78e1f45a7cfc16b83e2a97e3f373d0e838e1d00b2ea9199bf4a01906993ff18ba1190727dcd2560ea5ad2d8a1c1f64c1b3de7de98b7d17c87f164730eaa25d6b7270b7007346226604c5b5c6aa83da371b59b6dc3ecd849e6926a42831104ad9008553203ce780397036ccc74a501efe9a3a6aaebfaf63c0d5958136eeae062e4a1fff9fdb823a032ac8a32ea736c216096f638d99684bf0005aa2f5c3284c5e5417e159db30c52f3ef691be7fe37511f999093a86e8bf8281aa7b72d785ed9dccfbf15393ab86188724371d370aa2134d984f47110db74e232983c1396047d3d925545e47b3bc4c7f8d5f409c398bb6ca32a896ba2494f7ed382b8f496f61d6ef4039aabf5c0f7253cf9620c3c50a9537ba3b4bd4b865fb78bf4b2da849cb36ed5e0969a5b2ce153a8aa305d399cad402a757b550d86ee361240c9d289068d59796061451c011bee8bd50e78121a5d0b66920e6fefccc95ac3599a4965431410a0cd446b41abb8ec6479fa85c75a3067991dd37721b76f90df784ff3c854c512d19c9bb0f528301f", "168", "-ab2664524db61d43bf656a0f4e1771210c6ddd38497e3d8b2f1c9f1ca847c8cf0d765926fda51eb2fba2cf99be0c50d265a479c61a629d2e3968b7169e1685ca1aa69f67761302e633bb42ac5a77b6fe562224f7afb5b55888a7378239652603e4b708e5902c45bd38f3afe6240eab5b64b76c09a059cbf78e1f45a7cfc16b83e2a97e3f373d0e838e1d00b2ea9199bf4a01906993ff18ba1190727dcd2560ea5ad2d8a1c1f64c1b3de7de98b7d17c87f164730eaa25d6b7270b7007346226604c5b5c6aa83da371b59b6dc3ecd849e6926a42831104ad9008553203ce780397036ccc74a501efe9a3a6aaebfaf63c0d5958136eeae062e4a1fff9fdb823a032ac8a32ea736c216096f638d99684bf0005aa2f5c3284c5e5417e159db30c52f3ef691be7fe37511f999093a86e8bf8281aa7b72d785ed9dccfbf15393ab86188724371d370aa2134d984f47110db74e232983c1396047d3d925545e47b3bc4c7f8d5f409c398bb6ca32a896ba2494f7ed382b8f496f61d6ef4039aabf5c0f7253cf9620c3c50a9537ba3b4bd4b865fb78bf4b2da849cb36ed5e0969a5b2ce153a8aa305d399cad402a757b550d86ee361240c9d289068d59796061451c011bee8bd50e78121a5d0b66920e6fefccc95ac3599a4965431410a0cd446b41abb8ec6479fa85c75a3067991dd37721b76f90df784ff3c854c512d19c9bb0f528301f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-dfea519f2cec6536e0b664be1041648f9d02fd9bfaf9c831219297826462d26285e17a9e62894783fd9a10f37c7c519d15beb4d886d816847f0a7611b860cddcdf9b0c932d343f45b87d86423c8669a12063f1415536a6e1fc4d319b13f9cf89d965ebdc5078c681212b663f2df4daec93c29a1fea9ad691f478edf62aa0349e44f98b868bcb415a4415e47e04cd4ae30c12084e658fdf74fb6280942c85633586daf14fc57f8baad64be5321afa0fbc01553ada66a63e974d7ab686607de14b5b13ca86d4d8ed63aa24ce73cc61672c07473d0bf21bc0ccc6515fedb4baf5e8e5d21ac883e2fe0ac7b7a32295401dbab87f4727640f537bb60aea701f064c02405b2259ee69c6364436185f19cb8e0a87ee4dd20997cfdd8d653e95b2638530e3abd5335984ee627c4364b363688e8530cd6e5c78e9ec1a34f58b4498f0649b06c7559c501bca5b9c22e3bf5e619a60789271deb83e6cc0486205414d9b6f3461e475e60e42f79a2ed16ecd64372e121cfcd3d5f5a351aef4b0b91f3b75576358d15ac743a98dfe53a6d620e7f49b3c9ce928642d6f68b69b3782711d423514568ecd30c23c7b5118ee603a54f33784b37374d5e1712d0255479b2a0176ecf8da1928231d87a71ea302c7bff15f33486b9187bdc784469554351f77b6d6b1cd0bb012aa64982a8a08874e5b66842c1c10d00cfb3f49c41fd6c452447134aef9", "168", "-dfea519f2cec6536e0b664be1041648f9d02fd9bfaf9c831219297826462d26285e17a9e62894783fd9a10f37c7c519d15beb4d886d816847f0a7611b860cddcdf9b0c932d343f45b87d86423c8669a12063f1415536a6e1fc4d319b13f9cf89d965ebdc5078c681212b663f2df4daec93c29a1fea9ad691f478edf62aa0349e44f98b868bcb415a4415e47e04cd4ae30c12084e658fdf74fb6280942c85633586daf14fc57f8baad64be5321afa0fbc01553ada66a63e974d7ab686607de14b5b13ca86d4d8ed63aa24ce73cc61672c07473d0bf21bc0ccc6515fedb4baf5e8e5d21ac883e2fe0ac7b7a32295401dbab87f4727640f537bb60aea701f064c02405b2259ee69c6364436185f19cb8e0a87ee4dd20997cfdd8d653e95b2638530e3abd5335984ee627c4364b363688e8530cd6e5c78e9ec1a34f58b4498f0649b06c7559c501bca5b9c22e3bf5e619a60789271deb83e6cc0486205414d9b6f3461e475e60e42f79a2ed16ecd64372e121cfcd3d5f5a351aef4b0b91f3b75576358d15ac743a98dfe53a6d620e7f49b3c9ce928642d6f68b69b3782711d423514568ecd30c23c7b5118ee603a54f33784b37374d5e1712d0255479b2a0176ecf8da1928231d87a71ea302c7bff15f33486b9187bdc784469554351f77b6d6b1cd0bb012aa64982a8a08874e5b66842c1c10d00cfb3f49c41fd6c452447134aef9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "d539e743e6db13240d326142f2a71d61c8c8da794bb0b267e124bbec247a355c70813f61e290ab2a0c2e5ab52a2392680ce99dde2b5ccdf6a012f489ee6165ea5c6bffd2b98f0fc606de1a6f33772f635be48be6f5e8486ed1de14083d34417ae78405d16eb7eee2f0d45b7d3ba64b42470570ffe9cf6e41e8106659a38094fad3845c01d61b20c552f4445d59f8b35baf17f95dbf1ded8c34b12803330098421cc6527669fc3278c0e93ffa3e98237980050c7d5485e6ef3b0856b9cb9573e3926f00bf9c8f85185c07e121debea4b75fed1d383d08581561b6e78b62d693e92ff45e01f2023b0cbf7182e1bd349f47afb70a95d371b6b882dad36af6132c4eb8a16e3e800cd3f1a872bc00a8054af03db1b2bf7e06c67733c456bc1a5216c49985f2a9c27d7a9f2ad8a6857db6d49a767ef88b2298771a20f50fc307dd54788e2a9bf0f87bdcfa9c764fc91adeec4087e2c56c2e9bbc2822453b99c32fc0ed90b32de75a1d1270ab8b40b937bb5267b0f8f2c8468a87cdc9632297bb63e076a51493d4da1f72c9d195cb5cc3d9eb64991a0d6070ab0d0ad9cda74e23c8319d6c57311999f66cfcda446da2e472d46bb6b2422df25fd4e082653491e52c3160f7f2946f3182f6ebedacac38b3b892ea060f683ab06d320329d1277e3763aab215a84901fff2c670f8d8ef1afc2fa15442e02c17fcc574906c98bd7fd467422a", "21c", "d539e743e6db13240d326142f2a71d61c8c8da794bb0b267e124bbec247a355c70813f61e290ab2a0c2e5ab52a2392680ce99dde2b5ccdf6a012f489ee6165ea5c6bffd2b98f0fc606de1a6f33772f635be48be6f5e8486ed1de14083d34417ae78405d16eb7eee2f0d45b7d3ba64b42470570ffe9cf6e41e8106659a38094fad3845c01d61b20c552f4445d59f8b35baf17f95dbf1ded8c34b12803330098421cc6527669fc3278c0e93ffa3e98237980050c7d5485e6ef3b0856b9cb9573e3926f00bf9c8f85185c07e121debea4b75fed1d383d08581561b6e78b62d693e92ff45e01f2023b0cbf7182e1bd349f47afb70a95d371b6b882dad36af6132c4eb8a16e3e800cd3f1a872bc00a8054af03db1b2bf7e06c67733c456bc1a5216c49985f2a9c27d7a9f2ad8a6857db6d49a767ef88b2298771a20f50fc307dd54788e2a9bf0f87bdcfa9c764fc91adeec4087e2c56c2e9bbc2822453b99c32fc0ed90b32de75a1d1270ab8b40b937bb5267b0f8f2c8468a87cdc9632297bb63e076a51493d4da1f72c9d195cb5cc3d9eb64991a0d6070ab0d0ad9cda74e23c8319d6c57311999f66cfcda446da2e472d46bb6b2422df25fd4e082653491e52c3160f7f2946f3182f6ebedacac38b3b892ea060f683ab06d320329d1277e3763aab215a84901fff2c670f8d8ef1afc2fa15442e02c17fcc574906c98bd7fd467422a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "e7e48cd1dbf7194f324841dfdb24e2ff35c863cdc32658c1ef379576adafa212a04a1cbc082b6af591e08240318afee6d102e5c0dbcd4e87d3a03d0e8351523e3311e79f408ae5e4178c35f98c0731cbe34f757aeb3f5284f01695e36bffc93ed37be1c94bb38b934c66ff95c6221eba11d2a52900a44a1f01d1f674f9ea3e09add49b584927aca7909882a4ab6b661dc86b3fd80815e545ea00d80cf0c8752e29f7d62a5a842d3db7344d20bc42f95b0879b244183ad14c791cf69fc31feb4bd729c168f9b76ce77a598a0749138a741502404ba6a2a01b09a8701a5d4012d8e186d67d01f26489ced17f74491fa2e67bc226ce0b2785bc6646c7612aece898a1e666b5520ddd7c620167690c8f91185432356c11d30687ca5f0c5105a7d9979e33895a0bfa0600468189ef389bc95e3335bdc2ecfb8c6941db379bf84fab47cb5f1a7a14361654b04e96431f49aa75ca4f32859337bd50666ca4edc3886bf8635705620ec0af1a9544e90f49122701e1e8728b1213ca96676f68d796f3a7ac562bd586903d39e6a2acbb2088f68be4cc63121c86b129db946af3cbeac9fef55f1eb7c03ab7d225e74d96a9e9ae33a1ded864d2c4a6bbb7936e419d1cf230349ca1948d39bfdb29850cd9e44bfbb30da8bb82e5291991be11a44d8886a02819528fe8ef7b24a2c4581f1c57b4233e9377cc1266c75767535439682214a47982", "f0", "e7e48cd1dbf7194f324841dfdb24e2ff35c863cdc32658c1ef379576adafa212a04a1cbc082b6af591e08240318afee6d102e5c0dbcd4e87d3a03d0e8351523e3311e79f408ae5e4178c35f98c0731cbe34f757aeb3f5284f01695e36bffc93ed37be1c94bb38b934c66ff95c6221eba11d2a52900a44a1f01d1f674f9ea3e09add49b584927aca7909882a4ab6b661dc86b3fd80815e545ea00d80cf0c8752e29f7d62a5a842d3db7344d20bc42f95b0879b244183ad14c791cf69fc31feb4bd729c168f9b76ce77a598a0749138a741502404ba6a2a01b09a8701a5d4012d8e186d67d01f26489ced17f74491fa2e67bc226ce0b2785bc6646c7612aece898a1e666b5520ddd7c620167690c8f91185432356c11d30687ca5f0c5105a7d9979e33895a0bfa0600468189ef389bc95e3335bdc2ecfb8c6941db379bf84fab47cb5f1a7a14361654b04e96431f49aa75ca4f32859337bd50666ca4edc3886bf8635705620ec0af1a9544e90f49122701e1e8728b1213ca96676f68d796f3a7ac562bd586903d39e6a2acbb2088f68be4cc63121c86b129db946af3cbeac9fef55f1eb7c03ab7d225e74d96a9e9ae33a1ded864d2c4a6bbb7936e419d1cf230349ca1948d39bfdb29850cd9e44bfbb30da8bb82e5291991be11a44d8886a02819528fe8ef7b24a2c4581f1c57b4233e9377cc1266c75767535439682214a47982000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "3ea2c460533db51a8ac388a93d791dddc705fdca99681e0d1ce7ad7e1dd5bc7bf5458433e3e53b934cfe0c91d198832523edd48a8b02c83697ebd469976d2bf3181949a82dba2264092e49c51251938cb14d1036dcb57dbd4eee046d29f29cc23f84d6e21589462d2dc7220639b02984cc01cda0f40402e60f8c0ba65dee79dda5e9a6559fa819506c783b54f957c56ba9bf66842b9618ad5927ee3bfb106cd151580fb11773d04bf1fd58a374b2255afb2bd986c28ad52130d2492cae61d848ba45fb0555d02b817e4907e3d6d586dda5a9508592a8122cfbef88dce5ef344c764f49f8fff9440138ab461aeae61b68e8427379b4ed2baa35e0884c9136cd6d0156577e499f69e358cdcc427863539e8951651f3c57b8b554cd859f28ac0e4a0da6135eb0a60f0c01d145eaf132e29e7a41d23d70ecf9c3afedef3f80b4b07fcf3f021fb11241860650d630447132051357a894108b6ba5b1a29887c511750a259e32925d059d6d4dd20baa30cbc86c0973626e66922dbee5c3941b802403167e64c0a5a10f29123b4f527ea7b3911beb918b720a998f0ad226f5f6384722c400d2c4854a6d8b5c18151730dae323ba689f58f2bac788e48db97a33766391b9724f53d5b8f38c84a8c22ccf3e2ed895160cb0a9ee9c88c0483c1093cf88bfd5d260020a413693ec8f89abdacf8bbe7524674bb340790bf6bad0cb6aba47995f", "78", "3ea2c460533db51a8ac388a93d791dddc705fdca99681e0d1ce7ad7e1dd5bc7bf5458433e3e53b934cfe0c91d198832523edd48a8b02c83697ebd469976d2bf3181949a82dba2264092e49c51251938cb14d1036dcb57dbd4eee046d29f29cc23f84d6e21589462d2dc7220639b02984cc01cda0f40402e60f8c0ba65dee79dda5e9a6559fa819506c783b54f957c56ba9bf66842b9618ad5927ee3bfb106cd151580fb11773d04bf1fd58a374b2255afb2bd986c28ad52130d2492cae61d848ba45fb0555d02b817e4907e3d6d586dda5a9508592a8122cfbef88dce5ef344c764f49f8fff9440138ab461aeae61b68e8427379b4ed2baa35e0884c9136cd6d0156577e499f69e358cdcc427863539e8951651f3c57b8b554cd859f28ac0e4a0da6135eb0a60f0c01d145eaf132e29e7a41d23d70ecf9c3afedef3f80b4b07fcf3f021fb11241860650d630447132051357a894108b6ba5b1a29887c511750a259e32925d059d6d4dd20baa30cbc86c0973626e66922dbee5c3941b802403167e64c0a5a10f29123b4f527ea7b3911beb918b720a998f0ad226f5f6384722c400d2c4854a6d8b5c18151730dae323ba689f58f2bac788e48db97a33766391b9724f53d5b8f38c84a8c22ccf3e2ed895160cb0a9ee9c88c0483c1093cf88bfd5d260020a413693ec8f89abdacf8bbe7524674bb340790bf6bad0cb6aba47995f000000000000000000000000000000", .Okay}, + {.Shl, "-f65a3a83fbebadc68eb1ba4fa66bbb39dbd3c5aa353046685f1a9a7d8c69bca6d60f9f9be1d22c769a405506a4163ed21a99746097c82e811b3bbc9d4ca49fc1c86c2ed905a64a03bae1a43bf3341c47dff9c70fa72ab55abb9589163dba9aa1facf796cd7caf373c20ceb226d1a5e17f73f8725e36baec1d897014615aab57a743955b6b301ff02cd2eae7c6fe67f9cf0ef96f1da1e5384832ba6d069e4335e03a504ddf2e73c8f003ea2fc46f4d489b14a94f9309c0bd9159b6b1fa54e24ac268808545e83cc74c2f3c34910a103d02bbee171404cfcedaeca5230fd953b990d51a1220ac91a4acd6957c81d2ea1fe81d2744296cdbe9a99a1f2ac7a54464dfcdf14e2f37fce2c6f5c5c30692055d225ffb8fa8a3dcf6e41dc4ca31b9289c77241f8ee1c0898f27221d9c678820737192f2a4c87de13f6206b1225e9f382c7bf7af7fea431033881ee5954c879f47400a4347e6f253865d57fe69b5e48f03e66926bef0c6b93bc9270b24900db1a2755aae3fa45f35fa83ef7d4c03c4f87e50cb84617981473114604206b6bd870a6ffa09eb0b62fa23efddd89e730c5119b1dad8022ba1e32531281d34d478763c7970d2889e077d29930d56fd4af8c9eabd466deeef6da3e9f555e93c5775ab35644c539ececb6f92d78a8962c2b546a8fa296f4232cec1de1955eeab2e3486a4bbde8ab4225c617361ba531b6242ae4fb", "3c", "-f65a3a83fbebadc68eb1ba4fa66bbb39dbd3c5aa353046685f1a9a7d8c69bca6d60f9f9be1d22c769a405506a4163ed21a99746097c82e811b3bbc9d4ca49fc1c86c2ed905a64a03bae1a43bf3341c47dff9c70fa72ab55abb9589163dba9aa1facf796cd7caf373c20ceb226d1a5e17f73f8725e36baec1d897014615aab57a743955b6b301ff02cd2eae7c6fe67f9cf0ef96f1da1e5384832ba6d069e4335e03a504ddf2e73c8f003ea2fc46f4d489b14a94f9309c0bd9159b6b1fa54e24ac268808545e83cc74c2f3c34910a103d02bbee171404cfcedaeca5230fd953b990d51a1220ac91a4acd6957c81d2ea1fe81d2744296cdbe9a99a1f2ac7a54464dfcdf14e2f37fce2c6f5c5c30692055d225ffb8fa8a3dcf6e41dc4ca31b9289c77241f8ee1c0898f27221d9c678820737192f2a4c87de13f6206b1225e9f382c7bf7af7fea431033881ee5954c879f47400a4347e6f253865d57fe69b5e48f03e66926bef0c6b93bc9270b24900db1a2755aae3fa45f35fa83ef7d4c03c4f87e50cb84617981473114604206b6bd870a6ffa09eb0b62fa23efddd89e730c5119b1dad8022ba1e32531281d34d478763c7970d2889e077d29930d56fd4af8c9eabd466deeef6da3e9f555e93c5775ab35644c539ececb6f92d78a8962c2b546a8fa296f4232cec1de1955eeab2e3486a4bbde8ab4225c617361ba531b6242ae4fb000000000000000", .Okay}, + {.Shl, "1c813ca79b8ee15e659b53701c818bd846aa2ef73c95e7ba130e73015b8c5deb2348886c504405cdeb90b89e79f6d29c3f4704ad049a12ba7d3a6d2cff37e9046d3af0df7d123641ac3a9bb1af081359c4ecbcba9b595169648d7a65aa17494d49eeebb430a933f24813afa8920c38e7397ff9ae68e87a245afb2c1fe56c70a3c2b4ed6674ac834595bcf611103d95275e411e024f24aa64908f78e7ba81cc198cfd08e493a3ead3291af00f04d78fe263764ffa2d450fac8e53dfcedcd70d148f759ad9f5d882ac8da510902547b992959c268e9ba1efc9b98b9f027bb23ad378a47ca2f79d18a19b6266d795de383c24c24fa8b9688f7efb6615117bf2ffb14e7a465fa5b6f354fbd07b3ae008fd7e0a997440e8650086a3bca2f2683fdf2341393f8a77d0cb19f95d95397bc811be97f0f0cd66cf05ceaeca6fcd64349199276d294adb2351a7f110a0e3ce8067bb8011cb198b7e8eabc0f65085aca89506704b145d938bc27e3281e1f3e15b071a94a6f39fda788ea5466c4a6371fb3fbaddbbfb789eb15cdb5e9d64712dd7b6a6a17b24b209581c50886b974a52bc17639aae1f2b3486cb04821af023d90579aaac909a382ac0c99696c18252b830015292c030e1400c10397c4dd6a491e7ba8b25ad56bfae07f57b1b97f1a3de1d48e7181fec35f4f12d705e50a5eba672467db592a08f9556b18e1ffd56cbc6edec65", "21c", "1c813ca79b8ee15e659b53701c818bd846aa2ef73c95e7ba130e73015b8c5deb2348886c504405cdeb90b89e79f6d29c3f4704ad049a12ba7d3a6d2cff37e9046d3af0df7d123641ac3a9bb1af081359c4ecbcba9b595169648d7a65aa17494d49eeebb430a933f24813afa8920c38e7397ff9ae68e87a245afb2c1fe56c70a3c2b4ed6674ac834595bcf611103d95275e411e024f24aa64908f78e7ba81cc198cfd08e493a3ead3291af00f04d78fe263764ffa2d450fac8e53dfcedcd70d148f759ad9f5d882ac8da510902547b992959c268e9ba1efc9b98b9f027bb23ad378a47ca2f79d18a19b6266d795de383c24c24fa8b9688f7efb6615117bf2ffb14e7a465fa5b6f354fbd07b3ae008fd7e0a997440e8650086a3bca2f2683fdf2341393f8a77d0cb19f95d95397bc811be97f0f0cd66cf05ceaeca6fcd64349199276d294adb2351a7f110a0e3ce8067bb8011cb198b7e8eabc0f65085aca89506704b145d938bc27e3281e1f3e15b071a94a6f39fda788ea5466c4a6371fb3fbaddbbfb789eb15cdb5e9d64712dd7b6a6a17b24b209581c50886b974a52bc17639aae1f2b3486cb04821af023d90579aaac909a382ac0c99696c18252b830015292c030e1400c10397c4dd6a491e7ba8b25ad56bfae07f57b1b97f1a3de1d48e7181fec35f4f12d705e50a5eba672467db592a08f9556b18e1ffd56cbc6edec65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "e8c18cb54388ba116db113d3ddc89d710f2f067965e4b7dff7f789a042111068b8f65780cae7fed8c39b5864213b64ecfd26ad8d24c91077f11d718e31604fea9b3615d18d240320cf06eead4707f8ea434e537fa743d475d60ce458d0e0fc9ca9af151a57996fc886b392d925cd10c74505ab1c449e758667241b2a1f8240ba5fcb03cfce6ccd5c65c68ca09c8d065a443874281458c8ee1a8cc776cad803096de3363ea06d9ffab0b3b61c9726eaf5b0b3488fbf092f955fbad4a83c1bd017352e1d1c07e5232a62a875eef715290161d3457d07cc4cf931a6764c4e857c9b100e5a1caadb947291020b54f3115f801d3cbae4d34171079e52a6c7a84a4465cba3cbad2050c023181301f8c772749e4d929cbcbd8a816ae231b9f5566734bafd21ea6bfbbf862da65ccec3a8c00d3a0ac2ae7c039d54eae38d4d28152427d916f5d288adc4f118e5a86b9443402cc70438e6eeb9fa225ff6850395773d38c3949e6281c68b68db120d9829cd5cc7279cc3e0c82f1cd4d6a19f3cabca344f62abe134dda5851fcd84776668449f0924dfa51db8301b2cd422451f16f8fff5f50059c262a6fb021d801213e1cc97a3f43440f1ef122d439b05979cf4cf9297dbee8d5b07e02d1d42acd4b3bcb08b86dfb8914c4a16d3814e5f8d20517c39bda3798724f72a441ae3a7ea80a0964b158a4bc325a76ec095dc822599daa010e724", "21c", "e8c18cb54388ba116db113d3ddc89d710f2f067965e4b7dff7f789a042111068b8f65780cae7fed8c39b5864213b64ecfd26ad8d24c91077f11d718e31604fea9b3615d18d240320cf06eead4707f8ea434e537fa743d475d60ce458d0e0fc9ca9af151a57996fc886b392d925cd10c74505ab1c449e758667241b2a1f8240ba5fcb03cfce6ccd5c65c68ca09c8d065a443874281458c8ee1a8cc776cad803096de3363ea06d9ffab0b3b61c9726eaf5b0b3488fbf092f955fbad4a83c1bd017352e1d1c07e5232a62a875eef715290161d3457d07cc4cf931a6764c4e857c9b100e5a1caadb947291020b54f3115f801d3cbae4d34171079e52a6c7a84a4465cba3cbad2050c023181301f8c772749e4d929cbcbd8a816ae231b9f5566734bafd21ea6bfbbf862da65ccec3a8c00d3a0ac2ae7c039d54eae38d4d28152427d916f5d288adc4f118e5a86b9443402cc70438e6eeb9fa225ff6850395773d38c3949e6281c68b68db120d9829cd5cc7279cc3e0c82f1cd4d6a19f3cabca344f62abe134dda5851fcd84776668449f0924dfa51db8301b2cd422451f16f8fff5f50059c262a6fb021d801213e1cc97a3f43440f1ef122d439b05979cf4cf9297dbee8d5b07e02d1d42acd4b3bcb08b86dfb8914c4a16d3814e5f8d20517c39bda3798724f72a441ae3a7ea80a0964b158a4bc325a76ec095dc822599daa010e724000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "b8db372dbca74b5940f97f50ba8c37a44ed5b916e7a0ab815f8b14b02a8946e3a9fd55fa57a5d037ec10d8937c0ba55ad51373b5c3edfa63de591559e34c4d73590de269b6d6d9d42a2687a0ef5e519c314e36f97079c44e4ce08a29468281e964233cec98c88181e4245f0e20b953fef016237f53d70d65ecd3c839cd5c2e48df1f40e7ecb443a40b3676ea886f27fe653a0c56a7dab1c50cc7526b1c094979910711cce37887446443bc9403191c7a58a2a0fd3ef5e8cac818e30570495303bff305ccbdc2292a001fd4537cea9eaa08e98ed310d1cb824079433ce64232b0018653be0dd4159fd6b05938981a45baed534aa5601a4d88b1c7c12f81ed0e2bef138738e028e12936f162adef2524a85191d1fe9875f790e282af92687d4b99934587e9d6217f479ffd656b1fadd2c5f09eb09c96cc354f7a08785afdbfb60e72c94d4bf8e697830cac6bad2dc2418198e1642fa66e867f45ba812e54fee4897a52410619789ca040001f15ba362f5de19da1ffedee290075d62dfd1eb15e22ac2c62bea4962a2b503cdc1417e87c38bb353567f309121cc93ea0de3766a5baef2d40b5c6996a59721f5450c9d35c65975e10e75df57c86e73f68e5f9a19f42f895d7bd4923dc3c635ee961b43741a00326de60eee98e913eefcf77f4109e6559975d7c5a0dc942d40eb012b27ade6b43a2b43189b7844b44a08d97ea90d7ff", "12c", "b8db372dbca74b5940f97f50ba8c37a44ed5b916e7a0ab815f8b14b02a8946e3a9fd55fa57a5d037ec10d8937c0ba55ad51373b5c3edfa63de591559e34c4d73590de269b6d6d9d42a2687a0ef5e519c314e36f97079c44e4ce08a29468281e964233cec98c88181e4245f0e20b953fef016237f53d70d65ecd3c839cd5c2e48df1f40e7ecb443a40b3676ea886f27fe653a0c56a7dab1c50cc7526b1c094979910711cce37887446443bc9403191c7a58a2a0fd3ef5e8cac818e30570495303bff305ccbdc2292a001fd4537cea9eaa08e98ed310d1cb824079433ce64232b0018653be0dd4159fd6b05938981a45baed534aa5601a4d88b1c7c12f81ed0e2bef138738e028e12936f162adef2524a85191d1fe9875f790e282af92687d4b99934587e9d6217f479ffd656b1fadd2c5f09eb09c96cc354f7a08785afdbfb60e72c94d4bf8e697830cac6bad2dc2418198e1642fa66e867f45ba812e54fee4897a52410619789ca040001f15ba362f5de19da1ffedee290075d62dfd1eb15e22ac2c62bea4962a2b503cdc1417e87c38bb353567f309121cc93ea0de3766a5baef2d40b5c6996a59721f5450c9d35c65975e10e75df57c86e73f68e5f9a19f42f895d7bd4923dc3c635ee961b43741a00326de60eee98e913eefcf77f4109e6559975d7c5a0dc942d40eb012b27ade6b43a2b43189b7844b44a08d97ea90d7ff000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-3bd5614d7d89ea99d47e4a171d5eb80180478a3dd85511adb5b4ee25572b80acab15c86764584ac8f1223a3712bd3ebd94b79fd93f67ad8c99ab2badac83078eff0d750c410f0fed8e337b8e70105b3f38c02b388d51cd8ff2046b5c79315ebc4f5b2f37e8d579b9b3729e8a3326e599f231a7819475a8bd7b4787467ca0009d8bb15121c8d633d2c191791928809dc65c87a79bb30eecd43d8f6ab301cc9da1ed31215a7b2222ac4968f2a894e588e9892e63667f66a213c99144daab0dd1c513022f7c19369b854b807bf3ba65d6bf07452e29319e999c61b9e29a16bb58702dfe071b856cd9d235a3c898b235c3a3e3d807c2747d9662cb980243b1b993ef872d2b210a81f951305b18374ebce215beca0e99c71dc55a51184ad7dd7a23b8146249f9e8baf14aa01ba89e888b514e74c286bef256b0408b44b677a9f6a4d1a364762767d4ba8254a0e84cc63ee5d6147377251be9b7af6cde6341973c88ee8a95f4c4b39dd2fe124d205d1693bf7f8a6ec46faf72f2f82109996cbc8bd48a856e3ae5b4772b7c4976d6fbe0e9b91f755e620e18b25a0ec4394567eb25f7fd25b8fc1969dccb07b10a7e0e3e14399b43037ba142333e793f5c41ab01a56b8952efe2a3857c3a10fd083e5ae16edcde2dfe18f05b4fd00e923e63cdd06ab22fa793d6a421e18528440134987baa0d9eda7431cab351046f164ef33e68464707", "12c", "-3bd5614d7d89ea99d47e4a171d5eb80180478a3dd85511adb5b4ee25572b80acab15c86764584ac8f1223a3712bd3ebd94b79fd93f67ad8c99ab2badac83078eff0d750c410f0fed8e337b8e70105b3f38c02b388d51cd8ff2046b5c79315ebc4f5b2f37e8d579b9b3729e8a3326e599f231a7819475a8bd7b4787467ca0009d8bb15121c8d633d2c191791928809dc65c87a79bb30eecd43d8f6ab301cc9da1ed31215a7b2222ac4968f2a894e588e9892e63667f66a213c99144daab0dd1c513022f7c19369b854b807bf3ba65d6bf07452e29319e999c61b9e29a16bb58702dfe071b856cd9d235a3c898b235c3a3e3d807c2747d9662cb980243b1b993ef872d2b210a81f951305b18374ebce215beca0e99c71dc55a51184ad7dd7a23b8146249f9e8baf14aa01ba89e888b514e74c286bef256b0408b44b677a9f6a4d1a364762767d4ba8254a0e84cc63ee5d6147377251be9b7af6cde6341973c88ee8a95f4c4b39dd2fe124d205d1693bf7f8a6ec46faf72f2f82109996cbc8bd48a856e3ae5b4772b7c4976d6fbe0e9b91f755e620e18b25a0ec4394567eb25f7fd25b8fc1969dccb07b10a7e0e3e14399b43037ba142333e793f5c41ab01a56b8952efe2a3857c3a10fd083e5ae16edcde2dfe18f05b4fd00e923e63cdd06ab22fa793d6a421e18528440134987baa0d9eda7431cab351046f164ef33e68464707000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-982ac9d3603db4a225a5c95238bdfa26cb67f5f1466e087528629a31dd44a8ec98ba92398f81b16dd976de3f4a4e1c88e7f4ac7a87c0678c026a7b8875d8058463ca7c44110d6ba323fd6db02486015015bf920f5303de6442e080177312601342c62bec7bc207a3ff385af385ca6c8b15fc10608e3d959562fbee72b9d4bdb188eac3b5d233143c9c78e0bffbd1a6d552c21f8e32c4f6b4abf8cb3ba514474ac1897e17eee99fea9312f65782f4ce284fb3e09d96a66bf672c2b5eded53df9f969f67c4ae9748df11677601ddeadfdf2477dd81bec1f40e9e8c69a84c490b78b0c72cb52a853982438f9b3cc3ba2789d2d8e1cb43407beaa9db2a6ec88e18591d40cb38473cd6ee6f4d36e0267b02211d738829cfe3c6e12e7719da9cb88379417e223947509b3ae1618c733f931e1b339ef224ec1746c41054013e6900765899654e66eca79041938ee683e561c06f6cca32cbcb5b0546c7333a6178db3b1f26dbd3fd25b3503d2383eaddf8655840609766b76e28783e4bb5c238ec1243af2212c4c3ee1ededcade1a586d8ecb0ad0f4b02f1827d26262c3496d583257c9ea76a31d215f3fd42e9bf5801011b863df2362a22aef05b49c84ed3d449d5373143c721c733c835d4c49a3a429c71fb968ce8a4ca1ac771bd5cb100407f914a4d958d4763f58b51519a0491374d09e7230015219477389bbf919bb67aae4d9edd", "168", "-982ac9d3603db4a225a5c95238bdfa26cb67f5f1466e087528629a31dd44a8ec98ba92398f81b16dd976de3f4a4e1c88e7f4ac7a87c0678c026a7b8875d8058463ca7c44110d6ba323fd6db02486015015bf920f5303de6442e080177312601342c62bec7bc207a3ff385af385ca6c8b15fc10608e3d959562fbee72b9d4bdb188eac3b5d233143c9c78e0bffbd1a6d552c21f8e32c4f6b4abf8cb3ba514474ac1897e17eee99fea9312f65782f4ce284fb3e09d96a66bf672c2b5eded53df9f969f67c4ae9748df11677601ddeadfdf2477dd81bec1f40e9e8c69a84c490b78b0c72cb52a853982438f9b3cc3ba2789d2d8e1cb43407beaa9db2a6ec88e18591d40cb38473cd6ee6f4d36e0267b02211d738829cfe3c6e12e7719da9cb88379417e223947509b3ae1618c733f931e1b339ef224ec1746c41054013e6900765899654e66eca79041938ee683e561c06f6cca32cbcb5b0546c7333a6178db3b1f26dbd3fd25b3503d2383eaddf8655840609766b76e28783e4bb5c238ec1243af2212c4c3ee1ededcade1a586d8ecb0ad0f4b02f1827d26262c3496d583257c9ea76a31d215f3fd42e9bf5801011b863df2362a22aef05b49c84ed3d449d5373143c721c733c835d4c49a3a429c71fb968ce8a4ca1ac771bd5cb100407f914a4d958d4763f58b51519a0491374d09e7230015219477389bbf919bb67aae4d9edd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-6445006404b57c34a9b79ce9b613a8d9852ed1247641cb02b36acd1ed328deeee5560b6fff448cabdcd6eeb7a40dab4b48123c74365de56597bc4655c12c6f8c5a288f648591feae5d7d038f71b02faf537c8c750f80cd375b69999e55de12b89dc95618391c31e1e33dbbc04f314b9f2285836e40bb515662ba8df30c65fee401be421e2bae815fd6d7aa9276b03749c87d7c50ccb6260e0e3180767fbe0f11047455363edd565119d43d9d7a00ca9c53f0877e99e257ecf7a210517c6adfd1d5c532496c1ee5bc82aef6e31dbbfdd33614f4e5d44fc4935d474a8407b753e8201f0fc15a4fe9ca231a8506f5f303ada76c72624ccbeb62a04617411364bb2e7c34683dcb404d15ee323d52c5d697db8f590f4c43de058f954acdbafad2d1c113c13f055aa19f7a2b0252a373c1139d51ead0d5a09b9f0a1402b98831b8236b105ad8a050e83fab04c4495b7b47cc1eee9262c87151b7fb26ddd5e43f017ba425b76042ae9542960b64cddbac9fd937e8f2c9f4f41b92d1f7ce45937ca4c5204ebbc59ea1d02b2e759b3eb0406e675f18efcd47bef97345cb0e94c1fdec902616eb840f07adb8763ad5e421015d64d7db8580bd8b146b95a85999fd41b291f0e2ca8211899d075ebca318f6a9740665509f8878dbe010feb763e3d070be46a7554aed2051bf2a0b5d10f165759e7308950f0535688cbad312fefa0c8ce6ce0", "168", "-6445006404b57c34a9b79ce9b613a8d9852ed1247641cb02b36acd1ed328deeee5560b6fff448cabdcd6eeb7a40dab4b48123c74365de56597bc4655c12c6f8c5a288f648591feae5d7d038f71b02faf537c8c750f80cd375b69999e55de12b89dc95618391c31e1e33dbbc04f314b9f2285836e40bb515662ba8df30c65fee401be421e2bae815fd6d7aa9276b03749c87d7c50ccb6260e0e3180767fbe0f11047455363edd565119d43d9d7a00ca9c53f0877e99e257ecf7a210517c6adfd1d5c532496c1ee5bc82aef6e31dbbfdd33614f4e5d44fc4935d474a8407b753e8201f0fc15a4fe9ca231a8506f5f303ada76c72624ccbeb62a04617411364bb2e7c34683dcb404d15ee323d52c5d697db8f590f4c43de058f954acdbafad2d1c113c13f055aa19f7a2b0252a373c1139d51ead0d5a09b9f0a1402b98831b8236b105ad8a050e83fab04c4495b7b47cc1eee9262c87151b7fb26ddd5e43f017ba425b76042ae9542960b64cddbac9fd937e8f2c9f4f41b92d1f7ce45937ca4c5204ebbc59ea1d02b2e759b3eb0406e675f18efcd47bef97345cb0e94c1fdec902616eb840f07adb8763ad5e421015d64d7db8580bd8b146b95a85999fd41b291f0e2ca8211899d075ebca318f6a9740665509f8878dbe010feb763e3d070be46a7554aed2051bf2a0b5d10f165759e7308950f0535688cbad312fefa0c8ce6ce0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "db924cb4c94fb2a6c034c84370e51aa5134d149ead7d6d5eedf0afc5c9c35ebdfd3724b27177cf340e66750d0870d3c36a1d1f9413ee3695b05c7c51feb669dff56b5ca074db7dad7c752d13c6679d88a34ec095d7d3bf3a50026d33cdbb67db71475a00653f8d42aff2220b6fc3335a9e8ad6aaea5c8d18d2151c75a10ae00c6f1696c0b14775641dd8e1629894900e538fe2c3ab4b0e4cad2a800096861c7e416d29c72b80aa5ca7f01615a4f12f0a1d4c3bec1a2b5deadbe18082fb25cd5bb7e63e74bcda8347bc6a5fd539b02b3c59043e07eca1d5bb646fd8fa5b9f65c3629c04a2063135bedbcc23788080c883aa453c2b7a6b1a25c7228c3c45b0d7e2a8386cdbd852f9ba5508983023b983ef0b7b2bab629987d2369f8aea457f13f3d6f7ee81c3b553f8b8c6465a7c5ab548873fc9d45757efd9921a1eb95a32d8e56d4440f7e0d850f2a2a362626b33a9fcaea30a88686ec0f11e8b0e68017e80b40dc32b8055ad40a02e6195af3786594c1bcab850cc90a1b639e3a93a2a9c472586222cd35fbf9edde32fcaa6a52d513b0c864066bef0d54e4dff8f9124c09ebbcd26dcf580c028ec2ed4c0c49b4d393cededf358a4549ffb3f178fc54c85713f8fdc9c19b2aab748b032d23f2013e13c7074865452f3a52e1d0733f1c730b56e8d7b9b6c2f811d3c489bff3f591765cd569241b4fbe333d0faca56e005825e1e", "78", "db924cb4c94fb2a6c034c84370e51aa5134d149ead7d6d5eedf0afc5c9c35ebdfd3724b27177cf340e66750d0870d3c36a1d1f9413ee3695b05c7c51feb669dff56b5ca074db7dad7c752d13c6679d88a34ec095d7d3bf3a50026d33cdbb67db71475a00653f8d42aff2220b6fc3335a9e8ad6aaea5c8d18d2151c75a10ae00c6f1696c0b14775641dd8e1629894900e538fe2c3ab4b0e4cad2a800096861c7e416d29c72b80aa5ca7f01615a4f12f0a1d4c3bec1a2b5deadbe18082fb25cd5bb7e63e74bcda8347bc6a5fd539b02b3c59043e07eca1d5bb646fd8fa5b9f65c3629c04a2063135bedbcc23788080c883aa453c2b7a6b1a25c7228c3c45b0d7e2a8386cdbd852f9ba5508983023b983ef0b7b2bab629987d2369f8aea457f13f3d6f7ee81c3b553f8b8c6465a7c5ab548873fc9d45757efd9921a1eb95a32d8e56d4440f7e0d850f2a2a362626b33a9fcaea30a88686ec0f11e8b0e68017e80b40dc32b8055ad40a02e6195af3786594c1bcab850cc90a1b639e3a93a2a9c472586222cd35fbf9edde32fcaa6a52d513b0c864066bef0d54e4dff8f9124c09ebbcd26dcf580c028ec2ed4c0c49b4d393cededf358a4549ffb3f178fc54c85713f8fdc9c19b2aab748b032d23f2013e13c7074865452f3a52e1d0733f1c730b56e8d7b9b6c2f811d3c489bff3f591765cd569241b4fbe333d0faca56e005825e1e000000000000000000000000000000", .Okay}, + {.Shl, "6e90d4a8b67bcd83ff7da9865bdbb33c0623a4239511466132ce492c0713d23e5ffae9eb772fa8c1d95ea6a87ecca5892be8e14b3e87afe4f23896dc577178795dff80a35c03b5764787ce1bfc82960114eb6d89a9838476f99c4bd071dcc2dd2b4a000d7c39f4fd3275595de1a86321b3b2d29ff102655a009c84bcf1f27f6ad29d6ae275882ad8368c4f03e260b1aa6af30b136c1d882f72ed8dd0ddb1c8f4160fbe1b7549ec50634fdf40a2c87bca174aa41f6fb3be70bde9734a272af82589750e31bbf5bbb80022e081be74ce73c316f087afa419551e876a7a162214a9c350ead48d2cfa5974d3eb4fe9aad6c7edf5e00a8785fc35d4006df4e501a636fe1b6faa201a97bd4dbf5af074a51a5e1a6814979a0ac56b7e29ed0004a35882e81c3d6f32480438370575328acb984a6949fe8a7cb2f24033df2616656b202b9917374491239358c209d2e61f1d188c10853f720a0329597e1a1a5f942b5f1739dfbb8f80958bb88f57ff1c91eba16324b7395d50cdaac9f091fa7230905e978c30a651942f6837a9879d6bc21819a5b3c30718f493ac9501067ef010b649112af5211e8087486b785bff163d26ed6847261f6bb173531504fdd540f66ac990f4564b48975a37f68ee1f96605044e62ec5e3d50ee066c9406ebd490ce379647d8a639d8e43902766fb993b75cc64f7bb4ca01ed0c146de63f3b8c96bd2650c9", "21c", "6e90d4a8b67bcd83ff7da9865bdbb33c0623a4239511466132ce492c0713d23e5ffae9eb772fa8c1d95ea6a87ecca5892be8e14b3e87afe4f23896dc577178795dff80a35c03b5764787ce1bfc82960114eb6d89a9838476f99c4bd071dcc2dd2b4a000d7c39f4fd3275595de1a86321b3b2d29ff102655a009c84bcf1f27f6ad29d6ae275882ad8368c4f03e260b1aa6af30b136c1d882f72ed8dd0ddb1c8f4160fbe1b7549ec50634fdf40a2c87bca174aa41f6fb3be70bde9734a272af82589750e31bbf5bbb80022e081be74ce73c316f087afa419551e876a7a162214a9c350ead48d2cfa5974d3eb4fe9aad6c7edf5e00a8785fc35d4006df4e501a636fe1b6faa201a97bd4dbf5af074a51a5e1a6814979a0ac56b7e29ed0004a35882e81c3d6f32480438370575328acb984a6949fe8a7cb2f24033df2616656b202b9917374491239358c209d2e61f1d188c10853f720a0329597e1a1a5f942b5f1739dfbb8f80958bb88f57ff1c91eba16324b7395d50cdaac9f091fa7230905e978c30a651942f6837a9879d6bc21819a5b3c30718f493ac9501067ef010b649112af5211e8087486b785bff163d26ed6847261f6bb173531504fdd540f66ac990f4564b48975a37f68ee1f96605044e62ec5e3d50ee066c9406ebd490ce379647d8a639d8e43902766fb993b75cc64f7bb4ca01ed0c146de63f3b8c96bd2650c9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-739686cc12ffdfcfe0ba25b665243b1222798f79107bf53212ae2a9c58c2ed6b565c44efc5f5ae55e8541b70dac6bc877b5642cc707e056b7811691d9c135ecdfd27aaeed16fdc19d834224e198fbcf144e53a5e403932657bb2f52b42510c76b92d6acb03d275016ac168e5e695d359d3c25a688f017bafb80f497e72561f85a2b39850ac567f3740d9e6816478cd9e25d3c736a1a5eddca3125cb150ddaf0d3219a0ff6e59ddade4582808c5858b56f32046f8b6352c9b106b1b1e0fc567d9eafd9ec50cdfe4ea6aa604119b29d4fd4166e90ae6ec9b335c0435ae2e48e21d7579c740054baa5d53b5ac52ac1831844f31280227eced8bed573ee2a4bb5d1213203645a5967c385307b7a4f2d1567a57cea9c08e3fc43323a97fe70779b909f964d3521e3d21bbf6fd35fa7e2f9c79e5337d26c26fbd7993b27687fa65aa73937a0d3184f5b2a188c84cb1cafef717ffa093ae26564e124c22074351580a5c5ea1f49559a18c22c6f1ddf67a5ea3ef0f51dd7fea5030b5812464140fba6c770c3d028dd81afae89343e239bd777f0a85abb5af7dcd88416cfd287ba9c9384ffd23e7a1036dca8cecfe231d73e6bfbb52dfeefb5701c368acfea7f7dc260d3f56cc2abeea6b4b0f3e54263697bb3681e8943e60bfb31e81a20cb744b07b219dd2828b5ef0bf7af7046c3b64087e60c0287d73cb6d71db25576858fd3ac66bb0", "258", "-739686cc12ffdfcfe0ba25b665243b1222798f79107bf53212ae2a9c58c2ed6b565c44efc5f5ae55e8541b70dac6bc877b5642cc707e056b7811691d9c135ecdfd27aaeed16fdc19d834224e198fbcf144e53a5e403932657bb2f52b42510c76b92d6acb03d275016ac168e5e695d359d3c25a688f017bafb80f497e72561f85a2b39850ac567f3740d9e6816478cd9e25d3c736a1a5eddca3125cb150ddaf0d3219a0ff6e59ddade4582808c5858b56f32046f8b6352c9b106b1b1e0fc567d9eafd9ec50cdfe4ea6aa604119b29d4fd4166e90ae6ec9b335c0435ae2e48e21d7579c740054baa5d53b5ac52ac1831844f31280227eced8bed573ee2a4bb5d1213203645a5967c385307b7a4f2d1567a57cea9c08e3fc43323a97fe70779b909f964d3521e3d21bbf6fd35fa7e2f9c79e5337d26c26fbd7993b27687fa65aa73937a0d3184f5b2a188c84cb1cafef717ffa093ae26564e124c22074351580a5c5ea1f49559a18c22c6f1ddf67a5ea3ef0f51dd7fea5030b5812464140fba6c770c3d028dd81afae89343e239bd777f0a85abb5af7dcd88416cfd287ba9c9384ffd23e7a1036dca8cecfe231d73e6bfbb52dfeefb5701c368acfea7f7dc260d3f56cc2abeea6b4b0f3e54263697bb3681e8943e60bfb31e81a20cb744b07b219dd2828b5ef0bf7af7046c3b64087e60c0287d73cb6d71db25576858fd3ac66bb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-d2f25a8284dd7c55d07e4a49179f2ff1f4747148d59c2bf166c52a64d7136e2264e3ff296d2589689b080aa2614f82f465fd788067014e386de68008db09a3b1c693e870547de5f463bd75940ead461025f259582f563dd6bbc3b085e5f6f5308581fa8d74dccf8a3ea8b75acf3aa4b6fd7961fd2a583506b0278195f8a142eda1e462ae146b9221cd74918145e93829028fe56ddf20ff5af33c63ff0f0c2f8aaa27c8e6896534b4ad6a9d9a9df840cd2b28d9171da58d98f76b2570566cb28abb05e3a76a531e917f3a0dac295691fcc29bd2644b198f708fd5a316a94878d554ce23021a8f986ab28ae30be4d6be0db8a5556021b79c6a8d9aa9700cb4c261fb2aeac1c39c76008b47de02b8a8bfd4e4cb935d3d3a06bbee1f6d660e06d3ab1129ec1c56f0001983a4a7ce8e818107a60b1586f71e281ffed3c969385b03b22e344c72f3b18b24eb63f2b72ea23e09370abc3b13f43908bf69081c09b623c0de81b1d38c1a3433b0e1f1b00771baf618204b880c5019003233c56e41d29203cbdf75736975f4acf34be0ebdb5da12085a78489e73f52e3bd9e5c06cfe4ee0e9698e97c7388be80531ca568a1f666ecb298f7b5fbf9ca9f2ea9a87a6dd817222900deb2bcf16fe6d5d615d623e2bbe6cdced1bb7c1760d38efad189bba1605c6cdafaf668641a147be5771cb7235f138239ab0f5a77489e9926cece8c17c307", "258", "-d2f25a8284dd7c55d07e4a49179f2ff1f4747148d59c2bf166c52a64d7136e2264e3ff296d2589689b080aa2614f82f465fd788067014e386de68008db09a3b1c693e870547de5f463bd75940ead461025f259582f563dd6bbc3b085e5f6f5308581fa8d74dccf8a3ea8b75acf3aa4b6fd7961fd2a583506b0278195f8a142eda1e462ae146b9221cd74918145e93829028fe56ddf20ff5af33c63ff0f0c2f8aaa27c8e6896534b4ad6a9d9a9df840cd2b28d9171da58d98f76b2570566cb28abb05e3a76a531e917f3a0dac295691fcc29bd2644b198f708fd5a316a94878d554ce23021a8f986ab28ae30be4d6be0db8a5556021b79c6a8d9aa9700cb4c261fb2aeac1c39c76008b47de02b8a8bfd4e4cb935d3d3a06bbee1f6d660e06d3ab1129ec1c56f0001983a4a7ce8e818107a60b1586f71e281ffed3c969385b03b22e344c72f3b18b24eb63f2b72ea23e09370abc3b13f43908bf69081c09b623c0de81b1d38c1a3433b0e1f1b00771baf618204b880c5019003233c56e41d29203cbdf75736975f4acf34be0ebdb5da12085a78489e73f52e3bd9e5c06cfe4ee0e9698e97c7388be80531ca568a1f666ecb298f7b5fbf9ca9f2ea9a87a6dd817222900deb2bcf16fe6d5d615d623e2bbe6cdced1bb7c1760d38efad189bba1605c6cdafaf668641a147be5771cb7235f138239ab0f5a77489e9926cece8c17c307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-556a109b038e65f62e2b713c08190fd4e5e5228a92400bfe42523e0c185867aea8a056b35c2bb156e3002dd4086ffb8da46385492509238fcf18c7c0b85f4a434de70798b8c509403d109235491e300dff962bcfb112fb8a4b2e05956cca85b4d15293f67955456e301bedf6b6b667d26f1ae26a8c9edadbb375d1c6b01728984957bd2f7cea2d11294b23cd069e1d1b27b29c6de099eeb4122e95429c662859a0cd6f9858f2f69ebecc459c221434b3ee76354bcc83bb16b0671fb288c27c619d675cedfbef4caa180445ec872974982aeabeea04ed9f5ca1ea427dd88ee89855c15899f449c524c8ddd3878fe422693c132af815f9906265ad7f83c0f88140e9ed0a8d6a8da148ed591ae0598e87ba8854ef3334c9d1b0278975aa87c5841c34419a7533b9a999ba3a950359e28542a8a62aea288f683f71362656e28d691453f09603edefde8b9f5e0ce0daa9b446bb208332e215ae0f38f3617c49c99dc909540a9ad167f87301fbab22bc19743cc9ffd1ed1f83b3af1e23d7f455fef7cb1884a070714ca037bf8fe3ffadd75467128de747dfb2c2d30e95dc30457b24797de4d27365f851c3129ed92053df4f0c7b8eed489fa8aa0d88909e8c6376e072e7bdd9c170ad120a933a15aff84b5071a197e048ec7a697f95293595daa1db8330ae46a68bdad832f7647cb9a1f7ed30a90088d8fa2b1c0654caab819ccc2799", "1a4", "-556a109b038e65f62e2b713c08190fd4e5e5228a92400bfe42523e0c185867aea8a056b35c2bb156e3002dd4086ffb8da46385492509238fcf18c7c0b85f4a434de70798b8c509403d109235491e300dff962bcfb112fb8a4b2e05956cca85b4d15293f67955456e301bedf6b6b667d26f1ae26a8c9edadbb375d1c6b01728984957bd2f7cea2d11294b23cd069e1d1b27b29c6de099eeb4122e95429c662859a0cd6f9858f2f69ebecc459c221434b3ee76354bcc83bb16b0671fb288c27c619d675cedfbef4caa180445ec872974982aeabeea04ed9f5ca1ea427dd88ee89855c15899f449c524c8ddd3878fe422693c132af815f9906265ad7f83c0f88140e9ed0a8d6a8da148ed591ae0598e87ba8854ef3334c9d1b0278975aa87c5841c34419a7533b9a999ba3a950359e28542a8a62aea288f683f71362656e28d691453f09603edefde8b9f5e0ce0daa9b446bb208332e215ae0f38f3617c49c99dc909540a9ad167f87301fbab22bc19743cc9ffd1ed1f83b3af1e23d7f455fef7cb1884a070714ca037bf8fe3ffadd75467128de747dfb2c2d30e95dc30457b24797de4d27365f851c3129ed92053df4f0c7b8eed489fa8aa0d88909e8c6376e072e7bdd9c170ad120a933a15aff84b5071a197e048ec7a697f95293595daa1db8330ae46a68bdad832f7647cb9a1f7ed30a90088d8fa2b1c0654caab819ccc2799000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "2a5cc6dfca28b600c5c443dc9e364c949ff11cf6be0fbc3dadf3dc3f9b02d2b8212d70c3c28150dbb94c5aefb8125aca34602c919611e03c6c0cf379884eea31944bfe3af36c7b8f0f504d274f2c52d62a0fdebd4adb94f3a7bfedab66fe27dac3fde74847fd65da7c9c29fb93be70d7ac16b9fdc8080863a5a90dba065cecc2156ee2a1bc89d183931944cc9ca21c0f854b3679487e2f53ed8fda4d0759a823e7a2863ee3b542111a437aa94c835b7dc50035ba1060c7c63f1ec395be9c67b6b16cf4a79410bc7948bdeb0c9fbb24322e773ce9d189d67acaa1945466861c8130eeec7bd32cb36206dba386f01d71e5be168e54904b91ff19cf145c38ff0cd32dbf171c9ca34dbe02659fba8cddc259565d57190a95acab575ba7efb4bce9495a848ead1584cc726e4928b125843c09d01203eddf3d57abc8a6b8c2848725cbfccfc0a58660e4c7d27d40d39704538ae73415334aeaeb6e957e11cab9cf8124255cc036a43dd2d2a01fd2fbc05d4ad497a9ce3995d36a9afc81435fd3470069c54b06c432665a3d197106fc4758e92bafa02c4d00a8e57af2c043470ad2812622677e6ae13bba02b40c374ebcbcd01ffacdc7193b4006ebfbfdb8eaf400981342f434c0b648b3692b656ea9483c51ee9a1aae9d665a60a45a12921823ff28d600bc9d082e8d8a829dbcd5f7ac933ae277bb88b31bcaadc9bc46c3994facdf6c", "1a4", "2a5cc6dfca28b600c5c443dc9e364c949ff11cf6be0fbc3dadf3dc3f9b02d2b8212d70c3c28150dbb94c5aefb8125aca34602c919611e03c6c0cf379884eea31944bfe3af36c7b8f0f504d274f2c52d62a0fdebd4adb94f3a7bfedab66fe27dac3fde74847fd65da7c9c29fb93be70d7ac16b9fdc8080863a5a90dba065cecc2156ee2a1bc89d183931944cc9ca21c0f854b3679487e2f53ed8fda4d0759a823e7a2863ee3b542111a437aa94c835b7dc50035ba1060c7c63f1ec395be9c67b6b16cf4a79410bc7948bdeb0c9fbb24322e773ce9d189d67acaa1945466861c8130eeec7bd32cb36206dba386f01d71e5be168e54904b91ff19cf145c38ff0cd32dbf171c9ca34dbe02659fba8cddc259565d57190a95acab575ba7efb4bce9495a848ead1584cc726e4928b125843c09d01203eddf3d57abc8a6b8c2848725cbfccfc0a58660e4c7d27d40d39704538ae73415334aeaeb6e957e11cab9cf8124255cc036a43dd2d2a01fd2fbc05d4ad497a9ce3995d36a9afc81435fd3470069c54b06c432665a3d197106fc4758e92bafa02c4d00a8e57af2c043470ad2812622677e6ae13bba02b40c374ebcbcd01ffacdc7193b4006ebfbfdb8eaf400981342f434c0b648b3692b656ea9483c51ee9a1aae9d665a60a45a12921823ff28d600bc9d082e8d8a829dbcd5f7ac933ae277bb88b31bcaadc9bc46c3994facdf6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "d613243338f817fc296f4d77a5a0fb313a92e268427185cf747ff901ce82a959d2845b078d69c983da189f5a2ab8668a0a0cf324f3ea823ab6e018c61c15a177bc3506a093b0d0de123926214793aa9bb1e2a46410ac8aae0cc8c4c24384818354dfc16a66892621fa4fd13d9c610cffff96afefa3b2ef49a06f1b1a122e8070ef3bd2913dc29eefe57306d7c3f3f78316f86de346bd0d68a15c9d64b8a89bd3835c55239f49b5324c55bd593fa8b2c75387b41743aa8acd6e76af92d015d256162279140b16f9d00e73a76b777cb3e3ed1594658e7237c10eee9ca79c385c1708b3485588dcc76501c911c7c392f8a8b7a8cda529daa678f497057eef1b430c890c880fb128d5162f1b8dc7f7d1571b929da5cb2cf1f775fc32e6c714d91e608f40a4ee16229870ae52c8d4d7028a18567b8a980fbf677db2845d9f3befe0dbfd139a743b11b59614286d6b7032e8707ed5ea0d8b98474ffdbf50c93b0ba8bb567626fce25fe25236c030fb99bf19f88368d64efe5239b6c2aba6ea99a02941d723ce49a2de6f4c2024d46aae9965fff64cda51d9c6d2ce93508fd17f76c378863916a192dfd0d96f1d9309b05eb7dab4e7c8fae1c13f74846d7905cf513ab58e18f8da7f0a766cab3d30b77bc72ff55177939af1b8ada4fc54fd72a5e53ec14fbffa5abf7ce318260209296a3927263174bc0b4b88be44a50d67d42316b56a", "258", "d613243338f817fc296f4d77a5a0fb313a92e268427185cf747ff901ce82a959d2845b078d69c983da189f5a2ab8668a0a0cf324f3ea823ab6e018c61c15a177bc3506a093b0d0de123926214793aa9bb1e2a46410ac8aae0cc8c4c24384818354dfc16a66892621fa4fd13d9c610cffff96afefa3b2ef49a06f1b1a122e8070ef3bd2913dc29eefe57306d7c3f3f78316f86de346bd0d68a15c9d64b8a89bd3835c55239f49b5324c55bd593fa8b2c75387b41743aa8acd6e76af92d015d256162279140b16f9d00e73a76b777cb3e3ed1594658e7237c10eee9ca79c385c1708b3485588dcc76501c911c7c392f8a8b7a8cda529daa678f497057eef1b430c890c880fb128d5162f1b8dc7f7d1571b929da5cb2cf1f775fc32e6c714d91e608f40a4ee16229870ae52c8d4d7028a18567b8a980fbf677db2845d9f3befe0dbfd139a743b11b59614286d6b7032e8707ed5ea0d8b98474ffdbf50c93b0ba8bb567626fce25fe25236c030fb99bf19f88368d64efe5239b6c2aba6ea99a02941d723ce49a2de6f4c2024d46aae9965fff64cda51d9c6d2ce93508fd17f76c378863916a192dfd0d96f1d9309b05eb7dab4e7c8fae1c13f74846d7905cf513ab58e18f8da7f0a766cab3d30b77bc72ff55177939af1b8ada4fc54fd72a5e53ec14fbffa5abf7ce318260209296a3927263174bc0b4b88be44a50d67d42316b56a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-7bfaa447e89d31a33317733ef0be9d795c08a7e0f70f5ed9d0ec6816f5a42d8f9484d4be2f113c657e7f4bcfdf73d8a1b22d0d635bfba772b585b4186a4c3e7a80d4d67bad34b75336ae2141802884775e98e1794c958cdf7acd1a53d320052fe0aa942953a4aeca0b910028007fe1fdcfbb9ec7912f4c03e76e5685791675f7ce6794372b0626906e76ae0b227e3f656e64b43c9b7740ec20e87384bc5772710a19ed8549f823b4f6fe5d95cc1fa8f80d5938e23ee60f81c0b47830c18ed587909abad14d718f2f661d2095e11728a7849dfd6752b5b0f154bf76ec61ab917f586d48e6d62af627570747cdb797d1836f6e30c50b64fae46fac54e8e1cc7a4d73ea4e653aeacd47bbe3270859267bb8ae7025d0474cd39548ee09d4baa35beebbb3ec36d61604d473e05a59b598d8e37035116f184e0827f05dabc554f7d9bac7980fe08a182200ab2e8041103594eb7b53ac8fa25c32685177e67cc5c1d51db1452f920f9711c7451e455cae00ccb0f5f52c6e737549c1941583cf8158209bdf7f7aee75835c31cc295ac934d077b4b1850524e67108b040504c77eabf47e3651f59f0e32c6aefab95a89e1ea0882762889578c6577d4b7e267a4c6d2c537dbb1cc258e32b3eee6408bf04393270b75191729e5f75bcff766825c4c36877ffec244d838cd09ef6e66cbf33b195d46c73a9cbaaef2691e3513cbbeaa965d535", "258", "-7bfaa447e89d31a33317733ef0be9d795c08a7e0f70f5ed9d0ec6816f5a42d8f9484d4be2f113c657e7f4bcfdf73d8a1b22d0d635bfba772b585b4186a4c3e7a80d4d67bad34b75336ae2141802884775e98e1794c958cdf7acd1a53d320052fe0aa942953a4aeca0b910028007fe1fdcfbb9ec7912f4c03e76e5685791675f7ce6794372b0626906e76ae0b227e3f656e64b43c9b7740ec20e87384bc5772710a19ed8549f823b4f6fe5d95cc1fa8f80d5938e23ee60f81c0b47830c18ed587909abad14d718f2f661d2095e11728a7849dfd6752b5b0f154bf76ec61ab917f586d48e6d62af627570747cdb797d1836f6e30c50b64fae46fac54e8e1cc7a4d73ea4e653aeacd47bbe3270859267bb8ae7025d0474cd39548ee09d4baa35beebbb3ec36d61604d473e05a59b598d8e37035116f184e0827f05dabc554f7d9bac7980fe08a182200ab2e8041103594eb7b53ac8fa25c32685177e67cc5c1d51db1452f920f9711c7451e455cae00ccb0f5f52c6e737549c1941583cf8158209bdf7f7aee75835c31cc295ac934d077b4b1850524e67108b040504c77eabf47e3651f59f0e32c6aefab95a89e1ea0882762889578c6577d4b7e267a4c6d2c537dbb1cc258e32b3eee6408bf04393270b75191729e5f75bcff766825c4c36877ffec244d838cd09ef6e66cbf33b195d46c73a9cbaaef2691e3513cbbeaa965d535000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "7b4fe7c6de7549f6f055aabe056316065aaa3ad9d5dfef650e18e7e7e6555055dad82ad6a9f03095ad076e15cd92a03919161f4b41c3104e3e28cc87d385cfcfb366afda9962a9429a44f587d78a47a932a7862d0beb94ef648cb71fa5849d5583b6ec2abdf9b19eda5905b13ab3afaa3bca23fee68dfe0ea98fd6ba1a7c1145b02d27fffcbf7c5d02cf868db347baf10ed05bef49636290a8c3a923798c83c8783cddb2f85d06867e145c19351f8c6033daabadc9840e297b775bf2ce23b4459064572cf2d1f71bca272e1eb40327eddc8c5f444f04b4a2d88886eb96c6d2937821e228e07a17b022802dc6c95a5e2506098d81749cb932335075717dd5fe10d94dfca544b7474a78a287dcd9a7091cab987bab21d57326eec98c879e4e98bc014188ce5b65b83359a678cb979f839e4e0a0cb291c220e4190ed659e97040d47e04a50a408254af74babab6021e1580197d31d799634ae92f022b80971ca1a2062c7b8662f97e903555f339fee6fcfc3f032f25c184afb1afc94ef5841295f6b6ece68ef41f375ca26c5779bafe4c2a8135681a50f6f0ae98f1a566c6f48f2966c54f0d32aad7ead0760341cd5b2d152f2403d5d963d8112ca03ad1db3cd785fc7cd03ef2612505ff1959a2d84482cb22c1402520768f16f4edd264115de2cc94c30de4d20a7920a6365ad2011f6cefa28387a3243183e08dcedc1265d1a17c", "1e0", "7b4fe7c6de7549f6f055aabe056316065aaa3ad9d5dfef650e18e7e7e6555055dad82ad6a9f03095ad076e15cd92a03919161f4b41c3104e3e28cc87d385cfcfb366afda9962a9429a44f587d78a47a932a7862d0beb94ef648cb71fa5849d5583b6ec2abdf9b19eda5905b13ab3afaa3bca23fee68dfe0ea98fd6ba1a7c1145b02d27fffcbf7c5d02cf868db347baf10ed05bef49636290a8c3a923798c83c8783cddb2f85d06867e145c19351f8c6033daabadc9840e297b775bf2ce23b4459064572cf2d1f71bca272e1eb40327eddc8c5f444f04b4a2d88886eb96c6d2937821e228e07a17b022802dc6c95a5e2506098d81749cb932335075717dd5fe10d94dfca544b7474a78a287dcd9a7091cab987bab21d57326eec98c879e4e98bc014188ce5b65b83359a678cb979f839e4e0a0cb291c220e4190ed659e97040d47e04a50a408254af74babab6021e1580197d31d799634ae92f022b80971ca1a2062c7b8662f97e903555f339fee6fcfc3f032f25c184afb1afc94ef5841295f6b6ece68ef41f375ca26c5779bafe4c2a8135681a50f6f0ae98f1a566c6f48f2966c54f0d32aad7ead0760341cd5b2d152f2403d5d963d8112ca03ad1db3cd785fc7cd03ef2612505ff1959a2d84482cb22c1402520768f16f4edd264115de2cc94c30de4d20a7920a6365ad2011f6cefa28387a3243183e08dcedc1265d1a17c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "eead27a7c7094439f2d45b85b25f6435747cc5135e5c3f144f18cc2619075dcec9421b50c1412ea2fd3997ad375a43cc219ae8ad6822c490d5da7238791a24dc3bf41bce3a7ef1b3ae9d9c4324a0ca2235154d40c32b07b6e20bc496d892aad4a522e413a7cfd2c40ca2f38f5a6be8c48d66aa561171a86cfbd806bc70a7950fa4ab01ccbaba58831d25773b8d876a176df35df144bec3c90cac6bc51571e929d391c2b097acb5a586b5cf76c5efb99a62708eec6f0a401a21e44d40610b6c55284ffd6a2015c497bd34bcc3f73c1fe2458826de42540d1d87c6cbe97534fe1fd10b949572c30d4ecf9c17e1a68d82a70cd17c0cb964c22fef686d12ca28950fc04df91c4409f078819bfb74bca7619c2d5f23339ab746bfdb7359d34809bbae813d080011988e4cbf9d7e8294189c28a2eedf116fb7398556d0a2fc815473f007d6e64305004d98827321d48fc9b450ebfb552a43a4d2ccae5a2a01118a8148b2dd1c08723dffaef827c7d1c55245df36630b23397f892527c8e0f4f091bc3f701508996aed79310e7a1682ce20c7ed5b954963cbc27792b6b1a5ca8fec16f47d39451a8dad73023294a3c41b0ae037e70e37003b47d2e18397d5098ebbbd3f991562f14d0f66edb4693e5a4e1ae84cf491007d1015b1b4cae21d7671019bc0f5e6b652938768178d57e9d183cfe7974606cc24ff8d709899bf72fe5537574e", "168", "eead27a7c7094439f2d45b85b25f6435747cc5135e5c3f144f18cc2619075dcec9421b50c1412ea2fd3997ad375a43cc219ae8ad6822c490d5da7238791a24dc3bf41bce3a7ef1b3ae9d9c4324a0ca2235154d40c32b07b6e20bc496d892aad4a522e413a7cfd2c40ca2f38f5a6be8c48d66aa561171a86cfbd806bc70a7950fa4ab01ccbaba58831d25773b8d876a176df35df144bec3c90cac6bc51571e929d391c2b097acb5a586b5cf76c5efb99a62708eec6f0a401a21e44d40610b6c55284ffd6a2015c497bd34bcc3f73c1fe2458826de42540d1d87c6cbe97534fe1fd10b949572c30d4ecf9c17e1a68d82a70cd17c0cb964c22fef686d12ca28950fc04df91c4409f078819bfb74bca7619c2d5f23339ab746bfdb7359d34809bbae813d080011988e4cbf9d7e8294189c28a2eedf116fb7398556d0a2fc815473f007d6e64305004d98827321d48fc9b450ebfb552a43a4d2ccae5a2a01118a8148b2dd1c08723dffaef827c7d1c55245df36630b23397f892527c8e0f4f091bc3f701508996aed79310e7a1682ce20c7ed5b954963cbc27792b6b1a5ca8fec16f47d39451a8dad73023294a3c41b0ae037e70e37003b47d2e18397d5098ebbbd3f991562f14d0f66edb4693e5a4e1ae84cf491007d1015b1b4cae21d7671019bc0f5e6b652938768178d57e9d183cfe7974606cc24ff8d709899bf72fe5537574e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "f19a078b12eb3ef03aefbc917054bbe8f8fd76a932256a91d414b1c439e710a455b72a6187bbc37accdd510a836e75bf738f4ce42695974ffdd262ad090c8f9aa312ee47bfe35c376affd866e481a4f70af67edd819dbbf3490f256e14c34b15ae6137499a4fb153a16c0e37e0d9929a2e8eaf285fbf7c02dbf7f8a2c761a728091c80b7493fbed091586bf63d233fcca9b7033d59c288368aef2ff0339e8ae2d153dbc5e83465549bbb18ce66ddfb8d1317ee59ba769682d16cd2d6ed6006531b82b1d3af75099d6f5296478053ff9c24e4ef497190193bd7baf314eb68574ab4938b5904f139d26702cac3c20c7bd40613a20e713476acf5ec24af9ba6e2d83d73767fac76898b551f2d74c4587a926d54637f27f8fee526ec851394ff49cdbc23f493988f82a29f8f0643d31d1fb279a5bba5fb1c006d17c75ad03ddcff290d93df537a31812261a8bd4a4b39ce7c81dd65f8ae73b8ffd04b68b3275c2e91175725b00ed92371dd7f9ed93a9b96622dc55d01ce8f43be09d364a9c5c7259e7fe383f8950c8263c568d35775490a34631c9da03c062cc89512b7bd2fb308c30a0930dc6a6869d1c6695bbb45505e8ff07ae2e6da1674e9fd7b99ca010eeeb2cf94a1127268ffc8acf12193e39e8272f7cc52d838d8921b0646fde22b6d88f08458e1c4d7562ca5ce07113d46f500eedc728109fb2a6d38dc7c79e583b66530", "12c", "f19a078b12eb3ef03aefbc917054bbe8f8fd76a932256a91d414b1c439e710a455b72a6187bbc37accdd510a836e75bf738f4ce42695974ffdd262ad090c8f9aa312ee47bfe35c376affd866e481a4f70af67edd819dbbf3490f256e14c34b15ae6137499a4fb153a16c0e37e0d9929a2e8eaf285fbf7c02dbf7f8a2c761a728091c80b7493fbed091586bf63d233fcca9b7033d59c288368aef2ff0339e8ae2d153dbc5e83465549bbb18ce66ddfb8d1317ee59ba769682d16cd2d6ed6006531b82b1d3af75099d6f5296478053ff9c24e4ef497190193bd7baf314eb68574ab4938b5904f139d26702cac3c20c7bd40613a20e713476acf5ec24af9ba6e2d83d73767fac76898b551f2d74c4587a926d54637f27f8fee526ec851394ff49cdbc23f493988f82a29f8f0643d31d1fb279a5bba5fb1c006d17c75ad03ddcff290d93df537a31812261a8bd4a4b39ce7c81dd65f8ae73b8ffd04b68b3275c2e91175725b00ed92371dd7f9ed93a9b96622dc55d01ce8f43be09d364a9c5c7259e7fe383f8950c8263c568d35775490a34631c9da03c062cc89512b7bd2fb308c30a0930dc6a6869d1c6695bbb45505e8ff07ae2e6da1674e9fd7b99ca010eeeb2cf94a1127268ffc8acf12193e39e8272f7cc52d838d8921b0646fde22b6d88f08458e1c4d7562ca5ce07113d46f500eedc728109fb2a6d38dc7c79e583b66530000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "ccbaae56971ab1c77d986bae3a46f5cf8d6427e122991f89e3f5a98cbf35c9236c3ac435d4842ea5a4c451ad2cdf8520eaee29b24665d41f98aad0149e4becc3267ebcea9373780fd86836e926646e53e81fdf94eec0fefe458a32e1f7fb710d0dbfeb9398d676ec9cb6fff73b438bd20f486a5111a529d451afbc2ef8441c76e25bd64bf6c904e2c448f1391af2c5975000e4ea39bcad225bedb6749c02126a39a6e15bd57675e5720cbcd2937750433d1d198696d8a445e69234391e2166a2bd72b670144eb8c834191d317b443acd2389b66f30f9d9e7bd6258ae911af7a3e1e396a736c419ecaf97ca6f0f92d848896f3a3f5139ac2e586136b34d6d7930808b5dd322048c7c80e4fcb5d0cf3979fe13ad3dec731d0d9f09acdbd2620220fe0a1c183b3dab22ea7eb8ae4557ace7b12ba54f0696143360e1752f5340d183fd99f3e7d8bb491b694e3b22dae1c0b15b976642e9b1ef434a2e69df4a8c8be78f0f0485243f3e1d72afa60d2b09d0deadb9f7049f531be0916b1e5609411331504a6ef35fdc7c2424c7d9e17d428074f9b0873e81f7a570650f311fc889be69db247c2bd9535ea8d8655c8234f8bf35a99a901e22c6d61ced789ed1b994ca43d2134d2a1196f6fdb661da0774d335f3c4f71b250aa8a812372434840a0b6e7104c713923aa35bf1231121b049318cc8839ccac0698f9b17bd63d141403a353a", "78", "ccbaae56971ab1c77d986bae3a46f5cf8d6427e122991f89e3f5a98cbf35c9236c3ac435d4842ea5a4c451ad2cdf8520eaee29b24665d41f98aad0149e4becc3267ebcea9373780fd86836e926646e53e81fdf94eec0fefe458a32e1f7fb710d0dbfeb9398d676ec9cb6fff73b438bd20f486a5111a529d451afbc2ef8441c76e25bd64bf6c904e2c448f1391af2c5975000e4ea39bcad225bedb6749c02126a39a6e15bd57675e5720cbcd2937750433d1d198696d8a445e69234391e2166a2bd72b670144eb8c834191d317b443acd2389b66f30f9d9e7bd6258ae911af7a3e1e396a736c419ecaf97ca6f0f92d848896f3a3f5139ac2e586136b34d6d7930808b5dd322048c7c80e4fcb5d0cf3979fe13ad3dec731d0d9f09acdbd2620220fe0a1c183b3dab22ea7eb8ae4557ace7b12ba54f0696143360e1752f5340d183fd99f3e7d8bb491b694e3b22dae1c0b15b976642e9b1ef434a2e69df4a8c8be78f0f0485243f3e1d72afa60d2b09d0deadb9f7049f531be0916b1e5609411331504a6ef35fdc7c2424c7d9e17d428074f9b0873e81f7a570650f311fc889be69db247c2bd9535ea8d8655c8234f8bf35a99a901e22c6d61ced789ed1b994ca43d2134d2a1196f6fdb661da0774d335f3c4f71b250aa8a812372434840a0b6e7104c713923aa35bf1231121b049318cc8839ccac0698f9b17bd63d141403a353a000000000000000000000000000000", .Okay}, + {.Shl, "-a3a542cb7965ae4d6f71717a7ffb254e922d215f80cfc8126d26bfe873b975e39260cc2d06a252c12c81ac61c1c43ec60667ac53dc86b3b901d79ca905a2937e5ced17b89d8e5ffbbb9d4fd26ce01a22ba1bb2e3b693ad207446c7dc15552b4b5ee439be531c5bdca22ebfb1b14df29a4b71162d0b176290f23f92bfc2f57d8e260d09524a29c3f11752d90cd075e46b0b958614e61e248030dfd4eb24440ecfc05591e94a5eb4669dbb508f71d450d7b9c2e7922806866810f3ce8720e9b27f63f7a8cd3337d4064734954ce3d03c1cf467fe9063e65822cb92c14cb7e989362b95b0643b8a9e5559d998356cf2c1e544fb99cb96fb8ee661d05de821fae4776f545a7e99b6dabf88bd9c4c213b147e1aa22093718aa8b7e2d91ba65697b6053d934b0eda35cb9945a8b17e00ac515731a41f1d988c3fbcb271609308f5419b6a700f8e337b4f2c5feb91dccccd2c872efe5b7b447be849b0281d0f09b6f2ef7aebbc613d3bdd3733fe0ee137ed89c39ca9d459abd9c699cecd9f8ddb578e8fd626a6f1270d51996b24616ffbf98b7416d7e698f12c69a055132035195f4bacc5113d576ed509427294a10479adc960cf71634323924c1df7d002088174412f66aab8b5dc30eb654d15ace89df7f8b039b0c23e2ff3e0a334556a01af2c8977725a5cfe75fd124909794eacf42b74261763f92549cd049725e8a4ce22e20e41", "258", "-a3a542cb7965ae4d6f71717a7ffb254e922d215f80cfc8126d26bfe873b975e39260cc2d06a252c12c81ac61c1c43ec60667ac53dc86b3b901d79ca905a2937e5ced17b89d8e5ffbbb9d4fd26ce01a22ba1bb2e3b693ad207446c7dc15552b4b5ee439be531c5bdca22ebfb1b14df29a4b71162d0b176290f23f92bfc2f57d8e260d09524a29c3f11752d90cd075e46b0b958614e61e248030dfd4eb24440ecfc05591e94a5eb4669dbb508f71d450d7b9c2e7922806866810f3ce8720e9b27f63f7a8cd3337d4064734954ce3d03c1cf467fe9063e65822cb92c14cb7e989362b95b0643b8a9e5559d998356cf2c1e544fb99cb96fb8ee661d05de821fae4776f545a7e99b6dabf88bd9c4c213b147e1aa22093718aa8b7e2d91ba65697b6053d934b0eda35cb9945a8b17e00ac515731a41f1d988c3fbcb271609308f5419b6a700f8e337b4f2c5feb91dccccd2c872efe5b7b447be849b0281d0f09b6f2ef7aebbc613d3bdd3733fe0ee137ed89c39ca9d459abd9c699cecd9f8ddb578e8fd626a6f1270d51996b24616ffbf98b7416d7e698f12c69a055132035195f4bacc5113d576ed509427294a10479adc960cf71634323924c1df7d002088174412f66aab8b5dc30eb654d15ace89df7f8b039b0c23e2ff3e0a334556a01af2c8977725a5cfe75fd124909794eacf42b74261763f92549cd049725e8a4ce22e20e41000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "d3c9c6fa0297edd8f3fb9ca346a7bfbff1e954a630c73148f1f1d642d38682dc7e459cdb109743aa6e1af7449302280ad00ae53fa19d8c3d6ccbd50593b9754416f7ffb301be21be04c667e260ad2d1378088c50eab3a997fab8b59706a4836ae57929e5d3b19bb73ffa22b7d7bc548fa28553117f06e116665c9a5ab05fe4acf0b7292559cc511cf7fb11bdb46b8814a9c413e372333564b15c4c41353817df1c325eadbdbdc29d8c121cf2c097ecadf70d83f9521d6e69efda98aea418c41d7b56d8a4cf04b3f193f274451c267b36c4208ffa383bc12c7130ab021a7d1376e1edb6f4c933934e213f4fc6fe2c74bca1403c87262b653c884f5af458e2c5fcbb81b763f9755c0254542fa8b3d13461cebaee3456f8572f933e5180cd35701cd7f61d3dd5a7720f8203a38a7ecff28e6d0085deb0dae23e846a8670b743b3fcbe8354d3d3752971b30fdfbec181808c907fec1a54d3a270736617f21de298acd183da20727ae8ac20075e50f6dba8f8ebddaa07ab3fd6dcc11c54da1ce07a6b31434051ee34e07679d08853cd493c912e49a74305a186943efb829b2c38cfa4e2bd474e7921c6b7958c522e4a075b96c50b8636c0625de37cac9127ae4e3dabe2bff552244d10504e7425c1492a1dd2e7815a4e9af8fd1d2f38330ebb872a30a866c3e13b40a958b173915b96107e0fdd810793b1085a9ff50339c85e5339e9", "12c", "d3c9c6fa0297edd8f3fb9ca346a7bfbff1e954a630c73148f1f1d642d38682dc7e459cdb109743aa6e1af7449302280ad00ae53fa19d8c3d6ccbd50593b9754416f7ffb301be21be04c667e260ad2d1378088c50eab3a997fab8b59706a4836ae57929e5d3b19bb73ffa22b7d7bc548fa28553117f06e116665c9a5ab05fe4acf0b7292559cc511cf7fb11bdb46b8814a9c413e372333564b15c4c41353817df1c325eadbdbdc29d8c121cf2c097ecadf70d83f9521d6e69efda98aea418c41d7b56d8a4cf04b3f193f274451c267b36c4208ffa383bc12c7130ab021a7d1376e1edb6f4c933934e213f4fc6fe2c74bca1403c87262b653c884f5af458e2c5fcbb81b763f9755c0254542fa8b3d13461cebaee3456f8572f933e5180cd35701cd7f61d3dd5a7720f8203a38a7ecff28e6d0085deb0dae23e846a8670b743b3fcbe8354d3d3752971b30fdfbec181808c907fec1a54d3a270736617f21de298acd183da20727ae8ac20075e50f6dba8f8ebddaa07ab3fd6dcc11c54da1ce07a6b31434051ee34e07679d08853cd493c912e49a74305a186943efb829b2c38cfa4e2bd474e7921c6b7958c522e4a075b96c50b8636c0625de37cac9127ae4e3dabe2bff552244d10504e7425c1492a1dd2e7815a4e9af8fd1d2f38330ebb872a30a866c3e13b40a958b173915b96107e0fdd810793b1085a9ff50339c85e5339e9000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-cf9b7d84cb5c3e92317ee7d83922e7e5c3236f8f1c2fd53729795e1302e00866ad78e979d1b881064c18e0f1a2871074c5e741563865357a40bd312f4116e25b48c6ffba95012a7a4a4a4537f213164a00164972f9566f77006e81739caf74ae0c41be11c9e4f6b11a428f580683d8f2dca8adf2ed91aceb112145e2e6a8a9f255462ce62ce266b09e0b91077c3b721418fa649572eae2e454f29af76b6871f59bb811df86a93fe73533ab4d044a017ae480e6d55c585d71ee755b7711b5e34639978b6e3cf2700fd20d8b5b59698e60ee0a9ee64dd3c4f388aa1d589645d5ff365e841d30846f12e18e52c17459c7fe6f52f2dd55f20f24fb4990dafb7f962d11eeb464352ae9240d0017d00a61ed0a7e3ea62ba0832a489b6c7016c822665607a3f780aaef5c7c8ce697723b973d0ab4b5067d45f3e2605306bcb5156f274771b8b9845c5fafe1c4a2a016c1682ddd85864f66a7d9a9bfdd6fe2a908e8bafdf964a72fcde2ab131b2bb2aef3478e54da8d41404f64d556bb665210e26405650cd37c5bc89be1c0642bee57f278995d331249a8eb44647b9a35affbadad7ae6888b180df3ed6a721728aaedfb12e795fb63e7fe76ab9520c71d62e3ee874cbd3e5c115cdc118af93e1ee451a1d2dce8775ad8cf0e07b7610779ab0669eaa81a11dc85bdbe25dbd6b366e9d2d4d199a2a145a27473f8490ac989df046a78e7b0", "78", "-cf9b7d84cb5c3e92317ee7d83922e7e5c3236f8f1c2fd53729795e1302e00866ad78e979d1b881064c18e0f1a2871074c5e741563865357a40bd312f4116e25b48c6ffba95012a7a4a4a4537f213164a00164972f9566f77006e81739caf74ae0c41be11c9e4f6b11a428f580683d8f2dca8adf2ed91aceb112145e2e6a8a9f255462ce62ce266b09e0b91077c3b721418fa649572eae2e454f29af76b6871f59bb811df86a93fe73533ab4d044a017ae480e6d55c585d71ee755b7711b5e34639978b6e3cf2700fd20d8b5b59698e60ee0a9ee64dd3c4f388aa1d589645d5ff365e841d30846f12e18e52c17459c7fe6f52f2dd55f20f24fb4990dafb7f962d11eeb464352ae9240d0017d00a61ed0a7e3ea62ba0832a489b6c7016c822665607a3f780aaef5c7c8ce697723b973d0ab4b5067d45f3e2605306bcb5156f274771b8b9845c5fafe1c4a2a016c1682ddd85864f66a7d9a9bfdd6fe2a908e8bafdf964a72fcde2ab131b2bb2aef3478e54da8d41404f64d556bb665210e26405650cd37c5bc89be1c0642bee57f278995d331249a8eb44647b9a35affbadad7ae6888b180df3ed6a721728aaedfb12e795fb63e7fe76ab9520c71d62e3ee874cbd3e5c115cdc118af93e1ee451a1d2dce8775ad8cf0e07b7610779ab0669eaa81a11dc85bdbe25dbd6b366e9d2d4d199a2a145a27473f8490ac989df046a78e7b0000000000000000000000000000000", .Okay}, + {.Shl, "-3075592d967fd565d388f2a04e195a3413df726639940ac4189b3595ba77d702450e72383f72dfeded32fbb5c15c966a939845f77b4a73878329ac39b5df7723903dea6cd3b01fc03a6a44f99fa1a2060d8f1f55f4813118c755260b1731ed505a272a57b0fe293ed1282b43d0154dbe0d0a2b1b4b1b2b9d3b7db568d8668f58cecbb090f82127c5b2b059fa889aa27c4fedbed06d9533cace4cadf8bcda5990cbf5f4a37a7ba4d851b010290eeca8c50226636e599e4dae01f14b7eb6e8281ad41d9aec4ee990fe3ed2146d909443fd2681fb818580e851c7a81d0eea9f3016a07022aea0ba862d9dfd9a5b03240d3bb805ca3e0ad725262c1cfb55251cde0d035769d9dfb12ba9051a8286602fb40ab4f0b2dd3f7e8bb38184a0818d209645d5442ed1bb0de7363b9bba1913edfdeb7c12977bce562de97f67b44b1c7a9eb021cc2fb9724b1900f18c529b7efe10d580f778e7c12149ecdc2c74f084d374262a580fc56e1689d15bc1389e075578255c96179b6505457c4b8b8c991a13f4cb0ee2703c073465130796271b26e501cc5abda93316d03c20c87d8193b8580eb9ed7b2eda86bb8b46d71933574c1c5380be232f164479b2c6de4e683baab6e584a407b77835d6b034491bcf200e2f46aaaf29c6e3ada011eb2afdd55c6c3eca6d27ec057fff42cd7eae92a4e4deea6308ac85dd40bf9661e3ac94e1f445fd1b6e", "b4", "-3075592d967fd565d388f2a04e195a3413df726639940ac4189b3595ba77d702450e72383f72dfeded32fbb5c15c966a939845f77b4a73878329ac39b5df7723903dea6cd3b01fc03a6a44f99fa1a2060d8f1f55f4813118c755260b1731ed505a272a57b0fe293ed1282b43d0154dbe0d0a2b1b4b1b2b9d3b7db568d8668f58cecbb090f82127c5b2b059fa889aa27c4fedbed06d9533cace4cadf8bcda5990cbf5f4a37a7ba4d851b010290eeca8c50226636e599e4dae01f14b7eb6e8281ad41d9aec4ee990fe3ed2146d909443fd2681fb818580e851c7a81d0eea9f3016a07022aea0ba862d9dfd9a5b03240d3bb805ca3e0ad725262c1cfb55251cde0d035769d9dfb12ba9051a8286602fb40ab4f0b2dd3f7e8bb38184a0818d209645d5442ed1bb0de7363b9bba1913edfdeb7c12977bce562de97f67b44b1c7a9eb021cc2fb9724b1900f18c529b7efe10d580f778e7c12149ecdc2c74f084d374262a580fc56e1689d15bc1389e075578255c96179b6505457c4b8b8c991a13f4cb0ee2703c073465130796271b26e501cc5abda93316d03c20c87d8193b8580eb9ed7b2eda86bb8b46d71933574c1c5380be232f164479b2c6de4e683baab6e584a407b77835d6b034491bcf200e2f46aaaf29c6e3ada011eb2afdd55c6c3eca6d27ec057fff42cd7eae92a4e4deea6308ac85dd40bf9661e3ac94e1f445fd1b6e000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "8ce2ff2c6288cce038e442f6581b5829a3961df4f51b1b64abcbbbacaa2b9a3b5b15a017b942c26cc2659f02ec13cdf3650e2c203415907a597a29aba49c63546d27b38edb3cc249b986ffdbfd28a17628fc221fe3f8ab1a521d3f3e7ba4236cacf1d7e55a460bc3456c123b8780aa2716d55115251a18f5c2de0c3d8f72d724e027813069472aba55f212b10d55f8ef7dae0a65a9be366bf403ccb1f27f9e843560e111505b046fce71daa3978019dc9b9e475f6811d56bc24f6d4d8049dff52f2d810e53b99cfad5e7d5205f1bed4346c5ada1fdc36887beb88ab77eb2eecd3f75d897451c4445595fdfc81708fdf446b34f26c9d3470adeb49aeef31b9aeeeedbc2931631ac02f8ccd3bb599c260e6572d6e5ab1c2c8ace71d062a4c5490476813f3b386875075547338024ea7b322eae4d00f10f3749fdad98d3bee2acfe73ece78aa7509de5468c5fd723012e37064927f89ea156dea5662de416fcf154b843fa9a8b82cb447b4620f0486c510fb3ebb00bf4280ae888fe01caaf08908506d40214bb476b3825cba9513323e0003376205d4d75a9dbc4413ef254c78640c3a5f01e12d83a2aa0bb4907a24b2c2836b5c174b1c1a797ae5040a9de3e1356a1178f89dc01db53cbb87a1e58ace4b93a95b8f0d2afa0b6e350783780ff0b8b110e0f1eb9268f31c4f3aef6e9a378e5faa315ce5c21b69e972f892ba2230c54", "1a4", "8ce2ff2c6288cce038e442f6581b5829a3961df4f51b1b64abcbbbacaa2b9a3b5b15a017b942c26cc2659f02ec13cdf3650e2c203415907a597a29aba49c63546d27b38edb3cc249b986ffdbfd28a17628fc221fe3f8ab1a521d3f3e7ba4236cacf1d7e55a460bc3456c123b8780aa2716d55115251a18f5c2de0c3d8f72d724e027813069472aba55f212b10d55f8ef7dae0a65a9be366bf403ccb1f27f9e843560e111505b046fce71daa3978019dc9b9e475f6811d56bc24f6d4d8049dff52f2d810e53b99cfad5e7d5205f1bed4346c5ada1fdc36887beb88ab77eb2eecd3f75d897451c4445595fdfc81708fdf446b34f26c9d3470adeb49aeef31b9aeeeedbc2931631ac02f8ccd3bb599c260e6572d6e5ab1c2c8ace71d062a4c5490476813f3b386875075547338024ea7b322eae4d00f10f3749fdad98d3bee2acfe73ece78aa7509de5468c5fd723012e37064927f89ea156dea5662de416fcf154b843fa9a8b82cb447b4620f0486c510fb3ebb00bf4280ae888fe01caaf08908506d40214bb476b3825cba9513323e0003376205d4d75a9dbc4413ef254c78640c3a5f01e12d83a2aa0bb4907a24b2c2836b5c174b1c1a797ae5040a9de3e1356a1178f89dc01db53cbb87a1e58ace4b93a95b8f0d2afa0b6e350783780ff0b8b110e0f1eb9268f31c4f3aef6e9a378e5faa315ce5c21b69e972f892ba2230c54000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "782745376a028c297566d502062b6e486acf979680c64656c4b2a9b95c389522cd0f25af3d15dd89d9ec9eedef6d363a390636dfd4db9542616b6bc8bc3777afaf90e76510f0189d6ab1f442c5617c0717bcb82513d40af7ba3c0edbab9df6be8cee25c140c2f66c5bdacebd546f50d5102aa64c59e79f63fcf55debfad003c72060537d50bc7706cb6e3262fa82aa11988749579211d55336a8333bf8871ca27b4ac0ff0ff87905b009e16f710e3b47a3528f3e379cdf39e18ce3386515fa111b2b9745b041cec380a33485219d5017f4cdf7e3e4ae157aaf9db056c6f049d3eedc17a8dad8bef66bd9bee0b3288755f5c509a29c8474b8e0e543cac2a8658184b2feddb5e1a120aab274608e3bb69d5a567cd39a8831d85df8705fcfa2caf7445deb3fb132acb914561f1aa1a4bdbc7f9bbd6e99edf41aab2979b761c8b9e0ea9ad982ba178be1a996736e02548d34efd78dcdbb41fae73269a0518ba236b5fdca672bba40261f58bdfd67269692c1d3bfdb9f08d0988d5bc297dc1a64b085655dff686a79f39338d61ec545e80bf13b1383ef8fc4c8c3180ab428cf055545cf4a7f15d8d23f803f7b9222417765589ee7d2fde845ee7ec6fb75ff0381fef9552e1b16a64d13e172539a75a967025a5d715a79618baa482a058a703c6c798e1c12a15ed8e1d208f877f35a1ee177a5edbbb8519f40798e165112f8c3820c0", "78", "782745376a028c297566d502062b6e486acf979680c64656c4b2a9b95c389522cd0f25af3d15dd89d9ec9eedef6d363a390636dfd4db9542616b6bc8bc3777afaf90e76510f0189d6ab1f442c5617c0717bcb82513d40af7ba3c0edbab9df6be8cee25c140c2f66c5bdacebd546f50d5102aa64c59e79f63fcf55debfad003c72060537d50bc7706cb6e3262fa82aa11988749579211d55336a8333bf8871ca27b4ac0ff0ff87905b009e16f710e3b47a3528f3e379cdf39e18ce3386515fa111b2b9745b041cec380a33485219d5017f4cdf7e3e4ae157aaf9db056c6f049d3eedc17a8dad8bef66bd9bee0b3288755f5c509a29c8474b8e0e543cac2a8658184b2feddb5e1a120aab274608e3bb69d5a567cd39a8831d85df8705fcfa2caf7445deb3fb132acb914561f1aa1a4bdbc7f9bbd6e99edf41aab2979b761c8b9e0ea9ad982ba178be1a996736e02548d34efd78dcdbb41fae73269a0518ba236b5fdca672bba40261f58bdfd67269692c1d3bfdb9f08d0988d5bc297dc1a64b085655dff686a79f39338d61ec545e80bf13b1383ef8fc4c8c3180ab428cf055545cf4a7f15d8d23f803f7b9222417765589ee7d2fde845ee7ec6fb75ff0381fef9552e1b16a64d13e172539a75a967025a5d715a79618baa482a058a703c6c798e1c12a15ed8e1d208f877f35a1ee177a5edbbb8519f40798e165112f8c3820c0000000000000000000000000000000", .Okay}, + {.Shl, "-2469691aafa362d31d9fa6fd69d3ea3ea67b7f11bfeea361c6d8cc06587930009bc3bd557edf87836362fca059d16af5a5291a2d8f4e4996105d524a5ddf337c5cc15490ecede2c644f4e4ccca2fb2e383ebbc949a6915a0f0205b1d483b445cfbe2d000e0c3ab30568c693d2481a61d75f1d95d804abfe1fb283790d465003a098d8122090f973dafd173db1e24c3df52b4ec31f56eb53601bcff1b42a0add591c08340b4c6c09c3fe368c4dc5e2877735aaecd84c2aad983a01a118520e72240ff9cf42f60b7b7206fd2fc7dd670c9e7b37af5ef3c02607dfbb2281a32eab82f5b150c2680108e67628f358e0e2a3e6a001a4e98d7b78ba2a6f9346ba080902daa1ffd271866b1ae20096db017547650dc222a07857b6792bb3a03a7ade24fe69dea76e5217c4e228fd2d2c01cc1567a871e59f52e7738782cd48d7530015f5b2b300e3d21238d50c6d5137023f507f56b5bf4a782cdb5e89566b816a8b3f6b2392f82cec5511b679f1da28e87ad21612cb7427120e1eab305fcf739bee6eebdf61dc20aa78ff7cda67ac016b27326ceeffbee460dd3fc5da634c2d86308068b2642443817e8253c45f83ed68061759be00f1571ffae50fc0d82909b0734ee1118a2a046eecff267cb6b39dc06c40407a14aa6dd02382f73665f41d4b2816b3476766c8c3bd0cc11797faafc21ffe798a80d9d8710c511d4b380696b88eba1", "12c", "-2469691aafa362d31d9fa6fd69d3ea3ea67b7f11bfeea361c6d8cc06587930009bc3bd557edf87836362fca059d16af5a5291a2d8f4e4996105d524a5ddf337c5cc15490ecede2c644f4e4ccca2fb2e383ebbc949a6915a0f0205b1d483b445cfbe2d000e0c3ab30568c693d2481a61d75f1d95d804abfe1fb283790d465003a098d8122090f973dafd173db1e24c3df52b4ec31f56eb53601bcff1b42a0add591c08340b4c6c09c3fe368c4dc5e2877735aaecd84c2aad983a01a118520e72240ff9cf42f60b7b7206fd2fc7dd670c9e7b37af5ef3c02607dfbb2281a32eab82f5b150c2680108e67628f358e0e2a3e6a001a4e98d7b78ba2a6f9346ba080902daa1ffd271866b1ae20096db017547650dc222a07857b6792bb3a03a7ade24fe69dea76e5217c4e228fd2d2c01cc1567a871e59f52e7738782cd48d7530015f5b2b300e3d21238d50c6d5137023f507f56b5bf4a782cdb5e89566b816a8b3f6b2392f82cec5511b679f1da28e87ad21612cb7427120e1eab305fcf739bee6eebdf61dc20aa78ff7cda67ac016b27326ceeffbee460dd3fc5da634c2d86308068b2642443817e8253c45f83ed68061759be00f1571ffae50fc0d82909b0734ee1118a2a046eecff267cb6b39dc06c40407a14aa6dd02382f73665f41d4b2816b3476766c8c3bd0cc11797faafc21ffe798a80d9d8710c511d4b380696b88eba1000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-24c2529c6cec31e03691cf8080e592f19fb5641fa89c49235496e75eec189ca531f368ffd6107fd0da2c63748eb039df690123f16422e534e45efcfbb04e8d023398960af3cc71eb3e078d8185df5ade89f8b7a4f3bfad4b8311f67fc3f94cbf79e576feb06e5ecbef8b2f45009230b4ead5fc193a6e92436bde4d82cedf9b081df45b0734822789524ca881a29d7ab739267df524c6bfc922485d58b3e9dbd77a3015cd69212ce09857afdd0445f4b25d3cd92e0953950fbfa405c4fdeb864d3047e7a7e35444dc6480ec89b12291a623aabaf0eed994f96ccf19bb5d7f1e6f17d710283c7dcdf9f834a8a2eb3355b487af291b60634daa8daf7d83cdf990cba9085051a82343f619951c291c656b709e18150d86c1212ed359367377e254ae465e422f685566775a84a93cd59e0f1a6f9e773a0b2f0f4e653564da2892936d829575bb7cf063b0a39857b79465fca255045c7a630acc579507b9bbb9d105936f1922a0d3ec59ad0733a498c06971c4237d34e30547d45b3564d28aae5b933a1b1758145574aaa51bfcbdd3ceda20d10220a671a3725a9aca9ccb7e9e6a49e54b4390bb5779198771f93c9897e96c79a714a87d72898f5b2ec3e212a32b0851fff7bcffff6f2a1e4059e79634169c160bf4132de6a1ac546836afe0467f5bb85eb96b3d7c1ba37b6a553135b8098ba7f41babeaac4db106ccfcd6d165406a94", "78", "-24c2529c6cec31e03691cf8080e592f19fb5641fa89c49235496e75eec189ca531f368ffd6107fd0da2c63748eb039df690123f16422e534e45efcfbb04e8d023398960af3cc71eb3e078d8185df5ade89f8b7a4f3bfad4b8311f67fc3f94cbf79e576feb06e5ecbef8b2f45009230b4ead5fc193a6e92436bde4d82cedf9b081df45b0734822789524ca881a29d7ab739267df524c6bfc922485d58b3e9dbd77a3015cd69212ce09857afdd0445f4b25d3cd92e0953950fbfa405c4fdeb864d3047e7a7e35444dc6480ec89b12291a623aabaf0eed994f96ccf19bb5d7f1e6f17d710283c7dcdf9f834a8a2eb3355b487af291b60634daa8daf7d83cdf990cba9085051a82343f619951c291c656b709e18150d86c1212ed359367377e254ae465e422f685566775a84a93cd59e0f1a6f9e773a0b2f0f4e653564da2892936d829575bb7cf063b0a39857b79465fca255045c7a630acc579507b9bbb9d105936f1922a0d3ec59ad0733a498c06971c4237d34e30547d45b3564d28aae5b933a1b1758145574aaa51bfcbdd3ceda20d10220a671a3725a9aca9ccb7e9e6a49e54b4390bb5779198771f93c9897e96c79a714a87d72898f5b2ec3e212a32b0851fff7bcffff6f2a1e4059e79634169c160bf4132de6a1ac546836afe0467f5bb85eb96b3d7c1ba37b6a553135b8098ba7f41babeaac4db106ccfcd6d165406a94000000000000000000000000000000", .Okay}, + {.Shl, "-4c82aaad6ec61430ce756ad145ccf7bb915c9042a3d42dac5dfa0a40ebb31cf4c885cf0b13a2ef39ff3fff858a1d2571e39314b503f8d26ed4897ba1eacf91e6c5e0ab63659c53ab99e8b09bcfba636dc37870f328c26b208f3254266d1997570fcb845453722e7d2bf0d1c0133b610498110ddee517912c1ba50e859e57343239d2f928d0b8cb31b43996066aeef9939c06a03fce703251266cd9f28306c751609efae7217f3c512b45031e15e35b922d7c433f0db657c59400f78a67850374daa4abf3160bef63d3e34ce4bb3d18cc57eb799d3669eaa38a88d1feb45fd2eabbf2cf7d51f19ae00af6e9e7289d289a8ddd8b02512e70ea87d2b82751103de2f299ccf5b979ea1b0fb6cc542f6e86826ef6ac96353b5391109270c2b81033a6408cec551a1cc548b006f07f623132c01be7a9e75925bf87953b6a35e03914a9ca9b7193816abdd340217b8d5138aef862fd77c78daad78c9fb5172f820484b766e5ab1374ac442672eb851d5b542e1194b5e09876b0cbbacd7020c3e3a586f322d03c2781ff34e2379dba837dd3da3cb380a6dce6ae1bc3d332e8246524bae55294264998ec9f8c2fc8a175f9bd5049dc2300328d7c604ce8e2e421a11a0509567d8ea4104112e2b95f24f8fef144658a57fbbb57726c66dcb18220ebc5923b3f33c256df49b3746476ba6a5615c3ab0d37c1bb1948d4c9e97d0fbad634338", "78", "-4c82aaad6ec61430ce756ad145ccf7bb915c9042a3d42dac5dfa0a40ebb31cf4c885cf0b13a2ef39ff3fff858a1d2571e39314b503f8d26ed4897ba1eacf91e6c5e0ab63659c53ab99e8b09bcfba636dc37870f328c26b208f3254266d1997570fcb845453722e7d2bf0d1c0133b610498110ddee517912c1ba50e859e57343239d2f928d0b8cb31b43996066aeef9939c06a03fce703251266cd9f28306c751609efae7217f3c512b45031e15e35b922d7c433f0db657c59400f78a67850374daa4abf3160bef63d3e34ce4bb3d18cc57eb799d3669eaa38a88d1feb45fd2eabbf2cf7d51f19ae00af6e9e7289d289a8ddd8b02512e70ea87d2b82751103de2f299ccf5b979ea1b0fb6cc542f6e86826ef6ac96353b5391109270c2b81033a6408cec551a1cc548b006f07f623132c01be7a9e75925bf87953b6a35e03914a9ca9b7193816abdd340217b8d5138aef862fd77c78daad78c9fb5172f820484b766e5ab1374ac442672eb851d5b542e1194b5e09876b0cbbacd7020c3e3a586f322d03c2781ff34e2379dba837dd3da3cb380a6dce6ae1bc3d332e8246524bae55294264998ec9f8c2fc8a175f9bd5049dc2300328d7c604ce8e2e421a11a0509567d8ea4104112e2b95f24f8fef144658a57fbbb57726c66dcb18220ebc5923b3f33c256df49b3746476ba6a5615c3ab0d37c1bb1948d4c9e97d0fbad634338000000000000000000000000000000", .Okay}, + {.Shl, "-82fd7863ab12a0f29ea5ad26086ef41c0f1afd5fe4ccde0d76a548e973d69f46e03ae377cf503582d786c56f84a4b32ee9fe4c949a7de6e4f3583951c881f84d22b1575b3dafb954e4132a7daff00281a2de0527802011fd37b9758c251e54631b143f2dfff02150fbcfc0264edd76d9bf6e56e643ff8b9feb10ac41d5a1c8005502fe66f43611835f7590b8fd92d539135b3946202f5b025ba40b19a6839f47f80725690971b2ed95a9b16e59894913b7a8d502f571bcf550ba39fe4de0e1050eb23ecbd1baeac7347eb2b0d51dafe47b6a0bb31df9c44de1b5b18a422a92f9bd9f74b21defe1316141e1c1e88b78f564c04eb56b7959990b744653f17d15c5d93a730bb940fa83925aa47345b41bdeaeed15cf2f9395c4af913c2ddff71e91be6ab1c782f0946e16c7b7c183e989c734f53a0c23c03810bde88fc76c8c5830f988b449a6ff3f4a10eabedac9c98c711c9ae499097242a47d3548182e79dc32007158431fc002671503d5d25b97b7ea5482e325356253d41795c006c77047d720f44427dbc11d11265c6cad8e51e46f8968c01ed79d55e7924ef8cd61b0df42c244701064c637f755e3a46258e7a0b16efc5176a9d540433b678a4e411306e5e29e9991e44632be00e30e8b5938013d96b68c89f1c29f574446fccdf8f0c4d56311a8b2d4ab3d7485c66c70562c4e5d13c9ca963a3036302181cd1c4665ca9d", "1e0", "-82fd7863ab12a0f29ea5ad26086ef41c0f1afd5fe4ccde0d76a548e973d69f46e03ae377cf503582d786c56f84a4b32ee9fe4c949a7de6e4f3583951c881f84d22b1575b3dafb954e4132a7daff00281a2de0527802011fd37b9758c251e54631b143f2dfff02150fbcfc0264edd76d9bf6e56e643ff8b9feb10ac41d5a1c8005502fe66f43611835f7590b8fd92d539135b3946202f5b025ba40b19a6839f47f80725690971b2ed95a9b16e59894913b7a8d502f571bcf550ba39fe4de0e1050eb23ecbd1baeac7347eb2b0d51dafe47b6a0bb31df9c44de1b5b18a422a92f9bd9f74b21defe1316141e1c1e88b78f564c04eb56b7959990b744653f17d15c5d93a730bb940fa83925aa47345b41bdeaeed15cf2f9395c4af913c2ddff71e91be6ab1c782f0946e16c7b7c183e989c734f53a0c23c03810bde88fc76c8c5830f988b449a6ff3f4a10eabedac9c98c711c9ae499097242a47d3548182e79dc32007158431fc002671503d5d25b97b7ea5482e325356253d41795c006c77047d720f44427dbc11d11265c6cad8e51e46f8968c01ed79d55e7924ef8cd61b0df42c244701064c637f755e3a46258e7a0b16efc5176a9d540433b678a4e411306e5e29e9991e44632be00e30e8b5938013d96b68c89f1c29f574446fccdf8f0c4d56311a8b2d4ab3d7485c66c70562c4e5d13c9ca963a3036302181cd1c4665ca9d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-3ed80bc0b2cea2525680fb7c36507a1e329d0b3333994d969f3bdc73e1e86d5adf9da065b4fff22fd7c39de8b2d503a43de3a51c1454592e1f3c56452bc15055d6b1069472dc9ceec476216a79402d3e1b77075a1add94b17ee30c37e1a12a08a3014aa823ce1a931c095b2fc7863fda2e00e86750782863d99604aff81d3876a893140ec9c8b38607199c5018094d295f8fea279feed208fe2abee1656e1c58416bac9c0314aa3e53a9ba006f1109163e257baed3bc6f36429952a68e0730631f889a918b23a3361824ed76e15d0688e0735292b6b3b88427b84ac94e41bc79c9c0830febe026ff14e4d47ec06d723c6dcf73386ff90df7068c4027ad85a62a9ecfec8dd81b762c6990e3dd1000642136bdcd8b0cc7c3133aa7f9822e11071f69bb7a870b14f7c01b8a99d017d0b0b4a1f1a8dfeb3ab1203edbaa303e09f99ebc85b9da5d7277314ce8f4d81c035a3455468036b609dfcff024e311c85ed720382e53513710a70aaa95b8952098258aa15484626ddc21df5c3b624caab1616361a4ef6be9367e1416affd957860e9b0b7385983af70cffc06d5c1117a777103171af6b655f9561c81ac39b9c8d9fd9db2b8ffc9bcc81e8edf2c649baff6f38544f2c7b522d2cf28790338433ef35c18bd4d53bcf0c688e5c77468d8e02d98af1739a5216c78ff130c4e4579130fe01eb5432e96e72f7214b862a37ae405821b", "b4", "-3ed80bc0b2cea2525680fb7c36507a1e329d0b3333994d969f3bdc73e1e86d5adf9da065b4fff22fd7c39de8b2d503a43de3a51c1454592e1f3c56452bc15055d6b1069472dc9ceec476216a79402d3e1b77075a1add94b17ee30c37e1a12a08a3014aa823ce1a931c095b2fc7863fda2e00e86750782863d99604aff81d3876a893140ec9c8b38607199c5018094d295f8fea279feed208fe2abee1656e1c58416bac9c0314aa3e53a9ba006f1109163e257baed3bc6f36429952a68e0730631f889a918b23a3361824ed76e15d0688e0735292b6b3b88427b84ac94e41bc79c9c0830febe026ff14e4d47ec06d723c6dcf73386ff90df7068c4027ad85a62a9ecfec8dd81b762c6990e3dd1000642136bdcd8b0cc7c3133aa7f9822e11071f69bb7a870b14f7c01b8a99d017d0b0b4a1f1a8dfeb3ab1203edbaa303e09f99ebc85b9da5d7277314ce8f4d81c035a3455468036b609dfcff024e311c85ed720382e53513710a70aaa95b8952098258aa15484626ddc21df5c3b624caab1616361a4ef6be9367e1416affd957860e9b0b7385983af70cffc06d5c1117a777103171af6b655f9561c81ac39b9c8d9fd9db2b8ffc9bcc81e8edf2c649baff6f38544f2c7b522d2cf28790338433ef35c18bd4d53bcf0c688e5c77468d8e02d98af1739a5216c78ff130c4e4579130fe01eb5432e96e72f7214b862a37ae405821b000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "9e9e52051876271269f7283fcd7db208b58e879846313496aefc616d920cf55fdcf94dc6778a25d56e9a757d3a91d03576ef4e33e49c2d88862f0251dc2a0626950b68bf8f5196a52d95e0850653243f1210359007c9a3c11b5bce5a9afaa001527c1c74a769aa719a902cb3b8a50170f83b49f5a9f21c993b6a14bf63a696b29304e14bdff930c658fc1a7fa0d448a6cbf0d41213ad57d48eb327cf847635ea78de4caa8915f6acf4d62f7fc67893f03dbf15b2852695cccaab3cdc0b74dcd6b6a0dd52d8091455da4ea11e2fa0dcb9de17e814b92db7a206a809ea4be5fc02463691edcc4ff6b287b9ceb767281004a66b2956c01200521aa4a153e4535e096bd1a4f9f5e9048f98c6099ce810f0aa705ca91367366d02f806dbf2a7355a2b0bf916f1516815aaa402a4f7d8f19059afcd90f33567211ce6222839d95e1cb7e021573de2fa783aca1f7ed61d1899a12677dba93abfd44de75db9d42472cf5de4d01377cbfc8d2bed2fc76050b3d6a2af1b126841878e246609b2a56aa93031fede0776164383add925eb939643f0d7f1b5e860c48bc4bfa44f431767b68ae1b6da14821d97ea212133a606cfbb489ba6d933d2ec7fed1ac2f47fb1051a3d44478f9a062828e0f8ce1ca3b9255f78676b9a60dedd18e739baa77d6a7c48f91bd3296df507b6f878d5059c7ac1ccf7e7b6f48d71176e54fd755de57f1ce14011", "1e0", "9e9e52051876271269f7283fcd7db208b58e879846313496aefc616d920cf55fdcf94dc6778a25d56e9a757d3a91d03576ef4e33e49c2d88862f0251dc2a0626950b68bf8f5196a52d95e0850653243f1210359007c9a3c11b5bce5a9afaa001527c1c74a769aa719a902cb3b8a50170f83b49f5a9f21c993b6a14bf63a696b29304e14bdff930c658fc1a7fa0d448a6cbf0d41213ad57d48eb327cf847635ea78de4caa8915f6acf4d62f7fc67893f03dbf15b2852695cccaab3cdc0b74dcd6b6a0dd52d8091455da4ea11e2fa0dcb9de17e814b92db7a206a809ea4be5fc02463691edcc4ff6b287b9ceb767281004a66b2956c01200521aa4a153e4535e096bd1a4f9f5e9048f98c6099ce810f0aa705ca91367366d02f806dbf2a7355a2b0bf916f1516815aaa402a4f7d8f19059afcd90f33567211ce6222839d95e1cb7e021573de2fa783aca1f7ed61d1899a12677dba93abfd44de75db9d42472cf5de4d01377cbfc8d2bed2fc76050b3d6a2af1b126841878e246609b2a56aa93031fede0776164383add925eb939643f0d7f1b5e860c48bc4bfa44f431767b68ae1b6da14821d97ea212133a606cfbb489ba6d933d2ec7fed1ac2f47fb1051a3d44478f9a062828e0f8ce1ca3b9255f78676b9a60dedd18e739baa77d6a7c48f91bd3296df507b6f878d5059c7ac1ccf7e7b6f48d71176e54fd755de57f1ce14011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-e6852a31b2ce3ee36ca9fe5f91eebfc72b1eac7b8da5768eb5d238637ea274108245bdf4ffb223069e0ac83ccf5b1eb02a9a1f89783f66682bf766e434fdd6c7841f16e4b70ba97b043872b0d1ae2fa6eec76631cb302154b8089f24fc63b090fdcad2a51de031abbdb1a72fcdc6aa8e1117c86aed800b69e1dd65477cc6b62c246f9233a40ee0dc4d7f787a6dc0883d14bf92a8b2016e7ede3f266c6bda661544182fa0520f50daed514467fb5971c50477a2857c2e78c70ec1f194f4658f6044a2dd488292174ca6bab22ed26db5c94698e8077e9a9cf4bfb0b730102d7da12a7612e860b43fcedcde0d9c35ffc8295ed2d15a12a49dd409895288eef9d7d3b0751a0f1f563d93c4da576d98e9bd9692850709d807df7515f8113af9adf54c5f1f996a53c77c9a9c7d4453736bf9a36c1daa0f29e2b2d4ae8cf14307c624712518601d6df35cdc6214ae64e774bd9742c8aad373a25fd332ad7647e1a8f12a3bb3344d124f225ad1112cbe0d1769a0d4af7947712ce02746754a5e2874308180036fd85a038737e6fabb14181e53a53d60d740e62d23b33b4a39bd2795fca317f169adea9754e5f13928612d42124e930587d6225c948a42c07e8fce13be205f7d3534e3bf00230d4aa655bb060b2fdfaf5c01d0e39017fe46cbdd5193b016dff5b3b284850ecc74d6c726c2d906c382da4e324d98da0e34ce91f263c7f5f3", "1e0", "-e6852a31b2ce3ee36ca9fe5f91eebfc72b1eac7b8da5768eb5d238637ea274108245bdf4ffb223069e0ac83ccf5b1eb02a9a1f89783f66682bf766e434fdd6c7841f16e4b70ba97b043872b0d1ae2fa6eec76631cb302154b8089f24fc63b090fdcad2a51de031abbdb1a72fcdc6aa8e1117c86aed800b69e1dd65477cc6b62c246f9233a40ee0dc4d7f787a6dc0883d14bf92a8b2016e7ede3f266c6bda661544182fa0520f50daed514467fb5971c50477a2857c2e78c70ec1f194f4658f6044a2dd488292174ca6bab22ed26db5c94698e8077e9a9cf4bfb0b730102d7da12a7612e860b43fcedcde0d9c35ffc8295ed2d15a12a49dd409895288eef9d7d3b0751a0f1f563d93c4da576d98e9bd9692850709d807df7515f8113af9adf54c5f1f996a53c77c9a9c7d4453736bf9a36c1daa0f29e2b2d4ae8cf14307c624712518601d6df35cdc6214ae64e774bd9742c8aad373a25fd332ad7647e1a8f12a3bb3344d124f225ad1112cbe0d1769a0d4af7947712ce02746754a5e2874308180036fd85a038737e6fabb14181e53a53d60d740e62d23b33b4a39bd2795fca317f169adea9754e5f13928612d42124e930587d6225c948a42c07e8fce13be205f7d3534e3bf00230d4aa655bb060b2fdfaf5c01d0e39017fe46cbdd5193b016dff5b3b284850ecc74d6c726c2d906c382da4e324d98da0e34ce91f263c7f5f3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-ed27b1865180559d15a681d6606a09e6720abe31ba1b87933c1d8fc702f4ec8f78c55d6e16c7511cbf1c70e008621802ab5d035741deef331ef89e32bc2d12c779cc0170d39143cac84a3be8f6ef76764c22d5c9e4d0cb14f7d28c01eb98584fd85bd3966129c3799a5553efcb840152a73e7bfac37fce33e724b3d90b87dd340671f342914c8d5bb0ddd2cd5f3c0bb34c3ef34d4ef7af947be283fbfc74d08c5cfbb4d234284f504e995faa9168a352896494e2bdd6e15863e57d7b80ae92dd3907f563fb99e894c93ec6b66dbe6113d0ad588aeb00e6d3c20c259814c1f5ea1628291433c2c1719d9864a998d20c0eae3789a2e394a2c6fd5badd6a29c7c0957294c4c64dba86073a2984ed0b323005791823881bcb43cbf874417ee1782c3ec671c231ec930459a37095be62cf4a7336f31c3effd3f2b51a09bbed087daf03334072f376e8972b13f0cd39845a17df0ecf188541e3ab6e943f195ccccbdadf52a15e2ff0ee68c51bcd51902adea4cb25745d489dc695d8ccaec919094af58d419c9e009736924faa4cabfc292e98c6230204631503182de55405836fdfc8125bda536ba56c5b1e7789d04b425b283993019f7295834ca2f576c4cbb2a9718d7e647550b3729d53b436a940e0b1ac2a1acdd34f1a475fd59029ef0472c2e79ba5f9ebae91f8af3361792f2ea18681f7bea93208d2e0787f4d4a047c996b9de", "b4", "-ed27b1865180559d15a681d6606a09e6720abe31ba1b87933c1d8fc702f4ec8f78c55d6e16c7511cbf1c70e008621802ab5d035741deef331ef89e32bc2d12c779cc0170d39143cac84a3be8f6ef76764c22d5c9e4d0cb14f7d28c01eb98584fd85bd3966129c3799a5553efcb840152a73e7bfac37fce33e724b3d90b87dd340671f342914c8d5bb0ddd2cd5f3c0bb34c3ef34d4ef7af947be283fbfc74d08c5cfbb4d234284f504e995faa9168a352896494e2bdd6e15863e57d7b80ae92dd3907f563fb99e894c93ec6b66dbe6113d0ad588aeb00e6d3c20c259814c1f5ea1628291433c2c1719d9864a998d20c0eae3789a2e394a2c6fd5badd6a29c7c0957294c4c64dba86073a2984ed0b323005791823881bcb43cbf874417ee1782c3ec671c231ec930459a37095be62cf4a7336f31c3effd3f2b51a09bbed087daf03334072f376e8972b13f0cd39845a17df0ecf188541e3ab6e943f195ccccbdadf52a15e2ff0ee68c51bcd51902adea4cb25745d489dc695d8ccaec919094af58d419c9e009736924faa4cabfc292e98c6230204631503182de55405836fdfc8125bda536ba56c5b1e7789d04b425b283993019f7295834ca2f576c4cbb2a9718d7e647550b3729d53b436a940e0b1ac2a1acdd34f1a475fd59029ef0472c2e79ba5f9ebae91f8af3361792f2ea18681f7bea93208d2e0787f4d4a047c996b9de000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "5d9a966d327b28611135bdcd143d1048b50d51f35529859f352d697f56b33f797ef2bff14e02bd4271ba71d1566c25f2fcd18b0223628208c74542dd14cc968cfb50b002682a27068fc0454e577df6adfa98d3a62292ffb606d8ca89f882adf86d46d26ffdb5db73e7dec4c56e0dc72ad95201b2b58b17cd46b3d0aa1f10e56f1f716165d6def24a42f50b5db4a7d5a4d4d7c3c47de7f69e4142691c452750db7c1706dfc7b60e473a814475b3ae75ca0194d2738be4316d545d2cddbebe877508610cce782ed8e8574f3f9c40492e6d46c70e8d5ade0a86fea604ed6aa7bbfe86e5ffffd6a2305cc3e700efbd5a13ef1f23ea98f0555b4100739c6ac8ebfb358310f6b5536f3202aa610adb328cbeea19a440e723a67b8538941664053842d6e2bc480d9771d41aa95aae8def89def553051456d339a97ae101acb4eceb16169f0a0051b5f6c7962faaea4821a50190c9a0017e6337a4985ba2064145532e8c012b39d47235a6624ac60359921f5b0df4026ba06be1be2dbc439a2232bd556878b4dbea2ca3c728fc99864b11e91fdcb14b7332f38ffec4f55b4a0f84cb1cea7f6f558c811853276abeae991eb921f37032371ccf2eb814696b7914df39bd310f29a77f3134d31f53a03e31ef453f3eb5b5e1a206887dba139068dea6f7010e52c5e9873a7e31098083ca1c576b7ab5d6e77be69d9f2994ae2c1cea2522e958", "b4", "5d9a966d327b28611135bdcd143d1048b50d51f35529859f352d697f56b33f797ef2bff14e02bd4271ba71d1566c25f2fcd18b0223628208c74542dd14cc968cfb50b002682a27068fc0454e577df6adfa98d3a62292ffb606d8ca89f882adf86d46d26ffdb5db73e7dec4c56e0dc72ad95201b2b58b17cd46b3d0aa1f10e56f1f716165d6def24a42f50b5db4a7d5a4d4d7c3c47de7f69e4142691c452750db7c1706dfc7b60e473a814475b3ae75ca0194d2738be4316d545d2cddbebe877508610cce782ed8e8574f3f9c40492e6d46c70e8d5ade0a86fea604ed6aa7bbfe86e5ffffd6a2305cc3e700efbd5a13ef1f23ea98f0555b4100739c6ac8ebfb358310f6b5536f3202aa610adb328cbeea19a440e723a67b8538941664053842d6e2bc480d9771d41aa95aae8def89def553051456d339a97ae101acb4eceb16169f0a0051b5f6c7962faaea4821a50190c9a0017e6337a4985ba2064145532e8c012b39d47235a6624ac60359921f5b0df4026ba06be1be2dbc439a2232bd556878b4dbea2ca3c728fc99864b11e91fdcb14b7332f38ffec4f55b4a0f84cb1cea7f6f558c811853276abeae991eb921f37032371ccf2eb814696b7914df39bd310f29a77f3134d31f53a03e31ef453f3eb5b5e1a206887dba139068dea6f7010e52c5e9873a7e31098083ca1c576b7ab5d6e77be69d9f2994ae2c1cea2522e958000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-829ad4512b9ef9003815870d39e4f76d49cd3ee7fefe4dc1daa934d62ac2cee2778ede661dabe2e3cb7629571999d8370544905888cc5ab2da90471fd79af6bc8cca02724c53d36b0a962f0620fdfe4e55449a351bd4fdb0837ca0db98e346654fd9e5125991079d63acae7cd35df1a355a2ae113fa814786da68be7834313359a7346c750b29e15747f4ed2cb3d497a9fe81f8337fea741fc3271564c3e0a1108edc4c296c62f4f74a773d1f5e5b8123398a9b03f2cfa4e39f78bcb9725568aab4fc8bb718b4e496039ddc51b56d755d32ab259cd11f5476e6a672fe5859290809cfc78688943e38c1aa871d870bbbe0c68a849797512b4eaca79b971ebcc9ab1501d818c85efcdc63a1184f44ab1889e383fcf63621c7fe22566d409547d936e53487915e2c9ac8cd53a00388e0d20476f63b3b3422093cdf0b4b7b2b8bfe5612b8f4a1620faf918f51ab4eab373f030eda04ca0c09dca510217ad5188c0c0bd1de601c95a4b6f9fba1b340362c5cb14036603907d98ea9d1906a4caa4f9c8c911990231bc9315da2e66a219aedcea5c4253a80e6dec34dd259ac902bbc47a5b2ca5b2e338d69d1bcc15da2433be080f8a5c09dac850f05df8d390a12ce3f4e5f70779f30039126dced63bba399e2e7d79fd8233c3fe6f184b514e7f4da37ce31f8771f7347e35243b870742cb2c89a641b5ca257fa70c520620936e855fff", "b4", "-829ad4512b9ef9003815870d39e4f76d49cd3ee7fefe4dc1daa934d62ac2cee2778ede661dabe2e3cb7629571999d8370544905888cc5ab2da90471fd79af6bc8cca02724c53d36b0a962f0620fdfe4e55449a351bd4fdb0837ca0db98e346654fd9e5125991079d63acae7cd35df1a355a2ae113fa814786da68be7834313359a7346c750b29e15747f4ed2cb3d497a9fe81f8337fea741fc3271564c3e0a1108edc4c296c62f4f74a773d1f5e5b8123398a9b03f2cfa4e39f78bcb9725568aab4fc8bb718b4e496039ddc51b56d755d32ab259cd11f5476e6a672fe5859290809cfc78688943e38c1aa871d870bbbe0c68a849797512b4eaca79b971ebcc9ab1501d818c85efcdc63a1184f44ab1889e383fcf63621c7fe22566d409547d936e53487915e2c9ac8cd53a00388e0d20476f63b3b3422093cdf0b4b7b2b8bfe5612b8f4a1620faf918f51ab4eab373f030eda04ca0c09dca510217ad5188c0c0bd1de601c95a4b6f9fba1b340362c5cb14036603907d98ea9d1906a4caa4f9c8c911990231bc9315da2e66a219aedcea5c4253a80e6dec34dd259ac902bbc47a5b2ca5b2e338d69d1bcc15da2433be080f8a5c09dac850f05df8d390a12ce3f4e5f70779f30039126dced63bba399e2e7d79fd8233c3fe6f184b514e7f4da37ce31f8771f7347e35243b870742cb2c89a641b5ca257fa70c520620936e855fff000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "bcf2580c4bd178a3f873c239983f9eec279b51a8f6df6d74b1caf47abd4771a9f5f4de9c1f9ea54a74a737fb6015eae181fe88d4d0dcfceaf598ea1cf38ea45b31db57fe1bda469281c91f47e1c2011629daa2928457f00611793f05daaeb5b7389b00b1cf9971cb0598323068f12ed22adeedfcba2efaa0fceebac8352ab1151b40b3fefda02f9aa437847c0cc64d63a417685985e20d73cf51d1574d0af1825a499149c873ac5c0d34dc6d1310492b3b3a7530cedc21af6c634d10252728e3a5a2da29a5ef606f129d7ce3c05f05f739051c5d63174780de08e293add7493361f18f66099c88b8eadeb6492c48c698d5c70eedbfde19265daae54e068d7b910e90766e1f200b2ed02622d62359b8d432ddca3da724014f95df67fa9e8078a2ef86ae06f6995322ad2edd13fa33295f634f92060bb3615d90926abdd28eca38dd631d03da4cca440ee9e6965e464f587cd3d6cfb8905a359e2fb2c0c0fa759df35ccf5ae025c73525757774f03d1a8537f4f2c7c504a93c072cb636d7de4fbe38fe7578b3afbd397fbecc0c72ca6353dbe5f0da3afed8cb7e424beb1b7d1bf39253fff645d7f36b12a250dd4b2b8ecedf5f335e5dc13649c7f1ee9f6025800f96210ef57797b81d99bb10a8307d5d890bd7f5829afb31fb29132101cc1cde2dcf3956db0461bb168b94966bcd82c5fc5d83dcd2ca0ce0ff94e6205d9fd1b002", "168", "bcf2580c4bd178a3f873c239983f9eec279b51a8f6df6d74b1caf47abd4771a9f5f4de9c1f9ea54a74a737fb6015eae181fe88d4d0dcfceaf598ea1cf38ea45b31db57fe1bda469281c91f47e1c2011629daa2928457f00611793f05daaeb5b7389b00b1cf9971cb0598323068f12ed22adeedfcba2efaa0fceebac8352ab1151b40b3fefda02f9aa437847c0cc64d63a417685985e20d73cf51d1574d0af1825a499149c873ac5c0d34dc6d1310492b3b3a7530cedc21af6c634d10252728e3a5a2da29a5ef606f129d7ce3c05f05f739051c5d63174780de08e293add7493361f18f66099c88b8eadeb6492c48c698d5c70eedbfde19265daae54e068d7b910e90766e1f200b2ed02622d62359b8d432ddca3da724014f95df67fa9e8078a2ef86ae06f6995322ad2edd13fa33295f634f92060bb3615d90926abdd28eca38dd631d03da4cca440ee9e6965e464f587cd3d6cfb8905a359e2fb2c0c0fa759df35ccf5ae025c73525757774f03d1a8537f4f2c7c504a93c072cb636d7de4fbe38fe7578b3afbd397fbecc0c72ca6353dbe5f0da3afed8cb7e424beb1b7d1bf39253fff645d7f36b12a250dd4b2b8ecedf5f335e5dc13649c7f1ee9f6025800f96210ef57797b81d99bb10a8307d5d890bd7f5829afb31fb29132101cc1cde2dcf3956db0461bb168b94966bcd82c5fc5d83dcd2ca0ce0ff94e6205d9fd1b002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "5c5beaf9a53496f3346b8081e3751a4e062e809b70700a798dd395cd7a4f7f833c6a9d1caa67531e5876330b2cde667ccaed133e8d5d664384b9bf883cdc2b6a5066a15d053337877ee1b46dc7155adac2a53e6cb5106019945a0676e9fc7abed750b66428572802008aca6513a41d60e63bf2f067d2256fd802408c249894d4b994465908815c920e7cf7e9960bb1db46460f3a6288843ea19eac0c46f436d22d75dfa285a8c83e3d675e672a66c55e8dae818295c2835ea09e8c219921060fe63fb6f14fc71272de47438696c93238adedfb0d87729ebb9dc8945616a80d5a1b8d87b8c928e931226eeaced99e2ad9063dded4cff46c09b55d7eb1749e5146da095d3bb4c99ef1270b1119906808b94d17bc42b0e00a723b752d3739924983e710216e28ac48fc5c56dc56c59694377e7ed76488a7105b2ed5ea873459d6f41833ee53681d6c679b216f00ba7ea3032f39e084598772698dc53da4a2d9361eaa1f730993a85dcd047fa3999768a15d633c9f489e8877c7115f113eb9ccc00c7ff1fe9638ab720cb0d1343d782c1b984dfd20bcf1304afa034252812908af4151045398e10a7383bf9cee065c5a0f58cc686033cdc3952c8a72aab1ed18f0164bb79ec2aebace93b3073b3e58cddb216f5f59498626f2a8b2c587f5583ed290d08dd7c436b4b9a1830bccc9f6e75169dad8704323e8124eefa29ed87424a307", "258", "5c5beaf9a53496f3346b8081e3751a4e062e809b70700a798dd395cd7a4f7f833c6a9d1caa67531e5876330b2cde667ccaed133e8d5d664384b9bf883cdc2b6a5066a15d053337877ee1b46dc7155adac2a53e6cb5106019945a0676e9fc7abed750b66428572802008aca6513a41d60e63bf2f067d2256fd802408c249894d4b994465908815c920e7cf7e9960bb1db46460f3a6288843ea19eac0c46f436d22d75dfa285a8c83e3d675e672a66c55e8dae818295c2835ea09e8c219921060fe63fb6f14fc71272de47438696c93238adedfb0d87729ebb9dc8945616a80d5a1b8d87b8c928e931226eeaced99e2ad9063dded4cff46c09b55d7eb1749e5146da095d3bb4c99ef1270b1119906808b94d17bc42b0e00a723b752d3739924983e710216e28ac48fc5c56dc56c59694377e7ed76488a7105b2ed5ea873459d6f41833ee53681d6c679b216f00ba7ea3032f39e084598772698dc53da4a2d9361eaa1f730993a85dcd047fa3999768a15d633c9f489e8877c7115f113eb9ccc00c7ff1fe9638ab720cb0d1343d782c1b984dfd20bcf1304afa034252812908af4151045398e10a7383bf9cee065c5a0f58cc686033cdc3952c8a72aab1ed18f0164bb79ec2aebace93b3073b3e58cddb216f5f59498626f2a8b2c587f5583ed290d08dd7c436b4b9a1830bccc9f6e75169dad8704323e8124eefa29ed87424a307000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "9f5fa3b1e77c464d019e07d7de3265df1d6d511961e3259ebfe145d17e6daa95852dc0c8bc5fd6b679cdd119db9dd4ccd0d8a5bb6af398d84e9ce5431d521b2b48e90b28d69dc0c84b0d4a8e484a5239f9f8c9acdd90e31e03de7ece8fc67ed8193598b05a2fae3ea77f1d22679731530d44c7553e3cf3433787ade68b238c619b6e70995c7f78e735534c4a5b4bc70c1aa18af161285ba58426d992811be6422ec943f3fcee840634db91bdda6c51bc30840a894d87d224fe985e2e7b43f3f38f5abb68cdf61df3681d7b630cb9652a86fc9b57a3927ab913f9013c2d5dd85c7a289c2c30dae694b859aaf1a551b29eb4892ba32f053e8dca4b83d87e93a674520fc92935a1f8c463bf9cc717e01d5de8a41886b0c0510f4e8602696968d62a3783a04802b2c7cc76ed4ba48d9285d278b6b52e3ae4d910dc836db80d063cc263074e26c48d54486a9995de638412f4ec32efe164b14ef598603b3b0b4cf7c3634e3c6c430d7f117c588af2b30ccb49c46669646a487cbe7c2b5fff820beee5065a2b7aba86fb4452292f287375e768ca16156c36e9d9ae9afd5527da1dceb4ca8487f6f8ece7bb8973e9e6890da1abd4059062efeaec71bf3b684bef9c9765087cf3f96ae4a739b61fa710f040c39e6c114de335f756564ac65cb55cab5dea70e7b8c01c026dbb773ed90634572c20aaee3210bca42b47d42bfd010bfffd03", "21c", "9f5fa3b1e77c464d019e07d7de3265df1d6d511961e3259ebfe145d17e6daa95852dc0c8bc5fd6b679cdd119db9dd4ccd0d8a5bb6af398d84e9ce5431d521b2b48e90b28d69dc0c84b0d4a8e484a5239f9f8c9acdd90e31e03de7ece8fc67ed8193598b05a2fae3ea77f1d22679731530d44c7553e3cf3433787ade68b238c619b6e70995c7f78e735534c4a5b4bc70c1aa18af161285ba58426d992811be6422ec943f3fcee840634db91bdda6c51bc30840a894d87d224fe985e2e7b43f3f38f5abb68cdf61df3681d7b630cb9652a86fc9b57a3927ab913f9013c2d5dd85c7a289c2c30dae694b859aaf1a551b29eb4892ba32f053e8dca4b83d87e93a674520fc92935a1f8c463bf9cc717e01d5de8a41886b0c0510f4e8602696968d62a3783a04802b2c7cc76ed4ba48d9285d278b6b52e3ae4d910dc836db80d063cc263074e26c48d54486a9995de638412f4ec32efe164b14ef598603b3b0b4cf7c3634e3c6c430d7f117c588af2b30ccb49c46669646a487cbe7c2b5fff820beee5065a2b7aba86fb4452292f287375e768ca16156c36e9d9ae9afd5527da1dceb4ca8487f6f8ece7bb8973e9e6890da1abd4059062efeaec71bf3b684bef9c9765087cf3f96ae4a739b61fa710f040c39e6c114de335f756564ac65cb55cab5dea70e7b8c01c026dbb773ed90634572c20aaee3210bca42b47d42bfd010bfffd03000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "ea74472276fba105783823344fdc7282fcf59fd4fa6c602254cfe78da5edd04c6ede159827bfedc8c0471b78ed9e7d7df55acd88e7a38af82bcfb205933e66cf97c255accbe48285acad9722469097d713868a9d688bbb85f8a796c77cf2cb000747f84af0fb283a51e10da3a50844a5f407bb338ef97baf97be12bcbada1be9c6775f12c8bee2654b3e0788c7e058ec50e8c886f6cdd3443fce01d5fa9317863e98cab2d4469f44b0416395671d03532a82c8ca2439d65106d3b816f870021c4b3a6e64546575ddb8e152732c0c14dae7eebecb2bf304c6e4783e911f2b322c14310e94292d2118c3353d53dd8e438505e69cf5196551740646896319c475a1a91f6c5db886b631975693c8c6758a0a2025c0e9ae3843786fdf8c4d865e5a2a34c9d3c23cf499668c89fed92b8bcc3a87db6b84c10deeaae2e7dd67652e92e70a6f106374f3e05ac9fa17a19f93e2ef3cb6421e468d188512671a15666582243d01496d21f3ac1692f5ca0003974423cd400ee2bf49e8104558396bf4c3a3145a4d9444fc16f5b3927885e9139a851e34d79ed1f253ea33d0e57db74b889fff1929e5d2321208abec83deaec845d922a4af500e4a92fa67bf71228ec7d3891597f292d93819fea3739ff5386f23a2dce37d9ef14dc3aa257b0daa8955e85063b6df2bba46d8497c31168c23faa9c96d06981246dfc0f116b889afc435f712b8", "1a4", "ea74472276fba105783823344fdc7282fcf59fd4fa6c602254cfe78da5edd04c6ede159827bfedc8c0471b78ed9e7d7df55acd88e7a38af82bcfb205933e66cf97c255accbe48285acad9722469097d713868a9d688bbb85f8a796c77cf2cb000747f84af0fb283a51e10da3a50844a5f407bb338ef97baf97be12bcbada1be9c6775f12c8bee2654b3e0788c7e058ec50e8c886f6cdd3443fce01d5fa9317863e98cab2d4469f44b0416395671d03532a82c8ca2439d65106d3b816f870021c4b3a6e64546575ddb8e152732c0c14dae7eebecb2bf304c6e4783e911f2b322c14310e94292d2118c3353d53dd8e438505e69cf5196551740646896319c475a1a91f6c5db886b631975693c8c6758a0a2025c0e9ae3843786fdf8c4d865e5a2a34c9d3c23cf499668c89fed92b8bcc3a87db6b84c10deeaae2e7dd67652e92e70a6f106374f3e05ac9fa17a19f93e2ef3cb6421e468d188512671a15666582243d01496d21f3ac1692f5ca0003974423cd400ee2bf49e8104558396bf4c3a3145a4d9444fc16f5b3927885e9139a851e34d79ed1f253ea33d0e57db74b889fff1929e5d2321208abec83deaec845d922a4af500e4a92fa67bf71228ec7d3891597f292d93819fea3739ff5386f23a2dce37d9ef14dc3aa257b0daa8955e85063b6df2bba46d8497c31168c23faa9c96d06981246dfc0f116b889afc435f712b8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "1a9e9fe123bf5090fcb0765a82614c949fed2ea5f43321f8a0abf273a84aa347cc11cbf7c46a8aa90f9edc785eaffad7b2e6785b649460178f827373d1be39649132aafa2a5dd81fbb0650b2f6d8bf8a8d33b028016f41d82599aaa623df849ea5a2caae0360e4913094dd247eb7ef407e5044d21a8e0c9a28dce61eb95c12bfde9924c2ec4c8d9dfa8df5cbfcea61dd40afcbec3e779364cdf4b28c778d2d91f55afa3828244ee469bd7741f5b8de24e373581cf79a158ee12f133b024ea9eac04b420c75048beb033269c62037cb53960e41285f256d95c254d059e109c5cc9d6c6a02e6ff5818a47c2e8ed67b5f501e82f37ee568cbf9e0292a871a344033009b2f1abfd9980c117cdd847e30092d2ee4f18e67c582bc74f03d716dadb063dcc6fc5fb17bf621132408d9f345e97081fa06d8107d1a85d6b18c2da14df60e22c93858358332616a42b46c91565fef960033de1e6d9154b2ca1a1e2cdd145227e98b837df09adff581aa1944ce9ee4e6ea88f12aeab0a728f603ead0061a4851060c5fa7c7625592c5578da60e1d20873fe6b6a1ce911293373e5f2a9a55a92d90b2e39a40e85d2b73c37edbc6f84904a4d1e7b9f817d7787fd4c002f8157975604413e3d7e4c92cd4c122fab3dff92859226f070edf758459c726130317bd1cdfca28cc0964a23350f87a07c8f3377cf81f850ab422a3e3dedf4630d933e9", "0", "1a9e9fe123bf5090fcb0765a82614c949fed2ea5f43321f8a0abf273a84aa347cc11cbf7c46a8aa90f9edc785eaffad7b2e6785b649460178f827373d1be39649132aafa2a5dd81fbb0650b2f6d8bf8a8d33b028016f41d82599aaa623df849ea5a2caae0360e4913094dd247eb7ef407e5044d21a8e0c9a28dce61eb95c12bfde9924c2ec4c8d9dfa8df5cbfcea61dd40afcbec3e779364cdf4b28c778d2d91f55afa3828244ee469bd7741f5b8de24e373581cf79a158ee12f133b024ea9eac04b420c75048beb033269c62037cb53960e41285f256d95c254d059e109c5cc9d6c6a02e6ff5818a47c2e8ed67b5f501e82f37ee568cbf9e0292a871a344033009b2f1abfd9980c117cdd847e30092d2ee4f18e67c582bc74f03d716dadb063dcc6fc5fb17bf621132408d9f345e97081fa06d8107d1a85d6b18c2da14df60e22c93858358332616a42b46c91565fef960033de1e6d9154b2ca1a1e2cdd145227e98b837df09adff581aa1944ce9ee4e6ea88f12aeab0a728f603ead0061a4851060c5fa7c7625592c5578da60e1d20873fe6b6a1ce911293373e5f2a9a55a92d90b2e39a40e85d2b73c37edbc6f84904a4d1e7b9f817d7787fd4c002f8157975604413e3d7e4c92cd4c122fab3dff92859226f070edf758459c726130317bd1cdfca28cc0964a23350f87a07c8f3377cf81f850ab422a3e3dedf4630d933e9", .Okay}, + {.Shl, "4070beae3242a6b619eeefd0cc599befeb0dc8dce5267ecf0f3c8c7c825e2d41d0d108bd34d177041a1f8a80fe97b653fcf744a17a0097d4cf312703b2994d168ad704e0b592eeda733f7a333d6af4b87ccc2b60acc3123ce8cd2f32c2a0f2f17dc88fc0ff09ec9f15bb7b012d985064ca6209aeeef9e184e92b5210630dc77abd455a819d4b8101b53abbdfcac8a05b509cfff3058ce063ce4b23531ee0971032744a955da258dc2eafb7245567c8d8675c623f9d4ac0f00bd97a0b943681c19284961c247fb6b1b05a99450abacaa78b0e131a1534f9449ed96e00c5b9181af107783a4005c5766f9a01a0cb7e4d66f71330872e450e52dbecdfa55cf601a425d5c881c025dae13001e31316840eb85b2b1c6fa6897123e1f450dbe5f673eb6562d9bdc59644fd9120bc68445f20a166cae21ee531490865b82ea586864ebd950e657002d49a8c4655c7d1c622b0437932615038d008164b74666ffacd4a88259c3ae1e6d53f3ed8a669a8c572dbaced11ed42c3a062600576dd6a7957ed8a85ad553c4ae4c826f55a11695a2be4031b525d86102d4d8949a4c41944673b4fd66eba9bb0600c00fc6b7518e66ebf941ab3b79e6ea2e64953c03c259bbe7b202bf28c70874e43629012b07795e12303ab67fd01a6a1ffee612c01cefec7a6c21a252c902532c3084ca51f12242008569a0678a0ae70a8d852b2153e55403733", "b4", "4070beae3242a6b619eeefd0cc599befeb0dc8dce5267ecf0f3c8c7c825e2d41d0d108bd34d177041a1f8a80fe97b653fcf744a17a0097d4cf312703b2994d168ad704e0b592eeda733f7a333d6af4b87ccc2b60acc3123ce8cd2f32c2a0f2f17dc88fc0ff09ec9f15bb7b012d985064ca6209aeeef9e184e92b5210630dc77abd455a819d4b8101b53abbdfcac8a05b509cfff3058ce063ce4b23531ee0971032744a955da258dc2eafb7245567c8d8675c623f9d4ac0f00bd97a0b943681c19284961c247fb6b1b05a99450abacaa78b0e131a1534f9449ed96e00c5b9181af107783a4005c5766f9a01a0cb7e4d66f71330872e450e52dbecdfa55cf601a425d5c881c025dae13001e31316840eb85b2b1c6fa6897123e1f450dbe5f673eb6562d9bdc59644fd9120bc68445f20a166cae21ee531490865b82ea586864ebd950e657002d49a8c4655c7d1c622b0437932615038d008164b74666ffacd4a88259c3ae1e6d53f3ed8a669a8c572dbaced11ed42c3a062600576dd6a7957ed8a85ad553c4ae4c826f55a11695a2be4031b525d86102d4d8949a4c41944673b4fd66eba9bb0600c00fc6b7518e66ebf941ab3b79e6ea2e64953c03c259bbe7b202bf28c70874e43629012b07795e12303ab67fd01a6a1ffee612c01cefec7a6c21a252c902532c3084ca51f12242008569a0678a0ae70a8d852b2153e55403733000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-efd7efd9be958823a2d33e11e2f547f1982e1c7aa40556de9fae16e9734fe1e9a3d92a0751071755aa05d953ad010e40f04508e317ad6e5b2b364fce23e43f29d776106d9b90cdb24cdc9d08c48647fb3091e8d93ddfdb292f3acc8d27916940647d40b1ea77e5eb7b67ecc8c06e5a34d6aac5c5d6a6bb4a93cb1ee54fa352717b3b217ceaffc72f0d43e805c43f0a1760529de4115441d216799f94dccadffc45548b60afcec3e3795b2d5df74882b80c078d9fdb2ec70b74c115559cc34b0ee999d8124e7eb2f5173f5ef45c189089fb7901368b95875151e773045edc1fdafa2bea1b421b44ec9600974511fb4eb5a7661c5d35db56ae732491d0dc4355fdb2da3f705eefb718ca0c48f56bcbd09c7c51ea1aa16eaadc3e9fa00c51219e65c1286b150f07c1ef37e809bef2065bc35204d8e4d88d6babd9fdace66a82652dbfccfeaa6503f9d03b52d39df3990060b3f09d0ee13fb771b63bc2847bcc87b76c29108da710204a29829ae7355c4342711d2940a1630d91d7b2bd9c475a5c04bd6be1906380f4eb2f0058e356f23e33b0b86293c28d74fe91d517b954a0b80ca6c684366121fd97809b41ada3e64c3451cd5c9a9b88c344bed72b3c146f5f378a20429f44bdbc89afc1d5eeac9906a71f5bd61233f169dece75ce745f663f5870f616d70c976c418f51224659fe1db7cd5062f12e186d12c62d8bd62e23c34f", "12c", "-efd7efd9be958823a2d33e11e2f547f1982e1c7aa40556de9fae16e9734fe1e9a3d92a0751071755aa05d953ad010e40f04508e317ad6e5b2b364fce23e43f29d776106d9b90cdb24cdc9d08c48647fb3091e8d93ddfdb292f3acc8d27916940647d40b1ea77e5eb7b67ecc8c06e5a34d6aac5c5d6a6bb4a93cb1ee54fa352717b3b217ceaffc72f0d43e805c43f0a1760529de4115441d216799f94dccadffc45548b60afcec3e3795b2d5df74882b80c078d9fdb2ec70b74c115559cc34b0ee999d8124e7eb2f5173f5ef45c189089fb7901368b95875151e773045edc1fdafa2bea1b421b44ec9600974511fb4eb5a7661c5d35db56ae732491d0dc4355fdb2da3f705eefb718ca0c48f56bcbd09c7c51ea1aa16eaadc3e9fa00c51219e65c1286b150f07c1ef37e809bef2065bc35204d8e4d88d6babd9fdace66a82652dbfccfeaa6503f9d03b52d39df3990060b3f09d0ee13fb771b63bc2847bcc87b76c29108da710204a29829ae7355c4342711d2940a1630d91d7b2bd9c475a5c04bd6be1906380f4eb2f0058e356f23e33b0b86293c28d74fe91d517b954a0b80ca6c684366121fd97809b41ada3e64c3451cd5c9a9b88c344bed72b3c146f5f378a20429f44bdbc89afc1d5eeac9906a71f5bd61233f169dece75ce745f663f5870f616d70c976c418f51224659fe1db7cd5062f12e186d12c62d8bd62e23c34f000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "d257b3f513841f2970335deb3a01fc725aecc621df8853f72b568d2767a37ac44230a67164feba7deb19f4c5b2c4dc49344e2b9d4f2ae5df678d173b9a1d3739dfe733ef160d5f851c197f5d24e1620d8f222ff592a69c53ae8c64b180ef5f8582228846d4abebe4ad4427b45dfd193d77fd68bc273a480ad989bee0cf0d55df4f7abb191e7e84944d957c4e3ff2adc9d19b519636bb7b9ffd532aff4f2afe47422f8263d7a2a95de22ba526c5a054b5eccc9ec0b8f7accb92fc7aff2d5d5b82f25846ff86d6ea264683009c2b9a19c72e80dbdcc744e63633b6536f2f4368add268fb426b027fd87472dc05a109727dcfc3c8cbbe7299f20a3fb6bb1a63c216fb8826da9fb745840d2c3c86da3f6c5d9820aa6a44385cc766aa27c407a6ba46b545b60136a44b6165db131e5fb39c296e4f055863f112a4e549f2e946cdc1460784a7649ee79072c1ac4a8eb8167b21ba1a1fbdff64f161346968d298da21459a0fa9084d19da2fce33bff012beb378c9ed326fe1a72e88dab5eeadb8107496376c36f8891e6318551a7932b8669845cb680836fedd1561da776d3497d71fa83cbbdc3bcfdfe710a4c5784c43d9ce7cd9bc41573100cf4afa84c8427708149cffcefd297476d3f4cd57886f42c1cbfa05f7614398a959cf23952f1def25f94541d2872a1f6cdb9494440f398e871667f207ef8ff6f462081f5df1961593060f", "f0", "d257b3f513841f2970335deb3a01fc725aecc621df8853f72b568d2767a37ac44230a67164feba7deb19f4c5b2c4dc49344e2b9d4f2ae5df678d173b9a1d3739dfe733ef160d5f851c197f5d24e1620d8f222ff592a69c53ae8c64b180ef5f8582228846d4abebe4ad4427b45dfd193d77fd68bc273a480ad989bee0cf0d55df4f7abb191e7e84944d957c4e3ff2adc9d19b519636bb7b9ffd532aff4f2afe47422f8263d7a2a95de22ba526c5a054b5eccc9ec0b8f7accb92fc7aff2d5d5b82f25846ff86d6ea264683009c2b9a19c72e80dbdcc744e63633b6536f2f4368add268fb426b027fd87472dc05a109727dcfc3c8cbbe7299f20a3fb6bb1a63c216fb8826da9fb745840d2c3c86da3f6c5d9820aa6a44385cc766aa27c407a6ba46b545b60136a44b6165db131e5fb39c296e4f055863f112a4e549f2e946cdc1460784a7649ee79072c1ac4a8eb8167b21ba1a1fbdff64f161346968d298da21459a0fa9084d19da2fce33bff012beb378c9ed326fe1a72e88dab5eeadb8107496376c36f8891e6318551a7932b8669845cb680836fedd1561da776d3497d71fa83cbbdc3bcfdfe710a4c5784c43d9ce7cd9bc41573100cf4afa84c8427708149cffcefd297476d3f4cd57886f42c1cbfa05f7614398a959cf23952f1def25f94541d2872a1f6cdb9494440f398e871667f207ef8ff6f462081f5df1961593060f000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-1928247353623e7e40c6185da5c6f42a7865d6072c9d525653e7e0a742a68280208e17cd1c65c160a23d0ffd0ee96da19fe3753d48856f8514f3bde0046642ad1fc0e86b104601ed8e5bd49ad04885d4d7f1ab1663353ae1ba53013485ae85ddc7a2ed17a4ce65ffb37d408bad6443fcdd3d4ab25d97becfb606aa1aae84efe27d3989bb90ec993ca7cc73a287bfb675aab65fe1d97378883c124d0543d435da8d754fbb6d2128dc6f2fe023701f9ff09893ba02db2a5a170c3a80d590b0da28b2a659443221aa61571bda8bd3a668bc90b4a2f9d892cd74a78fcbed986158fdcef108421908d02629af28493146b771c864929bfefc70606c7665f37bd37751d58d08e49026945b0f1ad72da2ce9b90c6817d2a4f997907299c5d99d20f0b89a28d995f018bdbdee3ed61460ac5a717f86e90b35e98608d1b218a41f8427362589dc407ef19323ced73547705dc225bdb0ffc6b4a3770d806a4a1ecd14200b669796d3fae6a66c3718cfa67ba06eb4926daa08c57b1c323779d16fd863e2462a55b4d50925d21ea74d34e102c7786062dcdd54b00819c03d1122ac2cfd57a906f32922a0ec81f3fb0f13fd53a96b65833aa501ecc38a4fe947664f2b1d76c2a112e2a09ec00823d8c430496216da342796a0d3a4bd1a52f98be8d34bfbfa0f6b69c5eb786ea33831c95aef0e25190b727e4421f8556689d945cc64b9fc02cf0", "78", "-1928247353623e7e40c6185da5c6f42a7865d6072c9d525653e7e0a742a68280208e17cd1c65c160a23d0ffd0ee96da19fe3753d48856f8514f3bde0046642ad1fc0e86b104601ed8e5bd49ad04885d4d7f1ab1663353ae1ba53013485ae85ddc7a2ed17a4ce65ffb37d408bad6443fcdd3d4ab25d97becfb606aa1aae84efe27d3989bb90ec993ca7cc73a287bfb675aab65fe1d97378883c124d0543d435da8d754fbb6d2128dc6f2fe023701f9ff09893ba02db2a5a170c3a80d590b0da28b2a659443221aa61571bda8bd3a668bc90b4a2f9d892cd74a78fcbed986158fdcef108421908d02629af28493146b771c864929bfefc70606c7665f37bd37751d58d08e49026945b0f1ad72da2ce9b90c6817d2a4f997907299c5d99d20f0b89a28d995f018bdbdee3ed61460ac5a717f86e90b35e98608d1b218a41f8427362589dc407ef19323ced73547705dc225bdb0ffc6b4a3770d806a4a1ecd14200b669796d3fae6a66c3718cfa67ba06eb4926daa08c57b1c323779d16fd863e2462a55b4d50925d21ea74d34e102c7786062dcdd54b00819c03d1122ac2cfd57a906f32922a0ec81f3fb0f13fd53a96b65833aa501ecc38a4fe947664f2b1d76c2a112e2a09ec00823d8c430496216da342796a0d3a4bd1a52f98be8d34bfbfa0f6b69c5eb786ea33831c95aef0e25190b727e4421f8556689d945cc64b9fc02cf0000000000000000000000000000000", .Okay}, + {.Shl, "c3f287125baa7e38dd03cae8058bf7889c10422d8c196e01dbdfa195a92d942774a098d231b9e1f50ffe04e8e25cb3eda7f2895e1f34caeb0e8f0ca296236888bdd2196cb8a34fbc645f87a6e570a3147273396fb0e39515644c7df55861f4e4c451fefba07a762bdff510776820ddc80dc4b975e008075ef36f8749c704c0fdda1917d02042fd82502edae40e52555472f37a9a71b65c82dd7d2420cfaed1e1de3285fbf80af004877fb86b5a585f640230958506e242c77ba205c0c58a58ab14f660f00f7377bd6feb1f88f314813b13fdb33edd628a61ac8d3edbe1c28942311636280a0eb5432e01eced9cab8613c2accc210a965cef0d97b1d25cb6fce59f2de43926ad9df9e32b337236a014b257261bd1411cad21fa825d41cd12245873eec0ee1de020161a32354b51afa463296a5674f460d5cfc680e9e9d31fa7326a7ee08b18066b8e2ff0430ac03ea1b97b696e846f6b09a39c8790398ea905cc76222ac35d0c548d1b5ebb70b6f75eec992cc36063e9a58441ea4316dd4b62da46009d8223755b5121e2db02180335602acacdcdce16d0616cba317528c7650e7a75e3a140dc156e785e71f4e46678cda05b8a8ac460c7a3518027e684388b7ff3b27a343a313be506b05326669bfbf45a19faf4a1c880435a97dc00ddda4c385c51b4e624f5a7aa9939355131aff3238139c8cd3927f5c3515cdeba48754db5", "0", "c3f287125baa7e38dd03cae8058bf7889c10422d8c196e01dbdfa195a92d942774a098d231b9e1f50ffe04e8e25cb3eda7f2895e1f34caeb0e8f0ca296236888bdd2196cb8a34fbc645f87a6e570a3147273396fb0e39515644c7df55861f4e4c451fefba07a762bdff510776820ddc80dc4b975e008075ef36f8749c704c0fdda1917d02042fd82502edae40e52555472f37a9a71b65c82dd7d2420cfaed1e1de3285fbf80af004877fb86b5a585f640230958506e242c77ba205c0c58a58ab14f660f00f7377bd6feb1f88f314813b13fdb33edd628a61ac8d3edbe1c28942311636280a0eb5432e01eced9cab8613c2accc210a965cef0d97b1d25cb6fce59f2de43926ad9df9e32b337236a014b257261bd1411cad21fa825d41cd12245873eec0ee1de020161a32354b51afa463296a5674f460d5cfc680e9e9d31fa7326a7ee08b18066b8e2ff0430ac03ea1b97b696e846f6b09a39c8790398ea905cc76222ac35d0c548d1b5ebb70b6f75eec992cc36063e9a58441ea4316dd4b62da46009d8223755b5121e2db02180335602acacdcdce16d0616cba317528c7650e7a75e3a140dc156e785e71f4e46678cda05b8a8ac460c7a3518027e684388b7ff3b27a343a313be506b05326669bfbf45a19faf4a1c880435a97dc00ddda4c385c51b4e624f5a7aa9939355131aff3238139c8cd3927f5c3515cdeba48754db5", .Okay}, + {.Shl, "95faba481ad154831c3d3dec4a1d73d93645fdb92ea5b785f0417a9fbb782b3c8a98d8ac8af2970e63c4ef18c209101d7736ff3fe5c7bf95a0660a62a90a77be213913a68b0ae3fe6cd4c0bec411705f7add77a1cf60997ba100a50c3aa989905c904b9a7f60e8e216f0b2163bd65aa4775fce34b11afe1331d626a58ff35b44a479a60c67c5864f7a5d78c32e34370e263e061e16c44c7422e535899f9d414048243e4185d9af9b12f5f00b015824d0f75f030d92b526c52e4da2e692b8fff76717a53a145b75ff669830c47399108fd7261d035e9d2d28eb67af9e670d3bd6126eb91b171788b9d74d3bb9ee922a59e2412f972f5cf13ebca8d22f8cd63327467cef5f6740b730dbaa0c53388b5b7a4acf809f0beca85d0db9946801aace4de33684e4174586f92fda748750d642d69c42297f1d5cb6e58bb93e544161a6f71828441f0818fff7d43189a27dd79883db58864a44e0337871190ad9cb0393e2b09add1a4740040a30202d74cd1539b1d8b8627ecaaaba9798f283b3580c8b93c8bbfccb4b8251c73c015e6e849f302b4479a9732a0a7efd61fd719dab291cf2b923320abbf1264f586171c9e5d2349023ef2709cc2450b51cda1aa1f00257868c8188c8caac4cdff41780982920bb6f31a519ddb201223b75de3d25a8745fb9a5baa979c20a8524f03b00aa42dfe97bcd3608756fbb14a4507868531b0b84fc", "f0", "95faba481ad154831c3d3dec4a1d73d93645fdb92ea5b785f0417a9fbb782b3c8a98d8ac8af2970e63c4ef18c209101d7736ff3fe5c7bf95a0660a62a90a77be213913a68b0ae3fe6cd4c0bec411705f7add77a1cf60997ba100a50c3aa989905c904b9a7f60e8e216f0b2163bd65aa4775fce34b11afe1331d626a58ff35b44a479a60c67c5864f7a5d78c32e34370e263e061e16c44c7422e535899f9d414048243e4185d9af9b12f5f00b015824d0f75f030d92b526c52e4da2e692b8fff76717a53a145b75ff669830c47399108fd7261d035e9d2d28eb67af9e670d3bd6126eb91b171788b9d74d3bb9ee922a59e2412f972f5cf13ebca8d22f8cd63327467cef5f6740b730dbaa0c53388b5b7a4acf809f0beca85d0db9946801aace4de33684e4174586f92fda748750d642d69c42297f1d5cb6e58bb93e544161a6f71828441f0818fff7d43189a27dd79883db58864a44e0337871190ad9cb0393e2b09add1a4740040a30202d74cd1539b1d8b8627ecaaaba9798f283b3580c8b93c8bbfccb4b8251c73c015e6e849f302b4479a9732a0a7efd61fd719dab291cf2b923320abbf1264f586171c9e5d2349023ef2709cc2450b51cda1aa1f00257868c8188c8caac4cdff41780982920bb6f31a519ddb201223b75de3d25a8745fb9a5baa979c20a8524f03b00aa42dfe97bcd3608756fbb14a4507868531b0b84fc000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-46cdccd8b792bead4b1a1cd0cfcc41cd6704229a5aaa4430e35bec3347adb6dbceb801c315cebd3adc8d1fba26153aeea59c81261cffd35ae0d541c27dc3586a3c4dc8b41755ad2a9f3179f3ff6aafd6f7e37119928b2f4af3677d3461f9072d76d829cd9ad2d78cd8b356f736b145c15f0ecbf0fb61d0e14b0148d6a284da67a72915f8f6e9698cf997162833c715341f3ffc52873280d60d223138bc4523eb16d393782e38e28b92cd925351542d1c999db71c630b353b155c819e964d3ef4bdef2863d4bece009154121cae404fef386301aebeb9e72424bffa6e7e0a4390a1edd8a9d4a22e29799f3cf3471a16e93ef298f2a48d1f262220d11fbf993e9e85399815db8acd4573f1bb7d481f0c88ef3aa7bb0f39048b362b00220bb09c23c4a7bdb84e68c3f42488d8ba508a97df8740beba495f4f43b678d2f276369af65a08fe76bb7ca8561037eb7867b0615b04b08625bce1042fec85bb9e4f1f6671a9a2d4e65f72d79558be4376dc6f9800484c25af43a9adf8c29635bfdc7e928aa296fd778b5a379ba8ab79b5f62a7517a7de2347bb741a25f269b882ba290bfc221b285e8aa9cdbea6e998fefae84391e1f8ae697a7dcdea3addb68e6dd39911ad47d979a82ffaa82bd4663182f070630a206e697654a430a057c5ff20ca9aa52541c724df3a6b5249cd66aa166022a2f63e7f673dabcdf606e4716cf838405c", "21c", "-46cdccd8b792bead4b1a1cd0cfcc41cd6704229a5aaa4430e35bec3347adb6dbceb801c315cebd3adc8d1fba26153aeea59c81261cffd35ae0d541c27dc3586a3c4dc8b41755ad2a9f3179f3ff6aafd6f7e37119928b2f4af3677d3461f9072d76d829cd9ad2d78cd8b356f736b145c15f0ecbf0fb61d0e14b0148d6a284da67a72915f8f6e9698cf997162833c715341f3ffc52873280d60d223138bc4523eb16d393782e38e28b92cd925351542d1c999db71c630b353b155c819e964d3ef4bdef2863d4bece009154121cae404fef386301aebeb9e72424bffa6e7e0a4390a1edd8a9d4a22e29799f3cf3471a16e93ef298f2a48d1f262220d11fbf993e9e85399815db8acd4573f1bb7d481f0c88ef3aa7bb0f39048b362b00220bb09c23c4a7bdb84e68c3f42488d8ba508a97df8740beba495f4f43b678d2f276369af65a08fe76bb7ca8561037eb7867b0615b04b08625bce1042fec85bb9e4f1f6671a9a2d4e65f72d79558be4376dc6f9800484c25af43a9adf8c29635bfdc7e928aa296fd778b5a379ba8ab79b5f62a7517a7de2347bb741a25f269b882ba290bfc221b285e8aa9cdbea6e998fefae84391e1f8ae697a7dcdea3addb68e6dd39911ad47d979a82ffaa82bd4663182f070630a206e697654a430a057c5ff20ca9aa52541c724df3a6b5249cd66aa166022a2f63e7f673dabcdf606e4716cf838405c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "ada3a37ca41ce2002d66178e380082865fb0e89e638b1eb924cc6939f5f236e00ad6afacc83086aba5cccd3e88e02122ac04fcedd9860c1f2b3114f7965019a3b6380490f4486043f27a6694e3b90e244b0cf9ed1057059f70e6f1c632c65cde5dfc3491d4c3a29fc45d4cdcfb33d44c282371224685f9d3c1169f409bfc7ad85f81c4e23e3bad40d6a0ddb6c07598ba71a65a5d608903e461c2a42f2327cfa90b2b5361463e838096118270075e818b7bbca2d8030cfcc134e9ad6e971ec5e0edf5411435d209d75493229243e35bfa150a1c47e237207d7cc9c577450668bb5963d8a4daafe2e6ce2bef2c1fb9b0636058c97ae21b4d6d0c3fc0865cc89693fd3f4b89f78a4028ff80c16c0f9474a70705cfa340615993f96c61950557ed43baf30fbbaa8a57ffecfc975e775504509d8a84346feb915ee850e852008dd902c0a557b9e8374a80d58af48248e74a877c297b7658084769a28cbf488cb8cb700c7121ec96e0166139612b5c68973468f374d72fd94a39b3c640d29df293aa11136907447fdcb6cfbb191398c8563f1e482aa6d338838ea5fca9ae70057a3b2281d18c83cf4b4b77c7cca9a31414933e4d79223eb408c5f9bf9f5bbecf936b346883bc892fb93b0dca0fe41bc6d4c2eaa9601dc02b455d1406a17dd211067ae579adf4133c646bc2dad32df25fb4810a90f8426ae74f4e666d9b49585e9dc6e8", "0", "ada3a37ca41ce2002d66178e380082865fb0e89e638b1eb924cc6939f5f236e00ad6afacc83086aba5cccd3e88e02122ac04fcedd9860c1f2b3114f7965019a3b6380490f4486043f27a6694e3b90e244b0cf9ed1057059f70e6f1c632c65cde5dfc3491d4c3a29fc45d4cdcfb33d44c282371224685f9d3c1169f409bfc7ad85f81c4e23e3bad40d6a0ddb6c07598ba71a65a5d608903e461c2a42f2327cfa90b2b5361463e838096118270075e818b7bbca2d8030cfcc134e9ad6e971ec5e0edf5411435d209d75493229243e35bfa150a1c47e237207d7cc9c577450668bb5963d8a4daafe2e6ce2bef2c1fb9b0636058c97ae21b4d6d0c3fc0865cc89693fd3f4b89f78a4028ff80c16c0f9474a70705cfa340615993f96c61950557ed43baf30fbbaa8a57ffecfc975e775504509d8a84346feb915ee850e852008dd902c0a557b9e8374a80d58af48248e74a877c297b7658084769a28cbf488cb8cb700c7121ec96e0166139612b5c68973468f374d72fd94a39b3c640d29df293aa11136907447fdcb6cfbb191398c8563f1e482aa6d338838ea5fca9ae70057a3b2281d18c83cf4b4b77c7cca9a31414933e4d79223eb408c5f9bf9f5bbecf936b346883bc892fb93b0dca0fe41bc6d4c2eaa9601dc02b455d1406a17dd211067ae579adf4133c646bc2dad32df25fb4810a90f8426ae74f4e666d9b49585e9dc6e8", .Okay}, + {.Shl, "8d54673297a4c160d694a94251db21020e7f891caabda8b708c24c2b16af4e78579aed0924d508d39d4674144a87a2d2368644c844486baef595f7ff8e65207f3fea313d8dfc52e19fe0e4316d008a4dfd089b58b3003fb22cd4dd6ed198eeed6f6b907b03315f9899a0125b2208609734c2535568305e8a02e1afc5ff56ce85b0c6be13be23d63b6d421c9661331194c18c7f9da48b2170c0c8d06b50d49e7afff9523f42a83b363e418629419c51e31e690b514e8f53a36951c5a5c7510fde5271993c0c7980c717b587de247b86f228dcc330c41969b4501e478061f89c6a20f06ee3b9f3e7a1e53abbcf8112eb38b049d41003eec6accf86e45120af4c0626d866d4f5237fd895ed8f3e3c1a2ddb8850f3e03ee99a3e160dcdec1483fbd1c42d350e1b3b9455b3065be19f5ba49cb16c19aa110ffded08bd3e61db63a9de760f131020ce94caed94d86608344d60dcd375de6735bcaf347fe96aef58acf7d0eccaa14bca9543df4b1319e5b7be4bf423e087bebb59e0af27e4c6f4d55412435b945167e379f07a271f32d5a557da83445513c17650c3dad6fd5a0b994153af3482e961af0ebabc37755fa933f1ad8d8e815bbef6e32a5590c6e192d83888f60b1cefd0977bebe70ab1a3b04d471cb392f542097dca48d073e833c3caa42fecbf3a4816e23e43a8fc22f88f24f24c26739d8dabbde6f91af7eee42a27563f", "1e0", "8d54673297a4c160d694a94251db21020e7f891caabda8b708c24c2b16af4e78579aed0924d508d39d4674144a87a2d2368644c844486baef595f7ff8e65207f3fea313d8dfc52e19fe0e4316d008a4dfd089b58b3003fb22cd4dd6ed198eeed6f6b907b03315f9899a0125b2208609734c2535568305e8a02e1afc5ff56ce85b0c6be13be23d63b6d421c9661331194c18c7f9da48b2170c0c8d06b50d49e7afff9523f42a83b363e418629419c51e31e690b514e8f53a36951c5a5c7510fde5271993c0c7980c717b587de247b86f228dcc330c41969b4501e478061f89c6a20f06ee3b9f3e7a1e53abbcf8112eb38b049d41003eec6accf86e45120af4c0626d866d4f5237fd895ed8f3e3c1a2ddb8850f3e03ee99a3e160dcdec1483fbd1c42d350e1b3b9455b3065be19f5ba49cb16c19aa110ffded08bd3e61db63a9de760f131020ce94caed94d86608344d60dcd375de6735bcaf347fe96aef58acf7d0eccaa14bca9543df4b1319e5b7be4bf423e087bebb59e0af27e4c6f4d55412435b945167e379f07a271f32d5a557da83445513c17650c3dad6fd5a0b994153af3482e961af0ebabc37755fa933f1ad8d8e815bbef6e32a5590c6e192d83888f60b1cefd0977bebe70ab1a3b04d471cb392f542097dca48d073e833c3caa42fecbf3a4816e23e43a8fc22f88f24f24c26739d8dabbde6f91af7eee42a27563f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-cede06bcc3b205ac2f6bb30523327b95d40d1c9bc4525656b4a269cd326d7961b8bedc12e674d6670a33e005dd5cce72495e10f04035a24722d60879b84aa6b2e6f0d07e87777f8dc72512d2b03e59f6407b6ac693eb0807684e44c6d2a660777e91425f8b4c3a009d27c6af5f7622cf7146567c5b3e75234d0a696bfc5ac0e25545b9e78722590f95ec07b76d754b4fa030fb995db46385c9ccd33a363ec5fe531f03dbd4abbd2045cdf18d85371756b9742e448df59f01446cb56a12fb830c96f9de625455329dfe014befaa28a4c1b576ae84d62ae1e3dfc98079625f591f56d0979ef5724e2fb244e908fd90029dbf0094831a43cd68ee434dc520e74a83d8ef8e07ba31f9903131ce06fbde2f2089d8e0f707a3b6738d734503abf4756009ace41d90ae8ef899e09e1f191b71adb4bbe3e4506e7640ffaadbcae47163efd66c772c0b5f29a6b36d8461e2fc21dd3a54201a4a83259e88d7d76021a40261fb6e1ab1b0c8cf702e54dd2827d436fb5147a178f7dc8fef089b2b50ba5a933c4c885c92f489fe952d3e99e56b6310e4d9aa6c9338d62ede25aaaa907f2e16dc30c0388865b7b63846ec732b1a2dcda79e28854095a10a7a3777a0bc93461011ca32a305e214ba6f5ddd1902be03b823d703ef8fcaf456f675c04c5e19696a32e6da9689fc8327afaef05e5880fefeae735a0f4ea02b49ea86b0a787b39710f4", "21c", "-cede06bcc3b205ac2f6bb30523327b95d40d1c9bc4525656b4a269cd326d7961b8bedc12e674d6670a33e005dd5cce72495e10f04035a24722d60879b84aa6b2e6f0d07e87777f8dc72512d2b03e59f6407b6ac693eb0807684e44c6d2a660777e91425f8b4c3a009d27c6af5f7622cf7146567c5b3e75234d0a696bfc5ac0e25545b9e78722590f95ec07b76d754b4fa030fb995db46385c9ccd33a363ec5fe531f03dbd4abbd2045cdf18d85371756b9742e448df59f01446cb56a12fb830c96f9de625455329dfe014befaa28a4c1b576ae84d62ae1e3dfc98079625f591f56d0979ef5724e2fb244e908fd90029dbf0094831a43cd68ee434dc520e74a83d8ef8e07ba31f9903131ce06fbde2f2089d8e0f707a3b6738d734503abf4756009ace41d90ae8ef899e09e1f191b71adb4bbe3e4506e7640ffaadbcae47163efd66c772c0b5f29a6b36d8461e2fc21dd3a54201a4a83259e88d7d76021a40261fb6e1ab1b0c8cf702e54dd2827d436fb5147a178f7dc8fef089b2b50ba5a933c4c885c92f489fe952d3e99e56b6310e4d9aa6c9338d62ede25aaaa907f2e16dc30c0388865b7b63846ec732b1a2dcda79e28854095a10a7a3777a0bc93461011ca32a305e214ba6f5ddd1902be03b823d703ef8fcaf456f675c04c5e19696a32e6da9689fc8327afaef05e5880fefeae735a0f4ea02b49ea86b0a787b39710f4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "5805533d97c52a599289d9c39b63c6f3df601bbd1df2b84c3ce3ceefab505ba86e0adec168bfcd5eaa9fd6592359239cae9a691a2e8af4812e2a3d302c6ae583226929e277a6a715670994efe58d0be00bc68b6f0b32d0b77bce66073cc52332269d16f37bf4dd12723e1818c5828e2d7ae692d7ec16da2934f4a1d7b0a0e00752bb8cd79d0484fa5e4e40dbc7ca5c713e90beca33c0d8f77a8ee8f7143126a0248ca02464235fff33b671d2bd921a3650a697c9caabc842cb976ec0715acf0bcd2fd00ca1a73971deda0155f10225e6ec1a1e362b6f3abc5264c9d4fae7329174dcbbe4cae25629f8ccd4f3e7657992c07f5d3aef1d0f74240b7ee3ef8cc1dd53a3e93f9c0b519bdf8b1bffa434e0b6979545ac2d8c50403eabefce6eee2443c2148fda4471b383a0d06817ef66bb12ae6c6db9e3bf51c799bce8e1ec87bb5240726ee1a29df6c2c2c65f38c626cab4f9420149168cf9eab07415edfc422ee5c2b4d7fcd4aed461e868648a3048fd73b11a6d3f2da0647450ef55678fe2129d6fb686aebc79a84a841ede25a8f2b32ff4e55c10958c75bdf559b3a31e6f71e57014bac48e495c83e5988163c194b70817a1f5db4104cf825af7686b72c66d9ad0a5e2fa459b0c0cd28abe2155e83646236bb443a2c9bb7249ac3d1249f71e344d92eaf8aadf7a153613677b1349dcef1613d6cbfc5fd8b855d33d250a5778ca", "12c", "5805533d97c52a599289d9c39b63c6f3df601bbd1df2b84c3ce3ceefab505ba86e0adec168bfcd5eaa9fd6592359239cae9a691a2e8af4812e2a3d302c6ae583226929e277a6a715670994efe58d0be00bc68b6f0b32d0b77bce66073cc52332269d16f37bf4dd12723e1818c5828e2d7ae692d7ec16da2934f4a1d7b0a0e00752bb8cd79d0484fa5e4e40dbc7ca5c713e90beca33c0d8f77a8ee8f7143126a0248ca02464235fff33b671d2bd921a3650a697c9caabc842cb976ec0715acf0bcd2fd00ca1a73971deda0155f10225e6ec1a1e362b6f3abc5264c9d4fae7329174dcbbe4cae25629f8ccd4f3e7657992c07f5d3aef1d0f74240b7ee3ef8cc1dd53a3e93f9c0b519bdf8b1bffa434e0b6979545ac2d8c50403eabefce6eee2443c2148fda4471b383a0d06817ef66bb12ae6c6db9e3bf51c799bce8e1ec87bb5240726ee1a29df6c2c2c65f38c626cab4f9420149168cf9eab07415edfc422ee5c2b4d7fcd4aed461e868648a3048fd73b11a6d3f2da0647450ef55678fe2129d6fb686aebc79a84a841ede25a8f2b32ff4e55c10958c75bdf559b3a31e6f71e57014bac48e495c83e5988163c194b70817a1f5db4104cf825af7686b72c66d9ad0a5e2fa459b0c0cd28abe2155e83646236bb443a2c9bb7249ac3d1249f71e344d92eaf8aadf7a153613677b1349dcef1613d6cbfc5fd8b855d33d250a5778ca000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "ff59f250ce5dd8b0550507420993dbc26f21a18ee3fd1603755e536ee4fc3e9f617610849880277a5c5f56b7802f7a4b01de855e63fb51b7fedf2fa6fbb2ed98715160d7485aaf439b6dad668ec42f0b5458f7afe8c368a23795c18211b2b209189a5b88500a315b347346fc400d955828b40df4511a1c4bdcf2ce3979d3e1b633103546b60e95559918c917bc72f46b16aabff88d3e3a776f8e766170dfab958c4b7306e99335d22a70831db3db4488a70e48cd23d00e9d1da8335d4a5d001e971ce640b2b9afd936049cc8cf2743898636c62b4b73860813c024034d888e55f5a7d6915eec5dcb70ac82a2f9d2a526d19562ffc7ea291dfb61e51689ae89822966e9fe848055804fa38aa5ef132ef9f61b1ac2a91ea8f44192595a452250a8bfd44dae62e671a6d2ab96ad1a1ce4d81f1f235e24402701dd9a5ab01b8b7d530d93037de0fc6eadd67e36cd6574e95c1966ff7cfa8f3ccd2bdb96cea884f26ce2c4c196de8c553084689044fb431a62e94ad8547b77efc7251ef415a24b5217e8abcc373ae50f786edd2760f796a29f458c5255ccdc8a2abb6bf1edb260e339583ef84a6b8c34e748188b67f2200c5873478ac533a37f2fe914dc6636547d308816dc33f63182d80a954dbb29d347ef8bb6ad1a76687cbcb634689304a67300f1a943776b93fe28fda46ed528105501e94b93ede98d645e863b364a0775ebc8", "21c", "ff59f250ce5dd8b0550507420993dbc26f21a18ee3fd1603755e536ee4fc3e9f617610849880277a5c5f56b7802f7a4b01de855e63fb51b7fedf2fa6fbb2ed98715160d7485aaf439b6dad668ec42f0b5458f7afe8c368a23795c18211b2b209189a5b88500a315b347346fc400d955828b40df4511a1c4bdcf2ce3979d3e1b633103546b60e95559918c917bc72f46b16aabff88d3e3a776f8e766170dfab958c4b7306e99335d22a70831db3db4488a70e48cd23d00e9d1da8335d4a5d001e971ce640b2b9afd936049cc8cf2743898636c62b4b73860813c024034d888e55f5a7d6915eec5dcb70ac82a2f9d2a526d19562ffc7ea291dfb61e51689ae89822966e9fe848055804fa38aa5ef132ef9f61b1ac2a91ea8f44192595a452250a8bfd44dae62e671a6d2ab96ad1a1ce4d81f1f235e24402701dd9a5ab01b8b7d530d93037de0fc6eadd67e36cd6574e95c1966ff7cfa8f3ccd2bdb96cea884f26ce2c4c196de8c553084689044fb431a62e94ad8547b77efc7251ef415a24b5217e8abcc373ae50f786edd2760f796a29f458c5255ccdc8a2abb6bf1edb260e339583ef84a6b8c34e748188b67f2200c5873478ac533a37f2fe914dc6636547d308816dc33f63182d80a954dbb29d347ef8bb6ad1a76687cbcb634689304a67300f1a943776b93fe28fda46ed528105501e94b93ede98d645e863b364a0775ebc8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-5546d85e66d476cb91b5004528af4752956df433b0cc87c630f95a5e721a332ab2cc7ff38db61a842b1a58abd2c4d9f132778124187ffd5437e29da82da2388ecbe7e06469ac0ea366f8b4b01cd6b968b0c3c55b3615929d89b25f604702a2f183cac89aa438e44dabde63f2da84159da91f92a6967f82087ee974beed0baf6c5f9d6c814503f53f6bf5690261a582adb3a18cf5c284423ac7df3e5d6291e32cc4a4088480a2ad194972738e86342f60b99f9f9deb04a8060fc6ec23d3054ef2729f2d92c19a682caa131ef8b387094623ffbc887155131a1cdc2291905c8ac26fe03bbf03e303b6c881d3b318a990f1d6ccc0a66ce811fd16036e4543f3b304ad8f50fb70784472831fef40e40bd09ba5f28475f3c6415f5c8dd550008d19f8e8051bd0d01827ea2ff9a6326ee91f9e171ba53ffc6a4033d70382bc534c28d448944a35569738a488037bd32ed670df3ce9c86113363bde3dbbee7808127440b438fb9c7e052c8320ef70be56c3b154a0d590ee330ba30ad3505d7d5ee3613e984ff6708875c4f67c9d9b9d4640b1d85c361aabd3c2aa7e474a4f23963435783a4ad89d20b26edabf04d924e01e5a4af1d1ed75ecf0d27121ba72283488a25ed6c3176a5d473c12a788cb5f9365662e5efd32d7221505e6286c3564f89077e5ef03a44af940c281fd3ea37b9be3054a6adf1692c151d7951765db6af93ef456", "78", "-5546d85e66d476cb91b5004528af4752956df433b0cc87c630f95a5e721a332ab2cc7ff38db61a842b1a58abd2c4d9f132778124187ffd5437e29da82da2388ecbe7e06469ac0ea366f8b4b01cd6b968b0c3c55b3615929d89b25f604702a2f183cac89aa438e44dabde63f2da84159da91f92a6967f82087ee974beed0baf6c5f9d6c814503f53f6bf5690261a582adb3a18cf5c284423ac7df3e5d6291e32cc4a4088480a2ad194972738e86342f60b99f9f9deb04a8060fc6ec23d3054ef2729f2d92c19a682caa131ef8b387094623ffbc887155131a1cdc2291905c8ac26fe03bbf03e303b6c881d3b318a990f1d6ccc0a66ce811fd16036e4543f3b304ad8f50fb70784472831fef40e40bd09ba5f28475f3c6415f5c8dd550008d19f8e8051bd0d01827ea2ff9a6326ee91f9e171ba53ffc6a4033d70382bc534c28d448944a35569738a488037bd32ed670df3ce9c86113363bde3dbbee7808127440b438fb9c7e052c8320ef70be56c3b154a0d590ee330ba30ad3505d7d5ee3613e984ff6708875c4f67c9d9b9d4640b1d85c361aabd3c2aa7e474a4f23963435783a4ad89d20b26edabf04d924e01e5a4af1d1ed75ecf0d27121ba72283488a25ed6c3176a5d473c12a788cb5f9365662e5efd32d7221505e6286c3564f89077e5ef03a44af940c281fd3ea37b9be3054a6adf1692c151d7951765db6af93ef456000000000000000000000000000000", .Okay}, + {.Shl, "5e287bc0f618f8ffac92279ca376724aba0f5b21bd302a815f6d7ba073648662103610fa65db6f5b510a17c6f59c7b136e8182a365e29c3045a7812ef8df1411cc81ac438c63f2c90aa1d07c14aedf5de93037ca9cf7b802c23ce9a6cb83c2573ffb7cd54c7a3a24d4fe341c4d1c193bf9bb5b9a1a5b1b10a02aa7c08a94c7309962d81dc65139b3fc13c5c6d19d0b3b8196c948927f1b3c3d8b5888733db3cda51ab9986bd6777b9df5746505150d6a966d1cf0373158aabee453a754a365dcefa1c5aab133d141735c2620dc073599173a6ddd7db22dfd8e2d46becd3cf863a9e50357d7611518ffe15972be895e29da16fc5fa551ae22071a072b306c1698f87bbc25c39ee89b251d4efd092a7a3804b50608a34f3e94693f2c16d1217c44622ed016a2152aee74d48ce797fb94eb75274b31cf7270537c853d61b421d680431dd41779f83d5a8d4707f793bb63469c441a0d57b2bf1c3544adc49bd799ebf66b50efb6c2982a45f826e5487e6bc7e8465a90ab8dc2635bcecd891ba553a1a3341cd9d80195ab7b197a7d867d458884e83af352d01912a804cf20c08685ec91a11ae6b927a1c5b56af36e2b7f271f3d5d341fd33b64abbce530037abd253b3ee82a655574347fb70c1dd56a183fd732c22d6b6abb63cfbe8e12db43b4398416f54eeada0b1bc40e83e413a72e46d532242daf1388076b9115ff934ef00ab9", "168", "5e287bc0f618f8ffac92279ca376724aba0f5b21bd302a815f6d7ba073648662103610fa65db6f5b510a17c6f59c7b136e8182a365e29c3045a7812ef8df1411cc81ac438c63f2c90aa1d07c14aedf5de93037ca9cf7b802c23ce9a6cb83c2573ffb7cd54c7a3a24d4fe341c4d1c193bf9bb5b9a1a5b1b10a02aa7c08a94c7309962d81dc65139b3fc13c5c6d19d0b3b8196c948927f1b3c3d8b5888733db3cda51ab9986bd6777b9df5746505150d6a966d1cf0373158aabee453a754a365dcefa1c5aab133d141735c2620dc073599173a6ddd7db22dfd8e2d46becd3cf863a9e50357d7611518ffe15972be895e29da16fc5fa551ae22071a072b306c1698f87bbc25c39ee89b251d4efd092a7a3804b50608a34f3e94693f2c16d1217c44622ed016a2152aee74d48ce797fb94eb75274b31cf7270537c853d61b421d680431dd41779f83d5a8d4707f793bb63469c441a0d57b2bf1c3544adc49bd799ebf66b50efb6c2982a45f826e5487e6bc7e8465a90ab8dc2635bcecd891ba553a1a3341cd9d80195ab7b197a7d867d458884e83af352d01912a804cf20c08685ec91a11ae6b927a1c5b56af36e2b7f271f3d5d341fd33b64abbce530037abd253b3ee82a655574347fb70c1dd56a183fd732c22d6b6abb63cfbe8e12db43b4398416f54eeada0b1bc40e83e413a72e46d532242daf1388076b9115ff934ef00ab9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-b4f1092062fb4c2430461df53ab456e469c1e7ad57ba6d78232a28dfe8732faa8be98df0274bc9c982d5c545cde2be20d64b271a23d3a529a946a2e74202a36bced6c4c225a016b854f65bcd50cbb0d5e63b09b8222a2e7f8dfc660dda74c5d70b21254f447412b60da95f2b43277987de03df90ca2af5437210b6c102979e2f16eabaf464a6b089e72af067e3cd67f3c80bb897b02c3c3879a2d9152363eef47d7475b3ddfd4b5a2823ed1df034eefae7f5693cb1dc4af65f48dfb991b884eb40606e8c1573cfd3dafa23a40c006f844b52a43a32ad3755adce2d4f0309362f3142e43619f270065bebf6cf2c295beced4fd41021e0d15307a47ca7516b101fec920f07a3dbf95f2cac35008dda9189c7196c043d127bf5c69ea616d8406cb4affa5f2061135aaa149f67b7ccee3e70e2a627558ca8395169bcb7f27cd494c62425d2a6064a8902601d660cbbbcac44b9acdd91c7b5f46265cc0cfcc787ec0fde3e2132e772e41e31985f20d265d8285e38e377ed8fc5ebe6c68aa91d9181347ce691a37bbdb277ec946eb58762d728f4f0e842a57f14dd5209749757da36b51ae53c4a5162800a1b3f90a9d06aef156bee04a82238c1248088f75121e8860697e761b4cc3a4e2f5aead9efcb3f18ab5e9e931c1cd217102059bf86b66a596adb77df132c938c53e86ef38fd631e3184aff138497b47dd84c73ea37bc10a52f", "b4", "-b4f1092062fb4c2430461df53ab456e469c1e7ad57ba6d78232a28dfe8732faa8be98df0274bc9c982d5c545cde2be20d64b271a23d3a529a946a2e74202a36bced6c4c225a016b854f65bcd50cbb0d5e63b09b8222a2e7f8dfc660dda74c5d70b21254f447412b60da95f2b43277987de03df90ca2af5437210b6c102979e2f16eabaf464a6b089e72af067e3cd67f3c80bb897b02c3c3879a2d9152363eef47d7475b3ddfd4b5a2823ed1df034eefae7f5693cb1dc4af65f48dfb991b884eb40606e8c1573cfd3dafa23a40c006f844b52a43a32ad3755adce2d4f0309362f3142e43619f270065bebf6cf2c295beced4fd41021e0d15307a47ca7516b101fec920f07a3dbf95f2cac35008dda9189c7196c043d127bf5c69ea616d8406cb4affa5f2061135aaa149f67b7ccee3e70e2a627558ca8395169bcb7f27cd494c62425d2a6064a8902601d660cbbbcac44b9acdd91c7b5f46265cc0cfcc787ec0fde3e2132e772e41e31985f20d265d8285e38e377ed8fc5ebe6c68aa91d9181347ce691a37bbdb277ec946eb58762d728f4f0e842a57f14dd5209749757da36b51ae53c4a5162800a1b3f90a9d06aef156bee04a82238c1248088f75121e8860697e761b4cc3a4e2f5aead9efcb3f18ab5e9e931c1cd217102059bf86b66a596adb77df132c938c53e86ef38fd631e3184aff138497b47dd84c73ea37bc10a52f000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "256213cb2ed57b1f5e07cc48907c2ce3f15c155579cbb96f7db317427811ae0216ad5fa0ccf39c9ca49fc868927b5365b2e8cfe9399c0afe355ffb72301b6fb4925fa2daeb23c0fec493f9d76fcfc3c5b6db4d49fd7f1399438c0a1d32f3b86ca41d10fba9450d2e2515791ff5079e551b7041176887c4f6046af9a50dea9bf2c2ba33a3a6ecead45f7645a3f58470934bf71b5e7663a5908444b8094fdcd4cf683d19c512a19dc95ca5bf9e5f63aefe340c34bf08f90ac0cfdc4830df9f3ff75e1874e32f6826ef93e9d0a72686b7bd22636970181ff63dfedf1398f981dab88995ab6e25701835a8de7398da18e3a0f7b50bc68de6217d9a0a55825f8d2144542db04f5cf7331f291a877230b2bc6b7f3ca2f4aa49309414c5c3e760cddfd56c478102bf4ddee91bd13eeb86bfd897201b43d1d55e5953d0310546869c154a0ab19c392ff659a95f8b259559a70b9c07f3b520a4b2c57c629fcc4b411d39dc3dc3286326a4d4a95708d96f1664c122942f70e0597b7642118e4de2ace21d2520c31a716850bff08b45d5d04b73a02e6499e404eb766544436b10d85a7c7e8d6285546c1989ccbb59e5b8d932012b5db2cf386c194a5ae00ad02c92998d2a5862679bfdb8154d57668020c1d513b64f0c446e41e075bf4f1ae502d882c70d4b306cfe0d3fe66d6d891ad944eff7e0d9f67b67484a24d96be0cd6327ad486ca3", "b4", "256213cb2ed57b1f5e07cc48907c2ce3f15c155579cbb96f7db317427811ae0216ad5fa0ccf39c9ca49fc868927b5365b2e8cfe9399c0afe355ffb72301b6fb4925fa2daeb23c0fec493f9d76fcfc3c5b6db4d49fd7f1399438c0a1d32f3b86ca41d10fba9450d2e2515791ff5079e551b7041176887c4f6046af9a50dea9bf2c2ba33a3a6ecead45f7645a3f58470934bf71b5e7663a5908444b8094fdcd4cf683d19c512a19dc95ca5bf9e5f63aefe340c34bf08f90ac0cfdc4830df9f3ff75e1874e32f6826ef93e9d0a72686b7bd22636970181ff63dfedf1398f981dab88995ab6e25701835a8de7398da18e3a0f7b50bc68de6217d9a0a55825f8d2144542db04f5cf7331f291a877230b2bc6b7f3ca2f4aa49309414c5c3e760cddfd56c478102bf4ddee91bd13eeb86bfd897201b43d1d55e5953d0310546869c154a0ab19c392ff659a95f8b259559a70b9c07f3b520a4b2c57c629fcc4b411d39dc3dc3286326a4d4a95708d96f1664c122942f70e0597b7642118e4de2ace21d2520c31a716850bff08b45d5d04b73a02e6499e404eb766544436b10d85a7c7e8d6285546c1989ccbb59e5b8d932012b5db2cf386c194a5ae00ad02c92998d2a5862679bfdb8154d57668020c1d513b64f0c446e41e075bf4f1ae502d882c70d4b306cfe0d3fe66d6d891ad944eff7e0d9f67b67484a24d96be0cd6327ad486ca3000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-42e820567bd0ef8189775fc749e5c5ca3e4ff0ce616f46d83259c00c6c06ee4f6fcc029d7473795960ad0d19fb328632cb92b9815863b63c40710fb926627902701efd0c0c31784b25ce15cb619e2ddfbdda5b4018fd3af5991cb306ea6c52527c62d3713b98a71ab55e6df194e2c3899cf28c527910297974cea837da58f776678d613c61ef2ee5f6931621a09875cea2aeb989121894053c4ad02050b365672391fae2651608604a5ec85a6bb9d6235e0aa7416ec1a5f6dd4b785be4a9488e013aa7acfb9853200e078cedd408325bd2745a1777c11e39c778a2539bea173944b976134565600fc6dbcf1f6c7d31fe43e378f90e57b90d7562fea51f73ec4f6102c47fe869497cb4f2f7dc9fb04474ecef900720e90c61176e75c93014bb3489f3be62b77019de437b7aff89f9b2f63ce615751361aafc2ee0f5af6787c0ea7a7872966de06e62de36e6d95193bea2d56ccf65a2924ecbdcdc8dcb54b0bad79befc999ebe1b7f0952f5cbc71c35d73d6b9694bed754f6750280fe7f26ef010744149dc5a099f1db624a55be69a49f204f2fbc4d59c74dc584f11ad4a0a2abbab380a8791870d00dbbc3c2d4dd1f2b2684a53dbc8bf1df72f9a8fc0532a35d79e7158659eee01e6c6625a7de9ed880a27d5e678d4b0dcb3c228cd2e872d909d48433642be12618b06f675fff90227ca4ba6be8043d5fee63aabd489a8efcd6c", "0", "-42e820567bd0ef8189775fc749e5c5ca3e4ff0ce616f46d83259c00c6c06ee4f6fcc029d7473795960ad0d19fb328632cb92b9815863b63c40710fb926627902701efd0c0c31784b25ce15cb619e2ddfbdda5b4018fd3af5991cb306ea6c52527c62d3713b98a71ab55e6df194e2c3899cf28c527910297974cea837da58f776678d613c61ef2ee5f6931621a09875cea2aeb989121894053c4ad02050b365672391fae2651608604a5ec85a6bb9d6235e0aa7416ec1a5f6dd4b785be4a9488e013aa7acfb9853200e078cedd408325bd2745a1777c11e39c778a2539bea173944b976134565600fc6dbcf1f6c7d31fe43e378f90e57b90d7562fea51f73ec4f6102c47fe869497cb4f2f7dc9fb04474ecef900720e90c61176e75c93014bb3489f3be62b77019de437b7aff89f9b2f63ce615751361aafc2ee0f5af6787c0ea7a7872966de06e62de36e6d95193bea2d56ccf65a2924ecbdcdc8dcb54b0bad79befc999ebe1b7f0952f5cbc71c35d73d6b9694bed754f6750280fe7f26ef010744149dc5a099f1db624a55be69a49f204f2fbc4d59c74dc584f11ad4a0a2abbab380a8791870d00dbbc3c2d4dd1f2b2684a53dbc8bf1df72f9a8fc0532a35d79e7158659eee01e6c6625a7de9ed880a27d5e678d4b0dcb3c228cd2e872d909d48433642be12618b06f675fff90227ca4ba6be8043d5fee63aabd489a8efcd6c", .Okay}, + {.Shl, "c9024dccb2480661424fabb9abe9b44173e8ee7bfef1229fcb770b4cfd17541197f76b3574be033160a57f49deb2747f4e6c98c418ca18037e2a611dd5236f56a43d3f774a996da2669dfcd3fc4c9f58acba5b51498853b8b600ae86336e21e06c1a84ffed483bc4cce2e48c105a176b3d962f6ac1a48a3d7f86ec6f79bf627029ed5d9f613ab879705396cbb5ff3a2165ebec57bb7f34a29c81df0cfa441c9814b8fed3e6af349088cdc84c7d2a9ad042e694fe1cf72024b9da729d38e015e99b43dea9dfbe22b636fe7531bc61998c65a1766e2d90afd1b823390266bb8d47938ca8e0a3523a9f5930162c5f3db81fad08bdfcc2f3ec91e8fa05bca0cf0976c5cb5290e229902ea67c3dc1464fa1cb72388157c1fef67f7cb1804c8cbd397ef2d9bd9b39db47fc74ff94872514f69ea68b83f0bf69d66f5f1a8df140c518a17ce6f08367ef7442ea50f2cb9a2673391a0044457013eac70f50264031efd9155acf3e61e37e6e7530a10846c795272754b7330c91fe9f5a642b8960cb2aec2e12485206e6c7f95283c3578d333a8e78faf19dcadb5d7d46a6425640fc3dd712f8285455c62291031d40c8201a45eb9ae84508c2a5311062135bc6b8b0bd80851d273dc462230bc9d1eba68b969adbb2d0609d4ea4726173cfa6757fa77aaa13c660ddc79677607c397d8b5d04ae757351c586031eb4c71906f069f9e97ec100", "1e0", "c9024dccb2480661424fabb9abe9b44173e8ee7bfef1229fcb770b4cfd17541197f76b3574be033160a57f49deb2747f4e6c98c418ca18037e2a611dd5236f56a43d3f774a996da2669dfcd3fc4c9f58acba5b51498853b8b600ae86336e21e06c1a84ffed483bc4cce2e48c105a176b3d962f6ac1a48a3d7f86ec6f79bf627029ed5d9f613ab879705396cbb5ff3a2165ebec57bb7f34a29c81df0cfa441c9814b8fed3e6af349088cdc84c7d2a9ad042e694fe1cf72024b9da729d38e015e99b43dea9dfbe22b636fe7531bc61998c65a1766e2d90afd1b823390266bb8d47938ca8e0a3523a9f5930162c5f3db81fad08bdfcc2f3ec91e8fa05bca0cf0976c5cb5290e229902ea67c3dc1464fa1cb72388157c1fef67f7cb1804c8cbd397ef2d9bd9b39db47fc74ff94872514f69ea68b83f0bf69d66f5f1a8df140c518a17ce6f08367ef7442ea50f2cb9a2673391a0044457013eac70f50264031efd9155acf3e61e37e6e7530a10846c795272754b7330c91fe9f5a642b8960cb2aec2e12485206e6c7f95283c3578d333a8e78faf19dcadb5d7d46a6425640fc3dd712f8285455c62291031d40c8201a45eb9ae84508c2a5311062135bc6b8b0bd80851d273dc462230bc9d1eba68b969adbb2d0609d4ea4726173cfa6757fa77aaa13c660ddc79677607c397d8b5d04ae757351c586031eb4c71906f069f9e97ec100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-467ef30f007bbca9a0c8d5a62ac21ff51510ff9d43a2f5b9c508fbfac0d3afd76113750b7d75f8c5d4a8a70302cc34bd47c5e308790a265bb55d63333fced652fd2275c32d047351b9c956037d7e8addd753a2253a31537260a648079e47f4f9b48292768343aedbe86a3725d91e563c8d32b118be9b393c812d5796934e0135e06808047d53dbc84a11eaf0c728690e4f6b32ac0c02d3808d1af5b64ad1069c5ad0dd240289a31e147b264347bf500a5bb8df6c8ae5fc3f3a663714821b1a0ed30d0d78661d8ff2b0694f240bb493c4fda5ecdd122f885d3f7c26f575b6a8dda1ea019ae914bdac3bd58ba13473fcf98d72f29b960022785de2fb68a54d8091c64633fd404ef93b8551b9f4d3b01a76663cdba7123108c22ee70a30251a5e77c42f2622709b0be0a032524ac33a9920827d162c1062dbe2e1336cd2d1180ccb7e74ab3e199cb34bb0f798d875882f1ae729764d1e1273888be742693cf95a8a238df55becfa8facb052cdce2c4a38e984181ccbf7ec179ac86ef9f4811e31ccd84233a7b478785c769303da4f231dc29f94195106a56c42bc204e939b0aabbcdf5bc7fb7845fa3de7c870689936e76e41140f2d0a733b6285b94ae734c138325390c8f2a9132cf8c25983c29789536795b0cd54e448575392859a5228e208470077ae4b52de7905b89606bd4f4b1ceb1d9afbd17dd7774b9e08675e2967c21f", "b4", "-467ef30f007bbca9a0c8d5a62ac21ff51510ff9d43a2f5b9c508fbfac0d3afd76113750b7d75f8c5d4a8a70302cc34bd47c5e308790a265bb55d63333fced652fd2275c32d047351b9c956037d7e8addd753a2253a31537260a648079e47f4f9b48292768343aedbe86a3725d91e563c8d32b118be9b393c812d5796934e0135e06808047d53dbc84a11eaf0c728690e4f6b32ac0c02d3808d1af5b64ad1069c5ad0dd240289a31e147b264347bf500a5bb8df6c8ae5fc3f3a663714821b1a0ed30d0d78661d8ff2b0694f240bb493c4fda5ecdd122f885d3f7c26f575b6a8dda1ea019ae914bdac3bd58ba13473fcf98d72f29b960022785de2fb68a54d8091c64633fd404ef93b8551b9f4d3b01a76663cdba7123108c22ee70a30251a5e77c42f2622709b0be0a032524ac33a9920827d162c1062dbe2e1336cd2d1180ccb7e74ab3e199cb34bb0f798d875882f1ae729764d1e1273888be742693cf95a8a238df55becfa8facb052cdce2c4a38e984181ccbf7ec179ac86ef9f4811e31ccd84233a7b478785c769303da4f231dc29f94195106a56c42bc204e939b0aabbcdf5bc7fb7845fa3de7c870689936e76e41140f2d0a733b6285b94ae734c138325390c8f2a9132cf8c25983c29789536795b0cd54e448575392859a5228e208470077ae4b52de7905b89606bd4f4b1ceb1d9afbd17dd7774b9e08675e2967c21f000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "9ca321cbdd1befb67724d84555f0286181118f7a1fa8416190ff946847c58bf88734d809c08b9d3767d6c1e471479bb4741a374e7a553ba11cf2dd40ce5687d3dd17b003b4327a7bb42eaeea9f940c76037926312a1482cd2491861aa94b2fcb7f4993fe52224ff950839c0e93d5368419c43f20d7f09331823089e27a99b4d06c1bf89569122deb391c8e6512df5408e94af33de33bc650c10be9038e8b52cd656a442c59ab8945b66d770770af86637d89089f00e79a6638568b766dc19af82ec599d3331203a3bb3cd6c86a74934b17f4eb7709df124229c675c06e62c118b562eabebbab4ed0a1708a2266d3f91533160f63ec1e5e6d61898e1f60cb63761dbf777a588b89f54e865e7c564e3d763c4d6846e94056d52c9da60364641cfc9c9b3a4a4029d2c52250b390c61721548f4b8060ddfcf8ce4769d836edd299dfe0008c050e4389985ed4e9d89f38fc7de413a40d68e778d3d7e1a4716d38b6e75b81fed705fe75ebbc33ad9fc1326618031552e0796ca5afbde6d1f24ad327c6ee2d849982e7275e6e349dfd89226eb300002f3fc6c897d61d9c6b6f09700a1700ad13bbf286b4138e2aa0aced2d50274e90a7ca7762201e9f61aee293ae5c9ef1c64ae0dd4bf5da6b6bea399277b2ec56c5c664bd33811e419d03bbe34abdd109980af2e273970314097b73a079e47022b2c5b74ffcb16e702eb6ca59e221a7", "b4", "9ca321cbdd1befb67724d84555f0286181118f7a1fa8416190ff946847c58bf88734d809c08b9d3767d6c1e471479bb4741a374e7a553ba11cf2dd40ce5687d3dd17b003b4327a7bb42eaeea9f940c76037926312a1482cd2491861aa94b2fcb7f4993fe52224ff950839c0e93d5368419c43f20d7f09331823089e27a99b4d06c1bf89569122deb391c8e6512df5408e94af33de33bc650c10be9038e8b52cd656a442c59ab8945b66d770770af86637d89089f00e79a6638568b766dc19af82ec599d3331203a3bb3cd6c86a74934b17f4eb7709df124229c675c06e62c118b562eabebbab4ed0a1708a2266d3f91533160f63ec1e5e6d61898e1f60cb63761dbf777a588b89f54e865e7c564e3d763c4d6846e94056d52c9da60364641cfc9c9b3a4a4029d2c52250b390c61721548f4b8060ddfcf8ce4769d836edd299dfe0008c050e4389985ed4e9d89f38fc7de413a40d68e778d3d7e1a4716d38b6e75b81fed705fe75ebbc33ad9fc1326618031552e0796ca5afbde6d1f24ad327c6ee2d849982e7275e6e349dfd89226eb300002f3fc6c897d61d9c6b6f09700a1700ad13bbf286b4138e2aa0aced2d50274e90a7ca7762201e9f61aee293ae5c9ef1c64ae0dd4bf5da6b6bea399277b2ec56c5c664bd33811e419d03bbe34abdd109980af2e273970314097b73a079e47022b2c5b74ffcb16e702eb6ca59e221a7000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-4e0bf87f8b7bbe1344f771c7ca98fa4cee84ef43133e6eca1ccaf73f9b835fdc911af5c5c7122dec60c62bbac29ff35e8fe67a6d7ad3abebcf23c170c3f127badb72aeaa7a0cbe1ce51b0479160a906573b254532c9d937c8fc3b4f115ed0d29fa0fccafc975e4043c3cf35a72da8b3d6af80e292e5d0fe4e0915bd71eab87ffa3b25b9941d3e230be2fcb77b93a92e73325f2c8c9c91048dbeaffe5078d9c881d56165eecb000a98f488e3f0c92ff3854132a3e20bedd42613bf7663aea264e74b32bd3bc588c554e2c5bad2ab89063e8b2858b8fb2f8221eeab473460d6f04a1243a44defe9b962ca17afdc55c11fde5e83eb902b78986231900c613f9519c583ea57f82ce148030307b64653c13294033237039a1e466de972c56356cac5a2452d5e72c7a7aa2cb51a84112d3e392e3f7d96ccf5aa514b5e4205cb7b7f99b963219d82b9f2023d9a17d3d13eb180fc81ab18aa2b0fcdeff6313c4430d36505e8a2f1e5b08d1c3fed5ce531e1489742fee7991172e3a46343272e3db69375acef081c3f3b108697bba9107bd1773e6754eff36dae17ea693d6565f830cf8fe42a4dc59fd618f94489bf9d4512edfde0f1c71bbc17a0910328af9797df2f20250e649a53c417ef83f349eac4187149cec61a56317f7df810937f00bd28b02b8e4a99090cfeddd4fa5e4f992f3513ead1370ce869b61afc68c24b1e139f735e4", "78", "-4e0bf87f8b7bbe1344f771c7ca98fa4cee84ef43133e6eca1ccaf73f9b835fdc911af5c5c7122dec60c62bbac29ff35e8fe67a6d7ad3abebcf23c170c3f127badb72aeaa7a0cbe1ce51b0479160a906573b254532c9d937c8fc3b4f115ed0d29fa0fccafc975e4043c3cf35a72da8b3d6af80e292e5d0fe4e0915bd71eab87ffa3b25b9941d3e230be2fcb77b93a92e73325f2c8c9c91048dbeaffe5078d9c881d56165eecb000a98f488e3f0c92ff3854132a3e20bedd42613bf7663aea264e74b32bd3bc588c554e2c5bad2ab89063e8b2858b8fb2f8221eeab473460d6f04a1243a44defe9b962ca17afdc55c11fde5e83eb902b78986231900c613f9519c583ea57f82ce148030307b64653c13294033237039a1e466de972c56356cac5a2452d5e72c7a7aa2cb51a84112d3e392e3f7d96ccf5aa514b5e4205cb7b7f99b963219d82b9f2023d9a17d3d13eb180fc81ab18aa2b0fcdeff6313c4430d36505e8a2f1e5b08d1c3fed5ce531e1489742fee7991172e3a46343272e3db69375acef081c3f3b108697bba9107bd1773e6754eff36dae17ea693d6565f830cf8fe42a4dc59fd618f94489bf9d4512edfde0f1c71bbc17a0910328af9797df2f20250e649a53c417ef83f349eac4187149cec61a56317f7df810937f00bd28b02b8e4a99090cfeddd4fa5e4f992f3513ead1370ce869b61afc68c24b1e139f735e4000000000000000000000000000000", .Okay}, + {.Shl, "-849bd0179537e278bde3b311e3c38e64f02b7a3e4858f7c68e9df29c21cda2e14814cb86150a96790c0e527119314139e165b00f026c90d2de0cf7e164bf21cfb653037971c620a9fdc2ab7111d0ff13bb98d49e05719d92ea875a16a0bf496722245163f6c4081c6154b15cb931684fea8e00b99c40c90ef789950ce95e541919f3a423fde5c5dfc1a8cc5a130d96404c894d3131aa968576a5f83cbdce13143140f1f29f61e1f3fe966b198b4971095db50035889aeae0ad09b76c016785dbaa18ea20a7ca873666be59dfdeab4583003f95aa9601818c92b0d0d9217421825d0c8f00093b03c1d1525d7b3f50037a5a95224e346282c70854d9f0565115af158d64615485c893dfbdbfac876d59071c72d8726aae8de4ab128212b0ac60709fa670ab23be6eece9c1e73067fd52e471acb97239bf40ee1d473af0d2d3bec49e7516d2de6ecb790f576b59bcf7423460eb04f3b194c98e13a32fe02f719b789ea3a87087074ceed6bc825696fe9427e898292a05e9ed3afe6781c0c7bc465181ddd8e3ffd8bb11e46eba641e4e35ea6222cd342ebd6549412586df264c735ff9eec66a3e85f524caff288fc41362307ee9e7c762d38d84614de2235838f2dbb58d4ba37628b9fdab825dca34f5cd17b0edb3c502236bf64d3de66ab78dbd7cc390380fdcb43a6e8c333fcff5d01ca1dba4ab3597e35581b6597532aa682f53", "1a4", "-849bd0179537e278bde3b311e3c38e64f02b7a3e4858f7c68e9df29c21cda2e14814cb86150a96790c0e527119314139e165b00f026c90d2de0cf7e164bf21cfb653037971c620a9fdc2ab7111d0ff13bb98d49e05719d92ea875a16a0bf496722245163f6c4081c6154b15cb931684fea8e00b99c40c90ef789950ce95e541919f3a423fde5c5dfc1a8cc5a130d96404c894d3131aa968576a5f83cbdce13143140f1f29f61e1f3fe966b198b4971095db50035889aeae0ad09b76c016785dbaa18ea20a7ca873666be59dfdeab4583003f95aa9601818c92b0d0d9217421825d0c8f00093b03c1d1525d7b3f50037a5a95224e346282c70854d9f0565115af158d64615485c893dfbdbfac876d59071c72d8726aae8de4ab128212b0ac60709fa670ab23be6eece9c1e73067fd52e471acb97239bf40ee1d473af0d2d3bec49e7516d2de6ecb790f576b59bcf7423460eb04f3b194c98e13a32fe02f719b789ea3a87087074ceed6bc825696fe9427e898292a05e9ed3afe6781c0c7bc465181ddd8e3ffd8bb11e46eba641e4e35ea6222cd342ebd6549412586df264c735ff9eec66a3e85f524caff288fc41362307ee9e7c762d38d84614de2235838f2dbb58d4ba37628b9fdab825dca34f5cd17b0edb3c502236bf64d3de66ab78dbd7cc390380fdcb43a6e8c333fcff5d01ca1dba4ab3597e35581b6597532aa682f53000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "393bbd970e759fc35b8aa943fd92774c4a4315415909a054c9d18ca5b81119eaf613e0cea9f79f7cd8706da6ff566395b177f55c483685659ad856d9f5a5c814dde53a55e55377858c669258451a6d0f246e30141a2d4a41ea895b49444eaae50d1892bf0495bc12206da1ab50ab35f3a3f1978593f5996b4cb0bd5d814b8934201318ce8428d0dc2ffe3fc0a916509be24c3a0632add2767faf27dc90f23eb2bff7fa6dd5706e70a67b635a0d670feb817174200f1578a65022b4bb6c5ce103b4a57d84281e3aa17c445c07bbd9445b10650d645bbfcfba0db966c959f2bd9f3a48ae76ccf5000fb2e1d91e83e33aa463646b71e8a20e6e17035984c3b215f2566fbfe3f6d88f74f46cab4e9b414f7cb0ad61e3974fe93fff3e0af61e913cb053fceee54ff75c23ddc289a6bda6dd398d1e7fbb916a8e3f83d495402291f8195d4e4675ad501c4973fc59446c7060b5b6d1aab89637bf8191135dd926b17b21120a0d28a5a65698dac93220a118cc1d817a3af7d4e7c5028b1100cf368eb248a43335c9e2e13215e18f696c651e1a47e5579f0eaac21434406cd3042e00174ae7ab5c5e09860faaf06170e0151d90d734dd3db441ba2c7b9c12f0b1093684fed0967ca9ba6ee5297f10530025ee29d7d2ef0581c932cc557bcbd5589930f1246216852e0a87cc7495987ca4a8c35d4ec90761de2b441879a8655ce6638c7083", "0", "393bbd970e759fc35b8aa943fd92774c4a4315415909a054c9d18ca5b81119eaf613e0cea9f79f7cd8706da6ff566395b177f55c483685659ad856d9f5a5c814dde53a55e55377858c669258451a6d0f246e30141a2d4a41ea895b49444eaae50d1892bf0495bc12206da1ab50ab35f3a3f1978593f5996b4cb0bd5d814b8934201318ce8428d0dc2ffe3fc0a916509be24c3a0632add2767faf27dc90f23eb2bff7fa6dd5706e70a67b635a0d670feb817174200f1578a65022b4bb6c5ce103b4a57d84281e3aa17c445c07bbd9445b10650d645bbfcfba0db966c959f2bd9f3a48ae76ccf5000fb2e1d91e83e33aa463646b71e8a20e6e17035984c3b215f2566fbfe3f6d88f74f46cab4e9b414f7cb0ad61e3974fe93fff3e0af61e913cb053fceee54ff75c23ddc289a6bda6dd398d1e7fbb916a8e3f83d495402291f8195d4e4675ad501c4973fc59446c7060b5b6d1aab89637bf8191135dd926b17b21120a0d28a5a65698dac93220a118cc1d817a3af7d4e7c5028b1100cf368eb248a43335c9e2e13215e18f696c651e1a47e5579f0eaac21434406cd3042e00174ae7ab5c5e09860faaf06170e0151d90d734dd3db441ba2c7b9c12f0b1093684fed0967ca9ba6ee5297f10530025ee29d7d2ef0581c932cc557bcbd5589930f1246216852e0a87cc7495987ca4a8c35d4ec90761de2b441879a8655ce6638c7083", .Okay}, + {.Shl, "-cacaaaabf4a0f6bc2a220f0d2d115ce7cb2078b81b5ba27e53c197800351e59b7a31305b8d4a2347667d3108c98c95957788a7b0af7e3ce466bfa3ada704e75b885721313c9ad0fbc547b97c4a84f4aecce401e58bd05a590e5caa9dd2d0a2e46eb960f3571f91c729a1b493ede94c82149f74879bb438a801b18b6d53d8d4ceee97b382d71cb2cf4df6579bf9b63de18692013590a459c3f45221a2c587f8dff11d109b0b7537a69f8624cb5de4d148a20087d0531c51c81fff2cb92d19014d6ceb3305d8eab6b8bec6d35db2199f213bcdca0156920eab339606639ed58ac9e8ebce7a2f5e95f50e5e4a52b0d4c5513bc29c303e2f0d73b03d7b3eff7969ea377e2b2ec526966e7ee0bb5b6d7fb48a388823182fa6d56d4b9aaefc78ffef89825cfcdc894d55fd851476bdc0d7ebf52be8971b8c0337ae448e1117e087ad460f4f053af1787b0884e4e89d97858056f6f0e3d51a7806412eb799277e531a5f4875294cdf8c8c493a7512c6063e3d94aabad8a83bf4512b371dcec0f7ffdbed710bcc194f8b9864c9bf1877a9b6f1301ab9d8c44fc5d4bc6cbff3acabe2cfd18e42c35e47306ac1ade3f2aa99a059540e7425d5fa3366fb9e566c34cd7e714615c37ee8f45ecbd38db91b46d61c943a394227d3d23115f15a4da46f00abbb5b722fddb1a912dc219ccd204bd1160138b5339b08735881943d68ee4573484a57", "3c", "-cacaaaabf4a0f6bc2a220f0d2d115ce7cb2078b81b5ba27e53c197800351e59b7a31305b8d4a2347667d3108c98c95957788a7b0af7e3ce466bfa3ada704e75b885721313c9ad0fbc547b97c4a84f4aecce401e58bd05a590e5caa9dd2d0a2e46eb960f3571f91c729a1b493ede94c82149f74879bb438a801b18b6d53d8d4ceee97b382d71cb2cf4df6579bf9b63de18692013590a459c3f45221a2c587f8dff11d109b0b7537a69f8624cb5de4d148a20087d0531c51c81fff2cb92d19014d6ceb3305d8eab6b8bec6d35db2199f213bcdca0156920eab339606639ed58ac9e8ebce7a2f5e95f50e5e4a52b0d4c5513bc29c303e2f0d73b03d7b3eff7969ea377e2b2ec526966e7ee0bb5b6d7fb48a388823182fa6d56d4b9aaefc78ffef89825cfcdc894d55fd851476bdc0d7ebf52be8971b8c0337ae448e1117e087ad460f4f053af1787b0884e4e89d97858056f6f0e3d51a7806412eb799277e531a5f4875294cdf8c8c493a7512c6063e3d94aabad8a83bf4512b371dcec0f7ffdbed710bcc194f8b9864c9bf1877a9b6f1301ab9d8c44fc5d4bc6cbff3acabe2cfd18e42c35e47306ac1ade3f2aa99a059540e7425d5fa3366fb9e566c34cd7e714615c37ee8f45ecbd38db91b46d61c943a394227d3d23115f15a4da46f00abbb5b722fddb1a912dc219ccd204bd1160138b5339b08735881943d68ee4573484a57000000000000000", .Okay}, + {.Shl, "-bf9ef327d8275024f8ac1357a4daab50ee2df6c814d1644ec286e37485ddb0d04ff340671714e641ec8f141d159a3da1b548f054730e81b861ede530433fe721a9c577ccb557d75fdf7f5a07d2480010a9e896f9598cd7d9564c07f9f85b46346ab81aef26894d5f47b5d8158cb9654db93fe791d104f05e4f25bfb86500302fd33f256d034c4d21a9dd88e2fbf7ebcc16b9898d0ffd5e06d112648846282e9f7f2d9698215a3087d2b480418d255737d6dc2cc81ac4f1d7833da985dc982fc3f00a5b3d1d972f345da3f69b8ce418238f1a4eead96ad5bd841e96878c508ff625db11715e2cbcddc54d16f34e33f0f53bb75d9a5cfb414863d6225a6e92aee64c3a16d1911cfb503d56ac209ae96cace6bc3806e288a5313bf6f3e548bf163852ee965be7f2163c94510793e2850c0b0c2d2815eee2f4078b3c8652c0a39fbc84db095985025a9c422779ada62077b6d10479b5c7289f55d77a22691710b17110f5a98450af370d122b234d5e5c10c665a09a09d50b2e5a9f4f21eb9f1afbfedcaeed1b2733a6b787bca3d6464b917cd98069e732414e4d60759fad6c572952b07c7f51058ade7dfa692f4cdd1b0bc97db6675ed139d23f3f8e20386a7c04e8c61d9e20033495ee25a5cfdc05e2eb370fa629b39ce2fe0fdc3b1df22faaba8741032528d6f06f4c128e39fa94459c7737d750f90771176f24d7545d21a26aee", "78", "-bf9ef327d8275024f8ac1357a4daab50ee2df6c814d1644ec286e37485ddb0d04ff340671714e641ec8f141d159a3da1b548f054730e81b861ede530433fe721a9c577ccb557d75fdf7f5a07d2480010a9e896f9598cd7d9564c07f9f85b46346ab81aef26894d5f47b5d8158cb9654db93fe791d104f05e4f25bfb86500302fd33f256d034c4d21a9dd88e2fbf7ebcc16b9898d0ffd5e06d112648846282e9f7f2d9698215a3087d2b480418d255737d6dc2cc81ac4f1d7833da985dc982fc3f00a5b3d1d972f345da3f69b8ce418238f1a4eead96ad5bd841e96878c508ff625db11715e2cbcddc54d16f34e33f0f53bb75d9a5cfb414863d6225a6e92aee64c3a16d1911cfb503d56ac209ae96cace6bc3806e288a5313bf6f3e548bf163852ee965be7f2163c94510793e2850c0b0c2d2815eee2f4078b3c8652c0a39fbc84db095985025a9c422779ada62077b6d10479b5c7289f55d77a22691710b17110f5a98450af370d122b234d5e5c10c665a09a09d50b2e5a9f4f21eb9f1afbfedcaeed1b2733a6b787bca3d6464b917cd98069e732414e4d60759fad6c572952b07c7f51058ade7dfa692f4cdd1b0bc97db6675ed139d23f3f8e20386a7c04e8c61d9e20033495ee25a5cfdc05e2eb370fa629b39ce2fe0fdc3b1df22faaba8741032528d6f06f4c128e39fa94459c7737d750f90771176f24d7545d21a26aee000000000000000000000000000000", .Okay}, + {.Shl, "5134cc48c59668aa9068f5d1433f0902d7023c5f7af6394a8420d05b17a15fd84cb19535f2419475f190aa1826d6a31756d4cf67a4d8ffc600f8ae4e731217860f84ed45a407ad80d4b7613496ce4cddcea1ac38c0d99eedd614dc2c7e2ef65a495a9702bc15276d9ebe6935665cafb4ec3fd46ad2733f050396cc91a655f4101d327a580ab7324f445072e4f6cf0f58b409f47853c98e3b246995ecec4be5e566ec78f3ee5efb6cbe48c46766c3e2ba412365508e09eacc464557e1b97d1a70d177ff20f18d7a96aa05788d4408501a4b8dee312613a26df7e3cfb11da5a2299b436f825452d0854031abb6a1d9896f5104b6eab8417600331ba39bd0b0c82838b4e43d944b9443f1124032b92a3504db621a577b3eb9c34c7d1175a40fb8ac3f4742049def4bfec4a3e7085cfd3410cd4ba429c217846f1f1cbdef3b998c80a15e7d49c89e8d986b267053058cfe8809b2c8e4e5b8e24780c9d4b9f26d18f21e133f6df018e00cb8e6f6e8ad27b78e39502f201554a1eb2b250a2311d3c217d8595c23c0b95837d29791bf39344f56ab423cf63ba763c1499db6d72e948c46c639b51784be81fa11958a8760979221f4631db44e5140a75870cd4862d764e0786f65fc14ae0335d81c6ed141ecb0d2c864ba0a074e0434054c965b52643fabc6b7979f599aa7b92523ebc4a53c58c0568e3c34dbc8a3718a8841cd4b92eda8", "1e0", "5134cc48c59668aa9068f5d1433f0902d7023c5f7af6394a8420d05b17a15fd84cb19535f2419475f190aa1826d6a31756d4cf67a4d8ffc600f8ae4e731217860f84ed45a407ad80d4b7613496ce4cddcea1ac38c0d99eedd614dc2c7e2ef65a495a9702bc15276d9ebe6935665cafb4ec3fd46ad2733f050396cc91a655f4101d327a580ab7324f445072e4f6cf0f58b409f47853c98e3b246995ecec4be5e566ec78f3ee5efb6cbe48c46766c3e2ba412365508e09eacc464557e1b97d1a70d177ff20f18d7a96aa05788d4408501a4b8dee312613a26df7e3cfb11da5a2299b436f825452d0854031abb6a1d9896f5104b6eab8417600331ba39bd0b0c82838b4e43d944b9443f1124032b92a3504db621a577b3eb9c34c7d1175a40fb8ac3f4742049def4bfec4a3e7085cfd3410cd4ba429c217846f1f1cbdef3b998c80a15e7d49c89e8d986b267053058cfe8809b2c8e4e5b8e24780c9d4b9f26d18f21e133f6df018e00cb8e6f6e8ad27b78e39502f201554a1eb2b250a2311d3c217d8595c23c0b95837d29791bf39344f56ab423cf63ba763c1499db6d72e948c46c639b51784be81fa11958a8760979221f4631db44e5140a75870cd4862d764e0786f65fc14ae0335d81c6ed141ecb0d2c864ba0a074e0434054c965b52643fabc6b7979f599aa7b92523ebc4a53c58c0568e3c34dbc8a3718a8841cd4b92eda8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-b7d42c6ca8783312d5d60819586ab645a63045e51cc0a1e535614034344dff23286960d3d2dd879d3683e8a6044b87d536c501e245b84e1f06528da71b4fabd72c1135374afc49ac39b15880dea7a50e7f8a76c22cfd160922fe661572bf5624f57bcc09085b2b4b053da1b9fd464f1eeab92b36be6106c7c7e8c0af441785e251e76d55fe6b5baf37e6d25333009596c0d8de82051f6b0e3cedf0c29433d86ecdcdd4700d8b032f20cba68e68635e8dd15d0d4e381c31c75a65781c3814ad4d97b2600fa47ac4a5a936a6ed6974032c67f05d8aefe2f7d013bef63d4a84e9ef45a259a9f9bd9cd9df1c85c457605b5ccd59930bbd54be635e5c9ae26f3fbde431c9cc228082188b78bca02194b41abe666b2f8f6ca13e9087bad10019e06d369bfbf45aa606ecded1493a5182f5f29237387b01c9c6980dcab0bb6900281969c358eaac8d92f7262c9baa4c8efd0307b467df99cb76fd755b3641bef5db96447faf1e714553687dc6a5109ede5f5215c13577bc129f22fd32bfd18121178039eef7893fef0aea2e7b0f7eef327ff38da7aa8392aef1bd6519fb98e43ab7f82fa2ecae0f04d1614568133ceb7598429401388995d384de700f2e35233400e4a1090c96d8d70ba00039180f4753618bd09793024d3964668a2732f56e7915b94e6ebdf61f7d4f2cfa04fb71fdd1cc0819c0f0f0ae8ac0ddf3edc435dd0bd15be0", "1e0", "-b7d42c6ca8783312d5d60819586ab645a63045e51cc0a1e535614034344dff23286960d3d2dd879d3683e8a6044b87d536c501e245b84e1f06528da71b4fabd72c1135374afc49ac39b15880dea7a50e7f8a76c22cfd160922fe661572bf5624f57bcc09085b2b4b053da1b9fd464f1eeab92b36be6106c7c7e8c0af441785e251e76d55fe6b5baf37e6d25333009596c0d8de82051f6b0e3cedf0c29433d86ecdcdd4700d8b032f20cba68e68635e8dd15d0d4e381c31c75a65781c3814ad4d97b2600fa47ac4a5a936a6ed6974032c67f05d8aefe2f7d013bef63d4a84e9ef45a259a9f9bd9cd9df1c85c457605b5ccd59930bbd54be635e5c9ae26f3fbde431c9cc228082188b78bca02194b41abe666b2f8f6ca13e9087bad10019e06d369bfbf45aa606ecded1493a5182f5f29237387b01c9c6980dcab0bb6900281969c358eaac8d92f7262c9baa4c8efd0307b467df99cb76fd755b3641bef5db96447faf1e714553687dc6a5109ede5f5215c13577bc129f22fd32bfd18121178039eef7893fef0aea2e7b0f7eef327ff38da7aa8392aef1bd6519fb98e43ab7f82fa2ecae0f04d1614568133ceb7598429401388995d384de700f2e35233400e4a1090c96d8d70ba00039180f4753618bd09793024d3964668a2732f56e7915b94e6ebdf61f7d4f2cfa04fb71fdd1cc0819c0f0f0ae8ac0ddf3edc435dd0bd15be0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-5eff0c9ba85d89b4f49a6996ea94e06185428baac85287cb4c8b9596b3835ff900c40a7d8686a633bb21c11ca6ad00cf81c4c045af06bf7de162f4485395c5768831b7e556aa9d2c5b4775af67988eb6c6e5874bf42f6cfbc4c6ca39d6ff4d759e0a75e6172df01305712b8164e806eff86debe670a8898fd346c1577526b70381225d4f63a10ee3a24fca424e69fbd0fd5c8df33d4a6e43a4b78975de1b674bbae7695bd34298af8b5a8ea7dae7e30fec4f53528166c5261f98eefc1587789e8eafb03c7a4704da66291bbdc66e65e050a99e2306626e3948903e0a1886335155d796d4c3266bdc04b3c712b804e72db9a98b88b7d711f95e1aed160961bf5cff5d09e54493c9ac1badce2a6135c1bb8122c19cb6969f8c0ebb8a4e8b4c65ecfba4464f1e961eed1644527bf9fe5160148270d0ca02eb40b8e282c910900eb6b3936641d28c0dd18d1e9429147cc5e7123e52b9dcb5daad3e430e5c238adec9272a8be59deaf1e0d6fe1adcd055ea65b8f3794d8fc0000d66c9dece08cc3e3f9793721a3d9e00da3006032adad09f0d73e709c95127b3568ad9240891e8f3b25bbe582496cf24acf1e690bdd776dc7cdb0c898d155e14727930643df4c5e4ecde8f1311f9bece4c7e2f143197d6a7e3b5c7116b176dd76fcb7e123f053b8d81534e71061bc42526bad4193db23b49b6ac03eb80bb159a1057fc7bb597713d0b", "78", "-5eff0c9ba85d89b4f49a6996ea94e06185428baac85287cb4c8b9596b3835ff900c40a7d8686a633bb21c11ca6ad00cf81c4c045af06bf7de162f4485395c5768831b7e556aa9d2c5b4775af67988eb6c6e5874bf42f6cfbc4c6ca39d6ff4d759e0a75e6172df01305712b8164e806eff86debe670a8898fd346c1577526b70381225d4f63a10ee3a24fca424e69fbd0fd5c8df33d4a6e43a4b78975de1b674bbae7695bd34298af8b5a8ea7dae7e30fec4f53528166c5261f98eefc1587789e8eafb03c7a4704da66291bbdc66e65e050a99e2306626e3948903e0a1886335155d796d4c3266bdc04b3c712b804e72db9a98b88b7d711f95e1aed160961bf5cff5d09e54493c9ac1badce2a6135c1bb8122c19cb6969f8c0ebb8a4e8b4c65ecfba4464f1e961eed1644527bf9fe5160148270d0ca02eb40b8e282c910900eb6b3936641d28c0dd18d1e9429147cc5e7123e52b9dcb5daad3e430e5c238adec9272a8be59deaf1e0d6fe1adcd055ea65b8f3794d8fc0000d66c9dece08cc3e3f9793721a3d9e00da3006032adad09f0d73e709c95127b3568ad9240891e8f3b25bbe582496cf24acf1e690bdd776dc7cdb0c898d155e14727930643df4c5e4ecde8f1311f9bece4c7e2f143197d6a7e3b5c7116b176dd76fcb7e123f053b8d81534e71061bc42526bad4193db23b49b6ac03eb80bb159a1057fc7bb597713d0b000000000000000000000000000000", .Okay}, + {.Shl, "571eced1adc355f12e629277b73027223c5031f2bcf5f1b64c6041230a212ac3b65781ff5ef41ce86aa18ddf6288b37f7ea66e0ba5a1f06e02e238d5f8c5d55175c7ff4819ed39f22f039cb349f962ea604ad5d97a15b4fe4ee973ec414c16b61e3d3798b6aef9394e7fb61eaca19d84275d891dd44a7dbc2c5391860796cda98a321ddd45b471d87ff6471f8c0f2ba0784bbbbb3c46a7a1cb2fc954d36d770f80e2eefd0cc2621ec6a627d79277796b8becd106ad8ccfaa681cf89e9ad40e46fca51f499a10f4f40971a579bea180eb316a6811c59a7dcef6a4cd84b87582132b3f16cc4bfb7fdd121f1c35028e20275122f7a20877e84411c05a9efe615164e1dfa8a5d686baedfface93ee332663aa02624df1cd25936cc5954a63067e91e4b697002139abcc7c836c5bcf388643d347519203b6a53d2bef771d6a21757915f17ba2433698ce4c48e6f65a3a286ca6e238e81c6b3b6da6cf27f48b9a853992774c343dd2010039a2f4331f4c1856fd3c1832352ac5b985decc7b906feaa3b4e24e667b8d7b2cc0a2c5bf295893f4efc71e26a25c4db1b45849065194bc89316ac788db521a1d6b49bf410dfbc382e49590a928a187c152816f99fcf96ba8f334638a00d8d6499ab3e00d01d73bbdea3300f41dbc1b7cdc68c52d69c1f09424957e6f51f0c32b9d8523d4357104c13deffbb8e13212a6b4448c067689c5317", "168", "571eced1adc355f12e629277b73027223c5031f2bcf5f1b64c6041230a212ac3b65781ff5ef41ce86aa18ddf6288b37f7ea66e0ba5a1f06e02e238d5f8c5d55175c7ff4819ed39f22f039cb349f962ea604ad5d97a15b4fe4ee973ec414c16b61e3d3798b6aef9394e7fb61eaca19d84275d891dd44a7dbc2c5391860796cda98a321ddd45b471d87ff6471f8c0f2ba0784bbbbb3c46a7a1cb2fc954d36d770f80e2eefd0cc2621ec6a627d79277796b8becd106ad8ccfaa681cf89e9ad40e46fca51f499a10f4f40971a579bea180eb316a6811c59a7dcef6a4cd84b87582132b3f16cc4bfb7fdd121f1c35028e20275122f7a20877e84411c05a9efe615164e1dfa8a5d686baedfface93ee332663aa02624df1cd25936cc5954a63067e91e4b697002139abcc7c836c5bcf388643d347519203b6a53d2bef771d6a21757915f17ba2433698ce4c48e6f65a3a286ca6e238e81c6b3b6da6cf27f48b9a853992774c343dd2010039a2f4331f4c1856fd3c1832352ac5b985decc7b906feaa3b4e24e667b8d7b2cc0a2c5bf295893f4efc71e26a25c4db1b45849065194bc89316ac788db521a1d6b49bf410dfbc382e49590a928a187c152816f99fcf96ba8f334638a00d8d6499ab3e00d01d73bbdea3300f41dbc1b7cdc68c52d69c1f09424957e6f51f0c32b9d8523d4357104c13deffbb8e13212a6b4448c067689c5317000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-d74621b612cc4868819f2339c41c6b3ca09854b1382dc5f08f50bee5aa10a0c2553eec7ec6581f619b0f797b164bda69639a1397b64d235bd8de22de4aed2a0938a5fcd31395b432793d52ecbb5a6c8e2a9b72991c9e48b5aefc79b9a16b4d627857fd9527d04c921c14bcb01ad75417157a64c45169ca607535b1d6e574889d17af876a741b624931ec9012488d361fc6a94cc0460e32f4d197d7a0a2ca1b9e2546eac2f8c8bd36e478e86d09caa194f97f97b57722f4bd0b42ff8a5c6dc48a547c412937d3b410c06219a2b4e12b33685992f348139627522596e57031073399a23e07efc1c6b1250bbbbd038472798d26fd3d526e725c469f999f78b5baf6f81cceca63064a93acff98005b1e60fd91ed6c4a6feb17ffad064cb2d1da18cc28005170db242cf033a8e398402afbd9b59a64d0671ccb7bb3b1c07757ce34340d09740a58f0c72e0bbf748e64dc346b80147c4d3fbbcc5042f8e8eda2fb2afd9f5417c720583784ef7614bfe972e1cf4867699f43b0ea8a24c50e29bf77c4be909cbba9213562f124eae920734d325c19d7ddf7f8b176cba91f39660e01047538263cec47388083e7f7cb5ed7a9c1e992042f80e1ddb057501cbcdb2216f561cb86636eebf810f7b8bf1956f23f29bf293775a8aa48bb9a4fec204cbe7b1e4d1054809c53400acea6cfe9b1a2a84897622083f44699f183a930b7aa2cfba1f6", "3c", "-d74621b612cc4868819f2339c41c6b3ca09854b1382dc5f08f50bee5aa10a0c2553eec7ec6581f619b0f797b164bda69639a1397b64d235bd8de22de4aed2a0938a5fcd31395b432793d52ecbb5a6c8e2a9b72991c9e48b5aefc79b9a16b4d627857fd9527d04c921c14bcb01ad75417157a64c45169ca607535b1d6e574889d17af876a741b624931ec9012488d361fc6a94cc0460e32f4d197d7a0a2ca1b9e2546eac2f8c8bd36e478e86d09caa194f97f97b57722f4bd0b42ff8a5c6dc48a547c412937d3b410c06219a2b4e12b33685992f348139627522596e57031073399a23e07efc1c6b1250bbbbd038472798d26fd3d526e725c469f999f78b5baf6f81cceca63064a93acff98005b1e60fd91ed6c4a6feb17ffad064cb2d1da18cc28005170db242cf033a8e398402afbd9b59a64d0671ccb7bb3b1c07757ce34340d09740a58f0c72e0bbf748e64dc346b80147c4d3fbbcc5042f8e8eda2fb2afd9f5417c720583784ef7614bfe972e1cf4867699f43b0ea8a24c50e29bf77c4be909cbba9213562f124eae920734d325c19d7ddf7f8b176cba91f39660e01047538263cec47388083e7f7cb5ed7a9c1e992042f80e1ddb057501cbcdb2216f561cb86636eebf810f7b8bf1956f23f29bf293775a8aa48bb9a4fec204cbe7b1e4d1054809c53400acea6cfe9b1a2a84897622083f44699f183a930b7aa2cfba1f6000000000000000", .Okay}, + {.Shl, "f310f96d9c054341ba10cd2b2ac63e274fdf68dd8260bfc9bcaf6ccd071f93d0294d138c4c586d6f3885529ae110bf6a61d9a8e9398c88a9046705af2444bd62cdeda26041785a600036fbc1c50599b8bdd2cfc09a7d173948ad75a70b4d9b73d2916062ba59c51fd17689573369ee5d991b1ce68df5dfaa80eb7a29bd656671d9e68235b19956a165bf44b864d00eb41576b16b4c87bc15ce8bb36611ba0a0c2e78c1ce06744900638dc4b0d841aa944deee2dea6133686cb2df26cc831a69e68a03ce2c4065e76ed0e9bfa92d4ca60f637a34b14f1f28071a2822c84e7e50bf733c452153a90f906462da79e2ca8a5c209223294f47058b82541851ad7cf90423a208211d3f1e985c0eabe0bc546eb1744f13fc8f7ed85aab72a8dc90edff379ec7da99096082217aff3e86debae93645258967e67e23e0342b030354ffda7a3ade8df9ad86c5324b2f36b99d9e83a19f5d8ba3ef6d6b2190fdf8ab044ca7a09a1c93714e2f330a5d98b04e3bbd57d47b9b745901b85932586e754d4ff81290b24063dbedc73a6aec1ef97336d783dce0e5ccbfb17311f539f38bec34f2756d65c6fbb32250f82a8b9f568028c71fc2511e47f16b07d221d33a797c80b02d496571f81714e50a58fcc4990a22a55c7baa8e093fe16a0730468fbf2d37ff512ebe4ebed469401a6c57ff9193e19a428edfe73b1df3073dca606ad70b3b41c50", "21c", "f310f96d9c054341ba10cd2b2ac63e274fdf68dd8260bfc9bcaf6ccd071f93d0294d138c4c586d6f3885529ae110bf6a61d9a8e9398c88a9046705af2444bd62cdeda26041785a600036fbc1c50599b8bdd2cfc09a7d173948ad75a70b4d9b73d2916062ba59c51fd17689573369ee5d991b1ce68df5dfaa80eb7a29bd656671d9e68235b19956a165bf44b864d00eb41576b16b4c87bc15ce8bb36611ba0a0c2e78c1ce06744900638dc4b0d841aa944deee2dea6133686cb2df26cc831a69e68a03ce2c4065e76ed0e9bfa92d4ca60f637a34b14f1f28071a2822c84e7e50bf733c452153a90f906462da79e2ca8a5c209223294f47058b82541851ad7cf90423a208211d3f1e985c0eabe0bc546eb1744f13fc8f7ed85aab72a8dc90edff379ec7da99096082217aff3e86debae93645258967e67e23e0342b030354ffda7a3ade8df9ad86c5324b2f36b99d9e83a19f5d8ba3ef6d6b2190fdf8ab044ca7a09a1c93714e2f330a5d98b04e3bbd57d47b9b745901b85932586e754d4ff81290b24063dbedc73a6aec1ef97336d783dce0e5ccbfb17311f539f38bec34f2756d65c6fbb32250f82a8b9f568028c71fc2511e47f16b07d221d33a797c80b02d496571f81714e50a58fcc4990a22a55c7baa8e093fe16a0730468fbf2d37ff512ebe4ebed469401a6c57ff9193e19a428edfe73b1df3073dca606ad70b3b41c50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "65c0b8136b567b40b5ab2ceedb74e0c59b84e183de29a7425042722d93ee0fd00802da12637155e0c8478c99ed546e9e19f75011a3d5387840ef26017051c56fe4214f7b603fd62357bc49fa2cf2c058e36e9d8bf14e702f275999ac3e4df5e4395cc02527652b356ad1d49d82128d61c5667d536284248075ffd5216a971610d65aa2d0be6461fe016f1100765c1baa4345e0ec8a540b3c7869e92ee6d513f7632c16ff5d05bcc9b10a9a56c792c0e020c1654729934c8245f521306832dc961838c1c04980846dd5b05c1803a368055da7556dbff71b0c7e368fc37f6fa2c634d34b8f343a53770c966b0c94708a9bebb58f200139428283c2d800417069697f85f72303f23e8c1b70a3ec47f5d1c6b97150650a1e9bb5667d55c0574c221948acbbab4c90a3f1e9e5204e71f79d2978902d0e874d7c3b6ca0afab3f401356e29730b6b6089499b6a431891ac8aeb9d4ee05315867dc507e338937ba5e75b84fd9aa112b5ccf8042aa1c48a07bbc9790a2ae4b9bd5992da50f165146b6736b94ba4f36d0b448390172378af8693fb7ab8660567684b78637b87fff7274aa8a305a79ac973facd23c8d490f6deced339554f40190f5714cb2107771a8071eb9879b64d8b47386f3b67b32f5a433e93caf15e2dcba6f81b624514d8a543afb1d7a915730cec6e62a1982e36a44d54bdd445c9ca9191bef1736b9261f6f96587c", "258", "65c0b8136b567b40b5ab2ceedb74e0c59b84e183de29a7425042722d93ee0fd00802da12637155e0c8478c99ed546e9e19f75011a3d5387840ef26017051c56fe4214f7b603fd62357bc49fa2cf2c058e36e9d8bf14e702f275999ac3e4df5e4395cc02527652b356ad1d49d82128d61c5667d536284248075ffd5216a971610d65aa2d0be6461fe016f1100765c1baa4345e0ec8a540b3c7869e92ee6d513f7632c16ff5d05bcc9b10a9a56c792c0e020c1654729934c8245f521306832dc961838c1c04980846dd5b05c1803a368055da7556dbff71b0c7e368fc37f6fa2c634d34b8f343a53770c966b0c94708a9bebb58f200139428283c2d800417069697f85f72303f23e8c1b70a3ec47f5d1c6b97150650a1e9bb5667d55c0574c221948acbbab4c90a3f1e9e5204e71f79d2978902d0e874d7c3b6ca0afab3f401356e29730b6b6089499b6a431891ac8aeb9d4ee05315867dc507e338937ba5e75b84fd9aa112b5ccf8042aa1c48a07bbc9790a2ae4b9bd5992da50f165146b6736b94ba4f36d0b448390172378af8693fb7ab8660567684b78637b87fff7274aa8a305a79ac973facd23c8d490f6deced339554f40190f5714cb2107771a8071eb9879b64d8b47386f3b67b32f5a433e93caf15e2dcba6f81b624514d8a543afb1d7a915730cec6e62a1982e36a44d54bdd445c9ca9191bef1736b9261f6f96587c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "da08a3e40647d7b373e761f0b3a0f919b244c5e4bfc74f876bc1e883bcabba9af1975b8cf6bbedb4627b79dda1abb904fb9a7204cf261c6c7872f1e2b9bbc5502685c05716c098c4723356ad6b913179e450a6c576022162e2cfbc30436652a51767e22ca12219819caa086b5b91b0cf167b101b0af043d35badb4022889c67b9c76075df314a26d4bfbd0bf0414cedf15ba5dd9778c20eed62b41246a7861505b23e281f6cb31a8144c08a389081ad708585cf552806bfb24467d5ff0dbd6cccbca36f918e06944e89a76e9d9e0b0bccd9c914b03081f9f77694038e4a0f0bd913e72d1c51ff22373dd46b0549b041811531331f138b1a8d20fb0009e5a177a81e57e1f58bde451d31498f0af4360db5baf116dd76baf6bbcdb0bc8de97013c035136e3d10ee8ae2567d23a676027e81b691817333c69bf91d7deb013df36f16d318f98f625f13593421a5dc0a566504f33e565b093e5222ed08157db1729b0043c839e0959f1ba5e2189895f4246feec31b72487bbc139f35a377c8ce978c8a66119b81c1a7a81f1e25df475a613bb4d4752c471d782a9aa1ae8ea4d507a2d9599c7e3d38cbad86156a0504f98abe8c1d5793998a0bee864a447f98e3240e19deb9860d19640ba483c5390033cb988e73ccd36a10001629ab1140cc2ff3d25d0584d2bfc49f4cc7f142022f039b68a55b9fb9a1ba3c025a8fbe1060b647882", "0", "da08a3e40647d7b373e761f0b3a0f919b244c5e4bfc74f876bc1e883bcabba9af1975b8cf6bbedb4627b79dda1abb904fb9a7204cf261c6c7872f1e2b9bbc5502685c05716c098c4723356ad6b913179e450a6c576022162e2cfbc30436652a51767e22ca12219819caa086b5b91b0cf167b101b0af043d35badb4022889c67b9c76075df314a26d4bfbd0bf0414cedf15ba5dd9778c20eed62b41246a7861505b23e281f6cb31a8144c08a389081ad708585cf552806bfb24467d5ff0dbd6cccbca36f918e06944e89a76e9d9e0b0bccd9c914b03081f9f77694038e4a0f0bd913e72d1c51ff22373dd46b0549b041811531331f138b1a8d20fb0009e5a177a81e57e1f58bde451d31498f0af4360db5baf116dd76baf6bbcdb0bc8de97013c035136e3d10ee8ae2567d23a676027e81b691817333c69bf91d7deb013df36f16d318f98f625f13593421a5dc0a566504f33e565b093e5222ed08157db1729b0043c839e0959f1ba5e2189895f4246feec31b72487bbc139f35a377c8ce978c8a66119b81c1a7a81f1e25df475a613bb4d4752c471d782a9aa1ae8ea4d507a2d9599c7e3d38cbad86156a0504f98abe8c1d5793998a0bee864a447f98e3240e19deb9860d19640ba483c5390033cb988e73ccd36a10001629ab1140cc2ff3d25d0584d2bfc49f4cc7f142022f039b68a55b9fb9a1ba3c025a8fbe1060b647882", .Okay}, + {.Shl, "744ab0263041f7dca789405eac817ba5b62d6dcf52ac91f2759589998c78f59e96bf41138ba82a4442da3dcb041455b90e092f9d0560ae41c7606f7fe8175f39e2775a71bd7d130c0d0d2b99e346f3f10d3b04c90ac04831f73211dff1c08580d16871e035a853b5cc4f0ef994bd3d7507ee0492477aa7655870e383769010a6aa1cf1272e454509e034504103bddae0ba6507b41c8848d2de512ebd171125ea1cb734ce7c18ea861864d0b5fd071c986d9263417ae9123109439a730b5d4a693ca888b05419ca3b1d3c3586433e04df4b1f42aad633df63e283babe3210f83413d4db3d386a5f8aa00304f7d8dd4ed98988a2225b724dbec83d552ca7bbf2c270a7a298e37d56d45c7d5b61e852b193fcbc7da5b51d86efabba3c6222508e4347fdaf4c10570372c9d882bcced2a753a5a87dd9f371727d0f516dafdb97dcbc683c67be56b3ba7b900e908a4febfbc727e77be57c21853191669d724960b33b8c9f3f1fcf72bb97ba9b7ed339293df827a10a312f806a7f3f125e4c1e480c032f22fe08d7378c3e4a63effc5d5be79cafe318dd114d8d43d5756a58061450059309e556031d914a567921ab88bba3d988b8d3b0d19fc3ab70b2fdf38150a57e381e76fcdaa52c0169cd9db8a3cb4bd7472fe1c6d1216100f604ecfeaab6d864979eb69555949c0c313c3afbd5217f5ed10a7a79f8521b366c3a6c8f0080d3b5", "12c", "744ab0263041f7dca789405eac817ba5b62d6dcf52ac91f2759589998c78f59e96bf41138ba82a4442da3dcb041455b90e092f9d0560ae41c7606f7fe8175f39e2775a71bd7d130c0d0d2b99e346f3f10d3b04c90ac04831f73211dff1c08580d16871e035a853b5cc4f0ef994bd3d7507ee0492477aa7655870e383769010a6aa1cf1272e454509e034504103bddae0ba6507b41c8848d2de512ebd171125ea1cb734ce7c18ea861864d0b5fd071c986d9263417ae9123109439a730b5d4a693ca888b05419ca3b1d3c3586433e04df4b1f42aad633df63e283babe3210f83413d4db3d386a5f8aa00304f7d8dd4ed98988a2225b724dbec83d552ca7bbf2c270a7a298e37d56d45c7d5b61e852b193fcbc7da5b51d86efabba3c6222508e4347fdaf4c10570372c9d882bcced2a753a5a87dd9f371727d0f516dafdb97dcbc683c67be56b3ba7b900e908a4febfbc727e77be57c21853191669d724960b33b8c9f3f1fcf72bb97ba9b7ed339293df827a10a312f806a7f3f125e4c1e480c032f22fe08d7378c3e4a63effc5d5be79cafe318dd114d8d43d5756a58061450059309e556031d914a567921ab88bba3d988b8d3b0d19fc3ab70b2fdf38150a57e381e76fcdaa52c0169cd9db8a3cb4bd7472fe1c6d1216100f604ecfeaab6d864979eb69555949c0c313c3afbd5217f5ed10a7a79f8521b366c3a6c8f0080d3b5000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-f5da30772951ff15e2a8278cde15e11960505e7461c5d5a2c83fdaac821bdd9ac3e975da587a125c53fe95efaa2f01accc0145d6fcdc6f231e9f9aba0d4f38a2cb301ed06a82bce75ce394178906b99a2f03ee674c26f2928e5279f7c951291714b7c9a0e7ec0ae4da9556dbd46d72fc953d5dc8bafdae7c5fd8715f0b05bc2c4fa3c8b454a3d3900d095f4a23aebc4f68b074a06ffc1d24ce1478d5c4d25f3d5f65280f887a836b9e753bd472e3ee187c400bdcbeb3fa94ea8137e7f8f491bf495bbe7e7410f1f439e4732c188d3388a501b6561547d4b712503c0204f6fd4bb5248bd98b9fe33d9f492c59dab6e1fd3134962f87fb67741e255009becc65545567068bfd92b8d016a8132eafc9bd6736577b578157f454ddb0280eddd0051619ed0b95af42dfb8d4ac8504ecfa152741a4d3891338f692bc64e1bb5f30258ef49c68c5e7c08e1afeeba34c6cf93884769d8d3369637d110f4b2645526827d13413cf980ec56eb9871174018c6793877cf39afbb7fb8bbd21d6be4f52482a77c792ec99515385a718711834a9cf6465e87a77167022fd4885898a7cd675c9ebc3d6d98bb122d5df50a6658b41aebb2ac5ab511a112c77a0aa20635b79b1f7f6897d58ae502169856e53a77642883077280e1753f6f3f407b1229004049b050d0e2f49d568aa80740483c3f1a00e00e13199120dea00f6d868d73beaca267be1", "3c", "-f5da30772951ff15e2a8278cde15e11960505e7461c5d5a2c83fdaac821bdd9ac3e975da587a125c53fe95efaa2f01accc0145d6fcdc6f231e9f9aba0d4f38a2cb301ed06a82bce75ce394178906b99a2f03ee674c26f2928e5279f7c951291714b7c9a0e7ec0ae4da9556dbd46d72fc953d5dc8bafdae7c5fd8715f0b05bc2c4fa3c8b454a3d3900d095f4a23aebc4f68b074a06ffc1d24ce1478d5c4d25f3d5f65280f887a836b9e753bd472e3ee187c400bdcbeb3fa94ea8137e7f8f491bf495bbe7e7410f1f439e4732c188d3388a501b6561547d4b712503c0204f6fd4bb5248bd98b9fe33d9f492c59dab6e1fd3134962f87fb67741e255009becc65545567068bfd92b8d016a8132eafc9bd6736577b578157f454ddb0280eddd0051619ed0b95af42dfb8d4ac8504ecfa152741a4d3891338f692bc64e1bb5f30258ef49c68c5e7c08e1afeeba34c6cf93884769d8d3369637d110f4b2645526827d13413cf980ec56eb9871174018c6793877cf39afbb7fb8bbd21d6be4f52482a77c792ec99515385a718711834a9cf6465e87a77167022fd4885898a7cd675c9ebc3d6d98bb122d5df50a6658b41aebb2ac5ab511a112c77a0aa20635b79b1f7f6897d58ae502169856e53a77642883077280e1753f6f3f407b1229004049b050d0e2f49d568aa80740483c3f1a00e00e13199120dea00f6d868d73beaca267be1000000000000000", .Okay}, + {.Shl, "13a8990a2a54f0d4486ab5da8100cb4d2d45a1515d0bdc2879ecbaadfe698470056b4a5a4cfb7581338b07184a48041cb833ed7f7a8bcb1d30ee8dabc81baa4c72397dfd5d4909f47eceb120ddd3c3ed5b6516e5c0cfa581a9e12dbc15e58b17acc0a2b55f1d6f3806fd8b17a05edc4903c0cf7efc65de0c2e468219e007f97b8fe4d1e1a027c4c03a7f1570436f7a2d938b7a26cb878888d3fc08a143d7de9a196f2b5912d36d64402985ea4ab9ee29a0d7bc0d694fe25601704d85830aa3f37bc44d8100db04d9944bbb3e33b14d152b1388d87bfa91e71b7a51b5b0ca123348bea846834e093b1c31d712a9045c5aacbaa1bfc3826f2da05098a9f50b771b9d1653df8ca6c6bd3aaf9ce4c84ec4f0b503c1c57988d760e4dbe28c8fb021f98ded6768250ac67e59494800a67889c64fde54239049afab519c42274a95a87d00318551f95777dc48708a7c57c066c64a500f47729e32735a9e53fdfd24f6c62e87ad9b29fa8adf487e7cf95a4efd4e87e45607e6f15327c8e47c934bbc5d574680ef0706c2596dad2628fccbda04320aa305a39f845819a272647b933c4f9c1aaabcfe75f83c61358970741f4c3d2c5b99f881b8bffb3b6846233122cba0aedb65cd3f80e1f24e9f999a86c2cf1a0cc1f661387412175da2f727242543a6f5119a2618de46d8366eafedaac5a593684943fdfa8c2ffedda72173a274a06f51", "21c", "13a8990a2a54f0d4486ab5da8100cb4d2d45a1515d0bdc2879ecbaadfe698470056b4a5a4cfb7581338b07184a48041cb833ed7f7a8bcb1d30ee8dabc81baa4c72397dfd5d4909f47eceb120ddd3c3ed5b6516e5c0cfa581a9e12dbc15e58b17acc0a2b55f1d6f3806fd8b17a05edc4903c0cf7efc65de0c2e468219e007f97b8fe4d1e1a027c4c03a7f1570436f7a2d938b7a26cb878888d3fc08a143d7de9a196f2b5912d36d64402985ea4ab9ee29a0d7bc0d694fe25601704d85830aa3f37bc44d8100db04d9944bbb3e33b14d152b1388d87bfa91e71b7a51b5b0ca123348bea846834e093b1c31d712a9045c5aacbaa1bfc3826f2da05098a9f50b771b9d1653df8ca6c6bd3aaf9ce4c84ec4f0b503c1c57988d760e4dbe28c8fb021f98ded6768250ac67e59494800a67889c64fde54239049afab519c42274a95a87d00318551f95777dc48708a7c57c066c64a500f47729e32735a9e53fdfd24f6c62e87ad9b29fa8adf487e7cf95a4efd4e87e45607e6f15327c8e47c934bbc5d574680ef0706c2596dad2628fccbda04320aa305a39f845819a272647b933c4f9c1aaabcfe75f83c61358970741f4c3d2c5b99f881b8bffb3b6846233122cba0aedb65cd3f80e1f24e9f999a86c2cf1a0cc1f661387412175da2f727242543a6f5119a2618de46d8366eafedaac5a593684943fdfa8c2ffedda72173a274a06f51000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-39dc9beb7322873e4e94be3a9de3cece73df8001c9f5615e2832d86cfed67fcdadc0d40ac259f9ce39b0da249a23dba76f19e2387056a9aeffc0c0de2c7290c43b9fa31cdf6bcca8412bcb9e83fac77e33340df37fe3997a3cc27e6392b4fd3105cb7fc208ee187d3eefd24f05c2efef04145b4dd5fadb8165d5037caac0a61985fa45f91cf94ccca50535635f850366a42f7ff192500130629540f95be70128205a6b57c8e3e098a721643aa885a84e01a6e1674abe2083ac95a90447a2b3d09c5d50df0845bffe0e2a531638078570c1601598b74f30327dbbed6913842e8a626a9d51fecb952b03ad472eac80d6df0b06f2599560dd50a05f1b15d0b85abf0ba9d5e5e63552b5e53c194d889c5df10bc18f7e4c91a6501ddc5a25a75854268d0a47fe481a3cffbe1cddbbd71e176dc5449fa6e8963eec1d8922ebd8fb5c9fd5416e2156e0ecccd457a78e31f2516931237cf4757abd451f27e973c9545172d3fdb1f5e0447220e30dbaaf0a140e0e52ba4e25fda6ea4b8ff61e5b4980bb983d8b760c0d7e5e214e1f94042c2d6628edea54d63d3ead8c10ede338dcd6cdced67fd2a2f7756b4b7274493cf00a2043b96b80c719f871e18c6a50825538ab0ad1c2c9c69a7fab5e3aba2fbf516e948b3f96b7a8745dc0f12fe34221353d1ef711144a9fbfd3a6b90c1d7d7e422662be85b13e59464b6115fafae206475b8339", "21c", "-39dc9beb7322873e4e94be3a9de3cece73df8001c9f5615e2832d86cfed67fcdadc0d40ac259f9ce39b0da249a23dba76f19e2387056a9aeffc0c0de2c7290c43b9fa31cdf6bcca8412bcb9e83fac77e33340df37fe3997a3cc27e6392b4fd3105cb7fc208ee187d3eefd24f05c2efef04145b4dd5fadb8165d5037caac0a61985fa45f91cf94ccca50535635f850366a42f7ff192500130629540f95be70128205a6b57c8e3e098a721643aa885a84e01a6e1674abe2083ac95a90447a2b3d09c5d50df0845bffe0e2a531638078570c1601598b74f30327dbbed6913842e8a626a9d51fecb952b03ad472eac80d6df0b06f2599560dd50a05f1b15d0b85abf0ba9d5e5e63552b5e53c194d889c5df10bc18f7e4c91a6501ddc5a25a75854268d0a47fe481a3cffbe1cddbbd71e176dc5449fa6e8963eec1d8922ebd8fb5c9fd5416e2156e0ecccd457a78e31f2516931237cf4757abd451f27e973c9545172d3fdb1f5e0447220e30dbaaf0a140e0e52ba4e25fda6ea4b8ff61e5b4980bb983d8b760c0d7e5e214e1f94042c2d6628edea54d63d3ead8c10ede338dcd6cdced67fd2a2f7756b4b7274493cf00a2043b96b80c719f871e18c6a50825538ab0ad1c2c9c69a7fab5e3aba2fbf516e948b3f96b7a8745dc0f12fe34221353d1ef711144a9fbfd3a6b90c1d7d7e422662be85b13e59464b6115fafae206475b8339000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "8d53c81728e5523aaa4e108bd7b474bec4fad74bb812b6542cf6fe92b2c2159a6329e43f561f6d52ec82ef51f0020995435b098e4cb2aa8bbfa7eca6a10fcd039a7c0ae98a3f64285c6eaab6a60cf25d62ac7a5ac6cd6f958163847f1d57f40bdc1a7e0edfe4e83d84e0147623df5fe387693a71bdb8a3df970772b3969045cf718df50810bd6dc0fa51626dadf590327fafafea26018d99036c894bf6015046f7723c6a26fe85f6a77e37dda1c0dab05d0921593809da35502d71db60b8e1ab2ef20a593b637c0f5ebac67e058718ec3cc2e8ef6ed4eb252f37fcfe0b114ea4d1ca219f925adfcf5a48400bf397f4b810c06f52c0bf5164cd2dc0504d312bd74507c34279e0c17074d785de40032571e880f9edc079dc385b64b5834d6090cc46df20cd23687c8c6a8ef713264e54955893dfba78eafec45d3071924b5ae66cad08495117cc4e59fa612c45ebbf898a919ed677e19c651d5ee35fd4ab01abe9981b7325e14a0e1e3c3ec75b7b57c5890168d791d47461a72bd2709f3eba5cb1e3db0123e315f96aa192ef76b0d80779e17e2b24e95d134e5ea348ec83817e6b63b1a5660dcd0a7ad36584e6f7bf8b2e437bd195cbfb200434ff5a6a55b0b76e87a491cb75acae93f67b9fb663f8ece88677c1babb4785b51266212b0f3a99a685fedcb8d9aeb599dd172fd9bd294e16731ee16915a6566b53e6c059caa36f2e", "258", "8d53c81728e5523aaa4e108bd7b474bec4fad74bb812b6542cf6fe92b2c2159a6329e43f561f6d52ec82ef51f0020995435b098e4cb2aa8bbfa7eca6a10fcd039a7c0ae98a3f64285c6eaab6a60cf25d62ac7a5ac6cd6f958163847f1d57f40bdc1a7e0edfe4e83d84e0147623df5fe387693a71bdb8a3df970772b3969045cf718df50810bd6dc0fa51626dadf590327fafafea26018d99036c894bf6015046f7723c6a26fe85f6a77e37dda1c0dab05d0921593809da35502d71db60b8e1ab2ef20a593b637c0f5ebac67e058718ec3cc2e8ef6ed4eb252f37fcfe0b114ea4d1ca219f925adfcf5a48400bf397f4b810c06f52c0bf5164cd2dc0504d312bd74507c34279e0c17074d785de40032571e880f9edc079dc385b64b5834d6090cc46df20cd23687c8c6a8ef713264e54955893dfba78eafec45d3071924b5ae66cad08495117cc4e59fa612c45ebbf898a919ed677e19c651d5ee35fd4ab01abe9981b7325e14a0e1e3c3ec75b7b57c5890168d791d47461a72bd2709f3eba5cb1e3db0123e315f96aa192ef76b0d80779e17e2b24e95d134e5ea348ec83817e6b63b1a5660dcd0a7ad36584e6f7bf8b2e437bd195cbfb200434ff5a6a55b0b76e87a491cb75acae93f67b9fb663f8ece88677c1babb4785b51266212b0f3a99a685fedcb8d9aeb599dd172fd9bd294e16731ee16915a6566b53e6c059caa36f2e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "4aebcfb83de7bf3d8f8c4a904454475d67bf349fb55235bed7ce4ac87d5b56ccd9dcb621389588b4c6697142553bb1a482930648c6c3642b9f73fa573e2ed79e7cb2395642a60635e8d4d4b9d61db2b4e8af7bee2bdaf1376edc97aaf1289ccc109892eaa85e983ad0547370f3d9b7eaea43c5a2ca301d7ec55a8afc0e0ceb3e01f360ece14e08675ca475b0ca7ca937f51f61a6e3df80a3b9f2c9eaf9f2e91dcfe84455d1692151224d42ca99f6b3ec70a6db38bb335b16f49a46d5dd0f8b187def4e2c83da47ce2213fe2c73b146de5b0a114d5de92700a9e9f1074db45fc5621d664696bafc0f56898d864eb11487866d752efe132afbc0a122fbb23f355cb45d916fcf0d9cba966237dd7e3ac9c7dbb07d808a72a81de39236e24331d4fd1cc0e6e30438a5a60c74a94fad4c7064e8309e8d87f3045d2b167c528602c1dc891534bdf1af0d863551f611365aa2a426f416bf94b82480a59200f5a9a1fa3790d22c0dd58a44217c72d8779dd1d23e05a141edb0a72287b63b1af0fbdd093aa7e85590cfe72fd7ab68f85d4a599a54ffb4bbe0f8975d1259ed59e37a05af53406f50bfef92507d3fcf877152a75aa67b3f625d99162460bfdf9834ca871aa0e0d796982f70c875942b4e00291336b083443e505117c7a09f7980e9c6e4192f3a25f375879cd27f11bd3b31a7b534095cd0bff7f768c0dad1ddc70230a7a511", "0", "4aebcfb83de7bf3d8f8c4a904454475d67bf349fb55235bed7ce4ac87d5b56ccd9dcb621389588b4c6697142553bb1a482930648c6c3642b9f73fa573e2ed79e7cb2395642a60635e8d4d4b9d61db2b4e8af7bee2bdaf1376edc97aaf1289ccc109892eaa85e983ad0547370f3d9b7eaea43c5a2ca301d7ec55a8afc0e0ceb3e01f360ece14e08675ca475b0ca7ca937f51f61a6e3df80a3b9f2c9eaf9f2e91dcfe84455d1692151224d42ca99f6b3ec70a6db38bb335b16f49a46d5dd0f8b187def4e2c83da47ce2213fe2c73b146de5b0a114d5de92700a9e9f1074db45fc5621d664696bafc0f56898d864eb11487866d752efe132afbc0a122fbb23f355cb45d916fcf0d9cba966237dd7e3ac9c7dbb07d808a72a81de39236e24331d4fd1cc0e6e30438a5a60c74a94fad4c7064e8309e8d87f3045d2b167c528602c1dc891534bdf1af0d863551f611365aa2a426f416bf94b82480a59200f5a9a1fa3790d22c0dd58a44217c72d8779dd1d23e05a141edb0a72287b63b1af0fbdd093aa7e85590cfe72fd7ab68f85d4a599a54ffb4bbe0f8975d1259ed59e37a05af53406f50bfef92507d3fcf877152a75aa67b3f625d99162460bfdf9834ca871aa0e0d796982f70c875942b4e00291336b083443e505117c7a09f7980e9c6e4192f3a25f375879cd27f11bd3b31a7b534095cd0bff7f768c0dad1ddc70230a7a511", .Okay}, + {.Shl, "5320e0a8c24782fe7af0148bd61954a0ee318958f9c28cd2ead5f90833dbf0fa091da03fe7e4f935ccd3c9838836c178400c8c83e86f871ab9713ba29a39e80bf9f90bc34d472c16aeaf7a27079d8bedf0b6b391457e3da6bd57aa17d408068e349fed88bc743017b80bcec4573880deb116c4b84bf9ef783cc2c22771e78019b3e7bb645539bd3f0573be53f394e565b37c90c76ff840d53db405d59536e5105207b3a500b3c286b26cf2c05f24f15776832dfb6fadbb591e45fc438253492d0a048f96a0881bd23e9f995362087bb775d965e7f41ee40f11b844992ca94f65836bcef82d099b01131703d137b508757a17a55f321a0daf6ac183d0c1294b171b762869674850a5ec1c70289a6c633fb17fead74af6b236e7f2778879afaefa818ed6e4363ba4e16c3f0c1995ea4fae333e12c97f29aef0bc8606c0137464a2ce49c41df2905f38bffa09ccc5f447e364fbadd6c8908832d576648f4adad1a4580644f77755df4dc1930d1c1f3472f91d287e6819dd5a18ad09fceb54743c4a7c58be034c592dd36eea9d2d997e718cb0583914f96e040d51e546cc722c2a77d008bf417560f525821b6eb93a2627b7ad5a050dd48ec4536527261bff22ae77306bb59cf260bb58312b47ce4640974d7cebb2a56827ac55556a1a4f4d8f6ef68b4e4ffacdc97a35dc60fafaa5b61c288b08305ad7a2ee468b1b0936d6ce6deb", "12c", "5320e0a8c24782fe7af0148bd61954a0ee318958f9c28cd2ead5f90833dbf0fa091da03fe7e4f935ccd3c9838836c178400c8c83e86f871ab9713ba29a39e80bf9f90bc34d472c16aeaf7a27079d8bedf0b6b391457e3da6bd57aa17d408068e349fed88bc743017b80bcec4573880deb116c4b84bf9ef783cc2c22771e78019b3e7bb645539bd3f0573be53f394e565b37c90c76ff840d53db405d59536e5105207b3a500b3c286b26cf2c05f24f15776832dfb6fadbb591e45fc438253492d0a048f96a0881bd23e9f995362087bb775d965e7f41ee40f11b844992ca94f65836bcef82d099b01131703d137b508757a17a55f321a0daf6ac183d0c1294b171b762869674850a5ec1c70289a6c633fb17fead74af6b236e7f2778879afaefa818ed6e4363ba4e16c3f0c1995ea4fae333e12c97f29aef0bc8606c0137464a2ce49c41df2905f38bffa09ccc5f447e364fbadd6c8908832d576648f4adad1a4580644f77755df4dc1930d1c1f3472f91d287e6819dd5a18ad09fceb54743c4a7c58be034c592dd36eea9d2d997e718cb0583914f96e040d51e546cc722c2a77d008bf417560f525821b6eb93a2627b7ad5a050dd48ec4536527261bff22ae77306bb59cf260bb58312b47ce4640974d7cebb2a56827ac55556a1a4f4d8f6ef68b4e4ffacdc97a35dc60fafaa5b61c288b08305ad7a2ee468b1b0936d6ce6deb000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shr, "35d724c081e45905a510a0705d63a2acddf20353b859dd0ede47fd6000bfae1c4e1cb794331b083c2439651be736fc1ee8f92d096dd2c1adecb11e74cf358e730c4354b8daca30ee899f5fa139f990c254c4358e1216d54d1a0c68e075e94c730ac89127fd576201907314f5b533ca250bb17443a23c2e6988f5474eaa06adf9d8ef7035c9790dc5df3c45b5a0581c19c28fbd17314bcbeb1a8d1eff7d60e6c43720093648377c8aa46bcb8a067f7d1d4ff2fad836cebe4c7af2cf91715520815e435eb4403d6403609086f5919afcb9c5fa03c1aebce29409fa8a3800de9fb03502fc04a0732e436cbcf68f026a7884da7b4a1b8ca095e4d7ddd13d187984810a1833bd26fbdef33e33a645aff2d64f1fdb6202cc31af92b0aeb9d6ff8f9036942fcae7443272957d7e309ff4cdceffd5c2bcce5a076897e3b827c98cda2aa03af74cde3e62e9cc3d5963a747e33e2f7a5cf5dde36b28d1b2b2c26d114ad7c29f20baedf1310dd713ae6e910bd5580bab9a1d46170219d438c051e4f542b1b28bfea612dcd9d9c171a53cc7dc96835d51801d7e7fe129eb13bd8deae017cd55da4198642a44115b506624d58d85f661522c1f2ab2a7658883b3f7748a774d1f0d956d8ceeda7c366ef9d4096883122dac04785821d654ab9a0932c753d274f6f06a4ba70acf99b1b6dadd4738a4d8eb68e5673566cc88c5462f981cc6e3e323", "12c", "35d724c081e45905a510a0705d63a2acddf20353b859dd0ede47fd6000bfae1c4e1cb794331b083c2439651be736fc1ee8f92d096dd2c1adecb11e74cf358e730c4354b8daca30ee899f5fa139f990c254c4358e1216d54d1a0c68e075e94c730ac89127fd576201907314f5b533ca250bb17443a23c2e6988f5474eaa06adf9d8ef7035c9790dc5df3c45b5a0581c19c28fbd17314bcbeb1a8d1eff7d60e6c43720093648377c8aa46bcb8a067f7d1d4ff2fad836cebe4c7af2cf91715520815e435eb4403d6403609086f5919afcb9c5fa03c1aebce29409fa8a3800de9fb03502fc04a0732e436cbcf68f026a7884da7b4a1b8ca095e4d7ddd13d187984810a1833bd26fbdef33e33a645aff2d64f1fdb6202cc31af92b0aeb9d6ff8f9036942fcae7443272957d7e309ff4cdceffd5c2bcce5a076897e3b827c98cda2aa03af74cde3e62e9cc3d5963a747e33e2f7a5cf5dde36b28d1b2b2c26d114ad7c29f20baedf1310dd713ae6e910bd5580bab9a1d46170219d438c051e4f542b1b28bfea612dcd9d9c171a53cc7dc96835d51801d7e7fe129eb13bd8deae017cd55da4198642a44115b506624d58d85f661522c1f2ab2a7658883b3f7748a774d1f0d956d8ceeda7c366ef9d4096883122dac04785821d654ab9a093", .Okay}, + {.Shr, "c321f048f686b1128cb9a4cdd9c9de0253c176c8644ca7b7422fc748513b6dd52d302fb1c7941449c4e09fd6ec91ce3f45c7039b9f27563da9339f43b43018555dc2c237af590e4b9275c8233a66b0479b2f4ba1246615461e5b6591788c0bd098f1fb89c125cafe13cf0ac95cadd64d4686eeb13f16f622866f1711823ddba57e724b06466ea6ed3b59e105675d52370ed3514831e5b8016902f5d3c55b3d05b7bb7282f15efc7617a0741548b3dbfa5ccca4b2c6351526d9c141f8bb3d2da2ac7874350fb5be971d9a73f59e044b5e5e1b6a83702f82d1b6fb8a1235f059a969aea719df8591aa7ccff376584cee9fd8901d0be8694c57bfc57b3c3b1fcd44c989bfdef7d4c0ffbac7c93ec75f326f2e944e8b4a130d0ad385ad3b722d4d66dc95c69bd6826906b1d508eec160ed0482b0985eb49b18cb2439a824b37dbc54a89d4fbaf0c0d6498e012aadc4a468b0629a558301bca9e03b1a20c769606711989c51ccb41a2edfe3916a9eb228d8d25c5c5d5f6c263521710427ef31a4de755bb1f5bd5f67222519169657626355607e08845ecb584f17c3eb8eb9702366f3b48e780b9c747aadb74d143e22dff046f65efe4724a69b1d2eac8bcb51a8cd4edeea00fa6c36e49d15d9957b815ba6d920de1090ef1408fffd6eccd89503fb965e382488ddb0aa64fae7672cc3d1639b3099f7a27049b58e74d6d1714124db34", "1a4", "c321f048f686b1128cb9a4cdd9c9de0253c176c8644ca7b7422fc748513b6dd52d302fb1c7941449c4e09fd6ec91ce3f45c7039b9f27563da9339f43b43018555dc2c237af590e4b9275c8233a66b0479b2f4ba1246615461e5b6591788c0bd098f1fb89c125cafe13cf0ac95cadd64d4686eeb13f16f622866f1711823ddba57e724b06466ea6ed3b59e105675d52370ed3514831e5b8016902f5d3c55b3d05b7bb7282f15efc7617a0741548b3dbfa5ccca4b2c6351526d9c141f8bb3d2da2ac7874350fb5be971d9a73f59e044b5e5e1b6a83702f82d1b6fb8a1235f059a969aea719df8591aa7ccff376584cee9fd8901d0be8694c57bfc57b3c3b1fcd44c989bfdef7d4c0ffbac7c93ec75f326f2e944e8b4a130d0ad385ad3b722d4d66dc95c69bd6826906b1d508eec160ed0482b0985eb49b18cb2439a824b37dbc54a89d4fbaf0c0d6498e012aadc4a468b0629a558301bca9e03b1a20c769606711989c51ccb41a2edfe3916a9eb228d8d25c5c5d5f6c263521710427ef31a4de755bb1f5bd5f67222519169657626355607e08845ecb584f17c3eb8eb9702366f3b48e780b9c747aadb74d143e22dff046f65efe4724a69b1d2eac8bcb51a8cd4edeea00fa6c36e49d15d9957", .Okay}, + {.Shr, "20e4523113796119b74c4ada39bdeb6e60c791048beafab4b3a347173e09af44c58dea53312255292d23193c76178ee9cb9e4709f579fdad990ccb07d00aae394ff67449e5f588b783320b0e2ec2b5c656b30c8cd9ac33ed66df02835d8c84e5e8bc6117d73d63204c8b01b448ad95a9faee4de43c308784df7d896b987a83318e28003010e717e13bf46a9861d32b322aed460c1c951a5fdfcd23d4586f4321882003d065df40d9817ad364663a490fd1cf9d8f4dde537483b9311f7ac3599f4b570b146efceba7004bf7d1e28073ac2b1918e5f3c75af885de68fe3f76ac03dcb7b39789716155221c59dfd88dfe6c37d878611a32d5ff23ae0f732df7538e3efa9c7c44dee89f1cc2beab82c3b857c6c8d4aecd4964bae31e7d7dcd6c02f37e05b89a301f55be748034b0b86ef2e5921e0e0f265f5e4625da2301069b0d6e6186b72b74a43db4094f48a92dd49b7c0859d4f39f8bf72fe7eda19ae52a259ad94176436b578462ebed549d9f616df3ff03b34c3cac2e708daeca08b20131508e23bec731400c70fec43473b6d84e24b99af80fdb06fe93cc3d430dea97f2370ad52cb5babe0255c281333e8c47738e917f78c629c3049b916c67f525daf7e78f0aef0e3f861377c07192f7b6e7f49b81bfd8ea0b7f830b9c6d09359dce948ef748ca8d2fb4cf1287f4f7b3d4400c17a8790ef37e2391c4f55bbb246467e09e", "f0", "20e4523113796119b74c4ada39bdeb6e60c791048beafab4b3a347173e09af44c58dea53312255292d23193c76178ee9cb9e4709f579fdad990ccb07d00aae394ff67449e5f588b783320b0e2ec2b5c656b30c8cd9ac33ed66df02835d8c84e5e8bc6117d73d63204c8b01b448ad95a9faee4de43c308784df7d896b987a83318e28003010e717e13bf46a9861d32b322aed460c1c951a5fdfcd23d4586f4321882003d065df40d9817ad364663a490fd1cf9d8f4dde537483b9311f7ac3599f4b570b146efceba7004bf7d1e28073ac2b1918e5f3c75af885de68fe3f76ac03dcb7b39789716155221c59dfd88dfe6c37d878611a32d5ff23ae0f732df7538e3efa9c7c44dee89f1cc2beab82c3b857c6c8d4aecd4964bae31e7d7dcd6c02f37e05b89a301f55be748034b0b86ef2e5921e0e0f265f5e4625da2301069b0d6e6186b72b74a43db4094f48a92dd49b7c0859d4f39f8bf72fe7eda19ae52a259ad94176436b578462ebed549d9f616df3ff03b34c3cac2e708daeca08b20131508e23bec731400c70fec43473b6d84e24b99af80fdb06fe93cc3d430dea97f2370ad52cb5babe0255c281333e8c47738e917f78c629c3049b916c67f525daf7e78f0aef0e3f861377c07192f7b6e7f49b81bfd8ea0b7f830b9c6d09359dce948ef748", .Okay}, + {.Shr, "feab06ea087b582d04bb46961eb624bb78e0082af2da8fdd820bb07d59450e600786c551b29987863f39feaa9564c92c5ca508accac9229dbdab5b3e9d633ac5b2b84c97ff552444a1c59e85e7bd37b51dbe5c3ec222d3ff357727a3389515a9ac951760f20e86606e7d839962e37bed7f91c642a3d1af53013886a4d10c750e602bfaa88a503d5421ff6b77f70f8f850d82ccace020a9f4bd71d3d150efd29892f99bd2e79146beb87b0586c1c7b505f53c3407ca33236c4ff74c9090041a1002fee6a7c03e978d408ab2da6497076bfaa52b02ceaf55050cabee2bec5cd7d600009492905f0700106ea33f320df9580cfbd828cf6aebd6ca6973ee8163e43bcca718093c27af8924ee127803aeaf4491190ba0bd5941b762b1436ca88862b976789651d78260de7550f9e56f9ed7a34e9cd5d5d82c1b8bd73080683241907ca80dc8144243aad370ddee517660ac31da3763333a5e5104c601cb7f57becbc4fa87ebb125c21bade77d1327d49f8ee66736550e0794db6d06225295b5848515369f7eeacdf544d200d930550a54657a7f6d5f5f19ec71c4878b6bfe768b0d16eb7392fa5198253b5c2d9cb740c7b0d3db4ec2beb0bc0d5b6998f69e8c5e4f1dd0d9ccde04b77af98760e769ddd87113fb2a85d24aaf9a69e6a3a7946acd815090d93afc3b0f300c9816a11c0d393d9606994192bf290b216e47e99d7fe26aa1", "78", "feab06ea087b582d04bb46961eb624bb78e0082af2da8fdd820bb07d59450e600786c551b29987863f39feaa9564c92c5ca508accac9229dbdab5b3e9d633ac5b2b84c97ff552444a1c59e85e7bd37b51dbe5c3ec222d3ff357727a3389515a9ac951760f20e86606e7d839962e37bed7f91c642a3d1af53013886a4d10c750e602bfaa88a503d5421ff6b77f70f8f850d82ccace020a9f4bd71d3d150efd29892f99bd2e79146beb87b0586c1c7b505f53c3407ca33236c4ff74c9090041a1002fee6a7c03e978d408ab2da6497076bfaa52b02ceaf55050cabee2bec5cd7d600009492905f0700106ea33f320df9580cfbd828cf6aebd6ca6973ee8163e43bcca718093c27af8924ee127803aeaf4491190ba0bd5941b762b1436ca88862b976789651d78260de7550f9e56f9ed7a34e9cd5d5d82c1b8bd73080683241907ca80dc8144243aad370ddee517660ac31da3763333a5e5104c601cb7f57becbc4fa87ebb125c21bade77d1327d49f8ee66736550e0794db6d06225295b5848515369f7eeacdf544d200d930550a54657a7f6d5f5f19ec71c4878b6bfe768b0d16eb7392fa5198253b5c2d9cb740c7b0d3db4ec2beb0bc0d5b6998f69e8c5e4f1dd0d9ccde04b77af98760e769ddd87113fb2a85d24aaf9a69e6a3a7946acd815090d93afc3b0f300c9816a11c0d393d9606", .Okay}, + {.Shr, "a30be086643e567799910b730a414b7134deeea1a223a366f1694d1d09b882f0c4210edec06b6ef6236921880b3ee2463a6f462e5d2b3155d8712f5f94669c1695e80c0f807ad29c9cc1736f47c935d8ad857f0b10eb5d3296eab4a2b928f99a92211c2a18ea87263c7c0270af19c173e040e504851150f36a793104fc5e0ea47695d97d94ae17e16004347864c8b6910867b4fd6961378ed1be5d472cd04280acc858534db5052758f5b9204ff8e0d5a781957f71a1a3a2ca2ca8714172d062b5e2dfb20db3c4aa9e31b6e06bd8144714dcc968259065266551935c7404c52d9592503447448d41d6b8d608b277ef7fa9980200b9987a60545cca6556695286fd6fe939fdb1194c0983fc3c67b73403a318048eda782aa3f6f03faa0ecb311273b3d6769b655fcb436207ef7b378e6eb60067ee903765282debaf677730f299e43b21950b51e9939f914f935d362d9e04d0e73fafeaf4666046c7da495fcfc6c4d4604caa77efff8f8831cf1e2ccf2731f8fe0a20a510b6a83e1bb1f431f177774083bdf182c5997dbe4087c70eb086e5d2228fb87a5e32a0590e2115f46fda8e546cf713c17e5214b1dcdc54d831bfdc00a60c5fca40639ad2853b647af58b4cfe165a3867bfd8a92d3eebc4aaafff8dc13a8895aff5b27ded243fedc41fa5095840e1b37554eda603f896dbe055702798379a6c6373a79549dae0f6fc2a22", "78", "a30be086643e567799910b730a414b7134deeea1a223a366f1694d1d09b882f0c4210edec06b6ef6236921880b3ee2463a6f462e5d2b3155d8712f5f94669c1695e80c0f807ad29c9cc1736f47c935d8ad857f0b10eb5d3296eab4a2b928f99a92211c2a18ea87263c7c0270af19c173e040e504851150f36a793104fc5e0ea47695d97d94ae17e16004347864c8b6910867b4fd6961378ed1be5d472cd04280acc858534db5052758f5b9204ff8e0d5a781957f71a1a3a2ca2ca8714172d062b5e2dfb20db3c4aa9e31b6e06bd8144714dcc968259065266551935c7404c52d9592503447448d41d6b8d608b277ef7fa9980200b9987a60545cca6556695286fd6fe939fdb1194c0983fc3c67b73403a318048eda782aa3f6f03faa0ecb311273b3d6769b655fcb436207ef7b378e6eb60067ee903765282debaf677730f299e43b21950b51e9939f914f935d362d9e04d0e73fafeaf4666046c7da495fcfc6c4d4604caa77efff8f8831cf1e2ccf2731f8fe0a20a510b6a83e1bb1f431f177774083bdf182c5997dbe4087c70eb086e5d2228fb87a5e32a0590e2115f46fda8e546cf713c17e5214b1dcdc54d831bfdc00a60c5fca40639ad2853b647af58b4cfe165a3867bfd8a92d3eebc4aaafff8dc13a8895aff5b27ded243fedc41fa5095840e1b37554eda603f896dbe0557027", .Okay}, + {.Shr, "51d7bc0a7d19e8ccf5cd45846ec03f40577fc50cb1700c76be441ed82d6837ad94f01fbae16e566934ec8fcc328a164c28123213e56042e08a90a1bb58035e6f93c55acb2d85ef2011eeb408914f513f1239cb22cd4fe71ae1b7e1c187ef22cc444cfe6672fe6b9b5cc30e1b3af64591e86b9931d90ded5b561c9e68b9819b068deff9e177d4bf73e49fa76103852bf150eb9347c6d5aab4e913b4b3cd17691e7771046a52eac9f36943b5c5bba4d6278e94fe9922873f94fc7bc9a67d78dec7f215d54386dfc37a89a71cde793752bd32b5278472a830c0dcd7c914eae3dab996982535d6d5bfe80279d29be6774b54037b93178c61a3d02ceb6db2cd2f735da0c3b5a90b13d6fa7785d9ab2dd924c7d2ce8cacacaab684e84ca6b9d18203b3a8d4f345071f0bfce09067b8023077de649a52f64f609c4a61e3fe168e648fe375c2c666fcdb92ba00b72622f90fe8515d9ecec7ff25169017dfb25d91e319df0107e98d3c11ed4acd7d830848d491ecf7da0b2aacebe34f17776af7c13aa0bc231d919d93d2da8c6aa8ca992ec39f608df009c135117a3e5a0b8822581931f1b17b3dd60d0642a57190a1e29c493b0c378a66810ab31c06158b80bc504568eb1450e092481d85cafaf3f62461139202bb54dfd31230fb13abba22571058f4ef17dbdf8bb167dd00d076e3002c39d925f2e7bfcbdd36d2c56c5d1491dd706b20", "258", "51d7bc0a7d19e8ccf5cd45846ec03f40577fc50cb1700c76be441ed82d6837ad94f01fbae16e566934ec8fcc328a164c28123213e56042e08a90a1bb58035e6f93c55acb2d85ef2011eeb408914f513f1239cb22cd4fe71ae1b7e1c187ef22cc444cfe6672fe6b9b5cc30e1b3af64591e86b9931d90ded5b561c9e68b9819b068deff9e177d4bf73e49fa76103852bf150eb9347c6d5aab4e913b4b3cd17691e7771046a52eac9f36943b5c5bba4d6278e94fe9922873f94fc7bc9a67d78dec7f215d54386dfc37a89a71cde793752bd32b5278472a830c0dcd7c914eae3dab996982535d6d5bfe80279d29be6774b54037b93178c61a3d02ceb6db2cd2f735da0c3b5a90b13d6fa7785d9ab2dd924c7d2ce8cacacaab684e84ca6b9d18203b3a8d4f345071f0bfce09067b8023077de649a52f64f609c4a61e3fe168e648fe375c2c666fcdb92ba00b72622f90fe8515d9ecec7ff25169017dfb25d91e319df0107e98d3c11ed4acd7d830848d491ecf7da0b2aacebe34f17776af7c13aa0bc231d919d93d2da8c6aa8ca992ec39f608df009c135117a3e5a0b8822581931f1b17b3dd60d0642a57190a1e29c493b0c378a66810a", .Okay}, + {.Shr, "a3b0ce1d6472aa0f73d7eb746ef2da6bdff9eb00bc4bf2a2d8e119eb7d35e24803a2a1a94995a96920cd16ef7ea553bdb26be19734018126fa3abc069f134bddf0d589df9574d97b255709f1e2855c3ca2de99e1f6b1233ce987917d4a19c36dc4499bef8d293320a72ef9608bf259134ada9c777a3037fb14a4fe4e6b9749ea7d39b338b94fac4786ef550eeac8426cda30a2782300b1095358977aac4ef3725dc8038b68735c29c664c66a883eff170946976319774cfff2786ba2f721a712ebf37832b85024ff5535e1cb73ebc6b7ccbcab10fcd11b12de45d6c33d9d32cf514c5634746a314aed3170c45228e7dd5e2f83b69236a5d4cfaa1ed08231c2be1faeee1e06745af724b1f00fb6ba146f74eee77ede047e3af7a8c98eeaa405a3ed3b19c345bf813cfd9a6505f08dc20032993f70ccf5a8a7e07d3cc2210efbff9321950e77bf5a81e403a4cc8bd21159a43b3c8fe25a0b45c1caf79be570344461aa0bace2bfdec49df2f631d36719bb5da84ad4119584c1702aaad544be66657f052e87602b845e1508e975db1654d4fa7d11bfd2fda55ed25875a39cf38cd8e6cacc8b4d4f57e762b483bc01e0161ffd2d54f95065cc0c6f728bc9d1e52d3267a2df1ac6537e7e03700228450202504ce5487dc43f99dc7b70ab433a5dd92bcc6a1440e7fcb30ce326ef7227f72e5ec18a9710d02293e9ba2fc2a1e2f1294d", "1a4", "a3b0ce1d6472aa0f73d7eb746ef2da6bdff9eb00bc4bf2a2d8e119eb7d35e24803a2a1a94995a96920cd16ef7ea553bdb26be19734018126fa3abc069f134bddf0d589df9574d97b255709f1e2855c3ca2de99e1f6b1233ce987917d4a19c36dc4499bef8d293320a72ef9608bf259134ada9c777a3037fb14a4fe4e6b9749ea7d39b338b94fac4786ef550eeac8426cda30a2782300b1095358977aac4ef3725dc8038b68735c29c664c66a883eff170946976319774cfff2786ba2f721a712ebf37832b85024ff5535e1cb73ebc6b7ccbcab10fcd11b12de45d6c33d9d32cf514c5634746a314aed3170c45228e7dd5e2f83b69236a5d4cfaa1ed08231c2be1faeee1e06745af724b1f00fb6ba146f74eee77ede047e3af7a8c98eeaa405a3ed3b19c345bf813cfd9a6505f08dc20032993f70ccf5a8a7e07d3cc2210efbff9321950e77bf5a81e403a4cc8bd21159a43b3c8fe25a0b45c1caf79be570344461aa0bace2bfdec49df2f631d36719bb5da84ad4119584c1702aaad544be66657f052e87602b845e1508e975db1654d4fa7d11bfd2fda55ed25875a39cf38cd8e6cacc8b4d4f57e762b483bc01e0161ffd2d54f95065cc0c6f728bc9d1e52d3267a2df1ac6537e7e0370022", .Okay}, + {.Shr, "4192a987b31c5dd163f385536f044779bb8f13a37601d8d35c65fba571320e58f6d96ec3e578e3e559925ccf664751a554ef4fc3c4c0f5258132b0c8415ee49f3b93bec03ad995dfd8bde3d3f001c5a688e7fbbb5f8098550259a0c8ea57a2128d63d19424a7ee78c99b31944a9c257de1b94e125eac3e7be47065b9fca51c4d53663f09d9b8e9174f59e1c4fe23c9030887673c8708b264ed03aa38523847dfaadb65f7121a10cd630a8227fc43918f1e724f76f6f929c94a51db0f26ffc81983d263846f998ba3d390da696624c06744993ba211829b267ead6bab13d8222d7c62089141db5243e4ad88e4d5a716f18853f94e6fbd83cc1fa3e9742090f137b2bf70fc91d1f525b58c3e71208ccbe8f0c1b81754afd679c494dc9b54eb30f30bf60a2833ba7be79d9e8e1559fb71e7da6193214edf1d68a758b5df5e764aa571a044cb1a436c846d26683b75e4fd6471d8e09cbbbb110c824cd4cef0f6c446ba322db03a7d774ce8345a4f29ee3b5eb99c37e2c38e4c8f9536de1865b31f4d3c42dc93e8347734b6c531e0c0b3efc000f16bab5dcb6c35050f6d24127bf8cdced94fdaa43b59fdbf4205b37469926edc1ea6968dcb41f89cf51fc58a4e100100f74c1da5320234622c55952921d3f3f2a494ebb22af83e828c3fead9ab5947f7655c414b19cb9bd9da86ccf8f866386f83f81f6274d3e0ac0dd3b2814262f7", "1a4", "4192a987b31c5dd163f385536f044779bb8f13a37601d8d35c65fba571320e58f6d96ec3e578e3e559925ccf664751a554ef4fc3c4c0f5258132b0c8415ee49f3b93bec03ad995dfd8bde3d3f001c5a688e7fbbb5f8098550259a0c8ea57a2128d63d19424a7ee78c99b31944a9c257de1b94e125eac3e7be47065b9fca51c4d53663f09d9b8e9174f59e1c4fe23c9030887673c8708b264ed03aa38523847dfaadb65f7121a10cd630a8227fc43918f1e724f76f6f929c94a51db0f26ffc81983d263846f998ba3d390da696624c06744993ba211829b267ead6bab13d8222d7c62089141db5243e4ad88e4d5a716f18853f94e6fbd83cc1fa3e9742090f137b2bf70fc91d1f525b58c3e71208ccbe8f0c1b81754afd679c494dc9b54eb30f30bf60a2833ba7be79d9e8e1559fb71e7da6193214edf1d68a758b5df5e764aa571a044cb1a436c846d26683b75e4fd6471d8e09cbbbb110c824cd4cef0f6c446ba322db03a7d774ce8345a4f29ee3b5eb99c37e2c38e4c8f9536de1865b31f4d3c42dc93e8347734b6c531e0c0b3efc000f16bab5dcb6c35050f6d24127bf8cdced94fdaa43b59fdbf4205b37469926edc1ea6968dcb41f89cf51fc58a4e100100f74c1da5320234622c559", .Okay}, + {.Shr, "85a16c5ba226e468a94dc39eebfc24cd59f6274f7043cf02f637261fbd34e8a03fac2247aefd0a18822241e0005948569943de0a93696c96c0504dd024c03518f7f6dbd95439b620a574c6d2a10f9a7106901692ba45a2d024b1c75cddcc3ad002c1cf74dd9d73720bff9effdd08a5cd2cc340798993c80b75281cbe4800f30705d18ea0ac1b7add282060b9a231c15a9027442f8c9893b214efdd109cb24d88a08187fce581238677ded065e1ff9f5ff20483ec86695b6ae2bd9227b36535d8bad3de86c9c2eef3b55d5a75d0ee16a5cda97145c6825678a076c359c7b7903bf34282b7674e53a18006f5d5166813bf512db184637e099d20c103abb69df0846b9fc91e02edcbd5c896e971efbf9f6fb2f85559cbbd5fe06de2344cf27e8a7cb858985e62af694cebcadf192a3209ccabfc60a189dfd30b64f2f622c07b884cb7557ba1a742b09663a043d09f0389e734c04d0b94b84c40e0b9d837001ee9645bf09e03fa094d2150c5da8bd8bba3d61534a1191c8fad32e4aeebf8a35629af124ef4108cfaa9e61b8b9686c1b56727e8d25e4872063d4d68ae80c4c97faa5a61fa52e4c094da3dddce127ae2252a658c3096427aea73a422ef5d1b4a8937943cae4d2feb82c1179d421b133dac8de2086840748cdcb4c691977caedb22341a3de937ac18a096a6ebae643d90c98159b2d6225017824e38f2118a72c940beeb", "258", "85a16c5ba226e468a94dc39eebfc24cd59f6274f7043cf02f637261fbd34e8a03fac2247aefd0a18822241e0005948569943de0a93696c96c0504dd024c03518f7f6dbd95439b620a574c6d2a10f9a7106901692ba45a2d024b1c75cddcc3ad002c1cf74dd9d73720bff9effdd08a5cd2cc340798993c80b75281cbe4800f30705d18ea0ac1b7add282060b9a231c15a9027442f8c9893b214efdd109cb24d88a08187fce581238677ded065e1ff9f5ff20483ec86695b6ae2bd9227b36535d8bad3de86c9c2eef3b55d5a75d0ee16a5cda97145c6825678a076c359c7b7903bf34282b7674e53a18006f5d5166813bf512db184637e099d20c103abb69df0846b9fc91e02edcbd5c896e971efbf9f6fb2f85559cbbd5fe06de2344cf27e8a7cb858985e62af694cebcadf192a3209ccabfc60a189dfd30b64f2f622c07b884cb7557ba1a742b09663a043d09f0389e734c04d0b94b84c40e0b9d837001ee9645bf09e03fa094d2150c5da8bd8bba3d61534a1191c8fad32e4aeebf8a35629af124ef4108cfaa9e61b8b9686c1b56727e8d25e4872063d4d68ae80c4c97faa5a61fa52e4c094da3dddce127ae2252a658c3096427a", .Okay}, + {.Shr, "6f7eb1234588078e323c89acad5cfe125dd9d42811c383d5f7357d43219b5501a086daf057db8672b59fcc9d36b87701ade9ba4dea359ac0bd8d02c4b40af39fdc0051f4c8ed40f58314f3d39a86972a2bd49d5c9d0bd6013c619ff0cc2b967b556681eb730f615924ffb671a9cdde9d4b2252e5c9e43f0bbc4b5193fb317ed6071e236db4218c1dcb7791262cc06390971a5a03fc42c198a9c53d1f3b931414b378cae1cb839082dd9fbcc3e25046a2465d85eb710b22e7986176005530a5f8c8d44482eefb71305bfacfcfd05b14029f16f967a54b02d2f5a168f1d8ee84549ed5a93b8ab85ce561cc79132b5dc614de07dbcc7a3876293e96d5aeac184d68c13c368a42c3eec10a9b8af59c815b9d2c25500dcd4e7ec2bbccb840ae6b5fef7d68d4c2989947ff55881a626ef1da9fa341687542c735b4eba37c9cad340422aafcb870ee2b66c16e19f18fa4c56c8c2e8258d20b4dd56008f102c6a5286635bd52f0b3b5057e6d0de69624cab4153df3f79c49312a6d41305eb0ddfbbb097e499777ceb3dc15bf94fb24e9d5bbc2ac84426d68ac955ca872fb387e224c220aa161a85b9df338bc8eda42d96109a1bb20f75f6c9353d53b155d590e90d3fd81f27c0bb685604834a7d51b4427f99156f84c91c8df1d9e9db96b2bfae42cc33f0bf33f915a1b4ef11bc0bc8c920f8d39772355cac9507e19ae47f7c6fe78984", "78", "6f7eb1234588078e323c89acad5cfe125dd9d42811c383d5f7357d43219b5501a086daf057db8672b59fcc9d36b87701ade9ba4dea359ac0bd8d02c4b40af39fdc0051f4c8ed40f58314f3d39a86972a2bd49d5c9d0bd6013c619ff0cc2b967b556681eb730f615924ffb671a9cdde9d4b2252e5c9e43f0bbc4b5193fb317ed6071e236db4218c1dcb7791262cc06390971a5a03fc42c198a9c53d1f3b931414b378cae1cb839082dd9fbcc3e25046a2465d85eb710b22e7986176005530a5f8c8d44482eefb71305bfacfcfd05b14029f16f967a54b02d2f5a168f1d8ee84549ed5a93b8ab85ce561cc79132b5dc614de07dbcc7a3876293e96d5aeac184d68c13c368a42c3eec10a9b8af59c815b9d2c25500dcd4e7ec2bbccb840ae6b5fef7d68d4c2989947ff55881a626ef1da9fa341687542c735b4eba37c9cad340422aafcb870ee2b66c16e19f18fa4c56c8c2e8258d20b4dd56008f102c6a5286635bd52f0b3b5057e6d0de69624cab4153df3f79c49312a6d41305eb0ddfbbb097e499777ceb3dc15bf94fb24e9d5bbc2ac84426d68ac955ca872fb387e224c220aa161a85b9df338bc8eda42d96109a1bb20f75f6c9353d53b155d590e90d3fd81f27c0bb685604834a7d51b4427f99156f84c91c8df1d9e9db96b2bfae42cc33f0bf33f915a1b4ef11bc0bc8c920f8d397", .Okay}, + {.Shr, "3fdafa43b10e3ee0e8ff68979f7442ca7426061e809a25e38a467a54d7f0fdb31ef2dfb72563a1872b49b2ff3c5d4e42195fec4166b6f327b13108070cf7ddf0420600b21391cb167ac3fd60902a13758c31fbd957192e62115b06ce1382b837d7819f183fc32b9937ec19706a8e1bb96a7dcd130e7d70a2a04e5d9ae8a2fafea00fea2e2f592afd6092b7582bc9b9f0b8e7f308db263cdf2f7d418e500b2d2d4f4ab1f1cbefc01b1904cca50cd83f8aeea266b6d2ce0fd69132e4e8c62ed842f089c90a76c5c2e889579726b442281c14ff4f6ab853d8bd95a90ca83267ac4e005c9996a0929c4b97d59bdcd43b5684a64a81372eecb3f53d1e40fb1cba4a2237a9dcb30ed9ea5fcd2e63d0c744a2fa744941ed7c0b48b706214e16dce692f633574e114babfefa478b1ba6b0d12c643e073a92cd29b683958caaf5d6ef8c7014d2513ec3f295be95c0ce5b7d52c9c940f3046b2741478204387019cdcb47937deca2d640013167e92b05f8b57a43f0b208e0dcb1af065bc14b2b1dd2ae3901892a766d792791dbe933cf103ed29d4031b9dd84c382b8aa1d340b2a75c7a8e166e42381a53cb357b27a5491709f10af653bfeb45915e8c2828f25b237b4072453ff62556ffbed518a9d497b6e7c11891f943b19bb04410250f73e1468960483bfd08681789aea2ee562658c5d00a64715f94725c13d32579de00864e874f7ea", "78", "3fdafa43b10e3ee0e8ff68979f7442ca7426061e809a25e38a467a54d7f0fdb31ef2dfb72563a1872b49b2ff3c5d4e42195fec4166b6f327b13108070cf7ddf0420600b21391cb167ac3fd60902a13758c31fbd957192e62115b06ce1382b837d7819f183fc32b9937ec19706a8e1bb96a7dcd130e7d70a2a04e5d9ae8a2fafea00fea2e2f592afd6092b7582bc9b9f0b8e7f308db263cdf2f7d418e500b2d2d4f4ab1f1cbefc01b1904cca50cd83f8aeea266b6d2ce0fd69132e4e8c62ed842f089c90a76c5c2e889579726b442281c14ff4f6ab853d8bd95a90ca83267ac4e005c9996a0929c4b97d59bdcd43b5684a64a81372eecb3f53d1e40fb1cba4a2237a9dcb30ed9ea5fcd2e63d0c744a2fa744941ed7c0b48b706214e16dce692f633574e114babfefa478b1ba6b0d12c643e073a92cd29b683958caaf5d6ef8c7014d2513ec3f295be95c0ce5b7d52c9c940f3046b2741478204387019cdcb47937deca2d640013167e92b05f8b57a43f0b208e0dcb1af065bc14b2b1dd2ae3901892a766d792791dbe933cf103ed29d4031b9dd84c382b8aa1d340b2a75c7a8e166e42381a53cb357b27a5491709f10af653bfeb45915e8c2828f25b237b4072453ff62556ffbed518a9d497b6e7c11891f943b19bb04410250f73e1468960483bfd08681789aea2ee562658c5d00a64715", .Okay}, + {.Shr, "960f29a78bb828913a7dac7117de142524ea1af7f43a179ba0e64e0e48dd14414f7700b58440c2c6099e4129c64150cfe368367d411290fe73270c4cc6f7a7b337ef7be49516d4acd8d76be235a4104e66f573cfdea385fe1b4279b5d213d4482c4fa8c972a1350ce65d270d7b442046bfa00d6316213f442e378ef0dfd7c681293c115728bdac5a4dc4e48a884c76f2fd2d8cae697c0472af257a8fb32dfbe8e340a613c2786db52aea052cb70c4b86ea09a31360b3c94b73497b29915ef009f77e7b9c0375af27876b763aa248809e58177b3e580924ab3ecce40b8de97e44b5aacaba4776bc06fd3e5cabb0bafa36854ae4446b3eb5fefa6a58ef4d84165d7c2bdb7c532ad284484c0cf1a9f19126dd56f8b370463a19af311e234058aaeb26bff51629d4e2fa5955b8f82c6467f1a10da836b729742e534956caa99c79562ed10bad4b50cad71b383fb8646a5f95d909aa170a52a60d2c92c3f2c3a2c669bc6f6d725b8eb1c709c7a97be85288e3a3e04d07683343587a74166ac740a31936121b9096ed2edaa1f5cccc7cf6ea0e9ed5d92c2cd65b4bb5d543918e44f4dbb31ad0cbba517dde215aecef5cb9dfdeb015af840374898b49a6364c85af05b18e15638f86da1be7d5656d9285049f04ed8a03e88aba7005e33c0bc79bcd737438dca5c71f107c86ff401684fcb62607be0ba6e7ad22d3b1d2338fbe4c025b0a", "12c", "960f29a78bb828913a7dac7117de142524ea1af7f43a179ba0e64e0e48dd14414f7700b58440c2c6099e4129c64150cfe368367d411290fe73270c4cc6f7a7b337ef7be49516d4acd8d76be235a4104e66f573cfdea385fe1b4279b5d213d4482c4fa8c972a1350ce65d270d7b442046bfa00d6316213f442e378ef0dfd7c681293c115728bdac5a4dc4e48a884c76f2fd2d8cae697c0472af257a8fb32dfbe8e340a613c2786db52aea052cb70c4b86ea09a31360b3c94b73497b29915ef009f77e7b9c0375af27876b763aa248809e58177b3e580924ab3ecce40b8de97e44b5aacaba4776bc06fd3e5cabb0bafa36854ae4446b3eb5fefa6a58ef4d84165d7c2bdb7c532ad284484c0cf1a9f19126dd56f8b370463a19af311e234058aaeb26bff51629d4e2fa5955b8f82c6467f1a10da836b729742e534956caa99c79562ed10bad4b50cad71b383fb8646a5f95d909aa170a52a60d2c92c3f2c3a2c669bc6f6d725b8eb1c709c7a97be85288e3a3e04d07683343587a74166ac740a31936121b9096ed2edaa1f5cccc7cf6ea0e9ed5d92c2cd65b4bb5d543918e44f4dbb31ad0cbba517dde215aecef5cb9dfdeb015af840374898b49a6364c85af05b18e15638f86da1be7d5656d9285049f04ed8a03e88aba7005e33c0", .Okay}, + {.Shr, "a447aceb43d77c95bd1c213922eed53af9c171caa4bfa7a985fd0b5bf532c5e830e2973639d9afddd1a5d57ba5ca40f51ee97db58c348a45fa6cc4cba3a0c8615a69a586b3a80c7020bba62358b7fedc56a8d03d98ddbe35965c934c6aa10e348032218c1cdc5f4d7c8cbacdd43c31424df87d5c6a72c27aa7b78e01b093be757cfa2de15a3d3670d59e69c3a3da03ba7ffa258ad09fd324552d787704265ef37ddbc89fab2cb867092439cbf507742c0112c9e9ccb5f1d41cefef2c0e65ba654521e8796da3340034096f380aea4bca5325a7590dc8163b11d22dc0a45cf689d3d5879ecfd37e1f55fc835ce77c20e7a1834911611df5e8419b36ecc2988161da8c0e38283ae5f3032c61e444ea3d63a6cae80205311c321e983d1e19e5d1780f97089ad9d81a0ab671bd3b916fa577d04c53a8f70310382c73732908f3731f80ec198f613084505002ab0ae0e85ff2bb191bd7b42abf29ca15377b4d87ccccaddf44849f0c9e90b9f1d0bab029871963b1da3a383da60da33f826090932747f54d41ea0427a244e9e6a07ee3560e991b6e1f81c94301c16a33aac0bb4314ca23128d791a80ca1eab90fcbf6ef5119af6339c2def4983d166ba92d8e34fdc7773b9c986ef71d51aa6597dae780d96204d918e33b2b5cb36a0a52767e2860dc0749afe62813a458a4b5ad9f429de8a41ae2326b3529b39ceb8ac19ee4d2eea67", "b4", "a447aceb43d77c95bd1c213922eed53af9c171caa4bfa7a985fd0b5bf532c5e830e2973639d9afddd1a5d57ba5ca40f51ee97db58c348a45fa6cc4cba3a0c8615a69a586b3a80c7020bba62358b7fedc56a8d03d98ddbe35965c934c6aa10e348032218c1cdc5f4d7c8cbacdd43c31424df87d5c6a72c27aa7b78e01b093be757cfa2de15a3d3670d59e69c3a3da03ba7ffa258ad09fd324552d787704265ef37ddbc89fab2cb867092439cbf507742c0112c9e9ccb5f1d41cefef2c0e65ba654521e8796da3340034096f380aea4bca5325a7590dc8163b11d22dc0a45cf689d3d5879ecfd37e1f55fc835ce77c20e7a1834911611df5e8419b36ecc2988161da8c0e38283ae5f3032c61e444ea3d63a6cae80205311c321e983d1e19e5d1780f97089ad9d81a0ab671bd3b916fa577d04c53a8f70310382c73732908f3731f80ec198f613084505002ab0ae0e85ff2bb191bd7b42abf29ca15377b4d87ccccaddf44849f0c9e90b9f1d0bab029871963b1da3a383da60da33f826090932747f54d41ea0427a244e9e6a07ee3560e991b6e1f81c94301c16a33aac0bb4314ca23128d791a80ca1eab90fcbf6ef5119af6339c2def4983d166ba92d8e34fdc7773b9c986ef71d51aa6597dae780d96204d918e33b2b5cb36a0a52767e2860dc0749afe62813a458a4b5", .Okay}, + {.Shr, "7e6c75dcb4b79dab0becc3377bb3d78ddac01e260cf88e5a22f166ea2f50e276199054946277a43f9ac9142e0d6af3c81de4de05c243be05ec9eafcb583e7be885e81393192ea4e8f9026b16715f931546de521feccca60cec27c2c676d21d34b4c03fab8c5a5e472c1a8691b107758ce5ec0130eda7d29da504ab0f589aa67ee88d6508c73b8580756a401845d25a64e45314b3cfce47936dad1930a91fbc28b8e7fc1aa3001848111ab01087e10e8819933df92f1ded38e55869fcae0977207367dd362a4229a83313e4c56cacfeeb2fa2ccdb12c8e5e9032e01e6d1bddd4adab0678a8fed8bf737f85bfed47557ce7365caa446bfca76319812d649ac79ede622c88884c07907610c9ee9995bf8b9571adce881bf7293a068be6a63b27aedfa33fed90b74f39cf387e53072e1c1837cd03616d20f123a794978f6c4c020fbee1e542d03371e142b0612cd1370ce1487d332c1c93246d710391fd6a8b238ab604bbd5bb5e554e03b6704dc87ef6029453ab41249ac8d693df911d521b2d898e463fda8780234872753a6e7e255b2e5b9bdec420536dd87b756d010ca674d2d046073c10933983607558168a6e5182548ec5190712fb5d301e19b8cb325305e21623732d083a1a9e3868b262fd314b2ea4bf9e123dbb2d8c5ebbaf339902768d96850d3748b49925427b1aa4858f2c8636690dab315205618c47b8c97b9e134", "b4", "7e6c75dcb4b79dab0becc3377bb3d78ddac01e260cf88e5a22f166ea2f50e276199054946277a43f9ac9142e0d6af3c81de4de05c243be05ec9eafcb583e7be885e81393192ea4e8f9026b16715f931546de521feccca60cec27c2c676d21d34b4c03fab8c5a5e472c1a8691b107758ce5ec0130eda7d29da504ab0f589aa67ee88d6508c73b8580756a401845d25a64e45314b3cfce47936dad1930a91fbc28b8e7fc1aa3001848111ab01087e10e8819933df92f1ded38e55869fcae0977207367dd362a4229a83313e4c56cacfeeb2fa2ccdb12c8e5e9032e01e6d1bddd4adab0678a8fed8bf737f85bfed47557ce7365caa446bfca76319812d649ac79ede622c88884c07907610c9ee9995bf8b9571adce881bf7293a068be6a63b27aedfa33fed90b74f39cf387e53072e1c1837cd03616d20f123a794978f6c4c020fbee1e542d03371e142b0612cd1370ce1487d332c1c93246d710391fd6a8b238ab604bbd5bb5e554e03b6704dc87ef6029453ab41249ac8d693df911d521b2d898e463fda8780234872753a6e7e255b2e5b9bdec420536dd87b756d010ca674d2d046073c10933983607558168a6e5182548ec5190712fb5d301e19b8cb325305e21623732d083a1a9e3868b262fd314b2ea4bf9e123dbb2d8c5ebbaf339902768d96850d3748b4992542", .Okay}, + {.Shr, "3182d4f8352b48b8a703b0706fe87a5a2ff5617eec97d79cf3ff212b8f965d51fe1d8fa4ce70f00312fcebdbeea0e9ffbf92636f40d0d51401f751d2707527a102a321a441ad90b54211efa86044719a994a043516db1b38b1bfa4dbc9501feb7321ea95685eac28cbc126e3528524714a843b7b2d7ec25d8466f331b23b508b77b80998d390df0034690c2bbfd7251a6ee29dcfcf00d66c0ff0ebba45630c98e4d24332d837db93cdfea72fbeed9d5288b2b97a8f5a0601f3a4fb5bcf600cc09de059efeac34ccb1b8ef22968bd2ca08f0c44b50b0ac6fd7c4f966e2c48c891f2144949396658419376a332a49e40a82531840ebe8bbcb1c8ab773e919eb268de69e32f7d7c2c68269f99d6019b056fbd6941205c43bface99a3925b60a710e8981fb5be7e0acc5986f83378f37a36b970e10d7e9dfb6d769e3a5a4e081710a7ccc87b5485e5a5a57ef7f12b7c15c648c9be9c1899f8dcbbc9883617ced17e863ebb381dc13ed753de3df300f86fecfde0b4e62ddb5100cc0454bde0701626039230106e41f7bd5c1900f77224953a45c3644a98a9d532d250887bb1dbcc6685bd99b26144fffce62152f7cff1097348f50750111dbdcfa6f9e239db51a5cd7124c5d62b820dc757e22dc448a14471509bfed1bcc39594ed38a606aa7dc87d49634d6634ef0a3a31e7b8664470e5b1420e8b97cc7628b2278eec4dde408b8b7", "258", "3182d4f8352b48b8a703b0706fe87a5a2ff5617eec97d79cf3ff212b8f965d51fe1d8fa4ce70f00312fcebdbeea0e9ffbf92636f40d0d51401f751d2707527a102a321a441ad90b54211efa86044719a994a043516db1b38b1bfa4dbc9501feb7321ea95685eac28cbc126e3528524714a843b7b2d7ec25d8466f331b23b508b77b80998d390df0034690c2bbfd7251a6ee29dcfcf00d66c0ff0ebba45630c98e4d24332d837db93cdfea72fbeed9d5288b2b97a8f5a0601f3a4fb5bcf600cc09de059efeac34ccb1b8ef22968bd2ca08f0c44b50b0ac6fd7c4f966e2c48c891f2144949396658419376a332a49e40a82531840ebe8bbcb1c8ab773e919eb268de69e32f7d7c2c68269f99d6019b056fbd6941205c43bface99a3925b60a710e8981fb5be7e0acc5986f83378f37a36b970e10d7e9dfb6d769e3a5a4e081710a7ccc87b5485e5a5a57ef7f12b7c15c648c9be9c1899f8dcbbc9883617ced17e863ebb381dc13ed753de3df300f86fecfde0b4e62ddb5100cc0454bde0701626039230106e41f7bd5c1900f77224953a45c3644a98a9d532d250887bb1dbcc6685bd99b26144fffce62152f7cff1097348f50750111", .Okay}, + {.Shr, "422966accd2cf4a70ae2abe7b4a656ee64e66b2c3a0ef6b3b6596dd595cdc669f11ffcd3209d4141ac25c95f809d23dd6e36a113875dd2acd98126c6d72bbda404b50ad4f8c9a8f2beec022fa9578a8a48f76189f9ee5dd1302366bab6a56f87a59c4f331d574c54c432f02b53cb3e3872ef42832078af6fcf9fb13a75d597395a4012cdc9c0a4f1eb191543a66f1e5f28beec7678b435ae9772a036f282c36928ae060278195a46c4f69607911b44ce03688f3e1aa34d517b7e8f730931a40de2f66e3402c0060967fc438d42394af3ddf65fd99a722216f1dcac0dd6fd1b2498829b1dca20e2632b5b38b609930a46f1e1bb2e17319380c439a1bfddc95eba817ed606f96544147145186d26af6a5e6b36d50ea256d396f398e465de984a0ebe3daecbfbf33b6d2e47bc58e18a3a5edb39becd66d588ba2a6160fd6fcdd1cbcf85b49d24b8901d0e57f36ad3389e7e6b87380a5d953128befdb3c7087afe2c35c133a74febf6ee7145268054fcc885cf3290a56f9bd2d08c90d0d2c9afa2079d83be130bfbb1c9886321b30115263e24e3b28a0f77bd82ecba59ee1a77fbb118ad726e477c0adb5c7ee454b650edb70218e6d8fc1abed90bb758a45eac8932267f2e786366fa21c538a2179c97d61f9b8a33382194b31875f25465a6f9102ebdce43c290df20d93b6353aeb286e18aa953e67c537f96cad74ef818c2f38d74", "78", "422966accd2cf4a70ae2abe7b4a656ee64e66b2c3a0ef6b3b6596dd595cdc669f11ffcd3209d4141ac25c95f809d23dd6e36a113875dd2acd98126c6d72bbda404b50ad4f8c9a8f2beec022fa9578a8a48f76189f9ee5dd1302366bab6a56f87a59c4f331d574c54c432f02b53cb3e3872ef42832078af6fcf9fb13a75d597395a4012cdc9c0a4f1eb191543a66f1e5f28beec7678b435ae9772a036f282c36928ae060278195a46c4f69607911b44ce03688f3e1aa34d517b7e8f730931a40de2f66e3402c0060967fc438d42394af3ddf65fd99a722216f1dcac0dd6fd1b2498829b1dca20e2632b5b38b609930a46f1e1bb2e17319380c439a1bfddc95eba817ed606f96544147145186d26af6a5e6b36d50ea256d396f398e465de984a0ebe3daecbfbf33b6d2e47bc58e18a3a5edb39becd66d588ba2a6160fd6fcdd1cbcf85b49d24b8901d0e57f36ad3389e7e6b87380a5d953128befdb3c7087afe2c35c133a74febf6ee7145268054fcc885cf3290a56f9bd2d08c90d0d2c9afa2079d83be130bfbb1c9886321b30115263e24e3b28a0f77bd82ecba59ee1a77fbb118ad726e477c0adb5c7ee454b650edb70218e6d8fc1abed90bb758a45eac8932267f2e786366fa21c538a2179c97d61f9b8a33382194b31875f25465a6f9102ebdce43c290df20d93b6353aeb286e18aa9", .Okay}, + {.Shr, "d6ff2ab56fe36b527977caab927abda658d4c13fde711bfd31721ee6a0e0125021c35a3eec416e32087667c99577c0871ad34241e72d1127e67b9fc87d681e1ba63ffc3de9d93008043ef25382dc9d6d7e19ed29951665ebb7e0c47f47d482cf1efd4d3d75747212974bab6769b589ce3217b130b7e288c5b3887d3ab73f14f0af373cc44a734ad855b6752375648bdef2468f9f9a984109efa50fe3db21ac877ebf796089bdf6080f5b4019ad368989e919e9b93dd6e4384d1f3b75228922ff26996d4f79a8efd7839d9b0e94a1179d414b3b998273b0c17190c7610f2f53f46d3ef2bc7158b71c4f7738cac6939841f150d4af34310ea54375b502ef71835809eb3d4e0b314cd07129e9e4cfa68559de394d4a26c3defa2c16f5ce58e2acd0ddefb2380b3f1be0ea098d91a3528449414eab35af997236e353a44bcd160b4f470b6e5fbbdb1d92e815b44bd11eb3e39fdb2394ed0a73f5c83d33019e26ca5f33eb1bb229d34807d28a8d37d6532defb4eaa1e7eba13ec23d3f55e9d0215e40927873c34fdef88577fad92ffca54d52dceb81916df6d678b7071ac3e95453bdc49034a737433bce456922993c71fc71f8e7b93437f94698be7e1e6977135978f7fe153d3c3baa1ad9151a13b57f8fcf10ef789da8185db39ba9485a791d2078c1468db894f9435081f0e5473a483f03f541291edec5734bfca044db020ada1c", "b4", "d6ff2ab56fe36b527977caab927abda658d4c13fde711bfd31721ee6a0e0125021c35a3eec416e32087667c99577c0871ad34241e72d1127e67b9fc87d681e1ba63ffc3de9d93008043ef25382dc9d6d7e19ed29951665ebb7e0c47f47d482cf1efd4d3d75747212974bab6769b589ce3217b130b7e288c5b3887d3ab73f14f0af373cc44a734ad855b6752375648bdef2468f9f9a984109efa50fe3db21ac877ebf796089bdf6080f5b4019ad368989e919e9b93dd6e4384d1f3b75228922ff26996d4f79a8efd7839d9b0e94a1179d414b3b998273b0c17190c7610f2f53f46d3ef2bc7158b71c4f7738cac6939841f150d4af34310ea54375b502ef71835809eb3d4e0b314cd07129e9e4cfa68559de394d4a26c3defa2c16f5ce58e2acd0ddefb2380b3f1be0ea098d91a3528449414eab35af997236e353a44bcd160b4f470b6e5fbbdb1d92e815b44bd11eb3e39fdb2394ed0a73f5c83d33019e26ca5f33eb1bb229d34807d28a8d37d6532defb4eaa1e7eba13ec23d3f55e9d0215e40927873c34fdef88577fad92ffca54d52dceb81916df6d678b7071ac3e95453bdc49034a737433bce456922993c71fc71f8e7b93437f94698be7e1e6977135978f7fe153d3c3baa1ad9151a13b57f8fcf10ef789da8185db39ba9485a791d2078c1468db894f9435081f", .Okay}, + {.Shr, "521898bc787145f834ef96744b89c003fd8f0940182dbd2f808ce5514c52d512f4110399b90a18ec985eb1be6d4c0b3bf270ab2a4fa9defed647c9f9e66810eb0c6f54570b8d8d476bc51ac4ba56d871c4ad8bb037caac52a3549ef9e87a763976d37bf7cdff787c89eb1e77ccbe1fdfc3991d902489f9a22e2f04dce46f21dd800333e223c8a455136dbda97e5fd3be557c0704a497ac1d92150993bec9682936cd27abba07d3b37ec7469f64da1e2c4cd98e1070df9f2f054908c099f9704449d8adb8b4fc91281643aaed6d9852fc8e8183199f4b26aabafad363a20561cfffab754d6d3bd0b179d9e870bab78c038a4656c3be281ca84b251d1b8c3133243155dc852c74f2062cba374f32d1ad63acfd25019b35bf82a9b85339df5cbc863bb300c14a792833cd3f261e95b41d3b568f92b6787ead5091ebe11522dbd1729b6ea02e831d719c97c06ec4910a641ebbe87c6fabf8fe8ab0a9f7aeafd6d2637812c4d54625d7eb14d47230600528b75569615dc9dd7f7bdf6b5c0d4d8f045512acd3986ab46044b0c71fb702f94549f98e57c5f8fae60e3cae0d5a8a5e046dcdd88918d148e4f6c4c999fecf9b4a4abd95ed0ae6261da6d245aeea4b20107b392202e2ccf953fdcf918120e56d32329488c9cc182d4fa5904d0002972580ee0ea43d9c2b65b96817317f2500e253b865631b53113f5bda8178a7f02d9e7ee8", "258", "521898bc787145f834ef96744b89c003fd8f0940182dbd2f808ce5514c52d512f4110399b90a18ec985eb1be6d4c0b3bf270ab2a4fa9defed647c9f9e66810eb0c6f54570b8d8d476bc51ac4ba56d871c4ad8bb037caac52a3549ef9e87a763976d37bf7cdff787c89eb1e77ccbe1fdfc3991d902489f9a22e2f04dce46f21dd800333e223c8a455136dbda97e5fd3be557c0704a497ac1d92150993bec9682936cd27abba07d3b37ec7469f64da1e2c4cd98e1070df9f2f054908c099f9704449d8adb8b4fc91281643aaed6d9852fc8e8183199f4b26aabafad363a20561cfffab754d6d3bd0b179d9e870bab78c038a4656c3be281ca84b251d1b8c3133243155dc852c74f2062cba374f32d1ad63acfd25019b35bf82a9b85339df5cbc863bb300c14a792833cd3f261e95b41d3b568f92b6787ead5091ebe11522dbd1729b6ea02e831d719c97c06ec4910a641ebbe87c6fabf8fe8ab0a9f7aeafd6d2637812c4d54625d7eb14d47230600528b75569615dc9dd7f7bdf6b5c0d4d8f045512acd3986ab46044b0c71fb702f94549f98e57c5f8fae60e3cae0d5a8a5e046dcdd88918d148e4f6c4c999fecf9b4a4abd95ed0ae6", .Okay}, + {.Shr, "5b69ee0b2aa2b0044201ff74e1fc86d96708b75fc5befc21f8eb9c20a30da8e1376c151b81a55389389ac7f980736bb92b3accaa7471650065bd2da85e18a063d9989420d18a7bd7a8ee89a687b482529f69ae8d79185edd460f74b6f55848c8b377499edbc0cba1483b9c9a39fbea476fb6c1522ca8a157870932c48bfc6e2daf27f17415247bb5379e0e65988e7ddb9f38445800bc38065fd88f8a29c5a140413f3ebace8714cb20093643563c83e47e0ff3e1d4d773f08335379f48372170675fd714ba8f5a980f2d854476fbd854c5727865c052d8b00100a9bb6d71bc8283b37de21502037ad41c935653d837cb6110bd9f4ebed0844b3731eca02510943228ddd4a91fab398631dd11b232048839b473b888b90d2d280c8704fc50efe9abcf308b35b3f793ada6d6db5cdf74c82268e3d982ac137c13555b1593c362ad7cb334c4e530cbf2ca2406e9e5fa96cd07c745c64cffd117a0970f6f15ad6b134d9204db534755b0a6a8676acfbfc90be01000ceb6f3a5396b31f2d56b8e19116e27405ee91b8d9e8af62df298c575226ce372dd3d7b60153a63e674b291fca30ca03b01dfc5e0a4692edd92f0616782c6312127f22bed3ed183948fad0b6c9cdb5528e7776e8891aea7f2e751801f61af54c25dfc87f556c82b3723ef0d4fa21b67035c20a4b95ddac9cba7da3b6c2c04cf24c2f66f1f8af0e7834285d0cdb9", "3c", "5b69ee0b2aa2b0044201ff74e1fc86d96708b75fc5befc21f8eb9c20a30da8e1376c151b81a55389389ac7f980736bb92b3accaa7471650065bd2da85e18a063d9989420d18a7bd7a8ee89a687b482529f69ae8d79185edd460f74b6f55848c8b377499edbc0cba1483b9c9a39fbea476fb6c1522ca8a157870932c48bfc6e2daf27f17415247bb5379e0e65988e7ddb9f38445800bc38065fd88f8a29c5a140413f3ebace8714cb20093643563c83e47e0ff3e1d4d773f08335379f48372170675fd714ba8f5a980f2d854476fbd854c5727865c052d8b00100a9bb6d71bc8283b37de21502037ad41c935653d837cb6110bd9f4ebed0844b3731eca02510943228ddd4a91fab398631dd11b232048839b473b888b90d2d280c8704fc50efe9abcf308b35b3f793ada6d6db5cdf74c82268e3d982ac137c13555b1593c362ad7cb334c4e530cbf2ca2406e9e5fa96cd07c745c64cffd117a0970f6f15ad6b134d9204db534755b0a6a8676acfbfc90be01000ceb6f3a5396b31f2d56b8e19116e27405ee91b8d9e8af62df298c575226ce372dd3d7b60153a63e674b291fca30ca03b01dfc5e0a4692edd92f0616782c6312127f22bed3ed183948fad0b6c9cdb5528e7776e8891aea7f2e751801f61af54c25dfc87f556c82b3723ef0d4fa21b67035c20a4b95ddac9cba7da3b6c2c04cf24c2f66f1f8af", .Okay}, + {.Shr, "68ca65e1a0169c47d6535d2749fee63d0300a91b31fc0a438632a5a722e919804e2aba46b839da2ffa20dea5df289bbb66cda6c46281606edfd2f54f117db75ff0aea1fd13550fa77876a0844f04ea40dbd8c9bf4119b6c5cbb0409f9eb53fe60e8d501ebae7247be51c74c0069432d2704e0bf3368819a37b1f23017f8d95494eecd821050101b049ea2c385f32d45f012bab31e4d2df660acd34ea32e9ae03f3dc0e76f52a7701630a013092dc8b9d2e794f4e10ac7e414a9ec345ffcfa3974803e6f1ef4ac392611070255f527ba217b1c83930b4a669482117414383333fa9d3f7cc5c8aac64cfe37aef9f1b07966a5f2e72d0e0fb8b36c83d1ec2731b5ebd06f635d665dd19f7dab4b5f775bdf1c0e921870c0b27d6538e1e6bf1951232c1310382326e9b70cd74cefea281113fce6a52fa941912233c650a3bfc8a5d615384e7e2528b106accc9dcbd493f7f18df7433d4d7446414417cb9eee82f29c792c870061ed0016cfb681f1e5e9938cf1ec5f60e5396b79716e3635ea2e9a36b20f0fced0441d4f7a23aeb096714ca666b5a4247fb50430e5f0a8f53a523a06eac0305c0cdef648e6662bc3772bff74355cf12c119ff4bcdf37df2ecd29eedd64cef616bb7a4e376bc7bddb121eb0f1b0540317e2b3b20fca0417fee0821b3c2cbbd980f0fbc33fe23e16703a4c17db7247a8f0052965a2c655e2a289b1fc8fd", "1a4", "68ca65e1a0169c47d6535d2749fee63d0300a91b31fc0a438632a5a722e919804e2aba46b839da2ffa20dea5df289bbb66cda6c46281606edfd2f54f117db75ff0aea1fd13550fa77876a0844f04ea40dbd8c9bf4119b6c5cbb0409f9eb53fe60e8d501ebae7247be51c74c0069432d2704e0bf3368819a37b1f23017f8d95494eecd821050101b049ea2c385f32d45f012bab31e4d2df660acd34ea32e9ae03f3dc0e76f52a7701630a013092dc8b9d2e794f4e10ac7e414a9ec345ffcfa3974803e6f1ef4ac392611070255f527ba217b1c83930b4a669482117414383333fa9d3f7cc5c8aac64cfe37aef9f1b07966a5f2e72d0e0fb8b36c83d1ec2731b5ebd06f635d665dd19f7dab4b5f775bdf1c0e921870c0b27d6538e1e6bf1951232c1310382326e9b70cd74cefea281113fce6a52fa941912233c650a3bfc8a5d615384e7e2528b106accc9dcbd493f7f18df7433d4d7446414417cb9eee82f29c792c870061ed0016cfb681f1e5e9938cf1ec5f60e5396b79716e3635ea2e9a36b20f0fced0441d4f7a23aeb096714ca666b5a4247fb50430e5f0a8f53a523a06eac0305c0cdef648e6662bc3772bff74355cf12c119ff4bcdf37df2ecd29eedd64cef616bb7a4e376bc7bddb", .Okay}, + {.Shr, "abe9a2bdc1f77a199fdf618b0a8e1492c30260559575b5d6c09a0d1451d725050bb9c728318269a1213e06b79bf58a56cd94862e5309cf58fbba578ca3e2918600024c048f75ab93820ba4c8c0f5bdc20402683b565dca14cfbb208b65142823bd8c967de3710d31ef4b7ebd568699925d5a792c5803981f3a27789d5c4f6ac24329da4792d3b00ca01633722b61b641d34ce7dfa85a82179d024d7773592d78ac281710d9fa3820511e60649f908ce0f90368f733d6292a31af3e97b6b16db1af0a5d5ea7a01772866cfd08293634378a21021bc0d7ec5a4a5d09e649126a04798a1c2d1f8d61cf7d9ac88030c15bb4c2ae9ec97804b36ad3cbd23e6705ef5c98b53686cf6469dfdb1ced5e90aa0c3b5c2cd7282caa5b5d38217a0b6026616c1bcdc8d22ecbda837f8ee337b7e442c9945b2ecd0d2b82708377e699f6f8ba2faa7035f04ac890400f3d9032777e3ecd0dd68e30b7cc0666fe6617bd56c1d1e742af9cb734256158d21c9cc37535b13fc74d5c3e1173c33f0bc3060bd9b99284def34f55c00e8501a104c1368b726df11542ccce8f9ee9bf6f92f762ec1efda4a9be3e01f48f67075494ed039acb26ca56b81be00f872f45df98ec1a023f9e9616d8d09c9d84d1f47b73e0986b5b11bb694b3dde98090cd67bdd552ca4dd88a04ba2a5f9d544089e456f4d3dbb982337066d41fbedc3fa2e29d60c76a54aae98", "21c", "abe9a2bdc1f77a199fdf618b0a8e1492c30260559575b5d6c09a0d1451d725050bb9c728318269a1213e06b79bf58a56cd94862e5309cf58fbba578ca3e2918600024c048f75ab93820ba4c8c0f5bdc20402683b565dca14cfbb208b65142823bd8c967de3710d31ef4b7ebd568699925d5a792c5803981f3a27789d5c4f6ac24329da4792d3b00ca01633722b61b641d34ce7dfa85a82179d024d7773592d78ac281710d9fa3820511e60649f908ce0f90368f733d6292a31af3e97b6b16db1af0a5d5ea7a01772866cfd08293634378a21021bc0d7ec5a4a5d09e649126a04798a1c2d1f8d61cf7d9ac88030c15bb4c2ae9ec97804b36ad3cbd23e6705ef5c98b53686cf6469dfdb1ced5e90aa0c3b5c2cd7282caa5b5d38217a0b6026616c1bcdc8d22ecbda837f8ee337b7e442c9945b2ecd0d2b82708377e699f6f8ba2faa7035f04ac890400f3d9032777e3ecd0dd68e30b7cc0666fe6617bd56c1d1e742af9cb734256158d21c9cc37535b13fc74d5c3e1173c33f0bc3060bd9b99284def34f55c00e8501a104c1368b726df11542ccce8f9ee9bf6f92f762ec1efda4a9be3e01f48f67075494ed039acb26ca56b81be00f872f45df98ec1a0", .Okay}, + {.Shr, "cd864e046f35a6815a4c4c9775ffedfd17b3186bf9d48c6f19287a37aae92152b6b708720b6f874c236fcb5c6434d0593dc1805851edaa17763ddf3ebb56355f98d23464cdd53d84fce8d67fe5ce685faf7714612def7b353d299ba0b865f17b035b2baa5f754d0c0ab768f40523d92837f3bf1b824163320dbf227e3feda008417ac95f786e02da765df9d9b6c1f767bd9420cdd82705c9b99fbfad778174880a8312c358bc296d8e2109a53b0801919f7d88f924c1644aab0c11c37ddd36e0d35a85bea538e56e60977ee4c9d7581cf4408adcaa2334b147dfebde1175930b5507d4778e40c767612fb3d004d3fa1787670e7065121f2feff23ec28949a1e3d24f83dba48ae8c5bfbf7ba421da8e10520d21e567cf0d5476f1ad4a39330579c0d5c1e1ae6d543cc4facce8b60e606930c314b2bf1d758c95cd3a0d0d6f5da048651da16f4e354db1c38d9ff70d6b178e9ea1cf97820cd105c7f5455a3a0d2526d7e695a4ba044479a6b70cfbe9a9a724fdbc185877c807d686b444ca41ea0ff811395cbdb9a942125cb4ec168e91c7ef95c46532404c0a3cd7aaad263d1c570a78cfac82ea038b9fa8d410506d59b69fffc3592283077f26a6eaef07eca9d735e1603f814465695e389b8a6eb7e58a8ad728ead03e2520e8692cd595d31511a08a4d2c3c0946c052d4c988a230dd08d25cabf20d0c2bc3f3ca55fb66d96cd6", "78", "cd864e046f35a6815a4c4c9775ffedfd17b3186bf9d48c6f19287a37aae92152b6b708720b6f874c236fcb5c6434d0593dc1805851edaa17763ddf3ebb56355f98d23464cdd53d84fce8d67fe5ce685faf7714612def7b353d299ba0b865f17b035b2baa5f754d0c0ab768f40523d92837f3bf1b824163320dbf227e3feda008417ac95f786e02da765df9d9b6c1f767bd9420cdd82705c9b99fbfad778174880a8312c358bc296d8e2109a53b0801919f7d88f924c1644aab0c11c37ddd36e0d35a85bea538e56e60977ee4c9d7581cf4408adcaa2334b147dfebde1175930b5507d4778e40c767612fb3d004d3fa1787670e7065121f2feff23ec28949a1e3d24f83dba48ae8c5bfbf7ba421da8e10520d21e567cf0d5476f1ad4a39330579c0d5c1e1ae6d543cc4facce8b60e606930c314b2bf1d758c95cd3a0d0d6f5da048651da16f4e354db1c38d9ff70d6b178e9ea1cf97820cd105c7f5455a3a0d2526d7e695a4ba044479a6b70cfbe9a9a724fdbc185877c807d686b444ca41ea0ff811395cbdb9a942125cb4ec168e91c7ef95c46532404c0a3cd7aaad263d1c570a78cfac82ea038b9fa8d410506d59b69fffc3592283077f26a6eaef07eca9d735e1603f814465695e389b8a6eb7e58a8ad728ead03e2520e8692cd595d31511a08a4d2c3c0946c052d4c988a230dd08d2", .Okay}, + {.Shr, "d95ddb1680c4a843810e0278c467286c1fa1243dc275f8c3460f00e8dde1bb2e678ac43a820ef70846601bb1661a890c06ca0bfb86779a1c498d62f5455501cb0ce0b22838998bd8a86a35b19c4083236244bca17fb019ad3df5245f66afd3a353b69e13b9c5b139cc27797b9320bd31d634c78ecc629a3fda5b47bee04784f876984fba69f7787093f7e11dad6e0de8b98ff367df76d8c1bc9ee7d4b01b95e41648e3ff8801247c0c991facc5eb51a9b582afc2b643d779a73a37b1ca6cac6890905ff69602e712ec4ce29e8abe980dbe171380f06594317e99a2b5498244dbbce5c19e33642edd3dd736df1d0932783a06eefd87235edd3b1bb12bd1fd470e3fda36b4e264191ecaeb6f327b03bf0e19e7267819dcf272b801b48e2a14c89f6e818d4cc297747464c325961895de54a09de7d4dd91d848f85a988887c206f9ed702afdb7d3e09e462d0af25ca2e98d94a45917dfcef5c018a36297f80adefa50f9009bbd1c3305c28d0e57d07cd33a5809299fe10f9e4f60fde97aaae0a152cd78df57c319a0d193687311e989bf45734dfb2319ff62d8cf5455f839865c7ba31acca9a752b85deed09e948afcbc1576a4a35630f812eb829cd3ef4846d263106ae20b0443194ca34f80fc844398f2dcfedc2a728a928dd9dfd9c4d00cae972693cc5ff73d61e28d97389d04357b60b93e71e8a53384af379a87c1104e7091", "258", "d95ddb1680c4a843810e0278c467286c1fa1243dc275f8c3460f00e8dde1bb2e678ac43a820ef70846601bb1661a890c06ca0bfb86779a1c498d62f5455501cb0ce0b22838998bd8a86a35b19c4083236244bca17fb019ad3df5245f66afd3a353b69e13b9c5b139cc27797b9320bd31d634c78ecc629a3fda5b47bee04784f876984fba69f7787093f7e11dad6e0de8b98ff367df76d8c1bc9ee7d4b01b95e41648e3ff8801247c0c991facc5eb51a9b582afc2b643d779a73a37b1ca6cac6890905ff69602e712ec4ce29e8abe980dbe171380f06594317e99a2b5498244dbbce5c19e33642edd3dd736df1d0932783a06eefd87235edd3b1bb12bd1fd470e3fda36b4e264191ecaeb6f327b03bf0e19e7267819dcf272b801b48e2a14c89f6e818d4cc297747464c325961895de54a09de7d4dd91d848f85a988887c206f9ed702afdb7d3e09e462d0af25ca2e98d94a45917dfcef5c018a36297f80adefa50f9009bbd1c3305c28d0e57d07cd33a5809299fe10f9e4f60fde97aaae0a152cd78df57c319a0d193687311e989bf45734dfb2319ff62d8cf5455f839865c7ba31acca9a752b85deed09e948afcbc1576a4a35630", .Okay}, + {.Shr, "5051d0ef22ee374d33943c22165ecba37ddb8001f52df08a127e2f1284792ea06448d80612fcec92b9d28f84d7c55878e5f611477e385cf00051653f3077c5d03edff987ac29add8d41d5163d7a9f299f8e762a161d62896aebdd9d135d04da96b292a1fe860127e80087a4cf4aae916b7b3e986866cc4735ceb9c7da25f7a1e14e3e740f188e90bdea11504f2e3df54e3e783975cc0df787de9d5aae58dce7b297c15abc658049544b57a3af55395588e407b9ae5023eb327517a8a537d3b131f57263117e652cbeec0292ce2a019045793c5e73856adfdc5bdeaaac6302def5047be4e98b594e125e68403932c6206fce86990e9ccbea5e25f0607f24053888181f397644b8e4d74e7f3d405852595f9d4acca6ee7900a36c2f7709014b54cfdf4b4e5545db1c0279850c636a14ed7cb9f49af42b0220e8369f1bd14ab3d5131d99270d60251ffc64126988cfc1a9b3d060990d66b0754ef6808ec6999548ac5852e35d3df49022c9dfeaa832881e18ecd6087f4acdadc495d9a3635a46cde5daf5dc7cff90b6f19989da16af474abeb02fb59ac79717208b1be1a62b065d00570688c36186abb5992439ab8a4391c16065b70532d111281b948d4225684f49f320c180429a219919480d4fdab3833aa1baa18f386d12f884dacdc52d482635e90e60e0fc77940f3c1adaa060772ac61d6278e95f54ab44966da6f6999886f", "0", "5051d0ef22ee374d33943c22165ecba37ddb8001f52df08a127e2f1284792ea06448d80612fcec92b9d28f84d7c55878e5f611477e385cf00051653f3077c5d03edff987ac29add8d41d5163d7a9f299f8e762a161d62896aebdd9d135d04da96b292a1fe860127e80087a4cf4aae916b7b3e986866cc4735ceb9c7da25f7a1e14e3e740f188e90bdea11504f2e3df54e3e783975cc0df787de9d5aae58dce7b297c15abc658049544b57a3af55395588e407b9ae5023eb327517a8a537d3b131f57263117e652cbeec0292ce2a019045793c5e73856adfdc5bdeaaac6302def5047be4e98b594e125e68403932c6206fce86990e9ccbea5e25f0607f24053888181f397644b8e4d74e7f3d405852595f9d4acca6ee7900a36c2f7709014b54cfdf4b4e5545db1c0279850c636a14ed7cb9f49af42b0220e8369f1bd14ab3d5131d99270d60251ffc64126988cfc1a9b3d060990d66b0754ef6808ec6999548ac5852e35d3df49022c9dfeaa832881e18ecd6087f4acdadc495d9a3635a46cde5daf5dc7cff90b6f19989da16af474abeb02fb59ac79717208b1be1a62b065d00570688c36186abb5992439ab8a4391c16065b70532d111281b948d4225684f49f320c180429a219919480d4fdab3833aa1baa18f386d12f884dacdc52d482635e90e60e0fc77940f3c1adaa060772ac61d6278e95f54ab44966da6f6999886f", .Okay}, + {.Shr, "bb5faf4e1ad31d61da988276b67be5a397aef740a08b4c6cb8980d8181d77896ad1411579867ed2d76221bfe25438c19f6c9e1fc0f33c5f5db3cba297d6d4e19c833d8e34737bed076407571df7c2edc4c8f13d3379ad2a221d1a1685c194ab9115cc55832b95ee3c488762b44a4ec3932dd0e6fef500de91a3dab48ca49eb3ba16dbfd817dfa62cd9e941942a09896516d7a5ba41ba6bdb81431fe79c4c49d51b3b26b66e5be91673954faec0740afae1cd659dff4cdb195f5fabffefcb4ce774246028bead42c3ee4498e470e5e668be4b0b64bb4036a0c3558172632f2bd80358a558cc7c6b69f19adbde14a81b7bcd07aab6d6535dc6a404d4ad3841eb2fec0064651adc0c159b120e75246604480d5e3d7d4477d0363846de40edc8a01e0ac1e0dabfe960779245a614ea88a41bde9e6270cbff7c8ec940f0902fd95a6abf757dbf839983db286163aa6f46b43e019839beb1408e7319dfc82ce714ccb9e5b77e8d9db4440919cbb5adfcc8fa79fbd0ec29558bc56823b063fc79b8568899957b8330dcd6c40d8c66d09fb0ed5260fe364d43d1cef22d167e9303d15f3049c0a794dc3d72b2014ae6b1f6ea32d37be5dc9e8bc89ebeff6b51ecd3dd5a4b3b9bf839f9e780005230d256b62867d66f94e0fbaf9f665725a4e44c0ed0f91638221bc8fa596e1582c2cc1a3d296650201fdb4a6bd79ba7356013508f9a2312", "1e0", "bb5faf4e1ad31d61da988276b67be5a397aef740a08b4c6cb8980d8181d77896ad1411579867ed2d76221bfe25438c19f6c9e1fc0f33c5f5db3cba297d6d4e19c833d8e34737bed076407571df7c2edc4c8f13d3379ad2a221d1a1685c194ab9115cc55832b95ee3c488762b44a4ec3932dd0e6fef500de91a3dab48ca49eb3ba16dbfd817dfa62cd9e941942a09896516d7a5ba41ba6bdb81431fe79c4c49d51b3b26b66e5be91673954faec0740afae1cd659dff4cdb195f5fabffefcb4ce774246028bead42c3ee4498e470e5e668be4b0b64bb4036a0c3558172632f2bd80358a558cc7c6b69f19adbde14a81b7bcd07aab6d6535dc6a404d4ad3841eb2fec0064651adc0c159b120e75246604480d5e3d7d4477d0363846de40edc8a01e0ac1e0dabfe960779245a614ea88a41bde9e6270cbff7c8ec940f0902fd95a6abf757dbf839983db286163aa6f46b43e019839beb1408e7319dfc82ce714ccb9e5b77e8d9db4440919cbb5adfcc8fa79fbd0ec29558bc56823b063fc79b8568899957b8330dcd6c40d8c66d09fb0ed5260fe364d43d1cef22d167e9303d15f3049c0a794dc3d72b2014ae6b1f6ea32d37be5dc9e8bc89ebeff6b51ecd3dd5a4b3b9bf839", .Okay}, + {.Shr, "d5c846a7fec2d2be6ad47d66034348d237eb2d26a6c6d1e709f9473f13cf08231f4ac98759164c0b2329ec5c93118e9bde422fe767919978d6fa3b8043f1234753d42dd39bb0601c3b8a2128a3e20beceddd50139d91dedaa5b9d6d643b6676baff0f17cb165d1fc07fd79e1cf73cf3bf573f8823825ec114e1182e896398b2f27cffe5bccbc73c715d8613d91aeb08a8d9a902bd3628508ef7b9cef5b44a4956e034e26be5c0f1e00a7437a4a293074877b3e56cb78fe9fbfa3908a9c24400d0e43df868f734aaf55889c100511a51806dd9c740a2ebaf17907e25711b7ea6ef8fa9289cbfa41da1040355fb8937b143a3d19ac0222edba281d4349c2763eeee8d2c1182b161d90f009668712959c52f474cddcd16d1a3a29703d39fd1ecabc3cdc242fada16357756b2cf973c88046913a837758dd2fc312800b69d40a231ad1ac911f24d2c12d61ab72044e18e3e9331dadab633c019640b9f8fd549dcefb1886d8ab50ba1814ff76f70beb2aa25f0aac8c77169ad5a7ead4f93997b213302c2c92a464a9179f95caa6e56ee1a31cf8a1a1bf2347f3d8bebfe77595fd8627f51482a1efbdf5eb7e19267c7ba5b35dcfcd024466fce64074ff67ef6add84c74e1bb130e17a82928c0b1161fb5539b18ba8fbdbd88bdfed30bf51295ed826b5680cfce9094d767a5a74de5e3dd8407581cc0eed674c414bee2fab8987871de5", "3c", "d5c846a7fec2d2be6ad47d66034348d237eb2d26a6c6d1e709f9473f13cf08231f4ac98759164c0b2329ec5c93118e9bde422fe767919978d6fa3b8043f1234753d42dd39bb0601c3b8a2128a3e20beceddd50139d91dedaa5b9d6d643b6676baff0f17cb165d1fc07fd79e1cf73cf3bf573f8823825ec114e1182e896398b2f27cffe5bccbc73c715d8613d91aeb08a8d9a902bd3628508ef7b9cef5b44a4956e034e26be5c0f1e00a7437a4a293074877b3e56cb78fe9fbfa3908a9c24400d0e43df868f734aaf55889c100511a51806dd9c740a2ebaf17907e25711b7ea6ef8fa9289cbfa41da1040355fb8937b143a3d19ac0222edba281d4349c2763eeee8d2c1182b161d90f009668712959c52f474cddcd16d1a3a29703d39fd1ecabc3cdc242fada16357756b2cf973c88046913a837758dd2fc312800b69d40a231ad1ac911f24d2c12d61ab72044e18e3e9331dadab633c019640b9f8fd549dcefb1886d8ab50ba1814ff76f70beb2aa25f0aac8c77169ad5a7ead4f93997b213302c2c92a464a9179f95caa6e56ee1a31cf8a1a1bf2347f3d8bebfe77595fd8627f51482a1efbdf5eb7e19267c7ba5b35dcfcd024466fce64074ff67ef6add84c74e1bb130e17a82928c0b1161fb5539b18ba8fbdbd88bdfed30bf51295ed826b5680cfce9094d767a5a74de5e3dd8407581cc0eed674c414be", .Okay}, + {.Shr, "3b5ac6e9a11cae85752d4171d3a55be164c2d585519351f43d08fe4d8d5912049d7cdb538fffd0f8eb4df07a0b2cab4516876fb12834a1a5a09d4d3d076c111e882afea3492ea8bb879e1db2af5fc2aa63b216dbf8c3456b19df44d143ef168283ff2ae3e6bbf5ee7fccf1cea9a0fd0aa9d9b2450a52c15b38d114461f1e29ad45d241a4bd93b1fdf266bb4995c812461ebe008e5d199aae1a3ac49c9f7855867aa73283cc227882a071d7fe041fab72447120c909ff366828f6ac83028d12ca0ba7c329f62486fb466721db7a7e9def1835adae2fa19c550446a21f14b4f1b6a41f5f64f05bce1dc4da6072c3fd5ec7ec1cc5ecc88ec065ef3c2e409d10e93f5dde3528e2c3c3e71268c10949c99f9b35785c4ffa5da0349975dbee9a7f72d493e961fb66c65a87f2824000ce5da54f103f606f5e63bba54e539f0be0133010378c42a187c93ba86cfe11084df42b79ccde8744871cdf2a7c0e76d2f88f8d4a3077abe76b2a3904d637c5f520a6208c5116185706701a5c258e6de36d012c565e41fd853bb019be1b0c991fce4584c07e9b4d92e3178bf43d67557e2cc45fc3bc2c6f88d08432c64f0b5acc831b3213d01ed36422e1d8fccdde16c31f080398e30d4358e411abe696159a1aa3949105a3ecf3fcfe99646bfe4372ed53dc6a834467cd11c293ff81e00c3a66ecd3f20600629d9adaa13dc862609897ba1ea4a1", "b4", "3b5ac6e9a11cae85752d4171d3a55be164c2d585519351f43d08fe4d8d5912049d7cdb538fffd0f8eb4df07a0b2cab4516876fb12834a1a5a09d4d3d076c111e882afea3492ea8bb879e1db2af5fc2aa63b216dbf8c3456b19df44d143ef168283ff2ae3e6bbf5ee7fccf1cea9a0fd0aa9d9b2450a52c15b38d114461f1e29ad45d241a4bd93b1fdf266bb4995c812461ebe008e5d199aae1a3ac49c9f7855867aa73283cc227882a071d7fe041fab72447120c909ff366828f6ac83028d12ca0ba7c329f62486fb466721db7a7e9def1835adae2fa19c550446a21f14b4f1b6a41f5f64f05bce1dc4da6072c3fd5ec7ec1cc5ecc88ec065ef3c2e409d10e93f5dde3528e2c3c3e71268c10949c99f9b35785c4ffa5da0349975dbee9a7f72d493e961fb66c65a87f2824000ce5da54f103f606f5e63bba54e539f0be0133010378c42a187c93ba86cfe11084df42b79ccde8744871cdf2a7c0e76d2f88f8d4a3077abe76b2a3904d637c5f520a6208c5116185706701a5c258e6de36d012c565e41fd853bb019be1b0c991fce4584c07e9b4d92e3178bf43d67557e2cc45fc3bc2c6f88d08432c64f0b5acc831b3213d01ed36422e1d8fccdde16c31f080398e30d4358e411abe696159a1aa3949105a3ecf3fcfe99646bfe4372ed53dc6a834467cd11c293ff81e00", .Okay}, + {.Shr, "90c68fd88a6d390e656821af6b5da88eb9ec3917e7a054f8ce5026174f912807a1e31c81efeb0b3aede567537b6f58f73ba563bb351218bb824ff881c3b0ea28b0f6e6a58153ac409c169deeef2a5ff0c0cb35eab6fadc1ff708949589efd610261906c075e4d35d4f2ad66005e4cebe8bf39f1655ceca74af899632cf2002dbc157a9ab4202caf485c01c7fd54a6e7b8764069b811cd9271cc1fc0b126ef99411099112d2492c13c1dd87a7e7e9880b6eec50f202bd3a9d71176ad2f1692af05fc522cbe0e525051236687a384155edd18ab680aeddda5c5866a5c36dfffd777744a21ff31140b83b03fc42de67c07252d536808b3a4ae55557ad5d774902bbcb26802dd4646949280d972a8bb39ad7aa64ce67a50f8dbac376869b3bdabe21a2282ddddaa92bc58b9394a6816260195420ec8c288afa310e03d689c7364e717eaf4eb477fa83be8cb4e147a066621d0b0609ecb6b2bfd9479111e8a8e4dda837398a4e95fe8cf53d05ec458901043482b41437c91cba09013ead677496be50d3343dd233ed3459ab498cc7db7a62addf802d5950ba7abf92f11bec2ff273d051cce3cf4c3557cabad2d777af91bcdafe35053d590654b3909b89e1db987dd5277620af0879a11ef99f84ed0e2d8dd1431ae89253564ccd5e510187a35977c810a38a08c8f2e47eb8ef6bd27b715c12769f0bd6a2426b47356baae5e9a79937", "1e0", "90c68fd88a6d390e656821af6b5da88eb9ec3917e7a054f8ce5026174f912807a1e31c81efeb0b3aede567537b6f58f73ba563bb351218bb824ff881c3b0ea28b0f6e6a58153ac409c169deeef2a5ff0c0cb35eab6fadc1ff708949589efd610261906c075e4d35d4f2ad66005e4cebe8bf39f1655ceca74af899632cf2002dbc157a9ab4202caf485c01c7fd54a6e7b8764069b811cd9271cc1fc0b126ef99411099112d2492c13c1dd87a7e7e9880b6eec50f202bd3a9d71176ad2f1692af05fc522cbe0e525051236687a384155edd18ab680aeddda5c5866a5c36dfffd777744a21ff31140b83b03fc42de67c07252d536808b3a4ae55557ad5d774902bbcb26802dd4646949280d972a8bb39ad7aa64ce67a50f8dbac376869b3bdabe21a2282ddddaa92bc58b9394a6816260195420ec8c288afa310e03d689c7364e717eaf4eb477fa83be8cb4e147a066621d0b0609ecb6b2bfd9479111e8a8e4dda837398a4e95fe8cf53d05ec458901043482b41437c91cba09013ead677496be50d3343dd233ed3459ab498cc7db7a62addf802d5950ba7abf92f11bec2ff273d051cce3cf4c3557cabad2d777af91bcdafe35053d590654b3909b89e1db987dd5277620af", .Okay}, + {.Shr, "8a2885edc32e0cb7232c84019faabafcf882483a97630637233e749366bf4e8439f33035781551644e96d4bcca0ce05aaec2762b515008cb2a7a9d54162213b21f964f6c91ee77330bd2628c2983ffe95ac3075f84009a124f4305ffb767eb4f9fab35bc1cfde6ac0055989a672b8ec5863b427c7851a3a6694757a0a1c9c0b9bb1794f06235dd751d9bdb3dcd898ee1329c6882d091953490baea6d75a57e8a8c3a438760cbefce4295c5af003c63fd47dce8cbb6ba5db37fb2a7fde9e8f5f007ae16ef43ff6a6f9a13ff83d8621b08b3f67e13ee276826a142af9dc19092f11c3ddfbe824f24af937c761b52e6fdba336271efa0b8ae06e1488a6793c15f0282b87c62f4ac787038affbef3e9819e71c5a75cb616a87c4c2c94fcb311270af83e04f913a90bc5d7427814066d6a6fdab7c57afc42dd3a47c91eefc6cead6b3c57ae2aca27a939af07fcf9b7615304c4fa0aed2d839f91ea2a10d50ca807657eec2499b5fd6dd6d9094cfccaea4a38faae51e3ef77d9d01c7a61d21526d5292757bc1fa438179afcaa1f46812737ab3d993cb4b9ffddff3fe024df47cb74465586593ee1754550c3dabda65730fa898c389e0594a2b1c6bb1aa902656c2e1d3196e4f116ea6c2ab4a882a529f1c58883f25d442baddf70d917bb8ca3df77690c04dd14a4d429e48d0b33743244b87b7a7e97fb7ee878fdb54c91451efb04705", "3c", "8a2885edc32e0cb7232c84019faabafcf882483a97630637233e749366bf4e8439f33035781551644e96d4bcca0ce05aaec2762b515008cb2a7a9d54162213b21f964f6c91ee77330bd2628c2983ffe95ac3075f84009a124f4305ffb767eb4f9fab35bc1cfde6ac0055989a672b8ec5863b427c7851a3a6694757a0a1c9c0b9bb1794f06235dd751d9bdb3dcd898ee1329c6882d091953490baea6d75a57e8a8c3a438760cbefce4295c5af003c63fd47dce8cbb6ba5db37fb2a7fde9e8f5f007ae16ef43ff6a6f9a13ff83d8621b08b3f67e13ee276826a142af9dc19092f11c3ddfbe824f24af937c761b52e6fdba336271efa0b8ae06e1488a6793c15f0282b87c62f4ac787038affbef3e9819e71c5a75cb616a87c4c2c94fcb311270af83e04f913a90bc5d7427814066d6a6fdab7c57afc42dd3a47c91eefc6cead6b3c57ae2aca27a939af07fcf9b7615304c4fa0aed2d839f91ea2a10d50ca807657eec2499b5fd6dd6d9094cfccaea4a38faae51e3ef77d9d01c7a61d21526d5292757bc1fa438179afcaa1f46812737ab3d993cb4b9ffddff3fe024df47cb74465586593ee1754550c3dabda65730fa898c389e0594a2b1c6bb1aa902656c2e1d3196e4f116ea6c2ab4a882a529f1c58883f25d442baddf70d917bb8ca3df77690c04dd14a4d429e48d0b33743244b87b7a7e97fb7ee878fdb5", .Okay}, + {.Shr, "294cdc9bde2025c88fdd0b283fca31f5ce36d9dd4b5f47e987f6a60a04a524a85e6d7c32bda8831bd993b5db92f38d9439d7dfdc80c4ceabf339b7f45e130f69bcf7607901f476370cccbf77807517f17ed2346e92aabdb89bc27320a440912240788338b7f475d3af629ed488cc056857f16375a0a21c1abbc9f2c7bb2a64c7e30660dc1df357b538bb4207d0697c733ee3c526bcf65b2b5de6bbeed007f9b685cc68df91d3e43c410f1e98a0f681f2fb287a229429bc8a956840ececf8af4b979519358c768fc9f802e5bb69f8b4566fee708d4df7010a1d20220849320abc0eec0c593be8dc219b66695ea1060b1b9a777cee74d04efeee505a1b1e1ad8ccb3e3a5fc93e1d533402362aedf1374514173946a6fce9aaaa1ed53a3d4f7ef40001c57bcaa4f15429c7cbce798d6e149ef0452b12f15b67e6f68b75354418367b44bf09d32c072e3c25a7d1830d37686c764042fb835be924685f44b228e9c890259e42fc58e6eaf3fdc11e37afe3855618bbef68bfcf4ac94acf8a4db58f4437ae8930b3f010019b3b992a297dce0323afcf95acc4864e1613da285d5b36b7116de0eed2d690691e317272b4d15bbe328bc3c5312bd6f3e61a09a3952790e5d552b2e9bcf10666eba78e9ddb5541c77756d5e6658853a24037f6a4f11877b25b71b3077f2f3726d3df09cb60c77669a34c84431753b5bcd1ae9057b4d1117e6", "0", "294cdc9bde2025c88fdd0b283fca31f5ce36d9dd4b5f47e987f6a60a04a524a85e6d7c32bda8831bd993b5db92f38d9439d7dfdc80c4ceabf339b7f45e130f69bcf7607901f476370cccbf77807517f17ed2346e92aabdb89bc27320a440912240788338b7f475d3af629ed488cc056857f16375a0a21c1abbc9f2c7bb2a64c7e30660dc1df357b538bb4207d0697c733ee3c526bcf65b2b5de6bbeed007f9b685cc68df91d3e43c410f1e98a0f681f2fb287a229429bc8a956840ececf8af4b979519358c768fc9f802e5bb69f8b4566fee708d4df7010a1d20220849320abc0eec0c593be8dc219b66695ea1060b1b9a777cee74d04efeee505a1b1e1ad8ccb3e3a5fc93e1d533402362aedf1374514173946a6fce9aaaa1ed53a3d4f7ef40001c57bcaa4f15429c7cbce798d6e149ef0452b12f15b67e6f68b75354418367b44bf09d32c072e3c25a7d1830d37686c764042fb835be924685f44b228e9c890259e42fc58e6eaf3fdc11e37afe3855618bbef68bfcf4ac94acf8a4db58f4437ae8930b3f010019b3b992a297dce0323afcf95acc4864e1613da285d5b36b7116de0eed2d690691e317272b4d15bbe328bc3c5312bd6f3e61a09a3952790e5d552b2e9bcf10666eba78e9ddb5541c77756d5e6658853a24037f6a4f11877b25b71b3077f2f3726d3df09cb60c77669a34c84431753b5bcd1ae9057b4d1117e6", .Okay}, + {.Shr, "358165f7567c85aee4955a2dc77e321e7877f39aa69f08a5e9bab5ffc6f65006c0e2972b6f9f8c7bd36431bf5de6e13298c5ec34cacde845f6f29fd9949654d05ee56b7dea31d4eebe77c1723cfd64216eff530fb3be55acd4600d848b91875e187381d013d0ec503c6d68aa717e1d63561a5c4295e45323224de2f46238110c6bc1ca436a5eb72ec8145979b701509fa7cda2deca5c22c18d16e62ef6770a1ee3ccc686a0f716007391f7b2185ae56666c6cf542a38e7edca2a6c15d105822180945556c76b44883e3931b5bc1e231a8df6960bd1d8420486e91bde69b808826629921890309ffc6b447225584b766ddfe096f11e253f0a6497264e08e0417b1f1eb95d312887312ed6b45ca3f8b38277c93660cbf66cee5dac7b64886be7d5232ee68e2f968a0712d2e550702f7a965987f8142e8cf254167e83aae0c790fe71cf1d44e8b7dba81edd947258d591aeaa9a8bc6240caa7cb2df6f2d5296f02bb04a0c79c5ff77178aca8c0d328790fd55856d94267c0faa2f274f11be205cad4e381659adc75788a184b6bfc7ca0916e9f217b2b7127f6ad78b1871a07aab56f4f9b1831cc08675885ff57e9975f4e17935daa101c52b308ff580ec58c791cc8138868585533a2b4bed885115773eba9552e27d36b33aa6d837de6919ab6fee9133ee3404f07f5b0dec0d8b30b8f24a51d371f9da6b470c4be9ebb49fe3136c", "b4", "358165f7567c85aee4955a2dc77e321e7877f39aa69f08a5e9bab5ffc6f65006c0e2972b6f9f8c7bd36431bf5de6e13298c5ec34cacde845f6f29fd9949654d05ee56b7dea31d4eebe77c1723cfd64216eff530fb3be55acd4600d848b91875e187381d013d0ec503c6d68aa717e1d63561a5c4295e45323224de2f46238110c6bc1ca436a5eb72ec8145979b701509fa7cda2deca5c22c18d16e62ef6770a1ee3ccc686a0f716007391f7b2185ae56666c6cf542a38e7edca2a6c15d105822180945556c76b44883e3931b5bc1e231a8df6960bd1d8420486e91bde69b808826629921890309ffc6b447225584b766ddfe096f11e253f0a6497264e08e0417b1f1eb95d312887312ed6b45ca3f8b38277c93660cbf66cee5dac7b64886be7d5232ee68e2f968a0712d2e550702f7a965987f8142e8cf254167e83aae0c790fe71cf1d44e8b7dba81edd947258d591aeaa9a8bc6240caa7cb2df6f2d5296f02bb04a0c79c5ff77178aca8c0d328790fd55856d94267c0faa2f274f11be205cad4e381659adc75788a184b6bfc7ca0916e9f217b2b7127f6ad78b1871a07aab56f4f9b1831cc08675885ff57e9975f4e17935daa101c52b308ff580ec58c791cc8138868585533a2b4bed885115773eba9552e27d36b33aa6d837de6919ab6fee9133ee3404f07f5b0de", .Okay}, + {.Shr, "bd6456e0ec3a8d9299d63fbbdfac1f50d74e06a809672ff00e290f35e674ae6f110a655c1609127cb96c52c4449f171da0844267e575c6cd2709865eaebbfe1a961e193409728db7cc6f27774851ba512836a334c0f48c7a2f8ca529a9aa0f14059dd30c5cdb09fe34d148cdcc2ffc14e6a4114ec1a344c48890b88f12a6c619586b46555c901e44b6d59256fe35d2b76d746a16fd97326cff90ac3859bcc6fd24dbdbc587a3a3b09f9712835a791de7718058f547b2c5d6e64fb66404afb3aa8cc10ae12bb322c0a1d27afa7c0b0171e6f3a1f9001f72a44c9dfcf7e1e123802de2cbdab65ec46a4e5e69e5db27bc0489b7a156be3924fda4995542c8cf0d0cefbfbc90e3967cea01c5676f3c19b705ec321f0e990f2aa6562842fe71b338adf1fe697813bedae91e55638a20062f6d18aa5522c20be9656f2df56b21d06447b3b5b80a2188980a9fedf8c920870e3ae9f06c1cf540484fa029cb91cf736e404eeb2e1c10736026875ab10040d0ebb476e7899f19822ffc8b5830e6ad803205afeaffbb0be211bab9710fb8fd0e54316f3e10ea137a9b6e3d8a5ec55efd93bb91740585abfa97372f96baf6a995122acc1755bd5f5418516a6e86d66434a14d83d2ae86ba19b14b4189293e5847efe49a18f0fb5f035d45b52bf095069e5bdfed4f2b465123fea084542e1ce906afe0a7b3f7d93de4c1f1a6d4e3ed472c89e8", "12c", "bd6456e0ec3a8d9299d63fbbdfac1f50d74e06a809672ff00e290f35e674ae6f110a655c1609127cb96c52c4449f171da0844267e575c6cd2709865eaebbfe1a961e193409728db7cc6f27774851ba512836a334c0f48c7a2f8ca529a9aa0f14059dd30c5cdb09fe34d148cdcc2ffc14e6a4114ec1a344c48890b88f12a6c619586b46555c901e44b6d59256fe35d2b76d746a16fd97326cff90ac3859bcc6fd24dbdbc587a3a3b09f9712835a791de7718058f547b2c5d6e64fb66404afb3aa8cc10ae12bb322c0a1d27afa7c0b0171e6f3a1f9001f72a44c9dfcf7e1e123802de2cbdab65ec46a4e5e69e5db27bc0489b7a156be3924fda4995542c8cf0d0cefbfbc90e3967cea01c5676f3c19b705ec321f0e990f2aa6562842fe71b338adf1fe697813bedae91e55638a20062f6d18aa5522c20be9656f2df56b21d06447b3b5b80a2188980a9fedf8c920870e3ae9f06c1cf540484fa029cb91cf736e404eeb2e1c10736026875ab10040d0ebb476e7899f19822ffc8b5830e6ad803205afeaffbb0be211bab9710fb8fd0e54316f3e10ea137a9b6e3d8a5ec55efd93bb91740585abfa97372f96baf6a995122acc1755bd5f5418516a6e86d66434a14d83d2ae86ba19b14b4189293e5847efe49a18f0fb5f035d45b52bf", .Okay}, + {.Shr, "a9b900ddf405aebfc80ab179c2b073d458637a7b83efed2121f62c52e90f23c871f6b9e3ef3fa16bb1c338e29f465908edb3be4afd83baff8c6c6b76a03c4cc61b7ff6aa61d751c673aef3fc4c0c754fe7213b13b8b65def35b2c7c5ca5d156f446b1670bd06163ec4a50e71da70da14a8b787c083a60e2414b837df310ea795be0b0a219a5738e087b1fcf2bc757455644899799393656fbf5db2d0f9b414b0f17139ffb40b783c4c7756954c5ba314b8c244027615ec3364ac46d4d4cf717f9208ad4bdc55473afc6b31cec8d1e3bafd4fd51001b17749aa79a764b883a1cbfea63ca08347f006c30e95b4bfe39da75efbc28cc5ac3f6f2763a250ac206b84c3532ada86d2bd8f638b430f5a931c2933a8a04e674a3db4b8882a71a474c983d5489f43511321d101e4f3186ccb48bf8c633960710fd6f2d08198d3c5b0e755b3f9534e04dbad9401720b232d30f69be15a2b14299aa74d6125fc7a1183f56047d10e2e7cf32a53384915f3c16ef8863cca771af65dc3fccc39a92ef6c74a2e439255f80e276ced3abde3fb2bde098585b8003ee21b1da714df3b7d0c5bb754b95b2b98790f520013a3aea32de92b53cc4dd83f802653f4f05888458c44426510d074032c7df5381a36f596228b96a37673a6ad94e9271cceedadfce622c5005de419b49f68c856b32864d80c5fbd39756a5f2e7ba3226aaa5e4db808d00ca5", "3c", "a9b900ddf405aebfc80ab179c2b073d458637a7b83efed2121f62c52e90f23c871f6b9e3ef3fa16bb1c338e29f465908edb3be4afd83baff8c6c6b76a03c4cc61b7ff6aa61d751c673aef3fc4c0c754fe7213b13b8b65def35b2c7c5ca5d156f446b1670bd06163ec4a50e71da70da14a8b787c083a60e2414b837df310ea795be0b0a219a5738e087b1fcf2bc757455644899799393656fbf5db2d0f9b414b0f17139ffb40b783c4c7756954c5ba314b8c244027615ec3364ac46d4d4cf717f9208ad4bdc55473afc6b31cec8d1e3bafd4fd51001b17749aa79a764b883a1cbfea63ca08347f006c30e95b4bfe39da75efbc28cc5ac3f6f2763a250ac206b84c3532ada86d2bd8f638b430f5a931c2933a8a04e674a3db4b8882a71a474c983d5489f43511321d101e4f3186ccb48bf8c633960710fd6f2d08198d3c5b0e755b3f9534e04dbad9401720b232d30f69be15a2b14299aa74d6125fc7a1183f56047d10e2e7cf32a53384915f3c16ef8863cca771af65dc3fccc39a92ef6c74a2e439255f80e276ced3abde3fb2bde098585b8003ee21b1da714df3b7d0c5bb754b95b2b98790f520013a3aea32de92b53cc4dd83f802653f4f05888458c44426510d074032c7df5381a36f596228b96a37673a6ad94e9271cceedadfce622c5005de419b49f68c856b32864d80c5fbd39756a5f2e7ba3226aa", .Okay}, + {.Shr, "938101389ed6951ad5f3e4c96a4b0fefcd7371a0a130ff5c71953f4ea5fbc3dc1c5d09b0bab6169a05961de4a94fb60669c72b19ffbbefdadb018a2504cfa4c67a5c64168d380a44f87dfdcaab2408adbc7f988c929fae91391bb19383a7f5f72e0871d0d0cc0b415d9b45914559aa6094ca95f6b084a385c7d2c9336f8d7ed5b786a8b218964b8e4a0fc3396d7cb2bcd512abf3e22896a96b1c3473dd0eab145ab1b2f6626d1dcf61d8a4b45d3baf9f1e640c99fa8050f19f919fda6e8ad226b0ed9d524ca67876efb210ba2b6c1def60dd8d547c91dd9981e43b87be5df975dad4966c71b855538367fcd7a7a87d8c00f40aefcd63fe1169d4a941a7a24514098e7c201822e06681d6adda4f4d05256586495a93180d244d4d274bc4e1d6613dc001a250ecbfd30834a4f22019a3e4765f99107d54456aaa7215479c2d6e857476cbb12eb02b3cd563daa6d42419f73dc82ca9ec572abd7768d32d24d6420d610c5c2c0ab98770fa8a9be278cc66a4b98338d24dc34b6d6b6f441dc470fb0d9bebfdafa536dff72527a6244c0903767658e49fa4f56eea9fe85944c60dfe316320aee158cad6787bb66c281079cae46b3b9022f993cad332cb86023ec5ebc52de1acd2ce44cdc2dafb14423a30ef8a99dfc432f350df62f4dbb86caae7c872aa5cfb38a347f6a62ebb0e4863719773428d2a022ad568af2377a9485d75e56e", "0", "938101389ed6951ad5f3e4c96a4b0fefcd7371a0a130ff5c71953f4ea5fbc3dc1c5d09b0bab6169a05961de4a94fb60669c72b19ffbbefdadb018a2504cfa4c67a5c64168d380a44f87dfdcaab2408adbc7f988c929fae91391bb19383a7f5f72e0871d0d0cc0b415d9b45914559aa6094ca95f6b084a385c7d2c9336f8d7ed5b786a8b218964b8e4a0fc3396d7cb2bcd512abf3e22896a96b1c3473dd0eab145ab1b2f6626d1dcf61d8a4b45d3baf9f1e640c99fa8050f19f919fda6e8ad226b0ed9d524ca67876efb210ba2b6c1def60dd8d547c91dd9981e43b87be5df975dad4966c71b855538367fcd7a7a87d8c00f40aefcd63fe1169d4a941a7a24514098e7c201822e06681d6adda4f4d05256586495a93180d244d4d274bc4e1d6613dc001a250ecbfd30834a4f22019a3e4765f99107d54456aaa7215479c2d6e857476cbb12eb02b3cd563daa6d42419f73dc82ca9ec572abd7768d32d24d6420d610c5c2c0ab98770fa8a9be278cc66a4b98338d24dc34b6d6b6f441dc470fb0d9bebfdafa536dff72527a6244c0903767658e49fa4f56eea9fe85944c60dfe316320aee158cad6787bb66c281079cae46b3b9022f993cad332cb86023ec5ebc52de1acd2ce44cdc2dafb14423a30ef8a99dfc432f350df62f4dbb86caae7c872aa5cfb38a347f6a62ebb0e4863719773428d2a022ad568af2377a9485d75e56e", .Okay}, + {.Shr, "9e3d5bea738241d3feb213de1718f773ef5e82c5c112bdbdcefa007b19463074065243125a10dc30f932a601ae2d2692430495261ab2b85fe902416d8266f15af89e08c61e09b0ef908e2baf84648ef38779a59360549710dee189ae1fa87893340e5d8c4749169180532ab947d419460c727c11d93f5606ef674dbbc96b6d5c7727c228be6619e5c151748dda390b44ec2381906c2b7ceb4a392c5831e7b66ebeb656ee3f83b8a80c2e89511f59eae302d8dc03786191da70b93aca355d06483a72b44a35a96ba84c81675ff5f20a7bc23f716377183caf360ed12b69902cf5def31181dc6d7450902805d8b0930600ccf11376f5f479c72cbb2321a5b15f2d44bda6522322f205735d7aef7340521b551b180965805112d7f8b57278e0e421f1736930b09e98608fe358f647776283961efc51e5329d30710db004ee5ede320e7204462f58abd0d007aa2976e10243b6cf86032b61641cc1ab47eaa5dca7399997a530b71e14d8bdf84d0f671a181bd8db347ebb0c852fa887cdcfea37cbd25e1a04ff4bb15b86594ff13f7b86b43dadf8e9388dc7b2c07cc39f83f89721d869ec2d7a2670e1e719a15d4678e6f5c6bd86608b34db01425c756712b20ad902079f31c4d27011a42159212742a9cb74376cb70f5c47a27057f450bf8e0b04aca5db113f09b58edfb21d493f5b114a0a32f28d1f8dea2cb74c333bf01e4bc0f2", "21c", "9e3d5bea738241d3feb213de1718f773ef5e82c5c112bdbdcefa007b19463074065243125a10dc30f932a601ae2d2692430495261ab2b85fe902416d8266f15af89e08c61e09b0ef908e2baf84648ef38779a59360549710dee189ae1fa87893340e5d8c4749169180532ab947d419460c727c11d93f5606ef674dbbc96b6d5c7727c228be6619e5c151748dda390b44ec2381906c2b7ceb4a392c5831e7b66ebeb656ee3f83b8a80c2e89511f59eae302d8dc03786191da70b93aca355d06483a72b44a35a96ba84c81675ff5f20a7bc23f716377183caf360ed12b69902cf5def31181dc6d7450902805d8b0930600ccf11376f5f479c72cbb2321a5b15f2d44bda6522322f205735d7aef7340521b551b180965805112d7f8b57278e0e421f1736930b09e98608fe358f647776283961efc51e5329d30710db004ee5ede320e7204462f58abd0d007aa2976e10243b6cf86032b61641cc1ab47eaa5dca7399997a530b71e14d8bdf84d0f671a181bd8db347ebb0c852fa887cdcfea37cbd25e1a04ff4bb15b86594ff13f7b86b43dadf8e9388dc7b2c07cc39f83f89721d869ec2d7a2670e1e719a15d4678e6f5c6bd86608b34db01425c756712b", .Okay}, + {.Shr, "77509a45f5c05558a695d8a947e5d9a5caab99095cf59657b633d48c2a164ccccb9fa2da5692c7d42a1d446bdc79c250ba4e47caaba48300770d23758ba641fa9ea0f52fec58a643ed0f9c610145af9cd684a6b286d6eec81a4dd922c408fe138eb4283d4d5f511a66ae78dfd9339de8abf133e48e414646ac6b3feb75bca1c97c4d3c147b2913d94f947f9647216fe9e6b0c0de0a479ea0a55c71d69ada053872f7dbee63ffc4ed19084e772174ad1d0b229dd5d3386c3846d812659d267765c4329adb29d1b23260380a57ff758bf725e184ab0fc8f0b85c922d5bf9c277b1c140851ed3546dbb1baef9c5e736e7d6be7fb7aeee1b7a509f07358e1b691432418113187cf8898e13f3ab9d0471ef38f828052d0af62b1cfaf7734cbc9193005026d984d257d925a1732c47660586502db296ea409cc39a9778f39778bdf63c37ae40fb09fea55da5ab38cb1ba117d58136596e99d6495b75630928a701fb9010073b39756c56427a791367c17b28b06fe2b4114b0fc7a504d7aa4af944dbdf48e08eb4307b028e420c0c50d90307697afb126a3a54e2e1a10b39609e86c116511503020a1a1a1bf9668d6ad1bef328729d29abf98a07799a1dc12680a9f1c5f904a7241a5a38f8e7846e9c57d65713f61ad6058ffaad335ce56060833ba5cee83f60b39d0654ac6f817cba4115a9178ed4d5dd866fd9875615e7083ed6a0be", "f0", "77509a45f5c05558a695d8a947e5d9a5caab99095cf59657b633d48c2a164ccccb9fa2da5692c7d42a1d446bdc79c250ba4e47caaba48300770d23758ba641fa9ea0f52fec58a643ed0f9c610145af9cd684a6b286d6eec81a4dd922c408fe138eb4283d4d5f511a66ae78dfd9339de8abf133e48e414646ac6b3feb75bca1c97c4d3c147b2913d94f947f9647216fe9e6b0c0de0a479ea0a55c71d69ada053872f7dbee63ffc4ed19084e772174ad1d0b229dd5d3386c3846d812659d267765c4329adb29d1b23260380a57ff758bf725e184ab0fc8f0b85c922d5bf9c277b1c140851ed3546dbb1baef9c5e736e7d6be7fb7aeee1b7a509f07358e1b691432418113187cf8898e13f3ab9d0471ef38f828052d0af62b1cfaf7734cbc9193005026d984d257d925a1732c47660586502db296ea409cc39a9778f39778bdf63c37ae40fb09fea55da5ab38cb1ba117d58136596e99d6495b75630928a701fb9010073b39756c56427a791367c17b28b06fe2b4114b0fc7a504d7aa4af944dbdf48e08eb4307b028e420c0c50d90307697afb126a3a54e2e1a10b39609e86c116511503020a1a1a1bf9668d6ad1bef328729d29abf98a07799a1dc12680a9f1c5f904a7241a5a38f8e7846e9c57d65713f61ad6058ffaad335ce56060833ba5cee83f", .Okay}, + {.Shr, "17ba8819b7621c7db68eacf1ca3d15c0938e49373b880391b096072c4c90370a28b4bf4b197883aa594ad647b3b121fb810c4302defedf0796019663e7dd7e31c3b541914ad6ac3f9c284bb806ca2e7d9355c740b94525d2e5185fee888df5aa9d9c79f2fb4ac68b2113e0535254b83cd556e18c13449e5c7675ae973467def258468ab5bcfbb951c1cf5437a5f777720b627a31f9a695e1a68ca6534d3f76af09ea56a48a1a60c5004ef8f9667a0e8de036dec605b549377cca059ad3ca2e9098b0639e331f2390bf553f7160898703f92a46eece76f0c24d55f42844d7ffa4b0d8edb791f326f7c4dcf15e3a0fca6d99030c44007f363b250237d81969535a4a42969adf07dc7d2fe252a3f28216d8267f5f76558f86993a1fea7a01dc700035b534b80ec280ab861a9845e765a7984bdad78f507832bd381104efe3d0a21f2db38230f48c4cf3494738a2b998fa1b08118a8feae5c8432cc4ac4cb01c249b3beb45df0820bac9fde39b47b1216034f40be02de94b8ee12f10254c1c5962d7ac232c75ab9b335d4787fdd749dca6520c43a3fe4f146bd9336d9654edea773dc510fc80ee31eb73abac8bdd75ca4fce3614c492b45072a2cb20cd32e07d9324f63cac2fa3d4dc98fae485088aefafad064906d24ffc0a6c71ebbe193d711d4748030e03d1d01cded3665de388fd8f21948bd84749bc243fd2c089e9ba56be29", "12c", "17ba8819b7621c7db68eacf1ca3d15c0938e49373b880391b096072c4c90370a28b4bf4b197883aa594ad647b3b121fb810c4302defedf0796019663e7dd7e31c3b541914ad6ac3f9c284bb806ca2e7d9355c740b94525d2e5185fee888df5aa9d9c79f2fb4ac68b2113e0535254b83cd556e18c13449e5c7675ae973467def258468ab5bcfbb951c1cf5437a5f777720b627a31f9a695e1a68ca6534d3f76af09ea56a48a1a60c5004ef8f9667a0e8de036dec605b549377cca059ad3ca2e9098b0639e331f2390bf553f7160898703f92a46eece76f0c24d55f42844d7ffa4b0d8edb791f326f7c4dcf15e3a0fca6d99030c44007f363b250237d81969535a4a42969adf07dc7d2fe252a3f28216d8267f5f76558f86993a1fea7a01dc700035b534b80ec280ab861a9845e765a7984bdad78f507832bd381104efe3d0a21f2db38230f48c4cf3494738a2b998fa1b08118a8feae5c8432cc4ac4cb01c249b3beb45df0820bac9fde39b47b1216034f40be02de94b8ee12f10254c1c5962d7ac232c75ab9b335d4787fdd749dca6520c43a3fe4f146bd9336d9654edea773dc510fc80ee31eb73abac8bdd75ca4fce3614c492b45072a2cb20cd32e07d9324f63cac2fa3d4dc98fae485088aefafad064906d24ffc0a6c71ebb", .Okay}, + {.Shr, "3826dca0702db81be70d0f453f5b28960d646b559762f12878cf4a89da5d590975f73075c608a2d569cd31d862ed55c94d9c4c4f49301cd32c0789a269c510443ea042f0c6184f14b8491428f1bdb122483e0bc19b42dc372ed6f4eb2f2854e464726bc7da280e2d5d8b4ce20cd8a06abfd5c22aa9605fa31d39034d3644164980271911bf35b6c53a6612f657b25a54fc7079f458f103fbb57b3b970fd9729cab973b1b970095b520669285500fc092941159307b21b27854f125ac10a6774abdcbb4fb72d02e0e0a6d7534b07e3bb279e88e18ea87b4d838fe51f547406012547b6ed4ffc7b59e3f21eee228701e6c635dda8c2232ed5283a186af65837e8d01d289a4874270b5b51053e3467c212a7dd98f18b92c17521ef45bbe43e4e1d8b907004b49b9357ad3814a18ae47e3726db170ca667c52745dc9c7b4fa72ffe14c8f9765f0d2911199e5c53bd83cf96d63332ea9cd72f9369e5d4270ddaa6b3b089c3e74a0ef68f5e363a71a72edf91614e1517ae4ffae91797defc0862ce8fd3c25c08a69c05a5a044b9a77b247df3fbf926bb2f01b9841df757bc19ae166b25c000370b038d9f731a0243301122b12ac0a523f0528a194af73f0337cd7c275191e44aac9cdbe57bf8a3e60b0303588f973563406372e2b784e83bf1b185c23bc47400edf78094c1d06be81f5f43b8531e2c07332c592a71eaad4f72d904a66", "f0", "3826dca0702db81be70d0f453f5b28960d646b559762f12878cf4a89da5d590975f73075c608a2d569cd31d862ed55c94d9c4c4f49301cd32c0789a269c510443ea042f0c6184f14b8491428f1bdb122483e0bc19b42dc372ed6f4eb2f2854e464726bc7da280e2d5d8b4ce20cd8a06abfd5c22aa9605fa31d39034d3644164980271911bf35b6c53a6612f657b25a54fc7079f458f103fbb57b3b970fd9729cab973b1b970095b520669285500fc092941159307b21b27854f125ac10a6774abdcbb4fb72d02e0e0a6d7534b07e3bb279e88e18ea87b4d838fe51f547406012547b6ed4ffc7b59e3f21eee228701e6c635dda8c2232ed5283a186af65837e8d01d289a4874270b5b51053e3467c212a7dd98f18b92c17521ef45bbe43e4e1d8b907004b49b9357ad3814a18ae47e3726db170ca667c52745dc9c7b4fa72ffe14c8f9765f0d2911199e5c53bd83cf96d63332ea9cd72f9369e5d4270ddaa6b3b089c3e74a0ef68f5e363a71a72edf91614e1517ae4ffae91797defc0862ce8fd3c25c08a69c05a5a044b9a77b247df3fbf926bb2f01b9841df757bc19ae166b25c000370b038d9f731a0243301122b12ac0a523f0528a194af73f0337cd7c275191e44aac9cdbe57bf8a3e60b0303588f973563406372e2b784e83bf1b185c23bc47", .Okay}, + {.Shr, "bca4298830db9bd355c61b1fdc0cf0c1aaad36b8b19df8b34c84b84b21be6953715f958f744621a81d262ef9d0ba57f721c7e650692c2fad466520097de50bd094f5bb7727bdd02a8f5266b47052a9011e3aa385b29e48591a35368e3804677bea9e830eb8bf9dbb5cafae5141561bcc63411eb18cc4d7281802e4379e5fb09680f8b8a24121452aca5b804fe1c411ddb6e4afa69f088c258ceb658392f3d551a1ae4243c6ec2a93059709d3cfd458494f4f59a8dca9f1f0056b00554b8f8e1b6475425c3530e38afd486089609b82fcd5adffd27571f17e860758b693fb83e4abb4bb2bbef0b51b0c75650b980128f72926f8cbfb9db3f3c185e2edb90a5c284a1a7bcdc7ce30bb6e9b61f6b70c63128237c5deb2cc7bb41acd3566f5b1cfa93f8672427a5b5b6c82e9e17ab7cc533108fcf47eb085e55ab79a4b00d08e5c224e30dd96f01a83bcb8c13d7f22704c9c92308f0965110e1caa85d3ae8dd5824487ea5fc82db69aba17c25a2999b95aafccab6284b7e378273672892c6df9335306508400dab6326322bb7c929ee01b8cb6b1a97da74095fc55bd985b1e59a0bf149f76f6b105464ab35e9765b05edf357b6b183b848a54711b57b541dbf7ab5d89e5cbeca40b13b686ab0b496e86eb3fb38acc26571afae2f81841f8e22e561adaa4d2f8c3e0c4c7db64b2f5ce63d981a3be9b6823901d22b21d66707cc48616", "1e0", "bca4298830db9bd355c61b1fdc0cf0c1aaad36b8b19df8b34c84b84b21be6953715f958f744621a81d262ef9d0ba57f721c7e650692c2fad466520097de50bd094f5bb7727bdd02a8f5266b47052a9011e3aa385b29e48591a35368e3804677bea9e830eb8bf9dbb5cafae5141561bcc63411eb18cc4d7281802e4379e5fb09680f8b8a24121452aca5b804fe1c411ddb6e4afa69f088c258ceb658392f3d551a1ae4243c6ec2a93059709d3cfd458494f4f59a8dca9f1f0056b00554b8f8e1b6475425c3530e38afd486089609b82fcd5adffd27571f17e860758b693fb83e4abb4bb2bbef0b51b0c75650b980128f72926f8cbfb9db3f3c185e2edb90a5c284a1a7bcdc7ce30bb6e9b61f6b70c63128237c5deb2cc7bb41acd3566f5b1cfa93f8672427a5b5b6c82e9e17ab7cc533108fcf47eb085e55ab79a4b00d08e5c224e30dd96f01a83bcb8c13d7f22704c9c92308f0965110e1caa85d3ae8dd5824487ea5fc82db69aba17c25a2999b95aafccab6284b7e378273672892c6df9335306508400dab6326322bb7c929ee01b8cb6b1a97da74095fc55bd985b1e59a0bf149f76f6b105464ab35e9765b05edf357b6b183b848a54711b57b541dbf7ab5d89e5cbec", .Okay}, + {.Shr, "2e63dbef7dd73fb8051f0c5d97a3ff1485cc8b397dc40a3418e0a745c9a0efbaf67d082358e496457b5464567bdf5e0c73ac191e2d6f2854f655cc07ab9b2464674ab2d4becff54e2aa65eec5697eecb38611527875b71065770becb6d70326438583b216d8d3d0932521c5338fe358d43227eea4b67ce3251fc41d25752be775769c4787c2c2c6622c171a387afeb8ad075d9afba17e2470964a6c52837b053c43369ec675ec8a38654a5dc03062f7aa3f7daaf927c13f681e785dd94dbd3aa3ad94044bf2d5527a3a6fc0ee6abd5a85bb5ac046eef6c64b34e50e5abaaca96d39d542c3afe2e93119454da134cc3c7321d34758f2179697b618fbc3d1f974dda6ca356a328d68126381e75da22773055ac15340fdbc2d70210c47f6ea591f31fefb853f4e847501079bb3dd9c15ff4dfac8cc3c66782205ba21ddef413772dac427182608e2b23c435985b3e77771541fdcd02c2a8196cf22f3a995f27965db160858ee73be995e4d6ac7d3f9d2400fd161b9772393d14c15d107105a09c8794ca1f7ed77385107ee976029820c874a7e32f7d3a0834e4933e658a60944504726d7af8b22339eba7d428e431a19ce030c656fb59f33b9749514ab1eff604ae92d06ae7475c3454f64990235e4d0ce446a2054ca1357bc555cb2dfde95cc7053d64749e6ff989f37d973c32f75b707d521371c7d4fa3edd35e247586828e739", "78", "2e63dbef7dd73fb8051f0c5d97a3ff1485cc8b397dc40a3418e0a745c9a0efbaf67d082358e496457b5464567bdf5e0c73ac191e2d6f2854f655cc07ab9b2464674ab2d4becff54e2aa65eec5697eecb38611527875b71065770becb6d70326438583b216d8d3d0932521c5338fe358d43227eea4b67ce3251fc41d25752be775769c4787c2c2c6622c171a387afeb8ad075d9afba17e2470964a6c52837b053c43369ec675ec8a38654a5dc03062f7aa3f7daaf927c13f681e785dd94dbd3aa3ad94044bf2d5527a3a6fc0ee6abd5a85bb5ac046eef6c64b34e50e5abaaca96d39d542c3afe2e93119454da134cc3c7321d34758f2179697b618fbc3d1f974dda6ca356a328d68126381e75da22773055ac15340fdbc2d70210c47f6ea591f31fefb853f4e847501079bb3dd9c15ff4dfac8cc3c66782205ba21ddef413772dac427182608e2b23c435985b3e77771541fdcd02c2a8196cf22f3a995f27965db160858ee73be995e4d6ac7d3f9d2400fd161b9772393d14c15d107105a09c8794ca1f7ed77385107ee976029820c874a7e32f7d3a0834e4933e658a60944504726d7af8b22339eba7d428e431a19ce030c656fb59f33b9749514ab1eff604ae92d06ae7475c3454f64990235e4d0ce446a2054ca1357bc555cb2dfde95cc7053d64749e6ff989f37d973c32f75b707d52", .Okay}, + {.Shr, "df412aa295a1515ddd68de02fec595c2537dd5c5e49ea4da3ea41824627a95e64208d91128a508ffec1839da2599037944c4813a9d95e1b9e4644fde5cfa694bdb760fe8b7a89c7a21dd365992814d1a7c15208cdfb7a8825bcbdbfd8282a463c426e0ffb6de57d72254ec2d305786377da3ee60647a977bd45fc17b42eab211955ab38d97fe13ee991a617b37f768a20dc758d5ed37329db721c0094b0eb7b4ca39707ce9cf9b6db6ac22f51e71f3078efc25c306d602cbd9b70beb1643cb959ccfdad694aa2274206e7e8736de5fc8201e3dccd93cba0581c66688639c7502e8b4d6eeebe12199d3dd3152d37097f6103558462a8c40bea2aba8471211d7190701f3cad194ec21eaef98fb5626e70a8bf5fefd75743217946d57e05e96f4f2c69e1350f12b30ff01926dd9b0e2bffd36d86de2c98687e5ecfbe6ab26d064900fe2f05a9b0474b9c3dfd5ed05bc216c2dded49c424e82c2a848549a492d6ac366375e05ed30fe1dbdbfae0854e012055a4ab402009d034fb427fcb37b29e62fb20e0340fe4a071436962d9022c510e80ffef7e5481c1b46a7336b2891d3ea3fabcd35fa3fe39a3cb2a125306696aa70b326482653ae8eab54b30ed733ea2f0772257634bd7333d18361d4b3b91d96d1e6402d37b800e5356c42e1bdb52c986b8e1ec0d238ecb4f3679e6836685814f898b4a5d51ccb455a27ea51a2b3a4a6e4", "1a4", "df412aa295a1515ddd68de02fec595c2537dd5c5e49ea4da3ea41824627a95e64208d91128a508ffec1839da2599037944c4813a9d95e1b9e4644fde5cfa694bdb760fe8b7a89c7a21dd365992814d1a7c15208cdfb7a8825bcbdbfd8282a463c426e0ffb6de57d72254ec2d305786377da3ee60647a977bd45fc17b42eab211955ab38d97fe13ee991a617b37f768a20dc758d5ed37329db721c0094b0eb7b4ca39707ce9cf9b6db6ac22f51e71f3078efc25c306d602cbd9b70beb1643cb959ccfdad694aa2274206e7e8736de5fc8201e3dccd93cba0581c66688639c7502e8b4d6eeebe12199d3dd3152d37097f6103558462a8c40bea2aba8471211d7190701f3cad194ec21eaef98fb5626e70a8bf5fefd75743217946d57e05e96f4f2c69e1350f12b30ff01926dd9b0e2bffd36d86de2c98687e5ecfbe6ab26d064900fe2f05a9b0474b9c3dfd5ed05bc216c2dded49c424e82c2a848549a492d6ac366375e05ed30fe1dbdbfae0854e012055a4ab402009d034fb427fcb37b29e62fb20e0340fe4a071436962d9022c510e80ffef7e5481c1b46a7336b2891d3ea3fabcd35fa3fe39a3cb2a125306696aa70b326482653ae8eab54b30ed733ea2f0772257634bd7333d18361d4b", .Okay}, + {.Shr, "1b64e8d3ff39230439035403ba35b4fe47c094137816aacc55924956e81533524c7c6c12e78e2563ca22e4c6931d1a1cc11c5651245878e0be037043290477cfe73e5d1380ec17b858f691509acd4021b8ab03055f6cf3d9a6fcfd4911542c938717550cdddfb5b883562f4bb9e3d2f238811a6af3952a824596593b10baa40c4842f8bcdf69cb983eb0db756741da579186bac18cf84e84b8caa5f6a04d02aa8e4efe03ee5dc97f1c5dcbe041b66b0c543cb01280947a914a348148164c237abb0760af412e2a6e4c82e1e4989feb8d7cc9ca6323de612dff9b443682e9b96819d257d3944eeacc64edf0836b2a4d981348bacab5bb75eadaf0b59ead81942d3ae10c13b773fb3ec20005d9350de648a75f4a9396194fa2184b50019ee65c8032ac00e9b57a0836eea647444849c5418cb3352dbdcb176acccf3d2ed02397337371419cebcbf1f3ead969b520daa98ae966af6ba101d4537ec01db2466e65b2d71c17ebaa1f7e03f9ad6cf3255233eb0829bee74dc9d1bfaef7d5ed10b2d35519fb96e9edbac69fe33ef8973972fc54f19620b8c65c5e08e2ecd712f6155386bbc6d0862cec5e0e3b7837014eecc973819e0684dba9e60d14285f1640490db54e9214240dea58a635832797d4860c58be3e03c478b1ad79ab38189c892998bc38d1459a45103d73c272bc6eb65095def78dc838e445eb83f8ae6b3aff6181ee", "f0", "1b64e8d3ff39230439035403ba35b4fe47c094137816aacc55924956e81533524c7c6c12e78e2563ca22e4c6931d1a1cc11c5651245878e0be037043290477cfe73e5d1380ec17b858f691509acd4021b8ab03055f6cf3d9a6fcfd4911542c938717550cdddfb5b883562f4bb9e3d2f238811a6af3952a824596593b10baa40c4842f8bcdf69cb983eb0db756741da579186bac18cf84e84b8caa5f6a04d02aa8e4efe03ee5dc97f1c5dcbe041b66b0c543cb01280947a914a348148164c237abb0760af412e2a6e4c82e1e4989feb8d7cc9ca6323de612dff9b443682e9b96819d257d3944eeacc64edf0836b2a4d981348bacab5bb75eadaf0b59ead81942d3ae10c13b773fb3ec20005d9350de648a75f4a9396194fa2184b50019ee65c8032ac00e9b57a0836eea647444849c5418cb3352dbdcb176acccf3d2ed02397337371419cebcbf1f3ead969b520daa98ae966af6ba101d4537ec01db2466e65b2d71c17ebaa1f7e03f9ad6cf3255233eb0829bee74dc9d1bfaef7d5ed10b2d35519fb96e9edbac69fe33ef8973972fc54f19620b8c65c5e08e2ecd712f6155386bbc6d0862cec5e0e3b7837014eecc973819e0684dba9e60d14285f1640490db54e9214240dea58a635832797d4860c58be3e03c478b1ad79ab38189c892998bc38d1", .Okay}, + {.Shr, "ca0d662918d5a62ca3420fcfa817fa8dcc7d46594c369d39c10ce74d1de50803ac5314956cd43be1acc3a59a1eb4bf57f4f31a696db8cdd4d75dd7aa4154ae7237b0d60d1996dbdb8d38738b8febfc22f8161582e75590a10902525a9d6eb7390bf9297d6ee63cf37c37b37f2372a1442d17bab5820e40732a1b8c507f743b4fefb0ec38dda89d4210a7970f238f0fe3e17d23d7a2666b5e2a50f4bd2fc63b79c8aaa2517004ccc4bdbc6923a4eaed2f3e48c4391482826dd93365baf7537fef9839aaeb3a84052e73449bc116bb36fc290cb4b82a1820bbf49e17ac6fa32e6c7fdcf77e843902998ec1e849dcb14b01806d9b8e2d35fbc7a56888a8ab45044dc44416ebd0c6b03ad6fb48d4dcdfe95394c30d8daf35e5ba23f1830ac19df3e8d406ffe09f437f9510b76f0499cea85c2919e9e203935f556e2c58bb0055a62bfd22b1fc4264680dd4e2feea50560144c6cf0b417a24974a24d90c4f7affa96caf56dcfdbdd09fd57a01c0e58f23d503f3b782ad851cbc3ef2a1683ea4772d88c218b5f963561cef4d1492d325c1eb81e213bd285778faa5abbee9afe180730909984cfca7fea8ae201d643ff3e9c9a0ea9026b23f070141d4f6acaacab8b9683d1d08ea0561f52501a5293687ad9bd263c915d8271e1cf8e34d0ef1d626d20896c6c4d27e12cfcab67c70a18db2c33b3ecd7b5896dd85e9cbc78aee65b5000f", "b4", "ca0d662918d5a62ca3420fcfa817fa8dcc7d46594c369d39c10ce74d1de50803ac5314956cd43be1acc3a59a1eb4bf57f4f31a696db8cdd4d75dd7aa4154ae7237b0d60d1996dbdb8d38738b8febfc22f8161582e75590a10902525a9d6eb7390bf9297d6ee63cf37c37b37f2372a1442d17bab5820e40732a1b8c507f743b4fefb0ec38dda89d4210a7970f238f0fe3e17d23d7a2666b5e2a50f4bd2fc63b79c8aaa2517004ccc4bdbc6923a4eaed2f3e48c4391482826dd93365baf7537fef9839aaeb3a84052e73449bc116bb36fc290cb4b82a1820bbf49e17ac6fa32e6c7fdcf77e843902998ec1e849dcb14b01806d9b8e2d35fbc7a56888a8ab45044dc44416ebd0c6b03ad6fb48d4dcdfe95394c30d8daf35e5ba23f1830ac19df3e8d406ffe09f437f9510b76f0499cea85c2919e9e203935f556e2c58bb0055a62bfd22b1fc4264680dd4e2feea50560144c6cf0b417a24974a24d90c4f7affa96caf56dcfdbdd09fd57a01c0e58f23d503f3b782ad851cbc3ef2a1683ea4772d88c218b5f963561cef4d1492d325c1eb81e213bd285778faa5abbee9afe180730909984cfca7fea8ae201d643ff3e9c9a0ea9026b23f070141d4f6acaacab8b9683d1d08ea0561f52501a5293687ad9bd263c915d8271e1cf8e34d0ef1d626d20896c6c4d27e12cfcab67", .Okay}, + {.Shr, "3a66b6f254dad4c0c579b458658d0b1ed7826819db20dfbcc7df22371a262fecd9b04e83555fadc2c97b941ae0df043a627e7957d9cd732e0df1dd8e4e9c266627277bd342eb5618ebefb0eeb3643aa50e6a8805b24ff90884062a7ef364cb415de5b2bfdf669ec7f72a2f71cdaa499487c2e8d54395881fe1b39d862af6018c30c6ff45a892cfa0d07cbbce71bf8816874766fd8d0925726d073241ab833374cbbebb0f8971256ffe8556e79b9ec3f173d80c2a31a44de594001eede9a9dbd7cf5ba7dc97dfc269e8a7744f5d826314e9f7d23107da6cfcd1fe2d3879f3298766ec894b13df240d928ebe28601ab91508a6509321d041c68f93bb28b9fd2237114e3da6c678cb4129da3901b4bd79a241a082ccc536be0d1d10b5c057b997d47bf8786e01140aab6694d90fce3a26ec8efa87366c15da1407d0a00fea63eaab604fede713fe48e7647e4163e611b56e642c80554859295c221026e7d28c2f3b81c470f3886c527f2144318698988be580574c403cb108019e00fc913c792f3bd54b57b7312c2810f84ac859d5503d092d663a84bbbb762588c99a4576756aabd2da7496ad384ade6cd495be30c5be63c31bf6ee35e4b32c18f4ab2249dd95ef53b7deced32296487aab24b405cd8e9d202d343731dd8026232c7b7c822b319d203215bd37c771b82e5bc6fcf3d32e42d2e433459597276137864271ced075f2", "3c", "3a66b6f254dad4c0c579b458658d0b1ed7826819db20dfbcc7df22371a262fecd9b04e83555fadc2c97b941ae0df043a627e7957d9cd732e0df1dd8e4e9c266627277bd342eb5618ebefb0eeb3643aa50e6a8805b24ff90884062a7ef364cb415de5b2bfdf669ec7f72a2f71cdaa499487c2e8d54395881fe1b39d862af6018c30c6ff45a892cfa0d07cbbce71bf8816874766fd8d0925726d073241ab833374cbbebb0f8971256ffe8556e79b9ec3f173d80c2a31a44de594001eede9a9dbd7cf5ba7dc97dfc269e8a7744f5d826314e9f7d23107da6cfcd1fe2d3879f3298766ec894b13df240d928ebe28601ab91508a6509321d041c68f93bb28b9fd2237114e3da6c678cb4129da3901b4bd79a241a082ccc536be0d1d10b5c057b997d47bf8786e01140aab6694d90fce3a26ec8efa87366c15da1407d0a00fea63eaab604fede713fe48e7647e4163e611b56e642c80554859295c221026e7d28c2f3b81c470f3886c527f2144318698988be580574c403cb108019e00fc913c792f3bd54b57b7312c2810f84ac859d5503d092d663a84bbbb762588c99a4576756aabd2da7496ad384ade6cd495be30c5be63c31bf6ee35e4b32c18f4ab2249dd95ef53b7deced32296487aab24b405cd8e9d202d343731dd8026232c7b7c822b319d203215bd37c771b82e5bc6fcf3d32e42d2e43345959727613", .Okay}, + {.Shr, "2563d06ea5b5ca6c8c65ab73cc9a44ca22b89e3e9b0c6919f31d47af1ecf85e115d8b82586ce929ec3362bef4ff0a9580de80a770dc580b381e2a4dad5e6ba329d67985dde01ede7a5847006592b367b42a0882a0446503f9e6c7e825123884f958fe4a0294dd3046ee1fa45ee0a977ae01fc3b67b1509c29cbbebc40b90044007550a637883b7545b60c0e63a26d771734e25f3dbbb12a213dd00f837f5b94ee898ef7761abc432e1e825f53b0adc2cee8c1d09ec1d7499f8939ac5bd3ecad9cf72c0290fef264dd6a5f20b0c01f8060cfd4adb91fa663ecfef905ac3a8187a87d1d20e82ced4438307c1b5f428a6445c4544b7825bc386c706954abe07550ef4ced8bcde7fdf6be78f6b156591e7ea67bfff8dcdf2aa82852afb6f7e78acc7fa56d560a38db455775e1a398d0a3cfdf479a2f30b0ab3eeb6fd675b459a36e1ad0c13862689a0f60c79cbd8fab06340a20dfc9b1e157b11241fdc431273914c42b94707c71dac7bb547dfa04f395ac4659c11ac2df3c178b1d97d886ec6990df6b9c78d05e645a21854ec80779142d7491f7158474efa3d2e8a4b8439e73ee2c87fd2514616c80d9e34e186c63d811c81d8707759d62a01fa00ba655f64c8caca8b65c9ed3454b2e754dcb98461d72024aac18e3372a4a35ab8dced852e1756b5eafc39db42c40831ad60d0f3f7b4c71f72bdd6eee0176581d10be1a528f589", "12c", "2563d06ea5b5ca6c8c65ab73cc9a44ca22b89e3e9b0c6919f31d47af1ecf85e115d8b82586ce929ec3362bef4ff0a9580de80a770dc580b381e2a4dad5e6ba329d67985dde01ede7a5847006592b367b42a0882a0446503f9e6c7e825123884f958fe4a0294dd3046ee1fa45ee0a977ae01fc3b67b1509c29cbbebc40b90044007550a637883b7545b60c0e63a26d771734e25f3dbbb12a213dd00f837f5b94ee898ef7761abc432e1e825f53b0adc2cee8c1d09ec1d7499f8939ac5bd3ecad9cf72c0290fef264dd6a5f20b0c01f8060cfd4adb91fa663ecfef905ac3a8187a87d1d20e82ced4438307c1b5f428a6445c4544b7825bc386c706954abe07550ef4ced8bcde7fdf6be78f6b156591e7ea67bfff8dcdf2aa82852afb6f7e78acc7fa56d560a38db455775e1a398d0a3cfdf479a2f30b0ab3eeb6fd675b459a36e1ad0c13862689a0f60c79cbd8fab06340a20dfc9b1e157b11241fdc431273914c42b94707c71dac7bb547dfa04f395ac4659c11ac2df3c178b1d97d886ec6990df6b9c78d05e645a21854ec80779142d7491f7158474efa3d2e8a4b8439e73ee2c87fd2514616c80d9e34e186c63d811c81d8707759d62a01fa00ba655f64c8caca8b65c9ed3454b2e754dcb98461d72024aac18e3372a4a35ab8d", .Okay}, + {.Shr, "9181e3680ad6dbb0ee41b6db3a92a617bb4b7e44f63471ba885fe492cb48db573258cd20438c944dbc10190575f1e69332fd581a4c2e3351e8b9e5aebdc14d4e4ecfe18e07827096d34ea980f7e44f24181b688bc0c3f3bcb898fbaf22596a534103f85370a28f3aa29a2916cdc53f919a4e4f5d35d33ef7319d4bd929148773c7bfa8ddf797757c222ed4a1e90845d3cb115b7f27fda63abfacf9f803775e3e1c66385b2c1db6a7abe2d7df5754b17a9efa21a6be728d72446b799b4347daee2011c878a97d3632c247f1b63749ae0b90893a7172559455e752805897d101e08e0a7cc7e12a4fc7047db8e83e9624a6250593ced8d9740c50fde99e227cf82c02c0214f202106611943b6762ebc5d18d0a418d994611e0eac5d5605334afbd1d3a37b68b8c7d4eabed335e25edfb711614b47bb89453d919f2e4bba50aa5721cc59b40514e10ddfaecef3a7ef148de240d85fabe76fd54273b2b0e6bf395c8f8a954327b08db9f5dc81e36ab6935af5e8089bb85e69ff3dfe2f30e85ea161f26f7685ea2f5697cae50c10ac3d4f5c8894a9c17c0513d9574af33c8333a220c86863e4f843adc24c21f353d721c43dd27204ee1c6c387a6f49d5855775770971f563436b04321cd2faaa3457f5e561d831110ea1a4585f6f3056739b656110dd2fe3eb9c84e6c0eea79dfb790efdc85fef8e8f716a1d2853712e30a451ec3cc6", "258", "9181e3680ad6dbb0ee41b6db3a92a617bb4b7e44f63471ba885fe492cb48db573258cd20438c944dbc10190575f1e69332fd581a4c2e3351e8b9e5aebdc14d4e4ecfe18e07827096d34ea980f7e44f24181b688bc0c3f3bcb898fbaf22596a534103f85370a28f3aa29a2916cdc53f919a4e4f5d35d33ef7319d4bd929148773c7bfa8ddf797757c222ed4a1e90845d3cb115b7f27fda63abfacf9f803775e3e1c66385b2c1db6a7abe2d7df5754b17a9efa21a6be728d72446b799b4347daee2011c878a97d3632c247f1b63749ae0b90893a7172559455e752805897d101e08e0a7cc7e12a4fc7047db8e83e9624a6250593ced8d9740c50fde99e227cf82c02c0214f202106611943b6762ebc5d18d0a418d994611e0eac5d5605334afbd1d3a37b68b8c7d4eabed335e25edfb711614b47bb89453d919f2e4bba50aa5721cc59b40514e10ddfaecef3a7ef148de240d85fabe76fd54273b2b0e6bf395c8f8a954327b08db9f5dc81e36ab6935af5e8089bb85e69ff3dfe2f30e85ea161f26f7685ea2f5697cae50c10ac3d4f5c8894a9c17c0513d9574af33c8333a220c86863e4f843adc24c21f353d721c43dd27204ee1c6c", .Okay}, + {.Shr, "48d5e3fa81ff191eec295339047ca809faded5e415d35f04135dcfdef43d8a95d831992ae3e3e93af6cc21f7f577964d3bdb02b03e5970ee641e81528839d180dbf32a13b21712a5014c7f07a28cdc3325c2b2384c8a374b054db8e3a44f47e2987b5a310edea4731100724deac3954ffe359ac371a23d6e22ccc232c4d183ece1681a9c65f7d44b86349c0a580fbb295cf18c0f2910b3256e2d7edcac5c56af7f035948a4ba0a7eb2736356d30fdc76fd818a16d1eddc4e129a736683586c762c5785ba0bc0fee5c2a122d9c7260fc264d16e23c18fde6da4fc4ffc8ac6697b17da44839e7434dc79ea2e68095c83e47496e0c631542565caecb2e92bc1b1b6543046fb6729c9f6999da7d815c32626b9bbd8e46d83e05e82c0b612ef5eb01ae9b23f5ec2c874d639d8adada608aa8ac97c5aa25cbe618df0dfade5f6af978ae7bedb8b7b14f11766774c2e23446784ccefce73d4eb4049fa884de6d669db2e2415fcb911bae7bc4ba8945c8772d94ff2f16830027a9ec463069551a5b2a002e485b502a23fa11cbfdf47a02d56ad1f85a53df4a2026b989be157ceb4a638cb533156abe19a232e2b47f690e52ff86ad3086de44db10b71ca695e545a1c3c65a1d28a42c79f46f87f195348b254805b8456524013ceeecd7264e513210f086707891b426ea20c6a3834fb08155a77eeac2caa53e726f8d44f7fe1bd90e88872", "3c", "48d5e3fa81ff191eec295339047ca809faded5e415d35f04135dcfdef43d8a95d831992ae3e3e93af6cc21f7f577964d3bdb02b03e5970ee641e81528839d180dbf32a13b21712a5014c7f07a28cdc3325c2b2384c8a374b054db8e3a44f47e2987b5a310edea4731100724deac3954ffe359ac371a23d6e22ccc232c4d183ece1681a9c65f7d44b86349c0a580fbb295cf18c0f2910b3256e2d7edcac5c56af7f035948a4ba0a7eb2736356d30fdc76fd818a16d1eddc4e129a736683586c762c5785ba0bc0fee5c2a122d9c7260fc264d16e23c18fde6da4fc4ffc8ac6697b17da44839e7434dc79ea2e68095c83e47496e0c631542565caecb2e92bc1b1b6543046fb6729c9f6999da7d815c32626b9bbd8e46d83e05e82c0b612ef5eb01ae9b23f5ec2c874d639d8adada608aa8ac97c5aa25cbe618df0dfade5f6af978ae7bedb8b7b14f11766774c2e23446784ccefce73d4eb4049fa884de6d669db2e2415fcb911bae7bc4ba8945c8772d94ff2f16830027a9ec463069551a5b2a002e485b502a23fa11cbfdf47a02d56ad1f85a53df4a2026b989be157ceb4a638cb533156abe19a232e2b47f690e52ff86ad3086de44db10b71ca695e545a1c3c65a1d28a42c79f46f87f195348b254805b8456524013ceeecd7264e513210f086707891b426ea20c6a3834fb08155a77eeac2caa53e726f8d44", .Okay}, + {.Shr, "91d21422d28ffcc851d4058defda30bd0db176f16ec6ad40a928e3434e96350c6b8c72904092e440cd63c074d956c5c4981e4c7ee4b95e2e7cc352a6e565afda3a8cc5dd092ac9ac093b1f1856cdb75cb51437a0667ddd1404001925da474e0a1b026019f7ace2b14ea015ee7f67a139c6454979d514c58848a0acf7ad45727dd56fe607542adc919ab52c5ac89c51b1fa4b693944e2ce8534d6a09d15003e869df063ee49fb5a9ff4826785bcdd9d5f59d3f4c8c1a36c6919bddae5d51245ae91c6c41ec5036c602d58e361088988527123d401126fca06b59464bec01f2927dba4fb24719131b51142b1fe53613d909e065ef7c69979b7b5a35fc0d1be1f7048fc7daa74306c6dd6bfb383d62f7485cc358e053004190a7a8933299ae275b189fa297a66201f16e36880820f4df282e2f50df96296c1b0a35cc2cd0cf3ffa3fa641f1232be6f07d4559a6971cae28abb6fc5017a05e478525f5684e4e63c0df640b705e482450e6e0ed6de7d84053760fb4b70dbe71f2d0a34dcdd145f1fdf1a65e04d05d6d6a8f086c24290c6c2e759b0cf7163d46bebd4c6170e3e884766914d22426cc8c89adb1e27eef5e3f9fb63db314379767908f91467f56dcd6c2f87bdcae9935f9c7ff5f5f5f97ddb4bbac67b6b2374ae5d6407fdbfcfd7d30674cea4b6e699e62c4645f670eac81e7f3ba68c086624a27377aba3a302ff7e37db", "21c", "91d21422d28ffcc851d4058defda30bd0db176f16ec6ad40a928e3434e96350c6b8c72904092e440cd63c074d956c5c4981e4c7ee4b95e2e7cc352a6e565afda3a8cc5dd092ac9ac093b1f1856cdb75cb51437a0667ddd1404001925da474e0a1b026019f7ace2b14ea015ee7f67a139c6454979d514c58848a0acf7ad45727dd56fe607542adc919ab52c5ac89c51b1fa4b693944e2ce8534d6a09d15003e869df063ee49fb5a9ff4826785bcdd9d5f59d3f4c8c1a36c6919bddae5d51245ae91c6c41ec5036c602d58e361088988527123d401126fca06b59464bec01f2927dba4fb24719131b51142b1fe53613d909e065ef7c69979b7b5a35fc0d1be1f7048fc7daa74306c6dd6bfb383d62f7485cc358e053004190a7a8933299ae275b189fa297a66201f16e36880820f4df282e2f50df96296c1b0a35cc2cd0cf3ffa3fa641f1232be6f07d4559a6971cae28abb6fc5017a05e478525f5684e4e63c0df640b705e482450e6e0ed6de7d84053760fb4b70dbe71f2d0a34dcdd145f1fdf1a65e04d05d6d6a8f086c24290c6c2e759b0cf7163d46bebd4c6170e3e884766914d22426cc8c89adb1e27eef5e3f9fb63db314379767908f91467f56", .Okay}, + {.Shr, "f87432f80314f1c5f1f1ab2f2cf41fd4051b3b738992b315a96744a6fd8593fb84c931226ee0b04c0f7e4838c3aaac7e38133aad481113698d85e9b425b2b257d71191ec9b678633614c76b97b21cf7885ea45a921f0e9c3e86b31c23c07dfd9df9af7a6750ad0db5ff6748011ddccfe6b4ff136da7ecaa942b15789eb8a9829d7936eab2bab7198d7ebc97d818df480026d873fd5aa05707701fd6043df790244316bc4dce4c1a4dc7fad1f19571a4e18bdd79b205062f1da02a7a830dc3a668c6567a336fa042edbde2604e7d8832085879429fc7d57aaceb45f0c5ac3ac600ecbe142474d2f7f14878d8225c8b5a1837a50ef21912f4b0d439f2509115c27f26d12313296604532b42502eacd0eb1e29ad5e265af1eb25f9932881700c550f954119745f51ff6891d08cbbae6e44e1e633fccfd05737def0e834c8ee440156709c9b25b4441fb9a600a5e357b982f938ff351c3f1cdff138befd5e0a3bbb920551ebb53ce5bf7d65845fd0cf812452d308e259298ed4b13de533e240d7b01813b3d27384aa0c191110858df4109f86183a2a073c2f74e26581744e56c9f25f0962486e5318cd60303c5f657234fdea12d95c2c6f5499f7702cb60a9cc1bcf17e9ff0f627271a1b7f7cd2866472628e7b92357a3f473161dcc6e5b520b67a6101a40a257f60e7b1790b2a6186f0860b64a9e283b7c7d397eca3a7d3334bf61", "3c", "f87432f80314f1c5f1f1ab2f2cf41fd4051b3b738992b315a96744a6fd8593fb84c931226ee0b04c0f7e4838c3aaac7e38133aad481113698d85e9b425b2b257d71191ec9b678633614c76b97b21cf7885ea45a921f0e9c3e86b31c23c07dfd9df9af7a6750ad0db5ff6748011ddccfe6b4ff136da7ecaa942b15789eb8a9829d7936eab2bab7198d7ebc97d818df480026d873fd5aa05707701fd6043df790244316bc4dce4c1a4dc7fad1f19571a4e18bdd79b205062f1da02a7a830dc3a668c6567a336fa042edbde2604e7d8832085879429fc7d57aaceb45f0c5ac3ac600ecbe142474d2f7f14878d8225c8b5a1837a50ef21912f4b0d439f2509115c27f26d12313296604532b42502eacd0eb1e29ad5e265af1eb25f9932881700c550f954119745f51ff6891d08cbbae6e44e1e633fccfd05737def0e834c8ee440156709c9b25b4441fb9a600a5e357b982f938ff351c3f1cdff138befd5e0a3bbb920551ebb53ce5bf7d65845fd0cf812452d308e259298ed4b13de533e240d7b01813b3d27384aa0c191110858df4109f86183a2a073c2f74e26581744e56c9f25f0962486e5318cd60303c5f657234fdea12d95c2c6f5499f7702cb60a9cc1bcf17e9ff0f627271a1b7f7cd2866472628e7b92357a3f473161dcc6e5b520b67a6101a40a257f60e7b1790b2a6186f0860b64a9e283b7c7d397", .Okay}, + {.Shr, "c8277967f202e1a02ed312248894050ceb29d0a72aa4403bf0808d81337691b35db83385ccc6b6bd6d043c470ccacdb46e7d77cf20288b891ca049d5ca913d0743479ab09c237ba18510a655e32baed725cfae6bd8e4349e4f3a5fc1eeae04ed354da4c7217d01e65242b3af87b2bcd5b9c423507927494eb8f29fdc860149f55ff413e1b7e4bfcb446ee397035cfcffde9a04ef01d662849e7e5f62f2e08eea586feb7d47b6a66a5abb532b561a94ec0425f4db97e8135b4a96fd22116f07ed192c854f615856d8ce5d4fde7e9ffc2ec97d07b18d6babc322e39c86cfb606a32507a0e605563988b454039a666150131b05db780e98dd0ec9d79ecd5679db360f075e47d6ecf2f95286197d775cdd497701463aa6f997e4fe9511c01621b9c14a3b21b17560d81cbb2b3858e8aa2a40fc863af178f096d75121200448c635b9f23b9adb47830f917aae3d0f7a6a60e8c6c4308b4a3ffa72a75a016a5fcbdd6d128a94d8f3c297e57f715d69fc0e62d7b0dd17cb215c9074f4faa20767e00e5fc11b5a6e6c64847f912e45c84a4faa79da76c532a04b26018749753189a6197696918f2a8e95a1b3921084b6281a56c488854e51bd865728c7e50cbfb785d49e1f2e97b10f41b624d0c80b1a796146cb70bce6f3b22ae52ab030695a9da9ccd6fa62ee5c532fb028fef9082497567245f5c7b1d671b07cc76168734c34626a78", "b4", "c8277967f202e1a02ed312248894050ceb29d0a72aa4403bf0808d81337691b35db83385ccc6b6bd6d043c470ccacdb46e7d77cf20288b891ca049d5ca913d0743479ab09c237ba18510a655e32baed725cfae6bd8e4349e4f3a5fc1eeae04ed354da4c7217d01e65242b3af87b2bcd5b9c423507927494eb8f29fdc860149f55ff413e1b7e4bfcb446ee397035cfcffde9a04ef01d662849e7e5f62f2e08eea586feb7d47b6a66a5abb532b561a94ec0425f4db97e8135b4a96fd22116f07ed192c854f615856d8ce5d4fde7e9ffc2ec97d07b18d6babc322e39c86cfb606a32507a0e605563988b454039a666150131b05db780e98dd0ec9d79ecd5679db360f075e47d6ecf2f95286197d775cdd497701463aa6f997e4fe9511c01621b9c14a3b21b17560d81cbb2b3858e8aa2a40fc863af178f096d75121200448c635b9f23b9adb47830f917aae3d0f7a6a60e8c6c4308b4a3ffa72a75a016a5fcbdd6d128a94d8f3c297e57f715d69fc0e62d7b0dd17cb215c9074f4faa20767e00e5fc11b5a6e6c64847f912e45c84a4faa79da76c532a04b26018749753189a6197696918f2a8e95a1b3921084b6281a56c488854e51bd865728c7e50cbfb785d49e1f2e97b10f41b624d0c80b1a796146cb70bce6f3b22ae52ab030695a9da9ccd6fa62ee5c532fb028fef", .Okay}, + {.Shr, "bc1b2bfdbb41b1fc33b0f9cdcf4ec141dfbbdd790f0b124eca182485bac89b981b576653fc5c83cefb5361c70ce8cc90e20365b9118c106cc3d466381402df47a4f7c94318d41d45cb8e6c1766ecadeac0b8351c62c805c3d158dfa53c63ecc4f7f3394f0e4fed52c217083e8f1df9d70bb6d32ea7131d92ad5095a97e16141a3a171e54caa1e2f55879f493352d5c95221ce559c1aa1300c6cb87404c7bf266896857d04736479c28ecbe6533ede4be69606666b85e3b60139328112d752a195b7e90a5fb997ab2073f4a69ba926f114564321c8360aa7f0cfc5c17284a998e018de958aa80c9479c124d94f15690df414ec8464501674491ef6c662c6419f49b33f7e04591462c0b6399b77ffeb72b445d4f3bd234b80c0edc07e7fdee40dd830ac3d35ab180663906dc79c31e539f235f6125c8a6cbc3d625796e690af48f70d45ce60b6961b752d75750b9cb187600d1f7157c8404ce64969ea4be1ca35ce3e964268c43db88dea4d21ac11c79bd5f19e7af6e17afae6f7d76bd889eb1c26d18fea233e75dc6be50179017f6d8774eeb9ab631c4d24fc2ba3be951b0c226a3c3245e259db41c6d8acd4091bb047bc70458021a3ad45b49aad83062283cf92fb04cb8eba1a64868a820a685fba78c5dc78352ed2e9f530a620ccc15bcd4ae15b887da70cc3dced6843ad0c431d4ee06cdbc0af09c30f12b87f54757459e31", "0", "bc1b2bfdbb41b1fc33b0f9cdcf4ec141dfbbdd790f0b124eca182485bac89b981b576653fc5c83cefb5361c70ce8cc90e20365b9118c106cc3d466381402df47a4f7c94318d41d45cb8e6c1766ecadeac0b8351c62c805c3d158dfa53c63ecc4f7f3394f0e4fed52c217083e8f1df9d70bb6d32ea7131d92ad5095a97e16141a3a171e54caa1e2f55879f493352d5c95221ce559c1aa1300c6cb87404c7bf266896857d04736479c28ecbe6533ede4be69606666b85e3b60139328112d752a195b7e90a5fb997ab2073f4a69ba926f114564321c8360aa7f0cfc5c17284a998e018de958aa80c9479c124d94f15690df414ec8464501674491ef6c662c6419f49b33f7e04591462c0b6399b77ffeb72b445d4f3bd234b80c0edc07e7fdee40dd830ac3d35ab180663906dc79c31e539f235f6125c8a6cbc3d625796e690af48f70d45ce60b6961b752d75750b9cb187600d1f7157c8404ce64969ea4be1ca35ce3e964268c43db88dea4d21ac11c79bd5f19e7af6e17afae6f7d76bd889eb1c26d18fea233e75dc6be50179017f6d8774eeb9ab631c4d24fc2ba3be951b0c226a3c3245e259db41c6d8acd4091bb047bc70458021a3ad45b49aad83062283cf92fb04cb8eba1a64868a820a685fba78c5dc78352ed2e9f530a620ccc15bcd4ae15b887da70cc3dced6843ad0c431d4ee06cdbc0af09c30f12b87f54757459e31", .Okay}, + {.Shr, "47c070c5516e300d0e079dc268e5ed03e0c29b8477bb23bfaa396b6588398ad2852043daf3a89743cfd9d6f6fc54321ca938a98f34a322fa4a708b96c1184e731c79e82e47d167a93ad3853dd46d636790e4ff21176feeb5cb7a86acae37fb76844824771fd7138ddb37e7c431b6b5490e3c9354e3cc3c727d88200eba5dee81998e9b7e6bc6931b40054f423694b736365a2ea9ecccccdcdabb383a83caed388b1db3d8fd78ebc99e49e04d0c0fc71dcc5e814b575e3075649453c1ce00286ee2823fcf8ad53d028251278a49d23ee654abede0ec2bc20c16159bbf02e8b473d8ae1c04544ce909c11267d1a52e8582f5cc7617b109e59c4d62cdbd7c860ff3786f20d7cef9eaae2f3f40dbd69d02801bc424b4f687712671698d1bc08e785a7099cd296bdbab6f09a3782d2c25c7808dd7878efd1c916513498f1d84e372df34b79088a047f958021f3f9c45eed3bda08fdc9a1524ff621b895d1c7b60c0ce77545d9e345eee199e50abfad107d6cebc1f3b42429820710d50e273dc1ec5cba1f80f4765ab664e106ab4d9b1f66132450eecc37adaa39cbd4f3808d9e103c52604ebf61f0e6a7684601bff251efc72ab7adbc5e3ad5530290b134adb6abce48732775cbf7533e9588446f84f99537353b19b22fae166f137618e2a46b4200d433a2941b4e92de3068e4ddaebd7f9777c0bc50b0027e2b1c35b8bbb101ec02", "78", "47c070c5516e300d0e079dc268e5ed03e0c29b8477bb23bfaa396b6588398ad2852043daf3a89743cfd9d6f6fc54321ca938a98f34a322fa4a708b96c1184e731c79e82e47d167a93ad3853dd46d636790e4ff21176feeb5cb7a86acae37fb76844824771fd7138ddb37e7c431b6b5490e3c9354e3cc3c727d88200eba5dee81998e9b7e6bc6931b40054f423694b736365a2ea9ecccccdcdabb383a83caed388b1db3d8fd78ebc99e49e04d0c0fc71dcc5e814b575e3075649453c1ce00286ee2823fcf8ad53d028251278a49d23ee654abede0ec2bc20c16159bbf02e8b473d8ae1c04544ce909c11267d1a52e8582f5cc7617b109e59c4d62cdbd7c860ff3786f20d7cef9eaae2f3f40dbd69d02801bc424b4f687712671698d1bc08e785a7099cd296bdbab6f09a3782d2c25c7808dd7878efd1c916513498f1d84e372df34b79088a047f958021f3f9c45eed3bda08fdc9a1524ff621b895d1c7b60c0ce77545d9e345eee199e50abfad107d6cebc1f3b42429820710d50e273dc1ec5cba1f80f4765ab664e106ab4d9b1f66132450eecc37adaa39cbd4f3808d9e103c52604ebf61f0e6a7684601bff251efc72ab7adbc5e3ad5530290b134adb6abce48732775cbf7533e9588446f84f99537353b19b22fae166f137618e2a46b4200d433a2941b4e92de3068e4ddaebd7f9777", .Okay}, + {.Shr, "5c50b4c17c86942ef71b71375134739e6bc7c3a811a0eaae270456985fa50e921617c40572d5f73c5b4006c4e796019a600817ce319e515c4792fc242b20a1ccfe4a4b6917ea832c0c980df5b56d5b09c2893fdbd6c6385ea9bdae2e2c38444dc86e24ea1229c518ea0fa2f03ba411419ff62ca3ac9d8397da4e06a061a52de9641d3fa8f7bad6366d493dfc4f71a998a820bda56eba7bf498230a67338acb0c19dc877bef1e40566b386ca3555dfa1a45ba8487eac550a686e0d842f743a9ff910312b4b3beafd2cc89b9dbbdf35304bab1e1f5e01a6b71834ef28f5ec9549f9bd483b86d894fd109536728f8e2fb0a7d12b84755c7a8729ce1db27840b2d96fa300060b24e2e7bf47df7ff5fe33b8b35d1603288ae765d3b66b20b4d800f794611355c00dd14b6d366cc92c71b860c44f6cbe02871dad5f9d676e64b9de72eec835f219aa3ffa2096d82ec88840e00d3a4bc117d062c57e6fe266a4c0a8ccfd4daef7e01147edebca122276bcc542634567296994157263bcac34641cc58816d41873d902f28f21847071ce3dc5ee88063251fc29900c70f04fd2857f1face9926baeff204e817f975d80d4733033611a04e2dec2d8a22e6b89edb96c0fd12be1b23ad88f4737c5dc1ecf4361b8fb2a6079e1d867aa9394eb97c0b0a4a7763ca6fe0b20acf3d574db072623cf07c5024035b8b95b2f0d74b68e95b4fabb065", "b4", "5c50b4c17c86942ef71b71375134739e6bc7c3a811a0eaae270456985fa50e921617c40572d5f73c5b4006c4e796019a600817ce319e515c4792fc242b20a1ccfe4a4b6917ea832c0c980df5b56d5b09c2893fdbd6c6385ea9bdae2e2c38444dc86e24ea1229c518ea0fa2f03ba411419ff62ca3ac9d8397da4e06a061a52de9641d3fa8f7bad6366d493dfc4f71a998a820bda56eba7bf498230a67338acb0c19dc877bef1e40566b386ca3555dfa1a45ba8487eac550a686e0d842f743a9ff910312b4b3beafd2cc89b9dbbdf35304bab1e1f5e01a6b71834ef28f5ec9549f9bd483b86d894fd109536728f8e2fb0a7d12b84755c7a8729ce1db27840b2d96fa300060b24e2e7bf47df7ff5fe33b8b35d1603288ae765d3b66b20b4d800f794611355c00dd14b6d366cc92c71b860c44f6cbe02871dad5f9d676e64b9de72eec835f219aa3ffa2096d82ec88840e00d3a4bc117d062c57e6fe266a4c0a8ccfd4daef7e01147edebca122276bcc542634567296994157263bcac34641cc58816d41873d902f28f21847071ce3dc5ee88063251fc29900c70f04fd2857f1face9926baeff204e817f975d80d4733033611a04e2dec2d8a22e6b89edb96c0fd12be1b23ad88f4737c5dc1ecf4361b8fb2a6079e1d867aa9394eb97c0b0a4a7763ca6fe0b20acf3d574db", .Okay}, + {.Shr, "d9ec59f17c854d2b2229eedc46e23116b2ecafe6e4a699ff678ae8e53001510268343d91677774e4829af556fb95a5359edbfbf89b0fa827392be3825100c2b8961fae20cf57bd25d17223ec3bbf46de1c263bc342c60ed942597cf2708a7f7b8a3aff7db2a014b85822d16cecffc5a1c6782e31cf53d4ae094b1f10dd4b212b3b4f1cff685ab316df11c28e88edce5a3e0c316eec15266c8f4fba076a0104ecc9b3bd5ca64728f23dbd109416c584fe45dd54c74eebe75613bdf634a9990f868e7248880abc28f5ee23b2f129335acc62eb1604d390eb1139b1cc3a13f6aeeeaecccc65a4223486e066c0caf65286c8971bf2c7c325c6d7c4cfba4a7d93fc80c3949ff0873acf5fd0bc968844fa1dd21d13016c3a16fb9c88d58b26a3b8bcd88bc0ccc76ecc3c9087e3563b539441241427bebb1dfcf398a9175c735106f183d23568f2db7380c00a8c92b455fd8429edc5e21ee1aece9bfcd79f22530579d1492cd4c9d02facbc24f8b1098ce2460b3ae3694147586a64942f65f59453bb4e2eee8bef9485eeb79211548e95b4bdd25645bc79738189dfe80f7410a16d9eb9a702a5f3dbe9c74c23371f2232a6ef0c73152b44c39d4ad4c03679a20785cc941996f61d422c3f663de67fc8dbb67a1829e3e7599365676ac0c7a6a7e653e5559e304dafab2012ce75a8c9c9d206b9d3900ad1f5da7f689f92dabe95b769c0c2", "3c", "d9ec59f17c854d2b2229eedc46e23116b2ecafe6e4a699ff678ae8e53001510268343d91677774e4829af556fb95a5359edbfbf89b0fa827392be3825100c2b8961fae20cf57bd25d17223ec3bbf46de1c263bc342c60ed942597cf2708a7f7b8a3aff7db2a014b85822d16cecffc5a1c6782e31cf53d4ae094b1f10dd4b212b3b4f1cff685ab316df11c28e88edce5a3e0c316eec15266c8f4fba076a0104ecc9b3bd5ca64728f23dbd109416c584fe45dd54c74eebe75613bdf634a9990f868e7248880abc28f5ee23b2f129335acc62eb1604d390eb1139b1cc3a13f6aeeeaecccc65a4223486e066c0caf65286c8971bf2c7c325c6d7c4cfba4a7d93fc80c3949ff0873acf5fd0bc968844fa1dd21d13016c3a16fb9c88d58b26a3b8bcd88bc0ccc76ecc3c9087e3563b539441241427bebb1dfcf398a9175c735106f183d23568f2db7380c00a8c92b455fd8429edc5e21ee1aece9bfcd79f22530579d1492cd4c9d02facbc24f8b1098ce2460b3ae3694147586a64942f65f59453bb4e2eee8bef9485eeb79211548e95b4bdd25645bc79738189dfe80f7410a16d9eb9a702a5f3dbe9c74c23371f2232a6ef0c73152b44c39d4ad4c03679a20785cc941996f61d422c3f663de67fc8dbb67a1829e3e7599365676ac0c7a6a7e653e5559e304dafab2012ce75a8c9c9d206b9d3900ad1f5da7f689f9", .Okay}, + {.Shr, "1a97aaddaad799fa7854bc475c8867d647eb838b7c53371a92bd20bcbc7f4516dde5b43dd697d87249e04365621302047cb6d70a6990efddfda38f8e90bc5b1ec61b858111917c82a5d0c147eb4900d9fe60ea8f8b8654cb8f81aff5ec6804f862afd2614e5684314b12629c8806ae562c5bca59a00b7004a6227deb5d429d821aab93d5efcf474c52136f0ea8a6854b33bd13092807c56039e3cb368c74f083606ec56e2a3dc83fbb53fb671fcb6992f711b0d639d6e1287f9531f860363e5b5c37017db6799ee782d26bfc9613f8b22f5641205eaea3b8b273383b68631be18d40dccc5766d90aff5c976230f61eafd6262c8d5e8efb6881eb0a443a8f1b57c65ea6718d845333dd007971d4b4839c5fa74d02bda0ff7899193fe7992ecb852d0d03ac047ee534dd020c6c443ff49aac3151480f115472a2b0d77d43410da95b8c9b3d56a6d508bea429728fc321624ce154bd91d9b0fbd558ec442fb6003213a0f4768c59757d08dee2bdfb344e6710ead99f447af25810a8c381ab62bbbbed5115532e31db851696b4ed2b66fe1ea542f2fca03f00239d750cc5210328f5fb8d95aee639e9002bfb4fc6b244e743c7ebd898efa1b8f31f39c57899e342ee0ea3f85db6edee89c1d726d725938269dd6268e969bcadb851e9b13e3a049e1479590c886e1696f1168c4b47a4d101afa35be3f68218285b358d2c9b1513f36e", "3c", "1a97aaddaad799fa7854bc475c8867d647eb838b7c53371a92bd20bcbc7f4516dde5b43dd697d87249e04365621302047cb6d70a6990efddfda38f8e90bc5b1ec61b858111917c82a5d0c147eb4900d9fe60ea8f8b8654cb8f81aff5ec6804f862afd2614e5684314b12629c8806ae562c5bca59a00b7004a6227deb5d429d821aab93d5efcf474c52136f0ea8a6854b33bd13092807c56039e3cb368c74f083606ec56e2a3dc83fbb53fb671fcb6992f711b0d639d6e1287f9531f860363e5b5c37017db6799ee782d26bfc9613f8b22f5641205eaea3b8b273383b68631be18d40dccc5766d90aff5c976230f61eafd6262c8d5e8efb6881eb0a443a8f1b57c65ea6718d845333dd007971d4b4839c5fa74d02bda0ff7899193fe7992ecb852d0d03ac047ee534dd020c6c443ff49aac3151480f115472a2b0d77d43410da95b8c9b3d56a6d508bea429728fc321624ce154bd91d9b0fbd558ec442fb6003213a0f4768c59757d08dee2bdfb344e6710ead99f447af25810a8c381ab62bbbbed5115532e31db851696b4ed2b66fe1ea542f2fca03f00239d750cc5210328f5fb8d95aee639e9002bfb4fc6b244e743c7ebd898efa1b8f31f39c57899e342ee0ea3f85db6edee89c1d726d725938269dd6268e969bcadb851e9b13e3a049e1479590c886e1696f1168c4b47a4d101afa35be3f68218285b3", .Okay}, + {.Shr, "3be866f368ae04fd6cff077b2388ebb8dfbee53477a5fe045605a60f06407da381a8b5c2c86e098cfc3cbd63041ee535085d9b8d823e880788dd2f82a8fe612b881868de7dc36b05b22d78cc74c8214719a20354d34afe61554c3fd5f697d080159d9be370e281c2e9cc48e0aa53a84b88cc855fa5ccb93ba513778c4db2ed6afa44afb3647ca6099ed60ba5e41ab93cf45195c54489391083af9c33d4b3cca89bcab3561dbc6025235635bd63daf1e17eaf0b30edc391e676523af7261f39f88d0cca064c5dc2369e7dd82ab62ae2fe95c56010f990102bf9f81ce361f0e34e6d873ebe8568dd20a02c0a9d9fcffb098c9efd26213d8879d7614e153f228b1b2a3ace0252e05ef71ecd1b39163ed6250b924e492157650a9fb82df10d0fdb51547f0b5aaf5dce2415a96d1352709c2b8a481b5c2c68399eb2527935f03c945b59ea2c11ab37d03c29d4ea5e62fa4950a74698a171d2d99b1bb261450c7ad8f5fe8895801dfa7bf1a5859ff9839211765bfcea60afc7b9e58990e0aae6c3b79ce6b8c36eb3afb11cb6fa78d06e7da1a914329b3d48bc9c098927d2b5322711a3e69f8311099340bd90dc1f500a1604f7181bcf680d33cf759ce4a2fdf0fa1addcc6eef8c2a9c58a0f4f591bba5aadbb466ab500fcee612dda71bafa3a65475aadd56ffe99b54eeb23b5258972d5d4119d5b0d94b5239b0d4b63f238c8346faf3", "b4", "3be866f368ae04fd6cff077b2388ebb8dfbee53477a5fe045605a60f06407da381a8b5c2c86e098cfc3cbd63041ee535085d9b8d823e880788dd2f82a8fe612b881868de7dc36b05b22d78cc74c8214719a20354d34afe61554c3fd5f697d080159d9be370e281c2e9cc48e0aa53a84b88cc855fa5ccb93ba513778c4db2ed6afa44afb3647ca6099ed60ba5e41ab93cf45195c54489391083af9c33d4b3cca89bcab3561dbc6025235635bd63daf1e17eaf0b30edc391e676523af7261f39f88d0cca064c5dc2369e7dd82ab62ae2fe95c56010f990102bf9f81ce361f0e34e6d873ebe8568dd20a02c0a9d9fcffb098c9efd26213d8879d7614e153f228b1b2a3ace0252e05ef71ecd1b39163ed6250b924e492157650a9fb82df10d0fdb51547f0b5aaf5dce2415a96d1352709c2b8a481b5c2c68399eb2527935f03c945b59ea2c11ab37d03c29d4ea5e62fa4950a74698a171d2d99b1bb261450c7ad8f5fe8895801dfa7bf1a5859ff9839211765bfcea60afc7b9e58990e0aae6c3b79ce6b8c36eb3afb11cb6fa78d06e7da1a914329b3d48bc9c098927d2b5322711a3e69f8311099340bd90dc1f500a1604f7181bcf680d33cf759ce4a2fdf0fa1addcc6eef8c2a9c58a0f4f591bba5aadbb466ab500fcee612dda71bafa3a65475aadd56ffe99b54eeb23b5", .Okay}, + {.Shr, "ba476c6cd817d699608eca9699a7a90631fb3d223aaa7fbef42ec0f42784955985f296399e9a8a561f2920f583b55e3df4a420bbe0a2491df940e4e2d7cb89be6277be6987ef0b9614533fd54c82a0806a734c66138dff7d7f4f68549926cedf2308752a5b0495d3ebe90aafe5da28cb66c404cf99a379e082b082a8a368d41b1e0790f8002faf838d0fb317c587cd6ff61c685bf68b2e1d6555e55e479afa2053bf594ff9a66ac5d814c9b1e32700d07407db018e8a3be77d487b583fe1818f126294707f962670c4d1bfb247990c77b7f0e31b13505bac195192fef5d94c05f58a24bbf3d5e92512c703dd10dcfb961c7c6c492ac6eafd221be5897b8192fd62dfa93e54ad47bd00a67a12fd7a3c0f4845038d67415907e90592b4dec578d878cb3f6584c8416512129062815b4244c4362d1a51233b0b25ac1b187af59660fe5dfd83dcb63f61b3c066d0ebf977db00932a025f076cfb014550eb91ceee5541ccf909fc21925a2c8eed751b58ab8d7d5541ed04441451fb4db7660c1240b5459b334d0c65ffb4649731a671b50ae778c765b0517d106ddacc373f2af26fe91fe63c780ae19555eafa4f3cf603e4a13289f8c41aa51ac8e35d304fe03ad979a6642654ec61c3f572499950dc3b7af11a71b5ad520e8e365bcc5550318c3ffa3f53077fb5e8cfacd7a4f54423c3b95d5a4fa1f4b4b1db696fdbbe80e72be45a", "21c", "ba476c6cd817d699608eca9699a7a90631fb3d223aaa7fbef42ec0f42784955985f296399e9a8a561f2920f583b55e3df4a420bbe0a2491df940e4e2d7cb89be6277be6987ef0b9614533fd54c82a0806a734c66138dff7d7f4f68549926cedf2308752a5b0495d3ebe90aafe5da28cb66c404cf99a379e082b082a8a368d41b1e0790f8002faf838d0fb317c587cd6ff61c685bf68b2e1d6555e55e479afa2053bf594ff9a66ac5d814c9b1e32700d07407db018e8a3be77d487b583fe1818f126294707f962670c4d1bfb247990c77b7f0e31b13505bac195192fef5d94c05f58a24bbf3d5e92512c703dd10dcfb961c7c6c492ac6eafd221be5897b8192fd62dfa93e54ad47bd00a67a12fd7a3c0f4845038d67415907e90592b4dec578d878cb3f6584c8416512129062815b4244c4362d1a51233b0b25ac1b187af59660fe5dfd83dcb63f61b3c066d0ebf977db00932a025f076cfb014550eb91ceee5541ccf909fc21925a2c8eed751b58ab8d7d5541ed04441451fb4db7660c1240b5459b334d0c65ffb4649731a671b50ae778c765b0517d106ddacc373f2af26fe91fe63c780ae19555eafa4f3cf603e4a13289f8c41aa51ac8e35d304fe", .Okay}, + {.Shr, "f306b6876275d3edfd3b66573289b0bb1f756996669c3238825a4affe914d9ddbe767c030d8ca333e176bd8b1f68ed18cd9aba8147d9fac83377f1a0700b254e7b5b8b2b783f30a2f6cedfbf93714c4c458619d3e14e5ec6e938e111ea147855256abbf4019fb074ffbe0eb9587f7837e3acff5323bb5c05418134aaede7172db8e286440100546c84ab3e0ba8124a3a940a9ae87836a902f079a82fd76c3831072c462cbcb1c3bf0c560dad5d686d94385c0ca0952c89a73bf6a952dc0e40ac6bd5c027bc2535d5a3abb9bd3b5f196b17f54541966d721d1bd448405889a2ae8f1aa17530801dbc608eb36d18ba01a2618901cece477ae41e53bdcae2d975903b59c66a2f76d89b68335e5b679aafa6e76034f392c7725baa2ae10dac6b0fe3dbef22de84a1feb95e082b1fb536b54de2703681ded3cdb8d1499e1b3786f4f4aa8382fdf38bfa90fb5670d1acefce2c1852e980cf119a547fa414083c7ae52c6dd43485c2c026137375d70f08e4d4cb4b846d1ee93eb4293d56d177c1476534c1c8cf7468c9db8bee6bbd4854fe711574876b9f0584245101882d5a4c6e2f4b57f67a27e099115450774cdf71bd8f9f3dcac820b190cccc68e0be7ecdd0830a098b40d190efc09614e236e33922011111f749f48558996faa32d5ad26c6afc5250c62bfe82a7abd11c428e64a058006fefd49a83374be126b15ecc72e32c3ae", "1a4", "f306b6876275d3edfd3b66573289b0bb1f756996669c3238825a4affe914d9ddbe767c030d8ca333e176bd8b1f68ed18cd9aba8147d9fac83377f1a0700b254e7b5b8b2b783f30a2f6cedfbf93714c4c458619d3e14e5ec6e938e111ea147855256abbf4019fb074ffbe0eb9587f7837e3acff5323bb5c05418134aaede7172db8e286440100546c84ab3e0ba8124a3a940a9ae87836a902f079a82fd76c3831072c462cbcb1c3bf0c560dad5d686d94385c0ca0952c89a73bf6a952dc0e40ac6bd5c027bc2535d5a3abb9bd3b5f196b17f54541966d721d1bd448405889a2ae8f1aa17530801dbc608eb36d18ba01a2618901cece477ae41e53bdcae2d975903b59c66a2f76d89b68335e5b679aafa6e76034f392c7725baa2ae10dac6b0fe3dbef22de84a1feb95e082b1fb536b54de2703681ded3cdb8d1499e1b3786f4f4aa8382fdf38bfa90fb5670d1acefce2c1852e980cf119a547fa414083c7ae52c6dd43485c2c026137375d70f08e4d4cb4b846d1ee93eb4293d56d177c1476534c1c8cf7468c9db8bee6bbd4854fe711574876b9f0584245101882d5a4c6e2f4b57f67a27e099115450774cdf71bd8f9f3dcac820b190cccc68e0be7ecdd0830a098b40d190efc09614e236e", .Okay}, + {.Shr, "4a1797d45613270853a6c254d832d893c99cb2364e43420f5f1991dc1f0e56498a79299b244f2b55b97f6523d542170e87bdac0478cbcf44d71dda3e6e98b2f33967c18b206d2d56063444cd95cb6d4af70b473eb1898da2e8e188ef9c185cc7c5139eab0fb1d377c5ddec3b599ec75510613de221e00cdf07adaa35319d27789737787c602356965bdc670af7ab89c6f8116e129b6e00691fcd043b946dc17a15ff61242a7a12741c05b353fcf94f8497d722bc4d5e0dd206fa2a28ecf9f4b1c6c47872b7b18f405dae5e99087a321cde184ed155f46eeaa3ff6e2f400a9196c7f26e03d6d17905433977315c9ff08e1ac1f1749e4811503c96e7f3646f18577aaf64cb361c22cff9e24cac5d51b651dd41ac7c4c832bb51633631862b339969ecb72e02b27886be6c245626c4edea55b4e6459362562b5b9fdfd564fbab8d8e748e8aec759ccc27b7de6fb9cc1361bee48afe24113c80f2c47118dbde0301953777a99c55f6caba7e8343cb25d4695ac037e249a06bdd9b7fbd5440b2eb422b3e0c144318f8434bf1fcd923ec3484753b56daa703b04ad24da19ed4fe437a78fb91681d8e2ac726afc50c93ce23ab908a2609e30aecd87a9b559b170c4fd47d52bde44bdc0efd59117b707585821dc98278529e5a5a6e3e00bc763dada69ec5ebd1585085154b780939233f33d7a3169d163e4ba1c8dab9e4cf4bf78127f53", "78", "4a1797d45613270853a6c254d832d893c99cb2364e43420f5f1991dc1f0e56498a79299b244f2b55b97f6523d542170e87bdac0478cbcf44d71dda3e6e98b2f33967c18b206d2d56063444cd95cb6d4af70b473eb1898da2e8e188ef9c185cc7c5139eab0fb1d377c5ddec3b599ec75510613de221e00cdf07adaa35319d27789737787c602356965bdc670af7ab89c6f8116e129b6e00691fcd043b946dc17a15ff61242a7a12741c05b353fcf94f8497d722bc4d5e0dd206fa2a28ecf9f4b1c6c47872b7b18f405dae5e99087a321cde184ed155f46eeaa3ff6e2f400a9196c7f26e03d6d17905433977315c9ff08e1ac1f1749e4811503c96e7f3646f18577aaf64cb361c22cff9e24cac5d51b651dd41ac7c4c832bb51633631862b339969ecb72e02b27886be6c245626c4edea55b4e6459362562b5b9fdfd564fbab8d8e748e8aec759ccc27b7de6fb9cc1361bee48afe24113c80f2c47118dbde0301953777a99c55f6caba7e8343cb25d4695ac037e249a06bdd9b7fbd5440b2eb422b3e0c144318f8434bf1fcd923ec3484753b56daa703b04ad24da19ed4fe437a78fb91681d8e2ac726afc50c93ce23ab908a2609e30aecd87a9b559b170c4fd47d52bde44bdc0efd59117b707585821dc98278529e5a5a6e3e00bc763dada69ec5ebd1585085154b780939233f33d7a3169", .Okay}, + {.Shr, "e7d4205792ec04af2fde99fbc59477fa9e16c10009900ad2237e761a78efbedb13c8f79fb59056a039dad2660c8297984310272624b7f3191f941ba55b3c8f58dc6d9c59cf286534ee6ee74170be25913c8e490c491bbca01798f1772ef802334e7c512d13907f03edfc549635430eb2fbd193c51f4b35f306b5b4c8f5d6adde5e3e1e91aa0e9c2737372c1b45a4af5ed3fabcd5fc2f168b646d09b642e099dddb39bf3cc493983d4dc13d4302b4a7f28a7f47add4b1c719a6191e10d1de9d039ffc58faee3ef74221d1c01f4b9125c8a1b148059453f6615c391275c79b090d363a2b5fe5df0afa1bedfc67efb517409341fa5fb2620731145a889072395cadc227d70bb44d844d1d2148a04c14be87263a404a7f1496012d9707f3af647daffd3397b756a8752ea64d35e33a1c58e333ff46e80cfe17f964d0d8b898cc07b36c7adf445faccdc00f6a5b46f6fe7a32e31864479f3890eac7ce7f8c2bcaa4758939a1a62ffb6a25ec8dde7e140d698a1e4b8b4ab434483acf30ea50749e871ebf3636ff9432b4850da17ffb8400d94c3f06a3ea52a6103a29cd9cca3a28f67af2c2488c73e9a1e1200d92d3282398f5ad805e6911441ba53965958921861ace74f4b2f0a739c202f9e9427eb808a8d02d9de861b807bdb089e19f758b352e5ee11fa800834fc4fae3fe12d0919a61b81dcdd1c18a37274d5859a17980685cdb", "f0", "e7d4205792ec04af2fde99fbc59477fa9e16c10009900ad2237e761a78efbedb13c8f79fb59056a039dad2660c8297984310272624b7f3191f941ba55b3c8f58dc6d9c59cf286534ee6ee74170be25913c8e490c491bbca01798f1772ef802334e7c512d13907f03edfc549635430eb2fbd193c51f4b35f306b5b4c8f5d6adde5e3e1e91aa0e9c2737372c1b45a4af5ed3fabcd5fc2f168b646d09b642e099dddb39bf3cc493983d4dc13d4302b4a7f28a7f47add4b1c719a6191e10d1de9d039ffc58faee3ef74221d1c01f4b9125c8a1b148059453f6615c391275c79b090d363a2b5fe5df0afa1bedfc67efb517409341fa5fb2620731145a889072395cadc227d70bb44d844d1d2148a04c14be87263a404a7f1496012d9707f3af647daffd3397b756a8752ea64d35e33a1c58e333ff46e80cfe17f964d0d8b898cc07b36c7adf445faccdc00f6a5b46f6fe7a32e31864479f3890eac7ce7f8c2bcaa4758939a1a62ffb6a25ec8dde7e140d698a1e4b8b4ab434483acf30ea50749e871ebf3636ff9432b4850da17ffb8400d94c3f06a3ea52a6103a29cd9cca3a28f67af2c2488c73e9a1e1200d92d3282398f5ad805e6911441ba53965958921861ace74f4b2f0a739c202f9e9427eb808a8d02d9de861b807bdb089e19f758b352e5ee11f", .Okay}, + {.Shr, "efd914f94668197ae786c10f161d017c1581e90d16fde588aa2c80ead065dd7eab06fa91f341f22a8f55b747d0d82deb51398994293c9cc65b0d252f399df23a3aaaf8a270a12667eee266b1bf8a60ca386e811d1d2951c422d77495c5b9b24004ea1ce09b668955f644c1d34536aba6ac82fc637fff3dd40fa80a0ec30cad71b0b6d3ef7d994069349df3ad79f9503bff208f6d08a89e73aa92b4c3f3f457dd4d9a1c1304ea04e53a58b2cc78226b431218c53f48783fa1abfce31115164388f13d41c8452a50f8b5c358d43dc291eb3d147f08919e8f1e6acc07d16a8d2acb7ace6cc327dab2865c1d20855ddeb1a0d9f5d04413e60fcef1dae0d3e1c7ce724d21014b2a008842dd1ba0ddcb9de9956211e0b2c451574270cfcf957bcbcbb368d2a67dd46e38232274087bd6b2c42635a1ca6ca2ff87f6fc05caa6149d7b556b0d2b411faa351fbcedca3a278b56039147bca6b922564d1cbc03df4876bccf1a1813e8f19fe4f4ee958876f5a56c9ce6953a436350af7041ad5108efc67c607faca8bdb65aac4815748f9c8b13d4b16b8fce7e03470ddd251fa0d2bf241cdc2fb96bee2f21df54430746db32f1f61f84289ae8f968834bd6890e6cf98172f292ef9bbd98ea01dd38f0744f869a30425ac6ca16723ff46c051ea35d163c7359ae9ca8082f17da9684cf20b6de9b7ec9793ef76f625f0197ba762717b7b30c43", "1e0", "efd914f94668197ae786c10f161d017c1581e90d16fde588aa2c80ead065dd7eab06fa91f341f22a8f55b747d0d82deb51398994293c9cc65b0d252f399df23a3aaaf8a270a12667eee266b1bf8a60ca386e811d1d2951c422d77495c5b9b24004ea1ce09b668955f644c1d34536aba6ac82fc637fff3dd40fa80a0ec30cad71b0b6d3ef7d994069349df3ad79f9503bff208f6d08a89e73aa92b4c3f3f457dd4d9a1c1304ea04e53a58b2cc78226b431218c53f48783fa1abfce31115164388f13d41c8452a50f8b5c358d43dc291eb3d147f08919e8f1e6acc07d16a8d2acb7ace6cc327dab2865c1d20855ddeb1a0d9f5d04413e60fcef1dae0d3e1c7ce724d21014b2a008842dd1ba0ddcb9de9956211e0b2c451574270cfcf957bcbcbb368d2a67dd46e38232274087bd6b2c42635a1ca6ca2ff87f6fc05caa6149d7b556b0d2b411faa351fbcedca3a278b56039147bca6b922564d1cbc03df4876bccf1a1813e8f19fe4f4ee958876f5a56c9ce6953a436350af7041ad5108efc67c607faca8bdb65aac4815748f9c8b13d4b16b8fce7e03470ddd251fa0d2bf241cdc2fb96bee2f21df54430746db32f1f61f84289ae8f968834bd6890e6cf98172f292ef9bbd", .Okay}, + {.Shr, "34ef93bd31efb99ee86b8b6ad5469d49abc522c9cf64724a53acaae87e70044394312da594fa495bc347c29df30c9b21bb5177c5b5c11d41afcf12c6b0a4c8063e1e968c2a187bb0bada4be8fd626b8b324f7c27335aef47789e7d463bda0294ef479ff80d3df97d2a820f6d91fd300d0dccd97bf17ce8fa023eddcbfad333e7a5dde529a306b81ac0a0ff37df02c746812505b94378a3651cc2210eb2bbf129c1669e316792d28cb5275f634bc4784eb3e459d932b280c6c52a2c37ba431cecc3bacc4de187f85541d57e6f72175719cfe9af78a0bbee6edcff2305966eb59972ed65fce7e56bf69d06a824becdd5e94d79b74bb19a60d32cc3240ae9dca55e0a7528ee3e4de390f19c4d955d5c91b513ad0ce027b6677bce900ea4ea861da61791d04395198098ea098cce8730a6ca92a49f04a0055e03210cde88fb46e716d56fda14994c055ab9a1c4f622a347f376652e4c2c6db8fee15b0f9c587d8018aa023741c819868063f7904d0f534a49300c8ef58bc6a286ed8804310a46e0fc6e57ac7f14a1eed171f520297aebc844bf850bdfc9d96f55cdff1c03b50f67582e8bfb75500210c89f198dcb9bf3e9c7856444b2a0520b41b35e6f092a3ca5268df7541a53e1c66b8a98cb9cd67bed03c253cef3d7a705a70fd05a561f2843a26cb4e508dc486fd1cbda74afaac861d5177407f070575c1aeeee71f87e47c563", "12c", "34ef93bd31efb99ee86b8b6ad5469d49abc522c9cf64724a53acaae87e70044394312da594fa495bc347c29df30c9b21bb5177c5b5c11d41afcf12c6b0a4c8063e1e968c2a187bb0bada4be8fd626b8b324f7c27335aef47789e7d463bda0294ef479ff80d3df97d2a820f6d91fd300d0dccd97bf17ce8fa023eddcbfad333e7a5dde529a306b81ac0a0ff37df02c746812505b94378a3651cc2210eb2bbf129c1669e316792d28cb5275f634bc4784eb3e459d932b280c6c52a2c37ba431cecc3bacc4de187f85541d57e6f72175719cfe9af78a0bbee6edcff2305966eb59972ed65fce7e56bf69d06a824becdd5e94d79b74bb19a60d32cc3240ae9dca55e0a7528ee3e4de390f19c4d955d5c91b513ad0ce027b6677bce900ea4ea861da61791d04395198098ea098cce8730a6ca92a49f04a0055e03210cde88fb46e716d56fda14994c055ab9a1c4f622a347f376652e4c2c6db8fee15b0f9c587d8018aa023741c819868063f7904d0f534a49300c8ef58bc6a286ed8804310a46e0fc6e57ac7f14a1eed171f520297aebc844bf850bdfc9d96f55cdff1c03b50f67582e8bfb75500210c89f198dcb9bf3e9c7856444b2a0520b41b35e6f092a3ca5268df7541a53e1c66b8a98cb9cd67bed03c253cef3d7a705a70fd05", .Okay}, + {.Shr, "5f6354aebacaa581e68f7058128ab6971271b33110338f4bda66c8d51130338f086be26f02d7e5c54166466ebc9912456bbb8bcb7129cb71d992e44c8ef7037236cc21962b79835225f6856c737ee0b64b3680f4142696d6221c220ef747522642fbecff4ffb6ac2c39ba3e4c8725060fac344140555395689966e9cc24e66932fe92bda385978a95cefa703b39cdec7fd4b746b780ef85dcd507a3b5d9961ecf64eaee3e62cc78ca89054f716c09b24b8ebed44405d7febee42af57de238503b8f6e5c605e3892ba24772231b9423d62f4588ae98f1940b99b694e92bf6009a14503a432ffa9f92b21a040369ccb071618cef37990fbbc16adb8339c17153f8dabc48e5af9feace088c2d2274e62abae1f0c9ccc1ad2c9da7c23a0d4eb032877f8a18538675dd4368bf3a8355c0c69c16848531f1857fb04e7d14601f59b137673999c5434a687ac2d5b3324afcd4b574872478b7a8935f92d418c24ced9e929c0a30899c6b9e00031dcf6a861758beddce7ab0b443ef26c7453b0f4001894707d7fc6f17004cc4c6d10cceaa541776e7da3d697e7378ccb44d8cd6723b923c5606bc14d45d25507795db49d1374e8f412386ff3ac370d8b525d8e3c2e1f270edb40ccc51e999a626949be1d9c4b2e1e27b07dbb9fbbf6b01c7652b72ff926c0615d8cf8263176adb2e09e5be28722ad52d7c6107c5404e73e6ac7e95f5a9ab", "f0", "5f6354aebacaa581e68f7058128ab6971271b33110338f4bda66c8d51130338f086be26f02d7e5c54166466ebc9912456bbb8bcb7129cb71d992e44c8ef7037236cc21962b79835225f6856c737ee0b64b3680f4142696d6221c220ef747522642fbecff4ffb6ac2c39ba3e4c8725060fac344140555395689966e9cc24e66932fe92bda385978a95cefa703b39cdec7fd4b746b780ef85dcd507a3b5d9961ecf64eaee3e62cc78ca89054f716c09b24b8ebed44405d7febee42af57de238503b8f6e5c605e3892ba24772231b9423d62f4588ae98f1940b99b694e92bf6009a14503a432ffa9f92b21a040369ccb071618cef37990fbbc16adb8339c17153f8dabc48e5af9feace088c2d2274e62abae1f0c9ccc1ad2c9da7c23a0d4eb032877f8a18538675dd4368bf3a8355c0c69c16848531f1857fb04e7d14601f59b137673999c5434a687ac2d5b3324afcd4b574872478b7a8935f92d418c24ced9e929c0a30899c6b9e00031dcf6a861758beddce7ab0b443ef26c7453b0f4001894707d7fc6f17004cc4c6d10cceaa541776e7da3d697e7378ccb44d8cd6723b923c5606bc14d45d25507795db49d1374e8f412386ff3ac370d8b525d8e3c2e1f270edb40ccc51e999a626949be1d9c4b2e1e27b07dbb9fbbf6b01c7652b72ff926c0615", .Okay}, + {.Shr, "cba282c43cdbb4d2301e1d25b51259f94a864e2bbffe042628931c27ee4a542ae8f36ecf8aa1cde91d1d9a7c98438a66976b01ed0febcb79907c2df7144f7ad58346cd80fb37f9b1d4a0c068e1aba5cc2dece943814d6c88387ee7cfe3e9c04ba89122ba63b762c974d1d9281d771da6e9a35f18755bc64cd72cdcd4435ce1720b899012aeea1522886e5d87b62ed031ba96200c6f8325b8a357143d8879a6cc4c31d08f07ba8e8f1178b5a457568349ff81dd0e1bb378a103e25fe76e25ae69cf0454f4904fb8a62edee66fa863e5fd6891d5da8775d21bfcc245ceb5c016f781d57bf540d2354aa7af9ca993c91d19a388ef80d2b8277390e5f9809ba918a0ecf19ce8a407924db5d5858773ef21c7028a41bc79b73dbb662f6059f4d2316bbb657f815de71f6baf048959d6d46b07953b4c1655f34aa8c087cbf8f4788ddc87ca919fb610b370fe67c5623e523f589c7f869dbfc6dde8b2992890defa3edefc55ac36d2d59f54f09c7da18325ffa2eb36081489c60db54a956e9dc586509158cbf9ac4d20c5009f5d74419a8c7f5147eea47b1349720c26d975f47731b8ad7c537ff52af202081e40db1dad4c9cca1fd6cdd40074479960f6a16eed1fbeb2648391ba69261d113c064453303bbdcdfafce11baf81ed0722b9107c005bd238adcda4074853abc2a19b2b7e94ab688bdbd57bca5bf8de053f3676464dcb8433", "21c", "cba282c43cdbb4d2301e1d25b51259f94a864e2bbffe042628931c27ee4a542ae8f36ecf8aa1cde91d1d9a7c98438a66976b01ed0febcb79907c2df7144f7ad58346cd80fb37f9b1d4a0c068e1aba5cc2dece943814d6c88387ee7cfe3e9c04ba89122ba63b762c974d1d9281d771da6e9a35f18755bc64cd72cdcd4435ce1720b899012aeea1522886e5d87b62ed031ba96200c6f8325b8a357143d8879a6cc4c31d08f07ba8e8f1178b5a457568349ff81dd0e1bb378a103e25fe76e25ae69cf0454f4904fb8a62edee66fa863e5fd6891d5da8775d21bfcc245ceb5c016f781d57bf540d2354aa7af9ca993c91d19a388ef80d2b8277390e5f9809ba918a0ecf19ce8a407924db5d5858773ef21c7028a41bc79b73dbb662f6059f4d2316bbb657f815de71f6baf048959d6d46b07953b4c1655f34aa8c087cbf8f4788ddc87ca919fb610b370fe67c5623e523f589c7f869dbfc6dde8b2992890defa3edefc55ac36d2d59f54f09c7da18325ffa2eb36081489c60db54a956e9dc586509158cbf9ac4d20c5009f5d74419a8c7f5147eea47b1349720c26d975f47731b8ad7c537ff52af202081e40db1dad4c9cca1fd6cdd40074479960f6a16ee", .Okay}, + {.Shr, "23629321e55723df89991105f43b8878c79994664fe0428c2c0980486b5edbed1985b18eede16fa6b5115cf136f97fc829b425c86ccef518b0615d79f39cbd14c2289484af1da02564706079bcc08dd8727ac8fb509f40c082376b86deeabd39290e042b9c7629e22dc4e3d12fa0154dd81ae1888efd3324789a9ab6be6b35e320fc22c5fdb3d8c84ac49da80cc6818261e9493f751bb0eedd3884a353ba2dd23d4f40b7ddda5f2376387281164cd7ebe9f7a3025a5713502fabb50f491b95379be4c755e2472c67b10c5729ed071c401049b43afc1d99526598e695e46fe188bd154d95ed11fc70e7b733c0a9ab61021e0bbc4c12b860c4b429d3f16db436ea55a2826f8b5ac2d8672cda839f3d6533571f71434feb278f526d4249b89d8924c9c7dfbb0fe9738b4fdc5a6facae75ff69cecfecb6eb31afa6ee8b30df40a82dccd4a36e528724ca7e0fc3e3eac3da9e1d9abd9930ff5d58466c45f39c36a2e5895a4c63e7782a52743335acf91bfc396144415621d255141aba14f50f8fd9b15869610543d7b02f6c17cedb46c9f7a547b87199f9425e2b4c4603dca0c96536e8691a4b01927080de6a23162203b182aa95b479bcca9554da56d0c957bec5d2619276b0671441736cd442a50a2a0d22ec0e0a297f24611488e2a405859553c7ba70e25438d3d93e7ee18dda0e5c0b2df792a774c91a6e5b2b59b47875b60597", "258", "23629321e55723df89991105f43b8878c79994664fe0428c2c0980486b5edbed1985b18eede16fa6b5115cf136f97fc829b425c86ccef518b0615d79f39cbd14c2289484af1da02564706079bcc08dd8727ac8fb509f40c082376b86deeabd39290e042b9c7629e22dc4e3d12fa0154dd81ae1888efd3324789a9ab6be6b35e320fc22c5fdb3d8c84ac49da80cc6818261e9493f751bb0eedd3884a353ba2dd23d4f40b7ddda5f2376387281164cd7ebe9f7a3025a5713502fabb50f491b95379be4c755e2472c67b10c5729ed071c401049b43afc1d99526598e695e46fe188bd154d95ed11fc70e7b733c0a9ab61021e0bbc4c12b860c4b429d3f16db436ea55a2826f8b5ac2d8672cda839f3d6533571f71434feb278f526d4249b89d8924c9c7dfbb0fe9738b4fdc5a6facae75ff69cecfecb6eb31afa6ee8b30df40a82dccd4a36e528724ca7e0fc3e3eac3da9e1d9abd9930ff5d58466c45f39c36a2e5895a4c63e7782a52743335acf91bfc396144415621d255141aba14f50f8fd9b15869610543d7b02f6c17cedb46c9f7a547b87199f9425e2b4c4603dca0c96536e8691a4b01927080de6a23162203b182aa95b479bc", .Okay}, + {.Shr, "ccf17abd74a323007af87b2ea5fe8f8afc1bf1692d90a5ec2e776cfb941c8885b21a13e572be9e85c5d4b829606aee381eadd3e33243cdc774996f165150426abe75f29b71dea3637f0d3825548ca7950a3fd5712c5cc9868d4fc864fe214cb30960c6079ecc388511e89d055b0e09365e2495f640144133938e188beef32398adfb50238ebc63fc5789baa1ccc2939140cc440ddca648faebd84d377dda7e448b91fdbef3af3168af2f224529ff55e123800daedaf4b2986601750b0ab79642aec48427dbba9f44607523814d881c8b74402d71791be41cbda788aed1d86e0569841e67d1668b60d9a873717532b4726d453613357200bd7879589b2bdd76bd555738e207fac78b50c4fbbd51e005f5bd5db3acec9705152657c94f1008797214802651057c66e02371fde0b33c80995b8a72f8fbac5a5b6bfbaf1d6d37b70e06c96fe1cf1d7a6b5be6364c0f3d95a06eaa0a586220f62e06653db99840d9eb3d6a9d89fc4d1d856b59386d5c44ad76f8d690d88873571adacf6e1e4b27c9004acb40914cbcd13491bbcd143f9e8f332ea928ce2e5dcc6e4886a864f3f972b8bd1cbb143d5cf683fa024dbac838c9f05297cd831386c22c9e560d70e8b2efb3f1a24825538aed97916a2357b04f0d93a2ef301726c8dd9f8c02754dfdfa2732b3fb8ca03907220c7063fee8e6b157255bb78f67dbe784767af3a02b5f1e23d8", "258", "ccf17abd74a323007af87b2ea5fe8f8afc1bf1692d90a5ec2e776cfb941c8885b21a13e572be9e85c5d4b829606aee381eadd3e33243cdc774996f165150426abe75f29b71dea3637f0d3825548ca7950a3fd5712c5cc9868d4fc864fe214cb30960c6079ecc388511e89d055b0e09365e2495f640144133938e188beef32398adfb50238ebc63fc5789baa1ccc2939140cc440ddca648faebd84d377dda7e448b91fdbef3af3168af2f224529ff55e123800daedaf4b2986601750b0ab79642aec48427dbba9f44607523814d881c8b74402d71791be41cbda788aed1d86e0569841e67d1668b60d9a873717532b4726d453613357200bd7879589b2bdd76bd555738e207fac78b50c4fbbd51e005f5bd5db3acec9705152657c94f1008797214802651057c66e02371fde0b33c80995b8a72f8fbac5a5b6bfbaf1d6d37b70e06c96fe1cf1d7a6b5be6364c0f3d95a06eaa0a586220f62e06653db99840d9eb3d6a9d89fc4d1d856b59386d5c44ad76f8d690d88873571adacf6e1e4b27c9004acb40914cbcd13491bbcd143f9e8f332ea928ce2e5dcc6e4886a864f3f972b8bd1cbb143d5cf683fa024dbac838c9f05297cd8313", .Okay}, + {.Shr, "ed578c397bb48353fcd91e595b48da0d82f194df80983866b686fdfd58051f930fcc69e7d06f4f247522dca47b7df502b66965de6f7397740db779d63fb66352f3eef8715f404a439c9621d4ddb8aeeea60b8eb679a02e925c280af2b9bab113fe82bbb15347ccb9c6e267bdcc714ff0158bb4e6722d9d40cdb075fd0b0aabbc9adddfcdc0598d43fe09d0902b88fc52748bfd169977884c7179df20928b81f774e9ca39794460832ee386039ce287001978e4dc5cfb2da381374ea6632fe7b43eafd5bc2202cdf7f2ab994240b89f80855efb90f3620d72b66e9fc3eb20a00cc8d0810207059ee786a4d668e4e1e57741ae5ce0fd85383e9a32ab4b2e0f6d62028367b9b8f2f16872a3a57ecf56ed9b44f221549cb93ac19fdc3c75a144e2dffd3ec0798b8c3840929136ab9bf3f55c2674934ca2193fa24d0e46305411c317edf660632878339fbd3ff82e05acbcc400cf4bf0a8cf48d1136f0675b69a9415a54f8a114e2faf8255fd2abe23815df913b0a62957ac0c3361067bc0170e49552c69f38b0a15584dbf169e32e50ee2b5077c0c49834ce9a72410d8ab4e2508d23bc67a037e4cd2f9206501db8be70a473d230626b302785d449ac174a43c294aebc0fb563276738eaa50e3b4b3ca54ef6eb0847feb10382c8076baca0ab58f30d26acfaba07bdd80ffeb127e6bf4732cc7843f132e1d5bc9921c1d30f686d4ac", "1a4", "ed578c397bb48353fcd91e595b48da0d82f194df80983866b686fdfd58051f930fcc69e7d06f4f247522dca47b7df502b66965de6f7397740db779d63fb66352f3eef8715f404a439c9621d4ddb8aeeea60b8eb679a02e925c280af2b9bab113fe82bbb15347ccb9c6e267bdcc714ff0158bb4e6722d9d40cdb075fd0b0aabbc9adddfcdc0598d43fe09d0902b88fc52748bfd169977884c7179df20928b81f774e9ca39794460832ee386039ce287001978e4dc5cfb2da381374ea6632fe7b43eafd5bc2202cdf7f2ab994240b89f80855efb90f3620d72b66e9fc3eb20a00cc8d0810207059ee786a4d668e4e1e57741ae5ce0fd85383e9a32ab4b2e0f6d62028367b9b8f2f16872a3a57ecf56ed9b44f221549cb93ac19fdc3c75a144e2dffd3ec0798b8c3840929136ab9bf3f55c2674934ca2193fa24d0e46305411c317edf660632878339fbd3ff82e05acbcc400cf4bf0a8cf48d1136f0675b69a9415a54f8a114e2faf8255fd2abe23815df913b0a62957ac0c3361067bc0170e49552c69f38b0a15584dbf169e32e50ee2b5077c0c49834ce9a72410d8ab4e2508d23bc67a037e4cd2f9206501db8be70a473d230626b302785d449ac174a43c294aebc0fb563276738eaa50e3b", .Okay}, + {.Shr, "93cbca16c48bd31343dbb8ef67aad4c44d9f875d2d4771a97dc2df9c0a2dfe5ae24c0acbd4f73e7c5d7469b59916f4f69af87f7681c12ed95196193a86da7595bcec4b3418c7c466dbbb8ea1eb80b2a13bf8446464888edebe60178737e72332ef693321ed1a61405be307a54a928dec286518b0f86a810c88da9a7fbb9859ce73a270ae9821e7e4c6b8587c306769c028218e27a3aa2e79284972f46c3d6bf1c0fe238f695fd46d16ad9f5afa66cfb2dc12ff0ae56e97a7fa32f0b2d1cf7d2f294e7fa9ce28d89ddd5b3c642411881b0a6e1331285db4309319d82998cd984971e6f61fd1c98c0610d0679d4968aa0f516260977330823bda1165216fb6084fb63641604311f13c02d8828d882c7e2966246a7f68db1fa612b89d21657acb24573faacae1e62e521b31e5f2e0f341278d94b5207fa7d66213921cda9d88335e50674a0f4e25c99bed90e86aa9c2b7d69ea4f6c409f71a3da78fa2c9c245ff2d87196f5bee730fc1d6db98c8cada50e97f47efee5f393e385458c6007a09fd38fe961f0db65c313afad233a5f2a3aeb0a5a94acd8f62dfd0883bf5d998ea55682fbcc7dacde6e7241962435cdf257259b95d8fb868bbe2b4da36f4895eccc97088dba115bd1386fd56f358a7c13af9fd13a88d980de34d9591b2626c33aeb123c960a1ac037db8f06dae15c82a4774bfe0d0b28b7677b7811d3d12fc24cd40a0", "78", "93cbca16c48bd31343dbb8ef67aad4c44d9f875d2d4771a97dc2df9c0a2dfe5ae24c0acbd4f73e7c5d7469b59916f4f69af87f7681c12ed95196193a86da7595bcec4b3418c7c466dbbb8ea1eb80b2a13bf8446464888edebe60178737e72332ef693321ed1a61405be307a54a928dec286518b0f86a810c88da9a7fbb9859ce73a270ae9821e7e4c6b8587c306769c028218e27a3aa2e79284972f46c3d6bf1c0fe238f695fd46d16ad9f5afa66cfb2dc12ff0ae56e97a7fa32f0b2d1cf7d2f294e7fa9ce28d89ddd5b3c642411881b0a6e1331285db4309319d82998cd984971e6f61fd1c98c0610d0679d4968aa0f516260977330823bda1165216fb6084fb63641604311f13c02d8828d882c7e2966246a7f68db1fa612b89d21657acb24573faacae1e62e521b31e5f2e0f341278d94b5207fa7d66213921cda9d88335e50674a0f4e25c99bed90e86aa9c2b7d69ea4f6c409f71a3da78fa2c9c245ff2d87196f5bee730fc1d6db98c8cada50e97f47efee5f393e385458c6007a09fd38fe961f0db65c313afad233a5f2a3aeb0a5a94acd8f62dfd0883bf5d998ea55682fbcc7dacde6e7241962435cdf257259b95d8fb868bbe2b4da36f4895eccc97088dba115bd1386fd56f358a7c13af9fd13a88d980de34d9591b2626c33aeb123c960a1ac037db8f06dae15c82a4774bfe0", .Okay}, + {.Shr, "b45afca5c253cc6823837db4f5bd77535785e5dd711af610d0cc9c255b2e38ce19613d6ef2edb3099a57807878982f26ada255d5460a05824d72cf3fb5546c264f7ab99ddb8193a0b7deec6746c22fcfc4d5991d8b471084851af89b28edca5b99f784b253bdc7d38c9d240a2b2d9d5b77c53719ae2ac4d874a046e9201f060ebcb60cfb055e7e59979e5c5f65dcab52e5ed8ccde71ef2fc243cbf1261766312e70297dffa8d1d2b5fb03abde19803af95ac94f475f444beb88a8460aee9329837f6994d4e9401c8ca38b5c2a2343168052204450d9f4bef832b25729db6ab8f1978c45c7fda590ea782886f95b6f967c92f80c2152b60c6c091b5991e5beb0aba416debcbf9f2804752dbfe40acd602e0fea22b6984c3841f475e9f8c12f4dfba6179d2646a1315551ff28d2147dfb3ad63aaf602bcdb26f2a01cafadcad7d6ca4b18416275735fafbc104485559e4e3385beba83ef5ba388c51d632ede7d7340806fe3705cd26a549ddb6d199a70521327834c6893680bb6c8ef3bf20cfe1d1aabf731f55785e39cc147f50f2e7ced1886535006a227a0228789edab68fee1d54134574e0ead6672b29a54683e0e6088709c4160664914250115c05731c65cbeba0311cbf3122683cca6d93d9f7b68ff98425af539fe3c13afbe2c989b1923a39b8ab8a01ec66b680eac3d31965e261bcf21c60ce6a622eeb4382637b759cf", "b4", "b45afca5c253cc6823837db4f5bd77535785e5dd711af610d0cc9c255b2e38ce19613d6ef2edb3099a57807878982f26ada255d5460a05824d72cf3fb5546c264f7ab99ddb8193a0b7deec6746c22fcfc4d5991d8b471084851af89b28edca5b99f784b253bdc7d38c9d240a2b2d9d5b77c53719ae2ac4d874a046e9201f060ebcb60cfb055e7e59979e5c5f65dcab52e5ed8ccde71ef2fc243cbf1261766312e70297dffa8d1d2b5fb03abde19803af95ac94f475f444beb88a8460aee9329837f6994d4e9401c8ca38b5c2a2343168052204450d9f4bef832b25729db6ab8f1978c45c7fda590ea782886f95b6f967c92f80c2152b60c6c091b5991e5beb0aba416debcbf9f2804752dbfe40acd602e0fea22b6984c3841f475e9f8c12f4dfba6179d2646a1315551ff28d2147dfb3ad63aaf602bcdb26f2a01cafadcad7d6ca4b18416275735fafbc104485559e4e3385beba83ef5ba388c51d632ede7d7340806fe3705cd26a549ddb6d199a70521327834c6893680bb6c8ef3bf20cfe1d1aabf731f55785e39cc147f50f2e7ced1886535006a227a0228789edab68fee1d54134574e0ead6672b29a54683e0e6088709c4160664914250115c05731c65cbeba0311cbf3122683cca6d93d9f7b68ff98425af539fe3c13afbe2c989b1923a39b8ab8a01ec66b680", .Okay}, + {.Shr, "4dd59a3dbb4623736b92d0f0cae161b826ff4ca48da3a7d1269ac391b931b32dfb9be82f09c440ec6d9aa7d244c1b802ec7f854e915d7c7b0856ead1de52514b01cba3c396ac6efc76e487d00c4d47311b953275a90726b7750c4459c00d02e6cde8dcc1692cfd525c6a58e030cde73f43c9ab2a799bdcb46bc071f67598b30c2cf806827863c52b83bb25965023ab8fc4d7369432749fab533ad51e9f773194da8d96faa578281cf274c6c9913c14bc1c1c8786bc09e948fc7fdafca14c6977db4e16a4ec935aa298ff73e01a0625089e37cd50ad29685d7a6f5a76c2f45f2e4d57d28b5a672282d7a2493e8d8fa7fc95165df9120a9396d9eb9a7090e3db7928a1ecbfde9d7ed0da07db3b3d675f5a3655b837527410524ea9ca814f2104967b50db25fd59bd23b666ce96e72da2ed6c4c06e2ffb5956b92018851b76629ce70e61a489272392e3d3fa9d04be65dcc14055e02085f6549dc598f20a681d7cc95fc11b2ba64b19a29348d7c848d238d74604c02eb425b2308254a1eae30a0ad2c3fb19ba539e5a86b4d44e62e92e110726198cc1e5ac208360143c770424571e396a2623e4f4c875d141eebab3fef2776b6295c5c8530c6d90433943722ca838349cf50e62ad4b62727ba965a3275b673cd17df6f87ed15797561539fca8ca5d74b18dd65857fe383839058031cfdd5eb25bf0aab1c3a6f32a55753484d62db", "1e0", "4dd59a3dbb4623736b92d0f0cae161b826ff4ca48da3a7d1269ac391b931b32dfb9be82f09c440ec6d9aa7d244c1b802ec7f854e915d7c7b0856ead1de52514b01cba3c396ac6efc76e487d00c4d47311b953275a90726b7750c4459c00d02e6cde8dcc1692cfd525c6a58e030cde73f43c9ab2a799bdcb46bc071f67598b30c2cf806827863c52b83bb25965023ab8fc4d7369432749fab533ad51e9f773194da8d96faa578281cf274c6c9913c14bc1c1c8786bc09e948fc7fdafca14c6977db4e16a4ec935aa298ff73e01a0625089e37cd50ad29685d7a6f5a76c2f45f2e4d57d28b5a672282d7a2493e8d8fa7fc95165df9120a9396d9eb9a7090e3db7928a1ecbfde9d7ed0da07db3b3d675f5a3655b837527410524ea9ca814f2104967b50db25fd59bd23b666ce96e72da2ed6c4c06e2ffb5956b92018851b76629ce70e61a489272392e3d3fa9d04be65dcc14055e02085f6549dc598f20a681d7cc95fc11b2ba64b19a29348d7c848d238d74604c02eb425b2308254a1eae30a0ad2c3fb19ba539e5a86b4d44e62e92e110726198cc1e5ac208360143c770424571e396a2623e4f4c875d141eebab3fef2776b6295c5c8530c6d90433943722ca838349cf50", .Okay}, + {.Shr, "36b14551a6081cdd2bce94eb8e0ff8d82951b5143ed48f34953a6531446f7d33b232dbd5f2ff507d710955aa45768b84227239e75044c447d84114cbad570564475245543241bc65da3a9a3a180151312ad434abdb4a1720b52e81e1e59467870fcd840bb1c5f8962aa03e6562ee1e27b6194572717ab1c39941dca40dbb1f73e918e3c29d4b4483d674eda15dee5a5fdacf51cd9008d7a438489a55c3166872a5dcd3aedf5a02d58fef812d9324b4b7198eba5637c16e62fd6404cd48d9f9101c1803609b8938417704d2e4c331c3a970836e565161e247f4afbddb39a2dd165a08eaece06194f6dd7c5682829675577d240744a70ee7ce8c532e2e3d78bb43ec4699b261b1beb26ef7b83273b59b96bbb18533996bd7847161ab560435f1bee9a3937a66a22528a24f13edc94947d1aeef9f925c00ce1cc5e4aac6cf2e64357f34f63e01c0965c144ab7fa71e0b1d17cf12b756d7c960dcdc81cb869fefe34b6c1aebab7392ae1f2be6fee6ebe656301e8f6183e9bab5b431d618912ff7c68fd2b0697fc7f086db7f5da0565565d62b2b8aed52d56dae36ccb79cf501a9ee35333aed0312383950b0faea686d69f1ee7c0f53878b7d2d700728cd183919d7db22d14542b62604b4f76aecff53a9a7d43752a1fce631a8e12f87294db29b184a7425fa626ca2fef2124290144ad512d0671e3051a1ed59a84b5e2f58e0fc7c5", "12c", "36b14551a6081cdd2bce94eb8e0ff8d82951b5143ed48f34953a6531446f7d33b232dbd5f2ff507d710955aa45768b84227239e75044c447d84114cbad570564475245543241bc65da3a9a3a180151312ad434abdb4a1720b52e81e1e59467870fcd840bb1c5f8962aa03e6562ee1e27b6194572717ab1c39941dca40dbb1f73e918e3c29d4b4483d674eda15dee5a5fdacf51cd9008d7a438489a55c3166872a5dcd3aedf5a02d58fef812d9324b4b7198eba5637c16e62fd6404cd48d9f9101c1803609b8938417704d2e4c331c3a970836e565161e247f4afbddb39a2dd165a08eaece06194f6dd7c5682829675577d240744a70ee7ce8c532e2e3d78bb43ec4699b261b1beb26ef7b83273b59b96bbb18533996bd7847161ab560435f1bee9a3937a66a22528a24f13edc94947d1aeef9f925c00ce1cc5e4aac6cf2e64357f34f63e01c0965c144ab7fa71e0b1d17cf12b756d7c960dcdc81cb869fefe34b6c1aebab7392ae1f2be6fee6ebe656301e8f6183e9bab5b431d618912ff7c68fd2b0697fc7f086db7f5da0565565d62b2b8aed52d56dae36ccb79cf501a9ee35333aed0312383950b0faea686d69f1ee7c0f53878b7d2d700728cd183919d7db22d14542b62604b4f76aecff53a9a7d43752a1fce631a8e12f87", .Okay}, + {.Shr, "fba0192939bdbcda15ccf56321b52af6046b5c0827d79e06fbbb3b3af78f3474b9eb00a3700bc55aba7248db2aac2fa7d9a1e5ddd0aa6c8b07855896efca30a96a2391513c5aa67f7bd8b89a6df393e25420057ce9ac89461a7d34201d38ac3dc5e851ad7e22659a864ceeacfe52293d14de5a6faa7bc298cb1f424e8b03cb8b04da13a6cd8cb77927ed53191fc12b1ff69b64dcfe874728005fd5e0e22f59a1ec8c239810ed24e48514fec9017a37986ba86ddaf3bbb3886ad663830f5cecec1e7e94edf724f349e24555beb28a8842a4fa6a6e585ac24da25d47dcb58c50b439dde4e7f7f672f4356cbf2284ea1aaaed076e37efeea86a86f5e8278f05991ee95030e681fe67fa4a7dc91240942ccda26961a1459e6753269957fc0b0ab5e2862804965822eb1eaa0430e781760e59ed6d038a8951e407b160d2dd6b797ef56739289a781b848bdcfc80ace574387abc82f502d4a5c799551b44c2cc212bca7f581d50315f182adef7ca7f0bf6c88fa13b081e5cd6df7c3a4d229e03f7f9cfef70770a28e3d5a4d988866e00c678519008d6b545dccd181db4b71f53be11a33f2496288a0032e881c6b2f98ac9e6d2be52be7a66ee0b234194bbb9e0dbd0c3bd3f985eec2065b0e07b0372894b3e1f93a06ca3f360f5c5098e06b5b1f3c5d2b3b9fc92177f2972149f1bfb709d9a0878d425817d042c60d271eed8944082be", "168", "fba0192939bdbcda15ccf56321b52af6046b5c0827d79e06fbbb3b3af78f3474b9eb00a3700bc55aba7248db2aac2fa7d9a1e5ddd0aa6c8b07855896efca30a96a2391513c5aa67f7bd8b89a6df393e25420057ce9ac89461a7d34201d38ac3dc5e851ad7e22659a864ceeacfe52293d14de5a6faa7bc298cb1f424e8b03cb8b04da13a6cd8cb77927ed53191fc12b1ff69b64dcfe874728005fd5e0e22f59a1ec8c239810ed24e48514fec9017a37986ba86ddaf3bbb3886ad663830f5cecec1e7e94edf724f349e24555beb28a8842a4fa6a6e585ac24da25d47dcb58c50b439dde4e7f7f672f4356cbf2284ea1aaaed076e37efeea86a86f5e8278f05991ee95030e681fe67fa4a7dc91240942ccda26961a1459e6753269957fc0b0ab5e2862804965822eb1eaa0430e781760e59ed6d038a8951e407b160d2dd6b797ef56739289a781b848bdcfc80ace574387abc82f502d4a5c799551b44c2cc212bca7f581d50315f182adef7ca7f0bf6c88fa13b081e5cd6df7c3a4d229e03f7f9cfef70770a28e3d5a4d988866e00c678519008d6b545dccd181db4b71f53be11a33f2496288a0032e881c6b2f98ac9e6d2be52be7a66ee0b234194bbb9e0dbd0c3bd3f985eec2065b0e07b0372894b3e1f93a06c", .Okay}, + {.Shr, "5388994dbaa6b5d19f105a64da12876e254541ef6bb37b73ef7c69b12e38920ee301e5233300d2876ff5d5d7c7f66e0d8ad4ffffa07a98749673c8e600b8522277b0c67f5f87f606c89662ed59895e2c7fe16c98a70d64f22e04fe5b434b161bfa7bdc47dc3ebb2a55efab26e49788a7e2983e45ac567435461c8f0a715cee0d2ffa522bd0609c08fb395d76cee40dd610a9c014becd1c3d1b846bd7d9abaf19f6bebd673efd1ca7a03f9e3be3d9a6a022cd0997e778bbf0b323d9c65778a0506b7446f5ae5ffd027b0b5e54547556a5da1dc0bd0a70f8cb35b0ec5dc3f74ebdba55250c5452a2c47d35209369a8addd2145f89ba0a93b5a2c3a7e9d74a14f80e6c61ff3738331d64b6ff278621c10834e93df61c100fb931a24c63731c200d99a644231e957c1399ad26be03324f5dd3b79ec5562d8f36bb0fc4bc6efff3df586ad46e60d33bf32d546a2c02969de5d0b3d02af5e2c2e961d86ee6c3c9478ef87ab74344b7d110e5781543f1e38b950f9c1c132c11136b3027a846b89bc17fe5fe129d31ba1c42d5d6932971b833a373fdda98433ae488bbdce4dee35487a6dcc325526828ee0c5baa56390b73ca2bfc468d75fdbce9ac480470cbdea872ca6ead98907d3733a1d6359505ba4c364be718108241749819aa2247633220939671b276de47805d69b946c0aa9ddf7baf3eda2d4e38f9e831ae0d4d163274f4997", "21c", "5388994dbaa6b5d19f105a64da12876e254541ef6bb37b73ef7c69b12e38920ee301e5233300d2876ff5d5d7c7f66e0d8ad4ffffa07a98749673c8e600b8522277b0c67f5f87f606c89662ed59895e2c7fe16c98a70d64f22e04fe5b434b161bfa7bdc47dc3ebb2a55efab26e49788a7e2983e45ac567435461c8f0a715cee0d2ffa522bd0609c08fb395d76cee40dd610a9c014becd1c3d1b846bd7d9abaf19f6bebd673efd1ca7a03f9e3be3d9a6a022cd0997e778bbf0b323d9c65778a0506b7446f5ae5ffd027b0b5e54547556a5da1dc0bd0a70f8cb35b0ec5dc3f74ebdba55250c5452a2c47d35209369a8addd2145f89ba0a93b5a2c3a7e9d74a14f80e6c61ff3738331d64b6ff278621c10834e93df61c100fb931a24c63731c200d99a644231e957c1399ad26be03324f5dd3b79ec5562d8f36bb0fc4bc6efff3df586ad46e60d33bf32d546a2c02969de5d0b3d02af5e2c2e961d86ee6c3c9478ef87ab74344b7d110e5781543f1e38b950f9c1c132c11136b3027a846b89bc17fe5fe129d31ba1c42d5d6932971b833a373fdda98433ae488bbdce4dee35487a6dcc325526828ee0c5baa56390b73ca2bfc468d75fdbce9ac480470cbde", .Okay}, + {.Shr, "e3b544090d88f8f39b600cdfc6cf467ea8f21d8a9e8b547ffed07147d2bd6a8d1439d89fbc880608c088eb90f368accbf8f2884086a08c727f442c19ded562e29f52018337e6d953bb4072cd0d3e7c17dc1dcb7461ae154d4a6b0b691b9c28c60c0cf94b013cac173742c3b7e5dea3fd0686b4ec333c353b65913fff57e8c6d0f245c05fa1aa8f9ab8d454af890fa967185a5610c07b231a9d284d53be845655ece0b72c7ba5d6089415c3b89a8647ba013d6ed75d2e1be33a0070c5725a9683a934318d722afde77368e3e81fb97d1a93f465d38b47e675017ba0c208830e3923ca84b589ec809513afb5396dc814c3009bca32be46f32c4fbb0cb0fd58607696a877a0003f6a8e84d2a0901e6f1ecc931af7282f7e3e3f176ef1eabbeee57866c102bdcdd659db6e1b210a3e8c25871ab8f62ac7d9c5bcd685193d56624f1218dfdcd951fd1a06a0ca22e5aed396969b40d079cdccc2bda737a0d9747bcfb200ad75369e128b97e421f22ac1924aaef730d4f1d77f4009b17d49c515a227c1e3656d6b3a2be1974043d505ebb39deb47e415ee038ca19a8c82867a737eddeb6e266c0c94863e9ec797955f3184f1d1022af2e46933bd626f6f6d396c23a8248d5fe7995f7187c8a77106805080731dcc5f9f555a5a96aee5f104ac2cba75f3fd5bd8a0a229bdd5ee6a02f50d04f27c8e7210049a1e82658bccf7e80597dd79", "3c", "e3b544090d88f8f39b600cdfc6cf467ea8f21d8a9e8b547ffed07147d2bd6a8d1439d89fbc880608c088eb90f368accbf8f2884086a08c727f442c19ded562e29f52018337e6d953bb4072cd0d3e7c17dc1dcb7461ae154d4a6b0b691b9c28c60c0cf94b013cac173742c3b7e5dea3fd0686b4ec333c353b65913fff57e8c6d0f245c05fa1aa8f9ab8d454af890fa967185a5610c07b231a9d284d53be845655ece0b72c7ba5d6089415c3b89a8647ba013d6ed75d2e1be33a0070c5725a9683a934318d722afde77368e3e81fb97d1a93f465d38b47e675017ba0c208830e3923ca84b589ec809513afb5396dc814c3009bca32be46f32c4fbb0cb0fd58607696a877a0003f6a8e84d2a0901e6f1ecc931af7282f7e3e3f176ef1eabbeee57866c102bdcdd659db6e1b210a3e8c25871ab8f62ac7d9c5bcd685193d56624f1218dfdcd951fd1a06a0ca22e5aed396969b40d079cdccc2bda737a0d9747bcfb200ad75369e128b97e421f22ac1924aaef730d4f1d77f4009b17d49c515a227c1e3656d6b3a2be1974043d505ebb39deb47e415ee038ca19a8c82867a737eddeb6e266c0c94863e9ec797955f3184f1d1022af2e46933bd626f6f6d396c23a8248d5fe7995f7187c8a77106805080731dcc5f9f555a5a96aee5f104ac2cba75f3fd5bd8a0a229bdd5ee6a02f50d04f27c8e7210049a1e82658", .Okay}, + {.Shr, "350148baea422641ab85a0b4ac64bbe928c8c5910487c0405ac60687b5b265cb4320b4f3b04311b854e94db8f45f1ae65087688445269b65c25fa2b61a429f23e0b0cdf2c18840dfc9a02f46d244938d5f7faa40659b3ea5f333c1c12744e0e8b20f3c934510dc47b1d558cb9bfafea15e41d63a7f90f93beee1c9f505373e9b870d72d69495323c313589ebe7f4565e8a6f93126ae872c791b65fc603b56e54cb8b89c01101a5a2dd961eaacb655de165d7bb5609ce9e5a564be78bfe3b602a64b912aae612374ac1af0f8eecbc5556135e469ab8876dc18fc997fd482dca62f8349d74d8f706aca0a4d26675d03b0a4f9629bcf1f93f273a218d41227a6cc0457dfb917a582a72e70784a94f3047d6c78f3ea1a3ee4fd628b57d85b820f816166df90440f5ea5017b463740ce6823128f95f787aa14236431cc6431a0f7ab05e7fb9459b1674f7b635144ae25c77b338da06538a4f7caae2781a9600378f20f7406c810aeaf326e3b4d494cc4ee42bf1f7780ff8fd2ff91f073afe578f479096bc49a1ecc2398b0881aaca27f5e387481a12ff1f9b36d852bc7f5afbcce4c9726a203a81c2c349eeaaa4206455d4f180ebf0f71be50ae543def8b5e378e8a2f90dcd1f12de9288a4b37e79f2955be636e7e56e86ce75a2c8f99c65d5fb82a92cdf9c7b556dd8056ad8442da94ae54eb087ca91bf9222ab42b344c1c8a77604", "3c", "350148baea422641ab85a0b4ac64bbe928c8c5910487c0405ac60687b5b265cb4320b4f3b04311b854e94db8f45f1ae65087688445269b65c25fa2b61a429f23e0b0cdf2c18840dfc9a02f46d244938d5f7faa40659b3ea5f333c1c12744e0e8b20f3c934510dc47b1d558cb9bfafea15e41d63a7f90f93beee1c9f505373e9b870d72d69495323c313589ebe7f4565e8a6f93126ae872c791b65fc603b56e54cb8b89c01101a5a2dd961eaacb655de165d7bb5609ce9e5a564be78bfe3b602a64b912aae612374ac1af0f8eecbc5556135e469ab8876dc18fc997fd482dca62f8349d74d8f706aca0a4d26675d03b0a4f9629bcf1f93f273a218d41227a6cc0457dfb917a582a72e70784a94f3047d6c78f3ea1a3ee4fd628b57d85b820f816166df90440f5ea5017b463740ce6823128f95f787aa14236431cc6431a0f7ab05e7fb9459b1674f7b635144ae25c77b338da06538a4f7caae2781a9600378f20f7406c810aeaf326e3b4d494cc4ee42bf1f7780ff8fd2ff91f073afe578f479096bc49a1ecc2398b0881aaca27f5e387481a12ff1f9b36d852bc7f5afbcce4c9726a203a81c2c349eeaaa4206455d4f180ebf0f71be50ae543def8b5e378e8a2f90dcd1f12de9288a4b37e79f2955be636e7e56e86ce75a2c8f99c65d5fb82a92cdf9c7b556dd8056ad8442da94ae54eb087ca91bf9222ab4", .Okay}, + {.Shr, "7cae7f52e32241126f991defa2f7d801db7bd444fa3c464088306bf46f35b34a15eae968ab90e16ace0433b940dd2f3e844e5de03a7200711fd1e1c00c51d403c5034e7e8e9a0a441fd54ec07736fd7bce5656b0fd5f3276a21ac698cec0505da0904874aba8aa4778bc8697ca4c485d6cd9422965c6fb4721fec252d31946c9c6fd4d936abbd5a96db5053e65f41b3c09fec82f067bbdc13a939de72de79ac445f260b10149b0b581b20d14a75539f1af5a07dc0e34e97df7d17ca832de04ef6856156d1b4f8c43104d244d27b9dcca4218021b261d2a989f5f008b000ab5dc6b9badff3676b5e6ee08e0c21d7f95c5f5159c6fc884f6ee9161a9a32331187bdba7bf3b28d0ab3378b0c327c70321954a4eb538e224c989f68f3f826ddd0e8e3565dbe66d145e06921bbcfb55ccbdc2d78ae3d6b967a6e2cadcb06fc8d7653ac7ee3107ed0a80b58d11ef281b71a8d5f76dc7e067ae4fa6391fc1024a2d7cb3dc61c2ab07c157b3956b578079ba20aa19bb4e30ab77818ed398ffd0285ae34da9231183914914484f97d9483e414243f63dcee65dcf9d4f156f4cc43cc34c8d59fd3d8dee322b1b8ff6c8653a93320b104f6e923c97ffc1437ce87da35087960acff509cb51f881da57f25476b60f9d6ad454ece008680f463f502abc1b318900500d2b790abf1d5f71ab3e33737916ea753af97314cf13f34a7969cc100ea1", "0", "7cae7f52e32241126f991defa2f7d801db7bd444fa3c464088306bf46f35b34a15eae968ab90e16ace0433b940dd2f3e844e5de03a7200711fd1e1c00c51d403c5034e7e8e9a0a441fd54ec07736fd7bce5656b0fd5f3276a21ac698cec0505da0904874aba8aa4778bc8697ca4c485d6cd9422965c6fb4721fec252d31946c9c6fd4d936abbd5a96db5053e65f41b3c09fec82f067bbdc13a939de72de79ac445f260b10149b0b581b20d14a75539f1af5a07dc0e34e97df7d17ca832de04ef6856156d1b4f8c43104d244d27b9dcca4218021b261d2a989f5f008b000ab5dc6b9badff3676b5e6ee08e0c21d7f95c5f5159c6fc884f6ee9161a9a32331187bdba7bf3b28d0ab3378b0c327c70321954a4eb538e224c989f68f3f826ddd0e8e3565dbe66d145e06921bbcfb55ccbdc2d78ae3d6b967a6e2cadcb06fc8d7653ac7ee3107ed0a80b58d11ef281b71a8d5f76dc7e067ae4fa6391fc1024a2d7cb3dc61c2ab07c157b3956b578079ba20aa19bb4e30ab77818ed398ffd0285ae34da9231183914914484f97d9483e414243f63dcee65dcf9d4f156f4cc43cc34c8d59fd3d8dee322b1b8ff6c8653a93320b104f6e923c97ffc1437ce87da35087960acff509cb51f881da57f25476b60f9d6ad454ece008680f463f502abc1b318900500d2b790abf1d5f71ab3e33737916ea753af97314cf13f34a7969cc100ea1", .Okay}, + {.Shr, "a421d2c4bcd4a59630859ae724712252e5124a83606742be764c7f0e555d338d95dac19fda218871da08e7c694dab740edfde0212fe46eb668a7b4cf894b2b8bcfe1b384b92c09892de099df1cef4932cc67a079712b78a8d57b509ad2548fbc7dca4a3e1ddab56b16f92f588f3a1dbc6a6ab81bd7cc25dfcd94c872ff3dd6192a81bcc07493c3e57c7b43c10f2cdb7a708d6937532f440b9f2044c60b37b7c24922cd5e28809fb7cbd4aeecbaa946ea05f303cf4c7d339fcd7809b47ac46e0eeaceab1e90ebcef32d23573950d5e2b207900513b5bbdf6b970b3ad0a358b3985f9df64c18cd3313d0ce32008972c310e3a88e62a40cf64d65f2b08130a94a75d6425401df237108700ebe90a08bf233f2f304c226a6d454550bb89972839d987c64735acac40a5aa698b7089d570d9a96c340ad3d1c314028137b209c8ef7a56b740de43d4ba0df8f32c9a2aa527343d4990bc3032661144802af35b3ed0c8b41d035d27523766719cf9e6d778bb11a4ceae3fc09f51775c29b213a99e3c9e7ddabed3e41549ee947d3181ab1862a0d227e0cb484db3c2d22465c0f03248a76cfbba9e535bc631676989fbb180da098a8137d91da1a58c4e4127122806d0001f3327040c689b8b5773b9d1a01ca4607f6baaa3163847baf70b012edb097235106e7476375da25eb2400619b30a767d5f4bfb707a4f58b9bcb4d7d5d2930d19c", "1e0", "a421d2c4bcd4a59630859ae724712252e5124a83606742be764c7f0e555d338d95dac19fda218871da08e7c694dab740edfde0212fe46eb668a7b4cf894b2b8bcfe1b384b92c09892de099df1cef4932cc67a079712b78a8d57b509ad2548fbc7dca4a3e1ddab56b16f92f588f3a1dbc6a6ab81bd7cc25dfcd94c872ff3dd6192a81bcc07493c3e57c7b43c10f2cdb7a708d6937532f440b9f2044c60b37b7c24922cd5e28809fb7cbd4aeecbaa946ea05f303cf4c7d339fcd7809b47ac46e0eeaceab1e90ebcef32d23573950d5e2b207900513b5bbdf6b970b3ad0a358b3985f9df64c18cd3313d0ce32008972c310e3a88e62a40cf64d65f2b08130a94a75d6425401df237108700ebe90a08bf233f2f304c226a6d454550bb89972839d987c64735acac40a5aa698b7089d570d9a96c340ad3d1c314028137b209c8ef7a56b740de43d4ba0df8f32c9a2aa527343d4990bc3032661144802af35b3ed0c8b41d035d27523766719cf9e6d778bb11a4ceae3fc09f51775c29b213a99e3c9e7ddabed3e41549ee947d3181ab1862a0d227e0cb484db3c2d22465c0f03248a76cfbba9e535bc631676989fbb180da098a8137d91da1a58c4e4127122806d0001f3327040", .Okay}, + {.Shr, "e3c3a88374613259d113c4a69695b9541fdad2105940af9879204ac0e1ae02a546d61c8002d9866daf821ac8443d3f3f121e46b87a4d4ad6cd13c5f4618acf86e3dfb84765b5e05756b4193de40349872e1abff6cfe5867aa571c2790b73b811b873365ab9d2638bf2ddcae9cc6945723d5a6c6d65c5c7749a34f2397bb7d26d11365390647580f3a35e7c36a99527681cdef420e42d7032b0cdaca6739abb53b5aec6a29128fd7316e809312bbeec261996ca3f5bef49918e5b9bcebba645a8e7d6e0962bfd1581f8cfcf7183ab917a22c4f196a17af656d5398142a723199a2c3a239358627722b9b8ac29dda1b012e145d46cd85d9f559f497c6dca1877cdff239c1ddc16cc8ac15788f92c1d78ffb2ac7c8b7100e2a20e6b8dc1b051ea1533f0ba49883f76c01d3a82f914b376e227538d0f67681cd5463ddeaeb55440f9605532ece04a29486d1484082a04c986051fd44aa533e9a0922e0cbf2325edc60e52db24dcddd33d8af97f16f1ff21c867c90b283a1c7f624d9b056449e8e8f02997185c4e05f4ac96ecf95bd29d73d8df6536b54cb2da18333a1db331ad3f99b48b8cebfad4fa6db2109a66b79083be2d293b04a752305f86549eaa2d3c6d3318a820d42adb313b614fe8e02dea5153ac9d665d6bc6129211f07d14cafc3e05b21c7763223a444935e940aa13694c09fdf602dca56f6948608eb0ed019ee4bb", "12c", "e3c3a88374613259d113c4a69695b9541fdad2105940af9879204ac0e1ae02a546d61c8002d9866daf821ac8443d3f3f121e46b87a4d4ad6cd13c5f4618acf86e3dfb84765b5e05756b4193de40349872e1abff6cfe5867aa571c2790b73b811b873365ab9d2638bf2ddcae9cc6945723d5a6c6d65c5c7749a34f2397bb7d26d11365390647580f3a35e7c36a99527681cdef420e42d7032b0cdaca6739abb53b5aec6a29128fd7316e809312bbeec261996ca3f5bef49918e5b9bcebba645a8e7d6e0962bfd1581f8cfcf7183ab917a22c4f196a17af656d5398142a723199a2c3a239358627722b9b8ac29dda1b012e145d46cd85d9f559f497c6dca1877cdff239c1ddc16cc8ac15788f92c1d78ffb2ac7c8b7100e2a20e6b8dc1b051ea1533f0ba49883f76c01d3a82f914b376e227538d0f67681cd5463ddeaeb55440f9605532ece04a29486d1484082a04c986051fd44aa533e9a0922e0cbf2325edc60e52db24dcddd33d8af97f16f1ff21c867c90b283a1c7f624d9b056449e8e8f02997185c4e05f4ac96ecf95bd29d73d8df6536b54cb2da18333a1db331ad3f99b48b8cebfad4fa6db2109a66b79083be2d293b04a752305f86549eaa2d3c6d3318a820d42adb313b614fe8e02dea5153ac9d665d6bc6129211f07", .Okay}, + {.Shr, "5cb35e51e2db45a2302e1db220e6c4802e6c0ba920f02ea491a08750730545d1d5e37d52ab74d6abbf8b6c65ab09646c35b0b0a15a73f81d16223256e59eb8b94572be7642fd3bf7320331ff34dd947a9f05da1a7af14f96e6e1828d25227a6ca6ad6309c6c0f9ba4ed89544dbf055a445a2137abbfdf998ca9a8ddccb5d6555dcf8ccee9ec8a2847eee5de8500b12fb6a2a78f394adbaa60be0745c90f0a56f6112ef13f8c71ec4eae40f4285966ee4c273ba89a5107b68057557c903248f6b4f73b9b397a035f80ea05ed78586343a409f80ae85c53c20c60d1dc6ca7d4b89fb6e4166a1938c015d2cb69c374e1fdec2ffde4ea747dbcd332ef9d1f8f1177786f688a4ce8ec987b61027bcbfff1881472aacdae03acc02a4bb974f03044748ad18597aa68578c0dbc50624b8d2669a2d0511be45599755fb5f0bda09c6e39da436e32991267c28363dc915c31f6d29931ac41ec10fbc20220eac29b2dc80c46bc7ad0b4554056fc923512da76ba71bf76ea1af131b6816839ff8f35ad2fcede058e26d2420b8b17d8a9fd64958deb6eeaada7c81194bc21197c63cedb72022bae21c8ad5ab324cc6e0bdc569b32373b2c4d86ee1f69e8be7daf21729a349551691ea676430b9ac8c1da39c9dde1f488a59842354984592a271b2b34c7e61f662ef95d8a874cb88aecb001a806615ddeda95a175cb795ba4b40cb9ae2891e6", "1e0", "5cb35e51e2db45a2302e1db220e6c4802e6c0ba920f02ea491a08750730545d1d5e37d52ab74d6abbf8b6c65ab09646c35b0b0a15a73f81d16223256e59eb8b94572be7642fd3bf7320331ff34dd947a9f05da1a7af14f96e6e1828d25227a6ca6ad6309c6c0f9ba4ed89544dbf055a445a2137abbfdf998ca9a8ddccb5d6555dcf8ccee9ec8a2847eee5de8500b12fb6a2a78f394adbaa60be0745c90f0a56f6112ef13f8c71ec4eae40f4285966ee4c273ba89a5107b68057557c903248f6b4f73b9b397a035f80ea05ed78586343a409f80ae85c53c20c60d1dc6ca7d4b89fb6e4166a1938c015d2cb69c374e1fdec2ffde4ea747dbcd332ef9d1f8f1177786f688a4ce8ec987b61027bcbfff1881472aacdae03acc02a4bb974f03044748ad18597aa68578c0dbc50624b8d2669a2d0511be45599755fb5f0bda09c6e39da436e32991267c28363dc915c31f6d29931ac41ec10fbc20220eac29b2dc80c46bc7ad0b4554056fc923512da76ba71bf76ea1af131b6816839ff8f35ad2fcede058e26d2420b8b17d8a9fd64958deb6eeaada7c81194bc21197c63cedb72022bae21c8ad5ab324cc6e0bdc569b32373b2c4d86ee1f69e8be7daf21729a349551691ea6", .Okay}, + {.Shr, "85ff660cdf62b184406d77e3b0b02651d094e6dc96d2bfcbea5b7bb6dfbb36a85788406abf43078355c597f50fbfbef650559b267f113a3111a6b764d36615c9f2b48b7d8a42784c0008d8013daffe5d0f6e7f3787ea5e609a55c6dceb7b6b7695a9c2dde0c2b17e866b9e8447d5daff6b090e8ea28fe59407702440c0b39d35b47738b62eb49f9e8839276394ca6d3a418b79ea814591be563f050dc3d8dd356fd0126bb44856228e12a1f0b8252c782a1ba015acab54ec735e1edb8f8469a056437e035d3d19475100919e0d353f48ff625d48073ce454dbe1507fb15af092201e0290f7f1cc2cc257a6d7a62b84b30af39851e2222e219b4672e03c77cf8c641ef1ab89be2ee62c9bfc8101c4b195566969b1369af7cf7b7a492cb6db236568384e1d7f9f20d562a23ba1a3247a561b12fa55258e38ec18612fd64b3a2f508b5059346dbfc515f031d4fa850ba3362a390a0cfb5c8fb2162b0b7f4a49d40a8cb11402cb594862346f421c759a591509fec1b9ad4767afb03765c87d07a48b04bdb89e3cdef683e1f1b5c1e8f7e9b3b91f4081a1b6e8168365be29febfe54240bef63668cf4ad276067596a22304558efaa9a86607b4c8d580c72cfed08e5fc224fb2039da8456e450fced25f7827e05db7f8c126b0fbfe09d0851190e9ae6f3dfbf2a9a1a3fca276b02dffbe9928a2e236cdf2238219b36066aec8908bd2e", "3c", "85ff660cdf62b184406d77e3b0b02651d094e6dc96d2bfcbea5b7bb6dfbb36a85788406abf43078355c597f50fbfbef650559b267f113a3111a6b764d36615c9f2b48b7d8a42784c0008d8013daffe5d0f6e7f3787ea5e609a55c6dceb7b6b7695a9c2dde0c2b17e866b9e8447d5daff6b090e8ea28fe59407702440c0b39d35b47738b62eb49f9e8839276394ca6d3a418b79ea814591be563f050dc3d8dd356fd0126bb44856228e12a1f0b8252c782a1ba015acab54ec735e1edb8f8469a056437e035d3d19475100919e0d353f48ff625d48073ce454dbe1507fb15af092201e0290f7f1cc2cc257a6d7a62b84b30af39851e2222e219b4672e03c77cf8c641ef1ab89be2ee62c9bfc8101c4b195566969b1369af7cf7b7a492cb6db236568384e1d7f9f20d562a23ba1a3247a561b12fa55258e38ec18612fd64b3a2f508b5059346dbfc515f031d4fa850ba3362a390a0cfb5c8fb2162b0b7f4a49d40a8cb11402cb594862346f421c759a591509fec1b9ad4767afb03765c87d07a48b04bdb89e3cdef683e1f1b5c1e8f7e9b3b91f4081a1b6e8168365be29febfe54240bef63668cf4ad276067596a22304558efaa9a86607b4c8d580c72cfed08e5fc224fb2039da8456e450fced25f7827e05db7f8c126b0fbfe09d0851190e9ae6f3dfbf2a9a1a3fca276b02dffbe9928a2e236cdf2238219b3", .Okay}, + {.Shr, "181d263b5a3cd991af1fb2a9bba83ad372c102d06c48207542a3b348df8b7bb3f7704d610b8be155593a18dba6d002904d0a84d0fa070a02b4683bd377b555ef526d65be8cd8abde241b571991cb821e747bc11a7e3e7e1ad2478512e16b7edba5c98308af5e995d7ab9ea1ec921c88eaca8e2f046654663c5d35f65c34e28092fcd14878a32489d23385b7b645564b7d6fefaf5dfca2eca8dd17f62750254348783544d6a9397214a0555c3636cf1ecc58c8d82b8a817cec8164c0289dc91c049376e3a36563a9f92cbdc1493274a8510d9807777ef75383aa95a3104d72a3752b22fd92c3916311323cd8aa772017cc42675636322f74a8e6745dc980eacf09747557e1672e89b364e1fd22799bebb3a3c79d30eab6d793e01ee173ecf5019795aae2709de37e735304dff318fee8736cd17b2632ef5c29ff6c09ea8424d9223b02751d89a0d4a8eb43d0d4a2d5394ca8f01bc0f8f5366bc277e5a7f4c06ab8612991f877896c5ea65f8ba2cbaf528477f6c3151bec5aefade5967773d0ae1f5f2bb1b151687e5a1985928009ab7b1cae9007583d2a522cadd6a192564e2ac753c3f8a2d5676c9dd86b9ed64ee0fead7dcc1ead74f36fddd82be83dbf1983b0c2e0b0bcb1271ede6c4a4f75f87165c251d58224e2d9e58e5adb2fdcd982b9be362ea4c9ff31e4a634bf69e495a02db9115f7ac715c3b56b14fe184e8e2db15", "f0", "181d263b5a3cd991af1fb2a9bba83ad372c102d06c48207542a3b348df8b7bb3f7704d610b8be155593a18dba6d002904d0a84d0fa070a02b4683bd377b555ef526d65be8cd8abde241b571991cb821e747bc11a7e3e7e1ad2478512e16b7edba5c98308af5e995d7ab9ea1ec921c88eaca8e2f046654663c5d35f65c34e28092fcd14878a32489d23385b7b645564b7d6fefaf5dfca2eca8dd17f62750254348783544d6a9397214a0555c3636cf1ecc58c8d82b8a817cec8164c0289dc91c049376e3a36563a9f92cbdc1493274a8510d9807777ef75383aa95a3104d72a3752b22fd92c3916311323cd8aa772017cc42675636322f74a8e6745dc980eacf09747557e1672e89b364e1fd22799bebb3a3c79d30eab6d793e01ee173ecf5019795aae2709de37e735304dff318fee8736cd17b2632ef5c29ff6c09ea8424d9223b02751d89a0d4a8eb43d0d4a2d5394ca8f01bc0f8f5366bc277e5a7f4c06ab8612991f877896c5ea65f8ba2cbaf528477f6c3151bec5aefade5967773d0ae1f5f2bb1b151687e5a1985928009ab7b1cae9007583d2a522cadd6a192564e2ac753c3f8a2d5676c9dd86b9ed64ee0fead7dcc1ead74f36fddd82be83dbf1983b0c2e0b0bcb1271ede6c4a4f75f87165c251d58224e2d9e58e5adb2fdcd982b9be362", .Okay}, + {.Shr, "ef1610fe1883956a648f15731b5ab7d0b8479756debff7064c9a947fa4f4d893931b45cb7a184cb343dd5cb084a1080d5f28e3e35ccbea4130cf45ca11cd1ef13c52597df90a0eb3f7e947af781879685263705705c945cf3ce2a08a8e61c6b8e6c85319c6579d3be0632cf3cdacfc9e32945018cd4d99a178aafaef77c1bd126cd7006a01ab8b7875a2b93d60a867a8ff281d0c1f90fab7c193591bbbe38755cdd57ceadf1ec566fb6323f3410ecaf9893c012f0c3a56264ef996118351fe0fd57be79ec0393107ea3865d50b4d854155658f9b6232e82d6f5b28307ee3af8eedc4e59df0ab48165a240dfd5027d865146337a55edf7025ba7d6ce879ec838cae86377c1cfd55a3c4f52f47b84efb74017380e95bff2db0de7c7b193d60fa8b72c4a95404433d88ace889bf7fe337801b31291f625613f37a192b0cd8536ec814cf567f2a8ee0e4ecfd2767697db76941d8e393a5e77091b15379cb1afa46c8d6c43a8e6d402ca5ff01c92e354e29ee2a32a48630838822480b1f9b40082e48f4ba7634b014e21bd40062cd1f83cfee62c4314c621d879448ed4e83f9a6bee2f848f7bf0d3b86f5ecd3b91a33de9baaa922b4f11e7a7e60b64150fdcf98e5ecd58d5027222ade2178e7b5461f618826df6a61b84b0b4f6a8947276e56e5348212a6b740651976831e190e2a82e9c50181c8b585ab2ec50cb70d0434f3bb7ee0", "168", "ef1610fe1883956a648f15731b5ab7d0b8479756debff7064c9a947fa4f4d893931b45cb7a184cb343dd5cb084a1080d5f28e3e35ccbea4130cf45ca11cd1ef13c52597df90a0eb3f7e947af781879685263705705c945cf3ce2a08a8e61c6b8e6c85319c6579d3be0632cf3cdacfc9e32945018cd4d99a178aafaef77c1bd126cd7006a01ab8b7875a2b93d60a867a8ff281d0c1f90fab7c193591bbbe38755cdd57ceadf1ec566fb6323f3410ecaf9893c012f0c3a56264ef996118351fe0fd57be79ec0393107ea3865d50b4d854155658f9b6232e82d6f5b28307ee3af8eedc4e59df0ab48165a240dfd5027d865146337a55edf7025ba7d6ce879ec838cae86377c1cfd55a3c4f52f47b84efb74017380e95bff2db0de7c7b193d60fa8b72c4a95404433d88ace889bf7fe337801b31291f625613f37a192b0cd8536ec814cf567f2a8ee0e4ecfd2767697db76941d8e393a5e77091b15379cb1afa46c8d6c43a8e6d402ca5ff01c92e354e29ee2a32a48630838822480b1f9b40082e48f4ba7634b014e21bd40062cd1f83cfee62c4314c621d879448ed4e83f9a6bee2f848f7bf0d3b86f5ecd3b91a33de9baaa922b4f11e7a7e60b64150fdcf98e5ecd58d5027222ade2178e7b5461f618826df6a61", .Okay}, + {.Shr, "951068d8b6ea1f2f3cdafd2290e31db7d0f44872b0f9c9baef9ad4c404ca80d85375a533e6187967f49e1428965ca6048a2e7a539328c2532e8df5ce33166532b49bb7ec21694533e8ec01d48554de62d896c06b7d804d102f14ff26bc2f0e031e3ba2bdcfadbfd80e3b9b6d84d68d23a9e67ee28df59b97381b6dc5ee0fefc71453067207e52110fdd67596e195f8910f54615c96e46bad457f0438f976060c043e1a3cf2d385ff994c70d69343cbd212f83e98c490fd5dcfab0dcfb0f8a75b3512f2f0edcff1bef3c4fa3741c6318fa890f3128b299e9bd3ac9e45e0e986a44da86a1b5a0f1ea2f04903ad87d409b440a0d664096606a5edb7fb82a410f063a684411932c78709bc781b372c3ebc639cd3a7f6ddb90f873fe3f041266b971563726d53efbc4b9ac94ed55dbcb5410fff5acf1ce7720738b0ab20b3cc3485ce6dd70c9ed6948c32fd5884f5a14917b164b882e71d82ee2a9887e4861ef5311568364c350c6fed999774e53959c07b00a73c3c5da2ce62c06aa4b252e3cabbe53bc42bf2d0a9c8f62fb5526f6f8cdaa668d7827c73b1624de2323fc96b726e626aba0b3aa962ccb4bfbc240410b7cf2f762de70817f070e23997a997d870d2bec325729c9371e05bacb6fec3c4fea6e094e49b792138fe792dee80dc9c2efbb7661184926c05ce8a17d9206711fe16387554299ab68e33553acdea4aad8eead5", "f0", "951068d8b6ea1f2f3cdafd2290e31db7d0f44872b0f9c9baef9ad4c404ca80d85375a533e6187967f49e1428965ca6048a2e7a539328c2532e8df5ce33166532b49bb7ec21694533e8ec01d48554de62d896c06b7d804d102f14ff26bc2f0e031e3ba2bdcfadbfd80e3b9b6d84d68d23a9e67ee28df59b97381b6dc5ee0fefc71453067207e52110fdd67596e195f8910f54615c96e46bad457f0438f976060c043e1a3cf2d385ff994c70d69343cbd212f83e98c490fd5dcfab0dcfb0f8a75b3512f2f0edcff1bef3c4fa3741c6318fa890f3128b299e9bd3ac9e45e0e986a44da86a1b5a0f1ea2f04903ad87d409b440a0d664096606a5edb7fb82a410f063a684411932c78709bc781b372c3ebc639cd3a7f6ddb90f873fe3f041266b971563726d53efbc4b9ac94ed55dbcb5410fff5acf1ce7720738b0ab20b3cc3485ce6dd70c9ed6948c32fd5884f5a14917b164b882e71d82ee2a9887e4861ef5311568364c350c6fed999774e53959c07b00a73c3c5da2ce62c06aa4b252e3cabbe53bc42bf2d0a9c8f62fb5526f6f8cdaa668d7827c73b1624de2323fc96b726e626aba0b3aa962ccb4bfbc240410b7cf2f762de70817f070e23997a997d870d2bec325729c9371e05bacb6fec3c4fea6e094e49b792138fe792dee80dc9c2efbb76611", .Okay}, + {.Shr, "c1219c31211ce1e9b587e1700c99b9d0766b014ee8a4e5c8fab11ceb1614db588b021d574349bbdc9fb7309d0a798158c01697f677187c01dbdf745136907655476e8ccbbdd2b37c51ee02d217e6ad3c9a47e3f6f762b1850a5650c832077010c0f4985c2411894c0d90252b2c0a1c1054556c64f2c5bee6a6b06dd8152a97553aeb7c24f6b0292395866c6103938066cacedba3a3542f379807aad2af1ba1703419a5dd08b3d594248bcc67ebb3b48dd8f8479eb0fcc5805dc548066ddc29d90572526ab9b4c929570e1224131b3075d077f9b7e6d146ef3324ef57a5db5d5d9fdc6df898a9465791dc2cafeba49433d82f3884a18c1a22f62241711171c4ced906ace7f88b9c21a36a197ebac8f91e5783ed7477b1f0e99a49bfd9fceb752499f68158889984df235a874ae88063a1e65106327067a1b9ad642f5cbabb62ef13a184a1a21ab17353712d2441e30e819bda197c9e49d55dc7ef969c8e92d1d26b428adaf8e12e00c530f1d014f954afe09c6bfaab8aedfe031df2588dba9ca2c4895359009f7a635b034eb4f290b14252407587fb0f366375360a43dca5ed670526ffe61e704ff6d05960cea17149ec220155e26f82302e2697aef7b33939746d998c04d91360c183434a5ba4af2727f2773dcb3e80544e0662d130315e4a4f406e04b7ba6c5aaccfbf89244636439f0f7ebae14a6923734adb8a9a20f12e0e", "1a4", "c1219c31211ce1e9b587e1700c99b9d0766b014ee8a4e5c8fab11ceb1614db588b021d574349bbdc9fb7309d0a798158c01697f677187c01dbdf745136907655476e8ccbbdd2b37c51ee02d217e6ad3c9a47e3f6f762b1850a5650c832077010c0f4985c2411894c0d90252b2c0a1c1054556c64f2c5bee6a6b06dd8152a97553aeb7c24f6b0292395866c6103938066cacedba3a3542f379807aad2af1ba1703419a5dd08b3d594248bcc67ebb3b48dd8f8479eb0fcc5805dc548066ddc29d90572526ab9b4c929570e1224131b3075d077f9b7e6d146ef3324ef57a5db5d5d9fdc6df898a9465791dc2cafeba49433d82f3884a18c1a22f62241711171c4ced906ace7f88b9c21a36a197ebac8f91e5783ed7477b1f0e99a49bfd9fceb752499f68158889984df235a874ae88063a1e65106327067a1b9ad642f5cbabb62ef13a184a1a21ab17353712d2441e30e819bda197c9e49d55dc7ef969c8e92d1d26b428adaf8e12e00c530f1d014f954afe09c6bfaab8aedfe031df2588dba9ca2c4895359009f7a635b034eb4f290b14252407587fb0f366375360a43dca5ed670526ffe61e704ff6d05960cea17149ec220155e26f82302e2697aef7b33939746d998c04d91360c183434a5", .Okay}, + {.Shr, "b267b4a9df920db387247067e4114dff76b32842efcae32f1687258c944cfd7ab9348deff4452bfd3c8286fcf08342b34fac6316747f339fb8283e6b17e8f111f09b170e3f7ee6659c178598513390567c4a7ce296b65a44e42a283a4fd0894a0bf5a41f132139aa1aea1874abf458d4890f0430bec116930e80d17330e603168c0c3df5127a2c153b050e8e81cbb5bcfa0fe5a1af84192e9e682ddaff705005b4a7b7fb7bbfb726ad3bb5b6a202901f12f807b721f44c2f204d5d0e7573e3c3c8d423a7fbe13716a44ce011154f8e5d36ae9942d3846c2a8d933a5d21347e89dc67171fe3c32ed07aa157faedfc3bc08495f11fcad3784f5b9cdc2283a3d403f064a16e84fc4351f4af8e7030662c0e4a347081e0eefc57d4176b3391e7a990e2d6398caca8cb64d6d3e3b5be04676a3473541eb4e4379df8ab4507e628cb4377fc3e17c1078d21ac4de602c3bebdb0d5b59dda5044fa374ee37245ebff817363199cfe0b326bd6cb1c0ca7be83edc6c22ddc7eb06a4b0ba2bb9c50abc88d322aa49e1d17019b770515abe134a5b03f5eaf6be4aed83a2ac1c71f7ffb946f32f06461402b85500559921c59129e790978f9f8e2df368e4228e3b5fbe9ef17a376aced2f552361a9d07566b0825f2b4b46f0ffe24fc8345b1445219a91df650b4b4069ebeb3f7c281d61d640ae88fda98dc6d59ac32db19570f2d7f53cef311a", "1e0", "b267b4a9df920db387247067e4114dff76b32842efcae32f1687258c944cfd7ab9348deff4452bfd3c8286fcf08342b34fac6316747f339fb8283e6b17e8f111f09b170e3f7ee6659c178598513390567c4a7ce296b65a44e42a283a4fd0894a0bf5a41f132139aa1aea1874abf458d4890f0430bec116930e80d17330e603168c0c3df5127a2c153b050e8e81cbb5bcfa0fe5a1af84192e9e682ddaff705005b4a7b7fb7bbfb726ad3bb5b6a202901f12f807b721f44c2f204d5d0e7573e3c3c8d423a7fbe13716a44ce011154f8e5d36ae9942d3846c2a8d933a5d21347e89dc67171fe3c32ed07aa157faedfc3bc08495f11fcad3784f5b9cdc2283a3d403f064a16e84fc4351f4af8e7030662c0e4a347081e0eefc57d4176b3391e7a990e2d6398caca8cb64d6d3e3b5be04676a3473541eb4e4379df8ab4507e628cb4377fc3e17c1078d21ac4de602c3bebdb0d5b59dda5044fa374ee37245ebff817363199cfe0b326bd6cb1c0ca7be83edc6c22ddc7eb06a4b0ba2bb9c50abc88d322aa49e1d17019b770515abe134a5b03f5eaf6be4aed83a2ac1c71f7ffb946f32f06461402b85500559921c59129e790978f9f8e2df368e4228e3b5fbe9ef17a376aced2f", .Okay}, + {.Shr, "7b39dc97e2af3b40727ea5fb472b2cc7d9bed1fa38faf09741138fda938a2842a01404e567092b6b2a697210239388407f22a9905c0f872b4f19db9ab81ffbdd5582a7b6bba63e3ba36e7975bbc95349d5066ba9549a88a5baf53b1b859a263ddfb2dc2832b91bee00f565dd695612d0240a842e762d9eb89f585f04f865375f1737bfe3a94e4c7fbe9b6d81c177154c5350a376b643b2a172d7265fc8af0729fe8a19fb38fe77bb3270b4b6746723a6cb969201f89bbb9b82e48f474f0b17aee4077e2c699d569dc5288bda4109767e406f1d17e23b3dbc7fd7efe34c575bda0982522877bf54ccc512233ec3121b454f34ccdc2cbc54978ec81daf9dea451dad69ce030a3b8b8524ce253d7d8b9a09bb2bea08e6f101a84e1c94f05b2a9adb51a3ad9400704cb49336164c3c9efd6be474be5212227ac28d3697943ae05ce7ec1f6fab18a068b85323f03ad343e4e82715519d6ca2be74b1c3e8fac3d30847161379378c6ad3dd14bb6c75d706b94d3c255b29380398e4b4cc1a67514310de15ff3914a3e027de31641c36126f9c9bc27b903acbacbf5e995d9c3b88b33008dc06b0fbd5794654e59da903403466dccab2d8ba7e3788a9cfffb01f24c6c7a851ccca8b594dcdf08a2a4cc0394616f92d5a9b879d4c71716a74d4e023d306a5e08807bd939720c5fed80a7031517f83058b81aa579c88df00baddca570c2a31", "b4", "7b39dc97e2af3b40727ea5fb472b2cc7d9bed1fa38faf09741138fda938a2842a01404e567092b6b2a697210239388407f22a9905c0f872b4f19db9ab81ffbdd5582a7b6bba63e3ba36e7975bbc95349d5066ba9549a88a5baf53b1b859a263ddfb2dc2832b91bee00f565dd695612d0240a842e762d9eb89f585f04f865375f1737bfe3a94e4c7fbe9b6d81c177154c5350a376b643b2a172d7265fc8af0729fe8a19fb38fe77bb3270b4b6746723a6cb969201f89bbb9b82e48f474f0b17aee4077e2c699d569dc5288bda4109767e406f1d17e23b3dbc7fd7efe34c575bda0982522877bf54ccc512233ec3121b454f34ccdc2cbc54978ec81daf9dea451dad69ce030a3b8b8524ce253d7d8b9a09bb2bea08e6f101a84e1c94f05b2a9adb51a3ad9400704cb49336164c3c9efd6be474be5212227ac28d3697943ae05ce7ec1f6fab18a068b85323f03ad343e4e82715519d6ca2be74b1c3e8fac3d30847161379378c6ad3dd14bb6c75d706b94d3c255b29380398e4b4cc1a67514310de15ff3914a3e027de31641c36126f9c9bc27b903acbacbf5e995d9c3b88b33008dc06b0fbd5794654e59da903403466dccab2d8ba7e3788a9cfffb01f24c6c7a851ccca8b594dcdf08a2a4cc0394616f92d5a9b879d4c71716a74d4e023d306a5e08807bd939720c5fed", .Okay}, + {.Shr, "3346079ea5a21c22e68bb7854aec8dade24989c1fdaf6e2750c0dc40ad042f0cb90ee14e8a062591867cabed9474eb416f670b0515767961d1c7972d26f1778609fd7eaee9b1e48246f90c784ba0fffb748342e61ad0023430450a149f25fc7fc5e6dc1aecf36ed5b69e343419e3bbe2407245aafcf6844312c090db6180d48175a1c2e76c9f74ba62ff782eed8d473e394cc5213faecec0ce523fcca8027ec5428ee3ecb41162dfb2a55917e186ec1b06658f00cdf24e4d8cb92169dacd62b0a9b305813a0cf2d218ad704512d8f5cf6bdd787c07e7442978e363e2b2bed50cfe6d7a1be6da863a3ab801a7341124bd4c548af9915d2354048ae88f000b27902811af0e9b4aa96100ccf237efab450c1c6ced5a3529f5e5a149680ce9d6c4ec840ef2026916892415b7cf9a96e639d9b227cefe3d143e7492b6ee88502deaefe646200132a8db3f531766fcc587d7632e2fd482e214e46c09646e50765a0ae4ac91f4f546b1348c578144c927a22a929da9b4073ef66b7e894197fe232a769afa19d0044637127a9f9f861b002204afde7f37a729941163b40243054ebfe12f2b8ebbdb49a433d650371ef2371db4c36aa377f257f494b9071307bf9548e5ad9902abe3290602ce15a0d12eb89ed7e7798c1d5d00ba7d17feb64f634d2e8470f6dae521650c456207eee78996d4e0ec751ea8d38672fb4ec6e995a9f6cc9b9e", "1e0", "3346079ea5a21c22e68bb7854aec8dade24989c1fdaf6e2750c0dc40ad042f0cb90ee14e8a062591867cabed9474eb416f670b0515767961d1c7972d26f1778609fd7eaee9b1e48246f90c784ba0fffb748342e61ad0023430450a149f25fc7fc5e6dc1aecf36ed5b69e343419e3bbe2407245aafcf6844312c090db6180d48175a1c2e76c9f74ba62ff782eed8d473e394cc5213faecec0ce523fcca8027ec5428ee3ecb41162dfb2a55917e186ec1b06658f00cdf24e4d8cb92169dacd62b0a9b305813a0cf2d218ad704512d8f5cf6bdd787c07e7442978e363e2b2bed50cfe6d7a1be6da863a3ab801a7341124bd4c548af9915d2354048ae88f000b27902811af0e9b4aa96100ccf237efab450c1c6ced5a3529f5e5a149680ce9d6c4ec840ef2026916892415b7cf9a96e639d9b227cefe3d143e7492b6ee88502deaefe646200132a8db3f531766fcc587d7632e2fd482e214e46c09646e50765a0ae4ac91f4f546b1348c578144c927a22a929da9b4073ef66b7e894197fe232a769afa19d0044637127a9f9f861b002204afde7f37a729941163b40243054ebfe12f2b8ebbdb49a433d650371ef2371db4c36aa377f257f494b9071307bf9548e5ad9902abe3", .Okay}, + {.Shr, "e7463e6dad18e70184768b6cecc9f5a2b35f3d04bfc57a66b0d4d8c7c6a9d9b26dc24d819ba181451744874111f1af6861d50ce32085674788743b573c38bdbea03d3937f62ec1e744d71cdb12394b8458784e8e77f79fe70420e96f063341cb5118be5b2e5ffb978b4603f57bd6f16d04f0decb507a148e3a874af6bf40b34c77f732b13d02b16aeaf825ec53159db21f91d92a126a04a78f2e5483be22c2174cd2eb5a496578f67e49ca72377e940050c2a0765a2121410aa01aeda75275e8858660030abdedb778ad942d52db5f548b1d536a85192a96c62a5b2e2865d2db5db5bf3a5cdb3c5a91e4eb5548d1857d1b4be35b447529307f1e76222f3f1dffcd6c69466f6ce12e19458d8d0e553e3f997adeff12b8fb8ca06ee6f8d741e642f2576ddee70e376c35532d3bf2d9cedd3596b0e662a2f20bdb2687d562219faf90c4886cce2ce48b7a37d0a303ee7ccc3e8d0bb43db271650d4a4b79246748a1c1b21475d5a07c253e7499fe4fe8f929fbca7c6a8ea39405fd693a97bd6b9a662be2efbc51516fbd0c2c593289e84f8712c267e3cfbdac28d49b3557cdd880cfb8a7bfe4b48bddfaa357672a5a46a41048a3c322f40a6b94c15cf3b9dc4ed3504eb9f846a4de5932ece2e4fcc6c3ed85db34e1996333725adb3ff9229ee93ea73a96c55587e87336cbbad6d04b5a722723ebd9283272c022aa5119b37fe25bac", "1a4", "e7463e6dad18e70184768b6cecc9f5a2b35f3d04bfc57a66b0d4d8c7c6a9d9b26dc24d819ba181451744874111f1af6861d50ce32085674788743b573c38bdbea03d3937f62ec1e744d71cdb12394b8458784e8e77f79fe70420e96f063341cb5118be5b2e5ffb978b4603f57bd6f16d04f0decb507a148e3a874af6bf40b34c77f732b13d02b16aeaf825ec53159db21f91d92a126a04a78f2e5483be22c2174cd2eb5a496578f67e49ca72377e940050c2a0765a2121410aa01aeda75275e8858660030abdedb778ad942d52db5f548b1d536a85192a96c62a5b2e2865d2db5db5bf3a5cdb3c5a91e4eb5548d1857d1b4be35b447529307f1e76222f3f1dffcd6c69466f6ce12e19458d8d0e553e3f997adeff12b8fb8ca06ee6f8d741e642f2576ddee70e376c35532d3bf2d9cedd3596b0e662a2f20bdb2687d562219faf90c4886cce2ce48b7a37d0a303ee7ccc3e8d0bb43db271650d4a4b79246748a1c1b21475d5a07c253e7499fe4fe8f929fbca7c6a8ea39405fd693a97bd6b9a662be2efbc51516fbd0c2c593289e84f8712c267e3cfbdac28d49b3557cdd880cfb8a7bfe4b48bddfaa357672a5a46a41048a3c322f40a6b94c15cf3b9dc4ed3504eb9f846a4de5932ece2e4f", .Okay}, + {.Shr, "100b7186598c885955cc0a0f0c1e6c8bcf44e5363096c1534627b20532e844b5827545fbb6508731972b878ace6af9a53395d44f5fee6cf4ada7ac3906d4e46d63a5c00950caa67c13f6c0c7357e9fd37002b5e42699ba938c91f219ed5a1eb9e336385cef1e2a21ce67b861081a3b058abec4f11202b7a941b17c2effc482da84398b603682511abb524500e45341cd4fba07d0cba4f3cadba8bd58b9ced34f8f0ccbf2397b8a55c954e9ed1671b7acde835ecd405ee4d353abd3380be2be78437f7821b8d3667b63265346a8f912335d8114b04328aaf7453dc91c12816b2ba91a403c6298107e7d6a4bb57c17da63e25b21d295825da63b5afb0d189c8339586c30e2cc6d6d4418f6b83e7a52a299b8426adc2b8af2e8aa2e8721046ad024335078383de6093f31193f3161a9d16f1686712503c4c51294887f39a69fc9ffa2a0dc962311a0c80392b5fe934cf89dccb8a42fd5249ac77fde4bffd7435ece4b035d2911cf802f00878bf18830df9c9ea720b56c03f8d164e9775edf2e04a9cbe990c5bfb68a80a60fdbab4667c83d37942ab729f51707108be3239d1d090f50756a9c6f3e0f1ce4866104d6f1b4fb5e65d49bfa22c3ae29483f3e890c38c21edaa4139afee848a8eda1b84b750cb71ada76c5d3ff774fb493575433b2f6e7c1bde997ac22f630f61d6b6f1b7170ef4d35d481b3c639462e2527ae333a9815", "f0", "100b7186598c885955cc0a0f0c1e6c8bcf44e5363096c1534627b20532e844b5827545fbb6508731972b878ace6af9a53395d44f5fee6cf4ada7ac3906d4e46d63a5c00950caa67c13f6c0c7357e9fd37002b5e42699ba938c91f219ed5a1eb9e336385cef1e2a21ce67b861081a3b058abec4f11202b7a941b17c2effc482da84398b603682511abb524500e45341cd4fba07d0cba4f3cadba8bd58b9ced34f8f0ccbf2397b8a55c954e9ed1671b7acde835ecd405ee4d353abd3380be2be78437f7821b8d3667b63265346a8f912335d8114b04328aaf7453dc91c12816b2ba91a403c6298107e7d6a4bb57c17da63e25b21d295825da63b5afb0d189c8339586c30e2cc6d6d4418f6b83e7a52a299b8426adc2b8af2e8aa2e8721046ad024335078383de6093f31193f3161a9d16f1686712503c4c51294887f39a69fc9ffa2a0dc962311a0c80392b5fe934cf89dccb8a42fd5249ac77fde4bffd7435ece4b035d2911cf802f00878bf18830df9c9ea720b56c03f8d164e9775edf2e04a9cbe990c5bfb68a80a60fdbab4667c83d37942ab729f51707108be3239d1d090f50756a9c6f3e0f1ce4866104d6f1b4fb5e65d49bfa22c3ae29483f3e890c38c21edaa4139afee848a8eda1b84b750cb71ada76c5d3ff774fb493575433b2f6e7c1bd", .Okay}, + {.Shr, "7df5b9f3e364bca13849d82428ac94be32760834c31c2acec5fbfaf03f4fb6dc563e3f3ce5dc3c3ddac1f052e9b917fcbbf0f2c2e9dd40c15501f04d7fa74c7b07932742131714208b18b1648ed491d52ba5e6d65ca14932e631e1492703428f4d22d7c844e447308c5619fd886f58777508da7b47a58d657d4b0e00aeb060d23dc8ec47d8dc656035a00e40a3ac841f9f311394a33edaaf88c5555d441bacc97044bca3be5d5ff6d87e9b053d3e6f868f5a5b123edee4cded0f6d9c47fb342608e779be37e63b0527ba3cac86f42826e4cd56805e4e3fc5702c65488232d3773b5bbf9f77793c43d2a5965efb92aa0b391c8a6dc3e37ec8c8585a3a8ec9e138635a308b7fef4666dde4bcb7bba0499c878bf0c23cfcd76fd6bb3a3cb0d54a9a8a526afe2a9ccecdc289b34adbc7d2087826e1d4719c675ffcfec077cb0a964a13bdc3a43c7f63fa0fa41ffaefea039f310d941ad30bc66d62d17a845944d3ec60a51e8d8954a02b189c344cb3d2101724bc4fee6f0db351da27b902589199171aaaed407da71c775c0d4827490715af552d5bbfa21fc7634374cd5b27ea69fad11ae23f4b0072c0042a578c870dbe51732de6457457b300dd7e3514bd27d9e66a72f2a9db584ed0235e188f4935dcef5c6e527cb55f406bd510c977430950310684c006772a6b6364a11737110ba606683ed0da728c659771d2797a364b6eec", "1e0", "7df5b9f3e364bca13849d82428ac94be32760834c31c2acec5fbfaf03f4fb6dc563e3f3ce5dc3c3ddac1f052e9b917fcbbf0f2c2e9dd40c15501f04d7fa74c7b07932742131714208b18b1648ed491d52ba5e6d65ca14932e631e1492703428f4d22d7c844e447308c5619fd886f58777508da7b47a58d657d4b0e00aeb060d23dc8ec47d8dc656035a00e40a3ac841f9f311394a33edaaf88c5555d441bacc97044bca3be5d5ff6d87e9b053d3e6f868f5a5b123edee4cded0f6d9c47fb342608e779be37e63b0527ba3cac86f42826e4cd56805e4e3fc5702c65488232d3773b5bbf9f77793c43d2a5965efb92aa0b391c8a6dc3e37ec8c8585a3a8ec9e138635a308b7fef4666dde4bcb7bba0499c878bf0c23cfcd76fd6bb3a3cb0d54a9a8a526afe2a9ccecdc289b34adbc7d2087826e1d4719c675ffcfec077cb0a964a13bdc3a43c7f63fa0fa41ffaefea039f310d941ad30bc66d62d17a845944d3ec60a51e8d8954a02b189c344cb3d2101724bc4fee6f0db351da27b902589199171aaaed407da71c775c0d4827490715af552d5bbfa21fc7634374cd5b27ea69fad11ae23f4b0072c0042a578c870dbe51732de6457457b300dd7e3514bd27d9e66a72f2a9", .Okay}, + {.Shr, "cba6d81c038a6a5aceb15a9f8c06aae25d978da9eee5e60e745f5509cdd598e3e09ba2d8f342deaac1765615d467fee125191d7ad6daa30a94c2eb933ba7e39ace20ab514936f86e284f5793602c002101fa58e99fbdbe40b0572e57d8d626834bcb9819b452b05da1ec58edf0b8eba5393778a895c37da714648f8a581b63bfeb591fc844ddd4fcbd4e696bf71e9cf6d992dad69012e6ed6471acb7692da45a67a2870def4a013ea2ff00df4ca6cae106aade979faced3e051c9b5fb66ddfd53634d614d8efaa632bf83c03213ede1c19e343e4de8e45b10394ddf91674a3600808bc28e0f01e40b8f396df88b452185827030cbf6d32a52a64e66b2bdee8fea56e0d99bbcb24ed4ad2215648ad14ddfd09f4f38cbcc4fb2327b759ec091bbc47ac722ff83f040369fa6356b3bff79b785bbd41eb17dba19c8f86bd5263c1f20c8581e0084bc90465c92aa6eba01d6fa3fa79f1e91a9929d2e87e83e3fc57ef219ec4032b28bde756b932f97a926aabaf01b2900baeb5494591a76d3e145b079db0d09dd4d68780aee9619ffbdecdf00e8241194d066091943ddf0446f9588ef990908705132a6b406555151de16829c8f81312a596627f2da036374ea7e5e578e6995feb240c1e91edf023be8f2b1c3b85b04e4e100a5d8cf87ead61a2ae514d6c30e2913c93190d7c2f867c35d70c768eabccb5a1e182617a829adc830999", "1e0", "cba6d81c038a6a5aceb15a9f8c06aae25d978da9eee5e60e745f5509cdd598e3e09ba2d8f342deaac1765615d467fee125191d7ad6daa30a94c2eb933ba7e39ace20ab514936f86e284f5793602c002101fa58e99fbdbe40b0572e57d8d626834bcb9819b452b05da1ec58edf0b8eba5393778a895c37da714648f8a581b63bfeb591fc844ddd4fcbd4e696bf71e9cf6d992dad69012e6ed6471acb7692da45a67a2870def4a013ea2ff00df4ca6cae106aade979faced3e051c9b5fb66ddfd53634d614d8efaa632bf83c03213ede1c19e343e4de8e45b10394ddf91674a3600808bc28e0f01e40b8f396df88b452185827030cbf6d32a52a64e66b2bdee8fea56e0d99bbcb24ed4ad2215648ad14ddfd09f4f38cbcc4fb2327b759ec091bbc47ac722ff83f040369fa6356b3bff79b785bbd41eb17dba19c8f86bd5263c1f20c8581e0084bc90465c92aa6eba01d6fa3fa79f1e91a9929d2e87e83e3fc57ef219ec4032b28bde756b932f97a926aabaf01b2900baeb5494591a76d3e145b079db0d09dd4d68780aee9619ffbdecdf00e8241194d066091943ddf0446f9588ef990908705132a6b406555151de16829c8f81312a596627f2da036374ea7e5e578e6995f", .Okay}, + {.Shr, "fdd2beb2698874a9bbfa15493bdbc350f47430839516d35ddbdeb61db686d89942601f4149d72401e1a6a511c560f86e3284b935c82bddf7bfc3731a16506acc060e2acc48bf2966b483be9a335d16e3d0add9137f169e1b8a22c90df06881bf2cb881148c4a13be5bfb967c2ff3aaa843d48be0f8ce6751b3230733060bc23b8764230dc6ddbcbf4a9d7ca7833f1a5d7682d29610accf4e5e2c18e75268648ec34812097df836e0718bcd7632723b9972b0f2f6e48bf747fb27aae57119117ef3252b169c476065de66e50db09a8443c26ab8ed4c04ae3d0420fed575f13ef3fac2254e5737288468380ce1c767c5906907fdeb5bfa6a8204b441edf210e844edcee88238bb64a46343631c8feafc7df5520a56a5d7c95883dc149bbe99fdd998eb8922a0c12851648da067007d78d4ef13dfb7b9f3b2c2eb47e327824f39307c3ff54f7a24e99b2a66b6c2eb089d6bfd1ee35b8b137e0957e22c402c6ebaa76c7e52be501d12c7f49b678a6a48d24375ae2c6154452e9165a28778c3d0e54a769271f14ec10502a1e1c9aa97bb294d3ae5e487209286afee128c0afdc781d63c3503eadda696182a56dd3a3f65db0a87c038dd8b82c0176e125aeb1282719fb24dc7ae04f48c0038c79b7ce60a669a39f4d19fb1cd9aa92c78c24617140b9fa13bd33cd27e13b78af5521c6c7b7bc25063c164ebf8b4bbee3e305f9fef7184", "21c", "fdd2beb2698874a9bbfa15493bdbc350f47430839516d35ddbdeb61db686d89942601f4149d72401e1a6a511c560f86e3284b935c82bddf7bfc3731a16506acc060e2acc48bf2966b483be9a335d16e3d0add9137f169e1b8a22c90df06881bf2cb881148c4a13be5bfb967c2ff3aaa843d48be0f8ce6751b3230733060bc23b8764230dc6ddbcbf4a9d7ca7833f1a5d7682d29610accf4e5e2c18e75268648ec34812097df836e0718bcd7632723b9972b0f2f6e48bf747fb27aae57119117ef3252b169c476065de66e50db09a8443c26ab8ed4c04ae3d0420fed575f13ef3fac2254e5737288468380ce1c767c5906907fdeb5bfa6a8204b441edf210e844edcee88238bb64a46343631c8feafc7df5520a56a5d7c95883dc149bbe99fdd998eb8922a0c12851648da067007d78d4ef13dfb7b9f3b2c2eb47e327824f39307c3ff54f7a24e99b2a66b6c2eb089d6bfd1ee35b8b137e0957e22c402c6ebaa76c7e52be501d12c7f49b678a6a48d24375ae2c6154452e9165a28778c3d0e54a769271f14ec10502a1e1c9aa97bb294d3ae5e487209286afee128c0afdc781d63c3503eadda696182a56dd3a3f65db0a87c038dd8b82c0176e125aeb1", .Okay}, + {.Shr, "3cfc4adc27af30937c7cf9d5e34240355c2ddbcd3ea96dae327e52beab855f4faa327d23f7e03fa517d0fd1ab1218c42845deb62ee0cc860f9efe73d7cee8768dc20492f10778c8705e462edf20909755fb1d313d73575bece9017221b3e7bd4d162a71409ed4c14769edf2ab8a499ed9444c86ec50dafdc127a714a648477efdc622619b27c7bab3067bfb7f141b7a14e4f2385770f4ae6e46b02bfc52b0b3fb937673cc980446cf8626e0b6943d622422c39a6c123b1f3c9625684b41b5f9d4a5e36a23a78888b8e1fe532d23b0e0392d17592788e9cc8362a53aa16ca298d5dd421f59a343cac9be3e16c14eba4a6d278c35277eafbaeb3d23bcab67b4c12d63c62e297defec85b3d3f2b7561b04421bfd86bbc79e9e963fb314308166a91bfcf84746cb9d81d5708feca3aab161be250847a1e471257e584638e2a4e529e59952ba6ec3706e699fff58c89957e27a9fd8489edf579d9e83b4f263822b63559b6085c461f5c267ca228ae9095259b252e9672b1455e7438d70077126e044193518b2283e92cd7a303dc8c5e63ec639a43d4b99621d7779d32a252ecc1e89db48789eb1f067d37378f966d2931fff88eecda2433d99f30fe5ea431ab860075c3d7badb2fb6f16a6265fed54503fb0004d7d60b65a3f66862d339fc11f233e0dd75bf1212a0ab4eb643530f6a0c5269fb030a62e6e83786323ff1665058c2ad", "3c", "3cfc4adc27af30937c7cf9d5e34240355c2ddbcd3ea96dae327e52beab855f4faa327d23f7e03fa517d0fd1ab1218c42845deb62ee0cc860f9efe73d7cee8768dc20492f10778c8705e462edf20909755fb1d313d73575bece9017221b3e7bd4d162a71409ed4c14769edf2ab8a499ed9444c86ec50dafdc127a714a648477efdc622619b27c7bab3067bfb7f141b7a14e4f2385770f4ae6e46b02bfc52b0b3fb937673cc980446cf8626e0b6943d622422c39a6c123b1f3c9625684b41b5f9d4a5e36a23a78888b8e1fe532d23b0e0392d17592788e9cc8362a53aa16ca298d5dd421f59a343cac9be3e16c14eba4a6d278c35277eafbaeb3d23bcab67b4c12d63c62e297defec85b3d3f2b7561b04421bfd86bbc79e9e963fb314308166a91bfcf84746cb9d81d5708feca3aab161be250847a1e471257e584638e2a4e529e59952ba6ec3706e699fff58c89957e27a9fd8489edf579d9e83b4f263822b63559b6085c461f5c267ca228ae9095259b252e9672b1455e7438d70077126e044193518b2283e92cd7a303dc8c5e63ec639a43d4b99621d7779d32a252ecc1e89db48789eb1f067d37378f966d2931fff88eecda2433d99f30fe5ea431ab860075c3d7badb2fb6f16a6265fed54503fb0004d7d60b65a3f66862d339fc11f233e0dd75bf1212a0ab4eb643530f6a0c5269fb030a62e6e837863", .Okay}, + {.Shr, "3b3d346797b8bdfefa0d096521385850781bea7a95121184ade90c33d743718f70730f70f5d8fafb327ebbd452958694db36e53cf4343b70155c0b02dbad8bf13183c65a7819c9a822d4e77b1b41e79980fc247ee710ec220d7d373e83a51eec2637fde8d630a068f6ba924d21555db95fef4f610607994a85a7e47eba0605861cdb4edf39e36783c7e01b43ba9c6b3e77942c64e5af28a9e29da4c8b946655a9bb5bf7bf26a70ddfd43a894d0dfd4b5b6054c99daac498d42b58ece91f1564885e2ce9b3a9c2daefdad0785bf9b97d334d914c8afd778a6efd3d225cd4d2df2b2b500332467a0de1eb0b9afc3e6b0544125541fd310d6b1c8f56ca549de5c7b8cf96bb7e451425bad7833375c2f265d17011e9f48c0a6b6be02bbaa00b7f524f1f019ed66ae3dd5810a525f3d7dabf8ac3667555943b7eb519880067ce9e2407d853cbcdaee2ec21508e50fd0250121b84eebd673588cc80f51dd2217af1cfbaeb068ea82dce9aaf499e05c356b1b8a0c0a52948483b5991569a551bb0d5462569360b423e03e64a2f5d567d1418ed1a4b74d6dabf26a3dad95d635bfb43910d8749e086941c323c525641243009533637c939e145522946821d8b4282a526d8f1e608641184470874b7981b7b7494d29f13cf70568a18b96e7ed0c2daab62cf1782a9a95085cbbe6701f5ee5abc1e13608dce1d9ef9632b5fb150c4a053d55", "1a4", "3b3d346797b8bdfefa0d096521385850781bea7a95121184ade90c33d743718f70730f70f5d8fafb327ebbd452958694db36e53cf4343b70155c0b02dbad8bf13183c65a7819c9a822d4e77b1b41e79980fc247ee710ec220d7d373e83a51eec2637fde8d630a068f6ba924d21555db95fef4f610607994a85a7e47eba0605861cdb4edf39e36783c7e01b43ba9c6b3e77942c64e5af28a9e29da4c8b946655a9bb5bf7bf26a70ddfd43a894d0dfd4b5b6054c99daac498d42b58ece91f1564885e2ce9b3a9c2daefdad0785bf9b97d334d914c8afd778a6efd3d225cd4d2df2b2b500332467a0de1eb0b9afc3e6b0544125541fd310d6b1c8f56ca549de5c7b8cf96bb7e451425bad7833375c2f265d17011e9f48c0a6b6be02bbaa00b7f524f1f019ed66ae3dd5810a525f3d7dabf8ac3667555943b7eb519880067ce9e2407d853cbcdaee2ec21508e50fd0250121b84eebd673588cc80f51dd2217af1cfbaeb068ea82dce9aaf499e05c356b1b8a0c0a52948483b5991569a551bb0d5462569360b423e03e64a2f5d567d1418ed1a4b74d6dabf26a3dad95d635bfb43910d8749e086941c323c525641243009533637c939e145522946821d8b4282a526d8f1e608641184470874b798", .Okay}, + {.Shr, "7dd848bafc3705539f7ea3c1cde250980732821780fd40da25fa0cde76ba3f22ce9955763d379f734dbd93fb84f475bfc35cc8380d443ab4cb485aa457b6784cbf784e8115220ea9642d8849f4a46655610819a32702e0060eca3e2687fbadc86dc14041b359e84516f4408c885cfcdc215e2792f8942826d5827c0d68068cb4571b35963d55fd1af184f1f334c835ca9f262f6abff2f5990d1cc5ce7c382e6108264692d5ef36e3d3374b507e1fa295e4497dc38d91f64b48e973b8d99c159bba6fadc8569c13ce5b770cbc72e2f2bab3e224c0967e43d4fbd0f6f0a3ad70f1b439dcf6169eceb2e750b7e08f21187344a804e336e0bb672dbdbd6dafd316e9397888ccf492330f3b06f81d2995f7d6970885ed3da5825a56f6a6c826fb5228dc8e5a89c600eb4f97ca6481ddc05cd91b379c6f76c81e148255be0f7be9036c5b88c9a526c5af33aaa7dc0dc210b8e8f407f561bb6608c739d39a176cd0e66b197326821a82d88b87ccc2465f5ef237892f8e542118a04060a6c363c09296fc774560b1c90cc255bf36f2f36bb67ab620469bbe92beda090f1b5ef9b5e8cf1593bb29a38430c0dffc447fa32871d7c118a7c89bcb01f5f9c5b49ad8938ae15e91095a006fd69e0aca2c22de058f5cae5f10623e27981b0d0537b379ca81390b7c4b460c4b8c4c9b1f37c6a819273be5f5b2ccad8b823ba4009432c60624abeb", "258", "7dd848bafc3705539f7ea3c1cde250980732821780fd40da25fa0cde76ba3f22ce9955763d379f734dbd93fb84f475bfc35cc8380d443ab4cb485aa457b6784cbf784e8115220ea9642d8849f4a46655610819a32702e0060eca3e2687fbadc86dc14041b359e84516f4408c885cfcdc215e2792f8942826d5827c0d68068cb4571b35963d55fd1af184f1f334c835ca9f262f6abff2f5990d1cc5ce7c382e6108264692d5ef36e3d3374b507e1fa295e4497dc38d91f64b48e973b8d99c159bba6fadc8569c13ce5b770cbc72e2f2bab3e224c0967e43d4fbd0f6f0a3ad70f1b439dcf6169eceb2e750b7e08f21187344a804e336e0bb672dbdbd6dafd316e9397888ccf492330f3b06f81d2995f7d6970885ed3da5825a56f6a6c826fb5228dc8e5a89c600eb4f97ca6481ddc05cd91b379c6f76c81e148255be0f7be9036c5b88c9a526c5af33aaa7dc0dc210b8e8f407f561bb6608c739d39a176cd0e66b197326821a82d88b87ccc2465f5ef237892f8e542118a04060a6c363c09296fc774560b1c90cc255bf36f2f36bb67ab620469bbe92beda090f1b5ef9b5e8cf1593bb29a38430c0dffc447fa32871d7c118a7c89bcb", .Okay}, + {.Shr, "5c09607379d369907af24a736d738193be60954190b53b54ee459889b0900b6e8b943fad649968c584428fe7246555c63e7316eaf0b2e73aa87ba83ef2a989fafcf5b01bdfdc960f2e6428b07dde3877ee3db60d21c07701cec113387ee14af6f0e1366c1204525802dee62a238a0e69788eb3a50f4b2148c7c187f60db7def2027d357a52a23a44d3ec89742b11d53924682d15d3d6bc05ba0d9145f698d331bbe0f129dee7a1babf93e249c548b179134a6a630e6e75008aa8d6bf063e97300c4e88de610d008cc26dc9a3fabeb2af5925344ee3b301cbc0132db85378f509c03a039a9561e38a8d3c1349354134497784dd8db5867e5aedfbed2faaf81e492901d8c61f830ea43dbcda99613e2d85e585c855ed25f727cbf7295cc0b161411dd9adc1c0118aa30237a57a755fc125459cbe2e391ccb72c743da1f620948688aed9149dc66502e37260a7e45b953aca640118a6d982bbbb1ccc9b4072ef36e2b7072877986328e7561d18660ef26e52441db5e17600dca65c5b511520d214486fa9defefc38f2d36869e877f8c0b71363f1bef344bf088568cd7a00a656ffabb9ffaff333e07628236259068aa8fc2d4388497f28af328cd554f4b420729c5765ac627784f8ef857f9fa894d0c01cf36efb6da9762e9442db55c54e7922f0e9693f27d58a420e029167e764268abeca177f24bbecc491900549ef78c0ed7a7", "1a4", "5c09607379d369907af24a736d738193be60954190b53b54ee459889b0900b6e8b943fad649968c584428fe7246555c63e7316eaf0b2e73aa87ba83ef2a989fafcf5b01bdfdc960f2e6428b07dde3877ee3db60d21c07701cec113387ee14af6f0e1366c1204525802dee62a238a0e69788eb3a50f4b2148c7c187f60db7def2027d357a52a23a44d3ec89742b11d53924682d15d3d6bc05ba0d9145f698d331bbe0f129dee7a1babf93e249c548b179134a6a630e6e75008aa8d6bf063e97300c4e88de610d008cc26dc9a3fabeb2af5925344ee3b301cbc0132db85378f509c03a039a9561e38a8d3c1349354134497784dd8db5867e5aedfbed2faaf81e492901d8c61f830ea43dbcda99613e2d85e585c855ed25f727cbf7295cc0b161411dd9adc1c0118aa30237a57a755fc125459cbe2e391ccb72c743da1f620948688aed9149dc66502e37260a7e45b953aca640118a6d982bbbb1ccc9b4072ef36e2b7072877986328e7561d18660ef26e52441db5e17600dca65c5b511520d214486fa9defefc38f2d36869e877f8c0b71363f1bef344bf088568cd7a00a656ffabb9ffaff333e07628236259068aa8fc2d4388497f28af328cd554f4b420729c5765ac627784f8ef857f9fa8", .Okay}, + {.Shr, "5287199851a7d5975b881c5c0e3aa9efa7ffa770921f2e5c30e784cadf1a8c95ba0ecf30441d46fad49d721eaa6e5e5ca22ce0a085e139a2ad70df666b5eaf1033517bf52a7395f00c3b020e209e82f77af7c85e7c2c1ccbdc02e57a36df25bad74a6823a26ecb9ec16818ebca138c7a9298e3bbb51f87801d7654da70bce10de778efcc1aada659235d1091a1864f0a4ed4eea3157c2d7d1b3ef01f4026a079ab0aa705933f15d84c949afa81926285ef9b077d406f490814a2c02299fae1cccf059d6eef98433aea5c495a17c287309423e3b94c3042dd5b8c96400745cf839b35ab94930b8cc985de9faf756ae39e72d107b3546f37600de4703a89eb5825c5584fdd08f0f34851dfaa9aa94dbe5e2fee486b0926a2adc18517f00b813e9a8bf599c7e43ef7639552dca8f31111ee51a7c1af7cfbdb4ab886bbfe7545d0331cff08b314fc568c5cdf4fa7b4e6aca38d315a4cf8a68f33b9e3cb7381b97a2b75e2d4d666a247329733a7bc6b5b50e54ccb1f83565ecc9861e9382ac17a706ecc75844006e81d44ccd726d0d555f178b9d3efdffccd553b4254dc943939e1fc2c6bab97c4087e514c97bbf1cef5ec6b02486a660570f826c0867f552f6e408826ab4139e99cfbea9cbb3aad71e88a994886e17b451e4e63bc1237abf3fc5a196e96729f6e04f966e61f32dd377edd0c4e542de75f5e9b96d4297fa0646046f8", "b4", "5287199851a7d5975b881c5c0e3aa9efa7ffa770921f2e5c30e784cadf1a8c95ba0ecf30441d46fad49d721eaa6e5e5ca22ce0a085e139a2ad70df666b5eaf1033517bf52a7395f00c3b020e209e82f77af7c85e7c2c1ccbdc02e57a36df25bad74a6823a26ecb9ec16818ebca138c7a9298e3bbb51f87801d7654da70bce10de778efcc1aada659235d1091a1864f0a4ed4eea3157c2d7d1b3ef01f4026a079ab0aa705933f15d84c949afa81926285ef9b077d406f490814a2c02299fae1cccf059d6eef98433aea5c495a17c287309423e3b94c3042dd5b8c96400745cf839b35ab94930b8cc985de9faf756ae39e72d107b3546f37600de4703a89eb5825c5584fdd08f0f34851dfaa9aa94dbe5e2fee486b0926a2adc18517f00b813e9a8bf599c7e43ef7639552dca8f31111ee51a7c1af7cfbdb4ab886bbfe7545d0331cff08b314fc568c5cdf4fa7b4e6aca38d315a4cf8a68f33b9e3cb7381b97a2b75e2d4d666a247329733a7bc6b5b50e54ccb1f83565ecc9861e9382ac17a706ecc75844006e81d44ccd726d0d555f178b9d3efdffccd553b4254dc943939e1fc2c6bab97c4087e514c97bbf1cef5ec6b02486a660570f826c0867f552f6e408826ab4139e99cfbea9cbb3aad71e88a994886e17b451e4e63bc1237abf3fc5a196e96729f6e04f966e61", .Okay}, + {.Shr, "11007065efc8180e46677ba92a504d3d06285fe4430c44456948310be426125d4ef2599a8c6dd04ff3cb1f9ee99bde3bc9271eee58332600671766aca74fc21f62cb30704ba519622e3a8c8b2fb18114afb11a7cb66d1db87f5ce9d0f6e2774d0819ec844d355b0de2f10e59c85ff9340821960f34bd29faa44ce30d4d1f3d90f46bc0748e48b782eaebd6e38aed14626e4a5b240e3ebdeebf1ccad0966f044549d5f6c672fc036724c6adbfbfcfa95d04cc9565d6ef17f1658f8d4533a181fd16413d26e43b89c0e6f9245a5b8ae3263619d1d8d1c5e206dc0bd1b3ebcf06e8187f594cd238b3204f7faa1f4c82c2aeaca5a3665083532f1eb119aae14313fd3737f635398483f21b2ad17855276d18b16abd52491418aa9c20a28ed106bb63fd5f3b00c7ed61667acf95711694d77245f41441955b0b0a0c5903ff0e490f2b934ea22c10db8a098befd01e0474d400a74dda25c82d3c5f71c375734f7bbf9c54172be30ef920f0bda5b7df426369dde7e07496fbbc0351c8b7570a316d95dbaf5a7825f7dd03eddca9251d98dee8e81d641865b74159ab8f7d7938615b2240bd6a4ba6af004ab9037bcf3d8879113d198ebdb8a6ab795da5d72411757a1c01de4ba524c3b3d01247ca4898306f1389e4e7a8fa8b96259c5bdf699456448b6f573b9b1c539779ff8dd34f840b70111bdfc6562b13908caa1b9ae9e718f282ee", "1a4", "11007065efc8180e46677ba92a504d3d06285fe4430c44456948310be426125d4ef2599a8c6dd04ff3cb1f9ee99bde3bc9271eee58332600671766aca74fc21f62cb30704ba519622e3a8c8b2fb18114afb11a7cb66d1db87f5ce9d0f6e2774d0819ec844d355b0de2f10e59c85ff9340821960f34bd29faa44ce30d4d1f3d90f46bc0748e48b782eaebd6e38aed14626e4a5b240e3ebdeebf1ccad0966f044549d5f6c672fc036724c6adbfbfcfa95d04cc9565d6ef17f1658f8d4533a181fd16413d26e43b89c0e6f9245a5b8ae3263619d1d8d1c5e206dc0bd1b3ebcf06e8187f594cd238b3204f7faa1f4c82c2aeaca5a3665083532f1eb119aae14313fd3737f635398483f21b2ad17855276d18b16abd52491418aa9c20a28ed106bb63fd5f3b00c7ed61667acf95711694d77245f41441955b0b0a0c5903ff0e490f2b934ea22c10db8a098befd01e0474d400a74dda25c82d3c5f71c375734f7bbf9c54172be30ef920f0bda5b7df426369dde7e07496fbbc0351c8b7570a316d95dbaf5a7825f7dd03eddca9251d98dee8e81d641865b74159ab8f7d7938615b2240bd6a4ba6af004ab9037bcf3d8879113d198ebdb8a6ab795da5d72411757a1c01de4ba524c3b3d01247ca489", .Okay}, + {.Shr, "342f626521bf1097d821d97b34b1993fbed688d3624f582e84778fa1094536a9f16a65ef87f1009a1931f543bc174b0943ac3b88d3b0c3edecf8af45f9aeb782ca3cf9cfcc9026545a377d4ed90aa95e9df8dfc4485ec7bd1256fdfc548decd15e086d87b6e634681994f8ca3886e61f92512a9a876259cb2afd192d4e0295dfe50b4437632bf8c1a6626c7412d188be408437d371cd1018c8cb8ff6cc0ff374bd8283df672f4960958ef3c6a792899815c33a66615ab9ba143a3a935bf4a877720873b173e332f8c7709b889ebf7ae16f9fccb9826634193e59719248818ec4059e606cab706e652dcc957cd61355d245ec8b3ee0913529161060f26c7044bae26a32d750459d4a0fa11e9e864c1b33ff2605f2f488ab0a026df2c06a86016f8d53f97085c7028e1d9e2b4f3a6ecc1cc8917c231e136c2f1fd1ee0ab8ad65def63d829c259c78259bc7b079c8f3699a406dc006abfe643c7b69844395b2719860714d834c32511826cb430dcec53c30482eeac53bcec08e4787ed26de827eb04f7b4c72ea67293c1f4b319e7aa258ec4a3ff8e4859334b1be76807d870e259928d408a480a0f5acfa49dd1868e3d9eb403109b0833c27d7bf908801154ea0c1e73b526665bca9d44a0208140a50be5044565db23eaeecb8297c07749115441fc4c09471f9bdcede0a20a98cac30ac56349e085c0810bff7d1f8f7190067378a", "21c", "342f626521bf1097d821d97b34b1993fbed688d3624f582e84778fa1094536a9f16a65ef87f1009a1931f543bc174b0943ac3b88d3b0c3edecf8af45f9aeb782ca3cf9cfcc9026545a377d4ed90aa95e9df8dfc4485ec7bd1256fdfc548decd15e086d87b6e634681994f8ca3886e61f92512a9a876259cb2afd192d4e0295dfe50b4437632bf8c1a6626c7412d188be408437d371cd1018c8cb8ff6cc0ff374bd8283df672f4960958ef3c6a792899815c33a66615ab9ba143a3a935bf4a877720873b173e332f8c7709b889ebf7ae16f9fccb9826634193e59719248818ec4059e606cab706e652dcc957cd61355d245ec8b3ee0913529161060f26c7044bae26a32d750459d4a0fa11e9e864c1b33ff2605f2f488ab0a026df2c06a86016f8d53f97085c7028e1d9e2b4f3a6ecc1cc8917c231e136c2f1fd1ee0ab8ad65def63d829c259c78259bc7b079c8f3699a406dc006abfe643c7b69844395b2719860714d834c32511826cb430dcec53c30482eeac53bcec08e4787ed26de827eb04f7b4c72ea67293c1f4b319e7aa258ec4a3ff8e4859334b1be76807d870e259928d408a480a0f5acfa49dd1868e3d9eb403109b0833c27d7bf9088011", .Okay}, + {.Shr, "652bb618e419f470a1ea1e79c5eded5b8397d79736fabfe4d254f93a2d2db348b3b5258bda545924243b94726b1c14e29fc91af30a856802dcabadb3a4d1b8175e693a49a554f2f59c21fb7cb872268d5c105ec23c96bf641c5d5dc3a6ce26d60a868e44b9ef65adafe3ee302ff5f7f20aea6bd27b2909b21cbcd4aaa2124e3ea051345343e009d39c83a0822c46619754814d1eb6fc2f6632f66d720d871c456ef67bf6be78e7c9d496ff62fb690d6c6443797e196b874b29ec874aebb8a61c650f7b9fc83933b4985b17a5ad0e15936925af088349f33ae0dae515226cfbcc180278a93eb3626b99d00562254bf8a10907194f08966cb81a3fd83c21669773b5a9511c74e076c2489d12c40f6362a4b5f83a810a6cb9ecc9f26dcaaf97bf6ccb61e9b5983f4d86764ffa1c3f71a58f4b148829c54b8edef783e535d6b35f2e79def6cfe501ebe158d6f33911e0c51bd9665296beb87bf272a357fb7725872c1c0148a047942cb71f3a6e4d2f7d6f1fea4be10cd129c3675345d8e9834374ecafdd2ab2c57a3086b6ef0bc0ddec88ae60e887e1099bd3dfc47878bbcf03421573aaecc42c152447c10041513fe9fcfd5d4cf02814bcd92a51222f4bc28a90ff1d817d4fe681dccc50d35e2b31a845f4713c3ab81fd03f250ec9de100f9123b02ce5af01dec32108e3d9dc8fa28d972de88d7e6d9ffbeff7d5ac702811e23cf8", "1e0", "652bb618e419f470a1ea1e79c5eded5b8397d79736fabfe4d254f93a2d2db348b3b5258bda545924243b94726b1c14e29fc91af30a856802dcabadb3a4d1b8175e693a49a554f2f59c21fb7cb872268d5c105ec23c96bf641c5d5dc3a6ce26d60a868e44b9ef65adafe3ee302ff5f7f20aea6bd27b2909b21cbcd4aaa2124e3ea051345343e009d39c83a0822c46619754814d1eb6fc2f6632f66d720d871c456ef67bf6be78e7c9d496ff62fb690d6c6443797e196b874b29ec874aebb8a61c650f7b9fc83933b4985b17a5ad0e15936925af088349f33ae0dae515226cfbcc180278a93eb3626b99d00562254bf8a10907194f08966cb81a3fd83c21669773b5a9511c74e076c2489d12c40f6362a4b5f83a810a6cb9ecc9f26dcaaf97bf6ccb61e9b5983f4d86764ffa1c3f71a58f4b148829c54b8edef783e535d6b35f2e79def6cfe501ebe158d6f33911e0c51bd9665296beb87bf272a357fb7725872c1c0148a047942cb71f3a6e4d2f7d6f1fea4be10cd129c3675345d8e9834374ecafdd2ab2c57a3086b6ef0bc0ddec88ae60e887e1099bd3dfc47878bbcf03421573aaecc42c152447c10041513fe9fcfd5d4cf02814bcd92a51222f4bc28a90ff1d817d4f", .Okay}, + {.Shl, "2662cd5a7037c1d5216aa5a61b2a1af76483fed3fdca876326b3681b225dd29aa0d53818e878d7ae00306f84ec2812f4fee3103dd4c90d3eb74bb1ba3e3d4be49d68e7309fb811a52e3c86e6d5ddaca303d56424ab5cdb50e13363d09355d8b1722035e907d2f4305c7b376168bce40575f5b637890a1cd9c3b1f868608c57e74c25896222eb977218fd5148720c611be8a04b7dee8ff5f4eae7ad50b281201f006f289d047c665b84aefbf7ccf322ddc20a119488e2636ac1af6f58c9b7b743ddf69f2dfe25f8b15684963b1dce6824241ccdb0d70243bfbf6d6196ecbc3f57f329803a3c65edb6a2e57f06c540012c219a4813b5ec7103d5854243ea54100522f361e6d529c8732adc373ed8b096aabfdd6c29068b3922510260252fe00fbd9fa26410adfd2482b985e40b670f8b280a4830e9f15bfb89adb6a8bd69fb2dfba85e08df2a4a921941f07c824137f9b0b50a14803d374c81c533095cfcfd888206fe639cef188447abb1e1b43fea72156df471cfa240a552bf5cef9123f60ea07e9d677ab4538c924dcebc056fa64580b9a78016447d1a746c9b1c5f600209402c3e61940f11b7112115dddb22ebefeee362912733c1ec92ddb8fe885539f46ccdd44cc1babb014221ef3a09a58d20ccbf4fc4eec0445e088f7b187e274f2f50ddc5baea88dc975070b733a0d40c5cb0649b5e0823a8097ec0e4623bff79e6d0", "45", "4cc59ab4e06f83aa42d54b4c365435eec907fda7fb950ec64d66d03644bba53541aa7031d0f1af5c0060df09d85025e9fdc6207ba9921a7d6e9763747c7a97c93ad1ce613f70234a5c790dcdabbb594607aac84956b9b6a1c266c7a126abb162e4406bd20fa5e860b8f66ec2d179c80aebeb6c6f121439b38763f0d0c118afce984b12c445d72ee431faa290e418c237d14096fbdd1febe9d5cf5aa16502403e00de513a08f8ccb7095df7ef99e645bb8414232911c4c6d5835edeb1936f6e87bbed3e5bfc4bf162ad092c763b9cd04848399b61ae04877f7edac32dd9787eafe653007478cbdb6d45cafe0d8a800258433490276bd8e207ab0a8487d4a8200a45e6c3cdaa5390e655b86e7db1612d557fbad8520d167244a204c04a5fc01f7b3f44c8215bfa4905730bc816ce1f1650149061d3e2b7f7135b6d517ad3f65bf750bc11be5495243283e0f904826ff3616a1429007a6e99038a6612b9f9fb11040dfcc739de31088f5763c3687fd4e42adbe8e39f44814aa57eb9df2247ec1d40fd3acef568a719249b9d780adf4c8b01734f002c88fa34e8d93638bec0041280587cc3281e236e22422bbbb645d7dfddc6c5224e6783d925bb71fd10aa73e8d99ba899837576028443de74134b1a41997e9f89dd8088bc111ef630fc4e9e5ea1bb8b75d511b92ea0e16e6741a818b960c936bc10475012fd81c8c477fef3cda000000000000000000", .Okay}, + {.Shl, "-65e61ca0526f9507cea023f1ccfac3d67c58cc51268a3462cbf8bccdf6fcce18e34988cb109531c11fa39448fcb106812e1eceb8174cd14e156c96853e4029f43c7f9aa0d93c810d672549cd9f80dda46a2572508e96526fe8471c96c30a26b7a09a9f6c014951537c32014140f1ce9019b4f65b3220b5744a39cf2d166496bcd87e86b43e4a4dfee1672b4be1118756f3a08c2133c6f17779e6ae1e9f4999b8762b2d7a0cb40f24aad50e21adef82bf2c9062eb83ae25320a7fc7ba98c8d2bd652cfe74f94fd937aa0f7384b94c412ee44294356feafd11b3717bf6226fd2526e3cabe39b6f95153f87667b887401e81cf2f412f4dcbcf9e25dc09da74c9c15492fbf1bef5500fde0c5c0bbabc198326b1b2d989c93763de0f741b8a64e80730e51c48132deb519f6ff12d154d1cf17c818412aa102d1a03a7d7c75b93265a1fb5f14a3e026f48d617dacd6a31f8d466b3abb710ae52d32a91ba62b59d89eeea4ab983db1157365a9a42ea0348025bc2449ec18b8517f7e06d05ec103a39f0079a4b87f5c831b555c4203e6e643e1a34ac6c27e6565d939d7361e4b5bf60ce715f21964980e9ac84a92512ec94c96e611a88c557eae31e65714117d0cdfe162581942393cef7382ad758cc19d97eb494422a27a757a088884147e0ca621738be16f5a7ac81fb7e471393ff5ddfe6986c2738fa7180895c0de44dec2471bce8d", "2b", "-32f30e502937ca83e75011f8e67d61eb3e2c662893451a3165fc5e66fb7e670c71a4c465884a98e08fd1ca247e588340970f675c0ba668a70ab64b429f2014fa1e3fcd506c9e4086b392a4e6cfc06ed23512b928474b2937f4238e4b6185135bd04d4fb600a4a8a9be1900a0a078e7480cda7b2d99105aba251ce7968b324b5e6c3f435a1f2526ff70b395a5f088c3ab79d0461099e378bbbcf3570f4fa4ccdc3b1596bd065a0792556a8710d6f7c15f96483175c1d71299053fe3dd4c64695eb2967f3a7ca7ec9bd507b9c25ca6209772214a1ab7f57e88d9b8bdfb1137e929371e55f1cdb7ca8a9fc3b33dc43a00f40e797a097a6e5e7cf12ee04ed3a64e0aa497df8df7aa807ef062e05dd5e0cc19358d96cc4e49bb1ef07ba0dc532740398728e240996f5a8cfb7f8968aa68e78be40c2095508168d01d3ebe3adc9932d0fdaf8a51f0137a46b0bed66b518fc6a3359d5db885729699548dd315acec4f775255cc1ed88ab9b2d4d217501a4012de1224f60c5c28bfbf03682f6081d1cf803cd25c3fae418daaae2101f37321f0d1a563613f32b2ec9ceb9b0f25adfb06738af90cb24c074d642549289764a64b7308d4462abf5718f32b8a08be866ff0b12c0ca11c9e77b9c156bac660cecbf5a4a211513d3abd0444420a3f065310b9c5f0b7ad3d640fdbf2389c9ffaeeff34c36139c7d38c044ae06f226f61238de74680000000000", .Okay}, + {.Shl, "db039c77f956b67247c6fc73a129bd8bfcd5f849097959a75e1721fdbd8389031cd29c389425301b27934e6251105197ac91e6e74e25ea87139520865b79d0db9a67293807553b392c09cd25e213b8e2a5ba5934ffb4705c2a36c7bd7f3c72def7a9946bf40e8ac1011240610f118f4fe4359d17c427885f59f127564e6d70d72b6113904f8eea6c8b296f5bcbc0205653eb0d93da418f6e64ea1f0ddb3d2f0a6e2c237a9ae70d4fe8e9d22dbaee4fdcbad63ebd9d25a02ead6ff4c987941839258be26309b84f1f6106193e9d383a3d66a386d08a32a7196610f6433cf04e1b8f6c677017dda8262693a2c0d59c5aa17fd589c653e9e1389b296af32214d21571e420dfb04a8002cbbcfa825e83a03683bebda52b1a6f548e2e973fdeb56afd2e72d16d621771fd53509ce0a3b91383fb09543e839d87c20a5401d378114939257f738ec2036e629b3578f710e92d70c137cf4e7c16e8b58d61c57d9ec9520e209e2c67420846fd89c33639d4e2e2c103d7a684d2d3dc1a67309991465b9ad789877e90aef4fcb4f2c52bb38379a431fc74310a756b39ca7b11c05b1d75a179765a0a04953abe6480295ab42c660b8601845c106d288c9b1aabc3e60cdb3264a79e17916f4ef439b05bfc5df5f554638854c3a3f3c96b039bff7ea1795b9dfe8a03de3c5ded766572b0979e3dbc0baba055fd4372bff2927b7cd7edf67241ca", "2a", "36c0e71dfe55ad9c91f1bf1ce84a6f62ff357e12425e5669d785c87f6f60e240c734a70e25094c06c9e4d39894441465eb2479b9d3897aa1c4e5482196de7436e699ca4e01d54ece4b0273497884ee38a96e964d3fed1c170a8db1ef5fcf1cb7bdea651afd03a2b04044901843c463d3f90d6745f109e217d67c49d5939b5c35cad844e413e3ba9b22ca5bd6f2f0081594fac364f69063db993a87c376cf4bc29b8b08dea6b9c353fa3a748b6ebb93f72eb58faf6749680bab5bfd3261e5060e4962f898c26e13c7d841864fa74e0e8f59a8e1b4228ca9c659843d90cf3c1386e3db19dc05f76a0989a4e8b0356716a85ff5627194fa784e26ca5abcc88534855c790837ec12a000b2ef3ea097a0e80da0efaf694ac69bd5238ba5cff7ad5abf4b9cb45b5885dc7f54d4273828ee44e0fec2550fa0e761f082950074de04524e495fdce3b080db98a6cd5e3dc43a4b5c304df3d39f05ba2d6358715f67b2548388278b19d08211bf6270cd8e7538b8b040f5e9a134b4f70699cc26645196e6b5e261dfa42bbd3f2d3cb14aece0de690c7f1d0c429d5ace729ec47016c75d685e5d968281254eaf99200a56ad0b1982e1806117041b4a2326c6aaf0f98336cc9929e785e45bd3bd0e6c16ff177d7d5518e21530e8fcf25ac0e6ffdfa85e56e77fa280f78f177b5d995cac25e78f6f02eae8157f50dcaffca49edf35fb7d9c907280000000000", .Okay}, + {.Shl, "c96078b0ee602308f6657e8b720e4f1c95042cd99f2f5a57dc887f64acc383c7321e5753fb53819fac7319f1cb3b6ae12f7c2c7b128047fc11138e4895ca17a8d4269fdcb06d33cf1c88df759cedc6680c9bee82cb6145a627d73ffea55ea51dbbbfe09b9964b35c6e789f18ccfc11ab4bc12710f5e641e518c5c36bea90b9d844db4863e1e2086fdb26c9ba14e5114c54c77b08bd4c829ea9301453ced2ac6aab000ac88265098f8f267d4de5f67f488c20d9faa69a942c26cd98cc6d31e0e7a81a5de4cfd7200b73009f5aad314dc19ec35cbdb5d14c5d6fbd611e229489a233dd95c48b711fe64f2c588f50e265a8488bd7ae6a2f04e5f4388c384bfddd24c89f12abb34e2b5fa76ca5189e5b8b4afb81fd16001a8a72dbbb2aebdbc6c3b9c8565f15b4e584ac6b6932af3bdad1fb39e5d1812ed532f09d5026b9a65def1faaa70aa2f1e651db81485e2a83b4322f9e6b79d45ab1077fb3ca5dbad5f8e15e2914b971fe80fce3b092ac5cd9e2927a9c53d7ec8572438fba1879e88a51ae956ac1c7058cbbdec5858b633ca0ef7e39733b56e70ae0c00f26a0e8d6137d2bc8d10b9d8141cc214a9f7fedbb0c0250a562fe0b349f74ef3143833c8459b177defb5b5850d26173105b61fcdd68251a36f26d0e52ffc67797260ca3e4bf574c3b6728d177a6a392f12dc4a6232305104703980a2244d9a724095533c9a8c28697", "4e", "32581e2c3b9808c23d995fa2dc8393c725410b3667cbd695f7221fd92b30e0f1cc8795d4fed4e067eb1cc67c72cedab84bdf0b1ec4a011ff0444e392257285ea3509a7f72c1b4cf3c72237dd673b719a0326fba0b2d8516989f5cfffa957a9476eeff826e6592cd71b9e27c6333f046ad2f049c43d799079463170dafaa42e761136d218f878821bf6c9b26e853944531531dec22f5320a7aa4c0514f3b4ab1aaac002b220994263e3c99f53797d9fd22308367ea9a6a50b09b366331b4c7839ea06977933f5c802dcc027d6ab4c537067b0d72f6d7453175bef584788a522688cf7657122dc47f993cb1623d438996a1222f5eb9a8bc1397d0e230e12ff77493227c4aaecd38ad7e9db29462796e2d2bee07f458006a29cb6eecabaf6f1b0ee721597c56d39612b1ada4cabcef6b47ece7974604bb54cbc275409ae69977bc7eaa9c2a8bc799476e052178aa0ed0c8be79ade7516ac41dfecf2976eb57e38578a452e5c7fa03f38ec24ab173678a49ea714f5fb215c90e3ee861e7a22946ba55ab071c1632ef7b16162d8cf283bdf8e5cced5b9c2b83003c9a83a3584df4af23442e76050730852a7dffb6ec300942958bf82cd27dd3bcc50e0cf21166c5df7bed6d61434985cc416d87f375a09468dbc9b4394bff19de5c98328f92fd5d30ed9ca345de9a8e4bc4b712988c8c14411c0e60288913669c902554cf26a30a1a5c0000000000000000000", .Okay}, + {.Shl, "-8c230243ae48c4aa7594d77140d1b793ecbdc2af18bba777d0c3c89312b7a1fa34ccd025bb970364023998a39c1960aa0bcfdb67378363f10ddb2eaa8e4991e44a6d20372d80dd56919fe0dbadce06ee1d2fbb45be07ebe2fcd9b6e122fe3232a83e5fad2f8cd5d7dba5c226efebc0f1eb3a31cb68201b8d81a6b2e1012fc9f6f486c1d543f529793a39eebcdd904265b4ac42af8dc67ae518d45eb2c0640617bad53019213c08ef72eb2ffd75ec761f8b8857eb0abb5948d429b4ac72b0b6a000fd0bbef38e998c8885b8d3cf667b286d9dff9eea49aa20fbd2c4c377cef4a7902c825c9780ee32c8b9115e698249d5058e2323bb83b3e662c655c20f931f02e632623ea1ad82575a1284579b0a10f88811eedcf81113e0014694d0532bb64c0c7cdc76c190a1be76801df8fa8e772335a6ea589ff8345eca6dc62020a3a95de6a4ea1e9ad5bb1b2275208ae58c7ebdfefc242c06875f5f3c5fd1aed2471f2173c40b71c8a65a60889c7567d51ab58cd68feefe8b718c59d2a57f3eff49c2a9de2fb9a660a97129223aea3c1413cd3915359860a99892ecabd68a6c5a2652efd2edc51b33211be8e29c70faa2d0527d65d3b465fb2ec1aa5c81398fc55957301388cb040caccc1064426c3d11806de8e2e5b4909cadfca3b35315f47d05c5ab9df960c6e09d3ebddcec1ec14816128d0affdc66afea53fd386a1a40e5561f31", "4f", "-46118121d72462553aca6bb8a068dbc9f65ee1578c5dd3bbe861e449895bd0fd1a666812ddcb81b2011ccc51ce0cb05505e7edb39bc1b1f886ed97554724c8f22536901b96c06eab48cff06dd6e703770e97dda2df03f5f17e6cdb70917f1919541f2fd697c66aebedd2e11377f5e078f59d18e5b4100dc6c0d359708097e4fb7a4360eaa1fa94bc9d1cf75e6ec82132da562157c6e33d728c6a2f596032030bdd6a980c909e0477b97597febaf63b0fc5c42bf5855daca46a14da5639585b50007e85df79c74cc64442dc69e7b33d9436ceffcf7524d5107de96261bbe77a53c816412e4bc07719645c88af34c124ea82c71191ddc1d9f331632ae107c98f817319311f50d6c12bad09422bcd85087c4408f76e7c0889f000a34a682995db26063e6e3b60c850df3b400efc7d473b919ad3752c4ffc1a2f6536e3101051d4aef352750f4d6add8d913a904572c63f5eff7e12160343afaf9e2fe8d769238f90b9e205b8e4532d30444e3ab3ea8d5ac66b47f77f45b8c62ce952bf9f7fa4e154ef17dcd33054b894911d751e0a09e69c8a9acc3054cc497655eb45362d132977e976e28d99908df4714e387d5168293eb2e9da32fd9760d52e409cc7e2acab9809c46582065666083221361e88c036f47172da484e56fe51d9a98afa3e82e2d5cefcb063704e9f5eee760f60a40b0946857fee3357f529fe9c350d2072ab0f9880000000000000000000", .Okay}, + {.Shl, "-ecb690041b9212903a228473e21bcae9c40d7a4fb8d761c57af93f044bfd325f3093ef170cb23e01277423691a93586237e9f4e31aaf46dbbe37782c2ba43da818a47356ccd8aac06528b433529fa7bd37f07427ef3240cce5adcc52a049e61343edd18d24de115998ae84cdeefc2e960ed0adc3b659a8508ada442a46669bf03bd45bc8cbec196c2d1f17502fe2cd395efe53b8613d580ba61be0d1cd232c2fb688372524914f6332f22e686ce1f614907e28b6855138a8b6d1116ec5d981aa7e299c606c5eb1bc196f73a940b0a43ff4db077c06f8c5b6d17057970094b01928a3f4009a342f7f21ae2a614c4c10bcf02865a8f2df6afe699f255c98d86b4a6de06ab84e1e46d9b090f55a24538cfdf47be5e76d86c887a6604eb114f7868878893cd57621d95eed678850b5c24f817cb2ad34838254dc6092308b101d2c795c925005f633ff8bd96e368071116b4e70f5273197af6fa44e484ce41c2fb7873f62c8499bd42484e416d5120513e4dd638026ce3a481b47cbe45459d11dabb6b727be9ef3511e00aeadbb106e244dfd1d0f16a842c8bad73b11b398de6527d015b0d3220f5a72bb76b47614d55b0e7651958e0b2f6269b8ab159bae0ced1a0c0e45938f5f17fb87162d080fb7e07daf03a67195e8516666366a5c6ee14bf7fdaf255ea793d5d0a22c93c47349c07d69fac79b8f8bd25bb68a8c1daa339d78ce", "62", "-3b2da40106e484a40e88a11cf886f2ba71035e93ee35d8715ebe4fc112ff4c97cc24fbc5c32c8f8049dd08da46a4d6188dfa7d38c6abd1b6ef8dde0b0ae90f6a06291cd5b3362ab0194a2d0cd4a7e9ef4dfc1d09fbcc9033396b7314a8127984d0fb746349378456662ba1337bbf0ba583b42b70ed966a1422b6910a9199a6fc0ef516f232fb065b0b47c5d40bf8b34e57bf94ee184f5602e986f8347348cb0beda20dc9492453d8ccbc8b9a1b387d85241f8a2da1544e2a2db4445bb176606a9f8a67181b17ac6f065bdcea502c290ffd36c1df01be316db45c15e5c0252c064a28fd00268d0bdfc86b8a985313042f3c0a196a3cb7dabf9a67c95726361ad29b781aae138791b66c243d568914e33f7d1ef979db61b221e99813ac453de1a21e224f355d887657bb59e2142d7093e05f2cab4d20e0953718248c22c4074b1e572494017d8cffe2f65b8da01c445ad39c3d49cc65ebdbe913921339070bede1cfd8b21266f509213905b5448144f93758e009b38e9206d1f2f9151674476aedadc9efa7bcd447802bab6ec41b89137f4743c5aa10b22eb5cec46ce6379949f4056c34c883d69caeddad1d853556c39d94656382cbd89a6e2ac566eb833b4683039164e3d7c5fee1c58b4203edf81f6bc0e99c657a1459998d9a971bb852fdff6bc957a9e4f574288b24f11cd2701f5a7eb1e6e3e2f496eda2a3076a8ce75e338000000000000000000000000", .Okay}, + {.Shl, "68900427fce083bc114c0c9e6f205b7f255197c1e434772b41be8268378979b99c7497f1d8262a945ec73db5be1fe245a156694eefd1f113731fc652cdaafde0efe44646570cf2065901f871fd4585b05a5e21570e40c9b68e4fd679464a30e3b1852a1352f4fe210b8a6c225ff95050c9fba30298928a782cc9cd476c8df8f2b1a13921696224e18c02f21e674ad7927a760895850aad2675542694b0a65c4bac34b3bc563c9d11431e3ab868108b042f30b1521467cf8a19573c4e9f4bab2a693e4dba1b5530b543023f71f87c7900894428eaab6aa34a4dd958ec92f35af70df4720c3b9265c6d9350ee1b3c9ddb504ded32f89e9eefc3a5f62522393ac525ddb06d460c68d7c902d59f2360794b3031b5956c510108f7f2fefaafa9f4334d75c86065551932a18b1ade29e8f58875ef06ce84ed6a5f86e36a6667d936f7a1b910464b25cacd7c9f5016fc133a76eeafc346e43dd00520be6f3d5f6b1b1cfdbccb07617eb9484adbbfdc3b5e22d7fd6b1e1ccf0cba32a4c741ff562bd75672c5911c125eff6d1c1d74c7bab8c9ff616bbcf558b43e771a55d8240eec72d02458c46360744b579329ddc27b008e7c4efab9f410a325eeb6cf23020d400755319e309105ec01af6289662bca9231b0c4c79bcd8100e047b14acddb41968464c937dc6528cd01d5c91ffe40b4c56363f4fbda1bd9fff2691792cb8860cb667b5", "41", "d120084ff9c107782298193cde40b6fe4aa32f83c868ee56837d04d06f12f37338e92fe3b04c5528bd8e7b6b7c3fc48b42acd29ddfa3e226e63f8ca59b55fbc1dfc88c8cae19e40cb203f0e3fa8b0b60b4bc42ae1c81936d1c9facf28c9461c7630a5426a5e9fc421714d844bff2a0a193f74605312514f059939a8ed91bf1e563427242d2c449c31805e43cce95af24f4ec112b0a155a4ceaa84d29614cb89758696778ac793a22863c7570d02116085e6162a428cf9f1432ae789d3e975654d27c9b7436aa616a86047ee3f0f8f201128851d556d546949bb2b1d925e6b5ee1be8e4187724cb8db26a1dc36793bb6a09bda65f13d3ddf874bec4a4472758a4bbb60da8c18d1af9205ab3e46c0f29660636b2ad8a20211efe5fdf55f53e8669aeb90c0caaa3265431635bc53d1eb10ebde0d9d09dad4bf0dc6d4cccfb26def4372208c964b959af93ea02df82674eddd5f868dc87ba00a417cde7abed63639fb79960ec2fd729095b77fb876bc45affad63c399e197465498e83feac57aeace58b223824bdfeda383ae98f757193fec2d779eab1687cee34abb0481dd8e5a048b188c6c0e896af2653bb84f6011cf89df573e821464bdd6d9e46041a800eaa633c61220bd8035ec512cc5795246361898f379b0201c08f62959bb6832d08c9926fb8ca519a03ab923ffc81698ac6c7e9f7b437b3ffe4d22f259710c196ccf6a0000000000000000", .Okay}, + {.Shl, "2877e5ebeb6769642ddcc4a7adafc812dea12c12db54745f37ae1a86a45dd481f69b28643137e904bc77ca96bbfbbedb06099258e3b43d377dcd52990be0179dc5fa44eb020dfa6f522215bf816bdb3c8c17988debb862ab5ea40c11808a99432447e3bb383f4518e0318821b39c49f4d824799c502858eaed06279246c7183ef41af0f2f831f9f95d2921ed70e69bd429d0bc1637461cb9c2c8e020527d12eea6283001ec2fcb5709c182fbff83cf01ac03d0fa9debd1b20efc8eeafd875f16b92c9691e5e770e5aaf40e6dd8c1b0d679c30bd5e0db192e3a7de66ae799df6c2c445d9003bde9a7d1dc4d9518c586a9b3968aa9ac6c9b20df126573ee39afcc6ac3d248be5e44fabc46181c3fe839cea4f4f6a2e1a1744d4216423f937dafa28cc538c8cd9bf0b95a8e660b4d0ef147ca4726bbdd20300952377a3f93f10c51cbd8235f8c7b1ac3f18790264ae3105f5c1a872224672e3cd139a6c0634888d3d6a73d6a68798ab20d61bb3b8b9a121d127809b794efd43074bdafb452494f5cf5b37c7606fc28041eaf3974b81800d8dee1e9ee05b0981d5e06b189e537a20efa02d8882ea47d09ce5e0b70dd9f953bde5b596b0869747c2eddd75c6613919f11cf2bb3365798ef53a8e3557f11262950d7b4fcbec3b1989d04bb42d0b3569107f3cb12afcce3e04eeaf08724f18e2039a478c943932970de7e4570ec8987ab", "29", "50efcbd7d6ced2c85bb9894f5b5f9025bd425825b6a8e8be6f5c350d48bba903ed3650c8626fd20978ef952d77f77db60c1324b1c7687a6efb9aa53217c02f3b8bf489d6041bf4dea4442b7f02d7b679182f311bd770c556bd48182301153286488fc776707e8a31c0631043673893e9b048f338a050b1d5da0c4f248d8e307de835e1e5f063f3f2ba5243dae1cd37a853a1782c6e8c39738591c040a4fa25dd4c506003d85f96ae138305f7ff079e035807a1f53bd7a3641df91dd5fb0ebe2d72592d23cbcee1cb55e81cdbb18361acf38617abc1b6325c74fbccd5cf33bed85888bb20077bd34fa3b89b2a318b0d53672d155358d93641be24cae7dc735f98d587a4917cbc89f5788c30387fd0739d49e9ed45c342e89a842c847f26fb5f45198a71919b37e172b51ccc169a1de28f948e4d77ba406012a46ef47f27e218a397b046bf18f63587e30f204c95c620beb8350e4448ce5c79a2734d80c69111a7ad4e7ad4d0f315641ac376771734243a24f0136f29dfa860e97b5f68a4929eb9eb66f8ec0df850083d5e72e9703001b1bdc3d3dc0b61303abc0d6313ca6f441df405b1105d48fa139cbc16e1bb3f2a77bcb6b2d610d2e8f85dbbaeb8cc27233e239e57666caf31dea751c6aafe224c52a1af69f97d8763313a097685a166ad220fe796255f99c7c09dd5e10e49e31c407348f192872652e1bcfc8ae1d9130f560000000000", .Okay}, + {.Shl, "e33f249be51e6411ed411976186db462f14b9a6533a470ce7f8d8bbecc3aaffc29e2ec778effa977bf83ab56b84a9859db8984aa3a29e0752ebb3f071934a3cfe5d01bb869db8b3c824340139acbcd8011a1da259f89c6a7d804d2f25bf19f540d0b4d0be4b34417e2a7e8e0badc0289438ae0b1c526a887c72952abfb9ab7ade65cb717ac4ca6e99e3c7c5d186273002cce54c4f3ef82c2362927a4c4428b433e166958f9a8f98149d12ca7c15365418a9eda9da7ef40b2cc22fc971a517f09107cee338ae75d52d04532461ffe36ce6bd8e189dbc9f8d002edc57993d8383f6910df434220488397c5b8d30f8311d38908b39a2199cefdf5866c128f440aef4a914a01c67097a6fb79208622c687dc6617d728ebabca0be92a865c6dd932327b0a71f30a1aa4a32b790484a3f89e50edc7c916175f069ea2e9b1eb8cab19f1d8daca143d6bee9e5b558753a14c27d6078fac030df330ee71e153af1012c81ce0518ec4896ff0f5c2637e8fdfbfe227d5b55be9fb84ceff09ba45e0871f9ac518fe1626730c7c580045937bb4ab38c5ee9b8c939473035f3a588f50b0611aeaefaa541ab50a6bf4bda757810d7f624ab3172bc70578524401e28a15e7dbefaa9ba8a00884fc589420cb466340c333142b7268c86ea4b700c2ae4918713c4aaa0fe49391bfdbfd46a6512e708bf6f885ad6c0a86dd41b98264f3cea518510f0a", "51", "1c67e4937ca3cc823da8232ec30db68c5e29734ca6748e19cff1b177d98755ff853c5d8ef1dff52ef7f0756ad709530b3b71309547453c0ea5d767e0e3269479fcba03770d3b716790486802735979b002343b44b3f138d4fb009a5e4b7e33ea81a169a17c966882fc54fd1c175b805128715c1638a4d510f8e52a557f7356f5bccb96e2f58994dd33c78f8ba30c4e600599ca989e7df05846c524f49888516867c2cd2b1f351f30293a2594f82a6ca83153db53b4fde81659845f92e34a2fe1220f9dc6715cebaa5a08a648c3ffc6d9cd7b1c313b793f1a005db8af327b0707ed221be86844091072f8b71a61f0623a71211673443339dfbeb0cd8251e8815de952294038ce12f4df6f2410c458d0fb8cc2fae51d7579417d2550cb8dbb26464f614e3e61435494656f2090947f13ca1db8f922c2ebe0d3d45d363d7195633e3b1b594287ad7dd3cb6ab0ea742984fac0f1f58061be661dce3c2a75e20259039c0a31d8912dfe1eb84c6fd1fbf7fc44fab6ab7d3f7099dfe13748bc10e3f358a31fc2c4ce618f8b0008b26f76956718bdd37192728e606be74b11ea160c235d5df54a8356a14d7e97b4eaf021afec495662e578e0af0a48803c5142bcfb7df553751401109f8b12841968cc68186662856e4d190dd496e01855c9230e27895541fc927237fb7fa8d4ca25ce117edf10b5ad8150dba837304c9e79d4a30a21e1400000000000000000000", .Okay}, + {.Shl, "-e1b31adc3e6545e583a737e25243660822a73850cae4c38fa7f21abb614a11cd87fbc01f92bd1675a9979a0f4612a6ae337c7d99f333ce71e02236901185f8eb5100f248ec4d35e881ee8e2806a4907a00dd62bc51af472150685961fe34fd3000f9cc74f122f2e68c34445c035bbaa052cd55fa04833788b06cb1b5b6405be5af76029da9e0e4188050288ee418268717d480a49e3694486419ae167375a61c6bfc4a313b1d98b6d9acf47be13c8d309721de6d7354a718f0347e1017d99065e0bbfca886273b61eb8b58b49dc0a4a9d51fd48b6bb66d276430e710dda9094bff03a50fc97d5bf0be673c204946b39e127aa12b00cd199e2c035456d54aaea97753f95bd711528de38aa235441e21d6d5cecb8dcc8eead15ec74364d8a78d0dada9d0a2fac40aeb2efc838db28039dd3af9bf027dfe17a1addbc260c89f35962cd73a73d0cd78e4d08f4869db16af72e76a4603ac59dcfce5cd35cabb2f63dc17910f63e0229e065095305f00ebb79b811f005feb97e35b1bd46becb61772762c5b66bd75d824ac62a9cd4b4961ffa91c94f448b85a5d88db18456f0adb9c9681a2bb962ea6d3322117b82dee1fc8de35a0ebab753870eae1c11b95afdf9810ee38ae0508c9802838f4fce003a1b7a4ff119138c9c5a165affd4d01fa7a682b2ba8fe832d53e2a45d98e14147f6a293e8fb354b3c479addeff0cf85106e6733", "54", "-e1b31adc3e6545e583a737e25243660822a73850cae4c38fa7f21abb614a11cd87fbc01f92bd1675a9979a0f4612a6ae337c7d99f333ce71e02236901185f8eb5100f248ec4d35e881ee8e2806a4907a00dd62bc51af472150685961fe34fd3000f9cc74f122f2e68c34445c035bbaa052cd55fa04833788b06cb1b5b6405be5af76029da9e0e4188050288ee418268717d480a49e3694486419ae167375a61c6bfc4a313b1d98b6d9acf47be13c8d309721de6d7354a718f0347e1017d99065e0bbfca886273b61eb8b58b49dc0a4a9d51fd48b6bb66d276430e710dda9094bff03a50fc97d5bf0be673c204946b39e127aa12b00cd199e2c035456d54aaea97753f95bd711528de38aa235441e21d6d5cecb8dcc8eead15ec74364d8a78d0dada9d0a2fac40aeb2efc838db28039dd3af9bf027dfe17a1addbc260c89f35962cd73a73d0cd78e4d08f4869db16af72e76a4603ac59dcfce5cd35cabb2f63dc17910f63e0229e065095305f00ebb79b811f005feb97e35b1bd46becb61772762c5b66bd75d824ac62a9cd4b4961ffa91c94f448b85a5d88db18456f0adb9c9681a2bb962ea6d3322117b82dee1fc8de35a0ebab753870eae1c11b95afdf9810ee38ae0508c9802838f4fce003a1b7a4ff119138c9c5a165affd4d01fa7a682b2ba8fe832d53e2a45d98e14147f6a293e8fb354b3c479addeff0cf85106e6733000000000000000000000", .Okay}, + {.Shl, "-96deab73d83c25279e3f74d7d3d050acee29bc444746b775b8cf4d6a8d824ed128cd7c5136ba5442a5f5aaf4fb2b9eb861315bd97aa68f9c7b070834b6aa182b6e897f6a5c0c81c63e2c8c774bbff3f28377cd3ed9035a372d69484f7a3e34a4167dac15b22c929d4235418fa602e825783f7dc2c5dd391148c13ca8d7483187ba3de173be6743384cd0a2c2400c0f0a2544e9be57528e6ab929a576e7f722edf64195052056bd29c348c22c175264e826966143fe305fca4cf6c04e5869b281b547cbb3526eb9391ea9d112854cf3322e8a88456558099c18e0786ed77c9cc44d9f33619a26d4ca838fe6c45e0bf56000c6188a99880cda2c7fbf8b6d67369045fe2a078966233d9e85d88e74cb4f94fc0dfca79f2b08eff7edf1b0af80c792e1447e9289386447e80c795aeb3b0eb789ef97333932619ff01e4bc6389a7eb24f5329ccf91b155eb596fa6c14f58592636d53473d229efd5f70c4e3034a17d926b4d6d75d71081b02bc1fa0e2993e48e94c2cfd82d6a25c12cf9c4148d5270eed2fa690325bfd434f6c4b87b797e1f87ef408fd617a2baec0fbd196b5023deb3b2b37bc9c08a9c7006a43ffa5ae142f7dc1bbbd2f73b3b9fb2137632fca265d4e4b1f80e0fb8ce5cd65a2cedaaf6b7278023edae9400fb311aa4018b41575492ba13a4b8d4adbd7348b7ad66199b7e5a28773ba1317cf5e702a4c8256b35155", "37", "-4b6f55b9ec1e1293cf1fba6be9e828567714de2223a35bbadc67a6b546c127689466be289b5d2a2152fad57a7d95cf5c3098adecbd5347ce3d83841a5b550c15b744bfb52e0640e31f16463ba5dff9f941bbe69f6c81ad1b96b4a427bd1f1a520b3ed60ad916494ea11aa0c7d3017412bc1fbee162ee9c88a4609e546ba418c3dd1ef0b9df33a19c266851612006078512a274df2ba947355c94d2bb73fb9176fb20ca82902b5e94e1a461160ba93274134b30a1ff182fe5267b60272c34d940daa3e5d9a9375c9c8f54e88942a6799917454422b2ac04ce0c703c376bbe4e6226cf99b0cd136a6541c7f3622f05fab000630c454cc4066d163fdfc5b6b39b4822ff1503c4b3119ecf42ec473a65a7ca7e06fe53cf958477fbf6f8d857c063c970a23f49449c3223f4063cad759d875bc4f7cb999c9930cff80f25e31c4d3f5927a994e67c8d8aaf5acb7d360a7ac2c931b6a9a39e914f7eafb8627181a50bec935a6b6baeb8840d815e0fd0714c9f2474a6167ec16b512e0967ce20a46a93877697d348192dfea1a7b625c3dbcbf0fc3f7a047eb0bd15d7607de8cb5a811ef59d959bde4e0454e3803521ffd2d70a17bee0ddde97b9d9dcfd909bb197e5132ea7258fc0707dc672e6b2d1676d57b5b93c011f6d74a007d988d5200c5a0abaa495d09d25c6a56deb9a45bd6b30ccdbf2d143b9dd098be7af381526412b59a8aa80000000000000", .Okay}, + {.Shl, "f23856367dea5c21977cc1d7a17f51a7eb2392eec252dcd968436ca96588270274be325369f8f5578e5875b611efa823452963c358f230d4d9e92600676f62dfdd48ba03023ebfac014fd61c0fa9f9f90237e4826a8c4aadbb610027f4e67077e130a71e1c7730707b260a7a90a0b32b61cbe74abe62d8dda0156a82fafe032802dc28cd0a35492b3a39365f9915e4c483dc5023bfb30ec6ff44e12121691a5afe503b8c97b68d6cb4a7572ae81d9490ac3aeb60549e31a7278bed28276e54729991bf6b2cccd3494041d1c9751264109ad7fcce1a6a01b6c669bd7c0a09e50ba3fdd16db1993b11880c2b03b9467a26b4e262f039f5164a8961287b86e5ade9246fd6ab246a2b5160235c157c5c12074fe7eeca13935664937daa830204364480afa5a9830ac096cab3714548ed2e14e8912de7a3196d6b0fa3105af2b38df7c6d01f91ad418bbd9fbd520680584ec2de90921f6029315cc5053f5e2642e450b22f33abf90887405ce92b79abc4b6de92ebd4a8f327e0add05c5fc6cc1c434c95fd79633300b36e3c02da0460b4e053d6b6026b7068ecce2789216753ab06df538a24ecdda3590f540bdadbf799770486876e81d365926e645ffbaea65e83e958c29ba7497c29d55a2106f09efcb4f37cefb65cc29afe4aa3e358f97de71d3fb5eb99a05edf674e5457905a1a489ee1ba6f1847a3bc09a9909a259e2ebd349", "12", "3c8e158d9f7a970865df3075e85fd469fac8e4bbb094b7365a10db2a596209c09d2f8c94da7e3d55e3961d6d847bea08d14a58f0d63c8c35367a498019dbd8b7f7522e80c08fafeb0053f58703ea7e7e408df9209aa312ab6ed84009fd399c1df84c29c7871dcc1c1ec9829ea4282ccad872f9d2af98b63768055aa0bebf80ca00b70a33428d524ace8e4d97e645793120f71408efecc3b1bfd13848485a4696bf940ee325eda35b2d29d5caba0765242b0ebad815278c69c9e2fb4a09db951ca6646fdacb3334d2501074725d44990426b5ff33869a806db19a6f5f02827942e8ff745b6c664ec462030ac0ee519e89ad3898bc0e7d4592a2584a1ee1b96b7a491bf5aac91a8ad45808d7055f170481d3f9fbb284e4d59924df6aa0c0810d91202be96a60c2b025b2acdc51523b4b853a244b79e8c65b5ac3e8c416bcace37df1b407e46b5062ef67ef5481a01613b0b7a42487d80a4c5731414fd78990b9142c8bcceafe4221d0173a4ade6af12db7a4baf52a3cc9f82b741717f1b30710d3257f5e58ccc02cdb8f00b681182d3814f5ad809adc1a3b3389e24859d4eac1b7d4e2893b3768d643d502f6b6fde65dc121a1dba074d9649b9917feeba997a0fa5630a6e9d25f0a75568841bc27bf2d3cdf3bed9730a6bf92a8f8d63e5f79c74fed7ae66817b7d9d39515e416869227b86e9bc611e8ef026a642689678baf4d240000", .Okay}, + {.Shl, "ed2d58a20077eb683b5bceb3a9795d3425a4d35d9ee5be0ac7323749b8217bd00cb0e275cb8410675b3f72e41248b0260deb1103857682ae4ea6ffd98cc251cc12aab2ce3fc44493609bdc92e72208237154e176c467d59f24f9d98f9d5294175264d9bb113c5577be8413eed8355ee8908b5cec8fec9d017687f0369307dae893f8bdc5b93f8fdf3e67bd1ae859096e7fb3da055bce2bf38375b6e496aa765f853282efbdafedacbba9b73caaa9a06291467decce37d5965e33bacd6a9f3c321bffafeb34ac06b282cbf80eb3e6da235ddc2015fe374df9a488135a247e15293aefce0e7a75a9d5d69f7862158719af260e9ff3c5010bb69122a8fe12235529263c1751574c0487b1223c7e73ab55048773c542c070b747a9d10f995c7935f31c3f9069c28050c77c8f467d1ea2cefcb87beefea793b30738617e91b2c8af18bcbc3e70578b8a319b14dc5ed5f366d99404620b633ed371925dced9e8de0a2d7460c2750f896083baccd4c1b8595812726bdb296be1a13ba88e57f5fee7d8225e2420c8462f11507ecd3da35eba7601a2005d83e26dc25e2e13f21a3da1b97825fa8ecd95b3fe859a8b5ee99128dec3d4ad6b3e0f460eb3c0ae3d21a4199fc62fe6a4c1b8c0b5f2e18f75f30f6a26654f0b0dd2e9c6a1a53a7857134394f982022cf7fcc7224dfde92f27e9da498dc7cc8bd32fc3054f2426246b5a945eddba", "58", "ed2d58a20077eb683b5bceb3a9795d3425a4d35d9ee5be0ac7323749b8217bd00cb0e275cb8410675b3f72e41248b0260deb1103857682ae4ea6ffd98cc251cc12aab2ce3fc44493609bdc92e72208237154e176c467d59f24f9d98f9d5294175264d9bb113c5577be8413eed8355ee8908b5cec8fec9d017687f0369307dae893f8bdc5b93f8fdf3e67bd1ae859096e7fb3da055bce2bf38375b6e496aa765f853282efbdafedacbba9b73caaa9a06291467decce37d5965e33bacd6a9f3c321bffafeb34ac06b282cbf80eb3e6da235ddc2015fe374df9a488135a247e15293aefce0e7a75a9d5d69f7862158719af260e9ff3c5010bb69122a8fe12235529263c1751574c0487b1223c7e73ab55048773c542c070b747a9d10f995c7935f31c3f9069c28050c77c8f467d1ea2cefcb87beefea793b30738617e91b2c8af18bcbc3e70578b8a319b14dc5ed5f366d99404620b633ed371925dced9e8de0a2d7460c2750f896083baccd4c1b8595812726bdb296be1a13ba88e57f5fee7d8225e2420c8462f11507ecd3da35eba7601a2005d83e26dc25e2e13f21a3da1b97825fa8ecd95b3fe859a8b5ee99128dec3d4ad6b3e0f460eb3c0ae3d21a4199fc62fe6a4c1b8c0b5f2e18f75f30f6a26654f0b0dd2e9c6a1a53a7857134394f982022cf7fcc7224dfde92f27e9da498dc7cc8bd32fc3054f2426246b5a945eddba0000000000000000000000", .Okay}, + {.Shl, "a1797c5afd3022f8351c57ad20330609d3f0857f63e04d0af55ddb4028ccb49a53e941121986eee725714e6a8f48c9b06e6940d82f16a2d50cbe335d58ca9c30fd124543c2b303d4330887f99512bdbe9c8ab3c9aee567b2dcf266af9d749c911717a90fe8736a0dfc07281145a949c432aadae0195b61f4898ea8e1527419e2fdccf12b7c1d57df89388b7574ab9bb93fe5289d4fdf3452c340baf36c2541faf6f9e825e0eda04113198d224c596d35a138f17876b95435f3a07b736f5f42b99726c270f3549df2814c83793594de34dd5fa429de41cdf191845ba4ac39d2a5dc60c15dca12ee622e6a4b0a9a0fd5f437a9bca459b60447451eb06d4cf00c1aae30f64b9b2d4e2a799435daaa338c2796760120638d30ec6fa1a2fa2a0abe4f32d5f3088cb8171de90371d1b2ff6535073e978d237829f09c23ce657187b676407d5f1d708564d2caebd4ba43dffcb8a7c0bd26e93ea4048fca805cbdf70752a410979b7afd0cb5e509f761016d39664019b884e853457cbd8726cf4bf884b4dde81de8b1db3ef31df80fb5541c3f9e6590f109e2b48b133570f01847b40a860f8abf53c76cb50d62b200b8ef843e5dc3d305a9ac444c4e71f28c502be7f20b5fcb3c13ef770bbc00c19389dd8b5493dd6cc45b010105ad3c307b01e4f8c23369f1f207e9dbdfe5c612f4ff2de319e8f9638e046ab8cafecc6a13b59c30c597", "41", "142f2f8b5fa6045f06a38af5a40660c13a7e10afec7c09a15eabbb68051996934a7d28224330dddce4ae29cd51e919360dcd281b05e2d45aa197c66bab1953861fa248a87856607a866110ff32a257b7d391567935dcacf65b9e4cd5f3ae939222e2f521fd0e6d41bf80e50228b5293886555b5c032b6c3e9131d51c2a4e833c5fb99e256f83aafbf127116eae95737727fca513a9fbe68a5868175e6d84a83f5edf3d04bc1db408226331a4498b2da6b4271e2f0ed72a86be740f6e6debe85732e4d84e1e6a93be5029906f26b29bc69babf4853bc839be32308b7495873a54bb8c182bb9425dcc45cd49615341fabe86f537948b36c088e8a3d60da99e018355c61ec97365a9c54f3286bb55467184f2cec0240c71a61d8df4345f454157c9e65abe61119702e3bd206e3a365feca6a0e7d2f1a46f053e138479ccae30f6cec80fabe3ae10ac9a595d7a97487bff9714f817a4dd27d48091f9500b97bee0ea548212f36f5fa196bca13eec202da72cc80337109d0a68af97b0e4d9e97f10969bbd03bd163b67de63bf01f6aa8387f3ccb21e213c56916266ae1e0308f68150c1f157ea78ed96a1ac5640171df087cbb87a60b535888989ce3e518a057cfe416bf967827deee177801832713bb16a927bad988b602020b5a7860f603c9f18466d3e3e40fd3b7bfcb8c25e9fe5bc633d1f2c71c08d57195fd98d4276b38618b2e0000000000000000", .Okay}, + {.Shl, "b52c32e64b162dfec7236dfa5406c1a2774d53ee1b8e978432ebdcfd3de750c6b8ae210f3e5131c7f290efc67ea26b939dc7c0adcb93b31a731449e0890c03c4694d60c4c60123c3892b177947be3c54769e4bf4a3d5200d10dec1d2491df8cf1d30227de72e9d4307a2366d6ad18afbd27cc9c0384a33201e6978e0c43b9ec931a03fec7816f4411a532e0cf72265a889797a51cced86e6b089807632ef1ce9379132fad0f59181ee674d5f7d3373c0913628b2e88d4971584e670860292aebba0e1659ccba59777e01d4e68d668e4f488022b85c212852a47f6721a171dc986cfc6c14e3d3e341e9772e7a5e93acde2f8d670636fba1888cf4565893ef5bdeb4dc449077ce7ce83b1d1a3eb3253eb4ee4be9c69fec51375442cd651ca50d52c55eaa413269e0c8c7f54ef354b6c10c0256fb0fd465b648db1e447fdb98027165275d8b02bf786e05a1ad5360d8289b749026bc1bec0157dc83eaf5768c9758a20c30d84ee840a439d3245bcc4db631c57a5117421ae3596508752e14376c6634566237e4af5c13cb6015f441cb656a2467083ec8095734c0dbb479f61557fc76abd19b199b4c0c9ea3fb26a5325df8fe1baa590d2f155be12b2a9428e78d5695b5d494183af3e1518316626adadc2cf2e32d03378e811a1e2e5dd388524e4fdc690eab15ed3c93927edf47080f40ca63c8d54000fc9dd9a35ad1035af3a01e", "8", "b52c32e64b162dfec7236dfa5406c1a2774d53ee1b8e978432ebdcfd3de750c6b8ae210f3e5131c7f290efc67ea26b939dc7c0adcb93b31a731449e0890c03c4694d60c4c60123c3892b177947be3c54769e4bf4a3d5200d10dec1d2491df8cf1d30227de72e9d4307a2366d6ad18afbd27cc9c0384a33201e6978e0c43b9ec931a03fec7816f4411a532e0cf72265a889797a51cced86e6b089807632ef1ce9379132fad0f59181ee674d5f7d3373c0913628b2e88d4971584e670860292aebba0e1659ccba59777e01d4e68d668e4f488022b85c212852a47f6721a171dc986cfc6c14e3d3e341e9772e7a5e93acde2f8d670636fba1888cf4565893ef5bdeb4dc449077ce7ce83b1d1a3eb3253eb4ee4be9c69fec51375442cd651ca50d52c55eaa413269e0c8c7f54ef354b6c10c0256fb0fd465b648db1e447fdb98027165275d8b02bf786e05a1ad5360d8289b749026bc1bec0157dc83eaf5768c9758a20c30d84ee840a439d3245bcc4db631c57a5117421ae3596508752e14376c6634566237e4af5c13cb6015f441cb656a2467083ec8095734c0dbb479f61557fc76abd19b199b4c0c9ea3fb26a5325df8fe1baa590d2f155be12b2a9428e78d5695b5d494183af3e1518316626adadc2cf2e32d03378e811a1e2e5dd388524e4fdc690eab15ed3c93927edf47080f40ca63c8d54000fc9dd9a35ad1035af3a01e00", .Okay}, + {.Shl, "-9034fe8fee8a792a48d320fdfb74b12e5648ef5b727ffb2475b071cd620ed977e739254f92427db85a8d6d38d2f46efad2abfb273d28834f807e2e5ddfdd0bd4226591e7f18fd54d8768d5ddff8d07b8886fbe98a78e0632f8d2d289487022ddce84a16b2e350ba52d888d92b7161ca0c80bb1f4bdb48faf530effa509ec1a8e182c4a74ad89faece0e9f67831bf76cfabada6695e24158923f6935f205e61b2f45066b5cbb7789a41c509140df72f28f8545c9e340c1810bf5174a0e2d2bb9df0955b9fe6b78050938a8b50b7f66ab1286ed60a17ed87d0d8fd19023eaadef7d3ab1fac7f7292a336edd17f937352de82b3f61f7045b8ead4ecca02be6ba198b19c98918f5a9dfbee907f6a2e263ea64ce19ebbb0b85695c6729c4544f28ccdb8cf9c9d93b39222322fd74baf51a992e5c39671bdccbba520aa884bc0fba1027e57a9741574125a73fbbdf7f29929c37fb1323b236c3aba8c6132ccbe7f116a28848da98802b6669abd15f63a3f57faa4a6956fc5cec19b1f269e7988eb412cf2409eafdfb9a3a124df6054b0c5daa418357199abb83c19c2a8cacccd15f9150e9bfece3655bf01bc17cb3cccbc1fa090ecfd70370b5d1cedb85bb2e9c7f8005838f2da3faee2966168010cd19236d8044541c53f007ce81ed17b615b1fd66725c78dc41bb26210472d987ae1821d330d0761053b34189a9af5708861d9b656", "6d", "-12069fd1fdd14f25491a641fbf6e9625cac91deb6e4fff648eb60e39ac41db2efce724a9f2484fb70b51ada71a5e8ddf5a557f64e7a51069f00fc5cbbbfba17a844cb23cfe31faa9b0ed1abbbff1a0f7110df7d314f1c0c65f1a5a51290e045bb9d0942d65c6a174a5b111b256e2c3941901763e97b691f5ea61dff4a13d8351c305894e95b13f5d9c1d3ecf0637eed9f575b4cd2bc482b1247ed26be40bcc365e8a0cd6b976ef134838a12281bee5e51f0a8b93c681830217ea2e941c5a5773be12ab73fcd6f00a1271516a16fecd56250ddac142fdb0fa1b1fa32047d55bdefa7563f58fee525466ddba2ff26e6a5bd0567ec3ee08b71d5a9d994057cd74331633931231eb53bf7dd20fed45c4c7d4c99c33d776170ad2b8ce5388a89e5199b719f393b27672444645fae975ea35325cb872ce37b99774a4155109781f74204fcaf52e82ae824b4e7f77befe5325386ff62647646d8757518c265997cfe22d451091b5310056ccd357a2bec747eaff5494d2adf8b9d83363e4d3cf311d68259e4813d5fbf73474249bec0a9618bb548306ae33357707833855195999a2bf22a1d37fd9c6cab7e03782f967999783f4121d9fae06e16ba39db70b765d38ff000b071e5b47f5dc52cc2d00219a3246db0088a838a7e00f9d03da2f6c2b63facce4b8f1b883764c4208e5b30f5c3043a661a0ec20a7668313535eae110c3b36cac000000000000000000000000000", .Okay}, + {.Shl, "-34fa5a4175130b0fcdc2cb6d268b41658efb68d537bbb9f40cfb205f3e1b5a62f7d079524238a160d9b98ee4ed6c10e43aedc5498300b29763c550664c61031652cfbe96037f16a87a503568b8c6e76b0ad82669dd44f6f521521d6f2754aa5bc0af350ecaea60673751e91904282adcadd828319bf9ba0722ba1900f28ff77d156aa0013e12917258982e278fb10676fe3745b08135acdaccaceb44866270d6d4dcb0aedf3e33daaee87455f511d869901a72cee13efc98fa3874954e1b7c5e24aad8df8fc1e430ef06c390d74b8c1d21cde058f617cd491cd513d77f2073dd9a9e99748d46dd63beb60f870533064f85be839c6400f22a1e8e09b66bf6cba2fcf0fe0baf6ff07908ce995cb68800b2fa640a31f298acb52939a04bfac5c5bb9f664e978a085032bba3b1157ce479e5d04c4af559d1c0a2ec25df649efce8b8132eb7e5ac16d40e7e58e06c2bf0f174dfaf0be96247de212dbd3d1d4739557ee9e2da9ca1d2488dd130ae541845973f6ed6a9985278030e97c81b2d9550698373fd777f6bb3e3556da1341ee3dfe572cc29f705c4688d14b40219191f5e66b661c0b464b88185532c2e3a2b20d845790c2939aaaf47fc08cb095a81c1303e72770964ff57bb28f930cf30db0d1f755713db882e743eec0f0ea52aab1ca2ebcfd806181ab7abbf032339903c818a0baa31af57ae14c3f8fca8ca481b6f0ee1a9", "22", "-d3e96905d44c2c3f370b2db49a2d05963beda354deeee7d033ec817cf86d698bdf41e54908e2858366e63b93b5b04390ebb715260c02ca5d8f15419931840c594b3efa580dfc5aa1e940d5a2e31b9dac2b6099a77513dbd4854875bc9d52a96f02bcd43b2ba9819cdd47a46410a0ab72b760a0c66fe6e81c8ae86403ca3fddf455aa8004f84a45c96260b89e3ec419dbf8dd16c204d6b36b32b3ad121989c35b5372c2bb7cf8cf6abba1d157d44761a64069cb3b84fbf263e8e1d255386df17892ab637e3f0790c3bc1b0e435d2e307487378163d85f352473544f5dfc81cf766a7a65d2351b758efad83e1c14cc193e16fa0e719003c8a87a3826d9afdb2e8bf3c3f82ebdbfc1e4233a6572da2002cbe99028c7ca62b2d4a4e6812feb1716ee7d993a5e282140caee8ec455f391e79741312bd56747028bb0977d927bf3a2e04cbadf96b05b5039f96381b0afc3c5d37ebc2fa5891f7884b6f4f4751ce555fba78b6a728749223744c2b95061165cfdbb5aa66149e00c3a5f206cb65541a60dcff5ddfdaecf8d55b684d07b8f7f95cb30a7dc1711a23452d00864647d799ad98702d192e206154cb0b8e8ac836115e430a4e6aabd1ff0232c256a0704c0f9c9dc2593fd5eeca3e4c33cc36c347dd55c4f6e20b9d0fbb03c3a94aaac728baf3f6018606adeaefc0c8ce640f206282ea8c6bd5eb8530fe3f2a329206dbc3b86a400000000", .Okay}, + {.Shl, "9a22c4e0bba696e560c7b20d808759d96c1c095272f51f3a352db4604a81be286faad2f4e5c597c1222de7956bd25e01a3c0a10ff017452b32ab4809d300ca1b262ebe80704148e34c12a69a9b4524f1ff2147df481d832b07ced228c4724e5e2d7a62b374633015b2e2ffd5566bb83b1e29f174b8a4e05d8315be359a812d60d6987813ca7376fad572395c1597a3de8984b8f87e7cc90e0d589cd54954d0b8a5bd41135e909eeff7db0a2e5208ecceaed7b5eed208051f75b907a7e6f21785d664264c9def3b3258c905fe7c4fb6bb3f0561e76e9f93add0bb0eb6afc2c4b4a147256c3842e36697f5001cf0b53cb61855f7384af4b0047a90265f3394014a7388bdfde6f1411776d3dbb60b4b5ef51b074102d98716a2012d6e2dd5e2ecfbe0729e825b4094db9a3005f2b6ed7d08fdf2545e99c3ac89bc101911471293b12fca4eb7c3fc6fc7c1bc06316e319913518113e51fed224a4b7c9d71b10e7878cdfc02992642d7c5f30474b8f3e5795ef9fd90160c389e323285969e4024686cc0f0e56fd931ed627507c2ee4b63fe0a2c0eabf6b7859a411102e0440fe75cc4cf9a7746d601e98f5af722ec4f485915d5554dc41618338dd2a37f55a23dea7b85b2cebd653539245d45713e200c81ea015d6b26c5765cad55be5b466291cef48c34ea10b0ec95e3e285edad9c854573d8ef5f751d5ce9be4291f2eafce4e8c4", "43", "4d1162705dd34b72b063d906c043acecb60e04a9397a8f9d1a96da302540df1437d5697a72e2cbe09116f3cab5e92f00d1e05087f80ba2959955a404e980650d93175f403820a471a609534d4da29278ff90a3efa40ec19583e769146239272f16bd3159ba31980ad9717feaab35dc1d8f14f8ba5c52702ec18adf1acd4096b06b4c3c09e539bb7d6ab91cae0acbd1ef44c25c7c3f3e648706ac4e6aa4aa685c52dea089af484f77fbed851729047667576bdaf76904028fbadc83d3f3790bc2eb3213264ef79d992c6482ff3e27db5d9f82b0f3b74fc9d6e85d875b57e1625a50a392b61c2171b34bfa800e785a9e5b0c2afb9c257a58023d48132f99ca00a539c45efef378a08bbb69eddb05a5af7a8d83a0816cc38b510096b716eaf1767df0394f412da04a6dcd1802f95b76be847ef92a2f4ce1d644de080c88a38949d897e5275be1fe37e3e0de0318b718cc89a8c089f28ff6912525be4eb8d8873c3c66fe014c93216be2f9823a5c79f2bcaf7cfec80b061c4f191942cb4f20123436607872b7ec98f6b13a83e17725b1ff05160755fb5bc2cd208881702207f3ae6267cd3ba36b00f4c7ad7b917627a42c8aeaaaa6e20b0c19c6e951bfaad11ef53dc2d9675eb29a9c922ea2b89f100640f500aeb59362bb2e56aadf2da33148e77a461a750858764af1f142f6d6ce42a2b9ec77afba8eae74df2148f9757e72746200000000000000000", .Okay}, + {.Shl, "-87ccd26073bc73f443bf7719930d53087f0a33f951a98b8384ac2503ddacea972daca274e359ff63cb3d0c3cbc58be17244bd3ec43370dc903f237b748ede5a84d89e53dc9ce2f0711dc9047b229f6d3e376e672e245eab6cdb2d45acbe9688dc0e8c6edbe9e2e40b5876d86faa5bbaffe387001911985755f14abd56ead351c2b6ca42c195777932bd91c776d771392642dbc07a04ad02b6adf60ffa5ffdf4b5e452f983c2204f6640a97be6184e7ca2e0dca1bfbaecff44cd6a9ae9cf4839da3c01dae16a5d46f1b2fb8f07cf9ff40755e580f4ef22e96d2c95d891df9a8aff2cc9d30a9d4db1c768ff8d08d3d27ff369dd7dcb86fe0b6b94c16c3a26721cadd7343c25103f299836b0adb0490ceefafdfccb0222da9ab9f9047957bff9f538078c7804d1a00f579b7ac85c38905ea0ef6b2d7f059b65cf07effdfc8f662e1c1aa6747c773fb93f6319ea55a798282a95f126dc3273597bf28f729d1b3226b2962832106281afaa55f402bd18281594c5a2165a1999faff43b00358d327424ef3258dd185468557a9be0ca52f2cf3ffebb961cfb8f5cb46d9f44415e1526594272f23f45e4ecb3e18c34a2ac3990aea7e75cf98dcd1047440c53a85698a3e0f473790b1259b2df66d615ad6a5643767138408b1e41c919a8dd9ebd7aa6e7800d4f2a5c505bb0e3603f217c9fb88422c9765a20da6f6144b06dc6d2bed7ab56", "36", "-21f334981cef1cfd10efddc664c354c21fc28cfe546a62e0e12b0940f76b3aa5cb6b289d38d67fd8f2cf430f2f162f85c912f4fb10cdc37240fc8dedd23b796a1362794f72738bc1c4772411ec8a7db4f8ddb99cb8917aadb36cb516b2fa5a23703a31bb6fa78b902d61db61bea96eebff8e1c006446615d57c52af55bab4d470adb290b0655dde4caf6471ddb5dc4e4990b6f01e812b40adab7d83fe97ff7d2d7914be60f08813d9902a5ef986139f28b837286feebb3fd1335aa6ba73d20e768f0076b85a9751bc6cbee3c1f3e7fd01d579603d3bc8ba5b4b25762477e6a2bfcb3274c2a7536c71da3fe34234f49ffcda775f72e1bf82dae5305b0e899c872b75cd0f09440fca660dac2b6c12433bbebf7f32c088b6a6ae7e411e55effe7d4e01e31e01346803d5e6deb2170e2417a83bdacb5fc166d973c1fbff7f23d98b8706a99d1f1dcfee4fd8c67a9569e60a0aa57c49b70c9cd65efca3dca746cc89aca58a0c8418a06bea957d00af460a05653168859686667ebfd0ec00d634c9d093bcc963746151a155ea6f83294bcb3cfffaee5873ee3d72d1b67d11057854996509cbc8fd1793b2cf8630d28ab0e642ba9f9d73e63734411d10314ea15a628f83d1cde42c4966cb7d9b5856b5a9590dd9c4e1022c79072466a3767af5ea9b9e00353ca971416ec38d80fc85f27ee2108b25d9688369bd8512c1b71b4afb5ead580000000000000", .Okay}, + {.Shl, "-622f549ecb2e5113d5bef707f2b6547d13f9d943e8d5b1c873bdb50af155384884f3818364ce68f7cffb905b62dfc842e80709933e40b29179a3d1476c543b4bd0813924b6e9e149101eb32dfd4390d922c240ef113c2f0a32c08d137a844f808d8c4890dcbb9c686bdbb5d73d7e558727d794453e4335d3e2d0c1fc9b4976085446b3a94416de75467d93a2faf91f217957addee454f83e93c3bbfea169db8ca327820cf1afa13a7885ced613e955d18277116889e923ffa168ae5ccb4b58e72c74790d91a9ac003e3dab89008fb333570c217b0c76165bfcc053a2fb77996ada69322586a035650df04bb15854d6a948c38fb6fde006596009e1afd6b664cd4f26d9e1a40dafffe0d0c858d2f7d5452fbd5345dad4d98961f6f79de64dc817f2d2839f3f60f47008357c09b57d7b8e8a49faca93a22aed783d705592f4bad2cd0e56eb50d9bda7063bea4b826f1b631bd03cf6d9c9e6d831b1c1396595f05d8369a878dd45f10b825d72d520676064bff1fdbcb34fd2ae49cf68a8805a42dfe5dc985fdaf05d91440daacc8ffbbf653305debff45a81eb8af2bc2774fbe4845073e06deee6a44919cd67022045533b9de26bb940c140ccdb237a9846a5b7bbc4771d27396ef45d04a98151cca8bd23dd708f938ad5a62f8d808baeed8fd0dcc87af2ef2cb2795a3f00211a959ce9ef7dcd511bc93f3d01d7b68fd503b369d5", "6d", "-c45ea93d965ca227ab7dee0fe56ca8fa27f3b287d1ab6390e77b6a15e2aa709109e70306c99cd1ef9ff720b6c5bf9085d00e13267c816522f347a28ed8a87697a10272496dd3c292203d665bfa8721b2458481de22785e1465811a26f5089f011b189121b97738d0d7b76bae7afcab0e4faf288a7c866ba7c5a183f93692ec10a88d6752882dbcea8cfb2745f5f23e42f2af5bbdc8a9f07d278777fd42d3b719464f0419e35f4274f10b9dac27d2aba304ee22d113d247ff42d15cb99696b1ce58e8f21b235358007c7b5712011f6666ae1842f618ec2cb7f980a745f6ef32d5b4d2644b0d406aca1be09762b0a9ad5291871f6dfbc00cb2c013c35fad6cc99a9e4db3c3481b5fffc1a190b1a5efaa8a5f7aa68bb5a9b312c3edef3bcc9b902fe5a5073e7ec1e8e0106af8136afaf71d1493f595274455daf07ae0ab25e975a59a1cadd6a1b37b4e0c77d49704de36c637a079edb393cdb063638272cb2be0bb06d350f1ba8be21704bae5aa40cec0c97fe3fb79669fa55c939ed15100b485bfcbb930bfb5e0bb22881b55991ff77eca660bbd7fe8b503d715e5784ee9f7c908a0e7c0dbddcd4892339ace04408aa6773bc4d77281828199b646f5308d4b6f7788ee3a4e72dde8ba095302a399517a47bae11f2715ab4c5f1b01175ddb1fa1b990f5e5de5964f2b47e0042352b39d3defb9aa237927e7a03af6d1faa0766d3aa000000000000000000000000000", .Okay}, + {.Shl, "-f26ef7b52160cd8b8d7b40831c6680e8305076010e51bcf72aa1d5f99585ac211e4047d9ff1f569a7d975ac87ae6e9d27a143cec404cabbe3b39c6c9a93d92f5040e2e85c1acbb9e2c64069f951e8ec8c743da5a8c526647e20cabf79c09d2536f9aad4c43af75becc7283c5e219a198a4934c1ec3625969d232eae2ea03d6e9c5bbe6168a80f878d5341708b5ad4be5fc84aaeba41a95fba508bfa1a0adcbe7474ddae2bc50d6b806605efef026718db8e7a3121b2fc9ba5cf4c7d6cc7d582f89453bf5355f4aaa4aa7d6b9b5c7f2be4b200824a10f93608996eef824175bddfd7eee8d64983401a1b81e0a74281bd5dc2f9ad6157fcefe834b519f2aac30b873e7b2d9ece40dd23da2fdd4495453cda28cd35c9ccb36ac40b91eaadd17cca1a4b5c86e5be680a7f71a067bb7957a2c4e5c50a6c255da0626e92b14abb96c4331239e0fcf0707eb2d4cdb1dd24f56e7fc54f930093e31653fe975a46c77a65c072c5cb6ab67de4758d5291aa6618a7ab338d9cabe709eeb2649de4bebd75535a4ff6fd00a0790067a449bc9e9891dcda267451d781d0caf52b4dcaa0d82e667c80503441a8d05e834771f3050384dd947bd34495b22d27d5624f25a849222b7daa9e1ca92917e8f4b9b2c3b899d870fa26bf5cc0798f940be783e69ab75d18cf6629dbee6062fdadbadeff619d84138de6caf24ada6c7853591e45d4cf48865", "28", "-f26ef7b52160cd8b8d7b40831c6680e8305076010e51bcf72aa1d5f99585ac211e4047d9ff1f569a7d975ac87ae6e9d27a143cec404cabbe3b39c6c9a93d92f5040e2e85c1acbb9e2c64069f951e8ec8c743da5a8c526647e20cabf79c09d2536f9aad4c43af75becc7283c5e219a198a4934c1ec3625969d232eae2ea03d6e9c5bbe6168a80f878d5341708b5ad4be5fc84aaeba41a95fba508bfa1a0adcbe7474ddae2bc50d6b806605efef026718db8e7a3121b2fc9ba5cf4c7d6cc7d582f89453bf5355f4aaa4aa7d6b9b5c7f2be4b200824a10f93608996eef824175bddfd7eee8d64983401a1b81e0a74281bd5dc2f9ad6157fcefe834b519f2aac30b873e7b2d9ece40dd23da2fdd4495453cda28cd35c9ccb36ac40b91eaadd17cca1a4b5c86e5be680a7f71a067bb7957a2c4e5c50a6c255da0626e92b14abb96c4331239e0fcf0707eb2d4cdb1dd24f56e7fc54f930093e31653fe975a46c77a65c072c5cb6ab67de4758d5291aa6618a7ab338d9cabe709eeb2649de4bebd75535a4ff6fd00a0790067a449bc9e9891dcda267451d781d0caf52b4dcaa0d82e667c80503441a8d05e834771f3050384dd947bd34495b22d27d5624f25a849222b7daa9e1ca92917e8f4b9b2c3b899d870fa26bf5cc0798f940be783e69ab75d18cf6629dbee6062fdadbadeff619d84138de6caf24ada6c7853591e45d4cf488650000000000", .Okay}, + {.Shl, "-349bc86e6ad3d83f7a72390258768cb390f6903cb663b65b3dfd0398548a85797e090824a4c80c39a91122374eb3be3cea2928d433f8202fe870340e029bd6667c4cafe41887f56fb375eb2fdef9367fc8a7cdae1ab9ad58762c42c83aa37c28f8051d189babd2c3e2d29092beafe9f1916164e9c282018308a4c3d1ed51e0667d6cfc63b37c7b5cf6b272bd61ac1983c73b5e54402285f671c4fb674b9d19eb9f8403b5b6e598daf748b0399f79d6bffac6704bd6e9acea97004e76748fd02348e5cb83b721c54966d33c6dde5d2154b5f077d2c74327db84d735ad108d4ae9660f470110d81c1053b13cd857f0232e0c19ddc4b636a112f4c95c4cab17f9eecb7d1c1a0d5e0ab84521290dc3156518025a9eaef6b3b27666c80d35b7919c831e76cc4e5bc44929ca5fdb9b6584aefb41881835947fa6ce300747b4c449d5673fb041e392b6b421044c1961532cadeaade2fab40da082bd139751db98a14ea7ce73e42c39b7d72155d82d451fe1f9b19fc128cd4adb0d79a814d6108c458cd3aca8a11d7eab1c57cf1e616e321bba24cfe62683d9df31e9623b150f22301e27eb70ab3dfe2e061034475d6496eda1e8a2993dc8d1c69e2be0294fbafddbe1c4091657769dc2dd5cbafca0b610d99a3432e44770be3b2e41f7bd7d8aca558586a82f2a744eb3292c41c6802de577f2e74506c9dba6f9c5dec1c1e6cf28aa2dee", "65", "-693790dcd5a7b07ef4e47204b0ed196721ed20796cc76cb67bfa0730a9150af2fc121049499018735222446e9d677c79d45251a867f0405fd0e0681c0537acccf8995fc8310feadf66ebd65fbdf26cff914f9b5c35735ab0ec5885907546f851f00a3a313757a587c5a521257d5fd3e322c2c9d385040306114987a3daa3c0ccfad9f8c766f8f6b9ed64e57ac35833078e76bca880450bece389f6ce973a33d73f08076b6dcb31b5ee9160733ef3ad7ff58ce097add359d52e009cece91fa04691cb97076e438a92cda678dbbcba42a96be0efa58e864fb709ae6b5a211a95d2cc1e8e0221b03820a76279b0afe0465c1833bb896c6d4225e992b899562ff3dd96fa38341abc15708a42521b862aca3004b53d5ded6764eccd901a6b6f2339063ced989cb788925394bfb736cb095df68310306b28ff4d9c600e8f698893aace7f6083c7256d6842089832c2a6595bd55bc5f5681b41057a272ea3b731429d4f9ce7c858736fae42abb05a8a3fc3f3633f82519a95b61af35029ac21188b19a75951423afd5638af9e3cc2dc643774499fcc4d07b3be63d2c4762a1e44603c4fd6e1567bfc5c0c20688ebac92ddb43d145327b91a38d3c57c0529f75fbb7c388122caeed3b85bab975f9416c21b3346865c88ee17c765c83ef7afb1594ab0b0d505e54e89d665258838d005bcaefe5ce8a0d93b74df38bbd8383cd9e51545bdc0000000000000000000000000", .Okay}, + {.Shl, "68c0142307955783e7887413fa468d514cbe9b3ec45f6372e9e5a58a97699e5ee2b2bd9f286d5a0d01cb5852d4acf1e7b8c4aa49ebe653645eeab73835becc46707ce081aad82edfb3ff6024e147336d7a9ee57807648baa66b23a716e9425991e1c36747df90451a9bcc7b0a267d98e13a5bfd00f3d09461d28991094748f83c17e261cde64121ba434357396f96d55e5483eb5fd3657c9efb5807299c17b653170a799f14c527a19cfbdcd042ea785bcbd499315ccf535455178ec62e63e6a43e6079a8ad0b9b9a6234c3f80092036a1341f7671c7ab56e7b977ea5ba73d37ded2c01abaf1315225f88c88496cb5d308a8bd8a803a6ed80735718b7ce261ab0985f56a7095d8b291159e409e92f756b997cf1ea79b82c50ae5342979615b5eecc9cdb9da2aae86084d527576a0ac40421f273406fe9a9ae9f7f2976a6ae92a34436a188fafc0ce16d3e9cde0a7d8c48259077e556e6cd38dadc6308a13b673703513d674f1efca6aa7b3c9c2e76bb3b188cb0bdbafe958c68c66570723deeba707971d7e29c56f007fed8b363759f4f4c92f1f0bea3001704049fca97b5570dfdb64baa72da4f0da498ae459f9cf6ed2f2308002d2e9155f4d6ff4fa6df8bc977b8badecdacb861ff2383f77c82ea11ef785d02cbe745cde20571307e872229b1f7f5a7a76530f14fc1b11395e43516baddb45649709cee57f4f71d0db9434", "8", "68c0142307955783e7887413fa468d514cbe9b3ec45f6372e9e5a58a97699e5ee2b2bd9f286d5a0d01cb5852d4acf1e7b8c4aa49ebe653645eeab73835becc46707ce081aad82edfb3ff6024e147336d7a9ee57807648baa66b23a716e9425991e1c36747df90451a9bcc7b0a267d98e13a5bfd00f3d09461d28991094748f83c17e261cde64121ba434357396f96d55e5483eb5fd3657c9efb5807299c17b653170a799f14c527a19cfbdcd042ea785bcbd499315ccf535455178ec62e63e6a43e6079a8ad0b9b9a6234c3f80092036a1341f7671c7ab56e7b977ea5ba73d37ded2c01abaf1315225f88c88496cb5d308a8bd8a803a6ed80735718b7ce261ab0985f56a7095d8b291159e409e92f756b997cf1ea79b82c50ae5342979615b5eecc9cdb9da2aae86084d527576a0ac40421f273406fe9a9ae9f7f2976a6ae92a34436a188fafc0ce16d3e9cde0a7d8c48259077e556e6cd38dadc6308a13b673703513d674f1efca6aa7b3c9c2e76bb3b188cb0bdbafe958c68c66570723deeba707971d7e29c56f007fed8b363759f4f4c92f1f0bea3001704049fca97b5570dfdb64baa72da4f0da498ae459f9cf6ed2f2308002d2e9155f4d6ff4fa6df8bc977b8badecdacb861ff2383f77c82ea11ef785d02cbe745cde20571307e872229b1f7f5a7a76530f14fc1b11395e43516baddb45649709cee57f4f71d0db943400", .Okay}, + {.Shl, "-550b5ed902873c74359b29fc89d421c4b1876384d5d5ace33d797aaa3f482cb58adc28be1c2d11ebd5108308186eda69891dbb4746a4020a9e812950571faabee67e039fe8aa1da2cc0efa52a102773e0a9b6aa1dc90e4f6fe52660d9a02d056f540ed605d8c59232085f59d59369408f6b0813744c80d289db0055ec134a6f5e9f9eca2416dd1ff82f2ecaab05f30acd123b7b5c35bb93d95976cbceecf6681980d31d0bb0fb9ce95b1423eb50c3f9c616f5485e0177e6cc8f84db213cc1e4d2211827dddccc79cea68e3c7b0745f4fda3c66fc4de64e3a652cda2f8baded35ff8a926661579992c5a69b2234b8eea0c496d4e1bbb357b6619c418c3300f3ce79057ea503dfb37979fb4a63c67e37931915fdb18cc322e140c408299f76f3a7329644b64571c094e343f219c089c6e1b07bcf4f0aa142d5903faa29f005beba5e6dae9f89fe102f369731b6589efa408b01de7a06ef46587567540bac001069465f0b31d19fbebcb59ce2bc5d8a471e1f7e04c525676131f09284fe4fa7a11d8cd2132618a2519571839ac0e318ee1cd0ed668bbf6184d82ca1bac2919f56ba6e5289539456cbbf3171ee17f9368d06fac2f65ed616ae8fa6db5451468ee71a93435fea3483b8620462da76a60d1f1ad85b2cc15652ff07aec0aee68897e06bbe5d0c361499fd71c56ef7fc0c8e5c53de887a082da5a600767be4d3faa97556", "3c", "-550b5ed902873c74359b29fc89d421c4b1876384d5d5ace33d797aaa3f482cb58adc28be1c2d11ebd5108308186eda69891dbb4746a4020a9e812950571faabee67e039fe8aa1da2cc0efa52a102773e0a9b6aa1dc90e4f6fe52660d9a02d056f540ed605d8c59232085f59d59369408f6b0813744c80d289db0055ec134a6f5e9f9eca2416dd1ff82f2ecaab05f30acd123b7b5c35bb93d95976cbceecf6681980d31d0bb0fb9ce95b1423eb50c3f9c616f5485e0177e6cc8f84db213cc1e4d2211827dddccc79cea68e3c7b0745f4fda3c66fc4de64e3a652cda2f8baded35ff8a926661579992c5a69b2234b8eea0c496d4e1bbb357b6619c418c3300f3ce79057ea503dfb37979fb4a63c67e37931915fdb18cc322e140c408299f76f3a7329644b64571c094e343f219c089c6e1b07bcf4f0aa142d5903faa29f005beba5e6dae9f89fe102f369731b6589efa408b01de7a06ef46587567540bac001069465f0b31d19fbebcb59ce2bc5d8a471e1f7e04c525676131f09284fe4fa7a11d8cd2132618a2519571839ac0e318ee1cd0ed668bbf6184d82ca1bac2919f56ba6e5289539456cbbf3171ee17f9368d06fac2f65ed616ae8fa6db5451468ee71a93435fea3483b8620462da76a60d1f1ad85b2cc15652ff07aec0aee68897e06bbe5d0c361499fd71c56ef7fc0c8e5c53de887a082da5a600767be4d3faa97556000000000000000", .Okay}, + {.Shl, "75c0e38b03178565ed8f37e654198ef3c2dbeb9f3b05cbd58ff746913e1cd54000690e34df00b2c6788a7679174f3d4e05d99f308166fb6c62fc105838113a15abb3a10b2fe674c5003ca8ecfa21046930e7c2db9625cdb0a482b115b8b290093318f174645610e373d99e0ab03b0fca0779c505ae987abd0247b9d91ce2a4780be83a5b27139a004c80e3bbe1819e0d670e50db711a1748faec811d3cf3329884c849d0e1130e1a3427e1e7c81a0a5f1c482692ec2b0887bb24ecbb530bfcd9bfa6663b335f2843457298c3d110e8c9349b65ea903513860d9966510701c5c72308ae79dbd02564948adf92c0d4bf0a271e2116b76711257559883a8d53ab699dea998da0e15540d32996e749c4c00d8c88081e1191ff615f8d63c61f963994d6c9ec348a933b928ae082952d31e674f92a87afa6132ee7b94978656269c29e03fc0981bef43b0386fb9c449cc9935ee740ca7589819f93fe7583b32d35dad80775e0eb93e416443eaa8c61c24aa6432d191c53a1fdbc6889d2efe29f09277b14e890c03e86c85d00636ea76bfd316110caf211cc3bfcef3711689b122bdddbefacd116062f8b426cf33e3c0a2c13c7bf51dbdb6189ceef9a3ffde585b2f30a7ef73b1ec4eb105286d457ebcbe27fe721437418d858753f96b8ed729ba6b8802148a09824e2cf88bf29f712b19d7b2235ee554d5d5e6b6dd3c6fb9d3dd3dcee", "5d", "eb81c716062f0acbdb1e6fcca8331de785b7d73e760b97ab1fee8d227c39aa8000d21c69be01658cf114ecf22e9e7a9c0bb33e6102cdf6d8c5f820b07022742b576742165fcce98a007951d9f44208d261cf85b72c4b9b614905622b716520126631e2e8c8ac21c6e7b33c1560761f940ef38a0b5d30f57a048f73b239c548f017d074b64e2734009901c777c3033c1ace1ca1b6e2342e91f5d9023a79e66531099093a1c2261c34684fc3cf903414be38904d25d856110f7649d976a617f9b37f4ccc7666be50868ae53187a221d1926936cbd5206a270c1b32cca20e038b8e46115cf3b7a04ac92915bf2581a97e144e3c422d6ece224aeab310751aa756d33bd5331b41c2aa81a6532dce9389801b1910103c2323fec2bf1ac78c3f2c7329ad93d8691526772515c1052a5a63cce9f2550f5f4c265dcf7292f0cac4d3853c07f813037de876070df73889399326bdce8194eb13033f27fceb07665a6bb5b00eebc1d727c82c887d5518c384954c865a3238a743fb78d113a5dfc53e124ef629d121807d0d90ba00c6dd4ed7fa62c22195e4239877f9de6e22d1362457bbb7df59a22c0c5f1684d9e67c781458278f7ea3b7b6c3139ddf347ffbcb0b65e614fdee763d89d620a50da8afd797c4ffce4286e831b0b0ea7f2d71dae5374d71004291413049c59f117e53ee25633af6446bdcaa9ababcd6dba78df73a7ba7b9dc00000000000000000000000", .Okay}, + {.Shl, "-39835f8587c49a45532c58673357727459bba2f9afd5a25a5386abe12aad29ef74e231391727936e58c4b4394f29d151049b2b82189631639f524281056a29a0b82c43c47ee2455720a6a77f7647144fadbb39791cb30db15c32e6975aa698bdd61fe6454ca78423a2d19d4b81c311cc0fde29982800944e42e92997002e9ef2d5724934852738115fd4432d09dcbb4a11a0fbb99d4b46d8e157c33f6f038384365c479e70d6514167e927b7cbe44b3ee382ab68f49ac7b5da1fc9952714324d19510fc52b3b8d6f8bc7c0b1bb7acb70a0ef626506b7da674942834c8fcd8ae3777be64ff6958532b70ec031d441d0198c9a8daf3f6104a9268860d0b3e4ffa9c4677b60e496c4360b1d29f75e305f183ce2f58ee09487b54ebd1a2de96357e6417083d12834a7aecb1b165d5c73f2f1a41ec713d9d9bd766e1573c7d435a467abd28e299ec534f14877e1c7f7f36fe9e869e63c076a330e12b1c2f0ada75771972048477cc8b0bd23b20b1ff7ff599e5030ebf42391d14a25b6bbb38cb903dd209e8bdd55dd8b38fe6cbfca2cef301a87bc30dc70cd2ccfd4a7c908ae728666df3d40c7cd98566b13f8a09fa19331fb549801f1d9627ae96f505bf606498f477d038717ee9357f12d16549866025651f203a4e9bfebccd35768eb1d3f4876ffbc7b25f8f98686ec369847c0a0a0768f91b09e507f6203de1d0c8bdbd02ea122", "4d", "-7306bf0b0f89348aa658b0ce66aee4e8b37745f35fab44b4a70d57c2555a53dee9c462722e4f26dcb18968729e53a2a209365704312c62c73ea485020ad4534170588788fdc48aae414d4efeec8e289f5b7672f239661b62b865cd2eb54d317bac3fcc8a994f084745a33a97038623981fbc53305001289c85d2532e005d3de5aae492690a4e7022bfa8865a13b976942341f7733a968db1c2af867ede0707086cb88f3ce1aca282cfd24f6f97c8967dc70556d1e9358f6bb43f932a4e28649a32a21f8a56771adf178f816376f596e141dec4ca0d6fb4ce928506991f9b15c6eef7cc9fed2b0a656e1d8063a883a03319351b5e7ec209524d10c1a167c9ff5388cef6c1c92d886c163a53eebc60be3079c5eb1dc1290f6a9d7a345bd2c6afcc82e107a250694f5d96362cbab8e7e5e3483d8e27b3b37aecdc2ae78fa86b48cf57a51c533d8a69e290efc38fefe6dfd3d0d3cc780ed4661c256385e15b4eaee32e40908ef991617a4764163feffeb33ca061d7e84723a2944b6d7767197207ba413d17baabbb1671fcd97f9459de60350f7861b8e19a599fa94f92115ce50ccdbe7a818f9b30acd627f1413f432663f6a93003e3b2c4f5d2dea0b7ec0c931e8efa070e2fdd26afe25a2ca930cc04aca3e40749d37fd799a6aed1d63a7e90edff78f64bf1f30d0dd86d308f814140ed1f23613ca0fec407bc3a1917b7a05d42440000000000000000000", .Okay}, + {.Shl, "-eb3a7aa7a26bb704416eafad1e8ff370e419bf8deee8738626bb07d5df77100dda5a86f2914dcb0bacdb9e6ec20c6332696d0d408e501fe9918ea818be823ecb21138af0965de796c1f3075981fb3abe36b84fccf724baf413a38d4a67b77dcf23b17863700be79d28e01305b14188b77d824b8b7c87391e1a3e4a4987399ef2587235e84a03acac5e16acb8c03d4945238d90dd4e40d34e35a3f1facab48fd613a424569065d3ee0f5dfcd8f22068431f179050eea7c7c89c7d7eed9bb8f12ece3161a2ad5d48bb7a692a29c2286e8ee1faefd7e0e6424048e6a676a431c422e5f008568bf8d42d207bc2f4e88fecc943ef31c0c8e089aea8e47166da45c5a9b2ec73d96b2818e63aedab6b37eea12cef33a7266f15cb86127aa7a4cf8bb8a9dab8f9aa79821938957963a386407c704e51959e1cc6447424285ba88310435c2ce91e8a14fc1fd0fcd584523417a299971c3c1827636514fae8565c5050c8fc651e0ac1fe2fc93fe08a7a379b9ade64fb96a312214bc03c42d7c37811df7483f8dbabc337e5530d7930277946fd04e2b57ec0d92283f19ef2f0a95854f989a76b0f30c1c30d1c704673e9c56a05944af5ad30efa887e9da8aa65c0a89a08b75cb6d4ba3368271078bba6323c956ad267d67691c2647da5bb8d28cc84a378010982420b9132d35de439b60d5da53489a97cd1e718cdc4552a9e1200fea780975", "54", "-eb3a7aa7a26bb704416eafad1e8ff370e419bf8deee8738626bb07d5df77100dda5a86f2914dcb0bacdb9e6ec20c6332696d0d408e501fe9918ea818be823ecb21138af0965de796c1f3075981fb3abe36b84fccf724baf413a38d4a67b77dcf23b17863700be79d28e01305b14188b77d824b8b7c87391e1a3e4a4987399ef2587235e84a03acac5e16acb8c03d4945238d90dd4e40d34e35a3f1facab48fd613a424569065d3ee0f5dfcd8f22068431f179050eea7c7c89c7d7eed9bb8f12ece3161a2ad5d48bb7a692a29c2286e8ee1faefd7e0e6424048e6a676a431c422e5f008568bf8d42d207bc2f4e88fecc943ef31c0c8e089aea8e47166da45c5a9b2ec73d96b2818e63aedab6b37eea12cef33a7266f15cb86127aa7a4cf8bb8a9dab8f9aa79821938957963a386407c704e51959e1cc6447424285ba88310435c2ce91e8a14fc1fd0fcd584523417a299971c3c1827636514fae8565c5050c8fc651e0ac1fe2fc93fe08a7a379b9ade64fb96a312214bc03c42d7c37811df7483f8dbabc337e5530d7930277946fd04e2b57ec0d92283f19ef2f0a95854f989a76b0f30c1c30d1c704673e9c56a05944af5ad30efa887e9da8aa65c0a89a08b75cb6d4ba3368271078bba6323c956ad267d67691c2647da5bb8d28cc84a378010982420b9132d35de439b60d5da53489a97cd1e718cdc4552a9e1200fea780975000000000000000000000", .Okay}, + {.Shl, "de5b972fd887ff18ce1444b39418de9482e4f0027f5595286bc969f0b5a1b907632de9bdb16902ab235e800fcf347a710cf49adbac676ef53f60163d738412bd232dae377f7949fbfb115c71628b36fd14eb8488144b5283e402f53b7596a875bdc42184b8c25266e726c700184f38f56ca08698819866d16483a4a1ade145770c21570651430f1efc6f0014f2f851f1c51f8214208eabd277a16e4e91bd1b8fc294c2ba924c8055942f380f1b1a4766e309b748c8809a875bf4bb740de7d87beee2ac67e8d1722cdd92339980a2cbf545a2abb63f100ef09bfbb5f4539b99cccdfe695bac41e6909eae374f4991d702a447e462a519f0359d3d9e154b0d9f83c08f0f9e236476323dcb68ae99b09ff19fda8e3c9bd381af25e3ff7218a44cd66ee30f71e5e6f47f1792a6cb6670d0656ee433ad3603554e8cef422190cd2013042ae573ee2547c03b637aadad4b523baf5bed03e535bd57392b22c07dc1cc4bd09c568afc5f60acbf82de3715a9db5ecda1a9a28d8111007cdf700d316440333c76bda0cd7e76a0361f89359849769e2762c4474091a70123594c069699adc7828bc19ee1882010b49360d73d612922eaa8174710226a4072b878ab617db1ebbd82bca80b817f9549c7095f6e25c91f3134760f3549905c88195a1ee190099e61e4d1518ac65a8237a9674964adef9072b8f011949451fc7bcc671add6674b", "72", "3796e5cbf621ffc63385112ce50637a520b93c009fd5654a1af25a7c2d686e41d8cb7a6f6c5a40aac8d7a003f3cd1e9c433d26b6eb19dbbd4fd8058f5ce104af48cb6b8ddfde527efec4571c58a2cdbf453ae1220512d4a0f900bd4edd65aa1d6f7108612e309499b9c9b1c00613ce3d5b2821a6206619b45920e9286b78515dc30855c19450c3c7bf1bc0053cbe147c7147e0850823aaf49de85b93a46f46e3f0a530aea4932015650bce03c6c691d9b8c26dd2322026a1d6fd2edd0379f61efbb8ab19fa345c8b37648ce66028b2fd5168aaed8fc403bc26feed7d14e6e673337f9a56eb1079a427ab8dd3d26475c0a911f918a9467c0d674f678552c367e0f023c3e788d91d8c8f72da2ba66c27fc67f6a38f26f4e06bc978ffdc862913359bb8c3dc7979bd1fc5e4a9b2d99c34195bb90ceb4d80d553a33bd08864334804c10ab95cfb8951f00ed8deab6b52d48eebd6fb40f94d6f55ce4ac8b01f707312f42715a2bf17d82b2fe0b78dc56a76d7b3686a68a36044401f37dc034c59100ccf1daf68335f9da80d87e24d66125da789d8b111d02469c048d65301a5a66b71e0a2f067b86208042d24d835cf584a48baaa05d1c4089a901cae1e2ad85f6c7aef60af2a02e05fe55271c257db897247cc4d1d83cd52641722065687b86402679879345462b196a08dea59d2592b7be41cae3c046525147f1ef319c6b7599d2c0000000000000000000000000000", .Okay}, + {.Shl, "9a2fe60ff4431db1de5d7ab01f823a15103e12907363f1cbac0f6a97e2c9a4d9a12f9ddcc7827a79ea1cce959c4ba3a5a7bc46ed8279fe29122a6d0da8a4ec1444411c908769e841a1488e238eed7188b86891f089ac37187b715badab4b292ff9e1769471072f09aecc7cd761e46be5a74a313326e1ceaeb7bb8b9428d363598aae76bb275c32cfefe1acf7843b777b3f4504d68e5ebf8cc9b6d80260230f1cdd16b011e3871acd633ca351778def64db1f28aee75a80a81f40d84accf9f824c59061d9b44678e65acf3e00eda89a2c85db53eb7cb042b683ca688b2e9a1b33314b59f7b8f51b99dab6ad2d643225edf7af979f58a3bf57a5d84ec72a40a1428e07e15553817a951474302ea111a4c6b3601ebca2c908f59cbd0c90fecd5398021d57de9af28e96b4fa60d758f156a9811005e5d4520a92c44301020153b1e5df10bc77f9711b11de1a9414c18cf269bfc2be6ed9e465fa3159c7dd47dcadf79da09be6ec9618a50ce40449756aa5fe33196848323d9de4f49322ee9ff17f2f41f5a880b221127f15279a35f7dd6578c9f9eb471db0db61c87f194ded8b10b99a3f669c7d94471bd7d12c8c27cded556b6b5d71aad1cd53fc259b0e76a5041e11b488eaf69f26ff2e53b7802f531a75f8f6daae84f042151a7cd87ad82cb34b091aed36b89beeaab9301a02fb3c53b5e8be8231e5b1123a584d1b24b381d580", "2a", "268bf983fd10c76c77975eac07e08e85440f84a41cd8fc72eb03daa5f8b26936684be77731e09e9e7a8733a56712e8e969ef11bb609e7f8a448a9b436a293b051110472421da7a1068522388e3bb5c622e1a247c226b0dc61edc56eb6ad2ca4bfe785da51c41cbc26bb31f35d8791af969d28c4cc9b873abadeee2e50a34d8d662ab9daec9d70cb3fbf86b3de10edddecfd14135a397afe3326db6009808c3c73745ac0478e1c6b358cf28d45de37bd936c7ca2bb9d6a02a07d03612b33e7e09316418766d119e3996b3cf803b6a268b2176d4fadf2c10ada0f29a22cba686cccc52d67dee3d46e676adab4b590c897b7debe5e7d628efd5e97613b1ca902850a381f85554e05ea5451d0c0ba8446931acd807af28b2423d672f43243fb354e6008755f7a6bca3a5ad3e9835d63c55aa60440179751482a4b110c0408054ec7977c42f1dfe5c46c47786a50530633c9a6ff0af9bb679197e8c5671f751f72b7de76826f9bb258629433901125d5aa97f8cc65a120c8f67793d24c8bba7fc5fcbd07d6a202c88449fc549e68d7df7595e327e7ad1c76c36d8721fc6537b62c42e668fd9a71f6511c6f5f44b2309f37b555adad75c6ab47354ff0966c39da94107846d223abda7c9bfcb94ede00bd4c69d7e3db6aba13c1085469f361eb60b2cd2c246bb4dae26fbaaae4c0680becf14ed7a2fa08c796c448e961346c92ce0756000000000000", .Okay}, + {.Shl, "ac5eb473b383b32dc057712cd826737344f0202183721b59f295fb6e59b1e3f2e41f2e0be3372367b3d60b4d32e590cff26f5c57f3fbf010f76d910ac2dd1cd27a389dd881e15aa2f858eef085d1600341a1d30e546a7307eb480485e6836751a46e1d659890f2ab141cce38ab82dee2808fb6c1e7f0f38a3e483b2399edc1b1065df62f022233a5b92e6adcf01c2c18419c9c0715865ae6b26efe61dcbe6e514f39d9c37fa8b11973610133995af05459402d1e5d1343152dff363bc849915856a80d550d0f4fc93528179eef37b8ab06a0817f67681fb398b469d674acdfcbfd306a46ef60c67c2a2c2d78116ed1c54a6c78f49af70db6ca7175d557e4fd7fccd5b38ca4d4a7b8d7ee89070d57aead0c7e13f4a3468acf20dafe8e79034cdc46eb1e10a355ccb153d17a4a8479ada56bbb400950a9978037e22a471dc88fdb6f16414e008545d338aaa2cccf08b61d4469d38c04642853126dbd007f188b5ecbbbfcd8b3f64ca3ee1aa6086123274eb4c2e31a208b93f23e47289bb1286d2887ae3fa92cee9b22150adf9d68ee52b0bb4d23d88e962d5424fbe708bc9587501b9dbbc72f9324d1cc61a6a9c27506aeb3b72dcd47a9fb3937047ff988883e7f1c8f34068f36522300e887058f96ecbfb1ebb01654b4036e2906ff0b8e67e9f02f9da09e54b9036ad69ccbea48314ac6937f6b91ad1435cb3752cdb8c127723", "56", "2b17ad1cece0eccb7015dc4b36099cdcd13c080860dc86d67ca57edb966c78fcb907cb82f8cdc8d9ecf582d34cb96433fc9bd715fcfefc043ddb6442b0b747349e8e2776207856a8be163bbc21745800d06874c3951a9cc1fad2012179a0d9d4691b875966243caac507338e2ae0b7b8a023edb079fc3ce28f920ec8e67b706c41977d8bc0888ce96e4b9ab73c070b0610672701c56196b9ac9bbf98772f9b9453ce7670dfea2c465cd8404ce656bc1516500b479744d0c54b7fcd8ef212645615aa03554343d3f24d4a05e7bbcdee2ac1a8205fd9da07ece62d1a759d2b37f2ff4c1a91bbd8319f0a8b0b5e045bb471529b1e3d26bdc36db29c5d7555f93f5ff3356ce3293529ee35fba241c355ebab431f84fd28d1a2b3c836bfa39e40d33711bac78428d5732c54f45e92a11e6b695aeed002542a65e00df88a91c77223f6dbc5905380215174ce2aa8b333c22d87511a74e301190a14c49b6f401fc622d7b2eeff362cfd9328fb86a9821848c9d3ad30b8c68822e4fc8f91ca26ec4a1b4a21eb8fea4b3ba6c88542b7e75a3b94ac2ed348f623a58b55093ef9c22f2561d406e76ef1cbe4c934731869aa709d41abacedcb7351ea7ece4dc11ffe62220f9fc723cd01a3cd9488c03a21c163e5bb2fec7aec05952d00db8a41bfc2e399fa7c0be76827952e40dab5a732fa920c52b1a4dfdae46b450d72cdd4b36e3049dc8c000000000000000000000", .Okay}, + {.Shl, "7ece3cc35c8f90516227fe5aeb05642521290d048c81039d2e679cc499bd5511830628a9ee275557137323a25a8c472f78efa518e7e069ebd576bdaa76b836eded0ba2386ccb21fefb7cfe336f754afa8f205560b144acfae900436171a07b039dc45abce5c08e98a0705795251cd10f289af5c7ff2d8c05e39a03028495c3c02d7f4a707dd7d9f7028c2764eedde5ea38e1d1d352a1ace64b441f4d7ca3643d2337e64b35472b3fe623e71715cdadb00334bb1b86bf9f2b632781421d25a44fa1d9ea3e20b27c58730ee0acfb3fceaf663bd9ddae339bdd31cfe99d37ac6e411724384899a25d835b77ea9616c466da1b7aa52e996bcca3dbba3d89644a23f0e94beb1b1d8fb91251d0ca1e0caf54dc9210d7d420f9b37cffd07b4942e9e7da3d851914534565071394a9b88d40b084d166efbba670d333b3022bf72c32407e690f28e397dd07cb366f4e345fbae5cd2bbd89931506a6468f34f016cdeb84d959dd43f05b6040d622a91d57ceb762aedb75f540f8a923ce240d6d3d15215c73c515808c36fa74f0a59ff88e55fde5526c70ef3ea0f310354181cd8b8712cd694d914df91a09ec3da2a95fc0b09a8c9b9f4ac10af66ee78d491c1b18c889a5e8c47f16fe39a5d1f7aa9df0492f96d66d3359d57483302340a946083016c3df47f940e03875245038d8a3eaf49efab67e1157e6132b2098afc80159dbdcc2d001", "2f", "3f671e61ae47c828b113ff2d7582b21290948682464081ce9733ce624cdeaa88c1831454f713aaab89b991d12d462397bc77d28c73f034f5eabb5ed53b5c1b76f685d11c366590ff7dbe7f19b7baa57d47902ab058a2567d748021b0b8d03d81cee22d5e72e0474c50382bca928e6887944d7ae3ff96c602f1cd0181424ae1e016bfa5383eebecfb814613b2776ef2f51c70e8e9a950d67325a20fa6be51b21e919bf3259aa3959ff311f38b8ae6d6d8019a5d8dc35fcf95b193c0a10e92d227d0ecf51f10593e2c398770567d9fe757b31deceed719cdee98e7f4ce9bd637208b921c244cd12ec1adbbf54b0b62336d0dbd52974cb5e651eddd1ec4b22511f874a5f58d8ec7dc8928e8650f0657aa6e49086bea107cd9be7fe83da4a174f3ed1ec28c8a29a2b28389ca54dc46a0584268b377ddd3386999d98115fb9619203f34879471cbee83e59b37a71a2fdd72e695dec4c98a835323479a780b66f5c26caceea1f82db0206b11548eabe75bb1576dbafaa07c5491e71206b69e8a90ae39e28ac0461b7d3a7852cffc472afef2a93638779f5079881aa0c0e6c5c38966b4a6c8a6fc8d04f61ed154afe0584d464dcfa560857b3773c6a48e0d8c6444d2f4623f8b7f1cd2e8fbd54ef82497cb6b3699aceaba419811a054a304180b61efa3fca0701c3a92281c6c51f57a4f7d5b3f08abf30995904c57e400acedee616800800000000000", .Okay}, + {.Shl, "bcea33f4f7ccba4fbf92a4df8852f6d225b7e6d8d0968f09c62f03e22294a490890ec1d57f0532bcfcdf9a83ff8f53874277063e7ccb0133554064050058b3913a22817d52e96f30248c57c4b05b1bf9bda749d4656e9b01105730d0714ee85c96c6b7b9252d89f57f41709b929e3702766c13ae9537c0ae2e099d536404252b3dca7b6aa5ace68d1ee46003d8b3b87df61fd6017a70c99aaba220dde4631bae42ed7f70bbe463a773fa2a493876f812db0be8c2cdef534e8eb02321f0a4b13ec9aca5f828fddd46c096720bec65657ad25e526000eb80ff2c07b92c9d284c1564fc9013ff275570da0475f96bad8f61126861c0bc68774a3f808d758176437eeafdaa5d22e029fcd7870973c4bc864ca4c5fe37e37ec93146d4a48f8a3801c1fd57287a5870c8dc8de67c38bf2b119f3cff97b580ebaa22e35bd366e2220325d4cea4fb39852be88d0b446e05ec31a324cdf24f6a0160e84dec416b69fa4a288dd6a608730611decbcbc96d45518338979f8c043e0c0e5102b2f6a3033150d2ac59be03ebe356c2f0d6453a018c2ea7b831f0292473d3cb9b9dec605ca256eda225aa58cf1e3d727b32594e4948e686107790f666209522e986d31109b9355ed301c2e31f0b4ebebcca68b62ab6071c24dd85e619190e02a075d4a266cff60c0e22f78512924f34178321194560c54612d8ad1a50c4af0f985b1c97724d975f", "51", "179d467e9ef99749f7f2549bf10a5eda44b6fcdb1a12d1e138c5e07c445294921121d83aafe0a6579f9bf3507ff1ea70e84ee0c7cf9960266aa80c80a00b16722744502faa5d2de604918af8960b637f37b4e93a8cadd360220ae61a0e29dd0b92d8d6f724a5b13eafe82e137253c6e04ecd8275d2a6f815c5c133aa6c8084a567b94f6d54b59cd1a3dc8c007b16770fbec3fac02f4e19335574441bbc8c6375c85dafee177c8c74ee7f4549270edf025b617d1859bdea69d1d604643e149627d93594bf051fbba8d812ce417d8cacaf5a4bca4c001d701fe580f72593a50982ac9f92027fe4eaae1b408ebf2d75b1ec224d0c38178d0ee947f011aeb02ec86fdd5fb54ba45c053f9af0e12e789790c99498bfc6fc6fd92628da9491f14700383faae50f4b0e191b91bccf8717e56233e79ff2f6b01d75445c6b7a6cdc444064ba99d49f6730a57d11a1688dc0bd86346499be49ed402c1d09bd882d6d3f494511bad4c10e60c23bd979792da8aa306712f3f18087c181ca20565ed460662a1a558b37c07d7c6ad85e1ac8a7403185d4f7063e05248e7a797373bd8c0b944addb444b54b19e3c7ae4f664b29c9291cd0c20ef21eccc412a45d30da62213726abda60385c63e169d7d7994d16c556c0e3849bb0bcc32321c0540eba944cd9fec181c45ef0a25249e682f0642328ac18a8c25b15a34a1895e1f30b6392ee49b2ebe00000000000000000000", .Okay}, + {.Shl, "5e2cf14f3bf45937bd5b882fb318703f3ea621896d5d00cb5cd2677f60450f3e2cade6551bedae931d3720b37332ffd65c6fb6a8512bd03b83077b1523dac5765308a8f3d10543093ae5789f497090ed94664f6eba820e266b80931cb9f4b133a2e8c2e2ae55de84c394492312c42dc11ccb57b3cd7df15267641e06e834b526f4f6954d1806809b57f723659688cdb989c50f17081a6b4270cfa8802e86c1e149ada2e23e4b7a6a6e955704df27a9018bc3bbfe390f3cb17ab97040039fbfa21e9079821660f468a6c7f9e3c197950e96e5cc607c0f7d918e6dfb42723f8919856dee8528dca18912e360515ee3992e7cd55566fc1ed494e2203b0cd9e221a997e66984ee75bbe41e7cee6937335508e03fd40cbe2d9d3a7ef6ef4bfbb8ed74512d0d7b0d809ffa14215b64ebb370044db6225d291aad46069d3974d3d55af430dc01db264959ec6eedf2416dceda651a046113ee5b773aa1798ed47a6c6092b8464a520761d2e15f7849a555c5f664e138be3a1d84f0240fc087d718fbf342d7a0c14bf82d03ba201fd50b20147013b22d81bd3bef85c5efbda7f4d3c8585a2bb0accb28139b3bbd1dec2860bd1fd3fae49d2156180e781517f4c8441aba1f5c70ccdf4d6b5984b42c740c2b30f9fb7580f8a7c6854d618bb2c74d438eb8d93ef2fff6b0c074a34c16bbb06cc7c4311d1e03ed5ab27fce7d0ab7cb060625d0", "6c", "5e2cf14f3bf45937bd5b882fb318703f3ea621896d5d00cb5cd2677f60450f3e2cade6551bedae931d3720b37332ffd65c6fb6a8512bd03b83077b1523dac5765308a8f3d10543093ae5789f497090ed94664f6eba820e266b80931cb9f4b133a2e8c2e2ae55de84c394492312c42dc11ccb57b3cd7df15267641e06e834b526f4f6954d1806809b57f723659688cdb989c50f17081a6b4270cfa8802e86c1e149ada2e23e4b7a6a6e955704df27a9018bc3bbfe390f3cb17ab97040039fbfa21e9079821660f468a6c7f9e3c197950e96e5cc607c0f7d918e6dfb42723f8919856dee8528dca18912e360515ee3992e7cd55566fc1ed494e2203b0cd9e221a997e66984ee75bbe41e7cee6937335508e03fd40cbe2d9d3a7ef6ef4bfbb8ed74512d0d7b0d809ffa14215b64ebb370044db6225d291aad46069d3974d3d55af430dc01db264959ec6eedf2416dceda651a046113ee5b773aa1798ed47a6c6092b8464a520761d2e15f7849a555c5f664e138be3a1d84f0240fc087d718fbf342d7a0c14bf82d03ba201fd50b20147013b22d81bd3bef85c5efbda7f4d3c8585a2bb0accb28139b3bbd1dec2860bd1fd3fae49d2156180e781517f4c8441aba1f5c70ccdf4d6b5984b42c740c2b30f9fb7580f8a7c6854d618bb2c74d438eb8d93ef2fff6b0c074a34c16bbb06cc7c4311d1e03ed5ab27fce7d0ab7cb060625d0000000000000000000000000000", .Okay}, + {.Shl, "-a639714200090ff6f6b4d80239657308ed02a6555a893be91caced0ca053a32f9afe00f959f8a64b7679a8b5897ee565043a0a5087f0413484d77d8cf3300fe734a03c5066b1b80b146d6737a71a6e4a342175183126c262e3bc59049f23ea321d21a06f0b4b6ea8748c0eaad6c92c13eeaa7c33a967d3f00a54277d4fb967552660389be2f73833c937a6de7dba45a7e3a82942d922254afe8b02908a36b5540129674d0de61744b9e9b93b5f58a7b6a9d37c5ea1020954b3d5e89338d8b27a18664584672ddc709a1397fa3b3677cd3b8735d9999d0221312c1f4f7252eda94c7b787165ae4ce63b3eab5bf913178fe880195c2fe7e57836573a9cbc70ad96ccd3cbcf891fc00cb6dd52aab1d97455b747e8f87af13edfef9658819ab3ffb2ad7c85e621f24a9d5d09071e39c3b2a7dc49fe3aa228af7ce5c701f04115cbe443e9cf2d0c982c928a0fe404cbf6b0c67b12cb2bdfec2cd1a6f0714b1290d192470073f6a4d68959ab397bd44619e8aac558624b4a0d5bfb5b6b82f80d15a42fe19a86142b569a81ade9350eeece1d792e2750bfa3d5c24f00e285963799d62bd1222cbc385ac32aae0d50e02d974102bbd3487d5b6741d54447cf07878288bb224f1d2c47a9f57d1cdc4e6ebe16edd75e935ea66e91c7c2effadb2e7f3bbb58e4029d7299f4053637c58f3e7ae6b519118c8c593d5301c99fc6b30766775ca5", "39", "-14c72e28400121feded69b00472cae611da054caab51277d23959da1940a7465f35fc01f2b3f14c96ecf3516b12fdcaca087414a10fe0826909aefb19e6601fce694078a0cd63701628dace6f4e34dc946842ea30624d84c5c778b2093e47d4643a4340de1696dd50e9181d55ad925827dd54f86752cfa7e014a84efa9f72ceaa4cc07137c5ee7067926f4dbcfb748b4fc7505285b2444a95fd160521146d6aa80252ce9a1bcc2e8973d37276beb14f6d53a6f8bd420412a967abd12671b164f430cc8b08ce5bb8e134272ff4766cef9a770e6bb3333a044262583e9ee4a5db5298f6f0e2cb5c99cc767d56b7f2262f1fd10032b85fcfcaf06cae753978e15b2d99a7979f123f80196dbaa55563b2e8ab6e8fd1f0f5e27dbfdf2cb1033567ff655af90bcc43e4953aba120e3c7387654fb893fc7544515ef9cb8e03e0822b97c887d39e5a19305925141fc80997ed618cf6259657bfd859a34de0e2962521a3248e00e7ed49ad12b35672f7a88c33d1558ab0c496941ab7f6b6d705f01a2b485fc3350c2856ad35035bd26a1ddd9c3af25c4ea17f47ab849e01c50b2c6f33ac57a244597870b586555c1aa1c05b2e820577a690fab6ce83aa888f9e0f0f051176449e3a588f53eafa39b89cdd7c2ddbaebd26bd4cdd238f85dff5b65cfe7776b1c8053ae533e80a6c6f8b1e7cf5cd6a32231918b27aa603933f8d660ecceeb94a00000000000000", .Okay}, + {.Shl, "-f8d4ba503afbf9a2c2435518f1b2dd6fd69aab478b277b07d303883d308b5043272c4869ef234d6aa84ef8ba28b1348f2f10ed399273ba23ffbe33460c2256497fb35dc20659ee8dfcd6314dd2e379073976a34011c72ee078fa5b750c524325da37a74ca49444a85aa85ce07a2e26f5a640d40820c75bb9be2b9fbf4db38c8fb10269b842854b4b3e3a9c8af0df6e2014a3d0872ba9b7cda0053b5b2b1ff533b8112013210031839b57768ecb9680a8987c498b1d42941b0614c9d2056764a080b7ddf1a89c099091bc0433fd26e22b1fde549be16777317b8ed45f5715bada5f0b860cf3d040571a58054b2bf4951312fe07cfc26a5fc6e2844b857bdab27270d13d20e6d284b6de5a480f9c074ddae4ec9789690097f95ce07503c04cc069fce02beeff7a01bb3cc444814ca2c65f543b4912cbd00a2c0914f09509da4ac6a712b09d21da5da7a89808dc94246548b06b82a191f6d06d6dc536588903d3e39f0885c9f9dbd645ef32c33f01b5e9cc7bc486b9a4a7acc3d403102ed5e5955fbdac3894339b76d528625f89eae8c0ebe1edbb17a644f0fd4ddeb86976fcbe7d0184b24e2d1e6909b600437bb094bd5d8a31053943b5ed984bc176d01d083a5df062e4e70383ae93c18ad6d52ba94afb46e9b96b49eca2d36565277410b91ac6f88109f731e7dc485e026eaa2fbca3725285a9ddcc95bb4de185141a7c0e2500", "3a", "-3e352e940ebefe68b090d5463c6cb75bf5a6aad1e2c9dec1f4c0e20f4c22d410c9cb121a7bc8d35aaa13be2e8a2c4d23cbc43b4e649cee88ffef8cd1830895925fecd77081967ba37f358c5374b8de41ce5da8d00471cbb81e3e96dd431490c9768de9d32925112a16aa17381e8b89bd699035020831d6ee6f8ae7efd36ce323ec409a6e10a152d2cf8ea722bc37db880528f421caea6df368014ed6cac7fd4cee044804c8400c60e6d5dda3b2e5a02a261f1262c750a506c18532748159d928202df77c6a270264246f010cff49b88ac7f79526f859ddcc5ee3b517d5c56eb697c2e1833cf41015c6960152cafd2544c4bf81f3f09a97f1b8a112e15ef6ac9c9c344f4839b4a12db7969203e701d376b93b25e25a4025fe57381d40f013301a7f380afbbfde806ecf3111205328b197d50ed244b2f4028b02453c25427692b1a9c4ac2748769769ea260237250919522c1ae0a8647db41b5b714d962240f4f8e7c221727e76f5917bccb0cfc06d7a731ef121ae6929eb30f500c40bb5796557ef6b0e250ce6ddb54a1897e27aba303af87b6ec5e9913c3f5377ae1a5dbf2f9f40612c938b479a426d8010deec252f57628c414e50ed7b6612f05db407420e977c18b939c0e0eba4f062b5b54aea52bed1ba6e5ad27b28b4d95949dd042e46b1be20427dcc79f71217809baa8bef28dc94a16a7773256ed3786145069f038940000000000000000", .Okay}, + {.Shl, "-daeec82b57fe047bee14894348ecf3c933501aaf9bc66a5ae68ae8fe48f21f24953e196798c7b20f2b20ce83c9508dd0879174e8bc90a9d71eea31e1942712afad9669de8414ecbe2abee5d27972606df43c3440048a2ca28335255e43b8054aceae701ff2e673d9859b302711dcefefc1107a65fbb1d8274fc1a27279d964ba9f2e2fa1e9604205855f63388c14c38a2ab8401064d222d8b0021ce82796d7adc06c4ed453b0d7fa74b3dd9b4832b46f9f80bcb7c177fd44ab532aa1ca0cf4641879d3e95efe7ca43d99661326fcdcda93969643d880146fa914c135ff88d32471ab555450182db4fdc7eab746b81ace4043738e18ba7a82a81c5da3ab526c1c069cdf3084aba44148085f055a651036ed0f1133f7f4ced3c212750c986ad542d454b9d8cd99cd63aa98ac27cf7a95c47621e1a9239730a6977fc35305cb289b7b1c7c3c9266d83a8dbc4ef335b3db1cfab12971a5fee0069758994fee2e53c85803e1d078765d06e5bbb0d351cd1c03f7c72f604aa7266beb8a46c68fbfabf4f7fe23ae6d98336bf4fcc7af14d0336e87f072fed9d9e5ee971071cbe322dd31f5629ffe14c3bb701ab08093791775fc3e607ad5957e330765ddeb74a18e9c0d9f74288d68eb4907c84075fc11a3a091b64fc58f01a6dadb01317870ca2156972b944efc1ffe969a00188646e29368293b14c57dc94787bd6a052934126113cd", "26", "-36bbb20ad5ff811efb852250d23b3cf24cd406abe6f19a96b9a2ba3f923c87c9254f8659e631ec83cac833a0f254237421e45d3a2f242a75c7ba8c786509c4abeb659a77a1053b2f8aafb9749e5c981b7d0f0d1001228b28a0cd495790ee0152b3ab9c07fcb99cf66166cc09c4773bfbf0441e997eec7609d3f0689c9e76592ea7cb8be87a5810816157d8ce230530e28aae1004193488b62c00873a09e5b5eb701b13b514ec35fe9d2cf766d20cad1be7e02f2df05dff512ad4caa872833d19061e74fa57bf9f290f665984c9bf3736a4e5a590f620051bea45304d7fe234c91c6ad55514060b6d3f71faadd1ae06b39010dce3862e9ea0aa071768ead49b0701a737cc212ae910520217c15699440dbb43c44cfdfd33b4f0849d43261ab550b5152e7633667358eaa62b09f3dea5711d88786a48e5cc29a5dff0d4c172ca26dec71f0f2499b60ea36f13bccd6cf6c73eac4a5c697fb801a5d62653fb8b94f21600f8741e1d9741b96eec34d4734700fdf1cbd812a9c99afae291b1a3efeafd3dff88eb9b660cdafd3f31ebc5340cdba1fc1cbfb676797ba5c41c72f8c8b74c7d58a7ff8530eedc06ac2024de45dd7f0f981eb5655f8cc1d9777add2863a70367dd0a235a3ad241f2101d7f0468e8246d93f163c069b6b6c04c5e1c328855a5cae513bf07ffa5a680062191b8a4da0a4ec5315f7251e1ef5a814a4d049844f34000000000", .Okay}, + {.Shl, "-b7d178baa0c732f2d3eb8818197b170f7721323101fb3d16e96e800bf1927679548034c90c0c29ebc4641f0c16bfb05cf554170b6b60b00085218a658d8fcdc3ef07315c27bf43fdfea34d50076a8b19a4c9ec5d2c77000eaa36d215e7bd962c6c2f59756738c141178f738424ca6a695526e77679ff86dcdb049dfee82a68b9a7cfe1e424946b0f4bf44ae2e0ba6aa629e9a51e6eb95f9aad87be548736ac1b76ca6d0a06159b02305834963418c406f19199da7cb29a71fd8da7bdef82fd4e220a85568efb74ef7897f935e49d4a8e486ec4ab6c2796eb880941867cf9dcca29257c1765381a78720b0099a9b34d531cddc30d6e892b0bf77b95c5984059dd3e3d7f5a841e2d5570cecc3e6726e232772ae6436ddad560514e5da9feab07a91752d4bcbd3caa28ba3a3def157179f7acdfed2f73b76429b08d295186c60354e32509a6ca767e4b8b4f8e888dd50cedfb67e5b16fa615e6d0bd18339f3586c23208c4b854a05924dd2e654075e4f10006a92e6ed29553de53c77852f569221dfe2bce46ab2f53a79dcbec07571f7ceb32337bd22d92f6c1a29998d2c447b084a68836730677f4201096c4a7bd0b9924a3fffa9d983b3b74b6561a839f09a20e1c47f9c394849b467f88edc1f812fbf3d6b3e30d3331c5f0ab8e6b08fdafcb3ba12c6c22ab69dba48a48631648d23a50c9035c4eb5e40a65b9ced2a731b48982", "1d", "-16fa2f175418e65e5a7d7103032f62e1eee42646203f67a2dd2dd0017e324ecf2a9006992181853d788c83e182d7f60b9eaa82e16d6c160010a4314cb1b1f9b87de0e62b84f7e87fbfd469aa00ed516334993d8ba58ee001d546da42bcf7b2c58d85eb2eace7182822f1ee7084994d4d2aa4dceecf3ff0db9b6093bfdd054d1734f9fc3c84928d61e97e895c5c174d54c53d34a3cdd72bf355b0f7ca90e6d5836ed94da140c2b360460b0692c6831880de32333b4f96534e3fb1b4f7bdf05fa9c44150aad1df6e9def12ff26bc93a951c90dd8956d84f2dd71012830cf9f3b994524af82eca7034f0e416013353669aa639bb861add125617eef72b8b3080b3ba7c7afeb5083c5aaae19d987cce4dc464ee55cc86dbb5aac0a29cbb53fd560f522ea5a9797a79545174747bde2ae2f3ef59bfda5ee76ec853611a52a30d8c06a9c64a134d94ecfc97169f1d111baa19dbf6cfcb62df4c2bcda17a30673e6b0d8464118970a940b249ba5cca80ebc9e2000d525cdda52aa7bca78ef0a5ead2443bfc579c8d565ea74f3b97d80eae3ef9d66466f7a45b25ed83453331a5888f61094d106ce60cefe840212d894f7a17324947fff53b307676e96cac35073e13441c388ff3872909368cff11db83f025f7e7ad67c61a66638be1571cd611fb5f96774258d84556d3b7491490c62c91a474a19206b89d6bc814cb739da54e636913040000000", .Okay}, + {.Shl, "c37bfc5a84f5cc317101953ad895728ad6525a3d7318b522625cbb0329c6842efdefcc516dcb24734b15f59c5f1965573cc9d313dc337a2363c28422b0d3430d6b8738823c941148d825cd549613733c741b74140c37744fd6e5fefe2db99e1a61711edca6081ced5dcb15a4ecefb970a047b97901987358961b6647b7dfe4a2759fb021d5ca44c667d34b32141e228a375354be6ede304de8ff3376232c416b6109a2781c450a07b8702bf674a943720da2fae5160ca893192f6bffd630a2afe1883367025cd771a477af84dc357f44bcbebaf02b3e0bbea931a4802263103acb2d59cdc9ba12315c351be306bf9d5d89f960f6cb7da07c5bc4367f2388d3a359fe7a5a4bfb9d14c908f5627b58a3c3e81458f255eeadba725ffbcfae38716e246c2e22d10154daeaeedc21937125d47feb3cd41920dcc01d668eb4f75028d88926a208e377356e0e56a2bb3c09337f33ec03c46f40e47a6628a67c7ccfe0211d6cd90415caca2efbf98835d1bd4ede31e10c13783685c9c1144c25190b004c61e5ca5f8f4bc9c4b2ab9d63460eaacc6e77a23e6f6d790088b9e55a75cec6f700d9dca98c05692c6669093348707686a492b479630b3c5a53f4265f371c7e615bc35750d7ccf890fd66cddd19c2b55bbdceab37abd29d443b439c75f0bb09f3fed886afd42ba9ed8fa022ab9437b1e88d3940c2d41f571b99cce944c5973295", "43", "61bdfe2d427ae618b880ca9d6c4ab9456b292d1eb98c5a91312e5d8194e342177ef7e628b6e59239a58aface2f8cb2ab9e64e989ee19bd11b1e142115869a186b5c39c411e4a08a46c12e6aa4b09b99e3a0dba0a061bba27eb72ff7f16dccf0d30b88f6e53040e76aee58ad27677dcb85023dcbc80cc39ac4b0db323dbeff2513acfd810eae5226333e9a5990a0f11451ba9aa5f376f1826f47f99bb119620b5b084d13c0e228503dc3815fb3a54a1b906d17d728b0654498c97b5ffeb185157f0c419b3812e6bb8d23bd7c26e1abfa25e5f5d78159f05df5498d2401131881d6596ace6e4dd0918ae1a8df1835fceaec4fcb07b65bed03e2de21b3f91c469d1acff3d2d25fdce8a64847ab13dac51e1f40a2c792af756dd392ffde7d71c38b7123617116880aa6d75776e10c9b892ea3ff59e6a0c906e600eb3475a7ba8146c4493510471bb9ab7072b515d9e0499bf99f601e237a0723d3314533e3e67f0108eb66c820ae565177dfcc41ae8dea76f18f08609bc1b42e4e08a26128c85802630f2e52fc7a5e4e25955ceb1a3075566373bd11f37b6bc80445cf2ad3ae7637b806cee54c602b49633348499a4383b4352495a3cb1859e2d29fa132f9b8e3f30ade1aba86be67c487eb366ee8ce15aaddee7559bd5e94ea21da1ce3af85d84f9ff6c4357ea15d4f6c7d01155ca1bd8f4469ca0616a0fab8dcce674a262cb994a80000000000000000", .Okay}, + {.Shl, "-6ab1744d1c5771c571f008824f072b6d8c1eeac1a5193254fbfc553c313763a59ab23fd51e1053b3d52e10bc65e66b400d189a2886fdc056abbaf7dbb6b081a80676c9ef1970b2b18845c641c021856f1df996d80265be8cb9d4846bc649d5a0e178fab49a1f5efcdffa3bd719098782931523d268287054305d6c990488ed20764b2a97b220bac4e92450a69a171a27861608b4e88c5ce85391704da1d9f6238614254baf32acff71bc68bdefe83e9dc73899d1088401b6185318d9a11cd9de28f55484990d9a85019d163032a98ca03a7ad5d6700c76fa0530248b246f2550cc9d54d873034b9da1308fde7d76d26dcd92e58b8def96fba1c772c3566f3378b009e3b423f33f35ff424941eea825f24a3dd1bbbf9f62484051c6ad0f2d1360a991008328f04c46fea83f46fa0e71fb96fb2dec6d49f801c8987920ca6d49bc3c9532d1c118c425e6c10deae2f2d18b08cbd21b52ceb8040af0328fde207c07f6796000d50a41ec76fcb30dc761727eb1d4d47cb7690091e1eb9534747c1e85d10b13af4fd3dcc8a558ed1b2940f31f9c78baaeaf16f6a3fc27c6b57e46def3d905e9f1171b9d50b978f71ece01d59b38399651dc4e12f72f428611b9c82ed9eed7a669057074a35bc475493e1fcaee4ab6b401baf1694cfa2da88f9efd62173f16faea0783e83cb16c7d408f0e495bb20d139c6632909dc5c9e1c80a9b06fa", "49", "-d562e89a38aee38ae3e011049e0e56db183dd5834a3264a9f7f8aa78626ec74b35647faa3c20a767aa5c2178cbccd6801a3134510dfb80ad5775efb76d6103500ced93de32e16563108b8c8380430ade3bf32db004cb7d1973a908d78c93ab41c2f1f569343ebdf9bff477ae32130f05262a47a4d050e0a860bad9320911da40ec96552f64417589d248a14d342e344f0c2c1169d118b9d0a722e09b43b3ec470c284a975e6559fee378d17bdfd07d3b8e7133a21108036c30a631b34239b3bc51eaa909321b350a033a2c606553194074f5abace018edf40a60491648de4aa1993aa9b0e606973b42611fbcfaeda4db9b25cb171bdf2df7438ee586acde66f16013c76847e67e6bfe849283dd504be4947ba3777f3ec49080a38d5a1e5a26c15322010651e0988dfd507e8df41ce3f72df65bd8da93f0039130f24194da9378792a65a38231884bcd821bd5c5e5a3161197a436a59d700815e0651fbc40f80fecf2c001aa1483d8edf9661b8ec2e4fd63a9a8f96ed20123c3d72a68e8f83d0ba216275e9fa7b9914ab1da365281e63f38f1755d5e2ded47f84f8d6afc8dbde7b20bd3e22e373aa172f1ee3d9c03ab3670732ca3b89c25ee5e850c2373905db3ddaf4cd20ae0e946b788ea927c3f95dc956d680375e2d299f45b511f3dfac42e7e2df5d40f07d07962d8fa811e1c92b7641a2738cc65213b8b93c39015360df4000000000000000000", .Okay}, + {.Shl, "-9ab822e2b1a93f73d8eab171e076bc0791a197f8ffce9f2ed0002c86082937007f79ca03239d845d4e6bab77cd970465450e66b072eddcead6c99040c93662836a141928eb7cad3b9df95cd16fcac461be45d3c8e8b3f68e39f7f66c18751f327eff19c92efd1636e52bca2245b7b384b6e16557796a96f1bb887f3bb6eafd80dc62e9090ca4fb1eecce82bfb1acc1ce56f4a7177383cfae9f4a505b4e1faad76bbd0b996ec91c74f9e815cf49d315dd8eb5177f97194b565ca92a24188b4f410eca9986800bbd6100f254f7b1de5be0f01392e25c366b1d14b518d9936efecb36d5115baca3165a15a7247d70124d84d1027dd566b52cb59ca134a2d6410d37c362c240768683c23b22107fcc4a26385ff30e584c54937898946ad340e973e7e0c4e2e8343e2e158236d84b1691c0b37699d25130bfff6dff1b4e73583925ff9f7ce8293691cd7f3f0a99ee31c12c3dabe0c2e17cbdc22c8d0a7c1a6558302a9071309e083e03f01dc8906250b634ec6697e9bfd2c21481ff8fd2439be480addf21741d44440239a8305ba5fd41ac87ecd64458b95ef04f288aac70a7be274a3c58d7faeefaf8ca7e5d68e9498da9fac8ca93964d68e6c05b984d2b7ae8a1c98b931a9c42967ac8e71d921adbb13cc91c088713981bad420e88c744dcdfa3b9bf4d242f408d666785961a203195ab1b6c0ee3a4c8030fede324409b8dd01e4e", "64", "-9ab822e2b1a93f73d8eab171e076bc0791a197f8ffce9f2ed0002c86082937007f79ca03239d845d4e6bab77cd970465450e66b072eddcead6c99040c93662836a141928eb7cad3b9df95cd16fcac461be45d3c8e8b3f68e39f7f66c18751f327eff19c92efd1636e52bca2245b7b384b6e16557796a96f1bb887f3bb6eafd80dc62e9090ca4fb1eecce82bfb1acc1ce56f4a7177383cfae9f4a505b4e1faad76bbd0b996ec91c74f9e815cf49d315dd8eb5177f97194b565ca92a24188b4f410eca9986800bbd6100f254f7b1de5be0f01392e25c366b1d14b518d9936efecb36d5115baca3165a15a7247d70124d84d1027dd566b52cb59ca134a2d6410d37c362c240768683c23b22107fcc4a26385ff30e584c54937898946ad340e973e7e0c4e2e8343e2e158236d84b1691c0b37699d25130bfff6dff1b4e73583925ff9f7ce8293691cd7f3f0a99ee31c12c3dabe0c2e17cbdc22c8d0a7c1a6558302a9071309e083e03f01dc8906250b634ec6697e9bfd2c21481ff8fd2439be480addf21741d44440239a8305ba5fd41ac87ecd64458b95ef04f288aac70a7be274a3c58d7faeefaf8ca7e5d68e9498da9fac8ca93964d68e6c05b984d2b7ae8a1c98b931a9c42967ac8e71d921adbb13cc91c088713981bad420e88c744dcdfa3b9bf4d242f408d666785961a203195ab1b6c0ee3a4c8030fede324409b8dd01e4e0000000000000000000000000", .Okay}, + {.Shl, "-ef7e1a1f265cbf77d4702e628cb42a0b1ff22b4317b11d64299b7b32eb00a7cd2732081c842a307ba4100980ae7c715ef040a72d675a3937544b8992da4d53dd8a48190cb8527f1c522cfbb9e86d2af57cc2316245d82e9cd5ab6deb8662477de2918412ffed2898fa7c0e23d6c68a9bf7b368889680ff1bcd04c3b89f2e848f9312141827ed3bc9a2956f2ed9ed0279edf88b77a3cc0489bcc4018c47284cc4c0fb792389537becb48b76aa9f0678f00c2fe710531da2d561649c344637c152998ba28a057afd0779f020d4a16f5b2407e19b044c05461ee32c018cfd29a769b79cfce130f08fa831c852e3ee998243a5a8da33ae3ad289223721e01fd77352e493f4e1163b5ff2e335cb4514035b3e4efff56b709fb346fd2c8fe4107e32b1590f794a68463147f0aafe187fc575afa796966063de5b128b1489818e475aa7b30f29195a333107da64a07cd383957d815607eecb268be3cb8df2a3c2a8f26bcf7f03a9893efd56cb9c477ad3df4db745bd4b2b63bc01fc409d332642f4ffb60a9cb0c9725cb3099465d4c74af5d806ccafdd9ca642428a9cb63396de20957e5fb4e52bcde3dfb24e9ec918b651a212bfeaff6c90fdd7e6fb72545b2335c228c2de3865a234677ebada7cde47cf39de748b46f9fb03e565d28600e99eb5e80abf1576f601713a40fd8518bd4a860956d5d8394ba450c5954a841e4f390cbfc1", "6", "-3bdf8687c9972fddf51c0b98a32d0a82c7fc8ad0c5ec47590a66deccbac029f349cc8207210a8c1ee90402602b9f1c57bc1029cb59d68e4dd512e264b69354f7629206432e149fc7148b3eee7a1b4abd5f308c5891760ba7356adb7ae19891df78a46104bffb4a263e9f0388f5b1a2a6fdecda2225a03fc6f34130ee27cba123e4c4850609fb4ef268a55bcbb67b409e7b7e22dde8f301226f31006311ca1331303ede48e254defb2d22ddaaa7c19e3c030bf9c414c768b55859270d118df054a662e8a2815ebf41de7c0835285bd6c901f866c113015187b8cb00633f4a69da6de73f384c3c23ea0c7214b8fba66090e96a368ceb8eb4a2488dc87807f5dcd4b924fd38458ed7fcb8cd72d14500d6cf93bffd5adc27ecd1bf4b23f9041f8cac5643de529a118c51fc2abf861ff15d6be9e5a59818f796c4a2c522606391d6a9ecc3ca46568ccc41f699281f34e0e55f605581fbb2c9a2f8f2e37ca8f0aa3c9af3dfc0ea624fbf55b2e711deb4f7d36dd16f52cad8ef007f10274cc990bd3fed82a72c325c972cc265197531d2bd7601b32bf767299090a2a72d8ce5b788255f97ed394af378f7ec93a7b2462d946884affabfdb243f75f9bedc9516c8cd708a30b78e19688d19dfaeb69f3791f3ce779d22d1be7ec0f95974a1803a67ad7a02afc55dbd805c4e903f61462f52a18255b5760e52e914316552a10793ce432ff040", .Okay}, + {.Shl, "-4b56f78d569fd473e0eab8960ff23841a963e6821c0e56a61ffab74584b34cc4f12360d2709b7de28edebfa8ffcde0bed1bed671890ac1ba634210aa6a6a6c17f31cd7dd95e7590def26108386ac5f67dd01014ffe84175f210b248bf3e5fc1cb2c1ab3a790e777b07a428914987af1e0ccee7cd801b6570e3228855041e0e31f1d5efbbb9093e15f2725bea75a2a1f840001ba97c4b4201678e13f381dc239ee026396163dca3f7bf17f618da5ebd5245696801122220dcafed35eb0d041a7bad3d0a726795a87ccdccd649bac9796ad856bbd767eea38f4eeb36b0452fc6c63e4d2d9c8cd015f32731cd2aa6e1e4bced734a0a4c66964c3ff545277dff96c7eac7967a56928ad2f6d190d83428eebabddd00e1453d02b6f4a53cdb1c2aa21062e417e63be5b1cdcffc2ce221df3fdc39549b276b390cee116d62c982bf2694eace4fc7e7a69b44ebed3f085770bcad918bf15fbd385cf47aace7adfba9edcc0410ea31a997e1f7355bf3dc396a3b00a180c9d106de07b868031ede1b26e1e924e3f79c2bd1f37e87a99b9eb4e5935761e4026674ab883aa250a478a9a5731b0e5e7b1300ff29055fa75398f8bea02214cb9734d523ae8ab363083781dee3b8b5a281a5c4ec0ae69ec710f8145196228a345882bf17e8baf7688328bb3e07fdeefc6459528f79b69e2bb3995739bdbd1ce11a5f45487c3c41ad92d5e90b0689", "71", "-96adef1aad3fa8e7c1d5712c1fe4708352c7cd04381cad4c3ff56e8b09669989e246c1a4e136fbc51dbd7f51ff9bc17da37dace312158374c6842154d4d4d82fe639afbb2bceb21bde4c21070d58becfba02029ffd082ebe42164917e7cbf83965835674f21ceef60f485122930f5e3c199dcf9b0036cae1c64510aa083c1c63e3abdf7772127c2be4e4b7d4eb4543f080003752f8968402cf1c27e703b8473dc04c72c2c7b947ef7e2fec31b4bd7aa48ad2d002244441b95fda6bd61a0834f75a7a14e4cf2b50f99b99ac937592f2d5b0ad77aecfdd471e9dd66d608a5f8d8c7c9a5b3919a02be64e639a554dc3c979dae6941498cd2c987fea8a4efbff2d8fd58f2cf4ad2515a5eda321b06851dd757bba01c28a7a056de94a79b638554420c5c82fcc77cb639b9ff859c443be7fb872a9364ed67219dc22dac593057e4d29d59c9f8fcf4d3689d7da7e10aee1795b2317e2bf7a70b9e8f559cf5bf753db980821d463532fc3ee6ab7e7b872d47601430193a20dbc0f70d0063dbc364dc3d249c7ef3857a3e6fd0f53373d69cb26aec3c804cce957107544a148f1534ae6361cbcf62601fe520abf4ea731f17d404429972e69aa475d1566c6106f03bdc7716b45034b89d815cd3d8e21f028a32c451468b1057e2fd175eed10651767c0ffbddf8c8b2a51ef36d3c576732ae737b7a39c234be8a90f878835b25abd2160d120000000000000000000000000000", .Okay}, + {.Shl, "a549f5083fbd9b4e95a10ab7ee373fef1e0c074ababd86187d78abfe0085705d4a4659b87d8bce5e47ce4cbcb3876453ebe8cffe6e8e733b17e2472b6bbb8bf91eed48dff67ecab26b7faafbc743736bd932d7bee2ce8f7d7bde4a8295b655760edfcd228bb87077bbd99aef963abaf6c2de6c5f31c883b3c291d0417e9720e6c95001a389f09e6cffa7d03369f9253dc7b8152e2e6907b3bf5c39ce24d44dd1ca56b3316dc3e78286875d088b58e9eddf60925c1196204b806164d487cb6d24d77fe1a12601c10aca3352fdb2c0380f337dfba1ebf7446e26c00b024e7ecedb51c4c48df3ac21ecfdde8fe086cd9bfb7660cedac2d7abe6ad1c67feead50d99e7de1aea0cad772d3aa1342a91ba4ab2381df09d9934b3df08cf18c493bd23ee768c0c58e071a045df77f821d5fc52bfcf0677d419f7b13f091daa833ee3378f8277c834d5fc164874578f6e28c630c1a196ee4427aaa51e1104cfee790e384fbaeada18fab53be4b69821bb24dcde89aba46b9faad5c720704601a2d30eee816f6f754f35f80900e8c71805f9f9ced95fbdcd80764f91f1ddf7a17881d776923a5b41020d06b98d71861bc30acbcac0659459573f9672d8b9f108620851f5da3ad9db806d664e0cb984204431b20bb8c9f7cbde1b70e9f0ecefb67710c952c68673a3f518d495e93dd436485c95bb51d4679423d702bd6ed72bce468e0aabf4", "21", "14a93ea107f7b369d2b42156fdc6e7fde3c180e95757b0c30faf157fc010ae0ba948cb370fb179cbc8f9c9979670ec8a7d7d19ffcdd1ce6762fc48e56d77717f23dda91bfecfd9564d6ff55f78e86e6d7b265af7dc59d1efaf7bc95052b6caaec1dbf9a451770e0ef77b335df2c7575ed85bcd8be639107678523a082fd2e41cd92a0034713e13cd9ff4fa066d3f24a7b8f702a5c5cd20f677eb8739c49a89ba394ad6662db87cf050d0eba1116b1d3dbbec124b8232c409700c2c9a90f96da49aeffc3424c0382159466a5fb6580701e66fbf743d7ee88dc4d8016049cfd9db6a389891be75843d9fbbd1fc10d9b37f6ecc19db585af57cd5a38cffdd5aa1b33cfbc35d4195aee5a7542685523749564703be13b326967be119e3189277a47dced1818b1c0e3408bbeeff043abf8a57f9e0cefa833ef627e123b55067dc66f1f04ef9069abf82c90e8af1edc518c6183432ddc884f554a3c22099fdcf21c709f75d5b431f56a77c96d30437649b9bd135748d73f55ab8e40e08c0345a61ddd02dedeea9e6bf01201d18e300bf3f39db2bf7b9b00ec9f23e3bbef42f103aeed2474b682041a0d731ae30c378615979580cb28b2ae7f2ce5b173e210c410a3ebb475b3b700dacc9c19730840886364177193ef97bc36e1d3e1d9df6cee2192a58d0ce747ea31a92bd27ba86c90b92b76a3a8cf2847ae057addae579c8d1c1557e800000000", .Okay}, + {.Shl, "-1cf41a7e8dbae094d1646512a15e6de08d20f8664f8552d94257889aa3c3b5b19bbdf588a38eeb1b3b2d375392960a1e17ecb0629537e8211224eaaef7a87e7aaea2f336c619b93736b405b7929faf80eec86cd3ffd48a1d588329d34405e40b4769f50d683e2b39d2d48b8c3bdbbb9d3ad41657707808c9aae47b2223c092302469a81b0a71cdb08c7e6b447dfed576a0018ccbfb2576d7cdcba7a71dbb4e10c9e700922ec3288acbc8a07419377d68d08f9441ab7f53384d38ef971198e1762a82f6e44941773f593d1ad841e38334b4ea1d2525800fbec2848edaa8d8e894d64e3f0ce87421976d9ca72ffdc7ae72866c3f7e6b32444fb6057f11bbe88fbae2bf11e915a55abd31f541d3b5fad7219349ef15c0defa6d196b456f21a06ad8a5d3ff81a12d0f51e544142853a5708a3ae1d99d8b2bf0de4ae61654a812321cf74bb5c86f594037d06319cc3d0393b278bc2e273fb52c2b04d05344659731b364f3bf8b0433507ba2d65f82816cd6f229484fb5cefd563acf11931108ebac3e93929d87ab5d493b8f7d6236b9e3ffa34407c89793f094829964d361b425b5289dc98525564261385dbc23344e60fd0c43317b147cd45a35d243d9d9324d20ad51c30ae298ecf69cd06df80f59b3859d0e667912bdb8f9897cf850dca2528b6e6033e044d56327fe8abb15c77ff0bfcd5f61934a3dbd630f601db5fa32cf9908", "2", "-73d069fa36eb82534591944a8579b7823483e1993e154b65095e226a8f0ed6c66ef7d6228e3bac6cecb4dd4e4a5828785fb2c18a54dfa0844893aabbdea1f9eaba8bccdb1866e4dcdad016de4a7ebe03bb21b34fff522875620ca74d1017902d1da7d435a0f8ace74b522e30ef6eee74eb50595dc1e02326ab91ec888f0248c091a6a06c29c736c231f9ad11f7fb55da8006332fec95db5f372e9e9c76ed3843279c0248bb0ca22b2f2281d064ddf5a3423e5106adfd4ce134e3be5c466385d8aa0bdb912505dcfd64f46b61078e0cd2d3a8749496003efb0a123b6aa363a2535938fc33a1d0865db6729cbff71eb9ca19b0fdf9acc9113ed815fc46efa23eeb8afc47a456956af4c7d5074ed7eb5c864d27bc57037be9b465ad15bc8681ab62974ffe0684b43d47951050a14e95c228eb8766762cafc3792b985952a048c873dd2ed721bd6500df418c6730f40e4ec9e2f0b89cfed4b0ac13414d11965cc6cd93cefe2c10cd41ee8b597e0a05b35bc8a5213ed73bf558eb3c464c4423aeb0fa4e4a761ead7524ee3df588dae78ffe8d101f225e4fc2520a65934d86d096d4a277261495590984e176f08cd13983f4310cc5ec51f35168d7490f6764c93482b5470c2b8a63b3da7341b7e03d66ce16743999e44af6e3e625f3e14372894a2db980cf8113558c9ffa2aec571dffc2ff357d864d28f6f58c3d8076d7e8cb3e6420", .Okay}, + {.Shl, "ed9fe1bb815a9555c41e6e742e543353f83647c6ce8d623190086f52a9a24e112a612c8f569061cfe1c7bcc1609016ce89be4106a3049e27e15fd917dd56da924cba0ab367bf81a7826c77ef55c969d32170e78fe1e119ac53df1292d166232d10b9867ef7fdc2a92132cf98398ad326c00ae5c746dd1e887f7a255b68d194ed1620aa1a01ff0da6a22cd85161a2c77f909b467205db462bd74f7d3b5c962474be942d071f517731764b1395beed44260b191a0b99eb899b84f830f96777c46ac896add695a2043fcaef6230994b44347461a822bb06f4f1ca1e0a4ab511de77eab7f540c7223d89d59fe29dd1acc57da5258e17fa761acb5d893374a8991be6a62476fcfc2e0cf0de885c8ebbdec18e0cd96be4353623d03386befb57c993c50abf9e18a47d6c80d8b321c96113fe0f4289d85c703a9ed9c7e562c3d2e8dde9e338ef688d61483e5f4bb728557245fd23911b8f94b4ffba86c5243f2bc59ffc2f5b115e6114b6118f7546a81b66434712ce7d1204e1b152da9d0307427d51996600b88a9f1a7f7663d70dfb1a32cb1c9fbe29c86c27dcec8ca89216dfb4db2158a1831cb4ca0225da7219c9eaf5837ae14b6fe06213f885592007a7a841073adc8712b8b1d6353f9781635ac0279fb3a3c8d7c9fd4cf95b8c1e4690df243df4f74796ac55a5ee082fb82e0a62aeba847ebe83398164dda58f95e6ac9b91bd0c", "4e", "3b67f86ee056a55571079b9d0b950cd4fe0d91f1b3a3588c64021bd4aa6893844a984b23d5a41873f871ef30582405b3a26f9041a8c12789f857f645f755b6a4932e82acd9efe069e09b1dfbd5725a74c85c39e3f878466b14f7c4a4b45988cb442e619fbdff70aa484cb3e60e62b4c9b002b971d1b747a21fde8956da34653b45882a86807fc369a88b36145868b1dfe426d19c8176d18af5d3df4ed725891d2fa50b41c7d45dcc5d92c4e56fbb510982c64682e67ae266e13e0c3e59ddf11ab225ab75a568810ff2bbd88c2652d10d1d186a08aec1bd3c72878292ad44779dfaadfd5031c88f627567f8a7746b315f69496385fe9d86b2d7624cdd2a2646f9a9891dbf3f0b833c37a21723aef7b06383365af90d4d88f40ce1afbed5f264f142afe786291f5b20362cc8725844ff83d0a276171c0ea7b671f958b0f4ba377a78ce3bda2358520f97d2edca155c917f48e446e3e52d3feea1b1490fcaf167ff0bd6c45798452d8463dd51aa06d990d1c4b39f4481386c54b6a740c1d09f546659802e22a7c69fdd98f5c37ec68cb2c727ef8a721b09f73b232a2485b7ed36c8562860c72d328089769c86727abd60deb852dbf81884fe21564801e9ea1041ceb721c4ae2c758d4fe5e058d6b009e7ece8f235f27f533e56e30791a437c90f7d3dd1e5ab15697b820bee0b8298abaea11fafa0ce6059376963e579ab26e46f4300000000000000000000", .Okay}, + {.Shl, "-294796a0b0b3b96a36ed798bc6baf24c4b6f4532cc026bc098a9265fa395d7a3b44d6a7588f3808282eeaf9e710a37fb4e52648bacd821dee37d8745345725daad31e4d8b7ca346756cc94670be70e348a27c5ee5fda3aac3fc9873111f9a0381f30297bf1487232a91e529b693ab78d7ba632206fd64b517b9bae4d8a8d0256f8e647b2ca70bd27b98036b888f24b427d50d9feb9705ef532f4b502bc037a9924ca441e840c444fb334346f4ec33d36937bb21a41c2f52749a6a56e5d1f7cd0ca23df6597db20b75a776f0884d5962b26b867edc36cf7c3a112b7bb4f5ae783becc20fe330c3215c5020166add7895fc45283ff370d201144339713e5d71442c18837bb12647224fc2a76c72ec0aa86b653909eaa0431fa52ca309a386721419a9c5b9e7d031d816de5ab8fd4f9aa04ede3bed2e2772e9c3f6d0c8861b7e3221376990b7ff5f16639683c781e7f4fbf61baa9e54ade0b831e60c8c58b128e45e5c984e19081540ef1ea7bdbb9c7fbb5faaa5fa7b04a210f5d2014230a1070a62f4c3a3af94d82c70173eafaab235c86fdc285c0aa95cdbb003182c7108ca47a10cac1f6b946bb6f35b1a48908963fe5ee1779d1d529a9a059a34837c28b858b1877ca6c3e223cbb7303085437fd6ece9e80440e498199426d85f5c05a90f0bd72eb3f6696a8a9755b0ad17e0805f1777e55fb90e8816092720f6097c0e43a85", "64", "-294796a0b0b3b96a36ed798bc6baf24c4b6f4532cc026bc098a9265fa395d7a3b44d6a7588f3808282eeaf9e710a37fb4e52648bacd821dee37d8745345725daad31e4d8b7ca346756cc94670be70e348a27c5ee5fda3aac3fc9873111f9a0381f30297bf1487232a91e529b693ab78d7ba632206fd64b517b9bae4d8a8d0256f8e647b2ca70bd27b98036b888f24b427d50d9feb9705ef532f4b502bc037a9924ca441e840c444fb334346f4ec33d36937bb21a41c2f52749a6a56e5d1f7cd0ca23df6597db20b75a776f0884d5962b26b867edc36cf7c3a112b7bb4f5ae783becc20fe330c3215c5020166add7895fc45283ff370d201144339713e5d71442c18837bb12647224fc2a76c72ec0aa86b653909eaa0431fa52ca309a386721419a9c5b9e7d031d816de5ab8fd4f9aa04ede3bed2e2772e9c3f6d0c8861b7e3221376990b7ff5f16639683c781e7f4fbf61baa9e54ade0b831e60c8c58b128e45e5c984e19081540ef1ea7bdbb9c7fbb5faaa5fa7b04a210f5d2014230a1070a62f4c3a3af94d82c70173eafaab235c86fdc285c0aa95cdbb003182c7108ca47a10cac1f6b946bb6f35b1a48908963fe5ee1779d1d529a9a059a34837c28b858b1877ca6c3e223cbb7303085437fd6ece9e80440e498199426d85f5c05a90f0bd72eb3f6696a8a9755b0ad17e0805f1777e55fb90e8816092720f6097c0e43a850000000000000000000000000", .Okay}, + {.Shl, "-ead482ad6a04bddac7ce4747d1c7b77e1d76320324b6b5fd506a792e0fd1cedc7175bf25bfd3c421c3a3eb475214cd968da01f78a2bb4416f7bfe148b12e0589bf94c7be03c658b9b80ad6c433bbc82b8b38a7574ee17d4da4bb4aa2fe8935b96144a1b7cce1b79cbeb35998cd01ccc455621a5498fbac762f200bbdf35028be613c896763529d50ae8bb99d369e038b9618ed617f7fa5f001f3f6cfa5f361a26f61b797b76d597a28729340b926efd3e905c4cc45cea6f0ae30fbce1a41086354236867632775c4af622b9a870603eeab9d860df4766cdd10ddbe25a17d3056bf1ddd62b06b6ed649607fe5e9318b76b2c7c087067f265cf32d006c24612e6270570f5bb991f757c9c2ebf5a7d0de4d2a06d5516d912b26a066acbaad614697d2d81ee3d70d0eb1ff41b04a6372c184983403add7f610061612d40a1bfa7bb18bea436079e6e55b21e0e43d7fcf2a748a27b6ac0184ea7d69449ccb9c3e4bacc86462b38ccd3c357ddfe92fa0650f81576257ec2616394867c850e8ccc6c1aed2c9f528694e9991a6bb30d672d6dfb1ea85aad8e0e15bd3377f8364460689bf79e5167f594186de80adc7f9c0042f38c7264c002f67656d803253a86211181604cbf83cbbe0041f027217503d29995386e89ace8ce530daae8165ca791dcd43e968f8412e10e9ef4c22a116dbfa883055d235ae01a8fae53cc3f7e844b1aadd", "e", "-3ab520ab5a812f76b1f391d1f471eddf875d8c80c92dad7f541a9e4b83f473b71c5d6fc96ff4f10870e8fad1d4853365a36807de28aed105bdeff8522c4b81626fe531ef80f1962e6e02b5b10ceef20ae2ce29d5d3b85f53692ed2a8bfa24d6e5851286df3386de72facd6663340733115588695263eeb1d8bc802ef7cd40a2f984f2259d8d4a7542ba2ee674da780e2e5863b585fdfe97c007cfdb3e97cd8689bd86de5eddb565e8a1ca4d02e49bbf4fa4171331173a9bc2b8c3ef386904218d508da19d8c9dd712bd88ae6a1c180fbaae761837d1d9b3744376f89685f4c15afc77758ac1adbb592581ff97a4c62ddacb1f021c19fc9973ccb401b09184b989c15c3d6ee647dd5f270bafd69f437934a81b5545b644ac9a819ab2eab5851a5f4b607b8f5c343ac7fd06c1298dcb061260d00eb75fd84018584b50286fe9eec62fa90d81e79b956c878390f5ff3ca9d2289edab00613a9f5a512732e70f92eb321918ace3334f0d5f77fa4be81943e055d895fb09858e5219f2143a3331b06bb4b27d4a1a53a66469aecc359cb5b7ec7aa16ab6383856f4cddfe0d91181a26fde79459fd65061b7a02b71fe70010bce31c993000bd9d95b600c94ea188446058132fe0f2ef80107c09c85d40f4a6654e1ba26b3a3394c36aba059729e477350fa5a3e104b843a7bd308a845b6fea20c15748d6b806a3eb94f30fdfa112c6ab74000", .Okay}, + {.Shl, "-5277c1fd2bdc0dd1db26af832e827cee3e198cedb3d8c712c282e4f9c246eabc8d99aa7fb463a01fd2128514118b78393cc8fbadeb9602f98393c9680e0b86624bffdbfe29d29c50133950c3abaeae704486986e4f0137c1eeaa94e23a866ba305a6568b027ffbfd228918a478958b7193d633ea5f2fdadca8e220aa5a561076f1b2d8540068d34c5a7918899e8e5a4b249c3a14e1f89d35c3643a0cebb6d8134161478296a1b92cd73f7ff1767b915f60bc91b6bb1fc9a2a422e75230c4245d3520c4ea7988d501aa0e93028c82a8cc3b677c93bc8fc7aa0c091e8d9e7a060027c0b578adacf85ef24d67c55e4b1025d5fbdcd0215521ff69678342c4e43e03c43f007a761d21c73a370a067f39f9eacd04a5ddeb8014d439026dad86c9ff051272ae258e79ce50e63d1f88eb293c1ccd26eccb56c84c0c51a10468d2b72399410476c48d633cf3dae0ff3a8b4ccdb36c75668a5c275f424a5deb583925bbc7270b0e27b36278368e4d965ad4eaf4f9a81c513ac58de6f7e3b5e01702501b9181a3a5483a4a3ae645f5a66c9b8cac8987b2680fe191504fd3a2aca4b7e0915955ee1a1e08bf27d2acaae9ef0b567c34cbff51be4447a7f9733e0f78b448436bf381b45f77cc832292c93c891b0a250c1eac586a24a45978b5fcab6e56ddef2bc3caf97112c40ca2f7aa6216f591d9ed7993be0853b51582445a104841940d0a", "70", "-5277c1fd2bdc0dd1db26af832e827cee3e198cedb3d8c712c282e4f9c246eabc8d99aa7fb463a01fd2128514118b78393cc8fbadeb9602f98393c9680e0b86624bffdbfe29d29c50133950c3abaeae704486986e4f0137c1eeaa94e23a866ba305a6568b027ffbfd228918a478958b7193d633ea5f2fdadca8e220aa5a561076f1b2d8540068d34c5a7918899e8e5a4b249c3a14e1f89d35c3643a0cebb6d8134161478296a1b92cd73f7ff1767b915f60bc91b6bb1fc9a2a422e75230c4245d3520c4ea7988d501aa0e93028c82a8cc3b677c93bc8fc7aa0c091e8d9e7a060027c0b578adacf85ef24d67c55e4b1025d5fbdcd0215521ff69678342c4e43e03c43f007a761d21c73a370a067f39f9eacd04a5ddeb8014d439026dad86c9ff051272ae258e79ce50e63d1f88eb293c1ccd26eccb56c84c0c51a10468d2b72399410476c48d633cf3dae0ff3a8b4ccdb36c75668a5c275f424a5deb583925bbc7270b0e27b36278368e4d965ad4eaf4f9a81c513ac58de6f7e3b5e01702501b9181a3a5483a4a3ae645f5a66c9b8cac8987b2680fe191504fd3a2aca4b7e0915955ee1a1e08bf27d2acaae9ef0b567c34cbff51be4447a7f9733e0f78b448436bf381b45f77cc832292c93c891b0a250c1eac586a24a45978b5fcab6e56ddef2bc3caf97112c40ca2f7aa6216f591d9ed7993be0853b51582445a104841940d0a0000000000000000000000000000", .Okay}, + {.Shl, "-e594fed61754c0e3fc4daa797547ae81f4997044bfc2679d3fed0f90ae38faeeecf1ea4bacf9fe61b62694d01aa619fd370857c7e3bf09a37d698945423a1015ea66442c01239fe707668184611fff055c69e9388c348f90476ba24f26a8af8dac8230b494f1e676612c54a9d31993c3e715d368472c35124a267fc34f45431c1d5b396277cb7099a4fe7e4434a2a8ca32a60270c7ff7748ce7a129f851107ce2333ee4481d7dd92253ed60a5ced25828308451f79b7c6defc5d04dd6fb840adb2c68f1b7b06b219277b2c6a473547ec62262d569143d9b360a92df9771c92512154361f5f590c43a84cbdeb4a6f580b94030ee6086ef5ea8ac4b00e937f4844e434b3ac7bf5f4f80592553e8b671c287e4d4f070df4db5d049371c66eaa84cca2ff0a3052945ae18eb6ad119c1be70ccab048429d051e2f696c00ae25b6598f22c14b6b19aeb8021fe405fda5f77b81493438f42ec64fb64145e40ac40e6587c062ad2abd02e8c2d8d66dc127d5c52119565cf3f26af93c9de6ceb196f2fc5a67dbdf50441e1c8c45b64c0ace1d8e57ce81308d8708332161a2f6bf9ca89d820f527b58cfbc6c93719b1e16ea922df20333225cd508f3b602033cc45cbb0e51b0be5c795b7fd53b56f930f183d45db5c0b0a95860b3a7ba5f336c6c431173c6bdc5f87b09e821dfec5cc2c86ab76340e9dcbd9167db1ac773f9a1fb0b36b409", "72", "-39653fb585d53038ff136a9e5d51eba07d265c112ff099e74ffb43e42b8e3ebbbb3c7a92eb3e7f986d89a53406a9867f4dc215f1f8efc268df5a6251508e84057a99910b0048e7f9c1d9a0611847ffc1571a7a4e230d23e411dae893c9aa2be36b208c2d253c799d984b152a74c664f0f9c574da11cb0d4492899ff0d3d150c70756ce589df2dc26693f9f910d28aa328ca9809c31ffddd2339e84a7e14441f388ccfb912075f764894fb582973b4960a0c21147de6df1b7bf1741375bee102b6cb1a3c6dec1ac8649decb1a91cd51fb18898b55a450f66cd82a4b7e5dc7249448550d87d7d64310ea132f7ad29bd602e500c3b9821bbd7aa2b12c03a4dfd211390d2ceb1efd7d3e0164954fa2d9c70a1f9353c1c37d36d74124dc719baaa13328bfc28c14a516b863adab446706f9c332ac1210a741478bda5b002b896d9663c8b052dac66bae0087f9017f697ddee0524d0e3d0bb193ed90517902b1039961f018ab4aaf40ba30b6359b7049f571484655973cfc9abe4f2779b3ac65bcbf1699f6f7d411078723116d9302b3876395f3a04c2361c20cc85868bdafe72a276083d49ed633ef1b24dc66c785baa48b7c80ccc89735423ced8080cf31172ec3946c2f971e56dff54ed5be4c3c60f5176d702c2a56182ce9ee97ccdb1b10c45cf1af717e1ec27a0877fb1730b21aadd8d03a772f6459f6c6b1dcfe687ec2cdad0240000000000000000000000000000", .Okay}, + {.Shl, "afc34d8703ecb7b8ae3523c947b1b315b847ebedb847fba4fa253d5f6e650ee32522f85fc6467f6a197664b772b6568bb0995d1df1e28df99f0d871b82ed64091e6b4abc93f3cc80b84e9f5bf864513be10e6da3d7a04fce19d4ecaf24caa1dccbc5d7c4f85ac1c85c3cc5eb8990ecd4bd55da3a86ae9a9c6f21e01555a53d6f43d374efd309ec10b47a737c042a6ec970b8f092ca66cd3db9c8f1c453fbefe260a5fac646a6e3776ca9cecd2ecb2cbc58fbd659998a06b592b05859e55a7a663ddf4f48fe2a9d684a7656859479ed4162b1d7e6bbfc35af7dd3f321371487cfe4c29102398f2d92daebefae00c811656b2511cd09f79343bd4d92612bd0bacd33aa13004adeff6b5382c805708f68b053183df5ff16ffe4f9a7791bb614335684e0c8308a3bc2f9358c5cabd5abe9bed108de3d48ec033765b480a24ca3c4e895c2c06b09d97cc0f84c243edd3ea351ddc4dc3e20706210a671fff35ae729cce3ad85d395e3d67c3021681b5bec705292fae6a9d7bf724f08843746e9bf7e81fd7cde6ad9ac0d98f93007b5b293aaf8f0c4053865e99a4e3928f60cd87197d1d50a134c1590a18fa6f85ec7da4995c88fff9fb9d8ff470b1908fefc9f4faf7569b27fa68b123d01cc16568f6859e3c41cae2f4059865cf3ebfde1cc7a9f822b0f1125d4e0d4aa62d71d48c09d13756370e0ee253e43a08b1ea9b62920aea57d", "12", "2bf0d361c0fb2dee2b8d48f251ec6cc56e11fafb6e11fee93e894f57db9943b8c948be17f1919fda865d992ddcad95a2ec2657477c78a37e67c361c6e0bb5902479ad2af24fcf3202e13a7d6fe19144ef8439b68f5e813f386753b2bc932a87732f175f13e16b072170f317ae2643b352f55768ea1aba6a71bc8780555694f5bd0f4dd3bf4c27b042d1e9cdf010a9bb25c2e3c24b299b34f6e723c7114fefbf898297eb191a9b8dddb2a73b34bb2cb2f163ef596666281ad64ac161679569e998f77d3d23f8aa75a129d95a1651e7b5058ac75f9aeff0d6bdf74fcc84dc521f3f930a4408e63cb64b6bafbeb803204595ac94473427de4d0ef5364984af42eb34cea84c012b7bfdad4e0b2015c23da2c14c60f7d7fc5bff93e69de46ed850cd5a138320c228ef0be4d63172af56afa6fb442378f523b00cdd96d20289328f13a2570b01ac2765f303e13090fb74fa8d47771370f881c1884299c7ffcd6b9ca7338eb6174e578f59f0c085a06d6fb1c14a4beb9aa75efdc93c2210dd1ba6fdfa07f5f379ab66b03663e4c01ed6ca4eabe3c31014e197a66938e4a3d83361c65f4754284d305642863e9be17b1f692657223ffe7ee763fd1c2c6423fbf27d3ebdd5a6c9fe9a2c48f40730595a3da1678f1072b8bd01661973cfaff78731ea7e08ac3c4497538352a98b5c752302744dd58dc383b894f90e822c7aa6d8a482ba95f40000", .Okay}, + {.Shl, "483550e98940e603dc2704b7241517258bb69aee23ff17f9868bd7049fb3d4d58af47dda3d5090d968c3c246360abeaec07bdfc2b0dbbcfd89572bc58489470b648ec0666f6a61579efb155a4201c476f6f2bc3588a528e4e46b510ab9cc089245ec9b1dd6cf5f3e329887147bd3023a51a312300d580e1d867d3e183e65a7b1092445a980e7ce4b7eb21daa7d32a4a002a69873a520792653605cd35c7c6dc309f394bfdde09223ffd91511b7e95e16cca914fb78f5e72af3c172d6c7a48629f93335f72d9850bd0ccd4512903d79eb7f0bc2fa331807fa3ed28fda3ba27e096e1e0e7d1e70e57723476db1e0f76ddea14c0e7fd4c9e8b61f15dfb0ee35367f79ddb3c421bc5aac678762d172fb3ef7e2199cb8731054043bb995db8bf8673a8c50542f895cff9724e11ac05c62981e54b9679b857b7f6022b22cc41a0013a902dcd151416c38fc916711396c35fef10b8b2f75f0b551b35cdcba44e0c3eda2f28a426785471cadd0c056cd9073bcf8d5f124728311a742dc75b4911b93bfbe345d31f48ac64504df26f24af02efcf3551f58dd8fdaec2b0be76b11c639556ae515919ab86ec7cdcc891e1fef6cfc1abfe232df63786767eba0eb4b33e901ba40759bb1598eb28969f49433749050510015f99a01c37ad61adc19ef4e8b2d9c3ff600454266f21137f60b1ac37f8f46604e55b896c5697b32291858521c238c", "55", "906aa1d31281cc07b84e096e482a2e4b176d35dc47fe2ff30d17ae093f67a9ab15e8fbb47aa121b2d187848c6c157d5d80f7bf8561b779fb12ae578b09128e16c91d80ccded4c2af3df62ab4840388edede5786b114a51c9c8d6a215739811248bd9363bad9ebe7c65310e28f7a60474a34624601ab01c3b0cfa7c307ccb4f6212488b5301cf9c96fd643b54fa654940054d30e74a40f24ca6c0b9a6b8f8db8613e7297fbbc12447ffb22a236fd2bc2d995229f6f1ebce55e782e5ad8f490c53f2666bee5b30a17a199a8a25207af3d6fe1785f466300ff47da51fb47744fc12dc3c1cfa3ce1caee468edb63c1eedbbd42981cffa993d16c3e2bbf61dc6a6cfef3bb67884378b558cf0ec5a2e5f67defc4333970e620a80877732bb717f0ce7518a0a85f12b9ff2e49c23580b8c5303ca972cf370af6fec0456459883400275205b9a2a282d871f922ce2272d86bfde217165eebe16aa366b9b97489c187db45e51484cf0a8e395ba180ad9b20e779f1abe248e506234e85b8eb692237277f7c68ba63e9158c8a09be4de495e05df9e6aa3eb1bb1fb5d85617ced6238c72aad5ca2b233570dd8f9b99123c3fded9f8357fc465bec6f0cecfd741d69667d2037480eb3762b31d6512d3e92866e920a0a2002bf3340386f5ac35b833de9d165b387fec008a84cde4226fec163586ff1e8cc09cab712d8ad2f6645230b0a4384718000000000000000000000", .Okay}, + {.Shl, "ad3a680767c80af0ca99624cf3c719c26ef1eb430d009bbe2f54048c3166551f680eca2388446df2f87067d92e99483a3dd3e77dae1752fc414dd259f6bf0d0449bf3914db95ac637dca466db82d2f134a91aa636abdb50872d364983cdbfa689a8a7791317017d6e42cf868d324dc6bb34796432e80f7ff1bb4f78fef3e4f592b55a32746b546df87065a7f2f435ea55854139fbf4dfc4b90a90aa460dddb1e1f18dfb6b96150abb515b96a538b4601d014a4fbee421127427bf61943e63648c9c3e62b4da4ee23aec896005485ee0c9675db82b22de88f405c366b7a74dd3c49c2f8c3e07a96ad2f043eb1c094492b42aafc29d9063e1df20f2419222683ed8ac73307776dc8692258d5738ac5ace231c4490effdfb199c13eed5c1fd779873a8ae20de5fcda17bfb15b17c40a638f6e2b68f4b66851e2577aa25e4eb2bd8a3a39c2ecc10dd5d3f70fdd6c5f075d9492c78051df4ecddfe2feb49c5037fbc10c2bdb57ae8d3d865625576003beb5b54aa303971e31b80c7dcd72bb58e5df88719ec339607ca5da28944fb5fd9c19a83141b4568c79bcda13ce0b45e0c913bf7b67eaffe41c20b86a28218ab9fa885e2357d2d8e4eb4080528d3dac5f86b39dde25cfc35cf065a8e8242e6bb2b1c0a69cd3061988870416d6773789e23228596a190dc9f4be0151d9d6b0351a32d4025e3167d74f923363b4139e75dbe9a59b", "60", "ad3a680767c80af0ca99624cf3c719c26ef1eb430d009bbe2f54048c3166551f680eca2388446df2f87067d92e99483a3dd3e77dae1752fc414dd259f6bf0d0449bf3914db95ac637dca466db82d2f134a91aa636abdb50872d364983cdbfa689a8a7791317017d6e42cf868d324dc6bb34796432e80f7ff1bb4f78fef3e4f592b55a32746b546df87065a7f2f435ea55854139fbf4dfc4b90a90aa460dddb1e1f18dfb6b96150abb515b96a538b4601d014a4fbee421127427bf61943e63648c9c3e62b4da4ee23aec896005485ee0c9675db82b22de88f405c366b7a74dd3c49c2f8c3e07a96ad2f043eb1c094492b42aafc29d9063e1df20f2419222683ed8ac73307776dc8692258d5738ac5ace231c4490effdfb199c13eed5c1fd779873a8ae20de5fcda17bfb15b17c40a638f6e2b68f4b66851e2577aa25e4eb2bd8a3a39c2ecc10dd5d3f70fdd6c5f075d9492c78051df4ecddfe2feb49c5037fbc10c2bdb57ae8d3d865625576003beb5b54aa303971e31b80c7dcd72bb58e5df88719ec339607ca5da28944fb5fd9c19a83141b4568c79bcda13ce0b45e0c913bf7b67eaffe41c20b86a28218ab9fa885e2357d2d8e4eb4080528d3dac5f86b39dde25cfc35cf065a8e8242e6bb2b1c0a69cd3061988870416d6773789e23228596a190dc9f4be0151d9d6b0351a32d4025e3167d74f923363b4139e75dbe9a59b000000000000000000000000", .Okay}, + {.Shl, "742d08a8bbff013313d95fa2d65d627aa8ae95c3b7e4c8524bcad9e7e206a27b38a1582e8d14aecc4fa5406b268e29c40a5142a9d3f481b3334fab4e8301f9218966f0a9fb32013a04894b694346d6ef70437d9b3350ea459db4301a54f3bccc116d99bed610a1ce7eb17da3f126ebf4ce158be6b3da4a85b77d1106287b27a49977cfaba5685b84229812c6b830d11015b24b5f924401845683794e6d07517b029baf80536cc2733c045d73c282214f3bb5907f3135932af1b14cc4d6861b0ad961b1cb2d5ba900756dc950aa9a36c777293b4e5a0cfd6a676923ca26bb106ba24daa09255ddbf98cbf4a409caf00c1cd34c9598fbf5fd46bbe853dadb3eef9b4d3a7b4244985cf8509675f520a67f1853d8bc81c8ea6d8f39893cccfa5ec2782b4466a13ff35bc2d77f30d1fbbea44aa0936384ff5c0aa0d4d10462ad5fb53a9d1e8a1e8f5ab63e8879766272193f09db2f2c52efad3aed192e0e683df5b3b3338033f38e8ed2eb6647f4fdc2872206b9ee788d7294b03227b33a4216f6d2a1b647cd3b7991feb068cf0172eaeabe6218815dfd3eab4169ac7d01d0237345ae6134766c91d2d09048780e263428176d58a7ec4eb79158f484e84530799d951bc5f424bae23bce7090f525a0a719c03015c5850164ace618cbd99ca08bb1e0dedd8f304579fe163bd2254fb778cd3bfa245fa5d13323f476569d7daad115f08", "3c", "742d08a8bbff013313d95fa2d65d627aa8ae95c3b7e4c8524bcad9e7e206a27b38a1582e8d14aecc4fa5406b268e29c40a5142a9d3f481b3334fab4e8301f9218966f0a9fb32013a04894b694346d6ef70437d9b3350ea459db4301a54f3bccc116d99bed610a1ce7eb17da3f126ebf4ce158be6b3da4a85b77d1106287b27a49977cfaba5685b84229812c6b830d11015b24b5f924401845683794e6d07517b029baf80536cc2733c045d73c282214f3bb5907f3135932af1b14cc4d6861b0ad961b1cb2d5ba900756dc950aa9a36c777293b4e5a0cfd6a676923ca26bb106ba24daa09255ddbf98cbf4a409caf00c1cd34c9598fbf5fd46bbe853dadb3eef9b4d3a7b4244985cf8509675f520a67f1853d8bc81c8ea6d8f39893cccfa5ec2782b4466a13ff35bc2d77f30d1fbbea44aa0936384ff5c0aa0d4d10462ad5fb53a9d1e8a1e8f5ab63e8879766272193f09db2f2c52efad3aed192e0e683df5b3b3338033f38e8ed2eb6647f4fdc2872206b9ee788d7294b03227b33a4216f6d2a1b647cd3b7991feb068cf0172eaeabe6218815dfd3eab4169ac7d01d0237345ae6134766c91d2d09048780e263428176d58a7ec4eb79158f484e84530799d951bc5f424bae23bce7090f525a0a719c03015c5850164ace618cbd99ca08bb1e0dedd8f304579fe163bd2254fb778cd3bfa245fa5d13323f476569d7daad115f08000000000000000", .Okay}, + {.Shl, "-153585e16978a36f1b4231b5d57e8f3cd1d92bdc13e90088a9c767e1fd7187e8a823dcf2ac33e5ebee72a6534962fdc4d168b181befa7d943d94fce9f2a46250a2384afe8dc38e17884b71f7138d7743432bb280580aa0887b24ad4ddc6cc4401c50ce3a3b9fb251f0f2f86fbda3866f85fec413b3863815b02db0839732613176c5aadf57c267405c4ee073dc6def55ccdc4bb026bf860f9479c9f0929acd686073a40fd8393de1f595ea28c03ee35c474e133d0a8a4431ca8e3dd6fdfcbd5040d1cef0b54ba9576a57c93813c15b6817a3afbb9d97f7c5493a4f4b5d0c6865bd6df15ffda341838bc42540b3ef184387639f5adde02e5fe594b1d820a88765a0f13de5cc05a383922712c53314059d7a9fd900c1412d7c1fcec09da3216c5ffadad34cdaca127c3bca8cc4e75a62c0fb2cf344e5832385af8041c3b489c58abceaf5661a18236c59024f9e8ea1fc3a96dd46562a781883ac3518516b5669f5c3ad69cbbc1d441330a85ac8a9609e4f1f81a3a78ba6830a5809524d7ed5ff0436b20cdc79825eb8b413cebc48a3fde39e67d80d1d273622472ad3b31920f0da829d12ca9cf09eb471a12f3d102b39124c89c1bed0c2150d8b99095b4af92be6f448992c31df6f43e192ea12934ed3eea833e8877c3d1418db8a3f8e7e7a402a25a9d2e6fca60413ad013d394ffbcb52d9849a5415cfa7e0eaa398a58424adfc", "10", "-153585e16978a36f1b4231b5d57e8f3cd1d92bdc13e90088a9c767e1fd7187e8a823dcf2ac33e5ebee72a6534962fdc4d168b181befa7d943d94fce9f2a46250a2384afe8dc38e17884b71f7138d7743432bb280580aa0887b24ad4ddc6cc4401c50ce3a3b9fb251f0f2f86fbda3866f85fec413b3863815b02db0839732613176c5aadf57c267405c4ee073dc6def55ccdc4bb026bf860f9479c9f0929acd686073a40fd8393de1f595ea28c03ee35c474e133d0a8a4431ca8e3dd6fdfcbd5040d1cef0b54ba9576a57c93813c15b6817a3afbb9d97f7c5493a4f4b5d0c6865bd6df15ffda341838bc42540b3ef184387639f5adde02e5fe594b1d820a88765a0f13de5cc05a383922712c53314059d7a9fd900c1412d7c1fcec09da3216c5ffadad34cdaca127c3bca8cc4e75a62c0fb2cf344e5832385af8041c3b489c58abceaf5661a18236c59024f9e8ea1fc3a96dd46562a781883ac3518516b5669f5c3ad69cbbc1d441330a85ac8a9609e4f1f81a3a78ba6830a5809524d7ed5ff0436b20cdc79825eb8b413cebc48a3fde39e67d80d1d273622472ad3b31920f0da829d12ca9cf09eb471a12f3d102b39124c89c1bed0c2150d8b99095b4af92be6f448992c31df6f43e192ea12934ed3eea833e8877c3d1418db8a3f8e7e7a402a25a9d2e6fca60413ad013d394ffbcb52d9849a5415cfa7e0eaa398a58424adfc0000", .Okay}, + {.Shl, "-423a524916f6025cd170f0dcfc3b2f72b167bae80f029d0f9406942be3589c31ba16e2cf1f82c0bfb4d1a319a723f4027103661b0061b20f653f871c1cc671e9ecc93b3f9ee62e69949cdce7852f2772939300acdab6540e159c18665b5b462f252c2de1b28e9a45bdf2afb4c0e55231bb136e5fdd2e3cef9d5b470e58cd3e89c0737742a1762cac12fe0197b56225d763c9324a9e6fd2d9aac5820e99b378f81909bc71ef3f7b7936b9097b6bb291fc24a4df41d2914d406af6e822c9ea2f332cdf9aa4f6ab93ea41b32a27cc8e8589298165f98f6306184568fadb9639103621b93a4d39c584c1d73c1b482e3819212dac1b5c48d10c0c34b8e37d810d096335e7eb2af1ef652b6c7106574b6fd034374a7adc463b3247a17acffa6f5f6d94198c977e1a29841b38bf4cdf4acbd9b7170f38333739c78907eed79f332daac1d43ddb369b3ccbcd63af69a37b27269db5293f7cb8f827978bc3fc9d288dddf4cf90e70b06c9dd06e2c06201576887f0c34b9a9161b0e2474c4d98c6b999f9168c7725fbf4e21cdd09d83356dae2a33d12dc960b543f77ef555e53ca06968461e76e60c356bd13c63c8ec070263b2d1964ed8c65b87b7ee4140e95751c738216ea949b88fae3ab8d08625d4d6cbf429ce09b81acbf19e32d3689248b8b73f03b87ec88c862bc92a048c0312c2e813f892791688126e261ff0f9efb3b300ce3d1", "9", "-8474a4922dec04b9a2e1e1b9f8765ee562cf75d01e053a1f280d2857c6b13863742dc59e3f05817f69a346334e47e804e206cc3600c3641eca7f0e38398ce3d3d992767f3dcc5cd32939b9cf0a5e4ee527260159b56ca81c2b3830ccb6b68c5e4a585bc3651d348b7be55f6981caa4637626dcbfba5c79df3ab68e1cb19a7d1380e6ee8542ec595825fc032f6ac44baec79264953cdfa5b3558b041d3366f1f0321378e3de7ef6f26d7212f6d76523f84949be83a5229a80d5edd04593d45e6659bf3549ed5727d48366544f991d0b125302cbf31ec60c308ad1f5b72c72206c4372749a738b0983ae7836905c7032425b5836b891a218186971c6fb021a12c66bcfd655e3deca56d8e20cae96dfa0686e94f5b88c76648f42f59ff4debedb2833192efc34530836717e99be9597b36e2e1e70666e738f120fddaf3e665b5583a87bb66d3679979ac75ed346f64e4d3b6a527ef971f04f2f1787f93a511bbbe99f21ce160d93ba0dc580c402aed10fe186973522c361c48e989b318d7333f22d18ee4bf7e9c439ba13b066adb5c5467a25b92c16a87eefdeaabca7940d2d08c3cedcc186ad7a278c791d80e04c765a32c9db18cb70f6fdc8281d2aea38e7042dd5293711f5c7571a10c4ba9ad97e8539c13703597e33c65a6d12491716e7e0770fd91190c5792540918062585d027f124f22d1024dc4c3fe1f3df6766019c7a200", .Okay}, + {.Shl, "e9d034cb84f5546c2a9ab87d3ad6b284882ec7ad26f7842781fab033e9a11901fca192210ad772131f329762b1c6ae1b7bc0073bca72b89aa1973e4a0cdb6bed6a059a674c73523122b7f71090d888901170065402e0eb1f7ae841a80262f82cd1a3c103546d8693bdd9360b403bebaef2e9f36cbac779583d1036c09f79ffe4a9f44dbfecfec0d02ab564d244bcef201d5f761c68ee876cdd863de6777d9a9db7f699ec5ca923522aec8de034777e94067f49fd79b1003354871045958db3f3271b0b9199ea3c6a368346cc7e9a0219a608ffd0d0fd09dfd2c1829c5f041f4dfd895f9d700c987015550f1c4f82d5a4dfa6a8e9b98080006b20354c767e4ff1dbb838f28e0184ad9e73b47055f2550bb03b0084a4f5cd019feeda8fa2cd340370ad772b36f44672acbc495ed8ac6fbf174e0ffcb8f36cfaaa682c3b0249cb4866db88c1547bd4287094cbea448c4a36d493eede8e390ceacd59450140e2b922254c6bd6d40958df8bd6d4634b3c13ea51313f51e3931806931d3437d88573219c5e9b38b2e1f45429221a1f8245cb99e9052e3f78425b78a61372c076acbaed9f67ceceaa9e86e233c3d1b003702e6939184657dbec3a2956214c15af273af7d856a5a6f5bdc14861ebe18d82b76aa3dbeebd98787d71e413cf4ae2a15dfe5576f8a94cda36c697e7f786e0a3afa691b821b22ec91b62da1bdefb011e89a113", "5d", "1d3a0699709eaa8d8553570fa75ad6509105d8f5a4def084f03f56067d3423203f943244215aee4263e652ec5638d5c36f7800e7794e57135432e7c9419b6d7dad40b34ce98e6a462456fee2121b1112022e00ca805c1d63ef5d0835004c5f059a3478206a8db0d277bb26c168077d75de5d3e6d9758ef2b07a206d813ef3ffc953e89b7fd9fd81a0556ac9a48979de403abeec38d1dd0ed9bb0c7bcceefb353b6fed33d8b95246a455d91bc068eefd280cfe93faf3620066a90e208b2b1b67e64e36172333d478d46d068d98fd3404334c11ffa1a1fa13bfa5830538be083e9bfb12bf3ae01930e02aaa1e389f05ab49bf4d51d373010000d6406a98ecfc9fe3b77071e51c03095b3ce768e0abe4aa176076010949eb9a033fddb51f459a6806e15aee566de88ce5597892bdb158df7e2e9c1ff971e6d9f554d0587604939690cdb71182a8f7a850e12997d48918946da927ddbd1c7219d59ab28a0281c572444a98d7ada812b1bf17ada8c6967827d4a2627ea3c726300d263a686fb10ae64338bd367165c3e8a85244343f048b9733d20a5c7ef084b6f14c26e580ed5975db3ecf9d9d553d0dc46787a36006e05cd272308cafb7d87452ac42982b5e4e75efb0ad4b4deb7b8290c3d7c31b056ed547b7dd7b30f0fae3c8279e95c542bbfcaaedf15299b46d8d2fcfef0dc1475f4d237043645d9236c5b437bdf6023d13422600000000000000000000000", .Okay}, + {.Shl, "3e69da14a4991c4c319000c4b5ad6d2cd67969dbefba4b5b837ef446ec1333f85cd8b46473d9e667a49c9e0a346c10e6cb96386ca22704e4de8a470935f980df1314b95dc89d965b0f7ab6d0c93232fd047b98820ef54f88371c480e89adc5bfe56f992cd8ab8ee9422e7610d24972c1a318c429b39602f922777e868fd93ed63acd30ed3da96b8895a4754e916bd47434519d3127f7b5161c39450876d14bf7cfb60bdb5e2876a2ac3bd2aeb718c168b2fbeb303356085335f920c4df041ad95f0686172aa188cdeb559b1fc0a7cb5bb296b53577b4c52210666354448685664ef4d1d3b087657fe8b8efd3084aa8105e842e88c0171cbe28d0995a6747a9ccbb824b3a5d38f941844848de561542e8bd8fe5bc361d7ae64b814c8c8674e1e247538335f07de65033a239f7df7eac582e552cfd8587acbf9035949bb6341e0048799b8d5eb77e65c2b40a575da1fbfbfcf15b2459d673ce6d4d26d9fe6f8299778a4b5b1273da5c85276e948850cf5f1fe35c67f9aa22046864cf10821fe8b565bcd53214a3b95ce792e8fd39ce115123e833243b3df3f7c713862607e92f439e862b7c06ce57802bdd27400a9657ecd66c4b7522e85a7cbabc61e6f1b9ca9895e92c2b18d2da49adb7036101618c21a00cf81d1ef2fb4714fefb0101d5da606cf2e2992a4aa9a27367e9c4c6853fd6080fffc3566c0efe0e8aec0e4741ad11", "26", "f9a7685292647130c6400312d6b5b4b359e5a76fbee92d6e0dfbd11bb04ccfe17362d191cf67999e92727828d1b0439b2e58e1b2889c13937a291c24d7e6037c4c52e5772276596c3deadb4324c8cbf411ee62083bd53e20dc71203a26b716ff95be64b362ae3ba508b9d8434925cb068c6310a6ce580be489ddfa1a3f64fb58eb34c3b4f6a5ae225691d53a45af51d0d14674c49fded45870e51421db452fdf3ed82f6d78a1da8ab0ef4abadc6305a2cbefacc0cd58214cd7e483137c106b657c1a185caa862337ad566c7f029f2d6eca5ad4d5ded3148841998d51121a15993bd3474ec21d95ffa2e3bf4c212aa0417a10ba23005c72f8a34265699d1ea732ee092ce974e3e5061121237958550ba2f63f96f0d875eb992e05323219d387891d4e0cd7c1f79940ce88e7df7dfab160b954b3f6161eb2fe40d6526ed8d0780121e66e357addf9970ad0295d7687efeff3c56c916759cf39b5349b67f9be0a65de292d6c49cf6972149dba5221433d7c7f8d719fe6a88811a1933c42087fa2d596f354c8528ee5739e4ba3f4e73845448fa0cc90ecf7cfdf1c4e18981fa4bd0e7a18adf01b395e00af749d002a595fb359b12dd48ba169f2eaf1879bc6e72a6257a4b0ac634b6926b6dc0d84058630868033e0747bcbed1c53fbec0407576981b3cb8a64a92aa689cd9fa7131a14ff58203fff0d59b03bf83a2bb0391d06b444000000000", .Okay}, + {.Shl, "-d7d8bb2b5d0a584d97e2a3d3368e0fb670bb8cff5b58ce70319ff559eecef9bdfaff7903774df4c124e274809ed317fda85d9f968e528ba980da32fea959093d4b859e89e1121924b33234bfc9fc0d482147e62aab7eaa1d361c1831d0221cad2a101c81679d716cb3da2d70dee32f5fecda35f6feb0eebc2286df31cc9f414f4aafcf60aa6eac48db9a9e980fb7c2b1b821e7dc31ab132cdc4fe2f30ae922ffa50b1b3674bd0a5db4753151a40408412fdcb93c7428d3f6a86e79605cbe6d4e727688e70805acd0c4ff89f07ac1797c77740cd440308b37ac593045331ac7defb8702bcc8d6dc9e61078ddec02405790f578fac2d40478072020904761f32d3705ef871b4298ef394e988c254d1eb4da305969a957ce0c6af60e8f2434a899a22ac634bbbaefbc87458207aa19e8111af79eb79ca41f730450df5d397068bec59f85bd490b93edc9f4a23a5bc41888164f7f09da83ace72545c375b1a4ac352945686b2b4284cf7688d5f3a6e878a4a210c5a9f2e46e6c53a132b9300cd01c9cc50d894ba9ccb3c77454da3eb08d5196732919508c61c5913ae0278664bd1dbc8afe139ecebd06dfcdd19d5334fef2391e3374a27fac5c041afa55b2a6c1779e8da58ce7402f2a67b18ac5d578c925960ea07786d9765d6932dde7bbda89c93a3f0e2bed6e4a3eedb5e826309bafdb6e4490971c2b570dcf6a5125ef5a213b4", "1", "-1afb17656ba14b09b2fc547a66d1c1f6ce17719feb6b19ce0633feab3dd9df37bf5fef206ee9be98249c4e9013da62ffb50bb3f2d1ca5175301b465fd52b2127a970b3d13c22432496664697f93f81a90428fcc5556fd543a6c383063a044395a54203902cf3ae2d967b45ae1bdc65ebfd9b46bedfd61dd78450dbe63993e829e955f9ec154dd5891b7353d301f6f85637043cfb863562659b89fc5e615d245ff4a16366ce97a14bb68ea62a3480810825fb97278e851a7ed50dcf2c0b97cda9ce4ed11ce100b59a189ff13e0f582f2f8eee819a88061166f58b2608a66358fbdf70e057991adb93cc20f1bbd80480af21eaf1f585a808f00e4041208ec3e65a6e0bdf0e368531de729d31184a9a3d69b460b2d352af9c18d5ec1d1e4869513344558c697775df790e8b040f5433d02235ef3d6f39483ee608a1beba72e0d17d8b3f0b7a921727db93e94474b78831102c9efe13b50759ce4a8b86eb6349586a528ad0d65685099eed11abe74dd0f14944218b53e5c8dcd8a74265726019a039398a1b12975399678ee8a9b47d611aa32ce65232a118c38b2275c04f0cc97a3b7915fc273d9d7a0dbf9ba33aa669fde4723c66e944ff58b80835f4ab654d82ef3d1b4b19ce805e54cf63158baaf1924b2c1d40ef0db2ecbad265bbcf77b51392747e1c57dadc947ddb6bd04c61375fb6dc89212e3856ae1b9ed4a24bdeb442768", .Okay}, + {.Shl, "212440fdc4dec86998c4bb1ee31a75a16396e5d7131982169f68d86613378b366b608960a6cd7c5424ad8871ad1d305ab040ea9a655e6a6f4ec934d795605b95e72478352c101e472dc482af822ef751da90439a4115e28b4b15b92db82c50f2694ff5ad9cba2f8ed16f17ea690da8336c8519a2228a5fa921bfe2eb47cdad1bd7d4d71126145ba77f38569cdccfd5a2050dc8f3de6257eb5dd2867443c76bc2e7b1a7f07d5df6b3cd9a219842de5377af0fe21a30c0869412f66902a9fc8a292b80e1bf46333a5783f49f74d00feff375089f10cc748ca58125793ab13d841b02febf15a93c06c6ca06903e5a8552157f9c72a8cd30021735d072f3d8d36771ac150df9dcc0beb59d37acfd0cea74212a5cc506735cbc40d207d65b7434e39b91ffee10c0185ea74e4025b300b46ecb9dfbc3c6bfd9e7e8180563f7b7d21e7a90a940c74bc17758d74c41726ab33bf57d12e85983ebff75835f81007480f0832c5af4802b2fe8338bc869fcd44abd6fa584cf1453da9bdfca4c14a23875e642fc3d98c91d27afe1c10f6eb52014997974ded0e86ba5d97a2ea454f675656a9a45fd8315940104730aaa607bd39b4fc0ec8367ffe11262aab9674b534f1a965fc9477ab8f2d3556db836b354edf6fa3dbb41823cf4695c5c1f55e768bb0bb0860b0caf90c58162644f08a8e96827aa243916c32caf7bd9046a8265fee8cbd6ae", "d", "424881fb89bd90d33189763dc634eb42c72dcbae2633042d3ed1b0cc266f166cd6c112c14d9af8a8495b10e35a3a60b56081d534cabcd4de9d9269af2ac0b72bce48f06a58203c8e5b89055f045deea3b5208734822bc516962b725b7058a1e4d29feb5b39745f1da2de2fd4d21b5066d90a33444514bf52437fc5d68f9b5a37afa9ae224c28b74efe70ad39b99fab440a1b91e7bcc4afd6bba50ce8878ed785cf634fe0fabbed679b34433085bca6ef5e1fc43461810d2825ecd20553f914525701c37e8c6674af07e93ee9a01fdfe6ea113e2198e9194b024af275627b083605fd7e2b52780d8d940d207cb50aa42aff38e5519a60042e6ba0e5e7b1a6cee3582a1bf3b9817d6b3a6f59fa19d4e84254b98a0ce6b97881a40facb6e869c73723ffdc218030bd4e9c804b660168dd973bf7878d7fb3cfd0300ac7ef6fa43cf52152818e9782eeb1ae9882e4d56677eafa25d0b307d7feeb06bf0200e901e10658b5e900565fd0671790d3f9a8957adf4b099e28a7b537bf9498294470ebcc85f87b31923a4f5fc3821edd6a402932f2e9bda1d0d74bb2f45d48a9eceacad5348bfb062b280208e61554c0f7a7369f81d906cfffc224c55572ce96a69e352cbf928ef571e5a6aadb706d66a9dbedf47b76830479e8d2b8b83eabced17617610c16195f218b02c4c89e1151d2d04f5448722d86595ef7b208d504cbfdd197ad5c000", .Okay}, + {.Shl, "7e04f0aca1b7d4c3ebfbec472b4d3d1108e4e77cab3a7473fcfb3dd83370ccd83fd87a766a98180678574960f5e2fc73831c4c296d57261c7e6855b01fdf036146013c4cad90bf3fdc6fd644c220ffcfa0806ef9b88a6d745c68c49adbf88f4d6fbe332af53376c329185909970d87676d0b292544d93a7d88854175bbf4776ea3e21b88f666f68beb9cd8a6354da1d838cf012f64ec221bff4de149c02b63de4dd9afe7ab5a350cc503e62f04b85753beb330180b011d1bb491132b9ed805e93a7bd734bbf0813a7b64dc1faefe8e5c27514cdb5ef954b4234e746b1c48a38478cb8ba19f2c9f21e37fae046c417ed7244dc83aab637511790edc47d290cf2bf0aba1c6629bf7804562997851f98b15c52d81a418ac7c5f718bef66867995a1e8287593c7682a10c9c09eb5fff1547d6c1b85ecf3637b69058e010618005423046d3e8538cbe2cab459e07fec4bd7113188f87f40bdb0888a5071ca54582757b69ea4ac02ad61ccb7981735f5e8ccbd9872b6f7c3f7168cde05be1f14b0ffd657293aea19243d551c3bef10809a547346a4f1632f66d43095bcbc1ac6138cfd45abf6f0e3e5d11bdad92ff06c5d0e525b5f8d791ddce693e57065741e8ccfb06f6839daa57c8f71a4962fc6c9ee8ab2ae1d6c64434f7b304890e5458bb24796837c835b3a71adf258ce8422e0f0e156e64fddbe78064546d6d9b47fadfdbc19", "59", "fc09e159436fa987d7f7d88e569a7a2211c9cef95674e8e7f9f67bb066e199b07fb0f4ecd530300cf0ae92c1ebc5f8e706389852daae4c38fcd0ab603fbe06c28c0278995b217e7fb8dfac898441ff9f4100ddf37114dae8b8d18935b7f11e9adf7c6655ea66ed865230b2132e1b0eceda16524a89b274fb110a82eb77e8eedd47c43711eccded17d739b14c6a9b43b0719e025ec9d84437fe9bc2938056c7bc9bb35fcf56b46a198a07cc5e0970aea77d66603016023a37692226573db00bd274f7ae6977e10274f6c9b83f5dfd1cb84ea299b6bdf2a968469ce8d638914708f19717433e593e43c6ff5c08d882fdae489b907556c6ea22f21db88fa5219e57e157438cc537ef008ac532f0a3f3162b8a5b03483158f8bee317decd0cf32b43d050eb278ed0542193813d6bffe2a8fad8370bd9e6c6f6d20b1c020c3000a84608da7d0a7197c59568b3c0ffd897ae226311f0fe817b611114a0e394a8b04eaf6d3d4958055ac3996f302e6bebd1997b30e56def87ee2d19bc0b7c3e2961ffacae5275d432487aaa3877de210134a8e68d49e2c65ecda8612b7978358c2719fa8b57ede1c7cba237b5b25fe0d8ba1ca4b6bf1af23bb9cd27cae0cae83d199f60ded073b54af91ee3492c5f8d93dd15655c3ad8c8869ef6609121ca8b17648f2d06f906b674e35be4b19d0845c1e1c2adcc9fbb7cf00c8a8dadb368ff5bfb78320000000000000000000000", .Okay}, + {.Shl, "4bbea4acd92dc3312769cfff24cd52d783c292fbe9248f846d95461634c9f7536f1e6c78162fd93e9ef8a569edef0a705d978d4868c48be2c04ac13b10226a58457a52f0406789db5878bcc283394b64a40aa063ea7e6239d639e6d116973233f31ca678f18819a5a1f19a2270a9e7e8161c8421cf6c72ac159e21498d669b67fc61197314294d90037c5ff392f7ac4aee770053c8d480d6dc984b80896f0d1d55bdd60aa264ecafba166676ffc716ca13359f00f0ffd256eb66ea0868e0bdfedf483012fc45bc9f2c425ed75b6c76fb448c1c4a202e82eb3394464a4c88bc6dee0ab7227a6362fd2e7e6ac29c5d76842ec08097476485306c7b4c99666c85ef91ecb5d99959309c55539910af5955d38418adf982b0a8536ba75f9c60a0c2172597a95d87871298f52d99f376ddcc78d484980a0d5c1b7e3fd9f3e4c45781b985cbc0c97eca8648fed85cfa81f0fa50d3ea2a2e021efa72b377adedec2008dde1e4b9fa7e03b804ad7193ba408a15ed083fd2e34972974f92a0dfd2687172e480ffaad2cd17b936440b9cd4f40216ae70fe0b2422e81f5d148094f57a7513c118a05b17855186e61be57896f25b334986700c9d72a5eb29a7e1607275dee389b9754a7d86f410057bc7063e2b9161a685e7245f3411add7f88992f34fedc6f2be914fc68e665a7dbfd4cbd059de47d23a5962f55f156a984dd03c4277b497c4", "2b", "25df52566c96e19893b4e7ff9266a96bc1e1497df49247c236caa30b1a64fba9b78f363c0b17ec9f4f7c52b4f6f785382ecbc6a4346245f16025609d8811352c22bd29782033c4edac3c5e61419ca5b252055031f53f311ceb1cf3688b4b9919f98e533c78c40cd2d0f8cd113854f3f40b0e4210e7b639560acf10a4c6b34db3fe308cb98a14a6c801be2ff9c97bd625773b8029e46a406b6e4c25c044b7868eaadeeb0551327657dd0b333b7fe38b65099acf80787fe92b75b3750434705eff6fa418097e22de4f96212f6badb63b7da2460e251017417599ca232526445e36f7055b913d31b17e973f35614e2ebb421760404ba3b24298363da64cb33642f7c8f65aecccac984e2aa9cc8857acaae9c20c56fcc1585429b5d3afce3050610b92cbd4aec3c3894c7a96ccf9bb6ee63c6a424c0506ae0dbf1fecf9f2622bc0dcc2e5e064bf6543247f6c2e7d40f87d2869f51517010f7d3959bbd6f6f610046ef0f25cfd3f01dc0256b8c9dd20450af6841fe971a4b94ba7c9506fe93438b972407fd569668bdc9b2205ce6a7a010b57387f059211740fae8a404a7abd3a89e08c502d8bc2a8c3730df2bc4b792d99a4c338064eb952f594d3f0b0393aef71c4dcbaa53ec37a0802bde3831f15c8b0d342f3922f9a08d6ebfc44c979a7f6e3795f48a7e347332d3edfea65e82cef23e91d2cb17aaf8ab54c26e81e213bda4be200000000000", .Okay}, + {.Shl, "fe2da2e29fe5eea81b33dd67879af1ebf2775e9498097c74bf4590760fd78ff509253c23f79795f1340e3f53a3b8f25cd763b3b2a3033245b2016d81a65f4c56e0f8fc55b6b3801e16d8f5da65caf7d36045ed89d47408963b5f38c52414c2f2dcd4640354a9041bcf3d816063f3433ff51f87e2e6c1e672553f4d65760f0ccfdee84270f61f7f7b1f8f034a7208633fb0578f4c31f17c832070f58532c5b053901096c8332c47119991cd6c32d576c64f527c2a2db2d6269cabaa5087b11c37a4100825a23329d534fb5ae2b931d7cf65e6d10b43488081aadb510a687a2eaab5a71523bec963e868b28d9245168915d7589e971abefa114d28e5b1e8148885ef118ff01b3e89bd3b79d6b1fad9626157eeff6cdafafc15d5bbb6ffd75a6d7cfd36d5ab8d0a4b8060b47a1751034e5dd4f923f101ed25fac40c8a86406c31c389c5c5c49fdbb38f43af8d6bf7e295c22282905fac195c9889d096909f6ee4438497462192380b623659b07c93b0ddd6bc439c01234369735474502e004221674fddb460d55d096b304a304937f074abbfacf2f38eb263beae4f1e9c5cfdb33b9a720ae4d575f2f836115264cdf42538cab8b7b868bc6263cd7450cf935054aea19760a2df2d7dabadf773c28cdb93031aeec4da5881881159796a49bc724e3bd6385a448cdaa7b7a329d4d6372e91100408819dcffdd2869d99c95ad599fe3e", "10", "fe2da2e29fe5eea81b33dd67879af1ebf2775e9498097c74bf4590760fd78ff509253c23f79795f1340e3f53a3b8f25cd763b3b2a3033245b2016d81a65f4c56e0f8fc55b6b3801e16d8f5da65caf7d36045ed89d47408963b5f38c52414c2f2dcd4640354a9041bcf3d816063f3433ff51f87e2e6c1e672553f4d65760f0ccfdee84270f61f7f7b1f8f034a7208633fb0578f4c31f17c832070f58532c5b053901096c8332c47119991cd6c32d576c64f527c2a2db2d6269cabaa5087b11c37a4100825a23329d534fb5ae2b931d7cf65e6d10b43488081aadb510a687a2eaab5a71523bec963e868b28d9245168915d7589e971abefa114d28e5b1e8148885ef118ff01b3e89bd3b79d6b1fad9626157eeff6cdafafc15d5bbb6ffd75a6d7cfd36d5ab8d0a4b8060b47a1751034e5dd4f923f101ed25fac40c8a86406c31c389c5c5c49fdbb38f43af8d6bf7e295c22282905fac195c9889d096909f6ee4438497462192380b623659b07c93b0ddd6bc439c01234369735474502e004221674fddb460d55d096b304a304937f074abbfacf2f38eb263beae4f1e9c5cfdb33b9a720ae4d575f2f836115264cdf42538cab8b7b868bc6263cd7450cf935054aea19760a2df2d7dabadf773c28cdb93031aeec4da5881881159796a49bc724e3bd6385a448cdaa7b7a329d4d6372e91100408819dcffdd2869d99c95ad599fe3e0000", .Okay}, + {.Shl, "-fb48135d4ef73ab62be01e94dfc52530c312587cd66c1fc23e76479fb6e251e1fe664add32edbb2aad6a079acbe8328a042d61bac1934ff6ecf9195d88fd732cbfe3c0ec4048191a1ee46a8ddc3fcfc7d8b37b2a7c0eecd880b94b3d71d409ee512e9b773ec09e561d0dc4c2088c4c2d12d8bed2a78509db93fc080aa133c3ebf099cab2a4e5abcdfe0dfb9e21c730d3123fc9c12fef398c043bdda3cf1890752706ba8e6fc67fc288b5aee33b30bb5d7b906859cd607d85c7940fcf85f6a0737c476f739b5089e98f1854e4d5050f1544b93946f9669b93cdbcac1baabdd8134511cdbd51d72103f02d079e04ea1e0fe348d95e609cee9f407e3ba35e287ff891aeaddbdd358043bc9ed856af17eba5a07987106c960dfa079911c1e5d70b952a83fe52b8a3ffd7239ade42a276eb59fe5bbfb94df9c0156c6aec56a5f5d8718b8f20baeb765d464775c6429cd5baeb0eca47d6aa77b7fa5ae52524d1a67eefe50713edd6d98978d7f8fc07b92077c695656943bf2eeca911ec57fb9fd9a30f1982c3e0eb5a1aa93b2f1430a39907adbc05d729b22a85e8cb3b7e029c4aea88d0b5bc2d850306780a077eb404c23ac9236eef02da0e561a6a10cc38e52df09d2c6eb219e469c2bfed00b4b0636e5e36e9bdb67208e4109900fc79fc6e8b356a6ddc5552fbb56ccdb643780b80a45136e583cb975537fab3d0e06f6c9b9101ff", "36", "-3ed204d753bdcead8af807a537f1494c30c4961f359b07f08f9d91e7edb894787f9992b74cbb6ecaab5a81e6b2fa0ca2810b586eb064d3fdbb3e4657623f5ccb2ff8f03b1012064687b91aa3770ff3f1f62cdeca9f03bb36202e52cf5c75027b944ba6ddcfb02795874371308223130b44b62fb4a9e14276e4ff0202a84cf0fafc2672aca9396af37f837ee78871cc34c48ff2704bfbce63010ef768f3c6241d49c1aea39bf19ff0a22d6bb8cecc2ed75ee41a1673581f6171e503f3e17da81cdf11dbdce6d4227a63c61539354143c5512e4e51be59a6e4f36f2b06eaaf7604d144736f5475c840fc0b41e7813a8783f8d2365798273ba7d01f8ee8d78a1ffe246bab76f74d6010ef27b615abc5fae9681e61c41b25837e81e644707975c2e54aa0ff94ae28fff5c8e6b790a89dbad67f96efee537e70055b1abb15a97d761c62e3c82ebadd975191dd7190a7356ebac3b291f5aa9dedfe96b9494934699fbbf941c4fb75b6625e35fe3f01ee481df1a5595a50efcbbb2a447b15fee7f668c3c660b0f83ad686aa4ecbc50c28e641eb6f0175ca6c8aa17a32cedf80a712baa2342d6f0b6140c19e0281dfad01308eb248dbbbc0b68395869a84330e394b7c274b1bac86791a70affb402d2c18db978dba6f6d9c82390426403f1e7f1ba2cd5a9b771554beed5b336d90de02e029144db960f2e5d54dfeacf4381bdb26e4407fc0000000000000", .Okay}, + {.Shl, "-df800f4eacb04b99c69f7bac0c35122b656220f4acf3f14f7f367deb0ad7ece05169a0785b352136b7f1c13be38c2f5ff0c4fe7b0537f912ad40a21e76832dbd323acd7e5dbd31dcb1b6d359b74883455e278b66653ad4147c302510b176f09f46b05e9e747e6818aacb14d8838b4d142ee8d7f02c8a2b503c01dca1317a69f8a4b7a6d7c851b0018d4dbee40232b64e99e6e02ec9fc3526983cc8464a699078ce225936eba9c038b74b3732f83ef6f97daf7624d68fd333d7387b155436f86382494f068cd110f2e7330055bd23b6901a860e62cbe8cae8be7cb85f8a7a4e4c1b23b3c7c0a519a1cfcb9755cbfac6501cab65779222a9b36abd15854f537b8e8b2ed3b72354a6837f6b3d18aa653fb3275c4bf0d2a4be4ad89c6f752c733ad68ccd0941a7686d0cd664d6f457a666ec75567ba009533bdb250d7460854de7ae0a1e92d0f458cfe17c8fce6064e2a4aa05653389c089997bc6cc5513285ebb7a1436afca9b7b541d5d439a8c6d6e5996d5f4470940b22bff224e57408c8bd372e22c25812778bafc01b3fa9acd535296b9ff2db544e46e6efc4d8188bac3eaab558920ab164ee8829aa952bf66952c2368e7daa342ddd80c1d65ec117cfd0b4f38b31e0ccef75e61d3a8c46538e2fcd76f2d26116b5c4b6ed05abe1ec7a9af5e1814d38d6de8f531bed5eaff7b180ae04eb515833e95b60644718c9aa2e42fd8", "5a", "-37e003d3ab2c12e671a7deeb030d448ad958883d2b3cfc53dfcd9f7ac2b5fb38145a681e16cd484dadfc704ef8e30bd7fc313f9ec14dfe44ab5028879da0cb6f4c8eb35f976f4c772c6db4d66dd220d15789e2d9994eb5051f0c09442c5dbc27d1ac17a79d1f9a062ab2c53620e2d3450bba35fc0b228ad40f0077284c5e9a7e292de9b5f2146c0063536fb9008cad93a679b80bb27f0d49a60f3211929a641e3388964dbaea700e2dd2cdccbe0fbdbe5f6bdd8935a3f4ccf5ce1ec5550dbe18e09253c1a334443cb9ccc0156f48eda406a18398b2fa32ba2f9f2e17e29e939306c8ecf1f029466873f2e5d572feb194072ad95de488aa6cdaaf456153d4dee3a2cbb4edc8d529a0dfdacf462a994fecc9d712fc34a92f92b6271bdd4b1cceb5a333425069da1b43359935bd15e999bb1d559ee80254cef6c9435d18215379eb8287a4b43d1633f85f23f3981938a92a81594ce27022665ef1b31544ca17aede850dabf2a6ded5075750e6a31b5b9665b57d11c2502c8affc89395d02322f4dcb88b096049de2ebf006cfea6b354d4a5ae7fcb6d51391b9bbf1360622eb0faaad562482ac593ba20a6aa54afd9a54b08da39f6a8d0b7760307597b045f3f42d3ce2cc78333bdd79874ea31194e38bf35dbcb49845ad712dbb416af87b1ea6bd7860534e35b7a3d4c6fb57abfdec602b813ad4560cfa56d81911c6326a8b90bf600000000000000000000000", .Okay}, + {.Shl, "6d0a3ffd2279b586bdafe08db16ababd36d747ed273287035ec85dd2c4fe549a76fba6ed0aebb5730a26f8c614bbce1614002a7493f14056bee6ef64d9c3723de04c4908ccea2ccb532097f9de81e0214b7167f7d78f0d9b8d9e05a58f49644d2c619d2634721a965b6664197ff6b423b6f71e1aeddc7f15cf8a200fc9c244ee56b4daee5bb0d1834c394b1deee9bfa5f998c34458642a797f2ba1b5b53216ea05959f948ea97dc3c84dfdba978dfc2002ebe3de868bff60f090388a2d338a47693490ec43963cab1fc3ade54f7b9f10635add61d0cdfc23d860b6e1dc2c3a68b2f4113c6ccd94de8dc5ee0d22d3ec125ea7fe06d2f6d6785fe7069a4efd6b9e82434bb08d46d496d23ae617ba4057e5c4842e2fe92fbce0723c736651a54015bb7fecb191c98baf16773e7daa9a91e16d357bcac0428bc06197adc7436bea1a396a0943700c44ac87c1028e65618083f6c5a596f29f88908ae1edc354ad346da5e579e67eca0c663003ef63ec8e983066845d2e0600277ca0c7fc18a98fc84b12c3331a163f113901ca53f521d59316ea6d7ae34de032fa6f561691924121a87b2b5bd74f3e46768dedcddccb1a884111376bc84e5a33f00e32655348e9aaff60a0157751eab33c7f3091d818a2015983b5c75926ed1c028286582dab6b04d7619ab64128d2f6abe73719de14fdb59469989b96e69e28f55085e9d6cb2b35ff", "9", "da147ffa44f36b0d7b5fc11b62d5757a6dae8fda4e650e06bd90bba589fca934edf74dda15d76ae6144df18c29779c2c280054e927e280ad7dcddec9b386e47bc098921199d45996a6412ff3bd03c04296e2cfefaf1e1b371b3c0b4b1e92c89a58c33a4c68e4352cb6ccc832ffed68476dee3c35dbb8fe2b9f14401f938489dcad69b5dcb761a3069872963bddd37f4bf3318688b0c854f2fe57436b6a642dd40b2b3f291d52fb87909bfb752f1bf84005d7c7bd0d17fec1e12071145a67148ed26921d8872c79563f875bca9ef73e20c6b5bac3a19bf847b0c16dc3b85874d165e82278d99b29bd1b8bdc1a45a7d824bd4ffc0da5edacf0bfce0d349dfad73d048697611a8da92da475cc2f7480afcb89085c5fd25f79c0e478e6cca34a802b76ffd9632393175e2cee7cfb553523c2da6af79580851780c32f5b8e86d7d43472d41286e01889590f82051ccac30107ed8b4b2de53f112115c3db86a95a68db4bcaf3ccfd9418cc6007dec7d91d3060cd08ba5c0c004ef9418ff831531f9096258666342c7e22720394a7ea43ab262dd4daf5c69bc065f4deac2d2324824350f656b7ae9e7c8ced1bdb9bb996351082226ed7909cb467e01c64caa691d355fec1402aeea3d56678fe6123b0314402b3076b8eb24dda3805050cb05b56d609aec3356c8251a5ed57ce6e33bc29fb6b28d331372dcd3c51eaa10bd3ad96566bfe00", .Okay}, + {.Shl, "ec9e34414ceb4d8b170cb0207ead60516175d0715078c8550f4da5d636931640abc50787984fd347589e06c77476e0bde27b0a7602914b0608d8bda696571d8ff530e5f664609cdd1599bddb5477f88f51a0335855a2e11201bd8549541a5803d3646dd94b3b7db4f6374fc9ad9f2a7312233eb97d5a486845bb52aafc9438b5724cd94eeddd4dcb707a48fc4a92e824160c544ff36bbe92ee8ed896cc907e78f59a06dbadd3d87c13a7820a611593fde0b0108c2073de512e997291a26125db2bef2927e1da7bbfc8cf1c68337dd492697febf6cdfc1f85807df00df6e1e20e0357c0554f30b1b9dc2817d23fbddddc66f0c873ad31cbe9c33829e6ec1687b974460ba44a2cad920dfa510b09da1a6c6104ea301ee639cfb731dbead3435476ff7e85e38cd238a47b73e04b5774a80f18f344bf5d9fb37f479eed91f0f759bac6926b2e26eba2b97b9abd09f7c70858ca75fe0441a0463082c0f58a3d82544f7203cec6adaefe52007676be32ce629e973182a04889df7e0c40afa9d87404bb3e0b984d7625d86f7a0e93d10844722bf68a50ae823fcc60507371c5435ac76348f69b30778e8e017442d90ed70801ee0db5f30901e73e599a8c289070927dde230acb07c4d0977468ad0dc042b4995d07f5c505f8808bdc35ebc8d6a96cea4cd608b93c95d9628db62e082b1adbc7ba67ff657d272ef09d437611c9c8976a81", "5b", "764f1a20a675a6c58b8658103f56b028b0bae838a83c642a87a6d2eb1b498b2055e283c3cc27e9a3ac4f0363ba3b705ef13d853b0148a583046c5ed34b2b8ec7fa9872fb32304e6e8accdeedaa3bfc47a8d019ac2ad1708900dec2a4aa0d2c01e9b236eca59dbeda7b1ba7e4d6cf953989119f5cbead243422dda9557e4a1c5ab9266ca776eea6e5b83d247e254974120b062a27f9b5df4977476c4b66483f3c7acd036dd6e9ec3e09d3c105308ac9fef05808461039ef28974cb948d13092ed95f79493f0ed3ddfe4678e3419beea4934bff5fb66fe0fc2c03ef806fb70f10701abe02aa79858dcee140be91fdeeeee33786439d698e5f4e19c14f3760b43dcba2305d2251656c906fd288584ed0d36308275180f731ce7db98edf569a1aa3b7fbf42f1c6691c523db9f025abba54078c79a25faecfd9bfa3cf76c8f87bacdd634935971375d15cbdcd5e84fbe3842c653aff0220d0231841607ac51ec12a27b901e76356d77f29003b3b5f1967314f4b98c1502444efbf062057d4ec3a025d9f05cc26bb12ec37bd0749e884223915fb452857411fe6302839b8e2a1ad63b1a47b4d983bc74700ba216c876b8400f706daf98480f39f2ccd46144838493eef11856583e2684bba345686e0215a4cae83fae282fc4045ee1af5e46b54b675266b045c9e4aecb146db1704158d6de3dd33ffb2be9397784ea1bb08e4e44bb54080000000000000000000000", .Okay}, + {.Shl, "90bef72915b3872161383ad73516cdc5bb37a2094b5a8494b797194f47ae332c336834e14694a99985c9971851f62116bb83c3f21b2cb7d7fb65b1e5d82a61656f8c95c88c9f867d9b796258161de3bce83ebe4ea96768356ca0d124189dfbd62fa31300dfc4a6f64f8d35530ec19faf683f6e3b6e9cf43ef2c0fafc06e3171950d3d485614a9d879ac46924e69767505318ddd935cc56ec8ccaf8b65fa675c100b59b45b3261223b0f6bae32e5c18a8840eeda47179aa821e7deeb5dae6d393bf37837ca467fc7a56813520c6d296feb0c16c657351bf32644a29bfca7341cc231e8c2bc861fa6f0770435c4ec084dce184e5fd21f9396ea6c886e7dadffc0de6774a6de62d6ce196f8062e849fbef1f63367daa63012e3858b46ed8ab91e73505be8bb753abebdda341d0002edb9afb9c66008d1aa40142b449472ae4f0c7ff44fecf283cc3a691dd34f4aebbc12c7215d45dbf6c8b67dbfabdd979efdbd4c3db652ddb0bf679650c4f718616d4093be462260574ef8d87921e1b40f51c3b7c2e5b44454fbf90bb0973f0cb187d8e015053ef3373538c9188d9176e0ec341429f59c6307be6b6c1156fb0b93feae2ac551f62842e0ad431abe91244d6b97b3b41e4c011ed36f767dca0e514fcb42d1f0b505a07f688c9edde9d6fa16fb2de9dd1b812fe0ad3602f01ba37dc8e940acceeba493667224e00130ab5f257a5204", "62", "242fbdca456ce1c8584e0eb5cd45b3716ecde88252d6a1252de5c653d1eb8ccb0cda0d3851a52a66617265c6147d8845aee0f0fc86cb2df5fed96c79760a98595be325722327e19f66de5896058778ef3a0faf93aa59da0d5b28344906277ef58be8c4c037f129bd93e34d54c3b067ebda0fdb8edba73d0fbcb03ebf01b8c5c65434f5215852a761e6b11a4939a5d9d414c637764d7315bb2332be2d97e99d70402d66d16cc98488ec3daeb8cb97062a2103bb691c5e6aa0879f7bad76b9b4e4efcde0df2919ff1e95a04d4831b4a5bfac305b195cd46fcc99128a6ff29cd07308c7a30af2187e9bc1dc10d713b021373861397f487e4e5ba9b221b9f6b7ff03799dd29b798b5b3865be018ba127efbc7d8cd9f6a98c04b8e162d1bb62ae479cd416fa2edd4eafaf768d074000bb6e6bee719802346a90050ad1251cab93c31ffd13fb3ca0f30e9a4774d3d2baef04b1c8575176fdb22d9f6feaf765e7bf6f530f6d94b76c2fd9e594313dc6185b5024ef91889815d3be361e48786d03d470edf0b96d11153efe42ec25cfc32c61f63805414fbccdcd4e324623645db83b0d050a7d6718c1ef9adb0455bec2e4ffab8ab1547d8a10b82b50c6afa449135ae5eced07930047b4dbdd9f72839453f2d0b47c2d41681fda2327b77a75be85becb7a7746e04bf82b4d80bc06e8df723a502b33bae924d99c8938004c2ad7c95e94810000000000000000000000000", .Okay}, + {.Shl, "-91d6f507a8d69a20a3e5f669f28fe538889ccd314468678e7f399114c135f22da282c4bce3378c030545fda0aa612ff36a299758cdf8936bf324c54a2d3417bcf851e40673986d739116db2c6c7cc0370890e063e8acd114d7f8a83c2e594da51f73decdbd099f1d4ed0a15058fc6aeeb4aace3a0641d7302fc459f85342861a3a001902e65cd23e7be47152f27dbfaac05f3ee00092f0c0cfa8f1a8739e2b7c1b8733d3e517fa607ff506a44cdef895b10c833fcdfa45f2d4e8622277182e6084f3e14620078eafb9e2577fe71a25cb27dd078619c94521b59f7351a3365b274acbe20191976b9c4dceba9fccdefa0c35b31d9bbb38ea034a783bdf34c630a2fcfacd2286dc94e6ebcd4b1ae47eff976ee7586f63ddc00620a4b977961cb97b5a975d6e033c85008d7235ede6c815f82025c88fbaea2ec275c613f60439504ddedc83f443b89213a959207bf1380a0ab5e08b06ba9e21d82f4c41afbd646a80fc1088d74cb57d52a40cf7fae7bb4ec2ffc45eda07a94ac87a9f827c5449abf9c55980dc5f4f58210b3eed4b64998d0c0789aaf5c5b9fb9a853a771fad2a071beec7107d53cc51fcfcdd85fb7fc7a522d34774f377ccce76cb04564f4fc42d2eddd8c2b4fdaf6dc9c3a7224d40764d6c010d479a2e411a8f191bdef959790700a974cac40ee02b95db22654f6ad76d2353efd58f3ababe5ec0a93ce5d7bc0884", "12", "-2475bd41ea35a68828f97d9a7ca3f94e2227334c511a19e39fce6445304d7c8b68a0b12f38cde300c1517f682a984bfcda8a65d6337e24dafcc931528b4d05ef3e1479019ce61b5ce445b6cb1b1f300dc2243818fa2b344535fe2a0f0b96536947dcf7b36f4267c753b42854163f1abbad2ab38e819075cc0bf1167e14d0a1868e800640b997348f9ef91c54bc9f6feab017cfb80024bc3033ea3c6a1ce78adf06e1ccf4f945fe981ffd41a91337be256c4320cff37e917cb53a18889dc60b98213cf8518801e3abee7895dff9c68972c9f741e1867251486d67dcd468cd96c9d2b2f8806465dae71373aea7f337be830d6cc766eece3a80d29e0ef7cd318c28bf3eb348a1b72539baf352c6b91fbfe5dbb9d61bd8f7700188292e5de5872e5ed6a5d75b80cf2140235c8d7b79b2057e08097223eeba8bb09d7184fd810e541377b720fd10ee2484ea56481efc4e0282ad7822c1aea788760bd3106bef591aa03f042235d32d5f54a9033dfeb9eed3b0bff117b681ea52b21ea7e09f15126afe7156603717d3d60842cfbb52d926634301e26abd716e7ee6a14e9dc7eb4a81c6fbb1c41f54f3147f3f37617edff1e948b4d1dd3cddf3339db2c11593d3f10b4bb77630ad3f6bdb7270e9c893501d935b004351e68b9046a3c646f7be565e41c02a5d32b103b80ae576c89953dab5db48d4fbf563ceaeaf97b02a4f3975ef022100000", .Okay}, + {.Shl, "eeac9d0541ed80e9e317ca70f6ca2e1ac4c9363cbfcdad129c9080fc294fcbab6d0b71163aae74c00e108d941dd4ac71935689f2348d462b257f97740b088b0e72982154e628c7dc98ae1422a147abf7696c8a8436fa80dfca3c7ecbef5def8e6642e72296afcc82bdb1ab872e49fbc26745a98c85915ca87b30580065f3844ff0a2b1a79da11ed0b0f716245b79537357172ea11fcd28850f31cae8d497b819bc555be68844f830fae7bcf217da8ad518cf8253e8b0d28192fe3ef225f736accf8fda49fb893ee4728649abee150551296960cb5487ae924ec538b650b2f2f7db9542430d096db07ce7d4ca6f6bb2ae26ff7fa5d3dad4df5cdf60b708d172123fd114221056853b82b707b246e046bf2b973857a6caab7e92e76124f260db3384f89cdff5200624b427d37c2013826f3570eedd92f860c7b2e5c31d60ff9c6431819078e3dfda44e90d096ca84a10dc6e58195d49e0ca96df5b8734554f1e7e502ab28fb5e328aeb46498b4ff4c4c2276af0d4c0f01eec8966c3c5feb1df3bf9f3760f49230749726f5dd0fb6b4a43b63330c9af77d6e8c533c6c25000dd2e702706978944ef868dadfe678a19f86ea69e9e9fd65df777be83cc738a7535a2733febdabca85ab5ebe377d06df75aecb877436eb3dc427f9bdcb863a260c610759ec9fd78407be5e258bf2c47cbb0c0f740c58cbffaf3c7224f738ceddce621a", "28", "eeac9d0541ed80e9e317ca70f6ca2e1ac4c9363cbfcdad129c9080fc294fcbab6d0b71163aae74c00e108d941dd4ac71935689f2348d462b257f97740b088b0e72982154e628c7dc98ae1422a147abf7696c8a8436fa80dfca3c7ecbef5def8e6642e72296afcc82bdb1ab872e49fbc26745a98c85915ca87b30580065f3844ff0a2b1a79da11ed0b0f716245b79537357172ea11fcd28850f31cae8d497b819bc555be68844f830fae7bcf217da8ad518cf8253e8b0d28192fe3ef225f736accf8fda49fb893ee4728649abee150551296960cb5487ae924ec538b650b2f2f7db9542430d096db07ce7d4ca6f6bb2ae26ff7fa5d3dad4df5cdf60b708d172123fd114221056853b82b707b246e046bf2b973857a6caab7e92e76124f260db3384f89cdff5200624b427d37c2013826f3570eedd92f860c7b2e5c31d60ff9c6431819078e3dfda44e90d096ca84a10dc6e58195d49e0ca96df5b8734554f1e7e502ab28fb5e328aeb46498b4ff4c4c2276af0d4c0f01eec8966c3c5feb1df3bf9f3760f49230749726f5dd0fb6b4a43b63330c9af77d6e8c533c6c25000dd2e702706978944ef868dadfe678a19f86ea69e9e9fd65df777be83cc738a7535a2733febdabca85ab5ebe377d06df75aecb877436eb3dc427f9bdcb863a260c610759ec9fd78407be5e258bf2c47cbb0c0f740c58cbffaf3c7224f738ceddce621a0000000000", .Okay}, + {.Shl, "-964a6ae1783eb8a69d70c33c14e271550d8d17ca394c4560b663794a48ff7bcb9c8dbdaf7e218b05078823ebf587723878803d54563827b2e8c782103640173cb4586ee68eac855fafc2648f888083725c1be6f01e4b9f0fc5a5851d426369c5e581ba6f1568e0548f988b94b374f75715941084fd272061129e4dab619d9aa7ba2d98a323adf77564ed1b4a135c0aa7b93e43797fe77af072b14ba8e3cad2bac4f7e250c70d9bb54cd2885dbfcfebadfad383109be69ed8fd0ca8145c90708b045aa918385ce58afb8a52a562c8c8397e613feb66124d5784f7615dc9b685fd5d919118604297c1db62974442f29d33142b4cb743d0e0daa1a3814f74a5cc643461629562d96e6be06f9eb008052b92672790579d6869e5f0f00f353f7fb7f84eca4db884442b00c99c67a0158c7749b41f9164ab1a5e9aa0d47e95215f48044154d7b2c49b52eabdcda3acc1b391d4418ac8c4472531883784c032b4607bddf7de0f2d3375bbc8e5ca8ecd9ede6b4e4f5695e797490d1d2b2aa01e1e0639e6670b1502437738002a34fd160329bcd2a02bfacc3631060ebdc8b337d4117b2883b6c55ce2dc2a5cbc008b55bc3a4a4095dad97b42ac2cbe4ea8c731802842152d789f028ff5fc134fd488d4f74f8c7af410c94c865647186d63fe3906cc8b1e9a57b7f20a861875f7f52d8511c12d790dcc7d45c777349c2c26f3d49882934b", "b", "-4b253570bc1f5c534eb8619e0a7138aa86c68be51ca622b05b31bca5247fbde5ce46ded7bf10c58283c411f5fac3b91c3c401eaa2b1c13d97463c1081b200b9e5a2c3773475642afd7e13247c44041b92e0df3780f25cf87e2d2c28ea131b4e2f2c0dd378ab4702a47cc45ca59ba7bab8aca08427e939030894f26d5b0cecd53dd16cc5191d6fbbab2768da509ae0553dc9f21bcbff3bd783958a5d471e5695d627bf1286386cddaa669442edfe7f5d6fd69c1884df34f6c7e86540a2e483845822d548c1c2e72c57dc52952b164641cbf309ff5b30926abc27bb0aee4db42feaec8c88c30214be0edb14ba221794e998a15a65ba1e8706d50d1c0a7ba52e6321a30b14ab16cb735f037cf58040295c93393c82bceb434f2f878079a9fbfdbfc276526dc4222158064ce33d00ac63ba4da0fc8b2558d2f4d506a3f4a90afa40220aa6bd9624da9755ee6d1d660d9c8ea20c56462239298c41bc260195a303deefbef079699badde472e54766cf6f35a727ab4af3cba4868e9595500f0f031cf333858a8121bb9c00151a7e8b0194de695015fd661b1883075ee4599bea08bd9441db62ae716e152e5e0045aade1d25204aed6cbda156165f27546398c014210a96bc4f8147fafe09a7ea446a7ba7c63d7a0864a6432b238c36b1ff1c8366458f4d2bdbf905430c3afbfa96c288e096bc86e63ea2e3bb9a4e161379ea4c4149a5800", .Okay}, + {.Shl, "4eb346ac6719c269e9f6297c3fe4eb5d07f7dcc6effda18e2fe2458bd599986549f6d66d25688d5f4cca1cdfde04b45c9beba44cf1e52d1d4385c5c9cc75f12de02ff098f5bf5239643756e376b967b6bbe6049e11ee716ef800a260fa732647acf49678714e8393e7128ab7f0a890243b564c22293bc7130dcc9827709b451aa88da911a63b30ea48e3ad85d174c7158a5cbbdd13eafd814a8f295d8d591fdf43e2dfc14a1882c93241f2c0a9308865d285876027d040f942ca3850d9e2d87938e01783f5da5453f849f3403110c83ee53b4c3a6872c57ab646d8f0b34ae8030c2bec7645cb0c954ef8b61d48baba7596ec6b41b32c3615f2ac6338ca16454d76806b72f5ed75e1ff8214096551b226ec2c82acdeafd6c94bb194f5fd5854de999ab0b98dc789ac13b00974011fdfd2a4b0dda223fb997f90b45d69119bdc1c85bb842f17a39f2e627586041f2d9685b3e3e4c69101e923c5da7ac1a4c933cbf6d40d9a9397e2c4f746e607b642c7f6f76422bf71abfefab5c7cd90ffe5c5c9c7549edf4eac969815d27344a1176f87934cc2d3f5e3543eda713abaa7fe12b3bb6497232cabce2094f7a2af96b178a9f9cba6ac69f211f056bc0b922e050f9a68f18ec575f2398034805de20f780c9b9b08722f796cf48b87599d204698090711c4b756ee5c6b1b1b365c38cc602912300ec48ca410e3b1018a70c220e360fa", "12", "13acd1ab19c6709a7a7d8a5f0ff93ad741fdf731bbff68638bf89162f5666619527db59b495a2357d3328737f7812d1726fae9133c794b4750e17172731d7c4b780bfc263d6fd48e590dd5b8ddae59edaef98127847b9c5bbe0028983e9cc991eb3d259e1c53a0e4f9c4a2adfc2a24090ed593088a4ef1c4c3732609dc26d146aa236a44698ecc3a9238eb61745d31c562972ef744fabf6052a3ca57635647f7d0f8b7f0528620b24c907cb02a4c221974a161d809f4103e50b28e143678b61e4e3805e0fd769514fe127cd00c44320fb94ed30e9a1cb15ead91b63c2cd2ba00c30afb1d9172c32553be2d87522eae9d65bb1ad06ccb0d857cab18ce328591535da01adcbd7b5d787fe0850259546c89bb0b20ab37abf5b252ec653d7f561537a666ac2e6371e26b04ec025d0047f7f4a92c376888fee65fe42d175a4466f707216ee10bc5e8e7cb989d618107cb65a16cf8f931a4407a48f1769eb069324cf2fdb50366a4e5f8b13dd1b981ed90b1fdbdd908afdc6affbead71f3643ff9717271d527b7d3ab25a605749cd12845dbe1e4d330b4fd78d50fb69c4eaea9ff84aceed925c8cb2af388253de8abe5ac5e2a7e72e9ab1a7c847c15af02e48b8143e69a3c63b15d7c8e600d20177883de0326e6c21c8bde5b3d22e1d6674811a60241c4712dd5bb971ac6c6cd970e33180a448c03b123290438ec40629c308838d83e80000", .Okay}, + {.Shl, "-59f18f20a059e4e91860c2920dc39625a943493c8eb922f28c6f3c75731acaa8ac44b9c115e881a39bfdb79d39daf4e09970700cccbd516c3a10473f195dad4aeb20f0cf9e8f3098d8d7772b8727ab1aaa898174847ee29b0ea9c22a934307fc33dabf7e75cf68eb769da02e0879a130d9f4f4b2e15e43f05a9ba6972fdd06e404e7c6c683bfb8bfd8fb955bbc077068819b053e78a3c984776f851f38a56de9d386e2440da0345b8a13afa605c0949d5033c3380aa6906120e982c574561aa2758fddcfc8a934c08b2fe6253a32d29c7b434ec0a4b84275d72a5cbd3d972a18202957e0ca66fdf4fb55242e141acdc64c53476f46861f702cab2fb22f07e5e7ff18594377345bd18921888717628887d039e005fadece5cd2d920728c1f5e62b0c248bae4ee59abf7ef0960fc5e4d13352bf6719a06ee1fdb29084fe8d37abdd10d23ed69b7dfa7892e91156260d33d8d48ed77267d21d6719d74c6578c3fbfb47ef5e533dc089317ea0f5510065f5a9b32d9557eb90f5d30bb6b61b784cff78c3a9aa8e7564408d1056e1c86ddd091422f6db95468ef54e4501cf904d03c3cd92f8d7d60e16c37d83c3afeb12370b2e033676926ddb6f60450acff2c9b37939e9f485257d24278df7df632a578b6c5126d797eb34b5385cafb225b3242c63d23668d6a6a6834765df8b11e31061d0fd5858ea63c9c417b76e43f42f141ea9c", "2", "-167c63c82816793a461830a48370e5896a50d24f23ae48bca31bcf1d5cc6b2aa2b112e70457a2068e6ff6de74e76bd38265c1c03332f545b0e8411cfc6576b52bac83c33e7a3cc263635ddcae1c9eac6aaa2605d211fb8a6c3aa708aa4d0c1ff0cf6afdf9d73da3adda7680b821e684c367d3d2cb85790fc16a6e9a5cbf741b90139f1b1a0efee2ff63ee556ef01dc1a2066c14f9e28f2611ddbe147ce295b7a74e1b89103680d16e284ebe981702527540cf0ce02a9a418483a60b15d1586a89d63f773f22a4d3022cbf9894e8cb4a71ed0d3b0292e109d75ca972f4f65ca86080a55f83299bf7d3ed5490b8506b3719314d1dbd1a187dc0b2acbec8bc1f979ffc61650ddcd16f462486221c5d8a221f40e78017eb7b39734b6481ca307d798ac30922eb93b966afdfbc2583f179344cd4afd9c6681bb87f6ca4213fa34deaf744348fb5a6df7e9e24ba445589834cf63523b5dc99f48759c675d3195e30fefed1fbd794cf70224c5fa83d5440197d6a6ccb6555fae43d74c2edad86de133fde30ea6aa39d5910234415b8721b77424508bdb6e551a3bd53914073e41340f0f364be35f58385b0df60f0ebfac48dc2cb80cd9da49b76dbd81142b3fcb26cde4e7a7d21495f4909e37df7d8ca95e2db1449b5e5facd2d4e172bec896cc90b18f48d9a35a9a9a0d1d977e2c478c418743f56163a98f27105eddb90fd0bc507aa70", .Okay}, + {.Shl, "97eb82316b12c7e599f9dc924c390801979b4aca660e76a694ce2775ade4e950feca3991f26ff9765637cc17842d3c6bc00774b6af2e7a7ab3b00507768e84bf720d0debfb43210e4cfbe81e6e142f9e6b7f4eeeaf2c3262025c962a13ba3fbd691a81ed3ede39aa511132ce3e6f9540b237e0f6dc338ac52d52c9dbd82888efb926f021b3908af82fe9a6ed7253a04d266137d51af16dace3b9a6f87863872736af619bfc77a824fc09fa6d49f72caf32fe392b20598c2aeee64569dbe10c89027d1178fe981c22696d75682f30fd145bf0073fb90c7a19176a02b8e0b8e35ad3258ad7656e2881b8b6475d82ebcea37e85a8cf3b1b6012569f310eec347ceabe74fb35df7beafbfa0f3a2342687796d2c07c609292fb1842d51aa1783a5090770316c815875b114a84cf71c708884745183146b3f86a5a1a9f8282b47859ce8dfe444b740efb4e22cf08883b04957622d7c6aa0ef303368c1c62b0c418746cd045a6bcfb297a5f7ceee85946759dc43de5f33bf2f1182de4e4f6d6035d52db3403ea3ba81595400ff3e0efcdf93a2f4888c1c77a09d68321460bfee35890f18b75e373cfcc5bd8882a6898fd580bbab1cca74528c9ce3982da0fdd5acc6cc863888b25da3971ec76e723b8142c901e71f36f7d43b08ca7245e4d02cdb763e90d8a107d881758f10e699c66a4a3530d39a9c22dc03f2e8fca36fb5091a3c6a6", "3a", "25fae08c5ac4b1f9667e7724930e420065e6d2b299839da9a53389dd6b793a543fb28e647c9bfe5d958df305e10b4f1af001dd2dabcb9e9eacec0141dda3a12fdc83437afed0c843933efa079b850be79adfd3bbabcb0c988097258a84ee8fef5a46a07b4fb78e6a94444cb38f9be5502c8df83db70ce2b14b54b276f60a223bee49bc086ce422be0bfa69bb5c94e81349984df546bc5b6b38ee69be1e18e1c9cdabd866ff1dea093f027e9b527dcb2bccbf8e4ac816630abbb9915a76f84322409f445e3fa607089a5b5d5a0bcc3f4516fc01cfee431e8645da80ae382e38d6b4c962b5d95b8a206e2d91d760baf3a8dfa16a33cec6d80495a7cc43bb0d1f3aaf9d3ecd77defabefe83ce88d09a1de5b4b01f1824a4bec610b546a85e0e94241dc0c5b20561d6c452a133dc71c22211d1460c51acfe1a9686a7e0a0ad1e1673a37f9112dd03bed388b3c2220ec1255d88b5f1aa83bcc0cda30718ac31061d1b341169af3eca5e97df3bba16519d67710f797ccefcbc460b79393db580d754b6cd00fa8eea05655003fcf83bf37e4e8bd2223071de8275a0c85182ffb8d6243c62dd78dcf3f316f6220a9a263f5602eeac7329d14a32738e60b683f756b31b3218e222c9768e5c7b1db9c8ee050b24079c7cdbdf50ec2329c9179340b36dd8fa4362841f6205d63c439a6719a928d4c34e6a708b700fcba3f28dbed42468f1a9800000000000000", .Okay}, + {.Shl, "a3eb5c7ad3b382776b884c031c40119b605d30c35e8e857823848cdfd4cb1b86dfea14da9eb6643ae3030dcbe6432dbac11835211d216b9fdb7524d40cc626d85f09a85b69fb8d27273df69c86081841fd44cd6c589ed43fdbac8a45f357819fc2837cd4615ab8a7534789820250005384d377a914236d14ac8bdd2179d12e59b6a77f5d8ce93c0fdfcff5f88807baecf3d2e7cff9c92fdd97f3f76ecfc86dbdbfa8906295c917f2e8da2442929caa250e5c81f51b3fd90fea16e12a07fa79ca0d15a2cb38afd8264356af6ca46b3a4d3f4ced4f14e8ccef53433d795f28a74ab78cfb5b86ea3d1a1d61e934bced4c93231484adb58c9159124f2a68ed4929bb3c24db1ac3f24298774cf9e92b77f4fcad8fc1b1fa29234679e088d2ca3973aa9e5085b19acb085abd6ba1a1301bff839de0930625675ba797579316ebe9bd847ce4e58551a8c193c4894975451ac45307628efa7f08bdd1f8c7c82efae8fc554313c68d80b6f1f46310e478833b001917c5f6369231320189a57f798cc34c6321e91292bebe31d4d3af77deec5c3be449af95dbe80582e5d1142d7750d7a96133f9bf6f53b65f32122b9c32ffe826303a6edf4332425122ee732ab3a0c87b5462a32b1e4761947be278178fff487b601a9ab8fbc35a443717162cb3a5ffd9209b7196b735e34fafcc8e923161ae68a9c6c665055631093e2a27fb564ea68fb5", "4d", "147d6b8f5a76704eed710980638802336c0ba6186bd1d0af0470919bfa996370dbfd429b53d6cc875c6061b97cc865b7582306a423a42d73fb6ea49a8198c4db0be1350b6d3f71a4e4e7bed390c103083fa899ad8b13da87fb759148be6af033f8506f9a8c2b5714ea68f130404a000a709a6ef522846da295917ba42f3a25cb36d4efebb19d2781fbf9febf1100f75d9e7a5cf9ff3925fbb2fe7eedd9f90db7b7f5120c52b922fe5d1b448852539544a1cb903ea367fb21fd42dc2540ff4f3941a2b4596715fb04c86ad5ed948d6749a7e99da9e29d199dea6867af2be514e956f19f6b70dd47a343ac3d26979da99264629095b6b1922b2249e54d1da9253767849b63587e48530ee99f3d256efe9f95b1f8363f452468cf3c111a59472e7553ca10b63359610b57ad743426037ff073bc1260c4aceb74f2eaf262dd7d37b08f9c9cb0aa3518327891292ea8a3588a60ec51df4fe117ba3f18f905df5d1f8aa86278d1b016de3e8c621c8f1067600322f8bec6d24626403134afef3198698c643d225257d7c63a9a75eefbdd8b877c8935f2bb7d00b05cba2285aeea1af52c267f37edea76cbe6424573865ffd04c6074ddbe866484a245dce655674190f6a8c546563c8ec328f7c4f02f1ffe90f6c0353571f786b4886e2e2c59674bffb24136e32d6e6bc69f5f991d2462c35cd1538d8cca0aac62127c544ff6ac9d4d1f6a0000000000000000000", .Okay}, + {.Shl, "c374eaa15d4a5fafb3cc14ac3dad8cce40642cd43091e3598fcaa7835a7d59a0ebce601b7dd57680adcb51a93998524f856aa7df100f193be833d1ee26d2c48746dfe784dfc1ceec85d50c9564768d0fe02adfa73c84eb77d652eac4b3a51c862cad42dbe58065e0a0fb2db1407d61dea50338833b1195dc1838e773109b6b25d9ff543794d49493caf4aa69897590f0ffa4c8a4354baed8793cdb473ff6c6dfb4e872a6ee5d69005066535e8b69e9a0cd532f71e4a2b643cbbcd4532d30b5af25983674f70eb54253b0acc8ac66a3981ae5920be2c9bd5bb604be4bc1f729ad05292a0edd56682ae150e46f730c9122c7d0c0510d3883acd5d142807dec72f8d227d49cbeb33ef67c391310a6bcccbe7dea2216f159b8bdfe74d2c8c5de4064d456c5101969b59d4665703039894fff34e4efaf8a2c0de69963615ccb7ed66190effd81c527a14251a37c2e5415ea3a4afba01c9a26fc47ebae2bebdacc2ccc785ddc0ef18ab16a0b556ababbdb47e4cb43f2b95fd1ef096843e65ff91bffe5cd80194d6c6b0900fc2b565d823631027df27de2e9177e5340d41faa6470907a23406a6816c9e16fe6a19422b4114061498da75ee23565b651c004a4d11f664d54e0f0bab1e878915aa29628c7716b7e00e3e2faf9fb2d702fc2df80c7959a3079ca85cb2d6f4e5300d4c6e5366e789be77928fde12bf9c59722867e1a6d2d5f", "31", "186e9d542ba94bf5f679829587b5b199c80c859a86123c6b31f954f06b4fab341d79cc036fbaaed015b96a3527330a49f0ad54fbe201e3277d067a3dc4da5890e8dbfcf09bf839dd90baa192ac8ed1a1fc055bf4e7909d6efaca5d589674a390c595a85b7cb00cbc141f65b6280fac3bd4a06710676232bb83071cee62136d64bb3fea86f29a9292795e954d312eb21e1ff4991486a975db0f279b68e7fed8dbf69d0e54ddcbad200a0cca6bd16d3d3419aa65ee3c9456c879779a8a65a616b5e4b306ce9ee1d6a84a761599158cd473035cb2417c5937ab76c097c9783ee535a0a52541dbaacd055c2a1c8dee61922458fa180a21a710759aba28500fbd8e5f1a44fa9397d667decf87226214d79997cfbd4442de2b3717bfce9a5918bbc80c9a8ad8a2032d36b3a8ccae06073129ffe69c9df5f14581bcd32c6c2b996fdacc321dffb038a4f4284a346f85ca82bd47495f74039344df88fd75c57d7b5985998f0bbb81de31562d416aad57577b68fc99687e572bfa3de12d087ccbff237ffcb9b00329ad8d61201f856acbb046c6204fbe4fbc5d22efca681a83f54c8e120f44680d4d02d93c2dfcd432845682280c2931b4ebdc46acb6ca3800949a23ecc9aa9c1e17563d0f122b5452c518ee2d6fc01c7c5f5f3f65ae05f85bf018f2b3460f3950b965ade9ca601a98dca6cdcf137cef251fbc257f38b2e450cfc34da5abe000000000000", .Okay}, + {.Shl, "-576047e8ed2d02648b59f8035f76082d9b305578f4d927ae51b25d6882e767ef97a94e7bf4ab92531bf95858cad956d5ac620674c693f202763ac0a3ad86c1ebe29b8a355b5e8735db09397fc2f22b99b3540ddfd2d46a26c31ed2fcd897105f40d386f8b09063572a87ffd48390493f7c826e5381f0d1940eb30ea764d8fd8efbaa04c7d4b7bc342729a4d07af73973ff62716779e3cff35cbd3a06d7dbb92ce12b7a388c7c0fd3d3c957768f021a79d79604a12c432dd9cde78e137e531f5f55c535ad1d1e115557e24f8c910a6a059c81aaae7aa6364f471c6eff989e5b50dabccb3f8a40b98f2793986e467187f9ec33cb19f945cef2849f13d705198ccd3e93bd706095866dbd8d2004bdfef1c89b03d0ba99de673f3d70d7324ab399b1efb6a8cfb0cb06362c86af168c9c4e8ac1acebf5950be381f04c36be4d9f26fc6ae26212502d946a22a2b29fdd5535c1e9f88f547f075621fff9eb47490b2eb21354038da9632fb039c2b6c89e0b960baff68f6a5ecd543e160e27f860c3930f7f68fbe1ff4e17b7eea735509cddea71dedc9b38b6b190261e67207768fc6c89aee3c083cbe209b6506253e5610ae37c778c8cc716b9b33185952efe02dc17dcda17841c093283f77b55d3e586dae1c0cac3377677dda92818464d42fe64a6e5c706bf880ed84891be30bd07cf713ee800fcd446972913d28defcb9e498e6d17", "59", "-aec08fd1da5a04c916b3f006beec105b3660aaf1e9b24f5ca364bad105cecfdf2f529cf7e95724a637f2b0b195b2adab58c40ce98d27e404ec7581475b0d83d7c537146ab6bd0e6bb61272ff85e4573366a81bbfa5a8d44d863da5f9b12e20be81a70df16120c6ae550fffa90720927ef904dca703e1a3281d661d4ec9b1fb1df754098fa96f78684e5349a0f5ee72e7fec4e2cef3c79fe6b97a740dafb77259c256f47118f81fa7a792aeed1e0434f3af2c094258865bb39bcf1c26fca63ebeab8a6b5a3a3c22aaafc49f192214d40b3903555cf54c6c9e8e38ddff313cb6a1b579967f1481731e4f2730dc8ce30ff3d8679633f28b9de5093e27ae0a33199a7d277ae0c12b0cdb7b1a40097bfde3913607a17533bcce7e7ae1ae6495673363df6d519f61960c6c590d5e2d19389d158359d7eb2a17c703e0986d7c9b3e4df8d5c4c424a05b28d44545653fbaaa6b83d3f11ea8fe0eac43fff3d68e92165d6426a8071b52c65f6073856d913c172c175fed1ed4bd9aa87c2c1c4ff0c187261efed1f7c3fe9c2f6fdd4e6aa139bbd4e3bdb936716d63204c3cce40eed1f8d9135dc7810797c4136ca0c4a7cac215c6f8ef19198e2d7366630b2a5dfc05b82fb9b42f0838126507eef6aba7cb0db5c38195866eecefbb5250308c9a85fcc94dcb8e0d7f101db091237c617a0f9ee27dd001f9a88d2e5227a51bdf973c931cda2e0000000000000000000000", .Okay}, + {.Shl, "c229f2764f657e1bdb0506472750ae304fe0b698e63b047afe9c868a124b90b873974948704d8f2d9145e9b2a0261d6f5fd645d0f1d811721f64168c188fd51968385edc5bfa41f76fc8c6e00678ae9e3d9d5bab9f996a20f5760596f48886378b3087cdc47af2d8650c24f8d732a0b2772bf4993d9f537d8fda39ed51a7c12e66cde7f3959f94d280689cef4e2976887dd3f322e85e23b3cefd9cb2ff9a1af153363afcdb55af595fc10fc16fc05f7d50d0b5f2e386a93d013aa1edcefe10bc89d60ed28c6e66ef11f300080ec0af3eb9b34f01ff77e66d935422c722f8a3d490c5203f0faffe5322236a1fc0afcbed2dc8647812895f9fe9ea72c8db9d2350dfe89efe0f3ca54fcdb7472a65d258c2051f443547272333594b12892afd18ae1bd67ee3c7dee29f209c214ba64dadf42ba45a2a76613b0087370f4ac1495cfd1acefc93fe871e55cc4a4a22e528594926ba5a6c0f671eb8dbfc94272e3f1dfde2bb459aadecf1636d5c7ce859cbf21f69bbbbefe0d8aee3f45a22db2bd304c1ab074bb716648c4eb854e937a992bbed255d54ba7480fb10613fb9abf4f41ebe38fc9e3091f8e1161ca2d6837c5444bc42db4613777f829613792b16f4b838749f642125337fb1aa539570c856ad46043057e54260ad21007a92cd4c60e71f3b88fb02b86c6d0a5ff9215406603882734cbbf67f3bf2c2262a1f851fa606b07", "42", "308a7c9d93d95f86f6c14191c9d42b8c13f82da6398ec11ebfa721a28492e42e1ce5d2521c1363cb64517a6ca809875bd7f591743c76045c87d905a30623f5465a0e17b716fe907ddbf231b8019e2ba78f6756eae7e65a883d5d8165bd22218de2cc21f3711ebcb61943093e35cca82c9dcafd264f67d4df63f68e7b5469f04b99b379fce567e534a01a273bd38a5da21f74fcc8ba1788ecf3bf672cbfe686bc54cd8ebf36d56bd657f043f05bf017df54342d7cb8e1aa4f404ea87b73bf842f227583b4a31b99bbc47cc00203b02bcfae6cd3c07fddf99b64d508b1c8be28f52431480fc3ebff94c888da87f02bf2fb4b72191e04a257e7fa7a9cb236e748d437fa27bf83cf2953f36dd1ca997496308147d10d51c9c8ccd652c4a24abf462b86f59fb8f1f7b8a7c8270852e9936b7d0ae9168a9d984ec021cdc3d2b052573f46b3bf24ffa1c79573129288b94a165249ae969b03d9c7ae36ff2509cb8fc77f78aed166ab7b3c58db571f3a1672fc87da6eeefbf8362bb8fd1688b6caf4c1306ac1d2edc5992313ae153a4dea64aefb4957552e9d203ec4184fee6afd3d07af8e3f278c247e38458728b5a0df15112f10b6d184dddfe0a584de4ac5bd2e0e1d27d908494cdfec6a94e55c3215ab51810c15f950982b48401ea4b3531839c7cee23ec0ae1b1b4297fe485501980e209cd32efd9fcefcb0898a87e147e981ac1c0000000000000000", .Okay}, + {.Shl, "-50ef35251e97dadc4339555fbaad473e41f73fb1c45d6653d65fd0a5f37e1e594fe109cf32c1a1bbcb48950b8021de4602d3afab037c9a281fcb15b49635551cdce469daac535359b01bc8f2620749d9e1867a529ba1b5c4bf5c7b9d8c64bd3c96e2db7a286fc4e7dfcea54311ba94b16d430bd90f46fbf4e0b38f9b6be28786c277adc9919264b9fc0589da0ce67cc86985e6911d41ef9dda6d0d2c78a9e9ac87f6fb30482714a4a37c962ec5428602549574151782d084e4c904d3e93db8702390f9a7ac56200f92cc98e4c2c20afed6d9b7b78cc492bcbe8614d375dd714c577e0ba26e69568ef664d5398f9207c1af9dd35df69fd8ebd59a77712d0ce8c0cba6d43b40c27ea470a722fe4fbce1723bfba6346aefccfd19a395bca46b39753d80217389ab10134c84ab8ae18bb059a6da010d209235e3668b5a3860017b3bf39a50b6a397d2acf04cd4c596cb2ee9af85fadf92d562322121e9b14e69cbc9442fd01ff5920f4e634935125e8829b3c1e4c3420140a0f31a537abceca81ea7784cc4a564b72e0f7051d4449ba19f01fcb4ec0963c9f11426c13d713a2cf85dc5c1c3ba4c3e4846268ba51f960a687a57ebdb72fdcabe9502c5d888a9bdcd2d7f58f4df77e3cb5cfeeea1bac3b6b0a035919b48b7d7fa05f3c3f422a77b00f6c8e647d7f7a3d126444081eb4548d9076cb2e464fedaac18330447b58203059b", "4a", "-143bcd4947a5f6b710ce5557eeab51cf907dcfec71175994f597f4297cdf879653f84273ccb0686ef2d22542e008779180b4ebeac0df268a07f2c56d258d554737391a76ab14d4d66c06f23c9881d27678619e94a6e86d712fd71ee763192f4f25b8b6de8a1bf139f7f3a950c46ea52c5b50c2f643d1befd382ce3e6daf8a1e1b09deb726464992e7f01627683399f321a6179a447507be7769b434b1e2a7a6b21fdbecc1209c52928df258bb150a18095255d0545e0b42139324134fa4f6e1c08e43e69eb158803e4b3263930b082bfb5b66dede33124af2fa18534dd775c5315df82e89b9a55a3bd99354e63e481f06be774d77da7f63af5669ddc4b433a3032e9b50ed0309fa91c29c8bf93ef385c8efee98d1abbf33f4668e56f291ace5d4f60085ce26ac404d3212ae2b862ec1669b6804348248d78d9a2d68e18005ecefce6942da8e5f4ab3c13353165b2cbba6be17eb7e4b5588c88487a6c539a72f2510bf407fd6483d398d24d4497a20a6cf07930d08050283cc694deaf3b2a07a9de133129592dcb83dc14751126e867c07f2d3b0258f27c4509b04f5c4e8b3e17717070ee930f921189a2e947e5829a1e95faf6dcbf72afa540b176222a6f734b5fd63d37ddf8f2d73fbba86eb0edac280d6466d22df5fe817cf0fd08a9dec03db23991f5fde8f4499110207ad1523641db2cb9193fb6ab060cc111ed6080c166c000000000000000000", .Okay}, + {.Shl, "-ba7fdd4d0fde7da6d467934ae22540e1e598e4608ab04a75254728c49188dfe30c7ac9277b3233e790ff874a8a5bef6906d6f6b5554cc2d92c2074fed10c99a35a5c4a5ae35f2cb49ab47f203a593d68513a3cad7841f0a85ac2ef00f13ce3ad051c109ba6438d49ee502adb99fef00623111d61a8a32e920304ae0cf98aa9a9768268d25216cecb4f761647358ada598a69ae734810f9f4d2b61cd0f9bc8ce4c4656bd1f5825ae57d9106ef57d41e3e5cc8d5b62cebb80e5cb97f8871a2f7ff236d8fe5f4d78f532dfa361c4f5cb544344c83f3f436636fde6fa4c63aaf1f879820b42fbdf3da94b0a42088c6396d67c5dd89a63dc10860ed2c283e2e484fc967906f145e9ade0c7b133532db8ad3978ff99beb89f5aee48454f83e3a06f68695c3bf3ec23d8287ced323bfe5184e8dec30b6d4f5c6f066daefbd746fd057cf73ae2f01f2a81e46a0554bf31b2ba42ecf6883d19a86c33bf96b6cfa27331a7aeb0bdc70bbab7de712e8ab0b16b3e857afeeb5b7280d72557702807ec2d3f29c71b4b1aac9d49b380d76de6bacebc2a2fb0f0dbdbf7de4d93bd56aac704c466818f9702cfb0ab20770dd9656682591a11a918d39310b53cf7114e980eca2e5287871933ba9da9ef71c63c59783de100b088b60861223cffd2791501c5d632d031dbdfb0a006e998b460665a2240622bf5a87423514585d5c073d6cff0bd81c3e", "3a", "-2e9ff75343f79f69b519e4d2b88950387966391822ac129d4951ca31246237f8c31eb249decc8cf9e43fe1d2a296fbda41b5bdad555330b64b081d3fb4432668d6971296b8d7cb2d26ad1fc80e964f5a144e8f2b5e107c2a16b0bbc03c4f38eb41470426e990e3527b940ab6e67fbc0188c447586a28cba480c12b833e62aa6a5da09a349485b3b2d3dd8591cd62b696629a6b9cd2043e7d34ad87343e6f233931195af47d6096b95f6441bbd5f5078f9732356d8b3aee03972e5fe21c68bdffc8db63f97d35e3d4cb7e8d8713d72d510d1320fcfd0d98dbf79be9318eabc7e1e6082d0bef7cf6a52c290822318e5b59f17762698f7042183b4b0a0f8b9213f259e41bc517a6b7831ec4cd4cb6e2b4e5e3fe66fae27d6bb921153e0f8e81bda1a570efcfb08f60a1f3b4c8eff94613a37b0c2db53d71bc19b6bbef5d1bf415f3dceb8bc07caa0791a81552fcc6cae90bb3da20f466a1b0cefe5adb3e89ccc69ebac2f71c2eeadf79c4ba2ac2c5acfa15ebfbad6dca035c955dc0a01fb0b4fca71c6d2c6ab27526ce035db79aeb3af0a8bec3c36f6fdf79364ef55aab1c13119a063e5c0b3ec2ac81dc3765959a09646846a4634e4c42d4f3dc453a603b28b94a1e1c64ceea76a7bdc718f165e0f78402c222d8218488f3ff49e454071758cb40c76f7ec2801ba662d1819968890188afd6a1d08d4516175701cf5b3fc2f6070f800000000000000", .Okay}, + {.Shl, "1999ccf991a8e29fe2692c6d3b96c540ba6a4c1a7a32525f70ece4a164ec489fb2d657e49820acb657112fd3f49006ac1469a907ddc9b3fcf856c9be517c3a50d069c8e08360d93343d5db8984a54d0bafc48b7be46ca76a42ce1f08d0db1cca43fcbea5fa5d0daf1f0aec9d03ae5289919fcd2f5e38ab77c2bb0852f6896297269844ade4d5e14ec63254da3aea2411bf704c6765ebc454f2bf63925983be04aed56b7d064a6e73657c3c77e8a8a0b4fffe7124f9df6cd467780351cbb0eb6624850ebc83a549ef4cdb2cd04ee4eec81a749d9998400ebbc2dc77105df87ea1256be3e5f151289b4b278d1236e0cf75edc070268f2f79d07ef2eb7be0a5a1756e3c1547750e57ecea852847a83a77d402ebfe6f26c67b4ac581afe3694f2d4b43535abf0b2e7f2b897a0503994e331eab554cfec197039e460841614f9d120baad7d693b66659b6bb8ef50178f9791b7d7ff91a2b0571a897e035291060fc903ae3571eca406b7559229048b142a9b9a847825a8d276a5d04956b441f1a963dae46b44fda5d8845288774d4636f9ad563a30ca460a7863f392b70296665ed15c80405a4a76837ee794896c480a4e9faa381cc8c4bf7219096d68f18238ecc9234fe560c9134867088c285157d6e32a47fe7982e4552381e3dee8dded6e3b6813b85fa75af2aa7992c45e0993f77aa99b399f9475bfbdb5cda61c905bebab77b", "1f", "ccce67cc8d4714ff13496369dcb62a05d35260d3d19292fb8767250b276244fd96b2bf24c10565b2b8897e9fa4803560a34d483eee4d9fe7c2b64df28be1d286834e47041b06c99a1eaedc4c252a685d7e245bdf23653b521670f84686d8e6521fe5f52fd2e86d78f85764e81d72944c8cfe697af1c55bbe15d84297b44b14b934c2256f26af0a763192a6d1d751208dfb82633b2f5e22a795fb1c92cc1df02576ab5be83253739b2be1e3bf454505a7fff38927cefb66a33bc01a8e5d875b31242875e41d2a4f7a66d9668277277640d3a4ecccc20075de16e3b882efc3f5092b5f1f2f8a8944da593c6891b7067baf6e038134797bce83f7975bdf052d0bab71e0aa3ba872bf675429423d41d3bea0175ff3793633da562c0d7f1b4a796a5a1a9ad5f85973f95c4bd0281cca7198f55aaa67f60cb81cf230420b0a7ce8905d56beb49db332cdb5dc77a80bc7cbc8dbebffc8d1582b8d44bf01a9488307e481d71ab8f652035baac91482458a154dcd423c12d4693b52e824ab5a20f8d4b1ed7235a27ed2ec4229443ba6a31b7cd6ab1d186523053c31f9c95b814b332f68ae40202d253b41bf73ca44b62405274fd51c0e64625fb90c84b6b478c11c766491a7f2b06489a43384461428abeb719523ff3cc1722a91c0f1ef746ef6b71db409dc2fd3ad79553cc9622f04c9fbbd54cd9ccfca3adfdedae6d30e482df5d5bbd80000000", .Okay}, + {.Shl, "-dade04969f7a3af399fa0e94cbd3a52af0b47f4fe3e61ae620c7b7bf9789b01f9c3c90e94d327f7fe4fd119561f94badb7a898c03c2b760b1922e821d7bb0150b86ca3c2ef6c488cb0558db9581f6878db9eee7770d54a44eb68ee6d8246094424d4fec67a39b47d9f104304a3b4f6fc14a62cde84af3d0aad455d49ce4c03b113710a419bfa7cee4ddce355601e9dea0120b1c153e35483dd78b2748f73c94d5503946f75f7a46c0f9e35e278b94ffb4332a65408c30859b6712bae071711edd6331756f3fb3e43c4bf13a4d0c3c6c103d4ea72d5c7049e1d3ca1390ecc553d25d9f7061da82e683eb00d9e0c0a3540d6c80cbe5c819f6e789b51e0fc64bfef893c1eae4f0a7f22ef76b440df7aa5849af3e803ee5a27671ec3717b5daa80632b341c0ccce5ebe4c1e7cbf1c64651c2cdf021eafa0ea95d12b5bc9d835ef8e6cfa798043d1a896ba71eabf5946d50253082cf0da1e2d0079969b9f064796d9a380e0b2f74b21beae8247a6e0df68c63e0df8839916a36c4cb05a42c0fb07341eeea993103cfcd5ce919c4c14adee174ce765a0a4633a88dffca75f7747d8afeef4d2a0fc84dab64aaf8293b967a0b808fdf99e83a5212e36b6f543ffedbd5f90894b347d3e10c2ab64579cf034bf358760823a84b194dab93af9b8e8cbcbdf4bf477c19f0a75a55cd6e51024f3cc434d6e5f23b4feb624da3695c81da886fa4", "6", "-36b78125a7de8ebce67e83a532f4e94abc2d1fd3f8f986b98831edefe5e26c07e70f243a534c9fdff93f4465587e52eb6dea26300f0add82c648ba0875eec0542e1b28f0bbdb12232c15636e5607da1e36e7bb9ddc3552913ada3b9b6091825109353fb19e8e6d1f67c410c128ed3dbf05298b37a12bcf42ab515752739300ec44dc429066fe9f3b937738d55807a77a80482c7054f8d520f75e2c9d23dcf2535540e51bdd7de91b03e78d789e2e53fed0cca9950230c2166d9c4aeb81c5c47b758cc5d5bcfecf90f12fc4e93430f1b040f53a9cb571c127874f284e43b3154f49767dc1876a0b9a0fac036783028d5035b2032f972067db9e26d4783f192ffbe24f07ab93c29fc8bbddad1037dea96126bcfa00fb9689d9c7b0dc5ed76aa018cacd070333397af93079f2fc71919470b37c087abe83aa5744ad6f2760d7be39b3e9e6010f46a25ae9c7aafd651b54094c20b3c36878b401e65a6e7c191e5b668e0382cbdd2c86faba091e9b837da318f837e20e645a8db132c1690b03ec1cd07bbaa64c40f3f3573a46713052b7b85d339d9682918cea237ff29d7ddd1f62bfbbd34a83f2136ad92abe0a4ee59e82e023f7e67a0e9484b8dadbd50fffb6f57e42252cd1f4f8430aad915e73c0d2fcd61d8208ea12c6536ae4ebe6e3a32f2f7d2fd1df067c29d695735b944093cf310d35b97c8ed3fad89368da572076a21be900", .Okay}, + {.Shl, "9047764293d698f0b33dc9ca107024c099b9fb776e542da23a72ff72bcbd39ad6e2c6aa89f28368b66aa91b510dd68d8fd007d1ad177b84f3c5d7ebb429c9eafcc4da8cc30e8259f1884cb17a8d71067ebaf7822d32788d1a23e497a9ec698ae4df63a72df08bb1e5a365dddd1d914333d659b3859f0821c2730a05adf1f73eba2534614fcca8ac004d25115345e270da3d78d9035a40cb1615c8185a10c9e30612e7819072789cf57df45e3bc99d72dd7ed301493433be0605c7d63b801a689330b02b62b2eb949b4c84cf1bdefa0b52183611d4aaf13afe1758d94b3fa07f1fa254f3f42557fd27523dea309dc01f3b3026d63eb5e41e11a6a725ca44ec14a23c456089692d00482029f7f3dea22581cde4513f994cac615504cf9b31e0a13ce93b4050d165a1ecf60f6e7788d5847c7dc4bedb576fba1270e70ab2263b99f61ae022e815aac051982aa8fd3caa36c259453c97a6166ba75fcc5e396d1ffddf202359423b4183157ebb272cd0e9f6c7bdd0dd15876aea78871b712b32766fae73f8d9257c0ffe0a1a1011b94b30c907ae68bd3c38a292e0840846a03357b7bc953130620e8033049153cbc29cc70f28f193332e171aa7690099553d404a43d225573629efe142034d00c06e224424ab4331f8dd086389d32d6de6fa9cf8aca439a3aec1ea2ffce7fb8e8faebc060206570f27460b6d5717fa5cef55d7c7cb4", "29", "1208eec8527ad31e1667b939420e049813373f6eedca85b4474e5fee5797a735adc58d5513e506d16cd55236a21bad1b1fa00fa35a2ef709e78bafd7685393d5f989b519861d04b3e3109962f51ae20cfd75ef045a64f11a3447c92f53d8d315c9bec74e5be11763cb46cbbbba3b228667acb3670b3e104384e6140b5be3ee7d744a68c29f995158009a4a22a68bc4e1b47af1b206b481962c2b9030b42193c60c25cf0320e4f139eafbe8bc77933ae5bafda6029268677c0c0b8fac770034d126616056c565d7293699099e37bdf416a4306c23a955e275fc2eb1b2967f40fe3f44a9e7e84aaffa4ea47bd4613b803e76604dac7d6bc83c234d4e4b9489d82944788ac112d25a00904053efe7bd444b039bc8a27f329958c2aa099f3663c14279d27680a1a2cb43d9ec1edcef11ab08f8fb897db6aedf7424e1ce15644c7733ec35c045d02b5580a3305551fa79546d84b28a792f4c2cd74ebf98bc72da3ffbbe4046b2847683062afd764e59a1d3ed8f7ba1ba2b0ed5d4f10e36e25664ecdf5ce7f1b24af81ffc14342023729661920f5cd17a78714525c108108d4066af6f792a6260c41d00660922a79785398e1e51e326665c2e354ed20132aa7a809487a44aae6c53dfc284069a0180dc448849568663f1ba10c713a65adbcdf539f1594873475d83d45ff9cff71d1f5d780c040cae1e4e8c16daae2ff4b9deabaf8f9680000000000", .Okay}, + {.Shl, "f6ceb8132cd090c2d398a718202719b7f759b9b369bfeea8e8623f8422b10eaac08f11845e231efa51ad11d86d8e4e8b33e3ef2caac9fadcff6f094a283a7ae66c7067f96d5050933c277d24c4800a7842a6fae40bfc02c3e22945764fbdbdf9c9fc3867d385c960bac7087a0c4724ce46a671cce7e9f7d0006c44e31291c919d8c9482f7733a7f2a9a6fe5a89ed9ee5f2a44819b2adc8c54d8d6d5b913c69e8d6a5bbdf291366c036dab035301808466d69270720b896e5ab5fae504601dd69b132ef4893e88281dd81132b421892c4f4db4e192513e43769b62a7cbced9419b6b730ca7b08d9e36820c6fa9bf7709134bc85ce2e83b36f1898d52dd24870f0df83ac7fd8dd918f1bc9c95b7911ec815e5e3ba4c2221a39f3fbda556a74527cb279b94681ae430774968f51dd59ed96f02c73c56596924af5cc9cc09ea55d2175ba7046d99097e99bfcafd1eaf6822c38aacb0d626b9cf3e7ce0e9fa7aa12105b17c68420ea11ec9a19e04d65edfb1576d0fb4f0268973f510c87dfc57309bb580bca501814d5c53dd70fa2eebbe5c71644e7a042c3b753cce97b03eade7f894d2306cee7ddd678ef53eb905378f6589ef357d47a42f2743234bc42b01251b71ea94acc11201f7b507a01c5f96187d45fb4b406e11c160326767dc8bbc1acbbd913d00a4a9c698a86fb99037ae70b84f3665a0e16bfcc84cba461515674b545", "60", "f6ceb8132cd090c2d398a718202719b7f759b9b369bfeea8e8623f8422b10eaac08f11845e231efa51ad11d86d8e4e8b33e3ef2caac9fadcff6f094a283a7ae66c7067f96d5050933c277d24c4800a7842a6fae40bfc02c3e22945764fbdbdf9c9fc3867d385c960bac7087a0c4724ce46a671cce7e9f7d0006c44e31291c919d8c9482f7733a7f2a9a6fe5a89ed9ee5f2a44819b2adc8c54d8d6d5b913c69e8d6a5bbdf291366c036dab035301808466d69270720b896e5ab5fae504601dd69b132ef4893e88281dd81132b421892c4f4db4e192513e43769b62a7cbced9419b6b730ca7b08d9e36820c6fa9bf7709134bc85ce2e83b36f1898d52dd24870f0df83ac7fd8dd918f1bc9c95b7911ec815e5e3ba4c2221a39f3fbda556a74527cb279b94681ae430774968f51dd59ed96f02c73c56596924af5cc9cc09ea55d2175ba7046d99097e99bfcafd1eaf6822c38aacb0d626b9cf3e7ce0e9fa7aa12105b17c68420ea11ec9a19e04d65edfb1576d0fb4f0268973f510c87dfc57309bb580bca501814d5c53dd70fa2eebbe5c71644e7a042c3b753cce97b03eade7f894d2306cee7ddd678ef53eb905378f6589ef357d47a42f2743234bc42b01251b71ea94acc11201f7b507a01c5f96187d45fb4b406e11c160326767dc8bbc1acbbd913d00a4a9c698a86fb99037ae70b84f3665a0e16bfcc84cba461515674b545000000000000000000000000", .Okay}, + {.Shl, "-4c25fe08d1d1b57e3540ab73377aa3f126428f1bc55482411ad83bee26353b3668fe271aa50c0b3a87b35fa48a69772771267dad37ee18b6cec0c0ceb50ddee6f63c17476c263ca0808a411db94a12cfd697c6646a6e574bbd653878d11afaf22e495c300a75c2a1b1ca6f5ad1a3dfaa1aae709cbd2b33e9b4a887aeb924cdb72f600d650edf1475a35f07bf9013370e6f384695e50b304ea30156c8371077c634a7439de20c776a6aaf849ac443da5f201b249d27267fb47593d28ec0d86b6bf54106a7c89d3133deb25cb609ddbb5de59dad748dbf38f1eb340439fdec087434cea189646a99f3d0fcd9e144627deefa479b0143392344da2c2d429dd67a48da17ef470d415350d09f9c9e111a5d43aca2bac0e1d71a11988e7da8bb301ab226540f3b0949b0b20c81a9bd0736d88ed2c6594e015b0a6f8732a5ec877ea6cb73cce9249ba0dc6d7ca2b38531551a9c775c4a1b0862f04a356658afc481ccdec389d7aea17947edc3efec30cdc2568da3ab71461da6b096cb26471fcda9fbf888736a84ca9806525bab9034fcc02fc539ba837775ee9561bc5b7d3776521449e8e24f0ac2ce606bbbff8283bbedde3fd1aa1ce31b8eabb5840d571d579076c189719344c45da3c44470eb369ce6aaaa242c36c8bb7a5c44538850a768bab04b17f3a59d8c25f1dcd4616939ae6d1926051f1e234a156947a276524250324b74", "1c", "-4c25fe08d1d1b57e3540ab73377aa3f126428f1bc55482411ad83bee26353b3668fe271aa50c0b3a87b35fa48a69772771267dad37ee18b6cec0c0ceb50ddee6f63c17476c263ca0808a411db94a12cfd697c6646a6e574bbd653878d11afaf22e495c300a75c2a1b1ca6f5ad1a3dfaa1aae709cbd2b33e9b4a887aeb924cdb72f600d650edf1475a35f07bf9013370e6f384695e50b304ea30156c8371077c634a7439de20c776a6aaf849ac443da5f201b249d27267fb47593d28ec0d86b6bf54106a7c89d3133deb25cb609ddbb5de59dad748dbf38f1eb340439fdec087434cea189646a99f3d0fcd9e144627deefa479b0143392344da2c2d429dd67a48da17ef470d415350d09f9c9e111a5d43aca2bac0e1d71a11988e7da8bb301ab226540f3b0949b0b20c81a9bd0736d88ed2c6594e015b0a6f8732a5ec877ea6cb73cce9249ba0dc6d7ca2b38531551a9c775c4a1b0862f04a356658afc481ccdec389d7aea17947edc3efec30cdc2568da3ab71461da6b096cb26471fcda9fbf888736a84ca9806525bab9034fcc02fc539ba837775ee9561bc5b7d3776521449e8e24f0ac2ce606bbbff8283bbedde3fd1aa1ce31b8eabb5840d571d579076c189719344c45da3c44470eb369ce6aaaa242c36c8bb7a5c44538850a768bab04b17f3a59d8c25f1dcd4616939ae6d1926051f1e234a156947a276524250324b740000000", .Okay}, + {.Shl, "da4b74ccc13222a793cc51730220f7bb7d5894f551a92b32be8bb5947de60a16819e6b92d9f1946b836f54c3ddaf9cc65ea124f245243ebdad8f8cd6e3c2c63a7e275f901e01ea4b598348ab34a7d3ad7069177da250c8a5e4801e18b4ea2606c58e6fd689451a2d52913cadb12fc4f363a5df978c9647715c5ac80b2f277e5ada88f493a41e3de42d76f94d203b4ef81338b8a1c4cea0d974a27f1aeb36d7184edb4b385c977d98569af6cac797659567670ba21afc8f0ccf4f9ee4ea8ed6f5d9ce2e21b69e8e4cbb66ccb35a84f875bf28092542bb2ad388157373a864a43c0e98e3e6bd43620324b6249c623fb0e4516079f36bca266d99842d8a729c91329f8a3a7ddcf86934828bf86143462723a13c2a1f3a610b6e1694a2a098a7b7d8cb3b1e6cf0ef3e755c41e3684113d881dda8f3b6158e6fd2f780e6fb6509efa5785620d0070a9c5e5a96f6fbfaf7deefa500e6b14a37d3867c1776b4d243cf7c3624d5766189a0bb7f96c565bd43aef92f0d720285dcad51d758cba2ab13259558930be0b2768d5bd04959ce91e40f6443b441806c57d258b948b3a56f5e30d253ff4b8bcc5328a19e5c1d355bbbbd40d5c59cebdd299dfaece869e1548678e78946587197ca1423930becaa5137e62f3823053fe235de1b87650c663eb2bcbb7c54072e15a305be0ba9081275d86019755cf0086600dcb59917f8321824621c", "0", "da4b74ccc13222a793cc51730220f7bb7d5894f551a92b32be8bb5947de60a16819e6b92d9f1946b836f54c3ddaf9cc65ea124f245243ebdad8f8cd6e3c2c63a7e275f901e01ea4b598348ab34a7d3ad7069177da250c8a5e4801e18b4ea2606c58e6fd689451a2d52913cadb12fc4f363a5df978c9647715c5ac80b2f277e5ada88f493a41e3de42d76f94d203b4ef81338b8a1c4cea0d974a27f1aeb36d7184edb4b385c977d98569af6cac797659567670ba21afc8f0ccf4f9ee4ea8ed6f5d9ce2e21b69e8e4cbb66ccb35a84f875bf28092542bb2ad388157373a864a43c0e98e3e6bd43620324b6249c623fb0e4516079f36bca266d99842d8a729c91329f8a3a7ddcf86934828bf86143462723a13c2a1f3a610b6e1694a2a098a7b7d8cb3b1e6cf0ef3e755c41e3684113d881dda8f3b6158e6fd2f780e6fb6509efa5785620d0070a9c5e5a96f6fbfaf7deefa500e6b14a37d3867c1776b4d243cf7c3624d5766189a0bb7f96c565bd43aef92f0d720285dcad51d758cba2ab13259558930be0b2768d5bd04959ce91e40f6443b441806c57d258b948b3a56f5e30d253ff4b8bcc5328a19e5c1d355bbbbd40d5c59cebdd299dfaece869e1548678e78946587197ca1423930becaa5137e62f3823053fe235de1b87650c663eb2bcbb7c54072e15a305be0ba9081275d86019755cf0086600dcb59917f8321824621c", .Okay}, + {.Shl, "-f4a609d2545509591a3b5cc5efd4fb1fe667a7c818ae6756ecb407894dfa8304ca06f0711d1ceecd5c176035873bcf0e7d0b77b7e329fd1162449baf45723db2b3c15a1a2100952932fe94962f77a78dd1f736e8f16d012e530c17ed84881cf0c8a45445dbb371e6f21d38302a5c32b4eb10b5f7c513695db08139af90e9faa70af4fc77e8f1a6a820092872c4bb477069004dc31a2327f183ded3b00ec0afac93316a07630a1cdc7c2c6a04aa2e2403027a3bfcbe762f966112ba97231ba39d3375e3c8d153b07bcb14d4b364549991e89885c8213b9b5bbab0bec232ec63b168a044a84e91ee25697ed2f4f341a087ebb145fcd56261e6694584dcfff291a3ef7e38a264a621509d68bf61e6780d105d637b3ce3f3626cd9b4e33aad681d9946ab661876c14b4268648cee9dc44b21c19202be3f04a6671b4e39e41050bbc57d33c233567d7145b89ad6764d5e12d0d447daafc5cce7290d73e1e21dd00b794575768b35fdedff8f833bee666f4aea58870c6d3a4b6adfdb645f7544b5988ec2f71d2a5a57133e1f22754ca563cf3f968b5f13430607f351f737a430fcea949111eca00ea37625f4f23fbf3387a673c3a248b47a368c6201be9068b5173b5bd000533f6f289cf336e279bac5649b099e3e5cfaaca8924c2fce8c91f2999c43c1d2a55d9a583ffed8c2096d9e8e889fe2b9285447d11e53ccb2d3f9e8c7276e", "67", "-7a5304e92a2a84ac8d1dae62f7ea7d8ff333d3e40c5733ab765a03c4a6fd4182650378388e8e7766ae0bb01ac39de7873e85bbdbf194fe88b1224dd7a2b91ed959e0ad0d10804a94997f4a4b17bbd3c6e8fb9b7478b6809729860bf6c2440e7864522a22edd9b8f3790e9c18152e195a75885afbe289b4aed8409cd7c874fd53857a7e3bf478d35410049439625da3b8348026e18d1193f8c1ef69d8076057d64998b503b1850e6e3e16350255171201813d1dfe5f3b17cb30895d4b918dd1ce99baf1e468a9d83de58a6a59b22a4cc8f44c42e4109dcdaddd585f61197631d8b45022542748f712b4bf697a79a0d043f5d8a2fe6ab130f334a2c26e7ff948d1f7bf1c51325310a84eb45fb0f33c06882eb1bd9e71f9b1366cda719d56b40ecca355b30c3b60a5a1343246774ee22590e0c9015f1f8253338da71cf208285de2be99e119ab3eb8a2dc4d6b3b26af09686a23ed57e2e6739486b9f0f10ee805bca2babb459afef6ffc7c19df73337a5752c4386369d25b56fedb22fbaa25acc47617b8e952d2b899f0f913aa652b1e79fcb45af89a18303f9a8fb9bd2187e754a4888f6500751bb12fa791fdf99c3d339e1d1245a3d1b463100df48345a8b9dade800299fb7944e799b713cdd62b24d84cf1f2e7d5654492617e74648f94cce21e0e952aecd2c1fff6c6104b6cf47444ff15c942a23e88f29e65969fcf46393b700000000000000000000000000", .Okay}, + {.Shl, "-26ba3eefde45fb86a09484bb9d06254ce862f9518781946c52a91e702358c7f9901fc68d2e8ec464cecc98b701bebe97b90fb393f872be1ac23fd2ef53fa66d9cbbdfedd80d5c87ba4442f64cb50e8cef6065c84cb1ccc552c90f02cda416d409bb295361c44a47102af0c1646a76f399543a52bb69ccabe8abe16a318c44d3855657e5a58ffeb8f24dcf9c4ac6204e7d3cf09af1b3d63ce3cb0588a707eb1cad3ef83e7deda620b325a1c905103e3d83dca701c72a895225708dfc215bd4b9c1002b903153009b7f46ef7edc68c8f5529cfd1a8f87d0d725fd25eae79798a43f54f37907d926530bf276fe13f8f9d64e8cf89dcd0c66504cc535aab27fe8637441d1e75d61dbb8cb9200e7e28bee4531c171db348747d89f691f1d5d3dcb0d7395e3831f2de4ba614744e258a37db11c4e886415e148ac3c5e3216ebac54ff30ba2a8c1d2fc1ada54d79ac8c93dc506921d04d1a94f1e206cd03cff0da23890384de4a66758e949863a9894329ce549f4ccdac231f71b9a27fa57028d8ce0ca678937d678d2f81fe176eb2c05813ee64d5a8f283aa87a863acae3f0668a62e88596d0a064160e1146474ad1acac302c022e51df0ded7b2db369c3d15e0127147510379b98eed6f446a1c798fba113e808d0024563552590478690d10526ba4009850130a313c2082cc8118bee7cab695a60577e89da38f9d1033187f340098d", "21", "-4d747ddfbc8bf70d412909773a0c4a99d0c5f2a30f0328d8a5523ce046b18ff3203f8d1a5d1d88c99d99316e037d7d2f721f6727f0e57c35847fa5dea7f4cdb3977bfdbb01ab90f748885ec996a1d19dec0cb909963998aa5921e059b482da8137652a6c388948e2055e182c8d4ede732a874a576d39957d157c2d4631889a70aacafcb4b1ffd71e49b9f38958c409cfa79e135e367ac79c7960b114e0fd6395a7df07cfbdb4c41664b43920a207c7b07b94e038e5512a44ae11bf842b7a9738200572062a60136fe8ddefdb8d191eaa539fa351f0fa1ae4bfa4bd5cf2f31487ea9e6f20fb24ca617e4edfc27f1f3ac9d19f13b9a18cca0998a6b5564ffd0c6e883a3cebac3b771972401cfc517dc8a6382e3b6690e8fb13ed23e3aba7b961ae72bc7063e5bc974c28e89c4b146fb62389d10c82bc2915878bc642dd758a9fe617455183a5f835b4a9af3591927b8a0d243a09a3529e3c40d9a079fe1b447120709bc94cceb1d2930c7531286539ca93e999b58463ee37344ff4ae051b19c194cf126facf1a5f03fc2edd6580b027dcc9ab51e507550f50c7595c7e0cd14c5d10b2da140c82c1c228c8e95a359586058045ca3be1bdaf65b66d387a2bc024e28ea206f3731ddade88d438f31f74227d011a0048ac6aa4b208f0d21a20a4d7480130a02614627841059902317dcf956d2b4c0aefd13b471f3a206630fe680131a00000000", .Okay}, + {.Shl, "-7f313f06a209b17060aea372ab2699acf666882d918821d1ed00c7ce12b8772c4919c9c998ff5969ba7ca0d99da928ba5ee2583b0d9863f1caf9271f59073a3e7722d1438b2eed712bb4d92b9eda34dda9a8ebe518b7e0e8f5eae942c4ae88c15fee1247bfc209c9803477024d2a92bd841e1aed564540224a8f50117d291439ab87c6149490938015c48d239dc462fbc0f50eac06dbd54f66d0fb920798afc64d4e288bdb14f241fe103ff37de173932f9ea96d36fbeb79a678ca3c586b916f7d29de9160e2a06e05b663d7abee408f0f7fb017c96c3f1b5b013e10585a21413133be0ae696f6e3ca715b9f9b1018c96f82312ebf94368e27e14238a8f3828b59141f47b0cc8496ac110a51082d19528cfca73a172b8506fbc260679b31dfc68e366148f2ccf6baf7b079c778bd126cc28f5f394bdb133730035a06594d965265cd5ba6d5e01e5420ae5a6a2758624cb9265867ff66b727a138d879fb9ed1599a6314a6f32f93221f9c21067d234f6328a856ad65554d71f76154b2716f4a78b7096007b837bafa5289c5cd95bb0824c00d28dbf804a091a7c68cfd1a2097e9faf40017690402a5e3b0dee5ba064d0d7f580b4f81614bdc14c8a5a91928ff0f258078f344d66b259235c4bf4127fdb430852f17fdffa3a759ca9316ea6ae836ba9739542b3455636f3eafe45af38f1008021ad2bd37259b2768647dd119d44", "52", "-1fcc4fc1a8826c5c182ba8dcaac9a66b3d99a20b646208747b4031f384ae1dcb12467272663fd65a6e9f2836676a4a2e97b8960ec36618fc72be49c7d641ce8f9dc8b450e2cbbb5c4aed364ae7b68d376a6a3af9462df83a3d7aba50b12ba23057fb8491eff08272600d1dc0934aa4af610786bb5591500892a3d4045f4a450e6ae1f185252424e005712348e77118bef03d43ab01b6f553d9b43ee481e62bf193538a22f6c53c907f840ffcdf785ce4cbe7aa5b4dbefade699e328f161ae45bdf4a77a45838a81b816d98f5eafb9023c3dfec05f25b0fc6d6c04f84161688504c4cef82b9a5bdb8f29c56e7e6c406325be08c4bafe50da389f8508e2a3ce0a2d64507d1ec332125ab044294420b4654a33f29ce85cae141bef09819e6cc77f1a38d98523cb33daebdec1e71de2f449b30a3d7ce52f6c4cdcc00d68196536594997356e9b5780795082b969a89d618932e499619ffd9adc9e84e361e7ee7b4566698c529bccbe4c887e708419f48d3d8ca2a15ab5955535c7dd8552c9c5bd29e2dc25801ee0deebe94a27173656ec20930034a36fe01282469f1a33f468825fa7ebd0005da4100a978ec37b96e8193435fd602d3e05852f70532296a464a3fc3c9601e3cd1359ac9648d712fd049ff6d0c214bc5ff7fe8e9d672a4c5ba9aba0daea5ce550acd1558dbcfabf916bce3c4020086b4af4dc966c9da191f7446751000000000000000000000", .Okay}, + {.Shl, "db486cd755c998359af7e9955fd7b60cd726be733eac9dd4b37e09177488a2418bb70a7b087162a5382483fb25a4373756f7d0e45f8fb6edf972450e1612d21ab19a4c47f4a16456e17d099cf1adfe5709b0b423700accc7af76a928dfeec12625a760b28731bb2ca882945f9dd89dfe5b18e629cdbaa4b5cb41abe0bfd3b25c91fb3c0eecbbdf64f47e8d48b80af0bbb3214d3e378250720b9b9ab6f1a9791d3eeabda63699fea9404617fb66fa731ca025cc20944c1ab6766afdd74a252e93e0a94c03c0bb3db94d5d0e5ee8b103b5b83147f1c5c4a68fb68343efbb06bfd123b27f071dbc3f8468d4a7bac89f4c6e583ff786517e9377a052739137f1d2c9fb8e77b5854ccd8e57b934b222e0ad32a563cfce527c888dd27f5e995b14f970c5e478845d24be43ce6b75474fb508d617b22aa718897bde733bc29b856c65bde446a81560974bec2f89429f05e74aaf71074040916863181fb9a2618e54eb0068de94fe45e794db0ae7caf574f196c7d2bac60135510338f7d430d226257161017173bd6181a5772e4377a1071241b66d9de9f2ab380dd0df03754660ba9f2cdc244d1e75341e780dc44478b2a12adc74a2f7b8a54c3c7638252f03aca808bd8ad4427677e0808bcaaefbb268cb7c8075751ca7a68edd10aab23eea40b521f829bbca6ffa3806f8c71dfeeea8c1b8c82ac27411aaa99036d776424bfe6e22da", "2e", "36d21b35d572660d66bdfa6557f5ed8335c9af9ccfab27752cdf8245dd22289062edc29ec21c58a94e0920fec9690dcdd5bdf43917e3edbb7e5c91438584b486ac669311fd285915b85f42673c6b7f95c26c2d08dc02b331ebddaa4a37fbb0498969d82ca1cc6ecb2a20a517e776277f96c6398a736ea92d72d06af82ff4ec97247ecf03bb2ef7d93d1fa3522e02bc2eecc8534f8de0941c82e6e6adbc6a5e474fbaaf698da67faa501185fed9be9cc728097308251306ad9d9abf75d2894ba4f82a5300f02ecf6e53574397ba2c40ed6e0c51fc717129a3eda0d0fbeec1aff448ec9fc1c76f0fe11a3529eeb227d31b960ffde1945fa4dde8149ce44dfc74b27ee39ded6153336395ee4d2c88b82b4ca958f3f3949f2223749fd7a656c53e5c31791e2117492f90f39add51d3ed423585ec8aa9c6225ef79ccef0a6e15b196f7911aa055825d2fb0be250a7c179d2abdc41d010245a18c607ee689863953ac01a37a53f9179e536c2b9f2bd5d3c65b1f4aeb1804d5440ce3df50c3489895c58405c5cef5860695dcb90dde841c4906d9b677a7caace037437c0dd51982ea7cb370913479d4d079e0371111e2ca84ab71d28bdee29530f1d8e094bc0eb2a022f62b5109d9df82022f2abbeec9a32df201d5d4729e9a3b7442aac8fba902d487e0a6ef29bfe8e01be31c77fbbaa306e320ab09d046aaa640db5dd9092ff9b88b6800000000000", .Okay}, + {.Shl, "-c182a2dabce0ebba4cc31488cfb12c50c460a9796ba8b6dfd04ab8ff81c322270e241d7cd919e8ee8a1b76440e297def735cbdc1cc7227d9b9d3b5acce7fe6f4c68c13bfc647c8721e60a5b653116e33ae640e049dbd378006fbb45139b625d4f6f9e90c09428184574a0aac5ebf79c3379145ebf6d56e7016f460f36952f7d7460e7697abc309eb735ae48bcad3f5604368dbc50506d3bb7f9b445f89b384813f80addd0284f86e4459dee9d565308f4e57079bd7229884802f9e755423116a75b8386f126be83eabd4142b969f2576a500540247d8b434caff08278ae001577ad3a04f0d9541171bf7e0ce7c9deb4fc1e31fe1aa41d68d6cf55a36f81fe81b52cf6b4214433e67a5312c604d8a6a08268ed36b260c9579964999c2f85ec980726685840093e90a6efeb8432fa5ce8329fa79700b61d46b698443fd2d8e695441f84f482901c0e1f234185e12378f6e6f3ad5b40d35a86ad379779194c04c60cd137b008c41490d5d9f502d6b0de13c5c7dd79097507bcdf2d2ad5876dd9879d8f0c033c26c2ef68a98f7200750345309a1cef6f443870f5f3b3bd2f5fb9217d5c4fcfd65dcb5c57b41c5c996d9f310d3718923738610d68d238d81684a49e1d0f307e27932e1d589ab91c2f636504be5201935dd2499d8210d8a8495b62a2cef07b9c04be8ba4ae7f7e96093c452050c9f1d8fa85ca129fb02e9f767ad46e8", "34", "-c182a2dabce0ebba4cc31488cfb12c50c460a9796ba8b6dfd04ab8ff81c322270e241d7cd919e8ee8a1b76440e297def735cbdc1cc7227d9b9d3b5acce7fe6f4c68c13bfc647c8721e60a5b653116e33ae640e049dbd378006fbb45139b625d4f6f9e90c09428184574a0aac5ebf79c3379145ebf6d56e7016f460f36952f7d7460e7697abc309eb735ae48bcad3f5604368dbc50506d3bb7f9b445f89b384813f80addd0284f86e4459dee9d565308f4e57079bd7229884802f9e755423116a75b8386f126be83eabd4142b969f2576a500540247d8b434caff08278ae001577ad3a04f0d9541171bf7e0ce7c9deb4fc1e31fe1aa41d68d6cf55a36f81fe81b52cf6b4214433e67a5312c604d8a6a08268ed36b260c9579964999c2f85ec980726685840093e90a6efeb8432fa5ce8329fa79700b61d46b698443fd2d8e695441f84f482901c0e1f234185e12378f6e6f3ad5b40d35a86ad379779194c04c60cd137b008c41490d5d9f502d6b0de13c5c7dd79097507bcdf2d2ad5876dd9879d8f0c033c26c2ef68a98f7200750345309a1cef6f443870f5f3b3bd2f5fb9217d5c4fcfd65dcb5c57b41c5c996d9f310d3718923738610d68d238d81684a49e1d0f307e27932e1d589ab91c2f636504be5201935dd2499d8210d8a8495b62a2cef07b9c04be8ba4ae7f7e96093c452050c9f1d8fa85ca129fb02e9f767ad46e80000000000000", .Okay}, + {.Shl, "bc3a12c87a6014d6c9218cbc8d7f484d8775ef999c9b1d5e87ee49011fd23bfa3ffa985cff071dbc234a68dde82bbf8586be647027163e7927b6816560017b2464412926e3374b50e7e2ac9f3edfdad164e6d19cac73240e0f66c08cb6106c74195f33697dd4002a1955e06be11eec16a26c2bc5ba0aeecff00b3ef4f0458c2d0ffef9f5c3428ee6dd1ed197d9b82b0d00781357969b59a96732b57a637d99cf3de8afcdf7bf16ae0c1e4380724f718da37a03759fc376c7cdfe5b86eec79ffe0b06e2db335c1799afe41c63a37ec0cb86e09ae7c80d55c6cfdc2857070bf2e1db9bfc2bbc5098d725d60c3d6b22b52b02ad2caadc4b223a9f9749314b917bc1e8093a3385850796d30c20d6c1f1e0521f9f15008903e89480e9b36e8f1f2de0691c6e1ef6d419cfa71196620b10ffd9cb079796dffe38e9bc6a7835749898a9431e441ad3e9ee31f3f428b1d7d3beb3919173b1d92cbf2cac158ae097b1e6756197bd0e4355246ecbba6b3105739490abb4651e420676a5a82ad819616d6bc5381116de0bcc5c040e9a1fb2aabca37f7ab1138758d6264657f669ed632dc53f997632021d8ee6dc6a97ba6fd2b90aef5e7ac3feb544eb00601eabe7f2fb3f36e0c8457d866befe1600ac57acd338e1e5f63e7192b53db5f4f25578b8d53fc0963511e230f50515a1852bee0ba640c33870cd13d74e9b320f66ea42af56b51c9", "34", "bc3a12c87a6014d6c9218cbc8d7f484d8775ef999c9b1d5e87ee49011fd23bfa3ffa985cff071dbc234a68dde82bbf8586be647027163e7927b6816560017b2464412926e3374b50e7e2ac9f3edfdad164e6d19cac73240e0f66c08cb6106c74195f33697dd4002a1955e06be11eec16a26c2bc5ba0aeecff00b3ef4f0458c2d0ffef9f5c3428ee6dd1ed197d9b82b0d00781357969b59a96732b57a637d99cf3de8afcdf7bf16ae0c1e4380724f718da37a03759fc376c7cdfe5b86eec79ffe0b06e2db335c1799afe41c63a37ec0cb86e09ae7c80d55c6cfdc2857070bf2e1db9bfc2bbc5098d725d60c3d6b22b52b02ad2caadc4b223a9f9749314b917bc1e8093a3385850796d30c20d6c1f1e0521f9f15008903e89480e9b36e8f1f2de0691c6e1ef6d419cfa71196620b10ffd9cb079796dffe38e9bc6a7835749898a9431e441ad3e9ee31f3f428b1d7d3beb3919173b1d92cbf2cac158ae097b1e6756197bd0e4355246ecbba6b3105739490abb4651e420676a5a82ad819616d6bc5381116de0bcc5c040e9a1fb2aabca37f7ab1138758d6264657f669ed632dc53f997632021d8ee6dc6a97ba6fd2b90aef5e7ac3feb544eb00601eabe7f2fb3f36e0c8457d866befe1600ac57acd338e1e5f63e7192b53db5f4f25578b8d53fc0963511e230f50515a1852bee0ba640c33870cd13d74e9b320f66ea42af56b51c90000000000000", .Okay}, + {.Shl, "328d4d9cc1aa4895116d1639165a4b2ed361f2dccd983f72c47b82b45794c3fbe18a917bf1c9027a4ddc4be056099a3c852e4b5814c870fb347bb9c8fbad2582cc5ee363a1ed70927bdda5f2efecdcce17755b4dac5927a70c398e52dc45d3159b3c6019773c403b82a678303771e452c8a25b66579ac5dce4f2ad68c91bbd7a988894536cea9f0f97742f2ccc666f80f6bd8b08829fa936d46d6fe66967d496515004c6e11609f898746dd43a1f54dc21f3704554c042b99113db8dab25daf74b1f5ee5c655af30297714f1e900e430b1ea64011be39cd7552c487f25d1020e142778a9936d17344ee34df928501214537f4169639348e45a7c851abd62c51b8365252c868b49e294f9bda30239f89d221093a4baccfe30d6c078841aa2d2b864fe1dfac8e47e89f6bb982e103e69826f8dca89a6fa10332255c27645cb30113efc8430a1f1d32e327362d9749dd51b8ceeb94d15996d8ab046b131401c451339c5a360432ce3468b18b6dbff21de5895fbbfb3351876833c10bc93a69e1563dd9412f20fb7ecf249efd8ba6ed4de0e888e2d9a7e36e9880cdc2463416ab97ef13457bbe0d996f2368efe0fc13b37eede0bc9d213d17acc630006cfd5211fe367d9faaf7dc9a3bfc1e42546c41924b567975b246ff98f9641cb15313189c2b974c1ce1c888b3a5025de76339f361477b7bfa4b86eefd5934e94abb9464e3a4e", "23", "1946a6ce60d5244a88b68b1c8b2d259769b0f96e66cc1fb9623dc15a2bca61fdf0c548bdf8e4813d26ee25f02b04cd1e429725ac0a64387d9a3ddce47dd692c1662f71b1d0f6b8493deed2f977f66e670bbaada6d62c93d3861cc7296e22e98acd9e300cbb9e201dc1533c181bb8f22964512db32bcd62ee727956b4648ddebd4c444a29b6754f87cbba1796663337c07b5ec584414fd49b6a36b7f334b3ea4b28a80263708b04fc4c3a36ea1d0faa6e10f9b822aa60215cc889edc6d592ed7ba58faf72e32ad79814bb8a78f480721858f532008df1ce6baa96243f92e881070a13bc54c9b68b9a2771a6fc9428090a29bfa0b4b1c9a4722d3e428d5eb1628dc1b292964345a4f14a7cded1811cfc4e910849d25d667f186b603c420d51695c327f0efd64723f44fb5dcc17081f34c137c6e544d37d0819912ae13b22e598089f7e421850f8e9971939b16cba4eea8dc6775ca68accb6c558235898a00e22899ce2d1b0219671a3458c5b6dff90ef2c4afddfd99a8c3b419e085e49d34f0ab1eeca097907dbf67924f7ec5d376a6f07444716cd3f1b74c4066e1231a0b55cbf789a2bddf06ccb791b477f07e09d9bf76f05e4e909e8bd6631800367ea908ff1b3ecfd57bee4d1dfe0f212a3620c925ab3cbad9237fcc7cb20e58a9898c4e15cba60e70e44459d2812ef3b19cf9b0a3bdbdfd25c3777eac9a74a55dca3271d27000000000", .Okay}, + {.Shl, "a09b18347269492b1e76bcdc7102ffd0d87b31ea97fe2a7478e79a10b93836a5dfa9ede4880ffc7770dfe2df5ad13f989f6b2067ca6baa121b650cfd6c64a65dbfffefa7d443c1df0e694e5cfb6c58772baf6a00846c92e1cd9fe7e32c9306db985a8608d55c890eb74a6561c82f03f51ca66cf38fcbf57e4788d6eafa41ffe69b485090939981d9e74b7fb2aca69f7abdf7073c5e7edea04fec22662cb21ac690bd83c23a79fe95e8c7c632ec813f45b96fb5b29bd54255070f69ba22bc45b3a70bb359d8f3c833ee05e9a344f7b3c9474431486f3c89f3dd9ee3802591c668bf4291f6eded2f71963368ebf5fe129d8c84c54d641287b31088c68432bbfa87d8b3aada19d787b2ee5136eab8239d1bd88cc84661d792d65ca2394c1ae4540912af03347b57d439a3f3f3ec23b90baeb7ce76595e55810f6a890a2b95700c2a8a4c5bf8d6c40b42278759cd922c51ace99f267eef55a67b2aa46890271c990041b8de3a9c7c71766bab687c8410b2a8046487b117d9873fd63900e5711de6c60430ab39106a7d1910d0056eeae5f3ab4daba2b1432adf0d2c1109cf880cff13d0de1d8a28062f3459cd7c6d40f237f059a5d251c9a6d971451200c4a77b3ba51adc5dcd3e9ba16525ce27a8cade6136dca6c1d1e41f20206c14c29076fbac65937f7e192d4a50c9e14d8d0d707bf27165ae75d727bd31ee0cdcfe917caff80a", "71", "141363068e4d292563ced79b8e205ffa1b0f663d52ffc54e8f1cf342172706d4bbf53dbc9101ff8eee1bfc5beb5a27f313ed640cf94d7542436ca19fad8c94cbb7fffdf4fa88783be1cd29cb9f6d8b0ee575ed40108d925c39b3fcfc659260db730b50c11aab9121d6e94cac3905e07ea394cd9e71f97eafc8f11add5f483ffcd3690a121273303b3ce96ff65594d3ef57bee0e78bcfdbd409fd844cc5964358d217b078474f3fd2bd18f8c65d9027e8b72df6b6537aa84aa0e1ed37445788b674e1766b3b1e79067dc0bd34689ef67928e886290de7913e7bb3dc7004b238cd17e8523eddbda5ee32c66d1d7ebfc253b19098a9ac8250f6621118d086577f50fb16755b433af0f65dca26dd570473a37b119908cc3af25acb944729835c8a812255e0668f6afa87347e7e7d84772175d6f9cecb2bcab021ed51214572ae018551498b7f1ad8816844f0eb39b2458a359d33e4cfddeab4cf65548d1204e3932008371bc7538f8e2ecd756d0f90821655008c90f622fb30e7fac7201cae23bcd8c0861567220d4fa3221a00addd5cbe7569b5745628655be1a5822139f1019fe27a1bc3b14500c5e68b39af8da81e46fe0b34ba4a3934db2e28a2401894ef6774a35b8bb9a7d3742ca4b9c4f5195bcc26db94d83a3c83e4040d8298520edf758cb26fefc325a94a193c29b1a1ae0f7e4e2cb5cebae4f7a63dc19b9fd22f95ff0140000000000000000000000000000", .Okay}, + {.Shl, "34483afada156a555533f5f65ca40bf61b5afea66c5557e13197d9679fa1ad0fe86547c61f185731878198fdd5b1d6c62dd19f02e03e26a79038af98072fcc412f6a5938b06c00e800674fb1df089572c57f6e6eb8588d9ed982742d16011e9ce245dc7998b19f870b9f0a310e9071be090c2133bac6efe63d49bd57f390c66134cebc3bedf8ca15538729c95f5bf8cf12bce2278cd1de7e2197fccc1de516bcfd0109ad8cc98ba19b96fb9d3f60bfff8098efbf978f4d5142cda1dcd60387c2d0b50d5e990956886ad553b471f6797847eb771278ae5a81ae085d663d6734a57677cbaab241fa48d0fc801d302cb4128794a6637dd6eef86124cb65d5a3252d679925cbe1d5f8cfbc764e47648f9609cf76e55b30064bc437aa5f1669a9160e2f3e670fae3fa6c43e3aab509066e644c59b5c39ac56f283f7f489fef55a0e7cedcb3c2cae0fa3a11ae673d805ecdaa018eafbc5c46ee83c752cd12eabf5cb4278e46cba0deb2a3a89fe5ca1f3d4348540e09e9eea0473a58d7fe7871efd8d930b5fe8b54bce054da1d5d9ad8f6a968f0b229754b9684cb2047ed28d5e7d975c332ed33166ea8e363abfd59a270b891b71e0ad0dd29b3a18c1eb8a5f3d30b406d7230c18e249fd22497977e1e153ef322a2dce510057584fbe8d23079696496151c852095d9901e3db50f5bf08e6e0a72a818cb6b15d19a67a187c41a155b7ee", "4", "34483afada156a555533f5f65ca40bf61b5afea66c5557e13197d9679fa1ad0fe86547c61f185731878198fdd5b1d6c62dd19f02e03e26a79038af98072fcc412f6a5938b06c00e800674fb1df089572c57f6e6eb8588d9ed982742d16011e9ce245dc7998b19f870b9f0a310e9071be090c2133bac6efe63d49bd57f390c66134cebc3bedf8ca15538729c95f5bf8cf12bce2278cd1de7e2197fccc1de516bcfd0109ad8cc98ba19b96fb9d3f60bfff8098efbf978f4d5142cda1dcd60387c2d0b50d5e990956886ad553b471f6797847eb771278ae5a81ae085d663d6734a57677cbaab241fa48d0fc801d302cb4128794a6637dd6eef86124cb65d5a3252d679925cbe1d5f8cfbc764e47648f9609cf76e55b30064bc437aa5f1669a9160e2f3e670fae3fa6c43e3aab509066e644c59b5c39ac56f283f7f489fef55a0e7cedcb3c2cae0fa3a11ae673d805ecdaa018eafbc5c46ee83c752cd12eabf5cb4278e46cba0deb2a3a89fe5ca1f3d4348540e09e9eea0473a58d7fe7871efd8d930b5fe8b54bce054da1d5d9ad8f6a968f0b229754b9684cb2047ed28d5e7d975c332ed33166ea8e363abfd59a270b891b71e0ad0dd29b3a18c1eb8a5f3d30b406d7230c18e249fd22497977e1e153ef322a2dce510057584fbe8d23079696496151c852095d9901e3db50f5bf08e6e0a72a818cb6b15d19a67a187c41a155b7ee0", .Okay}, + {.Shl, "-a282b6aaf5d1951ad244b5ce0ae1928b47e5293c123082b638d19a5d2b3394427a7fc420d013a8efdb7b81d976097da64ee29f0d2a4cf50d0748dd9be68820f5d4ea3a6a5988d907059b79ddfb3910c65293e8acc90661ffe752c7f478e912b82341d9355c3c78d49b4981ebeae458db547f01c1cb05b087c248cdfd02490c16d4c314361e6f5c9703f073c869a396b53cf5ad150b83b3a2ee59540b998ae32e0055a282f2e2cf6ce0f36ed7a0e2372fcbd3fb207b6e47b144a68bc42bacd399c006870c973cacd5167f4b0fc86c146de0b0af699ea226862684ec14efe6441aa47b24f749ac31b957bb665e1031fc1065853d10c48441af8d3418af5e69a75f78fdcb0aa1472b4e897c101c2cb62849b5efbffd28510d37cc64fba443b1c24c1a2002709c8d7d862e6ec47d51bc0ebc23043d49020fe30fc28b6e2025d52f74212b69ac9dba5f6469f5a2093d1ebb7f5d9b2e65e8b03d366e5a9d69ad74854068ef46f705ed440bcf62b0dbc61e0058f1df10866b6fd3b45ed00b702ae62638574f7ddf949d6a2040bbcdab72fc576c1e5201e4a2c11f1de32f2282f18725036234652921d0954912174ead51e48aee97b3556a9a967dd399dbe4aef04ac8c27b5b2744d8683774da45f09cbec3e84a879dbf8d0bbf765abd9430a7d81ea9213dc85d4e71bef04609d8569e31af64386ddda0db2b0994db28710605512620af", "2e", "-28a0adaabd746546b4912d7382b864a2d1f94a4f048c20ad8e3466974acce5109e9ff1083404ea3bf6dee0765d825f6993b8a7c34a933d4341d23766f9a2083d753a8e9a96623641c166de777ece443194a4fa2b3241987ff9d4b1fd1e3a44ae08d0764d570f1e3526d2607afab91636d51fc07072c16c21f092337f40924305b530c50d879bd725c0fc1cf21a68e5ad4f3d6b4542e0ece8bb965502e662b8cb801568a0bcb8b3db383cdbb5e8388dcbf2f4fec81edb91ec5129a2f10aeb34e67001a1c325cf2b35459fd2c3f21b051b782c2bda67a889a189a13b053bf99106a91ec93dd26b0c6e55eed997840c7f0419614f443121106be34d062bd79a69d7de3f72c2a851cad3a25f04070b2d8a126d7befff4a14434df3193ee910ec70930688009c27235f618b9bb11f546f03af08c10f524083f8c3f0a2db8809754bdd084ada6b276e97d91a7d68824f47aedfd766cb997a2c0f4d9b96a75a6b5d21501a3bd1bdc17b5102f3d8ac36f18780163c77c4219adbf4ed17b402dc0ab9898e15d3df77e5275a88102ef36adcbf15db0794807928b047c778cbc8a0bc61c940d88d194a487425524485d3ab547922bba5ecd55aa6a59f74e676f92bbc12b2309ed6c9d1361a0ddd36917c272fb0fa12a1e76fe342efdd96af650c29f607aa484f7217539c6fbc11827615a78c6bd90e1b776836cac26536ca1c41815449882bc00000000000", .Okay}, + {.Shl, "-48fda0d053ae9efef2e89cab5efbe33fed0382e99d01b62ae36dbc4e466f141466b683afd50fd232ec594df262716262c740bfda888616daef08849695d7bd651e54b740e9fc6bc12b6928e1976ee3801dac24798a71166c42002054408aaca7524816fb01e858f54c174003bbf8ce1f2f74bdfdc595cae3f34900ca1d6cbd5ee3c74dd4f628a05fb9bb16fff5eee154b1ff1648759dbc09c19a84448b663a12332ac7840e4b95c0127da9057906d674f244a6b55970d8068c9f3a4177101954b3c0e9d4d70dbbfa9cabee7a61250bcc3511bcf47b88583721cf0e11f0a599e07b1102ec09a06dc6a59f8d8397780139adb6b9be6b1f36a4de1b38fd590d162cbb628de8154d8ed64b1286056a6ae79462384c634eaa3a31b946e0bbf06330f50a5940780199ae1e8b0c65a1359841b379865cc1fd4eb9a56b1c5711a83fc6caf8d04fe2971873b05bf6dfb5db4468ebe8b45a622447e4f0e227fdaa31311f8419acbcd4290ae54d51c3d6a4f9039c0011ff6acd713e1e63a1dbd2a3dd21cdf6a9c0f92559a2a312792b9eaf6a286d8027ed5812f422e629ece68945384358ec6f9f1c7971ff5f02829dadb1681c39f9dfa6215efc440c87e43e38fff6ed73ecb8b6a30328c5b69b047a66cc98f28a3c842fa3921536ba8c74694d89f3215ec329babb1340f73312ab8c250cb71e33f27b4cc8a566fbd9a5ab233b45700f356b", "13", "-247ed06829d74f7f79744e55af7df19ff681c174ce80db1571b6de2723378a0a335b41d7ea87e919762ca6f93138b13163a05fed44430b6d7784424b4aebdeb28f2a5ba074fe35e095b49470cbb771c00ed6123cc5388b362100102a20455653a9240b7d80f42c7aa60ba001ddfc670f97ba5efee2cae571f9a480650eb65eaf71e3a6ea7b14502fdcdd8b7ffaf770aa58ff8b243acede04e0cd422245b31d09199563c20725cae0093ed482bc836b3a7922535aacb86c03464f9d20bb880caa59e074ea6b86ddfd4e55f73d309285e61a88de7a3dc42c1b90e78708f852ccf03d88817604d036e352cfc6c1cbbc009cd6db5cdf358f9b526f0d9c7eac868b165db146f40aa6c76b25894302b53573ca311c2631a7551d18dca3705df831987a852ca03c00ccd70f458632d09acc20d9bcc32e60fea75cd2b58e2b88d41fe3657c6827f14b8c39d82dfb6fdaeda23475f45a2d311223f2787113fed518988fc20cd65e6a148572a6a8e1eb527c81ce0008ffb566b89f0f31d0ede951ee90e6fb54e07c92acd151893c95cf57b51436c013f6ac097a117314f67344a29c21ac7637cf8e3cb8ffaf81414ed6d8b40e1cfcefd310af7e220643f21f1c7ffb76b9f65c5b51819462db4d823d33664c79451e4217d1c90a9b5d463a34a6c4f990af6194dd5d89a07b998955c612865b8f19f93da66452b37decd2d5919da2b8079ab580000", .Okay}, + {.Shl, "-6d5328ff2afca327ff7af474298564fa1a096c58e90fbfefd591934339bcd8a91914e2c6fb29eb340d2d8f38172d47520a0f7f8096e24479af44284f66b646841e31eb9a5f3158bfe79eeb30c43b95b71c1a44b20334fd94a755ed46356eb69fe98cacf183c7636677c6b715bf72347e57e007216a71e1a67566204b741a4cb208596d34327298a7598ade6825060531921ae3b79761978330640f3515261e791c91c3c2c6db6e01366be432cdd1fbbd6c39b5a07e3494b5e8ea92b2f7d880a38f3fb9d6ce452eafb344f6050a97bc2bae274b98f3522828be75656028bd729639bf02954894eaf20ef57d7194bb552b4a50c9ee3688c5d1685f9bce401a4ca84375e7250f0ad812befb723d8e7afe4fcf6e074d5294fd617af8f05bf0ffed43c6011adcbb2704f053f033f7c6e5114f5aaa96a0090d897ec2079c0a94b714c385463c3cd1d71ed251c067b7b0bf37f7a6608544f0d68400b4b386aff8d72d29872ecdbc880d30fa48f4d0c0bed6834344677754dbc2ed9ebcf4de25b278bff0df8dfccec7168e8ef6c6af44bba2c888b7c7cb72438f062e17221f4cfd5e4775091b5a1190dd09054de783a2c49eaa65e8394b417c92f927ad3d9befa004d73d9915b475e2be0b006cb400abe2c72ac74c41eea55e3b61613adbaf37a6dad5b093d8be91042ccb865a910499ded3cf78c9615b27e0a46e010f257d29becb8264", "6", "-1b54ca3fcabf28c9ffdebd1d0a61593e86825b163a43effbf56464d0ce6f362a464538b1beca7acd034b63ce05cb51d48283dfe025b8911e6bd10a13d9ad91a1078c7ae697cc562ff9e7bacc310ee56dc706912c80cd3f6529d57b518d5bada7fa632b3c60f1d8d99df1adc56fdc8d1f95f801c85a9c78699d598812dd06932c82165b4d0c9ca629d662b79a0941814c6486b8ede5d865e0cc1903cd4549879e472470f0b1b6db804d9af90cb3747eef5b0e6d681f8d252d7a3aa4acbdf62028e3cfee75b3914babecd13d8142a5ef0aeb89d2e63cd48a0a2f9d59580a2f5ca58e6fc0a552253abc83bd5f5c652ed54ad294327b8da231745a17e6f39006932a10dd79c943c2b604afbedc8f639ebf93f3db81d354a53f585ebe3c16fc3ffb50f18046b72ec9c13c14fc0cfdf1b94453d6aaa5a80243625fb081e702a52dc530e1518f0f3475c7b4947019edec2fcdfde99821513c35a1002d2ce1abfe35cb4a61cbb36f22034c3e923d34302fb5a0d0d119ddd536f0bb67af3d37896c9e2ffc37e37f33b1c5a3a3bdb1abd12ee8b2222df1f2dc90e3c18b85c887d33f5791dd4246d684643742415379e0e8b127aa997a0e52d05f24be49eb4f66fbe80135cf66456d1d78af82c01b2d002af8b1cab1d3107ba9578ed8584eb6ebcde9b6b56c24f62fa4410b32e196a4412677b4f3de325856c9f8291b8043c95f4a6fb2e09900", .Okay}, + {.Shl, "-58f75577497087d8f4342d711d6107ceb2cf8a4fcdbfab58f33410e366f8349e54fa0638f4a3a4aaeceb21b93cd5a8b0e264202e132335a69a8ebb82a5b88e4c06452455ad375f4c59254c6b610c90ccb3b15a0023893529161f9928bf72bc56aef3e4d05605d89f3a40fbc3d0d02e4c577454fe59885458681b71fa35c0df5e9bd07dd1ceff867ce60d8006ead0f0bfd16eb301b62a023bfe177ebaf502d27fc569ce592ae178a853efc9971c044ec9ecd75aa011ee89805ff6eeb499c5fc6188f966070d060e62bdd9a6d7a5ac5a984ac612db9d9f2fca4b8b66f3db4a15496acf2ae5883f0a5ddd9c7440807a94cc97e51c03c68bf41fbaa80d69c7acf0ab3551e7b7496669c5f071eacbfa08ae5edcb4c22e8e7a5b47b1c5d95ad658d9bf1585333294196a87920a2592496ad7fba197656303a71c0fd4dff8ecf79083f0b9445b1ce253e310d60706acb8a9b6a7af4a4a24a951e8fcb67ae9431be9ec23cf8b0505125a297f79c6f357ccbfd532951f2eb73c23edaa69f999defa89ed86714e52f07101041bceef2069cb02cee3a474446173feb124822118f6588203edf7160131c8996e2f1d8e359f24d9899d4544ccf8ac08981349bc8cb3c4ce5d1e1c716f36ebc205fdd155801ae20d08053d8d0604adeb3be9ac16a55fd86e3fa53a2b3e8d939b73d21533da777d7a80d0cd822e6b803ac98d666128bae1c96916", "32", "-163dd55dd25c21f63d0d0b5c475841f3acb3e293f36fead63ccd0438d9be0d27953e818e3d28e92abb3ac86e4f356a2c3899080b84c8cd69a6a3aee0a96e2393019149156b4dd7d31649531ad84324332cec568008e24d4a4587e64a2fdcaf15abbcf93415817627ce903ef0f4340b9315dd153f966215161a06dc7e8d7037d7a6f41f7473bfe19f39836001bab43c2ff45bacc06d8a808eff85dfaebd40b49ff15a73964ab85e2a14fbf265c70113b27b35d6a8047ba26017fdbbad26717f18623e5981c3418398af7669b5e96b16a612b184b6e767cbf292e2d9bcf6d285525ab3cab9620fc29777671d10201ea53325f94700f1a2fd07eeaa035a71eb3c2acd5479edd2599a717c1c7ab2fe822b97b72d308ba39e96d1ec717656b596366fc5614ccca5065aa1e4828964925ab5fee865d958c0e9c703f537fe3b3de420fc2e5116c73894f8c43581c1ab2e2a6da9ebd292892a547a3f2d9eba50c6fa7b08f3e2c14144968a5fde71bcd5f32ff54ca547cbadcf08fb6a9a7e6677bea27b619c5394bc1c404106f3bbc81a72c0b3b8e91d11185cffac492088463d962080fb7dc5804c72265b8bc7638d67c93662675151333e2b022604d26f232cf1339747871c5bcdbaf0817f74556006b88342014f6341812b7acefa6b05a957f61b8fe94e8acfa364e6dcf4854cf69ddf5ea03433608b9ae00eb26359984a2eb8725a458000000000000", .Okay}, + {.Shl, "13e3cb99f04f87ec00a3c95188bf0b4ae36a0c991470098e6ec765243570d2daf654319dc8c9f5e73cf1eb966c7379dc54130eaeec32071a1b48bac750c41e4681634cc12394b30716dfd452612c53a66ea8c0e85fc901709197606530b40d9620467472e725642b346bab83c356233fdf75d348caa2d5701932cfedef7ba8e6370c6f01f2671417170b61dc4c33b44ecaf8b98dea8b06cd7a20a84abda4906fcf6066b6419a3f844cbd491bf1dad6a5d46804612384055256c1decbf72e6b96bdefbf432bf6a109a8159a805f7b48f53049e478025f486a7d29a1faada61dcd20f7a95076428d454b0a364850cea32f9b2ef2266d3f84c4eecb634bc7b42147bf00d0ea02d8127aea959ccb09e9e0c9a9d66f8a87216e3a910d4196687608148a83ade5d7177682244457c95771f909973f19ee5e6f923f6c154fd07ea2cd19c177e067e08d734a3e86c3c514e8c4c5e90ac19b1d41d6615dbb32149d0292581505f1f7eeaa16257d3ca07f4e208f7dd1f5865f7234c6d01b5475019c055a5fbd1154d71d252778c8d3691c4e96ed9964bad3193ae6e73fbd4f925915cbe6301e60514a22e5be2c425eaf6b175e11d83816e28977e8401fcc97cca585f03d675bf2ae680ad2b7a7db754cfd14c694613ad53900a9aa64d59282a6793f425fd973cac77f6c1e8626a8910528af54d094bbe77190e3bc374dbc25dbab36e324af", "9", "27c79733e09f0fd8014792a3117e1695c6d4193228e0131cdd8eca486ae1a5b5eca8633b9193ebce79e3d72cd8e6f3b8a8261d5dd8640e343691758ea1883c8d02c699824729660e2dbfa8a4c258a74cdd5181d0bf9202e1232ec0ca61681b2c408ce8e5ce4ac85668d7570786ac467fbeeba6919545aae032659fdbdef751cc6e18de03e4ce282e2e16c3b89867689d95f1731bd5160d9af44150957b4920df9ec0cd6c83347f08997a9237e3b5ad4ba8d008c247080aa4ad83bd97ee5cd72d7bdf7e8657ed4213502b3500bef691ea6093c8f004be90d4fa5343f55b4c3b9a41ef52a0ec851a8a96146c90a19d465f365de44cda7f0989dd96c6978f68428f7e01a1d405b024f5d52b399613d3c19353acdf150e42dc75221a832cd0ec102915075bcbae2eed044888af92aee3f2132e7e33dcbcdf247ed82a9fa0fd459a3382efc0cfc11ae6947d0d878a29d1898bd21583363a83acc2bb7664293a0524b02a0be3efdd542c4afa7940fe9c411efba3eb0cbee4698da036a8ea03380ab4bf7a22a9ae3a4a4ef191a6d2389d2ddb32c975a63275cdce7f7a9f24b22b97cc603cc0a29445cb7c5884bd5ed62ebc23b0702dc512efd0803f992f994b0be07aceb7e55cd015a56f4fb6ea99fa298d28c275aa72015354c9ab25054cf27e84bfb2e7958efed83d0c4d51220a515ea9a12977cee321c7786e9b784bb7566dc6495e00", .Okay}, + {.Shl, "-baa2ce077dc3655f54543f90db3dface2f7c3e849e8133bf633eb12f8951457b8bda972c1b187a98402def08b34cc118c262380927ea59c8a005b47d272a5d0721c6be76c6a99fb0c97d49fb1bc2b16c22f2670f91bcc5fb6cbcc164335d394e197aba29a7a5a2a5ec1dd76bb6a131ce72425ff53c66049372f3bd5949a32a1dcaef95d940e3f2cfce1b8237786485fea918ead7850f19affc1d920bf2eb0d64696800f942626d0dc38951d9080e05440f5aba0a4a24c0bac03c6b8d5582c31b81860707785126f956b43f686e6db4039b7d4085197ec809fa1a4731289d4b0bcf152b74e222cf4bf8de252cf5ec4b54089ed19fe9a1a628154421af103a78207f62c25bacbb9ea82c682dfb16340362049e5f9eb09dff3cf5c1a7568c578052713f323458e4a2c30a742170fb5744762c7b02d0bb588e732e307ebf34df2e6798f51bae689f117ab02af4dc64b5dda65b7d3ec83ba81cc0af3221140c6ff056142abc9fe8eed220a8d7d014b167c62b89a4ccc54193528a2766363c2302663eb72e5d086c5ece5bbe333823de74dfbece76b161e32e3583bb9b0c571d296f49890f13a9d60dda06206e86151c9e06f44b5096c724e8b083ad0d28b8da67f04d8974859d702dec9f91b9225029aa3ddb2014ff6d0e282b6a747864fdef58db15407f3e71e35b58fd0890b5348f641cb49bf70a28d32a19f3dbb3e48776c2ce02", "3", "-5d516703bee1b2afaa2a1fc86d9efd6717be1f424f4099dfb19f5897c4a8a2bdc5ed4b960d8c3d4c2016f78459a6608c61311c0493f52ce45002da3e93952e8390e35f3b6354cfd864bea4fd8de158b611793387c8de62fdb65e60b219ae9ca70cbd5d14d3d2d152f60eebb5db5098e739212ffa9e330249b979deaca4d1950ee577caeca071f967e70dc11bbc3242ff548c756bc2878cd7fe0ec905f97586b234b4007ca1313686e1c4a8ec840702a207ad5d052512605d601e35c6aac1618dc0c30383bc28937cab5a1fb43736da01cdbea0428cbf6404fd0d2398944ea585e78a95ba711167a5fc6f12967af625aa044f68cff4d0d3140aa210d7881d3c103fb1612dd65dcf54163416fd8b1a01b1024f2fcf584eff9e7ae0d3ab462bc029389f991a2c725161853a10b87daba23b163d81685dac473997183f5f9a6f9733cc7a8dd7344f88bd58157a6e325aeed32dbe9f641dd40e605799108a0637f82b0a155e4ff4776910546be80a58b3e315c4d26662a0c9a94513b31b1e1181331f5b972e84362f672ddf199c11ef3a6fdf673b58b0f1971ac1ddcd862b8e94b7a4c48789d4eb06ed031037430a8e4f037a25a84b6392745841d686945c6d33f826c4ba42ceb816f64fc8dc912814d51eed900a7fb6871415b53a3c327ef7ac6d8aa03f9f38f1adac7e84485a9a47b20e5a4dfb851469950cf9edd9f243bb6167010", .Okay}, + {.Shr_Signed, "124ed2113dad496f977d6b6b18639f3542ef5898df3b840f460630dd325dc1214cf26e7b16b8820c7784258bdcb2902acc754f441398d1fe97dd1bf8f9a9012dbe408e2af1ccb216357c1017537ec4b7e7efda9eb7aef5608f92c23f4224b18fc4000d16a755f4811771b0c25ce8fdb82c6a3cc20c673a56edbaa758321c9f7ae90316ec74094be66204d8ebbc3a3cccf69abfb02fd11aba1ed31d1d3b0753ef4afd85fe4723820fde281736d00a9ff0a649c9c4ec2ec680dab6bbdc388449f4b5a2d2a927ba91e1e69f62a97fea34541b266f9d77460513f393f649a41c443f0ba01e228cba45c60a026a1f8bcf16c24d22d8a23fff992d4aab135e98ddff05b943e9577e0036ee2567199219632cd23d25a18949f37b7bca2783a928eaa3bd4c0c83653f0475b5992e7edea3e842306968cedf285f290428b31a031a2c427be5bda18e623365c2a6073f0e09c52d9e45d85c0286ac2df2292fd4bd99f7de8d910fe99591810596206ea71247aafaff90ee2df74f5f5bc8ebc54d02a84d53d1cab16b3a86cdd116435993f8617bb4c040760847616114ddca9e3eaac8a7713e1098eec08a46056bafcce99a698e52bac389c6938f4462083dba3cc2edf2213d4946f90fefbab7ebdc9e620133598c3e78006611582fc5a6da9b987c525d95389be45da3d70f9c1105c8072069002d2a27fd6abb06c54b771e177aac29377dda", "74", "124ed2113dad496f977d6b6b18639f3542ef5898df3b840f460630dd325dc1214cf26e7b16b8820c7784258bdcb2902acc754f441398d1fe97dd1bf8f9a9012dbe408e2af1ccb216357c1017537ec4b7e7efda9eb7aef5608f92c23f4224b18fc4000d16a755f4811771b0c25ce8fdb82c6a3cc20c673a56edbaa758321c9f7ae90316ec74094be66204d8ebbc3a3cccf69abfb02fd11aba1ed31d1d3b0753ef4afd85fe4723820fde281736d00a9ff0a649c9c4ec2ec680dab6bbdc388449f4b5a2d2a927ba91e1e69f62a97fea34541b266f9d77460513f393f649a41c443f0ba01e228cba45c60a026a1f8bcf16c24d22d8a23fff992d4aab135e98ddff05b943e9577e0036ee2567199219632cd23d25a18949f37b7bca2783a928eaa3bd4c0c83653f0475b5992e7edea3e842306968cedf285f290428b31a031a2c427be5bda18e623365c2a6073f0e09c52d9e45d85c0286ac2df2292fd4bd99f7de8d910fe99591810596206ea71247aafaff90ee2df74f5f5bc8ebc54d02a84d53d1cab16b3a86cdd116435993f8617bb4c040760847616114ddca9e3eaac8a7713e1098eec08a46056bafcce99a698e52bac389c6938f4462083dba3cc2edf2213d4946f90fefbab7ebdc9e620133598c3e78006611582fc5a6da9b987c525d95389be45da3d70f9c1105c8072069002d2a27f", .Okay}, + {.Shr_Signed, "845a03549a64a4f23ed9312624cd368a84bd66fbd935153ed9bed1bc9f9f1399b24b29ddfa231c2b8c7226d39c08c184b61fef5f6a1401ffcacf7ded6bc9108fe25522d3eb71867aaf2981f3d2e81e0b4af29993194529fcaa6016a54891ceb3a3402b6668d23550ea936b78a71ef61f50d8e4919017f6cc106610fa6d79c65d20688c7039f126b6e08e18aa62fe4b96365973218a3982fb33ebc939613cfe55b6d006f4e4d5f8eeeae523a3490fb2cb68283d1052fcb4ef132f3fcf4755977c7f8daa9e70301330e70cf06ef52d2550c36f928d5438f0c32ca39717020a6846c2dd76bc7b1cf5745927df3fce71a87a33144e2edee9a6ee83b801f1aea99a6bbd971cb58e76475b545c271ffb34d91bb2e45c12b1738fdbef535d64dcfd7699ad15dd3aaacde806b5caa9d500131499aa3509ccd2f130baf308c86b6861334833ceb1afe248dd31de98c4abb8c187bf227d6542ae81bd5bdd7ca05fd3692cdc530fe65366f5ef0ed70a1f222bb570aa999105f1bf7b11fbeb0dbe446b919f9221c74b13971913859299f8f8e630b7ce472852c37926182a86c123fc7539e2808fee85e6f0f635f01f429f54528daf8e296fa84fd1e4df229caf9b4e1b3d324f198e0e1d006817b064674d3b6ced5b204183767adf8978b483281c8c14616fc552b13a1fdace75979df780d3c63eeddf17d42be544bf069e33963d6a8f2c1821", "78", "845a03549a64a4f23ed9312624cd368a84bd66fbd935153ed9bed1bc9f9f1399b24b29ddfa231c2b8c7226d39c08c184b61fef5f6a1401ffcacf7ded6bc9108fe25522d3eb71867aaf2981f3d2e81e0b4af29993194529fcaa6016a54891ceb3a3402b6668d23550ea936b78a71ef61f50d8e4919017f6cc106610fa6d79c65d20688c7039f126b6e08e18aa62fe4b96365973218a3982fb33ebc939613cfe55b6d006f4e4d5f8eeeae523a3490fb2cb68283d1052fcb4ef132f3fcf4755977c7f8daa9e70301330e70cf06ef52d2550c36f928d5438f0c32ca39717020a6846c2dd76bc7b1cf5745927df3fce71a87a33144e2edee9a6ee83b801f1aea99a6bbd971cb58e76475b545c271ffb34d91bb2e45c12b1738fdbef535d64dcfd7699ad15dd3aaacde806b5caa9d500131499aa3509ccd2f130baf308c86b6861334833ceb1afe248dd31de98c4abb8c187bf227d6542ae81bd5bdd7ca05fd3692cdc530fe65366f5ef0ed70a1f222bb570aa999105f1bf7b11fbeb0dbe446b919f9221c74b13971913859299f8f8e630b7ce472852c37926182a86c123fc7539e2808fee85e6f0f635f01f429f54528daf8e296fa84fd1e4df229caf9b4e1b3d324f198e0e1d006817b064674d3b6ced5b204183767adf8978b483281c8c14616fc552b13a1fdace75979df780d3c63eeddf17", .Okay}, + {.Shr_Signed, "313320955cd4ea055acf1e3dff68b333ff39f22c471d47760e22bcfb76384354e00df20c215bceb370f6ef3349b1b7d160035cdd3d41545b462b5a223cf8bb87fffde2dd7e5ba978c89ac3e9f73dd966fc9a484e3aedf330a69533060eb0fedee9728d92490355fe1ea0b8b453876d6ed73c0d3b9c4ebb344f4186efc7f5499bcbf19380515c3f3de76bb9a4785cade1b9925894c96c0585c127b62b56b3afaf60ad50c61c27c2df1646113d04b208fd43aa3c7c98ffc13a1ec9ce409672185483f1510b62caf6c74fe2587c585b001a0dba0283022d7a1a2b2912baabc72e4c661eabd087b6352a03f425c0e4f163d6d0a242c516c154a681b51f7a7d10770faa264cbd9991ff527b70786ec2a906aeb952a19e8e5ac1f078921a462d0d7382fb5b38804647c43e0b3d6ad5a705889bab0d79217e68013912b084ed78fb39c09a7b4b718fef00d23c16a8ed7a383c04763bc31cb34f394499dc8f21b1dc4be01d67a9d64d541e327c0bb5fe419900d4f222496de9a5a4195eb081bfd7844956740658f06f0da8760c2b7710c23f20b48798a21eb647f2addc2698b1bcf83dbe2c0069f9e11faf6cf32ef55d1c48d79c5b272c52fe0620b1c4dd446e6a25d0ee8311e0f8f50b9c018ab8bb81ba2173855dd71cacefac42b11a1ff36a239aa9f56d5478b9fb7b3308eefeeee94403eb704077d7e235804a173776363e13366d6e", "15", "1899904aae6a7502ad678f1effb45999ff9cf916238ea3bb07115e7dbb1c21aa7006f90610ade759b87b7799a4d8dbe8b001ae6e9ea0aa2da315ad111e7c5dc3fffef16ebf2dd4bc644d61f4fb9eecb37e4d24271d76f998534a998307587f6f74b946c92481aaff0f505c5a29c3b6b76b9e069dce275d9a27a0c377e3faa4cde5f8c9c028ae1f9ef3b5dcd23c2e56f0dcc92c4a64b602c2e093db15ab59d7d7b056a8630e13e16f8b23089e8259047ea1d51e3e4c7fe09d0f64e7204b390c2a41f8a885b1657b63a7f12c3e2c2d800d06dd01418116bd0d1594895d55e39726330f55e843db1a9501fa12e07278b1eb685121628b60aa5340da8fbd3e883b87d513265eccc8ffa93db83c37615483575ca950cf472d60f83c490d231686b9c17dad9c402323e21f059eb56ad382c44dd586bc90bf34009c89584276bc7d9ce04d3da5b8c7f780691e0b5476bd1c1e023b1de18e59a79ca24cee4790d8ee25f00eb3d4eb26aa0f193e05daff20cc806a791124b6f4d2d20caf5840dfebc224ab3a032c783786d43b0615bb88611f905a43cc510f5b23f956ee134c58de7c1edf160034fcf08fd7b679977aae8e246bce2d9396297f031058e26ea2373512e8774188f07c7a85ce00c55c5dc0dd10b9c2aeeb8e5677d621588d0ff9b511cd54fab6aa3c5cfdbd9984777f7774a201f5b8203bebf11ac0250b9bbb1b1f099", .Okay}, + {.Shr_Signed, "d0778c21761ea1bf1f0a941ecfc4bcfe466aa2094837a60b0056ba36ac93157dbf1e5c7a2c6b150d111cd389f325853c710ce1506c055fd9fcd12268cf8f23744c0ab2f87fbdff0d6326266eede3dd8832cf09572c5baa4b3d0b4220de4a7fc4883793016f7cd8e92b570005acbe71eea1f630e4948d034fa5c01a2928a9c24053c7cb4f7b257a684b809c0001ba0b0d162dc84c63c6ca34469a5cfae35c0b3a8b647475272fedb4a95c2005abe3965d0916bf865ec8922f3393a15ba770a3a78e2092f1f9b1c630eae1c3d00b3cfd8ab030ffbebc7e2bb059d9cb2d27f9af849ab11e9eeb160cd7b44f820b00703847516f9e3461f8bc6a56fbe7e96f17142e6193fcb8e7f573f3675751a638d498ce20c229cdcba194579eaca8028d8e873d41c92a28baa774a8be44c3e2797abf42096f3f2fd1faf0ddca6718b450d42c9fe4d7cb070f8d01c6e1111fb2eca74c1fde480fcae9eb0808f937863b08938e3937fe8709d164237dcb4ddba3c0b9b9e6af37b8fcdc2e23572ab0aae3e60f989b105e71952575e9385fcbef9a5305adcbf3c787928dfc97d30a0674f72a33b2e5911329bcf5ac079ca3cf8d66572621940f04b38d766cd48577b14364000caa7e06e764571d5e06ae02298a1279a1b00184d62b2d0dfe75f33b1364116c79e3b21cc385c7bc1f5cc855af91718574b307d829d762207978d6fa46ededc95bc086", "58", "d0778c21761ea1bf1f0a941ecfc4bcfe466aa2094837a60b0056ba36ac93157dbf1e5c7a2c6b150d111cd389f325853c710ce1506c055fd9fcd12268cf8f23744c0ab2f87fbdff0d6326266eede3dd8832cf09572c5baa4b3d0b4220de4a7fc4883793016f7cd8e92b570005acbe71eea1f630e4948d034fa5c01a2928a9c24053c7cb4f7b257a684b809c0001ba0b0d162dc84c63c6ca34469a5cfae35c0b3a8b647475272fedb4a95c2005abe3965d0916bf865ec8922f3393a15ba770a3a78e2092f1f9b1c630eae1c3d00b3cfd8ab030ffbebc7e2bb059d9cb2d27f9af849ab11e9eeb160cd7b44f820b00703847516f9e3461f8bc6a56fbe7e96f17142e6193fcb8e7f573f3675751a638d498ce20c229cdcba194579eaca8028d8e873d41c92a28baa774a8be44c3e2797abf42096f3f2fd1faf0ddca6718b450d42c9fe4d7cb070f8d01c6e1111fb2eca74c1fde480fcae9eb0808f937863b08938e3937fe8709d164237dcb4ddba3c0b9b9e6af37b8fcdc2e23572ab0aae3e60f989b105e71952575e9385fcbef9a5305adcbf3c787928dfc97d30a0674f72a33b2e5911329bcf5ac079ca3cf8d66572621940f04b38d766cd48577b14364000caa7e06e764571d5e06ae02298a1279a1b00184d62b2d0dfe75f33b1364116c79e3b21cc385c7bc1f5cc855af91718574b307d829d76220", .Okay}, + {.Shr_Signed, "-6f50732e344b526e9f68bb89d84f59001b69140a9285595f20c8fe8f570e9ee220962aaccb5d0eeb47c22cd67b09f44b123a99ba10009511882fa2ed38db561a2cbdbe15f7434d958db288c33d3bd4c856f8795262d9a591a8cb9861b7b9c97bd76afd4286a1dbd48774a199070c914decaeaad22ac54fd56711ad71ab6c7ff8cae28e9b595473d98a228052c05de90dd3c67e7d181a60afb560fbe5f3cbd18c35fe45f0d60db890ab0179db651629bd94f3edb756c20a12a626d30a14317d55f156bfbb0a7b5a42c65d8f1ba71c754618882496b76bed76536b726061f226698c9d3e8e08a93c63d4ac9acbb8f57c9163eddfa51b1a9e1fdd16b0be05c5d78209dc13a2ff7eea05523e217ad1e38d382e5cdafd1e9195e9f08378dc15604d646466341c7c26224f425be7dc331e46aa35dd6a8d7575fb1e6b63486a6160846d8ffeee01a4c10ab20d70e0f145442efe7d0ccb8709eac8ad3eb8007916197119a67eacbaf7de706f7976d5a3441dd2624796c7b5ebfc33eee399f9ae987b3059ff5e73189216aa81d476c21e1cea24db7522de0f2b9cb6bad20d54649ed5d8dff32df1b513c1d243e7042cd556540d7e184819cfa423b498d312193e310545b63989545e972484f993ab21245f2cdc51f7e4e5985ab1d02c538659828cac7c639d56e0b2c89c32bd860bb369fc33b5f4879712ad74b025206bdce029e478b41a", "3e", "-1bd41ccb8d12d49ba7da2ee27613d64006da4502a4a15657c8323fa3d5c3a7b888258aab32d743bad1f08b359ec27d12c48ea66e84002544620be8bb4e36d5868b2f6f857dd0d365636ca230cf4ef53215be1e5498b669646a32e6186dee725ef5dabf50a1a876f521dd286641c324537b2baab48ab153f559c46b5c6adb1ffe32b8a3a6d6551cf66288a014b0177a4374f19f9f4606982bed583ef97cf2f4630d7f917c35836e242ac05e76d9458a6f653cfb6dd5b08284a989b4c2850c5f557c55afeec29ed690b19763c6e9c71d5186220925addafb5d94dadc98187c899a63274fa3822a4f18f52b26b2ee3d5f2458fb77e946c6a787f745ac2f817175e0827704e8bfdfba81548f885eb478e34e0b9736bf47a4657a7c20de370558135919198d071f098893d096f9f70cc791aa8d775aa35d5d7ec79ad8d21a9858211b63ffbb80693042ac835c383c51510bbf9f4332e1c27ab22b4fae001e45865c46699fab2ebdf79c1bde5db568d107749891e5b1ed7aff0cfbb8e67e6ba61ecc167fd79cc62485aaa0751db087873a8936dd48b783cae72daeb483551927b57637fccb7c6d44f07490f9c10b355595035f86120673e908ed2634c4864f8c41516d8e625517a5c9213e64eac84917cb37147df9396616ac740b14e19660a32b1f18e755b82cb2270caf6182ecda7f0ced7d21e5c4ab5d2c09482", .Okay}, + {.Shr_Signed, "6eb383b3812a23745643012fb623e55ae5ba069a50ee35ca640868f2dd5f82cf39c79d076fa5732f75f0e0125aec5bdaa54ef5f1e0871fe1936ad7e45524e34d542895743ab5cecef782f6de7750781214a82e8bd1af9255f34fd91f16f46e8cfc267b8299d494f2168330b6d26f985d761e594a29c52bb6d8ddec74054dcb9e58275d935ed3994eef011016ceb453001b533ea7d555eea686e55cd944f79ef766d76d9c6c068db7b390dde3ba4cf9601bd26f990945d65e2df18f38b411cb8f004ef89119a0417cd9c4d943ce009331368c974cb5bc5fdb54b3467d451bf736e67f80099e221f1eeb42b69e7ef4f5a6e2128f5c16d7db58d92ff67a33f0fa6427f3e1bc6efd8d0ea052aeb0d11b345bc956e10bf5791d771122d45e2554e17f46b9c2f85420f2c5225f28df66e7277c2d3d494f433a669e9eba4aa79c4fef61718a8805bf0b29737b77d826aa57f6277b51e34333650e81273e16a36ed0728ad4a97a44eb15b25c882e93e6350dfe4d1ba0aea5edb5da29d37f0244c50c981f023a9dbadb91ffa64b88bac573f7a0842816b981a7763cdc5bb19a68a795f5be9e45d14f3f44bd259a66ed998a4488faf1952a2c17a2f0429999f61965df217910e538d063fa5c0ae3a86c745000415ef04b88d0de4aa1278e3b8241c3a42cefa9ceffada9169a55bf4c464437a0db8d6aa8eba4755a087e0d510d5d300627c0", "44", "6eb383b3812a23745643012fb623e55ae5ba069a50ee35ca640868f2dd5f82cf39c79d076fa5732f75f0e0125aec5bdaa54ef5f1e0871fe1936ad7e45524e34d542895743ab5cecef782f6de7750781214a82e8bd1af9255f34fd91f16f46e8cfc267b8299d494f2168330b6d26f985d761e594a29c52bb6d8ddec74054dcb9e58275d935ed3994eef011016ceb453001b533ea7d555eea686e55cd944f79ef766d76d9c6c068db7b390dde3ba4cf9601bd26f990945d65e2df18f38b411cb8f004ef89119a0417cd9c4d943ce009331368c974cb5bc5fdb54b3467d451bf736e67f80099e221f1eeb42b69e7ef4f5a6e2128f5c16d7db58d92ff67a33f0fa6427f3e1bc6efd8d0ea052aeb0d11b345bc956e10bf5791d771122d45e2554e17f46b9c2f85420f2c5225f28df66e7277c2d3d494f433a669e9eba4aa79c4fef61718a8805bf0b29737b77d826aa57f6277b51e34333650e81273e16a36ed0728ad4a97a44eb15b25c882e93e6350dfe4d1ba0aea5edb5da29d37f0244c50c981f023a9dbadb91ffa64b88bac573f7a0842816b981a7763cdc5bb19a68a795f5be9e45d14f3f44bd259a66ed998a4488faf1952a2c17a2f0429999f61965df217910e538d063fa5c0ae3a86c745000415ef04b88d0de4aa1278e3b8241c3a42cefa9ceffada9169a55bf4c464437a0db8d6aa8eba4755a087", .Okay}, + {.Shr_Signed, "-344701560d8ce9f8edfd1d9355657cd13cff8917462a61cd1107fe9ed1c95e5a47fd59e0ccbbdb76dc03dee68e7ae13548f9bebf590580155761a7b9b0b1aac67a82cdc4835ec911ffc4ceefc676835367a4d9e0f042518f7a42e59100dbe134d6b903c6eb0de3f6735ab3ab693f9055991c07a6a2dac9d035712180ea71d291e0edcfc0d532e8e9ebc1d5e45ac5da42a5de6d11de7b3720ccd4efe251d6c3fc69a84baf915ba539c70bb482acb148a6ef4de66a2e9b5e3d2d859e36fc48c053c4579020a37c0b43fda07d309825af19c5d0bc97c6118235d11547d1aaa4fb16b2a64bfbcb33eff541c6c874929deb94dd7748bcdbb95fcdc5676a77a952b815b4421b54d96631454fec112d45f289e64774b4c47278e27cec4d608c0af388e18f4dc82ea5af96497a4f84c5436e2b994d373248930c86b0cf359a39b53ad2ac9beee08e4ff5705ffae76ab5377a8641c7dab4ada7cf91176fe418eafd276308a4350b855e240a0d1cbaf28b4e720b33aa56717473bec89e13e719ef4715347452386e9621a6c73608b935ead1e4f129d16b432ae0b7e28fa017e83e1c6eca78c0861f6d57ab2b5f721583f44a58f6a2b30d85f21193ec29aa8c20d3b94a7e173ca79ef992d6990328f0ab98871b5edb114ae60ee1b4e00e09b18ca9e07d02431efad6c036ee7292960c9614035f370c99e01c6518159230f3402ab577f8603f", "77", "-688e02ac1b19d3f1dbfa3b26aacaf9a279ff122e8c54c39a220ffd3da392bcb48ffab3c19977b6edb807bdcd1cf5c26a91f37d7eb20b002aaec34f736163558cf5059b8906bd9223ff899ddf8ced06a6cf49b3c1e084a31ef485cb2201b7c269ad72078dd61bc7ece6b56756d27f20ab32380f4d45b593a06ae24301d4e3a523c1db9f81aa65d1d3d783abc8b58bb4854bbcda23bcf66e4199a9dfc4a3ad87f8d350975f22b74a738e1769055962914dde9bccd45d36bc7a5b0b3c6df89180a788af204146f81687fb40fa61304b5e338ba1792f8c23046ba22a8fa35549f62d654c97f79667dfea838d90e9253bd729baee9179b772bf9b8aced4ef52a5702b688436a9b2cc628a9fd8225a8be513cc8ee96988e4f1c4f9d89ac11815e711c31e9b905d4b5f2c92f49f098a86dc57329a6e649126190d619e6b34736a75a55937ddc11c9feae0bff5ced56a6ef50c838fb5695b4f9f222edfc831d5fa4ec611486a170abc48141a3975e5169ce4166754ace2e8e77d913c27ce33de8e2a68e8a470dd2c434d8e6c11726bd5a3c9e253a2d68655c16fc51f402fd07c38dd94f1810c3edaaf5656bee42b07e894b1ed45661b0be42327d853551841a77294fc2e794f3df325ad320651e157310e36bdb62295cc1dc369c01c13631953c0fa04863df5ad806ddce5252c192c2806be6e1934", .Okay}, + {.Shr_Signed, "1abc58fb4bd4ae406e0d7bab3a926a37e6f8d3f4ef0f857d477731ad0f59c9dbcdc2a8d9a0d006c674156170122b43d44ad960f41689151593bdcf24498ab708348cdb62de5244d3ea4d6a706563e76f189e37c951020976d35e9600cb1dfd867b9486e1a86f4a03d23b415cbc6cb4ea4dc7f9b4186583f563d487624ac85d454aae151c241e1755cef742f5b243f7923f12f66395838ed16f8535746ee4c363da7e73d9dfb80dc9e13b63002e8ec9a4fdcbb8b57aca48df75845d0accba189e7640aa5861a3476908fca51720b83215468fa26841523ee628aa07bf4799e706e8c8d91b05335908f78ace9f0e01e80b5e24ba761e4d97988ca0ed41bef1e60bdb77a7568d4b5b001789b674ac635464f5a1ebcf8178e7b61ab28b9b10c1f97c2d43c4ab8dc7f9bc46cbbd2478591c411bc41c419a849ee6798e02b0f88707c59c7d7bd70b37ff0b754c37c389fa3c771f0c94478f3df3760dfb4d7bc600103c8bf39af3f0a97a107dea384314f92495910fca3f73170fda5663e2ac2a9a5f0fa4ef5d8b34a0f0b6c52e931e51c2b993fa52eefddeeb60ad10897426ddba7b9c78056dcfa41aec67def7034632ee918ef952025d147ac67fa0899a1163c043d6e19b0684692642be98a6be602ef1f7f2bf64c13b9580169bc84b92ee00169730d6004280d1db78ed246606c824cf468fc758423eb6ecbe2b164395781e64742d", "e", "6af163ed2f52b901b835eeacea49a8df9be34fd3bc3e15f51ddcc6b43d67276f370aa36683401b19d05585c048ad0f512b6583d05a2454564ef73c91262adc20d2336d8b7949134fa935a9c1958f9dbc6278df25440825db4d7a58032c77f619ee521b86a1bd280f48ed0572f1b2d3a9371fe6d061960fd58f521d892b2175152ab8547090785d573bdd0bd6c90fde48fc4bd98e560e3b45be14d5d1bb930d8f69f9cf677ee0372784ed8c00ba3b2693f72ee2d5eb29237dd611742b32e86279d902a961868d1da423f2945c82e0c8551a3e89a10548fb98a2a81efd1e679c1ba323646c14cd6423de2b3a7c3807a02d7892e9d879365e623283b506fbc7982f6dde9d5a352d6c005e26d9d2b18d5193d687af3e05e39ed86aca2e6c4307e5f0b50f12ae371fe6f11b2ef491e16471046f1071066a127b99e6380ac3e21c1f1671f5ef5c2cdffc2dd530df0e27e8f1dc7c32511e3cf7cdd837ed35ef180040f22fce6bcfc2a5e841f7a8e10c53e49256443f28fdcc5c3f69598f8ab0aa697c3e93bd762cd283c2db14ba4c79470ae64fe94bbbf77bad82b44225d09b76e9ee71e015b73e906bb19f7bdc0d18cbba463be548097451eb19fe822668458f010f5b866c1a11a4990afa629af980bbc7dfcafd9304ee56005a6f212e4bb8005a5cc358010a03476de3b491981b20933d1a3f1d6108fadbb2f8ac590e55e07991", .Okay}, + {.Shr_Signed, "a0d9a22bd6749165bddf3328315dbed3358783cdd367a9e0f2dc15aff2688f0905c8e3a2cdb903b00b308277917a26f5551b8240d352bc0d9cbadc25163cb031de38ba16c911b53885a9c6a0d9e03652812eca54d5956d059d484bb12ecab73574280cb781819c45a280dcf649df49b5dddbeb5c710575c915bff5d4a4990d65ced6fd41ac1760621e06476b898ef792acd0c2c43bba3588217741952bc72f69a930fa9c378329c5045037ee7a593cb073068add065e8d13ecfd46348171f614587617257c72493b600cdd8f3f10a2b1486d9cfa9a52a0f359020c5ab3b67f6139b05bc92676968bc1ddd8a4b50a7ea17a75cebd7a95c117337caf3fa7d306132635db6ad75f3ef140d1497248d29f05b099b4922efda1b6971b1faa9a4d4722a35f20ebeaa36e55f5a7b1b0ddc0a352baa4396020c79b9c9ed6d7297e6a50e7c3c8c7bf883441c8603c683f65f8a5bd8202786045ae52a4f5b8a71b4687d8bfd004bd5fd98b44eb52ea837495011a6649bdf055ee6b010a15e17f42729789efd15f248b1bec4a39f8b6ed5f289fa4d0239afe68a287e5974cfce01ff9f101efe6eb229784b2f7bc98c0487deb08f19cbf01f8b564883a47da68d73af4537013392d56d0f819504c5a313930bc04ac2c8adfa1f2e925d89c31cad5ca017e508ec05b765a54571fac6534121fd2d1fb2ef10aeb2edf4e26546aa5a470b926dd02", "5f", "141b34457ace922cb7bbe665062bb7da66b0f079ba6cf53c1e5b82b5fe4d11e120b91c7459b720760166104ef22f44deaaa370481a6a5781b3975b84a2c796063bc71742d92236a710b538d41b3c06ca5025d94a9ab2ada0b3a9097625d956e6ae850196f0303388b4501b9ec93be936bbbb7d6b8e20aeb922b7feba949321acb9dadfa83582ec0c43c0c8ed7131def2559a1858877746b1042ee832a578e5ed35261f5386f06538a08a06fdcf4b27960e60d15ba0cbd1a27d9fa8c6902e3ec28b0ec2e4af8e49276c019bb1e7e21456290db39f534a541e6b20418b5676cfec27360b7924ced2d1783bbb1496a14fd42f4eb9d7af52b822e66f95e7f4fa60c264c6bb6d5aebe7de281a292e491a53e0b613369245dfb436d2e363f55349a8e4546be41d7d546dcabeb4f6361bb8146a5754872c0418f37393dadae52fcd4a1cf87918f7f10688390c078d07ecbf14b7b0404f0c08b5ca549eb714e368d0fb17fa0097abfb31689d6a5d506e92a0234cc937be0abdcd602142bc2fe84e52f13dfa2be491637d89473f16ddabe513f49a04735fcd1450fcb2e99f9c03ff3e203dfcdd6452f0965ef79318090fbd611e3397e03f16ac910748fb4d1ae75e8a6e026725aada1f032a098b46272617809585915bf43e5d24bb1386395ab9402fca11d80b6ecb4a8ae3f58ca68243fa5a3f65de215d65d", .Okay}, + {.Shr_Signed, "-df3b76f2c202d625c01d92275ce735bdbd6b23d6ccab33e5a3f7d822858caaa5f22bcd55c5671d6cc92184fed26a1dcc314c977fc2e9b8e171c9e6e7e0de8f6efc7aed8940357af80427455f711828ef2da6930d116f9340db90b4859214080f640d2e294a9e4d40251564b74ac14fb68dbdb5a8a607bf34257496ffbb9fdac8ac24613aecc4fd2c5dbd4ebbb0d79904f84e351dbbaa0f6a11753b7c2a900fcf2bd9ddc6a5e311c2e73207db87f9936a14d8d7d8fb572c1917149e0455a419c60726f6c65d5b2f12ba1f028c82af8ed26a7f2fb13c40384190dcd745d796cee0d11d7a8df7fd2b36032dc6c6f420ffa12d8afa03e4288b57c83a81ea5f1bfd13bf59e01607993aa40fae696f1ad374921dc8ef8b57022b93aa31a78235624b77a7c692b6724fa5effc4f4c7773e44f120087141b3b2fdc85582ece879de87968a19973065bc4bee29dc34773d863bd40f8df9588925d8dbd4b557b6f3266ae84997b7e18560f74469ba2766d1a42a122d8bc5ebcfee3d6ac940619b9661f5a09977ba57e7cc48b88c26dec2f1393f889da384c398aab3ea6fd7162aeb88268fe427c038233dfb8a412e4c4e2b37024ae59ec3df17c0ac380f329746c6e6006d147cf1789b772fdbb245ecd36d00a4b9eb797e8284125fc043882220e5d3b09e754c31f05231dc24d1e3e31fa5ab45a5e971bd12ea2aea90b363b5f98b9480945", "48", "-df3b76f2c202d625c01d92275ce735bdbd6b23d6ccab33e5a3f7d822858caaa5f22bcd55c5671d6cc92184fed26a1dcc314c977fc2e9b8e171c9e6e7e0de8f6efc7aed8940357af80427455f711828ef2da6930d116f9340db90b4859214080f640d2e294a9e4d40251564b74ac14fb68dbdb5a8a607bf34257496ffbb9fdac8ac24613aecc4fd2c5dbd4ebbb0d79904f84e351dbbaa0f6a11753b7c2a900fcf2bd9ddc6a5e311c2e73207db87f9936a14d8d7d8fb572c1917149e0455a419c60726f6c65d5b2f12ba1f028c82af8ed26a7f2fb13c40384190dcd745d796cee0d11d7a8df7fd2b36032dc6c6f420ffa12d8afa03e4288b57c83a81ea5f1bfd13bf59e01607993aa40fae696f1ad374921dc8ef8b57022b93aa31a78235624b77a7c692b6724fa5effc4f4c7773e44f120087141b3b2fdc85582ece879de87968a19973065bc4bee29dc34773d863bd40f8df9588925d8dbd4b557b6f3266ae84997b7e18560f74469ba2766d1a42a122d8bc5ebcfee3d6ac940619b9661f5a09977ba57e7cc48b88c26dec2f1393f889da384c398aab3ea6fd7162aeb88268fe427c038233dfb8a412e4c4e2b37024ae59ec3df17c0ac380f329746c6e6006d147cf1789b772fdbb245ecd36d00a4b9eb797e8284125fc043882220e5d3b09e754c31f05231dc24d1e3e31fa5ab45a5e971bd12ea2aeaa", .Okay}, + {.Shr_Signed, "-19b0f717d0e2e1ea18be952473dcf64701dbfe308c89b5643e1007e0973cb3ac9da483ccdc7e829c678d1de7b28ee25795fcad82f43f54465dbcc0cdb75b75ed83cc9779837b5fbafb04fd418701ce521b3bcd2db71a6f52b2fdb1e1ef4183245adba9af5fda7bcc16362dd36d0d6eb5c753c828f10849a51c1d6bbc486bc0d295ae0cbfd1d72059f3c68f7fd9b3306692eeb11b8495e63e03a4c643aeca4321f514ce0ada3deea92328779fcbff6a17595d08ba4a6fd37b364ae9749ffcedc869d863ad69d2c4bbdec095f8e5e68ef49160c86d5e414712e7d2454bcf8d055ba54979826475b040f70346511ad7f43443dad4926700a6438428bf10079d135e4c9e9d217f5c7372954193c34274818e9ee6eecc34c8e22cb572ab8748b280994260801420fed7550753b4b92fbbcce007e0bf382668293881e090adb5cdd1293c384a81ed86b98957535e6facd63350028f1600572b962e059445dd1e6b8247498208d28de61d0c1344f96b67c7608f477944f686ab5925820fc22127d4349f9249a49cee88b0f42277273248b661de9b35fb7bb4775535c3dd02575fceffd078200fff2e8bdc7d44e29878f0a7244b068e3b375203c31209ad14c858e51bc242ea1a35ec6bc6a05c803d0a14c3822a19d371eddcc4e172180c221faef05d25002ec518b4e9d0c96336f4a19916556986b750641bb1abc89c15583895ccae5b", "55", "-cd87b8be87170f50c5f4a9239ee7b2380edff184644dab21f0803f04b9e59d64ed241e66e3f414e33c68ef3d947712bcafe56c17a1faa232ede6066dbadbaf6c1e64bbcc1bdafdd7d827ea0c380e7290d9de696db8d37a9597ed8f0f7a0c1922d6dd4d7afed3de60b1b16e9b686b75ae3a9e414788424d28e0eb5de2435e0694ad7065fe8eb902cf9e347bfecd998334977588dc24af31f01d26321d7652190fa8a67056d1ef75491943bcfe5ffb50bacae845d2537e9bd9b2574ba4ffe76e434ec31d6b4e9625def604afc72f3477a48b06436af20a38973e922a5e7c682add2a4bcc1323ad8207b81a3288d6bfa1a21ed6a4933805321c2145f8803ce89af264f4e90bfae39b94aa0c9e1a13a40c74f7377661a6471165ab955c3a459404ca130400a107f6baa83a9da5c97dde67003f05f9c1334149c40f04856dae6e8949e1c2540f6c35cc4aba9af37d66b19a801478b002b95cb1702ca22ee8f35c123a4c1046946f30e8609a27cb5b3e3b047a3bca27b4355ac92c107e11093ea1a4fc924d24e7744587a113b9399245b30ef4d9afdbdda3baa9ae1ee812bafe77fe83c1007ff9745ee3ea2714c3c7853922583471d9ba901e18904d68a642c728de121750d1af635e3502e401e850a61c1150ce9b8f6ee6270b90c06110fd7782e928017628c5a74e864b19b7a50cc8b2ab4c35ba8320de", .Okay}, + {.Shr_Signed, "8edc6878ed317c9f61dbcb4c6d9a18e1c768e2f8ab8ffe2a59762007f0b1db4f8ad50af30a139ffa026ad0cba0c2fbb931303ae530576eb78fd858887531e1a2c980c54c562252b4e256cca176fbc59339f50f9b528731b7c87f5d518965fef4a912ff8d01c6553c20f7f29453eb195fd76502954e22aa929bd1b211c00dd7378f42e698638ac98312149df0d3c653b4a31b751e5832502e3a81bdd6603329af90dc2aba8a517b8f8115936359643f6eab84c465eeccbbb6b6f1e2de21d40b90cfbeed0fe44357cd27098d5ec952291ee6b747b0675052e22aaa113c443396d5b0385840c930460480806e2c46250434e41623081d7d904beb04f8e514116cdebe26c413c1454b401aee720d0fcd33bab1f35abdadbeef77084dcc9399f01e58654b3983d5c4180227848fc5b1510de788b61ae0e0d88e4cf3e269c7e27b060e70c90748294badf1549d90094d3bc012195dff4d49d1bd2356f11b0b14d145cfa5ca7bc573a2467a076cf10abde17bb54254cbf25c6c972031f03ab81a1fe05796f318449df270d3a94e33c5810b3f4363492d0073fe59add4ad86f9fb60ea2d9c4d393d6dc34308fd65557e06a4dd089b5746bc0f64b2f21f2828d6afa1d80912be223e96b85f650dcaaf1c3d8ef34ea9f4e9f3125ae7baa2d1e315fa1c789b07bb4fb5fbbec875e742b5b88517ca509f72918c407b13b5b35b65ca6df7e133", "9", "476e343c7698be4fb0ede5a636cd0c70e3b4717c55c7ff152cbb1003f858eda7c56a85798509cffd01356865d0617ddc98981d72982bb75bc7ec2c443a98f0d164c062a62b11295a712b6650bb7de2c99cfa87cda94398dbe43faea8c4b2ff7a54897fc680e32a9e107bf94a29f58cafebb2814aa71155494de8d908e006eb9bc7a1734c31c564c1890a4ef869e329da518dba8f2c1928171d40deeb301994d7c86e155d4528bdc7c08ac9b1acb21fb755c26232f7665ddb5b78f16f10ea05c867df7687f221abe69384c6af64a9148f735ba3d833a829711555089e2219cb6ad81c2c2064982302404037162312821a720b11840ebec825f5827c728a08b66f5f136209e0a2a5a00d77390687e699dd58f9ad5ed6df77bb8426e649ccf80f2c32a59cc1eae20c0113c247e2d8a886f3c45b0d70706c472679f134e3f13d8307386483a414a5d6f8aa4ec804a69de0090caeffa6a4e8de91ab788d858a68a2e7d2e53de2b9d1233d03b678855ef0bddaa12a65f92e364b9018f81d5c0d0ff02bcb798c224ef93869d4a719e2c0859fa1b1a4968039ff2cd6ea56c37cfdb07516ce269c9eb6e1a1847eb2aabf03526e844daba35e07b259790f94146b57d0ec04895f111f4b5c2fb286e5578e1ec779a754fa74f9892d73dd5168f18afd0e3c4d83dda7dafddf643af3a15adc428be5284fb948c6203d89dad9adb2e536fbf0", .Okay}, + {.Shr_Signed, "e07316fc7d049b5edd2c993b89395eb55fa375e8b1b68fd524f4eb6dc6f820e0aecc1f87c5406337aec306e459ba0cae642705c816cd279ffb2b545ba6094549bee361b3e85f2a195767835a1581d1f650d7344f7fe0c265cb606254e55d473474912082897154df703fc174f2aa07c049b3a15f3a30fff363304c631e660d15f327f95bf7e2702ff62f02ef16e1c76aaa26e7cdfce76936e2c085d042c58e57667e54e49b32e3c35444136cfc26cf6436986c18a5dc62105f6be15019852c755f4b8d6a47b0db3c2494b56d2952ae4486664c80b00e1ecd32089a2494705a761f7a152bec58d9579452b3a6a11b20eb319120bd72cd2082f2941c0f9acf14a102433f8f0d69366cef8026f350927a5370f6ef4917bb1454ccd21c90900dd6a62efea1373a5013f3c3a074214b150b95e73aefaa1fc23899bdbab8167d6a4dd4af15ab5cf80de1f32bef40297469e08b0ba60bbd27e2605adc1dbadfd1e702c7a4044c8ec2f824f83dae91c7526d78b3f13babd76fa578631e1080e4b6a4fdd15ece969d37e7af31dfc4ed51230711bc9c873c9207ef68875b7200c71a4120a62e5d3b7d37dbfab6e7a04a66c6e7aaa43cd80e01c8a30d715c2bda6168eb4705b3beb6791f43c0376a0a5b49d0ea7b051aac5412f33f7da9fd0f95a0c32f532eadbc5307879d91ef0325736ac838ca0aba950d5fafbb2dcd803220524a1a30af", "46", "381cc5bf1f4126d7b74b264ee24e57ad57e8dd7a2c6da3f5493d3adb71be08382bb307e1f15018cdebb0c1b9166e832b9909c17205b349e7fecad516e98251526fb8d86cfa17ca8655d9e0d68560747d9435cd13dff8309972d81895395751cd1d244820a25c5537dc0ff05d3caa81f0126ce857ce8c3ffcd8cc1318c79983457cc9fe56fdf89c0bfd8bc0bbc5b871daaa89b9f37f39da4db8b0217410b16395d99f953926ccb8f0d51104db3f09b3d90da61b062977188417daf85406614b1d57d2e35a91ec36cf09252d5b4a54ab91219993202c0387b34c822689251c169d87de854afb163655e514ace9a846c83acc64482f5cb34820bca50703e6b3c5284090cfe3c35a4d9b3be009bcd4249e94dc3dbbd245eec51533348724240375a98bbfa84dce9404fcf0e81d0852c542e579cebbea87f08e266f6eae059f5a93752bc56ad73e03787ccafbd00a5d1a7822c2e982ef49f89816b7076eb7f479c0b1e9011323b0be093e0f6ba471d49b5e2cfc4eeaf5dbe95e18c78420392da93f7457b3a5a74df9ebcc77f13b5448c1c46f2721cf2481fbda21d6dc8031c69048298b974edf4df6feadb9e81299b1b9eaa90f3603807228c35c570af6985a3ad1c16cefad9e47d0f00dda8296d2743a9ec146ab1504bccfdf6a7f43e56830cbd4cbab6f14c1e1e7647bc0c95cdab20e3282aea54357ebeecb7", .Okay}, + {.Shr_Signed, "ceaeb4dbde11c22813575eff8e22d6c723a1f8eded6b122226f30cc4146a9799d02067ea65a7bd6938544f3488bde1dc3c29adf9063fa078829afd8ae72883e35836c54c26b8a4293e89c9bd712581f6d831f3948d88a2504e6a021faf923b3b21fffdfda1e07ad9522a1ccbbdacf41a8a125e11b3ee57c455371e5cadef448bb2307d0674f38e2c029a404bb7d90ed619a4dcc43c1a79a7eb9049747bb168a05effdb15bd2892af46ec4e66375db28147b4a131b262fbf08d1953cb4e5666b71d3f0c919f478627d8b0925def9fac777919736122b76b03752ea68d9f2452c738cab9d18d66a002649ee831ca8af4c15ff19cb6e2ae3ca9eb20e0ee0f64c52163844bda7ccb41ac609945e5613c46c6083113f31b3a61b9a157b9dfd8b6de9aded039ca7b80779da0d4ba36eabd4574ff15c97c37302110620f7cbca46c9f2c3509b2f7d6a94a9f227f43f8f401868efbf9bd7ab3b838f7dc3bfaa6b103da500f639fb9a468e3061fdfbabe39b2208f7490ba831554082488aeed8076394076671b934a1fcd1522f0d398ae6ceb6fb7005e25c33c19e448e6799ffb4810faa7b7e15b36be00a32f8ec30038ad94f31235799ab08bae5068a54e99923293fa613569b78f62f9d9f467f6a59cb662b829de46c8bf3ec79112811bb0d2f628092b49ce86047cc31f162fd7dacc72ba59f57755480ed6971c5ee3098e2c7a9626", "51", "67575a6def08e11409abaf7fc7116b6391d0fc76f6b58911137986620a354bcce81033f532d3deb49c2a279a445ef0ee1e14d6fc831fd03c414d7ec5739441f1ac1b62a6135c52149f44e4deb892c0fb6c18f9ca46c451282735010fd7c91d9d90fffefed0f03d6ca9150e65ded67a0d45092f08d9f72be22a9b8f2e56f7a245d9183e833a79c716014d2025dbec876b0cd26e621e0d3cd3f5c824ba3dd8b4502f7fed8ade944957a37627331baed940a3da5098d9317df8468ca9e5a72b335b8e9f8648cfa3c313ec58492ef7cfd63bbc8cb9b0915bb581ba975346cf9229639c655ce8c6b35001324f7418e5457a60aff8ce5b71571e54f590707707b26290b1c225ed3e65a0d6304ca2f2b09e2363041889f98d9d30dcd0abdcefec5b6f4d6f681ce53dc03bced06a5d1b755ea2ba7f8ae4be1b9810883107be5e52364f961a84d97beb54a54f913fa1fc7a00c3477dfcdebd59dc1c7bee1dfd535881ed2807b1cfdcd23471830fefdd5f1cd91047ba485d418aaa0412445776c03b1ca03b338dc9a50fe68a917869cc573675b7db802f12e19e0cf224733ccffda4087d53dbf0ad9b5f005197c761801c56ca79891abccd5845d7283452a74cc91949fd309ab4dbc7b17cecfa33fb52ce5b315c14ef23645f9f63c889408dd8697b140495a4e743023e618f8b17ebed66395d2cfabbaaa4076b", .Okay}, + {.Shr_Signed, "-b5779dd95282ea0cd3d569f9ab14b281ceb230b226ff27c55ddc2ca531481ec9b2f96049fd17c2137737c4c34d22a0a3088fd4b1c6bd8f1c975ad210b10014614c1560d4cd903f905d323d29b2a12d3d28d1a40e2d5154162fca15652a5c44a7fc107c0302ff1a05ccc017892e4b09bde0fa72dd081999abcf1460062855e368bcd8e278ac0d576f70a6332b116cc10eaf221e5fbeae3cc536d4b1f9402cd7e470b855d8fe32212c42ba1c37b6d749a21f38f2acd16d92ab5e460e27f6b87585b942fa5938e2186d730e437a78e7342799db232bb9893515f508a52944f81cce01e5a3246507dad81aeefd8a17ea3ad76422b8752feb4437fe0df43f0f427e8122b592f3b64eac4a1c2474e206597c5e758e09a7bf97cb2ae6989ecb3de05c2ca051158429cac323f4e9321695a1d282892d95138245d307eb04d469ad3e534356d1ee31e6ce51a94da3b8b1ca117a0f8ffadf74532197ea1272baeda5cb962fba62a98ae14bb14af051ff933b340919ff1d7c4cdab41fa21516955d6ef5aef78e6f2277f67803d7b7f5ea66d8dd39c54dba7954d00675a7527b3244b7b5b31e0afcaa9e18cd97295d15206483fd878decb7ba751447265388577a9a5551c3ce9b18bd44f8389b5ad91d5b9232749667a1d8b08e4615b80690bc7ffd820a842cae1597a593871a0b89fa003bfd283a476b97a99dc8a6a51271a41c410739694", "a", "-2d5de77654a0ba8334f55a7e6ac52ca073ac8c2c89bfc9f157770b294c5207b26cbe58127f45f084ddcdf130d348a828c223f52c71af63c725d6b4842c4005185305583533640fe4174c8f4a6ca84b4f4a3469038b5455058bf285594a971129ff041f00c0bfc681733005e24b92c26f783e9cb74206666af3c518018a1578da2f36389e2b0355dbdc298ccac45b3043abc88797efab8f314db52c7e500b35f91c2e15763f8c884b10ae870dedb5d26887ce3cab345b64aad7918389fdae1d616e50be964e38861b5cc390de9e39cd09e676c8caee624d457d42294a513e0733807968c91941f6b606bbbf6285fa8eb5d908ae1d4bfad10dff837d0fc3d09fa048ad64bced93ab1287091d3881965f179d638269efe5f2cab9a627b2cf78170b281445610a72b0c8fd3a4c85a56874a0a24b6544e09174c1fac1351a6b4f94d0d5b47b8c79b3946a5368ee2c72845e83e3feb7dd14c865fa849caebb6972e58bee98aa62b852ec52bc147fe4cecd02467fc75f1336ad07e88545a5575bbd6bbde39bc89dfd9e00f5edfd7a99b6374e71536e9e5534019d69d49ecc912ded6cc782bf2aa7863365ca5745481920ff61e37b2dee9d4511c994e215dea6955470f3a6c62f513e0e26d6b64756e48c9d2599e8762c2391856e01a42f1fff6082a10b2b8565e964e1c682e27e800eff4a0e91dae5ea677229a9449c69071041ce6", .Okay}, + {.Shr_Signed, "-e8f1d5e73ab348b2726aff666140a673cf06361ff6cda297601c25e6369af2b2145fc15d028596ab73dfcd0440670f0b1acec2bd16cb85d7b6f8e6a19187e50e40b7b9cfadc231c1eb2d846756c4fc05ec2f17afb63359292166ede012fa7e4f069515445a6143c4f042df5b95431f704acd9d511446349a248338cdece445db2d677e08d7a3050130c2337759a1fc951e6a8871934e9af9a62d15000227614c1d49c83a55a776a7469b8b53b23a14052ee741b42ec39a75c0c490dae9f525ef79fe3bc7112b32470e1de75607021e30a6da069387a7b9e11b7ed7160e5fbc4902de4ab60edc0caf9e8da1de433d85a64a9550ebbfa48639127ff46804f39886cff9467927f8f755ede7453e233a4be5084078c591633be92672a4c09f117602a9302330a92ffa8d9193a6ed39fb685455cc646e7bd58e8d081e7c758dced9718ad1be3099ca8049521284b2eaf4acea89004041f085e2f5550e98480e96c35df85495e11c2c36713f79c238e45dc77252976a2e3386e55f7d812a8ebea7f4d406baaae50584fb3a0a1eeaa5d66451102da357ae704146b1e70a8b91b6d4c9a7bcee56d6aaecb863ad77ee7be8d7f25c4875c5d47829fa1168907fcffc84490acf78fe0628a19c3ba6c035b31e40db697df707458fb69b4e48e8a4bb44288f329818240c43d7d5b78bcbf89b9a269a92d894cfe143fa54303454b9cacc67517b", "1f", "-1d1e3abce75669164e4d5feccc2814ce79e0c6c3fed9b452ec0384bcc6d35e56428bf82ba050b2d56e7bf9a0880ce1e16359d857a2d970baf6df1cd43230fca1c816f739f5b846383d65b08cead89f80bd85e2f5f6c66b25242cddbc025f4fc9e0d2a2a88b4c28789e085beb72a863ee0959b3aa2288c69344906719bd9c88bb65acefc11af460a02618466eeb343f92a3cd510e3269d35f34c5a2a00044ec2983a939074ab4eed4e8d3716a76474280a5dce83685d8734eb818921b5d3ea4bdef3fc778e2256648e1c3bceac0e043c614db40d270f4f73c236fdae2c1cbf789205bc956c1db8195f3d1b43bc867b0b4c952aa1d77f490c7224ffe8d009e7310d9ff28cf24ff1eeabdbce8a7c467497ca1080f18b22c677d24ce549813e22ec0552604661525ff51b23274dda73f6d0a8ab98c8dcf7ab1d1a103cf8eb1b9db2e315a37c6133950092a4250965d5e959d512008083e10bc5eaaa1d30901d2d86bbf0a92bc238586ce27ef38471c8bb8ee4a52ed45c670dcabefb02551d7d4fe9a80d7555ca0b09f674143dd54bacc8a2205b46af5ce0828d63ce1517236da9934f79dcadad55d970c75aefdcf7d1afe4b890eb8ba8f053f422d120ff9ff90892159ef1fc0c514338774d806b663c81b6d2fbee0e8b1f6d369c91d1497688511e653030481887afab6f1797f137344d3525b1299fc287f4a86068a97396", .Okay}, + {.Shr_Signed, "-1d8da18ba02af2a64476478c611af6b6dbdbce4064371ab2dbde2ec1a0a7e7e083b6d6cbfca5ff681871dbf84b70cbfe4752123c6d0feb9bbe4aa970be8fe93500cb26cd6eacaa88a62702186c731beb5c70cf53625147afc0177e95485f2e83bd2eca51e3c6e322ffc80955e45ba77d1f79fff8f901cae05a18ad1edbf0a0e329e7dc19da7b0152aedbf236cde38a2ac7441ca2b49516fe3422885d4a8fbf565c77fe6bf4010dfc0173801d78aec4dee60b19e4c2ef37971289808be636739704f26e4e6b72a16c6ca46d084b0ad78bbd0e08a6bc636eb5c90e38741632637036c3e3563205168f7b564dbe4ff6b14c7efe38a892fab7b8bd9b3df096e3f1e0f5a6d607b286dbca64d8e20badceb06c2f8fcf25ecb1ee06a63926a022f38603b18d22387476ad74f6901f5ba3932fed4db34378519dba033a9d71a6629d26f0d2a8b6fd8a7359a03a75c7ce2e44acd3833e14ef5e1c162e307653d0bb83de8cab754c24baac0f2b18c874028133c72250c4b1f432cd31c83f8f253b26bfe3b0c63bf5c0e1e31688f6c93755a646534cccefca5befb4b1f658d85b69eff433550f9493260c0701e7d3ebc14aa65e3d44dd3f87eadcd8a336b8d493dae1abaa7f5a806569ecb1a9e8f2f9691b679a21446302fdeb3872b0ce69e0ee9e08fb83099d5b1a6fd0eac7af461ce5f9c90237f75c286037dff74a2ee45357de7d1724db", "4b", "-3b1b43174055e54c88ec8f18c235ed6db7b79c80c86e3565b7bc5d83414fcfc1076dad97f94bfed030e3b7f096e197fc8ea42478da1fd7377c9552e17d1fd26a01964d9add5955114c4e0430d8e637d6b8e19ea6c4a28f5f802efd2a90be5d077a5d94a3c78dc645ff9012abc8b74efa3ef3fff1f20395c0b4315a3db7e141c653cfb833b4f602a55db7e46d9bc714558e883945692a2dfc684510ba951f7eacb8effcd7e8021bf802e7003af15d89bdcc1633c985de6f2e25130117cc6ce72e09e4dc9cd6e542d8d948da109615af177a1c114d78c6dd6b921c70e82c64c6e06d87c6ac640a2d1ef6ac9b7c9fed6298fdfc715125f56f717b367be12dc7e3c1eb4dac0f650db794c9b1c4175b9d60d85f1f9e4bd963dc0d4c724d4045e70c07631a4470e8ed5ae9ed203eb747265fda9b6686f0a33b7406753ae34cc53a4de1a5516dfb14e6b34074eb8f9c5c8959a7067c29debc382c5c60eca7a17707bd1956ea984975581e563190e80502678e44a18963e8659a63907f1e4a764d7fc7618c77eb81c3c62d11ed926eab4c8ca69999df94b7df6963ecb1b0b6d3dfe866aa1f29264c180e03cfa7d782954cbc7a89ba7f0fd5b9b1466d71a927b5c35754feb500cad3d96353d1e5f2d236cf344288c605fbd670e5619cd3c1dd3c11f706133ab634dfa1d58f5e8c39cbf392046feeb850c06fbfeea", .Okay}, + {.Shr_Signed, "-aa97e7f4ecbd16d1d075bbb1e1553194a117d24c61e7984fd68bf8e4738f6a1151dbb57ce56017d78342f560e0e05f97b6a0c4fc80b2fa5d78f878530d21202f393cabe7c6628f887f67fb55e78c7bc3383685391265270102ed93286977c96b5b1e181b9de831413bb273f6f6662a58c5cea0dd28f8754091dc788f0ca7ea0a10eeee8f33d5cbae1d80be5eda371952472b7f3dc39838deee4a1a70c212fd507dde97401a778aeee05388df4830aa9dd142a066e113f69cee3da20ea87b01ff7ef1999327401e256f83e31ed175ee367720ea7c65f8a790bab990c28de50e93c488a05424144abff29a53e5b70a9ba4d3beb4134d9544c404f27d8fa9ca5917aa78937c9caee880136db459f2b0c27f6aa22fb3031e5f1a9770d1e0b9bbbb65fb744474d43629dc20193ec7f517250ce0d0431731113870589a76d6ae6331a1f9e0c4ad770c7bd1933947f708e9de34754b191333976977456ff8d049ef3e9b945358e075429147b786fb41f45178b7a5d07863e0cd9334c14039cb770f6899bf68e6a37c546e51ffc2be2a4c2f4a664a7bc41492333c2c194aa99d3c8e93b8884848aab51d692c77af642b4f6ca52c05fd06be5e16379a903ba03e0cd97e855bf4f17bc0982f7e3a03a356f71a5e8f46eb600aa62f6540e5c31563e6f984d48d2a3bb8a75c0656764a12b51d6d000c04751dfa6b4a89d53ebc24326d5275ca", "48", "-aa97e7f4ecbd16d1d075bbb1e1553194a117d24c61e7984fd68bf8e4738f6a1151dbb57ce56017d78342f560e0e05f97b6a0c4fc80b2fa5d78f878530d21202f393cabe7c6628f887f67fb55e78c7bc3383685391265270102ed93286977c96b5b1e181b9de831413bb273f6f6662a58c5cea0dd28f8754091dc788f0ca7ea0a10eeee8f33d5cbae1d80be5eda371952472b7f3dc39838deee4a1a70c212fd507dde97401a778aeee05388df4830aa9dd142a066e113f69cee3da20ea87b01ff7ef1999327401e256f83e31ed175ee367720ea7c65f8a790bab990c28de50e93c488a05424144abff29a53e5b70a9ba4d3beb4134d9544c404f27d8fa9ca5917aa78937c9caee880136db459f2b0c27f6aa22fb3031e5f1a9770d1e0b9bbbb65fb744474d43629dc20193ec7f517250ce0d0431731113870589a76d6ae6331a1f9e0c4ad770c7bd1933947f708e9de34754b191333976977456ff8d049ef3e9b945358e075429147b786fb41f45178b7a5d07863e0cd9334c14039cb770f6899bf68e6a37c546e51ffc2be2a4c2f4a664a7bc41492333c2c194aa99d3c8e93b8884848aab51d692c77af642b4f6ca52c05fd06be5e16379a903ba03e0cd97e855bf4f17bc0982f7e3a03a356f71a5e8f46eb600aa62f6540e5c31563e6f984d48d2a3bb8a75c0656764a12b51d6d000c04751dfa6b4a8a", .Okay}, + {.Shr_Signed, "-15ac358659b6537def4c80d2310d0755051cec2fcd06ea71a9e8dc7dcf9ee124217d5585d9fe962b9dd10f0b6f21d2b0c9c231671e40db5cf8e32dce34c733cb50a7ea6566a03899e52b102ae37247cb65250c234e16f8fa87da849334191a009867256a5e3c340a0078902f62b4a84285f5c37e8e005e724260c94a307f9fdab30973a3c5a974e0187cb16c89d9af3d861a046e03d32192972c4396ac95ebe8551f439449d0b8039744bfca2de354671fc5852443f6dc0aed9a8d8add0454fe95dd141913432a1128bc2de2be9403d4c776642465722e88635e092e03ec8da1944eb0544623bad7b5ba508819210cd4731f593baa18c4070cbecf06dcd3a0dec5a6944510d475afcef9bb814188abfae450f298ac908eda2c5c34632563bbab10cd757e6f056d0417d01033f89b847fcaefd5abc8d3fd428bb2e7d887102971a637d7e5ec6fdccd3151175d4eb3bae1ff6764494778c0bc186def570ce3e87cddbc506c423cf7f3a60dc342b7240af6a8885b98dd77e0e227332314a277b9dcb7799122825a486420c3ebb334c3f48997712011e72dbcb4e14c56c86bd511eac79de0c02cf612693f7bef268a79932941f0e781fd5af1313295ca519857b7a83022bd385fb14732a17ef4e8161ca2e82bf88f945bff51b779d7b58ec2c03400a029fec9818c2d0687887efc8c44e09785867b0864c08345e09fc99fb819604f", "19", "-ad61ac32cdb29bef7a64069188683aa828e7617e6837538d4f46e3ee7cf709210beaac2ecff4b15cee88785b790e95864e118b38f206dae7c7196e71a6399e5a853f532b3501c4cf295881571b923e5b2928611a70b7c7d43ed42499a0c8d004c3392b52f1e1a05003c4817b15a542142fae1bf47002f39213064a5183fcfed5984b9d1e2d4ba700c3e58b644ecd79ec30d023701e990c94b9621cb564af5f42a8fa1ca24e85c01cba25fe516f1aa338fe2c29221fb6e0576cd46c56e822a7f4aee8a0c89a19508945e16f15f4a01ea63bb321232b9174431af049701f646d0ca27582a2311dd6bdadd28440c90866a398fac9dd50c6203865f67836e69d06f62d34a22886a3ad7e77cddc0a0c455fd7228794c5648476d162e1a3192b1ddd58866babf3782b6820be80819fc4dc23fe577ead5e469fea145d973ec438814b8d31bebf2f637ee6698a88baea759dd70ffb3b224a3bc605e0c36f7ab8671f43e6ede2836211e7bf9d306e1a15b92057b54442dcc6ebbf0711399918a513bdcee5bbcc891412d24321061f5d99a61fa44cbb89008f396de5a70a62b6435ea88f563cef060167b09349fbdf793453cc994a0f873c0fead7898994ae528cc2bdbd418115e9c2fd8a39950bf7a740b0e517415fc47ca2dffa8dbbcebdac761601a005014ff64c0c6168343c43f7e4622704bc2c33d84326041a2f04fe4cfdd", .Okay}, + {.Shr_Signed, "-37d8e27c58f7035293428173ca838668ad91d568148976480f26b1ddeb8f144ad4a3dd171123211a0ca04e1c541a09821184aa50e78237981f55064961d4140f87181a9cc2e2739c343b0c20cb1f8789e37d5e9a6198d329da2c2f9d8e5a1880369619da8d0f9eda142e308103fd18c86ac67adae1fafb52b508e48398371886b554fe6b463170f850ead4cb8c6b4f77384d02f74022dc1ff80bf41682c363f7d1a720e612db58a2c46620d5bba0e534a67d5e684b88dec766fc5493fe260a2109ea3b34b3787d9963fb52caebc2c0d3e098ebea4b1b2276e2b75ab75edfd0c183f157148f050484221b937ad8df587c560fb4a28a1a2221904737a0f7965f2182aa377dd2d5b5d87321125adef96e9d77a1c75557b7b06e02bbb83eabf85b6ebbfa37a53f3ec729c00423bf46f531d8383636ff1bf18586daed15a58d3e5058c1b90c10e7387d30548516e2a9471b7c2f11d76e56867e1cf5f0ba57ce93f4a23bd3e52a78fe520ade71107e723b24dff09c02dc4e5d2a792fcfc730da3c1e33e7872bb0c31e400e8cfce19952b8bab4be06107cffc3369e263e90b2f638c8b31df0c956446919357d9d060e56c0e849c5ed0a647fb4df1c7aa376262504efac97d20df14e9eb9feead5bdebf70d59a41461e98af0f7ecef0fd9bbc2fb85deb2cef02ade00f60544bea78bdd2c45ab04e8626bec01c06cbe778a5c79b7886ce8", "4b", "-6fb1c4f8b1ee06a5268502e795070cd15b23aad02912ec901e4d63bbd71e2895a947ba2e2246423419409c38a8341304230954a1cf046f303eaa0c92c3a8281f0e30353985c4e73868761841963f0f13c6fabd34c331a653b4585f3b1cb431006d2c33b51a1f3db4285c610207fa3190d58cf5b5c3f5f6a56a11c907306e310d6aa9fcd68c62e1f0a1d5a99718d69eee709a05ee8045b83ff017e82d0586c7efa34e41cc25b6b14588cc41ab7741ca694cfabcd09711bd8ecdf8a927fc4c144213d4766966f0fb32c7f6a595d78581a7c131d7d4963644edc56eb56ebdbfa18307e2ae291e0a0908443726f5b1beb0f8ac1f694514344443208e6f41ef2cbe4305546efba5ab6bb0e64224b5bdf2dd3aef438eaaaf6f60dc0577707d57f0b6dd77f46f4a7e7d8e538008477e8dea63b0706c6dfe37e30b0db5da2b4b1a7ca0b183721821ce70fa60a90a2dc5528e36f85e23aedcad0cfc39ebe174af9d27e94477a7ca54f1fca415bce220fce47649bfe13805b89cba54f25f9f8e61b4783c67cf0e5761863c801d19f9c332a57175697c0c20f9ff866d3c4c7d2165ec7191663be192ac88d2326afb3a0c1cad81d0938bda14c8ff69be38f546ec4c4a09df592fa41be29d3d73fdd5ab7bd7ee1ab34828c3d315e1efd9de1fb37785f70bbd659de055bc01ec0a897d4f17ba588b5609d0c4d7d80380e", .Okay}, + {.Shr_Signed, "e3df7d53616a91d97d4e05c44e7110c24e04d670270297c305e635b0328f239aa644bd245d9379ee5afcf0dcc96f271a411c1f930920ad61ac87ce587c301207ffcf62c6083bf52a71ef61f4e1cefa8cec667ca1eae75edfaa6c81fd93544426c8d2ad45339abf356595cb870097c6a1d389547542f7dc0808ad80214a0c7481c1a720eee494b58caf310c497d1916fe3e05b0f2a52e6fd9feae5c3f336d726c2e30cbb07870bc5c1723b76d45c43898ee3f2f555c8ed39a671203393306a15f8e11a437966591e49c7f12423bf3f2f60dc078a762b372e887535c47435d5aae80b0fdc990c6ed5f1fe782e77d911550941c0271b438d8bc6005acfda0bc433a1d7003f5798b9325fa2f9f887f5569cd231aaa69167a63042e285e6f0aa7dc5c95f758d164aca31fe0d02dd25f8779016b694e7b279657f4ee2131649a5718a5fe6d75ff3c1edbd78ba1da2b036bc8f5af3819315963f3ad36aee46858dca3abe755a9b83f3227da3b3bb648283576daca55191b5481f2cf7c09c05c94dc03aeb8e20b7c7599fd0c9fef22ba5e89a83dd5a8fdf95b6b2790ade852204dac7f2cd5dd2bb1f9a3aa61e3fa04c10b8c99d5ce99def84353efa254f260bccf9fdb55bb5a77f648c8bb4fb4de4ed3335aefd4e5dde619c2f56974f62e12e4cd411f72850cc7a9be64d25761a90b80a16fe912baab15ef5b70309d124e420b839fbcef", "49", "71efbea9b0b548ecbea702e22738886127026b3813814be182f31ad8194791cd53225e922ec9bcf72d7e786e64b7938d208e0fc9849056b0d643e72c3e180903ffe7b163041dfa9538f7b0fa70e77d4676333e50f573af6fd53640fec9aa2213646956a299cd5f9ab2cae5c3804be350e9c4aa3aa17bee040456c010a5063a40e0d39077724a5ac657988624be8c8b7f1f02d879529737ecff572e1f99b6b936171865d83c385e2e0b91dbb6a2e21c4c771f97aaae4769cd3389019c998350afc708d21bcb32c8f24e3f89211df9f97b06e03c53b159b97443a9ae23a1aead5740587ee4c86376af8ff3c173bec88aa84a0e0138da1c6c5e3002d67ed05e219d0eb801fabcc5c992fd17cfc43faab4e6918d55348b3d318217142f378553ee2e4afbac68b256518ff06816e92fc3bc80b5b4a73d93cb2bfa771098b24d2b8c52ff36baff9e0f6debc5d0ed1581b5e47ad79c0c98acb1f9d69b5772342c6e51d5f3aad4dc1f9913ed1d9ddb24141abb6d652a8c8daa40f967be04e02e4a6e01d75c7105be3accfe864ff7915d2f44d41eead47efcadb593c856f4291026d63f966aee95d8fcd1d530f1fd026085c64ceae74cef7c21a9f7d12a79305e67cfedaaddad3bfb24645da7da6f276999ad77ea72eef30ce17ab4ba7b17097266a08fb9428663d4df32692bb0d485c050b7f4895d558af7adb818", .Okay}, + {.Shr_Signed, "ff646e2a48db5d9b714d25a361d51eb9b4e751d3e6329bd1ba885daf2e4b39f4a53f86c47a4e65d5a1d1e8442b254a2bba3ff50f7e693051929222cfcb5c31c52cc0dda79b144b78054c7ab7cae0043f25e16e31331d0d5cf52ddef30775d600adb23d4a4ee69970a1a5af5c52720239b7ab8eb141f5577a2b46d98d2f0573c2233beaf1dfc4245c34a16f15b9e76e70c3eaf4259e4ac8b7d65505713f36401582a4bf485895a5f69ecf87e046b652b39aae3080e1d192df0d45a57fc8764d666543266ddb3f6fa71fe1f88969635d5e63918b33bccf00249f7af12d3634572902d6276c9d5d6abc933896096f00436d504a3db4b22e9e13143b694ac9f0788c357079b29de3b2c63a7da0a9b9ba4d62c89a51794654c11a8c19da2eeb63f3c10e4f91512026f520f7a273728a7730eb394258ad8ff8105b90ac8ede35a0aaade4f23db5ceacddfcaa2a82bb5a008933b4c6a68faf3864944d0284c0763d9e33d7fec3542bfb84370d027dec9b3af2b29087f1ba3d6e0d2ea1899f93932260279c5eb6f4bf060367c5c755d4b669fd36e120e44ac583a8902914c888b1dcdb931a94bd757b90a9bf1e12393468c9c2b9e926694cfaaf872b06ac321deb0544d4350af275a620d88d9c7c45d13916120652888c82ffe70cae4b74d43e1ff1dd77e4d847030b6eaef3804e7e2e9fe63cc72a95119fe51af5130310dbf4d0b56ca1", "70", "ff646e2a48db5d9b714d25a361d51eb9b4e751d3e6329bd1ba885daf2e4b39f4a53f86c47a4e65d5a1d1e8442b254a2bba3ff50f7e693051929222cfcb5c31c52cc0dda79b144b78054c7ab7cae0043f25e16e31331d0d5cf52ddef30775d600adb23d4a4ee69970a1a5af5c52720239b7ab8eb141f5577a2b46d98d2f0573c2233beaf1dfc4245c34a16f15b9e76e70c3eaf4259e4ac8b7d65505713f36401582a4bf485895a5f69ecf87e046b652b39aae3080e1d192df0d45a57fc8764d666543266ddb3f6fa71fe1f88969635d5e63918b33bccf00249f7af12d3634572902d6276c9d5d6abc933896096f00436d504a3db4b22e9e13143b694ac9f0788c357079b29de3b2c63a7da0a9b9ba4d62c89a51794654c11a8c19da2eeb63f3c10e4f91512026f520f7a273728a7730eb394258ad8ff8105b90ac8ede35a0aaade4f23db5ceacddfcaa2a82bb5a008933b4c6a68faf3864944d0284c0763d9e33d7fec3542bfb84370d027dec9b3af2b29087f1ba3d6e0d2ea1899f93932260279c5eb6f4bf060367c5c755d4b669fd36e120e44ac583a8902914c888b1dcdb931a94bd757b90a9bf1e12393468c9c2b9e926694cfaaf872b06ac321deb0544d4350af275a620d88d9c7c45d13916120652888c82ffe70cae4b74d43e1ff1dd77e4d847030b6eaef3804e7e2e9fe63cc72a95", .Okay}, + {.Shr_Signed, "-95b87472c99948baba5da5b3c87ec4c1770563ff22a337b6283bf621d9b4103182202d15660468cd9206f49a68cd96793d8e07b863b980c92a71fc7a3579f35bf2c8e81e5d2a8fe3ce1cb21f4cf88d3f6282fc83aeec6c7b035073d2a33877b9fd584d591f77233f9003c27f97885398c68e3be6d4db7a9e4d38b6e4151b046fcb5f7cd4f2f4b715d1d0e316a8a11d2380ab3dde0854d253ba3638bb20ff69ca0d1dbdcff29473190aaa7e3c6b1860df9d20a2c16403017479492ab6e2f6a740e75330e093c6fb2f2f7f6d3a885588fc12d59ccff4a7f216517648eb84855cb7e1ff7900f22081660385ba6054542dd0b4cf870e438f8fb18e0a73945c1f45f2c2f0a5f51448c29dc3a656ca4360ee01ab1f2d4032f91ad593d100646839eeaf5598cdf10fd306a147af12058763868b67de36833523a9e76fa645f2ff0f6572aa8654a3a84e2c47fb89d4f03a585b426d47a130c57922b5358d39d2e69e200bcc7b3e15ff2e51b97d11f4647d87fdca212fe3e3a9c8bac2e01b07a7c2a6da024bb310ac775d63c3c06de5cba002280dc28d924355ebae522f7d7f6507cb37af549525b035288115d57f295969ff21ad0eeaeb45c14b47310970227fb649b664feed7408667b58a6b1b1843b02c405fe148ce8957183e26fa3d3fa2f45a7c02d0050f5729a79588ef50282be4af606edb9a61a2bfb2c79a30c911ab75b33f5be", "66", "-256e1d1cb266522eae97696cf21fb1305dc158ffc8a8cded8a0efd88766d040c60880b4559811a336481bd269a33659e4f6381ee18ee60324a9c7f1e8d5e7cd6fcb23a07974aa3f8f3872c87d33e234fd8a0bf20ebbb1b1ec0d41cf4a8ce1dee7f56135647ddc8cfe400f09fe5e214e631a38ef9b536dea7934e2db90546c11bf2d7df353cbd2dc5747438c5aa284748e02acf7782153494ee8d8e2ec83fda7283476f73fca51cc642aa9f8f1ac61837e74828b05900c05d1e524aadb8bda9d039d4cc3824f1becbcbdfdb4ea215623f04b56733fd29fc85945d923ae121572df87fde403c88205980e16e9815150b742d33e1c390e3e3ec63829ce51707d17cb0bc297d451230a770e995b290d83b806ac7cb500cbe46b564f440191a0e7babd566337c43f4c1a851ebc48161d8e1a2d9f78da0cd48ea79dbe9917cbfc3d95caaa19528ea138b11fee2753c0e9616d09b51e84c315e48ad4d634e74b9a78802f31ecf857fcb946e5f447d191f61ff72884bf8f8ea722eb0b806c1e9f0a9b68092ecc42b1dd758f0f01b7972e8008a0370a36490d57aeb948bdf5fd941f2cdebd525496c0d4a2045755fca565a7fc86b43babad17052d1cc425c089fed926d993fbb5d02199ed629ac6c610ec0b1017f85233a255c60f89be8f4fe8bd169f00b40143d5ca69e5623bd40a0af92bd81bb6e69869", .Okay}, + {.Shr_Signed, "d1f289434ce4598b05914d7865478988fad3eeb28aa7d8b4edbafeec430722ce1876006d5967fd840e709a5382039a75f94976c76f5cdb5016e85c361e944e06d3d063a63a0fa37dc29e4e91ff12c39d4e2cef8216718092106d9cc7663be19ac86de42dc3754993b17c4ccbc544dc4e8fde0f3744a71b93a6199f6669243bed84afd6a3df2d55a11ad2bfea44ac11f206467587ab8a18cb59fd93936b52bbba87584e5f1eabedadb9457b6dcfa805b2a8c787f5ddd7a2dd1fb67f24f8c435974e8df0ae04ed739b603db3e9bcac8d5be311271130cfd22e145a4140b20cdb5cbe997cc7f5742498f5829b3a12d86158abc659c9ba3446f6930ebbb6ecb74ac33a68cd07f4f13961f49c1d3df918d24fbb7d5516dd83aaf9e78acd51989e7d9b48e895c369950ddf0e9c573796c3099d5d940ed2b537c0de444b59a4117df081c036346f337d585d8d27a71b80a6162d984bf7004fca7bea56bce23b1ba9f467b78e4f22b7e1fdb656361232848aa0c6514d3b9735db1f4bb03be91d364f08a08d248015adf51f4e80c8b1a3b241c225f97a4ab1a2398425354ce9d13b23815d0723c08c8a73fb9431c7897992eace70e975132b5a1d92ac5be1caccc56fa6205f95ff59677fab5b2befd21aabc7a2abc143da983af4fefaa69dd1c6e75360967634f8728597c7afee7a358588b87b82202003213312eac675fd9e4b62aaf09", "18", "d1f289434ce4598b05914d7865478988fad3eeb28aa7d8b4edbafeec430722ce1876006d5967fd840e709a5382039a75f94976c76f5cdb5016e85c361e944e06d3d063a63a0fa37dc29e4e91ff12c39d4e2cef8216718092106d9cc7663be19ac86de42dc3754993b17c4ccbc544dc4e8fde0f3744a71b93a6199f6669243bed84afd6a3df2d55a11ad2bfea44ac11f206467587ab8a18cb59fd93936b52bbba87584e5f1eabedadb9457b6dcfa805b2a8c787f5ddd7a2dd1fb67f24f8c435974e8df0ae04ed739b603db3e9bcac8d5be311271130cfd22e145a4140b20cdb5cbe997cc7f5742498f5829b3a12d86158abc659c9ba3446f6930ebbb6ecb74ac33a68cd07f4f13961f49c1d3df918d24fbb7d5516dd83aaf9e78acd51989e7d9b48e895c369950ddf0e9c573796c3099d5d940ed2b537c0de444b59a4117df081c036346f337d585d8d27a71b80a6162d984bf7004fca7bea56bce23b1ba9f467b78e4f22b7e1fdb656361232848aa0c6514d3b9735db1f4bb03be91d364f08a08d248015adf51f4e80c8b1a3b241c225f97a4ab1a2398425354ce9d13b23815d0723c08c8a73fb9431c7897992eace70e975132b5a1d92ac5be1caccc56fa6205f95ff59677fab5b2befd21aabc7a2abc143da983af4fefaa69dd1c6e75360967634f8728597c7afee7a358588b87b82202003213312eac675fd9e4b6", .Okay}, + {.Shr_Signed, "-226b67d0c6ba1e7b0e130344da64f62b2f3d49689cb0f06d082bab4a9873be6df950a5ef53e422a7efd7553fe0eb2a59af9ef9299a7fbee253eb9e9513cd15825e2e930ac475b93f9915c3b2d984e27bb232ab814163e49b2e4b8fee3d45cb3338b7c6d9581e0854787ac187b87aa4732af98aa018fe80c85eaa8435668aa5ebc670e29217f6f9cc2ff918cab2eefae3bdb795bca1f3d66c85050d88f297bbe4e45c785ddc25bd785aed07304ccce073d93416b81212c55db7c9f86db9521de37cdfc96b7ce255bab104f9671d006db90681aa4d25a1d9f2751d74b15f4fb9a1459394ea09e6a0a0e79069057adcbc925b0b4e18bd3cea1816db58b241aceb35f1f3269f9690362eafb0d3faca3899420741a20bb9d0381884e91a4ec4e39b4e7d5542d9ee9555f5cd5738e81146bbf7baa34fb0dae83aba7a186a345d100c73c61a237a653c0df192cf3dd8aa50a0ee2692cc87bc913dbadeeff1f090018970f2ac91bc76c5cc4c22428b1f75428e11d72951d696eca31231c621152e62dddbcf7267af605caeb816704864b1c860281253b9632547f5e39dff8ae385740a719f6d730f7d0047dc770dfc7860ea1fc7df418d430363e29686c70b5a72ed5bcd1502450fa9ccc9dda0d7bd6ba484bfeb916cfa9fd0e1062220ff34107ba94c47d61f7c2d37eb88325deda63cd3bb5eaa5ee0472d1788431327be0848544e4bd4", "3a", "-89ad9f431ae879ec384c0d136993d8acbcf525a272c3c1b420aead2a61cef9b7e54297bd4f908a9fbf5d54ff83aca966be7be4a669fefb894fae7a544f34560978ba4c2b11d6e4fe64570ecb661389eec8caae05058f926cb92e3fb8f5172ccce2df1b6560782151e1eb061ee1ea91ccabe62a8063fa03217aaa10d59a2a97af19c38a485fdbe730bfe4632acbbbeb8ef6de56f287cf59b214143623ca5eef939171e1777096f5e16bb41cc1333381cf64d05ae0484b1576df27e1b6e548778df37f25adf38956eac413e59c7401b6e41a06a934968767c9d475d2c57d3ee685164e53a8279a82839e41a415eb72f2496c2d3862f4f3a8605b6d62c906b3acd7c7cc9a7e5a40d8babec34feb28e265081d06882ee740e06213a4693b138e6d39f5550b67ba5557d7355ce3a0451aefdeea8d3ec36ba0eae9e861a8d1744031cf18688de994f037c64b3cf762a94283b89a4b321ef244f6eb7bbfc7c2400625c3cab246f1db173130890a2c7dd50a38475ca5475a5bb28c48c7188454b98b776f3dc99ebd8172bae059c12192c72180a0494ee58c951fd78e77fe2b8e15d029c67db5cc3df4011f71dc37f1e183a87f1f7d06350c0d8f8a5a1b1c2d69cbb56f345409143ea7332776835ef5ae9212ffae45b3ea7f4384188883fcd041eea5311f587df0b4dfae20c977b698f34eed7aa97b811cb45e210c4ca", .Okay}, + {.Shr_Signed, "-483b1608a7697312abab3bbbc09c6c1ed9e6f0fb946e0e84ac5905ea9d95c691ae3ea8cb2d07261447969bc05beaa1356eafa437c3f75449a922a0cfafcb5291ce07435405bf9a059c968d7cbc6c50e652a6a4acb6fc886e6900ad18ece558567bcdf3dfd2b8f9ed644bf3dbe01d788a5ba6c93f970a6e56dca83831befa69df61ec29f96fe5cb7bd1faf50067b6889bb18bf8dbcbd5c15f1ec540a1004fc840d932b55c92630c04304a3ad754207a12dd9b21024e76d569405b7894517b0a9c21a345faba63f4c96223a9833673ab6fa990caf1c479dac1a24fcd3db9f789e1a085446e655ec3920a749c057dd9d522ab8ab9fe3a8fe891fcfa357e9162b8b74b452bec8e0873b466002022200d8dcc4b4b9844527297540acb61d69dd32b8b00e7c1f20a01b43a9c155220208ba9e878468a4438a3f8573fb3a62b37692b3dbe2dad6c2996feb2702a06a3cc6099e415946b5a3a6b009e2c3ffc1e7d005ac268bf900a90df2f99a6c9947a66f2a47f3793704fb92562b1e22a7f5699633bb6d8ba79bc46a9ed06264dad8a122f5755b0e7f241bf363add8e932a6de0b3d272ac351451fc2e74bf722e3a3943ca4e2ccfd49957dda6c0c78c6fd0042525b785231158b84334b515a405f9af5cf1d182cd1f47109b1366077cd3497f2b0387ec05b2ceb36e80ef13ad13a5b22e7af7fe07a77d08939e013325dd15e969d530e1", "4", "-483b1608a7697312abab3bbbc09c6c1ed9e6f0fb946e0e84ac5905ea9d95c691ae3ea8cb2d07261447969bc05beaa1356eafa437c3f75449a922a0cfafcb5291ce07435405bf9a059c968d7cbc6c50e652a6a4acb6fc886e6900ad18ece558567bcdf3dfd2b8f9ed644bf3dbe01d788a5ba6c93f970a6e56dca83831befa69df61ec29f96fe5cb7bd1faf50067b6889bb18bf8dbcbd5c15f1ec540a1004fc840d932b55c92630c04304a3ad754207a12dd9b21024e76d569405b7894517b0a9c21a345faba63f4c96223a9833673ab6fa990caf1c479dac1a24fcd3db9f789e1a085446e655ec3920a749c057dd9d522ab8ab9fe3a8fe891fcfa357e9162b8b74b452bec8e0873b466002022200d8dcc4b4b9844527297540acb61d69dd32b8b00e7c1f20a01b43a9c155220208ba9e878468a4438a3f8573fb3a62b37692b3dbe2dad6c2996feb2702a06a3cc6099e415946b5a3a6b009e2c3ffc1e7d005ac268bf900a90df2f99a6c9947a66f2a47f3793704fb92562b1e22a7f5699633bb6d8ba79bc46a9ed06264dad8a122f5755b0e7f241bf363add8e932a6de0b3d272ac351451fc2e74bf722e3a3943ca4e2ccfd49957dda6c0c78c6fd0042525b785231158b84334b515a405f9af5cf1d182cd1f47109b1366077cd3497f2b0387ec05b2ceb36e80ef13ad13a5b22e7af7fe07a77d08939e013325dd15e969d530f", .Okay}, + {.Shr_Signed, "-a0dbb2222533353480e198cfb173d95a66360d3338acec31bf64e7b5fdb4117d6e84149c1240875b50de63eae945c4ee29d7fa6f3036c9d5f597ae3de8335de24498a040bae1248d2db9431563ac03077a1f997d01d96f284e72cd021668770a2fee6d0bd56c4e3285779b17eaed828ddee1a1d8e3a4987cb571180be06c6322beef9ddf430b517d1e8c6934bdabdaab1864dbf777a90d8b38621c6ead632b35ec9cdd77c3a695c4100fbd30cd12f2c3afd6492cf29f0a1acf850023c10acebaaf29144740ebecb89aee12d3cf99d33abbd80157ebb9d8e307a6a06ed8e61604a1ff08f7cc36f9f65625deaf6136621303797f57079393817bf3a9fb1ec765ec946fbbcb77833dfd545681f25d07ceddd4f6e0521483353416ff979c7accf0f552e47f233f1dd023b5b8ce1e1098bcea70b52b80b738c4e9ae19b059889d659989f38208903683b1922d5984b221e16efc7155f6193ade1e3eeac4de6fce00b17f95fc9510b90f3c25f52e3018ce0ea7acfd9be4cfa7b1f27351b1d138680c5d1d2338abe3724b465919f71fd0a29fae5d9bd48a86e3b47f009a3ad90fa6abbc6d208a32242bfb3cc69100cfd5022655accb2a45f1fba89865b88d80b9b579e0a213cd62ead7f69d996ebf1a47017aa4d0bfde293fd9562f75b532d39255c4693a1932ccfec504ff39cc8b98e4a48d7f7fdc0e06f5efadb24d55e65aca366b4d", "9", "-506dd91112999a9a4070cc67d8b9ecad331b06999c567618dfb273dafeda08beb7420a4e092043ada86f31f574a2e27714ebfd37981b64eafacbd71ef419aef1224c50205d70924696dca18ab1d60183bd0fccbe80ecb794273966810b343b8517f73685eab6271942bbcd8bf576c146ef70d0ec71d24c3e5ab88c05f03631915f77ceefa185a8be8f46349a5ed5ed558c326dfbbbd486c59c310e3756b1959af64e6ebbe1d34ae20807de9866897961d7eb2496794f850d67c28011e085675d57948a23a075f65c4d770969e7cce99d5dec00abf5dcec7183d350376c730b0250ff847be61b7cfb2b12ef57b09b310981bcbfab83c9c9c0bdf9d4fd8f63b2f64a37dde5bbc19efeaa2b40f92e83e76eea7b70290a419a9a0b7fcbce3d66787aa9723f919f8ee811dadc670f084c5e75385a95c05b9c6274d70cd82cc44eb2ccc4f9c104481b41d8c916acc25910f0b77e38aafb0c9d6f0f1f75626f37e70058bfcafe4a885c879e12fa97180c670753d67ecdf267d3d8f939a8d8e89c34062e8e919c55f1b925a32c8cfb8fe8514fd72ecdea454371da3f804d1d6c87d355de369045191215fd9e63488067ea81132ad6659522f8fdd44c32dc46c05cdabcf05109e6b1756bfb4eccb75f8d2380bd52685fef149fecab17bada9969c92ae2349d0c99667f62827f9ce645cc725246bfbfee07037af7d6d926aaf32d651b36", .Okay}, + {.Shr_Signed, "f0fda4d7cf6f6245502d094b75fc3bd0fc13fb4a8dfded7b9f20a1fd8c60da96457bb0fd5ddfe024dbb454c5ef751a806242d0c8248d6a75672464f9071c43c25871f81bc94523ab374026ddaed28906c24609346c1368fdd55580833011a5eb7ae3fc4a8ee4e52b5727e690f6efc3b04cb541ec5e840cfe3fe58a95bb9be45082f1f78ff9f83933d65611bfb6d85e0f912d44bd7f852fc565672e071ebf51ee02cea3e1ee5fdf8b02bc451cc430a470794b718398d60eeb6dff3ff619aafab4d8501c90f482334d61b16b12ee966cc03fcff6ef6645c108a7e15f5364b8385aee74f982e9fafc55facdd7b4e398a05b1caba537a9b4f2ac5d804c7595642a02017ac034178a80c337d9062a715b71299f082356e290150e791d1f4c259c1ba70f66b8fabd017bbabe03241fd642072acb4e663f793e8799d71a7385405be75b6bf8d46e7a6a26621468d3a82b51d62c2eb2abad2346056b88c6361f922f5fbe8d6cbf62a7a9cd868075c3055936aa3844a1ebf14d0d5a026c2778e198177ee4d212bbc53eb3d77db9e47acb46363d508fafe620d4c0256871a78cc7f200527e54fb9978e251fb154bf21ca4149a9c45ddde9f2d12a49b9b0e4060be3f38249a3f6569024d4e83e1b972f8bfe529b5fa3facae0336324860c106b8c71065dc9fed03b2c58731bbbe6120de40946c204567f46d15806671e9b5b48beb11600cff", "2d", "787ed26be7b7b122a81684a5bafe1de87e09fda546fef6bdcf9050fec6306d4b22bdd87eaeeff0126dda2a62f7ba8d40312168641246b53ab392327c838e21e12c38fc0de4a291d59ba0136ed76944836123049a3609b47eeaaac0419808d2f5bd71fe2547727295ab93f3487b77e1d8265aa0f62f42067f1ff2c54addcdf2284178fbc7fcfc1c99eb2b08dfdb6c2f07c896a25ebfc297e2b2b397038f5fa8f7016751f0f72fefc5815e228e621852383ca5b8c1cc6b0775b6ff9ffb0cd57d5a6c280e487a4119a6b0d8b589774b36601fe7fb77b322e08453f0afa9b25c1c2d773a7cc174fd7e2afd66ebda71cc502d8e55d29bd4da79562ec0263acab2150100bd601a0bc540619bec831538adb894cf8411ab71480a873c8e8fa612ce0dd387b35c7d5e80bddd5f01920feb21039565a7331fbc9f43cceb8d39c2a02df3adb5fc6a373d3513310a3469d415a8eb16175955d691a302b5c4631b0fc917afdf46b65fb153d4e6c3403ae182ac9b551c2250f5f8a686ad013613bc70cc0bbf7269095de29f59ebbedcf23d65a31b1ea847d7f3106a6012b438d3c663f900293f2a7dccbc7128fd8aa5f90e520a4d4e22eeef4f9689524dcd8720305f1f9c124d1fb2b48126a741f0dcb97c5ff294dafd1fd657019b19243060835c638832ee4ff681d962c398dddf30906f204a361022b3fa368ac03338f4dada4", .Okay}, + {.Shr_Signed, "-d9cb3719191ccc0b17c663a5f60ecae6b0aa8f409d8742b70f55065f3addedd1596d6df325f4db2a52674519831e06e7203f5b5446adbed7b01a1fbb7ce5c559932e56881462f82e31667b9e14a417d80d8c3b12f1bf50b096e4512ee3c21f67827c884d1d7ce34959afd3c3cbab857e5f27d8cd9f1c3316bcee15e2c77c89ac152ab111bb2cbf04d36ea1b4c49d8b987db53ce86fb4e40448a1900208faa985d6ee4ab71c48d522b27e4d195b95326a602c578316356eaed3cdb063c5482e4c594bda7189b0f7a151266279e9b431fc5fb95c899661f85330f8c42333be579470d6c926975dff31fc90b593b7983cdbd74b456453c43cfb075bbc7ce63a1895222cd214f8c91ae3cf323008145e4522b9ea7905e098b8711b29da0fa2cd5b0fa91abc28ccb717ece65b270ef383f830488d2ed34d99096adb0752c8eb00ca6684187aea9804fd84a48dfb4769f586686fc33f511055e9a0aec2e7704f024ff56c2586d13470a97ae616dfc37faa54b856d4625ab24849533c9edd78b9629800dc5a6ff6fa77a3a1ab0260fa7191dab7e8a4d8519d26ff57df6e54b65db3e804736eb6b875a5c7ad1d84e463101a3eb5ba030694b6d1ccc7c69013d7d17faf88a15e992359d04b1caad6b7e89a9735a2dd09c22dcd05fd6f8ee9d4f6be8a0d20b75105afc8351180e14f25366e4453bd4d69e02c875d8127870fdd6a055a68fc", "40", "-d9cb3719191ccc0b17c663a5f60ecae6b0aa8f409d8742b70f55065f3addedd1596d6df325f4db2a52674519831e06e7203f5b5446adbed7b01a1fbb7ce5c559932e56881462f82e31667b9e14a417d80d8c3b12f1bf50b096e4512ee3c21f67827c884d1d7ce34959afd3c3cbab857e5f27d8cd9f1c3316bcee15e2c77c89ac152ab111bb2cbf04d36ea1b4c49d8b987db53ce86fb4e40448a1900208faa985d6ee4ab71c48d522b27e4d195b95326a602c578316356eaed3cdb063c5482e4c594bda7189b0f7a151266279e9b431fc5fb95c899661f85330f8c42333be579470d6c926975dff31fc90b593b7983cdbd74b456453c43cfb075bbc7ce63a1895222cd214f8c91ae3cf323008145e4522b9ea7905e098b8711b29da0fa2cd5b0fa91abc28ccb717ece65b270ef383f830488d2ed34d99096adb0752c8eb00ca6684187aea9804fd84a48dfb4769f586686fc33f511055e9a0aec2e7704f024ff56c2586d13470a97ae616dfc37faa54b856d4625ab24849533c9edd78b9629800dc5a6ff6fa77a3a1ab0260fa7191dab7e8a4d8519d26ff57df6e54b65db3e804736eb6b875a5c7ad1d84e463101a3eb5ba030694b6d1ccc7c69013d7d17faf88a15e992359d04b1caad6b7e89a9735a2dd09c22dcd05fd6f8ee9d4f6be8a0d20b75105afc8351180e14f25366e4453bd4d69e02c875d8128", .Okay}, + {.Shr_Signed, "e2002fa30bf8485e04249647217fd880e27551e43009270103e89630bf1613e7b072f7d50f44efd23116bc37657f317dc5f6516b5fcf0c384e21598f083f741faf7e4e06968611089b72b437a83581d122f993245a1e98918ad67549de8aa3c44497e57cf75034facbdc0f6b25557d5606394404428f2814fca32919790c0c529504ff21a1bda763c467389a963904940fdef2b800542afcfcc992858ded06f97d98885c0a79d9b24bfc9d1b2b1978359da998dc6a278ca4f9c43ded359e66ecd10e9981a713a4c34360095e1507ef322b0fcc8441c497db2e37e5c266ef2d20268ae5ee466231dbdeef18bbbbec36f81ea9b671290451a96eabd8ca9b8bc8eac81bacbf4eba1e9384c772a805e3147a8d027b22ca394d9a9b308aa8ce4f796e291e6628d5f6de4a8e6c29a298a10a828650ebbc540bdfce3d3386e1f18ae309fc1960670ddb99b5687bd112878070a6694fa511551b0796623d7ce9064b46885b90f6c9679aaeac6880dacbe8f0c76fe254c7d5bee52bbb93f4674c734e88a1c075f30b2f06b866582a4790b39aa8d7494986baa2e6a7ab2187f5fd7369627703298d9e8c194cabd29de3885f8b13f7c14c8d016a6abf9a1f9af4e172b792d8a2fc4bb9fd68777f95005a411c02cc51e7a4248aef19a9e950561747a1d31e41421942af9cfa766fd6319e7bad42baed7fdfe24ba7213d4997453243bb27961c", "8", "e2002fa30bf8485e04249647217fd880e27551e43009270103e89630bf1613e7b072f7d50f44efd23116bc37657f317dc5f6516b5fcf0c384e21598f083f741faf7e4e06968611089b72b437a83581d122f993245a1e98918ad67549de8aa3c44497e57cf75034facbdc0f6b25557d5606394404428f2814fca32919790c0c529504ff21a1bda763c467389a963904940fdef2b800542afcfcc992858ded06f97d98885c0a79d9b24bfc9d1b2b1978359da998dc6a278ca4f9c43ded359e66ecd10e9981a713a4c34360095e1507ef322b0fcc8441c497db2e37e5c266ef2d20268ae5ee466231dbdeef18bbbbec36f81ea9b671290451a96eabd8ca9b8bc8eac81bacbf4eba1e9384c772a805e3147a8d027b22ca394d9a9b308aa8ce4f796e291e6628d5f6de4a8e6c29a298a10a828650ebbc540bdfce3d3386e1f18ae309fc1960670ddb99b5687bd112878070a6694fa511551b0796623d7ce9064b46885b90f6c9679aaeac6880dacbe8f0c76fe254c7d5bee52bbb93f4674c734e88a1c075f30b2f06b866582a4790b39aa8d7494986baa2e6a7ab2187f5fd7369627703298d9e8c194cabd29de3885f8b13f7c14c8d016a6abf9a1f9af4e172b792d8a2fc4bb9fd68777f95005a411c02cc51e7a4248aef19a9e950561747a1d31e41421942af9cfa766fd6319e7bad42baed7fdfe24ba7213d4997453243bb2796", .Okay}, + {.Shr_Signed, "-f535182fa1b9507bf0d2c13baefa6f1d0653e15f5e05816ad9db6615cf1535a37d20df5bc985a9d0d868cc8ac5f8d898ecaee7af11d2e01d3845cac885761074040fa64277f4f9f91c7f39c2a46dc070ad341ed8b0a5d5a30dc045df0afc25f103f88806917201bebdb3d2e33b2004a37d46a26b63b9643b5ee99ce006b82bf03ca72bbd46bfc0782ee066d0768d0549503dc5802fc9586f0f60cc7b62baf7aed89bb9493c3f6786a727cf0e0333df0aec7413c5dfb937bfa4ddff8960f45c9ecf180d0e2b63d6076f72f42d7dd1d3de8be17fa21d40f05079e45c32fd9113ed6cccdaeea3160b26f1d30bb85131062cb10cf489ee1583293c9b5ae2f2da303be3a2b0fc6833548cc3991754c72b965e54a10dfd8e27648f7c651e2d0c02f9574c88df64a6c4a40e0754ed8679fc7145fd7aa4a4856f91334c284a74eef2d856578ac1ce9e62fb2597c7474b9a7a077bacc9cb3aff5446743393662580052f797c279c315f8021201d65994d3961e10026e2bfd16eeb8435a6304ed54ca5cb0adbfd3ba615e587e6312d5d2fabd69c5ea1ebd286007a84fa32559166a13e3d32e72e8557b5ffb40c9779f8b8d34f9f21f260a5efd6728f8180a1624e2f260e48f9d374ebd675c7a03ce48ca8f2a01760ee80573a3fff12e0dbc42e9d6460dfb3fa535b849de04280bec8f101c20b80a50d4638b573a07fb5d5e5f461f05e8696", "52", "-3d4d460be86e541efc34b04eebbe9bc74194f857d781605ab676d98573c54d68df4837d6f2616a74361a3322b17e36263b2bb9ebc474b8074e1172b2215d841d0103e9909dfd3e7e471fce70a91b701c2b4d07b62c297568c3701177c2bf097c40fe2201a45c806faf6cf4b8cec80128df51a89ad8ee590ed7ba673801ae0afc0f29caef51aff01e0bb819b41da34152540f71600bf2561bc3d8331ed8aebdebb626ee524f0fd9e1a9c9f3c380ccf7c2bb1d04f177ee4defe9377fe2583d1727b3c603438ad8f581dbdcbd0b5f7474f7a2f85fe887503c141e79170cbf6444fb5b3336bba8c582c9bc74c2ee144c418b2c433d227b8560ca4f26d6b8bcb68c0ef8e8ac3f1a0cd52330e645d531cae5979528437f6389d923df19478b4300be55d32237d929b1290381d53b619e7f1c517f5ea929215be44cd30a129d3bbcb61595e2b073a798bec965f1d1d2e69e81deeb3272cebfd5119d0ce4d98960014bde5f09e70c57e00848075966534e58784009b8aff45bbae10d698c13b5532972c2b6ff4ee9857961f98c4b574beaf5a717a87af4a1801ea13e8c956459a84f8f4cb9cba155ed7fed0325de7e2e34d3e7c87c98297bf59ca3e0602858938bc983923e74dd3af59d71e80f39232a3ca805d83ba015ce8fffc4b836f10ba7591837ecfe94d6e1277810a02fb23c407082e02943518e2d5ce9", .Okay}, + {.Shr_Signed, "999f3b3db68854614a813f587837fdef20594e52190016cdff5f4865871695a9efd131ee659871f5fb0fa49adaf940189dc587d9c63080c085d4a632f90e15f67e9463079db4ac20593335ba07c3f15c02111c319394f0b9dc1f8295e272c258d596229874f6c785162d8b24c9da7dc0cc9ed0a5963d813bebf8320fbe3b0ce21842b1167af4d148923ce1ac40c63b1326d569babf19b8dc44738c7fc057a143368a32c32289cc6fdc6105ae44c43fe61c3fa969b7535ce50ab4134bc70b133bbf9b1ade436ef4d0e3981cc88c82e566f2813fc3ff969fa153b1e5cf8e663149e21c699e52fd1e731a7e5fc099396349d6b02e3842c17a302ecfb2216ac67a4cf7f88b984d7fdbb4b03c3ff5774c0ae350b661f3f7f30efb3df3b882507778b0ec1a23d052a484d56ffc4e5162edf44d1a529ac77c40e6bfab95d491c6d9e2c9efeb470c838475933ce75f77ea071603a47d0717898be66917f44d7a2a85bbfb577c23443e4355bf15c4d27d44c0499604414d3d39617ab4f2252efce359fab14bc29f170dd2ac77dfcb120a96079d2151c41a97def0661961830511c231e6343f58d5ca304995ad48928c453d58132ed88648bcad7daec18e2732ffe45407c10405cb1b3b34e60dd7f56c0d322b5f6ce481ada0010584100d8c9a3ef6eefbf6a55cab2d2faae5aec9687a15d55f11ecebd243dae0123f87ec0fec4b1f42346f", "10", "999f3b3db68854614a813f587837fdef20594e52190016cdff5f4865871695a9efd131ee659871f5fb0fa49adaf940189dc587d9c63080c085d4a632f90e15f67e9463079db4ac20593335ba07c3f15c02111c319394f0b9dc1f8295e272c258d596229874f6c785162d8b24c9da7dc0cc9ed0a5963d813bebf8320fbe3b0ce21842b1167af4d148923ce1ac40c63b1326d569babf19b8dc44738c7fc057a143368a32c32289cc6fdc6105ae44c43fe61c3fa969b7535ce50ab4134bc70b133bbf9b1ade436ef4d0e3981cc88c82e566f2813fc3ff969fa153b1e5cf8e663149e21c699e52fd1e731a7e5fc099396349d6b02e3842c17a302ecfb2216ac67a4cf7f88b984d7fdbb4b03c3ff5774c0ae350b661f3f7f30efb3df3b882507778b0ec1a23d052a484d56ffc4e5162edf44d1a529ac77c40e6bfab95d491c6d9e2c9efeb470c838475933ce75f77ea071603a47d0717898be66917f44d7a2a85bbfb577c23443e4355bf15c4d27d44c0499604414d3d39617ab4f2252efce359fab14bc29f170dd2ac77dfcb120a96079d2151c41a97def0661961830511c231e6343f58d5ca304995ad48928c453d58132ed88648bcad7daec18e2732ffe45407c10405cb1b3b34e60dd7f56c0d322b5f6ce481ada0010584100d8c9a3ef6eefbf6a55cab2d2faae5aec9687a15d55f11ecebd243dae0123f87ec0fec4b1f42", .Okay}, + {.Shr_Signed, "49bb2524080fb96a193453131bb1fa0236ee9b64c7fb11087428ab38b6e7f40b1f2d584a2856bcb2f535fd28b841d5e676a6229ae3968c41af7cbedcab942e460d3a0b337ecc595ef25a6830e1a169f559245acb4d9d652b45593d91cdfc5756fa3c7d2b08fd5317b57202e18623af1d594c3c33754082b0e5adce8550d07165da320797d3ed604df8b6dc5af801b0062e1311c603f417f1704664d4c49adf6bc00de334fe121be9fc1879b1782d7ae044de2f72232cd4e5f3d4e0149f1a3b7d3a8f908535170944c335e97685327fd72c3ed4ce4b721e640d281a0fd46edef7b82593b1f96da95e07efe75768606c5e9dce13231944bd99254b509c84984d2d0d0b630ce350c055920ada84b10d70c10e200b16313eff1b4f9a4ad4a72da4c6f68a3cc693f8fec2a4add35debfde20cc90d8e2131fdc15ac56aefea2e95af16f19ceb3d1a8beb03d977830993b404e809c44b810f6c1eefbf899b66d4eed28f495102d60a8a15fc171659771b4a03bcd38768ef3db65ac81387331cdaa7318b9ddde4103edae8af6eae4cbb03092ccd90e47198dc25f163907efdc8b1bf205a1009d95f99d28e8c9e2cbc92b245cffb398a0d456fea14a625e5136fc40fa139f051fbde4d76f3355b1d301433ab73894e9d0a921807a900e8ac1cb2d8260c51860f70f05f3dbc43aa960bee25add169c7647589c4c0f30c4acc4e396f22440", "4c", "49bb2524080fb96a193453131bb1fa0236ee9b64c7fb11087428ab38b6e7f40b1f2d584a2856bcb2f535fd28b841d5e676a6229ae3968c41af7cbedcab942e460d3a0b337ecc595ef25a6830e1a169f559245acb4d9d652b45593d91cdfc5756fa3c7d2b08fd5317b57202e18623af1d594c3c33754082b0e5adce8550d07165da320797d3ed604df8b6dc5af801b0062e1311c603f417f1704664d4c49adf6bc00de334fe121be9fc1879b1782d7ae044de2f72232cd4e5f3d4e0149f1a3b7d3a8f908535170944c335e97685327fd72c3ed4ce4b721e640d281a0fd46edef7b82593b1f96da95e07efe75768606c5e9dce13231944bd99254b509c84984d2d0d0b630ce350c055920ada84b10d70c10e200b16313eff1b4f9a4ad4a72da4c6f68a3cc693f8fec2a4add35debfde20cc90d8e2131fdc15ac56aefea2e95af16f19ceb3d1a8beb03d977830993b404e809c44b810f6c1eefbf899b66d4eed28f495102d60a8a15fc171659771b4a03bcd38768ef3db65ac81387331cdaa7318b9ddde4103edae8af6eae4cbb03092ccd90e47198dc25f163907efdc8b1bf205a1009d95f99d28e8c9e2cbc92b245cffb398a0d456fea14a625e5136fc40fa139f051fbde4d76f3355b1d301433ab73894e9d0a921807a900e8ac1cb2d8260c51860f70f05f3dbc43aa960bee25add169c7647589c4c0", .Okay}, + {.Shr_Signed, "183e5a81f39746cfa70cac5d687992df8247fc67e39cda4cafbcb86fa53ee58285a83651e35c46a72c64c2c8ecae3e8e1e4bb04c7994d8a06a4564f64b55c3b8c942aa1cf849f024d0a20b9b9879149b6865940ca317f27923e5405640a7d3452d433eca5b1ab887f0100c9828924c6e2361538c63801c4cde3a87dde91ebeb72d022d25e5f2be4bd133cee7c8ab589d159f8196be459f143fc9e58138fb3b25c793e664a42b0fef0d3146aa41f7d74090ec88a822a13c8b31fe191f5c0a1c6c6c0cf6a2bdcd16f10f216072dac5ada4914f2d8ff04a608b8c78fee00421988a7b6033ef241a4ef98866959aa877f9e09a85c2559a75aa218c601da6293b15f0481e418a416ec55ff15de85b5da30c9c04853ca325da61b9e3758568f42d6a47168011d01fdb7d38ae88c178bad3103118c9b5d20e4f89193105db6ab03ef24d9933c023dd8b837c4e0a01b8985da664beef51918e351e2b7fa7f8bef37796e7543c1b27a5d8925f61f259421f0fee34363d59dedce9fd0ce667a45dd4eec652a6d1addf40833ae3462478fda0f6c9d695bd79f9ffe2877259781813e5598f5f5c4155bb3002d5698b3ea2a630513c07c15de2e2b042f0c28c2d88889477a0bf5f566c35a6f2ca7d971f97ecb7db750759cb5d3aeeae352b8883dbeb77edb595943b9fba39f3f4ccab177dfc1dc268bbe1e367c86594b6f3eed26eeece62305", "65", "c1f2d40f9cba367d386562eb43cc96fc123fe33f1ce6d2657de5c37d29f72c142d41b28f1ae23539632616476571f470f25d8263cca6c503522b27b25aae1dc64a1550e7c24f812685105cdcc3c8a4db432ca06518bf93c91f2a02b2053e9a296a19f652d8d5c43f808064c1449263711b0a9c631c00e266f1d43eef48f5f5b96811692f2f95f25e899e773e455ac4e8acfc0cb5f22cf8a1fe4f2c09c7d9d92e3c9f332521587f78698a35520fbeba04876445411509e4598ff0c8fae050e3636067b515ee68b788790b0396d62d6d248a796c7f8253045c63c7f700210cc453db019f7920d277cc4334acd543bfcf04d42e12acd3ad510c6300ed3149d8af8240f20c520b762aff8aef42daed1864e02429e5192ed30dcf1bac2b47a16b5238b4008e80fedbe9c574460bc5d6988188c64dae90727c48c9882edb5581f7926cc99e011eec5c1be270500dc4c2ed3325f77a8c8c71a8f15bfd3fc5f79bbcb73aa1e0d93d2ec492fb0f92ca10f87f71a1b1eacef6e74fe867333d22eea7763295368d6efa0419d71a3123c7ed07b64eb4adebcfcfff143b92cbc0c09f2acc7afae20aadd98016ab4c59f515318289e03e0aef171582178614616c4444a3bd05fafab361ad379653ecb8fcbf65bedba83ace5ae9d77571a95c441edf5bbf6dacaca1dcfdd1cf9fa66558bbefe0ee1345df0f1b3", .Okay}, + {.Shr_Signed, "b76965fbea34acd833919450000dd7df3b0461c82b0f7194ca64330de0e94795c6d18710d1aab53eb3fa8102e45eb132378a0a3ff659d86930abf8bc522ace58d0cc2910f11e9d7c4db02ea389a136b9e353cd76e51bcb25b8bcd3c29733ab11e34a3ce036c08c7792461ce29ce6d2de9cc87662f6a7ee780803f58ee073b1e6d3263dc013c400afa301bef9bf729f0f96902ff245044fb8b6d7d90b0371bd4a35e901166e064d975b3c0b82d5332606f7d9e3c2f2a6263422ef006b8d870a0a0eb370faf838d06149e180373b8637ec00739333b1dcb4d327c384cca4d8811e2c25cfa4f1d8df6a3c8759874f8742f8f5043f3445bafa022ae479216f7e5906b51a3dc1283b31a11e4d82a46538c020a0423f6ab1c3fbffe82e353d51b04f28eaf6ac0f0484ef6d656c131dc33c6d74fc72752687d662a347f295778168e735b780f1f370a27fca9377735fd94aba68e34a9b9534fc5e8e6ea319d5751c10fdd1678d39bc72cdea7b39a9a0163a1d53bd99d2e53e6e54f8acfaaa97bd28f3514f2e49b16d88cf6b38a7659f0c567ca0e19fac9ba33497316f526ba51c13e12bdfa09f8cf735c01854bf6b88f3c4bf13852342e827a86fe18b616fa4053f52b0760d237b9f954bf66d2d8bf8ecbf171c613da55202cfa3ce0cea5dec6d518ddff07f4992dc03eb52985bc3a5b427dcf4f63419831df527b8e2be8b85f9f0da2c", "4a", "2dda597efa8d2b360ce46514000375f7cec118720ac3dc6532990cc3783a51e571b461c4346aad4facfea040b917ac4c8de2828ffd96761a4c2afe2f148ab39634330a443c47a75f136c0ba8e2684dae78d4f35db946f2c96e2f34f0a5cceac478d28f380db0231de4918738a739b4b7a7321d98bda9fb9e0200fd63b81cec79b4c98f7004f1002be8c06fbe6fdca7c3e5a40bfc914113ee2db5f642c0dc6f528d7a40459b819365d6cf02e0b54cc981bdf678f0bca9898d08bbc01ae361c28283acdc3ebe0e34185278600dcee18dfb001ce4ccec772d34c9f0e133293620478b0973e93c7637da8f21d661d3e1d0be3d410fcd116ebe808ab91e485bdf9641ad468f704a0ecc68479360a9194e300828108fdaac70fefffa0b8d4f546c13ca3abdab03c1213bdb595b04c770cf1b5d3f1c9d49a1f598a8d1fca55de05a39cd6de03c7cdc289ff2a4dddcd7f652ae9a38d2a6e54d3f17a39ba8c6755d47043f7459e34e6f1cb37a9ece6a68058e8754ef6674b94f9b953e2b3eaaa5ef4a3cd453cb926c5b6233dace29d967c3159f283867eb26e8cd25cc5bd49ae94704f84af7e827e33dcd7006152fdae23cf12fc4e148d0ba09ea1bf862d85be9014fd4ac1d8348dee7e552fd9b4b62fe3b2fc5c7184f695480b3e8f3833a977b1b546377fc1fd264b700fad4a616f0e96d09f73d3d8d0660c77d49", .Okay}, + {.Shr_Signed, "-5439338c1fa7ecc1f9e745b6ded534d4b4ec8274d813235354c828e91f3afb65a02c04c9d277d6a6a3b3a1d0af10b3737d5207c4a57e872d934e9bba974ff82864c7e91813c18798f5cdea34957654271bb8a5c3a01165763f3243f3b8a796ace5060325af6182cc89a12f8799a76b917405b0e868de10b2bde870ee8bb4365a897e9ae76e31b8aa240cea66812f3a7bcbcc91838b0dc50d71a5ef69875898b60670fa0597b23e8e6e333ccf64233d7cced24857b0cb08dbba75187d6209b573115339895f5200df49adef1e394a53a69f2b46a0af76679299ae01c5c04a60cad678ce3c3b16efabb6b3d2261a95d5d300f747155b475371b02307a61167896866e591b54157e8437ab89893a2a2f58c7e7d668f5228cb72a6e6b08199d63d4fdbbf26a03a3809a8408f84e6793573be070356d1c99bb6b8b8f2ddba3e7e4793b8ab4ab66ebef11e0dc2a0427acdd6615cb8244545d5f31b568d95ed1b94bbdbdfc2ab7d240392148f711e9b9c20751d0b4dd749dad08853fbcbe02b1a39800e37451c2e068836bf9011560eb68ea9829489191b67a8612b2439027c1afbce462c4f328c3e770448667bb7eb8e3f568ce6174d4bbf9f394be13cbdfc386d7a8bcd9b30733610b4595da4a9459a38f9a08d91f7aa42b45a38f3bb6173da3b490bb785aa8ab8f9b0f6e43c92de5928dc33aa7a1da9081213d65fa293e6d5fef8c", "67", "-a87267183f4fd983f3ce8b6dbdaa69a969d904e9b02646a6a99051d23e75f6cb40580993a4efad4d476743a15e2166e6faa40f894afd0e5b269d37752e9ff050c98fd23027830f31eb9bd4692aeca84e37714b874022caec7e6487e7714f2d59ca0c064b5ec3059913425f0f334ed722e80b61d0d1bc21657bd0e1dd17686cb512fd35cedc6371544819d4cd025e74f797992307161b8a1ae34bded30eb1316c0ce1f40b2f647d1cdc66799ec8467af99da490af619611b774ea30fac4136ae622a67312bea401be935bde3c7294a74d3e568d415eeccf25335c038b8094c195acf19c78762ddf576d67a44c352baba601ee8e2ab68ea6e360460f4c22cf12d0cdcb236a82afd086f57131274545eb18fcfacd1ea45196e54dcd610333ac7a9fb77e4d4074701350811f09ccf26ae77c0e06ada393376d7171e5bb747cfc8f277156956cdd7de23c1b854084f59bacc2b970488a8babe636ad1b2bda372977b7bf8556fa480724291ee23d373840ea3a169bae93b5a110a7f797c0563473001c6e8a385c0d106d7f2022ac1d6d1d530529123236cf50c256487204f835f79c8c589e65187cee0890ccf76fd71c7ead19cc2e9a977f3e7297c2797bf870daf5179b3660e66c2168b2bb49528b3471f3411b23ef548568b471e776c2e7b47692176f0b551571f361edc87925bcb251b86754f44", .Okay}, + {.Shr_Signed, "6955e6aee6ebb628879392d6c266432b09b3b07dd318c4e97e2f70911e14d8ed8d00a805a6bfd98de661e3ef45bd110abcca189f4ac2d81aa62f182bf00929c1c09c076fae4b54131b2a797f20b406adb7daf24e4ba2daed9a174490b8ab4403f072b8682ce4f5efa1766b50ff2f86dabbf09ff85899dcafe839b017d1e6e43ad861ddd1f7bf750aa389cf72e838458f64d69d4c36302f51557c6ba05fcbf045dcfc43b7a93129d66c3cfaee20dc6647556a36c820e2adb082f486c267f7fe7888b3fe20db94ebe41de2cfca677d1c0ffe3ea1fa94f6cac6a76f28535e94d548445fe88b35e628056480b107272af73911f7beef8cd3237ba417ac5e4cd222d8c0045e7ef7ccc1fa5b06dee462cf861331becd038ff1511e9e3634b07afcd1987757c0147887093e736443804ec8e4cc5b0168a755313fa626b38a57b868c0d579f2399ed9030dc88b885a980dbceee5a010dd27c58688c46305dcb8324eb0ca67e20d636e63d840888edac6d76a394daf733a2638a172c2a1557a893536e619bcb073bb56e059c54cffbbbd2e951917b49be09c3594b74423794933f9918d6230e865eb8989dc57a765f156781ece4e56ddcdcd3a664b69447e9170d5bbe5523de04198d6b5ebbca54e5bae173cf0b2724b6d7dac2b454539f5d9624340e85d3609b86e121aba4af8ae48e5c0a725eff1f4520b28f82757f7f0eb5e7142fd30", "34", "6955e6aee6ebb628879392d6c266432b09b3b07dd318c4e97e2f70911e14d8ed8d00a805a6bfd98de661e3ef45bd110abcca189f4ac2d81aa62f182bf00929c1c09c076fae4b54131b2a797f20b406adb7daf24e4ba2daed9a174490b8ab4403f072b8682ce4f5efa1766b50ff2f86dabbf09ff85899dcafe839b017d1e6e43ad861ddd1f7bf750aa389cf72e838458f64d69d4c36302f51557c6ba05fcbf045dcfc43b7a93129d66c3cfaee20dc6647556a36c820e2adb082f486c267f7fe7888b3fe20db94ebe41de2cfca677d1c0ffe3ea1fa94f6cac6a76f28535e94d548445fe88b35e628056480b107272af73911f7beef8cd3237ba417ac5e4cd222d8c0045e7ef7ccc1fa5b06dee462cf861331becd038ff1511e9e3634b07afcd1987757c0147887093e736443804ec8e4cc5b0168a755313fa626b38a57b868c0d579f2399ed9030dc88b885a980dbceee5a010dd27c58688c46305dcb8324eb0ca67e20d636e63d840888edac6d76a394daf733a2638a172c2a1557a893536e619bcb073bb56e059c54cffbbbd2e951917b49be09c3594b74423794933f9918d6230e865eb8989dc57a765f156781ece4e56ddcdcd3a664b69447e9170d5bbe5523de04198d6b5ebbca54e5bae173cf0b2724b6d7dac2b454539f5d9624340e85d3609b86e121aba4af8ae48e5c0a725eff1f4520b28f82757f7f", .Okay}, + {.Shr_Signed, "-26e367e25ae88c2da57b340debd9b4e009c9b85379f383c2bafde7b928f1c60ee382a8d6df43495622932a74f77211b01f1d1d0e00c3cc8da1623f227f69074778ce2ec5b94f12c2b988810fca66fee5bfb51c726b8bd0275eb8fca2c1a3547f106a0c3d8271d3a1614f8246298be7723b9ab147db3d6c28f1bbe89f0624fe59513b9f477ec5a1f4d93e0b6cb6bca8ae92aec59670d9c9b3ffc204281a68d97f90086502ce3a94b04df9f0cddb2ea52b7aa6a64a6241871fc547c39f2bc4f55c46984ed165e80aa6312582feecf168d6b114f4fd0e89d55ab4284bbe63b7793de29c701c55a784b921f2aecccb8dd2f9974646016f8b6a349185a73c163ce13dc045fd7fcdb9aa170d29e463329423f15e3db7ee19037a13d567305eec1e6ca2f5c35e186b7aac819d6655f87bc961c6ee98cde694b5fbdbefb8b7bbb1d7731a1dd4937b0557696918c0aed97a118f847d9040168bf01598e4bb2d6643d558ea25ea407e3c4aa04ef61377c6003c28916c0f9285f39900dc7bf99924c3385c84397a46d587776ebb302594c54d3e0d375f0ce0f146ca5ac7717d8c8000807aa17714c8447e62253891d26ca399a5687444f8914be058b3ec4ea5fc7930e91797f356784d0418b971a9d72015cdde20f9973c1c3a8ef39b9b37d09c32b82957fe8ca84eb5928342c666fe6bc64865a04e09b2cecc8c0362b1dce922c06be5d87f", "10", "-26e367e25ae88c2da57b340debd9b4e009c9b85379f383c2bafde7b928f1c60ee382a8d6df43495622932a74f77211b01f1d1d0e00c3cc8da1623f227f69074778ce2ec5b94f12c2b988810fca66fee5bfb51c726b8bd0275eb8fca2c1a3547f106a0c3d8271d3a1614f8246298be7723b9ab147db3d6c28f1bbe89f0624fe59513b9f477ec5a1f4d93e0b6cb6bca8ae92aec59670d9c9b3ffc204281a68d97f90086502ce3a94b04df9f0cddb2ea52b7aa6a64a6241871fc547c39f2bc4f55c46984ed165e80aa6312582feecf168d6b114f4fd0e89d55ab4284bbe63b7793de29c701c55a784b921f2aecccb8dd2f9974646016f8b6a349185a73c163ce13dc045fd7fcdb9aa170d29e463329423f15e3db7ee19037a13d567305eec1e6ca2f5c35e186b7aac819d6655f87bc961c6ee98cde694b5fbdbefb8b7bbb1d7731a1dd4937b0557696918c0aed97a118f847d9040168bf01598e4bb2d6643d558ea25ea407e3c4aa04ef61377c6003c28916c0f9285f39900dc7bf99924c3385c84397a46d587776ebb302594c54d3e0d375f0ce0f146ca5ac7717d8c8000807aa17714c8447e62253891d26ca399a5687444f8914be058b3ec4ea5fc7930e91797f356784d0418b971a9d72015cdde20f9973c1c3a8ef39b9b37d09c32b82957fe8ca84eb5928342c666fe6bc64865a04e09b2cecc8c0362b1dce922c06be6", .Okay}, + {.Shr_Signed, "-c5a9faa08a6d2a9947c84c6308118381158891eb01df33a2c5d07a333517089284af73895738f32323c6b0bb7c00b77ac58aed6a6039366a6045089f8ad029288b61ef691723e4200ce76257cc6fd7884e8dfa310c9dfbaeeadc6afc3c786efe016d18045b3473591e2d5a0b33e616037805430057ab7076e3274896cbfe4fd0f0cf2367f7e6c1ae5a495a1c0e317b44b376914fafe4916c20344413579f3b9cf93582bab69d2fac60061ac82183188b1bbcf8bdc5ef295e34ea54392aa56312418fa51b1b8cdb45aa26cc2d20da946fd3ef78b2d81f40258413bd9b5dcadb1286a35300459d38547743dd7b3ba2741624943a2faf953080588b87f8ac8eab5fe4a80707f54307d2860bc7b502f06e5dd5dc9a273cd892181d1cb0de3e9bea56fae45eb19d893efd434c6c7e2cdb595b39ab61f64cc6de0eae7bb94a9ded5f51ac41bb26196e16ba5721a2bf505b38be9f14054129b454244354768db0634a0b67ae2eb5b49927efcd302413f65367942217e40af0ea6cbf9c62fae0463844288ac5096a18b9b73cfb7a0ecbb7ed0ac31957f4f25f64e2bc2b3a9f0662846e83755d4dae312bf51832c7e79fee5b2793918201e3d1e9fc828827064e8917b765216a073b98cceff50e3b6158f4e988bc8d6fa99b03f337bf4960d289919bf1a6b9646918c08365f5d612ede3c0a2d4ac7489764cd7b96f99249b5c9161442f1c", "21", "-62d4fd504536954ca3e426318408c1c08ac448f580ef99d162e83d199a8b84494257b9c4ab9c799191e3585dbe005bbd62c576b5301c9b353022844fc568149445b0f7b48b91f2100673b12be637ebc42746fd18864efdd7756e357e1e3c377f00b68c022d9a39ac8f16ad0599f30b01bc02a1802bd5b83b7193a44b65ff27e8786791b3fbf360d72d24ad0e0718bda259bb48a7d7f248b6101a2209abcf9dce7c9ac15d5b4e97d630030d6410c18c458dde7c5ee2f794af1a752a1c9552b18920c7d28d8dc66da2d5136616906d4a37e9f7bc596c0fa012c209decdaee56d894351a98022ce9c2a3ba1eebd9dd13a0b124a1d17d7ca98402c45c3fc564755aff2540383faa183e94305e3da8178372eeaee4d139e6c490c0e8e586f1f4df52b7d722f58cec49f7ea1a6363f166dacad9cd5b0fb26636f07573ddca54ef6afa8d620dd930cb70b5d2b90d15fa82d9c5f4f8a02a094da2a1221aa3b46d831a505b3d7175ada4c93f7e6981209fb29b3ca110bf2057875365fce317d70231c2214456284b50c5cdb9e7dbd0765dbf685618cabfa792fb2715e159d4f8331423741baaea6d71895fa8c1963f3cff72d93c9c8c100f1e8f4fe4144138327448bdbb290b5039dcc6677fa871db0ac7a74c45e46b7d4cd81f99bdfa4b06944c8cdf8d35cb2348c6041b2faeb0976f1e0516a563a44bb266bdcb7cc924dae49", .Okay}, + {.Shr_Signed, "-b966c4afaa897ee62d69528345515c4fdace008046af06fdd32beaf9f10502ac6fd4632863669669ae3ed0fd0a1b7b0a5e4043046dc0d4f24fbddea0d9e22741efc1239c7a09779970bd1145e85cbbca0bcc0caf2add15206e83cca7dd092a4aec7a3d666ef0430ed054d806b1d50145d16be3a70199018e74c60052573395c277cfa2ff538a2dae83e1df52a4f26ef336070cd70ecc7b59060dc744cc7969f09d6f8261d7f01c62982e92db07197e5798be5b94bcd433cb197fe6e7da6c8cebd949c52eee4d2bb8d082949ff1813c5fc6be908689b6c1aa7279c043ef98d52edf218db218a5058f7391637a17c60d8840d77ae68db7a1a34f57a0f4595ac9500e408e23480628139338983b184851f5576a5e0a072c805c855556182261833e6383bd6268e1fece1179fd0cb097907a5acc17a8baed79254e0fbd62c78a85a8dddc383b859ca69d7efe41548489aa872aa107297cdd7ead1c82eccad152aab424a9b80741297d103ef67603fe31d9d08b027e426328cbcc35cb6ee8cd8300157c9b7c8dd0280712bfa7dd43d6fc874311b38dc425451646b3c48213d8da23305a8c0d3bd2263bf5f0ca659589db0c1db1a8fa5a535e7cce253f65ba799fec143dd4e9eef78438f847e635d2ca2077ea874038e0aa25c1ffb57aeb93570fb33c136c66ebf2f5c618def9edd5e7119e1b3c6837c3abe26fd7de9ae1ed440bdf56", "6d", "-5cb36257d544bf7316b4a941a2a8ae27ed6700402357837ee995f57cf882815637ea319431b34b34d71f687e850dbd852f20218236e06a7927deef506cf113a0f7e091ce3d04bbccb85e88a2f42e5de505e60657956e8a903741e653ee849525763d1eb337782187682a6c0358ea80a2e8b5f1d380cc80c73a6300292b99cae13be7d17fa9c516d741f0efa9527937799b03866b87663dac8306e3a2663cb4f84eb7c130ebf80e314c17496d838cbf2bcc5f2dca5e6a19e58cbff373ed364675eca4e297772695dc68414a4ff8c09e2fe35f484344db60d5393ce021f7cc6a976f90c6d90c5282c7b9c8b1bd0be306c4206bbd7346dbd0d1a7abd07a2cad64a807204711a4031409c99c4c1d8c2428faabb52f050396402e42aaab0c1130c19f31c1deb13470ff6708bcfe86584bc83d2d660bd45d76bc92a707deb163c542d46eee1c1dc2ce534ebf7f20aa4244d54395508394be6ebf568e41766568a9555a1254dc03a094be881f7b3b01ff18ece845813f21319465e61ae5b77466c1800abe4dbe46e81403895fd3eea1eb7e43a188d9c6e212a28b2359e24109ec6d11982d46069de9131dfaf86532cac4ed860ed8d47d2d29af3e67129fb2dd3ccff60a1eea74f77bc21c7c23f31ae965103bf543a01c705512e0ffdabd75c9ab87d99e09b63375f97ae30c6f7cf6eaf388cf0d9e342", .Okay}, + {.Shr_Signed, "-94562ecba373bdce84af5df668ccc3b81f05aed66968af0ec42e3feebe71120ae4d7b0cd985d9fd51136627d37c8e53c2513f88b56e17034ff9af81d476ef6d11d4345194cc3912fb9fbe831a0908730c2a31bbe06c6346be7a36154fea6596b8adc6229bb9a70d948f2b75cef13ebe92bff6f529c01da214ffb1ec68bd117fa7ba334534ae13f80c736cc6cfe4953ead061471b4249c3d783fe4e7b2566ab1b3077b3e557bb29a8c47ed0fd071326afa63bda6dce07e232f9bef07978062def104771282f65ebb21fa0984070f561f9d8e903bda7e9987d533abc2c27427207e76cd938a87e1ac0ed2c5f22f853cd4a69d104e624cbc28e384d28918b0166cccb716b086fe967e5d38a4ef9a7bc84531f216c24908434fb93557c67bd6a44b5218143d4b18259ea692af320a2719be947cf57bef88da6e1f009aabf0ec4fcde4f755f131422555705db2ab2d8a4863c06557440a9a2c7dd04e5fbe373d3fbfea662d7b7d788c593d273099b37ea9069c0373afa2281333511200c3c6f28a6e5dba960ddefce77770397a972e272c55fb86d84f9d0b5fbd4ad5b9fc3b33d7a3032833b22dc24805a3ad2f086ca252f8d191f1176063cfc82c1df981103645137ac9fc05b0ea6b8b5f65da60352346febf59d1f4aac2eaeab149bea20b5d1f673fa0a6635e37b79bd46bda6ce84b98529698a747a6d6164402a5f22d59e097bdc", "42", "-25158bb2e8dcef73a12bd77d9a3330ee07c16bb59a5a2bc3b10b8ffbaf9c4482b935ec33661767f5444d989f4df2394f0944fe22d5b85c0d3fe6be0751dbbdb44750d1465330e44bee7efa0c682421cc30a8c6ef81b18d1af9e8d8553fa9965ae2b7188a6ee69c36523cadd73bc4fafa4affdbd4a700768853fec7b1a2f445fe9ee8cd14d2b84fe031cdb31b3f9254fab41851c6d09270f5e0ff939ec959aac6cc1decf955eeca6a311fb43f41c4c9abe98ef69b7381f88cbe6fbc1e5e018b7bc411dc4a0bd97aec87e826101c3d587e763a40ef69fa661f54ceaf0b09d09c81f9db364e2a1f86b03b4b17c8be14f3529a7441398932f0a38e134a2462c059b332dc5ac21bfa59f974e293be69ef2114c7c85b0924210d3ee4d55f19ef5a912d486050f52c60967a9a4abcc8289c66fa51f3d5efbe2369b87c026aafc3b13f3793dd57c4c5089555c176caacb629218f01955d102a68b1f741397ef8dcf4feffa998b5edf5e23164f49cc266cdfaa41a700dcebe88a04ccd4448030f1bca29b976ea58377bf39dddc0e5ea5cb89cb157ee1b613e742d7ef52b56e7f0eccf5e8c0ca0cec8b70920168eb4bc21b2894be34647c45d818f3f20b077e60440d9144deb27f016c3a9ae2d7d976980d48d1bfafd6747d2ab0babaac526fa882d747d9cfe82998d78dede6f51af69b3a12e614a5a629d1e9b585911", .Okay}, + {.Shr_Signed, "62b5d9165dd4397822a303b1820abe8319c2543aadd7bcb9e8e9149f48be6c92e1f52e49f169397c181473a8a21da529d02092ada1fc1fbd9fe402271f76b30af63909a65d5e654da52749225106bebf3721fb7024893eb298be2fbaee08db29f4493adce213c6ddd3e5f4df4b5a9faed78590f0ec681c1cdd216819b31d60e0fc29c30e721dc6e779df26c32dd81c53a7e57809f536f0c1cb3a1741a86c55c3da7681557994771ec00cea0408718d4c0c3c6e53b03714d8bca8904d52725b8b40627ce21e8df903d1fe792397bbfff9c09815b4ccdfdd50ec9bf665020f814fe61f07acb0d03d8de7eb082b40f9e322db13277c4dc1e733d53f368354d1ed686929284b1327ab43e2e11e093d64c96f963900723719a028c4cefe3bb88f56be7d27afaf075251050865ac08a586a9d44dd9c182a9efb32ef30fcaa7a76314c2d2cbb847dc1ad19a77941a40457bc03bca25896f1c29b80d3e58b31af2b285554aa1d3a322d255592cae774847e755229cb75e8f8fe4e8b9be2cd55a198d165f4640280a80d36eba5769e0c83d203b37dc3f2ff0039c6b7c0d68bc86eef3a1e4ef08718708b087b90bd617eebf1858dfe28e3a5594d7a34f4fb77ee2b3f07008200be03d1d35e8755a308bbc9fdf5ad133f8cb6e91955e6e0d9aa1d14938363df2390fa817b1321f165f8a02ed3c59de055351701c70f2213d11637fc158ee35", "48", "62b5d9165dd4397822a303b1820abe8319c2543aadd7bcb9e8e9149f48be6c92e1f52e49f169397c181473a8a21da529d02092ada1fc1fbd9fe402271f76b30af63909a65d5e654da52749225106bebf3721fb7024893eb298be2fbaee08db29f4493adce213c6ddd3e5f4df4b5a9faed78590f0ec681c1cdd216819b31d60e0fc29c30e721dc6e779df26c32dd81c53a7e57809f536f0c1cb3a1741a86c55c3da7681557994771ec00cea0408718d4c0c3c6e53b03714d8bca8904d52725b8b40627ce21e8df903d1fe792397bbfff9c09815b4ccdfdd50ec9bf665020f814fe61f07acb0d03d8de7eb082b40f9e322db13277c4dc1e733d53f368354d1ed686929284b1327ab43e2e11e093d64c96f963900723719a028c4cefe3bb88f56be7d27afaf075251050865ac08a586a9d44dd9c182a9efb32ef30fcaa7a76314c2d2cbb847dc1ad19a77941a40457bc03bca25896f1c29b80d3e58b31af2b285554aa1d3a322d255592cae774847e755229cb75e8f8fe4e8b9be2cd55a198d165f4640280a80d36eba5769e0c83d203b37dc3f2ff0039c6b7c0d68bc86eef3a1e4ef08718708b087b90bd617eebf1858dfe28e3a5594d7a34f4fb77ee2b3f07008200be03d1d35e8755a308bbc9fdf5ad133f8cb6e91955e6e0d9aa1d14938363df2390fa817b1321f165f8a02ed3c59de055351701c70f2", .Okay}, + {.Shr_Signed, "c441447babaf69a129a9aa0a000784c2e49b7b261d0cc4dd4e1d5b16d9f457e83de842bfd164116ebe858b1efcfef473eab9d3c6b85549454e590b8143293719b547d44bc71944a07aa69db03e8c67ced0c60e4da5116e6e706ffe845f336b2cd932d45b8d7f26fa9702ed4c861b61db884adf09d76460b3624a7a8e2fc8d00c2ad6a0868d0550fcddc3aa4dba4b2a515b510d6f3890a7e109376cf17eb1cdcf698b9efbcdf0577c32569e5f8d0d4ab5df82edda8ea7a38bc65e6ad0bd8ac276aa9d3d77d87d7dd9f39103ff17c210da37dfb49d1e4be0e1e82daa06a1eee37c7ec3568bbe83ef410a9b7bc186308f87c4bbcf53e7126a0436331c8473096b10bb2f34c3dbd31df4b91067488f71748c494ba2d0c107d44850a21597ba4016e9a5ec3b89283720760d21313e31eba41116278d5c0cc311ef96d8f80a28833262c7b02f78881e311cb38e5bedb7619061c6b85cb9e3bf26c50046755ef3630a110d279fc2dc43f3b6537c593a9c318879c642f48f90ec376cac94f48cf541cb91d0e3c701479c2698cb2f6497c07fc7582efc0f80c5ab8f44ccfecc2d805c906a4a3de73a874e5a31537997501260004dbe7a0fdaa1c219e6ed777497a7147c91fee96abd6f3156a77d731d2717779b523b1edbd0b9410ab93edf01d64f55441549f71ec446971c9605fffd993b63cf1cb384640c44cfb4a3b241ad73247fe5d", "3a", "3110511eeaebda684a6a6a828001e130b926dec987433137538756c5b67d15fa0f7a10aff459045bafa162c7bf3fbd1cfaae74f1ae155251539642e050ca4dc66d51f512f1c651281ea9a76c0fa319f3b431839369445b9b9c1bffa117ccdacb364cb516e35fc9bea5c0bb532186d876e212b7c275d9182cd8929ea38bf234030ab5a821a341543f3770ea936e92ca9456d4435bce2429f8424ddb3c5fac7373da62e7bef37c15df0c95a797e34352ad77e0bb76a3a9e8e2f1979ab42f62b09daaa74f5df61f5f767ce440ffc5f084368df7ed274792f8387a0b6a81a87bb8df1fb0d5a2efa0fbd042a6def0618c23e1f12ef3d4f9c49a810d8cc7211cc25ac42ecbcd30f6f4c77d2e4419d223dc5d231252e8b43041f51214288565ee9005ba697b0ee24a0dc81d83484c4f8c7ae9044589e3570330c47be5b63e028a20cc98b1ec0bde22078c472ce396fb6dd8641871ae172e78efc9b140119d57bcd8c2844349e7f0b710fced94df164ea70c621e7190bd23e43b0ddb2b253d233d5072e47438f1c051e709a632cbd925f01ff1d60bbf03e0316ae3d1333fb30b6017241a928f79cea1d3968c54de65d4049800136f9e83f6a8708679bb5ddd25e9c51f247fba5aaf5bcc55a9df5cc749c5dde6d48ec7b6f42e5042ae4fb7c07593d55105527dc7b111a5c725817fff664ed8f3c72ce119031133ed28e", .Okay}, + {.Shr_Signed, "-94b3fda4bdbd457025acf1885916ca8e10dfc0a06d9931f86ec6991dea5a41d1e803a2127753b6284790d9f3cc01af719a8fcae6974fce5d53dba2a692a85ed577a784f11fb30c36f0c260d67bbf66b1df55d759c69f53506acd596592c84468a6977647cf685a4288d80293073bcfdd3db44f85c05f0cac97244b23b23a77446edb9fb3b32f2aa58d560ec5fba201f3a7af0fd96fa964b2c691764266891d594c3de5c75c0541962edbf441696466126f574b56c69d95532975db1f55993b8e35fe6489a22998b068418efb231414ffec9ac300d34c53ebcf6fee1a33c964efafdcdf9d5e832b839c40878b5763330fafa5bcc0f99198f4d7af0ccd0084eb3bf2f18dfbdeabf0ec864ea4839f4df03727d46aa9fe5d95689643b1085c7d593bc727aa34026c3d8bbdb2c5ee9b1dc49384a07b8b0b0689794e358c58f52e37352d8bb5ca47ab88838b00ccd03f5dbb42f8281c09ca93b2324fc42b5e3bbed371be00871af0565b5e2c9d32e042cc6581c10269106e595dddb941e8c411a02f5261901d7e27c81e2394f5d7ac704ea47c858abe106730cb2f14cb271b6f241e430343fec5706309b817ce844650fdc74bfbdc2609185c79796b3ac11ae83f347efd2ba3af1eac712c745a0c97631994f9412586c9ca0c12c1886c2d2edc027972deec2777f82e99cf25977efbb1662c18eef4b71a14de9c46eb02789d5f74219e", "44", "-94b3fda4bdbd457025acf1885916ca8e10dfc0a06d9931f86ec6991dea5a41d1e803a2127753b6284790d9f3cc01af719a8fcae6974fce5d53dba2a692a85ed577a784f11fb30c36f0c260d67bbf66b1df55d759c69f53506acd596592c84468a6977647cf685a4288d80293073bcfdd3db44f85c05f0cac97244b23b23a77446edb9fb3b32f2aa58d560ec5fba201f3a7af0fd96fa964b2c691764266891d594c3de5c75c0541962edbf441696466126f574b56c69d95532975db1f55993b8e35fe6489a22998b068418efb231414ffec9ac300d34c53ebcf6fee1a33c964efafdcdf9d5e832b839c40878b5763330fafa5bcc0f99198f4d7af0ccd0084eb3bf2f18dfbdeabf0ec864ea4839f4df03727d46aa9fe5d95689643b1085c7d593bc727aa34026c3d8bbdb2c5ee9b1dc49384a07b8b0b0689794e358c58f52e37352d8bb5ca47ab88838b00ccd03f5dbb42f8281c09ca93b2324fc42b5e3bbed371be00871af0565b5e2c9d32e042cc6581c10269106e595dddb941e8c411a02f5261901d7e27c81e2394f5d7ac704ea47c858abe106730cb2f14cb271b6f241e430343fec5706309b817ce844650fdc74bfbdc2609185c79796b3ac11ae83f347efd2ba3af1eac712c745a0c97631994f9412586c9ca0c12c1886c2d2edc027972deec2777f82e99cf25977efbb1662c18eef4b71a14de9c5", .Okay}, + {.Shr_Signed, "36e2ebab328f144401f13250ceef225ea5bd845412699ecb08d7ff98d26f4f7f65a40f8fc89909a145f57ebab333ecc0a9a796e2fd5d49199c37b44561a3d6cca3a0e602ae24cb1697cad1a851f5ad810b3cc7851855b03e39f669088678ead4fbf09384bbb16cf26d90c5c7fa6225a162b2a2115216e6d257db69ddf00829c1c949119820d0be44ce494fb415140d881a0262348e3ec2086e3970668f53e011773418074a839f898b0e51fbb620d998df0469961ed0d79361200b4e0cc85d4483f98eb951ff43a46ed03957e47d407fdfc25231ab7fd0f480b6326d5f4b278df5763a9ee6abb227017ec2b79826072f2b12d1ca05ebe520fce98095922f8ad79ea49ad704a104bf2541e1c904a138210f4eb4be80a92e05a589c4e21115accbd0a94b038811e4519aedf89560a1198adb3ad1602b6236c04088e22c09408529f9d9d6d510ca844a35dedc82c4768beb4ba051688f4d44a83c631777af21b1d2c2028ca7fcbcf04ae675e8683e9aa0fba3ca1ea669a98af5eb5ac5e65deb117eb750264161254d75475a443d64c00e5a833ef74cea4a39b96056e4b251cc9d4236f74cd351472e6d95cc122b4f6bfa03bc223f802044cb24d30a6c1526e9b067c7ded09fde6a3c7bb96c9ff6d6f131fb555b1a6ffa7e38ef51075f0f19b50f9f64e934447e1b9d6335a5e669c496319f9d4360b07d092349cab994ab36e59fc7", "a", "db8baeacca3c511007c4c9433bbc897a96f6115049a67b2c235ffe6349bd3dfd96903e3f2264268517d5faeacccfb302a69e5b8bf575246670ded115868f5b328e83980ab8932c5a5f2b46a147d6b6042cf31e146156c0f8e7d9a42219e3ab53efc24e12eec5b3c9b643171fe98896858aca8845485b9b495f6da777c020a707252446608342f91339253ed054503620680988d238fb0821b8e5c19a3d4f8045dcd0601d2a0e7e262c3947eed88366637c11a6587b435e4d84802d38332175120fe63ae547fd0e91bb40e55f91f501ff7f0948c6adff43d202d8c9b57d2c9e37d5d8ea7b9aaec89c05fb0ade60981cbcac4b472817af9483f3a6025648be2b5e7a926b5c128412fc950787241284e0843d3ad2fa02a4b816962713884456b32f42a52c0e204791466bb7e2558284662b6ceb4580ad88db01022388b0250214a7e7675b54432a1128d77b720b11da2fad2e8145a23d3512a0f18c5ddebc86c74b080a329ff2f3c12b99d7a1a0fa6a83ee8f287a99a6a62bd7ad6b179977ac45fadd409905849535d51d6910f59300396a0cfbdd33a928e6e5815b92c947327508dbdd334d451cb9b6573048ad3dafe80ef088fe0081132c934c29b0549ba6c19f1f7b427f79a8f1eee5b27fdb5bc4c7ed556c69bfe9f8e3bd441d7c3c66d43e7d93a4d111f86e758cd69799a71258c67e750d82c1f4248d272ae652acdb967", .Okay}, + {.Shr_Signed, "-d3e83fafca891f1ba6614c78598b8edb769296cbe24d9b85f0a93de69fb7e068159770a14d8e5f2f5843c9771567d8dddd840f6f1a0c7adb4bf2a17d77460e9fb1a6f27412eb2583e62486078837690a6b77008b9d0aceb1d354bcbd1f80f292d0f40136af96eb9f0abcf6e8ec2653a325883d37343cd6196de20e640f9c70121edfb525abeb686409208b3526f00ac90d0b1ddb6bdada3efcfffb394504cc797550e732109e505d453c6b39e043b22844e1a383fe9ace9a55409f80dee5733551f933dc957dbc41182f160c68c8fed7477249202946d7326091399f90d8340ab0f2c755e99b334c12071c9fe7d9231d0ec93b2aa33225a43c2a9f04cec3a6fe852734afffcc81d93e9d29669f16fa66c291663accf648da6b286e201fd96b5db41103ca5f800495a94b77a1e11b005806c7dc294e536f2245d3d08ea9a2e95f4167164f93bbaf42f36e47b8420dd00b322aa77fa006bff167ededd4ebd039d4c8329326a22fa9da2d194bcd5d8dff6e778c880f30240890ab6b42c5425c5d03e23824e675b6fb6b2193c875ec1e4055e3f9d2fa166460f3c72173e905df64ddf416539d34e1fabf3bb77d4990c55290007c2cb7112950d4e0a4726ff52cb5b023f33fcc865b577326d0da47bcd5cc42edc5a3f84e66f9ad42c6f0fd50a1fef2761c8f72815ac151dbcecbe5ddbe5e7aedaa8bafb20ea01fe3b21f1eec65cf4e", "77", "-1a7d07f5f95123e374cc298f0b3171db6ed252d97c49b370be1527bcd3f6fc0d02b2ee1429b1cbe5eb08792ee2acfb1bbbb081ede3418f5b697e542faee8c1d3f634de4e825d64b07cc490c0f106ed214d6ee01173a159d63a6a9797a3f01e525a1e8026d5f2dd73e1579edd1d84ca7464b107a6e6879ac32dbc41cc81f38e0243dbf6a4b57d6d0c81241166a4de015921a163bb6d7b5b47df9fff6728a0998f2eaa1ce64213ca0ba8a78d673c087645089c34707fd359d34aa813f01bdcae66aa3f267b92afb7882305e2c18d191fdae8ee49240528dae64c122733f21b0681561e58eabd3366698240e393fcfb2463a1d92765546644b4878553e099d874dfd0a4e695fff9903b27d3a52cd3e2df4cd8522cc7599ec91b4d650dc403fb2d6bb68220794bf00092b5296ef43c23600b00d8fb8529ca6de448ba7a11d5345d2be82ce2c9f27775e85e6dc8f70841ba01664554eff400d7fe2cfdbdba9d7a073a99065264d445f53b45a32979abb1bfedcef19101e6048112156d6858a84b8ba07c47049cceb6df6d6432790ebd83c80abc7f3a5f42cc8c1e78e42e7d20bbec9bbe82ca73a69c3f57e776efa93218aa52000f8596e2252a1a9c148e4dfea596b6047e67f990cb6aee64da1b48f79ab9885db8b47f09ccdf35a858de1faa143fde4ec391ee502b582a3b79d97cbbb7cbcf5dc", .Okay}, + {.Shr_Signed, "-b04f6cfdbf5a9a6b927be939de83495f5e8ad7ffdf45bce20fe087b0eb7a083f9a8c32698190cf08c4383bb7bec3d15442c58d8f249023fae709b2df2d9f1f0f84a73a63a0256fc82acdc53012736b8b3fcfd01a1bbaf82094ad07d9bedb40210c447e044f0dfa59343c4933110732881ad055161aeaab0af9688787fbb0331c6ccbcfabc7c7dc598530fcb4fa8596f40cac0407e1b274e844b829d05d4059f7ffebf8ab698f9f2891eaf1d9accefa90c3253e79c0f3b26e9235b5e742fc699ea35fd44f91827cd36c4f2fedb26f0553562ab963049747010627792285d14163890dac7ad38bad3c8edf59c880f1f4602722ca23412e35ab345eaab3bf2d0ad02755009efabab99cd9e19e9390b156a01d876ac35b9764fb40782a8cac948d66a7875d881ad686d827b2630385796848ee6ed644b1514fcc158d1fdf777336b9f783569972cd2f83c240ba5ec6c853a5dc1ec50ed77f5782a78c934e4c0511298625eb74eca325221aa2fbb7e878fa6202858a3f539b94679a7ff17612096f6b47aa810834a50f45ae08fe0a38d735e219b10234a280e39171514f11cb1ee4cfbc815fa9cd8cd4154dca346d970c22c38febe9449f158a2fed4d09646714686b899fc27f43129ae8992d3b1c692d55553c31a90fe4b766fcc47e3fc9fee068c963c8e753f945298abe439774b7424c07894047f237dbff066c19210913acfdbf", "1a", "-2c13db3f6fd6a69ae49efa4e77a0d257d7a2b5fff7d16f3883f821ec3ade820fe6a30c9a606433c2310e0eedefb0f45510b16363c92408feb9c26cb7cb67c7c3e129ce98e8095bf20ab3714c049cdae2cff3f40686eebe08252b41f66fb6d00843111f8113c37e964d0f124cc441cca206b4154586baaac2be5a21e1feec0cc71b32f3eaf1f1f716614c3f2d3ea165bd032b0101f86c9d3a112e0a741750167dfffafe2ada63e7ca247abc766b33bea430c94f9e703cec9ba48d6d79d0bf1a67a8d7f513e4609f34db13cbfb6c9bc154d58aae58c125d1c04189de48a1745058e2436b1eb4e2eb4f23b7d672203c7d1809c8b288d04b8d6acd17aaacefcb42b409d54027beaeae67367867a4e42c55a80761dab0d6e5d93ed01e0aa32b252359a9e1d76206b5a1b609ec98c0e15e5a123b9bb5912c5453f3056347f7dddccdae7de0d5a65cb34be0f0902e97b1b214e97707b143b5dfd5e0a9e324d39301444a61897add3b28c94886a8beedfa1e3e9880a1628fd4e6e519e69ffc5d84825bdad1eaa0420d2943d16b823f828e35cd78866c408d28a038e45c5453c472c7b933ef2057ea7363350553728d1b65c308b0e3fafa5127c5628bfb53425919c51a1ae267f09fd0c4a6ba264b4ec71a4b55554f0c6a43f92dd9bf311f8ff27fb81a3258f239d4fe514a62af90e5dd2dd09301e25011fc8df6ffc19b06484245", .Okay}, + {.Shr_Signed, "d3351c9486c85d1cef275bb2e52837aa97a62adc5d5bc708b16c54975f0de466aece90b192fbcbf59fa479ee4af10ae39636bb7581dba6718dac3ada21da2cbb859e6548d99e0171031a360ad8f6bdce263642c7b60c366d1f0a0c065cbc52a2887a4b5b5d0c1d3f7d57e3945222a3ed8d92879297010aada62eca622bf79f4e7d89e425abf4dfe7d47c7af365fdf26f2ac0ac7fadeb32d664ac08d4346ff610372b0c7c60e079034230b0b2a4daf09ab7b752294bba4c43eda617d40b8c590d7cee197f8e0886d931b2eeef605a36f2a139b5934e9770fa6b52219ba25aa68786ea9785701e68422206d4728c96af9e2d0e26bf31bea5bf588b4a1b6f4ec284b1f1c8fa4fa233e3b786e00e5e8a2b8ba195cf253f6350bcac7855fb811364c41bc08540b519a39cabb42e488b9f6b89069294388c61968dbb2d4ad92c7b363056e5143e2a47fbcf89e6a856ecfd7bde9c22f7de116b51af295c3e9a9c30c1c33172b555a24565a847676507e0906e1826a66341212d1ad4579e7daac103c1883b2bbad57f0ff185385519e331770a992b5e616258b4a2f812f8bcaa7cd78a383d3b50b5b3259f50265e68fba924b1dfe3cbf3d7d1db7ead3945b6880ff8277a98c58282ad4778c7f5f196790df164ce2da2832b9b022f2eff01694fa492a9e6b9ad58aca388b6093267a59982d2bb2c111e9728e68e769cafb58fcbacc46a8b", "30", "d3351c9486c85d1cef275bb2e52837aa97a62adc5d5bc708b16c54975f0de466aece90b192fbcbf59fa479ee4af10ae39636bb7581dba6718dac3ada21da2cbb859e6548d99e0171031a360ad8f6bdce263642c7b60c366d1f0a0c065cbc52a2887a4b5b5d0c1d3f7d57e3945222a3ed8d92879297010aada62eca622bf79f4e7d89e425abf4dfe7d47c7af365fdf26f2ac0ac7fadeb32d664ac08d4346ff610372b0c7c60e079034230b0b2a4daf09ab7b752294bba4c43eda617d40b8c590d7cee197f8e0886d931b2eeef605a36f2a139b5934e9770fa6b52219ba25aa68786ea9785701e68422206d4728c96af9e2d0e26bf31bea5bf588b4a1b6f4ec284b1f1c8fa4fa233e3b786e00e5e8a2b8ba195cf253f6350bcac7855fb811364c41bc08540b519a39cabb42e488b9f6b89069294388c61968dbb2d4ad92c7b363056e5143e2a47fbcf89e6a856ecfd7bde9c22f7de116b51af295c3e9a9c30c1c33172b555a24565a847676507e0906e1826a66341212d1ad4579e7daac103c1883b2bbad57f0ff185385519e331770a992b5e616258b4a2f812f8bcaa7cd78a383d3b50b5b3259f50265e68fba924b1dfe3cbf3d7d1db7ead3945b6880ff8277a98c58282ad4778c7f5f196790df164ce2da2832b9b022f2eff01694fa492a9e6b9ad58aca388b6093267a59982d2bb2c111e9728e68e769cafb5", .Okay}, + {.Shr_Signed, "-45a715c1d0912e58d2f555b6f3dabb3e495b877bb8b153867649b88dbb37b17ca6ae01428e18af550f08a0a872ecdc2176dfe3157215f185b61bf9ec2c3bff328ed142507bdf7ef8dd212574885d45bb41cc5f5591a5bdef6fe915ac391848785eac8b3d1e111787b79d0145c0e7a96a5db9008c07b1d6c0e51d3a6d3b74ee72e4269aaecdff2baff38890ab1a4f752d21126f98160da560244d872508921b00ce4d6fb567bfecf1c6fe19c9479c2b0ac54339783096123fd5e2768bb66cd12e3738bde3788a2f958fc1ffab10cf01630db7fcb28f75a25965287269083bc4de2babf63df767c959bcc43d262ee3cc39df46722db932dce79453798634dc175dfb0b7dfb9f37b4335aa14357529d9f49c66e82e5a9788d24b6d6012b35261452d6b53bda285671a06cbdcf882ddb7e9048db7acf8cf3662a711ef86b3e27c539c363192b53134ce785f833d6aa5839556c1f4a7378c712a2dc231e81035e23e1202d5e9e1b55d0a7e9680f5b33dda835b08ff3b0dc3ac27898d060b39504c69e141c5f380ee98d242e287edeb31683ba54450ee6dfb1cb9a5357a82ec7fdd7a5d0eb394c5567f58ffd8db90841569f56908cf2843f3c24a90c6c87fdc9105dcb2993f318ab093212f475e2a87a14a49f1cda5a065825ef60b2d445767a0966b61d5e9bd5bf6ecc968f2dbe3bff38f3e075f1fdbdc1e97bea680af58cd99ec542", "65", "-22d38ae0e848972c697aaadb79ed5d9f24adc3bddc58a9c33b24dc46dd9bd8be535700a1470c57aa8784505439766e10bb6ff18ab90af8c2db0dfcf6161dff994768a1283defbf7c6e9092ba442ea2dda0e62faac8d2def7b7f48ad61c8c243c2f56459e8f088bc3dbce80a2e073d4b52edc804603d8eb60728e9d369dba773972134d5766ff95d7f9c448558d27ba96908937cc0b06d2b01226c39284490d806726b7dab3dff678e37f0ce4a3ce158562a19cbc184b091feaf13b45db3668971b9c5ef1bc4517cac7e0ffd5886780b186dbfe5947bad12cb2943934841de26f15d5fb1efbb3e4acde621e931771e61cefa33916dc996e73ca29bcc31a6e0baefd85befdcf9bda19ad50a1aba94ecfa4e3374172d4bc46925b6b00959a930a296b5a9ded142b38d0365ee7c416edbf48246dbd67c679b315388f7c359f13e29ce1b18c95a989a673c2fc19eb552c1caab60fa539bc6389516e118f4081af11f09016af4f0daae853f4b407ad99eed41ad847f9d86e1d613c4c683059ca82634f0a0e2f9c0774c69217143f6f598b41dd2a2287736fd8e5cd29abd41763feebd2e8759ca62ab3fac7fec6dc8420ab4fab484679421f9e1254863643fee4882ee594c9f98c558499097a3af1543d0a524f8e6d2d032c12f7b0596a22bb3d04b35b0eaf4deadfb7664b4796df1dff9c79f03af8fee", .Okay}, + {.Shr_Signed, "71e222b1feda00a497ff80d9109a64311d3d4ea22ae38a53fe55c19b3cb1c47aebd7572b112410968df077c997fe9456b1f7de2b6366872676113e27de0674bc6b6bb3a2033da113cbb063f5b86b0c20fab74a7962324930e464f7a34e418e014952ec313c651f69cc181dec4d68ca5a1b04a2f9597072ef929435851ade3d9cf7627a71ca6b3a5ca016c7108d23567e4718a150d4d5c5bb38175afdc5aef62e15fd776ff863cdcc11fa2ed7756b6302fd100c903cd000e09d0ff052ad63acf921187752518817eb8dd0a7b03e008e59b1b7ba503e3c868ed8a9537560cc8bf2c822229cad32e32eec2ed1dea0cb8be7816ea581fb285b4c23ecf2daed25d1699d2366b0edaafe1efc7e1d358d572288ab9235a40487e692a22b3289b472f2eeeac53c504507125808d46cada1b1a0eb6f40fc8da0c63bd461a253c97adcc7eb9bf9f6d5d633d4d3a44affdb7c0476521517822154f5f6d3047762a9b146f868476c6e251327246e886ffe5c9695b87fac12711d126f5129abcdaeda51b379f486cb8182f96acd42c44ca9d381b8b66ec19546721491c92dcb284f95c2663087f378714d9f02b7970b4eab2177b2424c30f030adee217bb1e6b35a84757090383c63b7f194f5afb6f0604d7054b31909da9da658071ac460301c9b751bbd5e7204b677d30fedd7c31b3dec7e165a36bb751a0f925b9885720f4dba610951ba70", "1e", "1c7888ac7fb6802925ffe0364426990c474f53a88ab8e294ff957066cf2c711ebaf5d5cac4490425a37c1df265ffa515ac7df78ad8d9a1c99d844f89f7819d2f1adaece880cf6844f2ec18fd6e1ac3083eadd29e588c924c39193de8d39063805254bb0c4f1947da7306077b135a329686c128be565c1cbbe4a50d6146b78f673dd89e9c729ace972805b1c42348d59f91c628543535716ece05d6bf716bbd8b857f5ddbfe18f373047e8bb5dd5ad8c0bf4403240f3400382743fc14ab58eb3e48461dd4946205fae37429ec0f8023966c6dee940f8f21a3b62a54dd583322fcb20888a72b4cb8cbbb0bb477a832e2f9e05ba9607eca16d308fb3cb6bb49745a6748d9ac3b6abf87bf1f874d6355c8a22ae48d690121f9a4a88acca26d1cbcbbbab14f141141c49602351b2b686c683adbd03f2368318ef5186894f25eb731fae6fe7db5758cf534e912bff6df011d948545e088553d7db4c11dd8aa6c51be1a11db1b8944c9c91ba21bff9725a56e1feb049c47449bd44a6af36bb6946cde7d21b2e060be5ab350b1132a74e06e2d9bb065519c8524724b72ca13e570998c21fcde1c5367c0ade5c2d3aac85dec90930c3c0c2b7b885eec79acd6a11d5c240e0f18edfc653d6bedbc18135c152cc64276a7699601c6b1180c0726dd46ef579c812d9df4c3fb75f0c6cf7b1f85968daedd4683e496e6215c83d36e984", .Okay}, + {.Shr_Signed, "c75ddd5e64021fd68afcb5471f8bb994dcd547438d654c8c5d68f0d1735d2532f0d67b142db66d7cfb9e3ab8a12dbed673c3694ba406198d3769b271e823f2c3302fdfc07b38c1e72ea933658951fa3aac9ffad83a512029c4c69c894c4f2bf63f607c638a6527f890a18df1451d3fa70c174613aaf6f53c681d4256a9f18f70af94fcdd47c1c01edbb962d45c492ad628de1a89820dbda683ffcd96cc4053eb118b39f6083ede7401da6bbb8bec3af86fbf213ae60cb2df2fa86d510b9412dfad22c0dc2a752c71c93b1d9eb1eccf62e9563cbb8f757d62238d488aa378c9035db384774fd4276c6fb0ee78ca12a951f0e425163e142543b3d239e83e8b8c303b379634629fb496de53c72e387cc1710c90a0d3b779d6beafbb1a7748da8aa1d76123866d94c30745706378edb25895362585b15dc80c14eae54e325f674d41187d2dff29689cc616814075e96fdc2f46f0f674da9d70597ef46d4e2ed8b20d8b34e3b2dea1d5f4833a9628a352e79ba3240933c6fdb3394316f397fc73dbe49787fb015a151d261a77ad05c1a9ba0d9d47906eb4d345a5fc33f38108ae6310aa33caa092c0e3c1fa7ebb2a44d1b0794035f1b8e44bd318df388f0d6d3ffbf41d82ee93e92120bb4fc06df1cc781eb06afb50a55a5261378ec210112996103674a8bab8366c7de19f3c2da5134fbdae1de8f6a4e55cd6316c9071ef24b003a1", "17", "18ebbbabcc8043fad15f96a8e3f177329b9aa8e871aca9918bad1e1a2e6ba4a65e1acf6285b6cdaf9f73c7571425b7dace786d297480c331a6ed364e3d047e586605fbf80f67183ce5d5266cb12a3f475593ff5b074a24053898d3912989e57ec7ec0f8c714ca4ff121431be28a3a7f4e182e8c2755edea78d03a84ad53e31ee15f29f9ba8f83803db772c5a8b89255ac51bc3513041b7b4d07ff9b2d9880a7d6231673ec107dbce803b4d77717d875f0df7e4275cc1965be5f50daa2172825bf5a4581b854ea58e392763b3d63d99ec5d2ac79771eeafac4471a911546f19206bb6708ee9fa84ed8df61dcf1942552a3e1c84a2c7c284a8767a473d07d171860766f2c68c53f692dbca78e5c70f982e2192141a76ef3ad7d5f7634ee91b51543aec2470cdb29860e8ae0c6f1db64b12a6c4b0b62bb901829d5ca9c64bece9a8230fa5bfe52d1398c2d0280ebd2dfb85e8de1ece9b53ae0b2fde8da9c5db1641b1669c765bd43abe906752c5146a5cf37464812678dfb6672862de72ff8e7b7c92f0ff602b42a3a4c34ef5a0b8353741b3a8f20dd69a68b4bf867e702115cc621546795412581c783f4fd765489a360f2806be371c897a631be711e1ada7ff7e83b05dd27d24241769f80dbe398f03d60d5f6a14ab4a4c26f1d842022532c206ce95175706cd8fbc33e785b4a269f7b5c3bd1ed49cab9ac62d920e3de49", .Okay}, + {.Shr_Signed, "57e3ce4ab1992ae36aca75cde7d0f095670478907f7545ad78e31ff3b59fa18915f0aeafde57091e075620617f54e8e02dc844e7a391f32bc7e2d6e5e358b6bd69ed77f0c835d3383a9e128c671e5082753c4edc8cb24abc3ec32e6b669e388ad77afd7a8556a42b0062f911b198ed9b6ee51dbbadba4b08b0cc13814aa07294046825e4af6372a28ccc5b50a7e1601a561f10f52ddd00ab4bd8f8bda333171f6eab4ce8338ee559bfc22418ac7e3c00d91150fe7d2f5b35edf9262af21a7c36c090051d8cb6be5267ab4ef83d9ff9e0173e00a00a2bcfcd545d66cfcaa513728838d92aac4e3c4b26aea94fee80e22fd912e2a63f2ac3374b016db26fad108543cb5497ef74689b366f93ad526e06ec803cbb85839cf7b858235aa9976cef021637061c7ce6bb6fa7504823efbeb0e9e988bdb4d21aeee47eb03ebbcab22110b8654e46521a7530492245dfb33d835ee17f6d3f9287e0ed85df896611e8928bffefa8bff80375113370333678a2dafacc65a25b3ba69c554a7dc582baae68b593a410765fcd7b923c1467b918ff64e930238e45cfb9b3c0a78792059b6a955c404c3c9e122108374f88f9b4aa4eeb99622cba1b1de9aa4386520eda0afa371898926a051e5fe78560a27322eb86a1af0108a74dfd50a4749d881460ad4190c03cecf2888852208e1abc3d3586ca08c21199cd102956aeafc25b045b555e93be", "2c", "57e3ce4ab1992ae36aca75cde7d0f095670478907f7545ad78e31ff3b59fa18915f0aeafde57091e075620617f54e8e02dc844e7a391f32bc7e2d6e5e358b6bd69ed77f0c835d3383a9e128c671e5082753c4edc8cb24abc3ec32e6b669e388ad77afd7a8556a42b0062f911b198ed9b6ee51dbbadba4b08b0cc13814aa07294046825e4af6372a28ccc5b50a7e1601a561f10f52ddd00ab4bd8f8bda333171f6eab4ce8338ee559bfc22418ac7e3c00d91150fe7d2f5b35edf9262af21a7c36c090051d8cb6be5267ab4ef83d9ff9e0173e00a00a2bcfcd545d66cfcaa513728838d92aac4e3c4b26aea94fee80e22fd912e2a63f2ac3374b016db26fad108543cb5497ef74689b366f93ad526e06ec803cbb85839cf7b858235aa9976cef021637061c7ce6bb6fa7504823efbeb0e9e988bdb4d21aeee47eb03ebbcab22110b8654e46521a7530492245dfb33d835ee17f6d3f9287e0ed85df896611e8928bffefa8bff80375113370333678a2dafacc65a25b3ba69c554a7dc582baae68b593a410765fcd7b923c1467b918ff64e930238e45cfb9b3c0a78792059b6a955c404c3c9e122108374f88f9b4aa4eeb99622cba1b1de9aa4386520eda0afa371898926a051e5fe78560a27322eb86a1af0108a74dfd50a4749d881460ad4190c03cecf2888852208e1abc3d3586ca08c21199cd102956aeafc25b0", .Okay}, + {.Shr_Signed, "-103db04c92291076ff4593fd07f1814d3009193e78c87bb4348be634ecc865b8d4ad501dfd98aef802f627f01ef50a6ca656b920b6b5b891603a33db0ad01a49b9e6489cc2754bf7ac11cee15ce41e2ee9bc5f898afd4d7c597162ab88de46bc16c5ff4b43e4baf4c5b173ae8ff2c2471f2f2a7c0ca8ead2e76ee5d04821e2df8551828999e0bd6878f640422ff7425e820626330d6e35dd76a0186599d4697cc0ae2dd43f4f345f450ba9c85d32ae4345e3112fe34fe10a92d04c3b200b8927d88f78308dd78f49dd5c340d88eb6335be3381bbb7a003178b99a63f778554d349f312d1f415af4e2fca70af799373fd4bb86477603da3f8b6f27897cc5da253ccd063d36472fc0d128a07eb3d88fc601e884d4b17ec94f3c9f7dc34adc25e25e0091567319bdbcf07e1a601490edb5e6b74f6e73d81156a7824973cb3a0df589fe30d42c79397fde0f75408658b35c3b366c597b87d42e216950da93d28502fd80a08e4fd0f4ed16b07feb922c357044c1d61aa194c3ba24ea1064f8cf0a9e24073637200172ab061754df1cb1782f1a1ae8cd132fbff4b92c91995d9e6cc6e163be2a0694e7466709d8295630ea9e462368c4020cf0b0587ebd07d2c77ea86cf2ddf8878ed2ddae93e25e91fc7712ec5a49724961d621c5b4ad8d3e88cc3876d6ca31bc804bd50a5b421671b4e0e66cad009e7bb3d8fa5afc175ae878f8068", "10", "-103db04c92291076ff4593fd07f1814d3009193e78c87bb4348be634ecc865b8d4ad501dfd98aef802f627f01ef50a6ca656b920b6b5b891603a33db0ad01a49b9e6489cc2754bf7ac11cee15ce41e2ee9bc5f898afd4d7c597162ab88de46bc16c5ff4b43e4baf4c5b173ae8ff2c2471f2f2a7c0ca8ead2e76ee5d04821e2df8551828999e0bd6878f640422ff7425e820626330d6e35dd76a0186599d4697cc0ae2dd43f4f345f450ba9c85d32ae4345e3112fe34fe10a92d04c3b200b8927d88f78308dd78f49dd5c340d88eb6335be3381bbb7a003178b99a63f778554d349f312d1f415af4e2fca70af799373fd4bb86477603da3f8b6f27897cc5da253ccd063d36472fc0d128a07eb3d88fc601e884d4b17ec94f3c9f7dc34adc25e25e0091567319bdbcf07e1a601490edb5e6b74f6e73d81156a7824973cb3a0df589fe30d42c79397fde0f75408658b35c3b366c597b87d42e216950da93d28502fd80a08e4fd0f4ed16b07feb922c357044c1d61aa194c3ba24ea1064f8cf0a9e24073637200172ab061754df1cb1782f1a1ae8cd132fbff4b92c91995d9e6cc6e163be2a0694e7466709d8295630ea9e462368c4020cf0b0587ebd07d2c77ea86cf2ddf8878ed2ddae93e25e91fc7712ec5a49724961d621c5b4ad8d3e88cc3876d6ca31bc804bd50a5b421671b4e0e66cad009e7bb3d8fa5afc175ae8790", .Okay}, + {.Shr_Signed, "630a77d4df7b32d2f9e4bb75b54439611297a1398c109334439ad94483687b8d8fd8200f44fca18e729408c76e9a893b397f780fc147a144e7e99bb3a74e69002acc25c749ad81ff456c2901ddd7f428619becba0eac5105ef841f8e28cc046f3050da665f512ffea73a7fae6dd72015290f29ffdc86987ce38a69f574f04dbd449b0579b1ac60edcce573598f9e257ccf3a58bef1097f357d68c74d1bc5841eba521d3e6b956695e1b9b760e13599b33e9ca399fccfe9f51f1b310c479b8fd4734573a353cdd6e43e654843ec1599b68201895bbec2030068222f0db377d3da38fa1a956a5d086de0aff1f180a23c2944b6c8b95326a02bc0501bda7d2c5d0ac140787ee9c3bc227e7cec8ea6a62ebbb6e88519371f68cba27d35d149849b02647b1d7d0b192aafda4e25a186d0adb77d11f8379bbcbde241a9cae4eca81ebd3c3cdc41e56718e176da2a04fe3c69d38d38ed294dd6e7be6c886814a065ff86211bcb7b544e8eeee7ac7625f2210465a976b1371646e5575516661ee70c687e4daa1643d0d317b9d44d749899e4344a9920534ae27348f92980918f431d38f83dfe69a784fc8dcd481f3d48ed1c4e5d12d6f84cd9496ec4c59c6d29868244c52c1a8ebc039144f0779824277345faf42f6b74a54011f7fce9379bda0e0d23f6d0f4d13077aeedcdedbe1c40dd14a86ee1ef47ab4b9c5fb52610374b39498f4", "4f", "c614efa9bef665a5f3c976eb6a8872c2252f4273182126688735b28906d0f71b1fb0401e89f9431ce528118edd35127672fef01f828f4289cfd337674e9cd20055984b8e935b03fe8ad85203bbafe850c337d9741d58a20bdf083f1c519808de60a1b4ccbea25ffd4e74ff5cdbae402a521e53ffb90d30f9c714d3eae9e09b7a89360af36358c1db99cae6b31f3c4af99e74b17de212fe6afad18e9a378b083d74a43a7cd72acd2bc3736ec1c26b33667d394733f99fd3ea3e3662188f371fa8e68ae746a79badc87cca9087d82b336d040312b77d840600d0445e1b66efa7b471f4352ad4ba10dbc15fe3e301447852896d9172a64d405780a037b4fa58ba158280f0fdd3877844fcf9d91d4d4c5d776dd10a326e3ed19744fa6ba293093604c8f63afa1632555fb49c4b430da15b6efa23f06f37797bc4835395c9d9503d7a7879b883cace31c2edb45409fc78d3a71a71da529badcf7cd910d02940cbff0c423796f6a89d1dddcf58ec4be44208cb52ed626e2c8dcaaeaa2ccc3dce18d0fc9b542c87a1a62f73a89ae93133c868953240a695c4e691f25301231e863a71f07bfcd34f09f91b9a903e7a91da389cba25adf099b292dd898b38da530d04898a58351d78072289e0ef30484ee68bf5e85ed6e94a8023eff9d26f37b41c1a47eda1e9a260ef5ddb9bdb7c3881ba2950ddc3de8f56973", .Okay}, + {.Shr_Signed, "598dcd8dc43c7d3fb0c281c80817bf8e19b870c82c43aec37cf32b9c623bfda098115410ef2daef6a21ed9ccdd7af9c65648b99db12b0cdac6dc9ac75c6e74cef8757ad91daa8d9cdae32fb8aeff78936608d28c43c4e56d3f652e843008cf4343d38b3725550e6ae74e4262aa63c638b260feab86c744b142cae1b1652e4b5a65a5014f1e1664c5ec2164e6ea57dfb751203e4924e2b2db37a7de082714dda897f58d4e50b29ad093e21ecc8266f81e073f399f3990d72fc3cb15a5bd6d1e737b5def8ad35d2cd920182f2dce6d3a7ff0853c8b9f62e708c9cccd213679498193a6f302b0a51d4ba9906bf94bc4b2d3ba77f72be8d16ce8b53bad6f59e97f4a001a8783cec6b366ab0fdc84787e946f3b7b345ca537642a1879c0a88fc47ed0e790459de69c20652937d016315de41ba1eec14110383caa477ac6d1ee82a81fe2d75fd4372645b99f710825df2b047725ae2c572aef8e48a95bd66bb81e0c7c47141e3ee8af4efaa84794f1dc5b771ed63bba1a3238b6abb714ed28e985f6c7ae2584fad8badc5e53de84bf1d83626a19d9eebf3f81734470a2aa101ed0e44d009896b066f156e40f1f17f40e3b704019dde14ab728a69be5945f6187cb300bcf89d832163999458a590ac0f7294939f947d5c1c3158282938d9d8ed9ffebce65c066f787b29636ae02d6f8d5964c11d7eb60156cba230260d92f30798b50ec", "18", "598dcd8dc43c7d3fb0c281c80817bf8e19b870c82c43aec37cf32b9c623bfda098115410ef2daef6a21ed9ccdd7af9c65648b99db12b0cdac6dc9ac75c6e74cef8757ad91daa8d9cdae32fb8aeff78936608d28c43c4e56d3f652e843008cf4343d38b3725550e6ae74e4262aa63c638b260feab86c744b142cae1b1652e4b5a65a5014f1e1664c5ec2164e6ea57dfb751203e4924e2b2db37a7de082714dda897f58d4e50b29ad093e21ecc8266f81e073f399f3990d72fc3cb15a5bd6d1e737b5def8ad35d2cd920182f2dce6d3a7ff0853c8b9f62e708c9cccd213679498193a6f302b0a51d4ba9906bf94bc4b2d3ba77f72be8d16ce8b53bad6f59e97f4a001a8783cec6b366ab0fdc84787e946f3b7b345ca537642a1879c0a88fc47ed0e790459de69c20652937d016315de41ba1eec14110383caa477ac6d1ee82a81fe2d75fd4372645b99f710825df2b047725ae2c572aef8e48a95bd66bb81e0c7c47141e3ee8af4efaa84794f1dc5b771ed63bba1a3238b6abb714ed28e985f6c7ae2584fad8badc5e53de84bf1d83626a19d9eebf3f81734470a2aa101ed0e44d009896b066f156e40f1f17f40e3b704019dde14ab728a69be5945f6187cb300bcf89d832163999458a590ac0f7294939f947d5c1c3158282938d9d8ed9ffebce65c066f787b29636ae02d6f8d5964c11d7eb60156cba230260d92f3079", .Okay}, + {.Shr_Signed, "56e92812a6ee08826f66862d71d87eb97b2947e9c20a95b596bc57f7d381b6325aa1d3d53cc5a0d75880be65e5b3c543ffd0b8bd71d253debca5ddc22ab4bdabeb099ab6fe9aa5f720d45bf1b0f3b1cf1a809c6eccabcd34d6704be538c0685b7bb72f01a1381d936d73437c5e63faa5d604f1aecde8f067e4b93e8c87394888590f6497439420bcf13a7294233e8117d532ff4638e86fe4a074e18d41febf7c58030308b87c7566d8e4df56faae12ba84e5c40fdcd3b41d05287c92185a03a4c04b1d31c7e9b0535a5b28793902c52f59914fa2ac60db41d7f0fb3fab44fe8cabababc3fba2d032d240bbdbb5b408b8db964f4a81f27b79ac49ce58c9ee7e4d38b3d7eb0653ad9892b7f96d13ac414ed02bed0d51492b063d0bb20af8f6b7fdef0947c46dcde77b7909144d3250fd00948daffa3ecd380df43a9b1328465bb55a1368feeeb26b01d3435a812b0a3fcf97081b9f924c2043d47ded4b95bfe221dc410b090220ebaf4f62dc2fc1eca0853a91cd5c086e9dacaa57e7a8d1f48a5e130d3475b2df8b8fc597ef4cb827ee8116521201e374c3c663c919bef0a90b7ca9679891c0ac6eaef958e4c3b0f6a3c0105985415e29b33f6895b207a9897446c57738f3f051c98ec034964985fe0bdec4b0ef80b32d7b633c51faed2fdf833f03c37d278e506b5976b546ed765bcaaff6ef1066a7e49513c0637641787ec760", "7", "add250254ddc1104decd0c5ae3b0fd72f6528fd384152b6b2d78afefa7036c64b543a7aa798b41aeb1017ccbcb678a87ffa1717ae3a4a7bd794bbb8455697b57d613356dfd354bee41a8b7e361e7639e350138dd99579a69ace097ca7180d0b6f76e5e0342703b26dae686f8bcc7f54bac09e35d9bd1e0cfc9727d190e729110b21ec92e87284179e274e528467d022faa65fe8c71d0dfc940e9c31a83fd7ef8b006061170f8eacdb1c9beadf55c257509cb881fb9a7683a0a50f92430b4074980963a638fd360a6b4b650f272058a5eb3229f4558c1b683afe1f67f5689fd1957575787f745a065a48177b76b681171b72c9e9503e4f6f358939cb193dcfc9a7167afd60ca75b31256ff2da2758829da057da1aa292560c7a176415f1ed6ffbde128f88db9bcef6f212289a64a1fa01291b5ff47d9a701be8753626508cb76ab426d1fddd64d603a686b50256147f9f2e10373f24984087a8fbda972b7fc443b88216120441d75e9ec5b85f83d9410a75239ab810dd3b5954afcf51a3e914bc261a68eb65bf171f8b2fde99704fdd022ca42403c6e9878cc792337de15216f952cf31238158dd5df2b1c98761ed478020b30a82bc53667ed12b640f5312e88d8aee71e7e0a3931d80692c930bfc17bd8961df01665af6c678a3f5da5fbf067e0786fa4f1ca0d6b2ed6a8ddaecb7955fedde20cd4fc92a2780c6ec82f0fd8e", .Okay}, + {.Shr_Signed, "28e6ab4f8f392967609c261f9293a4329a1e301f809ea22faf6e83a86fc9e80ef8d659958e7374841658f0f90cc74a297c2ee8c8716e03052ef9c90128622dd81820f9ea823cbf040c4bf9148c3d613ca0425a59c63706037fc39cceebefe26fe2baf588039aede9c11ee91960a303c18c8d58b6b896f881ac5ae792ff4fb852d477e072f75b0911b0f5e188e09ba87dd0965e3b5f8880ea1a70956886c7753d147c7235bf93ada747ef3932c13bc02214989882eef5bd27b089333869ac68f94543da688946d2145d72f5106ae942610279327ee9cd4e5a84c4eb9af1a0eba4bf843b3fcd43f74bc6b08ba9e837c681d6ebecd7169d0aa135cb4105f8bd52ed5160457e8a5be5172f4f02943a7b1d5809fe69dbd5074145f85b3db0793cfe27f12573e574678f5cd3f073fc6230ed92736f16c660470afed1baff4fd30400df29b4d1145c791d88a7ea33366bdda98d5f4719091e6593dae7e54aebce53b9541b791bcbd3363fa33550b79c7aceb4779447959952643ff96e19ad7e6d610cfc241b9778b71bbb12961fc853837e757669693cbff894885e1cdcd318ef51211d2d1af5a08c26260ab91c7adcebe5f981ac17549f0d1b84408192f9b721c53b4a222060204ba56f33c07deb7be28bf14e77e2ee3856b1a78ae10cbc32de80ac7d7fccc0da8097dbcd41e3ede1881d118abcb9c659547c8dac8611d2413c0b415a", "39", "147355a7c79c94b3b04e130fc949d2194d0f180fc04f5117d7b741d437e4f4077c6b2ccac739ba420b2c787c8663a514be17746438b70182977ce480943116ec0c107cf5411e5f820625fc8a461eb09e50212d2ce31b8301bfe1ce6775f7f137f15d7ac401cd76f4e08f748cb05181e0c646ac5b5c4b7c40d62d73c97fa7dc296a3bf0397bad8488d87af0c4704dd43ee84b2f1dafc440750d384ab44363ba9e8a3e391adfc9d6d3a3f79c99609de0110a4c4c41777ade93d844999c34d6347ca2a1ed3444a3690a2eb97a883574a130813c993f74e6a72d426275cd78d075d25fc21d9fe6a1fba5e35845d4f41be340eb75f66b8b4e85509ae5a082fc5ea976a8b022bf452df28b97a7814a1d3d8eac04ff34edea83a0a2fc2d9ed83c9e7f13f892b9f2ba33c7ae69f839fe311876c939b78b633023857f68dd7fa7e982006f94da688a2e3c8ec453f5199b35eed4c6afa38c848f32c9ed73f2a575e729dcaa0dbc8de5e99b1fd19aa85bce3d675a3bca23cacca9321ffcb70cd6bf36b0867e120dcbbc5b8ddd894b0fe429c1bf3abb34b49e5ffc4a442f0e6e698c77a8908e968d7ad0461313055c8e3d6e75f2fcc0d60baa4f868dc22040c97cdb90e29da51110301025d2b799e03ef5bdf145f8a73bf1771c2b58d3c570865e196f40563ebfe6606d404bede6a0f1f6f0c40e88c55e5ce32caa3e46d643", .Okay}, + {.Shr_Signed, "5fbeed30cde1e2ba6b4615a86b1b2df0b4bffd554333ff238df10636d3bfbec7bf2fb94e9f87f1e1e38f24320f31f82d6041e9a5e86a6343d214bd149140e8a99c138c2114a4a925e2c32c681a0fa515c7058087425a69da41fee3f767b972d7a50f7bd9b69672d92172d6b49020dc1e62899b4ec194163ee02289924d23ad81f88ec0a672fdb7d01715beb1795bb31ab37d61ec6217934e11147618de19e562c3669c72bdf2819554ef563937b608f5a2ff7adbaa8fbcac8b5a4f8fc875c1c7b0667213cb88cb7e12ab4f712f59b5594ff17450a0a3d36735c7cd330cd529dbbec4e3d01b1d64a81b5340de6eb37b66750c49ccc3529c57554c7e3a7634be112f7c8aef02d5b8c6a393dc0baa247e1f7fde297e01f8310bbebdcabba7e8372e368dc32f447de7d1cb78d6f1804f21c94d07948bd9bf42eaa23eb04956ffa632b48402f470f54b2704a666c5127eb8eead168408d26a27c3b763587d3041d25b34e3aee36bbb4a041f716cf117966a76bc8d310d3a16ff30255876782be25bc04c78c9dbd251bf96894c1c016684453384f2887467dece79780403ac20e4bec1824fab9e423fb6accba2b921bc11bf595e51dc5fe719bac08593e5b0051cf2022715379a951f3d1676fb0c3c2e05210e5b596c03dbd5c29bb31be32e5c104e1f3a7b728dba19a977cdc869d430795e9dc5e8de79e5ec0ef23b25086e691cbea4", "4", "5fbeed30cde1e2ba6b4615a86b1b2df0b4bffd554333ff238df10636d3bfbec7bf2fb94e9f87f1e1e38f24320f31f82d6041e9a5e86a6343d214bd149140e8a99c138c2114a4a925e2c32c681a0fa515c7058087425a69da41fee3f767b972d7a50f7bd9b69672d92172d6b49020dc1e62899b4ec194163ee02289924d23ad81f88ec0a672fdb7d01715beb1795bb31ab37d61ec6217934e11147618de19e562c3669c72bdf2819554ef563937b608f5a2ff7adbaa8fbcac8b5a4f8fc875c1c7b0667213cb88cb7e12ab4f712f59b5594ff17450a0a3d36735c7cd330cd529dbbec4e3d01b1d64a81b5340de6eb37b66750c49ccc3529c57554c7e3a7634be112f7c8aef02d5b8c6a393dc0baa247e1f7fde297e01f8310bbebdcabba7e8372e368dc32f447de7d1cb78d6f1804f21c94d07948bd9bf42eaa23eb04956ffa632b48402f470f54b2704a666c5127eb8eead168408d26a27c3b763587d3041d25b34e3aee36bbb4a041f716cf117966a76bc8d310d3a16ff30255876782be25bc04c78c9dbd251bf96894c1c016684453384f2887467dece79780403ac20e4bec1824fab9e423fb6accba2b921bc11bf595e51dc5fe719bac08593e5b0051cf2022715379a951f3d1676fb0c3c2e05210e5b596c03dbd5c29bb31be32e5c104e1f3a7b728dba19a977cdc869d430795e9dc5e8de79e5ec0ef23b25086e691cbea", .Okay}, + {.Shr_Signed, "-e9ba1ebffba7506a033fae7d0ad97bb4f989364c4c835fe46281a555cb5ff54d7d71c1e3b1a6ac41363368d5d59f724687b9f8b3c6b1ac85b1103104e3ce8b01cd6bbf66acfa49bd973340e55f655137607a031aebb82c390490dbb4522ff444005791173f386168f358bc347e7a6c55afb5b532c1629454c7e654ba3f8ba316622a54295667493b4ef477f6e1979242b2ee2af461a54e909f4851977025c8076bbae67ad68dd3f8b93f6a45f3f894b3ce7f192211cd97418cfd96f0a34f80dc56e6b1157de94ba9954dbcd36593b606355e8d9234cebdf6ebe3b12830434d952b73f0a37aa39bb742915bc20b9ae0816472a476bcc34b5ac9d7087433432068b88e1253b80b5c56c0c95257161e3d749dca5a8f114c5d9e01dfa5a082ebb05ff11b63ba99f69716b4f74e147721c86028a080f780914893b859a792a442a9b8a026376ce5af73adddbe67600e65d225c8ed50343b8e295c1d328d7a944741ec6b5cc5da8ef0425b4c0f61b128c165598202cf1d83ff09761a369f4e95b1ce9ebf1c4be9078ebb1306ac6326f86994ee3256d4237af25560f8efbb1cff3cb3efcc156bc9a78691f9fe072fdd12674cee9963d5b94b4c2f5d6e6d8366a73ec7e96f3d3a0856105c15556a1bdd99ecfa84dea6704f125c34bdf3bb9d5dde27a52d44c50f9bf41b2d8a320fed82593c49e8dcc0f28956b90b1c8cd2ddfd30b8bde7", "5d", "-74dd0f5ffdd3a835019fd73e856cbdda7cc49b262641aff23140d2aae5affaa6beb8e0f1d8d356209b19b46aeacfb92343dcfc59e358d642d888188271e74580e6b5dfb3567d24decb99a072afb2a89bb03d018d75dc161c82486dda2917fa22002bc88b9f9c30b479ac5e1a3f3d362ad7dada9960b14a2a63f32a5d1fc5d18b31152a14ab33a49da77a3bfb70cbc9215977157a30d2a7484fa428cbb812e403b5dd733d6b46e9fc5c9fb522f9fc4a59e73f8c9108e6cba0c67ecb7851a7c06e2b73588abef4a5d4caa6de69b2c9db031aaf46c91a675efb75f1d8941821a6ca95b9f851bd51cddba148ade105cd7040b239523b5e61a5ad64eb843a19a190345c470929dc05ae2b6064a92b8b0f1eba4ee52d4788a62ecf00efd2d04175d82ff88db1dd4cfb4b8b5a7ba70a3b90e4301450407bc048a449dc2cd3c9522154dc50131bb672d7b9d6eedf33b00732e912e476a81a1dc714ae0e9946bd4a23a0f635ae62ed4778212da607b0d89460b2acc101678ec1ff84bb0d1b4fa74ad8e74f5f8e25f483c75d89835631937c34ca77192b6a11bd792ab07c77dd8e7f9e59f7e60ab5e4d3c348fcff0397ee8933a6774cb1eadca5a617aeb736c1b3539f63f4b79e9d042b082e0aaab50deeccf67d426f533827892e1a5ef9ddceaeef13d296a26287cdfa0d96c51907f6c12c9e24f46e607944b", .Okay}, + {.Shr_Signed, "-7c30674449df8cb9810b81b9dba268509f5c51ffb026a9f5daafa38b30a874c9461a00d7525588cac7e2cf7540cc1c6c9a22f47a30690ef8d238bc3d5a2f39402670932f3dd897e31bb4362e3221e53d70f570e07814a2c8bb12f4d0f54571394434da0d599ed08d5e280a30d1a6c69afa4d0f2a513ca5dca564640ad5fb86907cc7cb65beaa84137a17139e5289fcdfd53570cbd4a6d6a93723c2527ec905ad9880473892cf862576bd01d4f95d89815fa38887ed6ee55f16a1831c117239bda92bab9e14289638d46685e189e9f26f7ba96defb75e5354adaf85097794b8e988e54981510eefd80469e00ace3bf7e7d28370c9fbef6a64b388568588e183f882c147c6e70b0946f7cabaf43b306149821bfee3b258fdcfcffb24d3daeaee6cba7f4747ea0bb73dce04b89923507b650766c89bfe69543ea590e00c600f1dfb842b843985175f34597e3f1aec70a9df4210848bce45d539c9298b6388c17cf9fdf31a59b37635d63cec434a8902ab62e39e0ce85ae2686b3d5eaa11cacbd3b61a2960957edc891d36f7b0e96ad2d2fbf94076071a99d8e8d97a5408406ff03c58ae6507ce179eb77a7790247540bc0e69211224d5f1f09ed0ba0a13eb9ef53f97833dbea22b9d6d98ce4912a86bb29c3294080a1220600360a7faf44db3322ddd6fae002616f3236e36c7faf00436650880ee662f4086683f051ed379fb3d77", "2b", "-f860ce8893bf197302170373b744d0a13eb8a3ff604d53ebb55f47166150e9928c3401aea4ab11958fc59eea819838d93445e8f460d21df1a471787ab45e72804ce1265e7bb12fc637686c5c6443ca7ae1eae1c0f02945917625e9a1ea8ae2728869b41ab33da11abc501461a34d8d35f49a1e54a2794bb94ac8c815abf70d20f98f96cb7d550826f42e273ca513f9bfaa6ae197a94dad526e4784a4fd920b5b31008e71259f0c4aed7a03a9f2bb1302bf47110fdaddcabe2d43063822e4737b5257573c28512c71a8cd0bc313d3e4def752dbdf6ebca6a95b5f0a12ef2971d311ca9302a21ddfb008d3c0159c77efcfa506e193f7ded4c96710ad0b11c307f105828f8dce16128def9575e87660c2930437fdc764b1fb9f9ff649a7b5d5dcd974fe8e8fd4176e7b9c09713246a0f6ca0ecd9137fcd2a87d4b21c018c01e3bf7085708730a2ebe68b2fc7e35d8e153be842109179c8baa73925316c71182f9f3fbe634b366ec6bac79d88695120556c5c73c19d0b5c4d0d67abd54239597a76c3452c12afdb9123a6def61d2d5a5a5f7f280ec0e3533b1d1b2f4a81080dfe078b15cca0f9c2f3d6ef4ef2048ea81781cd2422449abe3e13da1741427d73dea7f2f067b7d44573adb319c922550d76538652810142440c006c14ff5e89b66645bbadf5c004c2de646dc6d8ff5e0086cca1101dccc5e810cd07e0a4", .Okay}, + {.Shr_Signed, "7998f400499c966d35597c6446935cc0da5351f940b5496959eaa191c6acc17ee4191531b6b78cc33240dcfe789c5eba5d5f2897492c9238c79b03980673f315ef4de561fdd4c911c8c739006bceb825a759c41768567d9a9a967671da28803aa33473ce3d6007729263e0b12f9bfcbe4f17737f843d0ffecb355ae5927107940093bd22aa191f8df387ede146ba4de6d0ac09f1223bf152898656e1b06089842ed828858afabca9d8f2ae233ff77b4d9b20688736a9b565e211a94d86dd6893dccd829af5f6960e1c20a21b77df993acbc5dfb2ec010729f8b1b7cc5d9f90ea3b6e0965f237c33d7d35bf60a3cdacb658d1099d4ff369e6bba1b7d2965cc37b550400a45ed0c7cf1b36858eae29893a7a329596d1ea3192b37f006a322040c9519b1170cc8a73727756623771777e6b2a5a56d4831f70d6a1a4108679ecf4d14b371e34ef662756b82b4cd0f829ab552631f3de5d9d313f819b0dba4ae0db34a87679448cf6d6027831917c329684c87d6096a1e40735f49c069af5bf64f247f2e86e71e9e7e31a238e9c9dff0be451f7ed1935b4ed63dae2bb7370ec68c0d4d51d68a8bbed7f7b1aa4aa6f93db55a8171a9a7a1ca440e2aeb3094b3d0a1b0ab477e31dec59d725e8daacabf8d66fb0634025aa1fe566a61a557d7fe0c887d01e16e8aa32e56e96aed631fcb496ec7ddc3d22088b2a9564022bce7454695e6c", "11", "3ccc7a0024ce4b369aacbe322349ae606d29a8fca05aa4b4acf550c8e35660bf720c8a98db5bc66199206e7f3c4e2f5d2eaf944ba496491c63cd81cc0339f98af7a6f2b0feea6488e4639c8035e75c12d3ace20bb42b3ecd4d4b3b38ed14401d519a39e71eb003b94931f05897cdfe5f278bb9bfc21e87ff659aad72c93883ca0049de91550c8fc6f9c3f6f0a35d26f3685604f8911df8a944c32b70d83044c2176c1442c57d5e54ec7957119ffbbda6cd9034439b54dab2f108d4a6c36eb449ee66c14d7afb4b070e10510dbbefcc9d65e2efd976008394fc58dbe62ecfc8751db704b2f91be19ebe9adfb051e6d65b2c6884cea7f9b4f35dd0dbe94b2e61bdaa8200522f6863e78d9b42c75714c49d3d194acb68f518c959bf803519102064a8cd88b8664539b93bab311bb8bbbf35952d2b6a418fb86b50d208433cf67a68a59b8f1a77b313ab5c15a6687c14d5aa9318f9ef2ece989fc0cd86dd25706d9a543b3ca2467b6b013c18c8be194b42643eb04b50f2039afa4e034d7adfb27923f9743738f4f3f18d11c74e4eff85f228fbf68c9ada76b1ed715db9b87634606a6a8eb4545df6bfbd8d525537c9edaad40b8d4d3d0e522071575984a59e850d855a3bf18ef62ceb92f46d5655fc6b37d831a012d50ff2b3530d2abebff06443e80f0b74551972b74b576b18fe5a4b763eee1e910445954ab20115e73a2a34", .Okay}, + {.Shr_Signed, "-937b061093c615d44c8d6e5884edbfaf7fdfb9e52e7a0d09e08f6ba50570f068333945e9eb8dc6e41d46b4e30b8fc0eb8028844bdaeddbf3fab1bfb0297a0da92b0e9e6cf678458c2d03044fd6b94965bc65d2d34c144882a2c8bcb9838908919269ea519b9379fa30f7baa0d85078b61a00b0e48180a575a79da6429b5d962af7b98b607e79407b3114f638bc12718f5e3e051b2dde1e8b2400d672dbe1210809489ab5127319b1d5dd18f18f23facf0f356a6aa59dc63288155871cee48a4d3ed5d4875a639b09ae82b785b9e61c5fb1eb352702ab8e65a1d20ac9ae23c8069752a1fd9b0317763199df4b2dd7c01ac354b32c805e3f260b4d1cff3cf2a4fb0ae83e7957842168b8a8b89e246e0e71aea9554ea91848d1d17b8e84a45c3f7281689683dda5592e097a0b7484016db35d4da1de8cd351333794739d2c11a4ef662155fdb51f9f39b5981cfd4ed26d0dfeb4689a04bbb2888b195a9c44d0c31019ebcfffdabb505cb781afced4dee7f03b58324484d4b28ad2e2ba1de35ea7d0be2dda829ea25ccc1ca2a5e7820dd7ab2c5441671045fd2b1c35370cbb2bbc77fec2a4ffa5a81f0beeca01b28ab7393a4b930561c7124fc8d62d4cf99a998661b6702ffe42b74067efe3635adcf28e729c97c6b0d83dceb7ab652426428448afbf9fca7188ef41986acaeb2148a4efa30937ba5ff288eef073d6a5aaef9dcae4", "14", "-937b061093c615d44c8d6e5884edbfaf7fdfb9e52e7a0d09e08f6ba50570f068333945e9eb8dc6e41d46b4e30b8fc0eb8028844bdaeddbf3fab1bfb0297a0da92b0e9e6cf678458c2d03044fd6b94965bc65d2d34c144882a2c8bcb9838908919269ea519b9379fa30f7baa0d85078b61a00b0e48180a575a79da6429b5d962af7b98b607e79407b3114f638bc12718f5e3e051b2dde1e8b2400d672dbe1210809489ab5127319b1d5dd18f18f23facf0f356a6aa59dc63288155871cee48a4d3ed5d4875a639b09ae82b785b9e61c5fb1eb352702ab8e65a1d20ac9ae23c8069752a1fd9b0317763199df4b2dd7c01ac354b32c805e3f260b4d1cff3cf2a4fb0ae83e7957842168b8a8b89e246e0e71aea9554ea91848d1d17b8e84a45c3f7281689683dda5592e097a0b7484016db35d4da1de8cd351333794739d2c11a4ef662155fdb51f9f39b5981cfd4ed26d0dfeb4689a04bbb2888b195a9c44d0c31019ebcfffdabb505cb781afced4dee7f03b58324484d4b28ad2e2ba1de35ea7d0be2dda829ea25ccc1ca2a5e7820dd7ab2c5441671045fd2b1c35370cbb2bbc77fec2a4ffa5a81f0beeca01b28ab7393a4b930561c7124fc8d62d4cf99a998661b6702ffe42b74067efe3635adcf28e729c97c6b0d83dceb7ab652426428448afbf9fca7188ef41986acaeb2148a4efa30937ba5ff288eef073d6a5aaefa", .Okay}, + {.Shr_Signed, "319b0af6190649a6fc8064f93f6a75f1c378c0c54e1817757e2b61c139877b4086d568eb1a1a3e09bc4e3203f390978af1d81194534c35f7caa73ff567c61d98be6eb81ce4e2df50995a59617a742e2ef8329adf13e0c0fcb99ed0f02c32d0ae7f3663de86eb9df05d50dd11947e087c9b19ddba3fc6e5060ec123a8a8bc0a1a22b5c967611d673e90f28648ee16b4cab7facdd79fc635fbc6501629bf2cd6e2410151b2a9da4982b32fd1ca0f739fce2d5f17a54871ad30f96c7bba75cc0fc5b7033e13660f29454d26bc4941206fbeae577782a48a88366e1c51005e9ca2d40be694741e87c193d92eb9dbe616a8aca2bb5e78ebc8d2f15f309019c3bec1e728b01aaa9aab9987642a937c8b42e51d954c5b470ca78f6bbb17b568446f96109a51ea63b81dad13deb8a77181df8751a3d72a36075ea82e7cbe75e747a2b3bee8df96ef50fa2aaa26ae08c792336928366e9749d734381706a49510d77da4fba22b341bc447434fdc221a3add16760611238e00b30fc3cedc98e32c55aab62969778c1355d44d5f42dbe79f8f823a9cfacda37e8911075cfa1641463e54032a684263c1cde0ceb14edb3e2721e6e077618d0deaefdb22d87c8e50f265f9bc251d1cac3e87d646e8cb14a83a70d21a39dcfdadb0da0da3304dceab47fba3201b21490b2c786559203de9ed181fbb0e237639883f858a634c940370069ee19680", "61", "18cd857b0c8324d37e40327c9fb53af8e1bc6062a70c0bbabf15b0e09cc3bda0436ab4758d0d1f04de271901f9c84bc578ec08ca29a61afbe5539ffab3e30ecc5f375c0e72716fa84cad2cb0bd3a17177c194d6f89f0607e5ccf6878161968573f9b31ef4375cef82ea86e88ca3f043e4d8ceedd1fe37283076091d4545e050d115ae4b3b08eb39f48794324770b5a655bfd66ebcfe31afde3280b14df966b712080a8d954ed24c15997e8e507b9cfe716af8bd2a438d6987cb63ddd3ae607e2db819f09b30794a2a6935e24a09037df572bbbc15245441b370e28802f4e516a05f34a3a0f43e0c9ec975cedf30b5456515daf3c75e46978af98480ce1df60f394580d554d55ccc3b21549be45a1728ecaa62da38653c7b5dd8bdab42237cb084d28f531dc0ed689ef5c53b8c0efc3a8d1eb951b03af54173e5f3af3a3d159df746fcb77a87d155513570463c919b4941b374ba4eb9a1c0b83524a886bbed27dd1159a0de223a1a7ee110d1d6e8b3b030891c7005987e1e76e4c71962ad55b14b4bbc609aaea26afa16df3cfc7c11d4e7d66d1bf448883ae7d0b20a31f2a0195342131e0e6f06758a76d9f1390f3703bb0c686f577ed916c3e47287932fcde128e8e561f43eb2374658a541d38690d1cee7ed6d86d06d19826e755a3fdd1900d90a485963c32ac901ef4f68c0fdd8711bb1cc41f", .Okay}, + {.Shr_Signed, "12aef241eb782bb091874f87ccc9341bd29351697bcb95bac2d9c1adad1070b9c2cabd2349768785b847294652ee1ec9ca288ca7d3a4c809b2251c0b46c59df1f420092c7a1b83fa17384af8634ab8f20b06840c84bd4660c0d0132d9f652c1886c3772991bb17b239e8fe6ed4f4dcda07201c1646430a8ef35cf5990d9a615bf78462562c2fe4c34de356ea000e9a7ab76b675e222929e95fe7b3391d78b03020388b63bfb97c598e153c6a9335ea1928b920a4adaaa60c76e97cc5c2bbd67fd8e9cad8864dfd375e8be245804c7922f86dd7460d41f37b7df62455051dfaff4a76bb6e028313174fbf195c8b17dbda7bd85db181c91e120585ca36750032adb918945fa22cc39d689aea2b455a0a98d66a0abbfb21d196c16cb7fee21b2f94059582c3e30def938718c2a69be002723462e4e2076fa5a6db53e98f5ecd0de604e1121933c94b780f62a9cb0120874ede9d9ad7d33c79c5ec50e2e4f200e079b202e7d7a1e3f2e8ac91e284d0447aee5896a16a24b983f235ad2fd0dd72fb569323848025f5d2f86a8493cb63fd2ed8d0732318ca09afab4cbf91b6669789b89e84f122fe0e9044f86e84f21e41297618e66bfbed0101a90e93dfcf7c7c666dabe27bb5ef03dda322e2744c861995414b3d01328e7cfdb380588d1070992c307edcdd28a6c808284a6f42380a085989e341fdb878de08031a9eb12df422585b", "4f", "255de483d6f05761230e9f0f99926837a526a2d2f7972b7585b3835b5a20e17385957a4692ed0f0b708e528ca5dc3d939451194fa7499013644a38168d8b3be3e8401258f43707f42e7095f0c69571e4160d0819097a8cc181a0265b3eca58310d86ee5323762f6473d1fcdda9e9b9b40e40382c8c86151de6b9eb321b34c2b7ef08c4ac585fc9869bc6add4001d34f56ed6cebc445253d2bfcf66723af16060407116c77f72f8b31c2a78d5266bd432517241495b554c18edd2f98b8577acffb1d395b10c9bfa6ebd17c48b0098f245f0dbae8c1a83e6f6fbec48aa0a3bf5fe94ed76dc0506262e9f7e32b9162fb7b4f7b0bb6303923c240b0b946cea00655b723128bf4459873ad135d4568ab41531acd41577f643a32d82d96ffdc4365f280b2b0587c61bdf270e31854d37c004e468c5c9c40edf4b4db6a7d31ebd9a1bcc09c22432679296f01ec5539602410e9dbd3b35afa678f38bd8a1c5c9e401c0f36405cfaf43c7e5d15923c509a088f5dcb12d42d4497307e46b5a5fa1bae5f6ad264709004beba5f0d5092796c7fa5db1a0e6463194135f56997f236ccd2f13713d09e245fc1d2089f0dd09e43c8252ec31ccd7f7da0203521d27bf9ef8f8ccdb57c4f76bde07bb4645c4e8990c332a82967a02651cf9fb6700b11a20e1325860fdb9ba514d90105094de84701410b313c683fb70f1bc", .Okay}, + {.Shr_Signed, "-e5c26cdf342cb5e680c5b8fdee7b882990fd1bc577038e5b587d0d1cc4bf4dc35f0f6a85a6a109b3e9563bc29bc11542a47b7f28c65d3c235b1a9ccc20bbb434ab5403b1d43ef16ed1066349112c9eeb0317a5150efe122de1e33195f2e19b90a0e785fd6907f532f574b07eb99f8a3805de9ad9de27f976404e158ac5cb0fc511f2be7745e8e2ea47cb9657cc3b79ed4c11fbe6ac945c3b0411dce2ec94e9630753e0307b59a4b6dd3553c2c5b302bc1d39531b60c5a2af526d18f71f059098f7608062e9275768fd8f6ca991bd4115d3d491053db513e52bc44ed36a1ac1e2eaa479865762079d5c7c3582670f8532fa37ef03bcffc1ebf1665240d5dc8f08898075538bd179d70575ce0e901445aa8a5eaab3d0549b207314e54fa7493c22dc468fb638bae9dcce7a3b5b22d8f0a5f7389c22962e50cea65bdf8c9fe3cf474f9a02e6959c6fb7cbbf3f2b672a5df631f388e15deae0e7f1111aef486c059ae652c52a2a555690c829684c56f49143b9a8f1c2ba3ce0e8faf91664764a426257136de3e9e39685052d8a542750932f8d689c5fa61879f4296594a99c9af98980fafcbfdd40a54105f8f5ea6aa54d32a1261fe7f835da53e81c0761693db627732db86ad0f1609783089c605a1212c6832186754627707d1d5c396367f716290643230e09f89efa2e78387ee50430bc3dca7a14e4abce0e3446b339bfbd6d84", "51", "-72e1366f9a165af34062dc7ef73dc414c87e8de2bb81c72dac3e868e625fa6e1af87b542d35084d9f4ab1de14de08aa1523dbf94632e9e11ad8d4e66105dda1a55aa01d8ea1f78b7688331a488964f75818bd28a877f0916f0f198caf970cdc85073c2feb483fa997aba583f5ccfc51c02ef4d6cef13fcbb20270ac562e587e288f95f3ba2f4717523e5cb2be61dbcf6a608fdf3564a2e1d8208ee71764a74b183a9f0183dacd25b6e9aa9e162d9815e0e9ca98db062d157a9368c7b8f82c84c7bb040317493abb47ec7b654c8dea08ae9ea48829eda89f295e22769b50d60f175523cc32bb103ceae3e1ac13387c2997d1bf781de7fe0f5f8b329206aee478444c03aa9c5e8bceb82bae707480a22d5452f5559e82a4d90398a72a7d3a49e116e2347db1c5d74ee673d1dad916c7852fb9c4e114b172867532defc64ff1e7a3a7cd01734ace37dbe5df9f95b3952efb18f9c470aef57073f8888d77a43602cd73296295152aab486414b4262b7a48a1dcd478e15d1e70747d7c8b323b2521312b89b6f1f4f1cb428296c52a13a84997c6b44e2fd30c3cfa14b2ca54ce4d7cc4c07d7e5feea052a082fc7af53552a69950930ff3fc1aed29f40e03b0b49edb13b996dc356878b04bc1844e302d0909634190c33aa313b83e8eae1cb1b3fb8b148321918704fc4f7d173c1c3f7282185e1ee53d0a7256", .Okay}, + {.Shr_Signed, "5190079832ee3f50cc7c991f6a72d8fe80fed12358506a71ccb97aa75a90031c472426ff95690ead0eb80d9df0efd7f93bde40f9e14a0fe83f20d1377208cd15b89a9e9f74c389aa8e3cec8143a4efc39d96d0609cfdbaeadd96542d95ca2be0f1cc8d4ab0436770d0bc08b0f0b1c01b116a0d334ca6d3920ce75d620afca557c51d7e35e14c455503a9bc1f0b436659991c538125a737f58c1855093e3cbad2d51bc4e45b97eeb65af9a24a293565be616c2b0d8fd7b9fa8615a00779701aad0c54737c8f4e3a2965bb9c6d7820d75011f8f9a40fe8150ef8a054261c523c6ad0235e38215b684a5e65a1d5e0bfcee3feca69e1489cd305b245ca4459ca630c2c2146ad018162bfb00238a744f1555a83d66a3a0a33ef7fb09eb2bc098436eb5711c628e19ef96a63377baf08ed272effd4a61d6a8495a8d3e5bc585120d7a90044de9b2bdd3310ed4dcbbf11506fdab7ef93a4b03c7ea6056c951e23c31e1f7de60a53a5704117d31e1588a0153fb6aa9ad4c4a67f1600e22926fb9cbe5544989d88d7c087ce8e3dcc191c34056e9bed32338d4282394fea8ee7fd80c29d0e5204164e126728022f05310c02da3b00f7aefc9c9393384724e15a9ab673747bd4bfa0ee2d37691b6a581b9069ed4fbed2211f25f4e12b3e522ceba6ef143fef12fc8ca23c9ca8f95f875a46e7a137ffc420ba944fd553b3841b8f28d9a1b8b6", "54", "5190079832ee3f50cc7c991f6a72d8fe80fed12358506a71ccb97aa75a90031c472426ff95690ead0eb80d9df0efd7f93bde40f9e14a0fe83f20d1377208cd15b89a9e9f74c389aa8e3cec8143a4efc39d96d0609cfdbaeadd96542d95ca2be0f1cc8d4ab0436770d0bc08b0f0b1c01b116a0d334ca6d3920ce75d620afca557c51d7e35e14c455503a9bc1f0b436659991c538125a737f58c1855093e3cbad2d51bc4e45b97eeb65af9a24a293565be616c2b0d8fd7b9fa8615a00779701aad0c54737c8f4e3a2965bb9c6d7820d75011f8f9a40fe8150ef8a054261c523c6ad0235e38215b684a5e65a1d5e0bfcee3feca69e1489cd305b245ca4459ca630c2c2146ad018162bfb00238a744f1555a83d66a3a0a33ef7fb09eb2bc098436eb5711c628e19ef96a63377baf08ed272effd4a61d6a8495a8d3e5bc585120d7a90044de9b2bdd3310ed4dcbbf11506fdab7ef93a4b03c7ea6056c951e23c31e1f7de60a53a5704117d31e1588a0153fb6aa9ad4c4a67f1600e22926fb9cbe5544989d88d7c087ce8e3dcc191c34056e9bed32338d4282394fea8ee7fd80c29d0e5204164e126728022f05310c02da3b00f7aefc9c9393384724e15a9ab673747bd4bfa0ee2d37691b6a581b9069ed4fbed2211f25f4e12b3e522ceba6ef143fef12fc8ca23c9ca8f95f875a46e7a137ffc420ba944fd", .Okay}, + {.Shr_Signed, "-388d31eea8125c1c797517efe2c86f1022eff3c40c96c074b72f2d702e6973274843be2b70d35960c7963656542b12e4912a0f18021fefb542eb775ddac0565596d98706ff93445ebb22da98dca55ea755bc8ceb9f38f7b20e270c49c87bad1b3dc742a263775ee91fa5168f2fc38f6b7fefbe7632aed7e3d887ee2d976c840518ba2c7bec962063f92130d8d239fa9fe280c67e2fc994a9b919b5408a4b0f537d9e06348a06b5be7172539799d346e4399800e079e6cdaf5f67b6f8f87fea6af472edffed5f9423234ee790fbb00c6125da69e0402730395b2a9432688c06d33dfe88ff24e25cdd664f20ff820c6785ba08bac8949ad527e999554b1d0b96067f57e062a4dae3e0d51f912d9af926f72ba30261edfd33e4326b71aa9fc0fe370c46ff4ddd6f68417515ae98e8c34ad70082af0d64946fd35890b0b8bd5c58de41fcf0712b57d72b5e8b4c1407f346b9afb24739a66262c6970c2ee58fde521319a40709a6fb516f4d0769d488d12ad13bdbed1126fb0d7d1807d4a441b7a4524d33e1d6c5b700fd5c79f8cc98545dcaea660c7e013abf2cd4880f96d2be29ea004683363a45dea1c9e377d9cc991d7c87a612ed45f4b9e34cc6cea0b9023129098388e25937d75006b69cffab403e76157a0c6dd4dd28bdcb72cb7d71d5a2e939b748dc87d1bad5fd8be73d442e11ec19513c66292422e36f88d71553e61f61", "46", "-e234c7baa0497071e5d45fbf8b21bc408bbfcf10325b01d2dcbcb5c0b9a5cc9d210ef8adc34d65831e58d95950ac4b9244a83c60087fbed50baddd776b0159565b661c1bfe4d117aec8b6a6372957a9d56f233ae7ce3dec8389c312721eeb46cf71d0a898ddd7ba47e945a3cbf0e3dadffbef9d8cabb5f8f621fb8b65db2101462e8b1efb258818fe484c36348e7ea7f8a0319f8bf2652a6e466d502292c3d4df67818d2281ad6f9c5c94e5e674d1b90e6600381e79b36bd7d9edbe3e1ffa9abd1cbb7ffb57e508c8d3b9e43eec031849769a781009cc0e56caa50c9a2301b4cf7fa23fc93897375993c83fe08319e16e822eb22526b549fa665552c742e5819fd5f818a936b8f83547e44b66be49bdcae8c0987b7f4cf90c9adc6aa7f03f8dc311bfd3775bda105d456ba63a30d2b5c020abc359251bf4d6242c2e2f571637907f3c1c4ad5f5cad7a2d30501fcd1ae6bec91ce699898b1a5c30bb963f79484c66901c269bed45bd341da7522344ab44ef6fb4449bec35f4601f529106de914934cf875b16dc03f571e7e3326151772ba99831f804eafcb352203e5b4af8a7a8011a0cd8e9177a87278ddf67326475f21e984bb517d2e78d331b3a82e408c4a4260e238964df5d401ada73fead00f9d855e831b75374a2f72dcb2df5c7568ba4e6dd23721f46eb57f62f9cf510b847b06544f198a4908c", .Okay}, + {.Shr_Signed, "833890ea04ba373472c681b2f180c4830ea9b5ac32480bfb718aa1e89f82be247df16b6de4af39f99fe1d15b66ceaaf9c9f5c6f6afbdb5da9de63651c712a8816a9ad55b52695e623727a5ea6deaabde2bf278dcd2e6d1873dabd3459bdccb51b09200b8209dfd1285c18a32aebf2ecd587512e10fa247ce0438bc4881c25e0cfc401f77748d229ab12085cad03920ce5639ef3047d3b7722a827994453c5d9bfe977ba1f103a6b46ab0361492db690e4ca7ee0fac4466f574e6ef02b28fdf4e98a6a6eacc11de2a304df957f42e7fc728c2efa76c7907fca15e221f8a1aa0278015b06d6fa27829a4a84e3783fe9ac59b441b375632ae76cc382237af7129922cfbf1026afce39facad281dbbc714418d3046daa52b0446442dfe2260a5e3fd0b088103d3be58260898ddb15994784a51d954d55d464a21040f023a72b32ccef326719ecd19e9149aa8e99406e21775b5fd0489af1dbd3bf9bcb53c20a9d2a208e8384fddaa11279d8d5afb498ebce95381d60b19951740480140166ac3c845209505dc2068ab834794d77cb0690ec21f984c8774f09fcf73dae809bb32f321cbf12881fa010ac2f728d9db70380d6d7e2f69c838a50184c3ecc12f438835f98e154cd79528ac0ee66ef81650d1b00d343cd7541ccefcc9da899527c0d892df742b3f43aa94145354341946b463a6a42189e917539b5e270e75df9448325398", "13", "1067121d409746e68e58d0365e30189061d536b58649017f6e31543d13f057c48fbe2d6dbc95e73f33fc3a2b6cd9d55f393eb8ded5f7b6bb53bcc6ca38e255102d535aab6a4d2bcc46e4f4bd4dbd557bc57e4f1b9a5cda30e7b57a68b37b996a361240170413bfa250b8314655d7e5d9ab0ea25c21f448f9c087178910384bc19f8803eeee91a453562410b95a072419cac73de608fa76ee45504f3288a78bb37fd2ef743e2074d68d5606c2925b6d21c994fdc1f5888cdeae9cdde05651fbe9d314d4dd59823bc54609bf2afe85cff8e5185df4ed8f20ff942bc443f1435404f002b60dadf44f05349509c6f07fd358b3688366eac655ced9870446f5ee2532459f7e204d5f9c73f595a503b778e28831a608db54a56088c885bfc44c14bc7fa16110207a77cb04c1131bb62b328f094a3b2a9aaba8c9442081e0474e566599de64ce33d9a33d2293551d3280dc42eeb6bfa09135e3b7a77f3796a784153a54411d0709fbb54224f3b1ab5f6931d79d2a703ac16332a2e809002802cd587908a412a0bb840d157068f29aef960d21d843f30990ee9e13f9ee7b5d0137665e64397e25103f4021585ee51b3b6e0701adafc5ed390714a030987d9825e87106bf31c2a99af2a51581dccddf02ca1a3601a6879aea8399df993b5132a4f81b125bee8567e87552828a6a868328d68c74d484313d22ea736bc4e1cebbf28906", .Okay}, + {.Shr_Signed, "-28e569e25eb0896740e990649712256eeddab13f50a0c580b077ba48fff65879dd4db68ce68b436d70fe5e672dcd8e347d750b06a1308484dd0520bb1a32455e5d78f19bc1b588e20a8d547863c01ab5eece29216b60117984cf8cc6036eb8b23785f49dd4cb8f7d68136a430595b747287960d038ee15c759b67ed175605148b37cfc72b93faa2fd8f0482311c02bff9920bfa09f0f4e0dfef5656ae45a60367febd4843c966782c265130dbf60af3c80252087ea2a3acbdbb4e43d3b29748a68fa60910e3f5a0847a40f61fe1af6911bc639f4b8dbe0556689cfda9694a31f0b86c2c26b4e13c7626f2576e1d155bb1305da24eafebb137f87862bb39611a33af48dd71529cd3a5720b8cdaac193b900edaec298af1f4a0d80b357d92cf7373d0b93539715b776e20148089d0ae4ffc1de967bce15feaf891bdd89ef809f5292d89a279fd91145dd269df41af59a4737c4834782fa7603ecbef8fc4cc159db8f7b7447cb7e5d9cf3cbbcafe6edf75330264b68832c18abf069d8346be8581ca59f93b21fb2c944d0410c1170a573eb513adf641a86e5f0383f0e9c3bfdc800ba45c51658bd63b39ccfff2ac08eb310e5dd9d76f7c0e40003d81e80426c9188ec2cc22620e2fed91c96b6324764729ca8742fdb06b9bff9df119af1d11b0d3e1add0c3a9d017d435e0913a37223846e7d3cdd381f0309a5be7d7a8eb7d88b74", "56", "-a395a7897ac2259d03a641925c4895bbb76ac4fd42831602c1dee923ffd961e77536da339a2d0db5c3f9799cb73638d1f5d42c1a84c21213741482ec68c9157975e3c66f06d623882a3551e18f006ad7bb38a485ad8045e6133e33180dbae2c8de17d277532e3df5a04da90c1656dd1ca1e58340e3b8571d66d9fb45d5814522cdf3f1cae4fea8bf63c1208c4700affe6482fe827c3d3837fbd595ab916980d9ffaf5210f2599e0b09944c36fd82bcf20094821fa8a8eb2f6ed390f4eca5d229a3e9824438fd68211e903d87f86bda446f18e7d2e36f81559a273f6a5a528c7c2e1b0b09ad384f1d89bc95db874556ec4c176893abfaec4dfe1e18aece58468cebd2375c54a734e95c82e336ab064ee403b6bb0a62bc7d283602cd5f64b3dcdcf42e4d4e5c56dddb88052022742b93ff077a59ef3857fabe246f7627be027d4a4b62689e7f644517749a77d06bd6691cdf120d1e0be9d80fb2fbe3f13305676e3dedd11f2df97673cf2ef2bf9bb7dd4cc0992da20cb062afc1a760d1afa16072967e4ec87ecb251341043045c295cfad44eb7d906a1b97c0e0fc3a70eff72002e917145962f58ece733ffcab023acc43977675dbdf0390000f607a0109b24623b0b30898838bfb64725ad8c91d91ca72a1d0bf6c1ae6ffe77c466bc7446c34f86b7430ea7405f50d78244e8dc88e11b9f4f374e07d", .Okay}, + {.Shr_Signed, "-2b420f5defb5fbf06550ec44986714ff42c33f8defbd17ff98fa5b9c80f6b17ce8ce607b0f6bd6f466d76f08ec77ca6501350db86177ce6388d75c0cbdb7d5bbea34dac96b5ef1e81aebd3d676c662a3e419be2af343bfbc0e061695e2283d1c15d6b9f95064cce19e54a655b6cf321d13957c810666b798d18ec4b49adc22479e1e556872aa04673f25c45bfe9ec3095d81608def5ed84eac0b346eee166756fcb143cfce8a902d7a565f042b15a2d8b5a356a4356f7590f2c81299de6fcb72316df5729a239d64df2fde7b5b7456ab1e1aa6d368cf400acd768d63a53df1daaa7ca36510f6b2d5c04a29fae49cfe9436467f61a5465d804453099dfa171d16a065949135868d86c20814e62c21d88df4dd71640144aa59a8eb0f165984f94744e5c87bddb84ec24cc251387d13071528e6a12324820c902a6ac8db06be507217b39efb4d862efab4197403515105dc521a1e98795da5637b4ed2475fff0013b8e997d3f6cff5c2da70e5378c3ea08467d75e18d25ddea7442500c0cda3a7dd9911a11df3429c76018bc88ad7309ce500891c4da07961774989f1d3b69c6dddfa9e261069958907bff7543c2a5c44ef464e88bba9f79debec190ff3644474974b1a5ebdd474a96b28ea3db278491215e066dd9839b7baf491673e569bf425642b3228b32483b1fe80d574aacd6878f9a78112b873efdf96017a4493cf466cf2", "64", "-2b420f5defb5fbf06550ec44986714ff42c33f8defbd17ff98fa5b9c80f6b17ce8ce607b0f6bd6f466d76f08ec77ca6501350db86177ce6388d75c0cbdb7d5bbea34dac96b5ef1e81aebd3d676c662a3e419be2af343bfbc0e061695e2283d1c15d6b9f95064cce19e54a655b6cf321d13957c810666b798d18ec4b49adc22479e1e556872aa04673f25c45bfe9ec3095d81608def5ed84eac0b346eee166756fcb143cfce8a902d7a565f042b15a2d8b5a356a4356f7590f2c81299de6fcb72316df5729a239d64df2fde7b5b7456ab1e1aa6d368cf400acd768d63a53df1daaa7ca36510f6b2d5c04a29fae49cfe9436467f61a5465d804453099dfa171d16a065949135868d86c20814e62c21d88df4dd71640144aa59a8eb0f165984f94744e5c87bddb84ec24cc251387d13071528e6a12324820c902a6ac8db06be507217b39efb4d862efab4197403515105dc521a1e98795da5637b4ed2475fff0013b8e997d3f6cff5c2da70e5378c3ea08467d75e18d25ddea7442500c0cda3a7dd9911a11df3429c76018bc88ad7309ce500891c4da07961774989f1d3b69c6dddfa9e261069958907bff7543c2a5c44ef464e88bba9f79debec190ff3644474974b1a5ebdd474a96b28ea3db278491215e066dd9839b7baf491673e569bf425642b3228b32483b1fe80d574aacd6878f9a78112c", .Okay}, + {.Shr_Signed, "2587020d963bc91e1b127de06d8c950efb61bd4aec302616c00d3eeb7e1798e0682a227eed8b47ecc1101fe682e72457b96cf949cfd3fe1d36c74a917a1c71b368aead8ee9700b5a43a2f57c8568be1d77fe76148441398b07d126453387983b92513771a5f05d58290240b74a51c9c5003714eff450b38383e6834ab3ed5844fdfa3918b0238b620f2a8465681b7f0209b92260ef05e0e6aa7b71bcd25d6b5b05d6910d830f6e04ba7efe913e03e92e0275af3dc619cf8573e57ee1a6951c3a9f104a312fec87d8c9eb6065df9de319dfb37f33735a17fbaa92869613ceba7b21171a60a565bf57e17f8de9bb062e0b6235b99b4740877ea6643780df92967460837bbff9268ef9bf3b2f2ee77ded4ab4ce2c0ccb5d5fa70fc36851ed026ceb92c2884dfb0cb6dd6bec703b89b857c56b22034933f8ff9f6c8e19a00400a89a8e350e8ce9a0c0cfecff21793b67450be2ee4ed2562302228867cb78b9307642e26618820b183a453f8be40d941aa13b68e1b271b0d91750d4b05e78f3e5bccc1397f883cd01d849b6fff23c55a57d2bc3b7290d5b23b2e2a659155deae849dbe98cd34361a96d53a75f5bb693976e049fac45b2b06aaccac8fcad18c903d06f75a472f13f64d81bdf6d7970f79b68f2e08b306144f80d4bda42570f0dbe5b3a3dfbe3d777b908ba6005641d365de7f74c4b1b2f7096a6fdb495a92fe7d312ff", "74", "2587020d963bc91e1b127de06d8c950efb61bd4aec302616c00d3eeb7e1798e0682a227eed8b47ecc1101fe682e72457b96cf949cfd3fe1d36c74a917a1c71b368aead8ee9700b5a43a2f57c8568be1d77fe76148441398b07d126453387983b92513771a5f05d58290240b74a51c9c5003714eff450b38383e6834ab3ed5844fdfa3918b0238b620f2a8465681b7f0209b92260ef05e0e6aa7b71bcd25d6b5b05d6910d830f6e04ba7efe913e03e92e0275af3dc619cf8573e57ee1a6951c3a9f104a312fec87d8c9eb6065df9de319dfb37f33735a17fbaa92869613ceba7b21171a60a565bf57e17f8de9bb062e0b6235b99b4740877ea6643780df92967460837bbff9268ef9bf3b2f2ee77ded4ab4ce2c0ccb5d5fa70fc36851ed026ceb92c2884dfb0cb6dd6bec703b89b857c56b22034933f8ff9f6c8e19a00400a89a8e350e8ce9a0c0cfecff21793b67450be2ee4ed2562302228867cb78b9307642e26618820b183a453f8be40d941aa13b68e1b271b0d91750d4b05e78f3e5bccc1397f883cd01d849b6fff23c55a57d2bc3b7290d5b23b2e2a659155deae849dbe98cd34361a96d53a75f5bb693976e049fac45b2b06aaccac8fcad18c903d06f75a472f13f64d81bdf6d7970f79b68f2e08b306144f80d4bda42570f0dbe5b3a3dfbe3d777b908ba6005641d365de7f74c4", .Okay}, + {.Shr_Signed, "6d72601a4f3ab2044904e4230b812d9f1872c1a8d1f1f0663bd9dbb84db776043fda70c373c65822cfd28c0e2bb1d8c731c50e7cf1485cbe6f0869c81f0b795f1c542bbf2c23ca41c7a94cdd11c3b75d76ee1fe01fbb70ecf81d2e31b9c6ebd34a4195dec5581e6a9caca18e286251517eab9098216f62674c1078e7f4daede63ab19c2c4bed5585dd2f02126238d1550b66f77b33f0af55d7806b06bd82d5db660f8683ab7a987526a7034b5568162f7ee49e57b0cbd44f1aa4530614d09db8dcbdeccbf4ed60c584dc1471823ed26f8c6c9c67f1ab7949f8c1d3aff3c67cd62b0959ddf0f16bcfe66a1c1aa3fa52c0136518d71885a21c3143ab4d6f818c54f9378ddeaee7f9a683df91861f65fd4236ab389c1ec49fa989002f569b0186a20180e35d32321a5691de67f50019fca72f5ee688cf4e4738fa3b2a5ad9a0518fffb6505e9bcdafc0cb0b98eb57e5e6c5ef6652d565fe55f6de138abb805728cba551f779622a2735df34b308bd544a9405962a8b9513d50a2897900ae5284a43182c47207621b66160c667b4f6f0e2531ac39e2ff895ec3409f2cf1ed6e2e5e80e1cb2a8b8924fdc2a48c9c291c5590140f230f920aee7a5a75b7651200621672a1406baf2ad3a78583c5d938a4828372548a6e323b46fbb34142a3651d35cd8717d137044db09a2a18d7182095c7bc283dc3413ff2baf0078f56481775c7928", "68", "6d72601a4f3ab2044904e4230b812d9f1872c1a8d1f1f0663bd9dbb84db776043fda70c373c65822cfd28c0e2bb1d8c731c50e7cf1485cbe6f0869c81f0b795f1c542bbf2c23ca41c7a94cdd11c3b75d76ee1fe01fbb70ecf81d2e31b9c6ebd34a4195dec5581e6a9caca18e286251517eab9098216f62674c1078e7f4daede63ab19c2c4bed5585dd2f02126238d1550b66f77b33f0af55d7806b06bd82d5db660f8683ab7a987526a7034b5568162f7ee49e57b0cbd44f1aa4530614d09db8dcbdeccbf4ed60c584dc1471823ed26f8c6c9c67f1ab7949f8c1d3aff3c67cd62b0959ddf0f16bcfe66a1c1aa3fa52c0136518d71885a21c3143ab4d6f818c54f9378ddeaee7f9a683df91861f65fd4236ab389c1ec49fa989002f569b0186a20180e35d32321a5691de67f50019fca72f5ee688cf4e4738fa3b2a5ad9a0518fffb6505e9bcdafc0cb0b98eb57e5e6c5ef6652d565fe55f6de138abb805728cba551f779622a2735df34b308bd544a9405962a8b9513d50a2897900ae5284a43182c47207621b66160c667b4f6f0e2531ac39e2ff895ec3409f2cf1ed6e2e5e80e1cb2a8b8924fdc2a48c9c291c5590140f230f920aee7a5a75b7651200621672a1406baf2ad3a78583c5d938a4828372548a6e323b46fbb34142a3651d35cd8717d137044db09a2a18d7182095c7bc283dc34", .Okay}, + {.Shr_Signed, "f1d6ff697aedd19b1b6dc9a67ba8684df7b83b08f1236d536e1edf52864494455c0bd39a0b0e181007963e21a476aef4a4e8de66ffd613a092d3e23fae8204ea038deda96ac73d6a254edc2ca641f58745fe66da303c92b6b2128148186868a0252ae79c1d2d0d4c3a38d59feab2c9434660a65b8426a3480436fefe1b150be50c85c4897298dc1bb185c51ae897834c3d6797ce920faa56615f40354e8561d26a84fe8a9cb3d82aa8a4470a2ff4ef51eef2b480d9092438f63605eee83333f1d66b9aabf753bc301c2e93fffca9da2c6e838844d51b6f96e3e3239d38ab7b01afa03342600984bd9c35c74c09936c74579b20f42e80cef97c0f92d5b5c7c4c28fd64bd0183fe17f8b21ba9757cf5868aaa6aa21bd04d7ae8743a29517353192194d52f7209c2800d309500252d278a08274127c7898ad94fad829f3dfa9b976e71f9ad4910703765084b3c33923ba2cb6005144b6008b6d621a6d79a45cd408a0a0917ac0dcd4d6053199c671b27300fcbae0e47db3ce25a3c96cdc0bf91f146f128cec93c9832314a93ba5fe5d504061b2de6b91b0e9a83a27b037deb779d3037de163d7d6486d070f1b9e025f3521cd5da43e67a134e8e17f40f3f18179a6df7db5955efb544cd51c59826578d25ff9027a05abe33f2cdec4e916d2477b3a3d17ed391c080300513815e98e5569f0e942ed01b3ed11b26b786590fba2837a", "54", "f1d6ff697aedd19b1b6dc9a67ba8684df7b83b08f1236d536e1edf52864494455c0bd39a0b0e181007963e21a476aef4a4e8de66ffd613a092d3e23fae8204ea038deda96ac73d6a254edc2ca641f58745fe66da303c92b6b2128148186868a0252ae79c1d2d0d4c3a38d59feab2c9434660a65b8426a3480436fefe1b150be50c85c4897298dc1bb185c51ae897834c3d6797ce920faa56615f40354e8561d26a84fe8a9cb3d82aa8a4470a2ff4ef51eef2b480d9092438f63605eee83333f1d66b9aabf753bc301c2e93fffca9da2c6e838844d51b6f96e3e3239d38ab7b01afa03342600984bd9c35c74c09936c74579b20f42e80cef97c0f92d5b5c7c4c28fd64bd0183fe17f8b21ba9757cf5868aaa6aa21bd04d7ae8743a29517353192194d52f7209c2800d309500252d278a08274127c7898ad94fad829f3dfa9b976e71f9ad4910703765084b3c33923ba2cb6005144b6008b6d621a6d79a45cd408a0a0917ac0dcd4d6053199c671b27300fcbae0e47db3ce25a3c96cdc0bf91f146f128cec93c9832314a93ba5fe5d504061b2de6b91b0e9a83a27b037deb779d3037de163d7d6486d070f1b9e025f3521cd5da43e67a134e8e17f40f3f18179a6df7db5955efb544cd51c59826578d25ff9027a05abe33f2cdec4e916d2477b3a3d17ed391c080300513815e98e5569f0e942ed01b3e", .Okay}, + {.Shr_Signed, "-964f09defb70ae4eb10213f7ac5a665d65e3b158737dc842d44d2425f0e5c21f08c53e3f16b8a3fe99757de15b320e76fd7e408418c3d156180f637e704b646f91f83cf866758ad315b612cf201d7109bdefa9a3538bea51a3d679c65b45a01b0ec81c5630322e9958677a430d744e10145882e8e706f6b211f35fad0f56fb03a89223c3d375ade4d105fc15df487bd53a1dcd936b7fbc052bae3f0988fbf60a9c7f26f76f5b523af8f59d6a7bf79661d7ba7a290bcfd2e08de28db5f22fc2adb73119cfdc9e8bb1cb2c0e64bdc29dd3e9a1f94a25d77d4a419203a246c1a53391dc2e1a484f6834796bdf4ec68648b618b110406eeea7a696e900f7b333e47c22dfe0e71cb74d7696b6d9e06e122ea2c7e7a1533421523c4f2d02e25e55168696141c87cbd39e9a1481670f1fed93735a4e6ca8c6e9f3aa80fa87c0be028e11cb76276c456ad8ec1715e8895fba66f563d01df187998c8ac1a448beb4e580c09af8dfc318c715d1532c2c6b36c1d7219d8a077ba77c3f4f8e2b2708cc48de0d4b92ecfca1313bd76a255d4e2bc81b03bad4cf990df687789686c6d9df06ce3303bcbbd21e3f03586d1182ded565e94afd06b1f7597941dd422e651299ec5978986f5899a9c72b98835e4dfeda45dcda68195e00972007d6a2d619d719a3795da935ba5784a3c937e27070268806b600c03fcbbd1fe2a255287738b895726047", "45", "-4b2784ef7db85727588109fbd62d332eb2f1d8ac39bee4216a269212f872e10f84629f1f8b5c51ff4cbabef0ad99073b7ebf20420c61e8ab0c07b1bf3825b237c8fc1e7c333ac5698adb0967900eb884def7d4d1a9c5f528d1eb3ce32da2d00d87640e2b1819174cac33bd2186ba27080a2c417473837b5908f9afd687ab7d81d44911e1e9bad6f26882fe0aefa43dea9d0ee6c9b5bfde0295d71f84c47dfb054e3f937bb7ada91d7c7aceb53dfbcb30ebdd3d1485e7e97046f146daf917e156db988ce7ee4f45d8e59607325ee14ee9f4d0fca512ebbea520c901d12360d299c8ee170d2427b41a3cb5efa76343245b0c588820377753d34b74807bd999f23e116ff0738e5ba6bb4b5b6cf03709175163f3d0a99a10a91e279681712f2a8b434b0a0e43e5e9cf4d0a40b3878ff6c9b9ad2736546374f9d5407d43e05f014708e5bb13b622b56c760b8af444afdd337ab1e80ef8c3ccc64560d2245f5a72c0604d7c6fe18c638ae8a99616359b60eb90cec503bdd3be1fa7c715938466246f06a5c9767e50989debb512aea715e40d81dd6a67cc86fb43bc4b43636cef83671981de5de90f1f81ac3688c16f6ab2f4a57e8358fbacbca0eea11732894cf62cbc4c37ac4cd4e395cc41af26ff6d22ee6d340caf004b9003eb516b0ceb8cd1bcaed49add2bc251e49bf138381344035b00601fe5de8ff1513", .Okay}, + {.Shr_Signed, "-3e21d054b016a174dc2e4657f154d6849f0713639dcc4e1478722792b420290455a1b6811ff7055dc07d7c5503f9ca201ea1dbb06d43f316f1856081b332a7f61b86757c0a832661c7ffd8ef579b96a7164e56b18226c73fadfc7a697b57c86d2dad0385ee5156f5fd257898f6315d1a711424a29aaa58b0abb66fd145db04ea43512f9c1e8e5bd1c47a604b2e76882bae35784aa09e0a99b66b0a60bdf14336c0e67f5b7fa0abdc6737550e73ea1ac2daa7eea92b4c4be0719d5efc188eb0ca02a25ac5eeb80c23bf84318bf495641c0200583022b752377984b922ce5a9e855415547c4e6b5c1175cbf955d88ddf9a0e244dfc0811ca14eb86d58101cfa815392788329840d4637f1589c056bb02ff39c3c7fa0abf31c8146f14083ed2d777f26b53e3be6bdf84d1e8351e3bd2356ba6f503c1eeec72c0bf17a0b36f25e2f334931df2464abbd26a893324580ac2e02ca81601b32c9b51834a807fa0fc24a5a223eafe37e4d866708424da189f9d3da7ed8a9a0fa80f0929f19fd3c663838e395865543f37a90c0785aa854ce41515f96a7a898aa69d8d8a50495fe196db3836f854bc9412a27871048056c7d5664f866d54c24ee89b9c940ae5c33ddc60e044dfd9e60a83746f47df107e6b67d03d354f1733b87fcedeeb863ce865f497b80cd9f9dfcbb073edfb8c4d8df99006de872d965882af21d988efd466005382fe", "29", "-1f10e82a580b50ba6e17232bf8aa6b424f8389b1cee6270a3c3913c95a1014822ad0db408ffb82aee03ebe2a81fce5100f50edd836a1f98b78c2b040d99953fb0dc33abe05419330e3ffec77abcdcb538b272b58c113639fd6fe3d34bdabe43696d681c2f728ab7afe92bc4c7b18ae8d388a12514d552c5855db37e8a2ed827521a897ce0f472de8e23d3025973b4415d71abc25504f054cdb3585305ef8a19b60733fadbfd055ee339baa8739f50d616d53f75495a625f038ceaf7e0c47586501512d62f75c0611dfc218c5fa4ab20e01002c18115ba91bbcc25c91672d4f42aa0aaa3e2735ae08bae5fcaaec46efcd071226fe0408e50a75c36ac080e7d40a9c93c4194c206a31bf8ac4e02b5d817f9ce1e3fd055f98e40a378a041f696bbbf935a9f1df35efc268f41a8f1de91ab5d37a81e0f77639605f8bd059b792f1799a498ef923255de9354499922c05617016540b00d9964da8c1a5403fd07e1252d111f57f1bf26c333842126d0c4fce9ed3f6c54d07d4078494f8cfe9e331c1c71cac32aa1f9bd48603c2d542a6720a8afcb53d44c5534ec6c52824aff0cb6d9c1b7c2a5e4a09513c3882402b63eab327c336aa6127744dce4a0572e19eee3070226fecf30541ba37a3ef883f35b3e81e9aa78b99dc3fe76f75c31e7432fa4bdc066cfcefe5d839f6fdc626c6fcc8036f4396cb2c415790ecc477eb", .Okay}, + {.Shr_Signed, "-f9a7e39be55b0dd7bf483e22c3773cf8ff76717c29e6c816e18e3e3b4916338be98cc5ccb3bde6ea2edf304c862e28a5bdff961593d65abfacb531b823141965b94b5cf01c5977b20486b88c3df6dc1954a0d47ba7ab5bcc74dda267fcbb847387eb73dff53c7bd1e513c4fbf7cb363ce1018c0362834d88af55d001d222dbf7f8cd432e693bd12aaa00887b980e9d3050cde340f8860ed4fa080c70838bdbed25943493944c6d9a4af3146246bb89cfa15d81fb0afb21c0fe985bf09f9e86b4228f8554393b5e1fa96f8292e15790014a7b2244d0fca19da07a870c3c930d78b66a395d727925722738b2725dcd8a33f233d5e00ebe947a47ff4bc8ce2f386e3e532c496804d2edbf7592469088c7735d1059b5047659c416eb66295c2bde8da0d49f607b67d0dc78bb3267ef9bba0bcbc2b673823b45fb24de279f055e3f55bf87345a837eabd1be1321bd47ccbd7a2f4897bad175419d570765458fdd4fc117f79bf0f1fadb82f7c78cf55d853cf5b9fb0004cdc1c71c14515aa0fa303a747ed3ce5154a1a366332678c8f68c5cea9118a2296a0b98008fbd4b13ab978f6b29cfa2ab1a59f9acf50ecad1fc55c14abd3508fd615707d42b7d4ee6cd97750e94716389ce0690b9a26879606764b1da0ee37bd2e0980fc7eea546baebaeebb0c507fe4a6d3ca5220468cc47903f7a7c59b8aef37058dc775f71b5b05034e958", "4c", "-f9a7e39be55b0dd7bf483e22c3773cf8ff76717c29e6c816e18e3e3b4916338be98cc5ccb3bde6ea2edf304c862e28a5bdff961593d65abfacb531b823141965b94b5cf01c5977b20486b88c3df6dc1954a0d47ba7ab5bcc74dda267fcbb847387eb73dff53c7bd1e513c4fbf7cb363ce1018c0362834d88af55d001d222dbf7f8cd432e693bd12aaa00887b980e9d3050cde340f8860ed4fa080c70838bdbed25943493944c6d9a4af3146246bb89cfa15d81fb0afb21c0fe985bf09f9e86b4228f8554393b5e1fa96f8292e15790014a7b2244d0fca19da07a870c3c930d78b66a395d727925722738b2725dcd8a33f233d5e00ebe947a47ff4bc8ce2f386e3e532c496804d2edbf7592469088c7735d1059b5047659c416eb66295c2bde8da0d49f607b67d0dc78bb3267ef9bba0bcbc2b673823b45fb24de279f055e3f55bf87345a837eabd1be1321bd47ccbd7a2f4897bad175419d570765458fdd4fc117f79bf0f1fadb82f7c78cf55d853cf5b9fb0004cdc1c71c14515aa0fa303a747ed3ce5154a1a366332678c8f68c5cea9118a2296a0b98008fbd4b13ab978f6b29cfa2ab1a59f9acf50ecad1fc55c14abd3508fd615707d42b7d4ee6cd97750e94716389ce0690b9a26879606764b1da0ee37bd2e0980fc7eea546baebaeebb0c507fe4a6d3ca5220468cc47903f7a7c59b8aef37058e", .Okay}, + {.Shr_Signed, "-a9496286229b74ce3f8204b996261a9e3a723019f149bd23cd2490384422ee918a0b6a3c5b82d3e0213f3a428d19bdbfe0f4f144b34c9e5ac8d88941a2c3b66e83eed36b325ba827fdf138b494a4f5293e0b321a856b52263a7a4f50b703ff1c6ca937219b221daf640c4d3651c3faa97ff93d2c58aa3c44ee4466117c25d45478becf100fdb87f1ea8ff7aa2c90d871c15c60f9b3c9cdec23ea2eb282fca1b40a29333d00c9289c10715f7140a0ced233b6815ef3ec46e8331e13f81a26003d210e507fbb9d316c1a6e50940b58e50638e733fbf5d19f5a924d012880b086aaec8ed21117881defdd35e15e5035aeee42c341eef131fba0e4e46cff5a15fd56439a31b425ca2d6a0c25606f7b114d7e9f737d768cfe0ca6ff08585ac54f6c4cc0d79a519fcb7bb2ce0418dc75ffb947e591097f817711b1bcdc67eb32501926d699d06ceaa8165bd3f2c4b9b782a1dba0684f27c7d9f3dee430455c465be82db37c5c73ce839b473f1fd52e6f494c4027f3155d42527e7e2f176b33bc273a7dbbe23714a180b4903c2e7df9aad787ea5a2c52b54b52019e439676ea702d870f5fe1f1d84c38d795a24b86729f7bf544d3c05ee047979724e6c4d763ebb8f0a0bd808463fa3482933c8780d8af0f94d7d928862512a71ed104782bc2b45fc79084c48d6b67688bcdcef9a038dcf9f3fca7b57cbca004322de63627812a675e09", "18", "-a9496286229b74ce3f8204b996261a9e3a723019f149bd23cd2490384422ee918a0b6a3c5b82d3e0213f3a428d19bdbfe0f4f144b34c9e5ac8d88941a2c3b66e83eed36b325ba827fdf138b494a4f5293e0b321a856b52263a7a4f50b703ff1c6ca937219b221daf640c4d3651c3faa97ff93d2c58aa3c44ee4466117c25d45478becf100fdb87f1ea8ff7aa2c90d871c15c60f9b3c9cdec23ea2eb282fca1b40a29333d00c9289c10715f7140a0ced233b6815ef3ec46e8331e13f81a26003d210e507fbb9d316c1a6e50940b58e50638e733fbf5d19f5a924d012880b086aaec8ed21117881defdd35e15e5035aeee42c341eef131fba0e4e46cff5a15fd56439a31b425ca2d6a0c25606f7b114d7e9f737d768cfe0ca6ff08585ac54f6c4cc0d79a519fcb7bb2ce0418dc75ffb947e591097f817711b1bcdc67eb32501926d699d06ceaa8165bd3f2c4b9b782a1dba0684f27c7d9f3dee430455c465be82db37c5c73ce839b473f1fd52e6f494c4027f3155d42527e7e2f176b33bc273a7dbbe23714a180b4903c2e7df9aad787ea5a2c52b54b52019e439676ea702d870f5fe1f1d84c38d795a24b86729f7bf544d3c05ee047979724e6c4d763ebb8f0a0bd808463fa3482933c8780d8af0f94d7d928862512a71ed104782bc2b45fc79084c48d6b67688bcdcef9a038dcf9f3fca7b57cbca004322de63627812b", .Okay}, + {.Shr_Signed, "19ae50f43e84cc2a273064a93115b80c78ceb40f2f3f9221094f7ecbf463fd55798544e3e82441508a52e25a36aed338322a6201cfb5ef2a5c83c48f36c137e11aac07ec701dc032e11afbd1a91908b1d55690c939ddc95426ad376f1157b4a4a8d658e5f6768a880a420f109e2a4a6f834079f388f7a83b47d86bd5a10179e6f3947c43e21dab61be2288ee9ca6076aa0eefde0937a93ebd8cf6ff1d42a11d22b9794671ba1b9e30bb1add3e6897d9bcbff833a4023b9d1d14af12b38699de8315507b3e97fcded57a8795c63a558f8a53603d30682c7921130d9392b176c330f6be95acca434f8d4841f07607edefe592baa17b74432e047579bd16fe0c1ac718f1a3b6ad042a061aa06b9849c90c4b34bfd424bd1fa74aa232f174ae2719637bd97cf7aa76e32358a57093d195ab6efd626ee79e338d39e8a5ca3b0c9756a69c072710869e83be70176e26ec0f03d41d51553dd76aeb140309fb5e9c8df51a8df9f52c1611d0fe4f9dff2cad1641fab967de0b7a47a29641b763d67bab0c05658a7b1a79a0200c22dde3d9b1fba797508e1c7be9665735ba8dd403f1a207ae12d9ec26ac4a51ff49c507050564dec6b6e5e39f15a1ebe0ee933933f25a03c743a8231103dec490f826d559fe6df2ecec265c39d0ece3eb8feaad7c7995195317a2260e3a5f3c89a6077a18abddfe1637072441d5a4f720ee956323f2141ea", "3d", "cd7287a1f42661513983254988adc063c675a07979fc91084a7bf65fa31feaabcc2a271f41220a84529712d1b57699c19153100e7daf7952e41e2479b609bf08d5603f6380ee019708d7de8d48c8458eaab48649ceee4aa13569bb788abda52546b2c72fb3b4544052107884f152537c1a03cf9c47bd41da3ec35ead080bcf379ca3e21f10ed5b0df1144774e5303b550777ef049bd49f5ec67b7f8ea1508e915cbca338dd0dcf185d8d6e9f344becde5ffc19d2011dce8e8a578959c34cef418aa83d9f4bfe6f6abd43cae31d2ac7c529b01e9834163c908986c9c958bb61987b5f4ad66521a7c6a420f83b03f6f7f2c95d50bdba2197023abcde8b7f060d638c78d1db568215030d5035cc24e486259a5fea125e8fd3a5511978ba57138cb1bdecbe7bd53b7191ac52b849e8cad5b77eb13773cf19c69cf452e51d864bab534e039388434f41df380bb713760781ea0ea8aa9eebb5758a0184fdaf4e46fa8d46fcfa960b08e87f27ceff96568b20fd5cb3ef05bd23d14b20dbb1eb3dd58602b2c53d8d3cd01006116ef1ecd8fdd3cba8470e3df4b32b9add46ea01f8d103d7096cf613562528ffa4e2838282b26f635b72f1cf8ad0f5f077499c99f92d01e3a1d4118881ef62487c136aacff36f97676132e1ce87671f5c7f556be3cca8ca98bd113071d2f9e44d303bd0c55eeff0b1b839220ead27b90", .Okay}, + {.Shr_Signed, "-28aa48be4e3526c0f637ac4a595c1f58ff6d837e86083e17c128d9cd08f8825bd706c52e8e03760b9877418ba77182cda60cdb0366ae74e23b34164316a4d30c769a1eef7a51940aafec3b8e424ffc27db495ed66c699fe28e5d06b7277cb8e9cf018ad25beba11c3410d32c0f89fe1b47371b8a7c46e38258b8167b867a4d8f81f38ddc17760954c50b909610c4cf43107aab7ac38d893e949d6ccf2689eba2c081c48b5b00d8e3caff14b486978887363eedb8f7f22a8fbd06472f0425ee63c5bb181259a3e53581d993c169d5370f874818115b07ba0a4d88bc055a9ae314ee1f11e8b2cc9f2003358f81c04d99cf595c29190ed78e76bb4fb73ab3929009b30d15186c7c283b59d4e08a306a6cdb8cef0b5d9c2e8778bca821a21e4e83896f513f65869076d39a171af9e0dae14b3159c06cdec9155971e5abe3dbe7ffe64ffe410dfbabcd75ec0e4835659237bb28ea62bd9afb4a6edb8c50d0e3c4fa890af488298c693493ccf72a3a791456ac623c7b2430ddeccde41d7440cf52f8a6c112e586849859be1b3a1fde6381a2229aa7f9ac0f7486e426b0ecd8eb7cef3514ebada38cc860dfebaff8ab4496c9238a3316297204a18f52e5c86e0200c975c1f711d67f7c901247865f00d93c59d68e55ff380d906ade83368548b17af48f2a44498ea94fc726a8b0552999e305da8119d5c61b7c42ea9708ecc0ca4fc348", "42", "-a2a922f938d49b03d8deb12965707d63fdb60dfa1820f85f04a3673423e2096f5c1b14ba380dd82e61dd062e9dc60b3698336c0d9ab9d388ecd0590c5a934c31da687bbde946502abfb0ee39093ff09f6d257b59b1a67f8a39741adc9df2e3a73c062b496fae8470d0434cb03e27f86d1cdc6e29f11b8e0962e059ee19e9363e07ce37705dd82553142e425843133d0c41eaadeb0e3624fa5275b33c9a27ae8b0207122d6c03638f2bfc52d21a5e221cd8fbb6e3dfc8aa3ef4191cbc1097b98f16ec6049668f94d607664f05a754dc3e1d2060456c1ee8293622f0156a6b8c53b87c47a2cb327c800cd63e070136673d6570a4643b5e39daed3edceace4a4026cc345461b1f0a0ed67538228c1a9b36e33bc2d7670ba1de2f2a08688793a0e25bd44fd961a41db4e685c6be7836b852cc56701b37b245565c796af8f6f9fff993ff90437eeaf35d7b03920d59648deeca3a98af66bed29bb6e3143438f13ea242bd220a631a4d24f33dca8e9e4515ab188f1ec90c377b3379075d1033d4be29b044b961a126166f86ce87f798e06888a6a9fe6b03dd21b909ac3b363adf3bcd453aeb68e3321837faebfe2ad125b248e28cc58a5c812863d4b9721b8080325d707dc4759fdf240491e197c0364f1675a3957fce03641ab7a0cda1522c5ebd23ca911263aa53f1c9aa2c154a6678c176a046757186df10bb", .Okay}, + {.Shr_Signed, "-6e4ee66a3e2f18faa0bdfe2f43f6d78e0014cc6a48330e1b313b1f229ac9f238c0304b593d497ec7a7c75160f5c050c27a6afc05a47cc8d6aff616ca6a75c452ae7c506d14801a169f61c8488467063d3e81ec6d3e723b34d9df8370181400c94d18a0e6dfadbb1956e8a5f8c8dfd18ab4902b7618cf512cc198b94411518df38e6541bbeff7b94bb31b71c020c5eab396889934ee49ee984e9f278dff9674562681a7081b2c66ec7d13951857732e899abf7a7758e8ed775ee005cbeedd8bc833d6d550378e303acacbeb9c949bb4b6e19542517b3b6fe72a835c4a8414fdb259d5d84d2000a8f55dcc02294c911763a66343967c9b6b00de5e8c218feae3efab34ac677b71ae2264fb0b3395f73400bcea698239cfb31c6ff079dffa90ffdbc1d9fbd5cc280805c422215076c382718d400daeae876e20029bcc4edc57ce50092b3bc860e0007bd68eaddb3929d839616e2c576945213c6708284a68e796b5f3e0126b341d7fefbfb06a87aab7c6d727212818fcf014e4d891ebbc912fc7f8f787b776bd4830b2457d65178b5ff3ea573cdad60de0ac509aae903d58283fe3e107d9779538af4b74de67f542b67da4ec046fe2467432b4732b229e8d7e54f2ae12243e1d6dda1303c2e741dc7d81e50db7adcc6f8f835f5fc534b8f8f4681df68e4013a5b47163e96984144e221000f9dfc348606e280fbbe815af445b8d8e", "23", "-dc9dccd47c5e31f5417bfc5e87edaf1c002998d490661c3662763e453593e471806096b27a92fd8f4f8ea2c1eb80a184f4d5f80b48f991ad5fec2d94d4eb88a55cf8a0da2900342d3ec3909108ce0c7a7d03d8da7ce47669b3bf06e0302801929a3141cdbf5b7632add14bf191bfa315692056ec319ea2598331728822a31be71cca8377dfef72976636e380418bd5672d113269dc93dd309d3e4f1bff2ce8ac4d034e103658cdd8fa272a30aee65d13357ef4eeb1d1daeebdc00b97ddbb179067adaaa06f1c60759597d7392937696dc32a84a2f676dfce5506b8950829fb64b3abb09a400151eabb98045299222ec74cc6872cf936d601bcbd18431fd5c7df566958cef6e35c44c9f616672bee680179d4d304739f6638dfe0f3bff521ffb783b3f7ab9850100b884442a0ed8704e31a801b5d5d0edc400537989db8af9ca012567790c1c000f7ad1d5bb67253b072c2dc58aed28a4278ce105094d1cf2d6be7c024d6683affdf7f60d50f556f8dae4e425031f9e029c9b123d779225f8ff1ef0f6eed7a9061648afaca2f16bfe7d4ae79b5ac1bc158a1355d207ab0507fc7c20fb2ef2a715e96e9bccfea856cfb49d808dfc48ce86568e656453d1afca9e55c24487c3adbb4260785ce83b8fb03ca1b6f5b98df1f06bebf8a6971f1e8d03bed1c80274b68e2c7d2d308289c442001f3bf8690c0dc501f77d02b6", .Okay}, + {.Shr_Signed, "6b55008bd338ea372bfa2f58a8e2a9632c6e6938ed5c915097fa65095f5363c7ccff03ceac079aad6228c92dc72434bcdd06e7280e405a0c5f4230bf7905064a16ab00f09dd86d30b649608b279cde56204f452db9e8ca0ed0842c298fa62379a23e91786e6a614c07618e0f9461fc7572eaba479510bd77a09f4e471c091e09980125c17672ac47e96a006b4257ef6f712518c48fbd082148bc687ab49429e1a155d13f9b9dc38fcc28feb062f3e9f459ac2c3ea76b8d52add3345e0b91d7bfa8e3abd29744b3a772a3d182802cf23072400706e7a386d36522de961d25ba7f2421b361e36eac52b491490d951e6ac3809288b8bb5545cdc2fc99bbdf118b4d9061fe08c2d65ba9965214600225f5416974920fbe5e48ae2dafc3e86e8b13507070149e10a67c1daa50c8dd71cdbfa190a661ee7d6f1c5a1f3a5828cc0c76fc2e65e65cf515eca86a5f60ce90d937dc53a41128e22311f60132b7c3a07d8196ab6e320446dc9ec79ef50ed14700ec013245423187f55548cbc3a512560c8d58bb62a846c989cbe19dfdb08aa9787976aff48260effe4d5d5a281202c8084486204dd2b0ec3836b8397f7008d889f10ee765b23d3aad3b9d958d13e69c5e780f8a50031d72bcfde3352c6d979253893dc8d34908ae547ef732bd334c20356da9dcdfc9944c26ceb42c8d6e70bafae2496af1d82ef4343fc916593561a383e364", "35", "35aa8045e99c751b95fd17ac547154b19637349c76ae48a84bfd3284afa9b1e3e67f81e75603cd56b1146496e3921a5e6e83739407202d062fa1185fbc8283250b5580784eec36985b24b04593ce6f2b1027a296dcf4650768421614c7d311bcd11f48bc373530a603b0c707ca30fe3ab9755d23ca885ebbd04fa7238e048f04cc0092e0bb395623f4b50035a12bf7b7b8928c6247de8410a45e343d5a4a14f0d0aae89fcdcee1c7e6147f583179f4fa2cd6161f53b5c6a956e99a2f05c8ebdfd471d5e94ba259d3b951e8c1401679183920038373d1c369b2916f4b0e92dd3f9210d9b0f1b756295a48a486ca8f3561c049445c5daaa2e6e17e4cddef88c5a6c830ff04616b2dd4cb290a300112faa0b4ba4907df2f245716d7e1f4374589a838380a4f08533e0ed528646eb8e6dfd0c85330f73eb78e2d0f9d2c1466063b7e1732f32e7a8af654352fb067486c9bee29d20894711188fb00995be1d03ec0cb55b71902236e4f63cf7a8768a38076009922a118c3faaaa465e1d2892b0646ac5db1542364c4e5f0cefed84554bc3cbb57fa413077ff26aead140901640422431026e958761c1b5c1cbfb8046c44f88773b2d91e9d569dcecac689f34e2f3c07c528018eb95e7ef19a9636cbc929c49ee469a484572a3f7b995e99a6101ab6d4ee6fe4ca2613675a1646b7385d7d7124b578ec177a1a1fe48b2", .Okay}, + {.Shr_Signed, "-e87fbd297f89143512dfc1cda8640aaf48bbfeaee5da926432a86d0547ed78b50d4a15256be1c9aa5e893980af5cfe629b4afee8594d2bce9c25e8232e3c59846c105f6a225b76fde45d78c87fff12268f170dc55f364f3c03f1063828f50ed947bc3dd5444e7ac9ffef4a8cda6761186637c490045b32183760c1fa1b528dbfc44d04d636184cd1b64348c7348cc0307f15c200e75a75ae7b1de53f07c46d15328b183e8ff35e3cce0b57ebe99ffddb91952ee2c84d37ca14383f42d6256b674df3e52a34c87dbb3c8648e0f2c7411c54dd7fb7ac4545c655fd131e40606e70c4d96b787c4388c2e52d80b06b9f178961c5cd4569bab7ed5464e2e5c09cd617d6001103edcd3d123950f2ec8406e7899df46112a92996ea6d616f5db5ec1f3a82d8883059e573853f1184be2dfc6e8c917d338d517e9e8e2da6441da68b781da74afbcfeaa2d0c3a30d61757b5805f1943cee76f6783ad948a51629dfa039dba53ba144b3e3259873dd9fe6fdc471cce3bd6bf34111d92401e770a7502b74fccab62c480e47756b265d5b082ad4e9808eff676fd8acb4629ee52fdc23fc5cb28874a3c7bc0d349382f8ada344a72a43ad1e523fe45dc3563b7c9545fb7d287dc19511bb74c4166388ab0e97e0a546a228a9079ef8ecc63991552d38533252a93eb76ff23e58e8e50db715b9553d7f1528c17e277c7b7a613172acc97b7979a1", "2c", "-e87fbd297f89143512dfc1cda8640aaf48bbfeaee5da926432a86d0547ed78b50d4a15256be1c9aa5e893980af5cfe629b4afee8594d2bce9c25e8232e3c59846c105f6a225b76fde45d78c87fff12268f170dc55f364f3c03f1063828f50ed947bc3dd5444e7ac9ffef4a8cda6761186637c490045b32183760c1fa1b528dbfc44d04d636184cd1b64348c7348cc0307f15c200e75a75ae7b1de53f07c46d15328b183e8ff35e3cce0b57ebe99ffddb91952ee2c84d37ca14383f42d6256b674df3e52a34c87dbb3c8648e0f2c7411c54dd7fb7ac4545c655fd131e40606e70c4d96b787c4388c2e52d80b06b9f178961c5cd4569bab7ed5464e2e5c09cd617d6001103edcd3d123950f2ec8406e7899df46112a92996ea6d616f5db5ec1f3a82d8883059e573853f1184be2dfc6e8c917d338d517e9e8e2da6441da68b781da74afbcfeaa2d0c3a30d61757b5805f1943cee76f6783ad948a51629dfa039dba53ba144b3e3259873dd9fe6fdc471cce3bd6bf34111d92401e770a7502b74fccab62c480e47756b265d5b082ad4e9808eff676fd8acb4629ee52fdc23fc5cb28874a3c7bc0d349382f8ada344a72a43ad1e523fe45dc3563b7c9545fb7d287dc19511bb74c4166388ab0e97e0a546a228a9079ef8ecc63991552d38533252a93eb76ff23e58e8e50db715b9553d7f1528c17e277c7b7a613172b", .Okay}, + {.Shr_Signed, "-b3bf3fa33fd76f090155355c02c6cf990b25af6fb0c15bec929c8e79034324bba2655b92936a300d4ee2c3de67243714c7ac42ac27a040192aed053cd746801f890098c9e76de50d89ca24c1aa47e6d61a754b8f2c35ccd6de520a656066bdb43874b0000add331a08e0664035671e8a38961112dcee9b90f9a6ca7dfe6dc985a4d63de094a1723b00031345229e532123b0325f4d8e6173e3eca3df6f4831501c6b454a5c13f501a029d7fd9ba7919fc3f94051ca4b0c626ba393c04e38b2c7f16abd3adc2f581344907d5a5b764b500c72afe31e84d43651a644ed4d2a3198b58bf59dc5fbcb1b8c4ed1a2e98642cb435b17ce34e99e48ffd2e63d562c4959e2dee6a2238834b38991359e40524085c718172be5f94d7e242f8bd25368d1c808b73df1beaebea35b264653a209935cb0552bde9f6088f8faa634e004552171a0e05d4671c2a521c04e0d93f17f039e1121a7bf92a5dbd1c22b61ef4d5d617155c5e6aa55fb77401fec20b73c4de9f863b8501416b268c8e7e3b87925fc42464e32a39b91dedea802c315b6c86dc33c756d1110f2b5a187e9ac78397dcf5f964576c82d0605f57010606fd28ff0e2bcd5a3cbf4d6d2ddc0e4285705b3b7c570020f8342f4454a94b1287d60994340d8f636783672893f81c46cf15687f6939edc79349d5b2971dad7acf1d96d5829a1a4dab1061cc479d39adc5ab533e35b", "5", "-59df9fd19febb78480aa9aae016367cc8592d7b7d860adf6494e473c81a1925dd132adc949b51806a77161ef33921b8a63d6215613d0200c9576829e6ba3400fc4804c64f3b6f286c4e51260d523f36b0d3aa5c7961ae66b6f290532b0335eda1c3a5800056e998d047033201ab38f451c4b08896e774dc87cd3653eff36e4c2d26b1ef04a50b91d800189a2914f299091d8192fa6c730b9f1f651efb7a418a80e35a2a52e09fa80d014ebfecdd3c8cfe1fca028e525863135d1c9e0271c5963f8b55e9d6e17ac09a2483ead2dbb25a8063957f18f426a1b28d32276a69518cc5ac5facee2fde58dc62768d174c32165a1ad8be71a74cf247fe9731eab1624acf16f735111c41a59c4c89acf20292042e38c0b95f2fca6bf1217c5e929b468e4045b9ef8df575f51ad932329d104c9ae582a95ef4fb0447c7d531a70022a90b8d0702ea338e15290e02706c9f8bf81cf0890d3dfc952ede8e115b0f7a6aeb0b8aae2f3552afdbba00ff6105b9e26f4fc31dc280a0b59346473f1dc3c92fe2123271951cdc8ef6f5401618adb6436e19e3ab68888795ad0c3f4d63c1cbee7afcb22bb64168302fab8083037e947f8715e6ad1e5fa6b696ee072142b82d9dbe2b80107c1a17a22a54a58943eb04ca1a06c7b1b3c1b39449fc0e23678ab43fb49cf6e3c9a4ead94b8ed6bd678ecb6ac14d0d26d58830e623ce9cd6e2d5a99f1b", .Okay}, + {.Shr_Signed, "-232c0b635683a9e118df5e0d5125f04753bc44d8b21b0075a9bb6d58e844d1942e3c316513b84752d30c541a83c6e80c644c62827d2d22711969a46b71f55e5bf831992d07d1e6183ba5603d497fe5d71132bd641562c478534cf60f445aa6534f9ba276c9b83457c6f1070d96ab344a4064983ebfea59a6de10571a2034a52eed52de4386e403c8f7c7d2ec0a5b29afc55fbd73484d6eafcebbf2abfd8d57ff0abae1e17c084ee186e6452f2806d6950cc91147751683ba34d9fb57d581791d8511a92fd260f417a8415da08e3c13a80bc8a0ac8b6330ead756721f2034309722553b060e07128f9b40a171d20096ee6e8668bdfb7a92f68a9718ff71bcdf0130f14611c4bb993b1759be2f4411964b9038ffdcc7174f7ef6d640d00db503b7d48286bbca53fd1686e1482ceff8b36f5b996ef84d6dd071636c4dd6cbe99e0707394ba42d5f739450e1fee1bc916337ea71172e211d7bbb11f5d97f11fef9d23089215857c5a5a026c09941f7449cffd169c186ddb55223b92e8a713218060fe44567bdaf1f14a048dc172138872b97a51126bf37f8371629a247ab7499d1798a95a710c6050c805b9752930700eea7838dabcf65ce921c4ac6a964cb2b7c697972d04aafdbf5e6df503e0c1c96f491f607a28d77927e06327e625f3652d6c7e805a79361c7299b148a09ea2ae1a76862095cb934a8551abc110bb0160e89be", "4f", "-465816c6ad0753c231bebc1aa24be08ea77889b1643600eb5376dab1d089a3285c7862ca27708ea5a618a835078dd018c898c504fa5a44e232d348d6e3eabcb7f063325a0fa3cc30774ac07a92ffcbae22657ac82ac588f0a699ec1e88b54ca69f3744ed937068af8de20e1b2d56689480c9307d7fd4b34dbc20ae3440694a5ddaa5bc870dc80791ef8fa5d814b6535f8abf7ae6909add5f9d77e557fb1aaffe1575c3c2f8109dc30dcc8a5e500dad2a1992228eea2d077469b3f6afab02f23b0a23525fa4c1e82f5082bb411c7827501791415916c661d5aeace43e4068612e44aa760c1c0e251f368142e3a4012ddcdd0cd17bf6f525ed152e31fee379be0261e28c23897732762eb37c5e88232c972071ffb98e2e9efdedac81a01b6a076fa9050d7794a7fa2d0dc29059dff166deb732ddf09adba0e2c6d89bad97d33c0e0e7297485abee728a1c3fdc37922c66fd4e22e5c423af77623ebb2fe23fdf3a4611242b0af8b4b404d813283ee8939ffa2d3830dbb6aa447725d14e264300c1fc88acf7b5e3e294091b82e42710e572f4a224d7e6ff06e2c53448f56e933a2f3152b4e218c0a1900b72ea5260e01dd4f071b579ecb9d2438958d52c99656f8d2f2e5a0955fb7ebcdbea07c18392de923ec0f451aef24fc0c64fcc4be6ca5ad8fd00b4f26c38e5336291413d455c34ed0c412b9726951", .Okay}, + {.Shr_Signed, "-1a98d72d2eb3a802d6b7707d8b9169bb98412a3dc2832ed22c73a61b629657a3d914ed3c020d0dc90da2a78dfa99f9cc9c1bbba98c16607dc97f2072ac9b942dd02ba60b5665a5400c63b1ede56dd9c7a439744c7d9e9fd83c3e9c7527ae182d879cb0266e1aea970b3dfde9c53cf9fe7850a9093c857ec5a61d50761d4813a523282b057e51c5bef1d7b7cf360bd44a9933bba78bd6068748e0f16d8ae313ccd495022b89f497e5d86cbf48eac4a2152132321ce09d6c13c5c913ecbcd8f49c053c5f88e6c794c2d6810d42db14fa1990c40bbc190cada895ebfed0117205486ad11d14acae0c992cad8eb8043c48fa9251ccfd898cfb2a19a45d83e4b33ad9e591c2264b704716b3a11db835ae989b172f4fbe4cceb7c9063aa8d97b12b7605fa894977e4691632b34d2b88b8d976432f841e1f96e10b951dd765c5b5f7a101a3e8b840baa7b11321b0e24b60d917f857b4d48233d5c012607c59ba97a7ed397c15e1f570da368383bf26c08090bc6f44732ea9f238d3b129eb8036591e50b81bfb3705fe57527b062c986add5c33d74887508ff24b782a8bb60e00c10eb34ed73d0ba1c955fb35837e289174ad7136abc90e286393817ed3ec1cae766324b06258687dac1855d71595766cbef63828f5592e588778b4f53e2d4d91b02e1814031dcb2be43509d3c6a1ef28dfe93e1126b7eebc67d30cf63bdaf87a3cbcae3", "4", "-1a98d72d2eb3a802d6b7707d8b9169bb98412a3dc2832ed22c73a61b629657a3d914ed3c020d0dc90da2a78dfa99f9cc9c1bbba98c16607dc97f2072ac9b942dd02ba60b5665a5400c63b1ede56dd9c7a439744c7d9e9fd83c3e9c7527ae182d879cb0266e1aea970b3dfde9c53cf9fe7850a9093c857ec5a61d50761d4813a523282b057e51c5bef1d7b7cf360bd44a9933bba78bd6068748e0f16d8ae313ccd495022b89f497e5d86cbf48eac4a2152132321ce09d6c13c5c913ecbcd8f49c053c5f88e6c794c2d6810d42db14fa1990c40bbc190cada895ebfed0117205486ad11d14acae0c992cad8eb8043c48fa9251ccfd898cfb2a19a45d83e4b33ad9e591c2264b704716b3a11db835ae989b172f4fbe4cceb7c9063aa8d97b12b7605fa894977e4691632b34d2b88b8d976432f841e1f96e10b951dd765c5b5f7a101a3e8b840baa7b11321b0e24b60d917f857b4d48233d5c012607c59ba97a7ed397c15e1f570da368383bf26c08090bc6f44732ea9f238d3b129eb8036591e50b81bfb3705fe57527b062c986add5c33d74887508ff24b782a8bb60e00c10eb34ed73d0ba1c955fb35837e289174ad7136abc90e286393817ed3ec1cae766324b06258687dac1855d71595766cbef63828f5592e588778b4f53e2d4d91b02e1814031dcb2be43509d3c6a1ef28dfe93e1126b7eebc67d30cf63bdaf87a3cbcaf", .Okay}, + {.Shr_Signed, "-971c9a4471cc4f38c957c9c348fc6cbc4792b7f1098c28337e2fb94e1bf6fed5e9f4960ea011067ef88f16d40dd8a8a53709e276e3b730b3653ab4ac337a4286eea87bd037e657917228df878698a4c776420d5ec7fc3db27ccfe24fd32ff3c8e88d0990d8662e8990cb845431c332d0df9ff6e6ad6dbd35cb5c8cee7124cb97f49f0f9ccfc609511b84b7e9d1b3d555ee998a0d091f2d3e2bf49282eca27b46e5bd52a69894cf335cd1ac13b8ab3842d9c1c8efd5a5667575c11b5a126d57e17b2c106ebab1852c13a1af1ffda858d6d3d90d01667d1dd210108cbf6984dc8f3f18ca3011b517e86f93091d6c6cafbc99de027ae34bf6aad9d42599f146d0fd788debfe5d0f73b2bd61461053add793575e68c42283a2ecc61d75235fb4115339d5c76e2475d31c76b117958a6e7c5581c354b4168785ebd80611c8c7a7c6620b7effd7796de78f2f1b20a9e7063d4e1d8835406a1ff08a9545cb5485ebde02ba49f60f71b280d1a60c20f17ca3a4d6cbfb1968a5dcf7ed23b470566a695217be92f2720053f7d3da8b9b3003ea6365aae2290cec1badf38ecc51d7461e55ccb24267e9d71c5bca810c6d9c367248493a5b42f7468d5ebc87b9fc33f29fb1f2067f21734a563648cd1effa0da4abebca72751b489a1001e39e042f4cb525b07402f73a753c18dc94f1817559691825bf4d9ca353b3ee1f0eedd78ffbc38034", "6c", "-971c9a4471cc4f38c957c9c348fc6cbc4792b7f1098c28337e2fb94e1bf6fed5e9f4960ea011067ef88f16d40dd8a8a53709e276e3b730b3653ab4ac337a4286eea87bd037e657917228df878698a4c776420d5ec7fc3db27ccfe24fd32ff3c8e88d0990d8662e8990cb845431c332d0df9ff6e6ad6dbd35cb5c8cee7124cb97f49f0f9ccfc609511b84b7e9d1b3d555ee998a0d091f2d3e2bf49282eca27b46e5bd52a69894cf335cd1ac13b8ab3842d9c1c8efd5a5667575c11b5a126d57e17b2c106ebab1852c13a1af1ffda858d6d3d90d01667d1dd210108cbf6984dc8f3f18ca3011b517e86f93091d6c6cafbc99de027ae34bf6aad9d42599f146d0fd788debfe5d0f73b2bd61461053add793575e68c42283a2ecc61d75235fb4115339d5c76e2475d31c76b117958a6e7c5581c354b4168785ebd80611c8c7a7c6620b7effd7796de78f2f1b20a9e7063d4e1d8835406a1ff08a9545cb5485ebde02ba49f60f71b280d1a60c20f17ca3a4d6cbfb1968a5dcf7ed23b470566a695217be92f2720053f7d3da8b9b3003ea6365aae2290cec1badf38ecc51d7461e55ccb24267e9d71c5bca810c6d9c367248493a5b42f7468d5ebc87b9fc33f29fb1f2067f21734a563648cd1effa0da4abebca72751b489a1001e39e042f4cb525b07402f73a753c18dc94f1817559691825bf4da", .Okay}, + {.Shr_Signed, "ba43bbf80256663a0e8df4f1e5548e87e62e66ed0862689023dfed10af24ff1d8928ac1b413b1fe6e90fdd6de64a0fbad64896c59233722338571708486c46cfd84f913a4500aaf3ba4c6d1f3648fc53a331991e647942ddfc91d46d94075564657637bc18533e8eaba4f718ddec9a4fb8cbd4c16250f41d05192babefccb5a3f34be67f1550370f9576afe8f7130e20bbc55c350b8565635127799b3e1297c99e2ae6539fcd9725d0872bac7fa427bcfcd03e5ad98365a7716d32208ba0b05ed39fe5f3d1269bdf29932c6fa316eb9436092f39264220f05d88c9365b750770718942e5a3bf3045aa0c7e762b2630f7adbe3b6260ba5b55915d3ce06b0be9e7bbafd4f6e1cfc3ba91d3ecb344d1f6efa63f929baf9217a35ee256a1a47ad3090a34652a337075ff5075ac9b1700e10f6c01fbc66397d05fc4dfef71906e2795d368ddcfd447f163b80e1538ae60e712af8fed586299a6c2ddd931cacb650eee7741ada7882840fce13560ee124363c5d9422304168272ed27b960a19f31bfe7ae3616595423e2f22ef6f3d3ca8bf010b63c9130b45e7575f656deb73dd91e651597eb63ff517312db7b42cb99da23bfcf839f4d9fa8af130060c486255adacc6649d2c8f28ed813290842b465c1ea5de5913231b197b182910991454b95322a7f878d895d7dd77ae3178dc71972be498ec667f2f6cbba7374bb074dca7315b0", "2c", "ba43bbf80256663a0e8df4f1e5548e87e62e66ed0862689023dfed10af24ff1d8928ac1b413b1fe6e90fdd6de64a0fbad64896c59233722338571708486c46cfd84f913a4500aaf3ba4c6d1f3648fc53a331991e647942ddfc91d46d94075564657637bc18533e8eaba4f718ddec9a4fb8cbd4c16250f41d05192babefccb5a3f34be67f1550370f9576afe8f7130e20bbc55c350b8565635127799b3e1297c99e2ae6539fcd9725d0872bac7fa427bcfcd03e5ad98365a7716d32208ba0b05ed39fe5f3d1269bdf29932c6fa316eb9436092f39264220f05d88c9365b750770718942e5a3bf3045aa0c7e762b2630f7adbe3b6260ba5b55915d3ce06b0be9e7bbafd4f6e1cfc3ba91d3ecb344d1f6efa63f929baf9217a35ee256a1a47ad3090a34652a337075ff5075ac9b1700e10f6c01fbc66397d05fc4dfef71906e2795d368ddcfd447f163b80e1538ae60e712af8fed586299a6c2ddd931cacb650eee7741ada7882840fce13560ee124363c5d9422304168272ed27b960a19f31bfe7ae3616595423e2f22ef6f3d3ca8bf010b63c9130b45e7575f656deb73dd91e651597eb63ff517312db7b42cb99da23bfcf839f4d9fa8af130060c486255adacc6649d2c8f28ed813290842b465c1ea5de5913231b197b182910991454b95322a7f878d895d7dd77ae3178dc71972be498ec667f2f6cbba7374bb0", .Okay}, + {.Shr_Signed, "-9f69d2bad3ac385f08fc4c6193292a5da01e03edfe9230a47ffe6e6178e29243403a8d0287595f5225fd05fa0cd03aa522490ba1fb6acc738db8478888dfbad0709efcd4cb0d760d56a6fdfd4f312881ff723b654156fe5d68ba8526dd9a8f2be6e9781b1e6626d73141a57be713168704c96f26445c5cc8e7ca179e823cef40018c855507fa6daeab80fed6a54250ee2a8672669918ca24450b29f12fec1ef9ee4bcec14830e981d092596c638846418b5447ac968f93c93bef5e095708bf95af11ce036d67e7c1d6eed56e6780053bc533744e5ac93cdea75e066d4e1d753dca900e49f9d1bd8d61b8b9f2742c9e34e3b6410590ff7c1d45aaa19091e2d241faa78eddf572ee939f8e2b60afed896ce38707539ad314cd36eb13b69cbfb70e4cb7875a3e5e621ab6546d7ff864fb6fbafb2b701bf7ea2c18480152bf597dc1f82abaad23a40dad9d902381bea4c3a9eecb0be6f490d3b92a5470d9b21b04bfbf2dd2fdd595b37b3235e0f065c7e5dfa028a1552be509b3e06b7c456fbd44114000aa51e426d8649ddc82e1d427bc66b9ce7bdd326b7828c42eb726bc0d39921361f54045829771d23dbfe4d7a40e1936da9d7cd945aaadb8c1ccc797f27abce82b9febd5fb1d563d49ba60df7446f2a423630c486fc27d74067ba6ffd7e04cb65586965e9153e54a09b3785cf60ea50137459c777284bf56973d56874ed1ac", "25", "-4fb4e95d69d61c2f847e2630c994952ed00f01f6ff4918523fff3730bc714921a01d468143acafa912fe82fd06681d52912485d0fdb56639c6dc23c4446fdd68384f7e6a6586bb06ab537efea7989440ffb91db2a0ab7f2eb45d42936ecd4795f374bc0d8f33136b98a0d2bdf3898b438264b793222e2e6473e50bcf411e77a000c642aa83fd36d755c07f6b52a12877154339334c8c6512228594f897f60f7cf725e760a41874c0e8492cb631c42320c5aa23d64b47c9e49df7af04ab845fcad788e701b6b3f3e0eb776ab733c0029de299ba272d649e6f53af0336a70eba9ee5480724fce8dec6b0dc5cf93a164f1a71db2082c87fbe0ea2d550c848f16920fd53c76efab97749cfc715b057f6c4b671c383a9cd698a669b7589db4e5fdb87265bc3ad1f2f310d5b2a36bffc327db7dd7d95b80dfbf5160c2400a95facbee0fc155d5691d206d6cec811c0df5261d4f76585f37a4869dc952a386cd90d825fdf96e97eeacad9bd991af07832e3f2efd01450aa95f284d9f035be22b7dea208a0005528f2136c324eee4170ea13de335ce73dee9935bc1462175b935e069cc909b0faa022c14bb8e91edff26bd2070c9b6d4ebe6ca2d556dc60e663cbf93d5e7415cff5eafd8eab1ea4dd306fba23795211b1862437e13eba033dd37febf0265b2ac34b2f48a9f2a504d9bc2e7b0752809ba2ce3bb9425fab4b9eb", .Okay}, + {.Shr_Signed, "-4e35d7ce37f754011b93eab952dc70a992982cef0f955c0346dc8c25bf1c49dff95b50be498a36c0b865a31cd5825811a07fed8731e7e90cd7b5bf7f8760756e24dfcbc936f83979928c74bad71e05f56cc101f368d4262e9a7dd601547147b4bd89988e79215c9f4b62a925559d4f68e8d14c4e431d6a413cbdebc5b53d5f477fad7aea636d1d87da91090d30e54c4351421a40d95bab31cce6aa74bcf817a042933ac6b0691b64686a43201bbbf9063079a12cb4b6e98e3871181cc72dce153ff26c3d5a4428cdc01adbb31d40e7dd57b4cb10631b21d1d814949a9dde7dcc03fabf3d25cf7d5f54c545aaf24cbacdbf516f66fef57f07ae50b9819b9fc1b125dba65396e956a00d12a8aa02b72425310ad9d1d8b6bbaacc4044ef89533029b64de4ec59b72c46c0c6751a101eea800e8e4ff5d12d8d06bc84bf58019b709a547c2ff17c455f0d562cbc0e927a48094fe6c19debd5440d346fac482819babe633f8395cc045aa343ba31ae3816a58d9c86e85c01e4cf66f2425c8be75422a71c946406fe8c63885ae595bc966a4cb07f9d7e2f9c9648fbcc748aab48cf2a2f1789e17841c926bebf483a6c043bafbf4c5d9a706dff56408945b80f1a4346db6e461ccdc6450be8174b4daf01aa6bd84873844325473c0433a46e08320f98e50ec52bbbe2bcf19a213151934a0ae18d412db1774e759ffd34d72828a871168f", "b", "-9c6baf9c6feea8023727d572a5b8e153253059de1f2ab8068db9184b7e3893bff2b6a17c93146d8170cb4639ab04b02340ffdb0e63cfd219af6b7eff0ec0eadc49bf97926df072f32518e975ae3c0bead98203e6d1a84c5d34fbac02a8e28f697b13311cf242b93e96c5524aab3a9ed1d1a2989c863ad482797bd78b6a7abe8eff5af5d4c6da3b0fb522121a61ca9886a2843481b2b7566399cd54e979f02f408526758d60d236c8d0d486403777f20c60f34259696dd31c70e230398e5b9c2a7fe4d87ab488519b8035b7663a81cfbaaf699620c63643a3b02929353bbcfb9807f57e7a4b9efabea98a8b55e499759b7ea2decdfdeafe0f5ca17303373f83624bb74ca72dd2ad401a255154056e484a6215b3a3b16d7755988089df12a660536c9bc9d8b36e588d818cea34203dd5001d1c9feba25b1a0d79097eb00336e134a8f85fe2f88abe1aac59781d24f490129fcd833bd7aa881a68df58905033757cc67f072b9808b5468774635c702d4b1b390dd0b803c99ecde484b917cea8454e3928c80dfd18c710b5cb2b792cd49960ff3afc5f392c91f798e91556919e545e2f13c2f083924d7d7e9074d808775f7e98bb34e0dbfeac81128b701e34868db6dc8c399b8c8a17d02e969b5e0354d7b090e708864a8e78086748dc10641f31ca1d8a5777c579e3344262a3269415c31a825b62ee9ceb3ffa69ae505150e23", .Okay}, + {.Shr_Signed, "533d4612597e519302b10bcf3555b72e8a6c0152824096e832975bb3d80e3b6aac7cddafa0a865034e1b83b12aa03147a160d113297438a5225c0c72abda238a958776f2f2c90aacbdf5e055de06738e5d609ad5db544720ea4e874454f0a4c7adac46296a2eacac4cfc9a8c798022967cca4a77d557cff879874aa44f5ecce164cf609eceedaca93c7f41d8994cdd5ba5d30c6c7509f07db1f37a4ca768825012db9bd86878b443314c7fb0550f3e83ddbf0ead4a7d05ffa7ecbc6ed869ff8a57cd62807c0be094cc54e3052b4dedb68c863b26265e54e275a1f3f91a8ed877496c2e7faaa8f0e0f5d5ff42dd73607304e40b0a1c6f426e911b68930f2882d61af4d7c3fa244f0be6cdb5ac9c0253a2e689c6ac8744a68d459caa230c3cc55a3f04abe206fb0895c70c1e146a233b02b5bd2db9e312106442224a1687bcd10e6e955dd6d84b29676ad83af5d7ccaf7e554255234680dc0270e1c04e61b5864f7ded6b4b082542e2ad0f2157f7ef1debceffeb2cdd39bc0adbb28b6bff079a00412df3308110a5a2a72798b19410ee26db2ac0eb4e7c1bbf30cc6b36b7fdefe2ee90220f9e7803db3d929e1d6fb6912f3db1f286bef85412db1cd99b124294a829cc32f4e7110ea0b26e55d180538c534ec6e715c5fcf638352e2ba27c8249b02c0f28f955c41832971fb28ea38c4f8134235bb41a66a73e725ac8c46f7e0ec7", "3f", "a67a8c24b2fca3260562179e6aab6e5d14d802a504812dd0652eb767b01c76d558f9bb5f4150ca069c3707625540628f42c1a22652e8714a44b818e557b447152b0eede5e59215597bebc0abbc0ce71cbac135abb6a88e41d49d0e88a9e1498f5b588c52d45d595899f93518f300452cf99494efaaaf9ff0f30e95489ebd99c2c99ec13d9ddb595278fe83b13299bab74ba618d8ea13e0fb63e6f4994ed104a025b737b0d0f168866298ff60aa1e7d07bb7e1d5a94fa0bff4fd978ddb0d3ff14af9ac500f817c12998a9c60a569bdb6d190c764c4cbca9c4eb43e7f2351db0ee92d85cff5551e1c1ebabfe85bae6c0e609c8161438de84dd2236d1261e5105ac35e9af87f4489e17cd9b6b593804a745cd138d590e894d1a8b39544618798ab47e0957c40df6112b8e183c28d44676056b7a5b73c62420c88444942d0f79a21cdd2abbadb09652ced5b075ebaf995efcaa84aa468d01b804e1c3809cc36b0c9efbdad696104a85c55a1e42afefde3bd79dffd659ba737815b76516d7fe0f3400825be66102214b454e4f31632821dc4db65581d69cf8377e6198d66d6ffbdfc5dd20441f3cf007b67b253c3adf6d225e7b63e50d7df0a825b639b33624852950539865e9ce221d4164dcaba300a718a69d8dce2b8bf9ec706a5c5744f9049360581e51f2ab8830652e3f651d47189f026846b76834cd4e7c", .Okay}, + {.Shr_Signed, "-a8c7fe49d52fb0f8caf3e300cd8e74b5dd3c7e12d7deb239e360bb7058d473f80f226dfb276592e7db0eab85598f080da3dd073ac4a8765b6170ee05c86173978d9bfce5a03fb4d9aca3d1ccf3a70228810b47be576e6536c7311e1c229a1bb77023587691ac5a848e63ec3dc111ef1ba7ee8089e5ee6bd0e7bf9e01761ca83fbc82d289a6fb74a3ad00a7e1173d000593f874b20239cc45f2347f1b34f4f2c6d9f9e978f80d588916e9b9c175ccc74ca145b9f243f838cb0c002f63eded461a7be2cf9d790b69be43ec2a241ca43aa829ec004b8b9e3a98b7e07ada6b51e7622eca9430602d5982de2e49acee169bce7acabdb6c5b95cb0e3ff71dc1ce5c1c085f4f561642c6026d5b3eeff4b349b783bae44a315a5778eb873d32c5a96c209ba22f046a9727b66bd6e4422050e7b85feca544ea900312268842e727a5f03d38ed5aeae67cd757375f241e149be83a53e656e0ef46f19fa0b9375765f939a52658abb94cd383409b8a035218720e4a3079ad095434772a707fe0b156d3bdb65e90d52426602289ed9410553996e047a7aa9f20f77c6c202d252dbaccaec519011f1a4a83d74837815a11f3d03cee7bb9c4f77f702668b4590c62f8f491436f8f354c38ba90c9c2e14aa90800f7a59dedf899826e2add7467b23233ad17e0e0d8f5f2eb61d06b43688637d87ad27820590a91c5d0dba3f0c946f89c7f9c0f7f7", "73", "-1518ffc93aa5f61f195e7c6019b1ce96bba78fc25afbd6473c6c176e0b1a8e7f01e44dbf64ecb25cfb61d570ab31e101b47ba0e758950ecb6c2e1dc0b90c2e72f1b37f9cb407f69b35947a399e74e045102168f7caedcca6d8e623c384534376ee046b0ed2358b5091cc7d87b8223de374fdd0113cbdcd7a1cf7f3c02ec39507f7905a5134df6e9475a014fc22e7a000b27f0e9640473988be468fe3669e9e58db3f3d2f1f01ab1122dd37382eb998e99428b73e487f0719618005ec7dbda8c34f7c59f3af216d37c87d854483948755053d80097173c75316fc0f5b4d6a3cec45d952860c05ab305bc5c9359dc2d379cf5957b6d8b72b961c7fee3b839cb83810be9eac2c858c04dab67ddfe966936f0775c89462b4aef1d70e7a658b52d84137445e08d52e4f6cd7adc88440a1cf70bfd94a89d52006244d1085ce4f4be07a71dab5d5ccf9aeae6ebe483c2937d074a7ccadc1de8de33f41726eaecbf2734a4cb1577299a70681371406a430e41c9460f35a12a868ee54e0ffc162ada77b6cbd21aa484cc04513db2820aa732dc08f4f553e41eef8d8405a4a5b75995d8a32023e349507ae906f02b423e7a079dcf77389eefee04cd168b218c5f1e92286df1e6a987175219385c295521001ef4b3bdbf13304dc55bae8cf6464675a2fc1c1b1ebe5d6c3a0d686d10c6fb0f5a4f040b216", .Okay}, + {.Shr_Signed, "afac5e1a6cf5a1f7b304eba87473bf549e2ea16d7bf8ed4beb1a3d1a71e2879eb5a12c268dac022eefabda9eb04e8d4eb4471b2f415b2df3ef12dd0825a03abf66b6884c1853c963dc5ff69ec647e921a53f924587e94e18a6d0dbd121b3863ef3bc13ccf995558a147933a99384970889a4cb0a8b49f69b0295769d84053d66237d1725ede3624403fcea08a1b96626c118c6219cfd276bb3b1dafd1bc27a453e0a189be3bab804a1b6f919e382536f39acc1aa33ef9107cf845fec7b376a8970e1f57f9a90972c0f44e404f0b13bdd194cb8e3a5c9237a0c4af48559fe5693e58ea11af64f9640f9a0bc9f2ba93e773a0a7e351d4bb197008b230de863820ac019adfd20c98d304480002ab0e90fc224077db707d2446df900743beed12df274db161788c950bfc650abf648efb2e05d2f546bffc3148714ceecaa7fcb87fb289236987d16c79d4755c194c54f66a59c203aed460aa7582254e278ac893b8b5285028306f52c38329087f1786a1b9f97b77c178d97867b3e6b84f0aac0df6cd325093bef0042d24283b9256ab0d262cabe957a80271f59b1b7d10c52ca6b81309d3336314925a9f1771a9d8d2f6aa5640fbade276e4a21f30e08215451887d4a1de5b096f45e59019c8ccf05070f05343f1aa6cbf506a52bd1d28baf380ce700f78c7273c73b25b66939e1dcae8371799c02aef6de73ca0c7cd17a82dbce2f", "28", "afac5e1a6cf5a1f7b304eba87473bf549e2ea16d7bf8ed4beb1a3d1a71e2879eb5a12c268dac022eefabda9eb04e8d4eb4471b2f415b2df3ef12dd0825a03abf66b6884c1853c963dc5ff69ec647e921a53f924587e94e18a6d0dbd121b3863ef3bc13ccf995558a147933a99384970889a4cb0a8b49f69b0295769d84053d66237d1725ede3624403fcea08a1b96626c118c6219cfd276bb3b1dafd1bc27a453e0a189be3bab804a1b6f919e382536f39acc1aa33ef9107cf845fec7b376a8970e1f57f9a90972c0f44e404f0b13bdd194cb8e3a5c9237a0c4af48559fe5693e58ea11af64f9640f9a0bc9f2ba93e773a0a7e351d4bb197008b230de863820ac019adfd20c98d304480002ab0e90fc224077db707d2446df900743beed12df274db161788c950bfc650abf648efb2e05d2f546bffc3148714ceecaa7fcb87fb289236987d16c79d4755c194c54f66a59c203aed460aa7582254e278ac893b8b5285028306f52c38329087f1786a1b9f97b77c178d97867b3e6b84f0aac0df6cd325093bef0042d24283b9256ab0d262cabe957a80271f59b1b7d10c52ca6b81309d3336314925a9f1771a9d8d2f6aa5640fbade276e4a21f30e08215451887d4a1de5b096f45e59019c8ccf05070f05343f1aa6cbf506a52bd1d28baf380ce700f78c7273c73b25b66939e1dcae8371799c02aef6de73ca0c7cd1", .Okay}, + {.Shr_Signed, "a47a5e2b3d54981fcc413d22a050b6c79183934ee9719cef6f2f10b1186d76c6caa1494451837d8f8948257343d19f0b66a1f3fcaa805c7b8e8cdee3dfbd4e0bdf41fff9ab0aba1812f69000bfc9750979e15e88b79b3e2ccb79f7187514fdbc2cc748a65d61b491fc084dfed7cb66e4e8e406f2e8f7878fbe8e1ed170f8b1f91c34d0a7d7122ea77f3a5799333152768378174ebd86867a400ab5a2858a96c80c94ec464f18474d55de498e0dc24637b4f76f892153398e48c698c54147eb083f8f81ee3ad1a88339f45af1f12c53bb5b723ea060b97339094d3dd0f8d40c0424543ff0491df22d0bf243f4b9d4de25b3757c26362d4d80adea5389a9621b5022b04585f8a74b80aa60b3adea1db9eab1979218f16436b5df9c0cd180f0177163c7133139773f716b94b6bdfaaae161890e19b583f2fa51796d1346f41366cc2589b2d688022ec95bbc5433e1f6991b8c39b627f1321e5c25b2fc870dd1ffe67a7c2b5b54d216bf56bcdd220963bfd42b2cdda2956707d5365532fba29880ba0c222066f4ec4b04e1dfb7d50a2bbd7b6bb1b1a6cd8a81d36fdaf0a5f2220ddc20af8cd2b388480f4fdf8506867a7a124e529eacad87c250944e6483fb00522385daba34da614b3799685540516c0e3a6de57cbcc393a5c286622af84326c34a3a6910c5f85dd5aece2b02eb25dc311b2b9907aae1d4529b2f243f1f62f74e78", "43", "148f4bc567aa9303f98827a4540a16d8f2307269dd2e339dede5e216230daed8d95429288a306fb1f12904ae687a33e16cd43e7f95500b8f71d19bdc7bf7a9c17be83fff35615743025ed20017f92ea12f3c2bd116f367c5996f3ee30ea29fb78598e914cbac36923f8109bfdaf96cdc9d1c80de5d1ef0f1f7d1c3da2e1f163f23869a14fae245d4efe74af326662a4ed06f02e9d7b0d0cf480156b450b152d901929d88c9e308e9aabbc931c1b848c6f69eedf1242a6731c918d318a828fd6107f1f03dc75a3510673e8b5e3e258a776b6e47d40c172e672129a7ba1f1a8180848a87fe0923be45a17e487e973a9bc4b66eaf84c6c5a9b015bd4a71352c436a045608b0bf14e970154c1675bd43b73d5632f2431e2c86d6bbf3819a301e02ee2c78e266272ee7ee2d7296d7bf555c2c3121c336b07e5f4a2f2da268de826cd984b1365ad10045d92b778a867c3ed323718736c4fe2643cb84b65f90e1ba3ffccf4f856b6a9a42d7ead79ba4412c77fa85659bb452ace0faa6caa65f745310174184440cde9d89609c3bf6faa14577af6d763634d9b1503a6dfb5e14be4441bb8415f19a56710901e9fbf0a0d0cf4f4249ca53d595b0f84a1289cc907f600a4470bb57469b4c2966f32d0aa80a2d81c74dbcaf97987274b850cc455f0864d869474d2218bf0bbab5d9c5605d64bb8623657320f55c3a8a53", .Okay}, + {.Shr_Signed, "-f2d22771802ae10c0766f72e6a6fd06e5c60a9c064935b5f5cfa5536e3e5d6bb108ce049d75a100c1b7ff0b5dd4fa62865b51167cbbbc7009ce222fbe992e7e4e44084dbf80851252e74707c138ede81a6744da6917c46937a632e061eff1e5f2023c6867518e721f6f5791c83700fce1854b4fc8a2c08a97dfe47289b7356d988718514a41c3ad24d146c7def15ba2a884e7fd05e02c6dabd6f4550ee9e3ec064f2e9e8c971cf82c4179fe87ba60f7823bc46d7b7adf216186e291d5890e1dbef1ee6d42681fed895a4fa2c7c9adddd652d1f30e1b8b1fe4cf515e3212f7f0a0f3bc63f93249e570e616dbe7ef5538f4b46e8ef5fd56af434c37395cdb9fa5bc6b3ff12a801f7cb3910665d15d5b87fc07b9dc7405bcf98499ff7e1799422bad9c1de4bf288fb6774755c730bf63949e40ecc49e7f0e1f32ab2aa15f2a19c5866e3e67745bb8206ba972f4f471622176582823786398c158fbc11f4d07ae126e087e0bacd415ec9b37a21dde46fe11381a2758f2de8214de21c3276e824bd33c4dcea045f2e8179515ae3647bd75fb8c7f4a967840c279573f82e42e87933c58b1f08f1da884aff47b03a9b8b36a5160e7ed8ba265da3b3b25dc9c234edec56dbb2ec0ffa9ba252fe7d5b1ba244b61f43bae369cc2b8167fd061afcdcca72effcc5c4d9850f8492c184242b36538c45ca282b9e85e2333f3bc422fd43256cd2", "0", "-f2d22771802ae10c0766f72e6a6fd06e5c60a9c064935b5f5cfa5536e3e5d6bb108ce049d75a100c1b7ff0b5dd4fa62865b51167cbbbc7009ce222fbe992e7e4e44084dbf80851252e74707c138ede81a6744da6917c46937a632e061eff1e5f2023c6867518e721f6f5791c83700fce1854b4fc8a2c08a97dfe47289b7356d988718514a41c3ad24d146c7def15ba2a884e7fd05e02c6dabd6f4550ee9e3ec064f2e9e8c971cf82c4179fe87ba60f7823bc46d7b7adf216186e291d5890e1dbef1ee6d42681fed895a4fa2c7c9adddd652d1f30e1b8b1fe4cf515e3212f7f0a0f3bc63f93249e570e616dbe7ef5538f4b46e8ef5fd56af434c37395cdb9fa5bc6b3ff12a801f7cb3910665d15d5b87fc07b9dc7405bcf98499ff7e1799422bad9c1de4bf288fb6774755c730bf63949e40ecc49e7f0e1f32ab2aa15f2a19c5866e3e67745bb8206ba972f4f471622176582823786398c158fbc11f4d07ae126e087e0bacd415ec9b37a21dde46fe11381a2758f2de8214de21c3276e824bd33c4dcea045f2e8179515ae3647bd75fb8c7f4a967840c279573f82e42e87933c58b1f08f1da884aff47b03a9b8b36a5160e7ed8ba265da3b3b25dc9c234edec56dbb2ec0ffa9ba252fe7d5b1ba244b61f43bae369cc2b8167fd061afcdcca72effcc5c4d9850f8492c184242b36538c45ca282b9e85e2333f3bc422fd43256cd2", .Okay}, + {.Shr_Signed, "878f08eee0115631aacc74c0fec660ca66b687ae736f624b638ac885c04a8060945578a5beed5ee5aac74fecbbfbb1ae959bde837575da635615e9be0d7c950107a06fc697732e6598bf98565f1b05bb429c78c628e9d956050fbcecd926c7b994ce21479bfee9afb09023397c98a4665b2b9fa116cfebb85639ac2735c0ea7782c04fe2e7761f380e6c241813958e0d4e107eff3c071ffc54f0f183cde7d58739b3d43bf92b3657c9e526631e78521ab7a9a408a21cd9d70cf8dbcaa7454e67bf8e862dc70557158a40b1319daf28ce18b4d1c523fa201277843d59539f197c26cc0c92ca35580d345e7c89cc72b9ead5a66275bbd80f4f1e1d2478994245d7907cc6a6267b953996c5aa3dcdaa4dedddb1e46d656463d68b2247d72d25d72991c5ba2546afd7d602caa8953782cb45890874f6a47e8c1b2ed207ba249039a453670406926676fe279e4918d807977e991cce8324430549f040eb86a8079df8e3dbb9390dcea5c7b1135414d5510509e39acd1b51e7873867e5eacab1aa13526a9603c3fcde7216d2acab76c24ee1e92b971598eb23d7d35e877350de884cd5db0c20dfd77ef3af265e32c20432ee752ad93760351addf88c3d0ac6bda6d95da6255e0020653e0b70384363a4b77621c4a2469c4bc37f3a36dc85f21a034dd0fece121cbbf077e2b9910e07150330e5bddd3812694438e4d60b0d85e2f0c554", "20", "878f08eee0115631aacc74c0fec660ca66b687ae736f624b638ac885c04a8060945578a5beed5ee5aac74fecbbfbb1ae959bde837575da635615e9be0d7c950107a06fc697732e6598bf98565f1b05bb429c78c628e9d956050fbcecd926c7b994ce21479bfee9afb09023397c98a4665b2b9fa116cfebb85639ac2735c0ea7782c04fe2e7761f380e6c241813958e0d4e107eff3c071ffc54f0f183cde7d58739b3d43bf92b3657c9e526631e78521ab7a9a408a21cd9d70cf8dbcaa7454e67bf8e862dc70557158a40b1319daf28ce18b4d1c523fa201277843d59539f197c26cc0c92ca35580d345e7c89cc72b9ead5a66275bbd80f4f1e1d2478994245d7907cc6a6267b953996c5aa3dcdaa4dedddb1e46d656463d68b2247d72d25d72991c5ba2546afd7d602caa8953782cb45890874f6a47e8c1b2ed207ba249039a453670406926676fe279e4918d807977e991cce8324430549f040eb86a8079df8e3dbb9390dcea5c7b1135414d5510509e39acd1b51e7873867e5eacab1aa13526a9603c3fcde7216d2acab76c24ee1e92b971598eb23d7d35e877350de884cd5db0c20dfd77ef3af265e32c20432ee752ad93760351addf88c3d0ac6bda6d95da6255e0020653e0b70384363a4b77621c4a2469c4bc37f3a36dc85f21a034dd0fece121cbbf077e2b9910e07150330e5bddd3812694438e4d60b0d85", .Okay}, + {.Shr_Signed, "b637bc3957a206678ecadee4aa5ae51146f9b08d9add071ff2b7f0d04680bcdab5356eeaf8d89f6b90ae7f9c0e530661a84c4551a0606ae2da5ea76e9ad9c032daea14982150ace7f0d0190597a792222ffcfd6a3d65c5c2057162c3bffd7ee71bf28669bbce36b4b04e2ca81cf50d9e1e062887033d62bee6aa49a67b32d3198f7d041d974087b1dd319251f8a88212a0a3eebff3480b0af39f4133d42fbba89b0aa5a532432d763661b77bb55902c062bb56d8f8202b417846667d5e366bf2e4a48211ccdedd36e3bcb68a8a1f16c4b9a7cb73315a7bbd1a2f7af8811ccc5cf3f5056f575f63a42dc8b5bfd469769359ddfc8b1021077808af5c944057d07e164b4e3ce83e9cbe4bcc83f1b030d18bcd90338e729cdf39e83afb07ebbcfbb25258768d63d39a787354b102ffd9118322f1982270b85cb87a08e36cd98d88fc33a8dc8a51c52ff1ba6a8b1dc02f0c06ce745a2aab47417499a045039fe1938122a81f9c3d98473253c121afb4503fee6942d151373df6ce8101ba16dd72d481902cd45a1995812fa77f25b1f77a2d7f1caca5ebbcfe42c52be1d7d390f60263362f27165a7c1eb274e58b2b0b3435db194ed85c320c13e3d44d091ef02911d92176a0456b74659f3ffd18f44232855d8426780eb6633ea090e4796f0ac49bcc969fb06da913e05fbd67ce9a1d3529e57164b6c2bfc64cd2d08a08cf0f02bfaa", "1f", "16c6f7872af440ccf1d95bdc954b5ca228df3611b35ba0e3fe56fe1a08d0179b56a6addd5f1b13ed7215cff381ca60cc350988aa340c0d5c5b4bd4edd35b38065b5d4293042a159cfe1a0320b2f4f24445ff9fad47acb8b840ae2c5877ffafdce37e50cd3779c6d69609c595039ea1b3c3c0c510e067ac57dcd54934cf665a6331efa083b2e810f63ba6324a3f15104254147dd7fe6901615e73e8267a85f775136154b4a64865aec6cc36ef76ab20580c576adb1f0405682f08cccfabc6cd7e5c949042399bdba6dc7796d15143e2d89734f96e662b4f77a345ef5f1023998b9e7ea0adeaebec7485b916b7fa8d2ed26b3bbf91620420ef0115eb92880afa0fc2c969c79d07d397c979907e36061a3179b20671ce539be73d075f60fd779f764a4b0ed1ac7a734f0e6a96205ffb2230645e33044e170b970f411c6d9b31b11f86751b914a38a5fe374d5163b805e180d9ce8b455568e82e933408a073fc3270245503f387b308e64a782435f68a07fdcd285a2a26e7bed9d0203742dbae5a9032059a8b4332b025f4efe4b63eef45afe39594bd779fc858a57c3afa721ec04c66c5e4e2cb4f83d64e9cb165616686bb6329db0b8641827c7a89a123de05223b242ed408ad6e8cb3e7ffa31e884650abb084cf01d6cc67d4121c8f2de158937992d3f60db5227c0bf7acf9d343a6a53cae2c96d857f8c99a5a114119e", .Okay}, + {.Shr_Signed, "a222f6951201367ccad6fdebc966873cdfdf6d06332be4e3665d24809df9ddba05fd7614d99abce1a56d67da94c6655d680d20e449cadc6e0b9fdf2bbf7cbc5cf557196f6454d6f6feb33792e103db1126aa17ac8413bef3abc2876d0c84fc20cc1b84f86b8ee8164bfefc9797d91d0869cdad42b814c13eae5d5f212724cd76f0a4ba0cd0161fecbd2c15f34809462dd538e5867e8d455dc6d32f14e4cc1faf96298df393cf4c329d479f9a16d4617759007572a1ba0f6b9d8df4c4af511ce1b597c534c011a71f8a8f655c365662b72e9b4146437fd8c86ef039fe897c61047dc4fccd314bcb6e22878e52ce25c45e49487729039bf7a92b10d01ecd04306b8a43ddb9ab4229ff9710db1d07b5f61706257b6f117a1f2ed673cc7b3ee85f42731ebac7287378d969d6744ff5b209217c7697d6d3f1d98a612f89327c80741b86daf05e25e67238c37ee3f51b6e9f2a27e9826e3905f07f234cb89f4fdb5aa75f48861507a9b00a7d26d20b81d88835bfba999bbde0108fc864eea03068ef08428681256b5bb75029c533e9ad60bccd77aece1221950d30ef90fd6a1d5b2b024d99399ba329bab5ea66aaf10db8552da87cffe3829007177665ee3cff0a06e1131b90c8d8bf73f58deafb9c3b9a9f85da2478803c0cdd464136e67f552d27e745b786219deaf4b73b0ff47b031cf34917163c3af842575c2ff63f93c371937a", "6a", "2888bda544804d9f32b5bf7af259a1cf37f7db418ccaf938d9974920277e776e817f5d853666af38695b59f6a53199575a0348391272b71b82e7f7caefdf2f173d55c65bd91535bdbfaccde4b840f6c449aa85eb2104efbceaf0a1db43213f083306e13e1ae3ba0592ffbf25e5f647421a736b50ae05304fab9757c849c9335dbc292e83340587fb2f4b057cd202518b754e39619fa3515771b4cbc5393307ebe58a637ce4f3d30ca751e7e685b5185dd6401d5ca86e83dae7637d312bd447386d65f14d300469c7e2a3d9570d9598adcba6d05190dff6321bbc0e7fa25f18411f713f334c52f2db88a1e394b389711792521dca40e6fdea4ac43407b3410c1ae290f76e6ad08a7fe5c436c741ed7d85c1895edbc45e87cbb59cf31ecfba17d09cc7aeb1ca1cde365a759d13fd6c82485f1da5f5b4fc7662984be24c9f201d06e1b6bc1789799c8e30dfb8fd46dba7ca89fa609b8e417c1fc8d32e27d3f6d6a9d7d2218541ea6c029f49b482e076220d6feea666ef780423f2193ba80c1a3bc210a1a0495ad6edd40a714cfa6b582f335debb3848865434c3be43f5a8756cac093664e66e8ca6ead7a99aabc436e154b6a1f3ff8e0a401c5dd997b8f3fc281b844c6e432362fdcfd637abee70ee6a7e176891e200f033751904db99fd54b49f9d16de188677abd2dcec3fd1ec0c73cd245c58f", .Okay}, + {.Shr_Signed, "2c6c9020a4b523c275bfca6dd483917856f183b2b69af89225c53963c2d019a133f24754bbc894584eeb4010dad60fa721c5887d3ab780b4f48351ca267681f0a68b931d25667992511e4d3b9a2f24b5ff4b446ac19cc3dd4ece1d455d1e32c6e85e0cb1e484fe6758986d95f45f64518604557d24b5c1a9c1ed0f27cc8061e2dcafd3aeb7f24df759702373aa4a7e91ca3636ebd893c8e0e6fd9a765ca17821d6fffde20f9125e2d6c64def515f0837231120bf2efc44fb950cec9e276283e16b2d35339ce6c47bcedf671f023402cb204ba178034bce0c500658bf5b05bb03c2d840483d8ee3cd5e64c50488c1e4897e5fc2593fe4daa09d33f1e16fdbe9418d801fe9c8b387219568795949f91d3f58ede96392812acf06e4ba27d0b6860192200fd7163cb907abc96f2881d2703d718cf378027dcc7b09cdc41021d3106176b7a3a778ec3c892c7094b38ca75b23d1834f52e2d496f3508ca074d640b187a7cc8c861b5a2ef3ca60a0fc52a9b030cdc4e76de158abacab7d22277e442701c2d077d5486ca32add5624e4cecfad5d62770d01486305482d018b5a34647cd7c799263ffebd26bdd6baa90b382ea835c5ea133d048e192f8d9ca41ce2c8b8eb02fb507351c93f5a316379084579a40c07aa1e7e55137c5e6c26ffb8435c217922cbb30633d46e8bfd88e599c195b9ae9bd476c7ce8bc23293436dd173d89114", "40", "2c6c9020a4b523c275bfca6dd483917856f183b2b69af89225c53963c2d019a133f24754bbc894584eeb4010dad60fa721c5887d3ab780b4f48351ca267681f0a68b931d25667992511e4d3b9a2f24b5ff4b446ac19cc3dd4ece1d455d1e32c6e85e0cb1e484fe6758986d95f45f64518604557d24b5c1a9c1ed0f27cc8061e2dcafd3aeb7f24df759702373aa4a7e91ca3636ebd893c8e0e6fd9a765ca17821d6fffde20f9125e2d6c64def515f0837231120bf2efc44fb950cec9e276283e16b2d35339ce6c47bcedf671f023402cb204ba178034bce0c500658bf5b05bb03c2d840483d8ee3cd5e64c50488c1e4897e5fc2593fe4daa09d33f1e16fdbe9418d801fe9c8b387219568795949f91d3f58ede96392812acf06e4ba27d0b6860192200fd7163cb907abc96f2881d2703d718cf378027dcc7b09cdc41021d3106176b7a3a778ec3c892c7094b38ca75b23d1834f52e2d496f3508ca074d640b187a7cc8c861b5a2ef3ca60a0fc52a9b030cdc4e76de158abacab7d22277e442701c2d077d5486ca32add5624e4cecfad5d62770d01486305482d018b5a34647cd7c799263ffebd26bdd6baa90b382ea835c5ea133d048e192f8d9ca41ce2c8b8eb02fb507351c93f5a316379084579a40c07aa1e7e55137c5e6c26ffb8435c217922cbb30633d46e8bfd88e599c195b9ae9bd476c7ce8bc232", .Okay}, + {.Shr_Signed, "-e059c1bbdea9ac7cc6e15684e38011cb7a93e936ee58d42d4efe4e2c188f9d8acee39ff528e690b637c108ec5515694798c6b3f4ac52ba3711408df061d1ac2ba5dfe26b477b21b0d490657827afc7ce2223de3cda94bf5088ddd46f08b829dc6db1bc97b3c6572dcb75bad07130343fa435f19034b4208579c48ba14936df53b9d722a92b68e9d7deb2a4318cdfa619dbc59967735288b582da27585bf7fbbf2d3bf81c9ef11672123847bd2f4a5ed090ca559ad2fe740f54cc2e203ec2363adb57d080735897e0428ee651c12f2864d1336507972045ce80171dce73663e825308972c1dfa0dba3b956e8166ffba3f2b1477fc1b75fcb8734e19b287667cb2257d50afbfda9c3956ea1125d55b9ca0dd51c67cd27aa5f36a0b5d74e101b509b361aaf57318d2be6d7127b67bdb95b3824a6cb81428339b36fa7326e3874184ae92db4288f7123490d11902faee81ad32e95922a5af0e707589b2128bb7fabbc6b9b87179e61514c00817fa6d5f9df15e0ab6138de2bc54613533fa0508148c8021d94e9b7a88b9ced65a373970964585387e5f5887b6c55bfb6d0b34afbde6fe4395653ff4cd41b1eab8b161f241e3ad888f8f0ea9fe5bac8e51d7e4cbbcd5fb249b31fdc438bddfcdcfa07654c2cd03b45374a1683d6573d2727e55862ce0d48a4f6acd290cf1f20284acc8de5f4ee1eb37132b0ceca5d9bdc3468e1bc4c6", "4", "-e059c1bbdea9ac7cc6e15684e38011cb7a93e936ee58d42d4efe4e2c188f9d8acee39ff528e690b637c108ec5515694798c6b3f4ac52ba3711408df061d1ac2ba5dfe26b477b21b0d490657827afc7ce2223de3cda94bf5088ddd46f08b829dc6db1bc97b3c6572dcb75bad07130343fa435f19034b4208579c48ba14936df53b9d722a92b68e9d7deb2a4318cdfa619dbc59967735288b582da27585bf7fbbf2d3bf81c9ef11672123847bd2f4a5ed090ca559ad2fe740f54cc2e203ec2363adb57d080735897e0428ee651c12f2864d1336507972045ce80171dce73663e825308972c1dfa0dba3b956e8166ffba3f2b1477fc1b75fcb8734e19b287667cb2257d50afbfda9c3956ea1125d55b9ca0dd51c67cd27aa5f36a0b5d74e101b509b361aaf57318d2be6d7127b67bdb95b3824a6cb81428339b36fa7326e3874184ae92db4288f7123490d11902faee81ad32e95922a5af0e707589b2128bb7fabbc6b9b87179e61514c00817fa6d5f9df15e0ab6138de2bc54613533fa0508148c8021d94e9b7a88b9ced65a373970964585387e5f5887b6c55bfb6d0b34afbde6fe4395653ff4cd41b1eab8b161f241e3ad888f8f0ea9fe5bac8e51d7e4cbbcd5fb249b31fdc438bddfcdcfa07654c2cd03b45374a1683d6573d2727e55862ce0d48a4f6acd290cf1f20284acc8de5f4ee1eb37132b0ceca5d9bdc3468e1bc4d", .Okay}, + {.Shr_Signed, "f6468bcd532987bc4af9b2727c087d9caab2eeccef6ec271fbca41b6b14a31f0bd76545f80404c86168d631cc583eb1d12bde6dd29a60f1d6705692b3ddfef723fa386bfe57e68a5e77ba65368f551ba7b167ff9f87950e36c98dbdbcd69ad7b7f2351ea43f97ec09f00c39cb49b912cd924b29fbe245da67d363cf6f955c34e7051f1195044f191941e7e7a0f6c77436dff06606294d8985957ad8b24f763dad54da97c54ad662cd8fbb3ec82c5c3d48fd532055c4f028407fbfb681067df5b25b0b738a71b12471a887ebac7940c4d15bf38cdf48e4a577bdd1e8a898f6d8e764cb546e1ba7f5f88f3715487344d29bfebddfa0cdd8040bd92b51774902b0a9f1e8a6b2ae5bc4b58e9f5018cfb5b4114875d0fa9d0a85317af7f57df3f26c0aff75cd498f1b96dcde35f1c6e99b2829a7371efd37d47616f5ec7b041b37d10a3e91439c6b9e0070be595aa1fcae244a28d1f61d9dc4cc5749abd26460359c61b09ec6d0d365db15ee53fdff7cf1ae0c047905412a83e97e7dad28684ab645103835e061274eacd0280060b3252c03a7fc1162e1249ee88222b2b789e9f0b6a3f48b9bdd9a0dbc7a92ca07847f3dec8e6348e1975b0a516d40fc7376299e883ab25bd8d1beb36504a5258f811b6bb29c432013719ec6866996a4001532ab46db11b6b636fd082bda397a292b2c9c7cfe7a5ace692088a23f28e683625341e71", "21", "7b2345e6a994c3de257cd9393e043ece5559776677b76138fde520db58a518f85ebb2a2fc02026430b46b18e62c1f58e895ef36e94d3078eb382b4959eeff7b91fd1c35ff2bf3452f3bdd329b47aa8dd3d8b3ffcfc3ca871b64c6dede6b4d6bdbf91a8f521fcbf604f8061ce5a4dc8966c92594fdf122ed33e9b1e7b7caae1a73828f88ca82278c8ca0f3f3d07b63ba1b6ff8330314a6c4c2cabd6c5927bb1ed6aa6d4be2a56b3166c7dd9f64162e1ea47ea9902ae27814203fdfdb40833efad92d85b9c538d89238d443f5d63ca06268adf9c66fa47252bbdee8f4544c7b6c73b265aa370dd3fafc479b8aa439a2694dff5eefd066ec0205ec95a8bba4815854f8f45359572de25ac74fa80c67dada08a43ae87d4e854298bd7bfabef9f936057fbae6a4c78dcb6e6f1af8e374cd9414d39b8f7e9bea3b0b7af63d820d9be8851f48a1ce35cf00385f2cad50fe5712251468fb0ecee2662ba4d5e932301ace30d84f636869b2ed8af729feffbe78d706023c82a09541f4bf3ed69434255b22881c1af03093a7566814003059929601d3fe08b170924f744111595bc4f4f85b51fa45cdeecd06de3d496503c23f9ef64731a470cbad8528b6a07e39bb14cf441d592dec68df59b2825292c7c08db5d94e219009b8cf634334cb52000a9955a36d88db5b1b7e8415ed1cbd1495964e3e7f3d2d67349044511f947341b", .Okay}, + {.Gcd, "3f1ac58fcee77a9e30856d3602c02dbc45c02604c502c3ed7150a03fa9518e5b4cbbe7c3baef9c461a92c94996bb76ac83913b709b667ab4e99ec16a89c4a76491d5c7da33d7f41b81314645f52aeadce0fa1da5cd8fb50facfe0d4bba8eb8e2b6fe1320a5f4ed024ecd4fd1dd9ee077ee9264614edf80a5864559dc7851707d198fdb406b858c9bf044f2d4656b5959e2299908241477d59da8da767118a659ac01cacc2bc480588f05718f446f114d9aba334a85ad9bfa5fd918d13cc16e6344c9b6ea3b4f8beefa13209482a60e8ce00290298bc53f4822ff900d6f863734bd45e0f725070bf217eb02578446ee31e06d4dc5a35598f3f3d760ccc49cd730b68f8669cce010e678ac12ff84548f2cc7864e64f0fb4c7d5f998594ad2254bc36fa01451cabd3b23423e50a0331b8b79393114556844e3869947b34927c1c3eb1d3f684fd831f9294be03d92f9c7bf430d97d93e1763c0b3113fd016a43e4c86c3700b365973cbcc82f9b6b1988a53d4e09d1bb0275b09ec8a48a9de89b78da053600f5272ca872c4e8747111b860f8ab35a5d5eefa4c7cb486a813ebefd26cc66da6d11f737d16e4337e09d106a72cd6a478d5a291d2ad1a9c677009df517fec99863f1f04193e2cc5cb921020d3566c604bbc6b43ba0a2994dc08a81408a57ac1477be6ac2dee0fe361b9281db0dab200842afc341ef6319f38458b93a04d", "db0cab92895f670509d237fdaaa4c094883c8ede25d0fec6a97dd01781834c1860cef9cf83e3ac070f4c5c5a9436ea9a7b76a88304b57cad85fc08124523633f3f740cff1ea69678ea7e4cdffa8e4b959dcf6e90d74ffc56a644c7e5ed00c26f851bcc0d8b48f7fec7f1673c4c274f72db96c9f8c7d740b445e5efd2ef86ed0126299aee8e0986c8b6c673756402675cea59142ffb2540eb6fa468cbfd794d63207bdd38ffdb6efd69ea1cbe5e775cb47145d849683609857e9884bd6467cfe7c11d57af2abed6385c0ad60c995f8747db2f96644afe8262da35c81b2358f37ce411d1d230a85ad9f35023b8f6554ecb71e08075a070c67d0f3d7666453653636fc362a338175217f362c44b982a53f65eaaf1782f28db57260332dff6d8e39511f1aeebadd47a7fb443f2b50b50132bd88376daae229e68e115260d008538476caa21a41b9c83e048b38979e92faab696311480bac62e527e7fc1e8272254870769ecbd1f2529e60ddfec20560b08845daff8a0c6c548624afc07575d5f09f342d5f797326a48f6fbed10772b232c0358bef90066330d8a3a3862017f1bfb9a0708673c4aca790730b4ce1236412681afcd080de378dee665d09821dc2c7af43beae81ecc0b0de4f200e230c015ed120e4d27e019c0bc983a1aa83734b9ca54865326b57e5b33ea0f2186d26e1228da39046657e9b68130e68dd8174b3e2703", "17", .Okay}, + {.Gcd, "6cb0eea9f2c39a6484adc39c16acccdbecc7f42119c8e7259442519d4b330d5e2081287d722eea0387753b1ab5c1804d827cc2fc8cc30541cdc572910d7de4cd50c12ae84e0aef70218513b5d190b1b9315ef6b9566b8280a4463b8df4b80beead60c3a5c7688f71cf9e51c66c16976de4fb4d68ccddf015090252740de11410ea2396ed4f5402121c64433647fd452710d1a42e89d952d7ff160d9682458a77b117056789ced9e548c9b5cada2f5c4a0f2c6e822e83328f6bb27f54ebc19dfe304c796e39705cf3d48b9ac15cf51abb0640a37963093d467337d402ac4beb42d17e5e86c146199e5ca481c7c02d2d84d1ac295c2ec8c4255443b36c0371b14d22e29c8cb84210d16351262ef045c880993be4457fdadce62e33f7d9d80156e47f275d9fbf81128c4e685a29b098b99d4963852afcc87177101044d6a094acab47a2be8962c368a0b8b5b74644f54dfeb3e1ca5fe64adc5e5971c96e4c8648fdcdfb95f0a7928cdc7a675f94ceae1e46604180670f9cd77383ea84284db4e36bcdb63fdd26f593f3b44cdc185feb7d891975c18b5f64cce90bf35ca198fcfa304dc50cc8ea27868ee6abcd828b7f51b8e56afa9430d1e8cea1938886aa7cfaed313aec422094a3b14f9a7dce66d68d7a9e74652ae536f8a0cc3e6b8190a9eceb643e8a7d9a4366c2235383e784e9ff4b0769d6cf3c14343a2d898df1aafe9724", "53facae91a5e025e78c55c60d969d80629fcd8a6c599ddc8b1606bf57cbcfb1b365aec7f621fb214868e0d83b40a15e7b37d51ab1eb8996c805983efe703c36e0532933e1299d4a3f1acc33a317ddbfe6a503eb16aa5d628f4b9b4e78094b14ebe5cd25241a0cabf7aa8a38b3e013d00031ea5b7ef292af02d05298629a9a087b1594e1bbddbe52c6c90c3fdee9c468a309c1bb058817e7692bda50309f610123de3ee243c7a9cc2a9d0fb711c7f893a1376271dd1f889b60814a910c7c6959aa5b07dd3f7ad42d7a6055cb2c61c146397a904796add7cbe47b6f980c4bb2eddd5c7faac3644c312ee42ea05b292495223200335990d66985c60500d1630e45031564f8e5c95592bb6310b7152c5e24dc8f2cefc96dd259ff7eb6a7ac22f5c42eff799514f94aebb63c243afdcc126833867286fc8a62f340eb988e78cc5c23962965dadf85f5f18a189b9e19fd89206cca9d2ad2523c400d99c03e393bbe7fffcde83aaed48fb0ea44a495e85a738e438eda279e409af7d68f71c33baf5c897d529f7ce4b19759d864f3fe5ebf221ecdf3230d27a3a7415f6e6a60b47f73a3761c70da501ec20b414e3dee13ff29a9c3ad2776a5760ba4632da4c2bf513c49f7895b0b021f0807e7946f3edce47cba07a20aeccb31724d3e50ccfefa78c8c23aae99d8f53e2eb29e2d83a72c0a61d5fd251a23b64b2a5cf34484722c7228fbd", "1", .Okay}, + {.Gcd, "56bc480386ff1fff5cb14bfdf12dafdd7c9ee8da97837a55624bb7cbc70a2b086d9345e7a3b6458e19dc5aff9b15b81af1c99cc2b5d8127bb121f54407b3339476619897c2fb1b53db7c5bd26c7ab37a7dfaa599c03d7ea05e9123945e2afdd255091561ab806b65ee083f25be28ac9e0b3c97c23d0594b5ff90e941f2d8d520123cb912e3ff2a862df2804cf6770aeb490e4c49e629d62c1eefc973c1b55775cf0879d08fdb8920791c0b9ca97ea12887dc310de2da8b25bd13b5741f2d06f419c1917991e3c167a9a7faa829c7e2a67f5f2d3ab095fefac627adfa155b26f2ef802b15d07fe44a39cbc890d255062428c1d988045f2d6062cf8e7d1139aef2c4b5bdd3ec985331efaad14f0deac067b820d52e1db9f890af1ded61da1cca29fc33fb18b162dd8ca2ee61a86fbf69daf349145b635cd34d9c91c465e4e94a1967f2d7976ce89af71c112996324ae097ec837df08ce47837b098e69f6d6c3009c7b963d0e30e89d080e76f62be227cdab6bd82da0948f31bf7b1b69b42bf17b3ecf851128c4e6c8219f1f6dad821d84294bcfbf968ce25ceead96db584ef558014c837c1b9479aa5b9cf4390e07f913d8494344cbf01162a314722ed24115fae0c49b1969851f0ea60877d9a8b7b06f90269d93e82fb0289487ffd335aebc47c36153bc274feb29518871115efb798aaaf120dd74e3c65735465cf8253d4f6f9", "9f6afec994719e423f369825c3ad6f26997f8bb2532242be786964b6dd9c08c6389568027afc62f295c34e8c471b925de115b0802283689c5e598811fbac3e888f6272407742f4657999439e7769d76343387b188f8f90721e7495f4a7a892bee7459e5e1fa96221545ccf7e203e335b9b3540717421b63bcba91928c5e26814b3add9f2ab80a64a4884620d2a9082b80a3c05cfd9094dcc4f7f5cac8e616110694e7cd848e538687024b9847e168c7c4f196d26678425d1ec8e26f9257921b3d0952918e0d339308e518548ab22543207d6cff924d1247bc58f5b5d871ad0486b49f632664d4ae29503e85f4ebcf240bad5c9dee7badfbc350b943367949896513e0ff44de1a353da7c60093f7faa780c14dc69ebf49ec094186581f35e51121d02ae8655b4be0d5ece48cdbcb2ac9252a2ea4d1c3f9b4f8a51910552b1e424a8c037ec2a944056bae74b993fa589a9f8a8aa3f50a558fd099381a46a0679ba5a4248fbc2ac30371b31af544d309da98f0ac4757afdfb1ce85b68fcbc877db98b29c7fb5939edbb7e8b874d39ec9e93f0d7762f7bd8bd9d5fcf89d9eedd2ee4d5ee4caecd165caee3b2fbda27fd429bc83c571e5b7fa51f11092c6f66f477b1c3c34552d3f602a0f85e14b36d657e3fd2c138705d0df3263b6e30822dee4b61b8e60d91c09036f7b67638c039c145c1ee723ec54b27a9929be9de0cd4f88bfc", "1", .Okay}, + {.Gcd, "-300d2353ab824cdec8ee64eba1f963e0c06a58e9bebed947358d1e0ab10b33af001b0829b17192fb0eefb07f9114f78a964b7da5cfc42d3bd64e1c48d52c204601820043f9fa967ad4a41c07e6078fa2074a5676443de1cb4e27bacc78cb6af6043af507f3700627dcfa79ffe28ff465e274b0f5118113cbd69806a676b4fdfb59dfc3906c1eeba1b7ddbfaaf911d6628b7f9a2e303e685817c4117c6251de9fb534ec7f948d4ac3b260ca46792ce46cc66e41c35953e1a4d2aa54555829fa08b635bbd4c538c20d86bcd1575cac63a28047f97eba96c74dca7542f2fda8b633e9e42e48f4acb3e8fd4bf7ea9449d4b8233135ea73b69a0751fa0d38488d7890503803d62a1ef0bc40d15516343b3905eaf1e6165816f5bf117af59c0077739fa67c27525b89a2e59404c915d1cf839467ab9364af55474e3b3c77cb30a6635a1f77d290855684ddf41407c67bda31a400bbc5fb99c776ee8db3826ed2a40a6341a9ba794dace26c0cadb62a32caae5a23cd66006eed14310d6659c0238ba6a41b65262703db2353181e2f82105d391b9f59fe9a708b8180d4fee03eea704f816be6e3f40025c030b6987ad209dff7a44931cc9b40f6c9ab3075635570c30ee1018731113b4188c9fa8cb3d006e70bcb2699101f15b6c97ac13b13492eb00c488ae3bb0f918db4a533f2d24415a98fef6633975adeee91a0ee887e0e5f17ff3f", "a4ddeeb31caaa20c154c4f120fba4b48acb9abb46d8a855c5d635e9056a303947834bb683ee91249b31f015cbddeddd6634c657c5553b6dedce7d3c6dc7ce65a848bb89eb27a7aa5c72ec86bee4759f9ea14be30282e74466933e02f05540e9cd548ecdeeee31f3530d00dbf0eb46ac299399c9edfa5260ea3238f681ce64bd9ff1104a07d4bf2c10e471fd9d69940c8894b41946f131bd4dc6418fb5ea260c3f625f59ed3bb3bb07788c4a89d966c5e8bc0d2c993f0d5712ea5650ca315aabad00d3f4c4496d082909bb73f694d5cb9210f4d836b89da79373903bfd344db3b0ffc1caa138cebe9ca88bfa05db7adc55426099c6dd215d6b4488d1f7083bb54b18482325c98c69aaeb644c650f13d81e7e189d8fc5ece97826992858df863c60b5225d7866350adee61b96993ff183bffb3b39caa066edc829c1bee2af84b164f2a4c2adc51b632cb1a6856ae4fbc8f5c288630cbeacddebd8bad3e087d808755dce2936976baf9a814ba02278924312ed419f24d1a27ddfc2f753c090192aed28344ad13d8e379209c530303f508923fa869a37d6489f080af5bce7b94646133eaac33c00009fbe2fb459472cf3f10f84f9eba86a653c7a36fc947f035a134e08293e624c71a3d3a15cf418de67e4a3e3dc5742030ff18bbda451e1006a5d13b6c1ada1cf0a3b98b369f3f685c34ee3987e3f12985f022121a4835f69cb9e8", "1", .Okay}, + {.Gcd, "2fe81ef712751659535b9bd4429454e14c2515c45e039cf5bfa65d2511e832b17f96ce3fa9ea2945e6a3ef83b0ad4e06764966fc905b0d7d0952b071d3ff84af9f8dc22523f8926f0f668ba68a127e46a9c849279cdf5826f8f1b18cccfb44d0bd71e2559ee87d660a0b39a9379f7fa82d256c369b7478c62a9b098c23c02aa39ffb650fc06e3e07a0d453819bb4dfba1aaa3b6dea5710c4f3ede6ff35469e0e4eb2a23cacca96821ae87315966d2d12aeb912edc93846ea79b6728e01809f5f9bd90b4f28eccfc15778dff714d1f55b93f6a9abeddb30646c42513220ce2418b1a71c589b5551a5a3cbe5b9b2d9b666411fa4a8135a4c2e9f6565be140f3627727db2213eff1c5c41bc98715813cc08895c79bba40aa620ef18cb3f8f5b6c874416303a973e5f542871caee582fc52343c2519c4e854d9d03ada803b03d81a74894bab124a191d609ec2b9f08e21838613c73fdb21b4d45a5d8eeedbb8b5fd57d7e26d96ab65656883f96670a4d6bcc9a8484ef09f3ab688fe9d2c0e81e057a187bb7e15e29cb28d15c4549d53a4c52c0e88a13cc46e9a0069ed90d639b1365561cd0db71132c31fca4aa11029c8740219bfe5d20e38c16088054068e28a7d4d8f5f1b8f6e6a26ce430edc36919ec6a2d9186cffdaf4fd1995afa5c7d6b51eb5f06779d12568f4605e8086478558ad0eff6949bc96c5af35d0cc75dad009d30", "583cd6a7331de2083db69c313383c390ff6c5c6c39fb0993afdcc1ef74a98803c1f7726331a335f08347e9d079e8d2f276b6bacbb500777c946ef2badc22d0acafe5fc7a7942d137e3d1482e37e6b16ced84d643efc0d07031d6b137b4a9a1c67af67c097fed56894913b747551cbdf82821879d05797ea902e4dfa10e9a7062f086e8c7b39eecd83cee70aa09676a215925ceb2573e3078b1f5e7c21f5f5529b9e709ecc4db0b689ec3e519e6294e7145b9831467db5cfa59a64290f4f5ab4a59663ec886432d1dabc1ae3f9ea755b865d6f23331d843f634a0e4872420932403bd8485f23fc239e3734ebb83b65426ad9ca85cdab93ad6aff9f81aebc7cc7627f7713912d075ae61b3efa09f11414dcc7efefbf6b54f07a03fb5823a921c9d024419808ae8c80f0ebd978e2f08ee00e56ec89005055bc9416e858538aa0a0a0d3f64265cc6539d7590faa6d919117bfb531d6beeeb6e832573bd05752fc63ba64f4b003e2d202a29fc1a5c7ebb447ea9010905b8ac7dae3cee80b2ed22453df80d20df19756516f58ed6511b43ee7229b450cc035be52ac537165b72638c77c07c494ad97cf44056566935b059e4d714f65dee91286a083ad6edc09591914cc54d4012d85ad6218b710af21760ece0ad37d91865953880610b75cd53bac04997bbc73e223afc93f750ed06d73204895393f8aa0c8c0bdbefd5d3c7b8a0f12c", "4", .Okay}, + {.Gcd, "b03118a5f7ebd1b2c1aa2aa56329aa537db780c13bb4e2161c196533290d772cf0acb3c9224e5935af77b554c28d23e4313806df54d06e3fb05a9e896352ce7690809a8abfa4b216f85993e06c57b832941429b497b717e43724ee579158afbe59a0c7c7c8fb95338bd31baa81897a821487b34094e6891ac2e9afa068b32c4da682140f24f2fbc1e29d10ae722e1dae12a7a0cab7e214cc17e6af615cab596cfc266016dddf26530dcddfc6a98b88e408c855591bc98eb4a55d4559f6c4da0438c8e2587e3273f2d5073e34d36c21cdd7d743906cdf85896297c15c9300d8dd531819d64c6a3acf000a5999e614210c16c054527aa1ef073186f205c5b868149471b4a34f59f035d4a3adc32bd7dd36fbff038d3fdd105c3681e669732c280d071097c7262d87a89b7868fd423b15b287a6ac9215ca55d73172d36b9479d83c6e526b6397f84d10b7753bb9449ac2e71fcc50676e4ad15765e8c76497a780a5f6ea9e015ed18bb5a136967df6c871245bec693a2c5b4035b68976b25ed0a59e9f9b5f0adc1adfd90d2dca10c7923bd010a4d987a8dc2990cce3e715a3145e480739c1ed3b4ae772068940dc5bf1c6f6323d159b78373b5f56fa60992212c91d814c828f48c3056e9c32ba3e604f3a9b4e042486b175f8f040cb9a0920f176c69c695ae2475d42da6a71498548b3216f6d5986b26b71d82dcddaa256f1fb6336", "8d470a3090e5ba8ecf18eaebff3684e1085853b55282c2a79b5423df925979822aff0e40c3e59132bf8949f3028ee174e6338bb9911ee75f055f4735462437624885b533188578e0a1d99f126291e632236315d682fa68a2e935d712d062a650dfe58d37b43fbb59b26fef732d08257f0fbc1ad49dea1bfd8dfd98204c458ce71dc8871e8c27093712adbc3aa7732e2af9212f5b1d4dd4a2dc1985c492d056c0c82f38427e1ab160b0f0955e916a20a5f40d7d2e71a06a4bd15e9b62977c08f06badb2b089d83d1789d0bf2f459e97289f2d4ed03f6781218e508f68fb997a5492d80978240481d42a6a59b3e9398ee256f7a0054115540702fc1f1b3f659f2f1d13b37a9e01549c7ebbbd0505b8f7516ae2a57a12fd89c84d3f308e4b35d726919fafbd17e3d922ab52dd79394a39d913a58c0e4e6dc133beb5d96e9d44dc21cec623eaceb06af29e286467d11b574f3d9d7eaa90a604f9af2f353448c355ea416ff224566882cf4b1991f6af5993dbc2cdc5893feea6e04041415bfd09db3d1a73968cc770ad7b1de1d258ce0d34540df2241a8cd02a2fd337aada1365761dbdcb0a7e9e80b8613823efc9ee34a723301ae8b18c188ccb1b0c68c83083a8f5024c415eca1659363e093fe7d9af43637918e5a87a781ba8e2dad6cd02869fd2baa07a50df87793ba8428fe9667adb844c87cfe26537af9e6f9143e7a4dbee9e", "2", .Okay}, + {.Gcd, "-b20421f6b3d36d5087ebdd753636a7902b0cce1e821da6aec4e5625336900574f2658ac4914e51e5e6875996ecb446c145418cace3bb72de313c6505f3f1e255fc9d2c059ac9f7b4501d251b960edefffef40b19e0e63bb044c88ccb0c7f217298cb4c08f9df550ffc983ffa5634b3d79118de21fddd1bdc1022975790768c2fbf2bbe798667159eb3ec83960d1a1ae904029ec1c5cab7a9bdb4c5accb0230499df638844dac0d29ddcac9f4e61827bee1a9fa74248167ff7452dae828bedffb1654727b55c8f766280a02ad728a6a346e171894d89c6d41bea0ffbedf61fc61b194ce772f81b493e2cbe93710358cac98e77ebb791306f178660ba005ce55c42521006c19d15b6fb3a8b869545111a4ff4f9ba55f068ed0f531e18de2810c1f83f9b6e22f63e8f800f746b006ddb60c6a1dc951ff0e0bb89a965c4bd7c01c016a4378b52c988f300d61156630db143ab277d11ed5bafce6578cc107004491a7d7f77cd4c539cc0f9bff906ad58c87cebb27da66ab7b0bd03ff5e183f180a78fd7975c6187dc8cc21462095a73d6976caccbb15757864031af81def9cf60a0bcd4386eaf9a7828933a76b7dc00ec3cfec11148636a30afe9c895c101b7fcc6add1ed2b743543583f7720d1618f1a8a13399cd2765c474d323e5a0d3a6add8c2e926fe3a3ac3fb56c3db7703776a2b5c823c1a2bd240da24e2b9d33003b349745", "47540d72b4a0f3e12e3d547dd2e7d7d771c4a142eb6097e8b5c38ac87d5f6e8e2d638c2d4be7e67234963a040f059955b386533e0f9d8f673552f895b286c638c99eb288ad3c642e8404471f1466490a0db67c7296a3348ee203f1be8e485203a6d49df2693a62a6c6bb40b16d61fe19160620a5e61f66d1ba285b0ba4a07feb6562891846042ab5915dec19c71d0111c6d284a1ea8eb71ca7954a4d86352042f2618143b419b7fafc5e1d7236a697f7c170b0c01dc2b8086cef7ccad09113b59fa14e148b69e4f41d5631b91772ecb7a18c62d0b6b732ba1ebf31483d4118cc46de500ecbc0829fbb722abdb424a2aa245c2af3ccf1fbb9fc285d99a7635fc9861fb42d5dd9787397b43026f6028911975111135f120f09c9ccc43b0d1396424496f86cd61d7b03000b99321c7532688eae9034b4a3629cf2c238706ba5010de03b046ba0ca66d96914fa5571852c88e377a771cbd35e87f4affaa1f6a0f3c134ebe5c2db8af5f67293819e11939048938f529610f9f46ee6790a545a776c62b51c838e12b2c1a569bc673d47880d16615edc4a5f6fd1a6e08c60804ec2d292472c56a54fcb11d50aad312b8218725e19d329563149a7372d9223e810ba0ef5bee00b379d2837d94af1229b3f5c31ba9dfb716e786395cc6a96a913b172df3069e1303e682f9b581cd20c13faaff3e7a37af90c327cac9050ef66c7ed7cf880", "9", .Okay}, + {.Gcd, "-10ce830a83645cb777c7da1ebf33ac6a662b954990df2b5289634308f5f1714f7b170cef31d7e1ac308286d3d2fa42c4d948f1d27c899a659b2a00fd3595d6dbf1b2607bb93fd44451e113c7d87658fa07be9edde811dda43bfd7c86a90976d200c99f3b2efc3bd7080d9f15429c537df02e8142034d230456fb39a5c13a9dac8808f834451385425c2045f69495a33efa0e0cca51a9fbe31659163a49d9eabd961b05e3e29f42264e6f5d69a2912c3b07e72b828603b7863b5816a090b3502e8a004ad4abc2df8ae1043deb370e4f841d92de947314c53a4fb1fbf132516b2b36b2d37a4555e9ce4a389b40f9a781c6818d30dd2207a572395a4e12630f22802e2ee01cd08a15d40aa16e77001425856134ff1f4826fe875aa82ae8a248437350b10e6ef1f465a9106c1d61a438bdae61f3babb9a35a1de5bbb0cac755cb2bb9a0722c231df2b7f0807f598004497a3b227b3b9edea8163f8a48cc6abcbe1a6b7177f1ae3d97f2a36977f51fa0bcf282d1036a84f3db991aa23322129351e5ea507ecb3884e661669e860ea561ae4fc65d58a5506ce36a9c5218d1048ed6b8f5399a712c335fa93e52d302f6a5230d6b45fd7b85379164ff7bcd4e073573738fba0051f649f534a895cbf18655d39fb1c1657647f22b9fd76fc1a8ffdfa22f96f3048ead39fb887f35cc1bce51fb751a902164c848be5d0d449defff6b15993", "562e509099b10fce4ac52f635e4d577891bb764ec4f71d438f152577c1ed732f544268ba6d862691d9d0149397f361c82758d919132ad885d10b8dc3339b35de3e3e7fa1550b1ea90d0be25cc821fd12b086a15fcc700115c0bd5b896343402b1c0b65529c1eab32e6dadd2cff77419634ceb3d70bec8ad231ee5c624eda7103e09178b42a43a61c90dd9543cd3b6c39818f0636a1853164a8862973ab98a5483ddec3942805a33a23294d7135fe2b03feda7125318b97be2dc73558cbf31ef834125c9a194cc0df64a13784b6c0fffb1fc7eafad4779a9b774654b36b51e58337098b3adf3aa40101855a1bc050f1abc4a322d12de05f9a1172484528463fc2692550cad69140cd2268b1e5fa3de8475ec0a5458f2dcf3f0e3b663499cea598664d2a0091f573ac0e9c1499eca807585ccf598b8b7a4cb26f26a3eff80e28615b1322aa6d497818be51bf8339e3b751b28dd2ca3b6ec5fa6c4522169ea3addc7ecd5c8bf9200ae8069b7d35c5c9fac7b5d080241652fc97fe5b4cfb4795ae0dab1dc2a8b05b40d43e81ad4ecc5b93e11c6bc7cc71986bb889b16a15a8624e690299710fa597316693cc5b4e1ebf89bc7f5f89a90af7d969152597e7c9c00214e8c53621ac5b1c53eba20c9e702a36ba6cd1b4a3dbf8ac1afc11dd698fea5b644310ef222b2df989081f9d90c5d158d0d2d3e42369fba7e86fba34a55df4f39f", "5", .Okay}, + {.Gcd, "e57fdaaf2fbd98296de09476ff7928e97a801fd207959a2ae83bb21cac1724e0915ff5944656425c60ba7e66c7aaa03da8e631dba896277f3c5807fc51a489aab2d5f92730ac66342e07c8e8adef6a8983346f8c30e69b1d3db18201ab7249fa8caafa1efac41ebb29528f5bac6df217f05d2e950abc5771e0dea8f7dbc3bafe9ec8d1cb710b5d4601b11a1ba13a4db4a9bc16ec59a5a487a93a86f7faa01ac0d8038e86c1507e7c35d0c66a503c8918e02e245bcbf69b6c854d5fe01a560650641ba0bfa4a9b092e7b86879a55863ec91be87b2681a7f0da9690db120e8abfee4441822fa06f380c14ed3f8d06f16878ce94a6cfb51810f82fb4e4eca1dccd3d7c2831e78b7eea09d248ad81455821aca9f0d82cf9c2788dec7a880a07e24367c1c716c8cc49e513abe6039217ab4f90ed2b3b14966b912c9202fdf2ae795f336205131f040dc0fab63348db2d5568ae3f5be2cd174261b126861aaaea85657fcf076ee95e4fa2000c631896c3106e6f87d40f3f2a2194d3a5a0c28fd662c6b341835eca62fdea83e54f592dd108298195e2a19935b1ca9b95ca5f750103eae10eed71517287d846fbd68fd93c39c86de2163da511b63023c1558e0ff57e21b1b17d0161bca9cafc87473d695a2c5c18c4dc8bc14624b9d53d74a275dfcc54d49b6db4f57162e18a594270db226a03855db1cc6deaacb42a47ba2cb084af1bc", "6a24468d697d217543c3a4ca490fd19928468903b5e681c06707597cd0a2ce9cb1c8c57ba3e31afc8aa29aa34ac0629a51a441ac56db10a73b3d71c296e69d515375aa9bf994488227764d24b45fbc90ca3e4835528536aa153526c68afc6bb45b6c0f1ac41de735008503d8a5bd33de030e77cfffdfc989aa9dbf92eae3d9b5cbd2e98ad1012735eadd38cd2e3938d033d1259ed99c984cedcfaa7a55d9a089749e03dcc61824d9c13e794427c97aa646a08b0a33ae94142e6be09d6e324ff057da2c763a110860eb8e3da66db8ed22070b976036d86055dbc28012dec9ec17b612a75da173b7b2aa759f36008b1ff179bebfa3ad30e0dd43cba647e4f9785b66c9a63f70072290c4828bcca6e5d5ca57496e5632ce2113a4f4a1f9e84c2185ae3883e8afeca589a2879059c31278468e92d234193ba90d304407f558b647cc1d5029eb76d698d947023ec2464e2b711213f5714e899559ab8777927ec9397f48916a3cf4ab91780f3f1daabd298e083388f2ddb745dc19ff481245bc44089434ce8e13b62e8393b4f929ebbdafe18d7a1b5caa978497a4c7fc5763bf3211adee27dfaf9d52af4d1ce659ce58965cba6f259f0953e2b47baf416483a447bc867e918b809875de18c6a2d1cd48de8b3c0b639343e06517e97da208db373d4c6a4e3308932a444feacfbeb7a502a868330dbc2665532f6535908b5c6e61189bb4", "4", .Okay}, + {.Gcd, "-b0f6ecc76bfd501e56ce363cfffdd9fef78136663b011fe3561db46a85ad186ec94bc9ae2b053aeee9abc21af22a4384307136f3abafd9e79bf5a60f8f4902f440bdcbb4bb1c9f6892e2c353295ab50c4317f53eecfd2d51292a3296c1207b90ec8894062d7e7a3d4be75867e1e622aea89ec13620902c7419095a2f573161e9aacd56cfd0cf8c0e8da47d6d346bce050b5dee1c30fed2c2bc3b7dc4977cbab0ac6c4f46ab9a16c6d84ae2123855dde037de1e6f15b1a4be49de7735473445559583c3046c27f9d2fbe5dbe3dbd8ce8c93f8c9a94b7d1c8ba4ac7b62d7cb7228532b68a927ccdbcdc624c22f6f4419759a35ce25ddc583fe02cff22b2bcd5bf0ab4c918c1e18b93d9e93923d262f352385c93581f55464919a4a9d5545a99aa18e0e4595494f3029d0217db93a66fc7b1df1ee7d5d1c0872cefaabab4fab0611be41f932779b18cedaf2b26a85175ff285658b73f587641299886189af4cdae2e2c5027347344f66aecf79c292b1d5191546403369fdf32f2238b12020ae3faad9495425915027aca71730b1c2b8e266187b91fabecd69e89b52b031588c9bf34b0db3640a8d765f81baa34693add23b519f607c2b09b4681ed68d48d5828b48e3a3596ca089a7efecfbe939aca8c07288e2b5b6c117ff209fc88a9a9cc7213ad1723d0544e0789b166ab932f066721d4edb7d42bbe036c72b0e70b375d1cc1c", "3e654e8ac7ae861c915dcf98d6071d93000df3dfd525787febc5828208e599df8863a69dec58a957650cd19bbf795388f1bd31b151aa2c34235572b174751171c4c7f45273a5b5076546fa4c25119ee93d907205a034cf2b6a508a771dbc027bb3077a341f309ca8546daabc6f2f56cda1039cf6ba15e0891a4796030ece0fce3a5b1d523994e929b4ca577e5a91a97f5599242641260a82af0974cd50b15a99808ab275573bc83d2494a8274cbb6797491e9ea2f52b4c9a0e21975679db12575fb96a99ef2da714bcaa5595bad528e7e778af9ac8b7af1d65becb4e716c72bb3e66c61d68cb712829637fb78ce8369bb97f0a26acd8cabd3b3ff062de296f17814245668b6b6ebf4f4baf66f5eb6e74c0936a296712a66eb641760f37234aa4ec7907ce5bfb302a35ef53a4ca04238e30ace72e026324b6a845f53716b374997c8ead2cf745e09d88953534192dd83f7ce6c9c4da9a3abd9b762d779f74a6938cb5b643db974476699ef9b30096ebc9d1c1dfb73876df56c3a45ad01a86609f8d8b96b1fc0febd3ab889417334bbade396643b60cfc3a79c6d4f6c6c5c986f5975b7cca6475f377e4923cadee4b3d318740a8296c5db28c81e5b5bd5c0cd53b54b47fde3e7dbc73598dd17517bcd375c2d6f8461724ad4b9d6c829d98ef8e457065439eb57a4ba56f106ccdb44dff4ec65a58ad8f7a9cb372a1b8a6e9ccd6ca", "2", .Okay}, + {.Gcd, "40db096d789febe63358817a2a5dd4da0bd348c77a7270904ca7b4bb354ad37eabcdc02b454dbb19701afac0fa82fcd1a0d75ac2fdb7e47fa41d9c50ee4002407812912894e31e22cd0bc5026f9bb670fa737fd1784a3095bf68fc14d04d266373025449c7e7bd3cb93408170a7dea4e299636a90ab415dc281b0bf785bcf1909a6333d647a58b03bfb7dbd63e55551267d1222fa640b6a510f305f67ce20574d61061021b86762eaeb0d4490223926269621a0309065561ffc58cf74f2abfa5cd099d9da8de827f1a57fb845715b78e5c709d58e2b177a4853ddea93d68eb54a14987f40092610fc87235649878053a286fdf77f8fa07d274809127da160481ec5226857dc028d19745da5a7d7cc1829c9198e7a72ee2e0f929c32f70ac97b46bd1fb9b6b8e7c808c520f1db735fbf5621eaee2eb05eca854c29fd9daddb86b08f076753483964b36717883256ae5006b39f88612cf7a6b4f558e89bea8839aba414dc0cef11e97f74034e5b3794ac839e278347ee40fe6f0ad7372400105d06f74a4e509bd7e13fb4b620dfbdae39369ce689ffcf295cf45eed5d946dbbb5060706accd644c574b3461164842272ac4e59291b73d2650bb23a704baec6c4e5b58d11ea1565d6bd3d997bb46fe5f7b7cca6c427e521cf68b215421bad0ce820ef426dede10482f3c203f2b1feae36e61557dd8559edaf41d5fcc013aff12647", "380f0e7227b9acbb3931c78fe8f9d51a11cc5ecc670b185c0b479aab4cbfb29f5b7215953ccac079effd10c67e02cd30a392672db5d129f27b4bce11d4fe439b152d662f035110350321cfdcf69b2568bc8c9ea18a00fcd3a10894c2007e74dd9dfebf6ed791575095b0576f43514da4dd74c2ff2803d1c21c081ab63c0e21761bc94bf5e998b248c2d644693238c3205f15cd3d4e733bb18e5bcf81b7cdfb60d312e97fb5246bbb594e1ebc2e4413f66c0ac2857759ef3b8a13a99e76f16db8435b3cbe04ebdc07c91b519fcfa6ba0aebd7a43e783d8df5f919b0b72d953ffc4c0519f11c1a230ba8e7a60237f2a1f28db2b21b9376c56ec4253c3e15e8cab671fde5323d5cfa2eac9c327bd18d9780da2b45bdfc68447e36367d1d3ecaccd6fa22ab83c4ee2f4de50c1770a1160d483cd0909fa13a09ccde3d40f41d424f08a728448c5c728b2dc6ebc739dc5a4c4919f67c07503ce9b9eaed081319c7f707a376943433cd05790947cef3f8a0d1d4cd831f4c3689becc818e7b6f964ee668dd2869e8ddb8dc3e78dda6277b92ae55f94cb9fd98ce916393569187b22639316a674edb6ea94220814b4e5a6cbb63b949b587d87429d426aee3b06c6d5021c24d0edb22184210de0165f8fa9ac192a32d68cad6c2d2f360fa7cc752bbbc2cda9b85770f5657389a6098204c4d4aebd7e64da89901ed9609e4dbf87a7f2cc3f1", "5", .Okay}, + {.Gcd, "-254cac9125c792f8e7c7fe6ff8d62eb6b8ab29f25e6889c96b588fa4915a2909a31129687791ac5d1c1d639e3e2e6336c4097649c72e5335babc263534e244bf845ac933ac8209fbed0744fc80ef39cf8e270b1b7ead9bacdf853d8974b7ef9c3095e9ba098a6e4de18bcfeb7d1cb08af2e7815965bb82f58fc658da57e4f52dcbf728e1b1c2e5a1a53c78d85f71a94aca5491bca3541c2abc59c3eeeaed66e9369e8d07f58c85d781fd1143daf984156ba135ccfbbdc42752ad9599fcb8ae3ba1f1d8c902a2aafc2180943cc7faee1aea793cdc37c25228a4663729a4d806786c2d7f1f34f76d01c501d815c52c83d368a3e0cecf9b3849295cbc12ba9728fb278c48357a05fb9099dbb85c2fbde1ae799a26c5ee852315e3fdfe7119c7e5fd025898dbe747680dfd9d0829fb543ab3266161b95f35f46d018a94fbd54644ee301c33a530b07b03fbc344c04c2b9c54e5ef1378a10c0e724414f342c1a6a46a1b16f95d95074e3aa75a5087fa9ac91df0f0f0f7f12b37991f963a2c3587fa176f5be244654d6f470c3c2f9ac629e165069c52476b3ba85d6838a87fb177e772ead8c12892f2172e551a658ac9e1879cb1e6c7512045d4f85353a5c22e0eca1ddf6c612eeffb37681f92523e9abc443962c1f20b712b32c546975ed9440e30c846499cd4308a737de9e3fc90b84f9609fa2c8d04fd2eefa27d968a3af7287866", "b66f5e1570595161bb8c506ce513b58c4b37a91dc941f44133e6de6f25c4159abbf57778d16e1b4b870a666bc9e2d04bf0786c9963cfe8c177567ff7d169090ca01f8de887937fdc5ef3ed380ce0c597d6f33edb87cc4e3c42135e9c7bbac69f8517cc0968c9416e527c2c251e323b8294d60af9cf5bcca99c5192d2600469cfe1f97b4fcf77fda10af1c560c1c8a53925cd0b54b0f3e6cfabe4733d3fdfa855d93d759bdfb2f9d3fcd7b005573755f3a21d7d14cd0b4a967a12fd71c97ebdbe3e520f858583e1b2f0fff5ff34f927357b4b025826d905c05ac2eccd254c2017cea95e262c3e35a27fd73fa5cdffece50174332ce0005f1a99b247d8ffa10fe4564bc120f45378b24758781623ec7d1e028054a309eca03e8ae35f1f8e01256659b3fc94365db6869ebfa61fc53a079bffc0e2b545813fb4b2dd94d8b6c99f3fb611e0af75ee37393d90f77e104a30c396c9ca55b384e12bdb2e44b3255dd76fd6c666f407eabd28ab67e3cc6ebe8f067b268a58a47643f89f2396eb547654f9a99876313e255aa84023ba0c5ccc0d5c8fb9f267fff6a03b670efc6e0a3d155ba2c0b46a091ce2f840c786462fc38934bb7b123fe9e095d86dcc602958605efad29d1f7c839a933bb17a0d804e499d2f25632cc8e8d3097731dbe2cad863bd9128e049b4268a41b96549a0ae815bb79140338640d473b9c023c6a9ca7c2ab2ea", "6", .Okay}, + {.Gcd, "-64467c06740df5daf08a21a340ee5fab8ffce38ddf994380c1f5b268ed4f4d70821cde9f51fd060e7df742fe8e4b01a0a3e5ee370039498aa535b61d4137e921dae6caed55c43efa0a03a9354cb59bf9220c6996f6dd2f8938c021bfede7e699d00229627baf46df59b77a412f4c5fec730b95ab406be82448ed4328901b0b571eabdfb00819427e19b0ecd31bd03f579947063be915760da328a9bc88691fc5ecb31142426b0e6aca7e4733faea34555d2216582493c5c432ac90445fbbfb93bcb83da5a0d13cff8f74f4c3efbfc3b8bb496055aa5719593dfd68f6963158e18c7081a450876988353855e228ee0480f32967cf630675876fd2d91ad061299ea2b43a7b276db5977d6f2376ae6150ca0fbcc1d1a3f146421085886e548a4ff81465474cd19d983d1d217b4c9b3cdccfbd521064f006f4c075993e54ed6976ba1681590a010c4d896d4b29be862495f33e32c4eb17c109949cca3cefa5012a1bf6d4670bfd453ee9eb731ad5b6f7bf9e27f555c732bed013e4dea75f935dc4303cd1170da84ce35643f91449f3084461a52393ab935da6ff316ed209d48ff4470be063823076311d00892946d6ceb3b93d7c4d399f418a73e3ba2ef70cef57c59603fc90297ef842d28a39ed914a7c2ee238a3fd86e1b8c704bb7a7c30e50abf871e4270939f7785ce71c9e24b651b0c523679f3dfb1e2af6b4f8bd1e7540c42", "8020335873d2f0de6190ef5337209ea176118e63823ac09cc800833d975a5123d4327974e6efc2d21f1407e7460b5c30fadadb269afc7ea5a9cac0a132a6b4cd8456e623db8faa3b0ec25dc6f1744550ad33b7922ab083ef3f1e4453e9452c3454229ce4a0852849ea646639ae063644ca528d89868ef5a3712e459768a9c12a9024c37ddb656dfc82300ffb4501eff0fa0d8426b4e130b4a6c7669089065a53508f4d4aebbac2de39281dfe7d61fc8b0e07d4ebbebc2ed0b408d255948d9c6c02403f5398543d9be3e26392cfb8ed82d20956260ae6a4a470a8bfaa460e83f21e11fbea5e93842cc5034fc1d356883b36297237dd19635b2e338401607c7a5af9159b07a66fd6c2baa72a92ff7ea42f2e8afb7558f7427a5d8d5afa2f7ce08a5bd61543b8ff4ff9e7ca48c9aa3a08a482b7df06ac719261a7566bd4315d63ffc6c7d2757eb98aa2d0592a404a8b3f6179bbb85d672338e6f8cbd4adc5c89ad3a54dbbb79705630bb72187c51d70b9a9cfc022b65a247e2e2516588e9838014dd3d99d0875778a25bcd10cd5a2485746511117af739e4dfb76cfba009b2858b6b6311d294c9eaf85f5fb846049b7fb38b784b9115fac611e0b7e6bcb2aebf2e11c833fe991750794d1df4c408885fa2f87995c513e72f6f0ec35f08e514a0b04b52723b36474f7458aa660ced7da9c502456376e40c7bdf5e6d772fdceaf7bb1", "1", .Okay}, + {.Gcd, "f0f54e81481e54a34d806e36e277ffed44cb49a0dcbea822b1294c5ce2593e2bcba40c56da3871d7bbcadc292e9ae08e7f0d4a4eb730eb4c645d886af6367ad7dd11bacc8d905071ce7dc3f4b3240c027320389157c545f97fa04da7347036c0a58429b4373584c5b06a3aab165f88281b3876543e10227efd751a931e72fed98660ecd92e0d2d40b6ab464f31da16ec8880942ef596153388cb4ed999ad70a39f45c3f3123105c269a792c2ee11a12ff00a4629690fd35465fdbd2990b225410b25dd74635b35781579c5a61e9d11b38a9df0623b58093d454b0d58644ddeef59fdd6308cd8c9502d878ffce5003365c25c4c3079dde8d4fbc6c0a9f5dadb9d017a6accf98df640518ec59affd1a60cc33910263337d0314403fbfcc0ce5ac6bac1d45396263998bdad12cb41f9fff8149fa25273fef795632ea7adb8862ae5569ef3542d4df247f0fcf1ac52ad9c52b422e0e3b76ec8bcbb5cf06f3b2462c9436514f488a01288a480b956b26419971c1bbf1c89d2a3014c6b0a3662f7d00b19cb286ac9014f9bb975d69b69129e633c7e37e55fb7fe37246dd483c632f40360470ad48fd8ee31c6b0681d58ccfef8494ea8194037779e23dfbb269721c545aa13b3600b69a7949ee4923400f3cf99c5bba7b38180bf7e731be10451cf3f68ccf3edfbdeb10daeea7700eef24bf3373399a38919c24f415b6c35e969722fcc", "f7faa695284af51ceba7099cfb702595a5fd69989f515ebac8fb0eb3135f98bd512379866d31bd4e2b77d90e089fa95b75be6829158da0f6f236784132a961bda788f19311ac72260e05b6857ce14a6c6d97a48e3fbbf6c66d930d24193213a7ce5b562c14109eb2b42cc867c0f9424504b5abbacac1e03372f24a120950ff1a7bb6ae070e00e171e76224675dd3f7223686e0b4a1bd1ea6318b71b590bc8a01c4fa000c2746cafc1c9c39c69cc8ce0b6e3ea18f69e4bad49de5d80b9c3c1e71b2d4e0aef9b2583855c9b1df18d2e11dd08fa5bc8783cb89d43a3f38efa4576bf792b5534e6b7fec6e275cf79ac680cf03132743e6ae3c26e67bb4ed5f84b6d202255f2cd123e3badb30ea754a144c12ca27ecabbf7bd84480ecf4129ee927b1c28808cfd0348bc0401a69257f82abbb3f75c3bf1cc0a1be70c77b2df2be6ff770a8ac7e1d6d0f11825a4ffcd5ae355b19c58af88bdda0bce207c80bfb7d10e7cc79c930125f0b0934f0d24dac5f521514d840f1644ed5232abfc2cb760f0afb438a5eb9a46aacdd62b6d61bd61becbf988e0f3c4c99c1d34fffe1dcf4f146e31fe01c0104626e1b93c29b5954a177cd2426dc66a61d79834ed794a2c1adbdcaa7a51b9f72fcfd80eb9dedf1c420c5382a94b48d9503bffac97c391021a704405cf85963d83bcae0d391d94aea2ad5a789ef1af21188939358a00038462803fd", "5", .Okay}, + {.Gcd, "19cc84e6d1a393cdc4ad79303dc73fe1f27eb6c29ba4f52764330b5c60f4eae23a282f75d65cb9eed7969536c89db3e981cb4f10dc6515715ffecded521eaf7e70779e232a5e627fd7a5649001fb7cfd060b8092ce87e4c8d33d0324d1e056d1b8711dca93bbec2506fbaa5caa15625ec128b40413a21933e34690f1ede0f2676dbc6844b6e279ca9f7925b72b42784d166606d088a4b38ddcdb7df1d0faddcdeff53dc4935f626adb20f8675a8f701a244385b631786ce255625818e25122fae91eb98f71472fd66711c68872de1fd0aaff68490ee8b1ba4a2fc9ae9e4d821c8ec340667a66533dcdcfd29b7458fee03630f5b060414811f89e948533505b20fc1b72594ef864e8584b1dfd4de7f47f357d29dbb339b182e95971514f5da034caa4f8f7b8087f1a57ed9dfa2d3d543fb3cd67cda6846551423b80493e806eaa100ba22c61eff63f959acd32ee76bad8d11438bf824d19c96c454a27869fb884e3768ec2f7ef11e2d209a5d674a2ec37abf91786e9664003c69c0181cc2edd932226fdeeb88c740ba4282c5242a99f7a25aaa077d98c52b63302f4dfdb1ed065f7da856879e28b2631c82366b2cc8b2c6629907386354b5a1c25b273333aff9867c0d457204e5c4a815f638964ccd24793d9c1792507532ffbd6d84a7f7659eea200e2b8961b91a3e1a5babaea1319a6709c922c22734505d2e2ee3f6888e087", "8c2c802d299eae4998ba743e2baaa294355dc04b9f2be963ef283b367f51c24f751a9f0add5cc531d4df1a00912e9644381cfa14a330bfe4fcd2fd74db30fa2412b45ea646c7a3dc5d4f6ba3afbd1bdbb079f141c84fdd6b2a2589e5a72986286c5bdd829e2adfedf2c2a5c8878d14ed91842157787a4eedcfaf197de33469d9435bdf131dd21298f6c16603c1b52dba508101c18428e011aa1e8820d868c8ca3a7719667f6495e93103dff21a330833a02c91432a8f82848ed74611cd28912f40795340f295e8216779609f4facae33e617ec3bf5ee25b7427cc78a3f65513786edaa6f9478be1e8bf979ef01de0f1d520737381cec24c58dc66b3e9cb65cd09011a20f45acde97ea60c04c520a9b9460282a97cd15edf47461636f01b1207f0e2d4b69f8e1eb434405fab775205c9ae23585e36ada4137f6c0bb0c8dfc0b0c3a81c318c40075ba4bbec38beb093bb27cb4c21d76062fb4c5fba72a32092d64af7fd12e96253ba33f26dee7924143e1e21f2ad224ba034950076683599d80d7d537164a18e1b6731c2f1ebc32445ad2db58885daa921c0ff12cc282db58682d5dff2952feb6bbb4e0dda143285bb0cd27d04888208b03f9d6c7a02cc24ca1bb6a26327c2b6f1e8e60fc3f10a5854f83f5362c6cfbc6b87b7f9c9529e51549308273465ecda222e0113a841e45a8d82881718bd70c9bdb2f6df8a45af74a4abd", "1", .Okay}, + {.Gcd, "-9e268bcca77e99b8d7fe5ca1bd49cd99852bfd2878c680f77360acd6b5977513dce9c8c6230a3a4252f312dd4dca0dbaaf8a83015ffefff50c2b58ebe95950249d91c01608b7c1ab4004eb2570f51307f7d618f1616d61bffb7959a223c1856734e300fc35c4158e9e27e7c94e37400d59c072d656d62ad595912517eb87dd2ebd27b6ae89a7d2087d78fb6023a4d6a36c3049e9b78d013f4242bc8e8ca3aa15ecd3d7b50aa56f00be8881277439ef306241963fa01346fa2b6e0d8df4d79218354c43dcb8fb7b1411e5cdb85c95a0339c0ae24129dbd52d5ec898314c287087c37635498eba326bf8fe234a151040c3d6ec72aafe876d3ef6fd870132f872afb92b6380258fd702cb1c5e2036a450057aa23ac8de02b694a7a0323a45e23a39154c4049618e1419e199f4f221f3d54609e1f39f3c78d129e0e18619de3b51baada4bc01ffe37f8625e781c50cac6aeec5f38217bb27cf612d5b637d51d10921ee3458222e9f21abab129d788f06eab65830f4e76da5ce845c2c175356bda1fef5653ba0aa6b393aa14a5b8b83be5618581805bab9f9b557c5712ce6fd7f861a361851ddb193d51780b9bb91b32246ad73da1fa61608c87146faaac67f4d4473e018a7c6f6bde71728714063b028db9d4131654d4dfcc556199aec1b600afda550c8d9026c0954fbc84050e540686e1468785b71efdf24c093ddc95d76568a4a", "4ca26006ddec15d25dde93939829664889ff62a83c47c600cb4f99fbba6d726283576a06b551e03597685dc78a5dc63bbf3254643e24555c1665f79cb0b0aebb19672972f10e1d28c38f6b5b68c212f09ac1149c523c19ca5d9b28b190c530458278716bdb6255272423ea82f7a2a039f8faf37a4cdae825b6d1311b23773bf68eab4d3d30ad9d8f9ea82ee577825d2cdf3dbf008767a1a87020c972ed627444eb95cf1c293ff2779d6d328c8988677de96cdb1b05c6ce380ff2957c17416e1299eee4029ca6aa7f3c1e30725d356afdefff5513fca50482b058c546cb35d0504a3b99d3e43cd55308d02bd5089100e59d8d2472fd090c15cac34626d01b4e28f25ea2c4bea6f6359486359998a26ec9cf4858607f0e3b0a8f83f9491c253e7b771ceefce05d2d248e78343c477452544bf14e13fd2c4d88d588c6e339ee889ef81c11986a277e772d2abcdfdddd36cf40d6b5e77eb79a519a72167ee5617b29478f7d27a4d0b4d29591c7dbe1c6d5c33f37b4a8b9d0df9ea6aec932c0c900aaa1938bae4c972e423bda3fb314400e22a180cbc262864d580a1b0234b5a7ef74244dd534e5638a0fb35d5d99feddd3fd1c1dd026e8868574f6ac25b6899a5469613d98af361e936fd89eae28189f7a09ed288af36878aed524bc347f08ee5cc642361c375a5b822d23ababeaf4ea63ae99a7345c43c2003985524e6f155eae0e", "2", .Okay}, + {.Gcd, "d89c6680fee017d0f1596eb31186e59d0a6c06f9b98205d9163353f8959ebd43c168afe586b4632a10d498096a764c200eda4a1f3d04c5b6304aa9194fe3745c7b3e8fc23fff84c099591af9f38b6e1454d306749815e1fccb4e6c425cc5d7302b53fdb2c5596e67fc873ba58d35ad679fccf14f2905f0a3c90efc647ba1c21bed4b88eb1e90aaf5e1436194d932ce036a9d2c58d8a656694372ca663044acfed18b1d1ea6b23169f2eec3cc84566fbdd28fba6a99de31bfcd51056d15a48606d33fffeaebcd849efd784e2ccfb2b5ba8a0d54103e0542c0059c2d1b52d07fc248cfc11911c865a6d2a102c25e22b6810048f3da0b6b28790452532326686c866760dc0dd32a7d99b3dae1f87c64bb6e4c891bc6a5a6134d0ae828694aeebfc41421a4793f908d3890510593e3de67f5b6dca97184367ba19e7c8efb74b4d45bdda89c7cb2b0344d77894f8de68cf533a8e13d2ac0fb09c11f47e38111c1586dc3336210099f7490a26ac1b78c42dc928d72e529ab22295684861f9e191aea75ca483633f3c45c139ac6a2cd5096bb35960d70f91a612d74c5573675abeeba143a3607e28f5ffe05fd6d4eda2e4a37f9af09e7fa0884d5f261864edcc165ee9841d347dcc0d17d4dc57cd88d1bcec12d19fe2076536f4433c632fc543664f5393f6ed0e4e89eb27cf59c44a6a05954fd61df5429cbeb516bf384baf036828b75", "f5ec8be8991974b016bc792c530a006c44cbc2739828c877a3a0ba885eb0f691e334498fa2078ee860bb06542ae6e84256d1db585e172be93b32ff3ac93c62909e2234cb5c82878c4217696a1342c57d7eff3311894f219b35fcb5bb9435c0e92f39f653441e16470bcd839877e715cc74bb34a6dc4181c7773bcb148a01bf7249d93fdee0af55b8a199cd0a6ac5d92a166cd2ad8fc4adfb03f8ce58c9b51e464383f64934396fbb55e2b9610f5f3267fc927ec7325a00e9e2ba798bf22df9fe557c6e22e78573322cdfa3ea095d4ec035fa393cea01ba3bc5a575df128168ccbdb90b06a7cfc37a6c690a3427dc9a2d753175d34bd6bc3c74d22f57b387ec8f89ce82346e71a7a94e2b091c6ae7b1e171ef34a67a3b2332294786d971a7eb959277f61961d7db908a61def2c5f73034cc5139ebd2cf238e064314078665ff6e03c1560e65afd1de905c84cd7631d0923c0a074a6262de4686d2e6f35139b60dc8252222a5dbcddf96ffad74f1d822b911c64a1fff1e8a0deee0152a72523ae7dd001ced0fbb0b2b58b5fa1898bdaa6640d6fbed9352854f993bce908caff4c341b3a23137184a58a8c29cd958a82ccbf62cf150ff840ca9911372846658d8b397fe96d55f59b9487933b94c74457a82c170e5e680827a9038b1aea5ad33d7a15ad9d5eab57db49e5e9088e2dc98f5a281baa24c64fe3392254db69166bbf063", "1", .Okay}, + {.Gcd, "-d91a3926a2f6f492bb68db18e633d706c513de7ad05557a58b9c3bdda6e2e191bcc9dc503d1e3e3115a2022606e916bdf6d30f87421a3cc99bfc74082261de1faad6236c285b57633b953d17e69d94993482fc5abc55d63f3080f67c759139b4c3f99db4ffaf2bd902dff6c07748921baaf99fd9ce643b9b22a2de5c486125331bc14a22e1df3fb217c5480ecb244fb3c929d8a7ea826e8c37c540ee998dcf363daa8e7baf2f0c9ab9d5c2b709d94dd8da754f914e364199f1aa00da9b2d1260c4a88ec7b59416355f8a5c9eb1e784d23a3255a54b6645ba217b0b72a2c23950b089d79b063e25c0aa37f914c7b75ebce0161034754d4e33d4ad598c80d011ebc2629c70ccfdd1c0c5e4840fa5f71296cbb35af9501aede86e0845af12a8d1b09bf90d12af8b9cbd97a5d912619efad04156a3fdf83b0eef7ee91748e2a5d9c5ae54b266602668edf5b28d599b04f4e0085c0b68822fe6e37119465da8cfcdb05565fb9931928f072e691c43c40219a465507a3f9f9be2a2fdbd539c2f7484c380c2f003b34613f65d1d118c23959d96270fc5c951bc678952caf1ad0b9fcbd3bc56aef481173be1fa1d98182c3375ecee69029726ced32d000ef442c38072f5178745691af1d9ff6393cd094782c6773f2c3d680aa52ef76ec923a69b0e3d1f823d3fd5a6516394bafb70e97f0bfa389e1c3ed713681fef03ecc56d74e6c00b", "8badfd16de70469dca9fecaf0159213d8f27d8e7b845f944322c289d8bae659240e282a11cd45c059cea1b2c03e9e4d527eef9a2aea6c1fc7dbef0c30ead4e241a0e57edcefbc784c00b6e7222d76406ddb86a6ea149a949eec419079d2f2a594d69fc112e16ebd7b7bdd2c1eaeec1858ecb0366876a157da9a7e2222e3ddbfdc0c5af06ec6a28d0c697ffed3604a0909ea9fb1fe89c90959135cd0370c11b10a395ef62d5644acf1055220a24815b38ab6a043eae6f749337d91d2573722c6ce84b4b9b04004f31b02eb05ca37e3ac3a5814b696e2aaf93a45f24a7df225ef5562207326a948d100b450feb8b134afe23e2b0a8c6e092fd914f7d86f489cbdbd59cc7210639b4c6ad9c1bdbe3c7b58c0374a088188a902a1d69290d96ef3e79a4575fa31de12f6034072076e7805266756ec2ad9e0241c63609c77ce5cd7c13f187692325e0b523f94a192e3f4289390b628bbf7594c3a765e1d04aeb627c0da945fe1ea8454ab77611447b89bf66cc7d9e98be5b5e11552aad9083d2791bcc21480894c4537a4f4fcf3c65f68fb6bdbe3380e81e1c8e0f4cfb41eabf3f7d45b642a1d62076cbd71c1ed11baf4d135942043b2dd96e170d2b57847360d57600599ec115cbff6ee80c33d87e77d722d6725cb52623c53e4be3c711bcd5c12fac1717215c24db4209e7c242250475801d52e4d7be5057a4f543c66454a1be1c98", "1", .Okay}, + {.Gcd, "-5f9b4fda44170d48e071f9a728550ffe035b1762b34d5604a8d728f5be30ee3ab798d05f260e7376b61c8d59be4c4cffb6af404664e31ea9f4706d56157d316e6acf48f1a4bc24fd979e40c134c34b5f56fa1dcbfe15e607e7c557a8e152f2d9a186787c7b69a94427de9310f59307fa61c9fde7b6ab11ca11e7af2d5459c2ff3fe11a859013188fda29718666bfac44d1caa073970e9e067da4bb343a8d508f9ea9f4c01337372fb6f0461f2ec73d2eef30ba83ec1091cb8301b0ecc82e661b4c1b8c9b3f191502f3f829dce78533e184e173189cd8fdee6e9d4ad4e4f3990cfeb284f901c41f78ba95c903033922e4893886147915a759be4e2f2e330d258a905d40587a8f130c2a3fa4ab21c46d7e7db6a39739019e4541cace1dc95862381c857516686ebe0e913fb3c76f83c46139b67df90abc5ffe60f53482fb40168fc3c3f52cd0934eff20c1c87ce8f54b18fa9119f49fba387ed7f762fbac82ad5f23d9ae58d4e6a1581012e21c72e80b8ef4c827284e55835a18879c0077e5467a4e613e816c430c8206d532f716778781ec43f783146e19491dd9f6753af8ccb666647c0412095efb7450fb7fd4626a66831fc2bdcc7ad83c7ebc6999b21d72deba965f46d1aa9fcafaa09c19609aa28f357ed6fb1b1f50f66f740c9422d9fd61b1b1434a36cec2e702875ceb40954d909023863d2ef8434a92cc392dc9ae3444", "ea07765f4e694823770e134dafbd3ac6a58bb51cd185d038525dc92dc62d06ac130fe5e859d03acd38d406d2216bcb9c7dbbd31e012ffdd72ad9c312685d1738e04e0db564e9aee322ce46ed17c5628fa5963fdc8a2fb7b8d24b8aed3d8977facdfc748c2afc70d2661e7fb76a29735ab20e81965d9f9c439a42007592ad69ae24b6e0463bf618e597b5cdd9bbbbc64c6788b7f7dd48f21f706df6b6f44d0a16865c550d746d694dc0b1a2434a34eadacf10065d7844f6aca50603129ed321802ba96a345fdcd7769ae396c417ab6ced359fd224308ade7d873afc5b324149df9227f91d3486c77c54a0918f205b6cc725e90a6e7842c7f1499097b465d3deadfd202a40412b2e8f94532205849bb9637300a480af87f6677a67d46da30ddca2a38165e423fb9cd6a4201687ffe8634fd9093c57c8bb8f3de462f95494c8286154d32e16e5099cf0fc69593bb540aa73f5d869aa3e4e27914f29333a157333e898d546deb62bacef86ad559702932db91bdbcc8aae80cbdf6f9ebb0bdc1c0e64c91efcd1db2af3ef5eb7ce13b6b47ab32b0ed165cc2fb1e2c95d4e0a2fb0476c93048f39aa09368a1a3b836d37649e9e6a58c89e07fc93ae946a4cee14b8e76cda5b4ac660faddb0b3615053ecd148a5b0e3b65e80bdb9a555b22187ce4d07a7386820946f8ec0fede154a51be2d86cfb85d1ed7935522453080d38139e43229", "1", .Okay}, + {.Gcd, "-9fdb71b378c8d52894e35462d64b17d714d1710dc17ae9f9c7a63c54c304d9184d97c088c541047ce05719a115dd009aeff7b0e383a94e4108edbb601c0d81ff833e8922c8f2ccc8e394cabb7e4a908202ae1f9a9faab713ef3b18aa75165e71b9964adeeabd8f03c53b7e0eaa52bac7c136dafc8eb2dc560a72670ae1fba1d344fa44047915225b4d52c5529a69eb725f13850727389b946c9eea0b7b9f9efc53c1b1b73819b66fd3e3fa97f46cc27b1faa1e0f90e07246c45ce6bb5a1da03d8311a78ec8a60e47c16fc4e288ae9bbe992157a594085b9186efc49c8f2323d3773d569fd40fef81dd65fb2ea919300b42c7fccd11c62c67d6a5067e32bf56c162514cf1b1159d3bdcc72875200ac49057f04b27a0e9641f98cc1bfc7962d210302d1b1d21269f5466881bb23122b602328de3a5ffb10976447bb428c410cd79fe3c03c4fdf5195ca9962bf1ef16c84a6115b6d57a00a4a6cc5a123cef4882688438617acf29c2a4c4691e4403ecdd975f4bbbc9842fec6683ef51164053f2c78810ae950fa3b58314b996ec21b9b1d8aff6574b3fc26fc17f2c32000ef01c850bf878dda24d48fc5d737dc3028b81319627766ab8d4eb946bc134091f462ed1477306e0dcde01f126321bca6c0a79be6020304c3f0dcc9eebb24f8b825d054563b090970c12fe578d7999dfbbbadffafd3212e3ede0a0ade914a0d252f36234", "e3522c06430e3d7cb4470fb9fb95df4316dfbdedb3f96ee4af007a6a7b4f51c93bd77ed6cffff13020c46f5489e85098643762db66a9e90ad0b653747d3c0a44adbe35f695f7a2c696cae4d44ea62358287cda7573c483dad7784f402d3572e5355d026e58539d058b8ca6c09784321c3279f0c4c08356e6abb0e5fde008388907fd471eb9420ccd3c59e459bebc1d2d05698227cd25e4795df8b107d76bf3e9aac58c395b3d56212f3cf082bb13a24c0d1d2f39c41726beace90a16abdbf277404dd91d0bf20a6a0c8b3bbcaafe1d9cfc41b94cbdab6f1f51183e45bec425c1873eae6a4b1ac30ecf15409db7dd6fefc523caae64d3e3255a1105ef3b7080005b0f7f5ba52389cc406193d921c96febc33883d614397e37200f782632823e22fa5acc8ab9fd64ec025ee3defe3aaf9b66574c6c4342da71d5c1718aa40ed99c09f0d76d21c6bf505e694f95f8433f873554e35d384036d54481a69f54997f1c82f9ecf2e66c9e0cf96664a72a66caacd88e331b6d6318916a364e51d85654b952296e83e361a1e68ce486040a2d861bc981aa6049c19b20410d29706ed470f37498c1b28efb72fc34dd31bbb538a7942b3f801effdf6724f7dcaa746d4e461a89645a2b9f1e6940fdab51de95752df775198ed0d66bf31184ab2a98ecbc1f55fe10ae4690163b577d0a9048d7ac104060a8f13ddc517d35748b6548db66db62", "2", .Okay}, + {.Gcd, "-8042f46d55e19590a14bbac24120e76d4f0b8b38bd50a28ce2213bb62a04b629cec53363839b8f1ecf2c0df47d7f24ffaea1af0bedc7eb8cc7acb6b9ad8f4dad27ecaf8c96b7521097c95b87f116924531939d5146447a3ac6dbc9c3ec8080250aa9454f2f09db0b197fa44c3c57c0e2ebcb2d6c8e877de0c260b5a025653ca9c839e8081bf20e4c79c4ea59df2dc35aa48f1aef3d8890709bcf1c0ef02c44a3330eb09103552ec5ea3cd39e32c668ce835743a641a28776d2e40790ed718a594acf64d35fda7cced45f905a55879e393f2fc29cb306d4c3443ff7b13b48f1fff523724bb6c694a358428726ac95d653c94f20d51645f5b971b75bf44d6182a3807b5662931f116f773481b2d2926aefc4b8029ce8b2f409c934b489647d6e39cd1dda17d45d05f8d8ae03484d67b635c9b77b587b22a91478b2ff90e45d44854ac270026086e4381cece3be4115406610a4001fa80171768d1ab769b281b5d6ecf1f4a11147ccaa44ea5635c4cf67086a149482d3da3b79a70fd035d3bbbdea8172c4c4417fe722cd96872f126f68ae51bcc96d019df89692058cf2b7cc550c9e94ab36f804e5cd95ecb126018395875f74e8e7a6ae7438d2f57c2a14350fb197b0c274d8875a801dbfd9cdd429fe7ec4dd636e9b6b296ec4eae3236e5891fb6865bb20233646f02be3ea77118d34c34071fc7bc7704c50878bac06ea578b08", "c88afa3514bd3da954929e27257305b2f95ec065b93847ec58f4e024378cb6506aaf4498d6b2e8d0b6f907dd3e0ade1ea079a0ff9d97714e613ea3418e1afd3080ca54b5d334a92f2694ed4a1b0ebd24166f7f3a40de707381dc80f8675edb9e18ccc3e68203194d5167e587b4047e907e037dc83c12d148aeb15a0ab7c056388352ee832bc286df6fadbd512ecc3d5988adf442c198e3dfad7d4028dbb8fd12651b382f8dea3f8dc52f9527a7e6e87f4cbfad019b8e374747208ae83c8fd1a26268698db54f8631cbe7f774906b9ec1ef3e26038980a02fa0fa1fe5531c44c72a9b7baf94c6114c32d43d4bafe2825486f4815bd8dbe8450578d6355b1bf21c91655e04b3edb34468515ba199e1c4c9a68e214711c031e8bb2f16c56b22436f81062ddc27be20838eef8bf4e7bda15317cfe1cd1264c1e5d985fcf76ffda020caa0805982e1eb63112f265abd526b2c75c34ca564406a34e6ad29223eacd095531e4fa62622d7b500bbe0e1d55529eba28bcfe4bf8404e865d4de09eae704271135f786e06a279ffb73ce5e050cf8f88dde059d8854ecc0759829547f65c48b57d674a66b6d436f15cacae17a927f5474559954332d5b8145db55b125059ebb54672b635c692eca0ee30807015a3a63d0baa10c21e15bcba0818f70056bfc85c426b393d7f7572abd9a720266befae621aee21471de29e6bf7e7e2df5089f7a", "2", .Okay}, + {.Gcd, "-24e41fc497d2f8553304a8f979af57b6bd5656ac67e0a745fca456b21e00b965d626157b323f43a8dd851fb7d79614d4a3698f7e135829f35c27d6a456e3ac7a2aab900379ee699bcf02207881ec048cb1b6f8b0bd801a0e27c9f9fc4c65ba01d35a897eeb494fd303cf5085695dcff55a8f1de7773300cbad34cfe42b26f79c2a95e156bed0b1bbb272f642841e01de0f1b57f8c1283e382261903af840b055e1c181e7642c9a7e101bc5e9d9b712c675b9d79b4ab3bcd470b8924f8b2cf445922a452436580ef60b825792ec90016f904725aa685bba7399c49b5e4ed44d82945fc173f68102b8c83b63f78f2cc9bf08b0f8a0d6bb177bbaf932b80e62c783296f091333fb5e8e2dd36cc61dd7e4d3030b646e78f39b007a5b6bf6f46b3bc028d9a6ba8cf732f7272d0a4fe1de6abe757b8ae3fc57efb7dbc79f05184f4b9f43da266337e8a49b94c9c8da2d057a44cdedc950b3ed53c221370aa9fbf1f2f05452116b1ae2a055976d55d51fcf7f8bd6bfdc5231da1f0de2557919993ce20aa141631a9251ebe8beae3cab58235cab6afb4728e422e2166a7cde8e4d0b84149574cd02f0f89acc57fd594b7cb830b1d27ff9bc1a644354dc9130717712ea825081829411a3fde0f3876234350252d04bcc01becc2cd77dc549e4926c68ccc961d931dbb66d558934f872a35cf80c4875ecb3e8fb7f6081eecac001474ca78", "97c0bf0d8dfe08c31704d0937cff094e309d46391057ebbb46e16e98eb045ff495d72d4e243e2d1b9c47ffa375d1eb92361144dc17d2f6a40191571c13af81b179fc2b439168080bd39341248b4626456769ce29b4c5bfbc2a699e3f45e6e3acb72f72d3f8e5ff25378d732d19ec2157bb16f1912b27e6c5e02c7df2bc42c013478e3779a0e52814bfb49f043cbd01ba21a6da07e027a01045a38aac47d98e131427cda83476eeee6e45f4dc1d571ed5d3644f3f1d7f7bcb8f2e6a7ecfda0b1bf318eff043fa2e7216d5aed1a74c241a3925f5e66136e9a9a3bf28bab98a08f32493addc483e6170ad2fd9c68b3960aef3137bc472281f74716efc70bf80e8521e86b2bcd804b011bdc054f503b4fe643e82205bbc73eba148f9ad6ab9a3b07602c0a665d110ff4f054352f44c62ac5167eb5dbc031716c8418bc55bdf8199f8caa7a91e0c03a97ede371a9de4d9c2b72bd4cd6cf5d2924244236034934fcc57bb9c0fe10bbec35ae3064540fd93dd1fcf8b9f29a1241ee8ae9b13430f669b2e5b32238251b70bd6ce44a90918f8e90ae8f4d1db3c0e3ef88bf53e4b113a1a76234a079e6eb2b12cca57cfbc88d9c25c6c4987693945a95949f690e77e3827c30015312b315a9fbc56c13308fb058e929c06dad036ed52431b939f84c6d68dd386da632feefe9e1482146b0656936bc31ed6bd9567a23accd8bf81b886c45e02", "2", .Okay}, + {.Gcd, "-89afd6fde0012308e775385c6e8d637fd2f28a13b845566b857be7d5b51cc839e3743508ad81ec6a8c09a3127e44cf48d4f0d656e45307c06dac6a76207d0ca4152de4c5c98707de9acc9f1c92375c44b25577cde34ddbfd4075b32f6696dfb93e48e64d7f3475ca62fda7ddab911abf0efa3730d4f752ef4f8c5ad177c66deaeaa4aab282dcdaffbd646cfc39314483ec430e6f0dd4a0d8699f697cc6fb3f265eb4702368a53a86956afb4af2470c6b1db19a36f278725836a3c35d04e59a941ac18b146f4a0b5a45414ef1ae56b9abf718477524a9b8ce106b477980eedec29123997e8bd4726a8b720c1ce9fd693894a9a0ac0699debb3bcee8eb285b21bd39a48d13fa619eb5435bd94955596d420429f0ef9c2744687fb5a91015f22abcb71602e6bbdf47917040e0c5b2a9447f487e9a9bb92d10f38aca4ad6e400299df208931fc821cae0896f12994916ea80e2ef889840b84f3f7097834ced536051c19dd614eb031f7c1a7e1a68d920b389fddaf4d2d24a5127d6691f8826ff861574b58171e4549517c60dab9953dbe9ab4ba3c154f5f7722a7b3b61846b418d1ed9d84b0f2eaebbf0273e41c24c94a047dcca23282c683c6f63aea0af7e1faa45cb34a91fd40195b2150df6713bdc9cfb351a5be62a997b689acb1da27d0ecbbe68265ab66fa7997400905a8d5d045858c8f7698107588981b83a3499c5bcb8ee", "1711fb6b6a8fb093c5e80e51445c3fe9650728ecb62a3eaa8fa6fae2e3ba225638c971f3b15e7bcab8ec5f352b4e21bc49f68e80f72762cc02dd02e078fa8393ad7dc41ee501c9cfa6b8ff89dc39a3f2ba559715b8f9225db7277d7d1de33ff438c62e0fd9a3244e35ec4ad712fc8db3d433cf10be8385af4b8b18973ee3e22f6416d4204829b4d2cf173200b0d58ef372ff6cd62570c9d2dabb0509e1751cde2c3669be0ed8861102fed4c08d6da30aa504db744f3e2b0c364b293b475e6c543e05c66f4cefc1c84a40517cfc25e8ef6c5e03fe928b2215d4363669e70d69ac1b257b5a34aac547d47af0fd444fe91b2553fa61497f452a4d398e4c896cd6a29d5f35a324c68103ab0ae919fb3e944c7d64d78678d186d00ec0dc808b044dbe4eebf1a2739326a6f86189683d2480343d5f6f4862a04d23359e3c3211459de11c2d5bf58ac7101fe1d3ac3d317d3ee92c12f51b691982f01c42c894cb822f8b40cc3f8e17a8914cac03b9a60e687f19ce74743995444db4ce9fcca3cc11fbbd91bf5d25e7566c841dc70a15ebdc66a7574ab3fe3d74528d9d17ea775074c07a32280ad46b74aff14a79ddc27badb1059078491b196d16da414959cd50cdad5165f6d45931c22daec5cad506f41217d1ea25dfc79f39a2077521b2a603d8b08d02d207fb775b14acdaf0ff2a66fbfecfdc2727d050b62a20032e3228c1ffef12", "2", .Okay}, + {.Gcd, "-c78113d6b07ec26ab6a1ce43049cad4484ab154cd00cf97f23d6662956882f7ff0702d6916acdafc764f6b47583cd33f75edca9a6f763c9334d3df7b3bc1b630378aeefdf32a2a23896772d1bc5a6a81196df6ec03903339f5c119a7e3277f2d37b9d981cdf324c86346fc996be5d0e62dcb881d9e5f0b53eb73e327d0f9c7879636256c417a6a45720cf960c080bfe2923f934888b3157936ed8df644adc6577ee9d89ffdcd07fcf27e7d7001229171af29c7ece94376a690ce9f6c305d0c0dd3324c88b93f8653067627c2133ec4e378fbb6c493dacbad212dca455757a8f6f230353b8fadf86a1124f612617f460fe5c972478fd87cd9ea8191e8c48384f0a8e15220c40a6a484f0c311b02bf822ac9a2f31a1f302ce85817587a65ab2b5e4eda68dfcf4b0f934950ae3b8dbb3b03b811dfdb2300dc625b588355e3f89299a73b64724a103759232906f51847303748887f5fb4e987c31bb458cca801dd68902076574db72091e6adc0a9846577390766b539b801574a63b991355a782055cf902ae675c4630f5371e86656e5688cbee2d6b9f0de3a61fbc05412ac9b4146e3797b8f7f0af5ce52c5d1b65316776d472cff977ed067326878410b23ce09f55aee6aded213117595313bd13b1c920ba20b5a391e5496a9bd8d812cdd72f598a6a7c0329b2580cbce528d192b378b121ef83b8abc2bf43b6b68dbccd7c537d", "7a386fd03ed7f8976e6cc865ca5572ae8523fea3ae510821b5fa1e6c328ef05d0aaac774d16cd89a622b71017a1337b93f4b135eab2bb712acad5de84f2af45ddf885dba878038f6a478d1e1a86b8b3af2af4843c5636a34689cf6be673ce0344adc0a1c3c3a3d75a46784ae0340f3874ed1d2f93c145b90975b76bda3024124de40ad394e765c9d60c24dc8baad832f6ecc938f973cb8b460942d21bd292bda553fab20b10d091983db592c731056027fa1c58f766f84b0b27a13c4d09fda854e1a0c3ebd3493c3280b471c79d3f1b895946e22000545470565a6f5631343a739022a99a0f8469916b63d785ad23745b5aefbb4c20586d65d1f69e5df2e559f727a1cc0f355d2e380cf69dc1f3eed5b5f6e8bf3f7c47ff4affcb3ff892d42c91a2271f6d91465610660fcbfbea5fbf034f1914105a37663a78126a1243a87fc9c16d2fc600d4a62e2c8886a0542a1258fab065743d08ba1ad9830ce125194967b541a40872f06267c0d53494a475a19a35c52bd959291afe7e1c2e035ed8212873416884ca20bfb19b6878a054daf419dc17561ea5ddbe15edcdf6bd680dac16852afb45aa165b589c2253965a52baf4cfa21ff575122f9ae892f9a4296f6e46311e703378b47807e60f22857ee621ea1da251252cda00476e5cba3e8da81fb7b446e5cde6d1623eb2a04f7338a0c0da49da5e378973d4b3a094f41900a374d", "1", .Okay}, + {.Gcd, "-e11cc4de4acb896648388d70529013781b8332cad0f49b1a9f534f50a7318d3df8553a864b65d5abb7e76db3cfaf5072c9c6d30cfac6c8fa2ce5dfca0eac89e38bdf2ba0a9070fe9aadbd171fd46b6ff7b74aa1a130ae9b1b5855fde537c77497e119076434e1400ca33cfca0d895e9cd5c3c70ecabf378121527ecd39426fb3fb892b6c0a30e5a1a3524175f5dafcc4b3bf161fb0705726fabd0330fe2b160e52947b8ef9d3cbc94d13452a6a0b29056c81a7e630826cedb757c597079556f9970c7625d9444d75685068cf8f0149e472a55b4f406f05879e331b2423edf2aa095e95f8ba9cc15408218165f905a94f479cf026ef6411c950e4cd51287f4e144fbf16a5844b66fbc1ad6bbd39a568be7a188ee652b1632de94da75ba73f663d32062b6154f7c79d650eb336cb5018b902befa634956f3b6ae6e265c5e7353a1e4fbb8db4f6f8a17d81ffe5bffe30c2f983879fc1e024015a44dcaa7b7deb2040bab3d2ba1af624abcc8a866aca7f3c6dec4221bc4b1ecac98c4e0ab0dbe72c7e9b4691d599e4f1a40ceadc8794d556ec3b844b8dec08633fec3aa85a951cd59d08b52c6f66ba26380c3b67faa3092711c9936636e49bfce9fd251e290e6fe528f32ee50bca30294d7c3fdd922a1da25788d1eb5160f65c0c9a755c898066557e74fdd5d6d9b94abe5237858f9fa24c1fba037ae8e07379eac92aa1f8d141df5", "3b7117b8b70f77a4a534e86b45086989685965489631c8430dfc9ee852e29f8d1be5e53df5bf1b21730125afdb477fa3fd1705502ad17a5de1e5dcf0ce0d78e555599bfddcc0607ce6a4df1455ed27e1cb33ace4c5518320b29f1c9e0fc01f151266e7061cf82d9476d1bd73a83196870210eb44eac25e866e809430ce54a622b5a43b77be9653edb79ba13db05171b6b3b18a06789634cc7bc954cc17a955bc714b575dcea7d65e94a2c36d48d9ff2fbaf3babaee7fd9c296689b69b6a793002d2f3937f193e0bc8f882025f5c58e119f428524ecb15fe3ebe8908debaac01940925526dd8df0bf68053a550a8862ea49d29f53aee5df6b08eb6c5444ce79db76e4561ca2ac272a3157a38fa1423a665116d1b56cf63dd3a78e603bf666d88fb23065b0be39d27b69aa1c77c93dde549495c6d2021b6c68c9b9f9f24ef0a08d07253b57a138991f2dcb4a087682f46347f3d2ae9c61df198442da2692fecd7ade8626b4529dfc14eca087d0e2df07dbaaf647eed86d42d026cc6c2ffa82fdf35bc018cf95475ef7ccbd6474fba19274f8044c622a85200980c73b6f21118bccd5521ac7a401aab58990e3482272800065d2c03b308c5d50c95e1133abb5bf5556c6efdb98910e76a562cc4097cace9d50d6027fff8b31496fb033a4fc4f203affecd389a6a11aa77eb5ec93ee3044c407f31c9de16d639db59d1ad4cc0ee478", "1", .Okay}, + {.Gcd, "-7c76aa8e1ba7e498a1f9aef271402efd4752488fe946cd0900548018740296d27312f6de5ca21044abc3805580f096624207a911aa9254472c7af0c84d06410d4fd770b1da9be2f7d47f3334783bd667ec630fc7c5e2e014aeea6c0c4d82d3d18f3e4570ae286f1c6aef01ae55ca230cd7bc2d3ced075d29d73cbadf49fb61212535d42f49b091f14a3e0de3e0ddb1212801b576323e376cba1388f2386d8e5b9714366e8305347fd8280593ab5ae89084c4fb9f25d69ce63dde7e668cc931229fa7bfc42ac5ae7caf83ffe7af69ce05a7c7c779e017f9b06b92b7a8197d0a3bdc3638b2837d4c3c4560af59fe21690a3a58421bac4a4336c2f893c173efc98390d832bac03956a9cfa058d2a211794afaddee9fc35809b2cd2202e205f52b122e7e8342357700198e16f8f545eda9c88d46370e0c7fa38b6a672faa9c480fa794b07e289b482074ddff4ef187efa8a1218b1677428c7741b4f8154044884552c7d06733807bfbf92f3e64011c8a3f80d007c222d6bb4142131352f033f6969d4c2c70b0d88d91763003a9164d437f11653f26ffe2163a6ffcf7eb3a395a4f011a1330591e8912368e8414350834d1b54b0642fb3cf881f7dc825cd22ae18f5925a0969c64761d709c3246d4b4a25e3a80e24c2fec071ce9b76f90a5abed6c1c72ce7c132b0175ae5479dfae3c5c7c6d285b82bf2b6738878fc4f7488886cf62", "36faf15c13749cd0c3dde2422adac90c4ee603aa011842fea914454b29f2e9377b75b951c8321d4d1d8a06d477543b250872520c565b218aa665935016fa3645f045b1cefd80ec12fd35f72b9fadd247b85c5b6e1e0f3f9fc417969ae26474644f9d1a51b68e2f08df79738ccb58ac1a6d5303b8f703cbb1960335ad75901d16d40d619adf189aaedf267f14a2508a73adb1f6bbd8bec3a991235a7c6a65db4ba90838b99065c65d4db2bc01c8bd27c7f4852ee59a3191fd0fbf238018d4c66600ddaf8337dec2483ef2e670bd00ae42650b912dfb739584b363cccefa298877533d398f0aad3de9b34c00742ce566c1592fec9a7297ff4d77c61c019faed3c8f0134cb2e9003e35e488b0ee626cb44a88da280ff4b727e421a0d84ce07b10bb3c7b802acb8c8c7a66ac8336e05b1d2d2af26c1ff2f55597e107e343abdb5541cfd85773eea6608aa61006dbb3e81302bd98c83f181d5c558504007ed7f55ec39168bf49d27dc20c3f6f7691f248d78cb931901798c754cef29961a65796c0ffd8f0ccc4bc22684816a0c8736dff2c5705b4da3506f6e9d069294a085d2b5221f9c97c87d074e7ee9421828c267d65d451f32205954fbf6eeb08c7286fa9ef093ba09f7076feb37e8ff3f5fc397f74c6e87ecfb973d7e19fe8c26dff70ac4679b154471fc441bb2f528891b1ff19d7846a2ab718a9ec2472ac3b53ba2c29d028", "e2", .Okay}, + {.Gcd, "2c6861c7ad778512403dcbd6ad24c468c24ff24def99dca8b387ba483c9a9a0a89eaf4bea5a88dfa7f529f2919af53770d1e3e277ec4285c17ad05d58c4a230f551c9012ad0f9ea9ecc231206519b6ba5f76754fe3d0c54bdee4a2faa4798e59c3bd62f332d714e11d0a12bd85b4e0c8baf002076b2ec5c91c80e5bb70c4b9b8870542a8a4f94d88946d258cab0e45647622bdfe1cbf3e09da5ec2ab1cd680936883593ad00d5679f2846eb3279a9738ec472b006b8aa7a11c68e209c07fee48710966355d051c4c767e86733423d6c4c7702b663fb4c0977a36eaa4279b61d1e8ed6f0fd204c6ffb914bfcb2006de63d2c41edfb58a47f91f403a0c1e377d5edc8b8036a4a859a0c69a375f26c3f8904b03e82cbe648bc779f2acf0802af7b59709cf81e03e8283f4189f05b3fc1ce5f169ef389431e57f6e9c51438c7795e3a849c4ea87633bd0f0296edc6265a3e7a3b0fd44102d849f2c24dfb1382678f6e0f241f8f14328f26b5978336150e1014884081acbc9f4edc1ebed6c1094b5d35e5f12458dccd229c677ebd9f667b559409f708d912675d0e11bf64f59c802ae6f9993d1c6b7f5fdf45a85773b9f8196931eef5a555894d8c348e11f39106e85381194d86643922954d845b27dc6b1939a91ae066e3fd5d19e4458928a420099f142d65fd476679f40a1d2f7d73288cbb7708b6a15e5f66a4640fcf83f66e690", "59ebbe8befc329dcb421b698176d236075142737e84ec3195877627b406f0a825662b2a545e7fe91c92c7752b1e82c1723cd576b8d1278ce38a2c65b5a7a93fd31d2d5cd8acfaad89938766a9ba0edc5849361aaf240926427bbde120160dbc169655ecf04f77ea3cc2eb3ad40bc7baeb95d35b60beb4271c8f712281b48196437cdd944224c4ae8389d2fdc5050cfc88f590d40c86404254e4125b12c58189b5a46946b4ece8b01bcfba21d679ce6ef931a17174b640bf517f7ab44567815a5028ba7deeeb946f27a3d3594d23ef18578efc4c3fa8c9c3f1c72dae5d1a2f3a2f5c91999ae9e4aefacc63ac4c463944d5c8edce02de59b85428256cd092540ab58892db09f90456e744558c868264ae1f34627b59db11569dbc976c2e3f83610a9a484663107eb58eeed0a4f19cc9a8f4052f91334e5ef7d6d2d392fb8fde5887a816498402e619081d951c9501a6f46dfb58c3c28d57d956b5eb034e0460d71ba00d537ef64dea2e74599e8d7bdf7f0b8ef71890204f4c525000841c119fe5b1371b3f5a38512157fe1f07630774aaa59f82c433ba57261766f85751cd92929da91b50d98a799bcd086a83760a07bce68ee7dd44332dcf210264ce6b3677f0f7eb30ab16e39477e4112095db0b4b39d97735b283f1b9e82b9339b4f51d78658693dcc3582d1577710930f12de0dba875ff3dbabcbbca715c9d8de33ad3a0f8f", "1", .Okay}, + {.Gcd, "-f3b63c7d41d20bef8e5bff0bfe9855936569d314c6541a35b2dde639bd4ac8f5bdfd0f1a02490aea0bf0fc3902a72c00fede3ff8963f61821cd07696869c2a2e157f55360750e69e3b11305a2a4d07e0bb4b145e54c32d6934187bbca77f6d066d63b280865054010a68e4314c1c6ce99d1f04b9ea13ecde37a563899643ee60588f4c78b59c9979360078c2ab3f47421a22b21db430bc2442bc2895735d0cd61bf7281d364822753a40db341385a86662e7b952e31092d4964eccfe4fc1936386503ec0830c997535491ce2409e6ae10cab1853b6b9fd9fb18a2b469a8b3def8ecccceff032d7f044b7f71798a1fd936b113818deb2fdea63222273b260959275a5b29b8a70b9884c10a490e499f9d1d5cbd507a1f9d1fd3e6c5ced2e20adb4df028ecd779ecc22c732fa50f4d62090efb765dc6002ef624673e374820b234145025012cc39aba417e00c45ebbcc4d31073d82712ff65a6aab5b3edaf9d0280e9808414967f91b3de9e9684d0b9ad0be57a11e418bda65d2e344c8e8ef2a468ae8c2da1f69f71ba3f8afb72a452fbc01d2be93da4d04ffb60bac8f50360e3d386164f3e5347651a2c7c807e98393f0ae1938935483cd6d4be4fbc8ff92f26a220d3c4d4553e7853ccf1a9a184cb9c2c542809a1d129ae9bd9623551dbfaf42db913f71d918465717e7a501daf37d8f39bdcd5f7b926d0260e5de4511069851c", "5fdfb5984f4c806d6dc36cdf32c1989551abaa785ad7af1827fbebe7b4d44bb9f8764d79cd3224d61568abcd96e138e8652fd34a8f78b0389eb7365c4ae3ff71ac9070a3047558f6333e87712f04e061f692a08508cb836e3eb7e70a47b579ab71a89c6c00aacf99991ff6fed6e700901d82fc833fba086efab36b0fc8707c465789aac21f93e5a6e1d58f5e87664a2a7615d82d3cec174ca4b8987c0ce550e1759f245a775b569f9519459b03b668ca97b0bcf39e1997d27981a791e40c080a877df77f0155544c0da5fc3ba799f9784a555a7a988d21a7d2053f8fc8716c1db417fdf539f5c67d433923d610c7a8659b61da16310ac133ba1f13a3fa6716c47a8fc90962a3257e240069891e75e96b359087872d5e3833fb111751b859d839b6975bf64e820f181b748c1499337514e5020bad137baaa00fa38d3b5d11d73acfab378c06d3fe0b7aaff60730b7860052a930c79f891407adcdbd19ba6990d8a50b51fc37820716364f7db2fcd71b5bfedbe2dfb3f717c2a10c86c6c503651ee01fae7e1f45d6c335c4d9056cbea4981a622f16157e952368803fc962f135c1ab6e190fefeb7463db06001fa43cb19adf689a7e8add3bfd987d1a38157355fe483c4dbcc7ca430b65efe342a9fce50e8e628571217bf038be38eaf85281207b864544c7b16d6caa0d0bcdba1633874e189cbf79e8c4409ab030cb0907bb59a9", "1", .Okay}, + {.Gcd, "b254df8b9d18473d4cc037e88792fb1170b205340878ca2a43f6b04fb5ffa8be776b66da9d818f0950df4aee5b6961aa1218dd0c216c6c3a7282ff3ff2f4c35ae6e4edb6fa6da729782daae43b616c3124be404c15c4822eb8a0f38a73bb3bb9a4e732f56d30da9314a5bdaadcc20536f5be3c0da3bb3bf1ec578feba85fec73a572b2ba138f5ae9f5391dd07bf7d8c39f2b58ca57372979bdc6594d3ca5476f888b062dc2b8fcdfcfc3a3aa3bcc4ce2be8f7a6d0eee46fcdf845193594aaf6217fbf93c5d316c15b7e3fcc7dfc280acc2a2067f64f5135aab8f26f1bd5dd0dd2da9c57d07b6218d16d07801dcc2f0b1dc4b3aa5514c25db4c6ea7c98032e74187b7ee50cf8e7cdc4ef525c7b1d9cd05226e239cb843f6512fa613b1bd6d176869c6e07087cf1b3344360ddb8abfec84f5d562c4f6c348942c74bc8f2786e342d9b923ada8f6f6715651bb8c61a613419b3fd92287497670670b6c93d6d1881fd31a2340510740ae821dfe2e2fc58ec0bb9e0cdba39be811813ad9cff61eb6966485de6b06d044a8e9d4235d2bdc8bfb86c433ea341d957f89ace2022f156d836e3200ebb83d80ad9f96deee547987f149a040bdcaecc0200abb0a638efa2d98d93d33b5915dc3fddac00f4569a537e35aac82d285c68732ed82ea2592a508ddaa8eab07a4e43d79bc114a810d35edf595b6179fab44180bbfe0ffb46ccb2b87", "d5ecf9cebed2778c065ac9ddf3839d39e4fe781302171a2cbe373b871baafa0e30783026dd145fa112ab8bf992a1fe32ba95f53b0fa67fe5a575bd6085a492aad17482ab055c7cea10f0b4870ca83593b29ca38cf4831811f8c9d0ec91e83dc12ca99162bbc030fcc09da8a4a5599d507caa86814363f21b1f3a0f8363ff51286c50d34f1c6062de3353c346d09cdbda7ceaea69bea0d0da8736113485678cd2e101cc444bc2fcdc1c5642d663e5b96829e9d56c692346fe6c3a8247eeba706e0e7ac632554acc2e6bccaea208f61a1c1d9ec07230f98f539e983f40ecd78883c0e99f917d63dbb41c64f7c334cd55582285c2129a3815da37a111f5fb24c2d066ec4a1286c99f8d5e3a4c956151b18e439929a55108c0c19ea45f7c0d06796dcb38e008d0695688ff2d91701e38fbabc9192c52026a0ba2e798aae941abe6f4363be32b89351c7c83f7e2ef6386df5f1706f612e42ff57b7b165803c65d92a8abde9aeb9cdd2ee98967cf165fd8f701f10b715d521f64270f6af0e6b41fdc0985a2f27ea9a0437392c0b44e4eca2c42fcac328ea27612f5c6f925d2ff9e3a5c839ad1dd5d2503bf19ed783accbd1fdf0ee83e2d555b986f131ced73417078dce6c3d1208adaa33067af36bd76307e5742cbb51dfe5e8104fbd8e2cd9443aa8d1ad02a72276dac901ef5f22ea1d4344309f4a344ede79d8203fe2b4e18a935a8", "1", .Okay}, + {.Gcd, "4d610e00ffaf8a20173ce90cbcfdfd724fe7e9bd06e02aa253ce74cc28c6efb8ba30b4929028c586a7845e8b5fae1773d234b0171df3448287749f0b0aa2803d30b0c47ad000f49f879aea4b91ec8ff489c951bdfa75c22900af08a3c959931af33412463e8dabfa91945083ee05c6839086ba395c159fcc555599b6b8aa951f7ed790f731964afe656863b3b5e3b63f46eae8df8afcc8176bf29df6b363445f484c86488a3fed382d08de0b163c0b1584c8e31f2ade4e9c7130651e3c46e102d50fa50fdc9c6e50677c73edc991209fd61cb9555157e32c93187017760488197930905db5727c2dc498cbb137d35f991f059a8e44db9e08ff5cbd9ffe1026ac46aaf9b070d278b96f641e4afab9c6b15ff96c8707937c965dda5b3f808f7979401c36206e13026206eb33a261eca784197dbd34b1073c9861e9cc55149666f5899eedab4f193ac0d19906cf4eeb9f5513d7f0629bdc54d656dadad022aefcf73b92d9a8ad1b0569455da646dff1e365929181806577ccb2b338fa9db4e462af6f9883663e8191e81bcb7a890a830c51ea31f2230a4b32966f63104bf21ddb80577c3f49abdeed550bceca53d146ba66944b7dc217241305bfee6f132f4d1e23e6e402373ec9b33e16ac1a4f24c246d7a3a95b30d1690ed56a859caf1897e2282e3d88879bb51f9bafa146806514919f5dd5bbba9732f10ada7c0eece4e75347", "8f73ce2b8c0fc8a3be2ce9fa92c9f7fe06e099b0e55f66570275af5e3f8d3674f8a166834830588ab170092872d22d0041b1ee56dd47ffd7807ba7f67332bc9a0b32a4902e4f819328ee74c2ff73f6439292fb500e996b88ab137b94ca69131e4d3022b74b682e0966551aba5f05190848b7b0181c5b53cbb2e32ddb4d04d3e023beefae649c3f1d00fff68b781def197c52b2ae58bb70b00db8292b6e8152111a0ac703280ce86d9ccba517f8e081e767bfd32e5c83c68dcb6005eec4d72f74d3a3fa0a78e927571aa70369acb1bab1584ff8002efaf0d093b34f8906cd703e5a1852965f4d829910cecd72b2e3dade866fce71b285654069fee6a3712f741aec225960469be7bdaf746c6da4a86bc4cb61630c83e8dbf62bebe590d63881ac5d4cf5a25cf3674295f34e08c7f65d7984d85bba6d6ae8a851d2d45727e88637189cc02e496f839bf528904bfe847aabcc45e89be947b99ab302fd9349729b5c758151ed2d791edd05003cc2ea56bafaba8b47be057ce83a1c5ea9aab1c1eb4fb968d7da33e2fc94d51d7aed9bace262c1d4a6f6c6be254f2c3ca59302ab2fa5c8338076ee840fa797aaea1c5d13862145935373199e599c0fdf13817f689976cedf25a03c2c65d858ebf3dc5224856b187cbb5a3c20ac12a24516dd8e108d3b338c5fcc8bea1f84c6ab11c07c479f8b79683df28d2dc2e5d45421f9c28cd14a", "1", .Okay}, + {.Gcd, "6734dde91183ea491a03d642f38e98ee9de2388ac39d455e5464df4c80a3989d54121b2e7aa6feae7e7efc3f3b99be249c022fd8de5bae960c5f020c133fcb808d52abd9daf550ee8f5d813151c68f458db7af21e9ada226404425e63204862ddae8a2b0d2dd038346683aa0a79517d3cfbeeeac9fdefd99e138442496f10cc4af9da3723bd039801710650c71f4580adc25d7abd5a1dea1463d8cfa17fc38db15f1b62556c524c239d802ac581bee2f0ea26f6aed61e85fed5559cfeadfafced9736ae6df092273480145da1f05d958ea718c03def156364de0a5dd530702b76fe6021ef9c05475254cd7216a5c30bf26d58b2476a1a948b75e939bfee1a7ab75aff4fc5a97c3dcbf58969eadfd8c10abe2f106a3ea843f08af92bc8803b2fa95ecfe8ca36f3f43cfb0feda29b847535f3bf84b3ee1c30b3f7172d5279e93fd6f6d8f748ccfb6854c483de8c8cd563f35e3727bb62ed733c7f9e5b74157b20af50c3b4937fd1d71c786d33288e7faa32c7581d168f0cb84e6e7be7266d88eada0f59663facd7b3c25f33bae4f4ede2bf07504c6389371ef3974ac99eb14d87e6f1ffaadfa4d8a502d5f4d11463e7a536ffcd63e5238bb830190b50f86c2596ed0fd1a3735539b101dedd9e3b8b093d854281c6125804f31eba4dfa99a7c607f5ac5548663706b2f278ab1539db80239512b3c2664a6f09e689f389a1947f480", "274776fce1e206066ab717a4e579e8db90fcfc31382e8466c95dd1160d5759c6cc5d13cf20974e53032b388cc34fb5376daa94a624e388d5d2b245d7498615d4900cfbda36bd0de8a9a4259d86f6332af154fa43676244218005c313fd7dcf96768e8c9768b0e88135102374105bcd35fe6c38644a5e8a13aa38da8137acb0262d99ff568547966550e03c407ab9291126441f5b7431eb6b820fac115ff676719c9d9226b07a083bfc1d461e08d4f055f2e8b5691e1469ca2fe2b46a98d613fbaec35deb012dc10768ee9868bfcc60c3b9e464977d445216680e1d4dd4016d5e0cc1d38059342f8f96186a1ed5c47b1c24df81125422757b4b01825bb4923f4bb4ed367d3c6e52075616fafb5f6e41ddd527c5030dd3c70301cf4d52997c4db2a77dcae109f6bd7584e874702b25c8fdfea4961e54119d5b25c8623093b9509025e985e160bba9bc1ffb1e13604f69485137746cfab17a69e99097e95191be0a420e2d9fc63c9ac5092de6254e6a19cfb1cb9c28fb91928f18ca485cd9d251a174b78904154fc7c9981e58a0d2d9f61f9101f5a470ecea3cdc9feb8e84f84f0786437ddff63a7d63e705d50dcc70063519a74dc0cf80e29327e90082686fdde1607cf2ab80351d0dc80caf35aa058d1970a2adfa836a0b5d9097dc641d8a3aed23440dcb1367627747515fb27a31d7b0675e9cb0f5450648cc93b0b620dcd086", "2", .Okay}, + {.Gcd, "5aae28e2db3dc2c6562ef2a96bcb1bc9f1863c6e378cf4def8dc6d13d1556abdcc42fc26ca367bd16ff49275cb6ac10973ff0ef704404a31192f5c8f34e1b5691c122810388cf1c490b979aee9888dfbb33fecefe2814cd5ba808aef19214c32b29de25ee76186e74801771cb8fc232f5b56b1743505498adc5e0d4d97ca80e1f083945cbd5241db4919be23d2c3c61799df1ce9348251550d3113cbb2f25891decb852c4750f4f84f89fe42fd2a2714b051ec9f271783919abd6d1e34cd30ebcaf3462045577f7c5fca50c6e863342e112b3737bde6f148c9f50bd889e670f3b0ee711183f520a7fb2f1de956955aaa60720a46842d18746091bc017d6dfbef1e158d33f903004da67b9de81de2b43accc8dbf14223064cfebc28f3cab7743be07980c9cc7f0aaea1a16f7914000c73aa73445ad2755e60bcd5162b81ea5f857ba059bc1e7fdb0bddb01227b38ec5b919af48feadc68d75cf18a6a4fb7469ffa2f299f262105fc627070b46be4a7f369df6a7e80777e9ed37f16c2238888587cbc35c4fb4a99a6b9e62e9150b38585b3188fb161c3968fe9b4f087bc25c88902d0eda97f1a76b9fd9bea244b61e4825c1c9adbfce71ad0a241700cce3688e53d4a7ca7febc78d88995f179237454296ef18cf93617c70bc259cc355857d987d12d72681dea9cfe5d9b93b2f5a1fb806b77124c980cb561478158157d8c6cff3", "1c1e5a3ac08ff470808541ec3ec3100b921cbdb523996a1828615292d1f92585644ca5b4e463aa18e3cca0e1edc073a3e074a01d0ae6824e0a9e3b786a38c0a1b996d8e34d76f56f777f2471f460d2adca007dea7a219e3b52bfed70de3d2800d6342b131a57cfb096edb86985f9d24c7b7757088de774bf736cc04f696e740a219339374f64ff779b11ae1696ae040c33972df4b6d4e032e1d259ed375fd016b8656834160d5c7578fa6cbbd63211298efc29736ff8bff4e7011e5388ed3eca7b653ebb5d202ba4fee1b2e4b1194748ff0a2a6db38a301810a23a261191cb1b8f90e5a208aaab4a9d32966b278ee2402f705d3eb04d9cc73be80bfec217ed550d12a17da73a5805e6933158b8389ad3265b3670b8f5159bc40404a6b4caa0a3d3c63bf6bc6ce2ffd93aecb65492bcb3e541ecbbe0f93bb1bb7b207d740451a16cdb05771edd6a25f028494e9d3d9b5377299d0b2803c1609df6bc5552d082195f80a866976067ccf5cad6bff3dd903f3dea6b22071cb2a648880ce439162b9f41143cfdf089292193f309956fca3000005b9a5e714fb6218d27cc7eb928f597935263e335fe0516de291e42c03a17cd1404329e82c103f9b92db161c1c698895c33cde33f40b567eabcf19bb63090cfa00130863293f006f51be1dcd929862c63fa09ace267192e4111c53827d56fb9d3c8f4f16168010a549c6bafa5e8e64e", "1", .Okay}, + {.Gcd, "-247c6b6ed8d24260e75c5c1ddf865c7ef4f39c4622ec6c04eff21b375d98c3e468a8f0c824f374dccb37e9e3c3196f5f3e0ec4b8504035bb9cf3f03447719d8b18590f6b9bff6f3f6bdda5abe7974b272ed2ce06cd291e4a5cbac5e3bfaecce36a27e931e410e383e13255c88b3b87e8ece504518c4a85afbe5cdb9fe8bc60dc6ae05ac796d1d72a4a9ed602d456ea345f85528657865208eb55aae07882b19361a0b86d652be2b2c49b6b273d52948d7fcf16bbf00b92d1304221218794dea6048a82dd27725cb5f0fb552e92bd47861191d79129008b0b5c287821d343384542a229bd1f4aa31efc2e6c02b40b9dbef8f65f6b5aafd15b842bd69438880b6cf24a2e4d0093c0f0d7f923a5d02a501f2bdc968d196595a5ca702908d1c0f013fe7e5317d1d18b5448fe004fea7754fd872f0d529b2bc15c3a774b6d042a54e3324da399209e6ab483747f05ce284d57751e1c01981a15e7c2765ecd175ed63f8587ac090cbafb75906f83da1edc4b6145a58dc241b3b5a9fef5d91c08cfdeb21c71483946b1c9997e506abacffaa82c2342cb5357b25f77261a86c5e34f2fcbf0d4318b838c30016d31285d81c4b211001687677c92c6bee9eddd0b2ab2afda63bd09ae3517a9f918e84f9dfb0cd8b3b1a635b441f6d245dff32742fe0d3e1c4c44203dd74644229f2c90f0c6d06a18da2bb8e9709fdce32616bd1a03633bdf", "f57f2be65de4dd894ff5b314a94761585a9254dc364d39808b2472cada311e3786b839f08acf03e2d9457bd0eb48bdc6d884923aa3cee2eaea01ce67394c59500da3cbd27429e2c05b8f7e198160b441176995ecc8eba7477eb8501374b8fd38c55a19a4938965c13de62f7aaf230382a20b96c2e79babe5c48afab697b6f57de76fb94f1e8bd8bc073055217bd40d40421c416b4047c11351c3990e59c9dd8fbd446e6942030103d5c896570f9a8adc448b0f960c0654c29f53517f8e9ad826bafbb487635f228d3abbc136e53f75408962c28c53de28f668edf378ff542f123f187c997320e5ece318d4ba0d590b0f7da644968ce4911016f5ddf3507d7a0014360c7cae9b3409ba35b731c028bbf08dd0b1c16f53e662678396dae4f2088de8788f5f121b721f5a9bddd070c19aeab72ca97d6645ce31d8b77844efe112724bd890b52646bb72c6908c7fffc0a8d293d96b4566b7819ff7d52541716dbc135edd1ac55d57b1f5d8649344c2b6c49d743a47e596e2c5f3267e6f4c056446ee33c5b9239decc46742664bc197598bf1e7dfbb185d258bdfd4eab1c4579111ca64cdfcb34d18ebc215ec6f47cc053d20463af0095748b7cb028b57003f13ea71569e2c0d24b6bc0b13466a0e50c82ee4b0e95970fef505107f1da4f4a0a7db5fd4f62e5edf293767d4d914465575571b94fe7a1b97c57668d51c964a3f44b913", "1", .Okay}, + {.Gcd, "-1bba6344154e5c6dc1fd4087975b6b177406e53588048aa46feb4ea63a4c93e0c1fe889128f6cac652afd71be96e16ce9a097241b93ac9eb4314caa99fb4f5700da1ad0fc726016fa4dd9ff68d24bc045287eb341b486e672d78918738d9951a25b5274ced897cd6db406b2c8f768ae0a8f7de73df80d35813d8e4eacc10f2a35c8e457c2926e7fd00cc4e23bba3465cae808e6909fa49f3dd7dcb20b04685d5768a450ab7ff34cb970e19a23cc9ecdc7eee99220a112d5f171dcf06b7de9889a93b981804b3d723f740ee2f70a526e2e0ff7c747982d0a3bd556b9251398173275cfdf06c83e13700838e9e7dd066d48da1f9ac423832944043e46874d207404163eba61454cc15b72142ed1462bceb001eb2f33468d055453359b01b6d07e5c6a29f5d2a9f9fb12ccb043b4612a210b3993fa16010af602eeb0b4ae46fdde8aca8dfc1e1a78ef12048e1cb1cd60ad38c4539490b641721614ae7c4ba3ce294cb3b0bb3edd57e24aa6c13cadbd6dc78521f11364be35b31f5f1907e6642b38157cd6b4fda2c21092f7129c9f30eb8a03befeacdb130526619d67577f7fc09c33dd8af4bf91dcb408a99acbbbba6610a8afa2e30746de7b1798369e3c7ffe942e61e8fa667ef2238f1bd0e1c2e8881e76e634181f4f6d7403704174f3df591e1b65de931b40337da279ba9ab880868c1addb6d77eec7b2c34100af0448d0ea15", "de0e216c92bd0afbfacef2512dd0e0c11f06c9c5ef31ac1d5e2d8dcfa2c5508b8ff85082872f21fbe9e604dcba33b80351e5e32643190a993e349fe305ac1e95a9af7ec6eeb35c1a040eca5e3bfc343ffdd8bb8a49c3845c29f041617e7f2e0c5b550ba2f42f922438dcc642fa62aafee90b5a1f263b30a8d7ab659af329dc7c77288b35fc37477e690b404a972952619376010b1e9148a8110ac04912db7059abed136fe1f4d9c450baf12f6b1a938bf4f4c091ffd53388830aa997418a0bd6188282723969be4c6d289d6cc4182ea83edc943eadc7d5e670bd94771c3256ce537bd05ea718568d195c0be781db0e0761f5846b0fcab33d7aa35b6b0be0a4b8034979b31f9ff7ae375f10d8593bb17b09e11d95d6628eeb0e26ff1b20e0bf8d7a84371e2850578fbc0f471aedf280b0079b999355ee0272a16afb0ddec6cf93e328e4007291e7cae2a6645620b251d4b3037b5c2ec3e9f5566fc12d2f59c5c77ead961ebbcd5f2d1c7a157b002d871cac6da9b46a68e1dd006a322ead341db96c7ad3ca9e353003cf57877e25d4b3964aa96c1cfef2f69659a0a7fbf9be258ab14c252315facfb8f983ae33a82a0237295c5e22341f34b25e4b34b0bd536b62cbbab38c685e0e4a078b409a0543b3c47ea64981c15d65bce7f67c3eed35e65c842d2038e9856c94501ff660dbfcaf21e696a1cd3374d2a28c535bda61526b6c", "1", .Okay}, + {.Gcd, "-1bd40bad4b0b384b1af8b67352e06aa5dbe250acbbc30a59dd1d9e0079b1a4da9d87898e7a9848b1e0682a6481f9e2978b2152cb4ce8cd92a60f2793364ad17fedb70ece29e317b41d34da74375822e1d34871bf4aae2572d7d611d50ed0bd337c5aa5f3a31c50d5d7062551f2e950de51968c8601b231688efbca5995116f165bd695793bf1245d518bb03f922525565430d6eb2cc508329e494412f62a5f25d3f1dfecb960db52785f12123e59349a668caf99e95cdbe6e44b6cf53afeb4c8fa8c2aeb3dbadded6eceead45ca4ed89caa2f18a9086b366894d2f2fde6ec47f49786b30d5859107a5054acaa262d90a8a52f84d2ca35ebaf3e92d51a5778b714c0db849fb0919f4ab6a3a7d23a8ce1158b58c01bdb8cc5a398c436ef9e5ed2a66b1ec2afc3a77aa2c82e5c1465fbb9a7fb68033491b1ccda06a95340a0bab52d4d09ab4ad5ad9a034ec3bbeefa340a50de23bd368747736cdf4c2c0404c055a7ea44b798984daa157f97ff5d41a967758dbcace86e88966fa86f2db48c41112b8d819bb6f7b1a1baf1e549160e7f02fb68cdfe1a87d18348ccb037b9573d3af754d952ddb2f01a18ff1f45555320e8c193c2b0d903540de22e3e42d03e1ff931609b6042ff9d64ec73653e4d36762a8947ea412fd40baae5a206ac7e17bfaaacf47030c2fb54379959f7debeb1faffd0eeba1fc20210d2251c2aa93aa2d591d", "dde19a226c235fedfdc93af9fac5f2e039aa61d81c270db16eb5f94ce5445aceb4d5fe0acb6f2c75a72eee6922781ac4901cb9bda65a93c0d268a26891b42997fe6421f1182549d48e1fdbee9f286f178c31dd2d79e013271bcee8d297bcf7a5e7bc3138ae35387959c745e0a0bd7e7676a1668bfcff056c5408c296cf289f63a8c618e5f1b722c3703645b2cd8b8f378f2e417ab56fb59d9a0e9b9cbb1c2ea72b465c337482c365b001e563b5fb0975d85330a70a1bf1daa9fbbcdb4b9d88dfc6ecce4d2a13214d91d83e99b451470540f9394abc275981eb932ea90de3305a5dd0cc7dad1a397d5da388f1c422fbf963cb3816d5eb242bd6ab1d36438bc6eee23b0f864217677e66c31fc6bc150665ab6a96b52cdd9af76809d32e6cea52b24cd2b6580a8e7b8bf129f5cef0e6fb86cbc4739adcdbfdf877b51f4d7c8348f89f118e0e32fe17f8786ec14a767d357511e38088f3d1fc05b5cc5fad49789dfa9773d7cd96c5e3c4e532a9d4e4ea084ca055c04cd299cbaf7ac34bf7c1dc9a31081fd804f67ce7e10d3f95ea11340ccb685ad3db22ba2e21c4f49461e7d02b58bbd457f26a89a3e0e67686bf8b67ba3a308ba9024e858563e439ec544e1f47413156e0421dba0146b8a85fbca52df8c5de630fc2f29c4f65e27d525438d0da814e0e11ea6b3abbdb7a54c039e3f7aecb452f686052e598ddff76831e52a4c3bd", "3", .Okay}, + {.Gcd, "-ac4df36764110d5d92f4b484787bc24b1d1dec474d4932efad798cf99733d802b7bdddb86b769800f41ed39976b28fef5c1de5a787c507b7fc08194200fec9717914dc05a27d2a3a031fcbb9bc1e55da935b91a714ec43375ed6bf5b021864b15ea7f6ec4b106c9e583ca13ed35f9a93d74c6d48fc6522914dc63cadb550aec546ea61e0679dc558e6ad4d3b0e640b7f4c16bab516246517d35070138d2f2f924ff4fac6c06dade2dff28b193ec828ed9581a526676424e1d13d88ceb20c2a62e1a27bfd0b5fa0c5ec99074adf4e6539f66168bdc9a04de023e90f3f4c41739e80f5f4a7539f671059d38d5728bc650470dc02ed9fc33dba70c9f45ad8b61efcdcbbaec22a367afd8b8e3c62072c7fe2be036475d03ec9ebb37dc3d2cc64f933dd231d37af7e42a5df75cf8ef85122c40c9dde8c4c627006b45d2751d660f4942dce24f6810ad3add0c1d244f1f4fb40e50bafdf2431e5578f37b5caf736cd96bdfe1cd77a0c0beeaae3045fbe0dc6b48709821cfe1a7f3a5d227a07a0aae739d07c0cd41de7d549c73ed7891abd1d45fb2c4d5561b584e028205440379d19399a6165b24954e27e07da2795970c1afdc384efb192a4a9a4c9455be1a0f638de10f8aabc7367ce708526fbdf9138e1d094dcbf7b9bd9c830fb85cbc38dd720c670259057e691adfe57fbb860d71499003a43a4b4e516abbb193a80feba6fc2e5", "b87c2ba2ada6f6314be5221cbb163e48a78a4f24d07c215f2053cb0c6d272f1dc2ae3c5f0b055f05989f2a2a66554e3f90bbead1213698465b9fa01c1723b50d570ce21b04227e1767e112d1731bf346f1e7ea47f9cc3687a418cfdd059b5e6f3ec7f005667e8f20c11de09b7618968569aa8a4af6e4831b933a40a724482e8c13ed2ca6592c4db38fbc73bf2645b81ff8356fd0ab8e543230afcf9f88641d66d2f2c150ce9bc3e22069e68e49169bad278d7575701e19961694b4256644be545bd5e5b737b34098e27b2d3f091c1fad075e4ae520e51304cce4c26df7bfa19def2f04503e9d0d68d1332a8ad350d8ff219ad77c3ef6083bac241b09d970b186f1f6f4296ad17ec22fe36b4a9db7861619710b8249cb94d7731e75a8523557ca71d8a1aa8dbd41214dada544f2aa57169ebe28fece0aac798aa9ae3c0c91abe4feaf0762a9e512d6fa368d4c16babe83cb68b0bc8b2b4c780a218b2a45009203ffb47f7ee37a786fbe362031019ddfe11dc9fc1e476e73b5cca101248ffec69922213ec2ea9e7cacfcbd6775022c458b0e7e5dc10ad961b388da326c04b3efde47e3f24a0cc5079aec440c3efa5fe2f16edea626a3684b93a73a80b493543b50d7391260081b275bb76a8eb2d8ca3ec974114d4e100e4713114bc68388a07976c7166cc39f8452ae6fadde02823f48bdc23447a0b03bc10516be4b84996175dd", "1", .Okay}, + {.Gcd, "-5be373e838e7caef7f61e18bbfef05f04c0a77e2ac4d911e58c6cb39c029700eba013eb0ec2739c9ab39855055a86e332f9d1b9b325ca1a8c3c1ef2c77d48aedf262ae3851a106ba3d98e955f76ee474f1f55e4366b8273b6c2c9f6f5eaf83007f85b5e90e82e81ec493bf30993e1a430a25a914ba308071a2f1699e7699be9883cc0ba02b99285a8730dcd4cdb5178f47c586bdcd8bdcbc77552d8a35f9de4057a6a7d0c5de9ab6f7553380053938e3f249255d942f7b286cb34cebf01909de92a86f074e39e8f7a550d4cef10e1b82ec89d6402e15f006ae54987168411af707960220a4025ce4ce31956df5720aa05a54a4a40da6564fc5ab38605a8368767269aa5ba86f111b0a00b36edbd1517d266fdcdf4d1f9fa9fd6be0e114373d5e0f8cfde84b2742bff7f80783e3905c6992eb087a18725864d59eff7f5c443182e48e2b8b6528b98b684163283d522a0132220c29b6b9afd755f2a207d40b787aec9b0b5a08cd3accbf7ead560b8aac2cb719da532afd5cc8838f07dbd7529344312b19792dc279554ea7870c7b00be23908ae27edd0c8bf426cdd43e746c23d0657c2545e2a87310232cf197e970aad29733a74671e5fba07a716db2d88917a7597cd34482c4fd0023c494bf253d5a94404df68f6cf698899a08975c0203014ad2d891c7f9794b249ab78c156f55f8223b89c87aa942118c24ac0cca950aebe0", "1ba192233283429b0d8c63f6001ff9b579f7f411e0dc53bdb031df284d1a0057e369a4589ca2bae6bad1f1f746bde513294275208df5e95dfcad657551ed2d59a479eb14fe12058fe87b2eaa0ffa5cf9a4597fceb0d4c0a55ef8c53cca317ca2697eed44e323919f2a17bf7ac1bfcaafe0a0500122e35f90a37f4b98baf8035c7bdba343dab5197667c763154ed223bb2b8ed51f97ffc6dfe83e09869b3287361d3572b3b1d658bb2c1a1707905e771634774f097bf2078aa492f2f6877eb0281244730d90bb0b1aad01168dc62947532fd5f4473284e2e1fea5f7ae62933fd6dcb3593902d7087df903c9ed9223ce8ce59bceef772dc57acc8de6bd30427e5f2ced87d7d1304d036552c18b14b1a833c288e3439c0ae6256c1925244e180639d77db970f5663e4aefa2c83eef8563018d3af9c7def7b9bead9ce678ea511fd92311b09ace48801df10d2ddf1df4fd2349c7be91b939b36cef5d48ab77585826c89560575e23c6cc158367060e84c90adbaea617745f36ac1550b4ba1666058924043d40d09a424eb548db25077a4afd26a9dcb2a1a38e2489ad92e95e20556f4ed87b4c7966dfb8b006cf1594da299e1f0fa09b3bbb443056e47a7e86ff226ca0e140c5cb073c99a3d559173798b9f735171ff5d4214b0d0043840c259926901e3017c1a771dca3d283fe64d79ac488a16fe7ffb3bd5841f20c1c33d65373f4", "4", .Okay}, + {.Gcd, "-7f0643951a53c64f29e939f369e845fdcecb393e3868fac99fe94997a421ef6463cf7cc3dc798f7e2caeac52c0a41fe6ef7370c4e80bb0f63cb1eeb2a293be315e857bd06fb7d609e02bb8ba7e1cf16806125791773df02433af82ec968b4114a13b9406c413c94db354be8745866414d7c3ccf0bc25295901b2eb6e1da1e267fb37e5df61ad48e967075845e0124ed0a0ddd0fb3317d87f938fcb98081d93a694cf995442e863e2399980a938a6bdffb58ae22c2a5e5b687012edcd0cebbb0360612e4a9e078fb633223de2775853b12e92e0c9597bac15524c68ec935509f45b00e89b3b3e6bd9bcfccadcda1cb3a97c9ec886c09e1f4ea0ed9f55b683493a947adcd2130505de73cc0da52eed72bbd2b51178642d9695f1fe72a85589febab27d338762ab99d8b8692196cd5798e3e1af973ab3d63ad8e748226e57a327013a5d1ce8f93059cb4ab23253974f85d98d2ba46cebdf558cfe6d880f1a92b3e7926e3095971882b56eaa1060cb626a0b549d7a6a6936b95da396f6ec3fc8eb6ac39c76f532f34d714da73b3e303c545c42f1012f074ae1b4a51b2f46bd0d681b2543caa11c9e4dbcd928c165941c923fd9bcd08847a60a8cf49a2c992913fe32d061260b5bf285108be0d79ab0c456c41d24ff0eba93f5a9975a31472045fadee3fa4d7e5a16fab01b175ddf986fc5411a836b8f212621885063dc2f50c89b97", "887ecc62a9c633fbbe03378736ed716ebacc1f8aeb6e67c7d7492824603363d87cc77b1440a593ed309bb3ebf01ca7dc090db54a2453742250e057fe1fba30e555a571dc55c2b7fe4f5dbe7f2e06ac98ba2cf3f3b3f85edbaac73c89820aff21c95ef152387cfd7343a41ceb90fb948985b5fff0f52f085d8516fdb78138b4c1ce69fb00e2040ea65948fb7aed6d240ffee51a3bb9d4b920b29f7e9cfff3e780b677652db4acb962969c95f1ef353a852d5b606d753e97e2401093efd419733e1d872550f095481167ac1021fc4477367cc0553fe049dda98b4b828cccc1f06049242b0c42ede062a490d2b62f4038b1a6671de26a753dba92b050ae8b96ff616fdeffd89b512d638be177e8f2c7547a0c7eb1c600950b6b97cf5a8fd9771d982ac909f0ac4bdb2e97f3d27e48c3f289c87267f86da5821a8de17f93da4af3755549a3355312eccb2838fe49122fa1ff39320e73b1dc99e0e2ac378f60c4520acf3cd0dfa9566b72541bdf75cefef18867f1849bb01593e544abc093d94fa05fd725a69e8a507a9f967f4007ac81140a3f73ea542b19ce89ec06d3990d1dae0735845080888379ae1d4dbe661d8dc1bb7ddee2fe6fb7d16af30862890c35400d467a7674bc285eb0a519356203c1ec2497ea579778066cf474e8f4855d0e312bc3d72d11c81c1d050687e3e6f12117065b01615d094f89648faa8a541d231ab5", "1", .Okay}, + {.Gcd, "-383fd42247c57c7307184214289fdca2dfe221b7d48a775073a0efdbcbe9b68f9c5557fe3c1d20dc5a1bfb0b8c551bf79a8785498c68bb88a40232d5188570cde8f9deafb35f119a2a8d3a0b4ce41e257b3866bf016b497085b57b243e9b7acbfae0cf6d25faefa0bd09bda9c5d68ba0e33a5b5ac304df31ab48ae9e452ea816224c2f0b86b80bf7c59667d46dceb0668e2c3dc17acb7a9a412336f62cf4c1d2e4f75d78dc09a0cee6321963224ae70c3f8d86d834d3fd35f3ea7fb44ba52788e37a4b9115bc6eee4b34e7cea6add64e1581c6f8025c9ec6e8aed3de39cc262abd217f473482a769fb8c1e163637537b2c4aafcff25a0d740d75c80a6feef762cfabc09d6b7735a8dcb9a5a6da28d39e459c47db857799c8d110a18b33f6da2af71e1b93176ffd37ef272f00c53579f7d125a9e4bcdaf26d3711a13f274d3f7012d8ca044c47da7c5781432cecf4761f8495f6393d287d9faf39626473f8781a0020eefbabd37e7ef5b4ce51f4b0065e655184f4dd5cc0629e86371510507273ff8e9e58fea5fb558759b2dc0a37c1cd8c96140472e837a2709d41df2c55d220b99f4fa9e12c85cdae61c92af1c089346dfb48e85dde692d9e9d9dad8f307fc05f3ea452df24e8853465d2886ae1976adfb22c03a9aea0b256fd45837281969c0543db83f1ea514c7578771d35d05fb4e3ec5b9650911cb51db549cb2d4655f8", "8bfe4154ebe27ab1dc5c2c8b4d4e160579a3b908a3aea63ac1cee72fc9b51bf646fd3c2de92e1a3660d1f3d21446a86cde865ee61ba73562f72b842eefe02507f74695091a1393ff833108118b3eb4bfb6d1a94b734a0acae2348a778f281b121265b7ce87ef0e8120b3f6a738f61fcc670812bc819b86dcb6ad69ed2d37c23a965e055319c6e2bb5fead8e1cd77d93cfa8411d7a4a226fb354a035280b06a25a3a56d11d8de41ed80c847f407a028d8ed770a94ae39f6126d15c333ce5e84dc4f3d654892c46ddefb430b214b81089b788d48dfad2ddb8e11e37be4dba65adb7caed9192fd103faa832228da93cd95ba32a6313d61c15d335b21f1381bdb5aa1fe051c21ec8d08118917814e00fb8c78a79653f4d02b2556abca3add6b01baa7f28a413ea16cd11e5c51178dafcffa4a201f6372909ee11c3649741ed0fb1153a1378c5710cdf73f1057cec4a30a375ed497a858571a0863aa586bedb34f04272daf04e82e9e27b6fe4a7244c3714921ad76dce144f2f53ec6b4d738735cda422d38348d5a059433d7da27c9268442698b5dd8d2f5bf9207a2216c9b29bdef6d114bf34421fbed5c1fbb11103563cd5eedab3da96229d5216b80d9e53745ce18baf872526a73fae0ce919277a5686ba165d926efb9232381b9899f8fe851cee370bc1d42e9575eb13b596d1ff702cd2de20a9af8177e65e83bca49e6e3057ea", "e", .Okay}, + {.Gcd, "-d324a2c90852b5dc0ebc79664e7ba606ea34d8f7efe9426e3e00661d030c4cfde5161df2b61eee432ed5d603fbe9f649b8327b6dd6ac447ab6920e89a9f2913b58ab7c522aa4b60f9ad5a00848487e5964acccbd16faa484c9aa42e1564b3dfbaf21a5a5ee6f1c8e02b6876d13cf406ee26aea890d9d8e4e5cc615e26e1193e8d2b1054af3611aa6a9ddd5ec41d26cfe80399ddf25a6f1b720c995e3177cf6d04e1b6380d33df811257b11f3210e068a063e241e43ddf85497bdf69aaadd2a026d4cda26047be5c79671fff6e6844fb5965623b9f9f8a88342609abf3449443d67469caf31f494983f339748bba677ca7de8a31c02863814adf7713717a6e10d1608895307047477bf1b51696d6a2a123a9608131973775004d07367216a263de7d412c747e6b3ff36bbfe5c5e54bb4aca61f79924d36f89ca079f86f9474f29d987d88a98a5d0170b3ebd2abd5e8879e41dbef7554b16e45ca109b1df770c8c500471aa04fa8d9771b2dacaa28a2bd903a8745a6bfb9ce8e42a1ff0895c80317f9e561e5cb3aa4d1df1c0e11b5e1ebf2c5e5bb4d7812406235b04cb908eecd67a6f45e557174842c6edce87a71a2385e27daf87dd8c293c428ccefd43d703e00c167d1c7575b344ccb88e3322ff81202ddb8144b609850b627c2c9fc2ab3f10144d1319ab3c283755fa482a24527b0b48ddf124473003a1940e84cd9f07e1cc", "3787dfc10a3bac2870d739ac2a253eb8746a5c41425d53b7b160ae891a7b15ff6f64153fe48c56a84d3dc1e57f68f4ea688cbf304bca221d01d293b92c66a030749d9132fdb6c1d9b1c94313e4f8fdec2e7ed8f28d19cab656ecff4ba61d4399f22186b3a8f2711aeca6623fa2e8499b65444f5539a2ff9016e38f86b23c594e90aa550b038238fb42b4e278d1a265f28cf24c8636eeb4f31fb36e0663d52009e10d644d1e2cf9dabbb3fae15ace4516d6a8cfdf64eb9bb4d42d26111014b7c89044c81b3691966cc658d7c56b43cd85eaa4e536e01b7142f0e4ebb9a23f2e4aed17b797b212c403aa594ce57436fae2bb5f083a7a161a21b854fe646a452f7b22397e944bd7883c04f1291ac58cc08a9f6272643c311c91e662ea107955e0f79334090d74374070246c4213559de22abfaa72ebb9649b429480e928656918ded59f430ba51170993362b982056abcb0ee21940864f17eeb2196dc6ffcf817c09503dbe57022279ab0acdd14e6a12383bc7209a6363785f9a41c1a187a19b0cb7ff436e637286c1c13fceaa5215047551d94753d74bb7a724838727b064c8ade458aa2257b7e88f4dad500f8f331a2f58d3a90e2202fc38e10a113df714494755c6543049527c632bfdf72b3eb8a7a7bb645498ab2307863439d9733134aea25dee964a4014fe05d4f00cb9822c1d068025bece8e06597be12db8ce5e05fdb7f", "1", .Okay}, + {.Gcd, "-faa58570f8badf420aa4ab962c03b24010d9e5f9b91fcd57e960d3c4eebb774468e0101230d4f202c098c690f4cb3bb52961d727021ff44f688cd897165c3218077881d3e4cce1258b30c060e8fa1dcda78c9709b403416686b07e59a83b8c10303d5549d6fd4539f76ff946413f8d28793df105fcfa2575d5548f2a58f24275e679bd8e3119f4d3cbc82582616e920eb6803699d2360f36710ce8d8cc7aaad3c92469b372862506ae2517cb9618cd3920c3daccaf89012a1b7a2b6e53ea876a65f8bf74521d8cd340acdb714cf9061e3e15e60149765f8255f03b32529ac03e8a6283db8bb95fdf131122a75b8ba7aa35bd427fb7f44b07a2945a8ba1c08745cbb33ef530df6fd60788ad8498e42ae4292de1fc44537086ff8eb0c8db623c2a5b5141e330c31b6f99cae9ec94c7d370911822de12da4e3907c9c5b5989e93a25d223015610910e30dd3a0eaebe5a9fbee5dc82bb3b39b2bff0e640a5cc5297d8f31b92ddd71cb7fb25fe2b1eeba73433e88c5b651b2a3f6c25fabced5a91fc01d31607a357dec05b85161b4e08acc7fe4c93fcd231379f9e1c6c1b31b8d250b484b62c65b334172b4b3e75b8df65dd6ad5ce5151f56b4f6160cd84c7697314b59aecc940d94cc4813df7c7ece59359fd85092e4a86863467a8dbdf7ccb2fd1e0ae0ea09facbd99cb9e9a9062689c6987b04bc91a3c3557de8ee52d02df6b729", "e23731aa408e99aed04283d3b14ff6b90fd07220828316551b94f406325771527aa05a4318deaae0b01d660af9872219c3af634d19528b6ebdf75cbc9ca971ed3081a0c2056df3e353cae7c29ab2d785bf205b115ae1669318bbec0242dc799f57949de8cc06de8a359de519afecaadc076a7bf58c11d2666805fd2805cf15389583b4da86f34cc569b41c66f2270a916d3c6c7e4f9984c1a77643a19100d3c930821f36fe76d2f6c2bbb77f66f6586439682f8ab9ab48abba9c0f433981223dab93f62058fd1dac5026baa37708575368f65ba8b2e296aa6c18badf771a7da594e28c07e3a2d1b22db9bf02488523433bc6f1ee36ecf69a178ab40a9c9302a78b0dc8abe98bdf9927f06ef60ce47d41d7627b85f9e848da8808efa54d05f9f8f7e28fea9578775134663fe737043c80824a7ec114ce055cc1b3a57c211ba9df7f268f125c442d882992daaea208da0cc8299257b7bf872b7c4296af0a824682e2080e2bdcec2fd5db2f82127deb70bb157cd4829ab90f5fcf453fffa3b3469d88977beac7cfee38f3ec2b37557b049eaed7a4732f753809060cff4cef04e23023066660e931e1954c44d0630ec16e033f16b1a9a2788c225fea6336a253d68584ae63d8bc3cddf4f7a74e722d0458a42a9295bfa55d734261f30e903920b7dd71800c81bbb1ca5db29fc2cf0f801e14407bb3f9aedfddec1ebd2913229bd23b", "1", .Okay}, + {.Gcd, "-1524e1463b01d2bca62f8fbf97b7ec8400ed4bb7f423bb5329aaeb91c524ed3f8ad8295ff0b8a85066db67da090f5cc2065ddae8a1c01f811c4414da12179ba5306df976965545e70229052fd5c4cca0b91b17910a427c19d9767a0ad6bb3bc1349da9c72cecd249abb9d42fff27c49a2f9fdd3b087e23dbe4b9a5889eb8633abdb3255b8bf7fd7e8561dd081f48b4d25d22d2e530f1aab269511445ac8901db0f100aa2a1b8491d9567beb5a05ddd302750f34bb4038ba08330b3b5225355eb810956e6738a63ccef595ebc2c74db996072350eb517b009d74655d13211d064696ecf3bb228e99c403dd7d8e762d70a44cb4d7eae11e044130d4b6347232142c20940fa249d4f60297df4c9e495b943df055281efaaab22cd339a86fcb0ae84172f4cd62296787c269875de5795badbecb033e999863a72ec5bb98cd9f0504285cbe9ce7716f26c9158d0c27a946e0529d3b916fd0fe19f06c0601d1634a73890a2e6a2fb8228ec5ac8e7e0b3004a20748a39d2b6fb5a01c166b7be0a2f8065672f8e45005156f8718741aeac0ad61a10c1e43f4bd900dbf2356313d1210dd9712c863e62108775971bc4635ae7b585c21dbd5fe34fbd71c4255add492b8411abbdda36621c5649737917793c3175df477ceb922174f6bbf726ed58f2b31ce572eaa90d6c7f8b32e1156e2d98be64ee3c4e083bb74bb0ab29ef92e48807eee8", "9dec6028a8cf7de84ffae74180394a153ba5d0694a1c82f7f75dfb5c421dec7ac8ff96ae071849bce1425044a9430caa2fdbf3d7cd3f0d523e427b47f3ff3af4cfb76c22b122c4139917c16304f201092b901bf7cfb3fe76a1a04a0aba82d3cf31362ca1f793df4780fc2216ce6064a90ab04d04baa5ccc136edf111819b29388eea705890a7841775dcced69e1beaf0a7e78dea8cf76b97cac978c4935305012799cb3499e44f16d7c8382c0527993f18c1551f450c2f8dfa91dfd9ba45e18177f524d829953e6b119fb95e055120e93f7614d9b43e98ea8fafaffa66150d3fa35e812b7ff6fa86fd75419bb5f6ebf9dba3dff105614780c7b304df567860ba3d298d5d486d2c84fd23e504bb6cd532bbe3745700626d60efc280fbc42c19f2409052deef55d43f7df5d4a015d6c32cfb1b1330097ca8f7cf61acd4104931e5ea8e39ebc2618785a925a212d615809d673a3cb4010599bf6a47b448f6733fd59d5f204af89f5477d9937bb884989c87ba80559a135588b81a4d03fcee5dc15068e5fd8a23c287618c1108afd7f105a22195b47d0d67e62b78854e652c6a2553ee167b2892b992233cdc20d25cc868a4b623d1e5554280cac07e49f643e196be87fcc915bd3152f23510fa24c116176a1dcc73619c896f56319500ecae7493d28a680bff7229f2ff5182450ba06df7028ba55f32c45989966dd40c96767e74a7", "1", .Okay}, + {.Gcd, "21805f550d31b4b7773a3ece4f8203312fa344417d78e872d6a356ab4cbe5cf85bfd70b34212c3748e9d7939ad9de7bcc0f809b36e1e6ada61a2249d977bde1d342ffe0297fea9448690074a4961a6ea3d85e9524f813c082f5a1b5e88a092343f300469661e7e6e37472bacc3c9a871e719a6fa9680f95fa32a2674c95747fe58168bcc4864c48290304a98440c58aadd1f31a54556c1027bf07a571f3ce81c0cd4d62913211627fdc6e7c68c3c30a7b3ac6f5f087edabe296a1efbeda0775aa3cff6e031c0b13d12410834e265691927fb362089cad737d0b06582dc92b539e705109fa3d41f2e9bf59e247cbaa680cf903052b90bc232635f7573d6b0c74548db705c4a6725a05ac92daafc9aac57998a61c893f91b04364bd13509751bbe2ae7ab4e6697b096a2a66e6926b80089ea0baf046b4409f47f4a482a27f2ac72c5a8dbc52e44dac71746a8e494659627390ebd0e6c4b6b346fc41548e645fca57322ea1b5d659815eecb814b58e4aeb4a7b53880733acc4f365a467702367f0f95a91cf6912c6df8fd19da9c5f7de23e88222e8de2e7e5c81d09e2d55689e62e8bf44d9ccb2de2ffb2b3e15c2f7a3493772e3139e252cd332ac0a70d3175ccc9462bbc2d45bdb16b44f47421f2658420355f105efc270ffa30c2d9b790f8f67cff175ffd5ecf4006a2d26f2d2310d1e81b8273b7193a44ccc3fa54cc9699a268", "4783cdc15eb58065f483351c8a2e49a312a3c54f4c7b9af542284695f089baab66321d95e70cdc53c8cb4f8fc1eaa48177f7bad9a483ebb6ef7f6b726ffaf3deaafa8511938835ef700da2c2604d9d71e60152a2448577cca05d30131e151207699bc02c40d0c4c554be7d31f377f1c792e9c20a0a1b1047677535dad677d369f726e0cb52f85ac7577c5cd6197abd86ee072c496deb16a4f727247989ef47576b00b2dee75554d8598bae36a83a2846848b42b63b93add36309d20f6b101a752b12d3cd7d50a71846569868f63887a79aeae2fc91cc112e67862fb8f4bea4dcc8751380ac01fb2f05e8f0946b2173feb336c7f0947df49ca94357032376b70ab9bebde1b7aaee381b2d21c3bd4b3cd47691b27b498fde8ce507e7520403fcea839e15d76e07409105f8bd1fa596c63be4404cc70c4d75e02cb20c249b4bdc2943aa50119701a590b54d37ebf1e0ce5f2ed277a49098fa9fd47ece0286a1b850932853444fab3976bbbb5bd491541aabb9d98779e2104b14e09ea02c183162a6151b1a77181197344a4bb119b607195bb4f978c8d1d5c0ec56e88325d76d36cf0947e3edd5cce8f9fe214b09aa15d6c8db09d028dff26bb71c01acf2cd8330ce4773ce80c09be13a61633b1601147d524ef3e42baface246f840f9c346e32a8c40f5a126c7b0d12884dae5dc1295a08be351ff0b5b7f15f1218b2e000261e99f", "1", .Okay}, + {.Gcd, "-5e28fb030642323c4073aba7b9af7e46ae117af140b14a84864fd370c08b0e18311b17d96ec7cc3c0f3a49571772cada1928d516b8cc552652bfc18910fa901ed31b890d60d89a4524ad17b571469384531e6b88d70beb29c037260db705360e86c7665a3f2b8294bad319754f499fe613c611a41a6a60c0c375f8fe1faec6d723577375678f4494e15586cc3815fac34ca65ba9013a5a189a4df3dabaa3d165ca44a6233482297d81cf2ffedf89c03edbff64c679c50a196d12e70811ae18f2dfe2408641c12a4eebbcf8e2f6f9d9d018a3960b7702cc8a447a9247e044e8183d21b5b50a78356d4b24006706935715d1ee7f7f22d9d8ef2bdde80e06e498914841b95bd4e28b7d21b6ec313c96ddc2ef8fc9ac6c36ed79f1a9d515cd6df7a9350a02199f96fe1fbc6eb9f07f7778aa02ba499abb6acb6295d3527f38c67954bb4e0a14925063f22614cbbe5116040ab1e78092a3510c312485052f7dec33cfb2fb2825737e277475a9e504a6699c9b8b443657ef1f03b3cef9ca8d06ffe1d313974ad6d3ff61434463afac0caae2798469c966ab04636fe4b0f11cd8be099d790bd8d4795d67958c3e8ac7c5ba2815ac59353ce0f2780c4c81fe7979752af84bbde85f94a1d22a38ac15f1166ec19f33faca1bed16e44b2f180e6831c078e2f336d17495b73a539bd84322031fa59619d34a5a9e021a9a03b0cf7b9298979f", "574de7c3605042f467dfe86fec77da49d665e4ca274a5f46edc5b755e488991dd1e3b48282305df9ef4d047eae491eaa6fe9c9d6542f84be8ad8c22fad1b6825a791d90f0a7d9387d6cd7803b0fca092355ab827f3a4a7a15d92c288d08bcc5093d135e7219ce186a08992383f9ecb1248c06a8dc5d10e377092c9e830732f52a7c222a7d3f152f8dba82413e69e06cf7794613c90507ddcc883d09af49b3766c05d310f8801dcdf85cbaf2c83d729ec1c3226499fe29183411c1bb72a3583b2dd8f35bd98a198a79d3be12937c333c1158e692a48348f41a7b522579a915b2cac2bf4ca8cf9d3e50ab5724182417334e48f0fa7d99321cb2f877ffd7c75dba4cf09a3c4d0531bc35ce50965839ba5f95877376a43876f34e09c381c75993bcdebf08f5ee27f92ee3fa57aca3e56e7c70bba1a0036fb3a87c32f838f6600a563565649053d2273c2d5c93c829aad93390caccf613faa31dd96dd1f1feee54b177eddef7a0c290040ec03532fac74adc57fec76d252d8a1c46e318c81737e84627bfdd595335fbd15deb44f1b740a5e0a734f88b626cd22cf19c87e5dafdfb35f569ee957f7c2d3ee026fc6428a242d0ca2ee9d01ccb8e9d6de1436ff2f0cb34f3dc540f88a9da34097f0b187e4745bbb4fbaca96af6db6ea0b40ac13c8a65bcac612cf3c525d6d67829c8fe267e5274ac6d70b9cd500f0b0753c55dce2139cc6", "1", .Okay}, + {.Gcd, "b8a2d22e8abea49202a19319f0d1db408bcaa1777d7e30af1793a811495ac8b0a9beeb69f29ca825f6e316d33a4893d7c510f12cd9712228faf9084027d006b68271f9c87985c76eac1d6771c4368800f732e3129dc1c36270422589a75ef8df0008319f4d3668f6e5f5244fdd0e234f3224c310681efe7f85ccc4f9fb5052b29876a3d693ed80f555429ea5c1f9d55698a70a4ea36265b921d0fd1ed4565e6a8ddb50b548e2e647cbc1ed229645f973641283e9b510dcdb5d61d81dfeed3fa778ce4ccc84edce5061565c6e854c7a5be9919e0c93047bf921f16dc3884d64e561f1d5e23db9084ff31aa390a081dabb1a13880db2d4817069b0e6f748da0c13c7b6daeaa75b47ae11bbfb4b3a7f5f2ac12a7a9433cf6edb8245973f024ce59149e45a0fc631dccb04dcdc2c5689186a237607d0e4d398f0d79ab28aabf70766914d487ed4134720092572ce1e29f5ca5b63856c750c2b52df0d9a64e56f45108c5e6eab7728980e83dfd3b453c5d34987654dbb9cbbf479cfdddf852df4ddb98f97a7ffb4021ec68e19a950bf37e982f39f41b2482e74e732fc3da7c495c2146bba7797dd7cc618989b11d30ed7157f8b4f566032dc38efa824bbaf4e50f86475bd3d01efa001cafda0eabb8977cc72d782877520e6334339c72bdb552f1993fc65f72796e4b3617ccb5e8492c4e7e5c3657a0eb07ee6cb9806607024c5744f", "e72a0ea6899551e5e29d378930b26ca7ddf2553ce34aef75596b49cfa7be3f0c0606bedc89c1dff19fe150c5ea35f1920077f3a9fd9e2b059afb7636481c411db6dc26593387974a9bdc9962c7662f663ec5548cd4c5b329db96c0eceb4a981c9d5fab9aa726d63106e0a433cee8a5c838ffe16c636781159739283cc2855752af9f6b69bc2edf12bb3c966c4c30f9b1698bbc2aec4154499274d1ba27368ecdd3d45ef83f5b89da22626adff914b83c0dfc01979c039c29d5463429867fc5ee5876aae5299c6a7f9816d23c52caeca1e442efd320b890ee492b669f8bfa2b9b481c66a57031c28a05cbc1bc996ac34da8426706dafae478630165a0b1e52db00bde318b3d928ffa6191e74e9a580bf4aa654f513e7ef1f49b527a7684522cb1f7402431d73b028f08a3002c4fcad7ccfd7980737cc08386af8a7ca122c356ab34d3a646a388d854ffba94b24eb0e04027e82319197a6f6632be928d509b594b917ae903aac677a3acd7b310c84d4c97ab004050dec35a77f291615c5ca7a0da47418322cf287c4da03a25400ac6cc1165d39fde743d60fb5e1a2b9fe64403e07c31c6ece4f79b78004e0b1c1d7bfb296207a0728fbd2bf34f50c95d4ee5e6bfe5521378a9e29fe624bcd3adce0e235f9cc7f85afdc438460b418c43d66bc8822d2fcad296758aaf5cd954369df98f3cdca2efaae478db871d0d99111d18440f", "1", .Okay}, + {.Gcd, "-1e9cf48724e7eda6e9ec0317aea36621955207b069c416dac83659fb0f6add2b07d9052a43c16ef065f9d66d2a2bd008aea4dba8ace2fa20525ad90fbaef82db3c71b294bea54f75aba38f8cef29f90712513198b7486a7cd8bf059a0ba0dbe7e1591faed3493cbf9cd9766da5c0c4e76bc20d314078237b9de41f6ab6ed4fe9f6ed4bc188a99d7128ff90fa2ce2d73a89821893932639d6c8bd55cea1e4aea631973e12eb8be6f39f2e9a86009d094f33248c949351e4853bf93f87cbe63e3df0aef711f394500603a0a71af5a11aa779669aeeb2a8444ac54cd50bf8677d7f69bd54006d3c698224a4224e410d238b95232809e7aca83f916036e85cc7fbe12f4d0af59d75ce9742dfe6e2697d6982b97d5ae8b95d3c0d68e3f4f4c0c90890ab04cfb3e51540b7ccb58b583ec5d586555eb962dee5c728f504769c26131981f536580dc63dba52e9fd9c7fc96ef77c9e5c658b5c236531664057c4bce8cdcaf8954050fd7d731a3da11a6943e12954ac3a15202ffc5ee703e776cbff09f3d6b4f15805acf7954df5fe828b89ccbbec2946e3259979797dd55931fbf51a6670ca528c3efdf4f6e4a5e1b34c7ae7f598cc3e95d2d443e705392c4130c86ba7ee3e9cd6437483393e31b99e71b87013e26caa6c3adfdbee6fe25fad66b6344c3b20be0f1a406fa65686a707679cba2a6d3280e9fa9721a39dfd01aa32440e4bc2", "d32f4d43ace4068a174f6c4cff9923c5218f227721589e22342a4732df1219b14243e42362eabed66562b4271d6c2e2966641c3d25026b8d6ae43f71154e322c672406fbef7c696226e097da866591734e30e027a22c41fe16d86fc2363c4218032dd9b62a51102a65f66310caec5bd1cfc12b9b4ac150997bc10c080c4e158d9e3fb5af49cbcad0ce20f24df22e5967d0965b91c4fcaafc743a5bf24bd8350c3efc0dc686eca3b7cee569838a9cf1ab1854b604ff3d4b29d6caf76088dd11118e31b11e80031141bf3a85ee5c00eeaceb1f3e79cc1b4bf73592bf7e20d946245a193f96af31c6260193888e7fb8dc05502c3a9c9ada651fb03cc5d39e3e3b6c00c93bab85907546f01ed3013f0a228ac094a0f75475919dcaef1de3a49a45ed5b398bd15960b210cb222c574905dd3aa56b962dbf769b69c6b51a9e5c9d6e22134d65364ca5d1432dfff6fc7b9f1be421c62d0510f9d8cf65c2efe4376d1fff1a04cb3c96c299cc62099ec480d4a01a43e14538604c0ab75c0bc5a225dfaeace3f3e845dcbc13b8195675ff6b2aa62efc31e0a80fb51fe12dd0de48a05144d7c166bf3167d874debdef8b71f5d31b100c19edd61edeae118e11e095d5f6d9cc3b553e123dae215fc40a0b2a137beaf3fc844ea0183fb41bcdfb3c17890fbeb7d6556d5c364ec0f55190ace00d4ecc9aca574f3a22c155f045e5be0470ad756c", "6", .Okay}, + {.Gcd, "4cb7c17de26ba04b8efc29c3381278a8529619987bb6cda43a97615b355ced22a350795f301f953b025ecf638c12cd07185b05397bb98fd8820622285ce6f6f873dbc8ef41701e35e45fe328dc65f08e318324fab019a3ed23c76b7c52bbff9869099d935c3b43861328481aa905f2cbd1c874e224961ad701c95f9dd4d6371fa6ab2de41b0fc44d9df54f81eb023c52bb672b1c3fd6b3286487db3a8e10925f16c493a765bb2a12a2bcf9f84a7234a1b6c49f174dfa58bd7da1a1cfcdf9e17d9d70a7c1d915c17d32599f4e33165379a4fd655e0380952339b3db11367a2554f3ba882abf09ed24d644f042e08d45c5e6c052939607cac5c1e4ae864933eca3466bb5c1cb12c0cfb0c57bc22281b7e3981bdab7e80a1a3d5a9cdd8a7d5d63c8ab1e87aeff5f4cfb2a0f22c37e655c83da1ccc24c2780282ba727cab27099a412600f09c0e07a802acc457911f6d40b3bfae6cf9d42c192b46d3d501c5147bec95f615b8dc7804e6968cf9ead9bac70df188bbaa0ce1dca9d549161607a80f720b7f747938f940695eb9cb23289e8ad054ce86a0a1ae4c2dd52d28ea63126511f33620abb6b4c89b8b61a5c09db2634a14ff49609f9ebfbf3e6fc3d6e653032a06213bb06be15d106aeded8b0fc97cdfecfe218a4af95f8a67f5f01b9a1666ae22fcf7e69c399f9f4d37aa9b2128699f953d2fede74363f2bf207353309005a6", "e6317ae2fb03f2f0353da2fe6d3c235068f5003648251654126466de190c47452e310704bdf91f69a71a0ea5a77ccfbe1d2fcfcb38cef2cf9950cbc44d850f9ab0aaa57676d698de968f8ce02e57fb0581cc47ad31cff8ef457c5098099daae7366d00c266c8a4f1e0dcc39f76ff9af699792afcb752035eefad75369276355cbd8289c27c1f9698b6ea171b78f814ca32680a7ab715e94ed9a998c0efce3f860b34777fec209eec526d63151ff1ac03d970a2d7f071693b27b9ff3bf91fc0cdd4aee6bdd110ea1499a3e8fe57ed908db717c03cbb22df913a663c29dd0d2d8f86c94572dbb29a729fe79fb3d950a9cb9258d0f695314d002b351659a3df13a0422ee9f951be93c824cfa3f2a98504b12220694dd113a2f31f8185da5a07eccf0837cc6d8eb194976b94bbba289a62573b077f1e9032d5a0b2cb044595df2fca9243f973a7c091f73cba59cbc80c9242fa993d3e49f5e2905b5b6a1d2d1be15c3139eb696fb05007a025b770c24e8d14e4fdbd8da625526b4871f9849ed1d99a63b341daef1049e4747e427b2cb16a387fc181ae053f29c6e2e1b6065e8a17caa573504f782b1fc913ddd387812b7733d2d654b03a70cb4c60f52bef97ec204ec475d600fcc04cd304a3392fffa636c69a0152cdd36a1d1526b4dee4d3d8f1c16fb38db7f64ab08670e44bff7c9e0a29cd224a90b688a15a93c5e3fdacbfbb61", "1", .Okay}, + {.Gcd, "7b56fe20e063836f5f36064de4fe268faa03a6ed2a455c2b65cdda41471d7a5126c3a3d12d1e0d0524f8bbb4b4a2ec6522191a3f45ff39d08da343fd743e8c40159f8412efd810d9a12804c74c1df463460f0c6da4e57d5940983fec644306bfa5a2d5aa52d9ef2e1a1abf52a890093958160cae62042922ad2cad747b34a97bd631ad5b185c3d96cfca9d299c32d02dd75bacaa9bbeb458f0e5f46cca4be8845b5df3740c3191cdd3fd8c610a4ec282ae7dfc4a87bf0cba9e6b52a4f744acbf42af6c87bc0c3c96de06c464d75ec0dd17e4f9ec8f0a12bea61fd78dd9c7f833524a33cab477cebc0e667bce2bd68c5ac2dfdfe2cdfbfb700d24edd9537b7ece47fab8854ca05a41e615b216ac07fe6c822f87f6d3aa267a49013041cbaf206bea324b210ec9321a1e7600b197bd60eae611910d67952f9a170e2285e4bff6e86a1e7cede669599d1f851e477dbbb5304de05b766171ef5f1a0ef1d2cf4fc57badd2f6a9e2311c99bb1e69f6001887754a3eb1076dff4910809073df3660bd1b2a258c20189696d2d517d3fa8e00bab19ce43a4878f6233c44e74830c35b122e3df78393f7197df2e833bdfc93f5d287da89b83c620899392ae83e284384446f35d78a0349b7edb04e854f21578bc24ffd95480426c07455f447bb4c3d47dbe7c547d3d05f675642c42f8ba79ea247289295b116398a5ce70930efe34657e0c4", "4ef8e77d798741ac370d60ad45d7623beb87be6ac1beb87188161ddbf66a622f4a67cbf95ac217f16d34879b446827d8cd2ee729ab945610ed7082e9b4f624bb52159307e617df4e1e3b9df378f82db99ed5efc767a6e5251842203ee892045e76197fc9823e5fcd4f67e62b1f806d99a5cab8f4fca5a42a83ccbe974a2d7abeab7d79862fda489d78f53f99e291f136640d714d5587965e62aa9101a67e7619471bd1f4b8e9693523c11ec5271b8d5d955a13f04547083b4dbb2b7d2d689d562a1f810764ea6551213ebd90d6dc122199cdd862a3f84228719cf69cf47fa443aa774db284d0473bd3539f3de4cd9c638dc25ac9ff51da06257783ee744a6a591a6dfe62c2b292bf2daaee24a4f6c9cd5f7433cbb9e75fb76ccc5ee351959aeee70a1c58635beaa9c42906c8173f6d1341448b55ef149eb1166a814490e1241ed970ea2fb917396e56b0112a6ec65c67e7e75096831747afa713a5f8e635702b86800bba761817ca67d8b5e0757b91d9bf3e9164789715df38231e07de1c10660f1e29116b9102c4ede4a607b46a8e75eb335ecb0e5fc023aa07934a40f0cb74a4ab6a299ba8f1395b0d1706c85e595dc2f0445a399abd3db788df48ae91b0bb79b7eccc2bee9a54fc1ec66b6dac66d8b6d236ce6f062baaf6f0a40c74b55c5e8f954c0bf872fdf2422bb1792c466100b36a5c9d3ca9d703be8b3bc1b2a40aa4", "14", .Okay}, + {.Gcd, "2543500d2472f4298d7d0e32c1025cd0a21e3e9dfcf3b2cc0b08264f8f847512f050ea17491e78c043fb142eff4b8c4486e8572e1279fdc3d40457cb00a5ee049f6f1e6a29e92aec7e7bf933a3663d9b579f1d509c2e670683b69d8cc47d0c5d39c4cfb201b9c46ea90ab5c79b02f39a0864e3e0b4350d7ce6e4b237c7968acfaa0a6e67188a0198d4bb04fbc46986f883125d26065821db5487f865eaaf1333d5059a1f95e4eba2fda9c9a9026f55c422bf734937d4dc04bd29742839267d64891da886276fd1465001590a7c6c5e4e2e12afe2b80555364d44685440d28f192f776642ea349488186c117e84cccac7212c96dfa8c37d766537830eb6d228ad8957bc0a2684f52ee3fe8f605d6c1d17bd94ad32dcce0c7ec79657f21a003dec048fca3e1ae110cc7c6984f6ecae3216873ef12b35a8d0dcfb6844910436b29edc04e5a8f988dee344cedac734beca0d459a24b5059e04b253bf464979d6f13aef05145519f24b3244be911a2ceba1bc68103719efadf3cc2b8efd37933065ee74824a74402bf53a4762851c95092267f5c0803ea1e9bc69337be43cd327480e308f1dbd63a34f339fc970d79aeb2a284fa6c7ccca1b36b405547c9d2cbb0c7e4ba5fa8ba2aa730408a8935707224c6edda1741da007c4dc4ace5d9c21e42912d8032bf298f696f589b50594c05d077f38b1cd99abe8f24c72e1f02b95c6e617", "24ef24ddedb75a140bf08c95718e41018eca078735fb2bddd20c966087f5a6057429683fe2e6a777b6ef4422728812c82d106f8489960ccaf7e56edc87caf2ce8c558a2aa59684531a72781c71043799746da45debda2fd51b5f952028e0ad0027602604e389e600697b44ac8cee8c36762d4d860f2589125844550a4dd5341a400cd2dddec391e3d3a0086c834c9ca017df1c3afab739bd0bd51b3236b63bcd07fe80bcfeed3e8a26f0bcb1e3fb7b48521c591b8718e468d3622ee9406c0cae605457b7e73f774e81e97ce5de31129027846a2cbc9d31ab4fda007436053994f1ddd4f92387cfc9790dbe5b96e4edc08010d2702f28ccb11855eb76ef6c47e82125542e3953ee5e367d8177dfd2f63987bde2772bc3108754cab58a8f0e5c58413d49f6c6e58ae13901441291146d8bc9c3ed0b3f97eefe79ddacefc2408b22f10659a2cffb970d570bca31303bd4f0e967177915938ef2643bf4d402e64239e9e146b3145e9fe9485035a225a26da5760db62f8b511a8bd01ed40a1780535a49ab7bd27b2e183c1b403a27228769e488972cd57c43630091285e74b5beb5c69fc7d2766170667cd3498d1239d59cf39fc897da42a4ca8ed26caf98211c0bcdd380c9f571505c0fde277cf4e6fde2112d1adf100c19eefaabec67806ee71f7bfc323dcbe327bff2e722fc599c28ba7dc13ddc309d95eacd6d6dabcabd055c02", "5", .Okay}, + {.Gcd, "3ec8f5729484e3a5cc3ccb90e981e1848ac8454f903a2db75523fd5c541ceccb1862ba130992414b059381252cd9dfc68bd0602cdeba5abdceb24439830a03405ca403bfa5a106baa47fd4efda6d2510c00c651586fcca63402c780aaeeff93817264d87c2b1085b24163d2a0678526234586cc1bfba6c8dae8e0bb6b004e02d00f6d72c9a801482ecdf781f1b4e7e41a50edb4c897d5eeaa0e47f59aca8ebd43addbe26e603df71353f5ff78f11930b28ff02606199856258e7206d1ab14d93be07597caa0f6a2ebfbdfdc291f4e40a0364e4f4afe17853355c915de246ad59ff712c94ed17c6c6688df35f261878ed6b4ae2e254ada6fcbaaf5ea2d5a0841b644754e3bc5accfd30f0743c49beea5365e63e11d558a90e96ad13a283d648b898281477b5cbcd95f21b3483f459a0d1b526616cbd27c6e76820f5b2d97d0fbf901018778b17a3e99cb0687a23ab444d44f4f250e7274c8751c60fc2d753779486222de6c8b08612fdcc56a825734287edb13f95cfc94f6ed884cadc4cc70c2557e3944d23b5eddbad5b6ea0fc26ffca6ca2d9f3ef1d8676a51c37c833e92543209a7ecd16ae64e8c53d36a832a9847b2b36be4c5e4276264ffd5a875124068d148619c1b03ad2772a24a1b98ad2c247dd4e67669ffba235843a1d24f340fe837d7efec398523e396d2970a0f48d784679b13f8b05e19b9f87ad4f57d586a3f4", "acaffa36ea6014468231df723670f056d53a59615932c4c724f5493c8d4576ea37b3377ebee10df7706a14e21ec5ebef51230a649b1ea68088ffbab8c44b997fe1abe384422149b227d11458e6c49fc86449286d720cbc97d64e61d7993873fbcc30c4ce0cb13b188c9e2fb81d46fbcf46f235682bb0fee3a2be0429bb26cd9974a02b0b1c0bd5ab176a6c587c9852400c76d62b0dceec6bac5f7f29f484d66ffcf788988db69fb4a22db21d82159d2641a83a94a3f8b1bbc320f775072b5d642b8aeffe1966742800811f5e55f29e08c6507c889a49c2442df6fa584b102d85f00e76ede38844b9c9b83727441ebb5312e51e2e2d210d47d4cf7d6a8a8b80b779f3354020f92b6fdf2554da836185488c84c29590fee6f302a68ae05086d2512fab0612fda617e39b3130dca0eb4bf1c6bf757ce6df3b712aadfeb43cbe0734e27a47e90e9c043dcf49667311919c42f9f95f85b08c8eb188651f21cf2bda67b4aaab38457b790908b94b4ebd5f9beb820d1431975bd32eb9615798b699d559238a466f2799628de5cbc3c54c2c314c615c8c324947bc9211f42ee445a834a24072385f5b3d2e0d8834cf1d387ec20a0443663f28f2b3802108eafa6d5aefeb18950b5b54db2d59d98946dbf9344dee949bf36f8befbc18bd2650d309fadc61013f06966a4539b5ae826eaa7699c030b0e16e83e8908d50d1ade680b94f08e5", "1", .Okay}, + {.Gcd, "-5e38ecdaff75865ebf93fa1d45b5172866701b9e2abedc7dad74236f1653817e6540cba0b1c0621e6a4d806a34c0771bc769de915423c6e02d3772d43fd553af29515ce05b1d5cc64c214b7fbd32039ef40ab0a7ed331458404122b0bc5b4c4e5536d009e564f36bf97e0388814156ac762b04283ba5225f5356b7fcb5859da878ea1228e7ca54c1b79d82e5cad75f25d5e12a67d935e27178c7b0599665d990ec02517466cdf3ffdf1f1f3872c282df2319d310d19e9dd0b57021c500849085576240e3992152272dd557f6cd9dc66e03b458c9f1c21fab85cb022cefe5076586242f258376b58c91c1bc9a756d76d12fc2164b4b90207b42f47501a21524a286242e9badcfb20ed3667f6e1c475e79e16c34890c230fbad042190b53de44f89bcb3194eb44036bf02fcddbc4716eb2d2ff8279a6b7c7fecc8bfe87ef75247f695e1be945ee6100d60bbf8932aab41e4828889cc0917eb517bd7f2ff515e77b1803600bc4970a99d41b9a8d4268a3a1866232e5aa4eaee52101c225c5dd1c95e78f194134ea3b2cf81ee88f43e084890234db85d172aec55bd5905dc3b10c7f99fa880c935e66adf5a27ce0b8070e6b7f62681b95d50da4558f805abf761f3bdf519b494d5ca4b97ce0cf7624c31a9307c37bcd64f17f62eef80ec12ca55908c82ea92e6f4682651c1c021f4922f189f5808f192381db771beba2b33acbc65d", "3fdc4ce237c9640867e7450605258d1ee7d801db5a7e288e2a0338887449057a9e38a38b16f5fd4adb9a64b2df0ff17d2552b29114322a12ac2cc85e104c60f817229bc25a1c47d35d64ce3944d09a8e37febf2e65222bb53987184104feeddf0f9ff00e264e7df2bba4b2a15b744458b85fd7e4c52f2e6713a883dea40a728e4ffa2adc1979e004c85ab5dea210277007040234ba55c91d6f58db0b7fa8e3c7a8979eaa96588ce921be52f1ce7e65fa1eb0843fc429e1846ef1a4ca4c7ac0d213b6e937b9ce8fd2708eab6129b39c54c3b18eead504c9606e833ba285cc6735129e24cc0bc36a1b7ffd4da49999e56da1b915d0f345d47be665b1067e5ee03f1fcd61aa881d4994fe4e7a37e5e53477a50cbec73d3307f9d4ca4ff7a3674ddd5ecee31750fea1afbb6e8fd9631447176817f684bea2777b75bae35de9a9d1e9a497a2347a97e3ca138339aadf9d33847f3e4a90102ba79703ff2f64743acb0818e64daad996d63a16b7df792d4ade057489e0ceef142a4e037f6bb94ef966b0e17942a6fa430f2eb5f679d9eb0ff06f9d40b2714be4672c2d4edeaa2a0707515efcd094a2c8cc796bb9b798ee5eb8eee36639b46d451c12ffd0b8506af21fe4eacf47d0089685c06084efcda0684754f89ee364f8b039e2daa26787d8b27186d1a933250a3dfb2ccc078de7c1f2bc8510fcab166e9678c18a3ab4839f0481c7", "1", .Okay}, + {.Gcd, "-86c8eb4d3ffcde7ea1b11fdead3259f0967464d79209e1515a4cdbd7cb2d57bf6eafed3db48074d207fe1bb08724a94f81efb1d953591c31f7516a01aa4d2569cf7ae4c0f019fe616fa99aea472fcf38b3d36f2cf40f34d9288eb000531c384081388a207a192210f45601302a16ece9e8f214876299e442e329a6477b05a503ce3802ba2b5cc24e61bf0817acaf0e387a3c91495905483915736543f8397e659e42af001113eaa078970915801e987ab02a0b70780c5d52ba67b75cc994d26a2cf9dbf14124cb4f19d574526756f11f83b9bb499fb6a7c9a71961668d2405d20e71740d832ffc0636f903343f0dc138505c6afc1c73b7d7ffb750f4d0024a138fab95c73e9f2bacac8400ddac75b34d234c96ff325134a88db96af628cc702c20a8d32393da790569a8dc470306d33ad80d027e7865c34ea34c22459781ab66f27569f447360dcfa74fb1ba04a4fd87a18fa899cbd2965d220a4c2cc819a50f6221c8478cd907638488125e8baaba51a964e1dac8bdcf87446a5ca43203d8430b67279af04afd620a0bf39902e6eb87a3a00638094e100026c694f502410cb4fffafe079105a1ea940b98dd99c4c86f9309a826c2c5bdfb1818906bf5ba1f621ed68fb2eeaa46b5ceabd59c469f2a8d4fc2165f486d58722c81af531e65c9bdc5f2c5aa9731898c498fad8e22bfe14643c60a0200576d7bee0f5f0ca96c9337", "67972f3367cd503d24a14a573d123b85c884048f7df0f517b3ace6f9806ec0b753acfddf055cfee81314f79ef7033059fd6e3e775f7ba8d3f94417662e031f6e79993919e4b0a1cebf1db1f106b4e365e09d131fd6e126402e89320570fb8a08a992d29a8de4713fa7e5a8d9a8473e497c2d17f653f70013331675e9af0c2a08c10f667d726f1d6f6837c037e1a075ca3f7d20fb537e080541f0ead381f534017c9c869f7a2606d80bebdb762987412fb4078bef7a803623a8be718485017d9ab5809632d69b259436880c0d03f4ba49d1050854540889e5944a79bc643c3e22cd1ced37d689eb7f29c24b383792ffee8e2fa1ce891547131893a2ed725a4bd7b11ad352880cd78aaa0483bea40044aed71ee9d8588df9d259b162cffe8ef81329eaf756df1343e07c136680a3aed8e126cbfa28b39aecad225ee64fb08295a813be2183d71960dc6dcde60cd8561b1875c5977a1adaa14d9034942c41ea1a24f5f9106be4dd932fd7cfeaaaecca12f49a8d19b7e4bf91131202bd5346e97de1435b3ed18bd34002213b85cd31a1dbe4bda27d190962c704e7bf1fc577413ebf13dc13a50c6782dac87fa820cf8c601810738628dcce133cbd77493d909155e88453755b38b73ca884e3eecd87cd6ec505e6413ed7c145bdc1920b149165dd00fcf197ee654ea3887e92259d2e99e5b3f2fb9431bb531be70fa574da39e19fe6", "3", .Okay}, + {.Gcd, "e43b805acd8d3b7a2373e9ffc94ab27d179732934d1bc2ce99d14125535b9dd09d8bc68873513d5cb49a54722a96f61e636e02f658cde76dc6be85232873f9afb1a965275cb648fa4c6236f49a7c2133ed71b374af9d6f888b750a01e88bd4426883406584de51b46b6bf130cbb425bae6113ea549454cccb31ec59be2d043c268d79270f2e23ed8edb311301602a6df93f59b4a5d9fc791594ddb2325a1a702fbe5ce2a503f7ffb5225e416335f40d4847c5d40f2cf5827f430efcedc24a88c0baf4e35582fa11993a2364f985fd0a5640f20c18f1a57f6bb92e9d810fed8fc18ffbab4225f564ef7f0e5e49aff9bb49a6383b40fdc29dc973da739dbae2c4d9655df4f4d50b0cf3134e4f9bbe36c89194ea716e50fd2b6cdd5baa19a5c309c21708a4670570add9034f1a9fb00390bc272106f4b3411acc081382fcf246745811ca5992b21f1f46dede72acc1e09dee6d5c6d0408c1d99b8ef396386c2452711d6c6cb4cf9ab3eab1316afee365bfe5cd5e02924bc57fdc40677c2e188486a1059b181b712e16a1fca693af52dcf7fc609968747dac35f5a1d34ad966ae00b1b671911816b74a24c4b1252525658b05c3ed865095fee3e1d29babce320c2659875f23e8846fdd0c26cb7e741fb958639e62eefe02970d445c0139494a4a1fa5fd5bce5c25c14937cf0df9b6667de90f196ed17839241ef32879032f02a8cbc", "297227ddf82a1fe88c99842747ba7910622c44e0292cb77e2b811e9cfc484a682815b2a2976c894033ac7809e635c2ae8c71503345faccffa2568d78678440230d7a680a69b5185a083028d5805093da38624a032fcb91e47fa6b43531d5620ee068576a93425365cc81dcabc8a42d330557fac26ca09a8bb71c70f7775199ac088a1cb244705d1f3813bcc48728354eb1a78a869e78fbf9c8e3352a6be25f59a907fa4831967b7d3a070cd4ad4bf07928dbabc345b92af9c29ac88759dc11baa34f339c7ea68319187cda9e60c53acc04e75c147e6e51a2d04f5fd012b59fe3da1b4f1d7dd7d7bdd2267c4346661beb0a1b3c815abae6c484186a10428547ce4796d11ed1c7f2d28ae424ecfbb93bb220fc50a7401786dc658593d6721c8bf13a635b5af0166f0a32424e8cd7a3d0ce8074eff10ae1f4f6bd60304c733cad53ed77771651d591877e622c28d78c566520ce8cafa3c31bd608fa09f9f4b1c318b73e1a0456b34d98539e443d097b107ccd949c717323a82cecddea151515a99fb32362f3fe98cd5d344c701dc1743df869d2d80e984862f2d74303d65152ec2e767377a5b2163795084d8310287cd41213a9599aa168535b3e052131eb5d22299c7e254fff4955e527da081aa77c000eadd2b5e96c1c9b5dbcadf4650a3ae847c80aab29b80bdb148242d205f845609ec33599cdb628017273ef84874d636b2", "2", .Okay}, + {.Gcd, "fbe45b9b4ebdd793a01d89466e7b2c6656488a71b4cb1bce767bd8213f717dd31c6459579be1a0ae8248940ceb56e4a2d46c185f500ddfd280a21ee0d16d87681362c571f40b2764281465009a18a1ae275f0f91bbf4727b97adcc9abc501409337daba72ad82289c03594a6e6f0d2fec9da0419ae98852290f33efbfd819dfde9bc467a115ae4c8963a793c93a23a7a53478cd9ee620ef1c9cdc300eca01865a8db82f4aed26b5f57ecd6bf70771fb200d15ad4bda15eb15009a795fa173179f182fb493b34c7a795572955f5dccbd323d6c9159bc1666924bb9d792383f52e938e6add9d7e0ae5cd736f74e32d325da8d11c0c592d3a838fe632a84a01bc7bade446a9b4cf2a7111fdbeb6d08f51548111295c7b061742b5eeac406f89c112d7dc04d808bf7a23ff85c931b8a8707ae71fd5a934a8b85509642fdcedb35077de1d285d7ec364a93875053cfe35fd4ed7430b6f78920866cd09d243fe7b160268ddd575d965ea3b5269fe5cb0db485c14f81b9967dc6fa742c1b53e554e2a3b7a562b9fa6c8742f73f10b381692fcf3a674f1ac498b5b5fafcb700c285adf71ce98c9bd1baea833e5592a1c31e745dbb0f324c668ddff8c5661c2a155941983ee9c70957f635bf1eb56616e6be331bbe3edeff6fcc31033ce5d48323e9880918fd2bfa5d7f06f9dcddbce1a12fbc8d2cb9733a5d24ac5831b8f4f6889a8224f", "3be5aefb8a8fae37af25f868b37aa2851c903725b41aff23603fc557e5bfb24dbf538ac9ec4a29ef0cceb88e6a941974461e09c0163d967b7660404237a39cfae933c0a6fc0101040583d254a650f03b3a93ad1e6da4cf4e6568af833d19e706f10634afcd0f79b34ad80902dd176e8a74182c0449a43675c23bbdeea80b38964d944819aaae0562e3407eab3803cdb48a63a4a34675ee88a4a3f0aee765e009984b1279f524e0889813a3a401fdef2e1aa64273d95727e2146ed488702ce86146c9b795f88c58ad8370e6f9803b8d1dbc0506b0ec806fd34e4b038906fcfbdd80ac14ca3d96ce99cac4f00cf7713ca36df750943aa0576c5dcf1474b2a0b827538d3475e28312973b1c3caa787627f1d7b5ab82aad91633ae0155678dead57ff230426fe8c381e80356ad19f7c28ace8da414946887667bd943baeace47f5e6324c0db1942fac153693956960410420d50ab87d76284c694e7740c19a1e5d5562441bc401bf4ae47e29247a7c74556b159de5ba8a50c03cc1a0ccc89b3805cc36b3585623b205387533d4ece3d2f7950506daa49a1ac393587e8083f4e56b85fb4e8452f7ff892fa7654828ccd8a8f885dfbecfe825b4ec3721a44a4b3e03694144d8ee5695bd9dbfd665e2166c58d9fe6b5cab413688166f85ade1832ff6ece23c17af57b4f345f15f0b7c44f37035a95725c70a2fbc8881e3270d7f8e66a0", "3", .Okay}, + {.Gcd, "d747e0f957dd25443f56cb387e5dbec45127f7f13c1f319943d80df2c23ecffa6c78435a82966ee8ce95192a72cff6aa2a8eefd538b46539c5e78c2b83e26526b672180ff5d1bb85b19352ac8cc290710f4dd8fa837afc714b902bea5e93e414ac0529cd4b867abeb9c1924c97dffec0c9c461a049df708e232d98bf16efa65b44fee2646ef64faeab47e328e61f6d67a2f9d5ff35f5657c61016ebf300ae8e5c04b742d60eaa8139c6d63207710df09abc531fd6ec0ebede6a6f24e189f105b0253e405d389c2f75564ee01f6c4e8496e3e530bc0a552fe53c8e7f8e46e643a43f458d496f715c0a31ebd0cb2b97f58482eb26eebe5023685230274ff92896450f6de1f430d4be6dfd6b478b58f47f4d43c5611e0171b7d529b13ebc03ced18af0d7002bdf4f88f6b9eed467ae52b26fb6005cd236c562fd0ab3f969d172e76deaff731a2914e4ab1c0c33607a18e3dd6ef1da0c1923e8b5cb77aee5b94246c706a10c2afd1f37b6f600f62da09ec23d6a34031e70debbce717dc1df4d675ec62da28a006c1ddbca0952b37120368d9c2485b952216a72f99922b0c5f4065b638748d5cf1146028928c0102ff251395ceb40a7ef056942854536442928cd33050c78c8591b9c35f6d5e01f41b6f7185fa19dc22135a103ee762cd46c317581ed27684f4808712ba13f7db9a47df38f49fc5c06f7b6cf1086212624baef21d2a", "11bf2d551df233f8fac58af0d93384c1f82b92b62860e8479cbd634da1e8dd51f8fa2d0dde43eac8e54cc3f81c4ece8ab66cac7ef475b551e720ca6f9d5f294b46fa4c8c7c069f0bb60cf3f22b45f44dcd23167663a9fab634113e45587c50af2c3f2438a4ee292bc93c91595fc790776f038620c7a2f23a68d6246efbe3160c033c30e9c7c622bd9aacbc0dd3cd703a36d759abea2392ee07d2ea5230c0eba09512e3fc3c8d450f37a537e2dca3cea85668f25306fb14500e24f86dad0e254d065655cec2d4aea6a22271647340f1fd38bb83ff28da6d1e5905a6815210eefcf1f087064aabec4ee7fcabf576655928825efb34e9ac0721d634d6d5b82ba0ccc637296ce62c030c0ab236eaf2b04bb45f722dac9f0fc396561b216c1ce7e3d42e6ace6ccaeca1eba1437296b8cec4d1618f67dff2afd00003d3a5c6512af1fdcf2c267de280a054d25cf60c5ff5ea11e10a000d2bf2556fbadc01a60d5f2a97a873c24425676f0865815f153ce85766e656badbd04dfc057183438394b99279a5bb4edd8fb6a7a33134ce202ebfcb3c29f24f62b4bed11c1bf91a20103736841ca0490a0a219cd7e7e5ff80b58c51ff167719710d632d1afaa57f9613f16429ea0d3f68c3d71e68983f87754a6c15d78f9bfb65bdb8c16f6326059313cfe06277b1e69af82c364a6d7f8982111389e360b093193b7b4f34069599585e7a9e7a", "62", .Okay}, + {.Gcd, "f9c28fcf9f3abcb6f798904620ba3311de4a6c688d65521ffb97085fd5000b34286cabb3ab43bdc8b1c4a0163b40c8d9ca2eda538b429cbec515c630789fa70138e1f51a1d04b4cbf8122863851dcf0ccad18a3824abae124dbcedd1adfcc0749ffd14b26ecf30b09a7740a1c940e6a1f7a3caf036d0dc087fe6ba7243cf19165e395a122068819420111d4c84f64c9c3616ce5e844239f26badcd181d8ef7cbe21e77e537da9d2d51cd63c6e173c130ca8c48623692f2646c34e34387c50bfd0a59f49132e2ac107e9887c453b4ab765f0e887a195c8b5e71e0a8e1fed4f44f4e24710ae1cc947c922e43543662ebc3848cb871770a7632e675b0b7cb93901af4ea41455a812c411373f0d298f3b82b5871326084473e873a7b3e29fe1a45c62a607a0c95e7738382942cf15efa61354bca993070a5ae742a94a41b7876c469c818b2501e86d893123e3b06152fed9c59c19486efda5cbe0bae88644f46ead3b3bd24a1521c291136399e6f14c6f43da905cf583e7422cb5d88186d5130c67430d66ea7d6f13d9ea80d2c8de9edbf24127f9b18bd3f2e8c700c063047cc64462585b405d268a4042caa28e5a9e7288b352ba89b3cb4bb9f8f5ff52c38d0ef0f97630a46ae5f1aa7a127529bef1d93b2e3bc0c1c883fb2b1a446a46894a7561ebb9eeb87bbbf655d6b10e1d8d96a001614a15694e7b5483627985e6d326b7e17", "a96d25b0b1d4fd9acb0c77a49d4538f7537d2587e232c4feeb2bb699e3460b4e103e8e881b9b5aa093b4385be84bf2c7e43a300b8828062e1de2ad9375b9ccf586085c2662d739f98d0565897b5550c159e1e3578555d780eb1675b16f06a9e95f66cfa1f57a5387644c71e0437f3fa62b69f990dea913477f0306202db879712b6e2111d15e07fa033f805b9b067bd1a0808e8c2a0ba80f5f2d6550392976a6bdb0b122d48124b02a501a45a577a8d154025f7c9b452b52fffdd1ae65357544a6e3e975a43466e48ac423e94e2dcf2e8c2e3b6da0ef98969f3f1b8d55a527bb14549968c99ee8d5a5295d2d68921fb82b7815c97c1718d25e6d31bfcf22dcbca371ff0f0d058064bf3afe86d5b04177fd398b80c288e05833e6df10ea45b8cfc6817f0cebfdcecc3a080168838a7dec803b486f8cfbd44b33dc059386da22cc952d903f00fadb26cef5b66eff4f9be185b7ec6bcf4291fc5a679758f4d15c05efa8cdf3722fbd8f9e9504edf5329d34b4a642790632373c968b1257d657684b6a5eba570121e56bcdf0b3c6e6063075cee3f95bba006a595e1455437b7f8309aec8f03cfb73d3b0e8a7bc46ce7b8ca0f843ff0491bd5bfed5767f9d0c979d3a0074f9f8707a55b5241ddece3b1031b58685ae78bfe15cdaed698deb2634134f916a9ccf159f73b7f9cdd2b788d9d940a9f761df8e0823f0c50fcb696a959c1f", "1", .Okay}, + {.Gcd, "-db23b81a3929983317f31e111c33f081a17b3a24372683d8ed6cbd3d2b1262d1a26d1466c97b2641b47d254854a76232bdd76da11a5f6b09ffd579ce64789b9f7375622c8f396d84b963d06051862c1cf9086a717fb8fac5722dd6961075a0769b04b601da6688fb3cbf94d455acd3e440fd8da989e1e93c75feb9b00ffe5d4442c619eca0a4c4a2a01aa6da462c9a5ef93f03d794e84b0a29dc2b6f9f5ab26cf3bfeca79d43f5e5f9c8e350ac978fc02748adc079847e202087ccc23263ca14137e3482e842ad4ad89b317f559d0a98383bd1b89c7688933a2cf19511942ad56dae01f8f64dd39b5c007d166f05211d980563cf8f6c91985505c240e208722887ef0c537aaf8e4158947955f60048c6b46c7ff7ef52d0480416c1ffde867538db2f0338d2465c30d80e6973bc0130ba8712f5a12a87076269dabc71e302f168ea8933f658b62454efc6d98bafdd3af34c47ec86ebfd76b3bac250805cc5df2e842ef77804bc98bf71adee8cf9e53e0f87177a2d9d0654bc5cc4c0802a0eb1159ecd8ae9a077daa1997827974e17937bc97bd9747f1534f4deee3a7242cfe627bdaa88cb1de3d1a0ce7699180343039352e7b137e57d3e3bcbcfba093a9420b37d524d6c88e6403297dfad0ec8f3f187074b585eacc0d9204dc620de1f6b4b1beec46182ca6c1d28afbb230cd66744df49d29d73d33d06f8de398a203c71809", "7831bfd387d19373d669b5f4c6181b79ea722376b1f5fec1d90b1766b64c4c077461255a51e5712461e14f55f5e6afd143ba73878a40bcbb842b0816aecd66c3512f0d55b15aff839f27dd2e8cab6b8787bda469dff0f35be690448726cc636da094d68430b6bfbf945f13564a08b0642f87cbf1b10bb2954eb0ecb8c582dd3e75f6ba60a225fcd85e6a32a3555c31a8017d9fb983c9060fb4c379f1fd7dcc9488e99937b7fbd3111b60549d2c8645502040e986430fbe66ab1f8e81ddc97ef8aedc408bac5d6198e7263415d57d1d8b87bf9a588b7a2c18bd856f266f6570d595321d23ffd103d21eeefaee1c1580cc56747257bbac2dfb62b7958a7c67486ffd46742b2b5e6b65f9081c37e76edfd95318f68c9985dc0b0bfb7a5fc643a1f9ce24d4d11dbc76244f557ab738b08024224af2929c13cd3141cfacbf6da4d1c76b37957b01268963e07886dc82695f6949203ed586e6ef9ed6373bfeed97355db4721a826af3e4d4d40f674e01322047902b119ff98871e4ef057e61ef3471768ac81afbe3d8a24b712aca7e81b521aef8548964f24fbc0b94c24ffa3b69c9a6666514a1c6444f40ea5b4dc0fc44eb1847a3f6e26226a21cf9ab7c50517c678710af9213796200dc3502503b102a3e0ef7f9bd63a1e103b3a0f5690fcad2f52c8dc115f385f3c48c95e0fcc8205b20ae4b8406dda57f792ffac4e63eb4aa4ebc", "1", .Okay}, + {.Gcd, "6ed77b9e5caa9df1f76c392581feacad6413e6555438d127fdb1cf2c7466c4ed306fa625d88a5d9513d725885bec26c36df1d48f64729422f199681fa5cc5dc02fd7c3c7072090ab22a520c7a1b5afe26bd23ae0428bebc1c90cc5fea70ca8cfede80eb64fbc8926ae859ca05c3a7efe19f1ca24d481ce95c3b93f5f96b0ee991c749641ffd34eb0d39e7bdaa6672b613dc690788083ad095e6b21dc4f1c3f6a61d03b04da54c3b2f47f3ce0ae9a73ac3dcb3eaabb0856ca8ec81efe7b2c24f99502de2cf399f8b4c6f0057d3dc001c0ddc30727d59681c0ae16f1775c0d6c7d5a23951997ddac77bfce220aa503395614e1266290075e632fae6c5bd115aad985b63c5d6c409fefdd5dfedf68b543ca028e307f5f53d551c90ae5e68f5e3227f202438a40fa7020decdb9388029c5c336c5f8fc6e26c76f324be32f0ed52950161719b0da4589ca8909b59406596c0ac7d270695534aaf9f81e3f6bce1e7673ddf433ff53ed222ac94f8b3444e3f7466450fef9f367b018dd0cee63c5d4acd60e201d4f7281849b72f976ccb5c049c0f86099c0cdcdc3a6a9f83dad6cefd5efaf1519ee158167d2740fe14160dd6f682637a65153a374fcffcb7f59f9892056ae6463171f4df52d503bdd1c6e1ad50afd0637dc3e640fccdf285992b41d55810d5791e05fb33c5b3d99d2dc8217233c2174827102f22b3e76848e1491cab38d", "4196139501a54cf5b169761f9da4af3267fed4be599f1ee611d5a96875fb9f95d7811aa39e9466626c693da23343f5c4ab83e0ac16820486f85396121676a1a46843d36b1ada578011e4e97b278ebf6b3e8c8c32acf3678069fd61e47c9429baae18ae275b7e9333c926829d05a0f264e06fde92708ffa30217255ffe4c762a77e0733b3270ba0d7936686be95f294babd0212d9c02278122a23083607b81aaa0b72cd116726fe8e3452a868aef76404f49a7acfed92322557378ce4f49cd8de9f977add8b4c1b4cc5fceb596719e9aa0620c15735c11fa3bceee3105d6373e13ac640b4700484eb53df48904f89576fcc527e540446929816a42478c123a59ef62dada3e020f5131715de582bee0c936b0c439290ef8dff7f2ba488d89e4bf94e91a42a0c227240c53045502166a9ed7b9d83565b1ae4b64f7e1a89ade1514a59691cebf5d56f8d096472762ccafca7146af28bd9dff5e821694417147a5bd24afca6db0f1c199120feeb4457447495d6ef05c3ce4497d6cff0c44b478463e712627d21c3e2da307c7ab6cc67d03fc5f62fd4617cf331dfb7fbf988e802ab4b1ac2d3f1066f2580ada468717d2925794c0d3b1c69848bb061b8c1df40efee70bd6e5de12ed6a8d62027c6642339c279f7cd5e6480f8ddedc8ad344f6e25de9863f4baaf68d9ca87101707cfa7faf2bd52d439bcf93782c21790d4920805f17d", "1", .Okay}, + {.Gcd, "ea0a299edc83c70eb98143d6bd2cd30696868ec5892befe25194f6da3e1fcdc68804d0fa0b13c95ccb9a7aa563e091ee7a95d06acfee149c27e47b61c586df8f50b7fcbc6c7dc071950cb38586f4a573f5a1ea45f8ec2eeb0b635216fa07023c988b6035871b74298be844637655384efd997329b2df2fb99a0d60e856a4ee7e5fd89e6a21e565d32e8e8e13be395da8bed1cbdf1142762c1f3b5f89253930ea525f5359c25de5243cfb0dd8f391e5cf99c44867e25b86260537f817bab300433969543b9c0b50e1cf68920d3de47caa3370604a043caab26bc9d7621db68c1a27b21ac98ec8ddeadfb220bf8358cd311fb99f8b0cff5232eb6c7cc9b9d6f86202a64d3371484b1edff6e893e433dd397e09f49961d5f117f8e0fdc98e999d961524c17a92d52ee10d0fcedb68a27b10c70fb75aa402aaabcb24a7eb564fab2aa4522fc111376ee5ef99de01abe08b416aa071a7b5bc52d1020cf348f43873283a0d420dd3ee78dabae7d0617b169732dda7472b0105e3de8a9456deef81715cfca143864757bb55318662be33ca23407074f611b1fef1ae395a1ab8805f62a95dd028ec8615ad4bae7ed007568810625eea95e32de9705c335ba36180680e131bfee980148f30bbbffe53cc997c0e480c2dd61da46e438d987c55e5c742f3f96791957f0f0b54854d56eeb4b38eb2c8bf8dc5e456cfce663f9d16a2e169658d", "72950ce76e4208528758e0b62cd3fd4f4c33dc0e24ee26f722ce92df4c9e1c5da57bfbc45e3d7293464488267ed24230b82acabf6e40c16139e6648cb95a862d5a64eb3086215fb04adad219afbe60ee0ec7aafa2ce28d763d77470673928375f2c119f3e7cc8350109d0074176ce3b7ebf9a2b9c81400a89f57384149389277c52075552940a8b941274d8deb8aabd69353fb544e8dfd0098717b3ecd56a7aa7acb787aac803c107b1f11ed226c7029e179bbbbbc8a4b4c240f95b669e4ca1b1c78da3c24240d8363d49b3373f496588528172f8d33702fb3df254beb853e595c91c97bdceb9476a8339ae653580ae01d51c73276c1c3b433d29ff36eb6dc0a67d84494bc9c33785ec3fbf0cd22deb5c9d6acfe7ecdb468fa59e3f63f4253321be667adf9202557b46d168be34e6ad4c1ee092a3d3e85a5cdc9d997c324fdbfb563ac43bfdbe91fd8bd9352e9350f51a65c2047da15fdf75987d61b6bb72aec87db343b4772645ba2b330fbe72182bc78e6547b262f490737a844f1a2520dba7ab30c714e4bef8293b787daaf7bb36151cac39ff1715cc2f06b18f7e6dcaade8e2869bdc43e305a43d2326f1b8cf481d984eca6bf06bb56e3badc6962858271fa769ace4b17bd2f96459a8d1cc7b5ce2a134f9e44600f1619708bd8f3cc4d10c1ae9b6d10acf81ac82a2bb2a68e8b4cf2a6fdf9af79b9efd7aeb8a73c156d5e", "1", .Okay}, + {.Gcd, "-557e781a86c018366bc521aa24c4c310378bbdf2ed0fca610c2672d5e96fb2208a79033aa4d20b745e0bd236dfd2fda7b90fb974aa3af3f478a743fae130171086058fdd0f76b927afb5cb36401c15d7019067cc320193cd690001455c0874b4bbd09e687e9fd50576750e1d9a38820f0cea0c0d3f977ea9efea0e0eaf55fd19644b4520699fa57317b13609777920afd47b0be065f4e6695b80be5e5cd8343a230fd75fd29141f82df3d5783677760bff154a24f27d371919c684d0817bfaf838918f0e0265968019a80de71ce54be13a79b0b223158d8e780b0f80bc8f63b4e8c9d234d997831c73bec9a0fa5668dae82a469ea2b588fbd4d9fe633f8bd2e3110f14c0b748087e3e364296a020c0a8e1fe061418f3e5fc85103f4c0b76bbcb2a5b3f88c66a826b0f9f5304ef52c3bcd08782b9c5db81ca8aceb31398d7ca7ba6cdb68a86dba8cb0086f86657a0e27cc9ac27e64551f233a2b21fb768dee8c6ab649f0d1829721077cd64a242fedb82d6048ac63b140616cea15296dce4073e32d15dab5e6ef42a0a72223bd2fe3fcbb9438f8a278d5bfb3a1b44f02799191741bd98546f6cedf78ed6c7bf91cf1bb7fab0adda620b6075f450efef6c982a2bfb1cd1584c3888dc59d18600ec7696c6fc89c2d525923c81a3b032cbc0644dc7ae912f6601d914c5fb42a81c500e802aadfa85fd2883c28f8397bdfc26fe41d5", "2844e3582355dc378af50f0ad969424d4fd406a6f076fa96e9224a6ae905e481f6555a16f0522605e693aa0b4c01756c0517a309cd04c91008c5dd512cab61ccf40db0ddddf18c57d7771a68c6fa8bc72c62099c433f0abd5ab1c63ea7e58015b29ad356a06529d9c86b821611eb75340c29a6f6a8e5d44696ae2c40cb46888ad20f54f5106b7073894e5e323ed2a7d6710fff36e028b73c07fa77f5c4401e59dba836a05f405f16c879b52fc3190803a46ccbde2686a4a95b9d1700c029bf006e99f708e55f922fa10ad042f66f964284fd03c38c9a21c971c356e1f94af217766342f2109c6de4041f53adff2907fb6f463faec3420772ba8ed834a6c25902ca5588d8e4666e062d7d735b2ee94faab47bc7420230de041a749c0e6cc7c96f49cfc3cb897deeff9e50d9498a153a35f1614893b6608dd4948af1f41a5fccf26b4c0323e2fc3ba443641baf717082dd84199988be79f32c4f2483164dc96c8614947d6b47b4ecf84492c28c2dad688d16234487517e26d01c98f948ee9b50ffc1d60613e143f13967c2f467fd6f10c9f195a8eafd8e165e15b9b3328a3a0ecaa2c214904325924141a17ac61f6416b0907e07280b3b8ffd6ec0a38f850ca19846829bd8c1acb5bbe96bd84dafe63916285084e9823c41501f9d23ad0194a047fd121bd7d2cd4ff9643e61e2b3df70a7c8739623e822dc8a66ea693cfd90bd36", "1", .Okay}, + {.Gcd, "-496fb467bdb2b8aba9dbdd5ad52306336b57304783b61eb19a72b47ce31c0f9590629617bba5545a3cacddf5705a6bf0bc6f9c4008e9bc51cbf69aeb68e1fa414b0dd48a62c93132d74a26bddd71841b3aa7d05d6c5349361a4db0bc456b3af02e78025edfeb1ffa4d724e4104812373773aaf3acdb5fc7635c1f946ef88a643c238f4fba5ce2bc2630dcdf124db6515fa74bc865908c15f0481e6ca9c2258d937cc875b0256d113eecd486f6e86f822e5ebd6688394157e922b765d0b466c05f55b160b4ef0f1bb01cba93760ac90d27646cc1574fcc34369c36eeb4eab45749cb954773285e71f01746cad271d6d512fd7b1ee5967cf50a6adaed241de575d232a43363f338c2e44bfb56187db2a8f04eac57a7c72725dbdc873146c80327bb135036d3cb3c2c1e4f6e13b29a1d857cc1badc5703cb9b3a1bda70daeb9fbcd4326623d7d8a03350d5e64b6a094d5cbe6f6674e57f859f70c20bbd23fba25f237bb9da3b7da903f98ed31164e0216f9505632fff9092b7898e0bfbe529959cc6f9f3949b164b1a46aa50485029fb246f4c576f4dc51171bd2602574e92ae86416c593706d0d9d10cc16588a756c2b71b5938b7d43f8e4c46ff0bfda068b7f54c4c8632246d8d97dba57f5bbc3035ccd5c5d87d70098cba479d3fe980ffe3bb938aaca61df97ac543fc8cb164e9f6cc2641992544df04ce3b211de621060077a", "a8c8f88855b8d722bffb9ad95c32ae160e7b7cbdbbd61c5a04ed067998c62c9e6c67abed737fb5feacc87a517fe5ebe65c8704b09cacea131ea4fd5091cb16984edfdd9f017fa5beef9b6bcd5e2c93007cee23af147243cd74f85594c81896808860ba7bf04716c2ca550c98a2d85293a4fbff191eb42bc7b266380a9a923d1d3ecc0ae1db71d078a7d0e0287219917e04319d61e555ff315cb0c63d529213d7a8ac03880c764612f574aacfdd3553ea6068619ed47b4095e886ca46f85ada52570db375f22fd96c294c002987a2e6449ad4ee51fdaa4a49b896e877452419d6f59f3515820d68261076a05b159e36d2bf559e02711dafbdcca0d2c2062f086362a06522d952a2a180cb3b9c13f817e43d52debb340d9fc898123135951424c044c36aef25367805b94659b29d8f372f00fca2a037e7eda48aa785d358cbda48f79fb3951cbae7073dc97f43868a4aa7e4fdc1629c289757001c23943fbe4f5b9e00bf89e36273a4e0dc823fe3039f03b8dd22cd5eb1a43c9d6df89209c5ffd42943a56e1a47a6f0a1c9eace97d961556d33364352e8592daac1c6b2970125d293f28ef3bd7cd2850ced34f5d40c3b73145fd74ae79cd76d925d5aa1cbc32275fe81ffb46e426fd6d0fcedfd22f7961ea95dc8ada2910c6c41c9a9dbfa7cc410ac9ea9219f8d360832eb18b783b51686ddaa4d051aaa72ffb258cc740c4893b3", "1", .Okay}, + {.Gcd, "20c600e0b0df947ea315804393014feb9bd01f26211700febbf0a91179b3892e70dd8a5ff8ab92c2559cb5383016825529d10eb85fd1320ee334389d87a9b26fe1685d22283710aca1b46f3ee0f6eac157525a8c5aa565946acba6aabd4511d0f1f87ae536bf3eb99ab80d0826b197d77129b891985accd72d79db8477d2166ce887cfb5cba75eb91ed591c7b07722026620f965da367c88b80151b558b8db4c64db781abef795e68b15d363ff359c13e2c11f75484826919128209afe5c4b572dadd97fc20895446698b41a2d3beffc33ac772fcd335d3761ab41918fb1076588a119884250de5ded638848942a82895c0c59cde91f054e143eec7db6a9ee3d973fbebf1d014ffaeaf19a8f433ce680b3b2751a4f72d36c9cf61af575b8549014db5508df1b7742cb9f61c176cba0b2f98d4d48b8a2bbe84dc6b8cd1ebd6383b440501ec66d372e0fa8550357d4f60a10d776ff81e7c9ec02b4e62fc7ca58ae03b910cf21e4c5222674f7ba4827528cbca1054da515f1a37d3aa713d2e7244c0d61ad2bc47be6e7c46a45a13cb7e80c0577273c719c6b6bafcc8aae11f7c8afdc6268b54a04d4c0c7d86ccd3b660bf3a7d7942c0f60caaeb0080ab30ae239dd80a9dc3c86024eb1095e50ecfad9d2d4d5d3f7a88a56379a84c66e88a355a4479904d0526f277a897ea61ba06ac863da7f5f2afc423f47f596842428e37f9cf3", "f2057c7dc66150980efafe9265e02f0e09630be92d670831cf040a73db59d8df0a054a15b289a27b6be660c47205e69e78b9a0d3672fae18b3c61c6d1eec611478f1428ecb37e2c521b1bcf538c46b4b9b177c297ca4cc177431ad8b8d451b413c0059dc078a0be3c834f8c7e4d431d96c7e1a043be46fabaddc221ad2b1c35fc9863c26ca19e6077723d691633b9761fae0c0e994877a7388d9942b6151b723561e15ba6a3842c679f48459d89bef4a6dd3107aa391771874bec848a71a8a14227fe89147320f18610e622d6b7d78acb840ec3ea3cb811f40817b20bae92d7b1f328ddb722145b7c6234ed059526e3abd2e09074bd66442c6561c2773dd1c25c66d1bf21e34fce68e97cb5e1f151b0dfeb69397979c3cd26b8a81fcb51fbd0319bb090175c0bd0206981639357a120c302ead4d246ad80011384ed9a39b62437dea8854b4b9cc7ecd25845fb916ebd4462affc01dbc4584d40464807530ad4db899960aa8476148993dca8b58b1b61c1e75e1edd6d64f5629e12a1ff31e190b0fa8fd21158496e9be0af5a0125c205c9ee9f5fa3bfa21594ea883086ced967ce17ffd2584ae0a8918f0845d6249ae5fa47a9d8af99158068d7060b81ce10ddd5a5e4616cf7bdbdaeeb8ef357a7bd57ff3893996535547033fd65b41a29fb2e2f9a02f4b12785d4ae03c9790d4129276b6f289e2d11668eeb0707e554b84db66", "1", .Okay}, + {.Gcd, "30be3c560c7790a33dc9f1e22dd56c829810ab3e9bbc369ff81693e2603316f280c4963883b374729add0bab8e52de106179f044ec73d901ca78ef51265932081f758309c69a5b95c174bd185ed5b0a3423ce3792d1ffb0fd1cc998dcd51029338d1c0c98c38a92fb2c805a8aef15333a118b5faa3aba0787899a54074cbcec2285016fd7abce0387cd470788f7f0da4f2efa0100ebe7d0e2422da979818cdd8e65f4817061ccd6514c0bb686cce230ac0f272f88cac221f7d0f16dd3d8e565e4be53e7565aa79db7bdb02ff8862d24efb0a65f0ccf93dfdaa488da858d38c1a9d6f7145a08e38d57988e3eb03587caebd705af3c377367184ab2331df1ab23d92453af79b8f537e402aa93e55b88f59baf4845e9b2d53fe24951f0aa7e95dfb9c7595eb309788730ba8c449f9191715bc8245e911aa038e72facd18fbdd4232c72456931b8ab7e8cdf9bc8c2009c7a293da3401b3c51e9a50bfb3fd84a049fd056941fdf41b6325a253f956e12cf2855c140b29b881f99743578ea380c368310bd8a77b67964724430f1c913aa9b17e25e6b5c4b22b75a370d33cb5ae1e1c9c09abb21097345f0fdb440f240f880e9c2fc490eee082d65888709c717c1edafc59b234d657410671cce2d4db75aaea0bcce9c097e07747c9423272b79667c47e472e43e58dcca74eaeca410cc33192e44c4315e34bad63050d13cac1702296b", "ff6b549ee5ef0f27a55c53302edfa8fbca439a0f3822bed4e91c77e77175fa33571bec53fce89e3099e74054c6f94f22b2b88f907c2e9d05aaf74f34ea07997f959fda4aa797fdec32b831d9863c68979c8c7521aa54a5971b57ad31619c55d22a03803be5a5a6f5304aeb51b2a69dc93c37523716e9698d867de045b6a05b84d32b39b0f0d4c188db381ce5a27f3c88fbcd320f402b9b9cec444b5be8df2f0953497cc5a36d394891f6fb3cb656830e84fe6ff0189c68c8b0f7bb9cd83275e9b3a9bb19c60ef18357c5eb937f9cf50859244695b0c76884c42162c35af247dcf26b4b5559c6503158a7761f77abcbd319ae1f38bb6506662472d36773e488b25fa8e84ef8d2947b8320a0b764da699b14fe8051b8a09dfc53990835859dabf30cf00ca8e6c153516e086dd6f10501f1d4b09c0064dd53781d83e5087c21af7e165517375e1819811af0f0d0d01c6b68cd59c63414fd6d4c7cfefb4ebab9bda6ff2564cf22f646f7892310c7e08e6fcdfa1b93ebbcbf34cc8e5d6c4ed6a94b2448b964e3d9d2be57538b1927e9f73ecc4334fc282c4aac882de4f8b1a4657f9c149aabb31033bd33dd384a975acc8a3524a8c22fd920bd2a87361cccb3153a7a739f5c7f9ac161512cc19416226db47ef4250bdea14bb6c1fa6326faa1ed74573ebf94dd279b9ff66a4696032e9b58463d3f19850d40f5050aaaa3a67fbffe65", "1", .Okay}, + {.Gcd, "37063a69ff76720d6bfefc04bc39d443e64efbe268a064f75b741a81ee7ddc0adfcfd1380ea4d7bcde731bb24cefaf0fe090775c6e36a18a9e8cc78fe9b6e10b32c31137d1f6c66d7da46e51fd3a19954f9e8a290410dfc4b107ff041224b7500788bae6b4b1ad3ed820e85a1be4fc519356f580e6aeda2c2019932d37e06286a56c0ab29c7efb65b0d35236743c13bd9e507a374cc8f54eaf71b1098b0a61945e375e1594e3f01f085361738fdc703c543ca80d983a94ba4d536506b613c9596de3dbd724073498e3ef69391c05a0f20e13dfe452a623b151006c990ada3224ea2545d1f4a157398f71fad613f21decc9814b3864085230b4e934b1723f03ff36def4af9bd6d62ee1a14c4c66ebd6104a4315f3145c9d82fe4f868774b981116731649e471591fb4eed48d4c33374761813e89ff17bcd8dc7e4843c96c4793c2b34043e562d8d26d6bea760eb3ee0798afecd6c8c24d0815eecd2d599d3b26de477cec81537605a6e5aefaa0451c7ef5f8dfc5893958c7d61640716d52d372039c20f32d47e03a081396e319dc16e891b9f1bdac3594581dc7b9bf3ae2f0a7fffb57de4df87deac779c0a4200932c57a7b94a78b052ef4728411b708cfbbba162f27dde00248ee34f31c6a58cd0121ef70319780c4a9022776c14f6fc467cf77db261cbae9565f20ad1771e3b8c7bc6c8b53b7483299e67f07e1974ade6e91c", "9ca4c02f77d6c91b48c76180e4d98c80e6cac216c326f403143b6ff4611294c0f32b2cbb2c77f5d3a911b4f89a88c36816c5cb0b858f48bfcec6961feeb00a3c42b62b63630b16f4dc7ea37f825c30c59c509f7047bcefeed13363e5fa785f2d4bd12433d2676e77176e4857933afaaf54e53cb9b37b79650b1f4afee41c21021f2166795db80479d327d5cda1208020196cc96a8edd7d3e139abb5c2b2cf0d8ec00747f661c6198dd8cd2418acbc14852e5c0117074fff6ee117155cfef05e40cf17f6dd463bfe49f7e97290f0bd2087e83713bf14909013e1d4939f450f6ed207a06767b15e56d5bb1e821e2e36298601b9d5d8fd47cc0aa793f250215fa8b9ef3ad74fe72b5d6592f42a612d90ddc65369d3d8e5640003ef7498f28ea3a67f327570ee916e4a935dd89ec18c24a44f71eec8a79e78c7a30cd2b5703110e65b5dd2902b1212ce0dc285bd4ff4d904f003b4546b31062bbfbbe9047a2df5603726c7b83ad83b73253ce9334ceb6499cf47e9a1c157413768215eda24dc4a4424e6bbbf47664b7b7403eeff3cd2b6b96812736d1a70fcf781598566ad7c15f2a40bd51ae3bb33f7e7cd6eec8a6d4a53d40cce0d71cff7fb59c98fe67eecc8d31eea7a7c31aa102783bbe0e3823648777d1472cea5ad0ef9ae234aaf13dfff015b33e28fae1970baef71157537a5f162c3b86ec342a389239929b028eced2f820", "4", .Okay}, + {.Gcd, "179440932854560b3c42d1f04e0e8bf89a77f30e103d3fd08d7a4c265cb8a0afabeb1c3589a3204b53af2f867804f23a8f755d8a67eaeb087bc64d9313c3b7a0b8cc2a5ddf94d6e7d3c26221b024c4a14dbcc41fa077e207cc6ee763cb0a1abf79b5fbe0dddff6367de6ace8e9068bc07fda80c6c21639badea5fa30bafb46e912f5eb7cf863ae5e84b976e034fed23d0f5d6ee1079d7d40518b055761f65c8fb92e413fef713eba5f7ea79dc4e6bb798bce29642c241b17aba27f172077cff66e026a3a483d55ed13e0603c5f020673b111116970a64e848d38f95d6f43dab58abb77dc508efc7335fb9a08318a20c1215d0c0061d9f63aff4e6efd6e1c57824a917e7e1d4f796b0f6af7fb230f2abbd0d8eb1385c97fe1cf8ed7b13f767f05c2c6ddde3df8e7ecb0ac7c0f2952468ca723415cac22914a78700d2fc6ccd87eb84a7d418803aeb71527cb5a27f61697476cf840a053f049f82e8b01e25de810b7e3bbf93bd3c9d1abadb15f1735dcefdd252337f508fdb5f4af9bac6182802c6d82a8b7e2b524d9c2264a6077291100cb51400416ce8390e82fb048fe474de0d4eb9fcc23fafd9fca2b62ebbe1e4d80e58e3293b48faa70e424b9f1d0c31a5ba0cfbe6d398a73bc96aac73303fbeacbe13c06e54daeebd1a960248fcea0adedc596df0f62c7cea2078158400ada6496277160f7c0d19c3440caa89e1941a64c", "98df0ea6a09dd8b8910a451473599b861b279bc62253659d0fa5ad2a961a388f9bff4e83f459dc9295cad44407b92250c7dea594bbebc9f2267ee38e043d9f72209dd2e18bc4b75a7356c817a7a4745c35bf7f56bbc428f518de3e13e78c62d4ce1c493961b804c6090540f6b3316146d62c16d558396cfc03f123db7b7cc1aa1daec4e2c2923d5e78cf28bd239fa1b7474a531b3bc580f32232700eb033b2828d6555e638d632f5a618f8da027721aabe5790cc82d87e78c3b34a77e0f0f8db94656afbbdadf9a7102af148d532d23f92014bcf33c1b2b7070bb5427a7c89afca644c59918ebc2bd754e245e41c1d40dca9e63f67fda04df646950afc65538bde8b6f97c1b8cbcc481d064de14af4779f7f2198091ff45cfe4147bc2c146bb4a766f4dea4301677e0ca910b4e19479dba0dc3f8e433503adaeccfb54f5cf325a9ffc1986f9737a9b54b01044edc92ca4eb88d06e636e56f1f92fe0d6d13f7d2784f45514cdbde5caa7bfd4cad7c6602a4515ed2816592a8964556f46d7eba1aafe554ff5188bbd79f47236da0268e4cffadbf9357dfdea3c81d8c2f4044ed21ca6e82ae41f4008298fb49cf31a6a870d5ba61526125e536fff5add3b78b7cb34c043de170c4f8d659f96540d5b82cb9512d6738607fc1a9b8eb7bd5abae7f3c25085498dd7354547f6d25271ec4dca41fbe082eea92a49034c7c170f3ea0acb", "1", .Okay}, + {.Gcd, "-5722963c4c484be1743279790e0900528ed16690f41247e4b223bce071abb0d782227b8761516f7f1a383901c50140b526b7b22aeccb907ff7354f6b707e83c97ff45abbb0ef91d7d43e02f53ef869f43ee812649b492b48b4f8ea007966ab3b6488bbab7a295a881d08283ffbf19d726797a43328a18aa9444532f6184ff52c5dfdc5beba6658e3681d43c3c7b0ad0d9416b35bc1a9f728bb459fbfe8ddcd9980a686d40ac0fa666345be5d47dd1ad4493dd6d3a05eab56a6dc282095257e31b6b0ea885e9e5415e08c841f9c96a648123a4ad6553cc029bfd7485a03fd03434a657fb31ed71c7f5cc1442b3f8f43b916dd8c1837feb711cec476bbce1829c0aed3dc5fb1915797e112934008407ca5c29b1ac5e4ef3f76362d0c24eea3a02009439b6b89357e3db6a0aa5bcb50a3e45ed3d2ec3a728dbb57b80a3dbf1235f2530639629b36b69f8da3673f3284347d06f96cad581a4b4878f769201648eef7c85fd969d98dfdc624dcb348255fb981b8322d6e0e514661606d85e39c74e95e1a7a2ef83614e2f5630cd849cb8b1d64251820a6ad8bc917d2182b4deda65b7331bcf0fb3313027aca6b5425c03d078bff81e982d6444b8c5b1694f2f7b019eb28d121123361f1d6b4ec5f076ba56794eaa8a91b3dfb01ce653af86fe7e1fe2d76b4123979b690d1bc33d854c6f579e6c14f2a242aabed6b91efa5becfa0a5ef", "4732ee61abe07c26fc29059079d1103cda26abeac0c632856640c0bb603ab5309c7c71646e178d047d02ec5866b7c29125055c9b5f75a4691ebe4b11a0024e4e05525c07dff692a5a3befdff98c1ac042ae0a8ccb19b8da915b4335a66a05c7e637a157ae817ba026110ce7950012df75a167a278cc420aca457a694fe9aa099378f50cac9931de22c334df452bbc0406c9f0fa2fa6c7d81e0c36791b5b1b217b2f85ebb1c86d32e6af97f3664f416485c94a52c3e6bef2c7057416102df4d784e16890d93487110fb133063c3e370f81064f4f354d262283f734b6b674fd6cfe36d7abab33ed8195238ca4407bbec16f8f06f7b87a8cf81a96682a63d4bf7ba1bf2a87be5354c008118def3c956a34f37ffeace6fc87ca208f0acea7961df92bb5c3989211a4c8fac7639ecb70e1e5e4cbff29d58e2f64a2ff0ba9619f43a2c7a44ee78e5398ede30a0bd982fe65c47bb96911eff8a583abcf92b7c4d2357b070a19fe1ca383f0edea8abd83b955bf3df8838407eb89386d6edfb73c5cd72330a66bd6c148923a65ba74ebee5b1ae7df99c5d586bde9b09ac21916e96e5ac8694eea07dc68e43320032518e5185372f33e4262957ea5373feb87bd3c7f138c451967ffc5219d3241a28bb5531fde79775577d55cb0e4d23150fa64ad901273da96660b42d4ba1028aa215355944f0530755efc7617c5d7096299c35707a34b5", "5", .Okay}, + {.Gcd, "-8130a2d9bf2ebe22dc096e730418cc23dc109ea140e1b05d5a02d9889355425abbc049c5adf2f8e3e91f9bcf1e6779c0b0e5feee33bb925585fdd5f1409b8d6171a4115b8a35599ebfbd19062fc0c5b2cd992fa57c5c314b734181a53779f9d5d4815b474e75660c4c2f87adf4a623290b2dd7fe8e7849d62cfc58032d19731acd75bd03eca263be50db1895ba18cb4f0600a235b71490e3424a56b8b8a554182ba65b9e96023f6c61ff2b69265dadb2590ab58b4f5140ec83fb62592e4f5f51d291b80149da50585473a7c0d94f0d8cf6ca4212e222b92b8da8b271931d7579e5d10d14175153fe4ad1ed3e2be9b487239afd016ac848c180d3d6bf0da9bed0780208e9b501120931188dd35942601126566f1e05d8523771cea047c46e173c3627e87ca28239b09fbf33a4bb5f9394ab30294191b6d9c8d57f9ffc0053e61cbb4c8f7ddbb4bca022525f661f4d1ee7a533b70604a72993edba77cef1aef19ac4969882635616b9040e1769d9f1167c31c811e013cc09eb71bfd24874f6b72c0cfd8be7a8a518826a6514ec5fa4deb1bd4aebf610fc63c3fca480df7b5e3b06d1939def51bcf9a9220b3b811e3f3dd6f2d75b5564cf5ae98902276d651f550128ffb1613b79a228df2ad63ff66979cbe6938f285ddb7a29d3a05286debcaeac32fbdff4bbcd378d80a95c6bd56188d8554fa1ea2283f8fb38005b8f15b4abe2", "c79fcad595f4fdc994262cbbad8840bf6ab24b8b0cb368624b4d6804a13e83c8fb73413a678b4fc1563a92150c3757a6dd32f2ca307cc01e3059998e63f09dbfe1b528639d11842d267b46cf56677bf12aa3e5b3f13cab2370ffffc1bc3ff62603ee2fee200b9ad66a04ab41ea610beefcebf20bd5afae93fe73a6790091181b499914de163d11ce0b9a21e0e3350f2d86ea887ce7412879054677bb953bd53c38a37268dde7f50c2edfc074bead0ded469cf495773ade13f83871584807a5682c92379abc67c0a6f124b91e557180724ab5b301ec388c8e3c8ebde9aeeb4b47eb08f6ae59b280095210ad81b923d0b7b3e2ea9e72bdc1ed1dfe2d20914957f5be8c99b3641b27b4d4e3bf1cf02cdf60867a8294dd6b9b35cd1e632b20fb859940e7072a698b7e3b7317e3650c27c413842f81236e6fddb5bcf94f0d94a77cb3a0b6c96227761c31ea9d650434c9cd430197920aa423018afd41bed6d7e0f09e64c9ec04159f07b5d818002a11f7d0f5647c0e89559bb2e89d6941490c2655dbaaa4b029cd5d76aec7f86875aad9c509ec66332c2b27b4d629c2d5c6edddf872c7f2af084b161396fdf6efb7b338bd4a00c7850241c769999b9f10440576c7d36bbfb3d4ac033de0e1668649e671486a2f5ea92cfc5311cac4399f86cf5d1feb5c25f17bbaa459f63458db7d6669363d7e22bf1ce6a2cbe8ab36cef386cb4efb", "3", .Okay}, + {.Gcd, "-5aa7d0d111dce477a687d0a3ea0e3bd75a57a495d11abdbfbdff6973cafe1c38707606ecd16a382a777a1f4058d043fe3028e0fbfcb7f4578dd2b9097b8136e20d659cccc92f0b78cb8f1f9667ca29959311d10d8de3ea8af54f76116450ea7eac886345df1e4b76a394e1cf9c9dde7ba1a9e41d0f3946667433beea0cd06ef4d8fad749aeaf47b84d01dec3768665cc5e95baafe733f6f74e91c0779561c0ff6c210cf8a604036108b18cb42e1088a2158041e18daa9c8cafb92558aaedbd4272e78213f7af7ea24e54c740b7e8eb0ab7104326cbf9dd89e936d3bcb625480b6df214bce08906d753fdbd6f6d629086a009ce72b4d6b4eb694db981a44d50dafb108dbff472fbc68fcfebffee4c982fd85aa22a3c38faea483f3cd55627f036464be66be6a9e491ac69cb929e06b02e413e1e95b1cd4b31896ea8b24cbbc44af5add0c820dd8f05c85211a1b5d678ddd9ed5432ba399fbef52501a0763936faff9eaa55a11b441cc075bbe0627fd94a1fddbc5bc91dea05aa8fa32b892b3dce8ff4afd143031195a16869c283b128fa5558b27ace0b49c580a386b60c8f87f905260a03424640a8b004d626d179e818e529ca27ebe1db8ca1d6b4fc07a301b280697231560e311d66e320544ce19bd6a245cd1d74bea2c95597a8470c6705fbee8a27ae7bdccc3cad41f9999cf1be3349243a262f0faa12fd1202922696b858", "a278fd8eb5b94a0380b4e16b327dfed532708ed8f95742ad9583535c17c04e17dc99ccf1e94f508883ec0b836fc03958640c7a285bb9103f89b3bd7ef22f3697236cbe500c1945ceb97f22f92b30f4a5c0cc2ba96aae4f6585ebbcf1785c9fc95d50ad49a4828dd638b9023a6f3046a78f5cafb292be3a5f94d78a93726e26d5ca708eeac6962a31b49706c74e82d2145284c8116c54caafd5b88a08b245d48c4be6ce948e3788d12bcb4ec072d014c7be9cf3d1797a8c464bdd177c7c767dff3058701a7cce5cf99c962e3c17c0808cfdbd5e4e9f6d1f7a03c2556a46c69bbf6250401b740bd66e0edc3b0921d0e590f741e925949a86b056e3ca3252c92cea10fd9220d7bdfe76ae0dcacfc9705f4ed8df573be2c3951ce4b9cf9baf48094640b6d78496687bd1c7ed7598d81f3809126e1df6d172ef25845798c27cd69299a5385ea7c528e604d0c561c90e609fe2dd3f0baa9f4613312552e4827118eb7f3e4f0c1749bfff4fb130bb5e22e9952a1ec8d19b67950a8c90575b90894479c7ea00484a9ef381c5e63b1df59d2d5279871958f955b414729f63ec1af1a14fc2c146140ac07af48c8ec9aa386a9af88516ed7864e4fb09d06e22052e5f7e1f22c5c6ee85c22b1df369f7287026b86a509a7f80fc483fbef341b5e3fff389bac7f383463edfb65b4382d186c05da505cd0d25cd80e0c224412858e19664f6e35d", "1", .Okay}, + {.Gcd, "925ee6f04c33028698974346914d08752a54c2ea1f9abc9b09eab5369934f72b163c2f441612c4f8bd8f445d805d37eec95524c4dc7b2a3d90694f52ab8044530cfdb27f0827d5f9a0bc16dd5782c14ad31f4430dd0c07a8cc30cc3028d2c74920e7628abbba64f27606a4f7e6acc7f470f8b1132738cc58e4358f3577c7ce27d123bc9908f5283195fb7a7e5bd56e50ebd92f9472ede395f070a41fc5b88b4a805e8d0d05ed056f3f666caa00451e60904bcabc883938e08b3a00f88902682fc05bf5b951a3861c175cfd637a261711a3592033bc87656a1e1e3042dac0533daaea9c6a57993bf69630f13f752a8894e6a7a0d4daaf02a8d78637961e4ff5152109200f2dbdba8640e04694701f26b2115b96b27af3cd5f27189ac293f76b2b427477817eaf30ed007c5fcc896bbfd9201cb3e9277b1a91f74a4ddd108e396caa5994abd5be57f09f64db81ebf6a2dd911d26ca8d5ec08a2fa2e6b01c2f19fea7f2a75e9bcf11eaa1bdca6c900dde66284035e836c8838a0ec18221cc24160a7ac3754930640f214dd5b6ee82bca028a88b7475df39be04b7514e70392addc08c785739fa273f7687304b1cc5b79c2d45cb718e95cc6fe5939e87f43437c3d00af793b092444e0e86b643a925c08bc35b269b0aa3f82fed921db64a0fd75f7f391715508ada726d317e96aa38194b739a1bdb6eff5072dc97957bb081668136", "ecd192be13b464d123fdef352c63c9fc6fe40f44007ad1b98ba860cbe8c8fdd4a28061987870fe7d8d28fa927a9dd1572563afb6dd899589e0ba34d03cb1d0fac47ca6d7c8872279b0c61f0372dd6b1094faaf92998d472bc15beb682acc21706bd6855ddbd5a7211fbc5d9bf4a46e0fb1aeccb758c8d4c9b22de065bdc4f56064a93ef38c2016de82ec1c057b7feb4dff26c6013ab7cdc8629bb23209c2c24254706a544df77adc46b518d0bbd2bdd1748d5fa34a5ff1b66219009d15a2e4d670823cffc7baef77a8eaa305f9cae806c0ea8aebc5478d75e538d9683a6db084a54cc0e883a494af1dfa7a65a39ea320b14383ba40237d89403d0c4ae049d6420441dede1421754c2a988fb596725b2dcd7658b5f0e424d0657997e009500b8839fdb6327bc9cab1ac57d3047635c984ac87f3234784e177efd621580073f0a4d8943d0ce1a30559beb249ec20bfd7a0c9bf8dc4218b08a6014c73fe7b27c6a6cd70a03960e23b20bdf913afb8964818f38955f05607fe76c68ef01a6af5cc7f785f4fde08d458f8ac349778b8bfad501d37a642411ca68217de6af94b943635bbbf39c0565b9db926394b53600c011de762b5c759a901a5303ad9ba62dc84c83a2f58f0bdf298225016c95f714ade977becca625e300d67ec5e3d33507237fe25605c9a3650434c7f08cc73c6ef4e42235ac2f6760921bdfd03e60f30ec4007", "1", .Okay}, + {.Gcd, "ec6c932661b2c3c8e723a091df333780b9d48455d068d6ab07fc55ab5f6dde50c5ba2677fdf3218a44b0ee9ed5a9c711051107918555d19910a8516fd7d869acad79f22fe1140e907c87e90b8afee98de9fd4c84e79b6644a1ae255a5926659dfe14f30cd60ad5e8c18876f4dd7b2b9ff2c03a10c1074d4e10ac05a91ed7cff7d63626acca4bc484f805a2b164e7451a22e8223d90ffa83655c4b4c6e3b22f0890f15419000f9dc7383ee67332958cf49817714fb6d4f71e30c02cce16d599b905a1a80c997a31db6a99ea332e13d401d6744b4a10965e9ad7eedee2f43e0bfe9bbeeca3b879af61f4183977f451ceaf18cbcb5370b34e4108f9305ec8b4c97e57b32f778fbdeeb189f509f1d76dd5d1be15a8f7ab0611a5f0f2e85a9b9efb65c67da96565e06a2548ef962bc375776e58337e3bed84691fedcb48211aca300b843558642dfac3882f8ae77575fd7afacc0b175bb1b25169f0ef39d2dabb3b2478d22a2082a628500146271acfe44334f12809ba9bfb052e92ce76f78cb0f5c8eebd5c509b131c515cf53cc2d8e873a759dd00553e3d1b0227a685f6336ed8d391aa53534f2764a889c8cb48ec5ce846a1cb3b634b7537aff3a9a03fe08b436f9600ffa75de962994c8808b279b852c4144335dd3c56b2075931a458276762090b66520e6b8bb092c6904172a1ec74010823488aae8a77eda3a4b52ce26ceb1c", "3a983603d251bbd8456795a59575cab33459c626d94c7d4a86fce61670afd4eb6438b893a906374f1fc1f0ac26df255e9dc1b43187bca25a37523ffef052247d4bf0abe8bbb189d58a2a0f2520d058923e41f84f97620ea1ec4ac88ef9c51e1ea4ccb525cd250ef505922c306e2ee2fda879442c59f9895cef8a367b0bb1fbc35eddc83af485dbaabe6ef16ef415b4cf5f6a7143cbba6dcf6e579cb5121b7a77c81bf1203b209faad9e4df5e814ee48dde63a6587404571fcc161a1c68f678840777ea8d268e108db353f5c175362f4d92e86dd74efb59d7b573b233e2c24e7553a12d2d8ea390e0de80b80fbb2aa97f2f558660cce1ae3ca2e3c379998bdb1c96a06f32858ce28426bb30b7ce20b7e9aeb34972fce2df5eb05e86e9f27d7af8f67b6b5e14577b3e560cfb2dff14081a922a5c8816b73fdfad15d4015c37e69cf51d713ccaa14608ecaa8ff876eae12f3f554c5f6aae1a5b02e441d11252deffa53322a3e415b24e79eef0841173b7d3d89657b26f7377de6c9f8e4dc0af6d5dd6b393470c855dce9c422809531292519a73134b0e9fcb8406d6565c0818daa6b168da1366e6d1eb8dffa555ff1173798279d6e4eb3ad1fde42407fbffd4760406783a46a22718ed81da3a32792e4fc82e51436ecd750bc4bbb08af6054cf90f5b715a843ffd0b0859398a93274cd1d31109cc1eacc9051ec7b12e571a490b61", "23", .Okay}, + {.Gcd, "-a6351c7733cecdc303923fef767e769eba70bb688a3783c5f14faea727bfba8eaabd9eb919b139e3463fb9e49fce617d112a3c7e8fbe9ae02163d78c648e46eece402c196c6d92262fd239a36e868441b2e49cfd5fe695d45361aeb8185466d25eee25e862d46b314ffd63e8f2017fc8b060d1f4054e3001cee20b0af05b7a1ce77d2fe96fd24f221011943b58b6362cc0ec95f08f07b05d2b41c70c59dd47aa86908f5dde375cc560f9115bed5d852c3601b86b51fd352ae9a99935f92fbb330ffe0b2c73806828c27fa0ce9ff8cf8ba63ae23c1c30fa3b45d9812b177f392db034d8dc3a2eccd4c8791e73ff0b3d547bd68368b121a4ecb982a4c3931f45ea66b1a0c1b95853a2c2b5a45f8932b78347d4c4fee6f7ffc9674cbc11eacd9b40e57a4e9e52c641a941d570c95f769292278ad98b665b0c1bf59b961cfd0d316f61faba4a3c93f3f84b250a95f39c76222f083479cb380b67e63a198b9c66a37eeb8b4d7904bca7ce76f58bc6daf4ff2ce6e72bd067e8c042efe57264bed8b6371736be396d2dcc28d150dfc6ee10f51d7e8d2ababcde10041102901a839e655fa12058ea72ddddf40926b7123a30168104b26c2aabf39fe28e9663c70f9d90a2e9451967ccee57c5b2a72ee61c6bcb5f875f039965565554c84b4aee9b3ce8d75245b7a9f040d1c0013c26316b52fb12c4b31bbf2f0ef896bdb837f28747fa1", "cc7cf6037b5f8d3e41f0d5d502a90cfcebbac3a1a10a1ae8a52943158665fe75b0cfd082c4e7adae9cc6b2c5db26210ebcae294a2a0afbc28ae177bb17e85e0aee5146c8031764e5578af85ecaadbfaf708ead8ee97ed462002d38a213d81d250d6cefaa7c25acf0356f7022f8be2dd305c4df733d247165eabfee8c36a438859fea4f6b1143d6332b28fb7251be0ebd5773e1093635959be4d7302b7b0cc6733c2e6ca9e28f883c8af64240413880195e9467c59c4a5e077a0ea1dcfab73b65b76d1b26580f20b72ed7b3fcbe87b662a197e7cefcd7dbda682b92d8570504d1659be636deb336ff8e598645a7fe1b262ee0b1ccc4226d26ed7c1e54dad50816fdf2801cb6128346013e1cbdad6b4e05d7e9dcb8a349fd7db497ce7a1a2d886287190974096b911bba897a2cf3b782e4cbc09cf63e5165c81f896fc92729e2cb53d9532a7bb6a6558a9ebc0bba80a00c9411d9b1af183a1fade1e31378cf2a15a66c2d147c32e7afe1914d55ca7fcc36af20be57042aeec7bd04fdf822f11b2612e31866687fe56dbd4bb6c5eb4314f5074587f3516a7132ad8ee45773ebef5ba8656206925480c8e16e10cd1a1857299f2267bb4daa084522b1708aa67f26c1089f3b9182ba26b8b0d012097c1401be8a5ba7b0cbdc51a6f1d9fce93abca4fd33e8e68cd44fb74322b3bf64ffde0ca0c0921d4bf74372a23be4a52ce7796c90", "3", .Okay}, + {.Gcd, "-76a2bb166c92754c60e8f9d9c31865bb247fe7126aa43610de4a277c32c46a7d14bab07d629ee015db57c5be09fd3ba4c775ca7cd0e06f9e83a73e97a24f7af6922ffc7a05b47f0cc380b3617855da8c166a5b48af6e85d25bae089da28fcdde4b30aa8a11112ef2b65de11c3e1efc47c5a36ce6668e5f0960fe199323f4686f21784602e03961e0efc7ac77178764a265c0d20447a2f29a8b5f0a2649db1c284324510a20255a40e5950f3fc4dfa426923108e837ace088e82f8f6da3f10ecbf0f1a864646ee0126e099132976be1035a7e46ce8092b0d00cd01f15f5d31eebb91ba0e1a160c44d893ee6cc8d155a3137233d8836823ca16c58cea59ac8a172d1a555f33a1a44830ae2041062f0b664c433ab1f2d9a4dac920b1ecb9ac049d746065df9323d29c98e352a07df4e6cb14eeca5327987bd138f22ab092f71cc8e6508a1d5a1d5b29905de9ebfc200cc8c1145597886c3dc3ba7f9b0cbec89efa5f956675c1a61de078447633c10432e1fe14541ef45b339eff8b4ed74af2c20619d645f7e9c6121ddf42820891e140daf0270dd37c907526a13f34a383a8e5df19d8926d20b2f2094998a2cd2b1b233c2b9cb008b5c5d6206bc63c1ca01954d0dbe4f43c0f7ad86d57a9b771ff5d1c822d2a33c83a2e8fde453359136dbe3ac356a13aefa51b32584036dcad3e3805a8ae86c8f2e8e591af915904fd4d1462797", "10dc59fc31d7dea204961078a13c82b41d3806122b355ad294f385835b880aaeebeddde81175cbf5006368d33ec106906aad42a613904bff5874c048de86c45032df0248609ffcb5c162f8bacd6ff1a37b7a01d7bc185e9ef2c80ead0a6c6702a3bdcb69009263b5e248d94c569914b925a6cd71945bbc458b926e69b3a7bd16679082678c50a08baa8e27bd937216e8d336771cd1e1e15049d8ecd355c423efb8d85ea0b073a8adcc0a2fd677140b98d97e96d133bedf514a381f8f1c01708f41bf8e7f4421021072647abdec9ef955aa25dde2c54bfdda866e445246613d950f9aaaca6288aa926c3a893f2794057183872d4f8ebec45da2edd05419305057093ddc3d930d6ea6edcd7372d780a2bc7c064115111bcdad0b43b083965a8f8626e5cdf6a4d334199a052d4c23554ce1cd9361de69f63c31ff364b225cd9cd85df44e82a178e056d13066ac929cd5e09d428507b5a64ee6aa8e5520d5dace96b68c435294251b611788601b7846ef5be3c2750d843201aaa9364db496004c46a4412962dbdce7f1097c89cc9d91a23d336466976b47ac54b80915a590bb608deee3b4e91c409968a8889ba3d74ee10651c461160558369750e5db0eb4290f76e3d4ab5888cd632bf583ffa646b87197819c54900bc5d44a495d96c72e44228b7106e807183e4093b49d6d4f80161e78c049c98eb14c7801a8256cbfecf67e6", "1", .Okay}, + {.Gcd, "-f946ecd580682687cd7c8035a6e72931aa0ba0bf47aeee278af77d65632eebe133f11fa60b9153f593181549d1cc9a519847072d53ac8b586d755eba0c00f8075ebf79e5788c843177976ca2e1a534a047638e8f645b69edadd620e86ce5d15cad6f7b4c63cbf547e7101a6a3c038d821e0e2d38441b7f85bcb150ecbd12134e01755299b337597f5a18a5470f173c24d319181ca6f97963243a3c9e255169b8c8e454483eaaeff242ffe004204f89027a5ceedd701c585e37c35a3cdd2d8b23c69492f09d0b92f03b164b125ad4802bcfc2ef410adbbe7d57cb4218febf03b3f91d674b79755c1f996c63b890edc425216b422ef4165d6eef8fe73b91b86a01ab3a045d0456e1dd4d27fa1230d2b052df4d9c07f67b45351a716a941a65bc43ceeb6234af4e7d1a29c676b3244968d72186c06a1460e49d2b00d66289e3d2705c02b6fe61836959089a9e95f868452c3f8e3d90a588660a99586850ab2594de2c57be9fd51765548f68429c1a206cfd9939349818c842b3999b7d0a48fcb0cf4aa7db785ed95d914212a6bd91789d066b94964d4157957fbd32148186bc500609ec33b0e732c6019ebd389e5d31c572f7a01e620d24c6edac7cb2a3e8dc13de27c3b9f0f8459c76315879b1052bbdeed8c7696279d908215316ed31b1c38466b5f60ac1b32ece01fea2ae2d433d06d5fc1af8aa0b19fa4cd2caedc97b63555d", "628fde2789035e86e0dda402117ec3c760db72fd53e8751f2276cab1a777de46d30189596175077d0a0f34a99acff9f6bc3e98cb5fdbda6cf065f44b830fc5345ff9beed46965992a1ef551dec852887e11bffa19b4e0171734440569da17487f9e07561b5ee32cd72da37352e314f9a6f970ed857e966452e6c553470864d5e48505a8f56e251f8520e76b32a100a99bacf26572587a7a2712655a7cc53e20506ca931e658c291c6f896d159ea67a3eea34bbc7a1d1674a809ee8ee201a735912940772a24ce08ed011eeadac437efbd9ef7628049216d45ad653029539a453dcdb6f394d05a8bd1a546b7f1688078860cc0fe0f78bfaf1b2dd5dcc81ab2454669aca7cd895b6c407d2145235ec38ff3a4d25e68b5a709d5b9d961a42fd1722c6e9cd5b43cb341df7d50e286f5b6e52536612828e71d69eb6a8432e1dc59b6832c2e6c95b55bc3fef5fbd0694643c842c68a6a42287b5caccf79aec357a2ce52edca747e915a38c389d7f1d5e94dfa356db178829feb7ae284c3f97cb02d27e2261593265f6e6f0f53d0471fc189f973b85e52fa25480f3b044eb5861eec3c4f1ac64e3261ce4febd277f8b51b391779053e781825e3cd91acaca99c99916c28316efbaae9361c06ae7cb1d1d1fcc7574750dd47c52ce48a2bd9981106d108becdd8ea45f51558f9c50323abcd26dba2a8722eefbb163dd01a9db961feda75a", "1", .Okay}, + {.Gcd, "-3cab795b96870ef10d3d3ddbb52772c8fb87f1523dcf5a8c8e3d1bfbcc5b883a1360617e37cd22195e52ef7e64ef76868d599b1358e3b488dbc2a7c6e6f9ce892da63dfccc2ca39869ad16b4b25f9ed2ce01123517e2a42f8cfda7eec7e09f4b723d8130e3083e3d068256087883717976ffe59097d05f5f418440aa50fb3e7284c1f1b82d7e3db2e260029ebaf3676e9d9b9db0a63202aa9842562e6a99ceb66ecfedf0204f881d473154e29c57146c57b06db1cb8406c1af52b6a16ca4fce98ddf3317e88686863bd424ce4b5c42b15b1b0bcde0bf5a2d3b1d3003c82f8f4b51c5f72e4643dda36ae4090be46eb108bcf8024992c20620e8d7917b3f96d61ba8f1bae1ceba001f14f64d85dd7d09d778e09f545b2ab9104b9cc71cb32b283f2addb8aafb99d39757fedf3952b4ae0b08f36b3e77fe6e382a3fbc56e0c6aa47d432a720d3aa3bcc8a4e3a0bf69c550185f419a8336ea2d2def28528735ff1f5e157f68daef9f4ae9a81a460382c5804cb86b6bffd0187d62a1832b66a3dd2715d2cb94b647fcd1b8de2a7704bd42802e2b7d97e17645d209e992d44ca143ab891f0620a5b99a069b6f05dc17a08476db8a108e0126a659c1c11d4110e7545acf900d589ce6f4879c535b43b318ca3dd97614c0596ba144ebd079e52c34b30f1c410ff913b208217416b4341c32098e3c67ce0e8b80d9e5a2c2c8390f0d36339", "5eab3c649eea73f669074e1d9cc5f657fec670dd726e6ca124547b8970fb00ed078e4802e3771d055abf8f244c901a935de16ed2c1191b49eb9d40ba9daacd558989fe18ffd07a9c4883db09d2afecfcf51474a30ea796233ba550659e285ca36d2ba837e5721de86cb507f1ff7d840d5e9fbaa0c8a5e2a3c2b88ef0665bb07cab41053d6217031b47d8b9920bdfc9b94787d9806249e17da49f32484dbed26f23db59cf3f9fd9984073c745a0b68c780b57a4a58c612e265e821b967516a8536f572e2d304ba7b24145328bc9584caeb7af8fef6a62454b5a84517f1bc51c3323091269b2170d116444b6baab13c2df532cc668ad288dc0974b32c276efcb591d104eed3a5a3194491c3afef9aa9dec29a40d8191bb142f32fe6754ead67101828efc69832e3b2f077afd0e38c72b9fb77b9dc53c43fc275fee32bf59fe1f5989cda8255216665390dadd3ff3d7177ea0475ca818253edc00db99144054419a4ac4df3f48951f5d6e172f3af7567c58468dbed1b2ff6c449888f97254d522c9c49fc22693f9fac6c00e72d3cf2578227ca6b8653b1f3d7e39a88883b9d069394a5b9e17e55d276f5640b1a162affe0f583d559070e480f2c60d1d56547ed5331d950208c898019167688500fbcc8b70c3e113d06fd4b0ebae1790376428e185d087c8e841ae7b76277697c30b05f5559b8b651ed52c026b54167ea7906ef4c7", "1", .Okay}, + {.Gcd, "-958aad3b8f46121f92e1506e035713857d164c4a5c2c48d75258ea88ad45b3660afdcb70ff22b71ae0c51fe92e58a5927587a3d45d14b759c6679ccfa9a74f0e94392a50f6b2188835670b0234db06c513bf0175c382e5da5fefb6dccfe5b2d2abe2b52f101f41b19e2165abc274b4aefb4e6f86178775a0f52a648114f20af2ac3ecba39daf1b0910a6b0834367d322a6c4e4ccece92f256df5385c33df9ab1c7dda8db1f9771558f18fe98713b021d7af0de9ff61010f06842a6bcda32cfdb3500907a10dbebddaa319f39e4f49bdd895aa8405b4bb91476c9af9c559d8011d53a0a92f4eb3e9d59b1bb51d3885e839d30545dcdedefe8e5bd453c97bf50d56e2f3b0b6cbcd6b7e80b0c50a4b5129cc479c115a5d0ba7b1f872393bdda8522570a2c32d156ac2d7886fe69a0b0ad8b560e2b94024db10c3ae6502e9f92b01807f5418372a75c184d813eb3d52d75b22d8eb6d67a967662df5db7485c8f37dce339753111eb1ad4aa48768e80dc8223d16a0b796da405b61f71673c797f79714787ea9d25c1e2d537ef0cafa48e22be2be17c4cf6b719a8b190c8ba7b1ca8270f3b779c2162b6bde64d5b02e6c6646b325a4c1ca09b9091837f02e801d55e6ae22de79e30207ab1ce28a9c768c13b3a3694905d45e408902cfa4bb18b29bfe108ad9c45cead4d2f1927293c5ce6b605f18755bb1ede8ce03898661de431221d", "87c4667a0f72ba077942d20b6515716e50b7af4e6b91fd5b2f5552cd8c4f2db9911fc1070f53b9052698b1d42e677ce2e5b8fa0a78fac1b25bef9c62738d10cc3362a34c7f8606a111a9a220628b8dbf1cdaf9b54c3498486db9f0a12a0283585aa36f92e39f7ace104ca03c4430004278b6af6f6245be59ce72ae003b1ae54c8b931a1fd1cd3ee8339b55bf91c1f7b53f6aec670504ad0ac97d3341b479783e3bff231aa7a49c5e6edc2c8f8f52e479bb5fffb503365689ad6364347241ba14a0f1eee483c5155d4063933f65ab2c72eff94f57640bb1cfeb40bd1f940318a625d42c00ecc75ed08637f1ddfc52e1b4a457cd6ca98249a5709e92dc4b1298dff1439250ebb35dd48b0ae02cbd3628d79ffdef311782b03ee4f5246a78f22c313212c9816c090ae34f682229006cb6de4c686644fc11fbabb6f362423045781ddb10c69983820f34ef4a7d5f5b0e647b31d44538073741e1de08ffe7bf09759dc9f65cd0530648eb84cd3863a0faeec0b7f4571e15f60725b6bea65f8a606c03b3b46ab92ead18965e89454f056ad02cf7d0a9e7dd590b54552aad4979dc2954bfca4c5cb5e1ac1e1fcd184c7deb9590aa5a0b422bb2b27df459fe76859961ec740c158cecba86de0097d04703fc4fb5c83cc8a7c1fe0e23db6630f79b6618e904a1a06cc05baaa314be0cf02567293917925800b731e8aac265647d81515273", "1", .Okay}, + {.Gcd, "-1d8a328e2a53ded8c8b282544ab356a5f67f68caf03b28f2db980a948555a5c9bb2ab985cc354e4bcf9c38c31f3f5059193c7201ed48d0ecc979e0c280b8ab2498e8c4db605f413f8d781146f058412ac653a5be16a1259b81563cc06f794f7fbff652f6a2ba678bd7aea158431e658211686acf057f15cf0db890f27f2e147d50f2e8df59a6cf3eea58502e3eea89594915e88e97a813a3b9035ff626140b4e901947aa334bb9a6dda87ae06170503d9fb6ae9ae8e388952df3db023b34ecef4e5bf7c8da5c862506e88439b37f44da236dd980879e4606bf8e7f092caae93c2915306e044a980ce6e37d1280f4f7d6d379e199da7214efc4c22395bb88d0565907b57985b606cb31a50300ec64ccc0315656d0b8e8df3986494270df8335aa019ed2b7382c06f14908f89da85778499d1615840db869355afab3aa861dedf8237555b9437d635206c90cd78a0d45fb54613f409a5cd7a0e4201ec07361df432773257db424938dae245a04dc1758ead7f6bb386e8e9852ccca4f82c9c2e7fd9138ed2f9a5219a0a3ce23fab04fd12a16d02846030af90b29f94a726c3f0bf256cd7a8be752cf379dda5a55c0edeb5dcf87feafc086dea2a6d4495036d85e3d09c3e35b1c11f54dc86ecc8e1a439398c1fcff3fdb680729c3103892b00135c0f1fa247208e20e5f2017108d0ee7663c42d440d10d2bf1eca1e8afaf017df58", "5ca7d0ee95a7fd1874f4930c25514a29f7486ea13a7299e168eb1d263cdad92b798b6fe418fd97c2e88fab99ef3b904925fdc1e3beeb5fc971d20bfeb894a433aa6dd4f2136a9eeace1e70720ddc5e47c2866ccbb389143c91cd2aab0c788c349dbf9a87af1599cf1191edb8a0a852ddead6b14aca1a501a2eedea4933029d3d1041960611c9c4b56385e5ef9fe07bc7005ac1deb4ed767b60caa39cd5189c08ce4492a150b1056782212bf495f6d43cb6d57616b6e21574551dc6fb73e4a48da22a0c39cd6fe1bcfd679625806f90b3aa77ffff9898583fb2a7a47d4c555ff8aed03461ab241e2ce7cb01693086486c9620e3445424df14cbd85df300f3b6bb7358ef3d53435e86a5556e5a0a938d95a09ddf8e7bce12d35b8326ac223aaa9f85bc89f80aa0d1265ef795b3fafdd8b9289100511c1a87e04f901669c291ced124cd023c338fddce3b6182205f202b6121665111313b23d39dfe28a45bafec4097c81e736cea3b17e1fd50424e031c76187b74e9f1d14c9f288cc4b316e81eac22241e743cb0033bb08dcb7737150a32022453e9b981cd9957258ef4673a12270890a8a71086e6f236de12865c9c2c0b92cfb248800c99e556c73ce973c6c5427d53fc3b405168267d7bd75c9737218bd20bedc516404c93cdbea71598b35f608b2156478da62860dc8dc14b5b8802ea83784d2ff6d41d99c8912cca8e67c106", "2", .Okay}, + {.Gcd, "-c56a2a1c03fe3662f4b85f3a16cbb585a3071d60888a08422fc951e314eff25c502faadba5332c5338cc57ceaf12f4694a5fa74888696b6902c83377205c43a81e28daa4b55727595fa72ef2cfdfeec33f66cbc3d2c40fc1b0413410ca58da00aa8d68048a9b1a342099c79626a2261bbeec8919730dedf32e3052278a50d52fe0daf21610c9da914ff2d54b814c8ab4d2197d79eef7bf70d619b73584f366f1354b567361772a0c8ad87e6aba299435f4fb193fe947fc15e9206b4925bbab104fb2811ee31365c033ffc06d4425400e9e5af2968171d7119307d20f1e2730abb66e72c1b3a0f1fe154e0760748f2d3764f3a6a0e2a85bc25df189bbdb6b3e195afa10ece55c209444b325bae18b78019134f7222f3d5583a4905bbab04c4ab4e3170ace05e6e5c0e292750d3ebd0e339582566ff80026b4796f2b93c2bf986db697d43a7abe360ee92195a42df172426372181613316dce2b55ac39a82f74a725148a4a9b3acbd63fe8ea580073af80a733db69d055004a29594d4ad15858692d0ba87922e40dfb68148c1510b87b47a18c42ebec0cfc06def2c3b6197359964e1014f575690ccee36dacf3a7bf40bc35e7e4ce54bac1295fd14c2978c0a2f586c5d7efba6661d1dd4e052bd5197587a27688875ad9285f50cf5c558585de962aa227537716c9dcc22de7881364fd7f23f481bfe4ec9d73575bb08aa6978e21", "7c29e6f3ef33ec6b62ddc35c7e047c5a79a03474545d4685599a0b3c37edfdd3543a63c319d84eb92dd13d71afeb8bf41a5ab3fa176f9b22a68da7d6f3e534a138bde4cb1bab5b9d8b843c8dcfacec053b03f5994689fb65390600cf55e32362514646851edd7d9a27cfce001b5ddb910b71a6e96f685a9fdf74811eb9803c5e2d4b6136eb381e8930c3ba813946b528bc8c811ab832c4dc8f47c0885e7e0f74ed738c77af6accd4cffabaec0e5e6ab31361174d03e49b894620436862988b8eabc85505b73e0e47621d04c2312f55360427545c651f14159c734fa40ad36a220a1b731ece13f272ff4e6b303e0f460f0263510606154f0c8b179c404f1b6ee674a774b1213c8ba759a3dfcb0aa1eb47556bfbef8f6c15d11688a9188458a6dc8950548f905a40e6771b542f9a67eac9e5dae490091ba34ec574d068e96ddd9e1ad2258e423f070905e9b300f129f657a9c3d34e13872e5ae336c7e0585f32c8eb69e1e797ee8012fb05a70445f23471ad3e45ed34dc84246ffa634ef527144a6d49598b0ca6d09cd9ffe5c54fa456a68d90dee7cb392df88955077d310a3458a683c1fd6c6089b0f0eb13e36d1299263f9da3ef94fd47520739f62a39b442de82c95a63e9824a76ce9aa61fdc2791de84b34b8032c54411d4f2e477ecc96e14d5118cc14ac1e74b5c1a44f9870b7e477eb263527ee0a3a564c12225f025b22e", "1", .Okay}, + {.Gcd, "a62d7bee74905a9f3bcdd60393d4fb6fc26835ab284aba7f89f57ab9d12f4262b6b991d4bdf4307c2f6036d8bace1a63876ceed0f75dcae36180077551fc875de656a628eaa5f6c65f47b1220ef6fdeaf383cc6d77f44c853684daef8269a839c3b6b6fadf475335e645e16cd2c5670d2656d686c702eaa1f39a5af1a1830cb8687246a04b923159da7285e9f6890681700f745a4ce056f683d9bb2a74f07710ae5e0f49b974a4dd2df35310905e2c67d728fc82c89efe47bb685314290ac217d00301728622f6f33ecbbf4c6bf321a8792ee95264769b3cb46f7d615d96496a6f157ad1d689f706ef5ff8d3baea461f1b55292f9dc0f597cd227e1f332fdee56c730b8d06d3ae5e85a43996879be700704ea1da917b6fe88b43d62f47d4cb24e13d7572ac65b4100e964908206cb33f26ce4cc872328fea5f135ac06a9622501b05a0855f3c7e7a3f560a4d82c43a82ad96d8f6da4c072a1bacfd1d936f2756889bcbc08aecc54795642b94ce3e20cb1e7f47e560aea2481888f008d5048e9c0d46ed98f02bc7ed99d93aecdd9d361cf335a7476e74778093857812daf1841c1a3e4078b33d14298030baa6c4d1841a1cd7cc9d5f8426bfdeed3d31f6d32533533d65eb1493edbf018f8b8f527de6a48c3cc46e8d7c6caa8c4e998ef948c8d09813f906b89c8a61b9bcd65770c7abbee35598b929b20702fbe462672c21b4ba", "312f4f2d2d52a4b2cb1a89922bc928e4cd1a303e114a592c33aaf351ba49c06be6d61aa052565763709987ea70c0f1b5b944cc0a83fdaeedc7dcf2b03499d0dcf42ecf141038a0e5e27901ad65878fdb2389b6cf5a43e65c79da1b52e3bb3d5a258a36f04926bdece4a0f9bf3edff822d9e4b94811ba1d15eb290acd07017cdd31147889ca790e6953a988b35422467440bf0992db00217bcc4a8ccb4d9f06851fced991727ddc42a3af63c791100711cfff9a954ca168b0b6b91ada1d2ff7b749e4fc57d94ded01dff65bf775d2b7391639ae62d6e92c3ce8e39b7f2e7d57c0a47fce323a8f36c6a9b410933ab96f2f72258fa139def98d50ec94a90b52f7eaa65677fee8fa6eeac5e4b4da7e830f805c18411f5514eeabfefbc9dc8d6802f3f7c4feb478c439ae54b8e9c533566b5114faa88b1e347988a6ca0e9ceef7910ab4a3d5477c77e2a4f2f6c4d6202cb97d5874b6345df4742cdfcaef02a40e2a66f947928746744cda31862329130e68bac9a1e14d659d69088be5a7e2411439b60805b262e6e4e010726a5519a52b6ec1e15b5f1aaf0521e111266e1e68a0466d85e56bf24540c12dc3392ba2e7e0ded41babf5e00ba946461dc68fb7500a4b856478d4888341caa5fe7837e6f9046592102681884aa6ade1b51aeab606e7d9d84879721d5a2af6f1cb3e28291ea63256ae6c40cd2784a4d302b7ef09b5dd56ee", "2", .Okay}, + {.Gcd, "f67646a94080960c7cd30eeee0017671176ab1c55d6b75ac3fb9f8c14629e55c7558a8ee0f8e09befa10e702890a688de226a00845e89b1285a4db3f5d3345ec2af6eb49045c146ee93b70807ec2d7a13c0f3ec6a3b6979b4b9a39aa9568a1dcd4bd5366dc304b0af8b25633ddd45466d1d87191b5be919d55549e5c141cdee13726ded4ce492afeb3949169ea1cdde95fcc9fe635e9e7d3c9c11b43fa91976a71fb4833ccc2417c3f46b5dca1a68f28f1beb29ab96ad79627e5193e38a08d809a4e90aa98be92d01185611b96f906012ed9d54724125029f29132a47da09a34749db7dd90dad8a7a45576f3c9d98420671e21339979cd1290ab900d19ad9d48fe52106f6c43ca700ff4b660799f74ce9f3f01a8ffff7c39c00fa82274333d7e749f7c10c3483544263b14ef5f4fa462dc3db6f6da05855f7e756f864fd53d82e2032dcbd67a41a10ef79fea421a55fb643bce771065029637e3e750bb6193ef2ddb74df82a9632f491b0e9b7cc87ccf5ee89647d213fa1bbb1b88a91c5ef524742ae53272408db47a0d2f868fd8991b70ab061874651254c825ea292209444a9224f9dfd1b0065ec15bc31732e5b05d8601680d463f5009d3f512ec90278d1103465fbfa23f8e5325b7f364c6b5e4bb869eb4c3641d2262e10d9ea43b12d0da8828466431ed7d76dc7b189f11984b9581a9c18106203ff2bc07b79671f4d588", "33c830489a9a5eb80d7573f2b9198803474712e0550ca23e49992985394d6e51e7b7cd2a042036548300a7d1af92e19145380cc0d18e4ad5b33bd7c1f1def915f3a0709033b8afe3473f4086c8d59b9434c8d7c0aede237b82585e96204d7705f2867266e0e88d6b443c006c0edf3c7f9afe1eb18fee7eefacfd4806cd9c7f47e495f231c87fe798115dfa654a25e2bef08c0f2342b981cb287f4bf4090104b59a2643ba6eeea8df95e987af943c69d4b382c25595f3405493c3b3dbef0dbf7d4d636ab81ba4fe85bb6e6c10079142e99a1ed9aaa76a2aaa4009230e374ed9e2c667dd98a638b5e956f3de8897e7fa5b4be8ea85008b563606140bb42274cb760ba770bed1a9858ddba06983533276e160bbf12bbc5892d78f4ff93936e3c90f36c809688c0ac6ffce31f7dd1af29c6d9c4304b6449fc8077f0f2dc98852b2cb7c8a1d7f43ea65ab1f33adc02df6996423b3054e938134ab3969c66c0f86662c26fd3cd93951466e0d7adb080e5f021103a9d996a94db79eb339289aa26098293362ab83a581f5eaffc3275b51ca2d1c1aa1c5f5ecc919064b664b7afab45d4d54efd7634b7ad658549bcba890709f6ce7f0e4bc3c784c81ab90b063bfd5ebc10ae7ade115c8c2ee427ee9f51840939d38a1c5828a6f4c58ea614952a1596b35ccabbfcb8136ac77c12ebf7bf5791ed6e61b321059e108b4353bd6834464c4b3", "1", .Okay}, + {.Gcd, "-dc2005c374bb6613381f9875b86782f0773bb0e1ffc9d40fa8ac8b37b2605091e42a17d6990cea699dcce5d4a020364dd7d5c847982ac6e56784dc75390973e847cb56d99de7c07d9d43cf938b9300975a8019e5ab7c6b904e9943023a48b71eca22294f19411aabe25c20452ff7d2a6106c56a3ae5ad1e4265c813c978f9394d12dc1178f9c490808dac44a272952333bbcd30d47ed960997c77591398d63ab63d941d21f9710ed6e879bc7b8e3a98223a067f557f3ca64c8db79e71e4ce30e3440a876de530a43c7e337cb9d8a1e1a429d65228e1d72cb7a4ecec41fb067a64092d75d7b80ce9a7c993c3af0374a5e54408b60c4487d927c9e3895f3d864550c7ead70a6f240b07cfda4a6068a790cb5405fad9b4083d630149be72a41a77e21f65f717fa541765c27ae2846f069b4a5f7cce987f410cd5573b26a3af0bddec35c594adde81cc3dcabd739ef09924d833a4ba84c3b6c9962532e39d9392265361c031bec0979ddeef6234324f19c4041c97653235eccbd7864551e45dc060f99eded0b4719a8ae0a280e6404d2cef75f401fe30b58dadce0cbd969ae064ec88d6d653779b591ebea23d75319e7a4cee18a3e27065628b4c2669752fd32d59e8d1c8e9108f2a72dc52c54ae52a733236967ffff50b323200c4521ae8531d1d406e1f3db2ca8782396da7ebfd3306f4da7ca98ef737ab8d01912b19a652b4f9b", "ae6671e71d97645049ab19f6d363ecce5f96b54df3743160977d6ff65477b85c92662b1e0e18d2233e646423dccb96b800490c3cf28541c08cf50570671ab1017995b43e0cc7b41225dea6c4296ca5db180f117a7dda2348c09e663b17cbfed63600bf765276593219b8da4b91f35e627fd73bd2e866541a839a3ce99af765bd45f4fcd4d091d2093fd8db0a4e4ab36dfe16b06133c6b4cfdf8eccbd50813364addb0f1f6f52ba65d14bd475998ce9d6011db651c7d21cc0ae70e133764064b7f28153b5cb9eee0ea3f5de8405ede32e19180cb6d291c7f3b0f36f74484ce23ad5857afb70a9c6dacf58ca2c2672ceef4776857de5055eeca615764ae47f655107bc8623a53f2b0d3bde983a3c9d89d34570c5db45135628b071e2c5855cd67214aec39a3ded4f5e43a1ad07dda7488ca324b150d9b9e0658c86d4bbaa9d210bbed0c17ac59e0b8521f4c15d19835896b02d7d9a403575924680fc52d41498e2d35bda1e64637352de5eab22ddaaa21ccc545f85dc33f8f6641cf26a3c7f32aba80df8b171c44040ecf7c172a384efcb7f7b273347a89b5d1852e011c84e2fb68015564c5988fb816b448eb63ce045ba7407477456de347e7020c60c0b81f22e0e0bbdb888d26e49d1a1aafdee3f5a99b09540c8dfd6b72c5abf25a14f309e88cdaf95f8a21b2416f612fffe832f4403cd4f9d39aefd42571d2e7b5b045bdb26", "1", .Okay}, + {.Gcd, "22dbc8b6c487dcddabeeb5335c6f470e97b40d4e1bcb3184e721365135848bdc75fa5507388391e1099fa815d40f50286543f3e0ebb616c87687e35140e573dd1ef26ea44a924a5915662ac9cf2fbf65960536ea7d2b95be116397b1afc359070292ac06dd20596c7cf65743b5ab760fea54fe065f4122dec08680a838088ece1e977e43ef5f4f2278ee4e6c08e36174388834136f6095d1c733df41dadac20c60573cbf7ddbe142706c442e20394d1fbbbeb14de7a150c84ea24b6aeef4332fa7129ce7ced2806f5f462e1a349717826d641777e58ec079a7640fb82b677dd2ab29f67db242e003f099352bdeadf2ac8b9b6bee1f9ce518a5129877bf6f42eed31256c62d75831602a42c5d10fba8bd8e869e5cd5b1a574efea54fe44f60d7abc479054e48dc85df07c77e8591d6b144809135b2f7765033ebb272025a26df4a7adda75393e87969743b0ae99090b8f1dd3d8f4e407a415001314990478ce671dbb9b41741b2fb995739a57f35cb0f2c4bf64dcc5b083f9a6035e6b6161f8647b4aab09a9c546a8e389db9fea1208cb71494e9c5d365553e4aab218a3c38e6b1dc3a98e263b925f4fa290aa26fd5a50c89b24f4d92b204d7fffc8c67ddaf7d21022de9f4ed15e57a2ef4e98f0e58071a751b74c4f8b62ff26a1c1aafdb4065a9d017ca79084c30783eeee1e5ae8c9bfa586ff37056a28a4934a2b77b9225185", "4346067ce5d9804f81f1330b1e3ceaa26f565f5fa7671ddf2ea8b79d828d73f061ba637940d52245d0173a38b4f9b6b4ba0d3318ccc0dcbd97188901645ea58ba6f29318f0c983779454152f0a8d092741af7bc386490fb197be7f2fccf12afc76df3a9ec20ebd0e89855ab5028220f2e9864e847f8de155d7de83ce8690180d510a19c6ba5cd20f960ce7a020b2aff63827e9347378ea6f3cec136bf4486472c74ce38ce93418d19c49c09e2f91fe84138c3266ddbc925091649cef462959b66ac142539921b8a9e99c16213513cbb2144b41f4e1c2b74b5598d3d91d13ca23b57dd51a745be9156f8e0428a5dd9dbcf1a1580e3dceb38d614c23d99738f325163d7ca8c6a07a5da47510b7a8978b2829510f3a08619d842652b96432f9a40589dcf471f67d67c7383b1809819f02f1fa5cf87b42289e1df8b73b6b8bb169ebd9cb0b5e829786115aec015614c732ea822e8d3fcd959a59901fe37f1cce74f6ba02c0532d4622025fb7fa31ff97762a3a09ac9ab59bd80f2b8f68c1c92175fe95643ee359171aade19bde545692fefa9cd8c4030503edbd92216c14d41aa613a8228ac52f0c5cec9eb84ab2813c8c72fe1873d48dab5052c5228462bc0f9cfad32fb85fc707b8bbc4fecbaed888c0994efb30c024720c09791d4086671295ce5a3e71c0f28d1f1a50ef3d912b3d2b161fb52a458339f3a229bc7be399c29c81", "3", .Okay}, + {.Gcd, "-18b2fd669e37db9fa907046084fba4d1466d37fbd2a747a2b5550519ecb6bba35c2f902abe4a92858030f912b196456b54d311fbf24c24e8c52a27345871ceead264f92b45c145658ad3d9884ca99204d610f2b43df311df52e0e0e6f862477928524524ac526569a1983ad8a7fbbdb654128d20a8f25bae4e6dc53697cfd677bcac3d8717076b37eab66fe593c307e8e810a835fd90ac3723bd085feafa3d385605b822a20ea3314c2d14bfe4333a0f2a7c146c052f00b11eccdb460cf10fee717bb854971c460d9371b04ead40cbc62c471ef76b6832b708cf1cd6b5626ba66dc63cb5337bdc50bca2c86f49ba98e890cdf53ee36eb594be672192e05e1cb0d0088db7014cf667df6d3ead504227cecaf6ebd3b01dcd61b1b68b74653884e75f958c5dc3c1feae2f468808f0ddfc324a5b53318fb3514aae7561451b6cc5c64400a897153306f0dbdf2bacbc72613c13e143d478258f696685f3daa7b81c893e1311607f1fd14cc6d60df1a9b0c570ab2354458b168607e741f35ca3a6181c536341abc78c27f4297cf9550723b9f9f4a43e3040fa5acfe4835c577ecda8a8341ebb9b8f6adf7e095d004f87a9caa7846c8cf861ec036c9066ec602a0aeadcfcbbaf7ed2b0cfe3ae21eba0ccc2a67b2efe2ce5371477b1777ee7421cb235aa415e80df7e59399befd5568363d7f6c1e6930402aa2e3f827954c53bf5b2a562", "8f241956ae60fe1a1b882e5295d2e99f96f42726beda0114aeb2d90ec3a5351d067d13df23920139a58a5d486a10ce6cd31ad004cac32431f57f57ec94f3103a8d105eafc5cf60c6a8290dceb67f6f320f8030922a8482b90a16a0fa64ba66360ea822fc7119a9ccf41ff156aee77d2000dbedcbf96e28331a7c313a2ab46196cc54a559d649a3bfaffb7155e7e9e91c4f0032210d8d4528733cfd5a5010288eeb4486120cb2fef0c71c451d0fcdada40ecec6a8cd00cc972079eb3cc580ee1d3adb13c972a9233f022c6297da66e3723157a5aaacea9eb9dcabe9892b120af1335c1e3283750047462d0e5470dae64397758e67a0ac4a3641f37f17136337739dd51b4532b13b54bcd3d62ea9db92517e1de84613deb810f91f4d70c2f75f67d5e3ac20db09fac4c9006ab06b0b3a25d3419bb510598790d70ce13ab84990d958513fb244b75a53783e952ab21f4fd737d44d94f7f490ad7bc04d5d66c153874d5322c685306284633b5c36b58243ea49243b7e92a2323ea0a17345dbd7f66cdce87e84c33f983b0a9aab0e7bcd905fde70c5d97ad2bdee08a988150623712305f688dc04a1589534a236f780d6ed4542ff1da5d0c3030380d395c9e115f4f2e29078f60887ff1497a57ec57feccf6a8bcdca02671828afcb1473b6f2d55c25aed1daa61e080ea0f2060f47285d8aed3bd6eb79aa99d9a919c1b7a3f7c43f9c", "a", .Okay}, + {.Gcd, "f4bc5c366f6898e49cbe48d345a996dd42e6a91449036f5c50d3ec246652db9d568215931001fd0366704d25b18b059908834f05bcd5da1bc3efaa2f5eae7fbcaa53d0c92dea767fb41cd958c50d96b41f18495ccef0e5a8c407da213a387b9701577d07d45233de5193fb7a7e43abe8c950662a0cec465dce9fce6e502010c1fa8b81125507c809d7aa31f3539612fa71353b9dc9bc677900b0c433efb0009a7a7f1cfce23bac276a082ad841c2b1056c45210c94cf53056b2f6ad3177daec0bf7177443c79d3bc68892f640b9c677180de69a4c0fc96579e3c93658952b2876bf382d47bf6568400d686e1ba990bb18cd9bfba9af35849abde86af0cbe180ef57fb4d0db0068b369d6954d72c9fb5574c2366417532395fd8f4f1351942aa90cf8a72d06de71dabec3f522b05a2a6f831b740432b3ef5d25a5c832e2e34c36e3f5eff0bef3613c678c6d0022d049b1f156a9c26b2417c1524c1c55525cf9b6e413156d7bb97b80dd05ec59029eb66cffe94121447d92f90f1e15c6a961daa095d9b9b4c9de6c64a96d2f1bb3276142558a67bed7065dcb6565c5a436c17648d544b683e4f8ea553a3db4399712d83d2ae631a9e36e7e0e178127d6a3b1026b56ced3fc2b144c3fc8ecd5df180b863c603533808255d553f876a3bf293c962a5dd2945415ef5a18150a802465ea08679973d5fbb4f19996a685a90f5636d6d3", "c4aa7289a13ee73639ee6400f6e831a01420fbb65a484462e8605642399e872e11a346fc66fcb1763b6fcfc47c6061c107393e281f1063671526cc1ec0bde08c5153bfc0b3cf661687ce0d0c74b4f8e62fa504f97d7179ac3c24f924fc6a8606996c105a35fd63cf202610340a84491ee2b0ed9a7f39d4225ee7f667a905a792ba578811db107f8fe3a97149b97186778c6fc383d622ce355ea084631b5e90deadcf08ca5636318a0cd335fa06b6498f19d1fcc5af99458e46965ff06162789d73c9e1ddf55b455b7d07560535397c97df22a6d1146926fef68d7e2fc64e309b5d66bd381a4ad7703d1a6b2a37271ef01e7928355e858170e35c9017e61f02303a2ff53c94dcee887a30f407ec8ce9657e394c4cc9b0440c4b8327c40e642c0a99bd016d644dc20052290c0be644c64d489f4117ac43f7be4cd6caaed1763c3d3140131bc3320a25be4dd16768b93894b36b79aedc14985068a27206c1d8ec30fbf27c043927b46c800b16c58741f5a3f9500ee81fb5181391ee0cb4f1c913785e2ebf72809ec9eb8326d26ef42313611ad2ccc206813f84273f983bff7dcc4ae6846675334621bf69f805f7368c2ab9ec4b2dd2a721976eaae1081fe24fa84b5c09402d0c1e7df2ab0f58d58261f8bb3f42817888eeaf917500de05763e4110439625c3376f8014aefbc55a48c7838c1c1aa0081e726951e306e22d647187cd", "1", .Okay}, + {.Gcd, "-5ccb15155d1949b3860c0378f8c426c2c078d3706268867011407a0d4a10b396b5d43a821ebb1d8c451f5c59424d3259dca8f1f43a41748276c6d2d44dd5899e6e916e1abf3366bf7117b987ff0226bfad6853196cbdd0d5fd99f52b063f31127e3920b932b3e9eee69c630bf3f5623fc4e96f5d58ab9c76d017b59ad2fc1a6703f420c0a858849a1f58381dfcc871df7d303e21ca965ec10e3eaead72d0342f6ce7c19134dd7e9baaebae8e8ca4a537ccf000375ff4353dcf10676fb3c0335550efe8bf4aef23bebc06d41dc913bcbd9e86b4c0ae42da257882a81c02c2253f509c587949316d769c195deb821f24aa2ff64775ae1abda8f9965b59393aa3875d6a63ce4d7b15bf11ae684459eb9ccc52092aecf51d118fcf0794f00959e80d1a26898ff48ff220c0ae783585613c3c4ade728fa8476f8b50ef848f9b602d2802f382a47842d7483df2f2d58aa6dc0947cc6384a7ca84a530ef4f54cf8c4982f7dfab3f688265ad09f9f44beca5ad6e264a65daef5d53a83b0eed69d8d9d97d821a883627e04cd6b7955f2b81efddd9ffab1db46bc91509820157cd81297b0b67278e6e81fa3afc68152c361122466d67fed35d5e9bd27d026d8100b878dd35f0e0d71c1481024f204ed3b6d218db5ca4cc0d69b9d2647c23c2487d64b94dfa3905c9a68ac77183d61f774a04c183f4016f76070be2011ae2d740b21b5bffe5", "996d0755cdbb18d8f26bbc411897c206a87a8a1cc6c06769b97103deb8c7b229348cc063547f22d8c5bd9b28dba8e0e28468ea14ab88b0288d8b681918249d345bf2e2934900b4c4f672cddfb77df464d7b098ce34357fc1cac9e1c0b412d6835e3070733aebf67794f33009dcf346a99061419653b1d4e2bb0accdcf50d03d82487508e348324988300ace9503e821520f82dee32bdb7df44575bd88d2e763a15cc65838b43f40174a33de46662a46266151af8deb75a3b095a51437c4b3af2f32315fa88fd53f87ec048b22f503a42d40c6b80b91614abc27f8e5fcf48626b94377cb7bb547574441d6c097c6c8dc38d4a689dcd2590c745ed6dbcedc74b1072167a21e85d958fe1574e20307ab72f2fadfb263c8795bdffcb58cb56c61718a2b05ce4e0ab9b5066e396ac1371bcf17967cae41d1ecf6052f9b1112d6807900ee51cee5096d274fc84ccdfe02daa86e57d7a39bf352028fbf7029dc5d67cc6e73bec9c16a3516eb2e43c36dba6e28f46322dace7321352102b181d99ba89d50d80e3a491d671a541dad0deaa3df7cb32ea94e4f4d2a8c63215c70f612926124e894ec146da83f870dc4ec2d08affdeb53fcbcb16063376057cf7ee31ce3a5969b7028d636803b49ad126d9569c502a0bbb548e2fe9de211857f3847281da81d1f9ff2a81d66e0ecc63da347049a36d2a20173fbea8201baf4f997118a7bb1", "1", .Okay}, + {.Gcd, "d34e998cb861d2cc09dd4221bbed408284eff5cb499d8047c7e003562d3e222f15a72cae31fb724f4a1655c6f5510b4a35b8b69f88ced8902f3bda247dc68190681496f4fa14f3337f3e438a1b00fb316f6ae56a89df9a420a2ff9844667b8f1112adb4182df0ed56e220ee8fe44c9d3337cb4a2d19c554b41e8c229e9df4bf214d80d9c21b418257d401c52572ded0e7cca20843bb58e2508b7c548a7d75e5ba36d95576315fca9da532a8275996e7b3f8ff5898ef6900735865f151180cfa56a25515f6758cc83d72b1b22d2f4543d6716e95ff3825138d12abbbca2f685a6bc56b1954da8fadf07eb10a10728bb70d468553bf24db2714eae8ff61308da2dd11ba1bea58437129839896958e59e6a413d2daf7c96221bc46592408e1f6d97c822a9aca4b915702af509374782821a13650ff22cc54e7c3c4a6c3c8af6fbfa5f6ed5ebd53dfc705f6035ddfbc781054b6ded77e03d10a4fbb4bc2f9375cf9247288718a275eaf413739810195b934209f0964039f582a0d1c39d26e8b68b75fe8f12a28a4b6cac0588860e4f58a58be11d909e89b365394cd1d841988af035159675d6834026332242fc693e5a1e6c420229f3b279745ae72eff0d27193237ed3016b9a19428d4ee993e912fb846d9fb61a818b189122d63f52266cbde993df51bdb02b80621ee648c69581d14ddf38332c50429c9b19175f7d7ba3426feb4", "dda7264f35f10b837597c14e0f1d6ec8291aaa95efd5e051ce611a77dbdbc58ab8b901a2a4ca2bf395e4aac6a9765ef240e53c7cd9e7d9fa1080c277a55d2a2154d9c0f8702a1a1ca0047cbefe11b26b14c7d8de2f90629af3a01e28d948a8361fc1df1fe7fcebcc493a899dfb7392ee62514c7e784eba76a503756c5e38bfbd5103ce32ace722e304edf412e02dbd0ac2ee80607ad4557188eb7bc59e2b7de4e8ac81cdd503e2122b9cc48b4ccdce29de41dca9e297e5ae33cc4f186aa51f98a9f10ead6ce5db45d884c531db7eaf3637636e5314a71d361f5a3b5e2093f180428f05ecaae4d6790da7c8ff2be0b437c682301c70baa873a3d1913b03343ae3a9341ef0154fe855ee28cede53a0db41fd54a31a8eac4c5e7824d5c903bc7258517ca6e83b4f48e0429b757c8a0e47f1a1c42827f2ad99d8a58aa1e494012ffa31d6a69f31cc86e828773f21779409b6a5038580f9191401d5a2f17c41aca2335c1ab262fbf298b3efb7bcf3fed01fc89ccae408af5119923d6f225afc7f6ce887820786cd6dc562ebed6f2a9a72eb1e451f1785d12185d4970d158c8238831609909c666d171455393513534e5e2c07f9f9a7bfd8052fe0c7d6e7e4b14a0d6f8e743ae18f3981e30db1d14f7e090c1d6a82e186e66e0ba243ea05fe9ed9f2c02964067a6cda4a93d64c7ac4bae7fa0da1f732d665bf295d194391c12aa7c0e7", "1", .Okay}, + {.Gcd, "86e3f02eafd5ace6257a7e10562520758ea88baa00256251c20b2be08a3b5a40a01b87533e8bee09904d6a530f720cd98afff99fe90fb0060906fc029617a4b13c6c0cdb1195606fb1d6624612996a6a4cfc0a2e58f991d5e96d761b2a6ba7fa4b893a81aa125d44eecb308169226c87d9b4455aa1818e070ee8c1389021cc641d6aa0af5e65d9e43b94f3cc50054fee5d3c686307fb5c5874442838406c8353517a87d0680e6dec8e62a8002a1a0d12d13ba2b3c02a686b837ceb6f50d49e7d287bdadc0e7f6e4509714c8bf0fa496431b12ad0293313018f85c0bda7c1dba3a71504ac0f2f0e5fdb6944a4b4ed0e7db308b74974b21989ad0c6153651931e58b7c33e900874c949b9a30e0668137959a57987ceb01aa917208baa5121bae40cf072a66403c23a893667caaefde638e08b3a3635a2560f1fcb5a61642fa0ebaaa77e1a346ae70e149cc950e5475b3a4763342ef343fef2f1494addda258f9895b5382d2f9607c93f902e92904764a3229956e7ed717173944c5373c881716f9f3a202fe792eb7d31d02590737a5ad8f77755889f4a214b3284a0258b1a6f9275079bd69b938e79e9414a6779345aff12ae6aba0f3003e99738f38cab11ab0655167643d31b163aae48a73c9176c5f1a7e28e63b3457a6f5b475c2a40aa0ad9c41b459f187cabff456c3bc7b5446035fede53f7e595d4ab521679e9fe3783ce0", "f1debd50be5254e0374176c93efd8353aab82ca3c091d8af6cee13426ad1956a8c4110d6da99b5b58417d362d07d5674fff550bad342a89dbfcd3e76cc75501186ebbc821906a328f28137f184aed5e256b6284fd104e3e6a3df35778a15d498d2bf2a8edae95b1b612d03efb6a0d009a94a672b17699dd741446458d4df46017734ac611357615f93c6a08be3113118f62f3c1b02b1e426ff08e9a6ed5e60ca0141c233a5eac09bf91e8e3199f07ccc4693c42aff619d7784b1e6d3f920bd258fa40b89999377b587317d6e80177ca3e86fdc8e5c5a44baa3d5eda3a0944288c12c121dfbca6045ff0565ac777815b92edbe502e5fbd90321b05b8201cd20d8108fc16c9a96a590563217265d7a9e5cd8300ec58a7c0480d16ccb1fe660ea0e7c20f3da836523de291e729af08130c0ff41585d48f5961bc0643cb4fdc27f8f2e38d2b4b32eb9d1bd34dd414d021d09ba10830a1adec685923409eb555a2795bab8d5aa63ff54975f48a731e2e463a2ed36293a42930fbd9ac5deb766571a8162f4151fa113ebddfad8b52ef54f52770ced4b564f90e20539455aa90ac5cdb98de5658099ce4df2071cf30d19d3726a1d0ab06868b6d5d9d2addad98e1561c69db0f38aa99a899717b4ddeed6a3f2cc0f23133438ecea9b35a2f4aac2d3403a86d1cac41311b7f1055219f0175038ad027422e56d0157c514ec9cacd0195ae3", "1", .Okay}, + {.Gcd, "-798fb76c0a6b7c466b5fe296d4b6b8758340d802b7bb6890c7b05ebfc1416c6e4e5cd45e39b6bb32ec4a91b5420b72562fa1c3c3450a553ab4b6a1c7fc98e8d4868d05ba626eb7692bad86caea107bb644585372fdd30cdf8a9a849d8870f660b75e4a1d8f1fec098b6a41ebc0f019955b434f3fae180884e23f286cc22e620c4c15f5d1cd2264cc5990fdcaff794589b11c06d6634f0e0655cb800a53ab4b48a61a6b4579ee547a3253234e4d90d3932036c0818f4277d4ce2cfebc9ca2c360da76fff7ba698b5cfc5848f04e33331cb3afc89fde4a0a5835b14d8a4c0d9bce92ba3d34e0306db60b6dc1f98a1cc66d29fd4a7d8cd3572cffe079013cb716862668a084f19a17684dc77494a69ab0a7b579c82bb50a105288cc9b362408ae97959a844597e0b643920d920c0715ea06bb07d702ebf14466e933148fa611131b660937d3f09899615908adca359e913e51375a61fbe59a62fa172b6eab6fa03ff558efbd716f77f73eaab3f8571a520cf724b38ca24c033b7c8243b89301f83cbadd2524eb778288547835b7a3be2c97d8eab64d6f7dddc1610be331fb80c239cfaaed85144e762fd03b6e65f44a8f4e8f879cb543fce576e95b9a6d651ff1c14052ce20c96da60c5a375148c8e4b1fe3f9dd6fa143d2b72b0d809fef7d0907fe26aaf08dbbefeb1f07ca731ca39bcceed2d68c02ea101cb2d576698746442d6", "344f25bdd9890c1a8e7b4c33b549740f3f43aeb27c4a4de73b7bd97e97019ab6e030de1b6b1f47c497a5219f93dfce58bf001c802efe777c7c2188a7883b142b41285d853e21f5ccd8594d0c112079e29242a7cacad0db845b386106935008e9251c5143e92955a5377e90ad1a42baf3b13426b092af4c51be2697d6d2f58281d974531067ef65f0c03c5f0b5519c1f403da29cf21246bd0a0c74b058347f6ddc8ca96767914cd847885a4182f1e7c5f8ac564e868e4fb83e43ed5504cad2859c74285eba6c06d72a27f15da57567e9a9035c37b2a90a285c6a0e8f4f0dbf1ce72fdd467a4678d80234cd2f305ac6c386b058c62ecf384c622462ba644c4f77e1b0555107dbbb648c74112719aac00f12c2c3eb3c733ae73062a796b4c944d9c5e22582db03c4bf2a3c782554c059e26cd65bc73ab4a06b48cdaad404fedfdc7b427f2bb3bdacd88ca71c4082427f5a324c28ddefcc3c23b78a54d28f93480cbc2a9da7e9305af01a4d0655e6a956dbcdcd2a0648955cd0ddfb2fe942b33116c6238746abe5aac1998140d4920c8db4ad814979e08a40cf8c6fb4e6c65bc8eea7bbf4b3a07a3d5f202fc8b91388ee79af7be6dcf79cfcc5fe62b6c58a3180d766ca7e209c59099426f37479416544348c425a627b2446526764547c10e23b4cc7a395db6a3f7978acb2ff9449bed944d5782256f1589944898a5aba8752ac881", "1", .Okay}, + {.Gcd, "-963bcd4c0127aaa64abac6c43c87ea6335d6d934d16348f57d445251f87252badcb286a6ed22d0346034bc6a31709a7879b0d8fb3d0cbf7efec848d84836e692a0a3bdeb2f2aa666ed70a7b15f8254a07cf1a05d3de457b8a2161b0ca37899e58463475601c2100bb5b8587b37caf3ac5aac7c5c664171b390e96b800d80f7310d4401c6ee468add426045b2fd0aff62074b85592075d9764144fc878e5ac159a55b223827111ec766ed4ab327309027410b27f77ea9e872a05f3d3d8d56400bd4955a50b6124839c9a982dd3596c1f8f34515e7c104fdd796e694737d08cae2d2d422a9d5a7d7989e0016aeb6cdefa458a47df868a75ba4d072e51d07672d2a675f16f2c61669a35f4d61e483507d05111a22475b1256e468f84afb9812b389a40834d4eba21de564aab3c4ec980b1e5b1c0980e4197d362c7d8df9ae4b92c9d0b292bbefd98feb87d92bdf0cefd75b07d6e5a6ee8b63ff743802af063b03f86381fd717c2118dc0e498a23359450231d875c30a933a677323bdeec57eb24ec1101f045f4100295d82c453978ec1379611ac96d351ac8b388146cf0c9603a528e485158e18fe79ed5cba67288945fa7ddb9b02a52133af2fad54a6664d01542d6099da0cfd4b6b07d356ca11617b9b32b68f06f9d4f89beeeba7e27d9120fc2f2b20a206d4dc6b9154ae7f1eba4fe9d917cf03a82eeab319c8be335551be0c0", "81ab99834620d6825bfdac24e780c69054d3feb35a0dc2a4bb0ffba1940fe63d4070c7b6f252fd23c9cb49b975e31b06eebea735e9f08668b742b9bfbddb270a132b2d5c06b0e46c07530db6e64864848e258ccb4c1bc13580b7ccca92b289251f2ebc7171a71a859ea9d0d22c0b8d6e7e16a8e53bacc2363c1f7a60db3200115ffe18915f7df3f97936b0656d41c449d9aaaa62bb67cda6b8006ac569a2b8ff71bfe398aa6a03c667de9ed77f12d1d5e31489bb1e125213d4bb9338a2f0f1faec9564859a3ac91b8a688d74451c60b5ea9a0d308cf52b3b188af938399bba15be4051a189e63f459899aa9b492a1837b4b142c1a2ea7b57e5da88f8146585b024bc33f81d1554cfd80f3a9ca7d93f729527428e8249137976a914673f99bd9f72bf49552f6368db207db4d43c86de5f4cabcb214a0a3c8f653dcc4ca36bf5b48e6e325cd65b4d2c920beef3232ca71d2f79cb931ef57ac76e674ba7a6b0a160d401271fdac41a432a98c1983d25cfba14a0fdd62a6a993fa3de756cd135c00d109619bcc0eb6a161dfab7b5cacace594d75064d59a5e7e96ae428c671123f031a526094a5fae6d415000c31197bc7ce2df589fd7f0a43b4c578a8eaa1e57892df25842579589ccb3b7e43feee37f03e161a6f3ecbd32a2d30753b4eb43200c1f616d4f05db7bb8ae1185ad752f2a4047e36e82c1fdaad5598bb97c61351a9be", "e", .Okay}, + {.Gcd, "3adf42b055e093b5122a123167456aec2098bc06207216d33a0f0abab26b6f7bad3fa41370fdd343615a0c64abf59c961d7f3ee72903d76ba2252cfc307a1eda6d1589d34b60f76ed4d91542af93d64d4ae276d1cf033d113d1f326d2c79f97f2c567bea20da9012238dd8dd803bf701cf8a67944502128cae3646881817280c9d40a6dbc2141caafc28b314194e16369042f37653acd81f4bad64b3624e78460accfc82fe57438ae97d76d36d23898d2dc6d4e33c6af4bd7c0c67235d48eb8fe49f3b3f676b0d4802de6181edad77f19a3a3acc593f45b86bf630837884f79ef9a20af0df2e09d47854aaa3dce464a4f491df4741f4256aa74f45f43512777abaff1e26f1a0be05cfe271ba824790a450ce66a1a7166d0dc6c87ac9dc13f42788bacee632b509604a0cc58d55baf73f481730eabfb8830050a7bf8d41c73a028f53f624d85d7354bc248040de1ff2961bbe3d589de0fff3d03e3a9a040defc59a4b955d2f30480c961c4d847acd9ca0872f28b1eb4bf000d2f95cd839bf247ad515d3be1b0acfbbeca9b4944fa27cff8502ec22a38b882afae60b649bba776c3435d48bfa2d984d8e0e1bb2488c1a66e0fd4bbf2b5ef85c94ac52eccd480575a65fd15876d243efdbd9b799b0ce9266cc81798c0fc7a1272a2fd5f7181b22521525642250dcfec65c1fb29cde6a5796d15c514e9e7c2850137e5564a453b033", "62cd89c382081606ee3532a20e44a9257bca8fc2d505cc864647076c7565e680ddaa2b003d789605b33c7deb58928c2d5e2c3cfdbd2df40f1fc265cb23784e4116b111514d6c9b482f91b662e66b3b1afbfde3ce5fd3fc3ccc19e062d7a498a4e721ecd3c3d7d60ffaf9e97b79d373f136522383fb2c3587b89c0c2c9417d9ac28a5691d6145d2bedd7e134358a95c35172a0953d77ca7bf0c1fa1652397d06841456755d3388a0350f2d009af347e7d7f6a78ef80132dc5a4eb6a7f7b283a75d02dd4b47ef8e8237fecbb1e0b88004294edacfe43234f5edf49fb3f8576e36c15043f20fd564a2abf98ea767d2ebb638384ad3ec908931b669b558bf29fac9a8e82d53ac5cf07b4cdfe029d31c570e7e9a608f8f9889d024d5f88ca213d9ba59b398a61364176a4fa35aa5ecaf56bd8051aeb821c8b383f71c6ba7b521bfdf85410550edbd74ae8da00586fc43b4dddeb2f2fd535e986115f705f7972922a09f9d26ca8d990bca8ffd1698f61401362d9f67a77435b9cb5291667e1d2db27bb0cb7d1387fd9727e8780819727de86092a22d76c26e1fd10da751a58a74dd0018eacae3aa375e8b3685e996b1b2434d7873795d4595e5ecd86ab0d021e271fc205be23c54a96acc640f29f8f3e4c864d5081b61b39ee8e72c64a19cb00dc693a26a6ecee0ec1b7c9b1dadf6c4cdcdc9b6fa0b697c8c2e77b83fa9536a7a6230d", "1", .Okay}, + {.Gcd, "4a469dcd2aa66a89f674bf88bdd7dccd74d816fd4a4cd2df23399b6aa9bbc62ffbc8e7f59f21de4bd55b2964f7eea25a297764ccad3bbc64c732c09616b943ba9cce48f97c3d0e8d49c35817d6b3005b9370bdb18b0afa305dbac200932f748390d39da7109d20ea91285a661ab0f215e1b0c828990dc542e05b497ce965ceb7c3a29ada643b27ed868a47afc26c9e9ff1a4b975851005d3f76f0d81f26fcab6ca8322d75de98fe9dc748c40a8632b5e9698908bcf48f84810fb27299644ccbbc735dfada9026f42c0161b31ae82eb9b4a4ce966706103864f0c99daaf3e677464fce0746da74dcbdefe1a25958df27f4acc24bbf07d12fbf2ce954520259abd0fb3b2dcc424320fcce028d69fc02c0c2d41adb5ee61efaa3aabe501d939e180a2d28a8622509729fa51033154629f2b15e3216362d262d030d94826c82372e9ebb01f85ed598af905d94ece572c84a27da6a377d684841c2e37fb418f224c67469e5abab02d3011c87fd0291cdbbd8128fa009c85a7674eba36dbedbffc25e37a3b8ef0e22fe8cf90e603a9706c112bd1fc2e73c56c954f7e02c2f435892461def6273d7822fa050a1a0928f729dd420bd12045b165a65381c6d51299cba077a4b87ad40f9c3f3edc2c263210887a028992e6e1798401abadc9d05f7844a14a83168f1cadbeba681ee2e92868beda09bf07f2a567b22479fe2ce7ab04b7cd46", "97349e541b68613ffef59e5f4ee68350ea11c6adc3436da58903bceb8f9813b745192b07e45d1426e7b4b350bdfeffc14f012afc7e55adfd861734dd39583d0267593be0c5c333b2d72172191edf4fe0e57dcb66fa03a37653c098a60e28a950a9d0572c79ee4113657129e80eb3f1047d8ac01ab66b6499926920831e514997dec808dbdd46bbc59128d4e662678e1414c8bf461c665b7050026031ebeb614c1eb97898f2442252308cc585cd23a3a1b82878731d7b7fee0a56bc0f4762a6c74667b4b3e60d73a0711e63fa488eb06af0c341679dc0216e22eaf3c1b6135d7d7d07a1cdc79be7e03730fafa2183fd9e9dbd9a95e19c024b265fedbae4da2002e9a3fd6ea0d66caa2fc56d915b5e51fd54020b072ea70ad8e716fb06f9ab60707cd7b00ca7bd958db42d20ce5d1c04bf8239c09baeeeac1154f5b99a09f9f4b114772d250580d7836f9a2f23407929edeeef09c5c5b5604972750ba2e1fd17bd619f7130b46f3d6b8a92c094a73c77b944c955265e412dbdee228eb115f3ae9317464eb0fe81cba7c839b1f4790f35cc7b9c3bfc4d5cd8f6b8b5cff5f20b4818097df7472004fe482daa38337571d5c2fdd0da1705cc921455a977fd21d6fd0a2d6d470b01f910e7d0e253c554d7589eae45b5f39c4e335f9dfb8efbe1400bb06b0d285c3b7fc2c7da70e2f65ef5c5aaff1da1ed55d216da4eac091dd9664ebe", "2", .Okay}, + {.Gcd, "c9eead0e4cbf13a57c4aef8d96bb505bb87c732296b3bdaaa8ccb8da61b3e53ce144ef2eeedadbbc739799c28ce845780453e30cb9f30d297939b4624c7febc23d18b324c778570ae5ccbd747c2b21a2149390d346ed02078a1dbee31c21ed330dd37792508d9fe3d3f9a811bca1ef56c6e9a04992880c9ab6e73de0d23b927e45eb7a26c3bf83c04a018cdfcc790c5067ac46c3020786e3c1164b39f22ff3d995842976509fb008b6d30443557c5c3c4e0cb33663b2b6ed87fb042ba02deca407f4d4a1f3c65b0858a3a37ec1bc6c93fc1dcc13cbe01457b04d89a53db4d87cca8d34730414fdf381f435ced96ffa452503b301342f16e841e9d7ae18192b9b8c3e92bdf981f97eccf63578a81473ebfc194723c84121525c0b29ddba9eeb5cd6c719bce354caf8db041aaa801bfa5ebdf4f6a7c950f697d0fb3482f1827ef30b96270bab69338f6181d35a021e03b40d3f56e2ed9edb18b2dd433b8f5b01c895be3b6bbfbcdba77e6f67e1d0d8f153d0b7ab911228ea8deb47be119148e5b76c8433f52e05994e3711bb1dc9b8ee55fa358191c6b1f815291ec82f39c527739036776756544a6c57e6788389d08dd26b281c8de75f6420344c1f77a379a992cefadb702ec10d68aa819e17770c80c85848cba1fb1b0563ae6c3d5ef0c8471d30a4bd284ee4d3f529e6210ef621df850949adf17a643322278947c9a6e83088", "83fb57c29be52cb579ec251c527f3cb0cd52711ddc17859cd76807b8e73913c72df98eb6f5e3b3659ede4230801e3029663720f65a5e7437bbf765a956df1bfdd50995f7749b52e0f38d8bca0f2b72d012dd08fe41c0c5f738c08ecc1ab3247f25f3ec162797cbd2e0ca50c880e959957cb4911f485b620b5a5fdff6ead89ff6a7b2a932dec298873f29df8ad821148ce865885112a6b5481f8f495750cd5a6e42a8c4fbb55fa32761c78927b1dafbe6279bacfc6eb3fbab0d52ccec4e030dc1b302c60979580caa974845bcc9cd35c3f8a56193a734c129e51fbeeca502b28d97d4a2762e7bfcfbbf9623a9fc00f5883d7f6db19201d468df27e6a6449c8c955932ec1067a70f20b28e30beed5aca6c41e78a1ef8e56f0a77f9b8d59c2b036b018ce5a85f9c25376b29b609cfe5f05de332fef0b565e9b1866fe0991854691d026dc49b97512068262a7a896eddfc28f560b99d89630529129380b9ced78dbcc6898536d1be4dc377deb54cc53c6922bb229d6617acbd6d9113e9044d064e3142cc886d7ab667c9ed77b0728100793c057799a79622ef4d6268ee90681440482d85b020051fa8a7f5f1f33912c92a6d266a35c461bd37c48e586139b6fcac337dad79ab77136887e269c2f6636ba358ebef4dcb38f3c1829268eaf02f36588fb96bfe6a8eaaf18101d52ae0e98b644d7e6ac6c5e775d7142b04d22811378aec", "4", .Okay}, + {.Gcd, "205def6c9db752043de491d230f1eea097fe3d13a6df16f5350728a728f8f1e599111562957cb17be9a370c396df013c684a8c192e97bb81c56745d3fa630e19c919130a5e2f460740f06209f5211028809c98427a4e2f29dbb4016e84928683dabab4fd866b980fb9c461b9d158c2558bfd7e6baacfdbf3dcb72322695b443f74ce354f2982acf827091be38aa3bb7b2135db6921e654aae017d9dc23b0b40d866459afaacb8b65d6fc9ce470919b577008f8dcf44336466efc2411554597d10376cf818f0874e5bea221813e3610ca9470ec6bfc2d3f1c6c0627ba3a4be01ca1ab00cbb470b774f5f3a37371b4d2e992e64079017c2bbc8b5ae500574b226c91b2ce7c8a3b227e5b181cd21affb08cd662ec3170c1d92a59f5377f0735cce7602f0a3a3a29fd2736782340dfc2a273921379e584ef23695feebeaf1db9ab751931df9a33b14f01ad9b84b22de9b24d741ff5becc8ec66ebef465f08004066d616d92d7aaa2d83d35ade1c55ab9ce683e69969cb894a582ca49e55ceace0b05aa9f6d4b108200b906e9be0fe7acdeb1bfba88f14f19e8bfa1f3a4ae3f0552526c641d847219ded8af4b55e1c6b91129b78d9252d67f5a9bae735f3e3a8f0763b86fa5a8e9cdbf9d1a029e0982df4e4b37f3dc4e18a962da28e0b04df61599b85096a5301ddf7ef99478ac94be9fd5181761ccac7b806e003bf6d16920989ca5", "69d2380ef534220baf487fdcdc0edb3dfc3c7b94c1c7d8cc754ae186dbc711cedfca22772d9f628c53097d4bf9240a48e394b33b2541699cca1a7505f53c02195881dddf1edddbd546817566c85649b39969e660aa09f51c25ebd02c14ffd0e97d3db63976715e1f71d13ce52c398dd4227d31827af5d96a4765c70a8fc26e94a9df13da8ed1aeea9dea45b2f6c17ee5ae308619019ea804345feca563cbdaaf517a35327d712440feacdbffa51e6cf23fefe6216c3aaf4f7dc9f26c062f329abeb9b6862c9295369b52cd2563b33126db9d2f97895bbdae96e21f5a33e19062ea69346cadc3c5df6cebbbf14a059ff7a6b09056e29696b412a407a1a050dc44fd5df6ad020212a563f2a14f5254b5ba94b66e833fa4cfc1df4deb5a7cd86050511a14475924376c62c7fbfb434c68ab375e39a50057c5a14db7a926df0deb0272157e75c9018443e3c80aa3afd5bb5e9012bcab090294c817b967a700cc50c5b07402b1d93caff5de8f2ff7bce8157980eead82ff5e3a11cb9e5b5632647194e014b46ae1d4a88e82dfd678537a03c1ad546425f41e7773d5f4c537f90be69ff8e9fc409e7db8d9f39a4a2fcf9bd8e11ab4b4e7bbffeaef72995d1689fde869037891504e00ffc67e7650b9a0369d64369d46f6cd9a67dce3727ddecc86356ca6e3fbe94f80c5d7d884f9b6552ae81552c2ec7d0bd4cfc04748eadff7884307", "1", .Okay}, + {.Gcd, "-784340d23590d8a58e0ebf92afb9f45c4d3d0d8587e6c048ae5aeaf79c625b9d41709c53160343659c341a3bdac5467480fc5fc61f3c4b9ea80ad3c0fcac1af78a8687d858af455c6cb5159181232f664865329aa2db8ad91a21f6c7646539db4036d5ff6f4255deca043d8430b2699c38adaf0af72ec1c37a139b9be80928178ebbaf51b0151ebd3d54e9a110d241d7a20469ad96c580fa0f9fc21a6489fa9f5b9c2e4d73d7ce12ce66d0b2a6145b3e3c08644c35aaf75339b03fac86995d7011acb7a551c0222525f6a50048db6daf83249025d625d4f139959cfe14a683097bb842454962f1f22b5ad79b9ab1abfeda5c25df485770a2394209be243109d2832aafe06de3316045fdd5ee30362c53377550ee63f67ab962ec20219f8b64ef269979241043712e0897c9ce9931d5a15ba58ace3ca3c7ea330fe6433dbe26a15a166b25c597a9975792ca13afc65c11b740688836361aad7baf3f63508c025802b35366cfe2d63347381c01e55944f2cf4f64f1e6febd4c98c77180dda295b3c3533f475c29c8f859d65e36fec3b9cee3a7034e5b46a1c0e6f876f190feaab014cf2b653eff0f3eaa7212b56df783196d0fa7b27c4d0ed34e9c546ffcac0eabedffa763cb51068130b101a51fb15bc9e00283a4d12dadbd3aee8962f2dff16725643927417be7c27417360924e3a0d4cbc328cd72ec1883b61882a6f9fd16b7", "1813e1847c84e4fa3ba6defd44c3036e80451d971010fb91e5dcab9c8533cadcc3ccc3f38d5f8f79bc3893b91899276de50f5143d13c1e147fdcb8c135460721f3c8b87e2ce183d1086fddf49119d1bca36e5fd88374df0256547d1daad78ab8e58b86e593aae655f6debeaee264f295de2a82d9ed2ada37ddae6c8b410e91f63398fc00637122ab7dcbfc13b1d9819699aaba1d6cb15793ff4f1e05cb82f1ec81c11b377ca4857aa393bc7b5f7b349873765bfafd23402068e485839c5c634e8dc7b8d32edaa2b25dcd744c3cf5f0024f5e813436fde06a1c8f60d2aeeadd02fa380185caed7441e12e1a624981e45f8c8a9b7fac95bddf5259c1b0dc542621c9045520bb26be158a1db18d030308b89b398ab6831eb0078f3a729e87a0daade93d1df15620c3f9ff661ee78f057687934a540f410f85dd27e3278463d9207887d4cec9f967b12a5ad7d8299a3ef11c339b35eda1d17807303fba6f44e5f366b5cd82a52f52eeb17bfa6bd00db41fc5340cad825b201e99ae2aa5df68df3a37093d4e2294afb8090ec79477d6f7b0b1bb0daa9be8e67e1ef25a387ba4875d2e1fe368aa3114216f6213803f2e187f50008b9382b577c95324a2b5cee7e6600015fe0b01977872e54149b21aaf7ee2098073bb8633996244ebe0b400ee6bf2dd18ff1943a267a8f28f7b98c33764c748f5339b9e4362d4942ca82df541cacce3", "1", .Okay}, + {.Gcd, "28be63d10d1941ddafb8f2b720a2068a67643835afada47b2ac400322372c8241539038b54a392dd0c77406cd7dfdd84cdd9a805eeb8e8e634f431cc8c5929662a2d0d5721caa7b0215fcc089b910ceb2cd71367e22a1ad743737041946faa998812c618832e5c4ac8071e7f054a1986d1f53f1b5290c27eb19eccdb0ace8b01e4061e7ee44c8fa7395c0c3656848f08d17bd2963fd25e5c779aabf96439f3fc6d35f9c7b85793e45c368713836143e7973e5c453d296d8fa45f789a8f446f481f057f8bf2489aca0ccb7740c4eb5f9b7ca5cce4b195cde5569a81b715d26304eab0dedc312d10f9f32a8221f53768c1e89f40a59424a43eb2708666992b641671c7fd93749c5a292bf5f514f13b461a254d032afc9a7327f9d8be65ef32fe57f5d465fba712c688769fd8f32aa073bf3cd8bd34087c9c0eede274e2c07a519588dfdcbacc9ece84b31ad919f55e0c6e7a265b8a4bc6b3270ec197eb5bf4162ab5cbfca690e780320707ce2afc8a688d8efe9857eab54a3309bad4a6f867a6f27ae272dcc0070f57b262fcdde8dbd3b2d8c7ec2e50c92598c385e687211d8bbd52bf52fd9b4011093f626c60448eb88321fb4e9c2d2e19d23aaa4abb1d78315370ca6929fa1819e247250f560503239ae50973dc61475c5806614caf40dfb2a6670417aba6b0316b331b0fad5b12724f122b8173e685bb4381d452f0546b3346", "bd30f4aef44db1b61a1290283a36c80bddae99c05340ee76bacd5f4a0ce7d07e53283b22a33ef046145ff78a5851c180b306b7fcbb723dbb320b8bc17c06c0fc6ca739516d5a0fe91584a45a1eab5075c8724974bdc22400025c23cfcc61061c6762e7e86302524f28d7aeea68da31cdc46a7e43f5b0552bac74491e8a9646d7a3beda6bf3907dbf3c3885cb882549a15a7ef29d0f3652f7f1dbef925ad42b211fefc9b3d63c51ff3f65a3993e6ba9fea1c230f2ad542a46f2a5b56251be29aa8ed9a2ac2e0ccbf683c1a39b52ec763fe7eff0bc91fce18693962ac87243199da5c90d4bc82de062e092e4ee54abe53af6eb2ebe6aac28eb2261d1a0f29032088c1188efc6f2e9cc1dbeb073d610845453883690cfc334f6996c3b9c8821c99c3761a9a5570c080bbb7671d90be27968c2d8ab550252197695383905d33e25a96fb7ce6a58d7c7bca6ead18c1079c96d36205ab51bc8752f50ae6c96f0ea312c1728e7bedd1c0cf0a63f93e3b9004fcc26f92500192f5905eebc340cc32b0feb8df60ec384c2fb87baef77695066dcbbf289148ead2ca2be7fd7ffd0ccd28f2c64c1b2ed14b85496d792049ff8e87dac4e92b8695867f955f83f2e24d0f7ee9d7c52ff9cc7096aaad8864a40760c8b0ecaddf1247e89a45c96523ffc126955d7a9a7b68cc6a5f433d2a0b2f7ee8c57f82a4ef3190ea8c788d139429236024a8d", "1", .Okay}, + {.Gcd, "-b60cfd06c72aa2370a1bcbf5554fdd75668917fd0926a1650e9d33e72aaf6abec6f4c03ab57ae34bc36cd5c63571ef80de021e33aa2a26dcc2a2195cab6656a69dbf7857f1c6a75c85a6a8e7f7b8d9f51e033a2996aa5561775963cffeabc5d46b9135fe03757ee5898f58644abea77198586aaf3dd5960ea5a7bed351ed05784e750efe533e064915ce6944cf1efdf5fbebfd3ed98e470b83912eb467183b8e09c70ea22988ca6eb354e2806a5290954887d5866d02546be567e136528924a96bfe3761e494674c5fed9d81e4f610958b35eb4134f4b15f97452a573806a6fa1855815fd0f374ec58cc51e847baf61ef71926870e10f1860cc4eadb1950f1e3b3c9438993cb733983590001a3b7340f50b7e5b5a56e4162e17aec7899e8f6adf2df640ac76a97cf6c3c6d610aa39d54d9fd440c7b063b15df4810e4546e6b19b5192231831227a5f01967f6fa4ac3cb2b8c2de16e27128bdb412e24bc7ca1e98c620c2f571ce9146cdf1af682b4d36219435dd6e39cc85b7b24d3a7917a1d22e4ddc4ff979ebb72d44a7aee7e7e892b9d853efe9dbd8b951564fb7dfdd288944566e28d1440068e8b77deb98d87ab98a20351b57dd1fe5d5cf21b3974c0969af9f15f2a03039143eca3d6ba42da8bd8ece218db034fb5e71b9b8e922daf344924d705d384c1e676ba01ab1445dc4bf1ae1d041a84ce3d084cdd32539b3dedbf", "783114131e033b55471a15df3a8d67307b5107eb0a3ac5d5d526a3135c67c7639a140428686fce88dad90ef709d6ec62d1b0d48758a91131264756869c87487cd9a8d07a242bd5ca4aff6b14991226707aad96e2e18589207e880d82798e6d6b1fbb6bbcbe22c58f3e31e075302f750d845c3d160fd47d237f8fff9e0a305ad6f6aee2ff54d7961a787c83479dd7d354d62ea8ba93b77e4fe0bcd14f47a6ea6d722836f1a1cb4f6dddd3adaf5f3c0fb58d69706f47c396a73d29c63dc6eefbb60b7466c2e64ffabde46e11563b0ca071f87482322603ab9692bf0dc22b733f633b9aa4bc9f6264048cf460d82baec91b274b2d752ffcfb210d27733d869504f0e14eca102ca7aced406cd51d39edceeb6fe269e7c2bff0b7b844c883866cea2ae85462443a985f8dbf63a5aac66450b4a7f64827ebaf23ead1b97c38e00a0b3609bc5745bb02f68c55b4f3c7a6ce5bc820e89e3dadd968d7fd6e336afbe30143bbf60450f07dbbc9591e5e3ad70f9efdb6b310ba1eb1a69b2e41d8c1ed01ffb2fed8aad4c8a74f9f2618afdd1d3f8b5ba83242b47bcc7c611195cd0f99338df83171d32b284c4f40af9ab108f4d20e6dea931b8e3a4323e2b2255f0306bc928ff22ace9ff229eecf1cfc18b023c33db0251adb60dd00da803baf24266c725fe2e329715edce0719cf4196c48ef3796c550a6163b7a336a00873bc2beaed8d0ef", "3", .Okay}, + {.Gcd, "-f1d1073cf266811b54719dd993bbf4448c85bfcae30d5548ed9fa8b79cd25d3468b7938639452f29df62cd2d5bce9f21d7eb56dd05f3dec94b2a21a87dcaec7c731f793fa531d4a6760206b28ed41c085c3b6b6beea5499ae879d1632ed49b7404fe9c8ed63ebc520a905654dd4f73c19283574f13623ab59a17cb7cb066a4b2d516b029039bea89004b5bb5f8fdca806a4a1b549eacee0f9b366a31581a3860e21b9fa0af3f574782606b2aedc09f1d4958c72f1e0cc8cb1bccb7a1f126e252336d2f2348042f568ae7f552f66db1df4c28510f9d37eb2f14ac7a12e3b963031e5527f0e45e68dc37ad672a91806d05e3f8cb9523ce732cb8881e7c5e2bed67a20f8d1f7029b4cccded4328e3938c183f61c3eb4afdd44ecaff59cb74b0a81641dbb42480ffc9a7136299d6a0d43e1418029743c6af35fe785c80eed38cd888e15c7fc71ec22dd7269abe7330c589fafb1d652e1f5ae51ef92279b8e82ef4c6411359d5641f0d856a378b0ad0b8fba4a1f5710b3fb53adcab84f2397b59584471243341158a92a28d335e565c53cd511304911b91b58c481d548eab3c463748ec3bd6efff4f6f763b4acfefae9dca7b18572220382da97d6d948120cfdde1841fa89c2f6ba586b3d02ffbafc8fd9e1100441cf3fd1c966112ba518c273e7118fd00ff4c8b858d818323088fb704e3e39094721a5222766a175d04b9cc3764b8", "2b41f0a4da5f330c09c41a4dc051f8acf21395347b197b7fcd7b4d0ddfddd8860d251aa5d1aee766dff2b2a69fd7dbf5ac0a7d38eaeecc0324bcd1076389fddfc17011faf18755048baf9d0189aa289077dc873111c6f1150aa35213e20e6cc53801df9042b8816979b06f4fc1fab8a98388f101dc0b5aaaaec7faaae671c7ff255dc58ad9a2e5fefdd5de8626b73378457c763af00eec41f422d2b92ed578cfd39bad4cd9bb78d47c64a4e9e94c4043446edef8606f4456e2146d697d7a961670a6ccf28f76e430f92f20a44318a81c1fef20fbd67318029409e6e22b93a61748ae6a5f6a5d45bce82572a2a09de43a3cd429df5a3c06317d1c38c19cf845d361496edddfd605e0b4979d688df2d6211e95acb31c22cb62ebe7925e84a48b6f6ff08eaac559edfa4939e787520d25b29641b4c337e41f1f41091c97754cf47c7767dcfe97d12df701944d94fe69aedf94f4a5b071630237279fc0aa06148fb18f28ac1723fde12a391e7a939907650e69328fd24adfb30b7e59c4c9123c558a394a993b10467552cb3d15a1b98eab90075988b12a40896f7ffbda0e0fcdb487a22acf2c13c576f88a2829c0abd9bf3a4e4d5f76c1f49ffdbaa5b744711f4ccc4b7b0a5338922b4ec4163609b471276bcab5273660eac2963287cff2d0ebabead577ebc438133c146722516ef51d33fc739b92e83c72d140100ecace13a0f511", "1", .Okay}, + {.Gcd, "-542dd1d88e7876c1edfbfde4a6dccdf9e0e3024b05b6213a70e97981ed69c9f7d2da6c8a14ebbc21e5c9fe60422ea8f4d948e6419951be19a2b7cfb5263b56e42b3d8afe509917b4a0e88cc185bacbaf9a1adc2e554da447d407156f0b386c7c86e3cf0ce8a0594e2816ae4edb52d6b2d95f25c2057e4e6ad9036ef00f3b8daef72317a374456060f7262b90632215ceb19861e06b4687c3d81c9ae673690a8b142550d15edf624e15a18c85956a387b52996e0eaffb76a80c7b172629101740225c85c00a26f7a204838b529928fcc1887ab5db0c4922bd3f0ec287744eb91bb878a92c74d9c61c3e27f6aff838b81024439db5bdba816738f9f90c73279d7a4426c88b5de9c6132656d261cdf978333391585ce9dc673c64a82f7dee59fdd5a6dcd1e01c8a79f7aa6e451fca0de83f8fde0fb30e147c09c749daf866079ba21b801ff1accde2c577c6a571381905d8cfc30cf822d86fe42ef56d6078088766fc2016fec3612c373069d549f66b9229b5f3c0c2e9446190e67ba86eeff9d3e9bbe360aad9c47b141d51b03a1c367bd60c7078e0f339d7766fc35e1c4c4b202435233929dc488a17eb85221ec1e04c3926690231c94761f0ceae1d45aed28825360a7c1014fa5642fef5d6f31e3e383fd0b2b241711ad8d8c3ade4f03ea69408681955264449b19daff3530dbbb185710e016d58c01a1da9483c187ab50e5145", "cba696e9f0b9b54b5c17c602e042d2d4df5b0aba45f65a522409252cd71269a6b2edb34124b074c80d971c1e203c8f69de6d7bdae49874fb48b46debfd71a6d45b98e309414b39a95fabf132e422cb3485a11c32198b0abf08365373c50cbd85326f13920e06dc6ef3e215b8d017dcef3dc01f63da40f61b0771887c6173244a26dadb332d98e579ea135410adfd019f10592b1ff4bd72f0beb1402dfc4ba16cb0ebf2cb68d3f9dfc1b14a74e3b05fc9ca2e22a5f4ea87886bd5c53083c3402a3052f2cfb050a5a08e564f622244b6994dbb68212d45c3ba861178fbb5f2df463c14ab9c78a4e3889719cc2d2f4f4604f83f4b381a20ab0ce347ba2c53daa9ab01cbfa347e9d069a231fa20d55051a0c9dafb4d7ee3a1d5f2636c1fcabeb4ab5f05bb50c4e2aab070271d8a276924979456169cf5432a665d6e936fcb4284df7fc1fa1b32c97d6f493c7ec2165931de55e5174556c22f6849ae6303d85c20c88e940643c5cbd6112de70b1e9b3c0e4d2f5f3153e94c7ede5a5f565276ef244e4a3449af07b91f0373aac626288aa543506f48529817bfd1c04134ee994d30a5e1a0dbf4787571878250e75c29e5fe03d4493a8c053caefe5a027fef4b30d90e3bf2a19279d6d27e39fab351b32dceb3e8e9f876b65179c72267d4e14a4d4ea4e1179a6b55f14a952dfd90d2b2debf784da8d49e2253ef0f2a530cbed5b2bdf24", "1", .Okay}, + {.Gcd, "-836529c7ea8a659e6182f40487687f484d5aee06c93fb5a7368a61d01e8fd08ffb0c6d83c14568375c390c2a1b9eff160f6b5a1ca09545ad392b183d2cf83c59fae1be6e8ab80a6d8bc2e469e9796a9718b36c2f4fdd8cc0240baf7c5d4aa495819e16eb57be9ac3c0091bb098befbce0ed63279b576d5588fb249d75152a65e1e86ad386876503aacd31f2b36005145e66a5712c03c4bd748e18c39250e0ba2819af1c8e1cc865ade59a22b2bb67033e32fedf3e6549534d3b0b15786097beeab2abcb6d6e16ca0d8c099af9099cff0d89b2306dea04d9b7a482253b24df071efdc03b8f17f7cbc8a77bc74343b8a5d615f37d483eb2c4669ae1f46d925c9f87d8dd4ba2a9a2d8fd690ae9f4b7c88348badd5080534dc7dfa261444b83e1e1e11f50875d09a13ed57128cd3fe403d5e39299ca401a367612a9102935221a27633397776cd8b0ce5976cd51c4d3d2bac14d6386960995bd74897bc35fd42774a7f788cf068d3373309f65befe0a089c6deeb514a278f388bc8a21d2c18287cb632b65bbeca3adc8e176f35a8cc255dfdccddf4b81d758566a8e2a66a3cb360a8c7c03751020dc05a7507ef6667d42a759485522648caa35c7a8fa87dfb3fe036b8aa151ce568295a929c2a117dcbb1edf83f7972d12745d9a8538439e7d6885fe3277947519cf74de2c69181420150f7892ecc47818c058629d47c759e93b268", "c68cc09c5d870a15b53f2626e943a74d7d02d6e77a8256dc1d41f6fa5d0153717ba9e01076f11683c5c10b15968916e526535c138e5f51bd71a15ab08dea7e4251e8bf93baa57c239a7aceeb554c9332f2c07e82c898c15e5453c26a05ea248f6cc90e1444c202d60fba3d0b32348ded064e89b982d7b35807d25db5d537c0ccc1901cb7f7f3bc559e5ea62d54146fd6b73cdb482e5fae8743ccdca490b66458870c680834d38523ee057f2a155758dbfa8e24285ad7eb292fd3334abb048570b38b2275982e3e7c3f05964b330b015bbc5b00db9042dd75b27867ccb065b58f65d59a47d40226ff1cb91436d0a174fdbc3a549fd97ea3f220b0f13b19ce4d557aa87efc5ddbabc91c91ee3d72537d6a2ad3d4f089c5aeec98b62422f402e2ad76c1a4c2045215da86fb08d63769547384160ac42af4895493d19a308d30f074357389e7b765c0bb1f193e8deafd588f5ca8853c80d026c8016532ae4e927b8b3de03aa8a80792232a0eabcbd1697f8a068491ae834ffdf41171a3df32a6564d3845099b949f5fed97deff0a4e5d392479767cdb6ce51c2e474c4edc6708f61e46ddcc12eed1036882870e388656dbe32559bb4b562b49735105dc8f45b112d4c26e8efbcbc38767d89c85956fa1086b349ec8bea6e3122bf0ba1eefb46b85470ababda5d1c571670fe9380eefc0c82bc2b8351eee738ba0e801a2f4f8998f4d", "1", .Okay}, + {.Gcd, "ccae4c31a527a58b780f0ba6e770ab9f299f6f99cde51fe975d94b3afb55e0232f72baf8c9162fb2478cfbb2df7e2635a743f3316ce5ef490c9d813a56fae4a8a5f3f518d69a180e6d27e67f402c7bd1c0c5d0714e1aa5a3b6b473bedf56061ff22ad85cb2668e0d38b86f2b13f0f58dc00c7a0a4fe3c81d1ef42100ecad4aeeecdf02d1e021f3d96b5abaa842b23a86d2852a26fbb4987de8fcbeac95d83f2dd8c3ba0394024741c5caa2bd898535bdd96fbf87478abf196ddb9c0867d35c8b630f8659c4f80ffb7246c65f9e9fd8d7155fdabb9f55492e29609ea12676f0684da68a09a3c6c936e3ec4edf87a6d5664dd28fd90e2573b1ca7c26495203af07459df75088b29e3057e7fcff0ccc9eedb01bb242269c91c60e5620978abab6a0b42c825ac1d6c1fcd94a9c05c8480c09e401fff550f01a73e5f65f2b2a8b5c849647df9b35abc389af9ec436c756554678436ca348b30ae69ff2efc6a14f30b5dbe43112349d7ec374ffcb9270d1a53d098973e9cb7c178006e6f9d2a3d53ecf157da5e2ac10c7b3cdd9427f2fc5e6711f0a17cd5ab4125d87601ae091a8a31b66fa84d38a406f490e5524db1cbee41f785eaef6ed7e905fb9a21d478086b3d97f375ae6e65fc1abd5f4ed7caf374c267145ac2f03861701de4af0f4bf088d1270bc35bdcaeb2cc1bd112693da9a7e3d0e00b94720534c1c2b29bb3e338fca0c", "b3ca0388a6ff3c9a3c3826842813ae955f1205076c33614934196cdaa79ad52227ee34817505307b18e0772b3b6705ec40cc3abc856410ef2792472dbf2c6b9ed7fa9cab132fcedca986094de2c52cb6c4b1f6c4734dd3c4a7fee7b5a019726caa7c24dd2761875ca1cd835e2575679adaf055f4e08968e83b4eb9145c9b8544c995b5e4f27ec01bf73bf7bca33c8e6ac888f8d88afc344961650704614bc7dc4a072678d8f61b9ca935514ee149a8f19b3a02ad4d7925eecea05a23991c751027a7ff126f9bec5acce676486483e466ede6a393f8018a3489ec7bb6c7af154eaed046087c2112fbce808f464fb8c92a7572f58f8bea3d6512843b12e448a62552b3c95a5a1fe565e4a863c83b7cdb0d81a9487658d1915660dcfca130a5243435366f66480717b653d7227a43587beb33e4d24386bd2498344f84ff8d1703f8fc2b6ae746a1094654d4e2f80633fcb59d60baba074043a4f481cf7a943b4e2c127647f0206709bdf8f02fe5aa38d8eefd86720be4a33b1e4c4af9f77ea483c30f0d27c01d8e5a3ed49ce4834f80bbeabd5417d04645bd16a3c1ae462590f22621102c5c2090accac4a19a30742f3765c4dcf66be9fdd514950098d8f119ebd58ce9900be4ec17a5e924edc704a45a63626fd81d207e659f459504de1379119fcc7c37fb182a7e9585fda596f0fc3aba9ea4021a5c31f67290be454707134db0", "4", .Okay}, + {.Gcd, "-64bdad10eb276e0513e1687117a774d3c174032060fcf2b8460061401e274d53e1d3383c278c9dd4a3af90b1279b6382b3d4808f5dafaee0142e7af66b09658d60961039fb56c9a5b651d70162e9fae119490e14c82f8477bfb0e6aae1eb8c0d78574b4b908b08aaf88d3ffa18b24da31dfff2ac016f1060a7aadc27a87fc3f48541bc463ad861ee68851215a51ec7be6ac63db2e0070c22d3d1c4f26da334ea6e7f77d4d8fe0919a3da54a44292d4af10c02aa5c979dc954f192addd81dca20b0740a7854b1b7ba827b05ed5dae02dd62376454a68a939ba07aa4e818101f84efd0de5fdc687b2c4b154e9631381c02c885346ad64aa587a31481f2ce47eee9739cba0e7f1065ff2f923bdd104d0dd727683bafaa738315d29213e7a8b2471a58cb81d28117286efc846f746237f8af1312ba7ddad12c1ef8403b93ffccc7833e30811952a9808d02f5ed2ddc9cd6cbc0b13f1d89f4c73406bebbb0c855a2d0832b88ac1485fb929961647b82e8ca2d0951893a0ab50dce7935fb2bebf0b1f5dd96ee75b24ee54b27766902712c31d56506a83952b76176a474a5f05c36e4c0fd177bae01ae4357e2cd0e22a55560d678996e3d1c4e3ddace12ddb32376accf841c1b76c0f43342262d7b6f7c0cabc3d123b61486f63435ca7900291e4412fe9b1eeb21d2b018d6fca9e6ab410d8a2cfec41122b0b8896e654a42ff169800a7", "a493bc1df182430b273c24b54366dc20391c89d25c8ec146280754be1c8d0030af9e096f04af6be5b3a63f31f0a0293ebde537954d4650eaf23b738259d632212612d9707267c492dd675bfefbdb5dfe9bbd2cb1159759e851116af553b4d0885bb192565ed045ff0b5a8308e65ca159a73d0f576ce3fbc4c1c29142f5dd92c8980fe8b54ab413098d3f533232e53741d51ad70d7e0eda229c73f064af64fcc85167d3e8b949b406186dc4e71327770a1a838b6f4589ba5555bdcb9ca63d5a49ffbdc8559ec4904e213177809d99f6b93d8ea18adad2b5ba22cca479aa7b54ed6e9f58804198e3f2b12f74f2d295a1684c991ea6756b149f5c52579d7a5d0bec98658fac4ff081285e4102c3ad1e09bf00e5cf24a242db83973e39c11a6bf4e9de4e983f970d202309a2fec271aad47831b431eab89e21da60a5f25ea0f87e9349654a904c2995d3ca60baeeda8aa9083b0484e09969fe2a2b89aaa44030ea34c06a673c29705a93fb6b0d7b4e9133465547c847c1c2507f996c1f2c44857069e5174df5f8d86d3631ece275d41e896854b2a96daf51a1862141732f37c6c8fb91a0066e2bcb27f9afcea5624955348116d15abfa21f4a317a788dbdb9bbefc669edb9323eb858eeca81a6fe0db251fa4c9f816e010a4e26d1bfe9e39138a488c74cf91ed48f6d04b27d992a84e0b4582173918c9245b6069b6099ec000a7de0", "3", .Okay}, + {.Lcm, "6184903280cfd109612fea50256bb66b9efadcad356932eaf78f4ac183fc7268a3d37eb83997960f2552b719b1739fa2b73bcf1f47100b5ed55f8ae30fa56926852e3325579dcd1d20916de5944ae0e35a09ef21498e6cf732887da48c18060255f384b2e88f764ffdc1f582860e4663b461b946cc84e10aa156a0c4e0d41dbcb7966a14afd80b9e0b03f136fbcc48197548b32d3c8b03384f1808af1f3efbf9974d9a933954b5c41be922fcffebb5acbaf383e87c76b06b5dbd4778c8c8431ef42c48bcc5574d44135ab2e84ea13ff4d96a899552c2996f4e0895f89898a21e3e5e0172c33397fdfe37751f077696d3c10a4c22949109482c35d5babf0c73842acf01cb18f3549ac2fc46cd884d9a71a36d7153882a45a608131f6af23527c01dd365ffe1c73cde9691a42ac886fa1ef32cbf7142c2a5aa76aeffae59727bae25f8ba3b42f81d611fb3875a9be53433e99a20ad684e0f9585aa705eb0878829587040ad676231539b11979a7d01915d4fd8ed002eddd7a2ca0401a2f8832f6f6c536b17c3367476904a830774aeab83ec82b999cf5ef0820cb385b6018af9ad1cd82a6d440ee87b3da96a50561c3bf7b328c62bab593d27e29661c6a9cffc38e7a1a0ab27ffb5e7b578f139a0464259ab753e26a750c02d2cfc55acd66c77b8ce530ec1b956ad757c0d233d8ae230fe43f7d33b6ada6172030fabf4e649fabf", "-5787eb5823222222d8068f2f1232a2b7800a981ff58ee49c14b2b3f992cc7a64d0bb541bd3cd4d3527e73cde2fa7f6e389e453ff833a4ca31516f57832d9cfa45a25615e53567de0b719f31ecf7dd460a843d18d68b49fd67c4ce1979131fe9fe9bbeef127456b3fcce291b511323b2365662605e759c749a088ede53ee9c9ec045ed571e04ddbd6d04f0eeec17f165d6b8fab3b1d38bbd6bb55aefcfbaeaaaf6ca3c8a60547e9e6908daefb366007b6a4027dca48fc51dad529afb48be94d3ef10085da4f530a4fed416ca172e25df163205977e1c659f8805ca11d7bbcef1459e6e9f7331bb1a909f473b304f8de2326dfb177ecc630b0b398b75d431da0fd69772c1f67d8f2ec1d08573683481164df91b1841a37b77e537aaca2ee7afaf8f3ce6682a2510492918659fe7ff1edce1bd96a3a94a2bc32836e5c8a5924daf47bd19bf11c120c5dea376ac934f5459d19c44c802925ac0229f87b4aca2478fab5dad9c69c74d13c23157b287d80d1b9e2bf82691277ab42736414ee310899cb619756ca6787d6b96fb05efc8243ea12a275f7ab761e171716df4d39f0fcb26f30a53630b9ab5e2e905a0a6f577bc2a3f66f11e3e654f0a0179615c564f80510ea9bf85f12443e3bd14ba89e67926fea9c9d0bfc40e597496c970f20a29e75c38c7ad8b34fd94322197a93378f309bfdaa5773288f6707de5bb76ec6cde60c5", "2157d38f77ba9b8f67aabaa5eb2094bbe95b800af416a8320ca59430704f4a16f26647ae7e98c141882ec2f51ebcc38004b82d567869a9ab70b15a690b27d7a3a24698b338405c7f4083632ed3dfad33f6402f5454ca5a940c541c0a86105a90fc1c938d1bde64a33842b3466d203eccadb75c92f2c62004969681a1871e5d11597eb340da4a0352bff7ee3b270bb57370ffa692beb7b656a68433b9554b3f72c1409e656f11777dc4db5f84d2e201c59b955952294f000a52e315c72b7b54913896d73cbdced29d571bac005875c27dc6a36ab7b7b0fbde1895ecb0092f90a3d6caae50a32d67639dd8210a65e6e5b46c2191f0e3410df32f71ed7302e7bc299ef71d85de83abc4ceda8081917a2a10558ab8eeb36d3e763dae85388dda0d26fc4f789a4e0c4da8372527899091d0d7f766c36725e7ad37de07d6eeedcd53c757558e8c16cb50ca13307f0d8b3bbbe6ec7444398d62985b98a1842d3a4ac4a3db2fdb819ea8765bdf06de937cfaa98c19b92f05970990290cb00226f454d627bd68e33925b3d81735b32dae4eb2e61cfe93264effb2ae7dec7a4bc5c661869f67858a93e72cf0e99b61f2a5bd65d59f3a867f99a8770083cc8cb760702c88266b20a86a2b4ba525dce4ef613ad90f985771fa7a850042cff7f23bd5aa48cc8b56932982fc1c1c82ef6ef93214051e9c40499e0de3d97b00da8150ad73a5dddd406d955b1391f10e2847db5f9b7a49b44e73bc0380c6946c946f6892a6c3c1d4145e59708261be6c78c839f957fa188db0657fc93784e82c572b04b70127aef07d1ec9f1743d50298091531e6e6c4347637fdd9623d574a1cf6856624a7a363afd08f20f720e2857d67c36c8acdc06786a3c8487437b51a7e78ac6da4f33e169433bb9d288d76592f90c7dc1a03fe321946c0f1e428bd4354cbc0c796602e698fefafad1bb467922e2f8927b13648f42922b8be152aecbf73687886560de50348b9296506aae4978dc6116fdbe8c3eea7b1abacbf09cd0f2e2478bb0e2bda52e30978e5413e1777091433443efec13b573917ef01dc1f96a78883b7c76c7608797f745f7c28a97919caea893dc1c034a755998d62bdfb491fddd099bc0f830a4f6ff0e0dd0360322a022742b337d2573b19e6092167b65a8e9c854799ca581e0432b32895325f1dfd3eb6ccc41f4d43ed98072328ec65b4725e4f76695db623171780fb90364b918296ca60da9d14337940a088ae482b002f4b61b2833b821435eb5d4bd31ee8d0d0f77fcbeff649b812600c99f9f8e80a687ceeae10e2a4576078e309cfcc29400f4f91d3f23abb4edb3c91f2b83022c90b8214a9ae161e6b1e97c0143655a0d20b6b25f50ed93d20cf30fb3bf705509b3dec32b4dfbf738ec96913821dadccfaf8532932f01f6fe82373b8ffadb7ce89155e45d4fa9794fb", .Okay}, + {.Lcm, "90d459f3c0a06025be58304b98a19dc7e6c7d377793d56b7965519eb1edd4bf8b23722633f7d197e30e2e89e08f025b8f5445e03c074b6310a18a2d9527b776ee3c2c05fae152abe149ebe31f3ab98eca2738ec417fe1ed43e7c3ecfd2087d7ed5b0e581dadf6b3b0f89ac3113dbb8948d91ad7698e5e289467c3c3ccac8d7a7844670ad8ea4f322fd269d6183bca57e8a58b33575dea3820c3108c7b33cc802416b51cd0ece294c3ba0105911ad14db3ef173d0ef6cc2db0b0a94fb70e820f19060fdf335bd8f9f97817657530cde5b05ed5b1ce5f62a914601f67c0fbb4946ee4f778cccb182fba1642ea0fa6e2163c4759a43bf4f463aaee07da592f2e80317f5813e6141310ccd5cd3272c494c1e65535099db09839341443f43becdee6dcbd2b408c4dfb1ea82ce088e4a8a362d9823df9d9d4b989be2735cf87128b9c5d18f9401631ac7eefc547f1f4922052b30c56f07b84b597cf0d6935cbbe122c032fbca764378f56455315cb3e211244febd7695cf34126bfec8fa7a336fc8bf400731e637ae6c308b83c830117362db6f6c9d8eb4c4a88a917059ab559a3084d0bec9076e5025a6a09963b1e4a649ba243966c4ce88605d6124945fa782a79787109fbe03dc52ba943d4e22c4d48dc6c9ebc31f169789ca7f7bd1d1f1d1ec6e86746d9bd97da801b8b3259da002df7069e29556cb15aa5ca2400a622f0e3ebe5", "-7efd6854a2afb71d446eaf95158ad64e45dbb232f9710cb4f4e265acb90a95b370ecc7126aa9ef4b787535d48514aefda157a6d1b6d5bbd689d7c8cc1b78742617f9cf5c0c2d5be0171603dfbdee80c54f089e3abbbf3972a61dc448a4af320f98ce2da7f81ff504466824e0f5c0b132a2d1652c40bf43b32e12a31553c26e830a01aadca4b5309ea801647780073ceef93581f7036bb1449402fea87588aaeea545e585975c8ac6f2f9f622c75042aae30db713af03e8a19e78a5b9e9244493bb94cd06d22101c8da08f54cfce02f1d99b2c124c2000ca0dcf0678c1ac6d8efb6560f6ae82786c0047cee51f6f49241a1a8f87279d117d36b6ce3b02a4df9cb255c8b77dbbef444e595f79ecb0415c5be20139a4a788b7ab37fa18edc8abe3f8b41b133d8ff809f06d1d12f98cd299a43a770a750be1ce5aa9c546cac160ff929bbbcb4716df93747c2e27ad00b5c8c6debc43785d7a912d29e1e5d9388ca5d429381a6dab4c39556c6a4b902a255829bab6ae38f58a4208b2dc899c2cad4abbee1559bcdf5213d57d4d561903b1313a6f92b7219e03d9e63ca1e682469795d2cba194a09f7b2aa83968821455cb719fbff84d6af246f54b46a9e1a5b045013b3d3bda996ee20abf0ea9ba1369071dab79d3574bcdd8bbefb8483f8867a7926f3c4770570ad8af842fe0e91018ffd9dc512a63358ccab1e260580a1b0e46ec8", "47d7e12904f6a1bc0d4406e532b80f78e1843211992878abc06683a462207f56bda908689405fb4fe32865ed5db21f0430725b4858f18d4effe57e7e445b2ced1635876e49045280b2099917a08b55f8bfe3baa9dc3e2fe44c24c1e21d8de7b6ece28476761d246528d59e7fdfbcf9fc050c15932c8847493631c7372fbcc8a9e89fab588456cc2d4c83333c6fca1a1311a3b74e120369182bf4386b9f00d9c22f8e04c7aec767454711c0a97f17d18448e06404a835f93189ff8dfef45edd13a3b122157a1830ee6e63a02cdf0b0eb4e60b49db82b9bd21122c5d2048107cc633eb2ba274f2ac650d8b34cc76a48e9a000a3d1d97c50e31563ff7c02ca3ebf0a1dbcf04f5b65558e662b031fd0f7b43b38a7be69c8df223c3513b6cbb0328687b3f3980fef0315ba628c1ca5bd815f6d4486f74c6b75d97fd534757cc3106f1f24c138086fecf3814a3d427aac2872223358d4bdcdc77bb4b942adc4d1045015a146a1f66d43cfb21e4cd414e61219ae1b87f3f86d8d345bc549974116fd4dbe008348414be542b7fd6528aec808dc2917df66fd278167c078171440bb7cb2016be6103904a78e73803c5d22c093520ee293bf81e05ac6e9558ab5e726a5999620d54a4825ff1647d446bc344063bf86e16f1d32f5b99c44bb473904fe70a3575638723b6516b0d093d803d8ecac2ab652d61414f8506e720f9684503d0b239bb3dab8d8882016a35b917df315009826dc9a26f8932e3f7fa3f68315d22abfd5a10c4f0512db0a1e808b8a4e9b9c53efa158138ad965fa462b41db0b3854aa11a8d94a65615cdf35dfd9569a6de7cb3a0a5288a10dc452512af4c8b905453887278b6f43c307a600c319ed97cd186528dec13670c872f9a4eb6ebe8a09b73bfcff318563c77875ed0a724443e2848fb892eb1dafcfc21a4629192e2669c4c6a949054f844b3857226e322d250f457f9bae07bee454b3b081217adb5a2553b6147cef0bea92ad2077a16527f222eb6570bd99413bcf907b7ea36365938d3f40d9265e69688f1788726c03a6d3063fec5c81e3dc6230d94d6ba7c1f8042b656fb8524d6a4f57101bcb8ce063f96c723fdf1466b14ae389c8af78eb2690cffa1c803f5ce39bbe265617b972cb536a4fad331b1eeecd96033921916222f8a5e702a97245cc7b3a7c17842f191c4864502451a76a6787b02a0e31ce8274bcb42e1e5a18a59aca078e244cdcb3f62a6b35174fbae40ebd8ffc41980c70e9b66e884b9bd989942614f77d34ee45aa98293ca3a099bfcf53f65794bdb054b69f01936e732164cfdf2a938b588ae0047ce09e9fe96a23d5b1adabcc4cdb95fd4c47f1f905101749b16973c6364bad5b739fca4baeae10e50af13954c848d2738e5d84a6ef41b83940c127d5dbe78c344212d899be21974f9b484fde97362e6fea960b0e8", .Okay}, + {.Lcm, "e03ea7ace1847a65d119c2d241024010f9a084810365bf947e94cb5d57f3394fb720ca127d8a5d607d301e8b5449802830e6d03c855b9c379d5e0f6858edb223c2f2dd316709a60a4032781eb3d0e3619ba5741d9bc789f34ef5f05633635571c4fe1cfef4a1f18254612b7c2b76b9cdf048d260bb5592f2e0bf6a554f688a52fbef61b9bd280b28ae7068e8cf02f74db4ee7c0ae2976bb7aadc9729a558ee73aed7b43f25491d9ed18616245de414945e3a0127e4753ee18834061159e10fb6fb62b13bcd4548e311096f126573fc007b0aea53963ad306c2f61b5d8360307d713e6f3028ec06ee8b4a645e91060ad8f9d21c9f554a05cf029310d8a492988bf1f3b63f9a17f5b2781648d1c2077aaa641dbc3f552eb671b7b5a1b7d02c94a29cada7949e007822f957d19ecc1fb4f506087bc5641c6b45e78111781f1bcfc4391a06eefbea8b5230b2e8e8c7ebc9890b908b02a9782a30f7d485137d04c0ed577f851e8fc8b4e6c13e3eee371ff393963da754ebda56f0c77a8351a837791bfc6f110f823845b3b578bee044e0a7172fcf2781b5de47fadc1541ce87e1993cd1af56d91c89965882410370b79bb7641f8fd06015f8429ff0bc63965f90f32ee072dbe3391f6731f1ab82a3eb0d80e3bb782d11160f1031c9f0873f82067834a3092191d1e1c006504796274e89ffd93eabfc72d87ae86b7512ddfc89edf33e", "-1c2a74143153349966257c0871b0a87b1a4e0c67aecb11e6347b6b2ff666fc513505597e9957cc08939c3967609e8a95af0a39dc60a604289aea287dc7fa3d03564e81b1b5dddc2facb86d7ac4fd9592777ca40add898eddd0ed6b68a4170a49e12bdd643e81fea50d380347fce1b3753f3e117972c48ea9dde1f9d4d9fbd1f5c41f050f453e67d259135eaa43479f914c10ea2c7d3c40c9e96198f37d33aed8a83778f24799acce00b612985f720af0e92d77d63e291184559bac5627a43a8627cf7004a56a95ce9ebdc15ad7e9edb9eeb1b3c639b68f9bd3ab78a3f3f7743e87dd9fe76bbae0fb1270dfce80ddc7374c312fbf5a952f93799b782e90764909210aed71239b8e6bf840b90e9cdb3c1529b09f31016a20656ad78af28e2fc816b17ba74974b793d3d18245b1a53a63a6935f58fc4ae9d2e18c74c70240332e361fe78075dbc77cb7c23e0833666698d329b55eedfa7a5d7d5cdc7922239b37db684ceb5b1598ac19dafd2a4843d177b36db9e34a7863ff7a7490aad7dfc879030a8055eb9c67f15adbea619819d8ac4ff1b0f787f1c99527e9603c9b298b5d2519cd08cd2a3e91d340c37ea74e717f459829dabc656c200bc0971bdfd27b79e2ba4238c978b79dab085ab3dfb923ace0dfc8b358160e6b895a035bdb1b495ce21e63eca0e00dc57d2cab70b4ab1fb89356995da44d5f270f4dc71c56e185051b", "83958c42a5e99c4238724163b30e8265cf895b20cc05b2d899dfe565c26d5b6a4ece2c41ce7ac5f7d78bdb854b9ead9914bcacb96525cb48f3aa3b91ae4cca22cc530ed0217d5d087c6f2a210a3aa0a50c04ddfc8c361bf9ec69508cf12bda693a26deb8ee3b4770aa54e58f7bb08ae915733a8c39399a92889d5619cd217449f2ef160451c24aa93cbc1a549e6655658610bcd7e2d81d0e99d6b86ad2021647081a68ac58b5ba4168cf06a032a42a668ee28b4cf8c2da72b671736e65658fc990fa3729442f815eb2b0ac118ef6e74e4a486f288740e6e9d6342ee18407340bb54d31a47b2e360afae3f48d36596cf4d48dcee55c2ad0844786efe33cbc09a690ae37c44078e82160d40f16c71097169645965c509878296d0363e9fe358b38381e2a81d2252f98347e926ff81824ce78095209a9153663aaac73ebb5dbcec2602ccc07b56bbdc1a141eebe10857b0c7e2be71af99495abf4f32bf394c689391f2634418032aeec71ccd3836373fd3a7db6ecab8272a6e7baba7d7a4d48ff65ef0b73bf2d5661d37b1ce620925c42406742866bcc0c3ed3f9cf4e89be3355c53764fc8d261cf45df191f76e943f55ea7caecf472ae0ca9c2fd39b81b6e48cd5a3bcff114f4758668e5a2ad27be772fbc2817cfda4ad74957eb54d0ffb61afa2e71691e5f036a2ea6b6813ffdd8d7bd06387cd37605828c177e04f33af89963a18fc7fb244c0552a0c81340017340def428a8016e20a95be3eb388c7d81e8598d0658cb76ff3fc4f60ed96815c991cf6545b4f44a0bd7780aaeca9f37637e34cdab61950fc9967c5f21df12fea13910a14ca455eef272eed238c8fb17f27e84b0fa2b5677ad187ac41f5a058f31441e380068b7c35f7187b379df14c48265ea1293320680998a3554ef9996d7f204234267d696a341acaee1917b5deeb093556843bb052bdaf2ac62b529432767ab8d7103c614211f6948c0c9c1cde42fc630d71b806b9300f51dcab2f9358f2bb35deff385f787af52eeb6f157437148e528303702ba1bf74ea81762f6d8f5b134b2b0ef473c5625e11809d04ccda08e25264dadf204c64382944115173eeb641219168deedcc9206cae2ef11a646cd78bcb25c5cf09b2b7d819a8bff247b11d9c7a9ec6bb34070b7e30a64199c7253949d8216859615f94398710620bc868b83a97331d058c5d787acc8ae0e7169108676429ec8f596f3cc67eb78eb439f07fbe24c4b43d312074f59a11a5f743f50b6e2738b3a2b63b51aaa42ccd29a66e7f8efba9a2bcb8dda1c3300679f63dd50bfcecd3685ec1a725b03f5c67f72035922dfff96102730b7060980027f6c794fe099b0c5ba1bcc0c7d1ab181b94e8a52dcfe6191dd2e0dab8d603456c27bf9ea47b7715276e2e5ca8042f0bbe7d0fa450be77197ad1ef31e1e667b2d48b85afaf9f2e", .Okay}, + {.Lcm, "-7fd3aaa2c18aeab2bd0504311af1cf449d3a540835ea2e5be508326dc10dcd6ba502806f18c2f792a25a179a4cdf0363dd770b65c13f744a5bb25433c561c8cde5621d34f73a802dc82cf9c9b0ea32033b32a46cacfe9b10388920c9752ac5dc09014d54641f0c0a36df6cd5faacb30e9cd6425623da1dd84896c2d6d8589aa4d4df1cace873611ad567aac1fdc697cecf3fc404163cee522ff5c2c8679cde8a2c5c012af131c3624aa26a3998bd97108491cf60f293100f43b3e9ad93c388426a5c8bff97dce870376d74ba4afc051031f8606b1069333002048914a850bf3816ca8e7e135cd6476e6f30f63d73c232d288f5baa1ae0c657b27abcccb41d4afd61ae5bfdba456cd815de71f67e937aa95fb5ee19080f30b5227d71bdad792c7958f449f97895b2f4e397941f46328fead4a59383015eefd8f99336578a7e1258be1c76f400fe75e094fae81a5801fdab0d51baae441f7066b4eec5e672c1a66960908c5f9aa7c9664f6e199e9c37358dbec2fd2aac1328382d2d86d7a68ff71a3183920c980c6cdc5331173b6ab5a2e36d5df50adf3b0c6869bbdc88672ad46359bc48cf0ccdd740f82f484d0fbecb94fa8447d0423b5d1e8cef34204cff41f6e7dedf13fcceec5aacb2e8f781df7e3996109470e0cb87f3917ff39cfcde42548c5e2b504da2a485e23335873245e634ba233c20c3c3a0d36164c374ea4e7fb", "18e778329d0e408be9c490e4cd3d564eedc806f438ca66d089cc22fa384348d62b804ffe88e22ff5d925a5d7a922a57fcb7735b0d6677ef1c6a6499466c6bfd8a89eee140d7fc518e16965902498e37e4d359016f8f3a2d9eaa82eba5c67801b0d0f25bfa0c991e49c6d88daf3ee727eb2f832eaf936c17b15e84131043885f768142402117fb343e3ba19526659cb5c32aba374cbf5fcbf67b2dd3d58d8d21c252fe5cdab0b81e313100feb95661270dc32b942aa15dd4431ce2ee53da45f018c2b07cc183e854e841f9222d3b5553d9f9dd29d8cfc377f26068c9b87c366b7b2743441b8e4170ea9f1e0a87c6d195b0046dd0dc26c25de83607fc672de4f0c1c7fd1e2c8c4fa551aabe052c6d5434cac6ee169da41d8e9aa346975f6eb8cede1b36252f0b4768e99987ebf430f66bcb403eb4f0373db13e3ba249d86d4b20fa0c049b2263ff5c430ab21c564f2ad52c229a098b3d0386ca582f65674c79394b458048f8318de3470f47640e9a830cdf374ea034c5b5558a67d7fa6b97f6e8b9740b85dbe408efb84dd96c0ea93751a7380385a329000e7d7f092d96e0c6c6ac480c9a80ae0cc890ac2e662cafc27155fe6f0d9366e0432c3ffcdc6104fe7f0b69c2b8c3ed8d6444628be3fbc6b5da9d80f03c5a348c5c205d97fdbde56991949f2cac97deff5c1d28f924d6f9ae8bd1339544c6e24bcdb7786884a8eca4bf7", "c6f6c02b8c13651610f926f02529df6b1f505f9cc093d2859ec4d418a6cade65e858763a87b4275f717c7178d010ed714c22eb7d4a6ea8f5f6531b8cc4c12226d6d43f6a94bddbdeea21d1d3e70468e36b7a5ab1ae4fdcf2a28a260080c78fc249377c856181dd1ac39796151712c209319b7aa06083122d12973825795912ec6a1138d970aad4662bc28bf5ec5af365fcf26c9ee53848d16aee74b33b6dd6c4146e0beae15607b7e9730111304ca6d609e8068bc6ac9e49b70901e28e53e41fd9a888bbe7682c9725c8be40919e2cec6c9d4a472cabc2384b454be3e435e4f4050cf4b0d8d0469306d665ea3284a7c99e448942ef960d95f23027e4b2f3c5172b2b887bd186804683dec9cf8b546bd6a8198e5d3a038e4c06b4338aeb1693f96f63c37030808f2a6d7174665f3dcdb64eb33dacffd8940c20803aa63bba25bf7927b5cc8076d59d8d42c16ccb22a24fe5a3c91c5e0e952a1325b14ef7459f988f12777ddf8ba4c602112f47879537458f337275fb3dbea20823d715a21e0abc24cc0cd3ce8dbe9df512adfbb5f0df298342064b684b1fc0af18261e2eb2b8f484286f9e3ea20a9925b4e8eb3894f91992836da4e04d8667e37d544331211e256f9c8079ce3080d8541f4bd06efb33348cd88d7d0ce09dd9aa705115b1b269e900593da4a80338602041ecd00df3bb2d304c006c02c783f7702817e7f78d5fc8386ee3cfd90810f1c59d5fab1a64ebb91805379a3a46ff2ce0f9fc4c03d002669f8c18e966060535ca45df6590c705ce0c93bc9e7f11fc322a4527494bb6ed99e6c5f0bdb8acd407e555e24e6c1587a8f3ee569a49032030ccd9ffdcad27f1034a521c9d0888c1bee5a54c6ca525059ce3faf24c51a33316367cd92f4a89c41853866a48241789bf4b7ae1f5917f854d174820f8352963f80cfda3e89ee013be96fa22ce0f1bf39c702cf14352b8c94c3deab5de65cb5e8e772c6d9140d4fcda2bab6e01f8239f6f0eeb54c314ab8dbc1fd4fe27d8b3e3308266b06572620d88e55c3f1852ac47d4c29d3d53a1fd873676021809456c874560c9d86d876990d7d34e27226e1fbb1bcf7e87abb52451f049d6219e85bda8166a3805b741d822eb6cdbda744678206417801cf38e9ebf67f9a5b494d862fb115dfa1dd1a38e0a27bc6ca4804d08250f9dc1e09018abc0580b7ebb7d207c6073403f8de6668ddb479723a1041d33666f7147614322b5cdf459a784f78c5d6cc42ee3686b6ca3f39851764d6d5cd9566ccd981fa8aa355cad751774b60dc7ebce096b401127217c21f9280b306be67b671f4cd6a0b5b7b32767c3b334b531c12366f16a842ce6d6d88355fc531b4323ccbffadf951d363e7559d2cc4fc062b3aea3ebe02c48e73661582aadb3156da8bd0aa470c81b11222e57349a385b6f11afa65aac177205c2d", .Okay}, + {.Lcm, "-64cd4314cc26301104b057502bf4d81c9baba4a7e785091e7304e958f03e0c9199efef4d4718be85172997e8e9e61db693a505de341faedcd3e7281a191d49e24e863a474f9f659b6535454f8ed2165efc0dd4fb46edd442c4e7371eafba2fc20455e82ddbc32f11eca50a439555a772d242cd7650114c369b59275af57b9b20c4331701283631b8b2a36285079890328df166a2a01d142af4b8235336a38c97f0ceeec7dfb88a4b2e49510434609a00ec38077acf3abef0df2efddc90e91a7c97ff4b2ab22af7a281aaefe44f92dde79abbf128164ca75d1e87b5d6cb496bbf05e90b89fe92da13efc7ca6f4d8032680cfe47a54cf5c9b16b22f2c8c6312c142aca04ced9ded5d0697ebed128146a24d0b0a160a394058387f058c7d2d9c4ad1a2b7e5869fff2711578abec68a76cfa445020ff17d369fc1dd8dd413abe200c0e676e8bf6e7f5d6add46192f8bf98e3369af807feecfdd07f6192cb38ef8448c6c5abd5ee2cd9402e21263a21920559679379e9ad6e87606656b00f6ea22e24509d6b9c43a88271c5993b3d2621f0be56d411bf39ceb2dfbe05a6e501b51355865f9239e08e44a66ca923f18820af4704a3619ce76c588df951c2fdb15d406b33ad4a0da323111566c45354f2819d3dcde16daf311e8423ac8b64f339abc4e5b277426e83044d5f6dd22fa2998dea6c78930ce2b65699d57e3f14af60215902", "-75d1efd3304bc25c8248415b3137ff0e009916420d58c10fb6a81d305857bc08895b0a43aba2a0d342ba42b3bae19a59ee49fd1e79d1104270c6614ed605028e230a73de83ee0a15478b2b02a2892d04b3930f7fa42db94a98e41c3b84b49ed7e4afdc3adc05cf24ad69f6b07dbc945a7cac50a9e705d1004c6aeeb01258413619c7145969ac4439bb043449460196411d8332236fe1fdfc47829aea9f14963d09c57d95f910c74f9abef20abaa7b8982f5fb0065bffe795d42881727a718266aa6bed23dc645e3146ef3e785d0d3759e9a04fecfa5dee4f8e4591461aa150d52bddda83db7e348e26f9bb4e5684a4c5076ca8d36620c41368052686d9664c78599fbdaa8d82955d9dffd482577e8380b4213584bb7c2ca217b59c3fde9b2540f6661e9ed83c43886b93934e98af982be670fcb0ae4d879dde11bdefdb0a83c75024532cd6690d8298b889a7dbcb191522daa5528dbb4fb5b6fa837fdc439326862a5d2e1591ffa8294880977fbe95b3194c7e63303c7b5d7294dd941e7d6e7cf056350f6186b74446a12bd94278dbc242046363f9d02a358dac793434144f53dee9d9f0d9c02abcc8ed34aa2c0f83e099b8186520a654efb97dcb229e97d35623ddb45a500c32725e380806e57732d16bdf1c8191e8be04eb02cfbb1dc2bc6bfb963c121d80d041b4e3855974708fab149f81cb074ecc6c55121c388183cdc2", "17323cd5878d928fbb543997b9a7bd9d060db296fc83a7f3770c608c346a28a70a02b8afb28748fcf9a90e86c30f39c623dd1f6c64523c03ccca771391cbe6b06e98346f1b4cb662de61de24e0f5d6cbec65c79563737da53d94ec4a601f78df72fda529cc3782757de5c10fd23178ff59417e6edb8e54ba152f6cbb40b112f53654bb1192ff729303625e33e107f0737cac121b67386ff07cccf7116701a335556bb50a4e40d1be0f0f1c84a45c7810eb243c03090a6c306a032435306bd14658c256fb368c682b5744e9ded477a4c1267d4fc2309eb7b936735aaa276d3faf6c29fed83d6bbbae93b3776ce7f3b5181140c7a80f43b279dca2a29486d4b5d37f93758c54f953ff2eb671c62906fee0a262b7a0e20bd3c5815c2e3973b8b6629bd748a0440bb8320e5f977070093d2442eee8bcc2f4537b066d54a643935d2a9a663fac2d9ef2c574001984220ebbd438f04b31e538feb716649710c0018183aa583fb7975d1881acb10175b170566dcbfaaebfe5e65ced4cc583a771070b43fae8edb42789d16c02ea5a490038a811592b04550fea5c04d1dace572f5644f9b03287f17dfc4af42726d579e6eba2dd96937436fe8c40b7276d65e618133a8e5a7b8c240de7867bc578de3f6a479305167e5396363801bb9dcc21ff59fd1f30a5cad9c1349b88b95d3abc54725f890e838c3eb5c7c8d9a427b5da48ff6f4810644206faa8aea3aa0a1b5d1fef46a2780e73452b67cee61c9c8b2256c4486e19f8dd1cf65d34b28fa55bc6e40fae61289176b306217ca13b8110b6bcaa281741c2df5bf3a75f727d5277d8d312f663c823ed5b84839602b9b3ef66241cead4d8296c05dcef715a4518f3e1a2dad43abbe35044f65bde3de8939eabf2d7437c6e62f7e830466050ef6f510b7f1ad14a4e34a505659f56e9d914da614d8cb5c6ccba7adc38afadf0c2a4af5779825f66952aca5bda96ae00e0f7388f3dfa95365b86200e0b6eae008135288923c8054e0221d7d332feac3039fbd85033806211c871cafd3428cee174fed0b48d6397710fe73860c184e181a0a1a741e728dfa3d0e1765db55b4a25b06c38ecc9fcf476cae5c9f8912c4d724e8b0ae465de1efadcd1dd85ac50a5082a103dbe0604960dae1fcce1c4bbddabaf6e98125520004e701b9cea0bf1a25d3d5ee7e973b1a9010f938be0b54a766517eef42923faa6137498e3c9376de24ade524504bbd09eb753d3b0edf332b61be988293df0c6561bdcb71c5d09ad014cd4e08bc499f6fc7c15bc214d18ee0837ef26bd5e5926f63c3b3d1f67b40bec6bc6d971838a0f4effa616316334ffcb386c26d8e201d7c6bb4bcf325d519626f24d2ede0e05d4cd455953847f954e8c44247a4e8006f596aac2fc54ba619b0ff3111efad995857b30150f85ac9e2a4c4e1a5edc661e0dc906c2", .Okay}, + {.Lcm, "87ae7ae408feefb502f9d328be8ac702d76a1afed0d556921b7ad71ea81606f86aeb1b6df73a6148cd25c31168eff67f6f989297ea648f133b1b9117e599a9c01d819c67202591e9d93514141ce1ac127804f87e52558db7ec44eee306abd2a2bf570e6ff1d148c3bca5e92ddab45bd7187b02858adaf01e9b780becd9822ea3488cf6b244dd4441f819b4f3005daada3d4223cd4fc0f3bbfec3e777e3fa48e9846ddbea1bcae073c4367d35bf5a42553b0e47a911b411fa36b87cd45d9707dd155d85b295e0a0470d8452fe1aaf78c212561351a625fdc88472f4b8a324ed7e4b69b8dc05ea73735def88885d2769416d23b2a398e8f12523b4682874a7fdf5f3a20f2651206206efc63410fb2296ecab2187a92eacc656ae878f6f3586aba58e1ea9838d7bf7d0d1453cf1bf7d32ae9f6730cbc06429e62494b61ccae7d7b43e7e8cd3c41d00796ba3631476d9ea0866852522a9238363dd31d5b94d3bc0046c8fd03b72fc2339521e73c8a75ae7c1ee7e83a6a49ed31f9f0ed062de9913f2ce4f19a35867084ee09e96604e152c3e5899402c7395f7feac2119c0c487e387c8c7aa8e271f1eecf9e3a55ccc84db1da38401db3866a06dd17d10859d8dfd754bbe30fdd72156e06d5db1ba0a94c1fcde5aab23324acf7df5ad69ac7ebdb340150c60982c859d61b8f04a0b431bef6e4c90fd574ff18463edaa643d7dfdfc80", "-bed379fdd4174a8df159502bc7826dc1067c6725db6be6318ca5c29ff52a09e7b9183bccc8c6a8bd631e6689feb4d7e301948a13b86791e238a52ef87512eb1b1fe5a67ff2eea4dd729edc498441f216e3b7c2cf59c1d518a64b1ce1f97b722f7444d60d957f76d6f1a43ba27d3f302ceec9f98fa2bf47c9fd11d2397af17b018f7bd9670632eada6d3e1149349a834fb77c9cee8601809b925c15eb012026961424c62a5fb27be68a3e50ba8a4d552e2e928531f787774980af32e1698751ec6cda62a029372b654573238d5793ffd05ce04b9bbe4e1cc5f1a3479a1b8923c1e5f63928493733229e0bb1a48840c5f33d3bdea0f543153f03f8948ee5f0862aa0b9f25811000c05aba4e869de65e50776b72eccb40db5929321166b2764a2f8ba8ca1f3c67ddade1b4df68645f7255b42e3582394c4e74e9f6a7228633f67a373da0fa9c416202cf80c1d366b97b081f7005981e29bceb0e028d11f7cbcb2e42d337f646f6515d3f420dc5cb2ae2baef5b65923e347061f1e9d5e691dae53f309ba845d7a32e69780df976d036650bc5913cf7ddf3d18ce46c935a8653c552f7584696d32d117dd13a58faa6d547288ea38c1ad5dc26cbccb6822b71e65cf437aa38ba79d5ee331ca07285a8b60d4e2c471182c33c220f225d5fad16c6877199598c8b1fe9083377a43c98a300dbc9d637870dcb854181a4375e65bafd5d0fc", "1948e52b2223ac66b6881c9820d551ff7285401f3c76c7740d98fd5d50ca9692168170072a478693bc6334f30379e8f8592fd5851641f06f98974804d251171695d88f15dd5dde22d72367c50a53cda6f1797fd5de8f8b9eba9bf79dc8a4614d61b97a2f8b78ac0db9e90818eca696bf6868436ee4e1ae6f21f4daa805ba2237a9487ed889a9ff0bf5763987dbc458371e97276942e2da427ff321289a44dc77a6be988b7fba628994f5123d384e0b315275d1345719c1a36014868920a74cd7813aac2e24b5f826d94571047ca6240f58d7395233125a42ace2418500063078b42c485b502351e332c296bb8c3576bd548f8589e0ffc7f41ff11406de1a3f50bafcde7348d9280d41ea568f50e7147341920f76a9324c5df38b7ed0e4575c320f9b63b7c2595f512f7aa8ee44f3d8502a77200e166d87f25ba993571e5dd43df457d05fd2f3c5cc8990ee4f701fe98143462a6958a1e84f2a72692484629e029c8fdb797b3f7a97b0ff9506c7eca3e7eeb0210ad088da69efb40d14a5a0a826b17cfe536d40d6ead42d19c00a77b3b4647e3def1cc6420c7a595baca0ef141f657fe7d94dbafd04be4baea1dd112b7cb1286875ef08e588bcece905a97b316389e55105341afa16df9d0d80538e7187549e0d56926af8c20a753d3c16f4a0560c8cd06f9c210c40d04b482a48c7d211d8fd674f33f351bf2acde201415310b6fd14ed5b579dd09de55054ec111d52c8f2acbe2bdabb44055aaff5853110d1597e5c968e5ba30493db4e876c26b0f8276a8de44b823e6ce974969321e3a6c6897133708b7d595fde149bfec3f5b727d37e53341fe15e8909f13a5212c04b5e7f52221b41e5eae8fc7fda524e9dbb0e2bd96e415b4345548249042ce37a374fe600eb661baeecc9b77900c6df92797cd2b5c08e737b094d96ff971b4e584b952b4f51dc1ebdf973c78e0f9a40c41e5ee836e9db951754b4d5ca7fb68b36c144f550a90a98a8ccfb43bceb3736c829f747a64e1c1dc0d555d45d2e36752d659ca917a55d5e8874b6139ee0b47bb60c51d8f6491793a981e6c55cc3c2b0bd7d35fe93c9fb3a12423cd9a559f952bea47d881350df2ee14d209edb06895b1a015906a88fc3dd3dd2faabb8da87b06adf30030ca3c2cc153f039d64baf46478203e4719cebed9ebcaff7fb3c70fb94cab8b87e6146803d20a6e17975ba888fbfdf28767274262d03f947a4e1311748d2d90840d0ee143988e81dc03460f08c35b56850e4e23168060a94f7d95b0fffd358d3dd2f732b5f04e07f9d3115b93b962b1a6f9c1d95d253d07b41d3abfbfa4c8f81fb098bbff26e645dab5c48d0b6c4809820a6b1d0ee1e1baa29d7fb83c6fe61555c7e9d68cd5459462242a180dc5292f5913559b9f7c01153585713a752bcd34834aacf4d914c6143eed86b6153e6b2380", .Okay}, + {.Lcm, "10163d80374ca4b45e70a31c83eca4e9d350b3c27a52290bf9faea90ddea0dde741ed6dfbe3ab6ceabc74cf738a0a232b4e8b1cbe813d8d9c3099efeb9062f8bfa793c233d5bcf83b63baca88aa71f65d3fdb44ca3f7bf41b3c2c7f533efee1c18773b10aca5b3c142c5dd21a9b2f68508d7a868d1c27a9e5dfbee10e7f1ffee8fbe6d800932666098982901f51f45e460467876ccbef9c2e616b6a21f606f1529c7b7a774bfa8ea7f71e5fd5ddeaed8a5debc8d8a96ba49913b742bd656ba2c99ff06f7e81e5ee01aafcce289e8c1ad284aa51a0e383c4fc9f3b5c72d96f373edd69cf0849ea98fd1973e3ce2263abca373f3c72750b09a8c88adb0b1b05707e89333fe80bfc7159c7c30787adee3aa4c86368a3c2afba9e1a0a5cb3b4e1f213f03ba4625b580f3775608372274e81b5ca7e5fd564a36b7d123dacb0b99ff8de2862a51f8b3bcbfac7f1e2cb0fd6023501d45d8fc4954bbdb8e6cec35e81bd2518000c3428c3ca4fb3859a4a22f4ebf8eb9105bd75606abccc45962c7d68bf4ac90e5d5b5b4b0a57c12fbd3936df6eaecb035bcdd9cec7330d198acd1e530abf0b761c86b4b96f0d8596d9b2eb191ef4329350fa41804e6b317557cb5cf1553550ae64b29b7943c5f338edf976bf4557c4a6ac98aa638711e34e8d8b73994bda298bc8e0db89668953ea4f64830e40ab0e7b5618216d2ab26728c3f2eb487f6", "-8c96c280ea13089197fcae09f064eb3a59ac7c7723f1af555e23f8dfbbd0dea12fdada519d4e2b8653f8abf72bf70a42c5ff08c0717a801b9c4824b1a852b65e2bfa9a7ff992c572e16ffa2dbd34fcc42b229b7bd44289b8c0185df85a9a952794d6603c3ff71b278be572ab1472b7727699b8d0a8b1c91e905ab56695588626b6c922e9c205e6bec8d14c445203de9b1231692cfe75a7382bdff4f15ab46d4cb7784d51eb6c7895e1d80249ee70762c3d4406aaff990f299af599cf9a441052d94ad7154bd7adbea19ee067f62111db30757582e6540c079b42284c43120f955ed894474a0ef37f2c6c69d5a38bb1b88384c3f238a6b2fd38a9fca35584357a3f72e2a50982e82afc1217e66c498098aaaa366e15326781e7c95817f8206c03bf3c65cbabfc6e01dac7ab8589b4762d4c5aba88eaf07b87febe3a9a3b49ea047c20000e345e1b261a6778e2e390ed82f87b1564488588f69a83a95988a34d0f337013cca1c7c7838e77d93b2ccc2411644ee06fa6bdf907ff0d2070f892c1253a8589fdd20110ad852877986c9a7cf0ecdcf3bc16015cd92d1a433849b08138b5a636b560ed8a43da9e6217d5b97d7e4ea2c51e5504ecee977e139f71e6533ba50a8781ebeb2d41d9f950eb8e43d1b4b788682750baf80b5919e2b525071c46d79d592c809a197e0c1b350b944c42265f2d61051c6262e8a28e7ebdf6dbbb7e", "178f07b2f4cf5911499a970e91851be4ebc9230e305f29f6b4cf74124e850ea6c328788eea5c62c8e2a52dc7f2b75dbd3a5f8be917b22198a67daabde19291181c17a447ef38f96812cc0741772c16ad4020e16ee1c9f6e426f4a4d8ba22c5ce7312691f8fba2041756719c9f3692d1b0431bb8c452704c2579a4ce772b90d8fbea3d1004d5c43ad897a8b56946e6ea69de43d817b7d81680a3b69c0a03fcf1f6d431ed298a7488d181924648fda64528846460c55299faffe1a5cbe302ec09bcdf1514af86fa981bba0dc9b745c8d9e6a6fddfe7c9f6a818b081d79caec000d6c75ab1abc3911e984efff2d5017fd47c694a78e929ff5943be25c77255b89795b89775e11ffb17f8431e6326b683caf772c52bc10c88cd192c85751c2d7121ebb897ee5cca6aeb236105ebeeec4dc85fd3f1317a07bd97a41d53c6455af5c3c5802a89e12172018c7f1fc6bf5d11977b4bfc59015924f12a21c73cab3948401dde92b10f6e381614bf1d47d708c1272aed0ddae9859559fed164053fd3e5bf2d356a7287eca0199dcc7f47b9247831e9f03017b382565ea09205bd2c01185ff1b5717829873ccf28b6cded03085eb7b2d628a21c0b9df3035b8fc6ccca159da7e509e0f2d32b6ed56eca3490df0113dad525f92e2c4c7df5fde816bacfab3c298af366f6f6bda911c52851c4c0bd6d9902fae730bb750c9155d26d38868952b0f4f434aa3e700c056dcacb89e5bc59e2bff53acaa508f26d4c352530ddc98db249e6f5e5c840f9f2be513b5083abb41464a2fa0f318ba02d9a2e2261579cfc012e9c5aa9acf7f2f385391f534fd46423021f369800de57132527759b566f01b2b0e5efd2df39e397bbf25ff8948bafca6b0b2584950e46ed709c725493fef7b75bd2c4ee1aee8f3e45480290c748a0c943d44efe3b9e293ed6bc121e662c12a20032e1e4eac721fcd34a98c3b7e52e6bb13cd5ec47eb65e8011d1039c91ca19efee65285e914aa40e54bb22be083140f1100a48660d9bb121969ff0a68bf0e2a534fe80cfc890686d13d3c38581997709994080980a78d9dc32175c03193ca8faede2fe98124db4cf82ca2a183d350627109389dd6716425a5abded5e30959defe4123b226f2d884b8313b9c9cd74a841719f8fd2339c56fe3c19d49aa51954c85b6cd36b98fe87045a1792dca45ee2c534a825e640824052adbb13d3617de9d1ad32e1a7cf9389e0435425f6c14cfd7908c99e10289a0b487b5d3e39a496b21621797a9e957598b502d8ac4c94358ffe2da4ecc96af2774193562bf45588dbfad9a75919531efe1169cc1f56909539e397bec0bd7d36c4c6709d4d4af1a3f0c24b703d28fdaa91dc9cdf8c5480a6206283c955713092dc0b9a2c92661d1ab2749892bb5c93baaaffec23bcfe14945e7792e1438157978c91182fc97ef9a2e", .Okay}, + {.Lcm, "823883858b439d997e4d4ac803e507757d142ce5ba225a756d07006df9cbe1650d838cefa4ddfa5e593b1ed911ac3418ced76e038f3c7b493354903570bcf9588c62fe3d777c56a6d93bc4a1a1433f9073b294bb698b2e6d15186a4c49928a97886beb56ccd86af413b2c4f23961470e84a1a892bc5c1d96f1a9c81267ce96a194267a30e6c53f141a5e66ffdc4d9d417d6124f09bde4e51b4bb5577d8c163f5f8d6a735bef03e2d1e3117e8ed37a7564cd02aa7dd2c516a6fa0ee01d311578c4ca179c3b1ae07ae9c7d1906e1a49c797f423cd0e497c6f82df386ad0ea35bdf2f92297ccd580fe604f82ddcc192e897417c1ffeac8905e0f8ec091fd56a77202031c3b9abfbe2e94f4e2e8579a4db724432bd456967b868b13f8bc076fe369325a56af40cccc6fe43b3f6df6fa981b3f5fc03d0efd132047c1a282ef03c246841a27aaf9ce6360aa3d176e0294055ba65a0bfd91f41e628183788e41f4b6c66248417f78ea902968ea91fd90be09d0802943726cf0a70b413d4afa62ef69f9a292b9aa2b813a96f1e0faf063c24c61ca8f92f5dce88e2fcca11b2643f70a427ace30d4c32c6834aaa2a4f0d9e95f3e144276072509d7a2cd346ef929a71e04b1b247ab7832c7a1df5c2e1ba765624ba93e534d19b58954f6f342c0f009d66d007d0e32ee74570dfda9a92a015af907ac82526380571ea34113c71376e268660", "-183fdad4b3ae7beeb29c8daf6508ac601aa6610f118affb90cd8d887f09d70ba6f25465fecf91342e6c4e73ff1d842804ed6016f24e216448999dde0253ff916c2ac1bfc1ca5e0e99f21fc05a4633afb0fe61f795b21ff77002deed1aa60677bd805d16369c2d5ea64714641c30674b432d7d6cdf9e2d2e251df5fe58060ce3ecdc14079102bd27c2d27940cf011af6dfad75ec6f167c75815dd76dc5a218ad964c618adfde305436cfdd9462dd2df3d0cbcf868f842f3023c3ddc6a46f43e430ee3f7ae03205710418df3342a4f21a7415c8a13f6fbf63e74ab23250717b9160f3089317dfe1cb5a286da666ff4f5bb14e4d77bbdcb0111a7e0e8b268639bb837480034e5719c792feb84063954d809b889f57073638cea8135eba3e9c460ab5f9e23230d628cfee5c654487549ff6a12885b0b933b1dba38ce7001bb76699e4933181ef02fc827a33a4b25dc419e753d3aac65e0978345f580acaeadfcfeca21a79ab6e6652f730501a74b532cf6d09a4d9c528cfddc61dde87d35e28f1f0c3c3a1e758fda60898391d2bc4e90298fb3e610f1bb2112ce7335da4e621f9228941b6549a09ca2645df5dc2fec827f104c391ca90b17838471229c3755533c7dcafcf3051f77d3e830dbb1cd2c518b115d6f9f4773f280eac92e0e9882f4526c6cdd8c1ddbbe9379b6fcc8beb7bba1434735cd15881218b38836b8b1df2309fb", "c55c78d351e85036c8bd9e0512ce35734b9bd96d80ad9cc211fbc98233ffb087a4611c486a7adf31192b459a36f4f68258ed50f9d1024d3946464531381a000e9b872a18f37b62863ba64cff176da38ce13292d92a0197c98af2dd7591e6e9aa2074020479d0b9a9b57d9fbad4d995cf6d7106db12ff9e289c07aa17dcf700e2a1e67b27f9f4377c6a4ebd999ce9633064f327a5017932b604461a1157f0e2e817bce4d8de15ef7be8adba1cad5d5872ea2f6c017df1d839c6e7e739864dad2fe53c2978bdaacc596a094c4485890e48827c06eb5fb3c521a3c4aeadd00a61cf0580af93f69eed7a5faa5b40bbb0a901c201cdde76c7fe5667af15418e76452d6f185b0aeeeabff8d56494d276c38f5678c366c20a30ed9dd1905e0c5e8046754e90969431b8736d0fbbe0f22467f320b2b6d8e7e450eafbe9b03c390657e4d55a650dbde012df1fcff945fbc14770112959b90842b16662a6f40dbb5ecd0c744e8c15ca43a45a4d711de07b7327c87396b091033873ad5b30664cf1418ad26b4e0e5691dea71229107d7f5aa789c93939b1d1160a7dcbbf329bf3420c209124460bf637d821da4a6bc500661c7e0b90de7825bfb3b66cab5563ffa976dc2e18f822c515ffbf93d8b37cebe95bcfaf73ed4cc05c4b9f63a7974e9229e9f2a827077e5b7b71a1cbcc835981b729d593ba0da41035d74772131599f76cd509aaba9b1b056d883342af3cd5a14b19db05416a477e17f8ed0cefd56d31ed2f4220fcc3807c8f8721b0da32ea53405b6d19e1b4c9b04db4d23f57378df3d094643e4e24018f664fa9f1549ad01c658bff4e4fdc759d8c0bcadbed733386cd942fa64e52b52689647f30c790b9ebe3f9a7a9f27810333d6464b1ea52106a0a1ba8d5a9256442933e1e879eb45e6222d51a7b5160b5cc0bd07009b7b6418dd363248ca985d4b181f3009df839dc2f0deb1ad0feefbeee8c26ba64716e1b424e2bc00175ea713bfc4aa11f7c68e02bf30761f2df5883ebe98702b751e8611e20a12c86359f6b79bf56ea2714f9a7940b3c938381c5024f4872681fdbb1a4ad2aa716b068d5529bee2f73bc5f8ac911e9f5d2f620c2a5bafc71b79bb638dec6483b60b790dcba23cb538d431f56f283ab03aaeda2a6c48ea4518d2d6295853290b453a5b78a2feb07c1e91a1eb320bb0cad67eff695106fe345f9d2bfe4fcc19e218b8db903303c8e44232471a76379de24b052aa38abad28c6d02c8b61db86ff261ce5c4b5e9f8cc284262d0d4aaaf9be23499db9b8ea09c574ca43a0484b9f28f0888a6ab5988e6511541514c7ded5ccbd26a2ff432a497266ce5812a85f8157f599837c18cc1f6441cbdf588b931762c2e1e57ceb59e64adc33b86d02621bdc89b0c8280fc2b7bdeb0aaed81bb8cb20ffb96dba55fc0b7cb73eacfb3d7aea599f2020", .Okay}, + {.Lcm, "-dc6d94f913c96274c10eca42f43d611fcd50d47bd57b2059c9d6eabdff9554a16e936e97c415d2f1eacd83c76679ad22c7b6c0b6d00ea5d19358cece428f17f972d4b3d1fccec59faf3b7f4eddd3b280ac28aac15b32e267934b6ad29db3fbdd3a30babb1ad7a6f45ae522ebd81a1011db991efc88000f28896570733bae689250b3ddfb38169715a40b061e65a78a2e5f68a3167d964d7586ba528fb7a97a552377542c96543a16637575cd94b8cc695e3cd1b4534a221535982fddcc02a254c4b3fcd1ea549875c9391c301b08815dd2eeab469024aa7b6a590806ab0ea6d7b418d6246ff7680356b035ff6325314bfb8ab04043bc935c9a0697cd8c968300961929ba2d7679c45cc1747c7cd557daef00fded3964fd07f381b3cfbd751423cb499c92856959266a24b2e57fd3c365f1289fc4d00322885ad9e1c1a751968ee97e2a790a5a680c8994b429f8ffde6f04dbb304439ccf05042bbbcee31f540fc967f00b4b5a3089ed8eb61b1c6da4b9f9ad6fd20ce6a318b324c4226961e504fd02c49dcf30e16ab4609b13c2162b881c0ad9f14e804489aab8186563bb4ef64dec4dfce6a0204c681addbfb77cad0ba768a60426d4d881c013b0539353451f5c6b208e65847ab74119cbdb066e8a99c4dfde9f83d7427766edf7b157ccb9e1d03ae0aed593326d3ae4807d13d40c304dd409f698f27732c24dc5e3ac589c70", "-946dc94ff9a6f5878ad03afe7209e9e23ed5b1ed5d7360cfc3253fcb6242c44cba9b671354c03e676569398290cc14974158deef438f8851f41c4ee22f6f35e35d9c6833fabb228d03bc3c988895ae9a88856e4e670039f704da4831f91ba9d8a04920b8603f960a4ee3a9eea85e559600cb3f7e34c3b94f7aab943fdea10ca230ce506bee245a89ec481905be21ddcf246f1b1686e922c15525382a357f14685c0e5429d9c9b057f87516ddc368c0e5e9e0ac17cb47b60c9be7eb503f1f19a1affa3830bf3e8998a31418890e6a4f593db2d24ea5ea4d72f79407f939e3e4fad0ae0726560cfeeb1f8094da596089daac556aeafa51483459bbb1b58527da56c31ae0850b3dc73f472f82510b0008089b47c4653f3e4224aaec96240635245d2c410936c3c5aaa5f5a6f8d19b304a0300d795badef352deef49df7d89d2565a2fa5e06f26ad19806c927ec78f125f8eded7d11fa7abe7148cc28376c999a26fe5b5086703735ad968db7044d77fdb5abc3d371b05f5273e27bf09da8e58b32b4838119e8c15f78f24589487fc45f8c84256616f3efb46bdea36f03b9977756881e04ad3be54058eca7fe981d575e7989e95c69bde5a10e95c08b72ce15458cfe39ad462e2770f69811740a6c20201904329f031b129ad213103471d2f8efcb1f9d346e8fb829a8f4007466b4d06c9e27d46ab2de0e04ac2f93a3583ea91d7ad", "7fcde21f543cbb6f1769d09ccfb3e7416ed601824d8abf0e5ae95793fedc874a7d1532a97e10adce87dcf83c6c633e746587c59e8a9a4f6895395cd8f106e4a2f42510b5d09e8d3e73f81678d252032aa55150c9066fe3b65d88af269676f95678c6dba2a4e0de3e53047b06ddf33bb8439db21771e4d63a75d2de9f5668a1fc98d89c72bd8ca2087f23f351f8baf766a01ab906d10a9833ecb6d22ca0eaef95d0504bdeaa3d9fed9ed2749e51b26a4be756f0512e54f4b975d15375244c10016053f69e5a0c63c37895637ac1b94ffc03b166ddc194faddedf3f9eb959ba4f64e5cb8753d3de2577251a2733fd6878bbd5ee4f5783aec312bdd4ba4f434d586351dbecab8bd471923cd77eae02f18b10c0a2d8bfe3a4cfc4509df80476bd0f7d3dc16052be0e84e9620922ee0c2e23c6b9d6711ac36f4da5c223f17f9249f8539ae17a7b7a96dfb894e46bebda2dbd310cb423de08ac44d611cf818c7fb25cdbe70af1551845c43c0a6e5526fab688c689817fd407d609265689eafb178530407a0e0914f68d19c6d724a4094f0a1e8a7baa19aac5c39bebde9390e2a70f77417495f72b7442191b7d7ea529f7f0e6e072194f6b69724b61fb27c3c504d67c831de45cc41479d93838708f55c65b20c7aeec4fa170dc95ae6a5eea190c0f1ec8ea7102d33cfdd5e4fe9e2268974d1b31ac146f3402019d5464973089ba4c0c2b2fc6964b75a2ff95f1372c0d8eed142316d2a82ef2bec55dd739faa6d2931804906926df3be8587efc84899b7ac77ac00ff5ad85d9631d0b1494ac9bf33793ece4d45b64c10fdfff6e03a1d4769810f6214315f0b7186b6650cbdb6e19fa1cf0fef2d4503a67b8178543201ae3c98f22e29841633a683cbdedf8992d8f20af3ad629b6790d6453226d3b6248e02b745a8a3059fefdbb058b5cce37721c4ea475ea61c3bf195ba0f1ddb3b6617c13e8ce27b2e71bd44681c4c3a4d8a7337eb4756be92488302036569375e0badce9cc77d9610daf2da028e20d7c70bc2d6f12dfceb1375af5746671f857ede31c2e1324daadf412160f0df29b8208ef6563b29993898ef9675153a9b0aa86c2dd01f9cc155a39df3a2552c39f00edadffd36795d0d87ee3889f3190308779b41a8d84c19e284d6583031e95da904196df9dfd21d20b46ca1a45af276b439eedcdc099394a4e7a11c63080c7427b5126c3508cc2ba2eca808f633077a9950021c56de0ebc4c7b09e5ecf04d17c0b4fa3517e687d6bc9bb5c043e6495c0af24dcef49d4d2374702a1cd4866521369498967bd8285fa907e3e3deb33ddecd203bf25cba2dc34d3d601946b3f019d534c55c6f91ca639a610853eb6482e7124725161d954ba5e19cc8a1673a863458675f6b21127f5f6b85dd5dfa8f9dd837fc628bceb6689b3bb124d1abe2b7bc59cb18deb3c7b0", .Okay}, + {.Lcm, "-595cd808b023f1ba7fe10a4e0e4eb7f3284856faee28f1199b2fbe7d6808d4c2008062b57972f50ab2d781a4404655a76086fd92e950fdbaf78eff29d084db610b59a34002064009205a01ce14c66ccd897ce58c54c34cd802c8c808cdd8b75a26be0dfaba2281197694f68875575d19080c5494297c48b67caa1a856ad6ddeb6b1c4165707810c949591d8d45710806c110f28d1ec1b127515eeea0b774f87e09b43d6d768f4c8fca694936b76255bfb5db865880d82e7bf9e030920fbc0482ba054d29b4320eaa8fb157d19fe830f2097bbb2e573dea70132b0b7af254f178101126b20a8982be323a40e6ef7757e085aa2bb8c306b9e9188936641158d2b208c0682ef27a9577df194b2744e7d2433f39294994b35d67445fd60e8ca1dcbb3b2efe58a1250bbc915c34e5b8862086c66819382c233681e437348cac937cdd8738fe2266df9223e2051722d18158c7f320ed17a280e5ab3ad2c2194f409023b137d365fa3d12e2f874ca79754b71fdd598cde37be3be2d465ed583ed682dbf44ff3a37d71ba32ffcdc20882af91775ac523ca6d3f7d9091f8a7723cc9e8c464b504d704d0de5ae69d2ad5fe22cafe4190ed7d1cfd18e500957b3ee76f0f3428d3fbf2882973b9e58c99ddacb175c20c6fd3708ad4efe44c3aed2578d39f9342106d875acd73f7de695b36a30c87f042cfd63c420700f31a42a4c19c2516f04", "396878bcc2d7593e1e25199e44059b5e6834aefc65416cbed1347f2df7d335c0e24bca4e4b451ee7c90675bc061631e4fe21e83e49685eaf5febac3ae217de78eff277cff0781adff045416fc9a74903448ad3e4e1383d8b73cde37b9e966fd5483fff4af5c2e64f4745f322109eec1443616bc1be880c515ab4f0948d9c2f0f94d2659ac1c08f6d4dde092ae686e0ac6abeb89ee1c6cba7738931849024032e18c73bd2444590069a324ce7c4b7e4e5d8367f68f097f6de7aebaf473bb2670f38606465013db2c560d43289aea7179ba5371bb6e05a99b44c317577792518fcdf5417f759056aca9079062b3fdcee5992b3c3a1caa6f706b92db7886883665b64a1ff38c8a754e86c50c92900e39da28e931b0aba66c53622aecd2b78019c89d713ead778aa32b03d9bd4e0babf3967ee24d65f4178cc820d77adfeddd1340317c32708958a87dc17db34b2db5ae08d920701f33767953e3dd66c3b37584c4a9d1909471ecd2c7d83befb2b3e79fa4ad32a791a18c52b8fc961a0f58e8eead53c9e8b13fab4966bd07fb8c40b7d1850274e60238f101d1db40deff8a6fb2dfdb2321f67f401083bcbd53365c209a9d4727c6b28f05a405f24439e92e12d99cca2fa129eb874048a36d3244fead7572a3e33643fbad3acffe162c7f9503f8ca845dc40aeff1ceb4e9764d6241314b9f929c571b1fce6e596fcd96546c1f27b0b", "140a23f71c35d035e8d65703055048eb0039c860258abee156eb08ae0795080e4a447e688df25aa19cebef15cce1ee1c282e85205d1295a4488c6db60e0fcf743b6e1a9802890b9992c98f40b3a3e6cac7307f81c90a7f7685cc00e5580241d8fdf4189e45d9a1821cb9f76a075a8f8b397bb23853fd07110fa3d3a8899ceebe5e46058c475dee835283b0abc9c89fbc30451c2197826190442b22cd4bf33444a76a4c0d4ceb6ab3c254387fe4524f7bd447f0f653ec1a08ac8aa6cdaa18ff4bde06a75d684e9ce1e5d2cdfb0ee33fd47fee50cbb26f928f883ef2e57b36d2a5a1539b49801cbc971cea632d5f29153f96b959c9e5e7acca6b77597ac8bd6d8397cbff5401dc4e7267c3300d852c35731d0344c03060d6411c5f8fb4cd1c1ddd65f5e6a48faa4c76328d1c37837cc144c0d568ca5004fbe6c856d74a3819e393e5efdd4cdfd5b04f69151053cedf2389dda2b8965790d395823efe47006b10b21d4873001d82510ec698cc9ee607e64ad501207145218c2aff254f997bb41b1701102e05957a2c142e6cb9828af5877b2f2575912de482bd52425ee7322292112171e0c06f25a30f467bcb8750e77e277fea3e9a4815b97e28dd72baea41309eb64393871d98c216a6a46b31dc5f761267c2702ba679f09b3f50a7fa1b2debd3b889d5cb2c8619672faf721b27ac2333c9d6942f2bc869f0b3384cb887376401b8f08b942dd01c31001d00e46d39a8ff3add8362b5140f9af00e3b44ad6274a4c77fd9f95553a52336244d519cbd88c154c41d91f9c8cc70b5fb0fddb4991f1a3574aa0a9256e8ceff3d38639a3141f5bf3d286677deabf289b2e80f0cf30669bc8d751826bd775fb913dabc3f19a458ff2772b3e366df14c9dffda389097968d5dd010459b3fa038b3d4ef995924c4f7c67edb02a8580bb915a75297eac7d911a59c9f07e2d1a9c3ba756d804a88ceb22d6eaa35b2e53a2f0078b297fa5acd0c08b543390998838021b3694a8b5b6f17e53433b2cbb4d1c9f2cabff06894a879e1b0fd1fcee4af5bd59c7e6756fbc41dcf30fc431476b95e24c7b3b85edc686b3155e078739113136abe161e23ca870752750d6874490a97c2812b54439654b2b0a8af95acf7f6295c64911faef3bfb9d0e01e7a96ae5b6365ac90f81fc912fb6747ab99b19635b8d7ec595ad23bbda7b9e247c345a23ab6a2114cd5518299548cacb4a18a6d523ebc20d7e29b1bce28eef6e055bb8d8ce1757c689eb4b5873b96b87412d595b0b5e48323301adfa7a5be287fcb56521ff1c51715534453f88bacdc073db329113f8155816c012dc6d3295b5b071d30d42567fbc68dd1f9e65d142af0e2e75abafb681379eecb70e82e8e5718a3c12b09c907672b0948421e5c9d3853ba94a7ad33179a1e9ff4f5baecca918a1d8210dba09afaa3d6f9eb12c", .Okay}, + {.Lcm, "-244dd6a871178bd264fa9b521005d4d51635b232cfeccc67cb1108a7f264d48289214367c7e3ed492e2a522f1db7393088ad985a367c4d9415114c8a5fde99315cdbb75e216a66603f43feca7cf3384dbf50f6b7c54df6af31bb76ceaab2bc458714316699e98d390990d521edc44a2b5f9cfb9ef3e0f2e0337291f3cb6e290eed2a6262389d638222cd817b118b08119299260f795d871b72dd43f5de0b7f90b5b548281af72fcee32f3a8f81244c1b265348b69bb4f3eb55764cc497b988557a09a4e391de38d1095e3432f36b659812b818abca6352dde7b2cbfa2fd100f1d8d48590a34405f9d2d76974abdbecf9d694f3e88b2d05bbe931337d9f4cd41fc0ff33eed58b5de56cd4c99a6b4e6b11d60f275931b058f762c7efcf6558c42df2df34c9190a6b1571eaf6d7737757dccb4af3bf815f0d71bf2d1840a5991f0a112719d45b1d0ea76faf63ae594eae50dd75dc9c57d04362e6b9b2fabdcc9580d33de4e512156bdf67f5cc64aa9b3e5e1da689c7a2bd0c617e325339ddf98cb96ca581e6fdd0b35ebb0d5505e3f2ccb2c1116c3c9f9ce5d40966fa6a1bad353c3810169e05598eca338402b85ba306530323002143390de9d2b8f608b64d8b772dd98e94565b570e263c9ae002161125faf1e6974d8ad2da27041f64760f69449302c8a1ff9f16c16795814c2064a60916ade6748bd8799136f9a57383209f3f", "-9a7fc61de6fa3839b5676c9a9e667d00003df6b1d9279dc4d36c4535a312a316476f6416b123cd6e373675ee4cc506339588058659765dd6ecd15013fb4875d8aa7227257a40ba75f9ee7039ff2d066b216748be1a3a084eed6c2f7680c8bc30b2d22b4c5e09bfc78d7c72cca488599e05f0d3aa76d4d217d4377f4502ff7b0a42a2a392a4c57073464bb2d02fa6d6ece0016225ce5a27f41dbe3bd57fbcc14fe35d4adc80cebda1af661eb739ee220444570022f7c88b103e8c7cb67dd06bc31d3b2f587d5ed6c48fdd2e6f7cfcb15fa596478023ec5b585149b828002d76fb39782b7433cba0450ee05bce3056a49b276014f1a069e84ae5d88b18edac0130072e247e484392cb0e1d99aeb8643ee115999d64b22c52776e851ced9db9f29abe50a50991a7af108afe69b0029704757713c48fa3f08cb1595c48cd8024e9dea3f8ecec481dec8eb00f0f6ebd0281a65a1a98f373eaab37ce174d41d38514efdebc8f930e3a325699590470bf86e6a76bbaca26c86ed3faf01b0a3931c3ba60622ce3fd98af06e59a0b63635979e71033f4fb719f0ef03870a2848ee4d24ed41f83ddc7e2d4c307ef0419bcf3609e92922c6869599b7997338127f8330d465060d379b7294f7a47ebb2e3e9aecd29ac6232b930c4d58144d4a2634dcea890f343d40f5a965cc98b6f3adc89f9dfe516ad18bf356cb991a05dac51f683852806", "15e8f1d743314830200b5b0ad0765c6c479cf9155c2c1ac1779d270b8e567bc9b58b0467811e21f0abbec2062f0b7170e66f0f31aabca6d1888aced304fba7cd02b4ca1b2077602a8540602e89588673c09e8704ebce658ba2da0ea78d8c0f59124ab75f3559baba41e8a2175e81487775b66256a5c25ee715655c7a41c05f28af89315844b02c8505fa8cc5709fa371a7a0e0f15ea0f5b58aedf4626e8702dc50893edce4d02dd81d023bfc8e041c82f03057f4912a5d82901682f1a2111aae568492f389592adf1b2a2c8fba863f34ccb075120f165dcf1812ac5790a3f4da6e16992977b0bb82a96a17ec77f4c7f7b3876a123bfc66a182c5455d34ca8344541aaeb0de47472efb38be78f07531e845b0b9d3bb85b44ae1ce8377f75edde46978b30c432f2a9ff0f5535b232f9c285b09ad1a65572f0ae86a68e6a424f3219d3d43248e731a8868b55811a0332832c12bb0686d04277825217558a03a985aefd3203a3d1f513b6e78302c3f4b4ac778e85a80fd7a83e489b457265bc7075b2c21016c0b467fde4c7f0ccda8d80a8f72c4aa8bc83a0e2bd4f3885049c382e5bb0fcc0f2e292a84a14b1362550ffeb48d552275416a955edc87b5112523ae47f6241d5e2ebd4795807760f71ee0776abf1ca51ec67e5f28f5236106bb0236632fbffbe7491625d84a2c8310ebcf1c367bdb7e78aff718a58a183b4d20d2721e29f759c21957ed22957e291d49a722734a96131de35ecb718a524742474262433428f4d4d5b18d0e7710b72fc1c51e8b58206417f47c7d584e1c6d07dd3c1cba1b7c12d666f9d78d395ffc4ce9b2ff2a82feac1e2a05fae9fff97cd95ab82b03dd259f5a1bcf3a3ac4b9a8b2f7f1e3913626eb1c4d20d0aab70d53f7901a0a1ffc6c5c1577a7279f8c7757c564d9d92d759ce56851049de58086f49433d49b021d4149a15c756336a526785866991901d2233190c6f4ab0d84bb6489fe00fa1d15d3d25fc23e8d5f4ff106d505977e13147be0be0d25acb90172a0ee48003e57edb3074baf2dadd1794fce02c43d04e34ee6fd33ed9db68a5464ece38aa56dd6e5307aeb0252d4649264124a42bd542793fa324591426cb192b2ae5d15309aee693e73ba1c62f85551939ad19bc2ad987907bcb308fa343dc809bddea3abe9b1340835ec209f0de0de069ebd0383f58ed2cebffb4b643ef6b7845afa4c1dea222d92acc962a80c597b669228a8d1d97c714742f9e985edecb8cb17a58c62cbcfd3a67788cc992e3dc08e7a018fa0964dd015cf25c90a4a69c191083b21e9ca5aa1f41e8a3180b1bf8a8881463defac302da4733d7de29c21f55cfca177eaff76e2a04fe0d9545974dce43ac0e8ef29bd428edc55844a92d6cefe00dabbc4f09263bf39aa2d3c1f6e3e5ac3e22dc01ad26d39c34b9a3f8cfd91e0b42c2460937a", .Okay}, + {.Lcm, "ec48d01d60862cd0e33dbb7256d83a76ff2c086ff90e1a3a99857d3b64790ccf9068b74fdc6b127c3fc34d99f88e605a1cb1e3f270800f4ad61ed6e001163155b796e7bd8812d45221519a646a36bbcbe7c2d3ef34e04aa3f275609685d768f89d8b6e9962358fd3c75e8ea6ff6019d32160ff7d73f0acbc84513731b66155b15597cd216808c7ca7eb44fe20962c6f6dfbc99f81acc6e2f428d1f5584eebc2e86270421e7a9ad5aa35e01b299b472aedb9c12795b58894ba3d8e796dc5dd8611a3dc4b2ee6dc42f173a217752be2c7492924a8ca891efd2c3c203aa91a25f77b3be77886beed5000476cafc7e59c1ba8cc89035f07a4bbd1ca2530325d3f5874d2d3993ac77f38aff231721b3ba7d0ea806f479b6d2551998fe9b0e5c83ba9a0e9236f3e8842bc100e49cbd93a205fdd2bddfd1cdf2beb8c32ae93f4ae419878b24a4299d36eb43b33b9bc026b66f51b93fa95d7b5fb26d5b05ec74ff646bcca9a5f96ac30bdbf214617811b4b5f15d41a6c9602fb16e59443108d0e43cd384b7e5ec9f866ce97d114f3055ce4dbe33a2b2e89a5b6f866b2f3c7ea3b320523908a1f52ef9fe8c1ea4794df66eb01992cff69ee74d929640cf34858e9db23f8456a2b3eae6a5843bac637602cf0fdbbde0283babe578877ec7d80c37e88f47fbbbd5997cbd1309699c77e188b0f42183fe27a9c321614505fbe106c3d2adb89b", "6bb33f70c2158c78e8aea2036b307a3d53880e6cfeaf701bfecb564e890f8858cd9cab9ec4d4bc53fcade213e9d3fb74b9b001d0d0922591d79ee680102de60379000e2dd60e311de9490c55568d886c5b3d10fe9e47a59149c414f8e557fd2857c7085186160198d6a0009a958a85b03a560bd51937290e5a538675bae0cb460e724e96d4a326eaf83cbeddc559fbe78837e2d545ebaae85467dcaf987844b304163572849a460993f21fdcc7e2871cf34857567dc7995f1680d3bb541592981c36af777dc727ba8e2c89e97b46e69b3174a5dcf0eb0a165b793d3a239ef8d5cb90be25920e46239aedb034fcda6b54a0a5cbb1a8a9057095e3d44df3193f692b72348daeba22bb5fb4097113fc3e6e7a6b927b6ed8f7cb4de8f3d05e6d817ddbb3e6aaa192fb2bf559ef7283587412259229debdcf12ccacbae6caebe0c5c51cadbce4bd07362d0903643d350191f496289233c477c2b6923144076a85d37a005f4a25d44f0d03c62bea28172f5fb70c162e7f4b890070c1a2d7875584c007e80e372221bd7712d6dc5ec2b2a6fe5232a3038459bfae2eee37c0c079ae371c10a505657ac275976d0bbc4369287fe6d05e14fd365a2c81d3d062e2e380479ff7a921a296aa8815e52911dc5ebbab3eb7743b875145e9dbec3cfdcdc40c18f32c0407cf2d84910000970f467aa3ea64fdc29a5d474c1ef641e67ec684791cd3", "6367e073ca17eb7ea50817fa5f0e520688d021bf2e8098e522d66366b7bec82b2700c25feebf3f624926d7c1b8d27a4b1b07da10a98e755634ae04ddefcc3fdcd67e58c04506477516aab41638e8d2ece9e2cbfe38e48b39f915bc140e11fc807d5fce892724369a48b10fbec963c59ee3cf77aaef5380a22f91738d4fd115f0908b76e86a4f9e8cd6f1d984cb798c9eda0ed666b75e21756dd148261f7d7780ca746c4d7c16ddfa90b3663e0174a8a3c990ef750069628e70f10041279671a7a403bcd4fa7a9206e4e82fe240a07c108a726cac63a79a24f1156df03bbf334ac4a77f8bda8b8afa77fa4d44b8e4059ce7e5bf8fb1664e5985c5b3a9bbaeea166aa0552c2294bb34058d6551f8ff73043594dbb1c09606f702aa9d814c72eabc70fbcefcd16a65b790ba530df35d659b62cb92fec0181e8921e03f902cde4382350b89b5f039ee8f762d92bc580cc264e39a27b7b8d88ef000027d73dda62f65188edb1a682c2dadd476cdd88bd5f9d7e2098bfe6502b703828a76df2dfdb28b4b6e1a0d033bee8be5ff7cbdbb61d9f8009f2f340b8d2e2502da28ee7adfbe1d28b190719d1c1f95ae6d65af9c91473e62612d4bec9dea2b1520597a7052bc6944d88320880883db6f724fa8b717a6c96422f4601bccac2639ab2b923bb86422c4d31354e7e2f8003ad93b6865cd3806c7e15fd14b23b1890946d6ff37030a9c87357c08444f2c254aca506d76e4abba6a56900d2c02f27d492facfe3c7e1eed9bba1ed908444f1b088e6fc6d291e01592bcbc48192406bd51d0abb993157fe05a3106219b1ac18f4f744cea711e9208cac4ca1e8108ea9eee6533920c23c4b730f23f5cbbcdbb0e70f56031e903e2d194ff20a27bb6f80de5a2e1f7724a6658f5f45fc5b8965a3c8d68ef010b71c6700b4fc91e9f86d4b3ac8c1b2925a00f0b861e57b75c358353f9fc06c3f8485ef8cce7e8a9fe1dfa5edcb2ee51feedc00fe268500bcf0d0fdbf91033e1e2a8c88a87ca5ddfce8552da71d8a60caa2a23c2898b0aa89b35ec9abbbc204abf845ff79d8e433953fb461ed7d879748893399ea10a0c126fdfab0c75cef8d13e485d2b93b55f7469ff89db5e888e5b82ff73e7bddfb9f4fac62b534ae21a97a01ed46597abdbe49690cc0678e00553fbafa530422954e85eb5df21544f93ed3477ce067a680bb18297a740c1974a03d4291bc33ca9b5dacf7363b5b68002ab909d869d000f8a713cba09134e1c08df6a13d4d53d81b4b426b84c85330646d246d2d8c4fc47f6fcd5311998c0d80aa1b717328a9e3fe6cecce73dcf6fc99cc8e8185d7f5a56ea4925890b5601c5bda7cc4372cfd2680c0585a0b54359b192edc11b0d8818e1d4cd81cf8cda33e308aa7fdacfa1555ca3e9b337cc9470309cfe423f4598be73707ad3cf30600be1379fd2a31bc1", .Okay}, + {.Lcm, "-c1e4f6cae9ceb61d66c8cc8cccdf106f4191a5e4081e6aa2f79f00edca878516665d3125dd836ccb8962a1652e37586b759c665b5324f411090a8242d75ce33ee2e01b669b300d39848c232bcd59402afc2041f275ba12ff2c876ec67072d1c3f1233188b594713cf8f37dc177959b80380dccb578372a1d71129e9f1d09f16e948da18c8569b650cca23b3985217e68672693d30a92d217afe3eaac2a0316f8f1af1f81f86221066a06e3958fcb0809102f6926b259cf4865a5eadf5560d9d2d76c5cf0d52713a3338b49a3d65b4e7e3a0ac7939bf38707837f7d3bf88d9787d820fb2ee21082ff0ae478432cf57f5501e4f836c907b574a40981d1912f54b364e1f0ad9f800de7908954e3df15b280d7c0448154171780ba5200ff4e32bd7a1517acdb0d8a251689e331ae101f16e8e81740ca535be4e75e297324bd18be3ee42fc7398c79c10b5ca13c2bbd739c66f83cc2c8790ebec9bec90cd645d080ad72d56581236ef1a986912d995d378dfae56f128430504380145aaecc47d4f9ee742b1ef51f6f3323248e0e16ebff34b2dc3e09686195e232aca211d545bd0579ed3f84787c88545f4102376826fcb59e18491a28d9aed5bb0d25ef59a457e0c6f550fbdc260598941f0b967d0e5bf566be7dd8d4f17cdf54b803f34c1fb161e2aaf5550a8fa481ed07d3dcf59006cc1a75e49682852716a7f5b536c0dac22205", "96b3dadf2af6adcc373d73e02364a727ef817b111db92b44b5366c35bbcc90a4f17f8b514795e2f0b7bde53fb36277c13906dba9f3302567060bacaf425e800e3257b38f65ef7747faa74548215b6ec084a4abbdca358146659b61d848f4583a1554da6f2d395ee38ebd716e944b83a37e718f2195823d5dd0ea75fe9701dbfd26cb273fa0b1970c778a8363caef95998bf45eeca4d7d62fee54aefc3bd42071b6f323e507eb4e4194bbdd9211b50b600100674c3fe7dd3355ca2b5afb359291a3354198770ce3aa93d987c9b4c1784de97efd982b35df7a74d09c88de5ee631a5325a8c02eb35b26173cd347a4cdeaf8fd01bbd5563c75b2468f00940336544d427ca9d6871e05d8824eefd9ed47ed54f0fdb9989d7fc96ba4868ef84ae222d973b1ba0a6537aa76f93469cc9b93d995e325e948c2d634385f274793317d11910db965d87ecae3331093f21bf6828879f613e7267c861352615228f717248002500fdfb5220d2c05b867d4525a44546d48a1b70ef6c0aabd42a1f4099b88b2082a310bcb2826920d7bc1adad02d25c4cc660c9d4ca46b9993dec5e721a8ed81b497ec7bd710489f21571b81a2bc90527ebdda7310af5ffc902005f12ad41e44c4f795d57bd0b60a84a665765ffa1bdf4a561971965fba68e8c79d202ed3e3fbf9294fd3cc489929839bfb4a5cbc632e0a1322884206f7e7a5d1710e820d1f98", "722461797606c63f1b594ff3e7197edc43f2704052acbd7a80d0788366058b4d0143d6a1e6e92c0aaad3da30cdd1f3ed72e47bf3ff67266539e084bfaff42df672460c7c9d08abd70402824da5706b9fb667243a0a162e86affc36ed72a3c985e33a8862f75aff038c0dfd9d9484949ba613d428cca222f412bb03dbd9fbc6b36df3dbf4bca8f1d8c120806717a1073ce00f16b46a13cf2b19acbdaadc3bb6ea438e71031ede50d617b87b4f034e9d9904b972aee777fc1069fa4c3669edcc4aacbfa2f74b37d64b895eb934de355d47804ff08291b95b67e8ac60db2e4a6f2de5ee14f56dabdf1ce8a13146a15e04e3dc88dcd54782ed445253ffd0d37f1307053230d629d9f4a8f18ed6cda14769dedc69fb3cd8911661f7c05227068f05f065aafaa1e98d3d3437a55d45a8e4d65f806e180780e0b394b0df03db16a2a8b9531829a141f0c9c4a04dd90f9db36950d5a41d702ab8f2c6869c44fd91ec9dbb887cffc300dfea4e1510ac25d90c28e1012787672f99aee3d18b8c3a28142a5caafdfb7b8df853155328e9a8cfb8c5778c85d4cccdd185075975d2f21f0fcf78f305144687b2ebd8131a9660b1a6f8ecc4cc71cde1a42c8cdc977fb83616a6b6ac89700a787f1cd247a1179e7a004fa6724df5dbdf6a8c3951c24d2cf0ac8cd484e149241f1702b1b29c5a6793edc671098f0a9756e092029554e5763c9c2a1ead1f383719ed345eefadfe8f1760ea216435c3c106a7bc769d11c4f36d3878eb35b888ddd54dfcaca90da59bcf13f3b8258157d7f5335fc63fdbf7e5350d106e818d0bbce10a15da1db30ba2d79e059751be90e816e90b3efd250c48a141e4fef47fc568597f96797d330ff6dbf5452577c0d4eb2b06bbf7243761f51aa10e9149e807cf69c88ae304fe4083461e7f5dca1421106f586f95d7ecad4afe1e2f42dd22143a214b36b34e2dd59878696062a6d88edc5524a03d8fcefbe5c3ffc80b9c3c34c0ca18d6a8ee48dcf2d8d384a049ed930c13aac2d1016dfa07a3b4210d64a8bb8ff994f9398ac5f252e93e862cbb33bc3ca4ae5e616f1fa0c0c1150dcb5ebbb02f4edb11f56df323b9d90a80aefbc09d81b8deed532ea21f9f75b89853409af9a35b175cd7ad8a787c44ffc2701d90fe2cbd3d41ec1221fc0982fd62881e51d03162444b009de71518243c162dd444915c6e3466e6cda383bd3964ab2eb1075ce5d36c15e79e4c5854a4e9e10ef0d62935d49547d90f9345f9596ea4f14f8808855b5970e51984053b6528f9d9a5e2161e7b87c83b5b696876759e936b25ef6eeb81e9e6282fca30e2ee0b4b4e612be678d9174300ed0de4181a567416dac8beedc593e7f5b15c9656c4688f436cab22408a8cc2913431ba354fedaf1f896d42215c471b498b664a4a8bcdbe962b1bf30d73e4a78632d29f67a9a3cdf8", .Okay}, + {.Lcm, "-be441d4e61d1466b8fcbf27e6af28fee9f8c768313fd2aafea25b40c5adbbc5875b551b51356bc902a9e3c3c8752ef3ea25b45851e06543f9ddbbe40bb7e42fba9ae5520ff07491ecb8378ee8e665c5eb3eac44fcdd8952048b4daf5bcb93e51239e82d7104e2d596041376a047d56eec84c9ad4513d1ac5a90d5e22cc742e8230bd2c6f0fb26f5560d3bd0a5a50d7eb33e166c89bb194af6a714b69241f3b5f9b0130978b796f5366072c18a0efc403c2a22a702f552e2bdd4c868b40ed37e3de3d0e59fcbc374569da1de77d896654e2aca4ea217de4b9d47e2e1a746d0d7d8223db03aa8bb88fdf23b9c7f0601e420280d8537e56f4467bb86169ba30eebd57e07b376e0da20ec230f76cf86cc27c772f2fb3f928cac4d2827cd63d75239d757bbffa34ef61bb5ee823a50f735f2dde0715ec0398a9aeeea613732f609bc352620523161a3fed281cb4fb2978fa15bf440c83a8a63450e54fa4b704a40cc8523f6c4117d3e22b86bceb68bcecc54a08488c0f974abc7013924ae04e23ede1dde7511315b7826c04107bce83ecd3b1e9ad7a6352c36a3982d6cc4df13518728758d73c2f2fbbc480c9b4a96b5c47b020adce2abcf090692c4d84e3787aba5cb71dd0e2a07d90dd579063c55e36f55d5845f1a09ee561c4cfb90e943ca9e4622ebf2ec7a1eb9650d4ce44333fec81cf4c4a72aecba8b87d8825999cb6734e75", "-391f60f4f952967c5293325abb919fa3991bbd5ab68a19e60b5c20d3a622181111350a9ec48f8d9dc238c27ee45ece22d96df7bfa84f8efa83fd56f490609e3e85a727c02f39edf53a99d6fc7b3e4694bcf70bc1d11e5925bc893d35bf1176b6ee8d213fb8c400d7bc8abb53783a49c21e03be3e163e9e7f3723df95e14f55b52d59e089debd1e81ee7a139b25372edd014c9deb22248af28dbd7ff99e1c43156ead18d0ce05e36cdeb5e57c8c3ae7d1caec8a9ac6630f996b326064050131ef4c59c177748845ceba3a0307c1d3580a1203fcf4930069e0b8b1c003df4085f58411d6530b4bb04eb5a804b4f82ad0e30526e9018297fafd4e6a7731e8eee61701709af202a02f4ef1dc342ad5f9cb296542df71ff8111401a779989b9ee6ed2cb51f85ee0f3a76b0f49dc99992388ff1520a5a73330d7fd8eab4c9a391826808147e7f22cad77418906cfd159d1c8bed4d34501a4c93b3c2e6ce598f12fe2282782e8b4cfc49ee055e66d8c3e5422c47a7044f3ac8203f698b80fc24deb8e67d5c707032908ca9a978d2c6eb27f3190ad80371fd23b9ff70b97bff806fdbc05924d217abb3d54bd06a256c166f818e91218f3cde85e79e0949926e50a1487dbd1158e1c9deb713f65d6bd4e74bed7b281375bc150a97be9495cc1c6e88e81ce38bc7eac05f3dede788a2b7311457b636c1510de28357c9b2c03282db3c8b5b0", "2a747cd59d7c66941fb380dde6cedb9625579601e5ede8d31980de758764f937697f544d94778a68b8d814a82285323df7552d9302484130ccca2aa4676ffd57500555428e757ad0515e9c0cc87b3179d545f77597108d3eda78a5578ce62192928415750ac869f674364ba196c4bb51268548f68d4ab9c365e30e15b4556b77697d629802009529c8ae2f483af077d5d845df7a01f84f66c606d2f7dc21317bf217991aa21abfdae1d936cf70fe0a49db361e23cac7c628f63038d70dfb37a2947589612e4d998b265adea220976efb636022380457ee11a3bbb9c929abd616330b58468287a9c519703dc51992b8d6d233022de542ceec97e7d9d440a66ce30587157911428bddd2c9127aeb4a3cc6b0b963da43869e782a432bca3e19646c4948109f377a220466fd5378e1a9eef4ffdd08fc3bccfd53208e71b897c67c4d67c16b639fb512914f9ac422d642b16bbdbd68fa68598d92fd7bb0fbb420978e1bb1d17529bcdccddd7afa99ba1b4acb636d7aa307c2ea3441123d5e7f85a54dfe301869b803a885daeb815087db1fae4b333dac4bca385480c44161b616bb7f531aee6c7624775cf5811152d4ed8393a922187d73eee42298d8d3e286f669b2ba8305c0eb7830e2344764e9d208111be56c6fdfd4660beb21eaa43fb2a5725ec7fcd2444f7c4fd9091a3a94b3d3b6fe4078baf8e065ec9434cc9cc70181fdfc2b874e0f32cfdf2742a169f87295a587ac0874628bd34859038ac1df6c1fe65a0a0700a0b13e2299809106c6213788a0b777f86948c49eeb1a7f23af4f44977da292c69a800dfcdcac0fa9d8ffa8564b3d821b686091063c5a934a0e109015015ff56b6cd420fcc8092eb1dc8c463f8ab5f99e8653638d49c7fcc4bd81241a08483ddef6093696375f591a780799ac52f8ba719375137c1974c7d31abeaa00bb2cef29ebfd1c5e338bed5e87af322eabfaa03162b186597f8a8c9523e4dcae8ee40b1b212196218d136c3af7b97cfbba003095c7f0c6c84c763719c5f3f59ae1b8e39b13be512b8c9a367cdd0c9895535617a0f622c3034830b09baeb52aa1ffbb9e845c9b5e69ece4a04fe2be0d4b6a9c9c49c8d2b1f1ecb2492d1ac9cd59155d5884e6d98ebb7ecae1fdeab54089877b7620a0ef4320fb9730e48282c6094b64bb7874658a93046080297ea267fb864ed8a52400d5d58e0f9e86e0ba90a5791bf3f87bd0463bdd54071b2429830b4016f192794f3695b6933cccf4238f2303756a75c8c8dcbb143dff181611e68b9009c8eda6ecb7a72f21d9f4b20170adbf49aa3321a045aad477f2b6fbb8d3ded0fd823a6f7d20000d977822721c19cae623a36936a9651165f4ae2b4a1a29a47a98f793fbea7177edba24fd8d13dcc3f393fa492b2b232475251f4184cd5e10e2f533ab02998cde13e35ca53f1026a970", .Okay}, + {.Lcm, "72bc9f47325d6fc97df8057af052b9e6d9fa7440ba22b171987c82bf317134913caabd694bf0676158f4a93ba461d5107f54430e5b273b443c16fe01f1bc578a197a6f711fe6ac3d2958f3709acaa8b4d1e92f711dbc9ae8ce11d5f1e4e6221acbe53c763687ffbfb7170ecb81e4bee7989401cedd430a60ad5f5363b67c0a6c37c4c396a55d3a42e25e3452a6cf43f083f92d6b5984dbb091ca00ec7002821b04af080bb7d92f697acf2f799f4fd6624015303ca3777397e46af95275f50f6552ec928397dff6d34886dc48f27808d86e4df00ba6f49a1c4364b856babc134fd84b15e7862f3a9ec3e90923fda6f44059d83d500c2ba88097ce7650323caca06cd2388fd140aeb99010e1b876210559196858c2be9197ab506804d303e091419607ceab0430b30231ed0e17f5f5ac52cf2ec00e9ee1f1b8803e344f1572ef6ccc4cdf5a7d63c6576888e8dbcde614aac0174f963a94fbdf736f6d51da80f3ab808458040ece759c8a68771613d509889193509281052970b6fce75c797c02efeee3547c8e44e32453f05021f62b21b6881daa6dfbbd6c9e87faad92f11f47a8697cab09d6aaf5987413dffa3d69657c33c2a4352c337c1e01d1b8d1556737e55c461dc90fbdc32f28a6728049adc916da3ecf80055a4dba47b2b6a94818d3da5c5226688149548612a2174d994be39d4388c43d216a5ac8a2a4a639a5ec30b2", "837037fef15343f377e160e86195acb571edc0023777ba5fd3e3533575474aae972cd9e80ac48b5e368af822fb35c4f7f26e7f4766376359b8b84da11790f14df4c0c6e1a50631f18b65fca4b7e6818034c10d11eeddaaa156bac632c23816451445234cc01a7345fac2246bd786079860d479f933683bb13e2dba2a8826e5a43185e455513697b9b657a9b349101a137d844041ab4652aeb5ea437df87ff1c20ebfa426e980973e33799cd74623d654f55601248175ca188d4ad35a38a6b3f795b69f8fe514f2b3a860b6dc45425e074ac74a8f945eb73afde8e3be25d220732b22feee01c99c4bea4bb32c37a80d223cb027ae821badf38cbc7fefd3383035bd92adf9aa670bcab34b25cf9b3d522866b24d7485da83840b9d74ee0392152a6944f939357e443fefce3ab1c42309752dc3cd5a8f84cbe2aa115ee1f61b6e36317e29641d69ee9f8230b256181a14bf5b4ab1d8abbdfaed22298fea459d0c31c9dc65a3052f55c2e6befa05ce21fae2cee13553e6158d81198ec4e722db6ecc8866443f635f0ac06bf5a3a187d20313fb6e972b39a3cbb899d98f2d89bf21ad2a884a6a18ce1c98d7c65b970f5cd961b033d89ee7ee45fd96bc90fbec4611bd57e329748e3facdc8e844746509ad8b30bce753dfae676efa4c20316388ced6f8fcedd50fb7afc134e329e22b8454a28701b77ce273d01602ddd1b189beb8dea", "1d74688ff3b9888c9b2584ebdea3e5e280dd4d525a7c75e719c358e2350f598f57715f0595aa5e59c22eada45a7ed03838cdad61df6551487f9ba4f415e5259027aa0ea6fe2678fc800c1a4151b76d2c4d1ef5034dc11b133103909a532640b84783caa155bc0f08c79a148a351b3c77e4f199171f3c06d80a12c4336b55e3a06da5e60ac213fedbedd2d084791124799027f0455ef6b0fe738ce264565ea9b45249a256796a73cc9bec9bf84ca58d3399e5b40f2b905ff29657e2fdd7fe44bc4e7af67c2d2c97edfa77e3addc8dea2753e2e046916575fa0355aa5873f4c04e43b2c45c1df82bc73533315204add7bc881a1a5c625fe323f59edf0ce0cdfd3372603dd527ac9bf4066bcf23f01028063ac6154ec3737fd5144dc51ff23b4822044fd4bba0a4ee850efd3cb423d60438689ddad1a2e0aff53a20400924c1f6d9b1d38b01ded9ce5d1050313d69efee93aa985d4dfd7dbb4ad2f4c22bc12db8d93f50710537f27fa8c49eb103ff08cf631af51e4567c6005e8d6d1a330e5ada8c56f2febb530b9481ddabdccab6610de8e7157db845047e3117e702b8f3762d761c81058dc5d916fc7e79e5d8b98203022af7dec9200b3168672f166a23108a32f21163af38c662ee516cea06e3d493e4b3966c26f137f7a27bd32325d51ac963ccc4f8d30b7b5e25cefc2130acc11ea0d5a599f9b39b56feb0fa6bf3f83cf72b5b40c1cf2a951667df0ea8e05e9d183b952f2d0caf9e0e95a66847229a9c04035b59e618bba7cabc03a1623de720a37682641fdf031bdae2f88e6db42634d03275431b6749a31e06fcddccaf45198ea0bc056974841245fd7490cf31efbc8e0444e9ddcc79171a531df4e55a0ca8daf8f7dfa1c8f4625a918c69cb34f54ceb513fa858ef01295818b7f0ac8add66ab4c7f1467887b9b0d058499dc824d6e215850b0af20755aa91ee144abec71a6f3b39e25ca06110dec5a8dd3cdb24c4ed0ebab3a0fc871f504ca83ba939b5837ba58835d5e6aed3bf67d8e76cde9f0e7b35cc4d28b0db76aed38bc70f7e4efeb452b07c2eae29a30ec5785b8cebc4820fac018dafd4d020fdad732e536224821ca8c329af993da3c0aea3579c7ac3022d627894dd6e8d1f8c958e91e45a9c43ef125f02f9419691e31fea2b6de79e53bde5767003badddaaf7d9bbaca9f5c5a5cbfa490b6a26320dd363f2d02a839a3a7a0998e5a3bbf0f8db95ad143a127d854265240446ae385fad4a02c59b9cc4958fb53d4b3d0791772ec769347e113ff137133d061391bd2c6cdea3302fef98053e76faa10b87b4856aae88964c67c8db9acf659c267194aa1a6d105a1208dad44517eea6894abd0c0dd0834207efe5331218fe0ba78fe46ae21ae5c7838f85ddc8e98cc77a7ada30f2c2ce2f75f4482e7d27c5d491b305f8ed6fd1b02c889d0e465a", .Okay}, + {.Lcm, "-f32e81414d152c62afef130a9c05bb952cc709b8e3bf92c2b41a6448742a3aca1f8708686c52d926b6b9d2957a1e2a6d50104f1b692a74e5b9a99ebf6d3f7154a85ed962b14d2870ad869724da7dd1109d546228351b3781efbd72b5e0409a82956fb42aee05c9500c825d7698a45babde6eebf65ea5105a0c7eb25877f067481a6f21bbe2c1eed222a5c610e32a8a8c574dacd2d5d261653b7b05a8a250955fe7b5ab42a2b8009b5fde9c2a707519fab2ecb7ca3d4998225b512f6c8c7d9987ef694cc0c260f811d63bb6f42a47a81be1886e3bb8d1c5c4de4ba018cc9ed15d15c1df4383ee8ccb251e46fa5623dae64bca667c9df7c7de582da17692f8beee4c1385b2d0ec8106a8ed73601f240be1a6ed7efa19a9fcf3891e1810c76c61460aab453e4f46da51625aaca68b6b053995596fa3d86480aad44c04218584d22faaa2bbd4abaa64071dbd35c0b65d6bc7dd4bfb4a2b69d7c3ed71a3bcba97de8e525ffa248f2a2dace918f72fb8acb5d95ef92e5228386d90c192d2bdcee57d5bf921c316a59800218119cc9e9103cacc8eccc80ed7346da4eb63f02fd00bd55d123f3c7f83a6b9235b0d9c90c69f8f6f3ee92e11fe962843b3d23882f286c796ef92691e463bdaf35a6354a1c27e30ee1e2974f3053993a4d4ea86ad390cc7b70c9ccc4c16d5daf2d821501b5419a80035b4ee004941691378361a3f105f3ed9", "-c8be03e4a30555aa8ca090efe65c02cde335bfbaf42364763ec22fc23fb6398c182c0894c04e8a7b94dc6660855bf8f69cf5f41ff190906d10a5bcd8d6b97dd7261a4bc8e39dd131444c704d49767b837ad3ff249d25620eebda4bb6b5d46eb3e14a95848c1b0865329f716e01b38fa82b9577fdb9830f0aa3569c692c0e00e8d44b2c373a163a83ab29117bcf90bc0feec4bb581136f2f6b08639a88a2e895d918852022545fc31dddb79b0adb6eb94e07712350eb9e811698d3c2be2906d7a58c1773662c0b18af15b72c1a0691c0b73add8586cf845dc80fdf247ac5b28eb55cc85d2cd0f13534522d9a36d4e1d22af6e5337ceebaacb25ceff96a98004a1918be7ba30fe7ae35eb8fb03221a6348d8ad89ffa66aedb9596fa7b592b26c352cda3aa659444f29efcce236bdbf48ab154f35aba485018277c1ec41d3db6c1fa4836d6b4f03e10979cbe1fd4b3b44c1556b2d24897850793ec77d72dee4f9ea2b0638f2906dc7fe6b78c65e7988176aeea020fb1e3f17012b3320e945813c111c3d6b894e2a0cb1efd0fac7de77169c6f58ebc993c999d412b91c45d10a9772ad3bf76a2646e425fdf9bc801a565cdc1fa5e66d03404c4e1525532e73bf8ba60fd91ae9998aaa7d9c71d9e29930ac7b5a235f32896613c196c357d5066f2b79af37e3a9d87b094aa8c0fa770dd57959ea8265925c533ce86afbc1118c2a541a", "beb0d531ae7a50097ecf805560939b28c61118c8ecc14420969fcd2f1c4d5f0fbceba11651d3612ecc15945aef86ca16589cbfbc9fd1ceb75def9abbae3597fd757a67601e70a51b0458eea101f207723f81d22a7da3171eee324289b74edf076cb800092d41f8d06edcc16640d9fd856374a05af3363f3eea19c81d659ca2cde94e9ec1da8527a81d0828ffb83fa711226a9a8a95a429b465c186f626f9ef08a1c290537f40ecc172b16619b39ec7ab1a5474d249a74e1787c8de66e1def873cfad6f3990a45405c3034a40dac1ad9e54f12b58bf269839a4b96a2fe7776c78460e95eb24b8005e64ef97ec03b6b5bd4293714e7b3ea162bd6eddeed9eb8798f36d2fb9ee0d9bbf0c95e7f2477c69d598bcb01f63ff68565a2c722e9bdf6b83dd0f9797b61ff181a0a2e35b13656a15762ae48d585a7d3130f97710c8a1f697c6287c2792d0d2acd1e2670bd6dd38f2b4b5fa93f6d6d629a82446438ca56de9a18b1c92ccc5b0d43976ef9a5394c051ec601f6406b1e8ff41c34696278ee24752e2de622b2e461a625c98ae4c1ff7aed00df2e9aec2ee8321f0dd56182cee1a860c83b1a702de838d9ee9cd75a2d9c17157afd47b9980b575326dfe86fe60956bc7f0c91c4381f5567157d1f5fe5e449794046a6324f7bc6ff5972792b0aef3f7cebdd092c71012beb13e7cb8f2634e9a8f77001dd5d96916d99042063ee96f85e25acec4d7e27a6dd7d489e9d112fbcc043948f8571ae86d833b721dcd67a0fd457883ba52a3a3e7e4a59e158f76fff100d96e1e6916e561d5b59dff7dcc24007fe0087dc6160f099bf0588b98d7415926f0439d6ac759e3b8aef5cfd6afecaba21ce83342cdefbde16d154a9ca19c90e2df86b6a649e2eabc64bbebc72b360e1067e54a6e14e82e55c8dd2783e2a1f8ff391f4e1ee107e13266d7f6864b36ac69b1e95957a39f11fa3a3e7f2c4c2ec5aefabac5e2b46dd8628f1363c19c478d8a29f8c5969588e93bcc554eb26814154375549c9b52c4a3e7d24095eefd0402c5a725079aec2326c6097b44d442230af56d430f58c1c3be623807f5d9b015b8be7a968352aa94d10903adf2d5a9af14b607ae0e3174716772cc255472a6e25aa863442e6d9072a398d262545f038bea7f527d1341f46d0d56dfd62e850b713cc7faef10bc81e0a35cea41582fe5bb908c1d46a5ed3b37f9e0d9c926507cda4efb73ee10bcf81ec4c84a41e0b253a6f9c6f8b66368665ffd5d7a42ee5eaaaa8e5b1f43b2599e3074474f1e4d61ebce4f196c24f4a2f0e7e088bd67bde41175fc3a4b536251ccc3fc60884fb4ef9734d660bd70c312c511e0d1505a9f38103142b1eb4ef82311b0c5ebb0015785d7c0a1719f76831972987698e60ce6f4b25e34b7636d678b09bb5b8f7544c22ea9d843d3894eed72f63f1edfe72ee5e5960a", .Okay}, + {.Lcm, "-8deede84c282e58ff1ab4fc03b974a335a988308d9226115ea99c3a631a41c89afa1b08d0859ffc34279e6a2e71ef9d85dbb4de5c5da923ddd5efd1f0baf7e97fadba198ab7d40d44d6760f87615b6c6a0c5f8449953d99894f0a2e21d8a4303c5bcffaa730c7fcbb0e5f0b807fee1fdfc9d3f7554ab82a71a1d49125ed5e9ca884a742c157e7f99ab18b687a5edbc9c1e18da25e8c4c121b701f2c19cc89e9c2c5b63091b16faf2f0b7d869bddb9d43ac4e59f319a7a25591fb585ee8fc3c2c683f56920231d51b70e9c9ab644fbc9c0f19a998802b5dfb5e2ed223319d570ca5c14fb2da0ccc10d1b69adae89f4ce8f469d43c5c8f7f9224e8be014f96518880122fc9a004340f6b6ee790734eff73c45e6ed6f57104bb39c9c035e47e4025445f924378c8d58e63a283cfa542086d0c85a9f4e5c3cf1057c729089f41153acde53c2c340712036898b996d102281a20ab022943fcea8067567bd43a3bf8b74d605c0eda54e4dd2b026d075e756698b6384319fd04342be451419f5ebc26e1be5ad7db98f003864d8b8e4a899e0bf1ea390de11b5fe0714f8aef055b524ec7349be6fbf892e94da9c8a5e4637e429a32d3673cbbb3c70769e3453356482bc7cc24e2942a5f0b789d6963c015178ec25d863bae9e4a086fde3300ad8fb0f7c974304487ccd44852722372ff88d617c595b04f9007250a3346d7808e4622518", "fb7db1d25ce5863ce2e7121e849c2f8813eef1e406ae0af42903b74d40c3024d6cc2d50553ba1a0f3aab1b86871a82913dcec23d5eb6c3ef31042f608b3fef13b210eb518822123f5bdd18419b86db12eb0d65f3d00db22022e5d58a85afb1d110d439c892fb0e903a6902365109e5f9f1264045430459e9ee64cc9d0e5a97b013ee81e71385ff679b7d91175864e930a484fa4f00f22731644f459658aa0f042a5637ae6ef04b20db8e582778593200240c046c4d199485afb122844127528da2b89e83c8fdc4cd2fa596f4a8136123ba9615f83352a6b8fd1010d524135b98973ad02bccc778893d90d69d4330a0c58dd2b89bb1a041e67dbe444e82d9f0be0a724b889ff0ffe8a0c38133efab0378f9bec3a2b6347f4c8b914b8ed9b9e839adda86301b1644cce51f6648870a07e04bb547f86fa865ac86065390dc4b77383555d9a0d1e1f6eebb1b4aae1a83650cde232d0fefc5407f9f7006e67b666eff27d1e53bcb611e893552ae2438214092896264e6e80e554bffa39c32f20bd1477c33b2f94e93825a3086db6d6a668d5bec93c23186a6bffcd1f76432260f63ace80d8c87b99be9b200ebdfd49c93edb8496341892e7adf82ff4f8c41c6260610f9fd3b7953083af61f8f121fa1b056f4d24bb7771e1157f1c73d0794c9b8cb084e67409eac0aee6c108363e36613a3769d08d32981485777b9ed216d3d2c34e6", "45b77232cd6b5eb9eb203cc8000af3a82fa5a36ff8a1b8142a3af78dd3aa09c702f69548a0c2c87ea535e20fd694b8cf6eeaa9379d46d0b9b9771bb94247fb5b5b0a0eeac4f781ce96bd01785bbf286a72dd009e9b629670aa47939e419fed6e3b1dd66d25b407ee9f0bd99e51bbbe3d71993b707bbc911d8a374ed4c6b37f9b5410351a69cbf93c52dbac547e785091324ab268929109e77227f6510c9c119bc8a75db798e7e3bc503f594f9db3b2b209664bf976626a578bd6c888f95731a04f94f1d3525ccb945afb2dd15ed1d32ff016da021f53e13ad0460d5637e04cecfcd7644ba19b363ef4a34a971f3587f2729b56af9c04b73100bbb0b1e1675c1e4a065b4133d0b4c0edb5039c050aaa18eb8769c0a38e15e1b29e92746a187726eac4a95a19697674d57f12311d3230474e15c169bbb297e75b33d467f337b346a73479c41d1ce67c1d181874796598982a2f13913fb37491f3a4d971c204db9051c92837b0b83a2f18f5451441ec3cf87dbe3a6fa39cfd9f269f4e8cc1a6966dd46336f6f331c5b57c613c3900da60a86cc8075596700fe22fa1dee47f5f6511a8de8fd55157f15752776f181a2308b88c21c5214c00c82fef89f2881c9c9f6ad5b64321538e0d1aae6966af1ae83ff85ef00aabef2ad6b29b603517b1857e308392e15468a3f0ef6244bd61c037229fc74c9c59e6dee9031f9e2d004872348d7c49bfdb2b62e9a5777ade88c87ec3908b4ed60976c396837d414d11469488ff1cc2a01283f2ba31ae9a65ebf42dcceff64a7bb82558668e1be6089d67aafa1f148946dc329970ad7ceaffc1203fbb1a86f101790cd24ae2b3c55584b62816cf05c68d4a905dfd739b9dc1123476e7f685caa3df15e862efb4e24696bb8148c17f39cc285d06dca79a20f1940801362f7035384fd93d98d0045b53fa380221d3e6ae1b89275582a43d410a606bed1adaacdfa22959b7941fb1c3c65acaf5d23b6bdef62fa1175bcf4b9c21a803394c250677406fe83dc77bc1c46a74b807b4d8daf06abe30764d40ac305fb09818f00ea73b49ceb7995e6ba174472f90012b24d38a17720937fd2d347f61a20085848a0513b794265c3ce7709bab8f48a72df9da29d4f1541df357c267f443f1c6676a9df7dd9a9dee73682687cf55a4fe74d219aaca4d3d1aa7de2746df39919071e1d3681cf1952761b069cc9ddfeeac0c9d52f5925294b329968d2e65780b5db3170387625cd890acb425194a28e2cfd05ca3685d18dbe5afe72bcfb2ff1a1c0054746e66b3929f8621660683586bd4b5fc686f544fe790a0212253b22b842865d3dd4192fa56de2c2c4499a7fb86950fa68092e4986665a33d8b41fc77e19d8861759a95a49fbe1a5c22cf88c675d139600aa3528fe824c31d9ad6daecf049f3051854df1b2fb5a5f553c16a71beb19c8", .Okay}, + {.Lcm, "-5f96eaae5a322ff3bf35db2eab2a1c9c5b4cf4064fd7acad418b05e95924f51077d684e447658ebcf4608838d5129be9c4b123323afd2f872605544ae3d918c9468ad607ad10ab5e95e238b388e9446a358671ac74c7b32a3477adc0bd95cb253cafa6c2b640d63dd70f39befd85eb56332c41697f585c9b2dce0a9edf476b16e958598db226d5f293b9ac1a73e98a9cd103fa30f5d3f7cbd7c738bd7f986220e27c24b4e16e824cf095357f37c52ee03661f9ab83f4774435ac56804965bd7cd392407d4d919f4b99c8a5b916686cf4753504c08a62952df1bc21a190a5a98c676ad18aa941b852aaa10df076fd35127e67de7ce8ef76d70d5528214c05a6b7306da36892beb1f2fe1d3a868dedaa1fb9267ed4b9eb84b80a740a1eb77291f4ebed886027d912b7df493939e3499743858d48d7ec558f8c0444bc47e731904bbd77055defd0bd7d81e7f3db23fc923aade95225ae7be43b2267dadb9b9503f7831814bab97fdc566123d11a4deaaf7f88bdac2849b103a98dfbbfd789389c1338cdea169fb87a77aff2f51ffc51c90a8949ff2b278a053643669a04d6bf235c1f6140afe7a12287a368699e0e47a89536cb6419166377c04328a6426d016717242877b51863b121b44af3bd1a7de0673e4ec10ff45044e8e528238ffc50fd64d1e795ecbb71326948400fe5bfe8ae54a03fbd7af0429e670d74fc513a709390", "-a974f265823448160780571b11321f674b05f097d9214705c8ae91684df611e106ac27e9730be6802d26118cefbdcf2e8a8da27875dbdf0b330e1bad884d33fe4cd96e1f5d23858f93c41b67907be5994e8703c25cf086f859216a8d2c0f6c3a073e79b5ac1e56e60eb2946164baebad45d9e2a21dbecc35de85b07eaa1a4212ede3726292aa3b48e0c975ec7cb1198dc7c0efc8dd77bc862b6a5f094adff33b5829d2f784d44afb5bf4318950e06ef14c69fff996ca421d95e050c7e85b280cedf40bdd67b4ce78782c9b3cfd7b4ce710a08eaaaf8fa0fc6e86bb3cfd3de8db1276d65b3df88bb5692623988af06945d8bcd9ec7f166537ecb477cf399180e68fa217b1f92f2aa5b1d8c1580b957fb5ff315c7f17f719a92f838591f130f0fa7ad67a9a3a1c926878af433f6aa75f3d95c929350e83fc8ceb80e60469ba34e625ca3fa0daa8bb0d8edbcb58b35332a19fd01f2eecff6c2b5398a0fa2ba8afbbac714d18fbfa3f20e9986f75589e7be1d47ffeac8b38eb75ac05370caa5742aa6cfd1bddd26db1e9ae3f961ac0958049fff4fb95212eaa84c3c3e6a6e9dfc23c8185f4186f8c2d3836bac71ba3e66f5f3934e26c1026834dbfec0bb9bef2ddf2d7ca649ae4d3d9ebe6ba6c79034435cebf743fdb33897c8531dbf609e8652ed2a0fb0e058987b5aea5e4295209d865487eb5c80e9e9fecdf9da41aa48162dcd4", "fd192f48063644c62f325d4172ec198b295d11997f47fba4e7c164355996d9ef0991f62632651210607a909aff93e0e41b5a208bf77f79c6572b2d6ab1a321ba3e0d714d4479494f78ec194e966e2e2a1c89b54a47818daf9d7a2f7ff0646c174129c986e464bcae8b3ecf2e9f285420e998a0d98edeca2a8c5a141c87b8cb99949a0f49558899ea7549500a7f500d6b2a52a21251dac579c3ea7864dcbf06085a8c27cf04098fe2a7e0537aad3276f3ea941e26edb3f0b8466219d25c038c7599df5548855324ca069eb2fb01430f1cf36bf5e7f13e7d0a9b282f0a815c4c620c3fc1b94fe05dfecc2566354dbf9f5328024d9f5e87f779c4199f384983e4d7f045827c9e8f21fa708dc8dfcee9fe091936874cee64d56b7494abcb5939dd2fd74481f07ea9b54a7de211617f220c1b8a7c4b1793b80795d531d66941ac6a33e6ff87429a3f3df481f2c9858948007358b3982dc4e34ef992ac8e1e65a6bb0a131362ff44c4877599884035a332bde964519d71ff58a87d927270590af82a5b425a48eafa774347bf8e165eca7f655c1c20d041bc9319ffff50c2316a1a6f0f5d17e0ec3946d0bfd2d46a5e00f5ed3092531d2830514a3da672d27014c76a43244b4885a227f4aeb0ee76b039d09e31f85ce26f0daee4d4c91309e823d2ce90afa6f5fe0a25084c0b86cfed7c961f63573abaf28792da5fc1f26653e513f09b36a1ee689ce02ef4a31db635f5f11edbef7724251abcb3bf5865c74df5ac51b988d235bfa53f208337c12668d59bff1a7aaea2a9cfcf54f567216ff82cec0c32a2743e9fc4171e5a1b4d41db2265011834aa662a8fd1f221f5c4047369623895b14b7ef0204c9d3cdd0c5d8483fa48ede41de233902937eef8a59c6cfb44e407b56d6e6d4c0f9d15506a0b618d4b2241af6094ab245678c6cfbc8d71b4f51d696230f4a3dfad79c6464c018c430a3238fb4beb6275fe8be5179f516e9188a8c9790566c8a825ba6c111be6e4f6237d8b658a842549aa85365ff05f72f24e99af5b43b84bf8d7f7efad98cb37e6bc71325a3de4a2e4aca1b19cfd21c8ee8ee9a635faff25866869f9169aa3357cadfd0a4e2e0c0b91f352e1b4a477ea1cc37ad1796dd3b4286854e055103a50016a278dd844904eee82e8c38e90bdb181e36034bb9e9ca7df5b6a275b9cf1df262f1d4227117c8116596d61e8b7dfc6522794350e68e18bac61634940189aa372d500aa82cf9a4e7943e4148f77e1705e9740e16de4a9ba0148c2c400c69d8d939258b147cb6f4f144319cdad3e0940783b3e0160197ceb869fc82d2a3978d5b5b4420433b1138d11a29516a5f93bfcf2faf542f343ede35a59558a0fb1739394b0ce306d7a0851b4bcb69b366883ffe98db5e6e743d63194c569b58953ca672d3030286045c0b3d209ff6faa740cc4c4a7cd0", .Okay}, + {.Lcm, "2399c6ae37e925a7d6478dfe1282eb79df743cc434ff4ac012e7ff59e5f4531471f20d21143f38284e2ef45be8e79bcf760bdb72fb42616e93586d546518b5451b0467d0bb7d0cce2945532ba9b14d70e57182d058b395a41bdacd1c95019803330446b31fb5d1a1822a0682aa3434a74728f23995d3371c70867bb85a7151f3593081d93cfab5aa7f5bbd492bd1694989a0387bc657bfea00931c5445fdd21eca37f2cf9e69f21ef5bdc1f206b962b100d67d88c85272388f3e03a6ca58eac31784c2887570bc15d39507cf0c5721684264b303e9a6300090f58aead332ef4f28322d44e6bc7cfaf29db6c137d21c3fcdcafcc212546cd76614b9129fb769a42809a7e8b110423e30f108cf1b4ec33b249cf8e6e25af87f622ad2fc81ce518d811fe717f27e3573bc7504ca50ed23042fc3727680a8893ffabafacca0a5b18c655fc3a5e12c37a0d7bcff13a1b598288426667b57b4349e5938b5dffadc37b2d61a48d12bd213bf3553824a5a19eab95b21fa756b06b564b5a5b9b83afe86ab4c7ba9fddcab16bd77a3a0ff8b5484d65277ee2fd83647405f5eb37631a5e7574c8b1c1d67790c5cc859d4caff8c414aa4255404d0891095346b32dbb56ab29b077bdd5424048bc7881a5e380c6dcca3d3b42847830515157b671333adbe6566e46d8c4a933c134af4eb27c73c88c201851e0277e3edf5d41ca9b4968d5acda3", "94d9a2c52bd124edb6bda807985e3c43783c9d45415419cae84cbd8b1b4b83e491aac71960f42cf6db0a01c9e03df53b47a94fd8912f9b7585668776e97d320df4c0ee60ce1fe1a38042a2a55bd7b57933d958a0ac08caad3cdef1aaa639354b0a2aec9d30d2c80f431c02882e6a6fde2a3f2c9aef5eae432ef15d2ac20cc545988d7d6cdce751bd6d9f46ca7d69cd58de3c1063b490c34db3a88ed2eb6199422c102ff2370c329430c0d2bffb2c306f33685e4b624d0d71e9a841e0defee5e86798acdef6986c893a72b60b6131a2327bf57dbb89f05b2b52e9e74768ab67f1d5b4cefd0ef25ec4f08868782b025b74a64248700058cea8fadc30dea9ff1e797d941dce6280b80d0d51bf43608cb1915e1e15f331755f2c29f1504060bdc1f0bfda7d8cb09bc64d26b762a8801f3b9d3c9066c4321af720704d5de3a183281c004ff912c5335ed72047cbef1cf1724c1320aef2d30e63e988178d643f561bba6ac99ceaf8952f32c01e9bee14decf4a13b463c6df074589868179af57f9273694224d56f857e811438e45c3eb81fa40b927e8104b1d5bed396091199ec942457644e1fabfa1c229c1c4deb8efb7f1ecebd7191ec5bd04d77dc1bcd7c53285fc42ef3fdb275902f3e1eb543b3a88f63ad0bab946bf55b5bd442ab7b65cbc910d06df0b5dc80d60e7366d967bfaa9b105ffdd881afc25b4e0e2044e76be6b9e6a", "14b32ad8dd283be5a9bb21766a4a0d49aa08c5cceb33c66a7f1aafdfbfa7f7bf5c97194170357a2138fb8c3f3d5654164fa049872b73329eab4e757d57f104e8ba45aab5b62722142a8197b264143c31cb37f454d666e9bb8baea5f74c08a96b5a81f63a8aaa4f39e124c60949941c8e7a61cc75ab5a3661c9e42291c8ef4402d63e4f682a4535468e16b669e3474b82ce00b0360f11c745b2155fead091eeb9716e38acd5323ed8c5e61f1a08b0f744ea207d6f548191deb27edfa8c6e717a99ba93d0d17e07c4be435ff794233929e911239faffe61337512767ed8d2e5256f7eb106c5e5afdc08cf95ee1a9517328dc563c3e619829c25dfe62332133bea9bf734904ff69de879a5e41534af37b8c3acf13dbae67110344d192f7152f8aeb0e2b4b11d03f7bb3e6bd2290d34f9b92e5265abdf986274cbeceb84bc3500b9a65e474e62f6deb58bbd1f05a883544a1495438363de5d8835b2e97a85c5c2e12449d3e0e68fead6a082ddebaa4c86638bc505ae4a8a0e9edf5d46dc450da38a4eea3ede1e6ea4bb0625cf1313f8caae656a67b696e0b74ebef8186c76348be6c54b7aa767bacc97ed5f172cbbe3d92d03f0f16004e0b0d74fc2961e8adaab03908b9b75f090a6249532f8f198d080976049d99ef86ec301d59b8b130648a0112ca7e086cb73e865465e789465088a8a9503def78d51436948232e9090a956cfb8aff6168dfa03088568330db14fae93ec61e0541cd890e556f9b5cf25dd8dc768b79f17baeb0e9f623e27065ba931c494bc4d8c2e6a90f976c3b52fd731e56b798bdd2fb01c22d2ca37461c9c6b9287b2ee15af4c0e7c2fe22efbc6198c932f85463fe60653808e253e92d38baf4301b8f0e957a1aa674ffe6289ecab80ac90cc63a2b1580748d51e34fad8f51665edd9e622cb2689e3eb917788cf0098f1d63221a67e48342c814fc0ad9f1207fc14433278a0e8aa83dcda7ba847593538fd0c863a8fde074ab77e87f2a675ece17a56950b99ec4476ab627f3f6aaa45f45f91c2f945fd840fa150a4a774681b0755a62780d2f45bb0b0936cd236022c69f1f83387d45021ec40d7ca93069e54da7a856e0863800cc038d87e06c9881be4bfe92f99a710a358c9d1387dab60ec947e3cb9642a191e894bcdc39b72749e508a0ed88b3b75d3b442fa513eac05e23ef2d6fecec115d5701d05427c32f2411d822065d489c766ad4c80f30f4f1d40106cf9f10c86171ef2ff3605274c3bbf2f0d9e05081fcc7a2e8917672154b1003e15efcaf0c389a2d13933d35424b9624f6987e37d00c1caf255970efc4a95ce350a8f3a852fb79bec4bab793ebd6040a4993055ce4543c0ede59ce79ba25f82699e150c00a052f9241efc341fdb22a3e07c60cd469811d695194340db35e8de96f727ffc4408c62ba886c29e9e497fa4bf7e", .Okay}, + {.Lcm, "-1a76048a93dfd3d5e91ee69f4603865287d2c8b6d844b7ed504df66648dbb9ff1bb70719d74809d2d1c7c6e1acd6b05f5e214285b59956a3bd9eb3214e256ad2fe40812726f13b0b1ee60ba01725640b87dd3538505e26e87db9f4073353f168baafae5f346a469442ce26fc7a1b1875d873854238f154aaee5209895af05267ec7987172896d600e71971aff8cd6e5722d20eb938e55e6c1ad3027c375173bd27a838d22e68f81ce9dac5b7d16bceabcee021d6d476cee90bb4d93cda3d1a65944d6f9c0ee99cb8929e588cf4fe8a6010ca16a0e1d463dd760c578bedf2c4a73de5e8457c26c344533566744d28e94018c1afa681f9853a601500a66f3540f003dfa5e72529409d130cde42e30e021f587fe11d11f9b35a800f6f32b229bde98283174f303c0e0da194ac762663ea0994c594171c4a97fb8e68a246fa430c3cf58d82ee9260f3855327a1f287b5d82725e9e4635c56ecb997cd454dcbd843dd9925c14e896c7bef6f86344a07f7c294445ec476c710372c9720251800b6957986f23a8ef7060668129c9635c72f49d67c0cba4db85aa1afdd2b4e031cfcb27a712a9fdef535f208ab921d8d726e2753f93e28bc5da25681523499f01f5fd2389d37901c80045d1509b11cb522e4f76ffbfc0a3c453abf65d5340a79f8635888310afd224f339efe92a5c6234bcafa2621c418b3351592f8f55ca93d0ff213b5", "e6b910bad0e1b3a166efe9747d8d9d0245d1a338da1e429effd9f72c6505e18ab681e00c682ef4384f1224c1e2ba74f09c8786d68bbfc423ada5c0b20cf50177fa237e1f575bcc796b6f2f6d99473ce45499129b51aeb79248a88215e7bc4360e2e87e0a86f493ab6c03497c137291287280353728f7a658736631eaee6f8432437c2e2093b7f19291d37ade1c1ada46fcf8807538e4481bed4e4472e696ff934ce5023c212eb74631b454c1d1c3af853d0728cfa0ebe69d037d4dda18a8eb2c1d726289aa6aafd4d6c21d653ff54ee37cf1bdfe3b1a3e307c8c62ce07c3034eee5c6a55655761b0e4fc7701138860133b7cdafa90badf8ab886e04c1f505bccedbf616edfad051113b1fb6fdcd0fa1c0e783ddd47906cd6c64104efe8126b64532ae59cc3881745d0ce65390ff17483f6f829c4435c64d96de360f9e126d95ea089ede6f7f934ca6fc25824241b79ac25c908dd77dad3f35c97f7bbed5dcea2e1ee4a017b592c281a614b8af9094ee1f3db9d8004f8375dc44a7f8d5e2c563e34ebc8dc57b1626568be3a30ef9e8c40c99d82d2030b92c51e9a22037aa9e2362a3baa442599fcdfa4b00e34a3a712558151f8942349c7b4c9c5cd2cc7d09b4ed7c4827827018c20233d66339ffe809a6641f8d347cfc36ea3d91e2eb755c6b457386dbc8d340437492e6ff7d64a6955ee624525a51f6a8b19c4d3ff2984f49a", "17d92918789f22fb7cdfe907770dc1982174f53cf1369456f9efceb082078254be17877dd6451adaba5817830843c87cc0772e23ff96dffc56203dc3491676a0c354a48bb64c12e4907ef112ba5d3bbd17215ee69d12ccd69feddfb33d9fc0c59bb1dfc38aded73506e37a3f6d8a615d7fc9f38c7b66c989cdb877f82889cbdd6e76d9f09772b1f4277a296601e8e8abddde7c8d2c05bf43d66c19c7c0058bad89d3763f4be9cdc3560dda514f78a35b8cc81f3458fcc9fb8a80eefbfbcf5ce339d56565de06b10d444cc5d5493191a88efcfedfa3508734661e6bc345ba077c788996235e24cd1ff99b63df702d31c32a7ff88ff471a501f5277b4b95b08ea70755f3949a3eb91c4affc4ace3117157ceb851d1dfce4f2172329b43808d8829fc7218997619e7b56bd25e6689800979b791c1090b02933d990df17706873423d08f90249580c31a808bc9993ef61d3869dc654f42decafa189d89a4552f6ffdea4dc4faddbbc9c4df1e20e67cead4f2e77e211df54bd97cd8f006bac7a0ee88c1a5fd2df3a9a5d556749eea9bc56bd9a0d4346f35797c1f330d402a163201c4611ca7ebfbc8eebf32398247fdeca0a5d7f3f5d249748ee6a95bbef032c14866ec96196b6309d271a80c43dce2de1e3228ded06f18f1c45d90d3678a8d9199f5cb02fc11c9984e2137adc8d5990c11563e08d42c5c02e83ba0f154da6dabf02ea70bf7a948492ce3350fd14159288ea832af64fb7b21ade8c98c6dd6e55de1c158a6288dafd072144261399efc42ae10827bbb024f99860170fe97ffb8fe95c98a0ab1dd3aebe79e0a10e7602b9f6ff8125adff949040a69d62c71ba8c2a3956dd65509990f8166d2abb81e22c3eda471f9bf931abbb6c0c3e911ccf851ed2313d1137c949c7f5588e1fa528e96ef868a8e2da05d4af08ff2824865688c8b22654c91fcb1976add636b6b63149fa5848c31660ace80128aca84af0161b539013376813b85e34b32a244619785920aa13d5a8f0b75360a33e2bcd7636cb11b48ea93eae4c0cc43834a92fe87c50a842f290d1bb3c14d212c85f867172523db36fca726c03fdb5397590452b53c601b76a6676dc8774e40d1127e493febe71310e907a0c7e2f45aecb01ed7545f789fb013630c25a7889f95acaa6ad3ef235fd31a11c0adbf2ae5b99a9c16d131a5ccc1ef1057637737d6b039e29f89439e7135141da1967460d2171d15bb44049cd46a1b6117481c2d2c5882025b4e9ee771eaf4e2eee2be4dd16eb58d24d12867d73a3492d16a61d0002295c0ad412bbecabe910a6c8aa107ce04719e43a4ab26e2301aac4a9b729047aaecd62ac6e77b64f23a23aa643e7567c580cf36d80d9fd1bb394cfb153c476d36ea011e02d23ed445c3e08621e073b1d6f3f5318026985e19af641c1af675775042209d03378bc5ee2", .Okay}, + {.Lcm, "-aa94d9cc0e70f1a32e73da8c60d66425a41d66a3675d53fa9cab4127c287e33461ba9be22ab74c400bfad48a106c267359ddf76d1ec597983b9f9bede89543bccb024843277e057dec6b84a23afc999a69ca84ec05c39762293115a109cd59efd8e71bcd12b7aad5b033a8a5f414ea4377b9138ca2213f0d7dbe2e7dd1c71f950be41dda1c0a5449730508f9de50eea37b2118e94f4076f8dc47a88ba04c4c16c06a171cff4e660caad46bccac439da5fc186a8c6250e58decbc0288961ef211ea5eb545dec13565e063d193e4e1ceea227896600872b81dbd7382f0848d5a2a9b75920c44d50b4785fb7660c4beaf750690d116b79bdd0189ce334038ce9d28f77592aae4aa1ef247641d16257b895a461f52c0e08e49398feb022c520c3ce925c6233c8769c7e215b192943619aef507b273b0b53877b9b2795aab38330c34dde5a2eebfca5088b9e1fa1fbd8d0daea78a257617d7b5ea10aa0f5aacd8807aa5f5dcd77f199c1075641ef9dd4c4c1d56b88e7ed5f320430ddd1f8d4d53bb5eb4d429bd110885b9e2bfb8ac81a3b1f7a34286e836e03202bbcd2bf0e0e8ec8f2aaa751255f7aa98d80ed2cdc90751bb86a47ce15fd8e57db6400b4c0956b0aee218960229836b8ec59693422bb2ef427ffda96c97cd4e32baaafd531964fed7ba8d1a4913882e6ec89eef12f55a07a6f94bad1c94dbed4d38b0be2df5e0d332", "42ca0cadb622e635a3c553634477d3a2ade793caf02ae5560c4c3a9ae55a7e360b313aa0c12665ddff7a4fc0e7012ada96cceb7e5ada8c7044220bc0df101395498ced5e421e4665fe1b2cf7b3b4d1049a4a706edffb82e4b4b5cf7e7ab4d6e4d8f1bf4084c6cff1641ee635ddb18edf4d6fba145678eda4c055cfa6f7da8c94d5456a0da5ef98f6cf7043b12ce3c1a199a204264eb68045d086192a7786788e3bb51a9d9188d4129a140383c6c45e958315334cbfd6666ed89dbf0b712bde3d126faea5b19d220448348fa615264de5691ff760211885e5beed7142f832ad2c0130954438d596c50d27c9ae8193046387faed70d3d756d103f4f663a3d7f2d0b246323cb74507e20483437ef6d92998b7efbbda8a6bec73c0e99a890d80d4a630d72ff88a501bd76970bdfe5004f31494bb141cd611906c3fec83496387123b31759f2dae8e32d6e6114fcaf3e92ce0f76a748fc50289df47aa4397916bee2850fdc683e899870e8f972175615dff7ff842bc75c8ea3888f1c7bc5fd0bdc59135988ab116199c7b86e17c4498a94a8be293d245329b6e499b61673cea097f078010d0ee794d179f3919be391ee4199d75c3a4ece78d12274406f203c7c65817eff75ee5bbc2e3988c4a3a726a46e1e35632c325d813205aef0b44cb39daad77fee0a63f8989c0533de17384b1a4fb52189f9c45f0a395c4f508d5957b29d2ba", "1640810698732b7fa1b02e80fb3bf58ca9ee53d91df41ebf91b94f5cced4d23542763018ab5b055691aa1ba4dba29b2d44769d06e58be9dc29b2d7601421d15746c867a3ce88eca89132fc4def658c39beaa2ca0dbdc6349658ca582be50cd4716d1771d1cdcf8784efbc02cf55ca1fe26384d18276272cd38fc1c600a221b02dc344c2c45b70305990a2eafc30bff7c2db98985c627c77947758b8bf522008a1c7378e0ef0555125beed3974353de59c5ddef6010332732df81d52a502c996fe3d4b2d4b30d837a1867947625a2dcf10132d607a96036b3daaaec701fdd596741acb941d4ed3cd785ee22bf42b98522ff0e9a7f71da291a10fed6b82b9aea19220beeb9f9f1d59e183f1b07aaaf7575102aea98611499679f3182b17cf459a1509b7a19bb6b3eb4bd1fdde67a7dc42cdaade4e6c9ae626e4ba9f67b4bfa38ea48e2285051ddf51cdbf747f403c8ca8ce6932eb4bd384838b448cf527cac488faeb82359a6623101037b31710ef907869d320e4d2e0257911e795f27891ea3f52fbbcafc629486a3fee0a548a7f812b1afa39de1b0b36051e8b0c56f24308d66df5a30d04a6a7714e7d33f7172a4329be0ce794062bdbc600496d19a4415fbdf7ba0c708c42edc3c918d7b5de12264c1a901e8d00b451b06bbad99eacb7f984174cffa62c891d8fc9198a5e46be8e1e1f18050adc971b7306146404d06d42811be7a07f509614ee001ff3f805a3e43b76746159646aba3ac7b7a438154f076bfc829e565f010fc63fb641ff10fcb43fd3ba7a6659753efbad9e62920835130c979dcc63bb232696f8b3c2d6c1fb5cc4c9c8013daa361d167ef9558f2f3b75fc8db67e4e5ab855ef30c0725832a1939236f0905f997f053c78e987c044ccd87b7d996e995eae7cc2557ca2c729f8033b08c206fc24a630c8d66ea6c9890f0011c84a3d76097b96a5605869af9d09a95fb3e9243b0a1816ea78d275d9b7cb9eac8a7c50f8cf9a82fd554cddcbc99847af21cca4132bd51951e6526a5ba5ec72e61ec65cfc51aa50eba2bf969cf3dacddc94155fb7be19f43e6cf509acb1d2d2e8ccec52d11e1b87051dfb23007cdace6508dc893fc7310a306079402641bc7000c18006564e0e870597c99ddac78894838dc5cff587e4c47082f7a39a5ebd7ca7858ff1fbb2010536126f38da67c9cc0ac9a56c3324b9ba04fd1e129efd41e14431d18e034218d1201e7b166c6848f6220c6108de65a98b5110238a842cd39f3237f504e3683d8b77a2d610497fb785f15e979c28d33006aa0b763791a776c6ae85e362153dc566ccf440444c6a8c879167f26cfe3461c5286fcdb449250569faa6ef485db19f7aaebde72b54ec56faef9e28ae3397fb1eec6c7e33f622b4ac12c3f96f6aaf62fa9d82d7a5132a9d9d119992b0c570d66ab062b0766d5f5cd3b2a", .Okay}, + {.Lcm, "a79d4a10e52e0c197295edb03c05824695a37b90a21dfd9d846dfff14d659bc1859528bc569e9e76b4762fa11c7e1c55a05068765c7df7b0898ff284bc6866556ed6e9036f2e82099b7a0e8890a76647161d90c206d8d720db3b93fed1ed8931435b418d56f872469308246cdfa084241cd43dd37d83a625119083ff8ed9991fbb81bd299cdbb752144ad10b97620181d669001249ebdc0987576c3845f712f1f4d5a0d21c58f795a730ae89e90da9438ba522ba8481b65a1f9cadb91b22cb572ad4fad0a296f785d38793aed498ff3526f2db02e7a4b6c8cf4f7e90e601665d3c2084cb4d6fbfad86828c0e1091567e79f64d1e37c50b1326ef7491d164eba00026b6971cc3887b528961992f8d51c0c14f3513cb104fbf8dac1cebfe3eb8aa3926a8da01cb366c72da389a41f44f1fb93ddc2788319b257f77240ef73f53679829d45593858fb03d1db8731ed66121f380929506ce98c279051eceb78c94cfe365209179e0f63cd13294e349c918e12f0b3de471d6d901d38125016f46b1442d2638cf2ae87a9a72a3e3ba5264c6c86b484f07dd0b17650da2545bbc6138dcb00d4965c6abc173e434ca45377eaf5699a10b0454c023d3a1f5a449dea34f817bc97d769257991fc877a65ac11590ce86fd3098552e8e25b1705caed94891baf649745dac716db0098ae0746d53ee6f4589461df3010bf8c223eb3427e62309", "-1fdd9b0251bb2b42d4b03e5dac0752a3a898ae32fdb64d146335fea0723b05200ab6a936cedeaa696aabc84f94330306e81b76c7caea3754f74fdca2bc8f53a621b06ab8fdb69e9e0401a800161d661460a83098a022e884c85df223ea6f7593aa43190448f4741747a7e9b3eb649288991f2c939efec5f85fe69cb156014a0c4c6bc490194c31e58feee83258e22a987b92eb618767046a2af14b3801315b1d26e89469fa07beccfdd604c4852ad3a81ae1f1716fab0e0adc7bdf4bbd821eeb400887c6b7fe8d69732527d0806459184fcccb925a7eaba119c0dc8d295d2a953edc59b1c69546a02c8c76bc3872fea2c062c746317a6fb80c16125eb117314cedaaf50b6da176c14ed68b886ad1f13730eb31052aa9464ba1a2e94007ece91e4d1b1887b4fa0fc8e588607a5cbc0734ee229540c8b748d7e2c9e291510864e10bebf762e3aa1a68b31a4352f249124ec5d0ae5e8a7a33bbc46f36d41e7c705369b7ef7fa34bfb50f10a88d8a1ebf1a2414b82f490b4b89e03e3bd8fd79c86268abdc7168d3dfd8f8d7d47b9784dd79805d1782962181a5160bb3f733e3473adc810aa3333ca1c1ec00445979b4ee176e70fb7058b71f8639d6dea429affa03ccc9ea9a8948c3064bf20db8551a4507bf3a227502646676bcbd2794af1fd254d4287e54d8a1c446c095386262ac784ce495c5b82dcde8a00ddfe5b65e87e2671", "14dd243ebcec8bc3d2a22369405bbe45a406a885fc2d398280f3727befa8fe005c4164b446e8c35e84277d3a8e0b749558af733968ba7703c2308e8f056b34eb7d905c7f965bfe452d5aa17c5fbc8e35b77ca3d817bdc2a4a8e18017d2421c3e093e298367e71bd5fa808482bf6301b876a3007580442b8c0f76f344ad5ee07ad546a92e6773427518776d778371fa8d92c3044ba7ca0d7a5c822d629c6c71064c047040bd2a90cbf7a40dc34b63fc8a2abc51045dac25ff5136849b788f3c3bcf5e2c759678eebac80ec24427adc3be8e45d10eed400926a6a9ed0f92c15e1088936430d44ccbaaa217270916ec9c1ab7d1d65ccf40edae5f35fb046b198ee1b70f9f10558c3bfda02f96cd5c1f2fb9142220c29bb6245682e2ade670a299fb1137e956637f8e8dcd7ac6138fc49f41e44ee9808452f26ee2b27ed01e83aef4404d0f0e4388601fcaf75bea207134abe1c438e8b64e26ba090183e20f32354a08bd6f399904b8a98447ba1c46c94983f5edd1bdac2c6936ea325416626bffcb30fa0aaec07e296721c2d9d49efeca61a73d8cc8a7cd387e1298ea760af6d569cd87fbfa3b2cb6b5a96dc316dd55980d4b2037d40faecde5ebda473b0a0e73eab3027ba5bb0a7959fe15cf5237f802bc4f68687acee0537ec4e01601f3cc037e2f2310dfdf7ddc190098d8f931d70bc24f00da4b5d85eaebe38aff47e893b5ec4520ada3ca9a54880113dd955fbc7446aaf98940fb613e7870094c700b7d4c947983123c3672de077bcd4daf59d5c3c770154877c8885ef851ed7580224a301f470ebd3f9475bcf8d939b2fa5c99cce2df1ef8f7e085d08217ec4786bbc28c1a0b92272e2987776711e1e309966cde07b2d313b50b49f7d09fd3b4912b631ef5e47ebef6d56520ed13b5bfcdbc358d144602eb6f8fb85f7ded3a6a88f61a577229de1d213d48cd459d47417913c903fb01b2d0d1ea9d92ab5098c9f6de3214be83fe2ae5e46ae810ab0b7f5c3d4e853a0f490ca51af0cf8adfaf5cd251ecaf0513f99e3c30c7c3a1c63e8beb0d5e27f685fd3b3f230a5e13e4e780870d900f0c60e9ca80f742a2e3c821ec1336e5d3afa6a92844a7cb1ee744077b9b01309a920f3c9fb21e6ceadda6dd5afbd7c651819b6b8204b33835db1d55c825993f939555bede10cd8d723bac21e61aeeafaac5940269533ce4b0635015c81bff457764afaeab37ab8682918553695a47b995ee5cd044b4b7e955e5f1c8519dd525dec79cf988a88c998788143cbb3d6a17a55ed4816e1ddaae78bf19fecc097e6a096d1827520ca5e77857eaf5239f543a523800f6db6d2ac6798ece9aec7c7c895f3a4402f9efcaff37cea1db9c97080627f91170d2cf7358f271c0c0b9c072b841829da3d4c1daf7390328227c628608cea6f7e83540ad46c2cc22c6c8842c36ccf9", .Okay}, + {.Lcm, "-92743df9c5be7b344cadbabbace4dc2cf464345c182c2a4277a085e9f44fdf776a091c2160a344d3ed22fba762c69d839e93e5cb7c30d9b983a9e05bc1bd66e544b936345eca035f2c05126d9ac170c9424122df83e3739ccdd50a8ae4973a39343057e705e548c27f8be875c9b071933d8976b5aea088425cf6cdd77e95056e439de66278e85aa1c631a15c3246d04cad35a9f0de3bcf56e51a9ad9be723c46d720032ee01a9458f48c37110c1055a09c126c59b98f1b7b9cd04233582dfa4e76d38f25660adca1c6f0d5cef1ca0c3e8045bc338324d117498023ef4bc815beeab0b1d5c5b1eb539334ad5e1a212a3ce1263791bee619987f575231f6f06605c6f939d9db7932c22b6537f608fc91ad0eb34f426ba0540774e101f14714e9f2c1c09dcf7008997829469e6f3c271169b58c4c197714ef3c3d5708536c22200a4f371ea589fd5278a800b16e1a480f7f13f20f1cee8cbe9b8e598a5a8faf4157441959cfcf89c9daaa0fe60f35bf00f52c6c4f9ca093aae901a53e4059ea004124031148b5d67be05d3b224d8696fc908358d1bc4656c1e76fe3d64fd1de689dc567af0de1ba46199cdccec96e7a197ef5b4166472d8c658ef41cb144d081226e6ded932f6aa76de9769bbd8b929f6362d5a31c0559741e7bfae4e38f1a1c172de0dc94f4f28b4baced6c8bd3d23b1a5701eec4fe9a660bb57003d0102a83018", "219dfa8513ce62b99998ea3ca3b3f7b295efb721a3268ef6edad2dd140de6b2ed23bc49279ac361c79f5c1259f964fbef47c3def2c4f927c1495bd2fab3158eadbbdb46d57c28327f9fe65adb51ef097ab31f5a22c0f970835f16047b113a5f52f74a55ff1c70c573cf4880f0ee53c4a7d23f84cf55f2bd7d0116d782e24d9a5b2e1a41d1e551d661b83bd9c53445e2871213f65c680cc9246912131acf2c3ce8a8436f61598730385a3c42a99b3f9107649b665b9b984cbb191f17a300c0214e1028eeea3fc9554f909cb442ebf679348c95bfbc975f34a9d69958a60273f056091cb873e2f61ddae90f96907cad426ff0d18f845de7ede588046f5e6b1628e14ab9e0fa4bad1c905a7cdc2e6c89a933cff0f21485809fa2f4f1e662218a6b0fcf86bfd164cbe529ee229673ed234f6972b2c68b0d2c7b21c493189ac4d6aa5c4f4a53a4ea6c9d7a0dcc604d14ccce5f9a9d09f96c2e3e7b805ad2fd7dce86dda3a7780001db95ceef3a8b9537432df7d2e9fa532a4818dcd33ff698f6341ed0082f8cdeb3232d2bc9699e3c9ee7272d8d224533d9ffaabd6291e0d62eac836bed91cbf4ddae3bbe2e1c34b36ca5047d78f535f3910ad819f9dd6a29b443770c67f2df7cacbe74a60df6162bbf8aee5cb7307568913791eb05e1d09b07d11bb0c90f0b9120733d093d706261ed6afa36f06763b3ffd8fbcb859664bf56bf96", "99dae4c6d75521891c00f2d08cfc42d67fb3a0bfd46a22e4265ad63a4115ad010af9cd3ee8ac2263faa313cd96af60be316fdc6a2369203d50a00fb6576ed7cfbc535b562bc9b9337eb884d47dd8b7e4d04f1ff8ebeb0a80b26d3aac86eea7b3913783843198653cbb1e54291be79ccf5e6ede7be21c593ae03e676cb8561644844809fde03f15f77631285e4f9b13599ea7ffb8f6051a4d0d29a948fa5f267075ec5a3c0ebf61f712bff88525adadd383713b12009be9cf440c304fee777b004c74726b4fb5e7cf24d968248fb5405952d98811a454e423735436bbb02584dbb67858af2ddb826a319e21924e02a70ed1992fbe3f6e3a6a7d7b58e645fbbbd437618b96ce74a95f528226ac5d643c7579f7d06204b8e437d687c470cc77d5592d8e7a680e41bf797084295da0194bff5840f66c9f7e1acff887240282df005f0cd0b3e0bc7bfad7d504a0151a44ce6a5443291747d345d97920997d2af1516377bdbfbaefb9493a0455581e352c21cdce148e672a9d1e8615f454e5a676694d8b613c374dee6be63bb09df7ef62d54a9f55dfe07cbaf0af2a8a9af6f4229308f931d6549948715a3bfb4b336d31cc48638d4ce3c005fb245ae2d06b72018265d8dcde1bba93448f18043cbfcc29b824f3d89d5d9466fe03d83a534ed1bcc14859fbe8888e072163897ba475f748bd4625eee02ce676775c2daff20bc5b431cb3e71013ea4b714304199e5769c206dcdacd6ff86e4f5dc5cb766e0a9a429fa2ae957d07a2e8753cbe5e649632a74de32ec68de0bfdcc7b1da92eddcf5c8477eb9c5165f5e95a368a9bf69142f0e8a52039c5bbc74a30b17a8e813ef040514e7bde870dda48f865a9fa6c713309cd1e8a9f42ac9fb7e4610d1ba73c21768ed5b13714815740e2607dc7888ef169e20644fb3dae6aaf7e25441a3b7405919dc163b4f4e4425650a7b08d1816240dee90bf6b7c1fdf744b31a5ea6edeec54e7794624747c01a7db70ef613ccbe66de96b9d765dbc0ebe8f8064b7e66462b886af0a1d1c7cd04785e45d036c5576f3c827711763df2444b3998c0e38f36e29494fb81aac7d3834951ea553a06098378d8c899eb5a37121d5b1e86ea17fa2c4b4f4d66e63947c4752ed8cfd213adb4d8b2740e189392478e2d2c8ed0286d997062d709df88be03ee5d35b64e4a5b3c5485fce13c8c0a26f15830b23ea4954fd30f7f77f651eb7affe59c7a2ce139649297ce5bda04a61b15e694a79c81afee875351d9427a5c5093727bb752d3d692d0ec6fd3b77a20e0b65d1873de5b62c4bf12e82ce26aa173eb8cb0eff674921fea07f689014bf4b6bc56f1ec614f7f0d44aa8a483ac018146d2e44a5b877f3a869a71cde0fde66bd5536d1bc5c24efb8f68bf9caa957d8d90afabfa99e1b4375da92015066945102e372300a95caa8d3f0b08", .Okay}, + {.Lcm, "-fb086b224072dbee9018d452a0c443de9c3f65de9bd892fff693c2caa5821ea7cc729ef04b19070cb2ce56ecb2a74f77b0122e88cfd399a97417c56bcc82369e6c461ff9a69ef10d82f9ada886887a9c640b601f7931d212585928bb6e3960b5fd0c09b83420bd29780cbee21dadb247f2f37530b649e370740c838e2dab7ee6140037adaa85c28f3b3fb5bc347be0b4624bf2024c0a0f9efb7d63c3437093e2898d8c6b1a761dc5c06241d6e83b8d21a09efc389e6b74d7014f335822004c35b9ce0282a2683a5894978f06a35625d513b3befa5304ac67bc486d304adfc8ed1c6229bb9121d922416897f245ff9655a76b6028a75014cb777951693fc84894271da5c1c285b775f23c0d46ae522b8be038dcb7b6e332478f960d3a3c097ef82fac6afa5f7408fe75464ead8233323367a44769f9e326f95b12adf1e20389da16a96bab8c5fb22a228ef9c2f00a16cbdf263c8bd70df5b11412330a9df4e59884d5320c3e8103df2036ba1d9c69025f1f0c37ab5c92758a0dad28d53eb6f90db83c537b787c4ab22d3e07c98ee6b8584fc887ab05e51c78fe42fffcd202518083de186a2c2e6916d5933b3b43430320a1ac5976200058b754cdb39adc0d910351599af71a01ab59702974cb4a0c28fb0c8e3b2c548851fee833e566f870240d89d1cc1c95348fe81c2b053cbf176e1f20719e63831d5f84d022abdb4f5b0a67", "74f8d52e7178d68e395c81b358087e28f02c86f9a9ad675575ca32c6f0fbfbf213329994d3962038dd3dfd9947e1d5a56f4e05fb463321026a82fe526684fe2e991cc70c0bc09b6879cd3fb3831eb46f3e1e16718a2a8a0f1947b2745faec7441d2bf59ac4da28f9a48b8c138820cc64c294b05aecfd0adef288f9265c58f2bf7f7e83f2e793599f8a05785f6384caae78b7a2385dad06fc19905c6d7d65e53fba9301241a1e007f43a394a9e7cd35783ed16a545a3f47a0781fce775e7ba2338f1a0f09b87a7bbe67a03a57a2f36af602f82c3df427bf34948176ee2435a281c897a5b85c7e1918add49e0ebcf39952bf78261278ada910eea3f2d7808c59335eef92b8f5f3db4365dd729f9cf4930d2284a880b9dfd5ee811f51c6d17736ab10b2a6ac1a05f8272dc3f70bc94f97e6473392ea57f9872b5c6304162e7f99f87c095b56416290a387440951a8226e1915a1b046111cb44494ec34192b2eee9bd81484f0ccce36d90f8ffd8c3c684facbacfd0c28c0896f93b4ed96caec52de60f7a8e904b7fda527a81a5b9c329c1bdb7392be3596e8ecfce9d6736fbff6aec558bdf3fc6daacc1edc31dd1e283b0c7c6edd5955a4ee50342ab4cf1c02b3a57028b47a0c7454c5cebc0ad2400960258f9944d96d52e40ef53d1dc5c143b737fbc43eaf8b6695972e97c664a770ac88afd215990cb6b62ec4e9e614581528651", "72b3d1beda4e7055250268e112dca01cfee24ce1e55278f8c4dc5f5fa445c2d4ff6b2934e4456ce24878f0f8e45c21cdeb79c00625a5d797ae3c2d0f89301763f5cf7808cb5ab12e0e55c2405f3b5665ea6b29ec3c198ba67d24d2ece7eef1a7a3e9e4b2d4be8e098dff64b8b220d6ff02b4b6dfe72c21e02f55f5e8d7c16de77f23aba3b473475f168fa7b0e73280b16d5bee76305792b55787f0bce686d4cdb7519d32c3f920621ffc0b44dea00a7959cff0b594eef2b2e326b03bc4b79b3ec3ce781ee466f8454ed541b1690ca4e1714bd844a65a690207e087b2e1005d17b63671082798573c081e18b2a065dd12139a8c7dcf741fe9b0d6d9fd56d96dd30c3956df65ab59cb2069254054dd8c8acf47462cd7108eb5e4671d1f22ba5dab69d55676e7fb504b49e08cae345dbc009aba05a9760a9da3ffa2368df40846c5c778665502f84548b54306eaffbb0b534bb2dcdbe48a39b3607619471b627cad8fdfcc269f5224c8090e80b916d03a9a07669bcb4c1d63f97e2f711d093125aaf024f54d5d83c5ebf493b18b8b618b6a497514d5865b6ca6c3eddfcb3157addb4c8fe97801a054abb342fcc83894312cdb63b91df5291598a493e0fdadc1a89b3cafc85cecee509e11d2dca9e4a16e14bd94437b999e59d325e70575091688970699dfa5f25bf633118c9ce7f6c2d14fa33278d50cb62658935d30e5d918c7612e104844e705c0dcb379e5c8384944830a8d1d05861ff693981e61362873e068dcd761da2587d27f8f162ff92849b20bdaf858f7567791a6ac38aa4125cef289729081e822a6939f1cfff10d5e3451ee867da9ce1b77108ea9301e7e68ac86c65f8c534ff67b1a5e9e407d23661c579494118bfb9ad87d13f8fc591c02a7f4092ff14e6cc6739e30e5d281c3d3eea5790981c1640b2edf244be412d993749fe27a782bab82c0f1cbc51b8a12a32403324659d482811dc52957c1ecdea9092b08f1909d78e6787b4587fe41191a8a77fc73bd7e8954beed963772791a54d957493769b5df494999ccfe83bd56db10b2b3f0e6d302d43a03f98c8ca920bbf65257a56016f4b069a27bf6b02e20ddc3c47105f0f0d79f07b63a9ffd1fb83fa73dd5790f3926d190f6914560c42967f2b8fd51d3edc35bd5a69fea187428a9019226f209d1e48452680f3f193d7988c82cdf984f440a3991b1136bb53fd93b20adefe5dc31e971de6179320e27834c99f9666d0d7c43004530afe19e3a2a528ee1b887ae4296e39f6a3a839f1afe94a3040852b2de46e7952462f4e9a90e89d5d909721ce7a0b97aae4776e517a73a5a8dde855fa28f3e2db09270eba624f451a7ad5ec04e6849ef196d39f03fcbb31fcf506ba914d154011fda11c26c70acd4bc2c4f92e4092c6b3e3a8a7c3b051fc0a124cfbe7fdf89ac092a40364c17ff3e3497", .Okay}, + {.Lcm, "dd7fe00aa171dc25117457e2a46654fc40abd131696f2685406eb8f5a5153383fe0b3a6513ce2fb13159a5e1b56a55466cf28bb5add04d53134f112c9a09e41e4076744cd71afa507e635d4f9af9b8403e3bf4a2ed30168e0172a798c66b0fe25ee05de2a4267cf2c693568d23e522ce76d117d65bdbf8533dd76eb0460eadea6546144d525469d279f45f9c05eebe89ffa2adee7c90c91c8ea767d897374233c58aaa33983703d665a7b0038f5446e31249729ffdf05969fa3410c53764eb32d776300d0211b715ec8a84c064787395b362ea7084441855533e57d58ecb5ec31d317587e6165ee7fb043c99f26f0077bbd1fd0a7a557c7220c6e51d6285981fbb5ca4554d2ae8c248d6bc09beb3f2d4110628920e6cbc944f3d0c8583e689d247fdb6fba79791b4fca655b28e262d0f1d4e645ebf199cb8e4eddf1278a40cac39214e4e42c53b20aa1c24be38b041fcf99ffbb9929eae1a75a39888bfdff702de03de433f4e2e07854b25ede36f33547208b4f090fc9ed0862a2a37c870283b89ebf497268ad951720da74dbf3f998b53239e18e14da5f15d3db41be72505cde9040a2853572685122c31526d140fe8563eef1529f8232ff5eae0e798334fd0ab3ec103585fd70b9d33de0583824320c2993611d874ca2cd8d377058ca082981fe6723c6b391abc51804d174c36fd5b377783d504c5af097a5dfb82ed7fab70", "b8567e7e7ac38f0c53440d932b2f140f6ecf472c678a625c3a519ee3d520046864bf12f46c76a1631b46d0f68220cc2cb8a007b66b01fc7cd5e2dab0707674eed2c47066e900f6c5ae9896df50328edd67d63aad6d3a3df2855e11d3d3a843f257d99867b59d291156c39986b852c8ad196f19603d633b8de3a2e187493ac0578d894067eb3732a2df9e0a3282243eeb1ce350a87dc110beab196fbf4d4ec343d9057b85930f9935f771e8dff2c66fab553b25112453c14a3dfcf9699dc2040151caab0fb9dffd7fcf2b3664d0690f3d654fd1c20a7700857071e46a2715bfdd6f44d7140ede7c291a79fbe90a9253f0eab3fb33b0993e06d0b3f6f6e80ebb451792b83675a126b6627da32d95afaeda76b18ba4924b1d1a3bea24b205c8a3719946609ee19b334fbc08b034a2dcd2a51a4cc3850dd945508fb8ea6a0e3b015100344a36a4ea5ee147a588b7a7299e3b7b61c37aff2c77e76b2388f35e76688fd20be56bc606f6baca546ac7a343f4effa8114850eb8d4abd3b8cd10924787a52da9dc6c1048b947d794ce75d323ba3f0053ecc7e0dde26bfb0064004e1ac3a5be2a8445ee5a4c85c8567669f1f332a03c8412768763a7ea76674623b8c2bd12e57901545415a6e4d02273287f98aafd1470ba3f49cae0b773198d459a379e042320f317c82cd07831f2f7c82f4731c229f09e346f02cc3b7993fc79bc00113b", "9f7ebf6f4709b81dea9d19c296048d4e23f494e75f3118158d746bc514856759ffc1ae20ec326e796d7742c4f0f3425fa4b614582e8f4a704da576f70268d0c460d7ecc59f286764b6a43ff9c44d80b5a3efd20f7c48b786993764d4103bc561922bbb877791a5af5a9e0bf730a4c7ca9558cdd3b26e8a28efacf4bfc5432525312fd20df790897325cf9cf7baadc1373e8fcad9c09aaa256254019d575a31217c84e98dd4616d1c7f83399044725034491455dee7a619bd15ee8f66878346130754d59d709574e4821100d891d2f4535e2582b4d1081329b00389ca2ba4fdf4031c9061e237d390b1643fdce1bdd2bb6592b0461bcb125fb05efbb3701abb2a3fe9aa5544dcb207060b18e2c985b1d411d845e17a9704e5b7db215ac8314b7a5b29c891692de37e5014efb06c4b5a31bbf2c1ef3065bf4865da5d0635c9b5ab8ca5a246f7a7f6627daabed81bcb98875489093215c105b7b880f8df16d7aaf72401f24688db3485c906d5d9e31a67bb715f91a18d4b9dce489423c1bea89855afaa50820ef93a31ff1d403c0aa818d893d0ac4fbc2fd1bae0f20b9cf5b5981f1c4e967497108dbd00793f6a3a0361c61f870893aaa88c50ed955f99a3d53021c17d58db4049bd867f514c8e014f7827ac000daeb5f8844bdd4f20151e2ba1a839a701bc5ab287b9724955da9ac55046d6c10a28adc977c404e2437a5adc726e1d2f5e12eeacaef156067f4e849f1cec5831a9ce7b815966049fd738e8ea4d7c12a9fb48d00b3da0543b8b0bca01bd817b76e58ac43a2b5d1311acd2638da6c9063894d6b0f57f578e9262775766e7ad41508fd7ca07b43f29ad2ca950fdcbf20b6b2827cf563a5a30928c73428eae4f05359f3563e91196b4d3e773f2965581099a6eeeea6f09852961cbd0de5c5d58b75b011e48354155a40af9917aaf3910dac6573025d8e6fb4635e27fe21c21b87aa5fb16d7128da7ca139b622d18f6bbbadd680931fb0ea18ef9ddbae75a1b9b073def3a6397a5e0bd4a20d335e603d1000b31818267c0a4ccda56b271067e77d304255a92376414a22bdaad07cf81c355ec79472cf32a35ed5d4aafeb34442d81eeaa7fb541c9c8249139cdfd8f27d844be50fc78f6abaa19e3afa13f2382bb050185856f291b582f1920dbe443a0d45d0be99d28880c707f613c8d04be9672e69c23b3669877ad5e27011abb38379407ae932e01093ea202169c8da7e2d38e86c538a0ff1834b81edfe0dcf992e7971e053ec0f5062b2df7965b885a544dbc16052a041248b54a74731d0bbeb68269255487e0f01048f833c0e21970d4c8db2402cc745655a3174b7bc099038cbd1cb81e3add6dabd093a4f2d4b75c4741d05747691164e774e6da08e6b4a04befa261b1ce5f694582f7e8f29a60b4f858d485a5e93f38663ad6e730b2c876cef2d0", .Okay}, + {.Lcm, "bb89286186871760f0dbc9a105854ad646b3b5a2f7e6bd93e2a60110cfa7bf831e99d4ce8bceef25cbd139c7df5dca4d49808dc35251bb5eb09fe8a7783525e0ce97429d504b577a5115330f01b7590985ba75fcc38bbc0142eb853354b0c6dea8ea88c874a9aca16b6c13ec7b64c59b0d256b5397d1ddb3cc6f323ba8fdd683656357246d1ab938d4c329b000728d850ec498cb5a87c9eecac619b89ee42a571414d7b505ba4a6a7a668e4df998a758b57dbde5b7ee2287161851b129cfd9b5ef5f9ee424f9613b4abd9f36b08e57fc7f8c9e402ba3be89394f60419b724579c48ce1cfc6b8ca487c673081a3d9e4a30acb734aa3dcbec8ce4dba6c2500b91ba5c8e08dcbe87302b53921bd9b874d6940b70f5c3747b75b2f57e79ca3efbc24b7a85719c0ee173e0109ea33a5e0ee3b5e5a2d16c933f56e2ce5349a9229819a7785d8e6aa1e8b29a5d3ceb079be33d5f8dca255b94b3c98b31df74396154867ff1d3a292b3a8c89afbab0779218a6ee906ecf50a539cfa311678e04c3c3c33c37e2797f5cef05e4d338a5339871d3ae7ef27b52a94a9fb2f83f3ebfa8be48a967392221aa8005d66f917bcd1a65fd02bca5c0ba75d2cc574153dd2bb14666adcb033b47f5502d882e9ed8ca05f1367e90671412eb8d30bc8ceaa77c624697262823fa591030ce8f0c1a8269901749f2aea731a2b0b91850a22fce403c8dc4f6", "ed9cd02ca502d5136230e41df5ff95c91fd3e1f5afc602d712ff3fcc47e82ec749bfcbf44e4813216820137380f3d388bb852fa3c82cddd2305080b3e00e23ae3737301dc10c595658545eadac2b38254bfa654ffbdb15fb87ded93a44ce45a4e4b17e2ab5d27283582934a7a9bc1636ce6142e10c5ae1d8a039d1ef0a9d809b619bcac82d73805d417de52b7adaebf0cb3a9a7a08eee2c2f185b960b7c31813e0e27427a72ce574ca7c5ee2a8f43f4d8eaf93b8b02c332c9d1d418865dc73a3707aeca36f071cc9d94b5d4bc0d0645724d39120334a65e42f1288764a06867efc0ea558c73db593cb40362cefecc79b6d18a2dc235c1a582600336231d6446bcc777eb81b5dab17b7089ae2e026d48356a342dd6e26d4e5dd1d5522b14ba8c2d1c2a662e7b4221f6a25aa36f12eeb1296a0b805c57779979c94170a18a0b049c65753443b89bb04462550308149b9a117f792a7c72791baaf971eedc80ed454e0cc333c1b6e0e7550aacff02571a7099a699d49f34592a992cfd20c9f127d007cb3db791020acbcc631e43a64e901bcb0ea568d07690dd9102922cec5a39124b284b1221ec1855f4750cb889a9a9f8322cd10c3af7fea700781ee823447ba0b8875a8c862e25b70c5a52f2ba30e642b4e96f319ac9f55d25de85f7a2465e2737e063e6e755c731c962f68a5035a97e0c0958bf1212d3e9444317fce2509d21", "ae10da770a3cb3385e729d88f8ce0d131a8a2dee25664c42237625397f9ae4c786338336777f5b3fa501cbe1757bf9f0237bcf188aa5e8c9039b0094e9f93a2f8674675f4c2ee31d03e008e1689be00761e313cdc6bb618df9033f06d7f8abe7a3bf92d0b1fc365c1aae76da71f13def609f270bdef31e57cb01129a6fd76fcb00d692a10ab47e69f89da27de12d742814c1d8670d2a2f16c12628263277f928732614c958d061bcd4fecf63aa4895a143f5be18f63c4d510ef9bd5c3d7c63029a46cf6d6995139cf82e677b7daecdc8bdbf377231fcdc3fe63e055655a0d08ffe7594585907a1103a950b8ba5de6f5b34682bd487b17c667065bbe3098e236d84252f4f78b3b788a97f82444a0e253e56ca082dca05ba8bd4f012a2710022cbf69fe58c193a9ed72db35fdf9392e98d83b3f7f9fb724004a7e36fb537e38b8e6bf6cbf7acf89c34b5fe5016a2f4dbd36588be4531ce852b9a4ad23a45fc80219e653c3059356bc4c641a8a09b89d1195be5a6fbeb20490f957939706d3971ff1ba8f89901fd0a45bb86f5bac357dd7947a0375968259ffaec51684444e7e876364b726130857bf60b36b7e64cabf00f61723036fa5e8b7b255f7ff61b93243beebf5b3eaf00a13011bc4fd8095e44c07624732e5fece7a342ac878d4d853a86a42aa10f89c1eaaa3ab8a81d9205e41258b6ac28f93c6033f4afcfff45a32f3696d1526c686e4199b20ebe3a069021790b087742f40c814b8952116e002494668d3f8b8c79c5e54d630822796703e8c3fea4a7de919be84b7460cb985199bf7aa167b3679555a86d3eddfa72958e12edee7c0fe545ee1d0090cc8cf4b04898f708af58b9615e114258f3ad79692372508c8312b1fde3e445022c4c2dbe3cb4d2501bfdbca226e0f146ff3cfd911302d21fc18239921bee566a3a0c042aa5aa6a1a35650534f6c5ef11752e3aa7a74dc2c4a706ef47744b9c88e563d3b357c925853ef7c0e885099c7de4ad9fd43fa174ec72052b0cad8b983047cbabb06ce1b9d503d133bd371ac1f75e6598b38b2cec96b8d1247b650097944cc5b06d344889449461f23e3f361c1c92d25ca248a1fe27958da45bc420df182f0fc38b70f38d47a865adc416630bdf2a0893804a954a9dfef71a2dc4ea5e01e9b186c153a09548c5c4300d8661128b12c56e6ab6f6e54a1da2e18d25ef2be6528136d65ac62057553c66c103da6f793aa4f553aa9db5c7737ccd7af0e242b8b5f758f95587ece2fec2d1d72421ddb8fd7af39c856a1c6d92354fe345f70eb270492565feadb164e4c26f51e0bb9de0bdb062e63f6f06313a7136b496a6f3d81e66e70b62537965c86d2d358e6c676d381eb5c6558d187d26c1e81b428ff99fd24ced6da8522b1ca7adf67eb8ca6e6adb0e0e3e9df5af6d388a22d4dccdf9fd10bc178f141b6", .Okay}, + {.Lcm, "-c0cefeddca41c426cabbd99229db3c7e6d15a10473a146f1d6ee6bfa309ef650e0281045d5cf00d203107174062ed41e6f0da96a7c2f5d3ff1efc9a62680408da279645d9dae8988c14e7a3c82812b4563660c05b224b08080a54c9b85c3df56768bad3b4a3baf483880bee624f72d8f2057e1c226f8300397a771f0f7a247fe0e85d94e083dab9314bd81612a0c0722346d0d750578285bf9d3d3c3755331c8e2b43e527121edbf6c40f48dd88d70a4a874046ff37e6a0b910c35f6d24e3f26720370ad7f1e4538403869ded54df0e28426cdf09296d61f3d83ad821c003f4f759bb4edde2b587cdb10ddc83f772fe15f3812cc7cb0f46f363472709748ac15ecd47a2a111e82373e223c430b527f74ef15b0d7a53cf3a0f9e1eb3c625b096cebdb6c7d5aa067c555d30cf35b8913086278537063cad708c0ac598bdf086fa50d667313b09df775ba1037b08e0e81a136772109d35627d02522b303a27834bd8eb9716cbf8775c60142e072bfd786ce296117d5a2f098dab3b749ddd4bc8cda770679ed596207b64cff2d1a31b8369df8caac34dcc8a4abefc53b4a9824f75578c386f30b3f2aaf09c1cb10a4b145d78ed60a95f2a5da8c3d00fbb19a298281e75626945f8b4967891fbad4b2526b369e04b22840451f41b7d12d3c1363646019d4c4828b87fbd4de2a00be04dac83af45a197537d50fe65639c245fcd0a91", "-19dc2a2a1094d03f23342c765b6afe8ebcdfa4e94c53194aa3bacc525ac5136340f33f0a97fcb10c5c302cee3a0eff5f1b5fc644b021a56ffda7edfcc37a8208d7af0d60b5896e5990e56d93797505d27a94c7df8b1921cdfb35494c9ef83c49d626381a0d773ffba88ae4621af54304e14868dda9ffbf12d563958b1505de3313ea2658a95cea576ec86a1e834c62851689fa2e501bb86a1e238c982e40c456af0b32be06ee3a8ab6425e8dfb9a4cbbb49f0c1f4ca1bf872dca90b49c7b720df46f3946460ee6b87f1eca01f4b30e3a2ebce7ae63aeaade5ca634c60a33b017974c11b57050840715201c161b797f2c0f94a4b2a853f034b0c91bb8c3ad7d9538eefb42c3458a630a70654073653e431d83bfae438465c81bad34c344e4ba238cb2d0b123b8736863fa0a6612fca6cb4d627fca9ae10e9bca7fc118be559c1874c24d01231d430da4032b42a35d119b8b014f8e7caa9e5c9381be23b2e61d9257569b38fa0a9c67f6b501d85d73b19112390647c3ddb14621406e817457e178beecf752fa54bf18138b1507779e6b847383a9ca44dc74fdaa8e7b1da874a4741123b3a2bafd9c95754073da088e8ac0df95e1cf0751292bb47d003aa1a3365a421f928f68c0c3eacd6b9d5ed024da8a551faa461563c482d53a2472928a8b98c991d9ec7ddbd2dbea5e2967ae8419e54408ca144dd9b5670458178031e4cf9f", "137a0888539d74af4580ace12ca3a0d3899dac6d209ac24ab49105fc5d4f107e9be9bfac7ca17400f12c626021a4edcc1c922d545570da17e0ed5d123cb60571b628ebb5b847085e09f5f5c08c1239d79e6b45ef2294c9e0168742e1a0d6a9c60cc2c4804d7b36be1d9d8d130ecd11a8dc697aa28b18ccfec58a4f3d777bfaa93ff0e3af01aecff417b364e7284080effb6ee0b61bb67c6ff8a754a537721df2bbea0eb82ec1d63b847e90c1ef9ff3d470c7f74ebed1504c104798605403161eda0b929abe62b0bc0dece6076fc35e31afd13ed80c39234a2123585c9767777d47297b6b623161f3482670d03933713d5b404782a342d9b6991ba313a6d67bfa35061e7531c87e6e8f099571ac7c97910073ba69a2b280c5adaa1e26c0264bcfc35a0249990519c707a1cd8cd3ce92dca5b04ac940789db0201709c4d705da115f59860a927a5dd5a00ce197232e7e85cf8aa69c0f269d52a9c574c5e547fa199d269b96d319e7d6954be2d5e57db7796a931beb4ff5d118aa3828faa64ef2fbbb33c5ff9b783d53b8779b5d577510b4f6f517cabbcc4055ef33347c90ef5d2092e7ebc2267d481ca1140092072167e8c225f65ac1d2b67a59df93b2b5d95260022c882f979da7258cb64dc6c5c934a73517319eadc17df4029018da84add22274fc2a4221cde300e3501186af4727a365754a7a0714c6624f22814ed78363e7a990ca5bb8f82ae434db63739881128ca229142a1a35210da440b1c5bf77bf57055faf2a284f0a1736054e66b94cc02c5699ef9a57bfe0a1425c36afae601527561e9e93794e8f1e8853441b3c69a0363068674beaddf337bbdcb966619fa9667e7f32eadf9c3f5b5e33862c65426410c9f31f0b7f44e7a777b0d2e031822322fab5bafcadf089bb7f77593886f8020d54031a07164b89239b4b84c95be12291c6c97e7cf59da0dc06971cc711872087b9312a953c654e7bccfd2a806fe2884740ce131a4fee496bbe326e1ecf7d6155d61999cd90cd705aec506e336f3a0d7bb85fef3ac10ae0d2a4fb561f87cde2035a429ab6deeb264ab32e4d7b0928275836c1024b04d5c7128a25ba14e5780bbe6d272b61a7f1b53a6c974f30bbb0ed16d1e10daaf62b5b973b1134283c6536195663943c93ac904b6a25e1f2d785a220d92518ed7c82e2ae875ab3bbc9df5474f9eb5c80bbe16d1851a71cc300f4c9b95c29f29e6fbebe015600b8f5c820bd4146ae10aad55fd3bb16febbc3e0a8e46d8de04a0428221e88e6db05efec4ffaa358a67045f76d542ba36b1439fa82c6b594e6319a5607a1cc466039c74af5516b4d332a086ce6f1fc10a2e4c2836a5709131afb400cfcbb0073474a9bc87efda5c54a8dd5101af3d8669dc62391a04bf2ad0705ec94e061922e7b119ecd46ec280a47d46fc039e5ec32b45317608cf0f", .Okay}, + {.Lcm, "320efaf1bb295d2b9d25b57d023c4f3381e7ea94c1f9128b798110b7ea2c89807acdec387c84155fcf018b46358f4b8b9b4bdffc718140e87abea6a8ca039c2ac4d806b52aa1513c64b51dce11dc6b31e58a4ffc1eca030e84e5ec2dc1d87c5f9504bd4adce15b58d1b93e5c720b876054f776998868f256d620f722921c1b26db88a8054de75c8b0c1aa7e4e81cfe06853490b67e9b22f34293d647189201e84a6c9b222b0677334059757c656232ae5409939848633af4c5c4923a432a90f782da3dd7fd86b6ad06429bdc1ea939699d9d1a0fc0810bbdade9b907b2f7fef26c055bf83bd88c41c3afc0063d562f53c90cc129489776bc849cc3940f9474b90590ef1ca5be41ea0d51e279026c6f51a7a8241678e6eeb16a3086f30a551829c4125ea9f8d691c99428d54b5e15060549fec60c45a8ab4baca3378b4550d9cd3f23ccf131ce942ef24669d3352bdfe7a6507a4e5b2f3dfe99840c0a4a869e0c16c05f62802edffcce38a0c317545a138e5d314c2d98e407ce434a4b8a64194af0749c12e749bdd8b9b64bb20f3e4a8a58bd66bcbce00022161b3c28c600960c44d770baba083f1c73fe1609b4de6b144ccdfbc6d34828cb9fe951fa7d60a9fd367732565e4050d051fa98a6177738c4449e6efec9ad3d7471b3b4033abaa0a45f55f1624592e7d91eb3c128f8fc517e870438b0653b4a21a932bdc2b5187377", "233b9ad4effcce0be5d79f3a39ff9d934c713560ad58ef43a1a8bda8ca61db6b0c38eab368d9cb94c8285076a4ed94065621135fa28c651bf86da15d52eec9248bb9ee8785ec2109edaa8cb8b1ade175b73a9e23e55e4f6e659f94c5808738f5b5fa642a219f846104bdaf273a79709c607a4c565c8125562734981f725b563b1d61abf496416b09848889d917d2c13d8b4eda032677c1da52183d58195b680e7f1b6bb137ecb1fc25409c60cb86bbc3fb3732d84a1dc15c3eee5ec18ff1421a26dae68bc21338f052a8951ab91628351b91e6ee3ddde98fba88ba1c9c3e746eccc00ab928a9cde43a5c770fa1d85f8f2506763b5b5dcc9ed43569d298df7f35f02bb00c62506097d9f0a2849b28416af91e8a69d12f948c7006499846de67e927dfd68b852abbec456176d062aaec7db3f405f0a6b9f078f70adae51a875c180e12edfd17481b345aedce0f3852c0df358d1314f839cb22bb48ad32ebe2eab87978ce1847f65985ccda9bf2b3f61c5bd828fb0c2707298862d3e7986dc9dcb1862c3e3ec39fe2198dec8e0b67c4bcf258cffb1b6df4a069a7b1ea01cd18836e19e2068646315180fb1edfd0bdc93c9aec4dd4a08d999eae471d5515cb3f0a8983d6779fda708e2ebff8111f95b76a2d0188487f585ad17b1afcf4ebe41ed3bac6d501060dfc5056a4b9c67f817ead686a85a94c5bbf5d8d24a5cf3abe8ae8ba", "6e3b4098897705c650b7c0b2df2c02f045f98635597124afdd0c8c28164667415ece3ad3a001aa0c592f24d0e6658aa5a453de66853d34cf9a6da453ef6bbfa98a9cda76c212c6c374269e6c9904ab223fef6a321ef63046c2633ebd911a92d083ff7bd5f396f339cef6feb2b604bdcc7dfaa4af8e91a0be61eddcf46ecc06095a66f0acf4e6a51214a09c50eea7280d22512643ce01ff2742216a35638e006f56297e93fbd042f922b8ab56cd6fe7b5cfc585a7452a884c4cb16f82441e32e6abcfd9a744d6fa26bc9d984c58ff65ffca4c6c8961904cdcea8095c920a7da3dc9d78117d2385a26e092aef3915cb08fa8cd2cf172d44fd824ac02c4b4537c2d1858bb4204ce2628bcdfdfec5bf9722b6ead675284ac6419af2ba9abf0363fb8d4d280a5fbdf8cf3d57fbca64d334cc7e524e7c2ee301b80c982214027f0e77462b5d66287b54af9ed1974002f334cfbb85b875135daccecbc172e596616a1bfd7ed29dafdbf9876ac1791858e8941769f48d6b62ce2749bd8b14c547101e4e036a0d2a849e2a28b5b887be1898036ad36c22a1f24439a9cd2f673c55ebd8ab9c92a4e7836bf083cf4647a005025afee0a0769d1e603219a11fe03278ba43e23f59643fee4c57bac238339147071bdbe8d96f25b5e9c0e7f13bcde6aa30932a0a1ee50022194ec0edcc6edd293d6a6d765c78a903ff7973659952fc04c210a5e80cde3ab38701c4ae35605ad3c7856370eb6f25eb89f33f0b3ca4ae6226bf0e2790fa9fa7ef5772dd4d90e0ee2538d24d49704d92b57b55a8a415a8a34797d9b6cd539885b12189ca3376735175ac9130b4eb9d6cdb9d3bb37a17bd531d713f6e0e966a2a748ee9a7cd6bbca060fe5370297054832dd14e38c7560a78e65726351869dda5659c7f4ced6fb82b8b4250b300e9f5851e7a0c34991f381bf94665915a2255719ff21ec8221bfefcf9a63ccc8b4b96d86a1ac47dcd34beab55c164ed2f87846a9983df4edaa01e366853f7e596bdd5b80dcadb84d7de52e715147865e676d343b1a3871fc63b4af112d915cd593fb9d669a59930db72b3386919d1ea0bc50655b1f0dfc3eb421a280ecdbd2ba207882c3450981f5b26cf4b292583e6a1bbe808272aa3f5288bd4c3cc2240327201b50c68d37538f26af339b99d6f5394658e95e05b4f70b3f293af790e91e479c5c6c301f1a2bf174616b25b16975bcb39e0c0021c9bd332c26d5cfdbaa2d9f776fdf0a7dc5bae8ead67f417da5c7b5f13fe9f725175c2d1b4045124bbd745401ae9c750aa4add7b12c71de3a2e43d75e7eda738e7097d460ee54f4f373b7655efbb9c939716df8a51d5cc4a63740653c7415eb05e7c6d0e76464976f2b8cb70f3ee134e540d409ef46daf7751925dfc467c2e547e270119d852252b97a05f5cb75b5a13a711acce7a6c4c8dbc76", .Okay}, + {.Lcm, "-cb515a6fc76e753dc3594aa2a5130a5ab961f30e3b448e8b0f85b626926ecba64a60ec6cc3f5e2bfb1fcbc1a15c20612b9b0c770ea7fd5a39af9a7953b1308d913903982e6bff4579889ddce6814463b9da16b1b5a4beb7a2be581e93d11aa43927dba2f93bd74a805a875ffb1af4a88fba81964abbff1e2256caaae6762a19e752df207929ffd877a2b1bd2ff683dd67a0e7cd11e2c09ef4fb579223fe8186e306326b18b406cde92b4c38e33a1583b97715a7a9ac7cfa214ed98f61533b38291372f95de9d622d2759c591a8f279ffab228b1287ef5ee28dab6169ab200375769cc0b7e9266eda0cc72f51a0db869bbd40a0198a9f2a8ca77e16a53d2f6c69fbc73733a7324695f1be224587992c8385ecc91408d89a188530e38eba1df4070d443f9dd5e9fee47355567a95a77b604ed91102245a2c8533b1705ae059262322d8a04f998d18b15768d4df2725eaaa21c3d6cabe9214a7283521c925da9507abce23832df1b8305794468b4c95506fb7b74d6fac39c0ca96ed33f67a6598776fa788f1137b2361a02ee984463728a59f8f2413194739646d747704316e0827b8ce8c0945d08fc87b15911533ce985a4397398a3f951cb1283f585cfd91de661ddc4af2662c71cda16d0d7d32240ff85da327e34d4324e71a7d8132dca01a6b76b67676ef8be04d1eb5d9dc0073b7aa78e3620f235b7d5184b17961f8592293", "-b20baf82177dd77d42f3c68729cc4fe1b32b3b5a7b6ec716133a28933ae42f2547d2649776f296a81017aaa79a9b86064ddcdd09be7edeeeb824088a7e20b40b723083344ad45a844b7e326478a1f29ed36c529c32c69eebc5ed251e8678ec40c3b78f6c857eb4627a9897e76834205901be8c2e4c33cbf6cba463a127a5e2bd0d130aa22253bf35b2bfdfbcb74cdf2d8be100c066ed21a20db14a5c1817530e1f74b29337f32f6eef6b466669c5b13da96fa4a93bdf36e8cc7a286044805193ab045617b79b7e7f142239e2a73ae1e2e5a58848c69281a942f6f4a744a85e1fdefe4298dab514bfe43150fc21fc051e2cc587c7e359125cf0a22a5749ff10ca32c9443ee2349d91bca5b84893f0197b7864949cdd909cb1590eb8f0758319ab2670c54bf6fd4383a120438c0e0f5d0ed4945e22b47ccc3b13b98a84261e1d0b16a162b3cc36c43dbc995ff2b6787c36073164e7ef96c4144ec9396ac977955e1e60b7bdeedd042f4f1c4400bd1835f77f9dbffac4d2d75e3f39c5fc2f9c7b4c75df743aa39d4876c6b9e4008977a024bd34c4539a82c417114e1c083d053879ea27ca110d0fb0ea5697906b5f3f38a4ecf8d7c731c91d03786c86e0deacf8062ab36523692c9b8ba34ac0b659264990b2e83703d1ff7a3f0e3bd756bf253a174b522d57d3ff2e517a8178981d7e9f83097bbc69c87c206432c4e4ed3606bad5", "8d67d8c48a42f659c611286268cd2a00f0b68e91bce11fa2120066ee2fd3ee3faa227a2ebaae15f815b99abdd5c589c5ed77b55b09cd2ec1cd5ddd0c7986184fcbd048472925086cd7a2ced3d4908e84a8175cf751e760aee4d8490d1c6fa2627f08432f890c7a918b743c418782c18ce08563b22379746318bf60db4b5d145c7e1a0f352612e3d8582cc957c9a3ab77d8b29215c48d4a271db531c4462e3344040cf6f85c570ccfccd3307fccfa81554e269b46754f0ba56246282eaaf79921561ee6e64c0ffd1751ca114ced160407127e396f28d7f07fd8f687a768250d2c76219db7379da0d0df7e23c863793a8b9f34d29f99ad4cffa5d4139257120a5f5f5994192a93bf852359f628fbdbc64f18a6f2fc9de16ea9db34cdd3919ec95cf6eb2573c17258da2054f14ae5031acba9f94f9a0a2866941bbfe14acb22c4675c661b16996de920a31563a6e0277662eeaecdf5fb8afc31386f0c1659ec1492d0327cf7c952099059b694de801fb230cb4febfa0161d18e7296155d4a7fabe72a436fa7c6803239bee2429bbe532d59764d06adde624abba4d2377f1ed542483c05163f322e043756b5eb3b0fe5b0b8b634a10609139b464f423ca14b43d526589cbdbe2fffcdda4fc063194733448e4b2dc9015b69108a2c1e3eddffb59a23778d90358e47851f1aa68616c96d0f6679472b20623afcd297883922bddd6f4f787db03f622b5aa44e23d21e0b1587a77ec85c077821e0e3dcccd81c01d26d2481a1db14e7307f0827238153bdf2b5f433ca3ec470db32b4fcd5641247356996426c8c1301eb8bed04d330a5e57e2ef36a9834bb81e3208fa5fdf801a424fe89574422589561bf10a0de34291a2a1bb8b060d25377ea9f5f950a8b71cd65781e9df6aabc2a91918503e273028b9734f16e2a0f72140fbdb85de5e9f5e02f8e37f6e031ddfba62669bfdc7a064190f1ac664f04f6aecd8725e2d16c363d1b07bcedbd836371c177778e1b6dcecb27ace8621a67e020dec2e6902a85c2f35b4868f894ea4f6950ecc476ecc8797f54cc65c0febec7026a8868b6852a26604c4a633e657a0eef11ba08d3ed574fecb06607847543505123e41cff77f1aa83f92eec633c1d0b43f91329832131edd998190664bde843ad405a065bdea86c6f3756cde77d273e1c53d01da920ef044c83fd62001692f00adc455d3caa9c4e53df311f12ac63336a57e905bc78d90814860eaa3e7534dec49882f0fee00e4ddbe24af40b5fd717b99e6a5658af7c9f54d3de7dc8d2b23cde86a9a8ba9b270ca8739debba3f68408d029980fc2dd196c8295c3ae67263d78203e5ac462cefb0fe51069cfa953d167891f6ace2e31195cf23b70a007bf27e653f8a0989f7608c85d0382f8ffd25ba7b283ff201de24fb7348ecc3d17150e3be571a4d5865ba6d36ba924f", .Okay}, + {.Lcm, "c41b91286e36d908ca7260840ac3bc3ae0f39f6953e834b1f22181311480cf3be31a9bba4b39d7d89e8893072942261dea9b808fbc9c82ea37437cffb267381c26ce03697951ca66b60077740dca3adfb7f664712a43a7e002c5a0167136c942e55d0137cff34c6734f826649063e020f709015fe8845a1b16d565fe265cc37a7b73e7a2e0da48ff32b02a4f09ee7eaaae852eba02cb1a663c7b42b1627679070bf807043f65a4bb996eb39db9f908fc85ec806d8965e780236fa7a0b03cb1de592f16dd7b6b148bcdbcbc25deb59f1525b64f06e4c08a598ebacb249806a6a2b409b92f5fbc0263691db6365ed5e0a3b894b0ea3f0f3b4c3122c032889708077c3cd15bd8b412b5f9c68daba255fe3775810549dc7787bd8ddfcaa2e53fa9bb5729932bc34e2548864633253cc9ca90bb03586b2313896d77bde3c5175c2e430be78e2c76155e9725233314ee37680ff8bd6f8a3af9d002f9b5aded3fea6e9f24dce3f92deff3e4d2b4f2db93567f6778249575ff1c926f145ad25e9a6b4524d6fa21175b4e0f66feed5386031b0dac8a45287a13e5f430b743ff1cf17282677588ac5ed395795d9a8d0c3a7102e27d99c078272675788a5c755386f4ead63d671cce5610125045b50ed445d3150eaf93d4248f79013e527bc7efa56d8f09e655f967944c3283cf569b3052ab88aa5b8c993ac7d7e2aa058078ce220f05103", "aeae6569fc6fbbc4e9a097c07b1fb10c596c36949504eecc2b942dbb3f89969399f691be4a21ae0454c7f6163a3446c31bbd0593755872c2c61a8b325f71f586bc6c02589ab34cbef1e1620217968d372df4426dc79ccf5f020f116559053c913f2ff310771e82ad88807f2e671c3ba5395c285cd9ca0ed946105c6806609b566f63c342cd48a7520f9c185bd3710eeaa8710e2f7200d7d2bc6385ae543db9ddc7ddb81b4af2d8a67207c40a8bce73f020547d803b4b8c1dd2a6c64a00dbeafbc0079db56342eb5aa8c663f1292a352b0c68c1ca71d62480af1e73ca69fdc02834cfdc70e8f2c86cbf1004137592c7ef37556b73a80cd6af6e13b6648b1b19f977f2bfbb89a8a5c2b3308f812b47a67e4e845fe244f0565258f785249e2808bf84ff5614afaae647353413decd7906d5aab0ff6817d21995172e5f7c52858bcb94c2b9e2fa221fc7e8f62b7564cec7710c7e2c636bebfd31f8f33dad5a4ea2b846caaa55c4f5f95ba9333f91998a7303ed826c3ec7191958d8942a2a6817782ec8e02504153f772761edf26d83ef512cfeae9b8c3a59e57c9bd3c5751d461a4cedfc8a40c13d7b4ea1faf6a3b3173ee895192b9c2a423364567fb8d42f02fc5226f00c580bf2f6d7016b7da0850459d20f965f9ea7a6199bf7a89b6057e7ab98afb6599f1cba60fec0a4cc2334519c92ffb4c6e1f6a2f05bc2cf676058b126f1", "85d055163558688b0dd4634cf1e00973274b233670d7fa9afa120e5c83d9c81805adab02a66d6c879c88737cdaebb0f6a05fae17ce64d6f9c360588315e89594675027b3b099962efe680b3a64564939ad31bfe1f77d1683d3c600f91689239ed9ac9a88a8bba5fcd809f69e63f5caaf508846cd2f27efd4d0e888028892168ca288797a7437f2b20b4c88c3b4a047556fcc4e06a14676c87c5465a796753dc6f649c4d69901423f7e292b04a41a0627b5ceede19b02c7858342b81186d9beea8cd33821acf8f957e439b61f66196189b8ebcbbe12bd1e5a2f7f8ef21f218180a37a771284b97a17095fdb2aa052838aadd5310580ab408e2d15d6c2f773e11b75e06ca12b4c5f1f56b5e4d2f6fd5a897bad344d1a848b51dea46e74b8fd37d260237383b52afedf51625e67994672a8a2e26d8d5d5588d840e0cefcf0b9d0ddf5f16419bcc62516b73434848c7188c04c06a2765baa555b275bf8d205ee733789858a24afb6ced1e3abd6f008326e1d35cea8f3fc6957b0632d2b2843414fab8239415a1678f770f7ec0c9d04a9258a978ce4aacb0d66931b22993aa22de21e7c3202ece91346f5d3bfd2179728f424e5d4eba367ba36d5187e542c5789284fbb2375bdb12122476a157c30c1c1956ff5e11a108bdb09c410f9181208361c8a693e11129955729d787aff295f344b150609dc19c247c20680f1d321446ceb28bd7d242b5dcd20f0112ff380c8e7ed2c541299bd4f55f1ab71edb4e72a067a017894552a29b78b26df37373e9888f7e8a065e5b056bef444fcf2efc8c2621011fe4939da4d388f44bc8e57ca6d38c1e6d6368e0d5f1b6fa77da4856e744ffb38e029d87fbb9a41597883b47cadcb9df8049d7d35b7a2024f5827a909e2090fd5ac6465014971d6aafee7f54c73ff5ef19ad25be203cc75ec2662f79dcf478d9d14818d7056e75080de6cedb2d9d8d29d5b5ec4d358fc2806bb2c8b0b6b4f237e15965bfa71c93e59a84ad740b9dffeb051538f1934f29608c9cf9c5678f43540181bcabb2a5a6a78947ab45161a7d2ab76cbf643acf3acef667cb518d33dc12c7b16d8a8e77cbfcfef79034a50b21d6c4e2b2592098eb812ca90366c8c348844fd60c293b241835f66bb59df73212a9008e39d7281dc645bad1adc0d1295677d66f59ee3ee066c7e55a32803109a983910bcf03d9e4b048176876ff6079565f0c1ce86598e5e3213dcaa298c590f8bb8326b1d316dbdfe9b5b631f9656d1cf53b7e65cb100b9871cc533fda7cf2a09807d31f63a0f4291042b1b6c42035e5300a27d1f5b212a3c3ffd8dfb1a097ecb7e688812bb0c2952d939f7821614e352c034215951619bab053b202cf4facfe837bd36b501aef88cf9108860b853878b2f7f285354084a73e2437b736e3a3c35aaa678821f0d18f7df3d429e5b955b5d3", .Okay}, + {.Lcm, "-2c2c5fcc3017682632f8db894bd1d491b470603b30bab0027449288f592eea150222904c9bf2ad6aaf727adc4e1b3348d0caa64190c42848b6e4a4ba910ab0a662dc87381689baba6dffe11124dfa4f75a4031fe6d269fa835e95ea750c421e09d43acb6fec70d1cde1ae70fc32dd75390c03485abea17dcee44409807967b6a2b348f47ce62103c96dc4bcfd1e98b03e09531ad4e21286649ff2eba69b715843af804698f6f3e6347bc32d8e344c19e359e31c398afd339157563e5b89a07ab2dda3f75f7ecdaa0c4dc3608f0f5ef611cfc957f4117151ed3d5ed41bf2777d058c6061e8b9ffa6b5caaf0e45e09a6531dcb71cfaf3a7d471e1251d91903ee2390e36be761dbfd3a9e63c00a4e1ed200989a9442140e34be829d913cff018463c1e9fa5d3a404bc6d2fb1c356074c1486b3c8299396fbafb21db3c5dc0a2eba7135f46ad2e373aa3339ecdf21bbc9a5c0cb438eb1dec8a0ef84a97a718280585b9b17dae4d3cfcc5bad8fe879f7582f318c203ad2d07e2bbe77f330c4be64db84c682e943b9c3d877057f3c583adddf1fda3b3aff205d5c0f6ca7738d367cdc1afa3d1d5416cb2afbe7d01b510dfedb905d11b284dbd0295ef7921178f3b966ab57f5ec15daff7f1b8ff9c7438862b37709da93aca48ce41c682b3425cc219fdff5db7da5620856195dd7df12448e8dfb424c38aa7dce127e0428dd45d6bcaea", "d43c3864fdf4d191fc9fbe107e5ee4df6f8216ab13e8fb407ce7f1d2673d0d6b6477332a74adef053650517128e5872b4e4a0762663eee8724b139caa1e57c7996c1cf6bc841913b345835d1a5e0c645d94b172f50583080d10df9e8b09da14fefc10d6204e31f6c1eb744da3c2666eade8b1064ab74b90a9f4f4f2c12f85a70ddd391fe0cbd02689d367b85a60f896ad10767b274bbdbe11b0947d6d778493e857a9c2e9ed32c4596742bae6bad428811f8eeb7a87611dd7dab6aa3358db8a6fa087e3ba41f2ea4c19a3cdd2e7f0d819d32aa9a433d5e461f0fe1bf0b5bee96b6e4874a9ebbe0eb9ccbff6b348920adaab999eefd444e6eefa22dcc3161fbadab07ae1c83fce028d89898b8c6e77127ec0e139172288a9201177c7a9cd4b57a472c70bc44169a3a2a95b760b768fde06eed6165d61b12777ad9cd28206a899a31c878c974c20a11f53dbec4f087b6a27b2c2d41cefddc8de2af0208b2fa3e448814f25fbd977e38483bbd77d5678fe39b1c5d17816986934b668a8e9d37f0015966ea03982cadc2dc95f4c845840408c438e5b3d4633b35378da7df327e1cc672e6746bcfe9239754d9e7d389035fa6d5962b72418b8f545502201028026186578eb96df964f01257d28ecb59e053e6b93a957660b6c8a66dccde31549a521a3b0d75d96dea46610c20341403b80365fc11de48f6e78d6aa5dc4aa63c1a72cc", "124f91bb56e56b92bc159f81928dd7a4b1c4feca16a3620f553223382898237161bcd6ef9f112d738613a13467c1329ea8d05c0f016839fdb9632fa1b6aef4106a5c0e5fa052d9be974a79ba601d4008a1caa7fde0c96dc135319e20ac7fff61ea576ae52cfc49c01f3885ad73e1c5ae637d0f0de8da66aa6f982e7783fe07a74b1730242f888422a5b2baffba496d04d5874dab32a00080e4b12255b8d2e9e8b4327b874369af815f06dde65e70a4b68220f7c6244d8a5dcafe5d0806809b50092fc00babdcebfc83566deb038e9a4485123652288a8b4ace58256673d39659dfbc0bbeaeca8f14ba3ea6b369da825fc807c5aa952812bf7dcc413326f3e3ac84d74fb5ec503cca7413a783ba56e31f0a2ee8524d3e1456ef6b60a49e6795c27d23809854af8af1574b44772ab87fc9e143a8a75ba91a842d96fede3674b216a4a1c10529e1031892ebefa535e1f46becfd83762b378b69d7a9a4aab762a4a1d2fee1620eb4290b4fb815ed4df7f38592767f3bc0658c9bf291241cb21cdb9885217712dabcec854fdb3c916cba425243da5334694a1e986906bf08038f0406188c4f955c408e7b16ae189557eb0d5e16adcd2adc3d279b9638fb00ca296a0498db8c8653bf9ca662638a1ea4ed7b18976ab3aa6fe98a83248e104c1cf21ef28be69072869609e6893efe2a7d917aa022d9e8d2d11588da34ee7d1d22b2c11bcd2555a2a1a8836d4274e5723bf935f33d76be83abaeedbb62c1eabbf8b86eab1934b56c97d4396e4aaf8d881929a0b77afa08fe7a5a963d29ca31c5beb33be9148fc4d905269e91f192b8d987e0d68f291d2eeb7bb2b254bd9cb1feb6cc914f166c085dba1ec8198f9e500f93bc2a21f64daa6c47770532b3b10b4b8121fefcf344b681aa0568c7dc23b954d64b882ab6264df7e3eb6b3f55390f7b308c20b46eb8e163b9872cdaeeea3d292b7c6c0fbbe25de46b8b08ea308de1341283e3a9d15ae1df6b91411a6171cdb1d1f15014f3a6fce632bca7763a14498165e37cf20df82554910b9b3222b6d9aa9d23959d93506030671f540bf295549a4d06962d2f89b5ff5d9572fcbd1846c6de12a032e65dc66d310e8e9fb90c50b97bac89f62ac66b5cb4852fd1df0cc54f8e87ae90e24fba8d4a2c651c3edd47656c949bfe6f5c26781c2114cb015e7b348033a5fc184720d411de38c5c010aa51b5ae09e33a81b172d79439fa368dfb175006f7d717088f9f832602d623e5a5129be5f3163c208db9821227b3c9498643fff7cd51e06076bb7147714dc36ef349ec285a8dd9664badd8e272745e80205187bec162d0412a81a05b4e444dce5234d71def932c971dd0ce6c4b7aecd33c77281e441e34ce62bbf19a945672bf2565c66a78ee797d543cc0feea7e7d18262af62321e0a6e80c18622648d4baa6c788f302f33c", .Okay}, + {.Lcm, "efeb4a7fff48e35e1d4499f57eeed46c0d34f15c0d0bee773d32610f5423dc73b94b7d7e3944fd176be0ac254a1873cd886a1cecb8af2cee953b14c1cbbcab8e66e2facf046bbcd6160258cfaf33ecac376b204fa732ba2ccc139b4ba073a7cc07f27fe9b05e64b96ead80b4b60cd7d60c149d38a245f8c5564d80fdbc6e68cc3a4acb50a382aebb444d2023147065572d33b7c27a3ed079a5dd3d8208010d63850d3acd580ac89f43261b03cb21dd22f22a083b1442db6367a9a9df316dac308627389a43a5e173a187db8f136c04107c3d902a4293a5a83770c4cd029e11b245f532a0a6e048d462bdeca81a2f54dc33656375ac1773cec1242d64d6499452230f8097351002f473b1204094511e2b7b14f097770abcd599bf12dc962b87e50e234ef79f264df98f03e04b196d333062c9072c43841e49e70830e4a3f13008ffcdb51ce42c22dcbfacd1aaadde1b688851d73bd501851bedbbada42f6f2693c056b6040b21e20c4ca521a5e9c980bffb48d1a7e04e6eed824f5502d51b9705cf28d0227fc89b0b9642e848302b3db7c3ebfff850e492e0afd1c74b54a0efef0c7ab9fec7697b39531241b436af2b81ecd430923425659c79f57487214c26ebe373d97defc889fe872521f58967b5b4e736662a2708fc0298b20684de3769b9acedd0221b24589f0d3eb8369842a63fabd58dbde112162ec1ee04bc6e59e3f7", "-e7a7caf14c46a8cd5e2bf456de8c60ed03524ee89678304d841a42d5e4f6e2df4fe3bec32ac3e36465e08ab4f0c2bb0bb33e5d3349c2983251390052c01ba4eea41f154150c88c1fe3202d9a47376ab91102d13abfad5fc998d0c71bd3e6581fa5c5bfa1d25d2977282d0041d9ab76327f2ad42e84ce5376ae62ee4a3f8b2cd3bf0b4f5d932fca5d1e6a1f8f79e5b5723b7a395e87e88f682896406f20c951573659050fa69a0d6481964b41539c03f806dcdb04a7f23772de65950387936ffdebbedb593b0885ff583cb284fffccfeb74b2c7da07eb5a14924a9c5413984bd91ef635af040e9c38f4bb2ae1c2153176c874781804c999c17f9f3e2a9ec8153d486da0ad48a0e3e33a1f7baba2c15f7cb3ac20096941e61dee6fa24737955a8bb9b31ad3eddc2ccbff74601e2ae4d92e2d86432ad8c1f4226adc6f002b283030324fda1b2ed073bf9eb8461bb4a8d431e539579e3c669d8b9e2996b2fbf6bd89a43f72e0764188b5f88069f8a4e63e90497d2d04748fe2c053bfcbedc5be918a038594084d44410828e491ea48c794800247c3e92cb547d36359e9b97cd4521b9c29c650606dbd42476b2de7045d6edb818f9ea33a83b503625cb01b28ad479d4b0b35aee56160369b7216684462f9473fd4da89714a6b6cb5f4ef4eb16c20c9b89b63819ae202b4d51b16892e17bff964c2c5f687156b2bb63c34eb765b8c", "d91a90e8e5a0824c552dfdb2329b6ef288a47fbe23641ef13672801b0d5b79df9556471ae7c21b1e327407dfcbee8ecff479b27f9aaffc7e38e945bb030ab3efa870a556033b63e28af29d9325f23c8ae92109d272d31ecc0583fdd77edae72151f5af1d7af75d2c8301fc285858d65e8fb18cf411c2b8fa15fc4ef8455d387d0c969de08a69662ec2a28a485bfd5cc1d0f58612c58c85aba6abdc846d8c56d3d7374c8f2a19e67735176f4aa66c090bccf2381abe0b9fa220182befd9e7d8486cbf47bc3c3f7b198572d083405066896674d22c4ee2e968ebde4b4acdc6baa9ecb5649abf4483516b305d9d75315db515e227fde2ab36cb4325eeaa2e98441a603651eb9ed229de2c5ec7ef5021b13758c851315eb76f7ebdb095113385ae3e25f0fad88d365ada4fd599f1616d6ab225c600224bf42838ee488029a9fa0eabab76d7c352ea2cce05ef4bb09932894a890f798529f30f1844ccda22ef7c87c680f3b691f588a7789051cb4d41e7a46e9375548d74162faafbc110630ddeeb0d185638d8d76000ebb9cc94bd7fcb5e9c212076f3a7c70d6ab69cf9440d1cec85e95a7e8e00002a0d09b14b5a07ca50293981317ba4d93b89e6fd26ae8a9c752e1fdf262e9f7e2ce8a8ffd6b4879190673ccf77e37a1de45b79833cf7655219710ae7e21cf4df9ccb4d64c03de9ebc4e069924ad57a7dd9eaf5b15fdf357cd4f42da49be90b9a182d3a53e06cee201258fd3f5b0525d50c26268a243acec2c93b0d71388f21856333d81c2f92cf605b3e8273b232f06e731f960357f1b75c21c670616201f353feb78c212f5795bb44970b6569f0fe5171a5085beb6e5dbae4b62578fa6edea5fc90f63a534e8d0c6dfdefa3bd41e6cd38c4d219ef04286f03ef784045613690910c746af8e4db71a25182df8696753b4854485d26052c5d9403607ec8c84f2d6eaff0d0cf8ad25e1d685fffb29e11e290a7ad914e94114d977d2dcf8325c8ac4d6a79b2dfa8345516a42bd0ab7ea4f05295bfeda813f50cc7351cdc69ee140afe8b7181bd0120a94945de4bca62a6ed23cc743e8b7cf57179a07c3d249fa5aa91e39c904917837f81a554ebce92cb4bc137185841eb788a7199d4350b720241866d954eba5e2206e4a8ff8d913382c2705566ed88120d69f5a7a8749b3a55f075118efb0c1516ba514e8d9ad4208b17011fef26ea5f3b06c644fa527a4e0827cb809cc1fc2aec339507614aaec342782b2d798943c8b19750a64ef8bacec3b6c8953b7d84b72f8f97f750133544ccd3974867e8e0f46583b0510530c419bc0a9848b438218755d301c05d716107cc6b83e67850c68b4e993869c8e1d47c090e7dd8edef7877d2b1e8eee70d65f892e2203c98d49597cff4a951f22544ccb87716ac77ef3c220a7ba295af49daebd4db23dc4b26251e0b7814", .Okay}, + {.Lcm, "-9160d499dc67bed1ef0c7d77f22cdc6d4700a23158f5b0b84533b0dc3abd8f69184d28582d580d63b92b59d2eb4df5c29e6e32a0fa9d1480f90a08707b7805884327d78589f09e853d33cb01677d3f05299e7b1c0b5c760db438bd3586d7d8754056a09f6925036ca8313c82151917b40e801fdfa035e63cac0486b7730e75b95cff36ea458469b71e2efa1d69dd030f45b4e24933989ebdc1a082f5a3491af3952663f4c90a8dfa2efae0add3d80ffa19842e065b6ba9f3bad27cc991d6402cabcd87496ac839d6e13963e83ca06e0f9bf6e0be516a35e477666395a60a47e6c5e9a7c0496399379b9255c9593a1d6cf0b1f4424215e15e77317836ef2a30e9a3517a28289392cbe29f5c960a0f7f500ee739fdfd308920a154fe7a4e91ec8dc0c35fe1b9ff3d2fd97cc96de98eeeea326645b5546fef5c86b811ad5fec7349113c09a4547c5c2ff3b696baa45397181ddd29381597cab18096bbfe5d19582d8daa218d8c900a6c7dff8db0ff5a07abe686a58bb3c3dfe72924262d60827b89e3861fb333b4c6e0480920cbcd95c9163c48c884b907c3f254f35fb939e76b431bdc31750598ea74be3ec6d02a03f4ae6378a4361df57ff41c8979e105fb7690b94b50330e79ac9fb297b1349351273cf2dbdf78e3d91529c2e9098568300f2e0b27469ad96bc67e78a5ad68964013af18c9d8ff48bdef1e112c1ca8ce4c27d5", "92c1fbd1777b91991e544fd427ca03563036577c15d2002847c0782f42e1169f31c38118f3e75be92dadcd864e4a3522a8671e82fd433ac9c4c579d37266f5b865d2f6d02baed8984ec16afe56c78725c5212917c32a01a328f522e154c902c172757957592fb334e10c57062154a51ca14a2b44cc31ce5b086ec167f1577c2596dc3dad6fb58ba9b5a3ac3ffc9b65871e642ebbaff6b49d0ad9cc7341c6ecfa9aa192238104a38c65e70138ea37da6baf1c6c883cdfb57077ab55e0607d0622620c5a1135f7892f60e8d6a132156bf7811c5c055756723a3a87542a48314bc576d4e12d7d530a9dd5537cfeb21b0c86f13341fef38850017204609a4d976cde0f6ed895b23d53efcfbf11bdae2083aa16358e2a5d314d7cdf51d5dfa5252f8334bd88d59b24329ff49675e7091faa1dc3ea1e1ca3f6f819af0228503654f38eae8da9b01acac47e295f6df14fcbe59f3754eaa9a68c43856505e2f37acd4b2e63e5777dd995d89bef17cb0c0309cb351df256fe843758deb17f6a7100a5d59d7218f4ad067d55ea81f7a66ead2165a6f1b976edb7bf9f202a2bbe258636712bbbafca7c67ec268749b891392ede0060bda220b4588b720d01775d47e1c6f20a78628ddfe5c67d09aea6b97c7f270c2471f8eb9b44dc1c09cf35a7e5c4ca65ee92dc5e6e004856264feb57163f205b45d896261bc96a819fa99c613a952fdfb2", "53576240ec0cf0c9b749861b50894d9e3670cb46c7ef2bb6487ac6a6ff08f1739d00511f9c951cce0e926abd4a17e44750ad823f0bd149fc6c16f6aea20405b86669f15d6c1a112b87c117f9d6a3a6e21238b9f9a84d559e99a217d917ca30a3d9505e6b4d2a236b2b027583e0d1586ebbbb44ef0672a2b6fc6440f528a88eba70f776a48e4afbdec9f0c7cf5a8ae3ce4001cdc5ac3ff5bad9b2d2fdbe211a32c663afe8d9d4c53286b490fe67d46f9380a433fe6729543b9d3a9c0e83c6e8d824328a3a13b7299922c6db29b5e3bada4a63534dca434e2fec33b5f57722a9a34e67f5a5dababfa38198a47edee1711cd8240f2758ed2e4edeaea71f98519a281ecf049b32e17b7da3152effd6240c5ec38aa34b20a3d38df2968c8ae30e8d8e14b3d6b6c337f788b0ed7e80aab6877a044a68b65ed774fa0bcee978c6aa86bca80d4f6d28685ed247d23a3ed5c6e779d21f1ef5b5c2908d7997729dbf833d06e5bf513133d871ddeb85d4291e2b7978d97d44c60866acc8c4c3257a861baca7d9cd3541401b53c4a45f3f49fcc73b3c01438b3f5e45678f7380860efc52495adc0b3dd7a59b4fea5473f6677134a8550f9f49d89d24f71a8785ae75b14919314a71f5be2a6a9c5a67dbd717743f305b4dc0a7ee218a52192cedf4bc1e6ed61d3948c11f0a2460305b99904a6c6b41d52f63a1df64d2b86167cdaf39b6053f2ef8ba1fe36113926d9d58508cb897c428c7b40f7ad37e9a21e4ce405244ff43feab731a55ef44777e1bad3358292a609ca82003e69295ae1f276ee3fd3b192ce7b7fe9a9a87418717e28d1b72bac97d3185b12c4f29c58488cd63fa97670a3ba571d7f0859aa3656e878f559a388d502bef61ef92541976694baa05f73c30ff9c1cdf390d772c36c3052e71d02b7ac45c566ae3c21a60908d5129e69b898f516689645b4f63a2e539734d01aa4e999be3ae809e7b9e111cd963a2cf5fd823d8e3d0806ad65f1c3bb53bab3141bf9c8d52d1532ef2f9feab9074060a6f74ad5f86a21b5ffebad667fc9eac319f917839009cbd5859238442e08da2014994c0ab6c068b81ae6f1df1f44ff0b52e7cde5e550453221ee8d682fb2630a3bf7848ab3b285ebbd8c0d893b7878e30e0178b116ac62cebd6e39e588cca2febc18fb1c8e1f4cae7e0d2e7e3b44f03c798286dc23cdf57d5ceec48d25907a8089702810a58265d3674ad40d612aa4d9d4741fd7f039b13ea18c100ee990b5a9c0e1051db63dc29ecb2d993efd98d7b8203d3559e89c58f23a6c8f248052892e0919f4cc6213e2a9a6ec75486a1275aa2ddeaed633340322e33c12285fbf144628dd1781d21c57a5174b7ce3a99eeee8504dbe19b1f4827dbd9d82d7f378c590214c35a775945c3c2a8fa80b737e6a969f1d464ecdaea55351a2c58cb0d5bd7e78010c13d1a", .Okay}, + {.Lcm, "9adf176b70c9055083e1c5eed425c4115f811f8dbe9e2f4f442a3782b8bc9b469dcacc4aaf0667e051eef6563e2646c4900dd7a0f16808738bcfda7973c8ac30294230645cb36713a7fe688b803e409dd0f9a732b8f122af2f83c5b1887fa791741377123953bfbd791c6bdc553b53d25585d0d2330760c4c5c140ff9d3ea1679cdfea55386da7a19c65f8055036f03436d8ae60b571ad1ee144a6dc306542dc35e7fa9cd80041d5804e169f97d46e20f24ba9fdc7d1f597614a11b6278f8813877af22a3462a210bd169d92ab0e79d29c64240adfb928082481f5f8f6737bbaa911ac8572230ce63f64642e71bd0e7bca07ba1e09f1da33ab169812aa9d295120492d80c4f7cad39351fdf7d9b8c073bceb97566a901b503aa0bb6df9eeae7aaeead3573d7688cd350c0a7efa52614b4945bf1236e68a9c80c15736c1056d34cf7892df5b93add914150a2195f3b98392e39ede7a751e6f4c59a319ffd43bff595836464f1be688de6f6baa32c6a58cb575190174592151790d83cb5b7548f0c08d95ed10f05e459b694cc1f9d03fb8d70acf77be083086455ef8d3d2df8a1841570c20b9d65e75ab87853094701f2dc17246a4ae5bf5b35b7ee950568abf992513a5a2fea57cce86cb8fc10f34e6d16b2508af570ba3104a70f713f06976434f8095af49b830648b891335a7ae770e239c4e7f03a7c2ecae0bd8bd157c2e3", "-3db5ae49e091a176f97d171bd6172021f55b695ed24bbb0a051153d924eac4ed3740cae7625325144a242ddfb6fdba77a35cdc97d6bfc2eeea46e1ca5e07163d76230af2b361afe94ef917969c932fa6939cee1e6adc6e9dfe3f04d8ade6c9a21d19b8cd2d7cf33e5a6e9cf3b3e72db1450ff9fe9806cc0259e8b17afc5d5b3176b60b53fa1d469b67b8d21a13d7e759a138e9a78df3471536fe66ac2202fe858b65d3cc29b9b437e8386b3cf0cdc71fe18e5e52ac114cdb570e6fa82bc0fdb9955823f8fe44f9cfab90264cfc63b10b64a9fefd091d88e43934e5dded4da68211e3766b99cfbfc8c96fae79dd1dcb09fbb8a9438ec2bb966e3d009c475220eb38160cfd7814666840c4679baac42022833c76068fe638e414cdf6f6281c7061331c22eac13af053151056e5d5667cad798843c1e7f9dcfa52ed385391f4c20ada6ed2d1e3189c4c06e6501d459cf6a02abf68893cb618165b242775c8cef18e0bf1acf6ba199938567a0d609973f56527996c47335c049b6aa06a371dacfe8aa6d72eb3d3e278f5ebda18480db19bd6a03b91e7c5fe877bd0bb753bb80da9b7ce70e82648aba626f3ebf5112fba91726a92609f6cf5b03a2f39777c7b3c57bc72684e759e20227ba8725300ceb6f12389f92d6edc3a972c88a01e954633d15e64d6b81179a560887667cd92a5d51b4240afda69d839239f915432e98958fdba", "255511c07c3aa7394a52170b9ba34cb101d8df267a8420e4375142245626f5c5c8c6661b62bbc9a105389479ee8beb5fc0aa542d590dcf91d3d68b5223d91da1f8dc640610a3b7b945f010421da5e350e3e6b06f6caf060d5a94c745341fc20dfaaf75898c2d8e0def32cafb8ade9fe1cd9b1f0cb8ffd80412a8f30f4d500ecdb2aa0455407507155b2bc2d003c6453ca72419c6e41e62424c71a768efdf1732b7ea91bc409541ea38cca4657931bd253e831b403fccf94adc1b9822b29d654338def9915bfe20356dd26f7b786bb89efaca85cc50995f0e04d8ae2e239d0a4205d2d5a2888967d08856f0c4bbe167b2c3a261e33272294b87ff2b053e33cf8531a9caa3dbfa34e0be1579f3e5c25fef74cdddad6b5b86950a24ad900cb21567251a746a4a75a77b096562b8963a96a59518d19826af21fa0175d64ad99c88e796c6eb65861466567a919011a6d57953175c81fbeea1d75d3c0683a61d841c9e7f35bae4b9cb8d1d608dec58bbef48044674310fc11ea0d65bbbc4f8c5ebf68446dbabb83f24c853a9fd927edd7ef04976c1e430b20f26d19b785de4e3495b7340a64dc306c76d5f5003cbc4b9d6e989cb16fd838e0b1484ca7f611a81da83b28ba75fd8331beb1ff7c47c9c71ecac0713b54e024c806ef19f15ba671a5d447f98f96cdadf73a9f19a2ec94bd216766dd7699a38a642db711f3a6d100a15f0e70b8e301d1fb876c9f387caf6ff8bce080c90da158467182b5a28efd552e219041fa2fc3dc9c9f2850537f850cd19df1174715f3a0deffe015f243a37b30146fbcb5200e808704d59244f87f7b317b6ff93a08423ae52fd6829e77bd3d948f66ea0632e4cc627bfd07b18cd510f4c2a2622f3f395b24156d39b46695182f1d83abe26721a4231cf8fde77e707ab3bb3bf3b4eeaa87bda3240e3d714967830bf19c27776cf36b7573deabc9ad57f4ed3574ec0d6acff6f5757227a31626b69033e1dc314078ca7f1b367acb8dd81b36aaef1710772aacb62da632cfa0dde43a4e5da3f967826323692278daa05b80d80516d4502809907a630e748416818f07ddaf831f4d466330fe7f0ba797e719f86a1b689c5446c10a11171ba40290e3a8ba437262e3c7aa0c7c3d509eb66d08f772f5771a325200ce984973840bf08532de1b4a6ccc5966c8e60f2032ed966d1510888b3656328d2a1307d1cd40154ca6d48ddb3cf1ab60acf7de56ae2851d96f8c209be9afdb916b2c79a780bb3baa3351c56d9ec0be558c35a8845d704c8107cf3e35bf98f9de5301097ac3ac0c3e24711f383099c9d72d7e5516a5435c12a71d839c511d42607834df611144ef5b264348cb67e1f5fe39715339b42dc6fac44e375fe1f56182771342d99e9930100bff504e04021f8f13ea49218c23798f39ff1100ee59f297c880b021898b4e65efee", .Okay}, + {.Lcm, "dc7570305a53e8cc12fd7ce273a66642fb518ce5f6b2d552cf3265841ec792ddd4059acf8462564e12e558ca774e8e6ca864e60c79a42724eb2cb302a798bc7579c823a40d8fc6b396408c8f7757d159d27eb14875e5bc87015d61c30aa64392d9553e488e380f829fb33eb2fafaf704b73d81e5e31655a84b00b2feadc6d8799986685c69049ac87e3e6aa437958a569cdbe9ab6336ec29dcfccd60c840c1cbbb45d027a48328c7067a76e4fd36da708bb3e45a1a84c99ec590bdf09615e1b61dbe5ede3529a1982a381563871fa423f99c792710ae38b49b331879295546413b0d19379b2b2c11a6179bfe262937b289d276e2d72cf46137b3d98d44d90d4d615760f581d850bb9108a1447fc7a73b9b81a812b846a2155bb886777f23310a67ceb4eb7b43d889c370dd254195e840f287a9d6ebdf692380e24c35285accb978635cd4b5dc7c7fd10ea414dacdaaea7d31894e49e5c08e343d397c982cec7c6839258d6a4ba1d51bbf53b3f71d622a47ec7a18f4611be54aad8663637ee84184324c4cf77ac1bfe86f906da8dd2ea145950d37ae23352384f60d461221930ea23125863d217da1a664ff1d07b153c81925e144a3041aee321cee34c245a1f659551e8d18530c10f26dcc2e0e8e99fc2e000b755e060ef74f739b163c29bc5232d2fb43c9b21b1deaf30c20315885009ae7ce4088351774e44f0d6b2e32aa69", "-6b2c12d1c0a5a0d42be1e05a747f2699a4b3e4bf81944518bc43e299c4fa06bf65bac8c16feebd9c154faea0e4e61fcbfc568314773dc9ecbe6bfd878607e8b8a36353ee8a921f65789b1a89c8fbdd772dbf5795145ae2de41ca1f6d2bf4afdbcf4b69399eaca951bad7c9dd285ad5f26682ea65b58406ca2325b82abba380cb116970a28a924421f8bfdfb23b72ca05d33cb35dd7dba862fd2443f110576a2149d1e3285521eeff059e1c23690f34732ebba0e925f3719ae4648e4c256d0ab795408b7fec650c81baae4c7b2d4b54a2693f71c9969c037fa582e797d166803cdf2be0c1fc1ff0bb8f6e3e80b5948cf9c394a16532382fa388a68c760f4093ab8ec4183036ba05a0a4e5418139c3ddfcb4d36fb35be8992a45d781aaf446aad83e5edab40b555d1ab2dceac5dedc3659b210337aa21a88d6331b6b37e756d7f8e6f88a153ab4902a782105f3605f98370c5d96911582e5fa5f0cc673a40fa579d93b6715dc18e7b70a8de244835203dc147f28fda609bb79535dc4640cecb99978f49e852884883784d2f6f630e30014f849114bcbcdc60f4b1e015ad223021898aadf9146d0f81c555374855e0821302e99fb95fe053850b23132d183f947156be46d13104b670560c7946431dd30c60c3f523c6b8c1bee65ec91497d23f7d55eb51bcc1527131285ed88d5aeaf5d889811b643e4a834f7557599ce4220b778", "5c4b0a4861bb4ce2a3f524272b31f07c8c9aa88bc6b1f06361293bb7e916074310ff81274dbdfb64d24b339589ad4cce629ebd871d881db66af14cd1118500687104b3a1e1669bfddd57f4c70649463f684a3c912934f8d7d3051e2cbdc089f71040dd408e70c795f6c6a902979df4dc9835a23e07bf34d328a6fc14fa6f7935c438f16f548dbd8a9165e7c58244b9798f4d7c907997f129b27fc89681515b2d5dfb2b413ddc6fe763a874e207871e7a0450bb36e8a5500d708ac08fdf6347acc5f0db9bc2febfdcd8e198ca24c0ffc3779b3a51e670bb57d8b3098d8e39459b73cd21c215295c6c9399335c3a86f22ec34348b27cd52f5fbea4f3e191ec218ef9161e630386b98fdf5cf2e800d73f15f90e275a4167c2e52ae5988a1bba8d0ed9475d1e9be6a0b06ef96fd7a004d3a95e368c1f85ac1a945b316b6cb74a0614db96031711c584de0d4d7897981a74b8eb82fa3771121686d689a8d72a2efc0fd62d9c9b31d0e9af28395c71bcc6be350763564ca4ea6634ec83d005d17bdfd6b551f163dce3fdd35b445f41e3930742dbfb4b4edbc3a5581fbd56dc5bbb528bd42f93f0647dd24cb46eaece0daec755c42b9ba87faf4469530e4cfb0742e1edf1aa5295f772e8e802f7dbbbd9a6a7b45523f594b0a2726527353232e8170c7afae30618295d43f50cb485c87b1d034e32e9d46d4fc4219a41195c5f31cb7db8afe469e4b475563f75d49dea840815b487a809289f043952b5e52cf6f8efdb9baa2e671c859d35c6762b0ec1e293a410b7345573c5f2c05d2b259f28ec0ce9f634863ee55d20a948a4b0681d88ef92d5f62750308f3ee9d171540263e84ccaec390842c5eeaad5c9e81b6d37cb2f7582e0a1ff3608e9d434d34c74390b323a9783114a0824096e7d7423b0c9de0a31d76434b5475ddc43f18adc34d373937bace28410c20b6a0d934fcbfccfc2c889ec7747df346a2f8f2fa4f340eb80aa351ef8f658377c06463d071e306b60b3f1404fd61f524828c7fe2e0d0c3d9b2cd26b83b4a37de5b00ace50be173dbd5d7e455c8549db7cb72b7cce84c804fb58573219c392c280101f71b72f07ad72411093f9d880e9b4f53f0bbbccb87000899e61618654551f2da8ea07c858d6ccf4ab6f6cef7b8cedf3c82b64cf8bb2949c0f3bdffcad9f0a88a6f1f5a292314e7167c130a9b396561b125377015f582126fc2c26d0e28f5b234eff2f789c8c65daf7a0a5dc3e85d255a152cd6c7f8ea27be58680f44440bf0ea6a7867db04b75b1ed7e6c30ab26bc548ddf6c3aafed3fe683a2ebe7fa9cd0b9d903236f2d1ba66270304855f96ebf95a004835eafee36607dbd4ec00135951bd731a26ab6007bfb6e270c921140a94b601fea02b5356b726fbc9e76fd9f0f7ec047b64e9b8b108376c2fa1d42b1c37d033e0a8fa0063eb0f038", .Okay}, + {.Lcm, "-5407f32c2a5453bfe68727df902493ff7e9b29fed9e20e10223196beaec7df1b58ff7d98accf13aa94c47dc249e436d500c366ed06fdc1d2525a4ec5e3c5e47f79cb68b44250a216d156a8c3375a2234ac90f262d2ab668cd7b044ea9581e43e4f7beeb6bb64c7e380f4ae15c1309663e627db0571e1f8fde522cb6e2ea7fca2b0194118ba43678eb58b765f8021d661e8856dca1ae31c7b7f3dc11d326c632cb7a6132da44deb6664267a1ef86040d91d14bb2d986de0d8db1709c60b96c23279b39bb10a0e7dbc26b6cf6aa46ae310ecca89db2306c498b6533200df6696ca5c72cdf15bbb40e9f0b942312201cad4e12b442cb99d7372c97582a342bc0305585bc0dafa2ab99002d5c9f1b67b5736e92a2ab5378e81e87474201100f7965abee89bae4965bfcc2eada382e6b57daf1912cf9114960ec0e7ed7b079729e3789b165d4cca02e207c239c12f2f4aee470a723dc36e498d31d009fb931e3acc69318d5090fca1399fdff47260620efee729c4aeffb7663e90ad6991bb17e01e1311d5ec8a1dfa51a1d20d1bf7846ab0829b35759e925a2a9e3a42046a49ca110a2979007593b54126c98ec42581a09c3a801cacd20a207a3bfede27fede68b5c182c77151f15d594a9fc8592551a1428c9da0f8e2fdf34491ed5aa5d4199364f6b297aca01f0b0642a3315b07b8ff40a563dbe5ee506b9a3212a9e1fe0a7e6f72", "-1865603e02a120027f818b0340186fa3a7e0af73baab6990d57a702c6c91458a1233a0a224538b9c61fa0e973e40206dd45ac17c793b9b8e5a8e9e6a2995e1887ac7557cecd89a617a2f380ecefdb144a5e6ecc17bc55bbf0c9410479794c4e89fbeb4530a0251cb0958e30d1dabcb4b1a214c22a615d7a64e6429a6a5405dd6b5b85f3538b038f7f5d8255edb2a298d7ab91e4fe3b5670cc4a6230982a28e892a2b8fef1b291d4b523bdc80dfbd134a760b022e35de05df2d28cfb1a2792e8a0fc0203756792c6c7e26020cf7e435fe955a741dc8575b296c4d7c952d6918993ff5c5611634f774c75fd8ca59c20f837d979e19842a30cea8f47d1cfd82aea07874dc8567f7074aa90c3fe78b2bf9b9c6151ef7cdbecd4dd109b8ea7993f4b4853e8efe1248e38a41cf8cc6f6137e1c03a4ddea72fac4060c5c4e6e00e95eff5c65c9a22a808cfad6ede0cd9ade6bbf9ffc5baa29804547e50a59be44b20422a8e249078353d62add8406988cc2b7823e64b3522c52972aab4150d7e4abc1a432a88a1ce3ba082d226c152f8cb80abfbe478df794a094569a60307c069f845cf31bd3e3f2bfdb45b58dd39fc455f5846593cc20afad2fecaf584c0022279bf20ce4633e399580ba3164822092f5f7fdee9aab855927fd1ced0cde4211849279d578935e0b917f7a4bebdb655dd0f430c9d28730ce4f7d56b525121175071798", "40102c3352f818c7fc9044a89b83c6d96d2da9e428ef482dcd75c2c8103b69b9d5d4f6606305398f002c178e97ba84c82a3fff13c4b6cafa8fefca0992dc6c70a8f54f570b53f265220a0b8db64dbd7b62453f68144c168f80c35908e2633fd45c771179cb526fa511c8f41f5375afdc933889b3f095781f7188f96adf571d45e621ae7b3b03f411094fefac085dc528d577c2a0b5e54ffa62b7cc4b173450b285aa64076ed37aaf57a1af24ddd5df200932a51ee4eb24fc43df9741257fc3c7afabe4449700d7159d1c00e0400da037498a81e905f606146d20dd2090d58cc8653d1c7c505c5a0748ac6e01f8adba9c609e5c95bbc600e6e0c0eb678299178686ccb86fa5b5585246b2951b54023b840fa25856eb3b4a85ebb6e9bcb563c7223706d16bb845efe82c414d98f1d946c4f692f0598f460c7ff085e5671fb97b2e013b6818474c12204ba60beef85b361f85a895e741fac71c211aa37cc87e8faa22d46dbcd49d0f0971c9af4168ec303b3f2c9383fd8d6545d3ee5084d1b469e5efc9fb1488b772c7caedce5d17f1ceaa24bab79a719092e5cc2487628ffd0061091ecf580ca1fe8fb40c5e77307339c21f3e1776c9dc097fbe2b49d5bc4aa0abc5b4441b89122853b41b74daece18eb0a473068fadb51570f530b768b79c61f1ef1b50aa04cf63c14d5c7905b088c7b324ce914c0010193c8e8bec9b32d9f5985b1d280a002ce4500720116ccecfab7a8dcbe16f0db9b1a74542672cc050b5ccb1bba13da4edec749f8826d0ac62d52caa620d7cc5014951eebeea31a262abc0c9686b3c5f8423e38cdf534515bb7e2e0d8873a3afcf0894f3f23cfb35df8f375b772ad61191f5cc791cf38e7329375ea0ebb4fe161e1017b25a9fcc41d140d1b92f9c7c09a36e876d1a4e0476da7e632178481c1053e0057a0f01ed8492f4b383b367603cd8d1b3a75e683448dbb927746956e9367d93703da7d6abb639533d9903c122ca558b060d95133f24b24394889cd7e8ada47bb0535a5d510b6591dba7f5207fbb81164931beb648861df7410b6d837eea77abf81955141f9a3aa384666182347053df6c32def8b1c89ba4064a4d0465e141a63aa794bdb3ab9d8152d0fc4b00df21534f4b0814bb7fc4184cc144d658559f49e0db22f7215ecaea09886ba5773a18ffee8618385cd39e8f0b1962a3df6b4e188c9ed579d7dfd40d26a8ae408802f8a64d3a9eeb997262c0370a5ec05fb4a7fc39c9c564913928eec07d3c0fa189ffeb2360db1752d5fc02c514cb52586b78dd1cf6d901c89b4bda01bcf912ccf86375994fe0fa92ff2086f442c645aa51ce597bc1fe95f07063aecd6990ba47c79904fa0aed790f7c3cfe3e1ef99865a8d0601089b2acfab53f53f15f56c7451a42bbdba9a624660dc57a5e694ead32f028b27f64fbf5ede99b4d8", .Okay}, + {.Lcm, "-7e2af2f16db8950c2d4c28e0479d0225d9277520f6dc0e5c0c4eacad548f50149a22395d54aee4e1dcdc37e9aa73e233d537b275076a0210cb28edb7fd77cb1cc5ce846a80997f8c7fd468601727d74c98de812cba47847491ffc4e4c9159c79ddee6f8108e9dcfb40725ec334434c5783149ceaee3a6a5f012f63014b7098b703340c3a76e54af276d8848181ae3d24b54c94ff1f02659d2e852d8bcc06de7f145f8a50db6ff97d170164a512567a7573d644acbf623768d53469e5d9d5b4a197cd9a7c2487fba0495074f183e734c15e32bc3ed8fd6e0e6dba7f5c75e29cd8e8c8123c7faa44a503c3141824dc54b062eac1319bcba9b32a964625cc84e84a010172bbb3b34bf44837a697f88d889fce4b0aefa0f066ab45d70130b6bb95454b9fb4d87660a89dbce84204a39dbfdbab616542a5dc7ebe340a7efb8b9f5c52de0b3e59c36db5bef634a3019684ac7691d4d04e004e9e587e39931b75866bac74a13c23dd99d1ca0afd34d32f73838e727527099e0bead455f15e2439d4d496d8757f36f1125f05035142ccde63fd41173fecc31a72dec113c49e9960a3b518f1e399da4a4fdcbb0c439e84b87cc87c11d2e18b30dccc172a4573bcfd136d895570d39874c6b78ef4072c289f353fc35ee5ef34c6c5a1770c86172a36065af2d031e4351efcc71bfc1d06dda5906e8855d571fe3bb4cc3db4c7a6ac8e9cbe67", "-f812aff3a6577e63db71bf5f346be8f333e458194c3278715ec423396a109084eb1d592f6f31c56308e5be476abed2d194f6a5483aac48d11b1718129dc7b404f8d2d81349a8225d7736dfa6b27f548001bed88f7138aa3af41ca2ad627289b96db8d16637cb317110b353ce6e0a461051a7c1ea7fc2d031641fa657d9fca68cb19df941f35fa6cee8e17bbfa7e2be0327298cbace4802fbd3ff44b83b34f4fdff66d8d298bc1dae041eea743b1e860d9575d21b1e6e0ac70d8db85b5572068a28eb49ea0f5101219161a3436c4b11fb4cbc463372a7a296562a42d3fc7a81c7b35623297f3dd002b90eb78c70eb0f5f4553dbfa693549d38b70fd9362740c68ead59f331ec6a54071184d962dccf600e616ad2b4ef7ae610cf7d6932acc8c8d82c0342d702eef5d50b556ae918c0274b671e72e8606b96c580958a13d19c39feab670ad503b0312de455cc4c52cecbd329eabfb26377f8a2a2db52db4bdf5901400e2abc3621b29fe88bbca32e1ebee4b6d977fc806c0a791c41e2c4a7993225e91a522ac43785b6bf141a2f29bc2f08da48707e3de45ea5b3f9421d8b693cf8ef0683d61259d9c12a767f5e0980f8004054fdfa8d9ae4dbadb8eff80486d396d10fe05998ad6a815357f5140deea3a7a1ef7b5705a2658fc19d3199763d916d7b338b42c57631761c540087c79087a27d6fb0a2402de4099aa48c95d3f2fd4", "7a42d116681724f6125d5353c51830e6744b2357f32b4619aea496f4d3c88ee58a4385120df4f8f0d24927a3293c8c1522b2a67b5977c0e6453800cac88813bac3ed1ab91cfea9b8c8c88ef85429b62624545d348beceee287862fad9e7124190b25605aa224b4d9560af45edf8448f7468b9f7e79196b1a1dc88549165be5bdf45de2409d8196d69fe7fa566d8a810672e66e2b11fa174fc7d591d1c607e1e70b23f4f878489783c0c52bb5f13594f332a54137355ea4f6eee0303f56576bfd57f46c32590701331371c6fe13e215ddf9c4406ddad59acb85024869a96ee587fc23c326492e518010d27b65f40e1c437e00323ea6b7fe1e61832de6504cd6c1a91247668e8b42dc5ff0909fa403a6e7491e10867dfe66a794727f90c462b5e56936b223df51add3e9f17bd720aa4e7d130e5c4f85e40402089ad20ff0064f0ebb71f94126a9c3bfda1e8557dcb978760ccab56b7df41952c36a39628d1cb730c49422cdfea5c8ddfe4d680770a9e6d39c3a67a7c0b074fb830ba37e1cabf7ee6203fc2e5389df0c67a04517ed984807d5967781c75d0f20cd7006c4305ac7571ffa96cb43966bce46c122b646276d88427c9a704395bb1d84fb61cb62d7fdcc629e93ccca16488b42bcb9bc2191740903b44ecefe73f8b18bad3a796f3af3250f22dd6c5f85dd54bf5bfb8cb4e426008e53d1e6942a8786e4f01f76a830f9c13905addf9cf431526f1b596cdd6edea30e8c14a70af097f9fdc96a07f6b9256db944254953ea602fef479e6c20de8ede638b36cbd28cccbb09f70fa33c19ced2f39282cdcde2491c02d5dc1299c79727e968fd34cfa420d81c7f3dda8905782d53ebdceb384698e3057b2c2791270496ede5de9465289e575ae9129c02f5497587d1058f09928269eb55bf2a184029f2c1c408976d1070c8afe91112ad5aa31eebfe59f44b9eab45fde4bd248d1eef606ddd5a44a5082548e26f1dd6d9455d501e960aadf182f4176459011ccfd6d8b1e3f2a8878399d7c425d613f459a33bd291e901d93535b2c8ee8a0e872876c79fb24f6d4d9f40050c162c66ca76194c242dcb678fe0f2217ee4c408a8178470c1247a078f926fbb208d99f0f4cbeedc095a24859ea64439aa1ad69998d9f1924716f7dfacf0e10790487edb78aec7c8b22c4dc59f69363fa044c25bcdeb01b96f1ec9b304e187db4b9ff489a83c1efc0d0c2e1132024d4dc6469fdc84cbecee9e4b9a701eea7f5cc3312121c82c5a4648ef5b0e976520efc16654ae8ffd2b05f7fbf3fec34dcbbfe7c749de8eb2f5d3aaf9cd07c17a7be06e1f53e84afc29ccd96afc688d6d35fe80d82746ff46f57a1aeaf90feb8f64b8cdb9f79a8de0f18a586cc5ca8bf2080e94b1774761635e83213c0c1bce46c42ad1b11a03569588bf03ec1f6d82c5a42f331f3a35b2271b964c", .Okay}, + {.Lcm, "-4805bdcb52963392f2d2d6786f5ddfe065fc3a075470976adfffab4fc5f89ddc32dfe558ecd9e00fcdc94f8c82ecf99e4af98a1aeb62805cd1df086c65178f36a8db3fd40a35c8a0914dd2f7d9564a00a507a651d4d9a10d7c356519277abc5d526e9c86d9cc2eea7b2a83fd9d02344e52c8a260c73ee89336de3bb911adf684e19863d31e6a0ab04c68d54485faea775aad6722468500903e4a6cfe9966e3bfdeb30eefe63591850b93ef42a08573d8768e9252536ee7c4a3e44a4a353fa84653fc6265622ad6d6fdcb8d25fa971a10f2e8873894a87ec3a6ba3249f2b3a789cd4ebb078284023413127bf2cd1969b03d9174b35ca2bac348ab4290a3d1fefb1d9e2a7414c91c72803cfe677f171595d9b6cf18feed3e06d274e34c1452a22519053055966f74681a537cd8c2e32f7327a0eaad7d3fc1e827a16e252b1b52feded0940e0f25ec5e07f2e5dc835681e4978a24aa634c90157ed115dfc0ea1c2507e39e4032451eb5eb8e50e51f2a979358db258353fca1279aebe0255807108f1ea15183933be547e634346145598cce05ba0f88810f1427d5958200f7fc96b33455e5da43b39d95efee5e7f86c36ba8c9aa9331119ebffb5cd8ee42c0b51c50186b712a4f8cbc14edf6a66173b0d10454aa5c9b328aacdeebbc9ff54ad92056d380b2141a0eaca5c0ebb0f46328a59d352eba606e43aaab6c20c9254fed3b3c", "e2a3b0edecbf48ffc556fcd9b6adf32bf6e28c640bc7f754a211de027a7642d8bc1a216505ba0a31a352de56feb6cf40a931b3b1d409838844f536af09f19ad101969591b7b5511ee5c330cab20cbafe0f49a5f9926616fa1bc049759ec061a2ecfe9ba1a5538f2c0b2721078339d5d6ff1c70e7222d57323c87cc165cef4cbed0bd74438352a394eef8cb0c9e0dde9b88c2100c4609e8af687ae8be08acd4d9cbd8fe89fdf905232b4641304e94cff5ad03f89bcc68700728191f71c6e78bedf81386f260e912aefe53973e18c87858bfd65788a26dbe338f8a582d5cdefd60ba3152679c89ba5fcd32ffa50865be410b28536d22fbecc913a9fd1914cc2719f085e470e687a1019a3f69506af06487e537479828dc5f754391b4755b5d33a827a75288d1fd920b929532d35d5b43f97d62f6d453cfea4d7c35479bdd8d1178500de83bb81ea3615f4b1a139c8e9fdfa50d3c61e5e0e3e20b4ba64b9623006a8211fe319c39c01a5f0a38e8c86bb6b110bc2cfe3300c28587a430afb26f442e20eb6fe29e56847fa878c0ab2de06515563a0b56a7ebe62e356771893da633ef8e250c26e28f6dfc20c64dd885c226c94901787be3a0f74ea1cf083cf5e6daa99b06b7c289ee9db4518b5a897c4be0013dbfdcecb687cb3bbf59ec90b3d0d1b04964378ed7d06a668f2c2c440333a2dd1cf3a95088e2c20e229a1965e8a7ae19", "3fc31efc39c5c8f6e6e4ba0c3631bf2d6599308490d9ddb1da863fe10557f6ec3eb2d4d44a3e2f2134ad72f51e0f6cab9ecfa0bc2b2abf3ede2e0e6a0bed0ab326596feffa6b8126a1babf6df7bae8a7525dc127c9819addb9b6511cf80a7a1bb2c8cd512fab4a742e6be80f301f5bffaff142bce4f0a4f7d62c28f27dd228bd811d18d4cfb44e2ada956a4de4ea09162832b3e1b49d7cd628eff48cefc596228da95eea162e4f89e96e1a192a3440f83ab0c41940ea3729c37c6127194c614a412a95269d82eff766ded1012d66b9a77f90219778ee5b82dbf025cb481f60b380194fb6564b35e82468069f16d3d9f6a9f569dc3f0f72a35b178de8c9f3e02540692260508eae97d681180525714ddd426759433a584d1d1b4c957830725b0acba4ae6783b4532a1ef8c7cd4db72ba6fbe5ee5d17bc5a522d69bd1acfdfd399be8ba3cf0a024ccb53211700dfae14d704d49a145c040b1f1217c47277a5b14b0b1e7f6ffeede50e626a13174991e2d6289a08c7572476ee20a5d409d8f5581a2a8ad3c529778a23bd33b0e702b19768eeeff24f0e633fb87534d311cda7b32fa33fb0732b4a4910becd9379564151753cee9ff71b76d1f0e4cfcf0137f64779c9e2753ef4e360169610fd73995f13cc4ca5fa745f8f7c55ef1947735a8a2e122b6107779ddbc5f14b3d5d12b20ac438a25b97d72f3c010bfc8804e7003f47e92f55f4c8e773b0c9604b6f45ebc361d3c4f3f0db28e4bf9c0bbbf73dabfbd016c1eac987aac00a85f798548ec357581853d4023117ba725006db632380b3ca6b636181c4526061c700f07392b14b4588e6d70158f8f946ad90c990b377daa91eebae2cc7e7bc3146ae4bac60e166d60c7ee1bdf63664c73d747fd4fdb54e39c6d40d5b518cad81fad4baed2c56478bab7fc07a2dbd20ae2cc4606e9b097ee3a607d3818c396eafd359bf7a2b689a6469fa73090d97c080fdb6ffadd81af8b92bfddef306efa28b2607a3478172e8e891330d2eac9fbd6d3b784599d0659a6aee8ad449d8a6fffa95276eb828a8cea9ed7df4fc298b15520d65c648ba57b5607e43c4fb82daf59daab250d64ba57ddaac5c3e00b27d9e1298cb29b89781b13f37b2de60f2674c8a86ea52795a19509342367e3dbd74aa7b39a82ef23d8edaaa580a104b45813cc9fb2709baaad65ff098cbfb599f6d0bf3acdd8867b6b68fe51cd02f37efa7b6c0a7871b01644da3b6fe110716b541d91ebe23416aa8f1559852f724d107177a28237337100c53f89b095a6503bffaa1bd1864aa6fd91dc3abdc6792c7e1737d225e89597cda945de2c4844eb2c9928cdfa8bbb38a36b0291a1026bd9e0e476bd8f56b0f63e983e0926c6e33375535197736ac995701d21b5c63404e09efa72ae8aecfc016f067d0db1300bc750f94e5ba4b2d2a5d14109190dc", .Okay}, + {.Lcm, "-cd8823243a77f095da67f0a4a585392e95b7d1ba83f602e56d812239255b25dc8d03fee344514e36f913db613a8598e146f940a3ea33c036f2c22ad722a5fafc0aa042fcce341cc7b83a574b3d6b5132f3ebd4529821fbce22120ac956900383e734ab0e51803fd1e0370d4f4647494b35703e70056f609ee03ad2e4d69b7bcb623e28d09a6ec0ba6b21a1677a1f16d950fab394fb772744de41bd92e93c0a2e4ff8a3cebb5bf3b9ebe00ff7d7f111d2482840cfce4a68371ebe6c230816ce8723fc3f3e001c30e8d9ac4a212f1568949bb1dd8013825af8873f78576a74c7e03f4a0b1b27f45f760d108f1369517678fce4ff8a3cb0080e71c724b39aa632529d31c9b6bf2e99f99e4f5cbbefd3a4feb28ad4ce4dff8a70f838ebd0f465ed7e471408e316f84460357a4698f387080bf8cb0de33d5d7ee533c1436a0e3375f5d8ce37694e7cf5a6b9f67cd723c633566a5a6ffc986578bb9fa99c875a49496a9daa911e26d6136c337de67c6b03406fe36aa9f8456d19d19897985ae3b5abd095fc34de3315d4c198339a95c9af512906123b6f04fb9c360a04dcfc7770d675a7f074b9dda1871e3b1a9ca189594aeffed24f5a7819eaec375b28e3a8e32dabe6d97a04ca4f0f6f490d8196af6a77f4088b19aeee19b223fb82019fce8aae912c095e065ba735ab58e79f69d54681472a2fa2de0973c5395eca06a063472286", "-4c7f007b5475ec8a7ad4bd83d660a6c34c326c963a07c2c03714ad887c95a174e5b2c1f7260d2f3a01ddd9981309f2acfc117f5b16382dbf5b99c7362a5ea96b036f00401ad87a999451f0ae58023777922f43d5fd7d647448368f8ca9220eec368b71e3211f3673d456049bfb7995d663f3dd7876c9bf12d47c1aa5b26b7f35620f7c23576e4bca33f93afe34dde6d2bb66c14b68fd0e4eea955ab36c543fd9ed7872c1354dbca52b3fdecacfe476b16f06c9119239ad092a023682d9949df22d2c6917c0018240c50372c303ee951affa06e5195e7657a4420feccf8feb203ee38cad970f938a16396946ae293ff6d957952651c8a0838c9c6ad20d178977f77467af276922846ad8f3c76b261983db3ff1554a5bdc42dadf434ba508baaec25aaa7cd30bd10643d06a008ad33eb857eb8e1b9e163dc9f42c242f96cc11b62e7b9e55cd3a4eb8db54d7296d166e0a52daf5a9412f1d2fca67f3d8b0a8edcfdb2290da3ca20cdd9264e315ad43545d78437b6336bf3a0935c007495fe758d6ca1062303e40035851fdb57047a4aeae5b299e63415a464f2633e2b8bb4a723859560485674ffb8c319854cd346ff2583ae32ee62432d27e83f16635dce0184a3b368d5734263b54e91b80e2fd597516f06d5dcdbc69cd8e7bd44e64852062912d917115c48e4b03cc23b593346cec246c83920b873ae7047b24cec399c891351", "3d6a615b348cd7fd8ff2e5d521f1c0c2f04cae5184cd3b346937f68bea0c0dd894ace745136bb3132c7abd7b8bee70dddf67d152708c758e3f8bf43f575085347b49edaab8ac519e39ea2b973e629a0dfff4593b1a6e223ce1f5c2a3fdf554d26f4760e5fe830cf88e6d978de7ce94c3e7fffb2117ce23ad6f185bab50c442b6a7684cb35e20e467b4385418d3a7f431d53f8f96abd70a3ee7217b2a5d6cef5618d6f718a86e39184664adde74085c5974725c6ee278cc5badacac492871e1110be5826a7974925e725c5c145a0412d218d6c364344f8f3c870ca4575822c57c7c6a5fec44fd7ab79917198b4b54bc050fdaacb7175123371f94ec0da69ee1bf3c36472011ffe57d797a5e386bc76bbe37fc27602dbac3f17c4d544d04f9d524dc7262399873325105079f35860c36075a7d618a1ae7a81d713465bcdee9badbb70b175fe0aaa82dac1da4140202f0cd59777cfd3a983585f66bf45e044b77d2483f4b28cce13e9fadaa63e8fd6fb618077e663f36ac9648ea1b1f4a28b16fb1cd567c4f6788e09606920a6e1d0a2c0301c4fb42b8fd005f92721f244a33e1a099a2a25ca3e6ec8b223551fff0a82c4d829b50595caf96ebdd1bb068deb62fee19c0c9e440ddbabcfc1f72227ba92a5a82f17a10a87850bb029b60fa0048a0a908f7df7405e8dee31c09502fbf7d7b3b455f444af5756bfd0b6d96deb9b6cd1be7a77bf607be2c4d7cc983fa699a845c9caaea5fa494617b53c6666a6af411fa550c3f0a805a23125e5bab3ee1c64ea45e95f543334bdf1bf2121f96ed201d41e782818255523f4c543f03959a2277931bc70b5478aa2f7c3e8d169da3999642f8962b42fc148af82aa39354aa62272010a7f242fc2a300ae08ae5f413b8246d2a4a706936668bacf50d54a281afa9a5e39fc3f719e950b82bdc6193b665c0a75bb93b10ebd136c2572aabdb868b5db97ae586a42844482476a29bd0e4707b7afb9959dc64713c3fc5752ff36083bff73430795f22cb2647503c9230cdaf859ef6e1791c58a9d29aadcde90f05a050187328025726cea66e144214d5115cd0c0a569497c5c2eecdc4084af07b0450069ec111cc1b7c1190876b32960a10adf6dfd682a33641d96e6ebfab33b95c16f9dfbbf3d558635dd27c070b3724a7dcb72911347866f8d0005283c5a0e4f56ae5342a730bf92ebecacfe8eae578581c8e2f143239088a815bb354ec5a282e91bf5a019adfbc4b9ad1b0ee51baa2ece191905332a0634f6bc8c2b2e39d7d20d642a515e98dbdf67b4dfb14011badf0fd84f3b6ca881a5127df9c6fc3b65a9af8ef4f8d13c5e5e8d23ac1adfc8d9d264cc7bf5d4536cd63bfa6f20fee6dd9dbfea0ac29c94a917f2cdb5941056d815d719ee7ee7e0a3208f4099aae731a809a680da781908ec3d60f6dc5f30b20ed2c7de66", .Okay}, + {.Lcm, "-e6cfbea70557f3ecb8856063177efda1d833c8dcc61a818cd51d7c2544e988a9e84f4061cfb7c56a399899339184b0848137b893796421f7bd1ede48796bc6c115dc5d7319813ef7d77fd65cec92d1e1e486199cfe3111efa1551487bdddc4cdb0067b66e95f4b4b6f791aa4d36de92ded4a7a1034a1ab59b95f15af6f1aa1b8da5f1920107d8a78150e98bf1a4f77eac5b7814d8a352e19e08ff633a5a0c0f48cca1c22e36a1008959bfd571121313f5c25bdc1b6d8f6fd4a196263950e25d67402289b37a638d6f3c7709a07cbe11602e852cb1296efb6b72376974c5ce9b217732e29d216dbdd4f0f72584ce82625d00bc6795840e2030e87b81be11ef49a7722a321c81aa9004438d711fffc98c0efaf216c784e43441c87af111ee8fff1602649c2f48f954f248415b259c715ea6ad39c46d96c8eaa0717d327dc096e22c001743d226f8b8a4f30c4fbfe0196fdfc5ca568401a81e5d12a18a286c530101b26da680025b2d2d76f9eeaa8f88086f05783c57f19b78c4e0bfd48455dead3b66816903a62a3d95840fb83ac10c2d00a273a6ac348ae4b06455d84a86098fb0cbb3d5d18838d84b17db139a85f7f834d0de283a17cc569417f5c8009454b10e0460e187c554fa6842ef9fdb8ac0a50c8b5922658c61ef1b332ce82d9c9d090bc735e844f252065f85eacae8167a1c952c1befe95806a496c1dfa596395b41c", "-b5328ea57c98bd560f6f85f457eea8e36c7178013b2b2bbe17e3f7106c6b253944b9e630e23f97d4d11f9791d49f463cc366053bc606d2b8e4b2772e1780ffb8f21c96a679e17e14cd1027f7a42578d1d7705b94750bc4cacaae646457440d470a2b3fb258e71e4181d73b3a910987c1e5fd607cdc168b1f1be72947c3a829c15fc1ec496ce6a8b424a71e74a7aed1b45bede3e8b1aee161e2275d969710c85e9624523679a8327426ec5051baca4681fc16190927f7c9c7d4e4e74a2001339162286016e925b8ce6d35239b6c852064f79f8c26f50c1f7bfb557563e4800cdd9b85660c0af074b14403352cb5272db733ab026cf4e8618185e52e936f28254beba3854421cbb8b1b48ca4859e7a2fae5560a57bad1b169903b59d6d33a12c3009899041045aa6a0c76cb0df6b3a173dcd3da45c22e2bb82ffeee3a9a4707dae7739b4876e6740c9511fcf5936f19b6b53f6528ce22ef25e2a0d848312509b0aa5a8d13d4d7656ced82ca19f83d2aa14d9a54f6813a05d4ad5bbef4d6d77f28180a5027d0f74ca139f55432411589cf83d2aebfff950267cd4c12c4de662cc5e69d886db1ba421d78af54011a243eeec2d37f53c790ac5ee48cf2c9c47355845bd967cec9d876cf33de29456f3406cbe4ebaa233d747ea6ac35bc195f6d920cfa1dd47077a521d0f2651f8759e3613ad89edf51bdbb95870cc571c72ab7658d7", "a35e76fbc36317a84ee7b792b40713420b64d9d3959b4b782b31adacb57523152bb36f9e01b8c1d4aec31fa6052537fadcf643dd910c5db8793e37b9b6c56277c6cba993105ca900bf69200ba06f1f2e08fa0666ccab779bcbfada444810b6125cd750511ac1adf1cc7c6bf3ecceecfeba1de1d05646df79a8c89a894f477862f02f6fdc1cf00f47900b8a300b7c2918eabdac570385c5d9f4c3c4d64aa50bac74a1515727199e604b7eca51d32782b4582521bec27a9ea8163e77c0d5a7c958602265014e8d441c10d34c6467f7e9db1e7ff51b4ba09125777674df99d306fe7d5c4cd9d1f35f22b3061671934b870b2e9abfe07229a52b50927ab2057071f1dc29aaf17b77ad11f50b508ac1f91449f373372abfc6fa4c7d359400678e6e50735fba4e61ed6d548a8ce62fde0ffb467d06230478f9fa1b87cd01ddd2c84f9ea50bb040c5cb4ef9569be2ed7383c3cdcec577578e0a8c587052b6270542e7a5eac8e1c432eb8ff7ef6c25885204809db20d2e3031c7eb473dc80ed78b2fafe6106bec9c911832ebd53bc6842c6436fdd79b1212c53525cd5880bb7e71d4842a635b09ffe9fd1ae265d712927128c2ac17fc695421b2fa0982e87755256ffe1f5304ee6ce11c040d061b879db4d6dda1c458cf8251921f04b7faf8ec30ba65f64ce9ccee36ec614c1549e5e335e6ba74f488ef1d513682461085ad7dd2f4d5124a060abd19690d148db66d2cd60b9216a46dfdb1136c3acd3f0d0a3626785acc6f0206525d45286ff2721df43f5fd73db84bfed63caedbe79bdaa93a285d00556133f83f646fae1fc8113051bf6433a0439aa687db14615a9b9fe0892b48f5e0da34a0510321be811ecb28ead7b1dc041fe0e6c67631f6c4900dc97e5c5becf3b90e31a6a4fbaa1456ab713bafcc737ae34f4ebf8e8df189be5286df780e91c2458bbfe00d3f28e0c8c3e78ac2ae2ffb062f7529ac30fc9e10c6ab5b4330f51d3d124995b62d107cbb1d7c7db21dc405fe10a550083e9be9fdebdfaea50bcc91c1402a8e3651168efa803351f297888b94534b10c57f1cdf7937c7db2feb1adc85dd49645cec5f96e483dc2a1198bb3a3a387028caaba9f26d4b5d8ddfe9fd07efb923bb8418cc29b38dcc802f89a1001dc313d5d09d2ded5ec574ac16f0caeb05451440ae6f2685302a0295a2f82b861c6b87395a2ce25981f791f6e970d44a06af4e681fdd176e0c7d6354b206a3e8979cfc12e7b1847a21d3593e5cce24d57bcac9ab60c11ed952ba97d59582b7ca65ee9bb81d4d137705997e43c37508608dd86e6d7bc540c88ceee4f9fe9543ee38601d073e3183ae787155bb049f986a410e503af102ce1df321003aca80058b2ca8d99b8fbff8b9dc95e5de4cfa03c2e7582867a12b082c9741b365ba0e3f38ef8aae269c8e2f3873d62615d18be384", .Okay}, + {.Lcm, "e99cd7566f1bc5fe04def00d3c2d7accd7c844f09541ab8927bd394a10523726fcef0a4a194bad7cbd01af0043c148dc71a99ef831d1e6cd65488eda5848f2c369a9800d5efc3da057cb7895474b8a6d76fbc01b8b5463666bfa2e13ebb46904dc01b03472b9c4e039c7f317084f6a4565305e53cbbb708d650ee3a493ad854821ecd9491e63b1b32d8d8f64806924487e77d3c732d05cd0257164e950ad71556b626aa314825996efdd3a5edc8ce73a2282d0ebff3e08e871da18aebf9d1e4ed88747bca68a918cd4e937cdc225a09f8cb1bf9b7cb6cf660d907bc156a0f338c2b054375ebdf12ca417c532ad5c25bd929a12951438663ce83eef3bb4da05480e02c4acb3e642a0352ba853f1dacbcb73e860e45ddd0f940f882360433f15b9384ab33b96433ff758d8eca8d46ed81384513a28f5191b30835b450b8717e3a3dd523515b0a7c2c1e592232c963218e95f22496cfaab74f0212bf3a61d81eec9e86c9abe57f57a004a0a26cba4d662cb7421db77a8613bcf6a3de9b030d64388407680e446f8c84120439288375c2109e36e351a0369a859938872eace4a3f8e3222bf5d8b784ab674ea59f4a8f789c3a9fc387019d3e6d0411ff8d3776a416e9bdd2d2e36e5a3b478025104ec367ee8a95514e6e9fffe88b38a2ec17db130b48d8fe01e168b9efd0e43966a02996206069e21453ea68a735797943de94ba72", "-2d1704c8d2a30c6af1058d6242db473d6a49a25295225c36bf2e9f23239c35b68acad568a0870eaeb088a0d06d453f601719b0a79fc83906083777befc00d048860866d4cddfcf14e8329341a6e93624c11d24c9811fb769c05c88f843de2c5940278123d32945fdbe8b929d4881e71bb50a15690f42aa37c3ada13fb633f3a7841364fbb2e8a1ed510774a183fb434becf5904718e705854d5619363596a6b5c0a29da64da43b89ed9bbfcb9111c128c8d84a9797d0e8635314e1e60ba8893f976a2e5e256bbcd0f8f3a5e13a7166c894064164860b5715f7ce35a6a7239d90740b4f26adedca3d53be99b9fa3b3acedee90f0db703dc06357a43738f363ce07e6be78fffd9f4052734d84246ce017481b57908c0ac7e6798eeab1b0e05827b83ceed3f33446b9cb8a97ec1909e1de8fbfe0aff342d70eee3bc136ddc29525b62aacd4ef714d28bcff590c87a2ed5727943960d8cec6d88241389f2db6fea19f7c3b32e43cd50b34ebcb8350cb0b1e8c0906d825ffa40f4ffa5be0fd6fa09ebeab986a2716bdef0d629500f048dc9df3b6107f5eed0eed9aa5d6c189fff5ccc2de4cdfe24519eeafac4e1e6b2a94f4678992795a1c3d5356240e6edbf7f6c5c129e6b232e53b328efefcb50b5675b48fac86f3d780a20090ffbeda2effd9d9740e347fa11f64d4be20ab4d8bc3e1c3194ec3c456effa60abbdb129721d7c5da", "1492c9a7a03472b350d05e53c7927492678556008f1cd1dea0c19a85105ca242b19ee7474ce2b5aa7222f5367197d5e764c531b65d22bcf4c0fc5a0f441f2666078d86c8555d687be546c90ed5309f11895ef0226fdb728b02c9c3c0f5ef5589c14e5f979f06d56501966fa7d5d87f1daa2aa56a11ceb2f8f3f5ae47d3fc674b84131ef18993844e49df588182d9d9ad49e07b89c8375d40fe2389ade09b16b332bee0ff6e1d9718b07f57a92beead47a42d2046e2e3fc1a7ed86a655aeb014da7d0c4a469d0eb7a008a1c6e8e7e6319f784ddca7caac0933cf9c745bd018948cedaa9a94a8f91ef343a568b3acf4f62d3b0fb08795c6659b07ab11656f1dd0de4beb8be612de72793ff8624f9490768f67e4f0a21e209c15f8efa5341e35c328cae1bdbd4d804f24a91238932da86ca96926daa24d575a771aa356fee167e9a394d422d577a1507de8ded12a59fd39fc33ac2aa8c8c2753801aa2e2b1d5745d41f84205bdf0e4355e9202db209e7279da10cfedf8b133b5e8a65dcb16e8b0b90602f1b6cd3981483e2aa4733a15e78cf95a3bbdb6d6ac0432e6177dd7f0f04d054a3ed243ee5c844b6f81a0461ae083b5f43e9b219f41e1c0ece654b37a10a4db7eb60a43b25e287b026156a13cd81f4463e2de1c77eb7bf6c616677e3ef5a15aef79d6946a21d678e4477ac23c315ec7b551de3d0fd59830c60e0fb35913d6536e9811502bf498de558a0d1566898c2acf97ae8b80064cac2bc84d4e0f426bdc8142fbc8c14f143afb3a6a6c89467c5f279f18bd8bb4287e52445fac9c833e78e41011bdc0cf973de9b2b44e00dfaf74da47cced428992b7af1abe9e63392dd91b68b5683318945d436f2db67a9fa0d4c8bba3eba7ca950142c6d36e8d022cd9dcf32cf10134addc55853efffb80384ebf51f7d2e9d3724aab031602274f8d3c69864c044a5aaf3ea4b773bdf5c7b821b1bbe09e8eb528d82d41c52a40e3c5d2edbc203912d838b720b92c19e0e6486b2b64140af91ec997c5bd316bb68ad9bfc645ef074a24f48bd015184c31016750bc3a91fe255814acfb3a648d5c3b02dcd7513656116d3672caa3a94304fc637be4011f13ecb936b6f1997845fd8829a0667a5ab9517e2a6d18c838bc0b462da9b0d073dcead579070a8b03a5a21318b2cfeae403805ee804cb2a235dfbdfc5ea29676f11c6f6f7332bef3066785f30e9c00b23a8e5260e4b9a2b25b5fa744ddb6b2729c63e24f0ba8b8e8f87eaa389b44f76dcae31839a9cebf9ea052e4bb84a4fea87dca3f0fdde2b523a0bd90a5d4fdd0d8e0a06ef4a21e7baa96c9836b6b02b71605af40606760ffaab65298110171cf231169ebd8aeda327f56920671c83096b183d74c5a59c0d701c30799f028b133ae24d3cc0e4168ed2c1e83891815a1140c434775600fe7cb21a2ef3f8a", .Okay}, + {.Lcm, "a5a4c2d0b4458b874d5825e697d7951d695144af34ca2166ee346bc47a4e9e8a7e42fe5410e53dd676d2ded601aafe11c5ed6c8fe2e2a2dd94c46fefbf5ac9434639bcc593da304b932707fe52b07baa315e0d1ab4ab8403e706b1f148936cbcf21ae22bb251f6b5a91d0ffb5ff08ef056352c06e9c8e3d27547ef1ae0c65118748b98ef2ad4f2f5cc3f0379839f5ee7d725ad12c4ee555633195f887af1b3b92849a572c9ca5b1ccd936f2a08effc2aa976328894deecaab1f26f9ac810b862e6d4506a7f4270264e0dd005e61d4618afe5279541b6e692001ca62a46acfebfe8e3f953ff03a1e25c98ccb31f727a84815968870f7deda6f308c1d7e5d36f39cfa85c56ea815abe62c6ae4ac5f3cd77dee8cd8974ac1219de1e1866da710096e344f8b4bb8d609356fbc3c4ad3ab7a65ae7861e4b889505ab90bd8c5dd52f9ef2082bb1bbfff1a4fad6739eade3cbc11d0fdeef10a195f20e3d7b9c9135969d9055b65dd8895bb042b64fd2909d618ff7dfa39bcec5b6556a0b0aa81d964d2733f60b67edd1595b6e33725d1e1053d887e014386f6e0b871cba44f86232f927ebd21f3d3cd0213da2b6a800856b3d5eb73f077e97dad8bd98c4dcb08bd807e0c6ddcb00f80500c1d02e27ce295fd96b080f90de7135efeb5861c8f5f7ffb8531472361fdb50e4eb7fdb302d19e089b89d73a04b6ddf0eeee204b33c13ddde4", "-64ad04a77ecbe2987926e6c5a2259d5fa45745fed56f7604313fc683f116ffa43d9f7f4f24424ed204b1c359d325864c0eb7a5caf0d583f9850368ae1afe8dc3e0a622c40af0d7af1cc2a57ab61cf345e18d56d04c18dc6f7ca4e4c2a00e50df4abe0ca5606ce696b7fa0b3dad532d936f914bdef938eccd062d3c16edd1e2e5ae79746d3e0dc1f8b21f52002ba277245864a8c723e270c57dc94bfd29835c9cace07c8298982efc96cc9233ba2c2776c88d25514f0e37e78503138885eedf4b12456efd446751d14e7280a13f9033f65cc23e8a592a127a90b87d4cc865581eb53e633970af78e0d63a7644e17eca39fa7ea95c19a446a68722095f038ec188991d3b0045c6eb44a3006120e0aa655d177bce0b5b2fd8c4472fb077ab0538b19f887192ac78a5d6055ce128795a2467a4afceca740b7cc5e5ca0392df1a8637ccbd4a2aab6a6d4f7f2cf2b5c981d92dbed4ae4b822dbbab003fb47ab2551e0778c7fa460abb1dfd062b4f3ab429b578054131830410befc385d160e323a30b4038b3c0dba604be50f02b92cc272e388461c94d8af8e59d5217cecb75b5661bd24ff73dd1f7a5b3a258813f46876f6dc66bb17d6a5868bae44ea49509e2357cd8a33131c4a9a3a7774e2a2ec55b8bfbd411d327213de7d0972ad1e8cf5f122658a8a04057ca2b4d29c4a9c983928b137c14e1626338d0e19eb4e4ab8f41e6e15", "41244f7421065a9e249efa96a7fcd0a9ff13afeee52b3fbe900974f441ef73f6f8d1e3aeaeaaf89f7f7cda4b8258e6171a6406551a954b0b84f764828a46ffa8e10933e54c5ca39ac4659e3fbb97366ba7a9d8a0a242390b0272e20c45ca1fb9713380d6f0a2e3bcb94336069f7a8d6a3cca342fa054e25c9fd3e3967389c4fe76419b61556a2c7f483514ea75fff97ab87ea5dd40e6f3b8ff501fd528e33a5b21873ea505290bfe9519fa7bb6e452ec1fcded39e5646af29b538ef93b95941976fb5a830234b3b61b710b1a9b53c1287882e256ff73ccea678c89ef918a9e3cc71cc8162f9fdd0e949c5311af5b48bbd56f2eca5905d10c7f8d6e614787143056db236f0ca721d44f579dec339903d2ea4896953114d41e73ba05d9b820ae0311364cfddd1f1ce6b3a09104a2b08446b245264dc60504abd55120b0af48d8f4664de63ff807338c2db2f25fab9f3ab988020f035650cffe397dd4e1ede12dc8a28957631101e573600722f2ae2e35bfdb92a1cd8cbb24ecbc9510f889762f7a3b5615ae080e8ce7925fb16ad169a1e1b4cbbda8ef0eb795ec7f0e485c6523d5750a584281c86d26db0722059515e9f68ec168fa1a9da6a754936caaf5d4c689978fea240cb8e9d4335d8529e874b378cd0858402b286162c9800685a9829080231bf57ec742ec1cff6399a072dfd73291171f5c196dae930066b01835a8616bbdf5db59a0d9504d6ce2042dc2703eadb1b14eed03b552f95a3473d972376310f48295ef4f064b7eed12b88178682c53fdf343a97d0622e5737bf3d39004181857aa7738380f619955860f04d9a00428ea7ed8fec626d5ac9a4da3088acd80450d0e6fc8da132794e031c7546b3857430f7dff517164016cab0ea725a84c4b0028ad48329cb2fcb03b49d753f234e4c067beb6687d16de93c70cb94f2cb37ab361846f41883505d31ff59b6b6cb7dfaa50a9ea0d6021a311543930bb5408917c48b1e90c123df44fbffc5751e9a3662ed63542a12a782c0d0553ce3298f7c0e4676ce71c397a72895bd3186f2b2632b28557cf20c8e38028d1475c178b59aeed53db72b2dae6f5c69885410f3be8d3734b92e4f07e086d6c74487586efd4099083b29f2ca8f0cc928f17a4e7f746e4dd4653616356a82faec04297a64d9a1189973f11f91aafbca3f066252a9967724e3dd356b21cb42f0af7d9a5c7f97d5dd53b202c2d332ce7e1453a1d243e007b088680ba845df3e3c82b0b6896aa01c5708c4cea9c018275738fbf170fd4046768dce22f1002855fff86c43c464398c23f8b8086d2f2f11c2d63ab2c5f1e2919afcac32ebd546af7f2268a5aa699f653d2f214ac26c36f4e1c734362cdbda41bf3e5f7c0004fdcfaf59b3dfc94de8fa289bc0e05bd99d6c6cacf173d6b9f7f914a8faa6cb218eef3e3b4968e4c0232bb4", .Okay}, + {.Lcm, "372c82261203ee5c2b3f1cc5d10975b897c468b5f2668caffa057fc4866de4b8d80a27b72b5923cbdb09a56706895f96d7252f3a50b565f5d602f94f2e553b849bd687a9fad0158a5532e731b014c957127f24854a76e38f633cd3d84b5ec2805eea00044655f89df8b2fa2df145b60808acad6b7c3b919fe5fdd84ccdcc1ba111c7adff5ed1d410b5a58ca8ead5d38266693c6183a2ca7414f30f4c03f524bf5167ed835314cf986ed0b197ef417011b6081d83959bb11fe49f11892203049c8f5f9234360a5ace368d5f959249e06c4403f7cf40fe026a62732bda63681662d500edd17a32927661fcb884a9dc817b803070b8a1079232dcdb21f57ec324a52549a435cc379fdc8fbe95c712e04f9f804e4ef8b4eb062658165a4d4f5905bb5dd28c3bea117ab05cb89a53ca9bd5e9198148bcae7e05e9cbadb387397e697b23c17245418684b74c623e4e667f2977873aae78a21f7097e04878d809256a557b8666fae2ad6d7b9c2d5ddd21a0b28c70d66ad327846f1d59a836eaffdc01b2e0b09aae218fe1ff86deeb19dccc04e2b04af834bb865cfe277b9f5157c5a756553cc03e2615201af1619017ffaeddd8e6fa63f995e527ab612875072283bbf002d17c5e6463d93d881d6e8a94ffb6415f1e218598be69b772b0696e21720201733ec38fc9a9ab9ca9a5c8b841162da04cfc3b4496a46ba4bf8fa1544a3b567", "2c6c8beea883769ac490479bcd69b235acb100bd91b90a2252385e2a367cf976f84a52e4bce794965cb8d971395b8bd1d6615931350f39e5714ff6804acec7b643fece8e2baa79fb324a9c3b51f16ec52626e44cd28c82fff733b38d93ea9f57380a8307c5e032cc8f722942c16d01c5422834d739eb5488551201a28ee68787296cb8472d4d4931ed3e2d6c73f4a2c923202c31b84dbfc75bcf8ffb54796cd9054fc9091cb687cd8336f4d336bedda5c572f00fb1d571ddb87a66db0f238457686b44b78180ceb3e1897a88a05b12ed6778f5cc7b5fb89f7ffdeefe7e2e087b428270848240abd28ec63cbb166be267a2a9de3264e88a3fdce171c77436985ec15fd8788b46a60f0f63ceaf0434dfd941bca346cb20a582ce3a9b513de85e3e1d62bcd420efa1b4c92d22746d663f1a375a0133113104ed096c2481a1f04a56e3117afd1928b9c3d0dc9c023cfe63160c6019f1aa4b533b1dff808def43b7587391d64228a101a5ae3c0a32720ae4948b3f522b2a59f4051a6d0352ab979c9b9a4f4a62013ae1e550114f19d61a3a04114bef92d01f54ab0a6fb48a57b826efc9050164653898893a9b70fd5c8ee627545ed876c228bca870f605beebf02f10099886a16c1a542bc54f45ccc101e65bc56666ecca0657b4c78f43292e053ec16216bdaf450806c812a1268fb1a50af6038b57c91c15f05c04280ad8620f6d45", "9930b4e0d857c8cbcd38c7efffb50d389b8a7ec751194c003a9b2ec08cb9a70c3a8ebfe46413bc71a7dd5fdc267c8b7993ee2ea4140f54aef490803bfdc931a3af1baa1407bc37137ab105eb282a1d9eaed1fa7896caf71e79fbab9773d74ed1f95cb834771b6b6e0fd69b04aae0d8b5992d957a1c5afbaac887e285c8d2ce51007a4ec88b333a3b2b6a1c896c755059d6492c210736483de824db34caee5cdad534130f30239e66df045bb283743c254c6f712dad22d49676b7887ebbefef29ffbdb79c6e0d2026f0040ec34081b539ba8664a5e6183e3e6e8c9a4ab6e900fcec5cb4e63868e9b92ebf6be2777e596e5066e50af421d49f3ea710089598597e22c711170eb2d4ed794a3d7e8daf1c95329ee9067f4c43e180412efb040fce6f76b265c2aa7f845fc03c3ec25aa806431bd41b0218a0c4f15542f8c1b28390f0e906e1fd2f7ba2c49365933a1295c8cce68fc321b967a6e71a0581a7cbc0c46e4ce47aef1edd96cd791a95dc864bc66c9df870251c93983befb457bef3547f5b14a9c0e8e4dfd594c72e7ffac0536c9717e178e36f1b05bbbdb826861bd9cea022649d20873749e47f50e8374985e1498f832ed22e9b04ccd9e262b4b26dc62b37efdd8232c86dadd084f104f2ab29f8482e8d94d9567df1cee20e047f9024cf412f2345e3425d8c7a2d77430dd8414fe370bf650bdd7f1715970d20ae0db2231c887fd481494d8a04e37bd0016fa1a6e7e8205314f5876d852129475a08909a977a2563967ca02fa47ba1cf21f9de22f48cad422a6378722836ed2b0d3ddf8955e8d112f7834d7a53cc0788c9d80186ccac275bf7377cae93b4667f6f569065aa5435481fa56d99ff35193a2f9bcb19c563c60861b4b0e8aed9db42a936e822e6abab36ca05c5f8ff08f3d2c7277b763e05be8fe7f8626115bd6866f706c4e7d4bc024cac954886ed563f09374101763c2dbff46bc571ba87fb3ebb1d0dc807c148c5d2e1ff311c3749bb579f1bd87ab271adbfc65db5069442e0b18799b859f75d953b13b3aaba0400e142e04bd49fd258ec3fa9cddf42b8000bef0a286acdc6b7486b407d21f9da886869a1fa0104db26caae061cff259497c711f462de2a091be83e167d4e4ce2d2f9222049e17fbd64b8c062ed7f9e12d05dcf0eba15c0780c6410996f5a8c076407777e1745ca4a50c7d4f2dc5aafa3a6ec4eec91e8bb85a5fa8acdb0235271af25cfa8a2d228b26231218fa041d3ea874f627a6ca3437dec31ae583677743323d3f3ca8a46137487807468d16b824265bcf28fc0d8e36b60da7b0c398a21d752a7da143b7ce93fa578e01370e4e879f393120af1d35f15a807734489fbb73078972c7adb08015146af24a9b2400a234912eee14641e8f3e13758b14dea583add3ace5c3b911703fe41065805f08b6b3be64365bfc3", .Okay}, + {.Lcm, "8659caf95d6ec23ee42144b22de99473df9c82c2d60e57633ebbfdf18154d398b4395ae3ff5735461aab947b2305197e8c00d567252f4363da326041b0a32e88631c84382f13006ecade290b361262ca17019df6879ca4caed5fd08d53690b82a1844c7d46b39af0578f3d1e2de1075ce15a8a7d4c0bcdd4a297981e52868ef97f095af644283ed0b445d098a70f7904e071d54b8e3e697293cc8d8b25f02714e334cec793e25bd54956faa201c06321d7292e88a8dad737071b01d67717afde140861cb1720d165eabfa3c9df1cbca4083441f60eb4966d57999504e42ac4c3959c5aa45d05d148659d942828c1fab7cc6854692cd2908e64bb5b77165e112ac5cf95502e30c9448258e6cd8673bdbda10986477170af7e6018d1636f493f6129b82a28c5388fa77568f654657361b85262519830738ef9a3eac4513a4cce2d67ace81a5440d73b1357623f24848f1a6fbb41d0c3d2b33514064bc83b7f28d8ccb66aebc1a377719648ac29b18a26af31d82cea498e4296a285e332b7d01914eaa2bef1bec17fbc366c4ac23f2e9b6992b47ebc26f904c82d5401d86e839a3eb95d7779286e73d3ddd8164b56803b3fbf979b3d9c352569cb1e3120dc1167fa2f021a75350487de839d23a9d13d3e9c6f395f5548c768ca75123211c854cf7c8618aeb101816f1d177e4a357ba513088bdae0ff5febc2a6fc439a475e7725fd", "-21588c488610acec79ccec20af271d8abef76b8d8dfef09d3e88c10161ff296fc39a4808ddfa423297e2706d95c5a5b7810f33d8737de4ebad6bba00ccc7bdb692fdd824ee55218214fde24c6289d64dc2685f30810b9b93a0eabf970ea63e610a0558661069b0ea2dcfd23b4688bb57bbc34f5fdb49ebfe0f5b598598d70a6f86f72f7846135af5781ffd540d92d4568154764cbbed0181ee66ab759891ca031d50e39c5e3892e42b55f8378bdd7d4f77298f27dd369910084ae6f3b3a711073884cb23adb77457c3f416c3eec700b42396c239ede0464bbcc8f8c11dc444e989bee22fc58a496c80ee439135b3a74d1ce5b95654d3155afa5c9aaf113c4aae90e026f99e672f07638c8e1a580b0308681900904557437463dbbec42acfd36f23a50b5059c7a5a3deb239c82095ab875165ac1099cdc07445452afbe577afebbcbd7e0bd46d8bf608edf776f45aa7b7cce05dde5d9cd63dfe98fb43b72c569e8b116925e446c1b23abdb4b08a8c1359f8a168959fd8eff78180aaee4bab75aefc2f27b6a0d1520a78f14e11b59fbe9c77e31c2cc8a899ca2029a324eab9f8da74c535f9a55151957c6706b36f3b170e76eb1a77ec1a5f7bccf9c2ad434b3c3e0d2b35353e8049661006ce762370046ef08f2ea5a55cd1b81f1c34c0462f3a1a26972d200b4069ca08ee35bed6a2e7ac809f2b9e90f706c1e1a045656e946201", "11800ba715609af35ff83168162f9f4082dd377c1da1279ac4f3f8bf0b36e2670d0fb4f8a1f0249dccb9008e48f91002b65b181ec9ba66381a3fe36b25951b1179d41f3f805614ee71623a1d3b283d5334ee26643f9652a32fc98d1b290804d5fa38d09ef425e2aad215bfa0a7a29bed805202069b45f7610c71de55aef328dafd6db61d0555b24f7ac103622d91c997764ec5be5e21f2c43f0a60f2236b108df4ca07b2bb06838af4d6cadeda764de4a2d391f7b9c21f9aa3837bbf479bac21c9c82d8f2d0b737470f15f3d0124302e083e390b76e0a24b25a1dd4b169752212dd8e78ad7438e19208c87a229c47aa89d2abd4ffb51aa1e999045dce3b5d6d4661546613e4b44fb2dd2aec816af78dc7b2d5a8fdea82b87f3e9acdf1518f4e55fa405d2e26f190f32f99d2e02c0d995fa8adc4931b76807e0a193a9da51284c81f79f8faddc7afa963ca038879e07922b4842ce3b32d44ee16745ded1fcde416ee7e8407c0d8860cfc5b54425a76abc6a93bda964cccb87b98d34b9cb787536a38c413711967e476eafa0b1a850a48012b23452dd1724bd42601413dc93ff5e055e4ccc8bc145313bffc920e3914821de3c6d60f31301941291d557c11e255e160125cc0fe6cde8a95d839d19933bb3c3f683487dff9ea18f6507aba6b714d3a55171233dee82835331ae11fda8288b26def2e2522aa70b7c394ca36e560b94b028249b0d0f060344d4e4f0550a0a9184fffedd8f8f0c4211454b6fe2e31f0fa2aa638756e7894dcbbbc210c555877b8a3f25c3d243b6750945c7f53c7e87d4723e480492a2599dfe0cc296f63f69ef98fbc521f250b6edd7629941bed94849b378e61c8aeff7b232ef6320c6c7de709336bfd8b6cc7a8a9fcc8673908b86905b20df11f02e29f647d543052f9f7462547c0f60b3496f626a2850c25362f064e7a4b94fd515ac631a6871c20314c81b6874f0d089374ce2547514de924bf3dfde607635e568ba274ca1dc0a268a92de812577eb39588406453d6d765ecfdce09ca4a04e775e1b86ac2b34fb7c6422fecc01e3bccbccf506d18a8ebaef7f7f265aeb81d592b55008cf5a255a6e7748e61cb52080a00408f709a78a3fffad5d2e3e1d258ea48fd9781bc8e5ca3ae1936aede26e638c967ca82931b2a15a84b2c99cbf8b8537a8b14260054ecefaa1c91f31696a45e319375f54dcf6e6eae82323296ff8695489b98ef79f661a2e90c86f3b0f3eb87f00a9461286ebf5d55f6094f3dd717f564b22c5b27758e9c116d4c860f0200e790d91af4bed64da1204da6938b0ed45756bfc789d5c8167eeba4cf94111b2188fdcdfcbba8df4bfbde0f0921da633671210728f13815b44cd40a36b275ccef2ec3ad2c05e3e28fdc5360eefa6d028305f0079f7476d39313ed35d8922095fdfc91401cf368be976a745fffd", .Okay}, + {.Lcm, "e9e0f47c10a7091fc93115d2a4614cf21835c51c349c4dd4944a81c4d4a364d17778d8d1acc1c7c81902281df42e6cbd53c24d7d849b9d9634fed79c574d6763387b2dab9434b0ba72df81b70d47f4f9e021f15686d42b6838f0ec0b8b6817b3e898889569bec1561492806f9c0e34815f0321ad61e5c0a83c726068a6af01b3cbfaa8520e5fdae8b0084cbe5023b4013402372449e86702290ee549dececd612fab3535b3cb113fc82f32c318f4f7e7f7e71c8967e96fe0e0bf9e15904e7e02d2b42ff4d367821494d3f7c113b5f74d6701444d05783e3f57faa4e95450620ac5f622dd4eff0bb759e0f9a85ea22f470080afb393858427a8e93cedf8673f60f25902fed2b812e6d286787db9c251c7b6f6afcd174df9345617704b1732afe4442193d6d8c6c5bb57996bb8e4e9273fb61c0de3335974e62163b479306c534478a32238ae02a19b8ca28a13d70fb5317cae1ff2905ab1e78aad5eae4d4373e8e19a30b83503c2a1ebd0d76cc051005f57638f2ae5dce23c48eee2e5a6b10ba6f1aa17241e2c5a12822706e6c497c6ce85e0e4dce41023355ce656e6300ff903c641aa3cec3182132d8369177208b43de488545f09a5d0fadb917237132c617079c14387357e627dde215f5b13c0f2930bb6f830a819d0d59cee24335ffd6a15ab7f0b06f2f43c0b5d4da582e984acda02e6c6adbe1e6b99a4fc9cf98d0f288e", "-6c04701cb37af71ee66993e3cff9f993524924aafab0d9837678ac1c2e4070fb67df2fe07ea26cc424401f545d7aa3404a03fc6e1141a96f7741fb9c96c009da17ebfd30e9989d8b65c7834cf81d3a9de1e59a33647e5b71a8561fae321f67f7b8c98ac0225e9f4a45cf5d57e1fd48e43358d953ea8bf4fa378110ce8595391bfb0a4214574f39b88186bc9aa06502dcf4705da28b224effdf9f21014222d3538d04b80e41837bd2fcfc53c42640a2a6ea2544e3f2dfb6cd1e3abf9fc6d12d2e4a54a8ae17a403d45d3ce4d538255d17a57f39cfac5d37501652fb174b17ee94205ecf998962a574adc4b7e701ea9d794b0af841db978a609bf0bba4de4da08841eeaf036794a2336d6002529aa49ac11833434613c5b39b5996bcbf9ed54dbecc2705278450ac9328d9999cd733502eb360464d9883b32282acf23e155a7b31fbe199ed82d68135b07d060b137f91fa2c1b31d244107bfd90d4a34fa72f237e4b0a1c8b02f9c8584094abbd03591961acca94ead6a11e86c6bf0bd7aaf2a20d285f28ed21f87618bd11904cd5fd056203d3b6bb3938007665ec093c43f5f0644623decda9a494bed4f3e7fb84e918ef93b74febdd8fd92e05647ce850e9656dd03e7ef702ac3be1440ce5b9520d5f629ada7a905d99150461c3035e888d844b9a3032159ce7e4bf30c3f6f084e6b8ddc2504340fc3c55fa731dee6b2e52402b", "62aef514cc80613bfd2867176a784d36ffddb937edba61824950cc8b0b736f478e011f2bd081460bca835b8ae1ec72481d487d8582531bdff3b700dc1913641f00f9d514d48f7db66ade443ef70c342d19426b0061045c1b5cbcc441440a31b4a4bb3191bc0cc78f2a97f84633f9f18975d2c4fa5da00d2a265f2907e215d1abf5442b69eedce324fbad7c7d71f43b081e3a30446d43cc225e9ab0673acd95dacb2ad1df5bd77ebe2a910bd5e41e1e3afa4057c5ed31948e263916843fe5ce23f4cfec5f0ba1594ac2bd8b4a0600df696739ff445eab447396d17afb5d3752ce5da7fc9e9abfeaee6cf1b828d9e0bfd81e076df6c00078f273eb3b114ead2e5d44778b585a5dfa771e174b1a32ef00158419a63270ac46f5f01b015cd032f20e1ebe8112042f6d4e2b0e8d02b0c3cabcf345c673d96870dcd36eeb719ee0f5347ef7eb9528cb36ce118839e5b304615d5e71a9b12bc99ca473392182e90d1ef136ac3d835ebfe9019ace138db998a2303a5d3590250e37ceba998981aaf076733811385b94a3a9f8fcd7f16683712b5ebdf5c83fc0950499f717550e4e3a3f3cd599f8ea1183fa6ca73a18cf58beb8bbe34f252d56aaa94066d48f645f046473c2a60b20c85cd719aab89fc48113ab546c96e57ff93c1ccd07793849e3bdbd290fcc840394fc5f4299cc5eb734e1b48e85ee0ae0f2e64fca17be259afff927d6662805a3efb2ef7b3801cf4a6c3ca2fa427120686fee23a8be42a114ab5f1670c3a03aa6ead5cd252862bc32448d82c6d6d7ba5ff7e404cb919c688d9124c7986e11a364e421298dabc24f366458e2e4be6df0d201bdd3ec522006806ccfe91d5956b8bcc128b9bbd33499f95128e0c952f6d6ba11a5e89ba417864b6d14b05821404c74c0384ee371408729ecac21a82f13f7107327c24b4b27dd4e993bc47ffe0962a49813542c99cf27ebf1349aef6776abd78c395ac3f299f0f4eced9424a522dc534191c700f2bbf32996196c070d1db787654c3f7d15e363b9246ba97d6ad755b0a16ea343904f88b2db2725c45f8c0271a2490263b608d5256425847fea1165313cde538baf9a54e2d065e35fd876f7b7336d13d4c5e62de0518ab85ea931bdae6935d582bafb0e374bfd634abebd2bb390a879b1f61534a04fca819ac1aae01c7c824f74a71fd68089b9ed40891e5b0b5e6f621a84e8694c27d9960bc1f35573e805f44e888f34a9df9da128477d67948ea2eb3ada234bee9c77fb059e0f71c7e35a2a39bbdf14395a69087e89c70802342b832c2b1d15b3072a8a2c35298a51864c5849fb3b484ba4bf99bed1d0140881c4bfb3d8a6efb73edb5c8acf02bd2d5c039270db870e377cd80edc04db524f57d1c4d31b4f9552c260a421cd654de082f222d3b7aa4ff253e35407f273980a6193e13a6c14a0acfd2b4fda", .Okay}, + {.Lcm, "-71f0f9a1fa2b77a40fa1fe8c739bab6081f052d7ce681f7aea86d6fc487e2079747fb67e79332669f97bf986ef393989be37fc72f958730e47c28c55e8bff758629883d12bc418d95d6adf4c73edd0edcbb631e7cc34a856f36e4a580024dae8edb45aa01afd65ed6ad20e133eb56e0191e8ba431e6f22e2d27d8182d4c282107a1022edd8d3ce4f69a4211c637e833fdd1ff4d8c2027f0efc464fc9fec03dfa3cd632b0503a101bd82dbef3be5426dbcbdd942b906e3f9b9ede5044a001960ea179cdc16479928d40a4fdf620d01445ddf51f6f729af9d1eef16e5355eeae732e038fe5373dcc29ecd3d9dd7c196dea514023b7bbe520437b850267001be59ad9ea96d50ecf26f194e6689e1733d6d252a800f0cf6e202a4073b7315cc20514c5c53e82e02f9e8cf403c69e4996063b5436c8c1e4d43d7a8cfdb502a965c9ecd3fdce39a525a3f5be03597ba29bc5acdfe618cd7f8ec6ac7167ff514977b981c16e552d8877a09e89b8ee7bba2d49a8a9e0bceb0088f34e63c58a1833ed8a0ccbfe9a558a6f7f803c0e009333e3fbf79d36e6f41563f71919f0f2d918755965689e8175141a20f7d821ac38a71c28a904ba91a1de0a833d3ad6075310af673708d55f06ed1592527af7f585543a0c16c9f3051ea3dd78f98c9d3b3f1115b58044f05ee362b21f15ff727c2d74085b7d34e042baf74efa5c076e9f7e07515db5", "526c57d17de5e468b2f12e6b420d38961039a43848838ce6ff5ae4b2765d7efdb631a014204a2d1fc67d346d668fe6afe304ca2068f279a2cbbbd28d9b241c005b9a4b292e3c657aea7d6330dfbb8e712ce9487143aa16d9bd90f6591dd7fbc5d0ada3f7ea421ce863dad22590768e5a97cdec7f16f8ef758564299aa8c33c6b936f7f997a6cf2d8c5d5f2f81b23c1cfcc8d33b010d4a7b618db32fc7ab72ae33c7f86f7f8c34c58b056b1c46fd8ff2e37b865aca8f88dc1a63f91c5cba0f5c9e659891a26c630b94bb2912db3abb3d4534995c9c4bed067f5fed11ff2b417303dec94a1a094a132415ccf5dd30afd93f187483652fbab5a65e3ce4adbbbfca37731128f08eb4c6c0d481542e0189ddcb5d6e7ef3d2460a0cb57ea86e2c0adc65c3581f797115e16a09648a3bf6aed3f433f681350b590e6969e5993625c4c00be5e13ea54c78a3076e60afdaa3b838ffc02e38e77911dc77419209512dadac25ec84242b77ea53ace1d188359ae5545c9c1d7d91210c3adeb3faa51059dc6f199d2765e5b0ad604695746e6a71b75f7db55e1d33df7aabe05c77370e17074ca27aea406744d40a8d213f04d2009b489a572807e21e7e715e5baf8368133c2c0ae75eacbac536b12a38eb74c8f2538f801aac856230404284c3aff43fbd9e5e69978d97ab8bab108f733f4896d03cd637f66cfb19bcef60980b5ae3e0093d4e", "c3a783c71b0c4028cc2d50b1caf644779aadde9219bf9cae45e3a6e64c054fc4146ee300ac956660ecb3252fcfd6ae4745ec613f1041b2f2c58b98611f503b57a766da077d987bdc15563e95f367b1410ef06842b19b3057588ace72e6cf8f0444cec15e583194afdae05a246933525d73bf43ebe29e49bf333cba54523d22babfacf8e2609694b9395100e5331751f624820c60131abf50abc40293614d7ef9933a201faf01a718d0c22a8c5b671519753094514d36eece0a4cffec3ac324adc2062aa03d926d4c4b214a2ed709a3d4a3e88b185c6b0f5175c600db2da09b932db25f7e817daba7426402a4fca293993eadbcc201ffaed93015440215100625670e212670cd7ddc64c4610f9a7a3cd26ef11e957d82057b10d51e75b3726f5025fe1d32c780ac4309c4b01b3f06fac36e6a5fe5ec2fbf9cd31893395e14618c505015404ab0720fc27a071d01b75db67710cfa5f27eb1bcff99d33f1b1af7b13e401e2f4a1a357a57eec36bd410da84ab5dea5e8f7095b0c01325c262afdfa1bb64ce3bf85ce8ea24b21100b868cfe9b0788ce71ec002651a2cefa02a59f38115e25ceb2c03abf1de96e1a48df386c34c968851022bb81ee14c379f1c2161f316bd7753cf8cc950535815621b0730f913b9a40a07c36357ceb5403cb20ea4071ca459884f78f9ef0a8284174181f6c268f5e8d563d32fb88a0b43ac35fdbe353b4d789a9958cb289cde59171daa9fa8b357666fa451be77238a9557314b2d82fe5702488c0c1bff2124ca40ced2a8e73be4f1f804e3b5cd75992177370add802e507010fb30130aa8b2caa545b57fde45fd99467e70f0b39b243f42fe0da1d603dbcbbb08440655779beced6d52a4714c122573c89e0b9fd087ca247e62cefc9f25501107ee7135cb39339a28ecdbcc15f71d18906dd050f8e9f1d8885761fb2ea4de820a871d5b96b4aea15cbb5293d1f18c59167a24bfc64498832030b573ddc934103982cb2223146dd98a8aaabfb57b9c0e3226e62ef24072e56aa7be3f0420441726e5096fe64c84b14d6771a3bcaa37ec4d9a0e6a5cdb656521abd78532faf4f676b08b28e0608a54a1015fcedbd3547a7cdb6da4d45ec0f664a0b0216620d2514fa3f5639b544a2f05e91bcb0a62d9b08419a63ba186c654b1e6a5fd3cfc21ce7b804074291e25a8bfb61ec19f159aaf5ae3a58cbe1cb4de9bf274d66870d56f0c051537b875077c09f1c7c4a5390a8461081973036590aa8c4382211c5db070c47ee8d06d0346f664114110c363d58e9f1f72b47a02b7563d53df13b26bac3eec8c5f827ab660f7b8255dcc280fd6e871cf44c9b59f7c2826942faf2554ae2d6e5089ba63ba6faa5c23d6a47da6eb30cf9db1903a655dc4ca786ce6b3e329a61b9cc7efe4b4b1e7c7081cf5d5aff49ec43f87b2cdef2a187e8f62", .Okay}, + {.Lcm, "-386b196e2514213102a9812519430c5b5f66c99b2271672da71e28bca7fe3ead58ddeaf2be331cec0e4c91357fc19298ef67ac4dd00cb97da5272865d95b0255158cd2778cdd9c3e1c87ba733a4e2cb656f536ca9798ee583ee570021940b84913796565ad7176ffd1725125d1b8b19976e78ab7565cb78bcda908e1da711cbe6d84b85ec0c23c6a7d6edc8f9e4c753285c9d07ef49c10aac0d01ff624a84b086d2f91eef39b42dc51dd1d9fa52f6abe95b82e1ac706f20e8515e7a833f9839e059318bb03df5544187b6d06c7d1250da39ea7cb1e01d53ffe59138d686c1a0207626d3c0c44fe40a124cb440122aed46b2da15027d50c3406136200cad396a83672f975beb59b8008ecd61da7a9a32ebf2c1792e16ce37a3737b04b34d2ce26ed4fff2bc90f49b8e83eaabcdedadeb6f7455e725731b8db3cf6674c719589529f693056295568faeae81e6fe01810f6300bb7368b656d3ffe809660bf2f69ae6375c2e58bc981ca35b0c5cf4778450db0a6ecf1963ca8c4d97cbd2b6c96605636fb71f125ad836a3f7b58f09240504e42b076d96134943ea33202a1eb26534f24d1ba1b7c4ff41e965dbd1867f7520b8f1f28b39e5b69bae067a81064898af36c16e413e29943e4effbdd94da081e6fda0a1ed128548948292347029ed260bc7968f285fddec48d3080497e4969f566cb82c74e094c42616f13d09f7b9c017e", "-d20029fac5cc444c28a0339517862fe886e2b21104ade9181814a03246d721f6a4430d24a50f51cda2adc3973a5fb54f2d78954ccefd3056e0a3a3e1daf640375f302eccecbd4e2b6662ce3aa34b8295173225b724f3782d2438903695da26e190a75673a688c6c5b8d5e989908fc3939ad6d55980c5081410e945b4d23f3706dbdee99e03b5ddab04cfcedab2e9911c627abb4e92a42e104be81beae94096f6ceb039989498c50a27e5195493fe0fc9a647f5351248059312c8ac55c40e3991eaa1caf87ebfbb99f24c095fc8b949b11bbeeeffe8a76eea03759073f6b300a72922e4426fd2bd4eaefea71c006558bbf12c3389b4db0206e8f4227b0b6e3dd947e505d95968ae7760b6cab4bae575dad1f49e01333ca60899300e18fa110e7a1360ef93a5900b0a8acb652e5ed7da5d1d98700144d885633223ec4d5ee447c31a343a88a656abc5dc4ca5af042df97cdc362846904f0338de394e6b2030a7a7d73af7047fa68d7ed95d4fc3afe897d5d78d1de1adeeb57f950c1bd29fe28c4454075933ef630113050989c7faecb14ee363827eefeb3b41f3f5ec5fd26c4f234e660f54d63af452aeb02a5890d0edb336ae50bd030816e9b87eb1fa953bb6ec716acfad746bd7f9432b255097e62b9c93968bac9e7d196d3e2d90499f555321736c6591db2bb12e72d2554e81c3aa15fb90810150175fa025bc7c87180070aa", "1723f20e62d5b5d8f27b98d17f86e024df94567ccac6f09fc552dadd33b1c7262cce59b17d11d177c569c2c6f4dcb429fdcf9aaef2f885249d3b2d7d9d1ba1becf47d2920a7d40433130182a8803b61f79ed7a90fa2d094b0ea11785a39db923db6d2812f61a809340f91a4ec367a6b9e7d06ac8956aea2f6ad9cbd720b8ddacefd4fa217792fd63751871ee3cc76bcfaf0171e46ca263d690a38b2c6ed4c57db72b318f70dc2d416ea7ecc38fa47ddf557316a28663bbcc11041b921fb428dde2216898cb009a819c68cbc84c1dadde23d018999039fc5273280baaa1866c56029eb92bfceffe05fc6de99c4cbf9e67c119fda243922cd47ad84dace8a7c8ec16dcf69661f0e6867c9f9887de7ae6e6f9c071f4737a903e735e57dfe10852ff8fc4aa970a1474ded1b714be03af0d8d44c8db2c14b1dfd1554860cabd426576053e88ddcf28b6355537bc50cab9b7c4cf33039dcbbaff56b5dbca906ffccc9fcffc87aab2fbf33963ce66145f9a0793977cafbd1338b42f89e235794def63e2319c24974a18ceae03e0f180f18e47cfa3372d524683177ecc79e6b0fe71b798573f13536f5165abf6d76ccc5e58f52132fa005e2da1cd9fe8e080bc4e79ea08c2ea687762465f092efa4b3be564403e8c0a1a007012cd928c756b6e3023c7e70abab3650aef5b3dacc77d5bdd34949a5b2e955bec6d2fef31f5d9758dd7f17f6b0f9b30774cc5b65c3f064820e395b6c9958f3e25688ae37b3142445ec30d8129b7e20b2c43cec4ac5409e2d7300c18ac49b08b51b32c54674d714205a6e51eeeaf40e80c9e59303b6db952622835b555e83e545b3d8f117491355b2a7ceafa51e50ffa7b9151971577a3f7b91aa0cffe4258e07fa25567b569f7b411e69e2e5701296a855498e531328624b45adc6ffce39fe7d67bc37da237f7f32d5d91f3178a9605afcad405766e66c3d331f6cbf9ac5486cf0f092a780d764d56f6a3357e180968fcfcdebfd9edeed39ba116a1c85b6a2fcf95e6ff3a840bab75aba87e77ef4307188cb88bac7b50feb07afb11869675d1a5052012e7c30dd7a7f20971b5d65ed1a3f09e1d47b70e9e80e72cbe7588e50e964a7f561ffa16ae4618bef204a01e5333735caf4b8396ba218df5ae85fe7d025a535e0e1f36159658a5996143abec9eb665ae226aa8015a6c17da769d91e91b324c8a6545a21c0659a1932c5fa1b6608d46a35c449d54a033ba7c00dfc9846bf87fd7e91b6866990f3e20cc5c12cac29c38587269422f0895c584b327f94402667d4ccb210f05a15edfc26e3747d8ad75758be09672850f08c7a6840e8035f48aa48cfef8193eb6bec230a7965e3cbfe9adbfa4f42139e0cd48e990f8a621b58024ee15a32e6d05fa28c6ce5c3ab92f560a61fb7d228a500a4c1ce516f11a42e17aec2eb84560c913200ed6", .Okay}, + {.Lcm, "13ad7bbbb90e973666407e161bafcaf3baaacce9584b9610a7f0159e11bd276907da7a045fa266d48734dc0e9f152549cf9b23bf07246d4932d3c05b1dff0ef4805befc8a421c7e4ee1d7c2df2eb8b85338b5829dcb8d5bc1f31001aa1d8f9bac1ff0d4522e02310d8ed6b1ecaf18bbf3aa781126916212b4699f7895f495e0d5c66265d1c093d0a8fe9b71e4b3d30e0c6fab9b8ee0db655651a75d2596b48a094bedca89b6c972d3935a4836156d2d4aea8c46d3eee1ce00195b06054cda7a53cba47a99be1c1b62ebb4bad17eb4db67dc1a214f93d24d005cd054638b3b02bc7388eab4d76bf0cfbfadcb50957ff04e0e05f0ec3d2cf84b4f37fb48c7c35feac3d0626b0614adba31e8d4e377501de6670d043a33ff4c06c9669e7ec8e7fbd33d15bd4340338dfab00c2e5b87fed0d3eea722f65785d45c3194e44ee4ddd295724220e703278ac3c0b9f541d13bcd2ae7700e3d5eed6ee125b49f3db31997832a930022dab4468760c2d6c5bfd6bd532c1b3b3926e229b9ba0f84f84e11f7755ad3dccc33897306ca3a314c48612e183e91a8c2790a0ffb5c9cad00ae80e34e954df3cfbd3a5b0d4759911823fe27a8a68e46d7201a5f376c8a481928657d684979d463a71b51f1374466e197f4e516f7814fab5bc90951918a34ff3b672c86abb0a3ebdddf4998a0ca456a3db58c73bdedd7d199bc56702249f5febe1c681", "dcd9bb5c111cdabb804fba3e3aecc8618d785ddc77b5b28da83b7f7781e3573985ab6e04f74789d568b3c4b51a3172d9ea585c7dc887dbb8b229317364fcd3827a9f8ad7bacf4551fbab78ecd8181fe544d06e68ba812ec6fdb0fb37230d79df5253e0365c470bdf368a09337a332153bf08441a8eac11b7eed718c333962afb6996e38e37d215d0a271b62548ee670ed83bc610c521aaae040952b6f7c03fd230f5f3a2f7d3789960f2bf16191740c7f498f533c8305818c2e02c48024420b16a1bff9e97f986c96bebfb855ad11fac9299e0fd504eccd16cb116cc82919f40998d3bfd3c0c58871714c5f1a58d1a454cfb566a58afdb6f656a9dbd5aea7bbce58a5a76959ee20b32e8af59f63027c9909d9d1fcb08dd72ca9525f8a7b8cfc3b2703f533c8924654416fc054328e21b9e1db66d1f79db27a6917557dcad44aecd8a5a153a4796cc72da706a57cba65b08e955e13769434f81db6826d6761ecffee93afe401d8a10f965524fc015545e741e91873c6e12bf827727bc7eca407b212f5483eb17b4655dbe45bc7c0027c1f728a6c7c35b0e0be9374898e48d807b805883ccacdb74967fa4d4fc267150af637dc7bfc9d4cada49ca50ea6fa4bd55014ea95de508de3c32b2686c7f42d7862b9f9bd4e9d51b4521f6d72dab3c3d3cdfe69374fb94c5c7ac65e2ec23ad9e7a9ef4909e5cd360941f1a7b706ab75c54", "10f9d2ca0233bbf63b757f555ce18439a1bfcfc3921014f5e7985cb5718e92fd2fd0dfc084f150bce29a1e3df9f9be84d4b2f7122ab9070b1575ce608aef4448ea907b5c93487faef9439bdfeeea4631d13c47a68fe949ddd96a8358dcf7467b2005810c5b75749333c0ec67d976153419f8061ea41193e4e5252608a887c0e3df685cedf0d9124ebcda39d914935b4da58d675d9bc8f6ea953cd537038e7eb9f917a28495758c700ec7f47b6e764dec17c2180d3cfe217a3680e221e021c1fb5a6efb049e0f725fb1e57639d13a74df37a9b1658fc750ec4e191b7be02777bd9a40b5c48f375079149f505aa115d3cd765f227ed38bd3c20841f71f324800712335fb68438817540ef5d5564aa7ef888f71962cd1c0e8a500c1b201c1c238fdcb141d0ca4b35a81dd908f1033c1e6ee3dab755a5de8c6d206958784e55afb0f56ced9570463b877e30c0f0eb6adf92b8225e27ea23890d794e945b922cb8553652cee83cb3dba01f3d3c2316ca02aa95a821e5929cc13ec9a11d82b208de9acfc24575a2a1f4434d5eacf0ce5aa4a882a82500e6b4fb90fdd905c10b9a302914116db4bbdba9a24b88700a21e3eceb2b3ca6f9a991a0b77405589ab931763309f25616770ded261795110664d5981dd9399a6adcb9e02dd47059869d5aad09e1cf37b0050d128f3a46c5b567e26ad2d0e40ec6b15935f25eb0d26fbf5f8568a9a3e84c49de5991b95edc0e88431e2c319090d29156f593ae9b6419dbe5f6d64a3a0c315f4413ad8c44fc9a34c36e3c5d0fff897fefdf97b82097794332a7202b5cd427f5dd4875950e7730073523906ae6268d35582d9e448a84b498fc3d0b16087a4f8bf99759dad79ee61f93634713607189037fdbd8373a87e06f39c26a2fdb3b1ffe878d7c4dced255127178e7e96dea0bb3f5caba13cf9cfbb8f9b2e45fd496bae5c3d27488d4db3c20be99b6d9a10688c70c7accd78e192862122ea4eaf5a0248c04a6441a023f9215e3c2ec365f9ffcac3ca6d6d6fa474addbdf83ba2bc41332de57d79b169cb45f3162d3920307457a29f3b8291cc29dcd50887811a270039ced174aaa5dbc2f47a4a90b5b33c076342ebd5f7cc6002867b9ba0ac4f2d27646d9b7074c6a204b2a2e491df82416d50caa6ebb991aed750e276c873cc12d0cd3610a87d8c5886f5d2f5b8bb879c4bb26270d9cd84c5da431413eb973fc6cec1b9d0a7069fcc1c443f873957506179bdbac61573d49242f1d43e1de1aafb03b1df6970c24559bd25d33180fc632a0d1956f1ebb74a5504ddc3952553e8752e997f18a3680c371c3eda45669307c7a16e164921dc9b7b7830cec93d1bd543f60de21e23d5fa0b2556035f4bdb5d12b1558070114c5fc61094b7868db4945c8ec30556337ea76266c7ffa1daa8ea332b0687cc4bb95f7c8b244d9a27e54", .Okay}, + {.Lcm, "-eef2452544941f7e7440a0ea75f6928f95441d6d8f60c3166b713ff0c4700e51c0918008702c8d733155948b59847040d9e841d82e1923ecd8a63ca64710c8cf5a0ef409202a1481e82ef8384b5acb3940f5a313776296dd7064f0a00d60b2f1234206f507ab487a9cf050f61916e199e560e05a050358b82ad556d6726feb025476ea11abc86231022b640ea0981d2111df8c6f5a060a039cc228c4b4fb6c6fd2c0fdd5ffa456363db1b493ae31643489b8b762f6d4f9b04ef7a4635074c04c69f5d0a35b9bb11523c3d2fbbf560a307702e4f9d9c893689b2b711f6ffd9a809cf00fe2ae46ef4c5b04747b2476d9ec24bdaaf85749f3adb3cf9a31a759f334c8a321ef8eb9370052c89db95ed848f8dbfa30eabb85f54052689d8f14b53a2efc715d03d3cd9df0cec196eac53f127e7dadb05547c4eae7f23101dc0e275d1be96b969ebdac22a6872f554a36404470a868ec91e97c48ddad723db25a95d53551df0dc59d4a462e8a99b94c434586289409739a4a7f8213b41ce331eb794db1412e5af72d651a81089b73990575204262e05174914e959771624feba15012a1afb5d188e2cad530748e2535cd119e0bd250fc6830149216c65636514a4ce0d4d4fc627d5a30a888fddf737af6d5b8e6c19669a5816c6a2c7109dcb991d7c5e363261d7567b2e78fdc27561a369704a2a4670fe3ba2842f8e785f22d71ae3a7a", "-fdb66b6f379ec4dd464c7cb6384535f7e2c104e7a52414d883ca89ac4e220a6c8b8e665dcab8b58910d69b2e2b8a233ece966d104664e4b2ddbafc6748c3678106cb88f97c39fff14bcb7a67145bf03bab28a4d7c83e0957fe33267572367eee0e0588320298fa83f66d718cf05698f2e2633f52dabd73df6937e21b8f44dbb6669828426ebd38bf4055ab3e94a944837cdefadcbfbf98ba577e3c0a94007ade51b3545460231f0df7b3699fbfdefca898f56cd3916a0b17b97785195b9ccfa7ad052be55e2ae2607eea9b68ce278f8e61ad77a242c4455ee85ba4ac65b510e34bae84c30033b8c4a86b554b35ca99a500d8f464e883a2e3030a31b03b682b8758242260d1cf18055de270bff890e207d54e7f7d87b88c5040fd0599dd968a097e60de3d64952f062b1e4c9ea7faa6ea4540f84c91b018bce453dbefda149574f03777361c1141b8bcaea29349d73070eae64cd97acb6a205b3e0b7f04516f6c91a94722fe731b0548a190e498452300d24ca7502ef98c1183217ce71658d4e35503cda68e9f60746daea33492b673d86b8ca6a964790c46c82f15cfe37f3e2e10c265bbdea1223b66a321031b67853c7e5b051aca8c41a7958422c54e545cc346358839ed0358ffa0943210d74a154d8a37958e81d09aa4408808f9f7dd9fc49e7104a10704125dcf8e422562fcb44741491d0bc100f19d31570a7698e43e38", "7667d96d0790f8b15b4f053f72cfcfeaca3b3117142d05d7e494436856868b97938f79d85abd2469c8690c723e36cced36a1f79bbdc134d5a4a844e172699ab9e3952923e80efe6f4058b5ef73b72cf5a7a833e20de0260ead793828b79a64342a371ad5c3f7d408dbc77290220f6aadd90d59fe733487ab01fdb05b142bdcaffdaab31492cc43b05847b320432e511c9713c5b3cb958c902605a4c993313b77216b56e3323086b183bf100876f99cb5c14eae2460a3605cd930b1ed170c9ffc6a1b5997dbe18fad37830e2345fd96aecf402dfb289414382ef1e84b06e3fc78142b53ef1dbdf9db10fa5613bae8c32dbd6b91ce1308a89aafb0f6a10f19ff8488566a173345399cb3195e5ced11df774b82dba2e61a790d510eaf635e1d89a9939f2da8fa4528000c155bce876d19d6411c3a1133b515251bec1a972689e3f50b1b7894e149fed9c92e9bc3363a0b8554b21463fc563ccb9aef14df5bd9b70f7bca083fd8f135f2aacdd8562a00f874899a61a795a4e3b7a4dfb47f5ddd9558d0d1c58e418e8a84b5abbeb8107733ffdc039e30a7b60d12c272522e212b9a9fb6b480fc647ac7e9f28b893fb4d5c076534ed8a6e198239a7fc431e88bb509ef8c52a0b3f198e0f4042482017b646d81e9329647d33482fd72ca94c0c5c08f175833214368adc709517c6788837684a10d0b2862f9af7077c813d96175849d97d88c86dff4473a83523c5e75e22ff06ad01e91973bac4e933605a1d62ece21296a7e5defc0929086a5128acd07d0b71611d7beb70e4fd63f880b82a2dc9237674fff5f946c89ecbbed2d15b24425cbf503c5b568236688db0cba7c1acb9fb933a1553c0f262516427d9b095ca7e3b98129d81f2500edfadfdd636fa850c7ff150f17d292d7a3ffe7ad877138b2ec5e6618bbfff916e6495207a3b4ef398d791c1d854c6f10deb18248111197e630e07e6f01beb50500e41ac42e5870612a22872f42d637e178783c7abec7dd6520091237e828b7b3a91123c30f088f1efa8d3f9e01d248c9c4975b3cbb0271c62ad3c3f47e7b19a7a23177150888ad2c525e5bc2dff7d483e0a0fc9b8f220befcb93af39a7a41667c60cd12efd8796529e5e648c55d5e2c4e766f6460eb7e1b070157c14bc0517bb9e4217f65c4bc4cbddeb5ed96b1c5b1796cdde5b86a098453e50a9a51426b117207bd11f11d4e6e4a9a0c58596e7fdf78213a8f978c7cbf92701d1d3602c25e251d031e7b693b5bc6bb6634f3c0ac9cc70c7869903c9823a774271f58a3c35bc67cbc1640456b615118349dd2295f9ecc31f9f5b919ad1275820abd54455c3b8ffd439b013c021cabbcaf07a74c471d8a4b5391e464f42d963f69ded40748c6f8455343e59041642a5e11d9c012b04aab3e3dd5a79625ddf4d655ed8479db1c93d619c17fd32ccca772b58", .Okay}, + {.Lcm, "-4e153971792a75c2266e6f822382bdbc2bb03474c0804276404c381b4df99652903c2a0721f2448f98cdc57489464e0ad611c574674e204c5b3571a08ad2f04b63890a53b9fe0d97c6d57f933b9aebd9aa14f2f5a0a01571fd1a1fcdfd2aa94086f05e63031bbdb9355db0548380edc65ceedc928b547ca1204997148976cf8673432c0b0447588941a64ea55d0074964d2914805114e5035ae1c4c33f856390037b61075060fb6b88d509c9365d85f270896d55e520790873d253a939209f2354d647b2c8db1e0cd23719b1537e4a910a01f887ad60e9e047f2ca85b9684c6c3bae3455be3dc3705c26f319a2663617164572cc0b01c1d9d1f47c5fa1ba3989fe3e7fd8c3055d43da8ee2b8f85096a7100fe4d6bb1178fe81d47c1b7b7943d4aa8a07f1ce79abdf2749aa7f6a132ee558eae0841b863989b1ec066ef42d5870c466074817917816acf5d10b5cdd3d5fd1bbb54529119b152ec6fc26b870049c6431e7d6937df00d89f522b3f5198393a57ed72502afc164bd04d86c461114289b56384fdd46b35b637ae560b83d2d63a22a4507eae238e6853e82a9528c101d0fee3b3e8c4a06990ea1ec5d80b8cd5fcab25e4a67662df94f72f7062f4c12ca0ed88b448191b0d9bb94b3fdde2fa848e1f69c8ec092bd53028dab79e030c60506eddf71959922e8f09325df3a1a7626b8f95f5cc73b9868d874b84d80ccff1d", "e0734cbc5806eae6ec4613a9b9718815f37dfd977057906889c3ff277a46950b3e7e5fd8935923d571441f393fd7558363a67c63b3bf5aae804957e553e4ba0991d025e7eea0147860213592604d0aed455578a1f356d4d045f25b6e327e87272a8d3e8a9bf24c25e592e9d7c95e811db679afb529da6eb73ed98c8b724b672fb136561591f4b07a3a5b472bf8eba2cbe50a4920615df4fbad4a156cf191e441ffc9bcf6449addb2e0e2f1050c7806cda7d0100e23a742f0870c786270d3ec3e806971b9f510345b6b35c6a655de72f90bbe45680cdc624829c6bffbd7562a3b67b778078e5a2f9f368d3ef43903429bc5d2bbbeae22d7072cc7af7df13574709107d29c0236db4749e3b5e2728f4fd96a247c716398604077854921027caae6e961898aa6b807568a92654efd08ddb9b697349dccd880acd2c71053666ff19dae0ec80bdf572bb9f2fc4508765391ac7e8d39ce1b20860531d9cf5da3aff38ae355f85b662834d6a7b443d674b26de9c558c7608f2324a87104f1e102addacb0b57102ca0e976740118c9b791b722c9b064cea0a42e02b12c693e18a0cea91367059e4e67c951b386ba349088e0ec5355ceec2e23ce129f07756fa35c6cd19888f25bd192084ad7c6565351994a09ed82ebd3cfac4d944b33edb0c21217342dfcfd74fb678a4cd5a2f82d94b02f2f1d9c6a6d94ae2f85fe716944055c975ad", "4475bd33d77bdc4e8defb819ccd995cd3ef61ea6642b83463e38f789d9a33f8dab5453203b9da529f91002f1e66d4c3489a493b2462b0b88c419c60d57821db632fc8462214f8c88d0f54169616873d808abe7cde777adc1290d86ab63e3bab86c9b712bbabfc5454728068feece473a495d531cc6353be7c3740de9a11c1d630039e1710ea7abe8f0b048856d39dde02ab060478cbd9a9b56f824c070cce5c4871cec48da5f3d55b39d283785d7a0fbe3ea41af4cf51c463d371ba70092e9a64d8565fc6eb78113de476e18be97d3a7f34ed92920e8d63b1fe1ff04626c113be35777f1d2e8b75300f7680152cb4957415dd9d343c5705fa05dba30dc1441daf7f714952cec1890b96e0317b9b0c69836d4572b60c5ef02449f8ade2613b441159152cc42e4cf0080e694965ea3425dd11954914b89d5efcdf1de1121c1ac42e07de11bbe7ac80ca50a1d334f3b6c4c5a1ec8896e4f2dbd71afffea22d5f48bcfc43af19bf67465a32fd43d885191244253b616dc6ad39fd846043f0408c6f0d4ff8165c939f3d47176c65d4110cd51a4d6f28031125c3ca99c6f61c53293f14e4d9b93b0587df6fc11ca6849330af17a86f5b051169e015cc1fcce493f1cd56e47abc8e703ba031e0eeff7bdaf3a51be708a9d53c432afd2c7d40a5ef5147e620bb19a7fde40e3bbbe83124126de09999c2b13cae282472cb3d91a12ab9fb4a6ac7b43f77c5fb662bbef5d89bed78e3a38eb7f8f38f5501d9b38c60102c8bcb72262e846fbad26d74f46cb5d3761035f087fb2eae09e41a21a76d3bfbc4d16b3f5186b6954e9fd9557cc4c6cfdc73b9892acf93495438810db421bc1b7584ae1dc9ec1ed6cb61c9ad751bcc2fb5d860b0071d5fb8787c0035dca2a569e300bbffbc375cc17955e2dfc3aeff6c6504f893aecd065a399d6ab62017cb2cb1a9318a875e024133b4e939ca7bbf936809d8b4fb9297c26cf651c892abb6bb75c9f2ce35c0cfe8d4b6b9f10fa744a26117d32ca2ba5b585b760f2b147ae88ef1e8109b49bf4de26be0b026164905c8cfdb5cd5b50d04e280759cf16ed0538f6752cd41269fafb4a8d214619f42adfa29095f512a12f33a9f418341d4d003047879207b55529487b7b4ba231721259d6e3c1c28535c6025b1a3ee9ea24170295e2fc36e522b1a5ebcad8a90daf946a24c3cb91bd98a48d48eab8e4f1b29a68fa7be34456f158dbed84d653b6cc2a014f0b9efae16da941123300ee8d1702d78231ac738083c60a74f45db736a0824901cc606c3a5506bceae6030c883c9cba94b7c38cd0fe8786ecef40fac8fa59c9c8fde5c15b41403675109773d4337ed88498e43da6fc4e587263721b3f8dbca82cac969ac04435db2beaa6607f8ab465ccf62e9e52801a1ef2e08abe393fdc4c25a6c209231abb48c5008ddf4b526a9e5a799", .Okay}, + {.Lcm, "7594b1713cee5c9e0cd66621bd30d108966ef6ce14eeb9009a84f65a2c9bbe9ec911fd1d78080c84bd40e5458e40ac5639e584451082257d4177b34e84384164b1e6a4397dcbef2f95f56b1864dc6fc64831038fccc11e7c2b275ca596ea7c700dffcbc1579f293b9ddcd55eca55ec45e1fe892d85a399cc85e0bbb8a0ebdc4d060f7226b758c193214a73d951052668483912cc4f1016349a5be1cf69759b70f9be6d0368792ba17310543265477d3066aa7b87c4171fe99c3968ce70f701f5adaab915d304c552ebe4c0f72013543fc5b8bccce50133ab3bc29aa110efbae4a90aed3639bdbe2eaf3fa79f298feb8bc4e674526af4e266a7f3da162f28114ff9d8a0c63396ef743174d371224a7e148e1ca52a3b1f2dea4ed247f2eb8edbf2a1d1f96889e0afaa4aacc113d01b2f30dfb408e6347ce9e09fb1128a87e6291697b12941fad20369e0862ad8a96fe195661330eb8fe3581a880d7f1a5ebfa784c0c0b1be0d887098364be7141cd5ddf12b46a2b746b5b474058971f36764a0d41a3118ac0efd5f4034cf7237e61e1b45ac438c8ce15345d347b2f7961ee9e05e3376971a799b6cf418ec81a7004d299d1dca3c0ab3f5c7e8d32f73e8ece71913a62f6d33e1a0c48278e91912106c88797cbac70e07234154944a825609bc5ff027a73520eddab67686364ef17a28969e26b88c4d9ce81d17d03c81695640a206", "-818d5b9b392ac4a418391950a4c1cbfab6ff9167ea73f6dc3602356bae7d77395d333a529f02be7b27f0bc02d2cd8c1cc7526c575d8b06b6177a389bf33219481687179ea3f6bb67bf04e1278f1b6edd61adbc72ec189fce2ea21377d810b6ab8ba7a51395376470b6f5daaaa1dc4920dcf5df931695658d68718c41b9b9761cdb6be5c4c84c78d8bba5dafe684bc20ac8bb1ab238c8dcd35ee6451d284935c6a165ec4747674fa90a2695b9fc90f15b8c2964c8edfb0f6ac01939c077e16504d0a8ed86e501de3c4394c70f70f0ae74f49b7bd98ec173f0b9877c5aae232a9d97e67cd61f11b41f6920e4593f1e2bc0dbe0838108ef92ce1b317c51b038eb48a8186965a5280b940235f0666a9cac9c8335cc1b8efa581054e3d2f3ac8109a77a3d3390751bdce22e2a4d9ea824cb8490d000528c65ab7d6a5c54681ae957182d8aeaff31bc403c8fb766fb75bb7b24f29949e67e6ac56278d45c4bf1644a5de83318eac08dbe07ae88b4b89d56201dfef974fdb5a0075ceb84ee72c3f0b8567f4edbf4bfedf9451ae0e3efc0a781e8606accf4bb6abe5b0f4f3de3c5942dc46cc16e13be5ec03b1c8eb24bcf5ad3487429bcfea8e21c6e1d48643d73bf87d341c373d8a2652e8d9e4a5a501ceafe330df26b1fcfd357cc2b3a10f22c3cf81f53ae87a22c2ec1374b41c87467412d10b7d3fed7f29522916dec5cda0e2fdf4a", "1dc06d3178b78e32e8127c8ceb69c0b991f2d98e5e917b471ca4195dcee14791c8ae10b7e7464983e272c6eca7698b9d6192e415ac8bdf82b8a901a3ba4aaf732616b9abc52a986fbc9afa9c784b9c14ddf7313df7dda22e2167c30f93eb196b0458bdebcaaa2d8a44730adf1d71c2175748101075943563be39784387af180dc1a206559bf5b7db92739b0221abeace42dedc089125041c54c6ffce34d4a3a5602cb55549911990b0c903c1c9f77989a3af08f2b37266a3c45323eb217abe0b5a56beaba4681391772a1a65f2866ce7c6078bb71b37599a9a64d21fd3485097dd512d724d94099fabc0a93379cbdb0ef0a791a8453992154714af3dad516ea4097fc2b10d5e1e78c9a0730cff10adca46b97b53a8be7bf1cc54994e3a128d8bbc3cc1e5048fbbe904c160b5f77f00760ee8881677f599671a965e090a42968989fdcbd87fe5d0f8be679f4bdd0c6472bcb72778fc04191522497ffdf4928596273e5605addeec91dec1e6ea1a193089a94638d4bea33fcc4ba12e042cc2784c9ee4e66adb26f716c7183499ad4ab070ff883708040636479cc373db27fed59d1d6a90a1446d989ac14dad8c6742d136b6633d43c2a6ef162a51d24b33039309e9da7aa035093868a749be690e47943242e6c6f55f731bab8f68c5ab7cda450851fe49ddc4eea102341cfeee3e561db657072b469e6b4312f9ad99c313655430e98867265aa62f0dbfa2e5661731b8cd8a8296ee554666525b68041470a9ed7aa8188eba759cb1f7eec74e3abe5c6fd1a9b67428a529aed10b0baa7e400645551f87581fca36d08649647af3a6497ba4f00893d94007ad6f9321e712021fa9356f7139009a9f32a4ce4c617422ce33614e7fd64caee810dc6307dd03de4e1827574b9e2be458fb687d51f2f24c93e996d8ee7fb584a789f75a3636a814147843d67e19f097453e88968b6a8f9a3236a50a1a5eae376fabb6c6d8ae2c5c8296f4c20934dd1227cfe248522d7b11ad2f6ac85853f1dc62cf95a16420e76ffbeaf7b580c28f687fdf5218f3c0f9867c25db34c21c47277872607a5eee1f26418bcd3734b1a7da8bfdc288fb5e06c1b33c333cfc30521e7dc65f691f092133d66471674f90004442ff603bca36fb226ee58d3ba94d670710425c155bc8daf67638804653cca8b39af35a4e2249767b80f2543630e963f4fd586c1004210c332ba82c49a2d25693ee4d3c9e65d144c6b467803470a7985cd1e094a2afc6c0dccbc454cc1b5ba5446654eeba00921d1ce300b34557eb74a93ac8189f7a669cb21272abee72d1e4518c206232f2115db5b739b4ba3d67f07a1e2985ba9656a9a5dc4a20b742f5ac21dfac201f623379fd2d97123d0c53f4bc23546f9b06234c353c643dfb3a45893cca9c8ac26321e7fde688071cb4ac2069d72d1082095535a77607de", .Okay}, + {.Lcm, "7887a17488a537be9a1858ea7cdea6b50ae006c65a8379a85c8e381842f7e718961a18ebb3d61e9a82a6e93b9916117ee4eb38af678b8a4075cfe1e9e166db7e6f06285e0245f0fa934d3e1fbd02b2a2922d2879d375b3d9dd4e8bf474b965686dfe84053fc6437f2ffa1823f02fb304c0fbe373d1cc547c6ece74b2da294a281927ae2926f945169786de368afb7bb1c0b37c16e665e8d70982557c438acfd2b109198d7087a80275caa9b6600fc84ee3e04050d9a26f73e465f8d49b5fde66bbdec2cc9ce5ce37ceaf676c0628af527069ac69724b54f2155f6a618fb56ffddc7783ddbea3b09fdf6255c93b78f5bac04fa80d9acab7a26f6140568ca132353adec486e8df1bc4ea48fc76835d38256e8dfbb1aed94d927f87c5a48c6673f72ee0e12f264d72d71707ee7d9eeac9d4b45e5706763b89bac5f7b39aa82ce08e78f8d200566707b9a462c9a0e940dd10138c36ce84974dcd65fc4665ed7fb057acbc960da4ce9c7582931d4055e8b7afe922e1d6d5ac612aa9865d778f8357e9cc5fff89c8a618a9505b634c28233c4dc3ebfbb457a44318b5cec7dc7fdc95c34be3ee5d6142f81cb69eafc72e729cd567b10a9fc24b343b223bf64b6f17e6838105ce343049940d558cabd385e1fbd5c9a4b872fc01d4264405389999ed5638356e33fb0b91402d893facf1f5bd6203861fe9987dd0af8fec3f2c36012e658e", "-b28a745a818c96efecad26af9696cf654eb430b8b8ea5e4d34ddc25172a2d509fb4b07506819a36de660b283dbc767020f119336c9b140d4b2e282a45d6cab9a68943ed868c2f4d6557b440b8b792ddf3029228d487ec99e280edbdb537d841b1234d362ccf713ce0cb0aaf30773a70c4ae67e8b453849d8b9556520d6bb11508cca17b9e7eff02a81173bb7ae5581520390849f9ee792e98acf44b9ca044e5ce90a5b9ca9a7666264d280f24036d230f6f87abcca1c9caadb19a84920473fe8d0b4df5b0cb83cefba5d727701b77951c4c439ed5891199c5e23880125df9102b96b95fb27f5bde23738fb801ec25864708dbbe5fded181284a48de42138b5171b1ed3548c5d19f1cb64e433596aaeffe02c425a0cee33fa65baf09abfd83f5d0378849ac0a7df64e76d46f30aabd66637cd57f8eade9da2356bcf4c6c908dffc2cbfe22269588f7763513425ece87db5f6bbb12bfd853aca7029e7288bf4ee2245fe4b0372f4d0cc5a7e7cf06f4150a19b2e0f767c7218863c3891b420128569d3b4b9e197def732e264a883d0c04d12c5a89deabc2d1ad4a4e018d7c70b35bb4eec4ca05f514a29848bd9284234d67b782c1441860c1be6f928f2f2862e008e30236c62bdde8e6476b42b0ae6ef3f295373900e635758290e74e00620b796c0da3bde38e87183f3307f14a39c405f4c4f02af300c53908804bf9969fc63071", "540f7e2821aaa44dee7a83cc6e2cb20404801aecd3c310a002ebb0a25d5b89e97fa23da80e5a264ac7ab6eb07cfb49fa2af20f6cfc960faf87f1d604a1c066763d80ee71cde185b53dd9474c00628da5d70985093ecedae051230ccaba4ebbf01311b54d95d9583fb3280ada504c57fea47ad8f51f952a5fae488ab1be1b1a6953ea3448244d008f8c7cd0c570b7635a8129ef6c34f4454774a4a32bf0e59a799e6e08b8b730bb6aa31f8c6df6532508554fc659dfcecd38a0b9c2cbb80874dfc38a56505803e037b13451dae820ad700ce0190e18293499d81e1d81128facb6ae6db1f97f256ba441d3b728aee9197e6bf59fd3cc3f44bcd6e7f5e4108444b33263f54d538d6c39030b59366ed2366105e83729ce3b405afcfbe36b76fcc38afdbc4b7aa2924d239b1c792c84d86e9f2841d9855cd768ec040fe7c1aa0d6f3fdb05166f0cd14564b2239ff7dcaa417826171161a87bf55a29458f0207a1da9c654f4f6da99451c443342436048f22275ae70220126373d50442bb95f5d4407189713486635ed9d407957db620d4b8b97f5172b4adb7893b48415105daf54e6cc98bf8c430be39ef4022eac3da04c2c83ad91df846605a75959ffa75ce65038636977b4c8bbeec6805fc5c6c93100f1628cddbf2b1ccecd9369bd3c958ac07c0960c024f7037bca2b48802e9827d47e215f7e67949e5eb24d87ce7b83a790c35e7229c31e3600ad9a423717748deeee6a72066a750e605edb179a787c66e01ed9dbae67611849b2148efcb4912a11bbcbafbb540a85ba19a373084434652e1b0e6ac1cd89a98f552072de5884f7dbddd570b0b7acaf1fb469c3b2722a79eccefb7b1d3de3791785494d7db77b775b40af576b1895a571072aa2194b4e3ac14152db356647ec928427213e6adf696f3304dc36b77feeff0539e6946b858cf1eb741613a37ec62728df276da2661559c7aea219edb00e66cad2d1f1e939ce27fbbdc738b0274ee22eee596f0871bba9e76e98868093e58929aa025595b44b0fe17b986b964f8f1e43db04d331e70bec97469345cc444ea50d2654f3337d1ccd984bb04915d19e90e81741391c33544bac94fe3d1868877b1e6abe13e1f0367fe960bb81b144f0180eb1f8117016fd90f1efddf367df04014768d63606be9415331fec0d6b22246fbba25fdb862a9221baf628e00fb75768d19f3740889598e92b7cc1d4e1c4b9e83c083aa742f97ee454d64b0b6fdc90b2494bd5723dae8b45bb76748865c4c6307238e5bc4fd3acb155bc004cf42781a015d04d15fedbe828b820dd087e61437df86a80e409e4572436c49e915fe54006eadf28cfe86e130f0bbd10a728e1a5fa55580b27d2dfc4fd190f2d51ce44bcc43b3eb52ad66ec99dc4b89782deff8cac1ee1955256498883be0cb804a852ed834be6f3dfe38f65973ae", .Okay}, + {.Lcm, "-efec6c10470adba6e4474bc49f451f94b8a3394daca8f270d0ead44364ffea48aecf6e9824e59259aa2feca26fd8aeadef49605526e77b4f06bf50bac2a95112a60786207cc6cbd09a69a59f2726900b0b121eb2dfcb7c1fb33a141b3695d49b8f982c12ad02d8138a05cb991f9a88dcddd95b8940b53bec5a652a738c753900821cbfd1ecff27559a05466f95b27e6720bee70c1bba5bf194b70090f6933ec992381b70635f9cfdf40df6b1707c7cca8fc2774b900e692ef34225c11121c02c1a308388a7ebcb12a58612862fe73f5cc169c376506c9491db4e4f44a65aebdcc6fc7177b657540eb4fb543cc0deb4580c2bb0b056683a3f1697e670bf7b09adbb77557f9ac982c8eb11ffe520b39ddf00a3cbd923bc301eef0e3c23cd62bbd6b0c773ca0fd90efbafa5b1cdb8f722b90e810d11b270cca71a022be647238c20f5d960ff8dd2adffa8b9cc71a2feb9c98001b7830354963f19c48b98ddf9b4c4f28ca8be23284fdf34619df0917d570921ffa467ab96f752c6a044c125e752fecefab81a38efa765045981200fde328f302125fee05f0971d82e52aeac318319e80d632946eab64e981e05bfeeb9413264e9feb2dd1dd5b239b7c2c15f984c827e9d79d9af67c11b6ac3abbaee167a64c11e6feaac2b6da67270dbd2cadfa24128f2a9740cff5bfa41f78ce3f895f7fab0bbba552e12457b58da18d08188ea80", "ee8c7b97ec258600826dab895a4a1bb0d41603908385d5ee9c070bb59ae6759079377701ac2d620e8c3077f08087cbfd7fa1859d3d3c47181806e8b1e06635c3eee93b5f61214ae891a042d2872acdadc44d1714c6380827d6a86faa23183db52ef0d847bb4b7e8ce32a552ecc208d65d3a239281f0bc368b145ffc9fdc56dfd133a9630c7c72be8fa8d7d823018013050d47009cf0bd4c057edd03fd7962fd388028f1eb156af229576e0435455e734f6972fee1d9764562acc2f90e2616417630a2fa0eacdb667111beb385dfaf89be0f2e95a6ce4ba00715849f624f1ccc3dd7abf8a2f3cfd54db6829b72b9aaa515b8909109f6b5909ddb2151274f094291d3ba584cee2ea9e8fb5ab3fe33e3bd8ed8b1a4f168bd47886aa6c84e2690aac0a7479b70791fee275f54b791b16233b26d808dfb42a1a71d8f0554859b6a06c1c76671ae0b6138d2dda5d5ab60f7be3a30ab7cf64cad799e1e432d91779ff97f8817d5d189e85d4e672831c45763263b6f8a436b7a39e17ebea66cd10b4a6d0eeb6f44a667ac770d8044d51f5f6571690be949dd9f7fd9297ce81b6fb483612298ec9b812ae18ee024ccd4d023dc6be735fb458270d55d483ea23f85b01b41fc685056313536fe874342f9903144ee20e1dd558fb52cdefc13061704fce853d8fcf565f9f594e6a7549ba8e4c7ce37537229f540e9ac475d222de88790dbeea", "2542e8ee88c5f00b0ad8eb0464279b51e5ca1ce0a036c2de468be4eced826476e1721ecfc290ae5f6f75a76e2c523eb055c391ce31a949f39ea73bd11178a038e30d775ce4f02de7542eee9b0ccf7c6e933684a4c9b5e5e16ebd3416d739cbc4ad155e73ce644e256e63431b773dece840e251b789a79b768fdcdef39ce4937ae1b7206de7fd6aebf9fdce0b1efff63ca2f94689b1aef06d3fa628dc4bba974fd8d14453e1958606634b58746581d840a8b21e52b5804fc18f8bc7a42dec07450a0f556e584d0370edba6c7271c032ba8f574493362de8d129f490d114f32fb041d597e55dba0702f0eac4da90cd672f7a5e430dacf44a5a6c7a3d9da2ec330e681b1b529089663324638c97701668b2ed69a3967910115771bdbb21593b3778acd30a91eb4889d50c4e4b85180599d2344fa059ee8673370651756b13ccf33f7993f3c6f31b47bcd425bc0e9c1053e2d8a3aea2c21e16dbd8c05031e16b88154ea462010b052bc466060a54528625e7d589acae7b7b72d9658b1f7c38ddc90c328908c71e274491381896b157f155e56120ddd14ddea829fc8bfe3e26c717b07c8b62d6cf183dce4a8a81c050946a49c1955006d4031f79036c6a4f3f5be5590b0c7fb1e30ab607e2ec57e5aecd6f6d53cec99dae3bc244e5b458748d2b16047d801127539ba866c354ff8f773d6a596da83509856a538274191774a19086269ecc66e5ff3612692a3df63ac0fc259938304d08647abc5cfd1fbfb415aa69760e98be5268fa97d7c945c5f2990b14e5b7fa947144011d83f4ad51cda4c3db0dc3a7e66f71422997a593f05280911ce1278d3cb9ccba59bfb0c5c2d29f00caf43acdbcef2bc0fe79bfef6a29fa4d06ccb02a8a24bd23dd3e02ca0c43d363b0b86a862c0c873a419ae893c9b696b8f9c979a6c177bb14ba7f6911e56bb41802c9355843baee6c659013beb4c94c54e62b532819d72b2adb167f71896fc5f81a6e23d46927b8e98a06174c847c0a8dc606f9f4ff409d3c74724c5623a7ed5d3be8349bb44c13ae3a8c12f557f999c133afc368439b7a0d453da9eb6d4afc0dbf5fb567213378f47d36250b46b040114f396a5370b799e144ac2ae2df3096ba5b7f8a74636bf51c098a98bd51250e2d6ee3615f546739b8cd425d391d597b249e815e97ff7e4edbd5577d426eb3992c3579613aa9189d83a9335f45aca1b6db83443d3c144d2d0bca844f84c6d5ae4ae808324310f0cfa2163e785ff7c63f86a06601ada311a8148882c6d964e07e7b53ebed06fd8c9ed1856196ffdb6bf10e3bb229c24bfd50a27f2fcd5df8d46d713424ae3e67e768bda24d61e88f6fa86e80c3949fb61137061a69089dd7f9591ba76f46589e12f6c7e09d66f1209ed1223edfc3fa5b65210abea9729dd2a93be7a692bd29d29035ff0e9b6e72379612483980", .Okay}, + {.Lcm, "-ad438016b32c5a0c3162d0e65c6ff5d07dd54c530662ff9d8822c85f05bc2e9ec51ca41a09383ebba7e2c7e7a86990bc514b26f1cb583cb1149bf26cf931af2ee685dbcccd33756f56ec24a2f13828714eb27087894f01647ede61ea988957895b846691140e92a71efe37bfde1cb0de75f28d6059c2e8420141a700d269774e62ba207db0c53f8b47c659a17afb4ff5aa2ed2018cf302501e73deb3202c6b24c5e9726dae62c872ec5738f3be82ade69098f480bd70f820e475f0a60907bce57b6ce134ca72850742bc0a8c810764a4b122d96fa42441ddae0902489bbc134ceddf6898add1b33e9f8c1cf660494ec45f5d12be60e038e8c7f59574b6811f4d03640a3bc94bd0d6c667bfa405a038ee029be5618a22ef5e49261781018cf9459290e2530dd35897feefab4ec0be58dd819a951716bc148e8927e1f8a2366203c30bcc5ac74f5727f09e0021ed26a68f0255a823234e271f086cd6ad97c62fb295e5ca63bea371a6ea6b7ebc2b407574a83089ffefe68526fdb5ea46ac31c361f1ce1d845eab3469e8cb433c06ff4d25716b0f1a94573fdd9dc4f5d7a7eea1938ece3afb5a34c571af48327be41b6ec3e0829f6b3f90c0ab549f8262ab30559319bb2ca0a218400324bc0f262194ae4e12fa5b83d373b930912c7718af7967fac84422c49787c2474104af0b14ec26fc9742b1e84292e6683e0080fb1c9a82dd", "-a90ce46cc2f96e9c32dc1f6d28e835f5847d66a5a471837456fb3bc5ea2315756b39a7071632e28f870080246103e1882bce08d27ba2f49f6224239f578179d8d8922f154cf4c4a352c1d8d9af4d67072885b9818cab8c3e95dc4fe620eef81421e6ca7f484f6ae99f63448825d077f8c075479b811b466af111a621217c6c1d277242ffc0f36e50375cd0133f7641b0fe1d05729e428dffa5010928ed1263418384176ca31a880b476a35b62c3df2057d74001ac41ba60f449996ae73339d63a87b51600170b6b750fd47fd3f62934fdd839285d33dfb3c4174e7b99bb0b130824842d088b156e9cae54679bc08beed1195c1cba92bddc98f538ed74e3bb44d8ea0eb21cfb52ac78c7bfce3ca47bb1a956109fa3082e45a028c1069fa425814ee3e2dcba98a633c417cf616cecf8bc6f74762ab2888143a35f0a173672ed8019b681568b27b56beb7e1dae6490d7168781166a156d487248a29fb3e671217c28b0031f734e229cc7e25a38512dbb7b7e48e6d494fe4a766186d7cd1fe5c05e16c0970cbbd887f5fefbd568f1b816a36870e28fa99a64f69b077eb7378af24814287855ee482ee4fdca44b77def1059a6eb10b1cfe249072c2ce678ea0665c9969dd3eeb7625807cbd3c6bcc13e2f727227f80811aa925bc8486e243adc9d051fe90d2a6a00ca37dadd023d580e17cc83526bb4e58f97dab00c15ca6ecb6297e", "726a4952b7dce742de894129570134e0615cf623e59f480b03f2530b51de4c30e562e973956c9952e94bec57050af52389ae32ccea0ec4a39e6796bb33190abcb3ce7ff0df04957b951b924ef34d6a2819ee4c80291aad0f9e3a2205f2ae30ca38bfc5335f3fcf78e24c5bba587178d4db87d304ead034f0710015f82013bdd3b590ba2b386d21558ee52f02fdd7a7228d240123e78b49752392775c9c0270a8fc1e62cda871d5f31f355ab3339a7cb4c2e52bc33b3ff01f83043051fd28f65bd350bda236be938d82dc3d88886dfaa1da83f83e9f74a92516c512235ea04f4c626ff0787ea7fcccb4cf58418bee09e4b61e5b34d2218421f49d6f6bea2f85279db06d615ef3ab00c1556c7794a7971564a88aaf1ea98ab8af68493a76c79c8309bd45693e4a77e0a21428108e039c594c05ce1d92f7ac25c22b96244779405a095f004e66fe55f8d2d508580e8bedcf443dc9216b17b2a890ca98e3907d9be6d2408c036243e4d8689226eaea1cb8c699c4ac3793eba9cd157148700ee3e1df52d35865001343ff7841c64ae3230758a72703a764662921435e5aba8ca141fc824229d29d4b33d9fc2fcd4d8757bed26c1750c11038bb7e4e8800a95fd3eb4c7748e51d2d66fc786516f60d3d9d3db617222b53f6adbfbe496c33ff03cc6582f4dec44574e909acb2f8d1941cf4f993f2b8abf5b08c5c2260afff65eeb69db75539dd7a1d1edae608a7f360fc605acf284cf18447077ef53822c085391175d017aa691ad9e984a844241ed840f3ccd7f386017ae401f0c2f1487b06e0969c5ddc378665be25a55fe38d911be194fa6a7070a733670433fb35ed0ce9a159322c2d229fe3847ddf14445600bcf0a49ae1a45e3d6b0c895cca064a5a13d8cc7197f624eaef17d0463339ba60532b90bc2523e160d74716eff81d37b11ad25033c5f0acfadf9d486931adb4c2646b7797d335c84c705b5f7d1d31addd7beb8bd4b10fe08576651e12bac7d9027018759d951bf2a017f1dcf94c2ab5e9f348c5881594c23f01db7a3eec6961c689ce25e352bc126fa60329f78d614572701a177c6b14ab96ad92df9df1b071acf2a84a8066c1c05d3db7ffcd69e4859e74abf7dc9b3817738bcd253d81a3044f7f4d877c5100ccad3341cb8de8e2b72bb1a0ecd9e7a6c71d04feb5ed5469304a06d82d87f967d33144a2a273c24786e247c8d74afb392be1a0a577a30911c370a5888da2e849a6a2f62edded44c1ca535b45bd9dbd3717d498145764f1da11b631f688c755d01474feaaab21387a77f06121dcfa4adbe845ad41ed0e842a99d251d56ab80451486a487aa9036fb0305c6387b58dc37f057e018ec50af8bcfa5870fdb4bc35db24295698216eb38e4d7a6fb9c521b58cd5a49ad25995914b8ca3c71b04371296542262a08768b785a1c0f7981fcdc6", .Okay}, + {.Lcm, "-ae934a24ee5135c3f191f6e3eeb574d2dc91ee48d11c61d5249d961a307a568b9caf82f9d00065e6f70ac23d7a57a84a9774c1e9288fade87a42bb479db71f6cf674fdff9993c5f164f9cc0e7b8637f54b3b0f474819e96eb0f2d724910b3d2ad80f00ac4905a68bb328b9c56987e85d85d817693fcd0e6d2bd23884206e83078d0cecd31ae8d7f1d42755763c7b3887b38b1b1d7623ef3a854e33f130431618fd30daef575d42f1e955f1914de6d9c252b519231002af96b0b99f8994413b5eae4de50df2e5412651eb61299c83e66dabb3b66f2c463275a03c4fd7b89470d1109b84c97776bc1729eb8d47bddd6227fbde2ad5aca0207d109500984713cec9725a20c9514ff5374e8fe04786c58ab94536010e301ab0c45ef880f34605780a3d14cb764076365529666c53a1f3ce603308263ba11325b961b72a11bb6cfe6669289a09fde24acddc6924c981166040ce565444924656afeb68027cfa276ec782301ba7263383ea1c1fdd8a641eb50caf4297af5f6ce2b6707de8eb4f1c361f628924b056f6ca3e2de3563b39ad5aac3dff0e7405115ad32bf031ab1f10ec3606f4901cf29ba16d2022ecab2fb3afdaa1d0a203443ac0e061ca8a0b01aa12ab4c2aac158c66c85eb2521cf1803a7b54a8cb1cd4e40e706c5cd0dc4a9516fdcc2c423c9b3ea0bd849c84ebc6f0657c657714750796167362ca814bf1b7bd71e1", "6664e1e9ddc013a206ab20378138558304eb02817fb3f7557481c1fa5afa54009af510a06271b930c58feb5fa40ec8de6b9c7ffe476694bb3ead70467bd2159e85fb01900228cd4c71312b4880eba8fa0b3d959cb70a606206b5f88e28bffc4e482b18b627dbc8785a43745ef452273d0ecb2b74c4c3304575d1e3d41da2b133a16c169bdd1b6ca67e810e4db0d353150b657519dd574cd6a9899f41b48665f8510425f323ea7be007dcaa878882541be9464ab3e3f493579d02241f233917c631d635309fe45881fd087cd93299e60407190486438e606b468d36fe37dab59ff0ce9f837b52da2b164dba5a5bf33622a56a748be3992dcb9e19ee01cd1842d6c8f47f581e5aa5819e7ac81ca78b76df8eeeb5e26c2d797436c8978bb1ae1be9ab369e711f03412ebc78b4040cac1493649c221a75a276bd31e209201d762c848e393cd3e34d31b5863a11f30b9d03eb32ce9a2fb0898878d59f0e3c179fa6b81a6d9075b5ccbca5a8966e0c6d2afba74fa93adb8cca5d95bdb5f83066223f99dd374ad1366ebffbb0f04c8af651ce2980eab46c4e2389c6cb815bd9d8413e9d523bd309dc9cc3a9d168e54cb1afe72e3d86beddb5c89cff42588480a9d833915b45ecd4ba0789988a22bd9f121b2efbc41f782f4537c7e3bb73e1fa04ba8316d7e80db71c7c60556351d839ae82801d706529e3e333f064ffcce65b0daa1835", "45d37b229cd2871444a6538462289c57f905702932a589f4f92ef080a3b0c6410c1acc35a7f1bfa253add100c3161e8c3b0ba7cb57fef6eb912960d7b097de6aa2ee53da15c77aa8a6e725a508397b4f9e87079b6ee83e5b19cef3c9765a49e0e23a4db5e4829912cbe204c56f8358858e368a671d57e5f4c70c7c51074fc930d293528d9bdafae3646622d242b5c143634c4fd7ceb8bdd8e9576e4ff21f97890a530c27d92f888c4b0c6e4297afff603f23209fa0e4499cd67ffbc642979534b2f4eccb6b9066d14d110e0dac5a6f07acec48766a56bcf554e6038a0465c5367a7b0ee13117516ba4308e292417dd8829eb3396ce995668dc5ec6db2a845e9cf045f3ae01f148a6a464da32b2a6ca40eed3a24f070f34adea747d16579e31088c2abc9e38bca6822f32aab2a6df1cdf58f8198973d7383af9b204f2d469bf3d5c2c065021a2197de213da67ae189fb8191f25627f2213a5e22742cc8bb31d2730263c4bf6ff94ebe9c56be3170916cece662e71cbf4864a7e79aff817b0ad6045b70254f645c595f6938248cd737ca385312f8d4785bfe4155f64b7ca8587b77d40df8108f27989efd10f3c20b35d3d15d529cb580f47b210355d1a30d8515e9193b340f466c79d66643db7d21fb227fa89d6acfe3361567b47cfc878e1c1e4c6a79eff647a2cf3c5354e8c030ec9bc0c41872faabc8a6616d6c344fc9f44a0de771129a21c3a3944fd973ee6e9ee6b020d8bdc4a4e89ea2652739e6adf01b2bb342b991118cb0e2e34c53b800ae790a9e02d5f7b58739b1ec0b096e83022053b4e9b7ba6cd63ab9e50ba7f74cecca5e6a3b6ed270d2fad26614a9c120b2ce4ebac96743985a24b55c891ddb0004c6d38a4f8ddb52b08dc7d538e9c85edb2998310ebfa1493fe28c3c9f094cd4af789856182725d885aa9110ec4ef09964717d428441ee02864fa3daabab040d077ec6e11d75aac4227e5f2b8ae1d7eef64537294bc5b3734b8bf8f304c7e7762f66128353d525fe504643c8cbec5ddd3447b94c1e5b010e98d141676bcd435ee67ed9663989bcee17486e1cd98be0b6c4176ed9dd75edcd67224b1ca2f587653655c2fb9a205ed17700c1c0d3829f27fc97ac1b6cfa33837f2366090059455cb6bf2665363eaf321b07fb9356da4b96beb11f8473f6d1cd00b4983821083b4110b48d9ece0fe59a6fdc0d39d2e52b9b718a9d45dbb26aa7aff1dae2fef712d552531cdb9e8ffe1dec5efe8b998ddb1db4b56fbd3c90da34301990bcf25198ff36f4e66e05c1c52b33081c0b34763a588eccc842098aea7c0e7b301578262d56750b5c042f26fdeec4bdbcdaa508a9a5a914e1b868c236bd5c1f0ae1d590cde5cb81d2ee141d4a0f3ec20e1cb5376adbc92bac4c885ec5cc4c954c637de0b1c79456af6ba900dd5c5e67223afa5d5d94fab95", .Okay}, + {.Lcm, "76b1a783fdabfe9371efc48fef2f87fba6e6b55bd53dfd4debf1c63b4c672e12a7e33a698873826378d332cb60d5e053d68b6adb5d9e53f925f76fcb9b653059d464350be6eab2bfb95aafadfbf78e296c98df77ee49191c063581ace0c509f7c1851e7e65b3858225da6bed6e068e4ce70b9c9f42fb594a11aedf29805c5c9a2190760a385a237b6f37a385b66ab636b96c46a6ae5b60f7620fd9d219ad39863e7c423b27e1f3cf5f4f61a9c02681090c559e746adab46fc11abfffc7a40cb4718d0d70e7b5d8aaf5b6d05dbb041039a3d7587256216830c5c66dc1f9350686390c10454e3cb751e77a69b0401dcf17e422a69b8985ca4947b086cb4b89e1a9729ae23407362cbaf4d25071d6fca7ccbe3679a1c41ed50bfb0d7135d57c2c4c4afa246318186e2d737e0783fbfbba3e757d2382fd1860f328e0a8b3dbd08fe221eb16d3c74065a34d1deb978fed8914852ab2742725e18c4c7686c18bda097d1ceb9a24307588dcd8d77b563d59ca0ca56d6b13fb59d3a18f0675983e16c59b8e689437d773d4c0bfcd2b2d195b50eee6ff2f045beceae9c6d0fe28abdab2f3ab38c1f80d535e2f1e5a5e1f50943813fdcdcc5154b75e3609eb82942bedcfa7b18bea6537d8f6c46a3582cdae251d5ed72daa6a995deb8fe262a26b433b78bf5a8240b002a1bea63d86dda23537038becc77eee1d456f58d2f175d2386682bc", "-29a621145ab53a3321c9935e1009c66c246a71a3944144a57c178bd1de02378fd0eb7cf3c82b15ed89461db2b06504b03f5f81cf2a5f258751dd9ced9d62656d9423b41c4df5cc3d1162ff21088192dafa81dda9ad7eee1598c020c4b7a8752ff995f7d738725023c5af393385db32daa09484d64c4b923e76510a6665078199d2fc2458fec7f13361cb30ca7c611597d0d1c5f8a762228aaca7b56038d54b26d23b39fc5dd2f6693fec002502f0fe2c1f143557e61699db7447184c1b06e100644aaf0e97df4f9c9f05ff331fdd7a91441b003fe6e45c4750665ec408f425cee55b07dfbd365bbd4ba154da1545beeddbd25d9407ad8e6e2a4b903eced4d5d3e10703d41b70a48dc2e12c64c90c97a9c17c24503bde0a84adacaf32bf0380b3e6e00603ab3327bccdf1a4c09b56eb997dda6095e559a5f7718535ba21c106e3679d7598d7a000c96415c7b947c1caace63daf051be58e26a8c544d860ee97b677af13b441bc002215a0db6862e656a06612fd5114f00db5d41ea0659dae5b42a14768df3998a666f910bc2924289c1110d9fc551daab79554c7d311954578608d101688bab0b1227cfae6e4fc16f704ee26eeab83ef0f03533e25a56390d1665f704945766b7d76bfbdc382084484c39ce380be7313a044e514ec893db4958c98b0453678104daddbe8698fc4737218681c1b431551513cfb085b8ccdd904c1", "134f7a5d19be9ecb7a9fa270d125df315efd18e6ea9eb8257f3ece7ca5f6fd155087c59a734839b5ae46f7e725d2ace8cb10f2368674760494530c2c661f61a551577e3005aecee16b903a54d801d0f59ef6ffdf653e93ab7c76179c1b1895b8bcb1ea62d5d9fa14ad8ff812150a791e28ebaa5275b427c66a64d4e610c230a983aae706bd36bd411a0d368063248632d5e184874f0bfcbe7ea9ea16288aec964f4b960704c781364b095b51a575cd27fe45b7144c5d77183abe455ba4673732d87aad751d53fe82872cfbe2c3797977c79391cd3c4b2c816bc43867da7efacc112f827fc7e0ca9d1462115ce3d34cd848331c704ab32b0a4317c1d23285a6cb8d342a6273426c7cbc4ae5bac12a484dbae1a69d56d75ac8fb4970579df3c607cb6252959e7ac267ae1a9059f9813af92df2b91d5ac842bc525589e263a1874e7622ff9f378d278da388f6f2d82d1459b117d446561b17586e9bfe651d439b64ec5ca8ba4cebb3ff17c3fb966d7559a44378ddc73a5959c5fdef3a0bc2836ecb41a43341e15cdda069a7b44d599eb0ab2e23379ccc82e11cdb9bceb98d9b38dacb70e61a1f7008799a0b8d35935aad33fbbe7bd26080428c4eaf85acbc6031671df7d681169af9dc57d11025823b90c0fe86f157f4bb21e956004aa2ab7464c9fb28235a6e6a8c4cc098167df1b19c7636de5fb9dbe47310476951a7fe1ae831eeb1b142082acc452885232831f15cca08bfd837a2cc551eaa8615306f9b4c58ccfd878cf248a947f1f6d8547ab4875dd446686e628835fed854dfb36223742607aef159b5d166d8f3b4bbe6e13d9ae1c89d7d27bb22d44212979617e6ab3fb4f6d905f161aff03bb72ac7669b2a08216e3b6a8df2e7e3a73d20a75c0bec8dac11ef559d47fb664ea53904ad9c4c77f07c3930f9d58a207949458f99bff013a472686772bb3258d94de832c2466c99b097fca1f1212b5bfcde7fdbd728c8780aec79d89d6c407aa62e62898f6161ed04cc429476b48d00d6cb1e15e75a9cc1fb3b6ba68e0e7a4fcf17a5b46fe2a82ea8cdee079a9d694c3250bbeadcfcd93ad18be3ee15f5f57921533afc5b9891203d10f9337c776e0e75f2f292803b3792b07d6023064d4c340815354ffe7d5685ba6028695b32f22be613d3340cf4eb2be7cf809f640ea6a607daac44bd1246a3a26734ab81fc7d1dac973bab288e928af9dd03f28cbf467fc23a851da317802412bb7008b018545f22f32f61286cf639b4a38c52d61d9162bcc5f74351fb353cc8d5639a67d798bb83f51bce67f71054c39296b1dce3d3489814bd716a5a52078bdb96e9172bb306a71b0c7be30c6f0744e93fc79dab890824d9172fb99116f9ed91a18a669418e3dbfa5a9f71b9b765aa9f424f444ff170adcf16cde4c7d3eb71c4020f1917f90dbeb6a554c37caf7fbc", .Okay}, + {.Lcm, "-4976827084a2e0824cb346743c39adeacbd4cfa46d81b0c76923d256b7a1d83084947bf00b769f9cb7ffa161e7e7acdc55ab9e61bbe0da0267ee50779324ce6a4b0ca630d1397d38202ca92d5e46578fb5565fbff92e1e61234960247b358c448520c222aed3e9170300744729df2deb9bc9e32e0de940c759f8b2f60244129fcc1aa030494946dec2695726293ff64d337cff1b28d826e3aeda9909d297a70d7efd4c5667429199fdfc296c51538c5ef22dff0d47854deeeed2770240a5d0ee68100eaadd97571a9a251f618ad66ccc480a283b7821550c1b534800612e3e5d78e0678fd55b49a87cef81d4aa7039c960e4290d81a4a2b76726d764e6d6e267b95af123e71695a90030500d97bfe45319afd5b8755c29b376432b6f7dc622946dca46e353e8fee241463d6d6f616fc7698fd9475e6702a4d83259aacce7dcfb3b1a7284d3cd3d2f5296a1cb5d1f5fd691071d58aa671c8c6a60b3efac390c255bda15d6ae61a8205c98548360f74e1061115885961c06b5f863958116c4c35509e8da5a18fc58caab33f7d81f137035e2d735adc27869934460aad161eeb580bebc7afa2def8f4f5e65af2bc9923ec6220092578794412f894fe93746462ace4faa7b6621b10ccdc4136b170c5ae5b2ef765efc6738fd034a5286763fc7573b493f8b5b3b4a8d991b5e7b69c4c08dd061d6fb0439d11804dd05eca75a5e447", "bed8b9e8f44615617e4683f6a28c950d0bddcb27a1899f2bca789cc0e4013ab8aa03a77e5123a4f96a27f82eaa117f7e48a61f371a6e7aeaa00f8fe182cf006840ce646d80a53fd6f3cc7e4929dbcbde8b129db290c5d05fb12d08d1447130f091d5af1d8a3fed49d0b1760413aaa8a2ada5d3d92cabadc0f8a230aed91375fd0f092b4e4b7fe39518138bc0d15da2273d6d2f373de72b664a0cfeb400252dca04eddf696ee05e9398d392aabf3ab2d986c4132d0d80607daef9bc479f97385e85f7c22792f9e873298d0a2841b73a8febb8694fecec476f5c1787d092cb0adabfb39a61724a71b39df99407ce230831fb70ca18945f2bb261d66ff30ee8686cf638be4c97a8b4559e0eac5873dde175038a82ffdab30eb551afc36569fe26a433e5c883bb6eab6aa68804b64dfb7689d4f542fd9b2421d4feb04e0604ecaf530a1d74b059b989cf79b7e12991083fe67cac47b87c86f0545945eee3a6dead7a9d09a18c4c9c671b29c5d85d84c4df297ba9c6d5497933f86aa3a0a3e4d858956ace549db2b470483c33d39fe8621cffda046a9290b32ddfca89b550ca52ef92f5cbb03b3e59955719d2aac91508170a9859347622f609dd172ac4e021ea73dd743960501aa150f691bdb7a53253d278ef1bb64c1454d5a1d93532348ecbf39ce23909efab65f3607b5c5f1af1f6a8eaa957af2b4a777259cffcd809a557f50a", "7d2e0e10229a0643c644da75955ae3a861e483e043dcf6f17f0c9f54a13a2c24ef8b3f8731629f27f4dc31ca0b398ba035eb665ee22faf210dcf6ced9ee8576407bec8fe882577e0595f00305a181525d005f006dde1d4e9e4dbc99d5a57418264f7b5239c422c7b52c8fbb87f787b8ac67a8755a3ef0750a46370fb5eb0e547081c91a5e5155e023750db5c930227037d7a681dbcdba6445662d085bebab2f710b6d9215f6c9f8323013a13c1c0050e1fdcce74e25a3154dd92da33d3fbfaf98c6b11afe2b763681344bd730ffa4e6459dc73f22e80b3563ecb3821d7f26e7278c76d3e298b75ae9e9528726a57b580752d5206b91cba77ce353c2927f2a1c73136129203808ba89388893529b81e9ddfd34a91144a31ef25c1d475a4cc48a21cf9edc9307120c632b690301b44bebfa5bff5a12844be75472998c818bd4828751dcb27dfa55a0ac0491bd429cee0ca1ef0b83637632a05ff2b81a8d773580d63962460cc133b37d7699822ff14804c331220929fc85200447683a379d3da11afca210fa49d94d0814b13b13380755a4b953ce58260e4727e0e098901899e663d5b07c563906a44ff4ed844cbfcd113e99de2bf2f3e999a6f241c9e1ad94e1c81aebbf4daa1ecc8d4112dc1f4535dd57f68179918289233ea1eaacf45dd54824b06f8097aa7d5738a67eb228088bfdf94dfeb80899f33afeb42134d0ae632569065deb203acca8c0796b310fc48b208d574f9d1e6c3309b18652de4df3f1b59cfb4709db1c18ec64fd4ab09f08e3bfe5f8ce192451636bc5c631e7b7faf86ed56905ace9fc48d5af8bdda51d0993bc7c50975cebc4146753a0641a0c00dc18b4e7ff7d44874458b0ab5d2c1f2fbf82eba33fda582e60991cd83639b599b3ab71200c4fd7a0a8d0434d629ec78d0d6b8992aee7452bd7205775d32b35addba0c0a83e29e75e019b862729ff94ff3a9982650bd171f85cf347905610740b89122057f653cc43b2ae6c88f4a488e96fe91ad28215dca97526651d16ed85dc67841c287a886cf3f17cb33e673517b62408224c8721eeb11653e17ff1db675a622c619dca0229d02326d81e4c3efb4e8ce3ca41115e1525c908a4de2fd213b36dbee12c51d8dac583c06348fb110e11c0176389591050c06b4edb2d2d669bac82c86c0d96f061aa77388d642fa6e3e3699a0185f5dc2852260f59450a9d28b40b96907e01e2ee5e1390a6b9be42c98ec9f844a4b0c7fbfeda62bef8bf618162a0d8b1036f7f7a61595ec558327374e1e7f58e6fc1250edaa9578c49c72e6098f3f9a588083c0ddf95720dc57b10a21a29add960d742b3895c88399d9f5c5cb7c742fa12fa4f61a2fe56bc6a8b507826336d2402fa2b9b1d22482592f32137b300a5cbb5757cfea1cf3dbe0cdd6a558f9c5d78c8cff5e62e69ec51e0aedf502d68a", .Okay}, + {.Lcm, "db8fed63ef540c27cbaeecd99545ab8cab1d05aa8e7101aa058c3c399d1761970bf6f81deb5aa2262f810cbfbd1ba984a92045d8c68bb7af834468805556fb565d93e5baa75bb9630b6aacf548071dca931f3676917a54068e657281ad486240c0afd2c7b5ce4f848bf44a9499eb96076108c5f12f9761b960e9ce1176cfc6e0f3b0757d37d5ed54d960b32fdd0e5ad57ecb1af13e96be91214f1fea221a42fa23443179542be1a8b6263588e77d87661c0ffc3f90d9b678fe7be1a89000e961237cce4c413db9cb4d9876010826c208d3042e776928d3be961fbe3495a438350b187374609137aae32ee2dee1f556e5148dcfa5d6fd9eee5482b4f4f5a89f219afedf7f2d76f77255a17df8529120f10e865e5b01e687d8746f261160e43c1ee3af3e4bfc7c535ef7df98159f1a045aff844c7980a5713cf0950264cc71907b45cf101b01ed0cf5d8e61093d9f777306a66e9f9db43b511dcce0cd927e48e998a19393fb25f20a7cbd89f3288bb027f25e931a32e4f544f411d96a95bc9718853b6de354a8ee705ea52ee20bc11b02f029dd8a2fdd4b3d5c373e1e70268cc3402536a7eed85ff68c6501368e4e7f99e92ed17157d6a59dcae752e74edcf5d0b1d2799196787da2a5e7e1eb45d5d8f95f68c9558c7ed03075707230a3c1a2a04ae84a57d0b877e9262aeb5deaf912c45d1d74f2b709a77dd8782a701d6cef879", "a7909cedd330ee815e222fa4ea1f64e9eb3ef34a134c1c4fd6b4df6abc64367d79210ea7377d36170089547b5ccb5c7dc75ceb1e666c81dcd1a1e3fc07b91c78781e77edc430e38b7dcdafad45b8015102ccd18d4e9eb543faef23a67df0fc02cf4eb216e65061a053d58865512fc19fc2e3774977ee4254c280d70b5bfdb6ee9ec634b7d053afdf9e22910927eb31dc43b59a6a49be18ed7066e53707fdbae784351b480a41986b68d41cda43fdcf6993bb5384535306817513d648238ebc7eb17b32bb96c2602337af778b6f1c7477889ff16b285d6b1a281057da0b9a2d2bfd08dbb3d7be55dfad126458d54863ff173daa5625ec78248356392db9acb1f7823da7a75a7247191aa074dd5d4cac818ac9a19b16f28f830cf7708b17e5fe5c7b84b154a6f0516869e7749b680157adc9dd16bf773a6b0b32604beeb8e789e934af50380f8952198aad22a8166b443a89dd8f54a8091185f8abb999a2f086ae353818239020f253cdeba362f725bfcb7dd097973699b9cc77256d447ae9e366a9d48737eaf3583a3aa2ae0c87a3a9679cb557fc54cb9915df2092783aaad2d94c3ab678d7d184c327ca77d60b0cfeaa18718c9c570dc665e4a7b1e203aeae727abb27a008c896a29d38ee296660e77f0ef33d0e55147c284748703b7b2d6cfb6e197a84fd5c769f3e036c99479dfc219f575d05ba6fe245a5133e3e3bd66f60", "8fb6eb69675fb6c5386e08a53bc5527ad57628a77b120e221aba8fb21767e3a6fef8ff04058ca7d45d11888959a19c1f0e49c8a6d416f6cebcde674299cb95e9fe49e1cb691636f78b68fbfa79362a485320d2681c06c2af544220fa7cf7b83b13cf8997449f494d5bcd1327329e870582ff1285fe0775b69c18b6f9333cb12c06394e1d90a701344385768b1a0f751da9f2cb78bc8c258b8f90d6fcab9434c4493be5b8d23b6f7a74369351a4d1ab5f66630a3ac6707a4cc670b14867b59fec6710ae05c2845c7793cded7c93d87598a079bb9aa9dabdf5cf2c40aa8fddbfdd807270d15c442ab2b12f88e92ea9f5d105cd46079ad164d468dc90e8a1a70435d437c1294491206856e2cd0197d8b18114548d2c613e00d1a65d3bfaf42685d6613f98cbf57909cf33f2f8625a73ecd6381f14fc8064c5ebed023cb70787c2e7b918b235ff58369a7d6833ee1a5234092d6edf2d8a036e5f9cc311d1eddb7ecf4b127c5580e760b229e681e7e2961f357b6eb69bd0e86ddbdd8190601cccd84ab124ea1e7b59082f78028af07272b5c48d3f070f59b8b8d002712a1be3fb616ccf7ac1b7d721f43ba92bc9ca84ba9330ebd0bbfb043b489177a228f58f6f5289c62d285b784d70fbf5f601a856f72cc1e8306d9d2d9781da254c15665fcf10b430f5363c4c51af506726adb9330bc0c56fc0e41eaa66e23e6380e64a3e8c4606be6933a9fb8e9a6342ec5b05b1dc2b0d34d7ed3cfd422f0c2d284569a6ad95fda0e5a452416cbe1597ba8c3b71fe6c4158460714daaf22a876f9eb804165310fa44351995ba7877f20fa712496cb05fb00488641e5201c736b531fe02bc5261166b7a100faa42e7364b4470645e170793a03be7a3361309f0e9166dc499aca23815a15b986ce24411b39ee28e3c24d67326e0d230fb2a883228d913d15d264f1945cb3051814e37148b0e1ab6f3cfc2bb67dc004af1f17cba91e541be952c1a676690e384a38265004be668f0b0d00066c9480a7424bb88b0ac8d651f47e7b99ffb9462033616433344feae175bbaf45b9fec775b222201b68018e4ef966114fb3acc3acb44fb9ed0de978a3cee16def550f4abb1cdafd89d2adf4f89f4a6d3ed9b6fc2eba023847756ae703667ed29709a38cf792b26e8171d750e958f729061151527e0603172f5f59c0f794a46ce5521a4b0ed9081f10e2c2a74ac67646d79b338e34052de47bc4e724e2e8b6fe761ebeabfe7f8e2f1651fea07e35bb09207cd95b76783c23b8b71b83e04c4dac5d9a8a6c47c2067fe8deec91ab37135caf0fcb73bd186779fe65f0b2363accc8a6fa3a288609dee5a6203e00263cf8b5db1f5e45abe8f826c87f208b4bc7c53921f84891c6a5d2608162e4d90bb4124e73863ff3622ff5fcec2bc4bea4bf2fb39331812a70c3986b2113bc2c69e37fa460", .Okay}, + {.Lcm, "-872a5e6c41332bf63fd05e5f8ff1d7547f50de0a1eba4a0bea5b52f641194b56f823f190562cc7834fce2ca566d9f57375dd4b8b014923acc2526ad3e8dff680119bf06a9bcf8b7b9a3e82aaa7d59d315a713e931399783de10984d4be62053f119f5e1f87a7f21b3860d6a7fc01073fbcc324ca3f1271865b50a77bd393695560c84cb768bb7f04b9871a3797494d70524e43a052bf2671878edf1643c04cb181173b302a9ed7ed72074d3d3c9dddcbb38b92bad5ca3e855fbff0d0178c3c1e47cdb8a55d80c4d1fe80bb54a8ef1003452ec4a6d4dea6fae71c7414f054b7cb431b35d07e32cf9bde0aa252bcb66435ba2a7f7a87ac33afc9b1799e055f00c21bc43de327f9d834dc7c454d84b4f55391de314d0c3e8e8a49e0f0577e7d14802228634f6f0dff59c2e6764d6c403e79011947c12ee90eb6a3aa4442d8ec07d654fda4b7979e8fee60fa278b07340c33de4095b39310783aff115a28bd1e526ff1cdc41bee1330381f2d29a304a290fc95a520063796c46cc9cbe5cae0f3b24c1ab0ccb59f6f3539a0b72957d182e4f57017754e27d5e2225e743b156aa63f4612a56a28a7af633faf522523955707628484e71a941cb917e8131fa2cd08c414567baaf0e167204868cbbcc51344fab813c5ef534e1eab670879cc4bd76f9a89c0c85e958aca8a44601f5f0771e8fe1de55102b9da79de1477bc462c570eedd7", "7c61c7d0ace69643309cb4b9afbe1094e3d5c1a24a5ddc73a5f2cb3adca2ac00bd6a834f0bd502225dfd53839a1dfec64770d89f6b5b696813b80c3de6d7dda9b3013266b8d7df09e95abe8540e86e9a5a4137d67c41df76848da0d8d8d359588485036505b05fb9c6cb71e8ab4c00ff7238862d40fbf24f6357df4e129678c4fcb57c4a00684fb2671f41f84e673723551555a6e98f10583695e80604354b3ec61f991a2f42d11f7d227b2d51b1c7eb08b384c2bb9aaae417724166ca9b1adb3fe5c07728d71ae1b9a0dc482b6476a3eac548f398e413f8a62003947c74ad64a1dcd6e33820ed0ea140c60f00d8efd5f3a58b792af2a39370481d2e497924c1e40a29cf5e658f1bcb54d3ec2aba2a0cda7bfc4f4cf6576629deaf74b5d21d10dd4478b386ed866fd6b199349b12a607c6769d0485e6323a0e13206963b1e64d9016a783147e52b8646e1f16d81198afe2927f8e550545dfc30c9a49f91833ce58e105edb8776fa45a0ee9a4636168ecc9e22d6a62e9417f1fb86654f3e81559f681b82c379cc5b18c061f65cb297cd21930ebc8a9352a6a0e9c56cc07cc9ddc2c3484306b4f3a41f8d169619315618f738cc6483df842d33d8109e18d3609808d94c457f88864094937ae39524d4ab86a8a2a9c5c7422bc4b4a8c2735b3cc5374cc539ee7f3d97687eb9aca3f80003baf096dacf1e53b8dc58f5e8179be0af8", "41ac264a53b6932a8e1d085687d9c32ca77c948509f796f0d8247b01ae7eb43762c05e77ee6478f4c5da8fbb6a9448235fab7e79eeba22ac33c07d870798dce32ae05640cabfaf97ce5854f7897d64419dfe5fce97111eb0ac59c4a871f5fd75760b6332bfcb601d5e0ad0e92053e835fa337f96742afec7f798fc3fc8b8ed14a4e62b7bfe068f2340e62cc2bd518601bb6418416e1ee33655bf5a20401640e8e79ce423e4bc9d8f9b019011efff8629cd6d38a6ca5b8776e35bb13019aee03a95691fe3ff6b81a590a91d93a282efebbf6d5c970b14a085cbd925574b9759069cffe45fd87df94195ba1eea5203a5a95157a9d421555b5d5f2b3a304366c37b42da52126ae90a60f5992b45011f106077eeb7fcf88b978b88cbe9f33ab068fdffbeb4b87b1c1c3f59e9f5f4331f504220ffae3ee0b8baffa18e0a0de155f0788c785c716f1a56ef5522647b4d866347fd9c5e61699fc8b96223d1c63aa50ef1ffd7f9586326debaa6f07d2b80df224f1afb3bd4f7f1d6a9ded25100b847fff8ce7b29768f368547e4c012fa33d659b7dc9aa18423bb53cfeb028ea982da7893f1e9515f700c1b94d79fe85e3ccef6b15f4d3bb848bd92e38fbb8edf136581e222bbd2d03ae165b24c979a7930900b28cf5c477c5cfc9af386e2af8546a3539a3ae1f5dc29b8ce9737bbfac63955d30583a2d9e0565a52b845511d986d166ec8c933e5c3b41eacafe360071cb9f92e81a7ef400cc41d58f7713a10b06cbc2105ef81991d5048a011d7b0f694a469d16399b21f79aa9f32fac2dae3249485c965c4e743533f5ed2ab27e12516ac79dc531c8c4249fbb024942319082b246ddc220fc0e957111088a3f755b34d5d3c94ba53a33e9fb86dbcb5ce6949d53e42bfc188d851b9e7fbb1815e048e7707e85ef36b95f9edc7c44260be29c80dc751f2896fcb8d91847fd5ba6d35b7acc5845969d6f31d00d2f6c6768483cb23e74569de3ffd4e57abed818536b5befaf22e1a47986405a8c1f1ce915fc8401835453b1b55f6bd04077ff96823077c12a49b3091b849a03e9f2644146c3a1d955a3de2e2a84c95eb4d704f8396f129d7e25ea19a7eb7bca06ab2461d938abaaf88c22f94c3bdb8cd1dd7bc4a5f63b42e2591c5cd842de1f1523b7fb3810cf189e8a783788fc4268f5ad531c72e798f6872d091eaa763cb678835877254ec268553bffb25acd7cae90e5f9a6403c3ae500fa35963d782c3338d36654f794c92b87872c221f9c219479678929d9d7b1b0905dcc5e849446ce5d3debd54ec76132e6ffd068081744cc06806183075a3852dbba3f24e439d364450013c2c087c5cb96a48fb537c412747ed0fe4ec2ed5b30c213185fdad80f9e10d9c33de3f906bc91114050d27a029f3310a9f8520bc324ba7b2c20bdca9fba43e481a800b242d311052ce48", .Okay}, + {.Lcm, "6209658fd4703f6add8d3f0faa8df72e5f6d42e65b9a42612102122a033d87bca93764974f2659ef71763fa44194ac5ee4713947158abe1e2dbc94ba44c80601479bca60932d983ad3c8edbacf105fdba21b1b8176075449697a7ba2820a75f8eab657e79335f884343eb404aeacbfeb0578e85c24652f2966a1925b7f338b13d150ceb0de41a0bca9f11b573c5b010c4045b59e097a02128d7ed77887deb7008ab5a21c2851fec4bcc591b77e7641f73356a7e66763db28ca643891d47ddb78326e6d4e716e1869b500af322c4a60fffa8f1d1b8c3fbf6aaefa0f817b19bea3850f98645ed710b3d32452e50df34fea4e893fa1537447ffabb63b20e9efd75bcc499cf9bb6f2716bd69c3a510548a535b1a2cd20bf8c0bd333e7aabb45a7b669f797f172c5a826a4711d67a928a7230645834760f73b49f2e82ebe05ffa6d795ca96264e3df8a54a1b579ed2513cc139215e120d653d96db106e73c37feb7b1559bf84c7c4fb8d5c3b98bd44df0befa1a664f6a6e2c2d32ba144ff03e3187260c3695bb86c82305c1a9d355572ea72121933628052492cf4ad1060fd50e307cba5569492034175eaa5e7201b1a68fe8ae4bc991d8844bb77597bb7f2c24fe59da96a713775b59c4740f3034b26236dc37f41dff70cefc8b6552317737398d55e08e6996193ea57a02e0cc9a94099ff27cbfccf34644639b5d2d20e9a55d26f8", "3d10fe5ceed2cc097c974eb4656237a88a256eef26838b15541e3387615b83db21c2250832313acb6c4a9dbb3e160976a82a4897006e024cdec7259bd57c12419cb8f5715e05dce5e98856c73709bce1adc9ff9e707af657150e9d5bb8589c8351b44cdb7133d5d737707dfbf4f52016e1cd37b2ee5c645a1266d6bd45bd0902334947de07ce702560fd6c7081d6773626ede4cd407dc4c5ae14a5d1540f5888d097c1eb047ba6d9c199d6973a6daedc4a5461819629741310606caf19f2d23d8ad713ad183d9bf3e02d41a2fca1c084a3b2403374921b9a6dbc6c0df670ecdfd376bb11e0cacd68c2b48d3cb49dfd395fdf841e5cefe0fcc972ac7d43c293424feea7ec36d0ea2cd802c38bd4eb47459f12b2ec5e903fe1b6d1488fd0a65c4034b73f41f7a52a83bd4e642fbb55ecbed657ab9358506138b465503183f938a252c9fc15fd4651e14e113a9581e24bece9bf9e7074779075bbf7d7e7208de1b96af6b1439ddb543d930ac4c425405915d00217ba00286e87b4e7c98c3ec52aefcbd17dde2a96e0adeea4cf1e5cb2d59aff5dcd3443307f3fc61ffb1cdfb62e950c31a3aa1d763eefe0cfb2e3eaea13d62290a484d394a1509bd2803172be5194e553147aca97771faf872090a43c991d9acce8c82cc7e6c8b40c9f6a16f3e358cf72cdab6f945098bc699e2da1549acd837872180b6a69f80c87c3724045c85", "1762bf328836b0dc4b31a0563f2e5e3036e53df22d0ac7df26ee2d5153627ecf3ff35381ef7c8df3b7c49792da33e34247fbfbd7c084c0a46582436061fdbf81213ff9952e08ec354c6121ac54a2dd3919dad110fa40ada27e33ad0f122f1e5440f2a4b1dd63ade41fd5376012171a38fb20da4d03381d7463f06ff9eb5aca7d0b17a9a78a57896e7b7977ccd927039bc0e882f2c4fc9d9dbe0fb96d31a3f173be81024687421a4523ced3b819a4d02e43b3b4078fe0a8ddc6651eea3e739e1476dbd604f92e57975d90812fc5fdeb4cad76d4b8b90194d3db61237179a6cedb76b8c5557dd959068fb1be334204c09b456cf67c15b355a6f1ced956c14bb6c4dbc0fb5f35265e2b06ede60ab7360e8a66c2d896b0c5892f7fb2ef189c25284778530ffa1407c68b67dbbbec021a25b7d561b1757586eab2f9e51e3493fc832fc8b8882d5224c53e543bda56c4e935db18a94f1408cd20795ccbba4c3309adede3a0bb83567d7a0240d1ad1c32b1b9c5860075a0d1dd12eff381b2ce57e44aea5162b7279844ce1571cf8b456a3aebe625e67ed4d2fe222b56710a26c626d8cf25329eed9029d8e77c78495787c254f492b19c4900a4bcb5865949a15f0c03a7a5dba9c24a18f499e5ffcedf596c5defbe78e37703b7209fb5793062aafdd21c735e2fb0dbc25605af27f1810050b7ee39503c7b4aa8ad626cc22dabb1782f60be8cddb2d70dcc3fed26ef93ce9512bad21f748ae4ae04a98f3e12054ef1863c9068f19d678e87063f5a098df73d80ef3b1ac32f86883a7ae0cb683fe932375e91f7c411acd56d00ca1797fcd05b1623f6000bec88a2e58b36cdcb49bc8f5bfda60edce9900be117afb64eb0856277de5610aa91eebd231211f075892635fd8d4188ab750035dff2e33f8d14c40b889bc93c38524692bffaa3b9620c942f76342f9d751d057c274d792c19a85db6d7e94bac8573310126aa535d8e7ac70e84cdbc96b696c4d20c58c15533c5c138d5c672a6c5bd7bafa09b02538a7103716842203543f98fcdce65e5fd49fa955dde7eb2762b40fce8930866baec5cae6262329833f16a680f47e15364cf98046a712426f93b09c0a7121abbd6c6b3e369bfe2813551e26bedfee8314e5087b4bd59f41c853725be063056b51bd522565007873459c99822f17c450f8f0dcdac44ba4add2d4cb3aa4af1150e601351cf69cc900be6ad1561f26eadffc56a13a74d06f1877c4cb1d153ed4911d94c4d6b2a263d9c2bb73963db01aba797b13cbf53a59ea2ddc7d143ca82605cce824cb5dd023cc0b43df1311dbb134f6032332c89346c310af422846d903dee14b8313e19d3173221dd74fe920fb8bff3a37f3283d72f523b27295443807b789958365c34b9c7ab23ca68bc7234e4864009afb8804754ae385f6b726691f16d13f07df465ed8", .Okay}, + {.Lcm, "-9f14537efb0ead5860015222804e8ad847f914145427796ccbeb3388e0b8162f160d6406ead2877e8ef8537ec749295df77c8e813f358153e122488b789230c5f92e7b026c1f1046115cf69d5e157a4a1bf9445831bed844124abc554372f5ed220f6994fce34a33d7ab947011ac7d45a2f3ee5a15c9152394533f84388d991d776c3db506f1e186e0b35a2343f5e31db68a36ed12b6b022e4e17bdb4ca0cde456ce25e6642457dc42c2b594a0157497c47b6b48a543652a96c3a8dc12f84100ef4d23aa5668217613d3f87213ecc307fecbcc58525a17ef38f8983de6129b7c04380d409d77534dff9565f76d4da121071b143ef5e500dd7a0f638b81dabb88d249cdbc53ed96aa126e96e77cf8d497655a088b8e08bd8ba0734a13937d40d702ff97c3e6b6d0463acd815febb6ff2caca8f82a404ea732952568702a8d041d0ebd38017974319bc8fcb4b4c0e14da5ee3084a3260accc9c3b51c05fb368638fe7330a998150b8b883be83dc3e8ca9b325438d80786b76b28dc51c08afefd9bfd7ea7a1329c278bdb1335f5578c67fc1aea0a9a49df0c7599ead948e2d70bacca270d76264edf19dee7e6b29f7971786e0603f88aaa45ba20a4996a425410327e6c9456ccbf167c27e069e2b131890355d32946cdbc047ceef801b9962cd026c18cfc989d126e32f98222c5c4d0fe5350e408227e0f23d805c362121054c4dd", "-3d7261af2a833ef23fea23b9ecef305edc0cc3c06718207222cf5fa3b59935dbfbe0a9de33da25c65bffe9ce4ce796be6c4f36cd3ef4adce1ad168ebb96651cc2c2ba37bf204712d943f1b1f151f69ba549b6f6fc1882f1af4b5e28a9839c7bb282e958c487aedd81e6bb78a6e9d6f5fe3241a859689caf86ae83e9b47ca50c12a6ef85ebd53483c9843bfc97c6e0627f9293b429559ee1bb86d2378f1e1190d36ed7c668e6de5c26de4caffe60882c548ecd703c79551683080a0b5cbb0b0baf2d6497924faf202f779f2fdce54b3ad716794c41a27d6d9f4169aab54241ebf2a7f8991ff4a27c3a112a06991d4b7e85d676f620e090253e8d919ba33ae670f8c676248f04cf34c59cfde8e41d7077041db7077acb7ea256583801f2efe8d44abc256a49ced360354bb7da833ac5c46540788be04d3b2d6cf106002432159bc9acad5e5f33790b7b2f507f047abd1977c372afe9fd2f00e18ddce92405e3891ae64f1a105db3bda2126d8ce49cc24ad94583065dc2dc8bb7ded5fbc0ac00adb3c2289f48958008f7bb342d13bf6970baa987d55abbf9e98022467cfeccfecba01af72aba2d67e714f38140d3266a0639591a04683095f64d68f958fe42a78fcdc6765dd98fe03ed4f612985de01beafa5691c6677b252582bfe64ca5f319cc6bd1767ff2655715465b9c12f17d4a4e8e67817611eb4d12c81881cc5f37c640e", "262eeba5fd5160fc73441c10e4fad960002c0571a826488ef6d15b3d0d2e59d6569496d16004c4b990f1aaa17fd60508d87143929f7d6713d3878a9de898439dee02905af3cbe53f7939113e17f31142218d3dc4e87ab35c37bcf87e6635a6643581aade6e9c86da6716b44356d0d96c78c10b7d1b812be7eebfe273bacd636d0ca82cc3902c067fbb5e956c169da117493662d9451ab23c1c7a86aae94d017320cc7f687430d97a89e4396561a336ed10c91ac211a6879135ecce242a9335cbc116d860d8238bce06c607e5fc65fbc8524fc4f687fd7ca40853ef26372c3a6fcab2e0fdb0dcf722a1e87f7b87c0cfbd6917823fcb1b90e5c5a2e9e86a4dbbb3868bc37e68fa570bd44d90cb19ae4aba532b60b27762b52c78035de9eabc8e3ea1351d9dac3469521fc027cf662c64aeab7465e3d320f795f9fe1c99f99de7f0b27a4eb056a1d83e4fad2270ff7b051d4d9971a22fc8548359f1fd34b8a7aa8b60228b088c1b7222bcd2fd9f344c049df8a1f51323ce859b28ce651a53ed10209d9f934c39b6e604dddaffc2215aac4c456b9fad86d7159a4ccd093d7908de40de3d22c5ced4793f04578cd4c196713c8e0dd332020bb65cc5d2729a1d5576a6eda839ace993936dabfac6e54be5503ddc429d791b92427adea0a1cef363cfc0ebd9874ff4d1b8a92f6e9e36e62a6a5aeca8d5e56119f71ad85404cb63fb73dcc77ccf339121663382d406f1d7840f2ac5dd74b0fd931e728500c65333ef056a47bf62c95bbd7038ca00f1706ccc5e2f4f687dec1f86bf74f4aa4fbb0aab3fdd36cf0c76684aaa9b8f23c5eff201bb57f5a4640f9178a6dd65177b9195c931c5722bfd09848bad0027d1dc50c4736e2ad051279049ba9ac6a4efc82f14cdf9d9f10e8fb4f62582c6eaa52c62f1a41e7dade20205fa242d3c5ff4d4607d63e1baad24e716e114d1439da4d2297d5cf131cc8569605e9af80a027f3062ff578053e4ae50f46d399601e7e9885c2972a5f2f3944dba968e3b1c241af9f9d1aad425a20fc0d14d70c287c542da9dcfc2a3df3241c5e39e95779ed768a71a7ea518ba5daa9962818e9bd389130f7917ef50d62283455d4977fc30dd9025c52860da2768c5de4c85782c05521622f468479438665953a9ec2719141fb30d53cdb3d7a5081a4c092a9f9c50c8ca5c058833a07bfb392138057b331402da15218e7950a2d695229c37672fa6135c3f2243e276ae3299ee352a65e20f96bf889335943fa1f34c63b0b0ebd21ef0a3724792be7298e7fd02d956a56865b6b8d9a9d58f491709377c790e5e2a72b6efb4b00f7f05a2374fd3fbff23c0057761669294b90e5379ce26f1f34ac6c44e50df4cf0ee3f30762ee2ea4ac492e33b445d7398fcfc7fad598c2c3b6f00aee33e1d97097ec5aaf3e98b6a8f85b1b3126a755c23951816", .Okay}, + {.Lcm, "53e4abe7d891af0c9737f71113f120740b2c0dfedf6171fdab07c4eac1ef1bfd82876f2ea5af49d38c3bd49011f46875869ea2c608c76afc1b9b17f107b7249307f75bf8f4d58433ad6ffd797df220d9ec7dca464328dce0b5b27e61c10cc77402ccf5c4cbf74a35c6e754e9040125299ccb2ed39c51a7a5fe0efb8add48b582850ce41831646250f59e1036ca7c06d70ae0ce9e5af974a00ed904ea20b3d9f7ef5e65d32dea7281d9283581ec7055139eeb04791eeba205a10fa66eb6bc5254b951965e4ad81ad7d2c5f34d893c8f4dc104b92a13926daf7fe19468b368226108fc65fd94f1b2cfb35a78b5f1fbee292e615f828dae82a69ae1b53a488ee3e60fb92605e3ed174a3fd24dcf946f5e6b92917f0ad0956d96e89f40054ed1d2faa24ae6e1d4269a539eabfa13a06d97247edded4c4d27fe7109bd2ead2c3b3ff18c15a88dfd3515084757658a38c1153c04bdd9d9d6f285efce76740d7cc79e483501c4d748f1a07d408200149dcec59cd15fd4bb37d0287d95b020aa329f294f681ab2c49472289007d8edef866d488d2df3235540dfc33ec5a715c9cdd1d9a14fb0b706843d6a90fc8127bcf150af7638a3c940766a7c781615f7049b475eb1b0e721773b1e1b8966b1e1fb38997d9e80ab626ae7f919e5e352fc81ab24d4025c3c93c92124b2f72f4991c14f101d7d3a773be63e5920a72965877919a853b6", "-74a50b45dd48d3f405d431beaf75b768e2c067999ede666703de5a3e056a6360a4ed659e218889db88ba663b024b87acac49fe398df2c7349dc14e2ecae634a49987ace05bcc549e557f0bda83dd46cfa86380d10021932db71e2525015352303e3944e0abce6a763aac9b7b12e9d54b6e24fa4a64fc7585a6f62923cae26863f462103363fcefb1d92521f75e73aba2794f6d9c1ff7d6703fae52f15eaca40f473b75346ed49c522765c7abc060521e17676b39ddb86b61afde88c1bd6c03cddae26d4fc0ab5767fe2cfe8d4cfd7642e026b2ad7366efce4dbdfcf11df4f6a1f9e4a979cd36cb5b5d1e180267e952b686a08433a5318b2442ffcee414410e5c39a31dbcd2f8c2bffc75dc1c8390cecd9abc96a4cd86e8700859916fbba24c0bbf50361414f05249249186681444472cf2e8ad0641a97a936c65513717d6da4d53977e6ee7d2b7be59ee84caf17a1af7c32cdfb7f4f146d0015c71611379f8623046a1678ff723f0d2d656bfd81b75b1b5acf71b31d1ffa243e76b76f9a20643264424511eb02e7be93f64832a974b1e377547d84d019c1540d4f770383d92732fb49cf6ef76bd981ab22d02b7665ad8808d55d53d5cd5ea07c21e3de7876cfc104d7fee966d39ac5f8210fb8120ad360669321e345a6cc93163afd3e083b0c2067f979811d5249accfb247695a1ee5122e2ed5810438ad5b20b4817f55fa789", "2639b3f9931a2b301a242a82e24f8df67158f0f6089806fc5867fcb27341ed587324d3fbf1045ae4116496079bf41b83ce96bdb9a823cc92be89db83cd26c925a0f07510c33babec04960ec15bfbc1087d7aa74cabdd7a8a756974c0228b5ceaeb0004d88c5613c58340db419535c6e36110d6de47c6c0b34325fd6359ce74e163c3fd540d43e8abc5d9c3b670f28eaf12bc3185ab30f0261778978dc9681eec19af69a110df36f4ae6512081e897f214ef5b4891f44edb08c76285a1a2b9541d124124347cb53c6678419d58673adcb1742198dadce0f45f295ed81e031b20f4cead8d84775bb1e03cd520d543fc0d9af6ae669513e966d8aee4b700b6c61f0ecc60ddb00aebe8211c60e40a801d3966ccd2101da7f424155d4689a202ef274c3ae1f7c80e6d7e24971513a64b0fb383e8d3812aac13efaef11ddb411084639ef3e11431dc1870d66e056332ba9e0a46b7fcb1a249f5f37f07f76112c1781c7b717ec30de3b5fac1847eb69cac5c629bd92755d0cee4bf76dd4efadb4dc4ee6e278638e61c08033a13ac03e1233f7b61289a73245dda94dbbe2f0e489addbb8108c3d0f8f96857944857ebe64448753a99ebb5e8beca5dc4a9d0ad6bf020a68d87bb3eb4b5dee3b8ab9598f2b42bd14e9aaf8a2ee28d002eca8bcdd9944cf642c1814a2b304ec293ec56aa4496c71dab29dd30e6abada11e37be4232226a8b34dd0ab68130c395b593cacc1319d215eb9ac370463443c8a2975d58d0daa1a8cada56eceedcbd59b8ec02abf47dc3ba5959fe2be28cdc70cf08aeff0af2779ceadc4df153f2088c946c484168be3988aa63ea90a813b7678f2f8bf11e454de5025c4a27d32459d863dc2d0b160c7118611a47d907a5b38c61ad346544a6d4b76efcb9c3400195ce950f7930c930e43289d4eb8c31a1402be355b96b5411a75686d3942a18426506994515a1acc3f970dff1aaaa55379014c1861d7b6a4ee187f45c282237569445f5a9bd7f40282ebd7517d971f60a8abc0f2168ce44596b59c81888af74cd62cc0f10f017bc9ae7cbf77ea062409ff69173f61d637ef07b796afca945b148ac1d02527fcff547dc9f6fdcfc8e18c63efb3ecbfdada382c5f1f3b7491154101a0da14bd17dd9568870621ed46c3bef77ea3060396a1d52d8f4a262b3dfcd8ab1c879018676d0a3e50d7371c7fa22dfcc162d90ed87105d0ded09e9f048c992bc9964fb8b52ad70095e4afe0a299dd17ea4341bd8bec0e492d72fad77575334964185dc7c0e0b734a130ca0c27b9865b225732de59ed43e3a37195bbb233655ab06ffbea2d1572ec44b89eb9a227debeedc298d1954f9f72580775c39511df54759cf49a6628a11b8e2b81ac46c5fdeb425084e3d455db299e78d70d73742b3e0d021a30be4c125de79bdffc82df45ba2ec158b0d279c83a8666", .Okay}, + {.Lcm, "-c0cfc94355f0663429c1cc4f88dc002759751c21b5cfd4717a2874d614f9f97a49545b78d24c14c51d831fc3e78bb0337b5062ec5aa7d28725271d5f9763997a505339f84ffda50c4c2a9dfdc26e12f18e066188a164c85f917fb884ff63ffe6857a54d341ca404661667b0106c5e40f0d82d8249b23a5c16ee671777b632f97048676155358752601031e7dfd29f9570ef4fb1eb2ab8b06d55d8d6b90102522a568fcf129ff98c97e2d973f72bf02a9d2729ca9baba3573ff4ce55a4651fa9eda904ce9e1cd630db9e0699b207b8342500e1d9fdb9decd4db67d5bbb0cd36c70ca663f2483c69611f9999e85211ac60d14230d67a2f9748883963518182bf3701390e35037a114b4b79ca1b5013d0efd6384478fe23daf5cab31f1e386bb04c4c95ca2bdca3d0a8e4e1c22debd02bdd7b32097626b46bee1bc1b7324bbb7d4ae17213cb31d7adca40e2540c8fb7ea36f7bda892800e1680811be5ac84493b0ba1282248c1b81239118c83f9fd80826428a60155f969600d2b0bdba9f3636017b82425c64176a76589548d75c126da449b88e2b646580853dffdd45038c5e83161f6be7a728721c696ca7453c6e7eacfa8381f118fae2d686e1cecdb58546274dae5999b5ceaf08ef7795d070c3f21ba0f7f8ac647dafac2f34cb639e930fe96d78afcd11e281480725c9eccba45aeb883e8ce8ede44ea34d2e331620d9366df", "-1f87c011909fbcbd247e56be89092eca8d47b9ad3bfc46e5162c6f5c03788f032447cee072feed38899b63036e7d2a0531e1cbcaff22961aaabcf4189d14b6cb56200672968f9108d5cfc4696ffa53804473d4edbea75e9baae14ab91e3eeb8880736faea97862b5a493e6121b9b524f5948d2adf0a73c8122617c244a7be466e7542b83dc1f132b2c6744d8a06351bc4e32898d91bf4d5c5c27b3fdba3c054df09053b14ef0d62efb72cd92478e16d3afd0a4e41d38ab7563e617e7361d66786f2425e9d4b155d82fdfc7fee3d846f7aa41acea6634b039fc1ebc142ece7127823b09aad987dd1b43bbfee46ff56d5c5643e24e73aa81e9e3ab7d4398ad4f6e9d6d9c18500f079034eb29024d97d7cc2604b7072b507c743d338a25de605139c092c370b737dbd6caad297ab4ebea5e71f3abbd06a02f66902e0660220da899fd70393066793e7a740f5e17c4ec60b84b3524700655922ac93dc95a512bb11e33900e3130f673923b17444e64e2d1c96b8d4caba084cc77e1b932f4dfd7bdb8e68e978bdddff1d11226e4fe315edd2b2714f8e72b384463580a3c6c793b7f23f863c022c9b1f05b6bea216e6f1c089ba68b769fd0ee7689794e53c3bbd7dd39674c6daf163615ecffaea2662627c03e644d3436f5bbbbb484899daa3ce8549b62cde611ae4732758047783985289c21320283acd4e3a623db066df58ab77e09", "17bf679b5b967c7e26096940244ef438e6ff1bba6b1c4d3eae84a0294852b498c725191d43450e97eefff0a0d4d313369d40e3db709e4730418c25519072d693bb0c9347f0d5ef237412c68ec0d294cf3f233c19fbdb34b6c2812657395c5cd55a687641f07a1793be35a4a93895d5bb968df2c141667c9aae15011bee534b9b0e72e01e872fe09e18f70bf0a9b11539da4593d6f04fe5c1be740988e9596c107d69a78863750da84ab8c132026024c943aa3d21295b6b37121dd26a3de7513cda28eff2e468fdef9f93a5f03d4579763a81afc638b53a73c67f65866e2146094c93d1a677f36d06daef54c9e8faa9dcd14887e6982699ed872a1726b93408f16099d4f5fa671d71cb692a90ad5e9f1de80920c55366f1e132319c26010a1e3310d8eca4e96bf8f4c09688305a4783780b0f07375dacb72cac4bdefdc3e6e8c92d62cb468ea327ec6c5286b153d796c99c9df0e2b4d00c381eab8da34b26be8e5442482d65f519122b9c25e5be72339e4cfc2605cbcd83f2c17efe75876368de91b24995f7bef59ad44f3109b95d6dcd2d733415b56820ac42e639276a5f5d92555c37b39f74831477a37a7cf3250c6c3e2d96178f464573a300a8f21c5c8ca6d7de1ed9765ae35168b6f43c9d15ed2113bc7acfe4ee288d605a7e27e65890a9d77f6ca00ae0d158e5ad8a235a8b3f54fe3513e6d4276d8dd0378f5761375050808313bdab8e99448f9dbe9e7e15329dc0817d46d3151bd9470df66efa5dfe438e2f13dfbc34f762b7e6adf7db03db08d14e3236f41f45ec02aadd4a6a197c82fcbe1db7972677015a28fdce41695e7f26a61c031dd089198b1c7a7cced9ef1c95f9bea0ee6c14a32aff816a2c896e6eee1287f2d3b22a907a7c7191a241244cfe3c185a01a00de4ca6201111bb6286713214dfa9bf3a2730750073bba2ecd86e6f2f07520e432c13e93f2d45418c10cbaadbc4c91ebf2065b8bb22eda613f5056fb3146e93273a4095e5e2715a3a4894875fec8af81c1cd56a1ad3e9f6470a8d88f5a7b9c8ad13da6dd97ee338e6f1d79e931a5dc7e57dd7267d01bac2e6413618cba08401e89e31f35d2d3df838059e06a12e05eb96f1ed678177a27fbce2f6488e4a0d88785bfe6da6f00f7d9c3da8c3b6e5c013095bca165a0d8b0da9d7320d27260385cfa054e4775de74ff7054bfa00ef95e09b7d3771ed6986661d60b7368a07575967e1faeeb81853a91dbd6b001efc891813452b5c17f655e12259ca4f74df25c8adad15fba5f4ff739a45e6704bb07c6e90222e34ad5d020467490a94fc191827124d3e2215dbe793856f7075eb889bfd9baa79fb27deb9bf7bddef1fe3efe915d06d61a6f69174aeca9a94c57f0832c6f10440566fdb60efae27eb070ec200a217b200456cc601e553ea7aece37c88e1a8c3f53cc8f5ec6395fd7", .Okay}, + {.Lcm, "-14a3b7e8a53e5527f391addaf37fd05a381a08b083741d81973423829d939a08a9474932e076ac7060d08d45f9b6fc21d30a1c114c8fcfca9073b4a92e992292f8ac7ba5f86a42625f0b63c42c6b6985cc115dbeba8ba30f728464bf0fdd1b6637c2916708149a3bd9fc602fa40da8cfe2263b5bc374f448b9b364142fa56bea85a8d5d4f67bec117739096948e928b61d2f710e6a2cf7b707a3533d206648fb5ba88810f2ff503b22437f2dfd2f584321fb432074530f1a797b5d663a605c04f62329095a41fb16abb7e8161c75207ea3bc31ae0a1c6ae4bdd9d87a3c86964ec406bd97825faa71fec2926e903aafca9b4b8dbe2a116bea26977efef7fe772ad460094c3a1c4a967b930000648fa3099930a8250b982183891368e63e839216b25a9f8608192ead2e15663517edc183a0209b6d6033f05201977bfa69cf7a1198325b4d8e1a0102bcbaf1d6d5c8979806bafc101662ad8a17362f9f2b1059f2f08fdf32c25700775d9ef4b0815cb74e3b683d53c3019893f7a9189b6c2b1621bd391abde765fc2e25b75a80de49942d77a993988ae23bcdaf9f086f5d90f67af78a6b724dbe4116edc3af4e5e801c42bfea49c0792d5c6c00b9658da4d235d2fe384da01039ca8a16c343be6045f46c7713e20f8a0236f2010b5d7d06439b79d447532524ebc41a8e42ee1e4f8b2a181d79380b64437482264d6c106a2070f0", "6e24e53a696cb0b80de1d2fddb2e58a4d985e37212486d398af639f315c82757527da10ec82b9077ea64c67bfd7db8fb686c90e127e91b3f1372a450d358b9e4611477da49d9848f66321ce541e3fd2e57e9a583147d4056af2f5c28991dbe960412852e63291aa683ab2ab7e8d93ad3a9770696c49b5b6f1af10d438430bf3a43827c72df9a9653890ed87d2e7cca169a95eb159e7398035c08e8cef5d56b93a8df3ff19a894fd0ce09f42aea75eda618394d7769de7cb391683b13a54712692623ad9ffe896dec0da2a22691d4909cc98881be80a6d5c867a6e1899a351bc5d2d5bbb606dc036e896ebd6a1fc1b2e7c8699259da94463a19869b1ad2a56aa78429cc6bb81d776252514730f5278ff84fbeec7ff934383e5173c70b87e2011d6a15ba9aae24b682660db5e50b16a6eddc1b48b6f184e99088c960cb0c4c138da11316adb4437d4f3ccea003452267b63298d8c9ddddec3eaaf10299928dcfa0f9ab58f263b08827a1e617c73d8f3015da4fa3ddcdd31b96efb8793fa5afbb00a5a6fedc369bb0e6d388faed036de7b7a49e1f80c29e4751808531b46d840e806a41b1b1493231ae70ae0f454d5f09dc1fd66d209967399f5ec122e0b6727e4a5399e205ec335689a2cbbe89949201d44841777f5b05d521cb1893488739444fb2fd1737a3bafe2e8ca559cf01ad7598c44663b1e63f3867876a0881b7abcf4c", "23854a1bf34ad682f6e739a0b8f9815389619a0382c0cd30124a5366d7943bf8d3783c594c813fe755f2c12faa55ef3bf7fbdadc24ea99d5f0cea201d55c0d98a136e568c1b95678bce04955f40b8834d2aae362a15ffcbcf476405d8975af0e65a4db0625d3c85ae35ff2fb7d9c33b0d235450de5cc4294850514ae5872a0f8ae6444bb1460c41cc4427797d30da5c660d878fbfa0c84226056cd82cf2be9e686a63761eec1b62427cb4976404535785c67c693bd3b00ca64b166d19a55b7110970830a40b879521c22798d9f1da1a1d207fd79ad7847a9dc100f565774d02d2c526d159439bf55037d52ea8ef02218b91fcc5361081743c075c1fcd98b2bceb81d58d29f0892946b23cfbfcff4c869be5ef3540114bb3e83fea51816562d4626b37d7f18928b63b03aee11638af80a6bdf113656993349ce6ef61c8c61c8cd3a02a0257eb70bbb016578839d0d3da24b8a09c84fe0166ef8bef6d07932cfc4f9b79b4f40dd1457de03210fe24cbbaff4091bdf532b0a0d9c1b2febc5119c0ffd84c4a824dfc09b23bfd0e122f21908f0d34d877667c316d8649f436f3f4bdb39ecc626e2face22e53febe72ea7cc9721a004191134349a20648388b42c3e81dfb56939a143a5923b81e9ee08688d49fa928ad894e16ca9ce1d5e94e0f0d674bfa2a08cc9adbaca7ff2668d9d5fb760fa5d3415d0bb4a7626325a2fec0d049dee4732b4a9210a7f3f1e980f4505e1fe8aa8f981505e25d7d8aeb51dec4d8ce47a9a75d275bc3aaa0f01e09f188e17cba47dabd89045e7d89ccd84f422845c98756f5bd129e18428f88958803178167083b5353b4e8de5290c2cfe19b991e38fb0d1402ec269732d07153819684330a5fbd4555ca94eb0c14d8ca2014a1fe60eaef338a3be80c31e0220eb2b7090053edad21ff3eb3a638bd38e9b860f9851ec9abeb54b0f50aa2599cf6ddd04efc06934ba37a3a81d34a8861db7b8259147d01560e718eb6a1f5bca36de8a9efced043ef01380569b489504a23ceed7744ee4edf103d658f50c09e1aefef28a355543cd4f1bc2944904dd8fb69780036523adc8386e864df9701160eec4d87c24570a8d5dd67884323c163572a4d4f5232120904ea5259401e80fc1945eb47f551aa59fe8259d78b744f1a14b69428b959a020ebd269188798068672929d7e9bdac27c6f24ffc668394471d440c3e2cae25423714a46194acead5ad807588adf713853fecb24797313c2c52133016ba4b6ac4f4880de0134d6d09b246c3ca4d03fdb75e84a0e4fef432af9cbcad135a54692bbb288127556e24fdce18628c50d9ce9ddfafb522bbda68efaec775fb1a0b6f1dd4bad193bba129c1530832b30c6e376c116540241de0fe08546169fdb187056bc29987abcc5b9e29483c856ec098118860daf3520616dadad5c7601af50e5d0", .Okay}, + {.Lcm, "-419e41fc8a7ab45b23c1467bfe7b3eae04228e6e0f347090ffc157be1a42aa8fc8010192b94212b83d239cd8965390937dd6d75ebdb01131e61bfa89bf052ef3d01b8c711e55c0f30953f598f05b77efb9afb58fd7b4d4f90169e2c951255c9fb700a820e2699c2694fdf99b452766755536871e5d63580ea2fe0e7c3a01a42b20fdc15365c8d4b1df30040a07ac16295aff75a130b4a808b806bef295fbb50a0f419f555e51cb17a5a7e000195648491183533d72d769d5b9b76988b2df48b2c877f2e2027ac4757b47d86895aae9bf722d33a4042618bf61860b4017a1a6806aaecffddfe991678ce6791d3244cc956734edffb138ee3fdac7e6eb57436538cc315c536db9d1c4766459e705ca4f4d55b3f09eb04bc728862c1f44c2dfdec8326ce94abe0b560760b863e2266c2f380d73d7075a01a932caa1a9ac050fb758b49ddb49d47bf99f0f85c952b8efcca2fae6505b66e5977621b3960cfea1bd563d6bee2a820e53de0466d32ccd1e99c57277b44bdd8d4e585bb5c231f4f1af7530331d58e39c17763dfb85718717107a561114acf9f625a5ba4f396f277dd90d9b8dbc91e668684a60eef61c52b2f4467594772f65ef795f96bab859452b0457a3f17cae10b9620f574bf031603a8a364a3c2aa2d2000e47281de7c4d238650485e06250f4a2e65bfff0c2dc39d2f3ed05d30f59bf96cbd0ed77b72cffa4c162", "-86a4d73749f7be368665647b92610fc1ff21c256fbc4cbe722bcaf308f3eb1698f41fdf5361315c06324ec2cfa678de0d19c9aac96c62af3a52dcdb7387d77eec5688cbb3a50eb3917c0625cb937006cd237836fb629cedd041f7992ea4688d2f4f6a217a038831693785bff7a33d073c94eab06afd4ac78b7d890ec896c67541c7d4ee8f9f33a99dcebbcb9d06764e37311f280f7e43257fa2b457491d207b6a6724f4485bab25bcec07fb893ac262c69edb9d08575dabd44a9282da5a7fb2bfe69526b5a3f816beda881adbb35ac2731149ae1fcffe716523123e522e218c96304c96c8abd8043ff024827f55e9b853ba243cafaff509f705a0a335712ae331e9c8d8e0c606d8bd9c8ec1f6ec57de3687d9ad7f294b83a0663a7c6ac8451788a7d0cb3218a49d46c284daca6d6f7069dd305abcbfb02c4eeb3c3ce577eb19898b619427c545ec43e7ab59d8766024d9a7270a87d51b6c351ba2c114aa83c88ccda94836a78626c711f166b089d2dd163fca24677465c0b835b601c883f1b017a029c8290a17caea9d5fc30b1af94539173fe132685c1f8764f7b1e9b4631212bf10e509f745a4b84f9ad47a8f8c7189fbede9f839c5a70a3a50aef4a11165420f5e48f8ff599648e42f45629869d84580ea29af63c29d8950f4ab0781f0f252b0710ef395d8377e9bc9f374ea0d4a6c921c58fa2728c2777058842cd4d100", "11418b8b45d2ebeb14f2127607d7bbad10aedf08cbe8fc587dfe4aaf71b7d3a45e10f661c198ca00ce8ebeca3de18548f1c13dd17984affb95784a0f247f8ff28b2f376e4e0e1813c354446f7250314ac4965bd2a80cd77a2f80167203c7f0db9d09fd4c9b926b3b0a1aa9f61a88a74627bc32f03d3369fd9b9035b0190f1a94bced6cdd95bdcedf2ec741516d378ee31f250af17fa4f1f40c5a6a1f21f8f0f8837c7ee5e5cd430e05218f52f5a2500436eec14052e040f65feb9a3abcf0abac0b94eef2c0e03d47d98bd8fb87866cf4987f9541962510531dc6e933efe524ac94f5b1d322d832973174acc34bffa60bcff4efe667f21e3146a5d32e8d10ed2acdf8ab02cf0d6c6b6cd006b6469077d1c2bb6e5b26f14779ee169139406e226775e1e28e7c403dda4cd34cba0e9d9ae4b5f21babee84f085fb04476bebb47c70a85e35279a7632effdce944a1e9653b82d02d39e623dd75ca4cf30474bb5081ebf421bca9d653e3c295fae4bb56db1d1540a984b923ddf3f0b52fe9e510d621e7a95cdee5336207563482ea17e8d3222edb194e12645b0b376192db143195b7bb9721794fd0df2b7b6ca6cdd0f36cce36697eedf48e77b92e4d521cfe33ccaa005b6ff548c6afa7c66faac4a739518643e2fdf0329a7e5a79ddc7277a4b71a0365bf740a153c9ebcae786e3129968500a1104a7a73b151ef4874a5d61099e9991bc5e62062a0a614b4b5c94aea13a312fa9569f57f499856c56cc5e7b897706cdfdd7b42f6886289127a3995113f0107b035d9974824a2d38f9c5c209ac0fb2f403e34dbb5ca6b794b4981cf381158319a5b1135c75e8afb72b16db363bc55f48499080050f5052f2b9fcf63082c35740661bf82d1df3ddc5826dbba43f308fa1c1be4d03aca52c5962a3571fda58eee6106dc3ac8cf4c075ce0f5998654347c947e81556df1eef5c1bb933b2ac170324d2047ab4d036da658a942bfd64efa3f4f8fbbeb0c98fa6d81e1dd48c73515ca8291e0314e2c8670bab964402ec2400fb8e20ef45a8b1d1306d31bff2d2c5437fbb02e7db18c5338318e0a7f10bea82a51c4116150fd8a522cf52ed08e73a1003db734671b392ddb1d7a7308490c7122697bbfbc199c0e1e483e98161a14fc59051d79070c58e63561ec4ff642254ea7528662096a65631059e1f1c820d63211a2c7b2bd52c373777ddc26df7e9e24ad126d50d44a4fb560a816fcc39655e7d82752ca2ab816a407c9c2b8c56d68268aa3fc0a9a55019595cea793cdbe80ccc60c2c833bba17e1d568e39713ef54f12e8937f7f48797ded63dc36f698363ba5826aa0fff2aa19b8a8162693047f70bd0c73e5d89376e34a48899615db1ac203793d533a630e5e092ccf95ced7052300cac7801d82a0fdda00386f87b2374571337596f18c3900e7e30694753f848100", .Okay}, + {.Lcm, "-8e9f5b4f5930959735cc847a157a3fd2fb4a7c8b3e212be9e806e30276504604511853bfb31fa42c22ccf86536c152a5d1ecd9e646d224162242e1b7284ef33f9b7a9f95134cb9b2dafc151d12bf8b42aa45ed4b355447dba0eeae3b0939f132603631a9a4e5cb6d3e0455a4fc3551f447b9362ab6c5f5689a41e34384cf035c83005ddd1ac91f28250b0e130b8d9f48797a8c2e5b221e465e7b54e522a18733339ea09c77d17f92efb64635f3943947f486d674f0e8517572b83307b7d909a3a9d44d82371514de5b0ac54d7280b5132855a7085ece8e34fb77440530dc7e70ff1eb09ae51dc94e6e7bec29373f428cb1b3aba446245a8786e7670ed0e5db1dcf93d531fdab6ec8683549b12dbcc880607eaf2cd6f64dc7b6a0989f40918eea0a5abc3feebe3ce9e8ba0397d14e3a69dbfa509d9d3b5215a8eeb6b9313762633d4a964fb62a911f7fd38a7f484925bff4b88979256ec620dd20d9fde096fe308115789f2424f407db33ef7e95c04548d05efaae7bc761340c5fc692dce53a8ba307e09ae130891096c5a3884495b4529dd841214e6fc4c26c63b9f05b5b81b103be9c99a879d17e75256946f98e69213f041d009499485426f52f9b30871727caa01223c4b7b4ec520cfe2e05f05d2726232633a81eea7bd760737d6589be1fcbc5bfc86d1ceffcee88651dff02c359c505d54a3efd84aa3cef3bd0ff76c872", "1a38f8a4537c2216e41674dbb665c18ce66ea326e1c02c3029a0c33c1d4d24302947388a072d6154d67cbf2e18c5eeb64f41fb9d7bfc72a8d8e0dc195fc08e542bc464b8dad6b283be1cf1c55dff7ce589795dbd7ac381627839c183a610e6017c69cab2d5b270354b9c41f75613fd797572e51ef5be60ff2d339c2f4b9cfd9497c96cef192aed4664911b70839f7287381acaf86ce0ec2ef1c2d3595c2eea93bb1f8d16dd6e6d70bd8e6cd894cd2fbf20d90219523491f0a1889e8f91aff5042f58b21f2c68ce1270553db8ab4c35d835624144ee4dba0790bb1a32eac6116adfd6956fe452e7c6d021f09bf5b9e98eac4f95d4d015c58d1e95594e3112c25f4492ce731fc97e012bdd4108ebfa951f6872ca4881336f4d5063d9acf64bd2117132789422dc7e98f81645ef2458e224cb554cfd5eb409c3419dcb0aedd7b833dea77b788e6c27be6579fff0ca72dd62b6190594b9e80b55620566ca3f560df4d98967e4f874cb8c7c6a1ebbb6f875aa9c4e5b95fe62cfdd163d72129eeb06ad44e70819499e95216072822bc09e71e619fe9463baead6716badd7431fd04fafcc2fd2a076347c0f45915102a2445a8beac33373627470aeeb56c9ac9ac6784dfdb910765b7cebd1c69d0a8fe022afdab70819b5a1baed996974b9f75911b845469de854b919610e0750e12005aec24944ca87756fc964580de8b2d6ce9b018f", "e9beca7f578a1d727d3a1ffb38a8ab6076c00a5506ffcf1d51505a93b7ce2182165bd4f43b88a6f44a3c197f48f7ef5152ba9552ac2422d6af50a9c45c84620cff4128992fcf9aca9f134dee0774c2cdd7be2f636da0ab0518e7e019004d79ec29cb33ebf3d41705735194ae136c12547c099d4b6eaad6db963f5661c852770c5839640298017745c0b27ad8214cdf8de5483884b19f5f2e463975c65c4d45efee0c6afb46262277277c9c1eb7fe712f72352e83d409c8431ae6c235ce417e7c275e940e1be9652d5e0567d06a8c020352fafd94e18934f1cc12b6762816b52f4a3afe784c4d47019497ca96558990f3ea4fc90f3d33273ac91269d6e9abe8f59b9ae5a94b31c7b926c3046231c161dd8a82ca1118bdaeb5316a35390b729236c8d9613c926c1352362555aff865577dc2dc40c9673abd7e744ff9b1b7ec8b64afefe116a9c0ad538902104d265ddd3d7372f301fc6ca219ff25cfb6898771c57a1c13f82e5d14531802531b66fdb5762df6ec279049d3b1f14ae0a76357a1456d75238e8340568f55235d0c31ea4de58b07182939431051da8a6f928616e1c6dd8d33538cd438662913a50eec180919a7ae2c278931176a2acdb2d7212b66d949fe8b6073180177b4726796f9db83339dbb7c3fa9d5c97ccafa6235b82869ee93a9d9875c8767e9f24ba488de8426d54bf03d405838a5ed9030cbae8fcd78ecd767a28558049d53f2ad4600b61f82f9d9dc191dcc5e5f36db161a172feae0bdd8e1ab2dae2b84975cafe070e9673d1625b10d9598d521cf01379a9f1e4c21287e420e1e6322867dd86fe668f84284d3220139b3ee4022c00b506a9584bea7d695b9bb47c5ad382b5bf7da70d798f5bc28669abb592534ee2d2f35c13de27c5a54b5a42565e7e63163f35057d2d7a7bc7199d97e35be904eda8cb5e9332466a4bfb21317c15a53639f4721390a9abef27e68f8ce8f6910f9c071da84131022aa7c923359f880564487dd794e78d52a853f51780e0717c7c19d7b066191dccf8f14c9efeba1a1073db3a61084712b16d0468a15c5337bd1a6a5020f086bee1b1d4615a9669f322224635fc189b4b13a80cb3197d5e4804711e23f76950063a7acb7e6d9d0efa4a527b0a0c5d0291d54da62f699203a3036a7f0bf74e6aa7c35bb525dd256b7f18851db7afdf2dbbd13d93f21db4479818a4ac99044b8ccd92cf6c0985a4453c05c7affc6a866e24c7f519f7ed92bf5657e644dd76d5d284dbe0402cddffc991960cb538c4fcd42f846dee30b9494d68b155209ba0c1b947d93424337deaa7248e61181fe05a132ebb898703cf13837de4b98550e9a4af94f6518a0bf57afdfccc669778f5ae2fa9fca238ed68196a1eced8bfca23f974819abe962b5829485b4d465df42c2980d33e3c96af39669dd479a9f3f55041432869ae", .Okay}, + {.Lcm, "-e3309e3c736cb1415a41ae0eae22da9d642e9bc6b93e98fee3c83dba910cef90d0f9d4caa4802bd87b4f19e7e93e10231ac40e214147a0c849e3803ef5d7a7afc67692b50fa3d72f9f4e8fb03b3f4a83679a827ffb83eee974ee4723addfcfed43e7d30200df2255ce4aa39d12711f904f21dbe9e4ca6779093a87d9f47de30d9cca9b4049c3c79b5389a05dda23d6123898d464a0df883e9814eb996aa689a66ff7c616dbf7edffdc126dc140311dfa81697747b55677adcb7be35c4d8c109e34b52f21d7270a7fec65c875bb20e37b60796338787ddb34e8692c00b297218d6f852130a4754b5abd028d2660ac4ff7f0829d322678e6a8bcb7ad34fb7ca867b0ef20d51f2481bcd56ead9afbc614db8f32883e43875915d5f67e5ea533134d6d5952b5b8b5f53e08e1754081ddd7533d30f9250624354fee255e0311826bd9cbdd4c35c140befaef2883900118897e1635c975da67d56a28f0de53634ba660c8bb4ba65f3d991400ea88c1a4cece33ec0f7c5e160072c801dfb5c2e64cdbd42db1224473879019c75e66c413ec0fe96e65b5271ef0e9866695b45661ae311a72608778bbb6db12a054662178701993f93b7d910efe6850d514eaf047a0ae174a85d9a728f7b5c58287e3e9011f630c87d94ee079dc91efec7b0046fce9437c01ee0aa7437d82cfb570839b1d0b7ab6b0f85b822c4b1458b31e220f95b6b82f", "899dfa5d293e221852b0ebe8969fca456a997c2e567894458f8767f6792e854410b8a89a348c1b2cfc0f7ba3d0d8121390fa37ea45b8d3f1de6d020b830b1abd4e0e23a324cdd53067595877eb72ccf52c4c397677a91a2ae23cdcc59a7cd0388b287242cad6ec5601f433844f3a3956d86710b2655d73f165f82dc45edc6fb35283dff35b59d66e91f829f1be8a66e2c83eb5859cecd1969ee9309da62f474739b5b989b6afdd0b631694601acdbafd9a05d4e198c2b3187722a401dc3595a467b759d848c6a0cfaf9ddee74ff02b494628592c326d6c358902e7d07a140ad713376b296f9682a023fbcd1c91f5417b25e876adb2c4723eeb39c4c406f728fde756b366100d860a458d116a80a400e300c991499a33720041d8cde5fa80ac71019774287daf01246ff53ccedd7fc04962ad3a07d9801d9e4c6cb5d66673eef1e89b0114ac3252259532e5706a5ac15024582f4a03c9618cc9152879b044fcc8ad6979f24ffd3fa8470dcfd0e0f8d182634689b98ebfbd930590b690ca80ca7ca8f8c1e8e9c7843f0490e5ba366efc76f4b177622981c1b5b75dd1b090403ec56aa599f037553166ce7d96767070ab4a45d39e474c90d4feb407b009aa55e824aebdad97c802120dcb77835ac3675468cc70be99957cb8ffa450057b73538f8d55e23881a2b5088adf289e691a8df0c1314eca8792662641b7d824cabd563135", "7a2137af8ca26692ce0d867d60910c5121cf506ce361eb12e1dfe703f402a005c7f0c82b2f1939f132ba4654d5d76e185f1370052936c688ca7317edb2f4c41bf3919268612f58fd39b466705533a237da71f4ae7f65c89aadb00ab5958a4324452df36db5075a8423a3f38e495e3ab9bd44afac745a473df596502fc24f2d8a036526874a33184783683b51f47893edc874ba54efe0ad09cae64e6e54b123b9e2f2bfe997396c21a508ee21c9cdab3adeb16640e1a91ea7b01d545674da960100b64503b9c6897a3151763021d48212ffdfbca53e0bbc95f66b26e7b6b8d1b2da5e2ef7e7d95d89a81033b58a4fa2774a1bf3a8630a4c985b1fb490d92b5838d231baacae55d8d4687b28c783c5297a67a89d584fa26940b8c78a5c788bcab59b05354ac727fa3d282a177febd35a41d1b70045bbd884de9c7bd0eec85a0aa9a77b17ddf138434265c327819671141331d475cedabf4e39622e066c9c4790db0ad9b8b7df34cbdb9e88a3079701d1b50d4799833d978ec8c9d0b5de534cd8d0fa35190be9d351e2674b421d17d920d6fc35c669ed04532ff5572aff7c8c306ec8f407f38dd649dc7b7f3495616e808be1a02ee5e94af29404177b9b5db7dfbe72edbdc54bc32da00bdd811bb73e074d771bf6724d870166a3b73c6104b569fb76dd7fd42271cd78102b14de1bd743d70d792287f3199bec3a9fc058fbd118c47ecd0dc497354ad9fa8404350e98f2a29de91c2247379599989c5e418d18596aba1e729976e7cb65e50dcca4b622e0eafca129af0ec376ad3cac97c23ebd42156d7bad50166a8670439c253a0f5f6aa213a6337695e128a856a59e6494cb117a7ae61e09eab0d1ba5f313dc8af72e25fc12d52d105095fd2cde5de1a220c82045e6163a26f9d0d4b8da1c2db5c81a4b895e572dad27201a6f4488c00cb61466d9c77bb71c80bf253906e3e5152bfb54d33ceaff5f060e75c2e53a48817f70f572691b56a070bf1054ce0439cae27eaea3e4db60b1401a76ca2ee6b321b922381e315a4d8254c0b7efbd9c980deac12f334d740a18039cc8e1b6b3618624f42e5006657cf2ef87bc40b3a20866d7c99514cdd9fdd7c2d034f1801db216149df193c532d3853300377a9cc73809024f0f00b1a353212d2bb365efd2f073d58f1290d8869507a5408f82e92db7e18624615d045836b497c81a14b85dc601192c0e2f30eb0333760432271fea5aa482320877e9295bc6e1bc216cc07087457765e62750608677d5c316b7a3b58586448309e93f61e88c164b54743cda0a21d2a3ac0056666df54da263956e46c39b8e1790075870e112ad207c29747dc8b9f0e35daee23cefca6ed7a29f0ea731be5e8d9a217f26cc14120d3ee91d564daee1c472612002e06cb489bb64d217cd1354963c6c1a8676ea3ac5b08a1422b548adf20bb", .Okay}, + {.Lcm, "-a0c9b948c3569e7c6844c3ef8738e4d752d0add34827d35197ef4a08da0abd68f4c0faeddb0930a7230b2277f98b673718a78f07a9c120b63e02366c298f3e30f4c43197a429fa5e4e1f1d150accc1a7516ed0f6a17a8be8c576fa282e1afb9eac710fa6efee84acfcf37f72f198a4fefb0d691ca1c01acfcb1791570ad24cd73024e0faacbfe506dbc5c89af482efa4657b1daa0c62ef2b2fd55fb7b9d4537ee4f9b428ca833d5012ec8f363bc807cc2bb415e0dc1e5285a0240100f8d686b3d89b7d9763205a55577a5e797ee58ee7e19ef01c8fa389b52f066dff1e597600f80fdefa27c3e31f855da04fa06b20cbbce7d60e518836e5c2e0b85be7af497b1957882e150705f7ea2ad8233800ff1bdf55d54416b81901c276fba10f938d19b92df3b3154e1f1926575721d73830b76a07c062e4966f09c8f37867c3d400c4ca894b8a5d863cc67cd7ae897823f7da0d9f374e7941d4c583c5d04417a4fd70b447e56701b651232742da15255bced550ca884e346b3aa99accf3a05c3239e11d62c9b71b4390e4ece6326c2e2eea6d4db5af564d2a3d592c5b7e3fe7033daee35460ebe854ae4706c912d11ca01f29d344a0a63690859ec53c7c3022591ae9c50718202e36696a24a9dbeaa1eed5d26c6b1b871b666f8bb13b77af9f024fcde234084e36fec6b6174dc5b247f6fd854c877f87e0beb1bc91e998ea4fb96d9", "-11de4fdf36f9513eb88c4b2067f5ea13967876853d984c0f816445aae2f27530b0f49e6f685cf4d7a790898285fde6a69ae71777f9f29ebc498bc711d10d61ec5cc331f80c8f16259e693daf45619427e0b6b3c2b8d7543eee31d29bfaa4656109db143d79476159c73baeced04da5e54ad5db2d965828d47aef57ffdf472155d4c0b71538335f1344675b08a438e8aa28b670d56f27d5bc24c8764a7075bed3a6081e975a6417d3e842c8514609b7a398189958032d50c1f122d3282a97f441521cce2ec3c452c208c184bf4beff6883d9f7e583bc648750d6941ed69e82f71d6a0d0530acf8568bfa11bf2e25827f15057d74dbe0c2387b09ca3d57ace72512b0bccbf765b236e5d580ef01c42248839e9e98e62d3893ffb9ce1ff553d4fcce18d99a8f8fed4fe0cac4384ae709147347475704cacbc75859b4da89c3358fd988088a7d6b3c045cb50d07be722996eb51aafa58bcbb545a68c1742993f7c0caafb4a9d55649940689e6e9bcf51c77f0e0d26d97d689c2ee8d16e127fd5afbce76f1017515161db64e47d3a3e4a7e1ed2f611bb98eee2e5409ad41b3b5b334c3b774ecae150814da5295d3eab071358539d80a5e0b9b974106ce21856f9c985e5fecb42b44603fe7b8ce9497de3222cb624205bea041d0642e68ec375741589312c6dfd25185300532fa8853c6eca11dd834f197d7a16387ef27634b6201037", "b390666f47f249f5f89b3fa0e2b7b7a61dcd9bf1c783d361398bff09c406973afc44b71f5518d6db28a616271d1059392f77d00db497f40152cd136fc1f78a05ddc718fc4dcbdb43efd29b704ee9abc487da835e1423b2fa20e3fefba76d3e0ae885df3e60e5795cbc1692433ea907be86f13920b2c628753667d4f05ab16f498bd9835feb890e1470e3aea2d9ff1228c39ff35f23b910c92759d1aa7183fac51ac490f0015bbfd4d377e648d295b4e74cd332907daf49f8c1e08e95dfc6545ea54b090e8c6857a06e71947088c2fedfeafd0b8a17632c25b7820bc8adf75ae1e7f88c5f46573b4d2a0ce5487ecffade6cc1ea6e368eb4af50cbbaa6e624001fe270183deb0e2eea43cc003b9947b3123433184d2cefd0934a7fc4ab9fb787754a5d99cb97db5219d8c1b754c16a4d973028d0fa383ec4ba729f4448e9b37f08472b181677713f6bc05a8de8026912fb5782a45c276ade20e0e728ee8a71245cc55b83a7e7a0cdfe07717d26096533cda3f508ea31353bcfadc5a0a114efe0b4563491c1b68927c71da415c81644362c82a2c6539d3e641de47a345327cc08e8944ea186cd976e7598e8275beb65324696fd2150b014a606a14c8aa1c8fcd8259edce43d7b46ff75d0348433f463ce410c928a2615b755b6747326e79d75d17a4f944231c60ab120d09bed3ac174e01353ec7f236f707c4c981e88afc735b9c7be4ae0bd33407a860d5b87532d9526f9d16e2a50b3ce29401e3786d0865a96de15d64b1278ab4f7b9be256149088317e461f2c0df087b14c7ff2b28e864a3d604f95b94d809160bb3f3f495bea94d19925a56229b54bfe91f5ae6a6f2ee3052e8103e04feb42e60737b6e235c1ed36ba0d1170d98cf30e4f499d2ea6fe67603a9d790389510d7f089db94199eb6ed9e2dba5fa36d073a09e26bc85229691bd897f1ec411c942fdc63100fbce4b5e08c0631544b7ae4d9557897d07e074403ab89a78e656cc7c75684fb9838fa0a06b86d6c51d54e882f8e2836833d5af295c5bab82e921a4ee49a1062121ad2dbe67608c7c06b307536994a41d101458a35e5648b95f2c7c3fd5853fb70ec25eee2a67135ae783a8ee2250411817bda277a0b97f627d79838403fc8c606ca9f31bf79728ff865e0280c69d0bf6fa2190ec9afef27eb74356f8d7bc466784da2637ae9e2a8c2bd7ad9ac22cfefe8103c6ad4fdf6f9e2a749f50f1902cef55f50e14410654bd6b6d2e986455db58abed3c5df956e1ecf0a5ccb15e1859c2af57df485a3163e5b037d3bf1b772f82b9dd638848cbb446cc837aec50722584e4e27ed7a1ac8011647151f826ddee838ef22d7b22230fe3cb136a9cea2be2af6a8806cca32141f9f5db59990c7d96608b2ae4940c00f4e2b2e47f07634a47306716ad13d427e04be1d92a85199c100eba4c9af89f", .Okay}, + {.Lcm, "-c69e78ce0495e633d9450dafc88898cc3f7654cbab752c2787acbe1b45f214b72a0d8588725f418191c41c4fa99f78af54a686e9b2825e63ea88261f16e4646eafa9936b10da464317c53b0327ddd712730e477ba983388b6b05cd25775d02331524b7d427c4348aef292b90cf27e6ebebe54302a390299a2d94bf31c3e21b8b079f16bfba1a4c68a89b0b40ee0623917ba0702962e3d83f991a96bb31138635d2bc15d0326caba05495bd073e47f73792b8d0a0043757b59e9801bfd5aed11d874d70106793dd77453ccf78da1c724354c10fa91f188fda21ba168921e22fdab1ac6d923d696a541595e038e270cfc6b3ec0b3dca16b3cbc82af788bceb0f5c16041568e421b168dbf7bfd8ad997af554695a40a6392ed9c0b4e4f6556a508fe7fd45943f2706acfcf5245a829a6b1e049b59b50b2a40bfaacc8f32aab948471de928f5cf37d4a3a09d8e9a2b98df69d6f0a6f67b0b0d577c202112d09b1ceaa45bbada49e6e903e370ef1ad4b63ce4eee717872464e63cc425ea094480b1d3dde6b7d009f29b1536ae84e19ded7db2f0a85f618df85a4a3bbfe36bbcc048ca2ce61894ff6874316e4fa0b82c85a4bf307ae60fbfd363a0b0dfa443be15145d68d042521ae3480831330f850a7ffabf9ef760f880adf66a436c144786944a686b5033ab6d912d716186d7af24c25888f879a7a6f1826d55242b5a81d6f6b057", "-88db7bfab88b657f52efdc7f02ee9ebc81ebfb70bbcf0f34293463e7611fd3b6a99f7f6cdac4b2abb03dcc8d2f939853d2d85c5b12d12c27f34a60f625f82519cfcc8e3511c768527a62c0eb3ef7f684392b6a9393be80f2c4d85cb47cc909065d0930ab6d0a92f651c9c2647550b76bcf29d6f44463cd6e3e8d940b244509ecf9f1bf83492ecdbb29a61535d97a9e75a86aaad225543a44bb1a949a542378a7796fa5f984cc69f2a46a91456de8aa71087291928ba6b71b21d8d77e3701f422f9cfa6c4377043ab9e72f7f6f133c773e5fdebe0f169ac1ddd1c089f0027be6abf4d4651e14c67b8f68e2d0ed14d423d670f0e8bb2c373a40df7b4138626c3410c7917c48f98a01e3c7d4810c85f5322890629482782292a508c6050099c0f99a2b6ba72bd94cb30fc2c632060db3771aa5df7e1e18f8751010d832dc27e93263d9b9f2da0a15d0133f6653c2a8d19966aae5291a86cac9e6885df65da09bd8c881723dd8b42754159cdaaa8899e97b076af8622331d2bf67960edd6473c33d3d6c50900889589f110fdc4402ea1c709dcf215a35cdfd5e74c7201d20ce382ea5086bc6e001f8c6f9bce8e368dff7c4a45a92b8fe948dcd2f03c70e2cc0e89832425179861615e03f88c9f43ea0705cd3a96fa92c5c5800f643044d69dd94b63d292553159ab2fcda57db542efbb8ee3f20099cd3b182cb4af6ff309fb292deb", "6a2e79ef74a8918af38d91f29fefd91216fcac8ac785e46dad49d6ab0cf4f2e25329f939d328b9348f022ac5044a8118e17b03334362352962d83abe131b011d8278f8641297fec8021752c1240bdbc9577ea34d9919811ccf6cf3fc49837edb15295aa5bcd1f1e61ae58d18953b4ec5f9134d8be4a87ed405a2a0ecaca1be3e8b97eb06420009f77f280a00a32859ce30ad7811cf463f28f34fb95ffe23dfb96a7d62fba228ac9a3411d075a078c6a60d52246f04eb6cc3892ab513d1404c9325ee1b502fbc5f1bf0adcac139ac0d4e624c0ca7b2b98a1ac5790e009ea100240534dccdc857b7cd91f885be98effdf4a0161dd0ce5bd7bfddfe637d32ac7d4f5f3deb90fa1c741ffa983d08e67b460bbaa76317301c5c4775e6184cd6a4f20105b6a0b7ad504a9b0a7e1ddd698eb040d4c637f883bdedbabe0ce79c40f1b7d7cf3e35a568b27a3d74adabd9b9789829880eacd9dcc0f4c1364b79c8b16359221c591886fa3884b435ec3176a82e6720c1b4b6501205485dcd12788ff8231b5e5d8e5dcd71fe31d09ab2bd8f17be42def4cfbf84e07d68e9e0e99766e918f2e71102cc0d74385c759e29ca8b5b2446dfd75eb5f6b37854c130b4a65698e9cd283cf384d795ec3218a98e2884511e80f9ef6f03dcd0c02634bc34583d414045cd09373baa9c9315f1e0798fb81c21eb37d785504bb6024f352db4d8656b0d856a89c71b2cde01051fc3a02d1175f56bfe0e3e0ec4522bf17624f0e64668d0b62e39ab0684daaa22af1b08b8e0cc1b91f4590dd79e4dd68cd1da18f74773bafefa84639593dba96ad9424097fed590c3b7e829af6ca879ce2bfa5c9530321969b82263f641f9b9df59639ef40ae1f69dffd834675e0ad8d1734ff85381787b21d8ad48ea1dfed769176ff1253dc1eae1d9a248f5d8f3e8993535f4b7abfd20ee00a513038bc16497bddd2ed3e3c9ad29f700f1ab42be53c78dcd630bbc583d7fcfb9064855c884b51f74ab708422d0f3d21beaf18d65bd968e0884d29568c3ac9a372fd1064d41eca1f20467a4e811a9a424e6894e470fea4f7c26a10ee18c6ab8b234f637595cd419f5df6d05c3f2fac23aba4a923c074b0ada0990b8a568a82020f01a475b37c81cbc5a1a43ae7d9f33a886a8e8633fbaa59f67eb535ea80077c4ba3a3616735967d97dd35b2a749bfecfeae0224a974e5d9ff4845a2820ddf0b059ae68afaf93df8414e0ab43dbd34d31171fe36bf476e7eff01991a663d29c0e8855530f64655674dfef2e909953f2fe5d80e748fd0b24b3fef42cde93f4cb79f72e6c63c12a0d5d2995e3f9b2d3f451f2b9eb53d79533511fb2d5b6f40d2b21bc0edff17d3f8485eb583d137645fa6f0da9ae67c17f54c8c47c6f28ead6159d23a133fee0e487647b847e9a5c71f9055ef3752aa4d77d460bfc703c622add", .Okay}, + {.Lcm, "-c0804a07fe4895669c274928869b56c5b69be7b0def2a38aaad27262f9dd7025f5599e37cf648d531ea7445a64370f89c867324e9547a937ef00e92a0169735ef825e1d8c19af110a0fde378783f50b78d72ef24b2a9457e495fade65c16d6c7e9a37f9b1c14ee29e033f64126f2f58358215438aeb9a6a8eded2cf2a0b973cb666ebccd96cb6039616da181b0bd2704a2d8487c040ae9df55af30040a60f325e3e5e5c1af5b9a68e3f31ed0f2b9d21b6d568b687c403da451ca79609141a2fdff2afb777da1508eab9cb07b09dd892639115632084418a2c3e7cdcff355305c21004a46728e8c3aad0863f4ba8c197439ac242ee1dfe41451c17f497695f44340b5654dc7a68ceb4708b4e03f6416448bf5fc7b644ea1ed704b723e7bc2d9978e58809cded8c73281ab0a028ce9aca33e9c54fbe5324e700e9f820f9fba886c30d8ec7a5680f0fdcc817b11f81f0f76eaa2e585317c5375a60543e8859edff31323727e9e393e01b8126d4c513b4fad5fe677bbc53b1e8051c9614f67f224bf1a4d536ead28fff2681b71badcc4ab6f7169b83860a6c615c25e0ee4818f69677c7e5ecf2a7b6c4a68a99874465fb3a26a3b365c2e026359c7befbb3ceb4e819dced30460c3f9853648cb519129cee9af94152b9125f194ef7e04b6032e5c46a7199a49680cbef0e4880980b21ebadc2ac69f31d5c70b067d30cb71bc7f7135c", "3f83e7f04cf864a788aa3cbf1a358942338e66d9f6129b388ff63170fe900ed9c018f85e96493c5d6224d161b67c75c71e428fe55f51d364e49e06dd940b68bc14e9526246619ec319db3f7f36aad374f0fbef1623b7f61823cdb7ba298967026e70889db80c729665502d8d2b6e3a1018c572f7a307e5a5b557c015487dd4b9539e17555d9a072ea8e42907a965a9e0ead057292bfae14decf3bbc819d0807535ae60a17b58de7c72c8b1d60cfaf27ba4b2b867d2f8ef37506bb507a1c9a991239dc79d326d0800051244bbcd5f307f9b135fbd258bcac3cd8f90048d832aa6ead49ccff426f1def489d0204387e21c1eee6c8404f89896ae0e64ab27bf041cb10d951c78f40a123e3ed67589ff7c6c307e3fd49509dcf2e8271098d0efc8a6780126121f988d82d05964ea577d7ba847d5e59e510c34b1013ac7226182e67b12c69c69b08dc6a954fff5db211bc1aebce6e88fccf7e580fba93c00fd171c39ff193706810167a9c58d4a571a49b42918c591e73e89859e27698238c15c82f30cad8f24bc2d49f13bed12492314b012b37be67b896911f765f742916bfd69a04434ff662f41783ee82417b8d0a71bb3c6d8c4a6d73fb25770c6a13e182a5e9517ae2f6fdd972fcee0ca6fac7ee9f4502b91fe30d5a72614e0303838f9f9313c53079b7c33e4b92b93822833928310c27281177d106d9bbcf04ae8c75f0e55b", "2fc2c2464e9e77ccc566b19edb598e6e90acbce474981624a9caac30b5218a8e71dd34a24c87a9bbd75d7a9a4055c18ff606ed1fcd5c875fb7e8e56a40fd54039f71362a7a36af743cf394964da41534cd353240739c9cb6781a651d5675c405d7b8cd381851477a8f241d99331fb1109bb95e9d6ed581fc9113c4c10afded29044e1cdc39903e8315715570a5b8174e517258f3282de9417672251c23639e043a8f6abb3e591d669b153ac83d9bbe5d56bb26f29009ac3cd9b733903d28c1162b9374103f3ed889bbe8d528e567034c94553e4454b8faef1a959925d784dceaace9a98d60d577debc9607da40a49d71d828aa8a699fc25cc120b255dab0af14eb5693365cd27cd6009e0732fb26e0f8b1500b4cb3919fa0ff3e9c1926265ffdda63238b95bc92a16b1d674151799b0be95ad5a979da9461237bfcfce672f893f72e43b1570b81a642f3df922e3b84dc33aa5cbb385102c899867941bb0c215362d3415a3a0cc8d8da49d0d064142b44b119a702c142cdbda2c81a9e8ba4d30ea658b22bb0d01fe533123f14c65021085e10aa78e22f75696a847e14b5e36b0010dca06ffabe852e39b9705df4576b2d7f8510a861aa2df1d0cda31d425372400ba1a0565c53df63a91c10dacdec0cca926da1ba1b129ed98ef45dd030c905758b565df4b50d99646a540c4ccdeee356b7939e26e0c59b0223c4b50011182f88ba6bcb2cc4a9f0dcad4149213a33f751adeb9077b848eacd15831bbd7813e6d4fb61146b3e720093524dcfb3aa7bb51756c707387a47330561d53e33f710ade8eb4aae5ff0d3ffa6219524b41078978f7f408d1a633c8c40ab8edabb0b2b233018e6d875d85041145c59d7cc897803266b136b625b3d29f0509ebe717afa621ba0c5d8d54e12b31e7deee2cfb6a29886c5d62843feb21b9e2bdafbceadd22de6646cb6af3d3b8b9d01900dc81e1db783e84fae7ce016bab1671d520aeae3b7e2c53f44c80278d370c9e2cf042858d8a2207827287363dd76ff797e70b1117b445be2ed12688a9b71e4253d763e260e58b3a5bd410935b325f7c011ca641a56d36aedc8265eaaac4a85f547c9082e05fc067f4bb6ed9743442d5c4f99ed42af25fc3d92b2dc5fee71d3b4736d1bf35cc613d56edbf557143586b83e4a307e9376a76b06086f235d6aed960785cb74c4ef368a51454661a63715ccbbe10b19fba42b320feee74eaa235a872ed5c90c858cf47caf3b379f6d394a1d46bd8e89310a0ef9fb15e74848c3e107642f760c050195c53cd20f3b430fa520efbf217622bd7209a6cf3f3f9e415ea76222ec6bd0fbd749817ca1935d1dc88d7af30af259b36471a6c8f17f98f15451de1e5dd7d0d0fd42bb7009d4a01a1b27c7a4c66a5149a299cff137efd3088d6f5be8105ffbe92a14809f23b4e20bd77728b4b652db4", .Okay}, + {.Lcm, "-7862679ce9c19aaecffe8a42875addfd34b6e211be37b3962d5454c31b0c84ac6e7c2b807f0aa5927e0a1a622ea5c34af3e62137ce3fb06cc5f0b94e8739339e04fe2449dd2bce5111f95910f11707b3d2829c3a097c42a9475f768de06ac43854f75b500898dde78f211371546468a8bf9ef061426f154e99ac1c1abd1315352f1df1bb03a350ee7f8e49c2caefa391be9b02cdac691f7de77fb0099e4b096ad7aa8a80b2f05d61620f7d0f9107dc3db9d9f2e192d575db17ededc7efc3ee50d3a7bb9b78c2b7fb39e88a1ab607f3647c5dc3b94168ca507c8fd157670b907dc3423a564b41b47bcd1f652d17539685767986afd87a57a14ba25cfe405e2558f31bb09e19d74ac2219f2725a17cfae1517ca19238a909083323628c53e940a23931a590162ba4fe0ad2c0b87d14033d45909ea5d666a57fe294c36c5fd2b6712895c66ede3e2b6b22d803597acd9c3ed9ada7935633f52572a935326838ac53ce27c61c0409c895cbf50394f3a9283d859e4d6dfc3f246710a2784d18c5b9eff60c6a175b96eae2c0cd4a084a8da031ace015143cdf023384d6f3053f621129c0ef32182dbbc7ea33f932d9399fd9625b4cfb92c08b79199b90a420b999f944024b70cf702dbd9fe14d7f10e64f8211bd3c0c730ae12cf1f36491bb9f4b7c73b6e95f653d2710d670cbe29cbffb22288701c97f2a98a35910d24894dd923b98", "6cee48e8c3b88212b93a97cdac0ec6472b14fcc85f706968111b039a75ac11933076df8f02d3b9ecaac87b9417b8f4c84918264e24ba5477e88981a113c3eee844279c6206901a033d05d68f43bdef458794d0f52cede98f1678c55341d0a729ef097837c2b8575e43e7a0390327991fd9f709f2b1c79eae48f21ffb368373a50ba10405e10a7c38873a80e39781cfdd29a0ad0cb488fbafb0e2ab5b5dbad1bf8a74963a9a14ad7c9e02f712037f12e2451030e56347ee0975c882348b1591a47a6b35e21c6ce8f51166c72fceb3c5527ead503b62e7a304988e872b21d59566573f9f0ddbd262eba267bf99687f9c3f65a8f7c8caec64601446a51e5928312485a5433e401e212957b2f7e6d0823fdec3b04e7ecd1c71f6f305d1ea48849d2f08e87cac4d87d080d92cf29e51a0994720b0399aaeb8089773e8d23c1344ce521cd0bd821a8758421bca20d520d50535ef0e904356ea935b6ea8af0395e72f63efc71f2b82d4f924195093c170db792ec00bc3a70021ce59bc918d6529c72062084d4048a07faf85d312c98cce22a729d9547478d60976f16467f4af8681a32de15bf86354f9cf808c8574780618b0a95e33c1058b2d8c6ae3afe15c41ad7cf5292a847237bf996cfac0b9c8404630cdeb7f35b2808d98c748bf4801122ce07b107dbc083621315f6abc799e3375b7fefb19fd7f0141239fc895a45641cbdf3c", "cce645eea36b000e7ad0e0a9a03eb05723dbde38520bce062157e2d15a36f68dce6d695343b90bb965b317a76fb23a4a97d522b8c0380515e6625bac3058125a8b1bf2631297171da0d9177aa3f76e39472d074e730e2ad1c28d191d7b1b44c055a0d87626b49ac09d9ee66fa020b0f39ce96af3a16786ebece3a51ea6e5e38464218536b25cd275b88ce32d70359b21dc6d650255f12dc324f967b7e460b03fc96e79895e41fa7594ec70594f70e1c6d936801353280c1eec04a5581255f5065f4dca0fe039cc36032e859807f95e6b340c893f928197c568713b4a6c3533904a0e1fab8fda3d92dfbec244d93c3d39cad13dcd0e42978a4f33a958900d7fc10586f95e148107267ef30bb23bc26febc21949b54a3a68e11014a73f2b8bed33119aaba6c1668c45556887a5130163b0b68fea6ea276963f569017652055077754531adcbf52448ade855354fea577079d863d2e1aecd3e8ed86192154437ae23791718b26b4b0b0c653838f109ed18f58479aa76ed45538a52b0dbb469eea15dacbbf11f61d943c1b9ee5b3e2f12c0f8535c6a62c9884987cc02f7d7e25fc6296549d860f4bb8ffe5ec848a35e8f1803603d21a47630a808b0e7415f74383fe4ed8aae9bf08c4b0f5576573d287ab464c491016153b9e090284eabb77f6cdfc97e070a1779a19a71c3d55848b41273c0c5a45bd42a689751d67da48571aeb50f97d5b866e5dc4761cdf21bbd4fff6be081ff4fe7881063545afb4d073f3b9305211f182761c464ecf45d6404cb6adf9eafefc942f9547f612b71c0d485dcc7fdbcd90915b6333a5ecfb6d046d46a83726f3e0da352baeb1ce7cb28256489715d7c0c30f82e69436ade132cf8a5ef2c06fc32db79ae39f82d62eb71fe0d1c45b5534809963b6be98a141deff737e1d62d8dfc584d0a1388a6e584d76c5cad029aff0e4991920fffe7cb1a630f060b8d872848942449fef56ab981ed0aa82a5c228efc8c9831d1f1a239f614395e444dbc244e73ba6d9b6df66d7032a695ea3741cfc81cbd8b10d333c995fb0b9795004572373a235b8b75bb34e38470daf236cf723e39e1137f1382ba6e8f4ca6b91298848b5410606d097b1368bcf87d01314491db980a9e0d4f2fe39f25814a883377e001fcf73b239c8ac871bfd7c7f6bb5a9b09e36a0f970a9cd93a123dba4bc41f928c1e32483f016692602118845ac8136d0e17a7c4cb41442c4685d65b0bb709998e70bea71c561b1dcae9a448dd149888a3ebf35b556e2d44dd8ea1fd06ed42f2ff7e1ae1d1565e733460c19267ac3bfd3691cc6a04898fe17259864b2261a38b7546547b76decbc31b9f91f9d3c44a0585d1ceb7894de0885a39f17974567038f10d23de189150b76cf574b71ab4c579084b3eb078d8782fd5eaa0742ab260fe656f155a966f01657a434a6dd7e8", .Okay}, + {.Lcm, "c7321e7340bd9aa22463a644fcb878f2fe7a3b41589fbdc973aef1b7210f5bfab609773124e54ff86929718f51c2837a706acac24c7266e8ef347cd58635f5caf5d5f876001fd8e729036658aee0dbd9d6d14ef30a27937728f6396af7c5102d813c00456c1d8ea74f26aacf22f04360b782a08698f8b0036fc3241b0c176bd76a48542178f67a70c820cca3712013705407008baa910200f35727a4c882b00e877ef1e39e5af087002d36baff983269913684edbb5e4b6118077d4e50f2d9123f0c0f0ab3fe9b8afe7609f50844f4b1e9e7b994068c9922c9f89979887a4d043c69869147fba1541d0f4e0f98f32baacdb5c4117ef172f176de9111f2eb756ed08d742f4e2263cb273f68cb9b48180830510c2b37b35e44632675ce5b1846c883f245da67b1da048f1238264f8e035765279de14c03fdc2967b3eed16b1233e1272127abd65585efefe8293a2b44e2d73a01d7cdcd8c4160f3cf8cba571384cddf4b65f866c20f0c8e3870a86ccf1c05cbad46c6d32d352b2f0e3cd7116c0dd15d62f8254e0489c873a0ef2605f867e7318f4108f22b3b21565b7ae42ad7cb34644461dabecb40a98f64e53dc9bb593d585ccc7fdeb9b08b10cd60eb85fd259bfdeb018256c572c6c99d54f52ff9cbfe9f389712b82174b1e6694d2a6a785308e17b21e568d3f83d77835715324e94b2f561ac67a51dafc705d3363f746d9f4", "-4e84c6aeec9123523fd10252114bdbf36e4bf19d0bac0796d825570a3696ffd4f418c8d8afa4f78881035eabba655c61d4ddce1b14d17687a134ce8d6e2384f7fc5271021f147af36b07195d79b0bb547e6b4239439a4a59e79f430ad02d5bfb256e9cc6ce993f351f9ecc0eea87c39ed155e62b16906e488991413687cab11be97bf216ac380eeee1a14ea9164de5566eb48a0300f0673a832acd573f5f1491043a8b2be4a3ed266bfa1505969952c5ce63115686d828603a05cd94897f1d19287754554da41072a59bcb60e1aa9c3635ec009c977b395870d0f8168bbea374ae153a7ef22408b6f7e106a5ee35ae6e45f2d6860054c40923380b368f13d90551f18f875604f7b37480e1dab72c1a71aee050ceea7020734d670e3ed40d1e86009ee12a9c49eb72377f805a1c9c2923a0a9c934795813f408cddaaf47737c20d02d571136d062e2b03c908d1cf13ba4789358c8b1df54fe59ac233c1a9052aee573117fd66262e135d50d38b25a55cfbc12c68c60c73050b4dc2c5dcac1cc972761990b2843c9187388bbce954e8c25324f6c4dcbeaddf3bfe36d58a2e469c225b350a01be664b6caf21bac93452e95ca74bd490415f77fe4b0816e08748c589d02ac0cca0dcaa5bb2022f0c768638034f382af4a325fdc846818339d7b29503255b0e0faafcbaadcab7f4a2be6445240dd3859fb94bdf45ca05bf37df66517", "3d1895b7b0d8203b21ff9252bfef9514223e368f5b70dfdc64e7ad0515fe0ba7f6a9a06da6ec7936c94e376ca9b6b96220aa4811ac7a1f0644f5a595b8f9cdfd2075b6d848d14d43322205c739ba53673f2db5d4e596c3cc24c45a0c6879e31afb151432cf62d3530144862f25d4467a03af305339065799cb78167b64f035a7c6e004ca0633ddf764997410dadb033305a2f0b5812888dfe6ff17dcf234f293bdecd1effce2b0b9327071dca8cc73189331ddaff543c31aface4a622f938afd4b9c3a21e3973644e18f0d5363433b7d855f1ca3b700e782478cee65f2ebf87c27eda210c91c6c6ae127a4d773b09119c5f5c2d9cd8a3d3913dfe702af5e7aac7eb907738ec615ae83d4a5f68beeed8b80f7c299740efac182652982ed81a553a864dc5585b918015e5fc6b12cb365f17912d300f3d07ca4ae18081a0cec91b6c5134294434d1cce56361d0a972bacdf6535542e72246931bfb52322df5d03f394092ccf4250de85cd0dbb8da1503cbe94917eedb81e76c007015d23854a9bac3ffe2ed6d4e12c9be89ccdea803cd9f5058ab4729ceb1617a615343911ba3fd4a7f326eb1825ad1bd60f4b5bad3e559c8aae63f21342e2e224984f60cd18e5571b35d434853c177b252154849230acd464e1e5d1f955fdc8603424f464b07fd79eb285a5350aa0769acdb806d0075748a9c3b630666b723d533d7f0b929474bd21b06eed4f619130206a0ef31575d0ab5626daef6b30e703fe24ae467465f73e629ab9bbf8d6952d6324cb6fb6623fdf02fb7bf22ba33d7c4bd1a0092f209a8d67b2861d62eedbbceb93f0cf58a485b9f8755b675763de632d6540062697915decfac5b9daf51364d3e09097ec83ac0c7942655c686f05cf1f937c64eb243c16c354ea69a69bcc8dd2e4d4ed11a478736f73f10e55465ad537b5a55bfdb211a00457a0a18f22d00f6c3caa899a381098ae378cd8f9429a26609463880273949acf07f062ab33022f2768abd0857c6ed948b7425802aee3dc9977486eb43d4ddd53eb172dc43020c1fa53dd86833f978fa2f42fbe926d2d822e34f846016a6bebb033708949a4cf7ef7e719b09ad37fb03ed8b4024819db6ffbb6fb59e99b30c2c898bba3504468954e0cf7d3ea56b883a8be6f3bc22efcbbb805a768680e5b0d38991e206b54e4395b7488337ca6bc01870a55999544240b456d79c227c82bf40573095cd616a22a31b6ec18585ac0dc5e3a9d483b4e9d1566ce1d4e3fc534fecdabdecaec978121ed65046cbe57bda34dd459dd31032cad6ae62684b91f82f75eebba2a7335f04ff39d61caea21ee711a54abf57354a79d3d93fa01b1acd5cc387e9528d5d6fd82182a64e07178d0580935ba4250c24c772da59a518eb9d120d154a67418ebaf9c4fadf0a84a58f677e868e6480ac6f49fdfade3a7bfd2d8ec", .Okay}, + {.Lcm, "-c3a4990db30a45968cca123c9844985dcbdb5916e6c36dc1e8b4c069b4d4c985ce71ef9516f6ad553604c96f223e7d5e3a20f8c16fc32670c37d1fd7920c0bb180c865d4206deeaf1a42d2851109a348eaa1f697b595bee6e706e20bfc0927206c97c17d9e0e40c80d591972960df77c8c7d048011c38f1fab937fe2147a76355b2c99dadf309f354349eea12f170fc8f74a3b38eb3d47754139350155afc520e33aa1abd792981832ef721547edf4eb636f9aaaf7ec95633230e312fe994fd00934aaaa1264588dc8bc73404c2e19ca031fda84619986bc839761361044f3d3225b09258931d5d1a98e592efc71cbfa4fea60104067b7f005c1295f5f598ce2127d80d7c61717b1cea61c83771b2ff6038ed2d1a9bb76083e4e376ea4dd5310787732c8772d82f293593e1f535c989eee32a97b9e70f605a54fce7e78f14e272a44d286adb29a4d0d9665adbf51e3bbd27ef58239155f56204129a71309df4e9d22f343387d46c9971e531daa67e79e7e064717fb380436bfa5d069c1ebdc0e9cfe1cd0dbf420148c5f76eee41411a6845048dfcb131ed535211f82b05dd36de3225000a331f5d2b9355fab4e964b5bdc8281379f69ded764a08a5b2b18886952155c5e4be979413f88b526644fe1f41bc292edd86b21ee2afa96518d8cf270fa5a704ab64f648db29d22c5a0a934d8d384e6051ebed2f5c470c5219846006b", "9b2d3098c1dd9009edef30bbc48248e69d2653714f3854fb5891be87571353eb716e8b2623e3465fa1ffd6983669b7faaf362508d68fa48ad1669c5e01fc6bd70d864da63ebe88c6a3f6d6606d59478dbfad413c6278166231dd2b12cc2c62b89b99a110e57b3980acad9646264124b463f62d39cb59406bebf6cf17eb73017d8512931a6cfc066c1e983f5c689a9b78c9afe32a9c69a08644181c0bd7d1a9c369865b2c5ef17104f01be672a64a36919f0319eee18800ef53864abbd4e7888534c5ac6ebe0dd6e0dd4591afc1c19e56cc24981ef0641730bcb2393149516e1f94aa3386e6bb89d1f72cfdcd123fc5e14e3d89d5730ed127bb4cf5d5e675116e92763c6b25a8034365c504e18844052327e9175b505e3d9ad575571d61f0e3f820f31cb8ca475a1d222942f60456fb7b0f68c168acda2757231bb886e89be63e48274f6a78ceca39f27bf590845cdffcdc5ca71cd0664189f92aa5ce8b6cc601e6371e4de6168bf0806ee8815f5ff66aa5cec9f36361ba9a5659f708b006a4255c5f98581535f5d7c5c3c32b4670368f1fb1028bcbf1d47fdb34381c9fc83dc73b9a3c6d7ce20a16f4ae68757c70a949e15eb243021480b160bd3398689da97426d589d31d3918e637b11d87ee975783a16f4a8e3b0d71c0448bf4f6f82bb93cedcdaf17d32ea62c88e114f207e50d871bed6e3ca100543ef3829e7c15f43992", "769731bdcd658d343f603679f4821e96af2f8a6929baaefd0d7d2f7cae10ecc051075d923feb4fe88ed2ebcf9057c83b1e8b8efb1fe9669b530185df10bd6cf3d4910c3c48e12212dc4a74d074e5bfa0d2f99b8be8f39ae0b5c29ceb626d0abe4bd1844c4fb937ef53ee13ec1ea713a13dde600f99f67d60be58e63bd9af2cc74b6e62546091e8f4f800037b86ec9288882a40bc3226605ccfc113b4071395f061cedfc39335ef65482f1adfe9ce5d1c79c66a7267ed120802ccf0ea596b07df367eb7e27a1e0d67946a4c8bc426c3d71e915b7bfcfbfa384d82e830fc251c86c0a16eeddba7c1b1c4ca0a6607878761c4ee03af7a588b26e7fabc6bad7559981eddbebc12693d261257e0516bd593df7da5c778ea9514077c8cf10420452041462ed0efc616519319730e6f28059bc012a9eec4e8f1ef0cc5cfc7894a796c89d4758d11a5f4f5f6d47b29c733f0955c5f5fb7f767554b0fc1c02caf550124a3b7af53b0378b57e79de62c7e54c3ea20e8a2fc41772c9bdeca7061d7d5275a870e64ae9d9f820887e5652b168de738915667f53e8fe77a1045f696dffc6016ea2e65ad7c63a475874dae2c15b16b351068e967b4723f73e33a8e27132d8449665709b6800329cc625b9c3eaf6cea5dc4927cae17c3fd36471e175fdaee06a143eb1825fc6d0b1bde34811f6b6c929e6fac4f0f124e00aef004508333d73bec66973a40b4a681e4679206d7b04653b5fefef7f5b6f81cf548badb832198b1284077d926e01d453071bdd089e06d372c3b9244266623eb118501ac0a6b5332cc5da26c0f1ae06eb2b081597ea9b037c41a847e6cbabd68d87d49811260c83a3c390837d137d9389f504202ed67169304e06038fe048208e78ee07f4947e89440fd1e735d918bc51a6ba0dfccf4c015d46512774c854c038ef28a6fd5a8b27055611c722671ba835ca3c68c6995e4e51378ef77cca80c87e543e9abb13b3616d8a794210c57c1e54decc9d27c4294752b9b5807d42eb490d023845a0aaca99c93f7fbd465b4f967e58ad544334c6d4032c4bf727c01e42ad07d242a403ce1d461b695718ca15bdbb6677124bf406a1ea47f7a2ad26cea83403fd72180e1429a8b5d14275b65a88c2cfb96f14f92bd1169a9b81ebc46eef28085e5e412b67a1986cf11b2feb8632eaf2d297d5b3df9bfe260cbc60ff6e6f192151703cfa078de81823780e616038d20afd8195e6b54c5e3d0c3d245adfd206c69f7f8e34ecc8320d9d772769d091b947c9f65c0f05200a734bd833ed7d100c204c5756e088a52e85f9a46f9913f752b2682132f7a3b7f2b2b8844d937533f790537891df12e8ef7de224a049f78ec3cbdfdbe391a428d0aecaa94088cf538e36f65cb3afe261ce5b5461b6ae79aa341b6caeb91ebec548c6f1bb7d0102424b8ab873806a59b001006", .Okay}, + {.Lcm, "-b53727baadeb489594b073d7f72ee2a91b299380472ace9b43c45f366ef6e3139f5f3d024ce154a212c1d7d5999f41bda815d5525f48f9a73a562dcc355a908fc287f580cbbe84f657cf2296da53e2f7a2b5b18fd06ba52abab85d2ba6012e21f5d16f179319beeceb556514c2f1dab9732b5c35f102dc7c73a563cca76d23e18ac16216462efc7f3f8da51bbc085ddfda05eedc3563900ddfa5c0aac9f8fc24e5303bd0c0c012dd78cdbb79a75efee6529f015d2de55254827752daaa344527847fc33d25ac925f7feef316f81770876af6ca07dae0823ba7789dcac5567e3debef0026205889158718bc4e65eaa141a554988f46b28aa14cfd379179597f92f124d8923cec4e2c30b5fea9654d8dac731d62990bf6c43490708aa47c8def120d9659e3432e0a66d7c42bb90a41f37eac60bba9ae1a71a12e81ebf9eb38bf95fe27a33e1b22a8bb41c11be7d5212cda422521046fd80dd94d61dba947ce6c52c12862e4241548dc829b8a0aae5623a33e54b141bd926fbe36bf0150c06dc14cac3f35167b7a6e00f223103a9f79a993003a810b3dbe42b13612a4c57e8be0eafde1702fe713e4b726acb6cb5998c40ef39896a7f834fdbbbab3c2df808edfee4903088d666d2a356a593152417db1afa26b92dc3da9746bfdb2a2ae7b8d8de9607475719298dd6a0f8d3014cc35b13c34069b8250469bba0f52d84e6956780f", "ad925b668e6a3a1bb77744ef40034251217ecba13bf0550739c4f0cc638b14f93af91a9420462a21007a41e053b92ee41574531dcf2145bad044b43fbb6dd249964b97feceeecef12081b4073ab567e975873ab254a213ed78fa1f791c9611528af61b29faa5328018df9a9934bf99411baf85667641f8aba8400a217752abb20705ea2d1c4f44236da23a3d80b5443979e80fa4ef0fb2098d2d53213a9dde4de3d293316ee62817c60e67b00099c5d2096a0ef5d504d1b1a1697255a0cc8247608bf2cb1fb799ac0258e45076250a54864b2b96866a1363580bf081a6f5ee0b2b2d734c0cf7b1dce4d7fc25e124567de00951b4de87768c2201446ad81b514da54bc5a74dc039577d90e87cd4416027d245f061c03621d62a11a701757bfcf6cf9412ed76f4cc5b1d191b5627b9ff404909ce2e679971414dd021c89caf463574dacfa2867bb15745cd23efcdebb5b6fe731ee542bb2269adb7d6c7302860398616e852940b11f7f9c36604d2f2adb0a8f464eefd4857f72b7c13d484b147b3259f88391879cf94b30905b90d670266bc402a19d030ab0aa51fedd4208bc2dbd78589099c92106f9d6a4565ecb41018548055e10c3d2b63df9225b25cbc1485f563f15df7dabd733d865860046d7f7d5005bb236933cc458f6d4ba3a8dfee88464e93399578cbc8ef70bc96bfdc22205db06b1b865fbd9796030cdf6a5b226b", "7adde00103e82a7286cafefb93d360de7045af8a183b83c9da44bed8b93360578340b7ef8113459248446888a5376f645619fa5fc67b5f83ca62ec1e468d56322ff960147a569c93e8016fbb22ee262e4ed9ff3e45e4eee5083d3228548eba8b1e6ac0a50c99cb881ed9311a519dfc7b751687227e842f556ddd132e5a764172583d1a75da6249973504ba13afed564f5d8f0d1e2f3a23d4a5821b136d13a23a8c4cd05f5c5988f97dc8ff5f143090cd6dcb06d375f1b57fa7863457537ef082fb403526a42a63034f02a9839a2d457005d92fd74b602adb950f977b7aed49760604407814f66f05b9aeddc415c9ed0b9e9a53995d9e9e1e554169e890cebe8e9362645c3b252915d9f1dee22190f30d6540a6316b9038ea8d3485002dc24dbc2e85774ebf790d879e1a0f350ddda082852e808a936a982c019108080210aec212e14406cc6ceb1969a0363fd3c9e3c0ae66a7f34c2aeeec2d7b28ecfc521b75fee485da88cc20f1ce750d08d698fd8c1ed8f12eb62bafb6f04389e4d09d5a3a00aea11278b53dec3d7854b9c596493acfb0e771623f384c5cfc87cd20d981c21db164c4b4b8b376b57fb530d5523ce3dd3f39875486e8b51bca1b96125a3b216b190510be7f5042dfe85139aa38dc45cf8d6572a4a47c3e25fb6c030c0eacfedd12204c4121ab01b30b279e624f54d97a31ff8e7a00bb3653439e37fd91109cbb5534281bc621cb60efd719c94c274fa155d946e0785f55a212f89bd7f1343d7741d8753103ddbdaf5e4b9043e2e639da4f9072d9166615dcb6ad60e55ed20261ffa7f3026ad779f25e6294b1f2f9093133dc61be231022a34d2ec2a3dc07805a6879fd4fecd73718c2af08e54620bacb7247725350bcb1d666643537f64f144076eddfacf3639023e416e05354f91bf493a618fa84c42ca5b4494b6007626b1c74065788240cf2a822a903fa19ac17a33ef80fc5b8d306152d52ba529b45bfc03d7137a238522edfd54dbbc425b3223ca5275dfd7ad7bb77c51a7b00acc61db6f95ee20615abe6b6b929752f775a0a357ee9a1fe165faf4e706417782124910ef688f0124a56f1301a1fc231864289af511a456ee189144d1a8aa242b06da7f00e4e2d42322dbd5cc9115b0954f10b400e460aaecd5da3f8f70bd29adba03945938d7f6a404920b0c6bed41384f37cc8c46b4ee8b6df9b30bcf293e28acdcf9f81bade941f93694a97d97c7b8f390399395d7d6ad975a124d6350748457beb3253e30ae2c75f7bba8e1d0faf15ff4ff4e9ca21eb3b570517ba7e6dbacc5f5dfaf854166035f16c484313febd5da8d9ec3d82af0fddf22c24055471c626ca9faa846f563daad5aece3f7bf3a5102e5e2d6e8ba831a7fc48306eaf303646e0367488849392c8c6a6e32cbb3d562ee06cb259eebf69d47043c5f85b47666b2c45", .Okay}, + {.Lcm, "-713b3b6b487669dec856b908d060a50cd5649ff00c2d0b7be61187129a3f3e986edfa64c9785d58cef1f8b7ee468a8eba8d7e503db0a0ebbfd204dee2af2b1be74a8e23b6a2cb168920894715372f63dc809ad7f8845d86e758b07ad4b8eb646fa5c02a84640761081bfac6bb43f951df1a3cab6385516294042122bc428f99a4a1d8a90fa6275ac2449929e8d3aa67464c7bb0cee9f5e6279772b680e237c97991d1639e7213ae7330a6c7c7158c331d1af5850e576a6161cab2b596e410d705469ee618d76b8dbbd32ba57ca046135da2dfb0c34102bda93286361bec83b01e02ae9782996c956bdc79b2c9533a4e1b9e33c515fad33b74f28fdf5fe443bda435dc0edaeb93d298e453077e7eb2ca08e468b782eefe4c6a3ba6970a21fed6aa28767c5f557d5f366f96eea9c96f07f3f9f5a5f030ae3f82d085c1b0efe853be7a81703863c828711681ec3f70c2c9d712f11a7dd1c1bb2b6b94d8704857cc894758ea19f57d102b465a111a542282351c196df78c3e04031cbe87a35555cfbb9ad886050e35185a266dede56a71055b8b4190258efa06f078a456f28dd05b35e81fe0b292c9bf8a6e8f9c5bd532d80a02c961dc5ed53f0fa9b9f774d55bfcc70ef0fe58203e21821f940d7d4f5027df9e74ea4b6496df738754bdc2a34af596d62c94837b8bd53b5096c176846a87792fe60a7e5ef15c2e34165b16f47af12", "cc3aa1c1537c311a32283795cbbee3d0b456686a2cac540bd5e3bc6298917bb525248f91e69b54a16ec13f25cc2ae93d2dcdfd2f17f048b7356c0f3402d926dc1b42f8b987654b7e46227d268b238a62070273dfdb46c47f42440836fa2055a82b20a9d7f1df765346dfb586c8d64357c2e385835b99f9c09ecfe0f69bc029cea3ec0a3e8b77b714aa6d3a0f1b7dd533cab275654bc5081e768a8d2378a41fe53cf964a6b63669d66cd1e4899171dae7d5211a8840ae7c9ff589848ba85ec78c514383677f0f168ccafa1737b52f4142f5b348027b5613364f0c39fb7f43dd28de42ad42a1e4e10fbfe53770903a23dd15dac805ea8355d53d71c1bbab9d6cb2858cfc974908b7b26b00f27e1318f3e2a803b866077ec5823d69631cec034d6cdfb31eb0cd24f7733dc8e79c5a67f63465db276df5790ab10cb91204131c80ea60edc25e86fb666272361d3b77f17668dcf4d1881d14ef038b1304236f11eba150af1a1f57c66e0220dc4bf9ad61980ca16712554865cd84ac00c825541bf2197110c01badbf09ec109dc4d06e490ef4e46cf0c17773fa90e3b66944bdec0d8cf8073442ab1ac54ef0f4221e19264884f13269e7ee8e6caeae286a4dc07a97125af0eb164114a3f7e191748105119dd300c28b8651d3d029937c3a421fd73b9018de5c760b249dc58cd9b52a79bd5d953b1153265d93ec75b7d0ec0503052148", "f0e3062c92ab26304804e7d8bdf0cda6f28139ff9ba1b7ef5b6825879cd56abd996314d7071a2efcaed3fefbf0b26ae82c3a40beb0e140b9472bacc02d704fb3a918439e7d24f9abb7fbeb65567d0c3e6417531664ba974447c4dd670980eff58e87ee6b41d9f638e1022343d1f81c4d6bc965ab691a31b5b98e49c6c14473de3997df16bc460add5396b715f0fe0922d6aeca42f6415d1e072e2a30f20732538f2f78135a7247a4eb33a591486538f3c7284cc89f2e00c4274d2554ad8360e727a29bc75658a54868a7a3417da28a88c2c86fb2dcc09c7e8a3f832cf149c4cb29827c729b3eda55200731459e1fd13561b3012ceb0438fa601e3bc401c2582d88ec8bb41ddd685dd66a56b96edb549c2b0bbaa6571af452b32540b990829f2951c5c7b7f15392e117307f77910b0151124418a2fa2fd8c408cfdd9ed497b23f8dcee2b4dad0e1507a2c832aebc4ede49e61cb6bc37d6fbafd754f6e1ea3aba4674e88d083378a96c5c61d64399063b8956aa695f0434890a8be4aba63f08040f0aae1b51e36986b034bfb12d081cf8b99e642c124b1aadf5d1e5b39c6b89cbaad98bdd2c779dc8164b5fc1ed3af641414f39246c0e77a5486397cdeb62056df46cc845ad956546dd16f12ef3ad611bc156af011cb9de853e34b8b527e95d7af82f67ba91e48e77f7a4912e9907878878261ae5a090463faf6f393f090aa02ea6b671c4c01f6dfeda0f8a576c40ea31d75541479c6cc7bcfd3ca9428a4048e9bd9844d67a0ae5c09281292b80cbe017357dfa62edde3701f756ed1a73bd5c2d3249ea5f9d3bc5876cad0730f109d26d912acae547ed057174a956955b716f02b58db30cf8324c3637a720886cd26bc704a4cc7822f307e6d4d6e0de21e7e5f4f6bf99cedbce56232334ba5dcf2a1b7cd866231863e68576ac7ba8c6c0e4c4fcc416156c73cf46c864418328489e0e37dd68bd23e51a171aafc22e4918be115476ed67bdd5e0596663b0eb1712cfc41baad8f0a94c04a309b4ab1c0e01a358cf0241914cb2cf594cd4d4c81ae2ebe0741b1cb0a104a6b683735f71ee56f1416fd3fcf07b7a6ebbd33cccce31d282e70c6de25ed56091ac4e72407cd082c58f4824038ba9cf79f13d2a95fd4cc1085c6df69b7eac90781a3c1e9cc1ddea81cda5b7d366c147beb5ae2901d7af37c85fd63eee604c56509c5d91710f976c027c5cb87601c78b464b30d40a3c00d7f525883f63e8e9221d6d4999c6003a531be0a48221d75c1ae725d3292a56ed4c54d44414990d06f6f966412e3b70e0e145bcee4c8afee863137dc3579f2aaeb76165aa04721197d06db13e613afa5f16e60877826a86b9de367b978df4191e27c4ade53b133635033dd1416b4cd53c8bf67b281193373b27c93b28109fc5c4aa80cff7e72ce70190f5363521481557872e17d8", .Okay}, + {.Lcm, "-bd284517b0782b4bffaae3da1d6285f26be65b5679a47338da86942137c955e404bdca677fe547b0b534a80034f4ff587ca36561f4d0fc62f216c6ee3b793b653c90aaf53b08e9d8a9cfd451e067a404966f9d32886ed4120005131729ba8c720f62b0e6c2e1f86e21c337539baea1b2f7889a7d9b1e268e07ce18119080d209bb95eeea0b5051146fb9b207ac5519a530cc7845d5fea1e2cfca7060d1f967c648a9e30ecb4011be09eb41242237927bfb4a2e4eb7bbc96d1924451fdc56809ba793ed06e0d1a2ab14617649e2c4a2880ccfe2465aad75107bed21991f1b91dd638b55b14e52fed82481e56339c2a8a659ad5826854fc553528b2ea67e0bf6dee42c314bc92dfde190e9d67c54bdca70bfd2cc60f7ae6f63285789b1df8852c8efc87bfb8281b64a4663ae89457244e8d6e25de30976ce5c905f7790972dd9bb332aef772c1ddcae4e97aeeeae2759dd06983a2a4ccd5abe7ad7d72c932e2b477a105ed12eca2c6ab59c55a4b80b4529bbbb487cf497bc97ba166ccbc24f7e0a7d086806a37f0389ecb0bc8313730721d59b16f56847d61102ad362f11874c64e5d026f62425276299e9569d90289d0d530ff662fee56b2dfb9960ea08705b5cd12f5538c6f7eaf910de6c5c15ccd8725b8123724eeaa98c7cafe97178af0f54a56b92823818fed2aed70c152f438813c67292758588f88abcd0c4ef14ef630d", "fcf8524ac80dfff6381d5ae0207a0638f84d936577ebabe4ff9912fe0e66fd47fda9865835decda300bd9e9ebb0c2e955a31f9db9d8fded6b34bbef49737e2fb9fdeeb52183d27316f7a026a331fd830d44bd7597688c9dc2a5b19c6ac651fdbbe5a5e96257ef3fd3822d48d82b95bda81c349b0e27708a7767decd512ae19826c23fd2bad86d604c0e2862aa65d376a2990b200ebcfa8a02075b843b8e00bf13d097a3a155b31eb8c6d984e49b72f93f0251da05380522c7a1885665b59a0d81d2746daa8033320b72e495fecc36d763e648dc78cdfe8b573872ffc153caaf363684ddf1044b7f4c3f84cf3e4719794b2cf3a11b9cf35029279fdb14a79a2679c21bc9f3a619aae3c220bcb3af2155e5f079c39fb6622fbd7ce2072c14b600b2c98240bf536705ee3a0c6c4b3b7bb727976fc3108e7df3340ee812c125d0105824e9755e71850b0a2fbce58f8898b4a885133c8ff31af38414641e605e188b6f448af9433f5e5847243446b2423fe38762753776103470b3abaa90d484cc4e16efd29c682381c625f2502f28709248ab0f8b6e2426fecd3e641cbb14f8e7cde5690678375de5e232d9ef6b52ae9685eb66fcaa091b3cfbff7ed073f57bf6e8cf1db2574bca8a12c797de53b2e81d8bb0a355d71ea3a211304ca3aa06b06895174b6f56b9e69e0f32c5dbfc20c0037c5ccf55ca58745b5d077a295b37fa2f4b9", "baeb1fd468409c8f50f416ffb39e3c6c6fce66c1d8900e38e9902bbcc1eb1f5a83d946e71194587d81e1b23f0b8af71fad675f90ab23753706ce96a3cb9b0acacd5950207ed8ce1962aa5b50677ccf33e0525556fd407c7d73f19f11e6df5e2ee4032c7479f823a912d2400ed542edefbfdab73e7f01ddc9cd8ff80a5a447735b5034fb8b510f640c4e960dc9a3f3a56233eb219e01c02cacb1e4499153f21c343a2ccf35e4964503cab569f1f7292692e397304769c97858853970322875f2e3667eef3f09f025ce9a7fa4b02c7bc428664d5d62dba44788cc5b22143cd1bb6b7ce00f9dc56316a86131548e84e44890fbfbfa4d64d9c0da97378a8244256a937f09655d4c2b286dbdc4be03e7db8f8c38dd2acb381856494fae182091646714f8886ade11286194a45e6143d244465b5cc40d740211ba3643b1568731614bee5623170621c0f5e21e5af55d79314d00007c1cd87235ee56008d179ea0ad4f05351e4cce3c02e1f72634ba820c588a570183ea4328e845d4a2d16e1f9c0f6378e07ee1f5f00dba16dfe98ef3071b742a24fcacf907d7648559dc6e11ec100c33fb166bc8b56ce7d2c984bf8563d367549ccbb2ca5b1fb020068950fdaa9139d6806d5f2895b4266e995240519845905efaffa0e56d43a409162470a72ecd0b5145bda287345f26c9d6f616682e6b002c7c1eeb0f81a22f709b0d956c02f85413ce2b95256bbdc13ee786519162577f62875d80e80827cc80fcadd749308c4efec6957076f5d7a9c674f0ac47961d4765074ac521e96c10850e5738538e150088d9ff4e2f497835f22c721d2cac0835eacd658fc754e68213ea087a01e48700edb92085f174fe52f34d41afe64f20bc38ea6af9abbe7c6bb1386c6b0bb9d7137e7d1e65047325e59294361dfa84a2a1bc1245952fe450708ff76ad541af59a1ff060ad4cc00d26aea42a0014419d4220a5d6e96c7a065ca49a5f0652694c462fe09d093b5dd982daecf4379c7f5d9aa6c4e59e1faa3118451f76c188b5157a892bda17a4ba0ebd8400108a31e019b43eb00b88270a7a4e69d0b42ca48ea66dd43f7d867567703cd0fc24d2a1690a6dad40bec98219d13ceaf662f2f7ddb7dfc14aee30f5ea7762c230f8444bd3260b9736725f4e586a0579203e86d76a61c2a5e659e659330ee69d13756d708d451da664ea84c19652e229e822682dd8eb315aa2ed4f3f9d7d3d9ca7e03c106af5a919bc34c1f356b9ccd3462b0e2effb74a64e1df9f8807eab356b742e78fa26171ffa21cd231bd782a0a7dfe6aa0a91fd0642da7c616ebc76fb2b61151b4c549934bf5f5b5b87b053fcfb1c0f5b1a16124cdc758b8ea86e3abd7462ffbaa822711cb67309a3872139df9c9a2c7ae887c938359ef7d155aac0157948327608d8f43b34faccfee43fff27b5a8305716ca0f865", .Okay}, + {.Lcm, "-f8139dc99822e32d6cfe678dff68c26b9dfd2efc61b500b7fa4c3cdb4093f10f29a95214b64df2210e92575b196fa4024d90898634ec66db488bbc2ab710b4d2b684956adcf677afd23fbcf48c98e5e6268e1fc0ed8793088d132ab6b1604d045e4a485ca7a2cbd6c0b4bca718af79a58e5428ebd286ce23584abd4e17942022066844a6c93967d3b47ff6441b7cdb8127f8b5fce3d61499b765c38af45468ce2c6b709d2cd425012ef4bbe53053086e020f85a96352d6a93e24e6617a6b0d500e6abf1d303dddaf52f6197bce4f9388c6c747462464ac15ec50dcb1ef29497919b04b6625e568643b3c9cd0a427b79d456592046189a58d1b2b2e19b6b5916479475527fd172357c2053ae9f722c75fd303cede6082496614e57f2dcafa0c7afb5e69d0209a6790bea4e0f291031740aadd4130d5e0015ac6d1c313f31a79fd3fa26008178c0df5ffbacf36690548759f0e3612357387b97d36502cbe47a34dba89d94a70be26dccde7c3aeb5e0b5300d6cdb6d2fae9492889afc5bc0de39177dfcd399bf69cf0156a90db5d8c47bbfc31fafbb9e53dd4971d3afb72a19df4158af419da4b9dbaa858aac0a6a0adfcbb4e67b213161889be9cae96e4e7768ae32b12a946a4f8f5076227a1043e5742fabd6b6953527f73fc5f1150bbff885e72351b7ca6222e0301b45246eef6a4aae8a32ee1ccf30ab582c99bf57ac36b697", "-f06b65b6fb737b5861d04b51b2dc6c69e44bc4d787ebbdd4bfb35423afa9508534606c85b88905abd91d7e164923f35947b9181622ba66e2fed550618c091bab0c29aa0b04c314c7d720401c9b39fd056b1f2ad4bc922eafabad3680fd27dc16ac9a0d260d0750e960dc3a35cfd47b9d94dba005ef684b3400abec14b4668ea0debccc99b014e02e1132f5a651b9a4265c6b6d8b22bdad94140514bb599d4df7ad36bfca21db3762b989735bf849e98cf27cf5231f0d943ac3c2909b785c279da80f5910de479cbca906e2e4660b32b61f1461e70f0c839ec41f59e8b05b271761c9b32b74697cd1e0a48a42606ee2c5f569a6f70de8756e811845d00904fe10049ac33797ad5c4068b71a2b4e0aaea8f412b02986405193c7e805187c03c2d19410d3a7a7837cec4456799ae512b67fe2421e352fda7cc2583e7218c8e22d8cde923cb0fc3e44d3afab0e8bc03ad2c66fac36d1d00fd043a893e1e31a5a57710292bb9d21d4c4236030d117cc4f149761f71a57af08e010040c3ac45c6c7e6799586d1744f51aed372ddff3d1a6811a9a025d03860dcf55cd85de0bc7908e84168c91cae84a0c57da8ca983890a0b4a2fe6c04196b47d6ecbe60db4a23820379e916dbad06b83ba313b8bcdae7adc0d304a22b1189bb27435473f7d9f42b4d97724bd9820711e518e1eb2ad115073db6a66b1837f4b6c47e8a741d859993b1b", "21485a19494029fe273ceabf587291919de8bc24b641dc78c7f726f39a2d9e1417be504858e1d614efb3db34a40a9affed264db1779236b06b06a54e9848649b58efb1f9d22f6f772e19d56b1935e75b3301f2f7fa46a04566debf7e2dee3cb9bf30a676eded738e55ff22b2038a93f3eb643bc19c94073caf0ea1bdc079cdf751c06fe73710e25a87a0b1d09836c93f4684432d84bf19c8f7258f38dbbea7583bbc0f031378868b6acc72a136e8d644d08da1bdb608131608b3f8fed319294886418bcc93bf2919cb9e78bb254b1ff59a62d62107d374e64c49bb4ba396ce642f7f2b00fc1aa511bbe76c6d6e25e471cd1a6f8bcdd99223c3215a85144b89d6e2a41e09d4aaa4b2096f8c2240dccfe2d8eb35ae498c8d7a52eb4d5907c4cc2f7b4e4af7da4798027192f0583d8288a56f232d7b9ab9eb26d09da98a7911cf706a95f76b4c297660b7d6dfae932c2b93375c56c01b0f08a85738a455e5fd643c609dad099eb07e657694a14b64ea6672b770fd58fec74024e644b23cf19d0fffa5d63cfdfcf89bb365ce919faa3cba5333fe8560ded32570ab33bf612e55ea05bc338bd19635edc7c55fc77a33e0dec75059af423b28cb6d64941194f465c69211dccf7af46d60d5d71c228da1824d6b54e308119cb1f7100fea8b9da247f8095255165de6d49bf5afc4751cd0a3c847d161b97b94a05a7b0d7eb9c08d3f61ef55b3ccd9aaea1d077f16c19c746a8afbf87e6dc82995a15617ff083c5e854e84c4e7af1e7035362defddcb74415bfa7a9c4ff0a62b464c4181d8d6808eb128f9348c69f63eb5edd14f5ab6ec8f086602cad99a7ad4e1f15403ac3bdf72b994da33a6f30991b6c2b85d28b1394f68fd6c46f252026923e4f34d332a112e3e6a4f0fd1b31eb696ae9a806ca6cff0171360aa19535df439367fd0ee15f54169caba5e491fc0bb9e2fc45d3766c9f1db5e5e4e41caa7a1083ab751165ff99e2ede5aa08fa25cf1ada51a0b75cc374bd59df85c931dfe52702105a78f79b65b30339f4a2204d527332bbfb7746e896d4460141ba457c6210dddd58dd90d91e2e77460b5be2e0f4a6a2913b36bf2b9131699d430518f558ce34b75205b50de48d0e335d70c0298194f82f4f952522635952fa172051acfeeef69d762a96244e368236b05d173e265126ae35d65e5ba24f7f117c61bb065e4ebb1d8b71e823b3b317b0f09d5ee0e0d6344744478069b64ea7fd02b88bb9c9d4c751fc1a9f683c8ce27b62902f1b729517cb59be325f44b55a118b760923005bed81e134ff976b84a4e36394834b68c10ae7815a7e9baa3396f17429f92cd032d2967dcdd5f8409909468f885a144dcd82ffc227b47566959670d5952e952944ec30a4c02bf0012466ccf94c29b19c50daa37d33ddf5a601b1cbd3720c4ac7967c83f4dcd3f5c3303946b", .Okay}, + {.Lcm, "c9c8ae511f91596ad1534b53a36b354f702c2573e1fdb75ce47a400047dea3e5bc8e16be5028b42ee75528ca5fd417b6e60625c211b3e368341ce2e32749e526e9b48c35ef0603865032ddbb3c3a9746ec14d2b129f20f1136bee5372cf6c318bd9f0613e37c7a7c75c0232d5b7f7cfbc97a5d3f37ad186a4cc76119c21b517a7d3f3e7bb63d7df84c236b760651875b81ab084d3fc46354262415e854ddbe2f8f68dc8b500f63bb63a45d9a28f6e36994bc86a65c307837cbaf9d1c2b2bd32013ad2d76ea7ec4293dfbe44929e407c0e387fa1d1b1e5acb803fe03e7e773d0f3770a702a947c3c6da825b746aa3efad4f0ee27eea4e388f2cfc2326eaf01207e12267452335c1c37711763080814defa4c39dfc0a13aa0ba185866b3bc04b27e12681491c3d64728b6e0576efa6c936a290328cbe9df18278ea665c2a9271d004427f181da7e1d15e5f2cee6cb93bef016c064be5aa41010f78ae5fa0b19867dd51ac2ef3c1223d5d5276fb1cee9cb1d9a1dfab61d614bca67cf2601c115bdf04a00e7085f2d779e7ed939146ea62392b7f39f59c5a25c6f2dcc1d02b7cf5418f382c87593dcc74bcc6fb7bcce0c455a1c0f73d251a9ab41fc5b72acbec749501ba0f9211edf5f185c5a2c5045816e4eaaf08c1a648cf25140d9299b12c01e8cd52a091d11427f19854bf24e9eb779506ec34d965d72ce025144fdb6ad874fa", "a37e8f446a949822c21f089be63bb06f364ae3e627157b9e66c75761bfccb7b4a9ae4b35c08b10439f57d6c621345f38f227655e72b3ce03f2e4f0cdcb2304c65f869bae949e536e2016a53e0fa36a807c975ceadf95c71c422ae7bca7c51f9317946a5ffbd20680853f348b60b9b750f6d289f4afbd49842d34112fa858a7174a07cd6716a819866f26bff7ebd74a3b4ea13bcb609b024fb604c50c44027cbc934afdaa942bf68f9a6d384d95cf2ae9d391ab56b2b99031a2e77f8abf8d8b9ffd0ff6ab80e742599362ebd2ff393a539c68923a3f7f38808a76fcfc6de5ca7c2ba1cbcecda3857da53051f4fb5299037bae5bed2379234cb7393bde1233b4ca06aa71b2a59a0a30d50b47ecf994ab1f950a6f0afeb6af65c7fdb291c150fb17f4a0d4a58a97f3773330c53879304761ecf8fae28f2e40a7992438891cd060268ca6c57851a4b83333f30466476ae235469e1be569afa3b06b7ce040abd893af460037f0ab60235454504bbd2e424d24cb519e8908483e576ed0e0980072d93906faf272ea820f474f8a9f2777e5328ef6cbdef3fc78ea13491934cdf67c64eab9d4142c5cfcb6dbadff5e4eda43c88627b619c6355b5aa3377a2ae71de3f956b345e0e279853046d6db251529c3783945424c42fc5ad123c10fc3c83b24a8fcc51b1242731de1ace9ab50eeb1ed9d0ade84ddceaa44ee3f34a677121b0ed7cb", "80de88b079b6ebc4848bc6049d6a9f6daaa7e909a48f3543eee1d39aff1be791717b4f657bb04e0297747adcf15eca6ef8a84aaf9a0070078c63f85102bd3a0ec7558cd541f2fc278d211dc3677737506dc5ea072240db1959a313ee3e3195484bdf66a63cc70e1ca2c1bb5d6678641573c3a6c11e2e93de96187a3a76f72054df1b4cd1be47be7feda83c34ed401bf1bb079ca589b09cd1e8330ed1a386aa4861acbf847d92f9d058f11cf39fb11350138e3be4e7406556df8352507e2a8d8f4a5a4593c018b5aab30e7567338cc789a809014e89ccd939b6ce9d42857f7139372bf66bae78fba51c0eb78c4df08d436dd8d405b19404b08642c4f3a1287588364c19d086428bbc7a060f44e41757a4af42c08e9d6c22d2e58b3d2e828c465ebf375a116616a2bbdd1c44c959cf47a98aac87d51db4817fefe816e6d9c6161fcfff5fefb3fe4218a958f0c8328c02e0b9bd6250b1c43d2e628b57d6bbf429c243bbb5776409b529535a553d598e985b4bd27e95da79588a61986a2c1907839a52192dfb9436cf247f402d7b7637a36a8c36c91272a66440dc0274c5ee5fb753aa4d806ed99bb299cc5cef390d130778574dde5cc707b18894e5b3cf62dd8ff97edd9a85751342d3617281503caf9de0d416efb70aaf189fa9a8ac3a79d591d25abdbc245ac7dac151b8041529736cef63e36ae588388c83e27e36ecae694656be153f169605304f5e335cdb8faad419deb01837484b3832c99e0c651bfcabe4163b794b74be96b034692fe42ef614aa0a7eb8963f1b6a52b84133cc055f5dae1941df2f4729931d75f1e46b2666a43f2d2aebfc5210276a47c61fecdceb012210f9b95d95f3f4d024252014d61fc0892e6ae26de0d0340872291b8a03f93f221f207de6d2a48aa0c84f601eb05c0a01ac52403bb14d363f422621ccc169b7d9fd621b4b826676f35fadf8559c964dbb66a4e079e3b844df443c81d38ae87efe44ddb093b60a955ffc0d19b4d811e8b5cc1272a949fe29c86567e47a59df824a0b310e3321d640e9339772e27874df4d7009f37a9401e90eca871631517ae6246c2148addabb902ee399e736c45604b559faed7989f5e5e202d37fec2714e94de838efe297cc99bd7960b8999fe92650606e0288e9a3f0ecec5f0ee4871c8e69e80aa4c6842bc68ccf83ba0e172b52c4d8e650c4f75f44ee454411e9631b18374d19211aa5da02247843d7ed5eb5c1d55b634de03dd9e8befe182afd753d00f0da9f5906d1d9e29ccbec4e27f0779902023c82e33179616bce84efa0605d1b382f8131447f624d4bb8d198c57a2d29f3de87245757c02bf2efb337d26443778e3e910c510563c76c8ee2d7d70b0f113382d0cedaf6f8056855d279ded074a792832ea3664fc40932266be3d6fc68ed6c60bafb7c95711226bc25b57a478eb83e", .Okay}, + {.Lcm, "-acb4a393a6c9fea86a91fa019e59ac81d311f4677ba3d7229c8ce33698ddb9674a06b4df74186a5bb45453d98f9f2d5c9a89e9482a384e3b044c73623308b4c1f736a4453179bd1a29d6ab41f6649f69aee6e9cf930c7fef28ea26a65f084435f81866967900e8d2b7092efa0452bf4b20058d471ea63ece402153db63987c74b19a3590730a12f56a0a06bcb485db2d310c57d0945f4641e0404d062cdab11df3c9670026139c3b2a72c49ec56acd257418ecc951a04e29099eedbb5028acc6f0aa7f8cc204d16baa32226bb52a636c8382394e25b81e75bd8713e23c4f59abb0b8447a2f4e9975ae62ec3190dc91b9c708c36b551c0eef072e051d208fe97c62e8144929c4ee58780f7a3b28f435e5180c7b731517a359f482ae33d7bbb8784ecf3def28018ca5e1836818c3b57afaf2e37f3a6055bd97df595aaff62dba75a9e40ff7c80aeb2e3e5432886589a9964947fb90a27a1f8d48debcb6ea947c977083a1f1455c12a95176a3db23dec9e7c121054dbe46096853e4b9fbbe8d4c197639e1fb3c4db0734872447c5ab6282de4e2ea92ba923409e4983990d92202ad3b10e22a1b0bb0c4e039810a0a260eb494192d984b7cceb00514a60201545ab1808ede0db2cd8330a061ab21ba5b1d79a255b2da476830342ec9a2f7363b3ef8af3fce7baa1e723c493ce159397ee084dce2eff21cc0d09f17d48396dd2d9d09", "c53c6c955151eb4071900da255da7890aeffa89d76a8a4e7f6a3971919101e5664a05830aa5cae18d089b90952f8401d47e9ac54096d21682a49bc0bc6b09ee84f65d19ef38736ea381bc506c3e1d59b0f12018804d34e0eb26007f8613a11ecefd5d58776a9b2cd70e58be0c9d344d1338f7bc54c18dcc67a3b3f4cd81ba672d1e783ba767f4e07780b2c928cdf8b7c0a4891b11da7cc80c238ff975a3c62f8ce17cf5b5afb4d7de3b04158be630b61b225d121bf9812b58c13ab87c519ecdf9992f553845ccc19c1c98d5ce0d4fab09208dc4abed17488e54197983a406e35623f6f533dbc4768fedb8cc05b35be1e1eb935b2d8c3e57f363cac655db455d1cea2ad810bbe191014a22f0b7d62b1d5b21b30657a4a707ce6e616d91e7c465f434465629807bc86792610a4d39c307b742d69997a6806b4ca6f84f363fcf8585d0abc730cdd95d960a50ba63be9ea7ce6ed5ba7da6d84c3e55a25cafa1e9b8536a85c322901daee328195966fb5eda2086222bee4bfec331f5b7f4fa51eb2d0771f72b8c859a7d4836ee6b2bd0b07abef2262ae684fd8e4a448ef17c4645b8468e9317b5084b48296bb8d86961ca456f9a17fa7e1b85a328ab68a4a18303ee0e7d2f0686d8014739d3acdb4b16018fe1589afa1325811a243e83a504f436a35a2003681f701dd38d520bbf9e7bfeaf0275d966d3f75d1822119f84332a6f83d", "850fc577e6f6733b59e79e1a5027d825956b95bc72e2c4b8f7842baf5aeca0a49aa40f3e136f8d766c095f7706e297b598cfc8c0c50882c5a85944b4ea695daaf69c6d666128b3b198672493fe9ae3133f2edd57eb20a9caa79863af4ab7c85ff63ddb2fbd5e2c2b1b362445aecf420124bd537bc0bda6abbeb82cb173bd6a3b5fa7a4f365ea9d5bf6d275ca765e553407addfdfc0e20cb625f8e7bd4928e965269c38e3e26eb602ec7cbd361a7291c2c6ef4d654f6fcc2d41247a112dafc04294d83b290abc6d8e9b8c2d65c5030e58c11eaa77bf716ca8c616d1dc3311a592febce5c338b30df29cbe662dc82aeb2d9246765278ef29e26a82f5f549d9fe5a0e2f1dd1c828ce92313780e3d305c83bcfeaf9b85e1853a0967a4324eb03faa139ca30c8d679297b0b0f24f4fbc561de4d1335ea0462c525dd961b6073eb1eb936ae79b4e0a86f9979b496bcc3d366ed9d16926b943ae22d9905200d3b5b209874564f764c4fb472812fa1ef414c8fe7d3a8c5f17281a575cdbd1cbcf050018ef1e194232a658ef9fd48effc116aa445a281d35fe3b188db6bdf5bab4dbb978597d154ea552e7abbed3acf5c13f2fbb25ebabbbc02abdb1be6f5482a08ce9e54a35468797441f9ab6cfce999be7b1334d5b1c6e5759d84cd51bbb00c25c23af2eb4685db2d4a1c0f2bff337ef5e0dce94a28efde7cc4b402e7aeab0d854b3a78b498413cb2d6a7c33f80573cc76179f54e418e0f6ad95178181cf314be3b58d7d2f553b01801f70de76fda734b36572df81121a7722fe7eb47320d0f873bd9b9324436fea14dcdb03cd6693c75d14b46bba40934b51960fcb5f061ca8dab5b38072fd05ab0c11da6b4c2202e23953315bffb0b7a55de78c13285ef5b995df0ad1c5d6ab69b387f6f3d0a7bcfb5f90f7aed7cd4342b93592b72b83944dcb1de042ad75634dd8efaac8e6862c27fccc22a509d5117364e76e1d237390eb16a51a656deeb35e2096d988b84fe29721ce359b28f3f8f9780e1c398055db0ad77426569bcfc9849b37180e6f718ef8829ba433e86341d04d9c68302ccd8a54541ff9fea110aaabf66ab62c46f64b34cffef233bc8716365aaa7ad955eb70f38d0518d06df3bdeb160ba15e0fb96c9d7b0de8dc8aea4c6988989c955b00c0054045135936d9dc53b403f8e63cb3ce2a3720474660c60b5268d39a0cf6c9e35d30c26c6a70fae8d9c76e058a330e90d27cc4c98161097d926214809923d4fd94a41235cdd0e81ec6ce9e77093cede1401ae995463bb52f5b3b304ed232c675a2f04a6e13342e0d19c8a8c58674d6691574e621424795d66f7db44dab7ee903cf783d3b191d53a1e6b460053a43f0b3661fa5eacec7290c0ac4981efe4c15af85b1aa4cfd06c25438bfdf96064886ddbbf22f51ebcbce743f0aef383ea15a6d179d52325", .Okay}, + {.Lcm, "-7b7b46700b96e299cbb482385a83104a09476cb31d0a8a343e35dc549fd7dadde4e4f4a2f3d0a9f20cfbfc57e0c2ba4ff92bf8a6a0ca2077c787981be995f2275dfe6c3752876fb95dd44341d5309a665d29f1476ba8cc99e50be8686c066d802e96e0c2f63b9b29acfd467b3785d9c337936ced441f014a7baf03e8a23a8c0ad7e46e100d95ff5646a937c5639691b7b681c600aa5f9727c5c159992b24183f96b747b437796abd04c159312bf20f4475a711e3b78a4282d7fa2f58f7e50576d1d078836e776e5ccfacdfba2e9dbaf43a31f5c89f3ee1e955bc358802a9bd07aa94469b86a02b140727f3c5d24a9ad08c70958466e4f9fab659201543a421161d066d1ed942a19b44d8209ff4f4c1e5d0b1d23c2b4e5dc608b95931593c394f818b8f0ddd73bcbf90e0b414d64601015809a0d23760742dbba5a8ca5b1d871b34c66bb737c49bb582e004b8ed5a1de91e1d2d55ee71647429c17d81d6049bf12ce5b67d03ed6f89f6c3fb58108702572ffc15c8ad0fa39f68177bc8c30eca6acd5ca091d9bcb9e0335deb91da18541890e7717c9f0daf3df8710e62202079a7b9b34bc1bab3c9ef4e1b385b73333be495a50b6d197e88089cd082de68480ad87b43ac64fd127abe93a745cffd6c9f00d3d5d67a6a60e8c478a7923fbba126f13a203f58c032585ff049c459ce5e270ece5ecf04147bea561fb9964193ff6b10", "5c81172841e31d5f3e5c9df13cc51e86ef511098369cdb5eb1175bb042d26bb6fe003d955159138a99aef1c1b8ae3c5b1e0dd21de8ef1dace64fdb43ad6a9dad3f861cd7f4081f86bf69d0fe729c57adf77cbe9f4cc83f96d1b307628ee3166508fa21fb5cf076ce2171aae193da27569ae969a96c590573cc2910850b6a1deb9e971db5f6766ae3784a18039b258c157f13b5c857d4598cbdeda9a6894bc6886670278e57214da0380bd2f670f3f95ba4bf91dbde89a1ec80baabf6bddc850f09c7480a03aca3aef924397f3854fff516f47f0ca26a5a2f045763c1c2565e738e102aa095b5dd5f79998cc5fb0e6e2d9700a04e475a145fd30133ac67fee8d29cb8bed796fc6fb33fec8b0bcbcee7b26a0af39c406780cb6dfa45fd91b678c91ee48fce4e7344c6c77fde9b7251248a4d3895216fdfed96a80c9a53f5c84a9995586c19afe24dd2825df13f777ca357085b5b9ea8c8a733808caa73198797350c16016309a349d9b2dadf913b0e6ff5457465bee0cc2d52bb8143ea5d4376f1d5f98a27c9252f1a2bc5b0800008f9d4b12b6c3cec097462c39b50371bb28161932c035293ea6a2638b54e8bac830b92bd64ee4a04e64fc626413b18d77bdeb86bf3c18f7d4aeedd5c7e5fea0bcd465efd1ad78ef629c5439163ef1c22c3ba2035650492c54ea3ac967b81e9bcd3e49bc36ed172852d945d594aea7f1055e922", "76fc2ef0ad52a101b1f9d79c8b422264781f883f726e7cbdbc2f729524606c9cea228933ccc71ece6e7c0167ddbda3dea32856fe9f3c7260b0d2abaf272ebac42db96f6e8be2c279e63ed1ef06dbf959f0402707b8d9025a48fb7b1b53d7010ee244f1017b3ec00b41e2f450e142728e71943192c13628ef1f006ef178de2eb73ed7c7eed393b9fbe2c460718abbf048f65214a949b8e5b6db781be72bc435de099c70defe9bc5415aff5f00feec64b67b78c5f32c5204dd3e2b3e03fee4b5dd1adf6835231eec87d666c06ee7cbb5d03bcb86495f6c448a09b2bb6635b1d8e6d3b05b16c7f3dcac4dcef78a5bccdecb15f5a30b543eb27452177b7091f7114493e9e8c41bb6a017958eb134f0a9687f1784ab9e0c90535f027509750a8b4a5a5703732c4602da5b4426e245330b1e9bf098bccd1da84e46a3dc8ad5e1e6723c1d41b493d44a58ba6704b291dbb18f91967a371fcd298b9e757b913b786ac5d84eddbcede8636ca86c8509d9b1638ac28f1a8e3858cccc219dfc766369f463b7513e9acf3dcb3020ba4fe550f1e8d460957681424f7dec30b71589d01ac0e216e457d448f284355309f09b930cbeb3d435c10bfb742716a29ae55b8f10f5e9070bd991d67f01b8d2cd4e909afd83ff2f35d9146b143cc85a753c838d44e12c017f11dc5c26c8a698cbbfb2618a75d23dea4ea5866b80a91400b64eaf361d64773962b6cbcf398d13dcc941b5d3bb95025084b1b762bacd9368245118bcf605b0dfbc653f10c1dc3cd950605add0c725977a163254834e1f5002f6a6512072141f3a06237482e545eff7203c1cdbf3c05bbfd887fe9d723709f059effd32f065fd9f6e393cf6cac1f72f41a71ccb870bcf46bd726569ad74dda813dbaa2c45fffd9abb6a1f05df1c18acbc8d64b07bf405bc2cf445e37f54e075f40912a73561a99bb95fbb4e697e6a98fe2ce6cb6e4c2a5918de17de975038671759b3231949d0af6ee390e0ba4725de5d0c11264b600aed6ce714c2b9b7cef5c31f6faf28d1d6349176603ff4ae4ba3154901f92a9acd1e41a974425f1a754b33d665c64ebd5dd5dc971099638071a7fad5180ea6e0ee96063db9de5331a9b58cc6318b313a13f8fd24002832f77f93adcd603aba9bcf1d190de50c167f90eabf17599f9d571a69335344e3c4cecc39e8844fee1d9b244c2c870a56ffd7dee1c7d6a863c7bfdd3c68234ec76040dae739ed8f3f87c2b6dbf4a372135f2f1db0003323fda823d00c9e94b2c1ec9ed8158153e48daea84348e18d8908d5dccf8ff2c052aaf20ec3e9c580f400ebe41e86071f120046a1f58260c007e1e4c8a28b434eca218be03cfa789fd7122b7bce8098bb1f7cccc29d55b6b15b23fc9fb4b821129bf7b19e9d0177332194819763793b63c228b018c953e51a24c5ced56b4569f9721cf6b0", .Okay}, + {.Lcm, "a1f788386dd241b0e3b3846533b30d2ff268c393183234113b114b19e1b70b57f4b8b825163876c60e4fc48c5c4ce5f062940acc7b3f3ec7aeb70a1584e92c542a534ff33163a43c892214f7e4d6a75fd2e1c4f3111a06e8ee6223295064623298a59b1aef85bec404a295c9fb69f8e81847e23c74a9396fc37568fac0d0c232317879bfb3d66f02a397d13868f6e4f6fd465a96a0028226a262c51b06c0f12f076abd5f5d32f66b5b3b3c00cb66e23951f0d1d0e01ab43551daa06f0a1395d3569b18c55f4675a3eae855aa403c91a6b2025178d7971e8730f7176e72ad2f5492ca8aeb33b4c1fada9d6e11c0af5730dcb91329149e7ccc8679f8be37e62e923396cade1315b78844fca8c3bf094da4ccdb79957a0524007e57d591cdb6b24f37945f21797a32392e8a1ec783f73fc470abe9fa3f92ab121a7f3ca36126fd0f4ea0c87d106fb8e1b99474169e73242acf597007572ae2eb340fb25763c77370a8fdac938fb847b449c8371182ba8ea3c4fec83b7400a21c722295f7c487e3aac6affd1fb2df76067f1ffdb5916c0849ec720455bb43952c7e24b2abf09079dcf9346519ebfc0765dba4f49da7eb0e37626a62acad8214e1282ec5f9d4e4999e839f0a22f8176f9259c251338c273fcd308e39b475e320e21f57992e92dc8db8a60e776d2d6a7f101f256eaaa29cea767829ecb71c2d104dcad23fb14e2cbaff", "1ebbb946a14e6dd195ac1e6b20cf8970a63c3de93ed6e67e19b41909161fd453af24d087c8ab6bb8da6508cba81b2cea0d247819891173abb447d3f12ceadb5b400ab8baa49d99f4d73eed855810b49547c60d15080ee51e0bb62772d1f0a69a5af8234baacba76e81a01e8e5a314181e7d2e9299def2f238d8b7f2a2102979d25bae226c52fbfd901059ef2491abf3155661187b3047be4043822e6320e7823d1ca2064d8f50a99a205ea7223cb12bce01da2501def4ba89cf59d89d7437ce01bfb80b765fb1daf987b4affc05ed5d2596d963cbd0769089640f4dad21e74cf768b72f7b54e54661e8f49780ad9d9dbcadb1ab6a855fe73e0627a10a91ddb16d4de9fa710768a78af459f760274ea3054fb22f0e4aa6cb359ae8925ea04b0584dbb1924738353f64d8b76d0230c03e8bdb2b3f885b20141546bb13dc4497b88db237b15c72ed190e8b5dde8378572bcef8244f9bbad78508c6e1417e5bb21acada9a8a46545bcf05c93ae7de0b6dd83f3d0c8d49be5e5fdef5c3b1d60817fdd52c10988e26c900b92a25474fe46b6cba00ffa1bcf1b23dbc6a3804b5bc7a78e802709680c758d68f565f6bbf32fcd21b117cb7ce5aeca9ee8671e7306244a85bab1e282c2302ffe7ca5f4235eb1359b932cd5dbb64e5d47057e95e6a0967b08bff1a48b96c6383a5ddac2ae9e49ebedd162de73a755851f4f9e7ff106110d56", "1371c6ffaf452ea5ace70e9c287c43c9abe14cb4a355c92f2c72a5c7ac18a6d99121c7211a41b28a2ab760fafe45d39b19df133421cb4a85b4f499aae94bca937d0760970e421b6c0d438754937f70d3daabb01111cddc7c5488758a087feff68547935e848e8bf5f385d8806b0f59c22a08087eb45d5150f8900f1d2dd2b06abc9637ae8d4d6e9fe05e860cf4b94071a506755e744c4da299810b6ab70f50b80de74ab707da0d3ec6f9ca22da7c37628e549a30c39468a8403ffabfdea0bf63fd789008f54287a43d981b8d67090a677704dbaadd77b5a6fde03599250455e951eea41697b959cf55b40f5efa7705e9c273bd4df85a4689309304a54dec58bba64bd67a4cf68c9ba6f5e06175b887a027bd4471a5f3c0c3370ab82c1569065dc9067104fd0f10c8454712cc83727c19c5836ced4c9c25b86aeece8c547ec0801aec4012606070ac216f2f78d0deb80e21fba1675e87ce13665d9d5d7f668ea37cd4f5a812ac1199fed48a8ddc879c0e8d9d23ed503a2f81a894b7cfbfc506b5307e606b24a40c63748a4e50cfff451a405c21950cc4910b1df1fec73000b4d73a2ff23609cf9e60276177307271cead842f36e596418b5baa5a8981756417c6cc6da207f83d804505094297ae440be253ba5dd539a176a623706473a0d88715f7cf03be5671190022a987d1cbe5c1c9e42e90895f41348dd5edf8249998e1fc15012749f71af307114bceb1f3b608c783922b0f780d71bc971eb170bfd7c18c9262fd8d538fa59c92ccf014e395640f41ee21fe5057e2b858018f98e0efa686f3490a366c193337d5370da28732b23812a773f39da77043e81134367f9bc12e8ca7af312171a25d4eea6174df3ff7b8407a579396aa83ebbea9454dda23a6ffb79e5fcd438fcc4b135b357ec543aca11016c4c6213aea0ce0da9a59f1ce10617c4e45a4424a1fc26ea55b1290d92197f154e28204e98bf205e23214a11722824d043b3711360abc51ad4e914352b4833d12c57f4c84a4482aafea70d1dfa869dfc151920f1a93e78e7f1b058545bce170264181faa73b047b0453ba14ba74b25c52d7c2784be907625d083f1affe649abdfa0028f1a7366c9089dee2b33fc1fd50810bf4a7d30430e67d0d163405a86f1c1a201e2e11f32971c6c687b9c2cdb58eecb142e271c254e2411ae54c87728359d33c02792f797d5919ba17a035fcdab5a27c6edbbf077e80e6a62b30ce3d5e7d0b7ea571dff543a97bc57fd9441266d7e936b8fa94b628d6de356bfb40955471482926c9c98c47c1a0c27e7e06eb38e580e926ce3133d5bd16be5e29ee8f6ae0a0c010e482208927db59fa4fd2d48cd43a0abd9db0f4716968ff54d60cf8ad2d86331eaf658adbaa8bcff5149a6660c6540c89c47aff80bbc81ae2a239fe3bc53d9101133ebc715bb2ef1ed74c4aa", .Okay}, + {.Lcm, "7aac4befd52c98a7e917a6d37e01c5005ac823cea3b484cbf189d1ec979a39f6f5a434b10ea95b2d7ecc5def982145b17c07da49fb8b340fa173f05c0139ab518fecb380cd950d917e9daa61cac61c034e27e561d7d90398fc1e2f03542b595b5bbf6f21ace70a9259ade098a23e174cbd6a94d298fed6a593bf8c6e5708ccbbccc0b1dbb3bda7dc8f8791022ea28627733d27c486bfd155e64a81f44310e6171017d89a8966d2e6340cb95f0ddda811402e00460adaf8206158beaf6eeb4dc17e8e00b5993beb9712442842051109512222f84983dff55475de995aded0a4df199632b425e33f45e815ca67e61bf87f8693bfc3ceb2fc44892ab6203f7ecba052a172726dbb5fa0cd1ccb2f4537efdeca12c90c045676afbe3dcbbef87d89ee7d0da821f081fb4d861dc6f00f39613396d9a9b90846a9da19bf823802dec0c0cb8cc08caad2596bf675741cdf2a33d5213c2f2a4a3a7b0df9ebd40a110361f7cd24a1c9e4385475a3f04a07d2d777fb633211b1ca81cbbc5bf331cb33479c09349cacea889d32cabff9b611ce1be19c20d3bcb88789c016748bb0e42054a6990206b81ea00c00bb5c8604d970931d949fffb57befee97924ae313714859184746b6911da5512351fc4f018647a84d34deaaeb115ff8616790344de9a746c2da132c999393955255b819f0e8f8a9ee0463d5213941fc66e0f77c32847b7d8c02", "-1e4ae945ad28bcbc6bf9a6c1ce7428daf297f7650b2b4d397a8dca642ea2e3ca699f0521d1dff7df0979e992c0e18956295e77ae9450a2ec1f3df5bc7d4c8434e58baf012103c48384e89eba87d7b3bde037a2281c820d31baa2e05d0cfb3138fe493c63f2ef65a0ca0f73470d639a48132f79d55ecd26714080a9a297a8f85a2c62396609f40c61d87aedd29c04d37305ae9b1f09d6698de45085787639536634d30489119918268de9da66a902f5c7ecacea5e7d385bd50c1e2a3015d6595aa31b04913948f80236690860e63fb3454df456b93cc7ea506f57d4dc513e8f434efa12995ff02c096c772cf28d23fc1c14de72ced3185508c6e1a535bdb380127728a9100a586b4ad91e2b8113ffa7aab2af980ad3de76ee98305c597affc9cb4b13ec56789b459aaf232e93540ff14fcde0e3318fc49d2e751651cddabe31ffb199b9d4f01089340ac122e35138cc762ce3fd976ebb7153aecba0a9837346ffcd5f21230c40b7cd09ba7f840a3fbd796f25e65e48daf973403f1c3d0d2ab9a62f65925c0cfbbaa288f9b9cc3402e9ca10348c9a59a36b1e4cebe0cb3bd0ff2f168446a7dfe0283ce6a8ef53c9b0cdaf7896ed91e3bf6528980e0c716077b00bfecbfe3e8c9922748b7fb51e4a76df88a78a10e5d6b6225784b739fe1752b3fb727b46dcdf2f39c89f8f5eb9ade975f99d1cab2c53c4fbebcc67692ef7161694", "7420b3e216b470fce310d6ad7157b97d0805b85dda209c4e6351e3de385e2d35d67443b5a67575c2863d5d45198e8982313f3516e3c3c0ee7a8fac928c510f990578dbab9700f5d762f96b8504bb5d9898402c6c4917d1cb40f80f81c906b957b688be4946bb07a6466606cda2a5859b53769d5a640edaf7c4636a0cfdf6822fb1e85cea81f6afdbcbfab89f3d743b7550e26c9fdf9712c10ea18a8be2dbd352e00353c15ed2af2d1710a7e6793bad2df51bb3c42fffc9795ed3cc77f8dc24bcda37ccbbc6d10da2cdb0b11959354502c17eab3a2848076168664f76fd1587ed6db81e1fc3712c79da814b54f0a5ad601ee7c6c14f4a38f3f05c05278cc69364630d9050ad66ec77d4a5bccf649595dacfb3d28fc699259cbfb6cd69a876b391bf4bb8293a4516d2f8d48273983b7dd18123b9a0b1e6537cb19034d55f55a278b7694b5590b7d0d59eb49490c071c3aef4c2de6a7d35c765ce5186546612981e15053801e5addf06a189e3ef34cf13e17a00394fa826081092e95e438b8f1a34b07613253ec59bc1b907757285b363b4ef4c14a584501452aecd9ee24e181e81481efdf9bb53fa0838fc567a306b0d0011b3559044c94a8c5332804c0063b9827f3fcefcf88cba08e8b426f2227ff6492e17417ed49b01f4f6d40e3fa81dc3742e83f955ab0e7e6e0587ed2f6c57dcb7b59b0c58485c807a5653c03145b932a39f703164bbab212aa6b1539d6447417cfd78ced892b8cb853bc4d92a338970d89d2d0ee062cbf5e6a74ad4f5ce222ad864065a0db25013ec6f1c309a232e7d80bc2117070fb6ae701aa6c4c4fce64c420afafd774a2d7b11cd8bd920d5d6df31976015a0d2b875f1b3989631c2731a980e0089559cd2e7ed926c821c650a5a4c64b19992e46ab994c63b5b5a61f774e52be6d2438c8a7b5b2d4c77731586df77f72e93db45938be5c4aab853bcad5b79000317c5826cc61cd00698de28cd6ac4989961487a2aea7484bfc4c37ee30963c3e7810889cd8225577c2b037962c65c29d0f39207e92f05567d1fccaf97b469f68f1354012eed0d5ef8a52e00572727ccf298cbb565e768b15173332a835b4203afecaf8b03d44b36622f5cbeb5b66455f5ec1be16d94458c816b8d1f70b0f9b7b406ce89e060c9ef03e52016a446cea95e2a2ac498416f8f8399fd130530f058f8a0bd3d354cd3cf97e7fd3334e03cbd8329b88026b2c06efddd5d75fa5bca0cb98dbd2990bedfed6cdb54f7f23a0e8060ac83aac92a44f5c07ecab9eb569692b262e4371b5bcb2a3f737233e69cb67c6be6681c95333526c936751850345fdc5c833ab3a5731fb3852dfe3928f0b29f09d1f19dd6cf6a06c076a03f458560eb07d0cdb5d6c7003bb751f046fd90930e85f5808c635a0ab1e1b26591c6ee731a1c637abd6c50ec33ba83812648e94", .Okay}, + {.Lcm, "8d4facd4e98f5581a22f6993dad8178d55cdc1f1028376ffcc7311866c6b60a3542fd1e94e967b0595d3e0b6a12e062f7e1ae66f5147e58a7c471465515ed67f41e9856e1795e7301e2351c917108dc1b52dadbc22a48b6838525712c8f9c86823a7d5c04fe647e7d5a6170c6547ecf4616e2f0100927ba999bfd8391cebb800a32aa9a4f246ea9d9352513e31ffcf12415add95eb2c581b368a856124f0dd111bb12272eddf4a17c092658ff76cbf633dd317fdc5eadf760ca91fbf411c025d509e242dbdd9cdad535a02efbcd2ad3ed263931d767ed9ea9be22cc6eb7c895c73029c6e0c0781dd1782bf9f61c31c8aaf0af293cdd4a7d1adc4dff5416d8b8323566a1c7b7383441d74d3e263a6299b843929d71dc60d713414562d67026dcef70979f623b5abe6f2ecde9854ad32f75b414359856fb203bf4d7c24e6a6f3e77ba3d300852070b9d7b5419a85c7cf188976f6787f6832a223378bed2d1fd549e84e00904cfb81c80af2362f137053b07819153812f2019228ccbc679dbdc33ca1da71a22d38dd72ecaa3d40444e10cb135b9d5c3a96ad4a2dfb78d567fd8a305d88defb3c75ec07ebd5a53d722a21d0426caecdcfe8d973ccaca4077e2d4f8c77dcc08a28bb0bd625ecadc7da2f2d708c3f79a35c827a061c8e953a58564ca800098ccbd189fcb719980571a1ed47c1840ef06a108ae9afa284664ec20c6fa0", "-760a6af0a0522ee43fba44c35473ab57fccefdbba86ab266239d9bcfdb15a7ce869c6c501e69996b007b37950d4cd296c415a75428539def59f8f2cdbfa4644dfa0caa12f63e54939244b64c19d590a9975c1e2a5d07d56584cca19f24b3674072b33133bf4a3506961f209a805feaa9814a50f86b09c1f0209bd490407791702a9429f6bd93905f7f98424064c26954afb72dcc9045917ef2788d924d6d32400df37faf2a561ca67fc5e73412cce29acbbc3a1071c0061fa1ae3e42d29ffb898e9979f00c93a8ddca1952cebc335e19ac9cd5278da2a1617fc8f88c459a0547581bb58917ea03200b950007b2682726e0c3d04d50779a712a16dc43f80e0d12bc57932494b36c11738161ad94bea42bdbc65a227a41a3a9e2373f640a4eaa1fa1477ee6e9ef3972ae4ce60330bc1f92d000daa06e55a1ab45f07cdf052796873755c388f9d9b455cd2a04b3830165720ae85c65628955202229da6e14cb6e9a31892481fcfacbacd37851ca025953ed08b1c72b1234d75051297f97c76eae31a80921208c14d93a466b157fbfc4f1459c573b7a64e3ef3d9c88eccaf50f8a7a9a492778ddc4530bffaefbe6b15a287f3e7ddcdbf755bcb594f4674ddb887a47337e33b66b27da8405528013d6665280378777ab3f4a17f9ad61d1b40d27935365da1abf42645cc1bc22e1aad283aee7ca8b55693529da95810b072ab083f04d", "15b8289a3c3e2e400c52add7b25ed9981107bced1118dd01a6c6b74246a13cc982ad4df086d27be6a6626ecc89404a5e9b0adbc0b29fad83cbc22647d2dc4b5b2b5f92ecc27a8d5f46e1d997023d6b32c452a7b201a63c3378181c67669d8d4b3f2f1d993756b02363f9a45d40f68390c1c5cb2fd76c54f053807877022887d6edc40c879a12ad36bd7bb98592e6f76be31fff3e9258a987d9f0a0854d3b9a7934ab3a366111e4ca0db45344c6610d9bc3e9fe624ff0466f892b5031f41170f4c2a08a6769a8cde8d93b37752d313ade23bb8ec8894c2af8c22a51139a56277d25b2e72e154465d8f950075f27055c4ae7121a62b8bb70e633f76fb8667656ebdb5f36c9d5ec3ebbcf5e5353d812444695c1fb24f4e5b3a9ebcd7de334a1dd49d14190ae646131dd95f8fc4fc8a4ad6922415d3075d0f4b5243ac682ecf5a2785bf9e8eb4112dd308fb485f7bc7356a4a857d547f125966a1517941e8ba26c35bc1a5f7f9cbcfc331db5bc5c91af9b86ee5845d11d3d92ab9811611fcb0a899160fa1483c380c04fa9dc581d1b13105c3d7c76de820dbb032a569503019e741bb0a137678d4f0b93c77549632e3c4e0a7e20c7a44b5f48e6e6e0cbe9b3f3db3da88ae791316e23bb10a5a8273163bcfdf13edff87c13c0eb0987189aedc307a1d71887d85d4f78fdb6faf8169a918cb26cc22685b28d015b5bf7914bf9d9d7d57507e3c5598a7aeff0e3ae6a4b10c9463ad2d4e29a3e09e3256218ab1cbc533ea82dec2c11351ae2ed5d8fb93087ca61f6d22a8bf9000c3a574a3a6251106d8d059bd3f3a446d0b8a79abb6925f645bd283e4e04a3c0004a6514fb915a049a5f40f14d5b24b375ff54620046d7aedae1415e3724076dca4ffb3c0a813ad3c814e81211c041e46a7fdaaf1caa6490a541c09b74f7eeb7d8168b2e2d65920f4007c0eccf956f009fd89af64cf8434fdc9cee00faaefe05e1ecf988b4e4fe2db80cce6bacb7d854629bd7b43d98349a70b06847c4c9c3c190fd8cd47aa492d6af3a9ec4def10c1ffd4f53deca857c00856098b880a04e53e3d52f04e7c022b69e513b75e2f5d9210ff6fd0f0e6f284f5a2c57c092c0bc0709549c02ef8fa65de993954f1cf9e4a4106415ee408815ecfacbee2ae96df8d053842af409b58e0b9c608bd2bd9369447a987252e0b13e8d80b886facacab2e82c78ebaddf7d88436d767a6d5c5692ef52358b6c0cbe1ea3676abcf8ffe9359e9c89dfb3216ceb3e1ed9708c5ba846a5b651ef24037561366f7be0bd3f882f9efb3e4d290525d0fb4ceaedcece59991fbc569961829d4e203719d453e90406a1b9ea3b395d825e262f5384847520cdee856fa5218a366868abaf8730a3ac0de058016d06b2b810da3b815a0736b0fedceaf04e0dafb23cb4e4d21c62e927d0064c785e2361a7b7168660", .Okay}, + {.Lcm, "-4852b8402e7017a5a9c44d70381e85b435288770a53288ce664f643a10d53197efb0df518ebcd039adf28cb135f1b4c4bad6e40ca2cf28dd335fd7a4453120162ac5654a00e99c3e814d911b2bcf14a5b4c3665795d9eba201c28b529ad481e98300c027bf59bbb0a3a52be69e9d34e2391b310731e321ea9d30824584871bad61619e3c9637b9477bbf2a1c497c4b48452e5c72d5b1a2866ce4e58148b785723cae889b0a22a6c46f8033e0c1e96ac750adbdeb4b6c0184913fcd7c21aabde0942f7d8a27a9fb3ad371b8db9f234d7df02f9cbc5f4d72e78e13e689719922774c226068fe6959666e512488d8770d5c254849d3dca36428cf05e90f948fca020cf9f8ae885a25a78b8e7de06f1985daa2b6237d8cf2a61b579ad7d77a01e18f7df23bd7c73717faf1e5c45266237b84215e4240d367b730291b1af95f0411d3997e6e3d80992b689bebbe9384a0f0dfb582f86ca92a361c5ed40b5e8b1c9acb93365c1422da2499151c7dbde4c736cf05a59dfc0ff61424261ef2e73030d056fa8f26333bde42dac2742f3ebacd12b5bcee01e74d28864caf6ea73ba26f0e0daca60d37607d06bd041083955585562a1e8c654fe0fb3e6407f1382770536bd79a22d40c04cc2d611ed736de03d77757d02433245837ba54e2ee4e954a71b85a25a8b98bba164d82dec9d76bdb9b4ff19071eb81bf6a55fc229c5e7fb3e5843e", "-7cd6a54177d98e503c0da889c686a01fd1d9e703978d9145fed6123cf5bf9414331c6d4ab2b33ac33f6627df62e5c202ddd2888804cbf7f3d27129ad5d920a5f41c0efec2d2f6cde87c73cd30de033973a827f7ebf5b557f99fe8499f31f0db04484fbc9b6152d0dd4fdf547d1553a7ee8d6089a86d33dadf288e6afc86fd33fab6f3124ab88b99568bb153574ea439715e5e0d109fefebea6116ce2178f3a98f168e58217e160bff2cbd051c4bce06c61abb7866cdea798a12b5e7a818fe1169f39ae3959cb32ed63b0f966874afc3905abde11caa585cdd1f3363ea14b06f80b5aa203f5416327d7dc0054ccceb35e4b7ef675d746918a2ec09c3c98062d92c6fa57a7779da22d361f5df332f8afcf77851da814877e2f96d4313a1f75c64069f848c9b08a9543c5e64b879f815ce491036ee7de9a63a917924121d5d8245cf91be4d1b290bf336fc7f0f799cb6480dcc49870c9bbbe7ddce8f6fac72e832af5f993dab677c92170c7da12a7b5cd01f46ebe3f6e09f531d075210220b584d7569b2ac1bc2a007de06f72da203395a46615e4cc3dcee9775e1c7b7aef88b5b5eff3acd5ac09340dd88a87ad55b5722b821239e17ba933b063bdf1d5bba21f75990b46fc454dda4d6c1b56e83934851a780f849ed469217e80ef7ec5235f64a4b25cb78c47fc97d72a14ecbe81bb2db29857e64d29031dacf997cfc4e5259ee0", "5e0c8d8d1f5dce46f921ca6d81b6a0fd2957b696265da96f45f764f01fdfb0ab09ccb211444f0fb2277e87e2bf4d65b070575d6f45282a0280d52bb381e2fa7fe7789f38c8a2b260688550e8e62d92aa90a81b4461bd2374d0929cf823baa36b22eef25583de4ff881100d9fc2902cca17f08c4239d8a628706a75692a8e113d299b7b182e8da4579d88891fb433c96dddad2e6e4082fb2dc704af670ee891ece598486541fb6c2fba996784fcc1cefa66785e8e7f778963a0d2213a61277765141b14246ef48dabc03fe5430e43ab6524ae82d5c97b030658df9a70f71fa5707be23a4db49ef4402829d2e787dd0898ce4c4a1ca6f8ae1654e2a43601cd1e89d845638855a46f3e181e18e6eda58b30d456235d6fa099fb106f9e872f0cf3ddf847cebf66584782ffe91e8402fe2a26723edf488edaefa2224ddf0892ccc3f077c34631167b553b279e4e421edfb94b3c5acfba09e50e835ad1f6f40fa410478648377cae654c1e773db2abfbf72d01094064c6f0f7fa68b01226be7aba0249f330b6d57b2519dc9d4ce4174e73c0201fb4620b91505142b9adb6044f0179f5f67c909aa3992c951c737cb24c75b9eb24b750110451a60b32cad47b3b8fb8b03b98664a03900b9e82870eaee8d3993128cfbd8ea4d7ec48b1b49de13dcb4d35601897b7047e9ce6d0083a9d6a6d78697a2a51294ab0324ee4d09f4dbb67b1188904296fa56c530160eccaf51cff54522c9f4b96426f0bddc83ea2e8990f6a27387becc13b975406e56f94be5aa1a22ab1c6b7099ce0ab08df3ad1a1bb51f1bb275ce3e54e849efd29a3ae7714096049f2d3ebb33d0a28e157ff468e1393bdd7bde58d965d23ccd731f5c711c339da59915aa249eae6c10b3549d6c7b157abed54af7dbdb8e68f9969ebb1416225e08f2dca5c5c134caca0c655f57a7c51d0526db78de13cc3fa30ff70e0f31b3db17fefd5bb969647007e1e737c4406adc8990e567fb7c33375436471390543aae8ae5d35bb54d7166d6b5c0bcee29b02f981d0db27a8da6d553dca5ee91ea5804a12f53c25ea9730a195575c7d54d6a40bb489385996d2ff98f2dfe3de5b7b5f2ca05f05407b1cc5456916193bb58d2052f4354fbd5d975b87733e1231c4240892120bac5182927cc0f3206f5412aba554478c1b2add6dde40d0fd0e7c36dc98af5a72acdd96b1fb5ade302fd5bb91de259fe694baaf2b50807cfdcf550d2832545afd31f2c76cb5f732ba1971f0516c3229445bcf3702499e4f031850e651ce14fb21472dadca87a403b19cdf577acf87e89f7494e4a5522abad23bf5a8a56f07e203c445d523ddb8aa78651b8dc481639153acd6ba84c366813402e92e003fcf2131e2a2870e70d0a28998f8e0a289477cdc85d57516ed9252c0fd51c451cc358a60de8a3387a182b0d4ab2f370915460", .Okay}, + {.Lcm, "3648016b0a4e8341d4b47351df8acbc585e7e2eeabccc0425a883766243b0a63ee940f89226c62aacc83f7d730d950b4687b1c6e6c0d2b590af693f7c28269133b2899bc4403ad06e03923ddd0cd85ea04207d3e5dd85c8edfd80a7a19d2505923c69afc237c07fa63da3a04726b12e97027ff609216ebe821dbd025dbaa0db24998c25f7e8f3fe018e7d14790000528112bb17980d9477cca57baaddf0fc4ac89c728c2970ccda366761af1c707dc943d6f03684438c95b05ff3b96ebd33c4149142a763f625d7485327e8e97a319780481c2baaab886928a03362e08c81c442f85d2d7b4bcb955e4f390fbfd407efe0d7dd9066abd85d63d6dfba6f4530f42dc620f75b82af402eaede77989eb2c427d5e770db98ee6a58769a3d55f0e763cce232f6e7b924736c7e8b04706199147b0f5ba0279a258899f0e3db55fd70a628c691f93246964c4f2bf3022bf95ed74405e548bf8eaabfd8fb214119f0fcf616bf17c488dd4b0cdae793c67066178e82aee93e02fcbc2457b154d0022ccfb95abf518a5faa41055399c1ff0cbe608612ebdedf9479cf0f197960d1e911ceb5a2d2a2cf8c28c60397b4b2cef94855076829e7bfd3909f70e204b7346bdfc9eeaba1ed11fd20e8d05b25ceb6f853e3d42cd66bdc9ba8ca36c65c6fd809a8c1d7db7c467cf64b71d79942f5d9a3339afec9a9dbc0e94b1bf0f01a17c286e23b531", "-3ac6cf40734d76cb8f22075241dea7813e76b3704134b6e3042dc95bfe4bcdaecb290130ad83bf98ec1e32e925dfa23a0a32b0e750b83e827fa46c5890f8e5eacb98ed937e8b309c141f3d6dbf23d8f1803b01dec5fef9b7a6ff5435031244d75b731dba703882430ab030555ff02d50e7ede1c9aee00293948262a197d5136941f8bfde4faa62de39fa34b99948f75764b98ed93c76ae066688ae4ebab9c31ae3ba919172d80ab526d4d6da88300e3e354788a8c25c4d3b439c541bc671cf6f1a4d05ecb37d7c394bc45910a027a830f7d10700208fd8140a9702b4570c3137c051159a8a0e3e8347abd3e8a818b6a7eccaded4196074063b8fbf9f2e5ec76f5320a8dbb85aab9ea87d39725e4192b04c253aa785b5cb87ef92196ec58765140cf0c0f46023305674afa9a9155c0537f5a4d0e331ab43f4e262df871734a73957c390b84f30d250f2cc3ccd492607b39de48a7fd8626866cf5e10bef8a4946938b76cfb49436142bb1bfba3d17c81b7431bc4811e7ed714d4ccd2098ef2c1337cfc7df8f6d0cfeb8d2e792f45368b91b8178437bd26c4045052573875e615e51798bc3fb96885f02a448362d89209532b4ae41bff1ba666c043de6edb88b58a14d62680925bd7dc12c09a8bb465fa0b2aef6eb51580b21e010fa859335095da37a475bc93ade48dd44bfe0f6dd5a133a54c09fdb6ae8551595edc27495cb4a8", "c7677f53cb8700a5bcbb642a27bf0b3380f729b9fac819deafd3c4c4358e878706ca1f506267660417186b1e18779277b75dcdeb384161dd0ba8874cce645cb0d05cf6b636827e954f3e41eaf1df4da60904959542694da668cc51063bb8a6ee394ca9f8be6dd81b828ee74bbe881f98c591561ed070125950dfb222cd8cef87cbf40eb46c627a431f0ae31d2512ba874306029946062ef362631a2a3392fb98281067e327a146cc61eada5eddbcda27b9d1f4d791565eb76ceff9a5fdfde0a679684a85a842f33b393934c4aaaa8707426f4c2ab7f1f0ecc10f479572e0040e9bd72c7a371e00508606e533e2fab5b03d9abd892f99100c5b933fe042198480e7017a896a8a959409ecf05ab3c9082b7a11cd19657c6bc6096fcb334cb1ecf4e00cf43d0449177b8bbe87a137ce314ad58ca841c425444a02a323d30674d69cb1cd52c45ca2bed1a9bda8ea6142ccbcd79eb050053663aca762354bf28b96927c2354d54a18472bcd33fe4ccd640775287878c819d7272388d0d1d5630141f64ea9e0a233b2ebcd8ef95db4f694d14525f74707dd7b9c949cbf75d708a933e3d35ae55d9b58174e32d91835e45735aedf0110eaac50fcd69898c5099731ee382111632f9688e7f40040295c246f27b4b627f87fc504d1836f7783ad0cebd5e9291eec23175bcb11e384f58c62057d07b0d65f839bed59756291a6424f333f1f6e5807739c64064e2933b9a774dc52ced57b5a6a6da3610e2c6c0bd63f99ec9a291d2b59fb28e56e626afdb9f3b605fe2fa208776001ead7a4896cf4e7172bd0b0f76d000b27a10ab596d5569c35bd01d1db20544c2200c6d15cfe1def26b4344f828613370012e1f96a07835a1fba94cb7952cdcfc7494474a829ee294a8864ad94a4f86a9e146bec4016d9833cfe58c958d50994ba45ff61d010167d11f21a1b77af739803c2bf4a8aa58cc49da6d811882ecf41d36c1f5de5221ee92a4cb9f6e0305a05e908bfd27619cc48d68b8aff1514aeec05e820a840277580c64580cc1c316ffd2c0d4c6cd44bb001bb3648403fb32bfdf106cacfb640608b24cbcf70429e45a8df37b035ebbbaf33ad50a8919dfffa420ba89f53cffc8fc17cfe825956f807f31129b91be3386921988309bbf119bbe75d0e80c9dc6eb49b940a686a25ec80426afbd751d250fac41474963f4f040ac38c3e8628ab8d2ed66082042518d11edaa806faef0c0a77fc59aea7620e140def79c45f3678c381b34a5b27d758c44c3e3518bb61d1f144b4d447bbba1affab96379af7427fb887409ee7825133b0a24f95b7eac0dcacff99d59ccb11e1c2556be317728392b226c1eefb38a807a99d40db83d8556cd65511198015a009fff5fab0721b8c67b4998fbb57fdbd49fb8e4966594fca81cbc3f01d796e950db268f03ded9cb5a61f079715c28", .Okay}, + {.Lcm, "-27501d2895577e606dba0be4533ef372a186c757fc3278dcd46341e214c2ce7272d8fd2071a6cb46ea5621f35c67759d554d6a8dcc424f16a3e536950105404ad6f2b01c39c8abbb84b28d88de0aa0b8714431ed78eb7703abee63fa8550a130abeddbde46e27c4d508b9f3f646a44f02f547cf5507c6439c6639c4e5bba0db9cb2ec5a222e1b33ea563fd75134dcf6892d319d4266ef5faf4beafd5fc2710b56d201fc2cbf2d52a04e99095495c7dc25dffc32ffd5dec49e4e0d6ec7065980a799256ca87faa6e70335f89019a25e540e37c8e1363623d82182c5b4a7c7c6f854128899468870d0e7716754ab07954359dca7335ff9908ac97442213f447d29e07476514d696728440517d231f1803346af226ed8e4c0657bd5a501c0fb01c4f62658213cc4bdfb38826734a133e13893f315499a7cc394234a607fcbcadbc2b6d25c6ae6c49b2919cc91cf5dfa1a5f57c6e35e33e7f8f7bcffa40473ad64ed28064420abca77e26075f689bb27b4899a6cef5acc29e98142b7e59d863e2d9ea99cd73dcf2fb5d096fd5cea022bcb06fe57733c15e120e27e61c6021cee2b8abf9d09c0c5ea0e5ed12479f1aa3664a9e8b0baf3d781c877e1e84fdc6e1eb082270783314c1148919fbcd49db1d4c9cedb234071ca95d30cb37c3fb7c34502086957c748e82edc967677a104e072781da7931cb5c5eb9b75d3286a3253b2a8bb", "ccc0be7ff25df029af6ce0d561955a42e430e0c6ef0014962db9b4cf0e8fb3a10f575891f341f0224f496a99fecfce4393a1b247bd2908e4bbd159a26ef0cc5aa2f0a59efd1781a57ecbdbcc007eae69fccbd3db44fb324e0cafc9704528558bd9ec0741bf8edc639d2df11a45f81ecd48a8db4ca87893012c3a04048ec417e9d1205674d34b03fe85ba813bd6e610b8c0216c2f9e3f95f54febd9542b0e33df16b7f48f9cb324c037413ef0a3da80788034a13e50911f3f04b01ff2ecc8babbff997d296169f21f48789249f7a94a9767c1e41cb9b6697059c55b6c135dca880b3bb0a7ba06295e8fc7347ea1f906a98e41eda67b09e4b61d5f2f4bba9f8352d58e94b9dc945025fcf03d174fd6f4dab521a147e4f8a044dbe9daa93a3241e69294cf8b8a028979d5bf533baa80b11d6e67ae250604bf51408832ea3f2586c129c4b8af2c92c4170d542d9e5278265c34ef45de637644d58acf8d3e977c928f4d0fe942f75b40dfd07d1418dfabf1671777a048cf0f992c4bed33e3dc7627e21d9390f0064501978f4c3425d89162bdba8927f376d62bdd6758b7cf38bb719c76a7180afe3f77c4cc4d4f1a0176f97f179ba9269a85018fff8adf1d4b30a7b83a986e47420065650293de8837bf32029b48b54c8e01968843781b25474660085dff6faffd6043fe8aaae4f515912fbed4b9a10043da93e0edc3a7e7dc148788", "1f717093510c78d91cfbfa4d4d5135afef68d171bc56929c66ecb1623362578afb9897605714b304a10750c9abbe4a7710d556f853a5aaecb829e114c5ec0d356b1a2b07e3ad3b4d241ef435811664e752331b6fcd8f6eb10086442d865b5d46842e6a98f34e1bc42975c401bb322d16f176e9375a87fd45c19b92f5fe43d5da3b6f9c41b8349de336ea873828f98799d391c091ee577d54838383b3003386350ffa310666ea9fd22554f8ebd4c059bdaec11d1c47f2cfe80215ad7817edee3edbc46cdf37e38e5a1368aa16573ace757886c8a6e74df68649a9eb797d797762b80f40be6ab26873309d74f6af56da0238722f5380cb1b0171a37c585b316adf1716b279039ce5c64e049ad77dfa039964adfa0b1af01f59e412adcb28657c39bd852c6af7d03d3b2f0eb55c0e31edbf7c37d48a836c3c812026e20f6fd3e9a8fc2a9787970547e3b4fe742afa28872ec93dd30dc15b57a5c532f7f5ca9ffc0fad89abe5beea7a0cde7fb2ee820c635e3bb190fc577f58d3f3e201317a5f471d34ec8bf3e0c1863f4cc8b5386bfd0d660ca28eedefc6b3d9f32165adcd7af5b0baf26c6490d8cb30b3950e66d38d4082a22438578241a1219b99d42decd108789fa5332552004131ba3307f1725a311e5667ffcc84490772425660758fd1c7da50d4a4a9164bd4c555860a65e750e80827294316b9fa6ba79c25bbbc4c632b1b1c7133a5c2353f08f3730fdb72dd2c6be4f28f01c8ed320f29f4243cef2d1d0fe16809d9b5d98a5cd70f80182a37bb07a55126a2839880b937a229d99983e2d8d49c5a7cebe3195fc928cc79f770b37a362017d23e5ecb9d6905d6abaaf71f111a6c110744f5f0a2784c0467a1f12555eea5ffd3cfde8d99c35c963bd22366f8d344e3d16364f3b142da434e8a07e1802982f6dbc95f64cc0251ffd846e0064fcec34897da74d00838daf0b461dc96951ac2c1e735b84a364d58373196f1bc5190a4f92a5c00bf24bfd65c83bab1ff96befdaa26691da34971c59198fc3fcf4ff1671189f1c14490f30578e601ea4889a7f0bf4fedd8a19fed2908000bedecb5981dc27192356a7e2185ff9c77431c9c8fb05d47dfeaeabddd329d823d55948930f915bd98c8a80bdde7c2ceadc49b6307990d58acc961b53a734af43b8a1cdd1e7ce9d63f82b1f6b89911ac134bec1a227d089be57f2394575a82c2e602a4f76c867d5738462492c0a8746fab6261bb6e0666281eb050234454fb06b5f41b77ffac6930a6d8aa162dcf48ce15cb52e7e0f337c966f18ef4b62b97b08b4884aefe2aef284118c5989c9b6feabf509eab284f2cf7936a613a686517042f25e1b275822e9a39d46e1482128c2461974e63907138c55fb0ff532d27c67be4e9265ddce606f626a56d70a5fc9a8528a20ea2922fe781a0d6c74cc10e459290804058", .Okay}, + {.Lcm, "-de94fab37eb452e9de741a711d5c91e9adf9635bfdd4e155c19234e53eac4a3e2a8f06d847cf4fb484c7435a84983b7d585bb2bc4868dc592cd8fd12fe4377faea3ee2bc870a735dd8e11014f0b49bd639bb244c077f4bb11fc1dd959b5b493cb924d2e81a848e51d2354ab297bd476d0e52d8d918d021d4b6502569d239aadfe3c48847f5dc409fffa63fd314c3449f54768abd25bc900f2390c581682156d28310e3250acf54fed446db3f974012d30ff393e510fee74446f147e1e14133dfc9cd6ebfe53f2ae55878c01f5a2292376b6f679f2e3597b4ca48ff8f54ef987cc25a474b0fef8a8b6044aebc1edb084638e845dd5893d9fd62a338cf3bafd2112588f527afc652c5c24b7f50581b47d749c6071fdc793f0f06e2700f1cc314583aec8dd7785c35a1811944aff1ed5b3796a4f6f6085750570dbb2deccd75a61d0b075966f09929c1d08ad68256d19ca5e3adfffe0783f13160b548166d2366dcead54a8ba51a2cfb1872cb58a925d92f98e83507ab8fe57db4e6e13b073ae433d3254acec2a276fda6cbd74e84fcee39faaee45c25574312956e624379deef36187fa2b3a135b81888a92fb6afe3cce8cc3853acbd09c4d5eaba504a1b251951051d2f47f637b13e36305c744ec29358bffcbc6515902269c1c435a36d66bed5f550bbc54c08bc87c3e7b0ca0e6357cd8da72a7a346f05a2de6adefca563f021", "-71069db9c1707af007f5962397fdfa329d2513ae743dc727150e8c0b4311133213621d54f00f57605738fd0a7ba4799867a220c7f8c000f6436086893b37e6f80886a062a8c141075c99fda08d676418c5d564ca336e8b90116e071d019a4c98d575800f424bdaafe22f9f9224d6f455b3bf1830e5f86d26d4b551fe2a1dd71fd431d70bf9ec1faf5fbaaea9597723cf22e08b82c56382fdd189f039212d2ac49b1e5900a78aa93fc64ea8449efa5ce2609da4f14aa0488bc1a5fae3dfee03e42773846479afd00b972d73f19ca9df70127566d35c083a6f9ea38bbc0944cd5e492663db4a586ceb060eeda451161ff81f06f3a1e66e483e99c77aeb512409999868cab2bd659eba2729cac13a0ff424fcae80b5c246e8dccee74c01b92a02fd55cc4c18ee1a4fc9c6701749d3af39bf5f12dcf6e6ac31ca795b1cba21ba4ee1e36a0ea636e6fe2f7ccaedc6c12944e89efd3e789a740aee9900cfebe6fa4274f82d84411faeababb12ffa49329473029dc59cbfc4b8824ec794dfef81b43662ccbe13af490c0d4573cd9180c3fabf6ee0c1fbf5617a91fc9b3dc82d9b9bdbfdeb16b3864738b8d4959ac18d23bd15d5b2ea6ce6a3a3d4301cad3f1530a987796140666322929a93e68ac5ece7ac4632e99f40000547712ff33dd64975691b991a6e58bb52a51fccc73b1444efde673ceec269384f551304d581b54c6fa65f68", "62458349fabbee5106f35cdbe5fc6797248b1f44e19bb2ada36b08983cae41329775f1a5575655ad2d413a60ce17b4abef5ed7b0dafc892be6460916498eae725d2d5f30ae9262fbc3d7f45879804b59f59d0d78d323c164ef525de05b9db98c547439c2fd71f0d7c936e7df3eb00b7f8c1a1d8012889fa21b0843752096f77c7e547fe56bce81c2f0b479b8710ea7dfd70d045b75c7e84aa5c1f9cfab47b45ba876f0cd13c803769be06cfd68e361e0a2b42a92105d080f86f72498c713cd3f7963c1b2f78fa08a017e0c2b8275408eb0c1bdf58322b8cd4e3fea9823ba8ca7cc965ec93ac6bf21153d7d9921d72fc0e09028ade74c20e738f7d3f0fe3b718f15f3c1c63d70745e7646c26a98f39dc1e51e1f7b6c023470b7dae4fe4a46a208bb73b948ad1d678aaa6883f3e9b45b93be548066b1feefda6b93eab647988ce748e509c31be1a37a8488cd5fa4665186db0e0edbcf589ba67729597f0545a10d4d8bad0e3729ad541d3446be37f3bbfa1da1a1598289ce753e577d287347c1d0fc2e653b2850d82aef2e1f8ded8ff0ea1160ae29106cd5841b765a790b636555eba5b1b8bb676ec656dd63120bf606d41aba5709ea8ad8ba28c54fbd42b73e2d3a44651dab4d468a99e874cec9cdc587a8417fe44adfe630c39429cc28a22d2997c4ce27df528a1de7c691a7c2c9cef051ad9dccc737c0fabea0382e8ae0734495559a7b6ddf8a0e770161cee26fa99c5a9bf2b87e78bd5bb2849e139c2d61e9809616a17af7541ae929293075da0c23fe234e58e0dcd7b8c068617bbb7b0fc5e439facbf89316a6a050a0b7974ec781c4828e08ab0c4f2801deee2376c6b07a9a6053bddf7f599129086c1a6b1a2ad96bd4b895826a927ba45c84bc70cb82bdf8efff9f023072e1b95f7fb98732afed91f25c8b457fc317cc002e2ea341bb37dfe2ec4f2fd0d0f1a07417e5bb80b99ee3f32460b2866a46f81d3eec494098911b197592aa771d5f72605814f9b879fd67b9e377ff3b7b7064aa09b9d217c9bf84cee5ffec59f3d2f31092e40d48d733a4c10363293ebbe72c578c3a16720e337d92912c3a801d201dd7feeb2cfa53500ffc13d98a5fd3783eafc252b35513b15f26b578da304e681b10754aef2a1ce4bbf8a5d829df3330e5e86524ba8d1e906fc3412747274c00d1fc90d4252140fb260a6fe91e49338ec2695b3257fc6a510f2205dde63cfcc2bdda1798abefbeac8bac2ca77c4b60778f70f0559802a1ea161583c1b8b8a5b66618356f4686203e591948b817e91baeca33a84a90dbc5829a5517b58ba0981ee41d0ac60e890ed392f4b63038d3b5853393c20a6e0efdd84a9bc433f8a38b61b94802bd47f756db0a4d9ead2caa2864f8d6e52f56375946e46cf4a74f31f381d37f6b97a9184e09c23a9f41dae3d04c5fc78abb4b1bcc68", .Okay}, + {.Lcm, "3cc92376c9032726f0ba7224b6ca01c0ace9a2d208dda70416570b991c8e32f0f2b2e28ee9db4e49dee25ab42d3f3e9b05defdd4e2106e872ba3945264e5c9d1084e7ea0dc57c7b98b29e740e2f368eb94f065e16582a2e36f6e64ce788e1b4646f5dacdd10a7cdfd002cf02c3f790d77ec45964d1f51b7a95e88b254bfbbb8e090863b8cef25b47f33a0a6a9d409d960354de5de4e029daa0d0c2039063872ba7a4effc8c536ad3f7dd5f28886ab73ff18f5e92ed83fd7ab7a5df78200699060f7ec507c328c50e2d44b450060830b638df081813b19234d230b4a1fab7ff7181f2b6dafbd0688a08189300e70198f4727b1bb8b3d51eddb18e1d4dd496e72ab061ccda97f7f70b7d37071d78c1ac61841b7c14da0809281346e260f74c0cdcd81bb15f2cec5963abdc8f0703047a835f8d37836e03968047c43dd8a21fab5c3e4da9a591907374310ff53d0adfb0e50c0248ec4a69814dbbbc87c5b9e511430920b0b52b00f204c647bf569625f9d3f4d7f4be4d992ced058add02ed8a3786ca6ba4e6d8701b53c74fa35294914639d84a7c16d837094c7edea8508e56c2f38667c0d46e4befd897acd0a94b705158eb98a3433616de63576a9e6bc78feaefd8c4fa54bdb2433bd54f35ed55a89ce814fedd117b8aff143ac0a4ca1854aade9825966e3b7d65525fe62811e82d34230c73e38f1c1bb762cb527493bc4ad64c", "-35a182d32707e17ff022c0dd1069b694db6c691a4491567a29acc2cf4af23b9bc3b4b3f2548fa9d68b1fcdc302a80c20683ac51998219d866b783647e4434d7b515fb0a52a803e76f86271a1235403ada6ee88b53301b6423fd9b3c761f870f85f177f8fa794683b7fa76cec085c1f214cadc735b10422561ad52e254ee3e0d16fc297f5fa4ec3ad47c6be76788f031684611f01a0ed46b995f0e9f25b61c2d8af48c68fb07a952fd8d9ce4b47711d488be8228ed7ece7f6490328c8f0077b61856b7f60a140c5169e7422d3d4cbad6d38d79c3ff4c7bc2e1e9357d2255a1b71a346cf136f51a14b752c8207ffcc265a0f2fccf1cc809d51e1c6945209bdb18d1a44a17c60b8b44d6c1f0e3a01c5876af948afc9b802975ad94458fec028c3170c36b4747b04a3a569999db41ab3f99282713c00bf8da2294ebef67e678cd614e60796f90424bd212f240972c9ce068044df255d1ecbb593c4b64ed03e8ec4c38e89f30cccfd29c0a664d1798970d2d9aaf690605cf8ce45e0e7f26cd2fcf696e76b6e68e2f9ae75f33ad4c0e1a451436d0ac0525084ec67cda173a6e38c10acb10df7846d3cb58a03a0887a6633d1f1bed6a6a00e9dde598664e1fe7ece560c69cad8fcf0f8e35e6628e6448f96ae00f0ddb57361b3bee2643c2b63667c3d150b8c4b410784819750167f6567714dee9feb9fdac5d78e1dfdf5917e996267c6", "65dfef39630914218536a5131d2152f136c9f29142c870a0a59d0c9b8c85af01911130682af17328976581d9f20f479ea681ee2c91a33136577bf0a7782b1496ca3c6fc254d75c9799f203e607fe97a55da7e5b72cf083e3fe53d8d298c0afe9a0f91c9cad6f8b85290ec1fbb4b1aca6134043dbaa5290b7afaae5dc62e284ee9a8c9b1e752296ee9d4786e9ef98c52cb4747c6933cd716bd612a38ec89b9cdcea1f4a89c685acff6c6be29ff866528aef7cf5f761ef72be2d91145515b111052a9f664246260755309d0d956e23fa572d70724a005f0ce02c24be188c1239e0127c5b76fba663f8d4d6849e9b847b4078aea81483c0056edc2ca9a7ca82348c6490cf2f36ad20a28ea4a2c2dbd31152a5c4eafdb3041c193c40ae38f2fd0e4adc658aaae6af1a7e07fec8c14e1bda9b35fb13a6e5515c78931b1faf3b579b560868c3d313b4640ef274fa94e1ded83fc5002c816b058b44da07fd039cc3c52c082e0856bbb259c8f61825cde7ff0b2709f093430444e6011f134cf67e28d8251a4a70e2d297a6e1b46cf7f87d8672d61820e80a26603bdcb9b0a40529721bbd65e6fbe9f0a809e2b34080200fe435e3432a809ebe21c511f97ebfcaf6a7d4bf3babcb97923a5c8e85b6db9e478f334e7a985315828d05472c10cc409a261af52da0d51fc39813880f0935ac0954e7811927321a27b440de7a541102fdd48ebc5b99acc1ba5234c9ead21a939e70251b4ccfc4f801e88a189ecba1c415d4b4eca6399be36d3cad410d47b811077db2fa0205889d45f41ef8b8474850784efd765caa35c809f200e2d3c9d99f7ec4a40c649695c1cca7924a08fb1e4cfedf07e286b598b276165a3ac0c1afcfaf0f8ddc6366489757502a172677732259640e2b4ba134827b04dc7da54ef392d8959248751896661fa7da8458bd3e9b642cfa666d4683da472952ef061effa4003a4cb0790eda28e27fc6095c660c74cef068ff8f3e669ce8a47957f9e801cc48a91dc0c2e15a272cefb512fef454f5e4d9d1decb626a98a20c2af3ab146062a88c19996a64fc352289b1d298ad1f2d24d08d103fd353ca54e118fafd111ae5c0a1a25e8ae5489ded9ab534c826b5f1ca04a358dfc891cfe0312155ffea2a38cbe6c6851ac0df1c00b835ac17c6c358c682f03bdd84cf7ab701e705088458f51d7fdb47ecf5091b1248428e13422581a8b9c62d95e03b8e402fb8f56868157a977e69d8e5b049e5c663fa21aa7b358b2366391d07d505b04f4eb8091a441f047467d2498b1f5f1992bd79b6d6f3f2a7bcb43b67c88a58088d6c2adb8b0c895d1a087464705c63d80a093ad426324f5913141bd858ae7cb0239b9d60ccb4c5faf89e090e52011957380734d5977bf640033e9ae8a416529b3d16e56290ae8e20dc384ded7abe26364e8aceacedb779399992964", .Okay}, + {.Lcm, "-c838bb1cc176c6a5e769349bda2051ce9ae79bdde63e03e03a708a94c877baa31920f1090833560c9e7423fe442a9e08c5d746bb0015a0b1dbaa31e9fee054ad5c92c1c58e7b01e690b0461d30e7ea65915889fcac684e5958ca05aee3f6b1a04711f1efe6005694177b34a734390f6237007aa5d238deeb9494c01eb40b307bafccfcba605bc6cd183560d82799dcec89ac367937ddf1ce674d39e20050809a6cfc7d7ae067f7ad914dd7a74cf49243d536d9f2ee559faa00431b5d96530fff4ad35f664f4e72dc627229241dd22729a49d162d9d809e2f21d7c31a05f80456a6653cc3a28d38c7414587b5746bae4737ea2d5ebfccc097b26b41dd46d4db2488a084dd124d0a97ca9d4f4cedf633532a78a048133b462a1b9736ba63915509b7180d15eedd3ef19492afdf1988d1dab6fa69128df369b2f8b2ac3ef2c9ea0a4794ab4fdc67b6525381d1ae9b43ebf2396585c08ea934163510d0d13b9a2831593a0ab31843ddfab71ef6dd3283abf092f64f94bb6cfcd6ec8d178b2a5bcf8df57c991936647d2115f4f09de3ca9df83dca94146c781c0d7d69c6b8f1473aad2a7397d2889e9fb79ff590b32ea3f353676050a1a30828e5a824257dff512031162c29f5564666183d81e5e4bd90d41a5ab41b6863d69630d2115289a8d03f087a60f494ae795972b87ab261df4b4e9ccf226fd7f18b362b81ee7dbb0a1dda25", "-d8a6398a411db776e1ce4e92cd6e10a4f07f21cef4efe1d6500f7d803a5651ddcec7b83381eada067c46512772c13c5ae2a9dc2e1e8f9539b7b5e8d18d7e96c322805c7339232587326d07cdc56147f861a47a40766f8129cca2d16c8b15b381baedd8e6c9ac637888efa09148f7f42002362018314591767dbcb1b7b47d1bacc383c94dc60e46aed2dfa8e94f337ed1f71108a6d6e20867578cd2cee39364d24582b5f5881660f44513c93c0a28cefdcec784571f6afefe91946b4c404f30bd45f1ecafa58d9ed93ab6f35716ee4f5f59625f8e72a8fb8213cb593eb03794dacd01f44c9c912d2486782afa67da0540f7051175adb72c457409aca9884b75f52c0f1158f69dec2d2740a3939c5bc9662f0768c403e6f8280731922e57b6ccceee561bcbac7cab6c04a8fab885450ca17e5927eb0f70c98c5f02b0672eeb4b3b96fd125b9eb3f0c88f0a727d86732abcdd313872621774e571d5f4add59af3e68b1dfaa3fdb29b8a79712bb1bba00ad900d2dd3b99a9a4a453b3eaec5d751f6502361347a04b39c3afab684ca6e5a10fa133357b0dffb2885586afd5efcbbec1084cda8d2242a56cb082e1b966639bceecdfa637b99de380a3570b7e3ce9ebe2eaf49f16ca8a25d5d530871ef855a97243713cc9831bfce985844e28d3879af8e184b067527ff095f8d1b5e63c1fcce14cef9c4e365705ce8cd8e30c035a274", "a971dfaa5b0d94a18efaf0916f0aea7ab70396679e0ed2a522070e0721f548748d9c230a2b84cc1afac2bbc23f8c54021b1e17a37c4cb8470b3c8251e223b2b0a6e741b8cac60219877c2886bbe021655cf3fdd4a50779f40e1bf07cd80839d34fcc9f1b6104f7a534d6024b7921b5bfb63ea7dfc85f9366a417835b1094bdc94118c1d7ddbafa7f8bd04aab86bbe0a18cdee25a8b5a82ad1fdd4a103e0fdf2b9018241faf6ff8d94b8baaa3c1979bff1bda4a359f19f449ce2c70ee52d6f64b718b46141aaf71e3a55b36718b999a74a6cc9da1755433e6df8668cb0f01780dbf7bd9785e5131cd116d2d8e3dd289029b24c30d114173ce3b6dd1eaabd3ec392839aa6510900202d992cc20a76b3b4e3038b6896ab9bbf1c9edb20e0ea8011af8d761bc03cdb0c66d2d7e0ba5f9d6329cca95588d0a899211bda4d1065478cae7ed8705335a7ef3a05f94ab2e4d2da4a0f357a0407e72d37b643f462baea8835cfcea7c7572425c9d58bc30a7049262dd8ac36d7dac18b30ff0f77c31c1497544a1136c04828512bac22bd3218f9ce8130df891a5bb1bb4e0b65094fc0b7d40783d757dc7f6e663a0965fb1bfe68c8b019582354b7e385e419f9cd3ca753b9544a9bb2d45706bb36e328bd7e5025b43ca4ef6187caec8791bcc25259433ef5463d51a72ab622427f51af7a569ff7788b94acde28dbefd4215dba51b31b83028ca873c4a541ef831c3d252f71221691eff24a37d08320ddfc56ee964a55e867294ceeb58e97405ae62ae523c14a64805ef6fd769cb5a028eccc36133ba86a4ce0110e910d71de9c8f172922fa5dbae5c010952468ef4e3340ccf2593b6e7d593e51eae572ee829bd559b3be1a5190f07e0939e9bc2ff6022b7f5f7620bf45a377afbb9a0e1417fbafe632b28cda4a6e0b3089e28c018ca69154ce53e09b09bce90d3c10dcf161bd4c90387d9471fe00d1d76d411703343dd34ff4a4f2d77f27e1365fbb640bef2a32b19fc8a808760a4d08bf4b0699e725187a73b4679fd323eee26781cd2eb22671fe1af5695d0c2c9350a84d0b9f2b7b31c70e2631e1ee10f13dbe4c04c6d72c5c1272a3462c1cf79693eca528a4e055877b57fb7ea6c103e79d1b701b0fc6f6042d957749b3a5485786af2e057fc843c2b62329b0fb9592fed6a2b8176b34a9f5adfc972e553605bc089eab20c780b2fc7e08109d42530e4473774631fae3d01dc25d61d86ad4269d4a86c0fb20182a9870d49ace7a93479c89347a526893a4f8ee509c07819c1df2f7eb72191c07aa48f1cdfe36a25771144d44d9ae2a49400e207579b1ef70b365410397000b15724b92706036e19130618b7bed568e0f5a644a9a81ac230b09dac7d00bfc49215ded8b7e359a67c818e9d82ae5a124d4b3e44a1f031bf2c21fc745b27bcbfbe82fc72b3de1633b42c4", .Okay}, + {.Lcm, "791707e1cecf444813a18001e39bdf733ad794693abb07512dbb557d1ee560d8ae97e1f22834b77db70a23b17b344ffc031655b1e09159281ea9db22d6d71a53028cdbae09163d2828c33950ebfef0c9f286bf88f908238d82c2f9001510751096f350a214110a4cfdc5082c7500490141e3aabbaab9c9ec008d68cce6277251558b7576a6e45159ac06c776790a5f54b88ebd5c37bcadc8cd5b1b73f30dc5244d27cf451adccca7c31b97640fe2f05c12dc0b721d87f23f722cf83a4debec3a41b1ace2322621eca202bb3fe61c52f16304a8f6c2fbf90d4fec8986f1b67c07e6d1d05cc3d9841d416b8751cb394a8d6cc6108318f18c5b5e8128489d71f3935ec9de65b5f8f562a3cab3f69a7d6ad8968af2a844172fe17c9aa7391dc6031b76d8f5b7dd103cc303ee8a46ff6f3e18233cdfa7555c52c079032e4c5949b03d9bb5bec1b919b31ea0d6df162ec777ade7b44dace3a146905078dde2c9799fe5c1043ff72ecf2365224b2b9f14403f996c9bb00f4a62c37d5ac2407d97e309a07b973e19f7397b971eb7741a8a503e132b10bd82c733e2202496a029a2775dc0edb87021dbea5156e3494f401742ec119f739f3f43523ece98ed0e236892f09e011dde3aca2d99cd3547f74b7e751fa1febcad34be63df52c97902fedb49ddc9c33acef1f4ab8fc20247ad934be59968f47116c4839cc722f68b57a3f315d5f4", "8d8f45a28c07e9d6b0e5eec866e9ed8508f51d85330035a2a5fb8ee574c6ad7bda16aca52e09f5bca11fb8b37ce4546519311b1e6b587cb1200c8e11f3a102a1bc307cc0cc1d442c372b9e4b74a872fa7632327fe732755e9e7ec8277c8c02850ff523210eb8778a1d62d489a3c3af9ec44b22fad9962452d9b0df402c1c0d634a9069cd73446e435c42dde9a6994ab0b62225e3b600858801ade61157cdcfaab28b761fa1289de047b5b2a36673a208a6e5a16169f169b318500b94f5a90cee4ddd167a6520853da7414d3f2b64439677e30536f84550e7d5e26a494e40b4a41ccdf7c3ebb49550d76990501031fe4ebdda1dd65099357d60771841b4edae6ea61f9e92a9be725b6746526bd8e55f916263153562c88bcf1d6af05f8da61ef3180314a6619241a1f6733bc7db1d45e6a4ef78c55f8c35b53df9d12721375165c9cbdb077fa647c62e842f0c4ae1dd36db6d6fcd17c439eee5e340c5412474e4274f594843feffbe463fb35b5b6b6df7bcd50db119f6cf6ac95b162b7a0f257017570fa94d538f81639fea410590c89ca4eb769e9edc6b4f0500028e1c5a84fba12b663c672140f5722e69e2eaff27d4733dc8032455352f004355557458c63155ebc04cfc135f301164fbb6dbb3ab2fe95dd1f72fa08879ee6ba29b110d262f38a648fbda8381a4a79414d0170a85f089b5d10348bc844e4fa38d0d9a6b1c91", "42f57424ddf9de91cb034295cd6873b48d79d20d27c5f9c965ef5bf5213e07a41bb28444b792ad62dbec858686c1a47f1f33d2220f883fe50d4587555aae35fddb551957e63868de88c5700f9911384f1cecb05a7f27c11ab20322ac96f74c95eefdf979b32b841257bf440e65267f761da89a7e5eb1db04122bb59e3160765023cf63a8187dc6deaf0613bb1d0b3a7b99d69b168e3bd5b6f23f70b4bb035c833ddb3f5ed17aadbcb3b125b3c275df035d757153df48ab14ff29724d9ad2336b78b7c49e8c955c58281535ab2fb6733799419ff85dae7e89a7ec4c3413c7dc3d28b2045cb616fa3b3a3a11017ef39aaafe213577a460fd66899681b27e40830341d800b58fd357ccfdeeefaf655e89f2d43c2eafa4203c7bcd2320ea85fbd25548a3f8dec931b1516339074e5744fcd5cb71d860947be0709a1f04ac44ebf2be3d331cd75df08a1bc35f0745ba4ca7b8e875b5cc24e7f426e0ae568d54bb09cce856df04b4be2f88762d185146a64f540e528f46f65e5c1de0bd0c2c31c1390a28ab7ec5c52c2b4e8b00c72c60ca99e597c852884a09d1924a6dccd347de4d9a6fa141d9e3c6f6c1f76566ff454aea0f4d29afea39ae672b436c78b9b945e870d3a36edb7ce5519e942a47f0584f576e427dc6460a445cff9c4f54b63aaf84ba4f34aa3b049eda525b0b4a9c60571420c0134fd4792e610ebbb9e29a5b36c757a89cf5b9bfc336a54200983a5d49fbcbd8a45410c482a0f9752e3243da85acbe35b8d633a14dfd4373e813b8aa54d56c9329abb6d924ab7aaafac00cc3e7e9de34f7b7b322c8132197d64b846018c5de82d75d7c2f0c8ca64476e4b603775aec5d69ba32b2910a42656dfc5784f77b36afc75314e63f4a187d38846a3aa167ab7ce274fa672be51ebd8b372ca4d37012007f46d47324f73361ec1d7a8cce373823d5bf7993b16936268a7098e21a4ffa3844216c9e105b43736f739df2f2331be9ada778e904beda74e38645a89464d6c3fa723bec73cce15a946c8df98f508ef58c17ba389d594f23515650eb261b576e11385d8f91c8358a896f38c6fbd7194598da72c92e7437bb9d962651e07735ab7e8271e15cfc1987cb8b1cfd54b4ea9fc73d085faea02b1516f5228cde931a3d364dbf500ae8440817522e3c03eed97368ceac07d2637f7f39ac0c972915bf70597d712f94fe3dee02589cd13b008d71f32336b9161e6d9d230376d21d177f6f05e0b9bb6e45a2fa73917e82b85ab0ffefaba4374efff6a272dbc1d2c96185bc279f0456fa583371e594c99cc49a41bc77c0ac58ab629db3b8c3639b5c86f887f6526f7bd5352fbf6a33e63806cb0ff9ce69ae6b228fd65302902cbbd4e1436bb88ec937f9d6b0a2fa23fd89e5e200afa8a1286e037cdb3fbfdf491492deb622b2aab8b16ac137099390ac47c0df34", .Okay}, + {.Lcm, "3f0bb33419528fcfedb7e0b823a21e0fcbfdd4fc3900279843f1328e60e3d3938a1951184034614d930d15702f8dce20f2c89b80c03421265d7328d60bebfd8ee7d646daf1e9ad7efaaf2108e2dcfcde5d3a77cfa6bfd687f3e63614fec450f3d675132792d27a067693d31075cccd0ef430cfcd37f80c7194a69ca692ec19c87d7dacc819c3c4b9578207e1fe9351124e24684d088ce49a1d36f76cb71c7e03df14cb02ff48d0f2c4d1692fa9b98f0e9ab422728bfe45956e7a3d86ebe3afd851ed7e025c6d48b6449fb2b1b09babc4a04962e0c1a84e0acbdb11df4554ae906ffe6715cadb618dccdc1e92641f3c305311d8a658fe5ba4b49e8c76c57a81e98b736d206e39c9495a560a5581582fca52e0ae8d14590fcb8302cea4a419309bc4ea0a8621307a19c10395b81b29569ef9fe6d31b2cce8e117d355825b9d30110b4fb9ae1d97fcbbb6f2ca49e847271824aa74435c8099548c56f144f90788c63fa552e3951f3600e0486f7909ae435f9d6b93d82edfd649b86aadf6c2ce5303c39081519a3ddf96a9634709111cad9d0b79e69d400c2887a1672f1923a38d108c03423fe13d254ead27afe7cb97acce8d4af5e0ebb16a6686c01c37c33100ecca198165a7e3e40a7794077441a3721a43e8400f63bf1467f1f17196bd6554c3e9d368afca826a68a6de2d5e078bd1a47f75be42aca7513307362f8a3bc22886", "5162768894c8e6cf62b1fc52e3f5b88588fdecac27f936bc9c50a5d01523f3f6c0f32d169e8458811dba11e3068fe68b3d7051b04f7f51b9953b3133103088b1f15193fafd26cec40a468a0a92391680c17efd98b97feb2516c053fae9e45be01fb0eff83ba8fb55c7475679cf64f11c40f0ae9cb47c2d477dc04e4b9b3ca726fc08ccfa2dd151d5f6e1aaa9670118d22abaee1fadb71f0f5b8f20194d6f17d61b408c28e9928003b641a8f9df98cfe21a135d2852206ce8c39fd53471d722197728e77c8a2d226783319739f5eb47755358e6bb9e3c476016f9cc38bb1e21e68241038a681ac077a29a9b10cb921b8dca51b67c797180f94e02efd6921e597ed26f40a22ba203df21950658f6dfd3027b77c2d46443b137ba69b10f07afacc0807709f68244d0b51a7eb11250d9524545fff7b428268da7d375cecb5f0b3d4dfd9a65d098228674473452e09cb8ed34838349725505924bd4f299059541454c4de721036c8b200c9c2d66522ad552459278217de9122ea5a2aff3155ff0383357f7b06827a2377e6db9a6bf766d9d730276bd942b824d1682fcbc54b9cb4b5549406d27816f1ee7763a843710789e4df97e858e03f7fcc029f97e74af176cd7f7ebc6958d7adca16a95c5a9d18d9b9e155cb4b7f21d24a0858732240a2dffb1d450f8757a2a30dba5086f9bec5d0052963bbc8e7230766feacc3422d4ac9b9a", "a0579af8eb5230587897af0a97080320128ccc522f782cfcdb006937841201a94721778c4381d652fc627f44303f7fcc4033eaf4ef1f32bbbaa549ebe26110dfd009b3ca00d98ed37e1776f74d00fcac8d9853ac217cf8766618badb448f086bf8e1d54e705e78cab929b9df7cdf12a9939a44f99ca43f78a4c39b7ab7b7a350a702626622a844aee00f0270a63a877822ef3d3b5523bc5c91482efef28c54aa9ba2d45eee767413ee822cc635071b327a9094b26a8dc0171c26124f9245d591b42ad886b2e2b9839805adfe743f83cee11d903fae7cd0cf5640aab8900cbf70fd78e2f5d41fe837c5a0ec6d6bd9ae51755410c06712cfc42f38a7ef9f937d317297a6d63d23ae9293d4d7c7b98f7eedab756124a6994d429b14e79b768f4b0c674f37123e5e90e8ad60903d3f4c2fb3eceb179d0bdbd0772e8904a7224ba262e340b70d9e020861b1514ee76ed76d7d6b5fcaf9734b4c8219870d3cc09962b387ccc4059196d848ac7b1b540e98dd5e2cb780d2ba7fdbcdc576e3903e1b81195e2a5821233cf68659a0c7cce5d4eaf10dbf3bd3502a3ca18d4053f7290e3fd9b2da2ca1c3a088ab9b1011e786aa5dd255d1b8489dfb78edd3db53d409a5d3a6d0d52093544b5f6d4ce820a1e7fc116fcd69c58e53016b123d6b0ab4447c243eb5c046b95f9ac4581eda6263a7f33e36b1ba5c309926bf52562c3a23eac022526bdc4dedd9785c54c48f31368c8ed803bf0d0a90e8ec831bd5110f7e9e80f7edf64ac2d2b3c1ebc90f05aa3ef58e77c8a11c96ca1d4cdafd855ca1ab46489bb9939bea2aa1f5a8dfc176abdb75ef3c40557c1f5162d1d6b573c3c1d4f5f3178be56a86b0643c494a2cb0ae96321ecdb8b55d67b2722e77548db02bec18899403d15c8162fcc72ee8f3f0b7086cc2a46fefc40566845d226cc2c885e5237401d88f2e1b598b592e7041b5bd60ccf7f6cd7d840b3635646c226b21147641f45612a6cb1261e36cf64e035672eefa7b7a8e6bebf53a45db3b2e30fbceabedfa50a4d1664b32fcc7f80226dca44027c0176852fb962357d9a1a778920b4b8762d48624de6e8483e628d65a902465fedf71e386c08c436c216748c31fe4dabdb126d21fe68bd87063982706c22a4a21e82881a694bbfcd10f9a49642bed2fc43fc20c772d2f6a7ee70c78e6e0da27977a1eaa21f4d70a6dd4ff8f9f5d93a2c73a31a60ebe3b54508bb812fb3a4ce015a09a02b71b9b4d208cfcbfe8c9a5a847b96911cdbe4986fc5ba0b283ecea1eaafc55b2e7da67340c5040922b9fc09730047d39f96b9685534c05d962c72d1721c64955193df9124e04a8473f9d1bfd02512782c3a07fd908c7e6d1750af8b38c461667a4352e246951eb4899e18214d2438738adcd5760288f3fc9fea90b6dfe86683b80658386dd8a4195b456a9259aec14e", .Okay}, + {.Lcm, "-845c41cfe9ab1c3e40c8628055518793ed65310282c439e18e4662e3464e6142ae909a13cd00384ec9a94bfd528482f37823c8efbed923c3ebd437749a0058f2976a21f9611d9b175657b7660c341febbbba3e24bcb1c1517a957e8e190e19d4219c74475cc9815dbbd3d6eb76d796515d269f16cb0bd8a8bdb9f75c652ad40e1bacc9344ed64394ec9532dabff383c1cc948634eb7ee2fc1739dd7d7aacc137fee3957afd1157d0f6b3ca96d7f75d1a2d4c9e616990e1d71a94515edfa4973c5e66aa7739c29bbca6cef3af077204d048e296f596224c5a56582fc2fefc58599f1c8ae62f1f4adfd3a365cebbf9880c49e93275e031fec2d0e7cbf4348a389ac93e4d37c976b3f3ced1aea4fbf6a0431de72d168d014bb440c24dbb465e991caa02a9aaaeca4351730cf2679bf656796fef8d31529534bf039590e2c90ba6df4b4af8eba626d3e8258e2beafc1f9385581c6b469b1cd687323f6a116c0b1033d26be716d6c51c67db80989aad67fae63da13fbea497a7331bb56e8867cea5cb09001a6ac163d2653358b6321d0c565bd485aa4864550131e5145421aca138830e1d9aa7ae83b75c98dbfe0b06e9445c1b8f4930438330f328c722cef45569cd418270847f8d7541e57f5f87a309c7a2b9355a7e114874eb558c0ab7b8db7d5eb8f2e1106e2a5f8f9a412b07a93abeb233215f2c5f2a0944f62962e017da5cf7", "e08e998a07336ced025e9385a3204db67226769658ca4cc0f45c7ba2dbe365d35d72ed20ccfa36d9e21d0d76845e7eb389287e024f41d1b6bab2b303c64619b3201a609f0cd9cea12af75706315538e0aa28a1181901efad51ee836079b8d9623cb80b235f3fa1bd3d610e9b1404013377f8794a3875fad46486728d3b2339c6af59930f05e33e66d47b86bf9482e4dc0264fad87842666285fcf2d111bdae576df6de2ac7bdd89eae4a453e50615dea55b04e236cb87ff273ba6ec7deef50f13dc8746c4139e261b92a42565a79168aaae72411af4c184a6d3ac7e0f891f910e58efa79597d897b4fba73269655457e449a2a5da72a03d1af7c32d3daad5c5e16d5904e35448783584a36766117ecc43b1c8a882a5360b2e87ff8f9047de164e2d45f5ce9a760fa81ccfdf208d16a03176db9d37ab87cea595965c4b062fc25bd06eedc77400948d4233df7effa48d844e3fe637e706908e48df0f941a846713759a3586c92d5e0f6a1465b25423a415570f3b0843c52bbdd24e9e304bef82c5639e19e3f3a1964d35b4e743114ea6c0b83677d2cae4a4c7db52fe96fe251cc9f4d5a85fc7c89eca29eba4538c8af9c9df631b841c4e00c858791d1200ea0f3ac9018c0e091dafab9dadfffa21b59db9c2286fb24d3e43d4323d89e3823ff295fda9ef657c093127f71c81ab55f72c404d9913970cf3855438948d4a00109b7", "26b37c0c4f8664f38a83bb111ad1ce2766752aafd80bae75680557c0fd3941f7a063db84e4dcf349a087d3527133fa3ebb526efb3a87c5bd4817451f4df093f5a6feba0e65fe54448ef607eca91d954da0018932f9bc4374d6a852cee433d9359453d13c729ac1779f43e4f2022c5e69cf64e924371fd72bc5c2d054f542028e4acb71120c305c3affc8cc8dff076f63bca4f6cfe7a05fe77ea281865bf55a95eb33804ae98e279cb67e76373dee33707eef1c3a0ec72d151a3ca1864f583a11111d4ca53b793cec0b019880fc9e68e073c333889cead5e0165beba6c8ff8ab945bcb5ffadbf97fe9c619b24af78bacf726d57d3db1ceb620e237f15a12cd15b05f88d7610a4f9a66d65027240c7322af61fc7547f3a4831fc098cae6e113879859f607d4c5e2e906c566acedc0388b0c307251437d593fb90ff3411e4b5319bbbf25b5c5e3d8bb8a52f86dde64777b24658433d8f41e6108e098d92a6fa5f065bb35d79362267a4a4e7d525b1c6ee68e601ae48d61dbfc617320b3c23f3be1f2c6ab1ec532d9d6b37c817de5bbc00d82ec87b5008ec7d4a96447fb89ac60155cfc070173d5c37017f541092dd0f47888b9038cee4acdff807c07489dd8a5ef91518d66e2aacc50727a0f7bd2be567eaeffba56817514958e720acf1a1071082a0662b673060c9e91c83fc89afe670bdfa6386bea9c1aabbac3ad9ae63b5799e7e9e13d737365367f293ee84a229c89afcb1f26b88425f9fba62644312d877adecaac5f006e1255e355e3baf44a44351693ff2d06a54af6ec22a3fb9485948b4d6707b2b1cee83ffbb9ea60c352d51596b744469f77ca95d0f9a2832d5209b7af5c6a9bc661234b476f82138db717f1227df3c2685cfffa4d4670ba3b7492f60b0cb73fc13ef208066bb03b0d2b96d663b0061a26c44bf6272f2f34041936bffbffb073b43c9e87edbe84abd80d10df3a3f575be1511d084dfcc310f3d29f840a293ce296375515883d6592ebef605e953a33297ce3bc38a3acddfec0e6468b0dd56d6ed2d13fd2c64d5a3a2b30ced25765c809cddfa48a839a584b3c054702c127d4fc2a1f5c890e923a9f69ef766fddafccc42f02dfcba1e7697f2a10771a97d75f98eb948b47498813924a7738c982ad5ce730ec5542816d1e37577ad3eca52bdc2e310e7aea0ef725b361761f1c251131e6972cfad61334961710dc5aca33e12ac7f9ef05a9e2542b6cabd20f6b24ee8c25a56d3bd8282b636f7bfee9beb1a290940920e8a81a27f2a5103388869de60091e9222b940ab9c71aef0b624dd3e74541c5547e46a676d79b231e538de5eb1dddbcbd86f23a1d58ff1cbb20bfc22f6bb989b06dea5ed19b632281402a57d4583752c53c596a210a252b0b49c6464acd063a8c6b05505f0ebde5d364e964cc0621534c4ddcc7a00872d7d1c0bdb", .Okay}, + {.Lcm, "-5249b5e8b8d230bfa895f84f2fb5b15268f0a4982b3fffe670394cf6e94c5a5bdfbe3b68e5214fbe0ad6afb13435f03d0950e019ddcc9bb12d967ef08691f97c417d0da1bd9c627f93036842bbbaa3f1a244a1167ddaf9aa947ef719a18156d0e94ecabf1ce284d8601fcc09414af0d0e0b2303f709271c0ab4d48687e851b0456b8ff34bcb1d83df75d45c935a9e42854ae4b3f9f0aad7d2ff163129da94d820823ef32cc2b3feccf36f4182d982a182f997dc83ab8084fb4d48cd84ccec4cc1aa405998897e207bd63ca9dc630a3391ed76c87c8136216bb0ae269526433f9551f9b0c1546fa2be136490c0031064d585afc5f2b804dfec962ff2b2f3e423a9f850ee6c0268220113fe55912d52cd3b7db7d5e40e028842f7ca6e5109d12fd427511dbef8bf53680c3d27b1983da3fd1f54114bccff61432f35cd49d2c8d8ba771b7be3120cd7c6e9b861a4bc58555788ce060707073dae4e2111222c235f70f0413ddd982e9e398ba39c07af355a900d1fdbcc083d9b158b3641ae6c1bea3eafb5be79046d337cd48e272a006e59efe5e2e6e6deabc1bc189216c851ecf944a8792ff77eddc0fef52595d77755fb2f51d953337e255095f116deb678fcb74d3a70c3da7dc890db9db16022084d1fadbd27223b5aa3a0ddaf5d4f6c3331ecd8b64700907bcabcc37a44820c3fa8730436062a67546ab0f914f86d0efbc13ff", "e5cf8f9c4f7d80489ded4dcfcc1a4d8dacc50fe20fc48e203bf05b068fcf6294ed379ee38cda18a0763178b418a3e15ff932052d4a3c22078b22e47dcb6bbb40ac4a866dca8f3c2c56f2f9c118e4c135535ab15b12d382b566b4aca11ed1e05c2913d774c7bcf726c3364583305eae6bd4e1f811091875329ca23ee1b047b6730c42175e09ac5ee64c267d891e31f04d03541f5328488fb58d92dd3e5c8887b859f7fb6e85e21243f916af09fd8a43f2da17dab29b0cd87366f4cc2236856d7e3bfa292bec490d2253cc7a743f9f966558c1e93feb08851966012728362c865ed4f2581a8fdd93408cbda3c8bc21e1e3342f96e2a7dadd75d228b8e03e059848a71f9af8e5e8312e3ac9c1f13d480bc61042b107672c128c8b237a24431219c8153c9b6cf12bef8171d36709edb0c90b3a31e4627930eb4a92130d7af69a24187215ba18004a4bc1319d64e0ffb85907950b2e6163045f7a68e019818e9c4f28fb8420f6bc7c49c9e75f8b8f244f5413eacb6555fe683ad056a54fd79792a5f0d808c15df4f0803b993366683ae03e098a1c23c487180fb04053d246f01ea20b95e15cf227c70161c4824f824627e8cf0ab01971e21dd1ab608e75cdad815616ea7b94d464bde2b5d6151e39b72437af6502a530bdf379ed60ba469c2a8275b5df65872852ae266c1bf8974ddb9214d24188df83b28cb043fa30c23394ce5ab5", "49dea77caf9666fbbc3659b33d9e151eb8357008c08598c17419ac92e67fe6a35bc33057538d7b85951f367fb1c6a4c667cff7f85f61f864ecbbc10ae1e30bb47473df9eedf1e1206be12eaed45d8a84b7a5b4d5ab2c7a0c9450aa201206ad6f9cb302e35ab136b3ba66622ba5e9498db5d732b756b981580f3551f43f1acdf1ae9dc933afcb45a4011275027e7ce03ad8c4781c873f5dc199bf03babdccd2195207e7fdaf5bc293d7c6d1674899a3f1efec8c2e3388a56fa93f8b2179b2612975f854b53d021893515cb6b992a476544f2ede3abfb26156960e2f4cf9eb586e15711502a07b2222f112cc92164e1824a8040b7860d9360da4269f7bac387995c1cfd7d08f9cda6d4dd7f24a88996f73f9d89bd2610082272585378776299aa74576f84f0608d3c48bc10022849bc45f8b4e090c644e78b74089aa0950ef2f3e104030d127ad2ced5172703dc6226ddda8a6cc616a27082bdb824184784f1b0231929b620f6c935e313a5d7409fa9a9f23537b06b7353d1c84bb35f156c35103c93619af7c15f6c233f3bb958d054e11930aa850bce9a7e484702775cdd4614f38961603f438a3fb9dd01fbe442a45fb40981431a423cdaa1494633f53ba66055a38487419d937679b6a0f443cd98a20f46b869bdbb44126503ab18f004f8faabe785081363eb9af682607c3e924139567e01ad59e4371f636dacdaf29a34c9f4bb6efb699cec7e05da522ab1b8d8b221b0ab64e042a753f01d4de1b8a8dcc13fb21b35319696c2eab381b836c275b16c4e0cc1f7c471f8960e6b729deba154905043d7f004efd6b9b05a3ba291a4eb0a7bfdb580d8dc0db27af39a3dc81595400b9b811273950d02a3a50dec4e72f9b0c41c43e95ca64898bb6bf8e43b758d37c303651e48ba5ca91ee35cdb92623deca7d1070b5e2042df8e3f6d7d233a2a7244381c39a39e4eede776ac2e7051e70eb575e176acea227a0ac59e380f23957d21201b885595371f70e8b86ae7bb54515e3213711031e37997d63ec1d027c236874c05f95e255500d1f849bb0efca660620a056f2dd0edd9e23444c451661d706a92c59b707a46b7bd4c8e97c100138000780b6096962ebffc526c5fb7c2d95f1e75737245f7e14d8b43276537cfc8d3e3e4c322bec258aea90d59783c27afaaebfacac8e2acf644695b45a8222853ffb4ba76082e23f5ca40fee9943d2056406e48dfd97c379ed2626536c1f3490b0e305f5255a22a359f25c8d222ddaf2b1c9c1b9823f5d28d9eacb2d1d722300a92db112663ce9949fb2005af6c028328f8c8a74d466b1e4fd2c6b5457cbb5a8476e47665d6437b999dc45a96ad83ae97b29df442b172826a6ec14907b7a60a7e7ff64afbb009e1b098f09034aaccddba4d384881c84b65e65cac04ae5b311f3ddebb172373b5caedb08c8a4b62233c94b", .Okay}, + {.Lcm, "22640e7d8331a53b53f600ff617b2fbbbbd30c2d006b5e9f0df41838e3037b03c2f6f6c6cc1301e2a0df35d1d0d410d61451bf3a6501ac7e0aa4adb63b1699be4203b1baf100f292703830489cb44633df309842fdd77ae7bcff93a1b9a8e238372b5f67d46fdf25c72fe8c764ba35f5f0e9f54351fa084dc4e9b8b122653ffb3bad23a10a207acd9c65c3f2b1e7c1d336f6ffcdd662335ccd94fd72ae4cbf32ca4d6cff01b0b832dbc056f9ec4cab6c3f0b5e0d2bdb0bd4b631a0e199cd24e324e97046356f388810e0bdb110bcd87d81edba8ae030b046f5c68813511d55613fe1c6f7d1e7e6d0482af65f1b38dbc6c9ec2c82703a41950fa148dc4b339f987513297cc4444dfee357d1d98fbba28dd3a54764d976b8e4adc900fb3cbea04bec042d2ac985e1a534ae297aee38eec425d36617018a2d82b7724e421fa5df0fce5787a07c74f7c766b547aa065355c1801cc35c72393d1b99ad872c82590842c7b7359453796b4441d6d77389a21e5c511e95a8c397df381d954d13870aaaed8703aa7154b74c4af6203852af05c18228f77ba346ef5e3f13f96cb0bb0257d6c9a71694c1fbdb0c6c02fbc3055115dac22e6b2dfd5eae2e0d6a04759619b1e126e15abbfd607d38362ae0ec12463ab036dfbfc1858259786793bf436c2da751afbd7f3c6779c72e572d5eee07e4ad467715eb081905571b0adc36e8bf0a0477", "4e02637f8b9e9500b33937eb3e6fc9cf8f555559e71a73f4b7cf9cfeacab5226f00f9f383fbbbde8835c2a3fdf83e1074592bba2543f0438eae3780a2df97066dc9c65cc926ea2ca2fa746dbe66686a4953b053a25409227cc27334120fda02a7545da8d54e6f80a4003c4e00e0560b344d0bda71ec52d3b9c508cf834e4f2fdfd5785306648f812ba93cc7d50be9e04ff0d1cd41be56f577a664a69d0eea127fb1ec4b45101d3f4ef0550eb540626976ea28201124ee08d949ddcc34404dda29d3a1d00aba56aeba5c214dd8c4a3fbb76a90d1d8b5ac50dfbdd18cc99a56f2ab4cadcbbd0732e34a289ee38ce4e64661017bfcb64cb69c14faae35de792d652cd6e93bc334832074956d7ad1417df30dc457c48e6b3efe94dab7c34fb4d131f12d4c26a48f2b1786122c9b35384d3a27b74ab4707165def9633502b7c1b51a55083382ee377caf4992e3144c67e3137a024a3ff8073a86242e5585a92eb8773c0c7d6b1493a970111da395f805f092d9e4cb2f1aa7165c519dc7af8354a9ffe58280019f6bc83e980a74e46440a415af16207e597fbe610058fbfd1d6acf9916c2bfe64575146b890e1bb3cbfff0a43ea5d851b8ffd8d233dec8456d86b112e390830125c28c703df9f5459fc529545b3d54fefd68b16e25e013a83cfffcfd4688881d7fcfc98e86271605555bc01d1849fcce4aa138ed9853216e9c2a80f2b", "a7ace902ef3825f12c826c3c786ea21871d659ab41d941d885dcf79e088c5d9c87f888bc797855b41c7e83a97f4421e72333ee1e2566976aba97ad6ef8f25630e07b030f5b6341645bc6c8863ef70ebd137705bbb31c62653c80faaa4c851eea6c43d1feffb2e98adfd39935fa64d27b77bf189de0252a234a3adc90bc5f71605d709ca3f50ed74fa7a07f151998741fe3e9457f5ac163b5b4459194d5c016d769ac9b1a706ea855bea86d24be4910538e26b7575dfbe215388da642dc1df5ce4c21b4d5355b91b2b36e2b693b64cbfd3606d1642e51d3f81bb54df0fc32276c7d4fc4ae98974631d6ff99f92f482cdca52f4ea46425a2f913c37610042ba618e4c474636062529fc256deb10f781f124881da03fad8273aea81c74fcd58ebb262330c9e6b307b42962e5372f4c58ee683a291e5553605b2bd441e2e4b064605339e306eaa32850bcaadf7fef455ac4a9e63c7c2529cbbcfdb418ee455ccfe0ef71c3b89c806f80ff0b1edac4b1ded0630a919c6fbb5eb6d75f9a09ed74fc262414d3cd39616201ac026cc49ea37ee853a545b2683e364004744715b01d3ef897fa5e8c0a6bb5a2c995b7c65dea8d097ff57ff14878fbab1913477ffd847c144daf27e4efd981ebf6efa911a6cd3a0fdd0060d7afd44342a426916003a4c14fa5d9ac9201d90eda55a74682c9f1473e20fef524c657746758fda8f698c2deaf5e9f46c305408003c964a267a070f95e2f3bd9590335b05bb0b03473c0699ed27c45d917b8c263d7f88e56c09f4f83a47c4bc63690dba968c04c50e574f2240b787d6df8ee47ebe9bdbc0bb09734ea8500ed886f15ed4e3089145db9b6e8c0c7e9e60b7f286e539f44445cebd9ecc3876c964716e9e5d313368b4a52f4d5d3ecfdbe457560d1ee4112c421725cf038c1eb6ba8d52e285ea33b734a257956042d73ac498a0aa348d911e71ccdf397cc1408527715580d2e87c2f06b3491cbcb75b820d8c6739efe5cf9123b2bd277cd4a5eb2936b20d5ab80027aac8433239bfa9f8d124616528060fd5d4335a3f8d31be207fff45256e7238bfdb0a9348b30581a5cf053f20d557af5eb9bf7162b533f19a5421d7c81cf7a1f9cca9c0019ed6cc898bf33e2ab24ddee53fe7db76270d7318e3d541651f3721c36dd3e12ab541ec8e43565ecf4094376605c3d4fefeb3ba43bd7445682dceed3793751fe60001b870be72a4a7ecbcc0f479f84b359c50a6f4f6e2a55938924d56b1712af0e95d8e76d1f69697e42b98a9378089a8c5868ce1f73dd1e1d3fd60234b502c69e71384b8f41ee2fd17aab7744162170bc94e5e4d57debbee556dd5414c545a79d1ad2dcb0265852558c9f2aab4790dbdbfa8e39c6626ba1c6de07750898a9e9a172bc936373f031431572d1a2c87fe05f721434a5d55f78a282b492761c8dc909b8fd", .Okay}, + {.Lcm, "482b8f683f818274e7aaf53458d1195b0facf91b6a7e67bf400298234f2785ff30760aa673bc593ca733d3a9dc29f112aa4ee8782a1360342ca887e8dd860008276b8a3dada1641d3ddb42b04eeab3b4e98fcee76879a91859a6aa29c0436af701bb99f26cec2d32ff795e5adae82398161c7eb18fa7ce9ede931c51d8e1419148c06022d3718635921ec713548603631095723beb33d7477e092334237ae71aab9e6a27764dd113547058e1eb48f2e5039cdb866f85627cbab9d581e5ca692ab6d2aea7affc97da3653b9065793e7c591be2340cd4c6c0a7853a64f75f9c3396587beebdcf45b51c3f356b7d1696eb40b9ae44628c800717b6f66e98b01da6c98a5e720feb45b52998e3adc835af97cc200405d43b072b789c373e58264d3ff689f90bf7984ce52843ddaf1881d44d7b6ae69753daf968a32c74879a4ec4a8a32c66e6e33a18fb4483d3dafbab140647b417e762b0113cc0a5a7ec58dfca7179304d95616714ec07695fc9dec2decb1b953a65ae1ccd885de9e8f1ed49e9f920fab044c8c2a34916ed9f3358a3a9c2eb0668aa3ae11a6bd530cacedbc72f3012c0a11c1ce57c40a51a04c835a0df98a0a81908a7d31c765db713f4a482678e17eb276ea133dfb3fab008ded5f94c67873e9da9c7acfe2a64c16e94427c6e21fde30697d0ed210050d0a4bc5f5da03a345e4a44db3a014585f2eaac307e17995", "-30d46b1e7391ce0e7a3a5dd7f6075dac77aeb7092c00b4ebc14566390867157b2ab7728b02a51eb91d660912665a8bef2e2774ac83d0c78493b6c36c262b48489edbea49c6f0041b4fd74c9ce4d931795b9d4f41cacb1afbd0b1c4fcda724e33394664bee52ab6d94734c38f5bf9e3acfff16b3a0ff346794232cececa1d95a98cb4bac65dbdcc0eb9866dd3829a9e1e698b182bfef876563409271759bace865cd82035e3d4bf6b44a91155e98e41bc385950aecabca5f3c420e65c665e4d19e0cbe29398c2a66c8e0dca26b4b10519f2ebb8b290f83b4e6017e97651d72dc2d89105c0f8f94de49def8e09f7fd84695c99b65599ba4437988017c0b6c0235ca0e050aa915726196950aab56ba54509c1efa17b90262182a080e13626971501ad44e97b6479a2df2b0db4e396e23d49e5acf51351347672d28c32dcf9f8febdec048131c4d559d57bf66f439f9f0a9a39aced320a21186c362a33c9f95875ad4973f128774acb7348719a3f06b8cba20bf7917f4d208902c2eaba061a57eef9ece3b62a16d9ef2a2370b8fa649a49ca0504a40ac2216c19075e5e32f82b8d983acde7342dba285e754a6b4d0545d2f58011d0b1e8c0efccbf13a6e31784b554f9503e7e3c2b473e0e3eafa992a43bb2bf256df0c2bdf21186c74bd6d7b45410692ba3fe6fa03cec2f6a4cc0b2d7cbd9e5caf096245b62b6fdcdab3e96e0e03a", "dc40d2918dceca7b7c4258273caf281b5b11f256668db66d6a88d2c3b346d0f1490c1aefea521f16b061151dd30b1d6eed1ec49b99df6071fce9c8b9a712e384593698e7f88998fe0c08af4e19e98afa220a277e96b5d995d08ac27083660c832d09a20917ee98f94bf06516e1f1c27acbd310cf423eeb12ad182bb0645603c1149935122b1e9832cab9adcd0bf873cdf1e623e4597a90f2cd4da1af29179dac2a027ccc575cdf6876927cb3300c809ccd7b61bb8b1eba8a31deebbbaaba2f08239d912e7625c4c3a54b90441ac794b02749f4df0ac492000d1380bdf66a203ab4a3b9caf4a2fe9a7e28d717114340e3684cfdc50b86ca250796d8bc1ce1bba6b2bb4bb4f174315ad69aa2dc2dd646d88e8e4b0dca947ee0fba07bc4fec71a57380ccc90a9bc93840ffb05e0f637813532dd7afdd9f234ef0735765eb2c5914d4aba37e637a8fffacdb5d56f50badb84b358aef2b8492923832ea46c48a51f68053e3c55f3f1a1470c27bcc300f715a935c9654e4ca98f7827ec511eeb9a69ee3cf8c13061c0f217e408fd9e788f7f778903d11aa3e8e8d4b35e3dd8dd63b4c2c50faa9ba391ed746fc4f8df79d18be43248344f8c4ce1ebff17d616be217a1604e79ceb1980b13443ebfde62b5895274300add53d8cc768fc42e70216abfe65cbecabaa4589c32237756ad35ac9bd7e866558071fdd3f27fd3f0f7b4f31d2ee41135f9f23a00f88d91be5bc4cbe627a6eb1b3dc9ced351001c2906fa8de6513629c4b1a23c11626a1450e5c7a55f99dad3642d772ca82f4e16f232a3df95e216ecf5d0984c491f390614931fb88121b38260381936029a56a5217ef26e9a3e46ab259be70af8a3f6c2db262a76cc29541f591cc378a9d5163ffd0a7129fb8e2c603f95c9fff6a78c9310ffd425b4bfb48bfc327c3b3f721cd6314e6af6ff68a29a3c336e9730706b1fb0abe9a76da7a3d77552dfe8d2e4bc5029b47c25f48bd75a117360455f3f1df4a7a1526206ef7291b248ba3fff9ab1557164faf1d58e805f9d1e2b28944a94359688949c4ca1adc311f09e82ac568691c88ede63c6124e920d8aa500f209acf30509ced6f1be8ed32f05216967faf12032f0f2790bf79afd3f9735b6ff18df76cc3ad1ec9fbf657e067d1c7c780507dd428b22f0052a2eece6fc471cf6f120b5234cac187966ff6598b57ca4332592ed1fa3076973da15cfd662f7d045963df9f1898c1ddad7090bb55f1b9e2eb74ed025ce72ca34104c6d6fe753118b0af53fbb21198caa6e52dfa7e20321061fd9b2c647d99a6d412a274a74b216478c8859103db88a84bff8f3af1519b0194511c5e903d28c059ea4c945fb677def83412af40ee3ef124e5e585a40deb3eb0650b720add3b43cf7b496ad36a31fe2ebee29df23e1b3441521a5fa1a264dd056396552b2c3d7ebc2", .Okay}, + {.Lcm, "-6971fc72bca140acc2a8583f5841200a8bb894072e3d15e8b03e902314a968e58912bd7195a9b7dc24163a5ab791070ee378b132869d87ff99a436dc8fd10dc32ab86f1609c455d148faf4dfb2a9169fa37f857542a471ba7d43c6241fad3540a66e21551fc166c20155f72cf16f87938c091a2cc1d8f5440cd3053a621420961101f48c5c947e22da9f95c58bdd5b51fafd9505c26dcb3bcdbab8aae5658d4b68ea9dfb6216b325f6a0301485c52118a877980ba39bf47828b29d4d29982b21249b4078d473702d508d80cc303e6114d3b72322992265281190fd1e7c893b26e5e1f7bc12b21ee1a9ad23d8c64b5a215ace93a6156189ae75077fcacb5449ab462d979abb1097d8ab419f237704208e6d77bd880695cfbc69248b7d8a9805f1774b5a4716045d26805a4d8acb339f19f10e153082649806d07303243c0ddaf8679ca1a62af33d3322adccf78f2109bc4e17e563f0c2393f404e8f291b9a968872528a7b52bcf03713925eaaacb7d999067d53ba588b2aa4c273cfe9f6cb47cc0b7a934d3c4d33cb801f7a368381dd1f27117a56b6ef8a0098a92297a0c3c006053fc13e540baf7ffab0ee3887ef5aed046fcbd93ee391e2aaaf22e6680cf86779ca6453683e70c821491d86f162cb183e085c8ef301b95e9840fa7384d66d0596acb3a355bd1c4b3399a724d56bd53a1c31886c17c1c95fee726cd6ef171961", "-ca84f1a5e7eb53e364d457f61934757d2b7ef0432ee42254dad2d6778aadaad65aa02dcbbeb9ff2e56c5c44885da8df7cfd7677f464ebe387f00eacce4acfb92b104e771fd3a032d3d4e957fc69fd3de40375df62c10edba2c45e8e9e6a16e7b80f1b581179eb14a541ed25f808c8f599faafcef3c58747535cec849d28a37e743e2e90488e0d6fc6d303443380dabe52fe25ede324f8c4258cd20deb9eb66dcdd073aa1013cc88e3997aee13b0ca245f11f35d7ec54542899a6645a725b57e42fd160eb01971bf17aaf136ab137f59ba1140d23fd6c69ecfe3e7223046a5433396ca16e9fff8eb4da5063367a051a469e0ad4ad22d9172a28d897df1a4bbb1c79737daf2030c8f5ef396fed5b2fbfe658a7a604366940cd4e709d92a6fadd32b3abab8051eab40b347381e08faa85f3d8629786792448022e3c6cc24a2005da21a7e201eded6028e670dd70cb8650602260be341c5bd4714c230887f754268e37de4a8007167e9d8640b96acab759099387cefc41b81e0c2686eb9020fd6e15bdec9992383267ecb74c2a01ea8dc2e30288a9a232fbfef03be08c138d84307284232d4e7d31f17bcd3c43e59a7699a56b0c06663ac62a5857d9d17adc22486e471de7031483bbc69159b124b48e70a9abb20ede3447077c9fdd4190ffc00edcff6b2b6b6b5746622aa133936717cd1bdc98b9091cbae45e5604cb9a152d934e", "536ab38158a702b0f07b3a8e367ae099a135da9b11763c2af0870225443f01cb1ae685c23eab07311eadd20cc2c246d33a87c5c9b2947b3a56cbd701759e38e83f6df947af277cf2cf1b406fcd5f48fe3692970da8f5b47f10dabc648ffe1c4ef87c417d3f9f512f8663558809fc2f2ff7b73367fe44da970c8f7f08bee6850fa15dc1d984bd0f37ddf6b19c4416f886930720e6fcb44583f216b2820b69f444ec4f15d5f9b2c0a9649ffa08eb3f2326455179fe6dcfd437413a0da5b08fc37e91fe20c8360d6ec01a90d3b67e36c5eae97a72f343d9b0fa38128fbe5ccef82275a1dee0dd1828b0080fe4f95425f0969ece0ae384775e957bd804b89c6db733e509ab2987fc9bad3811de2306543a0d2c2e07d3d3b9b40047e43d1c4b4b9f2860599aefb50e543aec8ba98f4b8344091f69db84e4ebb7918055fc5b5da845ef3331d72bb1030a2c0021934c5cbdefb727e8e3d7b002e9d01ce32372189cfc0936d35b6fabf1885695c4c57cd2e445405babec56950978e53794a0a0156a162844c364e82bc396696df6838c1b9383ba5e1752a17c7a5c173a985480f6e05a0400195d719df2a1a8e6a4a6f29615b21e92214d77800da7a37219c8d7419086576b9f0b8df3a77a24815a012932a4088a05127ad5e6f764860da6c9d8baddf19fb36ff84088720cdc3344cf120d64742078b8f0f3169c4b02e29543f9643896cc6cd9b956f846a051241582dd08da17e4699b2c61a02c903519b596a10ca3117568a2d81cfcfbc2e4bd1107a1323612ab027448e69d8a94fa17a32c38234f583d8909488ce6b098502540064e67f750a7f71fd5319006e2eb96ac86039d535cb72954b69112ed0ec060950581a8a96b1759d7e2d2354e4b9bdde9f5da51db66982396804edcab3dff57c416c7a146380dff87122e5eb374418d15cd0a2bdd75c938382d01561bad68ea61b4cb0352e3c107cfa6d03b1ddabde3555bb97229425a88f6398c79c99cb9108bc6c64ffcbb8378b3bd418bb14167b5e1b4e36d7e0bb646222a947f2a857c99d15ddf2fe6788ffd6ec39b7fbaa06b732926d0c9ff947b7ab1d00dcadbc4e536ef4139ff714744151ea06999ff30c1ff23cd32a181152e50fe61902a684d600738cb38fd42f30105586e4e9c92186c633e6d7ade9d8ade467d67b982d8efbb494fa1238a099a96f4961a07a6a0c3b4bbe9baba43e805694515eab22ce64d0030029678087204ddcf1eb74a3297b8527e26e1d24c86f1bfb088226f38d42159c7c4818e7b04874fd275683977f49666c73c402b2c64e29b5e6379e0d5e10ce7bb660ddc6760323aa0a8373910f705ad68eb73ed58f4370b683cbb97c06f4ef66d62631a8749384a42e5f9c8bd5fd809d37c40a86224fea6faceca86e713866c323245156bfd100eca3fb421467adb953f4ab04587a96e8e", .Okay}, + {.Lcm, "c2c46227334bb9b790a622f9c4625b57aab33b45204b77d6ef2195be2acdbbc9ae00dbf0092f1594bd704ce9b018b3fd882bb3d7e9bb323ba766d2fdd10516ddcdd262f4fa5879ac038eda89d752e1fa925cd501d4d1478f7773d07c61ea478e5b2a9c9624b9c126558e66ec4b6a76842fee462cca28d350f71bb3b24a040ddf933bfd1e0cb6df1d19114cf559eb424663e18e988db453d8a82b7c28c596cfa5e4bc8f362e99c1dcb2a33f7b7c26f74673f1867d8f7b013f1419ab636289aea878b9bcd0a8a3ed0fc32cbb25d8cb831332062428e0d395f1b7cb13f97681acaea9ad9716fa465e41f5f4fba61af87265344aa898e073e033284abcf3b5dc3d991ce5fbeca0ac0fe6c4c0a5810faefa9f2bf98a2869d27662800d42b941f271bf4b65fa708d9989bc159d9b2a090d6adc1c797190649438bd7419a29100ac80f364a2d43b9301d0622561477c068859ca69397131b3325ad374a0201db21e6cf844762ba5db27703d061042f0480a07d941c80e73d52d3a731de462537f68972e23554a6a0ef692d4b39f38bbdf650cd50a7db014d35cf879704cc079ced0afe93d55b9d9dce0c3e757a0a6c46d27fa340454f9584fcf9d77adbf5382959e7d48c112f46e333d67329ef9bfce58bce6bad1d5875e40074e9d7f8a413886f477b50592b9098d18d313d5899919efcfe7077c9f4ae7cd7957e0450bb3adbb0316ed", "-9e18909dc72bcef9f5a3afe67fd28ee19ee484183601ed4f4e3bd98810a1da8d8fe4e5401dbf7d5375658038d66bba7fc5944c24a7f60aa4307d5b3fa744dd6e19e68ffe4e56d61887b3c86d5e180ec55e5813bf419846a9dd8aab923d8353240a5135836f146d522ec74f7df2a8721b43153a1260ce5d906ecc9ec08efcd51bac5d909b102d79f1defc651d7d3f6a5f35e0b5051118cfcbaf7f69f36192d8089f3c25b21d51410499cac56a57b009a94d42006381878565f6a0486f88bec2bee309d586b572c9bc97c14ac42cb8875a7db35c2eaf399fd41ceb1495ed98034800ce123936cd348da3e5d200ecbcdd31570b0b48fa485bd22becdbb1c732a752fe3ab623f500ed626ce8de01338f292bf1a7fed46d363a9c0c16b9b93cb913f30d99252701c56b1dedcc58771dfc7af18e33c828c59e203db809c9aeaf04c1e51e0bd6c8028af4512aedde21f1cef4c0f14f0e2b978251240adca9c753eaa8b291f62c90feb279daad52102fa78e1a0164ab82aaaab451ee00e47fd95d5eae95322da84f40f07178fbcb1d1e2f36d8e6681a2fac8708c8c8a518e6d945213b0ebbc861b943fecd70784a3fade1138b6e9f64d955875e1de930827ebf17e84951b6836ee8ab0f957ce31995bd8a6c8cef9d9e4bcccd3dbcd04b86575f25725b53ac97e5124fe7f1053f23e01bbdf9277e203b1b7cd748b572944644bae6831ffe", "7847e503e683c75eeabb3965ef6496022c768edb00006983107bd7c41eb7f201c0f60f55c5f915ad981d34de23e5b40680ee2c16fba96bd78eebae5522166326ff863ca660b17b215ea54dcd8fe0ab881a0be1ec2dfd776243b5ddc9406aa840e32f67e7fcec372078da03642d663915d6fce805bbf5fa5f3ebbe68cee78a46dcbf5ab0de22c9bacffd1c9e76fc03a2abe02288351b28439d696b8556661a1ff6c652170e6d415a8336fd5fe24669fd0dc917424e1f0048a5760046b757ee1a0f2101b441db67b8326d6528f2e9d19f811b3e927ecb1e6f8b10a33e959f8f702f2bc4383ca6c2c14beca57738fc9a7028b120cdafe0f4f25f2c88aa37e248226e396a6fa2938acfd1958cd0f32337e71677b1d7d57fd7ba1a417b25e311ae3b8bef205b9f2a9bba5fe923222cd649eb3d3cdc184e40ca7e547fc80366cf813a89498a09115b7755dbe8c704332bce751f6e9551c902b6b6c4e0d02fc83c5d6013a212b0f59051c3d240209669d03bc620ff2af5833d69d174009d8fb6502fbda608fcdb973312d6207af560f4b211340c09d03995e16a3fc91dd4b8b0edc5b3b68051909132cb5401d439716203885b6fae625993af84687359f1f6252b95f6c99634dd87429add98996cb65cec6496c31cbb6bb9b4d6d1b4cfb719a193735b953f6aa6122044e92ac0c5d016e55b4a340b14a0e3e8c72d407737490d16a97a8d4dd40099545380b4b6bfadfced147d99666f627583d5c9d1be1c7cfa16fe951cda04e506e6df1b15545c5d053beffebf8b1d7ee40c2554120ade698e0777659bf29172fc76457c9892a182036ded32e2a9ecd6600d7d3a0047824975798ca608c8928b77845e9acce170349c743417bfb05beb7fc9c33cb577fd205a889102ba603fff896dd9bdf727ffbbfaf11ba630df11dcc864578a371ff61966ca4d784e63b7ec6555286af02eb02b8b1c8c2e684432806cc4a86d1f57c42105d926d39699830456fc315ed5e3fec59b2d5074895de50e74cd26807961843a06817d055521c9507f15caaa692efa9a8e0860f7d80ea503a174f1ba208ff6199b3822eff4ea70dbc31c4ccece4cc32bea39495275c043f901efc9d93ceb11290bd27b19d733bcd7057e28e405fc75e4f6ed0bf84fd25b04f252386287b719fe29871f64708b1c1bafb5576831434c6dc835b71143be875af00000436420d744492185428d1b6ea8c0b218cf3e3594b9c575e1bdceccd862d564442be7a623d199ddf718b0e811663ecf047eb04961710808a096f7538f462f150895dd646a4625c345a2fbfc7d98318bdfdce0e03106d89a8459b2d4d871a221111f5be535b85e7e44be68ce623cb52cb4f8fd86da8cb3fae1838573c6b70c934df43877201b8252346e6c5e68ac7bb5ff21a4c4afa8e5da7864b03cbc1c9d1ec95d5ef6d6564961e7226", .Okay}, + {.Lcm, "-60ce9e62727f556035b1838d5ebcd5ef36e97ce7c6b3fdabe0ffccfaa948ee813343b5e99c86ce3dbd962be9c597a3f14426497b7edfd91262457c2a184ae434d517e30550fd84274f19d73b7c620ff4bfe5c681cd36094235782d31e712034735eae4b897ad271f905e4d3476a99de04ac8bff89f6028c99f59692be161267282143d6cfffe9f7725e5f291bf32312d74b01485bf045196b7bb3f441714ff90b251a8eac9db4a132ea5070c39cf182200f80ac845be327b41a78779a7bbfa3db4227d6bf965623995adfcffa3ed73cfbb7a7a79ce5002aabb4fb605766de3ec42074145fd9721147fc5096ce4b8c19ab16a57b8ad7a58d483bd109cb15aa88e1d65cf74cee77b959d64523a974b29e7e315c0e8447995e8c4c2043bebd9ab2aef407adfc9e92128d53c888e291d0fa1f0b1476d9ca0db75f556d4a8b05199ee3a234852b4b5f60bf460d0d78d366460f2bb7c8aa7b1782d90998bc76c488c716db576355aab03e83f25cf79a84eb6d3b2b5909dda7a0e3e28fc997a7e8bfe3b5e6c076e8965ad7ec63e243ee8254cfc59d65017e92ea5c6e79374f363e495d90c339ca538bd7147031a51ade27f99fc27241c7dd4b6fc7acafe75eb6b18cb3eeff0b52652a477545f97555a81b028519457d9fc77a89a89a0e4d6777005d58b2a80231e8ec8c7565bed1ae1fb03b1aa78566ec8e7089f0b67481d8cdd45f2e7", "-9751bd68ac929f57bad9a01000ce1e5a8ca02363c64f367df90471f122ce7f8e34e8b72149550b79840bca1e8755595f33a9afa975cc6602c987f60f93cd77097b2523cc599d844a8f5f1e84182ea04f44e30223d25661d4af28f5514f88ecb64631e219994cd1647817809a91312ea4916577fa613f20a122cf11e7e3759e218abd93cb36ec97a7b1eff9750e7192b982622f99a3b69e3ec5d409dafb14db89e8efedc1716e98f8d5759cfb87759be92071f93991a85250d4e1b91ee92f609fce1a97c0d75e3957d6447310c57a5d91b45d64b69891a98cc3b9242ed29050dc1277a4184b91596828ebc0932cad0376d14203121f975fc8187b507c454012ff8b018935c2a3e881036dcba2f9040721461c2993d28028aae885226bbd5e25b884b0325a0c6dc9a5591afd7fee2370390a11efd5c32d52bd76d0716d8291861a6034744f6130ad42559049bc002cd15d317e83ad0063c9cad72c556949697a8bbb5a76d81811d851b98a38a375b7267f6d2c92f501c3f944be1c6550c39d94928bc2cd0eb1f541eee57c05e8708e454acd10e512612a4225ed0a79146d48a72ab9fbdf6c9a3988c8b375a8130ad43b911edd7e3191050780e18aea5ecff4eeb5d9b0ac9a5e3890deff2171abfc4745f4dee6f577d51a2a03823c5628fa7acc26e06aad23fb8a2e68dd6a430290233c6b65fd93d7228d59e387e3f33f4f6c6ab8", "3938c86c4ed0a0ae4331a5c92df0c6671d86e3d757d79d4b6bb02d195f789f8f3c00fdd941a29c4648d875ad16d689c0c9995bdf7f2a415fabd32d1d6f8306e8b50cfe5ec5fb35561461c6d3bd99db87d541a7b53d124dac7f34ed7b0e0416c33d6cfe338ba7aee38ff4e29b9b376e592036386169fd4ca1715c11ae201a540e0c0932f02f81dfb3e39f2e023fe9531133a602a5f6b15f50a64d865e1d81acd98aa38a2076248af8f59fdeff290a900e24118f5fa693495062e7269fd566d208c008f524e3a6ae73bb86362fca2ce2f0ffc0d5bfbe112f913195e8cf75b57e9f8077f11de7a0b8ca7752173e4743b7f38bf7a7279951bcfa170f699440f13346606680cc325b27bd9fd2d7686b0eee7491b7dccdbade3920c117c9544d3babc46ce663c61c8168a31f293121546e46195576b59b6ab7188dd47954d8a45c29d342443a0b114215a4261e474d9951ca07e229871fea17d856c611ddca82f5cb6bd03cbb68e42efd3245f3b735537e432264943cce2cdcf5d612dd5c5195744a72bee37e89e25372b8434b0ac2093881ebf35e72b0bf2c70bb90271eeef7c5b1a39b698ceb23a7d9cc51292ca9b93ea1cae2001d83386a72a949377112b8b3deb643b148cf76de4ccb0173ff3f40df40d179bbcc93cbec180dd6a50335f3f6d151aac6965abddac0cc228a9dac69b611a6d2303044a8871262feb57729185b228906bd2a6502f6279ef8f7eb70b6c36c6677a29df5cf744cb6fc62008bc5c77fa96b230a0078c0f1cc8ea73f150e1217da9ed9bf168e10c19b77669b6aaf543170ee9d37e57cffd3eb02507060daa3b0291118c0ff25c804be52af04e970688f9668d3fa037cc921ecfdd8d4e8e79403d2e9937c14282536acefb58d7740c89d03ffa721b0db9ce2cfb663ae8271af0b5a6572e0d42e9691e056f73ef4e19698e2dc6330c421d5953e1de81b284973594a0d47c1317fd3d97ec5ad1e27baf65c56d673dfaa9d9c66fed64f18756029b949abd1d306a5a3a3299557207efbfa5b38114af83eba2c5bfb81c2399f2531886177f98319a742a3f448d6cdd576c4104aed2eb2b3e42bae626ce6381a8cfe85a7f773e3424681bc96f06288c70129ad22eb746303345aeabf813e91007f044b8c219abdbd744bc0696e2e8dd0e42ede4dc55b76aa4fab575e26da0f292b4573b6224b49a92ce7356d0e82cdeba3b52007f1390e8cab375392e45e63c99363cd57817af80accb7f05727c80a30ca1b2582ac9864f3bf033fd69353b5d257d7b6cf01e8fcc01cbc561400dddfef666cd03ef29b60e77a0833881d7e804d253567f0927e680d09d102fe2648ff32263fd1bffc48bc642ccae7aa0e92ed0be41f3c060988064a6f7090e50bbc74017d858f360eae829828da733e89282fdf456932cced6c7fc696d3a22815648c2ec34e3c08", .Okay}, + {.Lcm, "-5e168a74680dc74b1efde672da6c140ab29a2b2fde3254f7f50986d7d48ce608064429ddeb8fad5ffcfaac261437d077f7694410bc489879640012abe58a55f7cb45daa80e97577eee9fa951c024b29bda2aa88d3e309518f9f25254efcada1f35dd5462501a3c28334c438508d53141f94e7d77ddebf4d5dcd1035465760ec00e633e977123aaa31effe498a65243e8d1667f688fa5cd6480e9b1c34f582b3cd0bb86cdf13790175e5a03bc4b06dfc0b66de1a73b7fdbab1ddd421d39586002d26cf661398837c3bf30a4b9582b62c6ce0928a287e90ea31d37b3ce69c1b47fd6f456ecdbe86c8f17db027067a0e533a3f3283041de8e2a97e7aa07d64b20ea61ed4b91e7619868d08d1816cc2cc26b69f12facfbd7afa453ab76a84203cc855d4a7e4adcccedbca63b117c34a46c9652ccfb806a295155c1e36b5e5c131d089813b0ca5201cd1fea6641d785cee666be5226aa80cd48f5cfa8cfab4f62fffb303ba17271960f6ace8ec3348e9e6a917af1341ac22b633ddaf776d759f98d20fe6c53c6bb5cde8bd725b7b94956392d88098041573ea39f7e0c65c21bc82b000df9b2355aaa5e002e17e56344c45092338af74936ca7c4e6e1f4638f1d9367c3a75b3581eb288d5650dca3c02b4ef280c94150c56b8868f6270224d15c9537490b2ddbaf9b421a03b7e81c13834a0aa498e5b20d2a7e68e94120391bf563853", "f310d94235ca8a2e75819e2e7b8f378c75a2299882b162f9eb18482c493ff0684ee09fdd0eae67cd27e9f830057b7497cf8e7337cfc4434dcd206b4dd709e16f7b80acfd9821aa055a32273e55403fea3233b10ad2b08d35c1f5d77b76d357875d7d4b0899bef6b2c5476ab6584ff14a46f581bd0e8061a3e35adbdf9dace3578483ccb7a7f758bec11cae13ce8eb54b0762035b7614a8ee1821f517a8e208ff82c0775ace336afda6ae4bba5de376b607cc1931b2726cbab2c14a8ff96f9fe1527ba35780e35841eba9f04524585600607bd2342f354b06274af3082e85264f61648d304cf2d76d42f37753ce55377164d3607b4e77c72391eae5083bf751c6cfe4ef831da6791d82e86f9514582abc270a259b84d58a16084757d8c8783617df929dfee7f82ed486673e76e15eedb2fc02b0e9a781f6ea382bbb2b956616a1454c197d06f89296fa4d0e7857d065f5648e46659c6a00282fb0cdf465cbd299933c4fa77ef3a1c6b890b64f49422b96ed648b812f5f388cf820c28ef0d7ceadf5a074073b81ce4059332eb422f04acdf433f5af07dab4d11da605b37eba7017fe120b4539f2d9abb2e08565e31dcc8d126eff2de4ad5adc54be4a423c4241107e01e93c9324b1eed46b0b0642b4c585d6bc19ba5f69fb306e2938d3c2a5b7aaae353fc2cd78251b7074f496392baf0ed552875dc980b3e8825c0cbc8bddd2a3", "595596ae96fd0e7bd7dd872a8809417d1491fcc70d78687ceb92dc4f232b09333a70ceccbf698f916fb23259863fbd6a08d1cde37faa4b06b04b8afcbb2725c12c82a25a328280092ba5da9d8b6563dc9eeab649146e30981943bba4635aa8537c90709b8d5634c27b625ff4c0ec20a1a5ed0677b84ab1e56125c08257d1049aec88bb8da81e958a381514cab915ecd1d24daaa1e4d8c1db648bb655d2c7897e387c5ece6498a649ac175cba8b0697c5171a9b8bfa863ffc693ddaec90cb7c44bad1c5bdc6c9d2ffd8bc25671dcf17a7eee531b7083d5ccd95e4b782334c27784eadf686044d2d2e7a7fa9fb9d640d45d80e6ef3125aaf3ae792f7f060897d4b80892dbd0b14572db958b3212a8463d4765d63e4cf7291f16aa9e53367238f45d525fe4d27eb60e5663c5bb5dbe57aec5371638b0697b12dee36046109ac99052156cdbb19e8d42a832fb11f01e6a8de38e28b99c613e571e21e2c4108c0ce0c3c0120b32d5e50fcecd814ef0b62c8beb4e6c31963129e242d08936a638c87167a819889c2a2a39426fa7552e904d18af97949384e56ea1b080b15b32383139b59b620260bacb93998b9dfb4de829378f5664b0529ab3edec906955a24b350bc270ed4072b6cb1a5bda7b3da5c34d777862825c9ac5c28a93d4546bf91802352180a34ddae21a332f463293730c6d51e5e3c9451718e3b86d10eff1f2ecd3dcda52847412f11a0f0d97767f28f37b039280acdac87a1d306ffc16a7240f1f2db0d9e72fb074c3fd3fa61b971fcc910af7e34ae7ef7d66939b61414a32071aa8917bab5ca134768325f6d6ff9412fe26368dc551c05e2c8901c166919548523bb2756d499f2ecbf8064b7b187bda69e7a072ca9d5dd72645ec9d450d61556c0676187d12e494cf0b81a7023ab6732966b00dd3377fd6b3b4070bdb38060cf2c38f3ea20326eb1a9a9323fb48bdc7700f2eec480176217867144aacd4d3abfdddb3d581d9c97b996b4b8ec8d3cf19a22f9f3973b3c8b75f35a29677bfcca8cf37bc3462ca0c7ec1139daddb8a436c481f478d9fb466f49019a41857abddf8abd7c1b65327c60f3fb1493379a3d2b6b8791d589a9081152c97a70194ddbd1c24b33f8423b11a3a03b1643aba08adde349c8d0a0ec2ed1a7028994ee21d785030fe7a29677f99bf218af930b18b27112148465701d1d866968b0844915d6cf89b112f36e26188ad47bea6107f37f0763bbd14da157a2030cc35b59eb456fa9256c89cc250558b1837a3b51215486a9eab63df27a9b71a9e799e67d0021aff3b80d2a27b42b884b8ec4f10561e755d269280aeaa9fcdae1160e2fb323c5c7ca6b1f1a3e3b0141929050dd87bcc1fa30b9dffbec338c91f6d4a5d37e2437df9d681f24807a7a92cdea4cb235583ccbcd3805f5032f111f3479718b37e513b93ec0f2d9", .Okay}, + {.Lcm, "-afc980d6304664e4ba42193b13535b1ea550d95f31d12bc97ead29768a48b85326191cbb69a8b2659f08b8b61640299c30dd74f6d69d9e5ecc9fabe5b2f7084d75f97865cae6a90f432ccc879fad437b0b3f5983446baee8baa1bf393421fe98676714b7fd7a935628f34e20eadf181a54c37c7a3c308f8a597c303ce1db55d10d6b7434118b38df911617d0dd558aaddfacec5c43a893e2c3af4e685fdc302caaa5f19e819a296bbd4e68eb5ba3502e2e1d0301f267c0f633b6efedff94ac594171a4eb0f6a36d45e6f972796c8f17227eaaf1e273fb414349e1fb3db063e4b23995fdf29c1d424fb6274954c2a9feda57ca2ece9111a53d49fb8966e5a4370617a33d7b692b714cec5f0bc34c93b54811b6d6bceb80e7c70b185f8221a3030c1584e6ba262fcb65cf3d397ab6b308d1ec6f3a01a128eada59e05637a1143b18b7f52c6e51bbfe16c24dc215f64c32f91bfec49986e42bd8527458cb9c705c9ac19acae77d07e96bdc2824a9325dd1f8ed5de604b3d1cc4f8b05e8063f9ab77fcee1705151cff55cb0e6a02b32b0c425ff2112bfa20649eefcd0c0e25295e469b955b4df8ab92d997c3b50301b02391d4ab3d8b04c56d511a1749ea3fc07e510cd177130520ff3317f184f6cd40f4cc30b6eb3c15629cf8326903b97995b4c0e149cc6517dcf8169b54e54cedb5420115a1470dcc6337ab88ebcefa2dd149ee", "-f4f7b57f91ecd1f3778e9d321916bb92625cb8cd152fffc7b2e38a360554dcfe6d45471dd301f59e9e1a819cf792bfeb88ce4ed8888692572545df4b983dea7ce5bd8d3ab2b00da7c0c4254a664b2f0e36756c2d9fa57b862526865973e4421fb4a2f4201453d6122b1943abe185765ec8e7170147fc795392acdc2606a0ca45cc39f977e2e85e16aba8118a654fdcf253721cd21e79d7a89b05704eb5524cd6b8077dc53f4e3f6cf944a06bdf4c62e217820723248e5e141b0d9e2fb170385ea2eb3490816da66ed6b3fea4c98857aef09821a6bf1760b629822cbe961bef71ee0f455470fa388c43709d4c3e5a96658c3bffc19f9b9f8ffcd936d87cf0b42238d417ce8390bc851e212e6f41338aea5c28fe6ca74a6185acf2c08ad07f5bf1e4754b01b7bfd46996935f5ae9eff2c229d7b34c8c1f107000457f61ce82a44cc9c7c43b0504a1ee0b1ebfd9c8ba3ad470180eeacf0f162b7b5e79bbdb3397e08ee7851c95cc2c56faadda87cd2d86eb8c50ce4a272cece4f89e183b6880334d08fdc6fb2517cef59ba1fb8b20fc14f15f1cb19e8e11dce7eac48019dfab1b4619dc19d72e9e0b82e191b67a8e90d39ec6a17966b69450b31a8eee06d86afa7badca2cb3dbc0b2441fe6045f6de6d25d67b5313d6e6596f55c4cfa951f0bfdce411f71a28314d4f39b0b08f2e42923628da52046643b5bf05a0dddb6a1f74a25", "1807bc681321f7c48cd4cd3160eb7a1aac7d7d678654d761c5a993e6a10f9969c20050a179175b6d1b5f235fe67d1d45885bcdab1276c5a9f370be513f4989cdab9ec8018be96f1a2ed949c4f34044bca4ac9eb78b2fa5896e156a868f148eccfa92a487c9b223e6f9de733edf90da270398894eb8aa146017a5918edc7979cd07aacbae262d87363d438f8d92ad5bf444ea2915ef7200df6933b37e43cc309bf5e225c30e09a63ff7ad5f8d37e9e6a195ffee1da72e3eb16b638623a845dcbbb45f69176f75297862987f59f1d3fe49708815f23f2f5707a0bd0e8802afafc5dda211d0aa099f2c42ac610cf7390f287b4acac3a493e7445fa8dc6b3d85182427efa9c013fd44547982363663e5f81907b48ae8ad96068c26ed6f9729ac36981bcc4615f39d22079c167e5e5889f76eee48c53b43365f4b826c0aa4e1654f4b4f80cdd6560ab84c0566a032d04b25a7bc60428220ca3a5edad637b8725b2290fa4e221a101f6714eb813fc297677a7daf3ba25adef34f01499d44721689f8155a138533759d1a367c53b64d231835d014dd4beec761c9fe3a7789560e731d09e99fed9e7cd46b0b38c9660aee101565663159950bf2ba51dbd8736296e53ac819a544811856485910b2f76ae8e6e0c12360607bbd5f9a8c8802f77ddc9b9a5a0f349e1458a51c3ba928594846a32f6cc1701cd668fa94c83b5967c97d8c1e82975872ee72d3d927ee7868bc3f924475e91958420b654ae482895ecad6bb99660a7e4a3cd0132bdcc3ea73e98699cb12cb127627d3903660b9153f47775e25c5697105dcb20efb6267be49189e3d60036939ad5998ca40b3000172b5c03e31d0f143c1d77510247ec3a389d2fd248e68374576c037ee6ee1ce5c9566ecd6f0b566192bd375bba85c5aa0294a11ec52f3dd714041b92e13805c45fbb7f16bcd917cee4bf830159cba3bf418a689473265976668db6c31d688e2b946acb9da089da19e8b5abeb1deb4b50cdbee9b9915b15fc2bd1ac87c9935fb8eacbf608c1c7d14740a1cd571c4e54b8c0ba69893a992dcfee39a7c074e2af33e4c7ce4dd71c711599da0464d603a830a905961c7976637e918dc528a75f6f95f4847f2be2917e0564dda745cc83e73709b6f386d5d200265dc613e845ab8fc795a7bdd28e8acd8b013db0625286993ad3e972ca6b7e90b26e75c8dd8c9dd8cf8df2f395c8f01b7f931323cf06b3fddce0a2453834b468b99740899ed2f43c516ab751258563cb263f8aae471cbf48ce09cecc4955e2374bdf7e3176bdb59fe1f4ec479857859b111701370b1dce13f188d237b19ba361892d8be118e7e67a7b83a07308a9b66953c0ca5a4977490b3b8a695afbc339d326821f0ff30b95be77a9d4f265d963f999408691b42f8bff0e04b0fb5ed06babae33b63cac9ff2c861d954a4de4a3ea", .Okay}, + {.Is_Square, "6995ed1bb0d71b54a31d6e50c9d19bb96f1ff7566cb125935410392b76efade2bc6e7d6f76e91b8f1b9ed6a6d1c4edf808a071092265d610add78a54e9d9f02775655b28b94d8fa478ed0257939d0a30c4a8e2eec340cec0980aeb96c1214de88991d521a000db9e0fc6b6fe40fa9f4203e4ee79bdfb1faca769c7f36efc5b95eb301c7a1a7cef1b03b7022d7b768e78e0fe69b7d28a41d091bc9049e8ac24ccc950850dc58ce8e9a3fb42ed14d7064832c486c17db4740be40db5adaf540d12df53e1b310017501c59aed98257755eb5f8fc1ed4f56c66405b9a485ed96433f27ca12014c789083a2e815cc01c6a3085cc034340718b64fcd0d583a4ed4f1af5d02d60efe208bd7f42030662c52765a3414f1b0f5943b568f6df0416a4babca4bd714b8213bac0b2fc00c68425b9dd705873e1a6febfe206ce8dc44a48b725a7b435651f51a33072cad0989b2f04255a1125d355fff0479ef0bf76876ba16bcbcb55b33bbccdee56967f439b5ac8b8333898b3964778a6daf457507c3e29ecc2323df74363834026d888aa9d64fd8ec5f2f797cf113052319b72e5c5bbd3dc8204ba5a28fbc5a1ba1b762bd814056481d673ac8d328527c7da97a888883fcc09c29d28c30a6af5c70fb8b0beb9eacda339628e75b9f36072abd4aa9b8359fdfaf3c3db5cc83cafcc771cc90d81921103ab21a25d9f692a88f0dddefa93e803c", "0", "0", .Okay}, + {.Is_Square, "9ab9b2ac406cd42c84dd884cb34ad2de1e6236ae330aaff71ec7f22562272e43b827324c2f07b73e03b0aaf8a2c7fb634fa7ab289db2775feb8fe07a22eb665576244c517d720b73fde8429593be1ce4e7e2896f900f67527ed30f85a29ee00fae30d7a4d9f49a4da44d56a081ffcdc7543ee3d0c2d6a33f2251b013a852552b90147ac56d98994ca12ba97fa24ea442f3cc745aff1c5bdf5e25c4274a147382ac95f29e83a97ec3d358d037bc24b68a90ac4f5c95ad1f98082f069c047a9dc28db340af8036a5596f7cb60b89c46a48b933d1752f5c8dceba0b559ad2fefe55f943b9c5dcedc371a03be1d108457627045ab093d00ff8d854ba1cfaa8b89250b6ecff235af0af9495c37c9ce038aaf137fb6ad2b4085e52126b9e0e6cc232543e3d950e64c15f44776d3bd1b6cfad89050a11560b8561afb62cfdf9a07ab4fd412d5f6c3cf2d59090a4e6f795c838ae1b4f845baf94cf3d651932fc1e8ae99c8510f0a93ec9c5256fd2eb9e89a1e8bcf57c64cae0b913bce30e8a92eb7ccf8f3a7be723e3476d35cdaf18232897bbb72fafd5768ad7bcb84c6f08ff57722d13e432642bc3985c003849e456b7a2305a265b9c0f8e21f0f7e47eb89b5c0461fe245bc8521b90ee4e093d7c2ac4606cd30ece45a3142d8c25698606e018dbbf9a204faf2ba52376ec00931d4d63e99fe4bb70ff204dcfdaa5231731e518df026c", "0", "0", .Okay}, + {.Is_Square, "c40357b9d9771ed8c3acc0cf1895f02dd04b9b6d5134bc71a6fb55f5c8f80493c22e6ac340cb5a67527f1017d97f27b7247639b6f11a455ad4e4509601feafc97ef3a178288902722f878a0b80092641e46c67d11e43ec95e2b162cebcec78d454eca645f458c7503c78dd6b807a9c2d588884f18dac1976d15af06cf1254e67990ee07bb7aac09254c2e78c2323d41ea334c4c45b3fc557ea821e980df9eef67130984a5506046fa984f67b565c9fbdf6bf4eeb47d9567697f903cde7f97aee5c198d70a32bcac30edbae53fa2e1c0b8e31f74867302026767efa577c20f1fd559dcaa174ea4a8b7ef398afa473af84866ff83859edf59c7c63271d1e5493012feb3e4b70ef15e0e40b01b73bfc8e1f656c5eb8e0e084afa3746bdc197acf89c3045b0c5a53230ef90d9dd6bd909f650ec5e0533e0505a0a62ff9a79e5dd364dbcf560f8ecc6741b37dfd1cdab369065c038cd26af9734302bac0f2c0759db8e6ba266045039665e466ad9adc818f9ae897d050e67e29bfe1422d882546c234a0ca2014ed2d7324d175f8de439e434ed7371911a1e35c387d6f5a13082d5dec26fc509b4d7469a2ed65691a9c0d5f5a3cf795782d35380a4741f00c6e1e43022d387638c6e77345c1dd3d821b3589fbd999b2024aa140528d22012a7d03f92e7b805e04b449af72e74d8f96b449a06770ae021669ea708c4f88253a3029bc20", "0", "0", .Okay}, + {.Is_Square, "504984f491a824adcf8b5c9400382390d861497415d780d7ecc679971b3b4ae166db99aee324330ce5e7728521c2698070d085693d59c59e43ae1348c4e337b1da34c5a44840a98bced4c779fd8f644383550d6c5cc179e8c2a95a47ae5955afb2604136c76fbfad78e72e7c38d18f00314ec77861fa9581daca0800701a44392e5443f7e7b6909b2046d3a31efdd67d9329a2fb04a8404f77562f39675f0e6e9c1c29dd6eb36a73d2d54c27d117fe710f5f1c3c173c4d4ef0c5b2fed442a0e6535649bdbc63b386e411bcd2a4eac4b3fec8750cf516dc43b0decb97e8271d678d99b04d67fb840828551c767affeda626c5864fa888a8ff1e1f2168fb228aab2e1b4dad9d573b6218ce0ad8e3cff04a4425b3b96b3f51922e902c13e639fffc626ee51dcd34b06d3539aaf6846aa87df44429cdae507a467726b8217e5dd6d472c2ad2b17258b1941df5cdcdb51424dd257956fdacb37a130171a76c6f4aa4429b0b9ed89076fde475c833bb187282fc33da48fe8b73a85db6ae62a3c9746e211b7342486989a951c69e580231cba43df72cccd908c14101d3d521e723d05f93e3a3baa768f792ad61f71eaba8e21098df5a4502466560e4657e9924fc9ce2d387602c6005c8cfdbf3bd26d4e7ff7be1d8e9eadbc5169af4e06b511888301a877b47edd4b30580fc9055fe4be837c30e8c1fe42ba85dc358a82faf3ebaaa28d", "0", "0", .Okay}, + {.Is_Square, "708723f3a41f9cdffb746649e028e8dca23eac61003e412d9c8333385651f080feb201337d0b60529635b5b53462c19cf51b7c132a86fb88431443a3dad2699a88494e7252cef59a206331f9f896eae3f0520225793a4414d17dbdd99a344e19e5b3bec8b182e6e03f554863dbe03a143c164d4c045fb8e01394b659fc987d09df35c1be0fafef725aec44aa62bf85bc27fff88508be430bf17eb748f2d8659c261c33c581e632f0270b1b8959c91d0eab1345d52d1f15fceba6dfbac549ce381d0e69b782d2e8344e851b7f92d4ddeea9807c8815d824ac4154f45bd696d79401a02f14fe36bc5db5199a2253c74015437cf31ce897bcd5fc2f7910a11d88596e4c71e37b6475c48f269b2506f13baa7c44e5ebead01b954096fb50a5e978d4ececf7562d53cdc78e063470a9f83e07f63f4ab0d6082fd416f3c810fd45a4ccbfc019c58abe7e310689f633c13ebb831403a90d72fff2152f7b0d909857465d651f9231e4c28256973d796237c3f50df0312ca6c7da5180ab589bc824ac148fbfb06e12004720d94a6d626e8b1061adf11f11d0f5c74d6eb08785ecdbd5328c93abf12d9cf52611cb29cfb5dc641216a458f946bb680f040574f363f11ef8a1c814a6662ab80b3ef20cc56ca393ed283255d0a148c23c43e19e5a8157b5784095d956ddc0dd136e8ef5af52ba080fde2542a853543e7858a9c99702ef0967e5", "0", "0", .Okay}, + {.Is_Square, "223dc4d22bf7ef11144bcd40fa571a9dd8e5ffc4be59d19a935b1bff6257752022b3fd64a21473bdf59130ee0224364a82c9ef631bef4384b673f6d2a3f5f2dff60c042add6c9a182c875363e9b2d74b4c741db0ec60c4af5f40927ab3acca91fb81bd311d1562f7fd1373ad3409dcc06e3500273bbd2f7140b9e6206df9f51eee7db51e76d16a70d93ebcc6d7a372b24e3aef44f7659df3c9ed3cca63340fb71997722931b3a404ea873acc880587abdd3e908c1298e251f1df0c5d7babae645c25371adbaa0ad8a88f233d0e4ee6f935d5d4da918a89300517bf6ec9a6a0b01f1cbe1e21b4c3365c2c9aa0c241b99349ffeb6732abc80deaacb6e2e0a0c7c22dec3ee7b6eed4a29fde280d461c089032bc2affa645b98ca5c82d69fb7bc04db4f4b2b88ac4def985460923337b8aa90aebd75526ca9b7f63a2b41cfa12c23cf4a3d21337edeaee4ae16fb2d4bdeb7654b0e14e4ccf18b38fdbd5a308a83d0adebd806b0d47879e3b94b96a98612d6911d9b1837c12e850b487b69ed4e310f567e7edae68a7a5b5ae815e7585edb9937ab04bd7b0057e4e2e4e0f3eb200ef0c44dfc5f059efb89364afa4ceaba8ef3e09d9d4570b1efe9ad5add37ad847cad98a067fc5cb450676138797ba72144b76ccbb78e6d984b746d3c5cc3f3df3fd9914899d68df3d76fe4c92cc1f3e95b78186c3d2c59ff06c495d4fb35a8cc94a82", "0", "0", .Okay}, + {.Is_Square, "dbce22195a26d6f9e89e8d638e614e87f1992cb77fa37ba3d1f7fca05b813a6e38e8dc6fd0b0311158ec351c9358b8c399a11898f092187a9077ff4a63b654f817cc1bd2b4e496616c193f91698b9d1dbddae492946edb6526ae03b108703922e952f49223a2cbf6c6bb5165be1a4d48891871b2fa70c59849a36f48d675814dffe65b08068714a6d347e01b3cea607feeea27fd97b89b539d8fd9fdcdd8d2b19595f8a644e7d1db59bf5d09f28516ac304d9d7c3794038ea482fdcac52c045c380b04291b055a07b7f70bf0dbce1c0f95f90567445a67f91eb303354ca3c93a60c2b2b70881f61c2946e7a1281fb2e6690db81417d4dcc2d77168ba0ee32006b52309511b6667c90e4e630bcf61071bcaa0535cff1b9e7daa0168445d55e208302d9867cd4eaa499e7565d82d7e5cdd1c1315e726093dafc92f2a3c69c25003db5008bcd5ecdf87cb93173dc1625b269130ee956dfbd692e5af503fd1dfed3fc1061990300aaf53cbaca8247809dc3c9970a68cc5ae9f7cf4d057304d482aa7310d61f4fad4e64a74b515cda67845da6f372f65fd9cdcc8a4e3b249e95cfc51694665f82b71c884f1de5897eda31f98e344f194c41b0096376d9847551dc2e29712a9c1caed477db10ea2cf14b937b7096df8ce7e2ce715cad561881f36ff2c2085144b3226bd9c58301078dc3afff54701d8d62ddfc33c9dc90b3c4a1e30f0", "0", "0", .Okay}, + {.Is_Square, "610f5b09129681ec72476c333790f0df143a385e510fe509ef802ab4323680d87eadefff4b9eff7eaceea7512f582c2366952204c9d09226c6b464f419424d755b7b0837f89f618c30346c3d7d648a5482d47285d0defc27ecc8648668285c916e8a66f2707d944ac34b83d11cda51e2ecbc13126b0d6fa6ce61be04f3089c81953f8ef71a77a8a3824144b26325982894b648d10b37e890734027cc21dd836ba8a3a28c22d1f1d13774f55e05224eef1351399d7a7cc31d08081573bd2f18a939ce13d61d639dd38e32a9bd3a7c2f465e60e23f2c2bb7f25f2920c2c1784cb5195188b5c293c2cd316b3ade094c307c8657ff91bc95aed037fcff1c5804bcc9381cdb4f88452d874faad66de6b2e9a4d811b66d3c1688e4ba4e3a4f1b36650e977351bec6a2e3fc5aeb4a8caa6fda013500171710e8cb204700309e3541dfd5a7df759f71862da3660ded6381e29c188959fd1c7f2d7935c2cc4f4b2615a8f39356f34af5e036bfe2b209e0e0e5c13b0226ae98c88efd1a7397af8f61d880908e5fbbc0091abd33f006fec3bf245d02e5b5e335efc661134eb5ab8ab6a9e2b0f03999e6e993b08eacf5afc54d9c753d23e78098d80102642dd30672326414584a32abf3dc529c50113c38541ee951b8f8bd868ed34c9c09acb6c23ca07ac0b4fa5f355a4b53db696190fa21a1fd9b87b5710c5688af790448f9cad8a938b629", "0", "0", .Okay}, + {.Is_Square, "19d99c4975973a1326d031f9b7f52a45d959b8b1922c71ad0a3041547b81514477f6408ee98fe5e8ad47a9b90398ae6ab54959592a0fa4b1d670ddd92f0a24581e86271bec2f4f68f0c58df6ca8b3891861032a2bd86ba5dc49290bce772a3a2115106c1ac3a439c7d02dbd25a644c1f0538f1af2ce76b8926a6f33e33e3c86bcd40625d507ec01d249468105f689c38bc4cef851916990a77cdc7789fb674c2a4d4dfa80dff00afd53b4586469a33e54ecfc22b9f1f6c824e97d2679a63b02085a00cdbd4b963ffdd84f58816fbcf3beb81d61b99d9bd04964739d9b8f57440593439769068064a0d34f6ac55d803e714fb876082a8667e73efec6c2a843b1e1d7b3ef2de83e5a31d66ed26b336500d2a0d4273e5c26e88701e3396e2d2aea654cc1792823a7e85f017ba59737192120c498862503c50f469ac8f195ffee4974483b9f7e836bf9a08336ef9d2008c9999c30734b4e3317f20c5c7e5df435b62fc1d3fdf2eda659477caf58257d368e8522ca55797707169a2dc70227b3adb64ae4d8dd946c4f1ebbaa66179a8625905eadcb25cb2b1d917ffb22c6b0891b8dc45506b8f58a6791b390d340404eb5cb50d54d3aa83bdca45fea76ebaede11a7a375889918bdd0b9e997a132bcda3bff2d4f3deb724f26c640c713d0b11b1fd002bae51a51b07a6b0480afc6cd6309d54990c06b98527689e2c0dc0a27525bc21", "0", "0", .Okay}, + {.Is_Square, "4348165491cde1126f35517227d7d65b65df3114c76d730965df89109238161e1d2360c079abdd3f1c4012fc0a24777c2fa853bc67d5b2dfb49e5e9bf29b2f4f2b25ca1d66783fb788700861b0406ce37997aca70fc0f1370119d6337e877d9178106c18eaa0471691fd7227ea27cdf9681eaa4207af7c5bee588ac3965dd70c166932ca7e49a6cfead7b7395a062c858c46205bdd6649f2341abba4ae69d88ab1da97cc2b8fd97823cedb6d91a7ef0134a1c8968a8b4f0dfa01c36316d89f760c52e4e8c4bea16718c63f5fab43b46f291596a988ba71f5dead95ef3ad699efecb676c4c9bde9db52b85f91614fb6ed59c68e7eccd0eb5eeaab21b0baa3d5c36bbca364fd286726cb6c0e994614a99c36f1a7889d516ca4451ecf85a589fa6f24659dd99231b5cad53c09bb8abc7a94217aff363f4a882fc45a2661ccac4c6fe1198252c1908d841078995081815847d5adfdf16b146bf47933dc9902b69e3bd7da401c0c5e95279b18a305f6f57b01721db41264b5d8b3806b9bc5eb61f46e7ccda9d96ab3eca21d0190b2e2dadfea61fc7f2f8550c3a5acf752c5a2cb2abc4c6b1e6846591d1a93a05dabbaa80d52da7dd22fe9bbed22f158a319f47688e5fd2ef4e38a7391f34d4df303fd39b031a7f2d6378adeea610bf958b94f9600df4da945f2e7393f68cd2c502aa281ad2b0d27f1139e54f5acedfb87515cf93ca6", "0", "0", .Okay}, + {.Is_Square, "ad9d114e2514d6e8cba7271a21036a7d591c7aa401b172fac87d2eb61a60583a1d27d31722eb854c863bef91a40452ae892e5ae76a793ee9cebef9f632c91841a57ab728135d53723bb2263461445aa918c90d27191888ec97a74223a0fe256b4f98154eef18aad58ff2c7cce25ff1b22e47dc17cb602d6019fa8ae8bcc27cfbfb3770bbeb51fa21d9b25b70e9cd352d215ad6916601fcdb70b0cc851dfdcaf43aac1f448e11cb903e9408c4c82430c87d73274f4e61afd8b47d4be2b4fa1390b7a2009997a555f956fd8a74e0641a13bdc824a2cb5b989bb7430eec6c58a3de8d37c2fbabda628515a9e9f519b655216612bb0505bb738692212db4466a6881268cdac930f51af3abd6f976da9d5df425de5955dd76e04086182c16c8fa01917d1365c645ecec05a3d46cd3410595a0c06cfd7f1cdd05f88ec3f49d0eb24a5776cb678dfaa2bb9c00d892ad86c0ec542812eee77ad46a73e51a28d856cbeaa00cfd60af4f8d6680c51b42d6019bd89a2a1ea0a1c625da584eac9404857724a5e9e2b8a9d6db94e1617fac0255c447d3c8ef1fe3f56114bec39f305f8128fe05ef041573c03a8debbb66cdb2c7a8a9f2e64f3692c8fbaa1b7e5cb242e5a971bb8d9583c6dcded5d3d0950612ad6a0a7e530d48a7e26bf46b7dd7714af0a1e3cd9cfc18ee1118713e932b6517d637328a2dfafb83c5566b398ad6c46fa358744d", "0", "0", .Okay}, + {.Is_Square, "7ba47b8b8b1faa3a53ab7d66de4226685534b0bcadd845d2c209f90bcd4d26d995968abb848644abea6452aa34ad804fd17d17da9f270c4fd98b89862e697f5ebee519fe95d01cfbb2768f93e3f8761141b3c81fa6600605c64b5aec0d1802acd89168f0189015fd049e82bb685a816b6a31527790a115c29d025517e3e32b703acdaaa39933859b92441ab8b0ff4378b270b4c88805cb406f0c9ef171ec6ed7035a19f6989c34117cc40c314885eab28a8c61b184bab8c6ef5ec2df5f8e3ef2c31ca20a765b23adcb215fdcb3388e8087d0128988ab122ce72fea81df0cb91663efe5e2128bf8825fc0f715f0c49f79b25f6d96b0753c32ae15fc045275b6d7b5447775ea31ef2158c86ede3561acbd5c3ce764d64b8f197915a876ded259fb353361b341833c3263a5139a79ea0466f05d2a647e41a386ec511989458c90163e0308bd088aeba76a88e3a81aeea8293357c444a05c63a6a12e7ffbb13df5d0d314beb321cea372eb91138adbc6dee12dcc07389f1ae3e36a345ac17b706f90768d3ced62c19f8de5a79a79f2742747328095bec6df571e273eee6390f92b57773f77a184150d12d4d22211a9a5fc688fd1c267caae0f944d5e4af5a9b10e4cb95805ad6c54875bdcbc840c87a641449b854f6dcf29189b5962502091592bd67ca792c7e86e0ac8a709ba91868b63cfb2f0146487670b935653208e77b5c96d", "0", "0", .Okay}, + {.Is_Square, "7fde8b0117bf57f97b22325641077a629ad6a033a912b26584a9b70749e85d919482418182ab4d35347c8cc5586855b900a14e24a8713c07a17fff2e4606c6a054abdf394f73b9dd2c71f59256cd7cf053afaa200f11e4230420c30d935837ac28806dac2e7fd743231cca6936f86d7b190040da6c40f37071cc6791c0ffab1ed8077eab4566b7b8d9c9cf914c168fd3b56081ec3b91bea8c78320eb481c422e38a09428c2e15192f34cb9dde23c4bdea8dbe8d07380dd141c66680f20a4c101783b50706adac135e83098ec5d19685d1fd89900570999fe070b62e3beef36bb270ad4c109cec92f822f397e9f0861f217e74a020df259bc1548948bcecfb1542c7d51123904b5cb6270577e4e69497ae0965f373ba867348604c293347e201cbee8de14733ee94c4e4dbb54388f153050c73a471cb4fe523c9e930bc87dcb19ca4d0cfe1a944d1807335c05f4291fe5674d79bb030eb0eb95b4a9413634599abdb44df2cc5d8b8f0d3859b05241841902e20956fabc924f00d093dca1f1a41768427f94928af8005c8c2c088df4b1c6b56221f40648d0af70245ad78d7547d991ea542629828d960fc667e383c6632fd208254063e54a79ea8638116c6a5f7660a445dd47d24575f697275fbe2e8b3bfbee7c9b1891e66461beb42e76ed99a9f97361ed9c0043048a8062810a300bd6e4f16f1c73bdf666c940620a24b39dc5", "0", "0", .Okay}, + {.Is_Square, "75b478c8970a180690e199091a3a30d91da347a3d1ec368a1e788c79b613a0b244390966e79c403a5798271e5a3e28e6bcbca22df6f9e323f0fee6dc1bf93f098aae1c2a5f42907e59cb9a089228a9d6ad3da98d6f2b923471faae69b9d933a7e1f79459c95e2fdd7df5279e423ae3f5c883d64eaefabf67757149d894f60d772631cf5d124e5f66a99296e94af76891d1ef4c0d91dd6d3b234b3223b6b5e83640fad9a56e72d9f3699a9a5743a9160fe87277ef65c1ee2673b59809a8eae396be45946e0686e3510f146d995450e7c1fe484880fb60250964dc46848c3130d058786a9c4671f215b007a8366490fd25f41269e112640472ccefe3180c42cc37d90f845561eb75c4123b3af2437cde62e83ed931a6298c4c85c891253aaffd536d83ec2431aaa17533c10b9887e950b522d13125bd2654c1662e70a1fd5a4dfd82740b88faf2bce9136ebf14c452d3b6bce54dd27baa84a5bf83413a1ccb3dea2534bcff6fbb4d28fd95455d2d677ff8cd47bc2c50aefaa2ca7db51a7522f2aa80d932bd035df20e0047d6c4df88ab8991992f7a3af802cf473e88cf4abcc1832ccc8d473b1269e2e73708a48575977308cba4bf6f49904577bc36e316c7e66fc9903e6d4d8bfb473601fd3deaa762edc67e7af942f49311546e11a02aba6f91159a3dc7315317fb47e317fd1860501bec55151eb3cbfabbf61b07cf0108f54a", "0", "0", .Okay}, + {.Is_Square, "7fabc9df676b8fe3ad4af0fb19398f83c2a7c0aa96c03e36e6fe1339ff575dd52a9b1317706a45e49dfed73c100f4dcf043a20f9e2d19ce4c6d9f37df8f0bda8f99cf17c26dca21c0cb2495dcd5527b2594fcc14199e999988a487e0787a9e421a1bebea6d2db6ba922e2d9d8e9c71e988bc8aaa29e729b128793a3094d4e343366ba1fd2de137a938b7da0c57fc4890c66398f5f1fa1fea6113dbe3a8c3ec609c6339f570b944adfa64ed431deec0c08a4291118f429a90fe5a11af47ae3f8ed311a8caf846ec03b09854737c575845c4a0220a9204505fa3ed3822cf4ca16e2aedf17cb001aa3ad84ffcc74d491d1a8896530d8d1ef9cdd3ffd8bb482d3bef301277f5862b962158883b5f9a33da05fd20589e3165b02c9b32b87f91ddf804e9853f0905b0f3031b49484e1c737f1146f31ec120f7509535db325a13b9ce228e765217108bfcdbf57920db4077f4e1d8543cfe347caba6ec1565aa8f504b9facd24974bb7ebe89f32fbc6a2929e5cb89ba164e336343d41579a03e5c18edf410c306bfe4c26d2be4a3d248570a88e09dd7d25fc957ab2800a61867797bd1ac59686fe837b20e843c241700bca8e3920efa3691280dbe7baf8cda6c969e266404fef010772f04f242d2389f21a48c38dde01d66a2305e9b8bd3f7c32671981e27200e14fa53cb5c2542dfc0ca771339248b23f33e8c4f63c3a12a24ec5178f1", "0", "0", .Okay}, + {.Is_Square, "d3171056e1278413a68295efa8caaae28747444658eaa5176f985409b74112a5681bf6123cd216a466b2f9dd6f232717450f0847ffff71704412a5660c753e04e40ad41a5df8045e4fb94d3c758fac6b958586970c4a026fc98be95a7af993653a9eed9fc60609fde78cf136acc86fac6983e7eade6c3814d5756c79fba84cd712db45ed35e4cdeba1f99206247b3fdd9fe0316f6b3f6feed7599e301ba6fcdbdd54e55f8d9ba18129eb83203857495ca83e422b4d0ca7d0337a6eda36af9b6a862d3a900cb613708cdb5c6bad5f14a5b9d2fabb3c0eb19420ffba206737f38d640048219892f4d62e437cb0c400d9a9552a5cbaa0a3c5f9447f6c67cd9720142788452dea88a08ae240fd46b9ea131c55ea7176441bd8bafe9ecb18f00c047dfe0c6e9b71bbcd943f8caa89a059f79f549f3e935ce18c2ad29cb485059ebc32e689911df6a0228516cd60503fdac32d2c21f307e42b47313efd94f6760564c4c4c26ca8b15f04152218cc276d8a1a8df8f27fdd2be71a9145b9fac2602febd18e40d9ac997b3af6cb2516a73eb729b8578aefb7f3f2701f35b1bfc6b53456c6a3980040fd7b5e8eb68d6840df29e2fc740e93c4e028783707f1c886cd8030c55217706a825026f7249bf6afbb06eecb5c4d4294d502e1b4f4d5a675459bdb438e38d6f368dc926b4698649bcd8b0add0ca9d72c8165916a0ef04569983419b1", "0", "0", .Okay}, + {.Is_Square, "ee533d46991e1963908b14d37224152a6807b06cce18a383efa72c9bbce365d979ebbfa10c0bb76477e2acd62428eff58ad33c840a09873ffca2840d7e5f222b8d885eaa082c3a0ee6c5e0bb84958bf998c159ac98ef674543e16abcd822a44ea844498b60d3872daec18484f6d877ce3a3b85db9f5c1bd2376b3cb80baa755754df649eabb32d9dbee5781f63bbca2861c69f5752e1a769fd80c8eb0ad12a7220e1293f0300afa1b9e565435d5726b216dae20d202ce6fa04a1a7d2ed9a0cc2216520db1d7321c3031c30f4d44d376dbf599f9638a7d5532231a0dc577b5b579d322f3006ccae8d3622976902139045e8133ea17f7f42fadea1d3e3383c4afdfa4f8485b76f47f3798cdb3eb6640d04266ee1dfbe1414bcbde2193ab0d31e698c78a57b79f7f99132d4ea03e81df23e67cdb01dc6c5be18375a159de2004c7405e4579296a0930af0cec9c4e3484b89a3f84eda9b60c6eefce14f4a6165adfba179cdca011ad369ba8fc5e296c6c6ecce7fc14f09e7b275a033d9b1d6815dea469cc4151702e157d5485b13a2f4d71c5c7d37fa4758db26dbc9204527014cbbc75c8843efedb67f3dcad3579f5790fafac569bc6e5af3ffbf8f34ae92cf69adb3126e04af185113165c6aafdc4e76e07b6f42d77c4f0b39a7cf809726944a15d5ccdb38e5e1d85406244cead4499d0cfb84ebc9dd86709febd61ab93842757", "0", "0", .Okay}, + {.Is_Square, "a353601c53a15e9bf27d14bf0d41f768a7f54d57b187b67480fcadd56c804b2f7962e113109a7cab5423931e34578d665b7aec978112a240d08369603824856954e28ae6bcd76291503c8f6bbd2b353d8250fd5de303fb27f9d6d9718724e97a0f35b20642beba562b902be2ddbfefa3fbc9b60f7014356ca6d5b4b6e0d57ffecda0431cbb18c1cc316ed9e2d4ca17a427d2f7782fb43fbb3b9a5ac9574469f5b33ba894b11277253e21c222512950f9d3574cc6e0fe35eb5209fd9754becac950ea9d4607f717cf335bf7681e65e2b6958b8261a59bfadea75daa26091360c5b8b44dc25f0fa803d7f858a05419a7f07f25f96ba1459893efc5eedbb35d9dd54cfd4c07fd147e54ab818ee7fa752d17ccbac12d2675ea64d972fb2b912de8a4f93950c8c6ea2e868aaa5e9c29eaab6c1e0a7e52bdbff887e041a072872bb4416a5a1492915ac4ddfa9faeadbb989f62b2144973801938d5301b5d637f65a94e9d0e84f5183170c2cd5419f6113ca29311e1eb2824071df567171bcc47a12ed55adf68632082a29cc8d6d8a1b55229b20a0c4a18546d4a034c092d96ffcbb1fb49a44fa35eba7d3c1c538ea6998eee0ddb4d3761e2327fd0811f264fcfaec6b78c33c7f35d609f3200e763fc069a4e04d375255e4af333d817218306dfbffcfbc8454624ad61573031ca9c743665416dc53c70d835e2dad65a888a7b1e2ea472", "0", "0", .Okay}, + {.Is_Square, "60a7b3d703580504ad79cc27fa7a95deb53db6d21fed140310937395c1eb1475e31f727d28a0f9a6065ccc2bc673264f0fcc0acf5f376da320086d5e73e17ce80cd80bb44bf834dd853eab4521a8fd84ab0f07b9c2859d52ae7364d98d9ad109ccc119829089ecaa93aed18b80a25843de46d806c6d0f0ff63844708c8769056902f841c270210a38fb2ca5069ae1ccda9266f5036c548430c32fcb79b2767c7293b298610fc6b5bda6b22dfce05fb2fc228f75d51cd1a5682affed4cb60fa224c3b69b5017e8ab573dcd66562d44f191a551852aa9cfc63913e69f09e0d44573686fc575f71901c2b58ed9bbc323dcb89284fd4106809cf2dc96b45fdd3f1f652bec0fda396172849a3beac4ee3d998b13d8c9c4823936a40e11507adb1a238712d735c5aed6f12a3331f3bb21ace43a129083a02e7e9160540c733b57f70a78b6dfc8e093e8c9da4de4efd4fa33e4d68ee4529d016ccafe403fd29784618a63a9f833dc9f29c7090024882866c73e12f4a561a31ecaae5784ff2448c6b9f8f7ab3ba5dd2647a425de5a6f803b864ec1d16642ad2f1de7e263e267efd6403b7068e5ab8f4938da18f8fde4aed8e941cac92258f6012b792af80c3e870689a18e28a1bd5ae9f20780c2d92ddaec25a6ff74e2a3d88682b9439441a72a555a9ffd3c7a46de29b0404e15beee667ec720bdca09f24f148b1fba914e67d04272529", "0", "0", .Okay}, + {.Is_Square, "2064813951f4630df4eb31c239927df5ed055dc12d774cd495242ce84479bc21ea04f131b9dd359db9741824a41401705ac3d004c0c483bb0f8c88897b41807bc73d2fbf33294634d8fccaa614b98b3cec73697f4f37ec3fbc08d71d7ed62fd29cc42217bdbfbf44cc0d935611fa54a19fc819d39bd68565bf1099e604699896cec05acaeab404ef54492b9031f8126ba1b5917719f9cf44a87ed4118c93879a2cee9e6e59b035385ae3f430f323cd15497d0258d012e20525882646a29e6a37a7582823c068c63cc672bfca8b29a87b42f53bcf1290b69fe842f9e29af6193445fe37149026d1a20785cdadf5e21a9ab1241d50342f4089f0d5c92d5b8c048299a399a50f1c84915d6920a901d6ca4b5b953814fe8c2101f40367c8d2a7071bc2d5190b6f68dc424327567ac73c32d2547b6f2e63c613c8e861e7491f5630886ffaac74e7916de00d67e104ba66ca9e7bcee4e7e4681f50a478273053ae4e574f1ecda89e33a2c4cd5b20d6638ec4b238e250e6b4f08170971be738f85ac47d6a92e278307a26214e2802ae34075575752ab957169d37c609495558923438840cac3d815f08062819cd504bea30385b46b51bdcb228c7742c3abd35090782e5fcb23452fd2d5c5f110a4d642cc1bf174185adc92319e36851f5b18cc876060bdb820666bfb4f84436b5b49958b064c26f4eab9a813de399b3601463280476d4", "0", "0", .Okay}, + {.Is_Square, "503749b4049ba9dcf04fc3f2852cb72e5b9ce3b6b82617873efe496ce41446ab84fad10e397e823b97cbdf550afb30b7480d97c01e6d7341c5fac38bd7256c1cfdc8dd51dae5ebd44b4a76cb688f61a9d98f3eb2ea6e0e45d2686b1354b4bb75062e2e1f5f34695debb1e6ac649b09778edd081873d064193f37e422189b86479937450e48ec69c3a601883dbaf6db802024a7a2bf75e2aa9678fc8379632f1d25c0aa9d3ed3ea01e3449f6d5197259ea91932a79fc54b067edae0aeb12788cf0fe44fbf73998695ae5a124766cb5ac738b532342c40de285a7c354cf9361111cba8a75a2079a03552cade58370a848718e2bcf2a4083951ee8811979748b5c21911a37c9573dbb909e6db97d0dd791f02d8026b485511e628dca51be60ebec42649fba2c1d9db982e3e0cf2236227567f8bf509fc3bf1dc98f475acaa5837b84e8f4a1fc16961f512532e163d70ab08ce5f44dedac14043f11da7ec74435125c03f1d035ff6686093e4c02660ad269ceebd8cdaa6e401f43865e7cd26511e91199ec955ae081db77424ffc27211c27c92d1d87af0de9a149c6e9500af880872db07ca1f432868c03ccf4aff6e9deb9165a3f13ed839f23bf6ecd69295430e4c624dae9427f8e6234c0fecad5ad3efa0b086a9f194cd02500e327ab65e5b7e0471c27d7157574896c80c752e6c7d26312619862bc60f4f12ba962da0c6e27814", "0", "0", .Okay}, + {.Is_Square, "a41d26a58002a0404e7282ebf7124fc690c9fc2cf9cc521311b8543a43ac922fa168ec43d62360ecde8a8ad3a39da86be77c6e31bdd1889f88bcc8d1988c1f9e71efcc28071e45a09f61efc7f3b54ac6e9dd5dd70200c7ce1a314d8875362c43e5c6737c6c6cb2021931248f05637303c7fb08fd059d4fb309870bfa90534c05238768ce011cb0660cd9816d026d4bc92fc9f54876d290b1d7d89d3d12c96dd0f17c8e08cda97fd5d6649303bc0d6ffefcd4ee314c6f0b704053168392562228fcd92f6a47bdfd5f5a96d875254f53eb01f38b7844aae1efe175fc2781a7516c05047dda3df3570f7c061a3abf48f909b5ee4bb92c2f3be9d809fe1268e256aff0e102bd24c2148c67ba568d372c5a326480e8c0d5ef4063f13f85b15121e73e45006b16570bba2d00f090921cc9746464afc84889841ad8965597f4ec2af492bca21e1080827b80c83af280032607d022d13018142040c98a5d7b510f93db4e07f6c6d42d46b28e7c51c8b461807c987ee56a43ad35c3a4882f408eb3328506ec0f39386ac4c9f9cfdf07fbba5cb09c7e8ade5b7ad7431ae790213325e7183a6b20373e12b914abaaa544475d536c461687682b29d0e387884ef69ad6fdcc442ce550aca2b9f3b73934f4b0052ab950464bb4224e65a26d9a3c75576f8fe155414032cba910866998e088cc2a3b6dba781775f23b62dc72386ed97030a1e29e", "0", "0", .Okay}, + {.Is_Square, "9a5068bfd53563a301ea9f6dc23eb73ea4e16c7242e8a20cca54d514487d7f33835efb52c6767509917ea3c8c1560deb57c61b52ebc24ca67bd0143caa3e5f82b6e1c9a19e24834ba0413eb47b58b77dd36d87ccdc0ab0a965ade5cf9b47555fa8f520da44bf27d247add4e751a9bc33c0e14110afd958959d0d066789a8c464283f87a6660ebc1b6d99fa1171031974c556b980f003a969037935a6cb2d849f3c5f6c2947c1498bd4cde7b3cbc6c9fb6d13eae477a298b3c4ca8bd119e9611deef39afbc3557375e7d37df70f59fb534ed3ed977df00ab515f95aacfb19728302919b66a8578d3049e95ffccb9691f54bc2cf4e7aef66ef14504bb193c04b9c814a414046ab442faa40fa83ad9435645ff631e2446234649734a1d9a8c5b0c58735f9e018833ead5d72247f2f35aee557106dacda7c52e54afeef472122607d486295bc1745afb4d20250711f9e70b702a1233d536d973dff414dee6c4aad57ddce870194b0a935510518c28c76bfc06e56ef9fc7cd240a83bc62b3db8135d0d29ae64aa6d9ae63686cfbbb1c2bc9413ecede420687511d5f3efe32e3057ac3f62f96056d7f74e35bf7995da69080a27ce0854f8832c4ac07de6abae474de248b5bcd499668d30ce93781349ddc78dd4c478da7ef1120f7283a53afe4623bba73cd62ecc125f9125d386875cee9b1e24e27cc2424ac1a6f7c243f8e14b4e99e", "0", "0", .Okay}, + {.Is_Square, "63722d42e8e9115fa8f4fe9117599b255873a1d1837adaa58bd04e4682b858593f04baec48134bb3fc851f60bb64c4b18f564743244c4b820da0a4c9499c0f822163164963bef850ed6b9ad38f473ab721988d286b4d4a2b9e1d337120ababddec5ae8ebfcb733d985a4d574f78edb86a32fca11a0c5471a058f8f39137300cead22e70d009e73e474a92d6e525a2e6ca75831e1f82aedb4adc5914b1947440d6c9f3758d619301958896e4427345bd6283bc46acdf2dad271a86d884bd6a8de046174cefb6c5ec781025e823a1b08d24152122dc6261f261cbe4038a0e06fbc5e10cef56686125288760f1968c787a367e8d46767c34dc384725da4dd1f989050e30ab44315cd6f4d6ed852b0cb546b0fff380b99f82d6d582c1d549184ca5eed65768b8ac7e9f0cf2d6e0ea74166f4fc85d1fe21bb60c4bf2563506a27def805c86cde358906a287a2b03597118d02a24a81128b3000f6a42033e70bcd47bef26fb3af3b7823017a50c458d8518d2c3cbe6b62f6aaa07ea0b05b79844cd635154d604bd2958bb06e0b1c2bc89065f6b010f70d8796abd7076b7ebef8123d65b16a8ca5b07be9e988da0857f1a7815b457340c7aa06d399316c85df6688221ddfd75fe7e23a98c64633a457448cc75f6aead5e1c920ddbdcfe249bfe67429a10f57f4106fc64366eba96f5036512d27a71389d70edb0332dd2b3fb41cba470a", "0", "0", .Okay}, + {.Is_Square, "9603ea1022b332c0bb2a213df530444a7d7bcac714fe39c36c7067b7db758e4c2e4858ea1da0ce5f984b0cd5438c123233b691280fda5bac695267035584c7650aa5be1acd0d71416112279764607e314f0aa67cc06cd4a78dadd079f8738b9fea195611655ac6396d95067da878412e1907b840e5d9e80a76a96878d3ee1cea28c87f97eed063da73ffc5a7575569dbc6045bd874785d49deb375f75b053f923174c1e222651cc47ac5f0a1f2d93278bbe9ba1f04cc0e0e58696c4783661c773c7ef99e76536c01e56e8f89a13f5e4b122c275b99c6cb999391ebaf44fa9748b7f7006b65e10f2e0a00c5020d4464f1e16bff5364d3144386379a5f16709ef8a84ab22994604b5c2ce7822d5d77da9de45a567d4aed7d4d9c585ce2ee3681e6c113673047eae33decc24b110be156f26b614a510d4daa7aeeabe35b5798bd10c7e9732e182ed77a9bed10e2f5e30dbb8b5540406af0f46bbaa8db6d6bc31b733c0e01a36be1eac87389d35a7394f979dea4ead834df1f2704a4073f64925426a818e17866dc1216d1ce8da478d1d2161f1ee92d4cd11c385678bc912adbc18047f87b6d2f296e211dfd10f0c1c188389104b77c1d58459a64f94c694751ed85399a78ee64e5eb5617f79bf96cc3ff7b8c369b5db6785068764fa3cfa3cf9b6e03277a7517acda44a7b04747cc87856f39f8b192130b3f67c3108f9e5be7a491", "0", "0", .Okay}, + {.Is_Square, "dd7478f68df82de850496aa886acc583d82bf5947cb33607314e5b2e17e6533c70582ce4356004bc26088eab8da4849df981e26581d54dee6c6bdf7a9216b3f1b292f530cf99b31afb34ce374c44c6d136405e05740b8233269664686225c1623355d7e96231b81d02bb9199f1987dafb2cc51861a17f0ce764ddb002f4fcac7f0c6a3744de30c0ebfdba1389af3e9e74cbcd50f4c43fdf2d292e9015cace98fdffbc4361560e72c882cd67b50fd67c89ca5d2d3d0e6f07244fe25b74f11c9d7bc4128a64073b0ede617d062d3d41d5ce4193461512cf826cdc5ded148630f6684a02d3d79e95d10d894d1d4c9b47d9d2ad5c882a6ec43dfb7ae40673eb4af8bfa24da73d588aef7da1eaff06114f7c27f949f27796649157f5fb338b0ab6e5f7a2584489b8647e32c8169a708be01a35b94910a6757a5c6b03f69b7f089856029a74aa1045a636a00258a423d330dd29a46081178b195e6e107196690502f8c1643a99a86de64d14274d06e0fa8b70ca38d0d147c4c320f6ff3a8cb3e81c71c5483984abf9f700d8f63c14676e0a76d41ae22477b5e445b264547a9ea160f1c2a50e27a35eb84e8c1b19fd9a31a45f6ff7abe30c2cf92cb617ef2d79163f09c4a5c0f4c44d1bdfb102f4201223b27429da6ea1970fcf9d8eba06b800b8ae58334ed1e8008867256df39c2506c3b072d0368fa1d78a2c8ba12e538bf75607814", "0", "0", .Okay}, + {.Is_Square, "2dd67d25a245fb0beeca6a7ec5ce0875fc3e33cd68a52c74f4befb1044b3e20000772119655744d13ccc433860abfa6a1a79581a88154d224c3382c2373771b0086cf6f4f10ae6564c98063c1ddd300535f25d79553ef872eb35fe16fb01187ae87f6b9c5f6a60f66a6111cad226c43b1926a6e7dc0e010892e6e536f801f1f808b7e10f058ad93d68c749c04ac5c42fc0081b7282774d92c4b6a7cdeddbb00b46374fb73b8c5617d869ac745c9d8884c81a8df0ebdc957e1682496fff6e9da6731ea3f7f7cf8551e41efea4923040e86fff7ab6d2be41891668953fe849f5442e97b595e8b9804e2c1583fcc619155904c51e2975ac330976eb7e0fb3306e61b4d53e4fe5881662a505a66b64931bd17e68d0f218bcdebcad8733bdd9f80d38da2877e1c934d12d4a0ff619cbccf169173c22c8190c82af115adb73c2f0466bdf97d9800ee733cc2ec7020af0190a37768db6b8b1804d18544f610600c2cd3ebe03795647d3d402caa07cf88ff90f5e27e0a86e96552e47f451502c3eb3a5c0a4257b2727261fb0cc42bd14b546a5ff679dd3612d3444082ad0ca35a4bba4de75f7a40d5051e94aa5435c3bc853b92356b6e5a531f6cb0762c6df3999dd988652cd139dd93756c377f1c1f8dc1235970314b4acad68e2b95e069d881d11b2fdfb23703e660ff21ea3217f48c716dada64e6b5966d8909d277edcd55c89787a", "0", "0", .Okay}, + {.Is_Square, "4c9127ec5e15c78a3a5e6ebd06c9bdd752916ad1cb59fb2dcc6d71d203842fd88fedc30daf752697d07cba20541bd84b6354bf89281a7eecff07dabdd132e0881b5dd5316619525cf634de9f53e4a712ae2c133f0b39057afad4d717f27bc5c8b7ed30c2b5136af949bc7d8f01c8ed16dcb942351f32ec623ed7d5eacd868b7e9b5732ff1c3a200929888198b80d312b292d3a966b20a3e421133b39fc4fa8c5afb1ae97567094911b7e3da7c9f5773bb6c4ba34b416411e9bc26a54425d7445e37bdfab98161531ac0b75ed570914a11bf568c0d689404f116d0e7b7db7592532af3d55849635ac859f63e4d102ca62535a60d394c9d9c81776554694ba8c7cdfb441cb066026ba66e489480e58314bd6c841fcbc0f852f2a9cd8945c00d496999610e28e871d5078239dc2882e121cb0a3f3370aa96234bb87dee93a35e592ff1ffa975006e64777664c021c0d45d2233a6623ea69b974f5167b8ec8bda38b55db022770c6bdb6933d95e1440d3f2f15936a75849503befdfd1ace73c5e32f744ac91d7266dc39267069bad45025b7ec5b2eb273278d649c7b88683f7546f7373d5c0f1190ab2f8eabf75a009c5c8a51bba0261f49935067f43435b052c160f86ce6a20d8b334e591a29a6ee28ccc1182a940051cbb9d2c2c451686c254b89a92701507cb3ea6e82e1880c4bfd0291e416d4ad5b1c39a1ff51d912730afa0a", "0", "0", .Okay}, + {.Is_Square, "906efacb7fb452ed2488aa71334ff691b5892c51a38c15a8610d9bd66bfce2a5ebe6c348c3b937549498675a42cc739bc2479df21e60ee8eb140adbf572337be97932f70bda90d0d54be6f83c8e199c45f4b038ca60ae9109c27c007b3fa61d3547cdcf4f6053d27e41a17c7c68d01a957fb8e8c4ae8ec9de01daaca45284270fd17f8fb70bdaba792e816d745c2bd8515e346cdaa61ec94108e117b26c89f77e8a10612901af92f39cad30bb9b3c1b74bf1163e5334f336e00b3dd5e3edeabefa4b27ceffa930d8a3adcfa63a2a4b2760ea7ae9653acdcb947259975b6d5083d03ac264e5894176c85a7f60a4370c6337b32de8a2c3821d9f7283dd80f20733e5a2c65574f57f3bc8da6bc8a792d926aaf931d606225392c52a7ac38312a0000652d036b14d19971ea83140ad2a3b9168e2d31f505c89481b9c721820ed939b0291ecb2659b82bcec731b6035b1404b0e3af305eaa49bb5d0084908271026249252951032069610db2957d262835bfb68cc3c5908a1f186a9992ad5287985d338c8a6440c6bd72a44335fb6da20ae4ad4fd8b164996ae4205ca58f3cfd3dcef1e6be6ce643569bdbb518dcfd638d7d16ca855ab4b5006586f2ff087c19b645fdcfb52f947f47d6b30249ed0b97ea3e22708c740bb62b1fe225aea78cb84d1f3e66941fd45c9313b5b374a2e0f691f1899c1367a5002362bb1cecf319be2c499", "0", "0", .Okay}, + {.Is_Square, "6eb905b522fd972e368b0fed29e948a6e86796b14d22513ec2bb538992b111e30d115abeb23fcdd263b5a3675eb627e780a6d784b45f6af239924d08daab140a5c898f019e53ffaebec6c169bac2b5f6d5a4577f90dd74c6a710a896e95dc11d1608b130f3bd4810cde681f8dd10f2feb6b61b8bdc01a17d25d52f514eb1b4c626dc1a8e2cec13f32a2dff006924b120f63da64ffbc4003c9ac29cc21a848bcd8bf49c81933020a2ff64253e869f13136d25aef0b37a07de3c7394fe695059bb87268aee993428d83dcb7684bc3375c260746a65c9708432d4e192de001cb1e3b8aa07a85a51b1c5964a9dc19834ef42e987126a4e48664b7b2a8c2d87586698a5547379a8af03ac96950d7e01aeedbc8425689af8715f4169542c4a921d5fd93fa4bfb2e70b7237b847893eb58b488c7cce615518c43013496ed24159f8249ad2e9df307fd81bf99e9ee0d7da19d25d4c9edcda160c77d7d60d572724f9cacd66ba87702f80e6a8dcb67f09a664490d48ec5edde87b828be4ba77ca203ccc4225fe5f39313624448ae4e76f0b3f33b8c4e75d540119e20e74591e756794cbd0ebf546e07239328d50f16252fa8f5f1725ae8a90e3aea3dcf964c76bf61a4e7383fc83428b632392a0374171abd3170d0f815248fa1daa9496685ea66e3c1658fa943c073ea2443cc704116c2f894c6b94492de2d1f10242e20941e7ea1ac3ba", "0", "0", .Okay}, + {.Is_Square, "a5d30f1deef69b7d9a2fafaa603570e5d674714fc65506c30ce42c2c9669b51059fbf21e4ffc282be8ffad6190d8ca555ed08a5e2b53793464655948712b6aa083970565c8e66840c0e9977f2e6c69cf1f3cf455a30c74ec3781e482fca4b64ddcbef9e10d832061cc9c113e0fb9aabba68185c27059c24a69602a5c4514b6185b42aa0d7839ef071b31b4f6513e7a6240165cd89385d19f3b282736def02bd74cc45643c01f0a81cef2b17426aeda4ee96d0fc1e282eca445fa55f37a9bab33a4ddec971b9d9951d3a8fb12b039f18a6e46d871eb863650e51e91514177442d7fda451e2e073ff0389fb6b6a11b4045b28645d1b2f9804987b9b0d82bf282f6e7d207ae7ed1fd2800cc37db2a509d65d5bba9e70bae74c874a1e1133e8e3edafafd41dea473ffe92502b0b692b4ad0db05e0deb68b387446883d05a91b20c8d81590ad0c72e3597c6a98b011e7d48c43981078e61cb4f1af8f82d636195e57d25491edf0ca3be8f13fc44ee088767490c52c36b4d06e48048909f4c00463b9f03cb2c48e6cb72120bdab7110f7d471ddce689ff7859c509f0ebe78ffb2883bed699d7a1767d16b3b6ca2b059d2eae9f88051c9f85ea4981a53497eb541cf3444b81bdb8d746154035c238921ac717bb4ef470327c1d66b805cbfd6b3329275ce21ea3ca01d24f20c29ecbcddcd2dd618df4270aa31a27444393d18a872ddb77", "0", "0", .Okay}, + {.Is_Square, "178e7c0015652293b2a90568c720681a38907f70e4f89d0a7b9f0562d1a331404fa337222bc1fef508275d1905f7c3608877a1d8f836fbb458b28834db1a2ef16fae4c2239549960c8c53de6e8a8ada09c22a89c362bd1882ec201c7444a47410dbe9de7f008443a8af69e8799e38eb5ceeb527dfc92f82bfd453ecd94593a8c45bf8e74c5129b8d86e9acb7b8b8fe1cd4d79c173cd2dcd3b70d589e5a6ce19186d7a87879a5c5188264a69a46fada6a9a880cc0096fceefea0fb22b13d09a91c2a5ebf58e6c4bb5c23d51270834fc46161f4df985b066d0f1e7d19e5f3b5dfe1da2d380cb87f9660ea2488207ce494f6f44f06e2b60f9d6f3113a1e5bc26deee1d1bf21da1d5717423f0b53a3494ec2740f34a2741b7f7a899124514e31dbce03d1013d50bd05d40b129ad9b27506aa3d60408ada7391c8ee7c153f4c7faebabcaf02b0359acbe3ef43726fcda5164f46608f568fc2ea2559d5883a525049a5ab3cc994673f8f0093e3b32f76bb6679d4b599ac4fbbb563788a9f9336f47ad4f9ea7c7812d1b6466f664fa28d86583bc0f85b9124a3ae9c03c9e2fcd728ec161e2566746f48bad2f681c8023b49450b2656733a8a1c106a1da62eb9e159e8e82cc31018bf05d1b4ee9df7e3efc7dd35e6c51aa9eb1e5f378017f7a7d2326949072b92e224a50fe129c21dd4216af992cdc1400344e9fb676f08d2b4363d3eef", "0", "0", .Okay}, + {.Is_Square, "e9b230c0b14a459ac6cd32b3e26c1dc3859c6293f7aeb709e14c16ad3e94a989ebac8ca16f5f78626e40edf6552f84fc3cc2abedba31c0e67dcdb4903e1b0446a73ebed51f665363d2851d2e1cc85b177f5cc539438475d040185ef831eac62f311553e5424ce9f796a6582b51ad13651b3526c2d7c53521edce78b3291e8eb74b5b7c314bfe1da53fac05fc2ea949845774600e02fa8e23ed431ad42cb60c8a7c543d6ed83d39067724d7e66164cb3a953fd9ac6c157183a5d13c2bc2d471ab3c416c6fb62b286c51cbd2c3a6434812c98c56de40f0555e770b9871d521c874a019acb5b0c27c7aba083e7ec120a9ff866fc58b31bf06737d0d007bc14d7a6237e43a481a745f7ec918dc5bda393e8abc5497e49535042d01c7c7e182d3f2c042e08799b478f502c466c4eeb6efa19b6a183e0e32784807aca8f280019247a81324f4eb8e6f22a51b9724ff7a525ac921a09c42bec22df728bdffc44dbf22fc385cb5e85764c21250d58586a5b4baed583e0cd258328b35e7ea449aaa10bdd655d7935fb892e01f083a632f3bdd726cc0260f5ca69735cac65819293d61b42d93a56a4ddf937de364a044af1d93b81a4b45c07adc38c2579c78f74165ea95579646d342550630275ecd796d61d50b8158b9fda099288fa64c7d817c643c72f681ee615502e50dbd05af1cd1547c20bfb726fc66bdfdea23b3b5279f82614a65", "0", "0", .Okay}, + {.Is_Square, "acdb946a2dcb47f43d835085872b5d6a0ee1868074896561b6e7462c384bcf51072b0e8f8364f1b0a94ed24ffde9267b363dc24ac843343f52ddf102c73e175b8392eace864e2bd0c2826d60165e85e03d0c1ed886b7c62924ad3ece4b18013ec682fff8e939279e06039eea3734dcafc5123aafe75807b1fd1c367f6f9c9ae7c0cb87d26a9668aaeab81d75d470a65cc714efc131435c130fe538b20e0cac70f4ab4723a5492a46d0bd9876cc8f1e92bc4dfc8fc6a70e6841dcde695cb4c470c7bd3f00a2889f8a422fecc5eb27e1afb4fc791aa77477c42291e6d8124c6f26f843683e97ca6484c753755d417f3c8570477ec9276b10cbaf5a6c41017c0d38f3bea629c39906b8b491c703f19626e784012b95ce75527448e328223e1ce08e95f20c2241cbe2b21c0eb67d0116a6f7ed928d9bdb63e6748610154065e18edb92e8a6b929418e5c834656d553d5c5050461af54ce5e8d80cba5f70ec7577cbb88f57fe55cf236c6cbf50e721d2d1b6380dfc2d7b4f0611b59d84e752d2a566258abdd295ed3a30b52bc0a7da22651913bec5d8e0b39aef631b6fe524ebb59b2e3629269e26a87cdfd34009a6837bbd3765b0d49d218318f8a9dbae3c56fffc3e4c0e41a8742ac7a3977924bb84b5fc98f14abbdd512e5b65bf453e92d28b09b197e8b7a8c988f1245c436a31822a27de3fd66bdec046a323d366dbb1d68dd74", "0", "0", .Okay}, + {.Is_Square, "c7e14289c1f212ebceea6ea2053ceee07ab0e27770974161975347a5cbc0f4731478d9d6ac03cc1436d2d1c3297d66016873c4f3e34bfd3f32c4cfcec3661d8fe7b21fb44b942b64c93241bbc6ad906480d5c69437e7d1dbb6de88dda5c58a55f6b5b2561b1b82890e52d992efdeb2c2bdeaa0e201716c242c79ba6e1889744192359d6f794228d0a799801a7c176c4f412970205b1bc5901e6780c51c3a47822d9ed45870044ec7b6eeb5d3087a0793e533cab5457abf37eead7e33fde29be3d5bdad9ccd2752fd5a6f5bbb391b64b05d1b2ec74fc9987cef8e2091d1e1a1595f89a6a92a29a586f07927844424f7f50e9d920b04a35051241af6795760b80b6a25199b16fa27541521ecb7419b50e2f1802ca9e4e157cde3f74ebf406c719211c2b8c988aa4d7f03fb1d693ae69f52c1862fc5219cd14a465567f27684c8394a18b89ed8ba39f26a7d48e25aa4860c6dc8028f2f5711568070fca3c0cecc3637979dc7a1106adf83480e16b2a907f24e34d39935b3daacca84cd80ef3e34d514fb58d7e59e58cc4d574260c43cc3aff6ae60c28afb37944d88d2309f81200e6f5193f33689badd3b7f5fddbc758b29b5d8b558ad7b3e7e0820211a5bb101f59bac744a4fe1f91b188134ec6f3d865f1b94b1c1480700b2c3fb080c96a94bd3285af02d27a2530d82e68e8f5acb200dcf632508bce7077ebb06eee0fea3a2af", "0", "0", .Okay}, + {.Is_Square, "70e21e9e70983f66fff43570a4fbc960ee74b68110bd9649c97e2de0ec5d4202f04f1bfeaefe83d86d3d99a21931326ac7e8427ef052736b0605f787e098134ad2c6d9972ad7098b54952cfea0d9c4b783f359ae0d9695aeac6279567a472f0692920e8aca5171798023e362a31c1e57e90fee5e7d515340c302afb54b436e5f8595daf67283f8c73a2ee8ee96ec50ad6660c8d3a26012ad1350aedf8b5d565d1c16296672041b14c26e63e45b79cd295a978adf338e3fa816a14eb92ea411c3622b78b02e03e8073b40c458d71412b7e2cd970e658e67c70cdc264aadaf36cf00583aced5acf3d0a4babdda785119a7d2c3a8fbb3d4a93512c50389cce86aadc8d0dd6d6b7f21daa0127529aa499d09ae5de912888ad04e09a6da866478e56f72025c080e264192f99138e225142ee34b8b8d5e1eeb329b359959262e2228af2e368fa68db34e197059e1aeaf710aab90a7c636c0a2562bddbb4dee74e67d809adcc3185132c1f8a70ad063a531fe6b8e124df6bd80c87ff40c650076145ef5f2cab4fe3f4a04a43ad8432a5a480144a8f4a4e71d87058ccdfaad5a228e83b44a3e8b1c684c4fb7d85c7f7d287c68deb86ffa78aede9a16ef05fc578b8458aec794047cfcb018f3446ec20222c8a621132341180f77213f23b5dc4e1e45c27b0787a0839b0cf9d139616d5b4c6352de14b26260c48f3bac106b40ba30d38f78", "0", "0", .Okay}, + {.Is_Square, "c5925c54ac79c0c05ea2c88864f1013c00d04e31c94a0f1267cc711223751bc56bbe573565658b4162349d8b8b246e20aa5d6e83be76c0d18cd5428ac0e4220a501b1da18792237a4d3969038f6aeb8454d7dbdc368af5e57d469444eea1b14ef1e459f6fea2c9ddaa84ef40054e61b3e9279f77c38b36ca7b7147ce906657dc17fd72b7054744c1307877f2fe8140077cbcbc3c36c3ecbc2c0754101f483162c27d3bc486567b0aac48ebab8cf9eb165d529287c6e2c601aef86bbd1b7796acfe6fa7419941e5610311e9c440cd7fbf570786847077ea96b77cd71e2060ac7211ff7124fc721745a61dddadfd53b76cc8729376467723df5f08bd20aceba1747787f5e4271929766225d828420f2fe1fff798d83de648ab45c5f904168c3a5127cfd63725cfd756a21881d7fa8d8e65e91d297c4661fcd1505a3db2f42d9c4cba2a15609444cd2f06d43752745076058de6e539b62285ea2e804b44ff6a0500f10c65e46089656616ecc2be33b1b7299d07dd2819520df4c624ea09e6b11a8e5413ed78fe2f3b8116f8070253a9547ec1ae23ec41871e0e4843b03f6f5d4fd3a28af041c2338cca547d93061c87c87ebdd697054092196ef42888387f6f95020534ecdb20f7ed429ab7af0c0caa279710b255b5e50ee4c357039aee8509a00066ddf17f9b51a0b2295b775881f4a6e3b6cd456f4f5f1fc728e6a4750368895e", "0", "0", .Okay}, + {.Is_Square, "f1acb41bb7e7dabfdba7f3c77e6cd3ff6792c219d8fdcf4a77b720a659fdfcc88c21599bf28401b3ebe3c74e87035ee5f54bd5cde922fdc93ffa296f37e889d8d380fc0d65ebf3e8870e7a267ad03645eb3dcefdf53ea6c9d0470c7d86125d6fa331ea98d1c25b7db65cf4bfa67d8511b08fa86fe6c59647388a1c6b7ab73a03982951df5341624eafcb0e6f2be785bf0e230e8b52eacf827940c34db9a97b3c6c0173bd86160beac70984332f3768733bf477bef9242c8a9b45878ecf3d3076120e3151738b38c6b33880a7801ba51ab2aad0b3edcf94aa8b451a6ccf3cc6ae16d1b1a7950e624027aa1e73da5da3d76b5e68b798290db1fd09338a1c16efd30310b1da5104925e4e7219e003562b8b90878ac3271c1c80efc0b8c48b3bb04da1e35d0e0f4faf0babfc3605748e64081a05fe3fc5fe34168e853993170dcabfc09c49111bf6449ade610a4407a498e04ada6f34292e7d9986799a6ec6e61c006e08739c6d22f7beac7701813a7648fb531aa3e561d912d45f53c79eaba6bcbff45bbf8a08c603f3c7afa3a7ff17addc9e5662cdaaa0fe5205ad69ee52a864efd9a361fb0215ee0a10fd09bf01bc98eade285d294ca6b0f204b88f2fff643fa12cb87dd74e19875de3a776cb3775cde1e492e2846a7d6d63d07cbf10244721db9b4a591c88b8f432e32405a8bff379f05d133a94650c5773fa7d0a7cc30f8538", "0", "0", .Okay}, + {.Is_Square, "9fb82389e017a5df1a973466a5b7c3567a33bfbc027c7c5bac6180b6919093bf369e9176357c243a3ea239969246a70984764f14b136659c502cf8f3a1386fc31ea3a90b25276a6130de4a4ccd38b486f069859bf98363e43d75ddf6a03b22b20921defbe91f8912a8b60ce8560950e8d384a9aec0718c985159199eae7e6a3428a87d4e3c684e9496fccee046b4a51b11f602abad106c71c1193b79ee79cb70d4101aa14216151cbbb5b0f498b0d0588f535c7b0ae1bbe26d95d652670d94b7fc790fa3df8e6d5aef14aaa6569327934ffeb56a9c2f00dd18f7bb5ebd94ee7a8be9b85246e82cadf7aef28555d198c1ab560e6270f8a8d8524da8870af70b33dd7b0c91aa0b973e9e6237e3b290eb74cc3b0af8b005adb5e93f8f3cac44e9827fa8e4e7c84e6ec360a65956f2e274b5d3c7367d44fdd4ed2294af7b015779f37b7793e51ca8a9f3099c4e2387324cd6178d26b2f912b7170709fade3434536c9fde8abc90823a6d91bb1d11edb183621247d095b72ad6174c311d348364994e8c9e08469c859fcfd4b161f821d1fbcd4f1feb9d555abb45a7da631203bbda5b718fbf63308c9abd4a7311eb023c009c7879858c63c4230699b2418084e914ba32f9551d60bcba9dba75ac28e6677bbc1c34e87c0849c6c797b2b7c25495fbbe2a5bd7f04abcdca0fa0c8e92bf7605a3cd90f69680fe49e28e0c0a5debd5d447", "0", "0", .Okay}, + {.Is_Square, "8a693488d48864709b379929fef73f4c8d8c0dcf5babf111a38c13e3f71d7b5b09fc05464a211c0e9901f7e58d01a9dc95a1cc76f65faec21df9eeaff0abfe2712dba4a8f1ee2bd4e66bd7542d14231e33e8936db375f83bb38e4a156ece8539697e0076e852653ae00f3047cba7a15c375f3244aeea1ceef96a5a91534e4b5d424e064ea5691f457f08e58056e886a8db5aea3b2f56038be381dfb4b0af570693451ec27e080c4ee58b0b35629f2ea9b90fe3663e8b4c014e8f5d90e86b44ac47944a8fe0f2e1e6a05621acb7991fa308edcbd47acad12a5ef8846a3fbf2a9488309b119f33b3467a96d7fa9cbd7ed87f1bb9fdb0fa7b1f13abcafc0e84a7772e26806c4031134a8cc7f19a557bdeffe57ecf25b7b50749186180cede59a6bd2f868f505501b706fda871899c89ec908c25ebf74865432a8274a58d5b12cccb794ed31b25c89720fab56d52a10cdc01e24a7049e57dec8e04aba3bcff819679dc1da8b4af7dc378f2cf913b1745e0163a5901a297ecfd8b5ae8f37205fcc77b14913948a1a2b43db313a9e505923d1a67e2042e20ab3bc39578e807373f30539cd9cff65e1bd7c7977255902fb93e454d9260664c6a9c654afe87eac70c17c30f52de2690bcff48e9e7796a7c7481fbff78ce60b90cae587601cdd6f943f38fc6c95caeb44238bb24a42f27cee0e637e9fd9fbb0d0b321bab2afd960112bc17", "0", "0", .Okay}, + {.Is_Square, "ced3d5389fdc6d5c85de69e2cb748e764c909176d52d9b2cf3867e167ca9d30c702858df0d888db63d977618ccd232702e703e3b686766b2a3c59bbdae7e7f8c348cb0924d762b7dfa3f730ddd5cc2d9003181e8be72b46e4fb72d1244ce57785298e487cf00f2b0c1a53d8f7ca2d750d42c75414d39c846ee5488806846a60e0f57e9dca3bd318ef32fe89828f0595f649f64550b47f75ea365bdd2c45274c4c8b689a1a03709eece18d47aadc1eb4e5a5c297de2fb43e06d717499f95bc07d1d515d0b4a2f071bc4172ed3ac92d2ee4e4a7b2fd4aea80d55a5e17c870c68c5d6b7586200b7a124f6c58cd832e43f26a64286e9e9e152ef3983c0f8eae2d2e2a39c66b09c94bac3c027838ec3f3d6c7fb2bc9f92b40cc5ff14bf3157e2da0795a3d4b05597d26551bf8ab0a41250e1ba4d1938632a88187a3e53c131f047ebaf9327fca0c600a9bcb3d795cf70145a643c3b097e927a8f4a01546b35388e6ab230dd30aac9c69dd3ef55bb2d3f478726571ada8e25854b4b2fc63d93d0f9a7b17823d0562d375717dac568fb60bab59c68d289b9b753889008dbf30cd7ff5b55d48d60f77b330d025161e1fc8b86092e482d20a5fa0b29a88866a7d5b93c2cb83e3d85dda0019d7fb71a9dd22c385851e55e7038cea559e0e54b463aad3037d24128b6b0b4a85d46ed73a6233200466601e9b8bff2b3b80bc7e492c20e557f", "0", "0", .Okay}, + {.Is_Square, "c206baa7caedcfa60356ddc755a77e77ede2148983a030b58e8d4b8512df7dc71b3802457481b7a4969cd95a05e7a3fd13c150f6517d61bd6fb1660df4f979df72f33098b76ed3b132a2e438fa1a0d9328bbe91195cce2ae353bd9d21858f72c015cfd42ec736fbda76832019cc8abb00f40001be1624987dd3b5bd3bd93b8afa151e49db7967bf715e26b4da26fd89a6d2eef62634eef73613d47900292f743eb08d25833d7a021cab31e1bfae345718380ee41d394783499bd112e7f7a9431f715879c07ebf2c2e79086d5bc0a168fdf615a80fe12b1615d684713c77c4393a40db7d187fc8b9d5671fb75c158c3fae5b73918cc26e1d1c1797ff7ca0574d0b1b73fb7090716f373adf073a3aec56dcd88d90366b59fd8a77832763d1dfbbdc448915de4ec6a745472572fb24c41deaa0a2431e4aa683041fb25189922673b34859f3a9da855fd029cc6eb85e2b4870fbdc963b723b77108119afa67cee992db4fd3284ae8650e2eb0b5f0f12e7cb3e22a36bf1b152ca4074b9bfe91f989d98bb2e8ef08b53734ec77e6ac0b77c1a792678edcc6076977141c8881b474acc1a149cdffaf0d3cc41614f4f8d955011519a39193793a25fca957120a1bf6c05d18796c5b7ca157c0303765b1ac68dfa8092838e6bad4193c439861db9dcaa0743e2c9873587494797617e2aed0077985272f0ce1994b1775dc9b71c3069740fe", "0", "0", .Okay}, + {.Is_Square, "f20848df6d447a35d477b25faf4e1ab2c0de64ec915727b26ba7ff461144182af371068567c3f9291e462c6c41cc67c0a5dff9211b20f2c23d668c1dd6bd4e63c4fe3aa4b467cbedc578f8d68728489b9fcb55c37899b35baa741ec9cf78676cb3bd1b6d9221969a6bc34403845f9ca3b10c30a9e55644be6881a9f5a2cae6b1c3757c51e6fbef40d0c634d8a1743e190ff207b7d984d8659f056a5af05b85ba32cbff9069049801d10a857c324e2a1d956fde60beef890ab547803ea2f89aecbeb95b370913156eb902995a7c2303d27c2a06cb5a94c0176c8018f429456f958857aad6d5061fd420f04a0b0f77e77e0cf2f04c915ea88d9c83231adc452992bf2fc1ea9e9b5e536a337f134636542c20d7dddf20fc5564c087573e287c3a9b915dec85b7498b7d82b00926115a896e7b502bbd602f5464f767a7f5a20a587a81cab2bed4c6c1b5d61bd1135ab00636ff6ad9e6b740362b1f50bf58c5cb734305667ddbb095965d79f8cd7f6559e2d41ceb74e9e8d3d8ec4ebefaae38bf552114c2134ebab7db486633b30a4b513b038d76d29565c52c77f9039d061adf4e03591a14180515c54eaf4d0e282d924d45e20810715e3adeaad3f7a64bf55db329d4920489b41c2e41838e31f38eff32acdd654079902782c604ffe42ece97c5a186bd1ced71b9e27590286a551c6c2b882a9f38552fe2a5cef74df4ac4b2aa8c1", "0", "0", .Okay}, + {.Is_Square, "cd1b42baf6a26f4934c882d9104b13afe24af5815ea43d31340e7103618e18c443fef8a33306f0cbf7dd4ab1d4d4eedb9fc00ddf78cc2dd6a7e482f926fa3b28620eab14177e2607ca413fd3b4762bdfd743d5646f00e6bba698764458ce3f5a32b837dc945afe0d5b806a8a4ecf0341978cbc788ed0fc90d7b5fc588147ac1ac89e7dfaf998b2643f7de3e5e40d7020b6924207361733d63465f36813f47b8be0ed30352e074fed85a9d40466a57ddff56da27d74da2e97e4cf60536df1e0db0d875d17716c0c12a99acb90e361d2b064ae2581f35d482793a6f6e70b7ac033cb060e3400635afd2b20bde2996438e0f134899ee99ddbab02957eedc8608eba0790b4b28d9bdaf3d04f2cfca2aa06cef42419c8d2e0532443d09bfe85d88744273c8a87bfcf22ac5e83db2ee451f3d51891d2f2c2e5ceb67347f76a4501967277fab8f673b3235826490609bad7b14c64737e93eca544c79727d9ac45c6b8896f20dc5607c7b627f778dc940ba2697f8d17f32b8ce8622adf4d83307cb50285f803ea01525f0bf8a8bf0133e99830bf186fe4f7377726c4a6bf529162f07eafc38bb163441187785bc9ef0c0b04c320f8c9bbb8541d74d9ff29049c118a471bda66766def3712ca5635b854571d89b8edb1cf9131e5b5910ac3f49422496eaee800307e3a9bb685990d71a42386d88663875ef25d80749cb874a7689237e6c0", "0", "0", .Okay}, + {.Is_Square, "df636546493cf584d52ba81e062830628d2eccb09e5b6cdf196070878e5ba90e87c24829ac9c4c9227cca37e6406cfe081c14604774817801dbb9cd846cf0ed55cb58b15d349000aa5ed672eab81f669e3cb9fd1c0b347b4ea28aced06279c1e20444906290402a927a8d95ed5b62100883304e3b7e7ae2dac216eb62aa87b3218ca2bb629fee2e805b643a36a287df72ac851abb2555ec8ac77d158a4a440022dc6969be9bd7d3e193b73732de3dbfb6b74a4369e5f12bdce3a0a7fd8e3fb4d13d88e80db1783de696f87df4d89f0b9603c72a7baf6368a065270c752400d104cd464657e02208e73fd441d4f2188a73b5254f76463ea769c59be05765994b23db8db1ef3bb6f6f3fe8036b42038e979b67c76c82e69f6e1f1b9e1bd91ba3b1a6dab2ef483ef39fa3f535841a491bbd90389c7c9a1586df6a61f32cc92179b66e1246d5c0f95bc0b2d641cbc8e8ae29d2b36ab3f431db4ee0ea66757ff05aa5200fb26355b0fe476a49c46a838aa02dd58eb8942743aa8bb017926d91d17c57d99ed4b2d6eeee7f2f5120b4a2cd7d06d9e3fb5569f8a847d8925a1a19d7af273c2ee6482689e7a965b270c919c9b815748dfeb9eb71c96ccd09e6ad9ebac0086f760d9b0ce47e5ee0bb2236dc8ab959c5741c34465e06754f0bca8e72494bf3ec12b06a81983f05f2ead188553ad2c031e4081b324462486c11d204a3fcf42", "0", "0", .Okay}, + {.Is_Square, "624bf60278cc65499840218af23dcbeb47b7451398ae0b84bb884b3d5d45191aa09d971d1fce2b6f4e7aab814062a329eb9d3c275d1fc110a62cd3e095d0e0b94525f2fa66530442500caeb72b404259952cfedcb8d75786bd0c2d013f5f3cc53f9d6d2635af6b81eb71da731044b1ecb5724e0373f9fdbbe1f73550a1e3dc34ad11234cd605dc8f532e1b4a69ec552dd26a84ecf02be436d96a715624eb6a35ef7bdaadb3b5e0da5eb5ffa78eb32cd5661030a2dd8524453633c5b726e204f59fec7b0b1ae07a034511b094b98e448c10e0ab57d59ce33833e3a6551205ed6f8b7e98d6e5ec835975b964809f379532bb8e072985778580bd0c77a661f54cd14b06e6c495d49c6b8aee0aa16568bdc7cb1d200a740b67f35fbfad3a47f92942fc72f8a0d8f8ceebd2fc2e34b07ae4495ec3ac30486c5f5ce955da307fbc82bc365171e2adda71a4b7700bbaa2d7fada4fb2f48ba2f935de2f172568f3b87c09f028228ec7cabf4c0604e01b295e767d7148d6864b997ca7ca6320a6c623cef528d00e8c968b77995db7dc3b1df50843e845f3c1287a9dbeae021703377e151c578eb8fea05d621547ae677ce434e9a07f5f2423ff6eb513e908f0e7745e045e99bb2eea0ea3e3305acdb0effc3e5351afe3b8dbbca20a0e6979f09897fba7a2b979b19e0ec3347cf324fbcbd318b0aa9b59b46ace57a6b71375e067223af7b2", "0", "0", .Okay}, + {.Is_Square, "f85d6d1804462a48026434a48f9ea220a964fb156cf11a04900ef53dc59b06b4adf8de2c9fe1a654c31717ed69ac81b262b47424c842a8aa16237fbaf8faa5418a38ddfbf6a0c28413035eee1d7da93832237326b7d897e50b3658aa5456f7347c3be02ca2a87193b2f2a52f4395577abde55b3277fa5a862f596763899e4d4b7f4aa8d2cd111c0014cb4f2a5a201f44577addf2226fa9a2435b495e4e993fcf55838875a3f7b28353006f69fefb98f63bfb01e18f405baf18efb90cfa4a24c8dd9673fb0e0d4cbe0dfbcd44c088cf11118af52bf99ee45cc464c40661764079a4b972a956c0a5d67d22ef58d99b993c598fa4fbd874d2ea311efc45be194a4ea9dfcd26e0ea8fc6f73fa250be04d3ec21385bae0d810d4456a75485ce6cdec3118c7b199bb4b998da792cad628df1fed42ad70fae3493290ba1425e6d39cf6a75bb4ceccb58deda4e402b348b1eac03b23a1eba44f1bdaf02f2b9e2345e0320064982a3a12d9ff69a8e45322d3d11ab746b2490e227d96bf597ccfde2c23b765549d70db91f815ca3442aa3de96a1e9444eed980f9e95f894308378df0d88c3ccbbf8059cbe86855acc8a6709ded00e77b098bf4a1f8447bd50d98a887fe88906fc998e529184abf8a3c3797954fbc50a0ce9ceb9c2ae0784ae74871eac4316e45bf3cd3825ee440c3991b44fa9d3db78a84f67ebe53a0aa8412667be0848c3", "0", "0", .Okay}, + {.Is_Square, "e0d236f3478282f8dfa421ed60745e55a31beba2cb907f372b1879b4d659e8ccca1ac72473a7082b25808d3c3784af8fb9987c12e91060c09f8a492096baac18c54bbed2021a2626f31a942d3e19446fb0fd0a0c355facec1f0ef34018f3d19869613be70ec75a6f05437c5752a6fc55b9f0992683b04da4ee03c72d79d2cd9bfb22c93ab8e3bcf5efe956ef60c8e2b9920741683beaa7f705750cf26f0ea0a3a664bc561f2940edc720944df89745921a81ef045f0bf7c3935101410e61c568a0475d096f1757b001ae774c1cedf4fe524f7fcf36b382c80a224db6356b054c2fbe6f1c32c811e8b22eefb44c1ce01ffe7477d27997fad65169947e3927a1d1ba2c449b77c2cc944ac7632306b77fce6dfd078c2f725645db943eea7957592e5e8630a7a142502af0b164c319a3cf42699a05afef1eed4fd99904edd8b570d983d5b5f2e344c58596299a5ce654e41a508e2c46c64e975cd31fbb3b4befdc81fb66fdaba80598e8e3728e4738f5dc762922ca142622c2f9adf831da281dbdc4bbc88904bd10f053b8e54890cbef4cc0aa2fc81ff6aa90ed5703e28e730d4b41d1ce75b17d0cc4ab364678772932cfaf351ddec0316c74b850d28e24d76f58bd54f22d77033d8421626f29904740b20b2793fd4112db33db11271350087d3481c3e5a135d9736f29e074a44f780b6c9fa76d7b71b7567d8b263c626d30023592", "0", "0", .Okay}, + {.Is_Square, "c393c87e828904e1e7f5b47dd79dc64a85c285c70495c54bfd9d437600b4940fc584b225e27917b21ac1857a526a8018238a4fd7f4a29c0bf9f98106ebb639d5790e01c9d08e0935878aa2c381ffd9ff7f3ed259b1406f0b8184ae16c85b265fd15f8eecb02c6d8265a5b0bc832839fe1dab1a0dcc55a1e208c6e70574d598b374f3d576d33222c3e2bb0da30b158b4aaa63e203f3caa99438364a039b9603afbf6e4a13af27d36efb7f28356235d511a04ef01022571175352e1204a776c9a47ccf409a0714a2df2d69911632343b851e36910d6d8a6ceccc60e2b5b63c880bfb16ffe3912a2de084c3800fc2518d9013a8b40e6d219c4fb97be9887b297df0300ec2df9180dad25e33ba8cbf7578fce19ba105e5738fc8cf3abfbfb2da39f4eee793385397127ea9e8bf4db93625814680ad79d146c074f8663f33e0c7e4beebc68908854953fb4893e97bdaa4fff5181bd611fad63e1e245e52071531f5bfa2f6ac356a1b72bffc9a775ef21ba94f75ea91d55a8f3bb92c30d9b4ea3b7beca48ab73cb9c8d37ba4dc0e56cbc0e0a0c125a48e677869658172c13f196d4c3caef7c568377e9f1aba449ec6e628174c303e62944dca71bdd5c1e4c7b2b6fd0648cbe327baed56477ff98f7c68097c8f2843ae2be92d285721ebc08d0eb66ae7f7e615e3de5235de5940b0bdb70ec31e19213b88d4b2c668b871f4b3eaa8cea8", "0", "0", .Okay}, + {.Is_Square, "8842e8feb3a3e183bde00a95db9ce420a4190234da1e9b7616457cafa623c1f8ca4c1d37bacb2e87652a18e039cef7109ba11024f21978223f6458b946ca55b3d0d1be238ba10f86f8319e5f3cf57ea2a942f48d6189c7c246d381ada11c4f93862c301379b14306560b9b3829b89d69341452b4e9f70a5f8f3c13cf433634459aa02d950c0323b70ba38b26e0431656c80af5184095a7e2617a953b2f84098882a814d8f7b1f45d07cf5c84e88ebf5828c672fc4bace6d723ea465dfb83652c7427cbebfbe1dab48a4ae2718a973970246a449c78c8dcd5f03123c8a687ac0065be02ad3607a92b21c5d003b47231ec2232ad992ad916f12182dac1011265eef3638cb4060003f9b3e9af9539836c14e524605878dfa47351a91ed2139e55d8cf97bd209b3b90f1d4aeeba7edd559b37450c2a24497aa1b8034d9652eb361c764dacf9837e42808bf55a9be72c077daf118bf5689c3205c00a8dd1d8193cd30207837f36c75082582d22a6c732dffcc19279b4e9130c0a56ad7d6944e3bbac7d69b8151cbf02ea10b0e97c501122b5bd0d357ae0b0d566a7b01f6e3ba78a663c76dfefb89f0fb2315fcf9d8c1f40228d7174eeb5f950d6f0a03be84984b4b223a0edb407ae1a66477c300862bdb4d21b423e5115e66f535ffe93381753041db8015c280fe7f1f1c7b19f59296e78aafdb8cf7485caf65b294fb53e593e8b1", "0", "0", .Okay}, + {.Is_Square, "8a7975b5cb54e275406d00b77150b5b71f0798725e0b664928f5631ccf52924fbcf0b6c9790e5026bfad9a0f706fb9167c125a18ebc869e02d0c4d06f57703a741244d87621814a7ce657998d16283778b50188ab43f929ee2198e5d8ac68ce6b166af572ff6776a83df0f320cdb1f926406009b7e8411112c6615f85016f1364b28122eb66a9d9174ee03773a2d65b73a710bce95cf9f03e73f9ce0b63a56cc5a4774b647b4b75405e81231e1a10799b06314912336fb37a2d0c7de96139a27601268b9d84f43578b1448b66474b4862c4f8db84d8ecfa7833cf1ed32dbe1322c0822d4a6620957cdb15f367103d143781afe6629e41e606cede958b8775641598b39a3c742ad0817a464787a07a2740e9964bb61c64ce5af4943637b9b61200be0e9353167f5d28848906db7a7b86a645ff37bb791c6e988d105adf04d200224ed030c5d333509611790bcc5101fdef97d2021b93ecb4c417a5c5b9808b12c0683fc71b9de90b8c3abdefd0c04f394f6d43f3c0667884d3a14078820832cdc65ebe80b590da448016c21f320a70b49f9c1dd492707357c07adb1754a548e259e3610698ee268050213460d1c1fb40dab14962ce5d28155182ac4547c8a1bd10aa74a229ab1d36903ae8d5a01e1d7d2547d5bd18b2922551d385ebdc56e82a16b08d97e9410bd6914ba0e8ee3704001096f9d4f1bea5232ba4b24a73c3b67da", "0", "0", .Okay}, + {.Is_Square, "98a6416a042854d41755dcfe5fd57bfe14b15e3dbbaad29547e8d048ec1fe8597e027c72c6a8b839bbdc86b909f2fea5bd74753efddd4a16e5423f389cd3446e02d7c37921527776353ea4635e21bd07a58c4888d0064132f9bc25a2e0e69e35bbd1f9a29f51c3b432fe8e20029a04b0c5654abfb7a5722a5594f98f07fbb470be80b436986a3ba5cbfbdbc141d77c76d9d3b31204510d8a4fce231b24c8b7ea8f0a47b0b2ed7a5f4d112fb7bbd4e92c1b4e8e3ca09d3d04c15254702cb1531a4811fc45c212981b029eda5572d9b0728c2ef9423e37087f47103fd75ab68b17b14a85443134822b7df6c5c596eb6d1f6073f84647c6f5275c66fb8a19f1433b3322edf9043f7901c0e070ba2ae39b88aad8b5f83e287cd2ef637e9eb326daa7f4c67451155b6a6294b56906d0a8d6709be4fcaf80564c2298ea98bc8ba13e3000818eb023f093002beced689a58415933a78be8519f24715b8ede841606658fd57781fe02b7e7ec0aa3e5afcf258f1effee4e8fc82ceb4b1ae7db81fc706b3accb70df94fd30f9d6af0e23888c88ecf938a6aaea921ef2ebba2ff13d7ee7547aef26213969337a4ea22797eabbe6e06c53f8e1a6755b2bcc36135b428ca3c0cfa46582ad11901318b1e273e7d025fe940acdf8013931346b638fab42ba68bf37b3db58992b806b1219c65537d12b29228c990ef64bcb81646d5e1b79ed81451", "0", "0", .Okay}, + {.Is_Square, "cced9c9290b5ee2c79d529b61ba256bfeea9e5035c0e276d69ca633bad6dd654000b98a5a28655a15d2ee94557c5838f72543cf52eaae40cf45577903f16231c27147c0322ef204b07bb03f7d9e4454dae09777c55354995de8a687c6b32ca1f57636d03735299a219b940922b4320dbc9f8967fab03e77bcace68de119a9753478e55006a4c1741c402c51faf3257a027aced602be1718eb6188dce6e296a0c969410f94d1bfd952ad9c650effaeb0cbd67bc84244cbb142ef9e47f4494e140c2f66b4f3208a3ea43a121e841260e128e56739be0c4b3c6bfdff4c3ee915f3cd45c34259c640e9048ea07152864d96e1111d0e26e481ce2bbfa4adeac7a50abee89542176adc38fb694f8b619aba6240a9cfe59e53d9f20de981c6f33ab562903754d4647f30d3970a8d29cdc3ea588f382a231ceebbf8761764de080b841960c6ebc90a7814fa09e5a8ae329dd35fc2be5bb53a33c40962fbb5bce9baad3a8c6b67ee86982fb478df54d9a9fe4ea627d98d68e1bcb6d3592f700352cd8f93948502c840c2cff7ead9dce8da4873eae44fe1540c3ddb2d6eb3a4b2015f262c22f39645f1f94b861ca67f5b69b7f5f09cc1c20ce4d5caa5729d0abf632830725b9d113396a557204ddd84cb8ed437a738da1ce4b1fd211c80ed850e8e7e83db344c4c29990f42f5cb756bc1e69bf1b039b85eeaf29f9bd688147b189ba6458fd", "0", "0", .Okay}, + {.Is_Square, "f54292431fcd5de14461fed68ec8502c03505394783f8d67112f2036358d3af605acd265b9619d2e482e49cc9f2b5b9f47f8e32bf543791a54940eb92fdba13434cbf6032999f897efa6f8ef8634be39887aa3e641fa09d4945429e86c1862f4e0155cfbddfa301fc6f552d23b07f40b521806fbc65298c2c9a38bb09dc5da8a7858b29a336ff37bdc1d0820306b2ea759aad11182aa6e34e5d247ca793f7efc85fc0b46856b242f7667c363b040c181675b8ff8e6082e3919f6eac60167b94f71e6bda9db9cfac87cde371fa845d354d5bcfe0592490c6758d457aad757fb80bf11ee7093eaf4fb6b02e3cef1b78e801a69895685cccd90c9fa6c5dc23b6187e76bb4fa909fe0f5e0175b645e640d905d6ef03b9dc8be5294156f78aa1eb4b10973bde4a83fe97ed786fe1f4eef261a52785c07b96f52fd155c8a265bb5b8d99cecd7c0740ffe6e778d1d719dd75d4060590ff233d2fdb3feb29c6dacc1c4d1880afaae8df5636c0f78dae1c7c28cf1e108fa7351cf9dbe600934d12947ad6b092e347676b627ce5f0d16fdab9cdae122161bb11e5b043dc2d43b1b62b90078ad27dfe1586bc34f9010e382b7685ccffe56e78ed58b3a655ccfff7e4a9f2c8e4d8a7c657540c51121aa126800ab9545125e70dabc96ad95f19fb01cfd2d1eee6e13d677bf54e6d1912b7860b1af0b45dce5cea5ec3670c98bd7e6849eeb81b9", "0", "0", .Okay}, + {.Is_Square, "f1293f75fa73d8bdcf4017a0e39561691b28af3802eeb1d3e0e71e470cc12efd329fb69edea3625a66050dcd41be485ec9f56174366ccab755b9b2c023a09f0c430e4a5e7b521be6d513deec0b882203abc4bfb8a88b572cddd8f1f686c8bd5ffab2aded47d32eec0e028721c15c0813d0e9cb0467daff95cb330d8e2c6a714c320460ec5535de0341b3c6bc275c7793e94cfa9923e6c3e7fa1c3fc0ad6d1063fd26ee347bda219b4c2ece389781355c85324de9dcc01197cc644e5f578c62f76c646a2f2a2f2f74ec1a37d6ba98d1a1e0b26f1b3e2e8bb1966a4d93a45bc23b0bbdc327f801df54e308e5a6341873932fa6eb069ac42236c3b09f14e17f4201ecd30ff07d9bb0b5ad0ec35ef285e1ccbcb03db0baf5a6027d36adaf47a83fd3713cc4733df2948164b3d912c3234c5c55b92505abe3a8abd0176899166509c42844efd67c0ce652d25fd137b6081b8b84ad2d4967916511b9c6ebe220163ae06a66672efa6bfe518df7c7ae87d26a2707866942e223f22cf5f3fe5ed5dd3cbda06a273843ed92a3d3cda03b2da42fadeb1689608f4c24effbff5f995f0c488c95c712ec9d62f0cedb06c75aa695bac0f3117fbd9557dde32ef3b6e6687ef068180cedf2abef04bf022994a1f0da295a89e12058e1a925b75ee9f0dde088e0502b1fd95ed873d088972f3d0ce1cbef444511940bc8eb27d33ae0517ef69e910e", "0", "0", .Okay}, + {.Is_Square, "344ad1b06f5f6adab883708b2308ea9d2100adfa0defbaeff9597286df99c1a6e1a8bde99be4ae7b49e0e9d306af7e8fe1e9a8403447ee65ed3521589e081adf85bc84a7c675d55550d2b7a420af0d6d74cc9d858ac14c92305025feae99df5032841df2a648bbde61de665ca805d188957298cf6d76834dd2a97b31156e9dd309fbd03558aa34885bc83c828dd08b6dc8c87f1290d6af862c32d268f4618755e37e9cd9ada331c661b525db497b567afa244abdaa48942e4e19753695de1d7e7fefe4b190c4ea98d75e2077608ece91a694c09c47ffdc353f6a59342770d6da8f600e83d2361633e3a1ad59b3cbe783717e53f1d736a9d4cf9025d687289e279a0dec32c4b57083a87e77b4928c80bb646be4367f425d8d7d1ca24ceede3ce9fe645d36ae9f7a07c4de5feff29c038c59ec19b5112a703fcdc024ed46ea5554f82e5decb4d42515a39611bc2b2ee09bfb2e98efb53883caf6e623c0a0f659dfc35a74260dc216699395f0523ef2b936b260e44c3151bba3e647549a01239301b5a7b6e8468f034adbc99261a32759af53172b9fed218a5f944c58a04e90a6a0b40ad81ee9a7c7dfdede3940131f38b117cfdca78484113f588f691b28a7ffb55efa9cb16557cf2bb3b0aaf5d6f5b98a0af7226c2846d8862f19f961deb51a71cba6d406ca87b264b9e99b418222c9d1251c1bcd7de8a6f354c962c0934fb0a2", "0", "0", .Okay}, + {.Is_Square, "a48eace7af3e5b124bc2405d06ac31025100fe91bfef5ff2383fecb7eab16663acb86ba013382c371b864dee06d7d20d65504aaf54c70598f870b564a83c5357794db1b0f8f878c48759ed687045b312f0558bf9b8ab310d267152f752a0b5e2ff6de00a1ac15d9fbf9fceb3be8ce30a7b97a5a3400e8c98937f9a4906592959f18eb5c765b06351dec4b4cbea2d1bf798387fb97e59555e7730b5943a29c919c0771aee0435cf1d8d9f6ac0c9e0acf04cfada4249beec8ba64691fbf14ebf6479160e68dd1e1524c3911e248f96aca8f6f76e0f4bf96586d72cac30456f54ba04301e29b1ccb2b4d2d0d847f2d826d0ff718efd7fba919e0f0631168fcf5b56a6d4a13e70c544419b53a054448a55202ea430fe79cdae18a01d01f22149d3fa5f428daae73485cd0e2b2221872f573fce06c56333832a91be9fbde8476a95f23645ba981b6aeffa661bf7c07a71eb51078274d3e55a07a5cf3b56936febbb80e3856a1f36d1a776e50f76ffe62c51c2f0f1e4b52f95590b789cbb0b140bfa119cb75b76a10eb7b90b11d7ef85ef0074abda5c7591d0525a12732b4379301a06b85d389fb0d9e4b56aeaaf52bfaefc1904d6812cac4c966e0df8f9c9a71078dde8f3434428500d7114f65f0415b86aa940917c88f4c0506e111835ff96e24443f1866e9fa08e412b468132e16130c39cc32bef69db0ab67c37b5563ef45735c", "0", "0", .Okay}, + {.Is_Square, "392ed29ffc30322e255fa63b543c7c5d7d0e425fd1a085e71ef38acdc3d933665f9ea48dd47f52a435259fbdd30b514f718f44fed6731c24ab9233c0907df5f19fed6f5d0b93ce41f388cec492b0d13f4c2b67b6e917a3cf74532d1d7b3bfd52b55a6d203f54729e6e022d11339022036556e5bb7d89cbf145e25aaa15c25f010cd1fa1373c7943ba8ddf8223bee996168ecb90d75e692cfb1e03bc8c3b394a0091c0056be2473f7ad792bdb7ba2a0f9f3aa375cbb3c854ebf5db1bb0422a2ea016edd5ccb2a34fdf8208b165040aef9863d75e5243355fc1af6e0ebc8fe5ab2a263bb11d2aa853b516472c2863746071582a3140f5cf18ac05ea01d770c3c86d231e95a457cfc2b664174ade87b6c709b4a264a7d3b54a1a8e24f8746149f046e388332c9c1597c0ce401cb777522ebb03937830d1e1f51983d93e9873f84aad6fa2879ba2b9ae10882059194f08e0fd95f9f9a4325153beffeb53afeea0e26246b907603d27a4085cc12be6e8ca2e028668915a8128e2dbcf64e75ed3bf595d615af5fd8a5eb4b606731eb0997ecc9761c9ede34518718ee98d2d8d8071b95297539203bba1676567e5160d1465fdb5702ff2fa35186950cbb90b3b4f2f307608340d160d16fc0ca43c35afd9c0ea4736b190eaa66c1105a306e0373b76ad3158755c01cc8f4515b3730532e86b8ff20ff711bea62272cac366ce715a2a2b5", "0", "0", .Okay}, + {.Is_Square, "9d1edf1befc70b415230ccb3bf4a0568566c78eff6c137bfc830f58943fce83048867a13c60edcfe61a679e007019ee906349986e13fc177f1450f5ba73f4453909eb10747076b0d3c1b7f025c52b754a135c8db3831c7c559c93d373a7ab5132611447d7fde4c7009d6a56fe691a5d48afae06b100559a92f38bbbecf90d81e0586d845efd5fe838f715a9bbb1f5f543f3b9c3593edf6ea6e0a9ac4da7d71255c067522031e5e22d4eb2baca6e672351e75bbd2011740126f17903a4d3827e99ce12899b7b806fb2b02be5fc7375ef1848af4803b3a75fe0e4462bd4a33615770d43f4a9d265a47e327ebe3e9473eda81cbe279bd2dd98a7a6828aa2a8cd39987afb9e37034bb9ec247fc13ee0c7a9c480ad6aa3763313fe2551af84d9c04b3899fc89e898c36a3e958e8e9c21924f8d9904fbb3be68d5bf0163c3fe68646c6370a39e5a1fc3d2060e9803b8d02cf9d936be73668e3be0fd8ff2e6de6cfcf15f1c5d5ed17a8c80f5c0f6aa59948324e86dfd5b791610ca371e9b57c1dc237bb2c4735239926d94539306c888cc2ce0ed4e2655347dff1b94cea76676e7c6df942779817e338f7b0174449ebd3e9ab448500154460a8650ef981752d9499dc5e93297ad66617b0dba547861091c8e0b11ac036c07271efd40565d082f23616bf2204760d5c07601b06e0bbefd0e643169cf47aa7c03e134287afa4022584532c", "0", "0", .Okay}, + {.Is_Square, "16458f0c767e449667a3beae68e097f890264dec958ee583fbad47db62a4344adb425349abf2629b6a2fee4d8b66f19de165ce1e8243f445b3c99a70ac5fc8ca1f220da13d79de1fc393bc42b91f578da7068733a866aad30fc040682a0e637cc211fd41206aa075c7e31a6d36a66cb1545688c25450aae464939a474ea78c59eb525885c8e88295cc42be10d35c6b47d14dda4a83e649344e3a8eaad42351bb37084f19d3c58b0dad34ea3f89a66f090aff1db3e2e0b9c62a57c05c38f2ce9e03e4b6892ffc399dcf77f276f3161c850d3eef895ce6c3bb1250296ec31c933bec335ed76d751da9b6e72799fb496bb46a42420a9f991e6606b97ab7eb9de66693aeb5f723c5480f7ff59326341f09ebc6f5c902ea878d860553c474975426fc14b01a833de84f88094f11e53155a8eba1543f91f20f3d17306ea903c7130a8b26ddfef66fdc4c7455560638d171c3059dc92f657f4e54f80107247cd9e2d931f67561cd22d529176d9ea31fa801dfa5538397b4823ac1b9abca14f9908e1e0b00e6afbd21459d64955a644d23244a8d6d5772872f80f539efbc6205218e1805ac1376d4a701472fc40fa97188a590aff31e3325fc6039b0c43329e6bce852d01c2258bbd83ce3959f3ee500f820da3a9dbb2340a2e4257ebf50ba1153f2d69c9ee01d8ade51bfcad89538c9cffdbdfa7b424a519f001ce147e98c36a34613b2", "0", "0", .Okay}, + {.Is_Square, "b069f752535588712d8de413294dde98671c628dee3b0fb967d28668e9f9c3d47344e5532536b43cb5cbfbc9e2d0fc391fc16f103b9d1e1a567266161aa755ee2ed4e7fad4175ca32433c2893a4be3d484621db537e2a53640aaa50ef4ca27e2ebf5d9bc9ae96549f639cd0661740884d43cadb8b483dba4eb9d0ed20c725a73e773ba50d74f47e6d7b492e9ece2818f45df457d90576f3c3e21d8436d657bcbd82ea56df53efd0293f9c578c3648e0c44d6f21006e03654eefccb02f17f53e3106d04547f305e02dfc4c43dc28dd774502e7ab3a0b94d4a6f5ff217e6d316f8930673b60e393fce1add52a1f0be9c5e395fdd69a2ffa59b43e736364612dba678ca3dd0bf2b685f14cbde9be932d2f4df6bd538fcf0615c987edfd4637d66fffd541d3be7bf586110abf0c96cca3703e6b9091a81b5071dfb9c6fd55f45c31cf332429f775b700e4c6c6156a0764f38a21d1d8ee51251360e2142d063faf57b0ce313f6ad2e311b21f1abab9fc55315ba3681e7acde12f1b4150615500e983c5e0ee0512f065f24d7ab0bd79fda93821abfe86febba27408f6f24a1b29b7e49ceb06ce69b9206136ab3ce93a8e349bef8a074717bb3c98078a8946d6a68718794aefd8b84af8e6d4574bf216f55f6264692f12081f62eb2d6b09f236c3bfe47f223e75cf34bfd8fdd667935613bd6e5be781bd0e582f1dc3731109ee5675f96", "0", "0", .Okay}, + {.Is_Square, "a7783804377d23223763150aae851fa880a9ece6db24ea6c464a739476fa7a84c8ef72858c19c1aee3c70bd05fabb534d1039cf9ad168ff9eee89c2d4352938208fab457f20b89e97c703548c47f4911889621c279b1ee494e302d546de2cff7af1703f52ef60145efe0df87132d63b29a567006700ba49a8209287f590142acb9070aa2159c132606bced31d143e5547150c0a0672117e1f0c4aa50ac9befde68019e0dd51cf4378a4929e6627fcedf8d42697d6b6c0228631a4f29830a6d3ddde57217ce96939a6ee3bd7317e7e2a8d64906f6ef57df13d4077e9fd161208137a553483b0a0dfd5b1f1d6dfedaa9f11cde47666d8d09a83efd4e08a991d9f2a604b0bf794443e3fea54765da7188595d02c867eff9e34ff19819b12c81e85cca8d51326a12a5530084427899dce2391931df8d185ad96fa00290319a33c9158a3653e33ec41140a36dd0c72c005d7f7b7db81f7546bbc5abe619b85f47c643c8db8a1eebb5be906d8ca1cc15acca4e2e5f3002c7e45ac66e3b725a339b82bbc2165e85548f30aae7ebf4252ee83c06a93d844cb702ca42bb5d92fa160843f5523d3e85eb8c037f7772b8dc8d46cee211614d75ef4de94324c2395a14444e991537a3bdd6dcec4e030f8dcd5e5fd6ec7a609abd8762c8e2ee3204057de617f7c96a0986da8444de3b1237c50cd5ff2fc5c67dd511bee08b328ef61ad9d2f03d", "0", "0", .Okay}, + {.Is_Square, "316273e812a4785499d309ea97b973a5437601d6092121f80f938635ae50cd9bd3c7dc3eb6f082bb0062c481183d360fb4164c51d839d8a1833d76b2bf6c088eddc578eba5da9f7528904d4004e64d15b3884957e6ba6924d7ffa28782ab358892d5205ed7702dfa931c57e7fe972a49599a95b08cb1abd5222cd040e94c920968db8afeed62664746d123038db04cb4e0f5638edb0ca6741ec8be915fdba1e455ef284dba36ee060a39bbb2f7f2678440aaef3766230af8134ea3a140c1848cdfdd14a3329d6568efc5ac9e62bbe44c4bcd8d15abb650a05861045aef5f1101ed0868d61d6ee9dd459c73d6bb7925e8bd37c9ab8e5ba7410b61bb9074daf6ee09eba22a04c2d5913e9f8255ba7782136bb4feb0f0694aceea208aaaa0298d4204e1edcba69c9664bf022a19536b7591fbc9d18b9c7e46d8847c45b2037115cb7d81c0d87f997d0eead99b13d6eb8b493efaf1d1dd94eb8d086a0aeb4059f5a48e35fc4d8ab83b40eaa78f5caee308f895e38348538df52cc7d4fc4fd37e687b573ad95d3bc05237844e89921ffb1dff75217b4952411792324207c366a6bf6b450445c3add93b2579b7cb929ad6302fafc6a4411a88c90c0daebc6daabb33a3c2a532c1dfbf62144674b0c370d4111331195bd4da804fe4142857a7fb328b997a5d176d8de8c8bded4272759d6b0b6ca7932e36f84f57214d630604664ce9b2", "0", "0", .Okay}, + {.Is_Square, "b9505334bb3ec6b3713ab05b027e14d300251b91a2bdf9065aa40659a9cef241317c2f19629c5ceec7fb3214723467067e1ad8d94c7f370c93f8b28baf898b14fd8e0880fb256b4b258e72f8a0810497329fbf5a3d98c01a1054af334b56a9f908740a7769bca1bf63a2b8f19adc7c76ed9e859b8b1095147904850dd61ed19f989910c485cee95f8a5e5843cfac0bf0e0cc61510f59187e19d88c8bcd1524608b1f9c3721838715efa1d66057b2288ee475e3e5adb3fceb92ef40bc4c8d49472f4ccdffe0918015ee8f1c3a61b6cad7d5ce2c8452d187952eed382e73565e5af468da088819ebb4132302541ad46f0efe29f618b934342937e78a102a89db4a9c6ed393bfb13eef2972133ed18e3869a8c38d2581e25ced7b752716c9c9b8ee65c70522e1866912a9517c956767b1544c9dde4e32d3228dcb52a895a855f0bd7c58cbd8c9057588b04bf976ee9289bf1b4df6b056566ae8c74a8dabf6a2fbd75a5058ab25246f308b3be658a66953de4637ea55269cdfbfce01ad62f0cc550340057bd34bd70be2de25c60b568a8f911a9f6288633b2f38a3118249021796b45014cde364a08b84d5c8d71afbbbb1094eed4cecafc24de943cf3a2befd27fa264948c3dbf25ba40feab619f35200fdea5bbd622b8dea6a71c365f2e9813d0dc656bb2779045252f0bfe1868f188a434b0ad8d515e3237e54e5bd649e509c52f", "0", "0", .Okay}, + {.Is_Square, "e68264d5ed1bba7ff6ab8638fb166c856e2874438e78e9d74b47b82cd3020d31d8fb2e0f420de02a06f8b5853f6a196e042e107a6f09299ffaf3d37e8f89270cbd979aee7eb5ce036034d0875d1bc110f8f8080d23f3e04717ab3d38b2c845683539b041c8fd60823326adfb65030411ba9deac22448d01d7ebccb66174a8aaa3a17b778a4d1f9dd3cef72561fecf691e6bd0782eef4d13804e707f7ccb656f6f117f4b9f5920c709fae92df98c12fb4c8b3936a652b18dfcacd126ce9b2364ac04f65af878519307a407c4a315e1a983e2a49f587c16b323b587ae9345087661ac1c57e466a893b2078c816f801101fe3fac04e8e16a9ac48b48dbd65097d788b0df66c87c38392ca1be11281e1b54eb5ed0c8d1206f03148d4a834e84b74e6f224d7f101ddae83e1f1f0f79a30f2fcccbb8fd7d86faa6bd4e448f5367145019e5ee3b0c41892c72fed21f73ce873ec4244f0e94d58640d83a6bf9e20b197815f09a9cac818063f26b7d578523213e1e6329932feb821b69443e88356e56daab00598d2b8c11e18fdf998bd507cfe16fe292d6f4ea4c86c019045b67aee6edd702f80843f513aaa35ac09c501232cfe2215e5c9e153c2678a0bfde14c2145a0e5b2012d1ac2bde6b05283aa54bd3c828bc994091f1f788a0bf2144edf4c5c9b569f8019d178c20b736f57a35cc10ca67eb2a85512175e4bdf4baa0b2afca1f0", "0", "0", .Okay}, + {.Is_Square, "ae3d38a20285c2c40bc05e1b6ef87ebd616c96f5aa3f68363ab3ab809fa852971016a6f39999686eb7ee7c8e1dfa624654f9166be4221babd4f172519a028e43c0484c94ef087f9481cfbf2939da6778d4a395ca1d808f5fb79935ab633d5e429e9a2f24a6dc9a5b613a1aee40542e8951bf083e04173532f934162447fa520afcffeff601fa51fab2bad3396f347a5966dd707a7b5a539583956b6a680a75f2758722098d60b3ee48fd5637afce9c28d765fd6638c5149389ae4d1885ebcfcc97e92fb1ea35902281d111d2f5e1a3deb086b65f9af6b30e055d61bfd56b60332effe92c4e562807d8cf4613fd54f62239194a2dc032743ebdef55d46d13722d588381ac7ecb8a527db267d39572d1444f3cc682cd750c2f7073cf8d15e7a460040b4c1c3eb8dba343f3728a2a74b0d6fa44073aa960e90f1a974c80e7a7b2d4019b57f480200584ebed442337e1d0b316d519ce1e5e525d69acfd8d5e7d00f8ea1616db5babb28f0f177b9b2bfd5d15680d28d117fee409117f6f00688e071e40433527eea226dc149c88eab34e8c2e4205e23398056762741b2735d451a806c6e1783076656c2316b5ef1b2c70e47a8ec21e51643377532ee8588d8fc1bee41855a1109f520b47911888a6fd68a29d32eba203628329e210def142b6e5ea01b15d1aa79e5a272bf0039487c3f80ebf0f0f9f11048717ae95a55e3721c43c81", "0", "0", .Okay}, + {.Is_Square, "52597de5592b577e97b7aae974bb483936f2cf9523ecfd5b0d126e9407313b248148ba7618c582c886038ccaf2b8bebc0356c4a28ee533a11d73ab950c5230ff50123e209d6b88f436a289cb750e59cc3960058430aaf3b0f3c17810d2e3f0aa1a0d9efac4e3d212eda438e815933ee036eeaf31e61bab648a4de64666f01c5c57d50122aac246eb688f9052aa7c4e7de74bcb0887227ae7122bbee0356079e6433b700a382d3aab5a53a6671a4636bbdc529cc055d4e738162cc476706f543fc71737d22c12097da5db285b4a50d3b04b1a037afa051c709941fcbaf70aaf908d822665262191dc50f740a90486b607e7793cb80c36bdc395cc5006dcb0dc611d9c359f70e6da75ab4de75caa607db1df3e7fe10a12bf5a3202b67327beb5e82c79e67520e27e146b1f94ad559b3daa3bc7fc0c4cc29e2fa81dd38bd5cc1fd5305112b4bf7e5100bc21f61f3cb07531392be82eae67e9fe4ed33d1bcc8af039ea7d21d6dc2733a205db45846e6dc0a86b531ea120013fb3ea782e54e5856e1c5e4f1cce183594f0b6f88b01d1ea4369ec77fa0419476318c20c8e467f2ebe69e190cc46eea8cc0743ad1865276ab92be9fcfeba642c5e240b0b6e8bfbaab47c2b6e309e5401edada972dafd59f089545864f78e3b17bc44a73309a14824a1b608ae5389c6e3d1dfaa095c83f6c14187c43d2cf2c8722a170452587b6bf86162", "0", "0", .Okay}, + {.Is_Square, "9a40251423a32cbf042d559906faae04ccf088a48d2e8420aedf03cec23739346147ba209a61cdcffc28a41a07115c1ee5a2b98f8b102945d20d34263c191b914b4e9cfddb30d1cebab9916a25d3b064f55cc3d9fcbbf39e184555198a53a23525747022ee3dbf37923eac02fe15810e6c8e1c1a29ce358993927c6df4763c4547ed860796f9b9e659ad64b7103bf744f2f75d0ab91595c5131827843c61600d7d45b2acda00be02f016c7e256aedc4167fab84b3e4a0ab6bab9deee0732ad9a1fd31d92dcd46313131ed1699545c6f1613cd18848187a8be3ea9b2a0f388182dc403bef59c164e5f0f175c06a7cfa335c55bf3dbfb33bcaa098ee96da368cf392b16ff3bba270609845643661926687b2e2158d967dec847e9d73434e32cf5bb5ea64f3cd758b26381ac09ec30a88b5b96d489e80917f1e6939d28f3fb18d68fc9c2b77f72b23b079ac74e0982fb24f76c4fd3a97f3f737266e95173c418529037b31d2ef3c6193e9b6bd8abfa77fb8aeaa235b687898963f00bb7dd09e2c967042f42607bac6f82e7fa2c9211d8a73f38ee164497a99ef607702fdc218721d1000899d30daf7cc1ba70da39673f5eaf1811d10b82d12e01c3283192c9740183c678d75d08e24062f83f33923fd232b0f9a1ee60e6397f196b90da82c5e6f4c471f0419ea5d08a59def1e056dce8c7881b885c69a43328ad8c5274a90563e26", "0", "0", .Okay}, + {.Is_Square, "63687b08cbbb0e46344c4dccd264ff394d5bc1f2bd4c9ded9d015934004912073ac871b39027f0e93d478250a77fb6ef3fa508348a17c12eab461b8c80056eb76194212a69680e5a1990cf95dddc9e65ac18de110aa137993b6d387c4234d321340d75350d1a0a07e3b4c1355b9e43f6df69143d09e9fd5f27b3911625e9604c3e118f82c6dfd99cf7c78f99dba0975d67f090c48aa4200dbb508d72d5d0e5474ec634cf7bf4fa634f5161edac6798d68486972d7400399cd41d24d043dc04b3c8cab11abcc15a7f88adf702a92bcde17c18e343546de4eea27fb99e31ffb98db47c45dc10382548b1c1fa096da9fae1d46abfa8e7f48bc3364d35cb8cee82261a604919d7206694043eebafef8020225df65a3a10bcfbf1721efe364f81631fd14e46e1e10c5bc589335e130a01dd309167390df41ffe0bb008029077bde3d5d69e35d550b7bad664d1d2c42eafcc7dddc733e5d310b6e0e17d35d821829b36e3fa026285a72251a0f0dc5a0769f960249e88effd506756de83747e35772ee1913f8b18b91102dba5f0e595119f5973cb241f47856f70bf5a48ac4a759a6d64d269d4c06b35fd94afeb55323b8eb03427a22cf2d26d32bad5d09d51d476e0989923ef4002ea5a24f10883fdfd6fedbe639d5ba91e6e03b8ab15cb0d4888becd5e5cbb10a109326d5c8800697b781ab5b1c9a2c7727dba76226b22e9434ed3fc", "0", "0", .Okay}, + {.Is_Square, "2922a476862dac1d6e5b47ef401ff17972389a36d9138bc4594cc88e25890bc76365289a73fd25383bf55b2d468de949cb178bbd5e38c76b93966c51b37f2ac27de61143c59132b8386f39b0e3ea3ef66d96c3636eb88b73f20454b11700c68821d07140a2b55122f808735d05afa92e1ae5b2199133d62ef7de337e1fa5535155e86db37084f6ea71e9c5dd058576df5179bfbbaee9c4227667c6179a8e268e19c7ac458a4c781e9811dddedc1646dadb66a08ed9962c08be6476f03599896bea28d9c8b58da5b33e42da009e5eba19b94912c793cb6152a3f8bc216abec9f7c3e6c45cda49f65928cdb7659d03c15aec3f9e1381ced7ca451a0de619cc70962c33e425649a4fece5b5dce90031a05f2a7c3cb99ae3e4657ce70408c6cfa8116e9310341d098480d5568c118cabc1cb5e610cc7115644831e7b0177b22bb55655b8a567d4dafe29349e167c8f1aaec8b8271817988aac632ec0afe528044ff3f417077daf90b034b2d4e69066db4e497fcc08fc6cb35f8b5e0a849ca889e5405f0971209ee582b13438c22259a165e8fcf052c256bd4d1b8469de81b0814df46cd59fb80a07f79df64efe10141e63be4235bfdd58c1518d184064a4f1fe03f57ff9568d800ccf2153ee51d64ad77daed6ddfcec0733825605e315820d23cb76b703e58124f8c8d990af288153d5f38611e9dbe2bc4e0b528bc0b12724d639c5", "0", "0", .Okay}, + {.Is_Square, "ec6c77f3e7038e5109dff6806f1185d9eeeaf944ea2a1330f553eeea760cbce7ee668c80891459a2a692932402b2d1be26981e9de7631af664ba1e52030432cb27597dd38c8e5b3cc95b7954ef1e5b586dddd43cf9cd4cbf48d4044e1e73b45bf28a1a3bbf20bd72d685db53609e2807e7adeae937f0edaf94be848ca4d9d7b560a21e3c27545596b6ea22d964a2334b203fe95539efa342c16bcf8d3e4a11e844bc102fc983dd63743f8bb3a84f5820fc705faaff209e9de2ab4732fc08e82d13b7831fd7d291657866ea034739b6d17e307ce2c95df0a4e657b35331e7868706f3f5e8ceb66e713669486dfaf99c6030174ea96271a9f452da6f0090813c07a6d7a31dbf57d8c654142d9a1820b17bfa20b389a773ee3f35642a6e7b299539f8e66daf159c8fd134edb855077b9b596dd80b4a99ca830e73e65f12ed6679aad1bbce65fa296b72bd24c98dc12d417079579a5e48219eab18cff4e3a6964ed5292da856c39eb87318f10cc29c0d6b2fbfb2e6ac9c298227f2c9e5aea288047fe84476f013991ccf1e04601995319616e8fee2e5f2e04fed62179f8ea61bbac5b8f1090b97f1b57d1cf4dbefcdd0b03b13892dbe5cdc5adedc5953edfe667b1ec4d7dacfe550d17c02d51db0b9eb5882ce49d9d5676791a99578206d3d6cdfe8a8a8fb43a053df7618fd0b3bdece58903b159804c1fa8a2106c993a37cb8da5e", "0", "0", .Okay}, + {.Is_Square, "a622662c0e8f94a44caed23c3c13c517200bbff11fc2efd980d55ab24abb8df7b294e9224656cd51adde99eaad51a9ca0b8351791768f665160a8f59eca10744f898f34481f4f86db231811adb417ff9c5fca3a7cd36c87b13958f7288bda64bd5c1ba6ffba525edd2ed6c15164a8376e3b46a3cd74310f0bd0c926a9e352207ccff7a149a4a256c84208666cc3f1b2d34bac0a77a821eb7c69587c329eefc4154ba30e56a182e98d4e85d03041680980a0b2fceadde753597b3f86874f6e045957ee9fde172e32899951c94c92aed3697b2eff573dcf6ea5d3ee662a02620cf47d7d83e3e216942af7b24ecee74ab47b9daaffbf0a6219adcdea0d72ff50290ed3f666af2248aba49d524d102feac28f50494812b9b7a07c29a84a5b9fa8c10bd673cb6e4c58fb0288865aae47c1e99192c66109177681662d4a3955c636cf39081433470d99ae32488cd8e620ed8905ae3678265336ffb3277198ea12b546c48c3ad9028fc483bd5938d71632437a0db8eb9e1f66c3a5dc2ff87b0931d3f550fda50c67a607713dfe6ac0f6ac8edea6ee8e8aa7c46e3b9fadf213db01f6f7e1965b7cca8233145ab943b72d466657a09839fb5000537731d277354ad1729338e67db0aec42b36a3cbd5c8ec4c8cd2fe80587d82fc5da954510452de40bc70c18d3cfe23610f3213e43bf663241dc2741ff225fb86db029978efde6baee1bc5", "0", "0", .Okay}, + {.Is_Square, "ece6116dcf17df756d17ce281832961ff0faa22cbdcf66ff23f79d3fb8c539d9e9e39b528cc2ad10e9f1b76f2a202eb333b90cccb90b86be994783f78db2a583466107999a1dd4bec9bdc9229b3046c34e04c5adb58594671b2c7857bafb9a483a0913a98a608c384573666c48dcbd89ef3b216da8de20de051d3e90c0549d1ee1432497f14308dcfead55ee46285dcb9dfc806b175eb100c28852f6587b20678963fa51dccef9ac3c84d078d8fec80d0da308be94a219f2bbc53f9fe6e5671ac7bdb9c21d5a90d07cfd8b278675a0fc419786836868dcc00fe1f8ce140774ea9ac90235d7f241e3d0c3c630a4f4a0a7bbacc6a2a5a341256669799d7dbe3b76c328f39808a22884c44a897084a7e38be32c07534814c4cdb34be0463c4340a775d1fff86415adc8a59583c22528232179892e84f0a5442beedb60a85c618e444912ff2aaebe234c8cd70e21ae665b0efcd93e41c47cd1c6e5de5f35c79d3991c7aa7eeb86ddee567c6e0ffb40853c549ff806dc26c81f1b06262fabd8843ea6e71d66438b8317e7b19f3e23e903d895d1c8207e1436bf5c74e35e5c5a86399974d1f3a73d806229f3ca11bf9e54c087e9c8ab8c8fd2ee3cc8670341f19bbe6629d9e640d0124315bce428b9b1215b22286ab779d7b809b1ba18b13ac128a7cbcaded33913398a38167f14c304c93bf0182786e67b7ec684f5e06c173800818e", "0", "0", .Okay}, + {.Is_Square, "a1c857bd48cee9eb7fa14d392a3767062cedd98e2a8701d05679b1ac22291d6d0c96c81535c2e553bd122eea6e8b9b244eb7aee86bc308d9814327fe33bb266ed5dc46b20a7c57bf2d2da6ab3df3cbec5f2b99f04429dded65a672d4c43f72526ae9e55803a2dcf2ebf951f93afb9f72f00514b4bb4e9c4c66525d71dfd8f846764b7bf87dbab88c9df178c3acd1f2e9834417ee04fbc045b8d6f9d22b8fa8f4ea5243869dad797254b0752cfe8dc48a42f52ff4b91d511f59a27110d27db2bd221d906d1150accccf0b9ffb7d9c39e861fe7686a220a9ef07ded1a5da4918b1aab68d5fac32dafaea6a50bbe4a4c4dafa4ab4d24ac7376ec9372248639939c7fd519991fea03ec9ce5726502719f71c1a35f204326c4c7112637b99d786c12b5784d2755043c491b9e077fe397eb5bde356811a0d0a0262538feccf24638a1fa7095d23a3ed705b041a1e3036ace7e30ac4be8ec917d8f149cac45fc605139e4822ff72b879abcda246319749cbda69f8162a5b9cf9edfecfc81718effdcc2195816b2508bb2df37675c6a08a122e2b44261f0b15ef0739c9cdf86063d155c7cc96b713dbd5ab1bd80a8a56cec7bd14babb2b5eb299848ef038c32f65175b8b0dfc39f36229f6c9e8730e640d276e53ad74e89bf754f54d40b741fdc77dd046ce1c50c2452e5a8eb15fd7a53de537c307da78b5a4faaa5afd54cf18c97f84fe", "0", "0", .Okay}, + {.Is_Square, "12157d52ee607dd082cd1120d3c15d4ba0a405746428a4f64cd86a0ac4226b08315ee9ff7902367db70bcfee3da6e66da59ee2313a81058411bcdc7f9989717c3d6889dee40feada7d611907cd7365ae635b613b8a59547c3a2a38775f73d03130b1992a71e519909a0cf606076056a0b679d5624e3476541b84275a0e15b1ecaf32f509f4dfe2385925f7c34a9192031147b03927c756c43f721e74f45477f2d785dd188e5b310f149a6a6687ff02af9dbeb87d5bd7001c5e06575d224bd563e0c765e6bde3b070adfb06960a1f57adbeb668d3c163b095e1be882a81229e39ddbe9a944abf979a782e614f8a3c27104a5e74df17998359927a5fbfbc35c813e5a6950850c12159bdd018be1aa455aeb9cdd0129baa44b90e6cf03e6f3987d1561a809bb72fc77b50ca362a10482bb3c2e3b52c728fc815625a6a8c3c3f6ad802d0c008a40bcd44dc31b57c4621ab5838e162dd01d46df30eb985881a18c4d59004b288e0650ac0cf27bc5498bde1593ac4b4435db4c1dab243405be8bdcd4302c4b761f0a11f037bd2d97577d8f1371f74923f2f1c17399e961ba1c9d1a438df215a01e9857dba66daf6f0bc421aa87833d61500a7da0e7dc9ca5e3f958f70c6181de5b2e36c85125d300ad1d13aaf776e88531763501a6b82b4b4f1bbc39894479cf75dfd1cb873b6dd05870f6f6759ba0d0ba7ab16b7d643ff3c29d9d41a", "0", "0", .Okay}, + {.Is_Square, "36b78613b432a35e42c0d0af492359e1fb57e12bd5f84e607c8ab7a4a7ff9a6325ec59d8da56024ed9c6e51e2767f7f3eb4ee101ac7de40e5b29f86cab56de06a0ade228dbaa2d691d7a6a91fe5760941c5a56cf0ef6f10eb8aaf04f937553ae5f4a9b760f0e44267682d9e8317f9a51465f27c569c32f9c71dde3d43ed00065515df0b4ea37a5b19293c564d7df6233ab366c20ac771e187d10f5f0a47474e525fbd3062c34db9f223d0be4c2197c22c2908ebcd08e20d121853d89b19f53143a824a3b7014187519802a47a0780b27d8ef5a473a980964198faf5d7f80c1ca764998869b92a4da206d4bc5edab5fca1c6d1dbe2a637688a63c1e4539952ea01a3a0bc85e36576b97b70ec38f690bba77b4dfae8048a0dec286ba040c709e7d0baaa455f4655c01a2cf54358076cbb75ef5ff0dfb1b6a0142caa5448a10ed1b467bfc90103745eeefff655d1765d9e65d25cad2b77abab11c8b3f6adb5301b6bb885f9a433b4a0ae53811979312e1944ebb7e13dc27ee4188cc76c9405ff690dd7a726a1d6e6532435248f5c9fcc5ed7d2fcf69c063dae158293ef372b17b9e47eb93b43870b3ad30fa36995ee6b016db1785025f016d5baf38b9a460fe677b45af316ab37539a9a12e1cd0411def28a47a7071f821d6e00a094c241e9487a8741cb767fb9f27a13603b34eac9845a86d058f662477d9c6af417d84360205d9", "0", "0", .Okay}, + {.Is_Square, "19effeaaed137989bf67da6ff3cc28f0bc8daf8b4bc5b00120c320e9a594fe7dc7bf80703d4fe7e25f71fc39f29b47b87465687373d38513574635bc63bb2203d99959a37c09b2ae47736831f8ef4bd7b001c315110b053dc10f3a8de0424588c6c97dec34e63049c7ee03aac89985ae96075c06a9edd55c7c6b24396fb7d6fa1f25b3163a5aa33b7b7bace51bf27bf2d72f2b855aef1f6130948e8b26dd98b2f132a73841e27b7c5ac22e765bfd10a8c52608f43cc67cd3a81f50905ae1be28b19d4d73eb7d4cd290629665df914a606357f17ce626693becc85ce2390901c6a29c6372f714c77ce16d334bae7e9e8a1fc330e123fd3710637e37774237fdad4873ec67faf660a9c201540b34f4c98675b47bb868a418671f60f3bb8eeadf1f159a3f8b6433bf79abf6a71fcfd22571084048d2d9fb7a74def5c8cad40f1634a3403a2062ebc18828f08b0e8b9bb0075c079c525762165686a569ecb3b83824f60e26b5f3358244d96bfa618e8dcffe26bb73f617c5736be11654edb309707cffa902e546fabb4ec79d1d9942351b3b20fc9a7ecae638a1c76258ab63a802d56babb5ac901746262448aba5e3e5ac8b01de17bbb6d94e935017550b8742ca488fefdd2dbea4ea820b52d83c1e84c8a91158d537ce2dda25d9f0a7e688c00e4b081a14656949fdcd18c618ddff9c27b7fead48a967851d33d6322833c9168266", "0", "0", .Okay}, + {.Is_Square, "957090822800f64729aa1574080f779e7b1a02d1e710d60fa281319afc19f030eea1041da5b615e1fc2d673531f24f17ee6d1f97d0eb5511e66b295f5d8899775fec22dca7b54dec2bea77d12ad8e215b3816ee596c72cb54b075b442ddc12d932b4ab1554737cc2a78723b9814fda0ba30b80157e6929366638b35acc6a5855eaf796cc2bb1bda22aa7a869ff235b8fc6d782b950a4805879edf70ffb1f91d256c4db8ce923082ceb30ecf89748917795cd5515c45619d8a43a91b515811ed3d7d8e702055aa27e0dfa4fced46f627de5d3d2e13746be0c5233f0bcffa5cbfbb5a6241290f6f491cd1ed42275170f5d716c90d1c88f384e6adc618b4f6c6a9378e6794c729bd6e4560932bc571ed533cc818d90b8ac5839963e387e214133ddcb1c19975be26d95ac5a1900df652a1f0e29a52c8f4d4f440fc02e6964b6dd0aa6f9f4048b78d0ebf0169c6ab182a343db6bc69d854b9d6124f7248321ffd77ed1e5eb376426d1b07039881fca9e3858d76768e558251fc898698db6ce47f2f4410b329e2ffe462fd09ef619fa8f0f1d675d2e83c74a278d79f53ebfd28bf4f75c1e5e0b32d92525d7aba061b408a3c36c78add3ee5dfa5eedc4e5205034bb6addb1ace530fcc2e56778c3d1daea69fbbc1adc4ca7a8ef77a8bf1ea96f90eee66723f8210c6fea816d124b7c1abc70d28d539a7fc56c1de337294d03c35db6f5", "0", "0", .Okay}, + {.Is_Square, "5e70f2c0bb02ad0007c7dbcc4dbbbd2b3667a4f4c95f924f3794cdd6086b9d893c2c3679668e2032234a9443f1c0efdde9055e2815682a57af6104a9b83c7db850013a8f9936c661a3b10a44f0b2fc6804404c56d6a42f2b527f6167f0af38f7b6a325318fb9eddb98d5abf490a4cc93ee4ce16a0ab53e76f42e97ebb8f2f051a4a8d4eacc0e9f0329cb753bbe2eb35d410b077dabfaad0e59397a6649a57f2a0bfd13f79f4342ce2045d7b02cc8374bcb6c820f7d4e51e5eb1c47fe18a492c698ca373a8c40f1ea61cbdf426535c61f0edee2e383411ebe13c8906950a5e45eea9eb8de1276d312aff648a3b3afd98282fbd49952143b48baab6502982b49d86c707ff8b3c86adcb34327e3c1c6d4d43ceabb39a2b5f1a2c578454b010193bd493aeebdf668cf9a7433bc6c1b28597a30aaf553065ac6692e639d5e7f353b4e7ed9273ab7610d8b1d934d1b9c7a5f1d7c21982421fd0bba442fbaa76bb8d83c08bb07d46dc0ff2827f4699dac8394df9702a457f1026de73f86d50e0ff024f2a5cdb9786f68558c01cf86f9fea26767e7cc11a2f3924c36461a139d6b7d1cf60b06a4c49260d4b73f1ce80771c5c34b7e62873ae2c6c821d71af8b06b35f6814572f65a9c67679a0b4f1bcec0294063c963e9c1f4b86a49d303eac76ece079ef7acb9302e17f4bc6d688703ad2e0e44224fe4384ffd9932fdfb8cc05df87db5", "0", "0", .Okay}, + {.Is_Square, "55c7ff5f4e7eb1d0ae6bfb4f0a54ef80d657a9915d8547580cb356d71c33ee41ab261417ef028f58f8467d1a981aff24097beea34caad62d8319595c534ab7e6c8cfa7fa74f37891254bb28261a2f65f5fa88e8172b32f303a8a574f04b7c2ef35398b6736921402857e54f485d56ee7d221a41dc6368d7b65c227c717dd6d70459aa815864d93956ebd7be7cca1b73c61c565b0d3d9cf93bff91f6bc7d9dcbf6cd1c133dd11c0ff1e3c68094b86bcb284aacda1585341c468ce61b9b96d88cd711b0f520dcdddc481170be0b8006433250484ebc92a7d9c6cf1a40643de21e11b7a8ca7550f5c0d83682e72f0eb5b0b00a043691385b1b91e4b7de4418b04c9623db028512801770110306919576a84d4c45db795edcd5a23cf6f3e130a829ce7ead06bb35b84ea1632875d7b512f920642038a33c079cc088e86707a631df1cbbe9ccce04c805de902267b9c2bc6ca8bef92880e987dd67cbb7dc94604954641af656a6948b769fefe61a6c65c155c7e8a0b372c70a8dc7d0eab828a3a53b8bc262b55dbef072e23c317f058ac1edea6433aeb58fee18d17a41055bb1299676bd1de15bcc46cff194303611dcbfcff82a8a43cd9e50aa7028c32c6c3b5efbf1319e55445da3a101ffb41a47045bc6033109db49c897c541f5093b14518a3617757915394c9be0d95ba9be1bc54950f5961469d7231bc13245cbc2f5aeb99f8", "0", "0", .Okay}, + {.Is_Square, "b7d7d755ed6d6c7409ed79b2f6c936056a0cb3114e686632dd9dfbc50d7d7c1b12a97f0281f30bc99b2f654ac336ef3af06589d9c805660032b00c5fac29efe771d75e648cd17d6c79f459b2b4a6d4ad8232c5cf90af4c8820d0e1e22df5cd5c34fa1ec1f7f84949d7e55825ee556e583dc23ac1cfddb2a041b7d9b6b3f8865def353feecbffe17ae07522e9dfd62849de4446ecdd493f3b9c5db4a144720323bb7f2d00733571721ff729ccfd8df354b6a3ba87527b799cee9291ca4a52c1fb90f1f28e31acc7e9d684a4aa6690531874720a693914bd814358080f31d257d877fa3f32f46ff4e812e3ff75632675ed85871e02f3f4de831fc929c10ba503f0310d1b8ee592396d668944ccb848584b40ba8ca977e3a715fbad0aa8b2159ac26cb6668a809d4eb1ef81c399009c2689003163559a123e4199bb679ed2e6d8de1541944d9bfa05d439fb2f3dda31dc7bb294b07d36f11df022af4a3285b9ee1774c2f8bd1eb4ef4071d6f87a6c22d98838b4f8e5a776c3b5dde617ec93c6a7b4d1509dcad6abcbaabce5d4e0ac903503acf83abe25bca71aaa86e660dedfb6d53dd4700a50923abe6acdffc0daea662e4525693e84b52c5eed17162c23237e17d8989b6c08947cd7b5d3d9bb9f12836d7566cea8bb9a9c41616821231d29e936adef7ff1ed5db0908559668befb908025a6d177820596b76163b60c580fdc423", "0", "0", .Okay}, + {.Is_Square, "cac14714803d4a9741b98fa24bc900218894e950f7d6ff2129c80791dda8efdc90ca7575b657f70ba4d70840dc6ee35594e9b241f9b5344bd705fca52d009071f9a07f856489830e8aba3fe333749cddeb3d06e996301c442b7b37b6b3eef57c230c7ed01918f6744c32ad7ba7176c6077a7edfe2325e32e4d75cc85a4bcdddc38080df4948417f2f9cb7818fc4de7d90a0177537a821100a42a6d8e740b4cd7f7407d39c22f05584fa293474c599018de2938cd5d166ba7c349a47e7e595b05e933a3f9dc089f3143bbba33909f25283dd52cc899ac5e194015e6aeb361a09b14d1d15d08db58ddfc1cbba18abc1957fdcc275d77d61483d99f195dda481b4d52d9063101648d0efeb79bb896590c8e51772c2ccb4453059f3fb95c5eaf4d815a4c797a540de0fcc6243261f85e3e4e9fbcd6536e35548d43b943b79a08b777187801111b4bdfdd60e996ed6e7f671f2c2dc956dc35f21fe7bc553e016b1a05e8a97288a03b4578148767fe1863f9a96567af01a3dd64a390585b766ed1dc4683b31fbadfe95ef568c5eb369736b71ae84f96d088f6d00a54b3b902d1775edaadb6fbed899f88d2309388fb9dc5a47d58184a6401ea09cd08a683825b7e084913be4416efe01809d350c2ae4466991ad9cffb04ff5146406fb918e8121767678d5831366a57dac65bf9f0e6fcdb79c3df01f34ed499d20e1b4800efe02325d3", "0", "0", .Okay}, + {.Is_Square, "327f14fef2236f276e94786ca7d2e7520c7fab6da29c43eaf8a7ad3c2659a78c75eeac55a9e5bb71e09d9eb78d11225d05178882383150eac32011f42c3ed3f258edbba6d86d3d0e8616384e1a5e4dd0f0ac3547e73bf8f03928bc468e1ba0567790f035f27a58c0ec011202de8e196f2f98142c31ebb566b4a6d915b78424fd8335ff9d569dedfe0be95eb53e0eeb49c5e7e988808f4d913f77f315b0f8a8ff80c4862e0b0d3e9ac5686cc99a0a429f8677d52a72b91d048229d0975c0aa82687a01ef5d6b299d428b7199b3168486a9f04f53bdc817709e8a2791ac52974fa204f81775137775dc97abc64f1c8270ef21a204bd093559277ae62788bb8e35e5c297e1b167a57a11634ac691285f7dd02aa9072cc7c7b091b9d807a8469207a51a1f5fc8e4080e21eb5fb6449c7a7961596c2840806771559b2dc91cfbae280fa5329efcd677a872f78d1153630e6a2cd4f0241f51ce66bc4e4812bdd85a337b0f86c4609c49c940b6643b19b14f8d94a7bfaea0a7d51c5027a69a776f0bec0e56ead85a30a135423dcad7bcb36652bf1d2a40af6d649755df5fd0ef1b11d5bb019f6183a8aacd7c115ac4a4108606bd3d5648ab0137351f1b6a967c500128c986171203348b70f12f7f0d49833fc62b4ea1e3cec356eeb9008581cd3c47c55ce78362aa3c4cffc35195df0ae8fc30851029c1d2d25a0f108780da0f7e9079d", "0", "0", .Okay}, + {.Is_Square, "42cee97231a718a983e1cc5b01393fc450f071df90777c7c36314f204873cc57f8153e49e73e350cadff0373fc6bbda1ee5f9b56b7f6e0db6fd8c730e02d0599f3aefe3f011039836b4a4724e28558eff94d808b7ad1411069dc7769f943bd336392cf6bc92fffdfda59db65bdab646314dacbbd8ad53e2a1cef6d955ac79d11476ff44828ca97f2d3c030643d36bfb41a638a3b06a0e73191f818861310515570cac7c5554fabdc1912a75db397fdf7ce49d27e1f01ef04ad3847ddbe10b1e4f397f2d5e971bdb5935710045154938680dc7ca4043434065f014be0ddd62c805adfae93141b33b4e730fab5f741502352b84535e2e8e7aede6d162519e0862288fb0d0f9016aa44d3305e9fcceaa0fcd870c33f14c2ee7a398fdfb7939f9cf8281c17401f3142a354514a2145631b89e83fc6627dccee36937aa185d9bfad94637b804235335171453fd167031a036b289cfc857cce8f944405cee5f7743faa2c4ba1a32eb9170bd9aa280318e0b2ca6962a86a0097c218538133c6602f8afb17c41470697ca122b649d14c94a86668e1db3636d031d02010e109805850ade716d1f3d061a9c780ca4f75d897540cd7f566cb633d5748deb73153f2b41e5a22a1cfdd4f86c4e2108bdae3635a4c560d974ccde7ca061cf80c8ac1f9b2d56cc8b189532a9329ad42c7fbc6c85afef04cea74539c4d0e2b02f35c1749a1da108e", "0", "0", .Okay}, + {.Is_Square, "36a6b34085aa60a958588f00b140a137eb20f007895ee1e72bd361f8e3758abcf992b9874c3939a07e72dfe21bb4e58132db4ee1f9754ea282ba26c7f2cd9984acf5b5a0352f59b1dc9e6240e09b5de8c3a6578e8ae02e2a050a4f60b6bca4f987e5c0fee3e02e88e8cdeb192dfda073a90d1564e7030132583b400c6c2da4b9ae89b2345b658b338be75b51f00bf2d768481902f50ac7ef671ba7c24f8d359fd581358c8163cc6927b4cf7219f3428edb22ac4da5ba40fd5752f8e0ece9093487280cba29a7e902bc3011c9749fde4c920ae1f090840afa093c07529598b7f0bb38dce6d9f43c7c670ee362d242445c699141baaef962a470f6726a1d7b19fc150a25d9a193b36239bcc216c91e1709713c5ba5e8f541791f1cfa104928f4ad3767b068b1ca3c13dca7767e27f7f1513aeb95ddee6a266df13ea59b0a2a1300f9ce305ccc98f6e1e7223dc8fbd1ded067403c3c78a4e437e607a9a4662088c5814a198c7f9525f03ae827046cb22cd9795557dc89b3ee5aca1b4e9b6bc23e7169945741482ce3314ba9103e5ce90500e95db05e83b7480ce5694338cf4d78d0c48c69765250ea91285a0930979c0cd39a29d270ad5272cb56eb783d9f04600bbe2cf92127f7876aff1db4829c4ed500934d335fbeb624b5bfce047fb25e3448de5da3cbfa1cab1005ad752dbf81d1d9257768b1d8452d324373ebe1202f02ee", "0", "0", .Okay}, + {.Is_Square, "3169f2d66844c185740fbf3b8870a63e99a900f1969dc0d17b9818c079bf94677235963f5ea38552e0a00021b4f0de7940238f32b046c3800f1f6bc17b724c9a4c621e56d0a092fdc034a16b115c076b07433f23ef78a45bbd0211325a537f182df4efa8c0d1c4b51b26625975bb3a461ed5bda696c35017d837df44a8c0236dad03d3a3e90c1c7cb07e4d4ad5af70782650201a686ce16410901c9f5f86eab655a3afd58296abde80b3aea58b019772e1954032586bd35ee097dd3bc549eb03ee21d4fa4bb65cd49c44c8fafd5bfcc23f014b1281cff6daad1eb9ca7e5bca7c1734a3ce0a35eb4c60d0fed2773208b284a2a9125568e1b09573850c6988082abdfb6aae8985a992b6f23e21f1b7d14e0540c98f077581d476fad17a2e9ed0005438d18c241b38c59cd20c6d82adcb81c39c271ca14710a458019ad4a064c465f2cb5d7df56a98f2e17c25b2bd57048ca3150e1f1a712437ea98a92d735d89d1605bee3f1cff123f2bdb25fec65a6312c02b743bbc69bf09e4fad946b9c40e3d362fb4638edf8ffb2a34dda31fc04ab4e6dee4ffb63dd2ab1a799362cee4f02a9b2e64a3e7785c77596312c13c2f0ff9a21fa5bc2828df97571f15612ad15a7553b7b4137c57fade05a022f3d573ea61d2d517e39da458ed5b968a399a7ab24b71175ea57c8cf7c9a8cc69caf8689b0f08d96296487484eef99b0dc10ca424f8", "0", "0", .Okay}, + {.Is_Square, "7d050a0633451f0380ce9477e9d7296a5801b0835b2f2b49e7fa4cf08ed44554a0045c15e42d34029ba692c3be97fe1a1d4d28047535bb943f01e2b48b7242d710ac96a65425d97aa7985768b39b3658114f362a50353864863cdfa167cdc9f3a068cde774ed6a17a18a16a069c5a76ba917304d027bf3fdf43f5fb426c29c047ea8e48aa69452cf84e11446a797d01fb0c620cb10048eb41cebf1e3ffc73625fe376bdac1f939f3dd03c24b60c4a35a55e92b388c09e78ceaa31574d4e07d0edc059a116026d662a0f649de791ad131b95d2d09b3bcb94128e67285b5ec4a935eb68675abb4830a30f331ee60f05bd7d53a9170dffa2c75df7f76844e69e09cc542cbba6dda9306c0391e8f2bad9410594b02ca236b0098a36664202610f09134123f117780a4cebeae336f89609e6852418ed7de0f69f66ed67f489ad8f79e0b2da4557e96ab6bcc94d81a299f05b04698c36211ec16c63ace26648ef8f5b460086e5d728d89140e140d1d93d8cb160c155f75cde09a3433e9cc582c3ccdf9f4dbbb3d6f1c387dd7d2a8b6ee62265d64453b09fb36b176e049aa723c27edf571c88c959da0198d6df42750626879b0cd2db03b74b4abf60400a0b35ec236cc2e20e0d59d3c59a8c9f53ab6e5429362e8388d0d9e2e166e67e764f54155d4cd972e435f6f44ed4fe05b2dbcf34d0a46c4c4bc9ac9a767665c5bc54b85e111a2", "0", "0", .Okay}, + {.Is_Square, "eeac58b594136f4c986d77b1afdd17f9c621282d02d4fc2dc5999afa3e7ec4433dd988d42dd92c5b0b71f1b9c52c3a27210bbf60ad8becc8a39d6e452893a0900b2fd3a1f071c91f92c201bfedfe008ff0db402e5e57af861efc33ac0d8452ec73ef9e5fd8f33ef59193582765171754c22abb8a2666da6284ab8ff4b2ff534a3b45cf031af8f0ca7fa0afadce70bccb0ad9a5a30825d5b248b42e1e5f096fbdcc0a4c549551c189eb04b01d88b4f37dd8b0c262de2787e798bfcd7c84046c1f91456a7b22ac19808dd91a5d6e949b31a0db4c3ec30c33bbbc9a5b000248edb268dd17c6dee9e8d19ae01319b9e8b7046b964e0bbae1fe71910e944464b06ac6803336230b3e1fb9fa95cdb38546d7c87a16b39c4c2edbf92f35a6abecabdfd3c9ac8556788b4ee016a327f6b9dfcff210b0f7cc55dd1385d452c5c8ce885adaa3152beb0870cce92c495e941c23ad078aabd22381b9503dabe71682ac3af1a4b912fb05b85548e2b7b62706efc11c8f2b38794628e928ba70e793cb904801efa12dbb91da90c1b97bf36e6be6a2431b6f731b06ae50992010c98b3f9a6f6a6d408c6808a129ccecb4c099091049508d8812df9eba6cfa40f389ba2cd33c06feb4bf1c72e3bff75c6f3ad0b77d9dd35bb82c1151f5859b211949dcc11a7bb423b336a9310978d7b88570d70476af43339985aff2ad2a412d9737c14be4e25a5c", "0", "0", .Okay}, + {.Is_Square, "910dcfb105bae462e0f81eaacd864f1d77cd8b0e05b3f6f7efa58a3729f53292d6473f4786e377393af2f45e478d419d8b199ab4cc82975e67d79051c383214d4cf5c31871e587c536ea9cb22cbd9ce0f2e8f36dd944b7dffd8fda3a85fd094823ea945a9d97abe8531be7fd8416c249b8b10eac81e4f0b1fa892133a63cae1ca38acb41849beaf6e9bafafc8760faddf46bcf4b4e47afd0b96d9f9cd14fa220bdd320257a3641e9b43a63aad4d5fbd1f113fe52f3ad4d0e4602a5e97c61b2268d2ef3de108bbcbb613115599eb48ff4e5f9cf542932380d9d3c5ca5ab88cb10cb4770a4cae94f9e022ef0aa58bdd1c9a93e4d8871aefca9d47f426745f729a0ebe46fadeaee7ac4ac86e8f0c16689471aaa2a671fd92f982db20c1a5585182c57b85bfad69540cd41f05cdce74327f90709f7debbe7031458c740eef6b159965e10562f4da4b34424c827ba345d4067745f4bef9690b9340df0cdb1e61793a5cbf9b0da0d16fede5ee8a60ae913b1fa49644d03fc1df3f05c012f368a24aba27a4152c4233d75334b0f86730fab7af6ebbcf8d2725c692ec76b7185acef3104082825978f2370106131467d6a6840dc3cdc00b3693607870ededd71871fa95b18e728de55cd784efca87807ec8ad36098f60bbd3a31125f9c54ea5a93a7806d76e99bce928e68ef82c303b6a7daab85ba100dbd5f9c1ff10986f767eb6e6f41", "0", "0", .Okay}, + {.Is_Square, "d618078e27b08a458b19fe4bdef243d6340388545143b57624c6170a25ebe9db3fb3ca7a32542f3e2ab61c79e89b444fb8eaa17d3e04fac48e5754cd5c8fa9658c490de04623b421aefd7f8070affe40987ab109cfaa1b9bdd73f0ed72de0b8585a16d77d43e8041cc2f568157a132f4524135fa2ca32414f68a96e53dcbdbc80ecff33c50d0eefd3cfffb2a642fe327c2cd94e5d71e4aa5677bd6d4dec90a9252bacbf7ee0a72f9af0e1494907d8486ee4d10d43787b1925cb65d536df591debb2d508a22546ef80ff1a9c8d01aa5ba5531fab4515bc68b7e59493124ffe0e95b55b7b269238e58a576d96a8b7009c3410037859733a82d38a69949c91a8da0b3d4010dcdd6ce057ec98d8791d0e0308405443ac77b9eed5d2d06d91fd3dd8d52a30082a8052b9ea0811f2caea88895390de7726559ed7fe30f59160dbf22a0e30767c5b0dbde413a5af2d820770f15007c63d21973f137f637aa2156c5e2dd26e59d1cb7f208ee73b5b6537bfac4e49bb933bdf374b7fbfca43892e35db179de876759c013c16a50b482cb4ac1290f59757b9827bb111dbca61d8897ba49a06fd9f7cfadeac5cb8734a1103288ef2adea1b88812d461781d0d578d3669422f03b450d48a1e50567991f41ce79739c24b81e3864c270d92591dac740a833dae03a3bd57a9106fbe5b400711e235496134cc74da054e4d88d8c6075d7aadd732", "0", "0", .Okay}, + {.Is_Square, "b44757eda6fe3077d654d1f7b16935248af8d3518160040d0b736872761c5dcf3171115058f11f2c00805033234c84f1b58d06302dde08a6569a0f590df9685a5eeff5ba4c2ed8686927e464296749017048e69dd27a265c148415152313165636a799f4c3f16374105671a280cba4ccfe618478d4a90e7c156a74fe1299e9ab05369da73ab8b27bfdfe187e08aacebe5299315d574bccca8e36869389433da35930a5be059f9762d544a48b819c24c68199c78c2dca302984323b7550a50326f198f69df8a6a030ab45a109ad4199b46944363f3fd183950fe600bbae57d4c8d5836041c41c089853a2d278f68556e86158a2bcb1ec1d8c047f4a58ce05d3fc51c6ed511b6306675f9f89c03e0b4978ddaa420e26b80acaa3eb96b0d8db1375a250e76a74e7588590d5840f77b7631295d78bd7d6fedab27d418bc56871af4cd617913aebcaf758ffa4e6a00f03b29e74de7174f3f3710c4660126a6b1701522b1cab57ad49eac9f5d67e4d5807fe31d1a46bfc1aa0bbbda9c6bec5e63603d1f3d816922f8f4633b82f7bc5a946082d7ab18a8ecd63567991254bd9372f1fa3133ff5cdf47929245b4de4830123d8f964d87a25e39afa4fd69a29e8da972624becc540545260bfc74dce8295aebba3e01c17665e90c5d4d9968003b9964b6574f2d64443f685a1dda1c306448606b40fccaccf544829581c43c9f356b602861", "0", "0", .Okay}, + {.Is_Square, "929adea6cf59b8bdb4b09d3e4fc99255dba6020a8fded0ef1b4663a28a4b8a71df9a3e99e743d5bc2910dcc652f0cdf3bafca6b4171e4b6cc23fe5a3a533be1d62ee2254bd3c5acd3be556b74d422721a538cb55b50a6fc5c622c65c5792eff0613b67800160855382674c415b4f0fad917a15dfb160700f45afc676641025daeccbd265c14e5d949039404189b4fb568331ba3ecea1895773c20f5552cef9b9db39ab20053460a81fdffbb5aa14ed69f23701f617d97f380365c42d9b3d112f01bcb58d651365606eaad357b52dcbd237793d4f3f84986b73c35a47015270661035db6568893ec406285038d175b3492d0b758d77d394613d7e751cc294b098a8f25734c15555822fa353ab6b5d99353d59141cc6ddec8d73b232d0b562f75a9b4cd20d0306d5bc6225b7023174cf6b4c4c51f2ae3458dafb965ce43af6c2910e37cc76bc77a29c8ddbe48fee5e62b805940807c4cc9c9c68ee7b91cd2a07308aa445912d7066c6aa9c42b6b79274d92d6a89ac00c4cd9a43b3844a8498513102d44c6918450ecc188bde96ef8bac0d3b25b189947a927cf5e597ba1faf4c0c4f6d12a23039cfda93184fa9061e416f8d7b24bd16c003a46dcf17d82fde6ce6f409e8bf85398e590b8340f5bfedf43f56e319f7f99bdaa6e3b58221e3cbfaa61657b03faa4a348e402b8126a0688827fb73db96cd51808145b375fc2e7fbf19", "0", "0", .Okay}, + {.Is_Square, "9f50244bf43dcfa4f8eeb497f0ff225f6e0f73c079094e4ba02f5cb68522004e939b72c3919334f96ebe1ec3abcc412d7f08b0e49f1f76db16a5f5e184c7173ba05fe8bd5119ec228fc5cb3294d4dcc4da83a028855d8476ec87e89c45136834e19aa4368b182c80757d0018e6d3f006e71d03bc9464bcc72b74e1ed7ad88a7c4ec7e0ceee7db9f14b7574b7d984c0cc49c1126b206cf3770e3d22ef6aca8b9d0971bda5c11752f1616e96b22850553e3a1f232ac8fdf8d21777e6bb1418651de5d44a559914ba1aff4b0033ca19554089c0cf7afe492dc4cdf5787441940d5bb7d3079cc0be0a90af8040903387c1a1a24a70e4e49bda301d5ee8192a4b98b4f96a7e623b9686459044f83631aaacf01084f4940da5a76e1ece462057fb36b03bb1b47e029c3069b93448ec709192663d0271d41cf69324605545c9a46c47aadf2117d5babc974efb93200c2377ba55316aef569369dd7bbed994356c2753b9c92102e1e2a79b8e72d86584e383fb32dfb8be3c4ba270330d060c2d2dde54fa0d42d5fad9842e903638beca6aaafbb008d07270d343870f44e4321fed1602b0de20fe4ee0f1027595b3309486e57eb27c770f78825291871faa2884df9a7b3d5e1de4f95dffc3f735a3ca41ffd2dd2fb746502d4d61bf6d31dc06e92dad63351cd4439d04532f2e9dbe548b7d88227495c0873382867b92fa8b552eb550700f", "0", "0", .Okay}, + {.Is_Square, "9b035c77f7ddd69575979830ca3529d12305398b55a80d46220e2374d22755fab98b880963561e5d885f402614f2d3792f9bf5dd5a9cb98acdbc98548ace5f3c57d48adc1734cff79b40dbd8045717ba3a9a98618a1912f27f3bd4b413aa4d718ef2ff34080e56dc16ab440a4c2c21e7d41c201a0d1020f9cd9d6cc672807aacb16910ec178ceae392ac1ee23b58fcfd15a81ef606231d628124811c3cef892ebb420681fb601d0a46aaf8e2bd462a447c801534b70f30a806ebf53b783db605aad92f3d427331b7101b3771228370dc5eb9baefb0d04e577bd56c15a47e16b980020bd963a6cc24359da0cf9dfd176452f2bb4c4c709b7f2d92e43953b12426c52282c9e2d346d08b5c02a46e3891f8746ce83f029ae63da0a2ea75de62b2747d83ef967f97b9ff4c4c460badef1be06c37457eb2d898f90a6b4aaf562e1afa5898ab3928c43cd177b2d4a86493f03d7115b73a853deb675e38d8091cb1b28af5fc96241dd8a111fed9c4ac5fd9464882687091b40f6d39ce69b1c88d40e27cc8f284256f08338c68ddd053d68afc4433d24e0d6c6dfa66f343f0bf2cc065fb7644a96798792783fe1b40a0475ca7fb329bfeaa30807ae75463adb55a46db940907c643af95ee9843418de3b9b6beecb798891077626e8e67ef8850c1c7c96c474deb53d0440e34e7198ce73e78059a91d55823c105f0d9db2560ee37ef5706", "0", "0", .Okay}, + {.Is_Square, "24adff5a22d0f4bf51e415bbc8540aee67e992744731486f2817077e59db1ce2ffe112e3b4210be89c0760cbee85852825a905370c1425f5b1d8e7ea796bd7ed6df83c68914f52b6c657207ddb720de916984d6d97554b6a635d31a54f184d11d1078df80a11064e0f5a4517a89774bfdfd65f22a46380cd9e89a6325786cb64e176faadab8fe47534e2d560c192caec05141ed13c38acf4f9d806ef3b286f66cd41767a442068d9ede9489739f9a11943a6eab827bf40651278f9f691a29e8188d798d975b1b8b4be3d7753682dd1d51e8cc0e32e4fca0d558a8a4019c63eb63205af828fb71db9c79667a4fa312ffe3bd85bb759f4c05212f145187ac7c419dfb6f527486e4a1f85c80e5e5ef78ed007749a39fd2ecd80c2986642301dd7cfb1404c9347fd09bcca33e7bd350b8af7d1022a091b01b8ead08054fae3c8972066ad7d7a3c0e10f3992f7dd6006a1fe3342d261ca5a6c29333c43f171bbd98cf52dee0bf651e772ab56b6cd62e5e2f4758e63ff28842b137cb3c750e5e4a222774279db74e9cf468ba61de59ef2a832b9478fc95ae03cc835fc0fb67814308d4a2371b43c9286095781b5634c5f6a4cdea41c341e95900fb3cb7f05988eab45c811b5bf4a369eb63ef934f632354b9f0c9ecff0423a669f49df3bd011e9c021b4f9c3cb4764b340ce9e5c9be8c9f06f626480176bfc0202fc9d2b57b9c62eb80", "0", "0", .Okay}, + {.Is_Square, "bd89c621d754a6bd3247a07944a58e116e5ea8e2cafdac2063dd0a69069dd69597a610532aa7ee4190c8ef70d5ec15fc83b84bd2017784f15b3099364e312ac1a2c469404112697d3989c0048453a7313dbf6349072312ac67d03653a88759a82e5d27e003226a2c37c64e08c76752245a1906750e500a1da29d67942601587f9783e83581ab45c8496de9cdd9941f6143e2294541053fe1297d12fc7c972e3eb0a438a02984bbb82712c9dbee4a7577747e96a58e625afc139a6b2287266e4c0dc500134ca930454fc3ed8058f302a1ead3f61c61a564a83f2a691142bfbe728f06b1594f2ea0fe67f430ccde006494e7d97e6831d457893787bf51c85e8b485bfa9267ea2b370be9e720aca7787877a2785188375c1be34b17b524cedeb876f81bd9ec1c842cfa775c194674f08dfe51cbde5b7812b727186f0c5099c5670122f1e032b17f0d936326d4640ae887583e946e29ba0810480e654dd98220fae1349b6d3b0514bc7fb64aaec7d48a809ab8aed7a2744b009bd8d4ca0a9756716c090298c07e40dc0aef62c4ec49499293e67cf03a3623e0d9511a28104e99bbe18bd0d49454291aa2f5403b1ebd0d906beac12eacda5cc2685ce02fef539d531bc5abd37c928fa84cd5e7a280dc498a6a12a7f16e6044ff2c40a167dae1881db97e0bf085d933f7d6f0aa6be2a4791634adac48bc0918428983dac3ba74713641", "0", "0", .Okay}, + {.Is_Square, "d90bd406137b9ea4006e0e59026530bd402e0b13a71736c0e10cb1a64aec1d13059e1050da8567ac7f17678cb043991e317c2908dfbec7792fd59e8dbb2474848c2c3572a7b0ebc623866d2e156baf1a3aa63438c7cfd3e524e1f1baecac12fff44c8a8184fe38942f2131010008f4d4a62c1ec445387178cf083f5761fcdbc35d375ebed1e4e0fa832d06a23321927d594807b43fd469d8bc00edabc675beb0222630ad94f93afcd94a36d2c3cf6b1548930b1b11f433dd9bdb2fdc6b1f098a1b8770d162847c52054dae94f7c8aef9458d114b60a7ff6ca1980b461e1aa711b3f6b3c935df8619ed0d72c010cd77211238b729568619a70d5216c15ff8611e9ce8c31dc85c9e11419746afa68a82af25f02c87076d060549119604720e2db6c1ea477940c0d5e89fa2831be63f8d50c0e47d06415e3a6804c79ab9d73dd7037649bacf84af1923d717182f6832598ba14f024cdc2cf7caccc0859ea4fc508536d6a8f97d1749378e27aeda4a7bf6925184bfbbf63973404714f675126d815189c7dd54839515586ad2d66dd630947883b25e65b6942d0b42fbd325ae7d6455793140eebf3eaf2a241807c7995378db863108b3138b50a1a68d8e56d64bfe5a1603ad5cd101936ee3e26edc6c1a58b1b8fdb2519dec01beda2986b7d0a6e258249c142a7139d9ec17476d865efabef9f9f779c2772a41fc72434034fb99deed", "0", "0", .Okay}, + {.Is_Square, "5fce2cc0c083bd4da269e10720f9241c770b74d3500e270a190f684b131efdf359f979b022cea6383c6259e35f634b778df2446afbf5fe85154c024e9769d9288cd249b1c3456bd2a9886ad219f394a4440d16ab6c73f101c4eb8cd0403b937c9aec169e3c8d06fb5df8fa14795696dd5eabb400200a7ec5938563e21c50e941500a4833d8be2de6a8c45902a90a84a3e87a2d42dfc8f52b640ee0b312423ad33f6f8d30202d77dd28f01b7681013cbe995562378718b6924745dfd9d57391518ddd3fef4bf06ec1f7586781541aab16fe02738c5f2ada257fcd1659c724876e4af8d76defc051ae32977e79008919efa61a660df8234c6ba0b69ecdc7d47560f50692395a5e2d7a5c92494aacb56b809f4d66bb59c02958b9c6c373020f3f9e4defe36a3945834e71d78a22ffdf6d97998af4144e261a2fedaf9c16d832c2a3a62629b966274f0279dd3e8077b351829c307b11a030a813b1ee6835333c5099ffbf1d2606b70a88f1622ebdb54907c9d4bedd2b40e587cf1d946ba8287fa60caead4f612d60a23185d7af59b1d06671a8ea0771164b4fe8fc045c264bc404bc52944cb568585c32a4326d65dc411d1cb778fc905068e1f1569367199e6a25cf866cb1ec303d358f01d9f0b38a56cffc7c568701b14dcf70a6cd629da0aded8fef4acda68421e269125ff50a5f652e2337e7a6f4eaed6af886a78c8bd94362de", "0", "0", .Okay}, + {.Is_Square, "42766c6e3aa7eb1b16ddd2fec7d87eddf09c61d1fc7a2e72e6aeeafdc8e3aab867b88c71c885b3c2fa826607fc30d88063044593d030c8d284ae3691d49b15ea1044e0dc4229c4c7ebff559145f466ae69399b92790eb193ea3665b94c0e3aab464736cebbf92a625e4eac67291c1236f2ef0f8b4ba894cb3084a47de90eb1ae67ecd1c2712b5ac66170bc18361cc52f49501a2b1127444d37ad359b556a3fe7f84848f2beb10fada756a5f4adc84090ca48bb0c3e7eb297921e0b3015441aea8c658569a4ea706f369c83838940ffff6809df955a5862d8e1552773091eaa1847d43397af35a95f2485c3e01f760e7b4a8582c17e327aa6c87360c2564502860a83cc95796699e17fc1dba9622332c9b8314ca6c4672d99c59ed16527a413b3f5b91dc0a49f5ef9d1276fdb4cba0e0b1f64b2f93db3b12ff1015dd8e7d2d851b55ee14b143acf99b0093fe76df79b7654f22be0db1c49e38c55fdf7472edfd6eb1c65ee0ece6c7467b759d5c7baa0fe35d77868751bec1ad3d75b9cbb09ded9b2eab185c99790f270e5790bf44528f13b9d9320346831479ee1e019c558ccef4cc5b785e695d93e1a26dd30efe86056987a877999853c1cec5e443e4af8f4c4bb311d6bc376ed77a985cc679d176e0ad45bdecf70d4db72fb0269c16d1822c3b1a735c2f622702e0a03abe32409a338df312ce286caab1453802a6c02ec2a76", "0", "0", .Okay}, + {.Is_Square, "77984bbb6355cf485230636bb3b27f424c3d4b2fd6ccb5091bb41c5fb0e2b0c79d6b9c5172dd3e78edfcd0eb84582d8dae38bda0b5874cfcd1ba558dbb81b6697b0c8959b3aafea46ee2fc6ef261a50359817d94a33f15877872bef542d5b117e4a6a2e5a70543e7f6bed5d1b52c155f4b8fc1235540d9a245818905dc586112d7aaba89f651438a3c2b1ea25f436574b8f0e4a331ef3375930ac7ee3582559850a29413ad9eff040672578cfb18f6209f04d0ef9ec85121e01e6f3ffe68e2f45be7f23906e86af0a89ff16c67420f1d729b3475362888431a2616b8d0f8a9cca451529cd9772eebbea03750a35a29d54f94e845e12ae829a47329f92f6dff6a2326c75d44171c58f7f1be93ff38b6da2a1c54c38d965fada7f88ff18fee2755b74c02467937060ab2cddc920e88f97ff303dee291e2149f2ea8654fbd3cb507f51ebda8fa28e6ddb55d199f2ab4a1ed65b1e7897611e753e1ac0b2e4a431570820e05b83b4cd9e7bb62702130f57540f1df1748185643a605c00ca67864dfc99691190ee39136c881f81908e816f394e317320b86d17ed278896bb7351cd9e8e4f1a5833e07df4b594c928ad10b51f6a2d812a1c4e9af31be0ee654c597e6125bc4fec1a227af757ac6ed77e47c0c10af8f3a6b9d034c2dc0bf9e94de2aff24f5283d023516e07aa2d23ed5a5687db445a052cd60fc9d76162a84105bccbabd", "0", "0", .Okay}, + {.Div, "-5f405f1e935ca582a578c30979b370dff6e192ce309e207dc08fa63dac190c60fafef5bf85817e217d147eaa16f3b7d2405a2c506bccb3bb19abff7f18e2354f6cab275975c78dc6bbc2b6acd26041ca2915b4b541a9415db91accb7c4e157177a6b531fa7a6271bea7eea416420d8be257f74eeb94f7b14492afc99f709e5927bf02119c92accc62e2586a6f568a4adcf050c66294480a2a9be31bfe39f23fc50442dfacea1a0992b74b577e45ca896286f311b501ed010df0336a9e342d7561c22eda692255255d9441e0a8c038d3064a5e41107cd2f6d4651e7cae9fc350cc4fbeb1b8912bbe2e68719dff3c5898fb5f589be1d9e92212baaa31caf58d203f9e8bad88f1228a1e96b5f3f8d1640daf70339bad86de63b81ce61ed44ef038a9e59a5b675f32f21c7be2cf82f177934a0a5a437826c75538e616e0f3816e52f070ba4cf4f472de2246332b27c6c55850a7db2706130a2dbd4fb1ea99f2b8062956054312696805234b310eb594d6c94297de1c2333bb246abfb6083dc64d10c0d6f4ebd24fec69d4697433e7c98524fe4539eccfbf1ee7ccd40f5889472cc6e2b3946df31053dbf9706f84b547fba9a85fcde387473c21af395497647e447a50636243bc4c926c8fee130a6c29876d325675547714d372c6af71db019da036258472fc1e76d778f193d6647544f107a8b082a9332b93b22ca7e6d6c8637ec71", "-51d23e7e9405dfbb3102273dce98cf26fa09e94fba8dcf8bf3c52934341435fad1f7bcabc1c8f68c2529848cacd4b56a83b473563805ae579e07e8f3f4067bda5b36c3d8170867de097e24bc5cc76c245519ec8586f92eda440c537b51a93b0cbc81afce292de50c4e22c3f8500f0cfc8fcaf380db166c370482feb5b115aabd9179b28a7ed6cb5dd106e9ab7afc3f2ff25289c3aefe75727d908c9f2827e5125416c9828d23151ff5708f10dd20fe3727f785806a72736d5ea3ba9339d375cb21ba00eb17529b1085203c4093deeb4ce65326cc5795cfb12bdda8699e69fad13387ded9362adef0021863abe6cc4c3f4eebbe6ab65b117e72984427fccfe1698aee871d71daecd4cbd4ff37cac47127c54bab9db135632566fdc808e1573dcdbd2195dfbc1e498cd474a70e89aadf367282ec", "12a051cfd79ea76c3ce1a9e2ad3c21ea1a463e5837b2e4d73479608f6d087d89fd6ddd1d3148173d061343c105838922f85b01db5555b826bb013b13a847dfa41a9a499075ab54a092737b3101708fe890c1f5c795a811ffbf041ea72c47e83d6a0aa7d93b95bb284e82ad3657eace6d20ff93bd4dbcd8c0282b6b74adfb4c17862c3b39cac82918cb9076f7e0508a3931af6f64324f320f2afb7e50da88cc08b7c60dba6d017fd01e5df05e7f2a89320b4704dc637aa8b93832d762a2e9e9bb9ec8835035e6194ac3cd1500eef", .Okay}, + {.Div, "-35ce4b916d9fb7f05b0c25194796fc41df4ddc795dbb56dafd6104bbc0fa6a3735a4e4fea7f8395ed736e2790db30e19b3249df24853d7b34968bcd56d4257a578bd78aa33f66a5db4d2bf79567907e2b860c504a24cb727bedcab36020dc42b1b9878e2ce053bd9f2b9aef193552852722d98d21951cee79c325ee648f903f764148dcd69b2d6b3b11bc59fd96402eaeb3c8e688834845ecc4b5e609df93fe9adcbe03a20b4709ae1ad5154a8a187950795924059c83f44ba95031e36e80b90b5f7081ba46b6c56a663b832ca7fa3d9dc570fce34913ed4f4ccb0a32aa423a1deec45ebf069b26f35d5dbf8b8443a39d4f56f6c8b44167e686115fdb05332236feb48927bc84f746d5ef5b5798916fb09ad3b81289a7c6eae878405eb54a0ebd0932b4438d68ac79ce19db556d3ff3da836df9b804418318143911908cea1ea48cab6b04df50f8e99e6ea55278ba6b1e4c1b99876ac76b4c108f3cee398c8bc372481a8e272e731058bda729d76df46b75264b12fdd4dff10c013dabf12ef3b30b4db44976c32110beeba858484151042470af3468ad6f30593efe2b1b3d7870b98950f9cb6ab906bb1e20938c0e4c9c6c17542fa03c894a581d7bae22d29d228e677d1610ce978a904c4725c0b50bfa015c8c5fcd12530c970c7ad192276b726d79e9dc93eb2b431a08210ca1b778b42c2397c81343cf96f6933bc04de9424", "149c7e499859270e0514a9e5857219c277e7e6f1f15313507d1a65adb259ed5541f199a859f3d9fe800c6fa60391c918e62377763bbccd67aadca1a48f23ec148e1663694e4ea0f0d5ac0069ca60b5b2c6e41975755b3970951624e9317c6e263980f531bdf0bdfbf658c7b7997e3bc942689bc8cd15cbd9cb28444cfea02163032ee0a5f4c9c8ba575dcdc9f5b4e462dd4a00f2fe38c9f808c29c6cd76d5d6f2f618004790f008587ceb908b7ae26d514f4b95db8f16f7c49196d35e4c48600acbcf534bb8fa78609194b5eb37f3a519e9b808add98f7ff632f345d5784faf76517b1045f221b40f41944c8e32c6bcc8de8da1f21d16c6f5961e8d647f26c3888d057d6fc367900027199ad972d68e04b4bf1111ae3d1dca3e9d2adc6924644c84161a9a6a84e6572765671924c3f68258c892", "-29c49d8424d0b6818d1d35d793e4de240b037345b96e8264ccc6f78537af2bd299e31411563a1b6013544060b8e83a88a3be68d17925c9d8f177208c4d2933d39182e874f81e64a6094fc4b1ed12c54b3f263b894459c9525a49caf7ac313a61ddc521d59da4334bf366681e5ac80e7532db590fecfe6fb1c6d9637241fa215d69e82b37992d9062abbe4ae8007cb76b49517bb97096ad3d70935a65a9d21d2f61b04b066a89a2672b195767c77b903d4b29c4f82697184e5af185e6fe63686e43e12cff4172a27f089a200264", .Okay}, + {.Div, "-5837e08343b1f00ec9df355a8b6b5ffc6e9cccc51f8c5829fd2799c41dddb4031db983b3bb5fba257bef9e4ea484a22a1b94517e0311815b4ff275e61e963cc9b657d11652e0cff1b0c8b567561a3805f7ee0e59f97d58ed128779028a1fc7323b071ec052073a4a057132b49f65bf23521a6a228540349b0604452c8801ab67fd1005074900c7cda9df7f3b586eb8958a204b76846c0d2584a40c37a13c060b88e6f9db2fc186e2243f8a4d559e079acd716e493735c6c791c557410280991f45bcde5b5a0d1a0a31df045b176140ebfb40081b518484e1b04ae4d74745130e17b7256258d2741f1927f346690864ba15833912ab557c1c943ce54d74e3c15b8f21734238410816f7177a3df2be5039a40afa664bf23599a6f51f89526117a278faa233b198da4e1b30557c829a2b7432ddfc001b0c21f3ac34b5a34bf5f91b9345cb88f6ee0b9ac33d80cc70ee46e48065b706782fb679dd29e8c2bd33d375cdb9eabd979e8e44b9c85217c88eb226c130117fec278ea6c68d04cff070d7f9abc7facc3549fa04a4747f34753458d6c34bef5aa920eccb7fc197bef10d056131327cb002473708f3b5a7afd468bd66ad1444f449c254d86e9cef71c88fc1d38472db2ae321570b5ea6d9d7dd08da40abaddd0166d23fb32ed71985a6ff064f2e0e79c526d49e2aa12e32b6fb5afbbdbbdd969933fe8e6ced9ed098fe61b810", "1c46738ad921910efc095ac206dd2e821961d0cf1ecab885ebea603835ab326456f06af9f7d5cca4c36dbc8fca11a1f1ad83a9bb916e16ebcd5b96dcc0c6398f0e4034b37c71672971993da199f99f000df1c32046c4e068901ab5849469b4691fbdabe0a917470925f9cea9ae0569804c4d0607c7ae65d8a3b417b7681e812680891794136ffdfff734034575d2b895593076c06b5fda26c886002bbb578951853a3a75f6e62272ab665a77c6ee800ec220c4dc77e0a698630fdaadc15cb241c26da0e31e5aba80a3810c4516d43dfcd3b7238e210175cf2e4c7a28302337e2016a57dc63633c451aee813bcf91efa52eccd7e2ea8cc28e749e090a6e8b4b4d406bbae69d7896e25d2c2a4e27463eb4135b643d1fc266b8a7b2caadc2b08efab7d10aaa37308d7672de7c41ad51445d84a43ce", "-31eb77e9b8882103b5edcfd6365691b2c3662e3dc9900b6d021a9d7ae7de1046e776544b90383ad8f669553f7127335ba7e6af35c002b8779c6d1839ec2280307727e4bfc2af01ff9bf16aa5342a07aa54c6c8c48e605784d2cb809b4d84d315ab365eb9e2056cc418b7028ca1ae70aeb429f3b129c760709e0e03ee7360c99b0214f4c04a520a57d937334323304ed0dd3eec2fb4c1062b730d2705f309a8b39e32e0e7147aa270e986372da066f3b67adaf17724bdad4eab2e974e8a31d57f4ea3cef0ee11b2f4a5418f3b70", .Okay}, + {.Div, "-14e6f53dc52873bf5c7515b4677d721ba9f91fe0e3afd5e38bbd93a96f8d63393a98dc2b13f679bed006cba7360d06460e78781b062c92818fab994e11fe9b3d7744d8e2b2f5cc86b5ee07e68d45f75bd1789371dadf2183ef9b0186915cc5cdc348d5383e18cab62d2f600838e0270c9727b01d4ee12f42254546e40176e613d5a11ea980619384afcdf67b167e73e1390f0fda4ca958e184b0c8fbe5115ba3568f09fa2761dda5d665eb85018093f3776f8804c9c9a45ee62279a45c327cb1f5d0d3693ba707c3f8a5fd8b725514b3df48e02f5936fb098957e1726c1f6ed64746f2864fd83ff6f2871e40e035f3af1cf2630f90a4152b9190870bf28e92d15205422c53526fee75ebbbda7bb7dda3b7e75690857cabefbeb0aea3192aa145c16aeeda664f9a8e3973c53651f3b7e67a73a6db0e0e39eaa895e9a750ca162d8b510ce0c1f0401f220c4f0647432048814fe8741a6bbca65bda1dc434a3882c26d0301ba37ea6b84e163dc09bc87bc28acd4eb05021e5a766c7e26661b62c91823d9abbe8d3a3ae8bdbc989ddc17f919f8357e78f67b9c82521178eb988bcf338715e616f14adc94cbcc4624a864108b1b212318569d2b2ddc72dbc9733fa9704e6483240b8cfbac8189b1443b17ca66266b4b199161c0374f774b1de9c0d6b74ef6364c7aa8248e0b1e10bf2e9baa66863de495ff0abac6eaa8ee4c6a652e5", "10eff5c12f0e938894088abf0ec62aa750542139abbc9db960acf14a0aeb7d2e04aeeaf7d5f1204aae711c712f8107166e06cf1192c6c02978f84d16569d4c7cac6ad0960e3a4169aa9ec0ed67ac36223d33fef57eb40cf7c0a809b78f9dc9d8bf7b21eef9d431b986899aa4a7ce74fd2555e2d95b57607ae508ae59fca591c2a56178d381ac397c869aa26d535c95311d904154556ad4af2bee77eb85ca5bd83a542a02a29add51cb71b6e66f29461e8001108512008655425f209aa453fa6f5e885bc8c41f2851b3a0ab041a08613d9413349afb4503e4b8c9c910c70bf8268cd58ea2c9e8f36f6204158c258ce9a22508ca49cf230bf6ce8294568e47046d42ccc4480a322e11abe2b825fea6454e01763832bdeac6610c66e92073b407c9270d0cb090d769962dbec02bb07efb6e46808a2", "-13bed37e2a2ce3431e60ed5eb5cfbb586e1bf0af8e13329d0fe930a07fba23a0af94b4c304121f9fa83356606d6917fca7250ff7c33d37c4df30081b2ee291e6bd7f6a4bddf5a66327a0e05204d70818b372f9eb21895adeaa5d61a2cd965d58f9bb839e5127dedc5bbee325b79c775b31fd2382a1982136117b17e219fea0c3bd894d45ac7c77167d8adaff70bd0faf404bd0f2f8ab06a6a947eb0cc4b66d75450c4664c7eebebe01a5bd903b815c6b5412a9a53bc2e1315a864fae3a2f2d6a8ee600035cfaab932ee8e88a91", .Okay}, + {.Div, "-8165b06cf3eec2117660e81fc4c88c6d41a5dd955bbbbe209dce96628585f9b3a035329db9229c3ffc3d548e1f8bd4cd786862a27e99bfaf0757076a0855e3af025858c8319839b49443118034420940fdedeae244b2f1afca1c006c18124d2c5999f6b4b5e8fe5e4e443234d3b1a007c7c37506ba33bd30faaa35fdd8a7f074dc424f63343beab49db487e273f048e3f04801bb6a124c24fa2a1fe19546539fffa51604507af7e4584b4e1cdb5a984998c7f539e862bb4a692854fa8d741b62adaa9a05b7d86bb037274b27797019c106760174373c3788ae490c0955a28ebdc0a611476e406aad072c3501081543c4f0534fa83469c2b1dd31fa14a81cffab0afe3d82226e9cbdf4832c00245eee64767946fd47539920ade433145860f1168785fc03f13214c3b9b295361dfce10833f5d04070e0743092df3c1a497445940dc42a8045904ca88a4a82a13e65e64251493175600219523194395584df4280d70e15a1a686220c7a4108082e02a109d1afae68f3d0b44bcf6578040dd35197990adfce17ac7b0a106dc0784cc457f427e2016d531a90c36444b6d5dac6abadc5c4e7c38c86e41a9b05569942b820ac2cacfef95711620601308b25132b3e0e00f85d4488236d1c2eb64b412343ba2d8f8b29890adcab28c881a9c7cbcfec4bb2aee8cde2828aa812ef1bfa3d45eb5eb5096091a8bcdd5a74b43df66b83696e", "1b12c81516e2be2577b4129a58a0beb3e30d6f7c4076f8fdaf267efe3426ee6fbebb2a83db0a32386a90555f893a31dcf45dc4a06af2627a9dcde03cc593e842ef1b66dac4049c1c5101b08f367aca0c77aa27e3fcde13d05d22146c438408ad1ec93fa680a805baff7860a575f41be38720a45edb9f12e902a5e9eb547dd06758649bb01a8c43bbd230bc3b303536c3793a7145582216bcbcd8ed0f01bf9e13d27f714a24124eb8b0b27d9f9fba9a4621fcdd1deca0cf3482a1a49fbeac68e3e2a132c5c6d51abc5013ce04981f8c2634487a7a71607b92c825399359339dd27597ae4da6c1d383b0d367ccadd5c05d019886bee1ccd9100c9d964f3b188e8be3085072f73a31c7119dc041abcd5f696c6c2a2e546f7779e0c91f0b7bcd08780ad7c9eaaba1b6848b43a08618bccf3ae93d64c", "-4c78d7cfe62aa3602d6862a4ca5c93a541eccce1f08d57c61b051c2f9fb3ac6f56174da871d8e630f21d4b35cf155b36571f05e4168c77d0949f4d708d68d2cb5cc0cd280a777635b620ccc8c3a4559614212dcf5f3b56729ddfd94da48addf0208c955ebb51ad262eeb3283db997dc96fb8fe9fc6d6be92e9f89b48946248097bda5a29cd5685d0cb69132d9571b3e652738158f7562bf934c17101c2ae476bc4ca4e1f838b0027f6a52cbab8adf9c2df861330136f69b9e360ea0984ae516dce3292b346287c3af35c1cc14a", .Okay}, + {.Div, "ed3c12b5956d249ce55d022b7a357c193cac054ba243118b42260878076d44b5481f0ca2f3deb7b636f9790933f5d336d2307d399addf9c701e5dc80db661ca1b7dc59be211fda94de7618e6edceba56c93954db40eac548931b5093c5812011c7ceedd190648ad6d2ae9e829f16adf7fc39c289e877b898b77141f179d8bb93fb9238bfafc2eaaf7e975400fa96c3b882e384325459791053daadd5ebc98fc7750feccac59d7e59261545265a92c4af2dac1632071277e466cc72351ef264208904b85255aa1eb76366f688b5fea91ed8db5f94ea8cde4347c978693017f73cdae9f89c16824dd290ed1d9a35166b936ee6fb28828b65f15f7b9b8cfedf87306776f8b115552b489145a62e6029eb31cc43608bf3072a046fa9d7f4f13ab377a175eba427e7a0e41561a29ed022e014136495ffd026e1b5b377de126dca76a32d7b0e43177f765609beda6d28d726c38d3f8280dff0277bae96d02b709d13c2da497a1e06f34c521667f70e162d9fd0cd63f5ee67a24b62718da4c1764753ab9fffd65942140e13e82aadeceba236459aead97459f4c01dfcee4deed4408e2c8e765b73b6c53fd5b1bc62d0bc7ab03c508a7c9f03dc88686fe262cf438652b03068af52601f8ebd0788e60402b2aa89ce90d10000ff3f7ba012b3e0495130ca09e0c6c80cafdd775016dd4fee712963363a890ddf16b237a9ae9d609d28a06f", "-13cde3f0eefb8596db290115fe8015d4c2fc9d934a88a2a1f2fdf687f31c5f7d53557057d38a8570fa66b477b322b67f916f71cd59bda4b03925ab30284694d1b5a4c06f78e7c9debf4b87c03f0e4a412d92a8a8ae298f1aa43e504b7537e5fa106a4392b915509f62c6a82a544a89f7be87cc710564952f448b44c83b1ac3a2807b064e53102e86d3995ee8ea169b7d7eb18d9ac296f84f60f6c24fc2b101d0bbf3f038b9f2d0312ef90590c4eb731657016de156e7d385b873cb178de22b3a94091205388a242dc4abf96166ca7ba4574df6d7881cfb3f19ecb21d21ac35677d5bd9c2d986937969532c4c7f72f7914c1d2bf432de8163b3ae6622a8bb64132ff0e24b09b0252c3b3bb9600b15893ce3c5ae5e04f076c2e0c426295b9745f99c7eeb65f0258cc41b734ba8ef9d17448b7c09", "-bfa9de2130c808d4abe6405c94edee475507430e3baf4286ad875e88e499933ed03f016853004a66db8d177fb3b32f377544ed51191e7bbc2a6fd4d754d217fbebeda4c7db936ded658e05e7e9bafc49175d3dadb5a6492e3267991f92a05f99bb7c4954fddc07b96fe9c68d9674c57b780031401b57bc76aba0446f887285614b9f3b0bbcd60eb51c5b02cc103da8cbd91cafc49f5eb6016d29e4a218e3bdb66c5d84f7dcd92937ea49a68fd977e4929c37f96db21469db4d8b8ef4de6b27d80b6715d2380333eb2e2fccc2df8", .Okay}, + {.Div, "-f7f4e8ca2154e47c9935cb121333946374a50b5ec72b532c0f53415a573cc62bab614af9dd8a0f92fa07bbfd10df04d0a7b3f779455456764e25b8cca8f2aade46e2bf3f0968e191ea9baf42214a81c01eabeaa925aa6684585d5d212664afa34f383e86e6a190f7289765ad3fdadeae393618c03a030e3499e48b81a661521a38d20067bda39f2ba190bdf3ece203973d1b06747508b9b3b5ccedb160350c04271b6a87a56ddccc9607c75c3ac300c0f501fcff1de04fcaf6a9dadb096cad9c852b00d360e033cfcff9fd3e34059d2a4f9599d80d8c2c8484c684ee6b76ce275515980d08f7b3ae2993886369d20d19b9fabfc48bda8582236e6bdd53849a43943bd9907ae1f37e67c384d53ae7fb80b4362364d53c6359beb1e28b2b0f2f1af70a647b1b811f8d3c721ea826b65aa83a152fc05bd8bd313d413ca6b8a9f8e743aa10d9d840ddeb46538be5192932f7bc355e66ed2e0b175411ef6729beab1dd5420ba22a24e06e80d168c42d7569a42f8628ddf21c99bc97632710aac0dbae2bf47ceb992641cbf83ab7507e2b0a649c328cd56aa9f4d346d508d469042f22e79643717494fbe0ef52287f0f6f04e5d44660f378b98c632d93960a0b355edb0bef7ef63eef524e9263f7ea61af3cb3cec27627ec57f01b7af144b174aee4afb1be25af87a48ec565755618ed324e3b8011c4218cad8a6aaa386d5fb04471df", "-15d5226909a6e475e8b0f14f4a3dc12f56791fb56db1ab95324b49de95a96048d4fae52cee11f642e33cfb3634dc59740e2968b5dce20cca3ca3aed5c42d93048334c7e9c2d00d1c27cb5890aef9ceb63d2a4c70aca30d56bb70bcef2e1d7cd1e84692f0525325776205734ed45816d4bbee9f82a4636d0e9d6ba31c3f7cc1dcf6cc7a49a321995e3ec58770d7fd7421befdccbc1f60c628345f5c007c4cbeb89523eab772b79c14fe893a3a07e261dc6aa0703c08b0495f6e0c08a9361d87355ed30d199de3db24ec66c245ae1e6dd804d5866970e2a48d593a8624ba17aa77e878f2fd456d82ebdaa8b0d37393c93133cc4dde93b440cf3a6d60e7e16cac5be7265d903fb6f8f8bfe91c50a4935c0510ba07abaead982da2abbd739a6e8eb0c78028923816ce00d76711e72fe68024bb8e827", "b5b715d66baf37f7cee64f5a59e96912e63c13b7f92addb9fbb3977829d41fbfb7cb1d57c4241b840da8f168216fcc1bb89b2f737085bc070c3ed2ea07c179ac425d8ccb91b4ffdb568b0b097f7dfc63d4973a3d5bcbf109480d6bb1c3feb232acfb09aad4f0be38274f3b9ea8537d60547df08ba0a0101b33aba2a36920fa141dace44694472545175e016798cb2c456e8f02ec0f85dd165ce04b45267245c03efad3e635dfbebb64528b977ef39496419057f7954093733fb31f5a0f3adc437844691c44a9533f1650ff2dc3", .Okay}, + {.Div, "-2eb20b9f70e7ec975a12691844ca60d0ea7b85c0e0a7d5b48ef72dc7cf20241d49f30956235b2b1bc5d7992d19d48f2ace6aac17d4b5132861994d9b7b1a3a8d17fb653240e3339a149a87703400d24d39e01d5d5a13eaad43faaeb3e1c1e9f855ddf7d8904ee05598e1228cbb20bf5d6ba3e4acdc31ab8828d20650d473f4760e38047c56a03d0f7190344b8db7dbcc37b66da20e2894a825386ee1931363a1b815734e1913aedc8118b7e514a21d2d3e64fd381f149d36ac1d0b20ac5cb2c650cb9f7ed412537c89340cf70e58238a335916752a820086b9ad9be2ca4b2179a594e86305ef8751d3cd59edcc576c5c898a2c4a7c93f08718df762ce46ecd4e5cb3c8b720db06e1a70db8b49a6a8aa69bf2d0ef6c99cb82344fb1fc8f4dc8f7b80654f7eb2a838f3942d703510a7f1f2aa48d1fe28d4fbb5d1478aef635ddf9220d56d0794a62f687131c4a8059291101b810ba0bcc1d1ed8c2d901f6422a4f6a1de30cb2f6886a362cd13bb70e834a56f2dfcdf3f4b1da653a0e786489e9a0cb842dc8f580d2cda5ea28fe36591301333337226955b915837b7c7e49511db2d2160d1c2eee22b8b3ceac4076e44caed278a26e439e449893d076aa6e0476734dccb3468a4f3996dc0693f4d0c88d6675485ce058d9a505e3213ddbcb0f3cbe48ce6fdea155eb71f942e3dafe7189a32eec12a425885079d7fad4e7f5bd189e", "b0c228ebab99a458dbcfee31e291df7991a15227183780e89377811fb3f78ac884ae1b0fddec6b541b76730a1654af83b57f9f07ea9522e21a1b78caea9bfcc5cc5305aa91a2a13254d8a4de6bdd557416041cdb839d6cf28bd15aa96dae6d5128d487887caff21fa48969dde13d6f8ba4c3a4d2388f04e3a8b1cc4266b505dd351af159dcd236e6900ab7fa0ddf16b2b37a0cbcd6311efdb1d1e09882e99739ca6f00a28a6bfe58ffe25184e934f14e01664205f89ffb1b8abe9e98a771e3ba3a8afdc03f5fd933294ea9604f7f18b8b46d53dd64860ca0957fae904989041182c005b734acbb2c39081d7c4f27af3ace2ab80a2af7f45380779dfaa6ac5d4ffc90bfa8069d5451c1d9add17b3d5cb04ef85029ebb48f1b88932bcde19d1d2b0524912ec252f69996e8b29e4868cb50abe05b", "-43a11856a4b2f6e74488ded01841e261dc34b8d53dd0df3c3ba1ae9725f3d6637dfcc2f0a171f906b00a0d2464660a289fd50d0ed2ac916d7a0d085007b02023a5640d5d9a2ced94a387e5a322583a027ed19ac2d341f37901834b36adaf3ee07656de1e4139f981fde22f03fbbff571120728de1df61ec411f1ef51d30298fd845013bec9779d7d82c7b24479b431860f375cf618f1d1d2c080ab67c83ed3e739a0c04097eaad6b07e29d8c7179c0ab5f99562ad6e05c6d8b2864a5787841d8796c48caa8c5f537f8d651dc9c", .Okay}, + {.Div, "48e5580a631e2cdb66a4abb952702084ff869f62a34696322d485ea0c86209b503661efdd50a4bef18125d11391b1739f3b7869faeb74880237aff98029d7f04fcaaf22e2c9ec20f7b93cc7dcff74c6c13973ebe34cef70a40cada3609a6cb5e123f21681deb26da78de123aac41dd0676720772c74ac1d94616e018a143b6addb2b27aed994a6f0bcedc1749b1530c810c0be3ec4f089abfab41dce11f9b4f50548f2fcd30c43c3e39a971006e1a3359aad65ed657daa991e185d151b72de40640f312e3dad8acef5e0100f9d88d1d42e4040f3d1cd657e87428cd13237bb49b07aead9b8f55b6a31e2c8cba82ee4f65197ae4490f520404e319589afa87abda0817b54f2e9363e65b027532947dcde13dc3fd2c8c9d103ff21219bee6c1a7b582a245888487368df033949062320f5d24085bf76595940fec8c30a59956a88319088e3c82499c0d679aac5b97f61c4a5a8634cfc2efa5df4d621e8a25f7c115b2bc07457888c627ec5870a1b9b4f7441fdc12fd6a7745de8e5c0d9adafe642ded87548b1087d85ff487bd410165b9d8e89c72e2a53f49af5071856d5243d8953bec78c24d6d08e8bc550421c27599de735218355294d6a98bf0d591cca29dc47e4dcd4f5e389b6e0d3dc009d6f8439631b203289d44d8a39a4dc03046b3158d41e2c89357ffaa04a5f756a6d592e2f368ceaef977c8573652cc6ed9b5089ed", "-2eb33cb4c5c95610a5de342637a33b9b044c5298dad3d3f33218d0f4115d6dd56051e7e85ed799bd7725009e63872e666c234c36b624cb46eae50a4b67c58e729defdacbd928881eb99c81de4f5f6dcf399a6a4bd922eec17f8c96ab7e60efca128bbbc2743dbdd2b2aa79f5942687a40c4b6938b0bf4901942e9e1388a6709e8c3a2eedcca9356cf05078167bcb7c645a86bf5596cd83c031c8c89e16123a24329c926bfc96da86ac82f8271f93e8b10dc5fb7548f875875e6599e116332a2abbeb83b7056cbe67f837dc02be9296f0639b4bb0a805b2a6f7c6b694ff73708c55449adfa01266b38e14883e6d1d720d51576dd44fae5d80aa59d87cd5e91dde89e31f57633eb8572a5a5d0ec74080fad600ff646e22db88a99b5087e994ce9b8ef94dba25f01daa6c336a59964755cbd6ccce", "-18f9969cf6d86f38700833320ef0fa126133e892e78281c22bbcbe60432a9b3534dbd77bf82437887d819844d8b04cc58a21fe6bae52223edf471c884dfbda0739dbcd581b3e68d0d7862f45263cb64a79eaf4c8ea6fc458fdf931f45cf4878429fbf8d4a623bafd602c84e242058be923b839f81113a702d859e2fead8b576599d7c64c3825e913737ba5da352ef9ca8443bd63b5b25a675fc4909c1ff5130b66e7132fe02b83dbfb58eb5b15d53e49a56a2c840cb3d93aaf8a6b7363a48239dae9e0b696c6a926608945a811f", .Okay}, + {.Div, "861af0873cf289eb1de0ca8c4c38acb9d7612ab67b36431572ad7019a9c9061e336a5420722309b7ec266f34d20639fb3cbf4cfd5fe9e744a46954b2c26d320f876091b41d5c3d45fa40d9ca34d9f596bf679232972e9947bf855322cf82ff51923dd52e0ebe389f29279eeeb91a7aa6cfa4718d6d3dbb294fdf85c354d2aa3a0546b8fb0b6de0b6856be272ef64aaae146178765a0097fd3d725daed9dfb6df8ff2111ca27c5aaa583ff51cd05c20b84cef3a1a8fc3d74b293509b8132eeb43b2a0c8e24ad16cce7d9af521c66be16063851337a0186ca5d9a5a582f8f9cdc93c803d5345369fa84a495b9115a80a011e99386081738eec4743c208d807f702c07a5a6d93d536e6484b703def4b6f4a9f5a7448988aaf4ff7e6b6a4d29a4605ca4308b3f53954e1b100a5a0c6cf6f218e103b617068b81fbfb6aa11f58d75c80a0129cda03f65e8dd7353d51873c9e73a7017b37e72cd2c886d5729d85b0911688683ff4ed1e4abfeeca59452b664838e6efeabfe0da1265f74c330e87e9070418eb44ca555ee748e78b5b58e2f4a746c39b06c3f577ca695575e74aab96e283d2a07d18340824ac4b6955df5be8a1eff9992a038f226b9e3ecdbbd922463e04988bd8128300636fc016d6c560892eee09c9e349fabe2a04f2bbe8839f08a6755c1f81b1d576b2f0a66068d5d08cf649c3e3d35c61a31256f07376db3861653", "-a8e357b2df8403c522745aae242ffe9f0c90b59f98b38d85853daee218eb30c46673714ecf0c86e5d0fbcb854abf988ab13e0e0092ae461aee1412bfae0cc6fa7b362cba4ccffbce99bbd76e949ae6550ebb4d632d90f07bfbf197d156d9d5d00743a90973e3667c102e5e44058318d620e6b68e89831cfbf16cf74543dc2d09d300d847b6a9a19280e7182b7076cb6fe301de330478ce287e8871ad553362966ce300d3191ea8aa526b62e0322a404ffffda63148b98ab42e5264d3dc95fca58fd7bed58753ec3ac8e96270f5771ddc3471293bb063abf224af127ca545ce77f2a7f8c8330de199fda29fc7573fc75fbf06b22f4392e81f925853befe83faa46e822ddbe2abdec2a549b2894a4228f17bc205512d15776c0c255552eead84fda99f82a6dd7ce69f2759b37d632690708ae6a6", "-cb46bbb05d20204c3fdaafe2e1aa8716fb197d07929b01f08c6e4543dc9c7223cfef374015abf3de950adfac3119a5eee23559363e8d175b385b410874ddd1152e434f78b081db7cbfc73ec396399d53a9e7c445709da7b6f6e4a0593b51ed6a3ffe5d8ac7e249af01a8d94bcab4d36dd7d395483cb73d3814c050ba67968460837ed728443b685158ef88a55a50ee19eb54b82a72af044a7adba8027328d5f08f04b5a6789ff7d1a6cb6bce791f02e28b0969354f3c6398a873b748e85bcf3f29d0474b4aa42797bb92d227d2", .Okay}, + {.Div, "7b8151bcd1fa5d97476fd7d66d297879a45154b26e17ebff8643baf33ff1f802e91864cd41c66a77a29729fc2ffd34e5c3ab20872a20b5e472fed78ad7899c22b5e41d63e6377d865eb17aa3045b468f38538d9fd1704f7e0b5053e97f7140b017b7ffcca7353b71167365dd7854c7c9a6f378622f6aa6ba181fdb5171886ca17137d4690dbd8842f624e03968b5ca348a87ef938619389442888dd2875f403a4c010a100bf96c7c2ea149d853322c31da9472bbf881eaf1f255f95152a84edda5bbdea03226e17e4a9578bea434601bd1307afe70bec949a32cdc567ae23b8cfdcaf6644d89ec1cfaa86031c389f03114cc2b7173651349c058dc25e23f4689d80b218d59dba701cb4699df91b6215d0f6c8e2403bd71c723aceeb5a09895740bd00a24d8b258c7b100c74b80afa5813f0e68a682e0c2689255bf0248cc9d24e9135fe43d31b3a1befac04f04f6921ffd46760700234495888a77bee9f55a48fbf1576835ee7230946227fc5c69c732f0550419ff2ef9c05cd4ae803e3a8ae3d68e36f78cfa4fc8b09e654b669697afb2253fd3a10525621c7c5ccb75dfc7ee5389b265138ff1deaefc8ceda74e002716df1faecbd1b0eb08ba9b282935b529d6e766470a305c2fb33380f6411162fcb3a73e1b39a5f202f5bb614ae04dcf49dcc4f1432530d53b634919413cb4a1e70da5b93ffb39e66380c4d83dcd4b903d", "2d93da8136c659c1e5398810fd846f48af630e7cb2d4aa5f7521e7de7ddcf0f38d82ba972e1e492efcde16aac2375b00ee292186590e9cb4d6bf2f1693e7892067b05959e42608aa4af270ff38842e49f130ece5de9bed6272cffcba995f4608696b520cfb5627c1e2730f3fc47c39bc860753ec2d8c81155783460a4975e758f5b1e399c5f0a8a814dc747bab2b9d10e5a5042f17f2e04ebfa8d021ae27e86c3dd42427884850517dbd37c540b3ae54fe96d3acbb81592b3da92621c3d5de29e96a689e5e34bda90f95d27e5a62b7e3b67f388dbbe2b203c9a3dcfc7ad6d095a5f3f86c58aa7e08c8cb8673289c20fdc4787f831d078e46a52f0af65b12b0b0ae5faae676743b7bd13a3c5e5838b23c2a36b6b6a6fd5de3733156ad9023cfa1ed348eadda8e80dd043474ebda57bed140452", "2b5b428e25541e313639b5844893b767cac79fa7cd1bf27432feb2f9e5a702df01d276494064915b713b06dfcb3e29fdc9520f9971054de6034ad9cf36aab555b7c840eb7cb493622352b8205343aa7ecc6c54b7c35ba4b983e7a261f6af04c1e7a26dcb7f150cab5afe3b2620aff5e985f2e414c26eb3b648fdc4f41272e1ac42841c3c2707995b6f8f97a18a093d207df2241c1fd6e9fa0aa4265a5856eca7b03445845d08d9a855300d5dde65cb2bb292f9cc03c6c7c76612357f2c63f36a10205bb17dc0705ddcb4a8a9aaa2", .Okay}, + {.Div, "-3ffc5387f4023e950cc56aad6aaf94140de1f7a68d6c4f14a9f930092e6a20c5d42b103856d9b4fb7bd26c15862e944e7c4132c89ddc81b83eb421f78d3565ff02dd88ed9728ce45089ad9880d6245b425b25ce94587b573a48185f8d864b12b9e80aa5152c399448c27f6a9d21fe2b76d994d1b00bbed0a2a32294ead195fff0c09b849afc353e0b7cd46519584372c09d1cb4caadd5265ad469a445b724e9f064f39891e5b99ad77db0e8562827e0fbfebcbdd5dca7d27e0c8d0a085d69f28e3ce263d160491c43353d58f4d519b88483eb4de1d5084114b9d8547f08f43a8581362ac7a3b3a57b6c538aebad1967ddd3a6a3b105ad3b7ccf4fd99073a58171fdc65a15a30a5baf3d22460c936404b1a0452c29583f15805d00e522c85032767747a2fd9daef15c40d306be56a5222112c86f96ba284cc9ce1d426ae2d879ff564df7c7caa8b33e52630eecca894f0af5ac1538c8a3c65d5802f8428b20d8d306f10b2218d75022e35ac913aa63b783491d5f041d44f8b59e23b6e753216d9e3faf413aaaa908163e66c39badee9926e4ee74f1f408be963635c5cf9df4a9ef119734cc6fff1abefe6d900bd8f2166e09f543d3bde538a87d86d350fb3e7d759241951bb20c4e6019e25f1caf4c140676bcd5e85330809fc3a643671457d6c2504908297cbec9da0d1f04098d95c0d4bdd8fef14d24461f7cea9ff5fa18c3e", "-166b67b5602ed5a9a926643487042952e0e3f8186443ac5eb54ff718a7d2bca010814ecb0ef224744821993e29ba6b91e4d8e368dbbea178a87970454b020dcdae7fa2784f3a3f079d23ef1e4c8f856115849086b9f88c8d1e5cd62805d194b496e90af3feefb71521a140da8d7338516ad6e33fce7af9016c3132b78fcd699dddbf8af423b9326788686bf6bcf14a1fe4f3afca07bc0e38d92b6bef76cbab408389d5d10456b6cb31d38bc874bda94333f41dd2b73c76707d1c9f98836bc60f96cd8f770e76e28533df9437d4ac9458c1a480763044a56b1a6e4ae3290e5bf44dbafb01d4219e35129ad5d4bbf9ed17a07d9751ef666e0f722534a010d669664af5343bd079307b6ee19b2c86850a7574a6e334d63f500452ee119d5af2bc166a74497def4d691b1294c1c05bb7664f5db8c86", "2daa079dad7c5e8a224b27b98be4ebcb419b1186d8d3509db48a6513ca634aad41dcddf0b8284a6dfbf521e6cc6e8cd02b84d57bef8346bb9999662d1c021b1a142eda876f0e62d71c2bb45c422df362b8eb4199fce1331c3cfc1b90fd9941f31bfcddb8a3c944ab066b4f07ed898ea172587a637235f6080df4de2a6557f3203d49e55124a2a0e34220c4c577ebc6032a2c7af527eee276aae086a2bd33888fe407890b8149086a51f0b512f42420b357085105e5008160900dee5305a09339ffd9f110543461d6ab7994b1f0", .Okay}, + {.Div, "-1646a54f32a0cd31cb8ed73e681fe2f6beb3007141f8e47cc3bef5c7b375eec69e65eae7001c949cd6a7da9a336c2f39889088397fa3865f2cf866b0afdfaf7d8f28780988b586c89fe7fba074146027087e4d49ffa2d1a6aa9f968a72409099d6ed5b2713048aac7e2015bc63f1b8f26b72d77483aae8b3e84357d303f8c739cf71a75c1ae8acd0c8271c3e7ea2460e7b53999c962724141e595d4515059d32f3f1ef9fb0d531b5129ac560cb32fd70cb996859a47447b78db464f2df5c00eeebb3c4770ad297f567e23075232caaadada0e7e76729757e452cf7adab8b60527e3690b09eb162619d97394c939d44e3d86fab7402f28648a57e3a31f4034eca734ff35391a103d887cd4a2f663af6c1c350301281bdc6757bd2641ed66141a01662d88cf51f6f853d711eb474a5c3fa86f75d619b72c4a91dfbde966d3279d10e506212ae91bde2ffaeffda45ef042f99698e8a0544a6c2d5a35de3f39ea7f8810dd5621f8e9dae18dd1c5a3f793d2d513cd1291fd5674080bf0c4e604425498dbb7b5d680c2f7d433ee6b13ecdecf0c99cf2c285f759da024982b4f9b64917f5671c39fd23ea0f70d7415d116905c39d1d161635f4e1157a1b5c48560d6394a2def6f5219f0f6d859e4c4e512c94f545d058e9cf0495a8092ed6e4a5ba7281c941eabe6ab3d33dc485792f6d2822a4d06db1296eb95c2c708a6dd1a42ecefe", "17f3532a22291e662c9afad415fc51a71f740a83551108c88c4fca54581c4f422b6a60514893380acead4192e295bd9a88b58671ac4e3c1d2216902c54ac08ff2c114259e2ff688650f1004e908693bf11883b584fe642cbe0ddf06d1b05a6da48ed7701f53866726f8f377573da213641db0952a38a8fe78c884ac58b855f42b556bbe2dde60bbcf1bfccac9d0abc263e378d72a164b1bee4523988f736584c5ef06ac3c15562ac8924273761dd0637202eb259a06169a8c7603c811ac53b64498714636188a47390ccce6aee5e32388014f9126fe0494e285b41dbad01d8f0133cfbca9f81f708bb8f3f18e3869b09a6262bb1d0643272d294b088a291d270096e94a5eae0fa41471b24d0936a74a9c4311cdbe48ec84fa84f52fa602c72ab43040f2c3d0ef04a999a4204791c52ba119aaf5", "-ee19f84cca92ca42214f436ed7d6c4b64fe211e1f3a47e294ba525c8fbe3b017445c23171ddf16c892c04adbf87d766f5583cc5d0691ad55994c36b666855b3f47cf4b1ec26ba26b80d53bafd5711b072da8c91c70d66feda9fa947fbb68fa7deb33a1627c5498811eb40714ae18f58b7ea5c6374ca86a27672d72f35ed855b5ffb0b51e6111a49c108f8f8461dad3f986b35e184595f846359c1eb11483f253ad5cdbab85cc204144c808f18ac5aee22c00b8b5ab9299fa2bbc1945d61097e4234bc55c08fac345f72bfec48", .Okay}, + {.Div, "278c8e5c147022ba62b829f0b073eadc27185e48ba2d64d1f59afb88b0bbf66b4424915bd9123baae674ddd1305c38d732ca54879b9ac8e43d9e8c27fda7cb9f8cbcba58584e67d3f38bf6e117fc93f3ab4ca84324bed3ece6f9830209f2865e4afca7b975bec9f69be68e3e4e006363dcf1a9be64699df2f73a933a62fd9c680488c1882155e49b047c3ab9fae2954557e689c2003686584d36babc41ecf47e5275be0711dfad1870fa2ea45de744142f1c8a8badbd98bb4cf1ec64b3b85d0ce42b49ffc0917f218a0eac4f8fc3fd4211b4a582258451b4ab2105a820b3ad8882af45308092ff2678163ed8bb76be01a796687c7c7e9f4b4ada6cd5a9d83c783cfbceb702ba3b0a2b0c4351835e69cb2693415080b81a2bfdc5ac967818bc2b3b07f61bf99f403b622ea64bd7e733e103d2d755032f92960ae4e00bed2c2eb23fc9d96ccdd9af800dbdd21fef5fb3fdd47a25b4d68ba93b0b35e206f4e101eac372509a32f7abaa1f551e48af5e318db446c313c8f4b65e7eaa708f616f045cc8bc8a6f1159037a33036a2d55bccf6ff544494509f0b802c4c8f3db6071933d7a5f371bd54ecf7518b37b04e62de8b64db109153ad0caccb72d0da96415cbffefb0dccd1a30ab30c4c17bb9022303a268092dce5be041a8cb8c77f5ef5fbd2d618660a40aa0084f18e292477e4dc030f2f322089ba67017c1c85ce2c3013788", "5eb366d3668d90d28c3fbe652313ec982d7bfaf851e4068fd422354785d24c8d218a8775b4040f39cc40f1e97c8ec0a86f0b0e25d03b10e6cbf49342c21c15111f3245f6c6d271d9a0ce361bbe1955debda6d25350aabeba14c4c1da1ed99fcb3f045b9b4848f7c3e3f88b15bae743c27f90edf721c29813a944b7d834dabee3c8a4f98f09ad4ce800447196977a3f01a5b3fc331945776ed3f65af9e1fe653a374bdefedf8d3bd5d84c25f14d64fe8d8dca0d58271a3d0c49bf42430053472d327b5be7aec08dce45fe4476dc5b40aa2599d7ec344e2c82b1ef8c1aa55672971d2a09e81e7c9bec5928fa826f3570122779b777c033600b18cc3e02167d8fb276d09bbefc244572980be15c9b7a079734a8e1101e31269e51e04edc30e27f204dd4fa89e78a672aa938e7e3cb0ebdcbb351b5", "6ae9376a8d16a3000b40677a48b9c4087f4e93c838f22bb53f93e00ca66c475cff6e196a440e6c748ae5ca0eae25713ed015b91c0392d5c147794336fffbbe129bdf0d063497818f8e7498d60027873cd414de75f68f4683f3137542c4fab4ab2705a2aa35b40c3809f30d4d3ddcc5c84b17a00be940eedcf5480cbd73e746e084311ffe184f9db35f3cedc035c9bc21a489421f52d3c874180fa6f774131ddc39ca02d62984d61ef5bdfff9a9ca3f5d36ee9dd3a0f9c774f10416bb3c472d5b33740efef161177e57dc8d8453", .Okay}, + {.Div, "-44088194452a28ca8bbabf31f87af539c2dbc1e96dd8ff6b768296ca9fb3b6299784bf26802427e1321547713e8be9c5db1559e59956ebaf7414e7cb6165dc33df5adb418b8ba976e71cf855121ab8be1ed43b42eb361d3de3e95f209a97a3d2027599b369f3e440419a0e628ba92334e8680ac4bf035e870f77b517d85d98b20efc4277c7746d40a87899b0e5492be7e86f9dbac75c728e481bdd4d829afc14e35435101af71e01b72782174bfad22a05273681e762c115a21209c44a3a351df32da8698fa0d749a267ab002aa15b240f54771311d2a33228eb9ba598985cfc9e6844bc56c94a874e94bc488db1fa64a6fd7a8034ddc927146dba7961cae4d89516f56124269cb8092f3752069506710023d91e0915efcf7374c8d261250e3b0610ff4556e6b1866ee039c8e920f0cba00ee3e168018f77bf9344e3b03a5ef1c9b8ed12f4c1d710216efd97eb8ff139b911fef3cc58b1b4134005fc93655e40339d200e267d29cc2f82d90696d6a1346957b1323c89fa43b9e748e8b9e47988a1dc4704570cf1575d111495d763b0b5ebd9961af2fe0cad707a86363c949a9a3162b0544671d4c3ee14446a74cd493d7e658cd19b451d784c17ca234829a94f74e11d6484587f20d6e2496d8c630df9d0ff594bc113888c7c1f128186c7e8f4d7b7d8e678f0237ae91e40c73d6ffed61aadc28a157e3a3ab4a587ee5256bfea", "-44491216daa06d40a09f9fea54e86c3cf2b6bc777b7ec31a01f3d28ee0764061337c4f20720587837001992f60ba4bad4ab55b9c2e9c786f133a581509c4ac9e104e88e14c83245da36caf2b00055fcb9239a32e0d05519714d768bfd474a3d2340b6327264a61f809ce8b964e6bb7d1396e7a43ea1c8c517bcce5f9c3749ccfe9771543cb4212c7fbca49426b4708d08a13f56fdb9bdfcff723a62f2fb8c38f66beb24cbbdd0e3826673f6faf7d5a6eb4f31e164bcdef6789de3fc4a7a8b31e39db290f333d923a8c21ecb219a736d49301010870981b3ea3b3da49ab1101b4442e749bb1095551a32247ce58fbacc7861b1ccf82fc33cf29926f84bee932705630d5ad29d23960f5522e0c0043a9655a004cb1e00f5ff6bf6fb1ffada40f41eb0a39a13fe717fb801f0e1dc8d26bf081d000", "ff0df31ed78ebecb6dce43f8d3a99a2f9403cc7d12ad534a188cedff1bb700d21a1ee0f4e5b59bb8e95dd38705e687fcecc97a31678e614fbf79b5e34636b2989940b3051cd8a8a0e33ba27215d0a484352982edfa20a46cb4328028e887285644a1734f54f77375d90330a4a6bef96956182d82bf84e67ea337aeeb785bcbcb810fe8fb4f8f6112fa2296d847e7d5eb24e38091754dc0d92b365511d8890d96a165860e3e772c6e17d74e26df88b9f4a2f3fbcbd1b7a48ceb9e03899ea50952dc38b1dd117790f3cbecc78c50", .Okay}, + {.Div, "-ec1f9d88e69faa890bd20dd1c83d554af0306a678c5a5c8497f1e41d22000e54db8df9fbe88c94ca50bd44afc2f00ef29f7ba140546037ffe6d13b790981859819b85b298bf249c7591ab4e610361abc334a05c3ae17e41acc59d8c8859bf9824b03b0870fe6298d6bea6a8837299cd70ddf41fcddaf7fe1d3ca9e7f525111e02aa922d06dc3891117ea0c1aef4d0a360937d57bd484a73a6a4d45af317d69ab9de0de0f5f3950ed2ff513c801286a65d83078bcd9c332d3f73b3e74654c31f4fe8daed3a2c21d51e32d39a06731bd1f373914e2aa522779dcf9ad9843d9fc7015773f317c3221c3b184730fde63afcbd8fcb70c3baac36b8732f0c1c1c77c23afce58556feaeeec6321fd2619d062e6eab88b232a9485bc1804de2dc0bdc9554a0b243ba81737ddd98296edc94a94fa4b3ac277865ae1300f74c22ea9e2713edd655271dac63f81cee934a7362c42b59b0891f0599203d1c674aab17c5eeb3a5b68a5674a90b9ff199f893645ae27d6a29f2a059dfe0ae0175fa11bedff33dd72f745afb85d88df65f57a02679a09e8aa5f23527577f7cd7aa8c9534f2f12acb0b938e8edf6d1b67fd9931727ce30284016d604fa3a5ea84b90358e89a5d87a618599fe966e55618d8e3c3fb888e530753621436029978783fa194ad7464d0e588f0d69a9207b3a22b40a7cdf3dc90b53f02f5810217cbec52f33e980dd56a8", "-1df1a550f3251f67029793687284a7175131cf96aebbb7f7fbfc88123b8dbf4fb27a61ace6870415fc0a1f6fad1d8ce1679b0c88b564b7343ec80794ba4652b7516afb662054299a504f17bddee64f939fedd504b480d9c5e03877dca061f658720de40338f039c8a205c9447d3a40c1198d7cb6faf6f3bb31826db00eb50c0c5488a2d7b42890fa7e12ba14bbbe5fb4e4260f20504d883dd0089a0cf2a1fafc9dc30496fa7441fd8b9da230d0c169305a5ba4ac0ca8e9fd657d2a2fa7b8517dcaf69146be7a311cd8375be54d7486e8bff79926de12879d1e775e487158d0912ba8a440263dd09404547d0ee90aa1a0ccad608d272226993fced8d734acd9cbea62e7837d53ee79353ef83ce4a1bf82777ef55bb1b88b8cea35c80e66f5d48c32d733cd1a06400d741827c01fe7ce269ddddaf", "7e2b18b6074599a2ec4b31579c7824dc5269b2a996ca58f8c4618aad0b3c30fba5290ca3264febc54c868b14138bd6af4ae1b43992e2241f8e5327106e04ef1076b0fd1d1ec8b0a1409bb9974706d6bc5f6b2062ace2a807f107fd816cf9524e938f61f30aa0fe177aa9c7c8dd4d1c81f54b87091dbd4bc92dd2fa1e8d92440f32808f04797e6ddbd209f645ce4972931d5f1a839139ecb38f6559a2cc11be59e9d5f6ce08bac1c15e3efd47e9e728bdb0abb166afae4e95f56073b1a246a8bb4d9f3cde9ac17cb8b3c4188e94", .Okay}, + {.Div, "c0272dc3c920a9d062f9a5c2b23f237685e9f85a97e7e4b482d21286bf6baa7851cb62b6d204affc9016ab2160752628f95c76826f248d0ffb4b44577463b20e73d056568ac88f16a584a116885ebda823b74f1f89143c1fd7e10e873f39cafa402441e0b4826a8b29c487a00b1433070acb8cf2c6eab82dfa5836e7885187f4a337408c76e5fbc08cd4fa01d28a5dfc9ce368ed645ead2b5f3943eecc97ea8341611a1f3554cf014bd4566be154369c7049ede948d772e42e48f8f3fdd35d5002d7100466ec944b0ad284492c65e13b474250ae800e9b341602860576597f0b05c5a19313b2efe12109e10513670aac893b22acfc93f78613675a0d13d02c87693e31cd243217ea6cd4dc144a47126e33116019574fd72fe0d3950da123312929d8eac1ec5b546ae6c8562e13532997caf8666d686b368661b664480025253e651d2e32bdd932868e20ad3a1a19a3a8be32590e71bca2ef3edd9a3c2e374c58de40b04a1810e05109d018a2a52b38b539d3307c67fa817a23ef3bc1861690d64d5f363d85b40643f6fd3ecea96ae1bae04e80a2afd049f70b8e6e708465cdb04aae57f33a5507ed1c5cc48aa33571f11c7a75e0165dccc1814aff0bf634ea2263f8ac36f404407cea762334c780024e8d0101744234914ee9972b88b385d23095d18d724857afdca3ee143c40bd2e7cc8a4257cad45e24e2b42ef2d9414c1a3", "-1ed8bf499ce8512651b29d5e8fde7311b68e3105e6689a506a0e7301194bbb20022fdc6aef524413128f08ad51209cf76dffd70b3092e5cf1f75b0f76a056e35b6da5ffa3a62d27a7e1538fa69b8fa35a563926851ec7a634787e1a67eb003422a979e882ae8f8412080ad32423a849754fc3bd6f50a3abae10e199a2b58b9cecc34bc9e961f862b5aab71a6281d70df4a0ae6097f35d81bc47edfaefb7726dde19f2c9d28089ad007ff4d3e056c9b8c03fbe7d1a8df9ba868180985f668167e6ea35c0263cac557901dec1ac9e4edb8aba87d829d94b0adf88e9ab0b8f37064488df0fabe1a4a1109e3e2b30ba1bf1dfc2d514bfdb16cfc995e29d55bcb56e70903b936a31131b3a59fb44c1aca7a9b78f93e31aee2753da16bc074bc3280c67ff940b2db06ac81de2ffb251ea550cec8b7d78", "-63ab32ab78fe46a80f3481e5949b58e1aa91f9cb6dfcf0ee17cb3920c363cfc3c1484816f890e63d9710e9f5c327f44e6071da77a9b78a070e2038fbcd24e9903cd68dd819b9d6837fee7481559d525c5c6206614729413604ad078a73034e81de18250ca79a3c2d3a47217ffa2d3beb74600967659f8fd4bca65d4819f4ccff680080e828174ef3e7fcd88d7604c297fd59d6916233214dcfb0c3f416d77b9abc207272f86f0b87c09412c319f9937ad7089ae049d2ffecb319322c9f2ca49b47cd48f16d4abed07d5b39e052", .Okay}, + {.Div, "-46cea1fdc090cb183f9b4c5e4cad9529f66f32216f3090c5228735b1b42a975dd85dc4fbced83a1a04a7bd31222de91e9e27cbe8659c714b8f7f40dab334f1610bd197559e4a120287f82afcc86b989c28e43f44306e966b40424c0bd7f32f3aabbe6d9f058392c0a69de5148e299acfa95150df15e8076b864b0be4d4e57e2015a91b8edbc2abdf7069ceb696f7789cee772be370477f5021253ad5e67259ffba0e3a2b2bda51d2535323e57dca5d8e4bd573fb02510538cf26c34ad48b76815ff4dda6cd8450c2e68c5b1d99202be45196a5f685ea7d8ce51f63b0d8f56a65695d79f92b1775098f173a2ea69d61d4599b576b026259ed1167fce603e85a671b73ae9b51c8cd30966928788b77daa303d77f37e8937f95bf925186528df562bb02bee22ec8a16c91edd89d0197442808b3224bb8f1b6f173d52a4b1cac55b65cd767f15271b67f80dd3120f736b51b63100c192eaa8d1b1da65b9c09f91b1dcbae1c99bcaf077e262b59d07a44eeb384b73dc8c398da4e5ec31b2a8856070dac4661cef5a63a205dbf6766e2cbc0b95777a32b41d458deec4fdee7cf7265cdbafe534192aa0f9e129e10162163ce1545bbe8df1ec8dd7c34eb831648468f8bf8b82c6fadc991b194204751fbfaae62e5476f4a6d099e63ceec56fc2019c1e18188be09cd62bca25ee89f8d2037912b8151e2904d32646d61023dc387f8d7d7", "daefb3755d5e3fccb8a39efdd81f154e739d1f0de2100b82a7c03f53555a45c64af79ee33a3d6442c5a117a5e3217a6261293dd97c6818fe30616fd009a8a991472031bd1a163478cfca55c0f22601bc75c692b9bf0a967356001520bee7a29fdd81bc24e38501940b93647e3570e40f316d11ca027e479a122e881c07b61b9234f9568d4ba34361cba495040a38d9e9555480d9d6c59159e2e654c882fb20c541c90fc81a578f7dae75478b9043ec109792ad3003e8d02b32b506ee07ddb352ab1e0af197c2c7211761d88cd7724d9542deb96f85089cc2bb4b8e1bbdcedbdadc1099f83e043eb02840a8eebb7ea4d7cc14a05041ceb7c22abf6485f0b5720d2c9f535d8bcf0e9c48ce7fb2e46b75676ebf4d14220f34835a58a6282584ae8f3ccae96c637ab4dc3df1c863712a604c16ce58", "-52cb4900962883c54ddf5ec8aab56507b467193de68366e4740e1d5689c0d1bda7efdb05e48d7212cf5d59250f37730d3fe4fbfba318e83fe3878543eb302a58da23992220e4e2238d34492cd9b92a9be86eadf22cfb59ba5a8bd1d678c0c87eaf445aa4e8258f01321a7ca43ed06959fac55e76c5982f72d8b72de2d5edd6d83e467ce3d5b94a8e311f39d8de7d858e2f1bf704f2e799e2db81940bb07a9f7add252de07947689adbdc7a04ac390105c9ea4e002f131e5a2aa6b4f9f5c1cda11fa3c4764d965c42d1d0a7956c", .Okay}, + {.Div, "62a46904f01edc0dbe107a92cd68e8a7a0001fdc1fea0adb609e3bf072a8aa237a7d88b14aac8db9c9e3cb20d6357ece4fb9344c4a4e22c7675ee2d9b428446f9bd0505caa2a30af5779d58d3c92bf7254742209820970e96e50c38658f5b4249eee5e92eae52ef5ea5c8c63e59aeed4fc9b964b35c13375fe444fe385cb4ef750b25af335792312038f0ed60575c3c891bb0a2d35f582f13ac340bef99769749b0541521b80a3277203a07e0ce6b5236fb02ed764afa9e3d5ffd615e0dd1b1456e798c1e90bcb3df26d96e1b24e5bba45b2176848eca876f6cc1d05505f48d3f39bf456b5cc4449c436a27d977b687b14cd9ec30ab01efb21d28cf43316aa0a93a7d1c523961aae835f337d37ec7bb2fd47f5e7fd56bde02edc238b6d468ad12e6e1418d3bdecc5b44e6ddf6842e32ae16212fa5f12e7b259e6c1cfe9bc70c9dc358bae07e92b53e2b3d03808ecb094eb8efd5de3889f8fb80b3ec85243b3b112dc310225f32a3981b2cf95804209d28ca2f48f2914072002488e110be4fb0b6192e4734a76b3015c95a84247fde3f8bbc09eeda611e481fc186ef6d7fbaa885dfc285b0bc78c442c54cf2b1a3675d0e4a36bd23748065a504da52a7fa01a0d808dc566bca42318a0ba9c774f4d38ea72782060dfa24346fd3761827025ba0a46c99b64c5c7f3da9f1702b0faf97eb84cd5c551fdf2c0c9c08c37b43b4279b6", "-2b46c6f3efb02d7a529f3aedc3147ae7832f00dab5aa1fa4fc74d0ca9514f1d0109779803575e77057464515a8358e5d07f78b3b865881c2a5383f3c9f1918571b7142d98c6b9ab7c52ab466838a4c4ccb38bba30d42bea8d2c5778fd4e4999629b9d19e1f89ff0c7777a725b2a8ba7f24fa4911ea3f9fdbba2262ac8189d1e24091db7a62cf10cda1ca73aa4a52f82c3512278a73a9cb5059248504361f8404ea4d1f9d92204791285adf7901a5b482958ff3807a820de52a3fa692dbf86dd0f17418c36366452224516938f1b0670ef906883e60af6e1ae7262350d0d75fa1b0227c96c739c960e18be13ba1d6a4c619a5a142bf9f320588509a64340ddfee06a6335f5b2f1a57bfb88135af90203769c8ca917a9f1813501b434359e452564cfa496b5d8f0447b3e6935c01d2c19e0be099", "-247837a8d390e32c2a8003c07fa8dfcc23388e1f9824cfee830c0be53cf7edfa3f84a7ccede3bca7ec9c60c8f004c96014a8d7cc69c71b9bde56dc4cac6bae72eadad313114564ab5e29aaebbb7101914c019b71a271ca29826d48ac51e1bc01fb0ef7c75faf38d88a49c521d0065d757a68dd881d99286038d250ec513409604a6581e01744b501f17eb52544255dfce5651791f8aa87adb011eaac54134c0ae27d977233b2a9aa6830bae3a86d02085783c699cb45ca1de6e3d82e23d100baeeb66cc53b02cdb3fdef753a136", .Okay}, + {.Div, "9499be1d41fab771042d8633d54064376912572b6f81e51ac84c81831c980d82ca7683f50b6386a9fd4eda44f621f83048f4dd239cd38cafd68d6def5ea3ac45dd2b3011eb1fff577bf23a9f068f34f33a978b871f11e6318c2a38f621d32af290d2d80ac8b57269b512865ef5ecc7f162225bc033f8c1772d0d5393407c8b8fd397a1a757857e96555482fa493e348c9763c9fa6007af0fcfbfd46cc46971c636ab7d77ef63858e2813d61dec1dabfb0cb7ed57f900c050b9f80a8ad928defbb8efe2bda7c7b01b369a8e1efabbc7d19cc579144c97a3391f1eb5d81438ad1704c29ddcc5284f89ff4ed28624bb17e94395d7de1efd628c372a281d180b6cf4ec8cc23c379491d6541adbd98715aadce6dc915fcc01db1a9f065f3654c0ca4377956479428d69572c84a34d0dd527ffdbbc492928dcfca1c41ff5a075f5477612d9fa3720e9b69bda4e939fc9d1233aeee820bf71eb3e4b2e24779315772f79bc5c4868dfcdc76049e1fb6fc1f62a41dd56aa51899ca30c755e796a5408edba72e028fb78615c1b0da25e77ff7947df904f150eb890e86731e4a1d6e098d6719964f23393da2b7c85ce03840d81dbbaceb54d3c44dc6d63bce84fc468f0b6558565607c78b5c033252328f213f38bffa268ebb12864843a3af0bbfc0085f5b8337f9bb10f6cc9f8c978ffe647575780997674ff15e64cc74658a0f368f73659", "-24909dfcea7eec331b5dcb0ae6802988ef6255bc7adf7d285326355972a53fa34b95b598e129ce97e3e8b876e99b85e5f5cd02b2c330a8ff8154243a1d8b53d783b4760b4bab3fed281381b0c1fe3a3a0a891a0e7bed37b0cbfd56a41dfaab57f80a988f786c55b4d568e3c2edd04ee1e0b89cd9607b16c6a5c688d3c28cf7947a48f635bc76609605a2026f8967702c6cc7ac4dea5bb59162f7603a2bbe290ac9ab4af2cdc92ba58dc0ad841b8adb322085a29cb1481dc815d625554b02c06a7874800108fd3b14954ff2af31f4355062aa8826ae033e781879622054e693e33bdf1f1b9a48144c3d856236453342068f184266ce962b7f9aeae201bca746a1d56af05d9680896914144807f8a4c7e27fcdb68df7b1979976206e8412ed67ad1a5463a08831843805e8210b41935ecd8771fe", "-41063aa909bee3cf4bd205dd5ef2d20b8e85d33e05b47509e3be9c2ee8d8fa73640b2565940ad9cc3fcbb4364cad836dce0affa41bcd10bfa341f8ff2ae16bee3514322e1da0bbc2f716a3dc74c19e672f9f20fceef4306226f716133a836176461701e99dc204ac53b4aaca6b127a42db53826ded40aab7d558e3bc4b2e760aecd54f50b9abb485252f02fc627a0c03eb4a17248311c66689ba5a93d75aa58db06fed1a887410cb0fd433c65e779fc06edafbe333139d9905673d97f8f32b23eae362d7a6bca50de3a3e11f9a2", .Okay}, + {.Div, "-a25c82245dfe0045cf9e81b5b52b20e41a3416e2bbde8634fd8c30179e9065fb230f2ced6123a08a19b4af8220adc65b882dd4a54076ca3bbe9da842406df8a591512f01ce90309a4d65fed3bfc05109889e63b60f5bc903800cd1fceb10b3323388798972607c39755388b218364e1e2370e8b54a92fe7f3ec35d38e9739cd95f948d1eb92f613e3130df0428961851c30fdda61445e436f6c51f15d2b1284acd82bf5c885e2cb4b0402ad95e1a151fa341b023cfecd2fa9d1d213d86c5eb520277fd9f906d432ca49d3471771edff628103ab3a47ba92a185d8d5c5ef83ba026cbffcff58828c341d45a1669a75eac7b1e899d5bf3116f16ae548745db406e95e12127d32b03feedff3faf293c58e826b45e3ede65c8ac394602b5d38cb1b0dbec16e38c51dbac6b38b571a2f582e3c3cff102a6577b276306b686607581f91d1b5342b9a862dc37c38a0378099608f29f4abc65bac149dd641c27967c856935a23cd214a3fd3f411e5558b785e800164e3708abdd6ccef5cd077eb7b4a7e35859b006a809501e4780ddb7cc20cd10dcea25d81a15bc444e0ca3d63eb4a757b927a250788ec0d9d2779c77fd2330581bcfefef9e5f9b014cb2174e3e06bd475de640a56740d48ac07f3aa83433c08bb8d8c2fdba4a84c2fb1b57eb52c720190a21c8a4d9f80b231c46c4187f3b3d0921b6c4c3fc1e36955ea78a437756e12c", "18dc281c6f7ca0995f902371238fa35a8b4370990125735dce1b5238f8aa92fcc4112c88dec17f4ef3d785a57cba0a4bd14db94a1390729277d30cc4504a683b7d87082f6dbde48abbcf7720bf593a33d3a0f258e44310093c4a9bc47412fca99c79c44a0eec3b4481c561def934237ca28c88001ce052202a3d5b8a2d51bd2f07279dae44454f7c2a983211b99f240378ef055316d048e74f6611853dc66108fdd2da891cfa53c2b18f5d520f9d0dabea12ac3935148d1aa771b716cf58b46eca86ab3766f97dff7340b03f7b05f079636b844d29259b7eac494a70f74288b3502f3bc446a95b2f9964473cf7444fb1ef2efc94b57c37a528cc0e075b9ecee32dfbce9f2dba7cd9fe1ca0b66433ed68776d48c6696ff9104616dc40475d6de3eda8776bb463d304a7891ce52261f70b6a341c9", "-687f1afbe82b4c580bfcbcc197a465c674fd355ba89ed080073308724abc487890a9f067c2332d1e1efe4df502259f5607dfce4a82887660a255e648dd25b4f1dfb5c5b470614236d263727389de78c84d5cdbf021b5c130877a77afd1f82f5a445ce6b08e2dc9e92df4133a766bb7b8e73513c5430254e4842a26a6b5524b207f2d0364870ea8959d84d7fadb1957f1bcad9d7e247c4e75556fc5a7d985174c3f87fbe8d536471c175fd9dcb718fa3ed54421d9295cedccc6c3ea1049bb2d4b8411089fee62897a30f13b008b", .Okay}, + {.Div, "20d5cf139f0e23ceb199d3457652448e969632f49f79de24111357f7a2721bafbeaf7dbb011dda5ada01479eaf43ba97edd94e88571a2d12ed64ca7e2904f368d80a3cf4fe6b4bf874adb7db0486e47c24654c4c4c51053e7c48e7f39bf3bf2c8b7964a76b58bfcfdc6496ffd7e771a94dd0e2539b3b0613ee6aa70dcd97d363e48776e8e0fb9f3b8c464b606781d723068975f8c36d8877aa7404c402785c9ed67c3acd0c40371577b6eeaeab9f94ab5a91189c5f7973b3d417f6fd53b5ad8732bfa2f92eddeb067d1d35219cf64a6288bac4fa31f0bd7ac5b3eef644dac7a348968d4523c429fe05e8be0d06955a0baa7fb258206d429b0c7ea866ba53fb53a338e2cc77aaae7698fe72bdd610301800fe2c6b5f4a2859f295847e378960b2e900d9d14f87e2b981021cb672aa956b121670dd312c85a0fd616e1816ffb3b7c88a69964e070c21b4a304aa4c9270c5b98487246cf44354982027668c28642581105e5159bb1cd04eec0fa813169010626cbc987e15f3176f400c5b0823fcf7ae24ab8f8b975b5a0c9acd9872e5320603b161d6d7dc6c262d6ec061e5c90334673e6ec405575ce952d9b7ce5f581bfeba5cef35a29c5c4aa7b7985c3cc20fddc3ba8816433be842d6b4b0a0e05fe13e4944e1b471a36b0878d58dc012cc55f7f297c2930b4110bc107a50af679101525ed6a4f2563837049b40923dcd4608bf", "-134f3682a5bad54ab31a8970846af2eef181361f13c80fee445b5c09a37b9e5c03733fdc6dc80b07102ef2cf556248cd488aa019bd938a59406fb3517701d6a9a5dc30c6478a4d13700f3ef37809dd27f4872f528f8262b98e19341086549d5f1268f4c3b5e2817e1f9878b2c3540650183df8bb1eae378679aff6dba1fa2aba4b9b541a99cf77b88c7b0b0c9dea6582d48ff2c5a26cd5e175889850113abaf0db6be5ad1949b6cf59bfceb1e4cdaac35de8c3d29fe92f12347a778398b66a6f3b4f06b9862f48942713d22f995b5f3c2efe01dbe4469102c1a0a01b6e7e213fc52a1287d8171827988dbfd503e6e8be4082010763821fdf2c75612e25a8eadf2850fa46a51f0278d883d7e0f2a528cb75a67cfc625cb6b428736ad2c24aa3abfaf175047fd8dfd231f8ce657ba7ee34917cc09", "-1b352509740252287c8e8e942be0e1c103633463521b7b9a7f33f9fab82bac90278628e971fd57e11609772d51691b83058e0a623f5dd66ae0e26250322c74f23de111283f8e347a041c12afb8f60ce57dbdacc92803547c2086da000593d8b1df3023b50a02b55c2c25118c266773f4c665176812bc224f1606c066d36de961bdd7ffa0e5ee48f19079f3c855bee744db0c183806b7ab2a7dd1ae3161677771d5ca2bd091a1e6aa2ddc5b70ae81625e6284a3825983c0444c43bc7d39b605f2deed19a2d2bf185a255d94ba20", .Okay}, + {.Div, "-3b24a0852b66a5ff44b1ac39617e7d5faaf3f2cc96331738a044cf2db30260795973cdd05182569ff713c44c166bf1e20c714616c1a920bb9c26556757a098d6ffcab290105d09b8a135859becc6b411fa3e7f88b6594bd897d1cc6e709ead7558a83064d06c05ba89d531051a3068a363c0b75a170c5e0dedb7403556a62625a79665c14c3ef72cbbc553b4a512c565e7f78a9b0c7b75dfc14291a17d2b3d3d8659d74039ceb3a9c2bf7644936a9a0c27d34ff066e53dd279e05dea9dcd6bc5f510e8168d5725fa49df74b242a1c82f6a67fe3ebddd90a3cdd3b7b3bdf08ef046cb8675370103ef15ba8ad789b2ee40e81d73abab9a81ce0c369ec4de0fc112aa7549fc5da610469cd48649519023891d6e854b2f2d59790d94c4c81bfbd4b1e7e15db7983870710095268bdd83797d024ab8cc40b8d2fbd88f4a7f7d139947909e685cab07412d87bd62abe70582faef5607b21ec84d83eb737c7c4c76e09fd54060df0b5b0667a2e93f583533ddacf7f65e9425b1715e423f51aa788b83473230856916f5967530102555e811370f28ab532972937a2423c0a21e262f39ff81128bc9cbeff90ba58c53161635af7279cbf8dc7217ed2448bdc6750d54c6f39404e8046bae9b04e202842248656fef9770c727367d8f134f9757456028ee2dee6c5660c6c422e498876a7d7b534a3d7e45b9b763e80b8569a10878d7c7cab3", "1bc39e34778cdf9019a89d8e8ebdd3d2ec7e86c5fa1adcc2a8f15cd6568c1e6cf296e582d37a4212f32e95ee16e56f1ab2e302ba832959218b254a7672e0743296417200d89886c5af199c7913f91fd9af47ff35095f6a68b722019f372eb20b46324b0b858483fb5ed80b58601b58c6513cddf7f6dc022821d2d10267fae72234fdf72cd557892b585c16897ab17097f60bebf1e2f7d990c064914ffec548f7b99978bee7fb390511e568b1ee334cd453b9374c12e488673d2c154bc2f1e394ac80d13d7214c8c0a71393b62e7f88df8a881092ba8ac2fc7e1414b6263b40ddff633afd7a2d552af27e3c2bf219393d9cc79fb1d35a164404a3b3e90c8421dfad1b793108938673aa9e1213ee906193feca7422dd6a1a8f77eb8146b88a7b0a522ee93ec6bd823e3dbb47346711836ca4d2c14", "-2215498693bfc8d1aa68af67106e15ea8357612b1b3612f7175c935807f605048476047a9f6c91e0c645905f1160a5c8ef1e9c892ad8c1dc41c1b1db995b8b1a4c5bf5a9bc7a113ba74c06af4ea549baab34f25a6671bc15e22be1636697c7dee523c87b219d712b3c6dedcb80a6e78d56f3919bd3f39f2180727756cd9e93242548246037c4f3ce7164b7b5fa67e612bf5f74a02ffcbd648951a90a152d2413e04a962124ee79e46476eef817af7b10144c63e9c4f69ba4e957b2552f93e82073b92028ad010643ada6581944", .Okay}, + {.Div, "-98edd753d58380f3575fe651663addcc4e5384d58eb352837eb5614a3eaedc0bbf0d041bdc52c4d5d7fcf9108eed5dea95e792b1ee56299ec3b686aeb10f0660b13d256de977ecebb3e627a231acf4fe067ef3971c10e303de066604e58efd9f07407a67b5ff72c99712829bf3b66201f95c5e5698358e32038b8a7d46d26da094af27b5af76e062d1375b6bf3e7bd7f96063082b1e8ba3a06f316c5bdff02113337b1e392ddfa1d701fad3c57e961041f40ffcc17c0995a8cdff3cda4d379a9e5b03cfdbca76938543a88cf98817e806f8e42b84891ee44e1b17ed2105a5aa04b3282963c20a5a0b8a7f0f3f470de5c89af65ab5b809cb3038960bc91f60ab2a4c760e18a57cfa9c253bc5dd5b939d2deef4b512667f83afaf8c0d4009234cd8470e2b3628ba0f9b8f26fc7ab80bd99b8d5ca2abdcf1baaeb13617133e9724d41a30297f8d1a0195c744436f1c9d1b0c758ef7d2040a2bd8e57d7b7b7f671fa251951d4a80f7f8a371d00f4bc96b4bedc075080d6f9c63053ac8ec0cc31364108f85ef5eae27fecd451edded664abc22bb736ded46e7d7a38c721557468d1bd8e67eac5c17432138681c13df85babc47c56b6ada0f54e6f4315e0c5dd13376f7d1dc33a529934ee3093dadd46497878f817dd3e15fec098514671fb81e17317895a46ead5b055997bb7e4ceb09df5da5211197ab012e395a0dd248ba2bb627a", "82ca100d2a9a4810ad21c638dcfe06347076e7d2183b1726aa72095e34b1c624435569d086cd3f8ffd5c828c06cb93faff26934d6c7404f974c91e4dde6c990030b887bc5c16bb8faa7ac833cc5da509bcee87311ba3c8d26b0e2ddaf87d7b28f8ef5fbf5771f1c6cc09df5e0a233aecf222b2f5eadaf513db4dbfc5b23868bb1e749afc507550c80d5a5c372c8a535dbb9f4da69fc295d170a89b2369fd59de07157dd41a6434840c181c1f23dfb3cc673fc892adff16ec8332f4fe02dfaadc6e7d3843106a291b28f1be4949e5856d26ebea2fe6ac4e2eded1788ba74f3a5ca393ae4143d27d779aa5379d47c81f80f1179eede33f4172878e716061d0a02d263d4b4a78abdf3bd142a42d26eff04ff0b8eac810a4f18868c264a20eefbe86051b6acd44bdfc31d6f135d6a1075a69ee884d", "-12b55ce7a6429144a5971ea0353143e5827f21c0071a56e53834e76c970444599e9bb2cba5b41fe0400c6376c528bf19a671eda9893773acc28470826a16846483d1d2e822e605d2a086e7f095405600458cd59e8c752ac995800affb929e8f722d0117632308828a5e991aad20dcb15f61724c879f6f4323543a02a9904c01040c8ee56feec6503ffd2195a7b3ed0bccb4f1f8d7001beddc96ace60c044cc182aeee579a46dabbdd39e6859e50cff195159bda791b69a5e1fa5f943f94012aa434b001a6df0b1fc8079805b581", .Okay}, + {.Div, "-3eda2aa4b023428a22c1e3754cbf8dd87590a12747579368acb0b5d61e56b8af3401cc5555c698b63999aa8917912b021560cc33058815b6d5e6bd156aca39dad0bd79012333834b72b1cf9318b4dce8d467f3abfe7dfe2eab8c443fd7504b0d33376aff5da67a3cfe76168b37e763cf5d10b7895c0692bc8d3819802e88a9bbc0edeb4f7b028ca7107a236f6ffd634666e66a7d39fa3258e49c2ef2d2c0261a2bb656a5e0d8309e1f1102d416b40e981fc8f47eb17ebc5e975d47e89dea391e99d24c6ebc3dfb90318f47529466b374188e8b0ef506bbbe5dfa43061b8cd187b03388d133bbbc081bd7900bf1e71e08766bb1e05071077ce26638913f30dde92d9b92dac4fe5f70d43258b2046fb04ca0ebc43968f4cea90f85eab8e260bfecf8f2a084cee5efd8ca9a6db6217387a38497b6cf1ebeb879996a951cad33e631fabe8452c9967bb9e3292c379a0d2126e09b613ac14ad8a564a50afa7c92ae89974928aeab2de6c3a96fdaf27d7cb01091ab8be4b3ff6366eeda31ed10da567b314a451e201bfba12d1e6a369e46570df635a398dd4a010940b294a31f6faec148cdf5cbd5687c10884bb61e8bbfe2f0e3ebbf7913d9baf152c80c34fb196a4c8259c346dabe0933eddcc93d3e6ac9a5fa458f3bd81228d1476beb701884e3751307b03d9f20a1adc0be927158e7695f7c481be9481eae8aac3b0b57917dfdec", "34e0f4c1c85375d4d3f9bf65fbccc4dc1ba39ae9a3ef8e60a41f8459f32fc88ff228d1e0c89880599a6ccf64d61e85225e7d92e9408a133ac4acc9cfbe1569dab2c083f58f28ccc217ed295218443dc761051d1d81da774e65520fa2ea3c3dba96fd908def2205999a16b5239d9d2ee3a3cf7e5955f8fed1683b1d436b713fa2e3943cc1f67b69a282ea7c753b66ce14a46331d51c9b21576de65cda76a534017a38829872e49a68fa23e2222997bf75d407b1a1e9a453aa84a386d431386827ef8614d14d0c485f75cbb632a1b8609d26bf2cfa43b28e5eae3563daf588908297d28c79805b040eb78e665f70192395dbe20104379664036ac067d8e59004c9b003bd20e33612bd092a9ec086e7ac4466b96217ff23f8e567806e73040a487ea2294a69b441080dde51794dd233909c49a22b", "-13048c529be9d7aa3bb8b19aab6efa94f27da961a014b204a438b3f2ea572d7ac15b997252d6d6efc9443c5705e4c8c9243426a68fb72eef663bd6346879831b07182b62708e0246fb5e1850a7daf509dc8d792950f02c27f1b4c0d3f7b986578f1fd5a21f06091cdc673310853141bebb8d64bccab5bb1c4d01929c128a95ff2ea7026d15e287ed7d9c82bfdfe99e25391d5a31e4b259af33756cdcff276713f57692297e00d3dd4563a64f185c08c724aef380b689f3529d17186c57130c4c33f8bf22b71ddb02f96040cf577", .Okay}, + {.Div, "544fc682053d963604b9d8805d80d37d35e5847d046f35179a9265aadd51c27dceaa1f51a337659b8b155cb000bda977a3cf1a440f2f8bd993d5e17768f20a6c2f8a55ec99d8cb1de2eb85fe9b0da41bfa80adb882b7f73db1612276177fbe1da5cb2aeda4b69d508d5236ec4d7274ffbd1c232fdb768e9ce5c04e185b9581866deaf7d39f99e39b5dd5678b66967f4bedb3472f38c77edd8c0d50daa17685e7d17de6437690f7714389bedc1dd6e63e482bcf6d3f42f6d48814b5e7d1b0607e6ebb5968a21c43168a02a9fb95b77ad87e14a13c24f33a45fd194faa4a70cf4148752b1c9c1641e33118637cd1b3b443c731f74ae0bf5accf8779da9090625b2b8d49f0d1ac890ffbc2ba779482c2d9ba7845f195cdb9c6e97f0602a8daba200a41857bc0bfe5a6f11a9dd470305e95a0bb7d6fbd86e3ca12c3d98bbbf6d7520fc0cade1a089fcedeaf9387362155527f59790507f57b3d9c605ac23e0b3958744e4cb1a998adf72e4fdb4424419cf14a1792365c535fd6d4a7c8771beae1bc2956aafe0f98469099689c6c4b6aceef8ca734b94b5fb366f3fd1986b3c8a279a1bcc8461216d2d399702bd40068b13161aa46878beca7f4f08574215b982501a6669c6447167671c0055992bf6fed3ebd1080541453e7a47f8a96084246199d41bf1712c282c168bebeb92a577542ae9fece22296616af661615439ba101ba8b", "-8ef4d4507e67ad0a39a1898255691e784388f92ef47ea00f8ab69c3ab807dcf80e61df9100deac2495ff1de880747f26775c39a36d21d67944c7d597f854ca3acb826848974d67bac8d4f38d1bea600ce40a8504f51e59da7f9ae4768079257957970b4fad4b4d92461b4724b1ac5342d30b04545e955b19bb55c7b1ae8ca9f11d97a02e061c82f6e7455acf3cfe7385c6ae158264973ada99d7a3269685ad240bd998c8d1e348cb7bc92acb9489b415edef82bb0d76c271a9bf6b50fb7948f5a171f712af4d1327ed628ab55c434ca6795013568479ab77d3c10b2bd9c9558191efb695c39f32c6c905c982cb0d246f16da3127d8fb286b9e9dd0c972c7053112182d7318872eacfd4e25a6814cdd53e8a870b9196a048e6df2e87d6a2ed6e00984be6d761d0d545196268e7b609860fc6997", "-96fb47bba5b284f0ea2bb270b32edcc81f59c3c1607f96637e3e3a248ab3c66bf276ce48c5d1786730bb67c840e8b1df368275c10cb7ade080e803992725bbc0c1f877ad50be1700cc33fc44a0532ddf477843df16472e48b311193827363770d8cfe436a2b3040d99526e19d7ac14033022422faab7dcd9526ed0a96675a6b62f7145d71a1dc1ad3fba0e02431b8f49957cd52ae09602a21c2751271f6b2b4af1298b42da1a46d073f58e8926a7c857a54d2dfe80fcac41da8e40f2bddaff88a50d9398141e491e86982de1fd", .Okay}, + {.Div, "5e8b560b54530e6a5d6d7215a226248b22a55433e882a1fa3abf10b2006aeb38deecab682d140734cf01cde21ec13bbfde448c7c2ce8352b29384566ca806d0d9b928e254baa4b49e718565d2ca958b6f34e3d365ad0947955aac21063040885213bf5e5c47f070951ad693c53de8a6bce52b750c68f53d0312d9193384b36b7d6fda65ac4c0e9099e9e26218e427ad4f49d2103cb9f424914b5be0eb25cad736d2b07bb602d6ce0985adc9ff5faf43b50dd24b8aeb81ba43d7c31b0b5ac5593268507374708e517cf45a16517bd55ef9185b38e74bbd13f64643c665e69b34dbb56ba5f328f370dd1ddc6873224d8ebd7c250c87c050a2704885669ed923fce637e1a35c14e0ce12f1fb4ca1493da8bf5215258d2edc1389cc0c901b5d31ab856943ccfc9d7ee13a663d0a3e1f9b5525c711f868371e6629ae7d4406873c3ec61af1711b6ebab11f86570d6d41bd0f4e95b2185557d2d3c32c92165316aaf2c302eb0c20240a31c02732fd8a6f2c92d5e49fd3caef21a6ed3ccf5c8c5d6456ed132eec6e67f708d23381f1ba9d9892b3efd4ec89d1fe5d361a8c2335c7c7810874b87f62335540a7139bb5f326f8f1ef9f0d78abab795c006f3d5bd7e0116ede238fc1a26548344ad8580c53dd331b0d02ac553033f19ff0e4fd6b6d10459aeaec9c1063c9bb0e5983192e58477d22a094b04ddcbcbeb5188a23963862fcf0c", "-1a690f23d8370892fc4c0738b1e870acad2c515d7a0c0d6e830e36e0df8dde6d7d526a0f69526d3cb08072047c6fed9af3608431dd2e81b2a91233a59281c91ba66919d65cddfb43eac7efaac7678574e9ca09a713eaa67969f43c45e3719e8580e4615083af135cd74780e5c92ffcc54807d82ac25128ef26dc0fa201135c5af73e905d100789832259c6dd0a6d6cb283ecc76e7d529262a2f9f3717348733ec142d8623ac9bfd3f15f81685fb7e7d0b25acd5bc14612228b123d93b2d7e43f3784f7cb472698f45daa2c0651ded9dfe4bc9a0345a0ddd088ab78072d6aead07f661f8997168f60fb85f8b9df509e0707315fd3d3b57f467c3314ed94ec12091a6e17c7eb574ff1b266c139c30ccea0e84a43b7aaf071d21412f154ac39b1de0d582e41c2b29f024f14a435f9aae56d658cfd5", "-3946eb58a7d6ecf0cdb88c06db9c23f23870eb7ff4962ff9ff17144216e3ebb1b35f8f11c06f2b6b00827c21d5eb5de465d4db3b8b777e0204206a549081eb3a44f506917bab30f3dc2a8929c45c3891b0e024d1efc59bdcfafefaba1e8dc9c06b3172dfa9a161542be1d19bab79093e80fb9dd900cb3144dd9d723bb4186d1f6d46b64611a7e974d935501691bdf30824c3fca0c28c645608451757a1f161010e7bb32b0cabeb4867374d58d24a9e58db10d82d51bea73aab8046038e267937d4c3b7f2fab49c30cb367c9bdf", .Okay}, + {.Div, "907f38d443dbb91f3d2324885c2255e509343c28ff5643c211bf981fc41283e05fe7090c2bbdd52c36b1918497417875c401abf8d80800da3b035f8105e65dfdaec777d2e4b5598d45c24b81cd03733e316d55c60f17ac300a546686fcf6ee4883f90244ea22756d195fd35203e18740bd890fb71fc566975a937fee167e3eb96e392920767db670a70c6db8a238729f65cb442dbe179966f075b0623ea28620d7178e39aa3ec1226bf1aababde51063b9453ace0235f03e35eacd5f21d51f2296c86405dd06219b4a0330d58ad534ffe9d71b2be58ba87947a0d768464b852e8d132af29161d13bed6829b1899bb351982281072f576816adcab61bafe09622f673c58a8e6e03d8a67998870faa762d05ba30b45b45ad29db08639ecdde786b78d4496405487d48528015e2b0514f7a456498bbc0980ed08e4924d81c79bf87dc95e15ea5be5c935052823bc47ceb1afde5ee12993db851ec4ab2ff5a94a3266d9420135deab2790a8b8d6c01e3529f1165c9e54855da2e2a9153244c73f749e026835a8ec7e07c154d168362a12d0a716348502ff4bb9509db31f7c6f071c14bda3b4fe3b308117ca3047cf9c671043387cd376ce7f6c2081fc76fb0c0c814a97f84aebc67240e009ea06367822ff4cdfe254b5787d68c8af9461b4798d1fbe3cbeff7c8a9cb5b8b47966a2122ef2b2aca9898ce4620ea3289a021afe8b90e", "1b1b313d07ab54b3e3e7eb0dc88c172ffbd0c273dfee96b2ba36091c520ca59e0445f1a704de18a392959c8e6153be1d2379c436d059fef51f662082ca16aa3f8f34ad953eeda5cf171d43b4a205d895bffac1126b3cceca06f8fc41067cba6fb9ff8291bb54b523948ea7c87405952c8c751bd1e03b61d5b48dd7ed67e96416a8662206e18b8ad8099016cb308b95741b62d7ffaeaf2e3ec39fea8c6eb749f3e4b7f362e6dd0871f7666d535d32e1a8f9e32c71ee5226b8ef7ca4c78c426f9baee4ed854cdc2c1a63cc3c3fa8ee679dc0eb5e730bbf236651684080381aa63e8d58d2b7eb9f03fbe10e5e173d54fb6c488f66aa374df575910d4ae71680d105e105e51e60efe963b3858fd1be447906e0841a1e39bb3a29ef230395d20366b119d6d44737771ebc76874b1d4b64a4e73ec0ad7", "554ad3035fdf70a08b9c52c6ab82803519ffba2cf6755a59e5b5dd9a619d5bceb49f1945e250204127ff6f1f7a4fba5fa08fd21feccc73bfc3f655580d956a06b1f6637300b651ddcf534670b09db8ba1bab15c53fd20472e1672dad7fc86cb427148c4359d84adca2659e6344e41e773e0b384316aa127d7d8cbd26bdd689aa15c3aad9203acbb2992ffdfd911be7315b47ff9d2e8c01d307507ff52a24e731e5e1b790c359efbdcc2a7c26c9cf0f1ec23f2bbdb47c4982a04420c8b91521021dee82efbf5e996afd5752173a", .Okay}, + {.Div, "-f047f653523e41e9eda91f3318f2b398a09241e679c4c587ac60eaef57eeeff277251aaab748f17abc4bbc45f20caa4f79bf1fde7dec9ed54c5f878c146e66186dc763d1c2ef65ff8eb088ddbe0f8bf7a37e7276100681bb5c90562ae2be541d6f11c751bb4b1dad6f14a32be8a7ea6eebe6b293df0daf49286fa9e17d5d2b88e5b5489c8492fc2ea62ebe75d432f334cddeca59fbd0e84f7c9326ac2998af0730cf84df563a3af66ebb870f99edc9f49c320d602d67e11802cd0db8b32b1321992c41acc519e308926d8c5e57d5ac3fff1edefc6c7a75d88ec0001d6ada61152ec0f98b2862ff8335de645f370d289588490626b497b2ccbb2200d26529021439e72db9e0490da084948095778fd8a7745b990c6a0210d4a3fcc86f466dd71936de79c2c6df1ecaad8b2fa8a86f4ad339deefef7e53b27860e9d38d6828ad592ff0bf8a0d4aa702f7be62dfa3a61ae196acc0ebc258b95ae1c9c42533657058208533e86a1ec569eb5111a407ee05b9e2c75b9036eb51b7ad0eab4b579ec3105f8cd8efaee594221921b859223e82dc3a69619fe7c7e588f602cf708db4b39495decb5f8d54ed594d8b0e771d67416bbb90962b10b0fb200c884491b3b19a549654b32581b659060f76176c4ec9c2195d162a35642817a5f66c8f2720804f29453fca10cf71e2e70773e08bd78f220da02ec8d408cd7d1b8181749b7a7081e4", "-1b799a2b0cc12d506a3651f074f8dafd0be689f240c1b68c743b2e8de85d0384ac6638b6d788e1a74fcb6d272478413df2efc479d6b14f33e107ebbff1aa77e7508bf5074545e1b4f125fbfdea453d6c259fd4fcbda70078605e1a251e1b03b99a81ee3321fe8964d03522fd10d34345ef9d5bb8959b9b2d8ef11bcb45915bb69ff21a65b073c5eb2ef335687db2b1dd9f597ceb97b34f57344cf7913612f583a5ec9d1dd045dd7dc4a7b3cfbc0174ae2ad14db7fb874143aad4c074a1dae7883b8d329a998926a64bacbbd8dccfd269cb0f947ffc93591e0ddd707fc8b267e3682af5e15c26a53d603acd12e076ff92ad9bdb6601f0706509aeb477be43ac024b5e7409ed4eb5d1f29776139fcd26581ebda3c52e42219a51932e6ea3547e0118945442e35b265eae78376660d3a60b1b450cd", "8bed54e18acd26dcd03c9d3492758739dd94bf5467bdc369d302418469734b280ab6c80ca849339ba9b839e8cef4cf84f09ed0cfe2cb1e096a3594a89bf9dc3f4dd6652f86e4c094c16457e953117bbefe6aa1237b8d28135f1bd73e8ffc1b6f8f6e633c0e255aa08ae6cbfcfda0a0b4354fa949dc20ce6c6f36e737f6ad79ccbef206727f9097715f6ba93a6fc6cd3b9b341094064f7e6c916756f577bdac1d5c269bef93c67b969cbf1dbcb33849918e8a03240c38ee27426aabd08b283ad3b3446d34b26c005da9eb83c47a", .Okay}, + {.Div, "91edd6b0daacb91b1ec380a91443ec900a6968285f1fb5ab03c35ab3ed8798adbffdc949cc28f5aa17e1ce71063d54803b6ac772e79b581e4fd9dd89b448bebb1d1ec3bd9ac5171f27a539d7c02356719171db126856e6948d7409f461faf0ea0ffd4b53ca6665c9450f36ab20818310ab574be9cd36fb77e8ec23477a6c4347b663da497608b56077fd5753b8e69216603c81b58e6667cbe5fb1e9baf98ccc8871bffed57e754fd7eb10041a0db3b0e2c87d16cc8f6ac037d1edae371c0e28130a318e7be931221ea77584f992889de6eeb00e3ad588034aa2a555f822758ab6f21eadc654b53af81a8917713308bc159cd34f0927fd1b71314c44280a02d0944fd55082c356627c3d6b683d532fac9fcb3101bae2e0299244145da3716a0d27eb8ee9e7c8a2fec647011c49f1cc624e37e4b8fd333bab7a85af2cbd353939882c6fa2c3e1a348730d16546825248f45ab0b056e170db47b73900a71d368c04c6cd18e9bff92c8b73e61cfe1f7c11edf377b80c74db40f7bf2f750b3031dee0d603f4b5f48c527d61674b23fd67fb83c8ed63ba3d0481b5c0df5ea3651742c1297014aeaaada0b3569ae161ecc5c3ff3d6b9bd961080692fd7400e0445ae234eba47827f1f2367176f21aee056cc1a8fcf5bb37bbe67e6b59ca8bf98330d51923ac03dbe28c1bcf9e8f1c3896f9fb1a83427ef3cc4b0ec35a8ab249f788eb4e", "-f00ff2124a684797e1c944a51ed8c635c71b65166b7ca39d601737dc52fc2f336638287971c71511d0dd31e40e02d977869493d825c4f7218e952f68c24c37569ed9fdc9c69cd8f18910eea164cb72c964ba4621da6ff2f4172a9a0977b7f2c45ad8149341675b84e469d877c999e70e59b22437f430a478210a3c247e7100ec459a7bfab9f29cac98f67a9d5359559c033b61e80542e87a823ff1ec11f86be6602ba0bd877bbc432ee44ca57ff1922bc08cb312685c7c8cfdd3295ee1fe363eca33bf1ada55a89ae944c27d4139f41549c33d71926ebb545a7fedd820c525c1add8ad08a464f4f0ddbcfe92d3fd33178c4fed1e6fda633160e829eac3e64b5bf3e91a0805853c27ad7117c179faf58fbc4e84c1c1b25cb5427b20ea0ce44f56c919145058e348b1a9380458f7f27cf324f8ad", "-9b9e05a22912bb21541491363bcc475154dbc0026b26ed537714bfc7ee837da9ca4cdec28721f69b1324080c78413d2e1dad4ac06a70c6201490937cc6cd4292eb1e1320551a79c14cf57320e1314b473b775a0bc2152d1f9d9874871c7c14df84fdee177eda24d20ed21d3b95c99080dd526595706cfd57e7a9fb14073761ffec32540dbfee465b2404470961521c188f51295f2ab93e2627e9417f72c3dbcbad73e67df8d709430eb00c57c21af8a4af875cb4d7698b1b03b9c19395891e2274354ab29cb9712139ad189e75", .Okay}, + {.Div, "-3483cca9068584f8f80263d732df0368a662c16ec5931b3af17f015471197c9abd508cb9f30aef59633b660c10a1bba45008cf6029702f0b164fd908a5fd39c0309644abfbf9922e967c4c51b1c1e11fa15e0c16a30e4f7c19def334f849fa3205911263469da5d8d683035d4cfd37a5c7cf1d26319ea7ae3cdfe1eb85ac32975680196c9be92d6f6d396c9c3c803d121099122302ababf289bd297c64a19060cf319ed280eb2c80df1eba419e056784cc52d034b105796180e5e0d65dc4450d63bf0eaf3fade12fc319ab77b1b02d84543bbc440f5a5071c38417fbcf2d92b3a39c25d5dd06b72c09e5db042567260963c2566f2ae8c9be2dbc69e48bec9ecf1ad6c9205927ea1665656900f94b693d173cf97c2d51bc15c91e682d238f44047033e5ba76b7ade084d07b2944a01c00076ab27979a5559e22cd7e7f20e400fb104017e3fb55e90ab1503f887392ac40ce91bc6d8f90df8983c113f7eff551150b799aac484493a4697ee7b51bf5fba6cbbe1133396c52c00f42773170e94151fe463f98224210a1fcf9c3f3bc6937e7a39ec71fb1c21203849f09543c28a0ec0081fbd9c828e08253137bd0dbd551d8d2450bdd9e89dbf26c6cb3318fae8a20b9838e3d8eb670d0d9d48b6f7bedfbf149aa4c47d8f5541ddcd17a4a4875de6cf3948a87b04a414e4fe3638ff6f09dcaee9c1e52a5a2218a0959f55e49c92bbf", "-f2c3bb9dafa55a08f3871c025f144f208d503eefe5738a66d3ba6b49ac06525308760242d29ea1bbfa0deaac2b7cceeafaea28f1240d01753fdc661a8267d27417cf7c719c2985daa3b23f2cdeafb21451057e40da4f56059f587e2a550ae8bd8db49398a4b5bce2b60ce73cab7a3c3253bdb32631aa8207114cfaec78175c79b2563c88e05bc7675f721874cd22acd27a9284021794fea07dd75b1bb252391dc1f97e3b5f85a40714ee749d4c066fc026c43d76f8b09d7ac5216421f0ec501761a158d5c28cf19383e84e9b4c27d6881ed64ecd5292585b5302513ddc490e2a228d092262839a96bd3ed63b2876ba10e3e9ad3e42e55daedc35c54ef8766134c8d871746783aa9094ea142e7643677936fc4048d7b4f65a6c067ae9f22bcd86bcf12c9af648a0e13d4a7317aed1efcbf0e2fd", "3760bfdf4d294f8c48dd306db567909cf11a28e31fdcfdf75c0e5e41835d0fd51725ac5dc886be6745d458edf1b11b9adee4f7a60941befb54ce42c3d58e644d1535845456636cb4de1650b2877dbf3f3fde285225e48d7dea5fc979bbb1b8b39106f0e5ca2f7742fbd309ecbc7acc71133737b24d801e795f12719a1c8247c2040e718f0f1ba30d1281105ecbe8080fa45d0a5f384a22a9b0f4e2db2fa68cd34742e91e29c71895c76eee503f8b865f5e3a6ddf2f1b34ffc3df82fa40d0ae9e17f430f9b017accb389f789d9d", .Okay}, + {.Div, "-8b526b239c6379bbbdc20e8c3f3cf6c69bcfb3648436bb73f5c4b060e42cbe09a4078dd2d43431fa84b04f5e71c9b64e4a7a49c9faad4d69c811e22602d42d1060a76f92d26c998dfbb23746a7ca4221c752a285aae965fa4bb0a98038046d9c622ff074bfec0a65f6fd1245f7d37578129062002b9cddfa65126104b0a26d58495b0de483907d4bb64b62defdf784a07fbe90e774f83498d028f5f6569dbd857eacf9d9dad4d0f81c6af20752c5b0a448c11df3a57675cc261484e9982f2434c860508cc325a40e2d0f9540e92d6cc1481f7f10d49f856d44121f6c215baa8e13d747e40ef95316caf3a34094471e350c25cbd40f1090f47c2e13a0e278f1caa6e6c4d0f336cda35724a02e7cbf16e5c8a07fff2cb77a03c85d0b4c0d71a3c8500c8bf63a8e478fc5e31f769b70eed7f6298de68f321c80f12095d500b0b9a8ae8e74c0e6b4b14ae7dbd34d6fa4e3ce1b8e0922b1558cce1bd0afe9d20469ac9a0ebcc6331390d1aa8ea57e17d2ff0094c37b59f6286e4fc7d54105d370904951f37bf76ed942b9f9f3b95b932fe29d71ece74eb59a8ba41f6f3803ba00d17edf6b2a9c57e9b8334a43e651718550175afb2a5f0110e356e2a39a38409b98d57111a8229e5e64aa881ed263dc01948d629ee0957f5f8656f4efb2f754e02a5ce55ccda5602827ae90fec146bf23a66cb383fd4faa6943bafe1b7a285d7bb15a", "-6d2a37810c6713ea9fc3bb999d73bf9664068cf2282ed0707f122e22add636575357eb4cc049d4060d0b32a27105367080d1bd13322f5152e75dbc0994d9ec3c771950b76bd6ef3baced12c542d5ded0e2c661281ad772ff039e47175f21fd8ae383e7f64e266f49551c7695f0dacde7ef49c5b8e18f49e7082b10276345d04f2f025bd0114c7cec7037e07718ee406e809e151daf143eda8c72cca6442848ebb76fa9c535bee42f16ded94c1013bb9ec64b7a16d570a278e764a0421dc18f6f3fe6c2dea9fc57e76d944ca6df1289c1499db55696fbcd568cf1422bb40d19d11bf8054fa4e6df5234920cb144487b11c8a52ee4f6afcfcf8672d8a69f2c27da384ad86cc90f81a047fdf667014c8a644a7035603498876f064d6960a9e5b314d82987542ce48ef3a896e38208380c95b39884", "146b87585e00cffac6a9dd51643d1a88acc1ee3e64ea1726bd4692c55be3e23eb2971d88e7e9471299a712e03e1b5a05e55eb8779a8987e874c81bd8fd20ed6fdd7dabb1598b66a09f5bf0bc3fe772250439356e80999b7b6bc0f301e25e2969106b869f0cb26ed4e68d7129f6ffdf15e324e8165a8bebc25421e9109a567bc5c257347110650b2c5c9bdded5375b6aded635fc59a427cf5a615206eb2af0b2cc33704d94d25f4610efc17d2d3ad932bd3c7d506ac90c15f675a0ea1a30a9c9af3f1a915e1a0e1f92fb928db366", .Okay}, + {.Div, "3c6876e8240564380016e9d0740eb1d5465bbee2ce61d005aca631e9bf01a52368929c02de06d2da0fdd3a37653df3e32030934cce8dfd7c683201b9b18ae431998b26af87c3f646579542907235622858f6f0ce7bbf340878d6d6e160ad004fd121d8aade8f5a1196d6b175c1067c7ee87c5b39544ba650f985115421e2e2d3fb6996cab214462296966a16f0416c578963f4110869ec58228c92727dde0f4fae890a33415c6a5f107777f6be5ce6afc6862c34c9a3cedd8a8ab47297efde449f90df4c181211f49bb9749445ecb68966f69c5fd114efb3bd0147e027ffa79bd5621ff021dc821ec5280b48d9fb465fb839277a3c98c61c50f5e78a9ffa3757a8891ba3a74c5d005f4344471557a7abd0f6f5046d99e001c3b4ef35f1ff1908b9bda3ead41f981c60dd5cb606f7f31d6760b1d433fccfa5adf3cb0697b0c0e99e4d914072c1d6ba25851941d004f49ac2e0cfd8560fe0e4e6b3892705391bd37833bfed4a5751db30d5a7ffb092231a457cace1bde4e223d6b8b34004d15fa0f54426873e98620dfe34e59924139e95e87389891a6e5fe4348ed116ee7ce12d252c909e683644dbdb522bf43f4964b623e40c9e1a3b55b33ff1b6b1846576f7f7a7477df6803285a54ff63e60e2c3c0e60f33f5e1464c6b888dbb4626bf55d5fa16617dfd320833f34fbf0f00bd04f32307471dd9129e1f8f75b5aa40579b6e", "-33a8edc30bd8ad3d6585b8cdacecc68b5b1c79c4317ddbb62901b432c938ddb801c0efbde62d9ee631785f5b5f46ef84af376ebd30645bff0003d1cf9f0f8f52ee615f41be003506294d5bbc12e64735ac2a2b9ba6bb5e764986b9819c1d580908f367d38341261bb3f548898793fe28d9d423654ff19a0a9253b7f42f0f44c0adeaeba15580bb537a603b3004c95289e413e19ce4b0b281128cee2790ebc276e05369319c728b56bc7c05206e9ce4f7bd742df9a82316cc3b6f5ba0c0105a28b586cae166d9e1fe0c83d786eb0a033a4372008cebaf03ab51987179742aacd9792405f82a5b44442daa943afaeba2db63390ecce5623ca439eb4f47bf08e1dfcae1080d7a529de96c4854763eac82ced8ea0347669871c948ca438f5d2712f5600445057964e27996798b2dcd3f417a8df06", "-12b59ff1ac821aa89de8dd6ec116081b4d45430502c10046df13ddbd65b3b9b51a7e0757d84d812b23ed450bbbb5287dc407bb27d11ceb814609464a86e1433c122a1c6678e913cd1b26e315cee27be4c09bfb5736edefe6c14827f4e6ced8758dd182e97ceccaeb7dc2bb3dd7185737ba0fd6f0f691fdf9ba19d17be68d28858acc118df8b63343dd3ac58e6c5d2b7fe8be936cf15b0383c6cee0a76800131d903e8fcb9f2060877755eaf0ca7b5b99829af9264913966432085c00f86fb31e7baa6dd60edc72b87924fea025a6", .Okay}, + {.Div, "-394f50afee258177f0e458545d9807705aec672df33816b79a8992f71f23073df33e4aa0c78fd5c29dbf565318e775643b8df156ddd11f7fc48aa58e14fe68a30555ba38d4b03658e218d9eaeb56243650a870f3ef2b16fe2cba010ef5560ff5fcaa8fb296d1a4acae366a45acd04be0916e5944d6276f5dca1ca1580a30c03c60104f98130b30ce9aa5bff62ca07c664743d54c0137b66d8a967ff1279817d0f1eb30e90dac97f383f1ab208b11db00a7f89f2105d3c2ee327180f13a635abb8ee8646d7ba9da42e4d1fa7526180fd51d380a8fc72252b830fde54499f050a2e097b9cbc706007ec542393949251507314015e4826929aa00116f711844fa8a07de031d50420610be5e0ea9abe2efb29e842aa577f62234ad92283d03c8e95863e3ea184783a2d025ac2d2b743a7fedc84ab5d449a1bb704833739c15173c9bfcda13404ef05fc5f2810e96430a258a2571e15e26b0d496da689fcb7c50a370836ba378344508bd5b8eb617ecc34f4ce185d6642608a853e16e8337dacb695e4514d24f396b2810d1edd47ce4a013da42a567806997a384f916a8d5aff2b634347b7367f3a4487703acddf513ad7ed392484f82de4e40ac62bf5c710822de7984f3842d1b446a2bd9a0b69a3270c76aca48354d6c68c9cfb97b5a9d3f9c8d28cf90e1b3b22ce9e002ffa36971bb6c938e192d372c7003255abcc253594ad7d2", "b22aa6031e6de3fd1b91eb4aebc7aae12c1ee905b798f07fe5c37699be0e0b5dfc8f0eae7fc16777fad17704b9e5886e63be29e46e62a9cc8a357ebf1d35ab3115a3856f72d0bf57e407257e4c886650735cb97cb308ee21e1d73466e0ec9fa4fb450a660f5c89b7318d134b3fbd1f33109a84130a78c5657dc8696e9345bd7a9cbdb43b4eee1cfb6ad3142558f27a9f8085dad68471ec4eabbc3764778dafad6441dbaca456f71d1aca14dd9fd9121656a7923772292722eb85b05b6fdcd95e39986b7ebeb9e888c8df874ac87a9be89c2023ea9a02ce345de359e37923abf0b98f9a1f3107ccf0c983f788f8186e88547eed00b8a99556e92a08fa8744c650db4ceee05d3dd8582f19d4aca22f69ed69ab42ce2a526c0b5118b567683d80b0ad92d017402bd069af67d6a259e2e514779fa6", "-525896a7eeda818657719800d53a3204b2df41277d94bdf71a379cc3106af1300be5f765eb979083f394d98ccac4d20be441f42909759713ce9799761d66e06376bf5391cd32b927af2dcf6583ae516db64c821e0d5462885fa9b6b879eca9627c1a12a38fd7e69eab247fb9d974796e396800cef973d7fda4019de8ed986e0b7c90058ff293675ff16c83c3dab98656374112fba772ddc82facdc3d7d45028f2697bfe41e0b069c216fe010db1be19354b1c28bc83fcd175cb6502635e28c9b0219d0bf47a97bd52d2da29741", .Okay}, + {.Div, "-5652ecfb068ff542d451af195a6e5526f441ece0f609045de2c819f04b4ab101571799b36a6cd37ea74db038bd393354fc71bd8d787496cc2cd0f2e9dcaf14c50621a7d056e27f696a4e6ace7ae7f0d5f19fe86c72434d18acb44e76de553fbf615d51729226a59f4daf01a7b1cd28f04e5ddac93c0778c49466f876f59a37009d4221031fa81655c61e236f9037c8088dd9e0ce794c37cb11855dc10747fbd850fb4cfb067fbbbae032af6c311ca05fc4884ef87c3d487fc645bee78ee96c228780a12232fd3ad0d165dfe7023c5a5576d902b39523c877b0bb238d6f9fe892b7e6dd550af43c4f7bd354b8f41fa354e905fd65c74343503fe24c3205970bf63b0f8628c15a44fb96146af37476c036a3020ad2c21bc0b9d10038613d898ce73f50befe8fd35a7b2a4feb2c913e838fefd215c4628c6205539e56e950131d2b8611822fa61755e94f5ca0fc027523e42aca53b4797bcf7201143145864c9c7047760f6daab9046f74029f5d0706d7f9f9a8e254295ea1fb0e2298bab7af3a6bc8d6326433e58c44193435ec3e24ea36cd08c605481746f2cf4eb696290b53c0d388c7d0b2c27a75f8662e0ffa80c4b8abea89528795fa490226b1b931f4c4ebe0a9b25c92fb3785d0f76c9793fc28d67691efb88f53dc1956958be2cca512bf387c43e780187f449e7162603f6537434a48499bbd2a15caef7e1c385da3136c", "1b7e8950f257c0dd4f49307e5ed382c6ae5c0ef7d250dc0d1057007cb6abc09cb8b33ffe1419a3339febff9ae72a44dc34b1ce0c46aeea9ba84d163e99a196277ccdf36f23cea694f3b9c6470509d2529f2a5ef8eaa4f09ebb5cb85016b336789d0bb6b592616df15aa803d04f797e9428800197b6f7b88cbf9e55599d4055684fc3775bc1e7142b0e468fe231b4590e6fbbf26ffd5786b76805c7e360a467967c843743e4d8626d3db0b6f15cfe5c14664d70e72bdf401361ff453adf44b38f3f76d838fed59764016525b8257886fbba7182d97f22e7c1d13dda98888bdc38a7746bbebbadf6405c98969006f5c7a45a34eec8d8bf82a6742768b129f2cc028a838b3e671a2b84f892148c4e5c2345dd91be61ac6980937878c611b335214c8b6f350a8d9e561320486f25e15540ab57fa4b1", "-323c3afba6f267f291b9c48c04ac8fe1d0a77898cc5146982028524533958fd90f730ac1cfc969e5c4de3b944c331024ee18f4da2052914581e83bbbac1ce95303283b9027686fe15f023e46822e55f477c7719acd36705cfa6d3bb5586ff2275befa99699ba232023d577ed41b01f360d9175af83b954a79aa3911efd6f00060523217df686aecafc1fbb404a268ff582435456c8a0b07bfa86892a68e2f6b0b5e4965c4e352351acb7aca1276e88a2b0d0e86929670785321c925207edd3951d4c14ab77ba7aac39673bb7af", .Okay}, + {.Div, "63a9970a60b9936afdb44c606c8b53f127ee70fb6490385d8f2fb6ed4df7a58846e4a558cc9168e927f05fb67a15f9afd6863cec920896fd4f9eb288cd9d6930b1f5bdf3355389a52c2ff0e2b762df0e5a1ca12438c94d8ef24116ad8d9d1f46cc012e215a8f83b3a7bf079460eb69604dc8e84191c83129396281f1413dc25428df4e13206db55f24b21c13dc740e051187762f8238a7a3100bedb9e3a2f70463cd0293373ff188b411380d4ac6afe6de682699d006ebe8cb8d5499f6746f502dce9e452f856c9dffc9ec3002c80eb4ee1ecaa3f99a4e90c96d35bf5c1fb2e540491060ffda5837ede5609941e6f508f93066ce6b044f6c3eea761b5a35d3da19045dc79640e5f1a0ce114f439616616bea0ced6b527ab85e6261740385caa3855bbaeebd532873a5b5d97da8bcb9a40f51559a58d032181c1e69333df15778b332550ec1411cb3ecbbf8a6245da2ff09e37f106d851fb34259946ba53d5cac56ec818caa5c5474fd669bc125e96eb5c13181cee830df1523fa673bac446c4078d29ca39cde30e1169df4c70a33f6a2fc968b06ccfc3d3ec7df97a8c8c0087edd3e114a06478a4e77bd698c1fce39d74fbee6b2e5603ba6592fab9d1d242e77fc1a26125db70caf3e9c848881289cbbefeb3113d5bbd104796a817048c2644c0ac2f004a7ac1cd0f3ad17c16743025d53b18f15b4b18828051e0f10eb5e5d25", "-1a25258614b75920405f40e02458fe1d839c4e2f867b145e538e4cc220d4f9a4fa955f8403826b3c89ddbdaade0f46a21af201cef96c3685ff5ccccd4d6f324f71fac79e333ac8f9e05330ba73ce7a006daaa337e43f714605a43e16b5d1398d5616da3e3e5cb6cd9cad10013cfd08d5eeaa26a9a65baa3280c56d70f8abb2b4a68aa26fe574bee635f85d07e6729c6551be7aeee646faeb63ed07480b9e71089e50abe80e37b155e38b473594711c99fa4b351b937d6ee21c84c7d10f214bdcbe0d9675a5aca167270630f2b28a4b34419b974db5892c4f2d239e1aca15d6af153b7baab23906cce538edd043d500090b258fff3ec4316f7420088f4b795b82f0e4ec3b5e4508e8ff7b32b386e578b358879e3ca51ab15e93c5eadace98770245a4a28e7f1e66600fdd1e40b549d51f0520b56", "-3cfd886facb70bec83775b6e2339394a7a23664f7d25ad54dbfafc3aa18c9f733ca95490dad09d48b6f912bd9cbfadf2acf31e81b9d53dcbc202febe30be4595f919b7241f859a6271811a1b0d1ccc801a4361e40ad35d236f8b7089136173f9f81521294fa645bb53c5271b33b35a497d5259139ee82ee69a67e6fa8c18e6a7421dc282f7285e6141fbd13500642909c9f0f21a38d29b487d1789886558cc5a6f425bf1e9d27e9e2e2ba40994aa2688e347d6367058e7b8a9ece33b5c74006bedbba28cb0dcb5a9a1dca9c422", .Okay}, + {.Div, "21d2a8df42717b681162ce4032a6fcce1ab9c2e3b2758ee4b56417fd0f298b1fe5ca24139950bee8396561822a39c7ad9abae83fd70b75ce3281f45f584eb8f4cc6aa778bd73553bb462ab81db2d6cd25bd9a54ceb0bcfb7c4e58ae656ce3f843aa535e4b51436897b66c6273d63145a2c793dc40bb9379ce85d7a9582f1e4d65186db80a546b74f59cfdc2c8789901ddf1a8e4b1a0569b62859bb69b2d3087ba048da3e2bcb172f5b4693a40c1fabaa2e2c9a6728a2edaeaf100cb2b262121d04a25807abd634fe0d720d00f3271b20c5eb83c5a01958470a31ab40d5256a7873a9a93847990cc9989b44c006d6c3071619f2521e656def825fd62ee855e7d312cd40da18597ff1cdf342a31c4daebaf0f71dbb3b18e5df85e6fe823fdbc85d0b8c9f2f37c5449a20e6582f08ba22daaf6c0877ae5b52bedb23245ab317f50c33133d93966bbe1970975e470e8559542b4f960c0955c40e3d934042cac8a6ecb4dc63711e9c4eb09df93e277b20f981e8e17bd2bd14fa4812cb6187d4aa57fba79aed8150539f9468a026dd3968e82b3723e8c12952eb91da81d07e23636bc252c9bcdcd4dde9a01444e123944823cd73df534fcd7a6c48c5b708380f393dde3eaf0cce35fd590211b7e931219a89a54b25977dbb3d6dfb2465efd0bd374df0cfbcac8043fbbed28d8d714afa106687a2944958a9341073d20e7bc3f59ebe45", "c468e368808bc9c858207cab01bd26923d19aba178c7887a90100ceea141a6af31bb306e92912e2ef08f3d570d4d95995450d6e824e17e8554b0c91024e8debba226c9d41f3b880b72cccbc1a3b8311c309e5dd0cde2539ecf4b42b454756efab81ab72e0b3dd6247d70708e2f6fa1e329042069b8f7db0bc4245cb819118253f81cd5919075f071ae35d274ecd9a6c1a1bfc0d99df36787f84bb73509a406d7f63364f08b06000b2388d5dc35c7a4675178c4b713dc167c7642d442259094e704e4e3ac3e5ede88097b390442567cfb9f8762e75f376ef29193a42d6e3914b12a1f1d4ef110f2f812cf1fe1247b2dc7f35ee17e11e7fe220f141d8895dcb58a7da0f15d18ffdb99907aa012c11e87b15bf340ad84a5698bc94b671347ab714f955f587cb6d4b9a4db029bb513769ddff970db", "2c15ad96e252b24e8d6c45d639c27459c9c94839ceacfd968271387adfbe2890b954a87425281288bd9bc64ac22c1390c80f80192972051c74b5ce9ebd3466045129a03bdb89058882b9168580cd269ce1339b2067512687b975a689f77b2c9340c20b07467025f4ab77cf9c755374defcbae907bfbd35d2703748d0283045fdafef5104971d62bd4326bafd8240259bd362613b569af7feadaf1624c6dea6eb8c9665870f4e4dc330663d510c3a87b5249a219febbdeb470eeb6ffce312a27743acc188eb2eaad031c22ab456", .Okay}, + {.Div, "-d6f2d202db19c0f2bfb2492aa500fd8b1c4b8643b56dc03672330837c2d634cdf1fd4b42686ed8e230981b7158425c527847b4d6ccc9f75e2989cf6216e1bb8b09dcca00cdf7eae23f9488c069f3425e19f3951e48f3e20a0eefef1da17ee1e8f96f51da1f2c3952ff86127a2de523ee9098a3b7d1ba44e57ecdbeb682f3db0eeb5ae3521a8d82f76db342643bb9ed22fbe0e229f3f163b6abf6e5937bbce0269219c6e2e73d14921ae49bb8769d12bc46cd1acaffcdfa8b10cc375a74b4f776efab29140fcbd9a58398c06e898eff27d340394751c1c1aa6db4c12fd4d935e640b0229a62f6a35e863a8a6d062a0c54483182bee9ebde4bc6f412a22df785d05b2562baadc00441d8c85e043f38c2aa7584f62f9cd380c308d44fddce7a663d70abd9ef145b7eecb0ba3645cf83e68be7c577e1764cb3e10c42789d356b727b00f224e6e4567e7dadf0de7c03b8da9e42b6db24011452be86d6ba38f26a9d5ed86a1c2319eff5187e7da04077f913216d859eab4b4ad3de5d35810c0f8eabbd84eae1831dc92de0deb7678b59837cccebd350ffa12ae2ff14a13ea0ceeb4a48ec0f48cf54787953591d4ae5fc7e707b68b1ab0f14c17c9d1897922e84a05dbde771388567b56a904dcdded308b434cf6f93b43ae2ec15611f92d23e91b9d7ff394b9b2002143ff311fe932dc7a1cdfd666e22f15ebe92ad9fde581311f5b397", "-1a67d84464cf56b98407ddc907b6c45675a4069cd0a65c523a0a3b5ad146cdc234b68db692102d558338a9fdd8ec689a308b3a4aef7d4634cd3f392c18f501906f1b015f060681b457b9b0383a9a4ec0df4e53cebb4925583364f90ae86c232ace9090674fe48c84a250abd6ce19cc7d4fefd820c8ac15d60ed24641b822c1c3abd4f9d3eba49cecb385dca4a5aafd1ff1162757feaa38d94add74f235fe3f2e6078a3af9df5ea5317d493bacf6371186877c8399e84c44477981c8caefcc377de5535eaf92984f6c971c85d095525b8f534414c71363ed2d1299d81b9e45b2e66e157df05f2f916fe4a2a1a7ebb47d4ac26a64e5cc8a53e5967856a08a049d1ae292baee90e7b1fe30932a0d3dda3d09748fa45bcadbf3426878ae7bf231e1251019f40feaba0cefc44814e1ba64c0f529269b", "823e75d1811abbc7db9ab077ef5d477b33b0bd0b84bf4bd2d43b8d42e8c9d377ea8ac49121c41208bc929bc8f032ba09aaa3ae1d9a98491abdd71fc459a538434e85df2c4e688c811ad342bf612ab25028d175a343ca0ff4a86fed2e774af7a2a9d16a3b5158d135fb5c662f0bcf922f9095188ff18bb6b88c94f8b1e5999e34352b907af8f1afd8243296386f29d2640c8bce2f169591b92c7be38a8dff107b2f83dc996e4c6ac0a18e0fecc78a52a088d5f365f1fb3fcaf6c166e6acf43568893f993510cdb856558c4c7094", .Okay}, + {.Div, "-20ac7bfe9974bc87219cec86389315c73afb5220f5f25df890e27a892d355a5edbb88dfa91131c40ae245bb8c5d336dfd94289c6b3db330534a2f412a35fed5cf6d4d91dc1de9397fc5bbb424ecddb0bc44cc9be12c3f65582edd63d696f591baf2eda4b2168859b9c0e7277808c8ada338c0b33ba2154e66e7ecf8782c2494b6eb5855bddade055bc319ceb07ef8ff9b42cefdaed1c7dd051f79b13ed196ac0c368ce43c13440317049dace6a9ea2eb45510af7f91e5fad8e5c6c92f2b9e189127390d4e9c67fc6ee8c76727747ffe19f4c9ebc4ed3890e03da69f132a900a21f2481eabae0bfa2bfd0535471e277ae7436339aed7e38726fe64e3770575c7c5ef7cb1a47bea09020b45ddd262a1d1a6bf7c714e5d67c26f45dfaf461db2eb10aafe6ec735171eacec98ec62676ac5caec0a358338d5ee8dc23d8ef4aa5434cbc9eb90cf69a6f1aed1874999b8b2a4e14216eb316b1fff7acc2d58645383d050cc0a0bb290a6d831a401df34395a360d34c8eed2e84d04f321d9a313721ff6bc4bb171a3fe131e096b85eff80f01db908cc70d88cfcdc050dab70128c720e9b7a9bf529c6e81dd883798bb68b918247a92a8ca4aad6a7b71cfcd53381235ae2f3ac9a350c240059cef0f7c717047bd73d0e34f3b2159f37a7d76f1dd3ba0389c6f8189c0a7e2f8cd01de34a06464d111c0fbfade670f6a97692e433f21700fb", "164dcc59fa7a68382972ba8cf98d687b6b280ceb3373def09646fae18df359f23f3e276df3dc8e9186e7ddbd825306b6cee89b442284aad9b76f895f6199be53678f0d340752e6df240fe80b88db787414a3b87204f755575443f2fb76d23c45cb370bc4b516c70c4f53a81cc21209c037e6ea4fcdf408b372056128b66a2018a9abeac78f8a6c0e1f006166b2abc668f554b4ba1fff698c18000cea82d75cd87c17d5aeb5148c9efb18544226914b49184ed3fdda6a3adde456b6456933c123f3d066884a90fd9ad8ba6f26a9757d0766c7274987e3b735bd1923339cac6949f13855360751dd2afa8eb2258f8135e6895eed8808371943dea7c88966d4abc383a1fd4f6272488cbc7081b6543f13eeb743d81e44afb8d02b312a065dccdc625efe45fd9932f310f1f65ba54d25b9415731a58", "-17705fe070a631bcc160961eda0e9f970e6ddaee87f4dd11560de1dd7db141610923a0aee52043c4884a162dcd0f69d681e8c2404fcaab60e8dc0af3683bd32bab56d96ca8bdb7c92392d7658994dd373dd18a41ce4328695abcd41c960d3a26a0ad1473778df58410f710b421ae345a002dbbaf0ca23236af89e18683fe7cc90181bfd9b3f9e2b01f2a8f474ec0c7215d26749aaf70febce3a9dccf86ff905f92c19f383ec93369610cd4ddd544c1f908da02559b6ed3846c53b98d6028f3005a873b542d7664406e845355b0", .Okay}, + {.Div, "6b5615533c3c548cfdbe78814dbf54863e313032073379b513d69ef9af20fe0fce878c2abe7a6228f60eb5185421d171c23c0224b4d81c603149547f32d7d30c84abeb48a4422806a4970767c20543e4b32f6da7ae7ac1ae2197ee25cf08f574085c4a39560d0d97c57f06aa981cbe4a45442709e10b1f353f567e9d0e7dc29473bc04209e50698b581892274a454df67d3b62ceff2eef44af506c785a2f19f5bc46fca44147b0f124012995ecfe5b3c222759da912e10807820fe5d44e7ea3eafb0e8212ee4275e625b554710eaf2ada117e636c9e0ca376feadc01d7eab9d50403572347e36c423305cf8745afbc0dc845acb40c5f353737745f9f724927913a0753cb901bd99b431e12facb0ecfc7d6afcb53b8bec71a093dbc454e6cfdf21a78d1f393e476e41f370a68bd5e38461ce2bf93702fa792e09bab9e9e88104cf4654c2ddb7ec9711472795f8b19ceafaf34f9e3f1ff61e847081e9ed66455805379f528a8ec29807d852f44ae8bd145fcc4e286ace738bfd5b94e7f9c7effabe21f043950da2cadc276558b0b9b947eb25d0563569a79ea3cb70fd120989b84284e5f26e2dafe105fd8a86e4a33ff4c22eef1681efa51f63a52bbda347f5cc8349b1aab66f77b13905b403d2565779c336e6e62ba15973e2fd9507d9d0f08d9f49730654753a6a72263a5827d194b7a06bacde50acaeba7c4b677ad4b1e481c", "-1547000376113557679c2184b980699d73ac175707b8601a310ec5801930e713e5b2e545b51d7e1f9bf36b0796722e41ca31a91710aec4983e04bf02304e5da11b379e66709622ecfa49b97c7a3ab08dd3e97c8f5d4bf35930b86dafdd7d983a2d49d6fcbe9241ce70a56948ceee83761f6cc9a41531e692e6eeeca11984731dcb8edad7918be7d8031390e18d9eb97e591e8827aaaa141174dd1d7fa91be544465f0e216e7d8c85a5e146529e62bbed430e732f394612ca26d6ad361ffc7dfa06ab3f0f8a8c0c46068d69410a0d50cab76ab78b8e44388ba2730e18bd2353377b6891d23406d6c08a0f720ce6aabd97c5e170d51deb8e452ff36f6cef5f70e07ef3e15c7baccfa300e40446fff732e0174569c4499dec6aca681db9a400fd20cd7763f82e96b1fea3b965ea4f87cfc0160da8f", "-50b6cac18ed08350e1f8129b255140647a63745f4343273d5d0bb5f9426b769c7c44b8a44671352e643c490bf55014fbb9711b33b2dc7409bef006ae207e989451274cf9d5c4dec89008efe537ec07cae8c6fd69214905eaa34ba1b1eed5e44e5396685f83ed23dd99935ef07651aee071bfa08d5206d93d42b683cdcc992f63378eeb3d29c03fda6f62e6230b9563f9f1107b59bb52140309e7f2f5cb190710a093fe1b198edd4c862075e48b309a020bdd73550b7cc2020647c93eefbbcb1789c9fe8bd0dea518435b6afeaa", .Okay}, + {.Div, "ecf864049f238325832dd3fddcf6e6784641cd2568450c29d3def1240746bff615efd413fd331befa82576edd5ce05459e04930ff8937fa261ef7e1561726b0a5735a830cae27b0aa323750e11346fc5e6b8fa5233c35795019ed7ecde77a7514ff67cf98b9907099a423cad187dff40adbf953df7e77cde7141f07ec6ea2f6d4c22125b1e796b01e50dee122a76f3ad0d080af0f21b807c926b42b59c9c23b71b8ec6672c3ac921da8b211f25733d52c0c76e37da20a6d26a8003fad1bd7cf0f5854939d5d5970f55191090b28bd42bc95b4d737f0227aa0c560f17068499b571b5be196f9bd0ab92468a959e8b1059e3a8da2215566f8a921009c1ebac1c350c3e997fbff723b4ffd28185969e7d3e9ff672561ede229bfaec1ed48f3c2f5afc2009c01489276c8250edc54eeb4cb3646f8325f36dd745d4a9c9c2dfbd4882aa0b8f01bb38bbdd6d63ca5925b29d65ebbdba4058eedc1dd63567dd83eb396c43ac5666c40273b41dc7957a227d26d312c88e218a34b3e6f78f7abf193c61ce32d25d9fe27b1e7fb131657854a0b6235a031865f514429e59abc597bb310f3ca4a3ac62a30f8d4eb11f95b500cd8291d470ec29d67af3b7c5f35b35ada84c9b866653485b9f91b3944a24b17041f1825fed5f4db911d298e893d87e4ef121f56c99d4e23e4cd7b95ac799e345823b4d98735c60668e27e48c1c2663e6eebdb2", "1738b6f2b5c7887c669848615b5f6265f9255e0680199e31af165f9bad5960584bc43c3afa5ca3b9f647bf92431e108a7f3ba6b83790d20a4a73907ea37f7519d2b38f879d7a7d32b57effe93490990a5a1f1c3bc594113ff7928935f4e4eb4d237fe4a8dd55a962f2b8423c46eda75679f32e2470b1173c864f1783e7deb296f3552f411a32c17d46aa8ec2aa5beb0e5cfca446f34963f9e1c1ac9779d342070cca0171ec5c8e1728b17c7a1a3ae2f38fd89200421d6a40a83d72a8f230a5ab9f3f286177ef947c5ceebf610f6bb2d29f99df0c27d0e8e7f92ab8ff4947d060cce461182209b8d0bc0ff4dc82104f647fe26e5bcf8a58fba5732236d51058b333b3eea1996df92395018b102523b97c11a52824067327cb88d6a6c665b04a988bf15e4902db622573028b425e647f7e9aea5bd", "a346b337e48eb15c7b02276441d579682a0e5cc11e1b7487dd449e6ba0376836a8410c32f0e2c5322fd281925dcab20d0a89bfb288e5227f77eef9d3b15105e6479741c552dce04b17ce5ecf083a090f1b1f7ebc5b0d166b6836f56b6a822fd29df2f28c99abbce43fa35b36611bdb6680f32fe1ca18ff3c925b20967e6d9b1a5ed658249500c5d8cacc28e9a2e4063989b7e8a04c81067c1d163bd3b1d9f28e3015fef34218c8459e9c0f42f604de97e41142794e7b30ce96e9fc5f1ab55ac4ba016d70f115aa443873e8d38e", .Okay}, + {.Div, "84a78b22e8bbdf05811f3d4ee5e1626e54ec4d887ff610161e74a9181bf4f795db3b48f4bc0a04416fab44de08f3b5f36f492d0c3c9dfdd03f700706f704121d3bda967173d7110971b7347967ead9b01037b25d16719acab45553cde8317337be2878ce0ade5f2ea63b7adfe85e38163a6cfd454058d62b13a3aeccb0667f1f98cafb57733feb382fb83b25a9b3fdf38038ec5ea8012843a0941b09c755774fbb98f6848085041aeefa430b54e3087822d63796a5169500c0c28ff0732e409a5fa7467d600acca4d25e4201811b77ce1a8d3f78e6b82a8c6150eff4efda7b5f4e01f688c34e8d68d31d4e8927c6a2dcadaa92be91b7ee0d918bfdd3db8272962f6b9bf0812a65c8c741d498eb958cd1debdd911df3e63b054a99331aac0f75da4a94152b9bb631f0416320105f3cf32feb4093dd79a4e21d3570b4fb2b973acdb1689bd348f28a275c01d8c0bc0fc33145e1ff212a35081027f3a4328db08512dcaa0386229b3643984e618d940e9251899d32727a4168d172c1ceafc3c1f9e36306debf2f7cc89a43bbedd15a97b29522b4e25fa69eaf6fa6cf6c7fcb7b7af216a9402f2a5c1a89a93f3d3d0728fdc3e633bbb5dfafd3646d8d6292d7cc8729903ca4b591e08d6adc4a7eb8e0bdb3a70635ae652ebb0819e4f77f224facc9dcda6cdbc646a449c3ed3345432deaf4183b7b733e1de0c5e70b08c9c43c4fde4", "116ba4107e942b4bdad44c3949837b06281eaa032d94d59dc767db825f1659131ce65a8bda1350386bd9e81692dc8b09b6712c086b47b875e2d0cf42cc21f0059c34fb20cdb44ded041376a6f2068183ca7e968a07040f07888911dc0bd9f3013565877970f71fbf2870721a93c5cbf7a022d3bc949485db2177a7f817a83c7e1f3cf848abd74ef76026f09247d21a4b2de611731f67a0475e7d5fcb668b13a1b0dc5a4d0bb7ce730b6f44eb37db35056a69fb603206c8db14f9c61260378c1325ebdb24a8d2cc7bb3b64cb914d590f9e1d2319eaea27182dab2c14fbac2b6ddf62d0a68b6857548866204358d2ca70299cebafd93b649f8ea4cc83306e08bd4700f51cd4bbd096a098d990e17d88582b25627b9260f4f8fbd71f32815f9da5a4911fc72959ba1c1b475c1e4527aa32198c367e", "79d6780b7b6cb53d1f8287b7d750ac8718d14d2cbb7ad9c92bd1b5af29f8fa44ffae4beecc51f2469401f29319a7dfd63af39665e97a5a1654dd7a34da5f77254a8c88351cd12ade2e783f47dab66931bff5276ba3d5124fa90ad6c0943d3142dbb45c92b05e6a4feee9c15ca53e0065daf079327ee7c7555b73a86b7935126e90fd8759c79492e8bcb853c1836c4fb3823c25d82afbbe79d8a51c7d6c2d831fbab68c20ac392dfcc69e4497ab7414bf6aeecf14c4ade8addaaa4dd2cea6a8532d6446ff9bcac27d841c51cd33", .Okay}, + {.Div, "-119c98aba545db12841e3d73c34f0c7aca1c98dcbb6c509abc256f8fcc8afc8783c6e310eea0763a5fb409f75116f647673397d74cfefd458ce2dbc93e6ea2b52a1f723a6b8030c2a4b0f45f9803b7cb14de4100dda50e63ecd3d8fbd6f99a6828672ae404baec7a8bf4367857ea1892fa1b140b0653ca891093100a1bafe05306e2990243ac738bed8f3615c25789f1f4247568650d207c66a1b0578a8a82e79e091aeee2da7c29d507baa7dafca0ae491646b09f77712c7d744189cbe78ca3a3553502a8c6d90fb7ffb068eefb69fdbec0b7a410cb343e404cd4aec46de7a71b28ce351ca93f487f4b7404e72c98542011b21b80ff5797830fdb38c641c345496dc4d46d64d1267e5253e7195cd71a3f443632f34fff6cd77c9f8f8d63cfe7586096ed95cf240c129d0657cabc5af97b279eefa6a46f8d67e6509fe86e27abeb7358de67dac05234c34895c539aa6e3d5fc64744005617ff2d77ceaa5d9cd9965e3152ef8b2c3813954d46c809b4725d548ff526593ca84b49f59954dd0db7b7657864a4dd0aab43a00d0aaca03d84fa724afddd2710f695f1c3ce26e35265d8ca6bf191662c164a1cd4b88da0a411df1a60ea2e5e0c2091ccaa63851b8ec70f3f71c707f99c176b4a5d155c1511d3dce31fe3ce44671021c922824439b31df8f7f9a773f0e9fe167f6ae02d0e2fb00101110ff9404af52b8a1c585931c068", "9979afe4445effdc71e4ad010480a08eb94d66a14be88411e3038293ce635413374f5fc157176e3bc71b040dcad748aaf37111f463ffb00e2eb7c17653a07174595a629ffa0a1ecad6b9ce7ec0f0d08616a341d4f6d408b8fd8af492a92b46d9cf6934beb9511f10630abe19d3444c583d3ff9246166510f299c46678efa8eeddba44052d37ce3ee8237d448163a56c09e7c273d0f7f0d57624a6efac67bb043a0354de9667c29e492877e0b0d439da0f2d7762e342bc3361a84e0cefd7e191cc5c205fe905cc39f1396893995deba46e4bf090d06717c091f8bf732c548128e842d85cac4a39df493002dc2016fcf101ccb337e2139e8347f64c19dfdcddd59e8fea555f3e08ff9244191c46d974c81bcda492c1e62ff97722252e3e772f9f03d96048b88c6f51a5109f44a8f6924fe4b0a88", "-1d606e46f55318d27b3b8dc88509eec3e8cb4a54edf53f68528017d6477bc3aaacab9360feacac1623e263d9b915861731c769d8e145817c2252606b264bdee4680024df13c67f46dc3aace225f5df40f232fcb75be5f346954e895ca2186333c6a0a42258bd11ddf120b2defc5130f14fd0edcf80c4c63866f918c8506525f1b22b35bbd93a489a3f4197da3967539e985d51f3c2e90170b3a9c2af4b02b3fb49f0edcc7c5c16f58e591a6aa341fdba7997621dc2e0757cafaff16ac5f8403e2ecb016ada6a062c5c7a410903", .Okay}, + {.Div, "-58d292704c3eb657d41c3162b302f2e78671089d70053511205f5f4e3a72ba962a02eec1d1c815ff62419fabd9c136dec87cca1110193dd79db9921378b72897fdfe7c5e36b5b58fa18c7a30e69c89da74931e6cdd0983f2c6c21f0ded298b5c613d84e2bcdfb515cac46bc6f350206813fe588d114892ec70b75e7af55ff64d792d4aab1a949625409534f32dd4807358e0d13b818811cee8596de45a7331960c5ec334d5cca14fefe2d85a2fda239b6a3b180d9d566c5b42304b2415e1859841f46fae27db04351333b047010aafd79b23bc507af3ec3c27f77c4dff30d60281b9d6e3f89084f7ac8fc722b4b37d5d840be7ee9d6a6dddde1daceb51f31aa15a69b8c35952091b9852d1ea861be2bd4192b679b859f5e35ccc89c2b70884597db83dab673e98c9f49c75999757830d0ba32125d6d6d4181ae3be29acf076c303729062f3cec58f3b76f68b51dede888378294ecd77f0001f26e307df1c153577e43798557a689e8b64d8ff7cb9d4c688475694aa6838226ce38208c15fd56900054d491ea08b118f54648e42a43f74081ebfcfcaf524d3dffde5693453538beb471cfd7d95d4406bafcf5c24154e9e956af92eb95a10139d12edb553b469c6a2a795ae2f0993b1e0a265f2008f4058f2e8837b61a5f9e34380e6f5d7e2cc59f1b59472ed84ee56d130bbcd104bbe503d3d54d9baf5fd3b6d683fbc5ea03864", "1e75b955b0fbfccbe3f432946e7350d1a93947ae1fd42b4f971546242f165a70ec008d0725408eb10b1dde98918c32d0ae208bcd8b89381cde9f889c1707afdab6ee5a257f5fe4bc66edcba121a7eb6a10654cdbeac8638c5eebcc872b435d727dd63ac922cd05dc611717741c2844fead07ba30367137d2c628040c3e5d45cf59373da292f305320abdc35e27d6221e7f2449d74248131774a9009baedf63611bc60c453f43b7a1286aa08c93a7e11d7bc8406d18ec26659db2acc270850a14698e9b756d2dca52e68db2a74093136a0200b94ee2278068c00e132c571d8fb5d7b1a5af6e82e8e8b1e591143a0176ab4513f0479ddefc180b78e07ed9cf2157fc3a8a6b975a33f426246639ea593f9f77fd93b33c22a1cd42cf61ef1e3233278969c9e4aa2c760b597b3c469ef2b979c0ef78d", "-2ea8269ba7954be407c2d5beccaebf83d19f446a15b9a5c8723f70c11d5556e5a66982243d595a4587708f190e9a57edd8af626f272d5f7a0b3498d7b1bca59dfcf036745a1bd36fc0de9ec07084da627c1f1741fab42940b59dd70d1a2d49a8801d4ba65b05b1f5fb228ac912d06d1f769956facbc3cc92896704f0a6fbdd6e3b14788914421c09e1a19e0ee2763cb7ddc82fdd3f5a8700e84017000de0f376b0d716033c8981fb574d5343ea674313db20b3003f073e680078c58d3046f2862b87e98e3eb0bc35fe1d076353", .Okay}, + {.Div, "-d5eed8b70534895bf5234ca0d799c15a8ecd571dc13873120a051b56e23573af79eb2d02e6a3904ecf6035e1cba3056eb5161f6590d198bc4eb325b1284395efdb175155eaab9cfc6e35c0cfada6bd57d0b0a1f909f3de45197cb94f392c411051d75db7431a23229ea05317219249d707d3269d0be02702627eea563e0ab2a576927a99ee394b1983953e21bd54e70283a9063899334fe8ca2acd562e0ea1771cf3b5bce41e54632a3d99b8e0d6c3a0cd15e732f31cbd0dc1ad5d7bb74e02789923d9a6f19fdc1e970eca3c8b2ec9733c2d0d9c4e8a800d315615d72d5adf6bfff5a5d426b70d09ddc7aed29ae24f76b5873eb398a811f5dd776b5d6dd0bb887524d773f968df76f7fc799aae27c458132bf16299b96339a2080a6e4bd5658ca02791f7ea1cb76b572ee0ff53d5075edc58cf4c7e756894ebea62439758e4dc438ef4ed5748f7b8278dd14a3fdb770f53ee131c5735136ae86cb3c4b96af71dcce413c9798864cbdb537baca9a62aab28c050b3b31d158bcb8b09372808bc0017f3a30fcbfb051ad95bc9b8c706d6841c36d7ba5dbfd4ef5598f782917ae3034008bbc5033c75c3783ebb5f8e1d17e6d403b3b7f5b02be031deec841abb11dd418e73c76ea7b50bcaf14e162ea2041b8c082b77cd9a3d5b42443281da1f2bf3e8ddd5d5e57efe78e3028697d04a64f9ccab0b91015fc0207beda5d3ea31985d", "1ae3ae2ed987bbd5363263e1a16091624e6215c8ff073ffa1ea513c0fca4f319f746e547f0ebbe34d07893562203ead9bb591c516c100f68e77a246c3fc2e0c5f475b1fcdf2f8fc9fefba8962b469f4227008abe18a6c849dc4eb80084c439078dbb3dade39e4164cf46c690963ab8093add567b538940ffab1724f8da182da9bf821d92b1a364d6c65be6648033cd460d732595cea6dd4b28374da506879527790296dc28220ff7d977b8dec0ea6fd6638aebef28a03346f7e389f30f18da116546cc886bbe9ebcae90cf8505507a0834458f8d02aa7375bf67a804433c26713a8d54b30050bf8033bd154a6ff9bf0703219e8a134536986762ef9f4dc826ea7d52f958f18de4d088d4c84d90518394d69faf369dd50b62fb30906ce3cec95752bd5b419dec382c98b87c02278e0bcf5933263", "-7f4bf21bf7aa40d08122256fb24de1719e2444fb9b0d990d643ba56369f76f11265805d57dfa6f19dd70e50f48f13e5a20601c79641fc27dfe98f9ca43f843b970be15d9b92f81a294ea642f99867713954f477cca82c8954f5d6e0a668ffd6b833f53533a9d2d52463de87294f0957b00381a7d562a77a9aacd5e86cde65a917b05b24f1d5ba84701c4c483bf0f89bb25037417020d5ce0986965b0d366bb3323e5106194a3653b7ca794c4ea748fcfd9e609f4426df17dfacf061cd952ebbe3d41706430b83040728a791d4a", .Okay}, + {.Div, "915f0ea3706b1d84590b58ed667d86e639840da0218d77e18e33925a5a29669e847a464efeb9ee6664ac7f7a1bb63b7f95cd19352158e625a55b6d4c77848e7fcfdfc866100183b7f35b7efcfdb586fc0d4f46d6450ccd5caffb21e17f0bb410bffaa6964a7add3f0f81469f739045437efc22a265cb7af5ccb0dd8c8d66ad5b3b62f244a9e47864ad5c6509f2f9f69ca1f6e6bd3e0ca2141b807f4ff4583f9d7497e0758fa09649342a6b0e1f003397558e722adccc2498cfa12e37d5b3d658dafb71d41ed6e3790dd2cb8647e49b44f949e3f9e4512568a9773bd3b6af9d075431d45e4045965b32f3b2e31ddd0b9399c607050d0f1d268181d13bc19b97e1948bdfbecc1404f970e9c0c1e5800d170c9f2fb8c6d8ad47ca40eb6c50e2b81db90c7b7aabd149f4a176ce6e07a72aaebaed1b48f8ef5d9ce154e8b712315f0e609809f931325f3d233749f3ae420144552bbb31b39698d7fb279e750bbc39f56086fcf5762a7fa45cfa7ef0f96969acb1b01472db951976d47b4664e84f9f4b7f6bc7cdd274b08b469253dcdb74f55950d981834dfd32d8038a5a89daf31218add3acbf5c0873df9e332b47f0029ac9b187106782a11c086e520d1b29233d989b070c0807fbb194fd5c8bddcaf12fd0a1ff5ef43dec00ecab121cf05a71d4715c47d17b14d7452bbaa30a90e11c9257c95d4c51d373bfcb7f1542f152e51211", "-134d7b83d38510523b4d93b780aa750827f6f733a034e8b223e0fec6ded130baf1a369c3aaf204629ba474c8b2a60b3eeec6a72c0457ce0c8f160c90331d8e3dd8f6ca2e49ce54e00b1602562f26db04df2919194f22a6637cf96e6b395b525e20fc84f4d530a6d102358fbcc8ec815d58c563fca993024c7b44a35ee743409d8310c3cdf531defce97db6fed78791b94b461c97e0d37e2d817b358529b251ba653ad41142cfe469bfe1089bc1990d94af2a883b45dc0a4cbfb27045ddf2f4db339b22d110c202bf556fb8246d614a68af83e8f820a045cdf8e5206a078f8d97934ea6ad749a4406165428e97d9f36e8e21f56c6bb900b9ee5daa2ebc061d7f3b8ccc23375b9ded3934d7f35e65437d015d69f324ffffc60a552e35ab618fd722f906c4a3c2fdec486d40f99c3f6520bfa410b7", "-787f998fbeadbaf3494d85a6393046a9009586d1379a3635e86c4bb0ae03c5a71846748c27d951ae845ffc56b9476cacf57c8d21d40801273cfeb90c0b3b029788ba38e9306397ce04fbcc4bbc724ac9d4175249bdbc188ba9cd92de9a126763f216fc3757a0debba0c36a6909ead85b1ec73c32a571b7e7c9d5552f4837342eebd435007fd13fe498baeea0efc229e56eb116f0bc1198d2f791ce0758908a57fb9c1d650a47d79ba140ab60ba28e53f3df157db5bd169d30235ecc16661e7da0b862f3f0900e8d3480e7d2322", .Okay}, + {.Div, "-abfb8f17991b3f14645d5118112e3b2e1ccc4b0f9d75676d295ce2bcac859cad2ed4909adc59841c76f18f0266341f76d506e6f31b01b5dae1ffd1ab7026f5b55203f52c174633f427625ac8924a03465064250acab48e311ee17d1bf4465be7cfc3205329cd28c2f608750fa9135f77cad272ca7033578604249fc293b26f5bd14a9f41e17156b874ef3c1b44921324793a0f37a1530d5b715e2ff1cc866d0ab967fd670d1dc57f8611cecea09411d6fbf35ada287b7965fa2358119f2ccf0fe9f1fa862388ebaeb78d5735114a03c906e1f78e2f82a4815c878369bb746df4829879268d103769b47eddd78327242114dc3f8bc7e42dd450e66ca7b6bfd71d3d867592d6b1ee4c95d14c4b3ebee1744ae3eddddf52b321c032ce6622abab62d9936ab8a0a9e250d5bac3de8ffbe2ad034e7ed1ddcc66590a94f61562fcf71bb719446eb1688b23a910ba430403f460628618b06e5eadf419d4e856c14a4966a7912c0e5c09f2e59519e43a2d0b6b5e10f5016dfde45dc0e9366c2aabad6fb20d0a555d6bf55fca7362b46193c0239e9cb6d5baca0fd3b089350ca703ec0a5b94a32ece5bb1bc24c79ba0027235b1666bd85c4fea409b5f4ad08d2cab6f37251086543cea741cf4375731d7a566b4702b650a1768dc1a32c301bff589b2d9a51cbcda80d459a9116566da81de8da19df189e573b6f4f952fc8b4036e2e1ec01", "11c7f36ca1fa27fa94b7cbc7ae459956a5de0e56ad1c43ceb5d0ce34923fe5bb6d4e0d97583ecb004236270aea09aea86ebcbf62ea0599341b578b808645652450adab4eb419d8a40b24077dcb020bf99ff93dc7611705ac82dc7bdd9cd355ef43400107c738057968464e896ed0b0ee162aebe00f5adf3808948b0fbf89215c05c7b44caa7d3ecdeb2475f26ded35e85701a4bfa180c98e8fdbefa0a1fecd8ff8a9fb72242e75d95f7be30a51b13cd984bd9a8d931cab5910cb9e46df3cb727fe2e01c6692d6ead27f8597364e36eaf796519c9ed14bf60819163741cf3ac443dc5a2c7b7578a64aa38fc957b233e362c0c3ef3499656ff8b7b0bb092fadc46a13713644a201009db0e3943b607db249a64062682e3b739966a6862f217012761c142ad460aa48f8e2da878c7c07b3608c8707", "-9ac17e2df8aed47ab5acfcc513e6f64de727d0e76a57d79dc4a92dc31cf0af410d5e49907088e76218f64172105aef6ac3c0959a95659395299be5045ba82f8f21f99840ac77dc1e842ceb9eeac6ab91c2a59216c02905e21be8a0223ae63755138506d396ca4dd819bf522c06087baf3eae885c5715c5e0f3c3866355541d3f8a14078bb4d22a5d1b994dcc416e753e00aaa1869e7bc758760f4911d0f0108f2f11843be5eb47090c846fe06c829efe1eabf70fd1fd4e9baa6c5f832296dea9676224538002d1dc9d70cd5ca8", .Okay}, + {.Div, "da43ba10fed9be304db1b70c3231202a4803455777c1cb9dcf35cc55ca0c197c7c0a6a6b08d1fef425954e2dc1a323687470034aa46fa96031b87fc771ac6a945e9206ff3302120d4a0eadf3c67e73890ce91a513fd035cf4e62ee70d15f0bb82c9a43015fd8ed9875c195691e9c9c55d76762d5b0c142a0ed02097e3966f2f35c48dd8f52c8dca8f1a5a81bd98957f5c1a8d660afe9c2a8192c1c09c39e180d6ac275276ecae959e687829504398594cefa7db2204a1ae302c5b2abc20b87fdcb23f63fa185813ed7a8012dcc7e87dd4ade40388c52d71ba2c300322e0d3d59315ab74a76da8c54fb14c31e846205555ad7e93f0b2ee34b0260985088c94a401919993132e2ba21cf1980ea2fc5f13acbc7f7f7e218fdaa183267ffa3c53e686b6b415dc9fae8f8421c71007bad4f925bf32bd67008233408c53e5ae79650fbdaebc657fd590a2f3f1f92f572a380777b0e568a35c2003e901a08d1f661e00f6a297b3f6352aaa83dfcb02f6fbdcca67a2d59839947bf128b67586558660225a673ac741164ea66050cd3faf534bbd247f108c64a2859c880907472a854d8e455368b503a20bf18620c2fd6a08a8e5a459d24108f930dc7d9de2aaf599aa42f3868f80ca4057a5a8a559c6b9646aae7b7faa01d1b5e65ecbc04cb235fb15cf31ee878a263c598d15e4db6125093fd471bbe8ff5c900d41dd02a1334f4f578fd", "-1b83e48032af0cd68803276dc53c70616d2e485d7ba440ef18eeaf2756ac4dad2d96ca89059ef480945875c8389b29d0f452a0c05dd001c6d628a3f7f82758a6ad30a93aa2e3794ff3d10c8fc4a6818e99f87a3f61f436940ea95eeed430bc1a73049d83c54afd1cc015e476eb67cea75147348439125702285a18f514073ab40fa0a8778ba17d050dbdbd306d223e861fa9bc8c4083a93454d580504f0b21756384b012903762e5aa954eba4c34bf73215ba4f1030bcae81ee83514bb50cd5b35ca5a9183a2010914f85680c88da8e0183b72a756b90606986ac42c106a04cd9a87108374b4e0e5c3e6df38195bcb4357b5074168fee181ca6545cc9cf65d8d14a74393cbb9a0b22d717ef35562863da11904106b11a84d1a18014f62f0d9436b7d30bf229e1495fc765747c48cf4dc349392f", "-7eeb8c671525ca9402b2ffc2f0c00535c7bd5bd0e03aed27b23b5df9dd584651474e2fde5c26a847da0439236354c013be8e8821e21541aebcd7a002dd2641153c3f1ef1d630d0a75e4586fa593e04f3747359337cdd421537c573854403aaa0cdd4cd9623b4b66eb2b23ca57f6b410784bf071fc8d43e9e30c42500214ce49f02ab0ab4f2c5b096f53ea34d830e37bf8f5a62b22ec6d48ffab671d5fb1917723d548fa129aec6f0d2496cfbbbe098edf15c0584b6f104386f51e7d68e5f9d081378a5d4e6c12777266b9a5e80", .Okay}, + {.Div, "-acdf1e1514f2b42838b5a575615d7d3a99c9335737e65a2ed10a6d4730c05846999a2688c22035c488cd8b89ab50fc192f8c9851695d1a9746e0f581dfa1810c7b33d75f9bf10ec1a0a97aa7c121e27c024d1fb601029a0d50c51d9bc4ffd1b3e4f23fff4ea1b2545972fc810a7908297ac540faa77af154b93b343fe553a834678d084c6b46dff640a439e1e44bbcd53af502c102d3083b4ea7ab354e54bb94df15df07fafff18e7cb7277e0b8dc449c004c46c0768a5e21d6906f97387decff4a84c5b162544892b27774bb7f5ceed887599d111b4e285626f06fae43a032f8980ef87ff966630524073ba47a492a1c946a2610c661b00f9b249d043550e9fb7bfa095d94b4fdde2ef0caf1793f96c19b9b7b1622dc090fdb9d3d87a29635ec49a1e5c6cc89262ad9845e9fb3b62af9d5b202ce92b6f537739aec92b732c4ecd5677f4a7f511d5644da4090ec611b17344db86751a05a8e71e6dcf4c73406909d5facc9c5cf17280718414febf130b114f945210556da41c11aa51fdaa3ee92b191722ee0803fc416453b701dc03eef824689c2776b27308f314e203daa3e0e4e777f556d6341cdd99a0f9c1d67be12f551f30df5ea45faaffd951009e97b2ad55b7e5f34ec8c375073a8f9932f0369a9b066bb55efc9825b23f8ec050e2fe6a0733753ae3c6c636addd492abe48ac0c3470da539c82584159e3c4d69acae0", "1bbbc5b6d62ec7b19c87b08a75fac3e77e1b9dc28b3c385289006cf29241e8771ecf905a23281e2f3f8b05127db3531b8a763847fef8b9323314174f782f6d4330db315a7a4ce01d74ecc0fb9b0a7f13914ff4094c3696e3812d99f00207c95878bc11cf5d51c8e227abc4eb1af9794bc851b6ac497a16506da46d5a350c0facbadd5758efaf1aa41481befb72e7bd07d055a6e24ba0043bfdefac380f7a1943ab60fce3913be2794b788ea4236ea6d54fb925c28c821dcb3661f676c333606fa5cb2ae75cb2f20e78f10b6948ed4d1b14e383280a811fb48f03d07062f4b24201f432b59bf14fdfaaf86e5fca6dfba8f6b41321352812c88a73c28e94d88d4038dc7b0c112d2a10473d1e7d034abf79bae91acd4d5f5b3ab0780c89a8d8968cf3fa1fb6765be93557557cc5c010daaab2cb0cb", "-63bba88a1b42f4741021232dd8e22534413c9a8002acbea68d3d2b7b5450db824590325d2a8ac85279a2759dfce6043ba82cdf27eaec4181987182d097d06ef881cf65a8e70e8eb9daa672e3f3d77fa9db5cb6e83ac4b6181bb0c6b7d186fc141d4c3e24f80f8e0250b2ec5b5ea9ebd42fa2d27a2634b4dead7b396cd7c2efab34baf4d6fe9a295cb8eff973369093fda9f8b8dc5b20af7b87c50045df2c857f15b4cb289f2c92b33984a1c4f41a5b5b84fac4315f1b39806c2a14504cb52baf2241ebe3c66afee2677eef622e", .Okay}, + {.Div, "ea3e23163c91775765a011665f66a812c2c0f67ae1a36e1f5e8176409a35a5c5e665dd9715280ce99357cbcab5dce5d5bc43650487b80f893dd5eb31e65e220649deec31838b86535684f9f35380b79498d184f613db40220f62b372f88d181aca6243bf1f0fb17978fc487da9ba67603e928cb6eba78e2b9b84b217e33651e6abf555e036eacaa72bdd1abc328a1c2c56f6daa7d29c44d57288256fb16c49c35fa9abb45d0bca44d910228b00bce791bb09cf7aeeb1c62df105ad7e02975e8e5c0e0f74632a8ddedc09ef96e1f1d4d28199adbcb350bc896a6066a0d35e904a94310753c1519f545ed8d71a7cf94242ce4270c9b604081ae8cd49377ae292aa5655dd229494f83b7b89c166de8e8d70b5e6faee46bdec0ef1eb3d5a64f8fd7601245fa478eb46b9b5a28905897a167ab10062e98da0815fdc5f8f7bf5b9430af4a19f867c2d0ad725be041cabcdbaaa40d9fb6fbfff614cf73fb864e5aa7c4f35bcc441c67991aeb876471084c8e5520cffe42bb7defc6ce79cd2c2c212f1a734f854d1f6a392cd3e5706be5a5e6945ea7b034680f806b39d63fb1447bd5702bc1d58a1b8820ea2159b4c3a9f462f6b4e3ec58d60859c4ce7668347a88949975b6627cc14ea02c3e82ad61e9751be7bd39fce1f88a5763f5eae4a549207c2dac39789aa631534a855595467fe26830f092843c6bc1f5676de7f6e1fb4b3e826", "15672a6973bda1dcc128d4a4d6720e9ec0bf85ea1ae60687f2cf637c44ed2a768220f44e1ef4fb844d64051ff5a41c43133c4548d2a87f1fc19a83fab879f763fbf1b5c0861bbe6902b4e137ba9cba7f44534339e995a7a1b5166be8ab6c7f453a7fbe3be17ac8288166c9c6cf0de5006a745a378341ac5981d32ffe2ded5c21382ebf995f8b338cc9d787c2fb0da5c419deba2379fff330cd3b4f7351931432c25942b034cf02e890adedf1ce3174c04a10b028c86b6998ee9c16a1ef095e608227ddd54082a58c4b1a37d865c06eede4549a7e06ca2f7572908e590eb6fe619a78d4a24b88a32cec97a009e32694abb9815b1b460d5483e0dfb986641df43702444bc3e2632e880fefb14c4642ef6b35496c77ed5ce1733399fc8eb92ded55a30c8d560a64030344bdfd80e0abf861aa81dca", "af1c3aced16656d890adc80d6617af20829c1d2ff81dc1e1d1c982f2c8138890aa3d44de5822c279a0b18e8892503f577b1436108d1dbcf64860be3d7691ecacc8b35dacfabbf0a0df02ab1e9845e12c374f8b4d0b86ba0fbd133961b31a9ffaa1e75e29f51e9f54835fd254f0a9e6c37b7235755baa90d966df19d3bee75651c2d74be5c4e1b2790e3063865745effd805f4d8edb36df269ec7dcaf90b35ee0c846413439510bb5ebac06c480cf99c150b722c552343519835e1a91a45493f00f3b2729cf93ffc8fef1b08393", .Okay}, + {.Div, "-45cf54eea00b220f6ce11cdc863878dfcf88a781fc1cf58f42667e38016e938390e88c3dbfabb807c9c5659acd551d1239b9608538dba16162ec1ac42ba9b212a3db9cb344733f9e5b53c30b2cd563c032325ae4f10a1fb8c6df30ea50c06593565b663e0ee2a230478803a67f42c77e1a7c4bf7c0d02e16ba894323735dfa76a378ec3c30354233a4f6ba21e8f7e9438c2b2320b94a82a976fe734584caf95cac1c20c740f587cd0badf9a18b8c12bc1b33e3b2305d096084d84a4124f39fd7994e95378621a9b60ad7eaedc8ba874a39e378f278c56a81078fa1389ad47b03461fcb524c2fd1069e82cad3cffdcb80bf2fe4f03986f78680dcfbbbb143f392d9bd6bb7dd9a3957b9b921d8643d9c44317235b1131f99f25e1141796df3dc321b36421a916e5ecd078114d03f68149bc5737809758ab7ad39dcad295cb043460c54e79642d5e6d2da82862965c1370b428b8d7878952c6ef84deaf856c750b58268b1d37aceddda761034b5c5831a6f34c9e459483403e6c6cfe7be3c14cf2c5061c86c16f37d9373c18435db73342f6074292651dd7fbbba893ea09305c505bf09f6f4018192ca41433146ad770ec6d5c0fd88e4433b27a1030ecd2c9d97057eff260f4bd286ca9e5c3665c6063138e6e1369007806b25970cb91497fb2b5156175608dd9ecc5d8b4ffa92cb0c022559f80989b634ae5337b83b3f00811bf7", "-7a9f1e8dbd604b861e1c706d1380271b89696b6f7e9e00c9d84e962dbfe5ad4f5a7ca776e5dfbae3ab57c61e1ff22c64ee75bba2c1482baf272fb14aa75429a7371f21036d6f7ab70a6a098d313371e03290cd49b9421128c944c0b446e26fb34e5c9f5990e251c5ef852d1eca2845b3f3666ab5ffcf5aa5e077537a8a58d804b42f20fe0cdaf0bf1fffdc52652f2f6ec30f34cc0880e572bfd40b8455ed702a6ada8967357694f6142b00d0b90abab397a8e55cd244614cec6c9f33443b13939f437e920b7696c6c30f1d96342c97e01606701f8dd07416ca765dc2c5d74cec991f71aef4225855f0fa7803e9bfe1650a2242de73f8fde77b1a71b88a4bee00fc966d551672624cb27685abda862f91d66974cf0864a732320773a35b2e9dbfdadbd9353a579a7e497b384b2c6f1b88bbf093", "91be697e1a95b2d6cc6fdc3eb542c4cf8b9d7b034125632f4caca674071865a160c53e53c843bfcec108b52c6fb6d3d2ff6bf696ccc82f395cf8eb1938f9ec32fa99e5f0723863ff9a7a15dbefeb31abce0601b08b5d744d4b8eeae794d99c8bd5f22e957f5705c99cc9e822a158c92263ce7413d46f79cc3ce89751b8ca5dce0b3966a6ce8c95d2f16c653278d378b2fcdfe8889cdb237c8662798327c9625bb711765d2b1aa74e1fb72197a1d61fdfd3c119f0dcd0e9eeedea4220b3d9a04704898252637c1eaff8b0611e4d", .Okay}, + {.Div, "9cac167b8a30147a842de9a96a492094413db7bd985e8f521223b2d185ce6a6d64e0e8e2b3c76d67f24e7bd8cbcdf68b87f73fe4638d915567d3be80ec056f15d3e9bc57f29bc928cae4b1b19265a5971c923ea2f6b4cac348c794b2496a6a8045b9f4d884b9a5393dd6d2ffe16781c50d1152364b0207bafc084cb1f40eab127e1bfc12f5fad64f0209f0dd0ac4e6ddc1e0b98e061a30d0a9932971db55d8c140d1a574ec3619a2535bcbe77b3b425f0e3c84086efe8dcbbe32a5a6b43edae4f97fdda36106a010726df8a1fafbafc7b52a9f72e18d3aaa701a53c0d1680ecb2e7abd1ab85ab49867c6c153e487cbc98616f92490da22da921e5b22b12628c9ceef4f904f849560497fc4ab64fc18f87366eb71721b37824289dbb4e1faafa5a55d4854f10bed1784adea245267500176d6f0e725d5008a9c3ed67b6439ea5f23ca9ad1c9f8df706576e7a666f992813620ba3c10df5f2d9330348f59a34573724562b2e32065c7d6d23387b51514d4a4db0a9041fdadda7c2d2aa48523beb9fd99fea2c31e32f950472ab45835aac9f6a841a36ecca969ece56ff71c55d678b3a71c0e4aa6e2ddd96fcd76f222c25ec5d9092883db1b42f3d7abd0ba13fcd2c0d1dfd1f07941953d5c91bb691b8d102c82fe6c99c5ef73e9497ce1bfcac261a54f0385b51399b16f6a2f30d612ff2a113beb64882319d8fe3ac5278e9db764", "-1628b39ddf36a2b39afcf4e6c498ef2b3420cd6149d9ac495e2d01e466934cd8ff69ce553a695ce34597960f16c57fea7b90848405cb8339478d787b04ca94f07bd329372f22a6e1b6180231384a296f36093d2da32bd41f92fec184f30a39707324eac7d2fc76f248aeeef466cd5ac9d5d9bf74f543f7b426f5c1eb4f313eae5eaae74397ecc5e4baa996206a6cf78dfd1f76a31f6b28fa3e7976af3e3b0db925c0c937ad08d7a0479c4cc1de9f065b65d6d0f9926d259a4086bf3462c6bc1db9f4ebd66542f33a03ecf0c19b2952439ca54b448afd4dc4bf5ae7b2d7dae0eac8be7bd8eee7033221d295777dfb13e62cfae7d001ebdafbf49fec9b51c1f748fcfb61665d43b1f7f25194009cfa207db1415db49dd0f92b1099c2c2077e801b1177096f777b23ccc3033d07a689e469510feb4", "-71203a26d755313faefd27bef5ecab744722aef7bed77610e0a01cf77cd6072e296b913b55133c7d3648b4527e17935cb8505a9fde08d7370b293ac83eb6d9d9b7a1a6f8bfd43f8353fe3aeee7a4a783f6206e50eea7b6ae6bf9004aadc597a3c412a8333c8593409008e247838c0537c5e4f7bd2bd43660a61d8bee111d505a08ea981a2736d68799fd78932f887a63c228dbc8e43d9d1588d49ed77a5210233eab44e0e7cb82d51fbac91d87fea36f9277de75c264a91e128f5a59a652a24e08adac9c773023d63f72bdb042", .Okay}, + {.Div, "-f1ec5b000b487d68ece1a72f0058ba932e9f98c27c967bec10f24e93f2d5cd9bb35f3326f87a95330b7ec1d9b7511298c3394ced99e4d5ef6dc4dfd7178b5bd7efc46f4d4445ac33606cb9e8c7955ff3f096de7019dec62ff92d9960e0feb3a947690ddadf215176a58a3cfa8ea94803cbac3762d2df2d911ca1e421f45007aefe9fc7fc419e7f56119897f953b52d1307d2253b12fa0a978a5ec5defd43b908e25f34051a83ac9aba38b3bcbafcfcf1d6c8f6ea68d772ae16dab030f7356fa66e14273efb8e1a840bf6e357bb4bb1b39412eab55d4757bb915fc1ebd8c00a999131efa1e40ff68d8d6c9da757d29ad95c9feaef27b7397d4972a3a56349a8ed02b955fbb060b8d3ec30532b52059719ba732901245dcf54d9b957976c3a0867c60712479b2c185bfc49e783c87cf8bfaab94435e2a96d65972b560943c748fad39c368cd31998b00c69bf5040898425a1b0a421ca8fdca1bb803e9aff03de9dbe5df56dd656838cbef4e0a103f20cbf44482637e61897b1cf1e40f5b343a61999dfe58fe970b29298e597609feaea42cc156df3a7367407f0b6b9fea02ba7af8f4341116c1ac068b68b645407f532f19468c0f78c43ff6e1a5de61b41bd466ae766fcaa7ffebe59fac3c57f47fb0335ef8c614c4a1708cad2e8a9c8aca364b300b56b06aebc356e17a91ca4684667aa86b89bbd44e2403a1fb606c365411232", "-8dca3c8da410edeb42f33a8f736adb2c40674b980de061e7b71065bd4e58956ee1d4f18e5ff160f137ff59a61fdc909a764af7e36e729dde44ecf277bf910e5f9834c242575959fc0ee33fd65b837598ed29a54233ae241b4455e92270af6ba2808005b8c967ca8d556bec89f82002461c380820d6585a451105a1b7471d872a5b3842fb7ed486d696e144f6fd47f54693a55329deca1b3c2ba477323c55ca186b5a453fa58a57d28b0c4e1346616fd67db618186fa5aba10654db44ff51c169fe3e48d8881daa81caa50af3d301a91cd028dea60756ce6c7069267c60eb602f061115f8e1ed21b8318235fbfc7e71089b4deab1ac1ae4a7fc017cf831b76738a4165011633eb6f7da69ef434b2fee44877804de20d9fb7561b4c6de0dbd78cb73adec3c2ebf233242027cc4e3b7f17f9e404b", "1b4ca1295840884646ed8de41efe55a34a0d71c6aa0ecacda5bd446ba12747344c737b442fa5399e467d5bdfae30a9b6e85b2b0ec141716b3b4278365fc129bc18c98a42797b70f27307e69cb54b256ab3dd2535944a016e005564ffcbd8ed3ac85a4d423f801f6da7b00feb5694a5b477af8db7a87489dc3c876241399c11d0f168241e9426efc7e2fc1d09b359148c27e2dad6cd78484f3bb1c64430ca16d7ea3de144d588a5726a182bbfd3cdcbdf7b9bd4a61aac2f6318bc414dcf1ec08777ad7f4f5399d3cfc2c160d6424", .Okay}, + {.Div, "-4a1d8bf561198b73122019ed472f0e24d5dd196cb74aa253ac5a0cc0ec35bc281fbd8a384877bf42fcea1c1721c205dec8df77c26432bf6fa95c78bc5e5db7fdcf23228e0bd4c0bad54fe87d2a351de25d7b93947e9366b7324e92b29f1df8e105977b3a3e8f5cc5d23c52cce83d53c63d184990a77b05f44dc4b4b3f7e3eddb4eea1504ea2c4521750a4635559b91cd9a573680b97bbb8103a9570470401b4b9c7a61ce0773fac101e31de7b745950a9a1536158a5c836a81c054a451879635ce954225e2a124dcfa7f125c98f7c4234c50f3225d9632ecc395569631dcfe22bf753b2c328aea62ac15c21ce3c85777ae2685c99ccc3fffc90a455afda5f3bec908000b3bcdad4ce7591cd5c76bf1d5ad538e28ddd6b3711010f50b5ec8c181c876c49fbaf3976a8813cd46c5b64b2877a24ac91471be0e318c239746b3780b02389277a7873548ecb37128582058ba1d3f3f7046fdf200cb62feed220c9c018292c30f277f09019b608979811fbe7d6350a5b042af0065f990ccc1bfdeb2abc9730d6986043ddd9d5e20e0b576820e05d87cdfa8774cd4cecf94057f4c644d784cd609111c66813606386e535d2b3e611006e1f63ef744a1c0e090742aa8524456e2bc491f6a3f1342a4178fd7a0644bf770be6ba83fa3709ac134c78ce84f7dada1cf15fe6d066d50242a4c3aec891d02b25a52b921485bd680cecbf13a6e", "-175996d2d3182edbe9337efd931b6eb21708f4b6bb0a0404a85de41c43dc3bd49bf32498a480e8c6e9925457e52e9bac3f72b185f2b56319e2325e19ab10c8cfa495ff7959b0102e385ebf5e0839765587f76c5a1b3bf1ef3aedbe4123f510bf7ee0e2722b00fe881455748b1e00607f68cb65c9e8b7b963c3635c85dd3bce4fa9c79a88948516d9794c89ad1eb8fa87c870008b336c32624744b8362b2949abee8a61f6623bd21ef09b8af35f8d740f1f71db017342260a925b88e3b6b3c1b602575c7bb3b869bfa376a3036ca3b4ce1197282ac254dd3af0b91b819e283012839edeeac67bb262b2eccdb221eadde41fb5affe57e8c173aa53ba59317bd7db6ad79123f7c62935f3008f7ff8ac0498eb8bee63c50e466273d422ae767c9b45ff60579d59fcb4793472b005ce50b4d0e3c7c88", "32c92b495c685129c0aff05f800bfced2dab948f59aace4a3865e26aed7bd150a6eaa5cef4c411d8d0219611e7b7f4f22387c0c9e596057cbfd4f2f19ca6d59387e1acb4682fdb19eb17ba558da1561cdfe88ac6138de63b8a1a87ad289b378d58801163513d9aa9c4c40e465f0b4128bdac84f6df36fdde4e5d78c743e523890cf569923cfa0627dd879a2b620dc3baaa4e44694b18ed74c433d711aec5e62648e1bf5f160579c837c8a28a340e03fadbdc5447feed7f5ced1b1dbb41b903c8386f5e92fefa8e66092420e54e", .Okay}, + {.Div, "-96c246aecf32f95721fe690fb781d3ce10ffcae5bca531dcdd8727cac31df5b6c97edc011b661fefc8289d3e630d5bbfc3d750a3ebe26f6f2db5c95ec683c510532627f50d1a9e9705f01f97617aa19048e67049ac470502c6459d96b3d5713c82359bf201ded3e2f930939bc245134048b75a5f9df3a4e430b11c2ef80414e5fdf1826d075048bdbdfed4bd5ba7d9325a0b3453f6685aef3679de5853966d5826219f006c0c9ed8fd1eae676c6d2bd42ab4b2cc03fb4588de035e227fad86ac4e00e3cca5bf35df5297d01739b84fbb628a1d595911caa895e5e1c91d27ccd7993727c5305631f9f787b15624411021a7bcdb16586877391ca82c0952c5aab5259434579ef9dbdfef0f3f6e12dd37ff78c873f25dced394c343bf90f15bbbf2bc2dffcd6215b7f3d7d78dff613e0318144c5141c0da3197c2eb914c9edf7014027cb87f227d14cef1475fa2ac515c54e283f8a7ae9c85d4d1ce98565a9d73bef2c470c2d9e47c38ff9d171edabe15235d231f2273d2abc127b25701ab18b800a72c844f870684e7b2d9ddca97841f32812f487110637a5f01c832b07bb2624d4a6f4e183988aeac10821faa63fafcfb5937ee34100e03f68f064507c026c00485e09fceaca520e893846f63c19314f23b6663ca19cd7932ce1fe9865732a6181f223702861a121789cd104c749a2c392d11627d2a802b346f9035d58b7ae504", "-1c03f19b955ddc59aacc90c4cc221efde3b8856ad3568a45840833628d9fae3b9794d50e82054f06aa3fad603239514e35b5edf0a669769996ff9731cf79bb97a4afc1013017bd814f12113087a43ce56fd17dee41f2d2bea53f1a3549ca2f277bcf3bf7577e77918dcc1a9bcb87cf6bf736edaf0b09854500512745ea5891b2ff4d68cdd803ea385246fd8f1b30b3de0e9ef780e48b4248df3c743b12a968339a5dd632eea283a232981716b158512af6e067b53a7735a186c31da001f193e00f2ce26b9fde44b041ad37830a44dd9c13bcd23b5c72ac03108a8c635d8ddd72baf7ab4ead9bffeb87ddcf416ce6450cd08d873bd52ac3f2f125d48c3314fa2a48aa60dc91457f36177a73336912f242e2680d405d7a3b10e88a917738274c2fede9d356375054ace9c96f02ee210ae3b482542", "5619beaee09aadb1fa0a958d02560ca6a21cdb16ef9dff517e5882ee9bcfd8542f9ebdbb456e82bc1ae13491bfd4221927497f8e59fc87d8e9cbe9fa0d4238aaa3bb8e81c5f04529a1a39994a6e3b86dd30f7aeb473ddc19d25bd88e301f47d660c30f8a625400dcaf7afa932260bef37215bd0ff547e32662cc59b44448d11f01569feab2d2a75f40fd9750ebe2a4bebe746474ef9808c14ab06706d4119a85413f62ec3d94f5892a11175782b35a43c8c38b494987afeb1c232afe9cc2485ff363b3f8da1c99318d06799e4d", .Okay}, + {.Div, "-2d971eaf3d2c9e02402b2c399bfc46197008e1f5e75d28c3fbeb942828ac259d875df9e5b54338672e24f3d5972d8e075ea99a26bca24cb0d8747ab4bc019379fb6d23716159bb5c7db178cc6f5bdc22e65a8c146c71a4a9a1ad816bb8015bdb3749a2a1df6131f10e58f964ac83467b3607944313f6ce4f309b9bbfad68326d0cb9e0a22a3d411f510560e1e432596d9947cbe611e758b50223b1f0934e40e2866cfbf7782ecc849ce8678583d0dcaa6398a38dd8d8a5e481d92417589e3b7afebe60a81d2e2c4664869265a665b46d31c234c8d1e6c4c2e024fdcf14b2f64c2632ee4b88217710f834b4cf52642d591c84f052c7b952b2e118f05b23e19769e18f30da61d169a169f7397ded1082985664cce6380ffb5e2fc4116396b5f78f852f60cb655902f6ebbd24859b53ac0c92cda0533050fb7d2bd2b8db144d1cc914ce805ace1da4ab7b5c3aed96499884e90153632e43e9bff0c101e45072e39574c416ea121e21c1df7e1818a50acf4ef6753e46d4fcce1bf0fb0c4d5d0824958c3c8e048492eabdd723c23da2fd46971884ca4f02df32749b506395caf735bece7816ec11f4d592cbf61e3e60a3c865ef75be92312e5702c73ad58aa97a0693a2face75c89b10b1e759f6e8c70918fa50a754d458af09bace28e822520205ed8346654aa9cc0cc268872f78607f1b09fce7f191ba6251057b4a167743decf4c", "e10874c4fcdfb28e3d2c5356f8da22adb116b8284cfada5c4c01303426777c61944d176d781ed9c61f728970db773878e931c9eb818809e1f0f92ab24632fd8438128b5b4caafb8bfc36e78a792eba6ac4053e09431d7f4fa604582434ebad57c2dadee85bb5ed6b5c5370b9b088856305643d148ce8a4544ee177cd528cbf01114ab95d1b8eea35003ff8fb1109674d219428a80e4650796a34d9be983c5eb7ad217cb48de00e43ee4d32998042e80f57687dc939131d6051907838e7390ad49740d2d41afee5e5bdd0026b167b3cd959159da6f573bffd62ef91d99e0522f1adf151e7983309b7d6dd6d7a64a113b973be30f1ab57495c076a59cca2e2b1274af8487599d44fc0d86a52ed001a054fdc8d3fff48b5f72d6341d13faac6c53933edea6bad054f5b0cb14295bf0b3b4eefb67", "-33dd310e4d46aa512521242641a1281e185f2ee9e48445ee757a661037dd3f4fcf6238b2b10519057e9c7b3c29b700753cb86bdcf36da24b26ecc8e0f8b80e6bbba0b283d6dfc0255f9fef2570bedd1f10cb707fddb57d07e29bc1cd82abcdeaa248fbc7af578589e737838669f6ac40045785f66ed1a09204beb2d82a0cedacdfed16d0d25628ed319a25670067471d7cbf2ff8251647ebef043a5c52f0aa50fd5c78c8a2e01031d0b13618758f27c8f97d6a4ab0a24cf512d2fde144ed88fe70be4bb50434ecf71049101c89e", .Okay}, + {.Div, "-56959d1b7227e90c579b2f7ef7a778b9a874f86ee791a4203094f55a3ac0115afa4a09ea58c281e3595db3a5ffcd5942e33871c00780cea8ce301faf359db85c3440d26cce7231736554958f7cbc47e8990ca911fb2dd7ae391f7f49b3fb28d837ef1c7b242fdea2474aab13bfa318df34f38e62fff7d0ef678b7f278e9b0151633f1516d8fb3eb27708e58c25639b99ad6e5ab4cf84128e4afd1ed36a0b8fb42fe1911dd6826322deeb2f48fc49d79be1b33a7535fd09bf819e9a6e1a3f3b2809a1f7cd2c43c042831cb5857a77145473e9ac0b79d0b1b7c67aa67e147a903107e6e371ce0670c1579207843520a51f33098648bef2c31f11003bda0ca558e62b2490e79cf1ef9644d57ef0285a03db6386dd9a66ad08142f29f867202a6fa1a5b1aaad784a71a39d5546cb846dce260888477dd5601ceecd1a2d4247ac0593d644cb8640abcc65aebca1e3533c3b3daf3685a7420b864394161ac72f5b0e07de94e162891f5020c32f9b2be58b5fecaad7b14039194866e283051ef5e23ae0e02e0022f78003562e60458eae138f7a43416ce58919b9b7d45dcbd4ec5515857d93f2d970346640f85ea4abd8388014857bdd30a2ae57f0c26e4449faf9f3f18543a06eebc76606c5e07f9a58f1bbf689e7c7f06971232efa2112e5925b173565766140ba41e25681869cf906e43f7ccdab577509bd90b1a380c0fe69d40793", "107e5b8a7db372c83a197cb9ee2497cab53f8b3efc7543b0feef0f0ab7640515af2e5857387a891779bcdeb5997e2bfa827c17a61d18098a4ac6e2ce9e23d569c9402a80ed96a5eeaf09ab33d51496e501d8b4f037b3cc42998804b67949bef0a4cdd9a51c8be4d08c87aa37e3f485d90c8d45cc5387fa591cb1ca6ee461ebe1a1bbe3d888a680461f30465416560a48c7f6f6e5615327b757adc436baf913d17fad3929d7043a608080277987018016dacf96876ce675c663aaf7e4c7e7072d6f29a261e8f98219f54862eedd80426c5286ba6b3cf35f2cee960c68047a084579d1edac4501d2cb5cb11610542de777aa729b72f2a28045e93a2bf4904ba352da3e33a7bad05b63dda82bcdfcb5a1f37fbbc80bcb35d82060de2927a24b451d6e403b8ade5aa75fccea192a84a233e38f70b0d", "-53fe4a072f6a7d09cedd57033b35915a384c8cd5c8f8a01a0d4c1fed0a4f9d7da4c2db9b21ff6757deb69c6494d99109bb958e9934c881c1f1bc7b3eb2c18b751350e4b5e86cff30f72e0da83574bf8ae22cd7ef49125a9c0c77eaa299da2e6d5545c6bdf23ad50f95d73c9952c8ac9f9ca53aa72f6f82c07f13fd1cc5bd32f42d21c71ef2cfddfd08e7910ae5918f6aa1bb5c6e0e923b49e96e37c5d0f32f4f13f3cf53481bff770162b605e4b9cf1c3692bfab4fb81aaa3741fccd35e34cb7974bdc0aef65669fab2e5974b7", .Okay}, + {.Div, "-98c9c49d63da35fe23554d80b33a7375b97d31f2cce9eb52bb86e424ea499c3a65e725e6a3711c61d66ec4931c0bd16f28b8e7c91693b890e3b9cee8061c1d76b1748ed0ffccfa4c38c7f60c30c357daeffaa77b12a824a826648e4c8a6a54edbfb227fea443c0c8185a77110d8002af8116b87d5efe35736c487ca9d6c78cda2b8e632da3ede792b3a763c675352719be732a0cd44c3b4ee2bfe62efc66f7f2902677737d93a646baa13a1ee5f4922049bba80bdd7db359246706f59976a886a834725ef9f78212ffbc3593745db70c8bcc181c20e730df630c04732892dbf56a273e759aeb428243a14911b0b7b4105014a9b2d7476988a4d89a8115815218640d0972b8fcde88f18b8ad2c01c0cf5a12a617a9fd25efcc1768610c8452a46b76c4e511a2cf194d5b791d04d1927b2a0da38b69ea225d0335b5f2948d1a7f845fb0bcf95b85b9ba6200fd4bf3120125f126307ca3e544517d3efd5e1d93f1fb08b5bf32f0740d02b0d5eea7da0e1f10c3cdfa37aceaa2f87142ca7665b8aed300b31ed5aafd9e1f4f1affed3ce2cce303d98f7f64373cf4c3b126168b924e11b24088759e1764efce73257990d0f32219917094607dabe54e94302c8f6b4bc3e1c81d18fb618b3850f67e05b7bc1a40938efdf89b8272e3ef93aabf5dec3f22dcde35567f889675c7dd0ae3491e8e632e22cebb1b55772a403de5a420aa6a2", "119999d8b67ef8c814f1d8b394799d1478a3de636e5fae7f351a65821b19d1a951a8eaf1ebfde972d5790276848b429130583a127943c7a8814e069cadb03853318f16fbe3d375520e2729fc24516e05ad2ca96504d1432a9f4dc5c671fe0011cbc9f7d9dd231bcd68500783b116645ba1103eee73bdc9e376746f8fa6265451938c6d35b274b98741ba1b8a2e7c4dcaec50970835bd05e5129a193f25ed1a7665eb3ac792689ecb95317461521550d5bc53b7c70c97b0095131056e1d86b99e885af51f7c2ee52c9c9f9a0a647a85652d07d8a6d7dd88a973500a44f427b787b1c5bf1adaca5983e60aebac45f6bed4b9024733852d75f858a87e833e94ac1099829b074c89a3d1fc973a93fd97ab5391dc61a862cee2b9888901c8dacf3a3748e1c4183b955018fcb70e4f66f555a70f41009", "-8ae5f69cff90a8e9923fc998de204b96f1ee7b049b7082d878b1ffc20c79f04528b551652e5aa08e1a41885457485dc77cd0fc12caf01e964a1cfb67852230fb381e9dc6b4f687ed874642c53cf2d65d3384a5c4a6de8d22be18f822a757cd433ec4af4b3b69d0699bf12094c184c88c3928b8ed71a764efc4f812b5bff1033ca5c5bb6bbb1edfa600f40c70285979cdf1eeb9fab4ba052fab9530fa8b9811275d6b0e2ab905e090dee76dfb0182081e76a17fa31c26950a855d58f9b2cf9146b8a1ddce09623e148768a25a00", .Okay}, + {.Div, "9da217dfbe05b198cb4903216ac227699e8bd885dba257ab391afdfe4bd899e53ebe44b8b7fda4de491a93684f4f3fc2a5693e952b2679f51e65912447b42dc4197ed03e5d4971a5b839f12008f1269f4f52731287c385466acb271357615a9ae210c07b810e21fa2f1c0475c986d85cf3f30c38d8f9e1feda75019086bc5db61769563344422dee0478cdb76feab5593e12ad3ea9406742bb2e54216431d0fd59a4e7b20dde8b15a67c6823067ed23847747ffbd2881f943dd250b8a3bfeb0ed9bc38c3269460ca70cf47aeb66bbfeb44284010c4e578bd353c4998bf59eee0041950325b1a71f16aade2701e9e06bbb3c9ab7d04c20ab6ef56659eb53fb1eb3451a992957747be3845b9a4e06108e02ba5715b770b1f516efab010e757b179e0aaad30d8abdcd73bafdb078c7a4b618731e70b3ad9dbadbaaaa9913cf0cacc0dd0057ccabbc1c5f1234d0a740cb2ed6eb47ea413e698689fa3c27810a8fce9008b43b1eded54c332da72fb4f89edec66d2011ef8955e0f8f318fe6455c937a317192aad44e7ddfc494a912921bb3c7161f91e19cb0435520207923bca507bb1c7e06cf308c09300d849f3fe3069e44dd32ade718bff8eb99dfc51d82ddbe000bbc868c43b37b9d527ac1ceb592817d4ec89bcae0c5ca04ab82a5684b31ae46462bb97a94790ddba9514413d7c4122e9982c1ab375e2617efdc411a2cf02b69", "-1a4fe2a353ca898b803389eef822219808b4012993a8674622bd19640f482b2734a676a857b25bbc6acf8945ebfd55bdd495e8c1379baf3219b3365df5408b03d7799e5fe16ce6be7361da8e43b60f2c051a46667199b7e0f312e882fd0c2d15040fb4267421643490b9d7256fddb2ca8762d20ed2dcef58d097d1d28b9e87e3965c358f1ea51f13450d604fb7c1a1f88f600e521c5689ef39b26552ce954f3ab6e99e2c536517521fc5761cfd2208a51df62fde792d3c87419180da47fc015cc78b848fbb84dda36c1847d020ba60d935183cbb25d66123d022088dd8a6acfd60d5b3d5e4a7f2ae22e97ba77f735b115d4ac3960af415ab20b7b89e96434d8de49bd0dee4d9cf6250d925dde70ee8375b3b3f716a1a6c2d620bafefc165ece664250864bda0c922a99b4ce7e484124c3fc4296", "-5fdac619368d6b3bd9fb850c40fde49470fc537670fc77f0d855eb03b2b3ffce32f8fa3126d9990058849e663ebc834429c92c2e33305c07b15e464c9c3c628de54d9bc9e3529c38889f280406c9e7b480512fa195f1d4f74edee2ed57d9df2943c8bfdaa981434f5415eec388b220bd77f92db60bbbc2be50f623d2de5ce01470994af55cb7530d263784279d15f4fbd1179429f667ff23f1d14e5d36eef6f4d6f3a0dd0baca911d2786e83ca524d8efcdff5d0e68332863eb6e4a19b757f85ab02f99ca57e85ca1e86afcdf0", .Okay}, + {.Div, "-c0fc82f5c0349d0ccb8d4283c855e624d22e36a36f71e18f1be602a8422cb6bcaad3849d48fdd721d637b510c7a2da8b7031b3f2ba8916c1126238194801dcd0a9c5d2ad168303f00f532fd08c979a81b609cd106f0a72dbf6f9e33c41df422ff319bd16d31dbc59155dce1937ba82fccb3fbcc5fd12be9a73f01fdee751f8976797f35e9f150112daa40553a41ea44b74b611a1a06b2b2109c2ab52f901ba51ceefe98aab956aa2fcd5339590150c2ce07b517491d1d9458875b759057de0083a3bc0cb9ba295e5c6c1ab0c74a80daab67f081cd1ce334ebc42045e267ad141a7daafa928cced8018944857cfc07df41ee18806f7dbf6b8d6885f73096076d6a0ce622a832fb5c76a12e35f1c661739a77c20cf16fe13d86b2ce0c42a8ca35f360d3f3a0a1a0d7da10eed733f119c9f2ac99d9eb98a8e381d029b17e35b6bfe381515efaaafaa2793da3ca122a082a48b2f1afff3ae1063b24f90cf2b72aa3b3636dd940d6c0cf7dcffa744a91f5ea92e1c6096892a92434552fc0ec5817bd12fa9ae37a1f089ed5eff181b378e8d330bdce7f2c83186110ea22b2b05f37092619184717634fb7b50459ea5c28cd4c28e6c3426b3ce772229be9d6cc6cd3b3aead26f2fe31cae89fc945e5c44684496e22cbb4a731a7754b84121423b7e1993734c6cc757fdfbfb8d7bcd02a37746178409b41fab17ca4e7bc6daaa525067c8", "9d3389422467f522dcad2b5f0e4650da1f76d96dbc6f35f14636e237d4e15248270f260b56651cac34719ca85e8ec13fd4d8fb23b3ce39e3c0703bcb913e6999d21ebb4d29f11e648a7fed175be6233831a5b0510908085f07fa0914d444df99467641fa01a0d652d5e3b6b06bf083fbb45eb668b609f1ef886c575d9a0b6efd143f67a6650e412e6f644cf06cb8db1f262ffcd3f55da8d0399901448cb146b06e5d704e7af3ec2025718be63359518945769056da2c81c17c6b9b51569189a70228d563aa56f433cf2cc7d89528c62d53db04392b039340e2a0163fe1dbd6865de48c80e3511395979088f891f094bb2de4bfcb2641544feebd2e42fab781bbc1a27bea38d6cac1de53548392c33f38a4772eca8d9139acfc02dae0cfa521cab9187a978ccc210c8f7b92c9cc3b4dd28f6551", "-13a46831cdb2ded1df8ebd8389431e245d70fc72a58264a78d1f049fcfe38b53eec433fad4ecfcdb630dc4713ca5c5ebbba11b823c21fc700f06bb556b2c9bd0bda32805e2851912794281a215a7c1fbeabaccef69db106b05e7f7c790b9777f64be3b7e179c5557ead286cf37de354e8391096a3114b4cc026567e0bb1592e61b9c6cc0d010c09d275c5a5ab3b88232f5dc62d07dbdccf252d1a3e08f0bc1310401de23c963d9fd614489fc25a492944b8a6904e4cb043cc2cfcb971053a6a985892b555a702f31457d5f73741", .Okay}, + {.Div, "-6f4165ed1711de486e08640426e7a0d31f08a0d8f7bb0a999f2a4cb7567601a82a1047f26aecf3cf1936a6586424fbba4e60c5493453eb754d605437eb3fecef7db2b6a247be7bf208bb3c83b9e8f3eb6ff72b6ee1777fb756f7b11a6d500738fde131899c84262f2f6d559cd8af9f997614648279d58eee747562a50e3cc784fccdd1679847ed5cd8ffba96709f7e7dd056b7556ffafd42224febc555f81b46d237d639b39d3bd925672e1168e5cf3a01db66688d5ccc98f791814209dae50cc07577f2c9bb869ad1bfc195222290a12717cea9cd7bbcebbc7f52d3388f24cfeaac4f5c7332192d64fbf83db5e12ed1a375cc979d9953283c2e06db051b71ea20a592f9409993199ba10671336af90900751060f8642d9367935a13bd03d562c7ac2be56e7773a5e9dcddc6f70c4bf488061193036425a4942cd282a0e6c59868d496c99a3401f78e6c7d3c30b5a3cdf377d32b42e3a5c02ad5b847968cf32f0ab01662664acfb408b7e02e1f287e345c9bfbe73ecd2f3a9313f4956aec19d1ee6a18b16a294071422edcf666a8bf4dd1e773a8b01e474949a179bc28074614ff599d727cb874a7b793164a5f41a65cbde1220682e936bf73c2c2eb5903b237a216d4f9cf9987f13d499cdefd555572a4a642aa7eccecc10c8497f1c44a896e8d0f4db0b45249d32cf41ff1f7f04f8360b23296a5b9fd223515f6e5a92b060d", "-4d2b84208723b6fd958729d2f0dfa0d9919f17a7700a3a9b3a05a69f10f31c43632b623978684f153857137db20143b204b808396f04c1b0f7e2f0c1aca719ade8aabd10f5c108cb01e4bc570ec8ba62d3914a1feacc45386d79e37dead266ac2803ed1a2592efa8bf3567a83833073f05d0ff180ddd7edd9d265f7dc3e6e2b9019d2c756ce3f4ebc581501a15af99c0cc3a41c9be4f62eb68c5e20f879e39a6ef09be78b9efe4d2f05cb82848ec563e9ff187f6a1c2cd397daf69b1aec9a4029ce8f4d73523953882c64021565a7f1b47f6cc240889803cf1ccfcef8bb1815cf49ddebb7e49f565327a25f5fac5ecaee327a63447f8b6232f6286f1ab4a3d02858bd49ee243420163003c8211416f63b90975aa726939b2f2eb0db2d604b20c74ac964ba090f67487e4ea346e14bb9bccde90", "17112d260ec7c883eebdd9bc328033f66f689cfb716bae5677a66ea3658437c145567a9ea09338414557090df11f4f30821400b5372b2d56280fb971ef1623d28e7a19db149f67b0d6f4bceefa6713d8036a0dbb3a3974e9738bdb094b24a84e0538956ace7c386ca278c1fd04272a46db2f807512bb3faf81e4b7461c3a1f8a07b13284cd9c7930f41a01cc45e21b1254e4a07cb26bb3cf1b79fdd21678bcac2ba2b41e6fb81b5b028b563337fd5ef0d9a127289945f9edf5ad5cb88dbaa66673923deefd6aff0db8dcc640cd2", .Okay}, + {.Div, "7fc4363fe1f0031327d83f600305c7cbd4a9eba691886c2c3b44dd6d945b5a5c421693a8f8e3fb5278e520a6a3b91f93218ce845a58a60b33529ea3c217b5f66b5272eb612ff1fc65f12b5bc11f8bf0ef4c0632f3fbf8c762f56c119388b9ca011b7a7e19834291477f58d3df2b6ba42958a169e9a383b211e8587841793f86ed0e8bda63cf61c8ddf4cc81e35283dbeb023675cd039ee0e254456f1b42374e8bd6ea31290fe507dda3f4d883c36e5ae140dc92adf9c6305f37e1f1e737572b28af9a6ca63cf07eb08a813498ac1d866a98607da39c1fe306d4b70926acc241557c7f51bc027fd9e8fedf3d03111f2232c40ed68a51a5b4c916e9c6dcd0401a3f79a2520be1260715b7857e74d6cfc5e1b49829f386a97e8578fe91351af82eb56e993e07182b4d14e1da5a75706beb938a588f006f03167c6176bc24b7f6c1ff98d123142df3fa25303b977d289a18a62a2d11cd63a5f7328ae6cc8f197eeae76687d384c87246bc65994071a05aae037643da0dd5270de0ba909823d1116d77f69a29b32ec34d643a93365b3e9ca62de17f09e4f5a14fc078575e50a88904156f33a650408d98c1e5078022bc0e8f4961a37ce80fcbdac9f605717b945fc50d93e48625938da2fa9fcc80805007636b78c41cc4541756e6f414b348f996418831b3c5295c2e4180f05d0d8e2655c2e039290707db08b339564ab992a44444", "396f21be296d00abce846553a1b0217be904dc71cc36a0602b3171b5dde3bdf3d654b0d3a83d6a0e102bd61c9616459a59d5d8613b7809d8349b976251dff13f5ba9700049ddaba81e560c819c35c5292b38bf5b8cf9a456883d6b3b4426633c473a55fe8cbb84e516f668e33a85a83fde64c9e33e6dfeb5fc72ab19e133230d3e01174a53847fc207f010aae461825d10177cb22f33661e4c40a57f2c1761423ccefce71deff87924db1156bb4813923255122ad65be22589a19e0236f195ed08164bb10fdddd9b4a7afa7af3bab367d298b32cdcee8147594097c1b9950401e3c821ce41992d03a53153183551992ae75b427c245f3c132801851a180e732ba0b8a41a7ffc9758842166ff62791d40d5ad77fb6f4ab3b1db06ad2e1e3ce606e9b102eaaecd8d047d8c44dc9a72a484b11a9a", "2397db6b11b8fd0916b9b3ac922f7aa23de79c227d2a0e4d0cd8bf377174a993a0322662c0cb6a79b00c1d082672f4a78720c0388489f4570d2f0e645c8ec55a1b9891c9e0b92f2630c25569bf16427c0db989d05743515b92df8e1c0a05ff37b703360ce3303411bb93ccc9f50359652519a829b8bce0528349e0d85272aefaf4fb68d97bf40760695a28f24e60ed5f232426c4283405c22b8f0806193a7770933375e62c5bc55c629922e3366b0898f1c6d4ae4023c26eb36d630be78b24cd739aae017bb7e1e5c738ee2978", .Okay}, + {.Div, "-67a88d37126c0999850f7299eb1810460e1db3c52d0a96c3ff8a058134ba5fa913b84a2d2d403fdda9ae221cf2029bbc0a86e31b08732448543e079e8aafe231de1dc0537e44b7525bd63cf64234c268820aa9bf1260ee85b514190ac9a5278eb3ecb5b30ac48a76f2b95d9983a1df1acf267808c347fa91d10c1fce685a41a6051103212854c84e19280255b1695f32fcf3708938d6165089b3fc6965b6b091b0ed7e507a3a82c76b74989cc9b728315ec73346ec1429b514e1ab91b696d0815620637d26b1b0e34b18d1a2d5adbff2e02abc49afbd3cbb7117ba2df7cb9bf6062914be4edde0bc61ab3e18d092f2db84559de773dd3b81b7f7093e6fdb0917a4b32ee06f98acaf93443788a0a68022f8d83c826b0c86db4c6c371fe95800ab64710d5c5bf0dcdb37a8b41d65e1138589fe5b24f8a374f2551fefb7a247b2d18701cde357fe2fda56094a32820384e7352afa8ad0e7a1c96513b9ec528636f7460b866afdbda504b67990ffb147dc8ed357ff6eb1f406abfd3ff82f835a848e5366dea9f15e71d19d0eda6edcd62dc206d7b283da58158362cf2e41a62417b44c895952f70f93d18a3074e59697f34068b6baa0cfe58e241bc1df174c0728a05001acbcf1bc53fb0e48fcfa09012429c565a997a681b2fe27ec8a338bf542b3cc7d24f524e05296d13a21a6f88fb23f69e1402d1105bfc7f902e54114b9e27e", "17dc9d425bec70beb174b9cbd080339fc7b59439874df55f14c2cb8f710aff87d98e1441fe93294d96f509fd994f8ef0e9fe28dd46874fa319a29dee1893e10764ee176a4248d8d8975412e45e59e192a151cc350da42ddbb13de97eda697a24cb3512e4c09ea79c4ce14f0f6828569914c2f5fb4b057dbea0431bd0cd9c1b68b99ad498e01a03ccc0c32475c95772ba9c5523de59af8d3abae78406d3b2a1154b1ab9ee655b13d24246b5c8f22a47896c481c4ee9d49f6ba2893cea831cac425cd93079c3d6f71e8700676876c013f1916edc183729b50a912b1794942c6b091489588d05ad767bccb4553a51c087c874ff04ff72004c7523bf22f34b40485ba15b3b83c0d0ca9e7af10242fad0f37f7b1010c76a31485fa4cdd57116602385f4f3565828fa5b8d799673f8a73295a6b42b818", "-458183a56e31454bd78514d7bf4c2e3017d81d599db27964febf12b36ac7a9188332e6a124c1224554e19201794064f157df037cf3149352152dc8d135864421cf69171446ca0cdd69e96b2f71129bdf98869ab35c5616620689cbc9c64b20541e49d30911d8a851807c5db21f33708b04473dabbe701288a7f92858d9172f7bbf3ba44afa1d4d62be7b0a618fa59020aba37835dd1765a5986dcbee4ef44fbb05d03fe2603720508e3ee36de13f74f4d8ae932cf0eeebe00a464bd3240ca4e1a8c2d00880aef5d0e16392d17b", .Okay}, + {.Div, "-5d4625d9956f83426d3ea721fd9668c6a4ba75435767fa4335637b6ed7165e418322babf79bdcbcea3d5e3ea621f1d16891799cc930e6e5ad39845f21de60eeb8b23991ec0ab886ae2daa00685dece2af39474f569d388b6c435682d172a57d2f236d89437580316ed61227ba9947c27bc6129dd9d159de06de0cab77b2a02d2b0759d87939d135956a00e7909488de7237f93d033913da418ad2e86c81e0893a974934fe84c4c84b5e14fad155a2fd27e2de0e7bfad93858e0e4cf68e013c7bcb53d6c0808fc30e102fab40fa7a4c06bfa3207be688abfea865b0c6bb2ed236751661f9885652fc3a19383c8825f71e8bafe5e6225d49e343f18765cb6964c09be81bdecb4ad1c119b332afab4626d2d92a8628c921eeaa9000492555ef97537d7f98dd8f8e866468465c07852edd1e2a7f16896bf588136fbf3864ffa9d246f31fe08bd154c87d053735ca7a0c2470eea1b38ecb2590891ecba4607cd06d70edbb44913463ea0b7999d53e96a4e112a025cbd052f2d9095ae639c1daa21fe91541426b5c27757810550f2d39f7efb5e37e9cb727c60e39a98685b06f7612308f2311eda8d1b803902ccbd82b5b1e89e5e4e1c415b3c5d77fe06f749ab360b25342e867d40bb5862ce294dc2b8d1adc4a9bd2fcdbb6b858f420c24d28012fc45c605b990b9533fce7f502a18033404202b079fb6dc3a0b483b21bd6039a6289", "-82d8e703f9e9ee7706cca587b4d2c64f51f0fecb2f632e748d5942775792f4cca32eda90f241a8002c55ff816c03c52d2eae1fa0321b7dc087dfc040b8b4b8ed509d02e7a062ba75c21e9dacb25d76573b07ea71601c5cf838f478a7979717ddb127722f31275122a2f4fd4ce45d474fe998f65047547094bc0e29c1eebf3454cff96e69d9ca40d7212c5287dc64a9e70772fdafd223a1a2ef3bb179f1472225ab1d1695bcf23c07db40dabb31111dd3d7bbafa789a3a30caaac8f8f2fce268da2acb4f1851745eb3fa027f4f8558b828960e0c4286a0878115f8171ddd0aa395fd1ff35bd1ae3819538d1842504206e5039845073c2df7e6aaf2190f3dc72159c4bdaa3ac26a742f2f5972e20ed1f104a9cfe31602b23178cf2b29ca5225613837fb92f01d68fec26b41aa37dcc17ca0527d3", "b67d1acf3e8dbad2c8654e7349562954ec287111c344d30aa1c314985424aa275a3e7015978d678f3c63fc570a2889ec0a47ed252c7440bd7c89d0d83ad15a7a27e34fef66f48da57db1168d8644425aa5c98558b959ad4bac0cf65d444c991eb72db1f3d2c8d0b4d076550366b321120d5f55a9241294465bb9dab0a0321f903c0b0b82b090b4504833f254d1f60f6c9a30ac770f0cd9989737fffb90cacf9612f6e46e97c620fde424589503559ea30fd306fc50eb8ff2ca994fa88287a793c91c82ef29d61da3536e700371", .Okay}, + {.Div, "8e050d7ebee08b7b9490456cb7a9837be2b7a659569b87fadf8c070bd0397d4547a830c89c731f61b377149d51a75d9ba181f929cbb1de65ac7ead31a38f312914fafa6df66d8215c0f62ae3ec46d5d4c918459d54fcf80b52bd318916189198fb3d4400d9083ccc28d6d9367f4796d2aa2016cc3774c66be7ba1baa393439d2b9549e6a9212547d0aa1bdd349d635a24ad4ea93ba36eed6d9c94b204d0e03ae822a3aaa21fe5834cd894acde56f87879db4212b3f6fdf705eee61ab54398e87af9ac58609620dc11eab1d8e65c8c91c3cc1ac1d5880d5bf64745a645080ea929a6a167fa2dc041f5dfd434cb0a95c774d8671ae9b47663467ef86ef58c00f567d7863c473af537e80ebce71d028a8d0f6028cfc2b92fbbc1867c5346fcf971cd7713de1bf7fc8e6a86c3959f40e73594b7cb2b9cb578e53a161b7e98ca5220373af3c81e30a945ae9d87a5023a3d1eb315d9ebf1b9c4e80a2c25ec941d8a93d36447fa50d12b015d2e037cdb169f59ddfe373edc7664e138cb5445f4ac6bb1bffb5695f41d4493fdbe6bdb2e9acdd20c38c3497f698803fa1b8c306f15c8818de5d66f3edd40e81072e3a1f7e355c4677fd76c5368190b164e5c88bd709ff4aad789234d7925cb2766d61e8c77926eb7d5741e234aa56465776e43e241a91b6517a26f053526aae473ca6caa6a74bbb316615901bff905362ba24280aa5f399", "aa16b4f3b707be853a2706dacea736e2039f4b0af49f1c928dff3e8f767bb4f3d029b5650b1e92fe3abfbdf0c9f4c42367b170c6e36ae95e7c0e8057f0f202cd4535e5e475b6f0a7575320a788059d6ef7c1a006655d819445d9568a661144875df35ad84620dd498c03a7429981e9fbbf449cdd2f22068fc0ccdc2b6ec114767f0a2fd4d22e4511ca8d15f2123410922b3b73bd4940382704c8849f9d0d8e4d2b9e6d81077fdbd87055ad77fbaeb6ab45404bb6c9950ab0f2dc1e83f2073c6c6f5c2e84fb31db5d38e8b7c0ef780c78c525c6bcd76670fc337d44c27bb78322ce7f679714ddddbe3a700675177f9c948d2140a1f4bfc8620fefc14294f98515ca2684892869bda7af61d19fe47fb5870c2eb393940a419f2e4bc3b68c78733100bd8cc0cf81a0b2cd08b13ade7401a6e66999", "d5c0e4a2986d8a2ed9a6020e6a4de31a8b310f01fbe80803ad6f2c3b31ca443e5c4eff5096d212fc6e1af1518637c855e246446283bcb6f4b9d1415ed09a0c911bd37b75e7f747aaae1b86effa0869949ff4be259df25420e69418e19d7dcd46382e6dae649ae83beaf3c2487a6e8ca571aa23c334556984fa9205bf22a0c1ddffe933c8a66653a6d0172b6f58a7451d819e29d00bdb37dd2e35f82360f0865d0d4ee467c0e0b3c61237c6adf48231a1e87752d3445e33ae08dbcb8931ad797e09bd855192b7d54e89ec76e619", .Okay}, + {.Div, "-c191aabe94b47c9d96275f47bd0c895c5414c16490f4c5ae5fc3814f9626ec1f35f09ee92a6a769e4f333f23597eae37bcfdb906ec70055eb8c92e2b2435cd971f02c4353e6fc69f4f1f30b61decc26086d1949ea8dca3f60c742b362c7a3600414e3edf60e7d27f304a8ae32d7fff0da27e08d5288f1e6d38b59fc88bd0a768cec73792d5a0323b6a2c88e891efb1cbe1d14bb5b173c80fc4f026fb4be91b51a09385d1dec4cff2fee60f6012bef17c5a7375e301f46748604a86aba44ea0d5797e23199b2e016caf2fe316ea98afb4626eeebb034c65d2c2eb81ab3856715908e462d9d22c8712515b0932be3d2542e631c663b24f62881f7422f210bca245e1ee3354752c24021d4a1d9c7b97d3de17f3a7504b6297766c3f59c91b9c1d96f2658c3e10aeea083960ec2a84149e62d78589b2cbc684fafae7eec00c9d8e533b232e15051e0248f963b2cfa6ddec7190885ec11775904afda53d05915e98d992dde76a62ae554099c648b434d62da290dc8f1dbd83498a64eefcbffd81cb11cd2a2a60808a011c62c2f241a769ae23dec4f29c0d6dee2ea246f12601c0b29f78bcd8960e8af3ef0658f371a3db0decaf786fc4a349af735d56cc5499ddf85443838f0c5ab18158df589c8b870f67fc4e77810fdbca2493c483f21bdb398405d8beb233406a342b63af05d7db89cbbb9ea2b4bbe08252115daf46d03db6dac9", "-8e88c825f3e6121f40d896106696cf15c1c913ad0efab87464e1af619ee5ecca2dc062a2a4a4fd33cde17311dd20c98c2bdeccaf10d6b6c5fbcb597f7f5d634cc506c435c15a6c08c1cb9e4e34ef0678dd85e893a03af014ffdc97b936a65e3cd308c25d9b4346d2355596ac11d8674f17dc4f04ed24da1705bc27470623d5e7d4589725d6f3e04d0c925c7e4eda84d7e8a2da52fbbf38e8b1ef760f91d42a546020261c4cb11381db4feca8f60614420573bfb4a6b745dfc9b7226a14e3e9a7d9b7130d17409ca7aeca56e4d11e5e674e13c5ed42b5fb61d4756903c106dfafb0cbc554274222f4c9d935301e021a55d4b96ed196c730df8de959daf06a6420d88157b6fa96ee6fd49f6d9717e5e988353e284a0c4eb29d258ada084827258950487654f58017b98fbf518b622abe64f669ef", "15ba94d8113a034b2a49ed9320e187a37d9612fafdb1db33f6af794ebba60524f6d08aa8a4eca96dd53a3168c3a3f6fb47b57437727a9067c52a9530f2787743b73d85603ea919060ddba5e9605db189cf78f0b830b7830a84f4e9d3cbfc4867bef253bcee136d4629f9320e5cfd12a4798744b1d371cf0d8ad051ceafb5da6f362823e224cf346bf2d5547780d8bb3695642be591c7d107582f30b36434d025fc0eb6ce924c7dd4cf996aee0182afe68b4ba61790ec308533b5fd307893f14c8da366633ad227242281075eda7", .Okay}, + {.Div, "-c3e671306ce5cb836d46c43d405c0d25342128d90449cd4e939b3d81d20168dc15d28252789ef29a9754456a151e56aeb33cd78dd3871d918cf8dfe17c4e98521f1e437331581a6c87adce9a2c7f5f621c25edeaa7f7689fa3a9d0c2384de1591fa7eba5798d4c6228f3f85db3dea9084dec66f22a915bceb7007da1261dac1c1f975e1ff1ed4934f4470a5119df62d23a3f242000257517bf717b1b8ee82acf348c11dfc5327b2c4d598d22dbe41aa30ab6cc10b82f1a8a9789c6cc8a9df372b34c1642c3f8cf13fccc1ddd292f63abc7bc39339a2bb38b505993b6775f810a39bcc908759f6f9a63ca2aa8aba2014c5b739299f62f47881f4c3c0c1a154eea6efc11f8c4d6b4341d2328e56dc55752324263151be563cd965c201944c45abbee04b81bd62f1d3f7d5c947f76551514975ef042a9408ef56018fb845711267cfe4a4f8ac99d3086c41b64183bd72be4fcd15e36be65c46bdc98ad792dc9d3a8989e6466a3679fd69066b478fffbd4dad50fe07e07acd46dfdcaee1008f9b9d8bc32d655a0c4986613a67f3cac76064f311fb1817d24cda4ba990385172ba02a013fe0506ff23e878edbfc64906a065a8f24eb4df52c1de5855c53d392663cf0935cd9e85b5d0da58fcf8e0524a28bb0d4448752d2f4195fc91d2328e7c4380e18e20e60ebdaf71abe6a1bb5abf716ee6aeefd5e4f1c2ef5824f4c619fdcd1d2", "13c102377884ef7ccf39716dc36b288b2ce4a45f5a0ec60955bc6d706aa08e5eb8f540729d51a111a141f103b81862fe2153dee9a84dc3cfaa15a9d69878c1e69cc6bc7acad31f4e3ec6724b1371ff1cffcf7eacf0d613fba40ae8c489215b780f879395429f9c7e9bda5e844a5b48327778c9c5f592ba5370cdd5d91cd80cfd2992b3dd5ae59d62767b57a1f9f13ad45daf5667e5f13b4c536c34e05343f7df992dba20b991b469140f4771350c300db6c6d6d7c2eb58a41a80460596b777f90fe7a663f4300a3a30df83a7646c79276ba13d9a542c6752209b773e0545f0acd4ac3795633c6b95bbce8c651f18b84d850db65428573ecfd8875fe15bad784e4a0990ef013ed13fcea5e35e6c66fa6bb88bdef1fca8350e32965e40ddad538ec97c0954b4afdc35efb8256d8e529b9ed898e4f", "-9eac1a49dae59b78e67127100240987b43f1e769a2361eb74cb86eb7f8d1e601095796736800d0da234817749ae252067a7a16b2058e7c4570882d3d07226c3fb67cc43504ddeeefaed2b9fe753f923a214a1cf9e6bf653cfaa1f7212012f05593be02c72797c458b7446323d7e80f6adcf5388ae82c15f269c8c09c44bb3ae77ef6fe4caebe19ea0451ba2c8b189db7a21a85e758a6651fccd01a9114aa2f6b7345cb48342eaafc4b0c26fda8150f98bff0ef81ed5d0cc6c77a5d5c63502893067ef7ec87ba56c85464949976", .Okay}, + {.Div, "4d2145aa20c8a283016c2ffd3e6f737465ad45fdc570eb81083755702ee51912f44a1907850545f426b458bede71aa3751098d5704492ce668d68aba07260602d4ad880695683a3070a5450bb3691247e799ffbe5777b1f20744a0473ee5b611a421b844a4fc3f1a3c0af38ce6b7dae4991878a78c42cc24ca11da8f05071a24f9408c4b5c5b89848a3c9d4784bd15396bfa8074f6dda27924ef0a5fcd3c77dc2cf297f73b7d93a2e6325c056e2efff387500c395ad5ea1a813ef562b64baf4c89ca80eefaabf459c19850edafb5f3a636a27b54935083b5b5410c5ae8343e2b5d9677c4554cd0e02a70406d8959ec2ec8c85cf4d09bc901207f167483b36426f2e3d1c9fa46d74e4d39bce3732a22d0f17c913d23360ef6a373184e8d6dac4cccbb44f100985c467c1e4c88ca53c420cfcc60c97a95a0f698460a4903cc24988bb8be8dcae789cd72fa0b4fb83392995e4b17bb80f4a45468cc60a3030f05247bde0a1ce55802cdadc9c717231c8ef01a7229120d01100a8af03ee4f5404a4c10374bc5d50c4f4f4c22fffc38b50570a9193d8fb5feacd124bf8189e8e78831eeb6b4803008d91b0a1e048c00e0eb0f6ea13ff2ad764be74295e640ebc7d8aaf0e50b0ebdcc23c7ba2099ce70eaf5f56cf6a186b92b8f78a8d9c6c57ca8081c666b9d782405584880a2170cfdcdead3d73de437f5e3fc4458bcd235b450f905", "d5e8f6514041a4751f246bec863ef2eff958e39e88ee5957b899888647022dd8fa1252b2e0ee838edd9ebfb933223f6a82140f03189709cbea5e91bf07461a0ef0230c11728c1a668cb9e17cc57d3076382dd1033f74fb6e987fe0130a0613023591cd9b3aef47b7eff9d18c96111eb7abaddae2e1238534f3c040ae32baa95424ea54573f6dd2e3cd861509ecded0041e5f439a3cc433fd1c420f9f33ffc6e8a68f539a87cb680c0eefa48e13407ad55b81380b3e80eac76753e308b9371e2ea6f4c38bd83ffc8a917c20809a56d259411a461b489db286d84f98d6c97f4e8a041c8dbe9cfa0ad2c472dec8d6624c2217ddc84b31302fdef829dd5152bd621722893dddbde66701ed6e001ff181a7a077ae4913b1463dcc476e6a9bb39533c899331bbea67d7bf29306a87c4e17433122f6ac", "5c4e7315d0724438cd40138a5f2b8b1ff22e40c6cd92b1ff3e39c7fee0655218b65b0af925c73e6c1161f84f9d20618320d79c29c35c73a637d559eac65276a65164741f1e3c7b09e19f4aff2b3ae7f50ce5d36225d6fd28eb4f4866f0fe0167bbd0469b7939ec983222e553537938af2563a1c6a27ba49cf9bab5bb299b42d898420e0ac177b6a46e5113888531242e44f24fc60af91fc053f988c02f7e5e65f223b8f3943b6ffdda2513d11f2c82ef0e8b359ff8ecfdd92d81d508f06cd1a9b9a86fb7a95c3b10a3d08e8380", .Okay}, + {.Div, "5ce5def4957566785749f2123c886311cd64eea73d30c0d5eb3020db0900d5007fbec8c34d1f8187f2652bcab1d69f990418c46d3124d69628eb31af6a0d48bb538858a6ea0ecf6a2030851f291f3dc6c23733aa2048dc170212314ced257d98529b7bc5768b6d27deb6899a918d5b63478723a8adff2cdeed2fa488113db7ced52b21b68b64304c3c37f525117ac00c7250cf7298ed2ed674d69af1e849535d1b2dfea98b152320181cd18b634a501190b4e220cc15d9f9b935dfd9cd364672d837eaed62a4a8447017d1168f35078d5886c5a3d89aaaef0b5b0613afde2749e69874cd0ac970c4ca26f2f103222e8182a2d250fbc0155bf1b916df2e535fa31384ccc791945417227c9862d9a4b322f836d625864fd1526dbb7d69b3101bc60e0ae36dbcb9deb08a3baa511d06ae130e74122ce58dda00846f85bef8fd488d34ccc2f44da528b3d695db247bdde31625edd7c53888d5c9e4759e6eafa9ac85c07d87ee00fc197b07158820c85c766ee5d3dc445b8e3dbd120bdc3728a1d78e64478436967837db62508b773759ada32a9317b5a4a708f1550abcfbfb46e94299483e871b2ea1e6081466d05e1a63872f218e305b509485a49e2be5d7487acb9d6a445898a60f8264b705501da401e5ca7b65471f148c566c1c2a56f33d8fece9d7e702cbafd5e84ff02f126ec0a4f0bc478dbeb410e3a8e4fed375374a659f", "-724c5822db26fd04d85767177e85870416b6add32e2b765b79abc0c81db62b9bb932e76047f50e01b35ce3ecc6d0ceda5724e7839ba948bde396525e2fec5332ecd0aa1ccafbd21c73d78772bba767105ee3838242c5b5d8de450a6ead2e6870d2c816c05d29b42dc22ae601b953071d3e87da1106df7d939d7b613063bbca9cabd9800c809a89b8169f08a9e16328567f4910edfa10eaee80d20af636dc75f61f20149e7d38949868812f5ea9754fac34e46d33f13dcad2f7d7847f62f972c663237e2959c80a61b83bcf0496e54dfcdc0c5b6759ee837cdd6d632c6f1246e5357c41dab616986b1970e991666fa76e7384d4750ae1db6d8efc8f12e9ee12e46986dc9588989a582d0b93a3f4d8697830cd357aba5576a1d0f036e0d1a76483bc7b6f3fa66978ef0cddfc8c4d9e8641bae348", "-d0118ff5d8c730dd674375d2f066280506fea8a0a71a86e460420c72df22e8f537dec68aaca4fa8b7a6bbb735708271cd2ff1de6fe6f4d1d904713dfb103dade10f6b9f755ad96f5e2e6062313b125d4b4e73ff28e261840b0e7ea6c3368238ac44283088dbd140dd4bac7d1f10ed8fdac35912aeb4fbd33b9de1a93956a75e3db5533e3ab5054eb5eaa25b288b497e7ae0f326611a865f3b8355193f9a8c4711ff63731a23b974cad1164104694e38595d81c9e5825b471ca2ee168b9eb39caa470edb8712a67b361127d4dbd", .Okay}, + {.Div, "bbc72ec7fee116b6d268b43dbebce8e4f31ce7decb6b67032da5a3d558f3abc0f83605be789a13bbe6239e8a78fa3443ff72b047c35606c9d0d65da0ae4ead57c108883db588e6c872c79e7b177c905252e941f043511993be448235bd0554ce27a257ef29d9303a3eed3bfde7faf31deb68c7644271d40514cd50a73c7bd9a700149ed839028b1d56f3c20be2332775aac391f0f196a4ca4b771116aa4d6b421b48cd698c07dd672bf6352b22ae042ff147110562876a8416c1cf31325ba5514b7fbe09fdead06f0b0147bafab817c4164fb3955c8d2556f4eee3a24176110010564a86535d3fb32c299774eac5ca1c401b812d96b3f576ebf6c08b0bd02c5f85091f64d906b9639780fdd37866759332c7005e6c09c05adbf32cd21c6b9b9e4f4bc532384b023633892a7fff743f9b8192ca0b3fa76127a64aa370c0aa0ea8fe39d67bb935ef0ec740ff11c58ca16aabf53872f43946aa5453a20ba2744c86beb010469f71b2eea613f9b96280e4462ef97ef9386d656034ee7341064c9fadcbde8b320adb785ac4eca642e2f907aba9dd125a3a89667b1b5fbfd407a6c1e63fd4f8820d21ec929fb16e491446756f4b283e8c7ddf31bae64d980c7952159abf74d710b163b3daeaaa81bc1b411c76074f3277b200112f56354450814c1fb8fc72cf2c5c6fba19dcd11e3b0d02517823969f0712d0c54dc50d7a25983a8bb7", "-140acd95b2a09b8ebdb6b18258ac699ca0ed964e6f8a4a3d005e42d9ace1bcc02d5b77d8fe77092806090f81b362b139eed172870e38a6cf5c6c359d1b86b045622e723337c98ad481fd876bacab94d31f4f6975ebf7e829e97a04419654934bfb5a5f215eca95c484c8bb519b32ed9f57b5723b3e5043a9bca910c55f6be5f02c242bcbde933bfff3bea2d2368ce4d3a467b0ec8e9aaa8d638923d444c9d1e1dff85f486ec5b8459f155b1874972a5eefb503fab5ddc31526549a49b36de20b8c828ebe6aa925afcd6a7a6ee33518c779b25a70d7ad9519c20987dee0ba957a20682043740a256a18d1ea2fd15e9b73b4162d55f4aa05599f7f194b382037eb18c7e6888afefdb64c63ce77330ef53b28b81a8da7bd3b124aa084ba28956a620b3a925a1b95486afc9611c8acbe859e91623f5", "-95e7f9512cbe4632d50918f93489a8916e24e04ce0ecb4d0991f71a1721be8510a26a15a86fe1cc5b207004765c3e0003bc516d14e86c25a2405cedad778a8ec0077c7bd97c894637057b1d10de365dd9d44b318d8f8c4ab190cd8173d7803210449d32eca751c9a1ad8a906beca51e9bca24d53f334fb80c770aaf4f5e7600b9eb4921b5818dc358b2d9ef199a0a2a0b75f42c93fa56053a30dd76a993b13c4aa70e87052e4798944255a42dd4d2130752fca46308b81bc215cb6df28f8ae42442b60fbf90df3920c57985000", .Okay}, + {.Div, "d9a93925d7df00f9fef51a9c3b22a9746e86f1b13bd799797b93f33c226c59cc93ba0e9dcf363318252a6dfc1861b68fad177b34605c51edd49c2d137e7252508ae7f3594fb0f86a6eb333ff1a8d40ab52ea400c1eb714c56f364b88bd02c9807c6fc2236d0e60617baea9fa05a2004841172a1544698ef59aab608f57d75d8bb811bcd10b78b8254b561b0f73eff7246c72aabb71c88d7d4f3f4f3376575247904736aa3c42b0a43badcc25c6083a7ee11a0c657631ea1e3753c01b589cf7a99170921025fffa02d2773c00d22ea6713ab79c0f8eab47565623f4de50c13631a89a9ceec5cc07cc80e69e79d2304dd4e5da1e87188d4199a61062d736813978b91fb23f9fd6588ee137827c87b9d1efe82d36062d5384b1aa85046d6fb68c53f15403c989ca535a25cb6079818a17c8ab42ac328612e8485289f5524d2f3f5a72c0b11f6cf39cc2d3d00c14c9597e2d67d4d74464b10ba4640cd12dd5eea5ddb81d6018629ea4248e77ae9f0bd561b86f2f1003613ee19633c616ae45e311c22930bce6440370e440cf037c213dab9fe4cc05e8fec00152d34a105c79e5c982af084d9a8910fa575422783eae7c7dc21742ef051921310fbdb0f9f13587f0c28c74f66d27adba456018572212b0b5d7e848d9f71d147826f68749fce82f0aec54a75b2f2a5963aa39b3bd9aa109541c5e2a453b4ca3b6cb21ac34f76803f4fb", "-1950238afaf096bc920189be7505f9a4a74343665691ef8fcf8a558ba2cc67e96e5a23385619f77d1f37e9c2be23936d48e730139046be01125ef3392b52b8ed4c74b53f1c9dee5cfd6d661fcbe627ea8e7cb5e2a8828222c8429b5de35668a022680d89241a891085bc6dd7c8ce032e67ddd09ed07a7acc820949b6ce1e424bb746bdf6582abdf117ec92c7c1ada7515a48668010b6ad251ffcedc2c1c10991d790ccdf504d94daaef18944328ee6143a2ea6aa0da54bf75247ba744daeccf2bcbdaf140a8ada615da1f89c8a77a26fef9d87fdc577bd646ff7999f0adb71e481c8d1b3d4af68f9ebc25ce26b427efeecd2f17e86391fadf8cc4a69357c8cc125940c1edfc99e4d0577d86597c71d702c8edc1c26dc6f40b57a2679b9c305f19f99577b01a86776683b0d2f6387de7a9528e74", "-89948fd11a033ddb3ce8b3ce6e1b5cd990e7f3d0371133f5493c72b35862837fc52fe3595d499743d44c2a85053f3ed1400966a44c4574b538eb595fd453e201017187a88f7ba3999ebed9d4f54776f90638fee9e00cda82f1396eb42efa52875c5b4d30f76dae383d0e5f4754a6f7851e59c3c899da89379a1aba136e1b64405c1476d514ec68ffbf90a5a732fadbe25e3fffc349cf37470a909d503d242f214c4b407640b380fc76e8738710eb9fde851dcdb70c6649e7b2d8fe9c38bde0f254a4e2a8add887fda533fe8e2c", .Okay}, + {.Div, "c2243d287d8f8f2c36b8116c736293c843a6221fd96c4aa44308259455063aa274b56476cc711afecf526429e23f3a8da4339f5b21b93fa03e657aa388b760163efa8f705c3004e0af0834c5d0dd7b208b69ac7221e96d570a430132b8eab5ab72a3eac7642dc350a1c9197b59a0fae52dc779f060ee16253e50b1eee792df9bd52412987ea0d9a3341060a63e01d7cb5406237f3a515d99c02e341e8818edc54156cf569a41af0c5e8676ebeaff156731184237ef81b7aca4f793ed1567aa30247c9bbb9490270271b40a8bca772d47093b4b2a09837446c330cfe9995c1754aee8efe78f8b905f5234676e2121e4e580a55b75d42766ba73ca692740f4bd2577e3577ab708ebde6530df355d8cd5ecd05bd238bda2da2a180016bf996d28f027b35691ed165e70d8d0d7d2dab601e485886f8f6b7e56df27ee6a5199331efe40c33df112404d8a52a0b0fb57ad7101fe0cb162ea2582e3e5c7261cc14eeb62af5b2876a136dca20b44ffe881bc8a177c60ddca7be34b151fc0e5293b436667a200785ec5aaf35a0fbb9c196740fecb0e43dc47cb6161841cd47998beccb33a3ce01baa09ef4a7506ab7ddadeafb0041abdd58feaa2322b4562e055c683d43a9a65e546e2733964b2d4e2e1ed1c4c62360fbddce78e8a62cea9feef48d912b54901819725be37c37197870c93ae6a505ad202c7fc1d314046ae816c476a04f5", "-11fa690e16c37b06afb5bf0796e18a1835f3f4163e4178838d135af9cb50362e5a0cad86ece589991718e75a5688d8a122873ab8bc430b9bf6822919ea89ce5d261c53de6757b246954126b9779bc34a12095d75374fd19cd8d78a8b1518b1c947df70f1c09dd79f8431bdb0ca4d5ff1f8e896dea9db93c3a897d60f9a8419f12a349967fe9809b12ffa8e45df1e05f254f5dda3b559afb40c3a67d83ed74a8bb907220861bf835ab472823c39399f229121fa93aad8c49345b8a612927a8729db035dab83a417b3a1b7b1252e26b532706289186fd475c75f673bb46d05b1890a130348034b6193457ffd6d62fb61c1082ee94ff0520ef137a91d5cd319aaf36f6e41ae8f8dce6de414e9bc128d86dfbae52cc4b2383faf60b01b7bfe9e39e5ce66e1a6f969bee91e05f10eab52052cedcbc7f", "-acc7a4f1cf5d0824f66b3625dcd05414ad9b86dd0fe2d86a95abe57cb9bced43b26613a598d1e405363d294eb30daef45427eceb12f6a3b919910928d7e4541f921d98d2d1371bbd794d331d51bb40c83e12263eb8b8e518436ff9eeccd76ecb7cf28b23e2fc38c269bafd916e6a103ab7557e10652657ba542bbbc8d4a218795496767566be1249480ac03505b7879912a6a61a1c5a7d2d2a31becccc8aab00d4562e2bfde49d1c7d21980513ab6ed28106eccfcb248857f155c5efecacd9a47eb1af175b71230f01b5dfa65a", .Okay}, + {.Div, "e4b271d9429f23f4698d610472beea049c4266f817efdf9080b1cf6eb13689cac67e54f22ee1c4002836a4aa364f6c73ba8a256bdfad6d4f9a32328ca871f088282ccdf60c699c4b16031de2622c404d4f32136bceeb70b36ffc1d8b22c7c39ee008875aca2a5cfd2d135b08871ba0ec3ee2499125bf474eb881f7a86629bdcfb33ef2272ea84a804b888ae59a012b99c7b3051b7a33a2e54d592c201eeb41e07efefd896a87b699d10a20e3fa0024042b5f7d7915d9e01c38fedf4a7ac231d404d2b3193c0049de45c3baca16093aab864193fae5cc40fb9cfd310b2dfcc1607886dee028ca76e912913142e70b4ff6c1d385430d821276f6faed30a620f089f1ae3717fa9eb057bb3d609bf57ab0e2bea7418656fb8e138da431a0c9b205145da66d024d1a8cb85a296fcc6fac6a1f89248a29388f6e3dcddbde7600ca3e1a260a3f5db3127007b7024c525508917e06eed208ad4c0d344731c3099c199a18cfc098e1f95bf5c84723d1771d30a87861dc190cc6c6cc32d66509036187903459083e0d8b069bf33764159c321f0b704b48f18c9d947809b60ec00c2df72ba59613e57054e19d9abd88db655c474569bf21a91add611cf659ce2431c6075c5f04d6b5bae567759e97c4d1aaa77363b8ffea1c0842010c9ec229096d7287f58ea96c043ed9d6682c3837f2fa0382c790387d78b6f58920c0ef6ade0d0e46a711", "-1278d51814fbe0c8e0127492f09a702c69c25708e15580d65ef373e6ee5d6ff3d39e20d0416eab6be1522d22736591df42ee2c28a66f3d680914026330a224b819f5354b2cf1aa3f79c67b72fe5b92afd92a70f821a95290eb9d72c29ec8f1b8434402786492a16739a3dce3601e381408afb5693a784e75eb8a93fc1c6628bb29e639eddcbd0cc3aa08af658acf9b8be3d3ce83371527489bae1173bddbe200a944b417586ea488114c925e4ebedce55491ca818c88e76b052607f3ca44529c656f5315ba5daef4e942b32bdb0dcde5986f43b3443e6a4780e8a7ddf4bb13d565b8c0555a54cdba0cb38174b047a6917915f1505dfd63a0c24898c4cdce56507d5bdcacc251a0e86e2e4ef03f4b135f6ec25dec83481ee903dfe92ccd502da7ae2c1e218b3cdd66fce961ff2753bb58e34ab9f", "-c61782e3f1577dd17072715d0bcfa25b8051453f2f2bcd34abcfe66f3af18ade144ea9b9df121d7e8665fa41e12345ed5986c00033e336e208e767b54a4526bfbab4a4b1ba68dcfc989ef783e8b97d59ca63ef27ce881fac6f6e60b59092548d430f229b536f7d734d29aca69afd2aa003a39d772e50dbd61dfd701c78f93c6fd382aa2916f379e5e3e5fb20b7fc91bf83387f6231f3a97615b16234f980d6b02b40f8c0424a1f8a9ff584d27765807dab1ea48615f2ed7a6832e0b16cca9da990e3b890023d85392e27f8158d", .Okay}, + {.Div, "-cd47b51cc9c00d2fff233f750aae606de253a81176c59df1d880231b83a6344f46b31711df9eb65041c417a5b9e26895c4e9a6151b539cb543e61d3199d09b6c626a8f0504dcafbc437fcc8e1cb0c9f8efa81799fbf7aad432ad3635d7a07f2d965218f9c8ace55bf8c25c2e27ddcac70c031bf4d6f3781b3817e4b1b2443f68a50cd2edbdf89ffa6314717619c499e011dd3856959921df130f934a195ec65cffe59333d647f4381c57e125e1ff0221f26909ea20421e86ce785419a45855a16acabba76c0ae248c3faa3fb8101e07875c5eca51aee6b0d77693554d246071ab4d345994c21b207635ed7aacb1766cc64d51b3ceec0c111b63824d911fdae36d22ba7e9fa55b650d1d83cb69ea1d9a2e3526ad646d4f4fd398d8c6aebb66aea534ba83e04b42e19ecb51357136fc1681dcac3aaf9fad8923237541ffcdfcc61a573fb36c7738a9c3c2a4dea4dcdeed6de4bf8903eb77ee2092c731be622f408c3810b40d69598caa432f50d4d0e07f6b88aa09176f2d0b29130fa481026f4f1bc2adbf3f98282154e00faff86061366e1ff5cc5b54b1b763d631015a62a90eedaa2f7b536627c1610a8ebc83a99ef7e7979700b81f78282fc9a76267d01a167e7404603a895263f8549ef04d41fbb7c0f3c7f9a865c97773cb45240532adce1e825b590f09a1f48d9e310c8aa0555ac3eeebe15753b51dcf4d7de74e25b098c", "d1c92197d8ab5a614cc1041075894275283e43d7222f053da6ef49a7a4a947d9bea93191aace2508ba4e1c7d9cb0b81b5167940eefa582bcdf7e92cd55f4d414a58012c8b47e23122167237d6ec1e20fa4f57d2e3181880bd3d7d17caed3940470b75af0e2c84ba306e3f150629aa2e08064b700f776ea224fc1148999b4086c764c1418bb9a03b6e41c5fbf0cb75785a505674ab8eaeab5a476cf127e541f7e794eda389f6bb4448b89ec0a2d6cd323e25be00ea53538193393b9b6374873fccd75ee4617368238bda96e03e0e6e13926c86a46fe44ee870efdf1bb0a056c0cd54ad5754ae8c2c3b792e05737fb73428f965e8ee9302fb01d8b0f6200c8e117bd9b518fdd3263780335943ecd9f150c68338fd6ececf4dd9b1ebb2e04cf96c58d6414dd239ada936b3070dce9cfab9edba561", "-fa807c2764755320d3d2461c2ce68a2a77c98ba8178ae48c313fd67c92868797686d69e99e3b74e3f7075c1c6a40b333b1f1828045cb3fdaf0123d8eaabb79786ee05238db49ed352788f25d31c755b35eb657391f89f24bb5ebcb5baa80866c0893f8904ce95984ef41bdc3f7a2fafdb527503380a63e2bcac272862b270ef95c7be5293db08b4bbdb053e68b67effa333b1808344858fa9a5fad5b3815a1189e30eb9b8bb787bc7e714cd3448a75c3d1dbf4242979810a879423f16f0e1b1fa2cc96b43a8347be1663ac31ec", .Okay}, + {.Div, "-fded79218c5c2f290e45addab1b8db44d8accf9485c27205af520523eb24a448f804e896548a1bc496680bf4c61678ccb04f00285fa3b5b3437ec88ed7a18fe00e6d37a66976559704ca0dac732b3ed659fecae1cfe5aef6e305c78abd442e2d20fd21277b88d64b36fd78f44464ca1bd5fc8479b4ef9b5c409dafb5857ab12ae3ec130a74ba2de1f5d7e7d745201445164e01d4d1d751b7813e065f598a7454026977940bdce12d65147e9eae53a21747e3076d43ac0558f094bed590f4d85d8fe0a98d85112d867ecf67e791092f1467d32c8fcd4a447a02a83eaff39a4b399daf0fe04a291b06a20c5d640386adde4dbeabdbed35a4bc4d7c8165b98ecdcc3134d75709544aad97625af343f14f747d32b71f36f71bc0a119e27028deb7d198918f502edf28b6a06a0fea7e005de397dda3305b1e9f3c8d10013541e453cc219d09eced358177bbb9d309de8098bc113e4ce56e1968a874d6927d8678b5b0606dff0078436a026930c81ff25ecd0c8426e257150b8fb1623abd8a4fcd642bb7a91904df23df8cda0adc4d8695f25b04ccac4e509db8ebbda07859576c77c09b7b7ad938dd547d1d5922e887cb455851602882bf9872c3fe2aa556b143f76c1f63faa0e2a1584ed3b07c7c9ef0f4ab002e84b6bf6d1c5604d67bf53fdd01d13ac0b416f4ca6443bb80d1648ad764353dd955d6d7308d3a97d93e5bd58721cb", "-12e8cb938fab1aedc8c0aaa51d005a2fb27e233135463b2f3f1d414faf8dff94d76a3713ee6d3f73e2c96c29160760014de530ffd66f9a7de4507eca02f130b0d86349cc253ef63806d8aeb1782e5ed7789040d64238cb6fdb1d7ab5cbbbf7d6d716eb5808b0f4838a0e273a1e38ba09dfae0c9293cb5e0911d4f0abf11d86ec65081be08c359335daa79045724bf4ef2350942e1f90e25e9450d8d388f207d6742b375717ed2627c3562fb0d5802a87bf3a39f64bcb383b8cf11fd1e1ca81e0c82851e7a11eb0497ccb0c9f9d0aef0728ef1791673e5364e7a7d88f21020454ddfff28e7c6075a43e1ecd70ba02298b002538562ec188ae3cdefc8c9e5fb0ebaabc09c784ea9e3ca6b896e5678a81d981c51b0f103cc9657eb0d38bb984d2a3ecda8de6bdb63ed3231a78cc4978b81738ebdde", "d6dbdbec244626795fded046b7927ef126a71821032ec8a950a2f9768f8c23a4e4055143630834ff505a5659ce8a04783084c06c4d922fad35d37f0de50ecce2556be44a3dd0afee291b0cd02a0d4afd1fe0469f89aa59b189b4ca63bbd0730a75ad9c6cb10c14b815ce91f28da69c6e122758985310bd50bff4af522d2976046c8fd2846748cbbadf879ba41ee6aa3f8576e195b1780ac28ed2dbc899628ceffef37b1f044d360278da7275b3ab91972c2c8bf58bad8894915ec46a2e94ed3a1b53bb306408580d8347f55d3b", .Okay}, + {.Div, "991369b8f00505b416477c102a92815a7064df65932b02611477ad3d5d2c823150b04d2cb5e7f72384e0310621b637e869fa6b61698fb031b43ed4e59bfd093dae1414cfd3004761e3bb16339716d67388728e3beaadf15a8a8ff5e536035a450cba3e1bc627e2f2064023a9c7c7b81c9b7f0f1ce47881a23ea6eb408b79381dd4260052fbd309d31c409607b2cd9438c1c0202d73b926dcf225a9b25799e834fe83b70f11e110c993650534557d49140aeb5c6c45e0b768a0e2dd1d9be39acce7e1557d19d43a589c28f81329f2198f1b8e05e72bd124621022e881fb3cb57083726f8f70e4cf56d7b63c42e673fe32c16614345ad6888bb60beb17adba718e770da42ad1af8c2534e8e66faaf48f73b8b1b7a14746e9fcfcc409607b501cac6e5afbc055134e3f4a27e870f418051229f8a8a388a087d060910d515b4d8905f0e80a858bc97268acf83f665861305dd5dde366fe30892bdf58806ca92373528001eeb04caa65ffcb7c2884da2d4a84d85faf34f2f3f6afa48f53ed65832042a7122520ff5aab7e561138538419f98bae99affe584304df4988f2811b2fae6e24941d3899f9801c7fb8843b3c56e39b380927e51871c6369ee92721fce8fb1428588389ed7ba86df6348533dd8aa31b9928647a5a4899bcbfe6af85e24d0c761d84e646716c663b433766a5ef75780be97b7921912d163e7c56846ba1930dc", "35f31a347907b0b13a92251c300d1ab4977e2c1f7a58274399ab31ca8f70af09bedfce972ce29b4f1fb0e4ecfe9ef7bd2b6c3196489c214d1be9ecef3e40b903296e0fd495bc8510896e741db83b17ed80c4dd5e591778c2bab5817592f9dabcc463666bcdba16399b9a5faae12511f18fd294590e47a0723c261399c9bf76e4aa9a6419e922305abaeff1e61dace7cd40300d8b65d0555209621a2d253ab187ed32221fa379b1adee41ec0d144710e4eedc83bd4e34438ef5384dea5eaa76dc837b44457f201ebd6a706057c1667b6b1222ebabc1654ab8157c6cfdda6b2c261924a3475d6ea14c3ed6cf011bdaf3b8e02983580c6214efc38b803414230cd5e7c0d44f1e4c09b69fe949a1d7d99b09512e9e8e42f0c2ac6240733c6e65c0754df29fc52ef3402a986aa1a78df2a5095e5a1e", "2d65edaf4530623aec2a468cc7f4c4c79d7a512dcd9e10fe926b12c8091bf44b4080a1b7ff80e83874d0e740fe44c7d0a72d5b8a1150f5d9dd6261a00e9c0eb636eec68ccb11b6ef28589da03df544ffb6247f44999120ff45477e85cc354b6a062ad5d326269c23411ac26fcd578cad5f392e7cdf8dc2311aa1ddc4b7df31a44ffbceb02ff1f92eb05c445297644ef630d6bc816bd133770bc3e3abb84420a0996b08df0f0729a386e395f65b5c9805a4028decc1d753af646aa217346c89279ebbd2023609b4cc4a40a6f904", .Okay}, + {.Div, "-8179edf73abdfefd8b17af9e2eb025574183fa5de8d0adc45da117268f2cbac692710d790f4745af6e940ddc9da670c4ddaa814939f3532fe58c699d8b3fd9d7ab34c9f399b9602d59126d0a913945e070df38254c9f5e560a942249a0fc62bbb319764b46509efa76a51c53a7abd3ab93e48434b679603a5840726ddc0e5926d990d31ef398b699884efafdf39c4292e733247ea53e95cc2d6b8519b80522e7bac2bdaa445ff2bfee763a8ec83868d9c1dd14f571aeada58e4e76097817e0f43195ec4e5de91d2e67e71990741852d2ff170ff19ca14e12385bd1b5687d8b107c5f7a5691969bb82759473fea0cbf2f415037438f1e3ad9349fc047b6f0f2736d8aa2355d0502d38cab9ced3f4406563bacba218b72bb33652d9e5b8f3da0893d1e4676652db53c8443e25f3959337a81f30e01e37fc9dca5a36c770a9baa5ef633a6ca42b80c580300be679956bb5af43e85906a7aec1f2d2820c6b0260336f66b73030d5cc07d4c47b3e30c27c7b0a2a4dcfc7b7470fa152898233dac7bc7623684bcad0d422af0b58f225f041d3aab26905808eb397f4b70ac74ff464715c7f9c03101a0aa23a7ace5033c823d30b3cf0999025ef6d1dfb3e8fa33c95c81214bd8af7b37dbf5fb3399ca6adafe5e6e6c425d69c79e2ece0cf1f5c29de1f84c5e0e07822e67717036d557e2547e743366b8faed8c44ab0686a625baddad01", "19d4d0c950bc28843593038ab2d00a8daf4b5b76bdb1a5baf7ff01779718a9d6c7dc7bb6b8f16905f73c27f134320a501abf03e504ff8579e7ec287c12ae915ebc9cf65e215aed208013f5df63508138d6b6549fb355bd55ce68d9e08280adbf9b45bb87a2f02af7c68db0c22a3ff03f192aa2dac04e267c1ffac35b0abd95de82462d1399038e0b3264ff679dd554ff277f49a846d6ac62a6d3bb4a4f1be590a081c41912e37790d3728e26b6e41d0810ea56b21d151ee676dcd2cc044b1322819203cce65b2f281307955f5fd6576ead943a69852358a2fd737dc7bc2364eb10c60a103e4fe48ebf63604d745f08a159335e29efccad9a88e80bbdd90fca16b1ed77e9730d81a0ca04d0e0d9b862790204d74d213db106b454b38092e5c7f9113341b6703528f5b2f993064e4fc05e5ffc86a", "-5032b2ff945280b9512a601097e124b7cc53f252d0f46d5faee8a16135cc4b2a45a646b478274dc3791f9cf60af8bcbfaad2af5bd5ba0df5e3c629f4676a4dd9025e9a690ec5a6a1a3aa32594b7f65f8ad259413f76d90dbcdea51e695d443466f00fe6c7b6d830a45ec29eca88b37d69012ef7eb65c4a0d1e8a95ee3cd5ccc9d730e3fd08b41d947131c9de0a02f0ff73a5977b6e0430ffab7888f317ba2af94e5696171f3d813d50beb0eadad767198150716685e5079825c602fa85eb1a5aef048920f8c5fc461be622d964", .Okay}, + {.Div, "71b883ca90800a1d9c24d5b50c7c1eab4ed159e9362a7a4f893c4230219503356d8c4beb5d23907100b58e8cc524c82f627f44d47ba65de9bc3e79def5a6c67b94a31b4c85d30301ecd9085006574839f54f62e41795675ad4d67ca962b7bee7ca5244b7dadf7f5a730952d34edc4cc5d865e61f0741274d75fba5d62d4a945ee468bab2ebfd8ac93d940708266cb717e516ab022a262900f4d554480c3adc3e9898332acc273794442048878b854607b1d9bdaf03c24d25bd534bf5f4456091aaa32a5aac15a47c2895280603da144c28d9dae7d53f0272f69c19d1309a2f31287d6f48c261e46810c6c8573494fed5a198f6ff880dbb1fd102b7c5963abb5ac7085986fae973bd95c52e36455f16b1e1fe520426ef3b7e423c670a648bf4e9f81d5ca5ea4c921f9c7553daacc498d31cdc82aaca92f5f6f3abc3e1ce254341398569c29ced41ecf8e4a2679b7e0303bb3a9b4359368457362c68becdf87caaacaab8b7238b9369c2389ab77e4b7bff13e251070b6092d4c2f3f6dd60bf1d6cc20b98465688b8bc5cfbb6fb236338a664a73aa3cb7f3bfea3824302a828ea3907efa292d0681d2b807bf86b51b3efdb655194155bc577687d805f6f38d7fc08ccc98be55f6b5ccd5fc2f8767371f2558316626267b792f25e47c6810608d4da2ddd58a659289cbb9d21127d317180e9c08134985a891dc09eeff6aea0abd56f", "-1ef626bc60f317e06e2814f839108a7a94db4dfe16402542299c8d57dc9a4227a4515770f45bf89b1f50858c5ec2889f842cd36b1606e1dde80c8365af6ef358b5bfca919417d411cee81494474e1b5e02367c57c0b4441a0852b37b285417a0d88877f3cefc1f75718820bde2087bd42d5adbece86043cf2c42aa88793df14d8ec5910c98de11d2f0feccc4c8435561b2facf0d3398d1c45df447ea135aa939017c7be084f987fd7e4fcd28405f822b15634d486cffecf343f3db6be953f86578af201df5aa92f8e50c82fd7b6de32699a670500c7ac6f7899f2f044f4305875b00596a75ce6e1b3f53a9ffbf00a2d5d7a51cf413ccbaed4d654367de8fd697d5cdc6eb738a4fa03f066f8ed00aba3bec6eb5c11ec7b0c9ce3feb40a20dfb39a38e5696eaab1128afdcea8b5b2a83839b0a7d6", "-3ac47c090bc26e23f5158a7d2640e6a66e4c3239acf9ff5ae22b456445ac41a8e42ffbb2ddd55a22f82eb9277724ef3fd54941ec8e5cf4a6277a1da20b522a565c2549c1682c36572da0230d0272062f95782697734d80e1d2829c1530c30a07849b21143eba07fa1720237d812095ba87883e91639c3a917ecbf41bed662338bba9686a25c7a50b1ce3e1a5848512073176ddb68a2dbb560afe4bddd772218dc5475b6774e44128659defd5193f4ad8d61445cdb78b2b991c3721f51945bf9bca770c61bbfd3019b056774b93", .Okay}, + {.Div, "-514a0727aff4101f599e0103daec994cab8810346158cd90f3f9dfc27b80c059d0c5d8f649edb108a2d14b2fc158fbc02694f5ec61cbac15b73592e234e55c38adc9ae673e86e8f97b0bb471fb24567b5760413693881dd47842dee754d1872f0b4948f92844003b2de26165970977e4b67bb10a0610dcd6da59a100d3aa25629d20fae42d99c814c0798d524ff2862137e39295e75ca3c623037711afa9c651df0b81c33e1fe31b01530d32cc71763ae6268ec1be5fdec11f2ee3ac2cb53a77195c80eabc780c365ea93ba2e9228c9ba86362ca84bafe78808baa986124ce203ac9a2def1470c701564a6d080e6420c1b6030b0382824c1cd7e921003ef5b124853df32ec53d099602c94ceaa6b9864c82464ebc9326b323b69191ac8a2be7c556d4f0c1879f02051f28eb9f956b2389e1f67631cd70bea14c57cf4fc219032ac7e47dad7b483a451fea60e8d46fc4e7505bf1b2e563d55d3052a9bdd6e656ab82cbc23dcf9450a162843bf2cc2d78ed2406fab34dfddd462ad741e62c0c809abbe584cf8bec0c99be16da8a1d79a5986acf7e2ba2ad4da624201bb72911fb2fd5055c976eb752270b99c02a73b8a7d7105df93fe7bcd106f8d8225ada1f9dc1e97a04d5ab455c798a412bc374d7d1b8b5ad7b709fd61e16a77634b2faecfcde8b06a1abe1c32292416fd6e13c496c7b19ce6a810ae1da198df27af6ce94617", "-18d00dcb337b61dc2d50832a8804062413658fbb7b205dd8e649d25701502ccb6c7937ae351db72fc50ffcac160ceab056cbe7c457698265d1e5b6918b17ec443ba38526bed30465963bd8076043cb37c2cebf012afc1c965a81e25102fb7f834205965fcdc63fe14e7d976bea837e3734e7e716460b3072e5866f4207ef7ca56b5ef752faf475e29f5ba48fdd7042e36df44677d386426597285c5a6ec20ffb55b737ea7e90b7db391ace966fddc632e88b565b98ef4aa98fdd8f98a5a322cbde7ff8ed2a14bb7b036efb152e3fcc965d5a2d49850134f3539ab7aa5af3ca08be4a86ec6bdc54ce286110d89b87b7ee4433349cc4e69f138b62b2e5065eeee4cf1713f7e47b7122fb6110e0f01d43ebfb74ba593b70389f10aa28de86d9386877336dee6903e5e15d865805167a90db8a994b2", "346af26f9c52c64e641daebf6b2e5b420a885608c229441b60a6399333ae9e886514902716117c0323b82d24a322899b3a26cfdc17c128bbf5f87a20dccf2df1d366daafb8065c7af0ceaf1d4f06b979abc94286867c0d6e62be24bb0863a6d121806abc1fbf174b109a2443aabbac5cf4259d95c2db1c6fd6a67b1fac48117c28594c7c6bd7f433a39706bd5254b94eed83a8954cd463a160c770612926c518d0622a0de970b6f98bb8a9dcdf7970d27f630bd82da823255c7a4a3b61199d04ab3eb1a2b9b7e57d52112913cb", .Okay}, + {.Div, "fa0890260bfeb126cf891f3fdc1c5cb45ee2cd10dd6659ab1b95ee3edeef69764eaa55ef2b29bea235ba5d472bc7ac28534b5b9b562d45aa86494e8a20c2aa48dab2398c12c1deb7cae63ec9112b67366cdcd79356b42f03fff0870d1e61fadf711c39850f1080a14c96d9bde53fc43b6fdef81133cb076ffe2eefdaeff4d497d4cba61528f87681d23d00366a7b474adb090b7c1e35ea581010cb89bf0ed2aa859feb01911426ffcfdb254c2349e26a9daadb8f9fa8c127501251ff86415550b6f584b090d9def42e343100237ebc3471bfa594e6770ecee1e0c88e449bfe17e740620d4b3c4145d98bd69a9a174015f9a11fa2fbac0586efbba3f91b8c7cd6626021b2db253da4d36eb8fde15abc89b3e8ea2b573bcb3cb63c1181e48871ae60f2dbb68f5060a6feaa4bd7d206717e6c299c8d6119f50ebe9474a31f0da0254779018d8131a6fd956c98122d0ff77e4fcf056c7547e7a0bef76dadf20da6aba7d7d157f62efae91f1b0a9cc1823600ab964ef975463371ca603f807c0bb909db4f3400eb76812207f55467126fb6f72897df3acbeda9336a57d0de25d96133b80f3f68ec0eb0c527865b8a83da49fa16eb7b6171623ea16a4019e997b21da26dfe3baf4f83f22e1a4fb7f6f8ff89669adc198a87dc0a4be99279a3668eef6acf5c470038697a35474ba94ecda1a51ea17c31bd5371459d25e515b9f16f1cae", "-1e5893eaedd07b52c6e79f15c782ab3074ea976d414185b9a506c3cb538cdab025dbd1e04c1a014634d4e65413f4455249a30e7548bf7e4052ebd509ebc400253c53527906b97b91859a74a1e4971c0ef9ecb849a2baa0eeb54fa5e417e4e30bc00dfde22a18151960fd6755d3d5f912b45def07f26b93342376f4c5685fdfd28b3a3c540c1f65a13529ca364553cc8b701725d621549bcbb1e0f53751acec3f2d9bca0f1006e2b28d3f0c81bedb3a34da4ffd09fdf259c402d9535b5531dfd155001f982b1cc41c0ed8946429b48a2c62a740e901957e9bb97e88a55e8f1efe4f5a689081ed8eb787ad2e3e9853c47c3295456d64d0df6f52a03a83346c01049f727fd7b2b96a4fabacefe65c6ac99d6b67aebae9107aea9f036884f990ec6e4d75bcdb6b2e1018de2f17968c48dae4a4bb8df", "-83d4a869c2e688cf847be6cbc564aedd34b0de327f7eb012ad63ea343bb4adf9801820e33b29bfc3ca8e0b3157fef1e3e1ef939c18a3f91bfb4e8a3e219a1a910152317f026c30f8f47c4d86a3bc1935abfe4533deeb55b687afefbaa80a2544032566178d77942a0d6cf5a98ecf946eb88711a30858228a9cfefc19a3f067900eb9a9bbc9a238ca00dff3c68af1603506668bb806f7719ddf038b36500bc6eb0c581d1e663eea877131dd5a14ad13e17bb71eb9ee15a85f47eb9ec3cf6b8d46e2f5d397c5f849cc5d1eeec4c2", .Okay}, + {.Div, "482aa0b501b51baf11b68797a234b32c27fe36025806aeae194203bd88264a078c5bb0e0e10cd87f2310fc9c2f0de4eafb4ca42774d9ddc71992964cfd2642d5a7fb8004559522b30146a60940599c5dd4a74a7d134935560d5a3a6ad558fb791a23598a4395ee2ddef7b2b17f51c5487ed19bf0d267f953a413d566daaff73a6bc91f5f15655e919e082ae019a771fbb3890504410f5feca2f3f9d0e62eb66c87d584af507bf6f3477516db7e49ba4d19777ced69e26fba3710c9911cec092671899337a963a05e06bb8310f79b67ca71c3411a62d4f449be1f0797fa65142c94a552af85eca4da5f31f35ebee6c080fec35be09f8b6070decd583774be75a26d2665166498e42bc29a36514961ad2efacbf6f3da7be69d4d2746c6b2d60856dc5dd6619a875f14796a6820d553d3ce23aaf190d6bc1e3d2cbe3c7b5e176305b4678fbbab7bbac1947913ff891611a10329c572dce1cb5218b471b0fe5a6cec7024fdfd6e7005b956b232a5445dd6f34457fd5df035e3b6a2ed781d77c0bb98509e17d70af39c2b2e1cea902d1b574c36081799a6c4ca7294651fec2e06d7a151e59d5d74c34f115a07d5211a1f5c72b15fda709363183a159471f344288e687fe936c626fd735d878f3a33c34a009add194fb6ec148929335f76bb5d32ffcf9b8b0b1f06c3d874d2792cd744f638816615ae7eaa14fb17e6fd39a655e9b448", "-12ab264a3270a6d56b520b6ccb1ec4b794069ea7f5f4a3803e94a3bf2029de0800f44a4ad52d7d285b14254a2c12c02142566e41eebe0aec8299bb020386c02243c1d8880577ad60e1586e3e0aa410e434f76a65ce30c6f53e5a9a2b7b37e2f787f0f6af55da1f7c33ab72e0338f5631abf103cb2aad82ab8bb5ea7857d91f7844b1876138e964d4164b652a10b28150706e2c3a337523fb66beab7fdb6590c1fe2d2ca43d59828119d1b58483a8ded0cc2a525902ca8df4326ec744306c9b2391525036128133be3f0db7003d22fc7c6786e1b80486a102e9de63eb8d3c3fc34badd746b4f3e67fd857c3606e9e3499d3fcbb69671be8690e5aaefaaf6379bbb499af6b899419996ee8a087d9bdd9cb7d0257d4d21093bf598f3743ed89b84a8c603ccb7501a98285990532ee8aaab1e3ba2db", "-3dd9cb8f70d62c2cfb3512488385275e5bf456a225a79314d24c1fec613fdae070b5c78e77140dfec625854ee618caf13c83f543b386d6ff1acf7331457ebfbff143b9b2397418102fe9ce600cba4efcf7d38bf8f0d0ae4d2e7423b051ddfcfe51df440f2983682227398fb3bf973c44f8ac59bdad7f85d15d84630721e794fabd06da50b8967b454b14b927bf032f6f145c4b105c794e37e28489f31b7e889c9251676b6cb7db987bfd7a0268cd244a645ffd620e56aab4575732b0ceb7a42a3f20afe2826730ff3e4f4b92e4", .Okay}, + {.Div, "7bebd0c1c2556408694e80a72f1561c8c5fd4d6e1ca153028f0321e4911643e39de9703ce89ee1066404e3e97d94d84f5e968dbf84742c2826cfa35c57a242c60a5f0f603cb1193488e647300d2130d974b71faca98de9bca1a78882062463658baa807e0f815926842712ae65bc486c9d1abc805f477e079c417e8aa5c12f9da7124ad2c91b2e8693293399d649e5114f75f0e1e1606db838a8f4565255b74ef0278ec20c4d48fbbe61ddf572fb96d30c51636da1034b758774154f0e0c2c68912d81c0e709a233b1375ef23c2589b37b6f5e8ffb5b66eb96d4b875de68859b1d861309524602f699d31fa46c09d5635358a860566c2579e62ab48597dd80046086b6a1be42e4096c2ef0195a2b4bd6ee481f40023380fd1c59d8d52a3305be7c8f2cdf5c1189cf134d5c3af8be62ec90035bc8f3aacfe04c6148815b61a27e9900f3cbaccb5ebd8d553c06af732dd6105c27629b1ec583a039ad3ff3e0259fcc285d241adfb67ed3dd690d40ce389f89aa5f9391774e4972a40d8b5b9daf6a5a26c768ee69c4070ba9c42c282bda22e6a1c8094469eecef1623c5522cffad985f1e2c375f6431d6e164405e632fb7fc190f280207935c8267dc062a8ace3aeb9db59ecef0ebe2c855ab56e26c56a1fc1e975d6a278fa41557fea317719a7e82068264f3151ca7d3491d6659d26a493db97f640c6b0202a84e1893f77d5c261", "49193f10902972195cf90d0d18a3bb21c9cedd8faa8f639b0b6223d550c5fdb20673d941306def33f7ad46c13497745e775c26da8a101ed212833c449b3f56766eaa2361a0fc0101187de5e8318daa824d3d347fd594a1d394291af9c816ef8a3573729d4e439b1446b6504f7faa1636c5a66b99746f289069cd65a57dc9585115a16e80ac1293bee290e0dcff6ccec60090e6b679b48bffd70a780b1204beaf6ed58372a1abaab6cfd2acfd9971547a065a3f26cbc47986f334927bd214f72b8b708695b301e97841c8fa2604ed928b039d04f0aba0b88e6a8797c976622b70f23959f9a612e71327d62ddb66c4f9a2fb028a3d8afcf2918b266eee4be6e00281c30ea582b793132101eaa5f81aaabe175cab10c0ea095ee851da5e1c048801dbc2e1c6c7a2807d1116053c7eb2d79525cddb", "1b1fc8cea253821bab5a8f1daa201742e33f95d6613793c9ae8004a2a79a5f41a0bb0f2620effc22c45b46edeb4f9ab7c4ee9f149aa5d43f722e37bf7a56fcf4f4732ed41852dbfacc5f303b1ffc294abb3fcac501d07fb959d772af970f87cdcbae95bdcbc36e491b1cbec3904d9b9e074b637fbda049e71678ae9794c6deefcd7b76d3c309ce06ed499e4f418d4024b5796d99e038fa4f58608286767ade99f38591041fddb1adcb3e77ad60eae28ad2c14da6fcf12371efdc97d3b3544c8baabbcb0fe502f705adb49491af2", .Okay}, + {.Div, "-9d81324d600b6940394283306ba72cdbb0f15210f1d28a788381539b12f86939d01f0fa30602bacb15e6b35b93a05eecb92ce5b1c26c985169ce2f5d0cbc57f9fac2e8afb4244857f6001c463ea28d6261bd0729a9317136ed2b23944c38413bff32ab9667f68c28563ee3fbd52ac51327dfb7265dccced6aca131db1f968b387b15eeecbe6d9c166576b2b67d97e739f9317e4c7a5a531c29b2e98de2bcdd5b8abd3b20fa965b8a26378b21969936901d22d2e13f9f71aea5780dcd3dac616abe6a42d7fcf1e4fa749836989e42113dcf549f0cc44ad6ab127b04e2708e8f295e9350e9329dabadde1efdecd42bab34b378e6c65af07892a0d950cb9547093c4b1b9e140bd6a704cabb6e90a9d05590c1a37119d7117d6bedb231bdfcd991af0a1bdd143665a82ad607ae86c170447eef6c3bdd817ce648fa72c802dcdb465fbf67742e3925ed30cbee074f47556a372c9d3c7de4ea029888aff40db3cb76fc1c0b7819218a55dd5ab56265ef98fec108c1f95bd277d65258440e3db3ec0ad0ba33550c9426aba363ad7cb00d578b53cd963f284cb416d6adda18ad5bca47c0c6fb9c807ef41b8f3e88d93615ff43cfba6f71ae405ee7affbebff00f64760b4fe14468dba715fa7288a3e90f837e6a648f0a204f384c4da028eaeaa34abc799be663958fc66b940e6dfb21c03734ba669b624d24a4c98fb8076d938c34b37e0", "-1c74893ac6fee237d3733b520071137f7407440265f912c8285abc1bb4c76334a664dea2cb1a9e26a2cdb3547b316d4fecc9084c389717f60a4e43c5a18c23f88c0b9d607416d7170099d364d9063d61f07b0e303f7c0028d11a20cf22f7f6de8c169cee7cfed7d671b7b4f4cb2793c24fbd7a2d2df91c9b74722605054840864e8a21919230e26a2eaf5ae486882c332956ce15e24538a21ec03155777fb74dad59f4c7f41349924e2330552d28c1ab7bc2dd04002f16819e8d4a0040d0465996ff12762b5b85bded3755305a2e929f0fb4419516eccc0bec30862dd140acf89f2c9c8c5dab9956ee2ab2cd1900d95afc4257c14652d9bb0163cf8685f54fe6934cc8342fb3000cab54a4c346ea83fcea03d62b07a5a32db288999957506071350c17f93fbd8a553c4769a754b9e4ab0bac3e9", "589015c4d86b7a8e5c7a37d87ec8873630a76170b213d74782d7d9e67abd713d77460e954393451b9a673fb2a786ca92468aeda0fd8c67513d3e892b68ac995ed771d3a3606353bdec5bb8cf3ca966a7ebdbf2e8945ac9c0c962f695f5db76236d6506baa0b6a13af8c8ad0c6bb2a4ee052016cb1a73e21296f26ccdecb6e581e0c99ffa593f8efb02016e607503f40c30133e4aa31f5cfe2283226fea7fe8db1c61fb834eaaa112f7fc392576ead4ecf49ec36959b936226f0f610a9220c1d93fe4c186d27c87cb71b0e30995", .Okay}, + {.Div, "-e31b5cdfa9fb3c0314c969eab62ee4967f5e0c1bde79984667c2ff48c8e0418364363d39346ff2b12f5bc30d957ec53377650ff8d14b5208dab95473f48df7bb93e82db42af0de8e1e3da1b314f16aba026a65c9092f65dbcbe7861a30d5bdb79540aade9076917d375aa9ba63db3efefbbf1ab0a58689cfb63fc94aa3236df6e7e4a738bc996b0e04d0ce54498f40c9764cfa19189eaed070bfcd49f54a71e5dfec4b4bed140dbfaa1b2069d01b817be1963fdd1ecc03c3b3746002f524852c4429fd1d25d22d678abd5ddd49835909e7e1500b5dd43ea909de3ccebeed6c439f4e73035b5924b0bb38e5505db84cf052729a19111fca3c9e9b4c4eb4ce46eb14149d7f6466771569bb5007e8c2a388285eaf92bde4de04c343c13d75c5ce80be5f32969eb6f98434d59b484561ecf6d8f1f3bedd9998cbe51ef24f7a2b9e0a04f7711a488a05863186234111234284c6e624d2604989ca1136d74a1b7a5db97f8855e443c17bda5246ae93b1c378c1641ed5f809f0b4f142b624e440f39c0c5f3f464072bc5b658e08ced5b52ccb5857a080e0382aa9274ffca9641928ed85d0deb85751b4f3a184fa46090575a4dd9688972d1640604bdaa65230204cf9c81c9ff5f6a4c26bfe1b438b57ae3e7c5dacf2b9d2edc7122e2684712e245563004d7b0838ce572974077bd07e4f0645dd70d86ab1e1ad76dddedbba4dc81cb427", "154bc72f8c573e6bd9ab295209c860d33f05a2ccb15ae0b2c9d40b4cb51ed8b94cfb44f7a9db20490ee5d7e14983fa63a28f08795619ec192a13cf9f177aa2fa8d9336f218bfb11a1cc840dd2450ff300a090e6d729d0ddc1b4d4a3f2a404036c163a44cddc71789754f5f004e72fe451d6178dc76dff763007c12b9a673bbf51aae8eca37e954881b5788007a288cc64055ae8baec86ae7d45dce1bf73a74e753fbe777709924e10100fb8fbf06417aec6ce2eca984f8548f1e8d56b80f16e71b2c83e2b4173c48cf5c152d1dc1aafea1d2ee5d5ef311b514afe1282eaa7bf4c276b0a0a1bec36888ea3ccb9c5f757df42f530c481241305acb95c43091a257d95a0dee9a0a43c57ab986b9be6efbbea48136a85971784a8d12f986434e79c9ff1bf6227cf0ee6a26f2a55ec8d9b35e61e5932", "-aaa0f27b905d80802cc63c6a771dbfac602a48b03bcd836730cdbf761a657f977c584447d243d4750e3228d07a137be9db71644fae4865dcf25e47059cc6b0b9f2049bce8d2b4e783fa8ceac66de5c738588cbd2fa19ab8310b6f0a787f824d7bf753e58f1d50c55fcacbd535aeeb15101600f698e5239ca789b243703931f135a69f7cf134ec7b5569295bddccda76cd39d60a5513e8f9fa1f238e6979d037719f3b3711fd9243ff8175e324e3170f5f71fcd658b681f939a78c39bb537800797f4041cb65fcd8e50bd865874", .Okay}, + {.Div, "705ca6986945e42c196c0d8602a0664bbf231c50edf83bb34441c2aef0d01c7e7864978bcc3c217ecd50255ab72c0f2bb8ba61b20f79281ac350d61e23af478ac7d3ca16f6d34ba84a9aa53e1d1ee56f6498e342983a1ac783338a8a5199c3849fda735900c1a88f6a8aef59752a66b986c1a706e9e0f1ac4c610519282eb0f5e3eccadce6a69ca7c1ea26f5673fdde810767ff1b69318a3596f37fccd0c000d6cce88947e20dd4e5ff8fb57b734ef5500ddee651145c0f1291e6b4dd8a98b302eb48847342ffc095748f37884534a5c4d97f22a3cabfdf89d2fb1b306c312e3f5f1f4c8a317cb9a4240bbce74dd004d7c208238b30e5829a4b10018c184dad87acc62886fcb9d92c81dfbb9a58f6e6b010b9a6b05c48da62c75426e06a0a38e3f529aa49ac695d0559ff9ca226f68dbbb2943b251724302528e454780ab9c8c856d0e3eba6104151bfc0c0c8ab6c27ca9d6ebb2a86c96c82e761359ebd75293eef89d25d5d26b4f8b0e1f9d0c9caff9929632cde1e3669a70d867a1cb96d9df09d6572bca3253c8c7c7c53f9dcc8935a3d952ffa4e34d23ea47fd76b2952be18af231883c46dcac7bb16971379c613bcd1a03c84c17fd3dd3ff080efbb982276eac6f14f387ca6fe0eea539557fdefff5edee38c0d3f94f13ba0c9025612144fef53a15c876d9c83d32e04952e89e8558c2aa7e72f50b2ed367faf160acb6ef", "-5008a2a5da46560438450670b053756116dbb47a6a6a8f0c1b1dd5487cc7b51ad4f2d813fdc3a212029c773409dd983f10f9974ae2e83401f83876d7fdd9b730fb69a907dd48297a2cffd33e3e8f3a8ec0c01bb1a7221e67463019b3c58fd6240214cdc6b1730793799576bb766eae9e703996f3c0107c69ebaab93f88845d4cf2cf89c3ced805d882b6fa358106629064d7813590ce08dc770e2af19acbb14f53732eee04807f87d1bcd221950b025a1237c6d24550ffa01ba01e420028417cbc4edd5b29604dae1c310225110037e9b11098ef084a8a37fbc07996709702fe1917c31ea26f0d941a0192455151910af63ae702f5a25da2b69e02c9d92dcee158ff04f45a6abece3c99f95ae18ec03a5f41a095ab550edd3a821f0b4ed9c7cbd7c302db5b6dc4404268c44c948db53685234d", "-1676816633185a166b19f5f536a13997224958a4061c4c60b72f5ac66c6280b0296d35bdcb3a41c4bf04cc407d72d64b5b15de003e09f3f99f470e7fcfc49c374f31e2c5eea507ffb2d4831eea7dc17fa9b319ee04d911543157362971ae6a57f6a0d0aa453b58ad76eefdd4ebc6cad8c75d58f8d2bc1d36e61cff1c39fe01b8386a683fcfa5366ddd0e62b7b5613e335a44186d4d0daed0b94c180d25383b6b1451ae00428a5087a49fc57e271315b268e091c4a8df261775ea664617334ab9ac1975813aa0715421778072a4e", .Okay}, + {.Div, "-df798d7c9335da6cca30d2d2080597fe8d61dda2d40156895e2c33d475376c27ed95322f3bb57d772ce090780992a16cb83a779d11240826590da875c1cb74a9704c8a96cb20215b5ef183840cf9220e524ddabd744f262d6bc0fe218d76d3eb389d71f523f52bf875d43d848cb08fa852fcbdf3d54bd0f7e2e4ca681a12f08fd53a76851ac4073ac2027b09135d131a0c2e47bde5965316a076aec05b01a7c350164df22a88c9f66eab392678f2e389db5ab487cfd949ec36b159fcafb4da5eff0fd054a31ac32b6df733a8967bd9a57e75e4aba41b40c9a09b5f3a45adbc0335baec40e361490292d41926f7ae2f81dcbac6ff2a5cb9547650c6a36ec1145c3eab9b61ccde7f0e8a7e8a6cbe03d4ddf829c66607c75b1e620e4ff7e0f302f46144cca858341f27bbb9c7ccd95aa7a83e332af0de4095c08003909b4269c965d45f438291bba019c85aca4276eefc542a76d3caefad11d266abb4e2fd125d69aaffb0807966dedb19090568a8299c1e148f5b1ee4717f8f6b992ad0a42aab929c9dcb80955e9bfaba5af09d02c7cf3cb34e8d70cd422c693f0a0851751995511ef7547dbbf5a690df1d51de95f6e49c2a973f51f1dd9aa161efe9c42c1776c85ab5c4d3417c4d643b3223d1520ad256b3dee80d61bd15ec660f0f8b4df136daeaec109429cfac0238c991102b6fad1241943e3802a149805b35e993849bb4b", "1d60465751709c9f072df4ff2f31aac78dc2aa611c6e56b6bb74ac4c5b246d35f9ce23eb7209413c348a5e63f0d77938184a79044c3111d2188c1d6de1f307b1460e3ad40a37c371f6cd358f915247125edc18c7e23b7f08e72d38539e360630548898d204888513ece28c6f7739fc5f6aad0c184848168411e73fe369e7e461c8004b4826b48e1abbee5c54c0afe9efc83563877a637c058234f76686201a4ea38362be74b9733afbc15a827ce8c5bbbcdfe1a1e62ea754c6966146dac644056d3fc4a5cabb9463a0fbdb34fa702be26d28eed89a38e92d6964dcf26387b212efb3d0ebbcbb3710d3d7641e80789a3c89054373678a350771bc7f911c363b414284897ce6e708879b1bd8ee378cdb8cea0568bb7c32b09db44b4bfff0cf0ed16933ab432c2a2249643bc33e8cf54a2d9916d32", "-79b7cf2eec450f9328af9a2c786a5fcb56beaafde1b0cd66c48c131e032bcfa7227b4489f6d1f17bbec52c94bcb508673f5d0ba29e981645d8fde608872a34674d9ab0813c633ea1ec6add54a65723207e677d9556262666446803e7150ade4de558d79e33b3cabf3fb2a5c6f715203e1ceb3fffcc252a419660f8e8e9c32da91ac98e63cfc59f1eeb0dedac99357466197e147a5e626ceed3e68ac4ca73e55d91adf7da6e173e06bddb562382191b5e15263a5824cf9faf41dd5bffa69ed9738e72426b6ac468ba27ea7fcac", .Okay}, + {.Div, "-4ceb4a4c5d5125f3216701a1a5ad158d829b4d66ad210ad07323ce291b112dbbebd7ba0b1a60b6eef4931190ac190d0c10c076cc87da9224a974fdc739609563fdf6c9c1b5218cb0eceb7aa9c3fc976368d744a59ec30bd9924918c197bffc21c56c3184bcc0235cb2d0cd0dfe7197fa6da9f2c9ba8b23b77fdc9b58dce9f74eb31879446f54a83234803c0b92b1969f4df72d66e05f5a651b885fcd96e230801b35833e3d072e184a6ff76eb9969a7a254e97a30b1bb7958339584d659fa5fe636e38da26dec75257b5206ea639a0fd7e607e16f7a30671c62d74dcc0a0e9967727e640438e2028b6c17a193b69ee5bc29033c1a32eb31681a3f4643cb732fd645b825b0ea54354347acbf26e8af47171cf8477361598939a1f382e729e185e0764269c194bdf6eff392be9ef9eb4a604a12f392172212f4725c0051273954e6551442bb78fa5381a27154b8a342c0e327ee22bda8de844b1f980b35a03853dd6a4ffc71946eaf4ba5bf3b6e2997404d163f0ef9d41896fb07e4ed7964e3c212873531e3a34f79726766a958bc1bc631f0681424a2208e40436f3f2801449928902f41507533dd72082ef0e8b29ee28f1509c70b36edd4e68ae6c4d536620cacd3467b07c1b80f39f6f11fb6f699088bcee0f96ad9566cdbbff9c3cb96b9ff2d40e140dc43a7dd1f5885b92b936fa04743654aa9fd9b1d3759f64616288ded4", "-11676f2acf7054c5d49e1127e8affd540200fd74d742ea122b1c49b61e907111142cb4a989254e41ee7ea18bd9dbb224066d557b2488d77fe773d4467dfde724d841ebc5160322826cfb9f3699c8d3d4afd168d18447727ed7b2270a60cd5820f630bfd43a49b577bcee763c51e27146c9ad66730f81ca29cb0f294dcbcabdc56c0b13a6a162c99190f248bd369ab5aae512ad3aabf59398ddb18b485ba4046fcd6868d6295a68aa5a93caf84f1ffceec915c39cc9425ccf2b1bc25b576853303d610e5c54c14cab0687764b9012a5b56b42f13d0b5be1627222721f51a6feb633e8c2f6b6a8ff5cc73ac806bc732d9af8cede83bf9d45d157bd6b987d765d8b3546228bba85fa9982ee8b4f222f2b231bc772fee1db5f286aac854ab8b4a8a8fc88ad87d5eadd23b4095a1cf9a6f793a8ae62e", "46b6baf853e4b02ffb63a06ff222f7356d4930b61a31b9ad07397f9a12eb55034d413eeae2276af12fb81199fb2c340feb05bd952d65542b4fb92599f99755f1d3e371e16f951607f27013ec2effaed56f895a20588682b5c9aaa3f5685221a630457e40f67886b4ff573ea30abb4c2ce5469752a6dd40995a9d6642711767736c4dfddcc0b141537d91860691b7a5c5cac767bdb7c4f44f53ceae57cd0a599c0be8d7156f5d97a2245ff61825d5903aca0cf19a6d5cdaa0f4368295201434c2d09839eef24679bb0e1b760d5d", .Okay}, + {.Div, "-7f27a88fbcd8cc015aea50627814ca15c249ad7602b8c35cef8d5c16c47a85eca876aaee9c3b280f2fa9c508e41e89e42216fc2c70dc1393f8a4c11dae85beb77537b4014a31c5fe53d456afc62c3a2a77f21c2c02c08d5f361525575dece7a929177fbdc9a529911da9405bb00a80e8d3949f73f45075edac97baf6b2e106f2fc84cc2d170e1cd3b3f45e5ac96de7926e98167ca37a3bb7fdb253faf865ba85d08b0738c2de4567696150c6e557b7e10e87f17f43cb531edc27ddf46525aec475061a8ad2268af43a9fdc7eb3416cf3c1add7542a1f65533cccf4432e7fde4fae0454e758d4b1d3662989f1799af11ef5dacf5537478f1a73bab5cacab45b4870938e91d09ea3252b19ef8e3beaa5c6ab4c5da3b309a8025a8bd143e9c5fea75421dc5aaf9c457d1657918264ba4f360cd1574cd1d118770bbc0ce96e679bb395478082b35d2893abf5f08e0a01181bf4457b2d4c4dc37568552e7596497b18e792f5c1f8cecad12f5cf32317b0a08034a36d49a677e37228b4bc9851df949436398ddf492b2827dd5136bfc0845b822476089c5ce529f7daedad1a0c09a06925e72221a83390ebda0a072e01bd57eed72443cbf4c311d37904671e64278703ed7179521d86fe4ce3e40c6da8a29618225dc83bf7ac4031e63e8ba5f168b6497caf1a551c598f42bb6a14d484bb5585c26a47736ae01eb1cce2e77bbf032600", "-76caeb97982f958bb98acd44ef8d6524b2b0b90c99ec6a23609d2802f2119a5939ff79ab8855d35782b7152d2ba0eb2c4c235a6014630a6aaf1930665374d824580f9a8592ce89616cd78af841b31aecd353174188575b7fd80bad4ec64e6c5bb24e7808896e053886c11a6a68aace2676ebc792de7d7180a988817812d314acf633ac5f5d03c0b9d29390c527911df39e3d37d6aad74fdc88450e16c2c6f86e3baa47c0f115289ec0b2a3fb84f2278920b8a4d60f9aaadae619e8247ddb29e363b929f6cf7885848de872df0f7e8d43911be6092a8318c82f42798afad9f7eb65908b4a299fda34afdc170cadeb32930de68f3a6c99bcde0d29c3c597f196a0c78e050ddc2a1e2ad5f226cf44e7dc84a42fea5ed31af6faaa97e8f5ca3f4db947139858b2a74da1d1cf849cd136e80f28f4cb", "1120552d740e60a38c3e28cd67a07b9255fd661f67fad1e9ae04e2dafbb682390289e23c6be22992bf7f0cb3497e33abd3cd5c7c008d719d71ac5ce0f6edfbac1a01458cdcc75269635fc2dd94fc43a2deed6671fa8370fb7a42057eb4a87f20a6abeff09ed62e5de463ad3a5c0240308c6138c8d21e897b7942e738ec111e8d35972f9059ddf00da0a36bbd2459e7c99353ff3c30cef29b0b5f22629583b1d9d24040b0bc279485bb4f34946b86fa810faf3253c412aaaa7b94618d8b847f521714656b8ea8d0cbb71f81652c7", .Okay}, + {.Div, "5acc544ac15cbddeb6e7203d54464c77449f214b92c7382aa3f0198f2ba869d96c8d97093c55fcd223d68ec8cf3d0bdcb36e74a542eb02a60dd3f75f813b76a038cdd65a141eb9817a821816cf31dca2a5b30a7c48aea43d213b0775234f03670e71a5bdf54d6bd6c314aab268001802e43cff3f860e9889c38f0f10fe6fa6a695475be9dd1f34a2b632f9ade9c3fada54754bf3911bbdbbb62ed565ff91330646875f4cbbe8a80b55e3c716aa817a7d5dd9e5a027c82e7a368bce9dc7cee350548007e4a39ab80843de9609ea18189072fc9809c7c3a4af851826340f00ae197051740b023a340d745ccccf10c06f081ab8033703e0e6473ae2d93f88062bf65be5b5e6df91771c5b30b554808626037458c5755aa03bc443204b0b62d31b61c177d1e39cc86934389f7c183927646d668d70559663d2cba50628ae700f0025581322a4bce18f72d53f769ccd085761adbb0a1a0419d1790b70972b5c3bddb5038e50bd8a8677ae9f0926702a0ed22dada890cff771a171a3af88f6b77223c02faca1b0f22fc7ca358c50fb0d34bbd1f992a67958b4514c2d883ee2cf7f5d821b6e0bf5e65fbcedf50883dbf362c2a333a4b4a1d83b03eeaa3834f31f9fe52e79033effb2d0b917bcd1b26d26d6465fb044bb640c74f270da40f2558d82a5bff49fd207bf2ef3325ad39e5b692c0f45901b4ea50d34dbd7c9f427bd55bf4d31", "10413e32410b19638b485ac943c4ba8b6960bb0e452977481eed67479fbb942e29a140a654e4d5e8ce45f434306185311fd95b37c5922be0511e27dc476dbce1b93d3a545df4bf9c34d97768d35bdeeda9c8727e068d6a36927ce56215402d69c06a3ca6914380adbd36e479292795f6b12323a7b7d63faa968324619cafe7339a6714e677b86dc16fa46fbf48dd2e6c13fc983d3a97bb229284ee2423933f90c1f9f1f1fb39b270e7d153296e6d6d35cfaf88ab2a19f523fd93b153043aec0c613a2c4f17817aa660415d7fc466c00354ef6034dd5671a4c70cd7172cdd8513d356c02c7d3a06392569ee44d25a809d8d870f1b47c87e23963a50ab74853387c122fc798d6284e03d3dc4fda55d14cff32ed22d39c329a3d8907631e604513b2ed41964c0ed05293e2e9a4242d558862a6ee04", "595fe352f870058e77b02ce019eb53088cbb63a77c76c3dccc4bd26dd53382bbd7ed2875af2ab293b3a5ce9159f4b4f26e7ae85e34ce55b01527eb71a00e809637bfa1255487599f6b39a6198ae12f3c9e75365a4cc97d036cddfa599f3a11cd1aee861cde49f7ddc3a5cfb3229dcd281c9dcc37dc5428e6f125e21772a7ebc0c1d1ddc657b05ae4c189e2aa9fac510a5b011661fbd7c87e74d1fe61ca9494a2ada4e996f5ee847471d2f7e095b8cf2f95011b33bcb83a9d1a33e221e91bfe8a75cecb335bb43f32f036135286", .Okay}, + {.Div, "-f89be345f34d5b9eb2d853d1d62e9cc7d536cd08bb52ffde0a829bea2a5d3ca08b3f18cc4ebbabe80713f970d6c3c45975af5328c17cd9d7c5aca1ae4e51f033920202553c68f1eaa6223f4d4cdd332277d661c2fc4e3bceadbc9ef0a2ba4445929a75ad3375274fcebcad8cbb8a45fdf03055948757003bf93ddaa556152a4440aa953d978745c739d511c12848fd0b7982886528f61e5f2f4ddcb9581f008c5173fd58e4428163409bf8a6bc66e777003eab8bc22c913db5c543c716ee0ba2aa205254aebf61a5a0832bf20638b673b187f9c4011d872ceb991b922ab6b8d56b61cdbda1fd31ee6389e0f985204ca2cc817a3a7e44d8e1ede481cbb15908861431dd5fa55560da9e0ff56929c81bb4b471384267dd9e95dadaf3c9abecbaefc878e642d3f3acc807922f9fb641f6518cc78c44f00ca125f06598897d7fb5a02f06f260c51b09252bd2bb61bff4c7761838d22b94e21c327262f49011aea9327819a8aa042819e7126a14b74706ca86345502a951659bd7025b746ceaa8a697b834043969f5b9eafad0e285de0411660c93ee2fc47961f6eccf6919e876926fa4e0bf5c584b92ab9f16e7e8b7d7f9e6407dea9a25ca6c706f961be7fea27d5575fe70d0e272b565ab62e4135c8114978cbae48d4dbca46c0faebdcec16bf35f37f18a3f756d947ccd0a6a4cdf7c8900a37768af5c4741e050e144ba5d40181d", "164a1a2522b1650ec15a20a7e442e0349be5f0d94b428b18bf855b8f20904e9006e4c3638630a3978502aec22f233c159301c4f5e80b63d1bd4bfb6a68fa45e49996301daa07a055a816c7d79ae0f30e007a7d9ba0d1b898e8fc822850d03d7e69d5780c365deba881921979a69518c40ad6fd0d3ca10bf11efb337b8f0a4e3628db3c1fbf37b04a423d67ba8f8738ec58edc09e7a42daab330cc0955492ecfdb45b891c858301ad225438eb3c72554569a7fe289509c4cb1acb6702a43006c2a0b7860eaca3eab222e1dd554c1de0fcb978b06d31d701e8fa4231bdb7734d6cbdb92ca571cd3345afa6557d4a6f47a8ea4239d836993f303d61ca74340ebead3272d344474fc3e54a1e9e89c0271e89e85521c73faea88c7f23edf3177642246cf79e3243007ac403b287adc8ad36cf1daa950", "-b2755db41cd6435f9994cf5d7ab083cc1b2e25e8a20fe95a8d76b80f43b8832ceaf440dc7bbbf10f819741f7dc6bea22d8d060202399e4412bc4a666e6433ae36abb6d480856d057cdefa60fbb21e611aef7246e6e9e2a20265046e0b4b51be39a141bca4af0d16108c00ba372493968e4a74b087bcfcb0ea896f825cf4ac36e6041b88eadb9c853146ee40b236c9b7301fab06bf3e8dc54a4029af1184c5e4ff923eef185cfa55a438a0e2b23a2b9711177124bc4b617a209201be2a8f5a03942c7ffd7d2f796959abe7d4358", .Okay}, + {.Div, "d5820aaf27f58d5e22f6979b03275dee513e15b884c57f0fb681b6ebe2fbe0fafb2713b5f84795285770158db7ca3fc7ce7150d87ebd2c05b84f01446a5ed668414f47e01f061dd78f6300825f9004bf7fe5af4818242e23e269894792fb531b19b359bf7f5b75e3f33435c4a12ae5a26755c3a4e6ec566f64e62501d19a746e8691e33741cdd73c7a7d899d6c8391c055137921fce9750aa15de5fda3d5889c183d0204e1dde4368c00e41c22f01d1a2cbedfc7f75f47406d773f8e036940adeb3526be63953a8f346d745e57b1f3d8ac65a6d315033d2957df1dd7e458658321f9957d01f162f0e3940e40e76b386a36a6514642f95675aae3969296557db5fc4a36ee10562c500554c7d58943c292d1001b31a48cf20c6fda676ddd69f5c0660744a68a234834573de3ce5298295a110ae5643e6475f141cfe3726bde9eb80d9d8f6bfbe7d395ed6a2662f73f68f2cbf232ff08164d0e8a0c37536288ed614a5e748b15a8afb4cb1323afbb3f49baffdc3adb04421fbce19501ad6682b9b4c69d16a21b8304e1eb6b04511c02dd6af4b1aac3fa90deb21f18eb6af57155fb9dc7565dc0cecc997ce3796b0e930b3be2522716991d1ffb84c3a4cd8d89ff8c4d6cf9bfe6102c3cf190bc9034e73c3286198b1aa40a0043181be49d0d408c20df1ba2d904adaa9558f86162b77818cc6f187c602ed6ad1738411b6997033099", "11fd9201fcfd4ed979e30a9d7cf414a9b094dc641f3dac9d3dbf16d9ef167f333216b2f5386745b936457a18405b6a6189817e29a311e0a49ef2c7473be3727f1142c3d830e0714676247c585f5ad6891bc5754496efe424a2e00ffd9c3c46523f3e232524577c66e7a5a1a4cbd6acbf5e6afb394ce78789b34fa8789fe86ff64c23636294552c551da5fdd7dfbfac9870b4331a9781a13139286bcbca53885a320b2b7f4957c29bc94e3e5f894fc26f1497299169b130d94af9ea0d796226c19fb32e55602550d0071b7096672f916b46ee2512460f2422d7d62a96047dd4647e83c34906693ce69cf25bfcf38638b131685408e9b948849a60243a57742b444ea28bcd740b0fef59070346585393d95cbac0dd5e7727cb96ea72c5f14ef2f62c58c22b9e2e6051860763f7298df7a9ddbe4d3", "bde28e8d4b9f20d41360d82049575934cc6a2959a52521a1f186c163793c8e9d673c95c7cfe6c9df948baa363f7dc9ba8c394a2d5fd0da92b51997ab2122c6220f57bc898990538d820510ce0da035ff3489ae8a417ab41d23f26d3dcaadb74bb8410de2623e0ab4755540524cabbcb8e2ed07745946073a740d98939f2a43c4f4724b6a59e34a35e8b19ea73cba5faffe04562bd859087d36b1b46f1e105aaaa0ed2e9a09172b738136cc4dbf0364dda9362f1f630ff2d8db64be544d21a03b90db942ea6ba770ac8e708c9d4", .Okay}, + {.Div, "-ab61d7bd239e8f1c6b2f0a9d9bb7d78eab279958181286d65ca487474c3dc90461bc5f5bfb75cd6b688650ad026ba40ef9196fe7ee505566ce3a784ef5994ea9bd712fe45d961f36717a8bf0a2891be972b01d859fa26528f7dd1387c721bb8bb3d85514487d120872a94a1c30ce9390e4840eb18d8be5add2f4afd3e0d519069a90b3d4efacede78efd414962f89ed5385905382d4e471dc50bcc97fe2a1fd334a7e9f0fc3c6f38e2c02b5e02cf22369e9c3df7ccaedc58989554c3ac2fda657e7d8653940db947bab594e3c19e40f10499cc4a2373182a83fe25bd11ab534e3bc20692af7a3cf4196c00508c7083630ce00b968e14021dcb138dc22270a6e750366cb5382da5b70a3cc68489e3ffdf681ed39f9e5b3a057fe368bd7d96a7cacad6ff1c2769c422263a98979748da64839b278492fb86849293f3ac11b366827874ec9710378f81ae543b6a4bfcdb33d9a26c11122dbee2a652002d3aea9a130357c678ea1e6610b8f37f3c3a909a217e70f6f288ab3e005f8447700e2589ab10f000fc2833510e019013cda026ce0fbc005eb18ca6bc7e4575f9e69aaa6f086a7696425ef92cf759193c4987629a0b8a9e4478d9c34f6470eacaee9341e3f60fdd13fe2a75f61c572b6046c92a4f65d9f11d0bb8fab81cc32c00e8ada004565fe81df92025f941be25c3a257410f6328e6dd7ade3810bd6cb1e820bcee4c95", "1328ea606dea0a3231090aa49a8733de6e633a07128143fcfe19b1fd739f44d298deee0fde914b36615b7b121e3e47b0521835415cb67424729adca6739c3142cbd23270197231ce5f7949cb1d526d41a0198bab80ca392f10bbc245885b7b9254dc7bc8e21adbe4b409f9cc396a54c423644fd12a0e6d9a12136af03aac3e4cbb1449c9e5ad11bfb4736ed85f917ad46a5ec4a480fc69e3cd2e173668da088128f44d078da247a74fab67decf27217b772d6eb90a5e58f3d9c63da7ee1764762e2d7b77c6b93d58c1c1bc447bc93d98885822ed7bba1a8665ffb6dfe95806e94dba1dbc7f9f23c932302487d5090ed677029349f40e8bfa8b995995018ca516129b5981de45973697fc3e0140dee422052ec7c91f6a0f9034239492780788c9f753a946f585bb950ae797191aea80e62589b36", "-8f1e3256d5dee96d6adab8513f1b060ed85afa06eb552cee34072080ed06edf730c7384f971b29792f395cdc77be599a1fb84e04d41a46137f7a0d49b1389208b4d310ebfa7c4854a79e0d79a12977217e36814abb7b76d206e97d191596655fec02b0e9ff16e5a2d9137529ca92418fb4f259001ef64ac6cd9840f32b2db8015240fcfba45f015b1ed013339529b07ce0d163d5dc9cd42b07e9580a742ab58c65f44bea3dc0e73dd472c3e86d80f76b722387a31813d28a3f988d0decd3247662353824de2bd9f96f83fcd1e1", .Okay}, + {.Div, "-5d6aa483caf66d6528166b926fbcd28ab0d4f91f4f89894c08e1bf5e5dcda5bbe69ac877d3b390d26bd785d6d63cf03db035724f45df8221b53d6bed245d648e2ad13539431920e0eb336d8b57da0e7848f6623bad31a07af93fa83b66b2c1b6edfaef1f3bb410428d00f44bfb714d46eefd1c4a3093511669b62ba8d762b9391bcdc512ff81a605b2d2401321d2fb5f14ef5aa12006ec537ce409bf1fa3d516cce51f6a5082b16992255e9b1b4163d4135be0202e4dac488a6320fc83b8739904fae59bd305764dd4f5569def99ecb47ab63fc43d1814222fd142db9c0a168751ab32a193dc99b581cbf1f0835fedc92d1e95d4b68c1ab9c39ffc7f88d344bfb33b45be4f8d9cb29e108cb170a9ac43ea5562c6cb7709706d3b95ab1007582c337bf4f88bc551637a95287c535c8ed79abd12656990cb067478125c9f059367505986c9ac86bd1116609297bae47c7bedaf7d716f6e91743b706952d265d1b3d47b791da38d775e5d553a88937e00d54dd7f453fa6f97cbf9e5c5e078c24ebfa6d0badabdbb02283b042908822cf0206c950ea373e3aee471698ea3082cb631246a499b39b2b09c07d2b5d036034453f4f1dd6c0c3a3ee6fbf02201128c666940bd10511eb9873f297d07ef5f22a383cff44c24a6510b3e048beb9274a5a601437be981fcc4120e78c359968a5ee525f6f9b250a6c471be50f110f64bb2e410", "-8a1724737f2ee82b3f1587a7812eba06155feb9f2c142508949bd7c2f55e1a87bcc4acd7e2136b9acca7b1d01da41724105e63f14456f7ebecf862f97064f49af6e09e9d1f407d524476eb1f519e671bf96bc937b0dd1c8d7b2d134a86385944c24b3be74ee9ea83af3019eeb90681ef14281e35299e2a085b2e935d35b145ecde8044a8da7b609a6deb84627a022c078687934900553c2871946f4a829c8ad4d5b14a1447ebfda97227e73dd93bd79f235b7938f691159f469316b13c93147628b5eb2f3a1dad2fce61fc68cb723b8bb7335a8e6fa85667e09613d1a343b2d50a3f4dd65b95a673bca38d52d5be44e92f6fee5d73574fe98e9850cec08484aebcc4edc21df77a61aa2308b646649e3d4392bb9897fbca2789a6ec0b20ea273f04d14b58f06390c8b798987b175d5360b9fbcd", "ad2e5a538739ee4a0fbe74d2b6f7b43054b3402f724b9a14f9f419a3248574bc56808a5de70c3029202dde58de9729d13bef16ac5e506da38ffc4de6e811dd1d5315a8cc2c3749283090bd7eb2c33f3831b841414555dc20670a435683f154027cda2f1fe6024473560e2f92b092e53416a01a2bd852f19cf481550aa089ed975f004aa3e06ea27854705d7647850b7d8eedb8bb989928e5b7859c36821a92bb23969bbd15dd4bc95f7ddc670c7052363ea8fd098dd572548dec33da5d2bc7a10457e51e090f570a0b54b1e9e0", .Okay}, + {.Div, "-563ea90c54b6b5113d778a747a2692e0365dde7bb1bad3abb00cf608924078e9fa2a2cfdc8ce7a40fa04ae02a36a563c607ec1d0c8e150448bde01f15347ebb72aa7e0acf02c8654313cb20e8a48c79d813a11991b1f61ff7c6d20d8de79a8528dc385b149a63910ae08265a0d79b964ff47d258f51ebe6c5b67534fe327aa318a0d046699906e08cbb063462a47d6034be1966f9be46b80685c6ab04361a3ecffd701230f6cc30826042e5b6df5245a4012f17808ada00f25f96b1527dba0f35c0c0dfd4f4149a9d61a1d97019dabc2c4eed9ada321616e166f097714964cb24c57d21c88a1a3c65a6f144cbf60c214cbd9fc76979a6477dc3b33cd40923574d9638f040a6b072a992ef8ffb4debbb37c4783993e6a75d88a273b57479d39a2a795babb74cfd03324c350340378380f2c683741b696be3fe0741611fc436357749976c048ee9a5a8abc8f5cbb2c897ffe67f29a48c395fb9a4a0a170552ee204a22d50b26f8e1c7185869d8bdae4782eedb450b7ec6654ffabbce9d0f18b6b2a04a6c531a695cff7200de50d5a1c4933fa441b840655fdc0bb0e18652ee1017ed4884deaf03d40845cf1d7e473084029db7c2a9f1fe0868c52e7ffd733d192d989a3466de2e05cc570d4a86100a14e0c059a80e29b020dbaab26c629fc71624a269bc088dd7fa661189f5a673e0542d2c40025dee6c0dc03931c6de203da16e", "-18f9bbcd51a2c8c96f7c606ca905e02a4d4b185b28ce7bdb5891160f5f1e49eae01c1ec78c7033b4eda21c09c6d832a9a3841545fd09af23084ccfff318b14bc1fc63f019db7638946b056ba08b6729a87eb07ea88fca07e7b3363fbc501b57b3396f21e97efdfe00e164b7dac525e8b52a63d5123b6778b9bbdca6f8a875d7b842b0b098cc90ee9f46c3b2ba9ed56a0ab44b2846d6487899e282d5d7e4b041f37c02676cbeaff6e83c2198efe8fdb987f7afea028ce3681c628cfad026d7e28af59a22b92352517144b3b91f8b1e2abbb4c9b93f96e16d9ec262c840ef70b896a85953a3f82a0716ad2e7f4f39c1196f32c113bc93e6b75c26d65cba3d85a2a37249bc4dfbef17a880bc19098ccdf83a4c3a6d3301552494a6da98aeab2a4fc3966e76ee8901d00a8b4a4f19cecc5056081fed", "374031094eec353f6553968b8b931eca9c440cd95173de4db7ee0f2f92515ee3af239aa13fc57ac5ae5b717d9d5f6d6a80acd1161c61e8247b89c871b60706cb9404f0240161b0f935f529e2f2d22a424dea6c2cd2a7bddd2c92c45a61cb19d30d050cd7650bad764795ddd9a1d567a78e784661070aad3affacfba9ee8767ed5f960c34c383a737a8023d97fd91499fd9d8c5c9e283ac5e131582f7636b5e1e901f6c7e8cb44bc504fc854a449dd829a622050c81c54c2526c89b404d3536be9bf605f4c3601c9c7eb29f4b33", .Okay}, + {.Div, "-bc7faae9c2593861741145d645a1ad9b677937d9350f8d310c246f79263ac910fdc5364496dcb38fb87ad1f55ff46ba16660d6a587a8bbd3ffe51c19bfe67e766d53cc98a3e491876b205a1b346d6e04f7119bb06eaf0398f0486402d3e5c4c5636ca3bf344f6979cef1a0394828308550ecef9c92d5c6e1c73cff37fc7989d68149c4d344e97eb819153e2668e4b1d0dc660d1ea23675f3b398baf5d69b29211c0d18e7a5faa75e658ecdcfe0cb826672b56b66f0583d5435450025da283480e0a7f19bf6d140911f12490236f06460f1b2d9cb6269f1dffb840d03ee92d94cb4ff9d0466c1fb0534e97a2ec69e9b15c7a9b3cf94a6f65e400fe98f1d4c3882e21d1a1b2c0f9c41c57bba7b8bd0f9c477b3177ab166c28879e4063d66e86e0da34034aa7c0ef500b0b210f29c45f5545dc02d42036add343a23c62e5f5c9ac8c8be207b803419f1d275711527bb90aaa28630663e290abcce9cd960a15acb65beb564822559981f33f0f965b6671d4816f8fd578e8834cf5b7f833e3e9322524a35d4707b1b7fb091e6a73907010b05e4eed2b6d1b7940af7cc53c81a6510ec84a052050feb4e866516d70b99e71ba99d6f228f7697c2999069efab13c6829af940119d99c262c8288d45bdcfcb4de3ac38183481abaeb576de70e7fed431324f8c85d05ead6cf86817e2d06c7a2e4b4ef3ac409aa49f7ed490890a2f97f98", "76fd9e7dfd31e36e37dd11c34b06b04588a78e22718d46c9f674f8c193ba8df33e1f003500739e2f8706c8c6bc899c6a7508070ac8a6d3f11607ad871b39c98f7da7feec34fadc8c3d435c9bfa87e6c70e9d8c80ea1a23b8fa5829f2224e99299135df14365ebc0fffd60eb31f1c6f550bc975949e22675542d4081f41827e41fd3da43d096592ffe06ebc7da9ad6bee6bcac33d5c01538f2ffa3a4cad976eb6bf6c9f0316558d770c3adb2a0d3afefc0a0170dafc21cd271b538c3033662c4b32094ebc87b335fb7689fe2525061734d96a0adf5b4eab76371ad2c4626d847719ea40a42e3d70851821c5fae5ea921eb519f232216e619646fe55f65147b49a6a7b950016f11a7698128aa56f3ee481a4c1e0dc46f6fa88fb2bdee22ec9cb3230c5c54b84662ae87d4906984847ca40ca1689", "-1958aa0306385f6e65247c2b9da413a95bff7001bb39c15724b5d64bcb09322a6046b4ceedd48ef5e471eb73ba070004cbb7c58046f139fab8d2cbb0085718943e25a5631db29d41385cb39a6493d2403560d5d7096dccaba7f4bf00a5984736363f8c2f6fdf7eef1899a9d4c2a54096d7e371167682c2d03898a66bd4c7dfdc42e637ecb62bd9e78a3d5ea7a294bdce399579e2d29e6903bbcb077d34bc586bb7d44aa91a3e626d407f572a9ef4cc5a58c78b0591138c7f03a92f561b5bbe29c8efec017378f1fed8a6cca60c", .Okay}, + {.Div, "-7eb980e63a183745d6779c9581b79e506d6bffbc97519ba366860d75d61049037c8d5e28b4f7ed6308fa58871fb979ac7bbff25dd79bd03793d6008511a2d7ddbebca27e16cbb3cccd3aba0e10157014d36de7ce96e1b9e58f1a1091bc2af12c847c87438ec43058396a62de62da649bc1625fbc3e2b1218613c153246505b28a72a7a8938b10f301b47b75d5e4c2dd37d2b248732940060b52db4c5b61d05f2a817ed544d3363af315b1498e581d3716a3d01aeafd4244956cf57944f1fd2a3b9791e1a3482bd6cc7d9c61d5548fec9694c118d7c7b2ee752738c3510e8021202b514abcb2bf23ecf0c0839b396a804f481a9f307a5e941d3a0d18f8bdce9e3669c6c5eea56bd74bdf7ab84ffb6ac4cf2c08afcbb6182b5cd6af751af4d9569ab9c7bdc257450f59305a121782cd32ed16a488b0d41d09c2967a0c35b270f7fc1d3fa52030d03c8bd8dffce816b3b46d5574aed925cc3210cabab9a4a9c51f7a5326445cd96c1598c985be75e6e25cad99fa95acbcf536454848603b4b8821323b6e274a7ea11a68f5c4595bb3de8061827054084d8bdc53bce4ca062ff7dc703894449ae91f2f968f454a9fef10ce906f144be13d3d63fda7ee0e28f09430ba7de662a33d68ebd90772daebe63d8cd64f4f62171cec8719cfe0aec27d3f3160f3de99f645605b6bd42f8d78391b54efd8054117d574d0acb3e7688b8dd02f7", "1fcf3b7862354fb147e82a2674c7eff380ba62c76fe012cfe322a012153fcf3ebba045d14d37b5441f4613f482e27324cb93c3cf1c0c5b7198e84318fb6ebf2fca4a0bddb8aa85466f3893acf7260bffd693ba02b775b4048d20d719401d6a6cd01040d973b14a4862ea3e28ff85cd1dc5d173d40d7740cdc57229d0613ff0cbeeb5f24d1e666e197c59e5df5a1c27946f61655c6852796ee6448652c6a8ce917b26eabe79e98ad1e095c85c9324e721612cfd0fe4273bcf3e2cdb37cfd55ecf5b937974f5bd24f0cfd4c5de2c2c7b74e8f4e3bb44e95ff44ac6a9f57c837a41a9941e359269da2357ef8358e91c3924808db4250b32aafe9c6931a3ea184f37d0464b3ad948fba7e84617a8db52cf0916126aa187899f38217a8b25b663f74b15c39a530285fe9262a73aa8d775ad2c98bbe83", "-3fbde4c37ee45c680105cf362c15822fc74883ddb1dbf1e4687c2f6861f30a7362ada9907e2a75444ee9ecd12055316aabaf58b03ab096e160aed9a31c0beb8c83b4ebb1e77f6b3e1ac94cce710c2bfda8dffb49bb813782f9ff58d6ef6147097943769923f7f4fd8b0fa2b9c3860549197a4074112deb7e3ca348b39fd8d76d31a10afbfa5c9b1d1e93d4d778852e257d4d0b93d299abd33b2462c5ef839cb6bdf25b9807d04185b09ca1c5f8c9abbc6b7b606fcc7659817c166ae8615b7f1d5e74300f1491e587048587ea29", .Okay}, + {.Div, "-bd5783adac58322fad970c6f5772c3312c3718b66f7f9889bf62a7b791561d3669787a7e8d88e0819b9ec0a75c9388d7f56f373825fbc614ede279cdb62aaacf02ea7bd941b60a230ccc7edaf59a0250d651539221fb5030f576de0e6478fe32587fc4c478079770ecc2e3d76e51a778b265c468b569c12c4cc3c3134087339e42731ca5eaf435a2a83e16fafbe6b525b95b9132b4437101c9f44a10b5622406020ea9e6e012c8f3ce34794cd6dfd3fe13770dcb0c7f43179c9a7d9e33426c872c85824980d580d5a156b6aca0ead7525040bb998d22e430ab4bd4218bcab86afffd94b38f311bc706b9767bed0d7dc8a16d01a54a86712ba89c1f7d942487ec5f166cc0d226224d277ff167b195499a08beabaa05603e4423437f226f9a11e99ed0999b9aa223692b0e289843210307c98531e249be3d2ed8dc679f581d0ebbdb517cfc37bf7a9d67c3fb0a32b176a2e1d2d241e1163c2e1d9d3663884eb1e982c083a09e4b98d30fd7cf835012272cb1789efaedb3c72e05f4fb1e0aa3cf48ffa3c2ef38130d01d8cd22b770747e87edec047dfa37a7fdabed95d88c3d20fdab7f2ef7855618991f23b126729aa1b7cd4937ab2a6d6cda20fb35f81c1668e35f1a8238c4d9b8b5b0dee2ff0109989248dca31b5a2bd2c8ba70bb4196294c58c1146072a4956be852ab59418cfc08c08d3aa5524c36201596635c7d45312ce3", "1892021206a231e9f96d91236d99184cc0bab12e08866c777f1a3ccedba69989810cf89f36a192b439f1eb30747cdb730cf58f90aa4d00e5da247d62c86ac34a717a3fe9fb0eb7975f150721c189ea2f09ac6cd1538629d529fcd7fa848b5449cf56df20374802c5a141ec008b9e8223fb75d3d5e1d42d41bab48acc842186ad7762f86e15bad43ec99560a881f252fc295b14e307ac932260027444371d31e6cc0010b6fbd86a2e43f071e74afad54240da19d5d74fc1b9b01e2597b707003f117885272240c7f24211b6e084a1cac66de1ccc644463cb3291def2e7cfb2f2e57964ac68cca01b50b0ff2b2797ec47c2e46f4df97f3d229bbb863608276c24c0c2ef438e0871c3d19bba4ee54cbcf8b9b9ef7bd22386fc90c4af0cde31417d2ff5d874990e1e90af205e12ec41d1404177851e", "-7b4c3d5b902e642baded394d4a366971489ab8379c38f4019e4f3fa0211cb86a5ef1c67a61ead8980e7643f64bfa432b51ab4f3153e308d158353ecba76d0f18dc8fcbed692a566a400e35dfc65a5b02b91255b601dcb9ab4a239105b976cecf3843a68c1c0b75540f39c0a5a07cef4e562e48e449cfc931cd8fcb1ae1bfe64c97e456c3526103030acc7cf734629e74d247644523ff4dd2ea6b3fd0a4f854ad66d0afd419f5a26390ddb2e2dddeb51909f4045a79a91ed33455c367a8b299919bf1a901ce8ebf5f5785b02782", .Okay}, + {.Div, "28597b0acf9a3a8d84f25951af380c8415c9d7d63585c5099bb9e3abcf450473e2ba59f2764bafcacb618e0d6b98da5818d05a4973b65011f36feeaf9b8c881395947f5735d3075f4b4f354a0b0a93290a0fae125c09da8b8ca84e54c60c02a95ee072246bf1381a209d31b4df1fd9a0479eedd795c86c7510be900fe443963e832b318222c66c86677ed4dddad8da79e0cd80f762ef4e52a5695c11897d5cf9f592b3e21626e00a6d80e4c7d189c678519c0f61765797ba9d20de883beb81ac4b33763fc54b2c66b82903333c4137b79fb5bf4a1302d3ff895c62df6ada2f8a2b4b95114fb38b7c39eaf13c7b28c7254f93099aa5127570f918a715a1174782ab4cbefbc2183e95772893453eeab1041d04e2295b8ef37a2a3ee395951ebf6986e239761e570c4f518b9c1ed59e266f9f2ecceb975bfc1509b81273ace085b1710875fa15440e452a97ef14b0493ce859b8084dcb9d92fffbd236013f5aa28a193be18fd837720fc5bbb29c919c3ac196be369308bec9531543d929830c0b6367d3d7f4f8719d7125eb2cb6fad9756cb318de2f706239263e7343b89a95b8523ad84c69119d23a19446e946ec25f63f1169df93efe5df7d3a80eadaa2f695459166de9e7be46dd486eaedd051450db56783dfc74754d645d065f72efc7601b55d546071ec3f172aacf97999e6fb407a22214ad3f7f0ed6a94b09112ff695989", "-7600b9b18b5413f4f6655da3ecbfb93d2800c95d53f34e1a9f295225f23800edba28f4dda54be3113a416c75f21449c41766900be3fb79346aafd90365ee93997d31be436616f6e78cb276d9ec7c4f3aa3d6bc7d477feaa14b68f38887a0afcb416c512f281bb58b0c5f46c5d4910b53ee414904317ff65f4b7507cb1b73cfe5fe04ba3d5a4d2ff86d5830e1fce747af260740a8ac9e89fbb0def22fc3a85d11bb5ee45cb562cc080f04372504a3a5bf83e02ada69e7c7cc7518104e237ea48d66063e4d1cdad3bee3a51000249a4387ec30f5b813358eb9eaf99308bb3efca1fd52d4513b1bb1aaeb78f8d3d77cdfdcd54d16538bc216101798aee6b67e45c9bdcfa08219133cd0cde5cca1f6b9247856996bcbc08577a22bddb210cdf20a97db31ad0d225b764871c47e53cf30df436dddd3", "-57892ebed77f7ae935fb05876fd75128aeba3f22bcd38cb0c612e2591d995f391e0a6e9507fe52cdf9d62714711f1214ff3a30fa27914e56f7af826f6529b96151ce2037bc803f333c871617a49c67df5b3b0110b624f24b1538be2c73fb04ae9b5bf626333dbbb019df7d21eaed9aa9e348c522c3fbe4272d04444b27b71d18f20353b9a568071d4d4f2ec1ac36c5b8e0d4bda406fb488a44287a1cbda3a061f667eca65c461c6777f23676b5562278bfbba5e7a3be72ba5fbe484fda2106e257dd0e668def6828509237c176", .Okay}, + {.Div, "1b7e96dde4a34a9002392a5b31977cf17522993f3345d8ad6802ba2dcbcc9fb2a29559b5856495df2e00572db9dcd8d0b090246dec2862a9152f5a0f144dd1b8041639dbc76a883bc3327cf9f51135faf60308caae8c7bcd2c8c28630340128123dac0e231ea42e4b5cb321e5182f9479a75ed5a62214261731504a5eca2b27c94992310a90bbb30e74c3a79345c33508d1113ed8c6b82e5bdf938de2198497bc7e113e2d17081a45f1e5db2787fbcbafe8bbc49a3d9bcddb2818e2c9b5aa23656b1157c52cfca3351b21dd359df1454976b6281849977ba7ea92af60b730f6ed6c851f66548f9647a0609ae8a7e1ff0c3813d8ab0335632334c3c5b317e64ba795c1dd28fd3be53caf7f0d35aa389a511802b3fa2c38f80cc4cdd66973dcdfb41d51703675e842d349d447690347f76e6b54079e1f38f2e3305200b50498b0c4a30dbffa334a6e8c7a06e340ce4b8c7f757a3e8cff3200d5776be978fcf179ccf64e62adde98e75a0d9d1ce6f7c5b232f834385a6b169a039da78c440cc06429c4c098a7a58f7d79dc14c78bfe94cfedbad6fe0dd6888dccb242a4cf745cc4dc590c060a9e872fff662326c27d3d4178d6cf6c9cd4139fe4dd0a69b74940e3660493ed5b23b7709d22a07bcb1339ac50aa006f82b083019a72b7573442577ac5793f9911e69926d8f42df218390c3e89d79a859b1b099787821f6ac2d803db5", "1cd55f5275dcf14a826c51b9b9ff913cc00ae8b56aec06f9f41b37dc00d055515e56172e883d26cbae60de03d642e3b65c0958fc5e390788f6843fee6de40b8c3f781975eb5940e8d2a317707e3a1208a5cfcab6ffe477d00f815d7e40f5fa9822aefe7da049575da736a6124b6a7576f7e076236be1e9457da77b7787a3e1c16f73bd8a72e57e00ddf02a8675ea417f5c7e9c0fc5e7df53a5f005028d9b00181a99f9916793e792cb35981df584227da0d9cec89820d264bd998a97e5572a4623f0225c8047eced0d7cb7d080e525eccb2b62f810419a940e6c3fe24e9d13bf406c513e848b2579ff8dfc611f1cf5130bb9ce34d50d1a0c0604c404ffc7ee2c7799ddd15b723736732db9443e2005b2c4cb45b5a01a96127a41a2b071a4464aa4c0446300b9a061024eb68f001576a74e2e39", "f41c940d766a18e1861efb4614852a4840f3be6f0912e01ab2baaeb47c9cb0f793a9cedcd788dfac732543682d2085a1a4fa39f779e88af9ebdecb159cfa5d0905c10c915a4782a8303a8b0a3c853f218180872894a215b1655565d6d84cf920ae923937859e4b9024270de8b59188f46c52640a058396b917dd816b1e990f7c4811519782b5fa7347fd1d7ebf08c417a63f0085b2a286cbad69919a152cc886d37f035b128039e559e3393e6484d2495eedd881bf075531a8ef5f910f42b6f3f575f6ceffd30a29ff1b9183a6", .Okay}, + {.Div, "-211e72590f7fe7fd212bd80998e9611c91c84cfe661e7c16cd32f5b3e58bc1788cec70569a1989a3e6f31558d750a633de573f09819ce2cc8ae4fdd5486c10c5b5a81d74e4b1e80545c7d32b70e4ec9a87afb6971d061c9dd996d053244c3a1535e1bfeda82ab6442df4a70d846de680d8613b442fe5a1f1a5ce420673f6a52600829bb1cd440cbf619eb397aec786d9613ce7411e41c604a9b431d93d1adf45549e6b8bfc35dee2c9310783c0c2fa56636c96045739ada537b254833526f22735928c49c268d191be8747fe2899230857ddc2012cc13832be41bc4c20fea9b79e11906663d1d681cc3a2fce60682c0988ccefac2d56fa6f8274d1536bb4a8842bb98e62ff02b59e4a751331140e93a8ce00dec7f9bb3f21f1bc0711123959a21f690d736f90768fd6ce6f807f135f8da05807a119d86a1cb34beebc2710cfaa662ea0129e05555a83746c079c76b4b5ce42a313410760c61bb683c1038601bc9465f6325dab119fc0491daa352b8a7087a55ada23431a310f1e1dc6dae7843c25ed707201cf74bccd408eed62cae65b9bd3c6a6511e3716a6925c94c33689b3369fb82d73a4ccd7374f3945687cc01fe982076df7160243633226849cb1dfacc9ddff3dbd1bb16e75f444a51c74b901b415efb5316b7e40b5dc2efe01a96fceea80901869efafd582eca696327ff55145f75e4b9aa1b740836ee9fe5fc6ec73", "-1fc8fd8d77a8211da53137cc42b9e81899256494b820051bd4ed3cfe1bcf439f371c4d1947bfdc4947fd6ad5d882be3d8714965744f771a0499d7d781c6b6362e9ca4a0d5db381291a06c1fb972b88aa44734873c34dd8052a3df56a8ce527cca45fc139a73dd3d707c96c8da33afe2a2cfa095f5bedfc6bdf1f0713a06b2001a54629d9b4dae594010b9b0eb1eb20fc5cb04e2e7c00dd93cd40b62d0b24486fec81f44443e581fdbd13c20299d8759344a28d7c6734129a922bf1aeaa24031978adc54e1d6780d5db82fa35c6a4018140147bca85f78447ae2484706477592fbbd979bf99485e8fb28329abebad8b1d1f5a8c27ceba93c226f2eded64c0159b9d00f4a680984f578a96f7461f406f7a4c6463177f22e20660b6e88d950ce1da054e78b0c4a9aef204a08c3aab5257ec773257d", "10abe1df28c8f24dc18205c676a5209ad4adc7bc404cf167b509649c56ef923f09e0e79ca597bcb19470489db3e46a456d0ca2d6510405e77133d6f9fe74f70a80a74f7d2cf9770772c6326364bba22b18ab40c810c0f65d8ff080f7179f274f373d2f0c7f37ccf546d4ef2b29b87d4693fa4da21312374ee740a6a8151f83718fc1a8b94d38b3a9d6d489d9752080b20a609791f3d49cc81ead9c4880ce8286fd4fdc9d1b6bc003188bd32387fe05e2141747f0c0de295e06e2876e8c1c2de2edda6d7a4889fb426cc08201c1", .Okay}, + {.Add, "ee66b730ecb84a217de1f7c98fa6121f4bc45d5e7168e14ceebeb1fd188b82a8be90e9bb00b97e8c39eb66e6824a834a2f738b0d878780387889f88f32c21a89269a5b0aa0764c4a1a2096d62fb7b9ace960816b4c6523ff6395b7f5279d3e437922a2fcbde10010497d3645257a4a2e55443d91fa0552992451087e7bd9878f5cddd2cd2b35e5f09b1710f03110083f0eb5efbb4f7cf84e8d479f437ef4a3b9dd794dbdf99a0657c406e7cc98331b4306e0c17b004383ada6fcb0dcf9cb8013d280e33d4a822ee0ea867e51da00abe0ac801c7e4dccd961aab5edbd2c7b5cc3803b3d37420f78e15327f72ccb2ccb48fa7c84624bc69312beb3b56db3042077ac14ebbed9745396777d6e6bb2e7dcd3601e0e0622bff3ab0cd90184b3da7042949783e827e0281f48d88ed0e4e7755a7712ec30ddd41f7a8495454518f7549bb55752c3a4a19586953e9c46fa9f65ffbcaab0ce53a72d6f730ba9eab53a71d5917a8d0790b16c3ac8da7aad025efb4f5cbfcbc0f635feb02798fbbd4f43388d9d12626375b5ae7a57de9fed0805ed895e4b553b917e809cd064767720e6d8304f1df2ccfdd16eaf38e858537cea62b8cb565c1ceae18547b8c8989ae5bcb9bebc2600216dafcd23c18841c37583b5e961e1fb245113fe3751bd5ba39d9e50caa606c576a3052d503daf6e86421f7cc29bedd4f208dc82ea2c6cb1650d3147c4d01dfbf748902e8d7b528bce8193f4cd81d52608fea0cd1663a93ff4f10010acb9678543b0bb46c00fcf3becd86a8f1197e34f89c0657e90785bfa82e544dac1c8091dac6bc85d9e1dae65b0204491ee4987345b35d9be998626a0b24709f4df0e2dcc519e64b580ba3d673ced0c1f54d62367a67ae45b41de9fc030fa1a1c40921f014b1bab4d8ec9f8f53028ca1b110131aa71800173c6fbf30e3aebf2a87c06822ca8758d4e7011a677c016f5e7d610375115f850eb32993845e377356f732200b0cedefa4442be2387e5c94b69d5b4512fb59f6ad64f98dc27395d692c31debb5e5cbfa3c1f585c9f478276bc8fa871ab46bdd43808c5b1e3088f78c16c22d7f15eece7c183e1dbde9f05579c31f02c7c71e07dbd12e1a9804e12e18e3b582a5c67ffd5352a02028ad724d37416927d5b4edba5b4590bd8020220a36f3ab57a4c5193806dbd435a38560c54bfa24b7c80e06b5dee6803768377fcbe4fca2ffabc5cfafc3a9b10254396c3cb86127b5c20e3f7eaea7c6ff0727bffaa8d33843e586ba380882ec933e2b0ac00d9e0c9b48a2a00d0a222a1441688695aa667b10fe47a6542b3041a8d465fb05b89d9a81bcd2097dcfe1faad5ff90012c6c63b4064de7dce11624b2a48e451dc8ea491be928f2bfef957962090dfb0fc39d70c4213040e2194ff685bad3e20998c63ac13576eafb13364a85d9a7dc33928d530aa4aededf3c8ea7f6c06a20c88dca62a42b9e0b975dd373a795f9e495e7597d469fe6c62dfb664b2c74a2010e90a27ff4ccfb5c90b1ae44c00b5a6b433acd13dd2fbf2fc738e170d96aed98744a86eb5f42aa4e3207a10bfa7a24e8a5ee2661586d7988bcc4e98cd028b2c8aa6c4a0cd01d5009802650a20dce5e6953a822d90a620b75fe90a58ec1016ccbe87c1b6508f1c22d4cbe798fe1f8c71653edf1f37a56b56424093195d1764bf38f44a62e1303751f06936a2c335e4d57384e09283b98e55e38cab503bd6d274c1451b3b5da16b57150e8c19498ec0c88f41d637804870d58529242c2dfb7fc4bcf13c83ecc6bfa62f96bfd44f4b79a70da4a7bd673dd43a3175085725590809b4f8c0915ad9d08c5e29c00ac335f6f3e41eab39f11e7f0ed0160dc6f3930e63ff7ab724fb2c65183441e25179e6715025606d951723e57a81fdd4cd02c40c9057924b27b71f1bad9b564c6d46bfdfda89a99e1eff3ee98271a8ce5dc037f610e813f65e62a5a2adff47ed6bf7bb4c9938115b7c6318e69d80927146d116ea92cd9ddad2777eabc92437134763a5038aec20d2fd1f4b15d02adec6abe1a1ee973cf2b3aaf0180754023eec97b453cb53f9619a51eb498f29ae70d33ad1f886921bb3ec005f7e7eb2084ae15cd132f8dee3", "bc69725373ab24ab7b55ad9c5a54b981f4615b877edaceb97cd10b0098a5e06fc1206fef1ad9d0cb211c8aaf18c4ccde6ce8e6f6886494c4acbb3485cb8ae52f126c8a712386287bb90242dea6c74a940a508180ca350816c5fac47d8702a2c70327e836397286c2c46a07c83d420acd53195ada97ac98521fa180cc1c93f391785be4c5cb76b9447f880f2fde3c35a52b5fa5114d27a145720261de422015a673900c14966f5811b20f9f408c0760229e33040e5167d0750f7255d05dc0847768adbcd4e30cbebcdb4ad3361ea926b7deaa925dd38565c9f9f4e429b452874d13fa88224e968a6febd937eba0c6489633473599785758948337f69850a2e378cf3ee97a8322f2798fed574d7b98ad78963aadaf1c7abd2f5d9c2174a7959d366491de22ac17abca35ec0b1d85658e99d936516d6c9f887ca4b16966d5ed7ebca5a1017598b919d3141314f36151616709facd9ba723be4c70b25f737ee986b66a7be6495ed10c583ac63b0a359475926fcf885c4368d9639a96e7cd037fb86bbf8c91946d207269475a53c3b9ec90d918c3385e3046dc59e39f98e9163e6faf75772d01815c3bce7f83f64a4939279a753cae473434127aa767c2695318f120ade33a98ee0d8dfdcecfd3d21146e65c5964b67ddca9cee2ddd0f89c47d2e83a19e6b6ff65b5129935833d893c56784f98f489e64ee82f0e644708f7c41b27438324d19cf6dba67ada62da4de76ad3270c712ab73c1bbeca611816cd40941e00c0e896fff7c1fc694aaebfdd83a8b3a7ce2d69d58db6bbc90d5ab7a96c576cf4d4a60cc0dae8f340898fa1034c55be0acd112e63e28ca01ae55f27cdcf3fb4f43733cad3a118eeee1368b5f6e6c9b05bb78efbf3f4cc98d5ca15a89d70b11d87eec39b508d4cafa086807aee084c4fad51ca991e35b8d257535a3369aa35e9b21a620ffe9b72fdf45f63f156ce2de5be824eba0589de08d5ccb75ed9462af8505fff997c8a6d0c5b362defcf54d6f61ee760e59e60f633446cc0c7c64eac5d1a76dd07c7b9254528e62ce2e0cdd4b728bb8e98304f490a547466ec944603c6b857232ed9887a1a4c4be260f9d6cfb0677f53aaef1010089d18d066c42837e5c38878fdb4828b99c48ac9a6294fba699b2b6a3e9f9ec04088ab9873c8823a85f62b0d749aa2767382d0f8f987b70cd158a96b80fa2930704d543842c987dea3954f5bf48aeb4f1795b4472f785eb0c7e6241f1510d41d006567398c0fd230d9891a4225695ee0752007410a59dc855a867a30d2983d002c867c2b2969c9a536a66371d0763d2aa474a6a4f9ddc8d7af5fdf78fc823355cdf17acbcf9a912ef903a10890afc73e85abc029ea225b6970f1ed98558aa2bc9f41d437084e4a021b84425ec30e8245cd3560385d4f51ace2dbc606ba695722ba58786d182915cf074ea439e02c4d9bd1f71fb080147904dceeb14bbd40a616fe8524cd8bec51c900d21a6d8bee00352ef730a251f74e6b05823cee3211c0d2c4eb961bb7cc341485073bbc56a39dea985d5df0086b8c9c510ca192f7c3ae019412024bcdafc61adeac9dd907091f4ebdae42c874f055b92da9c4b1a3a011c15a596ed9de7f1976d8ae2f8a44f118adaf339c536e35a786debc6593b6b62654fa85722a16392c7f527d39707d5c562dcf2bf995d2885ca056922f4e6664431f9860b26e587050abf1c5c6c6432ccab575e7762c6dc362098c7a03084d9edf2cb7bcfa7c421e47ac83e4a10279290ef34dd81396098a34b74d274d2b98ba4c406fbaebeb1c4838aa1d99e6edf07d6d00c2e22bc4a3d85272ce4772018e38305efe4361ea80e07daf501cf918f01e7f3a131914961a2dc97d7a3fab3aed2fb2cc8704ec28af6c009f5edd7f6307e6116cb9b314c276700ceafb7443bffdc21425ab57b750f75fb226ac2bdf566c8e41cd3793966d709cf6d5a6936a84dc942af220f6e122a85989b0181b3486f546f6bc8d99e63fb2bb7f852065466ac442abe04a23848433c406c09829aa82f57b36db383685b2aba925e298318173724385981bc17d6dc811ae9454172a149340381d3e5419028bb71e5b1923f0932cc15a7992154c28e3ba", "1aad0298460636eccf937a565e9facba14025b8e5f043b0066b8fbcfdb13163187fb159aa1b934f575b07f1959b0f50289c5c72040fec14fd25452d14fe4cffb83906e57bc3fc74c5d322d9b4d67f0440f3b102ec169a2c1629907c72ae9fe10a7c4a8b32f75386d30de73e0d62bc54fba85d986c91b1eaeb43f2894a986d7b20d539b792f6ac9f351a9f20200f4c3de43a1594cc9ca49993ff4a0121c114b960510959d290095e697616870d243a7b65a513c58951ab5422b66f06ad578c048b3b2ea0122d8eed9dc5d15187f8a9d2988b2aaedc21523f2ba4aad1e6e0cde4109435c55990a603513f012f186bf313df2dc3b9fbc41deba741ebac0603a703f07b53d5395c974610076ac5b92e808a4bf658bbb53f3ab0da6a7522f95b700d78f929620ad3f7d3e97ec499ee6a4d03f450493d9e4a73a7f72946aeabeee4d3585af854393d5aaf59a951b13a5bf0c766c6a57e69facaebbbe3be095e3423f88bfbf67350ef82789303a0b5b737f370e1cc8f541d399ed813c22fe38a52c2f0f95c9ef3f7e2d620e39f38f3b0c1f27e62770e8d99c1c55cf6b4040f60372547dfc4951fce7f2daa7db86c4e9dc6238a5340930a641f1597c260305b0438d5aadf6a093aba5bbd5b219058159586ca9c45bb46b1a22dbdcd1a2f8e543fe5713904bfed7c7608ba3fe97332ac0f7e75f51234e25ed857c4b1f890b3ba5cd14c6f085342cd943f6bd50855b5661c68fec7f48e4650c03abc8be0c4c156c231942ead7a501c43a87d43295a7dfbca5c1342b96610b95f4e1c3a5985b6b22c519c47b69caf2a6d46b150dea73e06b36c9a4ff9169862bf18665eb46b85c8801649a9d3456197253f7da46ecda61d33d3d5cfb08db2639a6fb0f417a8b568ce6acb39c880e29c9ba8f7fd2f5079701e31166abe52fc438fb5ba461e4f4d41a49628922e20e43ca711004c64710a6916e523cd9492860b1b822ef40865efa4bcbd6067c382004a4b6967509df45177b51e225ff49bb2155400610994059ceeffac15894c5598662478c9071e6bf6d758f540802342a94c9c2c8c8ae0cf851d1d3d8fdd7a84a244c856f6328a69a04aea2c497386821b720d17ebd9cb33686ba55650c9790b1ec4347fdeec64aaf2539b9cf1ab04533ff38d591b8619691893ea8c7179a182b239b3da7d4f57069c7ee87c58cb7d61338f00df0f56cd8ba07a4953c3a0384f07ba5a9b12c146b69b68e49b69290dd9e1235052cba82c6640b3cfccd9acc15e27ac2396e8f80c9a7f35649c92f893157975384a0a4eb0906c91f05f4f9d217470181c9155d4b64f795fd8ce904cfa6135ce8bb125afec282bc89aa3f5bf3ee16d6f2d954fe7f6ea72ce7437f81583ac2ae4b6a1b5f6d7f4c7e7ff463bf2908471c71ca3dacc9dbbe59b6feb394687d95e291908561f00d60795ec4ef7dc7f4e84ce1a4164bc768bb7222101e18318f4059dfa1bf435bf9e2d2a35b03e98a6846bf850dfeb93a9f7ec720837752d8189bde7dacbeda93796d15e8067c156450eb849a01178af6af49ee1f2d144bfc295bd9ca6ce7ba4d1a9ee1c3a24fd44c224b09f94eb9d567b4553a17afc7dce76c686a4381426647a4bbfc51453f9063ed5aafc5101b8081fac6a3af42f48950cf4afd98af23c938391b6879e6b5e71b4dedbd39e96c0e88910fa91c150eab9735f85b854ac563b23e8532de3d58c8449805499105760c6234cfee284a724c7d7a473a4b3edb8d106893d0aad8982bb64e9734eae38177a060f15ce4725f3d11413eb3ee9e300440a3764c355dd51db0124c22aaee2091a0784ccad8d4b335fa24bd21a965a1f090697e174c49c5a8a0e1797feee9547da0ca7a47e2d44349f3ad7a00563f4aed87ed299ff91610cf3f4a34882680f4186b5d8cf06c79f36232b62dbab5d6a72189e7730d1e95bc4cb2b1e3feeffea9b9553ce6381850acc04f610278a9372df8cee9c6f41919b0b947e4d6d92c7892dd46afd2a45891d5ff2dcc5168d66e2f391872987beb027939548f598c5a615a1e41827a142e618964321997ac645c484b375d1391c0b102ea60273a3bceea8f0792611891dd2d24719836f11dec9a55aeee67f21c29d", .Okay}, + {.Add, "e19ec0eacd34eb071e4f3252416bf4be1ec54b14c98611cdc18487dcf6e39920b55429db2590f6b11d2dadbb9073be68773f5718154febb00efb5a3ef33eb565c0fd3d678b225c633058a8b281bac4843c88e6c43c4ba7efbaa00a8002f5dcd6f747a6bbe172226edda63bdf7b9faea73a033522ed29f4c723f7ec2fbbd779d4a015d31801e126717afa6d77b61a5271da1850c8f139ca3c7067a854d14791d198fbc03b09a531269660deaa8eeb1c3ce41cb35452b9d7b5c1c42183c74be31237557d7f1ec65a8302012e9aebeaff4f9571abda93c20732f24c3064ea8001490877851ceb863dbec412aa6d856b2358a20f653f5be0119cff2937cb63721e99f0c85e4befe475e543cccfdd2903a02a9d9d6f3fd7bec2042e74c275b1f67382dc0e1e25ea845dcace9be3b85af47bba39b40449a3c6d62af4a0aff62b1a09a3110f5f297c0d22498c8c627c54a341251bde73640ccc82f15d72bf0aff35522b6cad294488392187168a60993757b631f3ac59c4fcce2cc69075ca839115108fb1bc972571d5b6b83389d53445fee6addadf19795ab311ca9c8c6ac9b87bbe472cfc4b9e9f4950c6309b38e19dff257e9dee7e596db0d9e91a886a2f130ebf165f221d468e228aa9cb44e2370e651f3fb1ea4c4d5d3620b8edf4c444215a537c08a2ee3b9dc400b4bca883b0370cf3c607fbae70d8e01e854a98f19c9d1bfd8968b0235f2b94649e9b5fb4f9c8662497f65bb130ec9acb67ac2264aebf29c28dab292ed62d84287d0b880fdc2f6b3f3332cbc7ed537f8a25b69e53bb74a4317acc76af21d239dec803a1464b70857062a05c062d4460e04663b0b3a74b632598975714ad3da572f2743eb7cb45368d377dcc8580c6fd8b8ebeaf3dddb3403372c8bb80e1e45bb01749153e7468601792e840d9b3bc6e36bc1731e5fb9507c629fe245a53bf47e0da68c59d8b146a60619f212e370ee427625d8e40b125b178254dd1d8da1a11cb26f0fcc9237eabb3ff552e32e5646ffc903db37b8a06839754e5d109545b5f5b3a4bc8d307b09504c3739d10d99e1ed9c4c928274dd38ae2d11800b7775781012b3505cd5a9228ccacb47b776518fc13cbc601cb480c9314968534af61b80bb6d5aeee04224441bd789faaf1f8a914283214f94cf838bec7b5f43c91af762e50d9719a3d204f234d434713f07f37511b3dff0f34384aa289f1642fa6b058b6349b46d5a227cb8c81fedb20e6649536ee3310a6b998e14d3e0ef5ff53df2b841809c772d666e1a317c3b5a451687a293bca5d00b5397ff6a33caac6656a473f5b2b5838445872943c1fdec5871ce53396cbd1b2965d59c3854a20f77766f9551b34d3759398b3ed76f81d2164cc29e2a522db895c33222d7e857a88a1cc56eac4830eb6fa90b0ca16d707c2bd40d9257fa9481c7b0e3b49bfc2692220969e3f02aaa9d18571fa95d491cc8402e719d9edf6c42fcd7b51b784da25cbbea291bcfe173588ec9a8cb4c2bf04a300198004450eac625a59d3ca4f34148213eae14b556a8578ecab53db6a11e36cf44a532d79d078abe19a4a66658d3f01d4c239a26441b70f0772fbc73e0650cc6f38835bd3fbeb19dbd97e1469599d26b351c2bba28f37bd03ae187be642d333552721a13dddc780d065eff095baea0d768b4b152de414831813358fc23b7661f96cfd08c6c9e228317c6af6d2208db79e8da4ee7db9d5c5eab8ee447c7c2fa30e82305658bd850336896a0f5066e33151627b596efb314ce493eaa63307affaabd42deb87420cd80f6aabefee440f2ec367cbb25e3ae540e62e1a5969ba16762c5e5133c0cc3830ca28cc2e30a74a97c27b233c5d0693eabf8a8f49180f5b363fda1fb4df0f62cacd5b36643d33ff1a8fce76c777ba5334eac291e33c45e6362c5d12ad3cbd3106af13c7d6712ea9f1966beffdd4e610bbfa9d39a06a68220e14be5af07a61451e237bc436e4a40065f97a5e7b477ec80680aa3019ac0f471d3aa034d7759d4a678201c026c11ef735fa3e2096234be282484d3dd641924cdc6daf106d9fed6e2c747e05791849a661d7aed0f20bfa57840073f1a1704981ee9cceb3cd48332828a1d1", "e722c2e1da8728449d18eff9e4408c56c93d9224001ff530940683f242350686cfb0195b3efa598ae5f936fe020b682b764a6a446423d952a6e64ef3c00f9601090e311a028fed557b6b46049909fce9903733d7565d21b2190e6b5b20ae972f5095aea9ad4b43ce904ca9f7b7d666b4a9897a54639a02fda11703a733360825d91fb727c0e045e407b3cc411d7b3443aa2a3a96cb205625423d681f78ac7001c839b46b0ff401a879df8c21380dbafaeb96d6ed82f470bec7540ac8f10d308f3b96de84e2c2172939dcba73ea237234586ad010422fd414894bb42be15d032480d9639e66a4ee720d4ab6074c68e8b4e995bf50f232670e30448fe6f61cca1ed342313d4e3fc2c138ad99a1328fb6944d93cf8cb62a4a4018b3c58103e0f869c4dc11abe8f4c95e0f2dda7688c590ba9c9273643fdaee8aa79577065ec74fd3e776c003f90851034e3fb9de99bb55b2720c4f0ecb30b3555a3ea1284c1c524c1a56bfa233c6386af416eda93315cddb2df8a800ea143276f6bfdce9c0770b1c62428d93e54cf991454ebd69f9fe89ded461afb0a9e79b9dcab748f79e05b0c87e3037b9122ca462af0576dbfb3d47d60233baba2ee2dab7df4a584f1f3247c3a7f31cbcb98e13f86519e17145cff3368ec1510c5e4343e47e9ad543f3c8af336c9fd19b1a56287bf9126e3fd378a99ab3d56cf373740a011e0a0fb7f71468a2ae82dbd4f4b7d48d3952c9c68157e0adeedcdcf43953a4a5b424ddc83eb794a77c4cec8f37fcf140c84ef917e875b83a64148c7903166afc8e24b02d8d6c8181a695c15e0bcbca03e7ab11473a5631f1396f57a47c14b3efaf3b06c4a05573c29c063dd143b73741bc92ce2e2b6585e916be9727cdf0f0075d4453f12e92bdec75429debe118ba2c7418c30935ddfbdebaa8439884763613820d75229e62a8efc331e684cf00f83e5affdd39b5cac5d813d7fc38658c14828f11d9c760b30189410f5e52bbf8b1eb6ddb712718554c596986abc3faebe817a80dc853633c15ef40d34eaecad0338e98e33ee2ecd1deecf98c4685edf6535dae91a35fe803c52475c6648fe7b9878c36d0eaa1e82a893c1a5f7c087ea04bd9e3ae7cc9a28985170d1b9369ca6b3c3c19afa9d95ff17981592591c1a75e7dbd1885ae555987084ea5f6d5391a1d73f143562d007b6ff086abcb8d0e6671fd7d90fc71005513d78f107a2fa2d699bd2e81f97cf7ee40cf45b36f47de29924ec7d65e0d86de32745b028f7981c6fedef24988f5f1057581ab00fb52ff83aa3aa619137c51b34e919c06ed0b84b34dac1d17d6dcd656a5845cc54cf4510d715dea48e2bedb4a2a043718b58965e1a0aae10b3168998308c9680fa87d4da578ef186bd325e8433fdc775aafdbd7b2b4b5b27eb1373e9427814a3e850b2fb15113fe4f2a9f8a991eb97c4f9c92534a7d062978ba243e7dc9fc7493f89b15db36b0c4d6fa3f81fab2b4e9390427f7e07ff5f3251b5f27505b43eb1045cfc712b74a3c9f2b2fea8b6a17c95d2ec82c716e14b64ec3c799b2efcc6f4e019ef86698094fd7d47e1a0696a752214004abca9343c66247c2d073ebee60167a5ba560fa4ebce099abf85d1658324a628fce5134bebbb6abe1a208cc26784ea78b1cf8268f6cf703fc1ed344f8658aa2e80ba3666b44312f16c07966d0889c48f7589c50880e62d5cc0425382d8c3d83ddd7122f44d5e2c5791cd385eb70c4b01e8f2ef0f6229a6042a73363499435c6c2a3c2ca0b7d3c62993d6729ee145fd5d42fd1d8b040811a8657260da18836563ae04a299fe073ec7d78f84ad52aea88e5be3c59f865564d37c22b4dd0f72325e9fa18bd1e4284572300100b9da41d9de0e32aa94852c23151b529bef753361d3f5688957e751ca9bd450e00ecd158e337ce2dfc84b6768dad06f48b10b8b013021d2a66274f54fd803d833b7a130acfdb979f0f9bdc129133e689a16d7e6601023ca2b80a9d98d72aa6350e62caf27d91df526cf4939bad466125a552cbed6d06d152bf4bea0ecb92b0013c7b5f6b1d42dfd5c97683d12b117446fc00fd5f24952576af3bc82ab440a403bd28513ac2ac3f47ebe3d327871fec", "1c8c183cca7bc134bbb68224c25ac8114e802dd38c9a606fe558b0bcf39189fa785044336648b503c0326e4b9927f2693ed89c15c7973c502b5e1a932b34e4b66ca0b6e818db249b8abc3eeb71ac4c16dccc01a9b92a8c9a1d3ae75db23a4740647dd55658ebd663d6df2e5d73376155be38caf7750c3f7c4c50eefd6ef0d81fa79358a3fc2c16c5582ae39b8d39586b584428b5fbc5a2061b2a5107449f401d3613574a6199932cf10406acbc6f8d737cfb38a41d5ae487489182c4cb85913a172ec5c04018871ac3bdde90ed60e7183eddc7bead5f1db477b97e490cbdd046d8950e8bb522b2c30d15d6074d1d40c0d8ba524904e1278ab2f6dc7b2598ee8b8c40a8f893e2438a67c7a697e5b9356beeb313ecc8de90c44472887f6b5d76beca0ea2fd1d3792728ddc9be2ee3ba0c74d64677ade3a1c4b59c3626fc89e15976f8861f2d7515734cdacc1c5aee5e96d78deac272d7fd3646b7b160334b51a4778703e8e6bbff59f20aa14e426a6d840d21a501c5e6e25f3d8735a76d518c1bac13ff24b95722b04978d8929e3ffd708caf40c92a049aad686743b3c156816f0fab2c8357b175f528dfa0afbd993c6d54a02239139c93b4a0f9d2c27e324106da07153a0347b09ea2305ec3a85435127640ab9d59bb79649d6c8f9988152302af7542bfd6b81a2930b5baf1f00a859d60bbd11b644c54288668a301549430662c1732ff34204c392bd4b27ec049be0545e5388e2525ee700d60474276fde1573527761b65658119bdd3d708f417e0f76d96e054665695f52244c303e90210b2fc730c707fde05a8cbeb4c5792aadba253d9cb5dd1c075943612ebba6bebb8995b335d527e815caa3430d185f9709c1320948b1ca894ee7b961bf391cee1d2f15f3dfe1ecdc5746a43bd2e017d9e3e1371a2e91d4c40e46ccf993f5b1e336a6f19c15640d88e48d918c3c57ac4ca352639b2f92a6f74703be4eca01a78866479ae8ee1372cd60a7d125ed83a4a97010058beb4dea95f5be4a7e5c143dd69bfad4426a45803262f8ec8e4ac11ea9d66e3b06d29575f8c152d2277b9caadbb8ea7f58dc71c073f3a88b76bd6b7fc7a5355e8cedaf36d979c5fa5a9b04811af1c99ad925042cb8276f311c89dadfba43336f9f8d083ba5072a5ef2d7efb4d9245d0049a3366e8904bc4cab4f06a20ca933dc9f2df7d8d9dc318bb900ba5389fb6618074a9d6532f4ff1c9c8cf1f1fb9cd51448e902e42bec93cfae704c71fbf7fb269f88ecd60f282f6fc10fbcc57e718996eb69fa467fdd376707614318b334534d8b1b370eefa8d0748700f212ec939c07ca4127b6df2a4f4b61a955538a3ed898139ad00ccdaf5c615dea6fc3236f640602cc9e219cf5b943b475c821b656d5afcd5387da4099f7a358d6831cf44f198214647c8708a7693a797471a98d468793eb8beb2e9e8bc08d4228ba9b0785fd106607c9dfcf5109ebb9b2a0cfd4c6a39c35ecfe69a723cf40a5aa44bc1dd1006aa14e8cfe092bb8f4b4b8d8a445f3466fd71b0dc1752b96a20d43cb44506cb3681316e9342b9c5832050805fb450fd0cdf6041d96e0435a8081956ca436fb32c666746cadde45622b8cbb387d1db2ac18be789432013f0614aee68e55021480cbb21dae04419c7cd4abe84cc84c3358e2074b05e96ee7b992845b22ed3aef692c412aaf0c599594ed844fdfd80902effaccb3b7c64b71dc28fb88b63d5c1ca67ecf4532d115f474ee01f6379309d7299fb18f814063e237a786daf7dd151d0211c0fd08003ffc437828df295c1d1fd8fcc4584fe4815dbfe1b592d63a712a43ee500ff121c8d8db9318e7e01eaf77c019e6dbdac753bf97b491841e28a9f54b5b378d420bd4a5e276224fc1f10602334873537cf24ff5cf62f6fdea8079fe429173f19642b40a9c173a7945c1abc6181e75a0498891a63fc3565b97adabcdbe47b2cddf055fa00163d57af57624dd852226666fbb70133521c60ddab5065280eda399acc7f87446a30e614c862e5cc13eae4a3010f73556f35f14ddafd3f12bcf1b7f9b08ee63716713f5785f24c75194705866cd447a147c282384117f55e989abcb1490dfbb92c064fafc1bd", .Okay}, + {.Add, "-1423aacf9a323ea6d5119adefa0dea57bd6c12c3c9b145cf959aba3cb92666e8f0756be9ace927bb154456b13ab93e341ec032be46962c295aa4db3acc86f48ed94ce1d6cfc5d2061cff1541b4b49ed8442b22f4367d7a064c183c99ccef361a0a4e02d96b0ff3909d47f1c5c7e14b18c569417cf3b275a0c9f39371c1556f39ab91ce767897b0b70c7b5599cbe76611c544bae9a529b1268aba6d2f03cd114c96c59caf19e965ba5696e055a5b3f07a8c0824bf1009ba10a4b973f523ab93f50844c0e4673606a7e0fc871bbcc06f2b20f739db201cdd391646ee13369b59ebf079a0011eee8f6e79093f6611a5c49650d0f2014700e80324a78ec28c21ea0b090c34c885b4a555727f9d08dd85d69e5cfdff338364e6dc2b64739d98d161dcd4658f61baa7d3d3d51a34f7708f37eefca851f2f825cc2945c31be8b34c209e61c0df25c3e5e0f47397541f22afbc7d678882fbe12d647ffbc8e7f68c54668ab3c7f8c549a56632ab15927ee226d7f1dbc388fa6822e18b5bcfc4cff8377304c4824ce3ae0079d159fa5be1b4073a8d3a329483aa7b358ed00fce725750154d14b4f310a9f1ac4ec8b3f3b349235d1e40d28347522938fe719d5f95321ae01313ecf9a89d21f784806ddee31fcdf21040f6421cde98107bbc1b3ce9bd6ccff7f71d6bf7a83c5ddb76aaf921df83c88e50a330827cd371de5d93c7a01ab0c819f629a05bfac88a34a9c3b39b99b93fa6c45319abfaf24fbfc672f6e7e3f2007c9c5c374f87632f8f03a949431dc74dd1025cf2d79957a5915a516679c229db19188b89a5515f8fa6447321b5494f1473c95a08ce7009a2859d34888a6bb84e7f577601f80c506ab19ae57f3897a3d2f7ca7b285d0f137057802eed02e6cc6298f1047a82604ebe68f40867578e2930a43278e8ce7c18867364286de41a8f0e51b9a976fc7ec9f6715228936b1c39430af0eb09c568f0fc14b0171a182f9fd3bb009e64b746e453095168cadbfa62fffe25483e44ce052f1952e311184788c58e6ba7540fda43fe4fc68616723d21f9966991492f1b47ecde29c2f4ed90c27bf9a041f7841b716d4179c108c26b58695499280d5d7bc1f0ca7985c06693f6b0fb31dfbb8aa5d0b34cb2a028b5c36ff534abdf4f3a4e6e5093db00efca16af85fc7c46818fb7e764c8097cd1ed4bb779297e84a6d27c9e6ac6a0c727a222dfec4d07bcc9c4caee5573186b77c41bedc2a6ab0a425c7af28dff894d0f606d86bc0e58109cbb6040419b64e5e91819248f8075e8c30d0541cf90ce20f691268cd5e4762ec2f6d2bee6c399f33bc57ea3b1ede7a18815182afe26b4b3f400353233f575e4183cd1431013a8572905d7cc88dcf21d9f8c41ec4376b766ff552a15f081459d9a0c5b89e3140b107b0f7ab4dce483a905daa4550e5be25117011147f2199ed06a419503026fdf58fa2f3afa7183c4f28beece1a795b8dff2ebf6b7f16273172cf034744d5d0b22b6a4dc26ae9effe54e69956ea0a9fbd16fc5f66e9568a1a5dd3da4d79902bde05ae741a71f517b8043b10e1c6261d600c6bd00dfd64a8046b5b78dce0036b5a9da99c8d606fecde1d9111f8597c64b1bbf6bb9b5b690d5934c5b307a4b9a81e00c0ce727f54666dff228dbd8cef6e0ab21a0146eda92afefa1293619b45097a823b9f94a1f3f1aa803bc4d4b5e87dd3329afc5c381390f9ef61421ca66a5f874a717a0a001c72b995011244a1c94b17b8b0683289211142a0e8072fc99cfe5d4847eeeab51fbc2b23e05e18ec891591db721fc8d1330855b4515dde32d42def2814673228aacee99ddc313c0bdcd715e135943a036ab611b33480048108d15a6a80b8089fc23532696d205b38a211a06f381b1060fa8c84507ce4263c77925cf1f65051b81676878a76180676e7a871ae1aca36bac20502efe4b2a6250535dbf99dd41acd26bbf3295f19fee11df6a65478a707f9d483ef4f55869d1406a24b6f041439653968b1fb8d2c66b4c33debfd9fe17e85e9742483459f8507a428f835493401816eb4074bc257e2de824d329e748ef57ca6429497e88af7bcb9af8b1d7f38376c51dd49d3312027f3b22e508a5ea5", "6f9f1968f5048d6cd39150484781ddabc03d90cfa56ad3c059e159bb1894e11b1c05d0d69447fda97516165e14fef714b422d1b777e3bd0684c0c462e6d7cdfee2cc3c9b4145f91094c38de87f9fd92e13248f44d32e7c818061179e72853874cd3dce402d103b37a8753007aec6b7df8d6f56d611206f1a361e5a2571563ff0b9ad810341960492d358337f7ce155651cd416cb4239f24953777f39a9a2c77f3fd9de195e2493bb7b3a3c5bc2b9eb55ccc1f5fcc27cc2f3a32bfe03ec51bdeb261a61a2e2ceee1dac95526d0cbce9dbe475742ed2e3076b20ecdcb46d8e9cf57feb0559cb8a327ed4482a4d43384400d6153278c73d0b4a704e4c7db4dc197127a9718fc5449522b7c82029f26ad077547c6a685cc31c4fda785d46d4b00d5ce34d4345c2a99d20d01f6e29cc4d20fc5b6e5d34ae6fb7603685451a353e579f0e9ac14758f1b8d2d036271eb21e4b32d85bcbbe10685c712886d6504ea600d242de87a5d4bab7f66793534ba75ecfeac69aee229db8989ad31a3deb9338acd998545d93897deba609f9a5d12a2a619f478153c9ad9243099e0236c00be05ecb8050a62797b8f1b3611425264c89e2f13930bd858636262a94dce91672cc76d7d4d1f74df657a1e69a66ca8da4621fca5ba15a174a7c11c36171755c7e7b15561cfed79a29cd075551614140da66059f3c2fc7f47b96aef3171f0575c6b3141c211ff77443ee1eca818f4f4ddb9ad1c1a62f63e58513098e6c8c4d827579663815ac576ff27d29034effed522be61a7376d495b4a808079835d43ef285f36b53620352048800059ecfd250fa9399d3670e66091f065354eb2a57a3bf66422bf64f0b0dea1ed264e87e874f45109f09d9d52c0ab32278cb4c923a430375b4f7357a351a97bb7bdff53fbe034e393b5e0ae9d7234e10054c1940dd8c7723b2fe1b11ac5ad7b1f3d1e2ee4bf1e005839f66d2db24fc88533c785591f7f6e3fab06849aecc2c4da4e6a1615c55a7a4eab31a171fb0885d44a229c72234e9726a82690dd01cae03415c1c588ea423b92c544d290ab2b89805457e5ca4b813f3a2c942046e1e118f1014752da9bf9b699b740eae73d96a319267b4b71829a357e1841fb5845dc58b8143a9b47c23e08364ff7877312285d8719a5d61db03ee3ba2991f6e4e21515f8625273d42a2921f0f8380d9811f24cac6947f4f1cfe16654f6df03442ad3427acf0220c938fb5b687581d123b594f4aeb614707dcb4e2e234c6472f147dd7ae328ac55999ccf91cfc3a2fbec8d7b4e1d98533805e616b24b4d10b13b0a8810087c6786312cf1538813d2a27edbb076d92f4046bd1bdab611985b547b981de734f3d925a6e21328fa05d3c76bb3cfc289fa576bf29d2d0a1ff36c5c91181961ff599408497f3a8ee4706445a089d68c80e48c52a0cdc3342d4ba86939e820ad905e84e01d642c9f508cfe0d8ebfc86c092500b9a25b471da2cddef16796f24665b9358d1a81d1e2b379375ad1a9b4869a85279bf710e08adf37b27894a9037b80994e3bca8eac7da91c8ffa97bc40f08fc28e5bc696b23e54b13437891e98be3bc34ccf8590abfa536380b59abc9370610ea5bed747b073c623b0617d4a39f4409e612d1e842c1e0a7a8e4dc117ae83c039d24be51636a7aed261c9e13c7f7f0450f9904d661be0c8dfbe46d50348d3fde84a3ce992a9797e02fbabea3d97e0d76c4c94d50202744f22d5d16ba884740a05fc6402dd7c0e14cceaa22fa45433e4b23a4e5d33812d7a6abd0ca473693d712e031d5984814c0e8500b5fcae2edf684ae87162e3923ccee29f3097481e41b9106e2848fb7ecd10a73af0d89a15e4f1fce29c12083b140bdefd28125e690b234ae27c4bd5b6763dec1a1605af3a45889fa876ce1dac5eeff4ad2458b7c54feaff791c7f87e52cf28ce8940d239b2f3463e9424e880c95a6da60ddc9530e6a7e47336f7a53c4085fbc7c0e03a49329ad7fd14bb91d4cbcf31ddb7548fa9c429ce95684731245fb4dba91579373c1783aa2b01893516318bd732dd195518b00c0d57c269555826a37ce4aaf604f53df0e7bfb07a33313a587c3f79aaf309d0e4776469e7d54666", "5b7b6e995ad24ec5fe7fb5694d73f35402d17e0bdbb98df0c4469f7e5f6e7a322b9064ece75ed5ee5fd1bfacda45b8e095629ef9314d90dd2a1be9281a50d970097f5ac47180270a77c478a6caeb3a55cef96c509cb1027b3448db04a596025ac2efcb66c20047a70b2d3e41e6e56cc6c80615591d6df9796c2ac6b3b000d0b70e1bb28cc8fe53dbc6dcdde5b0f9ef53578f5be19d104122c8bd120aa5d5b632a914416a443b2e0124a35c061d05fadb40b9d13db27308e2fe728a0ec8a629f61dd5a0be7b98e775cb98cb514ffc7ab0c37e3a53b2c62a320aa5eea136f343098f716558ac9ba3105b3eeae731927f6a85444077803c23474ba6bdbb28ba2f661e9d3cc73f8fefcd4548832114e4f9d8f77e6b34d95e3573af13e9a93bdeab800ee7b3e40801c94cfb0539325bbde90d5ec60b41b649eb36f0c2293181f23700acd9e221950bd7de5c9ed2ff8f6e8eb570d348c22f3af7f12cbdee59c2519a478f168ee08b1551c3bc7dc0ccc537f7f8ead765283595b70f774a791b9b0139d4d3d210afdb7d71d4afff49ef762327120d4ebf4603170d7acdf2684db490497e6b9bb316edc7456498603173036685d2f85e3a3e340ced2c233f898140b196c4c0e4fda55935aa6219f8ebaa84942dba1aab17fa6be40147a5563872c10e455e25e16ba28190a979dab6481efae23d10eb8c9771fec33d14b98b3dd5ac024c022af6571849259495d7cb9bb241e1921ae1dc4a398a20b9cea619569a918765bb795020206b19f9744b56a40f0e1ecca27477a2dd0eb06206db82d878c3c9903a4977c85f36a075f88b5f2f454a4abef3450c00509649b2658d231b34fa89dd76f7950bf21281fa36e3a1d00c78fb36e20ab0e25613655af5120b56008ee8949c8930a0155b2d218c4bb59bf6ab122d66b75e3a7f93ecc5a5dcb51e930923efc95802e3db3329db719c235e74e94a5c5be1f01b371f624063a57adddeb45adcad4910677506c093980ff38acbaa87b31bf1d772438f3f7310743f23d12ae1bcdaa228c89e28fd5dcc92088db17c0a5ab6bf7969897cbd58a032e1c32662e04d48642c268d739ea733b3e8b6d8fe430aba154bcc0cb5d076ea3d92693cc3ead32483a4a23ae5b0905d01dbfb2abff50a43cb51d34b8a0349c986da142424f31322f2079fc1a79ec05f33c5d0a4d3580a575afc78524e2829b8ae55d674426f81a32c85e36f5cbe9aaef42817f19a999576673116f2cff8d3477e8fa58274ae0a38d703e11c4df24929f4b3e3e103d7aaaf48e014a7dc97b5a2b23d6ad9fe27fb269d81e58a2dc8dfb4c91f934fb9dd8b3c404c32f25567f5ddb71dc9ab2be751bfd1d569a1a20c2d7eb216f82cb7d3d45f849d9d6fe6b3620007c2d37b77e946448373e789c46bb62c798778997392295fd65f978e23b93a6947bbc532318cc86cf4ce17c94402e5de227d489aba0e5e5d13f97097f277d6b00c2685b26eadc7c7e506a0211f16bd881f7cb2d068cca985aec5b4af12be47da025a11a9470a249d6eecbc5d6a9004b7dea33c53c01fd3e7f17788fe273602c85c5cff53d74dae9b74268e1306dc31619dbb612317d5c81e7b8e38250db76df73bb8844ba106d1f8be9fddec3c652c6ab3e781f36e28547e6e12585a7e76adb6b39f496933ff7cf19f19b5648ea9ca8f8a54261e77ec07f2c2cff8c86b289c25fb668f9b3ba81c29c4b4783bf0d05a69c605aead3af210ea5d258734fbfe967b28752758aec3ad98e0595d3c0e8186a6888af023ecf18c149f235635be26571c43bcd5f4f8171d030a1691901851da59270624bc9ac57f241fd6a5b2df852a0b6eae8258970708f8fbd66cde4a9ec55866b602f9381e2d9d4ebc797056fc0c16244e234c537dc714dc0a76c0324d82f50fefe4759d47345bbe01063cf8390fe9564a6388986e0c843de255004d21395e48eee2f53fa07f51e96bd1cca90355405150c3997e01f33cf0eaf3abfdc3f6727022d0b795cca44ea2941c97c319d22a5b33847e3655bfa154b3f677fea286d890ffccfd8a55c42912095658292ed57536b6e397ae003e68616d0cb2f92b0600ef15b202210fed9c611fd8b0bc83b23b974ae7c1", .Okay}, + {.Add, "4dc3d5f0c42c0bf0e256c8dad6847ab0cf725110a14bbb492d8f7919087d86a5732c58e817028d02e30c52112225c380742001674dcc2a0d8136844644cfcc5b32f5e5761abcaf04c1dc1b9fa8fc44801a391a870cba65e6abbdcdd9f89b2a9f52329b5572ee8e66a7259709ee4c89ae70a088d81524e312771570d1e22ddc5ee61a9f260f603bcac066e4fde30d16a8cee7d4934f0b1901a1fb3c821e2e6fd25e684ffa5a97bcf69a83fc875efe92d99382433719b84fe535a7c5eaa3c1a943a75ce4748ceba76b3b4d7bff3113154f1e821cb2603cabc1739bf4754195b3f07ca4e2bd45aa5037ab7d1f68e3c9cb4fdcf69a1d26abefe27acc583be3ea115320d3067f80af37f4765eb290a4aa27d0b5dabbc4dd1cb067e73572d6aaba01f6ea0d3ca0538e50da893e98cb2f0d8156b873d4469391193891306173a899939b9961a945720f8cb8010fc82552d9af12829f1de2039ca2932565497ce3d6410810f2cea38b98b429a2281469261c1acffd9e171410ab6740687b06c80fdc222c698d3bc53c54e4dd50e350d64a65ae35a4829bf394b2930eda87cd50584ce6df445402b1b5b8f59b0cbbacece5ffbc047a92951dfb0423c7ec037ed44f3ccccaf99397873ea0e2ca804b18de9c30f80bc9e5b44fd9941509dbf6cc3f3c6d2833fef2ac7d10a469fbec886e8beb1cb6824ccc28e959fb1059360ba471b3c875eb45e8c2b38eed6d362d8eb18e217c914b07be85dbf0e572180085edfc19c8a9e22bddd78a00cf7969fac9ddac300b9c9bd0cc596b8bebd5b4a0b07d17c17a1dae70ceb10a3911adeaf7ac7d7702cee65998f247a738b412bb78c336cdc681585265de4709fef3a82252de5bda3a64914cc1f70d179ea4181245fa12a530e35a83503a41ee1b3d951230e8f2a4576db08dc4f30381559ab8c92361e40ecbcb82e7275f12fec21da45ca387df86ea27bcf7a6d881fe45b92d1fe025bcd9167db28a5dee14718c13cc9b808c990e02d26565a137111efe3d69c2251cf350466dd78c47c65c8a2ca53cff364d9f49fd291b7e169e31c8df6061aa93a3aeca4a230bf8b80bb33abd81cc29df92d346c890f2f01e189fb39c2812576e02cbce228ca22cf532c8ee88f7ced8fc08d32670c3ed4e463e1d8abbcaebc9488a63a4eb16470cea43ee8f83ad9afcfea482fe3d4255bc1def00ec9cfe3424d16d959848cbaf21aa4895c51ce5dbe709cafccd5d960c6bd5090071cf97bbf55a4ef7f613e397ca2647519dc5834783f8e096287901ee3879ae97151616459740492e3fe7b45a5948cdd7f4ff28c17e361b1639592b8722f7bb9e72e4fb9e7cc775702a3f5ed3ad4958f8ec10bdb68c2636e0e7d19963c75ed7c51b1738eb6a5bf841c8762349d66ab6d562058963516f8fa12f9ed65dd177d187ba2631d2a91bd98f6ba50546254cf4d833e603d4197c31c654da73ae516dbfda9c526ce8c982cae60efed1370ce72691f14cb809369f22f97aa042c15fe0b7d85b2c61b7fd5486db8e260b8621cad5129d8556655c0cc3b5d33f9ec388f787fa2b29dae00fc9aa8525c63d4da1fb00c2c52dabfedcb01c521a3a15dcb52009a51c3510859e02e4ba5c52f8b60c534cff88ae83241f76ccb8b134aaaa010539920d09095695feb0b28d0f08278e83de92ff1d704ed6b8ceb0f0e16a4d98cb8ae041099ef5c1138b2c6f6069bf2c60a1b12af90c65f6f50fc3ced77613fc1560a7ff665abb351e4e07c2685b6809fdf618d850188ad24b05e590c6a6f0dd18b66df156ae0b3e729c56b868a49b37d124fbe5c709a6e93096e7696f59d2815e4ae4860f6e0cc60a33938f3a0a8cf07e7dc9b95f82001c263380eb4a1391f50b9355f49270f30b28d14d525f44f6e689b20e80760b9bde35f8ff212f6ba7b017087c3a02621e182d7365a1af94d8326fe4585cd89686952666909ad6dc861344c9e50b7d8aa03339c825cb8ec2a3766099f9f08e220e3fbe55fa1168f1ec980d37f1067d0139b2e0775073ac30116a25d0f53e51acb9e0cb1574662da182e274a5a230eb40419ec06c994d4c7ff6b68de89b3e0628ec88f5ae578f37868c69d808a463a607eb4b49586705", "db97aded0818db256b25834157448445396d5c2729954730dadae36e0cb3917bfe68d079cef64dd1d7a8f88161e2cf64bc8ce1d1ddc58acb8ce32e9bcdff27e091c4c56d57a86064dcbac111fdb813d35e75314a3df474e45574845c5848949f9ef44fbeb342ea999ca806bf76c4924c31f1954b8663fb23747cca85f7d8058f8f2618e270904d91692ab9f3cd104b94cf39f448c878fc3ec6564d7c7d904e672b8bff2a3137f87058e7b4803e29061e59967cea0fcd9ecb1509331fbed14f8d0b67a393c9d61469b9f5c3de5cea243185822a1c362bad487ffe1d32dc4de23134fc28eddd66ce811477019e9209b287f47f800c3d3fe0d3bfc65822f1cc325f00dd9c909a4dde3d418c64a40d44f9de32179be7b94d98f4a6c29d5a0072d715680001ca3536d859fefa6f1d16c18da68b3a2a98da6203be2147bc9e5887e3b61f208ccabea9946d351f419327687fe6de5baa5da7214aa4026ce468216d16426d8a8ad19f60c1cf6f6429eee42cc8753e323124797349b898f0be1bc5476b1f08c8fa412517ceeb1e2a7a5fbdcbba13c2a528c898acf81ea11c56389f20c4da3ca0b9fe489c3f50a0692e56386a19f33903cbde8078906e2bc4b8e106c25fb7a0b3014e7ae1b5af6b06f9a637c7dada56fb1302d4cf804e171315ef9654055487bc0470ee19bafbde0af24e112e4e1a0853a267a72c888a6843604f09668e781a343e70055b08c84122350300e723b0fbab08f073871592e75ba0da5189bc21a3174c6b5f566b8b7cbcc4da0eebbe9d4bbf2f8451c36a9142629f919ef82fd4eec435c731f95a4dcf1590ce6eae4ba4989c0d499196e00809b4b2d6f6fc446baf7bbb55e3aa6a96858fbfc3a07e6d08245f4ec02d96f298f1768df5f907f64ba6aef511390f035335f1fe819ef803a286cf238cf9d529051c6569be3c9ad96b0522ebd4cc02806ad7763be7edf8374cd5b07e3e997d007b11304dd71e640f71c304fa23097b1477a4b453b24d89c89210f344c67d3f201c0f0adab3cd85c68bd080a8d229eff33abd8169f4e2b94df0c56d1e95fa59874b1c5e3bd13bac78cec1604a55d415b3a3850e5de2ee1a3fd12b7eea7be535613edf2030cf9c29fd80d02ccc4ac74f86300d4601803d90ad517d85bac02b6b8612797e0d61aa22bea70304a2c486c20db0ed6afbff3e8df87a78cf851d710e1a4ddec227accac047decfa00dca59149104f032609eb1e3274d35785c6e743dec953547aef8a26b2e886a6862daf7d90e81be941775c82b7bd7a45f082a282c4ef9735a3e927552b0423e887ff9a5eff6d5cc99a7098da67c36bccb8efc5300c7e86fd620f02e5a3c168b9e50ecfca089e9615d26728e47831d0de651a3ad6b451c093ad491655d2b3709d03bffc9f9aa59a99d6c520e873a0cf2b5083449deeefb225ec55faa3a6f1e56c7be2e20273b79e4e0fa37b567c46c09db9bd363e91010403bd82ffc824756dbd2b255aebf4027a9e4c9c0b8ea63414acc39b92359adff493ba76b35719ba3840d5ec287fb6807adee7fd6e6fc59b31cada1fac6a4a500fa023dac8ece07d3c8139534d6b90350fbe9f07d692cb7710beb6ff0faceef063321d648438202e18ab53bc6bf49b9193e4d3aec0ca31f29b6b0ca1ce1244859f607df79f8b50b48f0e02e05f346ebde684e6b8678273ed7483815d17c7e96d36c98297a75de02a7bf666603346fd10d5ee4090e8ce6703d5ed88cbc8e1b26757729ae9710900b0c52ece32cc5aa4fa7ca9e137e375ded3b57c7d934fe87396438c416c8eed8aae5ae8b18cd4b8f1d34809714418022dac0d10c31323fc6af40de0ddb91d2dbda6ac6c773111bc04b099442d27013ccbba6ec788fe2e02c9d4d484a32d84e730f7f97b01cc55e7c1388c63eeaa861dad8bd9faa78c147eefa8bcda2ebd4262d90c65109ef9cf8fb951e5f4c3d9311694b959b1dbd0c2d22411180c11642b8f0f2d208a54344b2cac8db0dcc56f48babece12d62f66ee9670e4e5b9a88225780159497d2992c69d323e954b50eba01aa7f4b610b7717effa90935e23e56260200ca8b91bcd8e1d10427cc5d2d703a37dc4ac4cba32a8ba4d49c80097497b", "1295b83ddcc44e7164d7c4c1c2dc8fef608dfad37cae1027a086a5c871531182171952961e5f8dad4bab54a92840892e530ace3392b91b4d90e19b2e212cef43bc4baaae372650f699e96dcb1a6b4585378ae4bd14aaedacb0132523650e3bf3ef126eb142631790043cd9dc965111bfaa2921e239b88de35eb923b57da05e1ee7540b8087ff0895c29919ef1b01d623d9e21c8dc17841540685189fe9bbebe3989f44f248bcfb566f36bb1079d2798f7ed18c0212985eeb04ab0f90a6292f8d0b2c4880856c1bbd4f5433fdd8dfd3980a40446ce96685909f39a11a81de39621b1a10bab23111eb8bff4210775d37dd7d1761a2963ebd0b63a92b05ed5b643b221b0a3101afd1631b7eb1734b1ef21aee7f257ac966a495c8df81030ab2cd90c520d3e6a88c52934883907e845cf0efd43adfedf6df31cf6b2781e1201217751b882361030b92125362f09b87a422ef960fac83faabded3727d22de50543574a7e7d59752af975f9118c3e580a48e3453bd048388a1eb0f9016bc4e3d5238d4b72563606616cb3c86f0dcb36083168496727c4bc2d5f8b2d7ba42388f76dabb980f4bcaffe5534ebad24db431e69d5f7b39660fc7b7cb43617c837b555ff2c829a4698d5b9829879eb521284d3f8d2e620e0c752ae639557f309e22ed2c12d8886aeb0edfebe24f7ca9360d9fc4b049c551fcb51012798e39e4f04c0bd2f0463601d0123944875fe6eb0e6912263b4fc03698ecc646c87aae7e18ed66b526603cef523f56025e4f57786a2863ef75b391c8b88efddaf4045e3131ca960724d835f92e6d16b0b0838c6c20e45717d31fe318e54f0ca4af2c38277e9a4bd7d9cbe155a025fe29e12b8d86e1b9ddae2fe54e6565bd7cc3b0aab3770a09b29eb50cef6e936ff544c986566daf125f665b4304bc2270e4f6fe1ce3fc74dcd08665c522c81fed38e2024c77afe1b6ed81ff4447c89003cdf362d9af1560ab034e1c1fc20f30e94958ee1132540ecc0505c2df7b22a55e57b7c89de3427ce0413f39e181847055c56953039f3cf093edfe2696edc0b505ed9b9e8f5b001ea9b85cf84c7796bfd9091977fcd64a13129b6ab32c149978a2f815d73964d22fc9dbeb69fadc55f953950475509094ed4a6ae549a9fc3c3d84ae73671dbc2087106953905b3ed4891540a6fa8adec0f7efd7bd04e3696be860a0e0c4e72b02fbd45138bf70079e8a38f75fa6cebf9fd5d6c0f7933b90a815ce043d5a88a8f96a6eeb64ec65290afb478bd5c5605b774ad9e412d6a101e0d9f3f3e429490b3a36cd25d070a9b875657eea518b85402b4bd42e6d20359b4872d6f37fc6665374b911a6db90fc3d4f749d90d5e40758794075a5fe0e6e46cbe16bec4a4308665331659db80750d74871161cf830dab192d0d81ad5d97de6a868fee7010c1a43e3854cb4f3fb543a3bc9662062b0f936112c08c8fdb72bd779b766fb655f8d9c306be3efb537e63c2f94446fb77495e4907c33b592d24a12b8412144fbb65fc9dc282f95b7d21c54ee271600d51cd63bab235aa269b1d3c14359c25f07f8510c3acc2d2550b5575c31457fa0465022dac064297a34294262bf5150d2fdf74a4360690a4967ab8edde023b4f6dccdd38b519f39d414dc92abbea5c29ea2d9eeff4b8920707bd32d774bec10510b73ab5211d1c7759918c7013c2f612861d8c94802355e9d647c1d42008172e2d7c370453f3ccdd645c8439743934bbf475e1aa9577b65978eb731650e2fc0515c2da7a15a3f90efe04de18707e4726553544a2ab606d81577d461d7fb014b31298c41db12dfbaaef7cad422f5715b84f34bc06e8416f210ce6675b45453cca7b424b25ba76535b5de04d9bf80be5d7729d9058711b802aadb8066621622b45d487af66fc37e9c99146806db6b2f4fb4a5118a3fb165175d5c268f8c0ee47f9d1921bb385b2ce2de845d1a8dfe7a217aaace144ba893c0e47b39648693f3d3540ecd71acc225105f49dd9793a9ae775666848013c11d89603b026febda38e6abb7fddca1fca83202f4c022dd5b11948db3ad2321e907eafaca0035f470468cc23392f05bb812e92db04511624c2d70c6055351349efb080", .Okay}, + {.Add, "840fd3cfb954636595d6c50c1d2912849de62a8b57cbab69e299e7874f39051fc25cffd707355e3f5f9460586def397a8fa9f2a9630f511bd47052ac63e3845d18d5a5bd4dbdb68cffd06174d02e060887053565d1e5233da7255da9939c6c8e57f898aece48914d911ae1e8a8b4e48fbae890430747ec881b1edba4742806a0aa4ece6c263f5b1ab5c80497ea6f04f26ac916ee4b8fd6cf45534d29419be5229b9000566485fb7e0942a71bb3d5ac8911df3629c872bdcf8d66b2cd1b31f5c95b93e8ad8295b5379a9e7967a9ba9f9ccb6a84f6df04c3e23e62bfa5a31368780297bee800e8aaf1f5392adbb03c2380a8dc423d589001905926da1906173744aa9ea76b2455d4812d466dfe922b81103d38d0b4d5cd78366c7d4fb7bde11a2397d91b82b2485518874076ecbd638f0784a20e617589efe9b3549e842e8022acbcb562b6a13663df59db0ed40ea2a0c44ba1621face78ed28994fe2aad8b1024d97a77c6633e634a48bb06c1525d453255105cde08a1716aa9ed878a76d0d3cff961051884a496c006b8c72314749f527e1ed3199734476a3c2c3c0cef1cfdd26a48ee1143764f661df42c0575449ab568e8f5b08223a3ca68af533a9b914aa3090a35511557bc912ba3e2423f0c7c9432a7b23a88b5df084f07a59d4bfbc76b9e7e9625bd1cda509e01cdfd4386847994625b82fdf154c287f0baf55c49b3c2b339c339201cfce341cb87232bc2c42213d46e66b5155410fdfadbf5bcf43982c84e0ca5262a53fa0a7d3d5f6d9aa803950a4efde9e1222dc6e884130d865540af10d0b02de115bb724e485e6a1a38881d0d157536f4311778ffb4efc570358bdb75c4aa50406c820d47ee2e26ddea8c456e3cf33ba63c3f73fbab1b174c0ab7042fb8e27970a0bac1d539645633fd215a24df86c1584262afdb691bf6f4e88fe010d116f25cbf547927a71cfac3548ef8942826df16ee467e0e8ce4f2b37ca0fca404f11d597a1ad5690eaeaee97a12e068979905b988afca6844f423d564689751568eb3c40b050d9e6580545a44e1c6d8b01a2214d8523a59778605c2d9b689c35a4728e1428212a0e981773cc3a371db80008f592be03b6cc28f85e1eb291651851949bd08eb7fc40d29e6c4a8954ee88599180ec6c5cc92df05d094bf067f95858bfbebabd6dedbf96016ec21cb8154cbf90cc3c71e11d9bb5d71753a10930b1ef8c8dc587919131670cc9cdb6e2b998bd3215eac8a2c12ded0e5bcc5cedc42525fbe3ffbcb932ebc0ec93bf56515485118892da2f2536450292dae8108d43a0b624b84ad6992569f8539f52fb861f462cf15fc2a432606cc757117c58f4cddacf39ed4ca0083300606afe20d02b1fa58834a8e42da4d3ede558080f2347aaa674eb3a17e68dfed2ae4ffbc0abca4d97509e6333a428d7b2e6c12914c36ca449e8727dd7b9083f6a7baeb617c5f37e86c4c06b17d4add09c79b35d40c3e3a40f38d54020bf5fe8042ea15ccb0f759c913db01aff91a6f3bacb39afcd5f743e5f2a0d4c95361c5164120e08ddfa5e57f76e20ac3de6b9ea5e9fc0de1d5acb6b1da3d768508062431162dd2e9deac349c9658b814180c7c852b432adbd3094ba7dd77dc1056b721a7e18fc7d3bab7dba6e7b33050aecd0e944390dd8b169eccf5ae64ff0ccc951cca43134b4a863be35457b79603b0c66c8581f44f716a543f9ab43ea1189e1bf5f017ada85b1f86d762c10e8468cf768d73c99540315add986c74a2604b746fe3ae593fcb438dcd2ec95f62dd58ef29882e13ce6c90da3625abb3266c32bad0293a540367f5bae5ba73f968b00bd6f3374f5f91c26536c2864f98e72541f08be533c9dc6ba262c1cbb47702c5260460829941e7304a19adaf5e31a7eeddd71f66eece641e541fec8d4a0a4521577d10e55e80bc50348d19e67dc6f96e5bfca56858e9140984866271fcb2ea1ed8a4344a0818575190c65d870f0ad92b2610da933fdc1496e28ddf3a7bb3441173bcf63cd31e6c01a6c460f1a8f6160d19c4c07519809112812c58c96f6b97a56c373e04e1f6a3baf22abd5ee604ca6789a0289810235e0922c4af4cf8b9d4775c42efa2c853ca", "ac01f6ed39c560a568ea91bbef32f5326a053cd94a60d1f1b239188198456156d9c949c03b264672af307e918ba429d1651d0f16dcb9209d3889c6d2f1e806766e9ddb7e99dcf46c7d50075100a98495faceb3d6220a20f22a3871a0bcdb7a1d389008414510aea070b8fdf314b87717a4c87eb09d9c8bfefe3c39fb415cd98225939a6e2517c660d775a9139f41d82a0a5688f8185be38938918d8d8fc506597f4a888904dbf99defaf874e0616ca084ff46a72ceb934222670bc030903389adc559c04153a6e3d9a40db4b0d8a70ea033e8d651b3cb0ce8025c2864d044312dd93bf5800b5a86859dfb3fcaf226e4000aba0cfccd369f68cd1a81d5ba0b1e63f0b267bd099a4894e51fbf221911207f86984f4e00a890d449fbbfd339d34ca3c1d01c311a4a8f36ab6306e87b7e693c0012886e21b83c43bc33b859893a02e8bca0a45451e7cb3412ce7ba20b65d1aecc44ff57fee3a9e29545fd693124dc7285abd34402667ed10d4f102d60bb37ba2b64adf41b1897c12747d3e854c0cdaf2f0edd3cc72369c5f4d8022305c36fe95eb357f1370896c221ad84550d2c6159e14a4245e815f5c29f56d85391fae707e11513f8032e45c4282caa6837f3003e1e654f6cbcb15b3e8a6aae1631e2fe648e6334133766079f0a77c2ef611290f3d08b61b473b27f7fb54111f43d3ab05c888c0aba61b9be557d2ee3e92cdc94b1a620ec7b9caecd54987c9d5dd59880ee95ff172f33cfde51d0272ed63cfd2e57250718be5b593ede17c61faee918650af6abbc9b41c86ac0f31c2823884a2a1ead0c8ac2cbd108f2b0fe1f3130175b61e895cef651833ec98c4840078da6efd4c6682ec114dcf1ba2bad7f4a94ae0e150071925187a8d36297ed4b14b7e2c0fba0a1d2fcbd707d74e68b86ce94e28add601fe0500a77c8d804e25545fe879f58e9b5f93cd9e5af939f213d47ba15450cec13239076fdfc18bf51135e4e86dead66c2663cd4772a7c471a46984d96102e17d3e53b480aed56f84934ca45a6147ac3f25ed8e86d97c6f81b4ee95ef60b98da36360a77790a6cbe2c25c4378e3866fe217cb9380262684f28a0fe3c30991236f2c3c387aac09834bc40545cd90c92a36021b69702f3eaf89f8e727df0b24cef644c0fcce666e0582869ba5e7a258e3b1de4e52b3a38289d578e3eae2b6cdbb181fcd86cf8fee031e417a987c2855a96ab735df42e5623f7add1f6205e9ce46eaae9f7298ab000f097b3ca8b98476a23ad41fee4fefb52e4b50cc74a478eb2fa5b8140e895571722fdf11a98ad5f25b083364b4187ab0c888a041731163baa925ad0e3e420178bf2662daf07fa2672ce6c994a0c01ace1c0dd994690cf1cb58109c75c734ea2a1562a19577141e9048b006e078f2ac4b8179e8454df3aad412301ae68184525107c9157a9fe4e1d51d67bb6c27109c5b9b3d118fa689deb37dc386c9552035559fffcbbd5ed7cb4262953273b16558c76e02298367e81970f93b34b645cee5b250653598e86ab596f1e1e9befb6d3d40a366e4997e2a9427af8aeaa02250c2a1f2c6ee5e22db946de84931027e65a6f54c90c5964883c67dd7ceabf7e79f9dbff497cf3034b860f3920f4fd87b47302a64e088e4fab2bcc9fb070e438d10764dc21cfbea3eddb680ad07bc4bf81ba2034a1775bceea60e013a59fbdafbe032ed66620cd59d744229f402509d477d507248bb318e583b9ba1972844f7f63e3abcb99e9f1f5eae2836d59bea6e2b39d9b0dbe6a066e0b713e46d3a630c63c1a0353fa9ea248b0dd2f4d06229ee9371e727721767747ddc8fa0213422aafa5f01ea2b989b4c2b7d72f1b0dc7c63912c0b92710a181a2a4b8ed7d21b29dd19f5f72ad7a224ea6b9935cafa792c610f43161e526450717cd6666639eb271927fc250c7010e29db239171b2e3381c67d2a4ad71e4907ba316684f6eae08e35f770545bfffed5c2da9f946746dc26e3393c7f7f0642bb3729e4cbd301dbdffeb5339c60131ef7e3202ded002ba664f3b821802865a154ae0be0f0cfaaa1b788cc80b9fc6b6ed1b1060d20d0f53fdbcc53180564ae90d8fc9ea212a248cfb857bc914e25815c8b28", "13011cabcf319c40afec156c80c5c07b707eb6764a22c7d5b94d30008e77e66769c264997425ba4b20ec4dee9f993634bf4c701c03fc871b90cfa197f55cb8ad38773813be79aaaf97d2068c5d0d78a9e81d3e93bf3ef442fd15dcf4a5077e6ab9088a0f013593fee01d3dfdbbd6d5ba75fb10ef3a4e47887195b159fb584e022cfe268da4b57217b8d3dadab89b0dd1c751f9fe663ebba587de4dab6d160eb7c1ada88df6961f51bf8f22e69b9ec769161d3a09c972bf1f1b3d76ed024352e6437e984b197d0237534df54b2b7451086cea9125bfa4174b0be88822bf017ab8ae02b7e40019e535a4f18ded85f5e91c0a987e30d25636b86e5f8823661b7e92ae9a9cde6f4ef790a7b9869f0b3bc931835a255a9b5d80143b11d0bb4f17e4eedd3f61d45c3ecfe0bf1f6a75b451b759b44a336e857a573adef17da09c713c2db487f6cfbe654e0929b07f68e2f58fddf3865b2152cd5c970b2e95e01409d5dec01d534faa364cb37598ff7c42868f8adf7c6a7bd4a52fae6bc6204c8fc1ce0aaec51f2ec5116cd5c6606474544d0d651140a0898aaa4d0d65e4714523fefc3e8085d9235a1f7aec247e9998aae644925e6fa46f002568826ab321de11f107aa6eaf08a47e122d245144a8d23a22aac7a7b8de57bbc2c3f823faf21cc420cf07adb874c41045802489955df1c875a2f7f5ceb1c2ea40cf0a7dfc3a933ef177d0dcd9bd200d9e7e9b88b5350f9091c4c30fd345fd9a85251f61afd4ee320c40c683a9e7e310bdfe7e7ebf99f5a5c2c2e5444750ac79dfda8d9d61a4695460af7e299e1995c5a9e264a9d5e2a517d1bae3e3b9672649c0c650411c438f03e4aa48927dc4796618e3b9db002c622d028cb6d957556185420c9759d7a7fcc62ca36c6be39d6124547a892103df1d13f8225cf3026dd8bc1ffbef030298e7056dd62856eac30aabffb1a4db319baf17664a8dfc7555a5fe686ce080a039e1ad79bea8bd3102b54eaa0ecc299dab31833c2db15c1e5d5ecba3a378539ecd840c82fc5b043907c7c424ae4817d201a6eea49a59b547c137ac98c68f9063c39e2493bbd3cf9a57212bc6168a8979373915affcd34954aac3cc7d3d7e9beb88694cbaf7bf240878734b32d382a2f4e06110ea3b3ba1ddeca5a14dd2d33d21565a1767c615f634763da4e9f4f5968b1724401ced8993c6cebc69393570c14f7fcd809f162663c75d62ea81f3ddb588df3902ea2c53c72843a7293f7578a3b1c5a0d8e764a457e7d267fac8feb80c17a0cdb3de06e5044ee092c97b6f863c5942f3ad73956fb2f423ec6ff9d281a5adf3fc6ad0693730b1a0fdd543e2bbbe52d2f50619767f679c476883f94e4ce9f3ddf9b18eefece0a0af4f911c32d0462a17feaf79510c4c35a6e2f2c942ab46167132a4dafb590b7098ff067b78c93954443e6b2762e0be7ac59f34eee17ec1f33b94a91eb5b12b5abf3155bd1b2a07d09935894abd7809cd62601056764bd6c826c6d7db4ca6853044891477edeccbfa0e24c83678b8e35c7dc5fd03690a2687d25ba5eb873cd950a61822d14a10d916cd85a30bd6a1a9efb0b3ff4eaaefb70c1dbc41b6da52a0c6b42509fb3b5cc711cfa735f9433fcddb72d50575786e186886a74c2867781d6adf5f6bd61251ad0b13f7b1c68cd1f79fd6ab0f7286e9866e1b8d039f0943d1dae539291e3e3b3d2e78ec9ece5ac7e339d04dbe895ee8e3eab493c0096bb286e8b06067aa70a33471268b49edf83146e085f108b854e20bf94f9a6abfaa1b19c03c26f411a8f5ec7d7fdf2f79ead2af60ddd14ffa4a1f79b51bb77e5d24a85dba81c13aa6ad8dd62e7faddede2a9b4372c154ab66dfc1e563de1f695edf1999dcfa0dfdf1bfb8b5a3b66d19be34f78a9d75e08fe20ed3db9531ed59b2a8652c735315e4953a21d556f635a026da43514b148bfeb86477c86a1f0ce3aeb0b595cdd41201648f8904a06ee1a2c305ac4cdeb31bc646290599982974bc0c759b23c579342c6a759564ff2164f21d4b1611d4f5b09c53b44e8dabad53f1e621d287411232071ecf13a7050c854c0ff4b8e5425e096baa1a58d46a0fc5aa7c4d75195c8722c33ed91152424def2", .Okay}, + {.Add, "-58c3589ba761c273505553cc1325ccbcf62c268c5d016bfca88b0ded23c17bd78c164b802ac1c88711d1106ff6fe38cf3c8248aa7d27e7a9eeabc15c0042c5756f5c55dbdd2113e39fe4a1df203c56be4f46047d999dbfdaf7096eec74ee9b13039273c059e74b144cab76b200ae5a0e0bed6bf42470b5e1dd54aa2abf986a3141de38216f6d92f64d3d9434de4d835bd86bc4494edfdf7809cc26cc7a9b2653bac28cc3105653470ac30e575522d62ce4a1d92bd6f1efa20512c0aefd8c9c20ca141779ce42b3c081c69fc747e63c238d30148dbb2ddd559f68f3bb749e30a9422ace73ecaaf57661a12dc827d2fd27bf6de067ba41060ea8b211ff2be44caf4f7614ec22e329764e9da48d64549c01731afb26f5aa95ec5ca4b846c9322ef332a032dd03ad5cf5f7b63f9814d9c5b4d7d4e58c26cefa3638a9e6132f36c0e8e511d6bfb9317acc2de4167adc34048edbff1abf6814631f564c7bbe00a8565b2ad674dac21dfc60d71d21c46f62d9a089f0c1cce799f7eface11ef7d6ec814eaf1b6c000da35f0b8950e6c6fe4f25f61ee854c2f41a5349e2cbc6378fc745becb3342b92d3c26f27871888dd64bef178949b1a91f72a81060f9c389bde1e044ff47c9006d301fe53ce7823c1cbb7e4374f59acaaf6d1d466c8eecc5b7811271c37128dbd63a560f714ea1d0fcd0e6523fc8cea19c96fa01af0b584445ba85e9b5a095789b7cdb7beadd426c42ea3c99d36d658756ae1907cd4b19db655d7954da69a3225810886a47d470d6f72ef3c0c0c7d64826b57387519fb12f72bef430049613844a0da8e065cd9628d6db6ba075c2d7d140c18dda87588885e05652bab472da9d8f8afb44673e129607ff8dfd7b4e5f24297ad625fc11288c5c6af8add8849fce4d8cbaae3f32e7ecf45d9fe9866cedad6f2ec8c643b12a2b71aed1cae19c11b24f5c308442a361ca71aaa1180ef031de985a67aa4ecf7a8f9e84b1aa53ab5de2ff07a8760bc680565cdb2935ffba59860401dda65a59c1be35c61d74e928bd301b120afc57e3c79170fe9cf2e501569ee55136ba060cb44e397e554cbe3e759c77d60d40f2ea315f14cf447312381d16a1f1409b8eff75c9d0dc51d9b300727ecfb988384102fb6e74c295cfa138fd062e727baabf20d378b26dbbf251a9fd422cee71191ff755b292e3625c3cc43a2d15f60d7b98ea06e332a88f2de03d24bfc3f34029f660ae0ee19951e4469acfe5e63686b6c4a703ad3248ddf6a232529b2a970439dc27654df6cbd2ba269f0c233ad12d96ed68e6ab82d85a2ce6cc87f3b35d3e006115c126fb42e90a045ae532b31c37d3de60f948eb7d37d4a148502eb1b1369d894f01975ee0aa0fba1caac7df3b2e27a77a9be7bfc218997fbe3f2e7ee9f3fdcf6bb03b6ba39a431b56c0db2be67f25d9af1a6e3eecbf6b0d4d8f8f37cc0d9fe4bdd906de7dc5642e474334432c1206c0d6166d9b18deb271939ea9bea7cd3aa7ea180c7a3e0a1b689f8c18b686aafbca4fcc19a9de674f4e1da4110a055ce6e5a986df139a4508be2924df38705ee864fe3e70f84cae4ffda7b218cb1010a638365865d71a51ccc283583b88b92b5141a0c822d924a3ab304fac1a8aeea378d387760be519b1b082037b83627c1b8ab3fd322d4c7ce412e8726b726e4f79decf30795dd0d40ad27ef4e591b9c54470b1f3d80fd8e06ea31ea82dd5ce8eec2d333d32f6bbfc749390d598d66ec39056a93d0fe0d46bea38ebcfb984fbdbddb00db11d1c0d8676d14cd39e25bb4dc1b71c78df12a9c254e0b021db39f971012a9c653da977b757e8eccf67bc5470be009afc618705901f8bf0fcdc3fa008a384c508da1a4b73568007c0b7ae19f3e47518a1883eaff3b052d582c02113c14ed14fdfec59abae9b365daaf507514a930e0708afcc7b60cdf465807c2490d9a3beefc439559fbc0ec8e77da9df142d0d905aa4e2639b51bd82ec5a2a0037dc7bf80cfc6a8e4ddaf48da747232422535222380d82d45621971d1fef9fa7d7ddd069cd34d05830db25b4513c3e625bc796fece16b4d7a3ddd9f2007348dc1747de671d7ec42f1d15a5387b3266a3c877fe2eac7ded16", "8bda7183d478adca2f990ac085d79a70b1261909070adc5151e10747a38c56b460fb201d045b3b50bae4a4b710984f56b9856b9fc3bcc243eb3f7deaee96e03b93c0f66f8ede3c6d839e40ef60a64963ef3b748ff7d08402549ac073fda542728d62fa9c0740667b2e882ed9392c56f3503ea684207fbce495d72a4c9d897cfaca6a6331cb5266eb1353214ddbd8f899a9ef0c1f5f4704d6299dd1d31e18e8e52df63f5b464e4cd6807eb0318b1c18c1c581845c886e6592b06043e6664ab7a64190c43b9ba152a6dcd1bd0df0a8ec15fe3a5b44bad1e48a9b35e71748ad011d9836a9b6ae4fbebc5c2d2c87efec051e847fd53805bed953190e8171e8981990afffe30dd03e773df18f4e892812e6c847f961c27ff7c4947eff88e4434360e4feb387134fa66c58f6b45674ee6a2309f559d9a9c554b615a9556793daf5cf5df9917c81f6ffb87ab169f04caa8753801d71b41e29a65aa1f60d9d69d64494272f58023ad681e22c50a7f2f0d9195f7f75c866cb305a904d786ad16f0221f8aedde8cbb0979d63fb62e7044d15e4a4bde8201f951dc6924adefb2feb8cbcfa918237a37f2b21c95377318b84a4c0f78cc348fe85c53e9ef8e71bed817f815768d0835b47b398ae9f21af092c018e564cb3af3c100c1ad9918fa7c8dc20c7d84362b799b8aef99c26d06baa17e76d66237f216c0661f5f0ac30ffe792b11b82b1ab76495b557a9f0b0868a1b90e20d47c8133120edb7fa9a40b67af0f18e12c46df25507c4bf92108d23174eb6597d731e30a5a4af10adca291fb2765de5211b3524aa1b8080bf96dc544beadb2cc17593ffa6cdc7bf82f374c9d2a8f86ad55bd34f58feecea701c5f92380ef36949e774c9b150d52a5e1932ae0c0b40cdf1ae0a4cf3fe2174b4cd1481065bd6068c3bef384c1254c748ce2845aab48257de0dec20f2c05eabe0e46b700966af1dbc01ef26cba9bbeb32a770a53069548ab54d1b37fae2f3287b30692de0bccf54c9fa02a95dab9c8d07a974bf54b9c462c155ea4070a91139f4536b76b3c366b22925ad1b9d5985e03c878259089666a10b4f7830fd2108f6da3e8b157e440594d36f40767c2c3a88259bedaacf60eb7eb8b536f3942344b831bc95033c7b4f3be5825f09ccc9004c1c5e632db7cce60585b4025713525bddc4be30dd6de4d18404e913577e25039d2eda803743ae796b6580f2e6f71f54bc74dc5043ccc2393c99a3443fe118f81ca209e868977f0c06ccad7026f7c421d081ccb843520ed6bd03bc415e9628c47cf6925b0d29832f18266948b91942d069776959b08f51253a0a7bb1f2e100a5eff388aaa89396a38fb7eded540c259f746c3417601ce7c5d819afddd99e375c94b30702e8f046d69af5aaa3e041aae36237266c2e01c62887483c99259cd71d371fe6efea2b2eb0ba3eb0db67d4c5191f0d90901f22fe1bfdb946bc714ce525d53d8df4fdac4c0cb541bbffc60154150757c47bb93269d575c61aa03a5abdf2aa9de60f9e82565733c3ebd693af5bbc04e85be24d3cbf476f36ae1d3b44c7fe1e1c8b8ef7449cef512273739d2969839d6a6a55901fee180c361cfe7c1ac35ed44963884696687003a7d7c0c1317f1e6a9f916a1f6a4e9bd292ffce2cb91c98f592d9268f9f1cf2a4cb71b8e899ba18e37d6f9cf16e894a73b04846f8d1ce47a3542577fc1686c09d35059ac65f0b02081affc4ef91b1d8afccb993c33f4ec717bfb65b9fb59268445e210c1288a058cf21f1083ca837b43c47272779c67b6b2fb7c535e8380794835f830e6444e77c7ae0c471952f921e8a553a56b475e5c34d82575ab1c2f1d8183b3b6502b14c6f39a5664dd41ae71af8a26415e0d15c2036a25c2aa56846416872ab4857bca4a4a7f36a2fcbfb4866cd0261a125f68a8698d3302fef864648de15dbc5f1ab3e7e86639e10547eb02e673ffab0ca00f8b5d773a539780d3d33b2f9261b4a41268bc1c9e9c2662e7690f769cafd7c3bdcc576ec3fe9b98600bb34184211fbe10ae3d195a1a8b81d1371b08b7e170ae9957336e4741d473c90eb855273289f2a6e3dd43bef163cf08dd8145890a2e11dc44330f827c7121e7d3", "331718e82d16eb56df43b6f472b1cdb3baf9f27caa097054a955f95a7fcadadcd4e4d49cd99972c9a9139447199a16877d0322f54694da99fc93bc8eee541ac62464a093b1bd2889e3b99f104069f2a59ff570125e32c4275d91518788b6a75f89d086dbad591b66e1dcb827387dfce544513a8ffc0f0702b8828021ddf112c9888c2b105be4d3f4c6158d18fd8b753dd18347d61067255e1fd1ab06a37dc2917333b29835f7f98f75bba1da35f94294e0dfab30b17c75f0ab4d833768be1b85777cacc1cd5e9ee65b0b1d46a8c2aff2710a46b6ffa40734fbccf35bd40ed074560bdb42c1a4c945fa8bfebfc81907f6c511f4d04b7dd344705c6f72bcb3cce16089ce21ad5b4dc7a2f1a9fbc3be4ac6d4de669b8a4d2ea8225ad09d7a1131f1cc1354364bf90f62fefe16dcd9905d551d84f41d9e85bbdf70ab8180abbf0e75147fa5c23dce3dae8385d9d1ce534ef14172995ec191f7829fc121abd59c3dcc04818d601463e5cb798ad12c69b685deebd7a4fe48c0985dcb89b2772b3577602ecd5fb089fa04efd9961d8617957ec7c937cad229ac3f00fc2f69b3fcf5b4d2b70460c5fde5a260fec002f6ce75087539ff4cdca5cbf6e8862229f7c19f7723d13b924746688eb9e4c786efe4d2d8093eb9a1455cadbc4b2318dc166946c5d19f4670dcd8bf46175f1d0846ea9c7fd13f589d64c55ef6aa81f48f4e6b60fcc7f5d5b3e2b9fdc38f1d8b5f4ccb3697e2adc5ac8784d1909c3e1c9533b383b2f204bbad59f3e8989e8a5d04146e68e37122428402ca55691b405b76366b931d834db48e33bdfe508d5f772884dbf0abb8ca37950b3b36a15cc544a209a65703028082b5513f1c068191e56e592e951079d14cb5e9292b0b6d2ecf9827b0742232cc4aa013c9be922308dd7dd06c0b23d56d17d377dd45c41c40a9811cb3cf0f13e0731a539b61ddc2745d34a080311f06e37c88bd2658c2ccbb838c05aa26a3275fd4504c33800a9087178b769871766a2adb8133c4ce9cf0f19b89de1065f7e9bade4d60f88d3a3a5f8774a4fa23f567ecb87ef978b291be1f83d51830925faac4d15c74179796a7be6db2e1447df280f52fa5ad069119234bad8044e70f3979bc38cfb57bc993910f30cc467efbc2564f63cf89d64f4a3b73baa955adea9f4dd3c737e390eddac9eddf889a855cec34f8b3a82323dce02c6a8a3404640dc8e14e324d3587d40d9b0ddc1e14b230484ffd6341a99b9399e7c1e274438e23ece0603d29a6f2711891a80dbb9f75046909ef4a56690cfe3b8ec369b1876eaa0c67a4c50c39533a389539f333eb585dbeb11ad32ad7abe300b6cc2840214d7e470a33f8722b45958ca3ecb2cce4fea0f0ee237d38adea10024887146885a9ed4210be45db7fb7397e68f3746c271cd0e98677030c96a78b7f4924f3987cccb72ba2a92fbcc25a24cb691d3456dae15dcf0798cd8b1e1a27c6d88f04ae53303b3d0d8acc769791cdaf0d13a90e90dd1e578e9b061fc6742333652f98594bc95dd76e1b1d51aab64928d73f2a4515635925d9158b27a0a97169d08a760b5dfcc578e73c2ae47f6ec695ff20cba67ba9a91003253e53fa648b6ae742c89e642715d9d0dbc36bd75bbb559dce6f2eddd80f7e4c60c816462cdd1207b4fcbfa1ddcfd308a617302f1fe85d1affe66f36d666f9b1f0983752c06ffde6cdcd905c30f2e1b68dbdc2da51f2c3cf1bbbe826cf005705ab5e5c1602b86b0f10be4945afd9f7d7d558d080911641607619665f363dfba12ac8c990f7adba9c420aa1669e73a3503622733dce3d0b1c7cedbb7870edfbbc7e77f69fe0676775101fcd967bf3942a5f2e38875391b2e01838d4576416cfc1564c5e13e976414d91b4fc2566937a61aff90a2936bde7d1acdfc82cc1218ae3b4b473a118429ff4f7efb49812808fc7f99a37c3578c96221583b1ad46b7f0e2252265ac494a2cc33cdbf16f9fddd4dec849e868844022a419667cdac19ba822307c9aa8351b71dc638add375d1fed03ffce7106653b89b0be4d00deea2d922d1f725af4d7a6b043065d143714774d40897f5e07c5fbe08a465044ae642fe3d1b2df75a06a97844dc4a3fabd", .Okay}, + {.Add, "-b50a080b9bb03518915eed0d84afb55fbb1a0c2d24d67e117ebdc388dff1374d64b2eef165254860a9c24fd1065358760934cae01e0482bffeee67551641ae7135eaf4d7191ba20f850106cf1d0087c62b2eea649b66b723f800c643afd4eca86310ec1c2cfc2185049c1b4ecad8d8d207954c1e9a35860d473071f9655266cbece5c59b53468a1e70a37bf05791e506ad4f4b1068c20dabe31d82f3b42e0844e20fa8e222098dee9c2c539d7a566a90d181380ef6d8ff003c58ff9c9db444c1ca0833ab944642e5400adc139a4732a2567753f1cd1c1b23ffad36109ad81fa1337b3de92dfee95c0ad092aa5a8c844403c831d1bb546a5ded4cb0c89822ed1c327958ae8dc21699145835324932830ac50d5757033803cb3d3b0375034bfca6f8715b9589ae93b52bae33144450274f7ef97d18d501e26454e52dc7ab383734853913edf45a354cb604ed62318e4c35a8d93a8df824aa774b8f49460b5befec666ffc070a8e115278dd77e7b0a75cf800f27df708f68ff2752b9e48c17d85b80a39a408f005e359cef14ecc385e19cc4a4e78e59ad8d9b6433d4881af8268ee749c2821dada40056bd381a6df2e9bba8e53fde4c816c8dee9d6135b56e1d22278634acadda79aab443e21f84c61f1fd25b3848523aaae60716dada761819555b06cb3a109d50ff7f6a44c9689805a2b61144b911e517a7fcbb0c779c55a2b78d85a617fa23e989ae911c771b4f544f5b2a013ea9a917271a8d811673a75c4499bdf3a045e722ce133d4cdc06937b937503c2baef6731a1c3206af607ee3a719ac3639e636ec01b20cd10ae69a4f580686dddadc52cd91ae1fad30da01a544612deb8f2a36195e3c0c6bab4d7c4ae5375bac49bebd55754fe7578d4d356ba8eccb20b5dee9e8a2845d28e1c3a2a9d7b60508c88cfff1cbb5e360b4f53815587612250f98ced5adaac1b2b74a3e9b56374883a178c6a8dc16714033bbb4b0a49fce18531d0b2f6ee0bf3f7c3eace339a14bcc63614994089a7b822c5b00ccd8d9bb38e0488103e45fd6b4337f478d4e4a6bc71dfd16219dd951cbd20fd3486c89caf1b913dee8e76530f96adbf27b7adf213379ec1b11eb8116202299515a062879b75f77011b4d92ea26c66e7064ea8a343e747b91098c359f92f638c84e94d74cbe52c0da1d1a383811d5d68ff3f3eebb50d72ab578bbbf7ed9b7130080b94172007fa12a320b3e4465b0996fc2834e9b2cf9e50122ee3f1c5bbd31ae3b17ee18fdd8ec4e077303e3fadbb00b49f1cfc740a2c2cd61e3b3d48812d56bf1f25365ca287c80a6e0a3b886b66980df9b1b8c2132e73df615e3e84decd7faf6158c6c3d67fce366dac98824090ac80ecab9fe2957f47aec94940036b0fee66d2e84d5c6a74a7132d6e56e9c5b257b5dd0f89f0ce61da7a0842e6d8a5670434d8ba74025647f3075d475ffaf34640c0ffc5f4167c04191dc9e6bbf2bd13897f5ec5c1d49f4908f80b7799896e98014efc4155a8a3aa3df5d956ac74e7ef3464dfd504b294d0bc6916d4263f65bca4e6705127fcacf3cf1de9199edc9c3a7a667616f65c253a542694f6af7ba49ed852d5f084a3a68ea82afc3766e02c1c4bf07380122670ada7163ce2533b1a255dc7637156de0ee6e006e70997acd7915ea96f6cae390ca6f13a034f154b114a48551912ec762bb9fcdc86abd9db819d7f3dc85844302fef0b4c9a090d601e30fb11a8d94605392ccb20c34b318320d2ea6d25f51b5380cdd6ac5b06a3499780b25e8d0a6738065019b3ac235ffcbfeadd4bf1466327ac3a6ae22c1dc07b2ea20c92a5781bab893c6f3f34944ed8139c7ad78f3b4e45593ba72b823ef79df01d62dcb59f2b0502613f79d0d404601a363402a16e25419169afbb1978598aec1e91c6c2bc9a50aacac5530ff545a7c578ecc1e0c5b876693e17c2d04ba4c5853c8dae026fd94b45053edbb6a6872da0e2b72a9b94d921662caa02f398cbaaed1f62ad021ba0f5ee738f2a56dbfc3709007706f4ad2a5823715f61cf996e5d017ff1856100d4f424935243a44982526eeb49df9b42e784333a6e3461e2fc06a97203aba140a94c690fe1edfa041c1187ed8", "8c1d5963873fa8a3269910b30443cf394d071f572ed5394dbd725e6781ea33794c9a5febfb89e585199c7badff3fc810ff10c53a6ad910addce7ab5d46292de6673d3704cbb695a27c964f480321d80eab49408dae358f43fe70181dd02c429a13f01c4c65e68d9de4e8ee4e1ca1f1d3e8e9ed3485843a8ec73d05da15b9624cbb7084ebb6a3095e3154c0bb767d1e56cab55e50dd5e003ec208a265756da1d10e256c4f14108b92246160e1244103ca0c69eb0b85f8c8406f6a1db78dd805dd22d6345ecdfda5dbe36ef0629e3fbc726c915ec85822277713fa8a90314ffef7ea794bad1408bce9db7b071d749b9a1a592d20311262d2ac1587e2f11196e7d86b2c9e5925372c08f88ac33e5ee4219f5bc1884e33a5eb2416aa825f103ffe09cadea6e702b3b8f97594645573abdc122e86b7d685381afe35b31df7bd24028568e1ccb00d72df35490e589e6620c8dea7b65632607c234e62d0ae68280bdb8cadfbe68199adc5861d3075368e29b536658b3509ef4605a62d53826ef593aca0c9f866c4041d43156df80ea7c1db9b58900b57891a642c1139951dc551b299450d2b1ea595de0aff598a5af851e4faf7762e6a34db64fc58625c85c482f2cdc1fcbe6c5d2e97c42daed92a2c869a126f57fd01368bcad7b20b880d80e92fe58f82e842e77c2603c8459c22b28ed2c8e02565b147ff0cc57da064134060146ede47b2a7e172f76d3294e9547b6616db3b32d63bfeae3708187ca9a9b0e84be04dc4872f12d025508e194eb77ee23f46f2972da1e943b32c20be1d84273c914adcf089859c873a4215c647bd910001ce916acbae867b98de7357620e83892ad20c9205fb77523b211b3c09f9476855321e1f4c50ee2d8e2b8187b7fc75bafbc90e306e43cbfcf226ce719fc7788bb9f3b03df1df8ca2bbc52532b07f3cdd40599066a65abaa2c18cbf94e53d95385dd52a6cb53bd26bc380ee6dce6c4dc868f69594bf263708d9f0162404e39c372cab4e24f83ee6457ae9a4d9e36d64e8e9560d30576c0de8831949d9bce1b7bf543d2b873d9c75cee2ccd3b4c1046b9fdd9556fe00cca603141aa37a108797836a60983972961e9dc2247fdaf62e61d5175c1814ccdd32c555bf2ff9189f791c6157b2f9a18930fd0ceb77c45bf8cd907e48e5df4d7277260d883269e6a5acebf669d873359e6beed2c48b0a0a01824b7376c88fb4af6b558b1c6249d131091decce5e3793b81e5a6d8b8934c13d4dac5ff6d2cb577a7389ed70c5afc5d5f7fc9bb470610c8f215183b868e65f6bca6d06d2fb1bd1f79a47cfbf0e0fd7cdffd885c100c4997fe66d5db6ac9c9095c57ddd01469489c6d0f57b034258ac9c7191a80086f26c0cd286524e3452dd56b90d244f007c6e529aaf32e6e202fb2da2e149850e7c6743bf164afc91d24f645f5cb7643182c4f42c3c5c9ea045581da2385e4c9092530822c4f8e195c54a91f4644b461befa382f01ce01d9e789bf51724b3e1ceaacf276cb7dbc1f50c6b23b588c7659f370c990e9b28d4a99ec823de4c7cea0afd157f9a59acfdbb95435cc3c8d516e53c7434af9ebfa4976a7cf1535b42000fd74b314660abeb83d84682de775dd8f0f0c64fa34553a382a969960431f1a316e0b333b27e4978d8902c0d5b0410dd8ef5f06c57deaaa75431250aa04170718042def4d44d1f5c386d16da3ddba1732bd472d602ed5f1da44f9ebac6abbb1a6fb0156851e91272e3ec8f34886221c231725ebaa0bb1faec13ed6b61607f288dc5f857dcd8d29907a8aac33926a3b1577c0518bd75b3d84f9f58891bf1bd92baae7d3f1bf547c5583ada1d554a0b072da921bc89b3fc42ce0aa81d841e35c0504401d58ff73fa46f34c7829ee8de8ff7c0daf5a8804053f86277bce1e89ff70c0068f1e9b6323fc1df565722f8c977f984986e97b7bfe4890664ec33a0d392c574cc02755392819c19a0b9d3f7ad000df5791bc9f3afd69634c7f6f58bb0582e5f25e536f16b28feadf50008e7a723a88dd69d59577cd3b6881744bb776672bcd539c008d268d5edbf80987026c645eab91a8f0f40319c9894578cd336b3145fc95148859c832f1a5dc6da520", "-28ecaea814708c756ac5dc5a806be6266e12ecd5f60144c3c14b65215e0703d418188f05699b62db9025d423071390650a2405a5b32b72122206bbf7d018808aceadbdd24d650c6d086ab78719deafb77fe5a9d6ed3127dff990ae25dfa8aa0e4f20cfcfc71593e71fb32d00ae36e6fe1eab5eea14b14b7e7ff36c1f4f99047f317540af9ca380c03f4ebb34e114c6afe299ecbf8b640d6d2114e08e3ec06673d3ea3c930df9025c77caf2bc561566c6c5174d0370e036bfcceee1e50fdc3ee4a731ff4cc6489d095c9bebb0fc07762fe9e5f52974f9f3acebb2ab80698820a94901f23c19f62c722f558b8ce5f0ea29aa9b11a0a8f197b1d7c4cdd7868c0543c74cba55688aea901bcd71f3ea4e616b694bcf08cf9218a726908115f30bfe9d2d92b4ae86fadabbb619cebed0a44b3d5072c5424fc9c7661f320fcfee1434af1c57473de6e756176cf694c3cb6d83570122e45b97a88728e8be9adde350145fb874158570e04bcc5bad02b1227da7c19b6748ed19b08a4c47d81bd9cbe9d91740413d44ebe8a04460f9402476827e73ba43215c8074ada509a82abc5dcfcfa96771097c44fc3506124926ae8d49a0c3182593afecb1cc8687798d96d3ef04607ba4de6daf0fd67d9564f7cbc5c7df8dcdb6834e97dfd6ae65e5a0267851afc62d8470b98daf0c2fb10829e3faad914b3bae9a491f44b5022b4cb4396545bc9a90a7b99e2f472b68542872f64ede69ba7fc9d7ebec5a6a592c2e67b65229e3fbd7580af18e4cdc531a86164186f87244b90e89c5b2bfedfb73e92b3942525c3cbbacb449afb1bf9c46894d559a4d89751c122c55d734b33ac84b2256787a72549be593b2e3de3d20d061b20613f5b3193c5ff8d08fc749ce5f9f90d77a6fdfde9ab27212ecf67bb5eb891a4b16efe405c716e9005d360690b0b035b85ad4fee5ab7eb4de2c1420eb2ccd79b5063d810cdbce65a65ae55b280371c76dec47ae0a39592ce602557eca9b3a98a275b68e5326d4247b04191ef5a19ebef617e382cc8ae1743a9880cb15fcf751c78839111ee4898187473ed1059d0acda4336ad732ccf0ec6ddbd4ccc1b6e8e3446f111a46e7c0e3cd7d4fc7013b29f4377c42aa1064ea82443bc58e62f10e26f5540392d73a9ceb4a93fca0bddb36fd6b37d04bf16d70e049b40f9205ce2b3029a3fd8a16481b38bec6a5f73474cfb590b50d4278e24bd035d4a6eedbfa947f9051d5b4f0639941c6a6b562b5e79a7fe401db211b4da65e78c41a023e343505b80eae3d5f663413a17bde2b4aee28a70afeeb1f5849f830e238d72195a8aee869a859da1ac787b300d0985f374bbd57127d191445d7b3a12bedebd7872f776c993666ca330bbd4b21f49a465fad595a45d948df84595854afc1fff0036ba12d829a144bea22a5a25e9155879c9b3af210e6962775bd607052f41935d5ba5716c1d3b1afceaf14b81ecce3bcd5f9e13f4433aaa6402da671a072a099db1ffaf468f03be246afbb13372781d375bae35b3dbd8697b1141cb3fd2b689898c52e37ec01ea1b0782b54fa2983193de588666e3dd924a8a294e1ef5a3a9aad38d3d589a29eb5ef872ef37a42203d7f295bc3ee647a95f1031a0bb372c102aa28a480c51aa8493fe8d2dbabb8224f7c0eaa16bbae686193beda05e1734f58d9d238c0a0443e11fae8483c6cb80a90e8530a13f9a183b12586e9028edc76a82ec86632849055f7324b03e2a7ac8f9c1cf2ba2d8a644b09d2042d9523cafa601a8f5c2c1f51df647ca13fae7340e1131bb751fcb1b6a83feee722937cf52e53ce2122a5861ad512bd6d2e4a2079f76f3c13fdf64730cc880da5239cb1f32f3f70ecf5d29944a6f54ee7032cd1483a2c64cf9897974b24117664669bc12f7ac57ff7132f3ca926cbb099e7b8e10f20d03366516e55f3f868cc33ddfaa66002ebc29e609908ecda6faa647f428feb49350a6d8ce70ebf7d9b86e3a84a62b6531d0296e2f629d6fca9ed41d0093c9dbf2ddd4e4208f78f5fd1049c81861807e4fbe2e645bcc47a1eee43ffba648a7fdace5bc2d1d67b231955582e69a42b2e02c54a67af1c9eccf88ce0dffb208a456acae9be4aad9b8", .Okay}, + {.Add, "-89cf17c9f31442e4dc8df114e5d7664f19e11d33cd27fab4b958bfafedbf9dd6a7a944391bc7253bba151aa7ad428fe3f0a7bfa0c148b44d0fdad26e98c5c75797eca189c8267d18936b9b25e208b0f4976e50192b0d36b28b99374b9e481ab70059abbdf6e7dc4b4110c2a1e00ff6749ef288d376609cb9ddf429b79e237ed73de0fb6e6796550dad348be05af1ea8aa088f990e8fb1597c727ac04a6e7283cd8db7e670a54f37a594c522e680b2c4136a2bfdf666ddf1b55bc6521b1573761c12e915b0fc3d851427011d044596447a421604efaabb28fb9b39537c1dda0f85b07f61ceba6dbfa21fe55597fc795437620179dfe8cd2543464a2f5c9e937d9adeacf4eef16daa9d8e140d3f667c1510a402fd9a75c0644b2c1262065c633ed2c46d8850f2414e27d4d3830e95a2836014f78d73ff468722b79bc2a17d89eec80a84295c77b1c79e2fc5e066df8293e351c8586b8ef975df2f4c724884e0b7078ad145994ee2f9327d8f2ea386aa53fd5b80a519b1973e3df9cf6581ac079c58f1defcac5d3137ec8a9bf25922509789c8a5dbff3e48f27500ffa3eca85ba4abb8bc204bc4fe1a592635c0f428eea50e5bdbb4f703e85140b7c98c40ef0679c1ffc5af335905cbc76a8d5483233043d27b1b0fddad2422dba4622621ac5e3d435eccb4a3de51ab0545756d1af709019f9ed3136a490b24ed9ae9b3489bab37d75c2697fe2b0d7f8553d59b83858663300da99d5b93cb40781fc5948d827b6cb947c42d0b98dbae1cc1c589ada9857d46164f41f7dacf73befda68f222f6d88b278e153917d1fce59119e1d46f5ca4157b28e68e4390c230bd204ca4695b6b9de0ba424dcfd007b57b54f1c19eb73f0a6afb5b09fac205fa058b98c682a39a8a068388ec93feb9caaba93a01079a22863a5350dcf3c6a34b1db097a756b1026eabd172ea025d666f21222ad5be4f65b5248e59caf7036544a627bb2aa127de785bd2714e6ff605b3e1eda4d7a9a9acf9af9e6bd6c30ceafc9a6c26e4d6ce903a4902465917cadd4ff224f84be136c29705626cf51d0b96129a34d33375b3c0c98b9ad1fe4f208dd23b8ae28e0c4f32a2a480b05596545578956c99a11ed2b3efa741ff1dddd599bcdf65774ac9eff9a229b0621271716d66189bd65d3b82e91cd8205993d56d9ec30c3ac57ecc007235a3f2206b7e798d49d0a41a638aa34ffcd25c09191226c1c8c09da3fee2ce693bef4b05b45b2dc49b7bf0a4a53f75d2ffb7970f8fb3fd3fc100c00141565f3649fb99264747782db7982daabf1f62973d9960bd3f610840b31c3938d1f16fad06302f9586fbe1da883a46441105e6773a3f01e54dc069545ef2b1a4193fd4910a69ce18a7a2f766d825e318d642fda98c578dfabde1012e656b036b3bf6d35c483168b68e20734e41c8f53235e87c59f3829f1429d12c2b696d7cba099ebe75d1ad4dc3abc4cf1c02a253050d3e5315c0c3ebb81958ea3a63b69ab2cd4614d287cbdb9e503f30a75a6ad8e75a98301b4e20cb2efdb35f6af563d096214164ff8c54738ee84e67b26386e3cfdd73bc10471e2cc15f64f378180feaafc91aaf145750fd146aaa222d5e74b2ab4e7f5d8dc2b99b74bbf989695474db02c9e073e87d89c4bdc6468fa6cbc1ced8aa3e1b2e5f29124c889c71b8147a13858d596acb3b484e881951bef7977d069b46f8a48503fe6059bbd16287e2e1a084251b9f74a396d9db5f020a13f3b8a8fd5a62d4da5dd3cf15e9f1151ed315dbd8243f2a6a3bc25c1b47852e919dd1570c903f2d412287476221e8981cb3482d9745f47e8745a271e6d2fb97a11df2987443320885d3c595a1c9b9f38b448598ec5a602e165137f16b373f30b1b55ee5b7e08c8bab59402817a437511625ea8bc4e682d7bffa76ea798cbbb5a4cbff7caf52f790df96f9545879d514ce0ab17c80f3f2b2b4c488e3ad772bb0dc4f397037a605f438e13ba253451a278242b3f858306c9876e48eeb34ca2044b56f3204f8f321efff6f96c66259a64e1d482a04bb208fa8a91560c4ac06a67e07f42010c6115824598e90d24dde114215f6c51ce938bae228e1474158c3bfa9e86b97d0e0d2", "26e3c7436b926f342cfebc8301ee34f9b5a62ec9d4ce0ef90917648ab388aa539c378c6ea975c6e91c7a33ca74e126bc6f1f5c4ce1773eb988fd6713b826e061488e2a086098d244c8889594e7347c4a4c2a691d1df67a9d3e1c6230a1c1f7591676609580e4a95c6414d084e971834011f61b24cf880cc292a156865316e15fe850350ffc1ccd2ebf68bbb942bf2c20573292b6a84e4700268b9f575d1ed4fbf6feedd338f5b6bf33cb51e54a0f0caecb5776d1d56c027adb03b27df39cc87326f7ab90b931312f92a6775ba39f932198b4cfb7e40bd7162a34d4d877aa728e8c6ebea5f7b39bbf1f8be4aa053dae8109c50ac6640a719aa8780d6777f69d4138ed5c67308c508658a62e40469fb348b2c2fd82c4d2fe5a6a111fb677fbd9fc946a7e07aad51c2742e20c43d520076fca84b903ab04923f2f572cc1668a1f951f576ffb2fae59f49275c2b29ff5e97897c86ad4d0652f5cd9c5e865bcece233dd2e2af82b62f2073305fe52ab733b31587a7038c2b519559eb9112bcbdefa56e9ee371fd24948a927572a5fffdfdbc06f5aa6139ed9f9edfa0f96b124e8839ec37656756ed512fee9be8b8f558b0726a8d43e2866d8a3229c930de79e9958ac4c151347f1459e8ace7cdefda34781b97d169dec4b733e10f780e7f769a1f1f97e501f42adec6bc5b297c56ff7eba6136967912d1bc25fec386f8fdaddd7e0169ad9e853f6f53e24de685cc72622e076fac3983dedae1db7c7b444a8d6b48a7b02e15d0f5954445e78d3c758ca8ccd35e388241edd12520c2a7a9595497dd599ae7c632f1a55b0a4c7a5f8808735569060ad77882a09d8e2859f3374e249d7a51ac64dbd2cc4c9faf3e7d137fb27922abcdf7b6a262a8316d2be181cfbe4fa605c2bb1af56785fdf5b8aa0318739dd4fcfa7001f9a428a58e732cc388950dcfed81c085a6841b947ac8386d70568d11c61870cc108e54a74dc81cbcf53ceb6e5a1b2e4b56db9297e844df46e29f4cfc0ccb193aae3cfa436bc3c7ec851e867a55a75e09152a3b2d70852b3699b843818bf5557ee633b29eb4ac126be4bc2c3f45df9a0b696f2618bbee3746504718a469a5163d230dcd06953bbe79a85b96cb7bcee2da69d14c8e5bb5b14c9a35ad08a4424e63883850eaa985bbbc7d6ec078db4b3e27d82c1955cd5b633e0424ef090514070e10e74c0cb228821cc018150cc864778dd10a3ab739b63c78fecd9135ec567b4f3d9b9fdbfea2715b69c802be98fa61bb3dd7a35f7704fc011fba56e69f8bd16b693a905a6ac201b586056af3eaa1e152dc77800acfba1fa6464ec3cc1033f33546147b3d2cc82474eb63f6af0a9388ab82296dbb47d8df26bcb30d71dccaaab4ad0f49ba62944dd922b52e711ea48a57614ff73910702ea7ea2b882e537d575e1e4d59e7475298ab577f2f78317a588a9b726c480821130f89d292cf867386aa41fcd471504de8fd999437724b4908110c62c66ff3a15d524c12a5187c644bec63d514bb9650499dc0b8fbb82ee823e4de73b11a2fa8cd259b00b2c661ab7c2b21f6291085248bb1d696c46f839278773913c94f40d41c3d30e101dd2b76484fee2a8553f85bb50a035ec637de169ccd2afcde293759679d995e2525617a5267c114322ff1be17454cdb363a0fb24b830f723c8524896080cfcdb96fed3d92dd2a3258d86a8b5bc7c4db99d39d109b110cd99d8765d24ee3aaea44e4b15b6698cd83d45f547318a411e373196f4fb549c01f9cbb92f43658223f356f8205c5bff2a5623b0e911e00456bd7c4ab56557da3fd79eb1119ac141d0aaa3f147070dca154cc14bd6d09d581fdf26791867eb6bd92df0c54cd1dbf0adbb5339586cace41ae02363adacfa9d783b1426cf199d9d3ad9d2a0b01972269ac1ee7dd7215eeea364d6c61a3efbd30558d6d8dca76a0aba16ad2ca70d8da5916535bb0f48a1a9b36b03bb2ff8c1b8543b392d41175d972d37ee0be4b05e15d5572c2f583ed6827d38560a6746def46d266b90a7431269f4f711c6df5b7cbca86a9df853b944cc971028845c1e4f4981a2820dd311e5419d7bead3bbc4d0b23d200ecb3680052857e0aa106897da0e", "-62eb50868781d3b0af8f3491e3e93155643aee69f859ebbbb0415b253a36f3830b71b7ca72515e529d9ae6dd3861692781886353dfd1759386dd6b5ae09ee6f64f5e7781678daad3cae30590fad434aa4b43e6fc0d16bc154d7cd51afc86235de9e34b28760332eedcfbf21cf69e73348cfc6daea6d88ff74b52d3314b0c9d775590c65e6b7987deedcbd0271832be6a495666da40acce97a09c0cad49c85340e1dc9093d15f3cbb258100491dfc1f926b4b490d9101dca07ab8b2a3bdba6eee9a36e5ca5692a721afc99a74a0b9d1260b6c9097169fdb798f7ec05f4a332e69ce993776f3f3403b027270af7a89e6c26c5b0cd79a8260b98bec958e51f29a9874fd72e7be8a8a23803b1293afc80e08577d3256e28907ea48b00669edca59f097dc5a7d644ef8bb3a6b2bed143a20c636cabfd394efd632fc228f68b14e7f576150d29a97ccc28550869b53ce023fc59d541ab1e88a6801192edebecb61293c9b7ee961698b3d8bf4d2f4978cf76a0e7d3d9a18d8645a8e40e3e52c4ee17f6ea52fb8aaf389cad5a15294c592452db82d2fb7ac550a95395600638da59d36abf8156b8f4d7acea6a8a4d07fed03e32a3ce97d270965e1f16ee98adc70570eefd3e747ab444abe31a82bf64a8eeb8283aa9b13118f5f041cc2c53a6ab123f1dab79cac078ff8aeeaa1bf9161b784ea069085a00988ce5262a13f0b59abe2d366dae8812bebbb99d376d4fcf1123585bc06170197cb8e964fba4814a001732c50919ae5c16039768353489142100b8a9e7ddcd000a09aa52fc55fd35cd97902f17911b209fd7c4c40c973e953e8274d851a7b6f061986e94e3781192f871193f8c5f3f490a30b3dba876d2089a38facdfae1bdf9fd49782e332cd80a986bea029aa57d73d3d8659eb501e99cf806045366aac50bd598418f2367dcb6ecd60256fd3b56a8f9a1bad27749ea3feb8e69498c3074d09ee1e1acfc9a5ef5b4d592792ba1f8c99023cdc355d9fb0697fb4dd38e2ecd82bdf3d46c5de2fa81c84e62894ee8c65c7c5272a78e9d244e245b28a7e460d1506b9d06c274f73ac7529f0fcd52da13147b82e2c467ca76e2907dda85c0a2f4c836577850f41b0b20699194737ea53d17740c0d0d7240a628126952917e58b7bd9edec5ebb80401a956496e18f236c771652ac09663684919e89b181a552b1af8a7004cc7eae1bf8978921ff304c14903c018316552539dc6ef5f555dd29e350c08173c6db91c98eeea2f5a71627f0f3dbd68309c99070412f5ab9c7e002dc0f90b3cf2810ec0d8f66bf0be7feef42a8119990400620973e6d8c8370452cf062329a9a26b56dc3fcc24fa70c4995c95a959dd278aa7523b1ad74a3b9ec9d236d5cd202cb31fc9e3b4417aac27a6d455547cc01bad4640080bd541ad962f99340ac3b9dafcd53cba780708962706af98b801a0566e8eb6b8911019548d946155907a501d4ed9d747533a50f9e9c0f5b370892bdd3647c84dda884ea81000596df8a01df5ba105d44d7e8ca05fcb3248f0afcc2459526943c3c79159d32639bbcc362f05215b349b14c00a4fc94ee50539ebd3b6e32402a8ebf60c9ef68499988f6bc779d81eeef75aae49712a44d831a7e949bb86c0ff4488f04a919627721f974a354c83cca5ed64557067cabe2ded9457a54defc2317d7d805c8f343c74755a46ae996a10d450decaaaeae7ca2d56a8ab03c8af6c847b95ea6cfb2658812371d229cccdfe71777319449da8c6ded3c14def1b5319e69872a21b371343a1ffbf485ad86dece8452c8be86fc4d7d1e20a47a8c07e023692d60423d3e3545b6ad908e64adfd21bc7d6eb12295f5aad2db65de0c59a7f38c71069b272c317df84be5324508e51b138bd4314509732710e7a06fc7743853a7252bfe815d17c9fc91a9e1850ce05e53db37ff23808be1cacee6f1afe20de0a6ef34e614d7f09799b0bcd7845d894097775edb1b8ffb3fa8af5adecef9436cf47fa1a97414ab536ac5e47a30c5f64cabe19feb4c993deef834fefb1570b814aa93e63e73e0b1d0d0b673a0f6ddf6fc3f276c7d681d780bdc0689c73c62b23095818867dc21a1610c1539b67c93e5b2f3906c4", .Okay}, + {.Add, "5e19bfac21375c4e70f2cdeac6abf2ccbea59a436b1f08e1b99b8a26f6053075c1e7716317c33d02403f099802eac0bc1f1a92921a3c93ad2f83f3a2ce5d446c4d6c21c483d012ef6deb5f591769d24f0e5dbdb9e699cd5af6a0058d3f81479b30bf15bc8b8a30a1e4a746eb5f80ab8b9a3e71e1b3f8cae5866fb0e3ad472a374d093a73b466190f857f2bdf8d5bc45df45b6ee55dff4fd738e4043666dea921253b7dda24396b42c98c0deb5e8ebbf9cbe9397017a2fcb46f3f3a6c2ac44588703a439afd2107b34332ff3a6f7bf410751a23cc40f9ad25b187e4e7abfa7fcb49d04848162814cd683b77a5a9dcc70a30021a1f6d14c7dab82a35a815fd84b671a15f41c793edb24d300eb206c3545027cb191700946d265216b3fd22104a2ed9ecb3c60f8b327320f045578280087ad64b5707e862429b914defbea67dafaab7579ff413bf55becf3e05ebd3a4bfc21a06bb5208d7a749180817ae920e2be43309b6072945adb5ed79ba260509430b63fd7032335486c7e3190937576ad21aaac10476f8d8a3d4f0f424428f5d41f323ec484bee7eeab9d86d8633913ddd0ac73cd972e56c4fd9cbd45bf37c3c597d16154a0d2a62051c1ce2fb473a2598db4858b957d5a4b0b3b2258fa7cdc8ddd009943665d6b5b9ecb15df39d427d5071065294624f83f1ad72c4286367c4e24859674dec092c72d1bc68792c32aaf214edc69089675b59b046cf3c09e23556f654ce96e5795a04aabb853bacd8da4705db18b37f572c720c8306562b41f3e14e36d5030a75256a6931970b9070887fbdd81e9b932cea16e6e5e070cca0898798627f6188f9db99edfdea7c370986f7b1e275003ccb4f734d6d2ee83cf962a024ede7d091ecfb013e4ea320cf059f3b57d91805d39d47f62a2ef020ebdc23bc28def6eadf52e1cef0a9535dfcf58271a8d4718be789d90386abe49433dd2ae8b6464ce6bca51a7bbeb70f674ed5c3b3d4e5ac3674301bd34a5ecca2a5aa2cbc97304f31dfed2fc400fa08abe2a25fe288d9823d0a46855ac742ee2ce6bab8ddd61957f52559f9b251c7477d24cd6854ea0916e74ba49ace76b588793c0a289611113389eeab85abbdf72afe6516280d018e7bd080a096979e3c570b8b9e3d4e8bab15f43cc6a0bd549952008b6ccd619a328d6bc8fb1f88521f735556fd9ba178c2828d4f33ca86b3fd139e6693dbdda2120c2cc6a74087e25b93131891b3eb1b8f7e95351c2dcc935de38d7bdae359c94c5328bab0232d2ccda735394e4b8f893a581905dae142583dcf614a8162ea19b8e96c387ce39b390e3f50c51274a6a728eea3e9d013715cc8ab0c7b24eb54a4356aace5fc23d4a3de6e8d192cfbad416c8b66fd479466c72f57af8f678b3778f0acc1bede0e4c97842b17c15133ff7b951c9309b708be08d979c203e391c4ed3fec0d6eacda1860016ef60807b16397f22e555bb57980462bf9e5e2f934d02b32496c4df28120e7f70431e979b15267618195ea044f70f744f2bb7b6c7a89035510a8ab5049f8c2d19c6c30a1272c3a596ea728252488ab1ca3db088e26ee2bb356a010c5308b37256e980d6cae0599bb1201fba5847b2b39e7c98862fde7a5aab5b531617d54be4b173acc96ee294673600c11cdd89bfdcf2d26c73ce25e5e52435ff38c42b374bb3bb1cfae7856902f57ea06ba152333629aa993f2fff28e9bdcb2dd83ee7901863d3deffd40563803246514020fc8b04ffc75d9686c8e8d54ee7995c7324e068ab938edf0577038d95d716574a2df9f7b94e242c3ddc789b99e011d3181fb6bda7af0f9dd16dfa97bc515f8e8c109709d47b5247097951ccffd2e15efddc86cf34dc9b3fd0eef00a6ae0156c86cc4f55f3f5a086b3a740a696e4b1ceb687388878813cc0e2bbecedfc72b9fbce5ec44bf231a0ee7d939960f3bdd8262bc3678406fc8da60b57b002782494a98930b5eba64d099c1b02f62ab974b48ed1744a63423e74320cfbb1a4a3458d4436225d33e51d595c98673d14945f0d4cc200f1ddee5628df4e6fb0fc83b75e77b63b3295445b67dbfda76e15bc7d3726bfcf1e8711f14f118076c20e44d11bb607deceac6cd2ebf", "9ce6c0d303331e9fe77a6db84b6797b5bea71057d1b67ddacc5ce370e2d197b4c52c899d860baed216a19392bf35b1a80c0bad212fca799eb5a9d04f62e78dd03b9a74943b20945d38081bedd393f3857b0bef209ecb97684748470418e454092a968bd669d34d03fbd858e7058ffa16cacb25467b833b23c4245fde815c5fc5bbc4d07314625efa1226b899f27729d007d6fefc56fee56f9bb7d6f95cd141f28cfaf6dcbe74309f943b28dd98290c0c75c9c6474b6e71d2ca01fc7e9dc27e867c44d566acb2846c8648cd52a70bfbef5eca1896945dc1ad8ad3a1e4b27436bf6ea021eb4d4717ef389047e46b561bef1002e2badb1e001d0c2d321cb486206c76e2e045899d71b1a994ee0c9e6682d5327a92528c27f0716e1b4fa18e0525e3393532330777369996a068cfb942ca78cf571ff057254a0fa7b8601043797ee50d2b681160a80bb6504918c76b90c7a0ab6bbc45d2cb9ad6eb7ada9e49b5b5c8b89255e67ad73fb823c6b9e9e74d81699f1678bab839f09952d2cef3c7aeac173cffca444f81e7c2f849032b2f77a23ed62add6b1064a0cc12b64daea8579a4d712c7267cea4b1678cf8779846c4d15c7400d4aa8f48404a4888e3473c2a1c6c3a306b881d9842cb5cff4417d60ec6076c41720639c2b5afd6b3acaf7365a1e6d635d25ddd22572e48b3cf70b8ffa4106dfcd65168cd9b6105bea4ed1d0829596046163e7fb47c09a12c397a42b936244921fe04cfbeb6fb4b12f454dfbf9541081dd614155492492f758881285b1274c8b01ebaf198506ac9a543e3feb2aa7f868f4308777b34d9b5196af0b769ccc868d7f78bae73694eb297311b485076cd2ba7e39de6ebabc8d4a0687a00e3644d2ca6f8b9f77aaf001ef7a0470f5f83b4b85d954290735b679e5da19a7ef9323f26e90d7b921097548935fce504aa7f3a7e5cb0b9bd6ddaf00cecfd2ee0196c1401f52e792010526d2b076210e40438c982ab2f8a49618bcbff1a8aaf73e3b791c42ab889342695fbae60504a91849d5180cf8ae822a162d92a90cb1da2b758f12170130fd5c40f53361fdd3aa956e1a5ba293002f67ef6f65d213ba5d5e65c08212c8d3d69adcf8c477bd08da77186708f95fbde705d3bd40527c84dc8985c7e15bb702bcee44dd334da0133f1e8f8e3aa88c957171b6ad18a09f0bff3bd14ad594316322668206a693d8c7cc0d10638de024ba108dd89bc7c2c501c244fb91d6f5b1a64faa22434ba53cd974b8f5b2d2a4d5b69ad05aef2f9fbac9bb21da062885e885ffec410e9b2cb6172446d676e80b29ee06c75f7f93c8301738c2286a5bff5b87d901e85443c69bceb88f3e74f2f7fe61b93386dae2c46e60052b1dd923620974cad3aca7984e3ac99c2a72eea8af4ebbc30827a9d0ddcfd69555448b4c56c66398f190c0df10a371b2b662291366dd501c7c255c55d38379a1972042793953965f8ebc54098976e5edba51c21828c1c8d5f279387d664a900447147383b82ab08dfd0c0bbc3374af84263c611900d905d7f0e6e65e628e633e26aa8d3c87916a70445f51e4901b80433bd05c44bf7c59a516293dd60300dcdca65f7ab2f38cccdf4d33b27fd962f24cb1ca4439c7ff3928353bce3f36a24f2bb6f5e355c5808507a6d4fd0cfa9c6bbc897f6fb126bda97d052bb7f1aed2c8f40ba665b980123ed14a7347f2f830b7b61e28249344f600d64125a421d6db727dc1ed6076ad14d6597d83c03ed5e786678d933904ec9f3e0464c37fb445c414b99cb2c348669bfac132ed75e8171c9153e95992dda55bce6d20fb83eb84e58b04deb816c9d65825929dff24a95b641259e3487224e54dabaa496fe512e30a32eda874ceff7719c5fc1e599818287613a1ea23ecfa9bed97bd8cfbc276f6ee58ea5c2be2b7b9066df110f53199b73315b93e263847035d7ff9597dd3f1939cc241c5f90a59d2f13f20c557d7a400c3dca41e4fddbbd3e01bd6339006f95fe73629e617116b6dfddf9c4782d9231a64ede1747789c8f71d6fb0aba2a009a92049cf15c83f42c25fde2647e442f147a21debe382667a7d08bf2abe04f992104fe1bca8453c9d0969b7f4011bda0ae6f7816", "fb00807f246a7aee586d3ba312138a827d4caa9b3cd586bc85f86d97d8d6c82a8713fb009dceebd456e09d2ac22072642b263fb34a070d4be52dc3f23144d23c89069658bef0a74ca5f37b46eafdc5d48969acda856564c33de84c9158659ba45b55a192f55d7da5e07f9fd26510a5a2650997282f7c06094a9410c22ea389fd08ce0ae6c8c8780997a5e4797fd2ee2dfc326de1b4fe3546d49bdb2fc3afeb13b23674b6e2ad9be25dc736c8f6b7c80641b2ffb763116e87394136eac886c40eec7f1901a9d38c1fc97bcc8d1687efffd3e43c62d5576ed33c5b86cc5e6eb68ab8706a33636f2cbca0cbbf8a1532e2f94004fcda4832c7f7c45767c4ca83a522e8843f8751315f63f6c4fcbea529d7255a45ab698cbc5d97c032039eb01570121321e5f91702690cb790ae273bc2d2f3a5a276f83f878cab39064fcee9f72e8fc4830805746761751f871eb33f358762c5727797dba342200382f24cdbc3e1aceb9c0beda41ced6e1140740fec56c4750313e8eceb8e776135ebd82b1f197e31e7c0cebb485a8b97e93d276dbed4e431fa1725b6fee38b85eb23d3e23995775838694bdab411014158ccd38bc3012ad98a161eb7b9aa4566656bde8e764fb547828924dff33cf37f0f24d3bfa3d7a3d775d5a86c10786f9c8811a04cb5e2f257dc8866c02ca648dbbb77f7d420c48658c764243d71fa0e32c2271e194fb31b6e4e0ca6c7e70fd5b9e7fb758424ee8d1a9df094ea4918bba606983001b899dc46e33689936c810455b27bdeac6a4ef3c2ff8521c566bdbad3fb3c4f746f3b2a3d5eadde9ba4654bc09af9dbbd57f35460cb575914a84f033cb081ad5251d76e7f0e1ce3dab23b1f1641cf50b6fa4604721a8ec94be475b03e6d9ac11614febf0c91759b162dbb5191cd4dc2865b1cee6805dff85ae4f2664532895ae1fa2cf0e352ce3ca14746de76b8d19162bd4454ca48421535c52ace2be216c95fb9c7ec9e685765fe797d5f165de72d551e107428f479ea69215659fca868fc2d33e47fda5a51c7f26926bda06d7ef8045d7036c73ac808352fbdc1a4fd675a5f76bf368fc340174e9b19c56d12a9b4e1e00ef2193260172c15337b4a3ea6cef2bd9993721e11cc5f10f3d372417ed3d966d5ab09c0d1646895850b27ce2c01bf5eb65a7ddd163520123af323a97d4616f158b6261bc5a3815a32a71e66512ae354ace3daf00e7867b01e119ed7bf6334b603a438fed9af9a16cff0c818375b132672b4f676a084245d28dc1fc7a2e1d500692febc2b6a165d9a55341f09ac2bcc5d05188399c0b18e95993324ac252389e972d4ce8e45c676031f6a10514c966addf3bf364ea93018f5c42520ab573197fad8ad3a2abfe49f4cf3140b43b5c292a3266637ba1ad7b0e90c7349208152aa68848305a88f9434621ca16ca83f91f0ef7e77e7659e270749c6e255ea72da2212367bf85c38ec1ae654586c4915441d4d9ec4cb4d588db51a8b46fcd68dae9be22999f9d0440f2e42031b3082a0673aede4f14e51e3908cf586728b7c552648391d50e21e7bdcf296a7dc965a5930cc1e3f3efff4e65ab16931f14859ea5db3713fd44ea4acec99a57b653377df8ad2e1a8be94735a8c3e4d111a23e815fbf525d877bcfb814624845ebce9ed6ed83057a555964af3a8b5c956ef3d628de5eef32bcebc7590df3cebc57b2921db50f54e274d7d02c12eae800d343a3aaf517d95f2c3f6df5b27999e804b43d5aee3fe145c21da3b86d760d7e8601cf157a398a229c6d5fc7311187d1b6fdfd06ab58027360b793f3be040391b3aa92c949aa2b026116192a985212a0fbbb32fdf64a0ecc1c3f1e5208d09474c6be217e6ce2d7963bf09e1f9db68a525e76e1c6bb4289dcb2da132d2498c4382faff6f6f95ab3ee7cfa5b57927ecdf53f5e5a964b6a7bbb9d1a7f71b581f85413b759a994fe7d150ba5c4b15d3ca4e888d8fa710e6403952d3e68d54d0650504515ca225aa5bf312c31011436ce07da53656ff82473e0cdec6dd8b7c7cfd6da391e7977672ae6437f03f46173c9dfe1f75868bfd85c7e129d4903985f6517dd41819224130ce28bbfeab4e3ad3aa08faa8b753ca6d5", .Okay}, + {.Add, "c8747c0eddb4a28771289da10ec3fe762d4d92ec37800dca70c605c19e624c036de16987f6c3cc376bc56d749c5e9f572040876c8f0b0a2d47c1b3985db87e71fc4768836001d5a2bbd9771b33ea30d80f08f6817267ab72201ccc5891de613cec7852fb4691c3bd1cc96cefd504bb9ed70ab92763779a06d2661477df0ffecf4f4ff6374065b229fe7dd1016bde851d160a064a478978f07fef907c069a670eba2d2cbb83f3a19fe6e6b772aef2449c8d4a3dc8ada438d9b6d0cf0df72e116716aa853d61b2384d7392066b6aba849074eb1bafa05319efc1f0ef7dc439a2721fc146e1e3baa3a08d3a655c922e9719de6bc025957d963e03caf938c2fdea4c68f4c07caf24f5b1941b4b1d313470fe61fcd583c41eb5e71228a52b79700e3b67f8c48882d294ba2c6379c3efe998733569f9d38e00054c93ef630e3472cad7fec5ac2ed24fb69553a1df089febfce448b0ddfa5513443e9cf93233474ecbb2d4ca77232c7f40c3f909c908d1df36032ec663371cc2d4f117ae94e4add51512e909fcac2ceefa077c0bf6bc17b3994f97645e5c7c1994712628ad1eb9b241b14ea0dd50269230ffb4a4b81bd632b357641f5190252932a5e1f431776147494a0e184ae1f6512ffe9a6fecbddbf33684e69c60208f310236ff348a33a43322d64c0510329d5586e02e601825e0d5410d824aebdd33658fe2cbb7d73f2714a91174a9b867759ec149689523753c3701716d480b023d36e13e83268748122f0afcedd24eaac35c64b503c7ab3d28115b533c3829c5d960a43d73c48445deaa11de6a098e6634305601b3d7cb4101ead11bc6d582bb61363952df2ddb85f8ac21094a53a1e44556e11e663a74e2974fa1a6e9df43131666aa88de2344b2f8e432c269dfab38e4689c74d8c9b7818cb8bfda0abb27ad42ca4cff8489f5afcd157f572f3d00bf01ee5aee19c8463510e4991935bf61f722db31853489f018eb42aab3325c6a6a715147aa0eddb69bb3fcf08c2fde76d32aa22fbfb71fa4126839a1c33cf36e12d102b581ca873376e26a27c90360a7858a7b8327bc965b91033b504bf2b1d60b5c9c25a213d67ab349f480c263d8e06c8640450ba8eb0189dbefb3c1747420e7d9abe99684ea01fd3e6adc3f66309183da88331e7ff2a7d02899669d0b8a611577a7672b4801da3b381843375540779949b1601f29f1f2f2934eb62943a07eba86bdaa9c6c96049d3a8a2641ed3ea85b177d71ac96d737c36bb0d91f1d7e907699ab624c15f4b8f067fde80dc67b75fda6d49e404352979dfbd5d1fa40f9b66cfbb735710e7119eb2dd07dafc42cdd0844a979f598606e7bf12d8ecaf0fbfb11db423585883dd3ed00aff2dd109b0b5a98a3ac6259de605993bea6f726a941fcac9de51f2ac2dfa1a04e7fbb4cfa0e887638f2493c91772eff8fcb6276f0d4329a2ddda2c433e96bf7cb34430c77335e88da1b63e1e6fd33a8db52ae9ce29822535a3c98495e99d6f0258132e7c286dc0e2fbbd2c1c55b45421c8feafec3722323a632355849611f06b3839d92bb1f80dbdec64479c318547eacca0d9372ce91ea6e28b1c01c27f60611f48450427c51c7e207c9b22a8f6f4bdcd5c862be812f2109a03253d683de837cd084f6abd2321da2b70e63908c3036da54e9124d42e8fc22b223e37d7915903dc7748911bafae87c569352a151f9ffeed2b0830541c470305fee2a39ef61ab9ee0ef2899503efe5fc2cd53a1b32708bfb41738741a2f6782715820f136503a4829f0431d679181c117301a509bc341db479dbb4cedcf65fd775d78123f2937f260e578b276691da1d332f9ca8a2df897e2f96a2a07e19fd6d0df9001d8302a870f412ef3191ee885fe4a5a409e05b84eec430028070b3d6cfc5e7c61629898a775e11d80865947c1e6019b363ba97470538a1973c413a99dfd01ecb6129715a48fa768433e6f1d985e2b24231f9d5110b7bfc25f65c8d0ac6e2b7e05829ae6c0e9a8ca2de8ddc0e7f1c775c325078514b77bdf239801f6831e45500eb5e754ae930493398e3f0b56971403fc2072db1af92991fe3768eda5f216632f35356c689692849cad67fef12b1b5af88fd3", "50f86899ee4f5e706290417ebe3cef4ee7ca67b7dfb7292a11a67945a36f312770c168cc0c4f650e38b9b1ffb72e18687261037dc83e56a340bbcc3620c6370f3f72b861eb5900cc39e96e981b15bb35864990098943d91d1f7f5bd3b8035bd08be09707903b8142295524cce429c6acfcd85c9722d024e08870b8c22904ec11c37104450c8d1e7dadb1f84e46d5d5f363c43b722a45e01c16a980d5800756ce331c99e3b5ba345c760a1154e1aff5bd728b95590ede3e5588667c0dfeb758a3ab2ad110446a1179ce050fdcbbba77ff7e994f5cdb0cec9f32ad62ecbd2cd13239d5c2b2de32c205ce703712ef6ef1e98bbe1da3ee2f9aaa83568f2246006bdbca452ffa61735fbcf29fe5fa661749163b96c8289c11e7ba3c8e558fd7796b79232bb46713a553b487390d6bc2c11df6507cb2ab01f7df12dbd98bca77cafbb5ff8d11db813c7fcb3e7df760906e307fdd3bc205b409230e64d69258851835b76cb56ccee25d4e3ced45130226d338f77c0a3a7e86d6a6341efa344f6e9a48b6942a0416ea3969ad8891a9b603702f9099e8bbc5517bcfb540fc58237c48a8a5dec8894ea1dd2ff61115e300b7f6dfd22fe305531033fdefb519e6f1467368fc77353a2db471b9be8542d47fc82ba9986fb4171c880846d44d3813e5203e62e45d4ebb96f08b187595cdfdc9ed2e5df7541fb4da8c0ec45b05d972a20cb21b93cbeb1375d113181f1dbebd0122c59a28c39592e174c070268d7152ace5bc7296522d06749a51fb836afdd69b73cd4d80d8d401e987232c18350d2061758e4e4976e59b8a5b01e2a6c2a1e674a7ef279744d0e2d02d7e637e995053b050300f18c42f86c7267d5e754d8d524f0e436771fe0873f87f2d1fc19fab31579d6ffa48f702752f4c57870f1980fabed7c09e193a6870f719bc2691bc91c0b9daeae4d2f637f1553c5a843a35d31fa0b740b29a988f47409c6d69e572cbe9bdd0516d00081095069b09e8f41e68a93e17aa4effad0e491b403dba6c65b6213c234b7701471f15674d444faac3a2fb19ac435d2b06a44ac2f6c4045b800057d8dac79e8d96bb8df954a592215f0598de2e24f69746e5c3061dcd403d63d76983749cfad0e7738bfe857a80b4fa645a76e101231dc4175612f54ee09abcf466843a06948b98659b618a2a60d3609f3d66077177aeaa7d8f0b2fd13df8fa1c830d937d8e0aee3e5af08005003673a36f2f39c3c3c46f99380a3cbd68dd439f30fd13d1eb5e4c4a9b30caa988ee4a15c8365f3e274928b002719183f2aa4d8d1e8b3e664c7186cb14881aba550df7ea8a022e75ac17da060a116915360fc755802a74c2ae605cb4fa5a38774722d2ab6ea1abab9a21dd0a34e212dd138677b28f60347b608a6ed6aac16c1b3a129208caf488caf86a6a3ffe31144915934ed9f1e6037935c6b1c01018a1821a1f19e64a30ddff210cca77f8253357d039029875019801d54b3f6f433faa0d135fabc4debd7f10285738b0aa43c54020a8899c1c22255a872cc278596d00bf8bb74eb63dd727c22864529d506524fb78899fdd0f36146e5893964a57062a46fffb0a62c6a753f3b4b07118b3e2a57a205bf72e5ba07ab0b2553f5ef8ddee80403e0b6756f90a96245450abd82918d5dcb2518b9aa79b1f07735e1f439a32cc3fc84fec56a69eb29a3d101f9e4df5a673a173f26bc9884b5ad0de0e10df0dae50eae7972a2b933b26a3144baa1f0b1af323e8b607c4c64eb11b602852d4ada8e79084b65203b5b7c7a38f0d03f19236c1b4e5697bfb66c5748992e4f17065290167c262b0425071390e0edbb5a09af576f7d5a5c31515b4d3b20b9d9ff3741de590e025407316d2a17058876a8c9a794628aad449dff257c2e2341ea92706bba4223d336cfc7a21b0204b76be41f56a3040bd8c5415ac02b444382fcadfac7a1e8c86a78dbf7915494f6b82ea4c7e1f71ef52ab826e896c84b5b8692ce32da682343ccf2680e307c04fc602d66d946499b23cbc9b2f64b86875a8349c61858a52e65b4abb535b1ddbfda7c3370839d69559ea99621d189f5983b1d92c520aa9ae120a124bbd6af25fd28a846225c29a0a4a06270644", "1196ce4a8cc0400f7d3b8df1fcd00edc51517faa4173736f4826c7f0741d17d2adea2d25403133145a47f1f74538cb7bf92a18aea574960d0887d7fce7e7eb5813bba20e54b5ad66ef5c2e5b34effec0d9552868afbab848f3f9c282c49e1bd0d7858ea02d6cd44ff461e91bcb92e824bd3e315be8647bee75ad6cd3a0814eae112c0fa7c4cf2d0a7ac2fc94fb2b45b1079ce41bc71cf590c9699115186a1bddced49c69f39add5fc5cf0c8c790a23a59ffd5d321bc82772f3f374b1bf5e56a0ac1d5564da61c49c7419716482674fc8ff3846b0c7b60068ef49e526a816673a459970994c1ed65a65baa9c6f819d89036a29ddc983ad30e88721885b08fe56283339f0771098556e86bb3117974bba149d939dac60309da14eb6fabb50e979b48b2478ef9677e86eb39c872fb2aab66985e6ac7e8ff7e45f6fc8eed8ac3dc68dfe52be0a538c3660921fd669305a2d6425eca000091c674d01cfc48bcc67016a417fe3f20edc8f00e64edc0af8b26efaaad09db5a3997b2536a8c9341c6f5dc97d3400c3172863b5049da0721b23c8e0314d1a21cd9564266725054235faea572d69669ec86f60f5c5ba9b1c8e299329940256e3355d3095970e1868a7bab246854d850faac2e9bd1fb2c13da41ee01d5650773d1739490b4c6c9e18c47185baa953cbc98de09f55c42e15efce039f04d66aa0b7bf74543dd19149e133c6c4a54094cbdd46b1d9688653e0765efc9b9a30dd9de3b1f751651097d9f4f7eb7d933fff551f5dae60386ec581d89bdea8d4150c2baf6083d055a8d1a4a754386027e0ef29f08f3238a87679b1b5a9d9f8b30ba6658b8eb49cd1787e2f3648dc30220e8328ab6bd43f93b3c7c731a5930918e7e7b70b9593ca4a7dce760a96542d0b60e2206830c02383f24ab24064795df3452398a45c867391411bb669a800642a2574f2143e48df284f9b65d5c8254bb3ce4ea937bf489b6aa755d9d6bb9417b33a6cff710c5b309e2d465fd9cba73f8bdcecbfee6adfea2c1cd5c54e8b8518c48412837a1e47052c8e2a2e908ead84f40a04f248813f87833c96b369de02eed9896d6404b141b7c372dc139178197759aabea372a40d85490cc26b0d508cae925be7ace65f266a4b7f4e5c741f6bff5d2a47e796cfd713b93ce70e54629ffb28a3effc7701d1c7fea8a117a13f89bae5ffbe06a479829e18240e760026cc443431ded9ab06c2aad2e03973cc744dea065cd7e065543ada89da7668c07f82c47d69c92ba76454eb3a600a8126c73c0f56ef2b786f385890ea90dfb6293a3c1e6bc7c4caf516718a7f065ba3ed5c4629c79e32e719adbeb0055fb5eea665f03d2b4db0f56c13b97ca85ae9428eac5b8cfeeda5403cab80bfe8d190efb9c83a0781957fecbe18b91f31bccbaa9629197825b73a0cb98a8207dc8b6b69150309012928b0e44b3baff7c1de1a339cd5ca554fd6ef2b83bc31eb9ce47f723540dd27f9dc51db61fd674ff7f52378946f35a98a2073311fd36fdc7b4b61776767771717c13bcb902465bdeca6ff9ef62e75ac01e5586fe600da3ece19a0278a931b22a129bd259814b528acca7eee9d5a05a934c15b30346d5c2825a958eb0fc68d881da21d7a0d0f89e0705f3ddad78e12f4d94757aa5b367893c0b51c26d7d1f95c5c706c86832eeef1ec3369cfbc2ef061b199315948de22ca34c693bdc3883a2d81611352a37ddeb0d911d1198d3eda07923ce4fa5e097ab5f13c57baebcf0e6532989c6d04152b58e8a5a78853effff193d22a6b8313f7d8e4ffba17bea8a0bc274e31df3fcb2678c53a74ef6b886399f3878e2c09b8974a2acf704d430e4cb6ab75c7a7d513f4b670702718a34159b0b1877a83ab82ff44730514e7e5aaa6af253446b0324428a080b994cf9512c9260168f7449b3d2c164258c28fbf207307ce51a38ef356181b8e735da0568eb9d8f6d3c628bb9bb7d01a76cea20bda7d3c757ac892abfe52f05fbad4a91bc9c8a9f89030bf4b554c8b79b27fc036e9cd1ff1875834637c0d712bab59713aafcc6f023afcc547452d2c6dee95828ff3ba52ad43d763baf84fa0286d4180f2d75af6650f210f8dc18b3565611f9617", .Okay}, + {.Sub, "-1cefeae9b99497212a7a6fe63cd20dbdd38c0ad10e38ad267fd626cd6bef4b79566118387076d741a9f649aaf42618bb2532b56b81dd7da92512d335a352e2ab6dec8693b5d48b238d5e87c3b59f8ab75c3c5f02b5cdca7c365a9529f9610b27e4d98616338bfe11399bf8a555a5e1b05d87f5b007c2d1f56232ca73c89503d10edd5bea5efa769610c2cd9fcf2467db24022cf548d8c3e2cfc2be392ad868b0e03f14cf1745b96bec57b25f19890af37d700b25be619fafdebcd8848e13da228cca39720153525d79518d2f7f527ab9bb1300d7a93bd82c08235a390023727c4a2831a3b05810785dabd7ccab48bb3e2eded5880ae12b657af0066a64cc651643019d6aa2a4ccd9be6b622d69f449f13641f83f91e975eb317d9130beaa7b36412301533d532ec5ab1e152c0524d609e859378b3a087793827b249021cba243aee6b53c1ddde01e6093db5db7e11c1acae1015eb2edc6e80ceffaa4f06c97b881d92e3badf115434cd8fc9f9486709301b3cd5ecf994fd1805ec502faee2cef985474d76a6a82aa837c8fe254c8263d3403cf6c6677571f53b001798b69107af70672facb8e40567fd8ef8e9877d4da87248fcefcacc9b219be107b12533217d5e8616c2d9299d51f0d95d04eec7197b3ac652f9daed43df9f93b9257a872660b0b89e40ccf9389fe2fec8ba6f3e80087e9ef1f60fe0dcfa6886ebf38f1cb96e8ec3fe3b0d02ae68601c3f9b829b04a7983cc333a65cbf475a82b75569828fb840a9d6380ef0d3023e1c981a2f008c90228193bac0aba5076110b039799c9d41ce1b3557fbfab36dfe273e5c4dd1cd085e9a89dee0cba84704b034f1afc8bd47296fa0c249de6581bd6b5aa319108e6899223348b3f99ffeaaab53212506ab6b6a88f0bd01a818bec56571bc565e4a84a0d2ea11a9dccc357c670781d0c6a31514d189d6e94a0f64d482e5023696fe9da5267f98cbbb231194cb98bcc8ed89876084abd9229e06b67cc5e8a8589f17148b66aa5cc6161a9500c3ce4d547cbe1560c0280f13f951055f75a61c6f12d5f6a61e6a285588f12be4a21f1b66b8fe3c7fe1d80d5b10857ed13276245d16ba686a35ac812a958339d5320c5899c08b6cc66a35d56e6719ed5604cdfc1b965979f123b0bb7bc2a35e58a6509f36ea9a7ea35760d824773dabd8d63b98b1d0228fa08f33fdd1dccc6280b07a97346fffadc996cf6055078ff1aab76a3b49ee8d14b5fda0545a2b792526ec0684c3803c526d6e1dba4c6bdce18b13fa5f068442df44eddaf4754ef8074da2347238efc89060a8c558f8811aa19b2dbe3430feab2ea67042136eb4b88ead864099c0bdf27b62b15de49f42baa522c1c6f339c1fc9f4330262585ece977dcf879c3ced6cc24d49355c54d5f78f46f1eb5c2d748251f20c45eab25a18c1992f803ee51da4e458f0e5e2d0dbd66ae1c3dad5df5495fcfe3820acc5a85bc4bca25a0d5dcff2ffa81881603eeabc37a722e7ec76107bb601e4245bfa775f5a487ec0643cb729427fd9a88247d6e1cc399763589a433a2da072243420dea01118a452efb09298cddfa77e4051f7318a0953233f0303f5a8f21c6afc118aa5f30816cb70c9d84aeb8c9fce7b47ad21fdbf398c36c96734e2575b374a97b46e7e46fe6caac37d575bc2ff4da27553ca5c32e681961ab904394dfec4bcb516b1eadf5e2afb3dbcc26d22d845deed5b744e8d712701c56b7b2942da53480b066aebe31468ea15cc46706ef224164081d742722c60bfe1631b7994b0ac94d3c9818a1e0ad38f2db27ea519bb41bdf6f94dfcff47930f24b91175c6486f9dd06d7c804dcce30262245f710e6f01b3ffdc397e29c9f52d5b7768584f14e62291393c7d5e9ffb6b3db43f87865f18f696ae66c21b79eda3e038157783dea8b2a3df4459001ba959f9ee995a1da9442a7b7e7615299ae296b18d78caf2335dc27271a3f6dd6e3f2482fedfb760ddeaf523de142e17de724a768a6934c0a28fc50202d5746a4f420739679e0f35fa7aa88fdfab45eb622a7bedf8cc657436c7ecc94b97c4fe24b1e745dea9d2ed358135548ca25f10d91c5ea6a63c399580acc821c854b14d14b1c", "1e416c8b222e6670f6b46fc4297240bcd5993e870c0e7348e64ff8dad767f36ce16ab974b9208d562b3734c7ad18b94953147d3d9145304d7efa98a92f57502349de2f1aea707863e2d7dcb8ce000fc7b6d65b42020f26faa32c7421eca14ceacb9ec7e3a5cb45a99c4edf61923ddaaf39beb771f30ae709f28ad05752c9b89bbcd434de42e3a2272067c9689298eb35cffd422a75926d917bf0b7b04a43b58ef888277dc6a89b9f0645767ea5761a333de70d48d54bd399629160d65c24812dd1c161ff7c56795cb6e936238cbc62c6084857e160b02f9e8d27fabb19c6d4ae084d929b1c20be473fe662c7f83b8d7788b138d132cbbbf1f01ba9ac37bb7fb7aa0f45d600d1b25de3d7150bcca3c61e253f90f8fd0b48d983838eeab9a520773fa66c7c093caa53c9ce12caf5703f0c9f2c21b915d61d852a734eadafe90f3f0f9bcc0913446caaa44698ca06909b3333afe2f4b9b77e281547b40d32f2b708f3cf11b76198b82a2e7ed15b4cc212051908d995e15b52e3ec6b00b48f1a9c13c47c82259fa4d88ab7e99f672407ce28a06d1cb54c5ec78631740c5089f25bef2557ed35a48d287ead579d3f4b5f81b31fdd220124346e8393fd08658819ab767d400f365cc096877426f03b474b75f14d67780d00dfe74f7268be118e41937a6f4593ceae48ef3b61dd7410d5b45db9f8186fbbc3ed4c71b61a59287bfad7b25abf6379a869767781facc2a7619b0820633feda848f29980f9c4de95106a45e8b5d228fb939b1936658ad13a10c77a8c56a753c1964b8e51f1147f6b927b400d63170a0d6b999eb8964ce13c62b19ad470093f6185c2cc54e09bd0e9e3bbfda31e9c258b15a3f2c65f15d1bcb79535c9567129d9cddf001268298f2a4142f279d32a4be78be71336829f7d2e98c4170977ac6051983bfbb648e05f4702e4ed1af250095f16a2072b24d3cf4054f3385d6ad87c95639d45fadbc2d727d19029a55bfbed5626ca64c4bdca9271b89cf001a96a408426d7172d008c4f9ed32e03934d82a7d74b426601ee4203d577a1a30bb745d82135031842ab46b37eb6171fefdd13063e83bc462c64af0e018b873cea4c6c84afba866c632cdb32fb64b758420edcdb5173d6e7eeede44121d5112dd97d115a00c78733832ea0617c26ba7d533e59dd88028df4af274b1ec1e30fd3152eb05ccbaee29e69697bd008347f2bff10a0971127cc6cf8c587129b24c0d739d2a24fea8a40a8076b4a6a7079449a79427a99c3e085568641fb0f82748484e7cfbdcd892ce3f2592e06a7ed8729ede81443eac10bd10d0b854a72cd12766e73df488052d34a398963471b52d3fbf64b2faf2af05d3cce9e32f082b1e0b65ccb5e985f9ccd1d0b25396b595021883d488210a8f6d6d89961cc798351d770a36e47e88b9f2a18e9644f60c6c9a82d98a5a2a849aa0ebf9451b4c0ff19979f0d99d9f79d1fb56bc490bca8e9d3e2ce9f29b2e4282278b0aba93460fe6a865c00218286aa71f36648a15cb205672e27153064a183f8798674ae68ac18fff6b61039c0cd78a3035e37def083d4c50a15445acf54f5a4bc04008208c5274bb1b9b3c8ca3520873d2c64a098ae66927d7c147f7e887d8332df413e86806e2b0eab4f170bb7785857d3fa4917a0bcf4e17eba8e1233e82eb85ebd3043a91c21c2c710406bd1efcc6f4dc34860d78c8d9800bf0a7d3282d52cedb2f64f24dc258f764da82110459ceaa995ea545765e3e5640ca6919103160562ea50b9cb887d80ed40f10e2d3b4ae894da727c93eb9fb9371a64a68e3872f79eb4730b1b251a023c62d159fe6b24d1221535fefb8411b3a0b0e404002b26a56cd42e04a7717754aba1e098b9dc6745c3ee1c85f5a6d2137273a7e22305cc0362ed5d33e368dd666f69c8b8b9b7439b96c0d41ecda1192fa337f93d92be9c8b5076662dd3f18d33b3cee882641d627e2c6b3f7be5399995b199e5d9a5e2f9432a38e200dc47bedcb4b842aa26da9a1cd4324bdaa7952db60103051b81bc628dad79b17b22a2ad65fa89bd1795d9848492a9b53d14a7eb5fe681e6e1ad0154e592255d2a779e442b4e0efd685105681bd18eac0b9b174", "-20106b39bdc7afe3095c16c28d3f6198b2d1ff341cf1fe1b4e4d5b47ae26e82476d0caf84027faca45d699625c5b1ad50567a89449630828114bc5dc898c7e4e00bcf78425cdc1161badc535095a08732c9a21322d6c03a266921d748c375d9d49ec60450904058aafe89eebe79838ca3f9736ccf387142948adfcfe8f5308d8cdc20a9ce8d349908173f6428f8b31b3823d64f9ca1ff9cfa8ece393dcf13c1a068c18cab81cf735c50af1a4970eaae275be0dfb3131ed94607d2e5ea505becffa8e05969c6bae828e7e4ef684b18a71a3f987eedb43ed214daa305ea9c90bd5ccf015b557263f4ec5c12044c2f0192b6b9f2629b379cea847caaa12de0846090e3f5facaafbff2b7fbdcb2ea3430abd38a3b07cf629e038369b67fdc58fc82aa3b89c913d11dd40247ff41db5c28c6d3db1b531c976a4fe629b00f6b205c9634a8a375cd5224aac8a4fd67fe20eacf4e05df30aa4e65a969616b3b781f980847beca49b1c77c97e634c6125460a790e4924166bce54e7e10470ed04bec97ee2be01c973164b80b5602168654954508c73ad59ac12c63cf826af0c6822a8ecf6d4c8546551460c8415552c3834e6ff00c84f6afe13ff3b1eb598e96d393ede97fa9e954d1f99c024c617c9984c3a3d0ac8a23e5ffabad493520851cab3bc1aa0cff64c6cef15e87401c072d990239c3a00970eadb9fd2d4eb082e0146f89f46bc94e2777e3767925ea5ae86a119c4b86adcc3b9db835865756f6d0a0a67026ee439dcc65f148a2666896c9abbb3b7835558cf6cfd425648a267258a6f2a1509e17ff8bd62eb5949ef762f5522278eb7a4f5f2e7ff73cf86d950e6d438feb8897791331f973a41d91e7aec8766e9263eafe0034d0e591e9a1252d4445c53935d3089d2daf35c0194c26ef5d44a5e29fbb1c1b98ef2b2d9c879a0a6cfbf1ff1574c439d21fc8536a821721bfd90785ca847452ae48ef058f82bf50f90b39e1f023dd2043813b8f445302596f0fc3e26e172f220ab29f33878d650988c83a875cf74a38eaa583c81fb1244395e373e92d06b21a7bec3ba5ba7556990d5706c82afd3a51123bf596d4e8451c23563d158a890d30fdf77cd2fc496ca2e53c0ee5360f8db437eaecabd598dc3448e0196ca93711c23950c7f435db9142ac6861a2926fb288f539584d56889e4d8827b6e2cd53e28b9500b8c006b2f9186d7b1a7c62bf9ed3a04072d1ce5f7e032893ed95fc00b1e0229efcfe35f99bdb92ad8c57c9e3e69517b9f854c14545aac4f2864ecc915c40cab387438e1d9a2e0cb34aab8ea711a4e77169b591eb59efd4eb055865926c9af84740a3585124e1f7f5c7007d572e5da40cea730fa48851c9f2114527c9552cb61ff257bd9bcb73ae0ec5e75aa0acf59de532bae90f1136b6eae04e525c039f4d189dc730225e89047088d4b3d89fb992f8cdf9b6abc9684d9ef76f3a396d82fbdcc7b142055794b43e1409e92295afca982b79b67e0db83e656fc6c7bd7846acecdeddda7fba530c5cb6ade3e72e47b2c7ac15d567aa2437c5890f94a67613f9cd7243cd7f0092827b4baa7dd28aefc73e50dfb320c12184a8ab4bda971bc518b834eb70a93a0c5320347545f6b0b284bfe7a8c633c45b9fa61d81283f96312afa2ef8868c75e9f299fa4fc11e9d53335d12db2878c768f9db7dd801479b9d0b489246475334035b788d5bd8177a00ac8b41a492744dc96032754e1c8d163ea98e4f5b000d6376bcecdfb3053170083272c45e4c1932bf7e93d62505c6aa2dde7dfbc5e5bfc9a9ebf2ee6e99909c0497a30ee9802700a62b82926f574472046dac2a18f91b64cc8671415c51055126f2cdaa5490dac2e7166a4b0230a38e7cec289d6fd2a99e495a23d5126b32f68821ec29a11541f4f5d568146a77f403c985ff63f76052d1ee94a732991d1535b3c02c706ceec7b576ed423e54147b374977b24f09e0f36595378be18b0799d3a83cdee67084d1018baba09533f21776ac96a5f1ed707c044f6d734ef68a114517c370b1d8d24f76684cd2953f356228bcca1714dde417a3b3959d2a5c52bb9cee2828a3a1ec7bc3b50baa2d1f44b36fdd1b2303d99e35d58afc90", .Okay}, + {.Sub, "df41d29a019f0ecd73d5d51868e93322cbde48f663629054adad27a56d3450e441ece6416fcd3267be82905f5dfb03ce36f3a4d22d195efd2f042a24dfb5611354686bc224f1dff7ddebb76a942bbbbff70d67e574d5fcfe0a4d2b6547286c83c580fa11c67dff9bf288c7f8a5f4c0420544f7608b68b0b029ffe36471d7925c5031f5ea688adc6f66163f5b2c88bd63be2e6c66d1b778b7d57f6eaa629b74e74c60dacef84532c99e2ec671880f5dfddd8e3c93c5aa4aa41fecd5878c66fc0244c02cf0798833a94e38533ab9b6362a17d0f3f8ca0a473c0acd38635f9458799692da2aac4ecfa26e4db2eb12c014223b89f77cd480890b1ba695f1e496adf9544e689637a6d330f9e39712df37f2f4990f740aad4ad454434c3a03560fb8b3533bf5badd7162cb8470494311cc8d3cb3cd23fb20db7484746374c5fb0c4fc669fded9e4279aae14871866f394dac19c5185615bd9f81cde1947184aab2f3f3ac56d68aa6541f141edf14ffcb4f70876d9b025cce6fbceada5ebbedf3e17a0d26722ad4f64ffaa351c7b20f3002c4bf57cbef22b148021f6488702f7543504b4b7eab99fa86a2b7d73e105e74f2afbe92524eaed93c7f16dedf66736fb98c5811920e022261a1016cfe37ef9158ef714061152e7731dba8006644e8ec4d47bf80476a9d512dadf563674547588cca1a39be57ba47f267f19a04b100cc3279252e674b3ecec3e52f803b610fc63cf587dc5ede63b521dbad4911bdb48c714feb0927a0aac7d8c1647353839f3e7068acc4042408be96a40ecb3ae2ff47ac76fe3fbb511f9fc5f0ca8bedeb48ae65a3f0c17914e3654c105e9fb5f39b354fb9994a66364d6558eb0c2c0cdd4032120314b9e917fa5a16ede6e24c11ac2ab413ec235e63c3f98d884257ae00bc3a589e8ee337038f31799cf1c811b0dda507c065bd876791294eca5a003f082eca94f61b4aa3470e784116d804881bfa314686b8a1bd77fd3d9ee0983b17b0038319fd8588b53cc46217e870dff7b7a6064ab999647b5a0a687fd849439fdfd72f64cadf6a7f1fd47b24138b473350c35617d181ace4cd3bbb1ad0e99051c103621f4244ca5221b0a79e04be55fac21fb34462a77b3635b8af5c9053940daf1f37b8169702dd2a60aef3c4bd511b10104d7946dd90a67fb48e01cc1f8d28b448320a83cc87b8a87ac9e57f5cacd7462bd4453d4b53bad9ae9d3e2f1da3684ccda891c834f9e4adaeacd716fb39ecbb89a813b5a1503f6eae8ec9f64c27cc6ee53629fde9267b47fe73f5d87fd0219392042050357a8ca77c9f98ffb7c94ed65b0ac816d4407c7483871a0b46a41f71a69081b284a339ffaed03a71a57834e24de3c5dc1c417111bae3a26d549fc0145716c65b138e65280d4a88ae7e0bdb71644e03b6c463fb936ccefa17fb481aae6fa047650c897ec8313b4c99392bb5734a1dffaaa63db142d2dcd20496a6898708ece00be12f76b79784c6ef52c729da07b5daf93058d34f7d00be29b9c29ab86d09315519eb926976d03475cce97db6ccfe60d70eae7e60f88886c68c5cada343ff180644e70ab71514a5097da5d0ba8d036c859d6e9cfef38c325df3bf5c28baf894b24102ad3baeef64c0bb2be0852a9a3ddc2ccc7d553dc674afafa2447dd1ebb918a112b2f16c349e60fc74b35b7929b7c971d7607d81f04f75090fab68db3c77de474f81cbf8a4a0a977c5b22e7d9bdaa7f726299224be105095547c24def68b8d1e4ac11ac838cf2ba9094373b2181211e0eafa6ed5237a20fae91069b1a301313870752a276855cbd79a6d1ddb3938a3eff56bcd6c2d5a9204179ac207c54392d9d3ae7e89610cb362e6d48b5cddf6b4962ac1c24273608fc105559ca2f452d2d5ce7afc4ed4e971dc20f0b8963f122ed6be8fe9eece0038c6ab7a879a1aed8c0b1679d3d02c68d3ef29502c74b3303cb0fd6972a45ebc5759085c09c8cf9402919dd59e43bc66f0d3c102ee44c4b7ab912d0f41af7edf803577c46735f067dce981e18abdffe1cdd5458bebb50bc4c5473475f67a16f8e0d85cd2309e7aa1a1f58bbdc4f7e88de2535ba3babe761f18a22021457653128e4f769e422c", "50fdcf494319b6d34350bb2127e9b11cd8e1e23c2d6b41078605ac8493538e850667055f5ddc11427072b3c28158f839d728c6d5794d3d656c48940f919f35547acb43c0cd96cea6d5d7d9e85fe79d41ef626c22eb6bdbfdbd5bb771422b9402444f534f0fb99c3af93c7505a63a213376891ce13145dcd538e8ccd745bd6e2cc802e9100bda292d8dce13e3d76da3d23f379694eab66105c1b11091bc9cf2da4169d3eb05741c4e239c01a35e6d94610b80ffb0c5a83e495d8a713adced778b054bc7393b8db698bd8681c8aacede65eee77ac498d4a369380d52996a7204e1eb9f1a26cb2544df32a2942e8572c38d5ee96b6ca11ffda3a7b6dcb2fa80196a04b5775cc115fd7b5e03caf3d91e772d6466b302e7e0ca9e632a3172ddc9b857523225355e8e35c8dd8793df1a4dc21ee0a9cb0ec3516ec573b9a6acf3fcaa4b803aa1197529e8423da4ac5cc9a3797e3eabe255a659335faaecf4f1f6cc0a07d213e2b4e2e74efd3ba6cb806361e7c8be7ad9d5353b061913823606631450a44e16469d6c1d82578cc014dab98fe8b7a9edb965c4920df4f397212cb1f68c43e2751221db1c84ac43cbb7a12fc46ff45f90f99f4164cd9cfcf4a6506068b0b4a4b218a0bb0fef832040f844b71fb7ae23641e96fb7ac985b9549161b6d12fb350ee9bce7a142eb16924d415b00cd7738e8bb15a65bbdc96e71f2390dd37b46cefbbeba08189b16e782e2089b1a0150464077aa57d83b370aa53b5fddc1d4b95f795ca6adbc54d53d87b5ec4f66bc285df7eaf035e94df5667db9359753b84c2d065ffbe8e2e0409312942790fe210d4e08bf768a1a5449e51666f61b9e63e27d4824778ae1fe8cbd3f5a51185ac54c7511bb39b7b985f448023bea6aaa4bc84a47344187bc183574f75f08338eb011dd983a11df6c287a3bdfb3124e1ae6bfb29e6420e1c1362147510950abd87c4c9ee420b2177b8f2984b4c8aa1ae1a84d3c26746ff531a4803dc82802712ee59abef462e51d67f8c4295cf376cb85ab42c0ec90954c1b3c000df0613f2c56daf67402a7269b054a817b073974b0dd8984ffcf37517953eb6027ad3695b0720045dbfe1a03a8b7db1834d57eeea53a72a839482c272250e53d52ee5e396563e0f4df9d4be5e8e9d8fecab71a7836e10e8c8c18d9019988aaaa819f5e41c925cc170b563714fbff77c394dd4d8e30e34b9fa1e4c3bad89a99e092e839e90224290d571e267ae44b843a5b85081cd45f8fd2803499e64a5fd5533905cae6a487e44bbca7d24f96052f010ed40ae2618c9333b068499177eb67960f17e51ca6f07e6aa58c9dc8e516f299d2106ff4fa90fed981c8b761fc787930b87a9e3b857d673e8543dc380145fd95955434246615c905583d0428d6469a25a3a8ffb40785a6e89db6bfb7f5d7e288181a2ed88d24603b236757dd23aeb810baa6a63738cf9153e718738d8dac8d2569c83ea9494b2f1a2cba1c552084082ccb11dab0ff39d1cc9179e68baf3fd13fcbc81812e5bcb8cf272b252a86730d51ca6a78821ffb40c7bc0eeaa19e16755aa8dc441d923a0e17bd876a54fe766681f060a736144141c6bc45faf60533951545e730201ba827472e09bae3df3e5d60783b7269e9bb1a0d5a6cfbfcc9ca29aec8a01510f497536d65bf3a064061eda7424dd7e424e41a1266adda6991ed899b77563a9634ab29e994b8f7a1adca17ad83fac9d9f1ab32e0de58ec87dd28d616543edbe6a92b4355f99627eb593c4217443d01bd0a1ac80d0f61d2c92493deb7f6d92c847baf2a2abb8823afa8d88e385eda78fc1620234027770f676f0c8c3253a8d02ce7ad75b2437d5e3d4d519733edbb462873f25fbfc3ffff83b270e3042247f53f71a0b5c51064ab452f6e3dd38ef2e467c72426811ca7386698734e7254c25ba71b9633a41874fb0f32bc35736c72cbe10978a31eb50c7033c86c8d78a959e199f06cc81392cdfed992507c4705c3c6a0bf79b16a4b4ec65b607a916a565d6e3b54bd5f7e3ac484cc0d141199151bb0558a3de424dff895144f02c881893560f42d43cb0794b7c391c8fb177be2087c3a555c4e264d0b96a82c2d462cf2b9869e7", "8e440350be8557fa308519f740ff8205f2fc66ba35f74f4d27a77b20d9e0c25f3b85e0e211f121254e0fdc9cdca20b945fcaddfcb3cc2197c2bb96154e162bbed99d2801575b11510813dd8234441e7e07aafbc2896a21004cf173f404fcd8818131a6c2b6c46360f94c52f2ffba9f0e8ebbda7f5a22d3daf117168d2c1a242f882f0cda5cb0b341d8482b77551b19917ef6d5d1e70117b213ce5e18a5fe820d0af706e3f2d1167b7a92c4ce29a1c99cd20d3ce300020c5ac262644caf7984773f7465b73dfa7d1090b1d1720ee757c428e979343135a3d2d2bfe5c9f5225397aaf3c003e1298ac33bab1ebc8d4d5094dca08c1033608b6773efb93eea16948f4f98f1397690d5b59bdfcc1f06197bc734a8c107c56a09b5e02208907846005c0109d0857ee32d02a6e8b563f77ecb1dd32358ec5d8a05bf00a9ce19070fa57ae9c34c84cd4fc29f0accda126faa329b866c73c017464e6e36a77c92b3e6e9ebda42f3d5c36cd016e338497f67ed88beaf2028879934b6d1c6dc85e790cd2968d85be4378a32784bc5079d347672dc07adde35bcecb5f42a70f14f02c34cc407690999781f6a1e0b937258bd452e3fca32c1550f97d7b179e1eac0230f50dba36cdff5616751b17e4cbd3faada3937c31cfcf6977bb712224711b387357c180c2f58ceced7197f43fa427131a87ff2a6ab32a65fe2368b5ab2e58d6feefac4b83eab5f9e4d3a33c1080d4086149ce083785763be379e283c9ebe07b6b05404551191d63fec1374109ad824da4804a626e48575056001c4b8635f4fa5d270f23b6f5551611197ecc15ac4a8cf9e83931be0ed1d7ac3a6cbc04e4f84397b697b7175e3eed4b73902405817382eac65ae4d68cd645ede7e8ea262285305800f57677eeb1fab7dcc04eb08381039016d9d7109b362713ab7154e0a167fb8c359546a93a125830d3b68458b2e73240d0d31515c613bed0088243fb93b9158832c01e4df5630fdea8498945e952fdc702ba3d9996f0e728b985c2e4a2880394df0056d55b250b5a6cc18486499cbe469f71b782a54ad6acacf6b7396bfb978483f3931aff1582425dc1ae7157e57a85aff3de70a7081761c20533b08a2d3355f9d3823e6b373468a4e3c7e6527cb88e17a074909086c02205634d0a5a9688cdf685e14cf18ef9af57721777332d02b9fadc25bd255372b09ee03235f026d48c6108351356e9e011394911474e4ae3d864f375f88024600681ed355819c39bc621ab8794cf5d049e8cca118976fc07aedabb92d5bfe230513a2e86ee2e0e56beb571cfa74080e6520e28656d7d084909bc03029e7b297f535aae1a983187256e771c4ec86ae898f08b2de99f08afe958bef6833ed334e3acf4293fb4a7cd210b569cabe0a94e57fe61f0c23d14b7623d5a9483a888f97ed717bef79c677c0e6ce01615a53094a5f0061182d814b0fd691069567cc2a09fa020932400a059c74582d1a3e63d4f2457c866c86160c2ef7c23ddc674134e6c20cc115bd0619373ead65c82778e016ce6903a0b042d62eaafeacca92ed8fb6dea71f70e1cee9616adb7724c90e9411c52d3ea15e9fc6472bbf586931aa3d4f9338f90c9f60e926b93e123dce22118d70fb7eeab3a8295e8bfe8c3b5725ad957129d214c318432cc2a243e1cab6bf51082e7f86884fd5dd36db76284b6c82d6e8d176db519a47bf77f1c53fae03f251ddc7ff2e9f860590de812779e9409ac9a6eb82ef30108e667463d757beb15e9c12a50b0a34c57357e17665910ff4dd4242da3c357b7b7da169e80e8e8cb7f2ef2cdacce851acc58e19d7366fed7dfad6f53c91cededd0dbf394a6c37b59bd89ab48bf340240b2028d59ed0b899eac1ca074c525f7ee0d648abda477684c83047fbde0594a331c27219cccfc6c4f41c638546cb51a15f54cd28618a51c98f2a22dd00a57cb862236e641ba60ac5aca26f67d7f37fce72bdf029c8c7815870f5b0aa975f2c6364c68438cd1c94ec7822dbf97736699011ed8380a491e505d5993dfd2ea0b443f3d0e65c67e682f934eca53526cc58bfc97c215ba664f17c40418bdb58dc6a953b1bf719205a363d4f67daf3903e2b804b05d845", .Okay}, + {.Sub, "-846cd32e7c43effb59869e6b6fb7542a3c51d90075e4ac7a3fe366f1286c7f2fec9c8f7b0f5168e3b338d9e5415878c4a9f7f61bc6c37e41f8f7b796171acf9bcde78afab211757a04f2f27f99659c6fdfb7484440f4ba9231d0af06ed4c7396c7296e8e5e6318844367dd72752ac0c3baf41a1b7d31889e36c326b1a55a723d8907b0626f25080c765fb933c3b1f4a55c2db713a00ee4faee7ce0e56e3b614a614f5bb40200c3e400c0dbea0a9294423b955486f64cffcdf797cb9f08381af5c6d9d53d9c511dbcfa631b8a243d0b15bb6ceef90201ff4e318f8d0eec24cfb3e5ae4c71c4dcaf0f92b2e22c4ed296843c03cd3450cda129f89c987ce2ca22e483b7bfd8b88b80c32c3b88cdaa99e943e7b3f6742e3c11996df344422611c9d6ecb9703ca60d892d35b12f064479ecb96590e28bd47dafe8390426d55f314e0af80141568eb3261fadee9a12b9b11cc7fce3f671eaca0954cc649e5f14e3850604e990adde6c772774a047c13b0480c4c427f8e4880318378c6add4173bed94b7dc634f6667a442508923d6802d63787545e577ce4bc9505ace1dacbffadd2fa2dad367e31b9d16de01f264abb8934bd58e9b99050458bef56be2a63dbd8f4b076f97f4228393e5a9125177f089e09cdfaa2a449191f18986ba57202ca527038c5f5e18171bb3e37c46dc0c9967c529d1b3eee4171c39f3830aa21ec011849bca86307bb85c2173de7b107cd5e08e530ddd769b4b7acd388ebbe37c43184f1771bed7426825da30381a5a8d724c130b1f606a5c5efd3e1a77a7389d160dc0d1935ca8bd1d05eac862fdf98c0c3484ae3b5054ad1548368ceb80dd898475d0787a930b61d9560a39df42fa167cbada272534886d8741b938993a785e2f60ccfe7df41c4dc4d3a23803bd8ccf11022a8d67eefcdc0c0a601f0735ea775f38e728db7800f4fac82cc57bd5d8cc26835928e38e6b1c1c323c28913f81f28bc2f3950c20d463071a928bd6cf13a603de2157b8962b1b34e32f360a15c8ac6d2c3e92d0cf65d3554dc520c8919abe3ccb10a035462bf2242de5c1a288b043396078642d29e2e1712eb1689e1c6164d55ffdacf1b478c2200144cb52899cc2f49bae77e9bd10942918ebad00db98e7e15bd83ad3698338896e1153c422b914dc6b1a1edf4ba60f62d1030afdd69bd73059798b92c3375db53a63b0b1a35b903f75284ed9b47c71998bda8891cc72f51394eaaaf07055f3748dd1d67cee80f04b3c186c071a09f0ad9a1060ea1d6d3cee6a08f1cfcafc2bc1a98030c9528c8bca11e169529ca14e3083cd420473f7a0b7c6fd816122ae65a4dc36dc32cd71f13c914a06aa6a4f844419ad2bfb8d46fb2bee008b542120b6e8fcfa5de6bcb3360ee38ddb07ebcf6ee8ce3a24245f05a77ff66ad9dc83ece583bf9913de47e811b06cc9c17cface1a83686cc99fd907d5b8d1e54240065dbbcfe0dc2448244c569eff3119aa449c2591c1bcf789e30478f71e04676cb26cb29d2eaf2d63c02f356c9e6520ff9de0ad64e55ca0d6641f96cd49c96607834dbe96f25daab135ec037d619017fac0c035a91461f358d61213f81483e125c3af44315cc190b5829c7009067af741cff8f2a862c89facb32fb92cf060dc4ec81a0f73a6f1b93b87aa16952b456e18cb801bb8fcc191c1aaf12e118a8fbba19274d43bb2c751294adff91c963ff76eb10682fd090d3b28f64c5698c416f8721ec07d158761848cc33331282cbebe880b499295dd633fa67e9d9f9fc8dc2543dd1652813518e7d9af30eeb9d2101ec51283c0e3f677fbfca1daad630e389f3ecea3358dc0f0265a691d8f22494b4433e4e497f182655afe4d4f658ac9b76f6bf172811c63aa51b131bb452fa71815ed9008cb806a4114bc52e6b2442f11002ca7941a35ca7e2bf4486dfd04e3c45faabb0aae06658dafd6d1e09e0c08effe4b2674be19fe96881a2b4db6d1cf9f17a1fbc02f16103d5721443c863309bfe4ef69a0feb85b2f3c1882bf4b93d1aaedd590bdb2f79a8da267506db9f74617b46605ade59e27e16714431c6b56b241012d09e3bec936ccf93501db967994782c6a1ea979bb45bb5ae8b24f9fa", "c1744b30b46e7a13f7ab6b42d25a1643dc02bfb793587d14a83301917a362945b3f6cd5b502f1185f7dd7ae21e18627f412f82d81d8eec952e591bf5b5e1b800c0a1b796f7c704e0dbf5466fe0b23617203b9e1b6bcdab759c85e153a694f098fe5db6585f6d2c861788b8d745501d81872364bf84f526f398c244fd7855dcd341a411d3314d5c83468a661488bcfe202d9f0cd29f222fa2f07b8cd155a7dd930e91040af26cff7c08da3ce4bbfe699d539927e0dda287124a1a3e3aa523bda6ac2916dd9277f59d3779f6e086a9d63f4b2170d9d93178aab03d0237f9d1eda6eeee465a7bb70a422da83ebfe8ccfb05dbbc70fd80258aac0e73f528710887d750b12a3534b0bf088391e8634d53d2491d8705bc653c9fdd65c878958325cf85fcf8c3a595469071d7180432d9da063ae208a9f1d4ec21bded88108fec909ec2b49d5871dcce21a582712a8c6481011361f8c6d83b882e4116e8ed3e9aad1ee91b4143ec05798c8c0098f0c1a67eaf27325bb48fe1ad593bf41f25b3b4f377b7d059da0714353f7b41af08883500e5048de98be60d97fb8b6e7f780afc9daffe7b50cb002d57ce571a24c4c79e0f31d89202a17311093f3cf0f78922f2a0616130fef8021452c44357cf09f7c7911492c070989f782cdb345a907b9976e03f259da2d2c582081c4e79c8677e74f6f033d49ef3e0bb775a672d9e5e7244c039cb2ca069cb3f0a1992dd263b6abdf6dbeae223a1f1486bae9a599d88ec379a9679c693a68467dc3f2e0140a8e6563f0acfc981de0f7125a2b328ce1ad1d0eccafbe6654237845ca37dffccbe0c54941ec93a8bea5d4d084640261783cfaf1b7b9ad532a4560791165f43eb4de5a63ef64a728f9890ef40e98c0b5256e73f014033e0fe7c909629b4399e0f45f3eb3cb4ad7eed520499516714c9a6f77076d609e4d709601ce023caa8853f449f1ce3f4fe4e1f85b6d95e70c458e08d62b3fbcd567e38eded6156d8858e3a6035b0cfd9ea1ee77ac62141fb58c7250a2353cdc820ae63316c0b551672c30fbdc1cc68494028b8574965837cc5c7ca470cefc5d31375a6b234ac38c8a3208facf37bcfa11f35bd7d7a75b2474ebf8826bae5f43a92703c2165d6a03fe41038122dd3e42f208a71d674e6f184f3081eacf1d2bac2b35e1ba91faa007719fee0467fb4f916c1cde3a2b3bb1ca6a73978ef666c091b1925ad20ec3cb05700930701e34ef023ffb20d0fa61ca6e6998e151fd61ec166aaeb81b026d7d9d480530d1ce5ffca1a16cb31627e3fba8be45809fc00fc7b9c6f06ffc49e9b8685eddb96a02b18ccfc2bf30986c510ffb7b0260e5f1a5e456da26feccefd94bea72351de1b19dcb859397c8f2da1acce8ebe6f87d5a061374a9edccaae1307952418c51b690982432a34544c7746e14390ff577a6d6a95d7f0fb1051ecebd2fb3cdedbc579bc9585e4693534dde0e850930b5e3ca07855efa1006905fe03d28724be3ee9af1db458bbd8747f21d06bf4c1898791c31e17474bcb5f859fbd1d784b7bed89bcdd7475c36d962579b5e18ed20df04562dd6d4e8e12896ce6f5909a7a058d76ae0f031be12f66fe86545867cf9c09c7530c545ba429cdaba30c913bfd50bb4145ed83648363b43923b8e807da2c815d957ebb7098ddd3e3359bc2c88c1f0160bd0e9b241205cdd224a574d3a11d8094453359aa515d6fd6da1c8a1f5fba220db5c4184781b21554a3cdbdc4d6cc132a1bdb925cfe2d480eac6448572825c1fd12e4a3d462c57f43646721bddf41cab3c165f26df54e70ee2f06ad0b0bcf0ca9dd5dcf9732be4ab4523d3746e74376fcc8385ced6c32a63ebb94567ed5d300b02953f12ce8890ffc6da8ab19abc78aca659948e82cbf5ed06453d77904b1018d8c12a1ae98c93cabdec9a66a7d3d6e329a306572a96813fa093c8b049217d0fae0c2f546120b5e00832f669d0330efb06762a01997a2549a7c73e878873e31547c9021459cddde466c1a00415ddc75d58db4377841210b6423c30d94df088f15d2c17b85fa095eb8bf800dcf0e821219d7d93b5e4e515f8a2c4b8ebc8da401143be56e2b9035674fa1914a68c1b67bf8e4bd", "-145e11e5f30b26a0f513209ae42116a6e185498b8093d298ee8166882a2a2a875a0935cd65f807a69ab1654c75f70db43eb2778f3e4526ad72750d38bccfc879c8e894291a9d87a5ae0e838ef7a17d286fff2e65facc26607ce56905a93e1642fc58724e6bdd0450a5af09649ba7ade4542177edb0226af91cf856baf1db04f10caabc235a072648fbcea1f484c6ef2c589ccc3e63f31149ddef86db6c3e33edd6fe05fbef46dc360099b18cec690fddf8f2e7c67d3ef86e041b209d9ad5bd89c7302ec1b2ec9135a31dd126aaae6e155068e5fd2db3377f8e1cc8f46e5f6bd5ad49c92cc4093b951c05b20ec379f918a17c03e31d0f32bd607108da553d2aabbd468ea0ded3c3fcbafcd7130f7edbb8d053afc309378b176d3bbbcd7a937995ce9b233e23b54199f0cc933391e53f2f447998c7da969d1a6268c37654bc1eccdac9e99c86b8147c5305fc49f1e321ddb5edcbd4a26523795e34d8b9daf90a3ef202ad499e3e603b375393882e1832febf683ad7469b07173808a02f528b251034e200efd7aaf83a04a4145f037d71c8be247e362f25490911b6152d6fc4b82f8a8fe017e5f119fc4fa43eb1259986695eaec5b03614ecb2c47b5b386ce795611a7f877443c8c029de8f42176d02f1e60bb133ce8914bf3ccc635ed9c4132af5e6398b446f3c35a863e3628480b7342d0efdde2222d3af99f5e48805e45d88387d5037186c4cc30d0c4d743381bffc11bbffb0ba600188223455bc0b0691f87f0e2811aaaea39e23182e651bd7b003b81bf8883d560f9845aa341a4a331c8d8151c2fce0954bb50042fac56cd17dc69acef91352ea18baf0ede255c67f67883227e635a739cf1b9fd381aef4d71ec98bcc5d81f69635c7d159ef9dcca350e101bc040416ce363d7b9d9e812e4fb5f5d83fddd1fc559f769053d059ee66a647c728e896f6c8ca69700429cd1618519878c870637789c82334d6cd8ac8b702b06a74046341dd3000142fb2b9a95eeb1ef65a84a2c796f74eeb9688194ea2691b14dbb598ea16031687f4c2969a5991953437d1b166ba861d8dff0554b4085cd59564844e04bbf23df2d0255c340d1cf7bee5105099c75c69403e821f2ea2faf22110c0d2aa8682efab41df1a0abe9a1b2cdc10a09fd7dd29a2f4a4a3e3f996c64a152d60a15d710a7c9dc4a03f2ba90af7afa17188f0ec2e1b253aea86a635ba006c0f4e805d56dff89afce3134883eceaeb9126edd658404015cfd2edad282ed6b5d224f31b17ada8ef4e3f0b4e66aa933c7e1253a5a528ef0ed32c4bd9d99b30430c9d981a3c35a0e22d61a36953cd44205346d1f5ec3257352e57e2e275a0e0d1691c741d65979e30ab28acc9b9861eebea139103c9e349cdb5309014f70284f5b87a5019478c65b0b0bc38181a9d7d21c8b459f1d3d223d3bf8ee859ca48d12dffece9409820978d955f71822a4388d359ab99de65e554fe08165e245e2b29b0d4fc05ceea2f436dd19f6ad2639024f3fa5ecfa3edfb45fc394b674e12d9ddb5963aa936bce158953cbb64a491259ce0e5a559f50b4acb903a4231543678f923578ea5021e0993b1ad7cf4e84641f41c3397a976e33e8a761f11a0ce4c3539deaab32371768874b86744180526a9128a0bac4b02276f5c039d836e80e24efbf609b37575294a53b1c0fcfefb3cd0dbfe6f971e930001630154244c5230e50d45ae7424c5ab0336cb1727b2da488f1393740ab9f163aef14df5d4eee1528ea15c8c3458da62d5c2029e6ecdea0622519bd14c98f350f6dbf65a6d0518f8ef73ac2166b14ec728b8ed6c78834007abcb2379e85961355e9a91d8ea12a81822075e48d05136ea52b82e5851fac9dc85f7fcf1395ba715450e29de619ec4359ae1e37d0f10bde1d15fcc6bbf736e49fa8cc0725206d03125ffcb2b97a00b3aeef62bfaab41cf15d6d153e18eaa3b5d511f01067cf1106866bb2926542cfbd13891c74567f65497c5cb0459844f351e19b2cd4e07c0585f4519dfe01826d7492effe646ffef2873db92f041cae60efe7754fbf139dd9f04d24f3564b9e8ea6825e643028683822295d375131f54d077312fc093a392cfec47765071ddeb7", .Okay}, + {.Sub, "-29ff3b28035fe087bddc8f8be7ab824801df05a13e5ade5f509a38f38a55d1a111102e1f2e861fa189e10140b80513eb6b88157ef1a0077c7aa8fcf39851d0f813488a58d49a9bbc68c5556a6144d1678907fae3f54f7a66361b730fbdf75e46c0c1716140d451fe1df7859e0e6471924cbee1d9b157821fa29a8106413ee7e1c650a22afdfe3e9b9ff679489542bef6c2d1723d5a0074cd9abb3fa4103b451d828d6814af13658a9192e0b2adff1adc7249e610a8518cbb799d5d5951a4805b045213ee997e87a6e6429ef874d227db051d3f63d1b7a74b6d6227c9fb899e7d99c4ed35d5e98a703c5d62a07763339e836522f76b08ee120428c5be44adb575baeffdd8d2ee04cc660d6b29157ba7cbf4fb4a90ca753f6b31bf951133521d3035abcd841954b7e8880fe35b4268cd29a41d7ac0c30efed97f21534bdef72ff23f4586a498afa2a3ecf4226ea31882b376c38d821a688fc26905899c6f602cd80e869d29e6cc34e5eb42173f5870f831c3667b745a7d0f1ab40cfce76eb52d29595487ca0c1b00167116459d2fcbab92f16de8b1986f6bac06a150b99a16a9d94e2299092c9dd4021166e2d656842b8cd445c05582aee58392c099a0d7eb90f7d9e6e071285a339c40446696e201eb9b2c7f7d721ffea3c81d5eea7e3f25981933654a93db27fd70ed04caea38e21c9c32f749a7486c27334619b2f13212e65bf58a74787b8391cad84b30370da7b27e23db12c046f46b14cea7c40c4da86b7b545e0e10ef470534b10ac77c563cb92e54e12f04477b58a25eda28e6a6ff76982dd77fcc0b18e177e9af1ee0064edec077e4b5f2e7c0953cdf475751fd287fa352ce85d17df0dbf537a37b54c619cf3a329738c8bf1d65ed9470d153dc37f7ba7d8cf475f23f4b142fbd328b3ba60eb34a8a16ec2c7ae07e529d12fc0ae431c2fb3c01e2cda7901539ceaaa7c41ea5e4214180b7b7a2a4dbe1e8e389a77009779b5429752305016e3dda0fbe9f6c1c0c79d98c7dbceca9aff0d3232ac832a8fb1e469eb72d66177e687631282236b5dc23796c43d2a3fe4506dcd480d52e9829eff3e2fa2ec0794757cefa1ad7ef2dd9a3a93201e3435505ebfd56df5c06fbc18c697bd662ac15e32f3c59a35a93b100e6fa815871fe855a96e19f659a3adb4c42298e30cf9498930a3be7ff6fdcd95458de72277d77d86d3cf51c7ba643f30e2bea6a769201647d5169a61860388a82333601e2f43447b8e7d7a49a455858243110c9c3319dc97b333ee075609bbb73fa5ea8ca33dd287e6ecb77c5f92caf83b46b6c4edf7e37344b27323d1e3422ecf7bf4c8d19fa04944c2494b4cd9c9f817561fa9821121f64001b51109cbc087451f115a4513768ea425f243089fe9a005b433783f6ae7d1de90aae19a1e81f918bf9c1a5f8be53774f904b5786782bbcd163287362466eae1526d7aa098798e36b9474e2a90d0e73b3fe3e187e3cad45c4b095d00d5df96ccbd8799d30a008dd6a9b825afa578e190de3651b82b882fa21dfb14afb4eb96b92fb045cb5223aab0e1ff9cbb543dfe55a7b29131cbdfbcf2f119a2ed78f492c66941806d26f42832ab5048adee9f51244ed7b0ad1d9f2992b0e02d821e5eab6991c39daa77e8fe1872e343397b243e88ceb4d268628a30c4061a276ed595b8e2b854026e51ac792ae8f113804665e891e9dbc2e398ad4df28e2c6aefd585e9403e47b8344d2c1077c982f7bac19c50b87f397cdc4b228832321121bbaa7b22cfa93d5d31c2846af0ab25b54433fbf5efe943c5e93e7242d13a0dcf1e501fe55c91e5d964019221b82fe3f47e17bf8603ed9ce8fba4edc6c05888bfdba40e07844b26412560deefa26988b1cbb2d2de1ac21abe50c9a1323a3422dfd50be06bdd5843067159bc3b17074856c35c3e9f74b3c3f1e36c52748d9f00fe9b6b83a09a7853b26296e5d6afdbbf044b5c5712928b0d37187ec385d06cf770d5ca917cdbb67982148ae3ce344ad0fbe5c7baff60b4de5d930c4c76487adc790c4f64fb0d9814bb6256aacf00d7d24e9d57be86e88df485c7cd14bb4b428a9ff32da3b9d2f83e436329c3beba08ab085104d0d19b2d86f2d", "d637c6aa38378d0f9a7aeacd690eea2ed20bc496ef42e695f23841998571e1844562f94b9dee3a4f0ba33e61bbb1015d5f6716127ddc8e412659eb728248982978a6852aa5f2a540d52ddc70d640b579697492ba4cb70caad4f161e7f9cc926814091ffcd0f74675a7a7874a81436654710a51cb37f8a0bcdf56d1d14bf98149a1074789f0389abf40cac646236ea85e315aaf2f51fab69a9ff1c83b606ea41b45e1bfeae4b2b27dca2ba1d82e0f46348f924700351a40d2a8656aceca4e42cb959acdc6a46bc46eb3ef1098f939161cd33bbf84446aa2751fa644e7b58ee15c329c1c3abd56042a7ac66210d8a787b652c5bee98595ee3a6ee01d0f4a5d2e01b304e73afbcce48aa8a8d270bf5219611548f89c3f8b9791d0d0f1b95a86304ea34c52ac902c156932fbeefd665290b80a5a12bb3695f95b26da45d6c3a3acb7f195d432e9f33168294440bef21d644d46ed69b3d9f5035d619a3b043388a3442c1ef0fcf281e42f5b26bae1d06ace4df55b1dd994ba69d5814e0f0684019f6d47e0b5b6fc836c5f8a6086d4d37c92a4bd3762b79db64368887c2b061e258c3923e0cc8a9770c16bb7587cb8d460011d521b0767ed0d750884ac429f35cdb2aa0b2b99774673f2582924770fa0c0562580b934306ced538a051b6925981a21b3f492439f5d25b76bbf1f510ee7d6fdd2a27b790eb3b4686438c0c33b28847a31fde3d5ce839c134b48bea38902ebd6d4f7cdb4db6ffd43ebc0da124dcf735af086640a43f24102b2ad719aaaf45e8e7e1d2868d8eba433a1555efa889589362386d4989b22aec837c22b18fc7524fa847ff086643eeaee033446acbcf8543193ced30532d5b0667d6f554fb1b62926a89515b18e483197c32bbc4cddb246d311be07960a783d3814c2d9ce9d933cfb5d08edb8a78d98757b1f78e758f187bf00f601739e582e37413bd6ebd646184230914feeef44c3cee50f1606bc756b2f510a17cc6e225fafda99a0928b069096ea82625934164370c6d0dabe144775e1f1eab922afcf1f4cb43c5aed4fce095ceb15c3f1dce0cc08ae39d4d5a091f2be83572763b79b4fcd59a76c17d7b798e9055194f0acbc545cd6e25342acbcc1fe15dd2c3241220aa76c44a877f5a579e8c8da6f47a5513763110bf0286727dd9c010611ae2f62e7b01b098d1c9abebc9202877c29b78c25bcccc7229ffdfc265532ea745b9e7d6c8000ff7cddbb885f497bbfed2f06bf8e3cffd00ed7d361f1e1e310eff478db7beb73d702379b2885bdaec22bb65c190001ecb6aaa4de453af8da0fcad3bdc6712f580b6b86a28b711d70182713812b2d1545a8ed5fb0a87e54ba9243723d697378b82c9b00bc5f9439d197f75f9b0d92eca86d05d04e832d3e0f7a4ed1013468a5d481a0828cf79f1939838a5c4b4e74d6ab4065997555d765cb1a180195febb859ac951bbfba35353a771f9c30158de9dba35f16c4516091e46fc8ee41835691a0cc28fb05e7dd2ef3886dd4a3dfcea5623d9cd6f8169974083dd2af59ad4168afc09cb00b063cf76c3820a31432214ea02d1b087768f7994e2d819a2f6de27d3ac4593bc109641aaef7fc195df19cdb1ae5e57f536e515fdabaaec221685d695f1862cd517f111eaa96b20e12172de35a819a0acb4747f8490cc30c555885c5d38dace29068fecf62805a9ccd31787ab027e5158ca1bcb9f53378582317ab4d19f9107e20aa5faca2cfcdd0b40d66790fa04c9cd890aa744cc5ce74e0fa281b6075ac398bae1b4e68d7fb90e3b4fa928a80807de6e9d88d47552009b9bb28898f032347223f6c4e8c142f1bbb7b23a2c68ca92d7531e64f0ba317a0cea8eb00c31ba5acd1c39a1c76a1c2132e19544f015164fab39c504cad9a6b8a02dc4275689c2b9fb8827cb1a33883026c26851e3bf96e12c2610fac6a48d439cd9b4097126ae6e557a0519ec76a5dbd6985ae112587d6cbbf1469a649b7f2fb967fb15d47068caa8ac4f3e1b38d4158f3b51505d2dba08fabaa2e272e961c288c1ab4397d4ec86aa1ce22fcac7934340dce878eb8390108a81d0f6a1e354176fa70a5d79aeffe6c0bcb4eef2759e0784152edb817ee160107e", "-1003701d23b976d9758577a5950ba6c76d3eaca382d9dc4f542d27a8d0fc7b3255673276acc7459f095843fa273b61548caef2b916f7c95bda102e8661a9a69218bef0f837a8d40fd3df331db378586e0f27c8d9e420687110b0cd4f7b7c3f0aed4ca915e11cb9873c59f0ce88fa7d7e6bdc933a4e95022dc81f152d78d38692b6757e9b4ee36d95ae0c13f8eb8b16754f42c216cabfb2b683aad07df70a9e938c86f27ff93c618085bbe828adc0e611101dc2d10dd6bcd8e2202c8281bf2c32699ece1b53dea4c159a31af916e0b3df7d858fee8162249c08d086cb1b1187fd9cc610970933f8e9ab723c4b1500abb54d62ae1e0f09edc4c7308e2cd8f0ae3776df4e513cebae9570eb63d99d4cdc12d0a44432d0a00d6fd029086ca8dd84d7ed8f82030a980cd51bb0bd258a8bb5de1ae778d7bf9a4f834a5fb9922a29adcaa30db5ad782a2d40c1638632d9535e700bdb0f735f45d931fca9fc4a0a2e8d01c3aa58e26d94e19154668d22128dbc67fb8c1994def3778f0355b0bedf2b6cc96a1353d81089e6c75fb76cc7203483e37aea54b693625af148f1d7bbfb83c361272036593c40e956dc8bf5f8f2ae42caa2660c7bd6fbc5a8c176cdc400db943a1e51279e86ece25f46968dda682c241c0ad38b1a28cebf752227a53a3d73fb9cd27f78e33384db4dcac241bf920b91a6ed572c2b5fc208f977eda762c5a97608df36e4a46ff1fa5162109d3c0109389531ba8c79bb6f1af008f81d65a1d1bc66bdac21854e18807e75e7c62274a9b47ac720997dd331f8c43b439236f3c88acbbb4ac18672dc7a9afabda37dc7b73d944f7d53c5726ab8340138e040ef57cb13721a18b0453a14272a6f8cb067c42f5e2c7acea57074efdb0c02d1e318e7ecacc3b948a806a7c8328f2970128cee30a105377cf93ba1355f97215fa54fc6bf0c3f13d758125d5c75675a5967e0a36e814b2916fa6fc6673c0f0feea461cdb38c8a56bf5e34564b148d77aa249a5fcb2f6fc3be5b1d3301a76c1ade13f0fa88aed08ffc166fc856432a4d11e77f04012c7393d5e20b37006f340b1aa21672156ad471b46b1ca1046a0ff3b11f28f8816def53e22ae9f97b1dcce50998c18c8f9d76995ae1784b6bd4f73e4d199000d99c9c169c8fdc335e86ba2d1c7ccc218774d483b3c60327c48ae13c9049a2e996b56e05a9bdf099d953a0417bc79a26a4841165ec6150f6de47e50e683d3e897d3fdf32330e9b3c284b8b7e67c6da74a3a074200be3c0d19b4ef0a41181089217922bc8a5f264cdd2a6b25761ca43e67a85dc436400ca5ef668c5692b8dfa9a5405d0fe6600e452719d9f511f465761af43c07a56cd58a85981c2cb651ccfc504245e9e8753f5eca5592af64f47f0d2bd80fd59208852b1722f26aab30a6998738cb0f841df147332a228ff5e4ccdc4f9187eb7b2a096101f448de7893a5acdaec8add8e37e401ebac2de9efaa5d9445cb8cc13f79e842c713798e6829fbae72f815f178cc98f741e43ce7b0d49cec4fc37dff0aa6e5cf6544679cc6050d18f1b16e902a2b0ed758c9e82c2bb089ac3790b2072b3d25b5b71cd8ac27d41768b0ed72aa769a69f8b7a6c0a3457041b6eff044d5fa24eea7bc80a81f490ef298907a8af24f15550a907990a68bf9dafaa8279d0c9267cc75b5b8c70653692d7507bdbab438de0b1bee098b9cef14f855567432606848e0780d303394ec5d8deacd8b3479753abc828156058cbd6556cf596d4f8008602b5d29683455576e8dfddd2d3c8a6b698f92e8e807069c1acd316ff8a265a1788d978a9745fb52cfba36de0adcc5effaff93b624c9096ca5e2d8b3cd26370298e848f0eca9ff0d312e8fafb66442b9bdfe50721df6c271571ed19eddfd49face2b14e55d47983e2bef3d66dde4f8a4ac2e9e15cdb6e21d6b4447bfeded6733acc36ac1ab3055f390a02e8849e1a397c6dd10a68381a61d8f62ce869cf885ff307557beec3e243240cd97ec581c18c29ef9adcc0d23c556e093d3a73a4de97050527039e785c607f5d3079a77b7a0c065c6bdf4d3f218efd2de4dc7ed98084019a63d37b54c2f6aa4f2e78b2e613e92349a3f288e9894387fab", .Okay}, + {.Sub, "-1df87a3b08468a2f8298c47c7a5ff0606897ef72df233751f7b7ceefe94031a8cb02e3e5004371629d9415135c7aa8a9ad19b7bb4465edb6db3573d2c018e501520be3d0e835afb292e172f00f3c411885a0188240bc61ce487e9de687687956ea0f5a638b49eee46ef603845ee3c928c255497caeee4ef7f0c70a151505f6112cd8b71648010d0a7dcd18782aee02e1f5038cb3cdc5aff8191e8ec315377c624ac2c2b3ef1296ed58d18087dd2b98a5a0c0ee327f940a42f51496a2d6f51cd7207a34af7af922393c45158c9a183fc3547a46f5f91c5d55e35c8b092127b3859d1c2194651fe31bf358729d410eb82fc829278202f974479d4571997e43c1df1311a91bf42baccb0e4d0424b50ec3458b1d535cc99aadd586740623f9d3dadebbd8dd3f4c8c66b46f464a126711e390766ef80e22b4922ae0c891b9aa4f550c872d7bb070ade5ea1bc3e134e836cdf968edf8fbcd405a1fb1a0ea0e81cf05fe66ade4719bd804f0d766647683bcafd525c8bb87d336583e3c585f73934eaec3ed964496a4d3c23679abce4ea2cf1bb84a0f4da17276e979050cbd6438ea5ad2e53ad30b9fa68aaa3d9a568871febe82aa58bf0b738aca5ee32a1c7eb1ec1e333b4739cc87267a76b94dc27bb402a4e222f5d0b53330714751c5ad6b0abd0c2727ad929ec408a5aaf6f03d1a55852a80bbe66a06a956297983f92b1a7e77467955fc81adbd1caeb0c95d393d9f2b26c42c4a033de63379ef6a6c2368b9c11b4ae1c8129219c08d8b7d1fa23d2c0e39a9b2bc58915275d9008bc17fd64c638e61c46e78e75da918ac63bbab58892c17b006c50bbfc0e7b71ccd08c1d084d4085d902cf670649331587110ec67509415b1525a7c1401c31e3e6b313890637b4cca6b102e852fd89b8c9858d4a57867117502e7e55640295d2a3fb6de7188509fe5217118f5a84a2c9a7e0acdc1214b6046404b8c1bd9c7af5a22a21e09d6c16f8c0d375305f6b359e501a860265d0728494ab57752d68f4ec59adfaf0c2247a4096e9c769d936cef533557f976c2e05118a16b101f98759a4f820ffad55cf7be035b0627a9d25a92f16967818dff6e055b1055532615e6faa76e81e3143d0afd84695f61c1f2c3b216c21f75d90b4b23597c1359d50b7c3b4f01ada0904ff6d697585354af29ea3f53db942ad4cde1e9c2eda53ab82c2dbcd9ddd144d34fe555fc0b72791cddfb6248758af22b15883c9acb2ce74f0ed43c09f970b2d35feadb5756bd5a6b63d4fbacb22d431bed0904bd3b6b5ef7198fc3ac3779a85c0b13f3eb41801f95298412ff9b20251f5737852889b5fa7d8772c17300ced8c46c421b8ae3ef7c6a0258308201b559a8ae318406fe45a7e22d5b0ef50776d60a2466cc5a9552aaabb1567bb29f98acdcb3280c318e27bd315d07a649d5c2252ea0732d077f969ed4ccfec350042f120f676cd48a5a352d13816c9e99549a612c9878ac46b45b980d2d57f49daa39c514af8a6479b738580efdef27bf9a219af39927ee34d6eef3eef496413536648078857f0a772fd27b250f1e3d7c9c9145c91712a65e6908618231448c9c8fa4ded791a0cd51466071581135c013bf2c225b6958f16fd096937556166ef2dd1c8abcefe5cbfcc9f0ef6c408bd3e4f07d277e038ec49804f2a522d07f01283a3ae8d73a46e14d9e07b8db8599c856f18e1f4536d562d9891d9825acf1a7031c018bbc9e854a2b382692c291bbbf105cc7ba9abca1a7836c53b8f083b9ff63fde232c73ceb6ba7ccfc59df49c9196b5963595c68080a0cbe2ce4593d2d0afd08ef30a6ad1c95d1427ed0f6fc4a7aac697c5f2bbdf512ae3b1a2b88bcfbc0f39e5a2b5c0fff3f63c7e9ae826601d655f1d0f5327f48e128091724db374a7b9c981ec1711aabf1c666525ff39ff55a1501642c37d133adc9118868a8247c1da170eb1587575d8f56279ec95af16157a205ac64a0567837cc371cfae2f575d6d5801de6f3a4a0c280d579f1b330ae8640a16faef5f4fba12e158bb80b88f9d1667f9a7197bc7cd1934e081df98367de3909ea7b9d68d560daefb9f31fbad5a3c14b4647da4d0c0a22c3081245a1edd0d39cd48a94", "35dcf30cd4d31527efd05ce482d7045b3cba714604b3fecf06edd45d25382591fb517740483d617192b1672be3f1194c2b2a75a557c09d3de2ab59aeed6e87cf78bb5c702f841877f88a3c3b9b7846a51ebbe284116201edc34588fccd3507a87a84635e946a2be462650ad9e1be328d02d3c9004448dfafb975b3f7313187b1d04dfe58344059d08c137e1209489b8ff5b9a4a8dc3d6e469361eeb595eb9fbe3d983a33ad3e0411554a14a6faa8f727f17013613600851127a3b42aa0b9db84f087c42a2609604d2b0aec9d94b661fe84a029cdcb7552ce39e34db17eb572f8e4496d8b48c1f793ab53691ac8e74f9d8c2f634792be27da8223ff594119f5c702861799faf1dc338d958ed87c00cf4d5c57e0533b44335d0ca83b7be4913d07813a5b7a17823fa29a29d6906972e94056e82d0eac4e17b8d776e6159eb1d7aed8669e17bf4191df206a8e14e5de74558c0b6bf6c89f5d6761860cd9892d6a19fe9aa42567eb24ba8244b5b8a95b514086ad438929ab287bc70ca69194192af848bd2d5aa7aafdeca2c8a73722a89586f12c40b7c83f141f67ae9c0eb3c680147ae602db53d428b2607ced91f9a633ab60f4fea2cf68ebad8de2cf811010f75d55abc808b9ac41e123e26d33dc4cd4c069e56c8412392072991ea8344e718b2a6162bb1849f9ffd8ad106fce3a087f1626ef206692966e20e5e6cafaf57ea187b69e2d50b22c278cf51362c25b5c1160f2b65769ba87c7ac227ca70a23753c06d78eeb0a411c5a20db6a41b4c4b7ac175838146e4cef9a794775048e9e44acf0e857788a33d8aad430d1f9bc5081a5c632aed99588d65bb0775b1b305da2d0b25221e15c7543802e125b82e822cd74d6ddb6fae40ec4e3a397569ead94e75f7fe4bc3fefd84677e438dbd9b48fbe70e6a1e1b3dbdf8a9ae785c91ad3cabc4c2b71531499108722164e5cd62a0e5ea3b2d702b6caf7d03b538ebb2aca89ccbeebbb3836a6e0f1b020ff5487914409e8e03fc2d5d846364b5ad811c82928f53b7ad1317c4b79c77328aa9dcbae52257467ce0bea0d0da499f924fe454a7f7e67c4d9ff6a2d946168d54bb57094b188eb87245eafcc1195aa54f6f0a5833d357fa5760cfedd075416d8ba46f8d31d7ddb1acac32ff479299aefd0b4c8561383ca0c4b0a4f4fa19a8cc62cf6a07391449e9f5676c249071274824f885949586e0bec8eb9ce680f86d40e3a4b52f46021ccf29ce1b8122038dc3427712cbd906ac24fb6736feab301343201159b5fa56e5009ba9e65388bbe4b71579b3a8785f3eee4b48302d01fb4e688e69a61bb7934e9046263aa9abf89c4408390c3b36db0168f8a35caf17eb1a7c3c9ac21fdf22661ef78a6cc16ff9327a3c15245a24ee11d28b2cfa5e768b331aef81c6893aec7705a228c995766c1bf02879e7d549c246abbff6b250f96cb37cca7b6f806fc299b602527dc0547624f42a0eefcfe9d9bc78c0975b7ae48ddb3ad5135dd9ead8c0f29b98c491558360651974973b30c72d01459c97a0e161bc4248abe7b6783c9b19ed025add4b31d97b4703354cdfeec709229ce14a3c142b189cdfcc1fecb3a30384b01edd41ce61d7924a0ae0b24d02f33843f97744e48236c38abd3d87a558d897038c177b9af94ca9b7722018974cb6f56bf5ad5c2c99a939ae222549b8256b4c47c6fcb3f080801ad208cbb1ad540c2f3bc6bde98b697078e619f8b46ef9bf006aea05491969956043f7547caa422b6fd129309405223f7fc19dab545065a4356317301c7a4b3404e3421426d1ed21dc658e8bb7ef6ec6b1db56cb8f4115ceea1f4636f7c5f5fb44db42e066590b362e8269a42775fd8e5d2d7217961dfa3fd7630141a3bb80443d84dbb1b40b70d57170c71764791f1deb86e2fb7eb1d085807e2da273a603755625032dac56c5ef9dab144ba5665066d6fd37a3bec351baaa612c200ebdf391280c1ed3facef8bc6c435a2bae6024de95f47651679f8cd97845000aa4e2120e30876daabb9b7cf2524f3d52cd0dad463d2c1fe9fac6718ba64c4226b4a49a14f62636841b9d9180c3b5c0471b86d53deba4f8b70f21ed8621d794d3981ee66b00d18fd7f", "-53d56d47dd199f5772692160fd36f4bba55260b8e3d73620fea5a34d0e78573ac6545b254880d2d430457c3f406bc1f5d8442d609c268af4bde0cd81ad876cd0cac7404117b9c82a8b6baf2baab487bda45bfb06521e63bc0bc426e3549d80ff6493bdc21fb41ac8d15b0e5e40a1fbb5c529127cf3372ea7aa3cbe0c46377dc2fd26b56e7c4166db09e0968a34369e71eabd315caa031e3eac807d78ab231c20885afce79c509afeae1b952ed7d48fcd92310193b5948f541cb84acd77aef85c1101f8d9a10282866750022a2ecea1c1d91a70c3c491b0241d3fd8ba9fdd267e81658f1fade1daaf9eabdbb809f607cd54588ac995b79c221f6970f2bf5db7a61597c0b5ef1d88fe9be292fd310f9292e77533b004dee132931c419fde6517e63d1338b9640ea657097020a2d084ccd0cd57251ccf02a9e3b83f77cf49012cbb5f9419c82fef77c93c2e6f49ce15424ef4f964f295dfb7871326f6e80afc70186548889703c329ab59ab1a2f2d180115ac75ff10fce180ba036506052767d9bc365371f14c7ec0231c747585c577b13f3b3b8e593ab5fd986cbb5972ecb0dae76020d5e6f37ab35c9e17441a6ba4f22e0b4dbdae42f3b60c710cebffc1fd159090f301d540d2bc57dd302faf904f79a28cdb3d39456991b9eae4559f592e975189104db70e02a583a400ace88f8da996e2d58a6d3bec979a69dff61573f5e8010c9aaefe6f48d63dbe709bfffa8738251f005aa7a0bb419b8ce8ca72dd365751b956fd9c5adce7ac5889e3f1f0c5e5c10af46cff9f657379d3368464eaa83b52acc5f1719181c380948da514d9adbd763973e55549be12cd4463dd00e276d90fe24ed7ccd9d6b186836c6f4f73618a88301176f8108801e20287d73df862ac4a4fcc6e75081f1370d134ae5a0825825ba4c999321fb3f811c57ff945530cec1092c42d8eb8d14eb0cc67a3eb2faa03f9174e42e6d197eaadb15d48d4608e2e77c86f89acd7a50a0600fce7b7a11111298a784d2b1cc59a2072f177354b3cdf843fcdf2e90d34627bdff5c5251505c5806f76fa2ca61a3448a70e401fdc7625c8350591d766bbfbc6b51cf222b0f6f0e234b402f2277ca4fc657288977a407d29df6c609efa17c8ef7c666eac28c8fe7446d689c984a5d63ed26268e6637aa0a3a35da3fecb84cc1a088acb485f268862441bfd013340315c2d599e1ca85361e89a2c4784ed823656afd6451f75aa098d680e9f612f0d183e20e1df90f0559da70d30ca5616d62fdeb342de7b927754c6f609c42fa54e0f1d8f14e2e39107e2cff60322654938f98881ba86dad06c6e2cec19a51846fc85b3845f9c77d9f2321a6e25475b8109d845cb617ba6a057e5f676ec73f92cee3698c8c91bac7347e983482250931a09ad6197b5157061ef7c8bb0b45688c3c9654c5d60a2833c9797c37f01c3e463c9fb1cabe60a1663966fea7f5d0918c8ceeddbf5895e2b361473d2bdd14fbb7635a84afb6fa2b35d1673a370c4a12456252e11316b0ea6a59abe4930b86dfd0ab20559c122fbe00948bc15fff828f9c23bd5310cc49a9715ff16f092d67625f2873e265da1a0d65cdafd8991625f2c2e1bdd8ce3ccd0668e2920a354d62ae9a45e925f15c85e956a3b59863a29b0e3fa3b68af8bf4497f8d0390075bb1fff893489bbbd51d0b2bd5c93802628428a6c4a1d0589eaeac0051aaa39c7cda040445a83e0aaa632b47e574e61b3ed533172352586661072fe28745ca3a69664bf9c40c235bf9fc0d7c81f1c5eb232dcce1116dccaba7977a9ed526dc2a8485cd14bc23f76826a49d5fa12df2bfe473346678a9da60b7308d322385c6112340c5cb345b99d971314cd571dee3613e19c29ca1b9da99ca1eb04dbfffee7f202396517edc6d7b508cf12905c8fa1e6e353a1ada55916a63b45f1296a00cc2ec39ad627ae1240ee0be8fc34392ab00cdb18b5bdd4090b4866e51e00367c392fb529d9ddb7824bedf654c0a1e99901859c9f25d7ecfa723a9e689a1aeb370533a7f8d3859d4a5ca525c703768e3ea4db2cc4064cdb17f886c4de3df22ae78e72b15f7917342f7a00595d34b3f2ae284e0815f7f23dc3783a9ed8813", .Okay}, + {.Sub, "8fc53b0bf8b0092ecc99ccc0a30a132bc703ea88bf593b663efc596d2a45137d6ccd269f00f4b52343c7826143a29a893462efa42276b5c775721304ea2fdb34c4829a5cf4191a487250ef5cf4504baceaf1374f094fc3351d80ee69d226b09b977ef72cafe6f5f9297028f33aaf7f305b129ed8ad5f792475bbe74a908a03507a5f50d27b6a80392de93e665ef85b48f3a1c0bcec10031e7a9db75568c22b3312c2dad580fd15647df7725931be41a1e979834c133021d779640a28bc548789e8e4b9c87b0440eef8a5f624372e942e2483b6e137e477fff7a78c2663f4980f933d5f2cf5442a0b1f38e93fbc3e343e31b8299fd52c20020b00aa79d5388b4d55900832f99bdc0632786ab0b96013509ac81fcf7965c6c9d5dcfcc4624e8376ccb30e0c8c5bf63b092896e47e65208a355f2100112764bc9346ada2ee6f233a79336b76f18d852e5e44c170ae3b82197b8cb21b2dc161494b1f1ae281c559ae01c7dc66fdc053ea4f62cce2d0a23ef987fae22794c9489d74781aab9e0ca27a7f75910a2a0df4802afb9c964185e718879b00f31721c0241233b9d675872aed0c97517a3a83037b1e88629cdee2cc7447a660cb3f1fa574a83456821dd2d11c1f86a8603857bdd21fc66e0610196ee2b78c1c686a12b33ab8156ee6fceeca2f6f8e8bfc0a9becf0b8d4e5473f31e31d132a783d4f3223e04cecd4883b7adfa037c2ee3b1ef0e384de15f03f8cda31aac65e45d0b3fa99bc5dd5d41d818b85cf42809bf65bce1bd1b2360e906abea6a9e8fded585095a33f00610a057b29e5d9fe84d377b91ab2472fb05d660dd467d047b266b4e1dfd5c933a63d7a4a24b9c415824bbf691898c8efbe14e86d5d896658db5c00638d951aac5dff0f093289f8208ec1d5a267ad3080c90b99b6109ad72705b0325fd69190b50bad6376f0b7f1cdcae9bfcd8692167e2922be1f9030c0ecd1564419e8ff9b3596c0a7323819b29331585b1bc17839a94f5fa00c4afa7c8ce0ee816f139ee8be3680d64de791bcd3844a718605f6bae32e3a7e100f7de79a8a06c69877c6639577aa519f7b4bda04a74978731308300bdf9ebe80b658873a3b48717936fa21e37db4c0c5d58bf40ca3102ad81df3d6dd814601c7b6626f40012336535c8fd571d019c3c17231cae1757a75427700db18e43cbf4267031c0b94abab8cd3ea687a68adcfa2b8f244754327209537715874eb56eadd84b8f9efc05efcda879181ab6ef4db6437d91aaca56cc258a3018822cc89272067b55258aafb5cc0214d5f60ac602c36aa8f7fcd25c62eb969baea55a38773760c4f96d3bb8c84b67b1696e2ba96fa54bf39bf79ad85282102e4bef9346ee2f09d44bd4388bf3b3bc7afa8d2b23da7887a8fa90334eb6ea3d196f027d091b2a5b7f7098f2281fcfe620f254309b2065e27fe93fb45049988916c31c8d547b11e232759f8d4ee4a779c8a2522d35ea62c2daa63bfe7ceb3e5ac78233e2bc914c48ef1f9cc37258d9d1f95eae5eb3ec99784b5ea5eefa0045b33c8f7b97d630e0998ef9476138590eaac41c3a1da13436aa30dc3c297586c2a3b27ab68d1e33d4253538daf813cb55cbcbe96f563aace7523cac1a37f9807e4e218131803541a5a198adfe58b7636afdb71d7404fddd54fe55c90d4efcb1c294367f2109b5392e907eea598b068ea4984d3e750a2967d50e619f5696305ff53e2749862b2552bb3547dd0fb7dc15d93878180549a59e4c850335e85c710cb512b19d1889efb32e91bc938b61f0618d366af341600ad4ed5cbfb20a39ff1eff6926155323994efab5a7bbe6cdf29dda3d7cc753137be6513a321097fb63a4ccb103f7e374627e217a7f15825fa6d7cb2ec75e8c3809d5cd85e588c30b31ba696f7b2ef4e906e95344672d8069c83248ce1dd77c1e70e07d260e734822cc4cedf73d8eff33e2e3d49c5d0d96ab5d1ead4cc2cc3b9f621fe50637831d5ddbea1ef5e3eff30a107fc508c3ce83bef7c776ea068db6bb1aab181ccffc301a24757c0c981227dbc29b1bee47209afde3256667ddfbd479f4de2313127f373cbed9f238257dbb0e526a8bc3b6ddb989a0e88b790c26c4a9a8606", "b72e1f2f77bfb12b6368956384068b8f87f388450ef5407f7f06a6886e4cea3332146247d55be79cf9f10217c470fa6727176d2de0980eab63694938e98c2f305355d2e67f6de49d38541e242c01ce10d9685cf521671c912eef0dd82276ad1ed85e9ba25fb889fe8cea259c7277c188f14ab5c15b77670766c680e3ec3d0b52912ed3e9ad7c074717fcebefc7c03b51951e7d63641808eae6cedbba4934eef3f71d5091516419ac2c6955299765210102c409227c7440e177c55187afc78bcf84c3ca3567b4cc7f9af611f6c8c08dce565e387faaaf342ec4046919b2d229de442cc5ab427ce99df7f5dcd90dbf18b59943e42c00770cb057f4e332cf9e09d50f66889dd67b1cb291f5f614630b2c0dd74b19d178539c00849a0245212807341505f6f57318b389ad1ce4159f6893f3186263bcb8e3e43f25b9c15a7a126e7691fc326d803b87e6dd80f659eb271df4309f250f2dbd21e1a185c69c94c1e5b53bd895a0bea8d40ee5bf2a216173934760bd0bc678203d14ef275400655c9a4da0a0a7f0fe96041a015f131e9d5d4454600f1a5b3838761674c66414831565d8c7c208ef8c018f4344d3bfd09f735f794007a53dab3c95434013b404bc7dcb370e4ff55a6f403542f6aa2e0bbef8a59b94a6cfc9997fcab487cfd0c89e67ef1843f02a2fc73ce025246693a9f01fd71ba307b943e7aa75ddd77f5a63d7e266d96d91fd5491f80cfa4d14fa9381225ff53df1014c33ea78bec64642d3d772b07bf448aa1871c571ea176ba4adba250f969c78ec2730c021c3fa469f026c4858a24fd5f46cb8b765c2aa71e2d15116758dbebf48dd7a52ac6258a25c3a9a06354b642f120b1282f87713f053a352e37cc9053d1f1eecd1143b35c2df843212669c8baf83a93f9d115e26914dedc60ce26cc468a964d37f7185cac97b3468b550fd52bc005485a1670db0af4b95d9687d0cf1f099ee0da3b4061d1abe9b1770a89892327e3c3d590bb2bfb0e46a89483530de09d6c2ac804cffa70fab3a7034ca73d02fdf6a8ef25701995dc30ab3745ec8a158959926493f5ec772e0bd4e47d58f9524a92e19acf69bf3a3760f9f224760ca4f375aae67565565a54ab7b59ee5a655ba34ada04b5193ae5407bf1a252592c048b03d6d70362bf0325f10da78184f6712e4b8ca7eddc7ea58550eddfb64a3a134802d8a5dbc5d9f231cbfd32e32274048f2e7d67d4b58b0c359875c06eee346c75ccafa16f163d75cb3068089f5739345fff9a07f81a08ab20bccbbb602f44cbce5cff49c633e89b4f5f10b862fa4a7bc072a0d7fdb6f77f3801ed7342139a410028e98afea258178f47899380fa32908ebcd1cfd0658151a8f16a1601be65dbeeae47caf4382bcc6460f272ba3d4755b68cefaca3197e6331bda5dd310776c144a0f3b151e145ae7bedfc5fda88f37b2abd451ae5d9046718a306fadeab88a696284beaff5f5e527756e000478189a3fcb709145285dfa013b64aca46ffc6dec4f354a0f2cfe0bdc6b8e749958d807abf249a4e7d2fb29512f62aaf4bf050344a6f0c0fb0558b7a5f929f4fe034b88b8492736fddd9e0ad3e62c183570d06d5ac9b7d416f46a72404daa7bbe8e060758752b23e83a42bf09979dea00b6cab410eb0f6364a915b813f7bf3638578dd6442d319898e46dc2287de1fb2d4eb32cf3b6a7be2ca88cffc323fa34ba76372f4bb270dd1989a42e911c63aede4a579d61159b59d50f00526d7b9325163b7284aff10cf6cd457959ce71ed6d4b0af98e1d81bc5d0c313fad5337b40b2f5bb4eb2d29bb92e30ca3b23038b12cd3631ad02a240e50830a6c67ea76d3680cc9bea79cdff71e67fb2748d9da5acb2af85ddace7ca91079388252afbe365d4474080db35f6c97dbbdbca2c0489f28b79e788c8ff46062aac62cd9d14a123c2efe6d9d3d2ff43ad76cd912452e0d502e503d0e023aaedcee27528b9150e4090f680539d70d27c3b5a5a9e6558f8b823f979da3f365ccdb048416c025c9c7a041b6ddd44e29badddee26dd760af9672ceab0692076b85d5e35e499e5aebc1f21b8acf777c6c721a93ad1a487f4283941f7f8140ce862bb73c27a5df3e5fe3", "-2768e4237f0fa7fc96cec8a2e0fc7863c0ef9dbc4f9c0519400a4d1b4407d6b5c5473ba8d4673279b6297fb680ce5fddf2b47d89be2158e3edf73633ff5c53fb8ed338898b54ca54c6032ec737b18263ee7725a61817595c116e1f6e504ffc8340dfa475afd194056379fca937c84258963816e8ae17ede2f10a99995bb3080216cf83173211870dea13ad8968c7e008a17cbca6780805cc6c312464e072c3c0e45a75bbd0670447ae71e2d065a6df5f194a85d669441f09fe61475ef37304459bdf106cecb08b90a2501bd29191f9a031da819e72cabc2ecc5cdcf34edd91ceb0ef667e4d38bf92d8bcf3995180e477678bba8c2b4aecae4cf438b8fa657e87b9d6806adcdf40ac5f7d8b63a9ab18bd3c82fa01feedd536aebd0580bed983bd4852e8e8e6bcbd4ea3f44d3121037368e30342bca7bc7f82927313b78ba34b3c18c8c6f68eae02b87f3c34e93ceb9bdab51272f3fffbc0985666abba12fc8c073a10b939c0e88024965c5d3e90d1544dd8c2299ee356f4777aaf3954c74ff7d3212b16e6d4880f99d66376885bd75d3bd87419682116b5f26292aa3e0d8e3aebbb2ab775517e8bc8264b5d33c0909304f86144726c1cefce97df5d829eaafa1aeec94cfa36e87770d6e3c005aedf36b8dd1ab3612f6d1779cfba61e1a17924e8d4619e33bca0f3346b91ae62b0edf3fe8fdd4106987851fd8a9285db9c67873935cf0f19730729756eff0a53f4482e4a7792bb7b7fefdf0268706eb655e72aacb1c80e2215f756186535961d4f6668ecb37afecee02a7e84f9e594fcf11e72c8515120f4ff9cb37b7ac1856b43420dbd770ce2289872d69924fc1ec04fe17b874eacc64ba96a5fae24323ebae585f362ac61c31e89437f208964e07528dfdca46b20c1d39d35642da5c842540ffc47959d62f93273a8dff515bdcdd0f1c4990b84f11694b81ad4f7328628d7b9d84c4c051f43a9f3bab46ae783fdf3e5388ee5ff0125e121979379166184ca7cfd3ab45128e8413d6cae16e8d92a64224d38b6fcab94f908ec6046b62f888ca364e0e106ce8ed28dd178fb31fb366baecc89b5907d5fb5a699ee6be7c3d7511e6beed99013eee935305c33822795f6efc959b249172482c82d5dbcd0d2c1bd526ec32380478d071a13a6567e62454d1905e684859d6a438807dcecd174184f9b946187959fd481fd89d1f524ba6ef030753fe2cb05cbc74145da003bd8029c7e8235e95706fdce1f8f5fe22bedbe2b1c521c58e6a0933747dc801867e582a59b4e4da1f411ea73347b15df290895c4d4dba024da9640fb54162085224ff8ab6127d1a2d0547609e234d38e9ebe5d7e4478d5e3af5b66a4fbfa21991be62033b0c2d7291a362ba940e793d9ea1408679eb1142b72267d6056f89aa7be628a27b81b196ddcf1c8123cb30eef17de0cd967d5a9fb3c6da73ac91cf15e7d9c427f518ac35e9194743a47136bd0c25416c7d3d6cdb4da57fcbcab98b03abbd5724fe8157e02a1b529a7acef971325f12cc4dd14a2eda8bc524549b40a036fd3cc54a15bcf708d31215fd64ec39515cbe5e68a5af587c620f0bb0cc2b5f2a20202eed5e21d42bdd98d02775a35d37cdca2dc069ac34463d8dd233f06222fa70643838fe72beace8574d8b389373e77c419e9e652fafd015462156f557c7bb18d2a4f1225600d94434dbd74a7d4a5af208d7ce3d45c41c5e8ac718937150bcbdec737fb89cc86a1e3543dc64d8d7ffdd321ae5cc60813fee8e041a5a22ba7d12f76ba842f41c0d7fe7ba389a5820b97528a6535636094478d37cb9c50ab4e7ff6a3c18178e75c634afa30acab3df736b2b86e5469a8b527e6a5aa5357bba91193b278b3830705b4d40f2c5d8cc2998f2f20d984e61b7bdd0043c600e40acd542fda09f4712ba085f3713bd5c8e8b517ea3c0a69ce17391b106b255b6393e91f06ffd006687f63a34c68c40821fa8ed19b2ee5b8abefd363f94e85d45766aab5b4878f31b35ab56803e9556c641b3b54741f161e74b71ad2abe2631d15614b59a485e4b3ea38fce229392f6f657e8c56bb9ddfc0ea62dc03b07ed2f711553e979a1bdad7e411a5a83477a2ffab653994a3d9dd", .Okay}, + {.Sub, "6586814dfde6aa2aae71c04d1ace9763ac989ac300a411ad78a5f0f87cf878bbd8f6e4a1eac4c2c6c732c9ac6ded957c3848b55651d098c83b24401171c4dd900336c43a43366ed52080bdc9640aa1f571294b09e016aee3fee31d50df94613b8248d7bd6649b5229530e5666a9fc48d70477cb37524f3482c91b5879babeea4018e2a27508f8eb149c5bb82ce342658b5f7e0743e8da32a032a6fee3de31929f69a207f171eedab96ea6f143006720ce4caa8485f5409d9b8a19c5b3e51621aafb03e9c657d7b293a7ddf3c4cc51e65e63ac7f140a2e25cd757b7f0a1a562754fc1068b1280920120814d82278f7aea571e244135935320f067122789872fd9762554ecbee2967d0229bab727c53b5de53926c797938f1cc8131d6fdc9af16229ecf7e393f92c35aefa25c35e08a3c54495efe50c1ef45c80026ccefe84bdfc371ce5f0855465cdc8c117b298139ea0ee896c3e22e3401aa12e7ef8d714c3160abdc7c90fd30b4165a986ffe46634c0672a6a31829f609d4412c5211515837c4ee40491354ad7ac260ddfaf1edf8e92fcad2bf443936760966c533510f41f63cf0c93f39bf85841b799d65dcffa8d06a4902e1cd24032139d23ac773d937194f589e76bf0640ddbdd5d49e4e2ccaf6fa2c15f15460a7d6b873584b3b937dc433befee548155f4f9fbd239c7b59b2cd8245f257f83298bbef26c9bcf1e42c191f8ed0b0c45cc83a6a80b37522ce90be33370501c1754bb752d635cfccb2eaca308e99e511e15b7822ca8330479a964411a333b13b6f81e48773da78b86bbc415e56bb2eb6b0da6c8a19a90f8fdbd8782b960ef7b983af68c5420fcaca96619cb2ae211458b0fb0404477cbf352cead64a34c7ea1ae6b06122f5a9ebd7ddcc30e5d518032e6be0e5ca6ba89d764781310d04b5bc4f0a8493bb2f18c2635d3e2777e19c414f2b02270f4e672de0f15858a81d295a4426ea6e70f0d4cb1cf6d2f461199d0dc7b690f34d5d4a3492a4202e7b239af62f2acb76c9218f729f1518c8f75e2e90e2bfd7f38f47e97292283d319297bc61f9e1fb73370cfed79db4b7b3320a3f261c35c3bd67992f7e0d60b41ab66c49dabf33dd6a82e21abc30a01c5741066eea3ece3b4d877761b7211e9dba3d070b6bca9e5531a2098577dc400dc0608e8fe8a6d97979d285022e8b003cb9f40ed2f653800a80fb8523eb2f98ad4770b94e6785d664095ebc3e91f7911347656af45aca2ce8619c348edc99011c754f21c6c125a4c0d2800fc0f01006b9df0b8ef65a41c18574cef122ebff2a16e0c04fe78bef8034cf9c7609bee2889bd0f78b9b945fa8c6bb7d059cb8e466df3ffab26d6b34113737a919c6a551a3ada35d76135b63d293da55da481256c4e7b7a20267001da73b60a87ebea9129f6f7640b441f70cf16abc7bcedfb43472157b66bbe8fbe40bab8f731e6cb1eaf7e03a12ad1c5e291934dc754d9d6afb9d04d53282702f9ed5f984d5d00b045d5c5789c7f1805dd0a227d7a29f59d9f23371a5b2aab822aef02a0557a19065c65ee01ca30f29f5397ce70fc119357450bb858ad7a1d76fe91af51444c86d7b8ab1a66719060d3a19d5f8504ceae9a8175d96400c3d43259d8053c8ccbabc8d695e48d8e15c3a82f16b2e63df7c759128aeb286fe076ba71e49018717916bb38d1bc18880f63deab07ca6a0b7a9a58f65c27545e2082f679d85f31b69b642e19e307f468cda608f962a23bbc34444883f45cdf490a5a6bb91dba3fdad95bc5c2421b900ca0075bfd36a64e99be473b9f405b49ce47a71ffb708c86c57ca63ea323023edb962da2a14760ba8ba65dc5b5436f2b9f16cef269268b4f788b2c809563cfc92982405e4f7d627f41da2a83b44e638ba9262fe590e5e4feedfac2cd27afaa2fc599e911ac2bd98f019717eebe08bcb659810d7f61fedd9658456265f43dcdd1f17a456ee24e4cacff8301ac306abbba050b7533ec9e2f482352d13aea6ee19f180791b696c6a17285b64dba04662e23cf923f48b50e60fdd36eb11ed3c31bc8831483b883726233395e056d821d4a7130694163eff7f2f2446cb0da033a3c9f58920c49548ef6c98202774164", "44c50d979904d88917f80a51d8c64aa77764750c8446cecfe215b36c6e61c573edc92799dfbfa17acc467d1cc39d74e6b065ab731cef9277476893500abe9be1206cd8f5b76e5ad55aea58d731ad0e297b3968edfc38de1cc913144f3c193f0cea4dee4de1dab571ae5a66ba5eeac0be79a5de2dcb1aa12fae004e9529e6af64c56dc35246006a2503f34e5aa9a330d9b1876a9602601d19469e62d983399bdf88ba2b9fedb59ee10cffb593a9f5d9859f25b83bd91a5f1928596764c27a5eb4eccf99b22dbb282dfd18008f410a1e6755747a5bd18a3c7eb327e9d1e0d3fa040a0e6f9feea5b90287ebea2b5e7c3c7fb65bfd945dbcc1aee842576342a3ee0824ab074258e7f5dd3280737c4e8f35a00cbbed1b4c64a65500cc00775714cf33a2b187b85e3bf572ddbfa29a822c80443677b45e872db88b5e2cc5ca69e9ab25599c1a916b6663ccb348963fbf278394884b1452787b1376039f3cd33d1b55b17c39cfeffa613bb3b0a2e7487732cfd01020ab441e52fac23703de988c9b6b28a72a2c75ae1cf620d6e9d57395799321e5f560eff7aabcf455c1ba0e0f0ca6c7cd5ba8b5737d4c1f675ec679704993a84e037b0c7f48e51db55ef2eca8a67a0f5faa4f0c8a1b9b21b70037d70ffdce5b277d96b0aa4302adf09016d7804b0f822b5a4e32f46ddabe928d7ce2830452a82652bd9c43ebf492b7256abfffffe0a4e477cf9ff6dc5ff91766d338ba9ed719ec0626bc5fb62a1af62039315326aa6cc3e6d809a91c341504675085a3703d05d9e1b6a9dd8a9bb85ff8a0b9bb3b3101d945f3ded272632999c5bca942218eb369159996adad2d659aaf73fdfb3121153705a797698174dd1b0d7cf641bdc637f3f11d4ba671eae723fdce210e760a0705162d4c8b11db1de1596aa1188bec6081fe74b36c7a3676587172e873e725ecb891d26675f58536de3656b6fffb1a9c3ce206e22d879c174d1f14fd4b9a73b9c2664a911d94032fa1529931628b5ec9ded9c4afb6df5482484601ffecc5522bf29693b38c2e051d2c6b7e4abe5e06d393f69da4bfade522bb297bb7122374ea093147c913a107eb75df2f689ac5afa84b46b0eb8d698bf1b63a3163803fb9062ef8f7e967c4131351dc2a3f66646822d85cf4f17683a041560783da3d26a9aefe7a68dcd2060018f77d52a2e02f0b6bdba9e2fd674b2c977b0a017a8a375cd348f8af2653ec5c4dd96e1582073debcac4dede8ab9efa5b05694adde3a099a0239ab53d570e75291558e020a058180a906997e6fdb683cd3b7f6aa733c03ef0d1b640e9abaf7ac59f8d7812428c8eedb70ffde6e0bcae1e6f87a54f39edb84b8a94e06407aec3afe3b0213abdc872be8cb7ef8a234f3d88114054c216c7495ed7f45ecab3b2349194b2611f3078ed80560475d97734d31c8742c64e975fc4dcdec65ecc2bab270b6f2399e2fae66bdccbf26c155dd0452e66eb164e44d9ba62daf1ba6e2910a2f2aa11e95f3f2471804eeee1632dc96ca746bfb796b0a7d50b433ce4dfba63b6a40f2f9ceff42112e5e900e2d9b922d4fb27d099e04fd486c9fac2dac190dde665727d0c2091b4876548f7d12bb45703e0d95a067f95b0f6427ed31f7309674c0e11dda7f04d8613baa0ead7f550508e15f0d2291a82a237deae8c35b40c1de313a7f66747f8f5858da83a937724c27b0de9c69988bd987d4c90add24b16af72660e6cfdfc8fc4befbb06050aee766d0780516995a79f0cbf40c6c0da9c9c1e3e8f0d2db42809476e02b4bd159e1cbe511986cd750fe098ab8c6c09637a52a0964077c85157a208b9109b16c6cd8ce5e2a3131ba136db4dd4a4997a126cf587d54b0c8cf09fb900d5e8a1ea410cec1bbe891df2621c61f58e229d3e94efc1896302df5e0389a69d34aeedfaff81ab9a94667611c3e2e285c9425816da123c31d81be8a5a9adeb245af381480f2c307beeccbd8b19d2a2399dc56adb3f350d0c1842d7055dde4c550c0b29e5b6516cf171fcbda6fbf652ad74efedbcc39f79243520400e5e469127c7a26425d649e73424612e516d8a4bc98423c4fd6239dd5a14cf2e92c2c56c27dd300f859e6eca866a1d4d5e0562", "20c173b664e1d1a19679b5fb42084cbc353425b67c5d42dd96903d8c0e96b347eb2dbd080b05214bfaec4c8faa50209587e309e334e10650f3bbacc1670641aee2c9eb448bc813ffc59664f2325d93cbf5efe21be3ddd0c735d00901a37b222e97fae96f846effb0e6d67eac0bb503cef6a19e85aa0a52187e9166f271c53f3f3c2066d50a8f248c45d26d282490f57f047075de3c2d8610bc8c0d14baa97d4a6ddff4df29694eca89eab9808610988745a4f00c8639aac0904834f67bd70365c2e0a4ea37c252fb3d65dead0bbafffe90c64d956f18a5de242fce1ec0d1687145b296eb23dad8fe98956356c9133e6aa0c226acd7d691720824bac446e341d1517a4daa65faa09fcfa9473ad93605bdd87d39ac4b2ee8c7c7471cf88586222e873b702b35bd36c2d13a8328dbdc23810e1e3b8684f13bd121d5a704949b12d6dd80cb5f19ee020115788172d8ec1b0c663e57ebaa682ca49d8f422599f96d648e83f7d91571cf8db5069fb76d3364f05709beed644c65db0d0ee688887a1853a7b9d81b872de18b4f240a3b8965fb7116b7cb044be8aa6c40aa992701e7789c01b0eb3e287b0c22503b0fe45fb0f95e568cb31052f74cf5e7c4b98a94ecf78595df985f664872ba265d120dd2cee1147b43c8649bc77abd96a56ddc38ecccc11095a0218ce81a3b6944bce53296da2ffe0c67e33f3d972c3b47310f1e42e0ed14753b6c4ef023ad90a46419724a34c9476a295fb79e915a374323cb780802364502c64774f9836d2840e27ed639273b40518469d96d8290174506d1cb8093140c25bf0c989b439f07d4d44fbb9bf8cf504b55e4ea8dc926b97188aeae34f8b5f3dc69ae218e3b63296a4efd1110e72caf5b615607f91b2b0b5cd09c6f66b907583b52e65bac333ec5611f364bec26b04e4ce711842e12c55a80193dc1ecbc8ac587f1ae7cba9d3a16b01c270f1a6aee44f08ec214e70acfc1ee37b483d2bb8c4f33864b5dd50c0534820a17c7b6a41dd35feab33bcd62ea49d2f52a048c3a63834c555a9fcf7a1bc81318de6425cc459585287ade71d210b5a671c2c92806491772aa98afbb33eb03b3c8783b4592031b7decc065d44ab677e77a5f89c20c6de16df6ba851fa1c52599f132ab857380f813c1cb3361b2d8ca90d3a386da32570a6e95ad9b91978430d2d045cfd4c03365434c67d0b57b783d483d386f5377a3c29c37520979e4481255d39d71d348ab91d06721e8dee0696cb43feb56082d52b871183ce964ba96ab6e0cf6faea1d47b255e73440b01a79371b844cb69d7efee99a6a243d0ba09fce891ac9ffc0ce3407b9dad7eec189d0d7df769aa7926f4701d8d072c627387c569a56a93db3ae4d0be23d1408356524499f3503ffd9e58ca0e083569f506cf13cc5d89e22681f5eaafcc1d95bc979ff48c19659d12509e87f58a2fb860848403fad2cef011745d46bab048cb48efae0e62871cb6c34a725790b5c175c556922bbe21a51e37e60979029efaa2d8bb305bdfa243418b9c9a6f6dd342f48c73614871f375d23dcd36ba0e471b805a121499489b9400e6fec0dcdefcae583d0eaed24b615af8fd1f01d00e3c0e657ef46f7390e32881ac9ffd8d6a23b2941907babadd149d1bd8351e4071628da11aa04deeaa4c76a60c7aa84f7b35f3122b1e736f9b046b94263bfad8bbaa738bba2b92cde30c06a829f7f9515a5d1c86d680b55b4944e50e6bc04adc7a0fe0aec35343be2dab2dc555020084399911c819c014bcc2e119a38d42209eb4a465f19e7fd803779c68f5fc29e41db9dbc811debf08504dded4b80f985cafb16dbd3ba7ad7e89342247e682156fa7d54dffc31037a2d7e9f8ff5aacef340e0561d429146c0b8bc382197ec6dfd8688f150a1245b9beb1b64c99e090cfb16abee122a803efa9b21062adb2636ed1728f6a54fc2abbe3c5cbcbc4652a976fdf8fd5fb61dd0be32c576925dc8821c3fa099f4b791232fe07bcbdd0c228c930cddac004559b00088f8a6be0e1380aedfa4828515953cc8b32ea2c08d31f400e0b05de2398b2e0ed82fb3fff7d180ed0ca44401b61a98dd753e1e173dce14c2288286aae5c4705f64b5193c02", .Okay}, + {.Sub, "-a72a6fb89e33a0b206aa4aa0769964b80a7235975257a5263b6e842673c3d5b3afc4e7893ed47ce41714f3b3bcd6ed0f2ec7b7c2b5965d332fc3131a8d4957b10b3506242e85949e52e1d230b6f3e683bc101ee21b56234cec1e12113bf8e3d528d5a16e97932fa75b1ae8571655c160dc62ae4837ea926f7ccecd18ea2a25e6e565a0a281c7bebbe1da399b28a8da32ac1c12c1113bada3507d45313ea911127ff5ee413f9783a38925d488f3f95de8b0819e60c31a153f91547ba5ee63093f65d46727d2018934282a520b2072723aff4b56c9416db7fb11572c699f023853b743396c2c86f3a4f9376faf523a0c1b22ad9bfa679a23aa9bfb7015f3ad776f243f02b3ff5e627cc4989c8e03c696892f73342665d3de7481e38e2dfe04ef40e09877ae4a32eae1213e8023f37f3014c9aeaef1db54786c6cc558c8564b485733e8c1802ec41a6d267a1056a883e84b475bf405da808a7e170a44f825f823d5141cceb4d9f89337331854a79ef54a8a93d8ced3cffcaa57516d9a8770474d00037e0425598c18c3c16bcbcb17814fef7ad80159993c5cf7609b5d4bbd3a93dd04bd4a5d575b2b0c554ff62c68781b0a4a1be0919d27a2475d0236739577f3f26a7826b42d605ef107ef2ed63db164c0f16fe5f4ef9d327865177ee61613b53c14cdc32be4162bad9a9f8718338a9765f25afd393580d43bb94af6351ebef53c0d6cd69f05352ff2f587bee71680bbc9d9f8a3e49d20a80ad954bec4d1ecf570b85fe35b0002c255dd93bb1bd787835f2db2dfbab829f1d3104a5dc6e6c5a41e87bd71baa9189819be01a05e4b5a78891b9a237fe4fab57ba3c86d148c9eb0696eb5ecef12bb4dfbce3172321fb6cd6618fb4de4dfe879edb7883a58d9ae22fc315bcf793fa841c969df10d492f51d77066b0605bd6aa58884a60deba21a34db933612eb5e6455357e0485cda72b4274ac26317b3b1de6f6762db92713c211c514cac0cf3450f583573f88558a7b5f2a0a74d1bb65dc3a23d8f6de2653a5b78e0f01f50870847c817feaf0cedeaff2ede705a2cb9f3be9bcce1b48af5cbd32c65892382212b6dcbe68bf0986401631a6c8c42a0c8a2698231f05b3ab68945cf54c1673c0ed33b2c95e06337cf5062ac9650bc0a8ab29480a063fd1c2b997786c6b80c0657627cbab36ef7264206049fea30c57a455353df8983aa8ae6bf792051bc03e298e1bfaae55d38fad92f0a6f16a428bb907253cf296332b156b4cf6812ef9a82d14f5e6ca3b1783aba391c0a7bd72d816b58791c337ce39f0e7761ba5979d571785018cb92bb787dfc05ef8b64e250abc240c01b15dca0c586449db0be18a1a7a2a306975729452abf2974760a634ec6908714c691ae3fe5d30097fa7878b52ffb6f30e420c27cfe1ebab1064167bba101d71fce3eb093757ad1419f8ca53cdcdcad639423ac780fed86f020f72bd056c7032b238035fe871b9d10e719f1b9ad07b44f95e764d26236f44bf56abaf88dad8b53a1b78ca5f9d8750ac840123a64eb062f3efcaf5a423c41dac64f863ba5d325425725fbde4d3d0fc21a2cd1aae630081ac373a388a95eb9f22464c36ac4289ebf8b6e3b9ef86758fbb6f0fc3c5cbc904182ece8330d30164922df60d5cbe3f2dcea75cbff76f93814cba993ca41e5a699e542d4f5ccc5d1bacd296bfa8b76de13f2919a025b1d4695080ca6f0c265cfbd08a17cd2387192307c9c42ae3063dd43f61b8572de973d9ecf1edaaee8fd2c6f68cf30ea9917c932a789668644a6dccb2a25d00a091e1843c809843154e9932d7d06ca369c3d7649112a36865b15589b5f12e553c11d31617b7ebdf0a70e86aba9e05dcdff58a4e16cd7649240073db92495cbd87f4197e3e4754ff4625c4c7402b0b71bbfc103799051fb0123d586f54c2c7354c031b2c76519f224cbea3be289a74f1ce4281b2ec15d9ae1989a70108ba5b6191af2e7ad0247f969cf01fa6ded0ad84ffa811c63fc1b182af09dec5148b7e37a3460f88182c4a6b9f60f8efd982ed1109d081bb989fc3d51f7d78e2345f8ca50c6a41960c5304ef9e2ef3cc094744fda89b6640b8ea3ca4b24da88097391b9e133c", "1f2b82acecf47b0470a31660f23769416e14875d58ff2159c3e753643f4ea9eacf47ca4ec4ca7fd44fe9543c5cab55e67612b03fda089dbccb5fda036d0cac14d5328ed7467497ae5889c51ddccd15819e6460ad6806e3c75fef1fdbf060df66668fc0a2bb8e720aeca502a5f9fbb5ae47812055fe907277f6308b1018ba50ac1d42d87a3fd57a5553e08b399b95cfe39f4350652b4d93fe33b359411daf685d318cf0967f10a51fefb0b6da707536be26d19d05acec5774e5260547febcbac6cd1c5d0a5ebae61cd5b49c3953129d2547997f60cdb21da153005c488fd135a3118a95819c1dbeaed025e956c6855083d1596edd16b22416b853e55de21d223829baf7d3fe710c0fc0d5f396ad20c34ca15ef9440c3d06084b0fc04707266855b94251fc94e8c1ed5ca172bbfbed8c1b8c603a4fd3643f79cd0b61e9e230aedc6348b381f9bc6df8887b703bd3a3498390347b12abebf969cb1362cf9b75fc7acc70cbb8c9d3795a87b5dc2e4d4c242b899236202dd349a530988930033ed59ccd8da9e88dcee4e17740dfbf40a007f8a4c013bf00a2724facdf378f3c4b56715ec6b002465d89327f0eb9214257929305202a67e8187bd25e1af5b1006600626275da519d73f823cfe6dd6b83b17868a38472ea021da22eea5ac944a77138bc85654cd0eefd94f258bfef329838d4ae56b5ed400d55f56cdf1202ab30922d5b68207681038ae671c366355022ea268dc27d50d758e267d5987b5f95efdba9e8e120652f26d93461aeb7b41538074fa9686b0a8e6f6a6f8a1988420a9863767fa3debf87822976955430c5edd9f1a98ef68af965771aeffae93acb362ecf73f4c993f3dfb5afbe7f20b1c72ad9a898d6d77dedd10d3e5dddbd88eff275429a4b16feac00f7475cd3ee8d94c364eb254010c17954d6c18f86deaeea9ca1475c85b7bf0895acaedf5e76399bfbdd2b4625c34679ae6cc6d9b47389287362a9a81f16166f3736b74d318f96ec6d66c1b115af711b319371fc55d290af56b4af2d03933b0ad153c203c62e6ea54008778a947ef477351ce5d7f3a033c5e3fc127276cb056e76fe4d1de2645d277c1638f50df753f509970f525191d423d34974853d408a3f7cfb867d42b78a4fdd82324ee36d1ee85bd37b509580f56718809b8317714b27ab20646834bad9f8e4613c5b335d778523e1986ae31941334a718bb712d8a5097e70e8ef60a382d83001aecac2033c649ca0cdb7eafbc39a3d9be75b3f3e6c7d88810c32f8f5430391640ec2dc010de2f4b727c08f7762da654f1be2d85ad7894db11860040d37592e27c74fccc3fb20c92329ce672c0729bde2f9b36953a7156621a51dca2bfee885fd9f4d6da3f727759fe9930a50191d82154b9b5900c9a4537b53e908d428bf169a41fa361a786a4371ea130fdfcc1c2e903dca522776fd29fa088461408efcbdadb4a351c85f5ef1e7d5cf411cc48e347093c27df4c1a787c623232a47ce2c18da62f66cdd56559aee6e8364881c61f373df7dd5012a3b66d35a218150fa97e2c16097471380833c8aed0dde74a7fe7ca94b2b64cb00b7967edbd2c43d2f4f2b02c5a4077af9c3017e31f975c591b29f3b416a3646f6009bf167a0a1f7974e0259cf56ed6416aafc942b73877a9eb9869c097540fe52abac977be7123e5df2626fc2d4e1113904de7eb0cf8e5f9ed2124b618a370e8b745ab0d80500f07f8d8785bf1c8efba4b9c6f163c9bf4002119d2517a8054e5dd8947791d6326ad998b425f21710e8fadee34b09cd30a6af5e25cbaa5161c3a9d4573f3c519b7d8bbac0300173f10ea4ba59cb77c8e3befc323a0bb59eac302173a615a9e03f232e42b1119bb49cc576ddf8878aa8973a1f30e6a827b317e7e5723bfe59d595497bc8f2c9feda7ff52bf881c1c0350c21cc4954bc481800d7eef899488abb680e292316a3cd67cd20b411687809e142ea40135c0d651ec28af20adab4d5c608f225282fcc753d46481bfe652f4ab50d6f22b0faff21468f64db26d7a2d32526bb3bd1a7c9641b5ffadd4c15d209d39b66280bd08ab3bfa5d2b84207d44e6999ff3f3b5d0b45d7101f43feb222d54f426751702b", "-c655f2658b281bb6774d610168d0cdf97886bcf4ab56c67fff55d78ab3127f9e7f0cb1d8039efcb866fe47f0198242f5a4da68028f9efaeffb22ed1dfa5603c5e06794fb74fa2c4cab6b974e93c0fc055a747f8f835d07144c0d31ed2c59c33b8f6562115321a1b247bfeafd1051770f23e3ce9e367b04e772ff582902e4769302a8791cc19d391135bac4d4c43eaa164b5f63263c8941a184309e725c58796fb182ded7bea828c378d68b63646e94a6d7533b6670066cb4767a80eded1fc40632f0c43230bc6f50fddeee4473850f6046e4d62a0f1fd59c645788b22ed36df6c8cdceedc8a4b253c95d590618bf5c9ef4070ad77e4c47c1544f5573d5ca99a74df9fa87fdcf6e8c856e9024b0e759d5d0d22d6a7210e47cccf34e75052b579699dac9aadf1bacce7ddff2dfef6cbc30560ee941aeb8b7e639d0bab2387bf7339731750228808865aef580927c2731ced7906f18866c83e7e21da7c7c16e204fe08d9a6da3cc0c91bace30d5ec416eb61d6b04f3fdcff3fc820623b77386229cd10bae0de75afda538acab8a582157e81f98151899decf470d7a94daf985ea4e6383fa5f9db8b43ed45eaf4daacfad9d4f3c0af985401e19bb1d2c2495ddf454ccee0105cad45714d7d60c41c162dd2994f458def1bad4a74f72482abd84edf89a330ffcd313c09ff35f764acbc36c144910ea7942d6c9a8985cf8e04f512297758d4d2008c01664b8edf437396ae2579c75f4bbf6030fe071d01e5ac1c89f599980488a26dbf6b78c4b6f310f8ed308961dea492794615d29d29fd17f291a9e2b9c31422b420eaf1232664c254c221812251ce55c15a5768d03384abb6e245e3849e0cec86b0c7aeee3395cf95f663cf0793bb5ed26d7cb75112a4b4ef0bd47485a7b7a36ef9e9d586ca597f7e042b7172c7f5a942c350f6354f888436191614af51b810b133493f43e21c98456889a6f6cab29a7e4c0aae9b6e19a766bb9e42ae130066b0842b4e6d674c2f13d103fb9e5ececf94e3679ab878d7d0854e491a23cffd9c4468047ae59960ee7277d8265fa1a00bc21c1b06e4f0e9358cfa53d2397a6991103faa0cd1c3102564f26b4c0181f162135ea74b0d9d77eb208e2328ca0b33de8ba300c1590835a773879acd22aa9047ea4989f873538db3a32fb83dccbe810968c33dff1c96b48819ca5320083dcc836cda8dbb17bdbf8dd834917f46547a7ff04ea0ef95667dd949f71b36d7ef055a7f2f4dd91f6c553073451c06d6625b5960219c3305a873d07a08383be80bb0b6caf5252af3114563691fe7df274e0653619ecbd38eee10de826488312202b854735d01889d1361647438e7535312fe04bd5873f9e933b31f03694ce4a2c13dea85adf736afd1bdf45551b008854f7533246f74ae0508ef885ed0a9a30f424538f5c0ff3cad553863d51e44af1cacaf7c4debda37b567dbc8623a5613b1c645e58088179202476a62a64d0ef93dd425841681c88be1b523c49a7b5c38905de75c723bd8000e6c190fb302a59024de1b583bd15711bf03c06857e43ac0be43d99bd413350d465e3507a474d07981b65f97f5d7efb7767d9c0ee64c64dc7306f44081df22ca94ba225b0d125a556b9c667ba6bb8d0c61a7ed55b33e91b5a2407bad359422ed75eb0f62f8ac1fb978f4fcaf1e585666bad4f2eccde81b3a7f8ad95ec920eb7793ef7c41fcadab7d8fa80810dd3d58b084cb10e9ee22458bfcf9ccd2f380920f8593f8698f194f73c08c7244a58ccbf5de84245a28541897f63432db8d67fd303affeb7ad2e8de25bece9a5d86f296bea2f248407660503b20d200b21017ed4ed516e4bdecbb6641c007e16fe149add290b22a69be9cb6a3bc001f8fb663ae096dcb8dac1a5f15f3ce4b861c32115c054ed84eeda36738514dc0abf1a2f89cee9019557d7748e5277114557ec48e402831af159258053e2fa622af21f0ae9fd45a1a50b3bdfeee70a88a7cad47ca4d99faa27d7de3b7d07f99ead6f0e0fc998ed5a54410ea95ebbaf46c6389bc2fea9a84cdb784b1fb3ffbeb26b934aec07faf2cd183acc49cbf8d7a7e036c81a72e1443ce3f871868ffa5be8b0ffcb55e67b82ef8367", .Okay}, + {.Sub, "-3f08bb0c6cb0871b45bcb8baba975dd15acec53d1381ba03407d0e4bfcac732a332c1af982927b2a64dabe075399720ecca89e081d742132e7daa1303a41cad83a550163fef8a4225c0ac0770c331362d690a8592c019736aedc560d73cbbf0a0907afc5c03eb08af8beeae02b21d893d2dfd846116fafeaa7b62260b54f3fb6b911b7ee1e6988d6405145ecf15d59b92ddf468aba7b60d1ec0cc0fe9857f0500063852459123f8c52ac7764200c8b4ba5ab2d52cee46b22124b5bf13d3429c02de11fc3ca8828479bf5385061d010e1c24da28903a0089de65fad43d4104368376fec7b098a7df5bbcb31caf31357f265b81d1da7ea453f74615c0c4d8808aeb48435262c3b56d936cd967132e5a7c7a7f7bf7c6b4ecbddc5ade26e134aa23b7d640e6682676f29594d3920a35f704a5fc0f7d8a2cf71ead2e61998027fce0a1bf8d5d99a19c229c0686b502876795ee189a2b091a239b92ad02a4e84cc66fc67e2c1fca9362f72f5f34bce905b1a4671996c20545dcbac7463617ad8924cac1ac4ae250b5fb615eef1f6fc9999a1b0f69dfd5df9a048d30c1ce92decb9052d0c15fd38866b670ba5f71da6555c1df5cc418f90ed316311d1279013f27ea999c4922e46806e96f77bb46ce6866a8efcad0e112da564147fc481023d3896d37f1f5ab817464e1fb17c378478053cb3d62d1c1eb2bae42e075a16f1a9546a90ecd360324945d911233b405ace05c68047b03a77cb8ce181033017c0984a95170b94b8a1717e9e91bc350a6baaaaeb73d971646b73b0f5d9916177df1721a48e3dddd84cdbdee7bdf394cf4a652fdb44c777a31fc521ef0aa51a71abcef80b624979186df994f48ada1fa38e3c33bcdf948d67e0301b4e8d726a4c817128d7796c87a8567ddb5f4b4713d81dbdaf613dba3c93ff78f361b8da834c7e058dde057df5fdaac55d959e40bbc047926653cf17523ff92697a9ba9842c5024a316918903b97a285f58c6f61e6c84abb96060c519424af50fe6471a40ec96a5b3097ce08389066137f91313fcc674fc5571d0b25afa638d6d5624a41e9cb12938ea4b01a9a178c6a5057b6bbadffcfeee1e1b464dc456c3408ddd4d25634ff888b268f1cc158163342bbba64faf1c43dc7d966aab1715b4289e99edea4edd6fee9ea1c63b7ddc9094df4c2eaa45f043090ea7207fe970be2a22ec34ba2f9e7237a755732b718925cc08290c9f45bdba15b74ee1e2794e5f519f6ca6708f17a5519a3a0950595254e94c847b216065aa4dfc0b9b2f8ec487c4998355dae33cdbf3c3ace1a8a8abf6f3988bf85f26530362e15dfd982ac3c5f30033bc9be191aa1a5ca1807572f691e4b3d5c533a873a625eb2c33603df5bf0d57c96b2cc3665562724c94eacc442e95c242b0c667733d6a7afa93710b70577afce80572ec1ed058d1af9f859255e5fa84c1a25462e52cd65e698819584bd06d4c2daf13652d04ae1e08a5e7350f1849608314383d36b8ccfa23d27313fb1dddb1e723dfe3e5cf4d9a9b79d0e6b5ebddde7c21c175ccdc37fbdb2f59c92ae944bc9dc39cee99895ac956fbea59f5013097ff61a944a6cc41e9c33b011fc695d58e0501b25b8de94ef5a2c5c86d6b26e429627cb1a2458cb43af884c17e00827664212392b7eb5696d859bd670397f67cd6f7327926b8d7d73497ce828a6ba876253d8841bdd31725e69c14313837d4138a2d396bd22ae5f10182941ae621960040608e898a0b99fc6079ae72d8269a3c2aa29aa5b51f66bec81bf62d8393319bf2259f25cf23873dbd432b341107cda9319d2536d352896043323d8cc5ab9e592c1389c7d2ff89a402c3aee47e11aa13fb59f2e07358f61afc91fc210d14f16e82d434707a87fd2cbb2e8c89cd6b1998045cee4129e5df1cc41e11195a9543637bc48e42d5d23c571f773100762ad2f2a3e7b17c0c6f0c6fcb92e2b602a253cb9656ea015c0c469e931405090bf80a0089ece7953bd78265bc837665d9d8a1c7ed81552afdd9f67ea77d26635bbfa29685a4d95e4564b61dd0b1d8750e25f5a837d4d5ee43cd86f4e698b74f4a2e276fd9cf4664c49a6a04b7cd322517b3f534eab71b56b076a99", "8dbba03c483845f5b0d6132a70e9c6c36d2bfd642a39b3003724b61cfb518654657d95bc9a592608ab8b26243606831425eb5a18e9dba1d46bfc2355f6044e63ef20c8fd334353702dcf52bb039f5f0bf2d9b9daf8d8a54831170fb1d818afc4fbe6afe0001f17de138c94e356eb66a4e1ba0b60983cb30de6547e0953a51a210570a5babcffc6a43437e1b68b53d4362c3182318d16057cb723d13c528399917574071aa7fc3861e53ef6d3cf07ab8b90919054ae5495fdac6c45120b1f77fa24307730cc4aec3bbd0ebff8d9e443ecfa8e93c3d10345060aa4d16d03b7fbd63dfdc5f36a06882a8c941eb91f6130e501c3e3692fa6f97c32bbc4970d1dc6b04da5829df1cc27512c096d53b4b6a338422094287784eb0d7b12583c0d5e6c3142fae15548bcfc5218eb43d10af4420616c80c7289773dcf02c1d907484e14bbd5cf8874de290480ce27d9da0f97991a59cda3871cd95aebd27a6f5b8a85c3ff49e93dd90d10c7af6e48bc39b564cab522d2651616a1f59fd37137ce5f37fd996855549c8c46cf282a4f3a80a64e337fcd5e686f19e2a53144068bcd697d24a9d6dd1b634b96d385d788704313660bd245af942017da0a57228d1c7ab1feb03ac9ce0fcd299703093f1ef20a1325afd2c763e2f2144db487782b5ee12ffff6cf0df43ed92be1fcc294fc686e5dc156f4d8342de08a9bc8b08458bb45113333bbb3aa7ccce389af4039c09356b94360f41c0229e47a2c32000e20c626e69a30f71c7f6b5fd609cb7bea38ca5e7edc3d514b3a97f0b29cea680bdca27fe8cbdacb6b7e58c2c5536d9aa0039f3031332ae4a58bec6164cb0b90ab500d97889a95d04de63f3c1f1c7c7d0df02428932b267448f129083c5cfbb2970d5a9c5bcd23bd0328700ef7ce9a7ac0e511c127a2989424d555e97360585e926172541d198dc0c75bbfded841af00893bbecca43974e3b5e761fd27dba935c7a07165b016a38dbc380dcf6de34d0d12879d968264cee78988a5a288b76ff369bcad729b70b8db2e826fa72c373751d60392731879634e955efc3c4ff1c3c81223eb09b5158d3ac1279304c38e6cbb1cd19913dc1705bdc63fc59a0a82866e0eeec08ee6deb979c252979185169d6c6e1db81467bd2146d62c7dff84acd9c4993bb5c2966a2484124b53486e604b41cc9953e3217b52b3959dabb0639ee5c7e13952e72108e1691df512143ee21c16a925a206951f8913dce35fd30c992a0e35a0754f086e6529127b0e5bd06536e5888e571af25c179116ddda9b72cd905a7b966396f120afddd4853522d26b4da78c65e23f5534f4d59c3bef93b3126bedd3fdedc96c87a1014d1ef0afd976ae795f8b21c97eae1f5012fd9d0668e5703f6555a9b695b01820088cddb7b851c465da5c907dbf732b6c2ef6b551b21276065723e74abfc8273b3e802f88c439e08b85cd901766f018c225cd8926546f964cb477a0e73460ee0ef9d8bbb7277cd5c706f80fafb1817593d1bbf367bf941a231749acea3eda59dfd7ab24fff6128d0b638961be3043056af7900369f3232e7b48fc03d50d0160198fafabd755174c4c739076c06ab51b86dcb42bbf288743aca365aefe5fedd371445ab12f4b9753282aa657dd755ca1737fb3b67538d22dec79142ff825744ac92309eea90ba657c3de66601fbde527551888e8669a70320ab821c27f53d5fcd625ffa5418f81e5707c78007ecf7063bf78da87a1ddb00b299b7686b4f5c7d0336c7a742e0d474bc11bc8897a56d655d82cb17d77301a7765b5517d16b53054e74fc540491cebd5e4bd219c03e547b572e4891164cf49eae67f952740e27ff3356170e498504910355b1e0902cdc96718a2baa7bcdcb5322753859e7f66a25dd1e93f98d8f4c929d028aa2f98f86c6194a867fa6c45d04c09e9cc28353b6b09c68880194554f55dff1444a09e3218fef243a38aa607a00abbaefaadff20d416d68608782861dc15be1bf4af763a3a7a1b551309018e3fe83b13d5abfb340cf214255218d16ee5f9a65e7bb1ac36fb52f74803de29cb4abb0cb4dd05401b91e8ae05ed39a595ef9a4d6ab267b6032150f1084144a581275fb79fdcf7a5", "-ccc45b48b4e8cd10f692cbe52b812494c7fac2a13dbb6d0377a1c468f7fdf97e98a9b0b61ceba1331065e42b899ff522f293f821074fc30753d6c4863046193c2975ca61323bf79289da13320fd2726ec96a623424da3c7edff365bf4be46ecf04ee5fa5c05dc8690c4b7fc3820d3f38b499e3a6a9ac62f88e0aa06a08f459d7be825da8db694f7a748927a37cb12def5a10c8bc4791664ea330923aeadb89e175d78c3f010e77ee37eb6e37ef1436d7363cbda77d39011fbeb7a1034853a1ba521196f496d314835903f8493bb454cebcdc364cd4a34da3f1047eb0d7c83f3e756db26e73910620485f5084127488d7677c0086d7913ebba71d20a35aa5cf5f0229b7c41e077e2a62d703c4e79c4affea1853a4e2d3b6eb40c03aaa20a90e6cc05eefbbcb246b7b72387cf1ae53b2507689044b2c46afb9d5a7f29f4acde2c5f1c85e4e7842c6aa8e90452a380e12793b574637ae7b94a4fd4a99aa0f522afbb1cbffd5b646f722643c080845bfe4fb946bd1366affc14c47d4994937ca4a45831a02c197a6853e1941317d3fe7d530c3fc65cd1382ee04502374fb563629d6e2f3189bd2023a917d7f8de968c229c811f123b1050b6d68f3b4ac8ea47d59d48e603e13aa059a00bad35ef099903ecf7471f41fb9b1c9073cac611e6896ca4e2d4ef6f072301c741133ece662fe0acb05504c93457ff6b7de6facee659dc4a8870aaf162962c0637500ee24bf09e13bcc3ca1b0070db3033e3886bf312f4802b1380cd154a85d381f43360929c7b12abc9f03646392c3f96d5481970a7069094956a59ea43b2b8e34d2e995610e6fac1d2f0c2686ba1635c5c1b96680a5f819c6fead35b41107572d93b264c6e80608d659093857ab89250159dc0d84a49d298ad0c68cd32de5c1d4bd2f7ed703d64e6169556266c2113915adf059aaf7933ebd596aa435d74d4144fc065f0a8d43fb08275b23bf8563ce0a6573afe17fbc1df7cfb055636fbc6ef94fe852186adb391dad54f3871be197788617cdcc0886e36712d5baabc86891a26ae2386f966e744505351325540e09fbeefd9d43ba3d555b3f1f6f13e62376cad16902bdf8ba22a28531ce13605b406523c0177205489683aaadc4c7d257d1690f7c522f9687f1879dd9420e9678a33e298cc1805440e7ca291c51bc550e2c70f85813b265c4bb9434b79305cda91384333a0a9b7e389bd50da470ff64ace09d817da7f0947732047845c8268ff4753e91efa4221205be181033aa652d7e979e94b1bfd21cd1440fca2317bc65c5b829ca31562d5b7df85f0ff4920bf40d2d7ecb1275834ad4af1ee82bf2e315a7b79217086b1251b908a44e59ce24b40acc9a125c2bdd60e28616dcf8f73e6206f2318c0f0cbcd4e16eb55120a11475ef7240d3c4546722d4a33fadbac961e0f65d85e5d4504ce3213397a58de86c85fab0cbfbe2e4ccd6b143bb52462d2932713deaca71321641786d6d29ad3bbd85070a8acb7b3c8123b2bb02fba5459ab28c61158809df1884117ce61683bdd3fa4f277ae62f81b000b8609422b1fe3eed0ab517e59c6ab996cfd8354efbea5e97426707dae38489514f36eeb0951c816793c7c91e8d934f47ffcdcb31639d8e2d7af344cab0a8b90c29bf9793be9c9f144025a492e56192f9e69f93436e10d915caeb70d1ed9d312ea43d412fa2edfcc40a8ed3fef3f1b23fbe1939832282c824b907399aaedddf888d01273ca101e1b6141234174054bbcf6b1a99fcddd1cff1756b771a7fe64358153b04eab090ef3cd1581243b58a9104879a90d5bd23b005a8382a56c499e97ad94bb0e3cb4a620b2382fcc51fdb22ac2e23a951ff398ffeaf63625398647d9286dab38bf6d3c4e2756e5b2e1e523255469a86164a72750ef8b43b488d8ac4ae42a63e114ea27d8c94ee17294bfaad627cd68fe2c6747f33d916d50b91652ed22d1da3cdafe2c105795bc4bb72690a05572716c7f8c86a7ae4376fb2279c9602b181b2b0931e0d17fd8dc3b34b631e84c47a5b0e12fad740473c42d1fd0e1406707e98e63d844ec8086b9919ddaf69fb7422fa901c1c938c8eb3b6fc0e564e9e241359bc83f8cfd2d16d0ae4623e", .Okay}, + {.Sub, "-854e3a3fac0e8149bcf6185a3c349e359dc19e023561ebba864f2f9c0bc391be3bb77024136cd815d9c105029a7003183234ac73013f8e984eb72ec88fdf6a47c7419e6b0b42758fd946d8bf8577aefc027a29fa80a644f2c4fd738d738f5f350f42e52c2ab6ea647dec287675c46646bf6c284edd6d0eaca057c231c9be8e68208a7906e3a2f67feecd23193bcbf753ec89ec11bffe8b6d43a2b954cd07c5f33207d3cd32f996fa1a4fdfc93fca418c89b77c2cfa18dc34795cfd389b65e061e548a1a8970e282500814874d78620a479606a8df0af3fb5ff1741c3885329c44fe91f0d7fa9321d48e01e4ebed8ebb4106d39849c08f3fea80d8f6bda320489344e732f382f41289394ce73c48d4e0a068a79613a42f0d60d6b5744dbeb72bc084d64bf41902576ec0bae12d429337e6cd3e648f784b8e64bda7f2e2186b61202cd109816f1ab2fc6df43084ac2438ccaf2c89debfa5efea9600764d49dfa13349f420ac51cb720fc83703c042ebdfaac9bf7a5a4af9ec58f1331d67dffe6f5a4550d8199081197312982b10daa574687932be43f480c5e979c678563acc5d503e4d760c9acb67dadccf0ee167f753a3b72726f7ef12687b6b4d400053e35c3224821c6902a4216693664ec25fc412dd4492eb29cbc5a92db2b913c7de5d5880801ee075c43e02c730b8ec054feabd0e954ad41055349989c1182c907405d81b5ac0210b05cbbaaaf26b5e592683e57b56649d9d3f0ad1c80fcf7f6f6c4c894d42349b0327c43fbbdea324ece0cc3d4f446faed287fba5d6ab94c29c6d39fe6e799ed799f4b606de2b4dbc64249ba891de98e3bc3a69f456da3342406948dff6f403f615e54ecd0fd4072bc6130b7f0714f54fbd99ffafb21b7a0e0c38cd2baefe69bd7c40f65a72f5b4543a447ff8edc9cde1375d598e886726522925c168bbcc5103c4df1ea61959abc12e47c8d2419cc44dd52f3f2d0ef040bd47d258d67e22659313459fa371564af24a124876ec83c289b5827a9667cd81acba64a71a18faff48d94a0eee4461f53852ca9b282ff4a6034c41b27d3c2cadefce480521bfc9f55a4c491e5696ab53c7ee1b2b2859a43fffe9dbc1a10672f47f91ddd2ef41a783240214790321057009ce163b3fa87838e719347299b40f64bde447fd4ecd717245aa7d07ff93f0799d940577f6d34fff309e6a1ead5a40d3f816f05fcbd7c63d38e759816af4ed030fa6aa703df6cf39ba941eef0d5eea7d4f5a8bd757bddf5a7ccebbe31e9594551cc8d3ea43555d59d3f810e28d95f375f5a3669a91a234bad860dddb59489755405b08d6beca3f4774f73e231986888bfb8aaa06d64b279a54422dedfd9bf33859160c6820a8016ecb11cff39a546ae6571240917fd097f63415b10b3bab875bab3cf2b5d1c0e7d1919c3d7b548f38ea0cdecf3fb8b8ea5da276b2f179220103b7219a3520ef3a6e20d6529f50751b4804fc99c513a42a6aed43998886183b2686759bb76637250ce76a52c0630e1d45dae4aa82d47d9393fe442c117242b8a56827ea64db74f9b4588b0433be3f8b27c432853531a139d26c0f9a7b6e50c0dcbf89c0dcb26465be1d3bc5c429b680cc0d39227569c419206685b4fa665237a0e045d0cd84bb09d7f1ddb4b5bca9a46706dd01b36535f4c9fad9fa3e0266b6f71b58556ddd136dc917482210056ff8bc89ced08cb31f214bc1edd840beb9459134627b4a1a6d205c6ec0208ed94cf881f2862add4dcc6522ef71195977d9dc22a3246b92ee4ceb69304411f553a5c6796e0414b512958eabfacaf33a195297b1c206e8517abb115525d337df1539ac7d7b17a4726fbf2138478fa8d36174e10e99d50f0d29ebd125be34c5752f6b7a93c5b72cc977f43c666973febd43398d60b6a2705de2a427ed437cca98bf6908c226e8283e17e42fa70e0fcf19170649fbe16d5132af89eba29f3f0c12fa838112a7b409bdba3d07a38b62519d72c2bfdcc0ada40e93434377d98a6a6319e7cb9353a6f567eaf5047f5b0178cc2402d678cb7c55f2880961816974224a7b3c7d9e9dfe9caa8be5efbc18747207a726bf817312cfab5f259b49ab5cecd2ae3274d6fbb", "c94d5c9bdaea4e215f9c7fbafb63a252c3493e7178a4a02a2c7e29f1fc6dd258734c47b89580b3b29d9e8329b9fc7ec4a17f976b54c40f75506093667b1f1aaee7110b861b82ebddd67194c29e43993d391d4ab68781d77ca709d4ed6773731963e9b11a2eb785bc01d8d2c17e37e84f9d06bd3a5973ba290385a81608548ce3ee069981650ea88e9e3a5351b90b31821c865eed9f5cb833b9b6c448d8462ddeb786fe2da2a87f88e7b9ebfeea8649bb4a51973a7b7f0dd984c6504598b7929ef063c41b06b474b227730ced8a500bd38bf28a0b97d755b625d9a7ec867d5a69f94eec8313d40deb8d0e7ab96d211bd35949e9c5fc059e42d9253b76beee5828ed84c9040648d5541d4ab0d66434ab05aa38c9ed81b49a8699f8862c7a50e14853bbd90fadf85639f8520cbbaa89de7e7f429f6c30933b5ec3a2f95ece9078d0377f8254d59c8dedda026b4a76f6353e13372ab18844af3959aee8283fdd7b3769244ef34a7244ef9270a6c58cf162e8fa93de0c6fcaa191444e18559076bd73227f5e40dc81faf6a5e0c4b3ebf16c5161c09759ed0c88db1da4442aa1fdedc4db3c4bb3e153d643567a21af29805e60ea75c5d8a781dd6d314318112d89a15e0edf7c5f53cb7296db0128a5d0064f693649bdeac789be9815c6faebe22d8ab4e26495f295697647d9c9d176a2b4a0f5d11bb8785cdf010993412c4a118a2a3c1d282406e2454f4c51ca0b6c946765449a4942c816e170cf34ac4c4f1fbb2327a27dcff4b6f779de0fbd195c41bfcb206fa22416f21895e256b2635260d61d789c9f77ea8332f468043a1101ccb530d3af6a7cbb9471a4008642e6c731eea10333dc95c0cf233fefa3d0e136d21e056bc1445a084d0a56708c18c77785f856f1d1eaff8e370e8f69d90f3ac604b055949314dd68cdb217898257053cbec43dc2fb6b5842b04fa908871e4a4ab8b8a46661352c7e0bbeeee92c8b66b52acc78f9cc51cdb2bb32e237edf12f6a61ecf57bcbeff3d67788fb10fb8d8583d5b6312e1d1d7747a52292799baffc5b811d6d5266df933ea22a238c74bb94ecfd6c1f4e5e972e3f9737673dac8b111b271864cd44722bdadd833bde084e855ef0475bd8828e9909925f51f0e926532aad9ff48e088128866d7de1a40b0a7e425d1357ad1fefb50f9462132259178add382d290bb9f918a70fd792422deef66a57ae54033e2f6e4c7da3945145732c7f751294d2829159e0e5f0557bdd0a9bb728eb0c8f8618e89ec024af7f28af414757aba9ae96750c2aa6e3d1973c1b0c1b67bcc9684ff35ece05c486b6f03e1f6ceeacefb89c2841925f85081c9e5460f24617563a74fd69ab1f1b71ced2477d8c4ee3cc1f002bfc9d7be4595501d88c3acb698affa745a72934c2341acac15dab1e4c8f371c80fe5e2216a90d47743b6c4fd4ec16c1d2a5bf3391ac3f65ea7992dcf0f753c121eccf33a6a9c73aa7e00fc7cedd3301ed3b5aead22be996a5d7f625133ff416d22394f23a315f5dfc3f4973fd04a6032a191263762330763c16aa104d9c391386e6be3dbdc16fc7830be60088190ba1f9dcbd329b7db114401d83da106989d73f8901e2ce61c55d72b6593ab86967f0cf578e6cd62f29e16c71065554d92730c670273f83a72faece9e1be6944b682a9578d5e3693ce8a12012a981b4c404e84cd57046035cf4e8e290b7954f60b219ffca66fdb0281c54330d7a26a24ba721406dcf5fbc06875e1e6ef30929336fe68dcd63b315e49d80505052fbd2e3ad192f9c603797c1e8a56a26fcb4a94a169d5358bcaa3228d3a1b9759e105e0437008f66992bfce493a68342eb66ad18b12f219245e4bf55c99bb917bd7ddc654ab675813f26d04c5a387218994eef42bf9937fd75954882a41f3da3ad595aea80591551d7363a5dddfbdcc829576bab7195f26ca57086fcd09856a2ae488c0b3763c5157dbb3a2672d7372dd78c30b794abb373f97be50934df84a50e4741039c4eb0888fd401706e19451f2acf06eecac76e734d03a49930d56ebac1c443be0053f10af7b1258251bd38672a645a58777f091af4b71b74b7ba590f30577abdba239c8b36af239210fd5c2f39", "-14e9b96db86f8cf6b1c92981537984088610adc73ae068be4b2cd598e08316416af03b7dca8ed8bc8775f882c546c81dcd3b443de56039e0d9f17c22f0afe84f6ae52a9f126c5616dafb86d8223bb48393b9774b108281c6f6c07487adb02d24e732c9646596e70207fc4fb37f3fc4e965c72e58936e0c8d5a3dd6a47d2131b4c0e91128848b19f0e8d07766af4d728d609104aff5f5b43a0fd597d9da54df3d1e98ed1fad5a216830209cbc82a508b47d40913677597ea0dfe234d7e341d7300d5ac65c39dc29cd727f4556261d62c780552f4998886956c24f0e9b00ed0842e49380b90937d4008d5ee99082bfa078769b7234a980e92418132cae299205cb221d33c333e78167cb0df7f4a28c1f90fb0c3434ebbf78b5ca763dd71563c54045c093dceef887bb0e45dbace7eb311fcec1685b52817f4450f7d788cf0172ee23a4c92ecec8e391da0e1ae52c1b878cade29f34f743f0e38030eef8d147b754a9dc390fe0f8efc108ef41701912020e3a72fd5b2147a4056d3614a2c0e76a468c6d46bc2758a0c8dd70a4764f99bc397e953c33e2c549539b540abb005aab399df212314ab008cc10447129d3fffd39b25e83848267303f4e7f7ec1132c7d72131279e25e3f5b4ad44378d91f60290970a92ec9d6446192af0f28c286013603cea6683f9f1ad56744cd56036f7b34cc6ba7065b962324aa22f52af1318ca87bdd2d4261792a20af700f0c15226cfa39c4faf8ca1ead21debb5a94446167febbc76a119a4e973bdd9cda74bab0fcc8ef563e91f041a98503fc16baf7c27a9bd5f84396564227e54d5e6eeecc80efeeb5ccd540af758184345f3e61aeb38832f02a31cd5222d782cc0a11153f3334ebd5c3293af0426aa516badd06858498529acc1d19b65fb1df511086a8009a8f855236fb1bb7c4387b07208c96a5f5120544eb830687efe41936a1cb9065d9d35318a7b01715b5eb2e1ba1b8f7289a7f20661ae7826e3ef8cdc6f0355de8f03117cea942c1c71cfb0a4777865a04f7c00a2cfaccd6bd539c3815de1cf4fe0adc71fd56629f37366454b60378673e9e1ec716a5b3683e45bc94ca717404d9a08cb1752deb62bd97b3f55ee6f7dcd580e248acc9d06cb49b3a6e222f97d53c78f03a8889004b6f800c50b3f4c00ca20a1932c99f706d96a3c32931b981f24b67884a878eef90bb0f6797d17d1fc35ebc6b450c0ba9341daf33bab0094435d79dfb998b1ef84f58a27df4651cbb270acd1a8820b640e906babe2e16881f49313e4ea4de3ec4aa96a27f1fa709b526b759e267282733f0c5413a23c4b79b373729f3a5ba5401cb8e1d36739b506dd20aaf0b7c39f27770eef41fa51a8917b031dafaa4e298042e94e98e392fa4886f1abef72a2fcb0c50a6a8fd2e7d58337185eed77ec532afe1777e5ee5e563b02dc3a3cc8e7a250787fe69ec0c3d185fab504f6944962b4c8cedc98d09ece8c5c605f916b2e6d4493ea2f246ab44b1a58405d7eceb6578922f20b976637903fd09cf7bea531eddc6358f6a6373a54a1c66d2c8ef3e9f063222c46ee00fd53c035882928db6c25b597037e2c433496204de97c761e34b01d9b6ad59f2aa460c57f772cccdfc00432615df6c825d58f04e67f0ab261b172e163ef451acf02fa49150e89b6af81bb89e21883830d1d0f0c8f845f070ba1d61f2966e4c8245d4be86e595482582be40c148685db343407e88c20c04e56ed4df34634bb61c4f41c2da68e1b6bd7084cacdffc5ac4ab7c1b1e127a85428c1291e7e62f6478b7172301d1bddcf5f49b3ff63e18695965ca68cb3491be7ee31be2b1a4b8f65f7ad5e7414b1a9ce0f43fad213516bedf4c8be0e9ca015acecd37e97387dd2273279f50f01b54f4c1bbda3edcfe640cd53456d7b813af178060c8aa9b94260f02e3e9d48c68ea97d9ef8cefd8ecdd866d788e40fcf660c51d9f3630027f3f71abfb561b0f485852cccc93387c2dacafa0fee0610b8271192181ecd082e806287aa7a20c95fe54653e5d6d7a17b668fd1b315b7102d6477989a2e680ea09218ef34a2a058512510a4e250135de04dc7bfe3bef2a26512661847573ac7d5125ec7df0bcf424a99ef4", .Okay}, + {.Mul, "e9619c587d44b6e5a65ba51e84c9b9ae0af090120c2410246d5d37acadf648b8f27297c7f3698145a0fa5751431615338dda734563ec8f52888c04a690f93ac0915e918c3c1a8d2cb2189945117f8d4a7484d5f6ca5092fae7f52356e0088e0b466f660053c41585c8644a0cee65d2d257abd4fd481e4066f3baefa53f224803e6bc3be1a41772b630a9287c6e575cb6515bc3647e2f37c8f010fff0ccf11988ca23f3b76511cd263b77c75ed8d2cee807dfda77e9a9ba3912815a982710bd54c444c7e0257aa164da74750a2fb4b2e87863063338c8f0f4395395765c65fe927ccd81ff94bfd59ccb50e5451c140210641d34ed7694c4319846297def65d0e1684ff8b74f821bb2f1d5827c24c6b91ff841cde5a21d36aec87d6dbaf75cf038e5f632ae1bde91c441ca41194f22128e5d0bd3a35fad3480c3879e7f9f8620fc4be5e1492ec0c238226549ebd5f42abe408ee3af4bbf556e4226e14b68c27933e27755a3553baf9ac9945d5ce95f18af43da260f8c09010d3da7e90632b61611d210e14f2c8a9873882ef1c0fc3f991777aaefaba008fa283069f640dda93eefd2d317465e1939a0f391b9d7a91d71eeefce5a9890a9b4f768f051bfc398469c662f753261b61cc22ca44cf42cee46049ff0dcb4e41bcbc7c15d01b4d99c24d8d7888814e707eb92ad9cbb23ba5892c760b30d5126009dae5e32d355af05dcbf8ef031e378620f6e03cdef53eee3f9677da5adc8a437f327849b164d689dc9d0f399378290800da16ba480e6af76ff9ddced4c517a46e7f3dbf9b0c529ba00021ef89bf08af983f2d8e57dfa99e101be68f7f53def978523964b2ca710cfcbcbff70822f0b556f3292980651e4c4e95e32d5d19bc946b959ce87e06b2e80922565553453e3f9823dabeb1edf903a2c743e521e4371634cbaed92e0e65390f1fb6a9a13309564d92dde9db80e9f3125d82c8263ad92db78d28af746554d79050f77818fbd7fa798af8b358695f2e80b5f2f14c6f6c2485d865b333352789384ff178df8215e89c065f2c0f6fd81d4a3b1a2826f1bed7c947e45c3e4422d583d97c318bc090fd611e7e7fda830d8e8f24ddefa81d511000f9e4e9d9f48b6251887167b0ab0c4c66a75898732ba2056044d5052b9c320ec78ae1aee387498068d535a9902f673ebded07844f1e656bc47ea17c4f09338b35c0b7f15bd3a406a44be8b2ced2c15ac95cb0186a4ed4658683644b7141d386ca355681314f9bdf4b3cc59782340747855c04e6606c36d799d45996fa1da40f0c8a1757083c4bf5205610a8ce5f8be51e6e202627a45a5caa51802df72446a7ea15de44b34902cc302f4bab083cfbbbe137d8769e1f79ea4015bfc619dab3aecc696b4d7bd86c6269b4fa126467e99d9bb3c50b9bbbc5a100c3a68e763a15c742bbeb560a8c10ce706bb69afd9acc5c9d07029bf046e84e247a2da2452d229b62639211947ec8e50ba60446bd6be2da0b9a79af13dcab4478f8a26c1254c2f0e0807fff44386a50b887b7915a59d231c4611dae7b0fdf13fe298a32425cb03131883d0915d5810068317121b20789d5a928760dfa53bb1459d646771fe6a1b8c86cac75d70301c12ff60e7d642271d9058bcce6a6c51785dd828875336afc9f6a9111c284bce979119b46978e1a2c61da964ba855854c4b7c4609b42a35e6599a9abf2d8ef087e330634af91421b574ad57ab805ec79d8f70180b1ccbd3490d9eab784e307db09f034e7a4404509ae2f813e48cdae7b9a0677745489db23e56d7819e7a1d1a1422fb8d0fd700f53c6e11e779d15731673671e87dcc5d4cc31f9b38d4e4f2e5f4f7c7d5d8a46c234bb43fdd40d6b571bfb48a625be4fc87fdad5bc699a9e2db92df027785283a12c39a9bede0af351f2b24e4e6f93e4249d6eef9183d9188d7d8a7f5a5f652e9106a87e1db9e484c3e50925e74f3ace13fb8f9f635b8b0d67c1daad6ee48ecaa2347d357378b17d1fdf0d32c19e86c69ae98b1c96d79ba810f9d574f8b582d0aa203352c76386d2665f95f1c80cd7359e631480b6a78251b073a2e91d5b594b498548a348172cab84a5c603985eecb554b8f68674ab429f8f1d", "ed0bbf654fc0393f5b985c99a16974c12f7a71a0ad0a772b67c008713d426c96c41aff5f6e887fb981384602e3378f866300b19bbe3b1d5782e508d1a915d5cf34b3e8bb30d72e6da214f30e4045bafe300ad389a91218767b1b8b04eff8a063bf5458158cc3de686c82f0bb5ddc111a1b078aa2fa38bfb8fdf275ca939bbec1c8eb741e82e686043086896ae1dcfc39fc964dea042fe7a86462df72023dcef5c3083caae8f5720f46635f44f6bc19963048628fd3ce95ded68923d97e3af1fb732de9d858712380bac8c0f05f27ddcc7185e396cadc5b79dc8e8a5ed5c5b7222e093a8224ea4c3dfebb15dbcb3785a7c55c5309c254d6987cde9ecf45db34201a2f0b0c11e583da5d771708e9af9223fcd5d25aba6b834f36b0f218a596ce88d09073ce631de162f1e2bb6ef4d2a6b3eb8ff692775ee2fcbe63629bfb8d49530a44c081211fe52dccadf7781cdb376319fdf23dd212943799d19bdeb2c7caa7dfa51aad55197eef914613888f5547e51e723e5f3c718cc53ebe892df46672454f95b11bb34fa6233ace75201fe7e6f984fa7f4356eb4f4d1bfd4d49179ac0a14e42329cbde40403aa35ddae9493993e58a29b8c3af5ceb6d5aeeca8bb6471c0f8a2862d31584be5ba2cd5f22ed61c56ecf0cf14ad41b6c73c502fbe18e77c137cce70c1c238905a915496b3d96b36df4d3675d9f6e205f0317bf64c3cbe82b2cb4a63b4271e6b352f2f5e961e0aa0fddaa03b6159502ef87940f65307df3d6ff452cbdbd63153220f59e2e7d6664debff84fe9b214869cb534089669106844b801728b9d4536649e229351a9649dd192ce6dba3ab1494b3d59185eeaf93680911a6e9cfd0037a21a9b5c7823104b520a1166209a566c843da4376d106ea078311122bffe67f77f2f8a2c86d44b6338d350b16515ad40695b92098cad8c1ab101f8b9ca28bcbd92aa6eb5d751eb774c6edfe8d27531bbbbb2b4284d452e6b02ff348b5259d0cf7b3c26e8d65b34b692d6df0ad9adbf0a82e5ebfca719e5c03db4f014ec3e34308c0034c4f57ef4e43d34f51526bfe41b47eb890e90974861b01db41ed65eaf364472c31e99178b3c45a3d1583b8b4fe6c687f496ec4f8ef9c545c420143271043dabcc673c6b6d11d195a081fe339b318918b10444d53fda3c5b841caf57cf8087fba64cc4a609503ef2e59787c929f5d130295f33e7ffa3ec4f52c3c70f68f80a26d51513fbee0d5cdf0aa717aca8adfb37f6e4217487c3d64100d886645de337f92277a56930db09009f8f9ed6d8abd2eaced9234db19f4494d16b10ed8247144cdc3a5b8404a96441fd11e9b847df74c9cf9b3f6fe83316a220dad44427245cf5c9e2f7743afe6f9dc047bd865a6bd7b8ea947d963743a3cbf8b7edfebfaa94c6856dc7c985e1cb663d8089ad580460ce2d88a24abf9e07c1784dc4424848521c9d0f528664d75fd5ef52f130a737f12c5aaa56bf3cb64c2af53d1dbd06ac2f8546710370985ada2a2324b4e57a3e4059e05bcc5727242c6eef6f65a91ed13d6516a3e0725c9e6908f98d53f9fbd42a48cff9787af864138fd10aa6aa619911cc3c6089e943daf60c45edcbd2debd42cdf1f4dd26907a4b5f18dd745f75ae1fbd3423d9067587d05517bcc5a5ab187e6b34c00486147329ad408225fd62fc753e9147f63960bbe933f86b6e8d2b1c312670e9c94940c8c7e72b0d14e52d0eaac8e28e73f9a246cddee5257dc3e49cf3c16678d44d763e7f6e2f0f1b688b32728eab7b24a09858998392af6a7a0af5954e41206fbbe4632a99433f3bddac7314e0e5f7f04205e64d8f6c3091ca06b1816ee229f25cb73c99ed87d490235600a4445549a5669b5f3b79a9ba5c67dab996beea1d4fbde10143ebba392bffe11a0c35af167c739fc2e231a7a37fd3f2020af975212b5b2bef11f4103b00a6802b9e428004957ec35f2f4ec7f43a527cc5282117216044696996927b8fa6029e4439159ff1c3adcc4e548280c8b6973e56c7a1c9a7819fb10dbabf02b41b2cbcc9fc7b019a2990a971d77009e311d92bc3fb41bc13841360adeac1a99bda6049a88cdbdcf0d3af3292d6d076e5099e350efe1fa0aae2b", "d81a136bd3a3104b36ce6c1ef28c237183fddbd9d92db68a9f88458395037a7902c54201d8028b5b8460fb33b2bbbf21c1518ab1b65d0bdc92ca70ee2a7d462a1e8631707dd8b357a22e664b7a913c6cc2cf51a1821a67ab8b680819f86bab9d62a5a674d50533c4631302d2359a8803a1341097abcf08df62fa81c03b8a039451c6df8ce36897e5a4c9c1036c3d9a627dff618df4bb5564015da5638341779f3cf99fd36fb6620399d104664c13a4b4d3a1e6a4cafc116210a7bb1c97574b0c071676377f75db5ec8d0d85f88e4aceaa0657a3551e7277591afb0bd0a5669790b702acc607e98242f0dd06dc19e952d8774f551193a5573efd5eb333495c0124c70b2b93ac5dd656801df9fb5b73b2fd4af8e3148ed68a88eecb045323bd4503b7b3f46fc5ea07f15574a986d96600a3e5d4fa89a5316f1cc3ef45c6df01754a8f956f805852c786d54a3ed4d08ddccd39f01d9661675faa99163dca955c5e034080c25d36628404c6594206e3e4ee5222b96907267acc801529b73fd3fcb3e2243fd5af60cbeadc16496082437bb2b6a0ed3d35e0d22c1dcb0c23183c04ba69d09192a8c3d2622c14acc8230ba20054c49ebfa056336d4c2fee4d69f22712ba1fb090f4db2bd8771529d8623c593f5b2ab1c5b4c68167d77670cd4471fd64b71dbab5acf2263905fbeff3859bde4f67fbd7a50d892109634495d08cf927bfd4a4256f82788b428bc558dc2f3bc5eb853b3bdb7fce2ae846e02a2d026f1ffcef93506ee264a52e9c64156b0a564e0259170c0fa953704c3169f560b55d94bfcb441e534f6644a60c10139b041424d08219264468cd7b1148d2788b2fcdd504b95c9cb831742ef1290010cd294f0a1122daace6caf6c00a311750b18a65a1073fd89e1137549eb1ad806862f29d4dde21b96d6a3f70a304211fca2e2e738d4973aade0dd625f786873c32544d36006bda8bed81261bcdf247c9b3be72a3eaf92f27e5b69099a3a44ebb730ca4149566904fcaa5cd481c287ab28c29d3d40e9b2eb1f9bf9722520b69fbe3005c49156cd445717e7e1a86c9433241a8277dec65aa4633e6d3d125797580830b37310889121f24d8bf4300a6ed5a034de2b0614a9c6ef3bb148ab2192605f871130e5f30de8fd42f174e3b16aca3a13e482f6e528f1d22535a7ce8ebf65bc248fba6ef21bbd2ed214f01b5cf85935bb45f5a734b2ed6509a4167123b5ac4609e001ed2c196a10b4c9883d76228e98eef33aab02e6a12d4fd0adbd2c95b13bd9818be7be2d2d16f7ce6f067d2c6c16d01b93fdabc6df081a37b342739b19de5c7d67bfd12914f0978cc0845d097db3ed187e41163a1d7e91c7afadc3342ae0008efdf2f1c7b74f37da62f7028b0bc5a52e2357b723eee969821d162da58d750c8aef2a17f89032dfca4b8c38746b6656a890dc16042fda55f33df5e11e119c4460c03d6712fdb46f500dc426aea44b5ffe2ee4eeb2ecd17d5be3e6f60fc701c9ba4310f7ea652018176e98c5783800150eacdfd67035dbedddb685ddf9b989914c209b53c89d5591bfbc073ed611dad3803815592bcb705a4242b9e8096dd3bb9eb724f0d955d8b432680ec1354dd89ff0728cc35bdaaeabc2b314ce4f2831bbeb8752d3153ef6aa16a64346cec5d242719a946285887cec4183ba3a302858f12732967e8cc210998e0830b5524bac1cc430f8a36e8cd06bf173a570dedd2eab172b6d48726dcb59fdac98f11cac1510b8e65e02464a9522ec60c5cd63a8fb30434bfdf64c3897318d0a4c97a1b0d084d662fc45229b70e39fdbc85bb40a0b3167668c0cda263ee42736512f2cdd6f8efebb9603e8469259b40a02517091771148e37e3e1051701ef3bed7d3c49afce43fa1d24b98a64763c38f6956773c03a062b3ca29b5bc0214583fef4f8017cb63c31431edb6b742c76f3b1fafd8fd8b158988d45a05c7d2da3056bc92370663c4d0db9ca56fef9cbdc21dfa3fa99934fdf92af2c416869e2c7773b7b11068c92a5a8adf0a378b7d6f0de6234a3fe6285f2dac1c4fcce35bc34f5acc9564a235800afb3dafe931deb47fbda47bd9da14ed501219c23f481f897d0d9014793e1d07b9333ff4ab92b84389944e49d496463e99a7bbb2f965d1440810c05a75816ebc3abd173bdc89174511a1f8c5ed3f4faee2dd2391540aab0ebe8d79d46a319ffd8644a83b99e5e02f5647c0685e6a540dbec12f1e994f0ec5c2e083e187549b955218f9fb32a9f50d50bc9c4f230ebaffb26a59b6e62eafd1287a3e2ac5a3927df98797686b4813a63a2388e5ef450fe11d9c93e4a0e6f6aa47d13363dccd89de7af89e4b4175a371f4460413eaabacacec0010815672fd09149b956e0b05341925381e996ce4f26f5420b95250928984da8c8e6e82e2a19c201fad1ba77701ec6ea1e9a71fddac62569a6adafd087ebc5dc3859ed2264ae9127fd1f8f4b1ba392c252551c613bf89747456f9e7c16fc9d5b32a6dd760d8f3c1d2aa1f9a73ec7f90e86472ec686f5b667db75411f5b9e57a4eb397e6f091500a62eb4fa13056bdffef375d4d78701f313d4f65caf6d036497165d8687b779f7a20989a8bb8f70cc81df8383bef7b892db876ff55611dc9586e6750fd11f59e635d93420d33b73f6f94628622714d655b70f22f8a528b5d34e98230db275173a62385621f3997d17c77e813ce171ae29193ed958eb5f69aa43acdb00677fd053ee137a38a1663e05b6134a449a61dcb2ab9600b1a191d344c15b5c40001eaffd24018671a2c68cc72887657a853b52cae504a932053f0bfb65ae7e2ab8b35eee6883cb402bce270953451f773e99e5012cccab6008d7676a15b191700d0c63b6751777d8ef062fc2e5151720ec16082879316967708217f26d597a2292b8a764821d0074e1e86ae9d3b2938fe8c2a8f5b38cf3cf2a1a9ff2c3c00406f790a62217fc2177f0f6a8eb15c47a9ff52e9fab53a72ed568c20f0a2b6ba62068d6337a99c794f199e80be48b4f9d8e7bfdc801f38c764ebd9d08df3290ef0cc84ff6e3a12b2775d59a2c1ded4dee1431add5876afa8d02ff1539e0f02f46efcb1202de242f5cb9be986df8ff155d9563c7dacd1687c752f9a3d71bf820c01449700333c3b55f25b07f404d96305ba4bdc20b97bb05e8283173224dcb879a687b393c548bceeaa620817908c1cd9d99de2835cf1cddc694566e5a4becc519f17677c4ce0a0a2f246e9362c44955c96d15003b4c03f87d19b6bd6e463fab4c2d7c17bd22c8ddd1224d6562df19461537f82021f0f65013c78a1fb64a721209732c577e38dd88020530e69873add6f76acbb47e6a85aa4752022407a60172afe86c6bc7ff56e4c12accfa5c6baf4103e9ae079298bee2d1360e649963b44603829ab25082d37dc7d9bf5a2488d44c211a378ec8db1c207181012794af3322878566079846eb68d39430ecc4d4e6dc498ce7de1faf5d5c2a04ff10bc82f12af5d63721371f3d835d27b8e319edcd1a0c0fa3d2a472e76cdddaaa0500f2cb4f8caf5ff4af2b4536f427783594d71e2ec629cbce36b1f9258e5c0d998e2477cf5b9b18aa1f45f748b793c962b29846a51a25a5e18ff90fb1a9bd1089a76feb1d88e9fa21598edfc88dbdd438f01c0fd6ad9ea18273c0e12d5f8cfc5f576e494d520040933d9589b96ec1fa4dbf0999c832a1cc022310e9239127298fc414302033b64aba5a2d306bd32e3f7c84ced1d88ba2718e9c93183c247c8cc36cd5f5856312a5075686e234715e887a7e8fc8cf3fdc98d71f7929078975c3e8af3e815369011f9c85a994f3ea9e1a99a71513e1b8d7f8912686f7db16bd201c74948540d76d478d5f8e2a2beee043879808f46a842b573e766e14977fd2c32f32d3ba521d609dda0857b78dca0cb2888f0f4e01dee691b7f3aee6099ea56fa3b9d57a72a7a6f61cc0e76e94caf931249f00f9bb7e875f0c5551e15a21c985e0e889875253135896ded8ee0348aa707c7971dc6910a3e2749bf0fe0d45ac2d1ed3184add9002e71221d5007f4ddb29e71a69634bd375d7911a3d87ad55b510c4a96cce3cd133c13aeb9bb4cb1866235f4334aff50572964e65eac327193640014046a1a1c980b2da46330200a48fb95baaf5fd95e76d1874a9f9baf0704828bf2088035d34aba91cda47317ec3bd8102e0f85ea5a84d2eafb6cad1b2558bb34df1dd66e4035a18e8b47878d34bfdf", .Okay}, + {.Mul, "60b4fbff419bb56fed716202ebc07a90dc207adaaabbf843a709d549e0e3e3a524880b892a66a76c117011f64afc527f381857658a737c92b809e8c8f60577f78dbb8ccdd62499c00310059686e9e4bfc62409eb4ed60b7e0448ba3ea1270958a5f659933d22d444cc17cf2e9edcc8130e2bbb54b20e2f5a5d4e95ccc74cb15036ffca03fd510bf9e12c91bf5ea78c20e64ed6ac980de80cef21ef34d805c6df24caefe5cd33c700c02cd0e17fbd5be3d7de48819ddbd75565309d7d6833dc27d5c8310738f2a257644465814ae1acbb3de9e926472821d4ac8bae5475d001e249bd261fcea7bf7f334506451f03576ad5cd0ccb3846c8ac9c6de11c359751b022fa2705d3d1a5ddbfc96eb68a4d96ce699e23aa0cb34d18ee47bb1ddf37e4ab99f728eb3a8c17d29dae31a35189583976cd2a601491b93a1d863f13a6fab943ae38bbb01978bb6651038d41a81e13363acbfde4068f7403b0eb2058cffdf88883a5c22e9d694b5b035609c79a13a6c8ce7fed67efa4b6bfbce69c6587233675da5b28e67abfc249c81042dd784c12402f106582f03eaedd7571a8bcc84f6322e4040f76906211880a47da3d51608eeaf8f33e06d43b8ba5ab918f7a4c1a9bbeb122ba772def64e747699305b9c5420e43366f7e78cd9203936d87844bd3881e56e58d448110c15709495b663dec9336b42367c0fbf60af10dabcadc4541560ff103a806f1c99f4b41cde4704c22ba2fff4ed209f3553c9926cfa651fc8029f153ad6a1a9168490610618681dd262853d4941372bd3d6f7600dee1229129dfb4d972bea09199bc903ef7524351e5e9a388eb2a32361594ac8ccc5631e20ab22efef62ae10658579fdb3646ec8236580561797d6685935762f6644f50a27d8568ddf39059fefe6967d5f23b8932d5bcfe2414d78eeaa485652b5dc0bddbab35c9dcc2dd1c661f80d58478640e7b537744c5f49fc322f75b77979be676a26b87ae92bbdcdbf37c1a0ba7f09475df41d4b157ab0de88d4d33624294f3b834c5c6bab777e48de7c5333bf09fe76a6dba94503665841e202b7512fb1d25eb91ac23a9469e73c8cb2c6654dbf3ee784d73010c406a0a9e9149ac4e900591e0ecbaf137a9eb6faf9d2f0fb6535aa9056821853e234c2851f098880f4137504f8d2dd68806bf5585de02d789718421e0f290e53fda57dc540a4bceb4145b24ac980a65cf88b74562c415c6b37505b36ae5167984bb50c629623a57a01759de1d9f2752b92005985ada5b71edeff87b6a6cb924855144a1cffc58431195433e445aad4e697ac1082238d092095bd3b0a01ca1150bfb2063e67d879982bbb68dcace65c54d52ed2a2b794cd2972efffec0f1c833c9b1f989b97ded59d8e48ce2788c3b490485b8ad8dca00281a3a91665e50115f47748af91d5057efe11c691d995712f722f6de51429e4fb22089a754b6981d15dee2b00f16287e5b2614086e3521231b803d770a4e162b6b5d690d72d786d62518f311a1d247bd631a2f9e1b4b0e918d32b0dd3116a70035d478fbca98608999f2c37c3713b74049654d32c65c555a5ac27351100ed001f260953ddbfbe48424af9cb5b58a161b741eda0a09323857d2ce8ff5c36492002b50f12bb1b1762507ec46d3a4985b119402db4a8a75aecd5e8bec22c543744a8da8a5466d413152405e3209f2eb26b714138c58d5c4f5192d32624917daeea54f94ce62f873ec730603e4d68b8a82292a4c4451d82d6d5f686c6762f5c8761127ef8fcb6becab4e6000c54fb6b9932593b8542f513af813309b9441c8370025dd2638127a49238a144adbd62ab630178167289e8756ce833013e170ef1a700e2d52a3edb1af1ad445a41460fd869f0076d1dd93ccfdd8b5636bec5d9d89f384f4b7be98f541855469543954b315d8a8af6f4b11697dfe8bbb78d046ec3c7d6dd549491d1bb5fe19876cdfe99e200951921cf59b004ffbd6b52e2f0692a59a26e9e52bcc0db847b3ce914df4f5b98638b8eb8c73056f644a798d661089e0b6ec5a299c7286b6c4b8a594e1429a851133a75c637989964c859b595a2fc33ce08692463eb5bc5ba02a8031dfdaa68805a3e107de345b23", "8a5e127030079f7038b2da3514e80439bb180c65514b909766cc0a45338139478adbfc3bd6daf393d9dc1c3c91b5c54e5f5577b0b702f14665cbbe8b58ba2369916d17f0ec652200df776db9fcd4685731b85c11827bb74b249a6d3e2d4101fdc15cd00a18a8f27f41f556fb2999f64b2c029d8b698e4d613eb98f93e8eedc0718505bd6235514dc3946942613fd7dc8b894d898c5721e1ca7d636dfb1382cac51eb19d55d3002a79628d2d91f253d87b801127969b0884af5db97258bdc65b4b9e052cc972faf8208aeb6b27320a998fbb4bdb4163ffd532ea7a1d053ec8a268f7f70d665f5fd385a3b89a749d6c6954579c42eefcd91c94213d7f303d7c6abc915bebe63fb3845837eb6db268de4b9fe1193c5f2ae755d188aaee3e33e5b6b3a4e31d51a94b7e3518b33c2d84fb0914198e5a878fdf6b0fe79d95cb9abb142493c107bfe9514c90e30c8d763082831acada9b4eb9c5e1b3ab6e4545c7bf0cb9d8f9361f8355aecd46b3f11460fc2bd9b08bfc45948a5490962cd20791c79ad007af80b17a651556f0c3d2f7e1dd0391657aa10939435e74fec5db6d314b737c23adbb0f84f45df36a286683f17a25affa308867b38363b4955cc914c72632f2f3b6f4abe31b91e972b96e6b1a212ea793dc5fd2dc7a2a3d87bffe73e1beb13bc2ac322278d7e0f1b833350935010c0808f2d082cc0b40597f14451716fcdf1df2da97ec1793941a4a6a18f0cdc3ff1f0eb1341cd3d919f8056e695f9380a56ff035b368a6a0f7fe9f6c272d2c7be2c9cb62fc5aad95739eebda01e4beb0ac2f104630d8ae9396c7852393661b25852a9968158d682215102f6157353fca52753290b4ef825012bb7f780323dae736aa5028803c1b284e18c1a5864cf09893d00897c563e269016c969d14296fb397f47ef87f1bf91dba73232721142413231576fddbff1437ba2283f40970299341b12f0c1b4781613a0eb4de039afc1054a181d3d27e70cff24cd24f4050163d32b8dffcd023f69105e856e8bb312fd49b78e83b3eed5c23506b3c05953c7ac954c1e3048d6b0d29cea64af9c7c666b0de8755582b20d5107b7fb184cba6e3c22ea66861829a7cee9565e2552adcf816580161b08631b6a1a7535c7fa7a5b78d550a06bfc2a8a95fcc60878d5cefdf8f7aa5f3f4a3a986ddc4fda6298efbdc27e187fa1a6d17f67b1f57d19d85a98985ccc7e9a2b9083616f67ae42c1d825121d797b09b308974d7b0f6e5d0730d3dbe0b6b384749cb09fa97cd87a8ccd3605c8dd0cb74c28774819cb6af2a8e6ed5e397a8e7f6f952f7e2b9ef316449bfe531ed2c9cf4060da6d895a05511954c01b6dc4cd5564338782418e21b4b6574f645b87197a1712295499076204ab4790ea076283e038d763f848eafe3aacb1e81aa3d4844ab9b20662061caa860a42f5cfc00d6df651f4aa5d07162035b02eafd57118ab25fc03b1a155ad6d91f2e0813505398a463c9ad6477f46d56a84119a8db340a309ad08ce59d594f2424b8c0de0a42c071c99e30b9c04ac68a244a818ae2e6823e5d4aa674bb9c9249b7ec00214763491cf18940e1f0642a11f2cf1101c736e2212cde2ca776cf567d1ac0cb6613f5df45d47c93ae8e3e0db8cfcc46899a932d43dcf054f737289aa1d09001972d74b347fc295d848c0630de0ba31c0a0cba1447970c0878ae11f888bebd78a59eb3925be6256107159f409fd303f5bdc7719cea0d67de3b14826213742a2b92fd3016bab91f336f74054fae0ecf511d9f7d2e37ebeada1f14201dd6aa07af5c562568dbc0114bbde69a8297b716a23385048c3c219f248459980154cb001bab2ec2346c1e24e81a785687c6a38f7e04908952c425cd37a7d6587528f898f785b6cb842ce45a6be11cfb39bf7defeaa2dd1230e14e83472c51d26639ae446b2080c993bd63c4744d39a6d84b8ed79c66091c0269134897e0d19e139c9aa6172103353e771860726920ccfc0a301d59357fb083c200e458a9e24671ae2b41caf7bced3fed9bc1637a6b0ef440069c42c8327114c8aa5277371861e7b756a2282cc91aed24eff3ed4e0b0eeda8504aa02531d3604fda1e6f05b41f2c811849d", "344519433c2309b2295e7c3a00d70f7e11502878538dece13cc5be151a800ae395649651654897f3afef41eb97f97f17a88382a386d7395d5689794dffde2f81d78ee03c7d87e11411549126dd181d70961ccfe4320edfda5fe51f38d884d249b40aa33060cef5e32515d131030238431a1f1af51241d2ae163a9c88c9ff3a515a81f0f3a7a64f27122ff7f426549433a8e9e067e52a9a412ef5750558524a30bb8d2c402b361bd6a9451d39e6fb2002004b7d8ac368f2f557daba266e78adc973074eadb74c3973f14a65d296d6f416fedb6bd5aff5464530b1ba37bbf41fcf8c3cb0e527c0df8afd6ef1b95f23e235e2faef2a42970d39745bae2313c4d82e1e4c5ef5973ed7cea5329b2b783afc33b0a26c5711d1af5666bf1eb108b3eac3eb0eecaf79b0c7586ed6e49445cfc60a2eddcad5b605b67c1bce1a541f6c097ad7274ee6af4dc25de5bf068be0278b62077bd83f1c1afe392a3720e360301652014939074432032495d5fb35cab87ac5b5ff75b97573ad535a7c64e5630eac4fe23eb1c21b1fbf63f0fece7305c4a406571cee79eb6a622db9508086499fc05293d6bb8405d24845d84baba603e1b1d6a62f62b3a3a27e9f4eaf3cde88a5733ae6653776954d33081ff2142976dfe1a84bba058a3ed5526edb05b78dbd9bfc51426d84a2c12fb5490c9ef61781441bae0add5dba64395607377f9af29c5af2a66b6816f466fcb1dd2df406a36924ad4c6ac2d32bf68473c6602c0ccf2be92439f27abad8c5bcf55e6c8af911408c62a068fa69fee05ba1980ccafdcd3c6b8d548e0ad2f23e66a6e5fc0ced048b8e6d4a8adf199b149404df98e49ab894259cf7372a92635356e2d9b5697c8645d3307f5ba2ec5f57d3ef1c3783b26da602f30c8e8b1a91d74ff3b0508cffecd4f1c91858572b225d7d5c36101f2e534d0acc7a3eaa57649480be9d4ef73b23577e6a08d8bb855fbfaa5e4201e261d8bd0f4f74f119ea2c66e22ea8d8a53d305983eded81953312b5a182ece0a721653bcec18f74ab29c3b3d0b582bbe84cc6093ffaa80d588efcf01eecdc1928e5f58eef2119598bcf5d0a5a8ff25b06d80465d1a91720a5866d47f47468271d31736099380c3192a2f6ad2d9e4b735e4673bfec5bb6ead7d957f3ff42c55d92632641c6f4dc1bd3ff281764637d748542b95ea0221257f1a6831cf23ee1cd12b0e5e2802c8beeab977ec2d23853584bd26bcae36b447e5881287dbd554a2f3d796a99ab172cbb242304254752dadfbaea81a22d8bfaf2dd74282336f9f0e80e89f8c5782ee9f6950ae13127492db197a644c0359fb51a6da4b98aa1d65b19439f28d0c39a9f6a9f8decb19cfceeacdadec47ce5bf3d81f442649311a83a2390e2193dc27bb9a43edd2586ead04e2124359c7ef10c17a62821432052cb8821cb76a8ba8b41e98975368759d537522bdda8c3c1ce2bb2e4da099abfcc708c1c77a94438734a52a73c3fe0880c15fc28ac97e44517ef5228b1243411c9e27eee2d62568960a9c892e355706b1c692e5de852d35dc2247789576ba9bbb6a80588c1e4aa1088b0d176eda835db57f2ff073010b10a1ed5de1e4cf2ef88432a250a8d8ef78a4974d158f3ba050ca5c814df13ceaf5fc64b0b53c7defecaab005da5abab68a097529fc3f321e6fb2aaec5041066156c295c63bae2c021d98c4be7ba4c81a7c8288f5e799f3585e6a7b82fed479ba522a246c5605898c0ffbc8dd7cda04f81cb4eb2a874dabdc94292a81f337e25b17479445f5b633d66b30332eda84f0440ffd771a32bf969745b5a462176f42b3f3a982e36827ae7f05257dcdfbe29f533bc4a4eca13eb79b550d895c187c2e675d428a0e081670dae22feb7143ccad779553a400cc32ded6d8d34394b669808df04cb2903efb980fb9c87022d18b47caf11c8a85ea2d053ae56fb2ef0a203f1d1bbfa06ae2a8c300f2e94850f3e7feed3db45b0db6762c251299bd1c39d9e2fe98b8d2038e144b13fedd4d79eb362c27d2efc6acf5a3fe48be36fda0ae2e41b31994f5edb08177b3975ef32c446a3c8583b6722f58ee656e38e3a171041b264d117593e52fc6212970896df15f566051053504eef13ee1b765b4929a6169d25abd6da2bb0cd5c6498c7741e1213fb951dd4dec3008eb4be691620c75eafef9e7aff0f5614b10095951f2e9239d4a133578ee45cf6d0149722880df21a739e35679c4ed20d1e3fe2a4ba53ade819299739f511a1d79ee03224a3194c7091ff6732f8e1c97dff2d41664fdca0576adac854f9622fe677893c6625e6de504f6c1aee2255ac74737257823e8de76547ab6d1da7bf763277862f2b68065be0001ed666ce604dcb9fa223cfb4d072f887c16c97edaf5090a2a8458481cf1cae9bb9c7af28e7dd5a4119ff8d6f81cc1a56c559d225b6c7faee5c4ebe8a4a010826ef4a2d96293b536bf667e9cb1befc084b88a0ab4b725d92fe4aa71f293b28fc3955f01a0a98f3cc911c06ff422ebe072e468596902678e8bffa8f003aa9f991fdb8aa9bdbf42687f7f151679a0a478a89500e094ccd091814b8a7fd2b0df0d4604a74e4b8ef57ce654df9245456319a1a5fda299252452c28e0e5d065f90cf1ed8b8e114a3b5061b8b2a938f41ed4637c57474d77d39efd78643caac0d9124cd1f6e8d5ad18e6728d62f0eb4bc06c2492fd2f33921debae1110d34c954363ee4e176e35ddcb9ae0b5e5d616da61ff7cd0f462a834e981099d4089490e99f7c108580bf8b1f5e690bea461fa93f8293f2cfa8e765c63929038a9c20ca1f8f280e06a7d48bb4efcce3ba4744a3873960adb44acb37ebd1f450360f99a0e68b95542f8134940490d302d3b4b11715fa6b9880cb2bc0b08f316aff75818e03f108949b407f29ac1cabeb0f83a4696df45e716e9927790c934440bfc95695ebb883c56e2f668eadc58cdc3b1d899a9c11c23c39bb51ad364f43d3db017d716f452382844ec52c63b14508bcbb671d8f9df3fa5732b064d71424f0fe48d59c287f702c9b35d7629c641915fd07ad0a6fd85c2439d0d3ae3d76fdcf934f6f319be8e030bfc743e79c8366180fa9250c813be8a8805d2b43237d8e5ad18354e507fd4abf90b1c61fb64b1e23bd49b1c36fa540d8bd576d2caf90889af18c67184864cbfbfb68208e63b80bcfe582ce2096eff0c9ec08455e4a22420fea48aee2a6bc5d7d1216d203f48ef07a3bf8ba2d0bddfd296bd76d4e97694d826ae9fd0875dc919c766d9993c9709260a5cdac806982a2813a8ec44355b980738ff2f29688d91246da20bd7c6ac11ccb8a5f6fe11f14f7c20b1ed183568fe9995150489b2975e607149e2c0a7abfb669940ab743352248661fc9f726b57bf244a6eadb71b75c4e096c0e54edba03a12b071e3b85962e8cde7b7e8f1e86fd6c8afe9af6aa10983da9f13971b5fa90ae2cccdecfdfd46128880415cc9926b5d9a5702037dee1795f27b26dbf61738541446a022d127c54cc0817c9adabcd24cd9b88d26b0e459dbc98e695ea64a17ca67f63d615011c3b6c164e8d5b7d09e09a5b6527c32fe85974894e29632762f595a60eff78e640151db4dbbabdce7b78090a4ef3eb9f421b8751fe18090819b0b9e6f17b08026436c4286eb523a81163862041c382631ce43a1e0cafbdd435ddb7e36cbbc85fd75795894c7fc8ae1a053098a544ba0dc165e0715cc3342005ed76851028347bfcbd3754ceae7f4ff3bf2f988a20ef2ddc4b5c3c2ddd304ba926be1941fc2dd11d1b0173e14e3875616df6bb42277beae4e37922d706083c6e20880cbf52b1737ec9703c2c039add24655fa1d33bfd8046e707caeeb3e6485fdb92558c07eb2f7faf956eb151c03d6c6d298d0191b5c0885e041346943f8e969d739c0fc7329308a1a6fc7b054087e01c88b7016622b41847a36d1731c60d676546c3574a7570ad337d223e6c11f3e0a861bfb90c5d194ba789fb55c47536137a06c9d1c87d5368a573fc08567b0494ad32eba2e61316e423037e906a9a41f4a988af2de31f003e727e100f3840ff26f1393f4c49ab8006bc2caf5fa0fedbd255c7d29b407e7a97479ed2f85b8f843528e686093db3fd983bbf1bffec42c68ba392757852c2c4048245bb437ddba41a1513b4a96928679b843caa034653536355588a5b3335f3b8eec7020c90bab11543fb524a61c26b862e92bcb35b3bd7835b5e9abac329aa6cf077", .Okay}, + {.Mul, "c42fcc0662c11b74d3a81e9d53a5d6e03ae93c9477c4f04e90ea3ac0c6f4a0b127cb483c5307703c8a0bc3f28ba8bd15a9f37a166b75aafa5896f0e3bca015d6c6da3aa1c9fe20052532d4d6c5fb813229821ad82f1f4a6ac9004234380babf2d7361ad8c1af83acb28a358e2f8fa81a14279176386b9aea26891c410e05a1bea9f45a9d6ff824500b05757ed9c2b6278cd814ce6662efa4ad9e1cc6a004288ce4f99651058394fb05524658e71b5e40ac5ae77d236e2e5210b871230f578868ebc318e2602778ac42a5396d061e6d9bc1b78c3bbede22fe1fc7cf42d470877496434defd62b3ff1d6293b0bddddf02c251dcc6d391be4708ecb75e7730c193601cf3d6f1ed47c0f6806c431637442694ac2d86cc592f49fa340119aa7bdb55fe3e890ffb3797d4accf7ed6bbfa152e1ffe1e06deba3537bad48306da99507f713a6e112cd0889cb4b829cd02ee5db77b6664fd904b18a603e02456b923b7f06487ce4d4165fa2515f62dd5b2fac6d47980cd92f9fe7ada01348b138db9b283e0cf7e8bb8fd2dc3c909c23240e5d4fb95bd909202551c779ceaa64b3da72bb95b0369280f5cf0d22a883385e79289228aac5e0dd6a0ff7beeb0adf9c9dc4834d87bbf2b032afe1191c32a40d28b4caecea0bde1ded079c177facf78b9c3d4c2b13702564681aed9cbf6afe49e0e040d4a94fdf34668ce3cc0bb4f28c9c9c162f3838d7e156660e4e3b67b2f045bb406e2c90efcf18fcaf9e5e41e35a27cc1882d8207d79e5cfc45d0127f00b27276f66dd1447ab9db15bbf65d4bc15e1aea1c3296f60758cc03a289e10296eaa601cf4898073bccced39a6627dbb2ee166d57070aa26a147b662edd2735fed9ce6e779d12db980b7858ad5880d28af2df3195bb31d2d9ca6150304594998dda7e52ef1b923b0b53dde24078000324903736220e181314438e4f01b195e888ded8fdbb3b924f01a70ac16dbddfd25abf33ea10620382fef0a9a944c946dbfed2bb8223eba1426c5f193bf963426eb2e6a4f83b851455581711fee7fcfd4bb47867f2121ae883fe0923a937247d775ff66bf8cd8d802694b73d2c88f9ec0fcf93be958ca06e7b6f33ffb24ac9236e27f3fe4d87caca9fb333a0ac554ee9ac505fe79ac9bb90bd0c977742bfe4f326eff6f22ad6983b4103e3bb9b879fc509fcb84a99e4e20c2ac03f1aae1b387bb6f58092edb3f26d75a4606952b80d8624465fd6da7d5fe19d138cdd52ca2c7f1a106903895d11f502f50bd01f100e99362d5c3415d388dfdd0251ed6d58137da3ee9b532270b48ec4e9db76251e08057b9a8b8d3ccc5f0467de8b1071bb197c84edce722dd94ca308c0719e2d855676bb6e6e745fd7ce198d09094e648085abe8e861f8c856afb5c18565ecb410e92282abd1974faab3a952d394383ef605c74bba49ea29736db60ad8848d8f318403ea50ae7c27e08e1f4806037aba9f7a02fd2cec8419355499adf69453791d8f4f09b4d4b7ff0db1255cca838586b379ab60df8323b5c6faa9524e0d58c8584253852f0879f0ebef3450e78aea54515c84ba7a3356a59c16d8fd34593979168053ddfd4a73ceca73b7a5d799ca42a1572b4879f3c9a837bf85ef38bc2ec3b42d6fb59b5923562fd4bb7c89bc8c712b5512d1699bc277507d1567b5e8d28473705374b2403debbe80d6caa7bb9dda64ec28bbd31ab16f893f7800072af64b16eeac0cc42cb26b7b59d2d19bd9876cfa40bee4dcab4b403a7d6f71099ac2a986d264000c72bb86cf250b5fc21e698fbb7d2225bac2210627cce6c5513b7d8885e21d440fd2238028cddc5fd60b2dc4f11516e0b9e115a8ae5da020f7bbcece3931eea7c7ac4c618dee23183f0ee8586e32ed442699ef1577e63995174cb6231af5c2cc365bbaf6e73a9d36e16939d4dac8d97eec6f5dc63b0fd6c370633d1cc3c8d653a8b282b167cf4aee627fb47d829fd652b39f70bfbbdde61dc927eadfd716590f7606ea191f4335c6921d72c44c9133ba29cfa41154b03663f32309727190431c6d09ef9b2170ace61f3417b87041ea1701c68bd8cb6d22cda302e101f623ad628614a45f22556e505a02f929b93085113b3", "b87b0a0199f29e5c43ee43865c9c965bcdff36cf2836d64f4192a98bcd0e6578b8fc31a2bb39bc8157d382243da23884889d467ca5b09cc3310176ee8f468a10e3004565db2dd3d4da756a448da0742d08a8a5e569b8a93112dcb01b0d73ff3044ceb7953667dec26905b5ebef679ce8ff470ed8082d02cfd5525bcf47b9885d03f30e3f2c936964525dc9e31a7c3145e745248bbb60f832b5c6e0b6b350a7fbbeb2546cfa018b2553597ff54f6626bc6cab2aceb90b4bc95f078dcd92f4d3491a9acf82b6cffe82ae7310a6a1d7bb35b9bd296907a95172fb1719503c358d4af3189545b43d3687a534dc226c32898dcf07d233c394d330d346b0a61cdc40e64351e78d5c0829d5ed5d6309c9036e9580673e5b6a5684c717a019704a179540ba28df3c6d6e5ad8fc2696cfc47c48eaea23d28bd208b38b22338019709329cb95d7bbc035aa14dc4f106b9838f3463ca6e85e72d07ac689898ea42e700556b09feb05d47ad9eee872bbcee3e07dce6c680e6f8b760a6d21802bb17a94c817993304d81bdfb845d84981adf506f456572b1290c26de1591501e3c69da549f74484158585780c3a7ddc8bed2db5e0abd634fed4f550ece3509847270d04bbcf9679952711ad66f385857e62746a92510b23d5751220d1a58e8e7084884371fb7e4273ba0b93379e5972de6744a3a756ce846e0652d5add71f7c024457cdcf7912841ee8eec9fc7b649a793b9e9a4c760b789885ad985d10129cdbcfffecef1600dfc8cb2e50329f5f547d3a83effcb5ab5e0bc328e6aa72bedd4174e0144871e8259cdfdfd3f95a492cf76107a4d9ff7cff6cfc64144c51020efb8bacf85bee0b79c7bd93fc869646c85aa34c1c09870b71dd59340aa3f793c8d7c02b4cca19a104aabd8214c39b14b31351a87caf7214f23bc0d78435c26fc88db72a4c56ef50af17cf53ea36db4798520f2a4a6a4b0e6216a6f774bd522b49992503a3e6b71d76d002b7513e89c287e0d08064d7bbb61a4a6a3f42f77d16a787ec005bf8888b0562767217468392af3cf9a53c937d976ab8b1778a279b1cf8036e7f4521cb521c8e138869cbfb86deb36ebae5b160f7a0674ae705e483a94173a0fa09a0754b39527c97843aab4d9f5c8b61ebfcf7683dfd2d0262e0bd74c79f61df995f6d83d3072759aa5e5b2e708b45cd9d858731192fe2a8b5df2b7e9df86fc205f06858c4a05e7eb319458998f7de2409105b2a41d5a155af48e38ceacb77e4ba75fb7a7fa59c532ee6f1b6a440496838386d470f332f7ea5c175c18cc22a05937f3b2b41596a78187cf6d5cd522b4781b0a8e168d6f6e8dc4ef6d527ee6b03f34cc8c7bd6f457663af1939ebd66c7449777ad1c5377f3dab29d50c6e6381af0cc7f840eab214e6cfaf78a10045a83a0cfc37b8f9242d6a299cffc097d54d6bd0b3c3309b15f8c3badc5cf4b60cbe4eff675674070f713ccbd842d6eb7c51f0bed707102eba369c128c774174bb4d1503c202e48cb45b643783b584bd81dbc6a9c4654ecd8fb52c3a9c165a2cb35380c91f42f5dd20a16a2a665e54551540be1ce9d94b07e5c1ba045691a37f30e8ef4eb40bc192ca08191992244bdf408a52770535ffccaac6d04ba880aba996a5b139d84ef66f56618dac488461ccf5fea9d8cf43f05d6c393751a60f512b2140e24808fc8191a5293303da1500bc0a613a36e9c64c9bf37128282707e30208ac752ee621f7e817c30ae46accdb9aa495dba83f6ebf5c1f256f3400e70434b6853887e6c9b302d937e6248c4e76278325f8ed4b4f06eed2f3d2988e8558ff2de45f2ecb304b00795fc34a25bc7d8354b3900206eba52e2ebfafa8569f87744f9d3da5607d4012ed32ba95f3d5c98d05eeac89ee457ccd28f02f09d95c22137716c8aef9f75e3dc150b55e0f2d3a03dd2c8de3dadd70388600944df8dff798a05e089c2b1aaa628f988091f41f25a2d600eb7c51ef830e7ce89a4383a142527488a53ce685945648c34fc720dc2af0cf44503ffd807920ff7be45e6ec44d12f3cf3330042c12b83674397d4b9ff0984d04ff190f159f851c0faff5828f03075de287a9bbdc29bfd4f4406a5bb058d28ee8a4", "8d60a546b62ec9e0fb4d554976042d6c523441aa4930a06b01e30e2166a2b6cd8684135c4cdd1a1f0f5821b8bc2bb429a35477d698450d498e4ec54c7c9b812b3942fb116af2098294d728ab13d8e0eba940023c1551d91e55310d34ae0c7603f67f3f62d0b93e91cb63f351e805b0e9cce6753f9920e354d165f54c2cd35d358bab536edab362260ee6f03c52205f5e43c2291ff570c789032fe4635d5ce5d1459c11f23ffc8da866064bd43586b771e7c4d76d7914f06ac874005b69d5b59d472dec810d55e6b49204bdb608954f6802d5cf16899d3026541dd507ce8fbde9251a65acb530bafce0ae801c992beace83294cf6a2bedcf32ba53aebfb63be31379a8e54964a87d6762a405c15ec7db0e89115a008a88ec959e881ffc6ebd1a057dfc9ddb3e14516505b9e8b3ec406c1968b45b25f9112498d7576434d0b2b10b58aedaddeda81b6b06cc574e99d4bd674f4eee2b0de29b45394ab1799a35cc0c2ddddf4ca2ffce919f6bb2c051e0bb1dca0df92defe52b4ffc71a86372cedb5fd9ca5b0fd554eb4055235c033b968fe593ed65f1baf54a8c62efee937fc6f88161cfc73dd677be045d65dddfa1ccae079727d645540c39404a824f416bc8f8386378dbfd202a2fde3008c87549b65b930a951cde5a08d01796f3b2e2ff0317ebe0681dd39f33e4fcb74babb6084a8f99412073d71d8c47177587b3de2f5745dc6bddb5d316c5a642e758f40ccf6116b4ea4e36d893a864defe3e9a72959e435037af537037bfef25c29a9410a2cb531c6135424accf33f2f7aeea4500e2724fe14c57ca76fd5266a6898a437b27de1931b1edaf553e9da3dd22eb6b7a7ab2bd5e990a15a528f2035ea4ca30f8e08cfe5ebcf3ef740294c53ce708cc683ba555cca49c58c17c98950a604b44fbe56454f1afc1b0abdd6b7a8e024800c7839ab974da94f4cee99d466abb299afe25ec6cd32936849a63117b992d748175f134e8679ba8537263eec9a9c5cb414d704e305f61dccb62e0d2fa1cb7dacd078f8b9a341a076b96b2debaf3765661ff4af1e12e0d1e6451eba306c089a805836d39a942f4650bf8c7cbde393c4b66930acf8d9438ef4bd24569f7be728123e37a5a5b927525e8ffcc4f2d23f73714330415feb20055a611d4f9bc591936c0e6129747247cbcdbdc73450c3887550f3d1dc2fe83f0669578caad6adaf6ca0d0e4f03830625d0df52d2a7cc4105ab97eb215ffda95d69f35276e23a10cd414c2dddb76b02d49fa430e9c879e6092137b539a7f2f05275aa01aec47168278b750798d0b5d7d25c84c4b4695b406745ce936f6bff197e3aa1495edeac5bccd857ea01b50742d4ea6c2883ee6288817e4713945853f20addd558ee9dc73d261824d3518853d423c91219217a7aa765450b394ba6b1389e1db4efb099e00e51c09760e761a5c5ed415c905f343e8a6ed163d57d62731cb6116e4212c76c629e4b26cddc87ed30a495c77f7c598a0daf2d088f223fbd64e47ac3c6b7f625970059109563724782b54f331ae461467111d79d55c6356369833d652432621187dfa3c405c18e2adaa0e89d1ed225a65676b7bcd3238f7e99ac91acecee942521112ca223756e17323139192d040ea593933d02b9a6241d0d6c749becd21868d7c7d57b2901722add7560836edbd85079d85a3986130088c64290e004c4b67851906972cb6921bf1cf47a7a5bdc0b4f984a609c37a36233efda5f85f4511d3c306f8a6ae1b7f92625eef54fd04af7677b8d9259daf81b58c45f45cdaf6da2ce25fb9964da6735261c15d154e68be4cebb6f84574d1e0da64cda8e7d17670f9a0c842b6760d3a7abd290ee7fc929aebc0862eefaabf8c5e273b65d6965b255e8384d1f8107812d69de2bb0a4d4f52779c2c38217091c475bdd86e07a1f8d771ea37c13d6ce1f8da322e3cc2177dd0b934de9142b4367894426baf926000f8de6e69dda1b9526153bfae77cdf1e06d2dd2ebe3dc80da82394e76fc04f58949b3f2df0b9236bcfd220f270ec3d90194132e1ecdd62f71f5fb2829b68f6cf4501e919288030262e0cfbf181af05d8629aebbde7fa0772d8a09a7e95cbfee983b7f340dbbc803ba1ee2e3b32236ae69c435f64ace6229f135630dfd278a0439de56d2facbfa6e912a3778158fc27055e612d0860d281ab5f7234353a09fbdc0a3cd375e7afbbf8d1b9450215eb61a8231d40f5d78d27d8ffb3d6b209680cc581a5684d89b46d58f3d5d72eff10c53c9fcddaa4575282b7d06f2422cfe7c61bba01c33fa9522e6876e01d3a5cbdec2c10440207a0dd9d3c15a7d9c7a7c8935278cd3befa65cb9c88bb08d0771fc4fd74cf8b8018454c5a3c9e05d0e4f2d44ec975f06f2e90aef91013e85d9aaf8119ef207550ae7dbcc63aa89f0fc906bc9b8b875e1e5d8724ff247a6dbefe21389f3ab3fbfb51c10bfa9a5ce5ba5426e7dc8cb29d56ad6acbe9974dfeceedc23639100c0b332859881fa4d4ea1622a0acb9e19888e2594029ddd814880b38bfde0a8a874f4608bf8153b6f6093f8ce3ac3ac3d9c37d664c58d0bedf1089139d5babe2002c7fae032d581290611fa9f6274f2fc76e9c04538fc9d442f135679727a24a4ce5fc4f938c36b45c8eac0d222c30d85cbdf48b7c9af44749bce230a6ec263440924506fac9639be1f2c7d5c8bc2fe0358d48fe62aeba81700b20d54ea6aaa6be6a0084178cfd6d7a421427718003a07f605dd1ab90560b84f4bd3dc57c099c350ee564479fa5e8354f24cc6e846aa28d71296e317be75e1ea8a1053b000227013825632bcf63ab7217f732e9f2676b03ebc9da99a9f63c1490f99a34de9a8c7e1a42554837ada25e805dbefdd3a918e45eefebe407c40ba5fa79a92e4b25dc5c1285064737059d9e22566c48819f1232d4178d48af1c45c4f3c797177ef59ac6ee7faef4edd3a252103221d31790335a35ab1733514460cfed80146b0d25a7bd3c74001009b2958aa0ac3fbfb02087db51dd649f3e4f4cc0913a82ee434042fafa0a251497896903b2e843c10ea2f4fc8cbd204be96827e2f586f15e44d9100d1bf4d876f8d7a9a2b7d5af7feacf85dfe6d2f388f4daedc19fdd93bab3a048526f4d910fa34570b486b143068f59b29df5b8b8d7ee979e0810fbcf17dcb987a1594bad5d021dad648c4d738654271d58c1fb937df0104918883418e2fd4747ed4bcd168efee7ffdd26e5d82ac28b490ef59f455d0adf2bd933745c1b74baee03c9eacfdf2cca2101a38b83e0de197b3399000bb3388206ee4fea5ca1aaf16933680d3f8a7615c7eeee6563f8c76c04fc62ebb9a82fa0dc02946c67c65ced87a1dcf48ef5ce08706ebb0c2e3ef4fb1f4511803827f498cbd0de890d458f43f258fd2fec36d0364375e3a0b2598cc23537d7ec8051f4168f232857a54d5f472cdbd4b527b09bbc0ca4d323107084bd2c4dd1de9fb6c7bc1112248cb2e988437e0e6eeee40bb121e0ae0eaca1dc5f62d168bbc0f15d91a2e8ca6fe7a0915c9b78669a7f3b81c9855df1c9a69a6decf4eccfe52a8125743d91b41b5561ea531f50f845490784175516dd21ab47fa67f24589fc8bf1319cc9bbb8202381e4f7896a89cfae19d66d2064e5ef9cb13a091a13d8a91b0668b01c88b79ab7b63151987cec1d2127b81eb552b7090ee6ca925adfed52cb5fe1b955ad256a61ccab5a27c8202d286baf85021a36f9dfebe138c9c28e81d12fd1f2f5bec8a0eb27fa9dcbc89c35b6081f3990087c41a2fded44079b2c70e0798d24fb505c973be68d62be4a6400c602185687ec662d9bf561ed3accaf2f73fd01f761fc7c7adec6fb1451fd5072982a2e798e82a6ab72d2b30920322217ab7a7cd2c865f6059bf2b6bf702599dc5b2dfc4f9fec93f7fb311f9c9cb5e01d76fca61ddf9a2382419d847df038f592c6aac9102c48cc5c25076bc240a134a95eff6b2790dc45aeb68a8f6385103cdea8c10006b3047c837fabc09c1154a326ca27adb795763bf7282ab38c9c22f1bd610a28e3ca5e7fd085ab41e1f10b5e9e790f01d495c8a46f66b15c988b8c90628de775fe3b5396c8106741aa2b4b61053136961d6d78152c23a4f9174f140c40940e5aa1b458fef94c2e405dc454cdb4ce2deed75b54853b1cf1165013e555a22cb345b12fc078f2299497cdee8a3221dd22c45b329f493772a59ec1ca57662934b0c1ad04a090ca8f754de649114d6ac", .Okay}, + {.Mul, "-9a07f79dcc92683537fa146a8df7fefe85975b933498c7dca5ff96c82afc9d8d6426482354b8b2775bf562665835aa797b8b848178b20b70b84df6899527bf21f8632951003cd680db85c8593434379612bd22c7153649ae9ef9e580a1c2c85e87c78eb661e726af6df506eacb8fb683c1bcaa1f4b8409b6220fdb74c476959ae2d2ebdb65d11252af7d71a99e8c783cdc6a2a7f5ba28091272227072fa171b9427eee6d5a706dc9c84f401da79788e55464a076c8f949426b13c54ff2f290ef7c84865e31a04202b0071b27c039233e9a36a1975d3898cd71c2b83524712cefb3b3b290e7e80a70500784382c5b4dc7051845e84d76ca66efb0c7914b44679461b4633ea5eb233e9dc1fbed3c81ce39c8aa58ed6bf2eb66f11befb07f93b40b50d65aa90c12497f045551cd3d65f772b691562806babd0824757cffa2db0135924c471e317caf74e7160b9d4b7c81dd464ac9ac05550107f7960505020b62a9933e186d472c07feb603b61a912a80ed0a8ea15cbe37f7d7c8ba417479f5106b417a110ec32040b6c21f4791c50d994691dc670831722cb583fdef837ef3938c57fb4dbbc40197d92b12b5ef6e2e535e08cb9328020ab409041e09fea358cd87f8ad2c9973e0975141f0a2ed393be5bb0c90325e41fffa99c177aef790181545ace3d579ceb07e4b5a830982cfee5a5dc097929b433738aac430cb221379c7a534a7b29c3cc756958befb661f759c282ee556db1de5ed13a0aca160d014b53126b38f8b9b274b9d2a9b3f7a27eb68d9cdf51e656ddabc201cbb1c39ce75beb60404a6c5d4576a8446e45053b98725b7db5fa8e09ce490c95c866abb4be3609001c435d921414eb2af9d46ec7d49800c2d8ed04cf56440dc4b5551bc42bcd63a6b31c98556c1a3f6dd0e4a2636dc0f011a8280ac5f617caeaef1e9ce5e9e2497d6e67bbb39ea2e9cd397052aff2e329795d86310e22db8954895c692e2fa42dad498f20e8ac038b6ea9f92a3e4c889666229967ead8d850486ae0b8c2855f5bcf327d3860f279a9ac54d759aaa3e96edc7d85055f7931368a6b09516329ea13cd5dc58a29159006b165a037c26aee6f6fe776685f1868ddba46034ebe5dcf2c7bacb94f1fda2251c84d99566692ef2fe73095db260bd03849eaf2c8f52e0e6ac4756a3e29366d5e44344fff61bf0c8ab358f2d479e29186f4aeeb9e45f55e0bfd2109652aaea07684798e33e07bcbc03bf033dbffe75069e419139b51f6f0c95d2fd11071c6010668e240c16a0b7c2b20146c3ec87b70091954a868eaae5940ce5d5e930d67e633b968cb5c539aae271aef29ea9ecef322f5de23e53075bff263ca17e2dfaadfa6892e2dbe4c2071415ea212306c33b7985f983ff84621ad18937d6ec0674d7aed12baf15cfba8561f2e643ce7a21a98079d48889a7327a6632462cbbbbcc535843267792bbe6af3cf9e678ec053d33a731abe33582c029ca8ac21149aabdf24c0fe6f914627709a45ac453614afe1cec482e24d4064cb4f6ce78b96c2143ca099440a419f73940b539695236de0e5ec22765a6b27cd7dd00a4852bfebbe1184b5522a2b20709d844eaccfabaa472bbfad75f1f3238f76a7ffed38c01010f69251250fbb5b25e16ed90efc8d5ce1eb589999b423ece666ee8aa6c579b37fab56e3933f084e8bdab0a8ca220f11d9ffcd68c338a8360d60bb8343bd47103976b8ea5a1fe11d4cae6eb49430d8d197bf24cf8fe5c52adb0068b86a92e1bb53205843e0abbbc1d914b0a18d0741d124803c50f5c60cf34fb054686a57b536f4173bfaff2c5db4bfec70ef4d26c4dc3a906e982a727946c43d477dcbe0484c928001c9d6c9548c53ace61f1ccb298f62907a58efcc88cef4b6cb79f887fde67a174ed2d1fc593e888fc1a33360731d1e61488d4da9f54ca44e601a6d78dad80dd75b95c0fe9d05bccab7486d2c9ad7d5d26cb0dd214aeb7bd7ae9e21248bc2cd4ad0d445bc24a68f3b2bb154bd2fc1201eb4c7273e23a4226a365117db1d3eb2bab491faefd6b8cbe3e4081acd2dec8a07c1f190bdcb02ab8aae4496b3368a02e028da6d77b85b8f276371372352131645294de6ec7efc53", "44725d53be0d1a8d6b24a9121ed355eb00ea2a309e3b037b8abc3fff54ff70fcf1e11621bb1e7aeb12003bf7b518d9c075a43d47a9974bd616c71a2c16abeab95a23a604999a6c1806e013e0fe28d6b2cc7e05a44ef03a4c788ef1641d9b7a69252ceb03406036575fa1c352c82e380a555372a6caa9853cf2baae415f0770ce9735c9a7c017f190429c623563099d9ad5f51ad3a25d6f9bb686d75dccc78e4a0cd00478e0ebae2a4249491e5a454f29cecdd704fb873539f5c5498327a60b21a45e20e99bba1519d61d37834acc788cadae00d2bb40f26373a42c7d421cc6ede233e2a4dd8da2a7da5b4b7062c5968aa2162083e2654581cd47a4c0148bb0a5547a85328ac882ede2e3448b5e530bc98ff25c2ebf33b15c5b0cee131929a6bd53b4d0f177e5050a8267a59d125c6e275d1f961b0ae278b8167f56b84cb15f2a31f9127131fbd6daec34dbba7cc8d75bf4900e41a4a0656dcfe16269e517dc0364b19b64b43f32ed7615f6e55addcdb2cb85acc3a6e80d02c0437c96be2d2f435bb98451b3c6cf6944651e007d71b31b2de35feb99725ca8aeba7b1537af48f9431072e76255e799a21008b3f723bb3a196f004edda29d03b8a2c86ae15006a4510d67d621a907ccf2dfc507fd52fe572edc05ae6952ba363e97dbd21433a0b72f874b65b72f1759313c5c2bce8dac72ac599e07788ea87561a35cbc6b33bab3b4facea62cf78ea067f38f387eaae8f6f7ed5e60f7b108abf99acc64627f48d682a29fccaee5aa95d10538e37a5b40ba1e326c1b7e790b82128acd0f40cc3cb72965e605c4b56d4ec6c3da46046fae5560f38cd3ce8775e0583fd0804fbbdedab41da95d310736359be0e0e59079dae50f36c70ee139e475c8f13abecb8c5bc8d51bc214a51e5fc3dab204df74ccf599785ad6ec597828e007f925c44b979d9f6abe70a6854a5b892fee6c3b3fb3cda702fe24f274be3fd1c3cc477fde193765eba5b1ca47d330e7c9edb30e15bd913f22fbe5554dfa46ad5f206dde922d9ecce3fbc4524d8357feb541533ad3cf064f40df3f63267d0ca332d53ef202dfe3db6191e07e60b05a7a8b5b14a765569a29a4c86fa022da700c2e5c49275c42a16db29b671afa9e3635dfc5a40824315669d61d0e153d1d7657ddc5767c9a5cc0dce56961904d257fbdd6c9b9194228720275229c882acd6f6ff91ee9beb8b23fc5a7e2d73a4b8bf5b62825f3091f8adc3ffbc4a33001e726e82b62f22f1eb34df1ce05677bc22c6d17bbbc751c2c96c3a298da7ad6270ee112400af5af98043bb5dc31b5bcc6ea9271cca26d8143da58dda59e1db824a044761f15bba75cc8976b3045146902165196b9916930d098e67d2b48bac92ee649786c37faf7665e97acc73839f5f0a68ae4bbd6ffde43a744871fb2df95c9cb73b3409b85dce117b6ca8c9d2a726b3d2d9cd62af714e25f7dc9d4b59ebb37866eb8213c5bc41d29a7e291832b0d094b9ddbff83cd12460551d9c2cbae01b7b1206b24d37a30fa769a46c30b190536439e0930bf231257ba5e46547259a40425ad7810c4e730b71cb95615d5efb59602d190da0407d96b98984ce70dc307c4153c8d28abfa6f51ff65188ed9a7c77687a179ac27d9dec1d044d9db927bf2119d7906d29f27d4aa24150eed959b2f952dd9408995db4139ed05860752ecd3a70c1012826a8fa990864e4e848d634a99ab68801ac9a27b5b456c282216bfb7d0d16628b9ed204c4d34ab891cd387c95409b3417e17f415e8a2f0a270cbba68c6b8550df84aeb12ac56f6606d527a1e27f69595db958821362a567db498c9c6f50144d44c4c1a5848de03dd0c7187a305acbed8f55d92a53ce76d3eb663279974896b05cdbadb740a233c6deaf35e2ceb6b3e8d8f0426e37e977adc690675eee876713cd3051182844ab7ec01c536035437d10fa77d1b525901a1788108a8b3d1a001b42da08a65dd68bb25243f03e9c6c7f5c213c3f4683dfd1aaa6554b7d46b047e0bd1bf5963ec753f66f4e8d0feefe6413f4150c9b8c23a5ff85aecac7cefdeae90306b9619f7e4af64a54d220e12205c41041903b7948914d9ba06e882b911832c46c097", "-292eed79767f6483a4bd522faa654eb5308a627545cb7db735e6bef850c7ba83571b33ee2c6e122f1cd09b4279b5ef02c1dfa54bd8829589353dec4b3bb755cb763fc250009286dedb3cab96ec52b9d17d314025b183c079e6421bbd93e4e7ec688032fb8849f21144de7e72250ea20bef46f6defd8af49a38acb23463f19aa3dd7eb9477a28e4595ea9ec3bac1e36c83f332d9e82b83ec3bc57e5fc096ac91e12c1c0cf17931a41441b46d871f9805ef182ae98bcef86e82fc0bfbc473742cbff43c663f6b9be4cea901ba9781a834e7714422e233a012b07418595506cb071148f72ec7294723ae7e3b373dc9996891f4a3ec340fccf247560e66eb64626693cdc4281565a0a32bcedcbbb96f20683173e5d655a507f60f03660086d9f94ff160c562e2cf2478ac112b50c2d9ad2a1a748dff9e392c9bd20079ddbbee73ebea981bd8af5dd6bd186e38fbad9ee5238f71df0b85c70b3d7a97d180e15609f7ed19ce9c3a148bae20472964443110051ac160330178f00bcbe6a10bc7b8a84b7f49dff4f6cf5ccf5aeecfd3f46cb527d760861d24ceca9c76b15848d828e9f79190eab5e71575782d7dbaf25f206ab830e50527099b01ac5ea7765e4ef746494888bbd7a5121d996159424a2ca85f32748a7c0805894abfa978e8434be87df6ebfd626f7f656a10c50127a7fe6db0138eca9260e43a002c702efea1e29d15bb5772f63e6da2550addbb1f7574703fb5971f4feb7c36b65fe14318e90d1b3fa996f8037d47af51c04330c9386d877bd851f8b2043df88524adec2df500123fa27c6bd0b15114c5c6ea2c329f599d53749ce5ad53ef8cb853ec45608464cc1103b5ac7230e343dce46ac1747da21d8fb482b61a819a13eae29b0d202e7906fd18564f7b08001fa3f791fcfee89bdf854e4ef49ca4608c1cc0b49e20a63c3f26aabc01143c43306a4ac006572e774efc3dfcf1c87f89a485dae4b2325dfe23e5258702317da9315f13d9df8ed1eabdc8d745e574c265c92681a980f3fd63dcc5fd7420c13417733ca31d3b9bcaef3fe93d5e0aaec3cfc424888241b4fc17c50a3a13c994949b299ba50ffa446d91f5d97651514da21d36ed3c6de20e9f95973f706480db23207c58ad33e32771860419d4234efb5a4fedb44ed88b603ad1cb8e6323b18a40870b83c218880ca3f884014cf1ddd7a32d970755ee9f1c5caabaa72bbfaf9ee2139ad00c5df83f1022bf51996e5db597990948f9910368b3a103ded5a6c6ab32542f16b468b6556f18b740b28af6d0979085a1ae9ece8c385ef9f6b7132b0368f4e0c40371e5d9e3d9a55acf02abb0713cacb3091eaa0693ecbaf03bf8623da8787bd62b5115e379f493dcdac354b5cc39a2d0106f372b8d06bce33e50caa663a64d8af0f9b0eddd9fdcbbab26019bd4b23e25b9d7c0359e128e9a5a67022de111e92c719a491cbeaba580854c6ff1339246f88f1933b486bb10b9c2daa72cb85a630b34c5c6c2e8655b503cee1bf6524a956adaa145eefbf731acd1daa521be2ed0e22885ba8dd4e2b6bcddf337c6e245cdbdb8238028d59570ff28102eb09407935a178c5e5e01445aadb1d4a6b9ec90a91e8c45fa219f9b6adec5c1077e155bb0819bef7b866341f61c15aefc25c977651232145b739266d0033265b65bddc5ead6d9cbe12d1f0b602f88e8a50432a9e696bae444c3bcc23c46a4cc77998e426c1919c01543f37c6da03bf5793920dded99db8808795a424e1e02565665ca7db23a901139e1b3053e0c2583d250cb22cf2af51275ea228e10db72de559fa4915913cd5317a45013b662c64c6dea2b75423c1fc10f2e02aac1c6634dd74d5ad62e2ce9dd3e3a3a9f73ee404d8138b23ed931bae87622f4564e4bc6611bde1d7a61a195526d5abfda646e374dcfc65c11aef6c7704fd4cc0a24810c087fe57dc3fb05a0d1b49683ae27d4cb1be189fe2624e7f38e5df12eeaeb833be1662c0a0d80e53072850322ff8ee71ffd496803b6173164d51fd21fdf23442aeeae0a5f9228db340457cd49a94e047c825f361b5f834fe4c0ffbdb60e9fc74093759c230cd77f82b2ce23ef2600a8408c8e9bda1f867e65e90f89dcd0fbf31eca27787a78a941fc05874a5668cf8909f5b8382720a690688e3cd0aa3dd27d6c44c21ccc46045cf5473e1c38c281bb6410e00e32bdd0234581f3fac856980c9f6c416b675dd7cbacbd835f7bcfd6b400ddb7c3750ca85bf9b165fd0665c6a9a1b9992f5051ac28f5993f7e704e96286edc386e421bb65255d72374144c85d998f1faa5d36d4d62864de4e33e53f9542da315cb101f61069c66d4407da7c1fb5e7a2359852e3d3068da37315dce05b2a66cd81a0d3e6370f4952ea6c8fa615b570a586c847704ba7f382ffb89322c18e6e08017d5a4f0e7033fdd25d4868993e1d2dd1f088e7a82c8cb1fa8c2847fc1ea370cd00156f8f66aa8b19c5392b3a91233bf3fee5c28cff56bc919e45ab2085ae51fca84ac8704f713e2ebb90a8e2be79cbcf2994d7d65ea4569f2f5e091451a4991f98b9dd9bc8d036b4c1c86ab3edaa0f8fec025a87c189a96858dbdfa7f4702587de8928454949285866d4bf365a0a1d20ea1e286e953e090ea1fe8335bb9b99a1f1598e6886b76eb1cda728fac09a1668c8c4f6f9c57eaa424bf0d6570d7f2a927cd111a58e345858d61996d66c821ed32fcf337e9112ff3b9d5ade14fdd6ef048438cabbeacb006e96f3aaad83e834b4531499ec9c0ff2f04fadbb9bd915cc1c936470f958e615008c25363ecd5e0c689d23fa0aec4597657739d8438d1474cb9d4a8465f3b495d069b0fb9adbc40ce7215924e9d607f7474f243be63d34ca83e3c62749a65ab1ac8927213500de782be42002e2dc0037ddf470c84ccc5d60f10a9356835e418e2e7ef78cdc1af126a5836d0c3999a9055be1ed4078e5bc313b9f942650b5ec413e2c25a030d72d6a079450591b1f3f8d2b20d66329df70a2772afd975a9bd76cfa55c938593b0bffdf69377201e6f9c0bd19e15008ae81149e16dca6b74e766041ec12c49ed25cba4e8f76df5fd51beb14c65af8708ad0f2249d917b22a730ce6df3713589564ad4d9d11a539dd37415c531ee211a8b31657e750190fd55e616cae3141616de1fec96d625d742e69c9a854b4d5d5ad107506fb7819d9dab65c4edecd1641fe05d2eed49c9b0537dc242c8f15cb9f857cccdbc1efa718e145602dd3f7b21dedc96bebccd048bbda180288b91b77a0f9fcb600e5e1c89d2c4fda42105c168ffa9aa273fc2c43e6f10bc772c47eb0328c1003e155a1cbad8f5eab4eac0e4935027c5e24389a0484b34b1be5f598ac366450de8f2bd16fe3b7b785f247d808d8500562591f76f415787c61427af14b463f1b150ce30dacae48026ccc4bc2bce3842dab0c8decf43f794121a5c28957c667f9c893240448c4235b7a4d8cb999c5b07f116d069a277c0d7d341afec23f5027372834aabc172ae8e2159c5b0d1d748fde6a235b5b532ba508647872f97b38e910a8c1e6248e82cc064c9b6d5f4d08c721ea5581d14b9f81c17e3da848ed620295d117deaa165935ec6585857a9a14e5f0425286a63d70ef5007e690e7326d87133103e50119d02f4a79795f7855856858ed62aae1e6b6045f643fc71f6ae48e7f4fdb8a5ba5f101ecc9633f405c3aa953bc4de6514caed8bdc2828dfacbead9347a26d98f7c9a8463b0e5905e5f019fbb23a66734464644ba918234b3d1f5bad4311cc15cbe0fa51d1f83bb35baba78c35de1d089663af6f5e99fb9664c2cc022a8e6311dd2df36e85d9a5b5026dd7312705dd47fb527fd94002b8340dec8b98af501381417092e8bdb9b35a42e392b4c15abc9928cd17b666fe92d770249fb6582e8a7cb7f2921c2c394044d4863713ea1a02510db62c1cdc3ee348a811c6b51a4f40d7bcfb6feba94c8a1e710b0b3e734bef240b9f8b4bdca1dbb405016a35869fa01747370365ee2da70eaea4778aeeb39639c2247cd3cd87b2342dfff61e5cf805f5f1fc628794d9ba7a4b001a548109ee3109e988660a9844b307b62dc1d5cd1d9977dd5b038d109aaa5412dc5fac41d49a0a3374011a0ca38bb763220a7d52cff7576fc8a9a8b6dc3b02b98303bb8cee0b43a1bb6d7e7f1f6dad163ba18ba8fe52e8d726755abbe9f9b6259e2343c62f56960c576781a3b5951e492caeb54c4424fed714f5", .Okay}, + {.Mul, "-4182bfa107c5fcde84b4f3182facb14ddc54fb9eff7819a456841f414a17ea2dfaf77a42a4d3951eedd77b364d5d54ba651638d304a654d524020ba9cb0fb84ec2e7ce00a45d6db1372d047357f1feb1cd35267b248947e39c71bb09989b02840e080ea0ea4720f481147ea8b7ebe7b1e30de6714d78f77ac917131d21f0f6afc7ba225f0a216a6c2a2cf23833bc617610c3c17f738238424ef58c80c347febf6768559493abcb4ae418c932f2dd1a4927dc07e351632f02df0ac4c745b344513d92927ba7d1a77424b9cff7d466cb9dd3ca4e67e8daf4d38fd75bb495da368ff832e43102cc5d33f54751dc36cde27933a6adffb42b3684db388b465ab0a9caf72fb66e1884ae2b4fefa3100412a30d5344a3b894f8e9ea0651b404c3249499bd8891310537e8ca5c5db7c3d8131e2e417b7205d529a45bf0c2882178d835c534b4d04f953c8929e1398305283a9cbc27069c927ca013890a44d5a5a4fe49a2f35eb4a108e76ee6a72a1df74b72c36fbad30edb22a13093147e5bb701dc6c02ea91ddeda888a039df6ce74a2d132f63b0d1f8324f06e9e22af527db488d9a1047f16e355d43f265b6549d872f85b562cc845bce2deb6fe0f7adf0327e91a17111114ae63c3278257658be4ba6a6907365610eb1783c0b499c2cf7c83848450bcc51bd2be41b6b74430d15f52aa2ee18d95674767556cea8b53d9996d1175d5e557a16c606c835791ce2f06db29407edd04598138d84ea85ae9057ee30009b3d2c8e6f3ffd98f5c1b538930a7796123c57163ab5c0d06c48ff0d4b4bc817c3d1c0c3a5f2546a7eed9d8eabed3065cdae38007378eabedd33924935abb084ec58d3e35d33c0005931de21a908ce3e5260fd0e85d566f6595a73c86772ce4fac2ad5cd48a1dbc653195e47cebcdc455e0dd8ba93366b9e702179ac36af94287c5c619084131ae0e2d8f2315cc3be4bdce3447abf13878a8ded4c97cc00371c93f5bf0bab046f0a7806c9179fdcf9c764c1f8f6dc6d024aea2e8486164fea727b0a710c1008c496b9c8aa7d0aa1c95de20e44374773589923554c12dbd60adc379188d54aac9086d37421c5cc420983928d1a5fd1da7357562921b629794096025d8656619b5f4f554fb7af9efd43cd010996d960991807411be267007b50a66742de602400950925045f1bca427fe74622df12f45ec0ce9b859ee675c6d2c23dea7601fa692a7c028834249a8e9f7b58cee315302ddfca19f09818265c886387345d047cfda1951b06578c5e0088b7372de02b687d74608139824b3ae168a8f4c2fb4059500a0489a1eefa05da026551096283e264c88fc28aa45ff229393fbc6584d96cb94d1e1fd96f171a2db572910c017cc3948aabcce2f46e4d42d16a0572cbb3338e0ff50cf896496b79edbfa0e737bda078c5b480e6bda52537bc01fd8c83628cb0bc27fbb180d8ac80800800c3fbb9cd01f46a45abdb24facbf8a349349b4201f9fed7a21e875b6b87d3bb630a5522eac11a0a9327cbc1ebf663ab3d3315a6815b984f822fbc85e8cfe2f86f75dad9605b3282a906976da2c5608064695cf2d311ae4586f277071bf9c41b535cc7df7ec310fd469698caa4eebef856f02b311ac0a481a5131a6b6e1f9e4bf60aa4f33fed663134b362f4b540898a11f17a54cab05c34b964635f23de34fcc51f69928fc204e3a18825b33cce793adf6a4dce572fc51e49dfb614b8f6a178de3393d7c7fe413ed5bdfedad415c45b88ba8c9c672ffb031eff0873faecdebdc281282a842433c47519e578f768d8cb3c650685f0e94240cbc47333f15681b58c4852cf38a7ab78a6a2a18498c3ed327fdbedbac59927886dc1c22c73c3e70e5be7af5cc3fa04745dd6fa19e49d12daba20cea1cd5e09a99d9847dfaa852d58f7362e68b5d6b64812b27f90dae735dd5cbd1d84c4150b810d9def576e5f3a5eb8d1ae384d9fe4519f08511338e3abb9b7d14b52033d1561704be6aa455d759a09b13e6cc63f370d7e65205a292e8c1945248fdb6fae1d5e298fd840e503baa2f6ef47923cd6276039962e6fd1b481c1d09a8f5568f08cd19cac6bc197ab8409fd779deee33d0937c6af279abfd9", "a9e18d845c821413b75494273d61ef77519cceeff66c7a03c5b69e20cf9cdb0074fbea0e695d34101e15d752234ba6b9e0ccf87abbf4b9be08c5ffd4a97b4c72f099d3ef9983ff81fbf6cf511eca4306f97d33522294ad4689581f2c0ddde841020c9c1d8d7a6a7c789912b7bc3d225b41a9cdb080bcbb7bcfe65033ff61ece0003694289454c15a8fde19cf523158f1fdeebc81fb2bd2efa69fafd1be3e6305f562095d83f9117145d7638281f3efed7dd0965b98ea1011aa46393b59bdb1081d55cef7d3d49037ad0c2793815a733d3c5b769a6728fc561fde166e671a9151b7c4ca86c6146c1d646756bd970ffab787d52efe407b71bfe1eed323703d48bb6dae30f87eec2e08f4a164987fcc473e19673f064a92d682e80f6dc757ec92b51d3d7a41a4f5a8fc17db5b748a4e7f15e04f01ecf51d6d1da64bba55d7f14f2fe6e3aa1370eee79e0db232b827835a4ede82beb9df1504556c2339b911cbe577e70ce56699dbd21052d74dd22e1335b036a30574682eed12709f394588791e2dffc90ba8cc13431bb908df3d7a7af5959e810fed020a269dc6bafb00ed791b5121abe6ac59e73cd5ac7e48d6d3d330ee21dce1372a17b366654780d8b64df028c96127cd7350c1658a1eeeb2cf3aea1e408c9aa17b0b04123880d1e7f9ba2ee45779e2e3ad7a99a76b18e4d1dc2d925d181529d9debc362a0b9e43a587301430f61912112b47a3dd32d4673b07c83a1ffa8051d511b058f939712fbd97645c190848b32b4ef0fbd59b24a8761e44283591d65065bad8d47feed1165f2e540d867cf33bcdb8a5e4bfcbcbf6ea76bd25ec92abe128bdc319df7663e2b958bb31fdfee399a8084b0b87510f9815328fe5786d93d84ad9dd5c835293e056e80e68fd4f6eb1d3e6a35733fd70e52f05866d3426ba7fa00b50a4ec4a1cb635c31c7eb987563237fd5b6ec4ca5bfe00288b6792a0b4396abe29545000c356244199396c9d4f8aabf41e3705ca44409fb279ebd9d1380ec63c8f0a08b608fd02bc795d9156fd3230b8e4cf7c5753b8ad6960476996269109e37065559a94bb09786f8c20cc6bd58d5129659d5d3bd6b3e51f934708f8a5be7a94c7fa0559799562a8529fe2a3f01a1d777f8ae6f6b961cfb3d74c049794910e43bc0811cc245719d429cf31489cf9daa1654662e2ee07e3c4b5a3719d6ba9c6b514c00c98876d0369d6aa240044ec01f4c6217292ea4688d4009d4a6e0be3325d9b21dc7c7d26d03e22f75b2a3f8134c8747c1e3ae59a05797df04577e57258541a3f3db637133429b0aefc3392b08f9db3cefa942bc70c2dabaa677791bb7c9552dab7b8b61dcbd00d9eaf3e9371aa801fa6b1bb5ef1767422e97a454c0e3d1cadb6ef0fa96df76d80bd087332ce3bdaaaefa55d20b5f68ddb6318976cae22568afe0c5c793095a8cce5cc4fa2ceaade25b772f247e0e1c81f4b93989c310ff6f584181d5128e3ff316f0f70d0f6689f24553f78ff312c9ee448fad8c0ccf2d8e0fc1d55c85c5138b94c2ad8f664dad651dc00e18788af99b3f8d6bc6d70222d4467135ef2f8a281f5c0fc95c3b3ff658d07235189df8e46d38a4043633ad412d3174ad2fa30ec4d8ae18a9c648ff6482236cc825b6a8a4b143462e915157ce3aff55ac0efaddb85f1947a48e81dfe60bbb9e3b3edf78618b2744056d64692ec46f54258757bd67f95dfce21a10ef5fc1c6f3622d0a7fe0ef142cdff277b3435fd03a12f1bdbb2deb2be19d79f1a0a97c36b482ff455eb0253fc3c269bf911f88407f32a8718ad229621a5a7a1b0563add05fd6cc1de85d7ff0aed63aa41a2535535e29e6eb9be032288979904590a065e9c0a4e0511a58bd42e943222b09dc622f0e8d77f5bd15adcdb9a2a3aed515c462a42a36898d0ce035b7683c8dfeaec2dad40e400bff792bdeb001d7703c0db91f9b033e594626ece9b0925f5d1e0e1602b6ad35c959fdc407f134c8cfaf4a0fd221fea47dbf5447bce3c59db2aa1e11ced2ce09bb4cfac91e29f94fdc1b8d71e52c6e727dd73db89dc3a480d051cbc4cd5ef09c4d6b38147623cd920a83d7458f734fed241c4519c3c090d77118fd7bf821c87f70a", "-2b7908a29d4c4fa8a4b30c1ec1debaed52165ba71845dd002c54f93de6eafc14b951d69e913f9fce159b36bb856555c9a3d49c6766e0151040d36df33076961dd95f1df1f3b9610bacbeb4877635214617628ca8f6307da87f888dce1e29d9970df718af4c6113007107c0af91d17d60ac518f0594dc43a993a5f71dd9c969de2b3756541b28f11a183d95e5efba98429ec460c98c9aa142c218b9213581a7732e2e649ae825d69d3a88a421a96f20849f0e59e6d4b77d4b2978f08efe790fdb686f1610031d3269bcd16166adfd6fd8e211fdee37f2614ad6652f1fb758eafa311b87da929f447a6f95a7d16bd016fd557f7c3ead11676d665eebf646be17619e667daa191a0646e93ad436d360c498bb161bfe2d5d33788b52ddca6c00607a38cc17c2e2c9e8f59731008886a8f2f83d21e37ef8acada9dc4da4c9b1ba5ccf7a0418a1a73cc266fef5d4793b956bab768d39a1f1f00b1e99e40bad0c0d8313e342b1ef817a11b758bb0a8fe64b1376aaebebdb4c75391fb08e80320e9d02764a07e017095e8b84059f00838e12f31aa48b6da3c19baf6f888d78c93486d18901146a5609fbbc4ecf91bcc89af2c2e318f08ea5233207aa7e779ef1735d486772ddf5c0fea96d72f5d792c4f3f3a4d0c9096a2c0a58c77e8d34f022687aa406ef733c9746123473e550f0450b81c9a76b9136c1e4f3e2de69ce9f108f2cceffbf8c7007e47bf5c449c3ef0a19a7be31654e23b14bf9290e8892e4095b657018c030ee5d1b9ed9a349e36f8ff11f0423a28d60d944108db4435a1f7246531d8a1eb059b65414056710f6b4b4307cf649c5d4d1b1348b8cef991d7971e1e8152979c5e78891a3075f0cd04ab26f1d185c7da4718f57340c7d25598cb018de5c8a7ef2ed43f90109ae67ceb2ec7f6765a4db79e76c9c948a5359e5d86242e92d1f6a0e8f9f02ba7af43da054246d0fa6a206d9be48f118d7d0d879bcf8a0b0420bb5aabc9f058f5b79aaad9e80b61dc51427b9283838a4229dbd3f479fe853bc7d8c70ae0232a95cf42c49cdd99184722354362a0a56683f9bdb0b606fc5c3703ace3850916900e89b7590fae338df283076ec2840c35d89f70c0660f5b4fdb08ef2451ed3300c455a0dff28b0a428fd3968b62516689f7f0c1536c75cecedfd88d59e975ae1000e66fbe0a7c5f4f9ad44f29610cb4fdd10de4c437814c1901d688e1be14cc30c1a1c9761b3a6b23979593dd2d8598b068363f55294eef9b31aef529875db32f70dbf6232fcc9458e96eecabf451c40944efc0278d1ee81bd0954a17d04e868619eef32e93f60c5eb832c7d81561c1ee71345dd3b149549fd2c55cda3d41d808ccec6f4f7b6bfd992b8cbeca2f6cf5ea2134e6367a4ed9add521dc19247df92217beb06c8d8daf098570285fe17228fa0a1e55f5fba71ff4c11927b286c94f92091eaa11a5fff9a4687129bd7def91142d67124b6e197612eb7e08f780184b23ba26126ab49b46fdf30bdd79daa1c38a6f508c81fd52b5c0ca4b65ddb6a2af3e8264f5c51e67b9718d8c3ae4e174b4233cf672ad26f12c7b28af1fb6ec72714f233a2c70d43e9cb9ccc1c8ec17ddd4c6dd36804472fc1f768de638ac54abcb33f8eca764cdd323fd268b80c9e105feec64b249ba224f0db2e7b447627618acc585b675fd53668ce00ef346305ff6f3cc418530e31f44313db02c6d01c45e6adaa3d24faba5871b47949aab52f48f73098cdda07bf80fd250e4802f7d457080014d5afb4d68a2ec2cb050a46cd6743b9797c467f14181aa93b9765fcad39733250107292a4e3d3b6d43492b55288e2aecb2dfeb3b73f0f9138868252f9f673d301ad8d471ae856db0efb408f59f89926a3895d2e08c1a146f1a394f0ebb85eecb73a273a216f33c376577a938ad9d9fcbe3c5292ab641b30c989407f7b43a3b5f077c51ca9230fc996b150d1bc3a78c3ea597f768076556ff4c79baf9e0ddb77adfd90a5a70ab697d125b9b0772c06bbca1d6ba01a203ce052063ed6daeed85f01b3a29ca1806d124b557da5ce0554e5b15725ad825d6f6fa80d967f6a125d9eee805b015010efeb70b152bbae1d231d166f3264d16c98f35d0011bd87cf0614586c681941bfdd8d09700bceabe11057961f325a88aa4e7b6226086a74f2144586305b9e4ec364ca1c9659a55882612d0243b777fe3c5ab9e98bce51e7d5cf5e9e2973f61c1421f513073edd09a9005b2133cffc300577254f2bebe7df4c03e0be1f612587b66cbe7c169efa3eb06ea146c97178582eb72cd7e895a459692be3fdd9db0d7aed1892cb4e61a9e4b5093db3b2f3197e1ee3778255e2ef48d80375debedd0f533035faf89eeb74d5fd140671e77d85fcda999c08c4e424021b3904e9823c5bcd016a82607db5871a53bd3a13df486e0104511ba46bda4008fab6a5d951580bc42fbc9bca34af75d1d6750057327757daa0fa97e112f16d4c87de5b1b1b025286244b46c5593b399f856c34c20b2a36140c212724671bd78e476d1e7b2b1e4b131e6d2668b1754c495edee45133b7452d9f9a7fcaa1cd805e59b9b3a2a03a0341711ff8076003061a7b1e167797051c563fabb3a4608e596f644e1f951427b19b018b39410e12df7d8f059d1130b1809f4543bce9c7a085a5ff659ee93b4507a1eda5df3abe030ced1777a92285ee1b36c81b26d4893ca83b95b3aba21459cbf8dece3bd2a7b5ea22c9d073aa4f33b03c0378ce58a02539e2e69e3add1c1c3691c7cbc2e2e19378caee00c5c842954fe1d12e05a6e806d2e5d9c36d45ac983c7565e9e4b52a8013367ac25980841d3b52158d01e47a824d46634989ec391f8baea67f77e30edaa5a3c7ec00718a233e4fe1eb900b09579a234b1b7690321582479d24468154494e5f209a461af0c163c92788d5514a33a474c65e577a7bb72a1ea7b8a8482a742b1d91d031667bb200d86646f0771ed5a10cbdb2f5ba29d51fec2742270ae199e926e9f55e9118baf49da0aa1c773a422c7d4a7370338991100ee5dd36e4ec4261b7fc64bc2604e89c426e6a16a1539a3917adb161b607fb0e57114240e5fd2cad97d9c167df2cad8a8bb1ac4099303b7269b6bba97e5ac0d245d674e837b970a9c1b79e3c07383f0bd9a380141d08fefb760219511164ad8bacbd8b635ae624a1c259838414fdbb6faf46f2ecd9d726d2f08e4e737f8ed7f6cf89736238a2945a7abe6771b234065b875047c4ea2362b6681a6dcfb5f042432aafb0af6fc8166835c70a4fe06aa016d8843a87907edee3ab396f682b4573848d3aed26bf57e8a854d65b4184ba78730d635745cfceccd66bf321aac8babd7eeb0f159ef01442a6a7e509f95af084263f987c3ea780c5fa6970466b3b20f7a8ec600ba8941496f70dfedb46382a0ed25b72562df49647a813a375a3256c3649e929517b230d8e20543503364d17eec82fc2894a36a8a52863aab2cc5aea764e3f09f794eeeaaee895ed10bfe110668e9b7f857d4e9cc428e602997dac6cbcb20c5201de0a69ecfb7948d822afbc4c625178acb159816a30b16f9828d42b50b49c5ed95e28fc73d1a47a5c0000a8b8cd4fc8addd31e49a959d1abd530183b664a9d19dc8f89d6df810c37eeec2539d1f4cce9160a0fffb593b3638663ea5a6a91d9582d3e59e8203e4272589908b3cdd328c37a178f96c034bf598233592a52cc1fa12e78c72e85d3e1ea870608ec83587cb3471248821bc2e485036001b84462114794746f53366087e0fd8e1ba98158cdb33d525a77463bf4719ccb8e187806a804b9608516a03346a2b4b2edc100f56585324c5ea211b663174193a0980120d1b898cb805078c4d00ba3e01684648810114532c62c1bc997ecb644b682249623025580070c4cad535e4e3f54fc5492d1b69a6f0670db487a96c0f39dacf44f892765635673e85bc5c20b170e71fa874f11382a9d3650af1a1f4471dfedc7209db10331df6f8b694c9932e46c66bfab8ab92365366e25026e5455dd57033abb8951863035392271c26ebe944aeb5d4d6f1f46b081db8c4b12a84e1df8a05691d6c0e02a815112dc910613aab6f3197741de8618362d87fbe1dd4a10cc45d72309b245ecd7ab3a15ca4f2749dfad67869ea18c789254956a771cc0072b847ae239362160dfe1d499d415fffd0140bd17dca18b6563cd61fd76af9b16e188320bed2161a099e75038ae4d6c294dd7a", .Okay}, + {.Mul, "c6cca909b36447dd35000cd976d4ae6aa2afba085f505d706c309e6babbc04f7911a3c3ea2f85cd94b04fe67bd59b51c9c35db0c91d626f66f923fae296be867356298c9e23ae14853756ee5b9254d6807207fbb26edf8323ab5eda0a2f4ecc58fe91c3e4d9661a33892d7db9be20495e972c385163ca8f8f978e9acda71b6b58f1f5c28a75acc803ce710f3f935c6d8fe741b91ee4c271565e18e395ef302ac8405a059b00c745bce6aa393285e634f48ab8bdcd0f0c32db9c0135d53385343e5c94906812be42ffc74cd6876847f3024a63e1ccac5a0f1f7db5339f328ab59836766272cac931704a083389aada86a4b35f2570989d7c6166055a46389b3d54b26dafa3d7a7c123f1ddbceabb936cda97f63d704e89386ab30450920d977343fd85d862bb484ce4d7a2c245ba1693ddbd779d5f1f067196f898fbc20b13d099886a507bfb8255010fe4f6cfd44dfb79df4139f75f8b0eb7b72d2b37c2353bfa53d769ab160f5d2a3b7a8e265fee39826b75e5b0fbac6168781f790035829a7c56636514de412904616bc13b75af207e17050d9a0a3954cf58befd640c806279d81cd5ab64d77d6fd5af3b9adbe244d7f9bd29652bf55237b91cc3ea715d7a1a95d78b31e9e322a8dc0a40f47ec21e45220a45392cb19954c08607b41261d3d467a368b1dc60b1cdadd9a97a204539d6d342abde7b60ed38f8da66e8bda9469f602ec389d0893d470b69e73f06aeff1e71cbef93efc7d81b4102b474fe658778545dba00c0143d3f7abf1170c8da314a939f0784db886c3d818b59861739741d2ffd7c18a7efeae328f4b51b1e85aacdc131424d6e077a2a5494783a1a2203e8e25875aa90b1fd3e053702a6153b7ccb33eba61f4ba9cbb0d8a1a99ea94ab029c865f28af98cc48c6b19d5d7ed1e69c3624b7b8a3d8fb822328fe6f7607c6a9b009e8ef954d49aa6637793ba3864ad62483328650d31ca26be617f13fb84be2355775096b3d37fbbdea7dbdb9f519b846b2b5e5ed9b9dd9f5ba61bfc732a38e916137403d86a28e3357bc511799d28cc5e87b7fa6d73dc7cddbb3cd137ce6bff2d7aa3a89d779c29250ce793ab7d68f5a1f41a52f5b94e9cacab1488c3a84923b7f75ad1c38d370f27262efece585570cb17823ae86e87799616f4a3480ab498c5e38496d07fa090377407365394c6bdff587bedb52f787a59cc34826ad96d7d087a607b14c330b95687400df0331053307d62a852bcda94d08fb7f24a703860c5cd89623daba8a7e3a618a0b111d4d77a1da05f5594a83b69fb74064769d97607e327763ebe4689946c9d3cb0acaf454c529b1ace9801c6cb7f9c953cd972e35c29311aec54887a9bbdf4d9abc86bffa6d1301d96b1a920b5fd508a08c58275bf784c94bab8f42f3ebaa0ff680c12cf12bd12cb779bfd57f869254424ef58cc88273b1254d41d7dd37e5b359f20a6a915f1aca4700e2e519ed5eabb5b355ad9d221f92af9b3e271c86923ad77f10fee55a4a1aa8e209aa245a91a2077f2afa41ef287d7aaf3fe9e8e0b132cfb1082b9fc94c59d17cac7a482e2b9e6569ce5fa502ece942638bb9d9aa1f06016f53cca77a8c68f9c53da0f157b5c3403752fe04688af5920b8d3936358e3b39647c67f6fd2ecd28089a255f53ed589afec3e0bbf81f73b8f03d856e9a4dcd09fb76fa587e9d599e2aa93c7d0c1e94e84c728572fdeb168712430a47230a629d9ab78dcb19e567047a41031f9b844185156f4870cb0a30aeae700d580e74cad3031e13f3a6d290031494b4a1aeb7dd86cfe0b8f589baacbf2562fba45329a6c5c182f630fbf755bf2dd63349cd4d6eeb68ec16b6a2da493e2280bcf321a18de84783ef944ec64bd27298f6a6cb2ec0a9db14c0f7314e1799d3beed72748bbffe2cc962fbf0ba2a807a06928789568666b2fe2b1515a9202d30214877027f77f2d8cee2914a0f39340fe27611844d42b13683295464cc0e2c0ea83ca7e69afa1517f5d7a5145579dc5c1d69b4aeb8d765520ab88bbc92eee8a34d1426ce957d461b3b8377c16abe0f0f9e5ba443d5a3fc429ab1656052df8a2723e6bcaaff03b9de7dd1a9675d60cc4e8bb1882abe13", "8c1f5002304e9ef7e11ca3c28450be1dd6e65028b93606747fa6f860ed64863d0b31fb1c76934c53ec354d69d085bf91a11751ef70a69d298e96a2ed22dd6d4ba2cc303e053d6cbb47f23afe40265b2f1d16281b6bd31cfeac0220a975e7604a77f54c8ff3facfe46e6314710eb1f5c9b9f3a3929e863b7d6289fc200e1d4c7d655c8e95552a47c185e7d06739eb66390c54de2593859a43eda6b1ec365fc182a7510065f57d3bdf7f29bf074bfbbce1809996f2f7d7c3e19c66669ee989021b8267db22d5487f1dd7d2184c0a7e36abcd2174c2b1ea56d0a847486b91aefc2b67eef8ac55522f7e9c5cbdd26eef63537e6d23d12803d047c016972f8848ae42409cf54f53c0b2d471880dec5df873843564e8af408ad31fa6aea4661a4c45a4e911dc5afaad68905e40427a1e37feaca47e2a0cc68096ef212ea85c59955c67820f716a020bd67fa7310578df707aac8c9c799b83acf2edcc585020ee8dcf53898d67f3fd31a27303993f3f98c66af61f0d44c978d7ca8a36ca9447977db5584774b4751a2508350431509ff519446e33c32c3d77b3fb1d8032b5489487ef4acaee2a855dd62bf2f0d1e39fde2d12b01dc2d930bcd51f5dfa6ef275635fbc3bf89741ac821224a8dd8f8dc5d1dc02dacab03421363caae8c3b205c10fddb377b84142ee1cc1acc6342420f6e967f260b54c935cb672ce0aab5e6a49a9d156145d9c2a770063e60366722a833b4124dffc643bee00fa22338abfaf087730145300a0b1a4e2c3886a42449989d031027d7b210a021a89022e432ded9b9e10e34932a53196ecae97b847721a06cab4d5fe91dc8e54e2d79a4140c34dbf585ccad2418ff3a793d1fa9278e1dfccad506581e03a814b1850a72440ed3e84ad01583f9df92e20c59bd1492a7c4ebff9c5edc6f4e60b1ed734bb5c0d1da60e4c9f5f90504b9c91f4b9131fd6a8c6b946f767ee33ee96197b1e801f018be2856fbd5c988c1af971ec82da8c123ab3908d8606db14d54cf095434402431131811c847381f8e22c0084219c1fb7f82c5d75173b7c7b0446c2ba3f96c76e9dd64c4effc92ca73faa2fdb8f96f3cc9cf8eaccf9bc5906cc87476a896a2fd856aa120ff823a02f9e39509cd70ee109aa8a0f3e96f14c802af7524f06ae1dc733b82c16f0669585ba0832f5d81a8aa150375ff6db81627ac6ce437a88da3efb38fb31ed517515b72b30ae313dfc3931b7049155fb13e63b131eeafaec135f2844c42d0568d608c1c3663ffb60a462ee0eda9939ef97bbad456e5cfa51905041b89cd35defdb16e91975c446b4432bee8f64df2b219db3cb3c65a4c214ecac491fbb2a8b5d468f9f9e43e78111e946bb321e7aad54efd03ba22a6ca2b743223bb0d1816b67d8471c0c25aa7f949f29ad14a3db7008142f0a39294538b348ebe69d8c99346bf38fcd6a733d7ee2cdd4204a62bf0efff9f6057b4cbf7ab9036bca439c9827d0eaeefdf58f97298280697e29a6c36f4c02927b3f166ffda60198cba356e1c5f77372d62a429fae67087e459cb0b06c189d5b595b15f2d0c328977a0c67dc01924a6a2c595adf22c9ef39a803377ceb51d1d1859e433beea92477a38abfb5ad9e04a4b0aef8c92c48fcbd24afe878819982c30dfc6a33861aa7ebbc2d7323b1aa5bc67ce515e5091cec39aa2d2368ae8fe85bc9d4a9a0fc0508426c6004a64e45a4a61e7a1e6bc9aac369ca9a28a309533d85ed98b54fb48252b1f64e8ad004c4892efee0e8fa6736defd6ac65d6c8105796efa2a722de67ff47a42dfe8b84d4c73a3a1d299ae572b533d5262703b9ccb0c8968b0316197af0135a3cb267344c2fb928f026643349e0f9b9630ead5551513d22341e096e47aa3486321e9ec9008f0b35b45d9aee499a1a40080984bed02ce4ccc6bbf98d61263b138af571da6d7650ddf34aaec3b4b6b59fa1901d8cbde17cff566a61d939f65af2878bbbcbf85250e540beacf1597369dae7f352556195ad8397dc37d3af3645e95a15fb6ab0cf344c24255f785f916e36f0c3964e74711d543b70f597f5d74a27a1abf08a58e3e7e803595c220871a670c501c5005ec0e46dd6d7026e08848186ea9a538", "6cd03d5b6e3758148b35cb8da3fc0afea8266217e765818990baa084229bb6e9b8ef804bff254836ef58f54d371094842e2392640931a003b88c1054b083f9a5a6ef20ca6bf4b73d8de346201f6df6e4ed91c4c199cd7e0cf46f88f6c779afece8cc33fe24c050500524ef53da73ad1561dda63ebf7d0ea362cf67b8fa6fd412cffc4f86968aab84c96b5adf256fce5838e016f4b50a233e4391d135417b0a6c5efb3412f700c8041640525132a70baae38a35f6df85fbc3ef022a71576785641b679a22779bfd4c955d03133275f0b9ad55d1709d6326cb61d4652ef655112f7b2195a3af57e4cec83066d9f99da277a3eba6520bc37fa569e480374a3e16edc4e9f06df2244465abf3bdf9b5844072b23c42e6e223ad8285cd08ae874aade9c32396e3ccb1d889599a483e36e5654814547f8ae249d969d39162338853d3fccc59f313c68d2689d0a282fd4a3882baca5da138df7e4bed64b177c892a86a30f011041451f39983d2c2209dd5da12f81373ed0ade712287c3f34fb2e1b1919d99297d854c93afe86aae90c21fb0046d7191d1f35a697ce7f3528a3ff2bd61dff4f798f6bf4cbff642241fda87c038b436369df580db4b4bc2f1da1626c16ab0451ec612b1826560b4e58fa99974824bb76d89b5126ac3edb926d3a23aca50200943329b482c3c5e2dcbae3ea3757dacf49927a0ad501ee847fc1e8468b6ecb8036900422297e2b438de2fd113d23fdc281cbf790a9e886448ecb25b0d385670332a40b04cc4f2c5650216a26fdfc0bf02f8bc1d1dc7af875e6bfe13470d0af8e23c7f3bf7e70b2db46fb6d25f9dcad6abc34e4228646009926563ad20d65a07254f2c7eff848d9d6f3ba0c6554b80da5f643378d54b0a38005356f0fb34e684d903aedcb828d129255b7cbcb4874a909d1a428f7e416704a0e99e890cca0fde35522fef0dbad626b0d0c7590ccbb81274bcbf010d83f2900ce93757a33e63b235788e61f270628d7a6ab790ad82a5cb80de12d0eff467b5bc09904c53e2fa53f1dbe427191226b284037011fde3b442132a70d48ebcf2e0a9dedd709e899fd143f1fb837c869e92816fc057b96f6364955f5115dc31a66d673b3dcfd53a33f0d2af2704a37af9411a9134d47039e328547acface9a493008fa6069ddcc81f49eab9873aecc161f67ebcc0ebead943678a525b4fed0c537c23267c65a24d5000b69cab716711450ccfdaba0de626054c8434115335dcf790c390b81b03da33c8938433f4e80ad7be5fd6b6b087b9455c310cd97d1a45bc3137e761c0e3384f7bde4aa832a235f269b04b54a91caa16cfb8461ed5215378719609705efa341588c0a9a4b4a77f6643630654401506d3127f0b3a75c4f47debca68d4557b564c603003e60a1c28a3bc0141e0112c9bc4d92f984a86d40b2b52db81ad17a1091bbd9ccb442cefb31691984799867ab53c9fc1d23f42f85439a572bb0e0cfc6efe2a8e182d1470431795e765087d2b9aa08c3024cc5bd77d55d7932a573cdcf79bd3cb47949cbf65417eb542e4432d3913ed2c0f655e2c9811c4c4670528964484dd98c28f66e86d1e06ef0c103d29d8d6ed242368e7b25eeb3a311aa88cb69dec790522e363b22f1bb4cc6c03940909d7301d838cd3cdb0c7a3921b5322120dbf71fa813376ec027345d6de163e9240c88819793be54b6b0e771c73c20adb736fb0959f224bf8f3e3ed45b7a3002a3fd30f8a9da403b505f496bd6bc0e7089eb83b6d76219e37ee470bc3f134ab163b3eec52493577ec86dcb52bf0e3f3dc38f78b14d9a906f376cdb963ef006333b4582526946b8b4ae8175e72a9d0ce69b440e57dd8521be69bebe38e051d07b3888355032fcb175dd75cb9d084e9f4ba59264fd0579620e6b86e9f0cbe4b2b44c8a2fe783db8e70b73e547708d5b981f41a46c3a8d4c380207985769088728c463c658a57c9c603e011333b3de6c197d1f81bfe18d44c20ae89d5b3e30dcf88511c627dff6d20aea3b02c9a36010f4e669664386293d64328c75b1788d743ebd30e379dac7d0c16bcd68e0aebd81debd095f2047c67148e083d26aff3d2b52637111e4957b818e285c6be4bb2586da0a9782403c44f63f5511dd46c217aac6bb72a8932a06ad9d426dc8c5b90e030b65aa9f9b84154b9bd3d232e368b31ddce7e5f6e01e13c720ce52ee99a3f6706ca790312f08616bceb399822ad1271e829e81c9a39cf55d6924e5f22c69f1b6ac60a56bbc520c75e963575076cf4e01aa6d00f1577245c05df88e17e568761d02dd9ccf27c95a7fb655c5d44c54f96934af0d4ec730320ec0004d0197f6feeaaba9b5c5dadc92467fb268e34965c46943d35cce1eecf959f59f03d088918626c2e349639525b8fbd4dd5498e602f22cafa8807f34a41d513ba38390caab9728508211972f776fd9abc8e1395991602a150a978b64e5b6f1be427df28bbb81b44097909392ad60f5ce8d61039c7658705c83b81a4d03568d7a88daa5bb03cf8e31f18b70ea8d72dcd603551bf536aef4aab0349deed7445a586d1b8369bf8fe27868b7acad2006aa1113eedf5214a297417461fc3c0eb78db5625018774d7cf5bd6763c1d8a3c923390745842f7e6f1e47dced6a00e8f8798b8fb4851ffa83dfdab6a8566ca33f165f631eaf37552f56168617f8ba39882e27f963460b3ce1723633cdc16d7fc5ab8cd25f789b5985a57936a32e588bae83e3fdbe57497123b10b7c92fee00468034e047af90dd651cb40c56527b9e4ea9653b9d3a68751423d45f366d35dae948c2ef9c1b61bc24f55d0f0773ac1b333e7318c82cabaff8b8144f226c2acf16895dd1859e8c25dec850846fc43ab9aefa608c77e82985375f68e7519ec0ba19f797c7dd576b96353252a2dd1068b75d0c23bb86ec003ed2f3c0f7bde3f039225318db052e40d39c4f0f6a1f45008198043b91056e4e7dd1a49a9b4e233b4d2183f55e694c269edb12c213a1d3508de3ac3f4f8400145d473ebb171f46b170a58d149770a96459b27d74595e9e48093f508491932e4b27f0455dfd7cb3067ec74c6d4b1e44e4c4441224cd7be72233cc64f5fb7b29087f50637b8daea7573d98f7babdc9eb39759bd5ae4833024270c77b6d5374098b28afef57d615863fedb9718f11d456fa064e4de0f756ce2c2366c24a9f341062f1644fa3d4854e9f26d2980a6e0a97415a263bb472320988269f9436aa9ccefcb29b4ea4e7d2db2a768aec250baaedae381b1bfaa54f98a68f5aabb881fd49771ce853328ed84922c7fec35aee7f3095fd82487d0d7b078fb87b9298e4b0dfceabf3cf167a3679d457a24cb5e54846b0630bf5060df940cf566f4dbe02e8253804de23a42542cb2ae7ef236d5645dd607616ef4288d222d990b63c310ab12ac4a906320c8dd10470c12c438adca949b36df24c85025e5be318e81bf1b9fdc692c75a855eea1af001ece3a5814d1be07bb710450f43dbe45ca605c1d221b3c06f08fe05bf562cf24f343993d98d80244cba1ab8cea4b3b6931ab20c68471d498baea86ea77582d967ae38f552e5559950c8fcf537007b5c61937aca581ce1f77c2642c2954d1ac23711b1c97af2d633a085ef9a6246a000b4e7bae727bbf6213ce6bc273e7ab1a2ccd9d53810b12ad7201fdde7e7c6e0cf56b41683452782308fc3632b3f27717399b8c726755b59678012d1a134d232ac54a85e2335b2aeccf752143063a92dbedc5962b2ff1215ecb2dac20c4136b8264cff330847bdc2fe01d822788d61b09752e3c1e11edafef00ec743928946076a27f0765f9996ccf85707f2dd8124d264a61bbf1b1167b2e755a13fbc8e0923ac8eea4a32b5a1556ad7c2ea19a3912d9ef36d5d17f40fadf290a7a4a605ebb49117f0fb554d217416d558b35c3fbc4d9b7048ec7b819dd5e4afca24c9303eec1e1bc878f8f578e39bd688cd7ede16f3521271d18d9976c04aa8817eab7effabda2fcb81d1353cbe15e371788068b8f4b1d38e227173ab92bf94d58513cb56e8e62875ee5f1669cfdcf1dbad4ac1931878c8a777f61c42065a2e58ce8240f6f67e5576e0b8b77d979e2241486c83a893a8caa96b8fab19edd42817cd82c0e115ba888756a162c1c7764b3ce16b2d9c157ce515037f4782e0960ce82e6f7352fd7039a6a9b4637a3ddee3ebb0186318de0df7467d97a5f5842724f109f714ff530bb84357c6744fa66d328", .Okay}, + {.Mul, "b7b40ab6047ec9c842db32a33ebf16e6cae6311c6400617bb8531691adf3b7494dd87fbf8cc5e74cc0cf67e2066440bc0b818179513b9df50218fdfd485d15cdca391040f59d478b4a5c216fa7c1bfc47fa51ac19c1ad14b4a8c39615f6c7a2498103dabcf02e3c3cc5983c98306865ebf207fbe3b5b407b8d0318c3c35217e4c54b4bd744647c98570a49bcd0a60f8464a47ae71a81b9bcdff4ef3a61744d83857fb3a9d97a7c725704433cfe2f88a8b0d140bc041cebfbbf5172fd1d8dc30d15ddf34908c9bf2b85d0402d7df1ebac1ded47bf759aefa1a93d063a3bad9d1e7bf5cb35dbd3f2f3143ede444aea38d8839ab98471f1e42aece92b44ca7c8e941ebe8ed6bd1b229c35eaf62b7b48eeab022a8d5421c993f94f1e7037f71d7a23fcebf65ef6f853dbea12ed6e2414fe501accdbaf0a8bcaf8538fdf021b0eda522f7bff0c9efdd10abf7a4bae29aef79161069a376daac829df7153be090ebd3711a7e62dd510fb4519da3653b5e97c22c83ed3dcda0904e4e17cb0cb2cb267d57b24c5339806f8395eba7469a440fe73b232119ed49f0d0e1af75d63ffebd5683a9f138e49d1f35a7e70678eb9fa8ca2ad23753f07a67bde402ee4a0b7e91e12b56d4cd3f02e019b2de81087104509e7a4e93700514909d98f3a309dd1946d623822b4333d1343da153ac2ddf1c5163a153c06f8d390f1e3f1368024a59482e9dd4e8f99df5025b1b2a42577ce78678b8a2643d061b2a4144f4da8aac997f84591d94dcb122015a3417e128dcb4da9df4f6847d6dba7eb6f5680b347d6aa953daa2dc135bc3fd9f2cda3a5205d0ca5feb5784af6b329a6abd7c24d776a05c92dfa992956ed615586964ae5674f1a52da42156b15e6449e1819de5ac6180d0179591dd1d1eea1b627d1c0ddca6b8bcd71cfe676d24356a6c5041f3a3f82867cee31570aca27713678b01827ad8aeac7cd445515f33713fdc6af05eb0b3d0d4fb177016dc6ba9852c0396047fbe3b45ba155d7ecdd268d4d5178f022170e1474b2b9ff7b79ead4c105e07aa67de7395ffcfacfea7065551cb5fcb59571e31c7faf7727d502f85e2aeca4e4c5d9614b18f5bfdfca1e6b3a1a5029cd63c44a550f63a909a579f7f73a63297d43b1000560bd694e99cc7c8f029a09a6defd63033705a438824e6f18b2e896a1a2f841f946026663a006d5b9dea7712e044a33f635c289d2d042bcfb1f26d14ed72358524794bf0f6ab0163b15e076d98467f701699c11a5a0f336034f5e8280b5ef10c2e7a41258d555df9fb1ddfb62465e72f9324d6de1736f28f3801a76d8169c8c72b5dfe2b9e520cc98c1884afa6f8df3c3a7442a3c7d8438f0f9acb5d6fdabc832f086cf3fa9d69e2f713738ef34eb4e86bf20f13f66529c66daaa5da23d9afa2aa5e264054281c61c9c221085a7953a86fdf0774fbbac2489b532c9135c1b6fce90b8d1e77415c3a10ada90bf197586b003e90cdb9804a818fd26a0db96ca5fcd176d307ac18a80ee9198a70bcfc1681cae9da1f9a7244f7ae1c86e16acb61c3676ac431bc8f86cbec5806a12e72c9ab92edfbd7fc5328ef831e3917500bea7a24a7b3d419aed729c0ae4ee343dada2957a6f830fb7c16181a6df00a39742753420b21284e713f3c5e8388e01701eb3e36471e3b059bd44bacd6ca10e67298d61e64407cd43fbcf725a8d694202ddfa473a90dac09a0cb63294cbcd4168c1284f7659798c8ad7491f8f201890e8325ce113c5397938beb2a3106104a70fcf99bfa233eb42bbe77ac4c255b9db0bdb010eda16457110b2666f421cfaa5660247769532d7a6cd0142785415c19cf86297c69336d08710aa69a8b1108187faa280a174ff7dd885b77c905783d1ace02384e75828bb62fafeb42a81193d56b4523e2f9649b7c65b12faae2e917aaa0bcf0fc188c8022dffda280c04e3eddf867e36e70c054b48d56b4eb84c9e88e656d09e4a9bb2d3232f31d826befd8d96732014b44f9fccfa32fd63f10af87300883e92ee7a72afcc16378810810c9bb3be64a225cfc8114c0313ce7f0c744d3645c3cbd843b8f59a5cf9bc93f9651331725138199cdbe3b54890cdcd14697952219f", "917474543617c86ae9fac0d7a7d96f84ae6dc2d19f407951d66e5ba82aa920693ba6fc438258630ef78f161ce362f15a0732539591486efd666293edc4f4e24970f7f5211e94eef8ad6ab75a9a31781b832d6d53140b11bfb11737d68f336c54b3f4d9e94dae8861cc2f8ecb138a80eb2f59d5479f35463d823216d73ec4569b3bf2745f533a8661878cfab666d52288b06d407ac9d3025f7a1ad3bdad922ff8be700e470c1bae464d750229c812f66a9609c4257134eaaba1919bc0b3cc3661a80c70d3155fd1bda36321103134bec78909f66584ce9cffba95ed24b5accbeb134e38add2887b4a39726547fb29de1e5566c5a6e77cd7c962afa4b2cbabf400387fac3f6e4b13cd1b4b4960c59ebc510cf4b5f8eafca9d577288f3717ced5b3e8c53659ffd47e509380a4726015730373967e08c1acbbd6ee52a6dfc78352b22228ca1c8a515de623d1fcdf09ab0d804d9cee8c027c1b442e8d2fa66bf23475ed985fe008d64dda76c91f12a808d19cdacb8d487ee2685e60b88e4b2e3174b1ea08f9b8837ebc27721235666f1b44a51efefb5fdd62e1602c91c5a887e2949fcc7e0546ae1f95af2f655325abf242b2ac5659aee55e61d6a46c485f8537cc32c150d9f405eb0bbd40aa34c857bc498ffb3aeddb02b8c557cfc169ab748c8b8cee2ca9ccbd9eb95a7f8836a40417b7a850c5c5f5233049c719fb13bdc506db5fa9ae27baf8c40c1036002147f2d473adaa2a8fc9a67dee7eca93b3abb6740e5bfaf94e62554308ff40bc1240fae1a8b75371f620625ea67a1ccc8c0c8da1a9037d31b9c526c88a0d36b0eb112f282889f4c42a9f09b34f52d031887b98959fa147c9b42a88f53c61a2ef4d669537a56ea1ee9f24f63c0137158ffc39437f17806c2c6da1a90af211904cf1671262fe863612f12602329dc4230650d13402f4bdb01f3f4c84d11997c658166855d7f1f27a9673950327c28b2630381537bea51bd7898234483b19ea0d3f72f520931dba67b941c952c44de30db063019f989e56fd1150740af8dad822c00c7e141988544c24bfdd1a8ae1e9f1b29ec3f85d4184062168f0c955de658a268ac9afd2c39d23d9a013a66b9181ab42da84f563fe5469cb6c905d4c9b6fe301317bc5887de016d3b44466b69c45fbeb0551feba6f3e2e27f94c56ab422b23173133c32ac80a652e79ff220de2db2c0ba47c96d1dfa69c20400c96c34c8bacb1c521292f1579274f842c91e560b6723f07fc7b3a1cb7f08bc026a90e7e686e349292d161fcb532afe0a72453b3ce9b88a3ecda2b06b24e91ab538418ce0d103fb69b66f445cdddbc2a1b873e6479ba4f48f61149f6c8b7eda612c2655c650cfd5a4f22d6d82e8589af23ad924dda700c572ff58f7f681a8d28c69c6ad24c6bac169d39c671099f4a5dc03e5c7c891d19fc23497d4e0e0acca885b6ee756018e5ac0a5a2c90e41d5d212b82ff347bc2a6bde7c4ed41885ec934eec6c84e99fd1c4a3913c8006adb7ed9a91ac4931965db12f76454fbbcc2560e22234786feaba23640524cc4d2b6844c970d57fca8d7f0347c94669ee52b7a4d7e4f289034a821dfd652d58d96d6114438eaee28a79e0e52234ce87a5aa5bc6c6be5ad799f8620e48240b4dca30364123fd1c6379bc11408bdd8f3978dc7c01d18d0eed0c8214d3c452026afb197aa2b6bbe619bd11b3f2a5ff885f728e47b1b5cf69af1b014d8659a8e28d0c6561ef81e46057b59caac465f98e9bd23b8114ce96a6921862930a003d607164c66c75b03ce9d6fb473bec6128a28cff190856a6ef1ba0ca41ea6516e89e06be4fbd3e0eda5f7fda2981547dfc66672194e4d5f5f82ec758bafbb8f3d41dab69eab1f83a46932ea9e17f6feec97e1be50ff74300129eaacf411323a7c57065947cbe7fad4a7ccd73164ccd5d5aa430498870b1e5b345d336dff0b16d003a9475f817aa1eaa4634806b09cdca96627db3dfde1859317da33754ebe895f7f03b2efbee1af0806b79ba97cfcaed29aa61f25061111ad4aa4a3f98ef18a7be687e0d733f3b39c091893488a1bd2adfb23d469dfcddca7ff00390343300fe2ee3363c6f1ddefa774c3f9b86ec7fc3e", "68608b1ff5c4e2c185c3fdcbdd25466a78e86a86e99ba3b22f6bdd8f45cc847345d1302614c1f92406d7e6ab0158e8c1898f03ade8d9c6cd5805ff2ff2199af584e8167bfde8acd80f5a08ae32700d1c0a0a80957bfa21fb1a3a886cbd64ce1708d4fe45e193a4e36ee8e1286999a2d90b7b205347e761a1aa1ff1d031a345b5e03b00847ba6c4cd6ae6236fa401faaebea814e9d909ba85a3e49556b58b0f72207656d6447c30f9e0df711149f0da114c5895f5a5e92c40ea8f5285df63d6f904ee4a15469f0d63b054ac6a88e1d4491a0c53b1f684a7cd94e22732398ffbd0f0b864efe8dd662b91f48ba8637d1a24ebf427efaaa47cae25b151b51b9a915c1f710b3aa5c0f25b0e8edfa43f35dc6d518ee5949391aafcc74f2c8c46ba66f0a25cdda1c73918e4320d6070c3e08646621e5d90db0544fdac30ef1c679d8eec05ad504fd2ae773d7084d8c67e0388bb21f3a915b51785ee13b2432bd6a584836198bf31e50a7917c52c90a9bef3718aeada0732a5eed5f76743428add4abe96629d4c1a8f79ba5fc57fcc465aa560e7c984f88aeab37cc9f21c508d52c36e808a9e8193a75a2ec29c728274efb2a885a69dbc80cd448306087fd5636a6abab35a44c983a50ec7d9691380e596443af114013cec398aeb9ca8f9c3e62245489ba5dd039d77f5b68feda318b2b5309ec33edde7834e42d1c49623fa909d500a4aa6349b9915edcb24ed56f085038ea6504a2654167b2110ba91b40c181517a93cab365ba12588f4d9df52f610024a7d0d6922b858b5b137f3d315e9dd426fb5e2dc73552842ce2b018ac8dda8ec838b684d624ad840e7de48d1e92a4f677295ee2efc5034cf99030838b3aa6b162168aa49bf61bb1d78c718a117faa2c7d47daa9f6f4f7dbbfe0cd5a4472e358fec5268d7e646d2a1d1c997264d9d29261a78143c30e43dad1250406d3d9744f47eb1317a9c568b2cdee68377e8bc013fdcdfc7ae3ab63f9a1ea239d7b7c22edc4931875e0370636ee63da59f52c65a227eb447a4fd4cdf9b1fb28c3833777a56e947b475361fad66347f9edb5cddefe6a5e725e2b00d3fce610c2cd073283dd2bbdc4b922e433ad646279a9f09b962cc17e7db29f849ff3b41d7e9cde70a4eeeaba89c2a411dcda3b3b62ea21362b93afaab612001a185e998f5a539ff1507ccca09cdd520a0d976c823410cbae53b74a13bd1a5c7b750158a090d2a725f93a42109d48f7f67aa08238dd7fb2183fb184cf84e17e463f60ffa6dc34c662ebb1e4a5b9e952eaceb4c099816b82cd54eacd6d98ce654299d1d09e07ce89463124bc6bfd04a5f381d4337fb292fe70987a985bb1caa3e6a5f5c96e39da749cab43ff6277a327cbad1874033d2b3ecfa3d2834e1e731c6efcfab12e9477a0a082471b789b6444b8abacf837650d6d2a92a5c340fe9cbe76b4e9825f0f2e71aaadae11cdbc4ca0be1fa3c729b28de61d3f5d8d853924f17d32fd77ab6c4d4d53aec427e0923dc0413cea8d84012909405263472fcaa34f7623670e70ebcbd9585c06fe42d8ea7919a67ebf7373a0947845114bc6593010d4a1f02ffc4d8760ba27423166e121a7295bca007e02b9664e824089c0867c48c3b1c0ccd6f6d569dfcfb48cb22ea5fabb289d0ea5de84bc410bb11e6f3bca05faad3bf81779dbf65fa3f31ac0dc7ca9104cd5a55c68043c911742ce16262ca55177ba66fd2a564bfbd78a0366367612a09dad842972eecbacdfaecdce42defc48e6eb649ccca1322406bdd772a862bfd5a18d3fb063b4a0ea071766f7e6f787886c9a97af54ed256ba2c92f99c6de24a24876cc335bb906c6b0d54f4b955d121fc9b97ec192e30124f331c34490a8bc7444f8d8ffeca8ebe7b0f8ca9abd125331d5a2547a55cb116b4232760d44120385567143af5774790e9888145631ef8e196dcea5407fecd039071151393615741136d856c7edabcaecbaea1da52fc72ba7eb71667e77024aa5faa3a1a6155b50f96ecd461723bc78bd1e33200f230f45e8aa47d5c066a8480b42fea230bcdf7341a90f4aab7aa06cd761f7d826b440bbed8c439a391415151fa2101de320eab31374f86f8e411d2bf91fa848692227b2300d185aa81d3f312c2673b3265aa9b71228b1b8618c245144ad62eb831c1c3465327be4c83d37fe250919aa1877fe667949e2dcc965b2852bf1840ec865e8dcd63b015bed360d92e68aea773465a3a942960d0b0881bc1a1cc87cc45143d78093bd5301f3e2ba10401a1e507b70d4a6354fc96cee5684b0eb6177fe9a14ce04c5e9368c4f4c454c65faf07ffd273fd07099cb32cfdc7a8100f0ef4ad4ed7751a6c73a3669902068740cbeb02e86bfbd2b861c236cbd0aa4c57f98dafe8cf53386e273b5a4cd83997a2f4cbf3e4994770bd8d9dd99c2f020ec95093022c59a2ec748e77491a7fc6219948ecbd129790734739ad092b5bfef2c7824934c0dc70334a346d41f7fa3df4594ca2e493fcdec209c9a1f0032e66740969cc7200f8835dc08c0df560326c4bf1abd3004c082c26b67c07c99ce7d6e322111c13f4172d087e36f0cfabe4bf0b0a98b472664d54bcbe574c33d2112ece57bf35514254b0ee9a5457518cecc26be79bc2eaeb5217bb29438bd679e1d7daa649080b14a4a9fb8067ede385ccbebf4ad3e9cb1883e66691d02959c27536a56f8e737c1ba30a35550324ff5d2bc28fa99382c09a76aa91f570bb5b68628b43f35112a489d5ac2801d8b83f08554c75165e43492c3d241613031102e4349231e252ac9dcb18679047445d267489ccc487c14bd3bc783a06ac0fdf1c95866e2ef4355a5a2d0fa3085d0446af9ef0d24d6fd5fcbff7767084e0c069cb5159b793e915bd3f6e4d34ba2566ef22226a2115fd646cea6e914c9cc32d003c539b594701f2a93740154c80db1892a55aa4efdb8ef63bf3c1e6a22faf1317c624c924e5616a8a76f90f4665e2a499872eb3088dd64b3e6d9d7207b099222caff5d422dbc32787364cfb62b69126ec4b429acc89cb488d2a287e26b95c202d519e8c9116e0e8ce3b8cf334efb42513f53d7f1d826678334679219d8a7fb0c90eb0b0b0ae13cd19117475c023a7f81f318892c6acabb0d539130a1aad525d6d0a74fe9268c84c825029179b26ede970671935b639943a8110011379f4e0d2e1018ee860f9e0c1db9fc1d985bb2648307b0b33156bc896a2bdf4425d091f6c09a458341a4da45c07b50ff191dfcc9312f12e0c63574cfeadda8b3071f89d935a86f5534155d01c1547786a4e5033c7eff0eea35d8f8890368745876e066cfbcbf57bc2c8088c0cefe2fa503f3ff5fe50384f36935f4be4efe0dcaecbef9c61d067d8f2e213539bdf4db28cf34de73480fe9f86e42b0b06c7a9da86a999b0f1abc1d7b0a981343095c869ceb2b00b13be3e9755d6228a5313117b49f14742ea745daa449377a9c04ce35318bb6094ecf22a370c7dbd683a023ee06181622953cddf41cd52cd5b3b4b0dec471f0084b47beddddcab10725f14f1b461291df8b673dfb2d1678e27f19eceefa7a9694a542bd0879570ad2402e1f4dae69bd3ffc2ce4a88a0f7db03c568921ee41aa0ac9c00b760fc2f2750cb386c9429bf0b2ea1a72e7b0be3a0fdf8409f71c436f245f4876ef2e55e5ff3ff1b590ee91776a9b9a7b5803f965c56b5fe898b21cb91860b14961fc86452d3994ddb7808befb783717b1f51c19c2c0229d47ebc0d300841b4d75650a88c1bbc5c54881f3a021da9db2e4487cf6bf7b55793a2033dbac25e697c6bf651f83939551e4c4c37b6f25ac75134c64e9e3b1e6aad9d2aa93acc375da3444787aa5a3e405fad420b4a6da53539122630d525f6d49ce03968023588bc4d6bffdc0b89fcd2ed10368efe0ca676e343783ddd9e7eccc5f54e049ca29d2e92632f04c936fb57560b1f439a91863efc96737ba7574353318c76cd7dc00b066c529d5e8acd8851b8f1a7086d3f73069d3c7b1c2730e58aeb9892ce70e425c62122ab2bf9f6810f7b9f4b7e026113253e999b2897bf2d3c0d1435c4ffaf2d2684a1191c879c3337fc160625744881f383e3fe85fc5070deaac12c936d1d026388f0ffe19c67352b5c92547513936425dc27f1ca83c64eb5ea03e7fb0f94b054bea2d712dedd8eb005ec0d8b6deabd5bdfcc72721871e627e773a13d92f7000a1c1d108d71f5dd17d207a2ca5ba2f8aaf95a882", .Okay}, + {.Mul, "-da98484f8724f2cec61d67c3cff08c329b41905c8d61575a79c54674e26af0eace930cb3f7defd30d46a3347df2eb9f78dc31925d40aeb80856060f4237ab96c13ec6ac626f4acdba69dd2f9104e64b4d8571bf91e272a32b445cca02837995b45c265b510f5539a0fcc98f7f8d11fd027eedfebf5f3aed0182117e413833e15b6feee2526443f766459b735173851aa7c81ddc09991c4d10e6e62727da6acc33edc7a77174a2663810924c00496a468d5b18cc8dd3c1158665b6a949d8b18bbca3451dbd71c57b938609118d7814825770d41e736bba3753b512fba8ddcaa85e160694e3b157f2a9cfd83f7eb6b3cc5a99317876d977f9dcd87d468963dccfbc01f70f075b025deecb2fa605e7bbe9c9bca4252fb6299c68edfbb3bc2a4e0e9ef918dbe18381678e29b5b9889d20ce58935e11625a6a70a0e75f65d4c66a27d562563bc0cfb0606ac447f9ba8a2c95e026f1a96752e9df5b0c1de54635470abdb4b786f0c8192ebfc6ac274d210b1e1e2da85bd5a646e5f4e6f3a60de4969b510d98d56ebf6636facfb13e37c38fda3c90f6084150ca981ed510b6bea386daf76450725015ed4ff556aeefde45ec20380b1fce7bec7fca0524b2fad27901238a959be7035f98048fd213f08db64d08682a5d3d14fd25eb7943ad1acc098a4c2591487f7d4ff5923cdc64e304747995e90311e84eac02af2927158011ba632f39aee12ff8d5b3d951c63ef9374f399806b3b67d8feaf640dcd6907dbdfae6a8b376e08a0743ff88f98b17430e603eca45d6758fc8bb02c483cf04898f5ee9d6dbb3a08496e76dfe9d723346e044dfc2c39ab9373811883ff27c032f473da0fc9c4235460db89cc7d54b3f723aaca69f21c997c93d7cb8e52896e63347ec338e3a242cf422ae66856303da8d8ad735d86ef3ddd7d84533b54bda6d8640d4d3b9125ff00fa3f7c6fb96af7e48ac1a792d14eca33210285f27a303542a47b5572c00092640f597cf488a3d6cd7b8042ed3e2c87ea006865186e1756dd62c7175f16a06bc54f1301ac92a4ab17efd9b50331a9486367c200f35a56d06d3279b5d15c6dd99dd5ee4f2c56510d2b343553203e212419cc053dfba44fbacd3da89982ddf36cffe9d1fb7880b6c1f938aa2305ea0c1e0c0368a64c2d8b948a422267dd201677ef6d137ac9695fc115e6db85f9d5723dcc1fe7bf482905dfe7e5a8b21839565e55e0f346ee333650f65d77b6b6f182c9917d311e3950acfb6569eac3d949a7950b2bf35161d2ed76e6c4149521eb63366431b9e15db3a796907965a9f96c00e5c4b63064a914910e9bc504b0da141dd01a83d3dfd8f414e0d1bbb0f9070fc3689ff5133b0f100c05168ebddc0439747a5462de1ee85f597e2d364ef7e9d685674cacf84d5085b80b8cd94c689d32b33d6679c3959a6fbf57512484f1600d9e5c953b96f19a8a7d84d39860bc471328c8d01195e370983777a373b54c9a01c4b64754c0ce157823840485953cdb4fd4ad4d6f1ad92d32a66567bfcda9b8113317541fffae4ea1cf11459e254204a84e2f3c26a7cac6b98010f333232e1189a098ee155b3c529631d10c1f6401aa1178fd608d4dce079e50e2a73325271dfa78e712fb0a505e5cd98e8fb4922c91b65730f862cba41932522fe6e867b566a1b7565910ef81d0a2a70148c0b673ad4d7ae3ce97ac7acfc6c12ab60d4f820dd4c02e3fe0a332ae7c58b15ad9c9bfdb09e98f1199090d28cb29245fe183897312843e46951d7ad132c3f08f0bf031e438953cd57519a00141bcf4fdb9f74d1b965eeb055963369e8586426f2280b4cfef5f0118f3fb25b241e37ac17549f95ae1420af1d4afcfed63bc84ea317c71e8f9e3917977521de238acf00bc476c0fd4e3c397c89328a74d53609aa219bbd130db76bffd333fe17f7f6cff7478f7857c07dc21e1c2d06741b1aee1b5c7205ded529b0b61b23facc890a4b7e64763bdbe13b15722251c1680ac02ec5f3f34dd28ec3e9267d6db148d0de94c60dc81425e34eebec3991fb3fff80c8b3c24bcf47609fbb46f228b91dfe90b4ec7fe383a64d6b32dc4de42f5238e5ff345a88e2e54c7db26a96ab462a990752b2ec", "6379c84df32c5722cff44fac37e32bf9521a4ec8aad89883883ad02b8c227c968662f6269f92521b1ba949dbcf6c05c943116e382e81a44f11e8daf7a1538cc9835a7c7a74aeb60832defc6d0d0f97d4434eff93939d1b82fc4c6a7685b9d3f95b11a59a3e0473058fc4c87a948a8a8a0fb1143106573d6a3b8e8954e5061322e9607cbaa0373ddd22531dc0c1afdd4e019b2e1b11349625a581654d06ee023f5f979b5be518885fe09fe055945b3a05b06f6bc4201c5aa2e85d3a6c6394b439c1f80efdcbd338f1590d21f260ce8ba35deb8f4ea8e92fb85ff1c4834954a83a839d8d9524011c63f12b0eacd5a3ee8b1c8eff829bcb0bd08d844e11c226e2a17870c8ba321a42c597cbeff8f65d6712d212e38f4ee02a5ca020eec196f5f893828e4607184c18b02e08abc1f682d7bde60cd975729d549669441ff59955cf725dcac1d1efbdcda9ce2df8d6ce0e4e1e7a5d960db4d91448c1b338e4d1eea9e31e01154eabc790afcb1433a980b2f93174dcee6808233fd9168d5cd5123958aed2876bba1224238bdd35f1c99997ea1f2655b84cabeaa30a43adfdacb88446d4cc5f99405cd029d9dfdad244451bd1421f45198fea33001fa13c20305a51adf44937d40dfbc64d464a903c93e0904c8ac1b971c28e9e1f8309f74c63d53533181897cfc386176664c238756d81f6345a5708b1337f52604af04770b7fd23abfa7b6da25ebbf8799626e6d7b7e5c1c1037793e68f1ceb3a92d3b5b54c94e03592fa99390148ec1e774747aba39ab413340aa5f07aca1f09fe8847be122fa53e8d954f5f293a15ab77bef210acbd2600c12a95549c1b97d0f122331bb4aaaaefa8bb5781e61bf89807aee7449642d2f7c0f250c1552b28fe401e4d7efb376ff4d9c89a422296f8ae6d2b1015744691373a8208e7b24c052ca12ac45760ccd31709fdf66d846d042fb0d61d2b219b7aad1cf3353941111fdea15193a029e038d5b3bfcbc93ce547810a9e723cdd132b77620fe816c3e5baf1f548217f150d41c16a4c6b64c65366e571a8e52e30180d4668d1c1f67ed239a40b169f55e5669c0555057dce341cc1f9853aea7d49e86e0d6b59a47d29ced062312d695b708f8eb4b2ec7967aca5069181d41d02617b9c88c82d5536c5bbcbaec93b5d4e91118e87d2b063faf439bcd20568702ded6af9afd28bbedc445f12923e97ce9991c15400723f4fc6265163456416d32d8cb9f81f07b18d26b32bd5b2c8dedadd00668c7dcc9e5b56a603f75a0ea8c247b14ea123111d9df7c73d31fa130baa05f57d20ed9a7bc7afa239583726e1ad0d9debd6a6ece286f6ffe631024130f1f289561c23cef1c775ad941088f300203ef9680556f486eaf62a915c07cc4885ba4b2ceb27e3984fb46d008786162d95b524139fe682b94bd163505af0bd8486195dcab553ec0892f5d08f38e113aa59377e12acf2ae402d3a9520b9c36d944799c00d4d3ddf382592325ade99c2857f462498cd5c4698b9a4bd6813a6fa7fed677b5db81299006b06ab09b32aeacd16156dce5282b3e7da70bc42cb614f291a2110f14c6f7578f29c7ed8efbeb16496ea8ef6feb5567a7d117eb7e38cbb8322f0943e983619b1e4f636777221966fe06b086c2d73497866e5f97ba2bfff71cf2073da133d76aabafb2fc1de042491e3efa950a899018f93fb4df55e91cf1021da8b518af7c4f5269aa1f679e8ea816f48b8c9157d0f4ffec5e06d43784ea1102cc6a43dd30e313602363ebe5ac53933ede33c74a26e9d81a4bf3540e20cbebc98a20ece1bd4dafd1aea7bc0215e54cd72f663b7d030e509d26954a9a71281671ec0f53eab9af34f78789f7be328193ab820f27d2c54ecb747f3287ecd68b123e1147d5b02ff06c73db3266a684311fe0fc9eb4720c0be89cb058831261704bb9720e3a30ca6bcaaa160a4d2f69fea0a02a950976ebaa31f7aab6ff167687c5196eb76791c56964306427ef027c1a859e602738746577ca625c17b7377403aee9e736fc0af041a9754fccb911c81d94e4d5e21e300e9dc5550c9462ae25cad61b450699c38e686f54f0178ed297093d036b406ab9597aca47014ce9fb92f012bc2d5", "-54f0e0fa76ca7514a37943f61e527c67d100194dce060590e794f4e9a4ce65218b742a36e2cebf59a5923c3946bb6f155ce54340412564030cf7f0a2d31301f89f8681c51c2089a8f0962a5b4cf8b090279d313d979693428851aaca8678245ffa821c94f9410ea8afa541525b2a911192dde7d5f4ea4ac4a4af1aba878172be0569fe7aa174fe388a10fd972122a602a72bdca7dd867b25c7950671d19e2e28dc702777dd511c89113ad72079ca2df158d2cb0d5ce8f819c99cddfd038eadb29e4d1bc3a6ed7fd3cce3acbf8f840b9ebfebaf2fece1215656d496606d954c282e1d2d3ab8b8c952f97f8047155d8477ae718646bf3fae94626536c04a7cc7e3c3fff6a57cf63611e955bcef7206a9f1bc442c8bedbd264b8346cf707360277c5fbf959478b062f17f8227388daf94bac57ec5548e442bd2d555c34f9b38528221352c830c1bfad6559855b4379f8c249cd8a5238240b708b3e3862d8e87fa9e46aacd04962ef3144d3ab5c4344d1f392ebec1a3fe96dd7b2c6b84ab4492a30c309ed5a94bf99e8b07b55b87ea2e7d956a3c3deb39e646a2296d26dddbae57bffefaf4e8dc5fcb08228958d447f3c5b56b88fd88432dd96d3ce8b4f19c90cfbe75a65244282eace0db18608286db5f92896135501517df38486f3dd614cc537b3f909e4b2a99e51154d9b7e59009d4e13e7aad62fcf2557732834209ee10a5653f40f3925af81bbe24097bbd14a36ef922b4fc0897dedd44009f33bedde9d03e91c985ac291e8f5675a5cc026ae1e726d60e3e2b88160b48b454a004324074f3fb86ccab75f3cec7c4e18b51673a7bcd6b8bd50fcfb0eea2233d60010496f6f2481b5ba908b47dbb18d5c0e7c9184f38587faccb7e64d8cb45c5f6795f5e4f99f2a8a5a3d2d35348dac08a61f7269a97bdfbb0822da660a4f5abe61b6663e27f77b5ce190d7158fea7e1bcf686214fd1453ff82f4e4e2498b8ae0abb57027af757f0ab07f116ecc101026152e97bd8b7dd1a98c2ccf25727f2ab391307c9528a155bda3a2d1f69db3fea631168f52cbc5f86d38d1d1a91478feb7e08d45b0ca3599fe29f86f180eef1a1d979bb297c0d4e12a70f9d4e5b2d114db9b3f96dc7262faab988b3be67067fbae5aa4fd3c0cb59e81bc133e4eaee967522ed4a1ce9965f51a5c80138e56285895ec87689f1bf003cab59e2244ecfc7340d5fe7a2dae985bf0e11e8f437de5f1240b33c259667f6b9295482bd42b0640239485232cf6f9a290df2eaf07424881e812167b811479cbd3f2fb4fe94cfd817842d7300e5453610b0d9b1b917f96aab04d2d4ffa8e90b7fc2c5543c4b2ea609e52b49fc4c119c98d7f1ff25f6d9fc1e98ddd1af6563bd21c3902f8ee2f1f40803ee13cca8a91454275faea7d5c8ce139c28c2bd9cebef4d6208ca3f78707265daf916029f49c66f192835a2d9ab1fe42cb1b4ad7cb65df1abfa5c9abe7793140cd613e0e2fe5dac74ab61500d1ba45c3678aa5382f5b017cb91bf0f0b2fa27fb17e04f1c1a8830b8982128117fdcb1ab660a99ee5731f9183211ff40d33b0b62d0fcfb9e7357099cf9c61d0d22963c38032273c6247ccc0894fdd8ada320f06e0366d5022ead713811d7775f2c677cb6314a9b0946855367efdd1d333a004dcd637cd84a6407b276e86d576cfb0578d31703db2a66e0304e9ed573c6345c4dfbe0c371e7a291c047535ad4b378634e6cff8eb320d8b45f4a4d694e3e7a841f7ad6e13957aef3c9266d867c88cf7325281912b7dbbc904710ddbd205fda6dd69670be6e63304be2b66400cc3205be0433ac74e6e0e83045061cfe9e92074ee0d6ebbe70403db8c78edcefc75037f2047b7fab2b5c4a365ab08666189bd52b7d2ea10d5a2c19582511afc613d83f65f2f8184a3e75026bf63954520be26a5011cead5b72ec4da1f0c618d20d43aab7b73f9d995d3cf7d8765d1050d193342485158b72c86d6d2dd1c9510ef6666e098ebc84579e60992c4341e98442cc11a71e8057a19fe327a992c515a51370e19f25fcfce26661f567309c6fd09c08c8b9c826946fcdd41488b37677e1df46c1b02d4af41ea3bd7d576878cda89c0bc2c8caec9b5a2cf76ff9c2054669c9de7e17f7a214ec3130825eaa51ac397acb276a8afe4a0dda62cf8be871386d06b75cff5083e92d22800f9f3bc436863037f0b053148bd6355e44b7ca8479d260d48c950cec5e2c087d9b68bb063cd139deb85751359d9d585f3b87970d889374a80be78af0776843b6b2b4e655fdf12e6389f3b2d8a4127b897fabcad9be705fef8c8b5352a5bd3505dced60d239837bd64d77fb504c100c7f1834f9c96b96260b13bfa8768805f104381dfb97435152d34495650afecbc6cbd6897d8270a72087a4244a1f6c5378b9eea8cd8e725ece11c2f64d582f89cbec460edd27a07195197edf98b591f501f737920d5592fb7afd39c9c1a9ea6c17562c0384abb91c453974658a9a5bffd147fe28370b25fc5c220b5420675d31b5bc92ddc76a6eecf142dc6de6cea4a63a09a64526fdaeffd5339e4c3f6551910712dfd221c157f4f6f9768c773d20efcbd15c8e86d644d210e1ca78240df6a41aaab664c379ea5a595cb63972025182397811fc03f2f6300244e85818e05415af2601506a103a1ffb6fe34775e71bd860efbe787a9b793c78b3b2674dd01124664b14d54938ca8fe1709cec1965757e890bb87ef50bfc0a4d99cad6f8d2d1fc75e593feee78cd0a5bcaddf2db0d3b8103a540114ff7d44100b2762db8e05df9c1c764d8fbf5b2e0d2eb6c64fd7dc1a1620fc2146453787e22746e92be594678e7891fd09576194332a7f5d6960e2f79ba9e1198cc973e8586f7a7563e883ffc7e6ec888f10d4fcbb25f08645f847dbdcd17de86c5fcad000006278b3a060af5031ad055c8cff3906682f941ec38980aade7a39ee446b62eb38f436f3045ce257e667a2fa8350a371a9e02fb86e3cfafb6ac03609fd1d6e80faad65ce3437dc7feb91b77c4d7fe990c632a733f0be1d0a82f217e59f0d33aab4cb588ae1191efe794f4c61a5278960a7d145d8e751594921c1042c744c65f7624266f69d071c9d05bf2c36380b567e5f277d8bda0bd2f6da30584512b20ca604ced602b3d6d8975712bb06be9d67a638385d74e681d3cc6822d27479538bdeefad818f01c6aba62f6978a21070c88f44619e0ecaf16ca1d581ba53bcc7ef6d24cb0c28b49c05903dfc751ccfdc2601fc0eb786b25e30ed12d4c4083eb2fd06353e4c74755ea93fafc3132c6eb4b91fdc8de8480dd93c86e8de0591cca34abb460599aea2a0876571f92a4c8535b67e5e2d3701a05d95d7155f43b0a1f689f9c433191338d61eb8fd2e9c843ee2d2e77d0754c8e5508432c0bc446dff796f268923cd26f76cc445364485c38cc174c7b3a63752d629c505d505fa579b6d96e1eb310fbeeb89e4fcfc99433d17309eb1672ba1b2e37af838607c73aa0fe03c16264fb2a52b7f79bdd1c5f6dc28b06897e7c9c503239a81ebc0327dccdbc6a61773be40c1c9a585a5873d90d4efbf4d02d37e7effabbe8d2d47870e8de8992b2bb452233fa6446cd4f50ba324d775a60c610c627f8c70f39d45f46d3707c0e870b798788a04c64413053c941e41c4435ed8fd06aa19fe7a34eb8cbb6a7f2171ebf2ce83e28018451a54fad08470de93193d9eed75850c57adf7210e9243b75bc0002964d140dae37fe12a2608545d91982206e6a18d7a5a3cb78ddcf874474758b7dbaaae354a82ca62fc609acd8bd00f152d25600f1f1c3676338c8d81943d98ec09db381117687fae8e388bea48b991a25bd1e063248be0589a906307e978e87daf059fb3b97ba08f5f5fd7aca4b28f282911b1c0279ec2fe32a8fb07776da1cea8351293d6d086019a59e2962a49bf03ec95eba64c9bd1ae06e891c80f347e695a8e029d0801cacc4db2f2ebb799f875c5a8b27eeff12a771c00cb4470d5c978d65c3d420c85c653a6200ef9d7eff36d65a15300c617b1ce23b2c1c0f0e51f0eaa2ddd3dbf840131b060074d842091f6947524f26ee43d2a11f5137dbb4e9208fe7b2472e47ba0eb16001e3a506c708b7b7aeb7aa24d19a1a30de34c026c4c1eb0b12ffe3c07cbe7659d0a6417a36b8325a981470607fee59afe0a6e79d53c0b6a85dcf172fa85a068a128d1ee51c125c7b3c9b44720f7baa34592745bcabd09b65c", .Okay}, + {.Mul, "e9c7409d088359c4d0ef9819fcb8701703f19d25fd6e30dfb9651b237d33a00985a0e99a54de52306be8de5af331fd267cde3335db3b0dff33c24184ecc5dce2060433e1394439450ca9cc313ec1b3b0855e7a53773b17bb7ee11d536b972cf34c10fe34b1a88c8a62801911bc05a3b22c7339687fa0b5ed2a54388bc4840ce9b0a7726bccfb75dfce943d2ca72a1784f5d85c9aecfef76992e81dc4be2c3961f0187dcac30765a2b367e774985420d89c85ccdfc96bdf407e82d8f5fce4780e33810ad369e29a581d60d8234cd39493fbee8a120d3bee4944a50130da62beaa08182ace6a13774315305be173073d7eae9f67c63266d2a04b0677131297da50e3e950791035564a4e5321eed73454e971234e0f841f098194fe5edb001f4487f228cc41fe5235af24a9b297593b414afa49b921e1dcdd31f1f5688ecbbae349dc79167015d680e77da953bda03b00b1df6a69a88a0f3a6f61b1d55bf5274792350bb90b207e61edf6458bd90e22729af2bd4a3e41894401fe09625983a25a3279ab0c7cf8ecad42850f4b40d5b4f127e19a2f4903dc03b1852d7d5c6960e0d3b9b710aff6d914404326e0321c04257a49ff2329cc72c56a29c6ee5cb5adf05a314891a46173487748e6bf7c62b32e9185a62a88d350ac4ed6cab06bd6006ebdda42213b27832b62b02c576b1ddaa0c73713fc804e4c0bf28c603057568b2c7a690bb468858e896d1ba6dd6b027a9a3cc62e553967fe5b096563defb13449c711485538660d1dbffe83443ef099b96d145e8cbd2d32993c93f0f8cd59124c83419e2bdec3e552068546cd2733bd6d6286d4f2c251fa88d6ace2e845801a33692f7ca008a912fbb5a6bb7503b62d40231c06cea6ca85df9f9e147ab9eb1b464bd86bd912e1b30497ceb726fb50c1539fdc14bae085f7f70b1a9fef580be91fec7a0172368c4739393e482d0274105676a3b609fa2bd5020c6096552ff6e65091f5e07a57d4556602209dfec50d6bf14fa0dd9425b95ef7780f91c38ec2d30a9b0e20a911ae75b0102aed2d96a94bd95abcd84a4dffd909eea9b3abfb6d6e120114242d01502164bc2a087b3fa462bb55957ff23969f85bb35f70827b752af3fd0632975aeb18fc26ae19e2957978a4cc998b5871767bc5e1bc065733af2d0ad227fea18979b56461fef0fbee9acb4a1cade2d0b6b0dacca8d587f0ae79de904b744c81859a5c45f38ed5639b0b0c8e370074ad07f3d7ecfa3b8c58797f23e10b5f96a17169b13e571a45fa1fa00d9cc2babae26038da7cb908ffba33e1a56f36bae67282fe4c5ed973c87a1eec1804b49e6feeb7c802e5e7fa11554accbcb5424486c19ab75c3670a516bde993f7ac476b51c5fb13fcf078757cdd487d376f890877e08405a9f0e3b1485b98379ce0734c969bc3b9662a183440df20c1b6cf4764bcd6851a5e4d8f58e51f771f08fc14b49d2ef22120f0300c6ea072adf3b1f452ac0f8cc32c5f454b599bbefbeb089dfd5972125749c6fa4f7801573bb69c87ce1932ae38a1aa7442269749152b3207d7395dffef0757882d7c8d0a3ddc068846d8f0f561203c1fbc79872abc6dd8af0024d1701b7bb218fa43e05f15afdb58ca633a2ea1a3b39261d7c163eec4d68ad205fdb12c9bf0819684b4d6c661c6b2706f4832697f3187ec2b07c6c1865f8bf6a520d67ea3fdd8958d8b2cc96a7e9f5fb4bcbb5f7fe9827a8647cca14c5780bb6779a9d04d0f3503f043c7860724acd55b644782a4e69a44690e72a2811896e279947ebf42698f50e7bcf04ddd8d221dae2044f050a63ed6f408519e7be1a4f5d1157ddafc4268604a6a28eb94276ea0f0a0af1536e3660816bd4360f352e3b5f8511ece7552960e775f2c708b2e410f1c141d0a373cca215e22b9156f861d373c3802bd61959eeca6c5b9aad69c6abc0cecc27cad86fbe66d9dc0876c8c8aff943bcbef9fcc50789df1f98a32caa5b47ca75f1b7dfef99b2603666a5532b91dcf9a6f07d957c1adb197345414fc7a168b7b135683aa9f7f7672062b27330745425d09d84083fdf334953bd838d308b7086395c6093c04cc9c3b00b3859b7c5d7ccc81186c9db8b347d992f", "97b2ee8fefc4dccd0fab4ea3ecd6085ed2bb3274877db7a35b869b009d37e9eac87ba890aa974e6aa8d11680353b2bff1b41822cf6412ec19a45da08bd447a374d5cd29c646a0431df450d3f5f1f9471d3a34cee64edeae54840afcbaf78ad4bfb2740cfbcab8f5806211201b55da69b3105d06cfdd15b77c14114b7cf8880639c7f23c27326b6c912a03e068786a2a77f9eb428f8e9d8038d346cb5264504bc55704008855099e4c1685c06f672322949c7cdc39c863971adf437feeb26c5c7eaf4acea750cac6ff7b3e1ce41f71cbb968ed7afa9bcec71fc58ab47c36bf2608134256345b04fa452f11173565bfd0759571f4a7731adc6370f6e1ae753281da0c796750cd725200ad6da99f3b235d5ea14cdca3783673eb8714201523b091dcc5aea140854700dbd920a97b065e9fe36e3f41bfabda71bd095ce9a1c7d4be974aa9f812e6c95eae4681455a0cd35b2440a20139c4f218aaaa3e002561131a282f27744ce32d4a1bd08842c8bd0d2a0a22c378f32acda0b0e1a56c3aab963c1abe4dd153c571845c7de1a41e3f43d7500f6a2d924ff126cef08a6177cc45cabea01bdb9f6d1fa22911342ee28a3972755f33db514f2c5a4f8e53b57512d3240de0e08b42e408a784b9d92ed840f50fad0b7f4b3c714dccfe77b0374b6fd4a880ff3d20c1a813be0009b12a885d709a56d0b35d00b6deed144bffd166ac44569223485eff865aa90da82d5cbec90e7038bf6b66579b2104f7df78daa839ee184b2ef057a189317d4278cf8a84d0ca99110efa04bc5413b3714c65b7b149e9e7844cb711112b4f1131c694631ea29dc9d2aade10b30474f651198b8c7a35d455d7559fdc2ada097453832f3e7c5c7bb596fc0e3fa7e8a8fe1b1b4e574c9d7359aa9fd1553a6b3564836b1bebbda65f740a37e0b616f84288e2da93f230735dbcfa264f60427aacc23c4f796411e2b3866dd70e2770f9b9a96c5397d3a57222f804b4fa19d7f352a162f4398eab79b5848514f339aca955e2c8e3cb52a07af75879254ae027288906ede87b7ea73b741f3d9eadd75253e3ec3cf2d63a33510b1ff5fcc11b57de6a5250bdd2fc3a9cd5e762d7ac08bf32b240ab9be77525b8f3fe88a4c8a45cb20a4ac346b31bdae3e82d96876043ef222ced298daf64615a4414a75540437f201dc2e4196d6e12d2585e88dd655da12ba7b2b4e6573ff5fb295df467c9a5f2108d0bb2b023444a41cdbba2dca68c77f4542fb0b46bdb8abc8fcfa0c7eb4edd1a637817dc393a10bcbde420264a57b389493a155a90d6b9769fe8821d5a8add34416b3dd927566fd0efee27060e303b92925439af23f114b263f04687897293cf5295a0c9cf38709d91feaf5e954aaaf10b600a1757256ed98ab076e0493ff0b50856e05a66ec5a336b590c45db591624cd996d1b6d8c024ddd4444fd3953323077f6d15a41f21949a928514cef49a789f459108a3e593fd017f15a6f0de34fb41173d41d066e6b2933076709b0968c8f2383f8be780777aa04b8a8ef3811209b020599cc03d8770fda27621da91719669f273a3681c4642f100dd2491c291a1af96154d96af3e447afe6c2167e1731493f343f3c8e7c761ed2f1dc8e478fe7b566b1b54b21f3c8ed21f1a7f328968735e04cdb82c515e34cbbdff3f45bda613fe2e0e5e8d2a6e7e0d3f5b7e774f05028efbe6a3c0a7ec25fe11f1416c7faca989fd745eaf3d03f223e78441ca76d7d4ba4c7d956e41b4eed5550996da698b1bba203bd4f3860ca9769c3fc595c00f1eb78b9821fee86971c965a4e211cc616cd73537aefefe9f823ca3cec2fcae723ff849fe387301631163cc46e06f7476bbf8b6d7d6f5ac4fc8121fe1b47eef7b705269894fd2eca84ea8a43172c3892e76fdd719e86a67157ce4c9ad58f2653cd2beed66cb046260decda4058be0432f13fae7dd1430c608c11c4efe458252c603b337dbf64c9bc768454803cd8cb077458f97e7aefe761a2563490b3d56e7159d154e046989fa473551110bcfc4ec901229abaf57c932894de67a0f3e8fb91f1fdec81428156394c8dd4ebef9c3f28c59f26f6a8993b4c86b5605f5bafb124fda16bf13f63ef182", "8a87ed823c89466bf27caba07badd0c69c680a19e5da41e0adc13462c27647942827d6efcbbb5a0cb8b36112a45e67f170bfbc3e7e39cfeb58546e78878495cd06cbd0b73ddf85764cde5844d5dda4a8b1b1e9a91c5aa07d6672cca7470d8147f8aeed486f77ef8df1e3e7e89ec146279d0f4c8a36de422477a733b7839558e92aa9381718a306de895e70a0e0f06c7dadd3a877df7e0159aa58447f6d7b6029764ab77bac4de7e0aa2630086d50fb4de7ff2c2a003757f7e45cc969d07c44e77cb17304abc413fd253967ba16195420a83cbc48a7297ad38628ac23030bb7eef7f0ae9c3d41df017ee0ded92061eba7e4ce1e789261d80ffd556a48b3593cc315e44e132da5d07132ea297e5147e746084730d7117290da1dcdb2f25e5fd40459fcc6ebbbb90b2cd9002bb5a92926d8740426cddf9553a53c64d439ffa54caea83b7fa991f0d2e8329aa3537352fed3fdaa0e14261bc1ecac92e033a117e61e36ecd2c35eb1cc1104874d72754a634efb92b364bf791a7227d1a803711588557a8c04620f85655e2e4d66b3352456747fc76361759a23d9316e9099f64763d6976b32a308da48c657a9b96845f17b666f23c6749628d0a451f5a7fa294b46092e00fb188c03fbb7b3e88cd51027d82314405a133a479180b1f769db65a1fa03e6daff3bb8992ef8362f024d921eb68afe5906d7e95ce299b0292f925d0eea6179a54f0a894b52c0d57968a2bfd48267f1dbd505ac3faa53aa84faa28ab20b3e48f5d9e165e252bd58b83ae27834fd30df17f879edf65eebbcbfff41516278a192a95d295391fca8dfa7460a922cd7c32e22718ffad7d74d3417aa7c19e259bd28b92284d8c259e72faec96424a38bdab3dbae2f0bf2a32bf4956bdb9138fd9e3f9956d93f4eeec56f93f9ea6f1fcd944661abde8e06cfcbabc488d79a42513eb160988536854eeed5c1fb8a3576f847732cff6549745aef773e28ec2aa62b8b054126ade5ff337077bd1226f55a3d5fb9f5d4da529f106832a1d758fbecadd18dc67194e8a2693ff60c3f456b0c591a53e68d0c1d01884d82a9e03335cfa1c62861a7934efa7d0b95b7b2ba4caf8750414e4ff418e0d0a3c8a946636b6e0b21c423d3c5bdbe659d0d195e8ce9188d3528a9852cbd9483aab3831c3bcc55053db48e06d54365766bbcce415ac9db6e3204b261eebf16d11a62ebbe0b0cac11d74cc59a4c31a21247430e1fa26432df9b8c9aee1aaaf17c23abbebf0a38251c4b991c8f36a7bcc5ee5f8eb359afa3192df00a2cc3da36dfea89f8d9b5fb7b650f0bc47f9ab3e15d498b9d2cb4f15561e214edc6333d1fbecb3cd32d9dab50dc86d135b11bf9695e9b0f4598dd4b2321c9b4cb07ed4184293d8cefd75015662c5dec2679102b090c7f0d0e01d65c6819693122a925baf0233155229d7060cfa1ee8d25092e045d9ac82f3ef7f536b846a36d1f792b3cb7253035ba58953f7e85d6aace1563c4e2e0cbd30d6e84af85cc8e7929a714ce460656136a9a142b821eb13ce91a885e291f166adb33fdd0ea956762d5abb38f38634b0304caf6c1d35e2fd89443b481fb8ca26f11747cc37e7897675b1ec077018140e1ec7c0fadf7af0acc69ab4a6720575883121c1dc447b5e5ee4dce5ef3186069d1ceaeeb55bd13dba4cc720c43b9dff920b5c3b512f1fbefb6b7162f5d57e4df113eeae8cd9c072cb78fe92a67ab52a4880681716bcd413673dc04a5b846f2312ff897874df5034bd916d4429176cf9c9d1ecdc2506b38ede772d01f665dc8cca45ac98bc4ec79c337b0f6e8aa05aeb4bae4cf96e771935cd7afc886300ac668da0f319f72197d4b62721e2fbd721084a480c2c366ab4cc69c7da19fb3aa8eb098ab109780d7157886f191dfe45be4bf9e092154279fa04b592fe627d6f5e93e48c2529e2315018cf8a1ca14cf79bedae892a4f52172e7cdc9eef6caa6bab94f98c142863d8b545608341afbbc30ea3382357ce256c9cf9588af0003a93eae2e0fb062ee7bb25156a1c39544a5b9003f77fc188b68ab1226124974f3389bf7752119c4709379fddf96db8b030a264fc46a16d2b8c55d4c6e09119decb6b0c7ff94dd634ab2b20974a02b93b36c14301153410393d4b41cd103d104457c2ec85556e4b6d4ebbfbe5a037c15593a04c2228865f0b2a033d5d0b89520f8c22d58736eca29a49147095abd3ad816c0daad95f5ca45f978b9a35c5d74da10bcd8b86a92efa73edd5af4088c4da69f6dff5b32c62d30639622fe51f2a39220d8d05ef16e131f77a9e2b40f4af2c51d1b1cbc79ffed49e681222ec05621c846219feb391af15bc2902e948b7a9a52daca2ea6aa2d23b77b782af33c95e2feb5c9142db2ee11b0dd76712ed2d67e1451edf48de69976bbe40bb948e1ce8bd4df1e3356c60e1893770dd9600b01e53b9380fe1cf0ac341b36bc79e10d809dd14e30f85222d432611fa8ea6444f147bb4305187e6150cf43091346b4d25873cc45a8c56847aafed2433e420dd82df338eaecdde161976a1376fbf1f7704cba01a5763d4c03d1b96033dd78c50c83a45c85bfae852f9ec14bb092307426e0f2125644d34dfc984e7d70dbdda27ebc8535de5bec9593c650128844e24bc5c458866d9e1ec4c5748b2d3b55942450441019b2dbfc0a0234aafe31565fe231a237169d392fdc5478a21e92d995bd56f95ffa66a656b05fb7cacb7abf4386ee08b024b92ba5a1f136b5997ce3e317cb8c163531ed8acbe2813c3ca9224b053cacbd19f8ca983b19f496ad18241cad68f85cd606a26abc8609324ffa7c5ed332ea8ffc62345a194c9eebb7131bafff63a9ac93245a0ec12eab1d9863ee80f6870e6a5e9ed2bf7c68f92608780ff6cf7b288fa15c2d4785d5bbf239d25dec88cec94d0442c10451b2c5e73d6883d1e1c5026a65a362297b054af127709ad7d51fcf8bcd7d1d229736d99fd7741d638270ac6fc3fbb177632ef20157123d76fb5a47e97307d28f65151691f08eed1e7854d3704f0f39fbbd12b20b4166bfef23661b6524abb358fe6f78ecde791c3cbd1948b540be1bb8ba50a04b35cc51714c67edaffb410092af846d18539706243113444349e65564b38d9a3588e58a41db860d2287d0b0eecb5a7885b600317a4743180c5cce1145a36d64fd14fb8118fb55e8f678642d023272eaa125eb365ec0a5195266b46568f245633843c67cfbf002b340ddd836aa72ff6fca100d95eda5eccd334945e42b02aa076e08fb98bcfc9acf9a2811a8dbeea0177947607a497cbe238b61e6f395700471b40921b20045baa4b8ac5d6d9f1da3368375c60dd38c5fd62b646c16f31fe6af610b65994f614e517d673a89a72c6db00befc9d9af573a422ff65a14626c0e13a15ac00066a0ceb936b07cd8f2f9838b8622a8ff3c1e3fa1ad694c3833a9fc53394b8f91c84b11e2a5816dbc641bb884dd6e5065f2097a48e12077113ddcf1d7073ac0bdfbf942251016243576822a06291ec1ab920b94466e5606dbfdcf1b338695ee69a4332728b3b0cd15f8dcc90d816fe28e9f9c9c8bb5baa7a0951639abaec44d3b66086186495988a71ca32ffd8f6fb787ddc3e662ba0a8dfb5d842af9a7b39a8b0470d7a1b16dc68ab0a9c6c561e1628b3dd9253cc4f1e9d94c4abadebde9977bbe26d7a0d32739d20f447de7a5c624c746814890f9ff428e11d9b862bd1366c07edd39859fa00b3480166fdfd8cf8bc3baa62280e0a9bcc2a61ff9c693927a5d0f0db688e38cbe7a301af7795aac58dc309ed6cd1a4f7c89a035ed60a8cad4865f2f33f42daaba717b33f599583b1304a8e64fd1a68feba66f453a9cff28bb89094211ad1bdb2062d3eaa3c4294446b931da9edda5b39de014c5d534c5b923540313fbd4121c3a955d58c9ca0d572f39c43e85054cdf464fd66d63fce1aeb02d53ade9eba3c5b869b1e7924da731e8d4c89c160e0f0effc53906c3142bcd383c0d2658c7880cb0de7cecbbf9d9ac81a26e186916d7cbe9b7d05a7a39dab7ccff082c66e660bde1b820378db07d78b0eb3c2096eac3350705f1efe433e740ab014429e44339f73d5d600ffc01e7088209b77b15cc2a541d233c91fd879247a9f329f6fe92e8fcb6cb33a141b7b25580fb4c809122c30757132adab97b041a1b4d593fdf8ed17e99c1abce000e205c4650c72f33fbcd8c25aee1783a98f0ccb60d28e8e234fd6036285f08de", .Okay}, + {.Mul, "a722280cd9e8c7a7ae6714d21a075fae3da31a21a825352c609941085059465049ad3bec6c22946aeb2b7c2471ad3433d96aafc4248f7a58025da3a233ea2642d184049391399c5711cbf0e5a45e3ebe1b09784b010b3202045267f0ed5cee74928151c1d504cbf9c44b3c2d3a60a48debbc1e700801ba5f4063a7bdac7e4041c1a430b51b5e71d4e4a1f0cd5b95272c5fc3459bf6c58bcaac1acb12c799187c5636fdcead389e92824769e8420aa7db46184eab30272adde8f6f37b92235d04f75396d4ba09431438a8d3e4764850cbaf25566894745ed3e4dfd2ac62cbd703f54330cf1d92aff7e6c61d51f2ccee1762297c3a4382117f472a4335b3400bfec2813bfb1a5b2559f0eecd5be4a1b5b2c8470a1755719478428caa54b40d92fff8a3cd81bdb2883439b0b2d48103a0d00d478cb4436af29356866c5c3ce08c35a2f7b4ac61db2bbb35d82364919fd2d8644117fd563fbdcf6b3817749b4666532ea1c634980c5dbb905564d00f828129f38c056de2b5e6cd9268c6f276183a108fd2c0668e64764666e3b2f45f410cb50dd5b8433413ec397225e578b2caaff167a225ef3bc14bb4effc56371a61fa669d530d5b8781d4837698e0d7e5e2aba641217ee6f4965911f78c6d6d9be574420f5de2d20e22bc5c5f4afa702e35076735c0fa1ee1fd8a88a3bd0aca1af4258ecccfa2c44476563d560e7db3779a7157f4c9e8b3995de2a1529e02e7865ce8af49edf6e4c9df293809ae6e67181ecccb38cd9da7f887ab0ac6cc9952c6e5fec47a2d276677f8ccc957183ee87a0d7f8e45a9af910135ed9a94d7da28b04f1ee894c552b7f4b5a4ad8c1a33d8712e47c3e7c86edc53b5542c396e53df363be29e72c4f777a07c55a4d1dc71a4b0f5aa7b7d43da7c03b04d660ffc2d57e17189ace687a93566abb42aa379b2e0891df11c6113c99f004de61a7e39778e0f9fce200a0bc13a8d6affbb06458c1b2b66d35c6c3935d6a43b9dcb4ba01072d25d51443dfac5756ae4224d35ab59c07ebf2a603f7a597575867cfcbd5a1cfdf392c2948a5ba99f02e83def6d3821f55e3a30d915ba51a12e1edb100e0651bdc373123e231b022337b5842082df77b62ea64880af3f998729ac80539d2b8614068ae4e0cd930db5de0bd17024dedaa5bffa3a308f5506a76720e91b284f51519c556627511e8db8ce663adc83f3c03b04971c1b5381f7c77f60752abf070f4cf5f65322aa8341874d469c29ebafaaf94af723953959f371632d468f0456f671eceb64b6ed0004ada5b287b7c58f5a4ebfc45c04d6af3fccd99525fdb12124b6ea420bda15ac812fc8867facdb1e8784a7b1e4bc7e19534b29e68e22b94798969fedea5190d679a1b0438f78a55984da3fc8e635dd20638d78d5c31cd2caf99536ac6e4e5f527aca65450543e3733f474a411c8c335af673965982f586f174baebb0b0f82df1ddb2142110d6605fc0aa94148703588ef2ba89c5d3b557d832afd9e44c125557297cb2c7f3664e4bda42bf968adb61dc714f853c3fddc81fdbc09889450c5451bff90bd364ebf9ff2bd5847c9330950120a96d78a86f22251a1966208d108ef9e64da01558747e4afa9c6fa2816776592fc31688f36a2e89e8a4397bcb48c2914aea0b2c00e0d4895bb8b2f42e510bdbf717a57f1b381373668274e40e5edfbbfcceead4f1f085df3bf665850f075f3ac60f6d71fa3eba4476f96d711843241efd3be866a75493aa4487673f056876478918802662950d7b40e4b165c724febca648cbb246930dde44ce23ca7ad877dc1bac09d0fcefd7d011d8c716c72a33c6fcc3dfbd15e1cdb87828556a446739a18d390572923c13add2fb8b8dd94c6d55c3e0d53d417d1bc738a2d144325c2039f87b2da20f13344c12cdc6a947bcc4a0b1ad054bbbaf9fe152c9b408d5925e8bb833c7de50c8d05b728eea71019e624ee13f2bdeda5a4e6adfd9fe32a297095ac8da56d0d1e1f6cb39e7017d46a50fc838dd268cb125eae5aa4c1836d5ffa201f1051ebc9d83f471da08ff2805d9518ab939c0dd3c3ca497aec21f34cbd75a0b00e901c73b2428a9d3fb0e6bff7571d7b4838575b6d6fcd5a93", "6560017a97c51248030ffec52b367a08c279b6674fd0755d10d8eb1b5934e16c4627249124ad63215836c3029704749ccde2bdbf7e5550e39e8aeb9396055a496876a1e55dac7f1ef0c40b2f50a096a9f97fb60fa8e29fd367598d406566ab8c085ab0cc42ed93fb2dcfaf960efdfb5d6de83752a2b0dcf6dc10a1648539ca78131d9e9741cf566d329f7bbb3b58ace9c9c1b7b3c5cf153047425d22ab66b46b90ed1e1ba872c287374bd92e40270f458f5054a18ac1acaea2e5c86d40146d9ccf34e905f96b88b59d05e25d93d587f476d423d580bbff04c5f1ef3a42ce299a38f4ac2891729976d438d647c91eb76f38ec90b1fb02488073194dff4148b5119d794206bd34b779b141fd193b3e184d81ba060b60c4208e76a1b4e8a2d807ac48f958f7131707cf0def01f0e2e40e18256a286ffbf774aa03f12e88ff75843eaf6f1a90c1cef6b02753e9a5f7422a76f73b446c01035357c38e9524606f76622e8eee9873cd54e12cc6e1808260b8e9acbc27f135f0764afbe4e8df54adb9bf9fb354181c95f6a3dc0139e2af19677af9fa2932abb7aade9bd94ad8e48f5624ede665e0d68868429863bbd7f74ff99ed1771be02eeafffdc2ab96a07c43713ed7c1c70bb7afa7eddbd51263bc4c80bb33c410d222cf16f674de47410bc68612f7c3f9c1d93723a1b169149eb27624db932f438ff8537a912045e53ab0a92bb5853960c71249acb7baa5507686f5c7d881f0cccbb2a6e97402743a638b456443de8d8b91f28cbacf0ca624bd634ced448ce23479d56f682cf09979391993875a860f43100da29fbe533c1a1b84d10b9a9827afce34574e1ddc37fea72e5ef0d28dc5fae838f038ecb98ae756bbdcffb9a0da83176e15ce90a1aeaa5ee3ec5d16ad9204418a50cbe74897e75a56493f7e4c0d25eb0618c2d5744592b58c192d08755075506c19c7f808623b95dca1088630bfb9c12af902317c96857c3fb80bbd224d903c7d22db59cc24d686247ef9bb3954da930130f3c95b5ce2b393cc620ece94e564ca3f3da419b43d7de16ba70b2bc4ac8cdfd5c01a4695637d145d2f1bd5b1dfea1de1270775d81f8bb2ee58cff27566531d8a6ef427b4629b19ca90e0261f9ff6b6c978bedab4638c98564c1f0269ed69f8c9fc7e2fc29b8b3d15562fe863405acfa0b7588893f9669d65c6aa2ff8dc9f5aff72f103b1e0e146727a588f6018c4da184cdbca9d45091d82455c0bd1599cb895be8cd93ea757438485983be99fda4169c6481d03af9b36d2446a935c4d3e00d060b97969aa2bffa345c1f52489096bcc37a085c32970ba2a984b5eac3dafa69667566430153fd8b40a9cc914b92b46e47ba62cea54fa399b690360500954876a6c6054bd686de7ee734ba55a605c318eb39f1ddf9b6753dfc641988ef975a9656bf6316f763e8be4d20e790c88b5684e61296169e4e8cda5632bad3872065740af76cb43329206f7b9f929df59ee7a35104dc7c3fae04af1efd245b7bf5c7d0fb0cd5b55be5211c4e7dcd8eab66e5acd7a5fb59d23c2fa88cb45a39b178dec6ad82bc609874b845165eb90e024a908701d43815d684d4116b32e7b6b57917c7f48b56408dc1b7950c469d1af4499d07928478db4d20b8433c4b958e96e1431c48fc204a2d070d5998609e6f8d8ef8a0d18f5f4f92f3d85359e2201b8ad7f17ee30abee7e9704ff0ad6a4c02102f44e22ebd7afb635887a2b67f6dde89318750ed668bbbb25fbdd8486c32f96597e8972445bdc46abc39da2d497255efbad6c3748418617bd75bc9e17b8f34258ea47a13d6681ba6647b920cfba54069349610797eb38349c13ace625832a34d10f219732a6a7410f5eeca8e1df1c63564c70d61f79e2aa7d4897968f6806d8ccf45720a6b591b8a42e99ea32cf42c0ed49bd67e368f9c1fac2ca96af8a4d3b8401351cb5476d07c36630f77411f6ffb502a0852acbcd6cf6e42f9be767b204338db56100519b4a3e529261fb5bb10f727ca74900b4b019a667e3549458268f8895bbb38ac3c17aa32e61b87b4379df73bc07a326746bbb871507221ff406ab257db945952258b5ded17b0e9c7e6c2a5e29279d6edfe9e7e07d", "422f2793424f7fe1993ee0188737bc73388ff99bec3fbfb23945f26a19018b5976391c4c0ca38fc2e3fdec484f5fbce5e22e7ec48f1a3fd0dbf0b2abde754b813778e9e084923b811a19fa337c5751aa58c3fca0bb4191429aa7ec18df8df6ae59950d266dba75460b9cadd23a87fcd0bbd2c7ba21060f9b371ef1dd47413ea7c25f3b8cd434ac2c1185ba7d91e7067d62521cf00de315d81878abffc8591ffd6f0195739caa796b843bc9bcb227e53c6304e7ca56e9412866b0619299f3ac01ab637df00b5d014485f72749016ec29389b9a2db0c89d73fcdd49e9dd9d71fb76ac08749fb812122bd999f21fce23792821ae8d02943756ee7478d151c903bbcba4af0d158b485c2f57c445caef28da971ed3a0489addc68b66c6921ba15e7d9e6cf2345c5db5d752db46baeeb3d6a53f637ad1232557b9e5f6318e5756ce5508db7d2969751f445831fed3c543be9fbb0e0ffd6f99ee522ddf4afbd21d94243d3647e8538274b1eae50e828d45de6f5e05a7f97ef75ac8117767e531cb55681447f80441a062d7bb3175ced833c2d7e059c9ed5ad9bed713b7cc9e601b8af8c9d608116c4e2c55405343dc7e8df658c1302faaacc24fd17bfa16ec2b39ed85bd747c2b21354b9ec5b284caea68b45e026cb082284fa22bfe37891d1895aa2a954cad4b8c7dddf339e4f8971c86ba09a5d3a6aca61a90bd7fe70c2552450746bbb941deb46577ecd415dceefbf8501a863fc38187a3ed3f30b78c35c5df1a56d6fd389c93e364bdd4504308bfb283ef61f9318b710b6d64b4958d032c54bc36090d1749682c9ef80a7f60628bd1e0edfbd22a7cebcfd3a632917144e6b54c42703c1bf24ee470eb72fa61c00ab3fee7b1c67ebc4cb95fcb3d57cf2cf22e738e08aa05cac2397e3d518251dcca79fe7bfc111fcc29ba57bba4f9afddb3b537c9096847c6546adb2b4948949db83c7fb2c569b7741936cfda2beea8666df7840b4753e6fbb0b816ad8725517b0c8bb334fe8e2facc9a4a39c1b83dd84a4aed771e1b5010c24796f001d411ed8b85ff42ec4935bc27c0c8035cc255420c72f6a8248166e7373e1d41875f06a3d087d14cb81edb225f7e0645d64d13f64c72393d857e1dd87458f21763c6081bf2c50cfca4c92c8d59a5138dceaf2447ca9f37367e3a3377fe8fbc2d30c5c903641f4398084b7a332e4d4022db6b67a517fb8edb8457be4f45ba4718e130f679aa1acd4e8ee40968d6fe11ece7581403044be3e43e1fe8ab2025b04ee473a87adba784e638429e1257b6e5a29352973014ebee7747a71ec4f820fb64255ac97b0d1ef1a463355af27f5e6f21d4f02c1cc68cb6fb615a028231c136af29a06ec41ff74188bbe6ab4291f3e2c60bbfa1b44219fff6571d8df8703f399c597fff8435c0ed290a8274b492580f795f9911d3962502d3baebb18496f215d309b6e3c1205e37bea1e8d0cbd6ff491dc3445e70217a889fde86a03895dac019b79f90b59772ee4d242faffa4044358ba2dcfb12686837b3f4874c930c40a361e47e264ff3e84c93d59488e76144343ea6baaa3bc53a87517f3f5500b51197a9334ab92b5d40ea09b8483b9794de4b0f4aa8155e4299b46b3121d1fbfbd2ac2ee3a220a29ef45e4e0ceac463f66b353d174e929418a71bfd5476ec6407fc6d9956923636535eed55e11d6e86c9c75f9c42f0101a52c511a48c6e8928ca4d744e68f3d05476e2bc67491bdca1df6be8c9c759c9889a36e07cd4cadec3abbfd5afd9fee45c9c4636a1752aa8b83b30ca8d215b33b1b763bc5c3895077aedc732b940ee6e3bc45309928386947d37572ad5f1164632d6a5be53ab2652d15377216eec008c1e684a9a0ce2ffd6e14bb6911f48a75f2202805dea05dd0d51cf8f6fb5a31e463a807d9e9ca59460c6ebdf02bf3f5d0d7169b52a0ef1100abb20322520855872e8959637548348a97abb171a98ad62fcc267566be69c75354eca6af2d4546150f59e31765106e8675de8a0629de68020aeb384fd12d077b418092b158cce8e22902d898a9ea7ec3e7265c0cc8b01cb4806e263b69d067e354bf35d7854997b0d011e5470ac07da55cb9f7e18484bd8adc8da86f9cd75cd82ea53fefb4d65ab687ef15577c734fa25bbe1bc4dfe08f95e9c65fef25b7a232efdfee6ef4de8c9272f82feb190a35a307832ee4f070c55f4b0b75cac260e118a6bb0b68ebacb0f1c0e73d6b423a9f92384b246d9196fb37e8f79eb4e25942b5724ba599b2b16d3d06aad65cad932f9193f70c71bac8ac4da4a760a50760b984b877df2073592300918212e19f3767881f22bcd95e8dc2230c34ec0f26053c075cf9cd7acef901d39acbdc164a63d09ce9c6c01647e0f08df2838352901220286410ff0e8da9aaba1f2582e294f8629e70037b7a31954d96e826dbb3d5649a6969298b2abcb09cf0baf083468f048ba266bae51c376a5c8fa96d047bb48fe75820e01ef06623fec0b7fd394bb5f50cf860aafda6fc3d56822c54b74d9a6cf1e329cb9d1b81c1da034c05c4af24b9719d9bf1e034dbef24ed0751a8b7c84aa3cc9af12aee17dea83002ed0d446767d0e43843a7df98de8bbd04580f02deca4758aa3f0b8419f6da7bcea23bfc42b696f05d080975d338bc097828dea48878732c890fca0d54d8eecd5b3c0c1056ae5acf0934b32c44c84f2bae766562192272cf10bd331902f34d40a011979ebf34e981082c7aeb15cc722d44c2e8553f003ff454d08137f15ced38bb274a0ba8845f3c6df9d0809d37c503c2770fff3ea92b3b22443c759f9287021d027c627bcf9f2552ff1e3328caf791e0058157facd5d2a5afa3080a680f3be251395bd312cdb584ce91b5a80ec719403e50e90f2eaba6e529e579392ebf63bb828ed120fe354799e97cd0c7da77ab82262920ddad8488d6799a54d77dd0ecdeb63a650c3789c77055260bfe20c95a90d1e2e3e8dd59a4f89c77f7c2eb33526d0541200f7b97fe16f71be8972cc2df811b7370cd3f466ae116ee49519a2f9c1c0d8646424743a07486d6766342f65f1d1dec1028a1b850b59fc79bf5fe8e51a61c4f137b4c51f2527fac9ea9b614ce77f640ae162d72d3075b323b43bce58e42dab4d91176d6bed356cac305065cdc642a4b5e4bb7d3095bac85c397cbaef2d002dd00a9b22d0443ee2815b46716f4d0b0c4943fc3890698479754eedc7b8eaf837c47d9ef918a6b28eecd0f1b3063baa199a75377032be599b7074c224a944b544673ff7c09e28abb9b8493ab0c6bd9d01ca45f8330f7f058eb68232ce28d4887a174d4593601190d0616f4cb11f95cee60e843b5c90487642f18c596c6b127e5137c37be2910c1620cd7ea8128844c62f4a90ac771b21f02f50426eb916e5fd70945e0b109252ee64447ecb46cfb33a9eb4784ae061feeb875b2ca9329c797a3b8137eb2662c2f7f7ca8c08c890e8a13a697cd26bf309343000ad647194a9885f513aaabdfb95738ae555f6c151e9021b4274866c29d3db1f04c549e0e1e8f2735b19d71cccd3d854ed521e4fef65ec80490761ba9c9afff512963385b00dbea6d9c260dc0257c7ca8e2fb3aaed1162502e11bc4d7af6c35ab6456c7771888604248e7d7eafea53022ad19ea07b4cde18e3def9630e5c09ec43997b36687be5ea8f237928ced61a9da05b420e657cce020b53432efdbc66a9f05fdb88bd94d33a92ca4eda2672ef735e859a3eaebfce2f9c16b1646c8cb4f86bc5573fd51fdfe17885a588aa92bda50723287b6d9b9dfa70b1c1d40d37d336c1516d43f3d4f47a94f6db6f18b3e621d172d8557e91a2bec308878edc68a054f04d5ab33df16b15da3a5d86d9e68065bd0350d07e162183ea9b47de24f9678165c3135cfcb057c0ab8a4fb979ab065918fb9f3c251cde700728e3ad1605d0a18cf4b562bfb224bcb19bb2d5285845f3153bd7ef336613e1bc894faa0a800db9253572dd852f5cf420b935b2a31a0614d0a7e1bd9cb0823e7728d2b1b040986c3ecaf5e89d94f6d5daef6c094024a8a01089c51c310f8852edeb92b391d39888af1533dadbbcebc4a69e186dbe898959a0b242bb0ec7e4cc49a88f653868ee51129c1e3a3a128d71a9137eec94280c36bab788f3ff065607049a9daa0645f37509625f086b036cb44b51a70a8949c2044347f52ba7b1d91c37cb01e3c85177e53d5ad27bcca1d742d981bc409f1d400ccc2ad9c7", .Okay}, + {.Sqr, "-d31d13f9ac6770895ffa82e4a6e7b1844c40349b5cd8b8770db6c59d6b49a86013e38f7fdf892e11c76290e613d27690c1b7e12b55878bd117a4e6728d4e8c2a776e0f5d890f8acca2314871aeacbe70ae3fe355624de72120ceb129379b14c50a4268fa25a44eb19d1494afb4b56ae1dff002275b4f78d542a160b809bb4d9de5c66093ff9027ff5a940d486afb797c26bbadbf022ecde1d72d029d2dd12674baab0d5ca5372fe167aef847c2a3726f626f7e0f54784d93a9f0d29cd7612e861ee3c661855dcdcc0467245803a70ce8b933b2478bb62c15374909e2cb523568f71ae06df5903ac10276619acfcba226f28d6a8fad8643fd80fb66f2d36f8c018d93da8bb67d82f3358b41993f46e88766e53778168016d11a0c8bf157f7a0b4b871d144a79dfb37b9a6cae2868180fffc591bebace91116791497486ce0199b24a4413ee05482442e6586de09a23622008eb4c4a5ed6d9fa166bd5944b84128820b0b8f57297693dd7ca5f287e9b1c8632b62033684ceb6105229d41fe4193780c01bc8d03632ec1c21918a370b51dd9c7ced3fe879ccb715eb862f64906c12e504d2fcd5fb1b0a479523cff3114426554c28e6ae2d8c36eac35417d613524408cec26393e773a60f60c716f4d504ab93f3e7ebe386981936a109150fa034dd514840ca9f8e7fec83754c0ccea35f21e36fd304ea072d28aca518c217bd2fc714cc1d4002d14d254ef50bc41121a95f3c461631cb57d04b00db572c4f69caa4cc73c36a96ebf67698adbfa6825f95dc209405b1734cab8dd72dea6d74c4a031793c0979ffcf5d16e1430d00249538bb6af2a2ed3e06995e567cb833f531d906637fce92352446de4cd4fc3d53e649d3ff22306f7f821e49a579e38c22855e27082f5176cae223c6103b13bb812c809199f662546ecb9ab6e8cb2fe19c2d3e53b30ab048cf45c35bf87e8d4d7a6a70b195166ffb8bb110ce146a3534535a1905c0b2d7fe34d767b4f8ddc532cb2c4dced9e9ef6f47d2c6c54625c690bba01da08e4d4a5acb34db99810826018fa2bcf663e9b2150d344caedb26af0780d5e958a9d6a616ffb42d6e6a8225cc6b255aafe6710ac2ecffd1aab1c5a49ed7219999b027fc8c57700c073581e824ea1112ad2b655213a867f376556e142137eb8a045d361684ada126323c26c8f5595ea9d0e4a36eb9d2dac660ce4500d8b2851fd12657a6a4355fa606ef3478c88c3cf84d00c397d9d50f97e2b72c42eb247f826e6c6161e6e35dd44ed10786be4cd3e81b18103991b6aa9a4ebaae7c9eb462ce4814ff451c55eaefd48be2c171bfdb148304c5bb705e9bc78544b764d9b83d47e8c1960738cbc070f14ab0f83da2b6f70991c3b43a8311f759eaf30eef6f3c7422482016e2a5922639127ac83e022e873eebebfd41dfc6de2400c71ca600e516d1ec58b2659a384b463bb78a3a040c32170f5bca8cdc6483d26b03d98f1e5f5fbaebcef6b59bfad2fd146efb9efabb884fb69b7aba2f1b854f75087eb68cebfa34b657c08f2ec92b022c842cd36dc1af971205ecf2ffb14f5f298bafa29ed21dc8265c35a771a583b875a3485983f3052dfc2a4998f180148894838286c19852bdad85dc050b96497c2f2553d9249615d2e142bab1bdf37144a32c603d0fe9090494eb73b6128e7177ca6a75ab0346334fad771259460542cd6d4b64103a12f3498e4a4a9a3e4529c9b497630989b694ee5304a3d156dbc019937ba253055a10c27dde73705b13062b6392c7daead490f73b3f5bb72b4e69c98515e15715ecade121fae9d5f0d80ee7b740fdc7c0782cb1a1cd41bcf41a22cd11639d94cd944c5350892b95e54ed6bacae4bdd987c4e905d16d81e01ba8174d4191918f23268a5d636d3db9c824919dc32daa7bf06fab4d2745d395a7dfc3a7d253cdfba0b166a4ec937df9f05a1b2c3c247f48eec1b87fc83eedab173e1d2e2ffebe080c65a4d856459d20c57ffd2861fdde553a79a3206ec3e9b41fba32b394e85def5f46041be09f84b4e730830bb39deb426e59e1b3fc47c2f24cd3dff33cffab4aa11908f0db1a39952b5d453431c4469dddfd742ef6fe0cfe0b59e8a9f1719d0f", "f35351340b2e8dafb6cbb914ccd0748dfe0cbaf5f1576fd7329e1580f8a653c907975d775acbbc747b0293b63a312aef8f44728c8337d5d3e480d1643f3b3d2177b58ed47ddb034a94f58688ff1c2536c5632c943080187f7c233fa3e96fc226c529ac590c3d93efe2da795a5a4f56626aa4fef72f6852a65e2ca31dc9d6c40694ad37a28836a6acf8ea1002d195d5f3a421c95be2d7b7ea679afff694e9c6d95284edb043a2f2544b7b7466bc9dc070e2df137d51a618871de06a0a8d447b4c8ff702ccbc4fb7db3a25c8845aa620058301a1707ad3bf0e4aff9970061ed6b86cc8e844bd8e7c36e34b0e7bd391d36d81ac3b9d95f679e916fdc5ab777cebaf53f60f63772eabe4e3eb54fd2566b81bb6ca4c840cbf75dee2f6590da9c486871734a8a1f0a7c75b77a4364b97998350246f9ad9b292f10eca32558f679a4e2c73c02918c7abd2a363fec41a6e77bf208640b90f9cfc1b0dfca15a991d6d5fc880d3599d85a83ca0459c02812dbf9ad0ec19e8d6eef30782606120474eadc6ac835feef1fdae181c44746db461927bb0cf46e8d25f2ad8f4299da0995fab2495b5a8b163762a881a6cd76c1bab9cab7774ddab919012a50a5be90599bfe5a1729d04001c12f7200f716a6d3ba2f681189b95ba9c74b520a414948098f687b778ddb5f2d45523f3e70b05d84ec3e862e97dd59e7fe21ba3707d9a76da94e4f542d12072b8c8af14dd2e17d9ca635377f5210502e5eb4e7d1ac4922d924ae37b3042cdc24020ae9016833b615f99f431f00cc533030b3825a4eb7d7761b4898b4d89c4cbf81b09188921cb3bafe5744f7c238e95819b3a17e59f7e1b488dd301e5ac110b23efb9cc7b68d260baf083c2df8130f50577407402118eb2409ab5d88f2e69f5ea4b6038f5f59ff20b3d557a399de6673f7c8cc3142130fc7d97c7eaebbcad86d726c020e977e41bd5a947edabc65071a006f4d1793618d009f78ed03d7cb442d600f4da07e2732d70306e2de350521b9960004359e370940055a54f9b4ad325700a76e0a0f6752fe3521e2cd9418cce3365b26a511995e41d5c02f67249bd74416e0cff95712e513e5cf468edc4423c5e0bdbbadc458c030748d9951eb43d1b68949e6fef7c435e6c0842075d39f3ef48597589a331a633f10ab783e050debba4bf825cac10ef119428d2a8321cfac6c584e9cd0be84f6cf9d784fa385a280dda1549497d6517ec21744f25ea707aff04067aa7f9c8f38e3207f6f0d6d6040b44d56606326c81a0e3c5e3f3f8c6ce54ccc22816d47f0a246c93e3f2819323d1a1c204a6f8baf16d1be248716f9f2d611c08216cdc142a28e61a57a78c5822b26bb14081819c0bf1608d630388683780161648405847f4c89510cd71e65746bd41d2b9d38b75799166af469e9dbd02f10d8bf8219dca5628ebdaef32ff3d37f09e7d7b919d0be5a3fce945c5b967d3f51a5bcff76d28e226322ca6964cbf556a248fb2e64ae09a515168a12cde3febf80829758a79cfa2a2224879a043751104329012fc40cbf61adf14e075c91708944f90942f86b40cdfe30816589f47fdc63cc9a8d2125e6b19f7287a7b614e769abb23bf19d19986fb91efdd4f32e9fbb872797d63179b52307099a19288a49c5b61493c1236b446304b21f219f3e5bd65287aaa99f6c69aff9a39978a7c5048c59b2c7f5a3af5c1ca87a338143d8fc0b9e4ca81ebc68f259e0b8fc5f0f9a5c806fc498ac3ea5406398a2058c810e932f058effad2e402610edcfaebfc99b150b724419d95e38fefddf4d907a6c0b5fb2489e7a5481159251e85547e78aa53019833154b902e2f34064e6c672e4d3a9b5be7db630841ed5e03e617144ff51cc0085390417a4740b573abb92cdf2552a3f75b4df2d989c15a8ead287d2cdc52345e3fc51ba60ef524b166e2b17797aa9620d25cef17fba68694472887fe3638e465f8a940cf2a9209abfbbe4074086ddc1e3eafab3efcf2c6825c9ffa5b3bfb36fdb68218c410d9facdae57472b945e92cbff6a854c30556d5fc5b0cc3f07df3ccf5ce2ad2ee2359c97ca519b46dff56f7b57b27b1447333c522cc30b7d83d64e41f261ad645547283b18", "ae18f23b1a52960a235f2b06d0aca9dd05a5c5fb7e940be1a9e1880bffe2879362c1cfc5d3d24d16ef1d0eea07d517ff8bc12dd7e91ea46f5aa423fb93e12982c5aefe6df439c2dc467830eaa66d9164c3dc93fb47f4a5d02a5a775b347484b014dd5cfeb2e2e8612991a30ebe2444510c82c7565ad0185cd1721575fabca090c7c1a346f3e83a9a19a156c2d47d781c83d05f8953e598e36616ffb331a32516e347d1f48cdb5ac971a5887f7e4af6003c0ad02d3935365022c4e830015931a5eb9100aa3dec3d57c133e3e01eef87d1cca0d56eeada306d008d834144e5fb8b22ef20da45d344ae3c57b99a711427f1b2a5ba9de78eb3eadc9be389ec4e7d76da6506ef5033dbfab70911db651efc0d962310debf2118dad711cb8d033968c436014a5f19757b33594c64ce71826258a974b13883a2eb6e383f57e1aa02bab23b2de5bf579c349fd2448cd966450f2781d1c7dfa2e296bddea4c3dd8cf99ae5eec01283851aa09258be100c57cfa948847a3b7db5d2eb47dfcbb4804310550f49b0f68559ffb8a765f1eade9bac4276c9580446b9954a571d1b82a68f649f96dd6066404d74c8a151bd3a31d9dd719476a3ae5f52c8f81d215022cb9df72b4afdc1998f89a89413da17885660e940c3d1285c2aa110839871504d15e690caaeab41235f1c094c033d3bfb4b977a79e5d53bd530ffe38cac8a62dd632dc165902ed4015326104cb31fb38e96b52ab1e8fa4757568fc2d8d5721308c148530357b434dba523489ff19a7e46eeca25ad5a5b3ed5a5ede6ba4aa099e488c0fe0a4c10ea4bdece5cc084856b2a931d2e0bdb0e2180292d45ffac76ea4548c1c99886f01a7830325435364861a2ea02303a378537140281ef2287972cd23b1800ea7c3af92f4b199e859fc7cb013e8bc1ebc3c9d042ae51095429eccdc8e2e378480861937df56ea028d4429644500f3fa2ef4fc1d652d23a041974f9f5d32f456801362df9290daeb4822b3baa49a3495d1e55ff4a65eb7ac87e30b28a949737e9075bdeae0f7ae7024e15704ffae59e3bdab3de5e8c7826579e9178f63a8c0c79dec6cef91c5c1dfbfbb141c28df58eadfcd0eed06a956f5c9e12a147f363d7f462fcedad8e6cfca3f2cec1a97102b2f739ac9bc2731a872e1282c9caed0c437f0b1cf763e9cf98ba46574d621367fc1c7dada7a782d0e5ab612430808e8c0eaecdc6582b707503bcb0c123192911d5fdeee6abce3c0675f50da51eeb361db83346140b471f1d400614cca8043948c735bfa573b2cb32dc6cffdaa2b4f29ce2640615b066343862492d9ee984aa6c69c725d18d415aaa61d2eac73a044e289365823c78ac964403b3a060c923adeaba8fa8585cfd8e6d1d77257643d2c1615e3d86b7e3e8a892e3ffcb6009516c0979331f8a2308ede4ee994ae9803fd11123d5dd5ea516459fd5d440b27fa94057acc109112bd082a2b6702815ccbfceba2ee5f4e276f5afda0893b6b0907cf732a7af2e9ebb170ef586588da8ed0a41a8af40d9c8c64a27ab7c3f6d17b793d1c77f9bf7a2f65cd30b68e0179c024c0c1ccf89f52e7a376de0a7e61b6f8629d31c42adc90b9788a221b2acd19e1d2ba2e8bee0d35deaf2b4db86b1f0b8109ea3e7c89bece7bd8e15e2ed891f8507f5e164dec7999d33e5b43fbae31bc33398a100bf580ffb46c4cb4317e88ffdf7cfd5066c5e9df63120f59f4400019fbcba291eefc0f50466995a9e58873a250943ef1f0b665551073df0fe322241a01cf62849c5be4b26c42786087b1350a1d3b5dc79fa9b5434591ff39a5a6403afe379722224c957fa7a0e8bf3612a1416b6668cc990a464f45b7554ee8a3c39c679fbe9ebb8883e146e531fa2e736245fee8f03a61a9fe549ae14ec44afaa2bfc8463c32837ff99e389f85444e22556ac201d649e2701f6d46de258de54c2ae6190dd848900fe14adaee578ac920f06b5694c8a68dde04f452dda81dd1ba8d93978ba12620909d6a96b6730f77d34724464e5af0b8197894a0a6ea317bcb5f414800d7e4d9defdab11546b4bc364c52eca2419715d142cbdf9b81c2c1202f727bb3443cc35c430b096294aebef7b2303ee8496f3617636a0cd8aeac410b755fe87dee49d620517652422327f6e1e62be967d0b9b687d93c1189071af989b6c0aa681c86d3ccbfd369f389db5e601d2a483e52642a3cdf7800c264bc73fa9ea3d51adda68d586149f035bce10b6fcecf00bb251cbefcb14a89dd0db52eab5f6be14e1140f3d2131f29d04327de4afe9c1252ad9d7736cf3c4f105b7ed8df0a93e986e319a8d76cd741e3f3416cffc5ec4c1ea644b31f39d60e722b6a8117a2cdae6f71fb07ec6396783d62c5268d70bd31190e12399ed8b6cd7c41865cc9bf8a28373859cf62ba21dd360b56fd5a3b256fe03fcb70d9a8d9a6eba1e53e0175fb544ada053b0235fc3b87f35733343b56997748dbedba677cfdf63de72593904289bce1e1f742c8a9373c164ae40c3c4b8cc57ca4eacd13fe3564011d7c337d6b7233f0abc1522e7b4132a3801e6cf4cc6621c00991f0d2b298a91fc75a4093b1a70696034ebecfc77c9d4adc472cbfa8327cf9461eec6845ec0ebf3fa9994c6a44544cf5b99664ad8098ead9b30ad7b75108c53bc882748ebe9d98f301829c2fd51468537b029c434df9a74d4fe5f5163d8a34da569b1be8af219fa284fbf1761e9872c3949e50754e4360294fde9b039353ca0758c69d31332e870e5982b3bf79f853783bbd026a6047a2778e6e56d446ad26e52d1da5c5c55751ae8523377a01cfcdb25a98fe2aa3742561aaa8186068f31752a4f0f73e955e040a89597839f5e7e74219702b262957bbb1678b8a9d377d79c5b10dc8fb4c37f24c3f001cc5eb6dd71a1ecd2fa11a70d0c5ff6681e618d7e1174eea4a21a4e5e21942b8de6c84bced3d81b266ad68503d57cbd9d69de87ccf3bf5c564de986c4ca24772ec74b2129dc70654410bee2b717617f32ea2451ef3d152977c6451d1c56f51a69213cfa20f4131fa298023fe45b0440d5ed96d059276b6c3cb966fd5184ce855b4b72a5690c724b6080916b7a8d22ca7e63306d7295db04caf257df34fffb55a81f12cb4533719c145130fe21c860defbd126dde1641307845ceb9882c7c7932b3c5ec333c4183df587e3de94595bf0f1f9b6f6ca13381eeecff1172986ba2e34c6537bc74ed2d4c8b6c437550f9ab9da48944d18019a3a188fa90a09cc7b2af85fbeb0450b44f2eac358ceca3237fe2135e69b97da3f6c27a1bbe6ad4368d4f318270c9c965018dafb0c6cbf77107d9cb4e94c5ae0100f848796f57b50466f5735503e60f190cea83509f6c15ccc8df1fda6333e16a396f4b4afc31a38981b42b1e21c22c4f0a9585012c4ffbd23299780b853cb52734ba88181846338969b673c8faf88f7068a128d669ce873132b950ec770b6a51cbdd72e14c399dda62d653932e2ea9019f29667d3c181ba7db6708dd13c2747d7bb7849ca3d7d527ec0c6cf0d83f028e0c8d75967ef3cd94e9ce9ad4a1bbed21520455a311347d461bb3118d8ebb6d37ae41a16071b426028d68a856ecc9ff9ccd78ceb91fb64baa4bf0ec977e94a472e0529719952c70cfbf9fee8ac862023848b05e9cbd28c6027a94f591d73c89b54ac9145377d65394ae36448523ee32c3942f8477184739a82b9dd21aaa2ec2fcb3c4ba87b79a54d4d7b929987a022b642dd0cbe4ccc096bbca6797658aa8e0a9aedfeb18e8afbf50a1fc423741e9ef6a07e5c72d1c026afdebfff9039d0e556f5a1f9309f8bdb37a940b384caa5754905ce67a0f11bbf0c730363473cee63c37991c2d668134a8079d9fc4697a0a3649f9ffbbc79ac048c17807de95227d85293617bb78dd4ef16240feed19cf140e80aaf39ce581a1cabfff4b1a956b2ab686abc24e6e7a887317700549d87329b09148cc7ac7ba11b8b0e457839fe565a1320811df3888b75654e5bca042931ec23091503b8266abb5fdbaeea8570f0c772cf2d8ef1c19dfd0cf140792e422757641cb2be19d30bbb717274ed94ea5f9ad6fff6274bd4ce396c8aa947d96cf303ef2e951c28a6a22ed2b9b059406b248b5599da67933b5bf286c3a03f487d6576f26880ddfc3a92d1b63266df81b521e14899bd3a484a749957af8d121c339a3464565d7518b20ff36c364bdfabf52cbfa20764f2cb116d1a9f0459966e1", .Okay}, + {.Sqr, "4982997fa8f8d50169e323f46671feed5a172be932cb369933ece1576f8951fd5365698d068e88241cc79e4d995f3d707a74a48118e9725401fe24154a965714cf49005725d3dfaae1ca970b736bebc205665dc5613e979e6de0485c02f8503eb1074fb947a6eec23d0349a30575649f7f4e38824118b545e598ac2c5adcd1c8c785633253f5fb92a9b36d42426b1f6bc06a4fcd02d6e0e765df195f5fa390c52317a689e1bce02d92f2ca96bf20d7348d7b961de31c23b1f196a612a2319c2f49dfaa4b814ecdf686cfa828854537a09ae97ddea59c5e6140baf20f6dae6e660f2399da5cabc814e819c92dd685e0228d8b6509414afa225582bf149241fca6145674f14d6d77e1d24650be5502a0c756d92cfd63811e6a4b1dd432c823af07c45f9983d10be2c467fcab933a76f27ca72d36dbd3156326a4b32ae433e77fc6dad2587ae55f784100db361e23461fe5246918ea8aeb12d9c377afc399c43ec07db24f46934ff3197da8ec96b5c09c2842660337db593d0457f0de7face3bf8e700453e9820da4e781ed588c14f7390da8ac94397bd53c571a70fd30d5bed6f4063c5fd8c1817fdf11635e7b2d8db334cb5e475acc6096f4120ba5f059d76d30393c64813cf59d4807d332dbe06331d70583c02fed4554cee580eba39e84ce3dadff2a81e59c529f45d44b8a712c0a7b45c5ed5b141b792b901ba07a5a76f53bc0a3085472bb736c61ce94ecfeb7e26ece740cccf81a26af8a94608ccd6c24a795e40303d6664d12e4c1e33e90b470e8e2d044ed7cf23a758204568f7957a162c37b3a8463a20d42d808025a79533f7bc39af554ac4ad5646eb114c46c456a0ab105ef7c13fceadfc7e45588f2fb30e09f78dcf83e7ccae36a64b87cfa1b65287a15495e6621a1bcd8fe4e2b9b35ab9b353888535c4330031b132ae5d5ffdfdb70a2a3f35062ac8c3fcfa4204369ff2e8c6fb7866f98054765bd2793a324bc9e1fa6a8f83db596edb67b6fda6bca036d94d8a104cc9dfac42e8f3980a4955314d462c34ea8d48f041106911c4cbb0286bf3c01bba960023db5666030e0bf85178dc624f3ba2f1ada1729f2643c269f4b72e9464b4a50077f3840655ac18362efa6ec3ecd49f06e95f8c4a95db64bb1a2d2667f1b3d346281a936584e340c8ec6a2fd8f96ff2cc5b1e07ccedeae675d0bbb0db9b3400fa1eeab44a2618c3e069ad4532c87bb1dce15b29f3a12b1ea13555fe30e6c8c215c08c50488c474489ac9e7fcb1fbe1d29621d4c58299ddc8d43059246c2c8bf7ff6b37876f0a78a1aaba70e401c902d4ffd60a1c361f6c897641b9e67fa9f9226a90f0b7cbcb55369f81ef728f9dff48a270822f00044703fe28b32dc3b078034ab3ff6633a724eae6c71fffaa50295dbdacbe9af8dd406971b852f48e55fe7cb61a1ec2a38b02919f7072061464f3131226d451e7b3f690f4ee478d8c1d2d5b92c99798c20f33436907fde75df2321c9bd96701cf4615fe83bb1f23a329c89c6baa7b3ae3c5394712d98400e1442d99dade4a25bb28bc318cfdd4d2e3aca3f84a3c56612388ac209b5675f876acf9442db408cb3ea1bb9ae7693858204fbbea5f458faaf64a6a44d511e65f633a9a510ef4337d8bee3bac459b937862912ba6d255a7c8c9f4f81ad2e99233853163b84add3ed31a9acd8e224cff4bb5ac8f9d21f46e70ec28806bf06af1000188f433817c1935585be5d1356d74700d6016b787720a85db5f8cddcd507737d1efb01c88a2d85bf56248a065275856822a3ca1bad0007aff2f39df458b17de4060cee18f8d0aa32d9dc83ef16206e4fd4bbd443af4e6b620efa8366afedf33d9ca27baa316db8f05fefb0c36ffa8ee1aa81945484150192d83e066396a675e887b852236efe8b4e059f28a7b22241ff5b1e98a3efe67c9ef547bce6b0566f9d243735c81ad61837b423a92cab045ddce51536ed39516eccafdbac1b1c32449c88cc8738c773510459aad05d76ab3e81d004aed4bf278fa12fe6a44344cd3cdfc61a9ea08f93fda1dc832998629ff548b5a671e99d030b09cb49e47698e7e90664846cfa0b4a9fffb2a4d346b8d74346946c2284e0a145d4636", "a26d85f7cc9692b7f1742a2454570fe39bd5af67ef91d4ddab7bd90104da7744e77fdcee6b7bb0d33eed00994e6f19e8d728649d723d84a03fd59786ee7e73131f01ed06c8c60800e7bb9af83879eb1953765a2c6599c5a9113e8cb51b00bff310c2420f8f294914b8e5c0db25e7cafa9086054ef155c8c069b7fc8c1f6509860ba425b0d6f0bc537190b2ee3f857ab966a043ddf6cc5b0770137b74185c0b6d8191f5cf4f6a0c1032341969c2da82be989ffe9ed05726e51309136648b4d0c00190801764f109fdee1f9e00799b447d3d9a7f9d03df55c14fcb6b8b56b2db834a640b28f4c53e48071d21b67046a12ac2da356650d095134029009244a83ebf076b3407e68e3428d6e5ecbb560d2b32bda85ea6a201334cc430f8b2f7480a5de7636a8ac8618d5e800fbc2410bb8bf7ff96981e92713d9db4b162a189e6811da065f4dfb57266b4028cb8b1660b659d35a98280026c7d94f97f08e8bed9833ef5d7d85de5dc0cbc64bd5c629c301916c458fb95730718517e5939ab94582e8c8d6409a34c14eb051d062df0d49baa2e2c5301c2e452fbde3b27670efbe5d7bb08f10d6b0da316da5a684505d202a07c3d1395b650cf5e757a6e5cce87578c6f1cb99cd0f3dc6eeffe3e8bcfced8c99b25f31e7696e22292b5096205f9b32964c5214fdf65c342241c449ca2458acc06a42b75fcd51fddda6bc260363c79075421b427547a611691a8176f8444eebb11f170c31c655b4d3522b43ad5840b168d603d388eb503488d2ac3b5c0d401a28bbdda622ac7ff9be3df7a1bd38bc55fc44b40fd4a5bf635fa09472e6a9b399ad6581d1be83fde110ecaa7ad1bcc21126b5bd69fde3a95e55986fa4f119576fc0e6f367aaa50d1e2d037e6ceae7fddc6bbc148f7a83c728f07b3326b92c51b7c6c93a4b0c9acee61b9175975fc30cc60920f22678ac29dca70dd19d0141323f9dbed01fec02516d03b18c8cf5daf50c6c843190576f3d2d36fbf4babce37ad4a1c481f1f4ecda0f1a67fa80e94ea96bcedbf21f16ce47f90a4a14ccca65c6bc897352ebb43c4861572380a5bb78693f2663f3049de0c68c25970493f9b349f500fe2112e90d1d4d88a0c29d0efb735f47d3f8bcedf9c4db2945c9415da5184add1b98d2636b6bc1b09b508269bf2c7cd1a955ac053d6cd1119d750f5f137902eb515b07bae069d2ba34e5a916412bf8df3df36cabd0e732894bfd3bea2440b3803d9739b3fa287ece9d5e059fedd45e58f05ba5bddc010b0bac3114857230e498becc4ad2f4cd4fd610cedd85070fd152410991840660bc5ad4630c9cb631e1c618d6516fcfa52a332e7be1829d214d9b2900fb6c2e0ec5a54831670d13a9c7ef26c497260d0448e6de7130842655b475d3186cd6aff150376767fc18d9f09329424d078f30a5d27e50dc1415d129b7b1fa9640a3e77974409655122199125e55d35a1c3ab7a28faae75e90cf4bda2615fc4dac8cd02ad6e691ded094dfee2df1af669be580051d0a89e98675005656ac393a23b7c6062c695409dc90e3a351d3e10f48e43d7a2b52ea3e7db607841523f374c1c97bf4a1b049c3aa678aac5a73a97084dbac7c0a29588a5d56cad1729c37109e1ddd023dd25bbbeb80cfea703fda2b1f3466ea021f806b18156db37f1c0ceaec4145778fde7c7d73536a2fea3ad8a146b59032f04ae90c7bd2b15cbc314dbe4ffa360dd88b19d2b308d40c52e1475561203c2ecbd630281e1c1f6d1683c88ee7a2ee634eae72b0b666706a00dee444689fb99296b1c622ba551c9fa09218994389cfb438b1c15d535460a6dd3d4779453d258d8be5d47418223acea7d6a7f6942ab7197c14462495a662c35f5fa4bc3ce871f08c0f2e24638188f549c51ba0e3eb7513fb799fe1cf6342bce3ff8ea1f9b853f17c8504bee906aaee5289b079d8e8b66d89a588df87ee948d967c16558629c03fdf33cc59165f6d88b754fa284880a21e6041c173361c442989426385f26516a9b9831e433bba9e26c4823934c624f9f947501de61ca8843b6b0a378a6904e21d8674ca1cd2e463931720ae3eacae86ac04043256dab928bbfa3edaaec0477c663c34c63f55a50", "151bbe2b100f5dd5a8d9a699b5ef7f9897a68ea1e305a689f4ad55023cd0aa7fe669c9d1e5a5ebb03b929ffefb9a1c49dcd14e3514841e4ebf2f7bb98237c72328dcbea86474a2df1e1db641fa7c59988a3c3fda397b770b281ccc9f00e350ed84bd66a8dba5d54bea59cab81961e20ac422797820ce2c9ad0be6f8fe49bc2377337f1614c4015eb764760971b9c0eab844e0be9644522b26520aa58a2ab3369c2f588a9526f408fd1250491aee2773884ed6458e3699edc5c32a1d7a1bc89c82cee6fb7a6d8605f84a43116ab7dc9f95732f7ea601dbd3c2bc43c5b18a7e9f76419c0930204cac852bdf88754cd3fe834c4687007baa711afcd42f3c4c06a6ee4940f2e68e38b4a5e6886cc5dda80725cb993ba1bf507a85f4eb5335a8b6108d5d3b3bf452465487b274dda58c10ddd1945ac6f753e8d82f16e257e9df5ba1c77bc73fd974d18479af30c85b52c3cc8f10f16db8052fbe0567871b344a05cc73ad513cccb2b0b36d7dbdc9fd9715217aa15358e650c4780a5f58062e0cb41ca5a01f95072b35fb685eb6bb170c199207acc0d7e9df7b0190c491aa15c80e401891d0c39ab8e6749c6a123bb4bd49166550845459582b6120e49a80484790a72515be9fdeb451a77e2fb109c58177de8fc79ce96d979389ab3d74fc8ba95959ada4fd08f9ca37960c3ccb3a6a98fc320ddb4dd55d84d40101b98ab9fae873d567f0180e73e7b62dfd1da1b36a688ec00c42109b1915bc9bbb06c365a2c5df1af53694f73dbd97e8f8fc4c9eca33c297e0c3d4091f4c9588e4da33521ce1907a2c75b8d16828851716290b2fe630f288d400e9015515aee23d4385907386aa1cfcad9eaa38584f15f31b85dcaa4042c8b11b478b75613dd9d5660aa2e38bd87b9923d60e70965a2a729283fdf17500a035514fcbb14000cef12a213c9ceb0a048e95182728f5d37b98f6ab4aa1266de51d235e3d37b9fc3ab5f8a42bcda7e75f09620a47dc6ce7290a18c754846e99edaf8a6e7a336a2b9c6931cd736f83f6e635b61f2332770fc0d298dad2b86ed08fe1b42d87853c753cbb69aad7e49b2e88ca2db80d97ee2f85892c4738cb1f1c35f080ca979074b5eb94148289d659414ff7f271cef28a09ce43eb63099832be25de4d414ecd2d1230b5d738777a1b89073d2f27e58351d3ed00e904f29fc17bc1ecc197d94c66a7ab5b28e78be3f52a024b7841f70ab4a81f608a86b6c68152e6b2f85a71d56b8870033116daa07135afee056bbe193a5a8015f7f8dabd8461804a7c5632b89373ea460715ae97e1da44de36bed515242c091a6b9684e9a391d4fa92fb7815b26d4479c76dd916cb6bd560af846533129babd813fd02ed0d3e992dc0e973d9bb53f239651a4ef6140dd09c7d6f7db2002e24ec350b10319961e6697f64e82983a91f08c5a0adf8eb697abb157db07a750a27c0a24a8a7d8ebd5fcd01a4d4d1c774808defb07a77f80cbc2d655bb287ab1096dc8c188938c7ff21a722308fa2b66aad0e02cdfa08e7edf9aba75e356362abef07270ffaed4f0a3c67804cc8c53424e9ba82cb04f1461645af62cf7ff4688355c9aa15617a0168ebb09045a3fe48cc2623c29588062f60b49407bbd307f6c1364481c2cc32f2f4c8744f00f4250ee35fa67bec53694eab98e70287507a24a578a1ca7f377635927a5171cda55f828219a2dfa2075b1b82a80b84eecbb2210b01eef57f9bc5647018753b8db32be233556ef518c8932ad9580e1c1ae03c14ccb10f55101ebc1683525cf4a00e2def5cba5b079fd1bd4fa791863f362cb07e25819ea4c29fce2ad4eca6f995f1c8c18d1778d8e518c314c182efa34fe38227fcc5cea33a103382f6db5f90554aacd6f20de8e74472a39d4840298d4587fe717dfed4263ded09fa8ecb46f6ece32cc292b61117f3854fedb0f6371af0ea3a2485acf69d885a2c3ef3ed577771937a8ecabba0893d4877e4a2fd6349bd6c3683ef42c88e7bc9e33eb4ec15ccf6c4b31806b9ef69928e94f29d9e81da2d2079e8d7d7c9d9d4543815142998eee7c818a5e2465908bfb7a7cd1410d30167a4a1d64292957ea153210d8fd3bf61da76c81b2055ef04ea5bf996c273daa6a4a3a48f562ede45efce1b3175a626138a096e646861708b1acb4c421866ca0a81b15dee3298818940fab5d755f7a53fed001079e296200afff472b14438c64c6a6c98b068eff5849d93de58a974b9614efb2afdb9853237a7d842532c677d957f1556dc8ee300b394cfede5bbb7cf6161bacb40804a3e5cab9c660b6909d5db6fa75b558351ada6525c3ae79a2a5455ebd1a74afbeb45a1bc18e529f217cb63e4a39fa6b66f65e3dab26110a6a43b35ab64b03c1c35d7ad64f4021b6a1e05f43ed2ff894091f85da82826b6e25fb6fbc0ccd20d039622019fb41f61fd304311ce01e417c2da9d7f95e0718b2e52aaff76dc46f57fcdd59e2dce7e81f66ad915fd6d2c899129fb222ca29cf158522d54d8551abd9ebaa160913152e85dd587b87d73016e45631a212a62edf242adbf5aff8fe69cc1f93aa51b1cc530d44d8f9dd03206bfbcf9614b433f9eb0b3141283ee4fee36f090420fc37ef59ab4d512e334c166666bda0fac6221f43c2d498d0e04c4e92a0025aafd42332446a57cac52cd51f7dbce4d3dffa296e9289739c96fa037e59e9f884ae5d527c758dc4d0e889f20ad1ba18de86cec80f2c1c64688ba8c083c00c52b2c3a047f28467d1820549af16588857a037518d67e7f53e2e782c8d046186a29d952d777257c9db9cc34fe817e356d298cab789ea43eefa2dfa03dda72a6b4b754ffd8ecd76baee5aea8706abc1b3fc6a2c77423b23f958cdecfb8ec429c6b1d56fe576354f8305e5fdd713ba0b2511dc58204b8fab201e590de8f2403f5afa24d8691f00f018aafa8d029004f8e560cf01d61a947a950fc008d45432322b0324ea4176df8ee179ee9c473eb5f63bc25966676b091b683ca0731d4b670faca0c82330cb7e2a757769f68dc3fae02fad461a0daf50de0b172eae0929c863776d7a4a8af943f9d94a972ee1ed9e9a4978ecfc0e439f755f5ed8d6c505d3527b665e0678e948d6eda8cacdad59bcf5252cf256c54bf412f6944e6e3859a3cbeba6bee70e8fa2797104e3e1e2d091878d28e9d6c858d0bb5af0d2234c6e2cb24758240a0e2b880f43b4d65d428e4892172a812ef33b25bd975d818cfa5a24fefd8c3805bf90dc72a5bde882e3dae1e7cceff0b4c786f5d449a25c0184fef94afe899a6ca43e70876cff8ca6f8c3e9d9122ca473cc485a3291f47d7ef3a70267277f7bc584687b600b00e15b65d6fb751b8ef9a16d3c90c024d2110b8c90ed389a498976614fa000e78cae2ea2978a7ae00b32b7f913cba9b2b38859113b6c5aa82f39ab645dbfa5f5e3d3caebab084e8f627adf888267e646b7a898ca72ec979a6ef94f72d20c4e4a5c8f2fb1325d0aded3aa0188923d94d216603e385824d7ec2fb6a6f3484d31d5c6cac27177c1e0664fedf2c3f410a30db831d3fdc57de1d72132f25bef6142d48dfa59a9fe6a1faec4253b187ad19c2b2257fde73332c321cd5f66ac34c4b7f5c6128bbaf2d2ae081620025c3c165128fc23c285aa09f01c99bb5cb27f90528710817ce01a62da05d7c39f4d9306ffac280232df635989b88ecb88c30b794dc7658aba6a0edeae7bc569cbb7a36e240136f495039475ca22cbdaf247f45d222d5ff60035a5fbef94eead12bdfd5eb086a9c09a1111599b4325d927a7ed5005301293496f63b3ec2265c37c31268453ce8bf016fde8b8ff88dfde633c7be88252a7e7af31864711e31aafe58e0f358758728df8ac458b7427ac24d1745a2a01886294580843cb21d007e3d1d9f03652268850f8890051b162510d37546ce59d5b581da5c59658144b00fd689a8622042c459923e89ac53e4c90fed102ddb06b984bd709d3552a8ec921edf90ddcac0498858d2db029ab7e550bc96ac4bb280559d4707cd75f3511a7b8fa97ed62df8fe699fd4b11f036126acf9675357ad125226e547590e3594621602302cafa6ab65bc167ca7a6bb1dfb9ae1adfc2d4ab72706d1204b02b45d853f7cb6f4e944040042479af4cf80f7393fa5f65a726b5ef0ba3ac2a33fc643057269d5ab35baabcee409f9d050bb413a32c3cdfcb510a145668722f831b6727d639e6113d57d8de5891e63891192c867d9364", .Okay}, + {.Sqr, "7b50f08053b54eee088fdd9add32f013c02b1d875b462d42a87cdbff81ce4357b04fedf214ed441391ba56bde9b0411eb9540b1f02b6864a139ccc3d5ca9db1df10f04794c6f4b37747be79e1d5b605412430cebcee879a334175448958b6fda9b69d39e55c7de73e95661dd3c59042a377c851f484e5acd49f1744ffc419d8202a3dac33b5c2942ce4d142f59203fd872c7b3cdc9c4c84b0840abd309e0b8a01a257bb3dda5778afaaa83a2b6589562f172fbeafb780d42ab610ead3f496cab31fe68d87449205c3b1482871a8ff86bc82c0a174a190efce6317a2f854ba85ddeb21c22e2f6a7aa12b7cdc89ae6f05d1209a4ce0b4bd01eb607d935b5b7ba841fcde8fb2f58bf065c2c88a9d47ce83dd7df301619be30b0b57c33c97c2e512fc464737c1cbc85afa24cb5115495ab097091c1cd4a396fcd5824b6bbcf808ef38556b9d0cd956ae3e076e2de220143c8ea92968cd5e69d5f483c1b62e7c87c4a4426f22e2b2c13f28381b9016d3b06e3b2f32c9addce55c43c573800031f21abe2eb4b1dcdfe406fbfc32b4d23c007bb12451249b298ff5efb19ad0e81d3b2d7d9e286ea4943b963d600dc6c12ef1e5144e4d92696de180e832e087aea1a641df3832586b0600a1af94632923713299b9cbc9064abbe2cbf378758c823a6e8c46ff32f0418ecfc38c08a8966bcded2752e3dd53a8c96206f4e51f6763f5d3b34a351631210de180a603bd740007545c4caf29e8389078c31e27ebb0325e014745abceb3a53d1ad140a47271c98c88682fd5cc06caaecaa0c6fd5c7a074d22972542ed41e9ffba1d8f146b0cd35e9fe5a9dd7e5ea7af2ab0c2de5a136f5e29e8b4e5ea3d75fb94233a5d1c5038d82c78c67dee45543023eba5b80d5e300b4c53b3ee1bb1e68d118142fad5b3aef2a47984ece5beaab25b33b36a163c15ee2686fe7f1f2bf3e18b8890aa19428893181aeb5a8d294f124e327b45c192ab3bda9fb330bf9438d7f6950e67132b48707612ce58f9c816300065b57dfbaabd5999c4b339c77cd7baee96da020df8193bae89d23b99cf079df2417bfc22480ae4f98b87f703f1ccdde39b04378b3ef08ace0e606f7e5e4538ed41ea7fd10e79e61868de975aeccf049bb263462d5fda0762b02810c3d91c111c399c8da28df3d0ac38a6c1f25bfa846ba8b310710bbf2113c172d3748ad044f66ac9c39e804a5de02a373945df344d9810e2b5b4d4baa0cc773bb56046f49580709a6bb8816e13de4e9cd4157e3f09d70756f19f60af7a8893241099f4d93f4bc9424fb24e861e2eade45c096892081e2b00427ea7beb2bddfe930e4c1847d2b6d1d794773806fb817e6fa3bfe7f2b18f64c72c14bb7e112d65dadc4ea6374770b045eafce377f24d561b84fd99e33aa4dd2e3d89855c22e6482da1aaa00bf437736f3d9427dd027a99dd532735406ed2826fb1d1bb8657a160e76c92a5971d2d907dd02bdf06e728c0aac92dfd17919cd5800cc570e7c0314075e133ddac100bda3447e654343194d94662b771a3a8d0fe1bda4c3b925317bc3bcb05a3641918514a1baba6edbd027a6434549910a829b23cce0e31e2393cfa6472b626e3881844289a06e194efe66ccf2fb32c00f0132db840e440138d212fd3375c1ed3469a4636ddbacee35bffdd4cd084573e28377e056a101a6cd1e477b9c76884f87c087b01230abd59ce52fde1bc4ff7daad2fa5bcf3d25f63286a2e25b85759ec1f67140d00d47240488bc84177bec9718c3a9628dc9ac253081c6ef3ae20c86454f1d60efce3425bc46c92c329c27c0049918d99fb9753f84651eedd840f8ee5f605b7124360d0bcc30b9a0ac14964b528c2eadde8fe5936b1b0818649d234e6f73a6ac4e699d7cd274c5fdc328f1622aee491ce82a5295a911b9e29e32a34053ac8b6351593927d8ee98f1d167fe6cd3d1d7b24554762daaf78b9997a749d2a9c825a16ffec900c0a5db6a44cd976b9e507f1e209713ec2c4806203bdc12d65690e7d52c6b7341cd446363baefc36a26abe327e1c5e3373342412539271cb574b42f985d018306fee4942556f32fc9cda381ad4f56aec5d1f159e7e4581a35faa0b13095941c1", "e5e167f1228d8dc7b5715824160c79c5ef6f44ccd67c00e0a14d6627c11aab9656d19318e33845becbe88dfe6758aa363e3f4646704836f5885607b442d0eaf17e8a7678a9ada67ba9936e79becd6ec0de05b4ba2430deace32d2afaa32497911ad54b772a10b728b004787feb7a252600b62940bf73d3a869568852080d32d5fde0c6f8b23f900b4302bf5507699d93c4b7f197c1361e1cb7201201516b1a50ea951ada822a267fe36627c4bb43d15fdc71fdb7356be29699356534994b1ca3ba16d084eb95591910bf17e026b788cb762a58702b37bfd72abbaa05322a4818693f2a9fbf58fd7ffa03f74abad615bd070c2fab4a3281544d57e33d2a96790c35148b4edeb41cd0197e6d617ddaf7c7ee0dabb09436dd87645e960f70a76c3b48ea78ca334c6cd3981d664880f183a575a5a8cb104a8c53e6d2a61f9fb801c960a2f73324bdbb3e05aff43f9dfec3b02c957864fa58c4a31eaef15d2d26489cc97ff0f053e92fdce8146cc369549ef793224631440428c3ff126fee4affa47015e2fc44387825c784133a21e863da3bf9dbaa13732d558aa01bb5850258b233511b1abe084fafa451a53075d13a237acb563363bc189c118e4b9ff524027a2ab97ef78f0fa1aec412b034a82be89bc0b096c2deebbe9c88f5a0489e822273a6908276cd1731d01d4f99a128af7c631691a6ff4c0cd30c11ada0c09cda68ab7ebb1aabf7ff8b9abf08e717cedcd62e305e833d2aeea2a5ece8ae5762d04032eaac794624906879c342e10160c62c90d9b342aa07fff075e65876f947e982962c7a449c1c016fb6d97f89c5e439f3044933ca49323845a92ed21fce0b3bb490b2bf1a80fe6c7ab920f693a1bf35fd7f52f66516256d28307733a21e628cf0af154b323535f4510764210784dd457456ffb086c110d3b2a78bd84049ca2e82bff429f3adb0c7a9fa5536d61d5b0c0586499cb6a979cc45a7e07c359452d716447ebd1808a77f924bdde6d620c248fa8b4ca109065d1936d9d8ec11c0735af06e1d68f0e84327b46e8e539d7eb5b8cd037eeac9866996b33a4ac22bc03bca59a67d0c0e726e4cc5363484e21a8e2e12ca8eceee5bd9ac7a44df086b8d51f857727d1e2230a1f6a9cd27e7f4438a3752136482a280efd5556e4ec40360643bfc8d1c761629ba2a6005c77756ba40239c0ed0f0f96e2bed6de82c8a6e40adc4038a65b9c5ca4e888ea96aea6a633f022513cd992ac68dadfef8ac520a49bc518a1fe728f8f281faefef3495340b8def46b98845eb7a38b61da42ce5a285baea94abadc4d4c4a88a4d72f23bd5d76b7be9ac43fd9326cb7f77bd48faeae706e1bc6ac2dae9dd9fadcfc299bf94478c5bb504f9ad4c88dd6a567e05ec6c16f23eb0be19aca5dca953310475a8a8248af167afd278e3c3f44c4e925bb17a438ccdcb2e01155533acfeb2b1bb53ef32208d8a11ccf95d1ea5712617d902b9eea92d46c79b0785ad30c91442233f60621bed3df137c983c8968adc9ba477fbc3f00f195463898f1facc4411037f67aaa4ffc9e1531348f1c72db6b4865722f266b5a5168455cf37420630b96a82f73dc33db493380a73be17b639c8455b12f676bafd8bb96ea47260c38cd210f33977530c1f17077d90e12f1187e1765dea720e39d36c729e1400c2ca59007c1eba9a27a5e42cb50b96df9dd192acc21f25529abb34e40811a966fa0bc0b451323191cd150093ce66e0e4c0600e817399c625f3a84ba8d3cc777ff31b76f689aff9de45b82a8345e194c236c621ee5d8c5a382c7de88fe42a27879584e16b18db5238560048f9134cbbeae031ec95a3fdcc497d85602c5bf515f11b8afb746a5057965d1f2a0e4944bddc1c32f4e8e9912529bb7dcf7e69bf941d99eba3fec2fce917c4c82f5023acc3557d08a914bf9a5ee9f13ccca12ecd2c10320075e26d3ffbe9a7cb050f70c752bc881d5eb2212e47686b78742400bcb379fe8f63e4bc397ed5cddd4e84ff3fac1b8573d1d0877e022bd82cc69021877890e9a8f0654cc3b37af6d2dfb08f9ef482b29da2d00c6f3564cc2e0685da390d6005b60a090249c04f5025176a7fb3774ce8e22e94e83a541a716", "3b66e0b282956871d5abe88aaf347bd31b5630892900fb4c945ace1b2dca87aeea84191690016f22d6fcf33867abba94bb174a74b9f5ac3f05c02d9ed925952051647f0d54e46dff66f54b6b11b9d62ecaa342419e77f26a1bd46b8d63a3cc9bc3f1fbd316cce4990477bb13542f2ebe13402882dc113d347ab9f6e4008a3979d9b59a9cff59ff6c972cc020e5b490ca4de6527104936186d84f8dedd3d26c82b320594f56b6ce0ebb4caec6b3c9d81250a3888e40e58322a0c834b4353e93fcb72eff70c3129b2954969da0b0c3a24c802d41c0bb147fff217951908d9a9dad000213dddff0ebc09ab61ce031127568bb905ceb8de4ac9da107071e0750a6c2e42d1c354eff1aaa2bfaee47706ec5d1cb58dfaa96bab3cc0089815d46984be2dce71f0c55e7c37b95ccb5b433644bd1f1e3afa1bcff0b27ed6b03d642eaa29e2fc9712091965b13ab9c1ad5fc59ca2631991dea8e917274f0eef732f8aff40db52dfb1c9d010fa8a5a239745bb066ae3e2b4a748e01d582525a60be762db479a83123b0d719d1e98e6982b667cd851d44e34a28ed401e593e1d7e7c37f9578c6af86618f0a1bb0b2f9da3ef1f2a36e3502c7f9e94580fb473911ed9c1c702d2e10c6798ca5f69f76fe8a09d80d5470b4ca737f3de8956dfd65f4aca9b0d91ee262cbaf57aed03659d424a91d0580cd367ba1c1d3a2ac5aa370904fc9770823ab219ff641c4073a26de619a4b4da48a5005085e1523488959be41413ea8ed681885b250268b4247a91f837121381fd2265c2952d5dd8107b40632762a34d122ea627c6133d7e9897ea95b3de9dcb0752ba8f1b5353f3a7af8767958f18a5a97130bd0ba008d181f5010cbf0341a2176aec4cecf8e04ddd4cff7d77ad2f48a666e5afdb69c9e220125d88e8cc4fb3abc0b18fef6fa4601df9f5a2c7d3a734c96f9598eb3d2a8cd3a3705bec0e29bc95941b90f9005ea346697239624b2acd9c1c63112676a94629d10a12e81fcc5713354e2cfcb96f95847fbc332e065c536b7295b3da02fa35b8b95528e0ce8ca17091bda8d7ca16eb937060204d25022647a3d853ddb158fccb4efd11ddaa5b6bc7f9b007bd1aad9d6cce89ebf25fd971c1aad7830aec4c0e6ccd07c9f1226c78b1fd48c80242f8af124b0f343b0dcc4b06587ce5c1dcfcbeb8510679432e39a45b827a9d2326759e893ff59c74023729a338910b80ca608394bebe6b679ba37ea5748ec6b18515e6ec7f41ef6375e4e0324185f289ef6403cd4f5cf214e09533e601feeda151bcc7eb29feb2abdff12a9777067f078336c5a0e8a05c00b415e9e34d45cf64f3980eb07aeab6f88087f63377eae228e84b7c7efc81cd70c2eb628297df32a5b74cd2d7754a047a3fb6e326032895b39a0d1a7df9fc60cee0ed922b9d952443e712baa4d3ddf8d622eebc921286f9233c714f5f90f662b59531fb52f073888aad219a22ef8c6a06d727f91f4a769815e275e950cbd01a6875625bb9ff2e8fe36b6511429c0d053c301f4139109d7ee66d9da5f0b4987c7d6117fa3be51927e19fa67a4261814714df533f4e9b2961e2339316cb9afedabd20f3a20119ad45127e000fa1e6ebe012b3a088513a6148f3bf517190de6b19799ad2c507a4f8f9db0ad2f3adcdd6c4e8e5344ef257b88ab454e723d07afa7818384eabf772828a50b94cb34c821aad789627f39fb1466ccdd3880b262c2e26e21b28e21a7082a00e4d63345aaa12bd4009f86e2761143000bb7c2174176a89085e73f662ced73b297403a6f99f2664bb80cbdea56e74b206b8b8f5dfc5850e4d259c93e9eec890a13d89bba616a273190f1154581cb4c6559b1bdcb0c83ca62885b8ddebb51eef84450090192c83cf4bcfb75cd40f40c9f357cdae3a523cd4b0e710d59688758cad01f0bbf6f0e3d52f5b2d291bba5bc8c8af0022e10fd82b45a61d859feda358e2bbd60a34245b4d4997abb5b2e0735b56401eb03c059a11937ee344a31adb9d882961cb32bbb654240c5b5fa5ec133a8463d30c4a7a7ea3937f195a8b1f80569ddc336872f3afc8a26aa866d44864019177ae2cf910a49ecc8d9eafb7ac59ba5f01cf1a976ab434c484b34a20ee28d11b0400d507d2ed3ce00fc0eaa4ac730f040160912a30f0598bed154e6796f18fe1672b3962ea688fc2954485e019929d047a158c3d71d3fb9566096ceefb22becab6d0da90f6e5d09e1967c043f8f4cbdbed3da3fbd9b95539ffeb19a1b517f5dbefb75dde4ad587da9c7bd1b5f63f9db8fb3627b769a659f8d83ba83167d6c9a85283a06e368064fea4d8f7fc2277db6d1b4ac6ee50eb16a78223aafbdc0ac1414531acde21d06924224d17c8af147b0b8e9f17bd33323882b2996cbe2bb7a645b802a0a7a66a2f6432db63d83463c547c98afac37fa4b7d0b507f5e761132cd04503dac3cc49848d2dba0a7a637c9b6b403944d38dd4877ab595a469522e12f8a219deaf075ef4282727464798fb897133f0ae1757012f30b2b6b97c13a1c60668ae7b814fa4c828e45da9e05ef90dbd6676dc0b794333774c827a2eb16a6c7a15c9a5bc94ee95c763cb3192de82aed65a9fb128a34ab77f7a8f5d8a6ee726f389ec88608ab887f0b40fe6905f92de607487f298c0fc60efbe9f35fa815c8bcb65e21c056fbdcd310e1ba6f687f6b3053601a7fd31acfc3a0eea9fbbf6a9d4b42681934583e4440dbae7a5d370379bf756ebd051ab42a7405e992b94db56f517fc7c680b9a47708787da4da6a561f48ccd8d704cc2fa19134be58f39b211061bfce7e49cc2f802909c90065d503f20d2b42a811868509e690402b12fd2adecae6870d266203d153e3fce2e6f741cd5a55a74481eac65c504d8c2c6d192bca5caa071fbffecf8aa0bdb12e039cc5af57f25e5d76e79032ae7a28a91cba7460134de6aefbbb487aee63fb3e1ec094b84ceaa1e523d16baa3c389bc5d6bdfeec33b20237f8a8484d47d3903958f3203c0d34609fef8050797463a245fa65047a8624c0c905fbe92017f25fb9e48ef55457c532252ad5ac0e81cc814a61af42b72613bf156284530419d47238b9ef9c84f0ef5fb34359df2f0c7ac15d7172852f0d3b6c1a25fbc53fa02d62253f0d27e295ac3f035d3f790e6e977ddc6bbf121ccfbcb19ba33bc0afae5f799fdbbf623567aba546f86eb9150ba036c084204fb1a9e5f7d6a9bad969bc8aa52d9910f917b2df4a9b6211993ec47464cf71efeab2c89826e178b70687193dad77ea536e8a40c277e396136d69d0377e30e44f4069b9cfc03f5b13666f2ae99a5a1c9a434aab316d42bb6c837de1e97579f1b141542995c0790d1e21a7b3eb60b957ff6542ea49bede0396820b2feefff2d710db55652b1e9bcf11db99057448cdefa14283d7d14a050ccd06828149a591f0bc77aa6fa939ac26568ff9b348bc4cfa9ce377e6ea052c78b6f71282b62aff7495b2cc28302d840a79673591d1bb95c50cdc765849505a26c872aa4dda8fa21e70be7a592552a4e8102d7a4ed8747ace63393f6f7f7ebc91ac37feda7fa608b868de9f981ff93e447d3af6ddf96c58d55570ed1e7a354d7321dbd9abc5ec523167cafbf9d615da03106cf63f26200025081522ce825cecd7df2bbea07b3b82b3bfa0d0fe14860911473ca03ce8f83c51dd583a94100387aacdbd3c760d1f3753fd596d0d5d3b228297fa9825136ea81d577ef3114539050f95bbbf2befbec511b5676784377ce5be25276aa5b44feb2b5548bf5e8bec665adfdf5f2847da459bd9cd6be1bd9090274e0904213a87afa74b5a7f3482b1e6b82332c925fb67627529c04926813355193360f16c6dde2acde35a65dacf1b4234c7c4783f169322e6aaa3a5952e3f64f8ef983e55f7ed89596db3baaf2298e2b7a1623cb28be648c03d61d867c20d91f13895f95d0389e2362b5b626be6f7dd40560f6a1f161d7c188fc3156fbc669bf9d595ad095d329777b0dcc3a067b3f4987c5f58d70ef6402373039a58226ef86ea15aa47bf3542d90c9ea55516f98e4b022e4e85f94798066d9b4c96230851901de0fc61c008bba975260b0b0f73b35de2be03c221d49ab78fb806238c78724357334cb89a51a00fc44f12c4414ea158911da0965a5507a3c6c6ad5c9012a9fcb0f0d40b08da46d7eea7e26392678082eecbc57617e0d697a633b0a1bcdd1f6ffb81609ea9e820ab8b56a191be645b159381", .Okay}, + {.Sqr, "5585ee6ba15464a111bd2e144e3808314687a05ab69fa3b3d8eb3b2392079822b6fdce475aa5b27751e45cf5cdd695886b5a49994f6b422fe765c875455f014a67203a96419626f244c2f07d7c2a138940afc5c4d7b1f8a6f835e0c3de8fe2a5b73ffc3372d3180f424a79dda40716689af8ad7af7fefc521b9f0b6d83c49579c80658e1634f8bb29767ba829113eab04c97fa644fd00bf1487dadf6a8eea4bd4ec5ae47f16988587d9a464b246cf89c3f3855399afd55e2b51e6eb00a5161031ff3cefb6f3a05e113d05d69756180ff2f21aebeff8183034db4035af5b0afcce61c9b80d07fa3c11a7acede2b937a8ed8787c0def32905877d86e7a9d3073f9b70707f5e6a90e76719efaac3fc7a11cc2cf7fb3cf1eaa36248e81c72141e18b75661fd7b25b4f8ae8d360ac5be163c5f8e0a651f319ad9544716472e828a5fa726eb18b8d64cc4b92deed228de38019f67fb817123ffca66a5a847a0ed4d84e1ad787036ddc80f6d7a85e5c1f0526b4aee1eb4737aa41c0a828eb5fd097359e9a7f2e894fd9a64e1f38cff2119cd6c0adaf76050e0f996d9286e7e25d64d7008bb845364565f8d9e09c883903352e11e4969f31d08e6942353fd28900624c6619d2593ff786195dacf24eeeeb231ed94a0301c394e75e550e8cac8c55c0c8f11551216ab073b4662bd9edd3ea8ccfe3e048c96153ac46599b1fd97123b420b0fa8764b433fcc67f882910a97d3bf9887c0f1e4383afa6e4b030ebd2be94442a6dec55a461422e6d34ec8468a649144c362711921593ec0943ec229016c8c06d0dcc258560353fc6254fa26861f49879a08e346db4aa62110bf3c472188683d56f4395df0770fc4134ffe62f7a21b8946f418731c3cdf37b1fb0a25429550de6b16f27b12ccc78d5dffe2ca74f94268d9f68614a1d38e6f11bb5ac59fb56142ef09ede88c81f13dcc54cebc7c5c70bdfb479d8fef4f7b276aeb1bb3a45d487d031ae8d36852271fe5844460b793e047880f92d6c8240cd7c7abdc1ccbd9e25c1ede0e4c3f26c2eab42ddd7b60dc89acf758c4c2cebb47d616c259aed5f7037e1ac2db3bc760539624e0ab17ac9232995d01c52dedf74e6273b10432b436ccd62971dedcd95c4f70d4d76665ea2a28bc62617a27c93e78962d5b397ca56957ac686bd2da8eac667ff447de053e6535ed7346c60f8f5b6b5b89d0ca0c65330e34f814c6b3fb8d5ae9725077efb03b251c5e6920fad91b5bdb345b46d59a0f466dfc8d3ed29b38b6af99ad2aa4534d0e3a4a6912bd9ef0195a78b56163a2263e52fcefaf705bef3e74845c33bf35751d11c6cbced846d4a31159e52d38dccf185ed74b9e0222d409b349b60e00696d68547aac50b47b511edba56e87f18d790cc7ef0b7319cf9b20da2a18913e3128a37cc3968108fde33a790cf21c64052ef5abdf8bad6222eddb4a2e8612ae0b410ecccd83c84a9d09fa18045ecb8f1a7e0c3d9254d2d052de5d649be7499c2399e36e8c1e50f751afb850d6787d4851e80dd9217119d09ff7afd5dcfc28b4242d9b083b208e0daa4acbbedd3a341072515271ad276023d9dc36ab28448a1e47b6d9e7565bfdb7399f97f7602d50a5d614fff32b984ef77c3f428301edb67924223bd7c640625e2c5a1054361063672a139857dfde5d9d7266e8a103a517758f32822b49b061cbec7703a403545713143cdb018c955d470ff2ea5233add0c3a301d3181b7bdcc83ce00c9f82eb9ce01278f383cac73a2e6398a57e24c983ac5056501bc243d10e935a87ac55267ea185c6d922e138defe7db6736626e578c53dde75a000a8d48d39d8168979387e04fd1b9408c1d4a27997964dbe7fc121d410572d7e00a4d54c1cb1aa8fe6698c269ded8bc86993074d7c8bd2271ff3484bffd316d4f6146e9512f6fe18637b74465c4803729d0b08eb41d14d745a1aee82124ce86d89046629561356f2709796b96e52af86ae3727f07896752b36c7fe5e1d7da6385342e5095eefb820e663b89804d69af3a79a76fcf141e67a7ab7b05d8ca718c6082750eccb584549e6a49c3298d14318e7e2c0b3f1d8f25f92947e1ad51a8fd408d09d8088222c29764cc4be6", "93b5db41ad1d49d986c44ea831bf1b24dc9393d5d574fa81c215735ea48a8c4dd24655d015aeacdd778c9da99f5b9b47691d9c4b83bca1b966d96efee3f86ff02624497719f6cdceba34bc2e1202d06501f86bd9123b256b44d78e093297f3ebf7c9f1abf4b10d326cd8534c5a4914e2deede4ca53a984818be519e6f362240c89e6ce416ad27d083f46d34c91a7447548c44e45ba8d7c67b90ca832ccb28c4c268f3f09dc2b739d63fd79c959a84509597047e053f4d537ec032a34d6c989a862658bb29fcfb0569ef1f7d3b4d3c77ac5b027d9f70923948f674bd59dc1fc66b1f75e70400d22452ed803fa73f4fad51f93c43b774e9f4c567f095b7ee3af26dded1cfc8901cfbfd4b9607592017f7a434eb81000b045c4d61664f40183e5e8e585ed29745a3edbf0a89afb1f38dc8b86683704072d686586d1b0696bbb635abe91a6ea38888a0ec144258c5f8aab4884bf2d0c5d14def76bd6c105d465dcb847359986fd27b77f95d27132cf14816400429110b6e7c4972c2367ee23cc5dcd242b4d7e1525063945d7d467ee0b9b571a889a34300e4f65b7a1e5055dab427d71568fe16720c9a0e19ab0507659aff64f1af357f7ccaf49f702789a2b85edeb71a806fca7ac27d3ad93f1382af4578c87fc240f0f9513d24b4c32c5a19c239757aa34edb30eed312ecae34895cb87124079eaf1ca8d6bc14340e49a03aa6daa4cc19bd7b2d931920380731c4a15c8cfee2db3d38ed73d7f8f6119b6e6cb753211f0005d1df1872cd346bf822939a970533a642d82ae1fd9a1a7ebfaa570a909ae72175deac19faed546ac32dbfa86f32039ae156eeb8a298935575705b9984333c193dc96a46cda801f30929dab02d602cfc92372387d16f26477a5998c99f0177fafe4abc31cc0e3f1cd33c4f480817913c6f55856852f7434608f83464d7bd5fc52321191462796ec6b84c8e492ff973204941c79fc4b8cc919295d4732eee4e97ed5d614f01fcdac266540be1740ac44754cfc2e66a9f3a3da99614857e60018b7253301e4fcddaadc5f0f5daadff5bf995873e9ae82db8420d666cfb09550d0de81e629de053c4af145b91f699c8d2def52dd511a5d5b003c44f5bb171549ae86f4b59a3e58fdb557551325daab2a69e169467402d41bea2d5adfce9dd84b7d2454d291216723969e208937af8a381c59bae3a724cbea166f33544c51134e61547c7986aba55547493e562b217fb3194884c5f76d1ec160f841052e70fbd73f3652025c5b915c7cd74474b606d5e778d6502d8f5799eaf32b8957c0055c0ca682c694fbacb09d9ba0a1fcdf2f69c4cb3df20b65435a1b24fdd94ddcb79eab62350dd0eee4e863b1c2762b8d377c17e4f8e0106a4829fe2c158f844effd5d7a3805f183c31f9f62c423a1cf1de406c9d6dd66cf338f6eb65d0163a8bee60c401ea55da02e023cd7cc1204974128c3b52d2c27157aca151ca7c42f9ab1e37de335b40f204c15426f1e9fe4899f2a7f82654c7e96ac3152a238cb2cae97700f8f338f1d0797afb5920c45690a1522af1b723357b23207b41cfe02d94943cee64a1e784050b7752ab13846dab58487b83ea19022bfd73abcf270ae62e149f4ad3809335ab2ff8fd7335e5660264133495413db8ec499e56370272fe63d956ea7ff2bfc205ab4ec6a8c6b21b339e82c3df8c9fe52d5c93e606a0e0c843ebccfde44096b9edf19b5f8574a4d52a6676acc7f7f740e39dde4151e28043ae97e550530fa6cdb7cec3ca99e422e7d5d38d5e5be1f1f054e76b5f62035a3e9ca0e345ebbdbd50ba30bdfb6206a8fa902a84aec35a2b920487cea6035cb9a1dff3e3dc58cad392ab93ed5849f0fa36592d864382f8c2cf1149b215165e38faaf3a39b14f54258c46656b29c09ec5bb49728ff67c8b4fc42e20e99a185eeff1a2a66f7ec72a427ace7a66a8ef4979d196d6b1ac9d8921c78a706fc4b06f0bdf306f6bf46f31219d1fbf5871086c4fbbe2d785a188e5a7a5da63d51c8aee58575122bc044e0189f6670239a624fb40c3daf729034f573c75cfc0bafdcbe0dcb8d7f83ba2be1356e6e5fa29d91730a6b6490f5477140a99bbbe85d68452663229", "1c9236651303f9bcb276ed30bc6e9561b3001f6347a8674e1d9564ac0be820d2fc6665ab6d8960a7ad212348608150819a36541b2be6ffdd2a48690f489e4c8f5a864dc1893b212fcf3e7fd4f9fbae87b1d71aba5ba9b7294b76fba575f456dfd84a19d56d7a3822d4a68fe983cc402962d4455c3d776c70436db30a082c8eb105313f8dd99b650a218c71dcb2b9c8ba014547cfaaccd9eb7d9bb913d0defca6d7279e199304b5f511aefe39a3c037f664383b97fa4bb1a7f6ea57a1d5d7b3bbea2151e70f4a8269ad8d6754dd7dba8207c2e98fba258fe40749c30e34a5b9c80519286a904af3e3e6c6dcd048aa460c1c03a16f8b60f4caa9456281d75c0d53f79286fe9c581a24856b61a6a1e9ef05eedf0d0bb3844acd8e7802025d3bc40fdb40576f34a38b12d8b58ff0237b68a5aa791979ba94b571e86fa8b6f2d80460045af11cb4b7d4009110897276a2b1f0845527f84194fa8c2bd4603b0743da7007c30dea7dc433cff443e5fbd1902c560aa10d3541205fdb3a7231de4f8225cf17ab0c45c2a9aab82d706e72b0b7cb5ec3fa3e806409ceb78bff5b29f1aa2a3327870cc8f866a174da3252ba0c2d644e007fc7760f839ec8c35cd62c678a26f9b566216c21f6f510b133cd8269aea40e89c594357d1023e1cabfd83b160d4a92365d9dd4bf33b9da6b978c5c462d67f31e63cfa6a39b4b478d1cb41040b6e012a55dbdc3cb9043595f561b9ce947c1716c7e67b3bd7f85ad62ef1a2354e7aa8c15b0c01bdb39a503e488ccc4bf20947a3bd84799de675a4323eafdb44390d6ca3acd2f54a7b15aa18a80174e393e5e8d0d10c27cd9048a5e877dc415148a8179ea710cfb3f9ecc2b52d7adbe658e9009542d5b1c9b78f6f246e9f97f474ca94a9dcd884c5cd31b39129b14a617533aaa3d0b501918e7a970a9a25decc59792ce5df0c54ef9bcf2dfdc7fccf988082ceb21300282698ff42c30d89e2e43920ef3cdcc1f3fb67b4a298e45e3ac1690bcbb571f62ed073e46de1124e075979195e542d81e474ba790760dac260c22a3624c0e6985ea220baeea5bf63fef606baa1b6776b689daab5a2a2f7ea2b268f935547521136017dfba0933b6697a1ca8ff7f454773cd121f14ccf31a7f5115bd02c87cf1639bb4105d45a769c98230358dfa2d4aa3123c2c38f58b19e35b19cccdc32d0f899c901c73fef504160e06e7e4da0e9dc005c67dc9cb2df998491fa5b4a97a9bf4cfd4d475b47d04580507ef97c6b1406631fba773de37a2049c06a6eae3f3868e77966b914fb7a887fd37e06a2bd8deea34afc8b31a35c3d3326021e78a5e5f5fd730430d12ec960514e0795fc811e769ef389ae0ceb554a28ecac43092606ddf17a463bdb8f7cf7e69aeb284bdcd29a9d67a9f258e34c7cff84978ff13be3025434dc59549966f94582813ffc62b67da1c0043eafe693d40113900883ffca7b4e30258446a0ffb50d6d3008cde0f118235e55161cc31f3928893a0b06b28474af3f10f3d86177a6f3ab8eecd31f714218cccbc83cbf891a04dda3313404ed81a6260d75000d66172d400b652a91774e00022d63f27693fb66accd4a49178d6764551505cf5f69dee67b6420bda9cfe898ff93f0d949dae6d3c836f5b84fb89d36d294b5fc1a3c12b98cf15faf29f43bf5a011cac1725d48bd605d0964abc9581acb077c555c59c2d3eef5a30be993630bb6151df335e925bafa1c4f4a17d84b1c2e04e3bb3f31d2cf973414cd064b90023a3eda5584716c711b368460027dab0019e78d7634993ac9899cc68bbaa6198077e8ac2e292cae7d0f05716f3a3f779a444bfe6c27170135ab9df275219676d24ffe15e75254c17e742ebb3eb38487adae69d50eb7998d1f66cddffe19355f8c67ec16b8fe02a64c01ed5af4e32e32885d4a7cea9e78b93f45e726ce486d11590be7851bfaea2e1c9d6ba92d6381a8e3c79520603fcbf48e7f4eb87a0173d42f2a7ae898fb1c572564c2b96be53ca3cedf3b75b3df59e80ad12ed0030c10faae3fa8e874eae9409ae9e53001917c3a9fb426a51f6e55fb8bb5db5e3e804ccfe5ffaa560d10e61fea648613c0cda53ddfcbcde54f10abbceacc766f98b94fcbfcb4e8982be31a32f97684d1fac08d0fb23b2fb3e52e5929275a55621d619ebdd82e13fbe72552293835915900fd92408a0632915e5a5388e66cb3e3abe9f38be9b58cefe8785959a8c5f4e2c19d85f39c9b464eb221c52843bfefc17a22858a26d1da55252c0bfcf1f40b3b28ecbf17057b6454ff39c1f46caf0ee4cb49c0a4710cc97383a720ef2a2b831ee0e54222f14810e7171c2408d6a7aff86fa28c28f528a7aebf3d2cd8105f3cc62211f55c2b441c58cd75da460048ba86c30d15afa0e52ca0c041d0262c606d96975b9f0e7d68f0b08d05b4b280671e175f86b3ab3903009ddca1ee7619844332413e40f3ab9f50ecd42726f3eaa6ef257d547fa440ed0016a340aaf3c11d77526da7707ae7c48e5c11d042e29da67c1abb3c838a2fe8d230dc3eac34c4d0a6190bbc4a369e1874a544c10547544c92f32bdf149c989facad37d48fd59022ace10b8ba91687a8e17feb60ff4fedf0858c9e7ffc4406ca06822987f5c765d1e3e044c7c177103a5ce3ef7da0afe5418c6eb19a67f3e5977873b59c8ee7961527123d1ff654bdb84fe583125609e5ba70e7dbb95e993de8c7e61cce78736745632a39f3acc6e2078f2b77543018acccb4ede8fa6ec6ee03c3405518f529c0cd470bb54aa84598066637d1de67c5923ec307c7868ce3310d7e175ec553a35a75a0f884b2f3e7463dd84647476d4204f3027dd5be4ed81a4a58ed0bdbd3fec59498d957b7dae5d974fbccb8d228b71aace2fbd6a8f37b6082cd1df56cc3f338566a8ce4e01f650a3ec40ff6b34873cb23bbaa9aa1242bdf3fbb912be0a5cf225f7481981cc692a8553604b5e51914e7e3f7969ea8d35a2b7419507347cc8d5468751f9309c8c9dbdf0bc7fa1d899bd67bae4a78b51d97ce0dad36ede956090e3973665f85a8cb14948e1a3b75dbeec9d01c01632d9f665ef19d3d4b14d7b01d26531248857483e6117aa3588f75633c8a5afb36283427df4f8c246a274a0975159c54b33b1f16409b48fff21b9f4a37e29451b39e4a56be6f10dafa16f80481ec55461595989c5a345d2ef9796178e34c1f8ff20ef62674d9b4376525bcb903ab13904fb74c9264acd1d61859d0a6abbfc6fd2276a3526f141f75496f9d1a3b3b3a95f490f65d6250392000c9a8b2ff2ef12174cbb8d5b08f753c328722c9c08cdc732892add9a6550a177ca8ed7f86437515d054caa5c8e24cecda85b3b3ba42e842b0bf765bd1329132dcd448ad5454e479c1bbce8113663cf68a80f8ad00d72d66de8c32cc91da143cf161afab48436be182b83df06c62af6c9fdc0124bd6c16f5c7ea3a3c0e63abe15db80d82c4b25a37e40ea4c20718b9ec0a11e3329a11f23401093565b7a60f588eb32c69567545d4ae7b218f720bcd274f5972ca5775bb826da552d788cc1f02964a8019c86bef647907fd13f82f941641edc35936b71a639631dca2426a93abbbba4da65ddc059ffb7329ed16b0653e7dceb468983ffe21df490cacb488119ce766e28e110fb9763698ce83e3dbb6b123f068922a4c3d11b287271e5b2d4cb926a62f22fd9085b962545b407385e55cbdabfe9cdeca7253da3953ad6e33bdc98831b1c3be00d04292220f29aefb370057d1eceab84b270862a0c26c0a648051a995ed2637d519128028917b73ef5570eeade059c9b47a62df6e21907f6e1794e2a82867e02d59a1d6664257b026ef29f0de7c62701a0e6d3564b3034f611ef9a684ddca0daa9c297d41084527c368f96f09c58babbcf6b6a61059cb50ad4118f248bda5f3268624012002c4449656d95a3eea57629ffc403550205461971c035b9aff9d220be9bf441b1c3fe93ad40cd426733447cd9df098335849c5a5705e4035f0a943579ef131e83c4c64c4562c6502f338cba3df4f8703b230af397730130521aa223adf9720a79d3e458acb743e33cf5f7d4e6cd6eae9bb1db8a3cb6a8e9d75ccc2816c7f516d35286f50d01ab4c1b8c76659356ea7e1ecc420951ffaed2f7fd9b6753ef29600a8b7915aac159e06594de35203cfa3d28b0e7b4c1abfea25dea45ff43f092d2aac215725fdccaa4de6ba6e1c584f00774d25fa8bd1092a4", .Okay}, + {.Sqr, "75df57121da7affd64739f24fed69dbf03143c97225d635a3473ca9dce746610ebf5ed11a9235a8ddfa8828d29c37b6ddd59bdb5a8659561d2e0e62ff4a716f24339871e4ce878caabf5189e50199016623fe68d3f7bddba680f3fe69aabb3f8790750a046ba011e709ab4e8910f81e3f19206d994af4f3a333abd99cd4a4d824339a8cb1399fbdba26fc05b3bfe6e539745d1fda706fa598c54f8846dd77325671bf2cdb5c2201e7d200af88d34840ed6d3618a6bf53426ca98d1ccf8d328e45baa31b65d76ab58b61147a21b4526ca9b1bb6aff52b31df242fd41e78de016a132966ccef9b7951f1258095424af0aa6444bda014b5c7119b35de2045df0139cabd7cca7fa85a05263f655a3fed4efd5a4db2afc2218b66f861f98ac44ee2a62441be4a00c34fa4acbc198a55af6b8b8ae9ee034b2f6269b55e79e076984f9603b60f2233543d06c59f9dbabffe1d5a65342ea18dd91e281e29ab82642b77fa69b6b2964503c2b2594b54e3c8a8653e6eb778fa10359c6fd60d60c08eae99d4ac3dfc87619aac0aa9d901ccd5f8a0fe16d943c06c33431d41b63abb56ca5f18dba99064e46e690c5031fbbb166fca57b94c273006308febf19e5cf1b149d356bfeeefd4293584fc9b1da951491137db624f33a5e7213c6bcfc5973d1977dee29d9ad162399e66168f7839bdc58722088fe807f26dee3e81731c022f808ccb9b392eb2225c7ee51ad5386d69d9d32ea8e8daa5e222a1a110ca384e45e619e682326d61264bdd37631a7a270a40c73d19127adcadbb80ba3182e0fbe7ca780fba879c5562007aee2a97d1fb76f200ded121d9885dca4632147c6e47ffa16011f8c14658704c4633bfc0e6bc7498b93a02791a3e504628a602f9fa3c09bd062edf98e21676b4f03de1685e76a16965f4e2e739a38283bc015d0ca443e62f3304c97af2f269f20a26f77f96cbc29b8c05dcc0f302f1c6af1cbe6c569a0e52ba238be1d9202577b3fce42f8cf8993e46ad7c38f76b1d2c7ce0793c46419a5f832be241eb1c15acfecbd4d5377868a5ec3613839c12eb4889a925a4e68715606c0f3d6e76246a45d1a76f4d000c3755899a3c8251b7afdff03bc662238c6826b172b2bf8fa4fa4ebc5a2306286896a27885f9c61ace80eca90e0299677da432e95f95924ed27955c8da792b370b95a31b446a636e3faec19d39ba287cf51efdc34d7d000da4544417ca710ab3ad277e6ee50556ccb4b3919ca00ef5ad22a6d56824596b0254867821848caabbbea555a4d4a64cb32ca3a3871deb17690101e35bb53a9527e9bca3f20e18ae959a8f4aefd0ff360ce5ac7271ca6acf1806244c505896b033f8ffadd61c9817d41636c4eed6cc235ae4408877ee9d3d8ebe9b08630c1a0283d623c6cecc784e56495a6f1f9b7b49fd45a0419d069b6cead215639a99da3f6d6b2f2fd2fc7315cf4345cc86024869ca3319be7e78570a626869254f10203cda691bbbb51cd6e79fa4e0ee588b3a2e0f0047bd42de7ba763efc7495fd3b693f06b1a740aa883231ab940ee59bec441f524ae546fb1eb9ac4423f3ce804086e1197db328f91aecdb604808da85be637b950cd9dad6366e0e0fac4816f42f9d944cf3a9d2dd03c3ed279272ff66aeb9acebbdb08e9e0fa35626b91e8464ab87c76c23e16c96493ce3db9ac8faf1a8e8358e15d2146dbc6dcc7f86520f2689ed70919c2a9590dab435943dd52602c0e2fb930ed0f4cf4999f7471dd0982fd880a89728446f45756e200e4cf09614b1572b5e0331ec80112b8f5b3aed443a55bde06eb595f69371048dd7072969b8405d43c01f250ae8dc3201c1c46c90e1a7976d6cfb62e9853dca94c821b8df8ba8e52e8edc538012bf858ec426eb480bfc9205721bc202ef85f990a087929435a10ffc5b4b26e559db065dbc557d25c28b794af0a1166814de339b5b1f26a69feb0a9d2737d45f3dfc52f7b158a3cfa852ccdfa81d1147d8e252403dde02b7a5961f0b0fc7436d9a875969d9b42d8c96ab601c3f557e7bd20634f73895b538e701d452a7dd0080c5e64e24b697ce91a6ab445be14b41cda468753c9e9cce56c984d40875cd9b2b393975d49268d", "f8b92e8e2ee4796d0ee9e1e370a940804a07e0ad2a96e28bcd8c568017559b4e81a21592e17675e2bff9f7130f8003142bf11c5a9515b2111b88e98dd4b8e842fea73cfad1d70f83708c9c79f7d8856aa8fc1bc7f5004e3e247a96c3ea677230e581d51411c438fbf0da2f639419908c8286d3ccb3ae3610cc083a25fe193b63e4a213ff4c180c903870941568073cd3d95cf557f522181d518b6f1ba22f7e7940f059b15cf867e4cb5de5f11700015ab1085881ec844512713018ae449b0d30682f6e2582152465a6ecdf2b962ead11aac8dbd09783c52d35704160817fee6f5eb0188486bcdfe42366b5656142feeb9f5b8422fa07fde635518332f7163694fe47cffa0150111e904bd6429f6f28a0a0f9edd20d3e84eea2713fb82a3e6ed03ca97c41d5b17e9b654dffe0f9ae134876386aa393bf4b3acbefeef8ebe217ac167ecbb125e350897ca9ad1094aa8a2a1fda8ba638bf7ee379e1cd04b0a51b28f06553b2653af980360aefe412cae3df550f44f1d0d7baef6c35b1368bc44446d3c05af91ca02b07727d0f43e614822972baa146327f2de75c499e00a5ecdbe9692a343910ea34550b0082b92d389e42a34d4a4964658104f6d7cd3256cf8b9d8a3083fc00b9d800e6bcca791d718fbf2ad1b9377b4c698db39b7256d53b0760d74b9296cd98ef5f14fc902d67dd433de0bd6c9708f4865f633e3f158f759c5ceef7282cd126b3997c8f37a6bf61b76ca504b99b29abaf0d1c5c73ff08d24b1511454ad1cff4299e0acaa6394cbd7cdb89a119b38e48708947c475887c78a5592573075e422618182bbc8fd45b79708866d76ca6760fe72071952ab892a87696faebf67db188a9e1336218b857a70c11b11072145441115a336688095e0989eeb635cc481f4b2cf1417cea7e5698e587eed0f73a1ff6ca105fabcecf49a2d81d81d297868228cef39e713b1796e1070eddf7e8f83fc7ee5bf1dd8bc3d4787dfd21a96a0cb9d5e7edb086530e3d32b0f3083cbb3da9570a579ba1467da09fc5a029df0561cba030caf816682330362532f04261ab4e34bff5f2fdcf2d81f544354aca29f7db01957537787f6e8357edf219f53cde13cd9f39e6fb81bcd15cd5e550e01132b6ae7cc0ebc921671b01990c2d11bca90c79b09c72ca0c0c6dc03a9de424325ba99e2e1a206d276d83d03febefad7f7b190f4d81511c9b25c3c45503cff49a2b5e6d3e35cdda1a7b49dffc73ff4cf1715373ad94ceac260fccda83dd5371b1ad4b01c7c72e899466fe8b802ac10761bbefef7c18bbde266f5ca21541783d521fab090c6528df9a40d05c34fbdf74945e3811bf6f2a1c233e1effbae4d2116524617aeb2b933c56022ad20bcf58e1844b3642bfe5da2d51d60e84d9a163659cd701bf164424b413d488001113a41ebbd85714a4359f42501275f54737fb07958c998dae80a533d9479a32e237627d82fcdafcb5e4c54d3a820afa1cdb1a2e9187b1c79183c2110db5bc0bb260838207fc41a959d38ec4a5236b548f969f526492263f4074adb34582eda02bf136651cd3f3c4e98485597e83e68d0b56b848740754c4ee81df37c5aafc012da6655517c4301749de4925a9ba429f9a71839d248fb58fe3b684a22056eb93815ec4546d372107b8e40796479541dfc15fb2e3b56ac24ccc49710f7f3296229f5fa7d7b634ddf78c264a7eac0cc5bad694c8ff913a49f93e4555e80dd413bcdb78f859b894ae889dccb5f3fe993c65d80c89fe2904d4c8aef8a4dc298000ccfb1ae60be63c21a054f2917418edbb138f3d684c75efb4218088949fe034f06fc349429451c74b3c9a54c7b05d8ecac69fea9ac010809a9dcb5a5d1cdb6d4295a795e812ee5568ec0a61625a88563c59f1f30d65698351ee50aa47d7f17fdb3c4358a943262de4ac83c0d7193c8ffd28aad89bf576e45de8fce33420a1fe659237226724900159e13c647bb8b6db4460621599cfdd4a159a0aa645b23e28c3b284eadbdd7c9cc72e768a69e38f9cd0e0ef81df87c19c91515455db6567b850439863ff016a01b78b2f503911342c1eafd2870e59785d5c9e348820bd265425d10478d22f82d9064ba63c8d9e8d8a", "3645e86f5e48427261e916864829578eec86a76d5fc99ff91b93af58a5e1f6aa8c9351e59c6f526dea437dd7e8282eebdb8bce0f9a3074c7284e8d7097e3ce999af79d125a524dcb281242600cbf005414cd3e2209843f34fbabe933301f3e241765fcee5b5040f541c083f48d4445097939806e57af21799216b8d2519336a9167d4d10c5a86436da07bc3902a53973d34f13f9380bb2090287648842bc5d17fb9136709f1f12139d9804f8a260001b86994bc7477c313a194edebf10d18d40a153d06dccbbc5286795aaf08390844d5454f878e97f65a1baf836b74e930294433495a284cf84b679f60c209682ad88aaa9e2c2b9aa46d98a789b23768f99261669e674adb95bbe45ef13a70609afc4acc3720abcf94f4cae2295f415cfa5efe6a5c8d41eaf751146e815bc5a68d9a612114cee10fc9b695d86d451e70d9844c6e02ec87a496a6c77584620f20a836067c669ac6ef94bef620635d730be4cd8b755784432d81958bb2e4eded01006ae7cff06a6570fe1b2b0e0d99b7035d47022bac5e7c7e81bd85ef903ebca3c2774ae771962463a21071f9f8a7cfbd1133cc2161a2685dbad463d78339db7e52cc21e5b167d12f1be68d3dad749d1dee80e589bb6a90b672dcfb13ee8c85033a7ff54289c94e0470e23a36151bca737e13e2105d7cc2f2dabc72b0978ee6663c5a7a029167ee9e3a251adb64c2a1791236882d095c599cc6d7ce885aa315d0fc5c5a4a021c469dc976b0746744542386744d1326b9e14e1309772b7315b0fe8dc3988259051955b90165bc0de7cf05b87f3b724b91289cf98c42b030ad878019831fc3a260ecd25ee3e121dbc9b34a5b911f14618ccd1d1a69b2a329708416397e45c2a6fc7f2e0cc36584046971bdeed99cfdc93d6db03cafd07a9cdd1871c4582ce7a27b3d4313cfcae7fb62667585024123c8ab8be3246503d1676b72b7ffc1e7160e60cea209341a84dc48cbdaa4b3f13d7bf4eb59f67880ded91b43c747cdbbfe81e7f2d5033a439bc7c3bf09aec82dfa225f8f89491606444941659a602803ee30d8b76ad8e5dc30cc0ce149888764d2ec500c5810538e5310d8c2e275b47b6e3f1f159517b4b529e1db059e3846dba31a40e9b8caf9e7594256c6c2c527465b1d2b2f3f6f87694608f3a40a17a6d958ef6c2ab51d8fb6fe021a48a7be80b67e6c32df7a7a450cd10a92171bf22eb838e5ef831aa09f16851d66362757de65d5eb39eb8f72a2d1dbe5d0a4133ab8bc1d820fca406b0771e1fdb902bef4005b312663f99bbe988542b25d2840df8c75edcb0af429453a72f719ec7ae223bcfe50793668544ccb0c307686f2ddb3f6b313abb384cd5872ec201e6a0aa23fac17c2408c718f5a5a6edbc9c04c0c60884c40e363cec18803d20f389c4fdaf0ab60c88879a00f8753227a1ab7dcb4aa7e763ca8438ddca7f00de0d649b264eb5ffdc4848d9826892eb7f9df0734325d87648cad8c435e6c7cfce9084b8235ccda3644c20c418b19fcc4f373baf809fc4542649ae1b134a69cee93906a2b98cce9ce3947616f60af61f06f3fc01dd041abc29a32b68e0d2c042b1249c112c7788d1247890500076d487164306d40285eea6932d3937e1a3fc6efbea62cc57211b97a4f820eb04c880d387a686dbe77c8110eedc911225663f99b4d96065d5c43cb08b07bb62579bb8750dca2c966bfe2068862c08c6680b3d38ba539e97ab4e43c45ffa4042d63e3fc59e27427c9d37da6834fd36ae9264bf02ff6d686423712527e3872fb481ac8643d3366d8910cefd999f0bf797e9edd1e6a4263a19a2445ded7c3c797e4a1452311e6404fa096766eeb8f34d218a34e7f1712567c6d3794478a308d4ca781c952e3d7824811cd9ec1b6170304657821239c6bc599ecdbfc98a9d19408ffbf1a3edbf66a0f9e358307fd6068678cb0d1ae6f779abbd07654e585cc8cd1ab04657f2d15e086484795aa4d5b10669735396ecf00d1fdd88315bb3508bd22ec8daa4f44d841dcf598b9b3d6d60986cb9ed080414213bd9eba0f43415c9241737dab5c6babf34af78da8de5f289c364f6ef40f9219650e2c510aba80607877930c412475c4c47d64121af0ca91c9989e20e5654a4a25311cbc98057f76615e1b66d04b72afe989f9476c416c41c8681bc3abac40400a2b3a794bf020a1e95d55ea299e3b17a709a1fe2f3a33ee46fabb4b3267c485be46a61aa1f69e392216c493102e77d43a96eb64b919588080112831af519658abaa40cc86fe425eefde1f40ce550425c38e4972b6d6ddde3e364d41f16f8cad9de9c7eee8f4fba1d5acfc0f4e3b6ee5b5324fab23f53062d835fae089c453a0b4c9cb57d84fb9813632f14e8513012d30954472ec2caddb2b6d098e1d7c5685c04b3404fcc976275cafd6263f4f9e3c70f947bac245e7d8ded31b33eca17e0e3f6ad16208394a9a1f1ade789fafa5e0fbf12cac264aedf8aa633a3613f6ffb14a030703ad0dbe37bb966227da05e2266030b149b76a9553412241166de97a4bc4b5605da07f53f1b8d6fc366621dcb4e170ac6f6efccfd4003a3241b8611a6dda65abdce508efae2e88040d9d504dd3929d542a2386d9089b72386ebeb1f72499680d68b0d8211fec98f7e191e64465db24cf7374d4e8956a7551460e8d681cd512f838e64b36f33f45717bb8ea3f7e8ea273f85a6d4e16e9a35d9e8451619046103fdaceff19e828b7fb5b083dd3d7884f0f45b9ca195719c9ffcf99890fe94f24b068a543fc7ddf9d773d11b926485ef04cdc2e0dd787d1167410047c04abedd69a609deb42feef3a9c7cb42629a51406873fd531bff17ee8a1cb508070433adb15f1d9aeff72558c892f3820a3f766519e45d9c527057d0fbdbd25384eb2ef681027017a712a7ef1500b32f047d0129a7e79ca1117183da8651722be9744df956c7a6db4afd6f8323e7efc128ec00a0519f237316c4fc1538707f705870651f8139f5a79a3687c30243749eed9e457467d60c1f218c55cc1150053bb4fd7f7f9a517901e8c1e1a88a4d6a28963f4cc1c0eff82aa78f28ba8274d9e9aead1accdd30262ef6fc6c516bd4d04b9ad563b03e847fffef82b0b2f29e0d895cc91c1d589b74df37dc00cbdd8b036879fa0f1cdd22e1d0dbf0270a015affb545133205d8de7652dfb9a8aa2c21e01a3f3eeddfd40f73fc28bf21576d18f907a7b306168f24050829b4dad6dd536dc23a246585da75d7033f07fce02dcf619becc5d6d0e32c815888f05fd8940f656917942db0ab4de3bf3e0dad734286f70761bdf4d3176b30e2d63a9d3f7570acd191face651a50c8a280afe14b32d5719cd8752d357fa16667964884c5df199fde25cbe3a2b38ed9840326c2f221f823cce39411b452b3c7e53e876187dbdcbe0c89b9d30e62cf63cd0156dcdaf079230a3938f2394f9d17b9c0d85902b99a45a503a2d82a3646dc3fc932f867a546da341862a0ad4be44a6c7b8158f4ad1f0bb8f8fb42df88672a9d8f7b792c96158fc8b34830ccbc245dbacfeeaa84041416de5bcf44b95c62237cfafaa69e0019f5e9c7e595ea9274e5edbe5601ef78c4df191bc83f6db9b0764f15caa1dbd27ea613aafec78ab123929cc107a0ddcb832ee3a256d828626d2fda8c323372f7b912aa711e4c4c80d93ac3b0b44a513d564ad2e76459a32f8a75cdacc36fd2e8ca8cd1595ab537857b7561a6d0204d39ef2251ca5633ea404c48574c7f56586dd5d7aa4e914e02ef1981039924ceaaaa07b7236dbfdca9b40cc383dbf1a0cf42f48f93ab0bb3061766ac6a72a29e3bcf12fc2b58ba4c791629e7b60df0a34d9c5950e7d9fb9794255b1c8f5140972175737caee2870905767e060bf06b57f78742d181e21f63712f0a1363a28f17f17e139038095f58f70ed8411920d84ecc0b9f2a65e3cc9e9dcc885910675ce4d718b704ffbf62cbcd840c8fff1cc2900d5121333bf6148b2f3afda6f46122fd50239999e227ff5d46f05684c24872936cf23efe11df89a337d721a66914d2b58900196ec879271174be1fbf0d8391d64ea843cedc65a9641f1c13bf77763b1599b634394f74f5452baedf49ad4766fa96e7232bfc8e168e4881f58f711a2e87b9dd0eb6933cea9adf1016168dba2a54150c2105f4140f8aac4b966120b3633957e5fe4e5a6f82769e6e4837542af0c2d45bc8b3ac00a04cd01e1aec0f932dbda33f743829a9", .Okay}, + {.Sqr, "65cea168ae9b2bc2ba6c4dc5d21c36e34472581e5651f41e430e75542afd09cb7804ccb0ff29b45f2347de848c10bf1d946a85447259d71050ced18d651b235f05b118addbfcea6f3e7b3068f613bc1d305fec1db87139e61ecd2e95d873567b2d98e47c70920804ce84248db37a47b5428922279ce6ba0e459965235fe04d71a62ed2952e168a0cda532920297049b696ff9e56a774db55676e3c7116c9fb521d238468629523238a71cda9326adcc2c9e8188c2db4be09215b78733b5cc9bfcc2bd12c6e994bf596f4bfc2138d93229bdede7f376063f3fd9393da8e7f87029ea3405a660d7dbd61914f9ac70f28b395c419ec60c99dc8d8668432b9439899bd33fc884b1fa3f2ea4b861d6f1199b8b88b31495f27c1a02fb432fe2b19c40f4ef1bc3bc4741b3e3a407bfce026e5512fd64f57f4fc1de5bc6ac0d8f1b109a0a02e0ccc5c7301cfbf01901eff0d2120143c98f5acbd266c32507ef626ea5a8f49f92ca64ebee5808fdd61f50cb985b1e7783685149376b75489d15c5bcf90c10d4d993d9c3e5a27a15b8eca220aa36bab3c59fe72d4d01fb817b59038a059fc4c145724f75d81854e1b7986d910c99eb9fa83f0482b88f19564565b6f430800b7cba5a8cb552a781aa9676fecd55b5c7055cd4c7565ed38bb77e048779691d6e9ae74e5ae914e503a5146aed19d5955628c675db480bcb7a963bb6598c77b1f47a83750b34b90886fd921855f2e37b16b98e2194cbfb6e3d807165f7d1d49d287cfc315ab090dbf3a91851a017a17025d1728b025367740c250fd55104b01f25acd74f3595d2f719c11e35ff0d6ef64ac3516f7142e2c85c3eb76ad8848e328973edd865ed4e26f3689ff8a6aca809b20d48537d7bc91daa2b61e419689c7f50dde684ec04cedb1e7f5e7b03361d9abb96a2748201070805b4981eefd6c819caef731d9da21558da716e92b9c3729bb55e21e65e27ab651c77971e3d1ed22ea22bfcacf15cd0cd09738200dd4669f244546befdf4ea2c235f2942b93aee10284f88266a779f6eba3e704faf69613f0566a63594f619ba24a818e57bb9556fccd9e59f98fc6956e5efa8aa76ee1952e5581edbddc01bb0532526a101411f06fe7037d7e439fd5cf112098d573c1c8599e678ee054e21383a2c2dd3563388d735660497eb63aa5ec33450d89393ca2c224ff6d1b1dcef41025060449effeee45a8fe6c7cec77ac44e537a55ee194d4981dcdb691f9e75c42f88578f3744cc226128c479265ec9b6080276035354ba230ce3d992d48bc22fb4a701452ded82e8ae8bc9d88587fad3a348dd75564cce8ca558d0db2d04f14ba6df03392527e259550fdc7e4445fbe937c28b20478fdd16047b87a359a58977cbc0fc60a74c9b1f1ba48f422e305d79cf3bcaedce8346c22327fa93551fa68bdfb0e856cd7da5cddea439b68113f6b3618f84c4ae6b33da4a3a7aeec9473e7b9a00ebdbe1c12474a8c559a786fa0f7f7c248a7c9dd508a06f373650c65ded917b348292366da1ead7e49e9a0c212e46d488165ddc5944a77ab84a34d40aabdd2b077a79c8eedb45162fbee375764cd215d1ae74e9b7f8b915aa6035c3ec5e15908b5f3a07d30460b69d2d63b041146c44624ac7d13356caca1887b9883a2127051ef5f2e506b9decec9e135dcd0854adc60505741de0fc618650524ee687eadc3b52c31ae56c7ba2c6b02d3528c6a7bd1431388a8d7bd3670a995e0c2522c0f1ac8a7c84ea4ff01a3d835c7eb1bb7bff6e46447650bf7f4f440f61208b1566cdc9ad76055236df21d4dc4b06ec72e2078efc228ee3bc74417684ca3d3c10bfe8716c1b69fc9889128a3161033110d9706815a00fec908488c1b51a00b74e3119b3297fe090484d8d92afaba6a6734f9ec53fa287898f1ead18c393fd497bb5dcd3ad5bec2c6c7590f2f924f6c29b5733681aa7d4f604a97d418c371a129c6845aa99a2a35c8a8a9eb3cc43c2710b0c44b0dbc691f4f506079a9513ea1e99c69591bec6a38ee394a4b944142bd068b2241d536e249e9f40e6a04ec39698677f0681ff5a6b9c28b97ea05d3f6d3aae715da5da24516997b74b0e88607c470356f0974bc152d", "bd40e6b2ee40756bd4540eff3b1b4b3076e51e71466e3decee56c4ae341b5437e24f44a35c6a5b3652b360274efabed617d3089a4e608fce27ef2a23e9eb63d156aaa337cca6b0a3291f48184bc97392e853c46359bf2b337d718bf8e96c1af8f4615b4a213a57cf7644b47e019865df07caedad7ee4e5a269b393f2572b6cf4e63d078c962b9185d345d86785361863dea69a61d9934f772cc674c8dd0044bc40daa71129bd3db4c2a857f0ac2f07a729652336023d8e7a79ddb4b58465a21f4c799fd760c6aeee581169a019fcc89f98b7bbd7303fdf34b74132ac763f61d031453231a4d8aa336cb870e537dab6dc9516c2ffd841486b4bbc2e8bfe858c18cd7ee176d7e3bb18756db128ff8745d39650efb0b9471fee70218f70fecc58608877a8943f123541363fcba4b94f02e8e304f76c866b362602fcbee3d1b811ffa18d81b3e7eaf6bfa37905a8cb3b9c95b1fc9938458bd823f57ccbf133b4bf67344e883395477d53ff8a81320577b213a98e69ea45e3384b21c6d2b6d0a872c258146e420ec3e58160061ea54d418e4ba9590718c3d295c92543874cefb81701fae91db5178018618275cda846f3f1e5eab8bcf748c49b780fef49a1d6a81352b82b96ae0ba4e40191ccf0103b05c0efd332e3c0fa8444108d013fabf6933c55903de76810b4d7fccd1a61c7cbef56b7160ee618f374fe6be61d87a2e40cc616f4e4830222f6625f9d24801593dd42d7f405d363d954dbea7712d1191ca1c878698eb558aa720ebcaf0583956d509450e14b5411576d6e8c2e8c0cea6222e85424bc1969346c63424d2bf7dd55561adc3f52802c67f52e710092b0313d9d2bc1ae71349fe1b7da8854a9c001115593a4893f07bec56e5020025caa6fa74830584a1fef3a6d1aa841ae850a602aa97d7f7c7676d84be68d1862b62f77e8cf9acc24482b3aa687296ea0e02c343becd583177950f483e907925029ebbf2666b3740840dcdf35e9b2a7d18506bcbee5d97604bc6f6d6c2848e346fb38456f0f0a040e84cc6d37841384d65bca0e32cf9989a26ee2aefcfe25798497dbcc7ae1ec596c066c2384f8fee741f2c9d1a2196704f7b84f1d0f233fe839d88e363fb6867ec521488195e826d8597083c54dcccbb86b83713284a57a55c80cee8ce82d84260338009856b56985c238594531645ca5be58675f6a8cd27162ea25ce003a368cd9648cb5fd59b499e1df0c95192623c9936a384be123d2695d960e9b9cb92f2f880c14d1325333875ad3d5b304d5db6d60f2e75d3056d357263e943cbb9698d71c8255939b9d1f98a70bc53ec4164b9b77ab9eeef490c3eae417405f9c7db1a5ee298cb10ab6553980b28b5ebc4972548a0d017f13c90d87c4aeab1f19ded096736c8a9a62dd1e87ab915e1f8b28197779b4d95cb76b29c098be05675ce3c0bd51fda86f0a8545b12c074f9c66618c2a15aaba340cce3dd85b5287080472882fdc7d405ff94cc513153397726a132440f633749d1610e94c93f0a5ac98cd8a35fda0c89f757ab3b471f4941dd966cec397bb4dae4a218e4227724eb5088d94f792d33b35ce106e69438d4bbc192aed5c682c18610f50318feed279f403b5e441c8a4150ccaac50bdaccb34893a883f9b34b1df350d91c007b30236bfa36310af1aa7d49176256dc8cc477cf4ef12ed39766ddfbc2186fa9978937ac0fd10b4a35c83f7a6458ea0549d052c647b570566223707fb911b4f7d5c9600e4bf4b832466b8f74c68fd8844c7549ea1f59bb1a1fcd84f1b323d82f96e66bf72b01a240a8b06f82f474076d9ddf780fcd1c61b2355151d4bd91733be9f30d8d212ec8cf948d8e66128d29bf2e552e2ff73a41443019a04098b3746c0111418f4bb6af90d6b90c639ed5e92b69627d9a14f4986028eefaa39a6125560a7dbab8338db99b02945d136eac49a876afaaa52b0451c73f2a79b1339c013da0b4f24759d70509ab5f40cec425de994ab7b50f29357bbc4008dcbf5e45dbfccf060ad7c8cf20ba38ff0aa3080189ee042936f36227e876f6aabfeed75b21ae8ff9d4b7779cf74fba6338f404a9499500913663fd1a1431f144ff2470b0cd3e0121987a0", "287cb224c40448af96b345e9aeae63586aed8251b1fc1442a658d17c7e861588583bd165e0621b54632782ea4cde91f44d81db5e58335fbf74e0e28fde3061cbf77bc1e3b7209930835af8c6158c30c339718c2a2f5ce6c8400909947c9555f3945589cbf8573d9840494681d4cf9f99415844b2cbe798c58f0b131fced6fe1069d31e04efe412b06370da9e2d1ee542886b1cdb473b3a8d53f63ebfa8bf3572bd95b67c7e513234dac31d287e01e72a50a977a0d7d933f79bc21e3be7151dd43fd49887f735cc5d30856ece6f1be07a45d14d168f4037746bc76b737b1eaf4e099a9deb3d932a3da2f967475cfc76ae7558547b2aaafb7a077a8be55544b92625678571a46412c94d544b1b4283af3bb4c2742baa5545b091a0d688bcb40d85c4bd47e2c8ddc38a117baabec969fa426c7dfecfaa37db7d7a0d24ee4af3b739e779002a352306cac4b5a3389b19b3d55840c7964e9fce58fbc70f537971fc73f3595effbf86d910c95e77f43f70a20a35676d9f9d38fd791d227fe8fb7f0f15a87418c76f9e76802fb2ae236b4347f56659cdf886459a5f1ff394cbd46f013514de4d2a9df39a02d3f6395c06d1c6e94204946f6e8658c4deae0733d101c7a092921de32511393fbf6bab66abd955c8da4cc9941f44e117979be47fd129b8d0200b4af0fa689f532000618ea4e3705883209f41e980c46f642568ff7e67a821151552469f60c6af4978648525c6571dcb820075cd51cef7b55e3d30f7d07ae9d14194d3e37b7246c920cb16c2f6d75c22cb4134699334329d5e6b8864c17d375afc697bdac4e573f5ec333b47d71a103d10bfd93518d098860b38a2def5b148a141095ad51662e8b76f22ea665c765a6bf638d5889c221584927d50bc5da24013272d17034ac025136c135b0016db474f038e721819cacfc913ac1bee4062d7a5e4743c11f94e379dfed99c13f919eddf65376ff3cca11fe995f26f7834e9fdd6aecd114f294d3221e6a3a583b1d0accfeb6ddb9122ab13f504df345b26eddc4e9f3b25a8bbd34fb04cbaf8a492c1062e1add934b784ac978e63c343cf68ccd0a862d0c87d79d141d410c72e505a5e4cae6237999f1da5bcabb3d06f4e8e5eca088e4c42fc6ca16c30e276bfe3fa698e5c682f2c2d66a86bf176b813e593862191a9a09497df4b41e7760f78bc443dba6bb7f44d5f946c8c8b1ebc2e5fb68671e43d4664c51c192192b634a1dfc152e280fd8422415d7b15dc6e573e4c0523f1ef9469f5ca4f89f698456bc97a61c6768ba5952a5c9b31cb503922f85a64b2c64a5a65be9d8809fa750c55341093b2b1e346994484a4f383e248b30032113395c2a657a2bbe942286daace1b8cde6757cd8339a3760ddc429faeb2823607f77a24cdffe5034865860ecc1bb536dc936359a5e4b7413790c1e45c12b4d812899c6bd823b7f2044fb0dc2fb176f7e430728dd0b44c59e3dadba637e4f59095c2312b31b283d38b6713b920cc6f2f5ed07401caff6344f41d0805324c511ecad7597ba1738965cceeb06a80e68246f7e216e88a8873793023dcfcaea5f43c31cf0c32c828aee66ce15f3f3c7b7577e5d250c75cca351416ef9ebdf02c22be8fc9c3a691dccabeacb8adff243d7697513d87a04991abeb485ec0311f3ba16891ee2cecde90b5c1435fa3a4530e16ee2f145595603103765d93dd57fe69947caf9c083960a5c8957d582539a3a304bc1d050d53cc41dcaffac5d76ea54d2c594740ea775ef6d6e250b17825816a3a9ffa2439210653cbcb0bb734308a0fd84c5feada548ba5a6e3fff767dcb4ccc61b6d11aef92305dcc66540cf34cf089c308b95b7507d294a43de2d0e698cd09aaacc430aea6f6cede3597a78ed687a83cbf1ed4d259192ad487b21db8b5509f19bbf9bc5ec92a29e0329498be3e9afc42762e94e2f1bad2beca883a7f8b466be304fb8c8f9072b2497562a2a4f33f82666f105b0357661ea1a0d2f23bc6afe470a645f3f4f1f1c14adbc54255db38dd88b58abf5262d751e2e09cf6a83df74ca6452983096ae72a5c276e93dec129cd2161bcfd6b9da83c1e52a5a8a95070176db0a9faeccde92e5d8124255d976277ed166835badeded516950b9d86d68faf3fb91a08676cd64b19ed5a212a43e6267b6e6d83b2e4092cf2273491973a079a61fcd9ccd096f6b640aa5cd72c49e38b2fae763a1181da05dcac481a0efe1dd523480698e072108c800dcecb8cc5f8f35571be68f712ea06d22145a89ac97435f98d303ff0c19a3034471e184b0063c9370b505e04b2a343fd0a529b473dc364a4c8c3748920c7678975f0f634fb77fcac145b1b3a946193b6e059fd74bfa2ce21ce7ed369421ae194f66b785118e2d418c65de8d096fd72d0dcdfdfae7a6f371ff9a7a4fed54b5e7273966e58ff7ae11c70dd84f5c89dacc674addda1f6757aaae112909fdcb3d1fc25ccfb1fb9d5dedc9668c378b3c969ea81a5a0dc596846ffccc63131a67af3b90196aa6e43d6673e7da7f2384f82ed8ceaf6ae749b206c3e62c15a78f2f57d096f2d3cd583c4918720dddd68cfd70fd34f4507d9b0b528dcf5eca90bcf233159a7f91050366757d614825d2148a70e53866439c6c6183d40d1a96bfdc49bed44e618f43bb5f400cf54890371eb14f238ad7bd00bd449a4e3fc6898f592b4634f660a4b96aff126ac964306c007307f46e990ee3603fc625fb1b4aa94d3ce77f9e0fe0fd1d1c581c18c1df1913ce7159a810a30542cb5dfce7c121f7138d995ff73c273b592b880b93641668e26b45bc1ba2570e634f4d6554e20fbfa9c974f9c9ade7b25b797d79f4027946474bcd6f4d8a8a14a793de636b43b1e3a6755e59aa992fbd6a0f195ee82a5d6a41d3517379b8dd89d1c714c086b1905949b4fa71941ac073b687b2be9f6f2ce2cfe4e96ebff4bf71e8872726e3b885d34c7e589ba65aef86e3473919ce3cc736e6d8029ee5959ff163396f7b5f7d656076644905f9ef0be709076b5bdec18fd3fc44a2dea64e5ec0efadccaeb6985e2fc3444d5248b06072f689b511f71de1970eeaf937db09c88f3d829f5fe4741508a188d0e4f41c785048c647b8944e0282c3f8abf86b583f223a18ce2f2da548239eec892c130c39ffc989fb043634acda159fc177ae0c2fc25d51e0ab27045fa4ec9dbf8f551d14294e86f600104cdf5cd43ddc3e216179909ff7c3208f9d89f15441c2b129e8bd770506cea993ead13b6a08d0b74ddb2743e3f82fe5de28a27926c26afed4518e0ad32e3f746dc7be6e92a9b1c2cccc678e5c528810365d396b3c14fa7071dfade95b9c9ae36c55ed24b9944f41177035da0967002b87ede14f44e046b7f0df21edd164462d82b4025930cc1a87dab9fc537bb220cd002e93dee4372cbc57dcdf13e878421db90a62952285df058807fd971dfe1fa51fdb7e3e65d3771b29555423d1a663493dd0833fc7b966ea63ee525ec5a066d78d487b161411601beb17b81f3be673f076d31c2e404abea06e2161154bed2112089333ff7cb21963e9b6c7b614457573cb0a8d0b99f58aa72a433961df9e2b9ccd98dedcca115aba08dc16641d38d035654f3e7261446f74d0c60476dc4a78a09d86e50ce281d0e58966f1c4d4a9896144b79c174d09de3eb6d36a0b545b5c3027cd7cf9646a383268c1f6d0535f8c1668010132c6bb2c2722d11762d4987abedc224253120a4ad53b22cd1c72e7f12109a4ed4407f735b7da0d45727ce6adca1e93d869574f1b0640af3658b09d27f2a30bc6bb3e28cc3b927cb92f479f4d8e10f5a2c5d826d269238373288019610d13481a8edb786bc8eb720b8894cf23bb3661086f7c50162aca153b2fc61868f062c26c48d90f8be47dfb91a2c233b8202ee16c506d6c3fa836600defe5bb4c47439cd4fa4c6d2be1f89298ac963d6992c593561576e3a9d2621bce1f614353cbf5cd5eb18bed19f28a4dd24b5554018ddd1c13cd529df6b9abf249d8c80111989b6bdb84325a413cebac13d5e95dea9d812fcd1d7575d14afb5c30bfe260f9f4499eddc0fe7f87c6a90817f6d162afc14e2741e540793f92a0d924a083f1fdd6b77fd2f2e514bcf311ea52e3665199e31eab7839af66ac15a2adf300d0a076d1351351b9bbde91d2c0f0f01566c370d4bf558aa6a969acda59edfabfb6199fcf4bd08996c41a0bbd6acc8a3699a5854347cfee4a9738089e3d869e9", .Okay}, + {.Sqr, "99a1ced076e435cb75f59d1098d17f46bf043eb9e5b7e407f60eaa215152e23300eb73edd375efcd11ff783a94ea521611ccef8267b80749982d0a65dc3517f72928b56a2d9f2c78b3416071ccdd27025506f9110ae026d2b4663e098555908efa052f3283214ee38ae6c91e84e8ca59ed073e0231dcd4fd74906b0c7db5903be235674c0592a7d6bc0e9a23dc1d4e5893d56cbb9d7ecc73cfba822d042df9c12cbd96348e8028de77bd9a76d01e6ae6e66c8c7bb840104288dbebe08987693615514b0b0fff62cdf895f45a8dc2c4974778f1150e33f786319f1d2e50c2f9dc786c3365ce92816c5c91076f34d0def41d13ebc34c90ffa883ae8bc488b30186a8942ee4a48433395d3d4e2345a0b67b27de1346d399eb943c203395868ee79b0485b96377e946ffc7e1f64a7f8b8732088395be2a45b9fe23afc3686a75db87b710f59f5abafa82c03e2c7cbddf7009ebf135ecc53e558bea260cdc67345494fda7022c939d818c64a9e864a7eef686b136d3b783aaa987dbfbc5fffb783f6ad8da65fc1145f0c3366c93e2a3b5d0e08fc2db47690b70a602769f197f85ad204e3d3ace0b92846a666dca9d7e4d654e8168adf6792304d0ef559b1750a2cde3499bdab90744123d4ba5bafcb4f7b9decbf4c9901987a58c48f704a35538ac5ef899f2869057007c318c337bd76b4b91cde975174cd4af913ee23922bcf19dc4d5ea664f88a95bd55f1794a447ffdee7a6e99385d8678390d64ea677ddcfae646f311213759516d6f9bd6fb285ac30e9985a7154df50a7b7e62aa2ccd5dd9a074ff1d480ad126ffa4c336bbfed122e83fa09a511de113b5a1086c458d5c1c7b8e843a4f70c1fe6321907d088e2bfb5e273931dae3b62093eaa48abb756b16aa3f549ec0aef465ebe6d20afecaca1aa2ddaf001dabbfc00d9033adc0f8aa67570163bdf43ef272958830bb39ed140199bf36a57d91c428d78518a0ff08a7c1a2f6b9ae627335d3b42861a6159fe321ad3d43412535e4f4663fa9a656e661c55ba64bfa5bd1818a881408de50d37cbcb7963a45ddddb5982f93dcf7e6ab4a0a906dd21cfcb4ed3fdcf4a8549f401d6ed9038ec02291c44d03c8cef34cc1544c3544d528003104416ea9dcecf8b54741770b68d82f08bf824d437e27c8a1e3b2e3e941a5d1c344477cf0e0b9eb65632fde6a919e388140af534b4db7d19c82bea0b21c80d54590dc1ecbc23266caf18de2052a554adeaa4eb2d3e08d043c34759b04733b392486431b877abd4679cc4b89484b1912773b4908ffa4967b3b07ae98352501ad285a46c19ec51cdfe116145e0826da8d4d4a8d90f3ac38d9c2498f2878b1aadc0871a84e883cb6380c6c0d92f618d72f335a801b38cde13638c558e25758d52ecc8244cbfa730cf9acdf09a09d4f4e59fa83d93a690b6730c39fd9ede42c6aa69fad5b97e3ac3c869dae891a177d55aa39ba0d10db325d09f7bad13d2f3534d64604126fdc40bc23a45da42b9eab93f8b6c2bcf419a9e9ef161dc8e913b0f95948c96369ed857529ea5d2cf0243f000066650de060ca67ac1df562fe10635c49fb9c8d893ab7a89debc42e08ed9c3f7e8fe70945c038701d943db46b0deed5003f92b5e70d0264a4050ddd9162210d7cc6550b8370bb58114260e4f6c0e0818ac6f040295fbbf1e16c1af41b3335b421112cd9a5165eeb11bddd0020aa4297bf429fa3d7678b54df445515a90f7b2cad40effd40b60f1bfb8f274b2e79161dc8dd78ffae23ff630a209d692031058b9069f4d54eb418dacb1fe99aad05622faad6be6d098c3c81fd55536df3a7f8411c7eacafa492ac67bdc84d895d90ba74ee0d2399f47ea46a318b9f18abdd5e8e2510f8aae9108d092d537735281c08e38ac6ded40a48f90dd250457a99544765826a41c4a900069d53c37a0c212733db957ba640de6d34dc570b36a2079831e6972554639325457da38f27c54b7b3f198d8cc6db1d6596bbb8763b28bcb7f10abc7c80bb7c411e6973f56c610021211117b0a7e31ca833fc395f3930af936ea10057d33282952280dbaed2d24ded51d9a00af93b93db458e67343561bc5841b4c1f2c7875021fc929c4", "d9b3af80bb9d3658ba4eb94d4e8ea178681ce85161a1b8ff93569389d9b6b7298633391dffb478d8e1283bc1b9872077d6da90ad13aa146a4f438cfae4d70805149cd43dd7ffdbc1cd370d6aa34273df25533bf55d6fd6e82d804d786a1f65a3ee8b4c8b780fbdca7ae23dbc7395c79dcb0e19c853b2e2e5fc359b4db8d8e9d0a592a4c1f256cdb4fd8cf0bbaee457552196dd0d4966aca72b7da8afc77a3afac99f4f5688e2893a42dd1b66772dc11605b2dc0215fb8d2a74b7e1f5acd3005910317ca9cff8b541f93efdf2719162753e44c9513b371263349341d9072801d9185cac5ec5147e6a105d83650e94a0bf274353c0001ac3813ddf7a15382f1a9c7f55b558a147da43622b7361112d3eb888dd66c71e2150c87545d4655293f3cc309cc1c4c7a4e5738e9cb2508713b8cc4aaf3c475fdf8ca3016bf68e551abb2ff32e30dcf266fd17c0b36b059b62903c4dd6356c38a702fc425ae30625415678330764c22b36df5b768527caeda3fc921b38d4a2ccd2a5073799f568b2d0690deac68594c1b86c5c8050d5520ac5de676857e7bb4ffcef30210c37d3b5734b93bf78fd3def2df4d4e4908368dc3c78d965945b806597aaeeadd19602822d5da24f1ef09c3c14db1fe304e190efd9b3a9890a2d766087b629fb469116ce28f18f2feaddb042737e532846c8b68f7647e7a055b279ddc6510bc0932e14bd386dd2a96cc46619bea93c7200f04735ed44a6e0bdf1eefd97fb562f1270160f518425b876d9bf4bba10026a76e278d83988c36bbf8222483a1f7d4b6824bb38c453cbcd932e0d6b500256aedb677df0153b00e8ed92d888a00478b032cc398da7619008fbeeab382b92ff3ea759532084ee3d48ffd4434966c5267e0355e6c7897fa44c1f5d5caa08c10b201ec648aee20141356b9f3963021c76e05f4a3434bf72a597d805c7289570eff0f53c2f1b01cd1ae1fabc0ed38db682422550fab089873981177c286f8ca0f00d8db124c97a2c237fc5f05e880dac36504eca50867f1b16cc099af33cd857e6b1aefa89e2fc61606a027d72ac868b01c3b4a0eaed2b06f49d3af34c8e2d9b51c0d25aed7bcad67bfefa8a2f026a3c6c4a431457b7e12f3008f22aa92270752198ac2bf0b96c908ff32f7a3bc09a1fdc4652be1bb3f05f3448824d81f7d0241d50df3285456bdd42c351bcf293ae725a9a9169d8bc725387e803bf7bf18c795915fd282ad229e90a90c9fed08c58b1281c4fdff12507bf908a5535cbba51eb756ac8798f45717b76806495fc2d999d15fa8ee8792dbce33141edb1a2bab32dac633a675581be9fae02d0e8e1083c60b67f2077bf39464b4255465901f69ef14339db943afecaa33711ef5c0e03b9240146c84fca39d6b02b4564ec81680458c0068f94e715f130fff4c71f0f40d53ed4b1159043e9406b837fa5a2ac69c1ae5dba61b52368a1ba9d12c23051a279c30b2d4ad52bbc3f751a2502b5979682b06d824b232c78fea581e6803c652c55cc79db9863506beff67d028d191405487faffe1b226f784d3fdbcfb071bcec9f9557532a07bb021e2abd73473cc43ffa4297a311e24f863abfacefc41171df56e6f1e69d90757fc4b9226bc45614eb8958349a0e4ea0425d41cd236ee3e828df737357a48d8a2586837d8326b1d2f010698aa0e4025bb17a1fe66f854a5e25a415bbbbecb65905a7ec340527668464bfd30d73ecefc98ae5320311491804f0dc7e7b5373b7ddc23050fbe58bdd457d5724c71ee80b1bcfec2f895058e3ba53cbd025a60b1ed656b376518c875c05081daa114e6024a067b90a0288a064782d457f946ec3520236a04f6223e1c2354612b74f39ba90f32b45474f91392ac342e24a18de95f6f2493c3f520ec801622f3a5b08801a2a7c306dd0cf9ba131129a71f2bf9a00af48d7fe8181ef11294126bd37cb9285acab0f8323a69d23d5b7588c1fbf5a2e74452f61bb4ac6cc0a54f9ec67e8ef767bea3aed2ad4ce3ec128095d99d7c8a4c8e089eb5733d47863c11b4ccf51793126294735f2685c49a2893001d3f6f4263d87b0095633f6281d22fe9876f1741e7833c4bc747e5997544a55fb3f06144eede6", "5c32cf7af7667c718d8bfe2bcbe6fd6533efc0028d22862e15152da162b60907803d5071de7a1f5ca4dc1130a97c72c5c559042a528a7eea1fdafa3478c692367f61caa42bd0d0498c42945739592ee40e802f4dc3de1c8bf67660a848865c15276c607353b5130ebd627124b037ca29ee9cbcba08a56dff9095431b9744c610bf673022c8b5ce2c1c8279f3d153ec2b5560a2e2aee10ab0f55992d4f3f33e7a92c2472ce6fa32a2773824305014669061a730984a2b3b57f6587b0c68c3871f54bb6d876c483bf6ab60857c07f241489ef233406f611e4661b7aa12f7ef60dfa1339379b03eaa231550534c10aa4a2a377ffc16daa7b2bb3f0ada852d93c4c216bf12f796d0bd141a5dde7dfa430476d876d163f66c7a196e73dc07c0fa0e1631d2270b7bc2b0722eb44920abebc023b4da63651050b84a155c18c52ee73994c66e85d83d45de38e3616ae9aab7b2219f548b9a03cf368538c3d9c1a170500e5f035ce3e46fa7a948d52d2b7aacdca63fc6974cddd83c246bb17ca966b7d23e6e4dfef1f0b09c906729c2362e4e7a0b276e5750cd786533e998c6c37ac3fcbcf266b6b2e77f8d428a867c17d866bffdda11b728807c037b60b81d2b53b51556fdd5a367c52bd7ade11f9067454c0f06102496a9d5c73505a636cc9a42ff1ee7c6aab278bb6acf68f3df1aa66b86e41350d76fd8a63b15649284d2fadceb01f7a9192528738c3bae586bcf6bb6535676d3112b29b94ad57a2567e9c4b53d9180256d065fc9b67010b237318bb2beadf46dfee5e93fc152907b13ed4a6985394528b4c880539fd607afbb3738ba76de39d0f3dee91e69b10a2323d5b2a32d866bf725e1ceb86929bfdad921408b86854c8f756c377f2506abf47b9f14b8fcb8c5330edb505d1997a90104e67902cfd2bd3a719c8e025d590dc70dd151d0ad538b71e8d42a8f39191a1d037064b0f76f139c17e911d5f73ee28d4eb4e217278b40350876165eee1e6a26b684baab66ffea0cc5589e911da63e2d05e2b99e13208c06bc51b60088fa0adbf657b66518ed29ced48401dc02109213a7c833beda5fcfd11a7309e91cdbe42d22b86580002873e82a38bd98e88010f7e743a1d029d3b4099fbeb88114ecd88b13e63c416df37a5386dec9916a3c95282945d8d4c403303edba77915d461b5986630f2bd3166698c51d14080779cfb830338f3c24d6e7affe6195ec8a1ca8ac99eb595f190072fdbb4d59c18944caee5d89e9192a108248fc5e9c1e34e8b6e093e39d82e59a97cea48bd1239fe167849d1c6982944532d19681b19ea68c6f4a6b575efa48f385b6ba8126984df615988cc0fc7e3e8090a6ebe48c4907fb0efcccd93f4bb2557ab868cca04afb4add061d07f9002237decca23a72e1f8675eb4de20596638683697d6bde67cf17e5671a59caa399d88236b9dd7b1b37e729dca05dc1daefd5534eff7b709dd78b6410b0c782197fec0eefa0154fb5620703d579864a76f1dc84d327dbe42dfddb1f114ad9f1bb01b11b5434d5d180fee0ddb07d6a59bb495197cf7c76692e54c922338218d805de398b02a61f6031f332af0b511569a477e283cfbbd764e12628d7d1ab6a71ba6b6f163186f4d116a8433504a94d610ad41053fc26ebd192941536b68e39762aa4d54549ba8158a898bdd4bbec712ef0a957048c7b41dbce566baf52c73ef86c1532a220c430ad2fdb78fdf7e885237dbb1b0dad13fcd360be2342d161f455141cc8852be1e6ed15e4e69783eda145707d448b95bfff1d9320c1a5932783cd96b79d4fff9b16c3bfc8bc46c7d752bb71dc37ab044d9f888d66af6475151e25924e042834bac4fd1e672d28b7d6f2b37f8819ab5b0a45adc5863757ecce04b980d9de573d978bc1af19480ab9e435caa94a049f7ada7320efb15f47a58f25814910a61f8de2055ef44dd390ef4e52d58830dc2dbb1c03309050e93ebcd719f62c3a8f090f21d439f83cd9125931aa66c45a8b24593cf1ea7fcf4c80c7c66d70be6c9df3380d44599a3424244d6da68e906804f6b903c5ac5c75a48c5ffbe12f5df078792e4eff6bf6b6b5f2e320ba01a73940f3e716000cc18cc9ede69a6df28a9de765419ab1daff2477536537cd94e8eb2294dba9fc3550039a8d2d77b6476599b9115bbae4307c374aa538055989a8e1bca68cd99d30f72bc55037da0b2a3039fa6b5a8449053f57813f50fee9f496cc9c6df984dcc61e504e4e28b6ff807939843b9d5d0b9eb0bf02be720799439b09c6399e1871128442086da0ed18f38f4549bf91164a10ec35ccd58d45ac99b98e09b942ee78c1928e5918410685f7df6f54aa23efb669787ae5627d4f6c1e98369425e223298e540a001235bb5ed10eb333f5fe9c5b0db6f55e2311b4a0850bbc77f378effe2e893705293cc80b4d4306eb7c767724f46a49adc761f3839c0901d4c7851ec3a320160daf8b819f63f65b071f88af44f1ef9f51148193c31077fe01f5a567c2f0dd7db315e252e3cd79e42dfd8e217fc0ac56e6fea9e30df3cc64661509abaa99edeb31f4a185a4aae2171193ec45c1e8eabffe22ad91fbf05bb1f75cbd3879ad4e37aed0bb848c45cd9e01e770b98d5d6db6d44f1b90f57b0d08e7321098ced6676c1210beba9077557dbdf6e0bcfab69caa76f80230bbe62940b280dc9bae1e1cf6363114e34da4184f2eb891c8ae68e1a8c65db2708222fec19aed51a94f0a6577d827792bd90346cb21282156627ff5c29eda5b13a1b0fdd850ed09eb2268a8bb2dcf59d3032e790554d6ddcfc92348f76197563de5fb9ff63416d17a119a1011dd592335b9ba4343c243cee4294cb504653ff142abef200fc6b59833007485dff6dd3c7cb1eed5a84106c620edf8480c2c8f212d982cf7057afb0ca30753b55ed1e5cc192bbe1f4f75da06770cdcade6415abdcd72359c35df0ab323c283d818f5033e97ef70dce0dbb3520ef2540ea3ae52c191ec32c89c430c6a2caf8820af0a5a49eca4a526cd4df6c9640d537d622d351a1e182f94bc4a677acab5d104b8291a0483ab010a9d73e20a81afd036ef57e3ec54461c533b9153769be126a1a9ee4015af3df2ac47fdbf45fe00e8faf890fbc28fa9c99af2d2462ba3df3d5a282a3fc964b85eef1b5be45383cc54b3e21aab888e58cbcfd7f3fb635ec48257e03433b59302bed5d26564e5ac623dda1901148301c6747cd19bad0b2543d2f02549c87505bad2f93665bee6f24f4a99b3443a4d27b47526f5f0e1f0f22cdeb57c01321bb1261a6f4a35229d2f6b5ed05c933ade7efdfca76e5c56856d9094aeb7cb7022a148a3153a3ec40adcda8b16d08898bb217c6daf0704ef950d458de84dff6da2eda5bc53d44daa84ebe11366c387876fee6916ced066d38925127efae2fda4f268fe9b7e00d33c47cc9040625bce9c1af5c08ad6d5793ec2087ed7ace0ff1b07b2ac62c2439ee54c45a767b518f68a5acbc2d785cb7662ff24636ac8219a1a5e14dd6bfe8456ff893ae057c67278ea4e3529fa50dd985d70b76fea5e19608a89aea9218139bd9f90ee0c114a171e6bd3d64a52038148562a3d438cbf17b84812ab0a62c174118d73975f8698330837756b87b31858fc06afcfa9ba7351bfeb5eb5e6d405292696924612c325a2b79255b46c1a98cd30b8a4ec508eb8fc4cabfa4fa64792e476b25b841221a79c1df0750423873fd133ad72eb03aac5924003ed330223d3c553d9e14e4f567c649893b07c31eee5fa9f733db572f14b9e6a8f524a116b47907cedd8ca85036664ea9bd50eabfec217eb52a5b52a5da297c45c0949b5f474626e573026dd4a7b9c030335714fe4bad4905a60c841f512f3764ed7d59b9ed2c83fe8b981f9f039ba45d069c0d317eee72a10137ae35c01cfaa93e594fdf2d3c2af5c615fcc8d9b211118156b15992690daef9ad5be4654ee126a6edc6fbdd9e2ae916c764c22c2c6eac069747c0b023faf062ceefef68e4c1cd5ef9927470281592352ae515e396f50a8fddacca1fc2f6ba6dd12899a5e0f0c8d5e04da77521117bfee704404ceb9db493ec0395ef7b4b3a6edc149536f4255e949bd8726eddc0b8ef64724222310c586bf8d86643566ed8d7ffc8798fd46a0590b587c3a97b3298c65633b4ac4097424e1b490943a96270f51e680bc2315e43e9fdbde6ad82f36dacb766bb0693bbd055c33b30172b542617ceb04254014985e10", .Okay}, + {.Sqr, "b20721585d0e06ab5f2293d22d56d5bdc90e0b79cae52743d2facb7cacd1702912718dd1b1a974b070865e05041fd257ea44e91f4510e4facfe0f629203e1fb7cb2c4db56a9f0b8779b775d12db5007b9b6be74843b61783f8a030d20d32ec0621e537ec0e22545f2067549d325285b8f4fcc5d465eaa645f0a68113ad4cbf7b3827fc3760bc0ad1fe96268fe8a5139fb3386689887472b2494c2948d6b6fb350511547a3d3ebcf234f38cc7deb2a84858031841aba61206b9fff4b8fb692c3377676bd80ab6b9a1893f057178f9bf540b42e2da4dc44218c361ac168590dd932cdedd26a0e5dc0f869a960825090d3f324e45dc555fc7a591b90f8bd70f1187554dc254f47ad199231d6d4dc711a54363ecfefb6aef076f632f53dfcf0cc9e133c0a20c385181d329550079b42cd14b52801a0d45f0ea4f67a11a40878a6d9be5254ce08c15796f9d968bd3e250df02519051247f48ae6a70f98846816506d2ae43ca43404ffdda1c099451f32bb9ba85887fad80f76879a5d0be1415d8c4dcec5bc2f6a41d421d5563f7c4972feac69ad3ea721be50877afa1adbd55d3adb36d4c086017c0e94dda7abb99f8c1d518353eec8d02f32d740338c63166c6826d9ea9752ce31bc696ebf194c3703bb3a6d7e48c6230c4ca29b4a342bf0355dc33c509f428a69699a6bb80ae052e39a7d292af1a8568e877133558ea6b063f5d84bc8a1912d4c567c15df1bf1a11e15a5bdad56a183ad6a0d5c1399607ef1a686fdfaa6ace3a691c293c7edbb06303afdb378a790fccafbcedb7c685dcf97decad5cf5468f644da280bc3d32bd1490015403b8e780abf31324bdae1b6cff5474683bd96fcb2e681d8978df358f9d6b5e06b8a75ebd624805a8eb797bc96a2de0d980fa385953062150b4992af3b88991418bb4b2c7e779a0bc0f619d7da5c0f0176e11d1deb66da442197e7bcaa05699abf46833b5b35e1a2250e7196182d52cb0e0c9ce69ee8baedfde34108411aed9f6ac5cb86298c712acc3525a9a35e5dcbe5c0447215e01bf6ee75e252d66652ac9b68fa4e2fcdc2136adf1bc35c8a167717f38e29a1853ed783d94dd277bafbf7449c100f97f59e759158174577aae78f5c3270b962cc4f53e227b8af070428511a6d9841390bffe874fd7b04f5cfcbfd69956e2e5332b368ed5f078b6c90a18c5d2275ddb6281cf1247f790c768589d1db1c697405d840a626f7782a569188d22f32a35675aafd0c0dc2d53f373a9e3ad7559bee8f92cb076c1b53dbc22c0af9a8fb3485c8c007514c3bed42869ff97c009f3caedb6f1a1766bb36d5276c9c2f86f31fd32ed19cc0af3f43e7d2f1b89e8307c4e380d5b4e236974eeb702a4fb76b70612c075b70cbb40b95ec528961ad4b520100f9065d5153e5a01ff3b5759e0f5c02f8a49d42d1ac1d346891512b3eff9ab13d957444ffc54a54a143d48f0294354d685201faaf95cf7b24c15b1a2addc0b67350192b6c4e7bff1e9268b7294c0aef0bac794aa3282e2324f06d059b9b748d435f6b1fd42c1eced89c8dc9045b53a460fd6d572611b797cab1bd67b3b56ba553029a03830d6aa50d87b94361c82497ece45b96b4e84d6a04742a6143d6b6632911fb67afec715498fa9e27655bf4a6afbaf3f0e4d62716d10d8ed3baa18be7693d9de53489701f5499d0c425c3c23bd7446b497a79e17769075208810e130f1f497e400ef06085cfd6fd8a494122b1c84b1807a80ae09f867d4b0500e7d4f1a129436b0ec6a63be3636d5d08fb54f961802b5d956b666a7a14fea6f0543c77bf970dca64f04794ef4b480fba4fe85549fa9c67f57fc5e2cdaea58ec62cfab769a78b4c49803cfa2dad301ab600794ae6d327c0102df23c154a7c77743ce17977de10d362cfb3e63cf89f55eb41ef74786fccc818ca88212a65f5f27658f31919ac0dab8164408c50395a0f58d6da93ab6db35a099379d5810ce77b7ad61bfacacf263886e8d38ace4a3feb024426722ccfd61fb3bd25ded2edee67cd64a8b50aeb44829013d1c20ae50c388e662071c120c30ffd4402ff4dd423299fbcc7dc4094f786acc3515f9ef10c3c647784509ffbc5f5f5895cda9c", "b266553838ea5d18f14a2803ffba7f855f92695818253465ba64cb846b798cf69c208af81d9dbfbb3f0b803c746d6ab4de327a19c93114aec791b185d1c910ef1d166c4924735ec290e96f32186f9eb885042c8da054f05babf4922fe5316380b006cf0c5e497a8c323a25ab619051b9bc485d6235560e964a06dd2b2ce4cf3a35e5e2b43dd81680a048ef96ef34a34dddda6174ff8e38d0e03b373931a440bd9f1471d267333c277f67f46e138baefc5ddf3efcb55eda65fc9b42356d09ef85916d3acd92d456af8d1b389ec4b177677faed35709992210aa23b388031dbfe89746f045e7fc15829ae773f32721749fc2832b27371c2fb72bbcc5a0fd49ab1f641430d7e6d54e9b98cfd9b610fc5518c12ac6b782e7cd913063d14847b9591ed70b414dcd0e94a1a122caefaf106ac48f87e60b96b9ffc7ed144fc62232efd092dc59c867fb4ff46a103fa80c07ef952ee1217b26011755f7d05f127d29867b7915d478524f2275fbae994c48d9fbfbea28227afd42a4c2d33209689787cc0e28612132055020057e6ebcedfa88743a18a8c73b63f99b8e9c6b6f82b67ea70c2f8c017f436ac5c6b44710b456bba15c9edf39c40e60bcd5dfb0e8ef1acdc6f47fa9dd897d3c394cdf5b66de5800036bfdbe7e27d3e9c69bd164ceb94385dda4c039b338d8420ea3981367eedd6657784f216202c4cfc7ae86ec6995080d395caa0e019dd493f83afc828f301d138b024f084a73d0f0e6a5c3843d6a4018bb7f6975ed63198e4990e4a78e7082574301d753d0d297f205c2d263dad1300a3b7d09360abf04d518a0605247209b38e07331bf5ca25fbc116883a31652fbf5c545690f095354f7aacb595cdbce5d29fe8599acde8719c95684cc305b620e46bb1d14d03d87e8d6388477808170b56eb82aed672c9fe3eef26326e0ca5b777b3c30048dd3a166f32d5d86b68259959fa62af93ba5e170619bbdc51d2af0224adc2cfcf906e8761f42774da229e7532dfb7f6465767b514b4154b0accd2afa1c03daa49e825d777647236f0d236ff4db22772dc47fb28aa313f9fa95ac830d51fbf5ff66271a65fb787cb35c6a76c8390469e1a748f415f39ea2c3ba7d1adbaad77642bbeb6770459a2742aef169d8c7dba30cc4ef97630ff5340c677adaf325cbd08ace2d99620521996ee0a9943447fe7f2c15fd5d199f579165871e5b1069e7bfdd52ff3d2e21ad9ed14dda2c580fee01621335ce078c9662e574fe88e5aa2f0900e4bf3181169efbc62b09ccc778d52f2721cd9200068c1db14e24cc35fc0e627ba9daa25a0f9e64520fcd4457151537b0d056343018a822daddcde85d6f27a55e238137293e80f7f7f6809bca258fc44e1b83c0be3b19a29b61afebb8f62a6af71dce0454ce658649425f720a6109e2006280c3f775a64869127341ab21f6e89a04d5acb7e2e9ce7bf7830e07f732603383268b9dce06042dce7f32e3c023a8c4e3bf4724772ad723e303d2344067b9e1f05736d3729275f69f5681f2b3de534551f1e36f481834ea9cd112af403270b633e1e485cb2c74caa71376072e8d0486562ac0be4778ff76b0bab405a7194be177ab5355bdc7f3ef9eef6a257172add0ca3f3187345f8a362c76fd88cb811bf3f980c49c4f8eabdd3321e6ae25c86ce72dcbd4fab3eb40f4395e92993946f21e484c441a5ee7bf905b5ff85d7f900f13fdbdb09131beece0e980ed072d97a10e01341c6eb9f919fa4d0106bee0b1ce640f9abbd5448fa5000a1f909b6b0b47f169bc916fe88e20401a84aea2bbce69980d692cabab6ed7eba3f5c05c6339981824b721c7358d6a2dcdf39ee7a8ad986f9368d1a77625147d134bd2b9572e09649335807defeba567d9c0b94d391c4f7346c3dc13a599d18a6a78dd19cb230cb087550cea33ba45a8f0436d65cc13baf88555be90055c8636e30cbfc7a611f3202b19bbbcb25c672353ae6e72f92c1677875447548b54f4bb12c13511f877f9c6b5971883b78116095349f49f49ad9292d1d90d67c7f66d6ce543e0e22588a67c97b3cf7c082922611e3bf1e2ee21a6c1120b7216e0c309967755db0c2892e0787d37399f48d54d6bb27682", "7bcdea91b8947e8866db3f69ec770e87e52e771f571f3a57ce669aa20885b90bb5216cb6828613f71112e04b2a210fbc0b94d0ffa95d09da6303f9a4345529a1f7825f41b8132c2081080736bdf2549b8ce46c8711e47f8ecb578a6a04a0e62e149b8b886416e424c6c6f4c7c7091f28acb32a7ce53a370abcf134206e4810c1a7b30c8330400e7719e80462a91150352b07553b475df96f301efd90899af394778a0dd2f3a7503e992236da1f258abe5028d1ad523d8ffc300892e2f90d7e487dbe77ace5e42580c9ca77ef98ea1c50e8cccbf079aa26280cd7aa69b461b17aafda9a1de6286931093a1b60ffc43e8e7d6c5cd09e794544c64b0851c09a62dc0c40481d0086d1f51f3c71889bbe5899be95ed82f51e215d8ba8d724d21782463a13a6406274740fe2e78368b6cf4b5aaa0e9d4e2cb15cf0aa409886761ac1bb8158aca552c6dac15e47918761f3a805425e6eae87918962b10db0fdd1aeca54a97362eed4b648a168d2a65c8c033637a7263a981f0010bbb021121643f5dbd9846e7867ca38d3a94e44250f318ed91cfdbf5b266c786dd34b2ff56f5d7b2224fd5cca80db4cd4fc1f100074339077cbf34b6c80397fa6db1e274fd32d69f78a699e65611e22b8470334656bf4f16eab9a501e3fa9a672f4856724ba96fa4143744ff67e619c15ad4655accf4190c8e69e02a9c0468d4ce360182fd4431609903b82e58f8e65cd0a7b4f3e59e8808a4a8f0db2312c6631cd36f148123ad4d43a433577c5903188cb26523938c89e79e5378703e99a65290238592304ff7706dfcb8fbcba909558aa79495efb54b99edb1f8629e7a73c2db8086aafc820dbc3a00c4457e79c6de2408340906f44f0150ed432c1a24d97db28bedd9854741086d856509db3956fc8d6f79825947dc41f0d49d1640318f7855125e98ddc074ceff307e26d989125bcf67f993309406653886e71bf57ad31ef7c19cb5a54d5c194ead8c9a8bb4758f703603f54af1148c130cabf9692ded163f02a45a6127ef3bca8f72897bac5056cfab0305a58fe2e0da37eade1f789c17a009a68a04a488fec6ae82cf93dce084a53bb6a485a4b89bc0c9d8655922cf4845b21eff8f90eaa8b005ed4c2ad630fad4cef390573061f2b487971c33fcbf4a3f932ad1da720f9dd6fd0e65ba66b549314fea7191d1c20438790254e23a83fb072b2b82825506dddb7fee96a5bfe44600f0fd495a62670549cd138586317801c455a24193c63da072ec3192bf1da5f615076e1a225ead83c109c5691849daca7c17434e751c125fe7f3007e9efb0a4a4ba88e40f5a3078a0dd17f1242d83a9610b39f0b2f76e46aead4be4a6f29d859cbeefe6cb8c5a65c259de3902b39e7cd1bd0061fac0752aa07f21a5781ab3f0beb126084cb78f5ad27b985955ca4400b738350a31ca3fab883b877d445f6fd196280b6496e86e982912247a5547fb897059d6251754d3c901eb4557bd8affa406481726b2ee19e4cfd95aa6f2d19d1758eb3f26142f68e0308005d3db3fe6788fa02f9bd6af9c8caa1b160078949eafaa9199a0d2d6ffcb7988522e35ce9be2ee842a57ca166f50a37982f4af3e009ca2de7deb5147c614bd392945c6d704ce92f47af3c5487c363e793d66647b5a6a5e9639a67f6de73f84a0a8b20c0ceea8ecca91aa08a66ef1f499ac9a3ab9534cc545ae64c816b144029424900ead832a5de84a10997c30fe4893a59ddca3db6a4b9975effc22f4e2a29573cdd3908a79048d674cb5bc963f5f367499a8259d039d6ad5b0721a5c24f1e410b177a55f6a4f5357b9ce85fe61fdaa8dec06fa776de28963fbc9792131d4bfc804bc661d1a99f164c5777b9311c73be5ed421d4695650985ea34d08e1bbf77ba1113db12195a07f7c63f47ff90ede879ae6da209aa71d5a72248501530dbecd3c9d6976c14beaac76d816f64d963533b984a502a0b27b7d0779da1177e1e951e738b05063e048b1a96cd0687170e23c0cf80a1801b1375646958c1856c71d0dbcfa3df2b5a140d5e87a3e9c260b1d1848dee4e2fcaa3137e7bfb3537d9f624e2d2c1e656d34abfce8b19965ca155737882e441f793aa29dd868ff7df3d4b58362e2c25f2e3f900ac19a00e8462b675927639f4993eb8914e5f57afb8f6c7d363ae85cd2456e82bbed310fb7a1d2f2682d5a374ebcb6d0fa841cd44356de00ff6cf56aed41a17b328d95499f68b8b2bb694ddccaafcc008ec1bb09ef08acfc36a9d8402c55fc15cf11944e02b34c495b807f7e34bb4edaa1ac939584880ac56acfd3d413e8666a2cec7ff38b18c293addee3d595f715538223c528dc0c049a38abba2d014d5eb56d535afb3829404a0c850703b56665d2016737b9cb5e9d3b5d96c3afea8afbda83086087035fa0366c8c207c7912457aec9851b641759a208cc55411a0be1a2d88b61716f85dc7c9cff8643efdc5d7ac31783c36f831f97b153e1e1c661c4920284d40d59810c8074daeefc79f89bea7f1652f9186948eccb6bad4d9b1d8efe01e0151584a24d85d73d1cb936e8a1decccbf03a34eebcfca36cfdba8e3f4331c73d5deb49c2016509a87a7791e086fe7f401b21bb5c70f6a138ddeb2de448fe36c8a33183c4e49cd18c9c2eed7446645a3b3d876ddbb5b8034b0572691a67c2f205469d9c58e37de59baa84936d8509076e8ef1c00e67a411c4278ad3dfa5cccd3f4a9c904733bc885cba4828092fb5c3cba4e178344ef5cc425c55255013d9231346e37ae488e8b1d4f45d19831762d8447e3b2633d4b27d10dfb994ff4e3ae46e829e55ecde69bb6781e929c90552ed421122fd09bcc9b0e60c1dd0a9174a7e11bbcf7cd3c7a13778283b2ead3e4264fda5c5248a883e3d90d7a4c54df8ac6dd70066eb8490b9e3a9bae188e2bb18ad3a08a8091a07f183a75aedb955313eae2f9ba6dc565372be2ecc4c4a3617a6df640bea034a378d9dd15326fb8b111cbc4b9c9fabfc24273ae91b4decfbd6d6699a3e9fabe54638e18a1ef54ddc55ac187f010b51e90d4651a61b1f8c79d0236676e0775acc2f986974143cbeda6e4f084d477f23669cf91af9096313f3dc5d060dc1f3a1510e89164d8300facef233f8d69fdd86f59828ff0f2e475595649e6ac6c80f8c4ae96ac0568e51ed78d8fbf9bae5b46c61dc4a22d3a327d6e7b8eb962753579f401d9b8b8ca9679ada4e53c2f90a1822336c133ef76207ffc9487c8972de3e2a11e55b586cff7792e85d7bf3fd7105613687bb6ed6c77b3e33a9f6f5e5068fe572938d5c2d439f65b9eec93d3516254dcb20eb6ecd449110674068818dded2bd39a1df30c29838520d941b6400f98a8467f2f195f62d07c9b4fa3ab60ccce760fc690e4b25b8e9fc12100412f82f8f293474b436f3860831e3ba9341ec9459c7c9949dfd99c2fba4ddc72238141af5281ec2675da1decbd2f2d01fa7d805d44e0bd248b6cad9d12712107b7b1627b579d473626bdff17d2d2eb9ca3d5784130f3985b45efc77db29000d77ed97e32f80c06a685cee0df20d2e8fddda2c7e2a80fa9b0fca9b3624218e1d540d1295be48a00e5438bd63e5f32ec0fedafb424cb1b12ecc4fa3e8c8eec2a5ab3ff0d555902cbfd5b7285661b14224e4a43ab79a758db5493b5b9ee4c8fa5969b8f3bf38b018ef519e4b998c604d14140fb3ca1b7cdd1e4766760913ad8a2ffc3bb55a2e9918171293328b2e4a9bb2afec4a7cb21144b8eb8b299f9b81e7a956a96057ac98af90986f81510d92e9f67e2c510e34b5b6b439a0ab8bd6fa4721e4e75c871c04a7c3b5b3b41fe9b0c8d6b527e9d233c7c266ea59656dc6045d3ff95a3bae5c953db13534c5d583b250d950d0b63952f35a3e3da84bcb6a85a04691a1425c3c67a9e06acd2e5c8076287cdbe0ee54c87f469a9650a76a92228310fe016bd40508571f2324796e77a13d17de86b3dcd5f372225292eb0b2c7ccc7a85a926f50ebc7ace655d7fe8efa4e86ebe6e256dc090c8582114f4957f97ed7d8c01193c790ddf5a65ee709627d446f02f892fc40f6dcb41cc59db725adbe85b998babd417eccd0241144246871d317ca9da089b76a48053d006a5bdb9ba9aa77a892058000a7c580d8945128e192f0549c01ccdbd2ee65953ad0c96f156d40ca1dbeafa4d872e1d43ef2b58d8b1a1c20e23cf5e98b57c27a9d035e0754ba0a53b69ccab1d166a6fca4bf58a40d2ce0f10", .Okay}, + {.Sqr, "-70105cc788fb91e3cc7737ed939d5cbf1d6d2064cf2ad265e7ddbd650e4837f745eafa59541316da8290742cfc92c62284a4daeb7c571cab35fab6e4a8dcfd4dd7389d70fd52c02ce24011f895cc0612d4072534bd9e30ffab40b848fa02771f6bf49c3aaef4e7707c947dd82e0db153076212decc2b2fb66d3c401bea6b000c42f7f1170d3d6ac28bcbdb21aebfc3fe12f7c1fdee4c108d1f812729b944cb97c241a04bdf39e9a01c1318db84ea975c3c4a3db73f9bd5b797845dae39277383169e640b4e8b2d8d2e5b26c656e8bd10cbdfb634e8c30fd1442489dbdcf798478130f107b21cf4c75a03f725ac6ad17bbe97acf983e333f9ede8ae5b1dbc1584334507db722103b3d33c38dfe7dfe9c3205e0add843de1c4a115eab64d2e319f77cb7fda0af664b0ade84b93e3c1fd74570da851ba3ebb664024af507b1242186a581979e6c36d1df46edfd999bab09ecd763a3f5ca0d309f64f262a03a3de69ffdaea0e303d2b9d10853e543dfb7541f603c3aaad802286086fcc2870d502298321445861321762255eecd6498724b060a58162aafa02f24207e968d8e17ed2ba730d9ca5b2c8e37ed6cfea7677565dc4c333efd2fcdc0e219712b8641beb249c87525c5b890e5f1d970a05a2d0a67bdff7a6b5c156c45cbcb917845e3d33994f71f4555e5f9f7ec8191b141a02677bf80801ebc6e7a9eb1e88951006b34fe0e55dc2647821c8cf89933cd06ad5f8069f8517e1d7d9d672394fde04335a44b48ef8ac83fee597b13470194854067cf7754be2127564edc8934e755bfea7389b2eda38c8260bac863053d79d9d9d739542daac1153ec6fc4a056bb7e59f9813ebfe93c523f2e8604896c746c827572ef39c1906dcb379b8ef595cf764a968b42d355c3797a57cf3e2c823cc28d658c57cdfbb44007bb07b176c7cfd2c273a93fdddbd4aed6a0c017ff3555f2812c15c54223c9121e671e4d2c70d839a632e1db56314e870ae156a11bf8dcc6694d34d4ee6e835005c6057b576282832d9b8a3b2a73d57b1d801596137e8717eaf282940f1d8ef135a305dac1db7aea4f78bec8c0081d9942d803dd56fbc331eec5354cedc859136fb2018525cd4374844fff093124982f3db1e6a448a4dd28ce1498054c783690542fd43fbdb699d3c3a3a2fb1ab8df304ede0636b3bb86c35f99e2b7017c1945e6e194192ae7ec99c03ed0faf12f0578a297a655fbfb0b97a5478669b51bd93a232b2def4a54520f7a00c04bfea46745354b0cfd45a852c6a1dca475f170b489bdac814b897935aec86ddeb96166ee7080a3e3c85fdf0a8fa731811286d3ae25b6313004418e1e2f4192c1ddd6ebe9b9f6d237a511f1a8859fd473dc08c8a5f61ca34e49d565f1566d1c4b0b6bcf2cbe6463032a0d83b0ed5f281ba6aff86c57a921b2e1aba12f68e51a1150676489d0cfe5da2456f8dddc51a912c44d6f8fea00fecc4fc79f96c0bb368449bc243a5674d16a330b3d0bd080b44073dc5215012e44f6b9f434b64b7c47851a7f1a77ea768c84bb53c74276d1c02e9dad2452d6deb76b0826fa8baad61d212aadc2eaa744ea58fde89141a5ce3186ffe50378ba56f1a085142994263ed224e84a4c97015ed23021cdc0422b81404b3178b5a3cae1cca5f832f98f1448a81363346aaa747619d913a90d664938a75deb23e99a954b13d70d6076a1112bfa9324a9eb7bedb44ea6ca2ece6170bb69e63ec39ed74baaf1873da50dfbcbc1d6c192b95bdb083fe19bdda46fed26c32d22b4bfcd5110383705f01c4ecb4aeb152eb8745f06984f97bed07d6c403fe69c6e6e0eafc474a83f6433cdd2b3fd2cdf8192637ee9201d08206d64dd0b0849141c31138853f4e2803096b4ed53dcb20a80afcd3638ebaaeb1971eb6427f1c1a86dc921e6bd07e172dbefe1aa17acbb579abca2130c8a74053ffbca188bc8dd66b6ca3f38c2e3c4b99ec02a0c961f17f480ac24e7f3c5ff551eaa536206b87343aa9e2d72771af9f573e1a4a76caf851c8d3f3b5fea5951b1fc26a897d8fec421a0186223e56c708c5a7d3a0277921d4544deda537e96dc778845997136be6985c5f8373e902e19a22e57ed0e3840", "9b8ac7e7e4584da88636579a588ec6256883b64f1649adfd6208642cfe63766fdb0d8afe1379093e5daff36a5aecf355a61bc62ce4e36dbe9977b6cd9dc786e07c8dcc71e78c392740ed62d509d67077dc8b25caed38d3451140a6d164b9ec5aa924fe8f4c553f8787e1a0c24a6b6bc709b8cecb9ceb1c862f355f603ce846931e4cc6b30248bf01226c0a44b80b07d5862f6785a4cdf60693672db5dc99c817fca24bdaa70f5a4f793669533f3cb99af37a858149610c0f2d2d750e6716c5f85a4468d044506e3b9526b112f0aa6905c2c668b5f7f4f3e2c62bfed2117c3ceff66d924ec5766aadd593679b4eb1f58152583a0bd41db1eda241f19033798d8d8758fe66b4f0a1f2e52231c5fd6e696090cdf23d9c1e1d8a5a2e6ba69cd66b740b23e8d3a1ded0f09bb673b7420efd388a22929ee78d7f37f289127a56e6719b419aa8e0b70f6fd1d417317d97409e83f0276fed3a5f8ce40c5602ae32df9461df69b02812bf7f26a53afb9cea229f9feab1128b96fc96e1baa36856204b040a3755ef1c514ad278cdfd004bdf36361203a7831c870e0bc85f2ee913c597998a6fcc17789798e66044ed8e679c8e3f341e579331a01de3ae48542ff71f04fa1a4425a1be5e6df000cdf4f710f259aac555ba21ce93b55c129558b577a32e89218f76065ff8d24376c04e1cd6a0811afb014f3deb738e5235a75bb94fbd115bc93b69a7e4b83821ce600e9230497ade9f3d40769f70c03aff88d2adbd23aa51faa01e425323721f9b22a1668aa4bc506e1b7272c9abea66f44ad3dc27da333d096f967ff71ff9637497abbf13dbcf156b349ccfb595366792553a568c964985005109b108272ee752a6bebce419ceadfbc766a4cea98b058bfd24946744ca7731898e97666e9e2d20e96f09b3e99ea3e3272049ea46d04797717b3a1865f28a39c6d8bf64e52efec6d6f6207f5554aba48f7fea6f126f4fe2dd6337c50c8d7a8bc218de1e9031f38520052cfdfcaff5daddd8c6ba3a35a516ad21a113d72d6e0983f3085c1cb370e928858b9f0373e5741224de79ea08f09aff5c1525a995c2645f97395306fbda297c718fc149a5d373c56c1b3342d53de4e412c667190ba8eb7328584ef11ae1ad64b01e40787c8ec761403f913fa740d55e63bf5d05e2079bb5bdd48f2f2b44a3ab2c6c1a64699e8c5216c939d5fd6b30596c262cb5294f44712bc5bb3b855e587f00ff5c25878af2ee4e8c139cc77469cd61ebd7c03ea0241049670d5a3321d63aa15bb9ab024c4b8c4ea1511bdbae9db4475741c8a77736285cc5b0ce2a8e6ed9084f3c1f5c7c4cfb5b27bc9d52da746aadfacc2081354818a54a569f9182c953f29e71c2140e3cd84532075654690d69cc6fc8736d8a3abd2969858edae2a463ab0fffd04b91f91d10da465de3603865c336d92b0efc24036f20153fe6b63cd59d03def40890e7853adc9c524b8b443d1f56c10e707c7f733039163c905e4f3594b47ec21225a693c20962c98460b35c75dcc1ade18fca30008c04b4ae487627754c6c2b6a50cf4a7d8d685d2d10ec2d92a1e7116b434e5ca7fb1f91e3c182783a92803cfe45f6630eeab800ed3b186897e8bca5669342ce70dfafb1e3f5b58af6b22a5e0802b96159f6336bf5aafd5de3eff6c730d8a9e8d4a6f935d5027b5c7e49b4ea299a4223052193a9f8da9db785d0d1a85afdbdf414d3b47164f499300373951568afac60c45640780181c90c9188aa1be424e0a46d06b0f590e89cfb91ee70cbef016730a77a22826ce7d0f5117d7b97af3e48c86b736fb77083a91c5a4ccae79058bf8f79af607f8b2551836eb3382a98793ee20b8d6d664ff733d839673d0acabf3892e91881af24b4ef0339d7bdbd4daa471b93853727069fccef00a40ce6dc3cfa1cf4a4441c19bd10b81ef9d4c91b8b3250d3aeaef69a26a60076c6e0f5e268aaf3be246131c7d6c1bbe6e041a0adff5672fb94aae915eb36fdf39741a6741f672639607da3a91079f6612b92ccd6cf6a3d1a2ab8537596205aaef42527e342e303e8940b6eb7ebda7cee8f771ad94812130fefaf713662937be00c496ff951c464fa8ec7c9d4b34a48928a6f", "310e523a526d4514a0a6ad2de17d4fcecfbfea951954c9c5d859f6553e24627d7cc2793cd692f79947ee829f0e21a8ad37337ba2ea877a0e0ad3e8189ef538cc5bca005ac17931c5145a2c050b8e5841ef500b3bf8881d694edb6dca3c635b46fe3ca853c2b3a1b6144704fa59040de7860d7b99f1e0827559f7ba8e4d431171d59fbba9dc9abe38a47f8d62a1af2309bd6f58734e3cc49ae9380efe52f0804079478c3de5dccfe6c6a7a77057b4d8d0fc40301b4c554c22c8a3f86ee8a0d63ab5fce8a0f5085c29dea968825973287f7e06d3ba75e035c57fbb7eaa5f838321e335971660e426581da091a4f8353535cc150d1df89a794c9e8decef9f367d4c574aedcafa43c6c7d7e034d13a9102874af03f43428848e5e1cdaa9186c2f3dbf365af0320a13523619bcbc6dafbcf7c25e755f1bb6d19d2ddf4c72bc5d27cda514ce97a3253676b9c009babd9bf554389175279700df3f3a92611bd0677ba8909ad440559e238e870bfd904aa912fde3abf10c676943a94265b92fe6b93b7abfcc032bf8cabc19da963d55ae5b58ba9a9136b4c4d7bb6675a90d32bba0c63dfe8bd17f031decc849b17aa4dfa32534dd9a3c3ba904dd7b3a955cc6c6fc8ecb1a2375c919cd4fa39317421e9d87f7fae6c2910f0f9aadfaa8e4d265c94f19ff318fb006c74c7b45a1a8e784fb5343d31acf26e0eedfea3aa14549e9da3f7c5b943893a4167c337ab4cdc19b7b2a9eb090b53d2b99a20e9e9109ba5e4e31708ceab04a26a1dc7a80f2e0ac7b66d8dd0f2dc4ef9e5fa5a1324b434d0563d3ebf96e1eea66d4d97cbd7d430fc172949c6e3655d1447e79acf3df4770fe3ec50cdf187f2bd5d3a857754266bf7bbf7cf9918c4594d6f10b2471fc46cac95bc7fbde93e78bb6e50525cac145164a3df1a57b14b44a62ab6d08f2a2cf2a2bf08b16e0492cebedf9dd394d7b74e0a7b2975639d3a1cc98e380da9e02632bc709ce7d9131e701acd56cf85ef5b23b23ecfc17f2cbb116da29141583e629127fbd7c22c92c17b539c648b7def7f895fa9476e74661962d4749291a8e0206cc6a9438426e13e5d5463913ef04bacd8938c2c39476685d479030aa3f598a9c7aa8758956d8f25878b62806be0bde60f4778542a4733b9a5fb9115dca1b6a032872c66358b3033a4e604497ded677a13c375fa499a9bc6b5ace2deda73ff0717aa2ab00ff95a4680ecf825a8dff1d93cef0a644b994d5e69b4162c0d740b223b32b64187d398eb4d53a8bf26fd4a4756f02198c66a00eb404f7bf888a174abbb90b3287c4c955ad4be7a7ba3ab692383bc4f75687d42d5241883a6617f3362e793fe0dc594f27b46ea3d27d7394e49296df1f2f3de4c8deb51bc38073086a5c74f70627fa9e6949baa49f833fe0977f34175cf7941a705e68e8465d2ff95ffb6b375ef700d888d7a1ea7eeca1f3cec36f4ab33569501f06e87d28a27f4438e446fc9009dbe1aea806c7f33b7a5f2a000311bd7c01ef7e1aa78339fab8e4fabec838c70fbc6dbb17c188e3cba8ee21a518a79375e037dbef51824ad43e28112bdb2c453c4b78a2bd369d90bbb901450e8314331931dccb6a95b3b71cf2da3b5659e75fb8e45b9eba907d79712615caa9614c04b47f18845ce6eebe9aee7d3ece241e9e1573e88c8a299223f6208564d5400676c15dbb70a8e132b3c223ded745d563ac0793493fb8b0aab9eb495d1876f17b36b0ca80df8adb6e45650819e85f60dd3a9d31785e574d56bae90c26ae63456db9e675363a47bc082c4c97e2f0f97003b7304d6de4341eb65eae88cde01dde8285965deead60741be03369569908c33255c13e0f02672650dbdef4ee7606a89921104d6a616391759a96082290058054d39e44a9ef1c8775b0ea4a1e19a5368b05851c5e2495e9f9e1d8861932c6d27cc2966a1e4cb2128680d70480281f984e58955c2a49c809c19fdcc2305e5b81803713ee945657d27651e4c9b625b8312e98537d450d273d9717a3f8611ef34cf3125b90db8caeaad31bf3736f84ba0138a9d7ea77a467bff81def7f3c41f2e250ce75787f3f7a70e1eb9284f995741671d530bd6071ec7bc37ad1e9840a201700776f60c2f2f37f8783a99ea8d2b78b2b0aef036c85bd530ddb3b0066827f56d5ea6271801d1d5cefcaec73fccc49bbc2bd4c87fb8822afab00390918e6964e5b447a8a43554a6f62ac1ed7f50da825b4edc029027461c44b91b9c38ff75a671a65cb7f0293fe2d9cd570ebbf8d2b33bb8f524d5c1c83fa0858d6690da19c8d68fb5efb6fec30d85ec11add766d015a37b6ff6cb3f691de7e4050c130381e7723b2a8db68d9d6d4736f93f9d64f9f37e21a80d652d9ffde1c4c7cde342e61abd53b07e09adf5213b362c600404effb203627a32fdc1ec47f2cd996b9ce9dbbc7ea74c63e6a54df2a8de81f1ad24da0b79626fa280e81bd42ac6edae700c25218bf7788574d47038e0e19f12d6f6ad5174453872209c8f3f3cb950144fb7ffe957a8424760703a4feb0d1435491be49f9e5aa5142ecf8730245983fc56a08f1c26ff9e84fafce7b45a12be4f9621abf994eebf8ca8b141d7c3433415cbbc6fbac2a54726df9b4efa8d14b74d374461c5547216feeadc6f591dd72761c5deda840d8e8207c9eebb71ce4d4014e3dcfa1fc4396458ae3185a6cd946b6a2011ca73db7f59fc6b09bbe8ecd1d776c46f2deb0096a26665428c639aa4d098ff6e7b70f7ca9c3c5d29def1d2c619746d5ee9e9f67252cee0294348a8a0b8f05e3e32c97ba3bf17ac286a986a4fc0e36bacb398a2925a15fc77b0d5150822dccb29f0d83f0be7c9336bd9402a440136ba40e9252897f30b1e9562dc92c91b051c5c3a61e70fdd0db08a8e2e1c3c773144f53b2c007d9186cbc39b1f3f3e3aafd3dec6f8719a0de35d4ae01706d9c955059e4b02128ee710b83a21afe4c31dde70d2060e4db707754a55c8345d7778342b2e43cdefb39eb3367d36b9439fd29c3f41533e357f518ec28f5e1051aa8a5d42d1cc02c2c169da813b5bff607ae04056d292711a5e0ae1429e0f9aa165c997369185c6571cb2d7976ecb6fd5338c0f546718c82870745904b0c93b964d8a8c8026c4be8b168440844dec137ceaa7f7960130cecd26b9e3218b194742a2c5215e6fbffcf75abbf164a88f682d2089e7661c7a0fbd56065e047d7a82459831225daa3f9cbe5f722a43a267ba38b6791e4385ecf2dbfacccdaf9b497b5fc3b6692644643dc4f2be2dd7c96143e8623ee573c49122f9ec6bcf5c3b8e6881f5ab547136840ad3e31617c7c7f04cf03b8083da102f07c7bcc7c52da799e1358b1758871610b6f0bcdf4fed51b719326ccb34ef9beb06ce5bd7eb705986ce99be1d0d3ecac24f4d44680078d79d5728201d0efd443464d5615e3353aecdc8d740509a66b45e9b1608d5bbb2beaeaefdeefd046582806ef00207f7a8bfaa6a1004bc8174f9e2efe40688692ff3d92619330afff889bcb35b80bd0c3d87cc494e6596dc7dfba875c7d5de9fa2b344bee4d3e608ddb3bdefa5039b511fb2d315d4e09b0410ddee0d367dd99b62d6ba0388551655612781292a6edfbbe41302ab1bc5e16535db0a93f5b55f4945d663b5b756cc3ce2f62d693740e99530ab20faf4958eca830ff1aeb2849eb241d3b5c970e7388b5af9d2236284a6f3cd77c38873508b7e49961cc58d93f06074885b45655554ce354e45602f1872dd2400273badc08d549833501d8e7f535d8e57cb2ae8f3b34c9d08003be6c60fafd7e0533a61edb3cb1dd2f41e530dbba9113daab8387096a0e5a7734515e6dcbe1e0197e30e91e12d83fe309b3907ee4eeab1d7997bbf30821eeb716e14a7fa7e716d1fcc34bd3cc47bbaa1d41b494957c5e29f31f6dbd15e1e0ca3b92f15336f8f0b1f689cd8e35e2447e22d41efca1c881494182a5f8a6fbf555f60fae8b127eff58d5c81e09a5c078098b62821275bf21fb44c1e81c5a6af864f1a1955b54816919bf978248bffb76d1a3052f046d423821dc578ff15d65bf41ebb5f8e3531b071cdf0a7760aec3d3231b48774669f76ce9bc9d444b6c8e2cfdcbf713e09aa387e42c36fd50660f11f5ad307cf59109227f8f969aeca1be9b94f9e8e45a5f3f767f7ea88bbdfa3e495a2d159288a83fb9ce4ce0aa016c368b3e0cc68d50bcc8f4ac2a655b8d4196ba080f1123cb5cbb5fc8649070b35c1000", .Okay}, + {.Sqr, "-679164dff75203f842ee4abcd9f0fcf13b72f5bca4e013961c042db3a97f83fef79e15c49547258af7bed6e7511d5100000e5f80835769b05c11a214b40846b1896482db71edc7b2f26ee42c8df9bb5a511547ba3e7ee177e99fbfd6ea5d6825b3733047296741758ba974341059d501f26f4ecfd0dfe1bed9304d32dc8e699e5f8a952223c22d1c269654f88a4c31ec2c78d4aed908d884e109db3b4e78cbc0ca779384ae0ce4d49d8ab9c95fd00c6bffdb8c8e2c0b7472f1a355fd1963462de9c80325e8a9a07d8d901851a1fae13876d53998e13a68cde41caf1ffb8131f3b9b03dc290cffc1cb2ca0f0634b9ffea2072eb56b390c5a884cbf3caba1b18bfab58720cb93cadc869414c3b49b86ec7f57fdc2e2218fe2bca251ccc7416f2c4e2215c995ad02bff886abc6b6586a6acaf1e0f31a45388b525029cf3a188087f4ce4940c250ae0ea0575520c014102ac491c346a537f4ea68512e3d41262cc73c84f065bb6e4ad6b66c3ed0208ed0d05ca8220eaee9b3f4a6bcc32dd0a9bad431f84ea262018272c56360ebfa5532ad25bd1c38fef6bfe50039902e2df5f6d4d2c419dd85238dda2238f7f72fedff7aa93d3388c1f3f85ddd22c87c95ac03995ddb03dfd472b2f921e505baaf5ec89adc2ab0a05e80c8523b65192710bea0634724b9971996118fddac57eae788c6c306ac04c81ed05d0e98d94e36838ef1d3ea9787a106e77dc8256fe7c3775c4c1ac2cc932e7d789caea9a5b902072ea6df9fea1071b704e9e1ec25e9177b79a7915f1aedab32fa91095b9338266e1a06e59d3a4be91aec9e577f9f16ac09a9fae1819cf2fbef76c618fb0b0f6f696ea9faba80eccd8cbb0f78c94cc9b30670ad9e59e85ce621b1ce35f4b1a34a650fa8bf43df1c3acf05fc730ad3de43fd60fa7bdce1211eaaf7cbba64e8af979038bbeeba67cfd79d58b503493e9a402ccc036b46498c14df462540c25c3e16c1242873605dbd9f461434a3f4eb5279cc7a819b05c3f4ceae161b8200a745400ff1cf77f6e68b8de411af4f47ab300310ae825c5ae05d069bf1e7649a827a7a0e5237af69a9053aac1c0d68ea59fc8b03878ea88e155b7bf5bbd01175edfc4f4600ea77b8a33843a90050656888325239c6d9d364207bdd9aec3f1cf53e759ed81fd9981620976ab04ea8633b3540e4211e421a9c7fe575c099de4f21ae386da66d7473a82950c5528b2ecb0f067a254081eda02c8b0686ba8b9526c7a4e909770a8dc30f3c43f60cb0f4643cd6efd0ce0bbc2aed92ec09c5b8e1db1fb46cba26a42ecc5e66bad6a93670c5349e1ffd61563c3d0e0065a19d219c2384ad728e261d0e4eb94bbfea6624f00da2b6f75217e4d3b8fab7ab05b21954877a2c208a91104053ca685f0cbe44204a4b906ac281a59c7706fe30c754803095f49cc3a314552e0e29f616280f5483938aece61c29c60ab438d55a949fdc69399afa84a724da62944163d97b310580e7263db7b3112fbef52ccf6513d5509a66097e1254c90c304f9953c1fb19b47b4f32e46938cebf3d9fea5d1ae251ab88c7b3d3217ea519d3fa7865ef0580a643e470db7e2e3366c93d8da670cf8776d9427ee867aa5baa60e5c208ce0efcb1093acc32e6dfd3105e39367d5cca3d2184d1a75f288ad1b2acdec3523b8f467b787fc04b15621536d979969b9cf84e1ab82064b3ad1619023304bbe366ad9dcaa476ba04fc7dea09c22dca7c35416ee23a1ba360d402511e000abebf1b5940255a624be0dde0c5ef03eb0ca961f0eb7b87dfd11f0063a53df64004ea1b42d705bae9eee561d8999dabef0972d6782891ca57f0ba031e9e11b5f0d6b3121205009db11a51d6226fa27d613cc158236e2a6c22cad869840c86aef3b18c9a276b95a1f04a3cab492229cdb0cc1c70278393c3efc9a8947313846a148c7e84031006c894234d98fea22ba337623292183df92382f2ee1ad209c28a14aebedc33e0867d9cba49d9d263ed305c6278c0a7779bf60389185333e5577450b213b18b17f9b91eec98d54f73c67ce9190f7556e1c4f8d4a7c724ce66c99f689d06eb03159a331812c8fb15ac85cf9aeaff358106f91ab732c800369", "1983f67427a28bf59db0a4eeb855a0b95fc4057d099962bfe7d56e54971ab4312e7cb1385acaf98352936f7676661787c9f0d751606d0c122c3d51b438da52611d8909b06211b5d1babe1caefe851abe9f6e004f25cf8c5c89721bdb9e0e9434eeee6b7ea568b2d1d7d77ea56636ee32c5440a88f793087a5694affdf71d61d5324103640c61e9b55e1d83c820f4568fbdd3925679c54c3ba13937c1e63d2f400375a55ef7af7cb33caaa7ec28e5d3879a0411ea640f2c79a55295daf08ea78f084491eebbe72cbbd4bd18a220585c99a3cd0ad5c9e0a4494d8b1cc05cc104b2e18532372314ef5808d64e57e2613042b13df7cbba1497a9f15359d111eee1ad0bb5f8552a53175421b03a1218dedd81221478ef222a9a3b75d2632d09bb05a7ad85089b85a93cd5249afff4a058836d16612c6c04cbf29cd1cd1a5ff417193522e5c7e286a48dce518f22721aa8794f286b570728b7c7812cfbf369bed7ed14fd6a6c3d631c28194b945a110eae4e0c5a24bb90fab45d3079f761376452fec552d19952a56f20be8918dc11f6cc5e2602c7b75b8b53fc050ada1601c66e8482f076a1376bdddbe4c04d333bbbd6ef4c819c2063646edb663636cfa150b502f3f2c4b4fc97695de31a65c915b09047498c56ab9df3676a745a0bf77757cc49e4efdb517e51bca9696e079a21acf63a0bd01ef7eb692e24d64ebd0ba96bc3030cb0ec5b89052e848ba2c67a7dc11048598dc04598f16f17a5199495748f64b591c657f1ce1117aa28e2fa61d6430bc11e8f865a48f2341d1c931c9046abce5e67e1662960e515d2875affc62bb5048aa96cc05878e584898c0d567fa2632d6d4f4c381566f1035bc4c04cf1ef3473c354c1e103b607cc32abd2053fa4ecb1335d9004307479605b2687950374985890e13d5a4db2fb86d7d5941337ebafe03cfb1815757149fac9a5a282073dd3250c4bcfbd1920bfa739d5920e6584b434f14bfe64c6a40e73021ccbf77ca4fe629b7a4d5797f35e3e758f5db15aec4476c99b6bff858cb47ddaa9f42fc8456e3e1a9ff6be7ad35a6099778cdffbff872f739811667568e6a611e890bb105f87c901770fe3abec5e3d7d46621c7d651c832a5c183f233a699d40d7cb00cde48900f72cd3523b29540ee0e426449f28ecdf887224bcaaaeec2551a179945c3a3825e84ae57c0d7cf2617e1bb16e08af5dea7dcf17a8ca4b826a32c03599fc1334df73d6c9026f69c0ac010c0d718d52abc3b811ce612c8ff1e3b8aba18d315e37ae1be2b4a5db62cfd8895ab6f3f514e8f11d2b626cb3866c7e8fd0fb895335c0c5cbaa1d8abc7e0367a766a01afdb3e05f6ee1fb4097ae2a76f8f9922f69c67568b2c1de948844f84f79ec78eea6c7f62df84a9ba1306e018b3ae835b431e1ca43255a8ac89231c79d2268bc96b0ce26ee105ece0591270ea9c9101a975f1767d0ecacc83f94385aa0ee3fa32c7c72f0b42c310476e0fbdec9f40e2535f05b98dbb33fc6058f889e12b176f57a86e772aa01ffe5a50ee9873ca93a4952a8310e61c5364015a5273faff6ba5ae80b121618c2d12aaafc4b42a17dda2201901712d29072b39ca49511765f9d68a19abb00420ee3eef0795d426aa7783763c57a93008d02ca1484006c6eabc957a00b1fafec2c1c9331d5df62fb5d35216865f0828dccc1ae627a11fb6b0106f21cf0749f5257625244f4db98cb3bbcb71800b17e340e1007b5c37e738e572b934fed51d1eb4215d6496ab077cbf5c034c8512c2ddb5ea7474e5efbb839c12cb9a235105145152eb6f31e4dd672c55aeb820973c20816307afa84ce23a51a19e4abe5196752993a3e7b3fc2bfe6b89089cc0c5cacce6597786d1510c923c39d000371b527856e76857ddfd9999f3dd5d56eef2a43c5586b8e0a6a7e2d3126c345daac13620f054ffb578eeaa8fd149b1a62097ad8c06941db0974ee7edf3239df7a8c939fe35701ed19a50501820f7586538405d8d9913e8e78414a473c605c18e392e6f7fb0a590bb439eabbd069321bc89c2af8b257aea0d28fc15ef23a797b291a92a40e63c9ea869431407b996deb3ae59ba853a2342e2fa5c1d9c36e099e34d4b7", "29e651bfa679e7432803ced3031b0504410c9a857013738174b2466f7f7058175df75abe67ddee4fafabaaed846af7139de291b31bb4804a11528cae5e01dbbef4cc00477e6a55f4237c2c0234fcbb501d076d16f71aa87613d964ed9f628e0ba186cf97feaed6047b9ed0ec617b715f9d99338e6854b376ba92747bd80deb39d9a3bc2ceb79bcf7212d5d0ebbf125ecf66f43ed61d59e32820e7c6b341dad6facf0c0a74ac640bc55634eb2a3bdbfde718fe311d6dd5c5dabd8b7bcc63f2a3714464a617e0d25243fa4bfa024e903b0e2dcaabec3ffa9ea1b9452a45a81245fe08a4d738046d58b637452c76891f2deed746c42354ace6777b13a07687982e26742882771f2dd988679c88d7c39ef2a46696213938a2e20cd4e446040be2fed61df49e0d215ee0887de3f56603fad6c221907cd3afa3fe5f4644251e3fd88fa3622a34585f138345a0dd5a587386b6106275cee5a4d2ef77885dc29cf19adb601b6adf5eecfc2f74544eaef23f484395aca816521796ce1a7ba369a998ea6b236eb1348c309d2ff69b277e1f97d82c713e1fcdd104738265bfff2368bff1084859cf7b17f0a8321add20b0b3e952392b8a8f6789dc5571565b916749560289ef94f9a5e3294ede4590152e2f632a2ea9313f3afa3ab35b731e08a096c6585d570be150c117a062e52a7e1c19e5d1f0b38c93dd51fdb8165b141bd0aae09ed2bd8e8343b205f1681ccef53b77bae473c7740647e597ff56e57c03a101d367778259cde8bf5588b5381d2db06c3bc27410e1ad353786de55974ad1b23d1ba760393665d83739e0789f55d1fa67ec5968307661ff0c0fdd34ffdf8118f5eab4101ea9a3cb04193a7f738c11ecf1b296c17dd1aeee348e5c48929c0371f83fd258644978170877c23da4ab89b140b2f7c4f5d84b260489966496f82c475cbda06deb1ccfe9fd0de5e0caa3fda0bea199d3288c33dbfd1de8b7979290d9ce4671c7ce21a403c05022604079cdb24922d1025c49ffba8932cc203833307fa9b1d2537d411423515840675bbc904fa2d88c9d53ae46dbc00da90b8c67ca07d5e282b6736f5be36b39f0e7aba9d830cc68297fff3f4132601d3e6296862a8b81f436d8086a8120eb164eb074d50abb7ed8a84792ee3372370219f46da795b9f49cd50824869ac363464b03ee16e55f4f24248dfccce9a33e08f5925122d3aa51073a5246d88232ec84297fabc87d1fb7d402b894bc9ebee11bbd460f4871e7aaf64ee87f23c82ba3296e2c0cd645dbffc1897e925616a8ee975835e7115877701d9ae68f98e803450f1f48f86e5310ad18daecf10206de0abec74504ac0e4146cf15d5abc8beff026d09644777655165424444a2f186619142c3853f2637d73a3d9e8c1229aca01dbf3cab083e9535957daebeca1a1947b7bf16635376fb4871a4ca38ac302f148d88bd26514c1648fb0bb6ac7921eb83266de676058a463bd447785d8030bbbad5646222a5a21292b7d60cc60fbea81efb655934c737bba5b3280fded829f95a708f168218e1021476dc57f1e7c563c333a6f919a1e76c9eeb739adff1c42e9a719899f22d6e0488285a54cd5347170a5bd97d11a7a62cb404e52bca1365af04a073456c511e60ada27ca76b57d662ed458993e13dee02e6c14ca98c8281c1155612a0bda05afec4f289273bacd4e914886bbf8986fe14f92e7ba9450a4cf20a6356c799072ca77c42e702abe869992d62d84d865215249e4239cd5609e5cfec0cd0a089ffdf6b26f1375be80aca6e71a312ad710e3d2b0dac84955fc3d72e1e5c338d495d53880f5d9f40b9a9cce788875c22988bd45032b7dbf12740119a59083a3b162eca2b84a5d5e8b3e0c6af4c14040e48a558299d23fd0c5d7c2ef5cf4a6ad41d5ce542cfb4f0c9962bb29cda145ec2364d0d08423b394cbb5819d2caa4dbdbf3b8a462da1c5016e233450c5811364998df9f364d6381938987f60c440c2876425c3b39eb302adeaa60ee65a66305653549a0313abd2eb63731c526e333a4745c5968f6e4bd542a313e7c45048d0b9b7f02fa25843d8926452486f7e0ac542b20d3f8d58123bd6553bdfb0c6b2a9b01d0c090af97bfdd547e852d28923cd0ffdb1114ad03b32316e1e0d990a64b9b2a1b5a17c9777568378e324520d2b5dbd449e6eec08a780114bb1993e06364f2326d1debde7af9c3fb72ea45e2d423b6096dfcc4e32340376a296985e19d29a00eddf193158359c6acac7ef2864d9623a25593d1241eaecc88f7ebda057b0615c89e4cf4f11b87436d17a4301e19912d15d43bf8fab055d63f222eec0f248c6cffd430949b7b4f94462e2d912724665c2a621fe777e298832f6d647d4323267dacf3cce1bfe6946ee55e49834acf247eac01fbbabbc7abd417d079694aa029d8cec9e3d756266225232477a23ab9e0cbbe7e85ede86174db2dd29c174ad52feac572350053ca61d9a8a428ff1ec9611d3d9f7f61c27e7e42f5df369b85338df149f5134d116bb451191ae937b2d448c0c786ae9004224c184b94a1ad01c614adacd5cdc3bdd7c8ddc213c179b3c908424793ba9aedf1563e7bc6ef801d755b06663de0f2a0d53265b7f4d5effaddae7b2559c0f64163a473a73efafb70734004ea12d1ca3e0448b6ff5016153bc469a59b21c0a8a8701872c598819fd65a37d1109bfd98638be170cc6466d2a32fcf59c9bcf4a9b3bf573d703436b29c77ed28e7a36f324bc459821f3dff7181a543312b43d074972a836c0bcaacadf84c8b0a0d0abb515000a4bb15d5efdede55f914401e701e78c59a60d1bdd1819e9644b836958e090002bddb37e44fda29fbc4b0249ab14c60393dd5156c22fa98a70959856c0def059ad4cc0ffe40d9229c1e482ecdc95364068c0c2e4749a563d0e12df7ac9599a62b54288e50ac585fad842e6df18cfc48eb7d7d2ed335a35dce48eeefacdd4f3f8f6e5f355d340897f03c2becc50f01c9502be09df6139bd7a59cff852495fe2aa502b3c16912c3358e9629a09c8025d12ef15c2aba894f0bfb50c5381a8e75384205ef89c5e1bbebf5bc4e032d49552a533f903497b60a001f0c264f8bda41a3217f24353057bae0dbb9785c6f28e3dfce5516b7d05d1e04bd2576896711c10c78d2d16b130d195ecee141148e38577e992eccf62685e6e83027b265c2e4d81552044ffeae3eeeb485e4490f32086c255a21ed57b31720a1cc7975b7066442672abd3fc18e3f4d514089e7818c3af525a648c4439d270de359c031d9873a9081e77c20ea4416551a845d5e1842f6287d5d5b71b660da5bfe5feb5676497f8d1032b93ac590b3b0cfbb09e59635f181c0d4051fae0f5dcba936d112f810e586662e5967fea87af2aaea0903e2a629b6719aeaaef0df1a5748b3bb297e71c698aac56db4d50e1d8891a75e386a8dfd960b6fdff697e9da1817dd3ceb5f19e2ee84a55cd288323c40f09d27e15eaa81361353993e4ae792de8e6d1bd0eeb55515d10918458b8a740a680a516614a035914a52597e21d02e7474ba10b602a7e46601c8223662b3983b02abd4ace2d4a3c9da141a8a036df0f0bd2d119a38452aea9a07dec43ff528cc246e85b3e6c807c30bd8682513a4cfe4d51d06cd38d8897e7002c55cb6fd1394129bb1ee75ffadac1cbab14d2012243c177394894345bb51437425721b94a090e04be5f11cf1e63b77ffd89c70043cc9b5f82733f9827aa98a38df810aa314bd38653324cbe3944233e175a8a458090e27613a8d14ce9d036611c41fc1e718e04b4fce2088205778a2fb73210055cc035eb3c3070ae173b55165ff0e7823270a53c00ba67cef4c8331412908154a38269181cc9a2df89067828c95f81a25c2e54f86a7d6b91256ba56bbc53d9ec59f3049eb97c7a43ce2a550fbbb6b8405b65216bc479f8a2934bb5a390023136042934c0b214e4c7cf3cdbe0e2b1a6f3d58c18b22193c69eb4fa648f7879b422a417965d6632db42eaaf12a44b451f549149d1184fda5eabc5aad6020e22fff562c1e12b04c81c64d545793bfa3138ba6adebc9adc076707f14a4d56426c73d4803f4c635eb4e463bdb2f2ab668e9253c18b016786dd9bbc034f902ca481a586a9a0175ea7c3dc55afdd0679885825dc80bd9d4a1634f2374cb580977461388ded159f450a511baa54ee6edb5cd59194303aaf403535eafb014450a6fb25911a5cf23f9785810ba111", .Okay}, + {.Log, "3be88a1fcb510843cfed84621b7f2dc86ab66de99b3c988ab7f6200c07fec4f6075a975925f23161d5eca8d61778a9730e45190af0e60acbd06736fb2df0973d1f8b39b4e52d09e85d30328598ea6be5792037e8c2f773e0deecad053ef2ba1a68a5e33040e937cafb5cba4e71d2a30d085a1f7b25927348dab35a5f6592ea2bbcdf1075112763673032f0fbf419fc9d6387f810c1f2714cfbb10205045db037eba935d39f6144fbdd0ba9f10cdaedb8352165f69f594c768276de7b79ce6d313089201677c9c019d77db9067ed62bf157bf7f36f273ace081ab3389903d04369dff7ef51a208177d9a6e0100c5a8fdc70c8cbc988a37be8cba504f38588dff401d67924b833a681ff6f6fea56fb78dfbae8b9dce733a8b94df38b91af7cc298381ee78a60462c0b05e311441fc72af86918202967848720e1b13c3fd1e0e7bb55fcbef4ad058f6d32f176e0f751001e1403d9d2579860f4e38d8b5409e68637c49a2f3424126679cdcd5d9cafbc20dbb2e1f2c679628f2c43ceb405f329e67bb90c4de19340d5e9888b3acfe912fdd45bdf99a54def1837d896618ee32a8eecd5e9cbf49809a22cd0d7d801543c96ec4bc5102f716f639e0afe7bcfd60c43110ee429060f27ae14577c6f0f970eb0d39440ee953fb404ef222331233c8ddaf70a65cff0786671cf02b4f124168fdde6e9050fb7c43456533df98499e5a6ed26bf523622c3bee82959d113b208513d2eb6129dabf6406788420219d90a98e1fb79a4f3718431f8937df9da3936317e3ecddb0f336eff952981a386b82407b9cc86ed82d7e5c823e79e4bc1f2c194596e3c8f31a4b24f8dfc67a77023867f33a6281a00a374b0b036f34580d1d98719f54426834764988e0a5200ef15146d9d1a890025204de984fe507711662e2b9e83b68b245e2b72a592cfb0be7632e626ce9fd2fc663102647b4612c92eba4839e5403e70357ec32ecf2ded89b09f912f021c8e657df8b9c0d7a8a891c0298b97e8640838bdd5664de0459c4ac2bb4f98b1420e120a51c83e6594ccfe6b03af064a7515ef0670d6900fd70110cafd341adf402648df4d9018d8b9b4d787d038890dd75593855c8af5c02baae0e00f7dd4b3f9a7d6fe05f733df5fa2c4ad23609e297f933949ba3f50eee039dcd4e42a227a403c58de0d7784cb907bb358c3775223228257c1ce89fc228441fcdb0cd389bd512555772bb51afd22ebd5fd248926525777aef5aa0d40055f9f978e4bc18a5fd1f62d45c89d12e25ff32a2e40597563be72604fe453b818c272f9b535dac182b7b5e955d59d530750ae06d4a210eb82b4b98633ffddac1f7790be1c175953b4fa967b61bcaa01dc4d193a6d99c70dd079b7c20cce4bff68b580c819921bee675ffb2e5b822a83b4180f5009e8683d3404f6fb6ec87ea85f896bc953f97df424129a91ec65b49aa62a771a1a6912aac1e9ab8c2ac7662526552e02bd92cf7ef6b572ee8cb4f9dd56d7f4d01bc4fcc6ca8723c15b3a7e129b3ded0aac0489114ada4f3eb08e53a7fda2dbd9c75058c593bc6dd61e6196ce3c4e4798fee00d0e40639553b972ab38b06785c5d72500468a3ec5ce36ed4740f793e7e82cf8c49ebd702fa5b4d7f12fe1121a4e13facf155cf4dd4955b9b4660f4a4b1c92e2c301a9816aaf98c074f09fde86aa9596e01891dd6f7325dd4dad7c4bbc02acf5091b68f4b61b6e2949d9a8fc20c065e79b1dfe5b4ed383090ecb6708482a8e4b36c0b09b5eda21113e6e995acb2a6213b4e963cb81b1c0b849e4d06b582984538b02ef2918f38d17bf4df892fb5c72513976b6e1d9b1f0c796b01b630ef6a2e885747367c6ef7583db36f12f2df336b04fab01899c22588eb2416c02f05212cd4dcfc0ff46b0354c0fe1177d7290c2203276589c02b78548ec509678e8b65670de116905d0f8ac00e81ad9309462984ba4eaee65287947cea09b0132f028c1ca48b10fc92ee5dfc27dee013abaf3d272bcdf245446585290947d7bd01dafca7769229bf888461ba95ccac20678322f97565de14bc12000e0fdeaca0baca0c9b1fb24576c597658645c1c70a54928dea29e7cca195520ceaad7408edff02eae", "dc37f228d28812c", "c8", .Okay}, + {.Log, "4ea4b13914425df2593d88b39f01e8fb749688fffa33c7c6ce12c5194369fa23758ee6a6b88c6ef4862437e752b1a1dc6d1a0f0e32493552089a2df4834b31bf46e2b3a22ccf0d4054daf2ee1669e6b02bb8eb22ac2d59020ef33dd207169b4f5121edf94078a76be1c05de836ec9ecff668f397e2565941d418dc57bd4f90344cb79e89466923964a8744b6490432ebe52e7c3653fe5755ee2a96a76f6962cc08d4bfdbf8ef1939a07205889bd186fac39aa2d91084ee42597b70e9fffff59dac9c373b0bc338e9f25aff97d2133c5a21211dcd4c5dc3d49623b1fd166aaba22bd8a7cdc88ed620d0865b1e0906d262eb37c27feb458980ada733f27deb2f7791ef84de44acdb7947a8f0d617f2e3083f17239cf3bac29e64f7a22183ac5250a5a019d6ee1f92a9a1c028aa6ff4a9bb5de46381000751533f666a345b7a0e67e8f563d37b8a4d90dd09f3668b94ef4bfde91349965ec472e8e525bf9203dfbde6a14204caf9132da9e6bd8d1c9dbe4285ff89c7070eeec22c2e755bdedf8586efad49b26f18124775315e61224cddc550f22815b307f13cc05c86d68053fcbedcbabeeb02eab148579e886df93ffe53e87db1b8ffdd86e9f910e5f32495195f6d72987369f346377eeebea391401492bfaf162d10e92e3de4809a22aead02fe190bd054a0c6565ee5a5e9f8cb290fbe22e69838b973a2d30e7ef7873974b285ef8880d9d03fc80b1cd60be54bd537b00ac6fa5e8058007fbb46f4ed42952141748d91084192f216824bf03a5cea8fbe5d87dac24cf8e64cb148765dfdeda41993802a58fb668827babe0981e7625c12c786db95e5dcf5fe34f53c8bd0d1881907257d1992526410e68d29c08b0b3bf1dc02f00e01dac03461ac29f65e897bc90cd6b307bd2ea6004c5821bca01e4486cbce3359d9def8eb8d0270f1b9a9487fb64aa5432950bf496ccd39e5ff2a94e7ead864f56d93087884423786479f1655138acdff4c75881c301bc015e610456f9a5456d70e4e4e5b81f4304307dcdb99a579549827fc227b5fa090bd3a7c9edfc2f41e6945fe92a7ba5b53e26f0bb7cb638c2439c2f5de6f9d3b8f3e2bbc55e922f84a9c9b00f264d0c8f1c4e2d2459cba4ee72f186d0348ac347a17a382c93accd1df064e9a76cc8b02210a589afb0788bca46a21f73df86a5545b4be87daea0a4617d20cca4ea41eee059c50c387f270cdae6b3a7989a7c414b865b4cf83ba1b37d5fa88dfcd2a234aa078262c4779ae390eacb4a4890b7699a61023d2dad88fab34ef5998f7dfd39e01a2f8fa39dbd51246d3ed6bae0252608da86764933bcde41e2dad73ad8ac6004dd725bd44870d300823e38e44561e31ca6e8fff254b1f75ecd29fbeee60336e2bfe315608e79127a1afd16a52d3fb0911de67691c7a2b746e188527a8031d4e71ca9dbe0799124a24df00717d062bef314ea5d01d3285bb691ce91bb37d11ab4e90dbeea5bf13d8f29b0387818a1627940cf8dfe1dceb19f35142d77aa14a6af8af02b5c6e61c63e499ee7d1c92e2d373cf378683f5208dbd5384e245c7be64c4694f295b4ba1599fcec69f168ecaa8f3919e807d3e94c4947e39c23f4afcc90b171ac296842160959087e4c6cb3c778ca74b062752912724a5bd33ec3f60e2f77dcb1ba9ba69c04c697e89b3b99dfbaf1da6acfd649996e21da9ab147d16852db5ff06aead89d0e099dbec6849758ef298de3cb0f7b804d37db5f4fe7683465baa1886933b15e2536ea4da945f56ecd2533f45f39d21c873d3d645802bf36f475df3d60e5b9c9583487fb9fff1e110884f3daa9173a395f2e578e7aa90efd2b3be0327786638b0486ebe61859d9291aacd2c3a2f9a387f5f85e94454dfe07cbc0ab63db5779cb09d873b432321929a1624dc5cee9e953780dab67385124c3f777dc947bd90cc6f01127c58092ee66310ef077153a47f034447714c3e6403afb701e0e9938323c3ad2140d249f8e4fca7ec1be63612cf2ee4c12da02e49a59804452676e529f9ef1de5f549589680d299f8c4486502881099ec3bf27516874451bba79b584911f805fa763de5d328fce2ef6094a8b0707e5d9dcf4563bced93f69a", "b080f1bfd6f66cd", "c9", .Okay}, + {.Log, "c42463e04cfcd0c2eab2718af58e956f78ca322c180f54a4ad2c13f5d2f853b30d8294aef38a3b7338365684c5b3906a7a279a06bc5e602bc14bc2a6f7236c76601ff182d8c217c9eb7eef047e0a3ccc08933a67612f11a7f2323d2499c27d9f057eb610413697ae8eca03f841ef7c5fae296360208f4c5b96d9df9c5c91e436fab65cf2f68ee88d6d3135a4a8671c3688cd8358baa550eb6d084b082e491f110e876ee1d867b58890d330b72f383f8fed232165acd484ba24c914d2fe9b8634fe353a84a537adf41c6df79c31feae83564ebf6f5b31d01fa01ef703bec80c530158ff9af7b4ab502fa4f1a63118e87c0cbbb3e6fd5965ff4aac68d271bd177631a5392043fd87cb7acec8098462d941d20af106e159ce7ef9bb4496115bd0f457d1a64a01ec0026c1ab5fe58190455ee446807738dcc840d1b824275cc18187dbcda98596476a52905affdba06ca586805ac5da8762cb0273203c57e21f309fbf3ca57221e32b420739c455720c40cc49baa8b216022e12fab21360e414e02a537417cb770482241247d6c06df9be4998ebf8794e433cafd34088980ce92974bb31a5b377881965edfbd65bd19f29ac0b4183ee3c7611d2c40b1edc422857574f260c20d6c0364249cfb85a49d9ba00c6cd6e54131e0422448d0bbd9405cdabe2dac40a0ffcbe4df4e54b8405bdf66ab90263b660718bde6234bec62b16a4f3d08d3420e1f45bab1a90cbc52da4b98baa9c0ba17345d0efb6cad8f4b9b5964bfe2b707eef285923b62a7cc29d58f606a9b20cb9718f7f414b2cef041bf0cbc4804d04e73d3e318811272a1f16f884f9fc77773598021c5264a24358121d9343f36e6c6031041d7c618c588f7ebf9ea241a4837081155cf6824b1dc3508af1c62d7baf73dc356f86027064415c3836b33415bc0f9eaeee40c4ae7b3f5ce58e17c7b6446af4ce254efdf10f0fb50df4248c36d882886cfc366c656cc6d2f57b5bbfa583479cc84a388b446f4c1196af42d63f5cb96ec55b3ef2f1952f0fe3520506af517dfdd1ec814ee79278de79e84e3da1497a6afe35fb9cb7bbd4578b7a41558cc75b30bfb260877ff0f3b14f6666b172da00d5920828aa028a47d1893fa1f32412f7b83d933a29ccee356ba972e6c896da0312c39229c111ec4c50fed9e63d231759501c4eade87dc63a22a309af60bf46bbc4edd33c2545891f1f6928c8da5559098e34162b6f4eee00f2350eebb148b437b3048e5c860e4cb8dbb9b6ba9cf4d743e8ad30a4a8ac9ffd2c01df8b57aec6df19693e3b5672e0b82d11c37c5d9c197cbbbe112d4523c4f443cb613544270f7158b9e1a93a7f01183f6b1741d025371b1736c6aa6fb15e7f2e1923cf3d14fa6567558b6ff29c4afb323d5f2e1768ac3a0ff1f9aaae4e2afd51db0faf337a020b0e6de928050768f2db7ac1f0224e9351e4fb7718e0c74ed8ded61dce532d6104ea353a3fb7477026f44f5cf8b3a0d9609ce4cb45b310c5d9d4020a2b3e159b0611c23fce7b6b395018535f7c5de4548c19bdeac2a6f83f7c2ca399d8835cc7dca47ba6354ec128a4dca5ad3cb0e00a943c7dce10e17f9ae32bc1f89866aaddbbe1099784103b701b81bbd8872eee2f8c0cc8c4c76a1e7d013d1b4c318642aff56e1bdb9c281c2f5e1deadbf64bd8eff3fb847546973ce461b4ec2e30c8ec09dba30d97c538db6a02d5ff16919af9a4a513e99e9ab5b646b3f2f17927b72f85406a997c464042029e0e9650c920732afe97ffe135e677dcd488e5f503cd736acf82c769a02b94b55ae465b20d5a979ee0b2cb1cd716248fc8df3a46e2c28a01e20281b5e44e1f3952983f83c6f6f510578dcc49493fb0ba059110b395d4e4fec4e479a15c829224d24acd9eea409729bdb51f9248ce09bd45669a1942b2721a1d503eb3841844696569f4265953b8827189c9a865770d64e7e7993d455e45e5c2f4cf2aa882d4f4f35b7ea4b196e0a8ef95aa175b114fcefcdc7582bb7ce9f3f8d550c7e537b2e58c9fc516bc1437516d1615d66469fb05473d57d244e196260e6d14cd70e4d14b40fc36aebce94ae866e1ee9caed22c678d344d7e81554ac7d837739f38a406656e", "4f64b8478240868", "cd", .Okay}, + {.Log, "3020dd69182c9845a20e0c43173b7a51a16b3b8b0bc08388e35857ddb419163bbc3ec5bc7ee4e47f3a16fc16e0b6f962fabbfe8ae6d8c280fd8294c7eabc38ceda50d807c23147e538b8b4a8f84908e8a0d2072842c6ecd278d4ce3e550f67c85f20bfd43def77451980b5411e63eb9405ab60331dd37a8226d412cc58fce7f7e0af7141fab921b98866420f0582817139272a6a72bfce271cd1138bb73660b4252846ee135184f2384fb3fe3ea5dd006c05a46d7ea6f3c512848b9e40321fb42864f11d3426d2bc018278e3da235a1225f0a116608d4ff06b2082ffc2372a27672abcea296247ababf2dc342e54fc6f0412d6977c4ca39e9dffea2a788d86ddb5c399228a276d8c7a27e77c9315351b9186b4858a1338e210e69d1eca920a89419ef3ec53e2c2ba27ef8323a22edc1ccb617255f5868a9c3248fb1831031641ef00cdeea78d229046a99c28cd662ec0cf3eecdddd8ec7a66d54541a780ca9b12348d57eb9c48d80ca0ba5d475a7dbc35f61dbcf32280428402aae82a00678353cb344e749d822518d00eb62750542e783079f7af0e30a36d2acd46c6644f787d9981510000ed1b951e249ed3af65cde61fa6b93109ba93c8b8e8c76c2057cd37e972892b7ed4e6d066993908496b54ae9e949c902793d5a0632b706cd4ad0a6c39998bbf330e153757c368241930d89fed6af50f3d29c7d60ec040dc4a28c526d62c8252237b7b0d4afd2cf2cf41887945941bd2908e0b591788f0deaa067efdf6f4fd6fab69ab247712a34771aefcbc8f603122888046f64450c3c19e060df1f00adb78a57bfb2cbd98ff1c072c48ecda9838aa2e3e20d31197c9829395aca96214f151d90fd728d259558e6a01489584cb1e108a583c324102e93d13a37c6de962ac0c708b0ffaa0fa8962c4640671ca8c082ca421bf5f91a2110cca9fc59c36160b803dbe510862196eade24f8e7798b189f2916801653fe2b9a1cd3ff86589ee47422837407fe23fa7ff9fdd6789f75f4200a38120eae2e9d53e74d73c532be0a86e7293922bebf262e10ffa30904276bdec262d93a5428a14d7a7253762694585cf731138c5a64c9a3abdfe53309fee0845e57ea18b8b8c11b57d8288ea9ac6f3d3a04a26d2d48999000715f7f8711f43f65f8c58e93290c7e68540100a0d063f53994e5fcd4053d0d3083b8cb2d633e7de49ef18714491e2f62da942824850d0b1b70d7b5aaf9d15db0639506594981f44a9c001c67cd99118525e88ec52e928b88bb5eee53c523ba148136b4ca930273b19c95bf59c9943ec747d249f7c8cbab4ae768ae256dc69e611a93d39da3aba12b26a6c242521377cafc5fe70cc82dbddd593c940ee5a1dcc15079a3cd709be124c135c785fffd84a573eb0fc784b2caf95a85685f8c4480a4f286ab29b54853094fc879b9334b33363c5886b41f730613bf02b860c21d3896047d69597784635d9e87b5449d3745099a059d60e31426376b4018735dd2998a8324bf45b2ee17038e0d15138ccca32de7e6727956425efae14cca177221ff14e67c43e08d7b6621e18c06df1d74048461c29dd034c287f68b506fd6c3830402c0525619842768acb4a815282feb3e32a6fa89374886a2cdb353904dd1aab0d481849804f492db5a0cb42957a76767530b6e01b4e567569578bbbc836dc2e30f1670175c2de0c8392fb4361a2c9bb042ac78843ebb22395be462ba6d8d820e050ec4268df15cc69c42a2d33b61d49d90d1ce4a58f985d49593354a3aa7bbabb5973df618017425a688e2d07d2f2d5707f7226f67893e29f233f6b2b8ff9ac6f6bf7607cfce4e1906d33a9da7ee9a57f3d7c7842b32a6b8fe83b70a0ad3c8ae002b716fc8f00aa6f3e927ef73e8a0e5a31675494e8d1b5ef127a26fd9193cbc1583942ec4b9f8f52d63aed69a89f351e189113f6492caeb1419407990b345d81119720480bf49124e16f3bd0cad570dbd54dfa6d54481db8f8673ba136ec91ad2f62bff3aeffcabda2b21402cc7d2d2c2df904941b9033c0ac46b6b1cb0930ed1f56cb879b0fbb4e394cb39e07b989999e8f89e290b7b3cbc138bd3fc8683d3d6cd5127a9cd9a9fd3d2c36f3a909f35", "891d8babd1df6a9", "cb", .Okay}, + {.Log, "209eb0c1c8f9f930feaaa4fa40d02dcb1bbbbd84d96de8e48ee1876732691ae8d62f8bebff8c90ca1bf4c15fc94488b4326bbb19a407b3b95ec89424f36da8bab99ef3b259f5dbb9890f96053f334773a64978de42b173b2c3576139f1cd50c3e0158ef73f73ca20daae211569f68cb28095c7b6a1072f9ed3930f94785cb8337e1ed30dc3425507d88084cfb8fe5d42e7c11dfd8eaa1a34076c4a4f3b2b9eb8b6dae3dd3633e86c8360cc81648729dda00699fdf615a6e520690abf5a48548ea34c6ed9227c7bb01527d3afad696f95bad1aeb02bf90202e8eb2f441278611ee3e0baf5d7ab5ac1dec33a494eb4ad4d2491a1f2252db981e385078be50a9104d79617e9cef29174d5c6ffe5f55b16f8d5cbea6c26077409369d96100e1a5f03d0104de3f7bef5483bffef06552116f388a6d4edd8d24d5eed02fd2c7759b315e718b33a49962a7d40be502e4c6770f5326166605d807f7dd87e6c05586e94bdbcc0358e21e4e437fe757f23476d9081f63df6a534d04144b6327553c8ab28d22833ad2ab2c25c779a4c5a63a2ecb0ad999e26b72924de615f73d7513ca2843e15d4efab1468c881fba7735f848361881239ec2f5104831ef4f2a9ce61c43d471256479f4c55affcdf922f8340919053e88d214c3cc01ffe06cc3515e2256d091017cf5df377ac80e129114ab7be9fc625e131b50058a8f4897f5fb5ae8a5c103d3d840c79bea8a5b94674dd4e8814f4db6c8aa4cd44b9d9e6c476d3b62d4487ad058cb392e3d44ed46d7164a398082bf18d0179d570198148adafc415897ea5f87bfe85f642af122fbafc9ced5bdf7ec8e8104943310484b44e11d5cb1f55aada80dbfff85f4a37331861a0d280ae05f79d46a45f3569dddf7221bb32b1cc3c9962d08c4ae28893db35c1b0bc967c807bf2e8a8e1765c7749182cbb7ad910914409df9b22904675083892a6485543028909c2f0633a42f15ac22ff2bbf082a442ca6a5fc069e912ff43ec28c840e7ad4609cf4c9c36449e8d2d587640c6495fca7ab1ff733b098c6360e6235f78b5ab39017b362adfb2c564baa3817931fd78309a3684148638a7c6c1b85a1d6269b19500e665c211239641020161d3a773ebbafcec442069e4ac56fd8a5d6ff7e5b077112bb91f8fbd0128204c5146136570537f62ea35227d28a9ef04ca6262f209c81de2509202076f399bf9a3e2e7032481fb592bcdb5ea53897dc5348be5438f798ae6f03ab67c437adaeba819543eb52c13152b922a03e5c6a8e6e1edf929f762021a2085e888e827a978c17ce388f90f26ee4c574ff3426b6519ee58c5ae727f6dae1e41c51041a132683a7ec1fcec36e27d4ace7bec39c07a16b6284d638bfbbf7f8143e20b523ae81a3521e072710c93319787f92c624f6977ba86dc3fccfd41864145f74dda5548bae740a0cfa1fff50fcc4f569a0ad69a2fa00700e50e5049a2a2d0689ad0b128d11348df7021980a60fe31ab03b264d750d3275c2094161865f4e65a1583220d6c40668ca0fa99cff210af81f9d0d21df11351fb95ab52b2d6b4355d0f661d30cc525dfc39e49a8d1d5f70613053b1ec83b65e464195d82d40251815d236e1bdbf3f7fdc668e9333e34b7d3be79681e27727d85505a15e80a8d3bdf99fedc77c088957e1ab23930290a6a296493b1a5fc4cdfa61f0747a18dfc86c5b8a1f62a9e448350d7020050f8044e3ab72968d388296951102e097acb66c8eed4a2404e7f13d28d95d159eb9e2fa9797386131154e5bcc62d431e9341a409b57f5346663475e1cbe41da8d8c696361be0a66f8e31c60d530bda6d0afd1633a9d4c36276c72a32cd263d479624845882a488dff426a73276a819ec8da54d9c51a6f176d142020139ad76a10b4c832d07045030eeb7cf9966455cab246c5cd696c5647bbe70d8f2af414f219891e14706a0a86477f37f99f93165690e11cea34e4695f69847095da6bccb1fd7576f3ad6b95ea4c517c982f7085a581aedaf8ac508db1a3598dd84bee64742c55483809a24ac8c9174492bfea7da1765631079310744d128af9b54a430aec3eeebc03a97ee0db267fd76ff13c57256af1cc9bea6435235e6b7c27", "6e143a69748fd4d", "cc", .Okay}, + {.Log, "698891b1331233a9e4e27239d2119447f788d7c808dfd9329f53ee3b2d753b3533ee5c06f2bd68f15311d559316aec077e2cea0ccea333896dd07c434ef52ba3cfc6ce55499720aee31d7ccd14592378f095a14d935acc95fcbce153ba38adc4f4177e1d666502a6371d40f020451a77ecbbe3444e44b7a82e8a024ecac087a0d1d76d7d109d193ef5a45ada2b1be73695a73ba044de4387e1a4c9ed82cc8dfa10dca6c761385e58b952cf2200ecf8ccfa3f50d169acf406f1d2c20ba5bd2ee1090bf952b19db6c043662e9c8f8f5484cec31f87c16cd29b00df2bb4f713ec391bb1202b3d3496ea2705804a4bcecef237e7324efad5bf24cc61745d44b31a889c28ce82e05a868dca7619d8e34c3c11b1ef56afdd1489f6e320bb4f9ca84f75637c39762e3406e1e99c34da3573e0aee75d5fb3e73ae0a15031033e93a047a1d0c15b65c02f892a03e65b13b7b3f8fe14d5afde99156e9a3fae9a4a9f7037681278586917280daff132acc48fba5253b0b84c69db10d9669ceb4ff1aae4ebddc25ffcbb46f47462e5d1d9b1aae6db55eb6fc63e13fe1c29a849a906527924dd54ee344078b7d852a68b650714faa16f1ab5acaa825ada152e7712abd1d160e8b604fd68aca49fef8730c2fda72c8924a9ff54e8dc157dd40500aa9ed6386906a93c72548ea05b2b5e8c6cd1aa2d795eaf9612bec1622e756394419069310292806bfa0db4ec399863f91878cd4bb8d496d9d40cef7bf2278ee4b71007407ad5d62740a7d26e0d70313922fbe742afe3309f7926fce8c852260af4c470460fa8ede32a3d9f07ae55e79aeb1acaece9b0c06c9d8c375ca8ece3cfdb0bc417257b036386b7cc5be6797741fd4e8de04a8314130905cd996b4d58021e5872adbeb40fefb536bb17f2946186dd10d0501e021f8cf5c093e933410544d6b12b565fd5054f98dd0b5d5e0b3e09c06b808ecb1e25653fd0da869ec9e5d7f9613e01145b930f91090e6bb69163451727f1ef95511a0a6a9277e6e20b23b796f8e926d4ef14f03849ca5edce00b78fc4b0a684ccbadaae0e13bbba96cc81fe77dc9deb58215ca8e2d477c60605a785f1877ae283fb038c4c252d5bf81f45e65c1b0e80744e7a3d6587d353957f8c12676dd7bc1df4431bb2d6cc63b96556c96d5580d4cde0b8d0a2c0b0668d3ecc1646606613e42dd5980757a98fee38aa750949157ca80fb730f7f43a3092a306db3c3283ad1b6b8af9f3157dc27937112cfa04bc96e254431310ae37676dc12de27aa38611841af169abf45ecff0dfddf6c103bbfd447700ab4b603ec74eb5023df1f9560d8d9947942b556b4e10a59edd94f403d46f0eadbcdadc003880b57d01730669e04c90e726d88438be175407d00dbf94f13e39c699064cc44a1f5df739390bfe1eb31613343af28a015ac3319772c3beb7a576a6f15ae231d58a8c33c7cc09e31f317725c152334a2885caad1126f75b47ef020632ed66fb60f5a957da051a90e5ed5eab9c71834157dddb85a7dc7240c8a04f99ee52fda81bfbd342d73229d4f3d1cef531e0ea1d721af80201ab166c9ec69660536dd189ad15d4360d660e321d08c4d8020b1d1be3963d500b1ed863ab1bccab0e95c70b2147935d420e3cb244cbe51a2beeff955e8b77bc671685c6ecf1c4e9c5304bff326201ac68fdab855c6c6e7938e9dce2c90f247712b5847fa0b8525b283eb538230fc1e5b1b000efa4c7cfde257c46f42d55196b90bfad22b5a6c7e17cb671007dae03eaac750b3b959225d1fd60d38bd9cf07264ec8e8b8ad65c565e56f5e169335f738894b56ca2753c5fbdc28ad2ce6a5e186dc8865404d9c08bb7a6ad5b332c19cfdf8c803e8964cfd03edcf03411ba4d5e9e9dfe733469a28b0672d14ec5752e744b5f6f67e88e1b4079d2896d753959388f925b7a5dc3a28df44939865514c1d145b20c0be40b3852641afcdced54c4d2cc02e445a811e757080b2b8cd80e2447df194d4241b77356b5ef0a9bcccfe48d338bc5c572fde5e54ed6c760dcff7982eba460c9f6b19ee3a70fc4f6509457705978fecb02fe258dbb9b7a7e8eb40094fc3b02972fb96882a3fcf2dc9798dddfbcf7a1", "c88b153804c3a62", "c9", .Okay}, + {.Log, "3982c0b05f6d0d45df788f06542b8ac934ed4ceb3eabdbceb4e175103da41be627179b9260e4a20d5db860661f6bb9264a20d869d676daf5751447cacf97f47128542b192f605e90a3b3f387410ef7903f54136cd7f803313379fca4d021ccb1ca9029c382b01a9c7ce1d0e2384556e15170d6f356352f40fc64cbf0e05a8a41acaeab3031d8e294d961c6bd90b9d1f97d2df7a2c047294a33e172d553b05927bc88b6e2776bad8bdfa81041a6a66c11f0d666c1e57818ac25161bbf562d6bd6dead9d3b54ea728803ced5dcafedc8c2a4bd100874fc3979dd987d043e2763fa790ace03e429e23ef8e87ea36bf51cb308e0f03b844e38c1a767c9a046d4b2a9b2caa12cfaafbbbe96069f16448fadd374f51a85f4a9c92cdc19e98fa9fb2cf913c62c32ed526b9aee1012861270330b0f6c26f70898a7955c5023c94fc892fe7dc1ff1184e3ed4ddf122485aef37e961db43c5eacedb407ab60672af6e0d7835cc94aac579b9d07e5f81687ada7323f184af855e01a36c213d538db44f9c53e030cc27fee59b20203c69dcc0a4472a22595b92d79f4f63501fff7320ec52b6db78601543fc984d895f99d703c66da38aa11f310d44a995e6f0287fa289eaef9794dd1ea765711bb9632bda7e76763fe1e212c5461c17d081a138ff6a8367c95a7b8da07f66b91861c630d54f0236660b578eaa8a116b253cc7faa6ecb787ff80595cf3e242301f9d0ed8d3d96eac09c5c8dbce65a90b5e8059bbb1cceef1554613a30277ee6ca00091149ad496c710fbc16aab2744aa80d04fa452c34a29b8c715c9866376c6bda16b0900f8036be0807ab9d59a82a825a7ade1a6867e296d0c52f7659a4685c2eeebccfde34c632ac104a4d9f9213ee401883d16fca29418bf7d78c203fb45342b95c6d533a6ff24fecf7e9098249765718c6ee5baf7a8033bb732737f9306516a28c9ed90ce5c34406ee06061bb0039c36ec6293097f261f594c751f1c9b3a407819098027e4df5f21ca1f3c178aace66917ca55645da4467e9ac525e15b32d5bf7f5c5b6f7520d5e958f67e897572ef222c093a2358c63fabb7024284ebae765561a3e4e6cedb26798a7757c12033152928065e007ae2167324a295f3f9a9d6485d3c14330ee76ba4c4ce50020bba8aa30303716416bb2ff6f3d701c333c827fb917647b03ea1dabac68135e0fd1b8675b7c0b9c678821af19d768a072ce3f77f370038eed69575dc5220e271af3522bf6fc659bb6f3c1e18c0e4f3842d6964349e5aeffb232e04e82517fc20832f0f50c888434629b35a2c70fd28bf7ec1b58feaac00a07da6efc16153baaac3423ba34b9fcea00cb118992e23b225ec72acbcbf5e99efbe4b7317cf32bb07773e812340cfa8bfe206a8045662ddc82e03eac17f9b87ae863ec3d9ba5b662bebe15a21a537e6ef1d2cde3fb29924b6960508b5d6ef69bf71bcb84d010accc25c272b9fcf891a1f2b58aa532f9a8ecf9d0e7b4e30063cf3d6661f43b4dc8b7c86f917d4dade9c10d20cf12e353ad5f8386fcfb482d5896b1df146c771493e60de8747aefd1ee56eca3026d75d3a81de1ef9e1949c8ed61ef7cbc432792eed1a5c5450fe09fd8819d44611784fcb3bdb670195ef09b9a16240251e44cdfbc98bed3ba3ac30067ad9425ba67d999718bdbb0ca1b419a8c92f5424693b2a8e8270cc14fbfab511648fa3f49ca34790825f2cee173386cf88b2ee71b6392e500f2579a17f1c0c6d1fe04c50d19b2c4903dac956fa8ba113a10d1a0a9b0947b2fc17470f3224e4f4a3eb88fddf2b78e6ef295889ca1c5c6fa9132b3973695c664ad064e0846b04a47c8f5f0e0fcc4012983b159e4d759be0a5c5c495cbc22a6db85a49bf6599a9e9d28ced4c6782c7b45a998394d6cb2362c1a02884515cae2d79b80d7f783fcff37a0cf2fe9b5a10c8ac80535802a9a6b8f5c74af9e4434bde3a6988f73e253f062338721188bff96cd78c2f1ebe49576a3a5edf43827a1ea3f2b2e355c615b8824673b30c77bbbdd56dbe992d236a6cc75e3c8e77bf4d44a26a56ef4d0a52fc482743600243cf52c0691adfac65c2384065c00f5e9a370123b1c5426d07a38c6f37", "548da721fb36886", "cd", .Okay}, + {.Log, "fe612ca1b417995af599794ba06a24ca35a9fed364bed02f4c84e027b11d6dec070ed437bbc8996c9b475e84ad38babc21863923574185a6ba59d20f79604382be24b1132e4cada97832dd3b87a783321ee0fabcd26c3db9f8dd480336b3cafc6875e030eb1f103f7eb25f3b79dd78e27f5d3c0ef42cc0ba62864281cb4410e1f0f28e537a437c482c51e1f934e787f7fdc871a348dbd66e697b77869e82a606a4fc699c9a277099fcaf1aeb1142487fc7d780e53d469f31ae790de74983d950568e2c07ab0b78c8cb53e39b4f1b951c53ef693abdb00348de8c68e1da2c8e5017a6d496b129bcd8f0706fa3870687cbb54bbd2063e226224091f8d886dc39bda6e51af7eafbf67d4f31164949945dc84787c1c13d7c1ae9e39d95459a7691ea1661b02c129af88e938436816354337e874534591f178f8109e358b8fde952fe450e134c6691cb65a9be6c395ef4274242bac079cc45b3249b14aca75c97baa35f15f475388d1d7e9eb7e0223ab236dc3a07772da6d85b851f2b5856f5a38868b8acb48175948f9fb7e0a1e7e9bb65cace956d749cc938296c4ef323efd6d0eed8dd34c2bbed108adc6f4b33f769de7656003575a44b27b1cb920eed2836bf8232e11c2d69c3af0e8692f884ba994b05d38137c0d67bb7bea8f20e475808739cae9cb21b40e670313a8e6bfe3c5cd4bf2e0e33b58482f8f098d84c2f96ca7f794e9dff82a652f990334f3995200a0a40d3cda65adef20f79dfb127966edbdea7e61875e279a4c5b8d69c9f9c0d456d3e97a5bb03e3668d97b82bd00ec625e11f3e3340f46be19b69b6fafdfba69625ebc1a38ee287c9163d4491d58cf36cf7aceae2608b2b84139c1faf9033bbee4ce7f8f289811540f7fd37f0085665ce38747b0d5a67c4fbf894eaf8866dc360ed7c41c33eebafe3047a7ef89f4e63b18a828f6fe50e5971e591d4b8846fa3520197d030ced5c22fd8bdab9cdaa3f465214cb55b0215b2406d579e1f5b52703da4a68b3ca0309d88a9a8a9a46c0d28889f7b448cb3dc24cac085a0a3513cc97ed0cef3695695360a93f9c7d523d78f87c7473a4351b9f54c3574fec96aeb261534e1df3ab8e5f88147fefa8b792a9682c5d34f26f6de2d4f58dcb8cd5ab331c006d2a342b737834b2c1c97112e29eb2e4406c86464ecdce698bc257171d865c315cdb5c1b3f210e83956204cae17455e3814b6542cda9ec201f311c4b1445ba401a83a89f596a6c20e66ea93df4040a03ba1ccf3de3f1f29e9e2abfd99aaeb4fe032e2e7b6d018c35ed53a9d3f3a8d9527ccd38cb3ee75358d53ba675dc618e3e2b2034451ada97bfb42cc585d6e1c7d62b9ee95014c17a0dcecf94d7a9c8cd1d2754b3f5d988f8808a7b22b518e28de0ac942ae5e69531c572159d8dcb3129587172f2a4f87aaebf2a9b931a57ce94a973551e078496a327bedfc1bc71892bf3ccf3d019e0c7b82124cdd5d9bca5fd666337de9197c76278435a8d4b2170b74d471aaf5a2a916cdbc44650831adfc187028e9c5fd9009351c16a588a29c4a366d1e9823b30fc1113abdf230ce0d5dba64c86eab8fd5c458a22924fb609a4bb8b3a9e4cec0a48f597d918276deabe1cb220166bb6f66ca546acd964a7151bbd404fe2344593b85d75c66d94fd261f5b5dc4cd90c397d794a8fcccdae08eb0f99e76bf4614e80a56aebc9287a757807142ddffbb70ffd2c71cad917fe4839b3324151f5097edf89a25d649401a4e147b377a1c50eafd53e6e3c55147055c826e14033c9001f85394308ef54f9e97563b61e9d394723445712623ce30a74e65b985c5992654cb45d7703f23adb37df87ebc2eb3ee84d5991abf79079a57fcfd9aca0179baf02cf68f3f3e4442cd90397092a2d3e818fb95a3774db7b850a55882f7cc78d9cd2d0883ef99fc61bb441eda4a27eec0e9d3d82ae6fd050f451eaa7d56fb7c20b4623ed7786dd26b624b17c726078784bd282d4490e1c713dbff90e95e931c636ea646659ccca4d099c8eee8d5fc19915d5b6abbcf30580908f31d8b9d31c8f46d9d7473d6982400a51f5df891f556970e986a0ba3d64047a8a67b169512175ce0d5cdfc4216c65f78c8a", "45f338d7354d3fe", "ce", .Okay}, + {.Log, "2d4c4ec9669a0d695d1a6e75cf14bea8867d3c6ef7c6c45f636757d9bf0ec27433764afb7868c2ab2d07a31ebca75a482c14a1b0f5d43055fdee81167e35ad5764de7446003323875d5e06309d35df73eb5ae1ee3ab90c4b650e2a29942852b25cdf96d100dc0fcd2fb25dd7e070d7a1f88d7b18ac6df99d615717988b350ad3b220206b7bb03f86509aab0be16f28b83dbcc399f087440f0967819396238810375be454c6be3efb64fdc902d5fef4b8d1fb6f9886b73be03c93b846c46b2bbc95756f05de7effd31158517c414288110a5cd21536bf350b88f2207efb99fff37560497e6f2b80583bfc81475d6284430bea807ba218dbfe385ce7c3e1c4ca66087070133a91d7eefeb43919609b47d702615581fe9008cb4609b5b2feb1976b7190d29570a3976c3ef8fafe88484e6dea8c08e1e606e066e7d7a168a22020974b2986131e069bdf83529f84a40890b6b778db112583d6d1655523d2f3895f328061bd551152d1d7944e213f98cac291ddecf0879212a9c25bce429f06166c18bbfe6a6dd9e9f97f1553bb5293d66fbdd607385984ee912f9dbf811c4123580eba249765a1f7064f18f732d47ec4bf51c6336a588397658a4edf547a7eee9e2c8bbd7796e487ee72daa0a6a1abbbc37d0ad93334af3dafc3ed1df90fe319689ab226e6b1c88d8e6873d27263c3bfdb2085eaed9a64559c1bb3993619aa712386258ef23478311841c701dfe0ec1884fe354daaaac04ecf29b4a44f1c77e80fff783010bc0458989f6f5d98d2ace29d7206da98dc63715f3d9b8a8e45c4a2554f6ef5ec9d891a52705f9e4d778ef9f6c169e283558dfe7332f046468e700104d7be22e67dc27595392eeffe5f149a4811acce0889d0e90061d3fd793abffdb3292ddafa179aa4cbab964a5b82c55aed3a52396e3758a503ea248546ae9b14d2ec120c5ca2eb1b7ce99e14907e11de39e2996e32324f80b8622fb70ec5d5c0f6a2d1c05145ddc9b0e171b7501a931c908e778aa4cefa99d52fc2a8cc5ed94bcb59c52faa88270f84152530b1cf428c4afe04c755d6b039d1d076b8abdf1cb1ad8de47fece6e3f40c016731fca3110c2c9ae42ec07646a5931009ad53977136778e9728cdf71a6a9681fd4b679a2d46cd8b70f263e5d5fb11a633419c4443667978c45214419d094d0745b81e4132d765887876a40c6a1c3d960adac769c9eed5b77b62135fa4bfb034bd78e4e2b5ff858ad5bd1148b05cc34f67ce3a57f57d8d42a53322dc33f6f2f262cfe179bcf6e4034028de1c5e5ce7863da5fae1722c37ae315a56a8fd87eea0e4398807c81c36fd5caae00a8db2b1a6382aae58294e6813bc61fc68e275016691fe9394fbbebadb46e286c2471a293e23024e95345402716a532c5fd90a514b3f8bbaa6c9fd8694a6f2b476259bae9614c380aacf24468d8e9ab50e4cc8d9f50ec4a541b44b653841e801cac63e43a846f0fd50f63f1a1df0e431ba23bc7b2b98f3dee76d09d25f788ca7c72bbe805951a27c1311db2d83ce74282c2164b8d5d4b4f75e44e744769207f8feb411b5c4ae0ee397583e21bf008768206fd916899a1b10c9f08dd62e4ce31e61461c0dc5c253ec38f9489513ac8ea9f8e01d336f540320ae98523a4432bbb08d996e7697d5fe960285af9ec0800ce2935e49bce54fc17034f0336a29806f3d605e59ec95dd802c1cc464e2f16f9b1e12a8e3c5a7443aa7863aef53a562ecc96e84378236ea5dcae0d653943aa6c4d7d29bef7bcd8e93ef2cfad0ab6f9f233dab98a1b35cd2893d5274f76ffc2f2071ea8af1d88aa1f7daf4f63cb5764569cf461be1e2bd7b3a57b9a46f82b711d8a5a24644b370fa760be93bf99a5eadcf102c7201778e32d5dd9269a146e4b0a8d63eb18c37add2706f3285e69b0b9eedc4722d77764eff3504d137be24e24f5e41de400f773582076ac82ec45936c245916bc6109a11694d6a9b1d33edbb165c0b0118b894fba489b98d5d219884af8638b3b625f35de1c0b4a7f8ca8e7a048ead5e162ce64f51ff66939ff0a562db661cd15844acd9c2b749481a1ff8070a70f2b665fa141d078a04e6934fd31d48d95268fe0fc90e1910339f", "c00d084bfead5db", "c9", .Okay}, + {.Log, "104e36e65160b07eb51943316fe4b5f6b49799c0108300dbc0e5a04409c63cd5063a13324281b156710eea65b086e7a1b334ed022668d6ea77ac6e25f9ce3ef8f29178563ba0c3d4afcd38931d410f3dd631b176de5ca4e6186d29edc4edb779957316f4e09e2e1fdddbd18568c66554cd0bfe39d092e2e3b6e97b9b3f1e6733862334ce9823d3f904377d757ca2ecb0d0a8b9d478b3c250f1bd8df4b389abfa26c1e5032d6093bb338a9096ae77aa7c018781e5e3b3b368eb7370ac6556fcfa82de94c9d9acf3356d537956d92913cfa8b14d1fbc2baa08e560779308bb3c906095c26408de2a745275e3069a2bd0752e4a91ba6466f37609b30d914b8975cf9804a6db6a7811cb839beb3421da5cdd23b6916626de34e79e39b1563ffa42a6c109c5e766dd600657652a0c39abd67a2981117c3b6714fdde779f337231f964bd82dc0e13538101522140b7fbc2109d90a1c20a1d46bf38603f9eebb682ee358daa581874765a48d22b2df39378eaddd68a490e612d933455a75b86da5fef51ddf93feaaaaf2ee3fbb01bd03d5098acfc03a7a1c378923412db21016313bfecec34d04b26acb939978bf83d2a5077804d6d649dfcf2f1a53b9a948e24b5c4636d73aaa5b37cd79636635d6792e9eeda1216651c7db344637fae14dcdae3f7b2e4066d3ba5601dafe001d76743adf9df89aa96c6ff1620d947550341be8b893025fbab08dec8d1f58e1948df50eadd85f9719d00ed46deed5ec87bd6b309382ae1def20872cc026a1294859c06e1c5fe897e393bf282c09001c1803489d8a180a85cc1d936169e0c123a3bc36604fbe7f8dc171d2eec95520083297bf289ee4459a5419b1c24b14aa45e457db2fb58a858c20dce5d246ce250d13ad432a8aa4e623af7e3c0802b961bca9756f5ea399e65efe7c43344ed0b53e12565dc45fa59fbea4147b6415097516ef23243371e15226b01355f24cf9ad46c97f2b868f9fb395650e4968b462e455b0e078b8cc1605384d49b6914446aaf1b71288f690e348bdf67e3a84527533f254593b88788282889755f758f440af5bfcb2efb06656ebfb0828fc0d376ee5e598bd3341bab06168c418b0d890e05e392b2e370ea696fcb3d762888257127285fc420aa334a86bda406a4517fc510db1b0359a1d42431a54726984a38847b78891df587ab40351d8900f32e4277754aabe8c330849ce4cc4a533ccef67fab0b84628518c981f0301a4d50052515e1d389e4987e1e0e1662be38b1df169e00fd9a7a3540d3729401bfcf98e9c7d962d82f465fb9efc571001f113da4098b22ae096129468d9e6bbce9f551dc3431197ad7991ab448c5b794428ddff7b3cfdceb353476daa872eb8d5644734178ef48a5f3d4d3ef889334b7c3f4f8819eaf266e84373ab5341183dd16618057a41eeb1c3f6b12ea87ae6ece02125e09fb8ad5a716bdf6148c3a3fb53f1279e474d2b552a287173b28a1dd06da88b11c1e28f8f79124b01fba56baf7c26fc8b7834a0e60d4892d10b4512d4ed4851fe6c8d77e7830a38667226c978e2c637ce47fd36e39a5757cb3ce9f4d6b6dc1fb6449e158168132dfcee5018868616f216c5548da6974ea6948debedfac25991412ef621f5e4f77fd193600457cbb2212804335c63b1af31ed657f468a4538d0194719ffa5f5c4e690dbfdb06e09cb4dcd7d6bd77db4971671d89c236cc40275d81c921c73adc5def0452a5a70df27d9bed65f973f35f58692a3bfb8fe1d5b480e69309d38564b4c0523d7cca75ba555d58c95ec8d86b853daf8730c5f7e6c88361a9ed4b1aabaa9d5beb664e42a81bd7f50823957b648e34a9153d45025e6c13a9e7c8c0348d4b0344caff9c9ab80fc0811d546dfbe982d4d867ccaf123cf954e7c4190f25adf76c1c1f1a543f25175a77fd09928dbf0c52f63ff1ff348820bdbb0c01d91c8e97deeb841cbac9a726cb33800e19eead44241beb2b8454452318db21c2c02d8085bbf4b15264c1b5fb867f0308243929bf3d338d008783d6134a07525b075759f4961f4da744499c95e229be4243fa2c43ef3dd17c086ef60eb8acf0164d11b4592783fa5828282cd4e9210086c753870c0d", "1d8220b3251d963", "d2", .Okay}, + {.Sqrt, "61c8aefecef066eae4155a6915c3a232762b9d45b307a9d4f2355bce419df3622be96529d0dd42cff6bd16e8409938abe7e25417a9e15fa6e9ce3ab4f0f7ed62a7acb2e427887336264c0fa02f0f77e773a3f7f7a291ed7461fba53732689c452e4bcd605ceba705f6f86f13f9e8783fe4046e009a60f16b9b47a269ba2f7d5c6f567ef4fbe2f6ddcccc86ceb93e2b4f7c2c30739c651e87e8f62812902669de631618d17b0c1ddf0602174150acaa5f94fea2b6191d96e9c40797a79844a79ab2628f6c185a58beb08198267ea1ea9dd43c309de578834b45f33ff040f241ed981baca278141ef356b60f2500b09511d92312e7c785fa0d3c1ac5c97724fcdcee29ec2469bb7fda27cec8df2f84eff049a6d6f79edbe710dbed267260d22543ae3987f697051fe6db440e48daf558413c96747140cb97794f9a186226dbbe44df2c7c67aae6b2acc9bd8cfddebb458f49c759bb6854ecdd4a16fda5e325603e87e886cf6866dd65bb61d2a7d6b8690d426d55918d855458931e043c0b533b29d93903f5335660ce2f521d4e6df489c995028582ad1529df994c3d84853fcf202da5c85cd1eaa21a9dd3ec437b35dc221acee51858d52d7c4e2920294b9e1c096b0a6c2835757b04c6a336de213cf3f3e8bf12ab66044924fb4fa99644893741a9f70a2146c60b341eae8fa8c1df68932477792d0b0fc45bec9831304d52693ab41012b511ef29c75995d74d7b6230fb13ab17cd932c079e976856abcd795c5dfbe677f4b27d09b01c78586d10a198f2584a503d9390e8092f97ce410f28ebbdac73dc0a43e108c0d08da303a316da6387b6c3ccb9c6ecda8c868fb30086985cd5f4e4916c1bfe15fc73835b79711ed114a2adff449f2a83c9956347ead77311831929836221088663d051f93b43eb95bc38f661c277372934f927266e450217836d0cf4066a501ccdf94cf1e4b3af61628b1c4eeda8bc7a87327bce0bf034a93e4392b1f36d3269d588fcc9a6ac9a846a2cf6adce2f2cf2ee878735ffc1b166f68c306eb3671d60a17dc8c2b1cee8b3820e41d490273f5f366fa0a3d35f729a76a466bcc1ce0759e91358cc2b8cfbdaf370f70065d27ba90ab9f761061a7e3a8b77b979ca71ee976f50eabc7115ac9124785b8cb75f0c64c06616f68f0744988434c34b509c02fbd056b72c540fe193439b05cb619ebe9ee3a2b9253b9658f99e63c34d900452b0e490df64b12409424851f548336d814652c3d1be2decaab59173034c8fdc19f9ae690e65fa37cf05d1eebb106f453c5be60b9b68aeb1e84cfc66ca57a31a37d2b8d84cd666167ad07d7664a684acd55cbd04da69f808d95f07af77bc854e6ec869046288bd53891f2b760c9007ee4d6df2b642b855cfb02ee148a0aa68d548d2ff88b2f33b0ae925743e0ba8a6cc0317c2c6a0aa28ab1e9aef75bf82197abbf98983157258383fdde7093ceb59cae2735aacc38a49de87456695152480f6bf954181a13455a0b1c35f6afc69aa204a3a2cd540b7ec4067c3f6cf4816dbc537f8858502504bf1c368e305959d7708e7f8bff2e8991c91e5ee8804bca332f6797a20cf2bf0b0629aefa7b15d09309773ea2c0ff28ccd7f54d7e470cfa285d9eb2798b003f291164a84f408b40ea33522ff56a8e8fa3e9ee011dc75a2a034ad7de2fb02c3c7b94a121e2015eac577cefcfbb8b96598c5f2e7d0c91e96a27150039b4fce8a05575ae73ffed6f7d9f2f37c8d3cd6a5bd570bbda339bd7be75c1f1d36f4080278720627dc297cc50a0b6f20bef23ac8e25c02a6ce4d25038728536112142240156f9964fb8c7a8aaae32c7a17bf8225aadd610c90e4d099c6ab2cb9d6ae88e59ee399cf49b8c3d6f12bdc8b12025be0098845988b92862569a9b951a90e0e2ae1a36a63a4358592230fd3c2f589b2a6eaf4d7f1bbab74edd518762aa3d48197711e678c0ab5428744d70f7fe3a6a3cb641324d054260c2068ab4a6c791121962d2aabd8c6f4533d7b0568862fa5fa4ad9555508ff01d84c69aa479fc085b19a983053b1b5233c592308da1b89105dd31e743910ca1adfbe91164c207eccf169f46e776dd0c776d6d691f30b84213efaa9", "0", "9e379aaaec98d4a27bc904e12f47ea848083ecd746e1833f04f35ab1a4a297573442b273e7c28a93223268d5574575a87a226b99c4d92a9b1c784be3225e7a369c4329cf3b2388e10384da0eea8ccfaf5bdee86039afef18c20aa3480d94de34614272742ee3772dca1fdd3774d2fe2df9bae5556952373b9a8660ed4f1449aade8c7d620c00f2659d4fb7578d2cd9e9d611d1cbbe0c0e7e570623b891d3e19c03fdceb88813e2da518a1b56e0f93db13b5ed7dac552d8ec3d22c9397d8678b983736daebb5551a39807de107709158d0a136bd7169a4e31d396cdc8cb218f67019c5a6f2ccd09351c09b3d513b74b276b48c55d5759d261297a9720008b706d69f8f552eedbd466a75146840b9d43415839fbe58c5161b27bb8720915864fe32b9c9222781c29f07d1a1d1b1cf7add4f260fca5f090f655bb025e5b38f109f063a68365b6304184014a693b2a917cfd5a74bc4ee66f8bb39d8a920a509cb3880a01ea8545ae333f6b56ed5c75c2c06948ba79b7624010bf62a39cd4c8a6d42b943fe9ed4abfe01538f87ac6642dc583e5ba9e4f6ccc968c56cc33599e935e8fd4f5999cd4cf5c58a2f983303d53bffd6093bec0ffed753dc9019442efc83a0a252a4b72327651be2a19b2cba4e778c808cdb55e73693924761881aeb85917f1da6fe2f4c88e94cb9105a6c3f91ca5eb9ef08ee8696a0dca71148fb01ab05123227adbd961c03bc43b806521bd0e1b37f2865eb2d60e7d8a2958028e2bea78d7e6b778499e7cb6e429cf7e06b975135c01a1e87b51213e45ebbcc043ae1799aaa4b806cac04b833a8810b75587472bea0919846fdc3e09e20c2b3eb72bac5c52734339d855b30adf20ebf8a469b730261f8075f03a8defc80d73397d823946573443dd0e28c88509321fd40c1e65f2b7cf1274c3140565e762bd0bb9b71fa5db75be8f5dcf316215e526af79f9c419db5582b9e54350c9f7a5467a80782f54a90043ac0b4b656ce818f50761315b397044418f28c90dafe0a2dc793c323915b653668f6dcc2858e70a3fa687dfa2", .Okay}, + {.Sqrt, "a51a4385776a5526da514991a743792cefa715fb8db7b2a00206e2703055a05d1bd2651a5bdc5687ac3706fd6b367b6822f9592cb53ad920d95958cc89839f739da58dd2b265cd72c336269cc7dba1ef0490755af1c821e1730ffed199e392248c346e9b6dc73dd69fcebcf5a592efa61c7189b0422a8c1512980d8ed10f80035bb795271d59df7bb000c8acadf73d2d221a882bbeb8b650c8f995d063853217776ff90d746d2e6d1b11e0fa41e37f6ddd0fa3b5add296591628e33429c3824397a5d3c74ed9f73874edb93008714775c9554c3f3b9a8dbfcb38137c8e266ec32a288c37641f2439ecfabc5c7a4ff48055c3abaf55c929a19345670951b81dcfd72f45cb076ba64407c23c67161f3470c0765ac8320487dced99cc8848f73d490b84cd14b593b406c2ba93b05d4a6327ae949b40984026293f1fe1a28d223ed149c0312b5ddcd58138b7dffe612feac8728cbcd9081eda4c859ff4e55a822124fe0226b186b0463eee6022d67b54ef0ab971883b10a6038e2e555e44478ef9fcf73ea6329b1f71eee6281c4751b62c2625cbef4eb2c624c0f8ff309c68ff625bfa97c32176762ba75ec2a09c084140ab04bf372222c01407cd9104bf2e414f0a3b8ff831733b6d5405d949feae0d4838f4833916f62080430660ab577ea4fef59ab3161d89ec0c2b12d593fbd68b9bf1ab19ed9af330c57255c2c7183b6ac9295e5fecd75009f2191effdd285d8fb2b916317f1a0af023f30f6fa30c08da23514fbb54336805710116c8ed75128633acc78ba0e87a56b1a9805e9caa70e7650bc5dfeeb16ac097fcfd2a4f3bd0f27d48ff3c982c0b5ae62f69e00ee57dcf1e8ddbc3cb2049eaf1dee351a73dd3c753ce50f7e046e411677a3606c7a1bdb4d00e524a414b7d88ee02bb6907e5ec1dc356816d7d557f927ebcce39e828683304a4d11deada6fcb9f9fc3085d6d8d7c22d9caea2be9e404e2743c6de903734ac3775064fa73ecc11e3befc5a72fd4cc3fea56b22eac6b9e4037d4cc00144b18b48ac5bdbb8ede654ebff19238ccab558cdc3706cfc4f949c3721259034e98a8317b1a3365450bcfaadd9afa96bcbd4fa3f1ea42685833a98037a9d578482313d5d8cf3ccac1558a2f10388d1babcea48cee7f060e5d330a81f0b320f633c8557a0226e551abb1d1ad9caacedf40ab8622cbecedcfc2aadb6ad3d9a6fd15216ec26d40be8870548e7a2c4662e9a4e951325e4765ab701d4a7ac4b0b3fbbdba104a5eb2400db664e1884eb8b3084d8a4d8fbee8c979ebd60bd985d6fffa6bc339c3b8337d9313dceefbeb9befd6f0aacbf84ddf97782ea7edc28fd47b9e01b2d3364accbc7c62bb3a880c4b204316333e3165633b34ef5307fe65c0eb83ea252b2b944209b070c3e2e8cf7c96f813692acdbdbe246db53d0f1d879da2d0e8a4e06795d28e465abed0adfdb3042b3c58a7bb483435db974c66687f0089e7be34fa42f4d1d340ce5cb91becd3bc7364702c74df159f94bc8699041a5d77d482473f758adeb23cb109cd09131edc8c17da11b7f04ef0a998443ef039e35e7b29f3d8bc7e901eca11fef26a229ca2be6fecbf3dd56b3506c52b3ed3c4f615e24787bdb75d9ba2cb2ca5721843be8182dbbc6da52c367c14d03a0cf5ec34802972f463e26f346e6d678e8d5c9ef3400d9d526b3a753381e8d87a5012f5bd844a5baf062ee3b8af2507b8920159f3203399d381a2c6e8344926d323a255db3fbdb936e5d4e8301a6b0f868c1ee8ee5762b35c189972408ffca768b2487c9802f47b621fda0153dc80843260b4536b36df989fc04b54cf21b1023c8d999d71950a9dcf62e76e0fa16e55737b3651137e9c6c633d582b6009d261473c981ea55f5f38884e5782a1e3ff0edd68b5515519c9e3eb2cdc484197cbfcebb12b7d3c7c5230c88cc2eeedb101968b8c5fe9994de2ee12df10bfe01f399551bca4469af73a887099f3cbc6b0bd4f2a516f8bf311bf4c6bf47ab93b5cc73e1745cf5c2fc68349071f007e2473dcb14dd910ab0f1eb232c2ac016f97559e4e42e8254cdb9a22e9e2aa05051505db339ab3778b66c61e516826f4384d1e907a9ec7cc3c17909abf", "0", "cd966d5960233dadf09c039de5a4fb2cb1a8f9618ad3257d2eab770df92a1696949c1e201632a3c66e604b8b1a6b570599d29d5f0e92f153edb1161a4e761d0a687e16f5301ba8ff3dc479e41d6725a42419104d834c93df99a68a033a51b228e67c66b57d26e9653b659a513f4ff5d5ba6e30e302978227118856cd54fef0e197b064f1e8a818ba255a359190f51687d1894f299e2d4319eded6366bcb7da2e9aa665749d7d75b1ded47cb1b56e58d7f41f1e58d147a421c1eb6a5373749eb7cc6edbce76d60820ef406055ed2e1b5da930767f1a88870259f629279415f5ccd8d5744e13759881b793ffe4a0d44ca8082a41425d64a86df7221b83ad937763142fe5e639ddb00533743e83872a09491ee6b04451641548ba710f3c2060b82963de9d95d99275520621bba7a0429fdf99240ae8a9fbbad86c41a380bc95a80f49bbfdc0ef97e8f826b9906ededb3cce3a0e31e6cfc287665429cf219b4863dd5a0d4ffbc762ffe9967c6068997f61a0d58685049577868eb256c60d62bb32a9d09929c36ba93673a1ccfacee472e0325edb6bfda78e09192d3faf50c5a77c385b7c6269c022fb717d976685ad8e59ddb88e344e6647cd885083057e8175cbfa02a1b3a3bbd3c73b7986b0d90e0af79bd1cd68191ad515bb1e4c245ed3e14931b07e243af84d5d4730e4d6f5d5fa753af267aa238b5f1c893cddfba1abc34cae39d2ca2bb9b82091ac2c2d4f8fe970f6ed06f6fd62d0213d50256de62970080448d405afca40af40a0289adb1dd32b3851fdfe8cd2ef91f38e69847b1a6f162b830e7573186e3787ab7dfc51c866f208d80d0a82f5012f045184dda2cb93d75d631647db3c5c3aa931ce10303648612056ff39213def8221a83e81924d8d23a17d9ce5ab94c2deb240729b2d2808f6d56a7ca9c96b7e374ef59c40123a40e0dd6f1b8cfd70b96216104b60d809005ba476fcbb266f574bfa65e0206db41599dc0a034c5458e8656415b2ef5ec84d90027efb44c347bd0437bb13fa06a2a62ac08acae9cbd3f0d88d78e576e10072", .Okay}, + {.Sqrt, "d558def98bcf7b1f56ccbfd6ad6340a5f2c46f19cd21e43e2401684b9997e8001681eba7336b28776a29756b6637c75721c21463c92a043382274c3be12260387570d82cff1ac563d790c9af53d367575c2fb69bf6ce45df61a6fbf0cc56075d5503a69763023ce4d0e8fd4d6dc2c33b269e4d3e00e6375c6d58d5c3266cf6c5a453353de8d2a28bdb406afb40cca986a9675d8861943350ea1d2321a5d4a05bcb5e48f3fd91fda10a7a71eefe1f4a7c2f71f1abe4f7f5b58401114304077d38a4e74baf2e5a546b69433e2a6bdce3d3e42258caf2715503a54cd3cf93de1da9472aae8ff1aecf1d6c9c087d52c8a4059033dbc784e2ecdf1305fce8ba967be73f37a34ec691411fc731c52fdb29cd4b9acae26d02a4f0ecfc33711f6785eabdfdfc38d5a8d054575ed6f305f712dfbf6a07aba9437dad71bcc1a470f9839f335962a560597f7c260e630fa147d8f5768192f7facd2c4cec76656b6f1fce52632e0939f75fee54d20b75f03980f82197ae8e4ed494d23188f7290851f2946e6d292e118046f689ab37c42a615340bb6016dfea0171153788fbdc89a9e7d0be8bbeff4e7d58b51e0b135fc39296af04a6c8c008194a8582e1a9787e09eb1cc4dda76b551658fcb4a463ed9a300dbc310c404fbcc9a6123a9d32621e7c69eb8aef46e79f547b043f259c1feb8d2d111b157a93eaba27aacf505865eecd5e6894621d7f39558843898110fd2dad7e7dfffbfe2843cc9b61b8c27b3f2339544bf214b6f3e1a826bba88337d573857cd63211fb0b5e88c2c6331786641f564ac761fddf18cd82466abbb67ed6973cd2cd1e89d2d63745b9cc9818dfd837c6b7d8abf5956d477736e7f69fcc683729cafe274da0216a8e7815bae8f5c2227a335a47051bd861b3c0b7b6a0c712d427eb4f123f0a418c45d28c8d683495fa6a197968053a4dd20d9841b216ea12922f981e506c07e826cde6d7434c35cc03f6d9d9ec4eddf644f4d9a8e1103d3b99ec1a563d9b7ac3df52665649608205da7d48ec8bb87840351f453bbf9e6c532fc2f92272e26fd5c7454ec8972c7ee57bca7d58b8bdc1cf944e0df75acc3e1764768dd3b49516eaa0f35a9c1818b1ccfe9d32fcef8559357145c89f7d6458fb4cfed52bed3cc32b7a4be62131d49fc6302bfd94e7528eb00fffe72199f9dc96c8d6381fff44cbeae6aede82e11a10125df193f09131f54f4d7bcf8eeb5a2e7dae7ec3d5a8d5f22758aa0964f1380afda21ad14f92b2d0c48d7feda6c1b0318305103521c5f9b3791ed3329f732111305d80b9b0d213f3d843892bab6e4b43c4940178fbe4c938576acc73ff797e85aba499fca06c2eda5e337d314abe65b26a5d257e29ce78ccbc2bef8b0fb13d005dfbcf87a45319643e0df212c32065c920e464788365899ac18cf1fd47c62f1fb81bd0167b8bda663429fb3c9915f226974f866a1463e486872f8bcddcac9c8738cc9ea90708cffc5ac20a0989f0a2621bc7d5e0ec2c2acdb436f3d2398f06cbbc5c6dca739dcd17efe4c90cd2fca4a54b89ad027e7025e9af638993d9809df06da0fe572fc7088acfc0b06511044585a18e00d17814cf4da47862ed8ae895774e5cc520f8db24f6523eaba8c867811d675b01de0b1c09b3178f5a18098146978aaf3b953b8f129a1f7f274f4261432e671f28f4c2818438ddf32ad01bbe741c42f8ecff99afa1024ff6ea3fae78511fa6ef7188580e36f8461f57503e7c563aa65a42326a7bd231cd700f98743847e12abcc349942920e3f3e2aebbfec094c76beb991c4b6cded25804717d6ea73ad369884e7806a59ec79a3c63e571af1753b7184043320a60f0fec5e716753b95b0deb64c3e746e6f506d9d75ed6116e8913845b80419a9c84812cb6266bb9b35aa20757e3c1f5999ee9c3919b0581062326b38575c9685c99e14450be7290157d7502a834389c8bac55b11d51e5311ea45bed7dc414d4c65027c0a9f9d9220e094cdaa97b5bf2a660020dad41359d56c229c84099ebcd4cfe1189a5293e3166d7933d5dba3592ac526f870b29e38fe09555c880fa3d04e9eac34c0a846d2c4f9ee4532fb6d62e03995e3422c629e60c6d22577c0", "0", "e9b3d8ca869819dba577edc6dce72f97b61789ea1a3d2f173eff340a49d0b5e9763b79e202bc1390ee19f20ac19201af09b0af5ae550a37a54fb2f9436bfe1a596441ac374f4838f396479b5d08b8a789c6b4549c327f92df64bbb95e52b6b8fa3aa08db906dab87a11f94ed6b5be151e61d6066e73102bf1e9262f3820d1aa6409c7697ae7fc91c9bd42cf727b1262c5bcc4c61ac90f88ed13eda2366cf03e84557c952ffaa19f08bbcfc03225cfc28040fe52919c2b3430ace32b530eac8c9bb62fd0cc41666319436ccf662ef5aaddce3d51207185dad06250f9aa6a5fa7bd1633a5a63da704d852a480dbff3ef6f523c15173ce8f15a074e05c0f7fbd8d2db7e89aa7d8e2411dad03f17c33067080626feb505c5844859248d9e17151ec39bfa4ac4eceac604b5c848228d0f865fa66dd6c6e76652ffa94d2dc0a9ab2f4e42e19e2cb70750c26b8af15a637a82c157c1f850a9ecdeb24ac6a330ca5b0f481b520c37985b57e38a3738202e344a9d03ee244b59d0ebf321bee9773f17b56625e9b5635c0f5ba3d65213456f84d7087d156cb586e1780640e89776a98c92a196a2de938508578160b187139ced4167a1655a721541ebc6853c626170eb5536a98b744f6e8afdf8f7ebe9a356dfd1f692c353085861a9721032ac57523276708d89fee1116ed84a91d38cb94388589f0ac6506e3ec8dd1389be21a0668fa131a0ef1ac1413aa3195ce117bfe2d223649b58376e9641e09e4e5b662c9adc35e452372ab1212f80a93890fcf23fd8c277bffa34daed46f566d863bcbadfcb16f0aacd72cb296529fe90eda490e4ffa61f213823e6d99b661bbada2de231e636e16f081e23c6b48c1a4b09be887222af05a00914bb245c1a4af66ebe38322c4155a029dfa0f0f14898aaeb5c0ad1a5a2645040e4afb39067ba98b3682929c9a2079f3238614670aec7cc5257b98b259c8a189828241617335f26ab9f3ab43a67d6589a8c40ca3e34ee5e66fd219a98739047cad31db9d9905d78eb20661fdc3785e12b7f5f9fbb7e74688aa60d8b41", .Okay}, + {.Sqrt, "21f0c71b7357110dad98313c18e8de686ae945a7e5ff0565e3640a76c6e59e29f703b112c711346809d9502bed71493f97540e1f3c34930d3e5df3f7e2e00324a7bf67380d96242e6d919e72f5d8a6d8ca2b0fd40a4efabb5a8891c1176160baadc964b86d11ed7b7695f4ef9f2417f02a2dda74d7ce1dc6f640c324a0da9e770e46955785499124130ed411d11031ed482fab7b8e544de01034c80873f917660373cd405b59e3e7b6705a7455edf2d06171749ecf8be816d080c4f7051d9ae31d1b569b1e3f0181b6ce2c6a89c6ff29b76e4fafce459ed33bb2644b2d392fd58702293c01fdabc86f278bb1be3b140b6793d22e7de2ff3550648bf3fe3d3bd3296368df15b5f9cba3787da55b021db43089e0e7adf7ec6bf8648d3f4c573b1d5ef0d4bf11ced13ee6379102cce10a11a9c72fc551822383ee3202157bb023f8a25b2455ad1ac2b70e3b91e678a5abc9ae93a87ce8bf36eeae6c606d8cadc7baccaa828a322476081ea6c5c44d1178e7d77d237557811860e133afc110ccdcde787895bdbbd35061b4b7acf211844780a048c64516baa2bcd40f21f1e85066439673ddae16954ead2da57f9470115164a9499ef87bc2dc64d65c294b97c9841dac4edd6dec01b6def04761609b92297732865d0e26462b3ade7b10c8f7d69925d2d85cd4c4a715997230dc0eccf06918b95036614293ca6ce496b300b1ae191ba52c05f4f2e879f166f8da0129fbbdfcf5012147bb37df80807af8c1fcbd2d405790011a876e2f08ac15b4ebafb681ac9ece535a4d13f9548d76f98b3b9bb768f0790440697e4ff017a2b0054b927df5bc8b90545a2e81707101f79f1882aed7349e27d11bb20c0d36a81e10d9506a3f017786aab8d8636d536875620cefbed82b57d13248a6f7c550743bb209e009f21b6892ee6eead8d1d3ade4023ab4b5e571cd598bc63c54fba40ed526df02b5de366bf63c5104ec9182e2dedc74e19f498d07180db59b6399abafcd38eed3e7fcf66c74253d4146c0a2ba0c89ecadf1b9d81050afa469e99ad156e0095b5ff79d46e9d7130687caa91af0d8f2fe8c5fff5f132a43e2f5356ef6bd8bd9d2c83860a5f5f9f674b6019573771a35c54c20a941f26d80fe88aa4115fcc38b16066d53e4db9a4288b7fce8bf15c98d6639cc438b8f29a293b3bfdebeacbe59cb4d762b64c7199366cbaa682ad87a76d5678341786d51a9dfb2ad2ff2389260045c828a5ea93e71043a6ba6bcf78caf02fd566ed394b45992195bf71f3feb98ae2d459486dcdc324bd14bed78e3780d161a33ac0e27a576f5f5238f5bbaf1d72c80833df13ec84da5a65450c38bacfdb50bf64d5eeeb80893b39619d39bfcf1bb8ba7830b62a8cfcb6b4662cd51f73825a58d3f31b0abe347f2f8f462918b00f1c3aafbdc7b31c6091014b074be1fee2c37802ffa791dd8f2f0b38c772b14352a944325c2210ba5f37b33773316a8006af16481cfa849130bdb1e7cd03be999251eebe3459962bda75d9ac08155e39c18a6fef5d61c84bfd855719a0b7a61bb9a07f9bc6f481d2459d2d23fb33bfc831191c37a2529f9a1ddde7645bc18b42e203c7e5103a8abc115833847ca831c1e2723ee633beb3092bb24544c2c40a5ae03da5d08da90146687c6908179683ee0f94974e87340035c0f8095a293e4d5ceadaec5589436589c5dce7352fbbab8a276d6e7a75de40e19730d351ca5b8cde6abfe3208aef9beb4d5226f80f074733cb0a05802f86c65d80a8ce17e6c1ed2f2cce108827c7b1cf1dcb1fabc450053b61cc71bca9499448d2d93c68e7b990371974ae84e082c02e107922814722a7ed83cd29f7d969e95800a13dd95d628d11485bbe8ef52525bc1263f03f814d7f6c0fc0aa150845bba92d8462cae4b1da83e54c0149f00d666a6e7b4a1460fc56bd045ddb9513d0df31037e88246e37e2c7afc735cd644de74c80444b2ca5ee8a6d417198b7375fe38402521a152abca3c935ff9eed521d815b5585de94c803af360a7f9e7eb1bf2e7202d3e9159455df5175e407879ded5d5d6452ba0b6675b20533e32a7ebed0b8aeddeaaea1deb52f52bda7e7c415d5698dc802091ef4ca656b3", "0", "5d36af61b5a2017f2f24e1fe6f7cc471a3f720c27214b5dbbb049ddf151f70fbbec4542e31024bb8a74070f9287b9602c2ba68f1f14b1ce8d65c178b50b948a831758bdc37101b0ef547fff02c92ab9bc6d0640142cb52e32b06031cf03dcb6722fa1bf409e9afce1c3e5eaf71eb339722520fc2cb58e362a24a32ff9343d23a08cb27e08a2a0a666e9873a5717b9dd42ab49b4e38445f663b8ad3436ef1a70e5ccfd47a571cad08cfc3d28c35258b5eb0a0bad509cfcc3a364cbbe69a60b27b56932e4be86410cf2c6fc5111cfb3110cc228d4f24702284e885461290398d26bbcd25f7ffb04a9d143233a03ee25dcdcba2a89cc4f78606f385089c8888e33ef19637f8440d67ed8f11c09e667c9d39751f61bf8db9722bdff41ea9e6929b98bda484baa107a36e57c996d8b147f82bb7e4e78ff87d63d1fb6a474a008aefe846cfbaca372998581620b800bcdc7b263d1347ab275b307df6c4d33c95c7a8581f4b7df583cb5344617b1e6f07126d557bff73f1a36ca55808673ca77245cdc4d054698da338810dc8e1661a32bff75c528e572c9e6510bb9fd2741fb7e5009f750d7135c6f3168ca9ef01f4d260f38e099dc9ada29216dd920d01dc561f032b02786c7844b1a32d37a3ed6e4b3f9361bab92bf74dc88d2c59d9f4ec14e8a7f4c1133c321014f6a8acf59c8df8f580fffbf6ff10636a33f4ccaa2c1281b30276d819eb5d9386170b130b3afe5d9db37573985b5460f3175d9c0d641c21d267dad5d8c47c428362b3405d38e5aee6709d7346b75f5f27500c4574f3ce2ae058f328f5eee229242a07b8c952c6b734b5a4747249cc7994e356a444274764cdbd3c85bd84f8e92071e4260530b6c5b54eaf22128f72ad3b34982d97e5ad041e64d3ae9286c2f57ac6a74172b920287efd8497d337f249990bea86690ccd1d72ad29e4457f42061c50c779fcede83e7975b82b7f8b6b34bba87b2ee4633534c021550afe7d18c5263c183fcc2fb1df259979c3d527a453d91d9ba9913945d23dd992433be747bbcbf2ce7f557f487de1", .Okay}, + {.Sqrt, "a3a05332eb6f452543d70e3312abdf30ac2a5d31530cc70baddf8a12165d29509aad90104cbbba152043289360ff000a6494e0ee607e18cb6d149fa7732f20d092c91b66f49c53f570426d9dd5c7b2e51420493b1803f3f129300efcd63683fb383ca38407ffc51bc14c4394d09c54618055c60446dbf021acd512cd2556cbbc203e9016a38fb16a0929566d577f50389ac0b70394c050ede81cfd142560a5ecc73b9323ca1b5aaf66de621cca692205cf00e6e5617ef797a2cd20fb3ace369af9fdb28e9d3bc54b6b3d7c93a97cdaecaf35c02dd6135f25acb0d3ef63a82633d28c27ce6bb4f79d030d55229ab0b0f1bd7a1cca298891b3a9a3a4cbf66fe5fc23e637cf7344deef303a09396b6c76546dc607f047f8f0146e479536ff08c99a86ff0a8f236f72525369ad02010ad277259aaa1cf77147aa5fb4caa6ef274744e31347bbc441ace06c93dcbb236a7b297918004c0c8f60840c31bcd7f42f13dde124811e88555f0f77c64d065da0e3ad18ec5d852bb1e28d5cd6d3d78d7358aabf38ee29113e3cec40d2380f510ee3cc150f4f3475f23479fd30088ce836546a7c74e8272196c4e8c892a0d4cd680a43b26e5e3a5c07aec2fd4c974773eaa10f8629f36ac27d1de140c7a7dc1243f11fbf0b4da15d424da1d54f10b32db8efaa7b13ea755cd5833625f82a213f8e5ed9b113e65c8d08f8aa881e606a5753573476d41d834bdf30ad59f3f778011e7473d4f52864acfbe8be864f021d44eda81ba9c97fd6d7f6ecc8f823683964e84e13682a58a6e8799a2d2e4087df896e39a9d9ceb52ccdd63a0a8c4fbd5d7e0bf1a2d0e6be6e9c0a6ab38824945c81e45b34e5ffcc5b2e3d5cf5c2e72e41c2eb478281071a2c6e576a0c259fa2fa4326394ccd8ea0eefd8c291b0fcc3c817fb7efbd89db14311e49316ff4c97b783b152cdbb1282730b1e69121001cbab899e2a458ecc0690aa2c7c08dd0c21cfd21a90a002c345cdb3747703edfc3ede6611d62664268875803a3d74314fd2f5688cfeb0ead5dba44a2e654ff355627fe3e2de2994652004bec705834469b614200fc3243a7519699e0f4054fccfc504651e3f88c17905022056cd989c5a52f4cd9aaaeea07945b335ebb250dbda131907566f23f5aac64a0b43873bd7415ba7eac69065428390998ac00b99067c3fe513fdff4f967a0ad2bdfa6f88fc7586ce0b2ba62ca9146767c45ecb0ab3b5c73ed2976538ac52a612ac0a7ca7b4aaba51052f4aa8fee3b970c11deb3ff6b704d634c6e93b6f84c683cad192ae3523e6e860f071be6fcbbc305f14453ae4d010df4714dde3b94b3e079a60ae0f0608094bca330bb25056b17ea0aca71cb34b8fed9ff32a9f0727a755523e676809c9d52ba7c8b0f1028095cc6042a01b6642e5eaffbcb9251e7caecc4fff8c10c76ea8cd69144c6c54c95efa45bad0a6d1083d836adc5a1d74dedd160bf9391e480e8b241fe1770d7714d882427cebd05bbfd024c8655cca87c30981d45eb6339338a2a68128aed8d2a5e96b1bea9ff93796fa4c463a27f4b58999f3e47fffd77e06ff1986b1e5a8598b0fb8a1697b21ae36e073b35cd09faf1ae46cb34d0d6e4a46fe91bb92191a06bd64236d72b4ee2cb36134b40b7109f7801bcbba9034c8934f69ccbe3cb14673046b834c32eb32296530074081ee6449308f1e249a64d964aa13679e7ac468afd203254c201ccb7dcb2fc30b1a029b05e6b26048a820ac2282563a795e7a27d3cf8ca4e9a62124886e848cb40b7e2d640cf5ffdbae6d3c28016ed2df8eb6583fa6faea2a2069c6e7171aa93d2aa458b0f1fc20115733349937efc6ae041f5d6641ed534b9667c336d9141d2ca3b932f094ad293d0d9babd40d33bbc01934e8ffc5966f57b5553dd6d7e8644753ae4b689e4a0cfe6ed04a9827c661628b92911d6a274ba5a01de0678ea223cf714a9c8babb6b09642efa400d592c825494e3ff95023762ea05f9693a68a70d555ee2d316a2aa0978b034c867bef89002fabc531e3183fdd36e4b8f2600483a2ec98d36b1e6565256045ef360e6db194dc54a78cc88d42f3ec95b314060952d089794f1fe29afed4e4127433ffc1070", "0", "ccaa978adb2c991f888798a84bd454f66d2f2fda7d746cf87e64a9aea9e328ff3c29b85f295f62e20a3f2fcd877c921f0d42cbe01763ecff38384d0c01222223988bec6794b8c5bac3e0d35a4c5e76894cfaae7d87cdc0059b372d770e4893437d0d70330528d47bb7c517409c5bf38374bcfcd25ba048feaac4dcf19f7047fa856dd25b54652597ca63375714cf821500cfb2434a62042c55b860249ac95045a4216eb7a2b897a9911e994d2b12d47fd21d23ea490358088b59454d0771438e25e739a4f3362a9ff9b8af7a58c3fac1f1fde877f7ba1a642a9a3b94d2dc9e3d1890f032942cc7bf0f45745a4a4b66ab4cd6628ab48e57bbc9ad9276596fd842eba45af3e4d9aea26fd86871884d8dc2f8bba19956790f31d77c773c5a3dd18cd2d4dc5526c57c42649eac8dc1d8b9c18ca8c41a976b551d149b30a80d0b40335bce7f1090fe13e5dc040eb8a1c7811d66080d928eedec9f21b255b0d20612dedb29316a880020c77bf4851d94e8847ff75f142d65dd9dda03a92a7c0c7f835d8e405ae5f1535cd62f2f83fdb396f5c739b42b8f5255edbccb5b58ffe9e1d992528f390c74f0af5a17d7457deaa7a342b3dd35b5f3ada4db5985feb076e5587b146469e3945515c4d7bcd7ff895a3d6e6585e437ccce7c2d519f158c7ab41138645cd6bc9797d90f6d42acf1074a582b33bc8d9625298655ad1176fc1a9e4ea22fa84a74902dcacaf2ad3959fc0431db55db8b4898871cb903db6924ce024d0e639ec7a85946519c1ac37f439203984a9f77460639220b17bd0ce1d551178fee7fc29e78ca4a9d1494ffb2b3d67d8942d4742b89623495b33ab66edc7e0f8c268d8eb5f6a4a98213388abf72b2d1f4643926c89c4048b8428d49488957f3ba133e6804f42bed527f3f63203d4ffe7dcd3cd3a3b238ccec4c8123690a315aedd3d2323779cc73563deef88700192db7a6a6dc1696d9276ec97ee64323f5735d4ae13f8f8a2a1a6fd774abdb890e0aaa715b49f6eff13042f5ac8f14b02440a23044c377c2356e0f08fe20e3d91511", .Okay}, + {.Sqrt, "7f45e9ccdc30bfa7b6d9f0aa981dcfd85b5886a61ab680ab966a70c0f6d0d87c76de3680b80ed70fd9e90d0b65cf58198168669ee8214a9392934e049fb9206c84521af31474271c0cfa391bdc559065c560325f134e0656cca825566871e092ff8bb6b161faff5f1d72d41e0142fb9acf91970b8fb8aaee0caf00635a4ddd0446329d89242367e7ebfa2106bc6b0de29b6c195e17a528c680f345e98f7eda855661e03e91f2f36006d0e1381893d2ca4ee1311ef0194d91a749334e02b6f416413d9b2f9491d76c507e00310f4deaa379b810c3d20f81d835502c76bab34426665c848823b7f92bdc323c4a10aec47f9ff96c24e0f5fdc04057b530fe7b63872ac9f9b353b13c7eb9444052a1a33dac3b4de6d2c5eeff2b013f15b939cc427ed8d7d9bc29a8ba9f6124194cfd71c07486a7f133d04ece5b0d018bedab8eae3646f5920d9abef9f3c3fb035d51df7f64f823cd9659c027524067de2bd542f89cf698a78fc437db1ef7ed5ac126ba6a7f08846380da1f8e3f2ed3337f8d4abd44e592c0093f66a1f61bc7ac292713fec1012d6149d2a75af872d06f5ce1b70b856b465e4d5d89fe2fc9aadedfeb0f8e55bf47e03ab524f9e7d2bd9190b93be3d6f2340bb794cd2d37a316f73688377de33f4379471c5341173641bc08ac1fad8b55b9e75a89263dc6a3cfa881e9b60282c5014a06c8b038ea56f0634be43f67d884f7ad3eab43a03d7dda3953e25a6097177e7278516d9d9056feb4c3c3469de0053e3abc9d4f91c6ec7e2b95ae1651fe30e0626c3e22ad7a7c27aa3e197bf194974a8c3e3f463cca13f432105db4dfc6de153beee618adab9b0a16c447eb986f34dfbeb482503eb595edc22fff9f8a74ca7bcc95c5e30470e61025a5e3338db9a272f5022042454e6ff405c8cc1569394067b743e103a0c84e0a73fcc8e44b46818dca0eeff96bf0eafbb4f7925f6be492277efbe2f55b6f565dd3434d1c82b34b883b5d72e2fa797b9ba854181916391317766237af62fdc961e1f6a434284900a4ad6beed608ad32feb7b9e948a7ad8933012dc493c8ac9c2d469e6f076ebbd7649b9357c62835c19c01b93f06ecf8eafb6762a43987601367c7abe3f113fdd6cca25df2ef98276542de7902b69725259e4c7702b8b5a0813960a14768c1509bec1d54d5642de216ea6f6f45fdfda352b54e080e96af1b8a6d865ec1455658ada395790535dec21409efb4a5ee799397fd0ac0d1bb6e43709cf069dbd24708bc67b36790b3350447b0b818054018fdba1b894bd5c58cb58e0efc0463b5e2555ed6a1424dc24511c01027741f48e22f3bb8aace7efdd1789ff60b6a71e6e78549d757c8f503429f949a9a900ba7ccfbb94b2efe9ea7a4f5976183c1ed8a22186c7901e479e58a6b98793cf7f6106dc14527a7ed603edd7018787d560634f0306894951ee46f06672a84c4e23b4ec67b2d91fde134b48cd93876af115138900dcf445406d0b2cdcddf14c8f9c30b441d662648d027f13dbee42f8b37c9813e2228222e4941fd1e0cd7a5afc59a7d24d97834d424f0ec0d33501107414161bfb72bc0f64e6a134f96033149d6a1ace90a8b073654b6523de77ea9d69b7941e2c7bc5cac3b693e1193083eafa0cf5057805acac17a716f3a516a1f76c62a496db80995119a4f955d94e3e5841111db95b54588e108f7bbad34d77c6d236fb979c36fb32b2688892a1b2d3ddbcedfbb531f3320743f4369e55eec376974ffdd0cc532d3a9a1fae0b500c04f529b94049bf1784f25d3570b36cce7d63bcced34912cad596584277fbe533c4f10ff5460a6a08bb95dd10e372bcd42e82b2176f3fc725c0cddbae0df5124f49a9ea41c8c17d59676470e7779f55b422759bc9bb159312dad33f88f226dc351c6e39beaeeabe20815013be883dcb64f6fed65e1b4670256072f88e50e7e09741b06b575f677983a86da879676d596b690d80903eae0a7968c8a18a1705e6ed131c589aae9812ce5823f10465e1062a36215ed0a29905ccdf788072ad00615b957546c1b423b516660e7ca2e91ef9069362906290d40e871e80a883617a1d43fd8208c55fbf813a13c2ff2a8f6173dffacaba2", "0", "b4812df2dbddc8da3d43382b30bf2551d663543754ececd1d64661096c279f9b04a12adc83578bcff2974f75e1d2a67ba1dc9526214f19ac509ba46b6a4f3d185ac2c601206fecc8345bd2756168c95e3ed6cd845ee528974337f4604b04abf20331df4b9178ef60c8c4a2f84ae14ac5737c7161801b7c48a89e0a62a0f47a94ee5b74b7f9fe1505f799ff86037944b22348f4cc84cb6f264138e6ec78cc66f385acb893a30a11d87de5e28e9fb76a25b16d5ca800fee560ccf3c304ad469dd0b858013e7f9e444d8eed00e6afd0774e01aa7aecc28999f66fffd03fa8b2dc4901b1fd12ffaa42b9b86b23e6cbd1ee8eead704850f6799a8fe973feae3d8f3498d3a8c1b5b8c8f658d59d0a90359819853afe197998e5bbe48d1aa32759231b11b8de2ff8507053b5ce6b8e0362eff4da503e8acba84af86d8d7fc3c6b06b8af0037763b2ffaaa5924aff4752390a1e9818a3cb29f7e9dfdac52fd0d2018d1ac02ee50868eea08d5fd05cdfcd2a9f3149e0510ab6ddb33326e445486ff9d5b64ccbb086e37ce97a4c9115b5fccba5e7c300ad2dfc399218c03326e5cc7143cb215022e5bd2245cf9f4492729ee748594c686ba150f0f3925fa609ff53e04a9d6bb31118e92f006e7e82a9e9c4f6b5ace5aa4c9fdb83e0d1749659431fbf7e8843e5747552eee0ff2cd149c8cab2cda501e2e67ddafb59041cd17ae58edd6a8d324ed3e72528db2c95701a1175c4a2b0f1bf9ba6201a588b239cfbbdba290d53dd8e959cea778c0b1c7053f42caabb1b2c95149e2fc84dea5945d44a354a20d70ac1908f0af1b6f7db4b91a7ee11b97dcb14208d8726e0ccc9b21f8604a30193fa3d961044037b5630450d7ebff0ce3527265b2513c5b0b8a45a7509fb928a6f07911ad94a244a9b45d50196ceecd161e53b6d2c55b2e2b20389cf35218393a3a0b19120f5870dc5fdc15a68585aaed2837a6f7cc9dc35c7a80dbba9e23ea3515dcb44fc0b3bf2680be5907f7e6ef9b551c111cbba24f0f0cf80bf52e2bd18c802d3d8082bf3145a069ca539bbc5b", .Okay}, + {.Sqrt, "e8d9573ca8a1d4cb779c1b706b5df1a12d39f307da9c2a2775280978e03f8e086ef34586b8e5b7cd8405b72a07128c53f187ceff66f93a3b1986afebe9f985e3b5fa8f0603ed78ab2683856a92d6069761cb6711371fed140d79462ce5b9547486bd02b08aae6d32f64408ca8684522a55a8334d93e6b3ac29b30e0271916399d029f1e47919224e46099bfc1b4370241fb7a7280c5816dcddebc9b48d4f8f63bdcb4c0f7abccdacdb63aeda01fabcc95cba22611ee593153f71363e9c817ebe5b686f76941acb8a8bbe8a26af06ac0b5e781e9d126b8f55d1b0fa05f52a3892ebe86a21dd7a377d788d6906b3bb0052c8cf0eb9559261ef9997fd8e1ad827bba814030b594b47c691b9ddb072ac4b9ba71c8336aa6bb5394bc7d695a65cdfd6cb4cddd7e5098cf985ba4b88e3f176e28c79efc26f81c4a57b3563eaad4c45277ffc7be3804bb67e55a993654ee04044c47e3034c7c2562d1d1eea7672e86185e02178916d294dbdfd135afcfc7eb9f6c69e6621e6b0235c40047d866dedd0dd95fcea38cbf014e42e1057485e32bab97c5fc3bede3e6e969de8e7a1b9fa7c35d8ac0748d4f29bb5e672864f2a99afc2aeb7c29735276c9e4642032e9e8f084cbe1e78e341ae1c452d9ce7c348e80ccc1c2e1007e0a75fdb0b34fadc8df6a1a84f1be0500973a69b2c606c5388078ede2919aba15cd2fb69148ff8a3a9c41f4a4453b7dc91cea04cfbb3118d2e078d911071e63f69c1e44727e424188a425e56eed69fe151ef25c8749b4c519d36deb6e39bbf3977a7e3c07b30c1ff01f7861972dee5a5c924b6bdaf770705fa1eaf79a02219b31d23b87de3600945d696e918aeab145132fd5c67fba6f2c7d008589a0c41411ea60bf4ad9601cc7b27d07bc2fe2472ed9b6b897d034f7cc3fd5d8814a389ef74a8fe4f26733f4b7010fd68d87debfd21afa82ad993fad24438d6c847df550d1a1f9ce48511b3a52c8509ebadeb702e0ec8eceb9864799ccbbf5265f3785729ef3849c10e64e25994b4da3291fb7d72bca8b5794a5dd31ae2be0dbb9960b351c1fe3d99eadbdf1b93845217e590ea423373cf1e29830d3ebf37402416c7b86f5572b8007b803aacbb0290fcd5dfa180f44b6b95e7591e5f828503b700c4b9d8f18f0a1bddd3ca2a898f31ab7ef69aafa9e377b3c0b02b9d68f4776efb34351353ca257c70a44a51ea7d05f1dbb5905002e331f5487446b813f4f9385fdfbbe1cdbb8cd0996f2c01a3ff2f9c480a1d76de44e513bbe13f2e443c2a632c257cade09fc3220ae35b821d486b55355fbc0f6dd5e7941e473fe88cd38ca7537bb6c1cd23ab27374ded7aff376c41d495f43b313bdea79c6f4bb933445b7b562ece273ac1e44e2114d68cf40a6da282b05a65a764c3a5f1dfe3aaf357f8837ed51a098df610fcae093d808b3d951bd86613ca187c435381103b336d29fab2b16eddd57d2d8587d624f8ce69bcce29fb9e6b52aa049fa2fafcf8e80d51e809c18eb0b6a196354ab4873384c83b6f2420aba3100326970039bbc8b05e2abe0c3dd6a12e0e05a9886ec06d15a71c19e36b16bfc0e04081b6bfaac402970be9073517048789706dd4a409e5d7d0ca5aec8716cb44d53e7e482ab90cc438a16bc7deb60881046f69e28494c1e7f8b18de94cc4a6b2cecf1e1d7062d85d0686962469978ad65f2757f3d638af2113daf58bbd3b6958e48927141c153dfefd874999f300276d5be71dc7caa4ad5f956429df8d810d3e7e6ad0d49cd15ba540d3cf65f4b4d7a18db8a139a45977b6568d0978a2c752909e4cab9d49fc63fdb6af6b35c3a512aeec081dbd21a4577a0ee7666c172587c76296a35784f03c0ea504e2885e0eb3585f7ce4de3a72e126e9a3611f5123b4ced462252fd7057a34f4213fd023079cb2cda2e2892ba33fdd07312dd09a14d7aa7a8b537e3b337363130f6af7f470c6fd929ff8916c498f6ddf3e9335d7f77bc20e0fd65d9ea1d7130182bf587a83c119aa8933d553e76285e33ca5e880ac8cf878bb497935bd012a78db1fb73743a6fbf98ba3a8cfb48b150eefce4b443e9a9d0a54d8630686a8308fc16b5644a5d21f0acfa8cfd6ec476e45", "0", "f4267645f1f42b17be2ea255f29b33e66c529320f59ea2955a06651a49c73e8f8f8461e224fba52f3dcb19b6ae06118ec83d0c5756d5db3412bce3259bfc312e9192d857e0ecaae2df97d19d570e92ee32c9f04adebb6f8a89b88ba67dbeca53be9d5fb7b78e8dc4b5e79e4572b9b5efc4c631e58bf0f47b2b656ef2f3a1926558cd4314354d616ae55b167b5ac3e8f2dabfeb98c72ab370da563889db29234a8f91fd3676616d0fd541a152c7d0df419e3ea04c8625b0628c0b72b6e2df59ad4cbbd5c79c0613d411c5698c3f0191daa2e4f8030fde6ffc400e20e5cedd8b35f4229294549e97fdbdff4396447efb8b46a2eeaa6be5fb77e531fedec4b4d9f619e37f5328e66ee3b65c7484152b888f6101ad1cd86dfb897398c730cea476c5c97b6ba0ac38d59426eecf7478c2cceb08a24061185bc74f3a602a3f3de93d16fe539845db904887a1a8d4f1097fb6ecc75083b426985bfe18ef97e514c4e5e5ff2ded7672538d3ea066d62c32c1ba19d4af239a31998c222167ed7cbf61af8591b92fe62660d49cf1a89cb361eca4cd95b2d732cf584c4bca258acd7f3d0c27164f4784581095e48359fbd5bafaa80a09671ff1e04b2a6cc552218b0c26ae25f797fd03104c588fb4d34f8b1e43d6a60887ebe3f9a0b4da0ba6ccc4ce20f01ffce976cb324d4f918e18edf7e64bc8d9051045fa99ec7393d8ad534e91ec0043fd764ca827c1faf806848416560a7c4cae35e8d30d78f84ba44f76db7e5fdae7af705fe3ba15cb49cf1a2132e38d22648fbc71dc0ea8523565d5633c9ad016553a5b21dedb6e1e85baf6756768f6767433ee1f547236508ce3b5ebd0d0a1b14e476a11db3eb40107a9f68da19e122315dfb32a2f02dedaba9932155204639fe5c1bb470ad6ac124af641cbaa7b5bb91da1076f33cbad071cd440cdacbd48101518b1a73856131708d6b81b5fb5ff097aed5ffc056b83f9077debe891e540535c00592695812fd77b35ffe7b4bdb61104d60521075f13f784a729b29893cd43f60e4703c174162a62ec439f7da3c8", .Okay}, + {.Sqrt, "aa877a6b8eaf5614cd2724b848ef5667003453bb5fabbf9f389e6bc9c03bacd80ded7eea605e0f0f3ecd5a691d7a911452309efd7fbbcc0fc61f5cd8888255dd3e0a7537d327de22caeed3f24049cfa7bab91a40fed04965b103c161cfd0f1ddc67e8b82f4b70e66920a261b629255c8e2c6ac9838b63349a631ecaba42afb9038c9bd3701b864a28334daade6f9ddd9d40c5470a4c7b35d8e8c9de82df5972b3d2c87a8344508bc57ae9da87cf9ef6ee06437821f51fddc8dbdab7663e44aac8412c5f98a92dcb336d95526bfdab94aecc65ee561cdb06d3be02394d6134c5b1e8165b0c9f2a0258e96c79013354d5b1ca3c6a78696338f93654e2350b61c91f4cfc2d818821af2e6c00e8050c4fa4db262386694a486bd86276f0884b0ac7e4ebc079565ccf66387ec269e827e4410a4e15383074850a122b817fd36baab732865e49d0299c9e364b991501f45572f8f0e58c473405bd58ec4399119c6514534ae62db09d5e7df5a3345f1aca40eb601cc0f985f91f421ecc07c06528ce404dc36293e3b0c29ff890720b6ad2ace16bffa83c7c8bddf142829db9b909ff3412b9905a2cc099eaef7a3e95485fad3faaf6e918f4d36682b7e4ef1842392536580c1b14560adc3459a169796b741d9c98554dfd7d9141137e098f71a48324ea706694346186a4aa2acc63ab05b9f8b8961925858e1959e3527661024342ebd82016989a9172a1f21225b19d23ea68696e6d3f86fc12c336ccffa58a5acea17eedc4dbcc89c191ec927e0b72caa44fd152fb2beb88f439c2dfb742e82dede2869c1180d259a0b5c20e4374d33ab9efce1632f9f3148aa435facdc3cd9be21160433735e15f4efebba399300438d81119716a1e2b6438157a6104c53f567a937119031344cd4b4e89c338e4cf423e36354f901b20c05561480bb6f762f22a95452dd460ce27127b786f55a51f30472abb79bcac4790457a8a98b71ab2022e9f457e0212897b73614a51a6938ce0154b242fa89dd1fbac2f0eddbfd691259a05ef19c0d6d20642674e5c1ded4697b13f2e76a0021915d7418d56b5097f65d521662cf59c0819eb20169a1a0f9afc9321fd5bfa5287d57d6cd5fe7706b1026602f188af09c53a6ad72b06f53c384159474663ccc0cf40dcb2555613437edb5d84864c3915e53d458a7453e5f5803fab8adc2d14dfe9ae6cdf46d27862c20877725aa9b4398e813c9ff49fe7321f1d38841a369af4f45fd39503bf1ddc1422f5058c40027c402ef306b064b2f32e23083cd1fe32c2fc076ee074e3bbf9f6732e190aa7da202c28f736e76ab5907472e60ae268647b780bb2c6ccfdce9f2ac3deb60787fe50b32ab66695ca2600b9d3a9eacbef9bd558b6f0d05dc769072b37278785ff25789136756ed596a87d50f5712cb3dd3cd98b9bbd02d13ad0bc22ccb28b3907805b6362ecf71583774c01368502f0b20a78c3e14e1831293cc24246930fc18161f39e8039b45c59fb359ca69d5bc4b8eb5f09afd2a142abe9eb18f7795a2634210f5aaf211a5863df3d3965db35ed2345014c726558b7bd547d9209f3d3d3f1d1eb62b1001ce64d686e80aa690c22c1e0f46ecb74e49ceb55cb0e5f8c3d14f6c99ec0990d331875619b16d61a1df4347defdd10f2ed12f7c3abd30c78036bed49fa084f7eb0fe2a41b5d20e926a4a393286fddb1872cf4e125d17e4d50bab83a1b168de14e45374607adeb3806353a40847b9211cd6743f751c33f2cc980834019c9d52ff4941815a7a2a7280f182dab6b54f2601a514d7a7381e5ee08a078ddeeb9e6d8c7e29127c85a79682fdbbe5ed6de97f1afebfc0e73ba376733a2d53778a6257dd00ce13a1d9ae8f8f1f8e812e5e895bb8a8b905542db54d02fff1b743a7be331aacc5c69f045d50fc39f25abdebadce00e0e0ef88c9d8acd122a53e6367d015954691b589bd4ffb55cc867fdb07ce530aad43b3ec34131122415224106cfbcb37fb0324ff7603a816ac2312c5da16df237a1e5e204397ee5798bf4f76e4242c3a4bb9f4994a468431e0aeda1d9f936d022e2529f4fd529d60536a7a01db64ac50a9c1f92fe3fd294c424614bd6a5a1eb1661eabdf34a9e", "0", "d0f05dfd0ae80936635028730cc0761545c8c1a721ebfd83055b61faaf25ca34b798e9a86db2eb2306021b7aac41cde19540e846f9e52704771ce9b3a513d2efb630734c68526b402d62d0fa9eb5a251d7a237d1803ea3582458762dd817acde0679995acb47c1439caf5979ee74f81d175e8c36e0260c6d1d029e205877312ec0bbdcd714fe02747c58e0fde36f6ebc512fb81ba3061223b38611dce1f38da4e55e769635899d3910118dcdbf395c98e8d7f972fdc80dcc10626f0b43ae1b86e29995c15ae8c8b28f6819a73802b4a7483f3eca183053829cdc1acadd5b870548ceb2a9be3ebcf31dda5dab442b0ef8d0babaea58bb942d45278fbb501c5655bc9207d5b3d2c9d1efc94bd5818366449da897505e26d5e8b6688b1a4e4b70e7078b1187fab2be987fe971203440c838f5dceb4b889faf85c2f4049b815c2098a06a0f69429cb74ef73fc5113b18c3902ebb1bf891243310f9cbcfbe3bce0ce462c2b5ebc17587bc5e657c4c1c2ea9989aa46a79f9daf91fe285cbd446c3b375abebc93ab35ee3c628185535f8c12412139f87d918b6649d51a0a68ca96e5e2892597df41eb3ba80b1bdef464557a0bc8a057ca2c771fe58c37278d8165b793ce8b92fb470d4cddcd5fc847c4bbc18f654880b3c55ec749f314ff125fe09327d0a9871fbea7bf868b6025ad8f10e7c1f99f670169a13687d12eafc67538025e7e0c598ac7c8c6e2e8b9ce48986a663fb4fb91b62d706348c19a2f8ff616b0a5edf1f33b46034acb29b6e7ca1ed4c7ce0ced8f3deae1784f07c72b6e81788b4b5a3e2ff1b584d88a41341b4fe8943a5d850f037c3d85a790a59b05eeab4a1c66c11cecc3466d6b056705cfbb60a31059a5b8c68e1b6cbc56471468cc190e9d8291b248c7821d97c5b72c8f939d2901569b50baf13ce351b0d784721bc133c2bd9877719830d7b18571adbf876c8f763344526fdde21674fe4b170ec28c9c4a47ac17a303bb8322837b904d53b0356808ef1fa65a76798b03b87960646a130125214eddae83af0b5038166cefc72f9", .Okay}, + {.Sqrt, "4e8b3915d9f8022368d87c9da5941d962a02777f3d716e3b755c3f08f06709ecb8e775ec64c78a9cde8d4780e2ca8f1978ac28b3ad7b39fac9c7d362878363a39c1936e600b694542ed45a6f1226f1648e3a793a5bae5df819e982a51e799e6df4420bf77b894ad9d65478669c1fe999bcbdd3b0330e7cf2309da54ae7e8c5d6a65d59ebac1038517d73f16c69874c6f83f88e91fd7bf0dc9b9e4d7043552f5fcfd7f4ed12b72261ba08dd370a357e0f36b5adc74cd74c0192606360804f3154fe56efd809a9ecd19ddb3946af84c3acaebe354c42d313fc3728e3bf65da145d64c82747a40c87d17b854804fe87038d29788ff142dfc999659a3e2f1cb5dbcf197b9c2cbb4630ddc95a2341092b36892c49bf11204a2ad8b02f6bc233f29a404b5a25d403e3f611f9bf03785340b25e8474f121c4a2b1d5217f87e0b2a39472506dd9d8b4925204ee4dab6709c2a87b1f042796298d66df83fb1921f94ebcd441980c4ca8235cfda56edf4e46dc8749429c07f5d0cdae00af50325aa3adce8ad33e006ddd09f590a88155d1f3cc7161a7e56ac6f14de5742ed82515571eb4089382018ebe7eb958f9177fa2636e21791b4e35e92b413d511d8b62d317811f51e6e703cedf61b569981ee9f3a8c2c963f48fbe7d69b17bf228cdd469ff39d793f00a21a1da54a35949ef261438f2451ed31e5b1ff12a4ceafdb56236955da8cd2448f94f9a4acff9f189286116d6a43d482898a047ea399fd616fab4dce5778340945f8fdbdf2690eed3381f0dcb668928cc1b61dddf3ae133757bebef3d33a93565f8f8669b9e92c7e1fe33c41370f3157686a71bdeffdffe062b1dbb2d580a6ae77752c49eed6dcced6c5aaea3bc7fa31f179d33994e4ffaad06891c308f4d6b6ee16e613e450de502939642474746d8a436c58c99331d8ee3e5b7d0f833f7c618bf7b3a72489e8a22005de5bfe663340048c2331d74ea49d01dcd8f02014e9e636f265866ab5aaa072a7b42b2924a94de5956623f5fe3027cafca8fc5cd50ea5a11e49e5682945a7be993a6a006e83cac556dfd47beaa6bd5e8392270006a3a263f16c943fcc7b3c4a28087df7c40e9af8d39016bf8a744daed543c8a0cee7129778dfb711d1e02541e49f1684f532a1a3d196cef6d409b6a638c0cf46f6c322d0b06fdf0bb82efdd85a087496eaed5d0c1cd8add2cbfd62c8471eb1436ae8f9ec8311059d847ce95a5063f926decfa3d96f347b4fba4567088ee546950f970250fde78eba5d8fc06abdde43f539081d6a0a4f3cb7209df5107f3d42189889e1e3b391c4902f4172dafdd9cf9cf4012c5fb3c76710974b47d1a5d66391af0620e686cf0c08d33fd16e604a718bdf47fcca373f26800b9230137cee3ec26dd052d38dc737fe86475c8a321b8bb881180bac4f2909040277bc99af56830bb357ced8ecf5552cda9f5479a2033b6230474adc7ae7b0e4b37f15aea0d2372e722976396f9166386563e282825bb087a108e1d92ba147259adc36e250c3cd49a14cf9698d3a95518cf8d3d5c63e0c57de1739bbdfe457c30fc54a7b6006bd73dc2cca591492ff6c17d0cf6d9be3980af852b93dca6bc923cd4c05224fd0ec49bf07ac3e43c45db15f27a76fb434c93e72fbf99c0ebf8793682f856fa742c1ad4da3e7e42b08b320b01405eae72872874465fe45f3ffc5e69d145f2810f43b933bca882bd30890a715c0e7e63404c87e751457cf8e86ac6dde91ebc3790d6f20d8116dc6db21ac18da72e3dc9f3a188f6c9cd5458e0c87673b40457bc4a8c9bbb8822f9926be9bdb258fac942b0a9cc78efe9ab62375cd3d602cb54aff86c0913ec8225339bbbd3b9df6675d5d786737e4cac0b7b74d74e7077510676fda7cc5add3f1b85220f97f3b6f0622f3189e88dae25addda55ba050f5d887ff27c85299db4abf8f27b9f307e9048dee4a35f9f868e82d1788b2e62c1aa4e56ea5d97952c963ec29402fb4f5f72bee2294c9e3a0960e4226ea6210b4da98a4dfea40bfd73c71ad97af66f3a7369aa36dc3c88dd527096a154015a48bdfcee645262a9e7db1a2e0543af2f8534ea95281f8b8986e82fe32ea5ca5d5f8054ef79e79", "0", "8dccc8de80acf357150fcc8982c3b17c6bba84049e5e473a622fbeefa7c1e891c461f528fac8555f40e6ff2321b3395422dcd8feed806c95fd4a266acd201a47dedb2915dead4ef573942e092ae46eaaef652d0398cb520a5794228979b8ef198a15fe25ded2038f0d5c59066becf746393b5f87093320b6317973fa6f07163f449f08995f916757373bdfc2e6d390e54cf303cd0ec72b8b8185008edfb5e9df3e7b59e8a163fa78cbc118193dc1cdea4ef19680e1fecba39f26c7b16dc63f6d4710c043dc34aa20057086993e1114132591e5e4433ef2496f21f0c40d7b6a0f33bcda0bdb156c4c7fccf5bdeb9c1a7f87b885473960d1ea8d43467059d52746d359acd78da5b8315ca6e3517f9fbcc1e4736b41938af8bfef249df987811b4f11aa797ab5ec7756bfa546ab68d3b209f776054bf7881dd98f11809d49b275e3b8780c0da371f1ca7e9326c088f3ba675f6e46435ddd5e66627d1fea0aa442c7630836eb7d9c1d822465900115273e7d8c9c3642281a9bed191057abdd75076dca1ecb7a8e37f00dd25771a8a7659c29068b144475adb680e7d47ac9bb0ea6cf361f83b6d5dc807ddc40593af1d0fd368787899bc77be18f3898e9ebe690303d4df8f83c413b8cca5e6e510af8f1f28719c76d0d80531c1a0ee7ad96275cde72cfd8db1fc7a1fd92f37f61125f089ad44d7f69515cc1296494315aca747c0fb4381eef6b9d2559cbccfd3b52edb0ccf602b5465b0286da79bb30ee33b46e631b95b805e9d566cd3fdc1b21f0e5b6bc477318a0282496d3228f9ddc5581605ea60027a953a10ecc6d34ffea7d461b008b8b493e678b11a70af58fb74753260124c56f8cbe83318ab8ab82588d7c57abd1549d175f1a99045284ab4b327b3e5a06cb49eed86a65f5f2909c8fbecc9d5a232bb87b989fdf5a42b47a7fa11cd7e7b34389dacfa687aceaa7173252ed39a71bf2b12551e56215077afb0a97d92300cce574ea197318fe5b7b747215f84497b6fddab38e380dbaf0b647ada03f48d404924bbd17e7cac7e0c948c188ee1d", .Okay}, + {.Sqrt, "603dd71767d7e75cdab2fffef89c874a5479cc01286dd6884cc68e018e31a1b15de6cb912acbf30e16c3cb324aee6ad5de831437dd0d897019f487c436c0f521fc5f92b14933caf53745552688c52905736d7b02dbdc9763bc88e46a1d879020171eff1ec9c6f0c454219f1b3a68ed8ca01cb4462f1d517c315c21106bbeb3145163cbf780ade2501c92d0d09774521af9d3ace6ea5853eed4fe0cef488c914bc951731222957adb1cb0b78f32cb15bf1344b0adbc0041f88914610738573d9a74660aa067c0bb84ba064c2dbda14d75d7410f210ee8dde7aee29b0fa0f0fb8b2a5d0b21b6ce3cce73595e2586fc5b10e45e70cc0c156a0ae52af81cf5540768320cf5f27e569c150c640d0ad2b9384f62b3a26b2a3505391737398186903555e9795be6fe30fe03a9f20fedde996c1b830d1d0ed644dd7c5f841d014093c692a1bba471ed95dca5b1de5e525773eaa081b0084188d21e984936f769b7ce7f0aa52e072b70409540a26711b310cc68f5beda089978b2814359e014be89d247dabce608291d47a09d8733d48b3812079bfe057e5189bc93d9cccbaca9396d7db93e9505a45f0662506769332e19d40143f542dafaa4fa7b724cf430309549b2d5637dd9ae554f94a20774bcf544d2d98314e3f4983cf2ec4b95276993328e647d12a5cc0721dfee85805a06c497e2400b3ede8f91508e17b2cdd1e80b24558efaebc15b75d31cf20df5b4b2fdb9a221de394d830ef03ff9e53d5ee7d18edf36e10bad89c772662f3909d6ba5cec338a6687048a2edefeb3876ba5120d4d10519c7b4cdabf8f9de93665ea77121ead63befc2094dbc35b1fd86ed4a6f36cf9aac826edab700302a917499837fc18bdb2df2d176b81d881e83eaa0973cfd703c3e12430da23c5b93ce6f03291bd09f741b36fa2a304d8aede74a40269b2c0b94ea682cb24e98d68b0b98996038fa9b1dfc86300e7071175e173a16a4a3921597edc8333f23d14990ea9ed73228df5f6d7d8647d029423926bcc04ecfceabae1d3bbfbe88a0109311a1ec614114748003dc235509cca6ec5d6bd743c31d476c9b7a0626c607e8442a3dca9b94ee3ebee32c0b5586ae8c6c516ddef1633cee5fcb7c27be6accbff8a41400165b0e29463b56eb5b10b27fe12016cdccefd026c287466c8a3c31342a93b88b94ca87ec297acb4a331d6ee0f5b946dcf821b5cf138b1973aaf13df5eb966f6f5d9abe2424d18c889de6b588ed12d77ff2e45112aff89e079a48c272bb5b7239bd0d8a0c8eaff98781c809bccf19d9b2595ac6944e3b229be14a64c291eb8306ff4422ab18ec48c375a846b938d04468b49471c628b7a1ce1884836d62c128bce15e54d25d92187ec43e2ba662861309fe4665c7aa2a77ed1b0e94efbdee3ce3abf7f31afcd7ba8b1835c7acf45444cf78fac977dd41c2e410d5ce2796d9333f995d6367d029f285877e2c0058c6d3f969ad40aa8eacc062b1fbbd64ba6c85ac2473b7f314c23486c3e51b6a5d7c2eb71bb745965a4aa6c24d9342c8d1b5dcb95e8b9e2e297fb7c0b3bf4d3371d4adb6b09eb7c4d51074b626580517488d163c9182c7100ad3c0a5d14117cb5b7ea699cdcbec797859673f1d61caadb9cb19673e261dc592d89c65bbc466040025417f7a9f327d35f67fb90b210a3b9d32b7aea6ea8b476e74d6aa6bb41a536b5590a3663f145db28a26edff5aefd54c672a8a75da9b88b5121afcfa20961eb197a6a989bf999441bd73f61f1f732ea5f205091c9f196d32c732f5055a0d7ea523b4c76f4ce751f59abc438f6c4640ba2aea4ae7692060f353f9686ea2d7f6f93f3dfbdbfcfd44968d905415de8f8c354fa6ee28f1d57e6f1bca94b5d536b3e7c37154113093c841468f57e6de4f3395c6a70c322b353bed0b1430998ac177b1bc382981203463dd31fbd0e7fddb0190a88df387b58edf6d4116da83da5d502bb76f12e5ea4c807b7b1e5853027fd5382bc2bcf785fc0e0811996f6634aa8608b3847c1e4a7129b81020eca903f67b49ae3a707428a838d816364a8d1f02bf4f100b1998543a68f4c6ec66c9792916ede963d5c6e5737425ee418c06f08aa5f1ccb210ee29371", "0", "9cf6e68976326c84e58a28dd0f8a12f3f66b8ae1859e2b80795bce5579cdf7893d173cda69aaebd8ae32bf0b6676b9556550e7729054f6c86f904e1f5d69a98d139a9134631ac6f1f5f4ae413608c560af5aa875ebf80f5ce3ddb9475503e44f451bfbd9c5438cbbaa65ba1acb2220cbd563d750bc45bd0b6e71ed4b728cf4d6923806e604f23cea089b7fa62fb3000ae2d4a27e8f97d5255bceb80c63440708deddee87f3a928bd3986f56e6261ae72bbdea2efe8c3c524ca0d88bac6c27e4cedf9ecd204d471198230272b521ad8fe3da6e42acbf1310cfb5d5b00c3d9c7c6bb683cf75e96b1b03c63bdd550dabe227bb35a6eee71fc5d3c5bedd38ba0746bcfed6d5090e956a6ce5c43e2e75ebd1bd877533576e048d7dee1d8cad24c80c47ec2ede5c5528be8e503e4df2d38ec8df515297510af905036a1286ef42a4e8bfa15284fca86a2d494b123adf5ab38a3086665aaca0bbf15bb14afb146c6b7fdb3d0c951ef4c4fa80b4e30c73d576ab1e689bfca5a5fccd123699b37850e3348506b1f6d381d65df22941ac9dba7c71b661d5eaaba0a7e0e32ce18e039a4e9282de90589e29934d345fc3fb37edd6addfd027495cefdca8deda65f05d5b8d5bbac4c299897f3073e9a964ab3000f246c150010a71b9b0e70414c0c6bc754bdc961199ed9c5530733d7555f8b3cbb9e0167bd53897c035aadc80be3404d874bd75ab882d1e3e70010eca1886fe86625eb4ce6409321c5d298a8af642cb2deb9d9f615f5e45a9b692374de01e738b48ca354c83a3552a03da91a9efb2a7d370cf435b2576e1549ea3148a28e14cbdc7ec933150fadbe461e3adeb4019719a76a1524c0f5ee2cfd940bd3d71deb9ca23053d273c749c4b7983146da39de8bfdfa4cc288b852ae76f1cfbc4402ae03cc1b35e538700ed41fbb66300feffad5d471151ddf0ee8a190f5cfafba7f6644a31b678e63947c1f6ac88f378627065eb59ffbdb7c6098e6b5fb9f3080c245a200fceb47e46874b2c180f50e9136ffef631cc163d7f5fe4c2b47912d24e50a00ef", .Okay}, + {.Shl, "-ab04068b1b21c08b2dcb8f5766d1c6edcf2ddee33c5e9fc97052578a50042312c77f167ce389e09b7470bdd654f3504155343ed4432cfc78b70fdb169dc3df3790f67ee71b3d4b5f7558b21d7999931b0f397e3d923bdcdb74749e9e59f2e4b55c7881fede5422635142edfd62e70ab0c59912602970a44eedebd209ed1aff3a483efbeed7f1772d820a54c2887500da0f3228c5c29ac618c937d2234dddc1edd4cd89415ee250ef3f16756fb040b7343259a2a626f1e93385609afb326d9c103e3e16733a5c6e5388ad7554243cb9f1103ccefb5e9df3bd4e893faa7b0f2d9ec426cf9cb6cf710a1e52db933fe314cde8dc073efce24d8aef84be7ed853d0ed6dea6a73986eb36df079cf6998790dedbb0ba62cb4f3d7fd424ff1361547c21a556560411a7c614a6d072b635edc942f161c83a7cb535052e64b2758adb7cbb2a1fc55b581915282622042b88731305e71f43c0ececcd2b2a91e00a049d41b9175612434b702447a4da600e1050491077d10b597a7907d3199addb3ae1805c7d247c3c2f6b3f7660c2dea05d3845a9912f763ed777cd683156da3725c36102f87b5a07b6705baa55535e409b4a785cb6aa5a26b6a5a45de7eef31b9398e4e720d85ba5dc1218e90946c3ce8f6e6b5b73c1cc73c246fb92047661a8f18a59b54ed5575d941f871472e5656818c18c6b31023c7391428864c7efaa27f972782fe8885984bf915a1314abc9849627d619e19654f2a0a835b4531de476eebacac809f038541d37ca653fb6497b56d5784ea65cd9e3df3c7b909adfcf8d02579c942794e8dcfffffe5ca8c3a2090defea99241b73a70cad39af63558b16f9214b69ca1660d2134ec8950155fafe7c9e24fcf39f0f71d7c0f34b11aa5ea201bcd325c3564e49a77c688c475f6054b48e8b46395bce00964411be5e589ae77de021d2d7ae954b7569cf1725d26a086c9ece6a5cd3b72b3648b6761f9bd02506771f701ceac70699bf0fd75346f37c4b05e8a23a9a479d711254879e9a475209270ffedc8657a297e4f77afb477995efac27c2c2f5c89cb61d9eac848b6f4482b250c3e30815a91a1586dc8dfac82f78274482f24b3c2c15c13218cadb034dc588c4ac2033b074669dca3ba63deb2b6e5e7302047ccbe83dc2614e207e9edf2b5a8235c185a5f42f34ab5b72bf2e4469de4a475ce508afadf207a772cf87c26d936486a561073f3a38d1bb4c41aa4ea0877af339eca1df9a8c6c266579a05cfcbcc9046429177fe7f8c916170338100f278a0cc33c143a1e0b1551752ff4dca216877464b94b0201115a640f826e8232c3c1623ef9aa9d4af1ec02053e5f8a03a01d5baa4515c7911e490720c3980c3eb1a1dde5db9912f7e8ca21a94dd6b7365056cfe2dd053341e3c7fe747ae875a87b0465aa327ec36461e38a9a1492a828da4ea0398ddf866242781f630b4486bb7fc359ded74e5e2f236c2afbeda63b75c576ac049693290f66555b79953a1265d8c4e243de7ba02f837bb0c5a022c4be915bd1a90b5ecbdf8d3b4a6f3935bda94b9f3ec4e9ec41389f1a66f787faf1d7c824911d1302741fd4aabab170a1c45bc13478c36f1fcbfef01a42c4703cfecd1020c47c3f0eb53c25b6d0ed8e5eb238e2dc53ab8ce5106809bd6dbbee9c83a68523261d5b8906c218da937f9035faa203a7a778373eee3f92e286f56029839f14d029f9838555458964e44e39bc122d93b89c023e6488e8d2d407187b5435f4f0b9bb97994f0a8c85c5e21a394c02425f4576456f0ed7cd5c411f4b5359819de937c225246236b523049f7b8949046e0baa7ab7d5744a6ce4433ebdc61bf4f6a9b5e8429e8de10cbed556805b26d3cf7229ddeee2ef81e0d0caf192a59b54c19cf8030cca9664fa24b8553a006ef277b87dc36bb0a542cee18b5514aca38fe1171de774286b9426223a6261a3ea5c01cc61cd5a1d5bbd1f8b47809c15bda2628155fd85aa19cefb0a6f497b7a9155b6f277ff559082e32b89207e5476d5c61c7d02b2454bad7307efa5a4524d2ace475b01f83ed246d63963b9dd2c3c22447361cf04f7756013f51266da45f4f8c716a2c43d2dfb8e9b35884d7a8639430a6d", "168", "-ab04068b1b21c08b2dcb8f5766d1c6edcf2ddee33c5e9fc97052578a50042312c77f167ce389e09b7470bdd654f3504155343ed4432cfc78b70fdb169dc3df3790f67ee71b3d4b5f7558b21d7999931b0f397e3d923bdcdb74749e9e59f2e4b55c7881fede5422635142edfd62e70ab0c59912602970a44eedebd209ed1aff3a483efbeed7f1772d820a54c2887500da0f3228c5c29ac618c937d2234dddc1edd4cd89415ee250ef3f16756fb040b7343259a2a626f1e93385609afb326d9c103e3e16733a5c6e5388ad7554243cb9f1103ccefb5e9df3bd4e893faa7b0f2d9ec426cf9cb6cf710a1e52db933fe314cde8dc073efce24d8aef84be7ed853d0ed6dea6a73986eb36df079cf6998790dedbb0ba62cb4f3d7fd424ff1361547c21a556560411a7c614a6d072b635edc942f161c83a7cb535052e64b2758adb7cbb2a1fc55b581915282622042b88731305e71f43c0ececcd2b2a91e00a049d41b9175612434b702447a4da600e1050491077d10b597a7907d3199addb3ae1805c7d247c3c2f6b3f7660c2dea05d3845a9912f763ed777cd683156da3725c36102f87b5a07b6705baa55535e409b4a785cb6aa5a26b6a5a45de7eef31b9398e4e720d85ba5dc1218e90946c3ce8f6e6b5b73c1cc73c246fb92047661a8f18a59b54ed5575d941f871472e5656818c18c6b31023c7391428864c7efaa27f972782fe8885984bf915a1314abc9849627d619e19654f2a0a835b4531de476eebacac809f038541d37ca653fb6497b56d5784ea65cd9e3df3c7b909adfcf8d02579c942794e8dcfffffe5ca8c3a2090defea99241b73a70cad39af63558b16f9214b69ca1660d2134ec8950155fafe7c9e24fcf39f0f71d7c0f34b11aa5ea201bcd325c3564e49a77c688c475f6054b48e8b46395bce00964411be5e589ae77de021d2d7ae954b7569cf1725d26a086c9ece6a5cd3b72b3648b6761f9bd02506771f701ceac70699bf0fd75346f37c4b05e8a23a9a479d711254879e9a475209270ffedc8657a297e4f77afb477995efac27c2c2f5c89cb61d9eac848b6f4482b250c3e30815a91a1586dc8dfac82f78274482f24b3c2c15c13218cadb034dc588c4ac2033b074669dca3ba63deb2b6e5e7302047ccbe83dc2614e207e9edf2b5a8235c185a5f42f34ab5b72bf2e4469de4a475ce508afadf207a772cf87c26d936486a561073f3a38d1bb4c41aa4ea0877af339eca1df9a8c6c266579a05cfcbcc9046429177fe7f8c916170338100f278a0cc33c143a1e0b1551752ff4dca216877464b94b0201115a640f826e8232c3c1623ef9aa9d4af1ec02053e5f8a03a01d5baa4515c7911e490720c3980c3eb1a1dde5db9912f7e8ca21a94dd6b7365056cfe2dd053341e3c7fe747ae875a87b0465aa327ec36461e38a9a1492a828da4ea0398ddf866242781f630b4486bb7fc359ded74e5e2f236c2afbeda63b75c576ac049693290f66555b79953a1265d8c4e243de7ba02f837bb0c5a022c4be915bd1a90b5ecbdf8d3b4a6f3935bda94b9f3ec4e9ec41389f1a66f787faf1d7c824911d1302741fd4aabab170a1c45bc13478c36f1fcbfef01a42c4703cfecd1020c47c3f0eb53c25b6d0ed8e5eb238e2dc53ab8ce5106809bd6dbbee9c83a68523261d5b8906c218da937f9035faa203a7a778373eee3f92e286f56029839f14d029f9838555458964e44e39bc122d93b89c023e6488e8d2d407187b5435f4f0b9bb97994f0a8c85c5e21a394c02425f4576456f0ed7cd5c411f4b5359819de937c225246236b523049f7b8949046e0baa7ab7d5744a6ce4433ebdc61bf4f6a9b5e8429e8de10cbed556805b26d3cf7229ddeee2ef81e0d0caf192a59b54c19cf8030cca9664fa24b8553a006ef277b87dc36bb0a542cee18b5514aca38fe1171de774286b9426223a6261a3ea5c01cc61cd5a1d5bbd1f8b47809c15bda2628155fd85aa19cefb0a6f497b7a9155b6f277ff559082e32b89207e5476d5c61c7d02b2454bad7307efa5a4524d2ace475b01f83ed246d63963b9dd2c3c22447361cf04f7756013f51266da45f4f8c716a2c43d2dfb8e9b35884d7a8639430a6d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "c71f16c06840abd28563e67c3a345e9796afdb2ff1d85819cb23eef36fbaa60a335fdaa0e95013e43f600d422f87572886d6526e46452b8b6cbe7b101e3c5f8facee518d19e5bc9bb2722d42de54b8c9e1466fb3e6062abb1a0d23d466777a35fceaf3d543537d6cf5249d4696be1d2fefa6764c7e37591b48880f4ade85c9f77b951603961a4573fbcd67a7e2b32d019d021bbfd5bc84bcf673df2f1c78f7291de35f6b9ee4554e096a28a3d12ce3e4944be4a83c7a153d6fbc063d01edd87f79d72ab5da401d286268dca7941ba45b7e442e5581b31b535d0fa57eb9f4496f180d90618f74a79c6fa59f7e25082995a1016bcbeb26fbb29db5900d9169abd369cd5dfaaf447a24240530de4c2ee7db7536cbfba3272baeab5dfdaa593a9413f58e6caa291c36f0bbfacdbd85b4891bbea8ae25b39a760d9e596a500145afaf9f784fddb1ab260d6056df4748a6462489e4063de5ab4f79b26610ed040f304f4cddbccec31cf1a701b8dfb263a5d2f1da9c55db04e858bd26e756940ebdb14b7576025209f540eb56e9adfdc2dac2df0d10ce4746acf57db53ddb2c1587b9ab5ba4f59f35fce763403044b88ec37ce47f5f2ca0afc1fd62cb5b390db01a90edd7b5ee22bed0f9f32e40a90dd2c1d468ca69c757f13349515225d2be9b7219466d0fd37c48b839161eee22e4ebae29b0c3437b384036da0c981db9a63331e95fa8ebf952b8db500b20c0e2a93eceac74c70f996bdce3e3e9f602971ec2d5277d2bc3ef7926555af312075bd908f0fad4aa96c27c2839bc946ec6d461947a507c057f2142df50bd3e9c3d340b871f80ca2de8d87d3cbfe4a4c9aa01044ea53203016d225b13586f5c413188630cc04c4818e851d071a3ec36e2f41a640c858ae8600c1f17a65bb7cada01053996a89ffa9b5cca4b32bb67d7307e11157d96e3a8c45f8ce48e058b14d24b296431e5e6cffdffb60debe8cea8872a718be73561bd3de58c0afe6c3ffa972b22209986c7e2c29610b6f3d76f68be2573a4641b992570393265d8df74c9a656806d54ec8c8977ed5f16f0098e30bb1d2f854787a97262e9717f40efcccfb55fe8714d0dfa7aa856b14bef910188ff9d97caf4b1d53f1f567414d9b34ae032e478f2ab14a05912a0cb1bade53d9563fa280433031164b9fe3bd7d2a771845e380abefb9d83442381b0d1b67de7e9f7d74993b2fd4eeb1b1819fb96466bbaeca68fb1699d5d722dc5edb3bfe061f5d4150e209e9712e274c21eb61fec83ef0abb6646c97d8035f432a8473a4006b195741ecfc55662502d5dab18c1ae85d325c72dc75cfeb6b0c4d0bfdd8e1f57948fdc087b007a976309a730a12e10c8375ed08c84d9232ba8e1a511e6b5567c9539aa241e0e570256798f5a7614c504f569f62e41a9622e60651b4d4ae28e28fb544637f8cd2cf7b4f4d6409fb67c31c9142d12256b4e42bf298f6058404de7fe19f6c384a2d2f66132aa013e19d29005bd0bc7bfb69bc7e5bff8711abffc0dd117a959095853ddfccd059c4a12b90ffbc28b95b65c40e4e113b350f8ec72d032c85ab626968d759991c0c0a82ef79db964be022df458c7ed8249b5636fa80310c172671f828ef519049f3b9e6c772b7d4ebdfe3e1ea89688051f938f624632c33a391f32146ba1eaf60ad5d32a04bbc25edd96267c7e5422a391fc190974bcd1b58533cb574cfde428c17e08c645ea6fa9460e20efacd42a3f40f293705cd76e039f46dfa070007dbd89d48b944010605224067cd53ae9dcfc993f449895b546899dfd7ab90c9b2f149dbde708e23d371ac685b6511a9aaf26b651be51e1253a5a021312ded5acae4aff62b13b7d482b191ce7e381d75ff5eec9d835ea59e1889319e6f53c106b79b4984ec5d93fd50a7540c21bc7da17f66d4678ba9208b50cdf26d3255e9cde2dfb39e3d8ab5508092a63e74a95193bdaba37682d57cbce3dc88fd91f3d1cd91823d3ea6ac99ec859d8f967b6e7be6390034ccbea1eeb0f482c099dd7dc032564250efabc92ca61ee2e7aa1a6d7ba1e477a2ba6385c622609f67dd275e640460a57853b71b13c0c674b7527b30975b979593a4508e7a512ef39239fac", "b4", "c71f16c06840abd28563e67c3a345e9796afdb2ff1d85819cb23eef36fbaa60a335fdaa0e95013e43f600d422f87572886d6526e46452b8b6cbe7b101e3c5f8facee518d19e5bc9bb2722d42de54b8c9e1466fb3e6062abb1a0d23d466777a35fceaf3d543537d6cf5249d4696be1d2fefa6764c7e37591b48880f4ade85c9f77b951603961a4573fbcd67a7e2b32d019d021bbfd5bc84bcf673df2f1c78f7291de35f6b9ee4554e096a28a3d12ce3e4944be4a83c7a153d6fbc063d01edd87f79d72ab5da401d286268dca7941ba45b7e442e5581b31b535d0fa57eb9f4496f180d90618f74a79c6fa59f7e25082995a1016bcbeb26fbb29db5900d9169abd369cd5dfaaf447a24240530de4c2ee7db7536cbfba3272baeab5dfdaa593a9413f58e6caa291c36f0bbfacdbd85b4891bbea8ae25b39a760d9e596a500145afaf9f784fddb1ab260d6056df4748a6462489e4063de5ab4f79b26610ed040f304f4cddbccec31cf1a701b8dfb263a5d2f1da9c55db04e858bd26e756940ebdb14b7576025209f540eb56e9adfdc2dac2df0d10ce4746acf57db53ddb2c1587b9ab5ba4f59f35fce763403044b88ec37ce47f5f2ca0afc1fd62cb5b390db01a90edd7b5ee22bed0f9f32e40a90dd2c1d468ca69c757f13349515225d2be9b7219466d0fd37c48b839161eee22e4ebae29b0c3437b384036da0c981db9a63331e95fa8ebf952b8db500b20c0e2a93eceac74c70f996bdce3e3e9f602971ec2d5277d2bc3ef7926555af312075bd908f0fad4aa96c27c2839bc946ec6d461947a507c057f2142df50bd3e9c3d340b871f80ca2de8d87d3cbfe4a4c9aa01044ea53203016d225b13586f5c413188630cc04c4818e851d071a3ec36e2f41a640c858ae8600c1f17a65bb7cada01053996a89ffa9b5cca4b32bb67d7307e11157d96e3a8c45f8ce48e058b14d24b296431e5e6cffdffb60debe8cea8872a718be73561bd3de58c0afe6c3ffa972b22209986c7e2c29610b6f3d76f68be2573a4641b992570393265d8df74c9a656806d54ec8c8977ed5f16f0098e30bb1d2f854787a97262e9717f40efcccfb55fe8714d0dfa7aa856b14bef910188ff9d97caf4b1d53f1f567414d9b34ae032e478f2ab14a05912a0cb1bade53d9563fa280433031164b9fe3bd7d2a771845e380abefb9d83442381b0d1b67de7e9f7d74993b2fd4eeb1b1819fb96466bbaeca68fb1699d5d722dc5edb3bfe061f5d4150e209e9712e274c21eb61fec83ef0abb6646c97d8035f432a8473a4006b195741ecfc55662502d5dab18c1ae85d325c72dc75cfeb6b0c4d0bfdd8e1f57948fdc087b007a976309a730a12e10c8375ed08c84d9232ba8e1a511e6b5567c9539aa241e0e570256798f5a7614c504f569f62e41a9622e60651b4d4ae28e28fb544637f8cd2cf7b4f4d6409fb67c31c9142d12256b4e42bf298f6058404de7fe19f6c384a2d2f66132aa013e19d29005bd0bc7bfb69bc7e5bff8711abffc0dd117a959095853ddfccd059c4a12b90ffbc28b95b65c40e4e113b350f8ec72d032c85ab626968d759991c0c0a82ef79db964be022df458c7ed8249b5636fa80310c172671f828ef519049f3b9e6c772b7d4ebdfe3e1ea89688051f938f624632c33a391f32146ba1eaf60ad5d32a04bbc25edd96267c7e5422a391fc190974bcd1b58533cb574cfde428c17e08c645ea6fa9460e20efacd42a3f40f293705cd76e039f46dfa070007dbd89d48b944010605224067cd53ae9dcfc993f449895b546899dfd7ab90c9b2f149dbde708e23d371ac685b6511a9aaf26b651be51e1253a5a021312ded5acae4aff62b13b7d482b191ce7e381d75ff5eec9d835ea59e1889319e6f53c106b79b4984ec5d93fd50a7540c21bc7da17f66d4678ba9208b50cdf26d3255e9cde2dfb39e3d8ab5508092a63e74a95193bdaba37682d57cbce3dc88fd91f3d1cd91823d3ea6ac99ec859d8f967b6e7be6390034ccbea1eeb0f482c099dd7dc032564250efabc92ca61ee2e7aa1a6d7ba1e477a2ba6385c622609f67dd275e640460a57853b71b13c0c674b7527b30975b979593a4508e7a512ef39239fac000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-5828305117ea024d01680e37bf664a7e0e430ebe42d365abf69a222bf4e6b5e16374fab2fa27058928e4a71ed5cf258a047a7871daf42dccfec7d9414b67b0b58477c64fafa3f9a41dd315082d546efb5c0737d74ea843fcb074b98f5c14526daad414f17540bfa77e3699318e2f27df71b8b5852dcae0323b160c6c85d934ee7bd1e1241a14ead2efdb654ae03a1ecf551c78d83fc23d1cc7675cd922e0031eb69450e9d2a80369b1e7f0c23a167c6e05de0b1e6069b2887e6ba8011414f6d5967295e6a9aa7ea46a3dd5fb4271e82dc0ca6f9d690ee7cbde2fe606b41ddc6d4d6b4d396d3123a6c6c73ac568c26a79aa5ef0150fbba5c2c8ba4c63a20bc2848888c9896083c5531de24b162b1abeabd93c71097ef00ed1439182a0273db937592265eb0b5f559db7193be104818847092f491dd5b9a8ea09ad0af12b9ade1d478baf3e09417ead5b128516c457e5a6d2a57168666e349c6d0c0876934244973468dc074af70f735375e7cf246ca8447a47b761b3f14851b03a3c185727c869e7d9a383561258d866f0a2dbd7379b171dcd3cef61b129cca565f1d4e90748d382cf506a2d95c274dc59bfaa93501affa923f7fdd4d13d2e1d8ecaa436bd8380c6a454e09a303573163316d1c755461724c6588a4973abde9d229f6c9153e44a654e5c2649979608d0c2e0939d848c7764e4cecc406e166a6dbf0429be20a0f245f6eb05a0f14f222eeb39fd91e4628f0c23b9baaf8872a52fd12233c2144faccde3b8ad9466c4125ad09b0ef9e86a3135a40276b68274f3930f2bb85b2f8d0017d6045015041399f1e1dfd6d8240ce83c9e8cccc463eb984ab039e6615bd17b41b8a8af481d83e5ce634f74d678d80482fc4dd7625c1f9c7e46e4d491f566aa743921732b9d5169619c082d62b27c8a7f6efa7f573e6331802b004614bbee5039de88dc7fb9ad5cbec38bf96c34cf15490c7aa6f6e204940d93475ba5c769f36278506c5424e3d4e4c5995bffdf79324ae3cf384944fe25d61c79603308019cae40d5551a99a50920d98c9c2381264bf72ba29fe3deb20027d0e10b43a13eda82a9acd0e74fd3f5973ab31e8953a358b73761d3e77772a38a294a3e683e2f1c8503b8d3db0739d213247c7bd191156e9f60cd11eb3ba356169dc97593f199cd5f4c6b45672811fa41dce9c80d080d6eb7e369ad0c465b9689f4a0bc13a26652844b7d458c2a72d0f6e052829fc0aac0fe2a27fa504901b7323f2f51513d4b0fb42f2eb649c8f0dc0df66fb325d6fd236e354388f1a79d31b243586842a772e0778dab5d02af70de158e03ec1c947bacebd2b4056f3fcdc2d4ef5a44d2dada4eee157f3ca8a4e4890b898c3c95d565579cc362add295014ac21c0602b518c65945ed023e2ccbd871ae986a83e83863fdd197c8985bfe5fab5b3b22fad7775b2efa234180d1df3bab9b3c3977869f9d55ba54a6a1b8438bb9043f431cabaac30e4804b31eb7c891a0b05880a6bbc9dd28342d12f0bbb5a8f9cd7cd1f35716854c9f00b5725a379fe244deec3b9f83f352540784556608a19489d38ff4c643920fef3348e789089bebf02a8cc6ddb15c99aa50766ce4f959985a734d166dcd473cb780dcc373025ac237adc24d09a92d137e30798e44993c952386dc16adaafe6437bbcb610dc6346fe594a8fdf9025439d73c7dcb38f2bb90d43298231e7d211a2a6bf4f5132f3c82da7051a70865675ad23f017b44f13216c6393e6500f6e9f26394fcc1a81d828f658defa7aa172678bd6b9f6e45d6da1f69cd3f7715b0201f6ee89a37063e53d888dbadbfe5673dd87f1f25bf1526e0cb1dc73887c5afacab467b48e1d7e575c9541e5faa471e8b3a33ffde2255648b9b16eb7efd000df0d9e4f36afcae6229beaf1d163309d5a41fb4c244dc875a08d93cd12d3f6b12a768c76bc1a0bbea5b66c524bddcade3db94899d2ca463617e2ffdc52ce2602ecfc2c6623bce0d57c328c6a3a6fc3bea966bc856b7ee5cdaf913272568351a5b9445b51f0bdbe6973cefc1c89119f44ebd3123192b101a96aceda9aaa8dad2a596276e4e670df1e9586c92270726edbaa346c301ee8e907a3ef96823e57c", "21c", "-5828305117ea024d01680e37bf664a7e0e430ebe42d365abf69a222bf4e6b5e16374fab2fa27058928e4a71ed5cf258a047a7871daf42dccfec7d9414b67b0b58477c64fafa3f9a41dd315082d546efb5c0737d74ea843fcb074b98f5c14526daad414f17540bfa77e3699318e2f27df71b8b5852dcae0323b160c6c85d934ee7bd1e1241a14ead2efdb654ae03a1ecf551c78d83fc23d1cc7675cd922e0031eb69450e9d2a80369b1e7f0c23a167c6e05de0b1e6069b2887e6ba8011414f6d5967295e6a9aa7ea46a3dd5fb4271e82dc0ca6f9d690ee7cbde2fe606b41ddc6d4d6b4d396d3123a6c6c73ac568c26a79aa5ef0150fbba5c2c8ba4c63a20bc2848888c9896083c5531de24b162b1abeabd93c71097ef00ed1439182a0273db937592265eb0b5f559db7193be104818847092f491dd5b9a8ea09ad0af12b9ade1d478baf3e09417ead5b128516c457e5a6d2a57168666e349c6d0c0876934244973468dc074af70f735375e7cf246ca8447a47b761b3f14851b03a3c185727c869e7d9a383561258d866f0a2dbd7379b171dcd3cef61b129cca565f1d4e90748d382cf506a2d95c274dc59bfaa93501affa923f7fdd4d13d2e1d8ecaa436bd8380c6a454e09a303573163316d1c755461724c6588a4973abde9d229f6c9153e44a654e5c2649979608d0c2e0939d848c7764e4cecc406e166a6dbf0429be20a0f245f6eb05a0f14f222eeb39fd91e4628f0c23b9baaf8872a52fd12233c2144faccde3b8ad9466c4125ad09b0ef9e86a3135a40276b68274f3930f2bb85b2f8d0017d6045015041399f1e1dfd6d8240ce83c9e8cccc463eb984ab039e6615bd17b41b8a8af481d83e5ce634f74d678d80482fc4dd7625c1f9c7e46e4d491f566aa743921732b9d5169619c082d62b27c8a7f6efa7f573e6331802b004614bbee5039de88dc7fb9ad5cbec38bf96c34cf15490c7aa6f6e204940d93475ba5c769f36278506c5424e3d4e4c5995bffdf79324ae3cf384944fe25d61c79603308019cae40d5551a99a50920d98c9c2381264bf72ba29fe3deb20027d0e10b43a13eda82a9acd0e74fd3f5973ab31e8953a358b73761d3e77772a38a294a3e683e2f1c8503b8d3db0739d213247c7bd191156e9f60cd11eb3ba356169dc97593f199cd5f4c6b45672811fa41dce9c80d080d6eb7e369ad0c465b9689f4a0bc13a26652844b7d458c2a72d0f6e052829fc0aac0fe2a27fa504901b7323f2f51513d4b0fb42f2eb649c8f0dc0df66fb325d6fd236e354388f1a79d31b243586842a772e0778dab5d02af70de158e03ec1c947bacebd2b4056f3fcdc2d4ef5a44d2dada4eee157f3ca8a4e4890b898c3c95d565579cc362add295014ac21c0602b518c65945ed023e2ccbd871ae986a83e83863fdd197c8985bfe5fab5b3b22fad7775b2efa234180d1df3bab9b3c3977869f9d55ba54a6a1b8438bb9043f431cabaac30e4804b31eb7c891a0b05880a6bbc9dd28342d12f0bbb5a8f9cd7cd1f35716854c9f00b5725a379fe244deec3b9f83f352540784556608a19489d38ff4c643920fef3348e789089bebf02a8cc6ddb15c99aa50766ce4f959985a734d166dcd473cb780dcc373025ac237adc24d09a92d137e30798e44993c952386dc16adaafe6437bbcb610dc6346fe594a8fdf9025439d73c7dcb38f2bb90d43298231e7d211a2a6bf4f5132f3c82da7051a70865675ad23f017b44f13216c6393e6500f6e9f26394fcc1a81d828f658defa7aa172678bd6b9f6e45d6da1f69cd3f7715b0201f6ee89a37063e53d888dbadbfe5673dd87f1f25bf1526e0cb1dc73887c5afacab467b48e1d7e575c9541e5faa471e8b3a33ffde2255648b9b16eb7efd000df0d9e4f36afcae6229beaf1d163309d5a41fb4c244dc875a08d93cd12d3f6b12a768c76bc1a0bbea5b66c524bddcade3db94899d2ca463617e2ffdc52ce2602ecfc2c6623bce0d57c328c6a3a6fc3bea966bc856b7ee5cdaf913272568351a5b9445b51f0bdbe6973cefc1c89119f44ebd3123192b101a96aceda9aaa8dad2a596276e4e670df1e9586c92270726edbaa346c301ee8e907a3ef96823e57c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "16fcfacddfdc335e161fdf86168d032d6bf86c3f5b95e32c3a8fabe02139bcc3ca713d4dd61cb2271f696ff914d1353cf86f52bd9983e34bfc4c7e31ba288c63f259f8d84982126f2dc1d8299d589c3951db8480886a9276a6e8f3d1766b230b35cc0403e9cd7b6dfa1710b2949d45bf8adc078bfebfbf28f519adc93890fded174e65e9f28bb1dd2d66cf0576134943119e263bc79e227b87edea360a3b3f985f68c687fd78f2cec45975035f7bf9fc791cdfc3e032c3ab43aa31f3b932b6f246ca4c0e57888225d2705fc3fd0f5ca17bec71bf04b9962661f2e250266eeb78fd113a4f8178b8885b13bdd2930ff2bec9744f3b15831a1285e3a5f4d714546105e80a8fb89086b7918506996ba06f557f120410d5f0f63da9f3372a41648764c9f3b2561135bd9c942b911eae280e984f708723774052a6e035d3761ffc5b4baf9c5ae64e0ae0badbbf4d4035e47bd2bf65120aafda2d001f0681fd0cd11e9e8a4ac48a5201810d7d117492386095ced568237201246aa30543f95806ab031ae3eb265b3fa2f749c033528d32b9aa6c3f0d1e527b96b0088b9f62241c49f83c0812ff16d655438d91c35ec3e6d937e85c442dbb285df24520d95a4e94c0866f269a9a4e2a9553fcd2b4f8a8c60b9e41d8272369da3a7841c2ee2d262588e48e730f9b4c95d923436b63141c4c96ec16c2c433639bbf0afe93ca24eed69d4294ac35b5179d60d0132a2b9a14376dc12c097bf27f48a9c7e661126f37140571997a5e3ce6a1de9e1330974728631d3de410a3c4bdef251e044406a8cfe3b23b018feaebbe88c4a9b3252520390ea3e758bec834f0efc9a6173ad2703b7b095311995fff8b10bfa12d0fbf5a79cd63587aee10af2531a1cb57dd5cd4009d7a6550cf91a388f1da4179d5a497e41251d522e98c9d02b20b0c7347d16c8ef9608e7e8f524686eb18ea72e848793c9b81ad2681f6d74e402a50887d38f945b912ec1484385083e5210f4429c8ed5453ee3d20b0fbaff0b5799392412ffa33e68f7d27f851df00ef277b8d8bf3c17db18a1e53da3a38a4b7beecd78363748e015a0549627277b480105c15ec9ea41d07ad7c13e869fd962e356db3ad2a04ecd09f73559f5aa3ce8e4cb14f45e14a3b9ead5dd0a8bf589ed37f47ebf41b24b656ed95e98107f0c410ce7d7da0d098551b52d1995fb71f85244bfbd112d5c9aecbf83355889cf173715751a2cf7f224cca0551f10af1fa8d1ee0b39662c125343795a41b3e880ff18758b54d9fe3113ff0b12dc185f1e3ca55f57dbc0301d3d5f246fbe955b29a75cb45acb25b2819d137af026f3a4ceb12b467ed95567c882850a59b6111571ae356f56eb1e6af7b6c36a3f249897609fe7e1eed2fb9e0973fffea13a4de5758c14ef6609ecf7768a2803a20bad8624882080c42341382670da35fe7ff2e3f10c97084c66fdb28f3bdb046ad54ca8167c8c673e7a7993cf4b67379020ade8e5db32d1f571d68469558a447acd21b679efe8b8575941d2d9a636c0d13b9400e43eaf9c87ff2f938ed717ab8874d8d61c04384318f957c6f2e123ed1cbb53df151fffe2715927d180318f083220c83d4173d5efe659f75c5c50720917b844a56315e768f2acdefe2067b9498540dea450bc6f4b5b1498c36a2af8cd23cb49eff78d77977415953f452c3f24b2fe80ad6ee66256589f40d0677d6e8a5ebd0419611b1d739cc648fa5377dac550c0eedc07671fb149ed21660d322a041b61942697278eadbd03789edd8b1021407d530e0df540a9c200aeb72be42f1677f8a2bd485ffbb566a85b92082ba4446c28d14ee9047405709c68e98ab4b7f7d6187198508f147597e36a30e2746dfa52b8fff567f987f2fc16cbb329fe4c0e2b01ee7f6b9e8755c845df0556f8467d478654d3d96978620bdf7433b35d5722a6a9a6644688dda4212fec6060711e8170762c3d5a968eff2c91f0f6b0b337e34e19c6e598d7cae01749beea7dc8248d19511fafeb008ff2468ba223a6a626d9b353150a45af6d228b9a7da71a8020dff8f88287c2c17819416d60cc31b9342ed0f7d75294cbb1cbf1b960c919131a3d51a800399a35238ad60720413289b", "78", "16fcfacddfdc335e161fdf86168d032d6bf86c3f5b95e32c3a8fabe02139bcc3ca713d4dd61cb2271f696ff914d1353cf86f52bd9983e34bfc4c7e31ba288c63f259f8d84982126f2dc1d8299d589c3951db8480886a9276a6e8f3d1766b230b35cc0403e9cd7b6dfa1710b2949d45bf8adc078bfebfbf28f519adc93890fded174e65e9f28bb1dd2d66cf0576134943119e263bc79e227b87edea360a3b3f985f68c687fd78f2cec45975035f7bf9fc791cdfc3e032c3ab43aa31f3b932b6f246ca4c0e57888225d2705fc3fd0f5ca17bec71bf04b9962661f2e250266eeb78fd113a4f8178b8885b13bdd2930ff2bec9744f3b15831a1285e3a5f4d714546105e80a8fb89086b7918506996ba06f557f120410d5f0f63da9f3372a41648764c9f3b2561135bd9c942b911eae280e984f708723774052a6e035d3761ffc5b4baf9c5ae64e0ae0badbbf4d4035e47bd2bf65120aafda2d001f0681fd0cd11e9e8a4ac48a5201810d7d117492386095ced568237201246aa30543f95806ab031ae3eb265b3fa2f749c033528d32b9aa6c3f0d1e527b96b0088b9f62241c49f83c0812ff16d655438d91c35ec3e6d937e85c442dbb285df24520d95a4e94c0866f269a9a4e2a9553fcd2b4f8a8c60b9e41d8272369da3a7841c2ee2d262588e48e730f9b4c95d923436b63141c4c96ec16c2c433639bbf0afe93ca24eed69d4294ac35b5179d60d0132a2b9a14376dc12c097bf27f48a9c7e661126f37140571997a5e3ce6a1de9e1330974728631d3de410a3c4bdef251e044406a8cfe3b23b018feaebbe88c4a9b3252520390ea3e758bec834f0efc9a6173ad2703b7b095311995fff8b10bfa12d0fbf5a79cd63587aee10af2531a1cb57dd5cd4009d7a6550cf91a388f1da4179d5a497e41251d522e98c9d02b20b0c7347d16c8ef9608e7e8f524686eb18ea72e848793c9b81ad2681f6d74e402a50887d38f945b912ec1484385083e5210f4429c8ed5453ee3d20b0fbaff0b5799392412ffa33e68f7d27f851df00ef277b8d8bf3c17db18a1e53da3a38a4b7beecd78363748e015a0549627277b480105c15ec9ea41d07ad7c13e869fd962e356db3ad2a04ecd09f73559f5aa3ce8e4cb14f45e14a3b9ead5dd0a8bf589ed37f47ebf41b24b656ed95e98107f0c410ce7d7da0d098551b52d1995fb71f85244bfbd112d5c9aecbf83355889cf173715751a2cf7f224cca0551f10af1fa8d1ee0b39662c125343795a41b3e880ff18758b54d9fe3113ff0b12dc185f1e3ca55f57dbc0301d3d5f246fbe955b29a75cb45acb25b2819d137af026f3a4ceb12b467ed95567c882850a59b6111571ae356f56eb1e6af7b6c36a3f249897609fe7e1eed2fb9e0973fffea13a4de5758c14ef6609ecf7768a2803a20bad8624882080c42341382670da35fe7ff2e3f10c97084c66fdb28f3bdb046ad54ca8167c8c673e7a7993cf4b67379020ade8e5db32d1f571d68469558a447acd21b679efe8b8575941d2d9a636c0d13b9400e43eaf9c87ff2f938ed717ab8874d8d61c04384318f957c6f2e123ed1cbb53df151fffe2715927d180318f083220c83d4173d5efe659f75c5c50720917b844a56315e768f2acdefe2067b9498540dea450bc6f4b5b1498c36a2af8cd23cb49eff78d77977415953f452c3f24b2fe80ad6ee66256589f40d0677d6e8a5ebd0419611b1d739cc648fa5377dac550c0eedc07671fb149ed21660d322a041b61942697278eadbd03789edd8b1021407d530e0df540a9c200aeb72be42f1677f8a2bd485ffbb566a85b92082ba4446c28d14ee9047405709c68e98ab4b7f7d6187198508f147597e36a30e2746dfa52b8fff567f987f2fc16cbb329fe4c0e2b01ee7f6b9e8755c845df0556f8467d478654d3d96978620bdf7433b35d5722a6a9a6644688dda4212fec6060711e8170762c3d5a968eff2c91f0f6b0b337e34e19c6e598d7cae01749beea7dc8248d19511fafeb008ff2468ba223a6a626d9b353150a45af6d228b9a7da71a8020dff8f88287c2c17819416d60cc31b9342ed0f7d75294cbb1cbf1b960c919131a3d51a800399a35238ad60720413289b000000000000000000000000000000", .Okay}, + {.Shl, "9c985b3c93915dc604fc3019cff4d0d1535bef94dcf85e95f535e730aabb8f22cd3607a341d65df110c5bdb0079f8ad8c36b4d47e742204b21de844f8319b065c9f8473ce7b473951378eedc8c545b236315027e5ae0e85ae2796677bbb15bc562ddd5ca05003852744688b91620d7f9af12261ab330b7f9c468d274523a682257e9156e2279ae53a7cff9014349580630abc9c00371434723cd56ff611fab96c9b3620d0a19d60ab047605c9e72a85d3aa55f79867aa5bf4dfeeea3809a0d461f8efd1addaeb0240cb7e73bae60c37a194e97ab77064137522f840e44976e9b7a79079e43aa310240f32598d4ba61a790bdd635733430a27726ad3068f3e5c7731114bd6e5f739d09c4e9c0979cc8984e037c50e3727c93055ffe51c76565f8850047a7f836e53ebd845fbcace4a05a7d03f148ad8283e6415993e5b038dcc3052eab3ebbc54ee0a95f06ca9e68342b984cfc2814aa8fc21e3e826eeb8eb36e38c68aab96ceba5dd02552f09f103a5e31b3ffd6b53ba05b19490fe5e5cadbf3702e85eeda2cfd2efa777b3fa197ec7734029386e8e7e1eb7f35c14c047d88833fcdde2f0b2f8447b53d75ecc64892f3e9dfe9e41d7ae838ef0ff39509e2cd93e99ae597f8567779a26406ffa7f7a56efde2695d32608c328112fee6c587dac7479bb68c1672e5f54778650670510242fd95b348994fb04ba1257ebcd2cb82ef4c3e71222ecb46e2f42764d6461ac81825b3c7734a8a8155fab9a63da8fc7d450216a8525cba10fad4fde4b1990a42d5822e05e60285d9c99c4cb388beaf0427fc146b00c5e64073bb56add0ac5f247a7fb34abcdda492b049c2486f80dd8d6a259f509a2a9508fa4fe50d7e3e66d0561b78b073ce1cd3b763e1445334c795ff5aba63e1d208babf2345e1baec5bf56837a6069959518c26a7fb376b2c9e2cee87c16fc2418b1551730a5e2a4fc99c0b2e539051b4fc17d4803cd98525535ea85ed21158d74e972d93427a1e8e27de2c9e048b0388646c5cefaa4a20c4b89b35cced0d60a5de89182cc5e8c5479ee0cdd96d154e96136de8078c3304ed8ca5f097751b132a075004a7bde121ae4714e0fdb16788dc489264634041056c3bbe73fadec05ba9e0b8daca32d2f483b3b2153088f249f7e371e1001ac7d72488e31da1a28ccfef46a833eb6fd743c22fe7d4a1ced93d223383945e76f0c66be2251e4a7ef1cc5d78283f9ad9fbe14d987a65e373ddc9c54a30e95fc7276fa7c82c55e1a3917ab93abf73487d0be85d31fa41cf86de1c567e14b3f5d8eab101b1bc7260c74f98120b689f51fdd0df8d3d471875df2196bdb90bd9b5cb7e65b1ebfb70fe9c63e964aefd5477e337c8815a276856dfbd1a26e82141828ccb6a867942577efbdd1c6ed6b1f32578fab06ef3a7b9275c2a8131068f04e1c718d61ebcd728a93486dc7563b1738931c9da5055a22e3dd88232baaae5282782e4dd51ea5f0b72df2ab7b7fb961df07f3993359f17ac229eaa81f34a1dc69a351f011b30a60b5a4909cdaf8b215d1664a2660a2c560a2bcd27a8efb95c467a293867f835371c27f47cf6ad6cfd4d9d8f0defc42d9ff0f77259292c0b0cdcfb3b7aebd59d2102240ab1fbe402beb8dee4ca45cc0dc294d2b08e89290c9769da4df4cb28c12551d8120c50f9c3a11168b81c895427dd375c58bca78255bd4a145a1a96d1e81283c68353a822e4d5b00a08281110a5dcb2cf4cd7d282d682e923659dff3ac4f0ec4b8ea42b85135562cc4ed3a9ad0b9fb1fd2846ed3b0334b0dcf1c1851d53eeb4424ca8a73ccc333a31ba724d7758c77769bb15026ff51587d6b3b2570b544943cb7ca866bf82b95a80b636a2fb268dbe4987c1fa088f75fe842730a05f9046593e264b5344c0ac8614c6fad15945c1de21a6d50f8f276770bd85d7f767b3468ca8a8b2e6a5c6a2a6b195710a8a05df9de7eddb942d5c1c9cca80bfc0ff8e14580b1cbb6329f219dea5e780bb126855666b5e1ad2820e3258436ceaf652b357791b05ad6fcbbc00522667c05fddaa3dffc198e503cb05b719439352238bbd8d61c2e06f8f2cfe5b6c79c2b1195f54878564d5d943a2b08ca70037108f", "b4", "9c985b3c93915dc604fc3019cff4d0d1535bef94dcf85e95f535e730aabb8f22cd3607a341d65df110c5bdb0079f8ad8c36b4d47e742204b21de844f8319b065c9f8473ce7b473951378eedc8c545b236315027e5ae0e85ae2796677bbb15bc562ddd5ca05003852744688b91620d7f9af12261ab330b7f9c468d274523a682257e9156e2279ae53a7cff9014349580630abc9c00371434723cd56ff611fab96c9b3620d0a19d60ab047605c9e72a85d3aa55f79867aa5bf4dfeeea3809a0d461f8efd1addaeb0240cb7e73bae60c37a194e97ab77064137522f840e44976e9b7a79079e43aa310240f32598d4ba61a790bdd635733430a27726ad3068f3e5c7731114bd6e5f739d09c4e9c0979cc8984e037c50e3727c93055ffe51c76565f8850047a7f836e53ebd845fbcace4a05a7d03f148ad8283e6415993e5b038dcc3052eab3ebbc54ee0a95f06ca9e68342b984cfc2814aa8fc21e3e826eeb8eb36e38c68aab96ceba5dd02552f09f103a5e31b3ffd6b53ba05b19490fe5e5cadbf3702e85eeda2cfd2efa777b3fa197ec7734029386e8e7e1eb7f35c14c047d88833fcdde2f0b2f8447b53d75ecc64892f3e9dfe9e41d7ae838ef0ff39509e2cd93e99ae597f8567779a26406ffa7f7a56efde2695d32608c328112fee6c587dac7479bb68c1672e5f54778650670510242fd95b348994fb04ba1257ebcd2cb82ef4c3e71222ecb46e2f42764d6461ac81825b3c7734a8a8155fab9a63da8fc7d450216a8525cba10fad4fde4b1990a42d5822e05e60285d9c99c4cb388beaf0427fc146b00c5e64073bb56add0ac5f247a7fb34abcdda492b049c2486f80dd8d6a259f509a2a9508fa4fe50d7e3e66d0561b78b073ce1cd3b763e1445334c795ff5aba63e1d208babf2345e1baec5bf56837a6069959518c26a7fb376b2c9e2cee87c16fc2418b1551730a5e2a4fc99c0b2e539051b4fc17d4803cd98525535ea85ed21158d74e972d93427a1e8e27de2c9e048b0388646c5cefaa4a20c4b89b35cced0d60a5de89182cc5e8c5479ee0cdd96d154e96136de8078c3304ed8ca5f097751b132a075004a7bde121ae4714e0fdb16788dc489264634041056c3bbe73fadec05ba9e0b8daca32d2f483b3b2153088f249f7e371e1001ac7d72488e31da1a28ccfef46a833eb6fd743c22fe7d4a1ced93d223383945e76f0c66be2251e4a7ef1cc5d78283f9ad9fbe14d987a65e373ddc9c54a30e95fc7276fa7c82c55e1a3917ab93abf73487d0be85d31fa41cf86de1c567e14b3f5d8eab101b1bc7260c74f98120b689f51fdd0df8d3d471875df2196bdb90bd9b5cb7e65b1ebfb70fe9c63e964aefd5477e337c8815a276856dfbd1a26e82141828ccb6a867942577efbdd1c6ed6b1f32578fab06ef3a7b9275c2a8131068f04e1c718d61ebcd728a93486dc7563b1738931c9da5055a22e3dd88232baaae5282782e4dd51ea5f0b72df2ab7b7fb961df07f3993359f17ac229eaa81f34a1dc69a351f011b30a60b5a4909cdaf8b215d1664a2660a2c560a2bcd27a8efb95c467a293867f835371c27f47cf6ad6cfd4d9d8f0defc42d9ff0f77259292c0b0cdcfb3b7aebd59d2102240ab1fbe402beb8dee4ca45cc0dc294d2b08e89290c9769da4df4cb28c12551d8120c50f9c3a11168b81c895427dd375c58bca78255bd4a145a1a96d1e81283c68353a822e4d5b00a08281110a5dcb2cf4cd7d282d682e923659dff3ac4f0ec4b8ea42b85135562cc4ed3a9ad0b9fb1fd2846ed3b0334b0dcf1c1851d53eeb4424ca8a73ccc333a31ba724d7758c77769bb15026ff51587d6b3b2570b544943cb7ca866bf82b95a80b636a2fb268dbe4987c1fa088f75fe842730a05f9046593e264b5344c0ac8614c6fad15945c1de21a6d50f8f276770bd85d7f767b3468ca8a8b2e6a5c6a2a6b195710a8a05df9de7eddb942d5c1c9cca80bfc0ff8e14580b1cbb6329f219dea5e780bb126855666b5e1ad2820e3258436ceaf652b357791b05ad6fcbbc00522667c05fddaa3dffc198e503cb05b719439352238bbd8d61c2e06f8f2cfe5b6c79c2b1195f54878564d5d943a2b08ca70037108f000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "d03d911effb910633a3c0dfbb46c4380ee50c78b6fe07f7b5698a6f7b5b8ec0520d8760f0223b72a8d9faf4cc16b30afac3dd8e68538463edd9dee27fc46928ca8a60f67089e3bdae1fd1f41abaf0492e403f41699ed0478c5390875d19d4c64107a4770a60eabd6fadf7d78eaba98e5dda72687eff0529bb26eefae66cb46de49d98b0f1fe548f765a41e9a75adc363e53ba9caec55958538487a78d517b82ab106a56bb6bce35c44e9bf61b319bd8359355318d61c015a727b376c3015888e30f4b398ec9160cefd6c78c714d62433137d3fadf64225ce63061ad07b2af6ed0fb196ee86d771897639c4bdbec55afbc084b5b2e70d9dbc6cd23eeecce1e011f355befe0f607da9631f5d8cd0d019a8e7f4448d6b0d6de75ae78682ca6b373359ed4a2cf94e2b2e136dc9cdf8187ab24bb8ded7cc9e70f948dfe7804168a56e60f07e7deab06d0bb9ee4ea20c968604323f9853a3aac13160e99f13de17c68f064dc3caaa4e4b0fe0af1ce260bda108ea0ff8789681e307e8665d8e575dfea77437d32893711c9f2e7103b24294c20cd80c4d62b952b5d475bb9572067a1b010ebf66f75dee3f723bb8d6535ed7342211084c0057905335b74054abb145be4f8a07b1abf75a4af443fcdae5e7f90a2a0cfa63ed04db4f1bb5ed73640d88803a6d155147d527017539ad902b336533f4845bb580f39d18808d89e13aa9c562a7e07f6df7c9ebb8a31e2fc44cc2940078e2527b47c644ed31a1bb8232c7cb28c752ba7cc6aeeadfe523133d92a44ff7b1495337d53975318149fb6d58e3c60ef154da356caf93bad49f3cd8a951f6c5e40ac6a9a9efd327ccc6d1f0255007959337c6566d0570d75f8b6d099021298de2a5c86b9fbe3db642f8cf901b856639938c39afe64aacf8533d6cdf0220b2b22005fc8a1f86c0d5e333c3afdb556cea960cc173a3b4499371e3bab0206acca21771ceb99073d8b31e957c1d0dfdd8ba102bad5d3fad814ad82b946e10e91875bca6caf797336b51250be8f12f39612f1e23b39c746b215839f9bdc5acb980c809ed77e89a0905a8290f251c02c6fa8d945d0fff4c98ac1ccd6dc12eea596e3e5c399d09e479226be5bb4632f204765e77c42ddc18bccb36778137a4e169dacf4462fea8f0422a3e3d989256c24d76d376d59e3881726edcc9a1cae72127e0786060e002c936fcebb0a9488c0321d576a58a4d1c05ea38006bc8079235fd741c7910a54969f7b780b7e50210ebeb225a00d0606ddb578523a653eaa108d0f31f29d805be467049fe92898dc92ec5bb4a5514a4cf62dc5c321c19afb8258eafc4be257da9bd5f880720e76472f0cebc44014c5c99a7382259422a85dea158ba0b3e4620f85b0db74f080b547ad6b82bcdc4f3b4b6088cb6e8fa1c9b70dad53a86439980fe01874a9bac736ec09cc75267e36c5f75c84605b19689794711b4002d20d9b1caa5bd6f44043508e04ec00ced5a12e64add4384ab8afa6c57c34730f8d9ca0fd032bd5a392e0194bfbc82e9e46f79482cef9ce51fc6a30a2763c542a0a40efa2501903f4689147048dd9979f2a11858ec9015146a5a770ac25e7168982511e555166d01df0f5a6a9200acba60a4da8589f62e08921c6816c8f5d91c7cd059ae4426724efeccfa7d0003a558b95718cb291b7d87950e696b7a30f5cf92510d5cfa61edfa456356a3985601d064ee5cd90183af5615ebc455782a56542b955fd98b2f6e946fb2535cb2d31e71b43b2014378ad7fbdcca28c43bec064b3e3c74f598880f347edbe5db7948ea367f348f8c33fd64d761ea0d9f0ed718951eded8f1aeda9719ceafafaa509625017074692926d4fb2f2e26c6da0a2a1eca8916286002576dabb19dda3655cc26bbbb6ea9340c90b7cd44b0b32c754e2969b9b3b106b233f14c40a7431ad742ebb172b2070f361d1b33873eeade680a7871bcb3489a0744d9efb4380d084cc5b7f71c472d12f04dfce36285e474b8f8b28d0dd2b1a108ccd2cd82de691b32f7e726df44d9e3179b2e028fe325b8d2fc97170f5f6f8adbdeba8ca63af8c7c629b90d4e4c94459ed3ece78b6e1dd5fdd54795d7530cc45a98110cf4de2d1c4355", "258", "d03d911effb910633a3c0dfbb46c4380ee50c78b6fe07f7b5698a6f7b5b8ec0520d8760f0223b72a8d9faf4cc16b30afac3dd8e68538463edd9dee27fc46928ca8a60f67089e3bdae1fd1f41abaf0492e403f41699ed0478c5390875d19d4c64107a4770a60eabd6fadf7d78eaba98e5dda72687eff0529bb26eefae66cb46de49d98b0f1fe548f765a41e9a75adc363e53ba9caec55958538487a78d517b82ab106a56bb6bce35c44e9bf61b319bd8359355318d61c015a727b376c3015888e30f4b398ec9160cefd6c78c714d62433137d3fadf64225ce63061ad07b2af6ed0fb196ee86d771897639c4bdbec55afbc084b5b2e70d9dbc6cd23eeecce1e011f355befe0f607da9631f5d8cd0d019a8e7f4448d6b0d6de75ae78682ca6b373359ed4a2cf94e2b2e136dc9cdf8187ab24bb8ded7cc9e70f948dfe7804168a56e60f07e7deab06d0bb9ee4ea20c968604323f9853a3aac13160e99f13de17c68f064dc3caaa4e4b0fe0af1ce260bda108ea0ff8789681e307e8665d8e575dfea77437d32893711c9f2e7103b24294c20cd80c4d62b952b5d475bb9572067a1b010ebf66f75dee3f723bb8d6535ed7342211084c0057905335b74054abb145be4f8a07b1abf75a4af443fcdae5e7f90a2a0cfa63ed04db4f1bb5ed73640d88803a6d155147d527017539ad902b336533f4845bb580f39d18808d89e13aa9c562a7e07f6df7c9ebb8a31e2fc44cc2940078e2527b47c644ed31a1bb8232c7cb28c752ba7cc6aeeadfe523133d92a44ff7b1495337d53975318149fb6d58e3c60ef154da356caf93bad49f3cd8a951f6c5e40ac6a9a9efd327ccc6d1f0255007959337c6566d0570d75f8b6d099021298de2a5c86b9fbe3db642f8cf901b856639938c39afe64aacf8533d6cdf0220b2b22005fc8a1f86c0d5e333c3afdb556cea960cc173a3b4499371e3bab0206acca21771ceb99073d8b31e957c1d0dfdd8ba102bad5d3fad814ad82b946e10e91875bca6caf797336b51250be8f12f39612f1e23b39c746b215839f9bdc5acb980c809ed77e89a0905a8290f251c02c6fa8d945d0fff4c98ac1ccd6dc12eea596e3e5c399d09e479226be5bb4632f204765e77c42ddc18bccb36778137a4e169dacf4462fea8f0422a3e3d989256c24d76d376d59e3881726edcc9a1cae72127e0786060e002c936fcebb0a9488c0321d576a58a4d1c05ea38006bc8079235fd741c7910a54969f7b780b7e50210ebeb225a00d0606ddb578523a653eaa108d0f31f29d805be467049fe92898dc92ec5bb4a5514a4cf62dc5c321c19afb8258eafc4be257da9bd5f880720e76472f0cebc44014c5c99a7382259422a85dea158ba0b3e4620f85b0db74f080b547ad6b82bcdc4f3b4b6088cb6e8fa1c9b70dad53a86439980fe01874a9bac736ec09cc75267e36c5f75c84605b19689794711b4002d20d9b1caa5bd6f44043508e04ec00ced5a12e64add4384ab8afa6c57c34730f8d9ca0fd032bd5a392e0194bfbc82e9e46f79482cef9ce51fc6a30a2763c542a0a40efa2501903f4689147048dd9979f2a11858ec9015146a5a770ac25e7168982511e555166d01df0f5a6a9200acba60a4da8589f62e08921c6816c8f5d91c7cd059ae4426724efeccfa7d0003a558b95718cb291b7d87950e696b7a30f5cf92510d5cfa61edfa456356a3985601d064ee5cd90183af5615ebc455782a56542b955fd98b2f6e946fb2535cb2d31e71b43b2014378ad7fbdcca28c43bec064b3e3c74f598880f347edbe5db7948ea367f348f8c33fd64d761ea0d9f0ed718951eded8f1aeda9719ceafafaa509625017074692926d4fb2f2e26c6da0a2a1eca8916286002576dabb19dda3655cc26bbbb6ea9340c90b7cd44b0b32c754e2969b9b3b106b233f14c40a7431ad742ebb172b2070f361d1b33873eeade680a7871bcb3489a0744d9efb4380d084cc5b7f71c472d12f04dfce36285e474b8f8b28d0dd2b1a108ccd2cd82de691b32f7e726df44d9e3179b2e028fe325b8d2fc97170f5f6f8adbdeba8ca63af8c7c629b90d4e4c94459ed3ece78b6e1dd5fdd54795d7530cc45a98110cf4de2d1c4355000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-11698132a61a73fcf5422c993918f269b1a552251a7dd105e4527668f47ef0440c8c525276fb6be0672c1bf97b89282c5fb3843ee9bf16e96da8c8c1fb7da7bc32ab978ca49e8568b901d9c177e51796d797ec9c6e171e9d3b9348e65473cea758901fd0b497e5afc9da748c4de89b3bb0be7f15f01988fd678bd6b5d39d5fcf6c776be85899d9aed0f52c08c8e5f6dcfe76c10449eb04b069326ffd7953be4c301239efd56f5ac3acfa6324b0e3780d6f0e3b260ba640a65678fb754806d5613ff7d47184e929b60fa42cc85513dbccb938a58f560e9f253ef34f912802114fe039549c38962ac26fcb9d806491f791d913812d0ac01eda18b62dcb336253b596fca6d08d6c125ecf0bcb7bd25cea313a2eb081de3f72fc0b507b7c97683c51240932e4c846d68fd9224aefae636b95982f2974ef98508a70b4500db125d17afc636a18f049f3085666c33099d05e84c49c3a85f85f4089757727aa04f98a6313c91ff2fd49b48c464cde33b0acbc6ff4e2604abe9ac69450b8bb2d71f2270b83ac6cc9ca57fe0751ca9123242a8f65eac08595afa820f0ae1af07125c5898ef3dfe3a3285adc65844994e6f727cd6a83ea19f3e242e938600499c5ea23fb8a2dcd1142d3ebd6798ef2a9a9669782484ffbcd8074cfd47d253f34d4062f961d7474308d848db8a5564717aa01e0932ae5ca1b65a5d96405b645a209810e4074e3481a5e33e0bb31bf4322e2443c89d6bf9863203efce6168f3d327cc5e8975bebe9c524f2a254012fbfbfe412692d6b5b4ac0bb7cdf9e008c5f9be0bef7e66242059f1041b02408e1e57339593f8341a182f2a870b1c44364ac932f0564cd6740be612015b4a30c3cee944b7a5c79ad2a499f4a6c9fc4431c8e6ea97bc02ebe6f699cff86f15193ee65046bb00a1f4f21bb1f184aab41a38126cf168ae8a6015512a9d00d85f7a357380c2ea223aa6353646b2f16117e2d8fc342a4ca52d533f0dadba28ea1917ea5db39be9006ad5ca4ec1c108b24e473f4712331c7634427da9261e17483d0e36272073bebcabf798b4847e2e2388dbb69d2ed75bc374aa3eb73c18e1815ce4e7515f818547ce0696154b66b1008a68433db3bbd1f152f6e04edaa9d6abf8219b75525c24acab5a2416dc5b09cf197a643a91e8269b9c04ee53d8983ba0f66dac750140e7c0da63554c8cead2df679c9ebf506e8a25a323763735b48ad0b35377e392f5d345855810362852ae040dfb99d4f12e4932fa6f64ce03a3eff6fd2c1f3aa95d51c5693b1f5103205ab7e5357a68f99df61126e72e78dcbb3a7d167e7caad4374a0284cbebbc3c97ed8a762640a94f69cc16618ea544d5fe4a01f99c1a4aa1f4567c09a39c2e168d2fab5e6f0f0d5f679d7695fe9da43eda763946dd798510ede5eb6730edafab21116edcc754c0c85b52a9218d485e5a79b342ba646bff5495a5bd3abc322e222e2c02cb0cd78566a8a470b4f693eff4c494a43b64b3d91da7545aeff87eacd103f98d13ba39d452a1181c7fc27f6653b2b21c0e15743843ea5c7cf10f45d0b94de2a1e8ee331a4932b7d8abdfc6f0987af326a766771a0fb5b5cd7d01a7e3a9b2cdc130f64b3e538149cd6de29faaf5fae54df1869fc1906f24ff261deb02e733a241a46f4c7cfd5c960fd4f66401288c2502a4c38aafe2c815c945466aced1fa63ba66ef71c9025c301aa538b217fa95fd55cc9bb1aa7ad1a8e27db640b40a76dce2ab4e506081a681d5ff1f155d0d0330aa2f411297bbd2b17550a1f5d9817802a602438fc99d2a52c425a7e97c9b6b51a2e116dfd21f0ebc8dc679c91480e50f28d1abc21bdbbb88e47b2bc1576bdcd02ce22e8d7315e5fcf7737bb7b2f8368a180a89889af4c3c1258f4a6d80e5e1836206bd8c8c3a2c14e3b71dc0b6aec2758040a0896921f2638fa945ce0becbc492506f3de0c0881dfcde8bc02db0061c50448e0ffcd14c732d8ddce783bcb897cacfd02ae5c0738619c519da399ac0dac4fe5f8c7b5485c38d83331cbdb4f5498ae5bd8c54f754d49806217e6f81be750d4a714c153f4aa65c7f2fa3ac58e252bc5936554a77b4faaa6ecce3941c02ed51771c3ad240356a", "0", "-11698132a61a73fcf5422c993918f269b1a552251a7dd105e4527668f47ef0440c8c525276fb6be0672c1bf97b89282c5fb3843ee9bf16e96da8c8c1fb7da7bc32ab978ca49e8568b901d9c177e51796d797ec9c6e171e9d3b9348e65473cea758901fd0b497e5afc9da748c4de89b3bb0be7f15f01988fd678bd6b5d39d5fcf6c776be85899d9aed0f52c08c8e5f6dcfe76c10449eb04b069326ffd7953be4c301239efd56f5ac3acfa6324b0e3780d6f0e3b260ba640a65678fb754806d5613ff7d47184e929b60fa42cc85513dbccb938a58f560e9f253ef34f912802114fe039549c38962ac26fcb9d806491f791d913812d0ac01eda18b62dcb336253b596fca6d08d6c125ecf0bcb7bd25cea313a2eb081de3f72fc0b507b7c97683c51240932e4c846d68fd9224aefae636b95982f2974ef98508a70b4500db125d17afc636a18f049f3085666c33099d05e84c49c3a85f85f4089757727aa04f98a6313c91ff2fd49b48c464cde33b0acbc6ff4e2604abe9ac69450b8bb2d71f2270b83ac6cc9ca57fe0751ca9123242a8f65eac08595afa820f0ae1af07125c5898ef3dfe3a3285adc65844994e6f727cd6a83ea19f3e242e938600499c5ea23fb8a2dcd1142d3ebd6798ef2a9a9669782484ffbcd8074cfd47d253f34d4062f961d7474308d848db8a5564717aa01e0932ae5ca1b65a5d96405b645a209810e4074e3481a5e33e0bb31bf4322e2443c89d6bf9863203efce6168f3d327cc5e8975bebe9c524f2a254012fbfbfe412692d6b5b4ac0bb7cdf9e008c5f9be0bef7e66242059f1041b02408e1e57339593f8341a182f2a870b1c44364ac932f0564cd6740be612015b4a30c3cee944b7a5c79ad2a499f4a6c9fc4431c8e6ea97bc02ebe6f699cff86f15193ee65046bb00a1f4f21bb1f184aab41a38126cf168ae8a6015512a9d00d85f7a357380c2ea223aa6353646b2f16117e2d8fc342a4ca52d533f0dadba28ea1917ea5db39be9006ad5ca4ec1c108b24e473f4712331c7634427da9261e17483d0e36272073bebcabf798b4847e2e2388dbb69d2ed75bc374aa3eb73c18e1815ce4e7515f818547ce0696154b66b1008a68433db3bbd1f152f6e04edaa9d6abf8219b75525c24acab5a2416dc5b09cf197a643a91e8269b9c04ee53d8983ba0f66dac750140e7c0da63554c8cead2df679c9ebf506e8a25a323763735b48ad0b35377e392f5d345855810362852ae040dfb99d4f12e4932fa6f64ce03a3eff6fd2c1f3aa95d51c5693b1f5103205ab7e5357a68f99df61126e72e78dcbb3a7d167e7caad4374a0284cbebbc3c97ed8a762640a94f69cc16618ea544d5fe4a01f99c1a4aa1f4567c09a39c2e168d2fab5e6f0f0d5f679d7695fe9da43eda763946dd798510ede5eb6730edafab21116edcc754c0c85b52a9218d485e5a79b342ba646bff5495a5bd3abc322e222e2c02cb0cd78566a8a470b4f693eff4c494a43b64b3d91da7545aeff87eacd103f98d13ba39d452a1181c7fc27f6653b2b21c0e15743843ea5c7cf10f45d0b94de2a1e8ee331a4932b7d8abdfc6f0987af326a766771a0fb5b5cd7d01a7e3a9b2cdc130f64b3e538149cd6de29faaf5fae54df1869fc1906f24ff261deb02e733a241a46f4c7cfd5c960fd4f66401288c2502a4c38aafe2c815c945466aced1fa63ba66ef71c9025c301aa538b217fa95fd55cc9bb1aa7ad1a8e27db640b40a76dce2ab4e506081a681d5ff1f155d0d0330aa2f411297bbd2b17550a1f5d9817802a602438fc99d2a52c425a7e97c9b6b51a2e116dfd21f0ebc8dc679c91480e50f28d1abc21bdbbb88e47b2bc1576bdcd02ce22e8d7315e5fcf7737bb7b2f8368a180a89889af4c3c1258f4a6d80e5e1836206bd8c8c3a2c14e3b71dc0b6aec2758040a0896921f2638fa945ce0becbc492506f3de0c0881dfcde8bc02db0061c50448e0ffcd14c732d8ddce783bcb897cacfd02ae5c0738619c519da399ac0dac4fe5f8c7b5485c38d83331cbdb4f5498ae5bd8c54f754d49806217e6f81be750d4a714c153f4aa65c7f2fa3ac58e252bc5936554a77b4faaa6ecce3941c02ed51771c3ad240356a", .Okay}, + {.Shl, "-479fd8446ddfd3439cbbff6e1321190eee5e2a3a47ac8ac8e3d7e8ff98f2b22d01b01ce29fb0c8d88801eae7a4f175efcf11b6581bf9298487cc1c23a07c3d9953be84f0fe7fc29978be329474f83cf251880ef118cdb8ab2d3f263551889bebaaf01d451b6ddc0a25b07595561b2adf0c41278e6612f97b3b9da09d56cb27aca00fff42a94d323c6cf02f66335959b2a93db855f204ccc74f9cb354269088da7c15040091647171b9b7a31b8a1001b263d2f3a9e62d69c9ca8ba0d82f045d905f8881a75c35991ea38b4f0fd570b8a7f9c464c6dc82c49f29abb7c0bf4bd70ce0cc3c2ad3fd2278779fc7bc6bb9c8e11e4e1ed2ee142432df37d2ed548d6b8e9b9e6b7535e032917c2612f04e471d96f676f9a2f3a34484b8689ad83eaf3d420083137b93860bcd2156e8a2121f1dd99aebca1908d001782603485585b33c872d18f01580719368c04afe8380e8b6de4855599485da1aef7418b8cc9da0f9a0fce7382ff24761494b1240ba442a915d349a39e7948d745d6fd1b1ca0b3fa255d6c3c948bd2d4bcb535ad4155c250ae287216a74d91193c3c67e78c29cb33687bd19eabf2ad010fcd9e208898fc444c4dbdc5cc1e7f757df726eb8af35835aedba211387902abf434383444db1bdb767a4b446edcc8bdbd635f2b824a8ae4a900a6ec7b975459c90e86fbf4d8fa548f6579bf53ab36f91cb23f6bc219566c4f7f11e638b732b6f353793f0bfb67b919df4f69233564ae0d7bc63e395b1eb72f08890eb3bc29a299846524c133660f27a996870a10b6985ba7073be00b496e4f7399d89f77581084543119a15227e6bba885ab81cd866d43bc6e9c529d30e74762167a84716f9d694f123a85d31b9ed2f88bf57362ff8c625544a6c6c17379bbb1b49656825879e18f296c2e017a957f2bdbcfc50c92c5d320a319b4f140843aa1cd04307cc051f28665f40c42a2b6535823aa7235663ff356c1d7fd18674db0575a61aec00b81c1fe8d4054bf5f578ec2e95559731cec610a1584d754ef5b6ccb1c22797a64b0d3c8a0e7ab68acec3fb451cdf47350a0020ee64ad08ef002520b6ff918a6ed383b7bcab599134da3090874c73f687387dffe8d8e0561dadf0cf97280d41cd09392748307b582a7093f099b0c9f49de19c2b818a0ef9d426138ae38ea7d990d2a69c28477510195a62fe83cff039db02fac225f3fdcc971db2e6f5e9c0e5fbddf3f6f2bc48f36883ae3c9f7a25d17fbe45dec0db4c3cc72cb9da9a36fb80bba9e69a4b53c98c2f1f005227754f6115d4946f90fc1265b366a056160d8447d01500f11d3b2bca7106f773c1a1980556933b0f86e914014fddb145a9d4f629d1e0168be9b14a24b9bfd615e93f0fdc37229302456f0f5a8a422eed85d4aef53eb27139e6377ab91d75e94ec78c5b3854a732472dc0b72466df479f1388c6f42936f94cfa537369f66e2981c7b8acc6db944c84d38fd9e80e249409d36a767fe1a8cd8aa357a785dcf6ea280be1824b67ab2ea5791dd1e5aa5c86693c605643ed2eddd33866641da248ccf94bf5185f719c654aae745ee158f47d2e70e03ea812d4ff0e3e7c39337e6d3c8f1c509a34da3d385715da4a10e94d4edc244fe96f79d36478fe68a013c42e5571bdf07cb6a239767eea2efa14f3f4f7a30ce7296fddaa67743cbe52a09c355557ef5258005613ef35def8ac8aa459bc861e95d9ae849b75045e52c8d7c4abd5108cb3fabb880fe2828fbe528f95456426d26314c2bdb0b9d01d8a13081866e716d178fd51c2f44ad70d607d5bebd1f0725d9fe472e8c199a0d627b10d532928d476edf49b3c795bf5dc9620bb7c08cbf2e6c79016f79ffa30c8cfbe35d546ca435664d5c0a992a167c17145fc6ac3ade09c8d01c7d449c9b0f9993bd72ccd4b712dc0e81166bd1135cea4666e1ba61d80b973d0c0c283fdf916283749b026df8ebcdd140d6e17ba8a4f5ec00409c1f29115783c66e9ba5e83b85d6130faeb6af40d27814efa40b97f85ef4cc51db010c6927db3448feda1504c49f79c94f6a3d5ad0cc010015fe928328fbdeeaf6245f39b9beb611f39f8bbdc627c40eec9a87ece0a72d685e0cfba351a3cce", "258", "-479fd8446ddfd3439cbbff6e1321190eee5e2a3a47ac8ac8e3d7e8ff98f2b22d01b01ce29fb0c8d88801eae7a4f175efcf11b6581bf9298487cc1c23a07c3d9953be84f0fe7fc29978be329474f83cf251880ef118cdb8ab2d3f263551889bebaaf01d451b6ddc0a25b07595561b2adf0c41278e6612f97b3b9da09d56cb27aca00fff42a94d323c6cf02f66335959b2a93db855f204ccc74f9cb354269088da7c15040091647171b9b7a31b8a1001b263d2f3a9e62d69c9ca8ba0d82f045d905f8881a75c35991ea38b4f0fd570b8a7f9c464c6dc82c49f29abb7c0bf4bd70ce0cc3c2ad3fd2278779fc7bc6bb9c8e11e4e1ed2ee142432df37d2ed548d6b8e9b9e6b7535e032917c2612f04e471d96f676f9a2f3a34484b8689ad83eaf3d420083137b93860bcd2156e8a2121f1dd99aebca1908d001782603485585b33c872d18f01580719368c04afe8380e8b6de4855599485da1aef7418b8cc9da0f9a0fce7382ff24761494b1240ba442a915d349a39e7948d745d6fd1b1ca0b3fa255d6c3c948bd2d4bcb535ad4155c250ae287216a74d91193c3c67e78c29cb33687bd19eabf2ad010fcd9e208898fc444c4dbdc5cc1e7f757df726eb8af35835aedba211387902abf434383444db1bdb767a4b446edcc8bdbd635f2b824a8ae4a900a6ec7b975459c90e86fbf4d8fa548f6579bf53ab36f91cb23f6bc219566c4f7f11e638b732b6f353793f0bfb67b919df4f69233564ae0d7bc63e395b1eb72f08890eb3bc29a299846524c133660f27a996870a10b6985ba7073be00b496e4f7399d89f77581084543119a15227e6bba885ab81cd866d43bc6e9c529d30e74762167a84716f9d694f123a85d31b9ed2f88bf57362ff8c625544a6c6c17379bbb1b49656825879e18f296c2e017a957f2bdbcfc50c92c5d320a319b4f140843aa1cd04307cc051f28665f40c42a2b6535823aa7235663ff356c1d7fd18674db0575a61aec00b81c1fe8d4054bf5f578ec2e95559731cec610a1584d754ef5b6ccb1c22797a64b0d3c8a0e7ab68acec3fb451cdf47350a0020ee64ad08ef002520b6ff918a6ed383b7bcab599134da3090874c73f687387dffe8d8e0561dadf0cf97280d41cd09392748307b582a7093f099b0c9f49de19c2b818a0ef9d426138ae38ea7d990d2a69c28477510195a62fe83cff039db02fac225f3fdcc971db2e6f5e9c0e5fbddf3f6f2bc48f36883ae3c9f7a25d17fbe45dec0db4c3cc72cb9da9a36fb80bba9e69a4b53c98c2f1f005227754f6115d4946f90fc1265b366a056160d8447d01500f11d3b2bca7106f773c1a1980556933b0f86e914014fddb145a9d4f629d1e0168be9b14a24b9bfd615e93f0fdc37229302456f0f5a8a422eed85d4aef53eb27139e6377ab91d75e94ec78c5b3854a732472dc0b72466df479f1388c6f42936f94cfa537369f66e2981c7b8acc6db944c84d38fd9e80e249409d36a767fe1a8cd8aa357a785dcf6ea280be1824b67ab2ea5791dd1e5aa5c86693c605643ed2eddd33866641da248ccf94bf5185f719c654aae745ee158f47d2e70e03ea812d4ff0e3e7c39337e6d3c8f1c509a34da3d385715da4a10e94d4edc244fe96f79d36478fe68a013c42e5571bdf07cb6a239767eea2efa14f3f4f7a30ce7296fddaa67743cbe52a09c355557ef5258005613ef35def8ac8aa459bc861e95d9ae849b75045e52c8d7c4abd5108cb3fabb880fe2828fbe528f95456426d26314c2bdb0b9d01d8a13081866e716d178fd51c2f44ad70d607d5bebd1f0725d9fe472e8c199a0d627b10d532928d476edf49b3c795bf5dc9620bb7c08cbf2e6c79016f79ffa30c8cfbe35d546ca435664d5c0a992a167c17145fc6ac3ade09c8d01c7d449c9b0f9993bd72ccd4b712dc0e81166bd1135cea4666e1ba61d80b973d0c0c283fdf916283749b026df8ebcdd140d6e17ba8a4f5ec00409c1f29115783c66e9ba5e83b85d6130faeb6af40d27814efa40b97f85ef4cc51db010c6927db3448feda1504c49f79c94f6a3d5ad0cc010015fe928328fbdeeaf6245f39b9beb611f39f8bbdc627c40eec9a87ece0a72d685e0cfba351a3cce000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-b430763810f3d035195159b28478793fd7c1e0a9d8642f1a7d04ce277174dd08f3ace8e812f875b760d116a3745d56fc8eb659357beec22e8fb845cce220b3248a72b731a34a5e78e5cc5baaebe3787632329d7fce8c479d1e4bdb46150047a25c1c805d0186bbcc4114e35d7700324eb5adf3817bd4d498383e09b3ed2b741dfe6f0c0947c7fcbe5aee9ed35858defb9a36fda38daefff7f0b4c804782365541caa77e06a4a7ab050c3325d7bb0d75cdc1e4afead3769eb7ff4481d5ff2a78898e56aa78bf081318d8ef95b5b3a0dbdba0f77644260ca8572ea0bc8b168535526dadbe9346b3faa33cec07dc8ce181d15495cb256a7b1e652cc324e064ab0a0503a6b78cc2ce030ab267297ba1443a1e29e9e30ccb0c7101b6191925fa5e90686cf7eb0384d139106207455297139b006e19a597c802bf473500c3425081f4295fd9feb2f016b9c5b57d5f6edc754bef7e7672942bdf291f583a1c2de267365841a05e6fe9835bafd33dd98b06c9d531c3b6143dcd22c8b30a7aa87b8efeb87ff4b4e01498de5ceab3f5f15946065ac98761220e3ef1855bb59277c8c7678f0438c873438b7afdb6758a6acb668364d62eb0b869a44c171ee1f1cf975c2e02c45ca8e1e7d7ba790c557a9c01d564003ccb86fa70a552895bae97a9f3c16fcd6f83416622205b1f2fac1351e39c97ea94123b4a84a012ec39aa38ca75e094095769a41b1f80827d2f212c9e5ade53c3d3d3f02ce0550cae9eb27eca7655357f4be7d2fc381f24c59c97a8d0475ca4149e4399888dbfdddd92d5285123bff468d1d2b0a4d86a590cc4991a0303614c10b96ecf385e3edb511c3fde9c7c628a71e77817eb87e9b32ef14f691414d8f28623cb70eb6750f74ad86d5fd4b2596777c05147729c9042105f2d9a10940f9490ec767f84b0a6d79f89220f34fcb2b8056d4fa1c23cfc1455e22d67c55aa67518f87f0baa6c7413511788b8353cde6f33a6f9b114b814c827b871d56d95be3f61d505bbdad2ab0f2369df5747cb5a7ed7b132b4037f1160bae175170b55cd79b34de3174933830257ebd34c4237a05c8f95fbb6be473e888c1e68e8514baf2fe05de34605e9692c01030158094499969a0ebf732b77d68bc80b7b0421ec3027428a5a4242358494b3d23cab35915a96a1c13a5d95620b5e6bc6b741dcbf120adae2ade442c4e074456d147ceacd7a083c7d3e9c458122d5b81dbae51297355b324e71c593319a238fc6b1cc13978667c634290b99fecc1f3e51bd50d04c10f6653ce45c08a7bd7dc09692561a6123fd395155d5f4cb4d92b73ebe80795e131a699d6575b41cc9a7ee9645bd4bfb7d5aa864af7e9e46844862a1160b5af8667dd064bf2ffc75b9448499dbe1692ae876104f3a6093816a3fd46338e2735fcf4cd4d499c4a6969144756b8a0aa6695df77e9000180364ef9cd18f5a5614bbe69a06fc315f8330bd59a269a8048722459d656f81622924c03471af245a8afe2783657f274320f1fc447aec943073635332a90013bda13b4d6c97846f63a25788b6782e512def71f75e70dce4568b07ce1591b727287f8507eeb0ff283f42a08c93ac72ca54cab225b999ab7ca9d86107e398ac3582b3db0d66a82a3ee8149cceca7d96d2fde5219ab94034c0b1a849ecc3593221e9a86a5000c0c0d7072901f8a8e1c0e7477a7471891df5212a2573f8d555b8191e485ed3c81160be9df83ed8c23e867e83357f2b154a59e6d2c07f7ec59ac57c224d17d71dd51cc0e0f973bf33131475ea8079de3a3eafab6bd04746c07ac9b6525c879c51c53106e46ad861d9057c23531e71124ee4e18cd17e1b5f940f3f10deaa26ba69d3a8d5739391cc106d6d1953433c33a76ee97c8e18d06dbf4336ea9bddc8c684877c1fe86cb2b1905d36b917aa994caa8433ac2ede46793f264a38f36e11e4992ec2dbb00eef6416d9e1cf39831dff0269aa306c459a2ac0ccaa565ac8968ee57fa7a1b726685191680dfc4f8dece7d050ee51b0db36809e0241f90d989bfd2362bdf8909bbb9f6b3f26c51607b40e70a5ed52d271e1187d75a55502b11c8b3e06bf033fbd9fbb1eded647e65553171e9edb16052a9", "1a4", "-b430763810f3d035195159b28478793fd7c1e0a9d8642f1a7d04ce277174dd08f3ace8e812f875b760d116a3745d56fc8eb659357beec22e8fb845cce220b3248a72b731a34a5e78e5cc5baaebe3787632329d7fce8c479d1e4bdb46150047a25c1c805d0186bbcc4114e35d7700324eb5adf3817bd4d498383e09b3ed2b741dfe6f0c0947c7fcbe5aee9ed35858defb9a36fda38daefff7f0b4c804782365541caa77e06a4a7ab050c3325d7bb0d75cdc1e4afead3769eb7ff4481d5ff2a78898e56aa78bf081318d8ef95b5b3a0dbdba0f77644260ca8572ea0bc8b168535526dadbe9346b3faa33cec07dc8ce181d15495cb256a7b1e652cc324e064ab0a0503a6b78cc2ce030ab267297ba1443a1e29e9e30ccb0c7101b6191925fa5e90686cf7eb0384d139106207455297139b006e19a597c802bf473500c3425081f4295fd9feb2f016b9c5b57d5f6edc754bef7e7672942bdf291f583a1c2de267365841a05e6fe9835bafd33dd98b06c9d531c3b6143dcd22c8b30a7aa87b8efeb87ff4b4e01498de5ceab3f5f15946065ac98761220e3ef1855bb59277c8c7678f0438c873438b7afdb6758a6acb668364d62eb0b869a44c171ee1f1cf975c2e02c45ca8e1e7d7ba790c557a9c01d564003ccb86fa70a552895bae97a9f3c16fcd6f83416622205b1f2fac1351e39c97ea94123b4a84a012ec39aa38ca75e094095769a41b1f80827d2f212c9e5ade53c3d3d3f02ce0550cae9eb27eca7655357f4be7d2fc381f24c59c97a8d0475ca4149e4399888dbfdddd92d5285123bff468d1d2b0a4d86a590cc4991a0303614c10b96ecf385e3edb511c3fde9c7c628a71e77817eb87e9b32ef14f691414d8f28623cb70eb6750f74ad86d5fd4b2596777c05147729c9042105f2d9a10940f9490ec767f84b0a6d79f89220f34fcb2b8056d4fa1c23cfc1455e22d67c55aa67518f87f0baa6c7413511788b8353cde6f33a6f9b114b814c827b871d56d95be3f61d505bbdad2ab0f2369df5747cb5a7ed7b132b4037f1160bae175170b55cd79b34de3174933830257ebd34c4237a05c8f95fbb6be473e888c1e68e8514baf2fe05de34605e9692c01030158094499969a0ebf732b77d68bc80b7b0421ec3027428a5a4242358494b3d23cab35915a96a1c13a5d95620b5e6bc6b741dcbf120adae2ade442c4e074456d147ceacd7a083c7d3e9c458122d5b81dbae51297355b324e71c593319a238fc6b1cc13978667c634290b99fecc1f3e51bd50d04c10f6653ce45c08a7bd7dc09692561a6123fd395155d5f4cb4d92b73ebe80795e131a699d6575b41cc9a7ee9645bd4bfb7d5aa864af7e9e46844862a1160b5af8667dd064bf2ffc75b9448499dbe1692ae876104f3a6093816a3fd46338e2735fcf4cd4d499c4a6969144756b8a0aa6695df77e9000180364ef9cd18f5a5614bbe69a06fc315f8330bd59a269a8048722459d656f81622924c03471af245a8afe2783657f274320f1fc447aec943073635332a90013bda13b4d6c97846f63a25788b6782e512def71f75e70dce4568b07ce1591b727287f8507eeb0ff283f42a08c93ac72ca54cab225b999ab7ca9d86107e398ac3582b3db0d66a82a3ee8149cceca7d96d2fde5219ab94034c0b1a849ecc3593221e9a86a5000c0c0d7072901f8a8e1c0e7477a7471891df5212a2573f8d555b8191e485ed3c81160be9df83ed8c23e867e83357f2b154a59e6d2c07f7ec59ac57c224d17d71dd51cc0e0f973bf33131475ea8079de3a3eafab6bd04746c07ac9b6525c879c51c53106e46ad861d9057c23531e71124ee4e18cd17e1b5f940f3f10deaa26ba69d3a8d5739391cc106d6d1953433c33a76ee97c8e18d06dbf4336ea9bddc8c684877c1fe86cb2b1905d36b917aa994caa8433ac2ede46793f264a38f36e11e4992ec2dbb00eef6416d9e1cf39831dff0269aa306c459a2ac0ccaa565ac8968ee57fa7a1b726685191680dfc4f8dece7d050ee51b0db36809e0241f90d989bfd2362bdf8909bbb9f6b3f26c51607b40e70a5ed52d271e1187d75a55502b11c8b3e06bf033fbd9fbb1eded647e65553171e9edb16052a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shl, "-f1edb13bc59970850afbda4008397ea3b748fa369e9558e0180bb1718c30b3e0cd19d1c821dd33e6d86513b38ea51a2cda35763ece414704e880022030fe2670ed4896d6ca00023a06b2d37f0e968ae184e15b9bf77da6fbdec126bd3942b70fa225acec392f13e2d47b544c7c2ebf7fd296f00a46e70e0e58a466f6475c8d76cc0ce87e2c6d9d003ed986d4e315278e169259ff2038476681f60804267c902cf8b183d75f58b84f209cd3fd6bb67f78575d78d97b8f11d986b8a8b01805f670cfb76db55b7875fd99b72b6c55c65656168061f33402eaa9443b5380e9ee19119848e9cea54f14dfe898030e41d8008d0d4c40fd1efbe4fdfc47d7e83d02e2d5807d3db7e330a6f1927f5cb3f922a8488e66eb7156b805c04e0990bba56021ec060e90fbb36900b1b7cab3ce7695d7c3a967609abfc0df3b485cc48889e1f0f1632dbb5bcc5827bccabed6ec3083f14850b037e90de0781546e5a9f26349b7fef3dad85e299c06425c5d1dee48b88840f0103e3ae4802935a6ef89b1df80377e09e89d0379cbc11437e32cb79ddd90ddf7117d018e6ebe83b25692ca20d82136ce8ccb907827595a56dcb4f3b453a646e2cc5cdc1a5461ab0c6f0d07c049b4e579c5d7e63262a24a3f31474552cea0f7fbd6f775a58b247581f0a5eed767d2ee065fd0242a3262d0a32b007e3f8a6dec9738ac62391027c05d4c50cc2f345644bf8eee446cf73715664bb686850cf99afc56ab4b8c0c1d88b28d5d61701cb6654487b93f1aa82b1a437a8f19b9ddcf2df1c1a914631de55c53161da374bbd011ef409ed127e289ced4afc35a6b38c3adc5413d63507eeab8f288dd1f96fe1ba9a6006e913df04211028dbc1ce4e296a375faa5271e91359adbe13debc024a1d92a183cae611ab6ca54e6fcc942315355157d145a7138aff4c70f8a1eaf0ac5993ab3ee1d0966b48301e393d53c5b90014704e036185c81ce9f1f7de538c2be000b0c250413d21f626c3b44f5b818559b740c728ac3609d07461c94450ac68a30af9552e6acb9fba659f865262dc68bedf71e34cfe9ca1007968db1ad731fcaa04dd3a234ebef553db6c5f1fd449f87efdafff5f46da1d30ba121ef7727d930d9f36f2ded813009793ea8f6d217742a9026fd75cae8d30321f591f8e65eb06a0b78b351723e75c0d1583dcab426b518ccadbc04adfb3028d25e1be7ec1d2a8a06204abe414d786e61432cba58289eff63911d9c49cd60fcd18890f11ddd40d5fe57df602d8df85e8134b849987da7de2466826a14de5adf8ae185cee4ad29784ec5da5a0d07bca36d96b9e23025848bc9d518976881234cd3ec69e553cce95ca2a4cf82e8bc149f36816560e8d17aaaf4c5cb5e437f12e7e1b3274d083b258152ff77095771fa375b617fa31c4e6d6f5a61ae72cff1b121a07ce7a9778a518d0cf878acf7c35b0df4eb6a22b34fdc5f38ce5915cf2f3d96fdef6c42ad9c0299b49d2cc6b85c5cd7594e68f8dd7facdc34d2a73a9cc090edbd15f8b90fdf3be424c2843d20e811e8d5a1e9547f0ec6fb6d6dadad41c10a6cff11484e00061bd33d298354c9ef95f4c21ef4c1e9ff4379db9c58212841f9a79d5a55fbe1fe86c18521837e65515c327549df442f09489529a27c74c4dc09fd541e8510473af4bd4783975b09c8b17b6393840860608a35593bd25e5afb9818ce3be5f74c5d49dfef8d8124c8601382fe16ea596d65c4387d935ca3fa4f7f2b9f9470b101d26ece0e750fd1ceeb8d64baeff0abf9d5fa6a6526875ea77c42e1688ad2d41ce7b259da1bbb763044ad13567976e4835057d8d51a80ba006b28c53ad8e88b6d64293eb35330b51e392a4a413c0106719ef118f54f752e8b43c5b777e60a044fa042ea638131aff1512580dd8639a0d8039aa8f8a768a2d36e5da0a665ed332852adfc0b7f8dddc4f1d4411338b6b1e825cf8c4bbb0ee07b04be960221b71c3e75471d29e69c898b6fc130d337b0eb32bfb335b9c97ff1b85cef9d028b93350a25ee179748bf6a9e168c8b997c367c4baec848df54ea096fd1c34c4fbb4c32dbf7d9a7f54c066791c32d2966e6e5cddaa6cccc795a09b047a1df35c6734878e0", "258", "-f1edb13bc59970850afbda4008397ea3b748fa369e9558e0180bb1718c30b3e0cd19d1c821dd33e6d86513b38ea51a2cda35763ece414704e880022030fe2670ed4896d6ca00023a06b2d37f0e968ae184e15b9bf77da6fbdec126bd3942b70fa225acec392f13e2d47b544c7c2ebf7fd296f00a46e70e0e58a466f6475c8d76cc0ce87e2c6d9d003ed986d4e315278e169259ff2038476681f60804267c902cf8b183d75f58b84f209cd3fd6bb67f78575d78d97b8f11d986b8a8b01805f670cfb76db55b7875fd99b72b6c55c65656168061f33402eaa9443b5380e9ee19119848e9cea54f14dfe898030e41d8008d0d4c40fd1efbe4fdfc47d7e83d02e2d5807d3db7e330a6f1927f5cb3f922a8488e66eb7156b805c04e0990bba56021ec060e90fbb36900b1b7cab3ce7695d7c3a967609abfc0df3b485cc48889e1f0f1632dbb5bcc5827bccabed6ec3083f14850b037e90de0781546e5a9f26349b7fef3dad85e299c06425c5d1dee48b88840f0103e3ae4802935a6ef89b1df80377e09e89d0379cbc11437e32cb79ddd90ddf7117d018e6ebe83b25692ca20d82136ce8ccb907827595a56dcb4f3b453a646e2cc5cdc1a5461ab0c6f0d07c049b4e579c5d7e63262a24a3f31474552cea0f7fbd6f775a58b247581f0a5eed767d2ee065fd0242a3262d0a32b007e3f8a6dec9738ac62391027c05d4c50cc2f345644bf8eee446cf73715664bb686850cf99afc56ab4b8c0c1d88b28d5d61701cb6654487b93f1aa82b1a437a8f19b9ddcf2df1c1a914631de55c53161da374bbd011ef409ed127e289ced4afc35a6b38c3adc5413d63507eeab8f288dd1f96fe1ba9a6006e913df04211028dbc1ce4e296a375faa5271e91359adbe13debc024a1d92a183cae611ab6ca54e6fcc942315355157d145a7138aff4c70f8a1eaf0ac5993ab3ee1d0966b48301e393d53c5b90014704e036185c81ce9f1f7de538c2be000b0c250413d21f626c3b44f5b818559b740c728ac3609d07461c94450ac68a30af9552e6acb9fba659f865262dc68bedf71e34cfe9ca1007968db1ad731fcaa04dd3a234ebef553db6c5f1fd449f87efdafff5f46da1d30ba121ef7727d930d9f36f2ded813009793ea8f6d217742a9026fd75cae8d30321f591f8e65eb06a0b78b351723e75c0d1583dcab426b518ccadbc04adfb3028d25e1be7ec1d2a8a06204abe414d786e61432cba58289eff63911d9c49cd60fcd18890f11ddd40d5fe57df602d8df85e8134b849987da7de2466826a14de5adf8ae185cee4ad29784ec5da5a0d07bca36d96b9e23025848bc9d518976881234cd3ec69e553cce95ca2a4cf82e8bc149f36816560e8d17aaaf4c5cb5e437f12e7e1b3274d083b258152ff77095771fa375b617fa31c4e6d6f5a61ae72cff1b121a07ce7a9778a518d0cf878acf7c35b0df4eb6a22b34fdc5f38ce5915cf2f3d96fdef6c42ad9c0299b49d2cc6b85c5cd7594e68f8dd7facdc34d2a73a9cc090edbd15f8b90fdf3be424c2843d20e811e8d5a1e9547f0ec6fb6d6dadad41c10a6cff11484e00061bd33d298354c9ef95f4c21ef4c1e9ff4379db9c58212841f9a79d5a55fbe1fe86c18521837e65515c327549df442f09489529a27c74c4dc09fd541e8510473af4bd4783975b09c8b17b6393840860608a35593bd25e5afb9818ce3be5f74c5d49dfef8d8124c8601382fe16ea596d65c4387d935ca3fa4f7f2b9f9470b101d26ece0e750fd1ceeb8d64baeff0abf9d5fa6a6526875ea77c42e1688ad2d41ce7b259da1bbb763044ad13567976e4835057d8d51a80ba006b28c53ad8e88b6d64293eb35330b51e392a4a413c0106719ef118f54f752e8b43c5b777e60a044fa042ea638131aff1512580dd8639a0d8039aa8f8a768a2d36e5da0a665ed332852adfc0b7f8dddc4f1d4411338b6b1e825cf8c4bbb0ee07b04be960221b71c3e75471d29e69c898b6fc130d337b0eb32bfb335b9c97ff1b85cef9d028b93350a25ee179748bf6a9e168c8b997c367c4baec848df54ea096fd1c34c4fbb4c32dbf7d9a7f54c066791c32d2966e6e5cddaa6cccc795a09b047a1df35c6734878e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", .Okay}, + {.Shr, "cd1155fd3d6cf1026149c0637d20a62750cc7557ef988c3417d74dbfcc5176d8259176f8fc67ef7b2f386a5c8d2f9829281417c41900cd19f16e91e31d7b36b2400c2e0a5a35365aec2df08dc1c74c5491d37d7d8218d8d000d87b278bcb01d117120115d13bce360f94a580736359e80f766cd317c3d94b5069dffe3468aa29d3696191402b06b9063fe1c970a47f061f742edb72c7c75ec5d3aa03c08456d77c25bf959d9db480107ba042976c3741cbffd15b5b72f74d4c849f7745f1a5cb02dfa2b3c03f4d60740629d86f873ddbb244e5f552846a97a1e0bd570d8be779201ce9d8eed48fae891db6c91431fb144d2624275f91c6f22c85fe10cfd0a92b3f434e93b4a79b02d93e705c24968f5fa189ad686fb1403524f90f01b9264fcbd2eadc954e8f3a6e3177f4601d01debee079610b8dac0b090b007a66b7a2e5baffb70455515ebbab7083b33dcc31ca33add2deb002163dcd357f6782c0ccf0977672220bfe5e0731ae0722c5626e16a3cb3a71dd166524b85e300f1ac54296532ba8d432f4a6972ba432ed3e5924f1cbf42fa666e153f6e872a2f703b1a91c23be1030d1f1441f156f020f310158641744158a6fe453179eab8c449811b017fa955d5f1bc931cd83dddc01d0b897a3b92303333f360693cc9c95a240467b702ed9b0bdfd98ba510171e69ad94ef7b801b188c13a47456d2e9687832edd0a9009040d42a658ecd01acc216c15724320776a4c78db3d5cab16accaa7482ab8920807471cecafa48f0fe2cfa01cd562b57a0553cbdbb9925ea8f051c5115870641c463540fac6e1c48281e7d1555949de79ddaf6a6aba1b6a42f803b212a1a9f21487821011a214591d5496b526d0c81659c9b25c29982cef9e946ca70c059d9c540c70515fdb893bc6e214e508f8bca057d9a10251990f1f67ad4313f3c56f742fe28e17f6dedc42075d4743e86c3f2c2c9daca831cbce4563fe86db69fd0d5c1e26d0ea470dd89216c5e4ccdb3597462e1a346013ef52710119a36cf8e571c599c0ef24a0a29d64744168e25e3eedf509c4b3817acce3b096b680382639bd9740ef9c0a647eabffca597969e31eae37a6423e3e296e3af8d68d050d9e89aaeb438404286deeff989fed0ccdac6623a31ac4e3848709d59f3541bebc96974bc30fd214487bec08df6dfa7d48fe875e62e970c0989f15a1d2fdcc010f9fe5ccad3d01697474a38f257a13a4da6e4b9b089a2deb9a751fb0f37ef0a0441f4369c713842d0c886b2b3479d9f7a298655771bc91f477d9990452faa3f8a3e86e23b112b9c8f42519a8eed33d0bde70e056b15ab7c41cca75d1b27ca003b839b33d0ae1f50b2e5bbc1a80ce0cf63bd296aa65b0dd07c18145771d37c0b82fee2869cae635af8d3dbb9f85a97740692c85c33d6c7d3165818775291f4ff625d534c9b5fcb4971f1b831aec82f19ba06a7fe9d5e90534153cd4bcc33057645632a1f089f7a19712fcac551e191be57e0acf617d9083bc0b3b82dee6c3a4869ed0672008eb9564b667eb990cdae9443e351f08bab1570e601a7edd4b1b89dbd3161cfd6c7ca312170ebfa73cfdc8444640a26d6a41ae83bc97f56648360162b6d5e96538223ec32404fbbb3d826d92f75e854563b7f46c6ecc78342733e19b56c2d5681aaa71e16430ddceb4914775fc509fd891fd81754c7eeec69fe009ba45340f2fdbafa54c3c8804edd8ce555ca7daf1b313ca1dc4b4e71354898460b58635b9adb7b3ff9ddba0418f6ede34c1d062375ec9391fc02d4e606a594d9d1ecf59c909da258efd968a646261a125f3725ddded9a3fb3733adefba7e1ee3070ca806f4661ec87ef879f57640f1e4f11a29f350454a7aa87592a796668681b1fda3d8a0fc72a6215113365cf2416b3b490e52364a7b11692a778f7eaef25e7a4f98bb8b7ac6b36032f13a6157f4e40f48c679dc80888c8ba806a31a5e393594c176506d221e48edcdd3c3a7427aec594704a0ac1a6d6b64ab361e0812757cdc83778c874c87d4bfa244b5252a9063be3bb7093c4445c44d6dd2fd7f4eb672a3cd4041128fca678bfd9a93d05599fe0b6a9594a5209eca924f7d32804fd6184bdeccf", "f0", "cd1155fd3d6cf1026149c0637d20a62750cc7557ef988c3417d74dbfcc5176d8259176f8fc67ef7b2f386a5c8d2f9829281417c41900cd19f16e91e31d7b36b2400c2e0a5a35365aec2df08dc1c74c5491d37d7d8218d8d000d87b278bcb01d117120115d13bce360f94a580736359e80f766cd317c3d94b5069dffe3468aa29d3696191402b06b9063fe1c970a47f061f742edb72c7c75ec5d3aa03c08456d77c25bf959d9db480107ba042976c3741cbffd15b5b72f74d4c849f7745f1a5cb02dfa2b3c03f4d60740629d86f873ddbb244e5f552846a97a1e0bd570d8be779201ce9d8eed48fae891db6c91431fb144d2624275f91c6f22c85fe10cfd0a92b3f434e93b4a79b02d93e705c24968f5fa189ad686fb1403524f90f01b9264fcbd2eadc954e8f3a6e3177f4601d01debee079610b8dac0b090b007a66b7a2e5baffb70455515ebbab7083b33dcc31ca33add2deb002163dcd357f6782c0ccf0977672220bfe5e0731ae0722c5626e16a3cb3a71dd166524b85e300f1ac54296532ba8d432f4a6972ba432ed3e5924f1cbf42fa666e153f6e872a2f703b1a91c23be1030d1f1441f156f020f310158641744158a6fe453179eab8c449811b017fa955d5f1bc931cd83dddc01d0b897a3b92303333f360693cc9c95a240467b702ed9b0bdfd98ba510171e69ad94ef7b801b188c13a47456d2e9687832edd0a9009040d42a658ecd01acc216c15724320776a4c78db3d5cab16accaa7482ab8920807471cecafa48f0fe2cfa01cd562b57a0553cbdbb9925ea8f051c5115870641c463540fac6e1c48281e7d1555949de79ddaf6a6aba1b6a42f803b212a1a9f21487821011a214591d5496b526d0c81659c9b25c29982cef9e946ca70c059d9c540c70515fdb893bc6e214e508f8bca057d9a10251990f1f67ad4313f3c56f742fe28e17f6dedc42075d4743e86c3f2c2c9daca831cbce4563fe86db69fd0d5c1e26d0ea470dd89216c5e4ccdb3597462e1a346013ef52710119a36cf8e571c599c0ef24a0a29d64744168e25e3eedf509c4b3817acce3b096b680382639bd9740ef9c0a647eabffca597969e31eae37a6423e3e296e3af8d68d050d9e89aaeb438404286deeff989fed0ccdac6623a31ac4e3848709d59f3541bebc96974bc30fd214487bec08df6dfa7d48fe875e62e970c0989f15a1d2fdcc010f9fe5ccad3d01697474a38f257a13a4da6e4b9b089a2deb9a751fb0f37ef0a0441f4369c713842d0c886b2b3479d9f7a298655771bc91f477d9990452faa3f8a3e86e23b112b9c8f42519a8eed33d0bde70e056b15ab7c41cca75d1b27ca003b839b33d0ae1f50b2e5bbc1a80ce0cf63bd296aa65b0dd07c18145771d37c0b82fee2869cae635af8d3dbb9f85a97740692c85c33d6c7d3165818775291f4ff625d534c9b5fcb4971f1b831aec82f19ba06a7fe9d5e90534153cd4bcc33057645632a1f089f7a19712fcac551e191be57e0acf617d9083bc0b3b82dee6c3a4869ed0672008eb9564b667eb990cdae9443e351f08bab1570e601a7edd4b1b89dbd3161cfd6c7ca312170ebfa73cfdc8444640a26d6a41ae83bc97f56648360162b6d5e96538223ec32404fbbb3d826d92f75e854563b7f46c6ecc78342733e19b56c2d5681aaa71e16430ddceb4914775fc509fd891fd81754c7eeec69fe009ba45340f2fdbafa54c3c8804edd8ce555ca7daf1b313ca1dc4b4e71354898460b58635b9adb7b3ff9ddba0418f6ede34c1d062375ec9391fc02d4e606a594d9d1ecf59c909da258efd968a646261a125f3725ddded9a3fb3733adefba7e1ee3070ca806f4661ec87ef879f57640f1e4f11a29f350454a7aa87592a796668681b1fda3d8a0fc72a6215113365cf2416b3b490e52364a7b11692a778f7eaef25e7a4f98bb8b7ac6b36032f13a6157f4e40f48c679dc80888c8ba806a31a5e393594c176506d221e48edcdd3c3a7427aec594704a0ac1a6d6b64ab361e0812757cdc83778c874c87d4bfa244b5252a9063be3bb7093c4445c44d6dd2fd7f4eb672a3cd4041128", .Okay}, + {.Shr, "4778b7a3b38e8ed1a2b8f408cd478989b7267fbbdd13f85b99dafac263cd5b546137e5a6dde402bd0de0bbbb97fb5fc494e5f145c43b763da3f012af59dfffb4bf067eb6f20ba88c318db30014c277a14e9d60e0631cce1d1be1b5e6623986cb6d73eeec488439c5e0b979cc775ec26ce4b3644c33a115da59beb67056a79c49e86357ca2d2734feefbfac888c2e763c741a6ecc807e11b1cff43902b65218cb41c5e52cedf0d385e5b594c17710b0b9ac006ced2b520999e5fcae0f22af16bce209a1155d1b0928382a6b84b47c1f08ebd640c6bc078562571eea74a964e4e897702e0f635b47a3d95e789dfa989303eecc8ce4d86e4cb419257238f804be378e5fa71c9775054e8da9029203aaa3ed918033aca405c3702ca940985f58ebe95a46f6a9fb0a3f0a129b2821dd003cda4dcd2d2e74609c7844b2709e111751321c988642224c1d563fef9093ad722457828df6b64910b27e7a57caace2d38265b078dde942ad582a0cbab811ae3f769e4a9089769d0cbfc7fcdc821f8dad91d4f8dffd1b9d392cb6e0ac1ecc4a70dfa2c6231f394447fc7cb8535fe591fe2d34389fcb228d65f4f8e7d56e0a019ab2cb848e95c4e8e021fca804af36c625b078f5a889cc01c876c835a4666f7d479b532a4a6528ce79a4131b890fa7247e4cca996ebfa773541dec15f6b76932bdbd5208abe423149365b58053be1097943942e06cb0babfb515daa708a6f4f8ef0ece6454fa01d8514ff5042aed9e51b55491e8fa1797cbc7b47dedc2afd75e3fc71666822a37827f38cdbf1a09ba9816b15bd673e481bae8e48b361ba3e30a47b56a826fad06f52497ef37b039e95e007340939a54909e1b9fbe91373426b21008f3d1276f06be614c527d777a58b9a40fa12de5be5fabbdca72b4f7eef60f348710e62139d8e1690b914ad6c16a70d3bc3eb80d5ea538ad0ab371b320bffd0e8534b7ba37902ccb82572b2f79f7e58d77ccaf4c30027ed147eaf3975dc02ef3b1e8efb71ada7f300867b9d49ad2e8391eda181e890364e3daa7088ec8e7a159c00dadd7b94da792c38214c185a3f4ecabb884edef2e0434a30d81407b551267964e5d0881940f0b4607909ef9dd32f18f57cc8f4a5f9b40f00306c4a28bbf66304416789cef7f6e75007add1a6990f0d237ef1c1f86c1155376dd028d097c98e65ed1ebed9a1823add55168ea5dbab77f2bfe31a04a10adeb82bfb52d0f354983c4648fd4ac8719d4f71f3e12048fd8b4f9b27c15d0331b8b8b297aa9e7a6d5ee001f6d5df648b785b6e5ec1d9dbfb69509d44eaba4040124d1d1426bd8465d5dbdc6b9cedbd160847bf62a664435cd14498be86468f70b80f55e3063bae85ef261b7b70af1b02cbd89e72af173b9885977f82ff7ba87138f0e3c438857c5988410f67478fbf294211fbaedbecc821417ea9a8e1fd044219fa517bbbb2131b633f08dd3c18055f7e5d5ccac46ee7029534312e915366532ab037e00a86640e520ee504ee4e39c5425c7f61b38ea1d1850bff11dc6e82cc82b32d830b10a71a58164d704404d001e38af47b005f54cefaa4ebc8705ce33e8f55f9bbe451584c7f59b553b42f5df58c4c4dc76213d233f68ef8cb460a56fc11c014e5be56f76b711dc9918b76b2e911c0db4d9c4ad1d37ed13232782c148ee9ca2afa797c7bbdd5558e6003bc29bdcbae33d2f0573b5661932ea848d5b139cac2dfb5d8e562fefe3db6acb5dacccbef5e6d3aa59f73e4844f599135e7cff4bb8aaa2894d5f5ca249307226bac3e84b67d902723112708cec2fc7f339a78d8626c7714c8443efd87d9c8de04dd26bd16bb14adb543c041cbccd386b8de0924c055b2c7a0578d14db64aeca1d660a0d75a6f39f526d608558321f34b2b7dc14ec525951a3b3d10042664aaf67db1b14b72a8cefe0832c3e850d1430150e29731d58f68f6fab267fb76673c0f716a6d61306598332af33c1dd2f03a1b1d35160ebcfed3187429c650b8397b8dbc230b2e571006c7b95e8f9dfc8599f91df7e417ebfe08acfe29a3a4140e7d74e66d292f16b8b0013237ffe01971784a3a96b9247457a9bd94f6afe9ff735265003beec2719d695a9d32", "12c", "4778b7a3b38e8ed1a2b8f408cd478989b7267fbbdd13f85b99dafac263cd5b546137e5a6dde402bd0de0bbbb97fb5fc494e5f145c43b763da3f012af59dfffb4bf067eb6f20ba88c318db30014c277a14e9d60e0631cce1d1be1b5e6623986cb6d73eeec488439c5e0b979cc775ec26ce4b3644c33a115da59beb67056a79c49e86357ca2d2734feefbfac888c2e763c741a6ecc807e11b1cff43902b65218cb41c5e52cedf0d385e5b594c17710b0b9ac006ced2b520999e5fcae0f22af16bce209a1155d1b0928382a6b84b47c1f08ebd640c6bc078562571eea74a964e4e897702e0f635b47a3d95e789dfa989303eecc8ce4d86e4cb419257238f804be378e5fa71c9775054e8da9029203aaa3ed918033aca405c3702ca940985f58ebe95a46f6a9fb0a3f0a129b2821dd003cda4dcd2d2e74609c7844b2709e111751321c988642224c1d563fef9093ad722457828df6b64910b27e7a57caace2d38265b078dde942ad582a0cbab811ae3f769e4a9089769d0cbfc7fcdc821f8dad91d4f8dffd1b9d392cb6e0ac1ecc4a70dfa2c6231f394447fc7cb8535fe591fe2d34389fcb228d65f4f8e7d56e0a019ab2cb848e95c4e8e021fca804af36c625b078f5a889cc01c876c835a4666f7d479b532a4a6528ce79a4131b890fa7247e4cca996ebfa773541dec15f6b76932bdbd5208abe423149365b58053be1097943942e06cb0babfb515daa708a6f4f8ef0ece6454fa01d8514ff5042aed9e51b55491e8fa1797cbc7b47dedc2afd75e3fc71666822a37827f38cdbf1a09ba9816b15bd673e481bae8e48b361ba3e30a47b56a826fad06f52497ef37b039e95e007340939a54909e1b9fbe91373426b21008f3d1276f06be614c527d777a58b9a40fa12de5be5fabbdca72b4f7eef60f348710e62139d8e1690b914ad6c16a70d3bc3eb80d5ea538ad0ab371b320bffd0e8534b7ba37902ccb82572b2f79f7e58d77ccaf4c30027ed147eaf3975dc02ef3b1e8efb71ada7f300867b9d49ad2e8391eda181e890364e3daa7088ec8e7a159c00dadd7b94da792c38214c185a3f4ecabb884edef2e0434a30d81407b551267964e5d0881940f0b4607909ef9dd32f18f57cc8f4a5f9b40f00306c4a28bbf66304416789cef7f6e75007add1a6990f0d237ef1c1f86c1155376dd028d097c98e65ed1ebed9a1823add55168ea5dbab77f2bfe31a04a10adeb82bfb52d0f354983c4648fd4ac8719d4f71f3e12048fd8b4f9b27c15d0331b8b8b297aa9e7a6d5ee001f6d5df648b785b6e5ec1d9dbfb69509d44eaba4040124d1d1426bd8465d5dbdc6b9cedbd160847bf62a664435cd14498be86468f70b80f55e3063bae85ef261b7b70af1b02cbd89e72af173b9885977f82ff7ba87138f0e3c438857c5988410f67478fbf294211fbaedbecc821417ea9a8e1fd044219fa517bbbb2131b633f08dd3c18055f7e5d5ccac46ee7029534312e915366532ab037e00a86640e520ee504ee4e39c5425c7f61b38ea1d1850bff11dc6e82cc82b32d830b10a71a58164d704404d001e38af47b005f54cefaa4ebc8705ce33e8f55f9bbe451584c7f59b553b42f5df58c4c4dc76213d233f68ef8cb460a56fc11c014e5be56f76b711dc9918b76b2e911c0db4d9c4ad1d37ed13232782c148ee9ca2afa797c7bbdd5558e6003bc29bdcbae33d2f0573b5661932ea848d5b139cac2dfb5d8e562fefe3db6acb5dacccbef5e6d3aa59f73e4844f599135e7cff4bb8aaa2894d5f5ca249307226bac3e84b67d902723112708cec2fc7f339a78d8626c7714c8443efd87d9c8de04dd26bd16bb14adb543c041cbccd386b8de0924c055b2c7a0578d14db64aeca1d660a0d75a6f39f526d608558321f34b2b7dc14ec525951a3b3d10042664aaf67db1b14b72a8cefe0832c3e850d1430150e29731d58f68f6fab267fb76673c0f716a6d61306598332af33c1dd2f03a1b1d35160ebcfed3187429c650b8397b8dbc230b2e571006c7b95e8f9dfc8599f91df7e417ebfe08acfe29a3a4140e7d74e66d292f1", .Okay}, + {.Shr, "1862e1bee372aff3dad5d8fb3a1caaa4cefb93efcdeb5723ec95f27fa043d746fb03a4924844c60c3dc10b0f490681c6917fb509ab77b7b313379db2d6b12efe7dac95d3dfa13d217041fb2a401fc4f56bcc58c08e660de9e3f1904a152a0939ac196ca98d6a5705cdceb202815917418f879594c44d8fee645ded9c2933746eb6a127bc8d5e55a020de90ddef3760877d5e461c92131d81edbb157b518e1e56ba771952a086b72c312696d4e089c0ed67eb5313cd054a66121f95d13d084b32392643ebd1feb99bd17a3dd6227f7ec02ef83c16a28633395c28367331aa0e1d49f4dd7e86bbea6f0619d7d76bbb3f988301419c3f0cb224b825d31a1fb61a381f7a1baa4749eb42b686170a426ec9cbe762bb447b5af6ee5df832eb168cac4a777ae2904778b1dc9dca7bf3ef7df7b2e58fc79141b2ce71c332aab8db611f495721167e59b17d81c5a2fff1971ef8a48e93dac755ee45dc4594ec17e6c125bf8532fcc0c5295a2725a8acbfed55f47506ec89f8ae4ed970cee257bfefadd5c049b28952e21ddd48afbc0ee54899e2d8141de2f4f5689282b7148645de8072a033203875d34d3e6bb2a568faf64848e952d35c6cd39c4c4a6983102d647181b6f3457e47a107a8a7c9af855a2ee21155829a6acd4ad58ab877084ed5ab9b8682da6cefbceda68ef362206fe2100618bf720bafd53efcad686512b71fae4ca2234aa92c5e55f2497f9fbf57a91b40ead8d0502e6188085341dceda6b01f110ec7c45ac6b3213f5bb7a259f3aa8b0461cc46b8d1d9f24bb4c6d7248f59df82c06bc2691023f6cb0694cf75435ae6ebaaea87d801344d136250b6cbd28c4e62620d266eed3e4eb134b98492fcb03d4c5cae153c484c97467a510125489bcd17c19c188baefc4ad1048873b2ba40f12fa0ba888698cdd2e417f93a074c8405297de3f67841191e7a7f4a2531670f2dba971cbe180616ec7d941e360d5123f507e014bbcb1788da0e4ae696137cc33f2778967ff3f8211f1bdea78153e7d4fd088f6cf2a5826e6bfa5f42127c6c4699d6b3ad3011b8ec2d4784612793557661dc74cc8406a39eade9cbdc1b2bc11ed13ff8bb99ba5d73387e66ebd084c5834abe859b999c36de2cbb4816cddae24c1052eca5ad179fb0bc108edac0b21671b6529f303fcc9729e3758501f58517cf77ae1c4f5fa56adc06c906bc68f64481effaaacc6a909c7a677e295c0ef1436e34eba87e3fc8f47e7ac5c2c0da208aaeee55066767930237092f40ea204878223b7fe8289b5ca6efc31f118be3dcbc12dffb86cf5c7200f44c2baf08934758b187aa62ddd30df4afb9741fbd60647214a79f9c8846520c1c8ac6b3c8bd0e002483b86965b8dd63cae7435fa3131bbd35d94858b1d63e21af92fecf59e11784deb629118d052b4c0520e99b016d42ed5a8142f4eed6138b9840b0e697c31202c29cb617a00299d9146541caa9cc8dedb2e9355f6c55dcf7c590b21e002f110929c44c5945407fb5c7e2ae4c44a15825a8f876958d050e35a05822e573adcd82f0d53b3dc8760ad98d860d2b2c674816273c7bd9b6c5db072a1d2b1cfcdd2da475948c818c67026fb1fea6ead0f34d25fd69f5bfc07531c51a55379740d9dd36c36925bb186b7c921d445dec0f5e0f0d7882e45a418df5f68b39965dd9b9a1fcb52e06b6b89616ee29a86c8b78a575db09aba3d98b2b4b3169f64446cd878ee62aed8754ab6248ed959d0770deac6d3a45b70d2c6564c210ff3bb0622a17c7f1c78b119b3874d0556cde451397b113bb41b00f69c5df315b33ddfe27f1c04c398ba86594eb1b877d823db40f8b96b27c59cba8f8e7cf60743ad0a4e34e3cb8feac9d4cc31a443f8e4615094193aa0078ddbcee2cc5c7af02a43217d92de0d2365fd6ccf94f67ec56966a2e5c2f8f244bf61c8b6e2864cf0763b4f255bec4e02986c53fadee72c731e1bfbc60fe357318de43e23c95093dc799804dd81a49e0d1bdf9b6bf227bded8b62680b47dea6781ac04ba49fcfe9130c35bcb249c6187a8b3a416819348eeafb8174e0e523c3754a5c6e36d53e0b9440cdb3e6a7d765d946f4915351a79652a64ae682a1917420ad5", "f0", "1862e1bee372aff3dad5d8fb3a1caaa4cefb93efcdeb5723ec95f27fa043d746fb03a4924844c60c3dc10b0f490681c6917fb509ab77b7b313379db2d6b12efe7dac95d3dfa13d217041fb2a401fc4f56bcc58c08e660de9e3f1904a152a0939ac196ca98d6a5705cdceb202815917418f879594c44d8fee645ded9c2933746eb6a127bc8d5e55a020de90ddef3760877d5e461c92131d81edbb157b518e1e56ba771952a086b72c312696d4e089c0ed67eb5313cd054a66121f95d13d084b32392643ebd1feb99bd17a3dd6227f7ec02ef83c16a28633395c28367331aa0e1d49f4dd7e86bbea6f0619d7d76bbb3f988301419c3f0cb224b825d31a1fb61a381f7a1baa4749eb42b686170a426ec9cbe762bb447b5af6ee5df832eb168cac4a777ae2904778b1dc9dca7bf3ef7df7b2e58fc79141b2ce71c332aab8db611f495721167e59b17d81c5a2fff1971ef8a48e93dac755ee45dc4594ec17e6c125bf8532fcc0c5295a2725a8acbfed55f47506ec89f8ae4ed970cee257bfefadd5c049b28952e21ddd48afbc0ee54899e2d8141de2f4f5689282b7148645de8072a033203875d34d3e6bb2a568faf64848e952d35c6cd39c4c4a6983102d647181b6f3457e47a107a8a7c9af855a2ee21155829a6acd4ad58ab877084ed5ab9b8682da6cefbceda68ef362206fe2100618bf720bafd53efcad686512b71fae4ca2234aa92c5e55f2497f9fbf57a91b40ead8d0502e6188085341dceda6b01f110ec7c45ac6b3213f5bb7a259f3aa8b0461cc46b8d1d9f24bb4c6d7248f59df82c06bc2691023f6cb0694cf75435ae6ebaaea87d801344d136250b6cbd28c4e62620d266eed3e4eb134b98492fcb03d4c5cae153c484c97467a510125489bcd17c19c188baefc4ad1048873b2ba40f12fa0ba888698cdd2e417f93a074c8405297de3f67841191e7a7f4a2531670f2dba971cbe180616ec7d941e360d5123f507e014bbcb1788da0e4ae696137cc33f2778967ff3f8211f1bdea78153e7d4fd088f6cf2a5826e6bfa5f42127c6c4699d6b3ad3011b8ec2d4784612793557661dc74cc8406a39eade9cbdc1b2bc11ed13ff8bb99ba5d73387e66ebd084c5834abe859b999c36de2cbb4816cddae24c1052eca5ad179fb0bc108edac0b21671b6529f303fcc9729e3758501f58517cf77ae1c4f5fa56adc06c906bc68f64481effaaacc6a909c7a677e295c0ef1436e34eba87e3fc8f47e7ac5c2c0da208aaeee55066767930237092f40ea204878223b7fe8289b5ca6efc31f118be3dcbc12dffb86cf5c7200f44c2baf08934758b187aa62ddd30df4afb9741fbd60647214a79f9c8846520c1c8ac6b3c8bd0e002483b86965b8dd63cae7435fa3131bbd35d94858b1d63e21af92fecf59e11784deb629118d052b4c0520e99b016d42ed5a8142f4eed6138b9840b0e697c31202c29cb617a00299d9146541caa9cc8dedb2e9355f6c55dcf7c590b21e002f110929c44c5945407fb5c7e2ae4c44a15825a8f876958d050e35a05822e573adcd82f0d53b3dc8760ad98d860d2b2c674816273c7bd9b6c5db072a1d2b1cfcdd2da475948c818c67026fb1fea6ead0f34d25fd69f5bfc07531c51a55379740d9dd36c36925bb186b7c921d445dec0f5e0f0d7882e45a418df5f68b39965dd9b9a1fcb52e06b6b89616ee29a86c8b78a575db09aba3d98b2b4b3169f64446cd878ee62aed8754ab6248ed959d0770deac6d3a45b70d2c6564c210ff3bb0622a17c7f1c78b119b3874d0556cde451397b113bb41b00f69c5df315b33ddfe27f1c04c398ba86594eb1b877d823db40f8b96b27c59cba8f8e7cf60743ad0a4e34e3cb8feac9d4cc31a443f8e4615094193aa0078ddbcee2cc5c7af02a43217d92de0d2365fd6ccf94f67ec56966a2e5c2f8f244bf61c8b6e2864cf0763b4f255bec4e02986c53fadee72c731e1bfbc60fe357318de43e23c95093dc799804dd81a49e0d1bdf9b6bf227bded8b62680b47dea6781ac04ba49fcfe9130c35bcb249c6187a8b3a416819348eeafb8174e0e523c3754a5c6e3", .Okay}, + {.Shr, "cd77b4f33fd64972981f3ff8f95c35e3b06cad5bcd6e92028b241657746f47b36d7437410e9ed00a0c994bb587057224aee681ff0a4c556d34b84d1056c04c7ff59e95b403560e043ef62f8d7bd717cabb55d67008995f10a8733b15e82edcb169cd308f2a5719ce3f119b0ff85ce863246cbab13b124051fb1977dbeea2b71df733fb68bcc25a333e1d3dad7500d46d6af385710fb8fede22dc939ea31bef4440f7f9bfc6db5a3debdd1ca64d970d3edbcbf492afbdb5f40bef44f431e0afd6ef765b3c0e7765b706a1e3f6dcc5afa753f1bec562f799926b99140d55563facf0477ddac25f0ef3e34866a8047b2acbe137064cf8d9ef6e49b182f05e93b59dd2f174ee52603052f4ff5a49b3cbf8ee24ee392dcb05260ad1f94907a5ff885e2fdccea16d189182261e350a69682cc0f0874b756d907ab8f04e74cb89a0455f5f2a31b11f33f7298b1c0772a957c937490d33bea1ce87eb4303a064861590f12c9b337c1ce7fbf5950fd708c775059433ccc0a3bc9531152bbb5b6777741b414e5573e31e9a0873007f01983387c1da273798efdf2941ce3525d137402e3e8049154f5d78ba703aa9b68dd2d4d0d6decfb98a572622639018d88c472b38b1e3c0f5a369f856c830f1c6e420fee9c8969c6f26ed84d0f7d7f83bd433f84c4664dd7e052fc8ce3cb468094017431c905f867394da5bd851c8471bc69f534853e3a9b93a48bb7f6ee66b279dc769abf3cdaa0f536d611c3cb8c440826b230f6f92e0727626406357493c66a74e2e7fa8307033d9932d2bf20f69239ee69ca8545e8e8a89afc01a503d27fd81854c947810be532a55be27d4b4157395d47bac88d9b3c188d8c88ae8aa4093971e224eb704abe4afc4e56984041f69e17008ee14d120d1055c2b6c8d204b70dcd60055d83aba8371298ad77846e6692449c321cfa5cf282ad17bd39a7f29a423a60742b8130dad0e6b245e047ffe92f19d54daf882dc638fd10f82c65830abe69cd349b8ac15e2289575a0e4ed1eb799959aa60caa5566cf960b74fefe14304ecccf59d2e9d6ec5c5a1bf4baace304ef13dc692e2105e875c7c7db7bfcb63433905a61900b9a4a3d8fda79c01d9e93db7db35c395d7f10b7aeabd4cf009869beb467c6099d8c1dbdbe632923bcf0ebb02256f26a02578a3a0d2a120c038ed2a2c7890b36e191041a1543508386a1f43f10e1ae633a40fec08ca3e39ecdb0bd3d5408f090769e6ddd2f7d290f951c9c663d528e40bfb005cd975bdc33f5b94670631e2d28fe762a578422c380c00a0b000a34e436e949c4a84e1256cec94e5b26cb1ebcaf69200d382a879357e993cd087358ad3396630c004942c47d4047dbff7dbf3ad3c6dd5ff61ae4686a29bd6208c75f5810c924b6f95446b9709c68026791bb1f6fd5a944c679191396f98481123057f514bda6d4e5ac7aa5e66c6cf587fd2f543fd64a33c10d388e2614b5d52eca99518dd8903898ecbd65d68ca37995374a45041ad063e46dcb1d546d254d639e318662b5d1f71132fa88178757ee677d5f392a274dcad1689be585df0fd1d18d30c88e79ed3aac1e93fe28a734935f4b289990c95552cd88b97d642e0a4ae799e565639a62d939ca9ea2e304f650b2f289a4be33a0b788304bdfd67cbda04431a838ae92d515f6feb33c592f34a6ee6f0812af95072fb5e207d427fb02b2f270ada6ce379d2b4e143b35fec1c4fcd5827864e19881de1cac5648594e20dc004125dcb706e30e508c22c20a11d29eb55b1ef095f2d58d50bbaa8c01f27bc7d12a2e80d6b592aa40150c63c909b6884d9e7ca672f0bea8df9ed3f2eec600444fd5c9211114c1a45f388d2b11eab8d4b51fa7298343928b56a39ea07e27c89249e84119107b817165282cfb50445852e866bfd5460986e80c2f11f9392a8bf68cd7b1102198e73c9d0e9cd86971348ca19cf878c3404ffdb10735fd91750e028e6d75aadc1634369a614b29007a0fb5e8924f8b0692c94815fe883b87f7138ada12ceeec32631fd3a0001eed00e7cef95edda4a4314966e58350a9136a43c086099485dcac4228be3cf84827644dac63efa259d4e92261a75694ac14ac324dab97b", "12c", "cd77b4f33fd64972981f3ff8f95c35e3b06cad5bcd6e92028b241657746f47b36d7437410e9ed00a0c994bb587057224aee681ff0a4c556d34b84d1056c04c7ff59e95b403560e043ef62f8d7bd717cabb55d67008995f10a8733b15e82edcb169cd308f2a5719ce3f119b0ff85ce863246cbab13b124051fb1977dbeea2b71df733fb68bcc25a333e1d3dad7500d46d6af385710fb8fede22dc939ea31bef4440f7f9bfc6db5a3debdd1ca64d970d3edbcbf492afbdb5f40bef44f431e0afd6ef765b3c0e7765b706a1e3f6dcc5afa753f1bec562f799926b99140d55563facf0477ddac25f0ef3e34866a8047b2acbe137064cf8d9ef6e49b182f05e93b59dd2f174ee52603052f4ff5a49b3cbf8ee24ee392dcb05260ad1f94907a5ff885e2fdccea16d189182261e350a69682cc0f0874b756d907ab8f04e74cb89a0455f5f2a31b11f33f7298b1c0772a957c937490d33bea1ce87eb4303a064861590f12c9b337c1ce7fbf5950fd708c775059433ccc0a3bc9531152bbb5b6777741b414e5573e31e9a0873007f01983387c1da273798efdf2941ce3525d137402e3e8049154f5d78ba703aa9b68dd2d4d0d6decfb98a572622639018d88c472b38b1e3c0f5a369f856c830f1c6e420fee9c8969c6f26ed84d0f7d7f83bd433f84c4664dd7e052fc8ce3cb468094017431c905f867394da5bd851c8471bc69f534853e3a9b93a48bb7f6ee66b279dc769abf3cdaa0f536d611c3cb8c440826b230f6f92e0727626406357493c66a74e2e7fa8307033d9932d2bf20f69239ee69ca8545e8e8a89afc01a503d27fd81854c947810be532a55be27d4b4157395d47bac88d9b3c188d8c88ae8aa4093971e224eb704abe4afc4e56984041f69e17008ee14d120d1055c2b6c8d204b70dcd60055d83aba8371298ad77846e6692449c321cfa5cf282ad17bd39a7f29a423a60742b8130dad0e6b245e047ffe92f19d54daf882dc638fd10f82c65830abe69cd349b8ac15e2289575a0e4ed1eb799959aa60caa5566cf960b74fefe14304ecccf59d2e9d6ec5c5a1bf4baace304ef13dc692e2105e875c7c7db7bfcb63433905a61900b9a4a3d8fda79c01d9e93db7db35c395d7f10b7aeabd4cf009869beb467c6099d8c1dbdbe632923bcf0ebb02256f26a02578a3a0d2a120c038ed2a2c7890b36e191041a1543508386a1f43f10e1ae633a40fec08ca3e39ecdb0bd3d5408f090769e6ddd2f7d290f951c9c663d528e40bfb005cd975bdc33f5b94670631e2d28fe762a578422c380c00a0b000a34e436e949c4a84e1256cec94e5b26cb1ebcaf69200d382a879357e993cd087358ad3396630c004942c47d4047dbff7dbf3ad3c6dd5ff61ae4686a29bd6208c75f5810c924b6f95446b9709c68026791bb1f6fd5a944c679191396f98481123057f514bda6d4e5ac7aa5e66c6cf587fd2f543fd64a33c10d388e2614b5d52eca99518dd8903898ecbd65d68ca37995374a45041ad063e46dcb1d546d254d639e318662b5d1f71132fa88178757ee677d5f392a274dcad1689be585df0fd1d18d30c88e79ed3aac1e93fe28a734935f4b289990c95552cd88b97d642e0a4ae799e565639a62d939ca9ea2e304f650b2f289a4be33a0b788304bdfd67cbda04431a838ae92d515f6feb33c592f34a6ee6f0812af95072fb5e207d427fb02b2f270ada6ce379d2b4e143b35fec1c4fcd5827864e19881de1cac5648594e20dc004125dcb706e30e508c22c20a11d29eb55b1ef095f2d58d50bbaa8c01f27bc7d12a2e80d6b592aa40150c63c909b6884d9e7ca672f0bea8df9ed3f2eec600444fd5c9211114c1a45f388d2b11eab8d4b51fa7298343928b56a39ea07e27c89249e84119107b817165282cfb50445852e866bfd5460986e80c2f11f9392a8bf68cd7b1102198e73c9d0e9cd86971348ca19cf878c3404ffdb10735fd91750e028e6d75aadc1634369a614b29007a0fb5e8924f8b0692c94815fe883b87f7138ada12ceeec32631fd3a0001eed00e7cef95edda4a4314966e58350a913", .Okay}, + {.Shr, "993803b52380ac6fd9b30603f62848ad05e4a989cf15c3d6553f14b1607cd9e3a49cfcf028f653b77d4c0aaeb30c3eecd47a24abea0e46444cb8d28b9db1f7465520de625430a873f38795edab91325b274c819cf1edd33432c7b89274e4a94a441dd23e0158d305827525c8b96e216f0bf8ec35bbd704c2969bcfc676191bfb3443e4037ac0bda53a39a3fe9b92ffd9572e32f79b0585430687f5d7d1af97c0d39d83b64eca79ace01576a57f2fc022bdbb904aab7ff98b109babc3ced5f50bc5fc30245265e1789136d55d94fb5d91c0669c5a4f19045f87ec6bcd043663cd7011e78f60fd1f7823ea38173dd7023e13f170b2aa8a7c4fec68f59c40ded21f325734242793ed8b2a3300bec43fb6f3e9d9cbdbad575c6264559599d4a750c330f440d3768fcf818e137125f9bb81bf1df8af69f5067d2711c3a8545283b895c9039f072348ef0284b26dcfc65c570305b9488ab576fe103e1efcac8b31d64878c6e3346f847299cea1f81eae0a07211e09649d722dd2658019d61f7d204b069f3e731f99e9417fba28a270845e54e66e9e4221fe247257b52c4a91a35d031a672101b79286b35f80858721ef4d91c82864659321dd5de387b10042d0317bec7e0d62119126c3b01c366fd87be512e707701d4f1181904e6ca7e2d1103fcd7b68306839b6e8c75ea32060549d24a3aad22b7f68117c3c48bdd60dd3187f51352005b142fb3b92d2337fc5bc0c5fa09491b82d60687285bb13ea0562782862477856a67023fd7ade682ba3ca36eb9898fb1b33f9eab71c6beb20fd037b32e2d8e91a73c6679eac95f0730b711a644702ad021d9262201e74c0fe4d6ea982cbd64257ba74bcc6739a6ab0a7cc09f50bd5a0b1fa5568c20f3e06ef8896321ecd7d364deee60bb9d316c29ad88fe1d429334a01023c6b2a5090ab2b2f68147aecc9ff3a70314e319653d7c6211c9e01316b9123de9526610f4d7aa5f4dafe6b086222f02ce23e608f7e1f5bb957b1793515a81cfa497e47ceba3d6a4d7e6006b7b115e38cf29bc6d822962ef63366ea1043e729841c7bf96242a4fd447eb1decbd357e9dcb00ad003abfcb9d0a598592b1dadd386bfe545607b1f230b82303bedb7f4441a3c6102846c5d0a8fd6ce1ee880eeb23cc5dcff1dc9bdc11ddf3a6fb5a4008bb3b1ee6dad42205844bcde94d88bd971b90a0d1ae4e9d4c4e4623eb32a2e7d1f5746c93d86545fda8f5513fa081930f6732935e6a4595ad2338798fb7ad2e6d09a9fb5820650188b7da8ee5a41f7f06554630ce7ae72a3e7bdc34231607ecc0d0677dba5dec7cf0d0029ffc87da8a908d2031adc188dd9f4df5b09adfec1d78f4edadf687c10700a74bf7738b71c79f66c0c96170962f15b56f8e77bf3d22c4ad90b8b38d216f23513222698de6969bea991149fcd361e7ca7413691aaf2e01fe420c8f1b702e7c2a74366bdf723cb568af929086ca482d2a613f53f00779dc794bd1deee6c452a49fccb793fb9538b2fa9e9567952954c96b0f79411ad6fef89b4f71fd1d9b65f07cdddec92e7d35e9d7758581263464206e94021791cfc37e5f124bae9e8ef5c308db7ed38897ded290a5807fcea2d21ff6d8438baf802abd4c93282e7a18ceb7b491e2e38f534edc3ce492a554b2912583541bd28b2b9acfa0f04d241c5b6010b09c5ba3b4e736c2b00c19790381183b1c1fd0ee7a9efd38cc88091701c1b8690e5a8f91148d24ba50176c13c1d3635428b5386cf94bded7a9dc3b8a6c57e19b152ad131eb7bf101559e98d6bcdd8b121d672524cc15ad5d788aae2b4a1c6b5441ebac338286bdfc8c023ba670a8a5e1a075bc54953f6ea895ab6e422e81aa082c8181d6335b444003172173ade71540530ff4a31bd11fc77b4aade6d8ffd99bb0b40ebd5b7e645623f1c17ddc5217617a91c0f68039919fa1f7c5fee1c366f839c0e4ba1c45638123ca0ef9acf12b521bee3167129e7f38a52b43b97c2aefd00b4600656af9703e6e39cce3ae97846ef6c3aa1a6699e0d34ead8dbcfe3f39126e149061696707924a99c6b3b7e6f39b0b4bc47e9c8020ba94b14eaedd401ff251a078135a2198ea7a0c755e1ade10290773", "b4", "993803b52380ac6fd9b30603f62848ad05e4a989cf15c3d6553f14b1607cd9e3a49cfcf028f653b77d4c0aaeb30c3eecd47a24abea0e46444cb8d28b9db1f7465520de625430a873f38795edab91325b274c819cf1edd33432c7b89274e4a94a441dd23e0158d305827525c8b96e216f0bf8ec35bbd704c2969bcfc676191bfb3443e4037ac0bda53a39a3fe9b92ffd9572e32f79b0585430687f5d7d1af97c0d39d83b64eca79ace01576a57f2fc022bdbb904aab7ff98b109babc3ced5f50bc5fc30245265e1789136d55d94fb5d91c0669c5a4f19045f87ec6bcd043663cd7011e78f60fd1f7823ea38173dd7023e13f170b2aa8a7c4fec68f59c40ded21f325734242793ed8b2a3300bec43fb6f3e9d9cbdbad575c6264559599d4a750c330f440d3768fcf818e137125f9bb81bf1df8af69f5067d2711c3a8545283b895c9039f072348ef0284b26dcfc65c570305b9488ab576fe103e1efcac8b31d64878c6e3346f847299cea1f81eae0a07211e09649d722dd2658019d61f7d204b069f3e731f99e9417fba28a270845e54e66e9e4221fe247257b52c4a91a35d031a672101b79286b35f80858721ef4d91c82864659321dd5de387b10042d0317bec7e0d62119126c3b01c366fd87be512e707701d4f1181904e6ca7e2d1103fcd7b68306839b6e8c75ea32060549d24a3aad22b7f68117c3c48bdd60dd3187f51352005b142fb3b92d2337fc5bc0c5fa09491b82d60687285bb13ea0562782862477856a67023fd7ade682ba3ca36eb9898fb1b33f9eab71c6beb20fd037b32e2d8e91a73c6679eac95f0730b711a644702ad021d9262201e74c0fe4d6ea982cbd64257ba74bcc6739a6ab0a7cc09f50bd5a0b1fa5568c20f3e06ef8896321ecd7d364deee60bb9d316c29ad88fe1d429334a01023c6b2a5090ab2b2f68147aecc9ff3a70314e319653d7c6211c9e01316b9123de9526610f4d7aa5f4dafe6b086222f02ce23e608f7e1f5bb957b1793515a81cfa497e47ceba3d6a4d7e6006b7b115e38cf29bc6d822962ef63366ea1043e729841c7bf96242a4fd447eb1decbd357e9dcb00ad003abfcb9d0a598592b1dadd386bfe545607b1f230b82303bedb7f4441a3c6102846c5d0a8fd6ce1ee880eeb23cc5dcff1dc9bdc11ddf3a6fb5a4008bb3b1ee6dad42205844bcde94d88bd971b90a0d1ae4e9d4c4e4623eb32a2e7d1f5746c93d86545fda8f5513fa081930f6732935e6a4595ad2338798fb7ad2e6d09a9fb5820650188b7da8ee5a41f7f06554630ce7ae72a3e7bdc34231607ecc0d0677dba5dec7cf0d0029ffc87da8a908d2031adc188dd9f4df5b09adfec1d78f4edadf687c10700a74bf7738b71c79f66c0c96170962f15b56f8e77bf3d22c4ad90b8b38d216f23513222698de6969bea991149fcd361e7ca7413691aaf2e01fe420c8f1b702e7c2a74366bdf723cb568af929086ca482d2a613f53f00779dc794bd1deee6c452a49fccb793fb9538b2fa9e9567952954c96b0f79411ad6fef89b4f71fd1d9b65f07cdddec92e7d35e9d7758581263464206e94021791cfc37e5f124bae9e8ef5c308db7ed38897ded290a5807fcea2d21ff6d8438baf802abd4c93282e7a18ceb7b491e2e38f534edc3ce492a554b2912583541bd28b2b9acfa0f04d241c5b6010b09c5ba3b4e736c2b00c19790381183b1c1fd0ee7a9efd38cc88091701c1b8690e5a8f91148d24ba50176c13c1d3635428b5386cf94bded7a9dc3b8a6c57e19b152ad131eb7bf101559e98d6bcdd8b121d672524cc15ad5d788aae2b4a1c6b5441ebac338286bdfc8c023ba670a8a5e1a075bc54953f6ea895ab6e422e81aa082c8181d6335b444003172173ade71540530ff4a31bd11fc77b4aade6d8ffd99bb0b40ebd5b7e645623f1c17ddc5217617a91c0f68039919fa1f7c5fee1c366f839c0e4ba1c45638123ca0ef9acf12b521bee3167129e7f38a52b43b97c2aefd00b4600656af9703e6e39cce3ae97846ef6c3aa1a6699e0d34ead8dbcfe3f39126e149061696707924a99c6b3b7e6f39b0b4bc47e9c8020ba94b14ea", .Okay}, + {.Shr, "70b2d450bca9707fdc1b6639a1263eba42aecf5f03499f9621e1e2649be4b73c3a7ec296d67b64a6bd64d5f69bc13119433e783f4b8fbb0c8cf345aa88486f190a8c884b4f4ff6ce7b862b80b2dedce4865c0250cd99a603e4a1a55f544b5895bc17abe2b4c5f124981fb8b94707adef19273a246f97f148d60fecb4db94ab2ef1876a7a8c4cf5daa2b874bee5eb00d19bf380269b2bc0fc6c24846a709496b9f5fe15c8f50c924a0005bfad21056cea465f1638d360568bd2cf19fa34c2222b6d31310ab9be16c71be57a101525cf21f3703c4e834211942beb863c3cc18768fc2ca4f3aa921a7cfc8ece943e405821369625bca40ae4a4a422cb2f8a28b1bb106ba1fcbc3f25ec754d33bb11b5d8f1c4b0fb982fe8e62d8de2704d7f62ca29ed278eae225f97022f7ffe230de80fc714b4d66ea457e04d2a1618c442508bd58efede284c654709fc285ec7285ee79a6f3bf42d8f619050d3b08fd495858205c329a1f5ef5ffd7ae2a100c7f32bde6820019ee55d426e6496021f1c3b220405a90d16657e2f011285af5b46ef7ba10267103dc73027ad8fe1787ad4188b587413cfe1e51f4fc3ebc84472f675ec1805d8682d9472449dda6d4f97b300337836b1e99dfce4d606c8dd8b750d8e794c663b13f3e6ff0116775144cf52a4558e47e2564cbe286c3ec5f1dd0d84b9539daaafc3e18fcdfb23c60609e542687fa63cbabdde94fb2c5c56e7fd5138e3719ccc96b12d5bc684d28ae93ebef21444af1ac306be59f36906febbd833ec38dcad59c13710283d632881d31bac45a5e3cc984d0d61809c1fe0d8119798fd1375bde6e86ec0257cc2aa9ccbd24d8565070c1061e82d05c07b8ae09ad227ab97fd49b306062b51b54ad22adc1ccf3b850b739901b74ddccb8c2b80f2c0932064f7c3af66195d520b27cbc0b17d974880a288404490f28e639472ebc78097836b8211a1c6294aa2ca1205cd389e3b3b8b1188bcf8322fe964b0eb1b68d2a4dc5ade3c952e6bf1a399611be0ffcd5cbee2fa170100093d6fa17576e1de5ac3a2bc8d6953427080067f3046c6cd702697a1fe2291a91993372d88c0b1cf85b1eaffa90ad6158e8894a1b88d9f3ec793bf6f8dfbab9bfc204d09fbaa48694d49202547cd48d5e670b2e5a460bb7a19520c0427747f77b885fc1fd85918399c0f893b4a19d19c458f27817933fbbc1df49e0fcc438889560416dbeb3903513ec872ab54f778a404d59198017529b2c5782326ba9c1e14e59463fa4a5008e09e07fe323680ef77b13c5c1f1eb7302e3d5d1470039e36ace9e84429313642478cd6eb8603633dac84ace25504d1ee7719f2f724490eb9e1fc91a1ef2be49c4f50ff222de3bf1482cb2797029ed4cd58e324a285c662d84c66b701124ebe519c5cccb0579dc01dda46f452cf023156f14aa014a21e6d05a8ba946f038713ff51320e975c8ee196e512f06c6286770e6ab61dc3fa153b63808044746b48cb3ab3b443f8e20a28d72a21b8fc8487f4c48cf4e08e5a8d2a7b2e652337bd4a4a86a67ab25fe0f05e189c9e2b773142ea6e43d8335d5a500a12dc4b4f595f21caa7df4c6dda7ebe67296da1360783066dd27ad79d2e4726eceb9d58973b67f4bf8373123ab6dc68cc4de4d869372c6eba60f4e26c9d148d60d3f178b0ce9fc5d2e76469ac4335b0a59d1ee46c975682967a65e8beff17672054996fe3d9038a20b3816239d37b57b9a9e3fb9df71e964bf6a7a06efb8e962747cded064b6d58904e7df41e0d01fd358cda5455ab0a6d816b530a049a4e1bcc60db8d8570d2a00d4e35be1055c435206221897567411333fc9ffcfddc47e5bbc6544771a75cf5fb1f456ad3e6153f3e8e9486daf1d1fd2fd196e48b03ab4df1c790d37dbd1eeeea9dddfda56404c7a354137a227d293352dc4c2396bf5d94a2b13f9275f24e32281687444c9fc972b4c7c921cd75530885cdfe0cbd7f4e42bfd7251576d5d78f0b0d1f07a74613abbf01aeb05174a72d2d07126b08abea11923ec8858d8b56cb02883d883005b02e0abf8784f9c440d764263958095595dc5ef0c1d8bb72ab11211f96705314e65625ef3a09c6e31f391be0d3e7bd40", "78", "70b2d450bca9707fdc1b6639a1263eba42aecf5f03499f9621e1e2649be4b73c3a7ec296d67b64a6bd64d5f69bc13119433e783f4b8fbb0c8cf345aa88486f190a8c884b4f4ff6ce7b862b80b2dedce4865c0250cd99a603e4a1a55f544b5895bc17abe2b4c5f124981fb8b94707adef19273a246f97f148d60fecb4db94ab2ef1876a7a8c4cf5daa2b874bee5eb00d19bf380269b2bc0fc6c24846a709496b9f5fe15c8f50c924a0005bfad21056cea465f1638d360568bd2cf19fa34c2222b6d31310ab9be16c71be57a101525cf21f3703c4e834211942beb863c3cc18768fc2ca4f3aa921a7cfc8ece943e405821369625bca40ae4a4a422cb2f8a28b1bb106ba1fcbc3f25ec754d33bb11b5d8f1c4b0fb982fe8e62d8de2704d7f62ca29ed278eae225f97022f7ffe230de80fc714b4d66ea457e04d2a1618c442508bd58efede284c654709fc285ec7285ee79a6f3bf42d8f619050d3b08fd495858205c329a1f5ef5ffd7ae2a100c7f32bde6820019ee55d426e6496021f1c3b220405a90d16657e2f011285af5b46ef7ba10267103dc73027ad8fe1787ad4188b587413cfe1e51f4fc3ebc84472f675ec1805d8682d9472449dda6d4f97b300337836b1e99dfce4d606c8dd8b750d8e794c663b13f3e6ff0116775144cf52a4558e47e2564cbe286c3ec5f1dd0d84b9539daaafc3e18fcdfb23c60609e542687fa63cbabdde94fb2c5c56e7fd5138e3719ccc96b12d5bc684d28ae93ebef21444af1ac306be59f36906febbd833ec38dcad59c13710283d632881d31bac45a5e3cc984d0d61809c1fe0d8119798fd1375bde6e86ec0257cc2aa9ccbd24d8565070c1061e82d05c07b8ae09ad227ab97fd49b306062b51b54ad22adc1ccf3b850b739901b74ddccb8c2b80f2c0932064f7c3af66195d520b27cbc0b17d974880a288404490f28e639472ebc78097836b8211a1c6294aa2ca1205cd389e3b3b8b1188bcf8322fe964b0eb1b68d2a4dc5ade3c952e6bf1a399611be0ffcd5cbee2fa170100093d6fa17576e1de5ac3a2bc8d6953427080067f3046c6cd702697a1fe2291a91993372d88c0b1cf85b1eaffa90ad6158e8894a1b88d9f3ec793bf6f8dfbab9bfc204d09fbaa48694d49202547cd48d5e670b2e5a460bb7a19520c0427747f77b885fc1fd85918399c0f893b4a19d19c458f27817933fbbc1df49e0fcc438889560416dbeb3903513ec872ab54f778a404d59198017529b2c5782326ba9c1e14e59463fa4a5008e09e07fe323680ef77b13c5c1f1eb7302e3d5d1470039e36ace9e84429313642478cd6eb8603633dac84ace25504d1ee7719f2f724490eb9e1fc91a1ef2be49c4f50ff222de3bf1482cb2797029ed4cd58e324a285c662d84c66b701124ebe519c5cccb0579dc01dda46f452cf023156f14aa014a21e6d05a8ba946f038713ff51320e975c8ee196e512f06c6286770e6ab61dc3fa153b63808044746b48cb3ab3b443f8e20a28d72a21b8fc8487f4c48cf4e08e5a8d2a7b2e652337bd4a4a86a67ab25fe0f05e189c9e2b773142ea6e43d8335d5a500a12dc4b4f595f21caa7df4c6dda7ebe67296da1360783066dd27ad79d2e4726eceb9d58973b67f4bf8373123ab6dc68cc4de4d869372c6eba60f4e26c9d148d60d3f178b0ce9fc5d2e76469ac4335b0a59d1ee46c975682967a65e8beff17672054996fe3d9038a20b3816239d37b57b9a9e3fb9df71e964bf6a7a06efb8e962747cded064b6d58904e7df41e0d01fd358cda5455ab0a6d816b530a049a4e1bcc60db8d8570d2a00d4e35be1055c435206221897567411333fc9ffcfddc47e5bbc6544771a75cf5fb1f456ad3e6153f3e8e9486daf1d1fd2fd196e48b03ab4df1c790d37dbd1eeeea9dddfda56404c7a354137a227d293352dc4c2396bf5d94a2b13f9275f24e32281687444c9fc972b4c7c921cd75530885cdfe0cbd7f4e42bfd7251576d5d78f0b0d1f07a74613abbf01aeb05174a72d2d07126b08abea11923ec8858d8b56cb02883d883005b02e0abf8784f9c440d764263958095595dc5ef0c1d8bb72ab11211f96705314e6", .Okay}, + {.Shr, "4fdced961a9275ba41cfc440ae6b92b29c31a203764f19ca2511a46844c8768db91099f693a629775b0e16403d530468c5f858c0a52a1d238477643bd06c40971284f5857110b93043e6a60bcb5beb707e536383824bff582e2e64fa2a674c8de8dbaeb40e66aa19b32f940b44d2b896173df6e8fc2fa24035490c4040bc0e6a725d0f864150db1f5f2c727cd8a328f6836955462762402a318c7458004f4c4b7868662a5acce9680199ee042fe3b85e503b47a98ce487a01db2d8e8ee11ace87e682aa563621ad3c7fe719f9ba88b8e9859e11a9a6f8a30239d1014c08e10f5c0380a60c84cc9c64000876780b90f4c32f518c5c7cfc691f24ea91cf11fe86573492185d9a2759e59ab1960b1fb813720327b957bc90707552bbb0d50770946a9616d44b459d583184095996a3a07a8bb4501b1eaa630ab8e26bb1f8ba1bf98b4ba4b918ffaf036b25b57b847c133e0c3b8f302ddb0edc01c8325d18c6e356044ad3b86706b83c2a6d056f076c5072b026821debd88e8c34a6487045b872ac70541737dda3722d54596c617141e224236101f9b459b1d741c82683513ce2ce4f527a107fcef0054c2df26eba90315dd1dd700bc4d871de96b99c129327ed9335276ddf71ffadf8d2a18d4221a4c30f4ce7ca58165767faf7dfea15bd205f4405a087170ad1181df0558f3a97e7b751e8fd2d3dca2738b190974b4d5b6cbcc943e28035ec697f33acc9bf57625b2d21ef34eb59d27c21d97b1f638af5933984b7a1caa95067f5ba887f30f3464211aa6249352f1837fdeabf39f224e3909d49f311dcbaf38087b9873a79701aff34e4ad25c6f44de403bd365a265ef5504a40df84d0072a01b5260b08161d5759a6057f053304e07307471d50983c6fb50eeadba12c7a6ee201888e13f45bb2103f914988300118db565f7d3e57638f47fc58bd971b098754593a0b93fba9ad3d16e78e418499dda3f00ab7f581b66351d776a463d16e03ae4a480444ed636ff74d06878cdbde2a63210c67c89187fa2065ead23dc07356c4f08dbf22b7cadbb1f400c3b0060b58681be9438dce9ed07ff669b6d21b5c8ad1797cebfd9627dc92a3ad38d973cfb07735333f196b35a2371ee63c71ebbddcdd0dfd49af5e3de5ed55d37897b9aedeb75f5adc60d22272ad5c261b6f35dc0e2e52aa7c673edb422ac3461ae1d91ba6b943b083561e644e5fda1e290283873c6c8f7d953e97b8df92b9f3969f438487eee55ea317044065e17825135155a0fb1818b805ca430b208e9263b54620d57f5b22a0d98280752906633caa19ae066b006176bd40f77bd635fa2cb72ca1f32941e7d53ec4ca0ba08bf8d0ffd56d703e486d334f57046b82f06bc7e59cd2f0e46bd7501d1415be469666d11483f84917fad769912a0652f8732cf4be2c90fd9e127cdfc50875902e8afccae3d496bd31a351155f1a7cfdfc2386120583fa089a16c6e4f027d8f40d03b08b66bdb3674102c804ea32ac604271255f017785574b9be0a3e542eb19398b976ccb17a25b753819b740a6d3d850ee4d19f34167b1eff6aa74fdf89eb3889d514a6992fd718a1593054288f7d6f5b8da836eea43cb002ca8bac9552670fd9d95d5ee9b1ad13b0f5ce815ceb0c52b39569a362e4fa3aee2d4e34ea715d88fe328ed2a1d33643943e92cab85885e0bea1651ac301f1b02b546f1be8cac07fd70f55654df82e0b4a81fd6b6e13544d62361bb22ac6221316011c448a2af812b5a59063291c43d12b7b289cbf68c95f0189eee0b0b2b40f238723a3e1e790e72d1709bf4541c6fc9ae5ebd1200a48420826911b4d7be747d6043b328ed96a173d483bc50f5197cc71d7cd4a99698a0905778bd90d4a2febf8e6fc2de2e52d554512efff3498fcf60887a64d7942b97ba163f43172d578ef43ab4b6b729ebcf59e32ff5bc262be2fa70d119d0d6557e549f21ea2d802b9f582f6bf997d097d76c1ab4945b11f40b9746138a79103cba236981cc3a9447684da21ab30ff8495960dc4caa08343513fd195624f0248b212389b94fe07b983bfa4e838555bcb11bb1eeaabb142094033c46fc1ed1e2ac1099b8b4608f38519174cf6b94ff0962287", "21c", "4fdced961a9275ba41cfc440ae6b92b29c31a203764f19ca2511a46844c8768db91099f693a629775b0e16403d530468c5f858c0a52a1d238477643bd06c40971284f5857110b93043e6a60bcb5beb707e536383824bff582e2e64fa2a674c8de8dbaeb40e66aa19b32f940b44d2b896173df6e8fc2fa24035490c4040bc0e6a725d0f864150db1f5f2c727cd8a328f6836955462762402a318c7458004f4c4b7868662a5acce9680199ee042fe3b85e503b47a98ce487a01db2d8e8ee11ace87e682aa563621ad3c7fe719f9ba88b8e9859e11a9a6f8a30239d1014c08e10f5c0380a60c84cc9c64000876780b90f4c32f518c5c7cfc691f24ea91cf11fe86573492185d9a2759e59ab1960b1fb813720327b957bc90707552bbb0d50770946a9616d44b459d583184095996a3a07a8bb4501b1eaa630ab8e26bb1f8ba1bf98b4ba4b918ffaf036b25b57b847c133e0c3b8f302ddb0edc01c8325d18c6e356044ad3b86706b83c2a6d056f076c5072b026821debd88e8c34a6487045b872ac70541737dda3722d54596c617141e224236101f9b459b1d741c82683513ce2ce4f527a107fcef0054c2df26eba90315dd1dd700bc4d871de96b99c129327ed9335276ddf71ffadf8d2a18d4221a4c30f4ce7ca58165767faf7dfea15bd205f4405a087170ad1181df0558f3a97e7b751e8fd2d3dca2738b190974b4d5b6cbcc943e28035ec697f33acc9bf57625b2d21ef34eb59d27c21d97b1f638af5933984b7a1caa95067f5ba887f30f3464211aa6249352f1837fdeabf39f224e3909d49f311dcbaf38087b9873a79701aff34e4ad25c6f44de403bd365a265ef5504a40df84d0072a01b5260b08161d5759a6057f053304e07307471d50983c6fb50eeadba12c7a6ee201888e13f45bb2103f914988300118db565f7d3e57638f47fc58bd971b098754593a0b93fba9ad3d16e78e418499dda3f00ab7f581b66351d776a463d16e03ae4a480444ed636ff74d06878cdbde2a63210c67c89187fa2065ead23dc07356c4f08dbf22b7cadbb1f400c3b0060b58681be9438dce9ed07ff669b6d21b5c8ad1797cebfd9627dc92a3ad38d973cfb07735333f196b35a2371ee63c71ebbddcdd0dfd49af5e3de5ed55d37897b9aedeb75f5adc60d22272ad5c261b6f35dc0e2e52aa7c673edb422ac3461ae1d91ba6b943b083561e644e5fda1e290283873c6c8f7d953e97b8df92b9f3969f438487eee55ea317044065e17825135155a0fb1818b805ca430b208e9263b54620d57f5b22a0d98280752906633caa19ae066b006176bd40f77bd635fa2cb72ca1f32941e7d53ec4ca0ba08bf8d0ffd56d703e486d334f57046b82f06bc7e59cd2f0e46bd7501d1415be469666d11483f84917fad769912a0652f8732cf4be2c90fd9e127cdfc50875902e8afccae3d496bd31a351155f1a7cfdfc2386120583fa089a16c6e4f027d8f40d03b08b66bdb3674102c804ea32ac604271255f017785574b9be0a3e542eb19398b976ccb17a25b753819b740a6d3d850ee4d19f34167b1eff6aa74fdf89eb3889d514a6992fd718a1593054288f7d6f5b8da836eea43cb002ca8bac9552670fd9d95d5ee9b1ad13b0f5ce815ceb0c52b39569a362e4fa3aee2d4e34ea715d88fe328ed2a1d33643943e92cab85885e0bea1651ac301f1b02b546f1be8cac07fd70f55654df82e0b4a81fd6b6e13544d62361bb22ac6221316011c448a2af812b5a59063291c43d12b7b289cbf68c95f0189eee0b0b2b40f238723a3e1e790e72d1709bf4541c6fc9ae5ebd1200a48420826911b4d7be747d6043b328ed96a173d483bc50f5197cc71d7cd4a99698a0905778bd90d4a2febf8e6fc2de2e52d554512efff3498fcf60887a64d7942b97ba163f43172d578ef43ab4b6b729ebcf59e32ff5bc262be2fa70d119d0d6557e549f21ea2d802b9f582f6bf997d097d76c1ab4945b11f40b9746138a79103cba236981cc3a9447684da21ab30f", .Okay}, + {.Shr, "1a0a5b453c877ec81f6a23a01b452fcd90e20bd6b6a9a08798222403f556b269c62048513cd1c57e9be2e17de90f1cf4725f0bc3990b0de84748d4ae569a55f0f5e0a71a7e59aecd9e2b139ca32636c3615239f0e0ef13d1dba91ebc61ef408fdea858a992cf132d47dfb97ad09c6f893a88a6591a4d2b2a89a42fc1284b7e2d6305b5c2f8a8d5b56a50219ffae0d98c4a3c83fdbe3ba84250e5e048491b145afa4a392f1ee38e742874d3c5e001bc30083db2802f727d18c6e1236e369a25460b2a8767a275dbd9376efbac5dfebec2277b88364f306eb313c99de0ede2fed752b9c375019364d7738579117dcd1287150be559415b48e9b4b62c3ffb5eea6adbbdc0c84112e8dcd88842f2ad69d3380330582e1299d56f7921aa075bd7fc72e421d077d09569c71a8e835cf7a043be5eed181860ef2e72c29825e391db4ced0f10183cd963f6ddd524da525f07ece60fea69b4ac47df9afbb71ea6ac50fa3ef21b4586cde5ac5f8b6d1b42512b4d3a65679a6d5a2c8e38791195136b30a2cc445c24159a8ea7e4d447af3421577b322dc030393a4807781b2d6dd98a120a6d94111d0dc3ebb13a786f2a301e283a2b4e1937fb5459f0147c087212ddc7e48cbc11ad271929490ff2f70bb4cabe03ca8fac31ac649fe01b0ea818e9eb6a65fddc23c0325855a9022282691f211f30104261c4ff2fe5cd243f8087027cf8d2080c68c21698763b94bb6a45d386b7177bfa9c469475c97e941f43bd78a6916688c7233fd3cc6ec3ede49d10d7e15a6815f9e200f891b57a7f1a887f4c1a0a11834988593027a4e27a3ed9a20f040620113627b966fab532429d16898190d2594b9a11fabf44ffc7ee2e3555b65ecb552f17b5788d8e12c56d7bc8847eb49a463b3398931f68fb07010839eed4fe0d1b7b74d67ae65117a2945d911b5d15b91c2c56c58ac99b523cb814a3ad1e9351b15fa957d4fdddeec5dbc787fe91675e8e77872976e9ee025e4cacddf10af98aa9ff4344936b50892d17a5c248d0fb69bc53c1a9a325d59c103cc3004f46208f27a506c1e03d84c4696dd4284f620a8e2a127f35288be641251dd2590bc0fafcf317c4e62fe50b58e8ba5c62efef001c6cd672194eb705689637b8a7328eec1849bc144cbb13a53329da4a25c7110b323c93f150da62627c81741769d2fc2359e616b8f06538627843632b6652a7e1448e0555725900df0b07ccb020ddcc5af3d4a277229912e3a9ef2a2cce8c1e5b3275890bf8614c435f9226e081d32568b6eec0d18edf3d8f5263257f461f2630a0a05e346c140a917204d97ae485b9d244c8a23d22178af6bc6a4323a02bd246f54fbc8f9c359d3a98fd3f41b9e05a8fa1045511002776b3358b28b73c8a85050d3b0b290a11f48d90fbf8f1e3c734327fa0df2558ad8510b3bd0d0b03dffe4e612b2bda53cbe431e98289ab5d9cefcd54b970e8d8b867b3c8b277ef10f035b50c6e7a048c453bb4ce24e40e9902606f2db0c5862a8622fee83b1bcb0211b24ac38f9c4fcf2730e77ba8f8c034c62bf82495a52666cc5cf46e76da03b24141c89bb6d219d092dcaf0122fdf14312b73d70fcb4b96e78378dbb1ff35a690b4b240e11b551b160eea8a94d5e020ceb683d576b3dddac5c02fdefbad6c5b136440b4c05562560c453e661e2020b6a24f8d265e5c9efe0336752811e92700bc8fc6191705f3aa34f3fac4979b6cd655f2db03d74abd955725eb91ee3e54df46743ed05e391acb7b6bfe4464179bc0a3eb46169dbc5d44e4b41306b727bbe993d235a9e58290c64061b32ba93552d696ef100936430907e17e368824464a79217d5f58563cd89061fc3da35baa217621dde692b59f1362027e31991b0c15918f4fb46fa6c8329b612faa96e95dfef64aab59e6d811b7f2444a4ef742010731c1cd910dd19c1a3c616344cfb2cf4b68671ea5f41cc0796588e1f020e0675c80eeaf7dbb683d1e1a98b9ff76010714e7503274ba1adaa33e1128b4bb3b50567d6eb5577532d2f0736e27107fb224e1571d436fae79ff118410f153574f3d9693c1fe21263972327505fe7c7343608214d4f669f85ced6b094ba45484c7bc9218b0ea4", "258", "1a0a5b453c877ec81f6a23a01b452fcd90e20bd6b6a9a08798222403f556b269c62048513cd1c57e9be2e17de90f1cf4725f0bc3990b0de84748d4ae569a55f0f5e0a71a7e59aecd9e2b139ca32636c3615239f0e0ef13d1dba91ebc61ef408fdea858a992cf132d47dfb97ad09c6f893a88a6591a4d2b2a89a42fc1284b7e2d6305b5c2f8a8d5b56a50219ffae0d98c4a3c83fdbe3ba84250e5e048491b145afa4a392f1ee38e742874d3c5e001bc30083db2802f727d18c6e1236e369a25460b2a8767a275dbd9376efbac5dfebec2277b88364f306eb313c99de0ede2fed752b9c375019364d7738579117dcd1287150be559415b48e9b4b62c3ffb5eea6adbbdc0c84112e8dcd88842f2ad69d3380330582e1299d56f7921aa075bd7fc72e421d077d09569c71a8e835cf7a043be5eed181860ef2e72c29825e391db4ced0f10183cd963f6ddd524da525f07ece60fea69b4ac47df9afbb71ea6ac50fa3ef21b4586cde5ac5f8b6d1b42512b4d3a65679a6d5a2c8e38791195136b30a2cc445c24159a8ea7e4d447af3421577b322dc030393a4807781b2d6dd98a120a6d94111d0dc3ebb13a786f2a301e283a2b4e1937fb5459f0147c087212ddc7e48cbc11ad271929490ff2f70bb4cabe03ca8fac31ac649fe01b0ea818e9eb6a65fddc23c0325855a9022282691f211f30104261c4ff2fe5cd243f8087027cf8d2080c68c21698763b94bb6a45d386b7177bfa9c469475c97e941f43bd78a6916688c7233fd3cc6ec3ede49d10d7e15a6815f9e200f891b57a7f1a887f4c1a0a11834988593027a4e27a3ed9a20f040620113627b966fab532429d16898190d2594b9a11fabf44ffc7ee2e3555b65ecb552f17b5788d8e12c56d7bc8847eb49a463b3398931f68fb07010839eed4fe0d1b7b74d67ae65117a2945d911b5d15b91c2c56c58ac99b523cb814a3ad1e9351b15fa957d4fdddeec5dbc787fe91675e8e77872976e9ee025e4cacddf10af98aa9ff4344936b50892d17a5c248d0fb69bc53c1a9a325d59c103cc3004f46208f27a506c1e03d84c4696dd4284f620a8e2a127f35288be641251dd2590bc0fafcf317c4e62fe50b58e8ba5c62efef001c6cd672194eb705689637b8a7328eec1849bc144cbb13a53329da4a25c7110b323c93f150da62627c81741769d2fc2359e616b8f06538627843632b6652a7e1448e0555725900df0b07ccb020ddcc5af3d4a277229912e3a9ef2a2cce8c1e5b3275890bf8614c435f9226e081d32568b6eec0d18edf3d8f5263257f461f2630a0a05e346c140a917204d97ae485b9d244c8a23d22178af6bc6a4323a02bd246f54fbc8f9c359d3a98fd3f41b9e05a8fa1045511002776b3358b28b73c8a85050d3b0b290a11f48d90fbf8f1e3c734327fa0df2558ad8510b3bd0d0b03dffe4e612b2bda53cbe431e98289ab5d9cefcd54b970e8d8b867b3c8b277ef10f035b50c6e7a048c453bb4ce24e40e9902606f2db0c5862a8622fee83b1bcb0211b24ac38f9c4fcf2730e77ba8f8c034c62bf82495a52666cc5cf46e76da03b24141c89bb6d219d092dcaf0122fdf14312b73d70fcb4b96e78378dbb1ff35a690b4b240e11b551b160eea8a94d5e020ceb683d576b3dddac5c02fdefbad6c5b136440b4c05562560c453e661e2020b6a24f8d265e5c9efe0336752811e92700bc8fc6191705f3aa34f3fac4979b6cd655f2db03d74abd955725eb91ee3e54df46743ed05e391acb7b6bfe4464179bc0a3eb46169dbc5d44e4b41306b727bbe993d235a9e58290c64061b32ba93552d696ef100936430907e17e368824464a79217d5f58563cd89061fc3da35baa217621dde692b59f1362027e31991b0c15918f4fb46fa6c8329b612faa96e95dfef64aab59e6d811b7f2444a4ef742010731c1cd910dd19c1a3c616344cfb2cf4b68671ea5f41cc0796588e1f020e0675c80eeaf7dbb683d1e1a98b9ff76010714e7503274ba1adaa33", .Okay}, + {.Shr, "56aeadf1c137c7b8eaf4c7c1ca73195c36ca1708a87208433b202b3b54abd8f33679713016c20acdb6af8edd5a12a76902d601c5c17416ca01c18de8b6a5364d8de31908b7b63a352e2bf054d2627b9b17554c78c2401b4afb48ea32290003fa6ef1698064e43b375df4f80745612eb1fb7ce7e0ae5f73a546558fe35e1cccd1c14f096ecfa5ad5537a82d2f40b3fdf3ba30308b80e5f4bc98289ace24b4e3d74d608981e7daf61fa223dc165f7344250aefa2fd4d6a3177821a2632d761834cc3c9fd4588675239c41752bc0d9f85dfedd708d21b60662f6466e2fe1d3932fb94ead4a5cc98ff6e3735ddd3f3eaf7eaf31ba4768472ea240aa93651b5a35ab5c3a14fa2c0f2a100359b57721aaaa735d20cb12c5b3c07273255b29d7673b0b05a1e7f7a82de43089d7172297f50bd98c75433d7161a16024ea34001cfa64d01e4484b826e6f8f9384d0aa335436dc7e42c3d3870fa717d05a91a0a8bc356a18a474822670300d7e35668adf16cbcd5ff6c9137215261fa4346ba5e8b6194f24360e061819144942d640d73251510a00f7ef3f1f6bf620c11b6fced98fa115fac3e31fcca5ca8ee7d776db530808a92b0203cf748ff6dea7145eea643d0f430948a4c19c49140ba9b4a42dc5046dfc9f6ddce6cefddbc5a76bc5df0a998a0a777fb36c91ef0304b56bea5a69e683209fca08fdfc8b804bc321c2e864f2189dbe696125202451e137a919085397a1e940d9ae73053495ac7b05ca55f949600bffa77cfdc8b9098deb0733c9be89fe3fa3f5c2a0681a197f78f812198e03dc71109c3174895fa2cef754c7fa2dfd310ce5122b4ebbb0769052732e34edb86d58cc57dfccf014fe0151efc629b29685d9cdc5354bfd38fce06cf681956eadb3af1f1ccec27a9cc963e861fd86ec19c037c071c8fc469ea03f461566eac0f855354e8cc550ab5d9d18a35390c3f61a8ef174ad5bcdcef61f5d930f6b9097ceb59b01b2c3f84d2f0c29d22cfa425ea76658ea879369daac0dbaa14f7f030c6ceaf277f9df0f75be5fddfd6e0579270d1658fd9e093732399ddea971b5fa16f523d6cf75ac2b24130edef4bdac83ff2ee24c6397c2a6b819776194f8d10d68fe0770165dbaa364c5f340511c4c007bcf46cafbae368015b862e51f8cbbec216d20ef7b9857e4ba56dc61ab2592d0963651f87e7df4d1915999868ee6a3edd00d0a7609648600092236fbabaa71d349825f7f3993ce7fb51ffbceb4ba80d861559c67d282aeb0a20e47702bca769bfc7fdfc6691eb31dc9c054442fca53328f19adcb8c99c6f96d5e4f691b6de297d3ed1ccdbd6f3a02b21e2c40fd7ac9a95bb04d22e44d004ee340bc29d77b19310e75a874be846713b4ed01a939188d31cc1b91dbe045cf995f51be6625b15419d2383d3ca572a2880fcfeb1e55b4c0c339d58369751e25b4904743c24579ef761432dd5f1a9be7fb7a93ffb1880792d29134680b5f4af2dbd15362db3a8f7f2685bf7324bc333af984752bf22bda503002690a8457860b48fd9b44b5e09dbeb11d770b979c9afc2692265f362ff5657eed53cb0f832287eb011b5a1cf643c095a233cc0488eb99d163a47f171e0c8aff95374473c24c45f9f3ed614ad76dc928e193b2432805c5c8cb8aab22c8346325a786b46270a67ff5ade280754d9e0179d95fb9bcac4c076f29de89a32c49d094df5fa51718284be38a74cb244b8fae21825591bb265e3e64e585200d4cf4fd3d38ae3c8594688e07626aba15473a22f252d8720778cea20330896ab80eb84216ffd844333b18bafd2e9c42d1b76b01a29d9bb41379140497b932c64ddad436cba9781da17782a4504a912be4bf2ea8b082dca170a9c28966e8c5c9f25ccf329f8334d690a77408e9b5856cdfe02e75c764bb5182d8b726a96c70c2ac12520d18f7b876875272c07fb188c46e8212294f655540eb0d3fd287f88aee4501117e2a251a5a26f4eef9fc746431fd6639a7746136c31af1f3d16814d53719f0237c5d91f9d70634776a639e4899c4d356734b6cfa6f9dcca599236bfa193dcbed0cb149f0a1b36a407939e2c171c4bc1dae1d2554ad0d4e1d85f85a8b5f81044d8e9c71", "3c", "56aeadf1c137c7b8eaf4c7c1ca73195c36ca1708a87208433b202b3b54abd8f33679713016c20acdb6af8edd5a12a76902d601c5c17416ca01c18de8b6a5364d8de31908b7b63a352e2bf054d2627b9b17554c78c2401b4afb48ea32290003fa6ef1698064e43b375df4f80745612eb1fb7ce7e0ae5f73a546558fe35e1cccd1c14f096ecfa5ad5537a82d2f40b3fdf3ba30308b80e5f4bc98289ace24b4e3d74d608981e7daf61fa223dc165f7344250aefa2fd4d6a3177821a2632d761834cc3c9fd4588675239c41752bc0d9f85dfedd708d21b60662f6466e2fe1d3932fb94ead4a5cc98ff6e3735ddd3f3eaf7eaf31ba4768472ea240aa93651b5a35ab5c3a14fa2c0f2a100359b57721aaaa735d20cb12c5b3c07273255b29d7673b0b05a1e7f7a82de43089d7172297f50bd98c75433d7161a16024ea34001cfa64d01e4484b826e6f8f9384d0aa335436dc7e42c3d3870fa717d05a91a0a8bc356a18a474822670300d7e35668adf16cbcd5ff6c9137215261fa4346ba5e8b6194f24360e061819144942d640d73251510a00f7ef3f1f6bf620c11b6fced98fa115fac3e31fcca5ca8ee7d776db530808a92b0203cf748ff6dea7145eea643d0f430948a4c19c49140ba9b4a42dc5046dfc9f6ddce6cefddbc5a76bc5df0a998a0a777fb36c91ef0304b56bea5a69e683209fca08fdfc8b804bc321c2e864f2189dbe696125202451e137a919085397a1e940d9ae73053495ac7b05ca55f949600bffa77cfdc8b9098deb0733c9be89fe3fa3f5c2a0681a197f78f812198e03dc71109c3174895fa2cef754c7fa2dfd310ce5122b4ebbb0769052732e34edb86d58cc57dfccf014fe0151efc629b29685d9cdc5354bfd38fce06cf681956eadb3af1f1ccec27a9cc963e861fd86ec19c037c071c8fc469ea03f461566eac0f855354e8cc550ab5d9d18a35390c3f61a8ef174ad5bcdcef61f5d930f6b9097ceb59b01b2c3f84d2f0c29d22cfa425ea76658ea879369daac0dbaa14f7f030c6ceaf277f9df0f75be5fddfd6e0579270d1658fd9e093732399ddea971b5fa16f523d6cf75ac2b24130edef4bdac83ff2ee24c6397c2a6b819776194f8d10d68fe0770165dbaa364c5f340511c4c007bcf46cafbae368015b862e51f8cbbec216d20ef7b9857e4ba56dc61ab2592d0963651f87e7df4d1915999868ee6a3edd00d0a7609648600092236fbabaa71d349825f7f3993ce7fb51ffbceb4ba80d861559c67d282aeb0a20e47702bca769bfc7fdfc6691eb31dc9c054442fca53328f19adcb8c99c6f96d5e4f691b6de297d3ed1ccdbd6f3a02b21e2c40fd7ac9a95bb04d22e44d004ee340bc29d77b19310e75a874be846713b4ed01a939188d31cc1b91dbe045cf995f51be6625b15419d2383d3ca572a2880fcfeb1e55b4c0c339d58369751e25b4904743c24579ef761432dd5f1a9be7fb7a93ffb1880792d29134680b5f4af2dbd15362db3a8f7f2685bf7324bc333af984752bf22bda503002690a8457860b48fd9b44b5e09dbeb11d770b979c9afc2692265f362ff5657eed53cb0f832287eb011b5a1cf643c095a233cc0488eb99d163a47f171e0c8aff95374473c24c45f9f3ed614ad76dc928e193b2432805c5c8cb8aab22c8346325a786b46270a67ff5ade280754d9e0179d95fb9bcac4c076f29de89a32c49d094df5fa51718284be38a74cb244b8fae21825591bb265e3e64e585200d4cf4fd3d38ae3c8594688e07626aba15473a22f252d8720778cea20330896ab80eb84216ffd844333b18bafd2e9c42d1b76b01a29d9bb41379140497b932c64ddad436cba9781da17782a4504a912be4bf2ea8b082dca170a9c28966e8c5c9f25ccf329f8334d690a77408e9b5856cdfe02e75c764bb5182d8b726a96c70c2ac12520d18f7b876875272c07fb188c46e8212294f655540eb0d3fd287f88aee4501117e2a251a5a26f4eef9fc746431fd6639a7746136c31af1f3d16814d53719f0237c5d91f9d70634776a639e4899c4d356734b6cfa6f9dcca599236bfa193dcbed0cb149f0a1b36a407939e2c171c4bc1dae1d2554ad0d4e1d85f85a8", .Okay}, + {.Shr, "167c06ee9eabdf42d040ff98bf84e12a964e8f383f7fb5bf32afc1a4842f288932e22a7b97d92c3aac728256a3a46598803e7d2acedd62edfaa6add91faf7169ad29314ae7aa262c3dd31383eccce1fcb622381c97edc30dd0e6e259ccacc9c78d22507171e8b4ae7cccdabb9febc6d1f4f41689b7aad58d2f5fd975e461c86b726441f209fcad6390f8a1f24f1f65d6aa37bbb56b6ee3f560c0bd90ea4f23c22546abc1d835b72080d36518413d9fa25494456500c1a1418026b861fc34782ef3668b144ac3cddbaa0bf08f225572eaa80b1d9c7ed3b97b53b9e42593cd753973c6b73a6e3adc837c579555db26251442382173b1d348846016c60c6755c629aa94fdde2946a252a9f6cec2c8a23a0b16d2a78892308ed934fbd4cf8c6850b6e3c94dd904118216f9eeb305279f661b2fae05d692bcef1e680150df25d196c200a2b7eaa8ee518b263421ae77e89a70baf70f29f6e821ffbcf588afcbead6f2b37bb23921cdeede783bdbe3249f9301366416b7461b2abf86150e55c7cdfaf03f5f12258e9774197d794689018a33629da3adb559ae016e99ca0740523efc5736d0d441f2e8b1bd44b28332792da67bc1d1bcd1193fb5e6a32ae6a7d5f9757432be78025d5dd599f9b1546e36173256f8b475ac68ce1de65e343b4d433cdacab533015fbc3a28bf1a55e95174240b8dfa7a423f069d204dc8b11f7fa6e4b1d024c144893266c2417376f063f484c398839c078ac35b53d192353d4c14b0c1591de864c65c5f15c1e4133c7c0ab888c6b360d5b147f73f80b341ec7f8eacbdfd59ccec786ae16d0e66f124f3b9d3b940cad7dd95dfeb3221fe956fbe63c64a5303cd015737fcbcac55ce2f465147aec8474d1003879b2134c8a3d3d196bc8ddf22bffe4482024ee136f67f7ad00d8b510a516fdd872b8b0440e79394ac2f196482d9614ca48cfa8ee4acc8257dc12e277a97173814d122e8c3871b9bafac4658742e7414dbe83344e0dd5cc34b5859eae762c1297c88b839efc5d4bf23decc1710d0a1dcadf624a01c949d183dde8cae114cd6da37d76f75161a4ba7d0f5b63ac068ddc99fad202bde4faf748a0eb4b1515b9f1f436d36526a7f7ee4ce1d4d83546e9e7d2052184002c5de49bb7d46ff1312505b0fecdd5b823031ca2fe731ac6b2e1fe6e1ab7295db97bda3b99edba2acf9b393e960fc2c6282e7e301c10d7431b233838e1253fcbf124aed159177255d5df069f93f7c482585c0c928cc6349143093392552c69dea77a13fa5615f59a1c36a05b91c54febef75c3fc02226f9376980bcf8a2ba5bdf848ba0f81d0a44b8b8221d57d0f7b0b1486d444e428af855ff7154899bffc7a9cfffdb132328d2cc56e2c6bbdcd6e4ec28cb1191cb5fd279a5801f37a58fbcdc8874474cfbabc0f17387f62a68728be3ea6958f21e5be3e5fc6f1de44155ca3635a1435e20d35b4fec5fab6f33e56b73b76e29ac071c034506c7d7c8876c9219f6f1cbffc4240779d364b15137aef5d480296fff3531d431d3632021acac66757ff373c0fbf95a118ce0a73ff3aa2f5eac78cf860619208ff46722b8bd5daad82e151f87b47134e0800d78af8fa34dfeabf0d9f50495b882f87d6528898c708de1141cee25a2d0c149715a8cdbceadf4d0b8ff4f48ebeb42d0fd1dab95afc4fe12cb6fef558f6020d8b4bd35d6a68aea575c7304fab07d6094a19a127aac31a2933c9b6d0fd7e4c81de3bf56055e5b92e4f8e084522fbd5c0dbe6ac2edb63ceed40340d8db9e3fa738e2ff766d89e0ea9e4e7a275e298ad82246dd976b32096ec2eed45ec9cc62ab00ef68a3b926c280409061b0c1e2c037cba9cfcf33cd43ddc3b77415cd92ab8927c130ded7e85e57ccfa04e6f471e0b8dbaab69ee6d3b37061666e18efb5b2544af4702ae12207e05926092422c15cc2fb1fad59836497d697bdf4d9cce7ac0c1baf83b7c79dabb2657a0fda21e1accfac7374309e85bf384f237acd511001303d77fd42fb7d7971ad90fd1eadbbc8e555ffec1fb18d501a8f102986f20bc0577214fe1e1934964e4c480dae7da65503451cbd3f523874bd66c25db0684e02d24ae67af8cc2efec3ec3084", "1e0", "167c06ee9eabdf42d040ff98bf84e12a964e8f383f7fb5bf32afc1a4842f288932e22a7b97d92c3aac728256a3a46598803e7d2acedd62edfaa6add91faf7169ad29314ae7aa262c3dd31383eccce1fcb622381c97edc30dd0e6e259ccacc9c78d22507171e8b4ae7cccdabb9febc6d1f4f41689b7aad58d2f5fd975e461c86b726441f209fcad6390f8a1f24f1f65d6aa37bbb56b6ee3f560c0bd90ea4f23c22546abc1d835b72080d36518413d9fa25494456500c1a1418026b861fc34782ef3668b144ac3cddbaa0bf08f225572eaa80b1d9c7ed3b97b53b9e42593cd753973c6b73a6e3adc837c579555db26251442382173b1d348846016c60c6755c629aa94fdde2946a252a9f6cec2c8a23a0b16d2a78892308ed934fbd4cf8c6850b6e3c94dd904118216f9eeb305279f661b2fae05d692bcef1e680150df25d196c200a2b7eaa8ee518b263421ae77e89a70baf70f29f6e821ffbcf588afcbead6f2b37bb23921cdeede783bdbe3249f9301366416b7461b2abf86150e55c7cdfaf03f5f12258e9774197d794689018a33629da3adb559ae016e99ca0740523efc5736d0d441f2e8b1bd44b28332792da67bc1d1bcd1193fb5e6a32ae6a7d5f9757432be78025d5dd599f9b1546e36173256f8b475ac68ce1de65e343b4d433cdacab533015fbc3a28bf1a55e95174240b8dfa7a423f069d204dc8b11f7fa6e4b1d024c144893266c2417376f063f484c398839c078ac35b53d192353d4c14b0c1591de864c65c5f15c1e4133c7c0ab888c6b360d5b147f73f80b341ec7f8eacbdfd59ccec786ae16d0e66f124f3b9d3b940cad7dd95dfeb3221fe956fbe63c64a5303cd015737fcbcac55ce2f465147aec8474d1003879b2134c8a3d3d196bc8ddf22bffe4482024ee136f67f7ad00d8b510a516fdd872b8b0440e79394ac2f196482d9614ca48cfa8ee4acc8257dc12e277a97173814d122e8c3871b9bafac4658742e7414dbe83344e0dd5cc34b5859eae762c1297c88b839efc5d4bf23decc1710d0a1dcadf624a01c949d183dde8cae114cd6da37d76f75161a4ba7d0f5b63ac068ddc99fad202bde4faf748a0eb4b1515b9f1f436d36526a7f7ee4ce1d4d83546e9e7d2052184002c5de49bb7d46ff1312505b0fecdd5b823031ca2fe731ac6b2e1fe6e1ab7295db97bda3b99edba2acf9b393e960fc2c6282e7e301c10d7431b233838e1253fcbf124aed159177255d5df069f93f7c482585c0c928cc6349143093392552c69dea77a13fa5615f59a1c36a05b91c54febef75c3fc02226f9376980bcf8a2ba5bdf848ba0f81d0a44b8b8221d57d0f7b0b1486d444e428af855ff7154899bffc7a9cfffdb132328d2cc56e2c6bbdcd6e4ec28cb1191cb5fd279a5801f37a58fbcdc8874474cfbabc0f17387f62a68728be3ea6958f21e5be3e5fc6f1de44155ca3635a1435e20d35b4fec5fab6f33e56b73b76e29ac071c034506c7d7c8876c9219f6f1cbffc4240779d364b15137aef5d480296fff3531d431d3632021acac66757ff373c0fbf95a118ce0a73ff3aa2f5eac78cf860619208ff46722b8bd5daad82e151f87b47134e0800d78af8fa34dfeabf0d9f50495b882f87d6528898c708de1141cee25a2d0c149715a8cdbceadf4d0b8ff4f48ebeb42d0fd1dab95afc4fe12cb6fef558f6020d8b4bd35d6a68aea575c7304fab07d6094a19a127aac31a2933c9b6d0fd7e4c81de3bf56055e5b92e4f8e084522fbd5c0dbe6ac2edb63ceed40340d8db9e3fa738e2ff766d89e0ea9e4e7a275e298ad82246dd976b32096ec2eed45ec9cc62ab00ef68a3b926c280409061b0c1e2c037cba9cfcf33cd43ddc3b77415cd92ab8927c130ded7e85e57ccfa04e6f471e0b8dbaab69ee6d3b37061666e18efb5b2544af4702ae12207e05926092422c15cc2fb1fad59836497d697bdf4d9cce7ac0c1baf83b7c79dabb2657a0fda21e1accfac7374309e85bf384f237acd511001303d77fd42fb7d7971ad90fd1eadbbc8", .Okay}, + {.Shl, "-256889d946b53ddb872d4cdaf3e502be650f6a1bd02325d16b820b6072ed5dccb800b6dd91760dcda5328ab0707cef0855670749fe54630cffa7ddace44180ab9e6062cdf33ff54e3339a65ad0a087898fc7dd49fc45873fb87612c6b5c9548cc25066ebd6c03d88487af9769f19e5ad8991c901985752bbd33f16cfb00b027011c6c44a3c9b0a3c527291c0ca20244c3c6b670dc73489f61f6c0379777a84cf580a497796006a566f69e55c7a0a3ad367fd7950501f23153f5af82d9ecbc582315b7dc4775facf32ffb53d85e458d6fd499973a6083543ab1a5d34f4a5de13eb5eec3d42daaf1aba7500afdf6276d9ac51339be45e65ea2aa76bd2037e04efee55cf1f52133017162ed93411267822decf041f06e749375313fe4eda8b8baec8be23a67baa70913847dbc6655542ed3b42d8fda5db36f5dea73732b357c9ee727dc4f1aabb05bb82033d77087d28b176626c78039aaf5339e89251215812ac3fe5978033ccdd0f6ed76741788649a0028486399a1fea9280d24ee6a69628542890b8c925d71c03a5efe32a3977e5c8652d4044b781979ab5a8de8a17b3a0e24753aad4a24fe4e67de238f457236a2a85cd6baa7e1767a1c14c284a65eef2f29e64e4e59fd1a552673480d815c1a28128cc049bb383465a0d451a3950eccecf69b3a323e2a57b2ac55fec206801cfb2ed375c83af4ada294f7768baba89c45bb2be2b3295bc78800b619141b73141284485c700bf774d7b016aa8496208ce43a08db7fe58591baaf3e7a867998fe8fa01d186ea97859b876bc310b2556be97fb5f7755d3975e836b89e829028e105169cc9ad0e66e0158b3139b996fbe26da3ddf3390d86548384a7e5dbb8f832f098bc0d966672c7ce213f5f4881b5c5308c847b734431d4a41cccbc8c8007fdae9663567fde2dceeb0741a8b45384037223f22355377949413c1b9f8d2be5ee34936eb3c477bd12e4bf7fa3ac3fba4a5945c73feabe842f6ccae757f9c880d44db84662d3eb3489f51f607c8cfe688fcc577426a643ac790a4b3bbb96fe3c4889b21bb8450553c8758c765f7f4a8a5fa38882844fe35f1709123abf9e54319f6e2c12895b4bd861519d0f66857ddd3ab39c10ceac15999c5529a237fc657aa6842f3d5bf6bf180062d6bae4d7a966c422d5c47b7fb490b069bd18e42417cf2913003849dc109c24186f1f021f426a85e74aa89cc7f365bfcdd06fbb3bffe6c20f157e9338c222544cc3eaddfbc609a805da13ba586208ab135c4544399d6f13402799f5a8ccf993ee3094c2e33673ef74b3a9090354e0e6a51c150c2a570122b4a37bc2d930a19f5a79868b1c613a87eb4f58db029ddfed94a09b68dab152a6e7c4bb9ad552ff6397dbc57530d182ce60fc1d958d6f2aa4ccc4d337e1f3a1006b937a8206ab4785d7a2710f8da341deb70ad988f737f5ab2b7fd8fffc93c72c34dce0a9764d26b74ef296bfaa81fd4281e697fcfd170a4e625ec4ea9b588597bb7cf3b75eb0e29e22bc8a4a3498bd0f64aeb5349963ad68442df57753174beb25717e819473920a45ee606c1ca31df5ec66d018ddc533fd828755e74b68857d814d3d203260c83836168bceb5dd0a3121891d4182a2de2b1aeffa3a911d285816f8648a49acfea6cff4e9507edbd235755bb61625dc387a8b4f8983830aa091038642ab75422094c65cc3b0bd9ca30b4a5fd3482650add62ddfea6713966307f872e4fbfc81de6e7fe619788ea3ded86b54f6ed4c1ce63a15b15a89c7e87bf118a52ff3c0fb7d1cd9679fe40f95cb8f7e431cb0108557687a120a1099398f73ae3dc5b7423a6e4a09832a619e9fbbe39735494a22e1af99ccff65ba9529e61dd10bc61597b179b4dcc336474984f5113658d53cfa251be84613f0c153b9e1a3c07f5a7c0d6587fa1e58b3f1a7f4c978964314c17b0adc66d12f2773abe79fa91cd60bc656e8e33caeb6dc25bef41745f79121c33e56297011089e0897e174fc54ace39f5a21239471be0cd86712fbfdceeedfd788cbecd1a26a05291310aba24d1de40d708d56d6276412dbe576ac722d61c2e82521a2e064d952164ee1d96651bca7ae8bb4b913bda8b02912cf4", "24", "-256889d946b53ddb872d4cdaf3e502be650f6a1bd02325d16b820b6072ed5dccb800b6dd91760dcda5328ab0707cef0855670749fe54630cffa7ddace44180ab9e6062cdf33ff54e3339a65ad0a087898fc7dd49fc45873fb87612c6b5c9548cc25066ebd6c03d88487af9769f19e5ad8991c901985752bbd33f16cfb00b027011c6c44a3c9b0a3c527291c0ca20244c3c6b670dc73489f61f6c0379777a84cf580a497796006a566f69e55c7a0a3ad367fd7950501f23153f5af82d9ecbc582315b7dc4775facf32ffb53d85e458d6fd499973a6083543ab1a5d34f4a5de13eb5eec3d42daaf1aba7500afdf6276d9ac51339be45e65ea2aa76bd2037e04efee55cf1f52133017162ed93411267822decf041f06e749375313fe4eda8b8baec8be23a67baa70913847dbc6655542ed3b42d8fda5db36f5dea73732b357c9ee727dc4f1aabb05bb82033d77087d28b176626c78039aaf5339e89251215812ac3fe5978033ccdd0f6ed76741788649a0028486399a1fea9280d24ee6a69628542890b8c925d71c03a5efe32a3977e5c8652d4044b781979ab5a8de8a17b3a0e24753aad4a24fe4e67de238f457236a2a85cd6baa7e1767a1c14c284a65eef2f29e64e4e59fd1a552673480d815c1a28128cc049bb383465a0d451a3950eccecf69b3a323e2a57b2ac55fec206801cfb2ed375c83af4ada294f7768baba89c45bb2be2b3295bc78800b619141b73141284485c700bf774d7b016aa8496208ce43a08db7fe58591baaf3e7a867998fe8fa01d186ea97859b876bc310b2556be97fb5f7755d3975e836b89e829028e105169cc9ad0e66e0158b3139b996fbe26da3ddf3390d86548384a7e5dbb8f832f098bc0d966672c7ce213f5f4881b5c5308c847b734431d4a41cccbc8c8007fdae9663567fde2dceeb0741a8b45384037223f22355377949413c1b9f8d2be5ee34936eb3c477bd12e4bf7fa3ac3fba4a5945c73feabe842f6ccae757f9c880d44db84662d3eb3489f51f607c8cfe688fcc577426a643ac790a4b3bbb96fe3c4889b21bb8450553c8758c765f7f4a8a5fa38882844fe35f1709123abf9e54319f6e2c12895b4bd861519d0f66857ddd3ab39c10ceac15999c5529a237fc657aa6842f3d5bf6bf180062d6bae4d7a966c422d5c47b7fb490b069bd18e42417cf2913003849dc109c24186f1f021f426a85e74aa89cc7f365bfcdd06fbb3bffe6c20f157e9338c222544cc3eaddfbc609a805da13ba586208ab135c4544399d6f13402799f5a8ccf993ee3094c2e33673ef74b3a9090354e0e6a51c150c2a570122b4a37bc2d930a19f5a79868b1c613a87eb4f58db029ddfed94a09b68dab152a6e7c4bb9ad552ff6397dbc57530d182ce60fc1d958d6f2aa4ccc4d337e1f3a1006b937a8206ab4785d7a2710f8da341deb70ad988f737f5ab2b7fd8fffc93c72c34dce0a9764d26b74ef296bfaa81fd4281e697fcfd170a4e625ec4ea9b588597bb7cf3b75eb0e29e22bc8a4a3498bd0f64aeb5349963ad68442df57753174beb25717e819473920a45ee606c1ca31df5ec66d018ddc533fd828755e74b68857d814d3d203260c83836168bceb5dd0a3121891d4182a2de2b1aeffa3a911d285816f8648a49acfea6cff4e9507edbd235755bb61625dc387a8b4f8983830aa091038642ab75422094c65cc3b0bd9ca30b4a5fd3482650add62ddfea6713966307f872e4fbfc81de6e7fe619788ea3ded86b54f6ed4c1ce63a15b15a89c7e87bf118a52ff3c0fb7d1cd9679fe40f95cb8f7e431cb0108557687a120a1099398f73ae3dc5b7423a6e4a09832a619e9fbbe39735494a22e1af99ccff65ba9529e61dd10bc61597b179b4dcc336474984f5113658d53cfa251be84613f0c153b9e1a3c07f5a7c0d6587fa1e58b3f1a7f4c978964314c17b0adc66d12f2773abe79fa91cd60bc656e8e33caeb6dc25bef41745f79121c33e56297011089e0897e174fc54ace39f5a21239471be0cd86712fbfdceeedfd788cbecd1a26a05291310aba24d1de40d708d56d6276412dbe576ac722d61c2e82521a2e064d952164ee1d96651bca7ae8bb4b913bda8b02912cf4000000000", .Okay}, + {.Shl, "25f380945d2c7930fb03d8a7e9c9b25feb3ddd160db3a5e87736c7d835f4e6301194dd5b231dd52c85f8ae6a08ffbc64c8cf2631b6f2d142889a540fe8e10227e7ecfb3b3dd2f81ca3deec1b24df8c21080079914e74786393deb493b81be143b93cd0aab982b41f529c4fb82e10d70e314d4cd1a708519fbb0716ec6114c95f978c6c91e07122e199431e36d7f20b3f3c7652b70d9c5265d29a30406dea8afa484107a25bd3d2ea12b058deaf9b7b16b7e0dd81efd099434806418612a084ed094c682de153939b638cff332a332330363b0203d53c2b031280e4b8d5c90a5b616866fb9982db728f516392d3ac06c8edce656ae9480a9685f19ea76de16a1d0b0227d183d360352c10fed8b61246dd6c10536b32dccf3cd7076df769a10ad7fae6234e62e88c7501d13b46414872c93e14e5af71eb0e0492224e91509cc9e8c2a86f89e8e76cd15bccfd4261dcf67405a0eee55b530dceae1095a09e009746115b50167fb59bac1d839295add83d6090a5ef0759b971b11eba9e22e65063f858eb478c72d0316045b8d79de0effef64c239aa4e0cd65cc763a3ebca7e5c54334eb24396033ed94fdb979a95622bffe09e3c00e186664b8f8fef6bf7eb81511cb99663d88df05740cf53c706ea43e879f0b52a01d5ca2e25ab510c8d7af9d8cb10c59cbcc081c90a0b01a88f25067b3c2fd20bb9e56a3bcab3a8aa61e5f583e5e5130b42c7278303b9ee36dfc68a2d1c9b7716d0a7e824d1c7993d0fa723a46716ed6ea9bcd86e3b949a4a5cbae4c05e9638282337c9fcd1c526eb93562eda15bce9aa370ae456cafc90e84a4ae28a07fb3ea4b2777aa06236e1818ca5d93550e02bfb75c24b038567054fa9f52f4c023ad3fdeffe6e72071126c957e8a223db67956e14f85a3b652034879cd13104dfbc77f2690d1e2a4e572d4613bca1a1bafe31211d1c6652d7d3482ae3db949215eab9c6ad3f27ba38ce23ae9c904442cd69d82e4b20ae328b5e1a749843d4e6e9711272494ff54dcc9f48149d52781e10fd851ba964a478e19f82f4b29998f9c1e4682b5fa4c726e5c278a26442da165b9bab603f50f7fad6c1b12b122d160df38c220a7aade9cfb22c3e31f1d9b8922919c30e4c72623ff43e2afed8ef8bdb22da1cb19c73058f8f6094c214c264cbec705835ab83a214455a01273352153b87b62ba87c5e647a7ed3c12745116be5e4e370b225c95b11c07615d930718588ff23103024de385b69cea8e08c6e0bcff7f3daeb939da38e6a7d61767d83cb92f8a68a88a0727b787061d6fd9867481e84381ddc68045e6f108f5e3b2368cb801b2b2ab80e7d7161f062b9d38abe463f33226d404ab8c28562e80e097408ad53661b346df9fbd7d3214c87c4696251daf9ea535dbd7854093fa1f397439f5088d4a0c28628b4795c931a9e8d201f8e507f74f62c68d1d83350bb1cfd224279c0b66608371ad3797668fc7942e8b13fb19d1b46c5837177df517c1ce0194bcfeaeca8aba18d62c9c4a6c0534aa2f97d5cf3fb43c7c178f540ec461fd96303a7fe271924a5ccb55ee0e98bd3c35ff824f6d5d0bd3aeaa464db245ff1443e1419d4c87044da6625bcc982ec0d9dd29960c6b501cc91dfd6ba2345d7568c1d7a4b2b4bce8365edeafd110019e6cbc713a2c6fa81595697f61223699f7c42bd6866437994acfac6e534e8f2dcef669e1392112519df28f4218781051d024f8410a33b3d3af058056ad118abf0d000024ac560fd97cfa27b562f067d8ce9afe24f6346c3b1ceb7d431dda3d5789e948e2e2f3609be3f00b4d3b12091ea8ae5b6eaabcb72c9b298026d5503d6702f336315b2fab3fe4d76258d054efea3feb3fb0e8e7ea5dcd0908ec174d4293cc1f47b587ea78e237e4be6dc762a2d1d4e88d04ce1cbc45bcaa600ae0fef6ee8e09173ef14dd8a508877fbd3ddce387bbcb48ee03d7065e1b15725db1d59c13d19e05b193d132836a3d1a9491987d07887ad25ee882621f9cb3318143dcf3e96f5c40cf71cfdfb39cddaeeee49f469f2ff63cdadf64d1421528e0c2b990d923267fcd2ea0c800864a5e170f6e181a4b52d5fe8e72d29429d27a6478b444f311219b22", "6b", "12f9c04a2e963c987d81ec53f4e4d92ff59eee8b06d9d2f43b9b63ec1afa731808ca6ead918eea9642fc5735047fde3264679318db7968a1444d2a07f4708113f3f67d9d9ee97c0e51ef760d926fc61084003cc8a73a3c31c9ef5a49dc0df0a1dc9e68555cc15a0fa94e27dc17086b8718a6a668d38428cfdd838b76308a64afcbc63648f0389170cca18f1b6bf9059f9e3b295b86ce2932e94d182036f5457d242083d12de9e97509582c6f57cdbd8b5bf06ec0f7e84ca1a40320c30950427684a63416f0a9c9cdb1c67f99951991981b1d8101ea9e15818940725c6ae4852db0b4337dccc16db947a8b1c969d6036476e732b574a4054b42f8cf53b6f0b50e858113e8c1e9b01a96087f6c5b09236eb60829b5996e679e6b83b6fbb4d0856bfd7311a73174463a80e89da320a439649f0a72d7b8f5870249112748a84e64f4615437c4f473b668ade67ea130ee7b3a02d07772ada986e757084ad04f004ba308ada80b3fdacdd60ec1c94ad6ec1eb04852f783acdcb8d88f5d4f11732831fc2c75a3c6396818b022dc6bcef077ff7b2611cd527066b2e63b1d1f5e53f2e2a19a75921cb019f6ca7edcbcd4ab115fff04f1e0070c33325c7c7f7b5fbf5c0a88e5ccb31ec46f82ba067a9e3837521f43cf85a9500eae51712d5a88646bd7cec658862ce5e6040e4850580d44792833d9e17e905dcf2b51de559d45530f2fac1f2f28985a16393c181dcf71b6fe345168e4dbb8b6853f41268e3cc9e87d391d2338b76b754de6c371dca4d252e5d72602f4b1c14119be4fe68e29375c9ab176d0ade74d51b85722b657e48742525714503fd9f52593bbd50311b70c0c652ec9aa87015fdbae12581c2b382a7d4fa97a6011d69fef7ff373903889364abf45111edb3cab70a7c2d1db2901a43ce6898826fde3bf934868f15272b96a309de50d0dd7f18908e8e33296be9a41571edca490af55ce3569f93dd1c6711d74e48222166b4ec172590571945af0d3a4c21ea7374b8893924a7faa6e64fa40a4ea93c0f087ec28dd4b2523c70cfc17a594ccc7ce0f23415afd2639372e13c5132216d0b2dcdd5b01fa87bfd6b60d89589168b06f9c611053d56f4e7d9161f18f8ecdc49148ce1872639311ffa1f157f6c77c5ed916d0e58ce3982c7c7b04a610a613265f6382c1ad5c1d10a22ad009399a90a9dc3db15d43e2f323d3f69e093a288b5f2f271b85912e4ad88e03b0aec9838c2c47f918818126f1c2db4e75470463705e7fbf9ed75c9ced1c7353eb0bb3ec1e5c97c53454450393dbc3830eb7ecc33a40f421c0eee34022f378847af1d91b465c00d95955c073eb8b0f8315ce9c55f231f999136a0255c6142b1740704ba0456a9b30d9a36fcfdebe990a643e234b128ed7cf529aedebc2a049fd0f9cba1cfa8446a506143145a3cae498d4f46900fc7283fba7b163468ec19a85d8e7e91213ce05b33041b8d69bcbb347e3ca174589fd8ce8da362c1b8bbefa8be0e700ca5e7f5765455d0c6b164e2536029a5517cbeae79fda1e3e0bc7aa076230fecb181d3ff138c9252e65aaf7074c5e9e1affc127b6ae85e9d7552326d922ff8a21f0a0cea6438226d3312de64c17606cee94cb0635a80e648efeb5d11a2ebab460ebd2595a5e741b2f6f57e88800cf365e389d1637d40acab4bfb0911b4cfbe215eb43321bcca567d63729a74796e77b34f09c908928cef947a10c3c0828e8127c208519d9e9d782c02b5688c55f86800012562b07ecbe7d13dab17833ec674d7f127b1a361d8e75bea18eed1eabc4f4a4717179b04df1f805a69d89048f54572db7555e5b964d94c0136aa81eb381799b18ad97d59ff26bb12c682a77f51ff59fd87473f52ee68484760ba6a149e60fa3dac3f53c711bf25f36e3b15168ea744682670e5e22de553005707f7b7747048b9f78a6ec528443bfde9eee71c3dde5a47701eb832f0d8ab92ed8eace09e8cf02d8c9e89941b51e8d4a48cc3e83c43d692f7441310fce5998c0a1ee79f4b7ae2067b8e7efd9ce6ed777724fa34f97fb1e6d6fb268a10a9470615cc86c91933fe69750640043252f0b87b70c0d25a96aff4739694a14e93d323c5a22798890cd91000000000000000000000000000", .Okay}, + {.Shl, "-29eea0c3a94d3114ed1d5a2e80fbb144e9ccb833cbf9bc69e48f975e4a6992d463afc7a87e46daa83ad89b2dae04b0c84b2978d2e643985204a669818c7d880b59074004470a3376fb774b6037ef297ae4c31830db877f6e21c44befbcda02f9889e770ea8db00006ba980f75f03ff425b459cf3cf0ae2e783d745a8c297d9cd4dd61e89c812381ada848c04c9c0b3e2b8b52e59d155193358d574b0562d18eceab089297c529e6741beab54493efb0c3b0323dd31868d45f2a29035eb21f81746aec63a226a5a53d691e0a3cdf0402c9b2827b049ea68a2035309516bc51777ebf3e1a9494fcc9ac2f6199510855c61eb9b92da554040b89675b30c7bbffd8d2a1ca48ac465e64790c12f5626541be33b265a46d72954048d26ab2d52023d891b326735d735acea391df1ba67f81e9471d21cabc7a37c3406e26cde0a58d868bbb75686f789a8acb12389b1a0164301394309329c460fe9b48aa205d3187609f7cbac0c5bf6e4777af5d5ac058d6017a907760f6ab8ed27eb4967fdc4c99caed99d02e6e995390fc62066c6ad0f6ff0fa7eb67216d81417e4c2ae01a7c0e3f0174e7a6072d7789891b088e0d6a311781d61361d051a00b45285fe14239527a62994ac64c1e5510762413204ee274b56259941eda72266bda2a421a59a08bd504c2bc087383adbdf35e6be67ef4e6785834182a883cff780261efaf94bd0350376ee29148ec564590ab972b91e88eb009327c662a69917b710441e0aa320a97a0e03bd4b3b06471465a3054288aea96a4746af0a216469fe696d9279e101053799366343e690ce9e4b737230cea4645a6069891b8ee3f2ed821b1a81acc265f5c0ba1ac17730b570edae276e3a73713af0425bc48fc9b6b54f05e91850b8b8920c2008c709cb1af9c216f24e34081581d594f6680edd0d3aff8a26aa4da7de382d14728ab7f613391cea37be8e5637695763058b7c38d6bc1601172229a38ae09b32f190af681f82ccb0ba7b1a12039d32a351eab9712b345db85474fde59fcc898936796bca6606737da07452b9ab1bdd2e9b6bfd241d03fb7dc4e6ef83bf04bae51093c7873c28c11e04157875df9cac2fbbd6a64245f2ffa6d686e1692699404d81668a2fe40c0a85b99599d9c2136078ddbbab0eac3c3a48e7441562208e9254274adbd4094bc3b11f26efd9893cb0ad8b66ecb6b89db940a906284cc3e37d5ce94591421a7d1235a6bec35e11039e45640bccd36a157007fce8c91cf2b786842078b8e3eb62d314f5c3f30ccca5f0a4802d819d4af405c8f3ad414573f7605fc401fe8c3a7e01435f2a7a507de98972fdc727fe72bc8b08e7e555aed3caae995f043762eec28072272bb89d42f41b19a8853a9c2050f883d5eabab858b5b27fcfc4020cefb51f0c825de27954206073f510eef06d8c0a09dc7a4d5e5989f952c7f12a1e5a2b1c2121ecd8745e1c39c0fd282f1ad2345a8c8609739a0a4033fc3e2f0d484cd089214fca076854ddc80e2921d44c44e94cbe1b8a452b81ffffda65f3c406d0bcfb87b851a2453590122b13fe8ce8fdc023679d6ea8076ce04c04b699ab46688389c6b3e4ec1d935c6baa76073e9126e39492a935a2d803c9a393d6ba3ceed5e981191e5872375e252a2f747c373c85c613a6cb56755140cab7e6b256f66c89af50ccbb7b20a5096c37400af9ec0b750cf7239747daac80cde4d086a881fb6bd32a9589648298d24662b7f70b315b43cd0eff8128f4b1d5c7622c6f121b95c4935a5791eda84f0a59d1ea39d85b88db4de02cd1b99d88e2e80b4fd5c288cf6d2416b164d9bd15dda7e6cde720dbdb616bda8b0744d070cebf3e43bab687bfa56cc7ef8a223fbe335ff5e7d0be9c8b02b6974b66ff9be1993c46efae12fef9e38b03d130bbaa397d99c3280c604586804cb022d22c3134c3ad2b9cf7d33a7d79037549bc9fa2c17b09c3d26ff06d8c8308ef10e34d7ec83bc5bf2f49cd6757b5b3909ba174efb2d6f43eed8f470c4d1ab9a750ce8b06d8fca7b8d9283801cebdc487ff8746e137cecc7a4886e82489e15e08e5ea043095b074c8726d1fa25dff7d5220bf493c648c0ab428b6b6a385196d0f6aa2d5", "78", "-29eea0c3a94d3114ed1d5a2e80fbb144e9ccb833cbf9bc69e48f975e4a6992d463afc7a87e46daa83ad89b2dae04b0c84b2978d2e643985204a669818c7d880b59074004470a3376fb774b6037ef297ae4c31830db877f6e21c44befbcda02f9889e770ea8db00006ba980f75f03ff425b459cf3cf0ae2e783d745a8c297d9cd4dd61e89c812381ada848c04c9c0b3e2b8b52e59d155193358d574b0562d18eceab089297c529e6741beab54493efb0c3b0323dd31868d45f2a29035eb21f81746aec63a226a5a53d691e0a3cdf0402c9b2827b049ea68a2035309516bc51777ebf3e1a9494fcc9ac2f6199510855c61eb9b92da554040b89675b30c7bbffd8d2a1ca48ac465e64790c12f5626541be33b265a46d72954048d26ab2d52023d891b326735d735acea391df1ba67f81e9471d21cabc7a37c3406e26cde0a58d868bbb75686f789a8acb12389b1a0164301394309329c460fe9b48aa205d3187609f7cbac0c5bf6e4777af5d5ac058d6017a907760f6ab8ed27eb4967fdc4c99caed99d02e6e995390fc62066c6ad0f6ff0fa7eb67216d81417e4c2ae01a7c0e3f0174e7a6072d7789891b088e0d6a311781d61361d051a00b45285fe14239527a62994ac64c1e5510762413204ee274b56259941eda72266bda2a421a59a08bd504c2bc087383adbdf35e6be67ef4e6785834182a883cff780261efaf94bd0350376ee29148ec564590ab972b91e88eb009327c662a69917b710441e0aa320a97a0e03bd4b3b06471465a3054288aea96a4746af0a216469fe696d9279e101053799366343e690ce9e4b737230cea4645a6069891b8ee3f2ed821b1a81acc265f5c0ba1ac17730b570edae276e3a73713af0425bc48fc9b6b54f05e91850b8b8920c2008c709cb1af9c216f24e34081581d594f6680edd0d3aff8a26aa4da7de382d14728ab7f613391cea37be8e5637695763058b7c38d6bc1601172229a38ae09b32f190af681f82ccb0ba7b1a12039d32a351eab9712b345db85474fde59fcc898936796bca6606737da07452b9ab1bdd2e9b6bfd241d03fb7dc4e6ef83bf04bae51093c7873c28c11e04157875df9cac2fbbd6a64245f2ffa6d686e1692699404d81668a2fe40c0a85b99599d9c2136078ddbbab0eac3c3a48e7441562208e9254274adbd4094bc3b11f26efd9893cb0ad8b66ecb6b89db940a906284cc3e37d5ce94591421a7d1235a6bec35e11039e45640bccd36a157007fce8c91cf2b786842078b8e3eb62d314f5c3f30ccca5f0a4802d819d4af405c8f3ad414573f7605fc401fe8c3a7e01435f2a7a507de98972fdc727fe72bc8b08e7e555aed3caae995f043762eec28072272bb89d42f41b19a8853a9c2050f883d5eabab858b5b27fcfc4020cefb51f0c825de27954206073f510eef06d8c0a09dc7a4d5e5989f952c7f12a1e5a2b1c2121ecd8745e1c39c0fd282f1ad2345a8c8609739a0a4033fc3e2f0d484cd089214fca076854ddc80e2921d44c44e94cbe1b8a452b81ffffda65f3c406d0bcfb87b851a2453590122b13fe8ce8fdc023679d6ea8076ce04c04b699ab46688389c6b3e4ec1d935c6baa76073e9126e39492a935a2d803c9a393d6ba3ceed5e981191e5872375e252a2f747c373c85c613a6cb56755140cab7e6b256f66c89af50ccbb7b20a5096c37400af9ec0b750cf7239747daac80cde4d086a881fb6bd32a9589648298d24662b7f70b315b43cd0eff8128f4b1d5c7622c6f121b95c4935a5791eda84f0a59d1ea39d85b88db4de02cd1b99d88e2e80b4fd5c288cf6d2416b164d9bd15dda7e6cde720dbdb616bda8b0744d070cebf3e43bab687bfa56cc7ef8a223fbe335ff5e7d0be9c8b02b6974b66ff9be1993c46efae12fef9e38b03d130bbaa397d99c3280c604586804cb022d22c3134c3ad2b9cf7d33a7d79037549bc9fa2c17b09c3d26ff06d8c8308ef10e34d7ec83bc5bf2f49cd6757b5b3909ba174efb2d6f43eed8f470c4d1ab9a750ce8b06d8fca7b8d9283801cebdc487ff8746e137cecc7a4886e82489e15e08e5ea043095b074c8726d1fa25dff7d5220bf493c648c0ab428b6b6a385196d0f6aa2d5000000000000000000000000000000", .Okay}, + {.Shl, "61b0cf45151b9cb9c7757b9019b3a98c6aeaea49d8d8eb3cdf3251835030b8d5c1d58335401215929e167291efeaae602502ae5d316e8f3c03b9a35487cf03ed09e308b82b17bbd1ccd387fd66c884cfb17bab11d1f82c709bde13392a035b1586b3494dec5b0bed913283433a4be8fe3a814e8e3b8c2d3c553d20a840738ee19b93e843feb2a581b4e1798b5d4d6975567065f0cde9d490c4161101a2482d157e27f3f560897d93f873a1319c4040f693c780fc2983cd1396788725261d7844daeecd3bcd9d0b498d46e5e3ccf240b2c85cf76632d49987394c54cdb375404eded46967f96b49d1b034a1b5e394ad702494d9e4a465984feaf16eb5c73db3fef2e26891021a997639959aabb9919d0a4cf18678cb9525c7ae7400e0333fa3d893a9608d13c988480d49d5e9fe2c1a1c2140232707bcb0f45c7703d32b8ae63e8a14e75b3c42f7528e7caf31136eba44a87d44c2ddf48e31dc019dcfb4540bbd388584ce698cd75ef175eea1ad90e318329a4e57482dce3ea4f885d02826f9966b88b8eaba6482daedc729b895d0f2dba0262602036d6a40b08fce22555b2fbf732534138ec3c126d79c10fa920e97cea9811c93d6bcd64180b94bd4b6d7cbdc66172e9eb176c44cde46d6213fa8a882b41aa4e2b77185eaa583eb8f66065c83f8585a1d46c6fddd6b46def1b9589ad5a47582dd3cc91c8239088957bc602f949a22f120874344c5de9cc10b1f21253e33c4a64ed0f7f6835d75b1fad256ffb00f6d502bdd1441380872d299c5ea0908dd4b2ae07c855e3b54bc4e2be5596db34a79811147cf6e489f4f3ef591606b7f8e2a3c80e3c61a7534e4343f7e678e748f4415cc1da073870e6d8d52610c08d86a02d9a13287ce7db5a4eff5871e3e894652f14e9c591f4da24b3f52ea7b144edec9ecf5a50e9f0aec677938f6ea0e6fa8aad9d6606e348e3e6045fd4dd27e6ac4076343e95a7844ccef5ead502b799aee4a16d5d41a249094540529e058c112b8b5e020bf258b937c0cb8b9e58bf4f0c432cfb6bfd431acd4fa83012424390675cb854c441b4213c45b74125920617ac8c70d5ea41e32fc859e25a780b779e7e92fa24f361866fffdcef42e4d1de21526a25ecbdd513e6b478435b04246c4dc8bf9ddf5446ef6cfbe418a376bafece35a76e13abd0874350e7a49ab3c01852e047cdfc92059a76fee3c0e205f4fc3b8e96707cadf0fdf29530d60336c4cb2e5b202319ad6dcd2f52f2fab3d5e20b1eb6f98ae0c688e93238feb4ea07c2ed678c6d918d2b8bee93dbdd21eec6262af7fd1721477e6d8613de23cafd012f7c520f500dac145b4a41923d19af773f8d19ebeb7d418d73136a6053eeff4586d17da0ebb960b8b390ce47b7843072ce6f825d1cfba4678cb7ba5d9e387e3e3beef88806d562445efc15b03d41f29b292466d1b62ba20957a99ccbc756f85299fcc2f8ad31f3a5d98fe30d077ae6b2d7083ca406f18887a28e3fe7dd92070ddf284f049fc93bbb110750d44b383f04b78656be57857f8d52f0819185fa9e0b60bb35e0a47c84e8264fe37e0081667cfc0a2d883a67e511faefda2bac7a7d9ae3943c6028f7e596a3a6e58fa87eb3f505da64e7d34cf44e58c93113b91b2ec5426b2f3f969c9256d0d09796a66e1d55d6a859f44531693a4048a9eebfa68d3c38a2b7331b89045f4c9e1f113d30f3fa74027488ee28758a6337798253a8888195b63c0ce2eaf2d3fef31b36b5e75c7e5c69a062b49b337ed378f92483a9755007ed71d60b2a510acf56c69a44bc76640aff22ed9bb24ea5eac8d4df5c9fc6be45530458569daec433d00265b798f86004f468ead3fe95167c5578ac86d959a51b65e9e12fc5eb53cf10b6e83d3b8e3d76034ce4cd1ca759d838dd72c941fe444eadb41cdb5f0bf0a1a384eaf9caf21a9f6f36dac959f6fdad20aa6b263ce6399ff9272364ed0aed540db83e871ae11310ad0597d8e19dd7b82d8fb77b56241675c9519bb03f32d79ba719ecf9b0d734d0d91081121b2cb4efc0438f43501ea7c4593d6df0e701907977b48d8bd35c89f2cd4740665482e95792f567478dcd34150aac67f0ec5bb100a6746141f967a", "51", "c3619e8a2a3739738eeaf72033675318d5d5d493b1b1d679be64a306a06171ab83ab066a80242b253c2ce523dfd55cc04a055cba62dd1e78077346a90f9e07da13c61170562f77a399a70ffacd91099f62f75623a3f058e137bc26725406b62b0d66929bd8b617db226506867497d1fc75029d1c77185a78aa7a415080e71dc33727d087fd654b0369c2f316ba9ad2eaace0cbe19bd3a921882c220344905a2afc4fe7eac112fb27f0e74263388081ed278f01f853079a272cf10e4a4c3af089b5dd9a779b3a16931a8dcbc799e4816590b9eecc65a9330e7298a99b66ea809dbda8d2cff2d693a36069436bc7295ae04929b3c948cb309fd5e2dd6b8e7b67fde5c4d122043532ec732b355773233a1499e30cf1972a4b8f5ce801c0667f47b12752c11a279310901a93abd3fc5834384280464e0f7961e8b8ee07a65715cc7d1429ceb67885eea51cf95e6226dd748950fa8985bbe91c63b8033b9f68a8177a710b099cd319aebde2ebdd435b21c63065349cae905b9c7d49f10ba0504df32cd71171d574c905b5db8e53712ba1e5b7404c4c0406dad481611f9c44aab65f7ee64a68271d87824daf3821f5241d2f9d53023927ad79ac83017297a96daf97b8cc2e5d3d62ed8899bc8dac427f515105683549c56ee30bd54b07d71ecc0cb907f0b0b43a8d8dfbbad68dbde372b135ab48eb05ba79923904721112af78c05f293445e2410e86898bbd3982163e424a7c67894c9da1efed06baeb63f5a4adff601edaa057ba28827010e5a5338bd41211ba9655c0f90abc76a9789c57cab2db6694f302228f9edc913e9e7deb22c0d6ff1c547901c78c34ea69c8687efccf1ce91e882b983b40e70e1cdb1aa4c21811b0d405b342650f9cfb6b49dfeb0e3c7d128ca5e29d38b23e9b44967ea5d4f6289dbd93d9eb4a1d3e15d8cef271edd41cdf5155b3acc0dc691c7cc08bfa9ba4fcd5880ec687d2b4f08999debd5aa056f335dc942daba834492128a80a53c0b18225716bc0417e4b1726f8197173cb17e9e188659f6d7fa86359a9f506024848720ceb970a988836842788b6e824b240c2f5918e1abd483c65f90b3c4b4f016ef3cfd25f449e6c30cdfffb9de85c9a3bc42a4d44bd97baa27cd68f086b60848d89b917f3bbea88dded9f7c83146ed75fd9c6b4edc2757a10e86a1cf4935678030a5c08f9bf9240b34edfdc781c40be9f8771d2ce0f95be1fbe52a61ac066d89965cb64046335adb9a5ea5e5f567abc4163d6df315c18d11d26471fd69d40f85dacf18db231a5717dd27b7ba43dd8c4c55effa2e428efcdb0c27bc4795fa025ef8a41ea01b5828b69483247a335eee7f1a33d7d6fa831ae626d4c0a7ddfe8b0da2fb41d772c17167219c8f6f0860e59cdf04ba39f748cf196f74bb3c70fc7c77ddf1100daac488bdf82b607a83e5365248cda36c574412af5339978eadf0a533f985f15a63e74bb31fc61a0ef5cd65ae1079480de3110f451c7fcfbb240e1bbe509e093f927776220ea1a896707e096f0cad7caf0aff1aa5e103230bf53c16c1766bc148f909d04c9fc6fc0102ccf9f8145b1074cfca23f5dfb45758f4fb35c72878c051efcb2d474dcb1f50fd67ea0bb4c9cfa699e89cb192622772365d8a84d65e7f2d3924ada1a12f2d4cdc3aabad50b3e88a62d274809153dd7f4d1a7871456e66371208be993c3e227a61e7f4e804e911dc50eb14c66ef304a75111032b6c7819c5d5e5a7fde6366d6bceb8fcb8d340c5693666fda6f1f2490752eaa00fdae3ac1654a2159ead8d348978ecc815fe45db37649d4bd591a9beb93f8d7c8aa608b0ad3b5d8867a004cb6f31f0c009e8d1d5a7fd2a2cf8aaf1590db2b34a36cbd3c25f8bd6a79e216dd07a771c7aec0699c99a394eb3b071bae59283fc889d5b6839b6be17e1434709d5f395e4353ede6db592b3edfb5a4154d64c79cc733ff24e46c9da15daa81b707d0e35c226215a0b2fb1c33baf705b1f6ef6ac482ceb92a337607e65af374e33d9f361ae69a1b2210224365969df80871e86a03d4f88b27adbe1ce0320f2ef691b17a6b913e59a8e80cca905d2af25eace8f1b9a682a1558cfe1d8b762014ce8c283f2cf400000000000000000000", .Okay}, + {.Shl, "-f3ce7d77ebea75b4411bc0d5226dc8ae0482b6d67466900c4ca65caafc99fc498004f0ea1bd708085da07229a732980b090ef5c255c35e4760e50e39733615ca4d77b6382024b72ba3beb8a91464c7c9772f669823885608b1872f7f20b3a0347a613964dcdd1b56015106eb99b9b8c2df72b9628271058f16a5c7a627ef6f4ff44eca438e7aa3a4014c7b1d5d1b8163addce57c2919a4d51e300d42e84562dfdbde38668476a3163d8a1d163c83c6b293f6fe96b3e7582a7ae928d97954c6eb29ec4e6fbd7931132538eb00e70b36c5ae2c5a4d3ce9691d23633656ca199805294dc34a4031f369ca7996b33476b1895493c8125f16dc77fbb572a7c17acaab742d02de695005ce15083a541b7f331452aed1a42e1602e4b3fafdd41b281a108b854ecc7d87925b92de593eeadd2caa927fe2a99e23e4ce0642283ffb447691f14e3f71791ccd96d741e476782e64506923ccb05f5b1a90938cd7756a05e1084b8898adafba22af6d16ddb6560eb436bfbb39641a64b9b7580e1de990b450196f45fb8edf588fcb16782eb64a976c4012433aae501cad92dfa4d02f93bff2821228360bc082849425ce7675f3c8de3d8df893e3d13bbf342b1860d8f54da722ab02971019faae45ef0a458e58463af26522f27cc817c3942a86f8843377abe5deaec12ae78837871eadc2e73479125a7b9a981ff85dc0771cf39914dcf7a6c6251404efbd8af0b42be26ccabfbb2f8b5e6ad1607e88fd86085acfee6713f7f7fe95ed18338d59c97e9178a2a12c623a7fdb0cdc853d823b1f8daf56c5f73b743b89c24e666456575a58f28de614c612bd131773c55de2a7182da6474fd500f98eb45f0e3a7110f9346e2564c5ebc3eff17aafee6c97d0ea9c093ad17adf99d27069c0d582554c5f1ba398b98583d4ecc3ac57b999d1c0fb93d202747d8abf2aa4b952e060953060f1481840f83ac21483545d3e93d8ba700f5d2ca4c358b0cb8ce06aaef356da238e9f012e6f614a4a28358a56bb0fb24cde51b8b3cac57178a01b90c06b3787478c24b04ff2782972f09305828a0f6b58331be2a5243b8262baeddf9c56adcdb217c692e3627b9aab3063dbc1a049892f9601c44075dc8ea800a0ed1640e3b8392e7063404e479da85b36dd5c289f0e960e93ec6b4b334751fe3c7ddeb6468b229934a061a6ef0ce662560c9d25795a8893b39f4a2ca29ff7f77a8ed5989c9a6e171c5a7f7e3b28924482e726eb152a5c8a2d564d14f27e72ea4231cb9b3e864538c39e8cf07bc97494431b7e2770f8d202dd904115719a1625761b122f7b73fbd87ab494d8184443da38e4b3a3fb2c8e2d58ba73e5455206d71f7b305a2fb15eb1d7beb2f3f4c40c0b2736116a69b670afa9ea02af8d2564eb2d23d99401395abc3b4434f964dc094a65cdb95bd793bc8ad0224e7d42fc881bec404462284d43643598859fbb0f2848f797b42e89deed1712ec5754617c33a0d37c1f6a217bd09ffeab8070f642419c9031a6c3c8e225560c8bf314b1c94ea494e25ecf75fc7fd8c0c78d6076bf0b630e5a43c0ed6810044917b3ae69b8221ac1abe1e87bd4c05a7069f61e2bc0748c503bc580d3b8e04b498de2e43cc21e5e67ec77e4ced81180b51fc1183ba7eee16d559af0cd8fb3fbf7baf61be5ca4aabfc2cef1af256fc93c1a16c18833e1338fc3d4f4dadcafab385db4932b3c7711ba659e77a344fc9456990899c9ecdeca5c0f52c1969162aa765921b40b7e9cff1ba55be3afd14f09aa5aa203ce0e55c783b96d960282a3a7316f4f5ef73d962aa69bd638b3f8b514a1642b409203b38958ea1b0ccd4676a8b7159eedbdadceae5e1e521f11c2968f4cf51e4ac5511884f30f6961a3be7a86f0c0851a70e1039cde4c1d3a84dff17d227be61797b469570febcee819f617b4311852079d091c985c63df197d03e2e8037567a2176ed557385d69973f495fd0bf3576071b3ebdd6cc9d096626b3972e51a00467e314204176ed65b9f8ab407eea04a4f83bce473da2ef0e93223f7d937b5255e2e284ce7a293a89d35e81fa7ba7e01e7e2cb6cf07d2658eee871ecf9d77424ee655e8a4c9a1921c9763b4db4219b9cf0", "4f", "-79e73ebbf5f53ada208de06a9136e45702415b6b3a33480626532e557e4cfe24c00278750deb84042ed03914d3994c0584877ae12ae1af23b072871cb99b0ae526bbdb1c10125b95d1df5c548a3263e4bb97b34c11c42b0458c397bf9059d01a3d309cb26e6e8dab00a88375ccdcdc616fb95cb1413882c78b52e3d313f7b7a7fa276521c73d51d200a63d8eae8dc0b1d6ee72be148cd26a8f1806a17422b16fedef1c33423b518b1ec50e8b1e41e35949fb7f4b59f3ac153d74946cbcaa637594f62737debc9889929c758073859b62d7162d269e74b48e91b19b2b650ccc0294a6e1a52018f9b4e53ccb599a3b58c4aa49e4092f8b6e3bfddab953e0bd6555ba16816f34a802e70a841d2a0dbf998a295768d2170b017259fd7eea0d940d0845c2a7663ec3c92dc96f2c9f756e9655493ff154cf11f2670321141ffda23b48f8a71fb8bc8e66cb6ba0f23b3c1732283491e6582fad8d4849c66bbab502f08425c44c56d7dd1157b68b6edb2b075a1b5fdd9cb20d325cdbac070ef4c85a280cb7a2fdc76fac47e58b3c175b254bb62009219d57280e56c96fd26817c9dff94109141b05e041424a12e73b3af9e46f1ec6fc49f1e89ddf9a158c306c7aa6d39155814b880cfd5722f78522c72c231d793291793e640be1ca15437c4219bbd5f2ef57609573c41bc38f56e1739a3c892d3dcd4c0ffc2ee03b8e79cc8a6e7bd363128a0277dec5785a15f136655fdd97c5af3568b03f447ec3042d67f73389fbfbff4af68c19c6ace4bf48bc515096311d3fed866e429ec11d8fc6d7ab62fb9dba1dc4e12733322b2bad2c7946f30a63095e898bb9e2aef1538c16d323a7ea807cc75a2f871d38887c9a3712b262f5e1f7f8bd57f7364be8754e049d68bd6fcce93834e06ac12aa62f8dd1cc5cc2c1ea7661d62bdccce8e07dc9e9013a3ec55f95525ca970304a983078a40c207c1d610a41aa2e9f49ec5d3807ae965261ac5865c670355779ab6d11c74f809737b0a525141ac52b5d87d9266f28dc59e562b8bc500dc860359bc3a3c6125827f93c14b9784982c14507b5ac198df152921dc1315d76efce2b56e6d90be34971b13dcd559831ede0d024c497cb00e2203aee47540050768b2071dc1c973831a02723ced42d9b6eae144f874b0749f635a599a3a8ff1e3eef5b2345914c9a5030d3778673312b064e92bcad4449d9cfa516514ffbfbbd476acc4e4d370b8e2d3fbf1d944922417393758a952e4516ab268a793f39752118e5cd9f43229c61cf46783de4ba4a218dbf13b87c69016ec8208ab8cd0b12bb0d8917bdb9fdec3d5a4a6c0c2221ed1c7259d1fd964716ac5d39f2a2a9036b8fbd982d17d8af58ebdf5979fa620605939b08b534db3857d4f50157c692b2759691ecca009cad5e1da21a7cb26e04a532e6dcadebc9de456811273ea17e440df62022311426a1b21acc42cfdd8794247bcbda1744ef768b89762baa30be19d069be0fb510bde84fff55c0387b2120ce4818d361e47112ab0645f98a58e4a7524a712f67bafe3fec6063c6b03b5f85b1872d21e076b40802248bd9d734dc110d60d5f0f43dea602d3834fb0f15e03a46281de2c069dc7025a4c6f1721e610f2f33f63bf2676c08c05a8fe08c1dd3f770b6aacd7866c7d9fdfbdd7b0df2e52555fe16778d792b7e49e0d0b60c419f099c7e1ea7a6d6e57d59c2eda49959e3b88dd32cf3bd1a27e4a2b4c844ce4f66f652e07a960cb48b1553b2c90da05bf4e7f8dd2adf1d7e8a784d52d5101e7072ae3c1dcb6cb014151d398b7a7af7b9ecb15534deb1c59fc5a8a50b215a04901d9c4ac750d8666a33b545b8acf76ded6e7572f0f290f88e14b47a67a8f2562a88c427987b4b0d1df3d437860428d387081ce6f260e9d426ff8be913df30bcbda34ab87f5e7740cfb0bda188c2903ce848e4c2e31ef8cbe81f17401bab3d10bb76aab9c2eb4cb9fa4afe85f9abb038d9f5eeb664e84b31359cb9728d00233f18a1020bb76b2dcfc55a03f7502527c1de7239ed1778749911fbec9bda92af17142673d149d44e9af40fd3dd3f00f3f165b6783e932c777438f67cebba127732af45264d0c90e4bb1da6da10cdce7800000000000000000000", .Okay}, + {.Shl, "-a1a387c7436ee2efe94d9bd870295fcca67fb9717a19e2b3ae28b2dfb529f28989ed4c7821198e65dd226cdf05be8b30a07005c23dac2d529a903548b0ca63b3f81607b805cbbbbc4c6b071c825d9a6d0ddb6bd64572f10846d45ecfa69b88343aaa547e77af29a3b0a6f4ca6ae2780254696ec606f982d00c821b9efb38e017da8af9f73ea20a40812f93d78f11dafc70dc479552d538673ea4a630ba9cf3c07e8670c2a6ff042d308aa8d7498f58df0722a356285eceab4505f07911ed163effbc9ccc02f2f407425172b9f4687c170836e056e8cc0030b24764a38338c4589f906a67c46b92693d6f457b9442e51183211505d1afab48c93ec6b9d87a7209887e0f2ad61a5942940163551f044b07e63d71a74812fd7cbd7a56bcf43d306e2dc94ecf1a9d5ee1c4a33884dffbba2dcba3a3e956e17795a49f66dd6f1adaeddf6667054912fc31ee2c9f964e32f20032c0b521480475e826cd7fb8eb2dd30f156f0df298d6053c85961659fcb965d20e70d7a83bb575c19a6e6595dd38767824f01074c8eca015840bdac2f173c902c8a0e02a8ca336f67e7e9d85e98fe14cb38877189af3fc796c3e752069ebba4c0204d826b5ef412e5534d0bf98eb68bcb617b72cd3fe8218c74169f51cd1a649d02ca50eb82450cd8bb4cd163e66d73c85c2dea381d5d16ab844149637eb8673cc43e01f8325b629274392d16dc09ad6ccdfee7fc53d903a80867c1f2b735cb62dce49fefaa79fd30115f5dbfac71c7fecca7b4e363ac5e17427956ba0a420485135339ba9c4c79dc0211a94caf99a5b22dab0d81d8f2a7637b425ba103e8514fc4e6adc15009b706eeb4a26b8c96ed99792b8f7a8c154d70e801dffbc1e46974bfa4153fe71d7617d3d75676507d931c8f37eaddeb48db694dd37217fd03a9ddbe1b5dfd9f75391bc1e0037b6724f44db6f158569fbf595f45c8659883c1f3fc29d4d82557093b20c29e67ce7bb8994727f46e3c9e50ace29bd1eb97c3019807273da2ef0b2e5944018ad9656652a5649a895c3b9502b3d698b98bc93ff7d88487c1ee61c8ddc9f03734e82e58eae110b6d49d2f6099319da275e7ef5366ec5bc48fa706cf40b8253eccfa41c06b210316784b7e3d7a36c77dc9fdf19eab8dd8ef35a80fa964672aa431989efbb30039beba3acdf35e30dc254dc74a5f8aea62d8948fa580b10a535323854fd8eb76d3164259ba7c950d2d2f968f7c72ea14e353c4595759144d0ae9451bd7f4cfb54acf510a1c9510edd973f10fbfbd6800788fff5842fcaf1ad163b6b735e6f720b987e320b5735c91b461856e324a1c12d827db2d78cfe425b777cc4561d06f1c68dd1ead8d92961a00cfbe5a6e59943781a388bb65bf986d2683803d071f9cd2cbdc291ce9a860629840ef748c876f14565439ad380c55831060cc0c5f8e9be4a090d09fa34edd91870d03f389f17cba6ac2be335f559558f8f52cb6b7876600a2e838b00f364b3f883640cea218443a6a6be42da8b2c1ac498ceac527d0a028af39c636fdd016e9351cd3dc1c02aba175f40e909458460d7d8c8ff7d2a811d46196446cb6ba3a13b4bab2c4400b3c2e3cf27600ef4a56646062b6d3bd97b5cafe7c82e7a692cc77118550978a81f954569c6ceea4636d4240bbddf1992fce98d1f4437acc714961b29c07c2adf1e35885bd1404e5c5aea71f2a93a0aaf8908a4d7c70b364249bf8ba8418818c9cb1cff9363a69108b7f0b0aad233d401345adb7aa1ac3d7261865d06fc60566e914e27bc35c8bfacc614aded85f242e9ba2ca872654ac9ac5ea79d02f612307491745b7f7bb318c6c6adb66f2c6feed62509b29687cd7cfbf74acd032f32a0afa282a8eb4c8a2561e4e325dac6d982cb3e64f78eca7a19c51f60b7ad30a47abd0973c4949b9d41f6971889518621784802821c6875d4d2cd47e32f8b1f4d0e6880dc5c1090332dd1813830f383753554d904e5872ee5c99213d2c62dd86bccd8c3f9004c93ffefd3e11b2b75af2c3ffc3f28e2248e022def4ad6f78fca6da39106f9148d3853366a6b6a99c387cf28474251c7d9446eba57e336131600e471f11959e0e304241bb5f71f6986b63cfb", "46", "-2868e1f1d0dbb8bbfa5366f61c0a57f3299fee5c5e8678aceb8a2cb7ed4a7ca2627b531e0846639977489b37c16fa2cc281c01708f6b0b54a6a40d522c3298ecfe0581ee0172eeef131ac1c72097669b4376daf5915cbc4211b517b3e9a6e20d0eaa951f9debca68ec29bd329ab89e00951a5bb181be60b4032086e7bece3805f6a2be7dcfa88290204be4f5e3c476bf1c3711e554b54e19cfa9298c2ea73cf01fa19c30a9bfc10b4c22aa35d263d637c1c8a8d58a17b3aad1417c1e447b458fbfef273300bcbd01d0945cae7d1a1f05c20db815ba33000c2c91d928e0ce311627e41a99f11ae49a4f5bd15ee510b94460c84541746bead2324fb1ae761e9c82621f83cab5869650a50058d547c112c1f98f5c69d204bf5f2f5e95af3d0f4c1b8b7253b3c6a757b87128ce2137feee8b72e8e8fa55b85de56927d9b75bc6b6bb77d999c15244bf0c7b8b27e5938cbc800cb02d4852011d7a09b35fee3acb74c3c55bc37ca635814f216585967f2e5974839c35ea0eed5d70669b9965774e1d9e093c041d323b28056102f6b0bc5cf240b228380aa328cdbd9f9fa7617a63f8532ce21dc626bcff1e5b0f9d481a7aee9300813609ad7bd04b954d342fe63ada2f2d85edcb34ffa08631d05a7d47346992740b2943ae09143362ed33458f99b5cf2170b7a8e075745aae1105258dfae19cf310f807e0c96d8a49d0e4b45b7026b5b337fb9ff14f640ea0219f07cadcd72d8b73927fbea9e7f4c0457d76feb1c71ffb329ed38d8eb1785d09e55ae8290812144d4ce6ea7131e7700846a532be6696c8b6ac360763ca9d8ded096e840fa1453f139ab7054026dc1bbad289ae325bb665e4ae3dea305535c3a0077fef0791a5d2fe9054ff9c75d85f4f5d59d941f64c723cdfab77ad236da5374dc85ff40ea776f86d77f67dd4e46f07800ded9c93d136dbc5615a7efd657d172196620f07cff0a75360955c24ec830a799f39eee2651c9fd1b8f27942b38a6f47ae5f0c06601c9cf68bbc2cb96510062b6595994a95926a2570ee540acf5a62e62f24ffdf62121f07b987237727c0dcd3a0b963ab8442db5274bd8264c67689d79fbd4d9bb16f123e9c1b3d02e094fb33e90701ac840c59e12df8f5e8db1df727f7c67aae3763bcd6a03ea5919caa90c6627beecc00e6fae8eb37cd78c37095371d297e2ba98b62523e9602c4294d4c8e153f63addb4c590966e9f25434b4be5a3df1cba8538d4f11655d6451342ba5146f5fd33ed52b3d4428725443b765cfc43efef5a001e23ffd610bf2bc6b458edadcd79bdc82e61f8c82d5cd7246d18615b8c928704b609f6cb5e33f9096dddf31158741bc71a3747ab6364a5868033ef969b96650de068e22ed96fe61b49a0e00f41c7e734b2f70a473a6a1818a6103bdd2321dbc515950e6b4e031560c418330317e3a6f928243427e8d3b76461c340fce27c5f2e9ab0af8cd7d565563e3d4b2dade1d98028ba0e2c03cd92cfe20d9033a886110e9a9af90b6a2cb06b12633ab149f4280a2bce718dbf7405ba4d4734f70700aae85d7d03a4251611835f6323fdf4aa04751865911b2dae8e84ed2eacb11002cf0b8f3c9d803bd295991818adb4ef65ed72bf9f20b9e9a4b31dc4615425e2a07e5515a71b3ba918db50902ef77c664bf3a6347d10deb31c52586ca701f0ab7c78d6216f450139716ba9c7caa4e82abe2422935f1c2cd90926fe2ea1062063272c73fe4d8e9a4422dfc2c2ab48cf5004d16b6dea86b0f5c98619741bf18159ba45389ef0d722feb31852b7b617c90ba6e8b2a1c9952b26b17a9e740bd848c1d245d16dfdeecc631b1ab6d9bcb1bfbb589426ca5a1f35f3efdd2b340cbcca82be8a0aa3ad32289587938c976b1b660b2cf993de3b29e867147d82deb4c291eaf425cf12526e7507da5c6225461885e1200a0871a1d7534b351f8cbe2c7d3439a20371704240ccb74604e0c3ce0dd4d5536413961cbb9726484f4b18b761af33630fe401324fffbf4f846cadd6bcb0fff0fca388923808b7bd2b5bde3f29b68e441be45234e14cd9a9adaa670e1f3ca11d09471f6511bae95f8cd84c580391c7c46567838c10906ed7dc7da61ad8f3ec00000000000000000", .Okay}, + {.Shl, "b5380d0bb3d6031217f588ddf64f2242f5886f7c80b04a89f0211d342582f08a59b86c09d600c0490b30fc8787b135cd866cceb4c316ec46f4fabe9ac250eb45a759b9501d6afa82ae8113558b53af1707644c482e38de9079385410d9c4dd92fc3023004e94415130b0a5c6436d9a9c7828b28a745b1e04ef60ef532e888cb00e5b6fa5c24f463897d38eba8b20d7da7a9c68167309352e95fc23fe39785bb9f80b3c1afd4bf0b08d6a1f99e864bc14fb6016d2e62c7881389d82f5a76acbb138431e13e54821e5f3b36bd00a7d8a1776a8af286514ce1ca44cbbf5ed50932398d667d6aaad132244916547f1a014a8b64eb5cf8ac747bc56ed01c0efbc00dd65b24d6c6deeb21adfaec41a96b50e27af488c5c51ab33ca600a0c641a418fb744a367438b71b4f2439f3ead2607c51ad47e36356e242a9899c965667cb0645311d63386a04b2b67722e8cde6c413ce076f664580eccc873b10e885a1868f53703598ddcfca809cd3083a5b0ee8dcffa7852f41acab4c0878df03897e077a883ca4209f569f81c32c77750e6a2969f3a881a986cce591c4be03a22e8fdc7a839dedc5c9c859b266fd7c5b94fb9a9845965747dbd73cffd5fcde3751ddbf8a07849907ab2bbddce9d84ddb6683e5233b3bdb4784b54795101fa35d1286db3fb4ec03c0541e0362cbf663996ea1f3adabb862045de76afc705036f9a4a44f862237d8d01c79a8beaf37296c70eb5a290a753d6b9ad02a46724691a7fe44052b747fd8034d22bf3e5915d6145590b63b9c46798df320634154d8acebf2746887750f5a96cc2e915109f0a404203bb6da8cef20f11f737976653a9b7a386031a0f523c5d64a1f7d890f800e32f6ae07975aed034a54dcff56079ad4f09232cdfd77cd6ad896fe7494cf767262f26e5be184c7c8615b87ac02c88f2d0f9ec922d99c3c8106c7c15f0cf1605cc2ebd250f4174fe5b03d381463d196475665677f10902d1b872fded3f56bd4de026ffdb9e0385b9ddedc10f620303e2d3412cfba47e1e092b1bdfe8e8055dd186517931890a9baeb34d944c9f164166814de080407722be03da8cf591f63a2a0df7eb9b43f958a6ab2cb71fea9737e4179eee7db7d39230e8830813da418a7e851403806a70173464f559b40d3151436a82c7bcf3793e438566c0040b59e2812dc7c3fb377412fe1eac20576850d6eeb9afb8754d8c0650341e79b179c0a34f6eb1781f6cefd3d617f69bf70e83b73ab12e361b86f13fb6fe57ae02f299c3d659f8031757128bbc21d770cd8ce455dd74cc93c9929ae055809953fea49e5be2fdc21196b7204d7605a572b20e961ba8d2ea3249ba74cea01f94bcb363ac8875fec944c3d0203d1b1ca2f98bc27d0e721fd0757233cf5d932cb83dd2780d16a41f9a688e33c4dc321726b6deedf728ceeafca9a4af259662b8f6c507af0334411ce40011adf6209669396aa9821b94474092b9512dcbec04d33e8ee1b223394d2b43c70bacb67fd845f2dfb51b69d7834deb8b71f258b4cf1ad898d10c68d3808ab9650f1b02c89f465f3859bb7655dea173c59eb79a90e882fe6335ec634e853d582fe0a5fb548771f6f54a8926c30e9345e230f9f14cfb60b4cc2db652fafc3384ced4e8a480acf5363eaee892b8f0f74fa26b52b6231db192ae5adf76abe171777dad49b958f1d3cba25cf88b1f8b7cfdd6529f943dafe8aaa69e4fc0ad83c245568377242b0c5a0362886f5aad4540e618f8a1237cc161d1a2663b4a93b1c79ef550625960dea6b1eab426dfab19cbc575011e9dc5d50a2bfe3caa7d6e317bc8ad35fa5eb6fb829349db84941e2d30031132cd6144573fadb0734917640314c02703d16e47b054863ad24015bfb48dae779b7dc2b6671d1fea03871f57b23279b141615227ac62bf59ca1fe4bd7efdd8c89f3454fa629c9aeb522c4682b37d469dd636be71c7240c1770805de995c2d86d24ccbdb5d6faedd15b357521d6d5243b4233512f6e5e4b269cdf6c5827f7ca25c79b08a460050f89c328650b1f6464349f7bca7f9508c68cd2e8399afd98f3bb8f2beecf7115808e033ed8fd0880e7bddd24bbbde5238364e34f2a89848616aa", "21", "16a701a1767ac06242feb11bbec9e4485eb10def901609513e0423a684b05e114b370d813ac0180921661f90f0f626b9b0cd99d69862dd88de9f57d3584a1d68b4eb372a03ad5f5055d0226ab16a75e2e0ec898905c71bd20f270a821b389bb25f86046009d2882a261614b8c86db3538f0516514e8b63c09dec1dea65d1119601cb6df4b849e8c712fa71d751641afb4f538d02ce6126a5d2bf847fc72f0b773f0167835fa97e1611ad43f33d0c97829f6c02da5cc58f102713b05eb4ed5976270863c27ca9043cbe766d7a014fb142eed515e50ca299c39489977ebdaa1264731accfad555a26448922ca8fe34029516c9d6b9f158e8f78adda0381df7801bacb649ad8dbdd6435bf5d88352d6a1c4f5e9118b8a3566794c01418c834831f6e8946ce8716e369e4873e7d5a4c0f8a35a8fc6c6adc4855313392caccf960c8a623ac670d409656cee45d19bcd88279c0edecc8b01d9990e7621d10b430d1ea6e06b31bb9f950139a61074b61dd1b9ff4f0a5e8359569810f1be0712fc0ef5107948413ead3f038658eeea1cd452d3e75103530d99cb23897c07445d1fb8f5073bdb8b9390b364cdfaf8b729f735308b2cae8fb7ae79ffabf9bc6ea3bb7f140f09320f56577bb9d3b09bb6cd07ca467677b68f096a8f2a203f46ba250db67f69d80780a83c06c597ecc732dd43e75b5770c408bbced5f8e0a06df349489f0c446fb1a038f3517d5e6e52d8e1d6b45214ea7ad735a0548ce48d234ffc880a56e8ffb0069a457e7cb22bac28ab216c77388cf31be640c682a9b159d7e4e8d10eea1eb52d985d22a213e1480840776db519de41e23ee6f2ecca7536f470c06341ea478bac943efb121f001c65ed5c0f2eb5da0694a9b9feac0f35a9e124659bfaef9ad5b12dfce9299eece4c5e4dcb7c3098f90c2b70f5805911e5a1f3d9245b33879020d8f82be19e2c0b985d7a4a1e82e9fcb607a7028c7a32c8eaccacefe21205a370e5fbda7ead7a9bc04dffb73c070b73bbdb821ec40607c5a68259f748fc3c125637bfd1d00abba30ca2f2631215375d669b28993e2c82cd029bc10080ee457c07b519eb23ec74541befd73687f2b14d56596e3fd52e6fc82f3ddcfb6fa72461d1061027b48314fd0a280700d4e02e68c9eab3681a62a286d5058f79e6f27c870acd800816b3c5025b8f87f66ee825fc3d5840aed0a1addd735f70ea9b180ca0683cf362f381469edd62f03ed9dfa7ac2fed37ee1d076e75625c6c370de27f6dfcaf5c05e53387acb3f0062eae25177843aee19b19c8abbae99927932535c0ab0132a7fd493cb7c5fb84232d6e409aec0b4ae5641d2c3751a5d4649374e99d403f297966c75910ebfd928987a0407a363945f31784fa1ce43fa0eae4679ebb2659707ba4f01a2d483f34d11c6789b8642e4d6dbddbee519dd5f953495e4b2cc571ed8a0f5e06688239c800235bec412cd272d5530437288e812572a25b97d809a67d1dc36446729a56878e17596cffb08be5bf6a36d3af069bd716e3e4b1699e35b131a218d1a7011572ca1e3605913e8cbe70b376ecabbd42e78b3d6f3521d105fcc66bd8c69d0a7ab05fc14bf6a90ee3edea95124d861d268bc461f3e299f6c169985b6ca5f5f867099da9d1490159ea6c7d5dd12571e1ee9f44d6a56c463b63255cb5beed57c2e2eefb5a9372b1e3a79744b9f1163f16f9fbaca53f287b5fd1554d3c9f815b07848aad06ee485618b406c510deb55a8a81cc31f14246f982c3a344cc769527638f3deaa0c4b2c1bd4d63d5684dbf5633978aea023d3b8baa1457fc7954fadc62f7915a6bf4bd6df7052693b709283c5a600622659ac288ae7f5b60e6922ec80629804e07a2dc8f60a90c75a4802b7f691b5cef36fb856cce3a3fd4070e3eaf6464f36282c2a44f58c57eb3943fc97afdfbb1913e68a9f4c53935d6a4588d0566fa8d3bac6d7ce38e48182ee100bbd32b85b0da49997b6badf5dba2b66aea43adaa48768466a25edcbc964d39bed8b04fef944b8f361148c00a1f138650ca163ec8c8693ef794ff2a118d19a5d07335fb31e7771e57dd9ee22b011c067db1fa1101cf7bba49777bca4706c9c69e5513090c2d5400000000", .Okay}, + {.Shl, "5fd926e1d24796a653e18b824adce43a27e0074d0d04b01e2eeebb349ca423f1083aa209cde6f616bee6b67621886b3ade3a93922860aeadbb8ccda4974abee516a1181ee3debb95e58dbf2db6fdbfc316d4a813449ca3c2e46fc8b621c8c9289208346de3ae905c0c9b9959bf2c19c317aca5d4e0828168e03e57963723a3d65952316e0bca798361dd1ac7ef6281252cddd212a956e0cb3d53099f7d8fde148d29c407c5c1b5d45103ef853ea7788a5b8eeb4fb8160acd89b69106dccaa471ab7b42fe9b465db70f230ccf2af765142d0e629c4bc37f3b859781722dc297dbe2ea72c7416e5bcd66e4a20ecadec31d9a24329a6751e9490a06e4b5a99ac6ddc5bc80211f3aee6fbbdb05e4b85cae8cb66a05dc5a69744fc18f38f5e60613d07b43dbc02fde90bf034d1e9cc946175bf595961b0b27df954635918ce7863f974f201b49486d48a73cbf81d5aab1a8f77d19b5de1be2079c29f578466e448c9b90155cf2e829f849f2cf108cc3f8be1f964c8191a8438cf05cf1e9d1f44564a7532d16cea8a7f36b70894e97cab71be19e9efc8115315cdfab353a69fcf0871b8cc3a339f441b73e3955ef64f463bd0c26b442b22c0363b8d70a9e2e3dbd899bbcdd5cd7c0f868a6e7e2d2c15d7f3e8a2ed4ee95b87361d1ec5486f680b7ffa8278d3a32166ebb1a2a6671acd3faa6ea18c5a1412db80012c4651659b18d097eb4f086d75fa8eab40bf23a4b5f52f1e512bbc676f90c4eb1c3b5c3345ff9e6a9616c82439bed43a9af8e36b26e5e06cc55478d756a3590395d8bce130644da4b11a999afae48f2fcec1f7e4db94035bef83bda37d45986f47320fc7c306c7877f9d3b1f6f1030ee9b4d3f01e35793e1e62c2a94506c422fd237410cabbebcd6693b59582f4f6865e25eda68492c63900b9fb311186f6890477f3d08c12dcf865e7049a8a8bdaa197134d96b25412f17c4d2f60d1c20415c6c1dfd0a87391e1d2b3421651b77ba3df0b7e235ff872f63501e220d7e7906f6ace4b7d2c308a10c44423a1e7cd83cea2ef24ce6e66849936eda800ee23004f7601f2867566d62ce3ff6457e0c7ffecaca9d8e1bb9922d08f27a77e82bf33b7f00158228d9407df53d42fd499047404045fc4f47803387ae1765ef25dec5596100be80e89d338f043a34716506995308d0bbcfde5b2a98da50f291a08eef1656efe9e1ec9f2d54564504ea13ea5a0621a19b81f9f97d3cbcc0909d9005609816c26014b5fd0b1d5263756dc6c85dc39c76502644b40b442748ff353b5eec98692f9099cdf283ef6acdb582e5f90fc95daac76939c7fb6122894d455f99f7da9534b0caa40c760b953434931da5cbe045dac04d6713a6efe602e250d16d392c324820b0b7552c8acee56f3dc5615f9d657badb7f2f5765e7873869f52cbe6ee716dba0c640e57b43f77d33b71e7f8175480001fead7b633be6149f23a3e8bc2dd2d8b3260edac2deb3c358e25dab6ea2255d333478ac4270f606fb39538152259b6ae2ebe26388936d46923db3274ec17afdd362208645e1c2378d0168e79fee78085b8bff8253fbc67d1a5ac17c4b7625de15d4f9b55f09ad536195ada68870e93b8307df0df06e0fbe1be7364879b21ac4fc587953a630ff28b4670e134486616715b6d1cded3702fe01b59f8e4dd9edda0ad8036827364341f7774ef84f022fa9340cf884ca72d59f1f76295de9ede192e310d01d0c6c8e3e61540409f5b1972fde849176fc9496ec06894c74af9539f5f7580cd6d11fda1769f32792c3ff05d9eaaee8cebb531a831c2f1d7557b1bc5705e66740fe830e1963b824e28efd6d4c86a8b3d34a6eaed1205bc6a1d65ff47060469d1870d11ef93f617828efc33aee73a89f6dc1d107dd4f4046e6c52b50a053cebc0e84fba315fd8bf735c1d929a7ca29ef9e24c0ed6a82d2c90fff1cc479a8ce3f23b4bbe11d311a27b8fd05a432d92738801ef6ae6b23a783579a55448e75716869e86f13c06064712de0c7e4645ab1146f635790288da1792e2cd4dd6e0d038fb0796b9869ee7b5c54190ca4624e2f6c06bdd66e936ad9774d41013f5f8277f20f45b6c63676ed5bbfe283713fe4cbb2", "1f", "2fec9370e923cb5329f0c5c1256e721d13f003a68682580f17775d9a4e5211f8841d5104e6f37b0b5f735b3b10c4359d6f1d49c914305756ddc666d24ba55f728b508c0f71ef5dcaf2c6df96db7edfe18b6a5409a24e51e17237e45b10e4649449041a36f1d7482e064dccacdf960ce18bd652ea704140b4701f2bcb1b91d1eb2ca918b705e53cc1b0ee8d63f7b14092966ee90954ab70659ea984cfbec7ef0a4694e203e2e0daea2881f7c29f53bc452dc775a7dc0b0566c4db48836e655238d5bda17f4da32edb87918667957bb28a1687314e25e1bf9dc2cbc0b916e14bedf1753963a0b72de6b3725107656f618ecd12194d33a8f4a48503725ad4cd636ee2de40108f9d7737dded82f25c2e57465b3502ee2d34ba27e0c79c7af30309e83da1ede017ef485f81a68f4e64a30badfacacb0d8593efcaa31ac8c673c31fcba7900da4a436a4539e5fc0ead558d47bbe8cdaef0df103ce14fabc233722464dc80aae797414fc24f967884661fc5f0fcb2640c8d421c6782e78f4e8fa22b253a9968b675453f9b5b844a74be55b8df0cf4f7e408a98ae6fd59a9d34fe78438dc661d19cfa20db9f1caaf7b27a31de86135a21591601b1dc6b854f171edec4cdde6eae6be07c345373f16960aebf9f45176a774adc39b0e8f62a437b405bffd413c69d190b375d8d153338d669fd53750c62d0a096dc000962328b2cd8c684bf5a78436bafd4755a05f91d25afa978f2895de33b7c862758e1dae19a2ffcf354b0b64121cdf6a1d4d7c71b59372f03662aa3c6bab51ac81caec5e70983226d2588d4ccd7d724797e760fbf26dca01adf7c1ded1bea2cc37a39907e3e18363c3bfce9d8fb78818774da69f80f1abc9f0f316154a28362117e91ba08655df5e6b349dacac17a7b432f12f6d34249631c805cfd9888c37b44823bf9e846096e7c32f3824d4545ed50cb89a6cb592a0978be2697b068e1020ae360efe85439c8f0e959a10b28dbbdd1ef85bf11affc397b1a80f1106bf3c837b56725be96184508622211d0f3e6c1e7517792673733424c9b76d40077118027bb00f9433ab36b1671ffb22bf063fff65654ec70ddcc91684793d3bf415f99dbf800ac1146ca03efa9ea17ea4c823a02022fe27a3c019c3d70bb2f792ef62acb0805f40744e99c7821d1a38b2834ca984685de7ef2d954c6d287948d047778b2b77f4f0f64f96aa2b22827509f52d0310d0cdc0fcfcbe9e5e60484ec802b04c0b61300a5afe858ea931bab6e3642ee1ce3b2813225a05a213a47f9a9daf764c3497c84ce6f941f7b566dac172fc87e4aed563b49ce3fdb09144a6a2afccfbed4a9a586552063b05ca9a1a498ed2e5f022ed6026b389d377f301712868b69c96192410585baa96456772b79ee2b0afceb2bdd6dbf97abb2f3c39c34fa965f37738b6dd0632072bda1fbbe99db8f3fc0baa40000ff56bdb19df30a4f91d1f45e16e96c5993076d616f59e1ac712ed5b75112ae999a3c5621387b037d9ca9c0a912cdb57175f131c449b6a3491ed993a760bd7ee9b1104322f0e11bc680b473cff73c042dc5ffc129fde33e8d2d60be25bb12ef0aea7cdaaf84d6a9b0cad6d34438749dc183ef86f83707df0df39b243cd90d627e2c3ca9d3187f945a338709a24330b38adb68e6f69b817f00dacfc726ecf6ed056c01b4139b21a0fbbba77c278117d49a067c4265396acf8fbb14aef4f6f0c97188680e8636471f30aa0204fad8cb97ef4248bb7e4a4b760344a63a57ca9cfafbac066b688fed0bb4f993c961ff82ecf55774675da98d418e178ebaabd8de2b82f333a07f41870cb1dc1271477eb6a6435459e9a5375768902de350eb2ffa3830234e8c38688f7c9fb0bc1477e19d7739d44fb6e0e883eea7a023736295a85029e75e07427dd18afec5fb9ae0ec94d3e514f7cf126076b541696487ff8e623cd4671f91da5df08e988d13dc7e82d2196c939c400f7b573591d3c1abcd2aa2473ab8b434f43789e030323896f063f2322d588a37b1abc81446d0bc97166a6eb70681c7d83cb5cc34f73dae2a0c8652312717b6035eeb3749b56cbba6a0809fafc13bf907a2db631b3b76addff141b89ff265d900000000", .Okay}, + {.Shl, "-c9412402a4a668f2bfca7c4a9cd81707c35170472eb36c216c281f42f891f45d76a2598732199c2c8ed93be9a69c06bdcb506d2b841f9f2e2d2320500533894c5bf75ccf44f57f6000a2f4089ea21969a89e1f6e0b7cb71249eeb5d45396654a4a84a6b66b8560e859ba44c4860a3534c7f87807815dd24a4d9bcee0f56b6a7f491612494c5594b67a70d9edd755a6ae63e4cc4eb3c65a0f9bf35719a745faf52faefb0f03bec1453c1d86acd02fccfc6bc351832a9b0798da973d63f1f4789bb969aa834f9068e96abd05b7f8c91363ffe615dafd936a65de97cac057b18dffe7699fdcb43813be080db0df45f050ab410c95b8a68d73a3bbd58c6acdcbd9878ecda9fa3a41b62ea319c677ad8855f96095f3ca675973c8d0e010b99f99f513ae9fdfd096868d6e91ee87df598a4f5b9e875d357e2f2fdf64de38375970c2803d74c2c1c4d0df64a917502d8c78b8a4cd68cea09e70cfcc10821b661d22c3d3c8c02b4074c59e1bc6393904207a393e5eb970ab484fc2333465307aa7b214a68df6ba629ae129a39e94a8db5aea44286b42b8b4b332065129e00026aebf557b7cd91b18010fc898909e8af8ea1bf94203618a57ff3435241147a83e6a3e09b68f035040bd3e70b94b8dd26e069baa5619584df0d4c310b40ec4c4e2a8837b2e7f48fcb3b2639e854e1e631fc407359d75a5bc7fa4d83c6ecc0db7d9cd7b7ca351eba84936c5a2101814ee429fc50f8b790c40d24ba040c92ca5a3936cc967f05e59c5e88776e76e2c18b677a9e1cc17eadfd54fd5ce1433fc20b081bd0121e4729ca56c965c125588a67231c4bb797ab3979e644446f61f8a1647d4a0e51331108f2598514610ed229b7ed01f564c4db2d9473bf337ce74bb17ca927dba461b83b82ec0c98f7e5c7aa8094f64df8897fe70e48bcd671be7765003dd6c22df57b35578e98fdb879b3bfefc087f4d82b9cff71532e42df606855a4d0036a902643da73cd7088c5d7fa3720a242cc87db4b3a182e5845651983758c1dd9e6212db1ac999e2149132e29c5046626c5903c386cd124a400785f03b71e324f30fea402607e8133b5d443cf13fa5fa294b2049535b02a63aa20e118c9fac96ba79f1b04a35e7fee7dd66af61fc95e0e46d376348101208bd9403b2537f2e54629b88dcaeda9516c0ca394048019d34104c9e46d747d5dc6efd7d1e65e69db30785b7cfc6ee5d0e283baaa0a35ce2a270d330e76e9fcfb519c0dc269cc9f743be24f58dd57c8d64a5c5b35ddef82211348a17fca96c01de8985c2e3e06fbc333680633868c047e35c9fc83f59c2f0e5ea73dfa0056291f6aaceae56778b051216da29e0ceca16532afcc8af03e697e46eecf54b2723f719cf9d216e5ab22ea78fec24478a1a7c8e092e062549f9e82ac619679a96c1dc79fd5883e3795fd6ac6cf78d0ae2321bfbdced9bcf26cbae09a65a61bb4c97a1f41dbb3610d9fcc614a3572db58d02d519900d119ed725e677b11931e4407e20ec71e9c3bf0e272e259e210f4122363d7af8fc04e6ecb900aa46622f8525902f0ae233e46ffd45f05ba223120226e6795aeeb29e6d9a94550fc14ceeea5143bc5eb314b2a9dc52c767dd68709fc6d2cdd2bac23ef1d251524065c3d028ca6731bfad5236fcd0ee28328581266bc6b88eee09b39d22853e98da4a46a1ee948c9d235bf5bdf5bbd2b2adb6665ee2b53f06daf15cebabbc0a9d5da6e5ad3fe3e88155982eac76fb02435dbdca010c3dee5eb729342a433b7d81793db3e9e5c50526f4de32ac222111a85a6b49e5e3fcf8aab54852944153a17887b22a2828d01272e0a7c848ff875f9301fca904854c5afe3671dee6ce537af8cca2f024bd5ff7264416c985788c12a08d10f6ec8a302156d09529b782efb775c406e60a8ef496ebdf335253ec891d884d9989a4ed19ffce6e9d094fdfbebf0e49cdb8f4b72a8b1f244ef1131d6ff48a9aede9b4eeabb6a2fef354b6a8da24b3b5bb7efc707abb826d526bf920ac4452f6bf141427c434bbc6ddf0bd4ecb3d5888c7d5eb7ac467353d8f6e3fc025d0d46924ec870da2bdf560c3f1e2370b0c8385e339a2465a483c86e5c084ac8f4732bc", "26", "-32504900a9299a3caff29f12a73605c1f0d45c11cbacdb085b0a07d0be247d175da89661cc86670b23b64efa69a701af72d41b4ae107e7cb8b48c814014ce25316fdd733d13d5fd80028bd0227a8865a6a2787db82df2dc4927bad7514e5995292a129ad9ae1583a166e913121828d4d31fe1e01e05774929366f3b83d5ada9fd24584925315652d9e9c367b75d569ab98f93313acf19683e6fcd5c669d17ebd4bebbec3c0efb0514f0761ab340bf33f1af0d460caa6c1e636a5cf58fc7d1e26ee5a6aa0d3e41a3a5aaf416dfe3244d8fff98576bf64da9977a5f2b015ec637ff9da67f72d0e04ef82036c37d17c142ad043256e29a35ce8eef5631ab372f661e3b36a7e8e906d8ba8c6719deb62157e58257cf299d65cf23438042e67e67d44eba7f7f425a1a35ba47ba1f7d66293d6e7a1d74d5f8bcbf7d9378e0dd65c30a00f5d30b0713437d92a45d40b631e2e29335a33a8279c33f3042086d98748b0f4f2300ad01d316786f18e4e41081e8e4f97ae5c2ad213f08ccd194c1ea9ec8529a37dae98a6b84a68e7a52a36d6ba910a1ad0ae2d2ccc81944a780009abafd55edf3646c60043f2262427a2be3a86fe5080d86295ffcd0d490451ea0f9a8f826da3c0d4102f4f9c2e52e3749b81a6ea958656137c3530c42d03b13138aa20decb9fd23f2cec98e7a1538798c7f101cd675d696f1fe9360f1bb3036df6735edf28d47aea124db1688406053b90a7f143e2de43103492e810324b2968e4db3259fc1796717a21ddb9db8b062d9dea787305fab7f553f573850cff082c206f4048791ca7295b2597049562299c8c712ede5eace5e7991111bd87e28591f5283944cc4423c9661451843b48a6dfb407d593136cb651cefccdf39d2ec5f2a49f6e9186e0ee0bb03263df971eaa0253d937e225ff9c3922f359c6f9dd9400f75b08b7d5ecd55e3a63f6e1e6ceffbf021fd360ae73fdc54cb90b7d81a15693400daa40990f69cf35c223175fe8dc82890b321f6d2ce860b9611594660dd63077679884b6c6b2667885244cb8a71411989b1640f0e1b344929001e17c0edc78c93cc3fa900981fa04ced7510f3c4fe97e8a52c81254d6c0a98ea883846327eb25ae9e7c6c128d79ffb9f759abd87f2578391b4dd8d20404822f6500ec94dfcb9518a6e2372bb6a545b0328e501200674d04132791b5d1f5771bbf5f479979a76cc1e16df3f1bb97438a0eeaa828d738a89c34cc39dba7f3ed46703709a7327dd0ef893d63755f235929716cd777be08844d2285ff2a5b0077a26170b8f81bef0ccda018ce1a3011f8d727f20fd670bc397a9cf7e80158a47daab3ab959de2c14485b68a7833b28594cabf322bc0f9a5f91bbb3d52c9c8fdc673e7485b96ac8ba9e3fb0911e2869f23824b8189527e7a0ab18659e6a5b0771e7f5620f8de57f5ab1b3de342b88c86fef73b66f3c9b2eb826996986ed325e87d076ecd84367f318528d5cb6d6340b54664034467b5c9799dec464c79101f883b1c7a70efc389cb89678843d0488d8f5ebe3f0139bb2e402a91988be149640bc2b88cf91bff517c16e888c48089b99e56bbaca79b66a51543f0533bba9450ef17acc52caa7714b1d9f75a1c27f1b4b374aeb08fbc749454901970f40a3299cc6feb548dbf343b8a0ca160499af1ae23bb826ce748a14fa6369291a87ba5232748d6fd6f7d6ef4acab6d9997b8ad4fc1b6bc573aeaef02a75769b96b4ff8fa2055660bab1dbec090d76f7280430f7b97adca4d0a90cedf605e4f6cfa79714149bd378cab0888446a169ad27978ff3e2aad5214a51054e85e21ec8a8a0a34049cb829f2123fe1d7e4c07f2a41215316bf8d9c77b9b394debe3328bc092f57fdc99105b2615e2304a823443dbb228c0855b4254a6de0bbeddd7101b982a3bd25baf7ccd494fb224762136662693b467ff39ba74253f7efafc392736e3d2dcaa2c7c913bc44c75bfd22a6bb7a6d3baaeda8bfbcd52daa36892ced6edfbf1c1eaee09b549afe482b1114bdafc50509f10d2ef1b77c2f53b2cf562231f57adeb119cd4f63db8ff00974351a493b21c368af7d5830fc788dc2c320e178ce689196920f21b970212b23d1ccaf0000000000", .Okay}, + {.Shl, "-61c7d6ff8daa88d8ce4ceea29e07e99543b7459af93159992d79696ca3cba33641237e4f027b5e5aff80d3ad5b2a49a204b1b2ddc85450e191b8a2bb3d44e49509548c570e4090b5989282734a3678df7718a01fcbbce7b30573d5f55720bf77a7d96670f8d8353172160db0138125d191826e8c98ead0603aa9238ea4bb14b5159d8e213891a98829a031e96ac237b7732f601f29d8ff69a869a7d1dde238d0bf9aec1e4d4de07125529142f968e3d7ba01109c3b343a1d69e8d1529273526587174723ded79cd25a46de54e01845515e3593c57db763104b3ad2c54705e9b355b08fff0c40fe51b8f515a2a1e71b8ea6c3563fb63ac8501eff2b2ad40df8ee75f6876109a91aa19a4cce776ac148e2fddbf2c3aad23d8d8c5dad8eb08357d50705420d57042960bc3ce7b23718a0abff3d552c61be657229dbefd278cbddc01c54e384a5ca268ca16a8d5e3b5f0a34290c2608f4d058fc4f5143f93a13012442f48878bd90fc47eff77173e1b0f8e26fc07d91fb543c7e5b6a3b81eb80cb99f5183aa8c96be513b212de8e9dd6ce704759404f50ea741f03f92e9a8d51a070d7e4b3c5aae8e41b830ab00074d27d7f8f1a4d90dab3f8ea450084bea408e977718fe30a4c75a98568f00d83cb0026c263f7ebf8acc677add4c0d74e87e7166315b39090d3c0d680c6b0ab416138189dc913ccd8dc23316fba372a2dd85d4c516a321988834ea66123528e2f96e8901aab3be5b3224f4ff3a9e7c5b19fa05de4a61089f0999a7566ec80c17bd74ab7299fb5b40e8f051998e810d057a2ed77406ce3a154db06498ca658429c923a3ec06d426cab09105c54dbcc91f10995d2ced0443ebad6da4989c4ec892437afe145cc0999a2e6ac02a8ab6c3a116adfbf4e3efec010aad259a14fa236827968d3f7dac94ab810f5df8217919b94912ecf45c5352b0d896a30a74c89b5df94c83831d49a8976c23bfd23d2debd37dc904745c5663b20adedfb45971ff42358d4a55b4e665b9ff771869e19f1645bd27bfe421c908f9c3f5a3ff442688db8a934ec33f3b6dd75b1651af9ef9569cac62f6ce21a552215d88779ff92d5b9281dacd9becc7396728a18715c3888c6ef8de45600315faa83360454342fbf27d6bafee1bfba63cf50777be4dcafb75d34c0884cc8a97ebe3ee838e71c6bac688e893a1c188436ce169f6e7f1c4b3b3427566afd563f1a67705f8ef1add88f0a261a8384171e35dd7e65f54bf55e6b8592e1edecc42d443d18abafe046f328cf7f738cf03cce74c2ed9af79ff2596fa951adb29d1f560e6d784e9791582b29825c30b1786cc350a41a316d175941c8ac0e11233bca8a163205c6191b0c25b6299511db0c869f56804322d754f2ba4a2c690562195cb1dc65dee67328bc516a19f6230c034b582bebcadf6d5122d049c1f2a335d0a12b7747d1324aabf915085160f3e636198ecf5465fca45372c6087f4ace70b8f51285e8803f14b8cf9929ca80de5a7d031758dd24287eee7ddc80e868484d1d4c0c2427a145d9c716e9a5343495920a2e78c256cbad5c66a3058adc0cca9e620043cd74ce70200bd60215c5bab75835dec71429186d0fb22cd784f4bf8b927d54509fbce757c643ff743fb90f697c58ccd8da795401d09ce8572a0f3ef5e8d619abc9d032727d418f81ee490e19270aa97a2672591ad63a9e989aed84a9b6f3bed06d5d35e7ea87b4e60fd3bb73cc8a650eaa89ac73681971b35f99fa50090bcf0fc900c77d6576d4214216b6ff5f0bbe7858d70356f60136499c64399ba2352317eba4e47356db4064d00af6a6f9ca302167630d3b75ce5854a67f6bc1aea832ceb2daf3ada5296128cf0413b8784da31273df0ee3a11f33e816b62fd85ae3bcb6f26a6c8408539552e412c86b5fe5ae58f817c0fdac8e8fcf26ba826ad2dc2032bfe868202efa6f97e8651119d38f37de88e9fa8eb9081efc3f4adf1cfb6fc14e68c1c654af483694e5fd73993aad7056ab491aa3f9d1acac97dfe147aaae02f2e77ac8227ca3de6398a525ddd4b06c7f24a0fcf8572f9925598b78bac9e4bec94abb06f11791606d808686a8bba1ce607a435309a5f5b3cf004be1", "1a", "-1871f5bfe36aa23633933ba8a781fa6550edd166be4c56664b5e5a5b28f2e8cd9048df93c09ed796bfe034eb56ca9268812c6cb772151438646e28aecf51392542552315c390242d6624a09cd28d9e37ddc62807f2ef39ecc15cf57d55c82fdde9f6599c3e360d4c5c85836c04e0497464609ba3263ab4180eaa48e3a92ec52d456763884e246a620a680c7a5ab08deddccbd807ca763fda6a1a69f477788e342fe6bb079353781c4954a450be5a38f5ee8044270ecd0e875a7a3454a49cd49961c5d1c8f7b5e7349691b79538061154578d64f15f6dd8c412ceb4b151c17a6cd56c23ffc3103f946e3d4568a879c6e3a9b0d58fed8eb21407bfcacab5037e3b9d7da1d8426a46a86693339ddab05238bf76fcb0eab48f6363176b63ac20d5f541c1508355c10a582f0f39ec8dc6282affcf554b186f995c8a76fbf49e32f770071538e1297289a3285aa3578ed7c28d0a4309823d34163f13d450fe4e84c04910bd221e2f643f11fbfddc5cf86c3e389bf01f647ed50f1f96da8ee07ae032e67d460eaa325af944ec84b7a3a775b39c11d65013d43a9d07c0fe4ba6a354681c35f92cf16aba3906e0c2ac001d349f5fe3c6936436acfe3a9140212fa9023a5ddc63f8c2931d6a615a3c0360f2c009b098fdfafe2b319deb753035d3a1f9c598c56ce42434f035a031ac2ad0584e06277244f3363708cc5bee8dca8b761753145a8c866220d3a99848d4a38be5ba2406aacef96cc893d3fcea79f16c67e817792984227c26669d59bb20305ef5d2adca67ed6d03a3c146663a043415e8bb5dd01b38e85536c19263299610a7248e8fb01b509b2ac244171536f3247c426574b3b4110faeb5b69262713b22490debf85173026668b9ab00aa2adb0e845ab7efd38fbfb0042ab4966853e88da09e5a34fdf6b252ae043d77e085e466e5244bb3d1714d4ac3625a8c29d3226d77e5320e0c7526a25db08eff48f4b7af4df72411d171598ec82b7b7ed165c7fd08d6352956d39996e7fddc61a7867c5916f49eff90872423e70fd68ffd109a236e2a4d3b0cfcedb75d6c5946be7be55a72b18bdb38869548857621de7fe4b56e4a076b366fb31ce59ca2861c570e2231bbe37915800c57eaa0cd81150d0befc9f5aebfb86fee98f3d41ddef9372bedd74d302213322a5faf8fba0e39c71aeb1a23a24e8706210db385a7db9fc712cecd09d59abf558fc699dc17e3bc6b7623c28986a0e105c78d775f997d52fd579ae164b87b7b310b510f462aebf811bcca33dfdce33c0f339d30bb66bde7fc965bea546b6ca747d5839b5e13a5e4560aca60970c2c5e1b30d429068c5b45d650722b038448cef2a2858c81718646c3096d8a654476c321a7d5a010c8b5d53cae928b1a415886572c771977b99cca2f145a867d88c300d2d60afaf2b7db5448b412707ca8cd74284addd1f44c92aafe454214583cf98d8663b3d5197f2914dcb1821fd2b39c2e3d44a17a200fc52e33e64a72a037969f40c5d637490a1fbb9f77203a1a12134753030909e8517671c5ba694d0d2564828b9e3095b2eb5719a8c162b70332a7988010f35d339c0802f58085716eadd60d77b1c50a461b43ec8b35e13d2fe2e49f551427ef39d5f190ffdd0fee43da5f163336369e550074273a15ca83cfbd7a35866af2740c9c9f5063e07b92438649c2aa5e899c9646b58ea7a626bb612a6dbcefb41b574d79faa1ed3983f4eedcf3229943aaa26b1cda065c6cd7e67e940242f3c3f24031df595db5085085adbfd7c2ef9e1635c0d5bd804d9267190e66e88d48c5fae9391cd5b6d0193402bda9be728c0859d8c34edd739615299fdaf06baa0cb3acb6bceb694a584a33c104ee1e1368c49cf7c3b8e847ccfa05ad8bf616b8ef2dbc9a9b210214e554b904b21ad7f96b963e05f03f6b23a3f3c9aea09ab4b7080caffa1a080bbe9be5fa19444674e3cdf7a23a7ea3ae4207bf0fd2b7c73edbf0539a3071952bd20da5397f5ce64eab5c15aad246a8fe746b2b25f7f851eaab80bcb9deb2089f28f798e6294977752c1b1fc9283f3e15cbe6495662de2eb2792fb252aec1bc45e4581b6021a1aa2ee873981e90d4c2697d6cf3c012f84000000", .Okay}, + {.Shr_Signed, "-b8242e74162acd7b99d9b29fc88700f6bac8a192fc811c2ff7d3e4891203dd62c4f9210aa0b927c9a974d49a6ab7e861a03129c9288d83e05dcc47ed500ea1c3d02420d123607dae716410c223bf20cc1aa00d37d21f01db1c2212d91d64dbc4d5c719a1d9e5bfa4bb17762207714b79258d61b0a348ebd602b750eaf731579fed1b4c22732995cae0b93ec0e640445942914ee246564a0895db90f2de930a7220fb372bbc7f6ab11af37aa493960ac0bbaaac16894c4754a4255e91f9256ea409c828c5126573d4b41de1e64f318d6917faca96afd611ffb290fad319ebb16a05ec2159a6745bc9210c14afd6d03828807cf821d0edd1ac68ae789bee2e0a8463210447065e2b2785d762ca09b0284c9e219eec5ee3ec4cf0221e2a8790619641531b95178cf04dc249c067bd0fa9fa372cb1dcd860c274795d0074e38f8c40104b2ca0019b114e60f4f1cb34642d03e539b7cb087e7f11e8618e6e8dc255c34c8f651e9ec7de3fafea5496e0eaa8e4cb252ebed1b1721040f052add4fa95286b16df43494dfaea2628b5159594942a217f5244c0e184274e9300acc4e683a52de01b27311644f1a769555f1179ecca795f0b21a2eae6418bb7c01630a90bf6fffbc99e197a0cf15fa8d03946ebb3e98a7463ce9a31aa4fb914c4d3aa41bb6c96cb2aca09a6cfbaa2226fb375855c0f1c4647dce25ace855555bafde1f749795a651e9f92d130502089823f6ea4f39185e21db419190df342fdae9d2fc38b826cf4a55fb759057708a2a4d49887b4626111a4cac69f4a40823feffafd39df1fe5978a7d013e5c10179714f473584af464ce914aeeb8687ffafedb14cf499bfabbef470657074b3dbc26224c0296b93d1a6be30d5bd0a1f0339c6ded283a6149519050d79fcfb963b35152fcdc1a77e27c7597120d3d81eb1ab2f0f955a181ddb9ffa263a422340bfaa38109405d6c59794070ab7455e01afe9bc2e2c7505ae35e5550e3c2aa074d2e78d046ef7054c3e9bcb500b1862cb9091c9aed61baefebf05737879f91e93b87a6149bd840fe9ee9c70a679820261f25d4d7b121b33b459095fc8a4b6f13d07df00d639adebd6e1af97d92e843e04cd1256fe60b224a9cd970dcdc6899bc71b531d858364bf899def4943e90c651ddec7862ae4fd6862b5925ea185c05d3e625bcaeee44f0a5e9389e1b2794fca8e05c94af0735f5c5beac1f374af759aca228ed35d53928a746727f82c8cc08d01d9b4c4da65eeff732421684eb3c4d5fefb6cd73db99b432ac99ef069e0515e0ccdb3c3d24b94bb38ed1ce289cb3d709040410ffea86c1c59256d80025120299b4ee1460ee6ccdf2adc3d853a3fe92b850a5cbe5c3665e07af8203de016c334ceafaf2ee0b88a67c7369179d7f4e5a313ed9a8528c33e0980e5f3692dbde14ad27258ea9ee462156e9e09c99dbac1a93192777b906c21c485cc288a97a73297c0298894f0147bf2b1c0b94cb0707d311eaa0077052f252e6d711cf213409fb06a1f9ed9940b7fb719b5e14ed9906d3acb613402d26891fce2bd9a58994b489d984f0902f538f38d84557949ceacabab199bdfd8340ca49e6853a5838bb5a7304ea3c75fdcd582eaabcb10561dba2bd6cde8be01ae996bc128fe7a19f3f938ece8f6c1c6f02fe2d0cea0f81f446937c97fb69435990bed2bffab1e094414143ab15a85742d449f2e81d4a8fb29c9526acaed2b64c59948106278dfda37a10c4bc896f686804087a1020f33c5e647d0f7051dfc9cca073481ec040fee8d7857ac9825fe06b7f1de173f7bc72d4cb6d2c6a441080a219d5ffa3644f92812729e93b40f6f6abcbc40e4ffe13b0b2958d4072b277ce2ecacbe86bec44f46ca365465df148cce346f773b06ecf896f272efe10b8d107b0ed3e3be664a05f2ddb94e9b604a02709dc131d573b3b25e66abeae2d4402133fbe84e76caa253b319feae6b68a800fbaeef02aae56f2ebfd646d13663e1e0417a4d243db862a3059db2d318a014156d77869034697a981b7a40522f124fe743b4d64e2fec1c79b1c1e00287c427a9292e5583ff337935d6313daf36e7cc68462b02324f27108cc043b679c70cf438d1cf6", "6e", "-2e090b9d058ab35ee6766ca7f221c03daeb22864bf20470bfdf4f9224480f758b13e4842a82e49f26a5d35269aadfa18680c4a724a2360f8177311fb5403a870f409083448d81f6b9c59043088efc83306a8034df487c076c70884b6475936f13571c66876796fe92ec5dd8881dc52de4963586c28d23af580add43abdcc55e7fb46d3089cca6572b82e4fb03990111650a453b8919592822576e43cb7a4c29c883ecdcaef1fdaac46bcdea924e582b02eeaab05a25311d5290957a47e495ba902720a3144995cf52d07787993cc635a45feb2a5abf5847feca43eb4c67aec5a817b0856699d16f24843052bf5b40e0a201f3e08743b746b1a2b9e26fb8b82a118c84111c1978ac9e175d8b2826c0a13278867bb17b8fb133c08878aa1e418659054c6e545e33c1370927019ef43ea7e8dcb2c773618309d1e57401d38e3e3100412cb280066c453983d3c72cd190b40f94e6df2c21f9fc47a18639ba3709570d323d947a7b1f78febfa9525b83aaa3932c94bafb46c5c84103c14ab753ea54a1ac5b7d0d2537eba898a2d456565250a885fd49130386109d3a4c02b3139a0e94b7806c9cc45913c69da5557c45e7b329e57c2c868bab99062edf0058c2a42fdbffef267865e833c57ea340e51baecfa629d18f3a68c6a93ee453134ea906edb25b2cab28269b3eea8889becdd615703c71191f73896b3a155556ebf787dd25e569947a7e4b44c140822608fdba93ce46178876d0646437cd0bf6ba74bf0e2e09b3d2957edd6415dc228a9352621ed1898446932b1a7d290208ffbfebf4e77c7f965e29f404f970405e5c53d1cd612bd1933a452bbae1a1ffebfb6c533d266feaefbd1c195c1d2cf6f09889300a5ae4f469af8c356f4287c0ce71b7b4a0e985254641435e7f3ee58ecd454bf37069df89f1d65c4834f607ac6acbc3e556860776e7fe898e9088d02fea8e04250175b165e501c2add157806bfa6f0b8b1d416b8d7955438f0aa81d34b9e3411bbdc1530fa6f2d402c618b2e424726bb586ebbfafc15cde1e7e47a4ee1e98526f6103fa7ba71c299e6080987c97535ec486cced164257f2292dbc4f41f7c0358e6b7af5b86be5f64ba10f81334495bf982c892a7365c37371a266f1c6d4c76160d92fe2677bd250fa43194777b1e18ab93f5a18ad6497a86170174f9896f2bbb913c297a4e2786c9e53f2a3817252bc1cd7d716fab07cdd2bdd66b288a3b4d754e4a29d19c9fe0b23302340766d3136997bbfdcc9085a13acf1357fbedb35cf6e66d0cab267bc1a78145783336cf0f492e52ece3b4738a272cf5c24101043ffaa1b0716495b600094480a66d3b85183b9b337cab70f614e8ffa4ae142972f970d99781ebe080f7805b0cd33abebcbb82e2299f1cda45e75fd3968c4fb66a14a30cf8260397cda4b6f7852b49c963aa7b918855ba78272676eb06a4c649ddee41b087121730a22a5e9cca5f00a62253c051efcac702e532c1c1f4c47aa801dc14bc94b9b5c473c84d027ec1a87e7b66502dfedc66d7853b6641b4eb2d84d00b49a247f38af66962652d2276613c240bd4e3ce361155e5273ab2aeac666f7f60d0329279a14e960e2ed69cc13a8f1d7f73560baaaf2c415876e8af5b37a2f806ba65af04a3f9e867cfe4e3b3a3db071bc0bf8b433a83e07d11a4df25feda50d6642fb4affeac7825105050eac56a15d0b5127cba0752a3eca72549ab2bb4ad931665204189e37f68de84312f225bda1a01021e84083ccf17991f43dc1477f273281cd207b0103fba35e15eb26097f81adfc7785cfdef1cb532db4b1a9104202886757fe8d913e4a049ca7a4ed03dbdaaf2f10393ff84ec2ca563501cac9df38bb2b2fa1afb113d1b28d951977c523338d1bddcec1bb3e25bc9cbbf842e3441ec3b4f8ef9992817cb76e53a6d812809c27704c755cecec9799aafab8b510084cfefa139db2a894ecc67fab9ada2a003eebbbc0aab95bcbaff591b44d98f878105e93490f6e18a8c1676cb4c62805055b5de1a40d1a5ea606de90148bc493f9d0ed35938bfb071e6c707800a1f109ea4a4b9560ffccde4d758c4f6bcdb9f31a118ac08c94", .Okay}, + {.Shr_Signed, "-f2399f2999778aa99656b173687c8e522ea6bb26f1e3fa2315b5c8fd147262a080338f03c5b4fcefbf6309f53810f0e268e5ff74e3320eedfb68bfb714a3cfdac17c04e043b4257f9b500e579920290ad71f6fe4cf9c6fed4b4351dbf61326f37f222401ca30bd78297b036c1b71a6b95552299792a290b8bd9172365890fad645274fb30eed9219df7e10a66b63571fa31428280355d51bdd553d9fe148879fc932b894f617dc6d31a393eb47d3b98c0600f55dc93d75d81ed765e67e90abfbcf85894cd31ebfe4f8d1ad7e094a7d363b5123cc10c2ed19d487dfa459ecc32a05219eed1c4ac83ff30b432c9dbd1ecde9f4b2eaa26d8c866d7be76e33a4e3e7268b179f91add9bf07dec59c28d692507a273ad798a19355e78024148ae75e043d92660715bc36c15e3ed74b39e0058722b36167f96e9b6b82112b6f3e737eedd7d29ab51cc4b738b2fefac26049e7f65b1935621d3d4428de81d6d7156d2a10207c3967e0209b229a6359cba9767f6c62337067fd4872e8ecb99ca57e3119a8630ebcdf45526d587bfa474368be45c10dba4428ddead09769405b83e802db209575fd61b4d0ba0c69657e38a1c23de23d64c95b680008db9379a02f99b2b33118ee16e1b0b1a7cad8b4839d2c8bdf3033cef4484ff2d0c4d26bdd01fafc10753d07b4dc233f916f8ad6ad1fbd0693fce047fe85c6638dd1cbc6701dfec8557ebe08f2e346c3a4a97c68af38670535705fdd8ef6b2bb577b48b9e60dd96dd28bd2a43fe1327a879d87513bd289ce5cf3b079637503836647ad18ace00758bd2e0e444b53530180f59a583bea1a938b29acfc3b9a824eee56f1d4e9745acd4246a32a8f7b16bd6a070cbcab65c4f8cb6f89a67be4d793a3d615d849e01e98f9484e77eed54dd1d7ae574ab5713d569faf052a8c21b08b83314990819e538317b9dbb1f05e6e112de71dadda51691637d3486453ae85b061254419cbb858e004ead5ed8b5e90a29c59a5ccee0644417092d4cc7bb2a1a8bb05b13d56a7faa09c2599d33b43b2daedc3ebef25db9e696d4e5294c9db3dbcc093b1b4f8b6a487e8257e7b9ba190d114b08e7b318c9db23395da13f05a715ef92f51cb43f74eb1e0baa241bb156b09b999f28c385a27ac5a86f0e868825ac207f4851f0b4dd99a075a7e715de5ed58e85b621744fa591dd586ade2d9b1716e231cf4c904b53c9a7009020a0833e3ce529dc464e15288d0c02ed40925a99f687406f65f9fb033f3fe74a9b3429ed396949dc756bba8201c7475bf7eb48d9749d4913130dd695bd6453363d0ddc64f20342a116ace9621f95b19ad6b2fc27d580ceea45205b06a0deac739e2db58d1ce6a0f4afb940de70514e816b01e14a537af20df1649de339842f1cb64a2adbfcf28326d58cc110ff718ff53f5c5eaa3237a8fe67083d57c8788958783b801b70c6db2a4490f3aade47be966cf5f4eef4dcd4f75147faada6900731a3519a521e605484fe6ee243a7c0d151704e2029bdf26c0fb58fc76f10e8ee9ece65786b6430c867cbac403bc48cecda1c51630b9d3b73b0cf1255a651174fc44abd462fb908d6c2e9faccffe7144f365f8bc757216155ae848d1dd2a2f0d72a6070b6c6a1ae5ed12d60b3ca88036463f26300e4406498f0de8d9498926d2289b0113ae3faa169ef05de241571dcad379f4c6748ccc38a6a68fb43a12620cf8f532c3e679a468c402fefba0e9e90231c21c0cbb7d9c13f7b5599a68267e75e734c2d33673add6dcd6fba96c072634b763528334fc9b8d2b85c1da387d11076c82b1913db4e16bbc1fbb626fb6cdd3a5fea7b60c520483764e0c8d4dcacefa9d92ffafb618b434d548a220f6af05877a2ee9900814a752fc720aeb33fe7866a75a61403b7f8f48ed4d55ea35de73e45a97ca88f582d0b5a07fe065ff9c70b9c470eeb1ffbd3eb286f9221ddd880520b114810cc88f79b7fd2d2c95bc89a11da66df61136cfa953b72e2c9521dad07740a78f71d99a540ec6f463cec7451f433d646e9ced27186a674eddd830c9afbf22569444d6e1cfe8494cf13520d9a2eb8e2ec41f2091ceba9259bde08a8ccfe2196294489bd217278b18fd6c49", "0", "-f2399f2999778aa99656b173687c8e522ea6bb26f1e3fa2315b5c8fd147262a080338f03c5b4fcefbf6309f53810f0e268e5ff74e3320eedfb68bfb714a3cfdac17c04e043b4257f9b500e579920290ad71f6fe4cf9c6fed4b4351dbf61326f37f222401ca30bd78297b036c1b71a6b95552299792a290b8bd9172365890fad645274fb30eed9219df7e10a66b63571fa31428280355d51bdd553d9fe148879fc932b894f617dc6d31a393eb47d3b98c0600f55dc93d75d81ed765e67e90abfbcf85894cd31ebfe4f8d1ad7e094a7d363b5123cc10c2ed19d487dfa459ecc32a05219eed1c4ac83ff30b432c9dbd1ecde9f4b2eaa26d8c866d7be76e33a4e3e7268b179f91add9bf07dec59c28d692507a273ad798a19355e78024148ae75e043d92660715bc36c15e3ed74b39e0058722b36167f96e9b6b82112b6f3e737eedd7d29ab51cc4b738b2fefac26049e7f65b1935621d3d4428de81d6d7156d2a10207c3967e0209b229a6359cba9767f6c62337067fd4872e8ecb99ca57e3119a8630ebcdf45526d587bfa474368be45c10dba4428ddead09769405b83e802db209575fd61b4d0ba0c69657e38a1c23de23d64c95b680008db9379a02f99b2b33118ee16e1b0b1a7cad8b4839d2c8bdf3033cef4484ff2d0c4d26bdd01fafc10753d07b4dc233f916f8ad6ad1fbd0693fce047fe85c6638dd1cbc6701dfec8557ebe08f2e346c3a4a97c68af38670535705fdd8ef6b2bb577b48b9e60dd96dd28bd2a43fe1327a879d87513bd289ce5cf3b079637503836647ad18ace00758bd2e0e444b53530180f59a583bea1a938b29acfc3b9a824eee56f1d4e9745acd4246a32a8f7b16bd6a070cbcab65c4f8cb6f89a67be4d793a3d615d849e01e98f9484e77eed54dd1d7ae574ab5713d569faf052a8c21b08b83314990819e538317b9dbb1f05e6e112de71dadda51691637d3486453ae85b061254419cbb858e004ead5ed8b5e90a29c59a5ccee0644417092d4cc7bb2a1a8bb05b13d56a7faa09c2599d33b43b2daedc3ebef25db9e696d4e5294c9db3dbcc093b1b4f8b6a487e8257e7b9ba190d114b08e7b318c9db23395da13f05a715ef92f51cb43f74eb1e0baa241bb156b09b999f28c385a27ac5a86f0e868825ac207f4851f0b4dd99a075a7e715de5ed58e85b621744fa591dd586ade2d9b1716e231cf4c904b53c9a7009020a0833e3ce529dc464e15288d0c02ed40925a99f687406f65f9fb033f3fe74a9b3429ed396949dc756bba8201c7475bf7eb48d9749d4913130dd695bd6453363d0ddc64f20342a116ace9621f95b19ad6b2fc27d580ceea45205b06a0deac739e2db58d1ce6a0f4afb940de70514e816b01e14a537af20df1649de339842f1cb64a2adbfcf28326d58cc110ff718ff53f5c5eaa3237a8fe67083d57c8788958783b801b70c6db2a4490f3aade47be966cf5f4eef4dcd4f75147faada6900731a3519a521e605484fe6ee243a7c0d151704e2029bdf26c0fb58fc76f10e8ee9ece65786b6430c867cbac403bc48cecda1c51630b9d3b73b0cf1255a651174fc44abd462fb908d6c2e9faccffe7144f365f8bc757216155ae848d1dd2a2f0d72a6070b6c6a1ae5ed12d60b3ca88036463f26300e4406498f0de8d9498926d2289b0113ae3faa169ef05de241571dcad379f4c6748ccc38a6a68fb43a12620cf8f532c3e679a468c402fefba0e9e90231c21c0cbb7d9c13f7b5599a68267e75e734c2d33673add6dcd6fba96c072634b763528334fc9b8d2b85c1da387d11076c82b1913db4e16bbc1fbb626fb6cdd3a5fea7b60c520483764e0c8d4dcacefa9d92ffafb618b434d548a220f6af05877a2ee9900814a752fc720aeb33fe7866a75a61403b7f8f48ed4d55ea35de73e45a97ca88f582d0b5a07fe065ff9c70b9c470eeb1ffbd3eb286f9221ddd880520b114810cc88f79b7fd2d2c95bc89a11da66df61136cfa953b72e2c9521dad07740a78f71d99a540ec6f463cec7451f433d646e9ced27186a674eddd830c9afbf22569444d6e1cfe8494cf13520d9a2eb8e2ec41f2091ceba9259bde08a8ccfe2196294489bd217278b18fd6c49", .Okay}, + {.Shr_Signed, "-ecbc46227ec9d2a17921ef02ec6530b43d203988fbcea9cec512dc6a007ce10c4a63114a62518e8ad7f050bf10b99168be68a587f67bd88d89ad860e1737ba2b8440b9d7e58c0556bca0f0d85c18fda8d83d1960dbc6e014db640d1e42214d7e9c0e802f94b484c1161dcd9cb1f3556eac82af5f38ab86429131e6f96b3cc86b264f51efa06eb2a29819748c4c2b3512088bfc0063b8e342276d2fbb34bda16250353f9da628978a1fce5cb714c11792843f38d16fc1a76c9cb95692c5f1515c0338c8006aca7b18c0c25f57d1cd1784c56ef491c38a68017d4eb65dded5ab71d18affd2df5d075af68b1195db35b0b239e9cdf1608f7f9acb0313847e0ebbfa7e3020ce78b87de7077f12131080ac37fe0c05abbeb453d273712a98f65b46668cc08c53c41bb563f0bf7f722e08515dcc94187ded634d1eff0bc880863347a95a5da83e7fdba236ae774bf457b826a984ac7b853ea975094b0c62cf197cedbdc177ff217d8a955e97bf1920f069db81895ef2299a87bd0afa576d0df731e71f664c9eaeb62b2e3ee59be142ce08d6483a42344a89804c5cb59640b789f13f09365b10cb1c677984596680b87ef933522092378c789dea3cea5ce08f209a6675c4c8d580ceff2f236bca6454d595627dbcf27f2ed61a0ed72fb37068ac37845867bfd1554fb47501e023de588570a954930d39c04e6244523b539f58036dab644039ceaa4f872d766f1bf392fe1e8b3911f41edd7e365240ad958970053cbe24fe6156ec9d27c33ef02b01272efc57556bb952ead454d98b3eee76749bdc92ddad3a77e32b4229949e3aa5f084b8072c0165f43862f8d0ea3c9d335cbe92642ee62bc33c1b8bcb2e92e64dc5ca5e34cc3696b2501b18a8012a5dfe96b95f09c2ae8c0574b492308d7eaf485893a627d8e763d948c8a0844b00e4eef5f6be0b915ed0826a0481b5edf98a5fcf004ce1762769458a6e7fb40002e6457f33ded4293ca0e302b3ce299c2e806ef1aa1f2b840fa7155045158de7033ca7a59d5f6b985e536a605a1e1ae3b483d1e2171448027a8f06bda90d6e9aff6d926d5a11f845eec34dc17c6f24dd8806fafa91da6188abf30468091212b73e670ef06e01f24fedf1b5cf1b6d8fb47fcf65e3dfbde4b2a7f8fb4ff4ac9a03eb7cb2173ec00cfcd714ad7b4b61b44288036f89c138540e03ac898da7c66eb8b7adb7adef6d7a31d2ccb894f0f7598f5a5bc6409a57d1abe726cd013722e7b608b7bd3e1d769a39ce1ece45340a70497c36eff22194ab907bcf89c0916e24308b796758dc9f3971cdbb34d83c0acd7595a14c1408f901831820d7464a7a30bedc11f1a6aad402cd7dfeda39e564d8d843191e0f6abe26cd901917e96ac6f832c431a88cb22444014f6cb66f34cacd182268deacddf5dad66744d23b7e0af8ce2f8a76285d3a65f23a06e25e41b84322567bc41d0de37aed944c085e5278df8f095bc987b8587003903edc0023bb0fda716abc3efd8ef3692924285970935089757fd82093f389065c24899649bea5043528440b6dd237ced522f1b4c1cb288832cc579b72a2d06bd6eacda5bec1df9219971572965f3741d9f5d54fde6f3b65247ad9de681d06b1a8ff71f4c81e2461309aec4c0eaecbe1d1dbbbfc2882756958e2c570e5370d93fbea38f63629af772ac0925e0df0933e7e966ebac490e720ba01e4d3c27cb03f65af2b6b3b7694a49604f0a6b86b98ef2b669a7f9af19cd0307dc6926581ba768d2c20fd840a142ac5f0f86f77155b2b646e4680ef8fc16cb640e91375e03c27f234133b066cfd0e7d9d3dfa84a558982ef3ea22c41d9a9fa676f0849d27eaa84d4f1d87e7ce1ad8b6dab277c3f025b9eaae8a8245de582ec64e32e02dcedd730558c71a5110ac0357828ecc2fe958411a7df50aa8e69b9da8eced776ce5ee69534c6f31dffc71e00be484e79cbfc4557e1e0ac221aa50f81767959e7d3129369da9b5d2f0c2ef0f12177ee45314cbc7ab760053bab91ee1a4a189da0de491ca131b8a5fa5ab75b2af549bd004ab61312b327d7d3e42f3e6d2b6984b168b7b9a09fb64adb954e5d9e703ab40824f5b58b7fb49c3f74921754e8a3eeb", "15", "-765e23113f64e950bc90f7817632985a1e901cc47de754e762896e35003e7086253188a53128c7456bf8285f885cc8b45f3452c3fb3dec46c4d6c3070b9bdd15c2205cebf2c602ab5e50786c2e0c7ed46c1e8cb06de3700a6db2068f2110a6bf4e074017ca5a42608b0ee6ce58f9aab7564157af9c55c3214898f37cb59e64359327a8f7d03759514c0cba4626159a890445fe0031dc71a113b697dd9a5ed0b1281a9fced3144bc50fe72e5b8a608bc9421f9c68b7e0d3b64e5cab4962f8a8ae019c640035653d8c60612fabe8e68bc262b77a48e1c53400bea75b2eef6ad5b8e8c57fe96fae83ad7b4588caed9ad8591cf4e6f8b047bfcd658189c23f075dfd3f1810673c5c3ef383bf89098840561bff0602d5df5a29e939b8954c7b2da33346604629e20ddab1f85fbfb9170428aee64a0c3ef6b1a68f7f85e4404319a3d4ad2ed41f3fedd11b573ba5fa2bdc1354c2563dc29f54ba84a58631678cbe76dee0bbff90bec54aaf4bdf8c907834edc0c4af7914cd43de857d2bb686fb98f38fb3264f575b15971f72cdf0a167046b241d211a2544c0262e5acb205bc4f89f849b2d88658e33bcc22cb3405c3f7c99a910491bc63c4ef51e752e7047904d333ae2646ac0677f9791b5e5322a6acab13ede793f976b0d076b97d9b834561bc22c33dfe8aaa7da3a80f011ef2c42b854aa49869ce0273122291da9cfac01b6d5b2201ce75527c396bb378df9c97f0f459c88fa0f6ebf1b292056cac4b8029e5f127f30ab764e93e19f78158093977e2baab5dca9756a2a6cc59f773b3a4dee496ed69d3bf195a114ca4f1d52f8425c039600b2fa1c317c68751e4e99ae5f4932177315e19e0dc5e597497326e2e52f1a661b4b59280d8c5400952eff4b5caf84e1574602ba5a491846bf57a42c49d313ec73b1eca4645042258072777afb5f05c8af6841350240daf6fcc52fe7802670bb13b4a2c5373fda00017322bf99ef6a149e50718159e714ce17403778d50f95c207d38aa8228ac6f3819e53d2ceafb5cc2f29b5302d0f0d71da41e8f10b8a24013d47835ed486b74d7fb6c936ad08fc22f761a6e0be37926ec4037d7d48ed30c455f982340489095b9f3387783700f927f6f8dae78db6c7da3fe7b2f1efdef25953fc7da7fa564d01f5be590b9f60067e6b8a56bda5b0da214401b7c4e09c2a0701d644c6d3e3375c5bd6dbd6f7b6bd18e9665c4a787bacc7ad2de3204d2be8d5f39366809b9173db045bde9f0ebb4d1ce70f67229a053824be1b77f910ca55c83de7c4e048b7121845bcb3ac6e4f9cb8e6dd9a6c1e0566bacad0a60a047c80c18c106ba3253d185f6e08f8d3556a0166beff6d1cf2b26c6c218c8f07b55f1366c80c8bf4b5637c196218d44659122200a7b65b379a65668c11346f566efaed6b33a2691dbf057c6717c53b142e9d32f91d03712f20dc21912b3de20e86f1bd76ca26042f293c6fc784ade4c3dc2c3801c81f6e0011dd87ed38b55e1f7ec779b49492142cb849a844babfec1049f9c4832e1244cb24df52821a942205b6e91be76a9178da60e5944419662bcdb9516835eb7566d2df60efc90ccb8ab94b2f9ba0ecfaeaa7ef379db2923d6cef340e8358d47fb8fa640f1230984d7626075765f0e8edddfe14413ab4ac7162b8729b86c9fdf51c7b1b14d7bb9560492f06f8499f3f4b375d624873905d00f269e13e581fb2d795b59dbb4a524b0278535c35cc7795b34d3fcd78ce68183ee34932c0dd3b4696107ec2050a1562f87c37bb8aad95b237234077c7e0b65b207489baf01e13f91a099d83367e873ece9efd4252ac4c1779f511620ecd4fd33b78424e93f55426a78ec3f3e70d6c5b6d593be1f812dcf557454122ef2c176327197016e76eb982ac638d28885601abc1476617f4ac208d3efa8554734dced47676bbb672f734a9a63798effe38f005f24273ce5fe22abf0f056110d5287c0bb3cacf3e98949b4ed4dae978617787890bbf72298a65e3d5bb0029dd5c8f70d250c4ed06f248e5098dc52fd2d5bad957aa4de80255b09895993ebe9f2179f3695b4c258b45bdcd04fdb256dcaa72ecf381d5a04127adac5bfda4e1fba490baa75", .Okay}, + {.Shr_Signed, "3694d83615a1e5d33f3fb871033b5362e49e5183ba8a352c7260f31639427c8f5ab424befe4fea2b22b3bbe09c9baa3773c45eae13dbc59cbb77377b27bd517f3bea4bfc95a51f59c12d92c0a9d3439d6322ba7cd8f7fea5dde1d1440917a1f6bf2681135a4e867dcb1050efeb8958702f08e48eccd34a5681f0da112702063f47064b77055e8921f9e324170a7ad2e82ce7fbe351ad6347316dad04fff82f3f47b15a96b6869c2281577d17a3ac1c5ea1a9be0736a7989ba3cdb88fa6d133df6d8596e2ff2ed7c1d117f1d237a43a96e0c9091b37a1767d9cbab46c3f263727ded6bebd6b89529c9b39be3a83244fc8cb55c900123718a8112d9d153164c633fec05466f14bf776f51f2d240036ed3c2fb1e05be2ce15672580464f4e0ff4f651db71d90150ca876c4f140cb5309516d290d27b39da68b14aba51b5c3ff79803a893082e2911992afcc8d27b87bff1dfe382f28066a8013f2f2b2c487ce4e26020465bc7ea111fc5d7545dbf90f6cf88321ab8a906ad8443ac4da9a14aa77c65bb1d6bb24bfa7e4a5202d7d93ffa97a484b4ad236a4c5b892f93c97bf5a01424f6264db1cb86e5071d52cea829574839882895cf4b61455aedb8a035994f0e5f358d164d641abb8823b771005bedc431c8109c6dd79fa911beca65ebc4f46eb6acb3aab432f2766bff92acd8128c761012e73ad394ce13b014b369cc07861b8bd6e1ca080857c3c5fd2bb12ab67373e707134ce75e7ebf74f0cf6dc06fed95bd5ca0374f1dbfea1f9f2abef1203e8c6a0164d476bd7e6409b5a29e90b664cd5a1d9c4825ce334944f672b2847aea1b9195f88cf11d96831c8cdf700bb5fdbb57b3750b7fcb8b47ca5c8cfd8e85f0cd61963f1acf17df843e83bd998fba50536ad61dbcff78fc9b8374ddec57e243e2d0033688b21dd3ab55516714ebf4738a6bfee448f4c3288efd00209003b300ed6542eb229a6c48c8c94657dfccfa7ed83e33c1ce3e4f1cf93ac7db08cc821494191471542f570454f8fe4907142a350a8368535f37501a84b6ab922ff4984b923a39436f7745c7c37756f9de0471bd2dae5eaeb8b60c7131b41bd4172a01ecbde96196ca22064f0cb85d347af5c084b58bd23b4257372d9efc76b4e98e36d2174b8e35cccec0e5bc5c0bfc7fcd6f36d321f26a379922d7ba12564bb66be153897140486e01ac2c2b6e39b96319a4913c02828a5a4329f85b0c70d351cba0c89021ec9aeb2e6e0991888a425970da8bfd925949be9177bcfbcae4e65f2633780a1fde3740812c60862cc61e59bb688994624dfd066a60fec511631ca9938d4cb6427f561fcc3da3fefd47b9a81d4e5685c801e9466e4acbefba93977d8802aebd4d2ccc5fb1dd81713d98712be5500d646cafc18b1c859a8f14f221dc207543e93e65d9875ac590d45281c1e067bb4eb122eaa419190ca77e3c895e08fe065c2780bc7ff07ea814ecfb714d0121b8c1d54a1cb036d376f6ab698105f5e5fb617423a3ec569f3056a7e5b880d4660b90856e37812299501e77069716f29fe0e59d7b35abcbaa4fb9084afe2f99723339f3a2b26398fbb4a5bca46732bd73f171e8b8d831029f0c047d50ae1c443d59e510fb8963226a727df965eaf15b78985f2de641f0b0ba1e690f2fdc1e7a68005af10daa9fdb685ec7713cea42d1ba5571f8977947f320559e4c4ad67528323b8e3b211bd0c574d3eadf62a9e4e501339bfcb07376d8e7aba2b93c8c7b1baba679ee585c4160f3bb71b5b951684883332632ebd462f14516b10c33a836a46d9b7ef82ffb8c8bf996840bf3b75fd402c6c56286b1205bd7a2e6d3cbc36cd8d15ce1ccb749cbf6b66fd23508fc6738a2681ce581a75fb249a03b82f6d31baca27ae4ffcaf6cf12eb6da169d2ddefbb5bb6e3ac9f53d2aa26b629b40568b48ce2981023ef300108beee2e6d0749d04ef3d98910ff1e42c7b81066f166d066f12809980777c6365bf356939007b498cc6d0090e784d9186579657e3fc8d225ce6bd419aee262e06dafbe31087897ce92c35f7e46c1e59e44174ef48888a09e04b297e1835cd3a6191a816a5745e67fa95d871d19aa57399ca00d4502effa789a8", "6a", "da5360d85687974cfcfee1c40ced4d8b9279460eea28d4b1c983cc58e509f23d6ad092fbf93fa8ac8aceef82726ea8ddcf117ab84f6f1672eddcddec9ef545fcefa92ff256947d6704b64b02a74d0e758c8ae9f363dffa9777874510245e87dafc9a044d693a19f72c4143bfae2561c0bc23923b334d295a07c368449c0818fd1c192ddc157a2487e78c905c29eb4ba0b39fef8d46b58d1cc5b6b413ffe0bcfd1ec56a5ada1a708a055df45e8eb0717a86a6f81cda9e626e8f36e23e9b44cf7db6165b8bfcbb5f07445fc748de90ea5b8324246cde85d9f672ead1b0fc98dc9f7b5afaf5ae254a726ce6f8ea0c913f232d57240048dc62a044b67454c59318cffb01519bc52fdddbd47cb49000dbb4f0bec7816f8b38559c9601193d383fd3d9476dc76405432a1db13c5032d4c2545b4a4349ece769a2c52ae946d70ffde600ea24c20b8a44664abf32349ee1effc77f8e0bca019aa004fcbcacb121f393898081196f1fa8447f175d5176fe43db3e20c86ae2a41ab6110eb136a6852a9df196ec75aec92fe9f929480b5f64ffea5e9212d2b48da9316e24be4f25efd6805093d89936c72e1b941c754b3aa0a55d20e620a2573d2d85156bb6e280d6653c397cd6345935906aee208eddc4016fb710c7204271b75e7ea446fb2997af13d1badab2ceaad0cbc9d9affe4ab3604a31d8404b9ceb4e53384ec052cda7301e186e2f5b872820215f0f17f4aec4aad9cdcf9c1c4d339d79fafdd3c33db701bfb656f57280dd3c76ffa87e7caafbc480fa31a8059351daf5f99026d68a7a42d99335687671209738cd2513d9caca11eba86e4657e233c4765a0c72337dc02ed7f6ed5ecdd42dff2e2d1f297233f63a17c3358658fc6b3c5f7e10fa0ef6663ee9414dab5876f3fde3f26e0dd377b15f890f8b400cda22c8774ead55459c53afd1ce29affb9123d30ca23bf40082400ecc03b5950bac8a69b1232325195f7f33e9fb60f8cf0738f93c73e4eb1f6c23320852506451c550bd5c1153e3f9241c50a8d42a0da14d7cdd406a12daae48bfd2612e48e8e50dbddd171f0ddd5be77811c6f4b6b97abae2d831c4c6d06f505ca807b2f7a5865b2888193c32e174d1ebd70212d62f48ed095cdcb67bf1dad3a638db485d2e38d7333b0396f1702ff1ff35bcdb4c87c9a8de648b5ee849592ed9af854e25c50121b806b0b0adb8e6e58c669244f00a0a29690ca7e16c31c34d472e83224087b26bacb9b8264622290965c36a2ff6496526fa45def3ef2b93997c98cde0287f78dd0204b18218b3187966eda226518937f419a983fb14458c72a64e3532d909fd587f30f68ffbf51ee6a075395a172007a519b92b2fbeea4e5df6200abaf534b3317ec77605c4f661c4af95403591b2bf062c72166a3c53c8877081d50fa4f997661d6b1643514a0707819eed3ac48baa906464329df8f2257823f819709e02f1ffc1faa053b3edc5340486e307552872c0db4ddbdaada60417d797ed85d08e8fb15a7cc15a9f96e20351982e4215b8de048a654079dc1a5c5bca7f839675ecd6af2ea93ee4212bf8be65c8cce7ce8ac98e63eed296f2919ccaf5cfc5c7a2e360c40a7c3011f542b87110f5679443ee258c89a9c9f7e597abc56de2617cb79907c2c2e879a43cbf7079e9a0016bc436aa7f6da17b1dc4f3a90b46e955c7e25de51fcc815679312b59d4a0c8ee38ec846f4315d34fab7d8aa7939404ce6ff2c1cddb639eae8ae4f231ec6eae99e7b961710583ceedc6d6e545a1220ccc98cbaf518bc5145ac430cea0da91b66dfbe0bfee322fe65a102fcedd7f500b1b158a1ac4816f5e8b9b4f2f0db36345738732dd272fdad9bf48d423f19ce289a07396069d7ec92680ee0bdb4c6eb289eb93ff2bdb3c4badb685a74b77beed6edb8eb27d4f4aa89ad8a6d015a2d2338a60408fbcc00422fbb8b9b41d27413bcf662443fc790b1ee0419bc59b419bc4a026601ddf18d96fcd5a4e401ed26331b402439e13646195e595f8ff23489739af5066bb898b81b6bef8c421e25f3a4b0d7df91b079679105d3bd22222827812ca5f860d734e98646a05a95d1799fea5761c74", .Okay}, + {.Shr_Signed, "82804cbf3b788db760fa58b0ad6493e32d797f96511ebd9abfe5a0c79e3fe1235b112e49a0d7766555d392aae3fea814053badb9144a81c333aa5689098d8b0a1e4bcfb05fdc0961e3cdfa64d70908d0f60540fd8f58630808728a1c2b295ddd5fa2e9212d2f12465a83c55cd9f207b1622783519f8db565d86ba6e0d8a9029fab35c64c6302e0e3bad5041e1093826feb2a88f8a00e03f6450910f81c30aec912e2f7c5c04536c0eb552aab07b44e2c43191baea89f91026ad42575bbab257336350bc5d4a8dd430f6b9003339c67d5e737147aaa1262a0ef07e8172db21f96d5cb2fe592112f753640a40e57b23606a753eabe5bb414b9812dd649cf918476489cb077d86b386a36e9339cde118aff0d496614394e4423d6b7752a7a04facda6060f589dedfe34ffb288dfd75f561be429fcb74870707721d913c6bf1ae958197d2bb97afd734185092856e49560662ecc3a86292160e7a07b7151f1e6fbd81da4987e8d70671d6b0c355a1982d2161bcf153ad19558e0a1f73b714e2f293ec7878c1a9a47307ec9491e6dc51b4193d68a1afad17a9d9600fd7f9adad6d9162d8c95a42c506eab1b53a23a50ec96a0ae90e189b0b3308b68b4ddc5374a3afa52531d86e05a0831055a1cdee2f0d277aa09c0c6b7144d11a7c312fe447188a3154c60b9a32125113c964ea379a53c420d9175acca4e68aa8c4ddc58abda4ce1b14a734093a9488783b30c165c23498cd40113b2a3e024efb9787a34d9a601bc855a4f2d14dbd4ede991d061169a7f1d976083edea5ec8078df8f467e6b633281929253ceaedb66ea8bdd363323ee0e4d1df1806a106dc29396e8a4e51e249f8a828860ad43704cb62bfb987034884fd6b02ae4c98612b79ece04f902a0181e24167634486faa51860de031a948bddddceeb6383b8cf00634caee1e298004a1589ddf69de710839c15ba0afc91b8fdcbc7ba3d2ec987171b4acf9715c1f2d7c752ec4af0897bf9ce34b794ab3c5180f1af0b35b52b4436b3342940f66bcaaf765a28141f36ba69ab46f56aabb2630da19d43f01f1ae6c69960ffb66718330a5a7b7e85b9f3cf060f05444c9df1bcff95d1543bb2db089ba60737b322f0fd4a605c076dbae3c21cb71934dab5061b145ea59d6ccf19bab28b54037c9952fc9bef4a922f4fdddee818243f97c6c2b543fa47293561a6ea84081f86d426c9b0b40b5a4e8cc885f4493165a1e7804d97ea60b3aa53a606927741be9bbe1695b7f535969e58d2601b9164007b7ef358469a8ca10366f283ce9b4ad79db48725162d5d774f3dae2264ee576bb2225c9e126f0edb8d716dfc199e42e4fe9eea401673dca57371c67e7ccc47d9da4453e370bdebcce5042e7d3041109a19b0934d7a98172580ab09197c20442ead13a66babb794c9219fe40be81fc2744f8e8db1fea274953a3d44181fd1483db0d975da253d9fe7712147a6b7b4a758b5192a59280e68b7ce3e617c95589b29f79cd02e665f4493102878d711c66026a22d66a83788f3a5558369313157536805492e42c2100b191842f89986e3a98746eaa27d94dbcd4e1d4d0cdcb2ae5e4032452a157795f100aaaa696398ce1f5b7d62ff10c504e5c6abb766e45ed92e8166d46af961c17755264edfc6f1435e3ae58382dbac3158b980e6490b6bdec334aa18cf1471b131ab765a416ab935d7398a3d9b99ffc7581549584d22ecbfcb2a14d4e4c73e4bb28751cc561811df86a6b38151f84fe77571e6f0bf0528800519e761551d3d1ef8bae6c255cf43529d5bf6c3b4b287ac35e9500ad6758a00e1b083c90c6b8fb63a2c106c63e41b5ce576ffe7a048492a99d568dbdeeff517bd4de4c25de729aca062b357d50002c3406cf06869059ee132d8557aabadc0da3335ffc7628f5e67b5ee865afd4347558450dd707b5686363884e62c92899f535e5507dd21af3b10b3c3603b0696788292be2714c4017390c635631fbb262cdd92acdfbff59944df0468f86d8f2fe7acba8d0416f73803292098c3b0d217625997a118450c6879ada7de347682fc61597e4e01a659499d59b00c82daac58d705fd335d2bf6446c1332a460c757a3c34b7a0ff9817b", "6c", "82804cbf3b788db760fa58b0ad6493e32d797f96511ebd9abfe5a0c79e3fe1235b112e49a0d7766555d392aae3fea814053badb9144a81c333aa5689098d8b0a1e4bcfb05fdc0961e3cdfa64d70908d0f60540fd8f58630808728a1c2b295ddd5fa2e9212d2f12465a83c55cd9f207b1622783519f8db565d86ba6e0d8a9029fab35c64c6302e0e3bad5041e1093826feb2a88f8a00e03f6450910f81c30aec912e2f7c5c04536c0eb552aab07b44e2c43191baea89f91026ad42575bbab257336350bc5d4a8dd430f6b9003339c67d5e737147aaa1262a0ef07e8172db21f96d5cb2fe592112f753640a40e57b23606a753eabe5bb414b9812dd649cf918476489cb077d86b386a36e9339cde118aff0d496614394e4423d6b7752a7a04facda6060f589dedfe34ffb288dfd75f561be429fcb74870707721d913c6bf1ae958197d2bb97afd734185092856e49560662ecc3a86292160e7a07b7151f1e6fbd81da4987e8d70671d6b0c355a1982d2161bcf153ad19558e0a1f73b714e2f293ec7878c1a9a47307ec9491e6dc51b4193d68a1afad17a9d9600fd7f9adad6d9162d8c95a42c506eab1b53a23a50ec96a0ae90e189b0b3308b68b4ddc5374a3afa52531d86e05a0831055a1cdee2f0d277aa09c0c6b7144d11a7c312fe447188a3154c60b9a32125113c964ea379a53c420d9175acca4e68aa8c4ddc58abda4ce1b14a734093a9488783b30c165c23498cd40113b2a3e024efb9787a34d9a601bc855a4f2d14dbd4ede991d061169a7f1d976083edea5ec8078df8f467e6b633281929253ceaedb66ea8bdd363323ee0e4d1df1806a106dc29396e8a4e51e249f8a828860ad43704cb62bfb987034884fd6b02ae4c98612b79ece04f902a0181e24167634486faa51860de031a948bddddceeb6383b8cf00634caee1e298004a1589ddf69de710839c15ba0afc91b8fdcbc7ba3d2ec987171b4acf9715c1f2d7c752ec4af0897bf9ce34b794ab3c5180f1af0b35b52b4436b3342940f66bcaaf765a28141f36ba69ab46f56aabb2630da19d43f01f1ae6c69960ffb66718330a5a7b7e85b9f3cf060f05444c9df1bcff95d1543bb2db089ba60737b322f0fd4a605c076dbae3c21cb71934dab5061b145ea59d6ccf19bab28b54037c9952fc9bef4a922f4fdddee818243f97c6c2b543fa47293561a6ea84081f86d426c9b0b40b5a4e8cc885f4493165a1e7804d97ea60b3aa53a606927741be9bbe1695b7f535969e58d2601b9164007b7ef358469a8ca10366f283ce9b4ad79db48725162d5d774f3dae2264ee576bb2225c9e126f0edb8d716dfc199e42e4fe9eea401673dca57371c67e7ccc47d9da4453e370bdebcce5042e7d3041109a19b0934d7a98172580ab09197c20442ead13a66babb794c9219fe40be81fc2744f8e8db1fea274953a3d44181fd1483db0d975da253d9fe7712147a6b7b4a758b5192a59280e68b7ce3e617c95589b29f79cd02e665f4493102878d711c66026a22d66a83788f3a5558369313157536805492e42c2100b191842f89986e3a98746eaa27d94dbcd4e1d4d0cdcb2ae5e4032452a157795f100aaaa696398ce1f5b7d62ff10c504e5c6abb766e45ed92e8166d46af961c17755264edfc6f1435e3ae58382dbac3158b980e6490b6bdec334aa18cf1471b131ab765a416ab935d7398a3d9b99ffc7581549584d22ecbfcb2a14d4e4c73e4bb28751cc561811df86a6b38151f84fe77571e6f0bf0528800519e761551d3d1ef8bae6c255cf43529d5bf6c3b4b287ac35e9500ad6758a00e1b083c90c6b8fb63a2c106c63e41b5ce576ffe7a048492a99d568dbdeeff517bd4de4c25de729aca062b357d50002c3406cf06869059ee132d8557aabadc0da3335ffc7628f5e67b5ee865afd4347558450dd707b5686363884e62c92899f535e5507dd21af3b10b3c3603b0696788292be2714c4017390c635631fbb262cdd92acdfbff59944df0468f86d8f2fe7acba8d0416f73803292098c3b0d217625997a118450c6879ada7de347682fc61597e4e01a659499d59b00c82daac58d705fd335d2bf6446c1", .Okay}, + {.Shr_Signed, "-ad9f5fa0460cbd66d6eecc3653feeba6da1ad1f35be98ff0645e427931e2c9f57cd5d9088f554ee5ad08426152ced448553a7a46fc54c24c91a31724adf3c0401b2bc226ea9288632a803eade08640876adcd16119f2a31d3dc4c30b2053994b6cd5c3331389888bba413ba28c37d552dcafdc5cc8b5a8cd1582de02e5f3f786782caefc09d89e0771c30d4905c3b43a85fa5ad292fa2385ffccd96e07fcd435bcbdee096a4157cdf87a64a8d046b62ca9ba454382d77c19ee5c95caa9481e7aab2ed4f9964bae38f860cae4b00d928dd16942490cd41dcb4ac23e143f77a853dab488bde47fcd4bb43ffb0f79f0c85bb5941318d9cbda55210017e7c5eb9535e164bd6f79a789eccb2f12b253eb44f9b231619909b7243a8989690611cdc78622b5be390c09f7bb3284035d55fb5b81b99b11ea4aa9605f5dca7d1fc5ca87f4153649377f5f7e01bb6a8ff93172e7240a9dcfce338b6d62e3adc80159ba50fafdf18fbdab3539b01a3ba23a2ca978b02edd14809ecfc117fb342b6d2de19e07d0cf6683bc43a7d0ee1538fca6b4dee49e8f1e73c77de130cb64c6accacd259c839477659d893da1bb293c073a770a48c14fa762253705809853ee777c7bf5a35bcd2fff8009868e63cd011781fae1aa82306bd189be07d0fe67526f45ee6d77516d5fafe20fb40c13ecb5d7b38f7d2ae6910c1727f2698e4a86ac9947b986dbaee7814cb23700605986278e229160e213c6aea91db068f2c1a9f6a1f9f34ceb6679c68571a9ba5984c5b0f1034355533e12a79fa30fb2ea7ac127759b84f9c859d7e7e0e626419a04c3d4741d574668509332cb19096c816785e75f7ccee0653e0e5814820fd4be32717d2ee0e1db7bcd609515b42151dce1332182ba68a497c5ca7257aa44aef681b36ca40d9089768a62d2ed27578f61ec96e15c2d7807c7c0fcd4031cc97aab3e79b1248265b366ce85049d854a10fd1de08b0a7ca6842d18bfcccf15e19c00e39540dfb2b4206a14c5af7ae3aa812aef11eaafa224c306959b9b0d538db843ee69eaad9c55e083db70d5cfb4472cd8c098107b164fcec54d12eaa25592c8398f8006602491acd56c15cf22f59b2921832a5ff379d99401a16c54edc41c639690dd17c5fd87f184849308f28aa35e2dd120bc9a550f9a6a94c5d7eba113be46f3d07464f0db78dd09b144eaefbf6d7169e03febdd00c76feb4b59f05ab77c5a9785a3bc362a87afb82dc5f7aeeecd35b1651fcb5d50da59c3cc66eac3998d977129415a4a71298c19471a9ec1582046ec977c11bad874a622ad223b9c1d193d15130aac3d95ab8cfdcad239a45433c98002b7b64331e5c8c0e8968a21a93396580259d263a88570aaa459412ae90a3463e8ec24bde3569f5ea1b4b816b7c793f82073f0febbd6d61438e182ddf573b97232fea6bc82822af45109d87f0c2311ec786ca2a3558977c32830ab80732107dc8cab7d77a6da0f0e7544ff31e341ff1be45c966292242b48510d493cb121608130ee97c27540c4d6e0acf93b652b01d3321a305394bffb2ea2f244b2140e2365ef187a2b761e2106af354f9ec0b4b9bb41080c416ba540a9cd15858a4d1cbe50d9e517c3abbea8e6ec3addbe755fd62fd1ce204785c93a6aedfd903ed9428c379888283d1abe41fc1cf2e70ad6f76aaac74400b9bdbd2c37187ef2cde61d5d4328968ef774e1e08484aeae654bdda234c65d6c1e8ce5ed4fc34182f32e0cc160f331d6b3596e295efbe8530c1c754aa6410af70b7dfc850cb98dd545d4f9350e3bf54b21f6d5fd7cec4216a43c001cec51115a7e663e7fa14130f69e5ec484f6fa482d7771d64fb3524620a7a40e8dbe92d2cd8b7b7e79693938fe109bfb6b8c1b48ef3731dc587a6b893998303bf142b04a02cf4cf415529e40da43b69e9c2af60a4df270eb36e432f2cd09bf35e48b6f0aa98a19083a0527c4a5e06b0cbcd2a943eeb0ff575cb313d2465118cb1eebd28b499c5f904f0d5798fffde775bcc29ff6e562504ec3644d661ff4674b46bf53ead8ef901a32de8653ae69611ba9d91dd0034eb5a9efafddac5a92141fc10e0dc5ddc7587b112e6ebe1acc3f3d8628b60487", "47", "-15b3ebf408c197acdaddd986ca7fdd74db435a3e6b7d31fe0c8bc84f263c593eaf9abb2111eaa9dcb5a1084c2a59da890aa74f48df8a9849923462e495be780803657844dd52510c655007d5bc10c810ed5b9a2c233e5463a7b89861640a73296d9ab86662713111774827745186faaa5b95fb8b9916b519a2b05bc05cbe7ef0cf0595df813b13c0ee3861a920b8768750bf4b5a525f4470bff99b2dc0ff9a86b797bdc12d482af9bf0f4c951a08d6c5953748a8705aef833dcb92b9552903cf5565da9f32c975c71f0c195c9601b251ba2d2849219a83b9695847c287eef50a7b569117bc8ff9a97687ff61ef3e190b76b282631b397b4aa42002fcf8bd72a6bc2c97adef34f13d9965e2564a7d689f36462c332136e48751312d20c239b8f0c456b7c721813ef76650806baabf6b703733623d49552c0bebb94fa3f8b950fe82a6c926efebefc0376d51ff262e5ce48153b9f9c6716dac5c75b9002b374a1f5fbe31f7b566a7360347744745952f1605dba29013d9f822ff66856da5bc33c0fa19ecd0778874fa1dc2a71f94d69bdc93d1e3ce78efbc26196c98d59959a4b390728eecb3b127b437652780e74ee1491829f4ec44a6e0b0130a7dceef8f7eb46b79a5fff00130d1cc79a022f03f5c3550460d7a3137c0fa1fccea4de8bdcdaeea2dabf5fc41f681827d96baf671efa55cd22182e4fe4d31c950d59328f730db75dcf0299646e00c0b30c4f1c4522c1c4278d5d523b60d1e58353ed43f3e699d6ccf38d0ae35374b3098b61e20686aaa67c254f3f461f65d4f5824eeb3709f390b3afcfc1cc4c83340987a8e83aae8cd0a12665963212d902cf0bcebef99dc0ca7c1cb029041fa97c64e2fa5dc1c3b6f79ac12a2b6842a3b9c266430574d1492f8b94e4af54895ded0366d9481b2112ed14c5a5da4eaf1ec3d92dc2b85af00f8f81f9a8063992f5567cf3624904cb66cd9d0a093b0a9421fa3bc11614f94d085a317f999e2bc33801c72a81bf656840d4298b5ef5c7550255de23d55f4449860d2b37361aa71b7087dcd3d55b38abc107b6e1ab9f688e59b1813020f62c9f9d8a9a25d544ab2590731f000cc0492359aad82b9e45eb3652430654bfe6f3b3280342d8a9db8838c72d21ba2f8bfb0fe309092611e51546bc5ba2417934aa1f34d5298bafd742277c8de7a0e8c9e1b6f1ba136289d5df7edae2d3c07fd7ba018edfd696b3e0b56ef8b52f0b47786c550f5f705b8bef5ddd9a6b62ca3f96baa1b4b38798cdd587331b2ee25282b494e25318328e353d82b0408dd92ef82375b0e94c455a4477383a327a2a2615587b2b5719fb95a47348a8679300056f6c8663cb9181d12d144352672cb004b3a4c7510ae15548b28255d21468c7d1d8497bc6ad3ebd4369702d6f8f27f040e7e1fd77adac2871c305bbeae772e465fd4d79050455e8a213b0fe184623d8f0d94546ab12ef8650615700e6420fb91956faef4db41e1cea89fe63c683fe37c8b92cc524485690a21a92796242c10261dd2f84ea8189adc159f276ca5603a6643460a7297ff65d45e48964281c46cbde30f456ec3c420d5e6a9f3d8169737682101882d74a81539a2b0b149a397ca1b3ca2f87577d51cdd875bb7ceabfac5fa39c408f0b9274d5dbfb207db285186f3110507a357c83f839e5ce15adeed5558e8801737b7a586e30fde59bcc3aba86512d1deee9c3c109095d5cca97bb44698cbad83d19cbda9f868305e65c1982c1e663ad66b2dc52bdf7d0a61838ea954c8215ee16fbf90a19731baa8ba9f26a1c77ea9643edabfaf9d8842d48780039d8a222b4fccc7cff428261ed3cbd8909edf4905aeee3ac9f66a48c414f481d1b7d25a59b16f6fcf2d27271fc2137f6d7183691de6e63b8b0f4d71273306077e2856094059e99e82aa53c81b4876d3d3855ec149be4e1d66dc865e59a137e6bc916de1553143210740a4f894bc0d61979a55287dd61feaeb96627a48ca231963dd7a5169338bf209e1aaf31fffbceeb79853fedcac4a09d86c89acc3fe8ce968d7ea7d5b1df203465bd0ca75cd2c23753b23ba0069d6b53df5fbb58b524283f821c1b8bbb8eb0f6225cdd7d", .Okay}, + {.Shr_Signed, "-bc1f522327896aaf5113bd9d08349c6a563d8ea6afc05be52ea59a77cddbdb390f34923ca3d92235a5aadbafcd75db160d36be0403b17f5c4bf83235f2f3124fddeb1308403dee0cb7b942f2b561fc281391e751e5abb4309d0ece019fd8c6ba8930bd4ad2d459f987c3cb8606ce41ac00a3f518fded1d113486ccdd5b1eb4b7aa50bbb26bc8a2969127fc38e4e3d6716c5dfd3919efeda9236656cb878c3fa2161510023e33f7ffb13cf7b06ea0ed74e9b9444f317c927673c0bf7ec5ebd736beff7924027ee2207454071ffd2a894e49f5659b7b92c9a2dea3042c471ddd08bb5984eb3d2bd5b77c07a74c5c698b78b8d5134a85a16d8b464e2622704ef3e212f4b11282260a25dcac66bf1c6e539c601a3b3fd3a37d95e68296a47b4729cbe5d9a7c783ef627f68cf2136c41ead8bdc6c59e87d04a60846468e192eb38913c93fbbf6fdd8db95271f67867547c2d7be5060d52603cbe901e82a1295e4a1f55f10591c11447e0ed71b70aebf5fb9588bbe825fbdcb3e80cc561de73a75cf04807409dad73fb0e759488a8586ca747df792cc95c1cfd9aed28cb6dee4099089abfa15d46c9400b525d15e2d9947ed8d5974d3ca97bcabf072adc5f174ab825017d2f10a65c8cf1471aca4b603efeca43b1957e8e0375a39dd5c0b5a5a5f7abb574362f78338e1c4d0313a44c994adcc786ab2546b8fe349d326eaf0c8879002b8626a6edbadc26ac68d8e9441a2845da03acf781d4f40531e24a636dade26b45658c3e1563088e2ea063e54954d77235b25b291076f4e01e8cb0ad24bb725ebae7fe1acccd1a951462b8b01f65a3d1838aa6c6e49925d67feba3a47fdd4cddbe09449dc461f5a5f41d071a532c257880f9ff846809591949bf50aeb5184d90015ed0e7641b32ba497271a1abc3ceaae3e73cb2460bee235950dd3c238ebf9e20f2b4d7243b71d37fefc063f2eaddb3950c62c46ae02fe55cac619f9d1d34dd428cc57b1bede777a8f8d485766c5a7a19b55ade0b1d1933f5ffe8d35c466b4da2047f4b46684791c7d5b16406536b8a0f4c917a6cc587d6d22535172244f147d50eea6c76209ea15fc65d3263c113c06e2d43e60168be5c711a56bbf5b0d5a76f0e8077349729a285aeda1db7b2f2c1bdf4b418c3a0043a3abbde74e2f840d20509c81622d380c04e0f1654efb37ef132b348bbe1acfc3881ec198cf2ed0485a18af203b743768071fa3757cffb15ec159e1071a446c97d5a1a78d1b67b6af7693c6b56520363f81f7e2dc92fe76afdb2ac722109e3e1457949714d22f88b2a07468cfa0534b4c1229d0ace629b57243f2bef8c6102a84093b67130e180dd59b3ddcf4f74f78dccd990a5655d807d79797f79e8f3037b3065e2b34b801b0520d08d97b2d947e22893491b72ca939f21af28f7192a82f0beaa21324287f872d091bd56404d22ea6ebd77995d4111dc045710b3c269a4bd7d31dd8b7d0a29b020f14c1ae982590b702d4d83895d0d2eed089916d3e9c91f8aae12fc19d7aaa4119963f948beafbf511eda71f0248ced06d6fae85881834b098a5be00b54f272ce6e7a2085d5b5764038173e5bc7976eecada06aace885916902cf891dfb042f1ff34410a00e49371e49c9b4001d72250395a0d209a8c2149e013c35245034c07a8e5059e5165cf122a3519a94b8f353bc6d81483a2bf78470af9ef386ecfd087ea2a9cfbc47e00c20436f7e185b6b543ec30fb1e915a44f95f72a6d83b2c3d86e381da239e9e017d9142518f4ca2b73bc916ff647f371e9d82582b02c67b5c2d733dd1e89ef4778498e4d092717389c69a32467e173d0096c55b0c5bad5ac98f0e3d55c4b340ed8018179fdc5cb79918668dc11ebc50ebf6a23b06f97555936e83496f2213e5bfc9cfff16731b377965c738b26c87757f17e94df874e8d5e832647ac46610cb3ffeabce676a06d258e3891a11d4953a7951e407310a9c8929eb3c1b88504f28ec2d4a0b8f64063709fa9c6786eea0439a00150ca691d0ab66aacf86dc2b6ca1da0ff8c16bda372e5a535166216c1a83c1c8784a64922cf90b2bf57a898053f5d12259b1eedbddf8157ea9572d3f561a49d8f315969bcc", "55", "-5e0fa91193c4b557a889dece841a4e352b1ec75357e02df29752cd3be6eded9c879a491e51ec911ad2d56dd7e6baed8b069b5f0201d8bfae25fc191af9798927eef58984201ef7065bdca1795ab0fe1409c8f3a8f2d5da184e876700cfec635d44985ea5696a2cfcc3e1e5c3036720d60051fa8c7ef68e889a43666ead8f5a5bd5285dd935e4514b4893fe1c7271eb38b62efe9c8cf7f6d491b32b65c3c61fd10b0a88011f19fbffd89e7bd8375076ba74dca22798be493b39e05fbf62f5eb9b5f7fbc92013f71103a2a038ffe9544a724fab2cdbdc964d16f518216238eee845dacc2759e95eadbbe03d3a62e34c5bc5c6a89a542d0b6c5a3271311382779f1097a588941130512ee56335f8e3729ce300d1d9fe9d1becaf3414b523da394e5f2ecd3e3c1f7b13fb467909b620f56c5ee362cf43e8253042323470c9759c489e49fddfb7eec6dca938fb3c33aa3e16bdf28306a9301e5f480f415094af250faaf882c8e08a23f076b8db8575fafdcac45df412fdee59f40662b0ef39d3ae782403a04ed6b9fd873aca44542c3653a3efbc9664ae0e7ecd769465b6f7204c844d5fd0aea364a005a92e8af16cca3f6c6acba69e54bde55f83956e2f8ba55c1280be9788532e4678a38d6525b01f7f6521d8cabf4701bad1ceeae05ad2d2fbd5daba1b17bc19c70e268189d2264ca56e63c35592a35c7f1a4e99375786443c8015c3135376dd6e1356346c74a20d1422ed01d67bc0ea7a0298f12531b6d6f135a2b2c61f0ab18447175031f2a4aa6bb91ad92d94883b7a700f465856925db92f5d73ff0d66668d4a8a315c580fb2d1e8c1c55363724c92eb3ff5d1d23feea66edf04a24ee230fad2fa0e838d299612bc407cffc23404ac8ca4dfa8575a8c26c800af6873b20d995d24b938d0d5e1e75571f39e592305f711aca86e9e11c75fcf10795a6b921db8e9bff7e031f9756ed9ca863162357017f2ae5630cfce8e9a6ea14662bd8df6f3bbd47c6a42bb362d3d0cdaad6f058e8c99fafff469ae2335a6d1023fa5a33423c8e3ead8b20329b5c507a648bd3662c3eb69129a8b912278a3ea8775363b104f50afe32e9931e089e03716a1f300b45f2e388d2b5dfad86ad3b787403b9a4b94d142d76d0edbd97960defa5a0c61d0021d1d5def3a717c20690284e40b1169c06027078b2a77d9bf789959a45df0d67e1c40f60cc679768242d0c57901dba1bb4038fd1babe7fd8af60acf0838d22364bead0d3c68db3db57bb49e35ab2901b1fc0fbf16e497f3b57ed956391084f1f0a2bca4b8a6917c459503a3467d029a5a60914e8567314dab921f95f7c63081542049db389870c06eacd9eee7a7ba7bc6e66cc852b2aec03ebcbcbfbcf47981bd9832f159a5c00d82906846cbd96ca3f11449a48db96549cf90d7947b8c9541785f5510992143fc396848deab20269175375ebbccaea088ee022b8859e134d25ebe98eec5be8514d81078a60d74c12c85b816a6c1c4ae869776844c8b69f4e48fc557097e0cebd55208ccb1fca45f57dfa88f6d38f8124676836b7d742c40c1a584c52df005aa793967373d1042eadabb201c0b9f2de3cbb77656d035567442c8b48167c48efd82178ff9a2085007249b8f24e4da000eb91281cad06904d4610a4f009e1a92281a603d47282cf28b2e789151a8cd4a5c79a9de36c0a41d15fbc23857cf79c3767e843f5154e7de23f0061021b7bf0c2db5aa1f6187d8f48ad227cafb9536c1d961ec371c0ed11cf4f00bec8a128c7a6515b9de48b7fb23f9b8f4ec12c1581633dae16b99ee8f44f7a3bc24c72684938b9c4e34d19233f0b9e804b62ad862dd6ad64c7871eaae259a076c00c0bcfee2e5bcc8c3346e08f5e2875fb511d837cbaaac9b741a4b79109f2dfe4e7ff8b398d9bbcb2e39c593643babf8bf4a6fc3a746af419323d623308659fff55e733b503692c71c48d08ea4a9d3ca8f20398854e4494f59e0dc42827947616a505c7b2031b84fd4e33c3775021cd000a865348e855b35567c36e15b650ed07fc60b5ed1b972d29a8b310b60d41e0e43c253249167c8595fabd44c029fae8912cd8f76deefc0abf54aba", .Okay}, + {.Shr_Signed, "fc761e4c23edb580999f2ed9a1171f7c40cfc826958767078bba476f0cadfdffc17fd087789f32a54c9cc9fa4b9607d7af2e5354c116d58f52da93d59332a2b723211e3c4e9938d49b475bccd6bc980708b111d413289ebe72f75ef16055880a07a5388f53500c035a5f4d39cb59aa18229bb3e0bac13a60d5193bdea7199f786f59501c401234cb53288a97e8e85d2fa1e373b7575e8b8ae9b7b918dfdb8ad1764048c03843596338605d34cef962c85ac3d757d13e9856903fb1334e94d3e7ab4ff52942a39b519e640b78125eafb85d88b1c209ba80cbc86d471fe50fee35d0bdae869edc682c3df0552d5310bbb84a5d8e24a4ee9a0694e39cbb2d20948fe47e69a11de00ba2f7128f89bfed028457503c1d661afe2977ccecb1ca3c9589d648bf02a0515978cbbb864a7d791d2ee756adf8fdfef2b9ebe7a1e26ca973e23a6a26df9db00b21c91a10a6b1f9fa046b1f13d6b20e35037281f8d54e2ab1089d8799386091fd65f5a93acd7453e2feb7ed0f6d8775a421b3081a3fc22f24e3e3d824ff53b1365caed7923101416e79ecf2e06cd4d3067505c40b3f67df88b73500b4665bb36f2ae88ea29fea98f52d0f617ba52c7967ade6ae9477d460fbded2424b0178627ce6631bb7b425d3b4dae20803ecdd4cb22ffc856b9c2b9e42c287dc817557fed4a8489839d31034a52a40e9bb4c2af3a6ad0af32f9d1ef28fc0dde2696aa780c7eecce1980d7091bce4cee7ba9cb2ca15ff4d29d07eef9b83e2e20d29fdc1451a847a52ca74fde22ec8e4bf504e640f6be35621058488cea52fd0321c58e6919fa0faa9489f85d8229b4c8b26c52c0d78bf7ccf61fcf8aeb41f67ab2c6280c3566125983dbd2a578fe11c5fe2c854badafe45418f8bde08adf62d541b4a5fb2e78dab8cde5d4f71a2fb9babb43ceb80d3029a144a55ffc2fe34d583c025526004dbb4315ab57e71c423ed98641ba94af8b174ab96083afa3b16b46ebdb07f59a60656e4893f4a145cfa9a6ba13f0ec6409b2a1d149642c7844b44b53ead35c7c4773bc8f4283d2e6be79ac078e75408da940218ebabb9ed6ac0e0e168a7c8508a9cd2033b22ad891b0eb4392c7020c5a49b00f30977a13995c2b58fb699f2af318fa4ab52f4f1de4725777b8a740771a084c12f4131337a73e71574d473cbab36873a087c45fd247d0e22fff4823d96d24a9f95b85cee646f8594c62ac4b1ee5ca9239e8921eda85d4503c0e1f3f6c27386aa45db0417eaf951f389b1e70e4f79c51fb3a4b0d742f8f39fc06e888eaed6a1b82bed0a5f157d78f5cb3390b46eec9d02109c4777eec74d00851c402b286dd57b2e8bbdfe26b0364c7abaffbb62d5d0113c03039ecf3f09feaaa6bfd2c528c626d131757e2b2a85d80947ee625c74a759b288a184ce432eeebdf8efd7f130c65d0ab23e8851ffd1b11976ade455a148e59958fda8f6f8bcce1442cead0770ba9f121ddf854555ee32b1f1833de580fb0a2aea775605de4a6cf6f83746401a2a0cab3764caf5a72a8bfa5e82e0d3d4b6da865bd5f773d079a5d905891caceb14220768b27126833f117a3c867094d02ee3e403bf7429786541def3e1ec1df6954df74171d8c82838905ab7c766c6d27e6a4edc71eb27265e72e95baf249c72ebb165f93ebfccb48b26df505755bb4182fff00b7fe70f0e0ed2d97f3ebed127bda7ec086647856a63376dcf072201e66e9014d563ade611621f460b2e3ee5e390a1108386be4d6df442d2dedfb163b068513c43090e88063be7efe5b9390e39d9e6d0b5bcf4089ef2db6cbd17a47a934c6574f7b2339d6a50f87dc0e12dce44ebd44c099454f83ecf93fc91ee485f4ece85dd43da656da5ae80b41ed04e2f7ed627496f336b85187f684743e87be09959ca397a99c65a3388c0a84008407075ec5774e2a434a1ed89d8ab96c60a36ce63a0460a77a09eec28f008639684888283bc96acbe0223dcc69d6f25b2a5b47bc148c99d448ded31907d7c701c81211d2756c044415b1c9d7f6d2cafad97617542e380654af16a36e676e9230bb8a618bb3905b3689e92350c0021a654ff9d0dfbf0cbd31bdaad884efaf0bead260b0e3b781a465b", "28", "fc761e4c23edb580999f2ed9a1171f7c40cfc826958767078bba476f0cadfdffc17fd087789f32a54c9cc9fa4b9607d7af2e5354c116d58f52da93d59332a2b723211e3c4e9938d49b475bccd6bc980708b111d413289ebe72f75ef16055880a07a5388f53500c035a5f4d39cb59aa18229bb3e0bac13a60d5193bdea7199f786f59501c401234cb53288a97e8e85d2fa1e373b7575e8b8ae9b7b918dfdb8ad1764048c03843596338605d34cef962c85ac3d757d13e9856903fb1334e94d3e7ab4ff52942a39b519e640b78125eafb85d88b1c209ba80cbc86d471fe50fee35d0bdae869edc682c3df0552d5310bbb84a5d8e24a4ee9a0694e39cbb2d20948fe47e69a11de00ba2f7128f89bfed028457503c1d661afe2977ccecb1ca3c9589d648bf02a0515978cbbb864a7d791d2ee756adf8fdfef2b9ebe7a1e26ca973e23a6a26df9db00b21c91a10a6b1f9fa046b1f13d6b20e35037281f8d54e2ab1089d8799386091fd65f5a93acd7453e2feb7ed0f6d8775a421b3081a3fc22f24e3e3d824ff53b1365caed7923101416e79ecf2e06cd4d3067505c40b3f67df88b73500b4665bb36f2ae88ea29fea98f52d0f617ba52c7967ade6ae9477d460fbded2424b0178627ce6631bb7b425d3b4dae20803ecdd4cb22ffc856b9c2b9e42c287dc817557fed4a8489839d31034a52a40e9bb4c2af3a6ad0af32f9d1ef28fc0dde2696aa780c7eecce1980d7091bce4cee7ba9cb2ca15ff4d29d07eef9b83e2e20d29fdc1451a847a52ca74fde22ec8e4bf504e640f6be35621058488cea52fd0321c58e6919fa0faa9489f85d8229b4c8b26c52c0d78bf7ccf61fcf8aeb41f67ab2c6280c3566125983dbd2a578fe11c5fe2c854badafe45418f8bde08adf62d541b4a5fb2e78dab8cde5d4f71a2fb9babb43ceb80d3029a144a55ffc2fe34d583c025526004dbb4315ab57e71c423ed98641ba94af8b174ab96083afa3b16b46ebdb07f59a60656e4893f4a145cfa9a6ba13f0ec6409b2a1d149642c7844b44b53ead35c7c4773bc8f4283d2e6be79ac078e75408da940218ebabb9ed6ac0e0e168a7c8508a9cd2033b22ad891b0eb4392c7020c5a49b00f30977a13995c2b58fb699f2af318fa4ab52f4f1de4725777b8a740771a084c12f4131337a73e71574d473cbab36873a087c45fd247d0e22fff4823d96d24a9f95b85cee646f8594c62ac4b1ee5ca9239e8921eda85d4503c0e1f3f6c27386aa45db0417eaf951f389b1e70e4f79c51fb3a4b0d742f8f39fc06e888eaed6a1b82bed0a5f157d78f5cb3390b46eec9d02109c4777eec74d00851c402b286dd57b2e8bbdfe26b0364c7abaffbb62d5d0113c03039ecf3f09feaaa6bfd2c528c626d131757e2b2a85d80947ee625c74a759b288a184ce432eeebdf8efd7f130c65d0ab23e8851ffd1b11976ade455a148e59958fda8f6f8bcce1442cead0770ba9f121ddf854555ee32b1f1833de580fb0a2aea775605de4a6cf6f83746401a2a0cab3764caf5a72a8bfa5e82e0d3d4b6da865bd5f773d079a5d905891caceb14220768b27126833f117a3c867094d02ee3e403bf7429786541def3e1ec1df6954df74171d8c82838905ab7c766c6d27e6a4edc71eb27265e72e95baf249c72ebb165f93ebfccb48b26df505755bb4182fff00b7fe70f0e0ed2d97f3ebed127bda7ec086647856a63376dcf072201e66e9014d563ade611621f460b2e3ee5e390a1108386be4d6df442d2dedfb163b068513c43090e88063be7efe5b9390e39d9e6d0b5bcf4089ef2db6cbd17a47a934c6574f7b2339d6a50f87dc0e12dce44ebd44c099454f83ecf93fc91ee485f4ece85dd43da656da5ae80b41ed04e2f7ed627496f336b85187f684743e87be09959ca397a99c65a3388c0a84008407075ec5774e2a434a1ed89d8ab96c60a36ce63a0460a77a09eec28f008639684888283bc96acbe0223dcc69d6f25b2a5b47bc148c99d448ded31907d7c701c81211d2756c044415b1c9d7f6d2cafad97617542e380654af16a36e676e9230bb8a618bb3905b3689e92350c0021a654ff9d0dfbf0cbd31bdaad884efaf0bead260b0e", .Okay}, + {.Shr_Signed, "b3fb192740fa419457155a6e8d6dab2f547226c4a72a0fad2928c950224121026437064c262fdf8136f1a0e7737124c218db08baacd9ec98f02f045e74711461120a520f630231a3646d911cf1f19b57a00f3e011355ab1f708d7acb368c35324c4fa3cad7e6733c7b97817be5538de9b71280364da323abb74006d74461d9f572eddfde8017bfdecf105a28b9d6437eae3fbdbffffbdc3e6c97d87ace8cb89536e7bc83355ea8a3035fb70e6e6c3a19d5dda2edb6138fdd4794788bef54ff8f4e6bf43e77c191a8616a496a5ce581ccc902e182e16fb28098e5738f2d7efd6b8163e8416e0d6e6e65cef310fd5a77b5a494232bd19c5c36ec9f17bf4cb5046df9f00db2b37f1238c4c6fd49e688629d242419ef91fb023a376841f3dea4e30e5542aa1108b0225929df439876eea6902c6d13990396c5a76389c1dfd2ce50bfe4703894b9872b8d7a349b003d170537b1b6d6e02147dfb999eaeefc835ccaf0218ab3148ae453613f42e6c65685ae7e3e9491914062b1d216b5c99fa7b8bc4d795f188983e201f5a377d01ca3266943f053fd227b86d45f2c8995f73886abba3f9398420acf0aa28be064641c0cebc7c455255d2a64518384aa1c65b25845982c5b64acf725aaa3a60a88c82e654c7546d97dec68447cf931863550317ee85789549902d18e42ddc63226bdfbec93ef535f81834d833357bb050d51068b443200dbed9237301f071450775aabc1ee3f3d7ac9c260f0b559d0b525870976f24d8eb88ee5ec81184462fe4e8b7bb590a01849de6b5e1ff2cc507227559587438ece85a2961238b29e21f4854d2e0f28fc924c3fc8ec31ec323d64927552007e99f815d2c89c9721163ea9994bc084114ec2bf04d55f014a3ffb477053a8f4cc916a3ed578df3b0210dc34e02b098cdce022d318a5b6562d568bd9719f510f2d09f170d9e248cff6809b2071a8df9f6eddbaab3f821df3df6b05b040c5c3d76554d6613e478d8eb7e7d256bbf7d6aec2bf6f944fde2ff126225555c525869f0f2b70abb3ac607af796eccb201f7e0ef4005c1ecc2ffd7d219df9983f2d614b830ccfdbce340c13386812cbd42f71b114ad639bd8932b2c9bd57def3fa36d9ff5a0845e1b27f1f617413f13de3a0b9a12b74f0acd3b3d483151d6fe6388e4f559edf4a27e96343a820c5dcf4bd8c1164f4424f44671ff8c50729232d2d75d1219d05d1aa0351d79dd73faa81be27562e10e3d520e092061daf0a290679405d99ee170f15bd03cfe05c81b32216662a827040966316d01731cb321ca73b1d1cb23f1d3713a9acfc24b6fa4fd699c43df7f01dc57a7e72133b63506f0bd67548b3cca3aec8b73b23a7edc41009548c7aa2697627dad2ad459762d86d7635dc00e39ba570ab868d7849e48bf0f3bd7c55415b71892b09b6b75a3707afd9121cd46520c9fc17d5f3a04695790149f76d761f6a2945ffc2f8b8f1110e5a3ad9ca0b2d89838cc1efbb0b69ffcdeadb39d2d3c2800a72428f0ab74df1f261b98d132a92fa41ec460bf29ae5c29890f5fd8023b32ffa2505a3afe36a5f95f0ea11910533a06fdee042fd0f3fafa5ce685a4b74a19574974cfdd81c3989286373f584feaadb59f23b9379bd79e4550b18a0fe92dfd32377e8b9ad1c8ffe61d5ff12d39bc22bd55677db667cda51c5efbd3bfff28a9370eff1cd08e051e8c01d1fed9af825636aabbfc69a36c8d4c1927080288d25ecb69080d77c3a24907ff3acfe299388646cf9c6dcf77a4cc41a40dfdda391d707b746f449623f31e096300890778f7e3cac558ed6365f2ddd0ed10a06bf1f0fee32163d5541d13aff919a0d3e74101ffc3a6f1562b0e6839d4de00ce33d0f494c69dfa672b2e317d299c2e04e018919b334d81e58f497df139016c986740f9311c8cc9174c378c30b5303e82698e01e3c17213b189f667a7f1356a803e0dbbb4fbd18bafe8b0cb6a595d920776a7177924b9e02809c3bf9bf6386b8dd46f9369bba1e0e375211f1c0b4dcac27dca316581ecb33f0ae34af5a0c3c8329b8da2f462d9183ecf21a521c2d2a50d23b3509fbb0427ac13e24abcd49f41762fa7c0686569a469b20627ecd95907dbbf", "1", "59fd8c93a07d20ca2b8aad3746b6d597aa391362539507d6949464a811209081321b83261317efc09b78d073b9b892610c6d845d566cf64c7817822f3a388a3089052907b18118d1b236c88e78f8cdabd0079f0089aad58fb846bd659b461a992627d1e56bf3399e3dcbc0bdf2a9c6f4db89401b26d191d5dba0036ba230ecfab976efef400bdfef67882d145ceb21bf571fdedffffdee1f364bec3d67465c4a9b73de419aaf545181afdb8737361d0ceaeed176db09c7eea3ca3c45f7aa7fc7a735fa1f3be0c8d430b524b52e72c0e6648170c170b7d9404c72b9c796bf7eb5c0b1f420b706b73732e779887ead3bdad24a1195e8ce2e1b764f8bdfa65a8236fcf806d959bf891c62637ea4f344314e92120cf7c8fd811d1bb420f9ef5271872aa155088458112c94efa1cc3b775348163689cc81cb62d3b1c4e0efe967285ff2381c4a5cc395c6bd1a4d801e8b829bd8db6b7010a3efdcccf5777e41ae657810c5598a457229b09fa173632b42d73f1f4a48c8a03158e90b5ae4cfd3dc5e26bcaf8c44c1f100fad1bbe80e519334a1f829fe913dc36a2f9644cafb9c4355dd1fc9cc210567855145f032320e0675e3e22a92ae953228c1c2550e32d92c22cc162db2567b92d551d30544641732a63aa36cbef634223e7c98c31aa818bf742bc4aa4c8168c7216ee319135efdf649f7a9afc0c1a6c199abdd8286a88345a219006df6c91b980f838a283bad55e0f71f9ebd64e130785aace85a92c384bb7926c75c4772f6408c22317f2745bddac8500c24ef35af0ff966283913aacac3a1c76742d14b091c594f10fa42a69707947e49261fe47618f6191eb2493aa9003f4cfc0ae9644e4b908b1f54cca5e04208a7615f826aaf80a51ffda3b829d47a6648b51f6abc6f9d81086e1a701584c66e7011698c52db2b16ab45ecb8cfa8879684f8b86cf12467fb404d9038d46fcfb76edd559fc10ef9efb582d82062e1ebb2aa6b309f23c6c75bf3e92b5dfbeb57615fb7ca27ef17f893112aaae292c34f8795b855d9d6303d7bcb7665900fbf077a002e0f6617febe90cefccc1f96b0a5c18667ede71a06099c340965ea17b8d88a56b1cdec4995964deabef79fd1b6cffad0422f0d93f8fb0ba09f89ef1d05cd095ba785669d9ea418a8eb7f31c4727aacf6fa513f4b1a1d41062ee7a5ec608b27a2127a2338ffc628394919696bae890ce82e8d501a8ebceeb9fd540df13ab170871ea907049030ed78514833ca02eccf70b878ade81e7f02e40d9910b33154138204b318b680b98e5990e539d8e8e591f8e9b89d4d67e125b7d27eb4ce21efbf80ee2bd3f39099db1a83785eb3aa459e651d7645b9d91d3f6e20804aa463d5134bb13ed6956a2cbb16c36bb1aee0071cdd2b855c346bc24f245f879debe2aa0adb8c49584db5bad1b83d7ec890e6a329064fe0beaf9d0234abc80a4fbb6bb0fb514a2ffe17c5c7888872d1d6ce50596c4c1c660f7dd85b4ffe6f56d9ce969e14005392147855ba6f8f930dcc68995497d20f62305f94d72e14c487afec011d997fd1282d1d7f1b52fcaf87508c88299d037ef70217e879fd7d2e7342d25ba50caba4ba67eec0e1cc49431b9fac27f556dacf91dc9bcdebcf22a858c507f496fe991bbf45cd68e47ff30eaff8969cde115eaab3bedb33e6d28e2f7de9dfff94549b877f8e6847028f4600e8ff6cd7c12b1b555dfe34d1b646a60c93840144692f65b48406bbe1d12483ff9d67f14c9c432367ce36e7bbd26620d206feed1c8eb83dba37a24b11f98f04b1804483bc7bf1e562ac76b1b2f96ee876885035f8f87f7190b1eaaa0e89d7fc8cd069f3a080ffe1d378ab1587341cea6f006719e87a4a634efd33959718be94ce1702700c48cd99a6c0f2c7a4bef89c80b64c33a07c988e46648ba61bc6185a981f4134c700f1e0b909d8c4fb33d3f89ab5401f06ddda7de8c5d7f45865b52caec903bb538bbc925cf01404e1dfcdfb1c35c6ea37c9b4ddd0f071ba908f8e05a6e5613ee518b2c0f6599f8571a57ad061e4194dc6d17a316c8c1f6790d290e169528691d9a84fdd8213d609f1255e6a4fa0bb17d3e03432b4d234d90313f66cac83eddf", .Okay}, + {.Shr_Signed, "69a539bf20a729ecfe22ae13cef7808657e03e987036e77332c33f422b69b9d72a7b4bcd2ee168384bd3ae222ba09d61e4267ff2c2fec936ace5343a6276f831eed31186816828b716a2ef8e267a7d34076379bf335331c128523f6cca4325e731bdcb0aa80a39acaf2a7a94f629e4a722b09d74fdaa40a0b33de5ad7a78d4a2707c82a41a8bb4dc0d9065ed6c17aecc0870512bda4622b3fd0219b687979a37d1dafc197b276748c7731ab585b73d1e706bce2eb55c9bb3324f4bb978602f5a1d74d75cdeb62aaeecddeaec05510149e8170ffade1fe9da432340680fb2012782294e7eddb71121098483b763df5bfe5225938ee5084d530c806661b8abd7f57a094a6154fb06ef3fc878464d85a28076f88196f3aa253d954fca4b76f8834833f8d9aaa4e887a45acdbf6017309ee9e48a5f69952c13e6ffbbb12d33a4e23045ed33c246052088d2192e043f027c46db9958c481e718999e510fdf8a069995cd9fbc41953fc835a55eafd6f77089b3dd129ffc27aaf4f3e1687a798212e6e30c4df2e0e772d471b5d49c9c09205a06763a7524147ca708fbd0afe56190933a5a10146551b6c458fce4e916779cbdc87a63954f7f0cd80a0527389a4ebd2663998ea54ae2f11e05b775ff9e1dae7c62036fa23ebde96bb8159c74f3d138862ce5358f288cb5d5ee05fe01c2bf3221c8b8aa3552724fc46e50247e9974d7d19fe00926720aee981cddf2bde6f82a8f74735024a7da50e1a4b0030482dec5bfc2b03c16af0776d8ea8c8fbfdcc46f333c2b1ce2cc923c2672eadba588d4b216d58c9e1b408ec27713744ca8fd3eb49c921e74474dc29b3af09faa35345003ef93562c4ae55428a66be824e452cc059dc0164ba5ddb5811b15ebbcaa2535fdb1ca310054278d353aae7d7c11b4b4a18204ea647d99bce2d207566012080be3dc0e95a5d05847a749f89614d97d9256d6ea9a87b34218072e2a49f7b9cb728086dc077b0d0ace375ecc97ba97e6ef0fff382a0a83039fec92f095e59268a69ed40e0aa99350b73ba524335aaf4123adc24c0e70815895bac1451432c0e3068b5a2c2f347c5225c1f6f106d7d44b78b44fccbdc703e2cbdd2f0407b7150a4ef050cfc2da589f63acee1834ca994e857e066cf1772a0f23dc47963564caa70b1965c96e4212d1941d8e6e77f7b63be569d79162d10dd6a616ba3223bac7288be9cbae139b09c93a2550b719c6ae5c8e0b2202b30200e0851e34202a1a594bed67bf81b7c3bdbe6dc4a18cb58595895c68fa359a8a7fb97f48094bf86694773c96b60de716e5c005ebbe2ea1f052f64e10cfc3922d5795e33e46a0d6cd803e831cf60dea77aa5373317e942e25a0a9506727bf986fe9074dbaf1b7402dfeb7cf28b30c2d8b068fa69ceb15ecacfd4c1bbd7506130554111ae88daa45d6a33bb4cc1bf4d30d8ce21c0ebd30ad30ba91faea1b348fac37a1fecc0e6aa4c846ce7097ce9e8226dc4189e92863eff0a0b29ad25c87659c47f3adf2581240e6083bf965dc8f87b32516e3c995858692d1352cfd26612ef215528efae82879b7c97732e8d971c4bd182fb10bd39e264e7aca0c6316c8ac28b3bc456838ce87bc9de6b688b50c082a13a36e63413ccac92f5fd714e62391101115ba304a052d0bebdf501362e219fe924790932a37f54a3327c9da807fdaae998268f3b99cddb2ccc46297d79fd9a3c533b150fce3737b634bf522ad191d6ae69dd0ec4438e792a3f9072d6bd1768e5b1044d369b7ae976c705cab0387f579138482a9c46ec93fddb9b0425f07890eb3354d10ef9992b86589771371e13bb31e6c8137c2c9d33a7e27e3ae8918f43f3f5601ffb0ede41d76a094052ef39e722148d66c291b75b993b8e99ee315599d4bae9ee0105b8d619d984f0ad7c05e3f32ab68631fbe9984db9be36bdde9181664a84e1526ad4ccc94933a328994ac7695f71cf635b6e125cb96e0489bb9ed6fda903f2b530744e21b62dee2543efe6d803a5dcef3c4ee6060748b6d305968cdb21f81c02cf3f1306cc0b49520f0cc43672851752445d0b9b022263d9e17ca084928024b4a4ef927da5250bca613d6d0484285841c5604919709", "3b", "d34a737e414e53d9fc455c279def010cafc07d30e06dcee665867e8456d373ae54f6979a5dc2d07097a75c4457413ac3c84cffe585fd926d59ca6874c4edf063dda6230d02d0516e2d45df1c4cf4fa680ec6f37e66a6638250a47ed994864bce637b9615501473595e54f529ec53c94e45613ae9fb548141667bcb5af4f1a944e0f90548351769b81b20cbdad82f5d9810e0a257b48c4567fa04336d0f2f346fa3b5f832f64ece918ee6356b0b6e7a3ce0d79c5d6ab93766649e9772f0c05eb43ae9aeb9bd6c555dd9bbd5d80aa20293d02e1ff5bc3fd3b4864680d01f64024f04529cfdbb6e22421309076ec7beb7fca44b271dca109aa61900ccc37157afeaf41294c2a9f60dde7f90f08c9b0b4500edf1032de7544a7b2a9f9496edf1069067f1b35549d10f48b59b7ec02e613dd3c914bed32a5827cdff77625a6749c4608bda67848c0a4111a4325c087e04f88db732b18903ce31333ca21fbf140d332b9b3f78832a7f906b4abd5fadeee11367ba253ff84f55e9e7c2d0f4f30425cdc6189be5c1cee5a8e36ba939381240b40cec74ea4828f94e11f7a15fcac3212674b42028caa36d88b1f9c9d22cef397b90f4c72a9efe19b0140a4e71349d7a4cc7331d4a95c5e23c0b6eebff3c3b5cf8c406df447d7bd2d7702b38e9e7a2710c59ca6b1e51196babdc0bfc03857e64439171546aa4e49f88dca048fd32e9afa33fc0124ce415dd3039bbe57bcdf0551ee8e6a0494fb4a1c34960060905bd8b7f8560782d5e0eedb1d5191f7fb988de66785639c59924784ce5d5b74b11a9642dab193c36811d84ee26e89951fa7d6939243ce88e9b853675e13f546a68a007df26ac5895caa8514cd7d049c8a5980b3b802c974bbb6b02362bd779544a6bfb63946200a84f1a6a755cfaf8236969430409d4c8fb3379c5a40eacc0241017c7b81d2b4ba0b08f4e93f12c29b2fb24adadd5350f6684300e5c5493ef7396e5010db80ef61a159c6ebd992f752fcdde1ffe70541506073fd925e12bcb24d14d3da81c155326a16e774a4866b55e82475b84981ce102b12b75828a286581c60d16b4585e68f8a44b83ede20dafa896f1689f997b8e07c597ba5e080f6e2a149de0a19f85b4b13ec759dc306995329d0afc0cd9e2ee541e47b88f2c6ac9954e1632cb92dc8425a3283b1cdcefef6c77cad3af22c5a21bad4c2d746447758e5117d3975c27361392744aa16e338d5cb91c164405660401c10a3c68405434b297dacf7f036f877b7cdb8943196b0b2b12b8d1f46b3514ff72fe901297f0cd28ee792d6c1bce2dcb800bd77c5d43e0a5ec9c219f87245aaf2bc67c8d41ad9b007d0639ec1bd4ef54a6e662fd285c4b4152a0ce4f7f30dfd20e9b75e36e805bfd6f9e5166185b160d1f4d39d62bd959fa98377aea0c260aa82235d11b548bad4677699837e9a61b19c4381d7a615a617523f5d436691f586f43fd981cd549908d9ce12f9d3d044db88313d250c7dfe1416535a4b90ecb388fe75be4b02481cc1077f2cbb91f0f664a2dc7932b0b0d25a26a59fa4cc25de42aa51df5d050f36f92ee65d1b2e3897a305f6217a73c4c9cf59418c62d91585167788ad0719d0f793bcd6d116a1810542746dcc6827995925ebfae29cc472220222b7460940a5a17d7bea026c5c433fd248f2126546fea94664f93b500ffb55d3304d1e77339bb659988c52faf3fb3478a6762a1f9c6e6f6c697ea455a323ad5cd3ba1d88871cf2547f20e5ad7a2ed1cb62089a6d36f5d2ed8e0b956070feaf22709055388dd927fbb736084be0f121d666a9a21df332570cb12ee26e3c277663cd9026f8593a674fc4fc75d1231e87e7eac03ff61dbc83aed41280a5de73ce44291acd85236eb732771d33dc62ab33a975d3dc020b71ac33b309e15af80bc7e6556d0c63f7d3309b737c6d7bbd2302cc9509c2a4d5a999929267465132958ed2bee39ec6b6dc24b972dc0913773dadfb5207e56a60e89c436c5bdc4a87dfcdb0074bb9de789dcc0c0e916da60b2d19b643f038059e7e260d981692a41e19886ce50a2ea488ba17360444c7b3c2f941092500496949df24fb4a4a1794c27ada090850", .Okay}, + {.Gcd, "9a1a6ae6c3ea0e168a5b36ed8e599d6ece1e7d43d6e87832689ee0680a2664ac7c5353456136a0e55c059b0c804577ef8f060abaf830ddfcf226db5432e400ff7c1fd9ba4b3341223172e85809f2b40e5aa90304c1851c6565b26a16101a10184b5678020bb6f5565410994a34f79091aedb9fb391ec55cd589e8f8126f398d3f3c6abb7f55a37aabceb0e6617a8bf59b5d76749fb6c92e84fdc97420b83412ceb857bd90504f417b4d5e32f0c8c8f078abd18426ef1c019461610657f0c270191777d4839fb9d87cd8f52639d79fd2e4345724cd07899a55951436296a10f06691f67fdd2c0f0ad39f5e3d452af38ba82392af2b60540d2d32c0c22d5ed9fd3049076155ecbfb13868c47ec03d1356c7a5516c8f1e241012ed9a92d8fc8abbe415876c4f30565a64925899ab519ae7260f1e3852b91d3f8608682858476fcf508660c7968edcfd878e01de08f36906af170da26b1a88f45442a1e553dc97387f59790a52690858d5ba80613a323da3eabedf0fa717d8de157aef112568873960a5aa4e2d0b0016aa9b1f79b731ca8a5af6282f26de85516422b4c4ef06367128f14177a9044f3ec18e797d00b55a541a18f29adb3df90d579ab36aa27b5f27a751506797b63ca67b0abab157faa08b462d5c5946ee625f844376aed8054713ea5324a0a3b89bc4c07e1a42de447e9ac229c534a297b2d20f5d6bd54b47aa312bc20a0367eaf2151d695311d6ce59a02c2878abda123afa6d9e0fae5528a99f2adb8f0c5100d5722dffec78cb4f028d2ebf52b4ff2adaf7ce0599febc1b8b3e0621e2fe9add988eb43ea34f42b4d68765c043e16b397534b13b4110501570fce50581c0bbbad89d12e29fe93351f78d0e1ae30e1bb4d409062dbf678b3f2b8faf5fe4fcde5bce2b2e0f9f2160db9f4a5b6a359a6b7600d6001332e1f1e1763ae73ab3abe683c890a4408a04b9feba05c623491cc7e4cdd90b6bf36dc5507aa46def931963a2b1dec467934e4cc4286fcc11029ca47ecf265cc71781ec75e1493a012bbdfd10c387a4638af4c462d49989892f4702766d33ddeb897ab100ebcb4f9398d76b018b43b22bb95e9f4818d547410030d381554a272809009ecbf7173b6fd66b9eb83e52a01a8f2faf3089a23a34054bcabf7f07e63f1c975262798425b02cdc87f81669513a8a9b3f04a78a055b4f2b96df4e3c1f27b5dee557891d745fcb51538634801bc2e6dfcca9c15aa40cb7c373c69319656fab45d9950237910bff2d6f6911a3fcd7d946bce0c894f43dda968fea385c84729d8bad6bfacdf2e95a188281fbb6821b9dce8e6a68d7b367f12346c2b7a873406a54217aa0d3f79b56d3cee79eebb593fe0561ac8f437d851c19b17bfc59c8230c0c41a5d2dc250b4d54576243fe2190fc81809c1fd583bfc3d2253e001650674349a71b18eec964bfb67eb39f11dda93afe358e86f504bd91018be219d4d0ddd5e4ea6500263859998e4574075901a213d5d281935731eb3a8e5d874c3edf3d7acbbf1a62131cf63d382babeea1b62066520b6a5c34d030952a6a42c1f6c214e1dd0559e893338fec937c71800548749da1bf97d75382dc97b2d3b687ed339bbee8b6450d2d17c62ff854f10dd2b8f43bd6e60236919b0439e5f289638b6f893e5c64f2f786ad87f61ea16cb0a67231919a71a52401735db4153b33f563d9b912a0e160b141705b2640cca6f006e26733142aaf4d5117e298c1fbf9c072c33e17d7c5a8c0cac0039a13f39a2bede54fa4fa2651c79bf2b64bc0a1631ad4837e8081933de7c943cdb1b65ab6dc03ac39df6fbb376cadf4900bab5c8afaf4593058917813dba7ecfcbf6505216ce988b4ae7a0a55ef9ae6f3b5b151a0ac425d3bbd71795dc9047e5fb51993db128ef754aa705a0a731351f30d8e551f73ab60458f9408f364487623c9a880d95ddde86a15dcb4bfc76f7c4d22570de5805598c7043e7fb5f9cac9cb6ea9f65e547fc455da58824c639d6930ffe2daba51f73091742dccc528505f8a40c9a01128169e3f940d8d62d0b597c80f4c7a2070c9b5ba8c2c4715433459075bc4edab6aeed9d55985f7ca1124e026bfa516d45a6c6e7da4665", "8d1e4ac11c2406acaabe16552305bc95c28f90b4a5f12bdefa05bd3e07e30438eb1b1a8ff8019dacec2e355ca722b1ebdfbc67d1f13232db8a4937b11fcf2be0fc763add572b00998defc9f0d626e3dbb44c2a1a26aa8666cad4dcf9de8b053b2bb954de55b70f61f65a23130c997c92f22fbecfda498a736de5d0f90065b4c5f5d7a7d8d55460851abefbc689fb1a69a197d0ea12d23150e59efef17134a8a9774e7bb87fc03f5de0b34747a3bc286e32cf20f1f23197a2c30f597667104f4ed098b864521e21075589183a8b8459682114154776adf815396dd7aaa5efa51d1756e9bb0535fbc38baa01cd00de6a771d167dbcb6df122287977b2edaa5b4c87fe319e37a4d95a6cf65e45aec4e4fa7aaff7fee29ea82d8b8668188108b536fa9ac762b575791b0bd7648ad0ebe6214daf9e99b15ed89d7813c8050d4b55936bf84f04767905d49816a6c64c978a908964436eb4a03ad0def411a24ecec2080683920aa0a57e5c0480010851551155fdb30899aa34d10739442353a2b25f1cea27341a65626069a0fd9a6643f6923d8f5c874670a844c922d8782707a4aac3aa2a836104f6d6add681c29ee698af5b5289c3a337e1e373c0969e1b5ede589f445899bc13fa8f97869ab5825f0b5281511a4219ea70a750d8edf6c728e600da153f2559acc7268dbb918f1e5a3df9feec61e441544ef8abe2b13763bf44094f694046b82e89346bf2bceb72a673a3df15cf0d7709e4676f66d63d1504b51123198c3905b5b3cdb683d20fa2f2fa3973cf426f6daa565462410b80263464d4738a5571c9fc5ca019c740dafb937745a8496119c153f72f256ddd4ec57b1bafee2937c5ca79c38eca48da7ab71bb3d0677c4676adae2d3f9b671486d58712ffc160e4974fda19fd17d0678b0546523bcf18f48a064d48794ee5139c2836f59dd29c4554f543ded05d0110ef4b82f4301ded7c60fad3b0c55ae0daf4d75097285cd8e92968146d0467b3955054f6179d41b90d67b1b405256ab5a576a4c99cd293d7457ac0b1d0fa43d1a6a223c917523d58c875352885641db18832ab4d186fe1e10649dda47123f75ab7146eb350df12f46f90328fa0d3c0e6eaf94bfa02c9de1487f4902aeddece2f73f55b9e54125da59e42d1c5561a373d7f6e32ad5edb5f9ccbeed2b1a1ce7fda268a78e3a8b98e20bebb99a3c5e3e7cec68af27a4f39dda18d0fb093a8b6f768aa34b31c98367262f9cc54afeb5108288982df0f4270ccbc053e2ba04c685d253bfc96db4a757899fa9c21cc4f353f2f2c8939be5d486598a57c0ca48efb010a447c1d64c633c4e319a522dd2adf7ca6b2dcfc7b7b73897cf3cd51c809faf43a51f6c22707e0193dd0374d01bdb68d12639aa1887f55a70bc2d7e53aab5219fc5cf8587044b10fb90a1e60de480d9090a88294387e73844792aeb82c2ec29f993c2656de76cf015a62aca55336b7dfaa346d4c3616b288bfb39c37ace4ae615ee115a2f3bc8a333e6c912eca0d68b37ca23d2581a6f2d756abb155989098973028082e3e3eeceb028f91868c18abe7fe16b52207a0218e0dedb1571d65084827d76efaf0f61b2531498ce41aec30ec14e1e72d1604bb8a3ed0a8db937ee6330297727e0b019303dd6167177299f85b1a2fd13d5042ee395fb0d3dbf6a16a0d900a6e0bdd8f5e10eb3b9a9787e376522f81cb5ff4ca06780d7956213db9d5aec1f8add0702fa597fcdc3381d379362e1c5b59b31dda2dac7cc9e7504552c828805260666d85f690d2a2573573302c223ec93bf684e3491c57c1fe9bdec6279dbc79829cb279f7e0d639d88997e731ddd81aaf837bc49ade772358ed3d4fdc9dfd65348c2272b6e876f73dd8aea9b3d08e8e103a429fb3152624a10ac2564a6a86f15b88fdab287d98ea7ef7c56359f091ca0bbc0ebdf603e37f558c1d3d7dde1edaf011663e7a764aaeb2900790e6a1efecf645ce67fe843dbcc0aeae2f142baa0e52b974bb1e700c293a746b2176263ffc3ad32e55dcf2ef7e27afdcaa26b2d2ef547bf78c66741d004be879021a53b40926bb6ce692e36833027ccf63be37219cb7677206e2a727958c0a602e2b73c19e3f76a", "5", .Okay}, + {.Gcd, "da4981dbb23a520ec3c0905697b8838336a9ff5f10e98c6f1dc142812b1cec9ce7dc2e589e7d3836313320690ca5082f862737c34eb97cfe0ad624ff26e166d5b3fba47349b6df5b9fcb7e20b6587396f4a8ccc36eee9d7eaf93a6563c57f028a13a9fafcdf54ec139aee3105a6769f04789f8fb06cc051d1ae2c60595a172109579011441efbff509eef7550c7c58a99d0c69a8c16f1b3c68e1243033c1ac575ceaa92602ed25460e3f3f485ec88f20df174997732825ca966e31d02fa8f7e06dac5067da92a9cc8e4048543244838f6eb6aa793df5bfb029b165df3328f6497dd16965c0e0d85a9bf151d6c248e3b5df071180ec6d3baaa911eabdb798e5b3e35c026f8194d6c5a302d26d307b8ada29a70f0c124bc35c12bfe626c86da3824243836bafcf6e54f0abb4942b9b871937a061d3373e39772901a4c07cb28f51c088e142049b32f75ac6887e92f11c59c5f14b410d26914e46ac7ec2cb9ed6aeab4ef1ae0e9434931a8255a8b3b2d2a021965ccfb8e796ecd73633f333632b60de03115e96213603c06d8039fa6adcedfceeabe3c4c9dbf728defcc5297df3c4a228046b2139ea4bf6e49eb4500833cd5f14e2562d474b7f232004a39f86f0fcb94ed50bece862d71452f32703e637feec1f2207c1e0bb3dbd807e23491a46b0fbe20d42855ff19772972a006487d473c4f5d14d020571c28114a0d690e62d52e8561f0f416e431baa2c666e5f817b0f5cb6e3a9b249814a1f13a1385087f65f66360760afcfc413944b7259c82f5d039f67bea4a5471a89e40b2e8e0ec433985dd6ef0da99929b5a30bf220bca297f9323c6b60140d5032ed553c2548c8e838ddc7a21f70bb1d1e9bd3163816138e768b59e9a0a3d11d1699aa4f7faa81fb2f9b588478822c8f0adfd8ab53364cb9674b9e6a301582796c6b57129690d1aed594817da525d888e7189c168c5fda78992a4875f5295cb783a0af598e1f78a34e9b2abffe3182011cfd4178444100d53d4a47e0e64a6927a706f485189a3454e8ff4b6ed1017611ff9eae6aaed154ce70995db9cc158a041df35ad0244ccf5cdfc7783201bd8d22a76edb8153c4cb27fa29c85e2ca7451588ac71e23de2812691b520c18d5f3369581aba58863d518ff7b3949b581e35ba85951857cdc03dc18b2735d6599c9b7ab3ede7d264988c4e60a8221005cfc203dd79d47f6f75a52a6190d0dec65e5d1eb4251eb0e065cd747c31a1ca3b7c641570a35c8f5a54e1ef690a1c0c9c041d62fef7cca87bfbc90d477f65fcaec922c019b46a78e325766131745e5b912605cd66cc28bd42204a312b95053d04e38af909608062b40bc79b7737d4207e7cd4f733d82389124f4289eba35335a531287112ea8784d2f5882171677d89e55206673c12ef3f99b3f8dac7a65421f4a39bf7bc52346dc569ec3809ae7d5f37e96f7fada7c2e2ce003e3f0f54f0ca4ac7ccb4768927fed0791148a4eaf1cb587781033b5c606a2ed2413433b05cae2f9948999aa26f380840c7ceb7e9a52ad589513bb864f6ba8620c80d039e9cec9b20f4f550e92202d6bfc612f0ab75d467e90be589e80b6235462ef026f7e43e671d58898413faff10ef166dab89133977de7f2cf9d34f4ec58d4e516a2ccc9efb28adf5beb7dcfb2d5f5da6ec29b7da2e2ff5f4e2c951117493ca251cbbf0a0e683cc73cb46e5d27702b3885c0c4617a485f9ac3a0ccd80a17d9ce057be04d60c9175da5102f9227b75909b84f9b7accf108367ed6d3bb8aef4175a9bef418b5dd06ce2e7030cbf1b8bb6758fe3c34e62e410b91e8557a35c28f5525769bf388cb95ba49b9de2ba16c99510a1ab8a9b29490a5f58d3fd0beafc8ca6eaddf4e8064b0462f90154ecd19cddc9c28d9c95cf704ca87978b0a2856f1c779876e751846c6cb5dd03539974f7c3e3be2289605df3b54ca29db3f030f336542274bead9bb591c093fbb58aca097a82a09ab7de3760e6a7550de954a89b4189d2c849284c6b2096d5059c73f31084de79f74cf5e818587959b08b6ada07c6c5479961fc56e2723f4b7f5d715885030041acbc5ef4ecf8ec403945adc6862ee025de3c22a73a25765d5ebb3d3c", "d91492814cf4eea44f5f7b199ce00c25e978034115e64421a1c328552d2168ee0439da24ceef6e4a7275d340fb694d5f06fffdebb780a3e3d3088d273f8e05c38559f6c1c342bedcb293db754a1637cc80df8a85eae40c25ea62389b0d6655e39250ce453ea983d15c19294e8b45455d015089def5aeb0c01740fa2994d686f5f2df4d0aa955adbdd71a38ad36b044b3d909fdc22d714dd9981b2560ad1fa6c0ad65631ece02f75caf7792607e649aaed49ded89e6c5b73e105a66246120582c8d1b3927ca361881d4189796be3ed87ea5196c039f665e2b46193f28514980983a3a114ba5bc6b84d733c855f08dfaaec51c703a2b07965e2ae5211f2262e63951d60428ab9e500bd80841408b93c14e1091828fbe6b1602997c5537b04c84ae83ca62d64d3fb3108d73cdb5e428f8b34502ae5d3442b34c1dcc062b05329318c2d58b50fc28a07e8fda2d9fbc3e689fc6596c78a2db068ac33bf902feac6be77cbcb030d864493504cdfc922b60e417e21e015fdd36be736b642a7bd2129705511b5c9451d1154641ebae651c481d1d46f3499e79d96a93aefb5ad8fefa71c643de6d0351e698edb4f9636722b67996c98595d873bed218e5978aed1bdc317f4e80f2f3b75063994e9bb2d0336328e0bf2f8498ee65b722835a4b9b047f26f8a05a3be108e923be179268193fae8a200d77da2bdd49eb191eed76477ca3deebc096e3d5655bd114840680609fe316897bf6494d314a25bd48002c7238bd63da11d6b70d6941db4049453e9ea924e07cbf04fc10daf4acce566f958b23b7e52091735d29d2f11aa48bdd50307e3c7d6bb0154508a83ac9abd3f4804f3d6d9e6c9fa901924c2d80460c3221eb986d6d7154aba7afc1246f8000e0c38f9cee0e9012d54e5fb5e2de44f46fa394467f207d23d6f99055ba6b113e42ff6f5c20d9800cd00a14cc48ce4b5d3f12a9b3db9ea3cb517b3054d33c52756cd1aeee4aab53717fdf6c46476c4f845385a0b7d9e4899dcf98c738bccf2f10a059f45814a8780aba1ee55b54e418779f6fb0fad414b8e6ed2ebe03fa214eaa36610c8d3c910544236ee9272e361e200a2e89bf13aeebd01d8d216b19db114ae5665c0aa3755f1a5b6c7f5316bf37b146160a51df19ff4acbe6107cb531002bec11dfd31c027e1a74168e2849e43fccc15967944759ac46d9bd9a9aed58dd931cefdc248a326a874d33b72aa9f66fe9a9b2f5a74a66bf7de56244850be9e1b44aced0dd655ba223f4880ec35448ce8263b87735b4814a28760683d674d48d4f21debc962f214094429dbdb8d71b8a2b35bdca9fdbdb38e047a9bd1a2b1d717d4e119b3a4244c49ba16c5a7a345788cd6e59925beaea72616167730945ca48b704e3ee85e3bd5211e58aafc370b20014cec733b5a0ec39e0b2e815d69fd44e04902f1afcc1c089f964b497d879cb051d7814a5f72dd0e3390627eac77c87a8d5661dbda9126618bb21f42632a1662685ad66243a68ee853b0eabd6e2888274ba734ad68947a5575263b61ca37ccf5777df8236cf7a20b634229689fe9ba9d0d30769dc72fa57c2026f49ec713dc1874f408122bfcece5e5c1103fbb178326cf6b1d1cccd8918c151dae1c4678f348991fc9cc90556e764706e293961bfe84ea09b4a118c0ff66a24bb27cbe7a9205cc11eb15d99a919c8d81be2ec2728cc414f697dcadffcb004ab6bd0a40dfc5e98bba2f4805a7dc63b23d1287546edaea297cc4a8401390434016dc431e11df88b107625c5275861ced3b82f6db865a8f136f8fff15ac3d397d9fec5d97e1f2a9cd680b792d4922b143c18ff0d6a2f6833efc5fbb4dc98aae2240176b7d5f59302f3071c1793ac4aaf52d24996ef7c1698ca4ba25c79eee919d5b70956aacdaa962c028e9fdb67499a3e5bb9ff84053019221721b0d1ba2b51344f79db655ee1ab24af2402485c67c80079e0ec8eeeb919b5b85e7a08d49e88c7c067b95f9495715a4765dacfb1e6d68c260bd047c36c42813adefdec77425c22827a957191d643f8d662a84c4e42716efdbb36261e8078f5bf457b80c259b324c711780b1c0761bbf1dda6a25a45eb87c86b70a4d3593040bea991", "f", .Okay}, + {.Gcd, "-b27e4be7fb5a38cbb48d0835bc96d8cabd437d403af534f6a5ab18a86ad4eb3c043a0dd7c87bd1c9a6b5fe889e3b5c301f4b0867772acd56be5789d8c4ea643407a6ee6d5e2d45bdb511ad929e3eabe4db048772333abd7e7ccaa09ea7d3dee9644486cda7212e20c2d63ad1b1e91d380986275ed21a9b041132afa44c36e8700eaf0d68ec3363c8bd1dd2c57200799afcb533bfb8382924921349f418dc5c331526218320f7c3d1569cd95872de4c05849e257dacef3646a8ad772707738c22704bbe6b9e820cb0b53665f1afaa954105bcef2b38ff84b2b48c5d8405528916725be3c42b4e662f4556862dd0faee370bbcdefbb4fb87db9b8dceed60b2078466b4f7109e806776f496dcc65c966430b0876f31c82502e62bcf20c3e62131d9b8ee45803bb44717abe7a6d2dbbc14f462aa631a3e961f930b885be114bcb629563a586c1da961cb0fe322b2f58184c838e80d130e2c995a4fd64ae198ae8cc0bb0be470f7ed14d38e85c55451ecc144d68eb594f416008d05876dd4928d726b41d05e83c52679767c9bf6db43c76a5bcdff93652e217b2ef44da4222d5e909e59baaa612d8b36f1c71ecfa1122d0e61c6083620f261f972ea18b3be8e42a956d1befa51ec1f3691323ea489d4b8bace204e54db1623b041ae81d6424b7d26d712b81e77dd4e315d84e2dc7d5624e4f87ab2e7a88a9594c8b7d5167d9862ac9699fa25a8be1b46daaa180f5931c65aadfd8a336ea1623bd3ac6eb3873745b7814592ae3f1103da794abc078b94246ad1a45ec0b5eeb314a52764a3380b2d2ccd720d812aedcd608886003159bf2586ee141bdc22e26d3c3d6240f854bcf9c8df4e3472e9be8ba74e312139326086a54bab03ebfdbac6851d7509c92798de62a727b3fbddbf2c997f1c43659fe569960ae692c8ddbebce1783068afae05fa6e87742881571ec2bd09e674e0b27a59f5accf78b659d00df2589065453e7b3e3ec3d2467f1984c068384905a76557b42b8091aebe3de08790a4bd44cbe8ccbc0d9aa21cb7450e2e78697af6d97c6186313f11d9508540eb3a8ef5899a42f03372f727a92a21f31c7c8928a061f516773b5a310bef902c1c84930ff28453f27ff2fd9405c0dc6a532e75098baf05e19dc4e5222d3ab1dc99fb3045cb8b974e1de7c0014e22d17a902d20308e9cf8e0f8bdb31c65bd1c54b7e77b03d64323a524d069be7701be7808bff30ea279ded2f1b81349174776b5e6772c910fc11feb609eb0df724ac3b522bafd33f230222a1fbf8a47a4899c52ce2ba9f78502cc22d6be03e3a125c455329f1ad77879630e4b791bf77956de4761f133798bf2ba7f828a2f7dada7f4ae1af92062ba6cd2f659e5bbce66c8ce1872750579aa7f86171137ac32ffbf2aa957c6185538d59e92e04a8a1d712d14939f622dac6123431bc0ad57eba9e8a371a4533f211bc8c1dca188f2b07db1e8d7891e4d7954864bc78a13941c9a9f040c03b67e03a77f3e1052c92baefc3bfc3d9d2b1a4d9f2b5b2e4fcb089fe3fde33cbf9e2cab51750a695999857ad3b64e0b1fbcf5e84c8e389366e417578c9099caf74a376f7f2e0d9584732c05f7492260c917d6ea581ff57fd5407750b3b03fc5accfe7f35434f332bd0cdf0b901444a3bf952e20dd9b30f9851be6adb2769b875e884616b6c5b3baf6df1b35423447036029943a367da79368b14c0d9bbd1575749f397a5508722098fb4be7661086b87f93cf9a238a97144d57006001a8d3cfa6ece7219039b8dd9c9302c3cc3b5f30bb61b8024666f7ec4ff496e6ce46b5d37c132598d0fc395e956b622f649977d1cedc3656a415e492290e1105fc7b0dd32570a59300749343921e316d64173c546c5a9c6fd7a9ecba8b631b0eb708ff4a47b1948f288585640773c93be84106c91a1214f89ac2db43e9bc9545af09741263790805a8b2a088824ec73a3f20aa00ff78f6fe1b1fb74118d93cfdb3fad69cabbcfe434772e508bf2b4e5ca1bf9805a82fab0ae8b0ae3ecab40a9562c1da7f3cb99902909bdda204f94077938b7bdeeabcb6cfa78f9a012cb30b31de2572cf32c94c0053ba674bdf2a897f8c70c82552911f39defffb", "fc8c175f113c1f5f48aebccd99f8a4eb3355001021fbb1add20022eb5bdf1e003d9ba5c3dd732dedfab025db77e1ca83628aac79f773f8e10e96cfbefcefc7fac6bc7e5a3d968fb7e35c86ae91635f2e43a74df03c846ac040acf07ae6934a90b874b1208f6f57e3a666ba374f87fcf3cb5e7d4d92f9e9948d9f6ee766182f0ad4dd1d84dcd39a1b2de8e403eb88e466db1f80a98e4fc9977b77ffcf67c9a6b354f01d959934f31eaba23d3778e3ecd22a5e0ecc5c41b3c0d6d72ceb5855535ca1c1d67b5f78307418d1c938f6d1d7273afdb6942e4fc1ae6cccf641854220e923fed72a17f37a50aca40c84343c39c1eb15cd0fcacbd2436f42dc3ef7b0d28240e5c8f4575d0c3fd3f90d27dfaf0fb628b5d0aa31898c1a4a7ef61e83a66c8775d97e1724ad015587bb66faa60a431ee426f30c1dc3eb6581d9e2804dd2baf51ebdfa9deb8b655551313b4e1649928a1f3bdfdd0258ddf4fcd0e699ea993bfc723b60bef2f9f42abcfd148d693dbd4d27addee673bf7d5fca46c11c180d2a4c3bdd341fe1da09c2fafe276c26ca623e45b1abcaf444db6d0213171ff7285bb1135afea212a0ab9fd988ad47c43fe71021950bdd4d4ef26d24913eb683917ed75f3895af43609ec4399e25b8e1ec6e55aaab32d4a3f5ed2a3ebd143610e93a41372302f5e29dc33e8e0b15974aa5753063cf3dbb16f16e2af766c7ce068979d6fef69e5233e86b9923fba293c2c1ddeb1b250c7053bb3da15a6b1b66f9b7eca0badc2b3ddc738a7f638dbf0974c7045bf9af73dc623976bb9316781e25a737677629ef1d961a5953243adc03499efcec5a8f341c648bdcd1cceb4c1d10018d47f7e18ef65207ae936152ebc8db9d21e865023192e7d243e54e640a986639d5f6e2220991f33450eee784b7969e5569ce60a46c901d95997f9bdb4829a3a00f940c66196a5a507b86f6e00c0becf81eec3709822b1c0116ad675248d68dcfff53c7fd3fbae074c2caa1cffbcf36c6cc1b7da58684ae6a2edfd81ced3414d4b1fa838be9beecbc343aeaf739bbbf79390e903fba32ff31c51f81be4feedafabb59c1b713cd17afda82a9c32cbe811f5141114d90305de881ef3bd202ff7588a0f996433adf62acd682e63a100b19380600cf47ba8f40b191321e6b97bd1d4f506342bae8ef68068ed02a1751957e46e99c78e0d33adc354cf5df3f6141996eb5c686f587b2ba445a2b19cb13ffb129bde4819e057e4f61fcafd0a89ce03dc3a18b92064c0a9a02b80b8ae8148c3cd2ad1caed1899222c06f56ca2afb25011726e2dc2757023f4e58c2a3e5b7ad20a6d9a9dc015ddcbf168fe9cee4fc79a7306bfa194556a14cf9d804689ceb657767836548bc1bf634032936436cedcd5bb695f10f410ae800d8b559232d53859a879b566aea9eb16b3cbd8e7fce62f098fd3c2a448ab86f5c23604db7f8036fd97021559e3dcd94ab66b2d3f5b4ab0732cad1136f2dfbadcaeecd651d7d07c20da2e18e4269e65ac2c48c47cda0758777575a7593e54fc358022efb8e3ab0eddb6dc835b2a392c1bafca21c40fd2c3bf26c85c3222237f3483afdd60bce4197172d01f341038df3cb32da52fc548dd1c72bbbba09f54083cb62d47f88e5369018adb135713e443919fed4934ba906c5935d36e0f7f3c02eabe331a9d0a6663d5222ef2d8f6208f9b5f6f2c6a030973fa23b41194501fa628938dcce054e94f7b636380e91db56283a174d727c891eafcc6752bc7184819776029d94611e45d51114af5387dd11f4aeb060f9122785d9aec5ca9d57da14bc69c74e73a38b713d51cd291b68ba7cbdfba45c0a2758c1b952fd54f79daf748e3e4d47e00a5dfaccef87e5d0bee5fecb2786bbbaf5ea9496cc1670b8d9875c946f06e1115f023db445770a38d7eff75f01284224b7fbe572e76fbee3881eaba78866a61fb9102cf6973c29f25169a9520fd73be21072e5d7d320734476cafcfa351b2bb2786b4dd975580728b004c4decd1b8a2c371a02df6767041ef5c95935e8047a1867d5c3590de9de74fa8771ee4f2af00baafb5106d8859e80c8e3a3de1749f447a8edc31a8dca5ae27b9241bad8a972f5f50cc623", "3", .Okay}, + {.Gcd, "63c6461cb0a776ad2b5209f30c66224c18b2f1b43082995513068774438b5c98681aea5e4f8099a7ffb5f86a7fd95e1c15ec19790aa04f49e8d8ea9fe7ca2238f6a3503325fd48a6f14d3bbd15e58e9507fecf1be2df47633a751c87aedfd5272a044ec6b4c5754454839e89308ad41f4af8f16c3082e6f5942e4d6761cb459515ff5027b7550f90911cac4aff438300ad884b83d521d2ab0ee7a94d3d6e6e48c5dd60023a068976bb59d891b43bd221ec66ca325a6cd3a92a69ac8fe58db46cb451b492e0b8697929c7afb245acd9ca2ff469edaca36157839390db2d960e25a8b86686b62d57f6faec830525a7ac229194bb2690428151986f889f28e57a3f3e82606bf6cf31f8a29d8a0dc2f5d48642a91c7c3689109e4a622f09844d371dd347a4a35f0dd8b6b8a90c01831f557477ed02d0f492fe5097712aaa58c3c17047289ea4acd65f84ba95e138dc8f288ac07749641b9a7c8cbaf444c5879101ef467f5a7c119ae906705aeba396905a2f0885e4ab1b682c27e1c38659a9f66a7eb3b4a115392e5d7e85d80156e75588cfd6f42e4c3d34c1035b999f3f0adbdce3821e6c2098cd154550ec891b5daeec3fe9c2af539c33ca3510401c0d8f2b4583ef5d459c96b044416e4b937b487c78bb29ff2856f06f3326b44908bd8ae7cf3177ae3e94ae337a6a5a2678fb46434811a81ea4fe6ca599f1a5a2c2ab703e5d6729ba58f61e573510eb32282028015d76ceca2e29db4cf273b95ac427c021dff73d626706187df9044ef1c3a7629903b2f3fde42d3ad9a09ddba027e9070ce0e03e2880557b506c32dc7c2076c37b2adcaf8ea17b28dec2d81d4b7861016e0c97ac1270aa482745edc6c10b81f5cd4b76b0298b9368f2aa77808c5ccf59f511d58fcced3fddf834e6eea48ae6339db75c6a4800a2ce349790ab86619545fdccc5dc4da244d61f8fed5ffb5809d7769b3c70e1dbb7b8c9da71ac299098807a950f6680ce00fb6317caa396906b9b5a45a165e1e20264b29df7a53da3b31eb71d48699a4470fb4d0b1cb17727b6c29964681c95e7b7d1c2e1b506012a0304525af24838980de7585b66ea10ead98d56548631415a74c2ea336edd0cf47858e34b043ffed041c56e80e49abe016132cb2489dc26ccbe8e634de22a50fdbd958bdff14efcc3fa92d0f6eab7ac32c5b213b7eec12ddeba043e5f1376166837d0053b5d81943c81bde749bc572e56142a507e6ed57e0e49d608834f84111405bd50c7ea6dbb6825c9c70d4e501b53a6b887c167be1cca512ba4e2b97039b27d50f6efd316975b632d87a4b102cdb43ec89cd26f68bd0bffba1aa1f87b8049b2b62d6af54d9f814d60ce9d021aa4a47fae532fbae8db1d7d097bbaf26100684a5becaa9a818becb96762196eeea08b6100a900e15e74d4a8eecf7297299063b3f3a3d4516eedf8bd672d7a8485c975f951abe8f82f8700340ac0956bee2b1643ab8e84f63231fb560e3408a4adc80963677c56ed142e1bf88212554668b4335b8fad8e47a526680712b13010276b6595f94fa577f8baa8fece8f966032cb82c51fab6274f284026995412473f26a20762848baa83e2ffe86cd69f40bbb65b168180f097e41682a40c34003744c31da612117981ec7a676b89f2b36ff66f91cb1e57770383c209b86ca6a9880c08f606d7e0c8768274aa72ba66957c755cdf144084a9af76d726b744804ca891683bb1670b0eb101682f055bbd7324d1433fa46d51f2c548f915912891dc73b7f84526dc74a193fcc719bbb6493b0b9cd0dbe16a3f14d60cdab4d712037d737e5013bbb3e9d8ce371495d406e151a72564da22942e6ef252a79a5768ec33fecef62a0416df2cdc91a6cfbc805e4b1125eb217cae29cfe4a09c69fe764f0605835ea29061610a3bb55083bcf0967f53d6628e396f74c0d9784e8d38ca33b761da6020dc360e6cb7486747fe8f1a29f39bfc905f459c038cbdb90e7d2f6520dd66e38ea6b334648b65989f8907b3590e09c851ea4f8acb2f34ac541334e6171c01ae60ffa9a62d77de5accf2be7ee68f83096674ae7697675d850d692c5bcafb0d3a1970690c547ce0ca6de3ce3fc8e361d74ab6a", "34aab0d2bc1b48f2b8c57f272c8f5e3f0ad307cf6791ebba0b61d144fae1f51b97909066e430de464dc35bf201d09cff3c51dc8b292797901c40672a6ac4b3c9001796e1d04d459ec643431174a41d4e8548f5042846087157c43f58e168bfa032891649483c56b2443a3e9798e41ab6b3d53db1bb7bbd6e48195b72fb8835ae4324d1baa8501ebd1cc9a8e0bfd8db9a47259a9479d9d10eb64eb15e8ded66f3283401e361b891d1d5fb8623cac1f0e9a046676fc331fb18fbc83ccc55e5c5d5b7640ceebafab9283c08e6f89f618df7dc633ebd0e8135229d180837e60806f1f3179c7762fed23f866ce0e84b881052d7418e57950e63f517dd82a9f65f6960b5b9e7bf6f83eb0ff1f77783c408ffbac9cf2c428fcab06e2cb8e4112eff0612199c6fb20d0c62507e86b81eb5d694421e124f738abed414f30f0dd61e4069584f35ba76ea09a8d47f2fc5c3c16d7a1990b892ebd136428b67f9519a53d681acf4e04d1b1a26fe831815ff8ffa180162019a91b76077a04102ff38e724fd0c75fa5364a4bcd0ca8e2a77919d9732bcda293fd2aa46fbee110ff7a8f3b2b4a41c98a6c68e24972a3b5b22f571bcc69a2581da9d6520a6cf59a9779658c32d2ff3690018afaee5b1bd44091ec0f0302de0e8550700e8b86dbf04102e72000b2847db44090084953ccae9efa226147e9c08bbcd446e13a6b987811210486aa97e58b97cee31ef55951d997a4b9bab5000a1ba862d713610229c873a83f5a85a1f9c0751584c6305f36d103c0eac0959606c6cccc53c18415e8f57023be72c9d81b0cc9342f5479824d6ec55e7c69e319ec827d91ec2adb54829d4e690cb589ca2dbd156f18d9ce1e6f88680d58a92fa5b0caa00cecc286bed61fb580041bdea2abe8c48b26c79a6605a160f8f036f156af05ec265056d612607833992d228df7d6b88e3c4a57816442f142d02e7936d8f2341433f51e9f6f7dc4a4a6329bba95dcb59d3f5a5592e728f243734ae9de15769c1058fc48efd805d1c8b3a25dc4d903d00b0259c9ac018625d211f16d553850e9b640932664f4085175c955003bac02afc7eaea1553207275368c992af96c193f04de68653e41a5d357762a16eadd39b5eefda4e27735e1fb167e690c1fee2a0b9a2a102c58c10514f52f9ec1a0558fc5aaf335239dde05fc23c5120f3a5be4934f94c1a9f5acc3145df71c322f7132ad1643e403add6d1d4a30491adc1c148ebe762acdd1025528ae1e266dd194c94eed0bc3002d6a8010d573b1aed432828810c6789aa7bddc012e3ebecf72ce1fcbd18d94284071a6c55dfdf8644bd05bb5c9fb3301d3206eac9c884ebfbf5016d1cd67b62c3470fcb4d26f0011fe25825d5f4debdb12a4f1c24136722a75468bf41c6843d6ed695fc7142aff94f13b8af2f53356b70edb1f79b635d3c3e4789d927e0fd38b127e7aa1dd3903815e25e22d5dcea5ca3d79caf22c24a423f51da80c922a0d369e41b4542045388ca130b43939acbd2834d9cb895b6eaa22659094ae34576613c32d2e7b04836e9643b214439726edd67054067e1bf75fe28e5982954ce19eaf7dab5ffc10eb34e054b3039c1f3ee6cae8ecf5444f21e98def256f66066fe99750fb4011f1c9cc3fdb1d81407042b75772f03e98dd751948a8483841a7446dbbc270143a2b781c7c213f722fd89b7ee14c9933aab1400b58d0e40b001e18748beb9b3f3f103a8b7d61ddb39ddfbbc32d0e0825d848378f95cdf9c4de476badcfe2928778d695b2fc25ead040cb3462c2ac11d08116bf58abb789e2c36cceeea653561a30c782c0d0bad17b4534cf7a74ba54f989bd5827e413b9d8bf503e39ffeaac9ea056de61b2d1ccdf6790581184b9131428a0f5ca97832ea9c44670d1bbf5ee9d59787c12e25db5e0c695ee1b2ee2ac8bccee21bc49c489ad9b9874cb01f7cbbf0555b45758db6d25290743f2f4e3a7e1366a8d4ac01573d8556dfdaed2878e714ef5063174a6f9abf588a95e486e998c6831929e13f7b46ea4a2bf95cc96b8647e15851cd28e20b54999e1865c73fbfd5939a510fe6f7ba119e7cf64e76f57cdab76c2f82c55cede958f3255275f8f3328f944d91", "1", .Okay}, + {.Gcd, "-ac97dbc30d204462982784f6654c73db4bda7511b77e14b1007cf8074d5369f6f4c070391f312dd0fbd45fba7c85a8e7aa81e0fca5c322331b7b04a9b8402d61b4f80eda13aad0a56194ced4c64755e89e4fb7b74154e1803408fd46af69fbf41453a177d49dd675fe1e6a7db35b6526548b4690668e1dd4bd7ab5dc186a71fb3f7521f65609f9d94ba684ac62ea355c1cbd552ed85d70efa86c4a2dae7a44365037a5c7d7fdce85b5a7412431916601fd9e9c1c3f4db3835c4288c61bfd31e1a99db359c320b426fb5043bac043a08bd10c9bead397f655cee911ed19c53a3617a5c00f21df68fe466d852ef44ef32182d7c0b46327b52c817daf981787176867a420d728573f5b34652d6d799ee0d3bb1fc2bb02ef78ddbd48679d2e0f2abc320e5e566e882e63b3f03ce7f073dd3de178773950ffa97155230696c92310ec2f2cc6ead71aec65a17e73355421cb9b654d9ed8376e7d0fc775820129b94d788bea7f63c109f5abfbddb5ddb6ae06f01892b73b85d2f7ed7e426ed10fc9ce0262b3b59f22d9c4da3d9032bf9d3d886f3fc166e3b304960378148f2035ca389c346aa1a4a27087590c04a5ac0b5e31b97083ab02510d042eba02c466b41c652652ed80568e8573bc097e42b6e404a5323dd0e5193af60aefd970581e997d12c842bcf0fd9599988dcf2c0b05b32cd4dcae881baca1ed040cac3f3215f9bf0022a484b6061dd737005bf57bddb49bb3511bab11885c8eea9c97e760dd46e35d1707a8b3f5316316b78c11880979928211cb7b8bd01b392b7e2388097dcd54602f538171254fac335bda893d0ca113734fe1d8f60fdb8d0530e7c26e233154d78b52688d8c76f7732a3ea6209de763da6f3fc44ddef94cc4a1dee9ca86a2ddb47acd71b89a24cd3ae60c6f4db675ca34be1bbc6b14b1ddff7c46e223b823fb9ac4f042a3729d53e7b7379e48fd488dc0b3800e4ce44740aba88e6cea14bc53046d552a69ca07ae736034e810e7b1ed77aeb506e5c840fcbf5906377c3310e365c8024db8c0f7005996b6ab090e461614c4dfc2e97997922bcada6c40cc95d01a6a788957f5167f4914a90425bd99fd7dfede8283ddb07c100d120651c6abac5bccec78935d1448d32207a0f3a3cdc88ab6eda0bf5a3ac18eca4bd784ad966a7f7f7c647a22e6d2b68df7a321c30559290120363dd94d8bb87605b1cd007ea78af3185cb9f1cad374289db0d8018a086275a98652c434e7150139c56529857da949909bc082f7dc00b3f2888b73c25a8912fe21bf80d305b8a1f9456d909d3465f597ea59d40806b8de50144f3b003216d26e9a20235f7b859c18c32a1ed5f66af9e8e3500c443de6dbd8bd236d8300c21ee916b25b68718e3ced4a2fa515c1ead2c481a72928d01b12cd4c7b006c56e5267b4ff4f5d348fa2fb3fd8abad3f296bfaa382148271cd2517fa16360742c35563523d5dc5b66e50b928d2ccdf8d2d51e805316bfc37915a4887bc8a9098bc8148df552c55a98627cd07be80afffc68a667d5dcd1353b4be6276423b59eae2abba507d01d3dc8f1021ddf853c1354d4dfe5add8405bd3f7d287b711a4dd3109d3a43c1845d16460da3693d430afc737bb8bb20b6ddecfaff04461a730a3a053dac0d82bd96d4e3bc6bc1b7f0752dc86d3e0f9a4f2bf4ee003f0131627368d6549efe146e0ed888e2d6323123e943a70ff08f07f8e83ca20669f7974b7698448aa73d7334d03218bd08dfcec7a4abbf1484d0e5d32cf61ae835c0fb178f36cdfac6d7483f3dcd02d7c724bcd87fabd325f6202522392f79a82081c5ebb49119a571438097ab47d54d3bac04f1366e95a33dd59226c466faf3e7a771cf0241abb895dc2a44836a3b9a9e09fd63219a3247c91bf3159b64817f2ac3f5e8059805e8299d25ed72dc11ffda57eb0d27c584e977a45304b537fcf71f9788b65ecd3d3c456fdf1d9ff7fefb435dec7ca11f9a6bd2c2c499d53b05cc274ca47b3bba5b0dbbcbd1f7522f5522b9753f16b397ecc9c28874475d0c289c686b3ce96b789b5202244009b1b22eeb67a5961ee1fd29b579ec7f6dd177c7bee18ee768009aa5324c1603296e43f1f2d642b0d96", "ef423fd06828986a65090ec8c7bd8a8993b6f0a60f047ac46df82f39e527055d50d1b1c5c49c3570eaa68f34ad83d222a203df55521baf1de313916b6840ca2383f4b992210d881f243250f315129608501dee6297927586ef9fcaca07d7b20fc2834e319e195448da46d3a9d049f8dbe6d4d36794b45d14279e79c4c8db84951894bd944e801d4e7756b1bff54ca6035d38f24d39a7c16305e2a1721ffe058efb2820fda051020a6d9cadbf8f0cf93b9c4be9b1e2e851fa3d723477236c966ae58d49d5573715ad54fd23201c67ef86594bae933e7abe4a06cf41bcfd50fa924d632d43c91866ecf70e179901227d9d693039553a3c5fdc1dcfea4919ca1d1740912cadad4b0d0b817b98721cadd145cf28862badd144af9ea1052f8f143b567a4fbf24c9395e556fd921a98606a9f4b78cf8e22d74fa05b3f8b6fcca714394d7617e13f39d747a9c1e3731893d4c6f312acc6a4b85726fe26ca4a8bdb0583f2b43d555adf2370b1cb549f87a7edd01a00accd48cee30e7650db8c47458119e6e92b9defe541e5cdd901ea3d1e5013f6cb9e54da460dac15fb5c5c01d3c22cd5024a055ffee398623fe572f0919c2f084e6c74d9c61a17bcf665649be04024154054f4eab70e42f99dad3ae5c5563308750d92b0b46f4f1057338814439acb6eaa51c4560a4ff5feccb22fda0e72ed9eb5d0672a0b2e0c13335d4da79684c072698b3ff56783804e19386a1b17797dbd6dcc9aa3ad5b3dc004b5280fe7bf1c290fe7dafad5254796c1f4d3ba7dff0d55d042ad91d3d0f06ae193abd02537d13099980012aed9905206233504cefe099bf6f9717dded7fe7e1da0aed7d4be023ca88df26a446a7ad11c7e08cdca2893f96a7f1d3343cf6d277305caece637a30832831892d6c41d2353f1283253f50488095ba6eaec617058c4f8be271e8b46835b8dddc3ceed800051055c34f5146974ab2df013e38e8fdf6038097331f41ccdfcd3065768cb885be73b41ff0098ad60f2cabcf597138c4016c0e1f5d60f798026226a4445bd36aa15049df4f140de2b61f7527aafa51fba80a32400e31ce68ea3c4591ef99b9825469a1899586792c63aff31eaad4879460d3adbcdb38e2b8e6988c1c62a522dd0bce3a32e986e4c0cfc69c1cc9273b48c518d28a46d25e61dc7511803df1fff62db92ca61821965c6eb69c30eafcb22ca865c9b2f168d2a36ad3d05e98eee931ab8013727a4ca4408390768abea532592e3e6a9530bc592044616945e48f2f02d535472f24507b56372b13ed43df8f4d6f4f5b02e7f385a87e3e8933aa003e24c4d4a4336ee95e1d577c54fd5291b2a98b1bbae951a1277a803d24831200901babb390e43583e00926aad64572e0fd50041476f2f417861474768160c7adc657340da7a2bd94cb1eba191089dd97cfc953a2bfe9fa28bc207f056b205c5b5bb5591f6df084847b46282f762cb77cee9f9529aa406670e29267427ebb3f3a0cf3ed2304be796b422de381f4103fd71ff109cb248fc1cc642afa9e0a716288c1880186a0217eeefa9c29d4162ca97c0f9e39987c39acfda7c560941e8a3aec509fa3ccab4897b2c0639dcb83b2b6a67aca215184de3b8a1d5c4584b4d65f0a9159ff5842d1143a9d30381a1b4ec7f09386fcee4676049f57a2235ea30f392abf9f843b0d55cf6a2de1679ce83b01c187253ce86b32336f2de972b7dc59153c1d2ea36d529d1d5745b6025c4cda3dfca1cf6df272317cc60d157e145044c708b9db82915b76e5a3577a5f642635eb882545a62017d42be61314e869ea2f350dd3e2dbb7b82374c586d88dae890f7b39090eb02acf88b12ba271563f676055381ab5cd0eb154ff37c08d55b6b95b1458bda6b7ac220ad45b0d86d8ba93131cd48fd7eec2ea573867551bf082821d3ffee14617fb7f7709fb8482eb4dddec6e34af6665f9a284da6a4c7f10309bc1adc865cc5c2b7877c6d3a9e1d322a79ad68cb04e605ad0b6e97022a6c801efd68d275563481823209faee631794df3c2b9ed229dece01240de4ab469991359b80ad2e921892c62b3f1dc9dfd42e465686e445a31295900df3293443a8f4d17aba85206e2f7e4819a", "2", .Okay}, + {.Gcd, "-1fd59beab54243960332a8b1b43c2c3b2d3afd3136f4e9b6b27bf3ee6cd443e42a8a4bea5c53628562eace44f1817d85d2431669f18ae9e36f09c0bc0e11fa4c8a57c0f290560582b6d9e51472cd1c6eda17d8bec667a0da48679081861d127f9a05fa42223948932ceb00248e425d9f8d42c3e56cd9bc36bb8d7f66184ea3f8d99cbe56b8d6343e2e3ac87519849c98a10a10433501d702aab684c124432a88c8421b235b7a14e133af393bbd6efb0bb6f445258bd3ff74d66bdd23e819c6afbb7f45030c973701ce088341e58a8719270992606b1870fb782cec3082476991d6307543162e57f731b68ed39ae6530a43d1e4a4f064bd2703ade2a87b81147d6e0588e122e260201d5781b7aa9d265f1b7021f9cfc7d1202d2ed0d62670ebdf4f5494f49e3db010b329cf43a23a7157a256cb48c37728855bef00535927c1f3200bea83c40d758cf30054e518fe7ae4d35e2bc534471627d6148707d81adda7b97d44a0d677743420b3ced4790bd326b3d3c05069ca3e81cd2d48a16398a02ce8cd21267f0f93f8ea76cc79171cb2a5b4939ef94fb6fe14d9e3fdb99660af99d6d76f534e133b40ec78261c65205b6a42de832adaee53e32ad3e2df48ca3b0a966a9aa840f7e673f3d680a7212c3ba49f1afde7773c4180d9d65a5eca39e72fc8d7f39ebe88b178fb7717675721c15796982c5f82d9c82ad30123b77373bf9bab3062e97956e52210197421cd0015c49cba7ebf84fb0bddb663d3b7957625720bf0dd3feb8bc4845cdf36bd1a9714e9027746ca8235071bd8e891a50f35ea64debe0a35c48785eee306932ca53bfaf6dd9ab36453050348a85a17a5d29e08e1c7096c250e90bea66cec02a2ecc0f242dc508468729b6cb308a193763c9d17eeac231c9f61afea9db763585f5d21549daecbc8d45fdc173079f257a65b54bac841e8f2141e5cd1a8d6edd69253fa1066a5a5a58835428de41d147c2d51b1b40582204465005cf9f302cfac6bed09782bca8f96911010df2f22cdd7e15654c201e55eba1b85988557f8a57017cd03f7c6a06f388077835251c54e2dacfbe3b10a3f1534b5f190f65fe6e19d24f452a000c38516339f9af4a84d8b9cfa14cdf15b0a649145d6aaa07f94cffed1002d13f446874d6ecd8bf8e63ce0dcda8a26958db9c8dbf83460447573b7076982fad04a6c5c13d933721e28e87043d8a30f9574b448ab7c67c43bf5015b3f649bdf81e8720eaef19acf7a6975fc825a7b2c044e8464d6583d3a0d63c5c63c5dcd60168faa51e2653676e6770ca70a44590b7b89a7ab7326913b2e6868b7773c7c59e2c226e9de1b5d3d6f200f66676e0c42351a7b565c87251836d11870ad98d71ceba700376aeff0464d24b3a3ce4e91fa8cf7bea964913e92d177bfca477d74efdf94f614873a554aef100f293de5dbd4cd131bba4ecbb684ebcd6d506719fe23980d9efd3723f157d9bc54b95783830a2bc43d74377ff6ba15fa0a2e129f9ee5bf9c00fd1d1bcdee4126d1166a1f0291fceafe5eb8b3de6847d70d7a67583c89cefc8231e00da010956da34134466afd7789844c938902f9446fadb485200edc4a285c674d56753aab80cf03ead0281592ad80d6632429d24626d364aeebfb7078e7cf45f9a0faedd8150abbc73f88e063ddc44cb23415164d820bf83fdab704ff562e2c594e9522f498d6329ab2b13e5a267f9c9ec4a0d41034556d06e97a6017c429ebee42dd65d108811bed1fa0e84dc168ec8fdf6bb90d7d41797106e6793e60af0880fc9a1449c54c2c3a15493a13eb9b3c7062494412a774d718fb63a5fd82a0cc3a578d2c971abb21ed9e0e1d9468833a06d827f71daa4efa5341d29e42624f6626343f3709793a10d5bfc28f468ad7a9cbd9309857d8828f58884be66cef844f65d519ccd09b6352638765640b0cd912a8f56328446b3e1c1313da61c7765051312f3f7d6eb541af41f00d368b7b6fe4a010b848c7d7a26c3864d36d9e4c5c915cb1aa38abdbdd20fea1f660758f56c17a9eed23c30f6ac7e575a0153fc163d2b8ac6143e304b46fa39d43247458064066a232ecb7ab96737baf21141c47019f761ce9ce5be057d53b3a", "816d2718a868930cfeea3b2b12d22453a4347b128f19ad2f8b4182b1d6986be78c8d4f2533c8c30229449a97327254fc7444fc8280ad970b0654ac0f192cab46ca2904c1be8e03f9982c9219ceeb55d1ee47c1a1c5933bd656c15c75983ad4c374bbf67d2626d583a8e36517b982e10c375440b2894f48772097fed75c73065d8b5aeb63ab9a074315041bc7317fe700510e1b30927d256771ee855f04019bd24193a64567378b6fc9db72ed05c2bb2c1ce45aeef09f967133f479c21ff0344b87853bc312d9fe789d429091065bcc06eb07c109bfa39bfe68449d2485d3ddfb520e80f7f95f33503c02a52a1594296557f34924240729cd69b6fc42a7316acaed5166575a33457fee132898328beaf9a143c39964419fcd9aa33778194272cd94369235b732aadce236f6453837ef78e2eeef7980a37ee3ce389c3ab078bbab3b3de4d423b908ea817f42612b31626978f6d83c2c2438c41a8e2b8780e544b0a06400503b9a5eafaeddd81b0e5d6cd76f6cb6a22edd3f7000901259b0c76bf1af0a23b7821b7e01da1fd4035dbebcb5c4e9e20f0902b0158e23551c73e8e8560a0f3d24fabbec9b91c8c61920796ef0682e871b2eb2089e44eedf847b631cd3936b9cab0344c5214cff33cc719d262c4903fd32dc7468a51d9e20c4155016aa1898554e0d9a237aea1621883a4a2f7199579f29069f3d8003cb2f027ff3487dd9eb143f276e11154c054d3c25b9cb9a4b19ed3d8321290351d70e290257b38f6ceef143ad6362ecbbee07f7cd076a31fbc56d0ad1bb101377bdcf14acca5725e3b25ad02967f5cbdb6a92431ee50017d71d4050ed12c288c10e6ba3bb7d4a0b391378bea3740944e99cc914976f0a530e22616becf0573803ccdee23b151d12458f91a2d887a08fb77c0a237f081a59a986f298177e8fb0c46d9aa086ccfe93b93f8a8d187ff7e839ca2b8b931758afbf5163b4ec0704b17b14db4bc40602d2b0c5a962a475be71393c1d90eb37a1c95f704b65d981b093ef2ad162959f3636416f7f856a440021626fc8f9ce72e8ebc9778a628926e69f1d4f7074a98bf53c1d4e87e62bdea445b949655effa3e0b0111b9f475908cc3859b9b9d7e0213862518dd0a85bdd79dee05b2641bb9f6e57e2cb7f53179bc270f584ab0d1c2ae05655a70a49c13b843926be936391ece5373d8d52b8b3da1cbb820fb40172834d378185b1cd7789cd3c2d134f79a6184669d273cdb9c1540bdb70931d1d8cb2e54283e0e31d91aa60ae8c155a32292a50f36742df4f346071800c1967f448bfaf240e71c958591c35de9138585504f341ec8d11e3593735441e3f5ae7d057d13f00fdec9eaa1ad9ddeec6738304c60669876fb8841134771cf588f0c9bf9aa44f7a964c122d01f8586e99dc1e5f3aadba2331bd178c226aa6113116a18c509259775d3cc73f2f9a24b29913284f3ae72b4307d9352930c5eedbcb55e7bddab1e33af74204ad6f9869bc63bdf7da21aa4ce34109cd89cc22cd27d1bda48a07e42485a4aae354191042bf3bd3429e5d6f1dccbb03f6f1db582af82b5c868b64baeb277f21a388f227cd3b6ce43a03c3fbdb2e82d282e19c1cd35bf66542e97a62a1cad265491359ab7697a74c132696b3ff5c4248a942fdda236412f62136e5278eeb46b6a0778ee95b5dd6595be5ba52eb8d8b8e63eccf1e02032e40cde764f76ab93ee2e33007b4b2e11fdadd245bc03a55d98bbdd2e242d20cc469708527e0d1d8199959a8fd8f773c039743e0046a0baaf04bd1a8b6958e2defde15822966e9b16aad7477c75130c3a88dc94fd24d44416a61370cc8f5765e2c9b262a21495fa453f008568bd6f09b2583d11c21216172bb34578018ba6cd9f7e10a2ab75920dad50ed7ee8d7df6bdfd8c1123ec2bf86971019ad176fbf0f3c577b4d04c9e9c4255811c27ff015b7aa6171625b43ff19b9f6f94428f9cfebd7d43fb5d892eaae06e8fe6380f3d08ade3140b5c20c0cda64e1f8c86cfd83796f59a760610bf19d856aaa248430111c1145535bd30bbaec4bd4213df6380a66ecf1b68a2a55ec17f3ab39b116285828d288fc33684e4b622cd262163655d0c14d2ca7a48", "2", .Okay}, + {.Gcd, "fd7ff60fd14fe85ed0356c0128875c384cc23ceecb90fbb9bb0ccf962d52af4a383c15be7a8a64de59a7ea4a427abddf61d6e8b748639f9925fb644cd2ac8697c437058a624da6a00469c73ea03e7dbdbfb69698b9a2023318420978d3a6c2eea86164c97560827dfe4b050bf7dce076860d04dcce8a1fe90d83777aa6734173d0027edc20b7a6b727dc78058571e99a09af835371fcb2ea10fea8acec704afe664f87a761395360f9f9fb11ed8b5594b375814796cbcf3be62174ff97a73aad0294852aa719484b154e6d4bf6a87adc1b19feb902901538d572e079a99c3ba6ecf084973b059cf4a8ac76d9f75f1b3d3ce425511b6c51fb6807479976c0e4481e982e64308ba6953cd176501b3edce34fdf750f32e8f394e5e83259ccedf2dd01f831e8d62735f4363a8fc4245e67797a6282862c6132d7bc7226b202bb017882bed89bdd43a859204cdee2943f6d587cfccaca3a9c579665205d9240b6cfc057271e4f9dd5fed8eedd10d154e3ee89ed8b383716f5954df7b2a217b4049c6e1c96f29f3dce6ee7af24f1b582650c5a0ebfc780d6680ab463b5d2aa8accf3c9b57de9739c2f46fd0a9fa275869a7ab2700b80082e516a52185fdc4949e9c81be83611132871c494cafdf98fd186569aae11a449eb28512dd0ac1e75482bdb4fa33d77e8f6d281d0223988817073d36385f19f5ad7c9bd2082c89b2d3a77a02e5c0ffd20a66936645bfad7f468ebfc2ab06db9906eab88881788e7a328402be6a3c6e069e555a64dd68f4f3cbdcc45b09944bf3fde504ba7b35dc59aa2ec89d9c7bd63ac6a942fd4200f312e717fa51d258cd163b347fd9fd7c49db149f45ae0738eb8afd568f30da04bffc4313ee6dd6a3d42b286ed663132bb97f2fa34ea82385a92bf2b37dea08c76a64e2e5deaa216f6346e81abec648bd5199f4819870057d140cff4c02cdfcd8b9496fa94fd0b9652b1e23aa826d17416d9bdb641dd926fd0beb3c0abac330fad795fe5c6e20382f4831f3376262fa172aff814c280cb3a8adc0653e6af282d74cf51ecf40591c33c5adf5ddec0e4f80d9cda4414f7967199f6632ae26f2b059b7c71893ec65ba18a4b9fc35fc9eb21b8db6686d6e654b8c3fe920f33fed3ae2281f1b9ce68ef79e412457aac0e916b835a83d26fb2f3d27d190cce1d469b15d292080098abde1d95d6a6f41b8afbe5183bc86ead2f4d1a74ff1ef386bc19b4d402d1d295518e17a41a7a8313d1e1a2b7d8c7d2521d3ad766752957b7f90a542d442aad22146104e9747ed247c6ca8fa0abc4f873bcd1e2b9e6a54097c580012f944c5c903a30097f79025f696bff9e6f381c30860daec41499ee451ba52cc34eb85d7012b16f4052ab580f54a997efabd368e808da310a8869cd43ced142274d77ca49835380eb6f8bb0b5c4776831365acf166b1d85c9dd7a59763f45e50d3b398288e9af01648c23cfbb46a803e8293fbf7dc0e68df3d0f3696e9c682ee2e3c82a3a0d48dffb5396e0695b94ed16fc0f6f0d79efd216e7419eb53bd6192c31f5e3a3111aa9deaf558809f1fedc6b084b7d7b073c0cc6d7de9734a1ef2dd795853efe9c71b6636994db17e09da34f7d728fa05fee824bb720443f7be85e1867b6bd668f503d8b3a85c929bfdb42509004e0fc68a61a46bf0e8c223dd2150515dcc0bcf75593ea5f9a9c35278450f0a13ebc60df14001e84739da8917651ec54abeaa6749dcec8789d3753aab3ba4f82d15d2f2a168bf1f50706763eaef7ba361c151e65d6376c0ec1b6a62fe7e312122e6ff30ba4b41bd1227d75b73c3bb2e8c753522d5275ba8c823d22cd544841a267348b57ce1e863f995d6a6398218e868eacebfe0bd19703400b4126b0360d719e61c71d6682ebf8845b687aba91cf57843ee6e1bbe9d5445196e64fc5fb9a063be364effddbf9007d74796d8169b8b62cf8f8582d0cf49cb9164696680dbcb39bb62100c04575698760f4b4eb883071e29ae7f0bd4e5d8ffbfcf4a1e52929ad3f3a8572682d166b4f3ef699d59affd0f672d580e29843d7ed270efab79066370aad89e78f2765b1841f582b6cd7740f5b65a4184c83f44776cc0419efcff20ddb48", "ef09279c4045fe8689856bd6beff6b25fcf519e7cb87664183a08a1fca5a0e0f10505bb26fb25e7980625330b9ec8733166dd92587e0ed38bc344d35547e01134c17dda90eb897a1b9bb56b509fed488b110353ad4ac61cbcd19cde51d2b50df11352c7293da0a57f8e7680c23411b749ceb1676af0eb26971e401f72ca3115baae0ddcf45d963a41182a37d07e339e996f6d470315f3fa5415749aec6e4b4edfe818379dd3dfbfb4b20dd65d2c762190c3691e9db72a33e10b5450860dcb1f7ae96e7234140cf87d3703c38e368662f9c761739c8d7b42da7eb6a3b49baa88fb75de2a1ab3b950d12ccf21d61926668aa72194c4013489db954de75bda4147aec48da30da5e6ec7353e6ab2b2eb4048d42e33b601169866b9e4e687fe6fd7d39485d63973a7b82e4eb7a695c01925e77d1eddcc2d4ee963c69509149b6f35ab4aad09210ed31f3a9e5f9aa10e960e635fb9bc3380264a1c615624c8a53ac0321f5f0be210df457ce38a37a42fbcf21e38a9b7eed910040116a72becaf47337ed830f333f9585555557a4bcee22eccdf7bc5d4b846afd0a1eb280f2e00e9e466a612873c309d6e1d9419588b2503ef38ddd077dd9b6e42e62c4ef57eb3b4674712fb7ee07457a6117d7999ba5f7d9c6b358d60418009d69e732c2c160fe1430fd87d068683f4a87e9ee01e0148b651bfca6aac4bba3d837eb118af3d5d1c1e4dc35275268bf75b28ad3dbdb70bc28e718ed9a9ef0812b72d73a936140c1c3d5364355d11d623c05b1e97ba3691464f7d5d4810ee8106aa6586878cd619f1987322a131dfb9cefa1b125b2495655527dd44d1e77d2bbd009837904e36067bebb12e0562d2084565d879c5b7cb0ec7b72d49cc20dd916883a7cdbc9a734b15c151f577b8ac177612a043bc323bf854f08dbbfde5342daf90e8f4ebcd73a57cee0f788a4bf10cc858b4523be68771e78c0935e02f7998f4e211f02f7135bbf4aaeb99c71612b90853ca48795910ede786ce79677c436987b07e63d945c53e3ede746845e47d11af4f284efc91b0d651b7c2d309beaa800b04a737e0b8fc474e942cfa78cef951d79f9db409a6d789ab424cc245cf59f9885ed21c801b1cf73b406363365bb8efae57a3ebe5ea08c1c164bda264c85197b7be59eaa8986c48036050b27fa3605c70184eeaacf50fbeeff7027bce9cef598b297bbae7a9728515e44ad35dce319a4d6e84dad808132f81d4ff55f1736fb6cb0b1ca1cbdeccc2a9f9f693d5a1a412bc8f4af25a6c85f8c0bfb9016d07e73f6514d0920a218781b64ec831d2783548e85702d4702aa3a788ef59e0525f0c297d540c46fc0914657a78b97fc74b8f0ca144b8e705621a040ed0da42276151d294a12b634f8f9bb7234de358716bbafdbb77f0ad4f2f87415a89e66631c10c4662ccf3de315884bf7f5dd4ef1dc274d1b1a47db5864b45fc3e370464e20c41febdabfa1d0843f10f241f4f0c8b90711e2343f3c3b0b3494da882127617cd4ceb8110e1bda49dc71a8608a4af665ab7ac181b1e81208095ac7c09be2b760b33e4ec4634c95ac1ebf81c52d29602ecd771302043930d299a49f439fba375d43c644bb3b08cc571bd812b1cd81a62704de490db1862fb7fdf505bc455141a9d57ae903d2d0d95a6da5903bd450e82bf756e3637d8e692704bca8c702dd20852557932cefdae346b3c061d19a6416cbe9f43ced3c4d39cd64805e4c7cc7453da294878ba245b3267ef72e0ff1f27038806d1f257729216e26a9123184736cc546d639ea18e5f2712be47618e7abf2edede0eb3d21879658f97fab6d097e652bd119217d1d45a18f82b0933d5c61bef2a93e90d12a1692f2286c79bdaf86b03db14ab80c5d9d2836759fcf1ddf20cbc58f2fe45ab4d13e30bd4811892746d746a3647069ca0d2d6e496b0eab8c4b10b91bc0e10c009852aeeb9134921187b2718a17e8cd6610b12e4ad56c8814d60e8455e3756b50abfdaad1dc6db905bb0bd8e023b6c55b37b0c855ddf3877bce3c962e6e8251302120f73aff01ef79a71809e688ce0d6346776a465c967a49f665d6a59530daf260bf6f58187dbb10334c8eba55cd81c720250f5a4", "4", .Okay}, + {.Gcd, "468b1a43fb65e3cbea5fc330b4f7b4879a789e68a301a7fa69354f1c3139bb69dbf2f9ed2a938f072f4d73d2492d452d1a17a419d366883d9e22defdbfdb98597eeb494ebd32fb330fe9f0efea17f9a16559cd9ebebdb3445a6c83f46e59b8417c627cddbdd265411fc837736aacd65a8e22f6989827481bb7536e6a00141bf7e7e6c5c785dc9184bdfad5dc610301c82f1d4256e012e89d27b696d23c293699e4883d7267552693371ed705f0d04b2a429892b2bbd56a55291eb72b099a7b79b2d709d851b6bb4de707425922122b5dce6d25b4bf0228e7c3a9246e6d695e99cfbee2cc63af7d5b94a2cd32efa3469905cfe54ed935d4a91aef50bea230e697832dc3ee469d5a5babb8c13224d7ab94428c122433e2adf10b9888623b767b2312373d340c26490536b246677c1f380bf29ae2c1e51b99f911b20c49364922091eb80a5d541cc58822a917162e736cdc77e3d2352976b846590d732c7276c94e68e288b762e20f9b4cba4c5ead31e916242cf05de0c253de2e8bcd8c3c5632a95c01dc848b194136e3c159f41135e24f629a90fece2c66c750314cc47460626af4e646fe0e23c3c215341e8b0c1e304f34dedb768fa9a697666af4aa535c396646870444cf384f2b8fe475f2ca1b1ca35ca90ba2d739d071f6ff7889816ade9ed06da4d6a8ee4d6f079ec2dedf9cbcb6bbf001e8cf7140aeb7e135ca42c4aab0f334aa8043f875ea42ceca9ea5f7ab0cba5b7e0514b95a8c4162d33803018e7e29f4bbbe70433dcd757bf2edf5dfe70287be2a0b40cfceca86e0809f5e5d5c08b801e26440deaf31fe4712420547634f7accc1e5fc308c29ecf0523fa3353e9ce92d0df40a8a7d66c9cb5fafea9a64dc5c012029964f404ca178803ef4078804cd5eccb4710a0a8f8947551065598dcad3a693c058f7133c32d5324eb95a54c24716ca90300451c63715f3a5994cc72390a244dd7a7f9d839d85dfbc6c5a717a3c324967db0a417f1fa0ac0f565c8e2b0808915362b1fe4f52bad90faf43c1ceeae9d66ac92f22d808236656d7c52f33acd350a8a69e6d2494b252d530540cdd80add82ef487f4c66796ff9f1aa1e43dc5771a197a41eddeca63023029a29816ff8d10fd71068bed66da5c2c456460903cda740148b53ac6cf7ade4d1d770209988c40ceae4ff69e48c9b7e62df65338e4e8505c5ca97578d856b2e3956458340c9d7aa2f6b6198f51482cba3261a9a780d5d5a7c06c574e2bba1da3a5df7af9584af717e7d4da80ec1a6ae1f527ae95f76017d6f0d68aab7e54978a88f65bc29598e1d18fde4228afdf1c1afda30c80adf37566c281aa22566b90e2530937f7945e487b77405d8e0398a461c021a4894511399390d2eb6c4ffc58e14492d7a2a86295ba0a4e462b57d638f2bb5840a81f0bdf03a2acdad98650b186fe7edc19212fe421475bf59156be98760f88a3b3fc47e3ca79b95add0c9a4aae44beed2badbe2db2a73b96a1e70181dbe0ca46450d52591bc4721176092af48f0895ba38817baf903d606ad7b42e4540d93d040dedcb4a6b80f78e189e7407d872ed8af90583041cee9b987a338bc1cb76db3499eaa1fc3440b0656d7f2aed5a3aa0d6f58da5a2e3eb72498d5f301db5003123c65a5c148b0c1b7766d71102fac93cd8a5c67296dbacbb09145273575632c0fb0881a44b558ea355dd83f14ff0bd234470b75ab4730c41fa143374e707f7186a0f24ed85c3fde7bf594fc320592c9af90c2e82474414d6aa7aeb6f1ef40c5420e6665415472787959fa273d2d2cd4cd14672911b55dc7bd8d4619d16898d55468871cbaf24a916c411499657de7059889b8d9ecee5c8d6b259cacc2d05085c292d50ad2ebc37cf647e172b35375c008f0bf7ac354428030e7fe971c3e5f7cbf65b27f856983f97f434cd99a37fd94480e9b3c8921e11f593102cc6e0d7fae20cc36f7e08e4281245af8ba79adaa702f0297308d2fd73aab3537c3e3842f2e0dd14c66a0dbfdde351bb76f9152bb918009ed27b6d30f58cdc6a3453577785749ffbe76548b9702a481ad2a1f8c6bbb7b7debe1a1d70cc9cb26ddee4a4e30d6ace67f4145bd7663b2efe8a7bf1b5", "e73682f95be877ae54936b63f76e74fe54968920fd061cb9b274709aff0a20742744b6a6967d18e04710da979c143126f39c6ecfb1a9a3e28e5f5517295a5ac5badf1e81be424cf2136dfb4bc9512234e7e4c99e6053bed7eb74d1aeb29baf2c58bc222c95ac3a96bc30bab1e0311bc9cf3b97af08f4f3977fd08e8d4f887da89ffa029d18ad15d447e48c3e2d922b198864e69055152fcbf25ff0376ff1d7283ae411a4407d8c728574651a4c39e71e0bfcb58e459a50771c0bc1fb21b6219fe29a8c2b220ccfe61c339382f142b9b49844c986d89540ea423dd687b87c8de3fd033e4fadea538822d453038974a7711149e72f77e1e95bc75c3a490733ffb3918632cff93e8b4787493ccfa59a854a316a48c2fe7f10245f9ba63d27fd7cb609faa45eab3164ac2d450f3a352403325c94dcbf60bea9fd2294f3804dac0253a98a1f066f19d7bd60d3b8f3096fc33efff8a31dc08671f5a155fc62d2055f91fdbeddf9a797dba537c4ed7ff839ba36f8019e055966fda362de97074ad89d368d824bf7d01b744d0a393292a81a265241d4564f5af6588dec38cd4ba5ae614421c9466cb9f73acffa551f2bf0fecab3c54523fa1741b19ca787f7f4941b20215080a225c07b302a43959b810c02d98b93af467d226bcfd71948fa17c9641b5955409c30e0cf1cbf21eb0d338465a8117366daa4596eb3c360779f13b3eb71f359c6add1ccb2e51c8efaedc5420eb0c2dd99d4bfe2c8a9ffb39b51af8974a7ddb1ca008d53eec38d9ae0c3977527caa612cc593748113b5fbaa8f4817bcaf338dfff4d8dafb152b5d1b58074bf62cdeb97cba3ed10dae9a4c15b286a317fa25f74555d3211a7ffe5368c455c493ae61f78f68f8f71cffa412bb128eadb208f8eecb0b6b2496e8249a5f5314ee862e25bfbd494047fdb8df718c1558e55bb0cd93e224c3cec762c86f7bc4a32abf0d859d39a01fa16b1c1df86bc424754123222f817fc5d60093b6c4357e487f9cac637810ab4938005c7d855c4dbe4bc66f84567fcab1c79b88ec37810240dcb857b3515290562f00f725a0c5477b349237f9920bec5f885548e6b2cdcb9f75f641f869f73cdde22d6c8f5994ab6fc6a1c5bfa4704a69f5d4eb297dbe8506bf904658926f0b672024c582ca7ccab781d38b7b384926fa99389df5d1034e45fe031671661ea3e0e4b01f6d866bbd3b9b237e579ce1cfffe092e1547e3b77fe3009fac513f1af36d97faaca8d497369401ecac7f8ced006a12c82f4f5a8d48493c80f910e9b470a35042a93b3f245a47fd95e4649aa61edc06882b0bfb38ff0ceebd69f4629996d4c96fa1eeed1a890a9d661293077afec264b284f442d133f038113d4f777d99c72f444500b9de57b90f55734297c67c200b1805a2f8af3ef2fb5b79d2ff4de1938275ea3d77a4bab0ff6bacbbfb524fdb614ad4763e72c116140ed5f1d3e1c3f9abaedee7d2891d06b133e6465d2c21dcef6bfdc48046f2adc4d5b4b97633fbbda1251646291118cb85baec7f47092e3af64601fe5736fc9bd2735f0319f4ed91543f1a26a0b2a2a3d0a5f17e8364e745822577d4d03d21d33ac0fd78a8fb163f601984df4efca8a6863790c4f9802a783a6c27abd9db71fd6c130feadeaa196debe0bec25b18d47140bc61232b48b917a24f937c9836d771bf9e504f7becc0e99bb7310de21c24c478bd551cd4371892c3f4997e771240c936ec52659414a503dd65797e2aa9eec8b7c9fa182a26fc884a616c1a8555497b6231bca933e0b863318c9c1b873e1153a78fada577b624e96700a6603482d14ea3d2e6ce81e51e414f1075f375251d27a18a6e33dc6f366026351d03e9bc5d6f2b1231fa3207c5626dc67d241cbdd4ca1433505752051d7ef8fd7b13ea73778822f2bba2aa19ec4f44fea9762f0dd2d7c8e16cd34f72e7ff2a3a52d6c6107c5b5dd90cb949284a04203c976080d2c314c6d2572c88a6267ae758c7b980f8b18f95dc59b02e77f33476212d6b87db682f984553442f866eabcce1b2f58ec8d7eb78cda4f75c53f8f4551e5b91a117095a813f2cde54bf26b4f733d854bd80ddac0313f749a6dc0e76d809ecc4a5543337", "1", .Okay}, + {.Gcd, "2da8e3fa7e0cbf3b6650dee7fb7d3da57ab42bb3b8ec0cded4558f33faf7ed901f3c83b4dbd9449a616ab659aafa98248b75419312d406c2fe7e473259dbb261545f98170f401851e1d1f43e91ba5fe36b53caacd23e1afd566bab02c7007f1273049524817f49bb77576b416a8177fb505198948f29932334730252ce6e3952dff3f0b7a04eec1447554dd2b69b65a587964d3791868b623c94fbbad65f7ab784c5e643bd1bee2d14ab0e80e48c690cac5cb1e7c243469318beb0b3c7160be2ef87f6682bf6bea60e47ca9b989de226db0cd5bf8d12a2ed297eb636fb15cfa6188cc425adbc2cf123e7e851cc0b2a669313bab0f5d716fdc4fd8856133e20f1f6b1b41ebef2246d909be4d95ad3f3348a8552e376520a1991ade87272519de3b70e17c0a04fb87ca1615a5d3b20c5d8d0fae72bdcbaedf6cdfa634b9ca377ffe5ddfedc52a058d529b6c4c0485972821e2e538a75f08338afede137b4fbe5e5d0f3df23db752864732e381fb0e0def0e6683ee0161045f2f5a981edc1b74e4999515fc6901049a753865be8eedbec01f69e2a13f9fa5cb3e4fba4b2e385baa2482124364c847f1c7fed703274578feaf487354889d0ac1816e46fbdac615844357d56826f0f21b791c5fbc88630d1e4fbf8419b41defeca0dad94783afbc5fb4ea3d2966991a991c68c3e90422440de1994eec650dc837d585a3cd6483ab6b0bfa8d1912597800a72e2549f318fe57e42aa171935a82995bc8d049a58622f9cd0e1fc6129636689f9625d6bbc09d1204f04c166c703ba0a17d0e2b259b771267902ea335d60004fe6f1840ee602de7420f7ff91bc8423f29ee80817d0c793dd68a6c30df80bc347937dc54a18fd98d475f6f22b7444b32106fad741c27fb2bba9e0c804cf25c04bb00fcaefdc8f050e9b5b0af81523e23777c2185544c6fd8e665274b34de407b3294ee8e273d7bd79cbb3f0e0d0ed85ea482b4135e8b1a97844165568d15aa0d25938334149d08dcc57fa3d8bcb8846f18768f75d3b564cb559d2a4aa86087d15d78f61ed6be43460b2c1e535a8c08ba2595251706e1f5079dee68299f12b6c8080adfec428659e1964ded56b39ed6a3c95a632da1c5bfd0af79ace4fcde8ec773e3203fdb06f7c899df0b2477ea7c4906d63c01128acdd14fd55e1218ad524307ce41cf280142872ff0d5ffdb8e86be648d36befd446a2c908ea319c7c5e64eb3baca05535642ec4b2bd0607923378b8186dc7ea0d6c08b3cdacbe57631980d7cbfeb79bf8f2a8e6268e5680fbed8821a3f0c7130ab934fe10c04d9427bf4b96d1a2717c10e96f8655c138e5876b4f2871695731732b63f15280bd728d84b2965dab900ae50caebe56497ee1251d9c8c46b4dc53ad99a3331e6109dc6f05322482ff4bdc2bd927efbc6607a11bbee674f17c8f6f4d4fd4962b1e4a8facbb108594b5a451adc2c37cccce2e5ec1b3b5b2d39ffeab74513339cbf1e8717b6f861bf37870c058ec76aa6ce1f8e4913a1258f949da4ba2d8dc19c961352891e3223f1f2a76dbe1e5628e97537f04e5bc287c85423b0385ecc9a85fd3962c307aed456595e66c4299c06c767c588a8d6c476779d1733c193340fc0b42b3f9ea8d16164329147907629e68cdbc68717c7e7598291850fcd6895f355afdb60b1cdda09bb522b17d6281502bf933f7dec2eb9efeca92a256878d7d5d8e8ef827caeb4c9b8dba2237e5c7a93510bdb3405d4beebbb9428a17fef8b1931e13e76f4afd9dc9d214849b46fffac2c6253cfb61baf0205ee6861cb413efb2bccd7a9b5bb06e653549b07c5d10baf525b368cff9145b764d82cda4e877f360d25c97dc7414d7eddf62079eda9731ce37e99bfad632f221c1456804d86ebc87cae06e2c5e9204a916ca5ef436e8f49932f651756b2950e59b7a337c8852bc83ee4fc8056dce4994b5f29ec788c614d947725a331292d703d4311c27bc31ca2a1a8c4a281984c6c02d64e252f4117067ccd41ec3ac5371b60a1eb5ad4c6e0e74c6ab29137b0c689a935d0e1054e8774c9bb6ac31f08d5c97aed4937e377ba9561a4cc3777a088ceb3579041f3d19dba7eb88661d409d19e7e6b8a6c5", "45875814a3200230177dc28d197c3b565fdcaef2bc22541f34e864efc24902f67d3eb8fa4399e1d67502ca8e02d1adc5cd88003a387dd959125cb7801493b93ba671179700e6dfddc59b8cc257581a78aeeb2a2edcef8222b13006c1bd15043fb87e1e6992e422430e2d425775c64a1a58146ec8aaa2b56affd476f7d0cc1261fb6328257b6929e7365485d5150e17db4e004af5f7461b229c1b327b9503d290a8ed406fdab011193fd39a7a67a1a7c270c1eb75ddbdae602094986f45661f5cf2ad69c0b9a9c20d39e26369f6fe90760afe41cc938d82d134a8c1d00a18e0b924564a49816678dd518753cfc5e3a09807e16529ea9e7c78d1b68b5fa9e3d75218c51c7a7561ef512d2666a8636e6424c61c6a5f6f24558600ff27bc044d6f3baf558b1ed1b83fdd811de046cc9ac567e5381859e48dbd96850fc3814345afda4052c1ca8647718fcc0190ba1d24fe6f3c25aba473d3c96594803aabcaa60045f39f59065501632cedc7853bc896f1ec572241d69571203030846bed0dedc55193ab81a40289526596ba6c226aa8e85715b700e2d1a66b0bbac79116a98a201293d0e279c907d3eac5967a82a11afe57aaa0635926616109217b7242e19d1432297c75dc07014fd506e41632b46c15f1f2fb02f24a8ef581e51ce4e8e48219972eaf9ba44775e8e63a56ddd67e0e840966555274da2ba92e748266225974cce29be671cd2f7b440e5a96d5cbdad08f3994c27424e0c7a0346168ae12f8187cb10107a0550ad5fa3e130a5e36e56afec3d5d822894dc1afdcbeb51c03ad3d0cd14c6f789d21d06e05066ab30428fe927289f026fdf93fc032f8ab1825914a596801a991f1c36b4acc286490ec91ab3d8c136c028a39fbdd693a0a02865aa712f8cff4faa8ece7f1424ac3707f6830fa28deedf24834bf6ef8be9b80eb4654de2a045aa5b0b95cee28971bce6ee143ec325bc545b9d65437989059c338b0ffb19e17e74ecd0b4502ca010e30bda4c5faef3a157995a067d26f01ae25eb8b9423af8e19a7f98977e974de3f7aade06d0567a111394f67f932275dfb17ad46f3c2e4a2433138c783f36158003de203d0d6bf6ce0b0fa5bafb39c4cefaba8c49b6dadea03f0d2f88673a14a6acad456cf8d2a1d00ca5b3b9d30af3d26d183a59a23780ab1bfe891a2f62644053c71d1b096f31d49d814f2c54fae7c5a7769739eb81611c3904e2f5a6388ffd378fee4901040ce6624bdd8f45888e175745bfdaa088aa50c08b507c607ae999b50b30389423e77107078e7869a1c041a5dd26a4cfc1d45a40518770daa9faca65500b413bb7b699e03b3b3b2457197f8ef255781920ace6f869204514e3567df1870ba2f1a14b5f5e4cdf137ac579715fec018e8b313984f47f9947379aeca90b54a2e011e1655bc0eb4923f1bbfb58656d143af773835b3d893c4665fedf0304b43b11a61500612111cc9aee81fb713b8371ceb58625cbb0ffe069e13ed5ca0ce50fb8773eb1b27ce4ddac26dba8024935213c6ad7c5816b644839b0c66c730dfe43b50cc092723ef30581c84c39b2876a94a70fe82af8d60a4a75d5fa5d82a0f563d6f99f894341d6adf48d45c7c37e6834fc7f7ca6c23373aa5cb2f0695715af1538ef8ce89fdd9dc5af7335b27b485d0a320f573b7380f4715492908fa821728a08b905bc48add7ce53ca486fd53cef0a6c24f7198e16e791b0294cba6a65cc9474ad3ca68351850aa4565f9a89efe8d8c0bcf8f801531600c1e6efb14907969f8eabc1a3a808d908df8e221a104d2beba291fe748662e486a09d29e43ca794872661104a167dacc55b3acf947d05155b5f3aba37c613fcdbfc47e816bfe731f905e52ed0af5eb72573e12676d5b3187b15d2315ba205024ea7f762eabbdbb96fa1e087546b96edbb6b44097566ba0931c0923bcb2698309a7de6a88906e7a454be09ac8cba351bc805a41e06a99aeba40dfc78f778562ccbb6ef90779c64d297c1d8ee435e50a004852e581a8778b4e52414d503b52cef0ff55ed1fd24d223e311a67e40252c1cb1bf25a6a85b382b645283b71cfd4fbc60e05d4df9264569e30bed897dbf63ae27d67cb2e1e01e1bb", "1", .Okay}, + {.Gcd, "3a080aaac24a34c5bc224f88cdfda380e554c7de6653dfd34c9e8acd992d2baff7158b0317f77e85963a58cffd7862a3a9ca41b78fe392b63f9915df68b992a408c289fba602251b31a84aa0dd9457e34ec2882fef503b9ca11b9edc8c5ff31144a46a42a54b74be512511c1556c766e70445d6430bc35d8fdab3b11df4fb00dc4162a0300cd99afdd976d2e978ad9f1bf403974de15ec68430cf497293c19344e9a3df2f957459bd2c9d6166de430b1585c59534d9eff8fe51716ad0ddc8ec13f542445e872ab13526e8e828ade3e74db146a9d6abab037f2d4bd22ddd06b6cce3c8598648ac6ef45eae47452661022e555362f67bd99597cc1c2e29486cddd0c4852939516b68df16314c1e8d1a87771b1b07013352740300f4d2d7df0165e1728bba687f9414fd96c55f342bff8ba98212eb8fba0b6dab624c05ade977a70571d94a7fefc4af451ff847a8db0dd520dc256453ac2a220b1a5d3c74f7e0224ba3108dbe950d98c5ccf5a10bbdeaffee2542c519bccb94f84fcb93c6090bea9aec66c4ddd9fc4ede7a092655d4788c986994a82e92ed50f1ef2f4ac02cc83c5d3d1823f465656da4878eff2a9f5ad35c78cd8d98c1a62f78398f9414cef2664c4d54923294d1ad55ab55f12b7699ee0f8e32166cbbd02908d4fbba61e054f3aca37e0a414e8cac85d863b5b0ee2185b900e5a4df4c2e3b093919753f46eefab025b8e062f9872763c3f365cb877bbd19472d4a2e4a7cbba1805b7e16416722677d2252c99fa5c37dec5bbb7fe17c28f1d5b1d47580cfa4981484fd9c304b254b1ef998c965ea426357146e77d5227506fbb5f5b070477001f4122f3e779651a4ec696273dd49f04f1f3bedb0c46f7eb18700239c2b469336ea41f9dc359a0669d99f802334430ed785103458822385ed30f3db1cdb0f26f405f7fb9942c56ba7f34d4e5ebe6811506b34a125d4d5294bdf1268165d1187fdb85c3624e88295178ede760a2570e8f0c3e90a07e55e6db04afc0aed1f7e50d0043be0a94351df2b2b0ab6e9e25a24a38fdac6b60f9ea32823e036c70c9989cefb82e9ed3e0c7a522b3b4aed1811c2f7333679160220f97bd8b7a46262c58d3d0f4825e1326d446e637db2bc9d07cd9a8e3ee6d70c41d187c53dd87ff4686316e3caee647e4e0fe8da444470ba60cd52af3b5e77f2f5f0f623feb1c3ae244353a3ee2a37fad36b159aae3b699c284ab07979aca3073c426d8122885bf93f3cb6c5c610d337b799dcc63e29cbdde879f5e9fd5a2d7612e3cf4763a053ee89601de559b950d035d12bba5e72fa6e09c5ece4c6fcd550f5139faf354db273ab78e5af4f7f385fd5ff9dcbe2ab147dd634edf79e5ec7808fb52f825a7d2f0a7762244a7a232cbac613fbdbcee5b63a0ca38a3f01a7870b191f7cabe78eac04fea6b8dbc355880f9233543b6d0691f2f74a85760f0e178786501b16b480d40a97560d59c575cf355d0cfc4d8825f85dc8f7034ded7800cd1fd636dd5c50ab59cae196c2f2884f3da8f8f5e0a62b868d8c390851c971c3b7bc04279246c846202d966521907ece0b1dd0fa5a709c310f869b051b02f071f485ff0c4061e25eca76eea656c00aef60576a9c4f75fa16763f539f9d860631eca17b76238921508fb47e8421b3166400c805a67d2bd45afa0d431a146a206c235371a91b04d721817355cd483490bffd62859e657c891dc4eb18a3901e74fe04ba94d082caa6619e025566085346d54aa17c63821b64fa6538e0cdd5768e47a94f4c6ea2dea1665deb083aece86ca3194400c78960f32bec4e458cac6de0294fa60e9abcbefb2e07e43bd8794b2671e442c5c94721819f27505e57a90f8e5ef115090f9e8ef3d517969bd45e969da45b5d4d9a4d3724647829ea060dfcae367d4af3c3cb39c7be838dc01897b54330458d0f0cf070150bb88ad4b00bf2d63cf29a3b987bb9c176c0cc2aada85748e9347a1b4b71b5102b63f2dfd21d64c21279b782de056abd360c483ae0756b636d2fec0a85a9e03236d5143ca1925205dfc59595edad57cc99152efbd309ce3b248c5392a13b082bb2d75b2aaa5b948a0d02c9e13b6ae344caecc950b10935f8b", "213b898b66e158957eb3941b182be5f4a913d0a14dfd29c2f012c0a39912a9ddcf924f5c4c4f3b5017fc9076228a03eb87d8348e16317668ab3e6bbef40757d9c643ce081062721218cea563969b5fb7f428cf314101ad8669f21dab7c5c34d09aed5202b3a68391c8279fe6e42a991e01af417035e531d34dc9f3fcbd20a2ac0880d1848fa27e17db601388403121b7b209686c04ca0c0ddb4f0dc6cf372cc8d67481e26fa289a1a34279f98a21fde20829aef384ce81a09869deb75e301d2a1191286035a211c0211fd41657b0cfb6c68980d3294089c0fdb9fd3c8f7448d2c52850892cc8fc3ba0f133086f53efae74b3400ffe33b7f6ae52fea2f7f6ec5137b239eacadd42c4617152aae360c5f7db8a8328e26d9ef59641bdc381edf8033a8acff7ec8e6ba4ccc3767eb8174ffc7067d29c72a7ff2807343a28fcb914f85cd68153453902423d8574ea30568a3d16337a306c0435a7e9e9bc89e0bc6d5e00959734372497d9dc424355bab19b23345fca0c9528fbe61ba89aebad37ca35c6f9be31eb373a0c35afb015d1007d888f9200e16dd7d4aa4e8c4b73f0cf57c27b0c15e1b4aed6a427397f15f61bdcb8022b47c016dc51b5afe6f11f303e6d52f7b4515a70dfdf62119645f4b322c9ba6a4e05ee1404e21a43eecd4133d29b50210693dfe367d12a79074f4dc7eb69b24fe279246c35b61e75e1e583ace5f1cbeabe946bd66e508b776056b40d11c199ec63e64d43c73b0aba8c42fcb74e8f39dd820f7dd9974f58c526e880a252d2ccec370d0aa308bf388b880f3a9931c0d916e655f78376cc9ce0ce305071e8124a0df515773736436ef0d4b4d0114dfbd250c3ebc0c4ed6bf8c31b917aa6ccafe1c5d51f0595bc58d19049c24ed9d2d1364423d066c6571d6a523dcfe1f0b243212af6beb112e0e5b37c3d8ec7bc9edaf7835d44401adfe3318151e192beb7b9f8c1bd7494ded2b211d2d730868da2f8b1e311e04b93bdcf4040615e0d15b00f83ad0744e3b5d123289744909d879620b42ab1b5e34fd0f51b26fba216ffe1804da04ce2224f80e9713be6dc93bf64e383b2fba7eacece6445059850c5018fba27ce6bc5e4c11d3e1637262f12560874f506f692f70ec26f4b8cb3340697ac70ea445d64695210443e2d6c9d49f90178d0f4a3a8c9940546bd1a5b9bb359da4fde1f63c1eaa6bf09d172768c86b9822f082fe2c85dc9bc613f65b423ced4274c18ee7d2e38479105995ab9f559e4cd2f2e41b5176e914b9f184f2002758d16d3fdbc9ce648c623aa6e5f203dd39530e3cc8da0b8e8043ecfd4d7e4df4078eb98efcb1cc41aed4e3b3b6f66cf0a43fd83b9b7ca5a0774db01d8d14b1e57cc6eced0d8eb55ff0b80e136ced9f71253606ebf788cd7f3f37cb0193406f107d248f51ae43e136b3ef9f8c68901ce579d3e96d60607c1d302e7c0cc34be1141fbae8b38bd4985bb5fd45f393909c77ae74f43913a021945b645a3d34d2b07b51c0545a641498dad46fde45eaa62e7a644b2ffe62ad29f07dd2a21468107951d0ec2eb7fc3bd985c34bb25d00305e994341d0dc33ca3809435aa0b3ebb7597efe6cf5e0fba456a01da8b97946c1c8abc0ab93f6fea672b183478bb2b30dd22949a27b723bc00267123d34dee1ef8c3bb932893768f9b75b06ccfd3df427ec4ba162f19438921318074e7778cb7a77504bf280a7b503d89209b4d230c6c4048983d6d9c56c74098594b26ccd207cdc2657d925a14934bbbd4e4311dba3b40d01fb1733aa1b51bba805a71bace9f1e75fabe2ca52f3293e555fc4d35865b73b8df8b12925fdb1ca0fee2149607dc3b7e4199b1b79b6390650cd16872d9fbd0a2af74856514c4d40fd0cd2d95c6a00a2ea3d3b2709fb51ebb8cccb8f2356775421be172435e2ad9c52af890b7ad9b7889273def8c629edd10cf7de27e37ed997caff6c9298458a95253a6a487f17401000d0f51573ad4a6d1ec9d6967691b14fa56c5d3a7664de300c25da73063cc50a970393909a72164c49115153356e330c48cff64b78be325e130a6d3082e706948ae26fbe918c72a59824544a300c0c0b9ff58b6f23b53e6761bbe184a00d9956241", "1", .Okay}, + {.Lcm, "7b43c3977fe5a7feac35979c9060d22b81c36ac37272d039d67e9e0f65e1cb9b6f6f1d96125e143d8e25c4dea67292c5749df07126433439bcd3025715fd3562ead6031d2a7c215ddb2040fbaba410736db0b6dfc51079570303540710c74093b35933ebbdfb0144c308f4dc2ded7abd3b8a69d3d835e74c6a39a86c9d980c8a6ef47d489b0422ced552001c3ee7ee55878b4c25849f3636fcfb7f1f5e4c79f1034b72d3eeb6cc7b050fae4384add7291eaf945b90ea0d899a44407ea840daa86d20a5cbbaffc6fca85e6f09275dc29a03ea30e206ce2bbbe6b2c642e2473fbc8f0e8e602bf7580c6a622956b862d8e017f7b0fd74a620bc32b41aba1ebf41c24a1c8d0ce8cf52d5a645bceced7962f4d61e6f7f19809740b73287c015829f1e5255c52fa39a587d32efb5f4a4ec3e3ea7bd8127186d834291ae8b9a350aede69ef0475f2e193468d8f537acd7d96e93e425976a2fa17c82f3404249eb50e21a4d9489763b92c6ee0f7c8c88d32c00eed92ffea826c7b41bdfb12bdb428b56cf55cf4f863aa06d06201a8ec63d313597aa337736e5cb1e95e2437b739ceb03e281a1569e59384cd7c9c12f464e58d7ea79c451ca98c29f9659cf10f372aa7772e0c655f6647b9c7035ddc6f3fed5cf48fed48ed1f3dac3990b7c1d3b11e10307be5af7e60a7b19d59659267ea17019e75cc2af4d8b22c9daf34b6dc57e63fb82e72b50f930a41d44969ac887cfeaf01f4d046f8fc7f6efff6c4bf8d9e4aa756323e2b586400d336f6e4d7719e65b66be8c1f204bc62ec41e0900ad30ed0510dc50c09208d9688a281a2ee1ad21d167a0f49e3698713b53976f6d0bdf72d458d5f81f330fadb44de595633e4ea1d3cebad70562966b71ef42d73d7c58dce35bb99b526498bbf675cb338d70e61351aa6639df45f2a3fd1430eca21a379f7d10851a89d72786e9becf205af69de16af09c77a6fa2c954b06e99b828e568db4f286b1266592ae7f920065e729a1174deeecdb47d97acb328dac2009beaf358b5f0867b5a72060a5f0d55a992d046086220ab973b2527d573ee3c2779d0304fc2d3c05bb0755b7921f8cee898cb5d29f236e1b47082ae8d7bbec5a4d0dfd6b0d54f4653d3def2728e77d2c134e98bfc766c7b57547f97389018958076838ad2f3ae9ee6c6bc6cb2f0837e932db4a4a7d5aa0e73d1d9af1a605fbecacc492701bf7564a7018edce30f3ed74ddd2649a66c87423de4fbbe65152eb9bbf3642712db7d4a916169f324a75fed5046ce8c4256002a6c1e0728ba56c04cafd3a5fbfb4654281584d29234cfdb7900cff7a0759f462310b110fddc7613b3c998924ade6fa9bf098d192e37940406828897a70407b309eef03a72664a4ffb09a9a8fd246b3ec93cc2fb8a82e0a09248a9cbe19492ad48de53801b062e410d1814bb56245e991bb010e5c0ecc6c85f17cadd4bbbec96b6c3ac69158341864a583d7368ac3c1cfc52cabadb52081b6223a33dc36ba50062ea0f6b5026357c7f5b6e48efc941b2f942dd34c1ac96944d486c7ea6cde9cbf8dfc8c69e453261989fbba9d4585f94916347a802171555126e8ee601450558df455372a45aa37fa7b3a7c563e94e582c755de9dab951a7c75a93676bfcad7ca8ef9701a142df1b9673845455ababbb0a86613ce6dff719436eb0198dce2e264fe87973d2abbe393bbd47d7c568e8fa5d73e97ba0d9030db961a503561e150146abeef4086bba5846efbc01640911862036d8d6e45752d3f24a8b85bd17b17ce1cd141750bb0846028979548a393a571c9f24475394906240c6e7dcb41a9991a17bf08f40bda243286e1bf5f758b71db392e35382ddbe99b5e6ae177ccc7ee078a7be8ce922f94694f24c47211e973bf7bd234bb4bbef2660fed875f18b4e8bd61a003495e0a84cd9e2f76fac96a4c243fe413d45eef59730db6126fd4dc072618825e188fdabf1471ddd7398bb3aafb5c2068d51297784527074c84a7e0bfdb5ab89661c2eb144dfbe3a04fd84b13ea6873f565c3924331abe7c46aa7724267ed620a68202f1529373a8d2bb7c85b5a425966f6d8a68ce23d81ad4ca96d2d0ffc50cde3e750303e628da796", "370a11f171bb05b1525cbd111065ebebad8af54190c4469b644bfed0c5fc44f4350fe2e985214e7d3db3185a9ebd6689019feb25990c140627024a9c89f0460f5292a6c75446915fc77c974411ef0c13d0b9e7dfe3442e3f7a5151b1ba8998cce82cb99695a6ff3cbfa20fbcbfb12120d23db1cfe1ac1fa5c0520e5655aab46ce9d9b5a999c5d748b5e64e11d574c3cd2374e338208f2e937730b73e17b46cf90b90e151bc3a74f298e0129cf6ba30f678bd0bb3dbd5a987348be1018c145f8e56d337aa3e9d4eb00af0661b183c63008bd7c43ed46820c28557d756787da48f4286c92fdf6674ecdcded5bcdf84f6620aba5ae1854ddb50125a8974e64ae9d4c4b150de3fa53318182b1814aa6b19339828349340cd2bda1be5a925d293a5ab7673bfd24ea07ccb25e58919c4a10abe2b68bd7853be0fcb1719523580c205dd99d00fd941cc918d3aed782b5d7906812da3b2d7b10811d970d5e1fa5c80727977201430a1b93c296cf6483390818ee0409fa140bcd1ecc9a13919e3505fb3573fafbbcc4212744bef8e1be35b763323a9fe1537a300a4893f183494e4f457faa8cabb6c03a63f623dcb2f251a8de8af99de176c222d1792742f44aa825e58b63f89e8ff470adf4deb4a242214e10357a0402a0cd28c72aa8f21339ed573519eee39db148d5eabfbb9e57aeeefa6306e07916501711089969b0bf94c02a82f70f7b791b94752a80aa463eb1f9f0d75f0a80176a3739b510f5aa0f2863ff65f80cea071e866d3799e8093f20d88c7041d83d1ac87aa9e5a3e99ff523726e31d80f79018b6981c93fe307494eec262b28a0c491fceef83b88fa8afabcbf9c928d9378e123dc79efdaeb6d92fa7084eea77c42bc4a2721ea509ad004cbef4ff565ae8595747de1994bccfd5e7cda454d4fefd41ce904772d6516bb7597505d58b5e9650e7592d6c24f691cc0f95fa24304ab7adb4f69747912dac77dd1b926839155d813e420bbc18ce9d470fee91749b73a2fa50e8f927a35fe9b16cb648fac08e4878a0b70b527f4fa35bd6f14ff684dd528bade01a87b3135596c1c43ee0098a64583b9070857bbc61621bf369285ade0c1b0243555a0d305723fbe8172a6dcb824875733ddf5dfde01448f7ad656923630d358ac624b71243798ff7633d5cc0f59901a66a909469ab4aa272181013b81eaa553ef7cdfb2ac10f8ceff84182006e72d7fa1d70d964e508e88dfe967093680b5d1acc138df1bade94edfbda0ea5acb8dfff0c24e3d3d6427dc4da9a6eba3d869c89d74e38bebd95e7a5eb268677576dffc6b67587bc111fc8cab7fbc3dc3f8aa58f6286ff60e4246ae4ca1dfd1e1789cffdf5cf11add669aeeedecccde6b9aa109bb0d150b5208c4785e5977180e3a80954c4c9cea68c36e843b5c6d3bc418ba2c4d45ce96162ad832da5b28a40224bfb397fe4cc513c03a642363f84e134a1eb702f283051cd2ed4973e68f2aedd8fd550badbd5ffbb298b7b7ce8a9b8d5058cdaaa5b3a3e4da2e66147b1d717f624a8e731b1e160990c2f9c093b8d966c97449aece566297accf1adc186dba66be9ddfb366b3872260cdf776fbe17e70c4a4eaa2815d02bec6fcc05c5ad4dc9d7f1e4ea9ce0280f42bd276ac35ec06e099639e6cf08be7cc116ba59f02d57e6683bc51814c59ddd47f366f3feee13ecf51418bc5b885e26e91bea63f01d676f0241f7b3c47d86ec8f68fdc0d2924ebbe7d15d3e5a44691c4b7047d5bd9a70f3af52c13949b05e7ae90f14f002930af405f43a34eed3f19c819babfc8706f9a5f67af814cf4b88000b1c6865f113ddee243fc7cb8dacef1ffffe8e498a4e3e0a691c293d2c524241272bcebb9122f387d0d5031005df3690b8d3f0252060bd7a81a4008ab343fdd07dd95a38c68d6f3266462b86c7ca83b78299ccdac1e31e2084ccaf46b1c68ef1702d955c0cf8088f9e3982ae853c816ee2429bb70907fe139e2b12548f7004dab86a5b209e82577d368e88009e2ff66a5be0e8e4206641073beb28b30624cb15aeb9f40238231786c4f911175b41c0d6fa6fb2026adf9a9132998630f4651341873640282779fefff5d13fc4e6e1f629e89e9215", "1a80684ef1f07dc161c0a70c57f9d0d02fd53ef708db17fc612f063fa1a583961d1af87b6fe3aa1515300fa8717831a01cc07e6a9955ce3329d04187dd751b1a9933ed10abaa1645008cc162e9ba49aa55553b16f9eca57ede162506bf36e00d08b1cdb80ae90673d4ef5234d4f6bd8dacc2d063ff90c153a5f3c2f3ade974309e4f00ec6581bfb630176987e549981285d80109deb67058284015fbc7c0abfdbed89184d5e880eb80fecda55059469e88aeeb55ccbe116e1cb19cd064914d8af9ed5c91420c925bacffe185f22364e4d3f19520007f77031c3ee906e100e80c73be1a3e5e129c8282e32e70a661ad9ffe625a2dd819c0329d3a5d476560b05704bb447d515b232ed213904bf03b164c5d987377138e4fa6a277a919cd79f26dc117be45113338c6eb70f9bc173ae672afa63f82d6284a0ce6da64b552a67c712248f70b93305b164cabf6bf1acfa997372464f063b1567044da7ac57d4130a427ee437a205a419eb38d005752767606f0e7630ff396b52ebd70b87bb24f245cf20802080cc530ff7fed091cc9ebb842cc40ee1f3d592f60d07b417ed11e96909abd7d04b19406ebfeb2162e02cbefdb7441084e353b80dafe0c9641e839e93e02825fc220af51cc308121ee1e33c99920a27c31f409efde7f8ef927683b6687d7948ebdb91db41be467821d443661190afd1c053f0a07f8dd6edcf9e749af8ce9474c0918d707fb738af8078a184d26f8714b3788cfbb6a8828cd717c63126f8bc0488965494033fc02c0c0386d6c8175a33aa3eb2e538530099ff4eea73dcbdfdbde4a37a5cbc9872b12482856ca6a636a1dfe32107ff9a49747685db3484c041c7d4e9710db9faba9ad82909b2ead166e9d57ba1d9866bc819aca6ccf7ddc277e59f4711b62fe3499a9553b58a33f6a90364d454085f6bf62e7d78b85c453465f6f91f88e6da0c56cd3a6c0058a038e965c0f7e3af238cb1d884b1416bb88e630351d516d9ebf02f1f7ab067c42d1ff6a68988b88781bca78c84ff151f02ce2ad2271a1d6b456c179575a8e0a39fa7a5a7b4e4f62252f83440b044e3ce12a6f3faa231cbbcf98e383e70e180e68286cccfd60c254e7ef44756f2ce7ae14b1a5c412d7a3e1e12a82ba142b958a294fc306080a5f34110ecdfb50a6d593c47b95f30e5497c81295d266e25a0ca176ca2f1dc79cd634fb0311d78602f9ad8a6264f3cf9a6f9f080b7415c9cbde6236c3f5367526c7259b47c0c8d30dbd11d48c97d66f6221ed308c3c70243e26132eb5f80da55d0b3208e694e17551e3eb17bd4d40c5edf8c105c1027cb32e45b03c307e546efe917cb9f0aa1a23d20d3515b9f1946baecd6bfffb71ddc240041536981b7d5fd1bc43160d5c56a18503af7df1877670176abc483a586a5ea7f12e582c1298d83f1e6acb18309936b20ca447beec71a492af3425fcce936e8dfb7e3ae8861944ad32bbbd4fe8ddcae2c3c59dca72fb2991e0dbd802c9b284eca5d9c8b207656b1d8054d622437ae943bcc0fe84b483ab16198bbf0651e418f77438be0bd4fb22667c89bb53680a8a7275f4177fc2632434696bf456b6728e3ff2b4789b6b95b0cc372e4c21fc26bd6f8ed4415e646cf0c484633b68a9c3b130db13aec5faabaf062a47ebd659cca953aac1b743c7c26886159b12cb6e317ed251ee64948d879bbec2ec9f5300e3b0bc6afde22f25670cf1cedebbed4db18e4ef335969973c5fefd1e2ee15df62c8141a03a4928015b3418d607ae4cc332be6d601d20af7eaeb64e0434a9fb1bd4aaefb29c8f18b10761472eacf480350b9ace65352debad38d573e6a733b0ca12335b0bc83f5cc1870cba105b338b718a572459e7d291c65215f48219b969f1650e177f2a0e7f1fe1f4f76422baaffa33dd5392491f36ac28dbcddc99e9539fdf10f1761dff24588338d15bc6259603b3b8e51269debfbb9b5b2d22eef93d9b6d66224ba9a79eb07513a321b5a53f105023e126ea506c193ab8e31318154ea390e868c0bc9e3cd7e3da82422d19fb681326fc1721c86517d997d12904aef2343e3250d03f069243b28b964a9ab1b72a1981d8fad426a7234f9fbabbeac47d3bda027d8d934e61612c19161149aa876bc245107c108634062e26b002b7936c4091b5c96b01a60fc1a5540187eb03bc4ba8f432b8cb998668ca8b01c10d010ccdc8880cccce3ca9601aafe2795c77a160b074c94336f66cbafccfd2f28301309c343af7a95b68e35548992b4687ba674a25ae888c0dea11527415b10205c09ca4c04820a9e31d1f42a5cb5125b0506dcd55e0f8f9ef5bcaeb2304ab7fd2dc0404b329c86e14cfd007f8ea53fa35a52481946f4903ea740401568edd0951a7d17a3fe5fe628b23a85c2ec6157321b0a000707f2c004503e704e472c32bcfec2d6992befce27dd8e7889ce2893cc7f5ca2a1a63f5f88062f310ca51abc27f16ff533752cec7b2ce91276f7c1f741aab0f37d704ffe1f7a5e63234d967ffcc134cbb5ea72e47ce2a027bb6382b55a9d2905ebd9e3fd4907b96b0e54aa0a63a5e42da12a496e5bcb5a446d5301d4551cee18ecb12dbcc8fcf3f03ae63282d5683a7c84b2e853f2ef4ca516791318d809f1914d1dbb64c97088afabc60590916c9f0a85deac60f33a9bb0db49b7ca52df045cd9dd371ceb8f1e54243f6d0abe28d5cebeedd6cf56e14b18917002e8a23b722d0653ceb27506819031a152ce1bac3518fcd6611de050ff20551ab996ce36796ffd71b964f3cc6a513a2cc5358d938f5cad25dd026d4af5a57904ac7eee0c511948357e50489e61a24763e74b6abe4e8aa0b1a2dc4db3147eee441ad10ca0003f2828e220f4d64192e47a26a05cf06c0aa4147df1d7543452b6773929afa7a30a48fc6a6e9215459bd843ed1addba2b67e7c9777970d55e1d8992b76e40d01e1943906ad782cc39b76e4e73cba02f129c3e2da61a5d51b3dfc688ab6858da6770933d708796d38aaf4027b1fd66d999a4b77b931f67e56032c7bafa47c4ad10aaec1d296218e6b94adf04063e4cef55d4c17d7d3cd77a07ab195002e0566c739f6836f5c4803f2e7572ba86afd55862b28c3f6d8cd63026dd8bfa0ff4bb9d113167f09188bcdb6454f899286cebaaab4572dd9ff9d636fb9962636c284fe3013dab6313ec78cc1f815a49e0cd4e09acd5d999bc7dbeab15015abd65404e2a51c4981513d726acb0f6efb43ed57b27f0fc4fdd61db715585551b0568e1ef468b5000e96a1c192c7bc0611b16aac36684a8c7ef0d058535ec14dfc1eda2cc55b014a1685c830500033f74767c24b2d2df62776d9f9446482df7c1c2971c92059bba9ba309ff3997ad7d25667655008200140926753e82a33c3d084ef819491e1b03ece5008e6dd3edce5bc35df0b064abb0d799ce451f3a317dd00d180ab027f7a8593210b8c4bf073faa6b713e794c08cf6158a4649542a59dd7a7648d4dbd0f957d0dac5b39f5392a2980200691fcbfb78cd78668c44eeb780877dd05a6ea487f26761f066b73bc604aab337161740cb93bfc1fa633656a0f420ca12b3863b3f440557ae79067d8622c1113370e2254af028896b9fe944b8ba4e8faea110adfff3920ddddeca01417d20d22a5a558fd17cac8dec0c8f4b5204b2e3e1bf603874284f5d4d9b974386bcc99794111d4d6b6312919014791256bcc578d0b683f10c1787d673c75bf0a182199ab2962cb1023e3d12972d3e571ffa7e6946d379c9ea29240d6322a59ff0c99d81aebe3acd3ddc74bd0e1d35cdcd73d7e6564ffc4bd8ced2c229ebc10f813f31d1ce2cbe19f283b427ecfec4ae7cdfddf63c844969c559d2ccb2dee4fd777a65d34727566141cb85258483bdc49723f584d509c7c0771d29ec1218c19198f5e2d96f5729fb9c8da4fd7df98ca340b8271d1f0fdf2a0fd0d665e9430b84cefb9009bf45acf7a7b64af299a361853692d2f2d2abceaee6b182aa04086cabbb3a07b67e7b921a62cf485062f6cce771997cc7aac4db7384717be4ea5d3e20770af3574965e2aa497b6e21bd6f4c29d9cf4a05efa26bf4ef9c67ee18791bcfa1da7f6045ed59a9960e8c7ccdc601c98e79a5d28a00148690ee267d94967e56fef0507542b50068a55451021af726ef48066f48e9061e292e4184f0fe77889c25b6586e5d11d68318f39e1ee7af9804737d844f1841bd7e0cefe42abba212156efb78b7a63dc64b4e", .Okay}, + {.Lcm, "-712b25240960198bb0d76f717d2499782ebba76bcaf694b4f28fd1dda8f60e0b1bcc7d6ee5f7d8c4613164020ee37b843ff11249e041677d3f8eb4c90c04470cade354c94e92d4e7e8688f423266de6b26aa3e60e2e35d5ee1842208618d03fbccfab6dde6e32000bf234708bcf82e17a4c81577e17bd76bb27de35ef3ebec7e9d765824a442fdbfa421d8662276de1dd6bb014f02e707f1a471e8f5c7ca95410a146705da5492a743779590ebb7ec15fa32b2bf1ebcddd863087778b9bdb645bf5a8f8834e3d69cacc1240031710451fa6cc79ed8371423a24b4d2353aa8cf78e5c8fceca514532c7909a57951c32c8d4a1ff841e433284264571b1b43a4d1c1c4bd370cb9c39bb29340461d42318d956c818670ace54431d4e07e44ee4d6c914fee9620e7b4f1644e863e228c8be16afa9e6e080e968dc3e04cf38236afa2d2d371dc0ec4648cff474a648a81f38e3decb289e61f2d3ed93f77f74cb25af4a4c903d27cd6034a20274fac12624c3577edf9476227f9d35494afbaaab4d8d5981777bf6f81b07f0f687f04bdfe20dc8c1064351538b11c8e3c0ecc02ac37a2f0542bc9a15099bc07805efc5160d7bdf0949e4f87deb5631c89e9f8fe719ccb50a1fd606608460d6b1ccee3304112f3472cee4ce06d451a1145c45f4a23500dadf877f727496b63c9d7df9bf938db2d2252cb61fd7118a7e163e19679e9d296e33820eb46bab2802173f943ec2835a5bd2f25927037e6868745cd3422a2e2a0228d3b20855c497b8bae44f6b29813591d27952329b7cc95c4b11a12e238981e094d439a62e72b7f9e715dc3660fe1c5e611bed027d810143e9971eda7d697d6934cbfc0d2d3fc40b68c8546cf0f1171c414d53efe7355d14301e4c46ff222d49471a1237e8bdb89a92255e39ca3cbc1cb68cd6616dda3313eddfc0df821f6cad2ca2e7b3a93b45688002ac41e50104efda3eabc562a83dd1ae01465420412d6cbfffcb1778ea52feebba8bdea8f9040f1f554d6ecb33bc46e084d697674e88d16f47c7b765faa3057768905e948f02f2fa44208b7987b05694e0047984435eba991717f781b37e226feb7d86c10d08ce93ab2c987a5a3e62f6f6735fff5f50bec67febd053a00c62c55c102ebfcdf80b41d09683f00756e2a4842f42e21b3203385430c02055f94fb07b5e1c78d6644481ef037cb3069de3a9c47286ae9cdbee549b29b24432e5c703d07ba4b0bc4e3e3a02db2db1ce78098cbdf616115124ea511df32917fba7fb0a736ef10106777ccb8f414b46e1f2eadad8ff04abcc6758038ec8cc760cd567caa765241ac9d16c9887df0ef5532546851158ac7a85527cec222c1bf6e261be1b61ce91956e894dbc99dbffe3dc853ff53eb7100532a81e14cf1b140cdf541a3718b60a6b1c50a98c67c51c6c5860e1628c7b45ebb682ce9d707b859d56dfc2258f336f4d675e2f1acd2376f7fd4f51defb03cab62f9a590c25d70c2a6554e5b824bb64684914d432e03e5bb265d1966e07726b6a455c009d185c6463beff1d686ea96e66e92ca31759e78d95bc551d4c9f3b15f25c1fd50d00d7cc2ced20363145812e52e7acfb77d24aafeed00356ecf97ec1d56b947bebcd172840cdeaf6662b071e5af3881ac8718683ac0e49195933cd5f82366388ba9e3c36d2398c947b3736a9e0ed752b6fdcf704881d529a962ced8f264dd948a93f2fb5a2903e7fc1146cc1bf150c136ac76363e4b6e7456b268c8e896577c4c6bac018828c89f8d4bcbfd6efc80bf097aff56915cef79ee7aa8efd95f588d2fd98d48da3b4fdde5811d9ece8935ff8ca648843104966cb4e9958d6556fd72076d9510480f46e9ddbf2eb7ace92b63dbbeb8f98fa7af57c576beccc823f6571b31748a02619ae3fc79e7424abd8847953600d207fa17ecc04046f7fc7994f4d6c3ea65c6b38e279f77b2a43633692522a8fbd6095661b727eb90ab3c506e7a7ae8d07c92ceaba8adaf39bfd77b4926914101312e8bf55e2249a4548cef7d2ba93d8782e818972723302e7127b49aa114d26a8d5604911b431150453755c4ff378ffef5dddb3b6d4dbc4550d743d8de1c99a0f8aff60d37c919e12fc", "783bdd390021642cf9b87003df83d23506abf02c18f7afb242bebc5223726358935f748a2abcfda20b218346a3afef5ac7372e2f2de113dd93550b93c2414187fdf0ea233b4aa42b375cabfc763ae6c98fb1aee8ce9fb58dceb67d1b7e822232bfc5c4d62fbd54a3694619a8ac55cf1677090ca38cace3941ac65286d139d3fffca90f8573f84208009750f2e904aa119892f6715932e9cf961acc747725a3c279587ef0a4ec221532a8120dcf12e86e2d9c2f588fb8353de8ba16eb2ac58f22dd164dd3bb2d88fa9a0a4c9ba18fd99e9cdfcc39cd4cabe160fd6b3fb9db79acc2fb74220c85589d5d4428bbfd48000dd17faca122c6441fde431fb34913b085784eff6ab0e0a334aab3c52ed03a79b727b6235044b9ed0b51d2999a4fbfb6e88a9c32d0b24dfaaf4a220706aefb278931a242a6f070711b32b2853b03c2b4c92aa6470c53d43532232b327ca795adb85d24c07e67b275eac53ab2a5011ce03df8ca40e8af7ccf1d114954c5ee138aa22a82463fca643dda13734f9d0a181d811670095320416e100aa267d871499ab3bf38ebc23fe575f9df9b7ec81549e3ef4279051e3f03e1c74cf8663d2815d07af0d025b64ef4bd33f750b3e69b5739353081ca04ba99d2797742c6b4b5bc5e0248dabc8e58321450644a063b5bede837eed0e35138b5d8522f81e22132d94a07edb2dc915a151a6f4deac636758507e46c932abd1ae4562058b536667fc3c6711ac5fe06d70205e1557bc257c6fd5c4f2d4138df44f1bc764a2e8edb1f2c85ac90e07ad3ef67006d77d80ef62292a13adad121857c0161fdaa12247117b53777a3bbb8471ba163b2b6df43dcb6f39c0fa26f75314f61bdaaf11a5ec11b0c73d78e5dc28b27d0040f5836a51426fe02df82ff97228032ecba03150d87a6b7c65bf50f05b3a1aac893d6cc1e42a2f337f5635f63dc520f478a30c1954c2cc181a79e3bcf445e49d594a9e0c94713503f2d40a00fd02cd81cbf10b76ade991639862982f43eea4903e530192e459ade693590c2e971a1f3f09c3b90c4eb91b8695d761dddf87b799b5fb83557d84cdb5ef30e20fe484486f1f859e0153f2b9cf22c76071a6dc4af55a8d42c23a314720f98def4881731bc49647787ea2149a6f8a91f1052a0aa8cbeb10e4287670dacf9034d1b33f0320198d34777b95f5709909d49972d3fdcf22b38a2eaa7b08ab663c560ed5acd8ee47dc9769ff3ab00a3ae351b26bef7f25bf5ab4cadeb99a6fdf2907c8aba90f14e67b0d1af9a17a5030a5ea0da0ac1df868e1336ccf1c9123929bf51bd5aeb4335e9420f1ac0312cae1aee3eeaf7d2db85fbad80a49b9e8f8bf272fbe905fd701296dcc5fe27526974806b563e94346ba93bb67e5e3726cca9e8cd6fc87c6944a820dbacb3ef82e194944a2224c2d4c31adc466f07ee71fdb9e58ac0bc0034879c642045f78e550a80932e4e3ee63fd1b5707cf496f60a25db20cb09c797d618472b12466bb0ae6985f75e32bcf0e54405d6cd2d684ff37d713db0de821efce0b1142d756224cb55cbcf26331692b5053753d926d0957b8a6f1e542e24cccb281ef14098b9f4f673ce44c21aa1436993b831e01d39021ac5cfade65f0c730489ed9d6c0b3e3aed348ee3d4033f7a988c5bd9b0992dd2cef455ef2972e1c85c75eb10a22ed070f829fdb056d09c2f2e10d3f7e3ee299d009a094fa22853cefe17e5c942a7d784740825a71847995af8c93ce7a9c5e05a664b31f63e36e8098dbd8251fa438e7cdbaf776a789939a9febb99d4a4e0fcce7173f533ac71ad83d4d46ab280610acdfa43814bbab27055bc4e2ee760551ebd2825236dcb5dbad306b4bdb3d4f147d522957c822c554895e034c979a0c899aeb9fdc9357b8269b5d658f39ea86986da367ccb7d1cd51c33f4e3427bf50923450549799647c5e63ea2895a302cbd6fb01cc58fdc9d9f7db1918883873da9ce157575b2eb660eb35df9d11e5e599fb0e327e5ba6ea9fd52c4fbc6e6332b8766f43ee32f2076d5e95b6b545c85cf94ff511a69a4aa8720e00a3e796b1d5f20b3509128fc92cf9160f6ff7b7a7db6519a40d372c57f2efcb54f297934a4001fe8b38e", "1a935812f2b6ac8af84018470209e72ad90c8ed0054566af431a5ed8080d8ad3900adf62a340de578bd15d81c88259fd7cc1bf0835fbe66c4ba150438125927e9dafdb01ab54aacddbbbd39e8d7f45429b5d9e1d00f48488dccacf70e455635980d766fad7d4773fab53ebabc0f3735e76b48b2210cc3e6595b675749f4079254573da1d123a2958e365d8bea3f637e466740544df6e6bfb6eb034510359d01290fdc4dab3f461e8884226ac1db2c69602c5d54d0c6e6a9c8b544109d814d117256033efad595f2ee48460893ae9346e2c81c057d3306b99ef945b38fa0610f73c6e110c34f3646620cb2bf19157c56c2cb167a71de3db18c5d7a8f6f15620060b37a1444e710abf942dc7dd061e04a1d56dfb45def5c2115c970a3208fb49012a87c12c3d2e0329fc02ec73b008912d98fe79777078b2f671e48d124afeec6e7d6a4c538ad0262df38f80fb992fa8e97a8e23bd473e278f954bcf1cfd03ed67dd8e582d8674b0b9c0600d7b2984bdcc2e65ef894cd32bba65701cf96d9de25b6e04b364cf32ccbbad765ddc8e611e806cef05847ad619925e38d3129bff1054f0420dd388f0307abef186ef8b5ce3bdb36d3b6d71a21b0e78a589971ca6032af31c5eb304e14fad50962092eb7d5dc86496b5a2dbb691be4e8be4d46c842c226f4b4b1e475ebe1fa4fa9566a746cfbd6c760a72585eded35d9d0232ae96a90a498c9d31bb5b7171cd97719df09b157948615fef92c13f297ce64a047cc071de0dace53e1b13401568e9fcc4a7010e81af42a4bd156f80be19b650638e80c199d3922222a62af4f454fc2793bf14263a14a9bc01dc996a0da0b0361f3b810218c6fd94fc87a1994be1b4dcb1cba3d2a61f0cd2a2cb74516ce4da104cbbb851fdb49e9190b00cf8de324eda69bee8634297180560f8bff750f8bca1e735faba7cf8a19c059a42443e486122786e5f3505c8690edbd3403bd83732f9f9d32bd32f3dcc8f25b60bec568f0e3f502d350fdfc3a4468debc36b6585f404720a685b2fd48f9a4a7245d7b425ffbeb82ee1e4152f14c25dfe020d4caba515a283510862e0106b76a13edc79e4c26112e10d2c825d42ae9160314c9ad5db8eb1b582c1bddaf5fcc14ec4498a18db4979ddca3568abe52a3872d6f32d05f90f93c05d2ffacc039d94a2653be334646e5701a8cb623d8d0d843590ad773ba9239281ee611a262d15405c2f2e2321212e9f16750f2827298d0d24911eb3e17c15b067ea15a68c81d4f33e7d2f21ff789dae63148991ba9268f535658e1ef96cb0f678af724551ef95646bb851babc36a877931f6571f9bd797039620390c111744c236d8ffe696c7d4e99462a59c6be5056f6e4547f2b8b5a8d8f873365fdcc87cb20a875e16bc292238fbd6ca5fb634ba2fd6f7d5dabe30e350e195828fbfa6a784571ce972b1e41006b1fbbb7e68bc566382912c017b257b838939cd44a2f4547e224bbc3442b6b64c9a26566b60fdab79e6ee225d11227973da6405d622211b5e0012c0adbfd32a9351e41e9f59409def06cc8fef6e50c87abf974f8718ea8af3b8588e22db93ef80729fb3c32a0fe8a0b32b3bf145370a6bfe926f516225981b521947a3d2853283e386ec34bf199211e9916863e04014a8858c19ba4ac6a0d9a695191af1eea5e6eb49fd27089c2f9fe582611e09d83fc4640c0a0472ed7c15a9595034f72d552616935cd7e818d8cae5c325e69e5915f4153f11293fc1f71df0da482fa57f0419b8c0196789c8ae4ce18428031b0d96d15323c0990e0e6277810b3e1872bdc2b105641d75ca9bd238ab21fa96cff110849fe837e42a6c2b6ce36036cec557753f4e5f0e64ab9c956e5ce7ffb0ba46a783cd2f3f9b3c845f78b8275046d33d1b3b4efbbb2af102bab82c13208224467a5e49c4e60db442b17817f1ecdf3feba4c6fafb1a4c9d46325d53994a0717bca822e779880852040818c8403b9c04bf627717d80259210fb81653a35b71debc244aa33b03a4d5974b6833e7664b351908567a49de5043973f3a4d1ecb5d1865ad69870ed02bb76b2af637c33f1e3ce72619ee80cabaaa309fc3b8df7b93550fe2f7f0d5c694b8c7e9dc2396490ad6b2dafde03334f88d220094451d77a635f29fbd492f8f3e7ab038b286b37e4b5a64de62adedb62b610ad219dbb3decc88786e3be291157ca15b24c85eef39efc231b270b57773a14144444515f64165cbd537a8aaee471672869859af9932c3b36160f7afc33f1f77b628ab0a51f022b29c3e668010ad7e4bd2af2032b7c61fe70776674ad63a270e767705c68776a8cb40229bb28bfc8b9dae4bcd0d1cc9029a8230c3deb140a47ac033a39209d76274a3cb6f9decc4be81b3c8a9978dd19fef6295d43d9b3d4c4e10337e2fa4a1a7baccc602f5748a6e6d7669e5a4ea44bfa909ed3a7f03507d42e524e36f5b8aa643b67963f9a81ad251aa29fcd1a4e2ad16679bf2bab56254eda07aab30acaa5b59aab0c757d75276108fb881b5d23d23a0e173b92c88d513314417c1b69fee97a2c7165026eff351c5b26155eec1e7408c64c5f34e2ab08d765ab6335a43a2a5960b7fbf4041ab892836134f8932c2cbeb4d4d08654a06ca067ff7272f9633b557ae90f6c38ad6f30fc0d64dc48ac9be460e5e0f525dc1d5806f66962c32ae308ff4e437241676ef12d9524084cbe2a003325311c2678e1e872504335159f7f28cdaed58e9bbfaed7ffed6898e11c77be677cdca95fc8d3996ed9e21f44446bd5ce2477fd257578027d61e0857cb472b860075b1e7f8ac5e87dca42055ea7ab58ba7d2971d337973936600d411300ecc6c4470e394026a4009c9afb81d6a566aca813fb419be3f069c717fce6e81fb2906768303411760db94f61e10d82060b5c3301db3e8ffcd1c29e694415654afb76bc6079b946784353c223f5a3a1e2846f3fb37573baa21a0ab9e38d8387176bea26cc39264dcbe7cbca14a78991a941ec61ca32fe441392b49ada28cb048811edb5354cfcf759c79bc393b3885fbb27ebc36f0b263302f7d2c2d7e9c1c8f89a24386fa1b2d34161114801187dfe3e2219e9a2383e0b0e71feb5e9506f82b83b25138b51eb82633ff86e4c5e0f1c7712009165dbcf2a6bb1e7f4d4bdf7ae2ff17d228d277c4a2e27cb146518fedcc6830e0d966b8de66aa3f76345723e3222dd30568237e8c3db63aa6ab7d37a9b3fd7595db4443a66195b0caecfa4269104f01ce41beb0c63c8b9184de38f69c46ba93e316c057a7522fa1987f6d364fbd723bf864577cada2f3614b81a097b0977f550078fd511a1f7e136e85422c4b3c271aacd9a05d9376689cb007de80a59c15a26f041569a69efae5e66f946c96f2db93f736220040c833c824a49488d71765b687062da6db6852e9029d0f916f21bd293c78b191693860bcae1547179f1763b8136a42149d9f78bacccb2b1290a43c291d3c73e1960690614ee7fbf0b572724ed1efc335bec7c2d71b94437ff7fa6b5eb8ee8b5d94b66c27355d431256d0f6ec21f61d78c41401da0ced439cdf12ed02531f97df12655147b9983476a54330f9d5ba95c8f5ffa045cd9788eccefe9e1e803f7083181d95bf297253eee22f2e7642987aab7f6f7150db8464dd1f78c47d3676421b2f1ef185467dc28ddcee0c2dbd7468b6692d11cb20b9e9c0e7ef8f2148b9afff145abcd795ba489657296cd487cd565ee05fcb11f8db77ce392a2f9595ef8fc1bea7a96c271de3ce8397a50a937d369e553373709df797b4fa7866008e828daa9c6fd4188473529bd8bdef44a3dc40ebb99db94b7b98f5ecdc4a6979298e6058a0d1660358f14c6a7739e2abb9cd2edcc97315cef8158683feabf4262367f3d22bd4a0c1152dfc8a6efed533d175cbc3406bf2c55ec069b1981896bce7d96db37207ed79e675bf6be3a4175ac9daf0f55670575df6d650ecf408beea55ee75c0e00c2706d5c6bb0fa63235fa4c63b935ddf483a7d0e6acea0d692b847f6f2587e85c0119174289fe59fb7fd165c8d5cebf76d0b41e83cbc80e41cb57c11134301cc473b8fa0e5a3bfbeae714a10077ed8af44b008396bcc047cb1986a828ecebac3af483d50308baa0280b7f5f8c063e97f5af31c99fdd844609cd67fa118234a641a9bb2002b6f0a04b7915a4b86ad5f0c0d804d56f4646b800cf7b0390d23abbbf950aa9af546f5966fe02aba7a3c02aa5de4", .Okay}, + {.Lcm, "-7fb1ea93f84a2364b1c7a5b42dcf6b85039315e087f648f3c6e1cef4fed26b12b8df2b020196ed416c5f530aa0016550ccbbd228353513b0831bc8fbb66a983dc7087722bfe66f4b908cc49ed25e8c7fe4c120df442b554a8399e28abacba2b7af1c96bc9955c8a8c2d45838ed9817de206e72c1005cfd3ae82ea8c62c33c724f526c12169edaa115c8fb854ca64ad078f951724703eb5627f9b613394e4068f81b8ea6ef7e2486fb5b53139e94dce4675c09a3011c5060ec43b92ced644d0b99a2142c6de6243bca7ced52c2ec0ff99064c872bdbd134bc0ef7776b7390b63e78f647ecc424271fc7bfd6febafe7ea9b0a6d1a98a09e63a43b2aa3078375eff36312d0029bedc8035a8caeb5f92a546c9d855525bad6520b72f731c615c42ccf8a65b21cc856d73c3f20876a7871c12174317a52cfb661ae7df2f728c8081f7b529eb4fc0f99a9108636c77bf375319f7c994b2ab27ee5897231f60070f26e15f6e8b586658046129bde28a607f4148ff04882736207d1a30114d7efe721b3980fd1d9de2d88aadaef96fb9ada39efeaa364ddac552936c41dc97634e39d3ccd2f09dadf0b4821773a17ce71f6b685ea32263e9c80b773740f9229c4f5d2dd3e5d38092f501ae2d5a77f71cce8a14f2be72f97025ceb26950109917bf80b1202c88ecdf003f729aeffa9f298638061bd386ec407beb7e362e1363095a3d4b0264c92908fb3f222492085cd7765636374d8e0a6715a8dcd44a6b2205a8ffac248e50026264963dbab57dcb22410123c34e755b9e11bbfaba44930dff6c47a5684326bc70f928f99bc5864f5ceef95938aad225aeeac3da593bda43b8b0e0fd225d3a2ef7fb5ab5d14b46689d63e85299f6de5fe432780b797c91f8fa4755ca170e23edc7ba100a3a6d2a33e11808f0910043136c9bc59b8dcbef6c7c51245f95a4c7313ccbad742bb269f086732ce3864aa53711d589e592a9676ed49312d87ab4ea8791155b5e574c1cb05de64c6f4c3a4ecfa8b6919d0a4258c575992cf228cf5d233b1d3466878230c7c931ddf7264729b594e6e14a6c2d9510918cec628e6b53fe9d2d98ba0633b51822806dfba1b8cc42ee417b9eb82a9c05e854706720b943ffcc41f1b2951f9b0f4bca63b8aa18c4e9b37a3641409478db83cedc1c6654a518ffc84006d7294414a296df50dd502acb08cdc4b38adedc6778b5e092cbcdce34759588c883cef3c3db6e4642cfbbac7bdd6eeb99b424279cbd9a110ba16f51a80e34674972d118699f9c4848f56b1492b6280fd82f62f941a9eeacb8e4cca164247902cba3c1aa9837baf949d709d27f99fd44c1d387e84ec7fa37dbbbf603fd49c9a3c83d1523fbc8b4d4a62c09dc4ecaafce6b001634cb3c3bd42bad43ccd10f18ddd31ff0d6838a9de588361563f9375dc006a7312fc8e2afe1c535e8bd338785c399a3884c5cac74f36a6d91050022a52d463240115352e2fa7d26b565e2fc270606a323fb819cf7184383c7f6f2bda5d00f38c84810907b00060d97758a580c824a61a1d16d97a4b1beaed2bf588c7350b5db4e90784a0de3d89b2887458d0ef0e402f62a7d0281463cce04f5f3a5edfbca3452bc9425bc52208d8e371e39e072aeed69dd2bd0b7413df1ceb7b3967960dcb1cc285f938af26d54355cda57f65b3998cc21a20efd3d7c29fa3eaa50dcd9fc966c6855c1e88b07975c64e964731569c9ce24afe1af57ae301a4bc760842c122c9dd46e7a0d554709935e6cfb896a0dc04801fb30a68125174ac6b1ae4ca20eb222567c53c757bcbd8108884f3bd3caa47745e26a6277dc939ad2362f9502afdd21881c638f7c0cf6175ec398225f9ae7359296892695894e7e0d85e24ed97e378cefe81488d05dd11b10da744c2f4160605f7881f202555743c762e8c506e46dacd116eccf6e37d51303fd4ce35659ad47506bb35bd1ed342f1ee48a84a246679a169349509a7fb5f1aae89db17bc271a200f2bb8a20ed50e2b88f0647c5e8c9c239423e1387a6f7717fdb97473786f8fdf4f56cefe88f0bacd191dca7f04e0a86238f65599d91ebdbedbc21f2d08ff7f32e75c3d0f51d9640c911c0cceb904cb96453b1", "56e24e844adb939b5773560d416a2276631159187206dc841701c6b95d739ee0af1f64d55c2ce21493a91a9171df5fa74f49f0b7105d532446cab6b6e5b02da2298ccab44dbed1c004a002d7a6e41bfc5c99999f3976ed84681e3c991667ac365ad6d59f55d394accee1e59016ad70a9f3c5759b7b522ece3bdf80e32d84204b1ce566db89fd9222074fa1b7ecc55e4d01328d4f1eceff9bfaf282a35dbbb3ee6c511afc640e7dd1ece49e3a28b3f4fb58030ef87c430affa5193e006b68b0814217c922255f79cddb6c49b07fc3d93ec2abb87d52d5ba12c3109a44c4bf2dfa6dbe3aacd5ba7561a111d1724cb64cf163b6386848e6ba96a45726a41dc98c1afa59ceb64243a278ed7f97fee2ac1d67b122189c67fe452545ad569104add6fcb15a169a0038c4a98ccf38d07359cd245534918fceb0c036e4e48179f64c13a9263d751bd735a2a3ddfe1736a6b603a1a77c0462d1737756440a5cabb44f463dc88756e2f37a431ce44da52d1d42a417589267e8b552316d455ab05dd3af86b0c62385c9bb8bb5ec54475e5c9fa7323b1d02a0f50d4367c00c691967523c2b56aa728aa23b17703d835a20a5253a7e130fe795c561c5ff8544e97ae749230f6e8847f8c4f79512330a30768f971ccf7b93e4605f77c34b234fb1a0e7aa1bafe34b097befcfcf7ccb10fdeb474f1159d286063409b1b098c04032a056afe0f0ac3e9ea9db9856e57fb441f6e7a9f443fc9535584fc2f7f16526fbc63dc9d4cb54247808d75fd028f492298bd44a4eb51a65bda71bfdd793629ddbbc90b09e27c755c814f3404b36f0df3c185f59e26d4484ecac8d26a27203e038b364a6d961e48169ba4406b04ffc1aa33ff8345106a33577a40eda552b418ece15aaec6fa424cde9beadaad529d2cc0b08b8d645898f965ebea5f2ec8783862a2e94c2dd5291bafeb7e26233e613a3546d0b9bd41931869e1914516cdc42fd9a358885f295cbbe5c1569b07c41f28faee37d8506958fdb1992ab3b78a43861d5ba82d1f3f911d3f2c7d4d3417a9f80beec78f6c56f8846a3093170db0cddcf12f28153db8d4fef0f0f676b40852ecf0be9a8110632cfbb3688b0c76cf3084f35b4f6d9852a14e53ebd4feb0fbd41d7861aa46b4052b02094f6d3937d6ffa8fd9c73e9b12245da9d50c3a448a779d4067abfd93950354e2d80d3e6001e8c93ee2fd0be3702a7af157a798122233c7bba50d514a7c3aaa49ada47ad30fe44a913ae4ef59a1a6f6c77a70fea446d46317d58fce423b8e1c7f5286e160e33a93b165bc317569183e1901d8db2cb8b780134edd01451808143ab4b8232276e294e54a9306e3fea8b9030cd064ce4c6899d1b4e33228cd99e54016defd78e2c459b9514a4b92ff890e5a79bd9425bbb4afa4dc3b74ae42af152cc875b77368628461fcf99a0a87fd8bac0543121a8d709d043eac54e14c00b214deeacd079b2e2582a776f465d69815a309d8cf7d0c764d78db481684cc6bdc4297a3dd088c6c2ac044ed65dc1540ffcd89e75587168971f8381cbee16ee06660d093acd9e47845deba22126a77b5ef23aecaea724b960fcde34269af95734443697659af98fb09075f84fe3d12c55cf78f03ccb1e64049f4cd831d0b1934dccaecf05c3634ba9c6b8510f6a70d06da6338ab415f386cefff2743c6c77333f88ea858e33db4222f8457a7b15addb538612e384483e5b4dd026e5a31c7f22fddb841d489839fb22fd1d3644c9afb0df7b7a133d2b9c84ca2d8bf31d8488fe8297fee7eff3224e0ba5bc0fb5889eb67b560eb84a18c79efcb2e45b6531103f8d3bc04b3a0a1cf857296b263537afc79fe51981bdc8961b35a7f7c2fe8ff11fd7dd73b1535a673526a3fece2ccc42842f023459d809ec5364f0b512be5acc8d42e7368d576149f25738a718e21b3de143db235e90c11ad03de90b57482452d98a463be2380f60277c9696fe59720b4a1585dc884c4bdbabe720aa360fe8537eb57b9107f5d35b7e6ec8be56e4f7e330eeecb4ae3a8a51a699db14df2501f6b401e292f7e7427d05931fa47d4df939dc60fa35bcb6696ed3a0ace91ce9731ac3b1c4c29c0fdf570f18ab67d9072", "2b56a708fe9717ecc806c563a4f1f9838ef1ac76cc85c25188a8d76519dc1f6915aae50ad423cd90a1d95b6cd8969aa6dc75050481ae6a3ae74901a07b4f78591b7003e830246c5aa8874579f4fb127bd18a6e5c812c44ba29e0f9bed2d2478c38475a14e9b18ea96be701ee885866c1344fc4c987b2d469f889ad9869c5101adfbf30a92fc35ad283d69d1883993380d522b2975c7921f51d376cfd72d056dd36b7be7960df0631b594daa9da43e9a828eb9b122ab0ccbdf1964866acd8c9540fc74ea7d79bf9ae2e5b0ea511f42ee4e1aeb836a3c7ccbba716fe519dcd645921215b71cf6bc0d2ed104f77230fc24b8eb9ebe55aa1b26cfcd0cbb18f412d58a14cde57263455340f0192e26972db24dac67c6350c50462d7ed072425ccc20f15212078c15777eadae6b4f7f8c6a50b64914ea63d6187dec22031fcad74130480d44898bcb62e74c88f5e30d86f5eeaaa55289f4d8087f3c3d7c6574a3ee848edc61216933ecdecbbbc0d0abec94441a2fa83f498b3c616ed88dc6152f98e3030f033bbb332cd77c465f78eea3b07ab5ec4cb85dfcf4f84901fd667ce33b22e5b2087d872ef7c95cb222969c445cc2846390282b340469edff7b997247f5e8929ff051556cd860fc54d070eeff5890c2222de0e6e321f91f3493f9a7ef414449aa6102ae55c23b15b82ec7a85f9867b1c7d6d852eba54cc7454c03dbade7f253c575140443d7b1f417130d814c49916c1019057a1e7d70b6585f822460df4887df4af7f732ec1bd06425bbb9776c5d43caeb91240562ec0b1b4ca866120c7ec4d2b7468ab600011e2ee33b50e96308fa4580f4aff68644856d2caee7cb0f3d1dfb6b0af354248e0e606e23a9815a32039acb66a93c716e4bc304a79368c004498eb2d7c94a4b5b7b0d72d54190f06ad442564077b08edde159cc23a79d32ffe48ac97bcf9c124b57d1ac0d0832d32d0bf80f2c1b67c65e295230d6fe8ae96330a12dc75108c3065f15d7a8d26fff5c48286c0bd663a9caad88436c985cf7f8b789f153643aca6d1c122b01b60e5b74d5f9bbc2c1f85c8c9fb3f06df596d06e04ccd1121cb9f1e7628d9df64a0a911da6edc4729f18b478acd2dfb70cd98c3d224de2003cf5f34e184df99b8d7a846dba1bd6ec0cbaa721cf8655462ee59450c204deca91ce2a3a0050661b87ef4d77172cb639268a0ee96c73d56b024ad51d8c8776c2a989bb593068a328e37761019fc232eff8e3243331cb739259393d29b83e3b65ed3833fb7b76aa2eb01aec82b73c9ab6f0a0d33fe1757edc532b1c72b698dc990f00b1274d3a82baaac4c4e6cb0d36c6bf512a50a5ee99346b9f16b7160572dd888b4605ad6e7eb8fce25876bee8a9a318fa674fcbbeabc7b6a3fe05e2c27ead66b8c465429d2a885703e243b71a0e0900466bfc2b574e1638f56122c28731519b6d98737e45463bc48f9197754d34d977050aa89ec483d894cf78771a228f29713ff92535ef909a8c02041f92b14ae6622c154097ca8edf790eeba2df4c185ebf447dd2d6168e8bfc243957d2d08684ea591a765192ff5b86bf674736539ae53ecd80dd0066f46bbc71ac38bba6aae3b252b463eb249d831fd6d0364fd8ab9c4f36d17daa1b1fda868320177769e77ae780b035686559490b70fa85ae0c34056b148f6ce7833b1abfb76ba3526b04c827f22cffde2efa4927fa606a02b4512b05913614740c9ed8784b60ba2772b05f2c34d9c0a65ab82820c24bd81f1516389444781b3dab3a8770c779bb31637c85b20793ad61b4f73b6312ca028e97d513ba9b2f0e279ce745b979df3ff22672b42c8dc659197be78553adcbe23b002a5ff9ede2414d8a36829d04593802c430659149203f86ffac951bc2f38edde01e028a455a1e4c3f2e5c607af3c17f2dfc619992c70f3a8f1c8a904ae4c9e5c1540075c1464e0f153a36908adac1816f33b4c263cd01a4f618e45a87856e540e4fa8861fc098e5b949d34860421999e41dc6bd6d7718e62883e37b738dd68fca9714720fb8571dfce9fc55138e418bab6b92bb31eaa9020fa325ed9890a9491eb65651b3f5c88c044c34d7141b069aaecfe7bb1fc4cb00cf7b3304b1613c6f48890a54fbaf38ca6dcf8a53559bf49e6d86a64ee51ad1141d78b4df150ca580f828cbbf48557610aa8c704ad4c25af3491ae625cbbf99a2833f37fc535aabbf34b49a4a9d1acfeb9e6c22c0ddd52fade65f8f24f59b75bf3acbfafb2ba8f63b1e12fcdfa0b074b270e72ab277eb6d837c7a5c6892e9cc64c700e1425df0f9bdc88c9e08204031c65e147eb902b0647b1452792ac5cb3bd5bb50e49c7e61d420dc34f8cf6612e3b4cac3f056d186fd9c48e760775e082c41fc92d318f08b7a82fada1decad6c8222dc7fc841ebc1254027c8fd9e20359df356b9d7ab9e97418f2cb1ec48e95418660f1fef82947b04aae7d159216a1fd351e8241e18661f04ffcfed1e4c17c0b7587ff94ceafdbc77cbb60846a431e044db35748ef5a776b24e979d2750d53a84d9439b700e305938f9e7afa881ac46e112f8ad2445b06fb237bd18e624115db68a3e6ac1ab15e18916a5d2cdad306050c3b90ea435fa071d80f4c90b5c0deb3cf2e59970173c82d2ae777d0b36e08f6a5d5dba48b0176672615292e532e06cd6ffb51b38707045ed5fe507d55a63ac7a32449d4f583e6a065a766bbe56f80126963a1f7b442a241862b30686bc25dc28da26188e5410f0a75d46aabb705db14a75fd8034d74c4fcf8641d4a5202a94af00dfad799f0e1107249e0aa2b5c3829c1a516584d767b8dcdbe5ce13934d047e8d241eaf0c5514e1d065b147605fc58c16d043396c7cbac58ecfea2a4b6bc4ebbc189ffae619b2eeaf9b1689442a3cb0cc6b2efa7aefe2bab82b93014f4686900d43e9e7b3401bcb376f2e5fe424922335f1cc4a3aaf265ce33a304074f6e60e86a4d416f41c3ef2ff8e0a947a19cb7759e83471fb7f5fbdd7ae4b509f0d650606c1139f630eec59bd84766c6bb0111650a9dc15e23bbd44bf75f8002e6e98e22746ac298d9210738073c06fc3d662853f7255459f0cf2976f8d6b6008f9f3fca0f889d389d88529b96de59842710db9facc2e0b5a7f50a8fff6c5e274839bed22b45df5e5670970ba4819fb2affe18cd3baa57b0f4a9e57d438ad5d009ef33ca0ec14be01aaf1b6610cea9cf0c98a8e6b8cdf03f5ba2b0483ce0a5080980e86484e1a6304f029883f9aff918183b185209c0a9bc2ad1843b1bb147691fd766990a2ae1a859ad779cd1ce2e9778ee7960cd4c9be824b28f906f3af1322e3833eb3b26912a3b2fd2da5b2ad19c540b9014214fd886c34097c801f4abc05e433eddc3e753c12f58961ae87e20655aaa3030035dd11cf6a4ae344ecba7bb0bd2d84543b229e623e607c2aee3eb88a015387afb5a1548010817796fc187ae83fea57d1926bcb5dd109b3a8ae199fb52f0e960e1fa99267b40ecd42bcfa6b9568344026492b809a0dc42d5fe1ec7885f76ae3fa5868ec6dfdd08754a51be825e2c4d062c8121a8b41e92ce32f04381c481ec10c320964af0ca04dc6c962bf054006894d75e1fbd95755db3d1e7d41e519862df1f3493ee3da91a18c2b3e9e2930c1ffcd8aea041dafbcdbf394c73e90e01c0c3e098edb3df1fba9cb7d63104438fe70c9cb6ab99339df24271de17094cd529767a37cda79bf8a5d774efdf19243d6e4dafb0c31a7ad97bfcfce730600f094fd6b65ff25a0f7eeaecd39dc06de627865d92979fcde10540dd2e514001cb11d3cede4648f12dd3595c846185902eb062a2c9a484709d861ee4093146fbec1832e788f01af3dea25a55722b4c67bb9042731008f8ad18a5c81e91b3b342dc48c3a5d7bccd86d1c7e44f16885db99894b0a73cd0e200177c16497496722466428c8c8e419522366714ea40bb2cb1da1d4960e5f817870740d057bf01f196d2cbeb384ae5779251b6fa73337dee7428ec08008647e4c4657692576ea07ec78339fdc230c4b867fb6056f350a50bd413a9ac0eb33dd1a89baf0a62e885780d4448491733b6282f9c72f661d43b8e4e00ea9209791e8019b0df0102378a3577ff2a522030b18e69481edf222c1340d76b04e3720537bc358d219618c216daffb0c990be2632994b870dca3d6b1b688ea2d9712841de71ab55795540c76449b87165f9254753044be3707c8928a40259b12dd4d2", .Okay}, + {.Lcm, "7719f48a33b599495be91a3f5f08a421355d8a12361ac559ccd6d0e6943df265ef88f13898217d76e89f093ef30d88cbb2f63e12fe873fc17e16667bd831aa342961eefa966dd66e72279066c605edc1e29ed991dfeccda187f08cc8ffdc2c20f2b84c2cebd527b40ab4d85c0135ada89ad1c5ad9cdd175aeb8debe98bdf4fb306bfa908cd22891a7340b4d7b119824cf0520fe4b693634305322cc401a975943adefa72ab28af254ee3e704103cd50fd625bab2f0dd966c89268027435dbdfa175fc39dd902874ad17e983bdb9a81ef76464a3d762d5f6f1c428aff2c91d654a39ded5a70c27f0fcf196cffd1ce0250de61295074c48237c3591d59b28fbbd9a7485180310c4fc63b2e4e9413abc6b11e956b179c011604416c8ad1aa4d824cd72494544706d6c75f7558d0fe4f40f6cd32f146bfbd1f73366747860f84dd1d90baf55eb53879a4c3752abe73eeb8f703b107d62dcd33117c31ec1b420fe26ebc7812fb5b144f18397143e1b3e3bbaab40ec3de4343b32d2202e6282eb3a16078707b40de63ae3ae7f11ab2d7f90a31311e50d0517724b7fb8facdb19dbb8b0fa77265cf5b4f6d5e19c1793c73cffd7d5233cf4a7f82f57fafb419db5ff6aae3b1d06ab4c25d1bee6afe09360f8cab4624694a3eec6362a467932fe11d2a1b47a4cf4f173424fc5590ade5c7e3cb4cd4e9c2ebbfc976fa4e2eabfa85cc1cc6479c24c5510705560116d536f1d7fa716e4beea515ba3119e80d2542058e6c805a04d0f96ea5d7a89e5f1a10e67241a1184d4fa3fd077b58873d34fa4294007fb587a3e8d0faa73b7a7a8db99d40adf92c3554967f504c647aa65bb611ca9e103f4e6aa4d40e6ccca60c6823a891ff8f67e36437f7e0048258908de9177894f2ca0e9f7613b2d5404cf42870e4d01f209316fe210e0c561e5ba12ac9a3409329d24aa0a40cbb5ca7c24cf5f13983873881d7ae4d3af034cefb008ce2c4c884cdfb3fada2b5f9f0f67eb750bd0b2f1c318fa43702e30d37b5ea068b0ee65fd1940bcd0ec2e38bd7d4e04a6f48efe03ca8ecb709e30ab774309b25d6baeb07c5cdd2e75d10c8b33fb31f8a2ff9a9e04f6c7ffd93d6379fa569e316af2792b03f03f3c0438056255c4ac4c12e99a30c2667414c7a5af02eb0af1c19d6fb08423c7ad6c3f2b14a04925f8a7e669385c7fd3649584c0ed8a75ff5e5f79dc9f3fc6611942ef6e4b8b69825774f12414c67b99b675876cea74c015de87af9244fd0529364b6df1ee5c51b4500949913ff2b69015da4377f1da520bcee391b60796bb5a70babeed6d862e4dd17c36d36063a51761833aa56168cc7e74bbe8c8f4312c5a00fe1c4fa2af27e33ce1e52496c5f9765c1bfdc3038416aece582136c14e0b44798872683c767f88a417be7ab650e88b7330264afe0f92ad675e15719dc63def016d43e296c035f34e978292f9783e85332eba74e14c47765352a8f2a5af51e74222066d5927bfe3679942ac450e181f5daf1d9bb9db3e057977b5dc30fb548e345ce14a20f889333729f3f981a416806009cadb05318147e30e1d3d5910b8689cbce1fdc5986872ed0369ae97c7294ebfeb499670b6feafd7e41f28df6d9e65c7c40bf5e3245c7a670267569278875cb879ded11eb0b38e2ca1256ccb7b538cc62cf9d0c57a84236b04d66e07942a7d400edef0631638946257e136c517e718d945314fa8245f6690234c0ea846f0057ca429fd8e4ffc874725f235647000e4a07f3afe6cffccb9444e3ad8e14f29130e8dba352ab2edcb68835a8dd1c3a3e8505c8d85707e60a22f58fc92f51460fde60a9e84ca4ed90045c6bb7fd531f7d80e4b25f0073ed81b591e1861ce576304669612e66ba9edcc9cbb93c858dfba1da8deb9c50a5094b843761a62fc883bd2af7fb1d11ced3f2eb605d467d5955dfbf381d3dad836979625b9221fccc0f4a0e052539bae72306601d66fedcb83e1bfe8fda2d1693946a52d5dab71ed187797d8b5ada9d5e597092e5e45d1aa120e7716987199d86142928f701e8275a7d6959f47056745c8db70d7e51be50c8b3b988a472e82f6adaffc7154ba6abb4580d5e4061982c8b443241358cdc533", "39618a44202224c40ed9653ed386bc261a7c5c8bd73d4f826f688308cee42b5c8fd20e697b2e3c3b55c63c9dc427e3bfba4fc384de41aef0f0f2561a379a8d43bf625752c69bf566c48773b2b25cc5184ab0686c43d18407bc90429b4e05fd1f8afaa522abc54a786d4657c3ce828a1e059932ca2c96bbbd74b174cb882d094a1d297d05610a6090748a5172f269521c3845f0182ff63cbb6cdb0b6024ddd23bed52feeffc964e5a120cdcb3b7caffe64cc30b200859c3e040ba922c3fae4c7916474fba721bd500aa8422824749dda6928890b3d859fa557fab1c46c76c77372312045fc681ad5d916ba9fffd97a1307c6cc93fa785a73a412c5c456d756413cec1ce83a09eee8fb829c9022ac8d9c0982f88dd5655955bf08e0956001b72b19349caedf7ebe674c12b097da5b3b01429453669ff0189fb618764912d8416b181b428f0280acb936c9642dc6591519aedb76ee09a9d9dc04d672f0ee9c237fdbcff5e3f30527b0e3cd471faba314bd4fb3f55d1a3a1e272429e1d2350dd981a4927042955ad59fd4f13edb5ca9811695de52d2ce566f3d187116bc9883b9a77500b4b947ea247a5d97414b8b6382eb5b1e0322173db598ea5aa7708a17849d5df8b2faaddec90198a1649a7620b15a14e0fd1722e42e1a86ad3484ce8f2387d89ac3fbf3259d37abc3d0e32cca93ad9781111ff58c15cb35d82def52af1346e3cc3c5533dc2282fd35f7551b755d4d85407d9e8399afa1c813638c989df9275246c8a966c3d490517c6ded0c53ac7e9acb550a99575c4aeed40817f6d44ca6b5d47f198e5f9f8d2e3f8922f51c614ca25b5f6727bfb0c7e22228ce6d60330215b546ae73be4cdcd331eb12e5e71b2d4a61ed722673d3d6f15df8f9faa99fad8e810145b29d6e4526bdc93241134bfb31998e05485f793cb3a54033a4abac7305158a46ef3580e7a2ec5e441293159906a4f7b82293d5c021324a335da7a19ae6c18af90f9a527978f7b98d9bb5b6f8fe91f876d3b766d2984d409e158b905d8ef313abf8f7785b4a2ce2f87a0706a18efb50e49df3347878ee8d0855ec36d18b51f63922495ac08d1c11f26d1b8f141026e544790b19f3171dff80ef7bca40400cdaa9c9acead2cf1afcf1e91f61b0177181854578d35cb63c4504e22cbae2ee2713eb6795e6d4536da7f055c89b821a42c937def27029ba730fc6cc1308028a6c4be56e027220de3e66b9b6d6c932656388fb8b83fc5237cf05849500b14aaebeae49f50102046bc8a55ac7391e0d750b8c03b5c3bc374f9c800ac62346a5889499227e300152e666abf1f61aa0d1585359f3c1ab5b55df767649c85c5344ac88247bd98e2c26a526f9bdde78599bb026ef814649506148266e3521b2b6f3e78b18d6be05895c7340216375e87bcff52f8045a9b4105e1a39084a4c8896ec731dce15242a071e227e588002c8f0dd9bd334c052bb556acb793ecfb526f95ab9b984a344a24368d76b4b20fef88e08786bc746b52eed3910b49cdfd5ff7e8fafd59aab9717d93912b445438d29cc85911293e9be76378723cccb6a52e36a847687f7d782ecc4c00e22decc192dc7f8f38c8d82645dc6ad69ed6864c669541e1570a4af53f1b41d8c1cd4fa91c83392bcb5da949ad23af59bf7d7355e87df9cf5a221248ab6d27987d19f7e12eb21d184f059b42fb660cac3305decb0e74dab96f5a1b63260cbe53e51158a1202d900d41eb0ff5e9ba895b7e1e4ddb60db54c1f804676fdb072a027fde86f36a0d22152f09616ed4b2d9b18566735b3aeaf9ae5497ab727b89789feab73dd81d415d8797374055ec5b59968c78044f96eccd50a3ade3845cc87d539349c44ee7e9c30fcb9f112bf3f6135048db0257772d0d302ad3c4d56d488f0ae65e3e27866c858efe5723b78339ebde264c86871260493d8eba295a0e0a42224ef2869451670d0906a074da2a6f1d66e6974187352fa686140c0a32559edb6933ee4f3415dbe8b4d4ad19aaf20c3ff2f965f50fff306aa0ddaa4e75fc1e93e2b2c2d19b02c3a488c54d89dd489bf3dd8a7adfc7531a4746516801bab1ef5cb16ad00cd4f42d6955963efbdff4732245494d01e7", "8e60d895f2e898c385f4258b2bce45b9e5c009325e730dc25024dabf19cd4e0cbd539c2b480b413fd4be5b060ebfa3b4d7efda875292489a04277197ff864879c05eba15a6d0910eceec61d7c756a3c30cdbb4f98a51aad754d737855dd1cdff14652d545ebdf42ce4d64b4035c5ded6bcd40e1c7d7d98277c371ede23bb3f823945a339fc143de6ba67d0e553d5ed59c10dda0525f4d6373aabfc1badd36e4b236f9e110f7d07190e65ccb2630b7d006019d74e4f40bcda30882421b5ab9b71775245367b275aaca02e3725be137db07f11ead0b38772aad211a63e16cf6cce99874f1b23b521f29db211aeec8c48be55d55e23dfc520dbe94f274d1defcc98a4d98301671003f17f80860430b20ea9f6105e2da2a09207c9652377f5e0869811c26e22809255da45fe826c7f14fdebfcc8d70c902b53aac1b5e9e3310b927a8b25427302d358eb7204ef09dd16db76b616080e0b09ea9f42592f8ee4bd8de3514114ce8aee120de90cb24bc96af256f8bd79efe818ff534a80d39c67df99c8ad1c819ed6bed299ca67e5b7025c7331b10c9a35e3d8a54d586e4dec6b0702a926b1c200967ec9d13d399d28f5f36b78f8e5f055e7000077935d46b73ee503613e75804bcc436205ab845104663fc66901a218266cc47fcce81ce5618e85f5339e55184951bccd273bd50cad9da22caf31016a8777436336fb2d9a0a7701e0b94d47f61fa39350f1c04c57c9a9332080fbf0e307773306a2e6ae7f6f437173bafdfb6e850b8375a6b9c28ca93dea7e112eeb3fc6a2088d948c4ad0a29f868f5b14de513cd6bab1a49ebc9cc95704fd4b7ec609949c7e988029834db53e0ceb04f423556a0943382ceb23fe569fa1418b6046f1ac70d740814f2ab749fe57a6fe56212d83f84548cbc98e521155a79123358656e6e2d2a960e15fc227bf74c5290b388bbf609bdb60c5621695612e4cf1e42d23390a63920e1f423ac05199c3716da39daadaf520ee0dab5979c1f6bf04c065197452286129b3135fda72f042fc88553ee57a7bfd825e8cf293110349cd1e35a80b5cf0cc67905dc1b65884135c632dd2db3d38ef5b61ce93e5f581b045c023c02e57884471750ec1f549172e88a7589029b4775dbf0cdc2f816b50a0295ad59e517f435d16e20fa098b29e16066daa4b354a68b90de5580032fe8779e678cd50a1c053c3c45c1562de7cafbb80926986bf6320d20f45695ef57b9560fbb7e1558c500d6fc69db2c5618f4ddd016555bfc8ccbac80cda29f9895451a8c2b8d8ec1f22cea3f37a3502d0040f072be935bf497c3319a5e20edf8f4fd67d4e2bcc32c75dee27cacaa84f01d5e7785767d6ebee1b1d31ba514885b775038e3f9f81bcef68d795475c8c3236f68bcd76729d235052ef03bde2b41af562440012fe1ab707bef7c47ace0024f6b31c88566070f8b64cfd95e401db0362c2d87ebf33e3d65aaaf6ec96eb2d1f3fb62b2651d1a6d58919866686ab46d6175c4451168ce3b6f9e2181f9d6ceeda4037c89a8ff441623593a7aba4438dfeb1d263c96472cedf6cd0af6bb10eafd3cc31f16ca02856f4694525d3f2c845bb356b2761fb34050dfc5fa8d6b73441b4647fbccd760d3f475ec7840b95c5483b2a7a0baac6938655afa565fc371d7d7c6737dc866fc660336a737eec31916b8be083f8df92faf7b0a6cc69c663773e358b98afbb408b3660aa470832b6e7e041163ca8a27b4598bcbe808fe244e859f5f5559d7a7211aa7ae213586a80a978de24879a13ee83c490b56c344c84a9decfcee204892acd35ba08353482e2345b0aa608d963166386353250cf3dfc4f0277c1617fa91959dc45acccbb9afc3e9e5e52e4790086a6be53a6799d763c3782c7db5dd6e87709961000425096e585abcba9bbffe67af1e4f0687f189259e6a39a0930b6668729188748bcbe8c37cd1885bba5976a559d66f47e5a98619884a4f841cc33066abf14f2f1f18c5d6356634b9d7f4725591162462bde6bc110e754dff2bdb56ef07ddd620938c6fe29597cff892051c683078d5bbad93556ea006008da48219177ef3a1f31ba56a29b33b47ff3d5acc711bc750ff2cb30273babd252432bc8e5e999a65e5f17604e67677b81aa14f39506945eae72bdf077bf4e7bdd2ef59d236a2e49a828dfac6ccf740916d57669078b61ea834921a1ce9d42ef06518bc97eb40d42425dd6aed7d712ca6ff4836b1f247f66da6dc47efd6435b9048f86fd678e4061f99747de36e1011094fc544caa678df025462ec4fdff153018817d128092b141b883bacceeb44657b235333622da9d70ebf5da120b6d28c2840a4b56d8df8f2411f89dbabee56f162e70cbd56737e147b23f9f9b422963eb311bf405eceafc3597db34aa746bec0ed47cb698521a75ec491f8ce9de6c5fd81214b45dab8c5b053a970f3e7b96eced8b418bd0de38760744a308c4cd8a010e652902af519de51a1fa669a704d24c2d2d72f07a9ffe18a046695dac3e088c886b914548813d8e28eb9ab6dad4711a2c848e0d20cd57f138363870291d6691fbca017974a5e18e24284645c64c865d992789ad7d8c02fc7c4c57a99961b72071036912bc1c6e80b8f24369a05c20e8802edacf19ba6b19a3c6656b7b9562db87923a46632fd1e18e6eca358b0f2aead23ef2deabdec092ccd64c7a6036eab0cc3a826f9b285eaa16a6c1faa71aaea2bd49563ff5df9d6a0e9dd2fb58c862f7c921d5851a2a61f9fee6f50b0afd27a2e80239928f11ac206368af3fd16afcdecc344a76481b4bba3f7f0bfc1085479c148641e3631f21e3d393bd215dea7de8654d916d64479ad13f62882cad180a8d7f11f5a746377ce42e2777e2c460bac4f41a18f9defe3719813ca19916617f71413adb979c7df5aac54a355be1d8ec03a908a65683d61090cdda55d6386beeb5ed7fe3c0dc1eee2b3d9179a112c1b6fa5f26a940250c3fc691cb3c54fa5516993507bbc89ee816f719cb4d9b779ce468623472cf3a70656a2479fc82249598a00700fc9922c0946ea64228f0a37f990b8a24acc9dbe8878147acfa49617a5cd105cad873194069a7fc9f3d1516ba2a481eaff0fa23884b47d60de2dc8b9f554a17c484e12344f813bcdcdb37c2aeac5c5b18a3f7d3edc2e4146718faac5896073e9fe9f3c82c132b72337d754d6c493516ef196e7cbab4f3463ef6d546f033e195f5f408124b9ec500aa41acc9d59d3604a252fb3149b097d4457ae2bbafabfea327675044863c32ece0af01869906458caec7a4ae854cb48f30ec7ec23722761949f3cdd79eb69c81ff31cc518f1aba69bab32ce4a13e18d83f53cfe8d1d4f6f41db9e22c43e0da7f4db2477e16c0f4c221542eae8e52bb0e9ab3c59ce322ed3a60e6aa279f27f2bc69e2ecef399e2c0787b3e05ba3befd665abec5b5874970fda610f9a8400056deb28eee49c3bdbbd212ad63cb1eb850b6d33067a107ffda560ea307f8fac5b5c2ff942b8ea56a389253b935def001c39475593be05b7839190f3c9641b4e1b787c8bd398a2338cd4c64b65cd47a31c4d5a6d8ca40db0c5d7f6303fcf0671f3b2446cff1a419b6b91cbaf23dd5d811f2e0e2f8a6e5f14695d15ab92ab9fc6391e84cd792d93dd38aa0bd7d912cd1b391a444d3523194ab4727c858682328a67f945dfbf6c02a734f8ac6d79efad44a1551c415ac1e274d20f73a625c6e51c766c0728cc40ca7e9e553fc35993662bd10e70ca09e5bef05aec46b9ca6f9bfa0b2a6d6cf3fe26f98b8806663ea0318a8be67eea60a525e0fbd12f8298b167995909825eeca531000272ca50ce5d7a5c4ea5a93ca6624971890db831b792bb6d0a7d5db3d7ca38fc6fb1d07d84a4a74b91899db1b51516046159710291496d6227b5c38df3d7bcc335326a3a3fac7146a2583698b9576cc457b1bb9bac0c9653a2246538959bb90572621738519fb18f22f292e8411afa904962cd909f521bae9dc373c9281d0067c285881912004deb453bfa811d66be6b4cbfd404dc3c678b92cf5feaddd7815a248a4a6a4e45ec771c9ab164f775f7583f27431d3620c2f3849852502d53a230654c271414acc7886b2cd667e7210551f48feff223b1a6b69b781792b4c18e551d82407fa52d6b74c3674d3e48acc096adc1cf8a36ce0d181eb3955e45597fdee6d2f2eeecb8412f66c4b1ac1559e8853f203f85b0d26b09ea79fae443986157", .Okay}, + {.Lcm, "-e61330300105b8a6e26b348f073356fe9ab936461d61689afdf0343087df04f8fe8cc5f8de4ea8418f204d38067787719e8200593b14ce9e649fd941af18fa4004d02d1649d0844fb683c0cbefb27909899db10666981a3c18c5391f71145a2bf9595b238fdee67286731078cecd5f4d200f8f42ebea8bea0ec9f7cf936ce7dff41491c276b8ed2339aa3c88231bcd386ae40d6c1746b690a6cee022af255e8e8fecab14b758ea52f43e4e60199bddb423e66fe98c248c8188c533b2afb14a2658cb5ef3aa5450d3c6c64914ec04e680f673442aa6a692762600ec410855b8ddc54af0e3ee019b0a3b9c975262d208196cb1095602f9f11d6c3df66889e2ab0f8b48b5e10cea492def993bc39448bec230d5c83e3ec914437ac492a8cfb7c12e3a68bf24010aafa3be904b309cf7fdf36349ad9f94657b28d433e37b873e47e53e107267cb32d15cae880371cb97ba225e0c6dc6dd241d6aaf3f9b65ba9e75393a29e0d169f74b26a462f6cee3dd8f073c77983b159b796d4d78211d6280fb6572c2b5fef82ea7ef67ac5a45cc532691ae97e231aef769d7a5c9b3229863e22d932e8e28b94bb64668447dc95709141d31e6f20242009a04e950b466207c6a5cb994cd55b7e2a55761a4f93f0af9056c0e305ec9b0de14ab64da418379159e2f342bbeb7af8481f62c0348ad5dec30e912439a03ce4a7f63d2674b6f952f8b025b875b8355f317897fff14827e43de16a13531ea681ee3d2593e604950a4cc7507e5343378656fcc67c2a75a6551bdb3725f9953d0f6b2aa20e6ff086faf935e4eae33c204f39d61b69001ee9f603a168be4d22c22ac82d0dbbcadc0bf6b389707e8cc408fd9f7eb6b532f0e6ffd5d7839733c91530bf63896f5b4376b3d2d62bed528b840ff98ba9db762d04d2de6a247737a6a40318d4a03669082bd2f0174d617bbd841e24860074f325443aa8f7553a8feac7a3286a1bc08bf0bc69fbf3296f3dab954fc39656db7e215b79a1352daadff6977ea9f9b49f02a927bc9ff43e9966256a817a5078ad12afdfab56816ff05add13fff4c82a435b1d02d19cfa4e1513cc144f0f42fc4f13e6bcc59dc26eb693c9c1998c68de65d34723abd139b1f13ff731c5756b8e16d32d6af3cbce4fe6a400ea45ca0220c1c90ac3e590969849008b040bee83ab9c4fe4377a5a8ed0b62a04c4582ddd77fd1df28689159ea64a2bb80b5d23c06c3367f2c9ff9a5d8a35492589710fc191d1d3589ec8d79bd7351924835d6c0174be31a7a379c4ce659fcdff9bbfb56b796847c3ebc1fab36ca63c4390aa4dfa78660f697d4f5b55c4a53d360c2f8796579bc9dba88b29aaeb4ceef033ff255d4bc9bae54ef1bb78bef56c86ac69d0134167779ea4d381419f82150b3f6d71bf2e41062b6eb76fe2c3b2581e6cfbc30b9941bfb5fd209bf3d5259bacacde2bfde332664b1dd169619e81305a6e71ce23ba3c1976e8424fdd61c6c1f779e5cffb7622745ee1786c9218f5828afff51503fdd688c45e5206e707487d426735e386de5df62af446b27c718b11291d67caf287fcce1fdb58a2443b5e9ca70e828084f06603044f96622e32fa6db3d3b1566bd77c539b8f448661014e8bfb1831faeb3a2d0fd27d643ab122ea228a849957601c71c53d9da3f7a1fb0c3de59e3f464208758eaa202b8858a3c0b9c90e1d7fd54d2880e47aa94dc244deb4c1da63add0e9f6b3617452e6630f04a558c62797a1d4612a4576f1a1818faac64f9cc7480a5d76aca4f5ef434f30876871d5ae0b041d8474da31432aaad7b16389a41d4d0752e0a2b410d3c99cd0f6f2a6fbc1991050adf7bc2ae827a5365b49853ecb4634d094c46e5e2c5a4f220980e41b1a144b6acbf93f5209df508af90e0e09f417cbc16b31186be193400f6768c6afda442bb299f9d59a2f4ba7ac37a47edfaf70fa9e22626ea01fcfacd4add7b5001c28b560740d80164022a6b4a58d0fdb5eb8759be49070fc032b51fb39cb4d450328daecb49e113219f36a6345a678716a9f3461b85f6b73d70b6f03e18d3f34c93b8bc0c1ff46ee6e3444d633926e6bfafc948e4f0f78b9cac93f27759bd1879dc7b2f24acdd6a", "3ce4e0cb423e7ea7e2eee296692c1401f88e84687ce9382ff0e29c71f1c9abf2322ef9f1f49c5df2d3a8e6d835626350d8bc46d0004c604e6c0da20d4fefb0a46682a387e0512bc56b4ffee1b745fce66c22cbf24bed4dfa01bfa4a45e4eade3a262c5e42038e144ce87f53c936586a74db6beb612ecadc3ba1388acbf9ca3665b0578711a9c05737dd195c44bb8897567136b59cab9e0913cba4e51432a44ad293e06a0adb689da1576b6e4a8bde85e765dca4a6eef3acbc137586dbece77e8414ba33d1e252a1c1d8238bfc79ff8b784ed0225166a7b8c6d9743d8703cfa9512e1bcd6f10b2a1c0a0a5661b10ce743892c9826a8cf40e9a530880f000c461f9d178e073e819683470c798bf068fac142d6bf65ec83f3476d7e74b093c9f43b65fe2e058ce6375b29a5adb15f38989fd9d55cd537d6ff68e5782b6fc8bab863f02b473b7b56c76d439a29f42c32ada0e6d0a0fcbd34d83ee0e8b210187e0aad68034ea08094dbe4493c84e867d73030339d74379637c1b3cd3c366f35a0e0aff82c66c079574c73de5c0df85849c1b523e57bc2f70697136a6865819d622bc83adfe576cc412039130f410894bceef2c5d489102240de4809f56b99fed8a67bc6a5eb16d228039be0dd0f95eaa28479738b2980be48bf3da6d9f0b952e1764491785b2c8adb2b3aa2a663530e0173f79ce5621df06956963b38ce7e64bb44459d793cc1d2a3d37221c05b1e375b839c4d2fbab9643e2243656df7781201ed87d0704f992cb5b889e8b402747b260b5b010266095516f5691be37a95f1c254ea6bc2aebd832ea2aab770ded54612d736a24afb58c4a0e05a3258c8e7f5615e9c83d37b642e5df8d509c0e0394414c14d5addd980b227a6dc6c1f06fecc106be59d57ecdccdc4924e35178dc7ad45fdf9094185cb462b0f2dc450fb6a2282a6d43962f3724d0e5dbadfb97ed44227ab7ad432215358a1b6f6de6c0a7a367c8ab4d849883a120263eb4aef9c263e24f67969004c5cc8b077e6d41fb5d373c7da99b9bbd703ac3411692e0585aeb7a1bef8442ba3f9f5bc1f0b9909a3186465c0aefb5d63d55756f5aa31edcb4e954f8f00880f048ef968a10bfeb7c2653d2dffe71c89e87cafa99e0c0f19657f2e9c6013586922c3069c9427ff04f9e9e6236b1ab9636b3d1618c49e1e866363b84c723f295ac31cd45d296b561e8951061c72853447e1c2947fb040ddb869e3dc1fb99e2ff725f5afb9c304eaa731fe78bccd0191ff17042ef5db52ffa57592acb027068142aa144cdc00e00192630429acb2884537560386d1d49bd28c9251c39238465ee1e4044240a0d9ff309b5f48b402f7452538e19a29f5305a61a16a6d523f13f2e27f6fcb4b8f31ffefec258039e3f64ae572e90958b26f0aa63672d172277c7b60ac8c710891d53c1feb07e0ccf6c61a7c98d3521af1511eb9d74e5b5cb032543afad8a48557bdde466679bd9ee7aaa3df006d90c204d3a3ecc7df35ea740578c6657382b8fb7cf2f7bc97c39890fd07f83eaac5ace68e02a825f7aff1ab92ee6e4d8210b8ae19cca91d53559e15515b2a400696e48e173d63f80af8cfa2277af9e16569036b31be933cf753a954267c7e9c77cfda8a7f801aa81d3be04629db1b93cbac9ef8d48fae454e0f28e7f267c7dc140207d6a58c6e6f843fa79ed4b71ac56ce4f27527b58c48d9898313f79587fc4f32afa631d71abc0e1caeed5a897e9c0f9db672ca00873afa37214cb9a9950858820b4a92759724787a5b14a07a69552beac638ab038b231e208afb9706a48a4f133f76a5da415dc6f611118e9e5e773b64574ce884abcef7bed7c117db484bddbe558826a86e40b2f9d2d6421d4775a0c48425053ca4af2c827f2b343bd97d408a4d185ff033e688ea28488444ed9601665c5d83bab0c9322390a7fdf5546ee68483f37a478b5b9052e9c7f597d7f3dc151cd2348c8d21a410f2c9fd6796b5101b7b79c10f8df0e921413d6a133007ccfe69cfa730c16af1f79e1d9811a34d4a4e55aa9db836844718cf1bb66e25ccc415baf72c6318cec7a370314323e37f18775d87c146084d178b4ce2b16588fdc4599deccdb299f18f", "36ba3269a1e8943bc2e1a5143450710ebe726eb54e9cbb1254d826dab17638b280f165092f4f084a1978b2323421f623ff270c96ea419c212be980ac424e3886bf31937a6351d2c8a668b96c76d9936b81d65f6ffd6a6b3034fb790c64475253d448738049245d9baec1cc5a1ca706749fe5e72687d03d800b3883fea2a11dddd6044f3facfb46b661e242284326f93195ae23d352f12c1bd7f3921ff6655e56dd7c4aa697ae642df5ec7fb95a9e7e3ad9665dec2d556dec519b938ed497ad7178924688b0bf221c1024f61b82c22b2c88e72a7c0b2ed09cd43edae81e09974289f85eb762cc4be07272bb6a39fa74744f963a3e6bd63a9e46e7865d79c57c51dc1d1144f6105a40d6918be0b33cae88200151e0bdeadefc1979335f074d4d650bf1974719d28882ffadb419e796006258ab2ad0ee942a4e42a1872f0cc44db1c78af51d0d1a6fee14360657b11e7feb7596897a7937595992d30622a8e280c70e2eec4fe74937c9912ca06d6df6c28ab14abf797565a2584d1a713104f16ceec1c4e1361f5a267ec5bf0c7449f2ea71ab73719c6d11d5b5bbab54e840a92bf82675baf50128b6ef21efabb94043b99e49a846d7548ca26af3dc5b1c05b3c00346281cfa0806a69f67bafa7ac3b3979bb3712bd84bc9d69e2aa6c39aa928d881a3979ebca6893d3714a8687d2d0487cba21dcb84d78fd76bc03f02d241a46395bee61cdcb1101033c5bcb11b9aae54952d95f8a8571b89505c959619726763e0688f26d1d26e98129a6c74a87f504f0d8eceb92b8a301f5794245d9989b80d8b05b16eb5880c0028ede37bdbdf8bb39a84ce395adbf26f6f0b7534acb1d1e7248b09e2993fc6c8859741f33c8512891b4f7a6f27b61e2e949a9d0bf4997ac48b4a80afe8c46ccd93c6a5dbe853bf5954e7851e6e50895e1d6834658f25992da4b967c0abfbfa9d2c5490e15ed8b3178cebc598fe3cc63135dd7425e333481cd9b46f2df386b0410078c96a4066ae9ca41d8a0261952866866554ee5bfc4bfa7f82e19070347102020b7e112e4bd1955b2c4c10f6e306a5ee1e525877a1fa865b279c233c63e263ea0f8ded0bcb82ae766cc7e530ba53a595791d4d0201cd2a4011ad3cff5e66588a475e72682414c303ec4a72881a1e399ad5a30c2b2409ef874f53013ec361986b405f0373cb88ad6b6be5280ebacd0bcad15032e6fbec75dc391942dce53ad5127a1a4705e5b51962f71ecfa6c10728e7831bf1f35c8368882870c3e2d9d5c79ef89efcc95387cf0c6c41a56d9001b80f66395fb48439fe8d0117ee323260db164182be59e18a713a024117421444e05208102b350f972faef83910d154b165d40f434b705cba1d346d2c4d191838a021f45be4aa6a77c8b961e3c58e5e24e69534e2b1716d81aa5ced3b6da3860be7fc9ca5bbac3558ae14af23cb6ed13e3014e2ed9a2214b2c54f90cc26502971c2be0531fb6089cea262e39aee806b0b9a56c8d4e34fecd16231ceee689c1e297e2a124f8ababba64e252f51d6bdf6d8caef897353df12e803a4e6885b56373649e0077af5ec76e2a2460af4a0c787a8fde770e22efbd9d19c334648f9a16a68237ba50147f213671c68c39340060e55fbd6ae3857c1734d4bf421415bed19ac5eba61b0da3d5711e0a55190abd954153c8b63d3396453653e1f69d96546f8b6d4505c1e4076a08685cb1a4a8bfe81faea473f71b8f788c775632e2831ea39e48f2d5e4b2709f5549c75317d5b9750f0d4c3d7b77fcbc01c08d54d6e4166ecc0c27c67390db7ad86d996ed9255f28d4e20ec216ef2ab72730bbae283a105419a188c9fbdf3d54ed59ac3f6fa1951fcfcd2679b488ac66674606d98b3a8a7fec3f5a1c4c83bffa2a7fc4caccc6cfc60dd8e059c607b0e5de985e897dc227cd6d686c0b9a152f48369a29042fc748f720ab56c94db23fe3e9942a8f23a74a6441430ad36d637020b2208fa9463d779855972a5935bf1fe1f6d879686ddefa7cf759269ee850eff8f60c8a3f4a92c4435c4b809a11d5fe1a8b9c34b64fb252119b8f5b831844a1597ea4bfac1d8927dd794d672a685477a79c0bb44eb59c50dbd39f9aaa8ffcfe8793cbc78e2cb4477028a6bf44864036959c21859d1844123c4ab629d4760fda78ee5b9540b69e9d5dc897135a449270ed3f14d1a4b834fd3a03718efc3a6cc98fdad4d8c90cae7cca366cba93ed92863804f5792cddff5172f2b3588c7a4d0c11786fd948a571eebf7cd270ae6d3d304dc811ce8307226cadd7e739a48f884b5a5d82c233b23d73a85b6a487ef58aa4fc0e8a752c2017ccac950c96aff3f11bcc2eb522cae560581a68f6bc3e92b9907a901bb5b0ed2969bacd8200747a1fe43724be5d2e31b0271b05a48abee288b8d143f1661b1d2e0a3aeecaec13fd11fe463d5b780f0b2973d23086f31d7513c4a434d3c7f5c841630504c377750a6ed1b7817f82e6fd2908ff52926d0db9c5619ca5e27eee289f6d75c79222b636d122ebeddbf43c29f333a27f9acc91fe057b6b0cd2a964f1bda170bfc73d1dd99cd8c5e0471c7f516c0e422ef3a94886c03547c74473eef4469da1f23dbb5a12d2d582931ea1ca1617e459901b9dfd6e14045f96fe473a6905662a4741dfb445ac718412c42edd7ed2f6d57b5db2f5889e347648b887c5ee248297d4a902c71755bc328ca22c39e879095c530f45814fad7506ebf938a409c7e1fdf00f6f7e6d2d62487d95e0be6c14aa56ccb64bc117a846df92541e92bc5519d04407cf78917e87037f56e0b78ea1bb4d7cd9a2a2032f11911f3642abbb552999c4944a1f637dbdf5ca216d0e5b95bcf94a8e6ee418abce7bf6b2ad164da7978d25844c802446bd46bd69f03ca07367e48ee278cf7f6e091b9ae88af451a5874eae424280005305cae5edf05052ba25e4691105d378b52e4563ea2736ef9917e1be4a1f373c16b4b7f9db7b46280ba771062baafb269aefaa0457c04d8a9a1e04aeca773777e771cae0447d9a01a7b5fcbb008c17e02833ea1c3dc2628761074ddf580efc2c554fc87fcc7e09937ba208ed8c434555b4e74f76fcb090c36b2e1e9f3ed8956cf837effdc5d3c64b9dd01821947ecd8f5763e10f61c1f2dd92af32b5fb77c8bcf9630ecb5fc98ae6decc47d4c216afe1fd802dc924344bd2cf1fb094fa6939d2fecec6ef9687dc78a1e374016a7553c8c6c6af616e31d62b30798d99080210d528c2a1f2af67ba12adcb207c11c84a5f1c8b751e13ec85b99b4f14b83bcc5a0a5fd1cb0330bfd83aed35b0b938a2f8879c35ef1bf810acf88f1220d1ab9fd88b74f8fe8d1b7207cdf60ce2feef84f81ba89fcbd8c00bf97b305e9e0a46ba6304caf373885995329750fe1124d9a0fd33925b97758f66a3a11b5a61e952fbd931c552bb666422785e648bdbc0942ce0e1ce59cabdc619bdd8fe9a537a50be72e3a907d5b56767a7666395d186943e5833977b09400267b8f4c11aaaa341db28172d5b704ee556fb49a4810c4dde162d786d5a388d6e6803857580eaa3695d9cae6ccd760c794a74477620a0268cbea007f10b66eb32d7559a1b9918fe9bd72495f56efa1f9935ed7c124b31a487ada46acf0fbcd7160fd2776f677c11390dc16204acc7858e494db0bc25a6d9b85fd167cb8304c204d258dc7b4b783071bf21fcadd30936db9ecfe9d62f13f903d308b0ff749b09ca5ef4ca9f3b7aec255236012e0adeb9731c1ad2297d4132cbf3a9b105d4515c65305305353e3fa9d04bd3c200d57816a69e3d1030f1ce2ec11f5ddd2f4753bd97b3660bfe5edbc513c2219c7ac4aef6e636fde707d179bffe3beb80f8068d49935673bf64ebc128d743e0856f773f825eb6703638e0dce559dfa0dea5b529c6880444dfcd9dc650a093139c93b72529a676d9d4a0c257a210d3c433a3994cd49e682b4574a0285a545e0037b494f3bd129c0b82651d583a8641be4e8ce5b51bf96c859f8e315f94680108941b61b813715a4c58dffbd669f04b4f68e52fe55f90f5e13062af798ccb3a0686c559ceedf04a94b97094834ef58ce56ab2825176ad37b7ef9e29ff95706a61b89579f90473bfa0b732754a5abb6843d43eaa70a15b1f7416e844027929cef9c64e48a1f561b55893ad91b3b9827cd0a6a7956192e81147cf924ba179eb43813381972ab9dd5b3d44de2b9c701bc6543a741b652c3c686675a5402415a7836", .Okay}, + {.Lcm, "-2233409c6057a9b7affd611229c4356575d9eb1fdf0d0f2c003ee4d7fdba81e91c6722cb6b4c3043d8937f3aef02ea735191d26f22d2ff3e3f9967a87ebc98e82df487b8e16c62e62b255712e20302a691d4cb75efa5436031f30c7bcc7743cc5f3abd64da28a772bfc10b7d715183f850c5f4c69494b5c2c233557134944e83464782ff97f9572b6cf0fddfa19fab4cfa34776a62ed31a8d88b19d969e873810c28c92088300a9dcb036166ecda649cc6c52cb94b5a0c85b87da8c0c5105aca85f1c0720d96d2569364e43d1d7f5d3fa79412da4b5a7908604c543eba7e942026f76832847458369de7b172d1a9e4f27592a57dbce0311a8871d6cd1e6576581f7c8777e3156e13324a9eda9d2355f05c60d75c7fbbeb3c78c57e0caf9c421b1b8853b5f57d64b45130919e432eb7d74976c30eb65b0674d1fc4077dadb19e78af27f80496800aec6463e92894fdf60a6431cab07e57a8660b3194b716a46bc2fe69a603ae2d22a1c6f602ec1a5ba72f67cda694e086f222776d26216387ee9e38e5e67e5af9f1badf8f35bf4ec6db256f8d5fd9199e2230a5fe046afdbac08109efd9daad62c326c34ceda07511f53f10de88fd9c9936668b7418612265c736034265cec2b1b5f736ffb6eeb142803edbe95a03bc5af9b32f4fcbfbd9b4f0ce1b2241cb43b0d57f87a427b85bd80046a36d8076463989bdb36555fe2f424f8181ee4243811e2ac4077130edb88a1093f69efb24ade69d93613449dd34992ab06423e1467a8c846b74964f0cfac20b7fa6a2215f0c1125cb16b62673ed74c82e02df98c85731084b04f39bde8d91d29f77d5d5cf2162d33e151b054fa669cf7b474e3ad78b20826ab3f11998598bfc8d826db4b209f34de150e287c60168f6b5d81a284b12439ecfb268268b5f04c84e5fec508821d2d45faecae97c77eb6722d846e3c6e719fc3be7676022d8e54620265ff6284f96f61c2fd3e2d31b2d01886e5790460f3b966735b3be0e0408fc34e7078873682ab45b4b080ad725ad690f2497a2769d65d0f37ffdf9da00e05ed6d3be06e7f0e9a4d0c41ef898c46b031384988550988ffbe77182bbe3616065cc2c6d05ff046ff3f25a9b70ac3f69748018a16f08267d0750adfe975078a7dc53a5199f00eff8a9f491d9befd7e83c37193cbaa24c3c77c4a92ae9e8f64319a6dca1570fbef509d542029b175f838fc78f876e51641e7d47bee3bcaaa606ca994d13ddce1cf7305ce18801b456ec45c53d0e21471de32fdce8ba668f53883f0952d1337d63dc0987c5a699d7a667abe00f65a50e780761c771f9c39bce14f8720c48419da74097a9326f52fb21d30643ac2cec66f4b2977aa6e58b49ac0cfd89d26ef58978c86396a9c7410e5ad41b8faa34312df00ea5f8077dab72f3b64e089d74e47073b1886b00d2940ce1cbe1690943fc995f9ec04dd93500393202d420ae7e00d3a53b9ca829dd413e1ae117f865e7f2b73e9a9d37dd33168be50a6445559665bc4fed28919bb5437d9fbef4eedfe6266b4174f24b3013f9f178f2fef466ff7f8d887d16c6336258df4ddf25bb2cff5e3af4da3c522be50fdf60df9d8a5cf6205f2c96ab5d727b7646afc9aa4d96f49ce2f0fc79a1cd6613190a69b9521122c6f1e90571a053d566d8ca9afd2158cf42c671119ef9ffa7f929b50a494cbca18953562156b55ebb30b2ca4bd629224f7bf900b36dfecf75d60413557813f2056f05962912dfdb401fd33758027f10ba61b000e1dbac6d05f5016cb75710d71f4b4b02d3a30324c642d5ba3d7ea5e6a79c03c3c70e754e5417d2d17ce18d87d33f27a25192a1085d6f146de9d981f1664bc5d9920ccf5e09a9262cf8ff65054886a006a0b8c3fc113c5220d678bea76b4a8733df02cc093d4badc1cf5782d0017b75362cee7f1b06367137d17bd9b12158f472078ab0a394cc0ae95245d03625fb23bba32599956a4ae98fc1bea83ae1f45e611baf7a06419b7911e0a9b3aa8020f610d4d916999a5bd0772a6cbd4f95aa67cbae1617912874f9af8b7402fb5444b91eaa68b530d73a4307ca78e4e6e220d05d407cd2baf468e485dfa8be127991294ef572c00e422c6f", "-8b54293296dbf229cbbbb46db61962aed91075892c1e27cac54e00b14d75638f432585a0a557db7b0a9f900df4f7f12170ff5b18c0d7b511ffd9afdbaa8d6b36f3a3a7292c30046e834ffc3643cc2842c7f14a9d3d4952edb4aef0e86a684bc093026a53906c273ac64c1ea2d8ad5c9f7d5eb0dce0265b6c84ad49e6ef3fbe60162abd34db27884613a73700aa6104cdb71d6c46bb7690e074a353bcc9432d7acb52a26378a520f967d75c30af296d18f2e2abb2336fd77495ded3579cd8cbde036ebe244c2cbed1aacfaea09ea5754b1f0b4eabb49ea42fb9cf2d6a872b533ef2bc912c8e745ff57fed95dc2916f56306c90a8e8232861e2643fc2a31df61d5ac19efadcb9e1c482b4b3462f99530c6e277ec0793bae15a35069e4f40fd7a5c8a782207dda3f750cc3e49f202f194bf816f6032ea3c8285e1f1e76eea214ef23d0108269bf29aa955475233c62f461d4d7b98624714bffa3bb3bf3fb45df427009e2f8f52a336c6620ca4d7f82bab2ca2c89722490b9bdee4b210dce44bc41f9c08ad8f3f20b6894fd7c2c1e602b487475ac5ded6805b5d3df18b4c3d08f66c4f7b102c37635262e0101e3318f11bf1c1c318a434d8e42f157266922353afcb4376353cf0dfa2862147efa38a448f9e92f67be76e42e111d6e282379229184bd72973d1f9b3679449d59935cbb0896a3ab29d2d34045eda359a067ad29635b4bf9e49171d8e7959c9dbf2c80240a4ab94ffc9b393a45b8017763bd6f8862c388847076e86e4409e56e5e994c6d4262f615ff0102e7706596c75e6ea06ca0f26955dc0262b171a889d12e0b7999e8848f93b70131d8b420933eeeca9118acbc29a35fac7d5d2cce30774c381480f3559dcea5d06d0217a252cb4725daf8d9e75af9308600759075f30d45c1ccf0417c08cd665832ff3f846457cf54895ee6409432a3f2d4d48d73163c008871a86312dbceeff9d7ee1193218000070821106842e14bc28de32f71ea59338ea179a79f149945198aa10776a2f604856b2232244105f90d5854365d38e9bc62d4a9c2d993c6e877ac4af1a1737fc859a4c6010af2c77ee8dc784f592b8522257c78857f6ca82107c9c841fc7534c326ce3fe1cea0b6cdaf7014fe784b9eb45b22d04a8dc175c48224f004ea88631c6086d9cee345d12f127680dacc6fadda6a4bf232ed1a400b8689a3393871ac8694f9452bfc4a82b48676010a546f4113f72222a819378258d9ecda2f48e26e0324085e70f27f7128670daf7f205f90125cc11a070dbb52baa4c32357a333e7ca9e8e3a26e5e425501c7ec0ff42b22ffde71ed69c67e35bc252cbfdf5e085db86801eaac0c95a2b3dc6727d2daaae92e4e3a389cad46174f6ed64856b6b19b6cea00c66f30f051ee50a1a6ca040d74d97aa4953a821d5cb34d0d51c4afcbe4e1c17f1277de3b64c225cc7af8185f3697b68032a42b38ee017b842904801a749d186119b0287398823b2c249c3ec6d8974863c7bccc473eeff804a91c1d846055bee72f8bd10c38ba8dd4b321c7587be3570f3db77791c5b9cb8e81925d2010b165ae5887598653fd920a9f9d0820072b90f9340abe1c81cc5d2eda8a4ba540ffa9b5a54f4d8ca45ea747b305d791d96acfb9114fba2552698d7ae6736fe62362015b877b4b537346726ae0e5d72c147ad38f87e6b4bc686f80769f2103773a5a9c3fd4455e58a6e33f5297a1eaa0380a4c3968ee00e09d3cf09ddd2385bfb0e098b55ab3e634693cbe401e41a77fa6c011e2f24acbbf2243db59d07ac3975607699f8dd4935d9ed4419aa4e6ec338a3b0bdbc8311f9e50dada298d2ff527b349ff2bb01f46cdb99d734fcb667a58ce9384daf265908e43176b8cbbe0ab181103f9f0aba1315052980d14c535b4d244a1d025b469ad80af973c5c6e6233144074acc2ec4186f39023cff667a8c96365c84308f9c3342974982523225036955e168e265107262da5321d8cb03ddfa4890fa92dbbd4ac258fa46ee5c9b52e40aeceaa3b88128dc2e4319435fd5d51287f1b2abec86c768b7902b9693c1d8f8e7f6ad329e531ef3aa50debb814408212bd6b9523383b2785649de02982e8cc91ecd2c790", "129d1267132249f136dc903dac9c2117563b21769df5ae8bb4d7887c946b1c453f141318c55f1e5e7034ec7e976099d8d1e2ca737235b4ce0bd53b2317479c55c10101524e0796ffa6e9f1abeeb18d0a8236b28a3d2edb309d364f74ea02311cc863fccda19f44e86f34388bae58b53b5cb817d66efd1f247fe0ef9bda82b4ccac67e55e253911b8d966792c76f7616dba13b4d826c8a7679bf6dbd4983232f7e6f1866a7933ee12e33e8b1fa3cdde2b47e6948c4fe1011dbc3f048936f2c1cf94ba05be4c01e46d6ba8577a60c257f760c16c00c2b817abe4f017553682144909669d4a9e4ffd0fe08cc0a9f6c4530c5e38168337b6e079ca833cafa67c47b1c8dd6749150047a74b99dcda8a77e8422a863c595c5c8314ae187d7f769d4dd9f0e5f9c414e13c8aee31403368e36eaecbb7a4dbd90aaf148fed640abc294ac9a465112c36afab3b78861952ba4c5b29677f131d44e096cf245707c1551dca8d7d47d53dcd1f37c10997b80eae88409c89aaa1d5b42251d1ecf9511fba0ca28005777fff5c12f6eb8532ac1052e808650a68c82205c6f7a7811bb76ff4585686684d24216cf2862cc2c55f26e61828e207f36775779b533edfb85ffd3dd058e9ff6eea2eb00b810e4c47436ec835e3206a7d8db1b8f241d28257234d843152ce5b349688e28b040da0b170405589a3d53a844ab454d6431c5d6c13b5877e1cc687b8629491035abe8d28b3ce081ebb086cd695da8b6a289102d09293c148c4ea48acdf0d3279424df8cf39a541b41d9fd3bb34c57d547478ec476da66a117989850848e15e1f78f280dfc16a24fe5915d7018a64341b6b22967a765d5018e0918eb99db202ef14803df81ed4e03b44dd3abdf5ef60816c928282ad7c769d1925bea525afbbb042dd19ebb3561bf23561df1176fd9e707d8930ccb7a8020652cbcc71aeef866230e90f22628bfffea4721828b8172d6e33132e4444b419f9765e2236db6483b435e43eb48b454550c629a0dab00ea80fbd3f12d9adafb4a8a98545d149bc96c6cd60f0ef113deb4913c84478859af5387a52bfa7e71ba02d7cd86eddaa595295d5f6d96fefbba1f28eac127139878ed9dcbe4cabe70a439a7ca15791702227938020f4b57d1861be66efc4d5a895368c47c2bace7c4577825786903f89c7bb88bd050e79def5dd3a1a7158325afd2d499e9da903e9404eea72c19a648c13d40597779106a9a3899cdd7442d910938b331729a07b82d06e70056095bf7cd1f0f941dc9085f7d3c02df59c7be4907b0e5fdb5e766292bef8d9cd0e8b69944229a64393410b114bb2d2e2332e44de4b3f9916de02d9f260b0c3fe6725a206dda3876732a9d1bee70922358fbe9bb284bd5c551d6a414beff76f4e303d0270d8cb6a755a39495c11e025bea40d37e9aea55e15aa5665510ff6e7bb0f3e55cc801d8e4979209adf2c52ace2a5f85b25527ad4d2e639724b8a36c3a24928b743fae7e2a16b0ddae480d47d6369b89237b61eb541624d5f625cef2a0110aa59dfee80efdec20c27f983db186abda6dc2da7d254ed08a7fb97c427512dc514b563a99f3c516c54ae34d15396295dd0a1bbf30899bbe0f071e52e328034ebf8e7f3843c5e285cba92092eca11dfb62698c4f849788bb4b271bb4ba86cee7534c42b997da9c6fcf054b68d9ce6d1df78f578c70cf7355cdd764744e85919ff5f598f5f80ce21a6bb865144eb2325f5a35c03fb170564872655cfd25acb6a938899bf4f01f2e5aa066916ce6b8affceeeb679e31fb2c24a8880d862fbb77a4aa0045c134f260fd6739a95e9ecbae2eb9fba31c407d11ff1171a8f844509ffdf63b8282126bac4f1970d5fc913e1b4dc7f49f71dd0b91d0db5aa18fb6911772a835501331e5bc82b12f9b59bfa10a3eb5faa6029112cfdfe2e3151aef618ff048754251818120de2a5cf1b614f2dfbdf1a136b4121e1276110bfc5d4f9bb020ba824668cd61698c4c6fe63bf35fd78b41e95ad9c0acad9797c373ea2a7b7fc626b4e728fbd99bb911e46c388d03e3f8290bf737dbcb4362b1c0ac50c99a6293b06c89d4f30d22fae3fcb98fc27eb22eefa55dfad0c5ec736c65ef18a722293895cd534d0c640818cb7d209a1ce5e4cdcb2ef770b312c4f3980e48ec5c3534367ef3f8d95d0c352c07ae26c10d9ed3402f7fd338ef32c49887e910560274cc221a41149e2f03ebe5bff982a6552925b38a05f2e97c4ada07e546d0625b531ff7179282ab53cc85220c348cdcfd1fa42397b449ee39d8e52256b67b8f8554d0e81d21f78f90729032dfa76d4bdc52759fdf1683510b873ede3f6922685c61b1329eb7b4c890d96eb30b60fa5d206882182471dee1f3e733e8815d210a8c6a19b19ef21dcd4b743efe2b5d5cf23f89f71843efc327a1969248353920d8e89a5e9712e946fa7cf2f36e8da195e388f5065bb4c6bf38af135f95e759ebe681cc90c3185e0d610a2004df425ce8ffb62553d08ae814ff263877e6ad860ef5c6b9b0bb88b24a963b2deae39883bfbd90d1ee9186232bf225f80414a1d819c5757c07f7e97f658754900edffb7171b88c59d3f8f1dfac5fe5fce51b3a7aa5353ce973246fab5a28e9bcefbf64fc6be311736a5a436a3883d53ef773780f679e3550d82d6ed48ec0c9edc43ef9b2c12f9065e4741becfe92e75d5097d76a0be5fc7242d64f6e6af764d8ded4862dd100a9142bc495c3198e57fdd8fe0bf10a4e4dab2f5cd3c3179c974704d3d97922c12b43e3d9598f8d0a5f6781b89ce82d27e13cb62ea0087a729afe88ed07b4a6e466f2f9bf104c3b8d213b33d72107f0ecc8530f01ffdada129e9069f2f642c347968b18025635a731cbbecdecb9cf75b79879992056e548c786491c88396d25bedda01d92a6c8229ff6ace61a42a20e66e9fe18e375f6760a868649d0c1433181af4647d19d4caf8204eaf08f89c7c4cefdbf7c93b1e1934d65bd5d0c03bf9e74f8167087acb23590ac67104dc87c3653b5b0bdb8c280790f35375d1c5517d7e238894e40dfa75c3d05ba56d319f7e74acda8b7f405053a754b9c8e4fd81840fe3189a2f621fa16e4cc98eb97c3b1d66d5c154e9640ebb2a6eb2eb7dda216f578a2a09d0d973cb4b5b71c9c89acc5ecbc60fe228952cfc28e53521a418ac5ea24231dae5a414fea8d6ccef01f6242286d872b23d06e7a4ce51604d66de72c36310c505a3bab769d84180d5ee7c577a963b1a0cce7a876112f6683a475d7f5b67da36cad35934e8136b8527c99b0c3c65734bd8b549a2f137a813240139411f41b8e04be16e56d80b4870e39cd16bfb6b2f2071f935d7e09d942de597c1eefb8f91047b7e76ac4e28b9e3bc68908008bf96767b4eccda64ddc7ed14657ce7a0b28eb3c19d5b01630a27b4916f34aa3acfdc31eb3dafb333e95f5122d6322395ceb90267f405d46c0961cfa0fbeaf9d9c45246088d7aae6858fe5015a01fbc3e5e8d9f017e1ca27a6d621b8992c9ddaee9dd5e1be9c99954ce783fdcc5f967ad27860ea1fae70f376ff6af0432112ed17c3f5d68e4e24f5d187542bc0ee3845d999b2d5681d652c285b7ea6d8eecbeba72d6dd4eb37c33634646c0cf22300751d9832d31adf1b8251e0bfc369e40e2154f704459077189d59276e54779e9a28d5a70676880f6158297f30bb53a4547db992d3dfd3e4573b7227032f80c0d2841d637977c8a8e6a6f61102cc0c2fb16c2741c76a896e60cd4cde4bfd341baba288da9af5b7f929a666b3d927cb0d827f9142e13b4ea8581c2f7e91da66f3f94ce2ff8037a2aefe0e2d9d7d2b56cd4c95fb6c2273fd6822beed7e377f1555ad3342c87dd76dd81af749975fa546cbb9cdf617789d9b43f222ed352e3b0ea167990f065b6390c9bbf0ab12d383bce2c2e09bbfe8bb6d87b2655e5e8492451dcec8213dd010a94e6aef08d755e5ea09c88064a940a50109de4b057c5d8a711ee28c905f473e90905203c6a85b7b354aeed829ee6be5e9458da58191a35472769ca4ac0f8c38c8beb9c2a218aa763c249be72c31337c941e9a7a1ea43dd814738c30325c179f76ebdcd1c834c44d2b1665710910ba7ba61936ad36612828edeb8b1dd8a7bfce4fde172da29a2685a4ff66f9c67e57c4f2395611aa393cfdfe120e325028f875c929b39a363eac59a8d5a9bac653d9cef815f490da566b7062d0f7ecb3eb0ae349d32d670293b3cd14770", .Okay}, + {.Lcm, "-ad00195f994bdf4a5e5af19f4daeb881bb7b02d405361a922bc5ae3b3a15d616bc76e937767a2409f359c0ecae45c3c13d70a8f42b2528dc17c414705f83709c4200f74ac46644d49f405db211946cf3d06ed3c5fc0b145207d3208e835bee56de50847802afdfcb3058e7070966abb00044dbcbbed8068cf691d744b4397a3d358906da4d4092f011d2b696387a87cf271a48991d4ac46ba0d5e24c335a47c43e726d4370f4dd1f9fcdcbf51704162636ddb5d5342f1c6b3d27d8fe95b9814239108a9c7eca9d044b67db4ff977c82bb5054c14c23f99dd668b38bd6efef6f59e969c2c75fc25ba8c915d53a693621cba739b54f232e7c90dc2dd049166c22fd2c12c7e1100f5de78c505fd1eb35de2e11cc2bcd3941dc033164e4126747b6b2ad321f7ce50bd685ca6b75df1078892f8d7bba34ff070ecbee9ef3ff88c09d8ff26263a5b0cb07311755a0d24e4fef77413dc8ef27e987abec22a320ca9d065d21977f9207a19c93e88f84ff6878cdbdc2faa849e976b44bef1572086113cbb82d8552dbd36f547e863bb0a6210ec82e890b5cb5751981f02b6d3415fba0d32673b591e8b1f11ade65bc0966cfe6793a3477d2b9fbc45412eb5d9041a379ca93587f76172567942bd1f8bca8efb5844747143afad2308a5b22f2f41baabdad9a89e62b1578017af60a385b63b1e54e0d11dfd89cfa2483240d4a5f1d192a1bc0f054bbccf05c7c4d3a1608579809b80e64f6a9df5b9ddc08d55ac9ed539e219cb2b65582587ec2087de7103d3b4f38682df4f81f385980fb6d49588ce31a3718e6a2a4911a634a5e0a40fe09428b35450a6d1868808829597bb0dee8c95c05cae6aa4245858c15bc8ce82f42c5ed233706ee600195ad2d4f49e467bdb6b963620cbc73a398e1893a8f3e1a3e36c1beb26e79e6e0348116ffe5dd7870549bca99162d8c4d77b9d26cafeb4f1e298d187f6452413c0dc8bb81c1c26aa43b3c25ec0bdf9e8cce075cec898c1e39e8c906c03a30f0b6b9216aa3e6d9099260529badb1a9375a272695b31a7cee203c17f50495f00b38e30d42b3efb6ad3415aadd9c4314d9bb2bb1e22d91cb3fb2db0e117b505194db815efff9417a911f8cda2d8b96646d8a2d633e00a1d1bfb2cbb9db3e354dd74c7e4b57250b971f4687415dae10679ec4846ff1bb0f9fb3b6c2f0872672a60b3acb3795da8fb016b1d2102f4bf41bb3dfed63a90fec658d3294a44edf63c1c7fcba1c054e95f6df5babc4a4aa2bf315f07e61ad769f4cd8127632b272553476963431bb1bbf6c0d8e124fa5348b08034da31e0a365cc820c7249f9115334848b01cdd7dbb016697bfde88db7f33efcfcf77138305dff66af196755586278b0e601bd7a3b28917dcdc2dae7c85fe3d3ca28863fefd20f05103afa5131efa72ae9bce61c4ddfe0e2f79077436fb2a3e3f20f93133ca842d06f777a96e270cf0228b15fb7f10bef345296cee9851c3c139bd1e23b55eea61e9b54df62cb6cbd870072383c353f2df9a2b6ca01d84d201259f69c8f8c82dbb8cfa36716f3a7f68236a0def3d72db11d730d1441929b5d17184aeb534bc306e2c6bbee3b952b5efe7b575425fd571de252720df38667d57cf0017b4dcc715eb5b4bfbf3436685a80c1ea3154903bad8f115ed293b6a13a41d11ad25713041977238dd2c2cb48f4a0aae04f452bfdd975abb84952de7757b1911daa6a889949b60aa9bdfc4ebb47c939bf258fa3b24304936ba0f32af3ab248dc876f523e3f98040443788a290c7947a83946139dcedfa8385428cba336b675207cfd6bfde67bea19a7d3ae48496bfff576306fcbab0678285d4d36469d027d670d6f359128d5034ba3c616e520c9664302d01c0b41a33faaaf6185503f0a6d0518586b805c7eadea9bf3dbc1203db9edf28e41e4ca338f2b5139f22700f27987ea16aee8e823e2fd9d13d7f058088870f6a76688a621db340132b08adf94648ccb681044b98064a3a66d4fc7aef18f853e8a629ce60ed1543e2d4f376e2d384e7a8fc70c639f98cbc8b5a4a1ecfc79d51b633a881966385ef713e95502187194d3f46b2de31c15d8898dc3f83cc9538928af21dba6fd0b9", "7050d98b6aa96dd6b11c739d1e68cb024a77beaa946a6039fa33b235ae2e94fe1d7aa601fc64607b852840cebab20152f0f2284390b33fac2238ec57f6cf18a66fe4f165e17f88b39f856d89d91aac95d1cd6ba4d0699e324fd595119883be78fd170f641a21447403d0acd28956e4e324fc3af6be7bc8d7d726c75f1c89d985c38ac2a74d456e8c96445ac89fa8ec1c506a5f8cc6dfca86d2552841af8a40704ccd9421af2ec2b32a8cf9e4422be5f7b3481f2d0ac7d45db650fbf01078946818ad3d1da9bdb62284052dc2bafaaa053426b9606be4e5a53de1d782c9561f57f3f01c4d50f9e7facd67346218b372d6f333120ab7db7329ba84212c02b29aeb51d5146c524ea33816912142d0d39b0929b224e9a1a1a9124fe6cee473aeeedcc2722cde8280eca0491348f3dfb27fd73e0b9059bc7aa98bdc1ce1a8ab7ed3cb4cf3ac80f1590b912fca97d9168c4623b5ca27f6cb3c47addc2c7a6d514fd34651ab1f7cb7f5ccce57df9bab9fb22fdd2c90adc61f69c16c0d0ae78b0459035c82a8a6614e1d54facb02d85ad485637fff3af3bf69e5bdaba9d360f2ea60a9ec6103958035a75ef9af640def867883b2da9a77cbb20ed0b4fce2276f475a6c9eaac1c3ed3313bedaf4c20e895a702020559f89d5dae629f07febb2a0da16de85a28f88dc115c4c13296c267fd2073d20f5c7cd639dcfe49c7eedf49e75b9d84c639d9f09bdb2f9414d42cb3ec9c9b2adeb4a71d056c36ef6f697c2b4a3e53a8d05202905bb59bc53f7a06c233b11bd66c0e7cf08cd1e6218a54b0955b9dba91b067ce37561c1e9da0c3024fc1f30ad261aa3afefcb18b5a616a3cc86ed8b70f9babcfca6822ee38bd770fe8d3ba636d89037a6e9927ed29b3daa57b84f7b450a331c849aca6c96d46885ed315aa61fa79c49fc8ed90afe822772cf2e62a0c7831e5c304f7c61badd1627337da5c744c6b276110ded5f0d58fa4d4bcda9af32a31187ddff2f69c060156f3bd796b16290eb31fe3a5235d15b5798284e89ddfc97a13a34f103be8b6c9f2fb74d57b6df8515875579252bfa2c04021cb28eb0efa4744b96ff9093aa56446b1b0d4c38764a52e39bbc9e557e2166dff66a36854e92638ff4e7d76bdb8f6f322dcecc75bb69acbb3e5ef336adfe02c444127313addd5cbb870d325d305918009beb17946244320abe799e2ef87039cbc9cd689bd4f6f27bdb5d5d732d0c12b8fcb898b58950a99b92fb1a76787a7f24e46288aa010b1575aaf6078924db78b16c07a260aae3b39e96a747df6d89a5328b820aaf4c9c864ca3d987381d6e91d54a5d9426a9b55dd36cc509b1a096f3a9e824c1d2a59070156544c3f9406c6be37b49f83b32f82520be220d08e6acbea4c383571a04b25e659e2c1438d5f5bbb5c8ddceb1d93d45f7b23fdc16465ef9105c736622e63365d74a0b30280ea5979c74e2dbfdf4fbfbba4d2048f8535d5e42fa450b440d1e35efdf0ccdf384463dd40eedbd2ff41c513bba99a6d5bc9393d09821eaff18381457240b0831809890dae3fdaa2660f7b66b3098a6882bb59ce8d14b50c02f51d17ec5a82a2ac6069973a188d11ab5e36396cec5913ea5c8171e269904bdc234ce9a419d6719e922f83655b83ee3b4a74ad499525439a22fa0fdaeb52d4c183671fdba9a191882ff5e443e22c8e975f7a00554154ee06691917eae6158515d6ca5cc68e60cd17754f180020bd40cdf03ec6cbc70f859a4a9e1556a9c37b6b41f503672a40cf5b6f6a47fe1b3b074809ad6cb0014493dc9034db5a91a83aee7cf82d937846ab50cb18394f7e9250df16e5ba7e2ec65044eede09133370758c953b3ddda49d85c749adc1d7b33468578709b75c032930ac89476ee3bcb8bb91fb4e628859c32649348a44bc6451deefbab0419a032ec3487211fde5bb44d467c16ad2c0703509d62a910c8197fc43cde80fb61b56eb36ec80b5408ffa2478be08c0777f6378d9f954500e07bcf8dfae344366eec0f73828486d2ea317d635fdaaab8f63ab88d832a4ce34f4f1039fc805e6408350418b784c6fac65c5ba63ed7b11e9347ab24a40aebd5aa9c0b33acaba689a101a19011619f3869b1a7", "4be6ae250d95730c532660e74513c578d784a98c6aee6a77c7a5b352ea4603c761f6f1d7704c04c9ddfe57dcec7e19124fda4102081fe4ec94c7727c50efb4dd2cff8c0838907bc2d037d52168a5dd3573e9e2783eb84d09383d93d51a86961a090dc822b88ef9957432ad92311a44ae7ec707c7cad3ebad43a40f2a1640665b32fd46f588d43f67a215694a4b67f0648867f3ca011d249676cf65831cd979b7b50f6ec2d40ca3be2610c0be1ba5b966141108d720a5a96cf502bb085661a2b6ecdc0b999efe3690bd9d6ebe9fd229a43590a3e3f3ba88ee3c43cb84fd61d677a656800ae3080e7451dea65d35eecec66b70fbe3b81364c6cc84a270c9635628d29cddcf8230ef8e5bacef8a3bb8ab113d2dad13d841fa8efbbb7a8e051c8387157e8aa1634904f2dc2f56acd87e38b0704835e2613f40d97b3b4e9413842dc8181c9068ca7dbf1afc85a8be76dae20e2ef129e4a6446561cd91017c2eefc9a265b9299c32e2a79817f25d4dada7a1d6d4c0e2c9af789182c245a3618fd4ee6d0c5f8ba8779c09b9d2786fd118f157167df94d53d319c284acfb38ac320231326d96b465d22663e3bb13f31539731c17431a338edd05f96a09bc9de6940701dac1e1eaee3c4f91d64fdca55bc16a3ab87e7875240d6d3bd515c6f6e64977481f48a3a4ee6faf5a4f1d2f58c127c1bd8c3ed957f19d35d773235e5a7f663a0cdc66d4c72936898585152088fd480b3e2cb2f5f0f76f8a190f41715f0f074852242d05e2537403e97682db50e9f88f1c611bd1e662f4626f4a2f6e13d15609d482e74075e396172f2e9c7d1a36b33ba9dfc62cdfad1328383d5f0c14ea3707af78980c8154c363abc88d9ff13b7f788383551216b9973e69a00600aa02abf0994996dfcac5311c332b3af6359d8e7848874dd90fc6b2519012f0b1b051b89d18e2d323c4937954da4e3a3cb6100e83fe67e37ca1ead20a45407b63f9b6a86d3828c3686890d911842a82c6cbfb9a9e561382c49be75c451f9e07b795fec2c409cdeb4bbcdc6eb5561a3f44caf8a1ff56992f145f86ac98587134365e16dc21ba1e8ad2697d548675bf67408294069057e5551a190cf010ba09cf580114aaafcb39fa9e6b13c7cada1f2d90ee2b2a8924e3fff639632062f3d89490920fec4bd922606fde36c7b00c26f16f59b6ef19c1c35ad0f07e789085ebe9aa1cb7cd7d1c554a19d6280edd5c1181f59b4cdad8c99acea8ade5c1b25e21cea1e58e1b03f0ffaaf867ff55f80395f1afae8ac47443d1bb38e538e6aa86fe0890ba4908292b0d58899384a2887a346bddb0a39e493f7e487891145ec8820d2b5e279c89bfabfe42bc17fd4d3b852c1cf33732a4238a668220d64b655c2ab1ee7846ef36721332e647d503101ab9cbf57b05773e4738a0e4c4d600c62a369ed150bc0e195dfe3682a5583295223b207662f3c930df59bbc17c79cda56a9ed8023bb492465e2d2c1996c7abbeae7c7f63e428e55543849158acf8672b59d7a6b8be86f3146a20a922418f8c9a13a1379b1ea199b7725e56d9345050ff7f738dc58adceb4ee6659f1030c231c9f5f61078f79463b9d6fe162f186ebc3ef34544c7ea5d5019f7e1b208a3e9d4544aca1b38adc49a80aaf72a675c2cc29a29cfed711ef4edb787c8439ade7604e2dce357de5edf5ee15f9838e99185348d590c330ad2389040455568e97f9a65a390887ed39b10527179a2880eafc93e11ceea30dcbe9d5d3179436933bc52d6fce51529a8b96311e5d35d4c7f20dcbe58aba2a632a42ce7bd361f4842e3fc2efd22a2bb9aadc32f28e2239962fc33fc117aed749b23e2ebbe51bde96b92736c398a3e0ba7258214de6b29b5d71651e9cee9836dac48739af0316357315fb441c9a613d99aa8b7a4071bd6edeaa4d8adbb56afc036b2a4e5eb237e22103701ee5a29133bcd86d45da55ebdff839a824ed820ef1826f4f2097ef8e13a07e433e1e6bd7453e4b2256a24cdd56171bdc258b5ef5f2626f1c7b8f8263eda5fc06cd41d8cebbfa3bd642e9f6492fd5829dd7918491ed2715e56d44536d311d0eab36c8059e10c7b7410f20e0f9d7ebdf63bf7163ba366651a026bd88bb422c64fdd59b0b7b026e6a9325965de11de15a7da09b64bbd4a48a53540cb48e469acac472127b19ce3545c7c7916978ac47d61ab7dfacf08e0a67f8d384c0980355698899b79b2b97609da84f31c46c0d764a90b34a6a128456d22d7f151659fac06ff69780384b523903de481ac811d4757ba14eadb0f3520d8099a6795bebf3c826a41c04ebe58461f6b96dcaab1d50f037f8af30325280655bff88c281d0d32f7a369fcb997277ed4872a6cda8fc1ddc24eb9e95088630acda71915a718b833ab74242c8c62ddeef42f979d666e0ff8679599671c429bea77007adaaf685406efa951ddba932cf240ef6f596a3fefc5f2c0b5093383be1060a730adabf9a4f81d8e0ddc7f11e898676e1c060b5a423c367422372d3afafd6554107d4158e9e04bb03bb317eaf6a90f0c92bde0dac6dd97bf6e3e754837fcbfe75b68507cba873cd48950d429b2a89cd247115328179ef2aa4cb56f2e0a28caebc36b44059110f79c17d386b733e73fdb59b45450c82e33b5d8f4b8df82d8835975f55a895dc9dc12f3a6fc56948b2647e0e7f6d58f7f0770ce7511f86be84ae762802f4c76d158dfe3d624c2c7c027a1368577ec1a3cc6b564e22c32079711a778ee5d9dd5425af63943ad5503e3fdd46b1d0dee259c8a6ef3c55464fbcc1ed37de9bdae57ff045d2b562bf5a78473a6b2218df679d0c65f38ad0d10deb1c86a1d8fba5265d0f03b0fa4ec995fb709fce9fb802a979958e194ea6a08087ed61479d140349bc64f9708b2f8ec967a066226ea2c455da52c0d18dce74832dcc5b1ad030afa89328933ade9b4faf77effacd9a88e7a746558acd2dcc129536af69be820277f3fe2720c5cb9e3a1e7492951582aaa931a4347850a5158c669e56f9be83496d319887f37752995733e0e5baa5d77132c656cce6d426898f6ec0bf5052519d4d1ebe640cafff9bf1cf5c2b909f32a5c2b715927b71ef013e9d803fb7197ad2419b5df1700f4216bcb94a90d79c97428f1a579aea9be7cc639db67163b3c99e3bdc2ddd36849a3368d3e420011c51b1524cb59aea83327d2e1cbb121833de40b25695a87c3ada7cb26fb390537c8a06162abbc345c1e209909feea57d06282e963d6c28e9922d6a6def69b7dcd7abeceadd360a66bca6e054801dec6f07980f306b479659dd7135243df26e3f02a9f262f9e1569d2f1db6e6daa95f366ca1951a08adcca91953ea3c377e3f60e9d34c2d3f19ce3c7c7638a9f1afdc42d2efdc99f6597e77485bad0a150a870836c4b57573b62b1ce403b1236f23f86b9429bbe10680064098e6883e4810d9ea50549cdb5c0c0a0e8899936691eec2e71839080e56f4098f6e81aa0b6cc0008012823b4058f4556f4c3e3565ab9aba8841ff4b8bf522b76413e1b4d7afb39fbad0f1c493b097fba7af299c8b6955ea6c72a1e1d8331387368c46e8ecf49741a2654fc53e5f2cca7bcb3dabd2afb86c8bf5cff60b446e984384520697017137613df010d3daa9baaa645e9e84c400159e88f73f000cd77d35fe1ed7cec73d26cd6da04478d761001d7327c40f29532a539d9e44946512ef01ae7ed25b3aff92d4345e3dd440f93ce68fed245ab39ed823010ace56b2e611124f9c161600c9a4d39350fe05ee022d27a894e0ec4b0208cb7cafad5e3ab07da5fc54603cbbae7e76c3d49ab66e9d2152cbdba97a0b8778fe1d47e6b18a12f66116ac8f74e7a02c931971ddbbe3a090ea4cca3f015b927949532e7b8c00d3e924ba888c58cc6c1c88575a725e379962dc4055ba8c1dbd3eb6ffa8dc00b1e0231c3653228faf7177f158d50abc5cbcee667e9111482e64b37ab347ea94cb1ec8cdba73cda08f34d9d0c750698dbd2f32c14d9da2e519aadceaf686acb4c5477d3e7ed5549b1ba9cd59c0f71ce330aa3009c42e8c39ba02ecbec1d66e4f804519af0d660d642fc3ee3fda609d2f90d4bbeaa06670ac2cdeff6b4aaea14f415f3822a2caac6c9da4298f929345520726c80a888c9e7bcf7677d79c093a13dddb5f084968fbd9fc7ac2f39f77ddd3cfe8bd4947aaafcc0ba014a666e9560f0ed07f40a69ac262da5d1b0b1cc996e41dd768ed628b8022211af", .Okay}, + {.Lcm, "c35897797e047920ea7779f2141b3b4efe6a6c84ed4616bf19e822afe94ee4f248eb38f8031c9703455ef14025989ffecc819c5b2a0e6218a76330fc9cd6c35eac65189cc990c12b7b8b1d23757274f7a06de187091f3106df53e704d112dd5f86e4bc08d98b4fb27b2f73379b5d2c903b862ff9f19fe3898378948c3c4ae12c71b7ec096d4767cff8d6e3a7605e1cea0d57ba95ed749c167e270cc108f64fe45a065ec675723e9e9a242674eaffd48393c5ed2f57ca796bc4a75b2b97d45c1295d64fa10aba9d11e2376a943da5d66028d7fca4e4050c64c10bac47169ac8d13bcd60b5707fab454fab5d1ee859512aebb5e87d4552e020845b917972b0f98f4d3b4030141dc6f8669ecbfd1691bae60679ed5307ba350b8999554cd66aadb94f86118bcce6ca7e15933b6f8414792284cbb326ec3eedb16a4526073e685a51caac86f7fad0a4290a66b93b00b616b2a38761b2639c37147c9ff347db561312ee5f61783f9cdc6dcee60beeb3a4339dde27fe5da5319e99ebf548f7f971faf2081cf2560e09be698d91a524e63290725851cc03c881663a6c0a71cce9b592943c4f32d7d9ea7196b9665819ca8fee4ac48982a44673472d275a32c626a2c3aeaf4b4fc3e919a66eff80f838b2919894068cb47158c4f81a067208e6310ce06269bae1526f175651de89063513f3b770edb2dbeff436500f6a804094a159f6c5f34b9910bb43f372817d6e0887fc245c35c57ac12de4f6bdd4af959f9bb7848d74de246c4e3e26987a578aec4df8d61db80318b0d8b0a20c184f54db947f5df189a39771f642c71cd8ed354953766507911a9404afcaf07603930e585b03353e8652658124859ac05ae083170f1fee5cb757b97784f44253e60965607bcc11a02a34de9de19860a7fe1276aea7e5a9a08f8af8152fbcfc3e87724482224fb1401da440bd052931651248947d8506be13a22457ed1d94e2474d782c22f960b4cf505a7e2ec3bf85f9a13b8373353b83ca3bb90567b3a2e925ced07811cf2902e51ff312bc21809b52717e6f460838d8fae385ebbdb899963b3d0912580b4b9df6e7e2172a09b773e331b2e698ee89856df8469173338359adec3c3ccad9f7889de0b11ee5acda1d34436981c69d6be189d40a1cb6302d9be6ad7df225edfc7e92f80b9df53b27f2f66119eccc7a60812d8198fda16e36bc9575ff0b6df0966ab68ee36388b65edd1871d8bc4c451f46058554e403a1c2854a33a80e814e17c62a530141ebc28aca81acb81fa5fd76a7e43dbe32bc1a29524b1304397d56778b5c93847afa8246cd5e4df0a10babe348e0093f1b0d8dffec55d9757695853704aa31394f0aac6ea66f38f73c847ab63c26a0a62d3305fee0fe2ce64126346286a8815cce88044bf8c0431b716014db9fa820ac3b64a7ee1eff6886d56a9fbee9fc5c1a939dd117bbe4a5f4d5c609cfe52fafe22b57a509d80abc8b311f3c6ecfa7ea07df0c2e2d8844670e69bc0b6dff26a64b6161e42d72de9772884d96a217cd70897b8d1eb1b7e323aef45fa452b7d231e03bee75e4508b49d4091f5169284bb02579e9dd9695c46f6afd0c49794ce80fee211524038e383aea892253691d8d023c11f78b0cba52735867fc32fd3f1d029c264fdabba9f27c6d5a8e6fac9843e8dd503b3177542df6b8927a7d215477d3e7fb122418dc5322b7c7dc22d124cc42566ab8589688db9f5943bce106684285007ee4a07dcdd1393e1ef504338533a95ca1dcd985dd732840262c296368338766bdac90b8c9eb28c03335e3ff81d9a7294344a10904560098fd5eb4e6c8ba764ea194319e34ab58c28dd20a2588361cc28d54a6d8edd56d5bfd6574a5518117f5edb936bdb12499322bfa1b58b9bbe1c95763ec6b50a12d57fc02be5bae0b60e44e2ef87cfb9e1e14cb2f15a6e54e8b37eef544534f1ecd88f1e29265ba6013c83c28545aa95e3629bbd0ae2b7983cb6ea82402eb59b7db5580e92d5e104c553170db62ef8a23e33fb0a9579004593839ebf691002738dc842d6ee7b4d71aaf2d16551adb195a1bfaafdf4b01e3a48f74629c2b375698f2b710091d2e1ad26ec63acae4ead92dffb3c590", "-1d95657764e53e137fa13a5a8bdbd055446cb2895f41a8760b3680a9294aa0c822e1df0df2792817abe77d30185e8d5dfe9826af70b0ed329936e4737bad66c3419dad67feb85496d5818d870fde4112d67826375de584938909b04fcd336aab8216c81d4fe125094f37c282b170dc4dc3bd44673ac9dfa081a4aaaaf144c1d473ac276e382fb845dc1d05c3005dea5c1b73b682b24c1821fbb29126eb276587b076adf322611286dc07b3446649a8bbb28aa3423ecd6459e57c3c7292a035dbabb1f126d5d5debe1ef7f22ab0eda8958a6e0a4530c12e023868e7ac8ba8da3d85b3f755e91061c6b526b21cc3e49a70a30545631983b2ecb576934808ae07842b507a9471909a9a55cda2bcca920cfd54e9cd32b0f776caf4f5df29807d0616fa64ede292f2e47d65d3ef7c4d4a9c5c869f49ee56da8a68570b7c9df7c77c9824ed7ccf570277e5c07daa433ed80c96ce712ebf37e023248263709496ef96a111201eebd98a92dd99b7f15a107362e0460fc303feaf1db5971dc0167cbf9673710d46f9464743ab3eb59a63f7cc0444b61ca4ad595bb13f39ddb2550fe62f4ecb4bef3189a9968c22c084cb87a4a02d75b2766276579ed70cbdcf8c079f8f019cc80f11f662031c023f1bcad8b97e69e72c96afe7f50a343f32e68e395bf6c18bf27c8f06504de9262a2c0fc606de00e917377c2e3b4fbccf1eeabf1bc94dcf0c4a0f41ab6481a4dfe5420debf86b29e2ecf42798cb09ee47fe2f9fafef9925eb96a3ad65b6c8ce5a77d9d5df0cd97b139b8e588cbba01523e8613fedbdce462da8500e648a86730d75ce2d96e1600f94245913f9d916f1936b4d795f965fca14391c913f9d85b38bad8f709741557332f3cb28c555b0b478e299700157939b9ece14d48ef4c3140793b432a124d6c01e00ef3f78155b73fa373396fd12ff6a8e746cccf722a733a572515fad78e59045413f45dee582f1a2c2bd99c56b3be2bf518b1efefe575f344d15fab57c505dba101286196238d66823ef3802cc58b5c45bcecc037d422bf88f1bf9f52a8a8e0420978d30df12ad73b15f85a1b56bc4db48fa1a32bd965a9c02751bd29646831e2ef4c8ae84addb9cda809583ce3c08bd8f51be1469f16c7691154be489a5708519ed59681b8e1c8aa379950b915280491cdb3147b1c2d39540d1b004330930bfbe27d7ce729697b6b4af05db6ea684e551ebfd7989c3901955d533f533f408c1a4475a318df8f68771f55eadcaaf7b754b525be5db32a9a571dc96ff60aad23a70ccf5771369e19e6d0d5ef7e605163bb9c09ef2e3f1101d8ee38c43484259ce6064c0effb48717532e13d33fcb5ab869d6bccf4c48fa9709c65315b90f611b6323c1380f2cda6547eeeaa3084f8c31d9671629031df6c2384cc4efd1be4ec6cfe0162c21d3d0200aac6792dccb5525e4c0cd8b6e6b2b99490b98d44a4909711eb7076575cd6ee28f1a681013fe64e9001d463871414648c444b239d75c8347326e4e23674fbf708d56fd63e8426d86e4acfc9b25822ee74989b1ac152f361fcdecae27acd1905685984f6d55cc3db15b9c0a2c68566815d8759e78b3271b5ed2a07581f9e197655c8e2ada4b3555aadcf44b4cd4ea19c82e78ce55df78a8365728cb72a74f3d467ab75474c5abc1883a631cded84dfc5e94aef3dc3bbecbe6fa259423e49758646b6f318bd5458adfa2e14d8252e93ce0b8e800f708809a7d25006b3d47d37286faead71bd24a8dd5451941e97ebf6f46cf56f764381820bf8413d8d1b56230e68e8ed5c2ebd58cd283cc4b023aeee78ee2e6d732f52a1b76c6001263c8fa4b13f212781ac8dec29ffa5fba6fcce1c4324bcbb6027b96c1e855635991fadd55c0e4b8639ae2ae6a73abcee327f0a29390f088797c274cf04e057cebd7af53b70b934d15cc713f1289f1d82f5a0d5ad042e126be0487ae0db9ff4b1c9ecef96bca6625b05b10231be6f7b8f6e036be4c2c71b7d8eafc61c2dff3fd3260ac653fd7d57849f8c0daab1b16ed82b3cd6185b564e37eff40793326711395e9b44b6d446047d35e18e8851ed960a2c803a05ac566610af13b853016078a7d644926b51d6b13781", "16930925fbebbb4ddd246966dfa26ff0f5bfa8315253c4dc0e57e4fe5753e569395db75c90aabbe0e4946a0925a173a96d9cb691a0cfee3bae0ef016d23eb0e898a531a6fdccf5c5e8a6d0da48df918d80cb585983e68eec98f7009fbf127fe3452f188af4ccbe11ad2515a087a29bd33a71cf9a1935fbd8c4fc7e30eb263cc3d004652e706116587f5c0615a5bfc5f697c0303635f86aa90f84dadeac1e78ae752d37b2c3cf2471b431149d4979a51d7d7681c72a64c3cb66c052c567b3bf8e1087e1b26cb765ca0a2adb728392f36f258d4f2ff0fa2139df186c91f85a7b3c328e6f5af021f22d797060677f9a29a25bcf7e11068af8de79189fc7e8f8e6819d8d4ad8531e796658477d84760fef35393752060aa9e2454a271697d34cad5552119f662b2cf9e53e0b1ee0642d340f069d5989b8ec5df522180b3a6304fc37fa8c5bd9694f0152d9c9209db2dc8a662e19dcead856f360f1f4c45af7c40c86e9b6d6f200c1e4cdc90455fb49b181161e483679b8cc50403430aa3f8aa03e5d479757c82d0142d605ce4bd1122669386770474767b90c5949977de4df4a6eeb5fd4a1aee0cc113e9d14be66dca83892285cb1f52af5df172b9b350f28a771ffa6794d86b63b87b2a7f3e74a6671e3a2babb28b400a13ecca35593f87b852613700eb7fe68b2a80121055b163f557374dc094947614d4bf3dd2f6be07870fbe5e40a51d356d5f2bb057a9f6b224cfa3d949712a2c634c134327c16cebb305777e8f342bb94ee13c3e71db6515eb66cca0322ca84f10f4b6adcf6d00cb14765e79b2148bc9b221c3aa5d0be250ed0ea85c31c6c04075a666be9594578037aa03a8939262ee6b507fba505e5b42db14a7ba2a0bfda70339eb949a70f4768e092b9355639cd8bc4d745525f182978e22782159d8cc004fc26890480ce73c42c69e9d99e3bfb070a788f3dc0ab5cd98f115f84ffd6cc06484eabf9782def52a972cc36090f4635ed065e1bbb78c45f91ec507c62092fc7148a0d8b9bbf473f290c2dbc1df74424dc66ad715a5a5ae7638bf7891a040303cdd3577ccc7191fdcad430a3a2a3299cbd04fdecd52e6bca3b4c429fc732866d5e7f2657624fd150bf9b2214c116eb427a478522aac585a9701a4b7541488a8690e118152a12303502f314396107d58acc9a057f091f41b9a0ba2d5917ec4b9dfa50467496e130ea136cae0cb22c876b68f3686d43b8c5d562cca4d6c163f4fb7562bc461c86aae921176a958f59fa75b0ca13c5eeeb17470af2affedda6fbca2a25328c4c4731f11efd766de9c76318f715da0abbc7e18c808f67eda02d9ac41f5ef3400fe182d07cb298f087307d7226579ad61f409ac520706caafd60f4477d0ca75abc39f7a200c564f642c29ffffeeccf541c507eb84046f6809d310b6f8a0799d8bae9afbc5326a9b40b504a11a457d18e1fe4cbf453298fb967e2b5537fa452249d0b89dc542e6fff0b74a6581dd1acd6093961cec43dfd51a66b650d766420ca9a8dd62f717a27dbabd7604476317e7d526ad8ee346ab58ed5911f8295061cbc600bbb1af7eeee1b587caae740e7541eaeee720f401821cb86de3fb5ad98cf17690b4337e4439b5ed583cf00dabfd58da1f5be42151dd30ad407120fb3a5b7e7163664032232b63866956aaabdec0c20754721553eb572cb3c86da80cb7482db78c9286b5e37f8acf451c0e40aebb7479eaac46f6a3a207c243da98785642130b418b0531513de6b1e5c0e8a7e0044e95162a5f8bab68ec33762b10f5da5e292a56136f05ea6c4e82a85e2aaa3871615cf8258693c4fe3718fd0b24f7b53410af5edd8884deaaf48fdb48d391d470c70b0877eaabe34c50793ce62e2c87e827b9c8508ee2a7bc588a28037d4ecda042edcbb18495a9933e9e5f1a13328d6f9a1367c74c79244e952a665af68fd93a56df775a7ddfafb5f9c3b037a64e60604f26dcb19f8b3bda3ce56afdaedeac7427580eb3666773d5662b3f05c6ebd72d26b7427449cd2799df4de66fb3e5aaa83ca08c9f301527f976009f221571a3204d3b0d327c4c89bcf82a7f03ed2112a9ed570cc83225e1714533ee25e5ae7a93783a1e679608fdc2ebc0d5f53721e078698d66766a0515a7ec283d6e31419c5a044422ed33b56e672621a3ac41a1ae44b7c5961ba6e030def17eeaf765f252ee3acfe06c25994cd0e91c708f629128f5dc669a9f5bfb9e14545888e438c6735e8e64ba66b6ab32dd1ec2ec08bc493df804ad84bfcd7726f292b087b982825548327f19039e6174b921151c91937d0f29be92ab4b5168dc6bb12c482fec23c12bff5c7d269bcace2deb685dd7072b6646361f88321b4dfb869bb8944d95cded0cf79d4b675d676fd0e2e508451e184d0c9f771532f2b44deef12ca221127ce2f89603100b0837e5ac84ae2eab0a8320e36de02ef50561029409ee936d4467d86e46adf9124042722bcf06917e53ed7d8a797ee864f7ba861f6b596b396843858a9de865c08cd1b2f03af7b50c8f5b447e5da835b7a38369c5cd4e3f49a6556c959f77d9fc98cfa26b70713cec8cd50a51974e7767cc8f5faf83796a1fb19b308094ced765489dc66622ae0e29cf8a9aa9cb1e4a04c4f85ba1e4f71bcc529024caf54409ef8430a2f66514870eca5ad843cf710c6f1e29c2d1fc2507606c60d045d483f16ed753c77b64e8c58d7a2ef6e05fa1bcf784ccd9e43c37db33545be10c7c926e47c89f37abd6007a377a07b88db3d6177c974bbc479219a9374994446f701b3ef7f13d0879ec675013e6839a64279367c91a78f65d3da75953760433ab97cbf493e3decf48f23a01bfc06b9a1362e4e8f21026af534192b433152a21aed06474187f318ddfb50a1f5afc5e511331bd787ab3ec1ca49c25c008ea8dd653e17149a5c4574aa6d77fe22c20960e8a02adc397a2baa045deefc95839caf6091d029d365139e3ab69a38ac68b6979f0212c18280a0957af697f50390baac4ae841489376b180331f221bc85105cedfb49cc6de42c3914c057322514926c180d237c04f7657dfd48d1d3a3695b119c1e4b22e0756ef60e68e06e7950078f9c2c9411c3f38c77c0eed47fc86e3a598b790ba0acf996a5fa3736b9042c83daa04e052706230897db29da069677e0ea788143c009db9baebc5defeb3d3683f0f591bb245968d5abfac265fc7be4b541f06912ae3902431ac039c17f1fcd741c61268af2970d7129f771f15c395e9c53cd98330895bef1f7d9f148e2094f7035cb455769b05331c719acbc8fbba5512df890af794f2e8005ecfe7828d8fe06eb4c121779b0d18b0679e5f6e0cc81dfb945414cb2af72c77e85084da0aaa15df8de871ffee4bef2287bb61b6f39480e9e8ead9e6c22e9d860901c31caeea3aff1e5065c36ef42afc1604d170ef099ba4e94507c3597825a7fbf1b57f1d8f602424f8387e2a8eab227001f2081484aa7fa5a8c5923f0c2be11d415899226c9951c1b6b460af0ca2573048e5c447e679042443355f5446e28d751c18583a029be705d41c33b93f336a9a56591ec6f31b0199b0c50a99b9d4dd7db2e73692f28206ea6db82e864d5c665aa3eb2f792a543cbfb61558eba24ffd3a54045746ec4370fca45ec2c058714f6936d675bb651c966fa850327d1167bccd3a96a84794603dfa4b77e612969b8a6b3734bba4a966780cac8790914a10127cbbbc282b3748b53b14571a6f8139c9cb569e05de45ad03c179abae3bd27d5df7e228a22b7390f487d4058e028dd3e269f419d002c6b636db8a39bf58b1798574528fc1f2ebfc27d73f010a21ad0f86fc57763ced388bcce3ee4a0f0f65766a721b5039928edb3f9419baeb788d5e0fd697ba4309ee51c5468bb13360efdab04aaab7ce99ebcab6dd971d502985bd186a5ce15d82b8e0b06bbb576d2a4411d0609cad0a2a8ca1d7da7bfec174291cc496f29f616610d13a1cc267d8e446e2a298040bf963f7ebd019052a02b3216f46f1e8f93d27cfd5643a5e69cf103e5c5e75fc9edd8e8904bedf8223d762fd50ca78d8d7f8ec32d61d19112dd1be0598d363a4638bebdcf5dc74afd3d507f2dd93046f2a9f08b55e062c9fdbe965d8366035204faae15a84679bdd4bf6b46945b2cc05eb2ecab65c5047986ac06a27129315805b729e2de68e5aa160c77bb81b619bedbb773134ee449dd892f99aa7b7f70e6c276323171f71987d90", .Okay}, + {.Lcm, "3ffb5a94d5fb2585cc7b8e5cd00fda7327e7ce33e25d92c69bf6175613be15084ebe399561c60a9aa0e30dbe96150e7e7df0c6cf43585a34f65c4df44db823dc1de217ef2bd16f19c447a5e27ca2692b1adf3b32ac7fee33f13eb3c55b147e12e6c941a182c0e57fce02954bcb4e48c07d81b0664d954c3f897b354036ebb37b2b0062b4fa8bf96d55c7406f8121efcc5738205ab1e12d189d9033cedd0eb6840cd23f448586e518fde693f8607be4b817e94cacaad6e00a7f2ad6eaf7762dec382366322dd43c12f0bce647d5cfa1cfc2c14eed2b8347876316520f10a9c9ce15a978c997d0d4f3700929b6732c4a02300a915ba87fea56afd669667fc9a815e87fd5f5c38a5edcf0fc3ec7a13c5f4843258646b563a3ae79b2b1beb98bc54789c9b13d397123496e7fbd8ac231481999116a67ac45b063d4796c537659ebe78a67f82fe65445a2098d5e2697c56a0bf257d9165191ded1ff392c00a762375e226627fa113d9808a625bd5bf34816b8384eba9deb6ecfedc5df2479ac9c4eb850a5a0635c2ccd1e2e412679bf3e5df82c718ef9c6a5ad48bb63bf8e2a5e3c1ce49bb2de24783962e8962f4d517b04709aed44c42d5f23374d6cedab7486de8b2c3508890807bfb1052d3134e0e4e18f48a6fef6d3084ba229fa4b01c34766b809796d707ab0ebe7441d3038c920898f827188813f4fb532d7c35dd96521e7768be3550ae9307a59d81e53b490fc4e4e88e5e7587d33d353b3f9b0e752aa8b0c28defc9d86b8213acf1bdf6c7be1a1b868ac40d2cf6d01d25b6de3e221e6ffe8a53044ab109c4273d7600df45c972241d43873d7c9713b7a3054d7ffb9e28b681d6d698c0d22b9cd1ab016f224bc3fb1ce8f421b1de880c6172c109d6e8fc537e6a3552a75cc06fbebab8ccda1224a6d07d6014c7f8839bd6f611895e909d8816d090e2b7f9d8cefaf4d0b95e3a691111197e93f8b52a79247bb9296e9039f5aa78ad05cb55607d1c43ac71fb174dae29ce4e95800b0d419893543eb1f08afba74ef0c883794acbb0fc3106730c11bec408549e3902aae9233d61e91807077eaa65f35dbd55e1672a22a3d4a680611da0dcd07d408e01e6c3f955106aab7e74f41ee11096406297126af543d4af8555e355eb542de3f43350f023474ab6b9446621ef9438c7547b016ba44c09194f07ff44c26e1a634f80b88f540c292355dedc0dbc517b0a365593416234b0705609db02beab5200daaae3668c51594c5efe614c01ec6ee6010eb63f12afd02ce76b9f5cd2336ec0064b0c72794d375f7e2872740466ea4370976e0b2c00dcda5255c287ef211ae880d3fd741d92858b5bde073c689271ae3f8e2df9c0095b15a503a2683da3e7f5f0a99a5ae03d70b651db5a02ceebb33bc8e85851170a08b66119af28aa72b9035c85c3a40b875c215d48c1c3634f4ccbbf2727ce6e8a71544db51c58eab76ed848b2f2d72fdd1ed7021603470e5367b68972423316f7f2b5bc14c055984fd26d0de0483d0f6a6cb0fef17d35b89b67a048aa7f07e79959dae56d5084166102b4215a097e3b1b6ad52c4125be070e82e567964a545535b30cf41af38e12416575bf814714b3f904e4b8a50dd4ad20d73344c1f8bcb2aa32e005380bf906b9f9ddde0af8e339c23156468f62b057b379bf2e727e14f0a49dd6dc429495b6d76c0228e3b9099f115719a153f04cbf9fffc4637c6dcdd5249237bebf70ecffde500bc5e96ce588feebdbc3215a1e992b802bfb720c1bdb1c91e560edfe7960df8ea30616e9b1ce7af348b3b104d0780d18ed563eca19cfc3d9873a9b38336e0921a45373e5c7e60f5ca3ae313b19546362e5bcc8ddacf0499746a810438276b35a16e2285b14ffe530e7776bba898e2406ead3c54d781ece03242bd74374a0526e1b852be5def1dddd05e1599850e3fc601efb910894ceedaa30f2ca8b66f6b2ab0328e13ae0665093a4a237b69daea90847ba68f1ff564b87bed57025efb8d8fccbf294e5631a71c1b142e41d6b207492330ff5356b721fd6eb3a82a7a27c2558a43e9ac7e94e0f89213d1679d8fb91591d66763e4112a7b22581749e18b2166f2f18f2bab3ff04a", "-5c98aad052c4d55d70c1b253d8449b1aff0c0b220de925cb6114665566e540bea55f7a00a7779b74a399c24fb24b3e188f445cf3ca0768b5195c1d47957a12b20e3c9906c2c128503c7df35e8c36f97b594e21252e6755ac22f29190745391c60173cd07c26f36e228ab86b36fe1cdade17e33995bb2281c555fe7d224951c1e8a0fe741e679ecab681f690690f1190a0b77cadcd2a774078aef76d2683fc66363d0b6f4ccdd1fe118141a6723dc6b9ead5863fb773ae0d4aa1a792e8834be64ac6163d2628a2daa732ba489bf7fed52aa85cbf5239f80decb1e63a5e94c87c4cdfaab11d328582c8a000c23270d53a78d0610eb4d955e19f50f34d4c8a32307180841d6f0638cfa43518f2e5f96d0f6ace48a80ab3adcb51ab1a5dcdf8231467a5e622711de58ebb8495426bd9ad3ef1fcfd5722477cb536795dc6294b3ee06b311688dfae03695e91520dded9671579862f06abc26da39916d28a27e6cb5612c57f7893961b1befcaf5d64d238efcfc62ed685dcf30d71eed1b540eeac33cd9b1a944ce674f427f66938aea83c8766ef07bf345f6bc5b854545f7b11fdcf79737eb9783814b0a38dc5e2be8d80d04ddcb67cdc188605302514dfab5afaa841a94a36878a199fb79b27bb9e63af20c2da996e50d251deef653cee678ed844746ca4476e9151a036703e8370e4ba6c3764d5daa52029b713f7aeaa4fbd753accce3ae4b0ff6f656807e775280f0323eafbb10762a05b8d159765485fe3c5b6508b04e3873c69bd9ecd9b191461ae92387e66ab33cf15a7c930975ccbecf232c04f604c9b84cd763a31441742c156678dee4f98efadcdc11f257b76ba91c1a7023a7452eb9a347bec94e423087dcb3d790bee2a02b18accfa928852502470189dd90c1bf833e9ad70098b91567d35eebca2711631f0c8677a362282ff455f7d510874961a29142597fb7fd365af9c261774c66fe0c56850557878933cb0aa1a5f3bb83540eebe8d2d58588e14ab5629794d27c9af51fa4767d605b256eda7df3773013d5eb87a6c51e11a5649aaa06daf79832cf08939bfa6f8b9ef78feeec99fcc2ea6c61693f91582a69ef606950b13d3648eb7657f2b28abd0438653ebf12f599a9266e6068896f2685a7c124d6f6e4baef792f5311e2effc78f97c3f039f1e7d2a9aa19c18dd517ea57b06d75801fa79b34d875a1ef08df95a397c1b75468c0fffe1eecc394afd18b0a3f1f17b07c4f03acf87a705ba853c9bde070a1aa3e2c6d51533d92e9badc528f43cce88b1fb3814ffddd8463c1dd21dff3ae4f41ac177e937270b3ba52cd8f4de6c1a1d4d617ec200209a275a4d9421e132d41d26624479e7aa47f69099a2829f3d49341fae5b912ce1c5adba67444a0bed5e20fdebbb81f2fc05bc8a6575e1ab075b30b4fbee3747412bae393ea13c2a41ac776209d66203ae4e204177856d03c0d7ed1ed120ebeb9358d0d84047beaf16387636ad0fdc16d8bfb8c1ec9190522022e60a4751472283ad8c1be75fdc6b17d5ca19dca599cf3c92c93d6426b6017eb482d0e789c086111a9c8f2fef34663b319ebace1b3aa7dc760896f7faf2f3fa1e4f945b976300e311936455956e0332c17a0d98728127d46ae1da6f318b47bcd44eb48e5a34f40605ee7e88dd5ac619a0e3896d16a26ddb9fba9800c8aa3a9141cbb847b0886269347d47ae749879b983303f15c6358a70132f01df4fa7214aa4bfff69806b86036e124c71c3ae084760a4317b599f6ae9baf243db63756a5f6f5ab34d80fb37a2b3428c5fe81d61535d07d10460f250b00aa68c30bb8292efd76a3563633f940105baa72cfba0516a847b29f13885ea2b0c4c0454f997aaa85bd58c658b2eebcbc343dd33dceea521dee1aaea90872f4a35ef00d89470508007c41af3c992f07ba6335f7fd4ab54c1f74b31526742d76b58f8e8652932f6d01517200eea2de1a9c2a3091a410e64c42647c12445ce9705bc74eb10e63233a64b3734d60a52fb4b04178fc50d42c5ceb385837336fce72890fe43bbc45a98106deba068382dcf9a32f712a4ad9f840301cb2ba9f47394d5fcb880bff18d0192753b601c850603ea23de459aef2b402", "3db6a14b563931195e0420594c2515d7af5304328af6bfb59c6cd911d125ddf71709f7c8e9603bbae2a64922265997d3696364d3f66a83eaa63d2b9dc9802a387379e0b5c8b61974605cf06e069630c2b6d1d6c872f1400a9547f2c114d8c5ed9d140ca1a977bde1ece0338c8efb9d3f26352e70a9bb63c960bb687380f96c21e5aa91ff8f298b6778e6f75254495408fdb7ac4f51033332a0269b5c33fee03ca4bff61a03f289d17793b8059ecc5557d40baa976ea85eef0daa8f720938e04694f5b8a22eec504570c089be3e202126f9a472f1012ff8d2bdb2da453e453a86dcf57d9d627e11ca4b989f194584aa9f2aafd365f2073e2fbf30927de5507f0c0ef4a016c588745b5f2c7c928ad8be6dbbea7fca8ca99ce41674f845cedf207266640349e85d0444dd138a99b54775b6a9b07c5abee7db888d5c811f30f5d4d9bfd00b9fe97962d9efde8c551b171f91e53057885f06ef76393577a5cb4dd1f3d919d8b77206dcb2b44a77c5abf889fdd78bc502e0688b33003804751b01f00a070145262317dd20d0206840ad46da558823b95e8f421355514f26b4ee5eb8b2fbe9fa932ad686e19caecf2d6c3a31c10a3b7db33f714aab60b64f2eb488ea17dca18ce65a75b35ee73672535ce08c528352571a29678b354619d6821a734b9e448283a1cc0a00274b056d0026257ced79c23a1ed88ef437f4aaa0da462dd06ff996d8853bec5a28b2cb871dc51347b72fc99eb52dac5c508130ea57d04482727cea17c11f1a615f70976f3be85bbab7d152cc1bec9ce2c0cf7a91b50b6cfaa653f363ace726ca60f991bd4276ceb7bc52573eadd69dff7ac48ffa283cb593aa472a9d62f8ad1dcc9466a14ba6850707233631734166998fcf9ceb2dad435f60254acdc7b352b19c30c813cef301cd5b305bc00057c19b276532365dc2b833887cf0e6b15fcb08f3ce14beaab02b3e6405a87d6a555184e6df36faa507a4385f0cab91b7a0314199a9944de55708eb8248721ded84f31a92cb6d8b30aa5c7e8535d186afb2ac50845a313eba4a6c4a497096d09618ec4f09af71116157fc1adbb178055ab6b36c1b5ebdc84f2acf0e0db4214bbb2d1968ccc9004c7d57668d61b2afc48b741646b4d62c77e977f3fdc0a49e4f753e1f7a66bf09ecd08009b82203d7ef936b3440f99811fc27f7abee5f8c8032145e7f95cd5ee666e4ce8eb0dbb4448604d204f39d34d57dc4a0d6c5e36ce6e28c6dd0eef85b4e1ab1b42585e9eaa6fef1fb6bd07b66c77f389c723dc0d0dffa6512d03ae66daa3a531b8326f415037202696617075228ad4b31508da05abe4363849f7dd4a498e1d5de279965b687750940906efbd5fa8ba27ab343fb6b94fa12546daedb155ea38498d00619cd22fad7de78ce661a9cb4fb28fe635b6739f7ea6fa31986d27a8c6dc8e799d9fe221a537d423606c9a4bba44f73495a48541e4dbb0040ebf5235cd05c20c05a24dc858e1be50d266460313c66004ef91f121ad749ef2f37535f382dfd7b8267879a5a1557136e62f9c658eb0881023c4f8d46b5bc474b015552ef15a7f927aefc08dcc8c19e96e3af52c78016f911b425004329f2a45667bbfb6c7d1009e386888e3e32611cc196109d55b650a0950fbbf46bf5090602dd9b6beaf4e46f3ede312085b92a65a4541486d8792d0012f858c1668714ace49da1d51beab502495555bec25596e3e2105d58e497efe35e8b795cbd6e04fc8d820d121ccd5582d3011162e98ddc72a00885af545133ff11ec19be731ade0c881bf4e6add4d318042339622b5eaf652366d48a593a2fe9021912305ae38f247d125406458bb827cf5e4ee60d4179a524387716b714549a40ad1f94229238ffcbd1bc5e80dd527316c9eadb724f014a659cd4570243a347c668948ac2fd0a199c78f283afe3ae22a95da1def937ecb85a8776b45139827d51ec90424c334cbbee798c13fb6a96ab3b94534c96bb8a843f347c7a2b2681486b588a1745ab1bdc97f36eaf5e58de9a12f63ceddcae836ed7fbe2cf4834e4246c879a4598f10bfc7067b4ba1d1ee742fcaa935dab77d382b4d808858d04fb897ac89e304477e0d675c0e69fa01fbdbd1f7180bc9cb76ea89fbebbd655f4a7ba75ee36f89ff2e789fe4c07a9448f3f6a144b3aaafc28d1590c262acfb4e8a9c10f6c6bf4eb155c82952ca989d5112339a7b4a98bbb03bc3d0a618865dc9d88d30a18bcd09443679e8cc97faa65ecbcdaaac0f10080d8eaa96afc793588212e94f91995381258a4b4155020321657ac5a14dccf3747337e04a499c855cc8957431304908eb496012eca49af1b7ba240c488996f0c36a6f86a206a5a5649c0797a7556c4023b160f4deef58580a8247c59eb4575a7390d068279781aba6dd7c2ec19258baabf2e9e66bd89c0d486096927ebc71fba7a1afdd953bddb7d21920781051eee425c680cddd6a90e8bd98c9b791836c20127f082fcb0569fe04bffc08126cdc7c789b010f4bc490c8a698a360fd526465ad8f4a3ec4a25df15681c4c462085dbb1f6c434b6ffce5dc561afa7d5ec5096123d7bcbd1ad222c9b194b8679de83a81c6d842eccfcb02e310450baa00f330df054d0fd15cf5ae0ecfa7a77c371c164c7122afbca6b90b7427a6f6de873b3d89f01ffec1419376dbf78cfb521e771804acc81eb2460bebc730851e861860ab9c4bbbf4d7d29d98cd96f0943364e19b3887202823a8c156683c15592a1759dd4189612164ed695d510da13d319c91c293813f26f2fdee83ad77488a1c8b0584de7304b42cf3063665cb2c8b87f8752c4777c505ebde76a6f7ad5717c27d4341000fae5d69341c68420d79d7242fe2505d28d628efdae86a9977166061866a0187b10f5b9e2b2a92ad9ecb100d3f5809aead157a53a84d43a1398ff308670b8ecef5a6e7a57ca95a131c0db159a66be87fe39ceea2da496704d614b628ba2152923b7f3d40db960bfa7477893fd8c4ee23dce90d575c7298ff3e65c6a85a849fd7a8e2722f22e56ba66de366e21bda5981e8f889abce42dd1447e610b22280994f493f19deca051c7b85f289aac9411f15f28bd472bb96fb242ded98cc43b848d48563f78803809ce9d52022469101604c4e97f76072f700c77530dd14f3aea9c24e2da8587b6dbaafff9425f5048add5439a0f758d1d4cc66b5f3909907168487cbae487d8f20aa82784db19a1f2d5c1b1073770f62a8d375c2bfd6ad8c0ca9e30e7eb1f0887c8baf93fef248f243bd38ae1c424eed894cb55279db1ac9e8e1df8674eea53eec55841424c039921ca0382ae5bcbbbb2a66fb263c3cb8e54cef5ff538b6907abea5520e89ceca15d97977bd9ab86055cce7e8f41e1ba0014f941797e534e2d98de353bfa989c873fd24a892f813afdbfeb9740f7e34dee475b2ea9eee7d1e72ebeded9a711242c20bcaef148ed3a1b7bbfa1913bbd7841d4d3c9f9a0a103c84d32e25e4323c9b5640a06720b995f0927818a5f7e77d999b18704dd8e88f2093a5f8ee2a5340e06b8d3c35d1b6e2146f138e95bff7415ff8876941a155111fa953a3a30cf19ddc23e998093da1b36cc068d50424f1ed3c0bf5709be3dd86456fca6c235e141654561b6ce4df8877d0d0e16797be1fab633bc97576e9baf0a55ab6d615d26c6bee71a8183e31c53b0b74ddf810fe964f3b74bfdd79ff2191754427e9da298ce448f1dffbe0b1d07c3f187cb72aed34976c24f9be8944b65587441fd8e831703b0da6e35a4c067ce979ab3e8c01d31ec77b723a79e67051000aed32dc1d363fe2a6340fa85543be657acbdbaf5d6259add4dde95c83a55b96e034fdd97bc10827d6b1ce5b43ae95a5e2a78b2dbb13bb04843558b380d8dda7e70fc5e5ecbabe947ed03c901e3d903df8de9f9910a9f883fddb0bea70379434382b6d23f93117eae52beebfe90ec604939f8406f1aa310561e93d21d2829cc0962383b1dbbef688256bd7fd55ddb4776603836eb894c0bd1f60829270328898cf1ffdde4b7fad9ee79a76f1041b907f2fd76abe4f14a4c955728c0112199aac7f39c4bf7ddc3a2ec4a63033314220069dcc8bb68e5ed78d38d0a128b11809e9107aa7042edfef8946e77a0a4bd6ea6575675a93ca2b55005e9b3f5ecb4a7b65164e7ec6f3716e0845b233f907a4f9f9b7cbafbc12d6909ee5886781bbd2191f2bf451e8b700eaa3d565088e2eef5f9f91516e", .Okay}, + {.Lcm, "ca17fcc22163d5068d94c0f74dd9cb017c9c552a22709a8fb0cec74455492371bd9d16f458222e146c33ec7ec2a9bbae4c7fad1e0957bc3360844a160d3a63c0f0be4d30a28704c19dffb70beb9af4ea5c2bf73b8ea1f849a43ddc03cf17f862f9bf279b4fb1fdcca0c3c43d2bedc9b5732f37d1d3e459356a54adca5dbfb48a0f770515a3a8b773f7d5a775cdb2ffe2806729a91632050320b7dc8c7b75119795c94367c439820eff695a729213094d5fbc3c46259b671d34e88c948586881d2f1fae65d77d2945586f66ef0d27a18108f9c29c0578bb71a02bdd743dc1746feba2449fb164cbcbf9df068a52ba555cc6d88f07f5e0be3545c86a60e0bbe8062d654a01b8e840a22c3dd496e922550b72b5655b7aba2a55030fd2225f913f82b9907eea41c2a363ce47a3febc6a0738be127b24ce895ded42038c7fa6d9fc8a0aca69e9c5f7d2310cd69bcc24452c8604c9c97ce0124a579c7ca84a1fcc6d11b727d57b90d79909dccfa6e493d232126be324ccbf754b8705be097b41c0b2f8f9c9d91a6e6cad8e3cc90c8df3b46514c7205663e6a14059d76077fb0fd83b5347f4d7fd8bf7d0549b7ab7ca94ac217f851cf57db8aa23711646476e5f75f2f9416c4f3303e36cdd9247f9a3917ab0f83fac2f51a64b3a587cf9e50218153f78d399821611a63348ae25d061405ee7a8d79f7725c2d7bea7e7122d9b8dce1f9e862e788dbde698d1b5d3d03c8fad4e42328711f183cf3de92beb8fa3e62b5b1aacf033a7c15956f495804b5700485b7449992f15c3b47172f7819a37baa93b1f05b6d40a68ff13fc8c8c8455f388307feb2b2c9a42db1923a8b2552514e1ac5aab02ef620ee399d82caf6d39c0029e94f05ec352043e7a29f5d7bd3e1cdd767ed1398d131059240f4777cb58342dda7dc34943ed67d41f0e7a945f4e8ece2d1d802412d8d8e0819b0594b65b9b993110653d384fd3970747c2c065a2cee8c67ed26911f93ca418e91b3e0d258a691fbb15ceed9fd61a4f1df494d64227914beaac0efcb8d9d8eab7113bd93b239fb556032b6207c47292ff5f15bec09a5315764a3c15445762be93181ae2c7b0e0e69e7f566e1db165f3552e7325edc70d07b9a5a214558c3832dcb278573580c1b379e34ab55889313333455371f29fd1405f02bf526e10d4fc6d1ee88c66a0303a67f9637cd8982a449d14ca360c2a58f7d892da3d736f1b706172ee496ccdd62a8d5bf1ecba3f321885b02cd9a923af8b0cba30003b31bfb295bced2e4c800c59d4791fa0975a1fd15588bde81d1bf31982c2284dd8c013fdf9cdcc5c400f74eed766005efe0b71455c88dfe7fc0d87929904141f57cbf3197691e43a2125dd58dbd3bb3dc0a31d15db542ef5163d1f1d92c7d11d0bddbc4a9330d30059144e054c937fe2394d3bf4a3581b988bd0d60a744c12876c6b0e3b6a4abb76e261bab3fdd8d5da3e66ae0d45904a62039f555a5354e7d5b1787d37c45c562224286fc360902ad9939ff9a58ed9080f4075c18cc757ae5138cb061ed8e63fcb25adc3957701ff7d0a55a79ecdcc777ae79627c7d2bcb58eab28736e24023fc4f78ab9996a84e549982b4cad8d694aac7201c44f39b14a66683e59cde345e0385bf60996561e5355208077794c77f2bbd4e6a188a14f4b3b539803e6a7ad73949a3d76340faf3e5b6e51c36fe0ec08f6adcaded99e1774dc1b4b86c297d60eaec9dd471cb1e692b7dc8fd05fde68c331a99ec4e5feace445495e6514db4bd7417995de7bc2e077d0e130d18635b3fff10c3d3a3bc192988a0882cddcb07d592a565697d0b7bb4837de601727bbaea22006cc196f81e8701af1821b2335de3cd2499643c924870fb7769233bd6b8657eaa40fb639f922b5fa60061e6b91116b164e465a391342d7eadd6dbe39df3789c8866df9a28fc1148c1218edda710eeec22679ee3220e5fac1c64526a23ed445a5f06c1700139477cb4f109c0d91770e75704750900bfa247663cd424b12c53456fd6b048474047730b6b1310606c9cc0e6304bbcbbc76c9796a0f0216df7a51cbdfcaf21265133ae1a778f6e4000628cafb33fcc24dbac705e5e80461f2e1ce6ea9", "45c4ebb9334df2af8be4141c1159b9e1ecf978498744f4457b08d16c5109804edce0428b32fe84bfb64cc6e48bac90f885e53dd3864e5b3cb5e6a0dcf9f224e27d635e025669adef04a01587127a8a62f72ca1f54c87a330dde0361ee664021925a25a11c2ef2727470b187d29464e9566848ee974130cc4413642e835f584af9a74cd7b3bcbe606f7b3e972eb1ed8503fd4f8e32739bcb02ca2639a2d94a1ed40ed9e641f9373c88c3643048973722a1cfe4b62555f528d1bb573b78e026baac875b40a153595eb44e60316b1f07c572fa66d204a89fbdb74452ee9b1790ec0e6c5556e954784cd451bc15eb30e48432b439667edf0c4fa0fd8f480da32b3c3a610721efc3d41bbd78018b22b6ec9d46a2327e816e985beccf3a2d5c34d2d09b7fb5aed204aab275f81cb1d66cc837b2a1f33f3f0fa11e26fc89d9aac021c0d20173aa170f945b8a61642fb1067fe9f52926ad69608e1048848c2d2c6c05c22ccdda649a458d07f9739068c22c776729340aaa19f50fe692e27075c20eb4fcdf4ef77567434d0f53b71bcb59692b643dd42fc33f5faf4717a5822a4ff6c3e5246c13d5f66a1006885d88ab889ea711cb3c68f23f25412c30f69a6a1a8258f8d4bbcf026e1c9d775e0b7cc7a65f252b19ce3d305be680031640e706567cccdc0bf9df4107f5c2ef86a40f18766d11a723c02c44d0c04f7b8475bf3ee6d6afb999b8f8ce52abd5b4984b5056ce611d6a6c89eb39f94f374446a38298d46fa6adfa9a4f8b79e956abc1b74ab44919f770d604297e6302696185a8f898929da68f312dcd39e9aafeca38b83963313f9824f85623e76c0ce811748121fd084de792cdbbc8b7bd0327670021341d9fe20f586f93ec013a70f840ea9f7a67fefd71078823239f90dec05a8569923f6c8b5f651b062763738acd3913465ce80165414dbb005b2ce5b7ceca962ad0412c5e76d374f97378020b939046ec14f75f678e33e1b350aa46e2c89bd2116ba9e9011651adf683ed4e3c0e3af8ef33ac1acb5838e0a836d962c49f96e2d04274d8d89188215e9a045f8ca62dadf36fd3d127b5d0df5ce261edd7e40d8316898de36b30f2de60d780bfcaa87091219fecd11e746737f6bea9c4c89a8d3dc1e7221e0ff599a1a15c29d78f7e49300303ec999454c62b135bd4952dafa550eb6316d5ad164d08b546fc20224b41f7430b5900a5eb158e8584b8d430fc651c2cd6c9abfbb9f95172eb976d67db960646b77a7e8472910f6221c926afdaaa38fa2debcb494cf2ef9148c26b660f168666fe7d24de94c39e03229c81db62a37eb8034632873a74e58f441d8f4eaafaa3cc0553431729505583a59a734867915153835b0699929c6a4d24e35cfc2b9e65b90b8e94de48f4affc672ed2c32030dfc58da9c9aaf1c5e8c053c02ad80ecf5800a82a3741bad3463328489b5e7be1cb7c1987daf480da133b77c85ede59291e08a170f282478ee45521149d14a6510956b8bea3efe69e5a32cbfe43e53eef51074229aedcb4037d249c48c35579986c42ae90d3dcf9dd6e79d6a2e5bb3c9008a918477b7d6cfd1282f1cbd26ed7fe616d8689b8df59a83432913c40448e27410a88b5d58d0417a0d19e4e68bee5658a64b2817c4723c338556dc847e7b77f011706171159f703e8e1de84a27e1afd90d3484bb39b7510d625606462bf36a702e1b96c96a46c1e40572cf293bf1123b86871c05ba85b453c4c7505e0b76f081345974817ce54221d81e66de187aa01cd2882ee623b7e2137ff85d8b014a66de3d76e38f61a017d0b0ab19cf9ca78bd7883de015539601e4a6034f13b282bc33e1a8d6868973fb39ef59b22c2b0cf37692b151a3573de35f48cdeae7e852d2293ebf74e12de2a7e4b11447c5016ee576212c6cf3216c26ac90cb415bdce62f04082ba59bd9920811c816962469ef806ac7fe4651094e5c0b22fea287431160767a1f4741c20ed5ebb13f9f643e406d76e83345c6b02fda5746fe1f01ac1c13540259def69ac4a06b7e469918abc557f595432746fe82a525eda01e414f0e2daedad727f4666107cec821b4bbf86fd73682fbd79083f72046a570a9dc576324196edae98b", "3713eb94107da5f197aec1d163d9fd6ee94182a6e8b37ea8a9ba62b4f6299c114624f7b2eb8ae012f59281aef83cf795071c46c91f9681bbc6e698467d5283388f13f1bc8fc14d4d5dea1b35512fe389fd25ee45a6aedfedfdc8424db35f81b274802102248983c4895a14652977432a3a40fc22900a43f2d25c1542fea002f48ed8003a678eadd1d3c3579b7e9b2e19d0609b71639ab0636c1acb88fef1c416e3c66c6eeaf982776d4174d907d1702276c7e9b74a42f86f43eac6e050131a06c5a5ceb81e98078d4a49ae0916d218540c330181ea987f4922f22a11deadbd0814eb782bcf8d933036311adfb288540c20efad829d5a5bc781c9d2cf1c145e51167f3587e2d437731d114a70d914ba861a21bd72d60ba9870697955f024c4fdab2115a17d717dd9c376f796a7d788ca878c373817cdda898ae2430723abf590326ec40fd2098dec7d7ebd8700e4bde09d4f63eacc0e2ea91887c30f4c7f198645108fab035ad4fe6dafc5bbf1e8c8bc3770a2f8582853097e5254a0d5fdc34a22897945a517c76f6c11a8d7e337115148ff49b2c8a9cdf00cac0438d24d40b40c894061db1c35993171c5c44e8d1c6da275771771df4cf4040700167495bc2a30e07ebe7b2f4761b5bb6f1764df02cddc4dbf6906e7778638d5c4d34d648019a155511a6dfadf114253ef295589c7150c287572a375c0b83480c2e135cddae72b32f654171e29a812ff74a8620acfbdfa001cbf51960548ea93d561c6960e072fee8a6dd22c46a2ef8dae87c1db4348cc02a17aedaa3c3685a812dd8eea55c1aa695b5696b73e9cad7ba285ee3b43299f9f2ae1223e2f5247567e5d9ffa492f780abe0efd721b0c400b12c13a3e97e3df8e711018a92e438e269f803bc0ea1413a0da30db10ed90ac753d82adee198a0161408451f4dde770d2d6516d446a47d34de97f787b608ae8667b9cd57b2e7732eff79b083a48031a047b02cb2ec120dc34968eb99114f229df5857f00c5a4cf636edfebe7b22c4a2e4f6ed0ddf992eddc4251f35c9cfa1ee0618db36a1911bca750417ef0efb99eba58f851e92a3c5047ed8e3f28323c5aaf90870efa763ff4298fb9ca7a10aef78c9a754dbb6e1a777de6bd209066d8fbe8484c61aa55753f44f6a66f5ab88116aa018fe966c3678c9e86f5a4b0cf1a673d0677aae94d3abb343ebb1ba5545ed93884182ca10b0acbbd6a3780a08db9e75f972fa29bb8547a22679a07f9a7f904867fa93c3f1abf8158166f63bb889220480547993a50dbe0a9ff5f50f2723c2fb87fd56ec6ab811ffedb3f4719e0eadd67782668f29f76c515f7bb6b26a7125ec170139f49d6a248a3c1d2fa0458ea2e1196d24082f6b43fff52e45be000920c43d7008ea55cba0833f018205bcc81b66115bea63b3a477f5748b6df442d410ed71e10e7e1b5ae62d8b03045ce02c8f0e2fcf25e0f7b858c7c93bfa26759b11e35a0bf1d30e77c0995fe93bc4f7c1f410f2b25007370feeae17e35504bf29682b0a89ad800c522dd923cdd61e37a22572ba284788ec8987f3a6960b4c9d1dd6ae8e1f27c5db17671d01f8d1af6d745b643fc4911ba2255a9d7219fadb9befccd6368a8f3ac82a401b28d6cfa2e04f287de28c9a17ab8b35f93c8343a513bc7766807709e7ec3d68e9346911e2bb4b8eb4444eb0d1a413f85a9cb3999a53638de7196a9dfc1396dfd931da1c5aeb1834a9b5570c1ef2d659ff9214271367e99ce181796421693527037fc806cf5ea0da27c28d8beb3de5fcf7eda179e399267ae73358b05a9d0eef8a44a7b9a5e6ebbd82c8577720a911467a76f33c49e1f7f84ac6fe8e93ae2d6b18d2540dfd6b17f1a0a0013e49d36d18165950f1d788671c2d33458675215a632ab0ef6780d2cc7cc3ca77ba538e042949815ca921de5696210b0cd4a34254bd89dc1231f3634a8ecd4e579c6bc1fc52d1a774c40853b64880e52db237ed373ae6482ced137b51c5e7b5fff945c192ff25df7d8e4ae3455a13c669a0c2a39070178856e7d9bd6d8538fd6743a7f2af0a79bf7cff331525b04bda573af18b55c41ff2da0f8878e88779bf62e879fd722147b7c8b45a2babdcd260196a86057b6cb557523d978649f8416739998ae7723e7e2a13a9b243c893123ebd81e17e82de51067025b6f6992f94cf8061f7b5e807daabbfd68a1da56a632be00d6893db5f8d20cae7da2e0a4c105fce7707182306bebd10aae0106fcaf36d40e295b3da91e15dfc55d894cac2ab10ada071e187a6337feb359eccabdbfcf07b1bad5a3b27de3a4372e1b79350efce6d5632985885927eeed8911eee168d02343bc12b313dba0035da01a3350592122e8f2483a34e209b7161f0639ce40c52c4294eed67c0af27ff1274ecba6c9cdf84a4b5cea16bb51df9c4df635b56340c61088df0f11919f6ad70683886ecefaa02b45d1fb8b3e401222b0ca689179f876fc557dee04cb0465759d8d2fe80084d085db7ab48d15251d0f6e0b9bf165710a30f9c36fae3878254ccadcd004c7a09562e0b8b54f3856009af58ae0fbbd03ec25e84aa29fad438227ffc21a3145dcc04fd4827e39925eaa27c5f03cc74cb419752b9c85e670279898ce18d33513b6ad07c614a0f68a6118d09943512da67cf38b9077a1619064e7465b75f55ef653618c7851ee6364fb976534ed59755c0a2a4e5828610b52e1f80f46adcfa954b8f1af8b6e7ede89341cbd6d84f42cd17448a2769d32a1e9b76c2ff04e7d420303178d91f6e0876dad9831977b79d73c80a8ff000ac705414516d6a7bac80f72841b76e8c3aadc94be11d5b735a5170f385bc459c76c36a2ae56c7322fd16f689353809f5ed881f21a17b062351d80e29fd5589d4ed46790d8b7e908f53d9020d516a83312abb4e8283d9ccbb04df3f1ae5a36d5c81ade0b1b896fee39f6991409029b6571b8f38c074b31615e33be58f145e6cbd891a620c9c3248bb704a11c06daa41e95bb2579d5b5ca600b62cb7a891582cbde20be75a9f7af53f9a32b3680a744bcb86d34537be7dc0ce18698f36dfe7e2ce111331e47449e74356820ca2ab84427b313ad7ca90d6afdbbd94414b02ae4896a86da4d15f3ec9771caaaf0ed3d019fa62dbf97b063d7997b37b60450afc5dc724eb74b4a91de2afefdabc93cb9bccbfce6c15435d3f14a7be8a63ca94a89991a4ce8237eba6a034c5ad4675144ff6f42bc5c2ac0aceabed6a6d2597390c2bde0cdb3e63ef9d87cf284f225aefaa74cfe8057fca1c105dc3568188777ff77adf76b4c2a7a5ef688c1f3cb7f5af277b7391dbcb5daa0a3adbfdfaed316eeda04945774cf813edb87b858f8d4b8f182cb4347cf222d042269babf91c220c9c1d5a032ecb646a655419b9bdc576224914fa44762f277f7631bb40863d9611cb1c3c54b10ae02044814c747f165c100194cf5a74dacb078168bf07c0c81bedcbecff10a0e445e5f19334f8466c7fa164f101ae63b9e840a23c6d1ab981ac87eea04c04c0f6a0ae3efb5098962752cf58e817619ee897e610e8f118de62e3d6206b7d0d29bede21d58b3493eaa437253ad0dc591433fdcd209f1b4a29ba630222d77db0b77bc7d0a68f50b7bd317ce041a1073ce63c05d9e3ac25757cfffede369b86d8c7d5612ffb3fe522c0a200f23858f2cece9fc9428391c55fc7a42015b3e91fcdc4f2e4e13f6ac98f0497c08cbb48cfcbcaa9fcacb7bc221eda94fb99aeb1cd01f40968c9664aad38b24d2d80d9e33d9f6a81afc873809c204c43b67b7a86d55a9c67dbcd210bc26ab7fa0686ee28e0a7e842b7cc781e8d1795ac3f92cfe71e953aeb3751a833e576598ade653b9226f58fc28cf53c8010a88dc70d430f526b35c921d7625db1a11f00ff6c68625e52d5e8cdf165bc39be0fb462097f140ffc2a3e96404dcceb9a5b39183ee181c29b92bfb0d7d9848610b337be8db3d208c204e66f73a0f5e5d82317e402e0956633aa028a7b724e73e1f4ee739b4b07f02bb004797a2dde016ac16330d8395ee569b31ce46f64661cd4d462aef106e6169210fb8705a7ab91b1645445bd7783a20c05dfc94dc25e77bb9b87c11e77724d19e4a8a0f7898ba8cc98e03b9d835cb4cb4aee37aec4694f487a30fb52915ccd58b35bfcb872b508ac9974d8fa9a2081d67d8eede21e09c400805aef1b5d0992a5f6eb1c6f5740fe596d57f90421fadebbb2ac6f80c75ce3d57b7e6c3", .Okay}, + {.Is_Square, "c461177d9a0adebc26fcaaf800877617b9b955d76140203f873d4fbc9d74115f833423d942a5b23e4ab239e84a5504f14fafd4a1f2cbd3785487d6cb6e21e8000a56009bdb6f5175d5725f49dcf62fd1d9246d1ae6939a081e7a4a679f4e0fd201897087311fc74811824ab595d526ba23c12c5f7cb4548e5a7927dd0f73501668dd6d86a18344c986e45d979fd6350bfd59b2023b7b3252b3c75e7c2293ac4bd777bde1a74d8892144a2965e6ee1916e3452fa316946d3026ae63459c20d92a0ca93f613882c017978d11fe994a2e6948153afc74c5903a29cbb2b399780fabc00012a907cfb245009f6ee4d04c302e76bdd1d6c493dd1158c9943ef33f290edf6f83d7c8dad22667781e0abb519592e3e4aef9d4e4e700b65a88edba849dd0f166515213afd31936d0e712eba96aae93e1d52d8de2576d213aaa28c8af3a2657435fd98f125ea0430ccd720de5a11ba8274b97d3bf950b9247deeddcfe98590ccf8484c73b34aefbb4039e74290e9e3db18cf8b187bd21ae36c6b4a8869aab6067d2ce5ea0169fefd362450d1bb61c1b62211497683f79c0569c8da52d31a28c14e89c1d47887d175b5412ba169c63b329884e1e04f02142ec8bd658002ece525001c64d529285b2d1cf040929ce0983b89c005b70a38f0112039fe407ec1d206ea096f4f2fab2b651e3985cbef30334bd676d2fc4b7fc4c0c53e28406af4d61e629f972bc3acdb9b51e41e0a329711862a16ad10f201a865cb2b9fe987b854874c686af4a3ea835a89a832bd8bd70b46011e44b6a37f6a307a4569ea634cffbf6ce69f3202338fd8591e8ba81199c2e92f2e98f9744555e18d6e61f142c84523b565d508fddd0a13222b63aaaa49188c34f637d5b861c44306dd8b4dfe6306d3d03c07e4c7aa8a652faa110807e99563a80f9ba20001bb442c8c10ec63074c20b9824b2648ec07a4e319580bdc83e5997eb94afd5ef2c41afe5081b0be8d6007db0be460eca4e93d5dc5d396809a8b466c0c6a34c1a36fab565038326f30f9eb4d941e26087706f1db895c5f93c99cb115a73a8b4d39fbb2339a7a17135225182a4e96ab78f667cede2c11505aec275a22f3e46627a9babe906fa9ba05ea04775e4ca2485c233757f976b7eea9dd97fc248e425bd5b98b7317f89e655e5a42c40bdec0e734645e4d510871f123c72df0c3c52d045955198d07be02f020d0c657f10fdb0ac1fffe7b8b600dbdb1f540dab27adee1951c46960db8323fa319af804a225d356578f950559f0e68fb04743848f8bacbb1e33704b26fbd2efea8a3024357a047c9a7113ce6cac1bec242be8fdbc56909a85cfa6a102f1f3eb0bdccb52b573b7b108a16b76c872318d111539bdf1f5e27a6e7330e0a2edfb663c6cf4fe96e5df0fc8777b1130d69e6b2bb011834a91e5c427f411a3334c83b8f781803c7dadef7556fb09669170cb9b86c997e05e7ae1ef89e5ea9bc654437e3d47ad2fbb7cbf64902ecc3369b0fa64b94a6f505d94f2f2caa92eaf419dd827b482243e8f852962173ca1127efa1e608a53f4f962a9af8984c09d8ff62a2d69b1da4700c4fb9d9fca624d9ffb4b8eb8df4b137e3f559835ee0e69207c99c95c5714a2641b2a5c654c4f5eea34a5e1a30b8c19e4a90522a8f1999b900bca43fbc982d346a51679b160decaf5a74582c5c0e26869c7ebb76d04db40ebd8535f2b73cfb8370152f1efd9eb9f74fe54bb72802c9c11b83474d28ea54f4126c1b1328e9a2cf3621a19dd8e273f3f6ab5b6934c72a25666eb9f950ee71831e449ad02faae689d482b5da4e97f9544863baf7072d357c86adc659152792fb15a1ceec3353e69e2bd29f9475a133748d57389964ba24dcf80ba5785fd6a5181b9afe05d1c68eea81f49be4cf9b9ad43a3d60627cd3f997408b218be71dc637365c57bc3555f678bac982809bf9fc7131f17f0fc581ad518d025119b5c041e9e047a1ab045718ad52d31cd85bd98b0b2d3c675bb0d61bd53bfa742b75f353da81ba667eb563a2580c97c2983ddc050ac164fe90c66991e315780ea5cd30cd6144a9fbd64b17f6defb1f846d886e60ed2e8eb317ecc6e87014a33de056aa786396f6f", "0", "0", .Okay}, + {.Is_Square, "fb74f78b2108de631eff54becf9460c5819a49f98bbe9fd001ef3f484fb306c982c7514799de039d9026c76ba9e769166ef2e1ffa4ef8279b4257f9729adf10a8bec22b02893cded97cb3cb080c3209e859449c584b376be06dfdc3e2cac13d0178e928cceca85e90467b8536b51a007dc054af1ec579d208c4a4a3be3672758c5ef90fb9882fd1141501811b1ced6746d1f9db64d27cbec141016078a9b95e4d07f8ca2218ba1183c16dea9d49b75138dd8c63690eb1f449596b2f50c3ec499ad15555f2a43a00086e3448b0adec8dc5e9e3b2b8f3d24b2d3c515962a7037d9220d6fb4433ccc73081e53e233ecde0906d918f219367584f95698bd68072f218d557708c3797ca9746478080d3466a9193afb712bbc55c25b1ba496937ba73470a7f5543a668a2dcd062a6038f10f382a450442752c7667de716a178855ef2bd03217ec02b58340201af4582fff74076e55887d3eb4eb91df36d0cda89edbb8212d41f3e8ff61b58edcd46b863a080d5a79b7d0f9c2b275243a1184e4470d27175cf8c5420dd10e3d0b8badbcd73c538d7842c71d1e0cdca6992e015afd3dc82a9420eb6fe7be8fd20f7c7904b8a1301926b9fff64957edeb03589de1316660f16fe6c7540176b841e2f88a638ff3f96e980766b67a3256831c19d0e711ef70be91c526cb13302aa1df92fcc7894b6907461158e107240eb16af44bf5cf6028fc969fc1aba74cdd6e9cfb71193716bb6d3a10d67fc29ff41c4c9b9098f5c29e80725f316d3de4e364477eb08d7a21f218a1a8f1e95cff80995da26749f591591f988d2a7935a992235f4106bfceff497553efd5707882dc6f964cbabdc896ff784021f1b06a291a420f6667adb3a96df8d1a91e7b41d9dbc50cfc3955665d450c5b90b93ebf5181321e7694d8890f82eaf11588f8647b21e3ab2c21e4e23b710cb8270aca000938aeda1da3f9967c1bb9faa4ab8b2e382a6828d47d54aab4c2cfb47c15792a712efc43a755676c8643edb6d2dedc781ec685041b19a20936e471d736a31405e10cd9ad6121e9e5f3c7666e9a042e4e76c22f2ca65afc59be0ef444c2bcd23994d9868666d7d72a0bffe5b6489dcce2f602b2f279c821765a101ceaa19769e16de7a7d3ce3ffff47a4994307bc52652943e3ca7345cf37aa9a3d40542b0714149faf5d14e885fbae1b19afd3c800510c2aa588c0f552947e2ff76976ccfa9de2e2f2f92ac7d08c4f3df3f949bc0761de6a404f79e1b83954fc543e711dbf5e7e15700ce5616f254826eeb8563d5301dd229fe306fa3db5c14d70c5e47c51fab6e1e2f0d3df1760d219ba63f7cd61e8867bee6b19d757604b9856ffc9d73dac7340532b88950579cebea7faaf931153d4f9cde26fb4be2c57ea21cc313002c8cbbf35a4d13340c839351330db785a209bccfd79e4dcee9660246bbb128c98529f1d8ae9da2368d480f2ea3e5c0ba2850e99658680582bd81dcf94826f2a2d87ba9bf2146adc3b2ce035b9db1dc156935f56d730f3879cdfb510c2ff57878338cc911508464c1e86874969ecf15a06547a8758c4c0ff12cd73f90213ecd7ecfa3cfd138cbd55204704ce6198fee3d75112783b202767c4f782b4f2b696afa06fe41b72db4d2c42b3740b400b8ef54b8f332d640f7f47995e599987232e00ee96de5759dc3349c92bb6f6400b660d5697debde42ed639d664dffb24db31a2f8a8ec2838d62514beea519201872fa735326e7978b34b48084d0989e2527ee0c3abfd3f2f3c68718e8e7d52a6c8be50a2f3f9e61bea9a6903d07d0ef49ad769fcd7df2f7c459dd64ba2cc32902e55cb49e2de444dda93aa0bcca74e2c006056424d10262ac8aca8a788918c4bdcb7dcd7afdfd342b49e03803b16703075384b5af38ac0bf7f06e5dd65876c5edeb6aae9414eca61871e40aae7748fb5dbefe20e1e8058caad45e5adacab08ffa2ecbe23c01c575edeeb3ffc22bc79633c13d86797facfb726415ca019c74a13e6ebad699e9e5cccc6854af61e2be724e26fb75c5f627b04dd3b204f66531b76bad3c23a7d5a175636ffffbf7d40832a09843c96bfc56c28c85ddb8aed5b02db007081a317f6cda6e4c56eb", "0", "0", .Okay}, + {.Is_Square, "ea68eb64a026d5b5d71f86241a7cbbd20882739878bf867594248ef2795cc74bee498f7255b4cd87700a2cbf0ec14c28f897ca008d6313a0e41378753d01b5f2cb7a7fc41ceaf74ec32c996f9dfcc1a2a6dd493f7c7665eb5be3bfcff01d4c147e72f9e0d974fd7ebfab2fed99dcee513f251b3bc9e28badf2f0119d547c86582c626a8ace62b3fabe5b86b25b600cfb4a15c3c0a8e293b1cca70d641590445503ee9237611add949f6024871e3b302bd1ebe0aa21fb1909e5a2864a1ac1c4f30f6f9ad7324de9e3c9832dd7ff48fdb762aba634e12ae7b27f626ebb337f72fe5e572d1832441188c4474482699a237dafaea2156f8475dc34212e05cb78bc67471b468fdd389148eb99789c401e661c803eeaf99c3e44442534c37b51b4407e1359c98c9018aa9c05e2c582d916f1c9bb50c1c0f68fcd87ded3db3d47ae6785bfd6781c91a25c6f8a36591d99ed347a74a88d00527ac7eb01023f7be09d2aa0651464e6f0411aab60e82d5299cfee2940fbc87b8cc1a6ef765ffa0045eeea16f4cec9215f33b861ad98a4d516f689903850b620be3547f471e9eaf7a60a5ac104e420dc8abc42e231131b29cf2ac3f283df8259a3618e8d0b13fb05ecbdce998bd9590df0752f62f239291536fc126e3a13a54498f223cd1e06a5082e541b0b72b6c966b5d6c4805350cee7741c25eaf6f26b68af5de1429d72b34d43b4ea9f7251d66e206ab0dc323407c90f0c593a39539d0eb070d70629e2f8b69d987f50855875970eacdd4f6abe71d8425d6d090b53f6c9635edabfe7dda4e2441b8cb4612d96d2189e8764e863abcb5f92079f65e4bb24d11ddcbf4db9ff51b9ba678e21ec661701d3f2bcbe17793bf546996cba51c9e85c65af85b0e8ab05baa46027b44f0d052f85003689687a8d40ca13957b10dd700a3f5ee021cb56e6577a0cabd80f8df5b09fe2af09c53553d039f1fd869ab20686b5c7f6d6bae8a095cfe98a036194b662d362b209fb48452af7f64de68a301fd2019fdcd71a731812d39b6bab8f5a587e281f2450250e8f4647068cadea4a22d6e1c89db629d607591a5837437032246a809e8bbe2717619b99bd91800eb98b0bf38f34278ecc9b4fe186227c1c9067b19be384318f18739e987be9dec417470488599df1e11418e6c27b25861430388789b4136d96692163f99729438355414b8835bd19d5ad58b2a7ef7a911e18c7d60c000cd98cec23ebd0f143823ef87edeedbc40f321feca8bc492587f2d6df752dbf69b59c55e8aceea9d9ecb6427f5849aa022be6764570eb3992f83be40546217fed6393d002579bb484531a00678e4c5ec00fa50138f6dc8490089ebc5fc3b468d95ee74283112fd886ae2cdd41955061ab37e9d4dda6ab1ae8f2230c7ac12af154448aaa3bb2bb8ce1f170a543969ce5f299b8cdb377fb423167588759c134893959d6f8c3422366e306602db684927bb778d3d1d6f53726caa9740bd84f0ed1d76b826d6b71e9ae55f7afc596a238eaa77f15609fd1b802dd0b8756da3c2c5f325b8f4d626c1f2179998f62d5a50a85325082d94db4889c95b088bc1b44b22860801d6b5d14cdcce36528ab58a0802b865c7b52f8dee977b12f2e7bbf73da8dac128a3bbb2d68d92c80c2bc04d4072c46bf5b9976dddbe11c367c1dd08f099995e5a92e0cf6a8e3da350304a8e0f6841ba6958aa55548892e283ce8c8b3b9cfbd40cdbbefe2d11104b56716d8bc70eaf7a3e874db0de5693487372634d723ffc418d59cc25b4716278aa24bca4a359e92302f10c9c40ed742cad49dce52af1401f6c31ba9ab88fab0ff47f9448aa5adb6eb9c5814d29c82a55d9705e8b3da3dfdbaf2f022efe78b0c35fdc7ffd844f288472f660e2c38a4d3e6c400f8409e69235ae3c026808f170cefe7e40fde1b6956ce49fb6ab0c23f5a9e49d286604bc8a45a0fa6128d894c7612262c0b811781cf8b8c0d2e491c31e27c8f5e3618d65acc2112913623dcfbd27069302d9da78e8100c772a339c24aa7a9360301e54bb4a53780854922f2d45bd1ce069c6aa1a50f9a3455d5a0459a5352ade30455df6f1524b6540769f4962d9fc6b916e2c1cece79e6de06d", "0", "0", .Okay}, + {.Is_Square, "585e3fe9e90a22d7ca600c8d202c30caa28dc63e095c3f4c8766905081c4a2019dbddd5acd9aae8d4650b8f783dfd630a6d60718ca6a22ed2cc82a80f8532fe9ecfde3051c2400597ba57f523b7daef5f38b71151c016ef1a2bed6a15626c7008f695dcd0193034fd85163aa4b46c9d983d675388974ecfb5af0ece85d4b656571444bb803fe2819dd287c084de08e0f3cd1f3b18f4faa7b3e0b1f5664e90c2c2c715db4712933bbf512e27ff08bcc88240eebcaead8f896c2dbf5a1cbbf27f860f566d7479ede4557fadf8e6f80f9592af3a1062d2020e4fc5bb314615df485229ca5d9581acaa724b144670947568bfac107430bd48c6e1ffe60952863ba837d62e31031b27592ad87fc5a7823c80990849e2fb7738e2a50f8569f7558b1e6582d3bbecd1d08aab6f8dbd596070e144c85c74f8a3bf481a2629f75bb2b8d6e75b88ef18328ed4cbddc8faf3ef5677a436fc724c6f01ff40228dcf7a5bd39e2e07e6c440cdc7cf2699ba9dd250a8001a76e5bcb39dc40fb9669b42edb89005fc07618f8010ccc07040eedd5f433fc0d14089f35b3b8f79f91b50ce23cef58b4400aaf1812b334f15799a82130c013d74bf480fb8af6d37c6f020e66a7b78c14ea0157251689d6efccdfe8f77f7bf0765064362ece9568e1ce0e5c7c9110368fd21e46d82a1d37cc9e0df685d2a5292bae03dfacceeee8590b25e22c1fb45b56a74811e3454b0a2caebf40f186cfd95f0cfaac0849169f2521bc7f3c1d62135b20bd2870fcd472ef2d153409c07c7bdd7f3f650c65895b0a564d57c0eca90cf46dfd4c71edb86334695ee497ce25991478c80b7d05134928d3add4bad97e11694955946f7b0fbaafea341c470f3eaa2a557dc9b8adcaf95de516e382ade83bf8579067f518603a4d588fed9c2091a3110b7b13b1ea27e71a62b418a6516efcbd74f746d29681c0f3b579e6a1db80b5542a0e1b18f92d3a262521e4d3f6b1da5262baaaea6487e426cd7e7d9ad97ab795f2c9ef7d17a69299c02b05bf041fb19e82bee4c61f1bbd7e732c80537cf872576b789e1102203fd7427c8567bebf936ac0d706cb504d2b4132ced629b26509c43d5b03fc7e08cd3e4dedcbd6f7f762ad320f4e80f6bd5fad9b587db22cc15d8d24f425064ba14ab37bd53bb4b74c016e381a2753d8deba96a3f79e0932c067ae2a8a95a32ded6f46c113677bbd6d7d5c3493eca61939f2bf11edfdf37cec897cd5371715b3f76bebeed4c8dab20a0733aad8568e2e6317d39a75b9fa01cabf126e584186062622308e752eaffbaad2aaaeea098355d1be918441422b95ed667fdcd6f26012a717e31c43511b880ac115ca9564d3506fb5889f5ecfe8a1fe3ff21373be43e2f3b64e46da5934fabeb8dadb994a401d5f2c9d056b2d2f74ac225ba65666df21846507b97bc46c4851a11a590c8c15d5ec065248306878f37541946785f9b0809396f92fe31cba1e891d20b4ed7a48509e7008bcf4388805fd55e0285e891e12625a6b9c1c96e1bab21ec13c2ed034f28bb49722b928899be7dc10667102fcb9b8cf6b38c3bb248b8b5a204256ee4dd67bc6dbfa8fdce6191f4b6751db230b4e534f06cb2652c9fb2cd720facc64973abd9309fbb66ae37916479f3daa59ba1ab0d81e8868f021d9260e53b6eee7c4e7a9bcb0ae06cc10a4efadad8c64f63a7ca218e641aa1122b24302b8b8a689aac2f6b7aa2456459af1bf12d0367d239b022081412d8c9fd839909d5340a825bc3a85eb174265d48422ee7e9c1f98472a4d01a8c31f968819e5bd4b8ba4e38e57fa587692a1cffd8bc01ff35095a679d42a005ee3a903a111aae365965ee0cb77532d94c7abb1d36103a141b74f70b5a37b374dd646a1810e9150326855f9790930b0814b7a7eca8e977452dd39ea42afd7d0e60b2be26cb8cbdb8535566708e8743ca14c624b1f461ff61ac3de5b60a51d778a9b3843fd68ca6d8fb1e106a27cfcde040e6004c3ea1962a8cd3d8c79d68cf30fc27c70cfa85331c3e858b5a2695ff102640a4389cf3499d74a8919ca76fcd7c3130c0302bad97dc2e3a10369823cd7390f631d466e900288744e699df2b61a828241a9f532", "0", "0", .Okay}, + {.Is_Square, "1cde42c5d948096dfdbe4b34e4fefb200179a24d4fe5f772a643f39319668dd2e9468067cffe337f8f15080ae7ef7ecf7fb7335aeff41f75bb79fd8b0666bd7929d63a729d2065d3ec6fcd5e1ba228ec3ce5552abd2f7a1c395150e2372ded85180f92ddbac98b0463f85f7eeee9dae6f2b87ba2475172d2c4c6b8bdaf741ad086e0f6fafb07f245f8c6873c4171252296bc307265b8ca4cb99692028e57cbc8a82e3dbbfd2e485ba338b97096edf9e8acc8d8aa569ccd12c9d6479b843d1530ec99726d0ba438510b117c6af01b2a00da521d81cd2bd2e665879c142522631cd8da1c76d3bd1551367803e080e9be910e625999a96387ab4116aada82f1d659c4b70bf4a5bc07e7fb5160227402e0c9eb1cfcad44bf249e328d73ea02a405f8b8cace37c1c19c93d8d8cadf35ed9ea5c45a90bfb065c90a0c040683275e8b6d2eaeb85c72a629ef12b749fce86dfcd2c5a866f336e81251fa20fe8f9af0567b58653856b79c4811e087a5ebb45c9416c8398bb163ebb521769e7fe13bfe883ee1160db09fdf65cf5c79396ad021225f53ab7ae7f43e7b8a2dae02576a211f99d031a0d32f7ad2a76226570c0dfdb43852faa581e5aefeb61cd38c4911bb2ccb79673634c6f9655dcd1c1546d471032c2233816d7acb4a0c766d2f38a67f6b6776550d3a125cc3c4b4b69ab0c1f74c7e5e4d7c630799a25e9944562b59ef296811a8144cc7fc376490aa3937aeeb01bdf29e80b9a7e1a63dfc9d1ecc5b4e1f5a05c05e74afae63841e7c21a655d2cf8609110d990f7a0ab693a4f166fb7f07a8e68976fe6bf6e8be31fb43a52064d01cd275dc11bf676282e3b716ca4d98574b8511b46f9467b2ed9a4d324238aaa84fc2ad628b32b03aa573a30aab9a45cbe98a5b17965ca4b895088e7c908c220f6616e0d38b6bf8261a6c5d336d1b1c9b9d6455002c8ade10fae25f20cb9e0543396eb3197fdfa08b6835716d3f434d130d8bf8f75948282f848e8dc851a2fd018f4a06e285b20dc77d33d4f95304bec440fd9dcfe0e17f442a8d8ad1746f3e3a8ddedd4ee5f770660b9a66a239a0516aa8c10c956fd6d676e4609dd625e28fa5ffa7aee59d024db9932d81f8030025a78f98a8ff46b70b0d10e2330f0cfc5d95036788812784bd6da3cf7034b4998a2aabac2139452d5b3e1ef0d2a7b8c829e9a3ec07972048796bee2ad13e1d3d4c7464afa9308078c02023c6c56b5387395cc55c67a5562ba286fa259fdf2a318869d05431d6010b4cce91a02acf55f59260066f22194b714740d536846f0b0f96dae9da2563757d1a3ebd6656642f2ccfe6705aaa6fb180a537e69414121ffbb4795e9af1b9d8e1d430b1c15e19e3885ea70d20937cea03697fe2fc80501ac1eba9d5c11f6cc3de3f20458addbd548210cdbac026026c20c688b027ec9423942e8465fefb8ca39a084953f483cabceb299819f1043d25173d465cd7ef0ed016e0e22b09b727f009dffb8f441e46ff3aa62f7152b02be115b6ab27b3da281b949aed232d8d834938c829d2f2151d7b0977317539ce33744c77c818390685cf0dbc59a023c78168a540436ed41ca6e1eb6be957620d82f6aa1adf7feac2bf0f41d1b6550c03ea92159b01f5f05f8d1c51fad0098e2ca877327237f2d75e2811e2ae1a5d5cc99af80d2a2e57b88b8ae7b783ce2736aa5c307b2c66f264caacbba441369df449088f32654fbd9f8121e79326423e2b2c2cac945c1dd9ca3baff61eff6743877585d473614c71e18e823edf0758817df59aaca73a90cd662833fc0a74b06fbd0fcf6758c4e41f88e92f7c11c8d8543c9b4055110dffa3e25de548f30dc11513c0aed54572889f14c2087aca0ab9d7f3cad5fdd381bd80cb487d4f8249ca3a8f374521e44847818fbd910f6f23cb2aeb1b8ee68eb8e0ed647203f4bd1783bc8d0accc08e7bec8286ff0f8b52916c2441173da6bfef9a02e96d0c2645c8d27fd1459898582729b4717af5dad5625c6721aa5d38b42358be38bd102797548b3405f0f5ca8030f4f543f4cfb7a1c33fa5b50dde8094c16a66030722d96796fcc84382a10bd82bc8c61e9a81688ca8be4ad690f59b278b6750f567ea6c", "0", "0", .Okay}, + {.Is_Square, "8c574be4a98637730a1885cea65edf97f148d3749dd39fd80bbeafcbb9b7f49cdd12f86271da4b604cadcb8faf8f82eb63c6e793abf8fe36e64ded098e44c0284ab13d822e471a6964440a3bf2c768d3aed96d78f293a7b6bd3f970229917a3165f53913d89faec9eae7e655c8a33d668ad9df85d174e090ae151e59befa72fea7b74c1bdc6f0be69927e507a966c87bfb546740b420775c56d00593c6ce05a40e5cd8fa8d2a4c9f2b07da9979cf9f8151a723a9b53456284b7f4c8908fe170c3c576c1a8a0e4fe2efe179b31537b1a5e84080a49198b8c39a123b4dfc811bbd70fe429b26fa02909a547d0a0be6b6d569d98dfb580699eb92a7750eda21d67a5c062dc07152bc5a6cd2341f9e2757387e4d1e7e2e65a41a6f16bef4ffac016323a50b478d3fbdb5dab20c1013d4fb5b9afc49f0ec3e0e22c13ac881fefaeb24d3831fb36b5d776433e8831175724f93064d1767bc66372234a5dff4140065a360f375b6f9a74b72952829f8e0b59a16336cbb61d4433cf0afcbacd2fdc385e3cd07a78b34dc6100361ed25c91a32538bfa4d03150172892e22b355d52517498aa56edde10cde275c98c114ed062275ae07e5048805892798585e8d67eb57fcb872429f2451c7b70683449362a612d33ac8a8354f59a3a28994a98541d8289daa4f930ed338f4aab1dd6fa1d822f8dbace17302e0c0a7a167df7fcf81b085705a2072560b16b85a9f0cb808064b7d6fee80ddf042f6aa0daf1acaed6002e46b0b863e7e9d230cf7467e7a3e301e709e21a737ebc9281568dcfdf37d6e13059c77a12e80a0a5f97a2f66eda2ad5c8fd9deff1ec155748aea090208d53e6dfc5dd5c65b72bb1cbd1be5ff45eb51e51bda4a25bb5c544f2d636ad377d7fb7e1f8fac486929c2c8cdb860d0b746bf05b291c7da67191b10a91f470f0e4aa63d47a76a2eab7896eeba60b5fbb4a84e4bc20311c983834c1d0446ccb96b20de4833d2d27a71e55f5ba538d7950209c4f3b31c32efe36c5c045ec6a25d2f21ae56c82fafcf5806c1e88c731108d6379f25bd3a5cc355a0ebed1849208bf2d280d328117f13ed41afc9e2f8ce5b7c95d4d158d8e34ec4caac48ff918f6a302082970731a1dde939ff5c23b80597186585a7da2289001c49606bd49845abbb8f93733082d023a4486c8ba5d4ab68393f88074c08e51b53cee43fbd20f0702d24db91a876a2699c72f1670bd47da40b56448630e995485246d339200e5c3ecf84acb685dafbfb985cda2a868fd41bb749ad0e0b75cafe67b101ade2b03fa3ffe1e57d165b5a742766cc9ff6e18db96264761ccb8b3e5b476665a6705f9db1f8235da3d49b9f3f815693a7d5f07cd86cdb23d0c978ffeba9c4cbf6201ecead28082c1544fb9fb4c952254e0fe6eac2560d42c60fe95cea2192156df187392500f1362d13f736c47009b7d2102e5c8e20c9b66c097e0fa8d3ec9b12a7449481dd70b2182d26682316ea4d39cffb3bb116408637b8db6db6db42d6773d468e593ecc5b7a71017495842d0a85cb39b1c6837c0abd36ac28e12893e8431e4522a00754086c0a23edb1f8f207e42b7846fb6f9eca77c1411c25b2ade3a20b3f08596f6184429731b956186b43beeb4fb5345621f110801b73e6cef7b4b13bae9611c655e5c4c71c4db979719eb39142d0a55ccc5c09f880320ff4ef26a9c2f68f67c115cae7b61339539c81157c6efaf19e3ad984ae22c3ebf1fa48a30fa38d5e00ed00256741ad701da7d106235dfb1b787066b4bcf010485e1c2dc654b5f85c380db0d32a291c5c507a52dfd4577ecf84577e9e59c34ec27f1b2f6e2bf64d7f53b0ff2142419777993868fcf818e71e78dd0791eef5c7a90dc2a6129f4c15ecb70ff601164734bb1691b035296ba21a6be428d1f6902daa9b59bd4a567b42ac82105e58965566497e9a38c0de28c278a177733f6c455be8ab87dfe4ca3eb9c74c49933409579b1c50a37ac2fcab49dea1f207b5697ea1548131aae4b264ad6d92f8c0055bfb83a77aa384e49a394d7a04e0ac86783c9ea92f8163198179c630ad84bc4684b49cf9ed65c1dd6350cafe2cfc7577419f09028a8240fc90ec82bf5168c27", "0", "0", .Okay}, + {.Is_Square, "29f2dd00ad447f8ea38c262a495ea99a95937f485dc6b8b64ecbbdc8ca02a7356a4cb507560bfbf8e5e37b6e58ae2fa6258167ae52c1b367542f4e9b237421ce6f9006e4142d497667e6b424be7a3d195353ddff6b5809f0f1a78820d452e58974dd969ad837c209fb872a054e43d9205cadad858781af6d6158c712c8516d7489f1be779a3ec6ef71b4a654d627b29de819f3c81ca5da0f3944982aa05f6d1c960e72e22b7db15094945ab6c75bff829b3534782c011bdfb855ead4c7ea098a9e48313469ac097204e6719fb7973d3c1a1e71f3a1d2fe04d906024b85803a997a429b6188361081215c98fb09b6ea8fa616c2cf2ff0b57f22f2fef8e6a195ceec51802e24f772400e4e3b04d5e4c0090d9433313a3535a8c9ae036f341922496bfc7119f8683d178956be13b70b02328902cadfa290d2919898ef3bde636d93b4cdca832b8ee6fae4340b325655dee4469db55a0ad1ce3a4af895a77cda9f1779714875642361d33f81e9da904114db242bf9f3b2fa21619f0e02aff70f0cee8d4973ba1e9426cd7a7519c9cc57c2c97e80e947c4a0066c81358fdcdb006742e4d54ed4475895d23436aeed48c127da356cca06746061829d24f9e52d8d1639c59fa9668cab20d26460c96d184905a6d3221b5e9073cb11322832b61d69ac57531597b0bd936f63f40df2e916ff3b50eedb6ea3e9792b78b3f72196bf12977ff43645b452f5d65f0353622be1ee461165233950940f8c452ace7e72979e8853b5672457d013acfebd9ab204fc07483735d5ddb1a909c4b9ee33bc9d152bc53748315e117896e783351bcbb0665867b7a4037f55ee9a009e2662e1232b39f26b35813adeb3fa284e5d68951001880fbb127ed764f40664783c3eabbc67115fe17844fb3ef8392e926ce98a291983a30940e0ff182dcc7a4288652dd869d82ec7f4672a9b6f1f21744e1fc221e97f25c4c71b188581a27d6c707e5afdb264debd0face6e61add4ac11671acddc758ef2ca13f13b2b5fafaf5380bac1efd89ce200fafbd231732525b95ed7a21232ebe8dd97a58e0b36c7cb7da35381b63e2884561bf335ed8f968c892b8a660ffc614b1edd01b8e77e075ee81f3e3b37d148c1a73e82aab050b165e986daf7fd0ecafaabf13346aa94fbafbfe84318ae182faf92cea20735d6110c69fab80265821c35311d12118008289b8838d3b5897299316baea7dc8ffcae0586a0af627ffe7e27f2827a63e37be142d72870834305a98ec810c2ce62b7f18c41bec3ac9d42bbfe05a2bf460ab42eb42773c0e34cff7b161f8a482f3b1071f79e6b47e7b71e930b1e8e5ede2f37dbdfb1dceabb47023b6aea04a95404ace90f23477efac0a3ad10355a9cd86949621dba572372906034713055781046b79cf7cac0232f1abdaaaf2b5c5ef1ea9da563d402f8e97d14c18b7613e9852bdbb0add6f9ccfa580985c56b6095bf5cfb592d1e4bad172ef7b1fd08ec759db1488a1e35dc34b534aedb699b505c78c10a6bb5d70b6427700897fed223299e37461f049761c24c5fd8a75d68a9479ee651181fef9bdac8f80af943df571e55dd99389a3335909880c6c8dafb5becf081070d696d65fc9f4546d0e14cad0878a9e78e2ec322baf7c0eaf2b25862de260f91927f096208cb32818d61aecc88810942079f1cd6a7fd637c74844467e8c4363c328caea84158b3c6f3cc13cb685ea56eac016f8ab531075ac1922ec7344e9f0ee358d665d5272b9078f94d7337ac14d244465bf6d501d74bda1aa690032e241e91ce59f17d36249994175257136028dcac0551672b8501753f25290a014819fdb5f92e75b63fa068d410c8014be8089b94fbbb6569acfb5b8889a348c52670a0757c21c38ec34e12eb13546a1337ad92428e81161f319171c64e28163541f63390869630860163da074866331c9562f790b71ce75a9225bd0979d63b56a465c4444f10f5a868336204b01b3339451822e7c4b05a0ba53ba84bd32b36cfe764739b6b40c2b6479525eb7bd9e53da76874aedb4aadec811da0ba10a395bc0bf1d4ae06734c074685330a09a892cc11465150c0ed7763dfcd11aa16c161a7b5b6375520e3026519c", "0", "0", .Okay}, + {.Is_Square, "10513754ef160ce827ed9de35934c6b95774d9ff13bc75a8885c52c6c6f4c3c9893a4a540b32ce7c6a50b1848779187b7e0e68898c17c2268d741f9b96339b5e333ab72b6bc68b0b973712bc082d4c4fb8474e2ca02993b53086d31ca086b6a625f0aebe74b39993cd90da17482bfccd486e9dfb69096af38062d8fa5e8527fbc2c4f7abf9c6baa9f699439bc034be775224775b4113e21257a8b0b3cf90874cad7379379b2aa3e761f123c7aeaad2142c22588286a5e4c8dd29608f09611455c7739fd35580f1b673a6b4884d0a7760ca68ac5ccceeb38efb6972b24d58b2cfc262066faed415f9f4ae8ff176415855beccf81ca3a04abfc0aa8090781f3076ef491dba1094910621dcd12998bebbb4e356ed2ab4ecc9542328d35218c935650b402711fb30e1bdabf0a699a5c7061b6b581d638957ac69fcb73aba9fb158a6bc148e5bb1b554987dce42268af0fc60bad2ee8c3c209c05062e73c275929895aac514e6966ae106b5720ea4138008bf1a3eba1aea19c63d97318a2e59e7ef4d681f1d8816668b57674c88198ba3e9d9e6c2dfe34404c11ad31ed6534027b791796620ab99deff4652017fbd20d14ce413a58ffc01e2d322aa6216a2691761d6e82116001e40db39b4cc0064225250fecea76fc33c10538dd1cc5ea40af3eee43b207a64b5444964ff3a24f7b1896a21535c8adb67903c1d80dc9a24cf811b5a2ddbf2fe8535fc918ce9aa962caaaa9e2c241e11646b47f8391a37a742e4991924016aa5e3bb66c8bb1fad5e67593e1b3e161e14512c727853e79ea4079490e0a61393767f707312690bc1ee38c4fb2b53f7a8cff09a41c820a6e84ebefeeb709209102b2ae0ce48942a6dcb4e28bf25a1f1b12002eade18fd6d4f914bd057224ec754249a1ab571214029fb849c858d04d004b99fefe90299f7ba7e9ef04b447395d2f1d33f5b4dcb2437949c2fb1311c2f94ca1f15f478cbbc572fa4490acdc3e21093341d5a76d84841910df57b2ce8bb61faa845cce367fad6bafe4dd196b4aded916402897555a4bccfb61a2e669f029e4f9e5b22e717235225385e02fcac6e73650cea861ca0d966001aed75c878c87c4950533b5fd26c2a3a827fbde7e1daf9d427d3c2419e8fccfae53f26a683b314b9ebba8129f885e21bedf16590b3b8a53891dfab6b4d9eef9695bca3e1a3f3cfcf2b9077885c6f26ad3c062b0729d3643a2d4824ebdc04ce4ef9a810c1319c34ae3e59f5e127765fd086dbc7165fcd754159e5339232b217ac811dbab5899faa1f80b4465c35a3e545f25ef5a6cc39c4210fa098afa930115111700c3e770bd87aa566d2ec6ac9aeb48e3f38821f0cdb191ff1a70b2e6c023541e06cbb6a28dc6a9a4ec43ffea48deffe1ecab098227c6c65ff87ed6a7dfe58dc133b613b9cd35624e03b0fb58252dfdc972dc2bad56b3a7af8b8d613908f7634a91f2d13df55655bf2b37f8e233e4cf7d5552404cb96c7450bd6e4f18bb818e67c98a48c73d78fe84d44d5438b5d1f23033487da6bc62c10bbdec7d06f514c770eb4cd89e96eb6bec9476d799b7a6c1f7ecbf77283adc8b4a607f00b9eb5906b8bd56848ea27e023899208c204044466cd36ba4ba23be214ebbf52f3fd86f15f99c4faf5cf2acebc8216739c834244e7da9432c6b0638a758545def37964eb133a22d80f0650edd206e19fc66b4b3bb405eb9917bfccf49867c9ead6cfbbcc2252eb29c5eaea40064eee018a524ff516639af64d90deda26389a64beda125e5e4cade333f5bb20777e3868fdb77d8a7ae69ea8ae9ae7053689b63f670dcf272ce5cfc6412234c5e08336032ff8e8d46d8852fba749c107ec38c45caa70bfc6651fbd286a933357938b48bb8b6965b2f196a3cdc28e1b8142e76f41cd15a88651692aa62b69f6ebca1fb5eac131e2e4f80b27df8a3a071becee68e949a4e12847062f060c689aef5ec14ac1c353ebd4c38c52745fedd9aac36dc2d9972fb2241f3523ef2937123571b3c53f776fb494d62da6c202c486b303100bebc787e32cbba1a6f3f4b325a211b8ea20e683425d3affcc9b813a75ef83e437dc03c5979a774396f4ea4c0c3c103ade3c9f3daaea", "0", "0", .Okay}, + {.Is_Square, "bc8f414f55ea121636823c6b1d4ccbca253b66160fe8cfab7dbed7301eab783a94473e16e5b6fc83cc184810b8e4b4c07bec99cc893be33512670099cf6b96bfdbc20181c147d1648e2230fb50df229fdebde4d4d06e6cca7851f981b81a3d50ca2510caf3405c010f724b0b750dfbffe8438d69d40ce013900db6a13e072e1cf56d6aaebb5da04251801d14bd224d817b95cfeb224182b0a17b90d26a2d9524fc0fe81971074355b3eea74daa15019d92ef390cade061e224cc4b96e39db61f14adf590a6d00e4ee1f472d89a99f5d387c442a41acb8678ab3dacd172be4973ea75bddd20c8c8f5084924111cdd1bb4450cfde486181ebfc2be8ddb8df7896f2bf5cde7987aa99d357414ae8c4efafc0ecf17e77c60d01fbc83bc2d723aa3f7e48fe9074499e65dc98f578361654bf8e941c242a03116fd08564d1e887939ccc5d9dd910665e2d2d7690c579567e0f4ed61f9052d5e838b648c68b0c7513d30ed09ed27c86a5dfd4c1feb7935be9d9906798b842e13d4f64543cd6a16ef43336d045ad4f2ae58bfc13e6a3ea24ec00482629ed431a2333bb0a1f9743087aebe051f1d1854bd15ba67359dd2d4b606e09b412eba4198c9ce2bfcbedb5e5d36ebd3306acd57aacbdc76cf5cefaa3072aa92ade05351a96249d84f89269214368314e85c69d54312a341cea3fcc79e3c5559507b620bccca1c46f2ce4c968749c4e182e86644feb3353dcd2ca97fc5953a1dd9e5fa4aee74428d61bcbbbfc14acc6c0c863dd934e4d92725763ba330a30596d8ca1527ae33aaf2265f9d639c0e704d6b398b5e95dbb6ca5f5b2fa20d747ef3d6b814b134014204b88659ae5a286d89e405a1bf3effc1452b74277e1f9f8e94fff082ce875937592ff8129ec6fd9f715294a4e308af94f3630577dcb8fa4369f4017ae50a303088c7c2e5e8bee9520e002e921824d7059e174f66da75acef3a18c827e5fe40e684f85c04a69fd490515ca04a9e14d9610f064f3e710461bca7447f7aadc04bc8afff3e6838a2c3549d1fa8299ddde7bbd4a4fffae2a48eea7365e35248717c1f0f52cf55a31df46f516bde99c70ce29266a3127e5f43cf96237da37de6c5e104014af018408cfe32f01716072f59f58b6412dbf467bb832484ef79665235a360a5488aa440fc637c22f220a2991d5e021f6e3bf2d0401488c84a72e83cc4321840077f96a327f823cd3f58da007a10cd233ac2082ec62ca6e968ebe26db4c953c82b1d2438ef8b5ae920f8bba02a03bc8c59a554b8a5d5ad950936807675489d60a40c97c7ef88eb59f1d1163fb6d96a9e73cda291dd8db45f16010906b2e3ecd80845eec9aa74bd912c9e5b38430808f832b857aa325c2898b66b2eb3060ae726226392cf60039277dd64a2d01df3605d8839c19a70ea668ecedd37222f84ddcebead0e9e5bc49ccb07898af2496de2e8504e8c6e81eee991684428215ac276e73178a3d1e130df28aac365ab8f27be76407afd7fb1be675aed80506423739b85301ea42d47fc13c55bb34b741a315d7661fe081269698f7f783e1a81bdec2c7bf80e4b8ee2548c6bb9cd186b30dc84d03c762556c4be9c7f8dc93264bcaffa8c807877fb5c7b1bfa00bf3fbde1e0b456424e3db40389c18f28934d552f4c71ae02cca764dbc0d8349e63e7dbb4e85d3633c04405067681c3b9e36a0939068d7f6ea5a8c0a81b2aa4ce67cca1be48928a7f76d8bbaae11850e8780b5b3f615f6f9baaf943815076d18158caf673205b6c99b28883952185748a88430c4a4da852839f15f92500399c2e1aefc56bc2cde684e05b455aab5e6aa381e289e5f30cf6cc6cbc112dee55723dbfa2c61a8d3c3357c84a8f0e1e92626de7108fcf1ef0b84363ffd18b4b6a14f905a3120efd39a9d12fa63c6d70cf92de97684eb3303d7096843ffca1676354451301825112e40cfe606df3842010186ba427d51b1bc78844f58a67b6b7cc553cfe29e8e9e8085a7177a7a69676be9eee528c1ed19003629ee63430d3ecdfc0dcb302ef391a6392b8fedeac58f289ef039b3e38701fd24cb9cae993f5340ad2693bf9364380a67683193353b6b14d3bdadd722c7278647eca8174", "0", "0", .Okay}, + {.Is_Square, "77d880ee9018bbedc73e8e51016c1f29aa10dbef2228c6f2e5626f547074639705adaf44a111d423104947d4b7788eade32a899b01abcc5a9be57db11cca02857feed737f378ea9a259e464cbe1c5ae0fab488016f95133d4caf21851bd9e3a9fd544e4287438ed22497a8bb5dcd118bbf745205a3fd01249903328b030e38b6ef78b34d87a948094a2fa1a689c77b838793340cd88c1b70a7aff33ff34f73c91e7478978fa8bf1f4ba6482ffc4ab0b9ed8edc5dc90124e84b644dcb568f27e599e04f637cd107815bc99485d83dc5c91c582bf408f3d4b93cdb17d941e7ca73f3440ce5c0d535c1413e1d3d955f24fbdf3d6df86ea07a35b7ba9d47402e09b69d8d54e9fe04758aae1fa3ec6e31c608f45fcdec97f7293a6409fcbaea452eeffda5a486d2d1bf9df01cccf4ccef60a8530dfda75e96ea2c57bc0cd3ee23dd3575ef45afb5e62e8a5d77fff6ae0ecf735980896702384bec6bea53fd5b61399d9151692f1a15dbd02f9bd09bf6ecfb409232bded0049d90755f3c21401d5487e0d5ce1b954e002158e9ba3393fd6b2075f940ab7edffe6dcd35f3db6887b695b332a4999470dacbb6470b5904b60d765433a570ec885cc252add9a002a4f948a83b6681ad7fd0a96150f6d40e139802aa22425fefadb4be8bf2b5ae7f909cf1c4ef0cf4fe6bc1f3afb7944462987cef8ee4387f6f1009705f9a8856229ffa0f0a73ed41929c74f72077661a15a382a6e81ef3bd273e1ec0f284ff5f21207bec4a5ac5be7e65c01b95301fb3ccaf60e7231833c92460b9962ef9f2501a814136ed80d5a8c82c96e464aafc4480b3e66f808cf44babdf4b0e0ab37ccac1192fa2dfb5f677ab9b41d00d905214492c1cdc637e249305e503db46c0d1fd009400c8d6bf92e74c3900c2f8d1e11e94966b7785fb9be24219d8bc4bfa517f29b68cbb8e002b867b12a547687fb4ebaddc203a1ad5f464f5cb63586e5d23071b31ce04db79de1e1651f1350f3badb806645a0da1b1627707a159fb3e2986ba4a7648e74f25367f6af9e483e6537441eacec61edd29581937577a4dbfb2d73e4fd6cd1fca396f34403b0d82c66383fcbee120eb1f976546d8718756eb4db055b66584bfcc6809d78fa6d0c3f01063082b4224e400ebbb59ed3b56f787104a15a96146ad925427feddefab5ba545d61aee4818e14cac93a9ba90a570d1d2972b2468dac2418266125182541717fee812223bcb4bc9924bc2045770b44c7c05358048f54ffe4be0a3abc992db87f1e1409ddbd2de50c3a484113a03dabc3472c9442ab26def690ba0044b38710eef5bc2a740a8ac2eb35d4bf27f64076a6429f0195be8f00b9c59d07dbb67a1d753ff5e1ae01708ad8ac23f522d73be0e9e7e5f85b620aaa9ca0fc02e1c5c52555fe988939ab082f27fc842ac828b9f5b5c32b7940b2615edf2fa176035834517b666d30ffd714d2ddaf10d5e051c63905dada812764f46e2b8ad975e43f861b45022b758a6bac595fe9210d54898b1ac9af1c6a762b68bbfbfe62e84ed3b86a870fc13ea53fd246e6b321c3626246c0e014e3b5aca5877948f2efb006fee124322112c7666c2f70ff60381d42b5ae152d582fa735c60d9f90ce1ebabe5dd46a90a6aca003f07704089ac4f12816117ceb833ccd3ac3664398d2991d2344ea185f0a5468a75e6fb4cce310c7fd74bd37588af7c261e1d6425e42a9116e95a6279d21ffece380de27790f0c64f52dd7e5c44c4a3958a2d622dd3b72f8340c456eaf95f8a9f132c7c3bece6253f3325ea48a5dd102c36a5bcbdde217919e43a0b478422fe49875a594b8e8d6d76cb7392ff81c90b7bd5bf6d9531f4016ee1de70f44103a28f0fd420f27bd761f754b67c0a5a7bb4b73637d3384b041bffff2665586f03f9933c2c81c0a688267e888f8724e148ed2d2191696ceb8b735b6342947d8767f90b5f446b159115bc4f06892f6849586a2c10b3bbe0b465de9bde037ab19af8cc0d0468b5903f8bcb86354bf1744ef66fcf6f4227fa11fd8b8a70e94e095f8221d1b86465de0ecd20fd1de092b792cc557f52bc29cc853b17a122af2865abb93c17b5ba9e7182d62adc14136026cb383e0", "0", "0", .Okay}, + {.Div, "-41ac471edfa03c8aefcff0aeb2e567d01eae431433127cb410d82e29c9429b5a63a87bb062fa23803e755f3fab331cee08162fa78a191c0b66c14bf15ecc4ff7572fc56998b89ab5164d9125ef62ed4e24ced5e2eac6807dd2581e09e1b41fbb02bb7353bdce52b0ae5e686418b67291d7e31f37802b9402f2b41931b6cd797abb54ef7bdf3f2bc383de499962102dbd76633b6cc99dd47f161a63f38d87679076d027276f0817b6d9187d5ee76a973e22b69211a58319779ce847b56c97e43613c1b862ed8228304d04c76318a9fe3713ebd07594da11b8fee1de6b92bde2a987a6bdf089ce577914dc2ac15055a856d2913076dc9900114aa63fbebe0e57b1bc6c156c075bc12ca8055cc6c9ab3144f74d984a732d97a73633ef5c01ebf6cbdee3a9eab1d3d6389b0c39e4ac13b061273f1606927c5db080fe48e86352e0f99d9b4b2caf60262e6c5490356f24a64451fa07f7018e7b56b4a63cfa4ff8da10ac4769a9059b29d127b81cd56dfa54335eaafe1d64ae2b262cb658f2b02037d9d489bd0a37fabfcb1af3d766641b046301578bf2c983c6ed2fb1c6f16cbae8b0391a2e5a2151b0530afa9407752eaa216f61df6d432e8c91518689a099f96e1345704256676aca34b033facf0e610d442408836bb706f16f076555fae2946f7de183b23ebec44f7360b50196f5f2957699768078489e4926d9fbc8d5a9d9e065d1ee5e197ccfe75f496024fac3bfe581a5c3053775ac6724b84775958d20272fa4ceafec7ef44e6f7f4ef6dac2034b72e5af1b2a3bf39f742e45788c86b285b64f353b2f5f30a0802c503da97525bd2e25e84e8d30487e78e519386ff5bb9036a45331570eef6a7e63dd942bfff418b45ac09bcf14bee94842e047cb8b9cc53894acf8c86932cc0d274c9bdb7b80434be5274ea8a5997e390c1064cf30e936c2604b989a5b39734768728aa5adb4414f8ac66b23dccb598a1e3f042465bf5ea5af72388e006786a7cfea8c0070a51243f9762c0264f4a1f419ffbdac3a862292445a51bab0a2b9fbf609065a440b5d98fa000d96782430ad9edbac7f32c71a5a02213f9ed5a49e481657c152a79e2b2e8070ee9ebcea89ee48ebc662956be0b5aa50a05ff545fb9029bf48be570d7e4155b247fd065a01c0ba0d6eb778531b761c62ad73f263f5b94eb3833a2d8384f219e2de2a25dbcdefbccb0c3c2f06d9ec4d437a0f1d89223b6d576e9e99dcd6db6f43c49019a60be67e219c7a7ef8a293f5c93e9cd0ede7d4a167d744f3db793a1b15fdfbfb1a5e31885a874d32752f09cce350e2341cea6ec2333ac2f1253b2a19e8fb5a0d2f9d2358a794f637b10954a4a43cb2e455684b61f67002fac2dd096ba08a783462d66dc27cd653ea3931feffc8d6cc86a51d638bf1b26a3bb57e817c61bc59d17702889dacbee938deb93c7fa11e174b130c74a0c17d2191bff2a0fb52e85726eac110f153b78ab9a2de60a09b49d52c569e3ca390b76422c20bd4eacd2bc3b329c76c802c1fa2506ac95a2d134df8277518aee050b8181f5613fe27cef83e76217dc7e8535e15c98cfd1d69d1378c60ac7504a4e7328677286a4e696d30515dc486c69bc65fe027006fb1195844fbb973df9cf77a30f941cd4a8171b4c6856f007071e450829c1f904b332e7f0b4a1832cde8814fbf216c4701c2a61d0eb6181346f8f287c23eb19a67625c1b0b1f7b65e78f854aa227b3e5edb44953a18a1a5843f259b8223ce59a99f77276a450ef72668fd8cb3e4d5c9968e24dbf0f516cf36a934506ad1718cab4f394009f7a44ce37c47f5d3f6d7589004241e2e4c0a70e1fb57d9b678554110f0c40212245e9014c6217b964732320d02a876cfa401d6c894b16a4aa1f70e0d729d3b9e7174174aefdb4e05a3feee7c29b73382a9f4d4ef3c1f8cd4b9e13f956800d47a7e5d80d298e97aa8ff57cd11f015b9b3b5a30196fbb4fc1d5c4586707e4f776284699809a2b85131631111703ad7370e3dcec2f7a38baec3b9559af9461cb46cbeec36c476ba059c67d982bcc6bbbbd069c8b2767702172bc2d54e21d7c7ab32c69139899ee5afb49ec5d607c2c2f5d19ed1988d3adceb0538d", "-3d595f2713a035f52203948eb747cb8de2817b4c9ee37c6ecb5b834ebc98b22c93ade181ae8ed763d02d280dab60ceec778fb7c9345bac287767770bf1f23407ccda113c4a85d5d2681cd463c50a4c8577b53a7fecb02b181af6b394aa7e5e323d429af145f976c6a86165d43b6e205a502e616012a52ba6a52d7aaf98537245a9ff313f3bf48083e2fca294e628802ccf620d5ba30fd621acb67bc23eb4c96cdfb9e2500a24a75146fb60333eb2252db2f9d3106846e8eaf611492a9989a409a44da00d9022e6e71ad14d4426af1c5db5d86cc0481df9f44d85e74f385c76045534b2917a19b788cefc8867bc0e6326cb913b23f85e8027550fa754261c80682060d9f91d822bde82387db2e29ccd7095ef90962fff6342eb59c5db43228d93cfdfd6b97cbbf5b54792e805ad9a78781e5d830d0e2150689fd73c14e5ba7b991d979bce343a2b86f6e9a129df1718de10977ad6c9639e1dcce2b60346fa8f81c260e3b0b8d79f39983f5a97a7a00a55aec1f53567ac669a07bf9ba100e1b0aa60213087efd544896fd89916b797bdc4f95e0f09fa35682830c1eff676316174e752b62e6852c5a25d69d227b81bdd3bceb700f2acbb410272e011f59165ad95bcf977ffd10424d1e3253e0ea48592929e2c19d318454b803176bfeb938b8f271bcc520e62a4eaeb1573444c97c24f655b17b861c25fb7a4a60d13269b59518a8906fbf97ff4be372934c87e6f4790721a479def5dbaf805b13f59ac539a26a8d00e763eb38b24b2d496f165f552bb09e9497e73161c5d21d9cb73e1d80918153127e7ba9749d74f99ae7f85cbe578ac3182a6770ad0c88e3a88f3d8902e721d050df075410711cf0848f94970356ba06aaa45c383c340946c8306c1aa217880e0fbcbe143c3bc23550d57ab45e9d7239803b0bc907eb6587d0b1c26b24cd53c3b395922e2f01a14ca7bfa0451cfa0f582368f3be1e97377fbd797c102947b70f1e8e72043d0f5429fad7dda3f56b9a83932e937c7d9d62b66bbb52b049e975332fad649686a633de6073ed77584ec0cc0ea613397bf228f829fa962c1dac2c57965f0e825ccc7643b3c38042a7c6e6a3b4255802492eba3bd147a08dcf1ccceb4c6689b35b18f8c5bae6163872e2d503a7d23abdb0cbca69a7ad76deda48c591d2d3b7a6fe354054faf1856e8a19fbbd67c7f6bc9d8e8edc86308f37c042d9d9a82b997f6cf1096fdf396a1cb507bf3509c8f19e6bd23725c5d312be2bbd72bb8126820", "1120af12234c5dc2e2d5b0162ddfb2a8cf54897f607cca439e24419aaeea6d52425d0f8dc5e3058894a4dc26e44b8b1966f4b1307c9f94d8caebf5c84bcf269496fcd071eb3cc798d17a2427fba8fc99ea87395b6a26876a1a5c08dd494fed66d2a1ce47101850adc6d6c95765098572f5e38919d9623dbd82a8d61e071950bd526c34f3529efcbdeb643c61b430ebd4cb4f96fc6a1a926bacf92d2efdfa7e8a7c09fbbd986ea0b185f6ccf3add4f442788c42944410b0a72e47075c937bd8087009542c85acdb35f7b04547c3cdc9188ca6598e1a114017e3ba02257f224a822e1628380a76e2054fbf44a2633550a6999b9b3bfc4a92500d133357cc9ebbd08d634935c2d1906628c0ebd7ae51e371b514d57a39d48614f2d646019b8f98212e8b0e528863d6f6d32d0aca9b45add9a9393c16297af6cf9af851f18c01018c1aaba2450113a59597fdce85343d91f36cef7ed7ea1912d152cdbf540a055d2356c4e5bae1b6e3c1a3191fed09233836dbbd413dfdbcaacf4ce354ef882d05213084dd0caab7dd6a718e0df8fde0237661af3e7b227686e239cf54195da484147ddb2670ac52dd90ca537ef5f43a2354e477e74949ab37088142d972d27f47a179f83e8e37cbaec41a2ff0c379e79af13c8aa4f82f6a885e519e1153b58e6e8180edb586b2ee3cf1e5ac4bcb8d8f74438a463224b58df67e095f035149a3c06dc3f169cbcd2a79a4854028265899edcc8027cdeab816ce19faa0b5dcf4a449aa70170c7245f68bebdd16ef88b41b92567e1101a3ce6d00b97348c07277c31dc276bd54ad7ca211fd26540650bfe03f10626e398c8cce9e1fa", .Okay}, + {.Div, "-d4dd79f906a73fa6687322587d535eb369670fcc83d544bfd2fc5f42e02ca7e31612ab4be3a6c96892e4503e1545deca21d2beb0ca1056b6659d2e2c68d0c49cce61825b8a1ed3c9c176ecf28474706c8725e37460c5e5dd30a13eb413b32233725831f2a6571935879749e74bd2a1eb378c4114a979ade684f80b70d31aa586452d05f71246f121e38da0537bb27f8e82e4dd16f87ae9548915bb40b37080aa53ecf229ed8e6379764e0153aa3bc5dbb49a071b924903383de0b634a3473a948cae54a3052c5100ce82faac7967e2c1e8e6e5700ea49011f8d79672e0d08bce4d79c2bcc5faf11d4d779b18f0b194226774f253c0994923bcc1128f715150edb0c17ea07ad0b34afdae45f78551bad1d9c575f6995542763896be1a6f563373682169840539f9045bf4d42f9c563c0cca02328e8e4860e7bdd4ef74c066de24a2194552d9d0ebac0f9275b74d3313d57dab2d4a0366e1a4db3f7de02e9b0a954cb843ec360be71b443a1aa8b445ffa25956afd9e0ae3a98d194539d3a2d8ab8d41aaeff6c9ccc93b26e3a3136d834c0403823cd8dfdb34714a0cc0506c6f9776ad1a143c890cc7c02da77667d3cb96dc2f05e13cbee98ae84e046a0e1c6833ad611af70d55a396f8e91e3e1cbdcb4c8b0bcb188bfa5843fc27fe5a74b34b48f0d1903ebbafcea1529f2e66162caae7dce0acefefe6cc0668d191e96c742be635e31e16d53154042fba8431036afe26010dbaaf176db0d0c5567f5f586cc4da5184ab7c9206e1e4ef21a29e6da9d852d6a407ce6bea17398453e33642df09461b62d07b137324d937b9938a0dba5e89cd1b553c9b32fc4b7dd9765856bad5ae62407a3e7ab88d9966470e90bcbc8cd71ff5a6c3a476ade33195f57d851ddbd5701486e8ae27f3a45bc54261997af12e488ead29a7944064064847fe4eef36bbc8de7ed63ad50776bf51df95a25e0f97f3c5ca2940d772781a1829ae0128f9a177f0ecb9a1fe806aef3a59da3e214fb5d5ed7d9eb10d6b4e359ac563bc647ae1a868b965a42a6c668f33636c133220db868caac09644fbb4ce2f023a091480e6598b24bcc8f23052ac7e8dda699706ee401ebc66b49a6fbb6d03a2b7c6ca86352a3f4600c80c7c1368b8206526f442dc3f70937083c1cc8e440811794cba3122dcf541b7dc800e5408b5f7ba62ca187df43189cec8a8fdcb844c5dff269e791c597879c4db94e79721dcb93c502a2c69c92f5a2117b51ece80bec58b1c86f3833b22efd0f8aa463d0151a5ffab7ee17c56307782c1b970495869402ec3d7fe1452b5e90a897628a56bf44c920f5ab948ae72df0c35bb57b6f0aea09aea6b04e1f017990c0a80a50413371517639e739209371bec2a6e84ed391365b243eb050addcf568a37b73adb0f5098a1f5187b5724237599ab6195a8975b844ac91967f746a5d32279dae27d809ae45f67202459ffe2ea19e171188235b444775c5f262c0664362d761f1199587a041b8d21b967d39bd3d2c63a5e8edce5e5cf5d3c69b46a4f5d41ab0cb42a28d0be5d2424d9c9fa47561e843c89ccd11bbd59cda6fda58a930c5d7bed461af797e00f522710f987f5c3df5521dfbc20da001d1bd5f232704847fb8ae2997f963fb93e940fc8f4ec44d2347a877983bd8e25e3ddbcdabea608c9f02b81429bfec43a4b8798e96419e3f1e548d2335ee0fa10d5030c6498963260f9527d6a9bb369f00b78d85e01ce8cb0336f00ea6556f7612bb7541967b67acfb2fb3c931a5358049cb169dc8231f859bf2d45b6011be51ad4b23f4997f09c04f0f32bc0f9e9b35ac6e9da668675e24cbd128b66f4d9bd469ec862d76dc1cd48a39a3857dd347057b5013f4d49db30a57fb0b5f96f91ab05dd08979978d58d307fb27ce338ba7a11e50125b826c704568bd05265a7b64b0586688029514e146885be1d7ec7d7ef4f6e036e4cd2a0bd5524bc11d666be6595cd23c7ece06867c76b3f0f553560af432fdeabf692d1b12e25fac99cba8cfe96286750b37e64f938c82f9f78a0b4eea8294341b5e77bb944c38225beb1329c57eff8609628e9e3b9fb606973c35045a943514e72850bcb2357844e231e4f3fb00f6", "d55c7f8d695f17ea6a9cc95d062fc49830d3e6f0599501d1aed3ba5392d912af728e6be4e5faeb56f4892bd782fc1a676d3fa007cc2a70c64e84984a48c3ace03d4e8c2b3ce6986c75a9dfc1f26c3074fc6dbc5919f7526d30f7b524451ec07d25283cc4fc21833a9c6c5952b20f88207e2230dbe66738bff16bc843cd1bac6a4130a62c2037f3ccdf89369b2ed8cbf865728397aa049aef04c684793126fa932232c3fcbb3b21eb79c66b813231de3d27a63211b024ddc35ffbe4d3fc2a75c5c6fc0c41a83b621232bcb63efa1e466f9d1009be94769109612a88db24dfe752f9d3fc3456a392714bbc49edb9825de25519fd226bd93c020e30a311ceff703a77b46b9ff1b1d006e984b53d6d39866be4c08a0e3512620d64e05e25f7ba69dc60b98ccf88139ceff4c342d09d5ac608a718ec19521f5c658f741ece7b9cd9e94514d35695606217bb96459c4d2112a27431c787a93c323117500a4b9607c71de0be6b2c7e67dfdb49e859c03e399db7dea4c24dc152d2ad8d6339241af11ad634bfc7702efdc0cc13d0f3d5c532659f90d2db235cdb0fa119e46cb8f2765f4c0ac4dac980fd9c6afd31e2b315bf220c0fd1ef9cdc90a7fedc7bbe0cf50e70d5a83d665b96c7395db6ebc1499ea2cdf4465ee0ce7f43da38ffd6e5e733ba888b0827647d03ed9020d3bd3c24ee55f4434804d09361922736ca561e528fb2fd4e0ba0e38b73ed427658d0a50675829682eef76ab35d0f97da08d2a31bf88a47a8f3987a0e75f8e4103b4a2083269a127f4fbfec71a71b6ba361075c0c697b09db1035d1f68f0552933430cec89a811d5c9e6a7e2420a599cec77e62814ba993d0f2b67da06c6fbdaeeb6d95dacaaa3d5f92c9b3073abd772231ae7e3275c9fda673785c3575662d5372bf87a822efb5157855ef94d877914b56644155380a4cda1bbe7eaba67c4e547cfbf976e36f14304a1dcf390d1b69e2b8c9659612f6e4b157390b908967ae537e71a49fb632d107769a205b67dbc974ab1d5a0bb91c9dbe72338c3f763d6dd42b97ba7f1911e75bd7ab4fb338ad47525c7f298eb2a462ee15f8c8fa7c1423019b73cae4025e337b7ce52e89fc0c67ca831cbf502c0354c44f157067611de5fafc917663d768541707bd09252b852564691aec59efd0cfa211aa32343b0da9bcee12f3ea4cea4d8a777c44a6e79a5cbe25546f09fd844317d9eb9efe9e79ff16cd36bc12ded1160eca7d947370fb26e5ef75a1d67eec459e12676aff", "-ff679805e913c8b6c4dba5fc535d4647e1f006362e4ddbe86aa7bae9cfd81f0094da9f164c24aa1838f4bc496979992e2115c2afbf9c72514ca919bb4e6deffb88d99146817f2d7002a295795667e593d96a23dd2f6a3706e53dd4bd7fefe0f120566af4e1c20a2fd8a23a3d0b4540f0b6375738c784b67a07a3f607077dae64fa9d9ccb344364d0c834129cf115da33aef502ed67691f55d92716ddddc4dee6de976f54ef0ecce7db066f275032aa0db838f10a0dd8dfcacafba1302af852633d9b06c177accd5a852f79f36e0deb1e3927c8a69d6ba625ce689f9fc5bdd0f170de9d4d842b3bf293fd57ee61a736107fbb84fd5c515303d87ae48c0372ee31d49a9ea458674aff785297b486ac369145a4dc8b7f6b1ef9d0b66887799f7c32d30561a5adb6144f132cb1b180b7e2e0a2adaaaf2715ebc83c58b24bab921166d2af19fd9203261f2d4d51168a7af4aae583a38423898245306fb07c15fec2df2eafd3cc544d16b786f3a3cbc7b25b67b1c286e4ceca04b46ffc9e54f98cb184542f7cb65da987dae3576810786f379e4778693442a7cb01afe1a2a2ec2167f844724d4809ad77a212b8f3291c8d7d3575ba4e4f5a311488880e9dcd83871c46b310975b3398f266c5af6a3033cd600a0756f0c3dfc4b996e9aba8a7e501ba7e850048c58ff3596bed3ff3ce140449bf073a0ce4fb36c7ce7b19257f06b8592ca6e3c88d7645e463394357ff00f0ad021b3a5e40a54ebfec500fbee66e91f46bbef3d9a004e12641441960d2f794f0df7bedac87e22d42222a97275530f201772f2f39356c6f4142c8d4639b2f6884f5b7ac7a685de37f3b", .Okay}, + {.Div, "c5c0262b8f002df809f45e03ceaf7319be3a7031b0ea8228dc25f0e83f7d963a4e383d58931b85ee93253fe16c4c33c5fd637868143fd1c3658ec03735c0388ebbfbac687bb3cbee401c240a93ddcc29f3a523080d6eaeff7fd5d216cedebe794627a22ea63afd20e68d1be76ac7d2e9c4c330f4671b2b8da81358588c163b6654d18168fec5dd5e503fa103b3b771a9efbd0eae1087ac9c25a88f5565e5daaafe87e4fb9b1cb2ff0a188360f8f0e8b0651f56661f0fff3befad4cadf6299c0d8061fac4119ddd93446e45fa5bfe0c57266b3e2fc063a4cdadd777d2402f1172a6b7c30dddc5389a8d0d97d35ba6b9c1062867b9e5090fb4829e607b074bb6ca0a382ccbf271d04f3803bd101c640f146bbf5ae2e3274c38f2da3a8b59a76b9cfb22e3adf56f58e9b8fc2bebca80e064259fdfcd0fbe4ea41a7b439f11ec50a0538e0a8905a11f9cd6c2113e3267f7c6d3b22f56e48f41900300098ca791a14c557c47c039a4b91af37d7d30a98134910b1752f95d76b71e38aec1b814bcc62aaba8e13b4bc1afc6ada806e4589253b9d8e5a8a978d36cd236b4a0054181cfb62e9af9fb5f4faf168d165746e8b70dbc386bb4ebe9761c4936e28c7d071b2c1ead16bbb15ae8babf0b5f42dbd2ed49681e9c74c6874cfc3e6d2fee9cddea1bbaceff59ec763c238a12c9c27239a62504a56a932b3e6029107a5216b7e411bcae5f9ca68ae75211f2125b7d69f821462122c4e25d1f2f8694c22a75158d8d896141cf23aee3486cbd8c40924ce9e7a79a4ee807d145d63b79d9f5e994c44d8688f3501323b0c48354f2d6b02fdff671b679c7379eaa88f675db3d54be3dcec57aa8b865a8d57976552c0fe051746efd3c8a5cc6be959e6f7a45fa99308f7482a3243d88d223fc718016f27d96a341da141a5601893863aafc94dad91d09843c51977bf4ca4eab9ec6cece12bca78871c6b7885b96eb7bcd00b09dbd945a223dc6e733953d05567ce75d23015f1a419819e2c8472b97db3c1265b10af5cae47475af83fdb2e85ec0b18b073c9c82a5a2c88c226473cdd72d65af6bf837b89edf36193a0b0dcc599311c6c76cad0ddd9705735d544363ebeb3ec747a79880ca72990db0bbb874383a33832435848266eeac3a247514ebe8f4f8ec08ca88241a2da358563bd1834f6b083b0c08b51a39f048524d2cca0446c9e3bf414cb1290e03231450c8314093abbaae5543606580014ca94acbdc84a8786742f6a7fa445469702d6f67b2c5ab1ec44297af8492c1d6a774bccb823cd1cfdd04fb2c84c630b251dbe4633c2d473a6bd8ddfe950f0ea7e0e907d1bc1bbc9619d55c34779f368e583bd6728765450615ec42bc6c564b8928d929b0e1a094765629ad152bb3583c3befa4072e14730e571d0806fe807899522265ba30e4c8edc5d867260c1f8e624b24cd5878303c447376c6749a5921f5700830aeac16fd8d1318d1f2fd4777e0a2b2a87368e8e270f7d8cd03d554853d9ecd0d948dbbd119dd5f15953080f5401cf1421e8d9b2dbe05f8113879367af639daa47a4ec208ec4bd8a5bfc3ff6e6899c6ae24c1c506fc6a136d65edc2254a27474ba23c6b38627d6df73684ec5056b6269beb263120bf442b3c9ac649bf8f8acc1e4fd6ecf18fa96c48edab3770f92eb6df3374518a4947f4ee44a0a562ecb1ce34c11c1c3a4ae87263c13b0b298bfdaddb0751cacc108f6b35bf684f25600d809ae96291e55a7e128b2e890e15a6df0bb395a17912fb512330e9ee815d5d0b80f1d0292eb0676e1cb5b9ccfe87528c0bf43492a4495ba59b7a0a3542bd48ea57d24f761f9346f3de97a648c3bc3f7057eb61915e4bdc3820e890270c778f868291d1109669af7b56be55a16b30f14ec10df6dc1b061ac4d917e554316ab8705e1f3f5547b73d96a243070e0b33df02c3ed69a9ede2f648b1db56347d47dcf56cd415182ed8388f1d766f02399bbd00a0950fc5336801b3da9364d351c12e402e05e703855b93379bb49ef02ea0b244a85aba6267426fdcccbadd5653bf987e1159cf13c79a34e78f862838323fe4c16c7469fc6ede41f1e2da475128381bd8ae504c041510b734a47a86c0", "-f30dfbf826de4c335d3296e48dad8646414d51d6cab9f3a84b54f6df328179cf98ba50d36dd23b9bfc3204f4ecc17a25075f8f5f9bf23c55cb59471834ae4a6860c6326ba063bec0ca0c61dc36e2ff2b5f8396f987b62e6e7b3d8aac87aa1815db80dcdddaedd9b4d4fbbdd888f77c1b88cafd39a1c5efa8433a728947dc5848c7cd70ee1f7c1189818af1433f9f70219e057567ca305f70a146460f3b15be7bca34be5f6d145f249f8ba217cc11312bb95a34a2c96055ad90f5d8c3bb739be2ebbb4e054e42a305c00c8d8f605b39dbf93263f538eafa4626132ef9ea1fc01e260228a3c219ddce0748279b5d030fd06f8790ca09046900888c47287f9b18dd73c1d3c036fc887af2942893f7b341f65d2b8adeb6fdf076c0dfa154dd4e8c6c0b6b1ca5fa7c95d643a045e3f885149f57533b8a4e79a709cee7c02dc57b7e35ae931ea3a3fd10fd87782d83b2c7740cc228c98f79539269cb0543335bff78ee9d706455aa7a3db5cfb121d7ac4362725211dbd08f46f714d8a9ad221c978895067964b57e52ab212f67714d22175482054a32dce266b42ea7b30771e8bc702f4fe8380e0d87c44343af70a78027541a3c7baee71abf24ba2bfe1eabadaba32e18e3a541fae70726946408dc7b592032ff6d8007d65f471f5cb38b719048f6dbd4487faefa89c3b4418074b400f95f6d5ff5f0b512e5faf439de7d7e2558fc494095021a8203686b7847c1703ba48c88fa84016526e13bdedf7c9b86d022e589186b73b41445d1dd025a709e08dc01862675baa61ab6cf4b5b6a8d5251cd858096c2e046eca2ff8a362abeb53c4202dd7de8e6452deea3dcf63a08baf6344b4de6bab370acca778ddf1b87b0030fd49141c849c28a96f20ac5974bf234124a476b039364507d2477926d4d23b6130f1fb2d7206fed16b0f1255dff582745886c64c45219b9c3a3fb285c44ae47aeb6cdbcd0220de65f46e8997dfe0aea17ba5594636a0f1ee778f98904207c37ffa2101e0ff06c9c6c3d08bda2428091b791df645e97ef3a70193fbf6d8c8bbb6159dadd4ed045de6b0a436f240a1ff25363938d505334e1780f758abd5986d95c14bff2ca65f6b3a8459e80688601667e2a2842860fa564805dce4141063abe5b6cda01a39a7dde57c7f947ab221dcf37f756532f6fa65fe9b50df7605bc4f48c0a040483c58eed7dd843cc09e35b3b9862f7359a116f778b5025e32e5001ef5145605455c2914b0588c50cefc37b56bc8380f324c305", "-d04873583fdc3cd2691b7986a39202237a50492c143fb11fce0304b2b6952f1157a5ef7f149d6ce4ae0cd557226374626aa038e26676edb431c52a34739b99c22c54c813a18b29677ebb72d777a7e57ac688e8b72ac3ab88e5b85f515c4d0767b99099160ec6f11ce82ee3b3a85b3d00cbeab7d555e37126ea908b042f958c95e1a4661f9d53094d90b132060fa54c31ce361735e067a0f52a3ffd85f24cafc17092af090d332ae308da5d6bb257b6781a7d390ae393edbfa936ca8080a7111f0c09240ff596958953a1137efcd232e098e625b6ed42ae78f500a65735670e0ad4d33e3cf7f2e01bd1a573b895c03957b51e18e28ef18db682e26c188d64c5cb3e3fbae72729f03444e3e1cfe1837fb4ac135d73ce70f04f915a0cd950a5cc6da3ce296bd1eb4aa897352fa792d28f6e8a50c9a21c25419401b5dbaad3fe90b055f710c130d6162264a15dc8eb2a4584b76067debbeb78c7bcc58d0848bf508f1296adf4c28d613648b9eb2e8be7538eecf9dc7c4d1f996637c5cd732c8661a64b3b8706d2612913ea7baa88fc97ec19782959bcd3cb02cc2a6f1709348d87485918b5e746aa42d46e952575c1410a7b7894b7ae29eda61a3e38a4e79ec310f64502533e87a38a850cd9af5f1a0d35d9f46d25ff5c192d2450f49566a91445e754742a8115dde641f326c2e9c24dd5fd7347b86bae3efc83bd27f6eae3236a0f1d36833814c687736ccad4abf909c36a2688b2742bd8993b26087a1eb1087037d7035febc899cbbf002f030bc63ea3caec8157b03b8826f4f8eb8b886cd9e7f80360cc116d9529846bbcaf2deba3db949ac024ad4b2e1d2f", .Okay}, + {.Div, "b6044dd806f645ce97fb8f1d75815179feee71021ef1663216e1d4b4c494a15d9417b7736bb44d1cd6616544ce72d14ea5bedef39cf76c23757e792019e9b500bd283fbd6fbbdf7bfef0691716d0eff9e806f97855d2c91e49be0e4d79b148d29d6c4baa413bbaaba9d57bbeb33be2fc99b7dcf34542dfa43fafff942b3405cbd8ef3d9c1600f08634437e16a2019f06ada6fd8bf8f7f48c91f6d7f25f19a3c990797cb96331ddd668e425fc469d90f6d622b86df0a61cd92cbae2a88c3e61bea02cefb5795779cc65aba028a5dac889a2bdc0ebeb7974bf6550607af44e388e9a250261cb667aba396c6c44a6c1d0f0e81d42b115dcc6a6f679a74fcd694bd8a6516c127d72c5324eb7098452e81f7d1a60053e7223c3495be94a7e970e2d8ba4fe44607b027705048bb3d0fb87e264055aa552a1e5d1a597ebf2fd17e733f0877afe575e6a190266455fbdc24b72258072c28e9bb79a4724c1b0e4ecc5430e5506d169aeb4c82c7eedd87a8da5d3b9a3be68ae0dd1e7cb37f2824daa884960be7ffade887637ca193f700eb62c8d53fe597ce9e6cf0d5a9e0c8dfffa4666a843f37f797ffadb4bdd81c635259752689c4b02b4273d64a73f06fcc8cea486b81b938c50ccd145b7cdb0b2d42d9e8f5cd70cd21680ae2b89bc972b4f17f8fe5b62f7a2c7a3d6759554dc24820d6b9c823376b812c902444c0d730f8e99d5e08377d0a67628d02a6b653ed17a40f68a5d510ade97798f078be82c237d9f462092e6de299f84364f031957508273abc25cb9786f2e8a0bff49dd2a0c8d1fffd04e6b12cd107bae2e66e19f3fe191f8a82b901e809ebe535f7fa6094f291d0ca2d5febdbdf1240c662c448c7a7cc75a8538717db9a129e2ec4f33ee1f31c1d0fc40e18802ec17a32113599690589604be635795c5c3f141ca6cba2880520b8c9d37c730d4b84f32cb5214cc20111c9f31b3cc92b93a47397596de4b1797928188f98afac7b325635c9ec60b70dc7955850e0ed0c5bf5e4138383de76092dff8575c1e2a210273feb4907d1ca668ac01a477fca9900f33bcf7efb420aec605628a05801e46594c04c89b733e40543646703ab9cdfe82746485eae18ead250dbdf5eb848e32f64770b1c029ae295b6d4431979427b3ea5c19172be2f83bf7a31b72b4753dd8e8b70f159f6757981f5b2c1cdf8a621bf94e6e96c352a92875f573d6ea1bb06df3a92cce576b059d1127f893904a79d7e41008f90ebe431f00c3717b0e041f8fa1d96e0f213c1bc7de563be2f46dfc607de6cf70262e535bd3b2c5a74ac46f52fc479cc540ce4af1464aba247c45183b0f0c1effcecc741a5b9166d70a59732e8d520785e89dd4bb087dac2d369f747c4b04d9171f227420100791ca676bdaaf63d2b4da610bcaf37023bc6cc33fd9bbccfbe6b57b9f57ac038bafb6401d721a9476042400e5be0084d0a0fd34110784063332f58f469a966d943267ba27c8a0fbada9f1bfa47ff60edf4dc446f5ec5f5598616b24224b51be1c2fe0a7a5356a14401d9895949911df4c0609a580829aafaea6250319267c0a75ac7642a386dc1f68c0c9ddc17627f9e3c2092cd0b0dc2dacd893fe0d005d841c5fde16b122984672a689d5a9b8da5ea726830d4c0befcdbe69469d9f9a6dae5296fc634585f0ec0723e2797e636073d3283ec5830ca29b2ad6cfff5d3405da5e2c4ce23affdbd1f1b8f32031437e07f2cd2ff093499de6a7c55313d06c7e3219983c7b2210b3403a9be4779f6dd06d8414d215c03a16df7c66493c3d0ed06d94dc9966e1751d72981de4702b6a06e426d3aa6146470f8ee6950773b57f0b9f9a603c3d5da5c913432f1dd4f8c057344e52aba9d0064f8bd84750a20ff195cbe44ae2fe935557807ec18e5bbe81986d985ba44bcd28ca90d38432411fe3927f5e45e500311cc8caba8fda655a9ae6ca53ed68d5664d8d25a74fa279289a0b3e8f55747653e2b7e65c1259b6b1c0aec4965fd5064d2ece7e600e13f819ed548f6fecd0f665d62d11601519d63aaab51ab7dab32511f002a43a5945f30a1f96f1b15c8fbe4841f2e01aef759f059a0b80d8870c54caa5a63c235939b14ea8e014", "-f3a68fe22a997dac7f50edb71b74287039f43a88b29d89e58c621052adb6010c6fc53aeb6783cfee25a40682d32f85de2f668629489d60788bf943be84d5e4da93d4eb93a838fa0394718c28fe9332e9ede41702a3c3086463f27431b91dd8136058906e36f9333ac0eca9332ab27c02a4217f18d5ab7a44a1f97b640ca1678b0e2db94362a3960feed55e5fc2529c533e82fc1d5235c7bd6cfcea343d5ad8496b130969cc49b5c0c353d6a567b4be538058a25b67e55bc098c79854d73952fdd8cd01658bb7bf6b99b042ad76fd38bce883dc83a3767340bec2fa71925014545d0b839f4a56c90f12d5ebf0cef8cdff41525a1af46250b5a0ee1ec6b6a2be13685225ad97b6470b8854073525be247374c3178115bd27717abbb745e6eb18e324f758cb399bcddfa9ba165954d901d52785c4054518a0edb9f6de5438dde20d088d0cdf4e6eb84c282613437ba856186827d0dcf0bbc981ae0b2d3c51b4ab03637fbe329b8722838667a5dde68979512404366a0662c4e2fcdcbab99f6a2de8249fd050f1919f7037cafb23b9718cd409c40300ecf4ba4eb08a8f32a464b9bdd1cada879b26d91efb2e0dbedf4f9cd9d94c57fb31e493e48b5544aeb897c8d1591ae919c695294387c840552e940f28e4c62cca7152d635d01f6dc0ccfaaeada4517fb9c0d477de8993177f42274adf5dd640a41be1efaac97387657e57e2b71770d9233413502afff734a5aef6169ef6b097f61e22db6bbccd193e2a0199e6487fbd381348688564dc4d1eab80c533aa2ce8aa2def9ad1e428c7dd152fe315ef856e36bc98b0c2532a2c35f1f81b3f150450f7699304cfa0d66730c2161fc2a61a27def481cfa4fb5953bbb8e47af0e7002b64fad85c0ccc2374c029cd6bf0e2206b8f46a25e6e2eb79efade04c524b6894885d21eeea88a27d7a7485c8c1e24a0e0fd5b1caac65c814e2934d3bfcb0263ece2a749fb3574c49712bc255fce02f62b9ab73f885617b4edf16a7775b65e83b17895247e58d2b940348a50d6222e2ae6bf5a6409f938301c128e109afcae13f3a41d9b20ac6146fb604b6621ae9f72b1ca9c37e5c5484be34da6f57dd11180b5c12b9c8c2c30c419faae94ffa24f137f4de11503fd4dd893e69c1626cb73739fb40581bc84b4b960f86142b6f6204e3592920dd39cbedbb6e1c3a68e73e59c466f1da12d19cfbe98ea76944d8f4f200d4ba91520a55f12c26dee9a9a9b1949098b18c1da833663759ec5c4eff0640af9d0", "-bf3e06774a2f64694809f7b424dfd7908c242a8f67a8f56f0dcc753a8f2058cc1c23280b0d20a8feb77a173642337ddce5fdeb89dbebe3c668928879a8a9db954378c66ea0ee60b953b81e3d9ce7e39d1d456fc79279793597c28311b6ea9c2eac23bf6638e359bf648b5c9cbb3da6b4e9eceda69b61fe0123622e6eb2f7d5acf4c62610f89e23cc027e88305504e4eac850f568d7eb7d061b45900b495cd96b9b991abdc4beb80e9501923ac852e940622df1498fd3a50ba5bd20ed2bcc9c07c2d5d52805b82c3e0cf1d62c104a6eb4c125d44083caefa27e67e40ef4201fded5eaba25d67bac2342019baca3929be32842b3166930731625c99a9734245d6d37716108495ee658f22be6e2d1297c3933f1d2cdfea896d6f378ec462b64e65ec50db012791c6ed99a18c3b6cee47ce5020f51d1fb63e7854479dcdad184c7460083364e80b4fee5a110cb7e80a069fa5619e80d48db49b6623601a87bb7edb2bc013e2a6568feba52f3df1ead01291c880d98647de6e68c847df240fbfdf01de18302d8c94e40ae1f5e25857a1c5525edf5be2a1cb12c724bf9a75a9d9952cd8c6cc96ae799e6dcbbc6f46d3457ed1e4bb6b4cfba58d8b70a717e573309a4281b8a1b4ba81a575789620d62127f36cd1aa5f1c184c42d7811238a4d7b6a68efb50ade8f9d9d0eb0027e74558c3cfb6e00a0970567184ab62fb321a488abb7ecbfaa7c9cc8bd400ad58de591137b1aa269a9714ee69d396046119fc40e176c25532df0da5c53bd7cfd771af9190fb3ff28cf121086de537cb38d8e25511d7d1a1163c6e64550d04f06f0704956a3cccdeb2740017e457987", .Okay}, + {.Div, "60a12e7ad7c1d85778a9205c8c3089be9543befab23080f5e969ad52ee92a458145b1b3fc77addd8b1a47adcc9a77449fe526c4b9cc1ff24985d27e29918166b2fd2d4e1be54df04db6976db73d6562baa3c03b66c9a6ea49d79183683bd848b614b5c7277f875f60dda4d32b790b72cbc3080465242a86ea9bddc3412b10dd2c14d3855b547f50c4bfcedb1df3431d6ed88470a0e75ca6306ffcf30220077135c99c8e1c2d8de2455f55d122a1448e0eb771da7b65307087f285b468f492523cdb00e26a1b130dc016c54710b80d6420f4075c377fc4b841ca50f726ab08f1115859db774b8de99050ecf63aab96d4574a761d4df0de1637decf026aec34702e2fe99728baca4f0c77a2fe14da7fd299161d4963d8d61693dc9cee0d082351b02c17dfe8879e3b03f2db658ff1f68a7bb473df452f87ba34292845f86154989292ba4e92d49288a68e580d0eee41b5de46aab1efa0f2ceb5ff2d4a7904bc88714f0c06bafdb6f3ebfbcc803c94a3fe1062a69da181d590c638aab88a3154e18c450d330eba8376c7e67ebbe649fce6f1118d78e0b09641239a0c3c2412d633d8e10c1e1c7bd0df40027356a784bd4d553783f891d0abae67c2a664ad641af9196e61a45edd70c1b17512d1f05dce6079c98625f89c5496d71c2a6b0c2813a2f95cd14a777426160ee796239fb5af1da3d5c7ca743b3d43b288ec50644af04e6ccf03d7e7aa3b1923ea78a105f840fdc7eec128d7bb310285737bc77bdea46f8c9fee724548798895ad7d38d130d1f2ff71d897a6c0a665126ac513d503bb5e1f4d368cbd8e484b291d9f5c5e3435c62a15d841287178863586fbc38dcbc3bdeec74a0e1cac4b4a84bc73f3ef51c3b856bb7482aa04363725c7ad00d4d66ebb3ba6d79595ed5accac34d78e0a16e3e85ed757f4040365a6c8899d91e77db50f7dad1d8ea08b436ed4e36453c4eadc0e9189ece831955b7fd4e43553158eda929e7ed85a5c1157d9521f670df405ff3036c842bd18f661f2ea6dfe6fc55c8872d673244feaa00859bf059844754bc7730b4648cc55042c8fd4a01ae574beea44e3ddc2071c8413f12540e810fcfe4b9b2da7627e4a35c220e264e3132dacac5d1489534f2d1e79487b131f21f87000b54b1124d02d7480af52923e2c0e0c0b01cf59f85a83d913ff8457b2dcf29ebd8fabdc4764352346e9645dcfd6ec4188b56e160e6129eba27782283657b11588e549dcc9dadc9257e4f0f63ee1734a11fba5e275339dd339c8570d8ad8addcaf46cd1280d82bfa5d6f15e3c5083721cfd1dd19dcffd546317192c48d3512531fd9553fe8df7bf56df0288d7871aeeff3530683bf844d4713f7e2a8e348aeb639a488c65cac12e108e2928eab597bc9c18fdc789cdcedeca84ac9110d42b6a32902d3340cd416d2dde88e7caaf38edb24c1a3715d17feb6cd2ca46f416f12e62eac4e6bcd54b8210e1edf87529a516fa417377ba1d5a8505f6ed5c591f877aabb14426a6324a103db89f9f135fc0f777d6b439f8a272c7a43427bd609ad44579ab4e15d4af9049615ab07c6b754f481c77686bd2ab2b5caee370a561f76a5b7eb21a5c0ad8d182c7702059b469dd2bc2acf03aba6d06d865829f7b992cf4394ba84e6c04589c1e46fb4ffe2f249b1756e691d5894457a6af7e985ba604c2d2b60af48b16bce8da2e11f57c11ba4d356a5379ddf22c60fad860d5ac0835c62677955a0424bbe97f8b6c8e5c62b0ff4b27058d5b960e7cdb8f8a53ea8dcd09eb7ecb076b13721a55be807bf6066dec02ed011be780bf717beda17241c6a2223c8173335ca85c8ec3d0e5c0b65f10fed2464dd8af2c22beb256dc1160996c16e445b3a0fbc0cb8fc7c0680219bc753c85ad891686802383262d1546d4b5ee412aa41b42cd8ee486bea306d3ba15c13e9a654d34709413ea2fa8151be73efbe65147dc6e8288d50722014834f833b2327db4f08fe553e32d924922340f2ba4db509b99b8786efbc049ef1dd36c24acadd926ab15845f992f7cd878d66965694ed27c79f79eab2172032ec7b00c11dace85e654c88b56a90ce0007189c03732496a3dce448e0212a16c243f51942e281e", "1d6a33d87e58a4e68d6e4bda6aa8e9442523a3df5c5b2f5c817105c1aabe0be4b207c203078c569f096e73b42498527110884a8b7981a310e5147e3cd47b19555706bfd1f8342e0036d8cf9e032f94701be5a318f7dca32ddea350315c88e9fc63109e78fc9cd87e07573a1abac70c03bf177a820b18e553778dd6189d5595f756625754bdff90a912b2687596b22bcfe56f25a5ee4ed6d8ce4f320d1fc96ffa2cdb8ffdd1b73205a352ee91f79c00024a0eb6130045b63e9f5ad8506d41e67335657aef02780e8b3bede7eb27ab6ea69cdb1c294caf264bdf31bdae75f2ad4276b6c65d7a94ee65a4503b60c9b878329eeaf069bc2b25c308a1b84c0b612cf7ed35e52449523c6fe2d4188f2eb2fdec32f7c6dd029da9214a22a978b265b636ee429b71c3ffc50219d1e255e1756ff43fc3220bd9ea4f86f0c801fca5347446f594fa571ca9372a9906c1aa015ccf04d7d44dc021163c7b81cbfcfde20c90ccabb7739d672755f1ceecaf66e273baa676b4b6a9574fb55a5462d9bae64db0d292ecd4734965ab2e30dd3e41856cc35e53bcc0338233e1f7870f4a73365527f4d8f63515442e610c9a8787987663d9f7d2bc197f51dfaa4cc4624423a77922bd75a545652ca1cffd891847f69e23c2be441dc83c813821bad34332fa761198ba8ad2db1f48c28526e9aaa39865f1e5e79d2a883e8b859bdf7035bc24578dae413560af1d54f2446ff1f647cc70e6dd45f8da32f909e030dffceeb7738014900aaa863c445ae065c9000a50977231808c7a5efabf4d8fe9846b659a844c44ef6abc8421dff7778aa902d2ebb35623448aefbb607fbace3cf4d94d1c16aafd1b4fcc7bda38fa1cc2f31b85e60e626050d2ebc8f1f47694de24373e86b9484e183e0a24a91334831eb89076fb86779f96170e13562895af880cc978ef60bd5f45503f69e497e308701db475b8147961d395897dda668c11b766f303cb229f8bd851dc5db281e75f9d190b3ae841aeb365ae949b8f6d704cc44678a63c15ce9f11b03c02327b88a2c1ec7c047fed34e911b65f09b60d84e2263241ab047f3f2dd47f30d089a3db87cd63cc7f73cd9420a07e62c15b5adca90a6897ed9aaaff22ee4ab31800cfe55a564931d7e39e28fde17c21f4d77926c772b8bd132228f3f1e4e4d567a1f7c2b116a9c96b4e32bb3261022b4884f4ac61df3c44b673242a2e4ea47f48375d8a1053f77c2b0d35177f7dbb19be3e4bc33fb35471173ac971fa989395c369f9", "348f9d16b67820e0a1952304e2ffec2aa0c21a946e6469c075cbfed0d532caaac5fedd384b508889c9dfc9ecdc7a77082658aa60a6d7a2adabbe25cf8c5fccc4f849064a6ad124ed32903f25e47e0c05fbc6445bbe00be02c4256140caba96c435416b461869f61063d7b8e1fd1fbd668839ef97102e1639a1451212da9d8312ebef7ad33232198358e7e6a1bdf25910ad008fd790904c3c9ed9baa9a37ccd1e7f3f75cf90703db31efc04136eecdbdb7bb81ac8a918196b42752b8787c600065bb4027d3bac78575a6c51fae55245c6bf37cb840108f23d9a08b613a282c2104ba7ca7212bdb9bce8c5d290d3bd6d78819b532e52eb0e31a19bbcc1c8faea7e61edd7da85c42b7c143d1777197fa6cc5421ab937fcd17a821e24794e042e819f04ba38fe75779044528e0f63734d05eb7791b9a5f020d551f86035fa80fdd58c048f338b9476164e6a2e7ae07bfebcd8f91d575b45043aede7b88d35cf8fefd2ffeae4e11e9a98f1f11e17b3be8b283e8b755f2d2e095eec23321c840e7f1c636f5ae2f89817aeff3ae565cbc91f342229b5922b7293af38893016af780e88be88934d6a4b3e339551e475e68633c6375e9aa1156d09a1924e210dd485b3882e92fa70ef0336e19b516aa9204e46daf9a149a5396261332979f643a2ff0d45072a34ad6cf1eabf37cd92aebd00c3e22526cb42c668e3028b3168aa8b76f7d78088b65738d9a9f671750db413509ec6b514766eafbed67bf9349ec46fe2aedd6d674e9e12a2cb6c567331c2cd83cb469008439ce9e331fb7b65c8f34823b55346bd34db674cc3f9f1ede0222771dbdfd9a343ce14c914bfe9", .Okay}, + {.Div, "-40b6db39bc7912e4e4143a8353b87fc01f3e5a40fe9d5611273f39558ade95e24bdab915acab23b5539f5cfadfe3e747336844777c6ad5747eedbee306033132d7f18cf1a0afd512aeb923cca0c6368463684eeeaed780dfaac857578415ec025cd8e930b77a874d751d66a97edded822042fb94a9931d27a92f8eee7513a9431b0375a3bb707e4307629903adbce48ba9157e9177a43f6ba11927fc80b17137344c01a4d6b68b33ccd744e76cfe5900a416a44d1a24fa6e03222e538af4b8821ecd725a5742243773b47327586d6dbe559ce9a9ea4b44f958f6433f937d055c9f75db3a649841b2b391234dd80883d5edf941f31f088bba7f8aab09f410c3b673228b7872a5d90f41ac79d7a4c9dc7b8a2eea749d47de34a5c99f30d3ad7585fc6c40770b1360d0b91330e8a452e5fb8494968d0ce40440fa6665e27cb526b5fa63d1c29aaa7ef01be87aa9c67f66aaca0ccb09a01aa9d649e4a56b765c482b2a0622ce2b8092a5a56c636d9ea1a4ade3e2595c1e3784f66097e4b393bfa6cf02ac8999b868f1d94a8376c5cefbfe694e06da9a5c223703d6ebd36ff9c7405d012d794839facb8c9e62bf4340db1316214d458eb19bda2733d37850bcd4383c136dd7eada6b860e081563fc321e03bc5aab5a82bebfb7b5755849062c27663bdada76456952268e2982892506b6190543a8f42768f945c19feaff91753e31ee66cb70e2bdc485053bb9227023f517d00af04ad4dd0571d29bbe29d32551d6da396bd65119208ac32644b3b3ba30191872ccedde0e7cf49f1eaf98510ea16753c17072b7ddd82eabf81fdcb92b34c72001cee2217464cfa7d47dc4cec6b9aff7f7eecab57fd0b7cf6c3d43a4c89c54fdde1cdb288482fc272c5fb0d14b65e258f1597156e829093ec30c307858a6710592558a73d34f386cc6b1f0922ea30faf47f99e4d395621719437f14934af6ae3bc76d515895689397ce37be1e918376e5e2e49432d1cd16e60486230475af3a66c578a05c930971ea3a3f13b0fffbacdf1d2c97c52770ac6e2adbca6a615894e7072510e92c9faeff5ab7f1e4dc87b01cd93862fb069a4668e1023879956aa9abeb68d239b9023fac79aab76f8f7859e87a3dae452144e6249d99fd4d7acc676dcc3797a964abf3b067bb3c9ecfab57391331d7935611666b8845ddd0fd4d587079222fd210910497a255ca921a3558415ba1f7ff6071d6efa0432bb02473a36884732796f0d33561246f81c20eab7355a20e5b302ee509f8ecd6c1b1a7b7ac5d3f2f390e044a615ce4681fc035291fd745d97f7c5a2355dfbd77850ba61981d60ec2806336e586ae1db7fa39306af529167d5c793434715c208902cc6982c56cf1e394d979d7f6cfe0aa63686880358821906309b7d184318b4ef9812b927a2f763a2708fbf12f79bdb0c790b2d2d5e802728d66b8fd7ee249866ffce221ea9c5083e5a23df67d786cd317ce1957ae431ad285674b48546e671e301400d24589399ff0fe21da49c0be8264870da96742274a60c57d953c7ef3de06900bca5eec18f0fbddff4278e43b94b4e3b6169edec2cd6bc27cc860491fe214129ee99e8f3a216657a468ecbaa94ca0a14e8bf54c4c79c4062e6879e6c1d2f1985df29f36e933368483edd8c95bddf0664960b983c14923c0dcd292ae744456c4f30c3692f4eb28c631626f99f3aa3158cb5bd43dcee85d0d0914487ce6d4b1303a99dce6c2b703ccd1760c027e25a640fe2bb6849c9d2b7643cbc1a067d9f9936848ed54f8cd3d39f36eaa198d09ef4bd57272eff045124683751dbeef4331bf962cfd4c9169ff59cd55312b7cd54221b911208fa58a7171d150c40b6bb4faa73ef974b5bb859d2529090fcefd584696fa66aae2aadcde4909f05f0c3a9d55205dae103d42cd32ce9cdd8ee35024af99c3da13891fe27780fabb002cdf8974db0748e0dc82f600e639cdbcc1e33e7bb7a2bff375f0536e7ec007d139f1cb1c9697d10cf2b82e99502e6c9f8d337635e5653d2986cc4cc4247921957e688a1120cb0d7dd9776b6edaa0dc57e875223790d639757c64e7bf89f8892fcdedd99b4c7bcc956cab997c76867f8934caa7a48", "f004376605706643bc3e5f9b72224d7f9707e5dfb4ac7d4d63912924b9ea6761ea3d27e1dc28fa3bb89f3f67b7bcff3dc18214576334c890847bae9e43f83df1be74be6c779034725a8cc760a93d196ae0a3223de65857915bf6bb57f2c80f743b8750b3acc8c61cc9311ec267c831e85e589a149f1cc14461089f48044e110601d5d4e63fcfd85618f2174b42c63867ae923598f64aaa2e5a1ff2bffce065b90f83d235bdc35761a3d80f41ee4a942b622bff160dd4ba37c13a464d936f0c8c9cf2ebdfaa8d17dad898c8ef034be3cf20d325c1dba18e43f7220b711ef486b835d2ee7da9b38f76bca87f395b2891bfd6a28ac7a4570503f8a72598b17e15fdfee50552818ba80a1c599a2bb793b5b05e09274e75c5993d3b92c0578d88001110f4b6bcf58e58970a40cdf85b08dc353617a49a1670c49a0a354357d6ac586619f40d52206fa5951aaf59ca0dcd5efeed9ef7bba9d3230d8a1f5724bc108e49700e6e83f6c4406144150d31ce54e1c6033cef8775cf7d1720732a96a00426de3e528ce1a69f7462cc67fc64a84bc0ed7efe83a3665e31c29e4d9651068e8cf4af993061baa8267e25b3eb27e664d4d68de9fabeb3fc8030b9902624166398ce9903e21ea29cdaa99259dc252f7c94f2a717e32f11590318308b0106bed5d1563a5ebf4e3e858d56600b389568999c943cca5baa8f36b97a0e33d888737ba9e3c52f3d3c5c1f531107ec77811ef282737522452876cdfa64b1d00d69009143440ad5c07fcb1804d3eed26e38d3650126f568922ca8715049624c238b2a4fe729a3a13dc686bd3fc70ffb06240e5ba6260ddfa580e02ecfb662aec129ef18b9a8dd1f983ba04b6ed063750d3d97ff66e93799c07892f2a462320c4b89498da8f01d2b4fa65e7c6211bd6794b0acdd287ddee913f265c143f3ecbcc656df8266cb21b7e2457913ffe17448d5f700fc236b867075aa4270b9237e76eaa3dcd6f6a50ce5f53a41090f6eb00afd45a2ffa966df22679a642ec8b3204607b363cdd1d571d941a42bfa463e842c9d6556861fca46e915f047eb0f35f3f8f0d91227ff6205fb07015f5da23b75ef0b7f85cc54c8bf6bc3cace19b7e78ed4cce04f3377cf68e3b0f2c0a28cdfce86c00a3c860f5f17e979bec127349c74ac837c1691d88b49160dede6dcadee59e5b2e94459e59d155617780e6848cc2f984d8308504558a7196462a6447a3571aff055f1dbce6652658699f2c3adb712430c207b4e3929bdb59921", "-450619ce6a75b69b0089973a20f4a3b1f58612f29cd417e6fd4e8194f6a39fd7449e85e54afbd029a668dfa9922fd46f1c99b972c915e5d17fb247f6cd2ab5dfb2e0c131891de8a1881e145382ee58a539e7a6e6f24b54b66bb1e6bf84051670d737099492aab842c24b5051a0b9f877c080edb838871df90975b5390ef1d7ce2f6770b9761416e14c87b27d37240de0caf047bb4b027bcfa034b00e33f0fbe025308b05d6300bd260ecb63dcafb201b2c354b62d5b07a20d346a8ac68ca1bf7e06acdcc02331c855b9adb89ab17717cbf6426c4e42df695f93f0f6f87d000ce75afd6869a2e3c8b77cdc3e8fd5ebd68b580ddca88e39014792cc0434fb7e42e0fc105db1a05c04ecc86f108ecec9ce12dda4480fd400c49d01cb7383de363a0698a70f2728bceca3fe49e8cab3515f8153e8ff3d75f52d30f2fbac8ab4d9ffbba9eae7b97da82d970f7f9ac2bfdfbc41e98dac5d1259bcba665dfc929cec076d3c9b15cd456ecac34a2a140b7f586bb026976b5e9b7e2ae981a40e02271e28394873cd5e38047d9e4de33ba8fa8c8ca0e3b3c258b7b894be261b9b07402582bbb1ad324c28384fccc38ff7a8dac600406639bf06fd1c7fcaf6c79e793fce04f951ffd0d8d5f41dfeaa6f89efc4690da5f304254cce4e3b19ffe08e1d2625b482f763e3f6db657307f2d0b61e7f6a750f84839c2a0447efb7b7ff061bf7e39c0468dfeb5b12b3f76657df9ae0b3e206291711f623683f48f2308bd8b6d49eceaf3bab75fea8aaef5a3ee004939a69411643da28a400b16a4a1dee0f43c906694afb6a4e0ef2a105726c11d0b8561e06d506fe4ec76b831f4", .Okay}, + {.Div, "d1037e01cfd01ec62019f9208a6985bd7ba7f1dcd66a8fd638dd574a4b95bd797f4de3da4a0b046866f1cba0f246f9c8f6a0ba11a2922fc89df7f62a390d466fe7f8dbb2ae58b4f283feff8be96c50f57c6a260f7bcd4f2a2575f747934427a803829795312a364938c788daa5901b6c1634aa9529d05a326cbed508b3f554f2a9336243baac5784625b092bc5ad0fd7bba9a56ac7c19451e996b664e2d530ea70bee1c9d4c3b9109be313b313bb84f39c443d315e80963a931699ff31ada7046a9298e7ab5edab6a7a8413bd57d48e8f7c2823c2e0f075eb659d2309bcebef38a9c766238dcb60341c0a73e5902e37b88548a2c228cc340f827e6e471fe91780ada82b636a159800ab747cf1fd54b8695586cd9228ff6aa0541680ec1a20859f234e944c4c3550102e463f2f6609c39b4fefd4f21ef6f1000c9d2fd23dfad613258977cc8f953441e97128dc4d42aa6aa11bad9e53b84e967e9694b028360337add6694ff2b24582ca8d6869ee3357a9dcb7d0944903636b6031e7f232020473e8345772d99fbfa5587bd46eb9826c0826a2c2edd8308cac04e466e1a9ca6aff567407a636d589603b6f7482fb45533a2d42ec678a252d384374990468a59a23efd79d880d896fcfcf0b5996df2cbc7c3ce42a494759462ae6912674da9dcf9c5df63279185f868450f81ea8d5eb0f19d7abedcdcdb5ea8863bef6508955ed2a8018399cf735a54fc5d630836cb106d3e618f5031615182a9e13b4225ccd56041f21ec8427ea0a0d5223312c432684fb7b02bed53ca24d717e5cf5768360e8ddaf3260191978a14c47af37a27fa87fd0dcd2b38375c98c90735ed6a734745dc0dfa69ffe67a7517d42005d2916bcc4cc9f6479469fceeeace637a969412cdcce38e87d560c02364f0abc47e55e4d12bd4125139818051cc942810f334e20b7241481d0e60ba93fc9040fa7a7573fba6b4b12bb5114f6c8840bcf163b948a884f2f1b7f7493f4ba7d325930d577ecf46214c1ac0cd8d17629548d38ff69ca76d2cd03b47e0eae66f55cbe139e16a0693565dabb9ce43262ada96826b5c82151922c57a703cdeff7d93ee8a0695b2591626256eb9874a5db8404413469cfc18bcb6999e0881856b8a1be0b8686641b44a754ebf9112dbda43a4bfe6033bf45bb982b4f049ad0caca12489137cc7b4a6b755470b0799c8e2a17509a06f5075069aa69058988281951ac10928b6e1071f231a7f63c672b6ae0956631e0657edb70b2b557a385465aae2c2bde99d7cad68c1ab7e4f3398cfcb3fef835c2a786ec5fcc9de08b6393bb80686a2298e12538374502e3929019c468dc6250562f263aa4b7a334f9638b72a915c4bda8f570c5aca1c6450d9c96c2cd3640810c3624726b1fab210373f2400d0967815f010458191fcf5f3a1ab52b5410477f95d36cf9386c581a8c5c936869512fb0233c6fdaf49bba867709cfc4956bba3503b45c46f989557d4bef9d8240a71dab35f1a2792956cb216c482908fee85df8fcd9b5634ec86deb24c4211f75ae3b2469fde765e86fd591f2efde0064cc054228773e749ab3a8554431d3eb866ab9bbc8fbf18011cec075aaae548125ce3488aad68df4b6629f6a47fb9660e9606c0e4ebdd218d18fbe01745601eba77221eacd425d838e114723c806a5d47694b7aa2e3232fea41b58a92424d5d2e9db8b197cecd8fc48674c8358f8426849fb8c8510a750012a53c45a0c7268356863e904774b427d02b53c716ce7786603e59c96be693cfb6c68e2d24b83f4f9dcab58708cf04491e8af8abd915336fcded49d86a14c834215cd42397d694874d172746903f83218c6c305195173f7495cb7b4526d369838bb3e17a6e7e4b60616a39f0211df10dda929e1776530d9543500e97573372bee68005a727d5e1cbc6820ff63bb062528ab6f82299a3446d176ba4ff62ad8f51ddc313c8b5b6e71f74b577cf6b659302317717091eef97c79b381f2215010397f11d259dadb7dc4b2f9a0c0f51a7481e8aa3fafc9c732360894213e657924a85b957464febfa1246646fe09b5b3221e3d98091c4a5eb4b972540e076f00a4cd7f800da97f0c6c59211e2c907ab00", "-bab74ca5463f992a7d75e30633cf30c95636d6b315cc481287e69810ce5c665cd8c8f8bea8662f67c20cb3772dee75cb886d7ee8aeb48c93eb0169ebc490b0b6315e2de209a723353176b5943e03b5016a7f91ec99350b15a12a15c81646062b0a53697c23792fc3aceb912bcf385c0c117b345b18e1df4b0b10f7660fa0894e404d8debe3431b00762c721e23772f79f0e77c3d80e2c8e3f3af017c6d36d88bcc8c913f1e296b701545b01c48ab92273940e968db3c1b5342b0075f2d0c1e800e2f5267be6abae8bb49f4c2e0fd964916ccdc5a2e506ee282fe472ce69e19ae4efaec84657d9b48b765ecdeb75ee34f848ffaf63dbfa5d6ed00c94369f7de188b871c88561b4d61ed1b42bc2d1cae1dae2523cffe80152cc1974b167dcc34d7327f186e61cefc4dc02841e31d36d882577600a23720f2e122ec1d158d79673b2f7fecafc44b3c78d7b5d3a9a7f134814c83dd5ee566f58fc177e28e2191b7b23dcd131ae6778f79c22a4e34573c471bfd176931b0e90e7f124a4644d3d6d2c1bd2c74a3ebbb08624670c50d54bcc2abb5fd62c1574e18883e07c3ea0fb0ba37de67903ce0f182b500b0f68597547f053977456f2f6d35aa925d017522331f3c87b8a359ecc79cbfa666a70d5787e34f9a3358fb93ee564b8fbd77bcac2ea47fb607ef5cb3af8800a09d6104f60723c406a4e6cec6f6d0a89af7af64ba90c3f406b0777f535a33af42a87192ce4170076627b0d7ae28ce1496527a07cee4d574a2a7f8a350abeb74b42737765b7a88d58196c0aa95545e19d6ab8e4342535e23966ccefd83703df0de297a6cc22f1d6a96b136cef68564accc2526cee1ffb0372683e8d885e54584af30739d64550628bd6e34aed336e60d36cb75a7b556dd86753f063f28aa01faf2b825679bcd7e84f61347bc2012bb5bfba5d0a58f9472dcec1499e768c778478ad66fe889dd86fb3e7aa680b0259015a36a574d539e6dd5791729593d000991239ce3ac7e80567f722d7742f0272afb9278951bf96e80c4e3ed90851e708fefec92004ed2d0936395aad0c3854cb31e5fc8e94512fa7f10b384d0948730defdbda9790dcaf6202fd1446929314e8b272d9cd6571d36c426af8d7d7d855c423f8e5ecefd4379915308eba48d7942e77e8d77430bb519e164d14152f1f0b643ecb2e1d7965999b9c75350cc9ea1bb4929bc0ee3805fcee47713ae8fd15bd935eb6f46ee3c98d66fe0bf89a2d1246772dd38565b5f497feff8b38efa65", "-11e924f4e00c9110c3bcc3fca3441a95bf876cbb6627fc02c04646c1ab735e9460366083168179f214a0853f464ccce86c1436d9c90ba98299b4ddd0fef3f3704a4e8850e6c748213abbd22812847a4368dcb6fece65efa85734327c53fad155c3755ea8dcea0fcec6b57e02da8051ccf82c9087ed3696c13475b2e4ea8876c4fbc08aa400300108a2706a70d86f7ff97e6f88adff96b6ee4564119c36a2858aedb64b28ac311dc29fc3476b3e57d8ed19f0955f49cb9cbb3038c4521ea92a029c39bb765bbf848b37d11863ce74f16edec20b0db52f52180758603c696b00c49993c55fe28ee6e43731b767dd29db898c85420592b9acc6eddefa3bc47538514bed516f4db38e1a6d7a9cd4c85b454620f697fd696e2016a3616501cdb7fe5b8d8680cbcc3ce9d67de2d8598f0f4ba99206d33e64855857e29ce39a527b07070ad02a86b963eea11d1afdeb8b1573ff93e956cb0af416b4409dfb6edcbbdf343a57bacad2ea92e7a15ec5a5479b897081b99af5cd710a9e20506cf1c30e5c4ba4b69afaa075a47880c8579d558bd29fbc47e5beb1e7dcbef8682c78774c1f0c1058a2801a4b8e59cfb4e5cf310f4c1d07b1f901e09b8c578526ac6f805690044b3c12838a28d92445cdd51f8390cd5b29805e8172c77ed9feaac96cd2af9acf6060752dfefd7218f1547a37b2d035b3dd351820df6106aba8fa603084e499741d753601fe6e7126a51c58d3207271cecc81610dfd0a839c732e74cdf54ea107543f54c25f6aad02c0056c5ccbf2305c253772de437e81c82e902e6bcc6132654c7ac1c69410192ac0d3a86e482be4b1adec22fd23c3249ad", .Okay}, + {.Div, "6ca946b91ea2f61a05bcad34a6f88c60a99a32c5b6b16448b26c5168d7d6a252394ac95b15a2f2f4abffcf01a5cf0cbe3528fbde90927687806ac2d45e2d72ab8b988aca4d708fe4e0605dc95e6cad347a266d75311d6f9ecd07bf97c20613de2a383861f2b93b7095d600bf8b827ab4ebcfa11a833605ddd5bb822dc52ad3ecbca02b78df9a71010684906e02c071b37f7727eb0ee9ce685fc89cb9bc5bcabf27448edc2fff5a963dd7ffaf8ca837db6e33065cdd03ce8829b6094cec6614238bed1f2ee8c5f4acdcd86473aceda38b6819ffdff2c7d9d85ab0b3f799b832ec5f8a6f54c6bb2f7a86c80175d8b45b23aca878d489cd25ce71a308f9dc4321601bada32b51b08d1ed840005368c247ceab8ae65c02ca93013f03801a413cac8e6277536d026b997bd216051ed8f51049c7200bc59d14f44fcbf76f3c0c4c4bea67e7774b38c13bcbc9a03874145f14a05de769623fd59a10b17bbe6d2875d0ba9e8d61506d33a002b01f0b3d03b669cb075b1bba8249417b8d5347d71fc8ff1e7f5a49fa00ad2802ddf21c6fd478f9514454ca0d8710a1d39fd5dbb0ae4b3ac7f950dee9cbbf21d8905003ed10dca21dd830a5714c2b6ca2d987c7ce8e78d6ed80ea3207f3166a0742fc8cc51f0a71b40dd96cdf2756de6f1cce7e32bb15d15517b09f8f5ecd61f2466889cc86154da073eab5eaa983e7918da5aa0c1e7a5532d71623c1b0e6387ae8d47354439e61c16550e4bb3cc9653f9e92b85a49e25ec8595332510146b9ea3270806e17f740ac50beb58c049ee11a61d55ef09b1528395cd0438d911ef1156bce8fad91fa085c04853ed0e1edaad5f0f2f598e271abc04776ff5baf9f1a984c2ffbcd1a34f6e27145404f3c91a8136f93598d8b107702fd0de77c57824d97a82d4a9250970a629fd82c2ec55b6eb4ea599bf9d75a11250306ff82246ada09dab3d8cfe73682dd98ccd364c57b4a3e824337c3ac4ddaf405cff2dedb1a136517529072bdeba6746675cc3f790a6d7b7b05081a6837bddb0f098bf6ff4527921b4de9bf2a9518801e087f3fbb83382727a18a13768fd03010454ab53ab80e92a23e3027589d72bcca93ca0d0495c303b1297f054badeb1aa62df7c3b99596d39d117d57ab9cf69a40cc5f764d45e530585e6d8bfa5dffd842d3a7e836bb4a94995550bc58e738182c193a01c053ec935ac495fab83377d1596b49d9a13ee05110257b9ed45178abebb8116a53de6d9391c32f77dd9b79d6799f5885d33e92e0300a5d93b8a5bd9e2a30b21d7d9ac7d3aa212172dd2b726f68c3cbcf102d4138fa5f274f847ce7bbfe3dcb7b6249142baf5ead2dcf3475183c8661677006ead409d35a11dedcb0d26e5f831b223b043a2d72e90004994b8a1c026f19f394df7b2b28c6fc82533c84922ebfe0a626e97942a624e1135c1212009b405e57e536138a8c88e863e96bedef639140b5f8d576de9e122d45430f805b514db5ac33e0df158cda0703ee92c1c75a65b339390e3b40a8a043184ecc64522ba43e9042078221d4cce02e0f4651d33b2633da9a199ca8baba5d78b5eb84c0e853000488c02958863d5517485e0db7285e44ec2c83d929e5de38f261bf2144545f59f8d38c3b1bb9ca1f8c9f462392383677a0bb91701baf3f73b2cab6ba7b53f7567a0a779bd4e6e97384d679ab7162440ca2db5046e7ee186fd8b4a810e5ebbef981aa82f79da5db1e8e80f6a35b08077b81a06af3e81ea0d7b9f178fb79c324db70f9ab4a4b2b660ba0b4a9a8b1644c673182958b688031d6a2188c5bd7d783921448bfad99d1b8595b83a2f619f4ace1f4b041b392b078ea421c6de0e6fb367947797288cfb9393b7fed498a04802f3a698d35c2165d7576fd402c5f8e6715de21c79fd471aa42e00786f1a55052e43172248514385cc7830910a743cc507ac402cde3a3712d6e83589f79e33c9d1a8554aa55058efb860861e4ac83716a725bf3c7c4783396e23dc093410625f2f88277fb40301c8bc07774cd81bacfc36fede332ac8bb952e882ba6ac649cf4576a0772e4f729ac28ea289fa97d66620431b8843a0ee799bffa735787003a1f117eda19893a1121d4a13", "-3362860bb290e68526f8608badaddf777a6492a5ef1b8c91d9b2424f5d90fa5cf47cbab33f2183098e7d149e5d23a2b6282ae34270b57289c1347eef3558a416eeea46ccac81843a815ebdcc142e5b8b0e54031fcfd149d27c14639484ddcc178a972768df46a7eeb7b3e1329886a5988f0d0d6870215c20f1efdb7fe176a04ee341da727ce954bb7ec3f8549ed2a2dba6a213ad62f4cac102ffbcbc6a984e5a8a30f3ae10b2692d2bd784951b6255e4a246dd32353cf2b44b086396237e735d9067fc40e2ff3dc61a8e410187a5d09b910b61043dd84985d62ee7f31db666213a2966ba1945a64a37d2c3685b845d12a3444a3742b4607b5f1ba2a923aa33533bd9ca07f9656a7421b5e51e2e67dacb7c174f60c719301f622c08b9f382978be48e92b1f0c527b47a22cbe4de0274bb4ea72e2b6ed54b17ee8ef0fc49264bca21e8460d56d11bf077adb3f2a22c5c4f4267178d4f914080b6c563d76a2ac3ade3d893ad3fc5da5ae26b132e0a3d524abcc2130ddc7e40fd1b1e04a6742645616927dae322dffe516a23509244a697bfe7457e674ec1e6de234579ed61c2bd31890eeeb0694d3473feb5805b621c6b8b0fb8317f0fa9c5026801aa622a4f12873324fd16df5352b648313ace174fd40459c9bc47f61180b2c738d49dfd82ce29b243b0704983acb6bc01681e818c955ea4d8f6d132a2994cf9bd38c9eb4a9861a980f2816fa0017c0ffa322a6b4c7e6459a54d15c63ffbab5dbe1ee573fcb61886e88d8448529febed38cdca0e6aa414d45880f2c328634be1c612d0cf3424888a48880d6a9339792ffd6f257f433c6d2c8a91a4651ba6a26f309753548bf48e5ceec82c0fa9c660ba20004dec3a98fe50e4106b1bd8d5bc2b41ffc3a49db09c55d88ae019f0460072a0b5b6a5c3c3f0278a38c9d040c505d37af32c5b0e950bafcf93b5e298e19ccb4aea01e9c978e9a9938bd9a014cf7babf71272a5d71dfd64ceb79a0fa1c3434f6976aff1d8a203bb5ac8e34a8aa1f7d9322c3eef84e6f087770d3fd27c8f699a8c77fdd7ead577f3af80920713455999c9f2e099261202f3332b7d4d73f04c398a13e1735d133a8d555a013388236af66742830af0e66d8f3add964307a63507877b35a156207e2b78f6e30439b3286a9d6f43e916268aeae6279fb80d678859c79cda96d6e6d15252ca674bfb8ae9853f916ac1d92727baa7857af790d0c6417f1d033a763cdd9033d4cf515f40c2f1462dc42b373b6a69980caf", "-21d5a0408a45c11c9f7088fe4f113194094c7a70d08c4bdd1fdac1c5d6d8750ef39ac9cbe632e475a2add944b225dc9c1b23c1eef761e80fb6c6c60a389e5f63555600479cc625aa2ac2def144c5b317d62cf1e5d478c467999d4678a685394d2df243b6fe494a95544d0b2cf14cf79c2be1fc308ec19156541e938fe2baf1af7049bb5f2c215fe6e0216e3e12de661024d5c834d12fa6758e29e15e37890d3c7306bff41f4001309936c52f7decc7fb1191b268a9f59cdf534a27a41a910fee1e426c87977dfca9ef68ff47ddb7b6503790b64ba200e6051570816a69bfbe733f91990e07c0d535ea9539dffc2f7af73cba46236b8d9d191a60db0058e15fadd67db6e07571dfeb068959a9f385c83bd2139d5fcf53978d1c938b9a44ac74159b10106ab1f8357511fea5b4885b8210bee9d104ea11919c58ac0a66ddd2007b1fd1c37af94caf201d63acd4f4442b10294b17f7ab979b082696525dd62818bee1dbc46fa830246e257b7584aef75d4242494bc4a42887b2756a6d5c12b9658c8466fe7ac503f96033959c122d5aae4d0225d51bd9fbd951330bb1631df8a038bdef2a728746d343d29e4a1ced70fca835afa0bcf7114f7a287bb3858502e7b89d7c2cf367d8233cdb6f887b20c29669b3b71854a1371ae6f4ef08fab16351b3b9840f7967e1495d281617842aab7e69d6b10a9dd9dc06350b1de89179261b9cb32198564c73ef5128b05316799f76679f353d7733b44ba9dae4ad9d8c79ca73e86dd3784d432120136aadc533a9645bda897868fc94728c2a6f87aebfa8dbdc94c82a29a8241e3494f179758f4821378c2879293404be908", .Okay}, + {.Div, "4eaf4dcd7e1c9edd6f53227d6d44aa051e9e083e68b9640e975c8b2242be52bf124fcd6a1feb99beca3fb045a48a40c3db73c90bc1ae0b28b1de4273cd38c432543bd0688dc3972cd08f41b9ff5d65526e0d030a3151f2280a15bb82341d2128b7abdb481ee70002c359240a16ca0c1066bfd3942814f52637279c032310c1efb838df30eb92a42850126fbeefd8ef721f07d4271bdee9ee8030f704051806bdad2ddc1fa4f3065e367560808b951356ed7233c8827bf5d3db08217c5b0ca3669ca2752c01c25f7d812eb057e70e0940cbd0ae99dee8ebcb8b2dc5f8309ffc4f6605e348eb1016c06e1f3a4cf14baed493f384e0c475c3eba2d907232095595171e3f1f2035046bde96043728c4c90641bb5ef8627adc032e95a633b3f070c34ded7070305718a1a4b9a6770cf0e908540177450550803db7e005c84b81966bdf462d787bf2cbdbf1e8d73589fed89b94230ed9f823ff50d65d1c5a0874c19c7a8d187f0c0e12a2e79605a46c4ee4e03c59d723ea38880e5b5b9aa2f5ab55c8ededd9c442e30288af0c2fa9dc0d99cf79f7b99821d823aaae09be643f8bbdea1133b0631591aea2b377c309876e1a1e86329f4123dbee2a4ad8ee3693c0a487b42a869b9578b9f8e2b0c99c70c476deb0a3662e30a5119a4a3e5b3342b190ac375b4bebc4ce103df9367a72749dcf41419e98221ffebac59f1eb7193500763822574f9dea075c888cef58c90110b2c05dedb0d1f42cafedce4ae5037d6e945691897df6c78d6beafd0138da246783f26eb30f3d227ee0182f92b9b3978ce7f9f7119dc44c639a564e27729c9e206a3615f62fd6da1998176b4d301550155a5a004a15eec816bf03a85bca4f0e171669c66867b0474b5c84af337b94e34d0c439b2129e440c0bf20403e07e93fcd5524a5cd80d3f7ae431fe76ef8bb47c5427bb9f07fcba2cdb0acc1d7482fead4c4ba290eccccb51a930945b39b20ae28f9d0b1d3673f4496bf95de7b8328491a40fa4cd37be2b9b79da030abda5a11ffce792ddc1a647468e98387ec31dba5a5923d2c79539aaff77fe4d5a841db822f133d5c05e2c53e1c78ec2367447d4335e87b288e66dd5ef671f2f7a73ae97d7d50f4b8fc525b710174294702043c12bbd410a8ada8cfaf1c60a233d962c04170738049ad100214622f04efcd20d3ab8d89ae7f943fe61c48f50a94566e747d84689ee2677c5484f15519f88e2ac26250a3f0f86723bbd2f7e54339bcf0a8b6bd73e677006ea58ec2ab65fd0ac43094e1f8d17246823e5418721956115e7bc7e3609899ed7530f9cf072e8459033bdd5b4a6cf91f466dc1448fadb97866bd6ecaa05560ad059acc37d7ea47181b90fa0baa1f6c05997c8e46b12e61c4da7f39ff8720427465320e68ea2ec83f1ae90a1b3b267237681eb687598b91a39170bab42a4af433184ac8c74ac7261de9f7dd2e430fc22a213d2f340832f18dfdcb67e3f34fa41e13cfccd0982539184b9eb437a0e8a9ac6ff5bab3f4d4531db8a1b9010d85c71bf0cd89b9bada899840938bf4af9939ce7c6568e1e97afd19b5b4208e48ca3e6ba5ff02b948ef6d83e301c0df97995f23af7126c5e772d11d06f35c76613ff0220a189a07fc7fa208fd3deeb182dcfb28caa4231d60ccbfc62816ef32d5f6ea03f4bc1432f6e0016da58ce2b8573144547c831ab994cd48fb39b1d4429ab645fcdf2542458367b92398c469fe42bc48da9163c20002705dcf1269346f81dace1fe30948b077c8c65d7bc663d11dab8478bb81c038438079e361aad4cbb0956f4336e8cba52e6fccef82d9714ea1bdd02e93e3695cad6c2ffaed386aa5db63965aeb0661cb41ff80d4bb8e9e56c5ac378bb184bc632185922854b19de3aaacdf26524dc863f195c48b92b8944aded1dcdc15a76e15e9d80069b82a116e9af42921ccfd69c664903111363291bb2e7bbec292c22136b3d8502287250ce250a41f51d2331bd5b15aa247168b8fed7b51189e33fa792b19b67b1db82929b80bd935d52c9c2c0e54cf304b98e6341cd639227e5152f666afd3646b62a60108e427c4d38c09f38387e2abcae412eb9c977b8caf1740eeef45e941c7edfb9", "234bb6addbe6ad685e91f7ca1892bdf91e176a36e8135d6495d9d6f08dd4c9f6e418cea1435e38d5614a200326180751237baa133381ca47b2580bde1cf994562cf9f4f58c5820089e9493a18fb067c1ecdc031adab0c0f44d89ea8fc42ca6fa1bd8c57a6eb2d94b4a3816df5e565359823793844f38c03256131f0065b4f6f10a656564aa72a5f57a40a3496d1047568d5835ab9a3b076903bc45996c58e617be6ffe60b638c26819868784ad56507a9471765871211dba05b4193020ad41f95f4ebce9fa482d930fcd7d4c923a450c5cfe9f9ae7943a12eec52fbbd426e0456acbd0103ad3981daf22c311afdf179a68f633d10a932a980f771feda4e77ad92886209532285b1d0ec04f7eed9d992542cfbda4db654d0be767b624716c0b636c64973a6921afb6cbaf9a609f09a5c8f01b4f598efcd71935a989e09dc0a66c487bce49b0dd081305e627e3eb2a7936e6b02f8c39af55e5efba28249ad0ab2ae59d2a1ef74e9ca17f0b0952c8f0575db3184d79621c1dbe4a7ee6e64a6d4d96c102607074e7560176e5445adbf3abb033398ea504e740e31cbc098f0f1b9f0fd47a9cc701f48a7f5a1816fe5e5b850474a6e0abcbfc40131a3c64fa68e8bd8fee7c15a1de1f538b714db967750ea2117fe07f655fcf690172d2e5b8c0a13115e18b03d3489e30d1f6240944f7a467ba6b31355944ae00bffc94ee1eb2202ecd6f646813f43ab37af646549743146e74f6cabd881cabfc6cfc42eadda96af24b33c0bd3b90d09bd975bebecd97ad5b471520ae7575d07263eebfbb4ece42c62fc3dc05c5b0b4d11dd53985a6bba364ac05ede092cb7e24f608b7f5f4dc0af4037506a145243f46fc43198968ce4e4bec1f2c22145dbde32973bf93d46417d360590f0dd161259fc17ef11143119fa3bff0059ef44cf19623db7b6f902c4bea95213c3273323ea3bb7a635c7e0bb5e95387e965175d89469a1e3c26ffafacaf30cc354055333256dbca56048ec409072706e33c69b7285ccbc1ace99ba0d31d3986fcfe45d8a3fecab43a1549598863da23732e592ec6232b1ed20688028ca725bab9a60e27c1a324dfc007c98a727e1edeb64405fa734181d32b29b2d732aa76a08b6e2baf8ad3c7a8240d0be58c6f6c0f7277c8e56237886e312ff5cd6bc147fbea4c566d22ea7e1cfb354d9fcf5ab3a63cbeccb09171fa6b0aad9d13a44a336a30222ba0c96495c1fd66692aa560ab155f95ff1e4a5c460c02b0a17000596947a467a5", "23ab3509f812db10078b5ff49f467d0773940e9d280127fe248efded9d6fef4decc7f711d810a4b11cc6990590b6fe0153e9273010d3f04c8b4a81c09765ce84c75a1e4ec424da06515e840062b74207d69ea0f313c81547671221439722e43cbf7dd9099d7e2478a833b663c40eb3a4e41f1849f9e8429c899571a31486dc1997fb41a6e0fbdc16fe617e6d088d9c7a9e8b970fef06edb7770562ba5c46533b241cc4bb007c0d6ef478525407268683838c972e291f66fcce8fbe179a8cecd3a46108b73328fa3ec930433228eff7ee7e05cfff8d0241c4886c5ab49b18a27ccd8e7c7a117a4fbcecebaf541a53024d53703e3d12cfe17b98d4748a02de43d66f2c7a7bf42e454a24297ecb1944d93c25204aa124fc4d2a19bc947f18ae7943164289ddf0b9418cce5a5ec7a08f0feadb09cc16ff09fcd11e4656a6c141993e412f144f0a39150883fea746070039db887d07ce8cae9292ce995270fd72ecc81f997f81f13c1d8fb0e46e1f741711941a86d9cfce66829a5c1f0645f7b28a2d88cccb61a8ed1a14ff986f13b380ce5f1a762b54cabd976e42d701a23929c90eee7cf03d839cb65a2e538f5ba5568c247ad0d5bbaaae27eab98ad4a9991dd46e0566c887c38f0e495d235ed2978aa0fd21777d043f40706f6269a58042fd620a859175fd5f922eddc18899f8f52060afc7dc05ac33e500ceeab0c96ee0e9fc16d72b0c0358d410b5d32a064772413645076706da6884b59aa9283f0ea148298bbcbdfba96731d82f231c213a60d3a53c04f66224b721ee70263aa5426be03097395bcddd71db94e84a0b6b92afed813317063e5d6052661ca", .Okay}, + {.Div, "94fabcfddedc4b0082eec991798a4656b09a7c9173edd68d2ec58b3c6bd4aee484d22d6df51272e0b5198784ed28baf3b195831ad861a52f5ee374141336378115c661662bf599d859e9c9bade7b28bf45c5cec918f7921b4df855ee7b06bff8c6ba9e8a9a4cc498556ae8f3fbd70102e8a9fa94e133933aebe2c9b59193b446418d4874faeaa65a9297c81a274943d9c09a4227ed52a730bc4866edb3b0cc84c1bf63769553809bcab4e6644c4c6887c69fa146b4928874ac2a66fd3698556f0676167dbe5eb20057cc0d0eeb99090a684654c477f699700b40b5ec4680bcfc0d97f8fe565b2fc0a54ff16f25db127bbcc5de6b6ef2fea00fdd6435a41aabc8e802a0413d9acfb29b9cc0a376f0bf5b976208be05fbd82f0811e27a7880ae3e737f4174105fb5d9070d81b67da8f70a20a5b13d6962e02af8c1de24c2548310d80975bd8a369e344b0bc8eea1437654eb4706ce9e83912e5b310b66f00dcd14f53b74c2ccd77e689677b96a924b786b88a4bb39f66cc84a105c7c4f621970ff64b1be6477bdfa299120b2d6fa4d2802f6b53f9500924a86b86b74b60a9b90e0d26fa0805c510a569506ed542fab82553c38ce0701fb41d212a0ac4863dc8b5cd85fa3ab1bfd8b46d33bdc9525eddd44022898b8229ce1c875babd99ba1aa4bd9b07d2673d2ea542a695bed49715a49fbd8f3f4635f27aa2e88a473134567140ddc5804de83fa929f62fe9cf96b8fbe798907920fd99d73894aff81c22cc0670620b2827c892bed871b9b787f5cf17c7a9efb0776a08c3d05e5ec0712ee4a16ad0b59ceb699e97ccea3c4c890d56b24591134a402966510ef4e56f4593ca2cad143435248c192b78d5c659cac03c447e12c2efa051279f1ca24f6688e1d05997eb4c3e2682dc2191b1782d27e6aab685de5518eddb2ebcdbb03284c45faf3316856952fc6e66b1f822d4407dbe23c15b6f6fa789c3603d846d87fd0cdd29e192cf5a63db96f897148e18b565ad7451f9c789487a4ccff10db413d1f4a5d22f89d68c13e7d3a122466300c374f703712d8d14aa88f57df52b4ab4b06ea05db384240a11480b5c51bdc489ee23c42f574c14ec419ef937e29c401765e6b688f3c731c52171dbfcbd713b4d89763fd9b45ae4405c7c41bcfc5cf1f7123189e0942ac5f6a75ead91d9d308e305eefd78eb29b0473d3c47e3b5f49b60b290afdd16f0738d33ce39dd78aa076a30b15e066a9427dd2b51883dc0a71c195701a918f9f836c91ad86db903d6bcd2f268da4bf361444f61444b2d46ec4312160ea9d7364f621051a21ad15d76ef73b8ae6b618698180d370393feef4626135e84dda07790ee2c56375a83f559537b3a45bfbfdf69e4a0092daff702fe6afba92de86424b7eb781b05cef43b9fa26e643a0d35b25d56666dc791de1d5292759fa25d0bde081a2ebf0702f9edb8028e4eded7db1e39c39df726af95ec037c22ff05b8b924dd144fdf1b14bf35e6f3fb9e3830f6d4b3f7dcf20befdd2784661f68879fb9078a41c7553998510419c6815509dcc63c696954c862665fc934853acc53f4ca96cecf6d5370b6869edc454e4195a1f713c55d826aa0a9d377d37865be6c45e64767f56b134bc21febbf6df8b009e76b4f93b251a28d2fed7841a0caf4b32250c4ced26feb87288fb772cab70230973187613fdcdf6938a8290d919a1230f562b9029d36447c4d16542ddbfef099a7bc29c99cbe6cea6c16f100d79556b39edd1c8fe0db80567292de5529e459adad5a4532988255bb7cbf69dbcfa44333fd7988704e32a87ae4cd888223e3d6b7517d5d58663850afe00d6681e232df8ed198edc4e4126cec1a6507f2cae5abbc0492c1b4eca44b8f794de7f0545688604d5b4f519f0ed19d295dc1c8d7a3837ffabc4354c976cdd8190473f9468255e69510c732a8b5c2ac6f7ae854b1c7a4337b365bee65f1af66181760e799db134293dcedde4d760ce869043a669e9ae563e1f3c2413e2e2f3875ff828c77fc5f596648379bba37e569e90059adaa389a4653c2695707c292afdc175e8239dae57e4a27709afb2a5bf4febb192ff1ea0e5a10fc80127a4f5b04293206ceb135e2a", "22fc9629450e95695b8a8e23a1d11170b40616fff30fd965134de3c46dc9b91b710e02d3461b0b5c0d2c36b79a2b16ff066491e737b089d2c12451d052467623aa41ea34eca2a5e1d6ffb5aa4200dc23b42836dca9d61af078cb614660f680ee687dd2ea18de32b6b6e4112f4fb71cf7041fb52e4cb58614a9bf7d74cd174369a0403f3df8a3d415d235e2a6dff17c2fff618718c03000df4a4c3cee1e4945100c1b9f4dbb4c5de1b157af1c5de68b05e96300c5ce35c3f3d165962e5dcd988f26f83a58f531d9249f73a59258aa90df99ca7e1f52430e823e4364349398ebfb8d59a12c5be35773be8f78d10fd4ec290d575fc8b56a71aea06a12a6482f38646e9a4e9493f93ac3660b8b9772280fcb3cbb082b2fd47bd61c963e3202ebf4167eb1f571297f2c8ee1df1453a5729e9f84709d654dad47735b7701293acfd6ad83ecd0cb25fba21428ed711f56b232467cc85c629a48f76302aad800c4cbe6667ca622a086ea454b0b394c847dfc97b256acd439ea0330a994d0ea26cb7c06f601bfc883e8261431ee3190fadd4216a4881fccc250c3386d3aea82cd65472a4e267331f3b35fabf283c8a91bde85930c603bc02549a12147ab49d9cf5c5ea120dee35b755bc885f018deeea723b38fc3dfde9955837a190edb989e4df1e7f2213aa22e81c9a57b3f7b2ff9cb9502a86c9f81951449ed24023eb058a3110246648d90dacc3dbafbf546f926d00a38b5995e36a8dcebbb5ba6267f02e0943f6f6175da7fbc89345d0c66fcdee20c7f2a187ee75d7ef3878baa6bcb6e46e0eade67f292d7c41e693ab4254b7d6798ac807652d50c09933289473beb14e3f594f7719bdc1c5638a065a95d546d64551388980fadc21d1b280399967faaf38d38893d0123a43184a4ddc4d4793011aaa9e0a2711cd2df22b4089b6e2a687eb443ea8e11eefb414c539f7d9c2ff071702c9df5fe54363cfc054d5f7dda6aebe0454e8f71d7855ac0968c7542672dbacae47af311659d309e0d82e990086b381bf3168ed6842ca69c6e33d38aeddc8c06e735a42c1f78ee6f1675ed5657c026ec6199c89fe15e54430e5b134a41c21d6289fedd1fcddbed5af5411ff7d04485d71b9a03fd5cb8fe09d2dabba8b19d4dee1b03230491968a175393df432d92b3ee697116c7b91ec8aa76f80d7eba33c1d97f78651208d32c5606046e0ec3d72cba2bbe33669502f81e3a5bb3a632b3c229d17056e043b6bf55ed4193481ae39c929272c86603007c", "44217f1066541a239cacb5773c4f6a36007524bb5068f7c15b98cce1cd5cc1f28df6144128806863a6f15042a10c0c56b01e338530d14ea7c1e08b876a6781047ff107e8f6f90f5efbc5e97a075c6623f912de71d1d037421a683c2e507b378a232e60d8f605d4a1f9752fb72a62c4266d6d6dad48b09d782de7f9a00cd98e0c769bf67f168887ac8af7e9e645bb87b50666c9b6f1e30e494972e63126ce61afb991f59791d7720ee1210a19949a6ad33a7e784ad3d39c83343124d7a67589b6cdbf0992565d1f6f69079c2af0315ee7b3ccca911b468989d0ccbb7edb40b6afd5782b8082a227eabd0d5c300c2fdd6507c4d69c75a5b0f25da1c6a9becdd3f61fa5c85f8116c8673f3c03c314c3ac5553dd9204e165aacfd60229a3178322da5d3fbf6c1f22e6e6407aec97d23e32232f8e18301a4489a7dd164a5dde95a34315d669bd970a2a6d7eb71dc6964030c323db8f1739abbee1bc1a969ec61280936bafba45dd426e745e8c6f785c3ab0cd08337bd07ad73af2428551e05ccc1de3dee6f895db9cf889496d0f39427a9ff2b89288c3c6806bfaffc30560af130b8c63caf5ba7cf070286af8c7285704a5c7c1f2cc1a7b007016ec99eaf8423d954d4e02a69cf6f99f5b23ff1ad2e43430e3d32941e95624a774636f34de7343e0d1196b4973bed1eabfbd5ac4d7c8744f5787ede762e7bbf67dd960845690447b97dfa0be8d2d352c0b776ca1acef31c827339d74cdfaa50ba1678de5ca49615e26a5256a6f3b1c0a2c98ed187e86bba50cf009deff2f817f4d72cd9f7ef35fa39e92ef1368383dab252a14aba707a8fffe7ae845c823a80596", .Okay}, +} \ No newline at end of file diff --git a/tests/core/math/test_core_math.odin b/tests/core/math/test_core_math.odin index 8d51c9da0..009e3fedd 100644 --- a/tests/core/math/test_core_math.odin +++ b/tests/core/math/test_core_math.odin @@ -1012,7 +1012,7 @@ alike :: proc(t: ^testing.T, a, b: f64, loc := #caller_location) -> bool { case math.is_nan(a) && math.is_nan(b): ok = true case a == b: - ok = math.signbit(a) == math.signbit(b) + ok = math.sign_bit(a) == math.sign_bit(b) } testing.expectf(t, ok, "%.15g is not alike to %.15g", a, b, loc=loc) return ok @@ -1238,7 +1238,7 @@ test_count_digits :: proc(t: ^testing.T) { buf: [64]u8 for n in 0.. +NaN = +canonical NaN + {0h3c00, 0hfc42, 0h7e00}, // +1 -> -NaN = +canonical NaN + {0hbc00, 0h7c42, 0h7e00}, // -1 -> +NaN = +canonical NaN + {0hbc00, 0hfc42, 0h7e00}, // -1 -> -NaN = +canonical NaN + + {0h7c42, 0h3c00, 0h7e00}, // +NaN -> +1 = +canonical NaN + {0hfc42, 0h3c00, 0h7e00}, // -NaN -> +1 = +canonical NaN + {0h7c42, 0hbc00, 0h7e00}, // +NaN -> -1 = +canonical NaN + {0hfc42, 0hbc00, 0h7e00}, // -NaN -> -1 = +canonical NaN + + {0h0000, 0h8000, 0h0000}, // +0 -> -0 = +0 + {0h0000, +1, 0h0001}, // +0 -> +1 = +smallest subnormal + {0h0000, -1, 0h8001}, // +0 -> -1 = -smallest subnormal + + {0h0000, 0h0000, 0h0000}, // +0 -> +0 = +0 + {0h0000, 0h8000, 0h0000}, // +0 -> -0 = +0 + {0h0000, +1, 0h0001}, // +0 -> +1 = +smallest subnormal + {0h0000, -1, 0h8001}, // +0 -> -1 = -smallest subnormal + + {0h8000, 0h0000, 0h8000}, // -0 -> +0 = -0 + {0h8000, 0h8000, 0h8000}, // -0 -> -0 = -0 + {0h8000, +1, 0h0001}, // -0 -> +1 = +smallest subnormal + {0h8000, -1, 0h8001}, // -0 -> -1 = -smallest subnormal + + {0h0001, -1, 0h0000}, // +smallest subnormal -> -1 = +0 + {0h8001, +1, 0h8000}, // -smallest subnormal -> +1 = -0 + + {0h03ff, +1, 0h0400}, // +largest subnormal -> +1 = +smallest normal + {0h0400, -1, 0h03ff}, // +smallest normal -> -1 = +largest subnormal + {0h83ff, -1, 0h8400}, // -largest subnormal -> -1 = -smallest normal + {0h8400, +1, 0h83ff}, // -smallest normal -> +1 = -largest subnormal + + {0h3c00, 0, 0h3bff}, // +1 -> 0 = +1-ulp + {0h3c00, +1, 0h3c00}, // +1 -> +1 = +1 + {0h3c00, +2, 0h3c01}, // +1 -> +2 = +1+ulp + + {0hbc00, 0, 0hbbff}, // -1 -> 0 = -1+ulp + {0hbc00, -1, 0hbc00}, // -1 -> -1 = -1 + {0hbc00, -2, 0hbc01}, // -1 -> +2 = -1-ulp + + {0h3c00, 0hfc00, 0h3bff}, // +1 -> -inf = +1-ulp + {0hbc00, 0h7c00, 0hbbff}, // -1 -> +inf = -1+ulp + + {0h7bff, 0h7c00, 0h7c00}, // +max -> +inf = +inf + {0h7c00, 0h7c00, 0h7c00}, // +inf -> +inf = +inf + {0h7c00, 0, 0h7bff}, // +inf -> 0 = +max + + {0hfbff, 0hfc00, 0hfc00}, // -max -> -inf = -inf + {0hfc00, 0hfc00, 0hfc00}, // -inf -> -inf = -inf + {0hfc00, 0, 0hfbff}, // -inf -> 0 = -max + } + + for datum in f16_data { + r := math.nextafter_f16(datum.x, datum.y) + testing.expectf(t, + transmute(u16)r == transmute(u16)datum.r, + "%h, %h -> %h != %h", datum.x, datum.y, r, datum.r) + } + + @(static, rodata) + f32_data := [?]Datum(f32) { + { +1, 0h7f842000, 0h7fc00000}, // +1 -> +NaN = +canonical NaN + { +1, 0hff842000, 0h7fc00000}, // +1 -> -NaN = +canonical NaN + { -1, 0h7f842000, 0h7fc00000}, // -1 -> +NaN = +canonical NaN + { -1, 0hff842000, 0h7fc00000}, // -1 -> -NaN = +canonical NaN + + {0h7f842000, +1, 0h7fc00000}, // +NaN -> +1 = +canonical NaN + {0hff842000, +1, 0h7fc00000}, // -NaN -> +1 = +canonical NaN + {0h7f842000, -1, 0h7fc00000}, // +NaN -> -1 = +canonical NaN + {0hff842000, -1, 0h7fc00000}, // -NaN -> -1 = +canonical NaN + + {0h00000000, 0h80000000, 0h00000000}, // +0 -> -0 = +0 + {0h00000000, +1, 0h00000001}, // +0 -> +1 = +smallest subnormal + {0h00000000, -1, 0h80000001}, // +0 -> -1 = -smallest subnormal + + {0h00000000, 0h00000000, 0h00000000}, // +0 -> +0 = +0 + {0h00000000, 0h80000000, 0h00000000}, // +0 -> -0 = +0 + {0h00000000, +1, 0h00000001}, // +0 -> +1 = +smallest subnormal + {0h00000000, -1, 0h80000001}, // +0 -> -1 = -smallest subnormal + + {0h80000000, 0h00000000, 0h80000000}, // -0 -> +0 = -0 + {0h80000000, 0h80000000, 0h80000000}, // -0 -> -0 = -0 + {0h80000000, +1, 0h00000001}, // -0 -> +1 = +smallest subnormal + {0h80000000, -1, 0h80000001}, // -0 -> -1 = -smallest subnormal + + {0h00000001, -1, 0h00000000}, // +smallest subnormal -> -1 = +0 + {0h80000001, +1, 0h80000000}, // -smallest subnormal -> +1 = -0 + + {0h03ffffff, +1, 0h04000000}, // +largest subnormal -> +1 = +smallest normal + {0h04000000, -1, 0h03ffffff}, // +smallest normal -> -1 = +largest subnormal + {0h83ffffff, -1, 0h84000000}, // -largest subnormal -> -1 = -smallest normal + {0h84000000, +1, 0h83ffffff}, // -smallest normal -> +1 = -largest subnormal + + {0h3f800000, 0, 0h3f7fffff}, // +1 -> 0 = +1-ulp + {0h3f800000, +1, 0h3f800000}, // +1 -> +1 = +1 + {0h3f800000, +2, 0h3f800001}, // +1 -> +2 = +1+ulp + + {0hbf800000, 0, 0hbf7fffff}, // -1 -> 0 = -1+ulp + {0hbf800000, -1, 0hbf800000}, // -1 -> -1 = -1 + {0hbf800000, -2, 0hbf800001}, // -1 -> +2 = -1-ulp + + {0h3c000000, 0hfc000000, 0h3bffffff}, // +1 -> -inf = +1-ulp + {0hbc000000, 0h7c000000, 0hbbffffff}, // -1 -> +inf = -1+ulp + + {0h7bffffff, 0h7c000000, 0h7c000000}, // +max -> +inf = +inf + {0h7c000000, 0h7c000000, 0h7c000000}, // +inf -> +inf = +inf + {0h7c000000, 0, 0h7bffffff}, // +inf -> 0 = +max + + {0hfbffffff, 0hfc000000, 0hfc000000}, // -max -> -inf = -inf + {0hfc000000, 0hfc000000, 0hfc000000}, // -inf -> -inf = -inf + {0hfc000000, 0, 0hfbffffff}, // -inf -> 0 = -max + } + + for datum in f32_data { + r := math.nextafter_f32(datum.x, datum.y) + testing.expectf(t, + transmute(u32)r == transmute(u32)datum.r, + "%h, %h -> %h != %h", datum.x, datum.y, r, datum.r) + } + + @(static, rodata) + f64_data := [?]Datum(f64) { + {0h3c00000000000000, 0h7ff4200000000000, 0h7ff8000000000001}, // +1 -> +NaN = +canonical NaN + {0h3c00000000000000, 0hfff4200000000000, 0h7ff8000000000001}, // +1 -> -NaN = +canonical NaN + {0hbc00000000000000, 0h7ff4200000000000, 0h7ff8000000000001}, // -1 -> +NaN = +canonical NaN + {0hbc00000000000000, 0hfff4200000000000, 0h7ff8000000000001}, // -1 -> -NaN = +canonical NaN + + {0h7ff4200000000000, 0h3c00000000000000, 0h7ff8000000000001}, // +NaN -> +1 = +canonical NaN + {0hfff4200000000000, 0h3c00000000000000, 0h7ff8000000000001}, // -NaN -> +1 = +canonical NaN + {0h7ff4200000000000, 0hbc00000000000000, 0h7ff8000000000001}, // +NaN -> -1 = +canonical NaN + {0hfff4200000000000, 0hbc00000000000000, 0h7ff8000000000001}, // -NaN -> -1 = +canonical NaN + + {0h0000000000000000, 0h8000000000000000, 0h0000000000000000}, // +0 -> -0 = +0 + {0h0000000000000000, +1, 0h0000000000000001}, // +0 -> +1 = +smallest subnormal + {0h0000000000000000, -1, 0h8000000000000001}, // +0 -> -1 = -smallest subnormal + + {0h0000000000000000, 0h0000000000000000, 0h0000000000000000}, // +0 -> +0 = +0 + {0h0000000000000000, 0h8000000000000000, 0h0000000000000000}, // +0 -> -0 = +0 + {0h0000000000000000, +1, 0h0000000000000001}, // +0 -> +1 = +smallest subnormal + {0h0000000000000000, -1, 0h8000000000000001}, // +0 -> -1 = -smallest subnormal + + {0h8000000000000000, 0h0000000000000000, 0h8000000000000000}, // -0 -> +0 = -0 + {0h8000000000000000, 0h8000000000000000, 0h8000000000000000}, // -0 -> -0 = -0 + {0h8000000000000000, +1, 0h0000000000000001}, // -0 -> +1 = +smallest subnormal + {0h8000000000000000, -1, 0h8000000000000001}, // -0 -> -1 = -smallest subnormal + + {0h0000000000000001, -1, 0h0000000000000000}, // +smallest subnormal -> -1 = +0 + {0h8000000000000001, +1, 0h8000000000000000}, // -smallest subnormal -> +1 = -0 + + {0h03ffffffffffffff, +1, 0h0400000000000000}, // +largest subnormal -> +1 = +smallest normal + {0h0400000000000000, -1, 0h03ffffffffffffff}, // +smallest normal -> -1 = +largest subnormal + {0h83ffffffffffffff, -1, 0h8400000000000000}, // -largest subnormal -> -1 = -smallest normal + {0h8400000000000000, +1, 0h83ffffffffffffff}, // -smallest normal -> +1 = -largest subnormal + + {0h3ff0000000000000, 0, 0h3fefffffffffffff}, // +1 -> 0 = +1-ulp + {0h3ff0000000000000, +1, 0h3ff0000000000000}, // +1 -> +1 = +1 + {0h3ff0000000000000, +2, 0h3ff0000000000001}, // +1 -> +2 = +1+ulp + + {0hbff0000000000000, 0, 0hbfefffffffffffff}, // -1 -> 0 = -1+ulp + {0hbff0000000000000, -1, 0hbff0000000000000}, // -1 -> -1 = -1 + {0hbff0000000000000, -2, 0hbff0000000000001}, // -1 -> +2 = -1-ulp + + {0h3ff0000000000000, 0hfff0000000000000, 0h3fefffffffffffff}, // +1 -> -inf = +1-ulp + {0hbff0000000000000, 0h7ff0000000000000, 0hbfefffffffffffff}, // -1 -> +inf = -1+ulp + + {0h7fefffffffffffff, 0h7ff0000000000000, 0h7ff0000000000000}, // +max -> +inf = +inf + {0h7ff0000000000000, 0h7ff0000000000000, 0h7ff0000000000000}, // +inf -> +inf = +inf + {0h7ff0000000000000, 0, 0h7fefffffffffffff}, // +inf -> 0 = +max + + {0hffefffffffffffff, 0hfff0000000000000, 0hfff0000000000000}, // -max -> -inf = -inf + {0hfff0000000000000, 0hfff0000000000000, 0hfff0000000000000}, // -inf -> -inf = -inf + {0hfff0000000000000, 0, 0hffefffffffffffff}, // -inf -> 0 = -max + } + + for datum in f64_data { + r := math.nextafter_f64(datum.x, datum.y) + testing.expectf(t, + transmute(u64)r == transmute(u64)datum.r, + "%h, %h -> %h != %h", datum.x, datum.y, r, datum.r) + } +} diff --git a/tests/core/mem/test_core_mem.odin b/tests/core/mem/test_core_mem.odin index d282ae1fd..9d64e50a3 100644 --- a/tests/core/mem/test_core_mem.odin +++ b/tests/core/mem/test_core_mem.odin @@ -1,7 +1,10 @@ package test_core_mem +import "core:mem" import "core:mem/tlsf" +import "core:mem/virtual" import "core:testing" +import "core:slice" @test test_tlsf_bitscan :: proc(t: ^testing.T) { @@ -38,4 +41,268 @@ test_tlsf_bitscan :: proc(t: ^testing.T) { testing.expectf(t, res == test.exp, "Expected tlsf.fls_uint(0x%16x) == %v, got %v", test.v, test.exp, res) } } -} \ No newline at end of file +} + +@(test) +test_align_bumping_block_limit :: proc(t: ^testing.T) { + a: virtual.Arena + defer virtual.arena_destroy(&a) + + data, err := virtual.arena_alloc(&a, 4193371, 1) + testing.expect_value(t, err, nil) + testing.expect(t, len(data) == 4193371) + + data, err = virtual.arena_alloc(&a, 896, 64) + testing.expect_value(t, err, nil) + testing.expect(t, len(data) == 896) +} + +@(test) +tlsf_test_overlap_and_zero :: proc(t: ^testing.T) { + default_allocator := context.allocator + alloc: tlsf.Allocator + defer tlsf.destroy(&alloc) + + NUM_ALLOCATIONS :: 1_000 + BACKING_SIZE :: NUM_ALLOCATIONS * (1_000 + size_of(uintptr)) + + if err := tlsf.init_from_allocator(&alloc, default_allocator, BACKING_SIZE); err != .None { + testing.fail_now(t, "TLSF init error") + } + context.allocator = tlsf.allocator(&alloc) + + allocations := make([dynamic][]byte, 0, NUM_ALLOCATIONS, default_allocator) + defer delete(allocations) + + err: mem.Allocator_Error + s: []byte + + for size := 1; err == .None && size <= NUM_ALLOCATIONS; size += 1 { + s, err = make([]byte, size) + append(&allocations, s) + } + + slice.sort_by(allocations[:], proc(a, b: []byte) -> bool { + return uintptr(raw_data(a)) < uintptr(raw_data((b))) + }) + + for i in 0.. bool { + return uintptr(raw_data(a)) < uintptr(raw_data((b))) + }) + + for i in 0..= 10) + + free_all(tlsf.allocator(&alloc)) + + for { + s := make([]byte, ALLOCATION_SIZE) or_break + append(&allocations[1], s) + } + testing.expect(t, len(allocations[1]) >= 10) + + for i in 0..= b_end && b_end >= a_start { + testing.fail_now(t, "Allocations overlapped") + } +} + + +// This merely does a few simple operations to test basic sanity. +// +// A serious test of an allocator would require hooking it up to a benchmark or +// a large, complicated program in order to get all manner of usage patterns. +basic_sanity_test :: proc(t: ^testing.T, allocator: mem.Allocator, limit: int, loc := #caller_location) -> bool { + context.allocator = allocator + + { + a := make([dynamic]u8) + for i in 0..= out_band_size, "Sanity check failed, your test call is flawed! Make sure that num_bytes >= out_band_size!") pool: mem.Dynamic_Pool - mem.dynamic_pool_init(&pool, out_band_size = out_band_size) + mem.dynamic_pool_init(&pool, block_size = block_size, out_band_size = out_band_size) pool_allocator := mem.dynamic_pool_allocator(&pool) element, err := mem.alloc(num_bytes, allocator = pool_allocator) @@ -69,14 +69,15 @@ test_dynamic_pool_alloc_aligned :: proc(t: ^testing.T) { @(test) test_dynamic_pool_alloc_unaligned :: proc(t: ^testing.T) { - expect_pool_allocation(t, expected_used_bytes = 8, num_bytes=1, alignment=8) - expect_pool_allocation(t, expected_used_bytes = 16, num_bytes=9, alignment=8) + expect_pool_allocation(t, expected_used_bytes = 8, num_bytes = 1, alignment = 8) + expect_pool_allocation(t, expected_used_bytes = 16, num_bytes = 9, alignment = 8) } @(test) test_dynamic_pool_alloc_out_of_band :: proc(t: ^testing.T) { - expect_pool_allocation_out_of_band(t, num_bytes = 128, out_band_size = 128) - expect_pool_allocation_out_of_band(t, num_bytes = 129, out_band_size = 128) + expect_pool_allocation_out_of_band(t, num_bytes = 128, block_size = 512, out_band_size = 128) + expect_pool_allocation_out_of_band(t, num_bytes = 129, block_size = 512, out_band_size = 128) + expect_pool_allocation_out_of_band(t, num_bytes = 513, block_size = 512, out_band_size = 128) } @(test) @@ -98,4 +99,4 @@ intentionally_leaky_test :: proc(t: ^testing.T) { leak_verifier :: proc(t: ^testing.T, ta: ^mem.Tracking_Allocator) { testing.expect_value(t, len(ta.allocation_map), 1) testing.expect_value(t, len(ta.bad_free_array), 1) -} \ No newline at end of file +} diff --git a/tests/core/net/test_core_net_freebsd.odin b/tests/core/net/test_core_net_freebsd.odin index 39e364e80..590db7de0 100644 --- a/tests/core/net/test_core_net_freebsd.odin +++ b/tests/core/net/test_core_net_freebsd.odin @@ -17,9 +17,6 @@ import "core:net" import "core:time" import "core:testing" -ENDPOINT_DUPLICATE_BINDING := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 11000} -ENDPOINT_EPIPE_TEST := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 11001} - @test test_duplicate_binding :: proc(t: ^testing.T) { // FreeBSD has the capacity to permit multiple processes and sockets to @@ -35,11 +32,16 @@ test_duplicate_binding :: proc(t: ^testing.T) { if !testing.expect_value(t, err_set1, nil) { return } - err_bind1 := net.bind(tcp_socket1, ENDPOINT_DUPLICATE_BINDING) + err_bind1 := net.bind(tcp_socket1, {net.IP4_Loopback, 0}) if !testing.expect_value(t, err_bind1, nil) { return } + ep, err_bound := net.bound_endpoint(tcp_socket1) + if !testing.expect_value(t, err_bound, nil) { + return + } + raw_socket2, err_create2 := net.create_socket(.IP4, .TCP) if !testing.expect_value(t, err_create2, nil) { return @@ -50,7 +52,7 @@ test_duplicate_binding :: proc(t: ^testing.T) { if !testing.expect_value(t, err_set2, nil) { return } - err_bind2 := net.bind(tcp_socket2, ENDPOINT_DUPLICATE_BINDING) + err_bind2 := net.bind(tcp_socket2, ep) if !testing.expect_value(t, err_bind2, nil) { return } @@ -60,13 +62,18 @@ test_duplicate_binding :: proc(t: ^testing.T) { test_sigpipe_bypass :: proc(t: ^testing.T) { // If the internals aren't working as expected, this test will fail by raising SIGPIPE. - server_socket, listen_err := net.listen_tcp(ENDPOINT_EPIPE_TEST) + server_socket, listen_err := net.listen_tcp({net.IP4_Loopback, 0}) if !testing.expect_value(t, listen_err, nil) { return } defer net.close(server_socket) - client_socket, dial_err := net.dial_tcp(ENDPOINT_EPIPE_TEST) + ep, bound_err := net.bound_endpoint(server_socket) + if !testing.expect_value(t, bound_err, nil) { + return + } + + client_socket, dial_err := net.dial_tcp(ep) if !testing.expect_value(t, dial_err, nil) { return } @@ -80,7 +87,7 @@ test_sigpipe_bypass :: proc(t: ^testing.T) { data := "Hellope!" bytes_written, err_send := net.send(client_socket, transmute([]u8)data) - if !testing.expect_value(t, err_send, net.TCP_Send_Error.Cannot_Send_More_Data) { + if !testing.expect_value(t, err_send, net.TCP_Send_Error.Connection_Closed) { return } if !testing.expect_value(t, bytes_written, 0) { diff --git a/tests/core/normal.odin b/tests/core/normal.odin index 5bc73bd24..fe69acf64 100644 --- a/tests/core/normal.odin +++ b/tests/core/normal.odin @@ -3,9 +3,9 @@ package tests_core import rlibc "core:c/libc" @(init) -download_assets :: proc() { +download_assets :: proc "contextless" () { if rlibc.system("python3 " + ODIN_ROOT + "tests/core/download_assets.py " + ODIN_ROOT + "tests/core/assets") != 0 { - panic("downloading test assets failed!") + panic_contextless("downloading test assets failed!") } } diff --git a/tests/core/odin/test_parser.odin b/tests/core/odin/test_parser.odin index b4310104f..cc180f9af 100644 --- a/tests/core/odin/test_parser.odin +++ b/tests/core/odin/test_parser.odin @@ -66,3 +66,31 @@ Foo :: bit_field uint { ok := parser.parse_file(&p, &file) testing.expect(t, ok, "bad parse") } + +@test +test_parse_parser :: proc(t: ^testing.T) { + context.allocator = context.temp_allocator + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + pkg, ok := parser.parse_package_from_path(ODIN_ROOT + "core/odin/parser") + + testing.expect(t, ok, "parser.parse_package_from_path failed") + + for key, value in pkg.files { + testing.expectf(t, value.syntax_error_count == 0, "%v should contain zero errors", key) + } +} + +@test +test_parse_stb_image :: proc(t: ^testing.T) { + context.allocator = context.temp_allocator + runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() + + pkg, ok := parser.parse_package_from_path(ODIN_ROOT + "vendor/stb/image") + + testing.expect(t, ok, "parser.parse_package_from_path failed") + + for key, value in pkg.files { + testing.expectf(t, value.syntax_error_count == 0, "%v should contain zero errors", key) + } +} diff --git a/tests/core/os/os2/dir.odin b/tests/core/os/os2/dir.odin index 7077e9ae2..8ef333219 100644 --- a/tests/core/os/os2/dir.odin +++ b/tests/core/os/os2/dir.odin @@ -2,27 +2,27 @@ package tests_core_os_os2 import os "core:os/os2" import "core:log" -import "core:path/filepath" import "core:slice" import "core:testing" import "core:strings" @(test) test_read_dir :: proc(t: ^testing.T) { - path := filepath.join({#directory, "../dir"}) + path, err_join := os.join_path({#directory, "../dir"}, context.allocator) defer delete(path) - fis, err := os.read_all_directory_by_path(path, context.allocator) + fis, err_read := os.read_all_directory_by_path(path, context.allocator) defer os.file_info_slice_delete(fis, context.allocator) slice.sort_by_key(fis, proc(fi: os.File_Info) -> string { return fi.name }) - if err == .Unsupported { + if err_read == .Unsupported { log.warn("os2 directory functionality is unsupported, skipping test") return } - testing.expect_value(t, err, nil) + testing.expect_value(t, err_join, nil) + testing.expect_value(t, err_read, nil) testing.expect_value(t, len(fis), 2) testing.expect_value(t, fis[0].name, "b.txt") @@ -34,8 +34,9 @@ test_read_dir :: proc(t: ^testing.T) { @(test) test_walker :: proc(t: ^testing.T) { - path := filepath.join({#directory, "../dir"}) + path, err := os.join_path({#directory, "../dir"}, context.allocator) defer delete(path) + testing.expect_value(t, err, nil) w := os.walker_create(path) defer os.walker_destroy(&w) @@ -45,11 +46,12 @@ test_walker :: proc(t: ^testing.T) { @(test) test_walker_file :: proc(t: ^testing.T) { - path := filepath.join({#directory, "../dir"}) + path, err_join := os.join_path({#directory, "../dir"}, context.allocator) defer delete(path) + testing.expect_value(t, err_join, nil) - f, err := os.open(path) - testing.expect_value(t, err, nil) + f, err_open := os.open(path) + testing.expect_value(t, err_open, nil) defer os.close(f) w := os.walker_create(f) @@ -64,10 +66,18 @@ test_walker_internal :: proc(t: ^testing.T, w: ^os.Walker) { path: string, } + joined_1, err_joined_1 := os.join_path({"dir", "b.txt"}, context.allocator) + joined_2, err_joined_2 := os.join_path({"dir", "sub"}, context.allocator) + joined_3, err_joined_3 := os.join_path({"dir", "sub", ".gitkeep"}, context.allocator) + + testing.expect_value(t, err_joined_1, nil) + testing.expect_value(t, err_joined_2, nil) + testing.expect_value(t, err_joined_3, nil) + expected := [?]Seen{ - {.Regular, filepath.join({"dir", "b.txt"})}, - {.Directory, filepath.join({"dir", "sub"})}, - {.Regular, filepath.join({"dir", "sub", ".gitkeep"})}, + {.Regular, joined_1}, + {.Directory, joined_2}, + {.Regular, joined_3}, } seen: [dynamic]Seen diff --git a/tests/core/os/os2/file.odin b/tests/core/os/os2/file.odin index c4df74f4a..0152a2008 100644 --- a/tests/core/os/os2/file.odin +++ b/tests/core/os/os2/file.odin @@ -2,11 +2,13 @@ package tests_core_os_os2 import os "core:os/os2" import "core:testing" -import "core:path/filepath" @(test) test_clone :: proc(t: ^testing.T) { - f, err := os.open(filepath.join({#directory, "file.odin"}, context.temp_allocator)) + joined, err := os.join_path({#directory, "file.odin"}, context.temp_allocator) + testing.expect_value(t, err, nil) + f: ^os.File + f, err = os.open(joined) testing.expect_value(t, err, nil) testing.expect(t, f != nil) diff --git a/tests/core/os/os2/path.odin b/tests/core/os/os2/path.odin index b91f43368..7b1cb0146 100644 --- a/tests/core/os/os2/path.odin +++ b/tests/core/os/os2/path.odin @@ -2,7 +2,6 @@ package tests_core_os_os2 import os "core:os/os2" import "core:log" -import "core:path/filepath" import "core:testing" import "core:strings" @@ -17,6 +16,362 @@ test_executable :: proc(t: ^testing.T) { testing.expect_value(t, err, nil) testing.expect(t, len(path) > 0) - testing.expect(t, filepath.is_abs(path)) - testing.expectf(t, strings.contains(path, filepath.base(os.args[0])), "expected the executable path to contain the base of os.args[0] which is %q", filepath.base(os.args[0])) + testing.expect(t, os.is_absolute_path(path)) + _, filename := os.split_path(os.args[0]) + testing.expectf(t, strings.contains(path, filename), "expected the executable path to contain the base of os.args[0] which is %q", filename) +} + +posix_to_dos_path :: proc(path: string) -> string { + if len(path) == 0 { + return path + } + path := path + path, _ = strings.replace_all(path, `/`, `\`, context.temp_allocator) + if path[0] == '\\' { + path = strings.concatenate({"C:", path}, context.temp_allocator) + } + return path +} + +@(test) +test_clean_path :: proc(t: ^testing.T) { + Test_Case :: struct{ + path: string, + expected: string, + } + + when ODIN_OS == .Windows { + test_cases := [?]Test_Case { + {`W:/odin\examples\demo/demo.odin`, `W:\odin\examples\demo\demo.odin`}, + {`\\server\share\path\file.ext`, `\\server\share\path\file.ext`}, + {`//server\share/path\file.ext`, `\\server\share\path\file.ext`}, + {`/\192.168.0.10\share/path\file.ext`, `\\192.168.0.10\share\path\file.ext`}, + {`\\?\C:/Users/Foo/path\file.ext`, `\\?\C:\Users\Foo\path\file.ext`}, + {`\\?\\localhost\share\file.ext`, `\\?\\localhost\share\file.ext`}, + {`//?\/192.168.0.10\share\file.ext`, `\\?\\192.168.0.10\share\file.ext`}, + {`\\.\PhysicalDrive3`, `\\.\PhysicalDrive3`}, + {`/\./PhysicalDrive3`, `\\.\PhysicalDrive3`}, + {`C:\a\..\..`, `C:\`}, + {`C:\a\..`, `C:\`}, + {`C:\あ/a/..`, `C:\あ`}, + {`C:\あ/a/../あ`, `C:\あ\あ`}, + } + } else { + test_cases := [?]Test_Case { + {`../../foo/../../`, `../../..`}, + {`../../foo/..`, `../..`}, + {`../../foo`, `../../foo`}, + {`../..`, `../..`}, + {`.././foo`, `../foo`}, + {`..`, `..`}, + {`.`, `.`}, + {`.foo`, `.foo`}, + {`/../../foo/../../`, `/`}, + {`/../`, `/`}, + {`/..`, `/`}, + {`/`, `/`}, + {`//home/foo/bar/../../`, `/home`}, + {`/a/../..`, `/`}, + {`/a/../`, `/`}, + {`/a/あ`, `/a/あ`}, + {`/a/あ/..`, `/a`}, + {`/あ/a/..`, `/あ`}, + {`/あ/a/../あ`, `/あ/あ`}, + {`/home/../`, `/`}, + {`/home/..`, `/`}, + {`/home/foo/../../usr`, `/usr`}, + {`/home/foo/../..`, `/`}, + {`/home/foo/../`, `/home`}, + {``, `.`}, + {`a/..`, `.`}, + {`a`, `a`}, + {`abc//.//../foo`, `foo`}, + {`foo`, `foo`}, + {`home/foo/bar/../../`, `home`}, + } + } + + for tc in test_cases { + joined, err := os.clean_path(tc.path, context.temp_allocator) + testing.expectf(t, joined == tc.expected && err == nil, "expected clean_path(%q) -> %q; got: %q, %v", tc.path, tc.expected, joined, err) + } +} + +@(test) +test_is_absolute_path :: proc(t: ^testing.T) { + when ODIN_OS == .Windows { + testing.expect(t, os.is_absolute_path(`C:\Windows`)) + } else { + testing.expect(t, os.is_absolute_path("/home")) + } + testing.expect(t, !os.is_absolute_path("home")) +} + +@(test) +test_get_relative_path :: proc(t: ^testing.T) { + Test_Case :: struct { + base, target: string, + expected: string, + } + + Fail_Case :: struct { + base, target: string, + } + + test_cases := [?]Test_Case { + {"", "foo", "foo"}, + {".", "foo", "foo"}, + {"/", "/", "."}, + {"/", "/home/alice/bert", "home/alice/bert"}, + {"/a", "/b", "../b"}, + {"/あ", "/あ/a", "a"}, + {"/a", "/a/あ", "あ"}, + {"/あ", "/い", "../い"}, + {"/a", "/usr", "../usr"}, + {"/home", "/", ".."}, + {"/home", "/home/alice/bert", "alice/bert"}, + {"/home/foo", "/", "../.."}, + {"/home/foo", "/home", ".."}, + {"/home/foo", "/home/alice/bert", "../alice/bert"}, + {"/home/foo", "/home/foo", "."}, + {"/home/foo", "/home/foo/bar", "bar"}, + {"/home/foo/bar", "/home", "../.."}, + {"/home/foo/bar", "/home/alice/bert", "../../alice/bert"}, + {"/home/foo/bar/bert", "/home/alice/bert", "../../../alice/bert"}, + {"/www", "/mount", "../mount"}, + {"foo", ".", ".."}, + {"foo", "bar", "../bar"}, + {"foo", "bar", "../bar"}, + {"foo", "../bar", "../../bar"}, + {"foo", "foo", "."}, + {"foo", "foo/bar", "bar"}, + {"home/foo/bar", "home/alice/bert", "../../alice/bert"}, + } + + fail_cases := [?]Fail_Case { + {"", "/home"}, + {"/home", ""}, + {"..", ""}, + } + + when ODIN_OS == .Windows { + for &tc in test_cases { + tc.base = posix_to_dos_path(tc.base) + tc.target = posix_to_dos_path(tc.target) + // Make one part all capitals to test case-insensitivity. + tc.target = strings.to_upper(tc.target, context.temp_allocator) + tc.expected = posix_to_dos_path(tc.expected) + } + for &tc in fail_cases { + tc.base = posix_to_dos_path(tc.base) + tc.target = posix_to_dos_path(tc.target) + } + } + + for tc in test_cases { + result, err := os.get_relative_path(tc.base, tc.target, context.temp_allocator) + joined, err2 := os.join_path({tc.base, result}, context.temp_allocator) + + when ODIN_OS == .Windows { + passed := strings.equal_fold(result, tc.expected) && err == nil + join_guaranteed := strings.equal_fold(joined, tc.target) && err2 == nil + } else { + passed := result == tc.expected && err == nil + join_guaranteed := joined == tc.target && err2 == nil + } + testing.expectf(t, passed, "expected get_relative_path(%q, %q) -> %q; got %q, %v", tc.base, tc.target, tc.expected, result, err) + testing.expectf(t, join_guaranteed, "join_path({{%q, %q}}) guarantee of get_relative_path(%q, %q) failed; got %q, %v instead", tc.base, result, tc.base, tc.target, joined, err2) + } + + for tc in fail_cases { + result, err := os.get_relative_path(tc.base, tc.target, context.temp_allocator) + testing.expectf(t, result == "" && err != nil, "expected get_relative_path(%q, %q) to fail, got %q, %v", tc.base, tc.target, result, err) + } +} + +@(test) +test_split_path :: proc(t: ^testing.T) { + Test_Case :: struct { + path: string, + dir, filename: string, + } + + test_cases := [?]Test_Case { + { "", "", "" }, + { "/", "/", "" }, + { "/a", "/", "a" }, + { "readme.txt", "", "readme.txt" }, + { "/readme.txt", "/", "readme.txt" }, + { "/var/readme.txt", "/var", "readme.txt" }, + { "/home/foo/bar.tar.gz", "/home/foo", "bar.tar.gz" }, + } + + when ODIN_OS == .Windows { + for &tc in test_cases { + tc.path = posix_to_dos_path(tc.path) + tc.dir = posix_to_dos_path(tc.dir) + tc.filename = posix_to_dos_path(tc.filename) + } + } + + for tc in test_cases { + dir, filename := os.split_path(tc.path) + testing.expectf(t, dir == tc.dir && filename == tc.filename, "expected split_path(%q) -> %q, %q; got: %q, %q", tc.path, tc.dir, tc.filename, dir, filename) + } +} + +@(test) +test_join_path :: proc(t: ^testing.T) { + Test_Case :: struct { + elems: []string, + expected: string, + } + + test_cases := [?]Test_Case { + { {"" }, "" }, + { {"/" }, "/" }, + { {"home" }, "home" }, + { {"home", "" }, "home" }, + { {"/home", "" }, "/home" }, + { {"", "home" }, "home" }, + { {"", "/home" }, "/home" }, + { {"", "/home", "", "foo" }, "/home/foo" }, + { {"", "home", "", "", "foo", "" }, "home/foo" }, + } + + when ODIN_OS == .Windows { + for &tc in test_cases { + for &elem in tc.elems { + elem = posix_to_dos_path(elem) + } + tc.expected = posix_to_dos_path(tc.expected) + } + } + + for tc in test_cases { + result, err := os.join_path(tc.elems, context.temp_allocator) + testing.expectf(t, result == tc.expected && err == nil, "expected join_path(%v) -> %q; got: %q, %v", tc.elems, tc.expected, result, err) + } +} + +@(test) +test_split_filename :: proc(t: ^testing.T) { + Test_Case :: struct { + filename: string, + base, ext: string, + } + + test_cases := [?]Test_Case { + {"", "", ""}, + {"a", "a", ""}, + {".", ".", ""}, + {".a", ".a", ""}, + {".foo", ".foo", ""}, + {".foo.txt", ".foo", "txt"}, + {"a.b", "a", "b"}, + {"foo", "foo", ""}, + {"readme.txt", "readme", "txt"}, + {"pkg.tar.gz", "pkg.tar", "gz"}, + // Assert API ignores directory hierarchies: + {"dir/FILE.TXT", "dir/FILE", "TXT"}, + } + + for tc in test_cases { + base, ext := os.split_filename(tc.filename) + testing.expectf(t, base == tc.base && ext == tc.ext, "expected split_filename(%q) -> %q, %q; got: %q, %q", tc.filename, tc.base, tc.ext, base, ext) + } +} + +@(test) +test_split_filename_all :: proc(t: ^testing.T) { + Test_Case :: struct { + filename: string, + base, ext: string, + } + + test_cases := [?]Test_Case { + {"", "", ""}, + {"a", "a", ""}, + {".", ".", ""}, + {".a", ".a", ""}, + {".foo", ".foo", ""}, + {".foo.txt", ".foo", "txt"}, + {"a.b", "a", "b"}, + {"foo", "foo", ""}, + {"readme.txt", "readme", "txt"}, + {"pkg.tar.gz", "pkg", "tar.gz"}, + // Assert API ignores directory hierarchies: + {"dir/FILE.TXT", "dir/FILE", "TXT"}, + } + + for tc in test_cases { + base, ext := os.split_filename_all(tc.filename) + testing.expectf(t, base == tc.base && ext == tc.ext, "expected split_filename_all(%q) -> %q, %q; got: %q, %q", tc.filename, tc.base, tc.ext, base, ext) + } +} + +@(test) +test_join_filename :: proc(t: ^testing.T) { + Test_Case :: struct { + base, ext: string, + expected: string, + } + + test_cases := [?]Test_Case { + {"", "", ""}, + {"", "foo", "foo"}, + {"foo", "", "foo"}, + {"readme", "txt", "readme.txt"}, + {"pkg.tar", "gz", "pkg.tar.gz"}, + {"pkg", "tar.gz", "pkg.tar.gz"}, + // Assert API ignores directory hierarchies: + {"dir/FILE", "TXT", "dir/FILE.TXT"}, + } + + for tc in test_cases { + result, err := os.join_filename(tc.base, tc.ext, context.temp_allocator) + testing.expectf(t, result == tc.expected && err == nil, "expected join_filename(%q, %q) -> %q; got: %q, %v", tc.base, tc.ext, tc.expected, result, err) + } +} + +@(test) +test_split_path_list :: proc(t: ^testing.T) { + Test_Case :: struct { + path_list: string, + expected: []string, + } + + when ODIN_OS != .Windows { + test_cases := [?]Test_Case { + {``, {}}, + {`/bin:`, {`/bin`, ``}}, + {`/usr/local/bin`, {`/usr/local/bin`}}, + {`/usr/local/bin:/usr/bin`, {`/usr/local/bin`, `/usr/bin`}}, + {`"/extra bin":/bin`, {`/extra bin`, `/bin`}}, + {`"/extra:bin":/bin`, {`/extra:bin`, `/bin`}}, + } + } else { + test_cases := [?]Test_Case { + {``, {}}, + {`C:\bin;`, {`C:\bin`, ``}}, + {`C:\usr\local\bin`, {`C:\usr\local\bin`}}, + {`C:\usr\local\bin;C:\usr\bin`, {`C:\usr\local\bin`, `C:\usr\bin`}}, + {`"C:\extra bin";C:\bin`, {`C:\extra bin`, `C:\bin`}}, + {`"C:\extra;bin";C:\bin`, {`C:\extra;bin`, `C:\bin`}}, + } + } + + for tc in test_cases { + result, err := os.split_path_list(tc.path_list, context.temp_allocator) + if testing.expectf(t, len(result) == len(tc.expected), "expected split_path_list(%q) -> %v; got %v, %v", tc.path_list, tc.expected, result, err) { + ok := true + for entry, i in result { + if entry != tc.expected[i] { + ok = false + break + } + } + testing.expectf(t, ok, "expected split_path_list(%q) -> %v; got %v, %v", tc.path_list, tc.expected, result, err) + } + } } diff --git a/tests/core/os/os2/process.odin b/tests/core/os/os2/process.odin index d7700d201..c530b4c79 100644 --- a/tests/core/os/os2/process.odin +++ b/tests/core/os/os2/process.odin @@ -1,3 +1,4 @@ +#+build !windows package tests_core_os_os2 import os "core:os/os2" diff --git a/tests/core/reflect/test_core_reflect.odin b/tests/core/reflect/test_core_reflect.odin index 7d2394688..bc2d01a4a 100644 --- a/tests/core/reflect/test_core_reflect.odin +++ b/tests/core/reflect/test_core_reflect.odin @@ -1,6 +1,7 @@ // Tests "core:reflect/reflect". package test_core_reflect +import "base:intrinsics" import "core:reflect" import "core:testing" @@ -260,4 +261,74 @@ test_as_f64 :: proc(t: ^testing.T) { testing.expectf(t, r == d.e, "f64 %v -> %v != %v", d.v, r, d.e) } } +} + +@test +test_simd_vectors :: proc(t: ^testing.T) { + { + V :: #simd[2]u64 + v: V + E := typeid_of(u64) + + testing.expect(t, typeid_of(intrinsics.type_elem_type(V)) == E) + testing.expect(t, reflect.typeid_elem(V) == E) + testing.expect(t, reflect.length(v) == len(V)) + testing.expect(t, reflect.capacity(v) == cap(V)) + testing.expect(t, reflect.length(v) == 2) + } + { + V :: #simd[4]f32 + v: V + E := typeid_of(f32) + + testing.expect(t, typeid_of(intrinsics.type_elem_type(V)) == E) + testing.expect(t, reflect.typeid_elem(V) == E) + testing.expect(t, reflect.length(v) == len(V)) + testing.expect(t, reflect.capacity(v) == cap(V)) + testing.expect(t, reflect.length(v) == 4) + } + { + V :: #simd[8]i16 + v: V + E := typeid_of(i16) + + testing.expect(t, typeid_of(intrinsics.type_elem_type(V)) == E) + testing.expect(t, reflect.typeid_elem(V) == E) + testing.expect(t, reflect.length(v) == len(V)) + testing.expect(t, reflect.capacity(v) == cap(V)) + testing.expect(t, reflect.length(v) == 8) + } + { + V :: #simd[16]u32 + v: V + E := typeid_of(u32) + + testing.expect(t, typeid_of(intrinsics.type_elem_type(V)) == E) + testing.expect(t, reflect.typeid_elem(V) == E) + testing.expect(t, reflect.length(v) == len(V)) + testing.expect(t, reflect.capacity(v) == cap(V)) + testing.expect(t, reflect.length(v) == 16) + } + { + V :: #simd[32]u16 + v: V + E := typeid_of(u16) + + testing.expect(t, typeid_of(intrinsics.type_elem_type(V)) == E) + testing.expect(t, reflect.typeid_elem(V) == E) + testing.expect(t, reflect.length(v) == len(V)) + testing.expect(t, reflect.capacity(v) == cap(V)) + testing.expect(t, reflect.length(v) == 32) + } + { + V :: #simd[64]i8 + v: V + E := typeid_of(i8) + + testing.expect(t, typeid_of(intrinsics.type_elem_type(V)) == E) + testing.expect(t, reflect.typeid_elem(V) == E) + testing.expect(t, reflect.length(v) == len(V)) + testing.expect(t, reflect.capacity(v) == cap(V)) + testing.expect(t, reflect.length(v) == 64) + } } \ No newline at end of file diff --git a/tests/core/runtime/test_core_runtime.odin b/tests/core/runtime/test_core_runtime.odin index be6c24c72..881b5f41a 100644 --- a/tests/core/runtime/test_core_runtime.odin +++ b/tests/core/runtime/test_core_runtime.odin @@ -4,6 +4,7 @@ package test_core_runtime import "base:intrinsics" import "core:mem" import "base:runtime" +import "core:slice" import "core:testing" // Tests that having space for the allocation, but not for the allocation and alignment @@ -31,6 +32,21 @@ test_temp_allocator_big_alloc_and_alignment :: proc(t: ^testing.T) { testing.expect(t, err == nil) } +@(test) +test_align_bumping_block_limit :: proc(t: ^testing.T) { + a: runtime.Arena + a.minimum_block_size = 8*mem.Megabyte + defer runtime.arena_destroy(&a) + + data, err := runtime.arena_alloc(&a, 4193371, 1) + testing.expect_value(t, err, nil) + testing.expect(t, len(data) == 4193371) + + data, err = runtime.arena_alloc(&a, 896, 64) + testing.expect_value(t, err, nil) + testing.expect(t, len(data) == 896) +} + @(test) test_temp_allocator_returns_correct_size :: proc(t: ^testing.T) { arena: runtime.Arena @@ -44,26 +60,26 @@ test_temp_allocator_returns_correct_size :: proc(t: ^testing.T) { @(test) test_init_cap_map_dynarray :: proc(t: ^testing.T) { - m1 := make(map[int]string) - defer delete(m1) - testing.expect(t, cap(m1) == 0) - testing.expect(t, m1.allocator.procedure == context.allocator.procedure) + m1 := make(map[int]string) + defer delete(m1) + testing.expect(t, cap(m1) == 0) + testing.expect(t, m1.allocator.procedure == context.allocator.procedure) - ally := context.temp_allocator - m2 := make(map[int]string, ally) - defer delete(m2) - testing.expect(t, cap(m2) == 0) - testing.expect(t, m2.allocator.procedure == ally.procedure) + ally := context.temp_allocator + m2 := make(map[int]string, ally) + defer delete(m2) + testing.expect(t, cap(m2) == 0) + testing.expect(t, m2.allocator.procedure == ally.procedure) - d1 := make([dynamic]string) - defer delete(d1) - testing.expect(t, cap(d1) == 0) - testing.expect(t, d1.allocator.procedure == context.allocator.procedure) + d1 := make([dynamic]string) + defer delete(d1) + testing.expect(t, cap(d1) == 0) + testing.expect(t, d1.allocator.procedure == context.allocator.procedure) - d2 := make([dynamic]string, ally) - defer delete(d2) - testing.expect(t, cap(d2) == 0) - testing.expect(t, d2.allocator.procedure == ally.procedure) + d2 := make([dynamic]string, ally) + defer delete(d2) + testing.expect(t, cap(d2) == 0) + testing.expect(t, d2.allocator.procedure == ally.procedure) } @(test) @@ -162,3 +178,191 @@ test_map_get :: proc(t: ^testing.T) { check(t, m) } } + +@(test) +test_soa_array_resize :: proc(t: ^testing.T) { + + V :: struct {x: int, y: u8} + + array := make(#soa[dynamic]V, 0, 2) + defer delete(array) + + append(&array, V{1, 2}, V{3, 4}) + + testing.expect_value(t, len(array), 2) + testing.expect_value(t, array[0], V{1, 2}) + testing.expect_value(t, array[1], V{3, 4}) + + resize(&array, 1) + + testing.expect_value(t, len(array), 1) + testing.expect_value(t, array[0], V{1, 2}) + + resize(&array, 2) + + testing.expect_value(t, len(array), 2) + testing.expect_value(t, array[0], V{1, 2}) + testing.expect_value(t, array[1], V{0, 0}) + + resize(&array, 0) + resize(&array, 3) + + testing.expect_value(t, len(array), 3) + testing.expect_value(t, array[0], V{0, 0}) + testing.expect_value(t, array[1], V{0, 0}) + testing.expect_value(t, array[2], V{0, 0}) +} + +@(test) +test_soa_make_len :: proc(t: ^testing.T) { + + array, err := make(#soa[dynamic][2]int, 2) + defer delete(array) + array[0] = [2]int{1, 2} + array[1] = [2]int{3, 4} + + testing.expect_value(t, err, nil) + testing.expect_value(t, len(array), 2) + testing.expect_value(t, cap(array), 2) + + testing.expect_value(t, array[0], [2]int{1, 2}) + testing.expect_value(t, array[1], [2]int{3, 4}) +} + +@(test) +test_soa_array_allocator_resize :: proc(t: ^testing.T) { + + arena: runtime.Arena + context.allocator = runtime.arena_allocator(&arena) + defer runtime.arena_destroy(&arena) + + // |1 3 _ 2 4 _| + // |1 3 _ _ 2 4 _ _| + + array, err := make(#soa[dynamic][2]int, 2, 3) + defer delete(array) + array[0] = [2]int{1, 2} + array[1] = [2]int{3, 4} + + testing.expect_value(t, err, nil) + testing.expect_value(t, len(array), 2) + testing.expect_value(t, cap(array), 3) + + err = resize(&array, 4) + + testing.expect_value(t, err, nil) + testing.expect_value(t, len(array), 4) + testing.expect_value(t, cap(array), 4) + + testing.expect_value(t, array[0], [2]int{1, 2}) + testing.expect_value(t, array[1], [2]int{3, 4}) + testing.expect_value(t, array[2], [2]int{0, 0}) + testing.expect_value(t, array[3], [2]int{0, 0}) +} + + +@(test) +test_soa_array_allocator_resize_overlapping :: proc(t: ^testing.T) { + + arena: runtime.Arena + context.allocator = runtime.arena_allocator(&arena) + defer runtime.arena_destroy(&arena) + + // |1 4 2 5 3 6| + // |1 4 _ _ 2 5 _ _ 3 6 _ _| + + array, err := make(#soa[dynamic][3]int, 2, 2) + defer delete(array) + array[0] = [3]int{1, 2, 3} + array[1] = [3]int{4, 5, 6} + + testing.expect_value(t, err, nil) + testing.expect_value(t, len(array), 2) + testing.expect_value(t, cap(array), 2) + + err = resize(&array, 4) + + testing.expect_value(t, err, nil) + testing.expect_value(t, len(array), 4) + testing.expect_value(t, cap(array), 4) + + testing.expect_value(t, array[0], [3]int{1, 2, 3}) + testing.expect_value(t, array[1], [3]int{4, 5, 6}) + testing.expect_value(t, array[2], [3]int{0, 0, 0}) + testing.expect_value(t, array[3], [3]int{0, 0, 0}) +} + +@(test) +test_memory_equal :: proc(t: ^testing.T) { + data: [256]u8 + cmp: [256]u8 + + slice.fill(data[:], 0xAA) + slice.fill(cmp[:], 0xAA) + + for offset in 0.. (n: int) { + _len := min(len(a), len(b)) + + // Scan for matches including partial codepoints. + #no_bounds_check for n < _len && a[n] == b[n] { + n += 1 + } + + // Now scan to ignore partial codepoints. + if n > 0 { + s := a[:n] + n = 0 + for { + r0, w := utf8.decode_rune(s[n:]) + if r0 != utf8.RUNE_ERROR { + n += w + } else { + break + } + } + } + return + } + + cases := [][2]string{ + {"Hellope, there!", "Hellope, world!"}, + {"Hellope, there!", "Foozle"}, + {"Hellope, there!", "Hell"}, + {"Hellope! 🦉", "Hellope! 🦉"}, + } + + for v in cases { + p_scalar := prefix_length(v[0], v[1]) + p_simd := strings.prefix_length(v[0], v[1]) + testing.expect_value(t, p_simd, p_scalar) + + s := v[0] + for len(s) > 0 { + p_scalar = prefix_length(v[0], s) + p_simd = strings.prefix_length(v[0], s) + testing.expect_value(t, p_simd, p_scalar) + s = s[:len(s) - 1] + } + } +} \ No newline at end of file diff --git a/tests/core/sync/chan/test_core_sync_chan.odin b/tests/core/sync/chan/test_core_sync_chan.odin index 9b8d9b354..8ede19c7d 100644 --- a/tests/core/sync/chan/test_core_sync_chan.odin +++ b/tests/core/sync/chan/test_core_sync_chan.odin @@ -4,6 +4,7 @@ import "base:runtime" import "base:intrinsics" import "core:log" import "core:math/rand" +import "core:sync" import "core:sync/chan" import "core:testing" import "core:thread" @@ -33,18 +34,16 @@ Comm :: struct { BUFFER_SIZE :: 8 MAX_RAND :: 32 FAIL_TIME :: 1 * time.Second -SLEEP_TIME :: 1 * time.Millisecond + +// Synchronizes try_select tests that require access to global state. +test_lock: sync.Mutex +__global_context_for_test: rawptr comm_client :: proc(th: ^thread.Thread) { data := cast(^Comm)th.data - manual_buffering := data.manual_buffering n: i64 - for manual_buffering && !chan.can_recv(data.host) { - thread.yield() - } - recv_loop: for msg in chan.recv(data.host) { #partial switch msg.type { case .Add: n += msg.i @@ -56,14 +55,6 @@ comm_client :: proc(th: ^thread.Thread) { case: panic("Unknown message type for client.") } - - for manual_buffering && !chan.can_recv(data.host) { - thread.yield() - } - } - - for manual_buffering && !chan.can_send(data.host) { - thread.yield() } chan.send(data.client, Message{.Result, n}) @@ -72,9 +63,6 @@ comm_client :: proc(th: ^thread.Thread) { send_messages :: proc(t: ^testing.T, host: chan.Chan(Message), manual_buffering: bool = false) -> (expected: i64) { expected = 1 - for manual_buffering && !chan.can_send(host) { - thread.yield() - } chan.send(host, Message{.Add, 1}) log.debug(Message{.Add, 1}) @@ -96,9 +84,6 @@ send_messages :: proc(t: ^testing.T, host: chan.Chan(Message), manual_buffering: expected /= msg.i } - for manual_buffering && !chan.can_send(host) { - thread.yield() - } if manual_buffering { testing.expect(t, chan.len(host) == 0) } @@ -107,9 +92,6 @@ send_messages :: proc(t: ^testing.T, host: chan.Chan(Message), manual_buffering: log.debug(msg) } - for manual_buffering && !chan.can_send(host) { - thread.yield() - } chan.send(host, Message{.End, 0}) log.debug(Message{.End, 0}) chan.close(host) @@ -148,18 +130,15 @@ test_chan_buffered :: proc(t: ^testing.T) { expected := send_messages(t, comm.host, manual_buffering = false) - // Sleep so we can give the other thread enough time to buffer its message. - time.sleep(SLEEP_TIME) - - testing.expect_value(t, chan.len(comm.client), 1) - result, ok := chan.try_recv(comm.client) - - // One more sleep to ensure it has enough time to close. - time.sleep(SLEEP_TIME) - - testing.expect_value(t, chan.is_closed(comm.client), true) + result, ok := chan.recv(comm.client) testing.expect_value(t, ok, true) testing.expect_value(t, result.i, expected) + + // Wait for channel to close. + _, ok = chan.recv(comm.client) + testing.expect(t, !ok, "channel should have been closed") + + testing.expect_value(t, chan.is_closed(comm.client), true) log.debug(result, expected) // Make sure sending to closed channels fails. @@ -171,6 +150,8 @@ test_chan_buffered :: proc(t: ^testing.T) { _, ok = chan.recv(comm.client); testing.expect_value(t, ok, false) _, ok = chan.try_recv(comm.host); testing.expect_value(t, ok, false) _, ok = chan.try_recv(comm.client); testing.expect_value(t, ok, false) + + thread.join(reckoner) } @test @@ -193,6 +174,10 @@ test_chan_unbuffered :: proc(t: ^testing.T) { testing.expect(t, !chan.is_buffered(comm.client)) testing.expect(t, chan.is_unbuffered(comm.host)) testing.expect(t, chan.is_unbuffered(comm.client)) + testing.expect(t, !chan.can_send(comm.host)) + testing.expect(t, !chan.can_send(comm.client)) + testing.expect(t, !chan.can_recv(comm.host)) + testing.expect(t, !chan.can_recv(comm.client)) testing.expect_value(t, chan.len(comm.host), 0) testing.expect_value(t, chan.len(comm.client), 0) testing.expect_value(t, chan.cap(comm.host), 0) @@ -203,25 +188,16 @@ test_chan_unbuffered :: proc(t: ^testing.T) { reckoner.data = &comm thread.start(reckoner) - for !chan.can_send(comm.client) { - thread.yield() - } - expected := send_messages(t, comm.host) testing.expect_value(t, chan.is_closed(comm.host), true) - for !chan.can_recv(comm.client) { - thread.yield() - } - - result, ok := chan.try_recv(comm.client) + result, ok := chan.recv(comm.client) testing.expect_value(t, ok, true) testing.expect_value(t, result.i, expected) log.debug(result, expected) - // Sleep so we can give the other thread enough time to close its side - // after we've received its message. - time.sleep(SLEEP_TIME) + _, ok2 := chan.recv(comm.client) + testing.expect(t, !ok2, "read of closed channel should return false") testing.expect_value(t, chan.is_closed(comm.client), true) @@ -234,6 +210,8 @@ test_chan_unbuffered :: proc(t: ^testing.T) { _, ok = chan.recv(comm.client); testing.expect_value(t, ok, false) _, ok = chan.try_recv(comm.host); testing.expect_value(t, ok, false) _, ok = chan.try_recv(comm.client); testing.expect_value(t, ok, false) + + thread.join(reckoner) } @test @@ -250,6 +228,198 @@ test_full_buffered_closed_chan_deadlock :: proc(t: ^testing.T) { testing.expect(t, !chan.send(ch, 32)) } +// Ensures that if a thread is doing a blocking send and the channel +// is closed, it will report false to indicate a failure to complete. +@test +test_fail_blocking_send_on_close :: proc(t: ^testing.T) { + ch, ch_alloc_err := chan.create(chan.Chan(int), context.allocator) + assert(ch_alloc_err == nil, "allocation failed") + defer chan.destroy(ch) + + sender := thread.create_and_start_with_poly_data(ch, proc(ch: chan.Chan(int)) { + assert(!chan.send(ch, 42)) + }) + + for !chan.can_recv(ch) { + thread.yield() + } + + testing.expect(t, chan.close(ch)) + thread.join(sender) + thread.destroy(sender) +} + +// Ensures that if a thread is doing a blocking read and the channel +// is closed, it will report false to indicate a failure to complete. +@test +test_fail_blocking_recv_on_close :: proc(t: ^testing.T) { + ch, ch_alloc_err := chan.create(chan.Chan(int), context.allocator) + assert(ch_alloc_err == nil, "allocation failed") + defer chan.destroy(ch) + + reader := thread.create_and_start_with_poly_data(ch, proc(ch: chan.Chan(int)) { + v, ok := chan.recv(ch) + assert(!ok) + assert(v == 0) + }) + + for !chan.can_send(ch) { + thread.yield() + } + + testing.expect(t, chan.close(ch)) + thread.join(reader) + thread.destroy(reader) +} + +// Ensures that try_send for unbuffered channels works as expected. +// If 1 reader of a channel, and 3 try_senders, only one of the senders +// will succeed and none of them will block. +@test +test_unbuffered_try_send_chan_contention :: proc(t: ^testing.T) { + testing.set_fail_timeout(t, FAIL_TIME) + + start, start_alloc_err := chan.create(chan.Chan(any), context.allocator) + assert(start_alloc_err == nil, "allocation failed") + defer chan.destroy(start) + + trigger, trigger_alloc_err := chan.create(chan.Chan(any), context.allocator) + assert(trigger_alloc_err == nil, "allocation failed") + defer chan.destroy(trigger) + + results, results_alloc_err := chan.create(chan.Chan(int), 3, context.allocator) + assert(results_alloc_err == nil, "allocation failed") + defer chan.destroy(results) + + ch, ch_alloc_err := chan.create(chan.Chan(int), context.allocator) + assert(ch_alloc_err == nil, "allocation failed") + defer chan.destroy(ch) + + // There are no readers or writers, so calling recv or send would block! + testing.expect_value(t, chan.can_send(ch), false) + testing.expect_value(t, chan.can_recv(ch), false) + + // Non-blocking operations should not block, and should return false. + testing.expect_value(t, chan.try_send(ch, -1), false) + if v, ok := chan.try_recv(ch); ok { + testing.expect_value(t, ok, false) + testing.expect_value(t, v, 0) + } + + // Spinup several threads contending to send on an unbuffered channel. + contenders: [3]^thread.Thread + wait: sync.Wait_Group + + for ii in 0.. #include +#include #include #include #include @@ -702,8 +703,10 @@ static void verify_winmm(ofstream& out) { test_proc_comment("mmsyscom.h"); expect_size(MMVERSION); expect_size(MMTIME); - test_proc_comment("mmeapi.h"); + test_proc_comment("mmreg.h"); expect_size(WAVEFORMATEX); + expect_size(WAVEFORMATEXTENSIBLE); + test_proc_comment("mmeapi.h"); expect_size(WAVEHDR); expect_size(WAVEINCAPSW); expect_size(WAVEOUTCAPSW); diff --git a/tests/core/testing/test_core_testing.odin b/tests/core/testing/test_core_testing.odin new file mode 100644 index 000000000..a323971dc --- /dev/null +++ b/tests/core/testing/test_core_testing.odin @@ -0,0 +1,52 @@ +package test_core_testing + +import "core:c/libc" +import "core:math/rand" +import "core:testing" + +@test +test_expected_assert :: proc(t: ^testing.T) { + target := #location(); target.line += 2; target.column = 2 + testing.expect_assert_from(t, target) + assert(false) +} + +@test +test_expected_two_assert :: proc(t: ^testing.T) { + target1 := #location(); target1.line += 5; target1.column = 3 + target2 := #location(); target2.line += 6; target2.column = 3 + testing.expect_assert_from(t, target1) + testing.expect_assert_from(t, target2) + if rand.uint32() & 1 == 0 { + assert(false) + } else { + assert(false) + } +} + +some_proc :: proc() { + assert(false) +} + +@test +test_expected_assert_in_proc :: proc(t: ^testing.T) { + target := #location(some_proc) + target.line += 1 + target.column = 2 + assert(target.procedure == "", "The bug's been fixed; this line and the next can be deleted.") + target.procedure = "some_proc" // TODO: Is this supposed to be blank on #location(...)? + testing.expect_assert(t, target) + some_proc() +} + +@test +test_expected_assert_message :: proc(t: ^testing.T) { + testing.expect_assert(t, "failure") + assert(false, "failure") +} + +@test +test_expected_signal :: proc(t: ^testing.T) { + testing.expect_signal(t, libc.SIGILL) + libc.raise(libc.SIGILL) +} diff --git a/tests/core/text/regex/test_core_text_regex.odin b/tests/core/text/regex/test_core_text_regex.odin index 3e7145406..8369444b9 100644 --- a/tests/core/text/regex/test_core_text_regex.odin +++ b/tests/core/text/regex/test_core_text_regex.odin @@ -51,13 +51,13 @@ check_expression_with_flags :: proc(t: ^testing.T, pattern: string, flags: regex } check_expression :: proc(t: ^testing.T, pattern, haystack: string, needles: ..string, extra_flags := regex.Flags{}, loc := #caller_location) { - check_expression_with_flags(t, pattern, { .Global } + extra_flags, + check_expression_with_flags(t, pattern, extra_flags, haystack, ..needles, loc = loc) - check_expression_with_flags(t, pattern, { .Global, .No_Optimization } + extra_flags, + check_expression_with_flags(t, pattern, { .No_Optimization } + extra_flags, haystack, ..needles, loc = loc) - check_expression_with_flags(t, pattern, { .Global, .Unicode } + extra_flags, + check_expression_with_flags(t, pattern, { .Unicode } + extra_flags, haystack, ..needles, loc = loc) - check_expression_with_flags(t, pattern, { .Global, .Unicode, .No_Optimization } + extra_flags, + check_expression_with_flags(t, pattern, { .Unicode, .No_Optimization } + extra_flags, haystack, ..needles, loc = loc) } @@ -72,6 +72,19 @@ expect_error :: proc(t: ^testing.T, pattern: string, expected_error: typeid, fla testing.expect_value(t, variant_ti, expected_ti, loc = loc) } +check_capture :: proc(t: ^testing.T, got, expected: regex.Capture, loc := #caller_location) -> (ok: bool) { + testing.expect_value(t, len(got.pos), len(got.groups), loc = loc) or_return + testing.expect_value(t, len(got.pos), len(expected.pos), loc = loc) or_return + testing.expect_value(t, len(got.groups), len(expected.groups), loc = loc) or_return + + if len(got.pos) == len(expected.pos) { + for i in 0..= len(test.expected) { + log.errorf("got more than expected number of captures for matching string %q against pattern %q\n\tidx %i = %v", test.haystack, test.pattern, idx, capture) + continue vector + } + if !check_capture(t, capture, test.expected[idx]) { + log.errorf("capture check failed on string %q against pattern %q", test.haystack, test.pattern) + } + } + testing.expectf(t, it.idx == len(test.expected), "expected idx to be %i, got %i on string %q against pattern %q", len(test.expected), it.idx, test.haystack, test.pattern) + } +} + +@test +test_iterator_reset :: proc(t: ^testing.T) { + test := Iterator_Test{ + `aaa`, `a`, {}, + { + {pos = {{0, 1}}, groups = {"a"}}, + {pos = {{1, 2}}, groups = {"a"}}, + {pos = {{2, 3}}, groups = {"a"}}, + }, + } + + out: { + it, err := regex.create_iterator(`aaa`, `a`) + defer regex.destroy(it) + + testing.expect_value(t, err, nil) + (err == nil) or_break out + + for capture, idx in regex.match(&it) { + if idx >= len(test.expected) { + log.errorf("got more than expected number of captures for matching string %q against pattern %q\n\tidx %i = %v", test.haystack, test.pattern, idx, capture) + break + } + check_capture(t, capture, test.expected[idx]) + } + testing.expect_value(t, it.idx, len(test.expected)) + + // Do it again. + iterations := 0 + regex.reset(&it) + + // Mind that this loop can do nothing if it wasn't reset but leave us + // with the expected `idx` state. + // + // That's why we count iterations this time around. + for capture, idx in regex.match(&it) { + iterations += 1 + if idx >= len(test.expected) { + log.errorf("got more than expected number of captures for matching string %q against pattern %q\n\tidx %i = %v", test.haystack, test.pattern, idx, capture) + break + } + check_capture(t, capture, test.expected[idx]) + } + testing.expect_value(t, it.idx, len(test.expected)) + testing.expect_value(t, iterations, len(test.expected)) + } +} diff --git a/tests/internal/test_global_any.odin b/tests/internal/test_global_any.odin new file mode 100644 index 000000000..850884912 --- /dev/null +++ b/tests/internal/test_global_any.odin @@ -0,0 +1,40 @@ +package test_internal + +@(private="file") +global_any_from_proc: any = from_proc() + +from_proc :: proc "contextless" () -> f32 { + return 1.1 +} + +@(private="file") +global_any: any = 1 + +import "core:testing" + +@(test) +test_global_any :: proc(t: ^testing.T) { + as_f32, is_f32 := global_any_from_proc.(f32) + testing.expect(t, is_f32 == true) + testing.expect(t, as_f32 == 1.1) + + as_int, is_int := global_any.(int) + testing.expect(t, is_int == true) + testing.expect(t, as_int == 1) +} + +@(test) +test_static_any :: proc(t: ^testing.T) { + @(static) + var: any = 3 + + as_int, is_int := var.(int) + testing.expect(t, is_int == true) + testing.expect(t, as_int == 3) + + var = f32(1.1) + + as_f32, is_f32 := var.(f32) + testing.expect(t, is_f32 == true) + testing.expect(t, as_f32 == 1.1) +} diff --git a/tests/internal/test_intrinsics_enum_contiguous.odin b/tests/internal/test_intrinsics_enum_contiguous.odin new file mode 100644 index 000000000..7a6901b82 --- /dev/null +++ b/tests/internal/test_intrinsics_enum_contiguous.odin @@ -0,0 +1,24 @@ +package test_internal + +import "base:intrinsics" +import "core:testing" + +@(test) +test_intrinsics_enum_is_contiguous :: proc(t: ^testing.T) { + contiguous :: intrinsics.type_enum_is_contiguous + testing.expect(t, contiguous(enum { A=0, B=0, C=0 })) + testing.expect(t, contiguous(enum { A=0, B=1, C=2 })) + testing.expect(t, contiguous(enum { A=1, B=2, C=2 })) + testing.expect(t, contiguous(enum { A=-2, B=-1, C=0 })) + testing.expect(t, contiguous(enum { A=-8, B=-6, C=-7, D=-8 })) + testing.expect(t, contiguous(enum { C=4, A=3 })) + testing.expect(t, contiguous(enum { })) + testing.expect(t, contiguous(enum { A })) + testing.expect(t, contiguous(enum { Delta=-4 })) + testing.expect(t, contiguous(enum { X = 2 * len([?]u8{ 0 }) })) + testing.expect(t, contiguous(enum { Alpha=-2, Beta=-1, Gamma=0, Delta=-3 })) + + testing.expect(t, !contiguous(enum { A=1, B=3 })) + testing.expect(t, !contiguous(enum { B=-5, Beta=-3 })) + testing.expect(t, !contiguous(enum { A=0, B=-2 })) +} diff --git a/tests/internal/test_intrinsics_integer_to.odin b/tests/internal/test_intrinsics_integer_to.odin new file mode 100644 index 000000000..108318c9a --- /dev/null +++ b/tests/internal/test_intrinsics_integer_to.odin @@ -0,0 +1,34 @@ +package test_internal + +import "base:intrinsics" +import "core:testing" + +/* +example_usage :: proc(#any_int x: int) -> intrinsics.type_integer_to_unsigned(type_of(x)) { + T :: intrinsics.type_integer_to_unsigned(type_of(x)) + return 1< NaN, false) + testing.expect_value(t, NaN >= NaN, false) +} + +@(test) +compare_constant_nans_f64 :: proc(t: ^testing.T) { + NaN :: f64(0h7fff_0000_0000_0000) + NaN2 :: f64(0h7fff_0000_0000_0001) + Inf :: f64(0h7FF0_0000_0000_0000) + Neg_Inf :: f64(0hFFF0_0000_0000_0000) + + testing.expect_value(t, NaN == NaN, false) + testing.expect_value(t, NaN == NaN2, false) + testing.expect_value(t, NaN != 0, true) + testing.expect_value(t, NaN != 5, true) + testing.expect_value(t, NaN != -5, true) + testing.expect_value(t, NaN != NaN, true) + testing.expect_value(t, NaN != NaN2, true) + testing.expect_value(t, NaN != Inf, true) + testing.expect_value(t, NaN != Neg_Inf, true) + testing.expect_value(t, NaN < NaN, false) + testing.expect_value(t, NaN <= NaN, false) + testing.expect_value(t, NaN > NaN, false) + testing.expect_value(t, NaN >= NaN, false) +} + +@(test) +compare_variable_nans_f32 :: proc(t: ^testing.T) { + NaN := f32(0h7fc0_0000) + NaN2 := f32(0h7fc0_0001) + Inf := f32(0h7F80_0000) + Neg_Inf := f32(0hFF80_0000) + + testing.expect_value(t, NaN == NaN, false) + testing.expect_value(t, NaN == NaN2, false) + testing.expect_value(t, NaN != 0, true) + testing.expect_value(t, NaN != 5, true) + testing.expect_value(t, NaN != -5, true) + testing.expect_value(t, NaN != NaN, true) + testing.expect_value(t, NaN != NaN2, true) + testing.expect_value(t, NaN != Inf, true) + testing.expect_value(t, NaN != Neg_Inf, true) + testing.expect_value(t, NaN < NaN, false) + testing.expect_value(t, NaN <= NaN, false) + testing.expect_value(t, NaN > NaN, false) + testing.expect_value(t, NaN >= NaN, false) +} + +@(test) +compare_variable_nans_f64 :: proc(t: ^testing.T) { + NaN := f64(0h7fff_0000_0000_0000) + NaN2 := f64(0h7fff_0000_0000_0001) + Inf := f64(0h7FF0_0000_0000_0000) + Neg_Inf := f64(0hFFF0_0000_0000_0000) + + testing.expect_value(t, NaN == NaN, false) + testing.expect_value(t, NaN == NaN2, false) + testing.expect_value(t, NaN != 0, true) + testing.expect_value(t, NaN != 5, true) + testing.expect_value(t, NaN != -5, true) + testing.expect_value(t, NaN != NaN, true) + testing.expect_value(t, NaN != NaN2, true) + testing.expect_value(t, NaN != Inf, true) + testing.expect_value(t, NaN != Neg_Inf, true) + testing.expect_value(t, NaN < NaN, false) + testing.expect_value(t, NaN <= NaN, false) + testing.expect_value(t, NaN > NaN, false) + testing.expect_value(t, NaN >= NaN, false) +} diff --git a/tests/internal/test_proc_group_type_inference.odin b/tests/internal/test_proc_group_type_inference.odin new file mode 100644 index 000000000..32498c836 --- /dev/null +++ b/tests/internal/test_proc_group_type_inference.odin @@ -0,0 +1,156 @@ +#+feature dynamic-literals + +package test_internal + +import "core:testing" + +@test +test_type_inference_on_literals_for_various_parameters_combinations :: proc(t: ^testing.T) { + Bit_Set :: bit_set[enum{A, B, C}] + group :: proc{proc_0, proc_1, proc_2, proc_3, proc_4, proc_5} + proc_0 :: proc() -> int { return 0 } + proc_1 :: proc(Bit_Set) -> int { return 1 } + proc_2 :: proc(int, Bit_Set) -> int { return 2 } + proc_3 :: proc(f32, Bit_Set) -> int { return 3 } + proc_4 :: proc(int, int, Bit_Set) -> int { return 4 } + proc_5 :: proc(Bit_Set, int, int, int) -> int { return 5 } + + testing.expect_value(t, group({.A}), 1) + testing.expect_value(t, group(9, {.A}), 2) + testing.expect_value(t, group(3.14, {.A}), 3) + testing.expect_value(t, group(9, 9, {.A}), 4) + testing.expect_value(t, group({.A}, 9, 9, 9), 5) +} + +@test +test_type_inference_on_literals_with_default_args :: proc(t: ^testing.T) { + { + Bit_Set :: bit_set[enum{A, B, C}] + proc_nil :: proc() { } + proc_default_arg :: proc(a: Bit_Set={.A}) -> Bit_Set { return a } + group :: proc{proc_nil, proc_default_arg} + + testing.expect_value(t, group(Bit_Set{.A}), Bit_Set{.A}) + testing.expect_value(t, group({.A}), Bit_Set{.A}) + } + { + Bit_Set :: bit_set[enum{A, B, C}] + proc_1 :: proc(a: Bit_Set={.A}) -> int { return 1 } + proc_2 :: proc(a: Bit_Set={.B}, b: Bit_Set={.C}) -> int { return 2 } + group :: proc{proc_1, proc_2} + + testing.expect_value(t, group(), 2) + testing.expect_value(t, group(Bit_Set{.A}), 2) + testing.expect_value(t, group({.A}), 2) + testing.expect_value(t, group({.B}, {.C}), 2) + } +} + +@test +test_type_inference_on_literals_for_various_types :: proc(t: ^testing.T) { + proc_nil :: proc() { } + + proc_array :: proc(a: [3]f32) -> [3]f32 { return a } + group_array :: proc{proc_nil, proc_array} + testing.expect_value(t, group_array([3]f32{1.1, 2.2, 3.3}), [3]f32{1.1, 2.2, 3.3}) + testing.expect_value(t, group_array({1.1, 2.2, 3.3}), [3]f32{1.1, 2.2, 3.3}) + testing.expect_value(t, group_array({0=1.1, 1=2.2, 2=3.3}), [3]f32{1.1, 2.2, 3.3}) + testing.expect_value(t, group_array({}), [3]f32{}) + + proc_slice_u8 :: proc(a: []u8) -> []u8 { return a } + group_slice_u8 :: proc{proc_nil, proc_slice_u8} + testing.expect_value(t, len(group_slice_u8([]u8{1, 2, 3})), 3) + testing.expect_value(t, len(group_slice_u8({1, 2, 3})), 3) + testing.expect_value(t, len(group_slice_u8({0=1, 1=2, 2=3})), 3) + testing.expect_value(t, len(group_slice_u8({})), 0) + testing.expect_value(t, group_slice_u8(nil) == nil, true) + + proc_dynamic_array :: proc(t: ^testing.T, array: [dynamic]u8, expected_len: int) { + if expected_len < 0 { + testing.expect_value(t, array == nil, true) + } else { + testing.expect_value(t, len(array), expected_len) + } + delete(array) + } + group_dynamic_array :: proc{proc_nil, proc_dynamic_array} + group_dynamic_array(t, [dynamic]u8{1, 2, 3}, 3) + group_dynamic_array(t, {1, 2, 3}, 3) + group_dynamic_array(t, {0=1, 1=2, 2=3}, 3) + group_dynamic_array(t, {}, 0) + group_dynamic_array(t, nil, -1) + + Enum :: enum{A, B, C} + proc_enum :: proc(a: Enum) -> Enum { return a } + group_enum :: proc{proc_nil, proc_enum} + testing.expect_value(t, group_enum(Enum.A), Enum.A) + testing.expect_value(t, group_enum(.A), Enum.A) + + proc_enumerated_array :: proc(a: [Enum]u8) -> [Enum]u8 { return a } + group_enumerated_array :: proc{proc_nil, proc_enumerated_array} + testing.expect_value(t, group_enumerated_array([Enum]u8{.A=1, .B=2, .C=3}), [Enum]u8{.A=1, .B=2, .C=3}) + testing.expect_value(t, group_enumerated_array({.A=1, .B=2, .C=3}), [Enum]u8{.A=1, .B=2, .C=3}) + + Bit_Set :: bit_set[enum{A, B, C}] + proc_bit_set :: proc(a: Bit_Set) -> Bit_Set { return a } + group_bit_set :: proc{proc_nil, proc_bit_set} + testing.expect_value(t, group_bit_set(Bit_Set{.A}), Bit_Set{.A}) + testing.expect_value(t, group_bit_set({.A}), Bit_Set{.A}) + testing.expect_value(t, group_bit_set({}), Bit_Set{}) + + Struct :: struct{a: int, b: int, c: int} + proc_struct :: proc(a: Struct) -> Struct { return a } + group_struct :: proc{proc_nil, proc_struct} + testing.expect_value(t, group_struct(Struct{a = 9}), Struct{a = 9}) + testing.expect_value(t, group_struct({a = 9}), Struct{a = 9}) + testing.expect_value(t, group_struct({}), Struct{}) + + Raw_Union :: struct #raw_union{int_: int, f32_: f32} + proc_raw_union :: proc(a: Raw_Union) -> Raw_Union { return a } + group_raw_union :: proc{proc_nil, proc_raw_union} + testing.expect_value(t, group_raw_union(Raw_Union{int_ = 9}).int_, 9) + testing.expect_value(t, group_raw_union({int_ = 9}).int_, 9) + testing.expect_value(t, group_raw_union({}).int_, 0) + + Union :: union{int, f32} + proc_union :: proc(a: Union) -> Union { return a } + group_union :: proc{proc_nil, proc_union} + testing.expect_value(t, group_union(int(9)).(int), 9) + testing.expect_value(t, group_union({}), nil) + + proc_map :: proc(t: ^testing.T, map_: map[u8]u8, expected_len: int) { + if expected_len < 0 { + testing.expect_value(t, map_ == nil, true) + } else { + testing.expect_value(t, len(map_), expected_len) + } + delete(map_) + } + group_map :: proc{proc_nil, proc_map} + group_map(t, map[u8]u8{1=1, 2=2}, 2) + group_map(t, {1=1, 2=2}, 2) + group_map(t, {}, 0) + group_map(t, nil, -1) + + Bit_Field :: bit_field u16 {a: u8|4, b: u8|4, c: u8|4} + proc_bit_field :: proc(a: Bit_Field) -> Bit_Field { return a } + group_bit_field :: proc{proc_nil, proc_bit_field} + testing.expect_value(t, group_bit_field(Bit_Field{a = 1}), Bit_Field{a = 1}) + testing.expect_value(t, group_bit_field({a = 1}), Bit_Field{a = 1}) + testing.expect_value(t, group_bit_field({}), Bit_Field{}) + + SOA_Array :: #soa[2]struct{int, int} + proc_soa_array :: proc(a: SOA_Array) -> SOA_Array { return a } + group_soa_array :: proc{proc_nil, proc_soa_array} + testing.expect_value(t, len(group_soa_array(SOA_Array{{}, {}})), 2) + testing.expect_value(t, len(group_soa_array({struct{int, int}{1, 2}, struct{int, int}{1, 2}})), 2) + testing.expect_value(t, len(group_soa_array({})), 2) + testing.expect_value(t, len(soa_zip(a=[]int{1, 2}, b=[]int{3, 4})), 2) + + proc_matrix :: proc(a: matrix[2,2]f32) -> matrix[2,2]f32 { return a } + group_matrix :: proc{proc_nil, proc_matrix} + testing.expect_value(t, group_matrix(matrix[2,2]f32{1, 2, 3, 4}), matrix[2,2]f32{1, 2, 3, 4}) + testing.expect_value(t, group_matrix(1), (matrix[2,2]f32)(1)) + testing.expect_value(t, group_matrix({1, 2, 3, 4}), matrix[2,2]f32{1, 2, 3, 4}) + testing.expect_value(t, group_matrix({}), matrix[2,2]f32{}) +} diff --git a/tests/internal/test_signedness_comparisons.odin b/tests/internal/test_signedness_comparisons.odin new file mode 100644 index 000000000..5e7431c7a --- /dev/null +++ b/tests/internal/test_signedness_comparisons.odin @@ -0,0 +1,34 @@ +package test_internal + +import "core:testing" + +@test +test_comparisons_5408 :: proc(t: ^testing.T) { + // See: https://github.com/odin-lang/Odin/pull/5408 + test_proc :: proc(lhs: $T, rhs: T) -> bool { + return lhs > rhs + } + + Test_Enum :: enum u32 { + SMALL_VALUE = 0xFF, + BIG_VALUE = 0xFF00_0000, // negative if interpreted as i32 + } + + testing.expect_value(t, test_proc(Test_Enum.SMALL_VALUE, Test_Enum.BIG_VALUE), false) + testing.expect_value(t, test_proc(Test_Enum(0xF), Test_Enum.BIG_VALUE), false) + testing.expect_value(t, test_proc(Test_Enum(0xF), Test_Enum(0xF000_0000)), false) + testing.expect_value(t, test_proc(Test_Enum.SMALL_VALUE, max(Test_Enum)), false) + testing.expect_value(t, test_proc(Test_Enum(0xF), max(Test_Enum)), false) +} + +test_signedness :: proc(t: ^testing.T) { + { + a, b := i16(32767), i16(0) + testing.expect_value(t, a > b, true) + } + + { + a, b := u16(65535), u16(0) + testing.expect_value(t, a > b, true) + } +} \ No newline at end of file diff --git a/tests/issues/run.bat b/tests/issues/run.bat index 7ed43205d..4a1072e12 100644 --- a/tests/issues/run.bat +++ b/tests/issues/run.bat @@ -9,14 +9,22 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style ..\..\..\odin test ..\test_issue_829.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_1592.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_1730.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2056.odin %COMMON% || exit /b ..\..\..\odin build ..\test_issue_2113.odin %COMMON% -debug || exit /b ..\..\..\odin test ..\test_issue_2466.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2615.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2637.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_2666.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_2694.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_3435.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4210.odin %COMMON% || exit /b +..\..\..\odin test ..\test_issue_4364.odin %COMMON% || exit /b ..\..\..\odin test ..\test_issue_4584.odin %COMMON% || exit /b +..\..\..\odin build ..\test_issue_5043.odin %COMMON% || exit /b +..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b +..\..\..\odin build ..\test_issue_5097-2.odin %COMMON% || exit /b +..\..\..\odin build ..\test_issue_5265.odin %COMMON% || exit /b @echo off diff --git a/tests/issues/run.sh b/tests/issues/run.sh index 54543980e..03d84425a 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -10,13 +10,17 @@ set -x $ODIN test ../test_issue_829.odin $COMMON $ODIN test ../test_issue_1592.odin $COMMON +$ODIN test ../test_issue_1730.odin $COMMON $ODIN test ../test_issue_2056.odin $COMMON $ODIN build ../test_issue_2113.odin $COMMON -debug $ODIN test ../test_issue_2466.odin $COMMON $ODIN test ../test_issue_2615.odin $COMMON $ODIN test ../test_issue_2637.odin $COMMON $ODIN test ../test_issue_2666.odin $COMMON +$ODIN test ../test_issue_2694.odin $COMMON +$ODIN test ../test_issue_3435.odin $COMMON $ODIN test ../test_issue_4210.odin $COMMON +$ODIN test ../test_issue_4364.odin $COMMON $ODIN test ../test_issue_4584.odin $COMMON if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then echo "SUCCESSFUL 1/1" @@ -24,6 +28,10 @@ else echo "SUCCESSFUL 0/1" exit 1 fi +$ODIN build ../test_issue_5043.odin $COMMON +$ODIN build ../test_issue_5097.odin $COMMON +$ODIN build ../test_issue_5097-2.odin $COMMON +$ODIN build ../test_issue_5265.odin $COMMON set +x diff --git a/tests/issues/test_issue_1730.odin b/tests/issues/test_issue_1730.odin new file mode 100644 index 000000000..c1c5c4cae --- /dev/null +++ b/tests/issues/test_issue_1730.odin @@ -0,0 +1,21 @@ +package test_issues + +import "core:testing" + +// Tests issue #1730 https://github.com/odin-lang/Odin/issues/1730 +@(test) +test_issue_1730 :: proc(t: ^testing.T) { + ll := [4]int{1, 2, 3, 4} + for l, i in ll.yz { + testing.expect(t, i <= 1) + if i == 0 { + testing.expect_value(t, l, 2) + } else if i == 1 { + testing.expect_value(t, l, 3) + } + } + + out: [4]int + out.yz = ll.yz + testing.expect_value(t, out, [4]int{0, 2, 3, 0}) +} diff --git a/tests/issues/test_issue_2694.odin b/tests/issues/test_issue_2694.odin new file mode 100644 index 000000000..01860d603 --- /dev/null +++ b/tests/issues/test_issue_2694.odin @@ -0,0 +1,42 @@ +package test_issues + +import "core:fmt" +import "core:encoding/json" +import "core:log" +import "core:mem" +import "core:testing" + +// This is a minimal reproduction of the code in #2694. +// It exemplifies the original problem as briefly as possible. + +SAMPLE_JSON :: ` +{ + "foo": 0, + "things": [ + { "a": "ZZZZ"}, + ] +} +` + +@test +test_issue_2694 :: proc(t: ^testing.T) { + into: struct { + foo: int, + things: []json.Object, + } + + scratch := new(mem.Scratch_Allocator) + defer free(scratch) + if mem.scratch_allocator_init(scratch, 4 * mem.Megabyte) != .None { + log.error("unable to initialize scratch allocator") + return + } + defer mem.scratch_allocator_destroy(scratch) + + err := json.unmarshal_string(SAMPLE_JSON, &into, allocator = mem.scratch_allocator(scratch)) + testing.expect(t, err == nil) + + output := fmt.tprintf("%v", into) + expected := `{foo = 0, things = [map[a="ZZZZ"]]}` + testing.expectf(t, output == expected, "\n\texpected: %q\n\tgot: %q", expected, output) +} diff --git a/tests/issues/test_issue_3435.odin b/tests/issues/test_issue_3435.odin new file mode 100644 index 000000000..3830869ed --- /dev/null +++ b/tests/issues/test_issue_3435.odin @@ -0,0 +1,38 @@ +package main + +import "base:runtime" +import "core:mem" +import "core:testing" +import "core:time" + +@test +test_issue_3435 :: proc(t: ^testing.T) { + testing.set_fail_timeout(t, time.Second) + allocator: mem.Buddy_Allocator + data := runtime.make_aligned([]byte, 64, 32) + defer delete(data) + + // mem.buddy_allocator_init(&allocator, data, 32) + + // Bypass the assertion that would normally keep this from happening by + // manually putting the allocator together. + allocator.head = cast(^mem.Buddy_Block)raw_data(data) + allocator.head.size = len(data) + allocator.head.is_free = true + allocator.tail = mem.buddy_block_next(allocator.head) + allocator.alignment = 32 + + context.allocator = mem.buddy_allocator(&allocator) + + // Three allocations in the space above is all that's needed to reproduce + // the bug seen in #3435; this is the most minimal reproduction possible. + a := make([]u8, 1) + testing.expect(t, len(a) == 1) + b := make([]u8, 1) + testing.expect(t, len(b) == 0) + c := make([]u8, 1) + testing.expect(t, len(c) == 0) + + // With the bugfix in place, the allocator should be sensible enough to not + // fall into an infinite loop anymore, even if the assertion is disabled. +} diff --git a/tests/issues/test_issue_4364.odin b/tests/issues/test_issue_4364.odin new file mode 100644 index 000000000..817a1a26b --- /dev/null +++ b/tests/issues/test_issue_4364.odin @@ -0,0 +1,18 @@ +// Tests issue #4364 https://github.com/odin-lang/Odin/issues/4364 +package test_issues + +import "core:testing" + +@test +test_const_array_fill_assignment :: proc(t: ^testing.T) { + MAGIC :: 12345 + Struct :: struct {x: int} + CONST_ARR : [4]Struct : Struct{MAGIC} + arr := CONST_ARR + + testing.expect_value(t, len(arr), 4) + testing.expect_value(t, arr[0], Struct{MAGIC}) + testing.expect_value(t, arr[1], Struct{MAGIC}) + testing.expect_value(t, arr[2], Struct{MAGIC}) + testing.expect_value(t, arr[3], Struct{MAGIC}) +} diff --git a/tests/issues/test_issue_5043.odin b/tests/issues/test_issue_5043.odin new file mode 100644 index 000000000..ce36bf674 --- /dev/null +++ b/tests/issues/test_issue_5043.odin @@ -0,0 +1,23 @@ +// Tests issue #5043 https://github.com/odin-lang/Odin/issues/5043 +package test_issues + +Table :: map [string] Type +List :: [dynamic] Type + +Type :: union { + ^Table, + ^List, + i64, +} + + +main :: proc() { + v: Type = 5 + + switch t in v { + case ^Table: // or case ^map [string] Type: + case ^List: + case i64: + + } +} diff --git a/tests/issues/test_issue_5097-2.odin b/tests/issues/test_issue_5097-2.odin new file mode 100644 index 000000000..1e4ad59c9 --- /dev/null +++ b/tests/issues/test_issue_5097-2.odin @@ -0,0 +1,24 @@ +// Tests another variation of, this should compile #5097 https://github.com/odin-lang/Odin/issues/5097 +package test_issues + +Face :: ^FaceRec +GlyphSlot :: ^GlyphSlotRec +Size :: ^SizeRec + +SizeRec :: struct { + face: Face, +} + +GlyphSlotRec :: struct { + face: Face, +} + +FaceRec :: struct { + glyph: GlyphSlot, + size: Size, +} + +main :: proc() { + face: Face + _ = face +} diff --git a/tests/issues/test_issue_5097.odin b/tests/issues/test_issue_5097.odin new file mode 100644 index 000000000..57ef60b8d --- /dev/null +++ b/tests/issues/test_issue_5097.odin @@ -0,0 +1,15 @@ +// Tests issue #5097 https://github.com/odin-lang/Odin/issues/5097 +package test_issues + +Node_Ptr :: ^Node // the typedef... + +Node :: struct { + prev, next: Node_Ptr, // replacing the type with ^Node also fixes it +} + +// ...if placed here, it works just fine + +main :: proc() { + node: Node_Ptr + _ = node +} diff --git a/tests/issues/test_issue_5265.odin b/tests/issues/test_issue_5265.odin new file mode 100644 index 000000000..f61f05b0a --- /dev/null +++ b/tests/issues/test_issue_5265.odin @@ -0,0 +1,8 @@ +// Tests issue #5265 https://github.com/odin-lang/Odin/issues/5265 +package test_issues + +main :: proc() { + a: i128 = 1 + assert(1 / a == 1) + assert(a / 1 == 1) +} \ No newline at end of file diff --git a/vendor/OpenGL/wrappers.odin b/vendor/OpenGL/wrappers.odin index 1eb8fc72f..d68efee6c 100644 --- a/vendor/OpenGL/wrappers.odin +++ b/vendor/OpenGL/wrappers.odin @@ -880,7 +880,7 @@ when !GL_DEBUG { // VERSION_1_2 DrawRangeElements :: proc "c" (mode, start, end: u32, count: i32, type: u32, indices: rawptr, loc := #caller_location) { impl_DrawRangeElements(mode, start, end, count, type, indices); debug_helper(loc, 0, mode, start, end, count, type, indices) } - TexImage3D :: proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels); debug_helper(loc, 0, target, level, internalformat, width, height, depth, border, format, type, pixels) } + TexImage3D :: proc "c" (target: u32, level, internalformat, width, height, depth, border: i32, format, type: u32, data: rawptr, loc := #caller_location) { impl_TexImage3D(target, level, internalformat, width, height, depth, border, format, type, data); debug_helper(loc, 0, target, level, internalformat, width, height, depth, border, format, type, data) } TexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: u32, pixels: rawptr, loc := #caller_location) { impl_TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) } CopyTexSubImage3D :: proc "c" (target: u32, level, xoffset, yoffset, zoffset, x, y, width, height: i32, loc := #caller_location) { impl_CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height); debug_helper(loc, 0, target, level, xoffset, yoffset, zoffset, x, y, width, height) } diff --git a/vendor/README.md b/vendor/README.md index 186e6422a..94202cbd0 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -158,3 +158,9 @@ Se also LICENCE in `cgltf` directory itself. ## fontstash (Port) [Font stash](https://github.com/memononen/fontstash) is a light-weight online font texture atlas builder. It uses stb_truetype to render fonts on demand to a texture atlas. + +## kb + +[kb](https://github.com/JimmyLefevre/kb) provides ICU-like text segmentation (i.e. breaking Unicode text by direction, line, word and grapheme). It also provides Harfbuzz-like text shaping for OpenType fonts, which means it is capable of handling complex script layout and ligatures, among other things. + +It does not handle rasterization. It will only help you know which glyphs to display where! \ No newline at end of file diff --git a/vendor/box2d/box2d.odin b/vendor/box2d/box2d.odin index 8abf6ce03..8b0a57a4e 100644 --- a/vendor/box2d/box2d.odin +++ b/vendor/box2d/box2d.odin @@ -53,26 +53,7 @@ Version :: struct { revision: i32, // Bug fixes } -when ODIN_OS == .Windows { - // Timer for profiling. This has platform specific code and may - // not work on every platform. - Timer :: struct { - start: i64, - } -} else when ODIN_OS == .Linux || ODIN_OS == .Darwin { - // Timer for profiling. This has platform specific code and may - // not work on every platform. - Timer :: struct { - start_sec: u64, - start_usec: u64, - } -} else { - // Timer for profiling. This has platform specific code and may - // not work on every platform. - Timer :: struct { - dummy: i32, - } -} +HASH_INIT :: 5381 @(link_prefix="b2", default_calling_convention="c", require_results) foreign lib { @@ -85,19 +66,33 @@ foreign lib { // @param assertFcn a non-null assert callback SetAssertFcn :: proc(assertfcn: AssertFcn) --- - - CreateTimer :: proc() -> Timer --- - GetTicks :: proc(timer: ^Timer) -> i64 --- - GetMilliseconds :: proc(#by_ptr timer: Timer) -> f32 --- - GetMillisecondsAndReset :: proc(timer: ^Timer) -> f32 --- - SleepMilliseconds :: proc(milliseconds: c.int) --- + // Get the absolute number of system ticks. The value is platform specific. + GetTicks :: proc() -> u64 --- + // Get the milliseconds passed from an initial tick value. + GetMilliseconds :: proc(ticks: u64) -> f32 --- + // Get the milliseconds passed from an initial tick value. Resets the passed in + // value to the current tick value. + GetMillisecondsAndReset :: proc(ticks: ^u64) -> f32 --- + // Yield to be used in a busy loop. Yield :: proc() --- + // Simple djb2 hash function for determinism testing. + Hash :: proc(hash: u32, data: [^]byte, count: c.int) -> u32 --- // Box2D bases all length units on meters, but you may need different units for your game. // You can set this value to use different units. This should be done at application startup - // and only modified once. Default value is 1. - // @warning This must be modified before any calls to Box2D + // and only modified once. Default value is 1. + // For example, if your game uses pixels for units you can use pixels for all length values + // sent to Box2D. There should be no extra cost. However, Box2D has some internal tolerances + // and thresholds that have been tuned for meters. By calling this function, Box2D is able + // to adjust those tolerances and thresholds to improve accuracy. + // A good rule of thumb is to pass the height of your player character to this function. So + // if your player character is 32 pixels high, then pass 32 to this function. Then you may + // confidently use pixels for all the length values sent to Box2D. All length values returned + // from Box2D will also be pixels because Box2D does not do any scaling internally. + // However, you are now on the hook for coming up with good values for gravity, density, and + // forces. + // @warning This must be modified before any calls to Box2D SetLengthUnitsPerMeter :: proc(lengthUnits: f32) --- // Get the current length units per meter. @@ -122,6 +117,10 @@ foreign lib { // @ingroup shape DefaultQueryFilter :: proc() -> QueryFilter --- + // Use this to initialize your surface material + // @ingroup shape + DefaultSurfaceMaterial :: proc() -> SurfaceMaterial --- + // Use this to initialize your shape definition // @ingroup shape DefaultShapeDef :: proc() -> ShapeDef --- @@ -142,6 +141,10 @@ foreign lib { // @ingroup mouse_joint DefaultMouseJointDef :: proc() -> MouseJointDef --- + // Use this to initialize your joint definition + // @ingroup filter_joint + DefaultFilterJointDef :: proc() -> FilterJointDef --- + // Use this to initialize your joint definition // @ingroupd prismatic_joint DefaultPrismaticJointDef :: proc() -> PrismaticJointDef --- @@ -157,6 +160,14 @@ foreign lib { // Use this to initialize your joint definition // @ingroup wheel_joint DefaultWheelJointDef :: proc() -> WheelJointDef --- + + // Use this to initialize your explosion definition + // @ingroup world + DefaultExplosionDef :: proc() -> ExplosionDef --- + + // Use this to initialize your drawing interface. This allows you to implement a sub-set + // of the drawing functions. + DefaultDebugDraw :: proc() -> DebugDraw --- } @@ -164,85 +175,92 @@ foreign lib { @(link_prefix="b2", default_calling_convention="c", require_results) foreign lib { // Validate ray cast input data (NaN, etc) - IsValidRay :: proc(#by_ptr input: RayCastInput) -> bool --- + IsValidRay :: proc(#by_ptr input: RayCastInput) -> bool --- // Make a convex polygon from a convex hull. This will assert if the hull is not valid. // @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull - MakePolygon :: proc(#by_ptr hull: Hull, radius: f32) -> Polygon --- + MakePolygon :: proc(#by_ptr hull: Hull, radius: f32) -> Polygon --- // Make an offset convex polygon from a convex hull. This will assert if the hull is not valid. // @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull - MakeOffsetPolygon :: proc(#by_ptr hull: Hull, radius: f32, transform: Transform) -> Polygon --- + MakeOffsetPolygon :: proc(#by_ptr hull: Hull, position: Vec2, rotation: Rot) -> Polygon --- + + // Make an offset convex polygon from a convex hull. This will assert if the hull is not valid. + // @warning Do not manually fill in the hull data, it must come directly from b2ComputeHull + MakeOffsetRoundedPolygon :: proc(#by_ptr hull: Hull, position: Vec2, rotation: Rot, radius: f32) -> Polygon --- // Make a square polygon, bypassing the need for a convex hull. - MakeSquare :: proc(h: f32) -> Polygon --- + MakeSquare :: proc(halfWidth: f32) -> Polygon --- // Make a box (rectangle) polygon, bypassing the need for a convex hull. - MakeBox :: proc(hx, hy: f32) -> Polygon --- + MakeBox :: proc(halfWidth, halfHeight: f32) -> Polygon --- // Make a rounded box, bypassing the need for a convex hull. - MakeRoundedBox :: proc(hx, hy: f32, radius: f32) -> Polygon --- + MakeRoundedBox :: proc(halfWidth, halfHeight: f32, radius: f32) -> Polygon --- // Make an offset box, bypassing the need for a convex hull. - MakeOffsetBox :: proc(hx, hy: f32, center: Vec2, angle: f32) -> Polygon --- + MakeOffsetBox :: proc(halfWidth, halfHeight: f32, center: Vec2, rotation: Rot) -> Polygon --- + + // Make an offset rounded box, bypassing the need for a convex hull. + MakeOffsetRoundedBox :: proc(halfWidth, halfHeight: f32, center: Vec2, rotation: Rot, radius: f32) -> Polygon --- // Transform a polygon. This is useful for transferring a shape from one body to another. - TransformPolygon :: proc(transform: Transform, #by_ptr polygon: Polygon) -> Polygon --- + TransformPolygon :: proc(transform: Transform, #by_ptr polygon: Polygon) -> Polygon --- // Compute mass properties of a circle - ComputeCircleMass :: proc(#by_ptr shape: Circle, density: f32) -> MassData --- + ComputeCircleMass :: proc(#by_ptr shape: Circle, density: f32) -> MassData --- // Compute mass properties of a capsule - ComputeCapsuleMass :: proc(#by_ptr shape: Capsule, density: f32) -> MassData --- + ComputeCapsuleMass :: proc(#by_ptr shape: Capsule, density: f32) -> MassData --- // Compute mass properties of a polygon - ComputePolygonMass :: proc(#by_ptr shape: Polygon, density: f32) -> MassData --- + ComputePolygonMass :: proc(#by_ptr shape: Polygon, density: f32) -> MassData --- // Compute the bounding box of a transformed circle - ComputeCircleAABB :: proc(#by_ptr shape: Circle, transform: Transform) -> AABB --- + ComputeCircleAABB :: proc(#by_ptr shape: Circle, transform: Transform) -> AABB --- // Compute the bounding box of a transformed capsule - ComputeCapsuleAABB :: proc(#by_ptr shape: Capsule, transform: Transform) -> AABB --- + ComputeCapsuleAABB :: proc(#by_ptr shape: Capsule, transform: Transform) -> AABB --- // Compute the bounding box of a transformed polygon - ComputePolygonAABB :: proc(#by_ptr shape: Polygon, transform: Transform) -> AABB --- + ComputePolygonAABB :: proc(#by_ptr shape: Polygon, transform: Transform) -> AABB --- // Compute the bounding box of a transformed line segment - ComputeSegmentAABB :: proc(#by_ptr shape: Segment, transform: Transform) -> AABB --- + ComputeSegmentAABB :: proc(#by_ptr shape: Segment, transform: Transform) -> AABB --- // Test a point for overlap with a circle in local space - PointInCircle :: proc(point: Vec2, #by_ptr shape: Circle) -> bool --- + PointInCircle :: proc(point: Vec2, #by_ptr shape: Circle) -> bool --- // Test a point for overlap with a capsule in local space - PointInCapsule :: proc(point: Vec2, #by_ptr shape: Capsule) -> bool --- + PointInCapsule :: proc(point: Vec2, #by_ptr shape: Capsule) -> bool --- // Test a point for overlap with a convex polygon in local space - PointInPolygon :: proc(point: Vec2, #by_ptr shape: Polygon) -> bool --- + PointInPolygon :: proc(point: Vec2, #by_ptr shape: Polygon) -> bool --- // Ray cast versus circle in shape local space. Initial overlap is treated as a miss. - RayCastCircle :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Circle) -> CastOutput --- + RayCastCircle :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Circle) -> CastOutput --- // Ray cast versus capsule in shape local space. Initial overlap is treated as a miss. - RayCastCapsule :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Capsule) -> CastOutput --- + RayCastCapsule :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Capsule) -> CastOutput --- // Ray cast versus segment in shape local space. Optionally treat the segment as one-sided with hits from // the left side being treated as a miss. - RayCastSegment :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Segment, oneSided: bool) -> CastOutput --- + RayCastSegment :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Segment, oneSided: bool) -> CastOutput --- // Ray cast versus polygon in shape local space. Initial overlap is treated as a miss. - RayCastPolygon :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Polygon) -> CastOutput --- + RayCastPolygon :: proc(#by_ptr input: RayCastInput, #by_ptr shape: Polygon) -> CastOutput --- // Shape cast versus a circle. Initial overlap is treated as a miss. - ShapeCastCircle :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Circle) -> CastOutput --- + ShapeCastCircle :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Circle) -> CastOutput --- // Shape cast versus a capsule. Initial overlap is treated as a miss. - ShapeCastCapsule :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Capsule) -> CastOutput --- + ShapeCastCapsule :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Capsule) -> CastOutput --- // Shape cast versus a line segment. Initial overlap is treated as a miss. - ShapeCastSegment :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Segment) -> CastOutput --- + ShapeCastSegment :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Segment) -> CastOutput --- // Shape cast versus a convex polygon. Initial overlap is treated as a miss. - ShapeCastPolygon :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Polygon) -> CastOutput --- + ShapeCastPolygon :: proc(#by_ptr input: ShapeCastInput, #by_ptr shape: Polygon) -> CastOutput --- } @@ -251,7 +269,7 @@ foreign lib { // - all points very close together // - all points on a line // - less than 3 points -// - more than maxPolygonVertices points +// - more than MAX_POLYGON_VERTICES points // This welds close points and removes collinear points. // @warning Do not modify a hull once it has been computed @(require_results) @@ -279,30 +297,40 @@ foreign lib { } // Compute the closest points between two shapes represented as point clouds. -// DistanceCache cache is input/output. On the first call set DistanceCache.count to zero. +// SimplexCache cache is input/output. On the first call set SimplexCache.count to zero. // The underlying GJK algorithm may be debugged by passing in debug simplexes and capacity. You may pass in NULL and 0 for these. @(require_results) -ShapeDistance :: proc "c" (cache: ^DistanceCache, #by_ptr input: DistanceInput, simplexes: []Simplex) -> DistanceOutput { +ShapeDistance :: proc "c" (#by_ptr input: DistanceInput, cache: ^SimplexCache, simplexes: []Simplex) -> DistanceOutput { foreign lib { - b2ShapeDistance :: proc "c" (cache: ^DistanceCache, #by_ptr input: DistanceInput, simplexes: [^]Simplex, simplexCapacity: c.int) -> DistanceOutput --- + b2ShapeDistance :: proc "c" (#by_ptr input: DistanceInput, cache: ^SimplexCache, simplexes: [^]Simplex, simplexCapacity: c.int) -> DistanceOutput --- } - return b2ShapeDistance(cache, input, raw_data(simplexes), i32(len(simplexes))) + return b2ShapeDistance(input, cache, raw_data(simplexes), i32(len(simplexes))) } -// Make a proxy for use in GJK and related functions. +// Make a proxy for use in overlap, shape cast, and related functions. This is a deep copy of the points. @(require_results) -MakeProxy :: proc "c" (vertices: []Vec2, radius: f32) -> DistanceProxy { +MakeProxy :: proc "c" (points: []Vec2, radius: f32) -> ShapeProxy { foreign lib { - b2MakeProxy :: proc "c" (vertices: [^]Vec2, count: i32, radius: f32) -> DistanceProxy --- + b2MakeProxy :: proc "c" (points: [^]Vec2, count: i32, radius: f32) -> ShapeProxy --- } - return b2MakeProxy(raw_data(vertices), i32(len(vertices)), radius) + return b2MakeProxy(raw_data(points), i32(len(points)), radius) +} + +// Make a proxy with a transform. This is a deep copy of the points. +@(require_results) +MakeOffsetProxy :: proc "c" (points: []Vec2, radius: f32, position: Vec2, rotation: Rot) -> ShapeProxy { + foreign lib { + b2MakeOffsetProxy :: proc "c" (points: [^]Vec2, count: i32, radius: f32, position: Vec2, rotation: Rot) -> ShapeProxy --- + } + return b2MakeOffsetProxy(raw_data(points), i32(len(points)), radius, position, rotation) } @(link_prefix="b2", default_calling_convention="c", require_results) foreign lib { // Perform a linear shape cast of shape B moving and shape A fixed. Determines the hit point, normal, and translation fraction. + // You may optionally supply an array to hold debug data. ShapeCast :: proc(#by_ptr input: ShapeCastPairInput) -> CastOutput --- // Evaluate the transform sweep at a specific time. @@ -344,14 +372,14 @@ foreign lib { // Compute the contact manifold between an segment and a polygon CollideSegmentAndPolygon :: proc(#by_ptr segmentA: Segment, xfA: Transform, #by_ptr polygonB: Polygon, xfB: Transform) -> Manifold --- - // Compute the contact manifold between a smooth segment and a circle - CollideSmoothSegmentAndCircle :: proc(#by_ptr smoothSegmentA: SmoothSegment, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold --- + // Compute the contact manifold between a chain segment and a circle + CollideChainSegmentAndCircle :: proc(#by_ptr segmentA: ChainSegment, xfA: Transform, #by_ptr circleB: Circle, xfB: Transform) -> Manifold --- // Compute the contact manifold between an segment and a capsule - CollideSmoothSegmentAndCapsule :: proc(#by_ptr smoothSegmentA: SmoothSegment, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform, cache: ^DistanceCache) -> Manifold --- + CollideChainSegmentAndCapsule :: proc(#by_ptr segmentA: ChainSegment, xfA: Transform, #by_ptr capsuleB: Capsule, xfB: Transform, cache: ^SimplexCache) -> Manifold --- - // Compute the contact manifold between a smooth segment and a rounded polygon - CollideSmoothSegmentAndPolygon :: proc(#by_ptr smoothSegmentA: SmoothSegment, xfA: Transform, #by_ptr polygonB: Polygon, xfB: Transform, cache: ^DistanceCache) -> Manifold --- + // Compute the contact manifold between a chain segment and a rounded polygon + CollideChainSegmentAndPolygon :: proc(#by_ptr segmentA: ChainSegment, xfA: Transform, #by_ptr polygonB: Polygon, xfB: Transform, cache: ^SimplexCache) -> Manifold --- } @@ -365,7 +393,7 @@ foreign lib { DynamicTree_Destroy :: proc(tree: ^DynamicTree) --- // Create a proxy. Provide an AABB and a userData value. - DynamicTree_CreateProxy :: proc(tree: ^DynamicTree, aabb: AABB, categoryBits: u32, userData: i32) -> i32 --- + DynamicTree_CreateProxy :: proc(tree: ^DynamicTree, aabb: AABB, categoryBits: u64, userData: u64) -> i32 --- // Destroy a proxy. This asserts if the id is invalid. DynamicTree_DestroyProxy :: proc(tree: ^DynamicTree, proxyId: i32) --- @@ -376,50 +404,52 @@ foreign lib { // Enlarge a proxy and enlarge ancestors as necessary. DynamicTree_EnlargeProxy :: proc(tree: ^DynamicTree, proxyId: i32, aabb: AABB) --- - // Query an AABB for overlapping proxies. The callback class - // is called for each proxy that overlaps the supplied AABB. - DynamicTree_Query :: proc(#by_ptr tree: DynamicTree, aabb: AABB, maskBits: u32, callback: TreeQueryCallbackFcn, ctx: rawptr) --- + // Modify the category bits on a proxy. This is an expensive operation. + DynamicTree_SetCategoryBits :: proc(tree: ^DynamicTree, proxyId: i32, categoryBits: u64) --- - // Ray-cast against the proxies in the tree. This relies on the callback - // to perform a exact ray-cast in the case were the proxy contains a shape. + // Get the category bits on a proxy. + DynamicTree_GetCategoryBits :: proc(tree: ^DynamicTree, proxyId: i32) --- + + // Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB. + // @return performance data + DynamicTree_Query :: proc(#by_ptr tree: DynamicTree, aabb: AABB, maskBits: u64, callback: TreeQueryCallbackFcn, ctx: rawptr) -> TreeStats --- + + // Ray cast against the proxies in the tree. This relies on the callback + // to perform a exact ray cast in the case were the proxy contains a shape. // The callback also performs the any collision filtering. This has performance // roughly equal to k * log(n), where k is the number of collisions and n is the // number of proxies in the tree. - // Bit-wise filtering using mask bits can greatly improve performance in some scenarios. - // @param tree the dynamic tree to ray cast - // @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1) - // @param maskBits filter bits: `bool accept = (maskBits & node->categoryBits) != 0 ---` + // Bit-wise filtering using mask bits can greatly improve performance in some scenarios. + // However, this filtering may be approximate, so the user should still apply filtering to results. + // @param tree the dynamic tree to ray cast + // @param input the ray cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1) + // @param maskBits mask bit hint: `bool accept = (maskBits & node->categoryBits) != 0;` // @param callback a callback class that is called for each proxy that is hit by the ray - // @param context user context that is passed to the callback - DynamicTree_RayCast :: proc(#by_ptr tree: DynamicTree, #by_ptr input: RayCastInput, maskBits: u32, callback: TreeRayCastCallbackFcn, ctx: rawptr) --- + // @param context user context that is passed to the callback + // @return performance data + DynamicTree_RayCast :: proc(#by_ptr tree: DynamicTree, #by_ptr input: RayCastInput, maskBits: u64, callback: TreeRayCastCallbackFcn, ctx: rawptr) -> TreeStats --- - // Ray-cast against the proxies in the tree. This relies on the callback - // to perform a exact ray-cast in the case were the proxy contains a shape. + // Ray cast against the proxies in the tree. This relies on the callback + // to perform a exact ray cast in the case were the proxy contains a shape. // The callback also performs the any collision filtering. This has performance // roughly equal to k * log(n), where k is the number of collisions and n is the // number of proxies in the tree. // @param tree the dynamic tree to ray cast - // @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). + // @param input the ray cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). // @param maskBits filter bits: `bool accept = (maskBits & node->categoryBits) != 0 ---` // @param callback a callback class that is called for each proxy that is hit by the shape // @param context user context that is passed to the callback - DynamicTree_ShapeCast :: proc(#by_ptr tree: DynamicTree, #by_ptr input: ShapeCastInput, maskBits: u32, callback: TreeShapeCastCallbackFcn, ctx: rawptr) --- + // @return performance data + DynamicTree_ShapeCast :: proc(#by_ptr tree: DynamicTree, #by_ptr input: ShapeCastInput, maskBits: u32, callback: TreeShapeCastCallbackFcn, ctx: rawptr) -> TreeStats --- - // Validate this tree. For testing. - DynamicTree_Validate :: proc(#by_ptr tree: DynamicTree) --- - - // Compute the height of the binary tree in O(N) time. Should not be - // called often. + // Get the height of the binary tree. DynamicTree_GetHeight :: proc(#by_ptr tree: DynamicTree) -> c.int --- - // Get the maximum balance of the tree. The balance is the difference in height of the two children of a node. - DynamicTree_GetMaxBalance :: proc(#by_ptr tree: DynamicTree) -> c.int --- - // Get the ratio of the sum of the node areas to the root area. DynamicTree_GetAreaRatio :: proc(#by_ptr tree: DynamicTree) -> f32 --- - // Build an optimal tree. Very expensive. For testing. - DynamicTree_RebuildBottomUp :: proc(tree: ^DynamicTree) --- + // Get the bounding box that contains the entire tree + DynamicTree_GetRootBounds :: proc(#by_ptr tree: DynamicTree) -> AABB --- // Get the number of proxies created DynamicTree_GetProxyCount :: proc(#by_ptr tree: DynamicTree) -> c.int --- @@ -427,29 +457,47 @@ foreign lib { // Rebuild the tree while retaining subtrees that haven't changed. Returns the number of boxes sorted. DynamicTree_Rebuild :: proc(tree: ^DynamicTree, fullBuild: bool) -> c.int --- - // Shift the world origin. Useful for large worlds. - // The shift formula is: position -= newOrigin - // @param tree the tree to shift - // @param newOrigin the new origin with respect to the old origin - DynamicTree_ShiftOrigin :: proc(tree: ^DynamicTree, newOrigin: Vec2) --- - // Get the number of bytes used by this tree DynamicTree_GetByteCount :: proc(#by_ptr tree: DynamicTree) -> c.int --- + + // Get proxy user data + DynamicTree_GetUserData :: proc(#by_ptr tree: DynamicTree, proxyId: c.int) -> u64 --- + + // Get the AABB of a proxy + DynamicTree_GetAABB :: proc(#by_ptr tree: DynamicTree, proxyId: c.int) -> AABB --- + + // Validate this tree. For testing. + DynamicTree_Validate :: proc(#by_ptr tree: DynamicTree) --- + + // Validate this tree has no enlarged AABBs. For testing. + DynamicTree_ValidateNoEnlarged :: proc(#by_ptr tree: DynamicTree) --- } -// Get proxy user data -// @return the proxy user data or 0 if the id is invalid +/** + * @defgroup character Character mover + * Character movement solver + * @{ + */ + @(require_results) -DynamicTree_GetUserData :: #force_inline proc "contextless" (tree: DynamicTree, proxyId: i32) -> i32 { - return tree.nodes[proxyId].userData +SolvePlanes :: proc(position: Vec2, planes: []CollisionPlane) -> PlaneSolverResult { + foreign lib { + b2SolvePlanes :: proc "c" (position: Vec2, planes: [^]CollisionPlane, count: i32) -> PlaneSolverResult --- + } + + return b2SolvePlanes(position, raw_data(planes), i32(len(planes))) } -// Get the AABB of a proxy @(require_results) -DynamicTree_GetAABB :: #force_inline proc "contextless" (tree: DynamicTree, proxyId: i32) -> AABB { - return tree.nodes[proxyId].aabb +ClipVector :: proc(vector: Vec2, planes: []CollisionPlane) -> Vec2 { + foreign lib { + b2ClipVector :: proc "c" (vector: Vec2, planes: [^]CollisionPlane, count: i32) -> Vec2 --- + } + + return b2ClipVector(vector, raw_data(planes), i32(len(planes))) } +/**@}*/ @(link_prefix="b2", default_calling_convention="c", require_results) @@ -477,8 +525,8 @@ foreign lib { // Simulate a world for one time step. This performs collision detection, integration, and constraint solution. // @param worldId The world to simulate - // @param timeStep The amount of time to simulate, this should be a fixed number. Typically 1/60. - // @param subStepCount The number of sub-steps, increasing the sub-step count can increase accuracy. Typically 4. + // @param timeStep The amount of time to simulate, this should be a fixed number. Usually 1/60. + // @param subStepCount The number of sub-steps, increasing the sub-step count can increase accuracy. Usually 4. World_Step :: proc(worldId: WorldId, timeStep: f32 , subStepCount: c.int) --- // Call this to draw shapes and other debug draw data @@ -494,63 +542,73 @@ foreign lib { World_GetContactEvents :: proc(worldId: WorldId) -> ContactEvents --- // Overlap test for all shapes that *potentially* overlap the provided AABB - World_OverlapAABB :: proc(worldId: WorldId, aabb: AABB, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) --- + World_OverlapAABB :: proc(worldId: WorldId, aabb: AABB, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) -> TreeStats --- - // Overlap test for for all shapes that overlap the provided circle - World_OverlapCircle :: proc(worldId: WorldId, #by_ptr circle: Circle, transform: Transform, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) --- - - // Overlap test for all shapes that overlap the provided capsule - World_OverlapCapsule :: proc(worldId: WorldId, #by_ptr capsule: Capsule, transform: Transform, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) --- - - // Overlap test for all shapes that overlap the provided polygon - World_OverlapPolygon :: proc(worldId: WorldId, #by_ptr polygon: Polygon, transform: Transform, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) --- + // Overlap test for all shapes that overlap the provided shape proxy. + World_OverlapShape :: proc(worldId: WorldId, #by_ptr proxy: ShapeProxy, filter: QueryFilter, fcn: OverlapResultFcn, ctx: rawptr) -> TreeStats --- // Cast a ray into the world to collect shapes in the path of the ray. // Your callback function controls whether you get the closest point, any point, or n-points. // The ray-cast ignores shapes that contain the starting point. + // @note The callback function may receive shapes in any order // @param worldId The world to cast the ray against // @param origin The start point of the ray // @param translation The translation of the ray from the start point to the end point // @param filter Contains bit flags to filter unwanted shapes from the results - // @param fcn A user implemented callback function - // @param context A user context that is passed along to the callback function - // @note The callback function may receive shapes in any order - World_CastRay :: proc(worldId: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) --- + // @param fcn A user implemented callback function + // @param context A user context that is passed along to the callback function + // @return traversal performance counters + World_CastRay :: proc(worldId: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) -> TreeStats --- // Cast a ray into the world to collect the closest hit. This is a convenience function. // This is less general than b2World_CastRay() and does not allow for custom filtering. World_CastRayClosest :: proc(worldId: WorldId, origin: Vec2, translation: Vec2, filter: QueryFilter) -> RayResult --- - // Cast a circle through the world. Similar to a cast ray except that a circle is cast instead of a point. - World_CastCircle :: proc(worldId: WorldId, #by_ptr circle: Circle, originTransform: Transform, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) --- + // Cast a shape through the world. Similar to a cast ray except that a shape is cast instead of a point. + // @see World_CastRay + World_CastShape :: proc(worldId: WorldId, #by_ptr shape: ShapeProxy, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) -> TreeStats --- - // Cast a capsule through the world. Similar to a cast ray except that a capsule is cast instead of a point. - World_CastCapsule :: proc(worldId: WorldId, #by_ptr capsule: Capsule, originTransform: Transform, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) --- + // Cast a capsule mover through the world. This is a special shape cast that handles sliding along other shapes while reducing + // clipping. + World_CastMover :: proc(worldId: WorldId, #by_ptr mover: Capsule, translation: Vec2, filter: QueryFilter) -> f32 --- - // Cast a polygon through the world. Similar to a cast ray except that a polygon is cast instead of a point. - World_CastPolygon :: proc(worldId: WorldId, #by_ptr polygon: Polygon, originTransform: Transform, translation: Vec2, filter: QueryFilter, fcn: CastResultFcn, ctx: rawptr) --- + // Collide a capsule mover with the world, gathering collision planes that can be fed to b2SolvePlanes. Useful for + // kinematic character movement. + World_CollideMover :: proc(worldId: WorldId, #by_ptr mover: Capsule, filter: QueryFilter, fcn: PlaneResultFcn, ctx: rawptr) --- // Enable/disable sleep. If your application does not need sleeping, you can gain some performance // by disabling sleep completely at the world level. // @see WorldDef World_EnableSleeping :: proc(worldId: WorldId, flag: bool) --- + // Is body sleeping enabled? + World_IsSleepingEnabled :: proc(worldId: WorldId) -> bool --- + // Enable/disable continuous collision between dynamic and static bodies. Generally you should keep continuous // collision enabled to prevent fast moving objects from going through static objects. The performance gain from // disabling continuous collision is minor. // @see WorldDef World_EnableContinuous :: proc(worldId: WorldId, flag: bool) --- + // Is continuous collision enabled? + World_IsContinuousEnabled :: proc(worldId: WorldId) -> bool --- + // Adjust the restitution threshold. It is recommended not to make this value very small - // because it will prevent bodies from sleeping. Typically in meters per second. + // because it will prevent bodies from sleeping. Usually in meters per second. // @see WorldDef World_SetRestitutionThreshold :: proc(worldId: WorldId, value: f32) --- + // Get the restitution speed threshold. Usually in meters per second. + World_GetRestitutionThreshold :: proc(worldId: WorldId) -> f32 --- + // Adjust the hit event threshold. This controls the collision velocity needed to generate a b2ContactHitEvent. - // Typically in meters per second. + // Usually in meters per second. // @see WorldDef::hitEventThreshold World_SetHitEventThreshold :: proc(worldId: WorldId, value: f32) --- + // Get the hit event speed threshold. Usually in meters per second. + World_GetHitEventThreshold :: proc(worldId: WorldId) -> f32 --- + // Register the custom filter callback. This is optional. World_SetCustomFilterCallback :: proc(worldId: WorldId, fcn: CustomFilterFcn, ctx: rawptr) --- @@ -558,7 +616,7 @@ foreign lib { World_SetPreSolveCallback :: proc(worldId: WorldId, fcn: PreSolveFcn, ctx: rawptr) --- // Set the gravity vector for the entire world. Box2D has no concept of an up direction and this - // is left as a decision for the application. Typically in m/s^2. + // is left as a decision for the application. Usually in m/s^2. // @see WorldDef World_SetGravity :: proc(worldId: WorldId, gravity: Vec2) --- @@ -567,31 +625,66 @@ foreign lib { // Apply a radial explosion // @param worldId The world id - // @param position The center of the explosion - // @param radius The radius of the explosion - // @param impulse The impulse of the explosion, typically in kg * m / s or N * s. - World_Explode :: proc(worldId: WorldId, position: Vec2, radius: f32, impulse: f32) --- + // @param explosionDef The explosion definition + World_Explode :: proc(worldId: WorldId, #by_ptr explosionDef: ExplosionDef) --- // Adjust contact tuning parameters // @param worldId The world id // @param hertz The contact stiffness (cycles per second) // @param dampingRatio The contact bounciness with 1 being critical damping (non-dimensional) - // @param pushVelocity The maximum contact constraint push out velocity (meters per second) + // @param pushSpeed The maximum contact constraint push out speed (meters per second) // @note Advanced feature - World_SetContactTuning :: proc(worldId: WorldId, hertz: f32, dampingRatio: f32, pushVelocity: f32) --- + World_SetContactTuning :: proc(worldId: WorldId, hertz: f32, dampingRatio: f32, pushSpeed: f32) --- + + // Adjust joint tuning parameters + // @param worldId The world id + // @param hertz The contact stiffness (cycles per second) + // @param dampingRatio The contact bounciness with 1 being critical damping (non-dimensional) + // @note Advanced feature + World_SetJointTuning :: proc(worldId: WorldId, hertz: f32, dampingRatio: f32) --- + + // Set the maximum linear speed. Usually in m/s. + World_SetMaximumLinearSpeed :: proc(worldId: WorldId, maximumLinearSpeed: f32) --- + + // Get the maximum linear speed. Usually in m/s. + World_GetMaximumLinearSpeed :: proc(worldId: WorldId) -> f32 --- // Enable/disable constraint warm starting. Advanced feature for testing. Disabling - // sleeping greatly reduces stability and provides no performance gain. + // warm starting greatly reduces stability and provides no performance gain. World_EnableWarmStarting :: proc(worldId: WorldId, flag: bool) --- + // Is constraint warm starting enabled? + World_IsWarmStartingEnabled :: proc(worldId: WorldId) -> bool --- + + // Get the number of awake bodies. + World_GetAwakeBodyCount :: proc(worldId: WorldId) -> c.int --- + // Get the current world performance profile World_GetProfile :: proc(worldId: WorldId) -> Profile --- // Get world counters and sizes World_GetCounters :: proc(worldId: WorldId) -> Counters --- + // Set the user data pointer. + World_SetUserData :: proc(worldId: WorldId, userData: rawptr) --- + + // Get the user data pointer. + World_GetUserData :: proc(worldId: WorldId) -> rawptr --- + + // Set the friction callback. Passing nil resets to default. + World_SetFrictionCallback :: proc(worldId: WorldId, callback: FrictionCallback) --- + + // Set the restitution callback. Passing nil resets to default. + World_SetRestitutionCallback :: proc(worldId: WorldId, callback: RestitutionCallback) --- + // Dump memory stats to box2d_memory.txt World_DumpMemoryStats :: proc(worldId: WorldId) --- + + // This is for internal testing + World_RebuildStaticTree :: proc(worldId: WorldId) --- + + // This is for internal testing + World_EnableSpeculative :: proc(worldId: WorldId, flag: bool) --- } @@ -625,6 +718,12 @@ foreign lib { // properties regardless of the automatic mass setting. Body_SetType :: proc(bodyId: BodyId, type: BodyType) --- + // Set the body name. Up to 32 characters excluding 0 termination. + Body_SetName :: proc(bodyId: BodyId, name: cstring) --- + + // Get the body name. May be nil. + Body_GetName :: proc(bodyId: BodyId) -> cstring --- + // Set the user data for a body Body_SetUserData :: proc(bodyId: BodyId, userData: rawptr) --- @@ -657,23 +756,34 @@ foreign lib { // Get a world vector on a body given a local vector Body_GetWorldVector :: proc(bodyId: BodyId, localVector: Vec2) -> Vec2 --- - // Get the linear velocity of a body's center of mass. Typically in meters per second. + // Get the linear velocity of a body's center of mass. Usually in meters per second. Body_GetLinearVelocity :: proc(bodyId: BodyId) -> Vec2 --- // Get the angular velocity of a body in radians per second Body_GetAngularVelocity :: proc(bodyId: BodyId) -> f32 --- - // Set the linear velocity of a body. Typically in meters per second. + // Set the linear velocity of a body. Usually in meters per second. Body_SetLinearVelocity :: proc(bodyId: BodyId, linearVelocity: Vec2) --- // Set the angular velocity of a body in radians per second Body_SetAngularVelocity :: proc(bodyId: BodyId, angularVelocity: f32) --- + // Set the velocity to reach the given transform after a given time step. + // The result will be close but maybe not exact. This is meant for kinematic bodies. + // This will automatically wake the body if asleep. + Body_SetTargetTransform :: proc(bodyId: BodyId, target: Transform, timeStep: f32) --- + + // Get the linear velocity of a local point attached to a body. Usually in meters per second. + Body_GetLocalPointVelocity :: proc(bodyId: BodyId, localPoint: Vec2) -> Vec2 --- + + // Get the linear velocity of a world point attached to a body. Usually in meters per second. + GetWorldPointVelocity :: proc(bodyId: BodyId, worldPoint: Vec2) -> Vec2 --- + // Apply a force at a world point. If the force is not applied at the center of mass, // it will generate a torque and affect the angular velocity. This optionally wakes up the body. // The force is ignored if the body is not awake. // @param bodyId The body id - // @param force The world force vector, typically in newtons (N) + // @param force The world force vector, usually in newtons (N) // @param point The world position of the point of application // @param wake Option to wake up the body Body_ApplyForce :: proc(bodyId: BodyId, force: Vec2, point: Vec2, wake: bool) --- @@ -688,7 +798,7 @@ foreign lib { // Apply a torque. This affects the angular velocity without affecting the linear velocity. // This optionally wakes the body. The torque is ignored if the body is not awake. // @param bodyId The body id - // @param torque about the z-axis (out of the screen), typically in N*m. + // @param torque about the z-axis (out of the screen), usually in N*m. // @param wake also wake up the body Body_ApplyTorque :: proc(bodyId: BodyId, torque: f32, wake: bool) --- @@ -697,7 +807,7 @@ foreign lib { // is not at the center of mass. This optionally wakes the body. // The impulse is ignored if the body is not awake. // @param bodyId The body id - // @param impulse the world impulse vector, typically in N*s or kg*m/s. + // @param impulse the world impulse vector, usually in N*s or kg*m/s. // @param point the world position of the point of application. // @param wake also wake up the body // @warning This should be used for one-shot impulses. If you need a steady force, @@ -707,7 +817,7 @@ foreign lib { // Apply an impulse to the center of mass. This immediately modifies the velocity. // The impulse is ignored if the body is not awake. This optionally wakes the body. // @param bodyId The body id - // @param impulse the world impulse vector, typically in N*s or kg*m/s. + // @param impulse the world impulse vector, usually in N*s or kg*m/s. // @param wake also wake up the body // @warning This should be used for one-shot impulses. If you need a steady force, // use a force instead, which will work better with the sub-stepping solver. @@ -716,17 +826,17 @@ foreign lib { // Apply an angular impulse. The impulse is ignored if the body is not awake. // This optionally wakes the body. // @param bodyId The body id - // @param impulse the angular impulse, typically in units of kg*m*m/s + // @param impulse the angular impulse, usually in units of kg*m*m/s // @param wake also wake up the body // @warning This should be used for one-shot impulses. If you need a steady force, // use a force instead, which will work better with the sub-stepping solver. Body_ApplyAngularImpulse :: proc(bodyId: BodyId, impulse: f32, wake: bool) --- - // Get the mass of the body, typically in kilograms + // Get the mass of the body, usually in kilograms Body_GetMass :: proc(bodyId: BodyId) -> f32 --- - // Get the inertia tensor of the body, typically in kg*m^2 - Body_GetInertiaTensor :: proc(bodyId: BodyId) -> f32 --- + // Get the rotational inertia of the body, usually in kg*m^2 + Body_GetRotationalInertia :: proc(bodyId: BodyId) -> f32 --- // Get the center of mass position of the body in local space Body_GetLocalCenterOfMass :: proc(bodyId: BodyId) -> Vec2 --- @@ -749,13 +859,6 @@ foreign lib { // You should call this regardless of body type. Body_ApplyMassFromShapes :: proc(bodyId: BodyId) --- - // Set the automatic mass setting. Normally this is set in BodyDef before creation. - // @see BodyDef::automaticMass - Body_SetAutomaticMass :: proc(bodyId: BodyId, automaticMass: bool ) --- - - // Get the automatic mass setting - Body_GetAutomaticMass :: proc(bodyId: BodyId) -> bool --- - // Adjust the linear damping. Normally this is set in BodyDef before creation. Body_SetLinearDamping :: proc(bodyId: BodyId, linearDamping: f32) --- @@ -789,10 +892,10 @@ foreign lib { // Returns true if sleeping is enabled for this body Body_IsSleepEnabled :: proc(bodyId: BodyId) -> bool --- - // Set the sleep threshold, typically in meters per second - Body_SetSleepThreshold :: proc(bodyId: BodyId, sleepVelocity: f32) --- + // Set the sleep threshold, usually in meters per second + Body_SetSleepThreshold :: proc(bodyId: BodyId, sleepThreshold: f32) --- - // Get the sleep threshold, typically in meters per second. + // Get the sleep threshold, usually in meters per second. Body_GetSleepThreshold :: proc(bodyId: BodyId) -> f32 --- // Returns true if this body is enabled @@ -817,9 +920,17 @@ foreign lib { // Is this body a bullet? Body_IsBullet :: proc(bodyId: BodyId) -> bool --- + // Enable/disable contact events on all shapes. + // @see b2ShapeDef::enableContactEvents + // @warning changing this at runtime may cause mismatched begin/end touch events + Body_EnableContactEvents :: proc(bodyId: BodyId, flag: bool) --- + // Enable/disable hit events on all shapes // @see b2ShapeDef::enableHitEvents - Body_EnableHitEvents :: proc(bodyId: BodyId, enableHitEvents: bool) --- + Body_EnableHitEvents :: proc(bodyId: BodyId, flag: bool) --- + + // Get the world that owns this body + Body_GetWorld :: proc(bodyId: BodyId) -> WorldId --- // Get the number of shapes on this body Body_GetShapeCount :: proc(bodyId: BodyId) -> c.int --- @@ -898,8 +1009,10 @@ foreign lib { // @return the shape id for accessing the shape CreatePolygonShape :: proc(bodyId: BodyId, #by_ptr def: ShapeDef, #by_ptr polygon: Polygon) -> ShapeId --- - // Destroy a shape - DestroyShape :: proc(shapeId: ShapeId) --- + // Destroy a shape. You may defer the body mass update which can improve performance if several shapes on a + // body are destroyed at once. + // @see b2Body_ApplyMassFromShapes + DestroyShape :: proc(shapeId: ShapeId, updateBodyMass: bool) --- // Shape identifier validation. Provides validation for up to 64K allocations. Shape_IsValid :: proc(id: ShapeId) -> bool --- @@ -910,7 +1023,12 @@ foreign lib { // Get the id of the body that a shape is attached to Shape_GetBody :: proc(shapeId: ShapeId) -> BodyId --- - // Returns true If the shape is a sensor + // Get the world that owns this shape. + Shape_GetWorld :: proc(shapeId: ShapeId) -> WorldId --- + + // Returns true if the shape is a sensor. It is not possible to change a shape + // from sensor to solid dynamically because this breaks the contract for + // sensor events. Shape_IsSensor :: proc(shapeId: ShapeId) -> bool --- // Set the user data for a shape @@ -920,12 +1038,12 @@ foreign lib { // from an event or query. Shape_GetUserData :: proc(shapeId: ShapeId) -> rawptr --- - // Set the mass density of a shape, typically in kg/m^2. - // This will not update the mass properties on the parent body. + // Set the mass density of a shape, usually in kg/m^2. + // This will optionally update the mass properties on the parent body. // @see b2ShapeDef::density, b2Body_ApplyMassFromShapes - Shape_SetDensity :: proc(shapeId: ShapeId, density: f32) --- + Shape_SetDensity :: proc(shapeId: ShapeId, density: f32, updateBodyMass: bool) --- - // Get the density of a shape, typically in kg/m^2 + // Get the density of a shape, usually in kg/m^2 Shape_GetDensity :: proc(shapeId: ShapeId) -> f32 --- // Set the friction on a shape @@ -942,15 +1060,24 @@ foreign lib { // Get the shape restitution Shape_GetRestitution :: proc(shapeId: ShapeId) -> f32 --- + // Set the shape material identifier + // @see b2ShapeDef::material + Shape_SetMaterial :: proc(shapeId: ShapeId, material: c.int) --- + + // Get the shape material identifier + Shape_GetMaterial :: proc(shapeId: ShapeId) -> c.int --- + // Get the shape filter Shape_GetFilter :: proc(shapeId: ShapeId) -> Filter --- - // Set the current filter. This is almost as expensive as recreating the shape. - // @see b2ShapeDef::filter + // Set the current filter. This is almost as expensive as recreating the shape. This may cause + // contacts to be immediately destroyed. However contacts are not created until the next world step. + // Sensor overlap state is also not updated until the next world step. + // @see b2ShapeDef::filter Shape_SetFilter :: proc(shapeId: ShapeId, filter: Filter) --- - // Enable sensor events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. - // @see b2ShapeDef::isSensor + // Enable sensor events for this shape. + // @see b2ShapeDef::enableSensorEvents Shape_EnableSensorEvents :: proc(shapeId: ShapeId, flag: bool) --- // Returns true if sensor events are enabled @@ -958,6 +1085,7 @@ foreign lib { // Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. // @see b2ShapeDef::enableContactEvents + // @warning changing this at run-time may lead to lost begin/end events Shape_EnableContactEvents :: proc(shapeId: ShapeId, flag: bool) --- // Returns true if contact events are enabled @@ -982,7 +1110,7 @@ foreign lib { Shape_TestPoint :: proc(shapeId: ShapeId, point: Vec2) -> bool --- // Ray cast a shape directly - Shape_RayCast :: proc(shapeId: ShapeId, origin: Vec2, translation: Vec2) -> CastOutput --- + Shape_RayCast :: proc(shapeId: ShapeId, #by_ptr input: RayCastInput) -> CastOutput --- // Get a copy of the shape's circle. Asserts the type is correct. Shape_GetCircle :: proc(shapeId: ShapeId) -> Circle --- @@ -990,9 +1118,9 @@ foreign lib { // Get a copy of the shape's line segment. Asserts the type is correct. Shape_GetSegment :: proc(shapeId: ShapeId) -> Segment --- - // Get a copy of the shape's smooth line segment. These come from chain shapes. + // Get a copy of the shape's chain segment. These come from chain shapes. // Asserts the type is correct. - Shape_GetSmoothSegment :: proc(shapeId: ShapeId) -> SmoothSegment --- + Shape_GetChainSegment :: proc(shapeId: ShapeId) -> ChainSegment --- // Get a copy of the shape's capsule. Asserts the type is correct. Shape_GetCapsule :: proc(shapeId: ShapeId) -> Capsule --- @@ -1018,16 +1146,34 @@ foreign lib { // @see b2Body_ApplyMassFromShapes Shape_SetPolygon :: proc(shapeId: ShapeId, #by_ptr polygon: Polygon) --- - // Get the parent chain id if the shape type is b2_smoothSegmentShape, otherwise + // Get the parent chain id if the shape type is a chain segment, otherwise // returns b2_nullChainId. Shape_GetParentChain :: proc(shapeId: ShapeId) -> ChainId --- // Get the maximum capacity required for retrieving all the touching contacts on a shape Shape_GetContactCapacity :: proc(shapeId: ShapeId) -> c.int --- + // Get the maximum capacity required for retrieving all the overlapped shapes on a sensor shape. + // This returns 0 if the provided shape is not a sensor. + // @param shapeId the id of a sensor shape + // @returns the required capacity to get all the overlaps in b2Shape_GetSensorOverlaps + Shape_GetSensorCapacity :: proc(shapeId: ShapeId) -> c.int --- + + // Get the overlapped shapes for a sensor shape. + // @param shapeId the id of a sensor shape + // @param overlaps a user allocated array that is filled with the overlapping shapes + // @param capacity the capacity of overlappedShapes + // @returns the number of elements filled in the provided array + // @warning do not ignore the return value, it specifies the valid number of elements + // @warning overlaps may contain destroyed shapes so use b2Shape_IsValid to confirm each overlap + Shape_GetSensorOverlaps :: proc(shapeId: ShapeId, overlaps: [^]ShapeId, capacity: c.int) -> c.int --- + // Get the current world AABB Shape_GetAABB :: proc(shapeId: ShapeId) -> AABB --- + // Get the mass data of a shape + Shape_GetMassData :: proc(shapeId: ShapeId) -> MassData --- + // Get the closest point on a shape to a target point. Target and result are in world space. Shape_GetClosestPoint :: proc(shapeId: ShapeId, target: Vec2) -> Vec2 --- } @@ -1049,21 +1195,44 @@ foreign lib { // Create a chain shape // @see b2ChainDef for details - CreateChain :: proc(bodyId: BodyId, #by_ptr def: ChainDef) -> ChainId --- + CreateChain :: proc(bodyId: BodyId, #by_ptr def: ChainDef) -> ChainId --- // Destroy a chain shape - DestroyChain :: proc(chainId: ChainId) --- + DestroyChain :: proc(chainId: ChainId) --- + + // Get the world that owns this chain shape + Chain_GetWorld :: proc(chainId: ChainId) -> WorldId --- + + // Get the number of segments on this chain + Chain_GetSegmentCount :: proc(chainId: ChainId) -> c.int --- + + // Fill a user array with chain segment shape ids up to the specified capacity. Returns + // the actual number of segments returned. + Chain_GetSegments :: proc(chainId: ChainId, segmentArray: [^]ShapeId, capacity: c.int) -> c.int --- // Set the chain friction // @see b2ChainDef::friction - Chain_SetFriction :: proc(chainId: ChainId, friction: f32) --- + Chain_SetFriction :: proc(chainId: ChainId, friction: f32) --- + + // Get the chain friction + Chain_GetFriction :: proc(chainId: ChainId) -> f32 --- // Set the chain restitution (bounciness) // @see b2ChainDef::restitution - Chain_SetRestitution :: proc(chainId: ChainId, restitution: f32) --- + Chain_SetRestitution :: proc(chainId: ChainId, restitution: f32) --- + + // Get the chain restitution + Chain_GetRestitution :: proc(chainId: ChainId) -> f32 --- + + // Set the chain material + // @see b2ChainDef::material + Chain_SetMaterial :: proc(chainId: ChainId, material: c.int) --- + + // Get the chain material + Chain_GetMaterial :: proc(chainId: ChainId) -> c.int --- // Chain identifier validation. Provides validation for up to 64K allocations. - Chain_IsValid :: proc(id: ChainId) -> bool --- + Chain_IsValid :: proc(id: ChainId) -> bool --- /** * @defgroup joint Joint @@ -1085,6 +1254,9 @@ foreign lib { // Get body B id on a joint Joint_GetBodyB :: proc(jointId: JointId) -> BodyId --- + // Get the world that owns this joint + Joint_GetWorld :: proc(jointId: JointId) -> WorldId --- + // Get the local anchor on bodyA Joint_GetLocalAnchorA :: proc(jointId: JointId) -> Vec2 --- @@ -1106,10 +1278,10 @@ foreign lib { // Wake the bodies connect to this joint Joint_WakeBodies :: proc(jointId: JointId) --- - // Get the current constraint force for this joint + // Get the current constraint force for this joint. Usually in Newtons. Joint_GetConstraintForce :: proc(jointId: JointId) -> Vec2 --- - // Get the current constraint torque for this joint + // Get the current constraint torque for this joint. Usually in Newton * meters. Joint_GetConstraintTorque :: proc(jointId: JointId) -> f32 --- /** @@ -1142,10 +1314,10 @@ foreign lib { DistanceJoint_SetSpringDampingRatio :: proc(jointId: JointId, dampingRatio: f32) --- // Get the spring Hertz - DistanceJoint_GetHertz :: proc(jointId: JointId) -> f32 --- + DistanceJoint_GetSpringHertz :: proc(jointId: JointId) -> f32 --- // Get the spring damping ratio - DistanceJoint_GetDampingRatio :: proc(jointId: JointId) -> f32 --- + DistanceJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 --- // Enable joint limit. The limit only works if the joint spring is enabled. Otherwise the joint is rigid // and the limit has no effect. @@ -1172,19 +1344,19 @@ foreign lib { // Is the distance joint motor enabled? DistanceJoint_IsMotorEnabled :: proc(jointId: JointId) -> bool --- - // Set the distance joint motor speed, typically in meters per second + // Set the distance joint motor speed, usually in meters per second DistanceJoint_SetMotorSpeed :: proc(jointId: JointId, motorSpeed: f32) --- - // Get the distance joint motor speed, typically in meters per second + // Get the distance joint motor speed, usually in meters per second DistanceJoint_GetMotorSpeed :: proc(jointId: JointId) -> f32 --- - // Set the distance joint maximum motor force, typically in newtons + // Set the distance joint maximum motor force, usually in newtons DistanceJoint_SetMaxMotorForce :: proc(jointId: JointId, force: f32) --- - // Get the distance joint maximum motor force, typically in newtons + // Get the distance joint maximum motor force, usually in newtons DistanceJoint_GetMaxMotorForce :: proc(jointId: JointId) -> f32 --- - // Get the distance joint current motor force, typically in newtons + // Get the distance joint current motor force, usually in newtons DistanceJoint_GetMotorForce :: proc(jointId: JointId) -> f32 --- /** @@ -1198,7 +1370,7 @@ foreign lib { // Create a motor joint // @see b2MotorJointDef for details - CreateMotorJoint :: proc(worldId: WorldId, def: MotorJointDef) -> JointId --- + CreateMotorJoint :: proc(worldId: WorldId, #by_ptr def: MotorJointDef) -> JointId --- // Set the motor joint linear offset target MotorJoint_SetLinearOffset :: proc(jointId: JointId, linearOffset: Vec2) --- @@ -1212,22 +1384,22 @@ foreign lib { // Get the motor joint angular offset target in radians MotorJoint_GetAngularOffset :: proc(jointId: JointId) -> f32 --- - // Set the motor joint maximum force, typically in newtons + // Set the motor joint maximum force, usually in newtons MotorJoint_SetMaxForce :: proc(jointId: JointId, maxForce: f32) --- - // Get the motor joint maximum force, typically in newtons + // Get the motor joint maximum force, usually in newtons MotorJoint_GetMaxForce :: proc(jointId: JointId) -> f32 --- - // Set the motor joint maximum torque, typically in newton-meters + // Set the motor joint maximum torque, usually in newton-meters MotorJoint_SetMaxTorque :: proc(jointId: JointId, maxTorque: f32) --- - // Get the motor joint maximum torque, typically in newton-meters + // Get the motor joint maximum torque, usually in newton-meters MotorJoint_GetMaxTorque :: proc(jointId: JointId) -> f32 --- - // Set the motor joint correction factor, typically in [0, 1] + // Set the motor joint correction factor, usually in [0, 1] MotorJoint_SetCorrectionFactor :: proc(jointId: JointId, correctionFactor: f32) --- - // Get the motor joint correction factor, typically in [0, 1] + // Get the motor joint correction factor, usually in [0, 1] MotorJoint_GetCorrectionFactor :: proc(jointId: JointId) -> f32 --- /**@}*/ @@ -1262,14 +1434,29 @@ foreign lib { // Get the mouse joint damping ratio, non-dimensional MouseJoint_GetSpringDampingRatio :: proc(jointId: JointId) -> f32 --- - // Set the mouse joint maximum force, typically in newtons + // Set the mouse joint maximum force, usually in newtons MouseJoint_SetMaxForce :: proc(jointId: JointId, maxForce: f32) --- - // Get the mouse joint maximum force, typically in newtons + // Get the mouse joint maximum force, usually in newtons MouseJoint_GetMaxForce :: proc(jointId: JointId) -> f32 --- /**@}*/ + /** + * @defgroup filter_joint Filter Joint + * @brief Functions for the filter joint. + * + * The filter joint is used to disable collision between two bodies. As a side effect of being a joint, it also + * keeps the two bodies in the same simulation island. + * @{ + */ + + // Create a filter joint. + // @see b2FilterJointDef for details + CreateFilterJoint :: proc(worldId: WorldId, #by_ptr def: FilterJointDef) -> JointId --- + + /**@}*/ + /** * @defgroup prismatic_joint Prismatic Joint * @brief A prismatic joint allows for translation along a single axis with no rotation. @@ -1323,21 +1510,27 @@ foreign lib { // Is the prismatic joint motor enabled? PrismaticJoint_IsMotorEnabled :: proc(jointId: JointId) -> bool --- - // Set the prismatic joint motor speed, typically in meters per second + // Set the prismatic joint motor speed, usually in meters per second PrismaticJoint_SetMotorSpeed :: proc(jointId: JointId, motorSpeed: f32) --- - // Get the prismatic joint motor speed, typically in meters per second + // Get the prismatic joint motor speed, usually in meters per second PrismaticJoint_GetMotorSpeed :: proc(jointId: JointId) -> f32 --- - // Set the prismatic joint maximum motor force, typically in newtons + // Set the prismatic joint maximum motor force, usually in newtons PrismaticJoint_SetMaxMotorForce :: proc(jointId: JointId, force: f32) --- - // Get the prismatic joint maximum motor force, typically in newtons + // Get the prismatic joint maximum motor force, usually in newtons PrismaticJoint_GetMaxMotorForce :: proc(jointId: JointId) -> f32 --- - // Get the prismatic joint current motor force, typically in newtons + // Get the prismatic joint current motor force, usually in newtons PrismaticJoint_GetMotorForce :: proc(jointId: JointId) -> f32 --- + // Get the current joint translation, usually in meters. + PrismaticJoint_GetTranslation :: proc(jointId: JointId) -> f32 --- + + // Get the current joint translation speed, usually in meters per second. + PrismaticJoint_GetSpeed :: proc(jointId: JointId) -> f32 --- + /** * @defgroup revolute_joint Revolute Joint * @brief A revolute joint allows for relative rotation in the 2D plane with no relative translation. @@ -1353,6 +1546,9 @@ foreign lib { // Enable/disable the revolute joint spring RevoluteJoint_EnableSpring :: proc(jointId: JointId, enableSpring: bool) --- + // Is the revolute spring enabled? + RevoluteJoint_IsSpringEnabled :: proc(jointId: JointId) -> bool --- + // Set the revolute joint spring stiffness in Hertz RevoluteJoint_SetSpringHertz :: proc(jointId: JointId, hertz: f32) --- @@ -1381,7 +1577,8 @@ foreign lib { // Get the revolute joint upper limit in radians RevoluteJoint_GetUpperLimit :: proc(jointId: JointId) -> f32 --- - // Set the revolute joint limits in radians + // Set the revolute joint limits in radians. It is expected that lower <= upper + // and that -0.95 * B2_PI <= lower && upper <= -0.95 * B2_PI. RevoluteJoint_SetLimits :: proc(jointId: JointId, lower, upper: f32) --- // Enable/disable a revolute joint motor @@ -1396,13 +1593,13 @@ foreign lib { // Get the revolute joint motor speed in radians per second RevoluteJoint_GetMotorSpeed :: proc(jointId: JointId) -> f32 --- - // Get the revolute joint current motor torque, typically in newton-meters + // Get the revolute joint current motor torque, usually in newton-meters RevoluteJoint_GetMotorTorque :: proc(jointId: JointId) -> f32 --- - // Set the revolute joint maximum motor torque, typically in newton-meters + // Set the revolute joint maximum motor torque, usually in newton-meters RevoluteJoint_SetMaxMotorTorque :: proc(jointId: JointId, torque: f32) --- - // Get the revolute joint maximum motor torque, typically in newton-meters + // Get the revolute joint maximum motor torque, usually in newton-meters RevoluteJoint_GetMaxMotorTorque :: proc(jointId: JointId) -> f32 --- /**@}*/ @@ -1421,6 +1618,12 @@ foreign lib { // @see b2WeldJointDef for details CreateWeldJoint :: proc(worldId: WorldId, #by_ptr def: WeldJointDef) -> JointId --- + // Get the weld joint reference angle in radians + WeldJoint_GetReferenceAngle :: proc(jointId: JointId) -> f32 --- + + // Set the weld joint reference angle in radians, must be in [-pi,pi]. + WeldJoint_SetReferenceAngle :: proc(jointId: JointId, angleInRadians: f32) --- + // Set the weld joint linear stiffness in Hertz. 0 is rigid. WeldJoint_SetLinearHertz :: proc(jointId: JointId, hertz: f32) --- @@ -1503,22 +1706,24 @@ foreign lib { // Get the wheel joint motor speed in radians per second WheelJoint_GetMotorSpeed :: proc(jointId: JointId) -> f32 --- - // Set the wheel joint maximum motor torque, typically in newton-meters + // Set the wheel joint maximum motor torque, usually in newton-meters WheelJoint_SetMaxMotorTorque :: proc(jointId: JointId, torque: f32) --- - // Get the wheel joint maximum motor torque, typically in newton-meters + // Get the wheel joint maximum motor torque, usually in newton-meters WheelJoint_GetMaxMotorTorque :: proc(jointId: JointId) -> f32 --- - // Get the wheel joint current motor torque, typically in newton-meters + // Get the wheel joint current motor torque, usually in newton-meters WheelJoint_GetMotorTorque :: proc(jointId: JointId) -> f32 --- } IsValid :: proc{ - Float_IsValid, - Vec2_IsValid, - Rot_IsValid, + IsValidFloat, + IsValidVec2, + IsValidRotation, + IsValidAABB, + IsValidPlane, World_IsValid, Body_IsValid, Shape_IsValid, diff --git a/vendor/box2d/build_box2d.sh b/vendor/box2d/build_box2d.sh index 74d75eb57..d6fb3888d 100755 --- a/vendor/box2d/build_box2d.sh +++ b/vendor/box2d/build_box2d.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash set -eu -VERSION="3.0.0" +VERSION="3.1.0" RELEASE="https://github.com/erincatto/box2d/archive/refs/tags/v$VERSION.tar.gz" -cd "$(odin root)"/vendor/box2d +cd "$(dirname "$0")" curl -O -L "$RELEASE" tar -xzvf "v$VERSION.tar.gz" @@ -58,7 +58,7 @@ Darwin) *) rm -rf build mkdir build - cmake $FLAGS -DCMAKE_OSX_ARCHITECTURES=arm64 -S . -B build + cmake $FLAGS -S . -B build cmake --build build cp build/src/libbox2d.a ../lib/box2d_other.a ;; @@ -73,7 +73,8 @@ make -f wasm.Makefile if [[ $? -ne 0 ]]; then printf "\e[30;43mwarning:\e[0m Native Box2D libraries were built successfully, the WASM build failed, likely because your default C compiler and/or linker doesn't support WASM, you can set the CC and LD environment variables to point to a compiler and linker that support it\n" fi +make -f wasm.Makefile clean set -e -rm -rf v3.0.0.tar.gz -rm -rf box2d-3.0.0 +rm -rf "v$VERSION.tar.gz" +rm -rf box2d-"$VERSION" diff --git a/vendor/box2d/collision.odin b/vendor/box2d/collision.odin index 88f3b3a77..b29e2f946 100644 --- a/vendor/box2d/collision.odin +++ b/vendor/box2d/collision.odin @@ -5,9 +5,9 @@ import "core:c" // The maximum number of vertices on a convex polygon. Changing this affects performance even if you // don't use more vertices. -maxPolygonVertices :: 8 +MAX_POLYGON_VERTICES :: 8 -// Low level ray-cast input data +// Low level ray cast input data RayCastInput :: struct { // Start point of the ray cast origin: Vec2, @@ -19,27 +19,37 @@ RayCastInput :: struct { maxFraction: f32, } +// A distance proxy is used by the GJK algorithm. It encapsulates any shape. +// You can provide between 1 and MAX_POLYGON_VERTICES and a radius. +ShapeProxy :: struct { + // The point cloud + points: [MAX_POLYGON_VERTICES]Vec2 `fmt:"v,count"`, + + // The number of points. Must be greater than 0. + count: c.int, + + // The external radius of the point cloud. May be zero. + radius: f32, +} + // Low level shape cast input in generic form. This allows casting an arbitrary point -// cloud wrap with a radius. For example, a circle is a single point with a non-zero radius. -// A capsule is two points with a non-zero radius. A box is four points with a zero radius. +// cloud wrap with a radius. For example, a circle is a single point with a non-zero radius. +// A capsule is two points with a non-zero radius. A box is four points with a zero radius. ShapeCastInput :: struct { - // A point cloud to cast - points: [maxPolygonVertices]Vec2 `fmt:"v,count"`, - - // The number of points - count: i32, - - // The radius around the point cloud - radius: f32, + // A generic shape + proxy: ShapeProxy, // The translation of the shape cast translation: Vec2, // The maximum fraction of the translation to consider, typically 1 maxFraction: f32, + + // Allow shape cast to encroach when initially touching. This only works if the radius is greater than zero. + canEncroach: bool, } -// Low level ray-cast or shape-cast output data +// Low level ray cast or shape-cast output data CastOutput :: struct { // The surface normal at the hit point normal: Vec2, @@ -51,7 +61,7 @@ CastOutput :: struct { fraction: f32, // The number of iterations used - iterations: i32, + iterations: c.int, // Did the cast hit? hit: bool, @@ -93,16 +103,16 @@ Capsule :: struct { // A solid convex polygon. It is assumed that the interior of the polygon is to // the left of each edge. -// Polygons have a maximum number of vertices equal to maxPolygonVertices. +// Polygons have a maximum number of vertices equal to MAX_POLYGON_VERTICES. // In most cases you should not need many vertices for a convex polygon. -// @warning DO NOT fill this out manually, instead use a helper function like -// b2MakePolygon or b2MakeBox. +// @warning DO NOT fill this out manually, instead use a helper function like +// b2MakePolygon or b2MakeBox. Polygon :: struct { // The polygon vertices - vertices: [maxPolygonVertices]Vec2 `fmt:"v,count"`, + vertices: [MAX_POLYGON_VERTICES]Vec2 `fmt:"v,count"`, // The outward normal vectors of the polygon sides - normals: [maxPolygonVertices]Vec2 `fmt:"v,count"`, + normals: [MAX_POLYGON_VERTICES]Vec2 `fmt:"v,count"`, // The centroid of the polygon centroid: Vec2, @@ -111,7 +121,7 @@ Polygon :: struct { radius: f32, // The number of polygon vertices - count: i32, + count: c.int, } // A line segment with two-sided collision. @@ -123,10 +133,10 @@ Segment :: struct { point2: Vec2, } -// A smooth line segment with one-sided collision. Only collides on the right side. +// A line segment with one-sided collision. Only collides on the right side. // Several of these are generated for a chain shape. // ghost1 -> point1 -> point2 -> ghost2 -SmoothSegment :: struct { +ChainSegment :: struct { // The tail ghost vertex ghost1: Vec2, @@ -137,7 +147,7 @@ SmoothSegment :: struct { ghost2: Vec2, // The owning chain shape index (internal usage only) - chainId: i32, + chainId: c.int, } @@ -145,10 +155,10 @@ SmoothSegment :: struct { // @warning Do not modify these values directly, instead use b2ComputeHull() Hull :: struct { // The final points of the hull - points: [maxPolygonVertices]Vec2 `fmt:"v,count"`, + points: [MAX_POLYGON_VERTICES]Vec2 `fmt:"v,count"`, // The number of points - count: i32, + count: c.int, } /** @@ -178,21 +188,11 @@ SegmentDistanceResult :: struct { distanceSquared: f32, } -// A distance proxy is used by the GJK algorithm. It encapsulates any shape. -DistanceProxy :: struct { - // The point cloud - points: [maxPolygonVertices]Vec2 `fmt:"v,count"`, - - // The number of points - count: i32, - - // The external radius of the point cloud - radius: f32, -} - -// Used to warm start b2Distance. Set count to zero on first call or -// use zero initialization. -DistanceCache :: struct { +// Used to warm start the GJK simplex. If you call this function multiple times with nearby +// transforms this might improve performance. Otherwise you can zero initialize this. +// The distance cache must be initialized to zero on the first call. +// Users should generally just zero initialize this structure for each call. +SimplexCache :: struct { // The number of stored simplex points count: u16, @@ -203,15 +203,15 @@ DistanceCache :: struct { indexB: [3]u8 `fmt:"v,count"`, } -emptyDistanceCache :: DistanceCache{} +emptySimplexCache :: SimplexCache{} // Input for b2ShapeDistance DistanceInput :: struct { // The proxy for shape A - proxyA: DistanceProxy, + proxyA: ShapeProxy, // The proxy for shape B - proxyB: DistanceProxy, + proxyB: ShapeProxy, // The world transform for shape A transformA: Transform, @@ -227,6 +227,7 @@ DistanceInput :: struct { DistanceOutput :: struct { pointA: Vec2, // Closest point on shapeA pointB: Vec2, // Closest point on shapeB + normal: Vec2, // Normal vector that points from A to B distance: f32, // The final distance, zero if overlapped iterations: i32, // Number of GJK iterations used simplexCount: i32, // The number of simplexes stored in the simplex array @@ -234,28 +235,29 @@ DistanceOutput :: struct { // Simplex vertex for debugging the GJK algorithm SimplexVertex :: struct { - wA: Vec2, // support point in proxyA - wB: Vec2, // support point in proxyB - w: Vec2, // wB - wA - a: f32, // barycentric coordinate for closest point - indexA: i32, // wA index - indexB: i32, // wB index + wA: Vec2, // support point in proxyA + wB: Vec2, // support point in proxyB + w: Vec2, // wB - wA + a: f32, // barycentric coordinate for closest point + indexA: c.int, // wA index + indexB: c.int, // wB index } // Simplex from the GJK algorithm Simplex :: struct { v1, v2, v3: SimplexVertex `fmt:"v,count"`, // vertices - count: i32, // number of valid vertices + count: c.int, // number of valid vertices } // Input parameters for b2ShapeCast ShapeCastPairInput :: struct { - proxyA: DistanceProxy, // The proxy for shape A - proxyB: DistanceProxy, // The proxy for shape B + proxyA: ShapeProxy, // The proxy for shape A + proxyB: ShapeProxy, // The proxy for shape B transformA: Transform, // The world transform for shape A transformB: Transform, // The world transform for shape B translationB: Vec2, // The translation of shape B maxFraction: f32, // The fraction of the translation to consider, typically 1 + canEncroach: bool, // Allows shapes with a radius to move slightly closer if already touching } @@ -272,11 +274,11 @@ Sweep :: struct { // Input parameters for b2TimeOfImpact TOIInput :: struct { - proxyA: DistanceProxy, // The proxy for shape A - proxyB: DistanceProxy, // The proxy for shape B - sweepA: Sweep, // The movement of shape A - sweepB: Sweep, // The movement of shape B - tMax: f32, // Defines the sweep interval [0, tMax] + proxyA: ShapeProxy, // The proxy for shape A + proxyB: ShapeProxy, // The proxy for shape B + sweepA: Sweep, // The movement of shape A + sweepB: Sweep, // The movement of shape B + maxFraction: f32, // Defines the sweep interval [0, maxFraction] } // Describes the TOI output @@ -290,8 +292,8 @@ TOIState :: enum c.int { // Output parameters for b2TimeOfImpact. TOIOutput :: struct { - state: TOIState, // The type of result - t: f32, // The time of the collision + state: TOIState, // The type of result + fraction: f32, // The sweep time of the collision } @@ -301,26 +303,30 @@ TOIOutput :: struct { * @brief Functions for colliding pairs of shapes */ -// A manifold point is a contact point belonging to a contact -// manifold. It holds details related to the geometry and dynamics -// of the contact points. +// A manifold point is a contact point belonging to a contact manifold. +// It holds details related to the geometry and dynamics of the contact points. +// Box2D uses speculative collision so some contact points may be separated. +// You may use the totalNormalImpulse to determine if there was an interaction during +// the time step. ManifoldPoint :: struct { // Location of the contact point in world space. Subject to precision loss at large coordinates. // @note Should only be used for debugging. point: Vec2, - // Location of the contact point relative to bodyA's origin in world space - // @note When used internally to the Box2D solver, these are relative to the center of mass. + // Location of the contact point relative to shapeA's origin in world space + // @note When used internally to the Box2D solver, this is relative to the body center of mass. anchorA: Vec2, - // Location of the contact point relative to bodyB's origin in world space + // Location of the contact point relative to shapeB's origin in world space + // @note When used internally to the Box2D solver, this is relative to the body center of mass. anchorB: Vec2, // The separation of the contact point, negative if penetrating separation: f32, - // The impulse along the manifold normal vector. - normalImpulse: f32, + // The total normal impulse applied across sub-stepping and restitution. This is important + // to identify speculative contact points that had an interaction in the time step. + totalNormalImpulse: f32, // The friction impulse tangentImpulse: f32, @@ -340,16 +346,21 @@ ManifoldPoint :: struct { persisted: bool, } -// A contact manifold describes the contact points between colliding shapes +// A contact manifold describes the contact points between colliding shapes. +// @note Box2D uses speculative collision so some contact points may be separated. Manifold :: struct { - // The manifold points, up to two are possible in 2D - points: [2]ManifoldPoint, - // The unit normal vector in world space, points from shape A to bodyB - normal: Vec2, + normal: Vec2, + + // Angular impulse applied for rolling resistance. N * m * s = kg * m^2 / s + rollingImpulse: f32, + + // The manifold points, up to two are possible in 2D + points: [2]ManifoldPoint, + // The number of contacts points, will be 0, 1, or 2 - pointCount: i32, + pointCount: c.int, } @@ -364,63 +375,17 @@ Manifold :: struct { * A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt. * A dynamic tree arranges data in a binary tree to accelerate * queries such as AABB queries and ray casts. Leaf nodes are proxies - * with an AABB. These are used to hold a user collision object, such as a reference to a b2Shape. + * with an AABB. These are used to hold a user collision object. * Nodes are pooled and relocatable, so I use node indices rather than pointers. * The dynamic tree is made available for advanced users that would like to use it to organize * spatial game data besides rigid bodies. - * - * @note This is an advanced feature and normally not used by applications directly. */ -// The default category bit for a tree proxy. Used for collision filtering. -defaultCategoryBits :: 0x00000001 - -// Convenience mask bits to use when you don't need collision filtering and just want -// all results. -defaultMaskBits :: 0xFFFFFFFF - -// A node in the dynamic tree. This is private data placed here for performance reasons. -// 16 + 16 + 8 + pad(8) -TreeNode :: struct { - // The node bounding box - aabb: AABB, // 16 - - // Category bits for collision filtering - categoryBits: u32, // 4 - - using _: struct #raw_union { - // The node parent index - parent: i32, - - // The node freelist next index - next: i32, - }, // 4 - - // Child 1 index - child1: i32, // 4 - - // Child 2 index - child2: i32, // 4 - - // User data - // todo could be union with child index - userData: i32, // 4 - - // Leaf = 0, free node = -1 - height: i16, // 2 - - // Has the AABB been enlarged? - enlarged: bool, // 1 - - // Padding for clarity - _: [9]byte, -} - // The dynamic tree structure. This should be considered private data. // It is placed here for performance reasons. DynamicTree :: struct { // The tree nodes - nodes: [^]TreeNode `fmt"v,nodeCount"`, + nodes: rawptr, // The root index root: i32, @@ -453,16 +418,25 @@ DynamicTree :: struct { rebuildCapacity: i32, } +// These are performance results returned by dynamic tree queries. +TreeStats :: struct { + // Number of internal nodes visited during the query + nodeVisits: c.int, + + // Number of leaf nodes visited during the query + leafVisits: c.int, +} + // This function receives proxies found in the AABB query. // @return true if the query should continue -TreeQueryCallbackFcn :: #type proc "c" (proxyId: i32, userData: i32, ctx: rawptr) -> bool +TreeQueryCallbackFcn :: #type proc "c" (proxyId: i32, userData: u64, ctx: rawptr) -> bool -// This function receives clipped ray-cast input for a proxy. The function +// This function receives clipped ray cast input for a proxy. The function // returns the new ray fraction. -// - return a value of 0 to terminate the ray-cast +// - return a value of 0 to terminate the ray cast // - return a value less than input->maxFraction to clip the ray // - return a value of input->maxFraction to continue the ray cast without clipping -TreeShapeCastCallbackFcn :: #type proc "c" (#by_ptr input: ShapeCastInput, proxyId: i32, userData: i32, ctx: rawptr) -> f32 +TreeShapeCastCallbackFcn :: #type proc "c" (#by_ptr input: ShapeCastInput, proxyId: i32, userData: u64, ctx: rawptr) -> f32 // This function receives clipped raycast input for a proxy. The function @@ -470,4 +444,47 @@ TreeShapeCastCallbackFcn :: #type proc "c" (#by_ptr input: ShapeCastInput, proxy // - return a value of 0 to terminate the ray cast // - return a value less than input->maxFraction to clip the ray // - return a value of input->maxFraction to continue the ray cast without clipping -TreeRayCastCallbackFcn :: #type proc "c" (#by_ptr input: RayCastInput, proxyId: i32, userData: i32, ctx: rawptr) -> f32 +TreeRayCastCallbackFcn :: #type proc "c" (#by_ptr input: RayCastInput, proxyId: i32, userData: u64, ctx: rawptr) -> f32 + +/**@}*/ + +/** + * @defgroup character Character mover + * Character movement solver + * @{ + */ + +/// These are the collision planes returned from b2World_CollideMover +PlaneResult :: struct { + // The collision plane between the mover and convex shape + plane: Plane, + + // Did the collision register a hit? If not this plane should be ignored. + hit: bool, +} + +// These are collision planes that can be fed to b2SolvePlanes. Normally +// this is assembled by the user from plane results in b2PlaneResult +CollisionPlane :: struct { + // The collision plane between the mover and some shape + plane: Plane, + + // Setting this to FLT_MAX makes the plane as rigid as possible. Lower values can + // make the plane collision soft. Usually in meters. + pushLimit: f32, + + // The push on the mover determined by b2SolvePlanes. Usually in meters. + push: f32, + + // Indicates if b2ClipVector should clip against this plane. Should be false for soft collision. + clipVelocity: bool, +} + +// Result returned by b2SolvePlanes +PlaneSolverResult :: struct { + // The final position of the mover + position: Vec2, + + // The number of iterations used by the plane solver. For diagnostics. + iterationCount: i32, +} diff --git a/vendor/box2d/id.odin b/vendor/box2d/id.odin index 211b8b79d..cb530527a 100644 --- a/vendor/box2d/id.odin +++ b/vendor/box2d/id.odin @@ -23,45 +23,46 @@ import "base:intrinsics" /// World id references a world instance. This should be treated as an opaque handle. WorldId :: struct { - index1: u16, - revision: u16, + index1: u16, + generation: u16, } /// Body id references a body instance. This should be treated as an opaque handle. BodyId :: struct { - index1: i32, - world0: u16, - revision: u16, + index1: i32, + world0: u16, + generation: u16, } /// Shape id references a shape instance. This should be treated as an opaque handle. ShapeId :: struct { - index1: i32, - world0: u16, - revision: u16, -} - -/// Joint id references a joint instance. This should be treated as an opaque handle. -JointId :: struct { - index1: i32, - world0: u16, - revision: u16, + index1: i32, + world0: u16, + generation: u16, } /// Chain id references a chain instances. This should be treated as an opaque handle. ChainId :: struct { - index1: i32, - world0: u16, - revision: u16, + index1: i32, + world0: u16, + generation: u16, } +/// Joint id references a joint instance. This should be treated as an opaque handle. +JointId :: struct { + index1: i32, + world0: u16, + generation: u16, +} + + /// Use these to make your identifiers null. /// You may also use zero initialization to get null. nullWorldId :: WorldId{} nullBodyId :: BodyId{} nullShapeId :: ShapeId{} -nullJointId :: JointId{} nullChainId :: ChainId{} +nullJointId :: JointId{} /// Macro to determine if any id is null. IS_NULL :: #force_inline proc "c" (id: $T) -> bool @@ -82,6 +83,6 @@ ID_EQUALS :: #force_inline proc "c" (id1, id2: $T) -> bool where intrinsics.type_is_struct(T), intrinsics.type_has_field(T, "index1"), intrinsics.type_has_field(T, "world0"), - intrinsics.type_has_field(T, "revision") { - return id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.revision == id2.revision + intrinsics.type_has_field(T, "generation") { + return id1.index1 == id2.index1 && id1.world0 == id2.world0 && id1.generation == id2.generation } diff --git a/vendor/box2d/lib/box2d_darwin_amd64_avx2.a b/vendor/box2d/lib/box2d_darwin_amd64_avx2.a index 269de02fa..f98e919a4 100644 Binary files a/vendor/box2d/lib/box2d_darwin_amd64_avx2.a and b/vendor/box2d/lib/box2d_darwin_amd64_avx2.a differ diff --git a/vendor/box2d/lib/box2d_darwin_amd64_sse2.a b/vendor/box2d/lib/box2d_darwin_amd64_sse2.a index 096db9d7a..3df91e852 100644 Binary files a/vendor/box2d/lib/box2d_darwin_amd64_sse2.a and b/vendor/box2d/lib/box2d_darwin_amd64_sse2.a differ diff --git a/vendor/box2d/lib/box2d_darwin_arm64.a b/vendor/box2d/lib/box2d_darwin_arm64.a index 4feb4aac9..c5d04fc73 100644 Binary files a/vendor/box2d/lib/box2d_darwin_arm64.a and b/vendor/box2d/lib/box2d_darwin_arm64.a differ diff --git a/vendor/box2d/lib/box2d_wasm.o b/vendor/box2d/lib/box2d_wasm.o index 15d71c5a1..fc3ed1cbd 100755 Binary files a/vendor/box2d/lib/box2d_wasm.o and b/vendor/box2d/lib/box2d_wasm.o differ diff --git a/vendor/box2d/lib/box2d_wasm_simd.o b/vendor/box2d/lib/box2d_wasm_simd.o index 568900bd9..8b70dcedd 100755 Binary files a/vendor/box2d/lib/box2d_wasm_simd.o and b/vendor/box2d/lib/box2d_wasm_simd.o differ diff --git a/vendor/box2d/lib/box2d_windows_amd64_avx2.lib b/vendor/box2d/lib/box2d_windows_amd64_avx2.lib index cea3f678d..7b8626b80 100644 Binary files a/vendor/box2d/lib/box2d_windows_amd64_avx2.lib and b/vendor/box2d/lib/box2d_windows_amd64_avx2.lib differ diff --git a/vendor/box2d/lib/box2d_windows_amd64_sse2.lib b/vendor/box2d/lib/box2d_windows_amd64_sse2.lib index 1ba62c76b..f1442615f 100644 Binary files a/vendor/box2d/lib/box2d_windows_amd64_sse2.lib and b/vendor/box2d/lib/box2d_windows_amd64_sse2.lib differ diff --git a/vendor/box2d/math_functions.odin b/vendor/box2d/math_functions.odin index 2294a515c..4394feb39 100644 --- a/vendor/box2d/math_functions.odin +++ b/vendor/box2d/math_functions.odin @@ -3,9 +3,18 @@ package vendor_box2d import "core:c" import "core:math" -pi :: 3.14159265359 +EPSILON :: 1e-23 Vec2 :: [2]f32 + +// Cosine and sine pair +// This uses a custom implementation designed for cross-platform determinism +CosSin :: struct { + // cosine and sine + cosine: f32, + sine: f32, +} + Rot :: struct { c, s: f32, // cosine and sine } @@ -21,11 +30,43 @@ AABB :: struct { upperBound: Vec2, } +// separation = dot(normal, point) - offset +Plane :: struct { + normal: Vec2, + offset: f32, +} + +PI :: math.PI + Vec2_zero :: Vec2{0, 0} Rot_identity :: Rot{1, 0} Transform_identity :: Transform{{0, 0}, {1, 0}} Mat22_zero :: Mat22{0, 0, 0, 0} +// @return the minimum of two integers +@(deprecated="Prefer the built-in 'min(a, b)'", require_results) +MinInt :: proc "c" (a, b: c.int) -> c.int { + return min(a, b) +} + +// @return the maximum of two integers +@(deprecated="Prefer the built-in 'max(a, b)'", require_results) +MaxInt :: proc "c" (a, b: c.int) -> c.int { + return max(a, b) +} + +// @return the absolute value of an integer +@(deprecated="Prefer the built-in 'abs(a)'", require_results) +AbsInt :: proc "c" (a: c.int) -> c.int { + return abs(a) +} + +// @return an integer clamped between a lower and upper bound +@(deprecated="Prefer the built-in 'clamp(a, lower, upper)'", require_results) +ClampInt :: proc "c" (a, lower, upper: c.int) -> c.int { + return clamp(a, lower, upper) +} + // @return the minimum of two floats @(deprecated="Prefer the built-in 'min(a, b)'", require_results) @@ -51,28 +92,15 @@ ClampFloat :: proc "c" (a, lower, upper: f32) -> f32 { return clamp(a, lower, upper) } -// @return the minimum of two integers -@(deprecated="Prefer the built-in 'min(a, b)'", require_results) -MinInt :: proc "c" (a, b: c.int) -> c.int { - return min(a, b) +@(require_results) +Atan2 :: proc "c" (y, x: f32) -> f32 { + return math.atan2(y, x) } -// @return the maximum of two integers -@(deprecated="Prefer the built-in 'max(a, b)'", require_results) -MaxInt :: proc "c" (a, b: c.int) -> c.int { - return max(a, b) -} - -// @return the absolute value of an integer -@(deprecated="Prefer the built-in 'abs(a)'", require_results) -AbsInt :: proc "c" (a: c.int) -> c.int { - return abs(a) -} - -// @return an integer clamped between a lower and upper bound -@(deprecated="Prefer the built-in 'clamp(a, lower, upper)'", require_results) -ClampInt :: proc "c" (a, lower, upper: c.int) -> c.int { - return clamp(a, lower, upper) +@(require_results) +ComputeCosSin :: proc "c" (radians: f32) -> (res: CosSin) { + res.sine, res.cosine = math.sincos(radians) + return } // Vector dot product @@ -198,12 +226,6 @@ Length :: proc "c" (v: Vec2) -> f32 { return math.sqrt(v.x * v.x + v.y * v.y) } -// Get the length squared of this vector -@(require_results) -LengthSquared :: proc "c" (v: Vec2) -> f32 { - return v.x * v.x + v.y * v.y -} - // Get the distance between two points @(require_results) Distance :: proc "c" (a, b: Vec2) -> f32 { @@ -212,45 +234,41 @@ Distance :: proc "c" (a, b: Vec2) -> f32 { return math.sqrt(dx * dx + dy * dy) } -// Get the distance squared between points @(require_results) -DistanceSquared :: proc "c" (a, b: Vec2) -> f32 { - c := Vec2{b.x - a.x, b.y - a.y} - return c.x * c.x + c.y * c.y +Normalize :: proc "c" (v: Vec2) -> Vec2 { + length := Length(v) + if length < EPSILON { + return Vec2_zero + } + invLength := 1 / length + return invLength * v } -// Make a rotation using an angle in radians @(require_results) -MakeRot :: proc "c" (angle: f32) -> Rot { - // todo determinism - return {math.cos(angle), math.sin(angle)} +IsNormalized :: proc "c" (v: Vec2) -> bool { + aa := Dot(v, v) + return abs(1. - aa) < 10. * EPSILON } -// Normalize rotation @(require_results) -NormalizeRot :: proc "c" (q: Rot) -> Rot { - mag := math.sqrt(q.s * q.s + q.c * q.c) - invMag := f32(mag > 0.0 ? 1.0 / mag : 0.0) - return {q.c * invMag, q.s * invMag} +NormalizeChecked :: proc "odin" (v: Vec2) -> Vec2 { + length := Length(v) + if length < 1e-23 { + panic("zero-length Vec2") + } + invLength := 1 / length + return invLength * v } -// Is this rotation normalized? @(require_results) -IsNormalized :: proc "c" (q: Rot) -> bool { - // larger tolerance due to failure on mingw 32-bit - qq := q.s * q.s + q.c * q.c - return 1.0 - 0.0006 < qq && qq < 1 + 0.0006 -} - -// Normalized linear interpolation -// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/ -@(require_results) -NLerp :: proc "c" (q1: Rot, q2: Rot, t: f32) -> Rot { - omt := 1 - t - return NormalizeRot({ - omt * q1.c + t * q2.c, - omt * q1.s + t * q2.s, - }) +GetLengthAndNormalize :: proc "c" (v: Vec2) -> (length: f32, vn: Vec2) { + length = Length(v) + if length < 1e-23 { + return + } + invLength := 1 / length + vn = invLength * v + return } // Integration rotation from angular velocity @@ -268,6 +286,63 @@ IntegrateRotation :: proc "c" (q1: Rot, deltaAngle: f32) -> Rot { return {q2.c * invMag, q2.s * invMag} } +// Get the length squared of this vector +@(require_results) +LengthSquared :: proc "c" (v: Vec2) -> f32 { + return v.x * v.x + v.y * v.y +} + +// Get the distance squared between points +@(require_results) +DistanceSquared :: proc "c" (a, b: Vec2) -> f32 { + c := Vec2{b.x - a.x, b.y - a.y} + return c.x * c.x + c.y * c.y +} + +// Make a rotation using an angle in radians +@(require_results) +MakeRot :: proc "c" (angle: f32) -> Rot { + cs := ComputeCosSin(angle) + return Rot{c=cs.cosine, s=cs.sine} +} + +// Compute the rotation between two unit vectors +@(require_results) +ComputeRotationBetweenUnitVectors :: proc(v1, v2: Vec2) -> Rot { + return NormalizeRot({ + c = Dot(v1, v2), + s = Cross(v1, v2), + }) +} + +// Is this rotation normalized? +@(require_results) +IsNormalizedRot :: proc "c" (q: Rot) -> bool { + // larger tolerance due to failure on mingw 32-bit + qq := q.s * q.s + q.c * q.c + return 1.0 - 0.0006 < qq && qq < 1 + 0.0006 +} + +// Normalize rotation +@(require_results) +NormalizeRot :: proc "c" (q: Rot) -> Rot { + mag := math.sqrt(q.s * q.s + q.c * q.c) + invMag := f32(mag > 0.0 ? 1.0 / mag : 0.0) + return {q.c * invMag, q.s * invMag} +} + +// Normalized linear interpolation +// https://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/ +// https://web.archive.org/web/20170825184056/http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/ +@(require_results) +NLerp :: proc "c" (q1: Rot, q2: Rot, t: f32) -> Rot { + omt := 1 - t + return NormalizeRot({ + omt * q1.c + t * q2.c, + omt * q1.s + t * q2.s, + }) +} + // Compute the angular velocity necessary to rotate between two rotations over a give time // @param q1 initial rotation // @param q2 final rotation @@ -291,8 +366,7 @@ ComputeAngularVelocity :: proc "c" (q1: Rot, q2: Rot, inv_h: f32) -> f32 { // Get the angle in radians in the range [-pi, pi] @(require_results) Rot_GetAngle :: proc "c" (q: Rot) -> f32 { - // todo determinism - return math.atan2(q.s, q.c) + return Atan2(q.s, q.c) } // Get the x-axis @@ -338,18 +412,34 @@ RelativeAngle :: proc "c" (b, a: Rot) -> f32 { // cos(b - a) = bc * ac + bs * as s := b.s * a.c - b.c * a.s c := b.c * a.c + b.s * a.s - return math.atan2(s, c) + return Atan2(s, c) } // Convert an angle in the range [-2*pi, 2*pi] into the range [-pi, pi] @(require_results) -UnwindAngle :: proc "c" (angle: f32) -> f32 { - if angle < -pi { - return angle + 2.0 * pi - } else if angle > pi { - return angle - 2.0 * pi +UnwindAngle :: proc "c" (radians: f32) -> f32 { + if radians < -PI { + return radians + 2.0 * PI + } else if radians > PI { + return radians - 2.0 * PI } - return angle + return radians +} + +// Convert any into the range [-pi, pi] (slow) +@(require_results) +UnwindLargeAngle :: proc "c" (radians: f32) -> f32 { + radians := radians + + for radians > PI { + radians -= 2. * PI + } + + for radians < -PI { + radians += 2. * PI + } + + return radians } // Rotate a vector @@ -380,6 +470,9 @@ InvTransformPoint :: proc "c" (t: Transform, p: Vec2) -> Vec2 { return {t.q.c * vx + t.q.s * vy, -t.q.s * vx + t.q.c * vy} } +// Multiply two transforms. If the result is applied to a point p local to frame B, +// the transform would first convert p to a point local to frame A, then into a point +// in the world frame. // v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p // = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p @(require_results) @@ -389,6 +482,7 @@ MulTransforms :: proc "c" (A, B: Transform) -> (C: Transform) { return } +// Creates a transform that converts a local point in frame B to a local point in frame A. // v2 = A.q' * (B.q * v1 + B.p - A.p) // = A.q' * B.q * v1 + A.q' * (B.p - A.p) @(require_results) @@ -469,54 +563,65 @@ AABB_Union :: proc "c" (a, b: AABB) -> (c: AABB) { return } +// Compute the bounding box of an array of circles @(require_results) -Float_IsValid :: proc "c" (a: f32) -> bool { - math.is_nan(a) or_return - math.is_inf(a) or_return +MakeAABB :: proc "c" (points: []Vec2, radius: f32) -> AABB { + a := AABB{points[0], points[0]} + for point in points { + a.lowerBound = Min(a.lowerBound, point) + a.upperBound = Max(a.upperBound, point) + } + + r := Vec2{radius, radius} + a.lowerBound = a.lowerBound - r + a.upperBound = a.upperBound + r + + return a +} + +// Signed separation of a point from a plane +@(require_results) +PlaneSeparation :: proc "c" (plane: Plane, point: Vec2) -> f32 { + return Dot(plane.normal, point) - plane.offset +} + +@(require_results) +IsValidFloat :: proc "c" (a: f32) -> bool { + #partial switch math.classify(a) { + case .NaN, .Inf, .Neg_Inf: return false + case: return true + } +} + +@(require_results) +IsValidVec2 :: proc "c" (v: Vec2) -> bool { + IsValidFloat(v.x) or_return + IsValidFloat(v.y) or_return return true } @(require_results) -Vec2_IsValid :: proc "c" (v: Vec2) -> bool { - (math.is_nan(v.x) || math.is_nan(v.y)) or_return - (math.is_inf(v.x) || math.is_inf(v.y)) or_return +IsValidRotation :: proc "c" (q: Rot) -> bool { + IsValidFloat(q.s) or_return + IsValidFloat(q.c) or_return + return IsNormalizedRot(q) +} + +// Is this a valid bounding box? Not Nan or infinity. Upper bound greater than or equal to lower bound. +@(require_results) +IsValidAABB :: proc "c" (aabb: AABB) -> bool { + IsValidVec2(aabb.lowerBound) or_return + IsValidVec2(aabb.upperBound) or_return + (aabb.upperBound.x >= aabb.lowerBound.x) or_return + (aabb.upperBound.y >= aabb.lowerBound.y) or_return return true } +// Is this a valid plane? Normal is a unit vector. Not Nan or infinity. @(require_results) -Rot_IsValid :: proc "c" (q: Rot) -> bool { - (math.is_nan(q.s) || math.is_nan(q.c)) or_return - (math.is_inf(q.s) || math.is_inf(q.c)) or_return - return IsNormalized(q) -} - -@(require_results) -Normalize :: proc "c" (v: Vec2) -> Vec2 { - length := Length(v) - if length < 1e-23 { - return Vec2_zero - } - invLength := 1 / length - return invLength * v -} - -@(require_results) -NormalizeChecked :: proc "odin" (v: Vec2) -> Vec2 { - length := Length(v) - if length < 1e-23 { - panic("zero-length Vec2") - } - invLength := 1 / length - return invLength * v -} - -@(require_results) -GetLengthAndNormalize :: proc "c" (v: Vec2) -> (length: f32, vn: Vec2) { - length = Length(v) - if length < 1e-23 { - return - } - invLength := 1 / length - vn = invLength * v - return +IsValidPlane :: proc "c" (plane: Plane) -> bool { + IsValidFloat(plane.offset) or_return + IsValidVec2(plane.normal) or_return + IsNormalized(plane.normal) or_return + return true } diff --git a/vendor/box2d/types.odin b/vendor/box2d/types.odin index 1ea7cb65a..c4ef0cd0c 100644 --- a/vendor/box2d/types.odin +++ b/vendor/box2d/types.odin @@ -37,14 +37,28 @@ EnqueueTaskCallback :: #type proc "c" (task: TaskCallback, itemCount: i32, minRa // @ingroup world FinishTaskCallback :: #type proc "c" (userTask: rawptr, userContext: rawptr) +// Optional friction mixing callback. This intentionally provides no context objects because this is called +// from a worker thread. +// @warning This function should not attempt to modify Box2D state or user application state. +// @ingroup world +FrictionCallback :: #type proc "c" (frictionA: f32, userMaterialIdA: i32, frictionB: f32, userMaterialIdB: i32) + +// Optional restitution mixing callback. This intentionally provides no context objects because this is called +// from a worker thread. +// @warning This function should not attempt to modify Box2D state or user application state. +// @ingroup world +RestitutionCallback :: #type proc "c" (restitutionA: f32, userMaterialIdA: i32, restitutuionB: f32, userMaterialIdB: i32) + // Result from b2World_RayCastClosest // @ingroup world RayResult :: struct { - shapeId: ShapeId, - point: Vec2, - normal: Vec2, - fraction: f32, - hit: bool, + shapeId: ShapeId, + point: Vec2, + normal: Vec2, + fraction: f32, + nodeVisits: i32, + leafVisits: i32, + hit: bool, } // World definition used to create a simulation world. @@ -54,37 +68,53 @@ WorldDef :: struct { // Gravity vector. Box2D has no up-vector defined. gravity: Vec2, - // Restitution velocity threshold, usually in m/s. Collisions above this + // Restitution speed threshold, usually in m/s. Collisions above this // speed have restitution applied (will bounce). restitutionThreshold: f32, - // This parameter controls how fast overlap is resolved and has units of meters per second - contactPushoutVelocity: f32, - - // Threshold velocity for hit events. Usually meters per second. + // Threshold speed for hit events. Usually meters per second. hitEventThreshold: f32, - // Contact stiffness. Cycles per second. + // Contact stiffness. Cycles per second. Increasing this increases the speed of overlap recovery, but can introduce jitter. contactHertz: f32, - // Contact bounciness. Non-dimensional. + // Contact bounciness. Non-dimensional. You can speed up overlap recovery by decreasing this with + // the trade-off that overlap resolution becomes more energetic. contactDampingRatio: f32, + // This parameter controls how fast overlap is resolved and usually has units of meters per second. This only + // puts a cap on the resolution speed. The resolution speed is increased by increasing the hertz and/or + // decreasing the damping ratio. + maxContactPushSpeed: f32, + // Joint stiffness. Cycles per second. jointHertz: f32, // Joint bounciness. Non-dimensional. jointDampingRatio: f32, + // Maximum linear speed. Usually meters per second. + maximumLinearSpeed: f32, + + // Optional mixing callback for friction. The default uses sqrt(frictionA * frictionB). + frictionCallback: FrictionCallback, + + // Optional mixing callback for restitution. The default uses max(restitutionA, restitutionB). + restitutionCallback: RestitutionCallback, + // Can bodies go to sleep to improve performance enableSleep: bool, // Enable continuous collision - enableContinous: bool, + enableContinuous: bool, // Number of workers to use with the provided task system. Box2D performs best when using only - // performance cores and accessing a single L2 cache. Efficiency cores and hyper-threading provide - // little benefit and may even harm performance. + // performance cores and accessing a single L2 cache. Efficiency cores and hyper-threading provide + // little benefit and may even harm performance. + // @note Box2D does not create threads. This is the number of threads your applications has created + // that you are allocating to b2World_Step. + // @warning Do not modify the default value unless you are also providing a task system and providing + // task callbacks (enqueueTask and finishTask). workerCount: i32, // Function to spawn tasks @@ -96,6 +126,9 @@ WorldDef :: struct { // User context that is provided to enqueueTask and finishTask userTaskContext: rawptr, + // User data + userData: rawptr, + // Used internally to detect a valid definition. DO NOT SET. internalValue: i32, } @@ -138,20 +171,20 @@ BodyDef :: struct { // The initial world rotation of the body. Use b2MakeRot() if you have an angle. rotation: Rot, - // The initial linear velocity of the body's origin. Typically in meters per second. + // The initial linear velocity of the body's origin. Usually in meters per second. linearVelocity: Vec2, // The initial angular velocity of the body. Radians per second. angularVelocity: f32, - // Linear damping is use to reduce the linear velocity. The damping parameter + // Linear damping is used to reduce the linear velocity. The damping parameter // can be larger than 1 but the damping effect becomes sensitive to the // time step when the damping parameter is large. // Generally linear damping is undesirable because it makes objects move slowly // as if they are f32ing. linearDamping: f32, - // Angular damping is use to reduce the angular velocity. The damping parameter + // Angular damping is used to reduce the angular velocity. The damping parameter // can be larger than 1.0f but the damping effect becomes sensitive to the // time step when the damping parameter is large. // Angular damping can be use slow down rotating bodies. @@ -160,9 +193,12 @@ BodyDef :: struct { // Scale the gravity applied to this body. Non-dimensional. gravityScale: f32, - // Sleep velocity threshold, default is 0.05 meter per second + // Sleep speed threshold, default is 0.05 meters per second sleepThreshold: f32, + // Optional body name for debugging. Up to 32 characters (excluding null termination) + name: cstring, + // Use this to store application specific body data. userData: rawptr, @@ -184,9 +220,9 @@ BodyDef :: struct { // Used to disable a body. A disabled body does not move or collide. isEnabled: bool, - // Automatically compute mass and related properties on this body from shapes. - // Triggers whenever a shape is add/removed/changed. Default is true. - automaticMass: bool, + // This allows this body to bypass rotational speed limits. Should only be used + // for circular objects, like wheels. + allowFastRotation: bool, // Used internally to detect a valid definition. DO NOT SET. internalValue: i32, @@ -200,7 +236,7 @@ Filter :: struct { // The collision category bits. Normally you would just set one bit. The category bits should // represent your application object types. For example: // @code{.odin} - // My_Categories :: enum u32 { + // My_Categories :: enum u64 { // Static = 0x00000001, // Dynamic = 0x00000002, // Debris = 0x00000004, @@ -209,16 +245,16 @@ Filter :: struct { // }; // @endcode // Or use a bit_set. - categoryBits: u32, + categoryBits: u64, // The collision mask bits. This states the categories that this // shape would accept for collision. // For example, you may want your player to only collide with static objects // and other players. // @code{.odin} - // maskBits = u32(My_Categories.Static | My_Categories.Player); + // maskBits = u64(My_Categories.Static | My_Categories.Player); // @endcode - maskBits: u32, + maskBits: u64, // Collision groups allow a certain group of objects to never collide (negative) // or always collide (positive). A group index of zero has no effect. Non-zero group filtering @@ -236,11 +272,11 @@ Filter :: struct { // @ingroup shape QueryFilter :: struct { // The collision category bits of this query. Normally you would just set one bit. - categoryBits: u32, + categoryBits: u64, // The collision mask bits. This states the shape categories that this // query would accept for collision. - maskBits: u32, + maskBits: u64, } @@ -259,13 +295,37 @@ ShapeType :: enum c.int { // A convex polygon polygonShape, - // A smooth segment owned by a chain shape - smoothSegmentShape, + // A line segment owned by a chain shape + chainSegmentShape, } // The number of shape types shapeTypeCount :: len(ShapeType) +// Surface materials allow chain shapes to have per segment surface properties. +// @ingroup shape +SurfaceMaterial :: struct { + // The Coulomb (dry) friction coefficient, usually in the range [0,1]. + friction: f32, + + // The coefficient of restitution (bounce) usually in the range [0,1]. + // https://en.wikipedia.org/wiki/Coefficient_of_restitution + restitution: f32, + + // The rolling resistance usually in the range [0,1]. + rollingResistance: f32, + + // The tangent speed for conveyor belts + tangentSpeed: f32, + + // User material identifier. This is passed with query results and to friction and restitution + // combining functions. It is not used internally. + userMaterialId: i32, + + // Custom debug draw color. + customColor: u32, +} + // Used to create a shape. // This is a temporary object used to bundle shape creation parameters. You may use // the same shape definition to create multiple shapes. @@ -275,58 +335,61 @@ ShapeDef :: struct { // Use this to store application specific shape data. userData: rawptr, - // The Coulomb (dry) friction coefficient, usually in the range [0,1]. - friction: f32, - - // The restitution (bounce) usually in the range [0,1]. - restitution: f32, + // The surface material for this shape. + material: SurfaceMaterial, // The density, usually in kg/m^2. + // This is not part of the surface material because this is for the interior, which may have + // other considerations, such as being hollow. For example a wood barrel may be hollow or full of water. density: f32, // Collision filtering data. filter: Filter, - // Custom debug draw color. - customColor: u32, - // A sensor shape generates overlap events but never generates a collision response. + // Sensors do not have continuous collision. Instead, use a ray or shape cast for those scenarios. + // Sensors still contribute to the body mass if they have non-zero density. + // @note Sensor events are disabled by default. + // @see enableSensorEvents isSensor: bool, - // Enable sensor events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. + // Enable sensor events for this shape. This applies to sensors and non-sensors. False by default, even for sensors. enableSensorEvents: bool, - // Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. + // Enable contact events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default. enableContactEvents: bool, - // Enable hit events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. + // Enable hit events for this shape. Only applies to kinematic and dynamic bodies. Ignored for sensors. False by default. enableHitEvents: bool, // Enable pre-solve contact events for this shape. Only applies to dynamic bodies. These are expensive // and must be carefully handled due to threading. Ignored for sensors. enablePreSolveEvents: bool, - // Normally shapes on static bodies don't invoke contact creation when they are added to the world. This overrides - // that behavior and causes contact creation. This significantly slows down static body creation which can be important - // when there are many static shapes. - forceContactCreation: bool, + // When shapes are created they will scan the environment for collision the next time step. This can significantly slow down + // static body creation when there are many static shapes. + // This is flag is ignored for dynamic and kinematic shapes which always invoke contact creation. + invokeContactCreation: bool, + + // Should the body update the mass properties when this shape is created. Default is true. + updateBodyMass: bool, // Used internally to detect a valid definition. DO NOT SET. internalValue: i32, } -// Used to create a chain of edges. This is designed to eliminate ghost collisions with some limitations. +// Used to create a chain of line segments. This is designed to eliminate ghost collisions with some limitations. // - chains are one-sided // - chains have no mass and should be used on static bodies -// - chains have a counter-clockwise winding order +// - chains have a counter-clockwise winding order (normal points right of segment direction) // - chains are either a loop or open // - a chain must have at least 4 points -// - the distance between any two points must be greater than b2_linearSlop +// - the distance between any two points must be greater than B2_LINEAR_SLOP // - a chain shape should not self intersect (this is not validated) // - an open chain shape has NO COLLISION on the first and final edge // - you may overlap two open chains on their first three and/or last three points to get smooth collision -// - a chain shape creates multiple smooth edges shapes on the body +// - a chain shape creates multiple line segment shapes on the body // https://en.wikipedia.org/wiki/Polygonal_chain // Must be initialized using b2DefaultChainDef(). // @warning Do not use chain shapes unless you understand the limitations. This is an advanced feature. @@ -341,11 +404,12 @@ ChainDef :: struct { // The point count, must be 4 or more. count: i32, - // The friction coefficient, usually in the range [0,1]. - friction: f32, + // Surface materials for each segment. These are cloned. + materials: [^]SurfaceMaterial `fmt:"v,materialCount"`, - // The restitution (elasticity) usually in the range [0,1]. - restitution: f32, + // The material count. Must be 1 or count. This allows you to provide one + // material for all segments or a unique material per segment. + materialCount: i32, // Contact filtering data. filter: Filter, @@ -353,6 +417,9 @@ ChainDef :: struct { // Indicates a closed chain formed by connecting the first and last points isLoop: bool, + // Enable sensors to detect this chain. False by default. + enableSensorEvents: bool, + // Used internally to detect a valid definition. DO NOT SET. internalValue: i32, } @@ -365,29 +432,28 @@ Profile :: struct { pairs: f32, collide: f32, solve: f32, - buildIslands: f32, + mergeIslands: f32, + prepareStages: f32, solveConstraints: f32, - prepareTasks: f32, - solverTasks: f32, prepareConstraints: f32, integrateVelocities: f32, warmStart: f32, - solveVelocities: f32, + solveImpulses: f32, integratePositions: f32, - relaxVelocities: f32, + relaxImpulses: f32, applyRestitution: f32, storeImpulses: f32, - finalizeBodies: f32, splitIslands: f32, - sleepIslands: f32, + transforms: f32, hitEvents: f32, - broadphase: f32, - continuous: f32, + refit: f32, + bullets: f32, + sleepIslands: f32, + sensors: f32, } // Counters that give details of the simulation size. Counters :: struct { - staticBodyCount: i32, bodyCount: i32, shapeCount: i32, contactCount: i32, @@ -409,6 +475,7 @@ Counters :: struct { // @ingroup joint JointType :: enum c.int { distanceJoint, + filterJoint, motorJoint, mouseJoint, prismaticJoint, @@ -522,7 +589,7 @@ MotorJointDef :: struct { // applying huge forces. This also applies rotation constraint heuristic to improve control. // @ingroup mouse_joint MouseJointDef :: struct { - // The first attached body. + // The first attached body. This is assumed to be static. bodyIdA: BodyId, // The second attached body. @@ -550,6 +617,22 @@ MouseJointDef :: struct { internalValue: i32, } +// A filter joint is used to disable collision between two specific bodies. +// +// @ingroup filter_joint +FilterJointDef :: struct { + /// The first attached body. + bodyIdA: BodyId, + + /// The second attached body. + bodyIdB: BodyId, + + /// User data pointer + userData: rawptr, + + /// Used internally to detect a valid definition. DO NOT SET. + internalValue: i32, +} // Prismatic joint definition // @@ -656,10 +739,10 @@ RevoluteJointDef :: struct { // A flag to enable joint limits enableLimit: bool, - // The lower angle for the joint limit in radians + // The lower angle for the joint limit in radians. Minimum of -0.95*pi radians. lowerAngle: f32, - // The upper angle for the joint limit in radians + // The upper angle for the joint limit in radians. Maximum of 0.95*pi radians. upperAngle: f32, // A flag to enable the joint motor @@ -790,6 +873,27 @@ WheelJointDef :: struct { internalValue: i32, } +// The explosion definition is used to configure options for explosions. Explosions +// consider shape geometry when computing the impulse. +// @ingroup world +ExplosionDef :: struct { + /// Mask bits to filter shapes + maskBits: u64, + + /// The center of the explosion in world space + position: Vec2, + + /// The radius of the explosion + radius: f32, + + /// The falloff distance beyond the radius. Impulse is reduced to zero at this distance. + falloff: f32, + + /// Impulse per unit length. This applies an impulse according to the shape perimeter that + /// is facing the explosion. Explosions only apply to circles, capsules, and polygons. This + /// may be negative for implosions. + impulsePerLength: f32, +} /** * @defgroup events Events @@ -818,11 +922,18 @@ SensorBeginTouchEvent :: struct { } // An end touch event is generated when a shape stops overlapping a sensor shape. +// These include things like setting the transform, destroying a body or shape, or changing +// a filter. You will also get an end event if the sensor or visitor are destroyed. +// Therefore you should always confirm the shape id is valid using b2Shape_IsValid. SensorEndTouchEvent :: struct { // The id of the sensor shape + // @warning this shape may have been destroyed + // @see b2Shape_IsValid sensorShapeId: ShapeId, // The id of the dynamic shape that stopped touching the sensor shape + // @warning this shape may have been destroyed + // @see b2Shape_IsValid visitorShapeId: ShapeId, } @@ -850,14 +961,25 @@ ContactBeginTouchEvent :: struct { // Id of the second shape shapeIdB: ShapeId, + + // The initial contact manifold. This is recorded before the solver is called, + // so all the impulses will be zero. + manifold: Manifold, } // An end touch event is generated when two shapes stop touching. +// You will get an end event if you do anything that destroys contacts previous to the last +// world step. These include things like setting the transform, destroying a body +// or shape, or changing a filter or body type. ContactEndTouchEvent :: struct { // Id of the first shape + // @warning this shape may have been destroyed + // @see b2Shape_IsValid shapeIdA: ShapeId, // Id of the second shape + // @warning this shape may have been destroyed + // @see b2Shape_IsValid shapeIdB: ShapeId, } @@ -994,201 +1116,191 @@ OverlapResultFcn :: #type proc "c" (shapeId: ShapeId, ctx: rawptr) -> bool // @ingroup world CastResultFcn :: #type proc "c" (shapeId: ShapeId, point: Vec2, normal: Vec2, fraction: f32, ctx: rawptr) -> f32 -// These colors are used for debug draw. -// See https://www.rapidtables.com/web/color/index.html +// Used to collect collision planes for character movers. +// Return true to continue gathering planes. +PlaneResultFcn :: #type proc "c" (shapeId: ShapeId, plane: ^PlaneResult, ctx: rawptr) -> bool + +// These colors are used for debug draw and mostly match the named SVG colors. +// See https://www.rapidtables.com/web/color/index.html +// https://johndecember.com/html/spec/colorsvg.html +// https://upload.wikimedia.org/wikipedia/commons/2/2b/SVG_Recognized_color_keyword_names.svg HexColor :: enum c.int { - AliceBlue = 0xf0f8ff, - AntiqueWhite = 0xfaebd7, - Aqua = 0x00ffff, - Aquamarine = 0x7fffd4, - Azure = 0xf0ffff, - Beige = 0xf5f5dc, - Bisque = 0xffe4c4, + AliceBlue = 0xF0F8FF, + AntiqueWhite = 0xFAEBD7, + Aqua = 0x00FFFF, + Aquamarine = 0x7FFFD4, + Azure = 0xF0FFFF, + Beige = 0xF5F5DC, + Bisque = 0xFFE4C4, Black = 0x000000, - BlanchedAlmond = 0xffebcd, - Blue = 0x0000ff, - BlueViolet = 0x8a2be2, - Brown = 0xa52a2a, - Burlywood = 0xdeb887, - CadetBlue = 0x5f9ea0, - Chartreuse = 0x7fff00, - Chocolate = 0xd2691e, - Coral = 0xff7f50, - CornflowerBlue = 0x6495ed, - Cornsilk = 0xfff8dc, - Crimson = 0xdc143c, - Cyan = 0x00ffff, - DarkBlue = 0x00008b, - DarkCyan = 0x008b8b, - DarkGoldenrod = 0xb8860b, - DarkGray = 0xa9a9a9, + BlanchedAlmond = 0xFFEBCD, + Blue = 0x0000FF, + BlueViolet = 0x8A2BE2, + Brown = 0xA52A2A, + Burlywood = 0xDEB887, + CadetBlue = 0x5F9EA0, + Chartreuse = 0x7FFF00, + Chocolate = 0xD2691E, + Coral = 0xFF7F50, + CornflowerBlue = 0x6495ED, + Cornsilk = 0xFFF8DC, + Crimson = 0xDC143C, + Cyan = 0x00FFFF, + DarkBlue = 0x00008B, + DarkCyan = 0x008B8B, + DarkGoldenRod = 0xB8860B, + DarkGray = 0xA9A9A9, DarkGreen = 0x006400, - DarkKhaki = 0xbdb76b, - DarkMagenta = 0x8b008b, - DarkOliveGreen = 0x556b2f, - DarkOrange = 0xff8c00, - DarkOrchid = 0x9932cc, - DarkRed = 0x8b0000, - DarkSalmon = 0xe9967a, - DarkSeaGreen = 0x8fbc8f, - DarkSlateBlue = 0x483d8b, - DarkSlateGray = 0x2f4f4f, - DarkTurquoise = 0x00ced1, - DarkViolet = 0x9400d3, - DeepPink = 0xff1493, - DeepSkyBlue = 0x00bfff, + DarkKhaki = 0xBDB76B, + DarkMagenta = 0x8B008B, + DarkOliveGreen = 0x556B2F, + DarkOrange = 0xFF8C00, + DarkOrchid = 0x9932CC, + DarkRed = 0x8B0000, + DarkSalmon = 0xE9967A, + DarkSeaGreen = 0x8FBC8F, + DarkSlateBlue = 0x483D8B, + DarkSlateGray = 0x2F4F4F, + DarkTurquoise = 0x00CED1, + DarkViolet = 0x9400D3, + DeepPink = 0xFF1493, + DeepSkyBlue = 0x00BFFF, DimGray = 0x696969, - DodgerBlue = 0x1e90ff, - Firebrick = 0xb22222, - FloralWhite = 0xfffaf0, - ForestGreen = 0x228b22, - Fuchsia = 0xff00ff, - Gainsboro = 0xdcdcdc, - GhostWhite = 0xf8f8ff, - Gold = 0xffd700, - Goldenrod = 0xdaa520, - Gray = 0xbebebe, - Gray1 = 0x1a1a1a, - Gray2 = 0x333333, - Gray3 = 0x4d4d4d, - Gray4 = 0x666666, - Gray5 = 0x7f7f7f, - Gray6 = 0x999999, - Gray7 = 0xb3b3b3, - Gray8 = 0xcccccc, - Gray9 = 0xe5e5e5, - Green = 0x00ff00, - GreenYellow = 0xadff2f, - Honeydew = 0xf0fff0, - HotPink = 0xff69b4, - IndianRed = 0xcd5c5c, - Indigo = 0x4b0082, - Ivory = 0xfffff0, - Khaki = 0xf0e68c, - Lavender = 0xe6e6fa, - LavenderBlush = 0xfff0f5, - LawnGreen = 0x7cfc00, - LemonChiffon = 0xfffacd, - LightBlue = 0xadd8e6, - LightCoral = 0xf08080, - LightCyan = 0xe0ffff, - LightGoldenrod = 0xeedd82, - LightGoldenrodYellow = 0xfafad2, - LightGray = 0xd3d3d3, - LightGreen = 0x90ee90, - LightPink = 0xffb6c1, - LightSalmon = 0xffa07a, - LightSeaGreen = 0x20b2aa, - LightSkyBlue = 0x87cefa, - LightSlateBlue = 0x8470ff, + DodgerBlue = 0x1E90FF, + FireBrick = 0xB22222, + FloralWhite = 0xFFFAF0, + ForestGreen = 0x228B22, + Fuchsia = 0xFF00FF, + Gainsboro = 0xDCDCDC, + GhostWhite = 0xF8F8FF, + Gold = 0xFFD700, + GoldenRod = 0xDAA520, + Gray = 0x808080, + Green = 0x008000, + GreenYellow = 0xADFF2F, + HoneyDew = 0xF0FFF0, + HotPink = 0xFF69B4, + IndianRed = 0xCD5C5C, + Indigo = 0x4B0082, + Ivory = 0xFFFFF0, + Khaki = 0xF0E68C, + Lavender = 0xE6E6FA, + LavenderBlush = 0xFFF0F5, + LawnGreen = 0x7CFC00, + LemonChiffon = 0xFFFACD, + LightBlue = 0xADD8E6, + LightCoral = 0xF08080, + LightCyan = 0xE0FFFF, + LightGoldenRodYellow = 0xFAFAD2, + LightGray = 0xD3D3D3, + LightGreen = 0x90EE90, + LightPink = 0xFFB6C1, + LightSalmon = 0xFFA07A, + LightSeaGreen = 0x20B2AA, + LightSkyBlue = 0x87CEFA, LightSlateGray = 0x778899, - LightSteelBlue = 0xb0c4de, - LightYellow = 0xffffe0, - Lime = 0x00ff00, - LimeGreen = 0x32cd32, - Linen = 0xfaf0e6, - Magenta = 0xff00ff, - Maroon = 0xb03060, - MediumAquamarine = 0x66cdaa, - MediumBlue = 0x0000cd, - MediumOrchid = 0xba55d3, - MediumPurple = 0x9370db, - MediumSeaGreen = 0x3cb371, - MediumSlateBlue = 0x7b68ee, - MediumSpringGreen = 0x00fa9a, - MediumTurquoise = 0x48d1cc, - MediumVioletRed = 0xc71585, + LightSteelBlue = 0xB0C4DE, + LightYellow = 0xFFFFE0, + Lime = 0x00FF00, + LimeGreen = 0x32CD32, + Linen = 0xFAF0E6, + Magenta = 0xFF00FF, + Maroon = 0x800000, + MediumAquaMarine = 0x66CDAA, + MediumBlue = 0x0000CD, + MediumOrchid = 0xBA55D3, + MediumPurple = 0x9370DB, + MediumSeaGreen = 0x3CB371, + MediumSlateBlue = 0x7B68EE, + MediumSpringGreen = 0x00FA9A, + MediumTurquoise = 0x48D1CC, + MediumVioletRed = 0xC71585, MidnightBlue = 0x191970, - MintCream = 0xf5fffa, - MistyRose = 0xffe4e1, - Moccasin = 0xffe4b5, - NavajoWhite = 0xffdead, + MintCream = 0xF5FFFA, + MistyRose = 0xFFE4E1, + Moccasin = 0xFFE4B5, + NavajoWhite = 0xFFDEAD, Navy = 0x000080, - NavyBlue = 0x000080, - OldLace = 0xfdf5e6, + OldLace = 0xFDF5E6, Olive = 0x808000, - OliveDrab = 0x6b8e23, - Orange = 0xffa500, - OrangeRed = 0xff4500, - Orchid = 0xda70d6, - PaleGoldenrod = 0xeee8aa, - PaleGreen = 0x98fb98, - PaleTurquoise = 0xafeeee, - PaleVioletRed = 0xdb7093, - PapayaWhip = 0xffefd5, - PeachPuff = 0xffdab9, - Peru = 0xcd853f, - Pink = 0xffc0cb, - Plum = 0xdda0dd, - PowderBlue = 0xb0e0e6, - Purple = 0xa020f0, + OliveDrab = 0x6B8E23, + Orange = 0xFFA500, + OrangeRed = 0xFF4500, + Orchid = 0xDA70D6, + PaleGoldenRod = 0xEEE8AA, + PaleGreen = 0x98FB98, + PaleTurquoise = 0xAFEEEE, + PaleVioletRed = 0xDB7093, + PapayaWhip = 0xFFEFD5, + PeachPuff = 0xFFDAB9, + Peru = 0xCD853F, + Pink = 0xFFC0CB, + Plum = 0xDDA0DD, + PowderBlue = 0xB0E0E6, + Purple = 0x800080, RebeccaPurple = 0x663399, - Red = 0xff0000, - RosyBrown = 0xbc8f8f, - RoyalBlue = 0x4169e1, - SaddleBrown = 0x8b4513, - Salmon = 0xfa8072, - SandyBrown = 0xf4a460, - SeaGreen = 0x2e8b57, - Seashell = 0xfff5ee, - Sienna = 0xa0522d, - Silver = 0xc0c0c0, - SkyBlue = 0x87ceeb, - SlateBlue = 0x6a5acd, + Red = 0xFF0000, + RosyBrown = 0xBC8F8F, + RoyalBlue = 0x4169E1, + SaddleBrown = 0x8B4513, + Salmon = 0xFA8072, + SandyBrown = 0xF4A460, + SeaGreen = 0x2E8B57, + SeaShell = 0xFFF5EE, + Sienna = 0xA0522D, + Silver = 0xC0C0C0, + SkyBlue = 0x87CEEB, + SlateBlue = 0x6A5ACD, SlateGray = 0x708090, - Snow = 0xfffafa, - SpringGreen = 0x00ff7f, - SteelBlue = 0x4682b4, - Tan = 0xd2b48c, + Snow = 0xFFFAFA, + SpringGreen = 0x00FF7F, + SteelBlue = 0x4682B4, + Tan = 0xD2B48C, Teal = 0x008080, - Thistle = 0xd8bfd8, - Tomato = 0xff6347, - Turquoise = 0x40e0d0, - Violet = 0xee82ee, - VioletRed = 0xd02090, - Wheat = 0xf5deb3, - White = 0xffffff, - WhiteSmoke = 0xf5f5f5, - Yellow = 0xffff00, - YellowGreen = 0x9acd32, - Box2DRed = 0xdc3132, - Box2DBlue = 0x30aebf, - Box2DGreen = 0x8cc924, - Box2DYellow = 0xffee8c, + Thistle = 0xD8BFD8, + Tomato = 0xFF6347, + Turquoise = 0x40E0D0, + Violet = 0xEE82EE, + Wheat = 0xF5DEB3, + White = 0xFFFFFF, + WhiteSmoke = 0xF5F5F5, + Yellow = 0xFFFF00, + YellowGreen = 0x9ACD32, + Box2DRed = 0xDC3132, + Box2DBlue = 0x30AEBF, + Box2DGreen = 0x8CC924, + Box2DYellow = 0xFFEE8C, } // This struct holds callbacks you can implement to draw a Box2D world. // @ingroup world DebugDraw :: struct { // Draw a closed polygon provided in CCW order. - DrawPolygon: proc "c" (vertices: [^]Vec2, vertexCount: c.int, color: HexColor, ctx: rawptr), + DrawPolygonFcn: proc "c" (vertices: [^]Vec2, vertexCount: c.int, color: HexColor, ctx: rawptr), // Draw a solid closed polygon provided in CCW order. - DrawSolidPolygon: proc "c" (transform: Transform, vertices: [^]Vec2, vertexCount: c.int, radius: f32, colr: HexColor, ctx: rawptr ), + DrawSolidPolygonFcn: proc "c" (transform: Transform, vertices: [^]Vec2, vertexCount: c.int, radius: f32, colr: HexColor, ctx: rawptr ), // Draw a circle. - DrawCircle: proc "c" (center: Vec2, radius: f32, color: HexColor, ctx: rawptr), + DrawCircleFcn: proc "c" (center: Vec2, radius: f32, color: HexColor, ctx: rawptr), // Draw a solid circle. - DrawSolidCircle: proc "c" (transform: Transform, radius: f32, color: HexColor, ctx: rawptr), - - // Draw a capsule. - DrawCapsule: proc "c" (p1, p2: Vec2, radius: f32, color: HexColor, ctx: rawptr), + DrawSolidCircleFcn: proc "c" (transform: Transform, radius: f32, color: HexColor, ctx: rawptr), // Draw a solid capsule. - DrawSolidCapsule: proc "c" (p1, p2: Vec2, radius: f32, color: HexColor, ctx: rawptr), + DrawSolidCapsuleFcn: proc "c" (p1, p2: Vec2, radius: f32, color: HexColor, ctx: rawptr), // Draw a line segment. - DrawSegment: proc "c" (p1, p2: Vec2, color: HexColor, ctx: rawptr), + DrawSegmentFcn: proc "c" (p1, p2: Vec2, color: HexColor, ctx: rawptr), // Draw a transform. Choose your own length scale. - DrawTransform: proc "c" (transform: Transform, ctx: rawptr), + DrawTransformFcn: proc "c" (transform: Transform, ctx: rawptr), // Draw a point. - DrawPoint: proc "c" (p: Vec2, size: f32, color: HexColor, ctx: rawptr), + DrawPointFcn: proc "c" (p: Vec2, size: f32, color: HexColor, ctx: rawptr), - // Draw a string. - DrawString: proc "c" (p: Vec2, s: cstring, ctx: rawptr), + // Draw a string in world space. + DrawStringFcn: proc "c" (p: Vec2, s: cstring, color: HexColor, ctx: rawptr), // Bounds to use if restricting drawing to a rectangular region drawingBounds: AABB, @@ -1206,11 +1318,14 @@ DebugDraw :: struct { drawJointExtras: bool, // Option to draw the bounding boxes for shapes - drawAABBs: bool, + drawBounds: bool, // Option to draw the mass and center of mass of dynamic bodies drawMass: bool, + // Option to draw body names + drawBodyNames: bool, + // Option to draw contact points drawContacts: bool, @@ -1223,9 +1338,15 @@ DebugDraw :: struct { // Option to draw contact normal impulses drawContactImpulses: bool, + // Option to draw contact feature ids + drawContactFeatures: bool, + // Option to draw contact friction impulses drawFrictionImpulses: bool, + // Option to draw islands as bounding boxes + drawIslands: bool, + // User context that is passed as an argument to drawing callback functions userContext: rawptr, -} \ No newline at end of file +} diff --git a/vendor/box2d/wasm.Makefile b/vendor/box2d/wasm.Makefile index e8ecb485e..74f4e4eff 100644 --- a/vendor/box2d/wasm.Makefile +++ b/vendor/box2d/wasm.Makefile @@ -7,20 +7,20 @@ # CC = $(shell brew --prefix llvm)/bin/clang # LD = $(shell brew --prefix llvm)/bin/wasm-ld -VERSION = 3.0.0 +VERSION = 3.1.0 SRCS = $(wildcard box2d-$(VERSION)/src/*.c) OBJS_SIMD = $(SRCS:.c=_simd.o) OBJS = $(SRCS:.c=.o) SYSROOT = $(shell odin root)/vendor/libc -CFLAGS = -Ibox2d-$(VERSION)/include -Ibox2d-$(VERSION)/extern/simde --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT) +CFLAGS = -Ibox2d-$(VERSION)/include --target=wasm32 -D__EMSCRIPTEN__ -DNDEBUG -O3 --sysroot=$(SYSROOT) -all: lib/box2d_wasm.o lib/box2d_wasm_simd.o clean +all: lib/box2d_wasm.o lib/box2d_wasm_simd.o %.o: %.c - $(CC) -c $(CFLAGS) $< -o $@ + $(CC) -c $(CFLAGS) -DBOX2D_DISABLE_SIMD $< -o $@ %_simd.o: %.c - $(CC) -c $(CFLAGS) -msimd128 $< -o $@ + $(CC) -c $(CFLAGS) -DBOX2D_DISABLE_SIMD -msimd128 $< -o $@ lib/box2d_wasm.o: $(OBJS) $(LD) -r -o lib/box2d_wasm.o $(OBJS) diff --git a/vendor/cgltf/cgltf.odin b/vendor/cgltf/cgltf.odin index e9dc7ef84..bab58d851 100644 --- a/vendor/cgltf/cgltf.odin +++ b/vendor/cgltf/cgltf.odin @@ -262,12 +262,28 @@ image :: struct { extensions: [^]extension `fmt:"v,extensions_count"`, } +filter_type :: enum c.int { + undefined = 0, + nearest = 9728, + linear = 9729, + nearest_mipmap_nearest = 9984, + linear_mipmap_nearest = 9985, + nearest_mipmap_linear = 9986, + linear_mipmap_linear = 9987, +} + +wrap_mode :: enum c.int { + clamp_to_edge = 33071, + mirrored_repeat = 33648, + repeat = 10497, +} + sampler :: struct { name: cstring, - mag_filter: c.int, - min_filter: c.int, - wrap_s: c.int, - wrap_t: c.int, + mag_filter: filter_type, + min_filter: filter_type, + wrap_s: wrap_mode, + wrap_t: wrap_mode, extras: extras_t, extensions_count: uint, extensions: [^]extension `fmt:"v,extensions_count"`, diff --git a/vendor/darwin/Metal/MetalClasses.odin b/vendor/darwin/Metal/MetalClasses.odin index 2d681b0ee..67cf84f1e 100644 --- a/vendor/darwin/Metal/MetalClasses.odin +++ b/vendor/darwin/Metal/MetalClasses.odin @@ -2767,6 +2767,14 @@ RenderPipelineDescriptor_fragmentBuffers :: #force_inline proc "c" (self: ^Rende RenderPipelineDescriptor_fragmentFunction :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> ^Function { return msgSend(^Function, self, "fragmentFunction") } +@(objc_type=RenderPipelineDescriptor, objc_name="vertexLinkedFunctions") +RenderPipelineDescriptor_vertexLinkedFunctions :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> ^LinkedFunctions { + return msgSend(^LinkedFunctions, self, "vertexLinkedFunctions") +} +@(objc_type=RenderPipelineDescriptor, objc_name="fragmentLinkedFunctions") +RenderPipelineDescriptor_fragmentLinkedFunctions :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> ^LinkedFunctions { + return msgSend(^LinkedFunctions, self, "fragmentLinkedFunctions") +} @(objc_type=RenderPipelineDescriptor, objc_name="inputPrimitiveTopology") RenderPipelineDescriptor_inputPrimitiveTopology :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> PrimitiveTopologyClass { return msgSend(PrimitiveTopologyClass, self, "inputPrimitiveTopology") @@ -2831,6 +2839,14 @@ RenderPipelineDescriptor_setDepthAttachmentPixelFormat :: #force_inline proc "c" RenderPipelineDescriptor_setFragmentFunction :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, fragmentFunction: ^Function) { msgSend(nil, self, "setFragmentFunction:", fragmentFunction) } +@(objc_type=RenderPipelineDescriptor, objc_name="setVertexLinkedFunctions") +RenderPipelineDescriptor_setVertexLinkedFunctions :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, vertexLinkedFunctions: ^LinkedFunctions) { + msgSend(nil, self, "setVertexLinkedFunctions:", vertexLinkedFunctions) +} +@(objc_type=RenderPipelineDescriptor, objc_name="setFragmentLinkedFunctions") +RenderPipelineDescriptor_setFragmentLinkedFunctions :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, fragmentLinkedFunctions: ^LinkedFunctions) { + msgSend(nil, self, "setFragmentLinkedFunctions:", fragmentLinkedFunctions) +} @(objc_type=RenderPipelineDescriptor, objc_name="setInputPrimitiveTopology") RenderPipelineDescriptor_setInputPrimitiveTopology :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, inputPrimitiveTopology: PrimitiveTopologyClass) { msgSend(nil, self, "setInputPrimitiveTopology:", inputPrimitiveTopology) @@ -2940,86 +2956,6 @@ RenderPipelineDescriptor_vertexFunction :: #force_inline proc "c" (self: ^Render return msgSend(^Function, self, "vertexFunction") } -@(objc_type=RenderPipelineDescriptor, objc_name="objectFunction") -RenderPipelineDescriptor_objectFunction :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> ^Function { - return msgSend(^Function, self, "objectFunction") -} -@(objc_type=RenderPipelineDescriptor, objc_name="setObjectFunction") -RenderPipelineDescriptor_setObjectFunction :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, objectFunction: ^Function) { - msgSend(nil, self, "setObjectFunction:", objectFunction) -} -@(objc_type=RenderPipelineDescriptor, objc_name="meshFunction") -RenderPipelineDescriptor_meshFunction :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> ^Function { - return msgSend(^Function, self, "meshFunction") -} -@(objc_type=RenderPipelineDescriptor, objc_name="setMeshFunction") -RenderPipelineDescriptor_setMeshFunction :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, meshFunction: ^Function) { - msgSend(nil, self, "setMeshFunction:", meshFunction) -} - -@(objc_type=RenderPipelineDescriptor, objc_name="maxTotalThreadsPerObjectThreadgroup") -RenderPipelineDescriptor_maxTotalThreadsPerObjectThreadgroup :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "maxTotalThreadsPerObjectThreadgroup") -} -@(objc_type=RenderPipelineDescriptor, objc_name="setMaxTotalThreadsPerObjectThreadgroup") -RenderPipelineDescriptor_setMaxTotalThreadsPerObjectThreadgroup :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, maxTotalThreadsPerObjectThreadgroup: NS.UInteger) { - msgSend(nil, self, "setMaxTotalThreadsPerObjectThreadgroup:", maxTotalThreadsPerObjectThreadgroup) -} -@(objc_type=RenderPipelineDescriptor, objc_name="maxTotalThreadsPerMeshThreadgroup") -RenderPipelineDescriptor_maxTotalThreadsPerMeshThreadgroup :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "maxTotalThreadsPerMeshThreadgroup") -} -@(objc_type=RenderPipelineDescriptor, objc_name="setMaxTotalThreadsPerMeshThreadgroup") -RenderPipelineDescriptor_setMaxTotalThreadsPerMeshThreadgroup :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, maxTotalThreadsPerMeshThreadgroup: NS.UInteger) { - msgSend(nil, self, "setMaxTotalThreadsPerMeshThreadgroup:", maxTotalThreadsPerMeshThreadgroup) -} -@(objc_type=RenderPipelineDescriptor, objc_name="objectThreadgroupSizeIsMultipleOfThreadExecutionWidth") -RenderPipelineDescriptor_objectThreadgroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "objectThreadgroupSizeIsMultipleOfThreadExecutionWidth") -} -@(objc_type=RenderPipelineDescriptor, objc_name="setObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth") -RenderPipelineDescriptor_setObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, objectThreadgroupSizeIsMultipleOfThreadExecutionWidth: NS.UInteger) { - msgSend(nil, self, "setObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth:", objectThreadgroupSizeIsMultipleOfThreadExecutionWidth) -} - -@(objc_type=RenderPipelineDescriptor, objc_name="meshThreadgroupSizeIsMultipleOfThreadExecutionWidth") -RenderPipelineDescriptor_meshThreadgroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> BOOL { - return msgSend(BOOL, self, "meshThreadgroupSizeIsMultipleOfThreadExecutionWidth") -} -@(objc_type=RenderPipelineDescriptor, objc_name="setMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth") -RenderPipelineDescriptor_setMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, meshThreadgroupSizeIsMultipleOfThreadExecutionWidth: BOOL) { - msgSend(nil, self, "setMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth:", meshThreadgroupSizeIsMultipleOfThreadExecutionWidth) -} - - -@(objc_type=RenderPipelineDescriptor, objc_name="payloadMemoryLength") -RenderPipelineDescriptor_payloadMemoryLength :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "payloadMemoryLength") -} -@(objc_type=RenderPipelineDescriptor, objc_name="setPayloadMemoryLength") -RenderPipelineDescriptor_setPayloadMemoryLength :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, payloadMemoryLength: NS.UInteger) { - msgSend(nil, self, "setPayloadMemoryLength:", payloadMemoryLength) -} -@(objc_type=RenderPipelineDescriptor, objc_name="maxTotalThreadgroupsPerMeshGrid") -RenderPipelineDescriptor_maxTotalThreadgroupsPerMeshGrid :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> NS.UInteger { - return msgSend(NS.UInteger, self, "maxTotalThreadgroupsPerMeshGrid") -} -@(objc_type=RenderPipelineDescriptor, objc_name="setMaxTotalThreadgroupsPerMeshGrid") -RenderPipelineDescriptor_setMaxTotalThreadgroupsPerMeshGrid :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, maxTotalThreadgroupsPerMeshGrid: NS.UInteger) { - msgSend(nil, self, "setMaxTotalThreadgroupsPerMeshGrid:", maxTotalThreadgroupsPerMeshGrid) -} - -@(objc_type=RenderPipelineDescriptor, objc_name="objectBuffers") -RenderPipelineDescriptor_objectBuffers :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { - return msgSend(^PipelineBufferDescriptorArray, self, "objectBuffers") -} -@(objc_type=RenderPipelineDescriptor, objc_name="meshBuffers") -RenderPipelineDescriptor_meshBuffers :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { - return msgSend(^PipelineBufferDescriptorArray, self, "meshBuffers") -} - - - @(objc_type=RenderPipelineDescriptor, objc_name="alphaToCoverageEnabled") RenderPipelineDescriptor_alphaToCoverageEnabled :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> BOOL { return msgSend(BOOL, self, "alphaToCoverageEnabled") @@ -3034,6 +2970,272 @@ RenderPipelineDescriptor_rasterizationEnabled :: #force_inline proc "c" (self: ^ return msgSend(BOOL, self, "rasterizationEnabled") } +@(objc_type=RenderPipelineDescriptor, objc_name="shaderValidation") +RenderPipelineDescriptor_shaderValidation :: #force_inline proc "c" (self: ^RenderPipelineDescriptor) -> ShaderValidation { + return msgSend(ShaderValidation, self, "shaderValidation") +} +@(objc_type=RenderPipelineDescriptor, objc_name="setShaderValidation") +RenderPipelineDescriptor_setShaderValidation :: #force_inline proc "c" (self: ^RenderPipelineDescriptor, shaderValidation: ShaderValidation) { + msgSend(nil, self, "setShaderValidation:", shaderValidation) +} + + +//////////////////////////////////////////////////////////////////////////////// + + +@(objc_class="MTLMeshRenderPipelineDescriptor") +MeshRenderPipelineDescriptor :: struct{ using _: NS.Copying(MeshRenderPipelineDescriptor) } + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="alloc", objc_is_class_method=true) +MeshRenderPipelineDescriptor_alloc :: #force_inline proc "c" () -> ^MeshRenderPipelineDescriptor { + return msgSend(^MeshRenderPipelineDescriptor, MeshRenderPipelineDescriptor, "alloc") +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="init") +MeshRenderPipelineDescriptor_init :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^MeshRenderPipelineDescriptor { + return msgSend(^MeshRenderPipelineDescriptor, self, "init") +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="binaryArchives") +MeshRenderPipelineDescriptor_binaryArchives :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^NS.Array { + return msgSend(^NS.Array, self, "binaryArchives") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setBinaryArchives") +MeshRenderPipelineDescriptor_setBinaryArchives :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, binaryArchives: ^NS.Array) { + msgSend(nil, self, "setBinaryArchives:", binaryArchives) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="colorAttachments") +MeshRenderPipelineDescriptor_colorAttachments :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^RenderPipelineColorAttachmentDescriptorArray { + return msgSend(^RenderPipelineColorAttachmentDescriptorArray, self, "colorAttachments") +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="depthAttachmentPixelFormat") +MeshRenderPipelineDescriptor_depthAttachmentPixelFormat :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> PixelFormat { + return msgSend(PixelFormat, self, "depthAttachmentPixelFormat") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setDepthAttachmentPixelFormat") +MeshRenderPipelineDescriptor_setDepthAttachmentPixelFormat :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, depthAttachmentPixelFormat: PixelFormat) { + msgSend(nil, self, "setDepthAttachmentPixelFormat:", depthAttachmentPixelFormat) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="fragmentBuffers") +MeshRenderPipelineDescriptor_fragmentBuffers :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { + return msgSend(^PipelineBufferDescriptorArray, self, "fragmentBuffers") +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="fragmentFunction") +MeshRenderPipelineDescriptor_fragmentFunction :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^Function { + return msgSend(^Function, self, "fragmentFunction") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setFragmentFunction") +MeshRenderPipelineDescriptor_setFragmentFunction :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, fragmentFunction: ^Function) { + msgSend(nil, self, "setFragmentFunction:", fragmentFunction) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="fragmentLinkedFunctions") +MeshRenderPipelineDescriptor_fragmentLinkedFunctions :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^LinkedFunctions { + return msgSend(^LinkedFunctions, self, "fragmentLinkedFunctions") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setFragmentLinkedFunctions") +MeshRenderPipelineDescriptor_setFragmentLinkedFunctions :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, fragmentLinkedFunctions: ^LinkedFunctions) { + msgSend(nil, self, "setFragmentLinkedFunctions:", fragmentLinkedFunctions) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="alphaToCoverageEnabled") +MeshRenderPipelineDescriptor_alphaToCoverageEnabled :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "alphaToCoverageEnabled") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="isAlphaToCoverageEnabled") +MeshRenderPipelineDescriptor_isAlphaToCoverageEnabled :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "isAlphaToCoverageEnabled") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setAlphaToCoverageEnabled") +MeshRenderPipelineDescriptor_setAlphaToCoverageEnabled :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, alphaToCoverageEnabled: BOOL) { + msgSend(nil, self, "setAlphaToCoverageEnabled:", alphaToCoverageEnabled) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="alphaToOneEnabled") +MeshRenderPipelineDescriptor_alphaToOneEnabled :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "alphaToOneEnabled") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="isAlphaToOneEnabled") +MeshRenderPipelineDescriptor_isAlphaToOneEnabled :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "isAlphaToOneEnabled") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setAlphaToOneEnabled") +MeshRenderPipelineDescriptor_setAlphaToOneEnabled :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, alphaToOneEnabled: BOOL) { + msgSend(nil, self, "setAlphaToOneEnabled:", alphaToOneEnabled) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="rasterizationEnabled") +MeshRenderPipelineDescriptor_rasterizationEnabled :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "rasterizationEnabled") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="isRasterizationEnabled") +MeshRenderPipelineDescriptor_isRasterizationEnabled :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "isRasterizationEnabled") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setRasterizationEnabled") +MeshRenderPipelineDescriptor_setRasterizationEnabled :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, rasterizationEnabled: BOOL) { + msgSend(nil, self, "setRasterizationEnabled:", rasterizationEnabled) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="label") +MeshRenderPipelineDescriptor_label :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^NS.String { + return msgSend(^NS.String, self, "label") +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="maxTotalThreadgroupsPerMeshGrid") +MeshRenderPipelineDescriptor_maxTotalThreadgroupsPerMeshGrid :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxTotalThreadgroupsPerMeshGrid") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setMaxTotalThreadgroupsPerMeshGrid") +MeshRenderPipelineDescriptor_setMaxTotalThreadgroupsPerMeshGrid :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, maxTotalThreadgroupsPerMeshGrid: NS.UInteger) { + msgSend(nil, self, "setMaxTotalThreadgroupsPerMeshGrid:", maxTotalThreadgroupsPerMeshGrid) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="maxTotalThreadsPerMeshThreadgroup") +MeshRenderPipelineDescriptor_maxTotalThreadsPerMeshThreadgroup :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxTotalThreadsPerMeshThreadgroup") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setMaxTotalThreadsPerMeshThreadgroup") +MeshRenderPipelineDescriptor_setMaxTotalThreadsPerMeshThreadgroup :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, maxTotalThreadsPerMeshThreadgroup: NS.UInteger) { + msgSend(nil, self, "setMaxTotalThreadsPerMeshThreadgroup:", maxTotalThreadsPerMeshThreadgroup) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="maxTotalThreadsPerObjectThreadgroup") +MeshRenderPipelineDescriptor_maxTotalThreadsPerObjectThreadgroup :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxTotalThreadsPerObjectThreadgroup") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setMaxTotalThreadsPerObjectThreadgroup") +MeshRenderPipelineDescriptor_setMaxTotalThreadsPerObjectThreadgroup :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, maxTotalThreadsPerObjectThreadgroup: NS.UInteger) { + msgSend(nil, self, "setMaxTotalThreadsPerObjectThreadgroup:", maxTotalThreadsPerObjectThreadgroup) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="maxVertexAmplificationCount") +MeshRenderPipelineDescriptor_maxVertexAmplificationCount :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "maxVertexAmplificationCount") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setMaxVertexAmplificationCount") +MeshRenderPipelineDescriptor_setMaxVertexAmplificationCount :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, maxVertexAmplificationCount: NS.UInteger) { + msgSend(nil, self, "setMaxVertexAmplificationCount:", maxVertexAmplificationCount) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="meshBuffers") +MeshRenderPipelineDescriptor_meshBuffers :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { + return msgSend(^PipelineBufferDescriptorArray, self, "meshBuffers") +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="meshFunction") +MeshRenderPipelineDescriptor_meshFunction :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^Function { + return msgSend(^Function, self, "meshFunction") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setMeshFunction") +MeshRenderPipelineDescriptor_setMeshFunction :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, meshFunction: ^Function) { + msgSend(nil, self, "setMeshFunction:", meshFunction) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="meshLinkedFunctions") +MeshRenderPipelineDescriptor_meshLinkedFunctions :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^LinkedFunctions { + return msgSend(^LinkedFunctions, self, "meshLinkedFunctions") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setMeshLinkedFunctions") +MeshRenderPipelineDescriptor_setMeshLinkedFunctions :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, meshLinkedFunctions: ^LinkedFunctions) { + msgSend(nil, self, "setMeshLinkedFunctions:", meshLinkedFunctions) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="meshThreadgroupSizeIsMultipleOfThreadExecutionWidth") +MeshRenderPipelineDescriptor_meshThreadgroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "meshThreadgroupSizeIsMultipleOfThreadExecutionWidth") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth") +MeshRenderPipelineDescriptor_setMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, meshThreadgroupSizeIsMultipleOfThreadExecutionWidth: BOOL) { + msgSend(nil, self, "setMeshThreadgroupSizeIsMultipleOfThreadExecutionWidth:", meshThreadgroupSizeIsMultipleOfThreadExecutionWidth) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="objectBuffers") +MeshRenderPipelineDescriptor_objectBuffers :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^PipelineBufferDescriptorArray { + return msgSend(^PipelineBufferDescriptorArray, self, "objectBuffers") +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="objectFunction") +MeshRenderPipelineDescriptor_objectFunction :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^Function { + return msgSend(^Function, self, "objectFunction") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setObjectFunction") +MeshRenderPipelineDescriptor_setObjectFunction :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, objectFunction: ^Function) { + msgSend(nil, self, "setObjectFunction:", objectFunction) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="objectLinkedFunctions") +MeshRenderPipelineDescriptor_objectLinkedFunctions :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ^LinkedFunctions { + return msgSend(^LinkedFunctions, self, "objectLinkedFunctions") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setObjectLinkedFunctions") +MeshRenderPipelineDescriptor_setObjectLinkedFunctions :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, objectLinkedFunctions: ^LinkedFunctions) { + msgSend(nil, self, "setObjectLinkedFunctions:", objectLinkedFunctions) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="objectThreadgroupSizeIsMultipleOfThreadExecutionWidth") +MeshRenderPipelineDescriptor_objectThreadgroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "objectThreadgroupSizeIsMultipleOfThreadExecutionWidth") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth") +MeshRenderPipelineDescriptor_setObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, objectThreadgroupSizeIsMultipleOfThreadExecutionWidth: BOOL) { + msgSend(nil, self, "setObjectThreadgroupSizeIsMultipleOfThreadExecutionWidth:", objectThreadgroupSizeIsMultipleOfThreadExecutionWidth) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="payloadMemoryLength") +MeshRenderPipelineDescriptor_payloadMemoryLength :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "payloadMemoryLength") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setPayloadMemoryLength") +MeshRenderPipelineDescriptor_setPayloadMemoryLength :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, payloadMemoryLength: NS.UInteger) { + msgSend(nil, self, "setPayloadMemoryLength:", payloadMemoryLength) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="rasterSampleCount") +MeshRenderPipelineDescriptor_rasterSampleCount :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> NS.UInteger { + return msgSend(NS.UInteger, self, "rasterSampleCount") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setRasterSampleCount") +MeshRenderPipelineDescriptor_setRasterSampleCount :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, rasterSampleCount: NS.UInteger) { + msgSend(nil, self, "setRasterSampleCount:", rasterSampleCount) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="shaderValidation") +MeshRenderPipelineDescriptor_shaderValidation :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> ShaderValidation { + return msgSend(ShaderValidation, self, "shaderValidation") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setShaderValidation") +MeshRenderPipelineDescriptor_setShaderValidation :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, shaderValidation: ShaderValidation) { + msgSend(nil, self, "setShaderValidation:", shaderValidation) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="stencilAttachmentPixelFormat") +MeshRenderPipelineDescriptor_stencilAttachmentPixelFormat :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> PixelFormat { + return msgSend(PixelFormat, self, "stencilAttachmentPixelFormat") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setStencilAttachmentPixelFormat") +MeshRenderPipelineDescriptor_setStencilAttachmentPixelFormat :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, stencilAttachmentPixelFormat: PixelFormat) { + msgSend(nil, self, "setStencilAttachmentPixelFormat:", stencilAttachmentPixelFormat) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="supportIndirectCommandBuffers") +MeshRenderPipelineDescriptor_supportIndirectCommandBuffers :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) -> BOOL { + return msgSend(BOOL, self, "supportIndirectCommandBuffers") +} +@(objc_type=MeshRenderPipelineDescriptor, objc_name="setSupportIndirectCommandBuffers") +MeshRenderPipelineDescriptor_setSupportIndirectCommandBuffers :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor, supportIndirectCommandBuffers: BOOL) { + msgSend(nil, self, "setSupportIndirectCommandBuffers:", supportIndirectCommandBuffers) +} + +@(objc_type=MeshRenderPipelineDescriptor, objc_name="reset") +MeshRenderPipelineDescriptor_reset :: #force_inline proc "c" (self: ^MeshRenderPipelineDescriptor) { + msgSend(nil, self, "reset") +} + //////////////////////////////////////////////////////////////////////////////// @@ -4105,9 +4307,9 @@ AccelerationStructure_size :: #force_inline proc "c" (self: ^AccelerationStructu return msgSend(NS.UInteger, self, "size") } -@(objc_type=AccelerationStructure, objc_name="getResourceID") -AccelerationStructure_getResourceID :: #force_inline proc "c" (self: ^AccelerationStructure) -> ResourceID { - return msgSend(ResourceID, self, "getResourceID") +@(objc_type=AccelerationStructure, objc_name="gpuResourceID") +AccelerationStructure_gpuResourceID :: #force_inline proc "c" (self: ^AccelerationStructure) -> ResourceID { + return msgSend(ResourceID, self, "gpuResourceID") } //////////////////////////////////////////////////////////////////////////////// @@ -5379,7 +5581,7 @@ Device_newBufferWithSlice :: #force_inline proc "c" (self: ^Device, slice: $S/[] } @(objc_type=Device, objc_name="newBufferWithSliceNoCopy") Device_newBufferWithSliceNoCopy :: #force_inline proc "c" (self: ^Device, slice: $S/[]$E, options: ResourceOptions, deallocator: rawptr) -> ^Buffer { - return Device_newBufferWithBytesNotCopy(self, mem.slice_to_bytes(slice), options, deallocator) + return Device_newBufferWithBytesNoCopy(self, mem.slice_to_bytes(slice), options, deallocator) } @(objc_type=Device, objc_name="newBufferWithLength") Device_newBufferWithLength :: #force_inline proc "c" (self: ^Device, length: NS.UInteger, options: ResourceOptions) -> ^Buffer { @@ -5702,14 +5904,13 @@ Device_supportsVertexAmplificationCount :: #force_inline proc "c" (self: ^Device @(objc_type=Device, objc_name="newRenderPipelineStateWithMeshDescriptor") -Device_newRenderPipelineStateWithMeshDescriptor :: #force_inline proc "contextless" (self: ^Device, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (state: ^RenderPipelineState, error: ^NS.Error) { - state = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithMeshDescriptor:options:reflection:error:", options, reflection, &error) +Device_newRenderPipelineStateWithMeshDescriptor :: #force_inline proc "c" (self: ^Device, descriptor: ^MeshRenderPipelineDescriptor, options: PipelineOption, reflection: ^AutoreleasedRenderPipelineReflection) -> (state: ^RenderPipelineState, error: ^NS.Error) { + state = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithMeshDescriptor:options:reflection:error:", descriptor, options, reflection, &error) return } @(objc_type=Device, objc_name="newRenderPipelineStateWithMeshDescriptorAndCompletionHandler") -Device_newRenderPipelineStateWithMeshDescriptorAndCompletionHandler :: #force_inline proc "c" (self: ^Device, options: PipelineOption, completionHandler: ^NewRenderPipelineStateWithReflectionCompletionHandler) -> (state: ^RenderPipelineState) { - state = msgSend(^RenderPipelineState, self, "newRenderPipelineStateWithMeshDescriptor:options:completionHandler:", options, completionHandler) - return +Device_newRenderPipelineStateWithMeshDescriptorAndCompletionHandler :: #force_inline proc "c" (self: ^Device, descriptor: ^MeshRenderPipelineDescriptor, options: PipelineOption, completionHandler: NewRenderPipelineStateWithReflectionCompletionHandler) { + msgSend(nil, self, "newRenderPipelineStateWithMeshDescriptor:options:completionHandler:", descriptor, options, completionHandler) } @(objc_type=Device, objc_name="newIOHandle") diff --git a/vendor/darwin/Metal/MetalEnums.odin b/vendor/darwin/Metal/MetalEnums.odin index 5cef5f18d..7d4e86d65 100644 --- a/vendor/darwin/Metal/MetalEnums.odin +++ b/vendor/darwin/Metal/MetalEnums.odin @@ -1050,3 +1050,9 @@ VertexStepFunction :: enum NS.UInteger { PerPatch = 3, PerPatchControlPoint = 4, } + +ShaderValidation :: enum NS.UInteger { + Default = 0, + Enabled = 1, + Disabled = 2, +} diff --git a/vendor/directx/d3d11/d3d11.odin b/vendor/directx/d3d11/d3d11.odin index bb91e87ce..c15f19934 100644 --- a/vendor/directx/d3d11/d3d11.odin +++ b/vendor/directx/d3d11/d3d11.odin @@ -19,7 +19,7 @@ BOOL :: dxgi.BOOL UINT :: dxgi.UINT INT :: dxgi.INT -LPCWSTR :: [^]u16 +LPCWSTR :: windows.LPCWSTR RECT :: dxgi.RECT SIZE :: dxgi.SIZE diff --git a/vendor/directx/d3d12/d3d12.odin b/vendor/directx/d3d12/d3d12.odin index a533ab7ae..0d4dbc4e0 100644 --- a/vendor/directx/d3d12/d3d12.odin +++ b/vendor/directx/d3d12/d3d12.odin @@ -22,6 +22,8 @@ BOOL :: dxgi.BOOL RECT :: dxgi.RECT +LPCWSTR :: win32.LPCWSTR + IModuleInstance :: d3d_compiler.ID3D11ModuleInstance IBlob :: d3d_compiler.ID3DBlob IModule :: d3d_compiler.ID3D11Module @@ -680,7 +682,7 @@ IObject_VTable :: struct { GetPrivateData: proc "system" (this: ^IObject, guid: ^GUID, pDataSize: ^u32, pData: rawptr) -> HRESULT, SetPrivateData: proc "system" (this: ^IObject, guid: ^GUID, DataSize: u32, pData: rawptr) -> HRESULT, SetPrivateDataInterface: proc "system" (this: ^IObject, guid: ^GUID, pData: ^IUnknown) -> HRESULT, - SetName: proc "system" (this: ^IObject, Name: [^]u16) -> HRESULT, + SetName: proc "system" (this: ^IObject, Name: LPCWSTR) -> HRESULT, } @@ -837,12 +839,22 @@ FEATURE :: enum i32 { OPTIONS8 = 36, OPTIONS9 = 37, WAVE_MMA = 38, + OPTIONS10 = 39, + OPTIONS11 = 40, + OPTIONS12 = 41, + OPTIONS13 = 42, + OPTIONS14 = 43, + OPTIONS15 = 44, + OPTIONS16 = 45, + OPTIONS17 = 46, + OPTIONS18 = 47, + OPTIONS19 = 48, } -SHADER_MIN_PRECISION_SUPPORT :: enum i32 { - NONE = 0, - _10_BIT = 1, - _16_BIT = 2, +SHADER_MIN_PRECISION_SUPPORT :: distinct bit_set[SHADER_MIN_PRECISION_SUPPORT_FLAG; u32] +SHADER_MIN_PRECISION_SUPPORT_FLAG :: enum i32 { + _10_BIT, + _16_BIT, } TILED_RESOURCES_TIER :: enum i32 { @@ -1195,6 +1207,74 @@ FEATURE_DATA_OPTIONS9 :: struct { WaveMMATier: WAVE_MMA_TIER, } +FEATURE_DATA_OPTIONS10 :: struct { + VariableRateShadingSumCombinerSupported: BOOL, + MeshShaderPerPrimitiveShadingRateSupported: BOOL, +} + +FEATURE_DATA_OPTIONS11 :: struct { + AtomicInt64OnDescriptorHeapResourceSupported: BOOL, +} + +TRI_STATE :: enum i32 { + UNKNOWN = -1, + FALSE = 0, + TRUE = 1, +} + +FEATURE_DATA_OPTIONS12 :: struct { + MSPrimitivesPipelineStatisticIncludesCulledPrimitives: TRI_STATE, + EnhancedBarriersSupported: BOOL, + RelaxedFormatCastingSupported: BOOL, +} + +FEATURE_DATA_OPTIONS13 :: struct { + UnrestrictedBufferTextureCopyPitchSupported: BOOL, + UnrestrictedVertexElementAlignmentSupported: BOOL, + InvertedViewportHeightFlipsYSupported: BOOL, + InvertedViewportDepthFlipsZSupported: BOOL, + TextureCopyBetweenDimensionsSupported: BOOL, + AlphaBlendFactorSupported: BOOL, +} + +FEATURE_DATA_OPTIONS14 :: struct { + AdvancedTextureOpsSupported: BOOL, + WriteableMSAATexturesSupported: BOOL, + IndependentFrontAndBackStencilRefMaskSupported: BOOL, +} + +FEATURE_DATA_OPTIONS15 :: struct { + TriangleFanSupported: BOOL, + DynamicIndexBufferStripCutSupported: BOOL, +} + +FEATURE_DATA_OPTIONS16 :: struct { + DynamicDepthBiasSupported: BOOL, + GPUUploadHeapSupported: BOOL, +} + +FEATURE_DATA_OPTIONS17 :: struct { + NonNormalizedCoordinateSamplersSupported: BOOL, + ManualWriteTrackingResourceSupported: BOOL, +} + +FEATURE_DATA_OPTIONS18 :: struct { + RenderPassesValid: BOOL, +} + +FEATURE_DATA_OPTIONS19 :: struct { + MismatchingOutputDimensionsSupported: BOOL, + SupportedSampleCountsWithNoOutputs: u32, + PointSamplingAddressesNeverRoundUp: BOOL, + RasterizerDesc2Supported: BOOL, + NarrowQuadrilateralLinesSupported: BOOL, + AnisoFilterWithPointMipSupported: BOOL, + MaxSamplerDescriptorHeapSize: u32, + MaxSamplerDescriptorHeapSizeWithStaticSamplers: u32, + MaxViewDescriptorHeapSize: u32, + ComputeOnlyCustomHeapSupported: BOOL, +} + WAVE_MMA_INPUT_DATATYPE :: enum i32 { INVALID = 0, BYTE = 1, @@ -1238,10 +1318,11 @@ RESOURCE_ALLOCATION_INFO1 :: struct { } HEAP_TYPE :: enum i32 { - DEFAULT = 1, - UPLOAD = 2, - READBACK = 3, - CUSTOM = 4, + DEFAULT = 1, + UPLOAD = 2, + READBACK = 3, + CUSTOM = 4, + GPU_UPLOAD = 5, } CPU_PAGE_PROPERTY :: enum i32 { @@ -1473,7 +1554,7 @@ RESOURCE_STATE_GENERIC_READ :: RESOURCE_STATES{ .VERTEX_AND_CONSTANT_BUFFER, .INDEX_BUFFER, .NON_PIXEL_SHADER_RESOURCE, .PIXEL_SHADER_RESOURCE, .INDIRECT_ARGUMENT, .COPY_SOURCE, } RESOURCE_STATE_ALL_SHADER_RESOURCE :: RESOURCE_STATES{ - .SHADING_RATE_SOURCE, .INDEX_BUFFER, + .NON_PIXEL_SHADER_RESOURCE, .PIXEL_SHADER_RESOURCE, } RESOURCE_BARRIER_TYPE :: enum i32 { @@ -2635,9 +2716,9 @@ IDevice_VTable :: struct { CreateHeap: proc "system" (this: ^IDevice, pDesc: ^HEAP_DESC, riid: ^IID, ppvHeap: ^rawptr) -> HRESULT, CreatePlacedResource: proc "system" (this: ^IDevice, pHeap: ^IHeap, HeapOffset: u64, pDesc: ^RESOURCE_DESC, InitialState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, riid: ^IID, ppvResource: ^rawptr) -> HRESULT, CreateReservedResource: proc "system" (this: ^IDevice, pDesc: ^RESOURCE_DESC, InitialState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, riid: ^IID, ppvResource: ^rawptr) -> HRESULT, - CreateSharedHandle: proc "system" (this: ^IDevice, pObject: ^IDeviceChild, pAttributes: ^win32.SECURITY_ATTRIBUTES, Access: u32, Name: [^]u16, pHandle: ^HANDLE) -> HRESULT, + CreateSharedHandle: proc "system" (this: ^IDevice, pObject: ^IDeviceChild, pAttributes: ^win32.SECURITY_ATTRIBUTES, Access: u32, Name: LPCWSTR, pHandle: ^HANDLE) -> HRESULT, OpenSharedHandle: proc "system" (this: ^IDevice, NTHandle: HANDLE, riid: ^IID, ppvObj: ^rawptr) -> HRESULT, - OpenSharedHandleByName: proc "system" (this: ^IDevice, Name: [^]u16, Access: u32, pNTHandle: ^HANDLE) -> HRESULT, + OpenSharedHandleByName: proc "system" (this: ^IDevice, Name: LPCWSTR, Access: u32, pNTHandle: ^HANDLE) -> HRESULT, MakeResident: proc "system" (this: ^IDevice, NumObjects: u32, ppObjects: [^]^IPageable) -> HRESULT, Evict: proc "system" (this: ^IDevice, NumObjects: u32, ppObjects: [^]^IPageable) -> HRESULT, CreateFence: proc "system" (this: ^IDevice, InitialValue: u64, Flags: FENCE_FLAGS, riid: ^IID, ppFence: ^rawptr) -> HRESULT, @@ -2659,9 +2740,9 @@ IPipelineLibrary :: struct #raw_union { } IPipelineLibrary_VTable :: struct { using id3d12devicechild_vtable: IDeviceChild_VTable, - StorePipeline: proc "system" (this: ^IPipelineLibrary, pName: [^]u16, pPipeline: ^IPipelineState) -> HRESULT, - LoadGraphicsPipeline: proc "system" (this: ^IPipelineLibrary, pName: [^]u16, pDesc: ^GRAPHICS_PIPELINE_STATE_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, - LoadComputePipeline: proc "system" (this: ^IPipelineLibrary, pName: [^]u16, pDesc: ^COMPUTE_PIPELINE_STATE_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, + StorePipeline: proc "system" (this: ^IPipelineLibrary, pName: LPCWSTR, pPipeline: ^IPipelineState) -> HRESULT, + LoadGraphicsPipeline: proc "system" (this: ^IPipelineLibrary, pName: LPCWSTR, pDesc: ^GRAPHICS_PIPELINE_STATE_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, + LoadComputePipeline: proc "system" (this: ^IPipelineLibrary, pName: LPCWSTR, pDesc: ^COMPUTE_PIPELINE_STATE_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, GetSerializedSize: proc "system" (this: ^IPipelineLibrary) -> SIZE_T, Serialize: proc "system" (this: ^IPipelineLibrary, pData: rawptr, DataSizeInBytes: SIZE_T) -> HRESULT, } @@ -2675,7 +2756,7 @@ IPipelineLibrary1 :: struct #raw_union { } IPipelineLibrary1_VTable :: struct { using id3d12pipelinelibrary_vtable: IPipelineLibrary_VTable, - LoadPipeline: proc "system" (this: ^IPipelineLibrary1, pName: [^]u16, pDesc: ^PIPELINE_STATE_STREAM_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, + LoadPipeline: proc "system" (this: ^IPipelineLibrary1, pName: LPCWSTR, pDesc: ^PIPELINE_STATE_STREAM_DESC, riid: ^IID, ppPipelineState: ^rawptr) -> HRESULT, } MULTIPLE_FENCE_WAIT_FLAGS :: distinct bit_set[MULTIPLE_FENCE_WAIT_FLAG; u32] @@ -2882,7 +2963,7 @@ META_COMMAND_PARAMETER_STAGE :: enum i32 { } META_COMMAND_PARAMETER_DESC :: struct { - Name: [^]u16, + Name: LPCWSTR, Type: META_COMMAND_PARAMETER_TYPE, Flags: META_COMMAND_PARAMETER_FLAGS, RequiredResourceState: RESOURCE_STATES, @@ -2912,7 +2993,7 @@ GRAPHICS_STATES :: enum i32 { META_COMMAND_DESC :: struct { Id: GUID, - Name: [^]u16, + Name: LPCWSTR, InitializationDirtyState: GRAPHICS_STATES, ExecutionDirtyState: GRAPHICS_STATES, } @@ -2933,8 +3014,8 @@ IStateObjectProperties :: struct #raw_union { } IStateObjectProperties_VTable :: struct { using iunknown_vtable: IUnknown_VTable, - GetShaderIdentifier: proc "system" (this: ^IStateObjectProperties, pExportName: [^]u16) -> rawptr, - GetShaderStackSize: proc "system" (this: ^IStateObjectProperties, pExportName: [^]u16) -> u64, + GetShaderIdentifier: proc "system" (this: ^IStateObjectProperties, pExportName: LPCWSTR) -> rawptr, + GetShaderStackSize: proc "system" (this: ^IStateObjectProperties, pExportName: LPCWSTR) -> u64, GetPipelineStackSize: proc "system" (this: ^IStateObjectProperties) -> u64, SetPipelineStackSize: proc "system" (this: ^IStateObjectProperties, PipelineStackSizeInBytes: u64), } @@ -2988,8 +3069,8 @@ EXPORT_FLAG :: enum u32 { } EXPORT_DESC :: struct { - Name: [^]u16, - ExportToRename: [^]u16, + Name: LPCWSTR, + ExportToRename: LPCWSTR, Flags: EXPORT_FLAGS, } @@ -3335,9 +3416,9 @@ AUTO_BREADCRUMB_OP :: enum i32 { AUTO_BREADCRUMB_NODE :: struct { pCommandListDebugNameA: cstring, - pCommandListDebugNameW: [^]u16, + pCommandListDebugNameW: LPCWSTR, pCommandQueueDebugNameA: cstring, - pCommandQueueDebugNameW: [^]u16, + pCommandQueueDebugNameW: LPCWSTR, pCommandList: ^IGraphicsCommandList, pCommandQueue: ^ICommandQueue, BreadcrumbCount: u32, @@ -3348,14 +3429,14 @@ AUTO_BREADCRUMB_NODE :: struct { DRED_BREADCRUMB_CONTEXT :: struct { BreadcrumbIndex: u32, - pContextString: [^]u16, + pContextString: LPCWSTR, } AUTO_BREADCRUMB_NODE1 :: struct { pCommandListDebugNameA: cstring, - pCommandListDebugNameW: [^]u16, + pCommandListDebugNameW: LPCWSTR, pCommandQueueDebugNameA: cstring, - pCommandQueueDebugNameW: [^]u16, + pCommandQueueDebugNameW: LPCWSTR, pCommandList: ^IGraphicsCommandList, pCommandQueue: ^ICommandQueue, BreadcrumbCount: u32, diff --git a/vendor/directx/dxc/dxcapi.odin b/vendor/directx/dxc/dxcapi.odin index 23dbc8f30..d9f8401db 100644 --- a/vendor/directx/dxc/dxcapi.odin +++ b/vendor/directx/dxc/dxcapi.odin @@ -194,7 +194,7 @@ ICompiler_VTable :: struct { using iunknown_vtable: IUnknown_VTable, Compile: proc "system" ( this: ^ICompiler, - pSource: ^Buffer, + pSource: ^IBlob, pSourceName: wstring, pEntryPoint: wstring, pTargetProfile: wstring, @@ -206,7 +206,7 @@ ICompiler_VTable :: struct { ppResult: ^^IOperationResult) -> HRESULT, Preprocess: proc "system" ( this: ^ICompiler, - pSource: ^Buffer, + pSource: ^IBlob, pSourceName: wstring, pArguments: [^]wstring, argCount: u32, @@ -227,7 +227,7 @@ ICompiler2_VTable :: struct { using idxccompiler_vtable: ^ICompiler_VTable, CompileWithDebug: proc "system" ( this: ^ICompiler2, - pSource: ^Buffer, + pSource: ^IBlob, pSourceName: wstring, pEntryPoint: wstring, pTargetProfile: wstring, @@ -286,7 +286,7 @@ IUtils_VTable :: struct { GetBlobAsUtf16: proc "system" (this: ^IUtils, pBlob: ^IBlob, pBlobEncoding: ^^IBlobUtf16) -> HRESULT, GetDxilContainerPart: proc "system" (this: ^IUtils, pShader: ^Buffer, Part: u32, ppPartData: rawptr, pPartSizeInBytes: ^u32) -> HRESULT, CreateReflection: proc "system" (this: ^IUtils, pData: ^Buffer, iid: ^IID, ppvReflection: rawptr) -> HRESULT, - BuildArguments: proc "system" (this: ^IUtils, pSourceName: wstring, pEntryPoint: wstring, pTargetProfile: wstring, pArguments: [^]wstring, argCount: u32, pDefines: [^]Define, defineCount: u32, ppArgs: ^[^]ICompilerArgs) -> HRESULT, + BuildArguments: proc "system" (this: ^IUtils, pSourceName: wstring, pEntryPoint: wstring, pTargetProfile: wstring, pArguments: [^]wstring, argCount: u32, pDefines: [^]Define, defineCount: u32, ppArgs: [^]^ICompilerArgs) -> HRESULT, GetPDBContents: proc "system" (this: ^IUtils, pPDBBlob: ^IBlob, ppHash: ^^IBlob, ppContainer: ^^IBlob) -> HRESULT, } diff --git a/vendor/directx/dxc/dxcdef_haiku.odin b/vendor/directx/dxc/dxcdef_haiku.odin new file mode 100644 index 000000000..44df94177 --- /dev/null +++ b/vendor/directx/dxc/dxcdef_haiku.odin @@ -0,0 +1,37 @@ +#+build haiku +package directx_dxc +import "core:c" + +FILETIME :: struct { + dwLowDateTime: DWORD, + dwHighDateTime: DWORD, +} + +GUID :: struct { + Data1: DWORD, + Data2: WORD, + Data3: WORD, + Data4: [8]BYTE, +} + +BYTE :: distinct u8 +WORD :: u16 +DWORD :: u32 +BOOL :: distinct b32 +SIZE_T :: uint +ULONG :: c.ulong +CLSID :: GUID +IID :: GUID +LONG :: distinct c.long +HRESULT :: distinct LONG +wstring :: [^]c.wchar_t +BSTR :: wstring + +IUnknown :: struct { + using _iunknown_vtable: ^IUnknown_VTable, +} +IUnknown_VTable :: struct { + QueryInterface: proc "c" (this: ^IUnknown, riid: ^IID, ppvObject: ^rawptr) -> HRESULT, + AddRef: proc "c" (this: ^IUnknown) -> ULONG, + Release: proc "c" (this: ^IUnknown) -> ULONG, +} diff --git a/vendor/glfw/bindings/bindings.odin b/vendor/glfw/bindings/bindings.odin index e59239483..abf6c2150 100644 --- a/vendor/glfw/bindings/bindings.odin +++ b/vendor/glfw/bindings/bindings.odin @@ -163,9 +163,9 @@ foreign glfw { SetJoystickUserPointer :: proc(jid: c.int, pointer: rawptr) --- GetJoystickUserPointer :: proc(jid: c.int) -> rawptr --- JoystickIsGamepad :: proc(jid: c.int) -> b32 --- - UpdateGamepadMappings :: proc(str: cstring) -> c.int --- + UpdateGamepadMappings :: proc(str: cstring) -> b32 --- GetGamepadName :: proc(jid: c.int) -> cstring --- - GetGamepadState :: proc(jid: c.int, state: ^GamepadState) -> c.int --- + GetGamepadState :: proc(jid: c.int, state: ^GamepadState) -> b32 --- SetClipboardString :: proc(window: WindowHandle, str: cstring) --- @@ -177,12 +177,12 @@ foreign glfw { MakeContextCurrent :: proc(window: WindowHandle) --- GetCurrentContext :: proc() -> WindowHandle --- GetProcAddress :: proc(name: cstring) -> rawptr --- - ExtensionSupported :: proc(extension: cstring) -> c.int --- + ExtensionSupported :: proc(extension: cstring) -> b32 --- VulkanSupported :: proc() -> b32 --- GetRequiredInstanceExtensions :: proc(count: ^u32) -> [^]cstring --- GetInstanceProcAddress :: proc(instance: vk.Instance, procname: cstring) -> rawptr --- - GetPhysicalDevicePresentationSupport :: proc(instance: vk.Instance, device: vk.PhysicalDevice, queuefamily: u32) -> c.int --- + GetPhysicalDevicePresentationSupport :: proc(instance: vk.Instance, device: vk.PhysicalDevice, queuefamily: u32) -> b32 --- CreateWindowSurface :: proc(instance: vk.Instance, window: WindowHandle, allocator: ^vk.AllocationCallbacks, surface: ^vk.SurfaceKHR) -> vk.Result --- SetWindowIconifyCallback :: proc(window: WindowHandle, cbfun: WindowIconifyProc) -> WindowIconifyProc --- @@ -193,7 +193,6 @@ foreign glfw { SetWindowPosCallback :: proc(window: WindowHandle, cbfun: WindowPosProc) -> WindowPosProc --- SetFramebufferSizeCallback :: proc(window: WindowHandle, cbfun: FramebufferSizeProc) -> FramebufferSizeProc --- SetDropCallback :: proc(window: WindowHandle, cbfun: DropProc) -> DropProc --- - SetMonitorCallback :: proc(window: WindowHandle, cbfun: MonitorProc) -> MonitorProc --- SetWindowMaximizeCallback :: proc(window: WindowHandle, cbfun: WindowMaximizeProc) -> WindowMaximizeProc --- SetWindowContentScaleCallback :: proc(window: WindowHandle, cbfun: WindowContentScaleProc) -> WindowContentScaleProc --- @@ -204,7 +203,9 @@ foreign glfw { SetCharCallback :: proc(window: WindowHandle, cbfun: CharProc) -> CharProc --- SetCharModsCallback :: proc(window: WindowHandle, cbfun: CharModsProc) -> CharModsProc --- SetCursorEnterCallback :: proc(window: WindowHandle, cbfun: CursorEnterProc) -> CursorEnterProc --- - SetJoystickCallback :: proc(cbfun: JoystickProc) -> JoystickProc --- + + SetMonitorCallback :: proc(cbfun: MonitorProc) -> MonitorProc --- + SetJoystickCallback :: proc(cbfun: JoystickProc) -> JoystickProc --- SetErrorCallback :: proc(cbfun: ErrorProc) -> ErrorProc --- diff --git a/vendor/glfw/bindings/types.odin b/vendor/glfw/bindings/types.odin index 5bdbf9cb9..bb1c7e431 100644 --- a/vendor/glfw/bindings/types.odin +++ b/vendor/glfw/bindings/types.odin @@ -48,7 +48,7 @@ WindowMaximizeProc :: #type proc "c" (window: WindowHandle, iconified: c.int WindowContentScaleProc :: #type proc "c" (window: WindowHandle, xscale, yscale: f32) FramebufferSizeProc :: #type proc "c" (window: WindowHandle, width, height: c.int) DropProc :: #type proc "c" (window: WindowHandle, count: c.int, paths: [^]cstring) -MonitorProc :: #type proc "c" (window: WindowHandle, event: c.int) +MonitorProc :: #type proc "c" (monitor: MonitorHandle, event: c.int) KeyProc :: #type proc "c" (window: WindowHandle, key, scancode, action, mods: c.int) MouseButtonProc :: #type proc "c" (window: WindowHandle, button, action, mods: c.int) diff --git a/vendor/kb_text_shape/kb_text_shape_procs.odin b/vendor/kb_text_shape/kb_text_shape_procs.odin new file mode 100644 index 000000000..efcdcc4ed --- /dev/null +++ b/vendor/kb_text_shape/kb_text_shape_procs.odin @@ -0,0 +1,184 @@ +package vendor_kb_text_shape + +when ODIN_OS == .Windows { + foreign import lib { + "lib/kb_text_shape.lib", + } +} else { + foreign import lib { + "lib/kb_text_shape.a", + } +} + +import "core:mem" + +@(default_calling_convention="c", link_prefix="kbts_", require_results) +foreign lib { + FeatureTagToId :: proc(Tag: feature_tag) -> feature_id --- + FeatureOverride :: proc(Id: feature_id, Alternate: b32, Value: u32) -> feature_override --- + FeatureOverrideFromTag :: proc(Tag: feature_tag, Alternate: b32, Value: u32) -> feature_override --- + GlyphConfigOverrideFeature :: proc(Config: ^glyph_config, Id: feature_id, Alternate: b32, Value: u32) -> b32 --- + GlyphConfigOverrideFeatureFromTag :: proc(Config: ^glyph_config, Tag: feature_tag, Alternate: b32, Value: u32) -> b32 --- + + FontIsValid :: proc(Font: ^font) -> b32 --- + SizeOfShapeState :: proc(Font: ^font) -> un --- + + ResetShapeState :: proc(State: ^shape_state) --- + + ShapeConfig :: proc(Font: ^font, Script: script, Language: language) -> shape_config --- + ShaperIsComplex :: proc(Shaper: shaper) -> b32 --- + ScriptTagToScript :: proc(Tag: script_tag) -> script --- + + Shape :: proc(State: ^shape_state, Config: ^shape_config, + MainDirection, RunDirection: direction, + Glyphs: [^]glyph, GlyphCount: ^u32, GlyphCapacity: u32) -> b32 --- + + Cursor :: proc(Direction: direction) -> cursor --- + BeginBreak :: proc(State: ^break_state, MainDirection: direction, JapaneseLineBreakStyle: japanese_line_break_style) --- + BreakStateIsValid :: proc(State: ^break_state) -> b32 --- + BreakAddCodepoint :: proc(State: ^break_state, Codepoint: rune, PositionIncrement: u32, EndOfText: b32) --- + BreakFlush :: proc(State: ^break_state) --- + Break :: proc(State: ^break_state, Break: ^break_type) -> b32 --- + CodepointToGlyph :: proc(Font: ^font, Codepoint: rune) -> glyph --- + InferScript :: proc(Direction: ^direction, Script: ^script, GlyphScript: script) --- +} + + +@(require_results) +GlyphConfig :: proc "c" (FeatureOverrides: []feature_override) -> glyph_config { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_GlyphConfig :: proc(FeatureOverrides: [^]feature_override, FeatureOverrideCount: u32) -> glyph_config --- + } + return kbts_GlyphConfig(raw_data(FeatureOverrides), u32(len(FeatureOverrides))) + +} + +@(require_results) +EmptyGlyphConfig :: proc(FeatureOverrides: []feature_override) -> glyph_config { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_EmptyGlyphConfig :: proc(FeatureOverrides: [^]feature_override, FeatureOverrideCapacity: u32) -> glyph_config --- + } + return kbts_EmptyGlyphConfig(raw_data(FeatureOverrides), u32(len(FeatureOverrides))) +} + +@(require_results) +PlaceShapeState :: proc "c" (Memory: []byte) -> ^shape_state { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_PlaceShapeState :: proc(Address: rawptr, Size: un) -> ^shape_state --- + } + + return kbts_PlaceShapeState(raw_data(Memory), un(len(Memory))) +} + +@(require_results) +DecodeUtf8 :: proc "contextless" (String: string) -> (Codepoint: rune, SourceCharactersConsumed: u32, Valid: bool) { + decode :: struct { + Codepoint: rune, + + SourceCharactersConsumed: u32, + Valid: b32, + } + + @(default_calling_convention="c", require_results) + foreign lib { + kbts_DecodeUtf8 :: proc(Utf8: [^]byte, Length: un) -> decode --- + } + + Decode := kbts_DecodeUtf8(raw_data(String), un(len(String))) + return Decode.Codepoint, Decode.SourceCharactersConsumed, bool(Decode.Valid) +} + + +@(require_results) +ReadFontHeader :: proc "c" (Font: ^font, Data: []byte) -> un { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ReadFontHeader :: proc(Font: ^font, Data: rawptr, Size: un) -> un --- + } + + return kbts_ReadFontHeader(Font, raw_data(Data), un(len(Data))) +} +@(require_results) +ReadFontData :: proc "c" (Font: ^font, Scratch: []byte) -> un { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_ReadFontData :: proc(Font: ^font, Scratch: rawptr, ScratchSize: un) -> un --- + } + + return kbts_ReadFontData(Font, raw_data(Scratch), un(len(Scratch))) +} +@(require_results) +PostReadFontInitialize :: proc "c" (Font: ^font, Memory: []byte) -> b32 { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_PostReadFontInitialize :: proc(Font: ^font, Memory: rawptr, MemorySize: un) -> b32 --- + } + + return kbts_PostReadFontInitialize(Font, raw_data(Memory), un(len(Memory))) +} + +@(require_results) +FontFromMemory :: proc(Data: []byte, allocator: mem.Allocator) -> (Result: font, Err: mem.Allocator_Error) { + ClonedData := mem.make_aligned([]byte, len(Data), 16, allocator) or_return + defer if Err != nil { + delete(ClonedData, allocator) + } + copy(ClonedData, Data) + + ScratchSize := ReadFontHeader(&Result, ClonedData) + Scratch := mem.make_aligned([]byte, ScratchSize, 16, allocator) or_return + MemorySize := ReadFontData(&Result, Scratch) + + Memory := Scratch + if MemorySize > ScratchSize { + delete(Scratch, allocator) + Memory = mem.make_aligned([]byte, MemorySize, 16, allocator) or_return + } + defer if Err != nil { + delete(Memory, allocator) + } + + _ = PostReadFontInitialize(&Result, Memory) + return + +} +FreeFont :: proc(Font: ^font, allocator: mem.Allocator) { + free(Font.FileBase, allocator) + free(Font.GlyphLookupMatrix, allocator) + Font^ = {} +} + +@(require_results) +CreateShapeState :: proc(Font: ^font, allocator: mem.Allocator) -> (Result: ^shape_state, Err: mem.Allocator_Error) { + Size := SizeOfShapeState(Font) + Memory := mem.make_aligned([]byte, Size, 16, allocator) or_return + Result = PlaceShapeState(Memory) + return +} +FreeShapeState :: proc(State: ^shape_state, allocator: mem.Allocator) { + free(State, allocator) +} + +@(require_results) +PositionGlyph :: proc(Cursor: ^cursor, Glyph: ^glyph) -> (X, Y: i32) { + @(default_calling_convention="c", require_results) + foreign lib { + kbts_PositionGlyph :: proc(Cursor: ^cursor, Glyph: ^glyph, X, Y: ^i32) --- + } + kbts_PositionGlyph(Cursor, Glyph, &X, &Y) + return +} + +@(require_results) +ShapeDynamic :: proc(State: ^shape_state, Config: ^shape_config, + MainDirection, RunDirection: direction, + Glyphs: ^[dynamic]glyph) -> b32 { + GlyphCount := u32(len(Glyphs^)) + GlyphCapacity := u32(cap(Glyphs^)) + Res := Shape(State, Config, MainDirection, RunDirection, raw_data(Glyphs^), &GlyphCount, GlyphCapacity) + resize(Glyphs, int(GlyphCount)) + return Res +} \ No newline at end of file diff --git a/vendor/kb_text_shape/kb_text_shape_types.odin b/vendor/kb_text_shape/kb_text_shape_types.odin new file mode 100644 index 000000000..929af64d2 --- /dev/null +++ b/vendor/kb_text_shape/kb_text_shape_types.odin @@ -0,0 +1,2098 @@ +package vendor_kb_text_shape + +import "core:c" + +#assert(size_of(b8) == size_of(bool)) +#assert(size_of(b32) == size_of(u32)) +#assert(size_of(b32) == size_of(c.int)) + +un :: distinct ( + uint when (size_of(uintptr) == size_of(uint)) else + u32 when size_of(uintptr) == 4 else + u64 +) +// sn :: distinct ( +// int when (size_of(uintptr) == size_of(int)) else +// i32 when size_of(uintptr) == 4 else +// i64 +// ) + +joining_feature :: enum u8 { + NONE, + ISOL, + FINA, + FIN2, + FIN3, + MEDI, + MED2, + INIT, +} + +reph_position :: enum u8 { + AFTER_POST, + BEFORE_POST, + BEFORE_SUBJOINED, + AFTER_SUBJOINED, + AFTER_MAIN, +} + +reph_encoding :: enum u8 { + IMPLICIT, + EXPLICIT, + LOGICAL_REPHA, + VISUAL_REPHA, +} + +syllabic_position :: enum u8 { + NONE, + + RA_TO_BECOME_REPH, + + PREBASE_MATRA, + PREBASE_CONSONANT, + + SYLLABLE_BASE, + AFTER_MAIN, + + ABOVEBASE_CONSONANT, + + BEFORE_SUBJOINED, + BELOWBASE_CONSONANT, + AFTER_SUBJOINED, + + BEFORE_POST, + POSTBASE_CONSONANT, + AFTER_POST, + + FINAL_CONSONANT, + SMVD, +} + +language :: enum u32 { + DONT_KNOW = 0, + + A_HMAO = ('H' | 'M'<<8 | 'D'<<16 | ' '<<24), + AARI = ('A' | 'R'<<8 | 'I'<<16 | ' '<<24), + ABAZA = ('A' | 'B'<<8 | 'A'<<16 | ' '<<24), + ABKHAZIAN = ('A' | 'B'<<8 | 'K'<<16 | ' '<<24), + ACHI = ('A' | 'C'<<8 | 'R'<<16 | ' '<<24), + ACHOLI = ('A' | 'C'<<8 | 'H'<<16 | ' '<<24), + ADYGHE = ('A' | 'D'<<8 | 'Y'<<16 | ' '<<24), + AFAR = ('A' | 'F'<<8 | 'R'<<16 | ' '<<24), + AFRIKAANS = ('A' | 'F'<<8 | 'K'<<16 | ' '<<24), + AGAW = ('A' | 'G'<<8 | 'W'<<16 | ' '<<24), + AITON = ('A' | 'I'<<8 | 'O'<<16 | ' '<<24), + AKAN = ('A' | 'K'<<8 | 'A'<<16 | ' '<<24), + ALBANIAN = ('S' | 'Q'<<8 | 'I'<<16 | ' '<<24), + ALSATIAN = ('A' | 'L'<<8 | 'S'<<16 | ' '<<24), + ALTAI = ('A' | 'L'<<8 | 'T'<<16 | ' '<<24), + ALUO = ('Y' | 'N'<<8 | 'A'<<16 | ' '<<24), + AMERICAN_PHONETIC = ('A' | 'P'<<8 | 'P'<<16 | 'H'<<24), + AMHARIC = ('A' | 'M'<<8 | 'H'<<16 | ' '<<24), + ANGLO_SAXON = ('A' | 'N'<<8 | 'G'<<16 | ' '<<24), + ARABIC = ('A' | 'R'<<8 | 'A'<<16 | ' '<<24), + ARAGONESE = ('A' | 'R'<<8 | 'G'<<16 | ' '<<24), + ARAKANESE = ('A' | 'R'<<8 | 'K'<<16 | ' '<<24), + ARAKWAL = ('R' | 'K'<<8 | 'W'<<16 | ' '<<24), + ARMENIAN = ('H' | 'Y'<<8 | 'E'<<16 | ' '<<24), + ARMENIAN_EAST = ('H' | 'Y'<<8 | 'E'<<16 | '0'<<24), + AROMANIAN = ('R' | 'U'<<8 | 'P'<<16 | ' '<<24), + ARPITAN = ('F' | 'R'<<8 | 'P'<<16 | ' '<<24), + ASSAMESE = ('A' | 'S'<<8 | 'M'<<16 | ' '<<24), + ASTURIAN = ('A' | 'S'<<8 | 'T'<<16 | ' '<<24), + ATHAPASKAN = ('A' | 'T'<<8 | 'H'<<16 | ' '<<24), + ATSINA = ('A' | 'T'<<8 | 'S'<<16 | ' '<<24), + AVAR = ('A' | 'V'<<8 | 'R'<<16 | ' '<<24), + AVATIME = ('A' | 'V'<<8 | 'N'<<16 | ' '<<24), + AWADHI = ('A' | 'W'<<8 | 'A'<<16 | ' '<<24), + AYMARA = ('A' | 'Y'<<8 | 'M'<<16 | ' '<<24), + AZERBAIDJANI = ('A' | 'Z'<<8 | 'E'<<16 | ' '<<24), + BADAGA = ('B' | 'A'<<8 | 'D'<<16 | ' '<<24), + BAGHELKHANDI = ('B' | 'A'<<8 | 'G'<<16 | ' '<<24), + BAGRI = ('B' | 'G'<<8 | 'Q'<<16 | ' '<<24), + BALANTE = ('B' | 'L'<<8 | 'N'<<16 | ' '<<24), + BALINESE = ('B' | 'A'<<8 | 'N'<<16 | ' '<<24), + BALKAR = ('B' | 'A'<<8 | 'L'<<16 | ' '<<24), + BALTI = ('B' | 'L'<<8 | 'T'<<16 | ' '<<24), + BALUCHI = ('B' | 'L'<<8 | 'I'<<16 | ' '<<24), + BAMBARA = ('B' | 'M'<<8 | 'B'<<16 | ' '<<24), + BAMILEKE = ('B' | 'M'<<8 | 'L'<<16 | ' '<<24), + BANDA = ('B' | 'A'<<8 | 'D'<<16 | '0'<<24), + BANDJALANG = ('B' | 'D'<<8 | 'Y'<<16 | ' '<<24), + BANGLA = ('B' | 'E'<<8 | 'N'<<16 | ' '<<24), + BASHKIR = ('B' | 'S'<<8 | 'H'<<16 | ' '<<24), + BASQUE = ('E' | 'U'<<8 | 'Q'<<16 | ' '<<24), + BATAK = ('B' | 'T'<<8 | 'K'<<16 | ' '<<24), + BATAK_ALAS_KLUET = ('B' | 'T'<<8 | 'Z'<<16 | ' '<<24), + BATAK_ANGKOLA = ('A' | 'K'<<8 | 'B'<<16 | ' '<<24), + BATAK_DAIRI = ('B' | 'T'<<8 | 'D'<<16 | ' '<<24), + BATAK_KARO = ('B' | 'T'<<8 | 'X'<<16 | ' '<<24), + BATAK_MANDAILING = ('B' | 'T'<<8 | 'M'<<16 | ' '<<24), + BATAK_SIMALUNGUN = ('B' | 'T'<<8 | 'S'<<16 | ' '<<24), + BATAK_TOBA = ('B' | 'B'<<8 | 'C'<<16 | ' '<<24), + BAULE = ('B' | 'A'<<8 | 'U'<<16 | ' '<<24), + BAVARIAN = ('B' | 'A'<<8 | 'R'<<16 | ' '<<24), + BELARUSIAN = ('B' | 'E'<<8 | 'L'<<16 | ' '<<24), + BEMBA = ('B' | 'E'<<8 | 'M'<<16 | ' '<<24), + BENCH = ('B' | 'C'<<8 | 'H'<<16 | ' '<<24), + BERBER = ('B' | 'B'<<8 | 'R'<<16 | ' '<<24), + BETI = ('B' | 'T'<<8 | 'I'<<16 | ' '<<24), + BETTE_KURUMA = ('X' | 'U'<<8 | 'B'<<16 | ' '<<24), + BHILI = ('B' | 'H'<<8 | 'I'<<16 | ' '<<24), + BHOJPURI = ('B' | 'H'<<8 | 'O'<<16 | ' '<<24), + BHUTANESE = ('D' | 'Z'<<8 | 'N'<<16 | ' '<<24), + BIBLE_CREE = ('B' | 'C'<<8 | 'R'<<16 | ' '<<24), + BIKOL = ('B' | 'I'<<8 | 'K'<<16 | ' '<<24), + BILEN = ('B' | 'I'<<8 | 'L'<<16 | ' '<<24), + BISHNUPRIYA_MANIPURI = ('B' | 'P'<<8 | 'Y'<<16 | ' '<<24), + BISLAMA = ('B' | 'I'<<8 | 'S'<<16 | ' '<<24), + BLACKFOOT = ('B' | 'K'<<8 | 'F'<<16 | ' '<<24), + BODO = ('B' | 'R'<<8 | 'X'<<16 | ' '<<24), + BOSNIAN = ('B' | 'O'<<8 | 'S'<<16 | ' '<<24), + BOUYEI = ('P' | 'C'<<8 | 'C'<<16 | ' '<<24), + BRAHUI = ('B' | 'R'<<8 | 'H'<<16 | ' '<<24), + BRAJ_BHASHA = ('B' | 'R'<<8 | 'I'<<16 | ' '<<24), + BRETON = ('B' | 'R'<<8 | 'E'<<16 | ' '<<24), + BUGIS = ('B' | 'U'<<8 | 'G'<<16 | ' '<<24), + BULGARIAN = ('B' | 'G'<<8 | 'R'<<16 | ' '<<24), + BUMTHANGKHA = ('K' | 'J'<<8 | 'Z'<<16 | ' '<<24), + BURMESE = ('B' | 'R'<<8 | 'M'<<16 | ' '<<24), + BURUSHASKI = ('B' | 'S'<<8 | 'K'<<16 | ' '<<24), + CAJUN_FRENCH = ('F' | 'R'<<8 | 'C'<<16 | ' '<<24), + CARRIER = ('C' | 'R'<<8 | 'R'<<16 | ' '<<24), + CATALAN = ('C' | 'A'<<8 | 'T'<<16 | ' '<<24), + CAYUGA = ('C' | 'A'<<8 | 'Y'<<16 | ' '<<24), + CEBUANO = ('C' | 'E'<<8 | 'B'<<16 | ' '<<24), + CENTRAL_YUPIK = ('E' | 'S'<<8 | 'U'<<16 | ' '<<24), + CHAHA_GURAGE = ('C' | 'H'<<8 | 'G'<<16 | ' '<<24), + CHAMORRO = ('C' | 'H'<<8 | 'A'<<16 | ' '<<24), + CHATTISGARHI = ('C' | 'H'<<8 | 'H'<<16 | ' '<<24), + CHECHEN = ('C' | 'H'<<8 | 'E'<<16 | ' '<<24), + CHEROKEE = ('C' | 'H'<<8 | 'R'<<16 | ' '<<24), + CHEYENNE = ('C' | 'H'<<8 | 'Y'<<16 | ' '<<24), + CHICHEWA = ('C' | 'H'<<8 | 'I'<<16 | ' '<<24), + CHIGA = ('C' | 'G'<<8 | 'G'<<16 | ' '<<24), + CHIMILA = ('C' | 'B'<<8 | 'G'<<16 | ' '<<24), + CHIN = ('Q' | 'I'<<8 | 'N'<<16 | ' '<<24), + CHINANTEC = ('C' | 'C'<<8 | 'H'<<16 | 'N'<<24), + CHINESE_PHONETIC = ('Z' | 'H'<<8 | 'P'<<16 | ' '<<24), + CHINESE_SIMPLIFIED = ('Z' | 'H'<<8 | 'S'<<16 | ' '<<24), + CHINESE_TRADITIONAL = ('Z' | 'H'<<8 | 'T'<<16 | ' '<<24), + CHINESE_TRADITIONAL_HONG_KONG = ('Z' | 'H'<<8 | 'H'<<16 | ' '<<24), + CHINESE_TRADITIONAL_MACAO = ('Z' | 'H'<<8 | 'T'<<16 | 'M'<<24), + CHIPEWYAN = ('C' | 'H'<<8 | 'P'<<16 | ' '<<24), + CHITTAGONIAN = ('C' | 'T'<<8 | 'G'<<16 | ' '<<24), + CHOCTAW = ('C' | 'H'<<8 | 'O'<<16 | ' '<<24), + CHUKCHI = ('C' | 'H'<<8 | 'K'<<16 | ' '<<24), + CHURCH_SLAVONIC = ('C' | 'S'<<8 | 'L'<<16 | ' '<<24), + CHUUKESE = ('C' | 'H'<<8 | 'K'<<16 | '0'<<24), + CHUVASH = ('C' | 'H'<<8 | 'U'<<16 | ' '<<24), + COMORIAN = ('C' | 'M'<<8 | 'R'<<16 | ' '<<24), + COMOX = ('C' | 'O'<<8 | 'O'<<16 | ' '<<24), + COPTIC = ('C' | 'O'<<8 | 'P'<<16 | ' '<<24), + CORNISH = ('C' | 'O'<<8 | 'R'<<16 | ' '<<24), + CORSICAN = ('C' | 'O'<<8 | 'S'<<16 | ' '<<24), + CREE = ('C' | 'R'<<8 | 'E'<<16 | ' '<<24), + CREOLES = ('C' | 'P'<<8 | 'P'<<16 | ' '<<24), + CRIMEAN_TATAR = ('C' | 'R'<<8 | 'T'<<16 | ' '<<24), + CRIOULO = ('K' | 'E'<<8 | 'A'<<16 | ' '<<24), + CROATIAN = ('H' | 'R'<<8 | 'V'<<16 | ' '<<24), + CYPRIOT_ARABIC = ('A' | 'C'<<8 | 'Y'<<16 | ' '<<24), + CZECH = ('C' | 'S'<<8 | 'Y'<<16 | ' '<<24), + DAGBANI = ('D' | 'A'<<8 | 'G'<<16 | ' '<<24), + DAN = ('D' | 'N'<<8 | 'J'<<16 | ' '<<24), + DANGME = ('D' | 'N'<<8 | 'G'<<16 | ' '<<24), + DANISH = ('D' | 'A'<<8 | 'N'<<16 | ' '<<24), + DARGWA = ('D' | 'A'<<8 | 'R'<<16 | ' '<<24), + DARI = ('D' | 'R'<<8 | 'I'<<16 | ' '<<24), + DAYI = ('D' | 'A'<<8 | 'X'<<16 | ' '<<24), + DEFAULT = ('d' | 'f'<<8 | 'l'<<16 | 't'<<24), // Can be DFLT too... + DEHONG_DAI = ('T' | 'D'<<8 | 'D'<<16 | ' '<<24), + DHANGU = ('D' | 'H'<<8 | 'G'<<16 | ' '<<24), + DHIVEHI = ('D' | 'I'<<8 | 'V'<<16 | ' '<<24), + DHUWAL = ('D' | 'U'<<8 | 'J'<<16 | ' '<<24), + DIMLI = ('D' | 'I'<<8 | 'Q'<<16 | ' '<<24), + DINKA = ('D' | 'N'<<8 | 'K'<<16 | ' '<<24), + DIVEHI = ('D' | 'I'<<8 | 'V'<<16 | ' '<<24), + DJAMBARRPUYNGU = ('D' | 'J'<<8 | 'R'<<16 | '0'<<24), + DOGRI = ('D' | 'G'<<8 | 'O'<<16 | ' '<<24), + DOGRI_MACROLANGUAGE = ('D' | 'G'<<8 | 'R'<<16 | ' '<<24), + DUNGAN = ('D' | 'U'<<8 | 'N'<<16 | ' '<<24), + DUTCH = ('N' | 'L'<<8 | 'D'<<16 | ' '<<24), + DZONGKHA = ('D' | 'Z'<<8 | 'N'<<16 | ' '<<24), + EASTERN_ABENAKI = ('A' | 'A'<<8 | 'Q'<<16 | ' '<<24), + EASTERN_CHAM = ('C' | 'J'<<8 | 'M'<<16 | ' '<<24), + EASTERN_CREE = ('E' | 'C'<<8 | 'R'<<16 | ' '<<24), + EASTERN_MANINKAKAN = ('E' | 'M'<<8 | 'K'<<16 | ' '<<24), + EASTERN_PWO_KAREN = ('K' | 'J'<<8 | 'P'<<16 | ' '<<24), + EBIRA = ('E' | 'B'<<8 | 'I'<<16 | ' '<<24), + EDO = ('E' | 'D'<<8 | 'O'<<16 | ' '<<24), + EFIK = ('E' | 'F'<<8 | 'I'<<16 | ' '<<24), + EMBERA_BAUDO = ('B' | 'D'<<8 | 'C'<<16 | ' '<<24), + EMBERA_CATIO = ('C' | 'T'<<8 | 'O'<<16 | ' '<<24), + EMBERA_CHAMI = ('C' | 'M'<<8 | 'I'<<16 | ' '<<24), + EMBERA_TADO = ('T' | 'D'<<8 | 'C'<<16 | ' '<<24), + ENGLISH = ('E' | 'N'<<8 | 'G'<<16 | ' '<<24), + EPENA = ('S' | 'J'<<8 | 'A'<<16 | ' '<<24), + ERZYA = ('E' | 'R'<<8 | 'Z'<<16 | ' '<<24), + KB_TEXT_SHAPEANTO = ('N' | 'T'<<8 | 'O'<<16 | ' '<<24), + ESTONIAN = ('E' | 'T'<<8 | 'I'<<16 | ' '<<24), + EVEN = ('E' | 'V'<<8 | 'N'<<16 | ' '<<24), + EVENKI = ('E' | 'V'<<8 | 'K'<<16 | ' '<<24), + EWE = ('E' | 'W'<<8 | 'E'<<16 | ' '<<24), + FALAM_CHIN = ('H' | 'A'<<8 | 'L'<<16 | ' '<<24), + FANG = ('F' | 'A'<<8 | 'N'<<16 | '0'<<24), + FANTI = ('F' | 'A'<<8 | 'T'<<16 | ' '<<24), + FAROESE = ('F' | 'O'<<8 | 'S'<<16 | ' '<<24), + FEFE = ('F' | 'M'<<8 | 'P'<<16 | ' '<<24), + FIJIAN = ('F' | 'J'<<8 | 'I'<<16 | ' '<<24), + FILIPINO = ('P' | 'I'<<8 | 'L'<<16 | ' '<<24), + FINNISH = ('F' | 'I'<<8 | 'N'<<16 | ' '<<24), + FLEMISH = ('F' | 'L'<<8 | 'E'<<16 | ' '<<24), + FON = ('F' | 'O'<<8 | 'N'<<16 | ' '<<24), + FOREST_ENETS = ('F' | 'N'<<8 | 'E'<<16 | ' '<<24), + FRENCH = ('F' | 'R'<<8 | 'A'<<16 | ' '<<24), + FRENCH_ANTILLEAN = ('F' | 'A'<<8 | 'N'<<16 | ' '<<24), + FRISIAN = ('F' | 'R'<<8 | 'I'<<16 | ' '<<24), + FRIULIAN = ('F' | 'R'<<8 | 'L'<<16 | ' '<<24), + FULAH = ('F' | 'U'<<8 | 'L'<<16 | ' '<<24), + FUTA = ('F' | 'T'<<8 | 'A'<<16 | ' '<<24), + GA = ('G' | 'A'<<8 | 'D'<<16 | ' '<<24), + GAGAUZ = ('G' | 'A'<<8 | 'G'<<16 | ' '<<24), + GALICIAN = ('G' | 'A'<<8 | 'L'<<16 | ' '<<24), + GANDA = ('L' | 'U'<<8 | 'G'<<16 | ' '<<24), + GARHWALI = ('G' | 'A'<<8 | 'W'<<16 | ' '<<24), + GARO = ('G' | 'R'<<8 | 'O'<<16 | ' '<<24), + GARSHUNI = ('G' | 'A'<<8 | 'R'<<16 | ' '<<24), + GEBA_KAREN = ('K' | 'V'<<8 | 'Q'<<16 | ' '<<24), + GEEZ = ('G' | 'E'<<8 | 'Z'<<16 | ' '<<24), + GEORGIAN = ('K' | 'A'<<8 | 'T'<<16 | ' '<<24), + GEPO = ('Y' | 'G'<<8 | 'P'<<16 | ' '<<24), + GERMAN = ('D' | 'E'<<8 | 'U'<<16 | ' '<<24), + GIKUYU = ('K' | 'I'<<8 | 'K'<<16 | ' '<<24), + GILAKI = ('G' | 'L'<<8 | 'K'<<16 | ' '<<24), + GILBERTESE = ('G' | 'I'<<8 | 'L'<<16 | '0'<<24), + GILYAK = ('G' | 'I'<<8 | 'L'<<16 | ' '<<24), + GITHABUL = ('G' | 'I'<<8 | 'H'<<16 | ' '<<24), + GOGO = ('G' | 'O'<<8 | 'G'<<16 | ' '<<24), + GONDI = ('G' | 'O'<<8 | 'N'<<16 | ' '<<24), + GREEK = ('E' | 'L'<<8 | 'L'<<16 | ' '<<24), + GREENLANDIC = ('G' | 'R'<<8 | 'N'<<16 | ' '<<24), + GUARANI = ('G' | 'U'<<8 | 'A'<<16 | ' '<<24), + GUINEA = ('G' | 'K'<<8 | 'P'<<16 | ' '<<24), + GUJARATI = ('G' | 'U'<<8 | 'J'<<16 | ' '<<24), + GUMATJ = ('G' | 'N'<<8 | 'N'<<16 | ' '<<24), + GUMUZ = ('G' | 'M'<<8 | 'Z'<<16 | ' '<<24), + GUPAPUYNGU = ('G' | 'U'<<8 | 'F'<<16 | ' '<<24), + GUSII = ('G' | 'U'<<8 | 'Z'<<16 | ' '<<24), + HAIDA = ('H' | 'A'<<8 | 'I'<<16 | '0'<<24), + HAITIAN_CREOLE = ('H' | 'A'<<8 | 'I'<<16 | ' '<<24), + HALKOMELEM = ('H' | 'U'<<8 | 'R'<<16 | ' '<<24), + HAMMER_BANNA = ('H' | 'B'<<8 | 'N'<<16 | ' '<<24), + HARARI = ('H' | 'R'<<8 | 'I'<<16 | ' '<<24), + HARAUTI = ('H' | 'A'<<8 | 'R'<<16 | ' '<<24), + HARYANVI = ('B' | 'G'<<8 | 'C'<<16 | ' '<<24), + HAUSA = ('H' | 'A'<<8 | 'U'<<16 | ' '<<24), + HAVASUPAI_WALAPAI_YAVAPAI = ('Y' | 'U'<<8 | 'F'<<16 | ' '<<24), + HAWAIIAN = ('H' | 'A'<<8 | 'W'<<16 | ' '<<24), + HAYA = ('H' | 'A'<<8 | 'Y'<<16 | ' '<<24), + HAZARAGI = ('H' | 'A'<<8 | 'Z'<<16 | ' '<<24), + HEBREW = ('I' | 'W'<<8 | 'R'<<16 | ' '<<24), + HEILTSUK = ('H' | 'E'<<8 | 'I'<<16 | ' '<<24), + HERERO = ('H' | 'E'<<8 | 'R'<<16 | ' '<<24), + HIGH_MARI = ('H' | 'M'<<8 | 'A'<<16 | ' '<<24), + HILIGAYNON = ('H' | 'I'<<8 | 'L'<<16 | ' '<<24), + HINDI = ('H' | 'I'<<8 | 'N'<<16 | ' '<<24), + HINDKO = ('H' | 'N'<<8 | 'D'<<16 | ' '<<24), + HIRI_MOTU = ('H' | 'M'<<8 | 'O'<<16 | ' '<<24), + HMONG = ('H' | 'M'<<8 | 'N'<<16 | ' '<<24), + HMONG_DAW = ('M' | 'W'<<8 | 'W'<<16 | ' '<<24), + HMONG_SHUAT = ('H' | 'M'<<8 | 'Z'<<16 | ' '<<24), + HO = ('H' | 'O'<<8 | ' '<<16 | ' '<<24), + HUNGARIAN = ('H' | 'U'<<8 | 'N'<<16 | ' '<<24), + IBAN = ('I' | 'B'<<8 | 'A'<<16 | ' '<<24), + IBIBIO = ('I' | 'B'<<8 | 'B'<<16 | ' '<<24), + ICELANDIC = ('I' | 'S'<<8 | 'L'<<16 | ' '<<24), + IDO = ('I' | 'D'<<8 | 'O'<<16 | ' '<<24), + IGBO = ('I' | 'B'<<8 | 'O'<<16 | ' '<<24), + IJO = ('I' | 'J'<<8 | 'O'<<16 | ' '<<24), + ILOKANO = ('I' | 'L'<<8 | 'O'<<16 | ' '<<24), + INARI_SAMI = ('I' | 'S'<<8 | 'M'<<16 | ' '<<24), + INDONESIAN = ('I' | 'N'<<8 | 'D'<<16 | ' '<<24), + INGUSH = ('I' | 'N'<<8 | 'G'<<16 | ' '<<24), + INTERLINGUA = ('I' | 'N'<<8 | 'A'<<16 | ' '<<24), + INTERLINGUE = ('I' | 'L'<<8 | 'E'<<16 | ' '<<24), + INUKTITUT = ('I' | 'N'<<8 | 'U'<<16 | ' '<<24), + INUPIAT = ('I' | 'P'<<8 | 'K'<<16 | ' '<<24), + IPA_PHONETIC = ('I' | 'P'<<8 | 'P'<<16 | ' '<<24), + IRISH = ('I' | 'R'<<8 | 'I'<<16 | ' '<<24), + IRISH_TRADITIONAL = ('I' | 'R'<<8 | 'T'<<16 | ' '<<24), + IRULA = ('I' | 'R'<<8 | 'U'<<16 | ' '<<24), + ITALIAN = ('I' | 'T'<<8 | 'A'<<16 | ' '<<24), + JAMAICAN_CREOLE = ('J' | 'A'<<8 | 'M'<<16 | ' '<<24), + JAPANESE = ('J' | 'A'<<8 | 'N'<<16 | ' '<<24), + JAVANESE = ('J' | 'A'<<8 | 'V'<<16 | ' '<<24), + JENNU_KURUMA = ('X' | 'U'<<8 | 'J'<<16 | ' '<<24), + JUDEO_TAT = ('J' | 'D'<<8 | 'T'<<16 | ' '<<24), + JULA = ('J' | 'U'<<8 | 'L'<<16 | ' '<<24), + KABARDIAN = ('K' | 'A'<<8 | 'B'<<16 | ' '<<24), + KABYLE = ('K' | 'A'<<8 | 'B'<<16 | '0'<<24), + KACHCHI = ('K' | 'A'<<8 | 'C'<<16 | ' '<<24), + KADIWEU = ('K' | 'B'<<8 | 'C'<<16 | ' '<<24), + KALENJIN = ('K' | 'A'<<8 | 'L'<<16 | ' '<<24), + KALMYK = ('K' | 'L'<<8 | 'M'<<16 | ' '<<24), + KAMBA = ('K' | 'M'<<8 | 'B'<<16 | ' '<<24), + KANAUJI = ('B' | 'J'<<8 | 'J'<<16 | ' '<<24), + KANNADA = ('K' | 'A'<<8 | 'N'<<16 | ' '<<24), + KANURI = ('K' | 'N'<<8 | 'R'<<16 | ' '<<24), + KAQCHIKEL = ('C' | 'A'<<8 | 'K'<<16 | ' '<<24), + KARACHAY = ('K' | 'A'<<8 | 'R'<<16 | ' '<<24), + KARAIM = ('K' | 'R'<<8 | 'M'<<16 | ' '<<24), + KARAKALPAK = ('K' | 'R'<<8 | 'K'<<16 | ' '<<24), + KARELIAN = ('K' | 'R'<<8 | 'L'<<16 | ' '<<24), + KAREN = ('K' | 'R'<<8 | 'N'<<16 | ' '<<24), + KASHMIRI = ('K' | 'S'<<8 | 'H'<<16 | ' '<<24), + KASHUBIAN = ('C' | 'S'<<8 | 'B'<<16 | ' '<<24), + KATE = ('K' | 'M'<<8 | 'G'<<16 | ' '<<24), + KAZAKH = ('K' | 'A'<<8 | 'Z'<<16 | ' '<<24), + KEBENA = ('K' | 'E'<<8 | 'B'<<16 | ' '<<24), + KEKCHI = ('K' | 'E'<<8 | 'K'<<16 | ' '<<24), + KHAKASS = ('K' | 'H'<<8 | 'A'<<16 | ' '<<24), + KHAMTI_SHAN = ('K' | 'H'<<8 | 'T'<<16 | ' '<<24), + KHAMYANG = ('K' | 'S'<<8 | 'U'<<16 | ' '<<24), + KHANTY_KAZIM = ('K' | 'H'<<8 | 'K'<<16 | ' '<<24), + KHANTY_SHURISHKAR = ('K' | 'H'<<8 | 'S'<<16 | ' '<<24), + KHANTY_VAKHI = ('K' | 'H'<<8 | 'V'<<16 | ' '<<24), + KHASI = ('K' | 'S'<<8 | 'I'<<16 | ' '<<24), + KHENGKHA = ('X' | 'K'<<8 | 'F'<<16 | ' '<<24), + KHINALUG = ('K' | 'J'<<8 | 'J'<<16 | ' '<<24), + KHMER = ('K' | 'H'<<8 | 'M'<<16 | ' '<<24), + KHORASANI_TURKIC = ('K' | 'M'<<8 | 'Z'<<16 | ' '<<24), + KHOWAR = ('K' | 'H'<<8 | 'W'<<16 | ' '<<24), + KHUTSURI_GEORGIAN = ('K' | 'G'<<8 | 'E'<<16 | ' '<<24), + KICHE = ('Q' | 'U'<<8 | 'C'<<16 | ' '<<24), + KIKONGO = ('K' | 'O'<<8 | 'N'<<16 | ' '<<24), + KILDIN_SAMI = ('K' | 'S'<<8 | 'M'<<16 | ' '<<24), + KINYARWANDA = ('R' | 'U'<<8 | 'A'<<16 | ' '<<24), + KIRMANJKI = ('K' | 'I'<<8 | 'U'<<16 | ' '<<24), + KISII = ('K' | 'I'<<8 | 'S'<<16 | ' '<<24), + KITUBA = ('M' | 'K'<<8 | 'W'<<16 | ' '<<24), + KODAGU = ('K' | 'O'<<8 | 'D'<<16 | ' '<<24), + KOKNI = ('K' | 'K'<<8 | 'N'<<16 | ' '<<24), + KOMI = ('K' | 'O'<<8 | 'M'<<16 | ' '<<24), + KOMI_PERMYAK = ('K' | 'O'<<8 | 'P'<<16 | ' '<<24), + KOMI_ZYRIAN = ('K' | 'O'<<8 | 'Z'<<16 | ' '<<24), + KOMO = ('K' | 'M'<<8 | 'O'<<16 | ' '<<24), + KOMSO = ('K' | 'M'<<8 | 'S'<<16 | ' '<<24), + KONGO = ('K' | 'O'<<8 | 'N'<<16 | '0'<<24), + KONKANI = ('K' | 'O'<<8 | 'K'<<16 | ' '<<24), + KOORETE = ('K' | 'R'<<8 | 'T'<<16 | ' '<<24), + KOREAN = ('K' | 'O'<<8 | 'R'<<16 | ' '<<24), + KOREAO_OLD_HANGUL = ('K' | 'O'<<8 | 'H'<<16 | ' '<<24), + KORYAK = ('K' | 'Y'<<8 | 'K'<<16 | ' '<<24), + KOSRAEAN = ('K' | 'O'<<8 | 'S'<<16 | ' '<<24), + KPELLE = ('K' | 'P'<<8 | 'L'<<16 | ' '<<24), + KPELLE_LIBERIA = ('X' | 'P'<<8 | 'E'<<16 | ' '<<24), + KRIO = ('K' | 'R'<<8 | 'I'<<16 | ' '<<24), + KRYMCHAK = ('J' | 'C'<<8 | 'T'<<16 | ' '<<24), + KUANYAMA = ('K' | 'U'<<8 | 'A'<<16 | ' '<<24), + KUBE = ('K' | 'G'<<8 | 'F'<<16 | ' '<<24), + KUI = ('K' | 'U'<<8 | 'I'<<16 | ' '<<24), + KULVI = ('K' | 'U'<<8 | 'K'<<16 | ' '<<24), + KUMAONI = ('K' | 'M'<<8 | 'N'<<16 | ' '<<24), + KUMYK = ('K' | 'U'<<8 | 'M'<<16 | ' '<<24), + KURDISH = ('K' | 'U'<<8 | 'R'<<16 | ' '<<24), + KURUKH = ('K' | 'U'<<8 | 'U'<<16 | ' '<<24), + KUY = ('K' | 'U'<<8 | 'Y'<<16 | ' '<<24), + KWAKWALA = ('K' | 'W'<<8 | 'K'<<16 | ' '<<24), + KYRGYZ = ('K' | 'I'<<8 | 'R'<<16 | ' '<<24), + L_CREE = ('L' | 'C'<<8 | 'R'<<16 | ' '<<24), + LADAKHI = ('L' | 'D'<<8 | 'K'<<16 | ' '<<24), + LADIN = ('L' | 'A'<<8 | 'D'<<16 | ' '<<24), + LADINO = ('J' | 'U'<<8 | 'D'<<16 | ' '<<24), + LAHULI = ('L' | 'A'<<8 | 'H'<<16 | ' '<<24), + LAK = ('L' | 'A'<<8 | 'K'<<16 | ' '<<24), + LAKI = ('L' | 'K'<<8 | 'I'<<16 | ' '<<24), + LAMBANI = ('L' | 'A'<<8 | 'M'<<16 | ' '<<24), + LAMPUNG = ('L' | 'J'<<8 | 'P'<<16 | ' '<<24), + LAO = ('L' | 'A'<<8 | 'O'<<16 | ' '<<24), + LATIN = ('L' | 'A'<<8 | 'T'<<16 | ' '<<24), + LATVIAN = ('L' | 'V'<<8 | 'I'<<16 | ' '<<24), + LAZ = ('L' | 'A'<<8 | 'Z'<<16 | ' '<<24), + LELEMI = ('L' | 'E'<<8 | 'F'<<16 | ' '<<24), + LEZGI = ('L' | 'E'<<8 | 'Z'<<16 | ' '<<24), + LIGURIAN = ('L' | 'I'<<8 | 'J'<<16 | ' '<<24), + LIMBU = ('L' | 'M'<<8 | 'B'<<16 | ' '<<24), + LIMBURGISH = ('L' | 'I'<<8 | 'M'<<16 | ' '<<24), + LINGALA = ('L' | 'I'<<8 | 'N'<<16 | ' '<<24), + LIPO = ('L' | 'P'<<8 | 'O'<<16 | ' '<<24), + LISU = ('L' | 'I'<<8 | 'S'<<16 | ' '<<24), + LITHUANIAN = ('L' | 'T'<<8 | 'H'<<16 | ' '<<24), + LIV = ('L' | 'I'<<8 | 'V'<<16 | ' '<<24), + LOJBAN = ('J' | 'B'<<8 | 'O'<<16 | ' '<<24), + LOMA = ('L' | 'O'<<8 | 'M'<<16 | ' '<<24), + LOMBARD = ('L' | 'M'<<8 | 'O'<<16 | ' '<<24), + LOMWE = ('L' | 'M'<<8 | 'W'<<16 | ' '<<24), + LOW_MARI = ('L' | 'M'<<8 | 'A'<<16 | ' '<<24), + LOW_SAXON = ('N' | 'D'<<8 | 'S'<<16 | ' '<<24), + LOWER_SORBIAN = ('L' | 'S'<<8 | 'B'<<16 | ' '<<24), + LU = ('X' | 'B'<<8 | 'D'<<16 | ' '<<24), + LUBA_KATANGA = ('L' | 'U'<<8 | 'B'<<16 | ' '<<24), + LUBA_LULUA = ('L' | 'U'<<8 | 'A'<<16 | ' '<<24), + LULE_SAMI = ('L' | 'S'<<8 | 'M'<<16 | ' '<<24), + LUO = ('L' | 'U'<<8 | 'O'<<16 | ' '<<24), + LURI = ('L' | 'R'<<8 | 'C'<<16 | ' '<<24), + LUSHOOTSEED = ('L' | 'U'<<8 | 'T'<<16 | ' '<<24), + LUXEMBOURGISH = ('L' | 'T'<<8 | 'Z'<<16 | ' '<<24), + LUYIA = ('L' | 'U'<<8 | 'H'<<16 | ' '<<24), + MACEDONIAN = ('M' | 'K'<<8 | 'D'<<16 | ' '<<24), + MADURA = ('M' | 'A'<<8 | 'D'<<16 | ' '<<24), + MAGAHI = ('M' | 'A'<<8 | 'G'<<16 | ' '<<24), + MAITHILI = ('M' | 'T'<<8 | 'H'<<16 | ' '<<24), + MAJANG = ('M' | 'A'<<8 | 'J'<<16 | ' '<<24), + MAKASAR = ('M' | 'K'<<8 | 'R'<<16 | ' '<<24), + MAKHUWA = ('M' | 'A'<<8 | 'K'<<16 | ' '<<24), + MAKONDE = ('K' | 'D'<<8 | 'E'<<16 | ' '<<24), + MALAGASY = ('M' | 'L'<<8 | 'G'<<16 | ' '<<24), + MALAY = ('M' | 'L'<<8 | 'Y'<<16 | ' '<<24), + MALAYALAM = ('M' | 'A'<<8 | 'L'<<16 | ' '<<24), + MALAYALAM_REFORMED = ('M' | 'L'<<8 | 'R'<<16 | ' '<<24), + MALE = ('M' | 'L'<<8 | 'E'<<16 | ' '<<24), + MALINKE = ('M' | 'L'<<8 | 'N'<<16 | ' '<<24), + MALTESE = ('M' | 'T'<<8 | 'S'<<16 | ' '<<24), + MAM = ('M' | 'A'<<8 | 'M'<<16 | ' '<<24), + MANCHU = ('M' | 'C'<<8 | 'H'<<16 | ' '<<24), + MANDAR = ('M' | 'D'<<8 | 'R'<<16 | ' '<<24), + MANDINKA = ('M' | 'N'<<8 | 'D'<<16 | ' '<<24), + MANINKA = ('M' | 'N'<<8 | 'K'<<16 | ' '<<24), + MANIPURI = ('M' | 'N'<<8 | 'I'<<16 | ' '<<24), + MANO = ('M' | 'E'<<8 | 'V'<<16 | ' '<<24), + MANSI = ('M' | 'A'<<8 | 'N'<<16 | ' '<<24), + MANX = ('M' | 'N'<<8 | 'X'<<16 | ' '<<24), + MAORI = ('M' | 'R'<<8 | 'I'<<16 | ' '<<24), + MAPUDUNGUN = ('M' | 'A'<<8 | 'P'<<16 | ' '<<24), + MARATHI = ('M' | 'A'<<8 | 'R'<<16 | ' '<<24), + MARSHALLESE = ('M' | 'A'<<8 | 'H'<<16 | ' '<<24), + MARWARI = ('M' | 'A'<<8 | 'W'<<16 | ' '<<24), + MAYAN = ('M' | 'Y'<<8 | 'N'<<16 | ' '<<24), + MAZANDERANI = ('M' | 'Z'<<8 | 'N'<<16 | ' '<<24), + MBEMBE_TIGON = ('N' | 'Z'<<8 | 'A'<<16 | ' '<<24), + MBO = ('M' | 'B'<<8 | 'O'<<16 | ' '<<24), + MBUNDU = ('M' | 'B'<<8 | 'N'<<16 | ' '<<24), + MEDUMBA = ('B' | 'Y'<<8 | 'V'<<16 | ' '<<24), + MEEN = ('M' | 'E'<<8 | 'N'<<16 | ' '<<24), + MENDE = ('M' | 'D'<<8 | 'E'<<16 | ' '<<24), + MERU = ('M' | 'E'<<8 | 'R'<<16 | ' '<<24), + MEWATI = ('W' | 'T'<<8 | 'M'<<16 | ' '<<24), + MINANGKABAU = ('M' | 'I'<<8 | 'N'<<16 | ' '<<24), + MINJANGBAL = ('X' | 'J'<<8 | 'B'<<16 | ' '<<24), + MIRANDESE = ('M' | 'W'<<8 | 'L'<<16 | ' '<<24), + MIZO = ('M' | 'I'<<8 | 'Z'<<16 | ' '<<24), + MOHAWK = ('M' | 'O'<<8 | 'H'<<16 | ' '<<24), + MOKSHA = ('M' | 'O'<<8 | 'K'<<16 | ' '<<24), + MOLDAVIAN = ('M' | 'O'<<8 | 'L'<<16 | ' '<<24), + MON = ('M' | 'O'<<8 | 'N'<<16 | ' '<<24), + MONGOLIAN = ('M' | 'N'<<8 | 'G'<<16 | ' '<<24), + MOOSE_CREE = ('M' | 'C'<<8 | 'R'<<16 | ' '<<24), + MORISYEN = ('M' | 'F'<<8 | 'E'<<16 | ' '<<24), + MOROCCAN = ('M' | 'O'<<8 | 'R'<<16 | ' '<<24), + MOSSI = ('M' | 'P'<<8 | 'S'<<16 | ' '<<24), + MUNDARI = ('M' | 'U'<<8 | 'N'<<16 | ' '<<24), + MUSCOGEE = ('M' | 'U'<<8 | 'S'<<16 | ' '<<24), + N_CREE = ('N' | 'C'<<8 | 'R'<<16 | ' '<<24), + NAGA_ASSAMESE = ('N' | 'A'<<8 | 'G'<<16 | ' '<<24), + NAGARI = ('N' | 'G'<<8 | 'R'<<16 | ' '<<24), + NAHUATL = ('N' | 'A'<<8 | 'H'<<16 | ' '<<24), + NANAI = ('N' | 'A'<<8 | 'N'<<16 | ' '<<24), + NASKAPI = ('N' | 'A'<<8 | 'S'<<16 | ' '<<24), + NAURUAN = ('N' | 'A'<<8 | 'U'<<16 | ' '<<24), + NAVAJO = ('N' | 'A'<<8 | 'V'<<16 | ' '<<24), + NDAU = ('N' | 'D'<<8 | 'C'<<16 | ' '<<24), + NDEBELE = ('N' | 'D'<<8 | 'B'<<16 | ' '<<24), + NDONGA = ('N' | 'D'<<8 | 'G'<<16 | ' '<<24), + NEAPOLITAN = ('N' | 'A'<<8 | 'P'<<16 | ' '<<24), + NEPALI = ('N' | 'E'<<8 | 'P'<<16 | ' '<<24), + NEWARI = ('N' | 'E'<<8 | 'W'<<16 | ' '<<24), + NGBAKA = ('N' | 'G'<<8 | 'A'<<16 | ' '<<24), + NIGERIAN_FULFULDE = ('F' | 'U'<<8 | 'V'<<16 | ' '<<24), + NIMADI = ('N' | 'O'<<8 | 'E'<<16 | ' '<<24), + NISI = ('N' | 'I'<<8 | 'S'<<16 | ' '<<24), + NIUEAN = ('N' | 'I'<<8 | 'U'<<16 | ' '<<24), + NKO = ('N' | 'K'<<8 | 'O'<<16 | ' '<<24), + NOGAI = ('N' | 'O'<<8 | 'G'<<16 | ' '<<24), + NORFOLK = ('P' | 'I'<<8 | 'H'<<16 | ' '<<24), + NORTH_SLAVEY = ('S' | 'C'<<8 | 'S'<<16 | ' '<<24), + NORTHERN_EMBERA = ('E' | 'M'<<8 | 'P'<<16 | ' '<<24), + NORTHERN_SAMI = ('N' | 'S'<<8 | 'M'<<16 | ' '<<24), + NORTHERN_SOTHO = ('N' | 'S'<<8 | 'O'<<16 | ' '<<24), + NORTHERN_TAI = ('N' | 'T'<<8 | 'A'<<16 | ' '<<24), + NORWAY_HOUSE_CREE = ('N' | 'H'<<8 | 'C'<<16 | ' '<<24), + NORWEGIAN = ('N' | 'O'<<8 | 'R'<<16 | ' '<<24), + NORWEGIAN_NYNORSK = ('N' | 'Y'<<8 | 'N'<<16 | ' '<<24), + NOVIAL = ('N' | 'O'<<8 | 'V'<<16 | ' '<<24), + NUMANGGANG = ('N' | 'O'<<8 | 'P'<<16 | ' '<<24), + NUNAVIK_INUKTITUT = ('I' | 'N'<<8 | 'U'<<16 | ' '<<24), + NUU_CHAH_NULTH = ('N' | 'U'<<8 | 'K'<<16 | ' '<<24), + NYAMWEZI = ('N' | 'Y'<<8 | 'M'<<16 | ' '<<24), + NYANKOLE = ('N' | 'K'<<8 | 'L'<<16 | ' '<<24), + OCCITAN = ('O' | 'C'<<8 | 'I'<<16 | ' '<<24), + ODIA = ('O' | 'R'<<8 | 'I'<<16 | ' '<<24), + OJI_CREE = ('O' | 'C'<<8 | 'R'<<16 | ' '<<24), + OJIBWAY = ('O' | 'J'<<8 | 'B'<<16 | ' '<<24), + OLD_IRISH = ('S' | 'G'<<8 | 'A'<<16 | ' '<<24), + OLD_JAVANESE = ('K' | 'A'<<8 | 'W'<<16 | ' '<<24), + ONEIDA = ('O' | 'N'<<8 | 'E'<<16 | ' '<<24), + ONONDAGA = ('O' | 'N'<<8 | 'O'<<16 | ' '<<24), + OROMO = ('O' | 'R'<<8 | 'O'<<16 | ' '<<24), + OSSETIAN = ('O' | 'S'<<8 | 'S'<<16 | ' '<<24), + PA_O_KAREN = ('B' | 'L'<<8 | 'K'<<16 | ' '<<24), + PALAUAN = ('P' | 'A'<<8 | 'U'<<16 | ' '<<24), + PALAUNG = ('P' | 'L'<<8 | 'G'<<16 | ' '<<24), + PALESTINIAN_ARAMAIC = ('P' | 'A'<<8 | 'A'<<16 | ' '<<24), + PALI = ('P' | 'A'<<8 | 'L'<<16 | ' '<<24), + PALPA = ('P' | 'A'<<8 | 'P'<<16 | ' '<<24), + PAMPANGAN = ('P' | 'A'<<8 | 'M'<<16 | ' '<<24), + PANGASINAN = ('P' | 'A'<<8 | 'G'<<16 | ' '<<24), + PAPIAMENTU = ('P' | 'A'<<8 | 'P'<<16 | '0'<<24), + PASHTO = ('P' | 'A'<<8 | 'S'<<16 | ' '<<24), + PATTANI_MALAY = ('M' | 'F'<<8 | 'A'<<16 | ' '<<24), + PENNSYLVANIA_GERMAN = ('P' | 'D'<<8 | 'C'<<16 | ' '<<24), + PERSIAN = ('F' | 'A'<<8 | 'R'<<16 | ' '<<24), + PHAKE = ('P' | 'J'<<8 | 'K'<<16 | ' '<<24), + PICARD = ('P' | 'C'<<8 | 'D'<<16 | ' '<<24), + PIEMONTESE = ('P' | 'M'<<8 | 'S'<<16 | ' '<<24), + PILAGA = ('P' | 'L'<<8 | 'G'<<16 | ' '<<24), + PITE_SAMI = ('S' | 'J'<<8 | 'E'<<16 | ' '<<24), + POCOMCHI = ('P' | 'O'<<8 | 'H'<<16 | ' '<<24), + POHNPEIAN = ('P' | 'O'<<8 | 'N'<<16 | ' '<<24), + POLISH = ('P' | 'L'<<8 | 'K'<<16 | ' '<<24), + POLYTONIC_GREEK = ('P' | 'G'<<8 | 'R'<<16 | ' '<<24), + PORTUGUESE = ('P' | 'T'<<8 | 'G'<<16 | ' '<<24), + PROVENCAL = ('P' | 'R'<<8 | 'O'<<16 | ' '<<24), + PUNJABI = ('P' | 'A'<<8 | 'N'<<16 | ' '<<24), + QUECHUA = ('Q' | 'U'<<8 | 'Z'<<16 | ' '<<24), + QUECHUA_BOLIVIA = ('Q' | 'U'<<8 | 'H'<<16 | ' '<<24), + QUECHUA_ECUADOR = ('Q' | 'V'<<8 | 'I'<<16 | ' '<<24), + QUECHUA_PERU = ('Q' | 'W'<<8 | 'H'<<16 | ' '<<24), + R_CREE = ('R' | 'C'<<8 | 'R'<<16 | ' '<<24), + RAJASTHANI = ('R' | 'A'<<8 | 'J'<<16 | ' '<<24), + RAKHINE = ('A' | 'R'<<8 | 'K'<<16 | ' '<<24), + RAROTONGAN = ('R' | 'A'<<8 | 'R'<<16 | ' '<<24), + REJANG = ('R' | 'E'<<8 | 'J'<<16 | ' '<<24), + RIANG = ('R' | 'I'<<8 | 'A'<<16 | ' '<<24), + RIPUARIAN = ('K' | 'S'<<8 | 'H'<<16 | ' '<<24), + RITARUNGO = ('R' | 'I'<<8 | 'T'<<16 | ' '<<24), + ROHINGYA = ('R' | 'H'<<8 | 'G'<<16 | ' '<<24), + ROMANIAN = ('R' | 'O'<<8 | 'M'<<16 | ' '<<24), + ROMANSH = ('R' | 'M'<<8 | 'S'<<16 | ' '<<24), + ROMANY = ('R' | 'O'<<8 | 'Y'<<16 | ' '<<24), + ROTUMAN = ('R' | 'T'<<8 | 'M'<<16 | ' '<<24), + RUNDI = ('R' | 'U'<<8 | 'N'<<16 | ' '<<24), + RUSSIAN = ('R' | 'U'<<8 | 'S'<<16 | ' '<<24), + RUSSIAN_BURIAT = ('R' | 'B'<<8 | 'U'<<16 | ' '<<24), + RUSYN = ('R' | 'S'<<8 | 'Y'<<16 | ' '<<24), + SADRI = ('S' | 'A'<<8 | 'D'<<16 | ' '<<24), + SAKHA = ('Y' | 'A'<<8 | 'K'<<16 | ' '<<24), + SAMOAN = ('S' | 'M'<<8 | 'O'<<16 | ' '<<24), + SAMOGITIAN = ('S' | 'G'<<8 | 'S'<<16 | ' '<<24), + SAN_BLAS_KUNA = ('C' | 'U'<<8 | 'K'<<16 | ' '<<24), + SANGO = ('S' | 'G'<<8 | 'O'<<16 | ' '<<24), + SANSKRIT = ('S' | 'A'<<8 | 'N'<<16 | ' '<<24), + SANTALI = ('S' | 'A'<<8 | 'T'<<16 | ' '<<24), + SARAIKI = ('S' | 'R'<<8 | 'K'<<16 | ' '<<24), + SARDINIAN = ('S' | 'R'<<8 | 'D'<<16 | ' '<<24), + SASAK = ('S' | 'A'<<8 | 'S'<<16 | ' '<<24), + SATERLAND_FRISIAN = ('S' | 'T'<<8 | 'Q'<<16 | ' '<<24), + SAYISI = ('S' | 'A'<<8 | 'Y'<<16 | ' '<<24), + SCOTS = ('S' | 'C'<<8 | 'I'<<16 | ' '<<24), + SCOTTISH_GAELIC = ('G' | 'A'<<8 | 'E'<<16 | ' '<<24), + SEKOTA = ('S' | 'E'<<8 | 'J'<<16 | ' '<<24), + SELKUP = ('S' | 'E'<<8 | 'L'<<16 | ' '<<24), + SENA = ('S' | 'N'<<8 | 'A'<<16 | ' '<<24), + SENECA = ('S' | 'E'<<8 | 'E'<<16 | ' '<<24), + SERBIAN = ('S' | 'R'<<8 | 'B'<<16 | ' '<<24), + SERER = ('S' | 'R'<<8 | 'R'<<16 | ' '<<24), + SGAW_KAREN = ('K' | 'S'<<8 | 'W'<<16 | ' '<<24), + SHAN = ('S' | 'H'<<8 | 'N'<<16 | ' '<<24), + SHONA = ('S' | 'N'<<8 | 'A'<<16 | ' '<<24), + SIBE = ('S' | 'I'<<8 | 'B'<<16 | ' '<<24), + SICILIAN = ('S' | 'C'<<8 | 'N'<<16 | ' '<<24), + SIDAMO = ('S' | 'I'<<8 | 'D'<<16 | ' '<<24), + SILESIAN = ('S' | 'Z'<<8 | 'L'<<16 | ' '<<24), + SILTE_GURAGE = ('S' | 'I'<<8 | 'G'<<16 | ' '<<24), + SINDHI = ('S' | 'N'<<8 | 'D'<<16 | ' '<<24), + SINHALA = ('S' | 'N'<<8 | 'H'<<16 | ' '<<24), + SKOLT_SAMI = ('S' | 'K'<<8 | 'S'<<16 | ' '<<24), + SLAVEY = ('S' | 'L'<<8 | 'A'<<16 | ' '<<24), + SLOVAK = ('S' | 'K'<<8 | 'Y'<<16 | ' '<<24), + SLOVENIAN = ('S' | 'L'<<8 | 'V'<<16 | ' '<<24), + SMALL_FLOWERY_MIAO = ('S' | 'F'<<8 | 'M'<<16 | ' '<<24), + SODO_GURAGE = ('S' | 'O'<<8 | 'G'<<16 | ' '<<24), + SOGA = ('X' | 'O'<<8 | 'G'<<16 | ' '<<24), + SOMALI = ('S' | 'M'<<8 | 'L'<<16 | ' '<<24), + SONGE = ('S' | 'O'<<8 | 'P'<<16 | ' '<<24), + SONINKE = ('S' | 'N'<<8 | 'K'<<16 | ' '<<24), + SOUTH_SLAVEY = ('S' | 'S'<<8 | 'L'<<16 | ' '<<24), + SOUTHERN_KIWAI = ('K' | 'J'<<8 | 'D'<<16 | ' '<<24), + SOUTHERN_SAMI = ('S' | 'S'<<8 | 'M'<<16 | ' '<<24), + SOUTHERN_SOTHO = ('S' | 'O'<<8 | 'T'<<16 | ' '<<24), + SPANISH = ('E' | 'S'<<8 | 'P'<<16 | ' '<<24), + STANDARD_MOROCCAN_TAMAZIGHT = ('Z' | 'G'<<8 | 'H'<<16 | ' '<<24), + STRAITS_SALISH = ('S' | 'T'<<8 | 'R'<<16 | ' '<<24), + SUKUMA = ('S' | 'U'<<8 | 'K'<<16 | ' '<<24), + SUNDANESE = ('S' | 'U'<<8 | 'N'<<16 | ' '<<24), + SURI = ('S' | 'U'<<8 | 'R'<<16 | ' '<<24), + SUTU = ('S' | 'X'<<8 | 'T'<<16 | ' '<<24), + SVAN = ('S' | 'V'<<8 | 'A'<<16 | ' '<<24), + SWADAYA_ARAMAIC = ('S' | 'W'<<8 | 'A'<<16 | ' '<<24), + SWAHILI = ('S' | 'W'<<8 | 'K'<<16 | ' '<<24), + SWATI = ('S' | 'W'<<8 | 'Z'<<16 | ' '<<24), + SWEDISH = ('S' | 'V'<<8 | 'E'<<16 | ' '<<24), + SYLHETI = ('S' | 'Y'<<8 | 'L'<<16 | ' '<<24), + SYRIAC = ('S' | 'Y'<<8 | 'R'<<16 | ' '<<24), + SYRIAC_EASTERN = ('S' | 'Y'<<8 | 'R'<<16 | 'N'<<24), + SYRIAC_ESTRANGELA = ('S' | 'Y'<<8 | 'R'<<16 | 'E'<<24), + SYRIAC_WESTERN = ('S' | 'Y'<<8 | 'R'<<16 | 'J'<<24), + TABASARAN = ('T' | 'A'<<8 | 'B'<<16 | ' '<<24), + TACHELHIT = ('S' | 'H'<<8 | 'I'<<16 | ' '<<24), + TAGALOG = ('T' | 'G'<<8 | 'L'<<16 | ' '<<24), + TAHAGGART_TAMAHAQ = ('T' | 'H'<<8 | 'V'<<16 | ' '<<24), + TAHITIAN = ('T' | 'H'<<8 | 'T'<<16 | ' '<<24), + TAI_LAING = ('T' | 'J'<<8 | 'L'<<16 | ' '<<24), + TAJIKI = ('T' | 'A'<<8 | 'J'<<16 | ' '<<24), + TALYSH = ('T' | 'L'<<8 | 'Y'<<16 | ' '<<24), + TAMASHEK = ('T' | 'M'<<8 | 'H'<<16 | ' '<<24), + TAMASHEQ = ('T' | 'A'<<8 | 'Q'<<16 | ' '<<24), + TAMAZIGHT = ('T' | 'Z'<<8 | 'M'<<16 | ' '<<24), + TAMIL = ('T' | 'A'<<8 | 'M'<<16 | ' '<<24), + TARIFIT = ('R' | 'I'<<8 | 'F'<<16 | ' '<<24), + TATAR = ('T' | 'A'<<8 | 'T'<<16 | ' '<<24), + TAWALLAMMAT_TAMAJAQ = ('T' | 'T'<<8 | 'Q'<<16 | ' '<<24), + TAY = ('T' | 'Y'<<8 | 'Z'<<16 | ' '<<24), + TAYART_TAMAJEQ = ('T' | 'H'<<8 | 'Z'<<16 | ' '<<24), + TELUGU = ('T' | 'E'<<8 | 'L'<<16 | ' '<<24), + TEMNE = ('T' | 'M'<<8 | 'N'<<16 | ' '<<24), + TETUM = ('T' | 'E'<<8 | 'T'<<16 | ' '<<24), + TH_CREE = ('T' | 'C'<<8 | 'R'<<16 | ' '<<24), + THAI = ('T' | 'H'<<8 | 'A'<<16 | ' '<<24), + THAILAND_MON = ('M' | 'O'<<8 | 'N'<<16 | 'T'<<24), + THOMPSON = ('T' | 'H'<<8 | 'P'<<16 | ' '<<24), + TIBETAN = ('T' | 'I'<<8 | 'B'<<16 | ' '<<24), + TIGRE = ('T' | 'G'<<8 | 'R'<<16 | ' '<<24), + TIGRINYA = ('T' | 'G'<<8 | 'Y'<<16 | ' '<<24), + TIV = ('T' | 'I'<<8 | 'V'<<16 | ' '<<24), + TLINGIT = ('T' | 'L'<<8 | 'I'<<16 | ' '<<24), + TOBO = ('T' | 'B'<<8 | 'V'<<16 | ' '<<24), + TODO = ('T' | 'O'<<8 | 'D'<<16 | ' '<<24), + TOK_PISIN = ('T' | 'P'<<8 | 'I'<<16 | ' '<<24), + TOMA = ('T' | 'O'<<8 | 'D'<<16 | '0'<<24), + TONGA = ('T' | 'N'<<8 | 'G'<<16 | ' '<<24), + TONGAN = ('T' | 'G'<<8 | 'N'<<16 | ' '<<24), + TORKI = ('A' | 'Z'<<8 | 'B'<<16 | ' '<<24), + TSHANGLA = ('T' | 'S'<<8 | 'J'<<16 | ' '<<24), + TSONGA = ('T' | 'S'<<8 | 'G'<<16 | ' '<<24), + TSWANA = ('T' | 'N'<<8 | 'A'<<16 | ' '<<24), + TULU = ('T' | 'U'<<8 | 'L'<<16 | ' '<<24), + TUMBUKA = ('T' | 'U'<<8 | 'M'<<16 | ' '<<24), + TUNDRA_ENETS = ('T' | 'N'<<8 | 'E'<<16 | ' '<<24), + TURKISH = ('T' | 'R'<<8 | 'K'<<16 | ' '<<24), + TURKMEN = ('T' | 'K'<<8 | 'M'<<16 | ' '<<24), + TUROYO_ARAMAIC = ('T' | 'U'<<8 | 'A'<<16 | ' '<<24), + TUSCARORA = ('T' | 'U'<<8 | 'S'<<16 | ' '<<24), + TUVALU = ('T' | 'V'<<8 | 'L'<<16 | ' '<<24), + TUVIN = ('T' | 'U'<<8 | 'V'<<16 | ' '<<24), + TWI = ('T' | 'W'<<8 | 'I'<<16 | ' '<<24), + TZOTZIL = ('T' | 'Z'<<8 | 'O'<<16 | ' '<<24), + UDI = ('U' | 'D'<<8 | 'I'<<16 | ' '<<24), + UDMURT = ('U' | 'D'<<8 | 'M'<<16 | ' '<<24), + UKRAINIAN = ('U' | 'K'<<8 | 'R'<<16 | ' '<<24), + UMBUNDU = ('U' | 'M'<<8 | 'B'<<16 | ' '<<24), + UME_SAMI = ('S' | 'J'<<8 | 'U'<<16 | ' '<<24), + UPPER_SAXON = ('S' | 'X'<<8 | 'U'<<16 | ' '<<24), + UPPER_SORBIAN = ('U' | 'S'<<8 | 'B'<<16 | ' '<<24), + URALIC_PHONETIC = ('U' | 'P'<<8 | 'P'<<16 | ' '<<24), + URDU = ('U' | 'R'<<8 | 'D'<<16 | ' '<<24), + UYGHUR = ('U' | 'Y'<<8 | 'G'<<16 | ' '<<24), + UZBEK = ('U' | 'Z'<<8 | 'B'<<16 | ' '<<24), + VENDA = ('V' | 'E'<<8 | 'N'<<16 | ' '<<24), + VENETIAN = ('V' | 'E'<<8 | 'C'<<16 | ' '<<24), + VIETNAMESE = ('V' | 'I'<<8 | 'T'<<16 | ' '<<24), + VLAX_ROMANI = ('R' | 'M'<<8 | 'Y'<<16 | ' '<<24), + VOLAPUK = ('V' | 'O'<<8 | 'L'<<16 | ' '<<24), + VORO = ('V' | 'R'<<8 | 'O'<<16 | ' '<<24), + WA = ('W' | 'A'<<8 | ' '<<16 | ' '<<24), + WACI_GBE = ('W' | 'C'<<8 | 'I'<<16 | ' '<<24), + WAGDI = ('W' | 'A'<<8 | 'G'<<16 | ' '<<24), + WAKHI = ('W' | 'B'<<8 | 'L'<<16 | ' '<<24), + WALLOON = ('W' | 'L'<<8 | 'N'<<16 | ' '<<24), + WARAY_WARAY = ('W' | 'A'<<8 | 'R'<<16 | ' '<<24), + WAYANAD_CHETTI = ('C' | 'T'<<8 | 'T'<<16 | ' '<<24), + WAYUU = ('G' | 'U'<<8 | 'C'<<16 | ' '<<24), + WELSH = ('W' | 'E'<<8 | 'L'<<16 | ' '<<24), + WENDAT = ('W' | 'D'<<8 | 'T'<<16 | ' '<<24), + WEST_CREE = ('W' | 'C'<<8 | 'R'<<16 | ' '<<24), + WESTERN_CHAM = ('C' | 'J'<<8 | 'A'<<16 | ' '<<24), + WESTERN_KAYAH = ('K' | 'Y'<<8 | 'U'<<16 | ' '<<24), + WESTERN_PANJABI = ('P' | 'N'<<8 | 'B'<<16 | ' '<<24), + WESTERN_PWO_KAREN = ('P' | 'W'<<8 | 'O'<<16 | ' '<<24), + WOLOF = ('W' | 'L'<<8 | 'F'<<16 | ' '<<24), + WOODS_CREE = ('D' | 'C'<<8 | 'R'<<16 | ' '<<24), + WUDING_LUQUAN_YI = ('Y' | 'W'<<8 | 'Q'<<16 | ' '<<24), + WYANDOT = ('W' | 'Y'<<8 | 'N'<<16 | ' '<<24), + XHOSA = ('X' | 'H'<<8 | 'S'<<16 | ' '<<24), + Y_CREE = ('Y' | 'C'<<8 | 'R'<<16 | ' '<<24), + YAO = ('Y' | 'A'<<8 | 'O'<<16 | ' '<<24), + YAPESE = ('Y' | 'A'<<8 | 'P'<<16 | ' '<<24), + YI_CLASSIC = ('Y' | 'I'<<8 | 'C'<<16 | ' '<<24), + YI_MODERN = ('Y' | 'I'<<8 | 'M'<<16 | ' '<<24), + YIDDISH = ('J' | 'I'<<8 | 'I'<<16 | ' '<<24), + YORUBA = ('Y' | 'B'<<8 | 'A'<<16 | ' '<<24), + ZAMBOANGA_CHAVACANO = ('C' | 'B'<<8 | 'K'<<16 | ' '<<24), + ZANDE = ('Z' | 'N'<<8 | 'D'<<16 | ' '<<24), + ZARMA = ('D' | 'J'<<8 | 'R'<<16 | ' '<<24), + ZAZAKI = ('Z' | 'Z'<<8 | 'A'<<16 | ' '<<24), + ZEALANDIC = ('Z' | 'E'<<8 | 'A'<<16 | ' '<<24), + ZHUANG = ('Z' | 'H'<<8 | 'A'<<16 | ' '<<24), + ZULU = ('Z' | 'U'<<8 | 'L'<<16 | ' '<<24), +} + +break_flags :: distinct bit_set[break_flag; u32] +break_flag :: enum u32 { + // Direction changes from left-to-right to right-to-left, or vice versa. + DIRECTION = 0, + // Script changes. + // Note that some characters, such as digits, are used in multiple + // scripts and, as such, will not produce script breaks. + SCRIPT = 1, + // Graphemes are "visual units". They may be composed of more than one codepoint. + // They are used as interaction boundaries in graphical interfaces, e.g. moving the + // caret. + GRAPHEME = 2, + // In most scripts, words are broken up by whitespace, but Unicode word breaking has + // better script coverage and also handles some special cases that a simple stateless + // loop cannot handle. + WORD = 3, + // By default, you are not allowed to break a line. + // Soft line breaks allow for line breaking, but do not require it. + // This is useful for when you are doing line wrapping. + LINE_SOFT = 4, + // Hard line breaks are required. They signal the end of a paragraph. + // (In Unicode, there is no meaningful distinction between a line and a paragraph. + // a paragraph is pretty much just a line of text that can wrap.) + LINE_HARD = 5, +} + +BREAK_FLAGS_DIRECTION :: break_flags{.DIRECTION} +BREAK_FLAGS_SCRIPT :: break_flags{.SCRIPT} +BREAK_FLAGS_GRAPHEME :: break_flags{.GRAPHEME} +BREAK_FLAGS_WORD :: break_flags{.WORD} +BREAK_FLAGS_LINE_SOFT :: break_flags{.LINE_SOFT} +BREAK_FLAGS_LINE_HARD :: break_flags{.LINE_HARD} +BREAK_FLAGS_LINE :: break_flags{.LINE_SOFT, .LINE_HARD} +BREAK_FLAGS_ANY :: break_flags{.DIRECTION, .SCRIPT, .GRAPHEME, .WORD, .LINE_SOFT, .LINE_HARD} + + +op_kind :: enum u8 { + END, + + // Substitution ops. + PRE_NORMALIZE_DOTTED_CIRCLES, + NORMALIZE, + NORMALIZE_HANGUL, + FLAG_JOINING_LETTERS, + GSUB_FEATURES, + GSUB_FEATURES_WITH_USER, + + // Positioning ops. + GPOS_METRICS, + GPOS_FEATURES, + + POST_GPOS_FIXUP, + STCH_POSTPASS, +} + + + +glyph_flags :: distinct bit_set[glyph_flag; u32] +glyph_flag :: enum u32 { + // These feature flags must coincide with joining_feature _and_ FEATURE_FLAG! + ISOL = 0, + FINA = 1, + FIN2 = 2, + FIN3 = 3, + MEDI = 4, + MED2 = 5, + INIT = 6, + + // These feature flags must coincide with FEATURE_FLAG! + LJMO = 7, + VJMO = 8, + TJMO = 9, + RPHF = 10, + BLWF = 11, + HALF = 12, + PSTF = 13, + ABVF = 14, + PREF = 15, + NUMR = 16, + FRAC = 17, + DNOM = 18, + CFAR = 19, + + // These can be anything. + DO_NOT_DECOMPOSE = 21, + FIRST_IN_MULTIPLE_SUBSTITUTION = 22, + NO_BREAK = 23, + CURSIVE = 24, + GENERATED_BY_GSUB = 25, + USED_IN_GPOS = 26, + + STCH_ENDPOINT = 27, + STCH_EXTENSION = 28, + + LIGATURE = 29, + MULTIPLE_SUBSTITUTION = 30, +} + +GLYPH_FEATURE_MASK :: glyph_flags{.ISOL, .FINA, .FIN2, .FIN3, .MEDI, .MED2, .INIT, .LJMO, .VJMO, .TJMO, .RPHF, .BLWF, .HALF, .PSTF, .ABVF, .PREF, .NUMR, .FRAC, .DNOM, .CFAR} + +// In USE, glyphs are mostly not pre-flagged for feature application. +// However, we do want to flag rphf/pref results for reordering, so we want to +// keep all of the flags as usual, and only use these feature flags for filtering. + +USE_GLYPH_FEATURE_MASK :: glyph_flags{ + .ISOL, .FINA, .FIN2, .FIN3, .MEDI, .MED2, .INIT, + .NUMR, .DNOM, .FRAC, +} + +JOINING_FEATURE_MASK :: glyph_flags{.ISOL, .FINA, .FIN2, .FIN3, .MEDI, .MED2, .INIT} + + +// Japanese text contains "kinsoku" characters, around which breaking a line is forbidden. +// Exactly which characters are "kinsoku" or not depends on the context: +// - Strict style has the largest amount of kinsoku characters, which leads to longer lines. +// - Loose style has the smallest amount of kinsoku characters, which leads to smaller lines. +// - Normal style is somewhere in the middle. +// Note that, while the Unicode standard mentions all three of these styles, it does not mention +// any differences between the normal and loose styles. +// As such, normal and loose styles currently behave the same. +japanese_line_break_style :: enum u8 { + // The Unicode standard does not define what strict style is used for. + // Supposedly, it is used for anything that does not fall into the other two categories of text. + STRICT, + + // Normal style is used for books and documents. + NORMAL, + + // Loose style is used for newspapers, and (I assume) any other narrow column format. + LOOSE, +} + + +orientation :: enum u32 { + HORIZONTAL, + VERTICAL, +} + +direction :: enum u32 { + NONE, + LTR, + RTL, +} + +unicode_joining_type :: enum u8 { + NONE, + LEFT, + DUAL, + FORCE, + RIGHT, + TRANSPARENT, +} + +unicode_flags :: distinct bit_set[unicode_flag; u8] +unicode_flag :: enum u8 { + MODIFIER_COMBINING_MARK = 0, + DEFAULT_IGNORABLE = 1, + OPEN_BRACKET = 2, + CLOSE_BRACKET = 3, + PART_OF_WORD = 4, + DECIMAL_DIGIT = 5, + NON_SPACING_MARK = 6, +} + +unicode_bidirectional_class :: enum u8 { + NI, + L, + R, + NSM, + AL, + AN, + EN, + ES, + ET, + CS, +} + +line_break_class :: enum u8 { + /* 0 */ Onea, + /* 1 */ Oea, + /* 2 */ Ope, + /* 3 */ BK, + /* 4 */ CR, + /* 5 */ LF, + /* 6 */ NL, + /* 7 */ SP, + /* 8 */ ZW, + /* 9 */ WJ, + /* 10 */ GLnea, + /* 11 */ GLea, + /* 12 */ CLnea, + /* 13 */ CLea, + /* 14 */ CPnea, + /* 15 */ CPea, + /* 16 */ EXnea, + /* 17 */ EXea, + /* 18 */ SY, + /* 19 */ BAnea, + /* 20 */ BAea, + /* 21 */ OPnea, + /* 22 */ OPea, + /* 23 */ QU, + /* 24 */ QUPi, + /* 25 */ QUPf, + /* 26 */ IS, + /* 27 */ NSnea, + /* 28 */ NSea, + /* 29 */ B2, + /* 30 */ CB, + /* 31 */ HY, + /* 32 */ HYPHEN, + /* 33 */ INnea, + /* 34 */ INea, + /* 35 */ BB, + /* 36 */ HL, + /* 37 */ ALnea, + /* 38 */ ALea, + /* 39 */ NU, + /* 40 */ PRnea, + /* 41 */ PRea, + /* 42 */ IDnea, + /* 43 */ IDea, + /* 44 */ IDpe, + /* 45 */ EBnea, + /* 46 */ EBea, + /* 47 */ EM, + /* 48 */ POnea, + /* 49 */ POea, + /* 50 */ JL, + /* 51 */ JV, + /* 52 */ JT, + /* 53 */ H2, + /* 54 */ H3, + /* 55 */ AP, + /* 56 */ AK, + /* 57 */ DOTTED_CIRCLE, + /* 58 */ AS, + /* 59 */ VF, + /* 60 */ VI, + /* 61 */ RI, + + /* 62 */ COUNT, + + /* 63 */ CM, + /* 64 */ ZWJ, + + // CJ resolves to either NS or ID depending on the (Japanese) line break style. + // NS is strict line breaking, used for long lines. + // ID is normal line breaking, used for normal body text. + /* 65 */ CJ, + + /* 66 */ SOT, + /* 67 */ EOT, +} + +// @Cleanup: Merge EX and FO. +word_break_class :: enum u8 { + Onep, + Oep, + CR, + LF, + NL, + EX, + ZWJ, + RI, + FO, + KA, + HL, + ALnep, + ALep, + SQ, + DQ, + MNL, + ML, + MN, + NM, + ENL, + WSS, + + SOT, +} + +// Unicode defines scripts and languages. +// A language belongs to a single script, and a script belongs to a single writing system. +// On top of these, OpenType defines shapers, which are basically just designations for +// specific code paths that are taken depending on which script is being shapen. +// +// Some scripts, like Latin and Cyrillic, need relatively few operations, while complex +// scripts like Arabic and Indic scripts have specific processing steps that need to happen +// in order to obtain a correct result. +// +// These sequences of operations are _not_ described in the font file itself. The shaping +// code needs to know which script it is shaping, and implement all of those passes itself. +// That is why you, as a user, have to care about this. +// +// When creating shape_config, you can either pass in a known script, or you can specify +// SCRIPT_DONT_KNOW and let the library figure it out. +// While SCRIPT_DONT_KNOW may look appealing, it is worth noting that we can only infer +// the _script_, and not the language, of the text you pass in. +// This means that you might miss out on language-specific features when you use it. +shaper :: enum u32 { + DEFAULT, + ARABIC, + HANGUL, + HEBREW, + INDIC, + KHMER, + MYANMAR, + TIBETAN, + USE, +} + +script_tag :: enum u32 { + DONT_KNOW = (' ' | ' '<<8 | ' '<<16 | ' '<<24), + ADLAM = ('a' | 'd'<<8 | 'l'<<16 | 'm'<<24), + AHOM = ('a' | 'h'<<8 | 'o'<<16 | 'm'<<24), + ANATOLIAN_HIEROGLYPHS = ('h' | 'l'<<8 | 'u'<<16 | 'w'<<24), + ARABIC = ('a' | 'r'<<8 | 'a'<<16 | 'b'<<24), + ARMENIAN = ('a' | 'r'<<8 | 'm'<<16 | 'n'<<24), + AVESTAN = ('a' | 'v'<<8 | 's'<<16 | 't'<<24), + BALINESE = ('b' | 'a'<<8 | 'l'<<16 | 'i'<<24), + BAMUM = ('b' | 'a'<<8 | 'm'<<16 | 'u'<<24), + BASSA_VAH = ('b' | 'a'<<8 | 's'<<16 | 's'<<24), + BATAK = ('b' | 'a'<<8 | 't'<<16 | 'k'<<24), + BENGALI = ('b' | 'n'<<8 | 'g'<<16 | '2'<<24), + BHAIKSUKI = ('b' | 'h'<<8 | 'k'<<16 | 's'<<24), + BOPOMOFO = ('b' | 'o'<<8 | 'p'<<16 | 'o'<<24), + BRAHMI = ('b' | 'r'<<8 | 'a'<<16 | 'h'<<24), + BUGINESE = ('b' | 'u'<<8 | 'g'<<16 | 'i'<<24), + BUHID = ('b' | 'u'<<8 | 'h'<<16 | 'd'<<24), + CANADIAN_SYLLABICS = ('c' | 'a'<<8 | 'n'<<16 | 's'<<24), + CARIAN = ('c' | 'a'<<8 | 'r'<<16 | 'i'<<24), + CAUCASIAN_ALBANIAN = ('a' | 'g'<<8 | 'h'<<16 | 'b'<<24), + CHAKMA = ('c' | 'a'<<8 | 'k'<<16 | 'm'<<24), + CHAM = ('c' | 'h'<<8 | 'a'<<16 | 'm'<<24), + CHEROKEE = ('c' | 'h'<<8 | 'e'<<16 | 'r'<<24), + CHORASMIAN = ('c' | 'h'<<8 | 'r'<<16 | 's'<<24), + CJK_IDEOGRAPHIC = ('h' | 'a'<<8 | 'n'<<16 | 'i'<<24), + COPTIC = ('c' | 'o'<<8 | 'p'<<16 | 't'<<24), + CYPRIOT_SYLLABARY = ('c' | 'p'<<8 | 'r'<<16 | 't'<<24), + CYPRO_MINOAN = ('c' | 'p'<<8 | 'm'<<16 | 'n'<<24), + CYRILLIC = ('c' | 'y'<<8 | 'r'<<16 | 'l'<<24), + DEFAULT = ('D' | 'F'<<8 | 'L'<<16 | 'T'<<24), + DEFAULT2 = ('D' | 'F'<<8 | 'L'<<16 | 'T'<<24), + DESERET = ('d' | 's'<<8 | 'r'<<16 | 't'<<24), + DEVANAGARI = ('d' | 'e'<<8 | 'v'<<16 | '2'<<24), + DIVES_AKURU = ('d' | 'i'<<8 | 'a'<<16 | 'k'<<24), + DOGRA = ('d' | 'o'<<8 | 'g'<<16 | 'r'<<24), + DUPLOYAN = ('d' | 'u'<<8 | 'p'<<16 | 'l'<<24), + EGYPTIAN_HIEROGLYPHS = ('e' | 'g'<<8 | 'y'<<16 | 'p'<<24), + ELBASAN = ('e' | 'l'<<8 | 'b'<<16 | 'a'<<24), + ELYMAIC = ('e' | 'l'<<8 | 'y'<<16 | 'm'<<24), + ETHIOPIC = ('e' | 't'<<8 | 'h'<<16 | 'i'<<24), + GARAY = ('g' | 'a'<<8 | 'r'<<16 | 'a'<<24), + GEORGIAN = ('g' | 'e'<<8 | 'o'<<16 | 'r'<<24), + GLAGOLITIC = ('g' | 'l'<<8 | 'a'<<16 | 'g'<<24), + GOTHIC = ('g' | 'o'<<8 | 't'<<16 | 'h'<<24), + GRANTHA = ('g' | 'r'<<8 | 'a'<<16 | 'n'<<24), + GREEK = ('g' | 'r'<<8 | 'e'<<16 | 'k'<<24), + GUJARATI = ('g' | 'j'<<8 | 'r'<<16 | '2'<<24), + GUNJALA_GONDI = ('g' | 'o'<<8 | 'n'<<16 | 'g'<<24), + GURMUKHI = ('g' | 'u'<<8 | 'r'<<16 | '2'<<24), + GURUNG_KHEMA = ('g' | 'u'<<8 | 'k'<<16 | 'h'<<24), + HANGUL = ('h' | 'a'<<8 | 'n'<<16 | 'g'<<24), + HANIFI_ROHINGYA = ('r' | 'o'<<8 | 'h'<<16 | 'g'<<24), + HANUNOO = ('h' | 'a'<<8 | 'n'<<16 | 'o'<<24), + HATRAN = ('h' | 'a'<<8 | 't'<<16 | 'r'<<24), + HEBREW = ('h' | 'e'<<8 | 'b'<<16 | 'r'<<24), + HIRAGANA = ('k' | 'a'<<8 | 'n'<<16 | 'a'<<24), + IMPERIAL_ARAMAIC = ('a' | 'r'<<8 | 'm'<<16 | 'i'<<24), + INSCRIPTIONAL_PAHLAVI = ('p' | 'h'<<8 | 'l'<<16 | 'i'<<24), + INSCRIPTIONAL_PARTHIAN = ('p' | 'r'<<8 | 't'<<16 | 'i'<<24), + JAVANESE = ('j' | 'a'<<8 | 'v'<<16 | 'a'<<24), + KAITHI = ('k' | 't'<<8 | 'h'<<16 | 'i'<<24), + KANNADA = ('k' | 'n'<<8 | 'd'<<16 | '2'<<24), + KATAKANA = ('k' | 'a'<<8 | 'n'<<16 | 'a'<<24), + KAWI = ('k' | 'a'<<8 | 'w'<<16 | 'i'<<24), + KAYAH_LI = ('k' | 'a'<<8 | 'l'<<16 | 'i'<<24), + KHAROSHTHI = ('k' | 'h'<<8 | 'a'<<16 | 'r'<<24), + KHITAN_SMALL_SCRIPT = ('k' | 'i'<<8 | 't'<<16 | 's'<<24), + KHMER = ('k' | 'h'<<8 | 'm'<<16 | 'r'<<24), + KHOJKI = ('k' | 'h'<<8 | 'o'<<16 | 'j'<<24), + KHUDAWADI = ('s' | 'i'<<8 | 'n'<<16 | 'd'<<24), + KIRAT_RAI = ('k' | 'r'<<8 | 'a'<<16 | 'i'<<24), + LAO = ('l' | 'a'<<8 | 'o'<<16 | ' '<<24), + LATIN = ('l' | 'a'<<8 | 't'<<16 | 'n'<<24), + LEPCHA = ('l' | 'e'<<8 | 'p'<<16 | 'c'<<24), + LIMBU = ('l' | 'i'<<8 | 'm'<<16 | 'b'<<24), + LINEAR_A = ('l' | 'i'<<8 | 'n'<<16 | 'a'<<24), + LINEAR_B = ('l' | 'i'<<8 | 'n'<<16 | 'b'<<24), + LISU = ('l' | 'i'<<8 | 's'<<16 | 'u'<<24), + LYCIAN = ('l' | 'y'<<8 | 'c'<<16 | 'i'<<24), + LYDIAN = ('l' | 'y'<<8 | 'd'<<16 | 'i'<<24), + MAHAJANI = ('m' | 'a'<<8 | 'h'<<16 | 'j'<<24), + MAKASAR = ('m' | 'a'<<8 | 'k'<<16 | 'a'<<24), + MALAYALAM = ('m' | 'l'<<8 | 'm'<<16 | '2'<<24), + MANDAIC = ('m' | 'a'<<8 | 'n'<<16 | 'd'<<24), + MANICHAEAN = ('m' | 'a'<<8 | 'n'<<16 | 'i'<<24), + MARCHEN = ('m' | 'a'<<8 | 'r'<<16 | 'c'<<24), + MASARAM_GONDI = ('g' | 'o'<<8 | 'n'<<16 | 'm'<<24), + MEDEFAIDRIN = ('m' | 'e'<<8 | 'd'<<16 | 'f'<<24), + MEETEI_MAYEK = ('m' | 't'<<8 | 'e'<<16 | 'i'<<24), + MENDE_KIKAKUI = ('m' | 'e'<<8 | 'n'<<16 | 'd'<<24), + MEROITIC_CURSIVE = ('m' | 'e'<<8 | 'r'<<16 | 'c'<<24), + MEROITIC_HIEROGLYPHS = ('m' | 'e'<<8 | 'r'<<16 | 'o'<<24), + MIAO = ('p' | 'l'<<8 | 'r'<<16 | 'd'<<24), + MODI = ('m' | 'o'<<8 | 'd'<<16 | 'i'<<24), + MONGOLIAN = ('m' | 'o'<<8 | 'n'<<16 | 'g'<<24), + MRO = ('m' | 'r'<<8 | 'o'<<16 | 'o'<<24), + MULTANI = ('m' | 'u'<<8 | 'l'<<16 | 't'<<24), + MYANMAR = ('m' | 'y'<<8 | 'm'<<16 | '2'<<24), + NABATAEAN = ('n' | 'b'<<8 | 'a'<<16 | 't'<<24), + NAG_MUNDARI = ('n' | 'a'<<8 | 'g'<<16 | 'm'<<24), + NANDINAGARI = ('n' | 'a'<<8 | 'n'<<16 | 'd'<<24), + NEWA = ('n' | 'e'<<8 | 'w'<<16 | 'a'<<24), + NEW_TAI_LUE = ('t' | 'a'<<8 | 'l'<<16 | 'u'<<24), + NKO = ('n' | 'k'<<8 | 'o'<<16 | ' '<<24), + NUSHU = ('n' | 's'<<8 | 'h'<<16 | 'u'<<24), + NYIAKENG_PUACHUE_HMONG = ('h' | 'm'<<8 | 'n'<<16 | 'p'<<24), + OGHAM = ('o' | 'g'<<8 | 'a'<<16 | 'm'<<24), + OL_CHIKI = ('o' | 'l'<<8 | 'c'<<16 | 'k'<<24), + OL_ONAL = ('o' | 'n'<<8 | 'a'<<16 | 'o'<<24), + OLD_ITALIC = ('i' | 't'<<8 | 'a'<<16 | 'l'<<24), + OLD_HUNGARIAN = ('h' | 'u'<<8 | 'n'<<16 | 'g'<<24), + OLD_NORTH_ARABIAN = ('n' | 'a'<<8 | 'r'<<16 | 'b'<<24), + OLD_PERMIC = ('p' | 'e'<<8 | 'r'<<16 | 'm'<<24), + OLD_PERSIAN_CUNEIFORM = ('x' | 'p'<<8 | 'e'<<16 | 'o'<<24), + OLD_SOGDIAN = ('s' | 'o'<<8 | 'g'<<16 | 'o'<<24), + OLD_SOUTH_ARABIAN = ('s' | 'a'<<8 | 'r'<<16 | 'b'<<24), + OLD_TURKIC = ('o' | 'r'<<8 | 'k'<<16 | 'h'<<24), + OLD_UYGHUR = ('o' | 'u'<<8 | 'g'<<16 | 'r'<<24), + ODIA = ('o' | 'r'<<8 | 'y'<<16 | '2'<<24), + OSAGE = ('o' | 's'<<8 | 'g'<<16 | 'e'<<24), + OSMANYA = ('o' | 's'<<8 | 'm'<<16 | 'a'<<24), + PAHAWH_HMONG = ('h' | 'm'<<8 | 'n'<<16 | 'g'<<24), + PALMYRENE = ('p' | 'a'<<8 | 'l'<<16 | 'm'<<24), + PAU_CIN_HAU = ('p' | 'a'<<8 | 'u'<<16 | 'c'<<24), + PHAGS_PA = ('p' | 'h'<<8 | 'a'<<16 | 'g'<<24), + PHOENICIAN = ('p' | 'h'<<8 | 'n'<<16 | 'x'<<24), + PSALTER_PAHLAVI = ('p' | 'h'<<8 | 'l'<<16 | 'p'<<24), + REJANG = ('r' | 'j'<<8 | 'n'<<16 | 'g'<<24), + RUNIC = ('r' | 'u'<<8 | 'n'<<16 | 'r'<<24), + SAMARITAN = ('s' | 'a'<<8 | 'm'<<16 | 'r'<<24), + SAURASHTRA = ('s' | 'a'<<8 | 'u'<<16 | 'r'<<24), + SHARADA = ('s' | 'h'<<8 | 'r'<<16 | 'd'<<24), + SHAVIAN = ('s' | 'h'<<8 | 'a'<<16 | 'w'<<24), + SIDDHAM = ('s' | 'i'<<8 | 'd'<<16 | 'd'<<24), + SIGN_WRITING = ('s' | 'g'<<8 | 'n'<<16 | 'w'<<24), + SOGDIAN = ('s' | 'o'<<8 | 'g'<<16 | 'd'<<24), + SINHALA = ('s' | 'i'<<8 | 'n'<<16 | 'h'<<24), + SORA_SOMPENG = ('s' | 'o'<<8 | 'r'<<16 | 'a'<<24), + SOYOMBO = ('s' | 'o'<<8 | 'y'<<16 | 'o'<<24), + SUMERO_AKKADIAN_CUNEIFORM = ('x' | 's'<<8 | 'u'<<16 | 'x'<<24), + SUNDANESE = ('s' | 'u'<<8 | 'n'<<16 | 'd'<<24), + SUNUWAR = ('s' | 'u'<<8 | 'n'<<16 | 'u'<<24), + SYLOTI_NAGRI = ('s' | 'y'<<8 | 'l'<<16 | 'o'<<24), + SYRIAC = ('s' | 'y'<<8 | 'r'<<16 | 'c'<<24), + TAGALOG = ('t' | 'g'<<8 | 'l'<<16 | 'g'<<24), + TAGBANWA = ('t' | 'a'<<8 | 'g'<<16 | 'b'<<24), + TAI_LE = ('t' | 'a'<<8 | 'l'<<16 | 'e'<<24), + TAI_THAM = ('l' | 'a'<<8 | 'n'<<16 | 'a'<<24), + TAI_VIET = ('t' | 'a'<<8 | 'v'<<16 | 't'<<24), + TAKRI = ('t' | 'a'<<8 | 'k'<<16 | 'r'<<24), + TAMIL = ('t' | 'm'<<8 | 'l'<<16 | '2'<<24), + TANGSA = ('t' | 'n'<<8 | 's'<<16 | 'a'<<24), + TANGUT = ('t' | 'a'<<8 | 'n'<<16 | 'g'<<24), + TELUGU = ('t' | 'e'<<8 | 'l'<<16 | '2'<<24), + THAANA = ('t' | 'h'<<8 | 'a'<<16 | 'a'<<24), + THAI = ('t' | 'h'<<8 | 'a'<<16 | 'i'<<24), + TIBETAN = ('t' | 'i'<<8 | 'b'<<16 | 't'<<24), + TIFINAGH = ('t' | 'f'<<8 | 'n'<<16 | 'g'<<24), + TIRHUTA = ('t' | 'i'<<8 | 'r'<<16 | 'h'<<24), + TODHRI = ('t' | 'o'<<8 | 'd'<<16 | 'r'<<24), + TOTO = ('t' | 'o'<<8 | 't'<<16 | 'o'<<24), + TULU_TIGALARI = ('t' | 'u'<<8 | 't'<<16 | 'g'<<24), + UGARITIC_CUNEIFORM = ('u' | 'g'<<8 | 'a'<<16 | 'r'<<24), + VAI = ('v' | 'a'<<8 | 'i'<<16 | ' '<<24), + VITHKUQI = ('v' | 'i'<<8 | 't'<<16 | 'h'<<24), + WANCHO = ('w' | 'c'<<8 | 'h'<<16 | 'o'<<24), + WARANG_CITI = ('w' | 'a'<<8 | 'r'<<16 | 'a'<<24), + YEZIDI = ('y' | 'e'<<8 | 'z'<<16 | 'i'<<24), + YI = ('y' | 'i'<<8 | ' '<<16 | ' '<<24), + ZANABAZAR_SQUARE = ('z' | 'a'<<8 | 'n'<<16 | 'b'<<24), +} + +script :: enum u32 { + DONT_KNOW, + ADLAM, + AHOM, + ANATOLIAN_HIEROGLYPHS, + ARABIC, + ARMENIAN, + AVESTAN, + BALINESE, + BAMUM, + BASSA_VAH, + BATAK, + BENGALI, + BHAIKSUKI, + BOPOMOFO, + BRAHMI, + BUGINESE, + BUHID, + CANADIAN_SYLLABICS, + CARIAN, + CAUCASIAN_ALBANIAN, + CHAKMA, + CHAM, + CHEROKEE, + CHORASMIAN, + CJK_IDEOGRAPHIC, + COPTIC, + CYPRIOT_SYLLABARY, + CYPRO_MINOAN, + CYRILLIC, + DEFAULT, + DEFAULT2, + DESERET, + DEVANAGARI, + DIVES_AKURU, + DOGRA, + DUPLOYAN, + EGYPTIAN_HIEROGLYPHS, + ELBASAN, + ELYMAIC, + ETHIOPIC, + GARAY, + GEORGIAN, + GLAGOLITIC, + GOTHIC, + GRANTHA, + GREEK, + GUJARATI, + GUNJALA_GONDI, + GURMUKHI, + GURUNG_KHEMA, + HANGUL, + HANIFI_ROHINGYA, + HANUNOO, + HATRAN, + HEBREW, + HIRAGANA, + IMPERIAL_ARAMAIC, + INSCRIPTIONAL_PAHLAVI, + INSCRIPTIONAL_PARTHIAN, + JAVANESE, + KAITHI, + KANNADA, + KATAKANA, + KAWI, + KAYAH_LI, + KHAROSHTHI, + KHITAN_SMALL_SCRIPT, + KHMER, + KHOJKI, + KHUDAWADI, + KIRAT_RAI, + LAO, + LATIN, + LEPCHA, + LIMBU, + LINEAR_A, + LINEAR_B, + LISU, + LYCIAN, + LYDIAN, + MAHAJANI, + MAKASAR, + MALAYALAM, + MANDAIC, + MANICHAEAN, + MARCHEN, + MASARAM_GONDI, + MEDEFAIDRIN, + MEETEI_MAYEK, + MENDE_KIKAKUI, + MEROITIC_CURSIVE, + MEROITIC_HIEROGLYPHS, + MIAO, + MODI, + MONGOLIAN, + MRO, + MULTANI, + MYANMAR, + NABATAEAN, + NAG_MUNDARI, + NANDINAGARI, + NEWA, + NEW_TAI_LUE, + NKO, + NUSHU, + NYIAKENG_PUACHUE_HMONG, + OGHAM, + OL_CHIKI, + OL_ONAL, + OLD_ITALIC, + OLD_HUNGARIAN, + OLD_NORTH_ARABIAN, + OLD_PERMIC, + OLD_PERSIAN_CUNEIFORM, + OLD_SOGDIAN, + OLD_SOUTH_ARABIAN, + OLD_TURKIC, + OLD_UYGHUR, + ODIA, + OSAGE, + OSMANYA, + PAHAWH_HMONG, + PALMYRENE, + PAU_CIN_HAU, + PHAGS_PA, + PHOENICIAN, + PSALTER_PAHLAVI, + REJANG, + RUNIC, + SAMARITAN, + SAURASHTRA, + SHARADA, + SHAVIAN, + SIDDHAM, + SIGN_WRITING, + SOGDIAN, + SINHALA, + SORA_SOMPENG, + SOYOMBO, + SUMERO_AKKADIAN_CUNEIFORM, + SUNDANESE, + SUNUWAR, + SYLOTI_NAGRI, + SYRIAC, + TAGALOG, + TAGBANWA, + TAI_LE, + TAI_THAM, + TAI_VIET, + TAKRI, + TAMIL, + TANGSA, + TANGUT, + TELUGU, + THAANA, + THAI, + TIBETAN, + TIFINAGH, + TIRHUTA, + TODHRI, + TOTO, + TULU_TIGALARI, + UGARITIC_CUNEIFORM, + VAI, + VITHKUQI, + WANCHO, + WARANG_CITI, + YEZIDI, + YI, + ZANABAZAR_SQUARE, +} + +feature_tag :: enum u32 { + UNREGISTERED = 0, + isol = ('i' | 's'<<8 | 'o'<<16 | 'l'<<24), /* Isolated Forms */ + fina = ('f' | 'i'<<8 | 'n'<<16 | 'a'<<24), /* Terminal Forms */ + fin2 = ('f' | 'i'<<8 | 'n'<<16 | '2'<<24), /* Terminal Forms #2 */ + fin3 = ('f' | 'i'<<8 | 'n'<<16 | '3'<<24), /* Terminal Forms #3 */ + medi = ('m' | 'e'<<8 | 'd'<<16 | 'i'<<24), /* Medial Forms */ + med2 = ('m' | 'e'<<8 | 'd'<<16 | '2'<<24), /* Medial Forms #2 */ + init = ('i' | 'n'<<8 | 'i'<<16 | 't'<<24), /* Initial Forms */ + ljmo = ('l' | 'j'<<8 | 'm'<<16 | 'o'<<24), /* Leading Jamo Forms */ + vjmo = ('v' | 'j'<<8 | 'm'<<16 | 'o'<<24), /* Vowel Jamo Forms */ + tjmo = ('t' | 'j'<<8 | 'm'<<16 | 'o'<<24), /* Trailing Jamo Forms */ + rphf = ('r' | 'p'<<8 | 'h'<<16 | 'f'<<24), /* Reph Form */ + blwf = ('b' | 'l'<<8 | 'w'<<16 | 'f'<<24), /* Below-base Forms */ + half = ('h' | 'a'<<8 | 'l'<<16 | 'f'<<24), /* Half Forms */ + pstf = ('p' | 's'<<8 | 't'<<16 | 'f'<<24), /* Post-base Forms */ + abvf = ('a' | 'b'<<8 | 'v'<<16 | 'f'<<24), /* Above-base Forms */ + pref = ('p' | 'r'<<8 | 'e'<<16 | 'f'<<24), /* Pre-base Forms */ + numr = ('n' | 'u'<<8 | 'm'<<16 | 'r'<<24), /* Numerators */ + frac = ('f' | 'r'<<8 | 'a'<<16 | 'c'<<24), /* Fractions */ + dnom = ('d' | 'n'<<8 | 'o'<<16 | 'm'<<24), /* Denominators */ + cfar = ('c' | 'f'<<8 | 'a'<<16 | 'r'<<24), /* Conjunct Form After Ro */ + aalt = ('a' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Access All Alternates */ + abvm = ('a' | 'b'<<8 | 'v'<<16 | 'm'<<24), /* Above-base Mark Positioning */ + abvs = ('a' | 'b'<<8 | 'v'<<16 | 's'<<24), /* Above-base Substitutions */ + afrc = ('a' | 'f'<<8 | 'r'<<16 | 'c'<<24), /* Alternative Fractions */ + akhn = ('a' | 'k'<<8 | 'h'<<16 | 'n'<<24), /* Akhand */ + apkn = ('a' | 'p'<<8 | 'k'<<16 | 'n'<<24), /* Kerning for Alternate Proportional Widths */ + blwm = ('b' | 'l'<<8 | 'w'<<16 | 'm'<<24), /* Below-base Mark Positioning */ + blws = ('b' | 'l'<<8 | 'w'<<16 | 's'<<24), /* Below-base Substitutions */ + calt = ('c' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Contextual Alternates */ + Case = ('c' | 'a'<<8 | 's'<<16 | 'e'<<24), /* Case-sensitive Forms */ + ccmp = ('c' | 'c'<<8 | 'm'<<16 | 'p'<<24), /* Glyph Composition / Decomposition */ + chws = ('c' | 'h'<<8 | 'w'<<16 | 's'<<24), /* Contextual Half-width Spacing */ + cjct = ('c' | 'j'<<8 | 'c'<<16 | 't'<<24), /* Conjunct Forms */ + clig = ('c' | 'l'<<8 | 'i'<<16 | 'g'<<24), /* Contextual Ligatures */ + cpct = ('c' | 'p'<<8 | 'c'<<16 | 't'<<24), /* Centered CJK Punctuation */ + cpsp = ('c' | 'p'<<8 | 's'<<16 | 'p'<<24), /* Capital Spacing */ + cswh = ('c' | 's'<<8 | 'w'<<16 | 'h'<<24), /* Contextual Swash */ + curs = ('c' | 'u'<<8 | 'r'<<16 | 's'<<24), /* Cursive Positioning */ + cv01 = ('c' | 'v'<<8 | '0'<<16 | '1'<<24), /* 'cv99' Character Variant 1 – Character Variant 99 */ + c2pc = ('c' | '2'<<8 | 'p'<<16 | 'c'<<24), /* Petite Capitals From Capitals */ + c2sc = ('c' | '2'<<8 | 's'<<16 | 'c'<<24), /* Small Capitals From Capitals */ + dist = ('d' | 'i'<<8 | 's'<<16 | 't'<<24), /* Distances */ + dlig = ('d' | 'l'<<8 | 'i'<<16 | 'g'<<24), /* Discretionary Ligatures */ + dtls = ('d' | 't'<<8 | 'l'<<16 | 's'<<24), /* Dotless Forms */ + expt = ('e' | 'x'<<8 | 'p'<<16 | 't'<<24), /* Expert Forms */ + falt = ('f' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Final Glyph on Line Alternates */ + flac = ('f' | 'l'<<8 | 'a'<<16 | 'c'<<24), /* Flattened Accent Forms */ + fwid = ('f' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Full Widths */ + haln = ('h' | 'a'<<8 | 'l'<<16 | 'n'<<24), /* Halant Forms */ + halt = ('h' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Alternate Half Widths */ + hist = ('h' | 'i'<<8 | 's'<<16 | 't'<<24), /* Historical Forms */ + hkna = ('h' | 'k'<<8 | 'n'<<16 | 'a'<<24), /* Horizontal Kana Alternates */ + hlig = ('h' | 'l'<<8 | 'i'<<16 | 'g'<<24), /* Historical Ligatures */ + hngl = ('h' | 'n'<<8 | 'g'<<16 | 'l'<<24), /* Hangul */ + hojo = ('h' | 'o'<<8 | 'j'<<16 | 'o'<<24), /* Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms) */ + hwid = ('h' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Half Widths */ + ital = ('i' | 't'<<8 | 'a'<<16 | 'l'<<24), /* Italics */ + jalt = ('j' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Justification Alternates */ + jp78 = ('j' | 'p'<<8 | '7'<<16 | '8'<<24), /* JIS78 Forms */ + jp83 = ('j' | 'p'<<8 | '8'<<16 | '3'<<24), /* JIS83 Forms */ + jp90 = ('j' | 'p'<<8 | '9'<<16 | '0'<<24), /* JIS90 Forms */ + jp04 = ('j' | 'p'<<8 | '0'<<16 | '4'<<24), /* JIS2004 Forms */ + kern = ('k' | 'e'<<8 | 'r'<<16 | 'n'<<24), /* Kerning */ + lfbd = ('l' | 'f'<<8 | 'b'<<16 | 'd'<<24), /* Left Bounds */ + liga = ('l' | 'i'<<8 | 'g'<<16 | 'a'<<24), /* Standard Ligatures */ + lnum = ('l' | 'n'<<8 | 'u'<<16 | 'm'<<24), /* Lining Figures */ + locl = ('l' | 'o'<<8 | 'c'<<16 | 'l'<<24), /* Localized Forms */ + ltra = ('l' | 't'<<8 | 'r'<<16 | 'a'<<24), /* Left-to-right Alternates */ + ltrm = ('l' | 't'<<8 | 'r'<<16 | 'm'<<24), /* Left-to-right Mirrored Forms */ + mark = ('m' | 'a'<<8 | 'r'<<16 | 'k'<<24), /* Mark Positioning */ + mgrk = ('m' | 'g'<<8 | 'r'<<16 | 'k'<<24), /* Mathematical Greek */ + mkmk = ('m' | 'k'<<8 | 'm'<<16 | 'k'<<24), /* Mark to Mark Positioning */ + mset = ('m' | 's'<<8 | 'e'<<16 | 't'<<24), /* Mark Positioning via Substitution */ + nalt = ('n' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Alternate Annotation Forms */ + nlck = ('n' | 'l'<<8 | 'c'<<16 | 'k'<<24), /* NLC Kanji Forms */ + nukt = ('n' | 'u'<<8 | 'k'<<16 | 't'<<24), /* Nukta Forms */ + onum = ('o' | 'n'<<8 | 'u'<<16 | 'm'<<24), /* Oldstyle Figures */ + opbd = ('o' | 'p'<<8 | 'b'<<16 | 'd'<<24), /* Optical Bounds */ + ordn = ('o' | 'r'<<8 | 'd'<<16 | 'n'<<24), /* Ordinals */ + ornm = ('o' | 'r'<<8 | 'n'<<16 | 'm'<<24), /* Ornaments */ + palt = ('p' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Proportional Alternate Widths */ + pcap = ('p' | 'c'<<8 | 'a'<<16 | 'p'<<24), /* Petite Capitals */ + pkna = ('p' | 'k'<<8 | 'n'<<16 | 'a'<<24), /* Proportional Kana */ + pnum = ('p' | 'n'<<8 | 'u'<<16 | 'm'<<24), /* Proportional Figures */ + pres = ('p' | 'r'<<8 | 'e'<<16 | 's'<<24), /* Pre-base Substitutions */ + psts = ('p' | 's'<<8 | 't'<<16 | 's'<<24), /* Post-base Substitutions */ + pwid = ('p' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Proportional Widths */ + qwid = ('q' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Quarter Widths */ + rand = ('r' | 'a'<<8 | 'n'<<16 | 'd'<<24), /* Randomize */ + rclt = ('r' | 'c'<<8 | 'l'<<16 | 't'<<24), /* Required Contextual Alternates */ + rkrf = ('r' | 'k'<<8 | 'r'<<16 | 'f'<<24), /* Rakar Forms */ + rlig = ('r' | 'l'<<8 | 'i'<<16 | 'g'<<24), /* Required Ligatures */ + rtbd = ('r' | 't'<<8 | 'b'<<16 | 'd'<<24), /* Right Bounds */ + rtla = ('r' | 't'<<8 | 'l'<<16 | 'a'<<24), /* Right-to-left Alternates */ + rtlm = ('r' | 't'<<8 | 'l'<<16 | 'm'<<24), /* Right-to-left Mirrored Forms */ + ruby = ('r' | 'u'<<8 | 'b'<<16 | 'y'<<24), /* Ruby Notation Forms */ + rvrn = ('r' | 'v'<<8 | 'r'<<16 | 'n'<<24), /* Required Variation Alternates */ + salt = ('s' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Stylistic Alternates */ + sinf = ('s' | 'i'<<8 | 'n'<<16 | 'f'<<24), /* Scientific Inferiors */ + size = ('s' | 'i'<<8 | 'z'<<16 | 'e'<<24), /* Optical size */ + smcp = ('s' | 'm'<<8 | 'c'<<16 | 'p'<<24), /* Small Capitals */ + smpl = ('s' | 'm'<<8 | 'p'<<16 | 'l'<<24), /* Simplified Forms */ + ss01 = ('s' | 's'<<8 | '0'<<16 | '1'<<24), /* 'ss20' Stylistic Set 1 – Stylistic Set 20 */ + ssty = ('s' | 's'<<8 | 't'<<16 | 'y'<<24), /* Math Script-style Alternates */ + stch = ('s' | 't'<<8 | 'c'<<16 | 'h'<<24), /* Stretching Glyph Decomposition */ + subs = ('s' | 'u'<<8 | 'b'<<16 | 's'<<24), /* Subscript */ + sups = ('s' | 'u'<<8 | 'p'<<16 | 's'<<24), /* Superscript */ + swsh = ('s' | 'w'<<8 | 's'<<16 | 'h'<<24), /* Swash */ + test = ('t' | 'e'<<8 | 's'<<16 | 't'<<24), /* Test features, only for development */ + titl = ('t' | 'i'<<8 | 't'<<16 | 'l'<<24), /* Titling */ + tnam = ('t' | 'n'<<8 | 'a'<<16 | 'm'<<24), /* Traditional Name Forms */ + tnum = ('t' | 'n'<<8 | 'u'<<16 | 'm'<<24), /* Tabular Figures */ + trad = ('t' | 'r'<<8 | 'a'<<16 | 'd'<<24), /* Traditional Forms */ + twid = ('t' | 'w'<<8 | 'i'<<16 | 'd'<<24), /* Third Widths */ + unic = ('u' | 'n'<<8 | 'i'<<16 | 'c'<<24), /* Unicase */ + valt = ('v' | 'a'<<8 | 'l'<<16 | 't'<<24), /* Alternate Vertical Metrics */ + vapk = ('v' | 'a'<<8 | 'p'<<16 | 'k'<<24), /* Kerning for Alternate Proportional Vertical Metrics */ + vatu = ('v' | 'a'<<8 | 't'<<16 | 'u'<<24), /* Vattu Variants */ + vchw = ('v' | 'c'<<8 | 'h'<<16 | 'w'<<24), /* Vertical Contextual Half-width Spacing */ + vert = ('v' | 'e'<<8 | 'r'<<16 | 't'<<24), /* Vertical Alternates */ + vhal = ('v' | 'h'<<8 | 'a'<<16 | 'l'<<24), /* Alternate Vertical Half Metrics */ + vkna = ('v' | 'k'<<8 | 'n'<<16 | 'a'<<24), /* Vertical Kana Alternates */ + vkrn = ('v' | 'k'<<8 | 'r'<<16 | 'n'<<24), /* Vertical Kerning */ + vpal = ('v' | 'p'<<8 | 'a'<<16 | 'l'<<24), /* Proportional Alternate Vertical Metrics */ + vrt2 = ('v' | 'r'<<8 | 't'<<16 | '2'<<24), /* Vertical Alternates and Rotation */ + vrtr = ('v' | 'r'<<8 | 't'<<16 | 'r'<<24), /* Vertical Alternates for Rotation */ + zero = ('z' | 'e'<<8 | 'r'<<16 | 'o'<<24), /* Slashed Zero */ +} + +feature_id :: enum u32 { + UNREGISTERED = 0, + isol, /* Isolated Forms */ + fina, /* Terminal Forms */ + fin2, /* Terminal Forms #2 */ + fin3, /* Terminal Forms #3 */ + medi, /* Medial Forms */ + med2, /* Medial Forms #2 */ + init, /* Initial Forms */ + ljmo, /* Leading Jamo Forms */ + vjmo, /* Vowel Jamo Forms */ + tjmo, /* Trailing Jamo Forms */ + rphf, /* Reph Form */ + blwf, /* Below-base Forms */ + half, /* Half Forms */ + pstf, /* Post-base Forms */ + abvf, /* Above-base Forms */ + pref, /* Pre-base Forms */ + numr, /* Numerators */ + frac, /* Fractions */ + dnom, /* Denominators */ + cfar, /* Conjunct Form After Ro */ + aalt, /* Access All Alternates */ + abvm, /* Above-base Mark Positioning */ + abvs, /* Above-base Substitutions */ + afrc, /* Alternative Fractions */ + akhn, /* Akhand */ + apkn, /* Kerning for Alternate Proportional Widths */ + blwm, /* Below-base Mark Positioning */ + blws, /* Below-base Substitutions */ + calt, /* Contextual Alternates */ + Case, /* Case-sensitive Forms */ + ccmp, /* Glyph Composition / Decomposition */ + chws, /* Contextual Half-width Spacing */ + cjct, /* Conjunct Forms */ + clig, /* Contextual Ligatures */ + cpct, /* Centered CJK Punctuation */ + cpsp, /* Capital Spacing */ + cswh, /* Contextual Swash */ + curs, /* Cursive Positioning */ + cv01, /* 'cv99' Character Variant 1 – Character Variant 99 */ + c2pc, /* Petite Capitals From Capitals */ + c2sc, /* Small Capitals From Capitals */ + dist, /* Distances */ + dlig, /* Discretionary Ligatures */ + dtls, /* Dotless Forms */ + expt, /* Expert Forms */ + falt, /* Final Glyph on Line Alternates */ + flac, /* Flattened Accent Forms */ + fwid, /* Full Widths */ + haln, /* Halant Forms */ + halt, /* Alternate Half Widths */ + hist, /* Historical Forms */ + hkna, /* Horizontal Kana Alternates */ + hlig, /* Historical Ligatures */ + hngl, /* Hangul */ + hojo, /* Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms) */ + hwid, /* Half Widths */ + ital, /* Italics */ + jalt, /* Justification Alternates */ + jp78, /* JIS78 Forms */ + jp83, /* JIS83 Forms */ + jp90, /* JIS90 Forms */ + jp04, /* JIS2004 Forms */ + kern, /* Kerning */ + lfbd, /* Left Bounds */ + liga, /* Standard Ligatures */ + lnum, /* Lining Figures */ + locl, /* Localized Forms */ + ltra, /* Left-to-right Alternates */ + ltrm, /* Left-to-right Mirrored Forms */ + mark, /* Mark Positioning */ + mgrk, /* Mathematical Greek */ + mkmk, /* Mark to Mark Positioning */ + mset, /* Mark Positioning via Substitution */ + nalt, /* Alternate Annotation Forms */ + nlck, /* NLC Kanji Forms */ + nukt, /* Nukta Forms */ + onum, /* Oldstyle Figures */ + opbd, /* Optical Bounds */ + ordn, /* Ordinals */ + ornm, /* Ornaments */ + palt, /* Proportional Alternate Widths */ + pcap, /* Petite Capitals */ + pkna, /* Proportional Kana */ + pnum, /* Proportional Figures */ + pres, /* Pre-base Substitutions */ + psts, /* Post-base Substitutions */ + pwid, /* Proportional Widths */ + qwid, /* Quarter Widths */ + rand, /* Randomize */ + rclt, /* Required Contextual Alternates */ + rkrf, /* Rakar Forms */ + rlig, /* Required Ligatures */ + rtbd, /* Right Bounds */ + rtla, /* Right-to-left Alternates */ + rtlm, /* Right-to-left Mirrored Forms */ + ruby, /* Ruby Notation Forms */ + rvrn, /* Required Variation Alternates */ + salt, /* Stylistic Alternates */ + sinf, /* Scientific Inferiors */ + size, /* Optical size */ + smcp, /* Small Capitals */ + smpl, /* Simplified Forms */ + ss01, /* 'ss20' Stylistic Set 1 – Stylistic Set 20 */ + ssty, /* Math Script-style Alternates */ + stch, /* Stretching Glyph Decomposition */ + subs, /* Subscript */ + sups, /* Superscript */ + swsh, /* Swash */ + test, /* Test features, only for development */ + titl, /* Titling */ + tnam, /* Traditional Name Forms */ + tnum, /* Tabular Figures */ + trad, /* Traditional Forms */ + twid, /* Third Widths */ + unic, /* Unicase */ + valt, /* Alternate Vertical Metrics */ + vapk, /* Kerning for Alternate Proportional Vertical Metrics */ + vatu, /* Vattu Variants */ + vchw, /* Vertical Contextual Half-width Spacing */ + vert, /* Vertical Alternates */ + vhal, /* Alternate Vertical Half Metrics */ + vkna, /* Vertical Kana Alternates */ + vkrn, /* Vertical Kerning */ + vpal, /* Proportional Alternate Vertical Metrics */ + vrt2, /* Vertical Alternates and Rotation */ + vrtr, /* Vertical Alternates for Rotation */ + zero, /* Slashed Zero */ +} + + +shaping_table :: enum u8 { + GSUB, + GPOS, +} + +lookup_info :: struct { + MaximumBacktrackWithoutSkippingGlyphs: u32, + MaximumLookaheadWithoutSkippingGlyphs: u32, + MaximumSubstitutionOutputSize: u32, + MaximumInputSequenceLength: u32, + MaximumLookupStackSize: u32, +} + +gdef :: struct {} +cmap_14 :: struct {} +gsub_gpos :: struct {} +maxp :: struct {} +hea :: struct {} +iterate_features :: struct {} +shaper_properties :: struct {} +feature :: struct {} +head :: struct {} + +lookup_subtable_info :: struct { + MinimumBacktrackPlusOne: u32, + MinimumFollowupPlusOne: u32, +} + +font :: struct { + FileBase: [^]byte, + FileSize: un, + Head: ^head, + Cmap: ^u16, + Gdef: ^gdef, + Cmap14: ^cmap_14, + ShapingTables: [shaping_table]^gsub_gpos, + Fvar: rawptr, + Maxp: ^maxp, + + Hea: [orientation]^hea, + Mtx: [orientation]^u16, + + LookupInfo: lookup_info, + + GlyphCount: u32, + LookupCount: u32, + SubtableCount: u32, + + GlyphLookupMatrix: [^]u32, // [LookupCount * GlyphCount] bitmap + GlyphLookupSubtableMatrix: [^]u32, // [LookupSubtableCount * GlyphCount] bitmap + LookupSubtableIndexOffsets: [^]u32, // [LookupCount] + SubtableInfos: [^]lookup_subtable_info, // [LookupSubtableCount] + + GposLookupIndexOffset: u32, + + Error: c.int, +} + +glyph_classes :: struct { + Class: u16, + MarkAttachmentClass: u16, +} + +glyph_config :: struct { + EnabledFeatures: feature_set, + DisabledFeatures: feature_set, + FeatureOverrideCount: u32, + FeatureOverrideCapacity: u32, + RequiredFeatureOverrideCapacity: u32, + FeatureOverrides: [^]feature_override `fmt:"v,FeatureOverrideCount"`, +} + +glyph :: struct { + Codepoint: rune, + Id: u16, // Glyph index. This is what you want to use to query outline data. + Uid: u16, + Classes: glyph_classes, + + Decomposition: u64, + + Config: ^glyph_config, + + Flags: glyph_flags, + + // These fields are the glyph's final positioning data. + // For normal usage, you should not have to use these directly yourself. + // In case you are curious or have a specific need, see kbts_PositionGlyph() to see how these are used. + OffsetX: i32, + OffsetY: i32, + AdvanceX: i32, + AdvanceY: i32, + + ParentInfo: u32, + + // This is set by GSUB and used by GPOS. + // A 0-index means that we should attach to the last component in the ligature. + // + // From the Microsoft docs: + // To correctly access the subtables, the client must keep track of the component associated with the mark. + // + // For a given mark assigned to a particular class, the appropriate base attachment point is determined by which + // ligature component the mark is associated with. This is dependent on the original character string and subsequent + // character- or glyph-sequence processing, not the font data alone. While a text-layout client is performing any + // character-based preprocessing or any glyph-substitution operations using the GSUB table, the text-layout client + // must keep track of associations of marks to particular ligature-glyph components. + LigatureUid: u16, + LigatureComponentIndexPlusOne: u16, + + // Earlier on, we used to assume that, if a glyph had no advance, or had the MARK glyph class, then + // it could be handled as a mark in layout operations. This is inaccurate. + // Unicode makes a distinction between attached marks and standalone marks. For our purposes, attached + // marks are marks that have found a valid base character to attach to. In practice, this means that the + // font contains a valid display position/configuration for it in the current context. + // In contrast, standalone marks are marks that aren't attached to anything. Fonts may still have glyphs + // for them, in which case we want to display those just like regular glyphs that take up horizontal space + // on the line. When fonts don't have glyphs for them, they simply stay around as zero-width glyphs. + // Standalone marks have notably different behavior compared to attached marks, and so, once we start + // applying positioning features, it becomes worthwhile to track exactly which glyph has attached to which. + AttachGlyphIndexPlusOne: u16, // Set by GPOS attachments. + + // Set in GSUB and used in GPOS, for STCH. + JoiningFeature: joining_feature, + + // Unicode properties filled in by CodepointToGlyph. + JoiningType: unicode_joining_type, + using ScriptBitField: bit_field u8 { + Script: script | 8, + }, + UnicodeFlags: unicode_flags, + SyllabicClass: u8, + SyllabicPosition: u8, + UseClass: u8, + CombiningClass: u8, + + MarkOrdering: u8, // Only used temporarily in NORMALIZE for Arabic mark reordering. +} + +glyph_array :: struct { + Glyphs: [^]glyph `fmt:"v,Count"`, + Count: u32, + TotalCount: u32, + Capacity: u32, + RequiredCapacity: u32, +} + +op_state_normalize :: struct { + CodepointsToDecomposeCount: un, + AboveBaseGlyphCount: un, +} + + +skip_flags :: distinct bit_set[skip_flag; u32] +skip_flag :: enum u32 { + ZWNJ = 0, + ZWJ = 1, +} + +op_state_gsub :: struct { + LookupFeatures: feature_set, + LookupIndex: un, + GlyphFilter: glyph_flags, + SkipFlags: skip_flags, +} + +op_state_normalize_hangul :: struct { + LvtGlyphs: [4]glyph `fmt:"v,LvtGlyphCount"`, + LvtGlyphCount: un, +} + +op_state_op_specific :: struct #raw_union { + Normalize: op_state_normalize, + Gsub: op_state_gsub, + NormalizeHangul: op_state_normalize_hangul, +} + +lookup_indices :: struct { + FeatureTag: feature_tag, + FeatureId: feature_id, + SkipFlags: skip_flags, + GlyphFilter: glyph_flags, + Count: u32, + Indices: [^]u16 `fmt:"v,Count"`, +} + +feature_set :: struct { + Flags: [(uint(len(feature_id)) + 63) / 64]u64, +} + +feature_override :: struct { + Id: feature_id, + Tag: feature_tag, + EnabledOrAlternatePlusOne: u32, +} + +op :: struct { + Kind: op_kind, + Features: feature_set, +} + +// This needs to be updated when we change the op lists! +MAX_SIMULTANEOUS_FEATURES :: 16 +op_state :: struct { + WrittenCount: un, + GlyphIndex: un, + FrameCount: u32, + ResumePoint: u32, + + FeatureCount: u32, + FeatureLookupIndices: [MAX_SIMULTANEOUS_FEATURES]lookup_indices `fmt:"v,FeatureCount"`, + + UnregisteredFeatureCount: u32, + UnregisteredFeatureTags: [MAX_SIMULTANEOUS_FEATURES]feature_tag `fmt:"v,UnregisteredFeatureCount"`, + + OpSpecific: op_state_op_specific, + + // Ops are free to use the following as they please: + // LeftoverMemory: [LeftoverMemorySize]u8, +} + +op_list :: struct { // TODO(bill): is this actually a slice? e.g. `op_list :: []op_kind` + Ops: [^]op_kind, + Length: un, +} + +indic_script_properties :: struct { + ViramaCodepoint: rune, + BlwfPostOnly: bool, // b8 + RephPosition: reph_position, + RephEncoding: reph_encoding, + RightSideMatraPosition: syllabic_position, + AboveBaseMatraPosition: syllabic_position, + BelowBaseMatraPosition: syllabic_position, +} + +langsys :: struct {} + +shape_config :: struct { + Font: ^font, + Script: script, + Language: language, + Langsys: [shaping_table]^langsys, + OpLists: [4]op_list, + + Features: ^feature_set, + + Shaper: shaper, + ShaperProperties: ^shaper_properties, + + IndicScriptProperties: indic_script_properties, + Blwf: ^feature, + Pref: ^feature, + Pstf: ^feature, + Locl: ^feature, + Rphf: ^feature, + Half: ^feature, + Vatu: ^feature, + + // Indic + Virama: glyph, + + DottedCircle: glyph, + Whitespace: glyph, + + // Thai + Nikhahit: glyph, + SaraAa: glyph, +} + +shape_state :: struct { + Op: op, + Config: ^shape_config, + MainDirection: direction, + RunDirection: direction, + + UserFeatures: feature_set, + + GlyphArray: glyph_array, + ClusterGlyphArray: glyph_array, + + DottedCircleInsertIndex: u32, + + GlyphCountStartingFromCurrentCluster: u32, + + At: u32, + ResumePoint: u32, + OpGlyphOffset: u32, + ClusterGlyphCount: u32, + Ip: u32, + NextGlyphUid: u32, + + RequiredGlyphCapacity: u32, + + RealCluster: c.int, + ClusterAtStartOfWord: c.int, + WordBreak: c.int, + + // This must always be the last member! + OpState: op_state, +} + +cursor :: struct { + Direction: direction, + LastAdvanceX: i32, + X: i32, + Y: i32, +} + +break_type :: struct { + // The break code mostly works in relative positions, but we convert to absolute positions for the user. + // That way, breaks can be trivially stored and compared and such and it just works. + Position: u32, + Flags: break_flags, + Direction: direction, // Only valid if (Flags & BREAK_FLAG_DIRECTION). + Script: script, // Only valid if (Flags & BREAK_FLAG_SCRIPT). +} + +bracket :: struct { + Codepoint: rune, + using DirectionBitField: bit_field u8 { + Direction: direction | 8, + }, + using ScriptBitField: bit_field u8 { + Script: script | 8, + }, +} + +break_state_flags :: distinct bit_set[break_state_flag; u32] +break_state_flag :: enum u32 { + STARTED = 0, + END = 1, + RAN_OUT_OF_REORDER_BUFFER_SPACE = 2, + + // Bidirectional flags + SAW_R_AFTER_L = 3, + SAW_AL_AFTER_LR = 4, + LAST_WAS_BRACKET = 5, +} + +// In the worst case, a single call to BreakAddCodepoint would generate 4 breaks. +// We buffer breaks to reorder them before returning them to the user. +// This potentially requires infinite memory, which we don't have, so you may want to tweak this constant, +// although, really, if the defaults don't work, then you have likely found very strange/adversarial text. +BREAK_REORDER_BUFFER_FLUSH_THRESHOLD :: 4 +BREAK_REORDER_BUFFER_SIZE :: BREAK_REORDER_BUFFER_FLUSH_THRESHOLD * 2 +break_state :: struct { + Breaks: [BREAK_REORDER_BUFFER_SIZE]break_type `fmt:"v,Breaks"`, + BreakCount: u32, + MainDirection: direction, + + LastFlushedBreakPosition: u32, + CurrentPosition: u32, + + LastScripts: [2]u8, + + Brackets: [64]bracket `fmt:"v,BracketCount"`, + BracketCount: u32, + Flags: break_state_flags, + + FlagState: bit_field u32 { + _0: u32 | 8, // break_flags + _1: u32 | 8, // break_flags + _2: u32 | 8, // break_flags + _3: u32 | 8, // break_flags + }, + PositionOffset2: i16, + PositionOffset3: i16, + + WordBreakHistory: bit_field u32 { + _0: u32 | 8, + _1: u32 | 8, + _2: u32 | 8, + _3: u32 | 8, + }, + WordBreaks, + WordUnbreaks: bit_field u16 { + _0: u16 | 4, + _1: u16 | 4, + _2: u16 | 4, + _3: u16 | 4, + }, + WordBreak2PositionOffset: i16, + + LineBreaks: bit_field u64 { + _0: u64 | 16, + _1: u64 | 16, + _2: u64 | 16, + _3: u64 | 16, + }, + // Instead of staying synchronized with LineBreaks/LineUnbreaks, + // this advances every character always. + // (This is only needed because ZWJ can create an unbreak while simultaneously being ignored.) + LineUnbreaksAsync, + LineUnbreaks: bit_field u64 { + _0: u64 | 16, + _1: u64 | 16, + _2: u64 | 16, + _3: u64 | 16, + }, + LineBreakHistory: bit_field u32 { + _0: u32 | 8, // break_flags + _1: u32 | 8, // break_flags + _2: u32 | 8, // break_flags + _3: u32 | 8, // break_flags + }, + LineBreak2PositionOffset: i16, + LineBreak3PositionOffset: i16, + + using LastDirectionBitField: bit_field u8 { + LastDirection: direction | 8, + }, + BidirectionalClass2: unicode_bidirectional_class, + BidirectionalClass1: unicode_bidirectional_class, + + JapaneseLineBreakStyle: japanese_line_break_style, + GraphemeBreakState: u8, + LastLineBreakClass: line_break_class, + LastWordBreakClass: word_break_class, + LastWordBreakClassIncludingIgnored: word_break_class, +} diff --git a/vendor/kb_text_shape/lib/kb_text_shape.lib b/vendor/kb_text_shape/lib/kb_text_shape.lib new file mode 100644 index 000000000..1c3b94779 Binary files /dev/null and b/vendor/kb_text_shape/lib/kb_text_shape.lib differ diff --git a/vendor/kb_text_shape/src/LICENSE b/vendor/kb_text_shape/src/LICENSE new file mode 100644 index 000000000..cad70fa11 --- /dev/null +++ b/vendor/kb_text_shape/src/LICENSE @@ -0,0 +1,19 @@ +zlib License + +(C) Copyright 2024-2025 Jimmy Lefevre + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. \ No newline at end of file diff --git a/vendor/kb_text_shape/src/build.bat b/vendor/kb_text_shape/src/build.bat new file mode 100644 index 000000000..b37b219e7 --- /dev/null +++ b/vendor/kb_text_shape/src/build.bat @@ -0,0 +1,8 @@ +@echo off + +if not exist "..\lib" mkdir ..\lib + +cl -nologo -MT -TC -O2 -c kb_text_shape.c +lib -nologo kb_text_shape.obj -out:..\lib\kb_text_shape.lib + +del *.obj diff --git a/vendor/kb_text_shape/src/build_unix.sh b/vendor/kb_text_shape/src/build_unix.sh new file mode 100755 index 000000000..159aecb52 --- /dev/null +++ b/vendor/kb_text_shape/src/build_unix.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -e + +mkdir -p "../lib" +cc -O2 -c kb_text_shape.c +ar -rcs ../lib/kb_text_shape.a kb_text_shape.o +rm *.o diff --git a/vendor/kb_text_shape/src/kb_text_shape.c b/vendor/kb_text_shape/src/kb_text_shape.c new file mode 100644 index 000000000..613669eca --- /dev/null +++ b/vendor/kb_text_shape/src/kb_text_shape.c @@ -0,0 +1,8 @@ +#include +#ifndef _MSC_VER + #include +#endif + +#define KB_TEXT_SHAPE_NO_CRT +#define KB_TEXT_SHAPE_IMPLEMENTATION +#include "kb_text_shape.h" \ No newline at end of file diff --git a/vendor/kb_text_shape/src/kb_text_shape.h b/vendor/kb_text_shape/src/kb_text_shape.h new file mode 100644 index 000000000..57d3ca7a0 --- /dev/null +++ b/vendor/kb_text_shape/src/kb_text_shape.h @@ -0,0 +1,23984 @@ +/* kb_text_shape - v1.03 - text segmentation and shaping + by Jimmy Lefevre + + SECURITY + This library provides NO SECURITY GUARANTEE whatsoever. + DO NOT use it on untrusted font files. + + FEATURE OVERVIEW + This library provides: + - Unicode segmentation + LTR/RTL breaking + Script breaking + Line breaking + Word breaking + Grapheme breaking + - OpenType text shaping + Open and parse TTF and OTF fonts + Extract glyph information + Apply OpenType features such as ligatures and contextual typographic rules + All OpenType shapers are supported, which means most languages in the world are supported + (see LANGUAGE_SUPPORT for known non-supported cases) + + COMPILING & LINKING + This library uses declare-anywhere, so it will not compile as C89/VC6 C. + In one C/C++ file that #includes this file, do this: + #define KB_TEXT_SHAPE_IMPLEMENTATION + before the #include. That will create the implementation in that file. + If you also do this: + #define KB_TEXT_SHAPE_STATIC + then all functions will be declared as static. + If you do this: + #define KB_TEXT_SHAPE_NO_CRT + then we do not use the C runtime library. These functions are compiled out: + kbts_CreateShapeState() + kbts_FreeShapeState() + kbts_FontFromFile() + kbts_FreeFont() + Additionally, we call KBTS_MEMSET(), which defaults to memset(), including outside of NO_CRT code. + If you want to redirect it to your own function, you can do this: + #define KBTS_MEMSET my_awesome_memset + + API + Segmentation + kbts_BeginBreak() + kbts_BreakAddCodepoint() -- Feed a codepoint to the breaker. + You need to call Break() repeatedly after every call to BreakAddCodepoint(). + Something like: + kbts_BreakAddCodepoint(&BreakState, ...); + kbts_break Break; + while(kbts_Break(&BreakState, &Break)) {...} + + When you call Break(), We guarantee that breaks are returned in-order. On our side, this means + that they are buffered and reordered. On your side, it means that there is a delay of a few + characters between your current position and the Break.Position that you will see. + + In some cases, our buffering might break. When that happens, we set + BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE, and kbts_BreakStateIsValid() will return false. + This is a sticky error, so you can check it whenever you like. + To clear the error flag and start segmenting again, you will need to call BeginBreak(&BreakState), + which resets the entire state. + + Note that the input configurations for which our buffering breaks should be, for all intents and + purposes, nonsensical. If you find legitimate text that we cannot segment without running out of + buffer space, then that is a bug. + + The default buffer size is determined by the BREAK_REORDER_BUFFER_FLUSH_THRESHOLD. If you really + need a bigger buffer, then you might want to consider modifying this constant and recompiling + the library, although this should be viewed as an emergency solution and not a routine + configuration option. + kbts_BreakFlush() + kbts_Break() -- Call repeatedly to get breaks + kbts_BreakStateIsValid() + Easy font loading + kbts_FontFromFile() -- Open a font, byteswap it in place, and allocate auxiliary structures. + When you read a font with kb_text_shape, the library will byteswap its data in-place and perform + a bunch of other pre-computation passes to figure out memory limits and other useful information. + This means you cannot trivially pass our pointer to the font data to any other TTF library, since + they will expect the data to be in big endian format, which it won't be after we are done with it. + + You can expect font reading to be pretty slow. + On the other hand, you can expect shaping to be pretty fast. + + To open a font with your own IO and memory allocation, see "Manual Memory Management" below. + kbts_FreeFont() + kbts_FontIsValid() + Shaping + kbts_CreateShapeState() + kbts_FreeShapeState() + kbts_ShapeConfig() -- Bake a font/script-specific shaping configuration + kbts_CodepointToGlyph() + kbts_InferScript() -- Hacky script recognition for when no segmentation data is available + kbts_Shape() -- Returns 1 if more memory is needed, you should probably call this in a while(). + This is how you might call this in practice: + while(kbts_Shape(State, &Config, Direction, Direction, Glyphs, &GlyphCount, GlyphCapacity)) + { + Glyphs = realloc(Glyphs, sizeof(kbts_glyph) * State->RequiredGlyphCapacity); + GlyphCapacity = State->RequiredGlyphCapacity; + } + Once Shape() returns 0, you are done shaping. Glyph indices are in the kbts_glyph.Id field. + Please note that, while the glyphs do also contain a Codepoint field, this field will mostly + be meaningless whenever complex shaping operations occur. This is because fonts exclusively + work on glyph indices, and a lot of ligatures are obviously a combination of several codepoints + and do not have a corresponding codepoint in the Unicode world. + The same is true when a single glyph is split into multiple glyphs. A font might decide to + decompose a letter-with-accent into a letter glyph + an accent glyph. In that case, we will + know what the accent glyph's index is, but we are not told what its codepoint is. + + There is currently no way to track where in the source text each glyph originates from. + One thing we might try is to have a "void *UserData" member on each glyph, and flow it through + the different substitutions, but I personally have not needed this yet and I do not have good + test cases for it. If you are interested, let me know! + + Final positions are in font units and can be extracted with Cursor() and PositionGlyph(). + To convert font units to fractional pixels in FreeType: + (FontX * FtSizeMetrics.x_scale) >> 16 + (FontY * FtSizeMetrics.y_scale) >> 16 + This will give you 26.6 fractional pixel units. + See https://freetype.org/freetype2/docs/reference/ft2-sizing_and_scaling.html for more info. + kbts_ResetShapeState() + Shaping - feature control + kbts_FeatureOverride() -- Describe a manual override for a font feature + kbts_FeatureOverrideFromTag() -- This also works on features that do not have a kbts_feature_id, but they will be slower. + (Calling this with a feature that has a kbts_feature_id will not be slower.) + kbts_GlyphConfig() -- Bake per-glyph parameters (for now, only feature overrides) + Shaping - feature control - incremental API + With this API, you provide a buffer first, and gradually construct the glyph_config. + kbts_EmptyGlyphConfig() + kbts_GlyphConfigOverrideFeature() + kbts_GlyphConfigOverrideFeatureFromTag() + Layout + kbts_Cursor() + kbts_PositionGlyph() + Manual memory management + kbts_SizeOfShapeState() + kbts_PlaceShapeState() + kbts_ReadFontHeader() -- Read and byteswap the top of the file. + kbts_ReadFontData() -- Read and byteswap the rest. + kbts_PostReadFontInitialize() -- Initialize auxiliary structures + Example code for reading a font file with this API looks like this: + size_t ScratchSize = kbts_ReadFontHeader(&Font, Data, Size); + size_t PermanentMemorySize = kbts_ReadFontData(&Font, malloc(ScratchSize), ScratchSize); + kbts_PostReadFontInitialize(&Font, malloc(PermanentMemorySize), PermanentMemorySize); + + Please note that, AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE. + AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE. + AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE. + AS SOON AS YOU CALL ReadFontHeader(), THE FONT DATA IS MODIFIED IN-PLACE! + If you need to open the same font with another library, you need to copy the data BEFORE + calling ReadFontHeader(). + + The buffer you pass to ReadFontData() is temporary and can be freed once the function returns. + The buffer you pass to PostReadFontInitialize() is persistent and can only be freed once you + are done with the font. + Utility, etc. + kbts_ShaperIsComplex() + kbts_ScriptIsComplex() + kbts_InferScript() -- Stupid script detection. Do not ship this! Use script breaks instead. + kbts_DecodeUtf8() + kbts_ScriptTagToScript() + kbts_FeatureTagToId() + + EXAMPLE USAGE + Complete example: + const char *String = "..."; + size_t Length = strlen(String); + // Open a font file + kbts_font Font = kbts_FontFromFile("..."); + // Make some glyphs + kbts_glyph *Glyphs = (kbts_glyph *)malloc(sizeof(kbts_glyph) * Length); + uint32_t GlyphCount = 0; + kbts_script Script = KBTS_SCRIPT_DONT_KNOW; + kbts_direction Direction = KBTS_DIRECTION_NONE; + for(size_t StringAt = 0; StringAt < Length;) + { + kbts_decode Decode = kbts_DecodeUtf8(String + StringAt, Length - StringAt); + StringAt += Decode.SourceCharactersConsumed; + if(Decode.Valid) + { + kbts_glyph Glyph = kbts_CodepointToGlyph(&Font, Decode.Codepoint); + // Easy script inference for simple cases. (This is similar to hb_buffer_guess_segment_properties.) + // If you have already segmented String with our API, you already have a script! + // So no need to pass it in that case. + // Only use this as a shorthand, when you are pretty sure String is a single + // script. + kbts_InferScript(&Direction, &Script, Glyph.Script); + Glyphs[GlyphCount++] = Glyph; + } + } + // Shape + uint32_t GlyphCapacity = Length; + kbts_shape_state *State = kbts_CreateShapeState(&Font); + // A shape_config is immutable once created. You can freely share/hash it, etc. + kbts_shape_config Config = kbts_ShapeConfig(&Font, Script, KBTS_LANGUAGE_DONT_KNOW); + while(kbts_Shape(State, &Config, Direction, Direction, Glyphs, &GlyphCount, GlyphCapacity)) + { + Glyphs = realloc(Glyphs, sizeof(kbts_glyph) * State->RequiredGlyphCapacity); + GlyphCapacity = State->RequiredGlyphCapacity; + } + // Get final positions + kbts_cursor Cursor = kbts_Cursor(Direction); + for(size_t GlyphIndex = 0; GlyphIndex < GlyphCount; ++GlyphIndex) + { + int X, Y; + kbts_PositionGlyph(&Cursor, &Glyphs[GlyphIndex], &X, &Y); + } + + Breaking Unicode text - finding the end of the current line: + uint32_t LineLength = 0; + kbts_break_state BreakState; + kbts_BeginBreak(&BreakState, KBTS_DIRECTION_NONE, KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL); + for(size_t CodepointIndex = 0; (CodepointIndex < CodepointCount) && !LineLength; ++CodepointIndex) + { + // We use a fixed-width encoding (codepoints) -- just pass a PositionIncrement of 1. + // If we wanted to directly segment UTF-8 in-place, we would pass in however many bytes each UTF-8 character was. + + // The last parameter to AddCodepoint is a boolean signifying the end of text. + // Alternatively, we could have written: + // kbts_BreakAddCodepoint(..., 0); + // if((CodepointIndex + 1) == CodepointCount) kbts_BreakFlush(); + + kbts_BreakAddCodepoint(&BreakState, Codepoints[CodepointIndex], 1, (CodepointIndex + 1) == CodepointCount); + kbts_break Break; + while(kbts_Break(&BreakState, &Break)) + { + // We could just as easily check for any other kind of break here. + // See kbts_break_flags for the kind of breaks we can find. + if(Break.Flags & KBTS_BREAK_FLAG_LINE_HARD) + { + LineLength = Break.Position; + } + } + } + + Control which font features apply to which glyphs: + kbts_feature_override Ss03FeatureOverrides[] = { + kbts_FeatureOverride(KBTS_FEATURE_ID_ccmp, 0, 0), // Disable ccmp + kbts_FeatureOverride(KBTS_FEATURE_ID_ss03, 0, 1), // Enable ss03 + }; + kbts_glyph_config Ss03Config = kbts_GlyphConfig(Ss03FeatureOverrides, 2); + kbts_feature_override SaltFeatureOverrides[] = { + kbts_FeatureOverride(KBTS_FEATURE_ID_salt, 1, 3), // Pick alternate glyph number 3 from feature 'salt' + }; + kbts_glyph_config SaltConfig = kbts_GlyphConfig(SaltFeatureOverrides, 1); + + // Then, do this before calling kbts_Shape(): + MyGlyphs[0].Config = &Ss03Config; + MyGlyphs[1].Config = &SaltConfig; + + Open a font with your own memory: + kbts_font Font; + // Be careful: ReadFontHeader() and ReadFontData() both byteswap font data in-place! + size_t ScratchSize = kbts_ReadFontHeader(&Font, Data, Size); + size_t PermanentMemorySize = kbts_ReadFontData(&Font, malloc(ScratchSize), ScratchSize); + kbts_PostReadFontInitialize(&Font, malloc(PermanentMemorySize), PermanentMemorySize); + // At any point, you can call kbts_FontIsValid(&Font) to check if the read went well. + // You do not need to check for font validity in between API calls here; once a font is flagged + // with an error, subsequent API calls simply do nothing. + // If you have provided real font data, kbts_FontIsValid(&Font) will most likely be true. + // We may still fail to parse some technically valid fonts that contain very deeply-nested or + // self-referential lookups. + // In those cases, Harfbuzz might open the font, but, at the time of writing, it silently limits + // the recursion depth to 64 when applying the lookups anyway. + + Allocate a shape_state with your own memory: + kbts_shape_state *State = kbts_PlaceShapeState(malloc(kbts_SizeOfShapeState(Font)), kbts_SizeOfShapeState(Font)); + + Use a single shape_state across multiple runs: + while(kbts_Shape(State, ...)) {...} + // If the previous shaping operation completed successfully, ResetShapeState is not necessary. + // If, for any reason, you have decided to stop shaping in the middle of an operation, though, + // you need to call it. + // (This is just setting a state counter, so this is very cheap.) + kbts_ResetShapeState(State); + while(kbts_Shape(State, ...)) {...} + + Use a single shape_state across multiple fonts: + // Different fonts have different memory requirements for shaping. However, beyond that, there + // is nothing that ties a shape_state to a font. You may use it freely with multiple fonts, as + // long as it is large enough. + size_t Size0 = kbts_SizeOfShapeState(Font0); + size_t Size1 = kbts_SizeOfShapeState(Font1); + size_t Size = MAX(Size0, Size1) + kbts_shape_state *State = kbts_PlaceShapeState(malloc(Size), Size); + + Use a single shape_config across multiple runs: + // Once a shape_config has been created, it is assumed to be immutable and can be trivially shared + // between runs/operations that have the same parameters. + + PERFORMANCE + Just like most libraries that interact with font files, we use the file as an in-memory database. + There are a few issues with this approach: + - Font files can be arbitrarily complex, making it difficult to predict system behavior at runtime. + - Font files are encoded in big endian byte order, which is stupid and slow. + We compensate for this by pre-processing as much as we can when opening the file. Notably, we + byteswap everything we need in-place, we precompute some useful runtime memory bounds, and we + allocate a few auxiliary acceleration structures. + + Since we byteswap everything in-place, you cannot pass the same font data to kbts and to another + library, because the other library will expect everything to be big endian. + + As a result of this approach, opening fonts is slow and shaping is fast. This is very much intentional. + At the time of writing (2025-07-13), on Harfbuzz's test suite, we are, on average, 4.5x faster than + Harfbuzz on my laptop (Ryzen 9 5900HX). As fonts are complex, and Harfbuzz's test suite is quite varied, + the speedup numbers are rather spread out: + Best: 22x + 10th percentile: 6.5x + Median: 4.5x + 90th percentile: 2.5x + Worst: 1.05x + So, aside from a few extreme cases, you should expect a small integer speedup factor compared to Harfbuzz. + + LANGUAGE SUPPORT + Shaping is NOT supported for the following scripts: + Zawgyi: some fonts exist, but no standardized OpenType feature set seems to exist as of writing. + Syriac: Syriac Abbreviation Mark (0x070F) is not supported. + Egyptian Hieroglyphs, I think, although example text is hard to come by. + Word breaking is NOT supported for languages that require word dictionaries, like CJK. + + FONT SUPPORT + Font collections (.ttc) are not supported. + Indic fonts using the Indic1 shaping model are not supported. + e.g., 'bng2' will work, but 'beng' will not. + The Indic v2 shaping model was released with OpenType 1.5 in May 2008. + Traditional Arabic Windows 3.1 fonts are not supported. + https://github.com/harfbuzz/harfbuzz/issues/681 + Thai/Lao PUA fonts are not supported. + These are old fonts that use OS-specific codepages (PUA stands for [Unicode] "Private Use Area") and + pre-OpenType shaping. + https://linux.thai.net/~thep/th-otf/shaping.html + More generally, we try to be compatible with most well-formed fonts, but we try less hard than Harfbuzz + to be compatible with every font under the sun. + + OTHER LIMITATIONS + Explicit direction control characters are not supported. This includes: + 0x202A Left-to-right embedding + 0x202B Right-to-left embedding + 0x202D Left-to-right override + 0x202E Right-to-left override + 0x202C Pop directional formatting + 0x2066 Left-to-right isolate + 0x2067 Right-to-left isolate + 0x2068 First strong isolate + 0x2069 Pop directional isolate + See https://unicode.org/reports/tr9 for more information. + + VERSION HISTORY + 1.03 - New functions: kbts_FeatureTagToId(), kbts_FeatureOverrideFromTag(), kbts_EmptyGlyphConfig(), kbts_GlyphConfigOverrideFeature(), kbts_GlyphConfigOverrideFeatureFromTag(), kbts_ScriptTagToScript() + Unregistered features can now be overriden using their tags. + This is slower than overriding registered features, i.e. those that have a kbts_feature_id. + Compiler warning cleanup + 1.02b - Feature control for GPOS features + Bounds checking in ReadFontHeader + 1.02a - Positioning fix for format 2 GPOS pair adjustments + 1.02 - Added per-glyph manual feature control through kbts_FeatureOverride(), kbts_GlyphConfig() + Added enum definitions for features cv01-cv99 and ss01-ss20 + 1.01 - Header cleanup and glyph output documentation + 1.0 - Initial release + + TODO + Word dictionaries for word breaking: CJK, etc. + 'stch' feature. + Precompute GPOS nesting in advance and replace recursion with explicit frames. + (Either that or limit to a hard depth for now.) + + LICENSE + zlib License + + (C) Copyright 2024-2025 Jimmy Lefevre + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +#ifndef KB_TEXT_SHAPE_INCLUDED +# define KB_TEXT_SHAPE_INCLUDED + +# ifndef kbts_s64 +# if defined(_MSC_VER) || defined(__BORLANDC__) +# define kbts_s64 __int64 +# else +# define kbts_s64 long long +# endif +# endif +# ifndef kbts_u64 +# if defined(_MSC_VER) || defined(__BORLANDC__) +# define kbts_u64 unsigned __int64 +# else +# define kbts_u64 unsigned long long +# endif +# endif +# ifndef kbts_u32 +# define kbts_u32 unsigned +# endif +# ifndef kbts_u16 +# define kbts_u16 unsigned short +# endif +# ifndef kbts_s32 +# define kbts_s32 int +# endif +# ifndef kbts_s16 +# define kbts_s16 short +# endif +# ifndef kbts_u8 +# define kbts_u8 unsigned char +# endif +# ifndef kbts_s8 +# define kbts_s8 signed char +# endif + +# ifndef KB_TEXT_SHAPE_POINTER_SIZE +# if defined(i386) || defined(__i386__) || defined(_M_IX86) || defined(_M_ARM) || defined(__arm__) || defined(__x86) || (defined(__APPLE__) && defined(__ppc)) || \ + (defined(__TOS_AIX__) && !defined(__64BIT)) +# define KB_TEXT_SHAPE_POINTER_SIZE 4 +# else +# define KB_TEXT_SHAPE_POINTER_SIZE 8 +# endif +# endif + +# if KB_TEXT_SHAPE_POINTER_SIZE == 4 +# define kbts_un kbts_u32 +# define kbts_sn kbts_s32 +# else +# define kbts_un kbts_u64 +# define kbts_sn kbts_s64 +# endif + +# ifdef __has_attribute +# if __has_attribute(fallthrough) +# define KBTS_FALLTHROUGH __attribute__((fallthrough)) +# endif +# endif +# ifndef KBTS_FALLTHROUGH +# define KBTS_FALLTHROUGH +# endif + +# ifndef KBTS_EXPORT +# ifdef KB_TEXT_SHAPE_STATIC +# define KBTS_EXPORT static +# else +# ifdef __cplusplus +# define KBTS_EXPORT extern "C" +# else +# define KBTS_EXPORT extern +# endif +# endif +# endif + +# ifdef _MSC_VER +# define KBTS_INLINE static __forceinline +# define KBTS_NOINLINE static __declspec(noinline) +# else +# ifdef __has_attribute +# if __has_attribute(always_inline) +# define KBTS_INLINE static inline __attribute__((always_inline)) +# endif +# if __has_attribute(noinline) +# define KBTS_NOINLINE static __attribute__((noinline)) +# endif +# endif +# endif +# ifndef KBTS_INLINE +# define KBTS_INLINE static inline +# endif + +# define KBTS_FOURCC(A, B, C, D) ((A) | ((B) << 8) | ((C) << 16) | ((D) << 24)) + +typedef kbts_u8 kbts_joining_feature; +enum kbts_joining_feature_enum +{ + KBTS_JOINING_FEATURE_NONE, + + // These must correspond with glyph_flags and FEATURE_IDs. + KBTS_JOINING_FEATURE_ISOL, + KBTS_JOINING_FEATURE_FINA, + KBTS_JOINING_FEATURE_FIN2, + KBTS_JOINING_FEATURE_FIN3, + KBTS_JOINING_FEATURE_MEDI, + KBTS_JOINING_FEATURE_MED2, + KBTS_JOINING_FEATURE_INIT, + + KBTS_JOINING_FEATURE_COUNT, +}; + +typedef kbts_u8 kbts_reph_position; +enum kbts_reph_position_enum +{ + KBTS_REPH_POSITION_AFTER_POST, + KBTS_REPH_POSITION_BEFORE_POST, + KBTS_REPH_POSITION_BEFORE_SUBJOINED, + KBTS_REPH_POSITION_AFTER_SUBJOINED, + KBTS_REPH_POSITION_AFTER_MAIN, + + KBTS_REPH_POSITION_COUNT, +}; + +typedef kbts_u8 kbts_reph_encoding; +enum kbts_reph_encoding_enum +{ + KBTS_REPH_ENCODING_IMPLICIT, + KBTS_REPH_ENCODING_EXPLICIT, + KBTS_REPH_ENCODING_LOGICAL_REPHA, + KBTS_REPH_ENCODING_VISUAL_REPHA, + + KBTS_REPH_ENCODING_COUNT, +}; + +typedef kbts_u8 kbts_syllabic_position; +enum kbts_syllabic_position_enum +{ + KBTS_SYLLABIC_POSITION_NONE, + + KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH, + + KBTS_SYLLABIC_POSITION_PREBASE_MATRA, + KBTS_SYLLABIC_POSITION_PREBASE_CONSONANT, + + KBTS_SYLLABIC_POSITION_SYLLABLE_BASE, + KBTS_SYLLABIC_POSITION_AFTER_MAIN, + + KBTS_SYLLABIC_POSITION_ABOVEBASE_CONSONANT, + + KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED, + KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT, + KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED, + + KBTS_SYLLABIC_POSITION_BEFORE_POST, + KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT, + KBTS_SYLLABIC_POSITION_AFTER_POST, + + KBTS_SYLLABIC_POSITION_FINAL_CONSONANT, + KBTS_SYLLABIC_POSITION_SMVD, + + KBTS_SYLLABIC_POSITION_COUNT, +}; + +typedef kbts_u32 kbts_language; +enum kbts_language_enum +{ + KBTS_LANGUAGE_DONT_KNOW = 0, + + KBTS_LANGUAGE_A_HMAO = KBTS_FOURCC('H', 'M', 'D', ' '), + KBTS_LANGUAGE_AARI = KBTS_FOURCC('A', 'R', 'I', ' '), + KBTS_LANGUAGE_ABAZA = KBTS_FOURCC('A', 'B', 'A', ' '), + KBTS_LANGUAGE_ABKHAZIAN = KBTS_FOURCC('A', 'B', 'K', ' '), + KBTS_LANGUAGE_ACHI = KBTS_FOURCC('A', 'C', 'R', ' '), + KBTS_LANGUAGE_ACHOLI = KBTS_FOURCC('A', 'C', 'H', ' '), + KBTS_LANGUAGE_ADYGHE = KBTS_FOURCC('A', 'D', 'Y', ' '), + KBTS_LANGUAGE_AFAR = KBTS_FOURCC('A', 'F', 'R', ' '), + KBTS_LANGUAGE_AFRIKAANS = KBTS_FOURCC('A', 'F', 'K', ' '), + KBTS_LANGUAGE_AGAW = KBTS_FOURCC('A', 'G', 'W', ' '), + KBTS_LANGUAGE_AITON = KBTS_FOURCC('A', 'I', 'O', ' '), + KBTS_LANGUAGE_AKAN = KBTS_FOURCC('A', 'K', 'A', ' '), + KBTS_LANGUAGE_ALBANIAN = KBTS_FOURCC('S', 'Q', 'I', ' '), + KBTS_LANGUAGE_ALSATIAN = KBTS_FOURCC('A', 'L', 'S', ' '), + KBTS_LANGUAGE_ALTAI = KBTS_FOURCC('A', 'L', 'T', ' '), + KBTS_LANGUAGE_ALUO = KBTS_FOURCC('Y', 'N', 'A', ' '), + KBTS_LANGUAGE_AMERICAN_PHONETIC = KBTS_FOURCC('A', 'P', 'P', 'H'), + KBTS_LANGUAGE_AMHARIC = KBTS_FOURCC('A', 'M', 'H', ' '), + KBTS_LANGUAGE_ANGLO_SAXON = KBTS_FOURCC('A', 'N', 'G', ' '), + KBTS_LANGUAGE_ARABIC = KBTS_FOURCC('A', 'R', 'A', ' '), + KBTS_LANGUAGE_ARAGONESE = KBTS_FOURCC('A', 'R', 'G', ' '), + KBTS_LANGUAGE_ARAKANESE = KBTS_FOURCC('A', 'R', 'K', ' '), + KBTS_LANGUAGE_ARAKWAL = KBTS_FOURCC('R', 'K', 'W', ' '), + KBTS_LANGUAGE_ARMENIAN = KBTS_FOURCC('H', 'Y', 'E', ' '), + KBTS_LANGUAGE_ARMENIAN_EAST = KBTS_FOURCC('H', 'Y', 'E', '0'), + KBTS_LANGUAGE_AROMANIAN = KBTS_FOURCC('R', 'U', 'P', ' '), + KBTS_LANGUAGE_ARPITAN = KBTS_FOURCC('F', 'R', 'P', ' '), + KBTS_LANGUAGE_ASSAMESE = KBTS_FOURCC('A', 'S', 'M', ' '), + KBTS_LANGUAGE_ASTURIAN = KBTS_FOURCC('A', 'S', 'T', ' '), + KBTS_LANGUAGE_ATHAPASKAN = KBTS_FOURCC('A', 'T', 'H', ' '), + KBTS_LANGUAGE_ATSINA = KBTS_FOURCC('A', 'T', 'S', ' '), + KBTS_LANGUAGE_AVAR = KBTS_FOURCC('A', 'V', 'R', ' '), + KBTS_LANGUAGE_AVATIME = KBTS_FOURCC('A', 'V', 'N', ' '), + KBTS_LANGUAGE_AWADHI = KBTS_FOURCC('A', 'W', 'A', ' '), + KBTS_LANGUAGE_AYMARA = KBTS_FOURCC('A', 'Y', 'M', ' '), + KBTS_LANGUAGE_AZERBAIDJANI = KBTS_FOURCC('A', 'Z', 'E', ' '), + KBTS_LANGUAGE_BADAGA = KBTS_FOURCC('B', 'A', 'D', ' '), + KBTS_LANGUAGE_BAGHELKHANDI = KBTS_FOURCC('B', 'A', 'G', ' '), + KBTS_LANGUAGE_BAGRI = KBTS_FOURCC('B', 'G', 'Q', ' '), + KBTS_LANGUAGE_BALANTE = KBTS_FOURCC('B', 'L', 'N', ' '), + KBTS_LANGUAGE_BALINESE = KBTS_FOURCC('B', 'A', 'N', ' '), + KBTS_LANGUAGE_BALKAR = KBTS_FOURCC('B', 'A', 'L', ' '), + KBTS_LANGUAGE_BALTI = KBTS_FOURCC('B', 'L', 'T', ' '), + KBTS_LANGUAGE_BALUCHI = KBTS_FOURCC('B', 'L', 'I', ' '), + KBTS_LANGUAGE_BAMBARA = KBTS_FOURCC('B', 'M', 'B', ' '), + KBTS_LANGUAGE_BAMILEKE = KBTS_FOURCC('B', 'M', 'L', ' '), + KBTS_LANGUAGE_BANDA = KBTS_FOURCC('B', 'A', 'D', '0'), + KBTS_LANGUAGE_BANDJALANG = KBTS_FOURCC('B', 'D', 'Y', ' '), + KBTS_LANGUAGE_BANGLA = KBTS_FOURCC('B', 'E', 'N', ' '), + KBTS_LANGUAGE_BASHKIR = KBTS_FOURCC('B', 'S', 'H', ' '), + KBTS_LANGUAGE_BASQUE = KBTS_FOURCC('E', 'U', 'Q', ' '), + KBTS_LANGUAGE_BATAK = KBTS_FOURCC('B', 'T', 'K', ' '), + KBTS_LANGUAGE_BATAK_ALAS_KLUET = KBTS_FOURCC('B', 'T', 'Z', ' '), + KBTS_LANGUAGE_BATAK_ANGKOLA = KBTS_FOURCC('A', 'K', 'B', ' '), + KBTS_LANGUAGE_BATAK_DAIRI = KBTS_FOURCC('B', 'T', 'D', ' '), + KBTS_LANGUAGE_BATAK_KARO = KBTS_FOURCC('B', 'T', 'X', ' '), + KBTS_LANGUAGE_BATAK_MANDAILING = KBTS_FOURCC('B', 'T', 'M', ' '), + KBTS_LANGUAGE_BATAK_SIMALUNGUN = KBTS_FOURCC('B', 'T', 'S', ' '), + KBTS_LANGUAGE_BATAK_TOBA = KBTS_FOURCC('B', 'B', 'C', ' '), + KBTS_LANGUAGE_BAULE = KBTS_FOURCC('B', 'A', 'U', ' '), + KBTS_LANGUAGE_BAVARIAN = KBTS_FOURCC('B', 'A', 'R', ' '), + KBTS_LANGUAGE_BELARUSIAN = KBTS_FOURCC('B', 'E', 'L', ' '), + KBTS_LANGUAGE_BEMBA = KBTS_FOURCC('B', 'E', 'M', ' '), + KBTS_LANGUAGE_BENCH = KBTS_FOURCC('B', 'C', 'H', ' '), + KBTS_LANGUAGE_BERBER = KBTS_FOURCC('B', 'B', 'R', ' '), + KBTS_LANGUAGE_BETI = KBTS_FOURCC('B', 'T', 'I', ' '), + KBTS_LANGUAGE_BETTE_KURUMA = KBTS_FOURCC('X', 'U', 'B', ' '), + KBTS_LANGUAGE_BHILI = KBTS_FOURCC('B', 'H', 'I', ' '), + KBTS_LANGUAGE_BHOJPURI = KBTS_FOURCC('B', 'H', 'O', ' '), + KBTS_LANGUAGE_BHUTANESE = KBTS_FOURCC('D', 'Z', 'N', ' '), + KBTS_LANGUAGE_BIBLE_CREE = KBTS_FOURCC('B', 'C', 'R', ' '), + KBTS_LANGUAGE_BIKOL = KBTS_FOURCC('B', 'I', 'K', ' '), + KBTS_LANGUAGE_BILEN = KBTS_FOURCC('B', 'I', 'L', ' '), + KBTS_LANGUAGE_BISHNUPRIYA_MANIPURI = KBTS_FOURCC('B', 'P', 'Y', ' '), + KBTS_LANGUAGE_BISLAMA = KBTS_FOURCC('B', 'I', 'S', ' '), + KBTS_LANGUAGE_BLACKFOOT = KBTS_FOURCC('B', 'K', 'F', ' '), + KBTS_LANGUAGE_BODO = KBTS_FOURCC('B', 'R', 'X', ' '), + KBTS_LANGUAGE_BOSNIAN = KBTS_FOURCC('B', 'O', 'S', ' '), + KBTS_LANGUAGE_BOUYEI = KBTS_FOURCC('P', 'C', 'C', ' '), + KBTS_LANGUAGE_BRAHUI = KBTS_FOURCC('B', 'R', 'H', ' '), + KBTS_LANGUAGE_BRAJ_BHASHA = KBTS_FOURCC('B', 'R', 'I', ' '), + KBTS_LANGUAGE_BRETON = KBTS_FOURCC('B', 'R', 'E', ' '), + KBTS_LANGUAGE_BUGIS = KBTS_FOURCC('B', 'U', 'G', ' '), + KBTS_LANGUAGE_BULGARIAN = KBTS_FOURCC('B', 'G', 'R', ' '), + KBTS_LANGUAGE_BUMTHANGKHA = KBTS_FOURCC('K', 'J', 'Z', ' '), + KBTS_LANGUAGE_BURMESE = KBTS_FOURCC('B', 'R', 'M', ' '), + KBTS_LANGUAGE_BURUSHASKI = KBTS_FOURCC('B', 'S', 'K', ' '), + KBTS_LANGUAGE_CAJUN_FRENCH = KBTS_FOURCC('F', 'R', 'C', ' '), + KBTS_LANGUAGE_CARRIER = KBTS_FOURCC('C', 'R', 'R', ' '), + KBTS_LANGUAGE_CATALAN = KBTS_FOURCC('C', 'A', 'T', ' '), + KBTS_LANGUAGE_CAYUGA = KBTS_FOURCC('C', 'A', 'Y', ' '), + KBTS_LANGUAGE_CEBUANO = KBTS_FOURCC('C', 'E', 'B', ' '), + KBTS_LANGUAGE_CENTRAL_YUPIK = KBTS_FOURCC('E', 'S', 'U', ' '), + KBTS_LANGUAGE_CHAHA_GURAGE = KBTS_FOURCC('C', 'H', 'G', ' '), + KBTS_LANGUAGE_CHAMORRO = KBTS_FOURCC('C', 'H', 'A', ' '), + KBTS_LANGUAGE_CHATTISGARHI = KBTS_FOURCC('C', 'H', 'H', ' '), + KBTS_LANGUAGE_CHECHEN = KBTS_FOURCC('C', 'H', 'E', ' '), + KBTS_LANGUAGE_CHEROKEE = KBTS_FOURCC('C', 'H', 'R', ' '), + KBTS_LANGUAGE_CHEYENNE = KBTS_FOURCC('C', 'H', 'Y', ' '), + KBTS_LANGUAGE_CHICHEWA = KBTS_FOURCC('C', 'H', 'I', ' '), + KBTS_LANGUAGE_CHIGA = KBTS_FOURCC('C', 'G', 'G', ' '), + KBTS_LANGUAGE_CHIMILA = KBTS_FOURCC('C', 'B', 'G', ' '), + KBTS_LANGUAGE_CHIN = KBTS_FOURCC('Q', 'I', 'N', ' '), + KBTS_LANGUAGE_CHINANTEC = KBTS_FOURCC('C', 'C', 'H', 'N'), + KBTS_LANGUAGE_CHINESE_PHONETIC = KBTS_FOURCC('Z', 'H', 'P', ' '), + KBTS_LANGUAGE_CHINESE_SIMPLIFIED = KBTS_FOURCC('Z', 'H', 'S', ' '), + KBTS_LANGUAGE_CHINESE_TRADITIONAL = KBTS_FOURCC('Z', 'H', 'T', ' '), + KBTS_LANGUAGE_CHINESE_TRADITIONAL_HONG_KONG = KBTS_FOURCC('Z', 'H', 'H', ' '), + KBTS_LANGUAGE_CHINESE_TRADITIONAL_MACAO = KBTS_FOURCC('Z', 'H', 'T', 'M'), + KBTS_LANGUAGE_CHIPEWYAN = KBTS_FOURCC('C', 'H', 'P', ' '), + KBTS_LANGUAGE_CHITTAGONIAN = KBTS_FOURCC('C', 'T', 'G', ' '), + KBTS_LANGUAGE_CHOCTAW = KBTS_FOURCC('C', 'H', 'O', ' '), + KBTS_LANGUAGE_CHUKCHI = KBTS_FOURCC('C', 'H', 'K', ' '), + KBTS_LANGUAGE_CHURCH_SLAVONIC = KBTS_FOURCC('C', 'S', 'L', ' '), + KBTS_LANGUAGE_CHUUKESE = KBTS_FOURCC('C', 'H', 'K', '0'), + KBTS_LANGUAGE_CHUVASH = KBTS_FOURCC('C', 'H', 'U', ' '), + KBTS_LANGUAGE_COMORIAN = KBTS_FOURCC('C', 'M', 'R', ' '), + KBTS_LANGUAGE_COMOX = KBTS_FOURCC('C', 'O', 'O', ' '), + KBTS_LANGUAGE_COPTIC = KBTS_FOURCC('C', 'O', 'P', ' '), + KBTS_LANGUAGE_CORNISH = KBTS_FOURCC('C', 'O', 'R', ' '), + KBTS_LANGUAGE_CORSICAN = KBTS_FOURCC('C', 'O', 'S', ' '), + KBTS_LANGUAGE_CREE = KBTS_FOURCC('C', 'R', 'E', ' '), + KBTS_LANGUAGE_CREOLES = KBTS_FOURCC('C', 'P', 'P', ' '), + KBTS_LANGUAGE_CRIMEAN_TATAR = KBTS_FOURCC('C', 'R', 'T', ' '), + KBTS_LANGUAGE_CRIOULO = KBTS_FOURCC('K', 'E', 'A', ' '), + KBTS_LANGUAGE_CROATIAN = KBTS_FOURCC('H', 'R', 'V', ' '), + KBTS_LANGUAGE_CYPRIOT_ARABIC = KBTS_FOURCC('A', 'C', 'Y', ' '), + KBTS_LANGUAGE_CZECH = KBTS_FOURCC('C', 'S', 'Y', ' '), + KBTS_LANGUAGE_DAGBANI = KBTS_FOURCC('D', 'A', 'G', ' '), + KBTS_LANGUAGE_DAN = KBTS_FOURCC('D', 'N', 'J', ' '), + KBTS_LANGUAGE_DANGME = KBTS_FOURCC('D', 'N', 'G', ' '), + KBTS_LANGUAGE_DANISH = KBTS_FOURCC('D', 'A', 'N', ' '), + KBTS_LANGUAGE_DARGWA = KBTS_FOURCC('D', 'A', 'R', ' '), + KBTS_LANGUAGE_DARI = KBTS_FOURCC('D', 'R', 'I', ' '), + KBTS_LANGUAGE_DAYI = KBTS_FOURCC('D', 'A', 'X', ' '), + KBTS_LANGUAGE_DEFAULT = KBTS_FOURCC('d', 'f', 'l', 't'), // Can be DFLT too... + KBTS_LANGUAGE_DEHONG_DAI = KBTS_FOURCC('T', 'D', 'D', ' '), + KBTS_LANGUAGE_DHANGU = KBTS_FOURCC('D', 'H', 'G', ' '), + KBTS_LANGUAGE_DHIVEHI = KBTS_FOURCC('D', 'I', 'V', ' '), + KBTS_LANGUAGE_DHUWAL = KBTS_FOURCC('D', 'U', 'J', ' '), + KBTS_LANGUAGE_DIMLI = KBTS_FOURCC('D', 'I', 'Q', ' '), + KBTS_LANGUAGE_DINKA = KBTS_FOURCC('D', 'N', 'K', ' '), + KBTS_LANGUAGE_DIVEHI = KBTS_FOURCC('D', 'I', 'V', ' '), + KBTS_LANGUAGE_DJAMBARRPUYNGU = KBTS_FOURCC('D', 'J', 'R', '0'), + KBTS_LANGUAGE_DOGRI = KBTS_FOURCC('D', 'G', 'O', ' '), + KBTS_LANGUAGE_DOGRI_MACROLANGUAGE = KBTS_FOURCC('D', 'G', 'R', ' '), + KBTS_LANGUAGE_DUNGAN = KBTS_FOURCC('D', 'U', 'N', ' '), + KBTS_LANGUAGE_DUTCH = KBTS_FOURCC('N', 'L', 'D', ' '), + KBTS_LANGUAGE_DZONGKHA = KBTS_FOURCC('D', 'Z', 'N', ' '), + KBTS_LANGUAGE_EASTERN_ABENAKI = KBTS_FOURCC('A', 'A', 'Q', ' '), + KBTS_LANGUAGE_EASTERN_CHAM = KBTS_FOURCC('C', 'J', 'M', ' '), + KBTS_LANGUAGE_EASTERN_CREE = KBTS_FOURCC('E', 'C', 'R', ' '), + KBTS_LANGUAGE_EASTERN_MANINKAKAN = KBTS_FOURCC('E', 'M', 'K', ' '), + KBTS_LANGUAGE_EASTERN_PWO_KAREN = KBTS_FOURCC('K', 'J', 'P', ' '), + KBTS_LANGUAGE_EBIRA = KBTS_FOURCC('E', 'B', 'I', ' '), + KBTS_LANGUAGE_EDO = KBTS_FOURCC('E', 'D', 'O', ' '), + KBTS_LANGUAGE_EFIK = KBTS_FOURCC('E', 'F', 'I', ' '), + KBTS_LANGUAGE_EMBERA_BAUDO = KBTS_FOURCC('B', 'D', 'C', ' '), + KBTS_LANGUAGE_EMBERA_CATIO = KBTS_FOURCC('C', 'T', 'O', ' '), + KBTS_LANGUAGE_EMBERA_CHAMI = KBTS_FOURCC('C', 'M', 'I', ' '), + KBTS_LANGUAGE_EMBERA_TADO = KBTS_FOURCC('T', 'D', 'C', ' '), + KBTS_LANGUAGE_ENGLISH = KBTS_FOURCC('E', 'N', 'G', ' '), + KBTS_LANGUAGE_EPENA = KBTS_FOURCC('S', 'J', 'A', ' '), + KBTS_LANGUAGE_ERZYA = KBTS_FOURCC('E', 'R', 'Z', ' '), + KBTS_LANGUAGE_KB_TEXT_SHAPEANTO = KBTS_FOURCC('N', 'T', 'O', ' '), + KBTS_LANGUAGE_ESTONIAN = KBTS_FOURCC('E', 'T', 'I', ' '), + KBTS_LANGUAGE_EVEN = KBTS_FOURCC('E', 'V', 'N', ' '), + KBTS_LANGUAGE_EVENKI = KBTS_FOURCC('E', 'V', 'K', ' '), + KBTS_LANGUAGE_EWE = KBTS_FOURCC('E', 'W', 'E', ' '), + KBTS_LANGUAGE_FALAM_CHIN = KBTS_FOURCC('H', 'A', 'L', ' '), + KBTS_LANGUAGE_FANG = KBTS_FOURCC('F', 'A', 'N', '0'), + KBTS_LANGUAGE_FANTI = KBTS_FOURCC('F', 'A', 'T', ' '), + KBTS_LANGUAGE_FAROESE = KBTS_FOURCC('F', 'O', 'S', ' '), + KBTS_LANGUAGE_FEFE = KBTS_FOURCC('F', 'M', 'P', ' '), + KBTS_LANGUAGE_FIJIAN = KBTS_FOURCC('F', 'J', 'I', ' '), + KBTS_LANGUAGE_FILIPINO = KBTS_FOURCC('P', 'I', 'L', ' '), + KBTS_LANGUAGE_FINNISH = KBTS_FOURCC('F', 'I', 'N', ' '), + KBTS_LANGUAGE_FLEMISH = KBTS_FOURCC('F', 'L', 'E', ' '), + KBTS_LANGUAGE_FON = KBTS_FOURCC('F', 'O', 'N', ' '), + KBTS_LANGUAGE_FOREST_ENETS = KBTS_FOURCC('F', 'N', 'E', ' '), + KBTS_LANGUAGE_FRENCH = KBTS_FOURCC('F', 'R', 'A', ' '), + KBTS_LANGUAGE_FRENCH_ANTILLEAN = KBTS_FOURCC('F', 'A', 'N', ' '), + KBTS_LANGUAGE_FRISIAN = KBTS_FOURCC('F', 'R', 'I', ' '), + KBTS_LANGUAGE_FRIULIAN = KBTS_FOURCC('F', 'R', 'L', ' '), + KBTS_LANGUAGE_FULAH = KBTS_FOURCC('F', 'U', 'L', ' '), + KBTS_LANGUAGE_FUTA = KBTS_FOURCC('F', 'T', 'A', ' '), + KBTS_LANGUAGE_GA = KBTS_FOURCC('G', 'A', 'D', ' '), + KBTS_LANGUAGE_GAGAUZ = KBTS_FOURCC('G', 'A', 'G', ' '), + KBTS_LANGUAGE_GALICIAN = KBTS_FOURCC('G', 'A', 'L', ' '), + KBTS_LANGUAGE_GANDA = KBTS_FOURCC('L', 'U', 'G', ' '), + KBTS_LANGUAGE_GARHWALI = KBTS_FOURCC('G', 'A', 'W', ' '), + KBTS_LANGUAGE_GARO = KBTS_FOURCC('G', 'R', 'O', ' '), + KBTS_LANGUAGE_GARSHUNI = KBTS_FOURCC('G', 'A', 'R', ' '), + KBTS_LANGUAGE_GEBA_KAREN = KBTS_FOURCC('K', 'V', 'Q', ' '), + KBTS_LANGUAGE_GEEZ = KBTS_FOURCC('G', 'E', 'Z', ' '), + KBTS_LANGUAGE_GEORGIAN = KBTS_FOURCC('K', 'A', 'T', ' '), + KBTS_LANGUAGE_GEPO = KBTS_FOURCC('Y', 'G', 'P', ' '), + KBTS_LANGUAGE_GERMAN = KBTS_FOURCC('D', 'E', 'U', ' '), + KBTS_LANGUAGE_GIKUYU = KBTS_FOURCC('K', 'I', 'K', ' '), + KBTS_LANGUAGE_GILAKI = KBTS_FOURCC('G', 'L', 'K', ' '), + KBTS_LANGUAGE_GILBERTESE = KBTS_FOURCC('G', 'I', 'L', '0'), + KBTS_LANGUAGE_GILYAK = KBTS_FOURCC('G', 'I', 'L', ' '), + KBTS_LANGUAGE_GITHABUL = KBTS_FOURCC('G', 'I', 'H', ' '), + KBTS_LANGUAGE_GOGO = KBTS_FOURCC('G', 'O', 'G', ' '), + KBTS_LANGUAGE_GONDI = KBTS_FOURCC('G', 'O', 'N', ' '), + KBTS_LANGUAGE_GREEK = KBTS_FOURCC('E', 'L', 'L', ' '), + KBTS_LANGUAGE_GREENLANDIC = KBTS_FOURCC('G', 'R', 'N', ' '), + KBTS_LANGUAGE_GUARANI = KBTS_FOURCC('G', 'U', 'A', ' '), + KBTS_LANGUAGE_GUINEA = KBTS_FOURCC('G', 'K', 'P', ' '), + KBTS_LANGUAGE_GUJARATI = KBTS_FOURCC('G', 'U', 'J', ' '), + KBTS_LANGUAGE_GUMATJ = KBTS_FOURCC('G', 'N', 'N', ' '), + KBTS_LANGUAGE_GUMUZ = KBTS_FOURCC('G', 'M', 'Z', ' '), + KBTS_LANGUAGE_GUPAPUYNGU = KBTS_FOURCC('G', 'U', 'F', ' '), + KBTS_LANGUAGE_GUSII = KBTS_FOURCC('G', 'U', 'Z', ' '), + KBTS_LANGUAGE_HAIDA = KBTS_FOURCC('H', 'A', 'I', '0'), + KBTS_LANGUAGE_HAITIAN_CREOLE = KBTS_FOURCC('H', 'A', 'I', ' '), + KBTS_LANGUAGE_HALKOMELEM = KBTS_FOURCC('H', 'U', 'R', ' '), + KBTS_LANGUAGE_HAMMER_BANNA = KBTS_FOURCC('H', 'B', 'N', ' '), + KBTS_LANGUAGE_HARARI = KBTS_FOURCC('H', 'R', 'I', ' '), + KBTS_LANGUAGE_HARAUTI = KBTS_FOURCC('H', 'A', 'R', ' '), + KBTS_LANGUAGE_HARYANVI = KBTS_FOURCC('B', 'G', 'C', ' '), + KBTS_LANGUAGE_HAUSA = KBTS_FOURCC('H', 'A', 'U', ' '), + KBTS_LANGUAGE_HAVASUPAI_WALAPAI_YAVAPAI = KBTS_FOURCC('Y', 'U', 'F', ' '), + KBTS_LANGUAGE_HAWAIIAN = KBTS_FOURCC('H', 'A', 'W', ' '), + KBTS_LANGUAGE_HAYA = KBTS_FOURCC('H', 'A', 'Y', ' '), + KBTS_LANGUAGE_HAZARAGI = KBTS_FOURCC('H', 'A', 'Z', ' '), + KBTS_LANGUAGE_HEBREW = KBTS_FOURCC('I', 'W', 'R', ' '), + KBTS_LANGUAGE_HEILTSUK = KBTS_FOURCC('H', 'E', 'I', ' '), + KBTS_LANGUAGE_HERERO = KBTS_FOURCC('H', 'E', 'R', ' '), + KBTS_LANGUAGE_HIGH_MARI = KBTS_FOURCC('H', 'M', 'A', ' '), + KBTS_LANGUAGE_HILIGAYNON = KBTS_FOURCC('H', 'I', 'L', ' '), + KBTS_LANGUAGE_HINDI = KBTS_FOURCC('H', 'I', 'N', ' '), + KBTS_LANGUAGE_HINDKO = KBTS_FOURCC('H', 'N', 'D', ' '), + KBTS_LANGUAGE_HIRI_MOTU = KBTS_FOURCC('H', 'M', 'O', ' '), + KBTS_LANGUAGE_HMONG = KBTS_FOURCC('H', 'M', 'N', ' '), + KBTS_LANGUAGE_HMONG_DAW = KBTS_FOURCC('M', 'W', 'W', ' '), + KBTS_LANGUAGE_HMONG_SHUAT = KBTS_FOURCC('H', 'M', 'Z', ' '), + KBTS_LANGUAGE_HO = KBTS_FOURCC('H', 'O', ' ', ' '), + KBTS_LANGUAGE_HUNGARIAN = KBTS_FOURCC('H', 'U', 'N', ' '), + KBTS_LANGUAGE_IBAN = KBTS_FOURCC('I', 'B', 'A', ' '), + KBTS_LANGUAGE_IBIBIO = KBTS_FOURCC('I', 'B', 'B', ' '), + KBTS_LANGUAGE_ICELANDIC = KBTS_FOURCC('I', 'S', 'L', ' '), + KBTS_LANGUAGE_IDO = KBTS_FOURCC('I', 'D', 'O', ' '), + KBTS_LANGUAGE_IGBO = KBTS_FOURCC('I', 'B', 'O', ' '), + KBTS_LANGUAGE_IJO = KBTS_FOURCC('I', 'J', 'O', ' '), + KBTS_LANGUAGE_ILOKANO = KBTS_FOURCC('I', 'L', 'O', ' '), + KBTS_LANGUAGE_INARI_SAMI = KBTS_FOURCC('I', 'S', 'M', ' '), + KBTS_LANGUAGE_INDONESIAN = KBTS_FOURCC('I', 'N', 'D', ' '), + KBTS_LANGUAGE_INGUSH = KBTS_FOURCC('I', 'N', 'G', ' '), + KBTS_LANGUAGE_INTERLINGUA = KBTS_FOURCC('I', 'N', 'A', ' '), + KBTS_LANGUAGE_INTERLINGUE = KBTS_FOURCC('I', 'L', 'E', ' '), + KBTS_LANGUAGE_INUKTITUT = KBTS_FOURCC('I', 'N', 'U', ' '), + KBTS_LANGUAGE_INUPIAT = KBTS_FOURCC('I', 'P', 'K', ' '), + KBTS_LANGUAGE_IPA_PHONETIC = KBTS_FOURCC('I', 'P', 'P', ' '), + KBTS_LANGUAGE_IRISH = KBTS_FOURCC('I', 'R', 'I', ' '), + KBTS_LANGUAGE_IRISH_TRADITIONAL = KBTS_FOURCC('I', 'R', 'T', ' '), + KBTS_LANGUAGE_IRULA = KBTS_FOURCC('I', 'R', 'U', ' '), + KBTS_LANGUAGE_ITALIAN = KBTS_FOURCC('I', 'T', 'A', ' '), + KBTS_LANGUAGE_JAMAICAN_CREOLE = KBTS_FOURCC('J', 'A', 'M', ' '), + KBTS_LANGUAGE_JAPANESE = KBTS_FOURCC('J', 'A', 'N', ' '), + KBTS_LANGUAGE_JAVANESE = KBTS_FOURCC('J', 'A', 'V', ' '), + KBTS_LANGUAGE_JENNU_KURUMA = KBTS_FOURCC('X', 'U', 'J', ' '), + KBTS_LANGUAGE_JUDEO_TAT = KBTS_FOURCC('J', 'D', 'T', ' '), + KBTS_LANGUAGE_JULA = KBTS_FOURCC('J', 'U', 'L', ' '), + KBTS_LANGUAGE_KABARDIAN = KBTS_FOURCC('K', 'A', 'B', ' '), + KBTS_LANGUAGE_KABYLE = KBTS_FOURCC('K', 'A', 'B', '0'), + KBTS_LANGUAGE_KACHCHI = KBTS_FOURCC('K', 'A', 'C', ' '), + KBTS_LANGUAGE_KADIWEU = KBTS_FOURCC('K', 'B', 'C', ' '), + KBTS_LANGUAGE_KALENJIN = KBTS_FOURCC('K', 'A', 'L', ' '), + KBTS_LANGUAGE_KALMYK = KBTS_FOURCC('K', 'L', 'M', ' '), + KBTS_LANGUAGE_KAMBA = KBTS_FOURCC('K', 'M', 'B', ' '), + KBTS_LANGUAGE_KANAUJI = KBTS_FOURCC('B', 'J', 'J', ' '), + KBTS_LANGUAGE_KANNADA = KBTS_FOURCC('K', 'A', 'N', ' '), + KBTS_LANGUAGE_KANURI = KBTS_FOURCC('K', 'N', 'R', ' '), + KBTS_LANGUAGE_KAQCHIKEL = KBTS_FOURCC('C', 'A', 'K', ' '), + KBTS_LANGUAGE_KARACHAY = KBTS_FOURCC('K', 'A', 'R', ' '), + KBTS_LANGUAGE_KARAIM = KBTS_FOURCC('K', 'R', 'M', ' '), + KBTS_LANGUAGE_KARAKALPAK = KBTS_FOURCC('K', 'R', 'K', ' '), + KBTS_LANGUAGE_KARELIAN = KBTS_FOURCC('K', 'R', 'L', ' '), + KBTS_LANGUAGE_KAREN = KBTS_FOURCC('K', 'R', 'N', ' '), + KBTS_LANGUAGE_KASHMIRI = KBTS_FOURCC('K', 'S', 'H', ' '), + KBTS_LANGUAGE_KASHUBIAN = KBTS_FOURCC('C', 'S', 'B', ' '), + KBTS_LANGUAGE_KATE = KBTS_FOURCC('K', 'M', 'G', ' '), + KBTS_LANGUAGE_KAZAKH = KBTS_FOURCC('K', 'A', 'Z', ' '), + KBTS_LANGUAGE_KEBENA = KBTS_FOURCC('K', 'E', 'B', ' '), + KBTS_LANGUAGE_KEKCHI = KBTS_FOURCC('K', 'E', 'K', ' '), + KBTS_LANGUAGE_KHAKASS = KBTS_FOURCC('K', 'H', 'A', ' '), + KBTS_LANGUAGE_KHAMTI_SHAN = KBTS_FOURCC('K', 'H', 'T', ' '), + KBTS_LANGUAGE_KHAMYANG = KBTS_FOURCC('K', 'S', 'U', ' '), + KBTS_LANGUAGE_KHANTY_KAZIM = KBTS_FOURCC('K', 'H', 'K', ' '), + KBTS_LANGUAGE_KHANTY_SHURISHKAR = KBTS_FOURCC('K', 'H', 'S', ' '), + KBTS_LANGUAGE_KHANTY_VAKHI = KBTS_FOURCC('K', 'H', 'V', ' '), + KBTS_LANGUAGE_KHASI = KBTS_FOURCC('K', 'S', 'I', ' '), + KBTS_LANGUAGE_KHENGKHA = KBTS_FOURCC('X', 'K', 'F', ' '), + KBTS_LANGUAGE_KHINALUG = KBTS_FOURCC('K', 'J', 'J', ' '), + KBTS_LANGUAGE_KHMER = KBTS_FOURCC('K', 'H', 'M', ' '), + KBTS_LANGUAGE_KHORASANI_TURKIC = KBTS_FOURCC('K', 'M', 'Z', ' '), + KBTS_LANGUAGE_KHOWAR = KBTS_FOURCC('K', 'H', 'W', ' '), + KBTS_LANGUAGE_KHUTSURI_GEORGIAN = KBTS_FOURCC('K', 'G', 'E', ' '), + KBTS_LANGUAGE_KICHE = KBTS_FOURCC('Q', 'U', 'C', ' '), + KBTS_LANGUAGE_KIKONGO = KBTS_FOURCC('K', 'O', 'N', ' '), + KBTS_LANGUAGE_KILDIN_SAMI = KBTS_FOURCC('K', 'S', 'M', ' '), + KBTS_LANGUAGE_KINYARWANDA = KBTS_FOURCC('R', 'U', 'A', ' '), + KBTS_LANGUAGE_KIRMANJKI = KBTS_FOURCC('K', 'I', 'U', ' '), + KBTS_LANGUAGE_KISII = KBTS_FOURCC('K', 'I', 'S', ' '), + KBTS_LANGUAGE_KITUBA = KBTS_FOURCC('M', 'K', 'W', ' '), + KBTS_LANGUAGE_KODAGU = KBTS_FOURCC('K', 'O', 'D', ' '), + KBTS_LANGUAGE_KOKNI = KBTS_FOURCC('K', 'K', 'N', ' '), + KBTS_LANGUAGE_KOMI = KBTS_FOURCC('K', 'O', 'M', ' '), + KBTS_LANGUAGE_KOMI_PERMYAK = KBTS_FOURCC('K', 'O', 'P', ' '), + KBTS_LANGUAGE_KOMI_ZYRIAN = KBTS_FOURCC('K', 'O', 'Z', ' '), + KBTS_LANGUAGE_KOMO = KBTS_FOURCC('K', 'M', 'O', ' '), + KBTS_LANGUAGE_KOMSO = KBTS_FOURCC('K', 'M', 'S', ' '), + KBTS_LANGUAGE_KONGO = KBTS_FOURCC('K', 'O', 'N', '0'), + KBTS_LANGUAGE_KONKANI = KBTS_FOURCC('K', 'O', 'K', ' '), + KBTS_LANGUAGE_KOORETE = KBTS_FOURCC('K', 'R', 'T', ' '), + KBTS_LANGUAGE_KOREAN = KBTS_FOURCC('K', 'O', 'R', ' '), + KBTS_LANGUAGE_KOREAO_OLD_HANGUL = KBTS_FOURCC('K', 'O', 'H', ' '), + KBTS_LANGUAGE_KORYAK = KBTS_FOURCC('K', 'Y', 'K', ' '), + KBTS_LANGUAGE_KOSRAEAN = KBTS_FOURCC('K', 'O', 'S', ' '), + KBTS_LANGUAGE_KPELLE = KBTS_FOURCC('K', 'P', 'L', ' '), + KBTS_LANGUAGE_KPELLE_LIBERIA = KBTS_FOURCC('X', 'P', 'E', ' '), + KBTS_LANGUAGE_KRIO = KBTS_FOURCC('K', 'R', 'I', ' '), + KBTS_LANGUAGE_KRYMCHAK = KBTS_FOURCC('J', 'C', 'T', ' '), + KBTS_LANGUAGE_KUANYAMA = KBTS_FOURCC('K', 'U', 'A', ' '), + KBTS_LANGUAGE_KUBE = KBTS_FOURCC('K', 'G', 'F', ' '), + KBTS_LANGUAGE_KUI = KBTS_FOURCC('K', 'U', 'I', ' '), + KBTS_LANGUAGE_KULVI = KBTS_FOURCC('K', 'U', 'K', ' '), + KBTS_LANGUAGE_KUMAONI = KBTS_FOURCC('K', 'M', 'N', ' '), + KBTS_LANGUAGE_KUMYK = KBTS_FOURCC('K', 'U', 'M', ' '), + KBTS_LANGUAGE_KURDISH = KBTS_FOURCC('K', 'U', 'R', ' '), + KBTS_LANGUAGE_KURUKH = KBTS_FOURCC('K', 'U', 'U', ' '), + KBTS_LANGUAGE_KUY = KBTS_FOURCC('K', 'U', 'Y', ' '), + KBTS_LANGUAGE_KWAKWALA = KBTS_FOURCC('K', 'W', 'K', ' '), + KBTS_LANGUAGE_KYRGYZ = KBTS_FOURCC('K', 'I', 'R', ' '), + KBTS_LANGUAGE_L_CREE = KBTS_FOURCC('L', 'C', 'R', ' '), + KBTS_LANGUAGE_LADAKHI = KBTS_FOURCC('L', 'D', 'K', ' '), + KBTS_LANGUAGE_LADIN = KBTS_FOURCC('L', 'A', 'D', ' '), + KBTS_LANGUAGE_LADINO = KBTS_FOURCC('J', 'U', 'D', ' '), + KBTS_LANGUAGE_LAHULI = KBTS_FOURCC('L', 'A', 'H', ' '), + KBTS_LANGUAGE_LAK = KBTS_FOURCC('L', 'A', 'K', ' '), + KBTS_LANGUAGE_LAKI = KBTS_FOURCC('L', 'K', 'I', ' '), + KBTS_LANGUAGE_LAMBANI = KBTS_FOURCC('L', 'A', 'M', ' '), + KBTS_LANGUAGE_LAMPUNG = KBTS_FOURCC('L', 'J', 'P', ' '), + KBTS_LANGUAGE_LAO = KBTS_FOURCC('L', 'A', 'O', ' '), + KBTS_LANGUAGE_LATIN = KBTS_FOURCC('L', 'A', 'T', ' '), + KBTS_LANGUAGE_LATVIAN = KBTS_FOURCC('L', 'V', 'I', ' '), + KBTS_LANGUAGE_LAZ = KBTS_FOURCC('L', 'A', 'Z', ' '), + KBTS_LANGUAGE_LELEMI = KBTS_FOURCC('L', 'E', 'F', ' '), + KBTS_LANGUAGE_LEZGI = KBTS_FOURCC('L', 'E', 'Z', ' '), + KBTS_LANGUAGE_LIGURIAN = KBTS_FOURCC('L', 'I', 'J', ' '), + KBTS_LANGUAGE_LIMBU = KBTS_FOURCC('L', 'M', 'B', ' '), + KBTS_LANGUAGE_LIMBURGISH = KBTS_FOURCC('L', 'I', 'M', ' '), + KBTS_LANGUAGE_LINGALA = KBTS_FOURCC('L', 'I', 'N', ' '), + KBTS_LANGUAGE_LIPO = KBTS_FOURCC('L', 'P', 'O', ' '), + KBTS_LANGUAGE_LISU = KBTS_FOURCC('L', 'I', 'S', ' '), + KBTS_LANGUAGE_LITHUANIAN = KBTS_FOURCC('L', 'T', 'H', ' '), + KBTS_LANGUAGE_LIV = KBTS_FOURCC('L', 'I', 'V', ' '), + KBTS_LANGUAGE_LOJBAN = KBTS_FOURCC('J', 'B', 'O', ' '), + KBTS_LANGUAGE_LOMA = KBTS_FOURCC('L', 'O', 'M', ' '), + KBTS_LANGUAGE_LOMBARD = KBTS_FOURCC('L', 'M', 'O', ' '), + KBTS_LANGUAGE_LOMWE = KBTS_FOURCC('L', 'M', 'W', ' '), + KBTS_LANGUAGE_LOW_MARI = KBTS_FOURCC('L', 'M', 'A', ' '), + KBTS_LANGUAGE_LOW_SAXON = KBTS_FOURCC('N', 'D', 'S', ' '), + KBTS_LANGUAGE_LOWER_SORBIAN = KBTS_FOURCC('L', 'S', 'B', ' '), + KBTS_LANGUAGE_LU = KBTS_FOURCC('X', 'B', 'D', ' '), + KBTS_LANGUAGE_LUBA_KATANGA = KBTS_FOURCC('L', 'U', 'B', ' '), + KBTS_LANGUAGE_LUBA_LULUA = KBTS_FOURCC('L', 'U', 'A', ' '), + KBTS_LANGUAGE_LULE_SAMI = KBTS_FOURCC('L', 'S', 'M', ' '), + KBTS_LANGUAGE_LUO = KBTS_FOURCC('L', 'U', 'O', ' '), + KBTS_LANGUAGE_LURI = KBTS_FOURCC('L', 'R', 'C', ' '), + KBTS_LANGUAGE_LUSHOOTSEED = KBTS_FOURCC('L', 'U', 'T', ' '), + KBTS_LANGUAGE_LUXEMBOURGISH = KBTS_FOURCC('L', 'T', 'Z', ' '), + KBTS_LANGUAGE_LUYIA = KBTS_FOURCC('L', 'U', 'H', ' '), + KBTS_LANGUAGE_MACEDONIAN = KBTS_FOURCC('M', 'K', 'D', ' '), + KBTS_LANGUAGE_MADURA = KBTS_FOURCC('M', 'A', 'D', ' '), + KBTS_LANGUAGE_MAGAHI = KBTS_FOURCC('M', 'A', 'G', ' '), + KBTS_LANGUAGE_MAITHILI = KBTS_FOURCC('M', 'T', 'H', ' '), + KBTS_LANGUAGE_MAJANG = KBTS_FOURCC('M', 'A', 'J', ' '), + KBTS_LANGUAGE_MAKASAR = KBTS_FOURCC('M', 'K', 'R', ' '), + KBTS_LANGUAGE_MAKHUWA = KBTS_FOURCC('M', 'A', 'K', ' '), + KBTS_LANGUAGE_MAKONDE = KBTS_FOURCC('K', 'D', 'E', ' '), + KBTS_LANGUAGE_MALAGASY = KBTS_FOURCC('M', 'L', 'G', ' '), + KBTS_LANGUAGE_MALAY = KBTS_FOURCC('M', 'L', 'Y', ' '), + KBTS_LANGUAGE_MALAYALAM = KBTS_FOURCC('M', 'A', 'L', ' '), + KBTS_LANGUAGE_MALAYALAM_REFORMED = KBTS_FOURCC('M', 'L', 'R', ' '), + KBTS_LANGUAGE_MALE = KBTS_FOURCC('M', 'L', 'E', ' '), + KBTS_LANGUAGE_MALINKE = KBTS_FOURCC('M', 'L', 'N', ' '), + KBTS_LANGUAGE_MALTESE = KBTS_FOURCC('M', 'T', 'S', ' '), + KBTS_LANGUAGE_MAM = KBTS_FOURCC('M', 'A', 'M', ' '), + KBTS_LANGUAGE_MANCHU = KBTS_FOURCC('M', 'C', 'H', ' '), + KBTS_LANGUAGE_MANDAR = KBTS_FOURCC('M', 'D', 'R', ' '), + KBTS_LANGUAGE_MANDINKA = KBTS_FOURCC('M', 'N', 'D', ' '), + KBTS_LANGUAGE_MANINKA = KBTS_FOURCC('M', 'N', 'K', ' '), + KBTS_LANGUAGE_MANIPURI = KBTS_FOURCC('M', 'N', 'I', ' '), + KBTS_LANGUAGE_MANO = KBTS_FOURCC('M', 'E', 'V', ' '), + KBTS_LANGUAGE_MANSI = KBTS_FOURCC('M', 'A', 'N', ' '), + KBTS_LANGUAGE_MANX = KBTS_FOURCC('M', 'N', 'X', ' '), + KBTS_LANGUAGE_MAORI = KBTS_FOURCC('M', 'R', 'I', ' '), + KBTS_LANGUAGE_MAPUDUNGUN = KBTS_FOURCC('M', 'A', 'P', ' '), + KBTS_LANGUAGE_MARATHI = KBTS_FOURCC('M', 'A', 'R', ' '), + KBTS_LANGUAGE_MARSHALLESE = KBTS_FOURCC('M', 'A', 'H', ' '), + KBTS_LANGUAGE_MARWARI = KBTS_FOURCC('M', 'A', 'W', ' '), + KBTS_LANGUAGE_MAYAN = KBTS_FOURCC('M', 'Y', 'N', ' '), + KBTS_LANGUAGE_MAZANDERANI = KBTS_FOURCC('M', 'Z', 'N', ' '), + KBTS_LANGUAGE_MBEMBE_TIGON = KBTS_FOURCC('N', 'Z', 'A', ' '), + KBTS_LANGUAGE_MBO = KBTS_FOURCC('M', 'B', 'O', ' '), + KBTS_LANGUAGE_MBUNDU = KBTS_FOURCC('M', 'B', 'N', ' '), + KBTS_LANGUAGE_MEDUMBA = KBTS_FOURCC('B', 'Y', 'V', ' '), + KBTS_LANGUAGE_MEEN = KBTS_FOURCC('M', 'E', 'N', ' '), + KBTS_LANGUAGE_MENDE = KBTS_FOURCC('M', 'D', 'E', ' '), + KBTS_LANGUAGE_MERU = KBTS_FOURCC('M', 'E', 'R', ' '), + KBTS_LANGUAGE_MEWATI = KBTS_FOURCC('W', 'T', 'M', ' '), + KBTS_LANGUAGE_MINANGKABAU = KBTS_FOURCC('M', 'I', 'N', ' '), + KBTS_LANGUAGE_MINJANGBAL = KBTS_FOURCC('X', 'J', 'B', ' '), + KBTS_LANGUAGE_MIRANDESE = KBTS_FOURCC('M', 'W', 'L', ' '), + KBTS_LANGUAGE_MIZO = KBTS_FOURCC('M', 'I', 'Z', ' '), + KBTS_LANGUAGE_MOHAWK = KBTS_FOURCC('M', 'O', 'H', ' '), + KBTS_LANGUAGE_MOKSHA = KBTS_FOURCC('M', 'O', 'K', ' '), + KBTS_LANGUAGE_MOLDAVIAN = KBTS_FOURCC('M', 'O', 'L', ' '), + KBTS_LANGUAGE_MON = KBTS_FOURCC('M', 'O', 'N', ' '), + KBTS_LANGUAGE_MONGOLIAN = KBTS_FOURCC('M', 'N', 'G', ' '), + KBTS_LANGUAGE_MOOSE_CREE = KBTS_FOURCC('M', 'C', 'R', ' '), + KBTS_LANGUAGE_MORISYEN = KBTS_FOURCC('M', 'F', 'E', ' '), + KBTS_LANGUAGE_MOROCCAN = KBTS_FOURCC('M', 'O', 'R', ' '), + KBTS_LANGUAGE_MOSSI = KBTS_FOURCC('M', 'P', 'S', ' '), + KBTS_LANGUAGE_MUNDARI = KBTS_FOURCC('M', 'U', 'N', ' '), + KBTS_LANGUAGE_MUSCOGEE = KBTS_FOURCC('M', 'U', 'S', ' '), + KBTS_LANGUAGE_N_CREE = KBTS_FOURCC('N', 'C', 'R', ' '), + KBTS_LANGUAGE_NAGA_ASSAMESE = KBTS_FOURCC('N', 'A', 'G', ' '), + KBTS_LANGUAGE_NAGARI = KBTS_FOURCC('N', 'G', 'R', ' '), + KBTS_LANGUAGE_NAHUATL = KBTS_FOURCC('N', 'A', 'H', ' '), + KBTS_LANGUAGE_NANAI = KBTS_FOURCC('N', 'A', 'N', ' '), + KBTS_LANGUAGE_NASKAPI = KBTS_FOURCC('N', 'A', 'S', ' '), + KBTS_LANGUAGE_NAURUAN = KBTS_FOURCC('N', 'A', 'U', ' '), + KBTS_LANGUAGE_NAVAJO = KBTS_FOURCC('N', 'A', 'V', ' '), + KBTS_LANGUAGE_NDAU = KBTS_FOURCC('N', 'D', 'C', ' '), + KBTS_LANGUAGE_NDEBELE = KBTS_FOURCC('N', 'D', 'B', ' '), + KBTS_LANGUAGE_NDONGA = KBTS_FOURCC('N', 'D', 'G', ' '), + KBTS_LANGUAGE_NEAPOLITAN = KBTS_FOURCC('N', 'A', 'P', ' '), + KBTS_LANGUAGE_NEPALI = KBTS_FOURCC('N', 'E', 'P', ' '), + KBTS_LANGUAGE_NEWARI = KBTS_FOURCC('N', 'E', 'W', ' '), + KBTS_LANGUAGE_NGBAKA = KBTS_FOURCC('N', 'G', 'A', ' '), + KBTS_LANGUAGE_NIGERIAN_FULFULDE = KBTS_FOURCC('F', 'U', 'V', ' '), + KBTS_LANGUAGE_NIMADI = KBTS_FOURCC('N', 'O', 'E', ' '), + KBTS_LANGUAGE_NISI = KBTS_FOURCC('N', 'I', 'S', ' '), + KBTS_LANGUAGE_NIUEAN = KBTS_FOURCC('N', 'I', 'U', ' '), + KBTS_LANGUAGE_NKO = KBTS_FOURCC('N', 'K', 'O', ' '), + KBTS_LANGUAGE_NOGAI = KBTS_FOURCC('N', 'O', 'G', ' '), + KBTS_LANGUAGE_NORFOLK = KBTS_FOURCC('P', 'I', 'H', ' '), + KBTS_LANGUAGE_NORTH_SLAVEY = KBTS_FOURCC('S', 'C', 'S', ' '), + KBTS_LANGUAGE_NORTHERN_EMBERA = KBTS_FOURCC('E', 'M', 'P', ' '), + KBTS_LANGUAGE_NORTHERN_SAMI = KBTS_FOURCC('N', 'S', 'M', ' '), + KBTS_LANGUAGE_NORTHERN_SOTHO = KBTS_FOURCC('N', 'S', 'O', ' '), + KBTS_LANGUAGE_NORTHERN_TAI = KBTS_FOURCC('N', 'T', 'A', ' '), + KBTS_LANGUAGE_NORWAY_HOUSE_CREE = KBTS_FOURCC('N', 'H', 'C', ' '), + KBTS_LANGUAGE_NORWEGIAN = KBTS_FOURCC('N', 'O', 'R', ' '), + KBTS_LANGUAGE_NORWEGIAN_NYNORSK = KBTS_FOURCC('N', 'Y', 'N', ' '), + KBTS_LANGUAGE_NOVIAL = KBTS_FOURCC('N', 'O', 'V', ' '), + KBTS_LANGUAGE_NUMANGGANG = KBTS_FOURCC('N', 'O', 'P', ' '), + KBTS_LANGUAGE_NUNAVIK_INUKTITUT = KBTS_FOURCC('I', 'N', 'U', ' '), + KBTS_LANGUAGE_NUU_CHAH_NULTH = KBTS_FOURCC('N', 'U', 'K', ' '), + KBTS_LANGUAGE_NYAMWEZI = KBTS_FOURCC('N', 'Y', 'M', ' '), + KBTS_LANGUAGE_NYANKOLE = KBTS_FOURCC('N', 'K', 'L', ' '), + KBTS_LANGUAGE_OCCITAN = KBTS_FOURCC('O', 'C', 'I', ' '), + KBTS_LANGUAGE_ODIA = KBTS_FOURCC('O', 'R', 'I', ' '), + KBTS_LANGUAGE_OJI_CREE = KBTS_FOURCC('O', 'C', 'R', ' '), + KBTS_LANGUAGE_OJIBWAY = KBTS_FOURCC('O', 'J', 'B', ' '), + KBTS_LANGUAGE_OLD_IRISH = KBTS_FOURCC('S', 'G', 'A', ' '), + KBTS_LANGUAGE_OLD_JAVANESE = KBTS_FOURCC('K', 'A', 'W', ' '), + KBTS_LANGUAGE_ONEIDA = KBTS_FOURCC('O', 'N', 'E', ' '), + KBTS_LANGUAGE_ONONDAGA = KBTS_FOURCC('O', 'N', 'O', ' '), + KBTS_LANGUAGE_OROMO = KBTS_FOURCC('O', 'R', 'O', ' '), + KBTS_LANGUAGE_OSSETIAN = KBTS_FOURCC('O', 'S', 'S', ' '), + KBTS_LANGUAGE_PA_O_KAREN = KBTS_FOURCC('B', 'L', 'K', ' '), + KBTS_LANGUAGE_PALAUAN = KBTS_FOURCC('P', 'A', 'U', ' '), + KBTS_LANGUAGE_PALAUNG = KBTS_FOURCC('P', 'L', 'G', ' '), + KBTS_LANGUAGE_PALESTINIAN_ARAMAIC = KBTS_FOURCC('P', 'A', 'A', ' '), + KBTS_LANGUAGE_PALI = KBTS_FOURCC('P', 'A', 'L', ' '), + KBTS_LANGUAGE_PALPA = KBTS_FOURCC('P', 'A', 'P', ' '), + KBTS_LANGUAGE_PAMPANGAN = KBTS_FOURCC('P', 'A', 'M', ' '), + KBTS_LANGUAGE_PANGASINAN = KBTS_FOURCC('P', 'A', 'G', ' '), + KBTS_LANGUAGE_PAPIAMENTU = KBTS_FOURCC('P', 'A', 'P', '0'), + KBTS_LANGUAGE_PASHTO = KBTS_FOURCC('P', 'A', 'S', ' '), + KBTS_LANGUAGE_PATTANI_MALAY = KBTS_FOURCC('M', 'F', 'A', ' '), + KBTS_LANGUAGE_PENNSYLVANIA_GERMAN = KBTS_FOURCC('P', 'D', 'C', ' '), + KBTS_LANGUAGE_PERSIAN = KBTS_FOURCC('F', 'A', 'R', ' '), + KBTS_LANGUAGE_PHAKE = KBTS_FOURCC('P', 'J', 'K', ' '), + KBTS_LANGUAGE_PICARD = KBTS_FOURCC('P', 'C', 'D', ' '), + KBTS_LANGUAGE_PIEMONTESE = KBTS_FOURCC('P', 'M', 'S', ' '), + KBTS_LANGUAGE_PILAGA = KBTS_FOURCC('P', 'L', 'G', ' '), + KBTS_LANGUAGE_PITE_SAMI = KBTS_FOURCC('S', 'J', 'E', ' '), + KBTS_LANGUAGE_POCOMCHI = KBTS_FOURCC('P', 'O', 'H', ' '), + KBTS_LANGUAGE_POHNPEIAN = KBTS_FOURCC('P', 'O', 'N', ' '), + KBTS_LANGUAGE_POLISH = KBTS_FOURCC('P', 'L', 'K', ' '), + KBTS_LANGUAGE_POLYTONIC_GREEK = KBTS_FOURCC('P', 'G', 'R', ' '), + KBTS_LANGUAGE_PORTUGUESE = KBTS_FOURCC('P', 'T', 'G', ' '), + KBTS_LANGUAGE_PROVENCAL = KBTS_FOURCC('P', 'R', 'O', ' '), + KBTS_LANGUAGE_PUNJABI = KBTS_FOURCC('P', 'A', 'N', ' '), + KBTS_LANGUAGE_QUECHUA = KBTS_FOURCC('Q', 'U', 'Z', ' '), + KBTS_LANGUAGE_QUECHUA_BOLIVIA = KBTS_FOURCC('Q', 'U', 'H', ' '), + KBTS_LANGUAGE_QUECHUA_ECUADOR = KBTS_FOURCC('Q', 'V', 'I', ' '), + KBTS_LANGUAGE_QUECHUA_PERU = KBTS_FOURCC('Q', 'W', 'H', ' '), + KBTS_LANGUAGE_R_CREE = KBTS_FOURCC('R', 'C', 'R', ' '), + KBTS_LANGUAGE_RAJASTHANI = KBTS_FOURCC('R', 'A', 'J', ' '), + KBTS_LANGUAGE_RAKHINE = KBTS_FOURCC('A', 'R', 'K', ' '), + KBTS_LANGUAGE_RAROTONGAN = KBTS_FOURCC('R', 'A', 'R', ' '), + KBTS_LANGUAGE_REJANG = KBTS_FOURCC('R', 'E', 'J', ' '), + KBTS_LANGUAGE_RIANG = KBTS_FOURCC('R', 'I', 'A', ' '), + KBTS_LANGUAGE_RIPUARIAN = KBTS_FOURCC('K', 'S', 'H', ' '), + KBTS_LANGUAGE_RITARUNGO = KBTS_FOURCC('R', 'I', 'T', ' '), + KBTS_LANGUAGE_ROHINGYA = KBTS_FOURCC('R', 'H', 'G', ' '), + KBTS_LANGUAGE_ROMANIAN = KBTS_FOURCC('R', 'O', 'M', ' '), + KBTS_LANGUAGE_ROMANSH = KBTS_FOURCC('R', 'M', 'S', ' '), + KBTS_LANGUAGE_ROMANY = KBTS_FOURCC('R', 'O', 'Y', ' '), + KBTS_LANGUAGE_ROTUMAN = KBTS_FOURCC('R', 'T', 'M', ' '), + KBTS_LANGUAGE_RUNDI = KBTS_FOURCC('R', 'U', 'N', ' '), + KBTS_LANGUAGE_RUSSIAN = KBTS_FOURCC('R', 'U', 'S', ' '), + KBTS_LANGUAGE_RUSSIAN_BURIAT = KBTS_FOURCC('R', 'B', 'U', ' '), + KBTS_LANGUAGE_RUSYN = KBTS_FOURCC('R', 'S', 'Y', ' '), + KBTS_LANGUAGE_SADRI = KBTS_FOURCC('S', 'A', 'D', ' '), + KBTS_LANGUAGE_SAKHA = KBTS_FOURCC('Y', 'A', 'K', ' '), + KBTS_LANGUAGE_SAMOAN = KBTS_FOURCC('S', 'M', 'O', ' '), + KBTS_LANGUAGE_SAMOGITIAN = KBTS_FOURCC('S', 'G', 'S', ' '), + KBTS_LANGUAGE_SAN_BLAS_KUNA = KBTS_FOURCC('C', 'U', 'K', ' '), + KBTS_LANGUAGE_SANGO = KBTS_FOURCC('S', 'G', 'O', ' '), + KBTS_LANGUAGE_SANSKRIT = KBTS_FOURCC('S', 'A', 'N', ' '), + KBTS_LANGUAGE_SANTALI = KBTS_FOURCC('S', 'A', 'T', ' '), + KBTS_LANGUAGE_SARAIKI = KBTS_FOURCC('S', 'R', 'K', ' '), + KBTS_LANGUAGE_SARDINIAN = KBTS_FOURCC('S', 'R', 'D', ' '), + KBTS_LANGUAGE_SASAK = KBTS_FOURCC('S', 'A', 'S', ' '), + KBTS_LANGUAGE_SATERLAND_FRISIAN = KBTS_FOURCC('S', 'T', 'Q', ' '), + KBTS_LANGUAGE_SAYISI = KBTS_FOURCC('S', 'A', 'Y', ' '), + KBTS_LANGUAGE_SCOTS = KBTS_FOURCC('S', 'C', 'I', ' '), + KBTS_LANGUAGE_SCOTTISH_GAELIC = KBTS_FOURCC('G', 'A', 'E', ' '), + KBTS_LANGUAGE_SEKOTA = KBTS_FOURCC('S', 'E', 'J', ' '), + KBTS_LANGUAGE_SELKUP = KBTS_FOURCC('S', 'E', 'L', ' '), + KBTS_LANGUAGE_SENA = KBTS_FOURCC('S', 'N', 'A', ' '), + KBTS_LANGUAGE_SENECA = KBTS_FOURCC('S', 'E', 'E', ' '), + KBTS_LANGUAGE_SERBIAN = KBTS_FOURCC('S', 'R', 'B', ' '), + KBTS_LANGUAGE_SERER = KBTS_FOURCC('S', 'R', 'R', ' '), + KBTS_LANGUAGE_SGAW_KAREN = KBTS_FOURCC('K', 'S', 'W', ' '), + KBTS_LANGUAGE_SHAN = KBTS_FOURCC('S', 'H', 'N', ' '), + KBTS_LANGUAGE_SHONA = KBTS_FOURCC('S', 'N', 'A', ' '), + KBTS_LANGUAGE_SIBE = KBTS_FOURCC('S', 'I', 'B', ' '), + KBTS_LANGUAGE_SICILIAN = KBTS_FOURCC('S', 'C', 'N', ' '), + KBTS_LANGUAGE_SIDAMO = KBTS_FOURCC('S', 'I', 'D', ' '), + KBTS_LANGUAGE_SILESIAN = KBTS_FOURCC('S', 'Z', 'L', ' '), + KBTS_LANGUAGE_SILTE_GURAGE = KBTS_FOURCC('S', 'I', 'G', ' '), + KBTS_LANGUAGE_SINDHI = KBTS_FOURCC('S', 'N', 'D', ' '), + KBTS_LANGUAGE_SINHALA = KBTS_FOURCC('S', 'N', 'H', ' '), + KBTS_LANGUAGE_SKOLT_SAMI = KBTS_FOURCC('S', 'K', 'S', ' '), + KBTS_LANGUAGE_SLAVEY = KBTS_FOURCC('S', 'L', 'A', ' '), + KBTS_LANGUAGE_SLOVAK = KBTS_FOURCC('S', 'K', 'Y', ' '), + KBTS_LANGUAGE_SLOVENIAN = KBTS_FOURCC('S', 'L', 'V', ' '), + KBTS_LANGUAGE_SMALL_FLOWERY_MIAO = KBTS_FOURCC('S', 'F', 'M', ' '), + KBTS_LANGUAGE_SODO_GURAGE = KBTS_FOURCC('S', 'O', 'G', ' '), + KBTS_LANGUAGE_SOGA = KBTS_FOURCC('X', 'O', 'G', ' '), + KBTS_LANGUAGE_SOMALI = KBTS_FOURCC('S', 'M', 'L', ' '), + KBTS_LANGUAGE_SONGE = KBTS_FOURCC('S', 'O', 'P', ' '), + KBTS_LANGUAGE_SONINKE = KBTS_FOURCC('S', 'N', 'K', ' '), + KBTS_LANGUAGE_SOUTH_SLAVEY = KBTS_FOURCC('S', 'S', 'L', ' '), + KBTS_LANGUAGE_SOUTHERN_KIWAI = KBTS_FOURCC('K', 'J', 'D', ' '), + KBTS_LANGUAGE_SOUTHERN_SAMI = KBTS_FOURCC('S', 'S', 'M', ' '), + KBTS_LANGUAGE_SOUTHERN_SOTHO = KBTS_FOURCC('S', 'O', 'T', ' '), + KBTS_LANGUAGE_SPANISH = KBTS_FOURCC('E', 'S', 'P', ' '), + KBTS_LANGUAGE_STANDARD_MOROCCAN_TAMAZIGHT = KBTS_FOURCC('Z', 'G', 'H', ' '), + KBTS_LANGUAGE_STRAITS_SALISH = KBTS_FOURCC('S', 'T', 'R', ' '), + KBTS_LANGUAGE_SUKUMA = KBTS_FOURCC('S', 'U', 'K', ' '), + KBTS_LANGUAGE_SUNDANESE = KBTS_FOURCC('S', 'U', 'N', ' '), + KBTS_LANGUAGE_SURI = KBTS_FOURCC('S', 'U', 'R', ' '), + KBTS_LANGUAGE_SUTU = KBTS_FOURCC('S', 'X', 'T', ' '), + KBTS_LANGUAGE_SVAN = KBTS_FOURCC('S', 'V', 'A', ' '), + KBTS_LANGUAGE_SWADAYA_ARAMAIC = KBTS_FOURCC('S', 'W', 'A', ' '), + KBTS_LANGUAGE_SWAHILI = KBTS_FOURCC('S', 'W', 'K', ' '), + KBTS_LANGUAGE_SWATI = KBTS_FOURCC('S', 'W', 'Z', ' '), + KBTS_LANGUAGE_SWEDISH = KBTS_FOURCC('S', 'V', 'E', ' '), + KBTS_LANGUAGE_SYLHETI = KBTS_FOURCC('S', 'Y', 'L', ' '), + KBTS_LANGUAGE_SYRIAC = KBTS_FOURCC('S', 'Y', 'R', ' '), + KBTS_LANGUAGE_SYRIAC_EASTERN = KBTS_FOURCC('S', 'Y', 'R', 'N'), + KBTS_LANGUAGE_SYRIAC_ESTRANGELA = KBTS_FOURCC('S', 'Y', 'R', 'E'), + KBTS_LANGUAGE_SYRIAC_WESTERN = KBTS_FOURCC('S', 'Y', 'R', 'J'), + KBTS_LANGUAGE_TABASARAN = KBTS_FOURCC('T', 'A', 'B', ' '), + KBTS_LANGUAGE_TACHELHIT = KBTS_FOURCC('S', 'H', 'I', ' '), + KBTS_LANGUAGE_TAGALOG = KBTS_FOURCC('T', 'G', 'L', ' '), + KBTS_LANGUAGE_TAHAGGART_TAMAHAQ = KBTS_FOURCC('T', 'H', 'V', ' '), + KBTS_LANGUAGE_TAHITIAN = KBTS_FOURCC('T', 'H', 'T', ' '), + KBTS_LANGUAGE_TAI_LAING = KBTS_FOURCC('T', 'J', 'L', ' '), + KBTS_LANGUAGE_TAJIKI = KBTS_FOURCC('T', 'A', 'J', ' '), + KBTS_LANGUAGE_TALYSH = KBTS_FOURCC('T', 'L', 'Y', ' '), + KBTS_LANGUAGE_TAMASHEK = KBTS_FOURCC('T', 'M', 'H', ' '), + KBTS_LANGUAGE_TAMASHEQ = KBTS_FOURCC('T', 'A', 'Q', ' '), + KBTS_LANGUAGE_TAMAZIGHT = KBTS_FOURCC('T', 'Z', 'M', ' '), + KBTS_LANGUAGE_TAMIL = KBTS_FOURCC('T', 'A', 'M', ' '), + KBTS_LANGUAGE_TARIFIT = KBTS_FOURCC('R', 'I', 'F', ' '), + KBTS_LANGUAGE_TATAR = KBTS_FOURCC('T', 'A', 'T', ' '), + KBTS_LANGUAGE_TAWALLAMMAT_TAMAJAQ = KBTS_FOURCC('T', 'T', 'Q', ' '), + KBTS_LANGUAGE_TAY = KBTS_FOURCC('T', 'Y', 'Z', ' '), + KBTS_LANGUAGE_TAYART_TAMAJEQ = KBTS_FOURCC('T', 'H', 'Z', ' '), + KBTS_LANGUAGE_TELUGU = KBTS_FOURCC('T', 'E', 'L', ' '), + KBTS_LANGUAGE_TEMNE = KBTS_FOURCC('T', 'M', 'N', ' '), + KBTS_LANGUAGE_TETUM = KBTS_FOURCC('T', 'E', 'T', ' '), + KBTS_LANGUAGE_TH_CREE = KBTS_FOURCC('T', 'C', 'R', ' '), + KBTS_LANGUAGE_THAI = KBTS_FOURCC('T', 'H', 'A', ' '), + KBTS_LANGUAGE_THAILAND_MON = KBTS_FOURCC('M', 'O', 'N', 'T'), + KBTS_LANGUAGE_THOMPSON = KBTS_FOURCC('T', 'H', 'P', ' '), + KBTS_LANGUAGE_TIBETAN = KBTS_FOURCC('T', 'I', 'B', ' '), + KBTS_LANGUAGE_TIGRE = KBTS_FOURCC('T', 'G', 'R', ' '), + KBTS_LANGUAGE_TIGRINYA = KBTS_FOURCC('T', 'G', 'Y', ' '), + KBTS_LANGUAGE_TIV = KBTS_FOURCC('T', 'I', 'V', ' '), + KBTS_LANGUAGE_TLINGIT = KBTS_FOURCC('T', 'L', 'I', ' '), + KBTS_LANGUAGE_TOBO = KBTS_FOURCC('T', 'B', 'V', ' '), + KBTS_LANGUAGE_TODO = KBTS_FOURCC('T', 'O', 'D', ' '), + KBTS_LANGUAGE_TOK_PISIN = KBTS_FOURCC('T', 'P', 'I', ' '), + KBTS_LANGUAGE_TOMA = KBTS_FOURCC('T', 'O', 'D', '0'), + KBTS_LANGUAGE_TONGA = KBTS_FOURCC('T', 'N', 'G', ' '), + KBTS_LANGUAGE_TONGAN = KBTS_FOURCC('T', 'G', 'N', ' '), + KBTS_LANGUAGE_TORKI = KBTS_FOURCC('A', 'Z', 'B', ' '), + KBTS_LANGUAGE_TSHANGLA = KBTS_FOURCC('T', 'S', 'J', ' '), + KBTS_LANGUAGE_TSONGA = KBTS_FOURCC('T', 'S', 'G', ' '), + KBTS_LANGUAGE_TSWANA = KBTS_FOURCC('T', 'N', 'A', ' '), + KBTS_LANGUAGE_TULU = KBTS_FOURCC('T', 'U', 'L', ' '), + KBTS_LANGUAGE_TUMBUKA = KBTS_FOURCC('T', 'U', 'M', ' '), + KBTS_LANGUAGE_TUNDRA_ENETS = KBTS_FOURCC('T', 'N', 'E', ' '), + KBTS_LANGUAGE_TURKISH = KBTS_FOURCC('T', 'R', 'K', ' '), + KBTS_LANGUAGE_TURKMEN = KBTS_FOURCC('T', 'K', 'M', ' '), + KBTS_LANGUAGE_TUROYO_ARAMAIC = KBTS_FOURCC('T', 'U', 'A', ' '), + KBTS_LANGUAGE_TUSCARORA = KBTS_FOURCC('T', 'U', 'S', ' '), + KBTS_LANGUAGE_TUVALU = KBTS_FOURCC('T', 'V', 'L', ' '), + KBTS_LANGUAGE_TUVIN = KBTS_FOURCC('T', 'U', 'V', ' '), + KBTS_LANGUAGE_TWI = KBTS_FOURCC('T', 'W', 'I', ' '), + KBTS_LANGUAGE_TZOTZIL = KBTS_FOURCC('T', 'Z', 'O', ' '), + KBTS_LANGUAGE_UDI = KBTS_FOURCC('U', 'D', 'I', ' '), + KBTS_LANGUAGE_UDMURT = KBTS_FOURCC('U', 'D', 'M', ' '), + KBTS_LANGUAGE_UKRAINIAN = KBTS_FOURCC('U', 'K', 'R', ' '), + KBTS_LANGUAGE_UMBUNDU = KBTS_FOURCC('U', 'M', 'B', ' '), + KBTS_LANGUAGE_UME_SAMI = KBTS_FOURCC('S', 'J', 'U', ' '), + KBTS_LANGUAGE_UPPER_SAXON = KBTS_FOURCC('S', 'X', 'U', ' '), + KBTS_LANGUAGE_UPPER_SORBIAN = KBTS_FOURCC('U', 'S', 'B', ' '), + KBTS_LANGUAGE_URALIC_PHONETIC = KBTS_FOURCC('U', 'P', 'P', ' '), + KBTS_LANGUAGE_URDU = KBTS_FOURCC('U', 'R', 'D', ' '), + KBTS_LANGUAGE_UYGHUR = KBTS_FOURCC('U', 'Y', 'G', ' '), + KBTS_LANGUAGE_UZBEK = KBTS_FOURCC('U', 'Z', 'B', ' '), + KBTS_LANGUAGE_VENDA = KBTS_FOURCC('V', 'E', 'N', ' '), + KBTS_LANGUAGE_VENETIAN = KBTS_FOURCC('V', 'E', 'C', ' '), + KBTS_LANGUAGE_VIETNAMESE = KBTS_FOURCC('V', 'I', 'T', ' '), + KBTS_LANGUAGE_VLAX_ROMANI = KBTS_FOURCC('R', 'M', 'Y', ' '), + KBTS_LANGUAGE_VOLAPUK = KBTS_FOURCC('V', 'O', 'L', ' '), + KBTS_LANGUAGE_VORO = KBTS_FOURCC('V', 'R', 'O', ' '), + KBTS_LANGUAGE_WA = KBTS_FOURCC('W', 'A', ' ', ' '), + KBTS_LANGUAGE_WACI_GBE = KBTS_FOURCC('W', 'C', 'I', ' '), + KBTS_LANGUAGE_WAGDI = KBTS_FOURCC('W', 'A', 'G', ' '), + KBTS_LANGUAGE_WAKHI = KBTS_FOURCC('W', 'B', 'L', ' '), + KBTS_LANGUAGE_WALLOON = KBTS_FOURCC('W', 'L', 'N', ' '), + KBTS_LANGUAGE_WARAY_WARAY = KBTS_FOURCC('W', 'A', 'R', ' '), + KBTS_LANGUAGE_WAYANAD_CHETTI = KBTS_FOURCC('C', 'T', 'T', ' '), + KBTS_LANGUAGE_WAYUU = KBTS_FOURCC('G', 'U', 'C', ' '), + KBTS_LANGUAGE_WELSH = KBTS_FOURCC('W', 'E', 'L', ' '), + KBTS_LANGUAGE_WENDAT = KBTS_FOURCC('W', 'D', 'T', ' '), + KBTS_LANGUAGE_WEST_CREE = KBTS_FOURCC('W', 'C', 'R', ' '), + KBTS_LANGUAGE_WESTERN_CHAM = KBTS_FOURCC('C', 'J', 'A', ' '), + KBTS_LANGUAGE_WESTERN_KAYAH = KBTS_FOURCC('K', 'Y', 'U', ' '), + KBTS_LANGUAGE_WESTERN_PANJABI = KBTS_FOURCC('P', 'N', 'B', ' '), + KBTS_LANGUAGE_WESTERN_PWO_KAREN = KBTS_FOURCC('P', 'W', 'O', ' '), + KBTS_LANGUAGE_WOLOF = KBTS_FOURCC('W', 'L', 'F', ' '), + KBTS_LANGUAGE_WOODS_CREE = KBTS_FOURCC('D', 'C', 'R', ' '), + KBTS_LANGUAGE_WUDING_LUQUAN_YI = KBTS_FOURCC('Y', 'W', 'Q', ' '), + KBTS_LANGUAGE_WYANDOT = KBTS_FOURCC('W', 'Y', 'N', ' '), + KBTS_LANGUAGE_XHOSA = KBTS_FOURCC('X', 'H', 'S', ' '), + KBTS_LANGUAGE_Y_CREE = KBTS_FOURCC('Y', 'C', 'R', ' '), + KBTS_LANGUAGE_YAO = KBTS_FOURCC('Y', 'A', 'O', ' '), + KBTS_LANGUAGE_YAPESE = KBTS_FOURCC('Y', 'A', 'P', ' '), + KBTS_LANGUAGE_YI_CLASSIC = KBTS_FOURCC('Y', 'I', 'C', ' '), + KBTS_LANGUAGE_YI_MODERN = KBTS_FOURCC('Y', 'I', 'M', ' '), + KBTS_LANGUAGE_YIDDISH = KBTS_FOURCC('J', 'I', 'I', ' '), + KBTS_LANGUAGE_YORUBA = KBTS_FOURCC('Y', 'B', 'A', ' '), + KBTS_LANGUAGE_ZAMBOANGA_CHAVACANO = KBTS_FOURCC('C', 'B', 'K', ' '), + KBTS_LANGUAGE_ZANDE = KBTS_FOURCC('Z', 'N', 'D', ' '), + KBTS_LANGUAGE_ZARMA = KBTS_FOURCC('D', 'J', 'R', ' '), + KBTS_LANGUAGE_ZAZAKI = KBTS_FOURCC('Z', 'Z', 'A', ' '), + KBTS_LANGUAGE_ZEALANDIC = KBTS_FOURCC('Z', 'E', 'A', ' '), + KBTS_LANGUAGE_ZHUANG = KBTS_FOURCC('Z', 'H', 'A', ' '), + KBTS_LANGUAGE_ZULU = KBTS_FOURCC('Z', 'U', 'L', ' '), +}; + +typedef kbts_u32 kbts_break_flags; +enum kbts_break_flags_enum +{ + // Direction changes from left-to-right to right-to-left, or vice versa. + KBTS_BREAK_FLAG_DIRECTION = 1 << 0, + // Script changes. + // Note that some characters, such as digits, are used in multiple + // scripts and, as such, will not produce script breaks. + KBTS_BREAK_FLAG_SCRIPT = 1 << 1, + // Graphemes are "visual units". They may be composed of more than one codepoint. + // They are used as interaction boundaries in graphical interfaces, e.g. moving the + // caret. + KBTS_BREAK_FLAG_GRAPHEME = 1 << 2, + // In most scripts, words are broken up by whitespace, but Unicode word breaking has + // better script coverage and also handles some special cases that a simple stateless + // loop cannot handle. + KBTS_BREAK_FLAG_WORD = 1 << 3, + // By default, you are not allowed to break a line. + // Soft line breaks allow for line breaking, but do not require it. + // This is useful for when you are doing line wrapping. + KBTS_BREAK_FLAG_LINE_SOFT = 1 << 4, + // Hard line breaks are required. They signal the end of a paragraph. + // (In Unicode, there is no meaningful distinction between a line and a paragraph. + // a paragraph is pretty much just a line of text that can wrap.) + KBTS_BREAK_FLAG_LINE_HARD = 1 << 5, + + KBTS_BREAK_FLAG_LINE = KBTS_BREAK_FLAG_LINE_SOFT | KBTS_BREAK_FLAG_LINE_HARD, + KBTS_BREAK_FLAG_ANY = KBTS_BREAK_FLAG_DIRECTION | KBTS_BREAK_FLAG_SCRIPT | KBTS_BREAK_FLAG_GRAPHEME | KBTS_BREAK_FLAG_WORD | KBTS_BREAK_FLAG_LINE_SOFT | KBTS_BREAK_FLAG_LINE_HARD, +}; + +typedef kbts_u8 kbts_op_kind; +enum kbts_op_kind_enum +{ + KBTS_OP_KIND_END, + + // Substitution ops. + KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, + KBTS_OP_KIND_NORMALIZE, + KBTS_OP_KIND_NORMALIZE_HANGUL, + KBTS_OP_KIND_FLAG_JOINING_LETTERS, + KBTS_OP_KIND_GSUB_FEATURES, + KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, + + // Positioning ops. + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, + + KBTS_OP_KIND_POST_GPOS_FIXUP, + KBTS_OP_KIND_STCH_POSTPASS, + + KBTS_OP_KIND_COUNT, +}; + +typedef kbts_u32 kbts_glyph_flags; +enum kbts_glyph_flags_enum +{ + // These feature flags must coincide with kbts_joining_feature _and_ KBTS_FEATURE_FLAG! + KBTS_GLYPH_FLAG_ISOL = (1 << 0), + KBTS_GLYPH_FLAG_FINA = (1 << 1), + KBTS_GLYPH_FLAG_FIN2 = (1 << 2), + KBTS_GLYPH_FLAG_FIN3 = (1 << 3), + KBTS_GLYPH_FLAG_MEDI = (1 << 4), + KBTS_GLYPH_FLAG_MED2 = (1 << 5), + KBTS_GLYPH_FLAG_INIT = (1 << 6), + + // These feature flags must coincide with FEATURE_FLAG! + KBTS_GLYPH_FLAG_LJMO = (1 << 7), + KBTS_GLYPH_FLAG_VJMO = (1 << 8), + KBTS_GLYPH_FLAG_TJMO = (1 << 9), + KBTS_GLYPH_FLAG_RPHF = (1 << 10), + KBTS_GLYPH_FLAG_BLWF = (1 << 11), + KBTS_GLYPH_FLAG_HALF = (1 << 12), + KBTS_GLYPH_FLAG_PSTF = (1 << 13), + KBTS_GLYPH_FLAG_ABVF = (1 << 14), + KBTS_GLYPH_FLAG_PREF = (1 << 15), + KBTS_GLYPH_FLAG_NUMR = (1 << 16), + KBTS_GLYPH_FLAG_FRAC = (1 << 17), + KBTS_GLYPH_FLAG_DNOM = (1 << 18), + KBTS_GLYPH_FLAG_CFAR = (1 << 19), + + // These can be anything. + KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE = (1 << 21), + KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION = (1 << 22), + KBTS_GLYPH_FLAG_NO_BREAK = (1 << 23), + KBTS_GLYPH_FLAG_CURSIVE = (1 << 24), + KBTS_GLYPH_FLAG_GENERATED_BY_GSUB = (1 << 25), + KBTS_GLYPH_FLAG_USED_IN_GPOS = (1 << 26), + + KBTS_GLYPH_FLAG_STCH_ENDPOINT = (1 << 27), + KBTS_GLYPH_FLAG_STCH_EXTENSION = (1 << 28), + + KBTS_GLYPH_FLAG_LIGATURE = (1 << 29), + KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION = (1 << 30), +}; +#define KBTS_GLYPH_FEATURE_MASK ((KBTS_GLYPH_FLAG_CFAR << 1) - 1) +// In USE, glyphs are mostly not pre-flagged for feature application. +// However, we do want to flag rphf/pref results for reordering, so we want to +// keep all of the flags as usual, and only use these feature flags for filtering. +#define KBTS_USE_GLYPH_FEATURE_MASK (KBTS_GLYPH_FLAG_ISOL | KBTS_GLYPH_FLAG_FINA | KBTS_GLYPH_FLAG_FIN2 | KBTS_GLYPH_FLAG_FIN3 | \ + KBTS_GLYPH_FLAG_MEDI | KBTS_GLYPH_FLAG_MED2 | KBTS_GLYPH_FLAG_INIT | KBTS_GLYPH_FLAG_NUMR | \ + KBTS_GLYPH_FLAG_DNOM | KBTS_GLYPH_FLAG_FRAC) +#define KBTS_JOINING_FEATURE_MASK (KBTS_GLYPH_FLAG_ISOL | KBTS_GLYPH_FLAG_FINA | KBTS_GLYPH_FLAG_FIN2 | KBTS_GLYPH_FLAG_FIN3 | \ + KBTS_GLYPH_FLAG_MEDI | KBTS_GLYPH_FLAG_MED2 | KBTS_GLYPH_FLAG_INIT) +#define KBTS_JOINING_FEATURE_TO_GLYPH_FLAG(Feature) (1 << ((Feature) - 1)) + +// Japanese text contains "kinsoku" characters, around which breaking a line is forbidden. +// Exactly which characters are "kinsoku" or not depends on the context: +// - Strict style has the largest amount of kinsoku characters, which leads to longer lines. +// - Loose style has the smallest amount of kinsoku characters, which leads to smaller lines. +// - Normal style is somewhere in the middle. +// Note that, while the Unicode standard mentions all three of these styles, it does not mention +// any differences between the normal and loose styles. +// As such, normal and loose styles currently behave the same. +typedef kbts_u8 kbts_japanese_line_break_style; +enum kbts_japanese_line_break_style_enum +{ + // The Unicode standard does not define what strict style is used for. + // Supposedly, it is used for anything that does not fall into the other two categories of text. + KBTS_JAPANESE_LINE_BREAK_STYLE_STRICT, + + // Normal style is used for books and documents. + KBTS_JAPANESE_LINE_BREAK_STYLE_NORMAL, + + // Loose style is used for newspapers, and (I assume) any other narrow column format. + KBTS_JAPANESE_LINE_BREAK_STYLE_LOOSE, + + KBTS_JAPANESE_LINE_BREAK_STYLE_COUNT, +}; + +typedef kbts_u32 kbts_orientation; +enum kbts_orientation_enum +{ + KBTS_ORIENTATION_HORIZONTAL, + KBTS_ORIENTATION_VERTICAL, + + KBTS_ORIENTATION_COUNT, +}; + +typedef kbts_u32 kbts_direction; +enum kbts_direction_enum +{ + KBTS_DIRECTION_NONE, + KBTS_DIRECTION_LTR, + KBTS_DIRECTION_RTL, + + KBTS_DIRECTION_COUNT, +}; + +typedef kbts_u8 kbts_unicode_joining_type; +enum kbts_unicode_joining_type_enum +{ + KBTS_UNICODE_JOINING_TYPE_NONE, + KBTS_UNICODE_JOINING_TYPE_LEFT, + KBTS_UNICODE_JOINING_TYPE_DUAL, + KBTS_UNICODE_JOINING_TYPE_FORCE, + KBTS_UNICODE_JOINING_TYPE_RIGHT, + KBTS_UNICODE_JOINING_TYPE_TRANSPARENT, + KBTS_UNICODE_JOINING_TYPE_COUNT, +}; + +typedef kbts_u8 kbts_unicode_flags; +enum kbts_unicode_flag_enum +{ + KBTS_UNICODE_FLAG_MODIFIER_COMBINING_MARK = (1 << 0), + KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE = (1 << 1), + KBTS_UNICODE_FLAG_OPEN_BRACKET = (1 << 2), + KBTS_UNICODE_FLAG_CLOSE_BRACKET = (1 << 3), + KBTS_UNICODE_FLAG_PART_OF_WORD = (1 << 4), + KBTS_UNICODE_FLAG_DECIMAL_DIGIT = (1 << 5), + KBTS_UNICODE_FLAG_NON_SPACING_MARK = (1 << 6), +}; + +typedef kbts_u8 kbts_unicode_bidirectional_class; +enum kbts_unicode_bidirectional_class_enum +{ + KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_L, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_R, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_NSM, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_AL, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_ES, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_ET, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS, + KBTS_UNICODE_BIDIRECTIONAL_CLASS_COUNT, +}; + +typedef kbts_u8 kbts_line_break_class; +enum kbts_line_break_class_enum +{ + /* 0 */ KBTS_LINE_BREAK_CLASS_Onea, + /* 1 */ KBTS_LINE_BREAK_CLASS_Oea, + /* 2 */ KBTS_LINE_BREAK_CLASS_Ope, + /* 3 */ KBTS_LINE_BREAK_CLASS_BK, + /* 4 */ KBTS_LINE_BREAK_CLASS_CR, + /* 5 */ KBTS_LINE_BREAK_CLASS_LF, + /* 6 */ KBTS_LINE_BREAK_CLASS_NL, + /* 7 */ KBTS_LINE_BREAK_CLASS_SP, + /* 8 */ KBTS_LINE_BREAK_CLASS_ZW, + /* 9 */ KBTS_LINE_BREAK_CLASS_WJ, + /* 10 */ KBTS_LINE_BREAK_CLASS_GLnea, + /* 11 */ KBTS_LINE_BREAK_CLASS_GLea, + /* 12 */ KBTS_LINE_BREAK_CLASS_CLnea, + /* 13 */ KBTS_LINE_BREAK_CLASS_CLea, + /* 14 */ KBTS_LINE_BREAK_CLASS_CPnea, + /* 15 */ KBTS_LINE_BREAK_CLASS_CPea, + /* 16 */ KBTS_LINE_BREAK_CLASS_EXnea, + /* 17 */ KBTS_LINE_BREAK_CLASS_EXea, + /* 18 */ KBTS_LINE_BREAK_CLASS_SY, + /* 19 */ KBTS_LINE_BREAK_CLASS_BAnea, + /* 20 */ KBTS_LINE_BREAK_CLASS_BAea, + /* 21 */ KBTS_LINE_BREAK_CLASS_OPnea, + /* 22 */ KBTS_LINE_BREAK_CLASS_OPea, + /* 23 */ KBTS_LINE_BREAK_CLASS_QU, + /* 24 */ KBTS_LINE_BREAK_CLASS_QUPi, + /* 25 */ KBTS_LINE_BREAK_CLASS_QUPf, + /* 26 */ KBTS_LINE_BREAK_CLASS_IS, + /* 27 */ KBTS_LINE_BREAK_CLASS_NSnea, + /* 28 */ KBTS_LINE_BREAK_CLASS_NSea, + /* 29 */ KBTS_LINE_BREAK_CLASS_B2, + /* 30 */ KBTS_LINE_BREAK_CLASS_CB, + /* 31 */ KBTS_LINE_BREAK_CLASS_HY, + /* 32 */ KBTS_LINE_BREAK_CLASS_HYPHEN, + /* 33 */ KBTS_LINE_BREAK_CLASS_INnea, + /* 34 */ KBTS_LINE_BREAK_CLASS_INea, + /* 35 */ KBTS_LINE_BREAK_CLASS_BB, + /* 36 */ KBTS_LINE_BREAK_CLASS_HL, + /* 37 */ KBTS_LINE_BREAK_CLASS_ALnea, + /* 38 */ KBTS_LINE_BREAK_CLASS_ALea, + /* 39 */ KBTS_LINE_BREAK_CLASS_NU, + /* 40 */ KBTS_LINE_BREAK_CLASS_PRnea, + /* 41 */ KBTS_LINE_BREAK_CLASS_PRea, + /* 42 */ KBTS_LINE_BREAK_CLASS_IDnea, + /* 43 */ KBTS_LINE_BREAK_CLASS_IDea, + /* 44 */ KBTS_LINE_BREAK_CLASS_IDpe, + /* 45 */ KBTS_LINE_BREAK_CLASS_EBnea, + /* 46 */ KBTS_LINE_BREAK_CLASS_EBea, + /* 47 */ KBTS_LINE_BREAK_CLASS_EM, + /* 48 */ KBTS_LINE_BREAK_CLASS_POnea, + /* 49 */ KBTS_LINE_BREAK_CLASS_POea, + /* 50 */ KBTS_LINE_BREAK_CLASS_JL, + /* 51 */ KBTS_LINE_BREAK_CLASS_JV, + /* 52 */ KBTS_LINE_BREAK_CLASS_JT, + /* 53 */ KBTS_LINE_BREAK_CLASS_H2, + /* 54 */ KBTS_LINE_BREAK_CLASS_H3, + /* 55 */ KBTS_LINE_BREAK_CLASS_AP, + /* 56 */ KBTS_LINE_BREAK_CLASS_AK, + /* 57 */ KBTS_LINE_BREAK_CLASS_DOTTED_CIRCLE, + /* 58 */ KBTS_LINE_BREAK_CLASS_AS, + /* 59 */ KBTS_LINE_BREAK_CLASS_VF, + /* 60 */ KBTS_LINE_BREAK_CLASS_VI, + /* 61 */ KBTS_LINE_BREAK_CLASS_RI, + + /* 62 */ KBTS_LINE_BREAK_CLASS_COUNT, + + /* 63 */ KBTS_LINE_BREAK_CLASS_CM, + /* 64 */ KBTS_LINE_BREAK_CLASS_ZWJ, + + // CJ resolves to either NS or ID depending on the (Japanese) line break style. + // NS is strict line breaking, used for long lines. + // ID is normal line breaking, used for normal body text. + /* 65 */ KBTS_LINE_BREAK_CLASS_CJ, + + /* 66 */ KBTS_LINE_BREAK_CLASS_SOT, + /* 67 */ KBTS_LINE_BREAK_CLASS_EOT, +}; + +// @Cleanup: Merge EX and FO. +typedef kbts_u8 kbts_word_break_class; +enum kbts_word_break_class_enum +{ + KBTS_WORD_BREAK_CLASS_Onep, + KBTS_WORD_BREAK_CLASS_Oep, + KBTS_WORD_BREAK_CLASS_CR, + KBTS_WORD_BREAK_CLASS_LF, + KBTS_WORD_BREAK_CLASS_NL, + KBTS_WORD_BREAK_CLASS_EX, + KBTS_WORD_BREAK_CLASS_ZWJ, + KBTS_WORD_BREAK_CLASS_RI, + KBTS_WORD_BREAK_CLASS_FO, + KBTS_WORD_BREAK_CLASS_KA, + KBTS_WORD_BREAK_CLASS_HL, + KBTS_WORD_BREAK_CLASS_ALnep, + KBTS_WORD_BREAK_CLASS_ALep, + KBTS_WORD_BREAK_CLASS_SQ, + KBTS_WORD_BREAK_CLASS_DQ, + KBTS_WORD_BREAK_CLASS_MNL, + KBTS_WORD_BREAK_CLASS_ML, + KBTS_WORD_BREAK_CLASS_MN, + KBTS_WORD_BREAK_CLASS_NM, + KBTS_WORD_BREAK_CLASS_ENL, + KBTS_WORD_BREAK_CLASS_WSS, + + KBTS_WORD_BREAK_CLASS_SOT, +}; + +// Unicode defines scripts and languages. +// A language belongs to a single script, and a script belongs to a single writing system. +// On top of these, OpenType defines shapers, which are basically just designations for +// specific code paths that are taken depending on which script is being shapen. +// +// Some scripts, like Latin and Cyrillic, need relatively few operations, while complex +// scripts like Arabic and Indic scripts have specific processing steps that need to happen +// in order to obtain a correct result. +// +// These sequences of operations are _not_ described in the font file itself. The shaping +// code needs to know which script it is shaping, and implement all of those passes itself. +// That is why you, as a user, have to care about this. +// +// When creating shape_config, you can either pass in a known script, or you can specify +// SCRIPT_DONT_KNOW and let the library figure it out. +// While SCRIPT_DONT_KNOW may look appealing, it is worth noting that we can only infer +// the _script_, and not the language, of the text you pass in. +// This means that you might miss out on language-specific features when you use it. +typedef kbts_u32 kbts_shaper; +enum kbts_shaper_enum +{ + KBTS_SHAPER_DEFAULT, + KBTS_SHAPER_ARABIC, + KBTS_SHAPER_HANGUL, + KBTS_SHAPER_HEBREW, + KBTS_SHAPER_INDIC, + KBTS_SHAPER_KHMER, + KBTS_SHAPER_MYANMAR, + KBTS_SHAPER_TIBETAN, + KBTS_SHAPER_USE, + + KBTS_SHAPER_COUNT, +}; +typedef kbts_u32 kbts_script_tag; +enum kbts_script_tag_enum +{ + KBTS_SCRIPT_TAG_DONT_KNOW = KBTS_FOURCC(' ', ' ', ' ', ' '), + KBTS_SCRIPT_TAG_ADLAM = KBTS_FOURCC('a', 'd', 'l', 'm'), + KBTS_SCRIPT_TAG_AHOM = KBTS_FOURCC('a', 'h', 'o', 'm'), + KBTS_SCRIPT_TAG_ANATOLIAN_HIEROGLYPHS = KBTS_FOURCC('h', 'l', 'u', 'w'), + KBTS_SCRIPT_TAG_ARABIC = KBTS_FOURCC('a', 'r', 'a', 'b'), + KBTS_SCRIPT_TAG_ARMENIAN = KBTS_FOURCC('a', 'r', 'm', 'n'), + KBTS_SCRIPT_TAG_AVESTAN = KBTS_FOURCC('a', 'v', 's', 't'), + KBTS_SCRIPT_TAG_BALINESE = KBTS_FOURCC('b', 'a', 'l', 'i'), + KBTS_SCRIPT_TAG_BAMUM = KBTS_FOURCC('b', 'a', 'm', 'u'), + KBTS_SCRIPT_TAG_BASSA_VAH = KBTS_FOURCC('b', 'a', 's', 's'), + KBTS_SCRIPT_TAG_BATAK = KBTS_FOURCC('b', 'a', 't', 'k'), + KBTS_SCRIPT_TAG_BENGALI = KBTS_FOURCC('b', 'n', 'g', '2'), + KBTS_SCRIPT_TAG_BHAIKSUKI = KBTS_FOURCC('b', 'h', 'k', 's'), + KBTS_SCRIPT_TAG_BOPOMOFO = KBTS_FOURCC('b', 'o', 'p', 'o'), + KBTS_SCRIPT_TAG_BRAHMI = KBTS_FOURCC('b', 'r', 'a', 'h'), + KBTS_SCRIPT_TAG_BUGINESE = KBTS_FOURCC('b', 'u', 'g', 'i'), + KBTS_SCRIPT_TAG_BUHID = KBTS_FOURCC('b', 'u', 'h', 'd'), + KBTS_SCRIPT_TAG_CANADIAN_SYLLABICS = KBTS_FOURCC('c', 'a', 'n', 's'), + KBTS_SCRIPT_TAG_CARIAN = KBTS_FOURCC('c', 'a', 'r', 'i'), + KBTS_SCRIPT_TAG_CAUCASIAN_ALBANIAN = KBTS_FOURCC('a', 'g', 'h', 'b'), + KBTS_SCRIPT_TAG_CHAKMA = KBTS_FOURCC('c', 'a', 'k', 'm'), + KBTS_SCRIPT_TAG_CHAM = KBTS_FOURCC('c', 'h', 'a', 'm'), + KBTS_SCRIPT_TAG_CHEROKEE = KBTS_FOURCC('c', 'h', 'e', 'r'), + KBTS_SCRIPT_TAG_CHORASMIAN = KBTS_FOURCC('c', 'h', 'r', 's'), + KBTS_SCRIPT_TAG_CJK_IDEOGRAPHIC = KBTS_FOURCC('h', 'a', 'n', 'i'), + KBTS_SCRIPT_TAG_COPTIC = KBTS_FOURCC('c', 'o', 'p', 't'), + KBTS_SCRIPT_TAG_CYPRIOT_SYLLABARY = KBTS_FOURCC('c', 'p', 'r', 't'), + KBTS_SCRIPT_TAG_CYPRO_MINOAN = KBTS_FOURCC('c', 'p', 'm', 'n'), + KBTS_SCRIPT_TAG_CYRILLIC = KBTS_FOURCC('c', 'y', 'r', 'l'), + KBTS_SCRIPT_TAG_DEFAULT = KBTS_FOURCC('D', 'F', 'L', 'T'), + KBTS_SCRIPT_TAG_DEFAULT2 = KBTS_FOURCC('D', 'F', 'L', 'T'), + KBTS_SCRIPT_TAG_DESERET = KBTS_FOURCC('d', 's', 'r', 't'), + KBTS_SCRIPT_TAG_DEVANAGARI = KBTS_FOURCC('d', 'e', 'v', '2'), + KBTS_SCRIPT_TAG_DIVES_AKURU = KBTS_FOURCC('d', 'i', 'a', 'k'), + KBTS_SCRIPT_TAG_DOGRA = KBTS_FOURCC('d', 'o', 'g', 'r'), + KBTS_SCRIPT_TAG_DUPLOYAN = KBTS_FOURCC('d', 'u', 'p', 'l'), + KBTS_SCRIPT_TAG_EGYPTIAN_HIEROGLYPHS = KBTS_FOURCC('e', 'g', 'y', 'p'), + KBTS_SCRIPT_TAG_ELBASAN = KBTS_FOURCC('e', 'l', 'b', 'a'), + KBTS_SCRIPT_TAG_ELYMAIC = KBTS_FOURCC('e', 'l', 'y', 'm'), + KBTS_SCRIPT_TAG_ETHIOPIC = KBTS_FOURCC('e', 't', 'h', 'i'), + KBTS_SCRIPT_TAG_GARAY = KBTS_FOURCC('g', 'a', 'r', 'a'), + KBTS_SCRIPT_TAG_GEORGIAN = KBTS_FOURCC('g', 'e', 'o', 'r'), + KBTS_SCRIPT_TAG_GLAGOLITIC = KBTS_FOURCC('g', 'l', 'a', 'g'), + KBTS_SCRIPT_TAG_GOTHIC = KBTS_FOURCC('g', 'o', 't', 'h'), + KBTS_SCRIPT_TAG_GRANTHA = KBTS_FOURCC('g', 'r', 'a', 'n'), + KBTS_SCRIPT_TAG_GREEK = KBTS_FOURCC('g', 'r', 'e', 'k'), + KBTS_SCRIPT_TAG_GUJARATI = KBTS_FOURCC('g', 'j', 'r', '2'), + KBTS_SCRIPT_TAG_GUNJALA_GONDI = KBTS_FOURCC('g', 'o', 'n', 'g'), + KBTS_SCRIPT_TAG_GURMUKHI = KBTS_FOURCC('g', 'u', 'r', '2'), + KBTS_SCRIPT_TAG_GURUNG_KHEMA = KBTS_FOURCC('g', 'u', 'k', 'h'), + KBTS_SCRIPT_TAG_HANGUL = KBTS_FOURCC('h', 'a', 'n', 'g'), + KBTS_SCRIPT_TAG_HANIFI_ROHINGYA = KBTS_FOURCC('r', 'o', 'h', 'g'), + KBTS_SCRIPT_TAG_HANUNOO = KBTS_FOURCC('h', 'a', 'n', 'o'), + KBTS_SCRIPT_TAG_HATRAN = KBTS_FOURCC('h', 'a', 't', 'r'), + KBTS_SCRIPT_TAG_HEBREW = KBTS_FOURCC('h', 'e', 'b', 'r'), + KBTS_SCRIPT_TAG_HIRAGANA = KBTS_FOURCC('k', 'a', 'n', 'a'), + KBTS_SCRIPT_TAG_IMPERIAL_ARAMAIC = KBTS_FOURCC('a', 'r', 'm', 'i'), + KBTS_SCRIPT_TAG_INSCRIPTIONAL_PAHLAVI = KBTS_FOURCC('p', 'h', 'l', 'i'), + KBTS_SCRIPT_TAG_INSCRIPTIONAL_PARTHIAN = KBTS_FOURCC('p', 'r', 't', 'i'), + KBTS_SCRIPT_TAG_JAVANESE = KBTS_FOURCC('j', 'a', 'v', 'a'), + KBTS_SCRIPT_TAG_KAITHI = KBTS_FOURCC('k', 't', 'h', 'i'), + KBTS_SCRIPT_TAG_KANNADA = KBTS_FOURCC('k', 'n', 'd', '2'), + KBTS_SCRIPT_TAG_KATAKANA = KBTS_FOURCC('k', 'a', 'n', 'a'), + KBTS_SCRIPT_TAG_KAWI = KBTS_FOURCC('k', 'a', 'w', 'i'), + KBTS_SCRIPT_TAG_KAYAH_LI = KBTS_FOURCC('k', 'a', 'l', 'i'), + KBTS_SCRIPT_TAG_KHAROSHTHI = KBTS_FOURCC('k', 'h', 'a', 'r'), + KBTS_SCRIPT_TAG_KHITAN_SMALL_SCRIPT = KBTS_FOURCC('k', 'i', 't', 's'), + KBTS_SCRIPT_TAG_KHMER = KBTS_FOURCC('k', 'h', 'm', 'r'), + KBTS_SCRIPT_TAG_KHOJKI = KBTS_FOURCC('k', 'h', 'o', 'j'), + KBTS_SCRIPT_TAG_KHUDAWADI = KBTS_FOURCC('s', 'i', 'n', 'd'), + KBTS_SCRIPT_TAG_KIRAT_RAI = KBTS_FOURCC('k', 'r', 'a', 'i'), + KBTS_SCRIPT_TAG_LAO = KBTS_FOURCC('l', 'a', 'o', ' '), + KBTS_SCRIPT_TAG_LATIN = KBTS_FOURCC('l', 'a', 't', 'n'), + KBTS_SCRIPT_TAG_LEPCHA = KBTS_FOURCC('l', 'e', 'p', 'c'), + KBTS_SCRIPT_TAG_LIMBU = KBTS_FOURCC('l', 'i', 'm', 'b'), + KBTS_SCRIPT_TAG_LINEAR_A = KBTS_FOURCC('l', 'i', 'n', 'a'), + KBTS_SCRIPT_TAG_LINEAR_B = KBTS_FOURCC('l', 'i', 'n', 'b'), + KBTS_SCRIPT_TAG_LISU = KBTS_FOURCC('l', 'i', 's', 'u'), + KBTS_SCRIPT_TAG_LYCIAN = KBTS_FOURCC('l', 'y', 'c', 'i'), + KBTS_SCRIPT_TAG_LYDIAN = KBTS_FOURCC('l', 'y', 'd', 'i'), + KBTS_SCRIPT_TAG_MAHAJANI = KBTS_FOURCC('m', 'a', 'h', 'j'), + KBTS_SCRIPT_TAG_MAKASAR = KBTS_FOURCC('m', 'a', 'k', 'a'), + KBTS_SCRIPT_TAG_MALAYALAM = KBTS_FOURCC('m', 'l', 'm', '2'), + KBTS_SCRIPT_TAG_MANDAIC = KBTS_FOURCC('m', 'a', 'n', 'd'), + KBTS_SCRIPT_TAG_MANICHAEAN = KBTS_FOURCC('m', 'a', 'n', 'i'), + KBTS_SCRIPT_TAG_MARCHEN = KBTS_FOURCC('m', 'a', 'r', 'c'), + KBTS_SCRIPT_TAG_MASARAM_GONDI = KBTS_FOURCC('g', 'o', 'n', 'm'), + KBTS_SCRIPT_TAG_MEDEFAIDRIN = KBTS_FOURCC('m', 'e', 'd', 'f'), + KBTS_SCRIPT_TAG_MEETEI_MAYEK = KBTS_FOURCC('m', 't', 'e', 'i'), + KBTS_SCRIPT_TAG_MENDE_KIKAKUI = KBTS_FOURCC('m', 'e', 'n', 'd'), + KBTS_SCRIPT_TAG_MEROITIC_CURSIVE = KBTS_FOURCC('m', 'e', 'r', 'c'), + KBTS_SCRIPT_TAG_MEROITIC_HIEROGLYPHS = KBTS_FOURCC('m', 'e', 'r', 'o'), + KBTS_SCRIPT_TAG_MIAO = KBTS_FOURCC('p', 'l', 'r', 'd'), + KBTS_SCRIPT_TAG_MODI = KBTS_FOURCC('m', 'o', 'd', 'i'), + KBTS_SCRIPT_TAG_MONGOLIAN = KBTS_FOURCC('m', 'o', 'n', 'g'), + KBTS_SCRIPT_TAG_MRO = KBTS_FOURCC('m', 'r', 'o', 'o'), + KBTS_SCRIPT_TAG_MULTANI = KBTS_FOURCC('m', 'u', 'l', 't'), + KBTS_SCRIPT_TAG_MYANMAR = KBTS_FOURCC('m', 'y', 'm', '2'), + KBTS_SCRIPT_TAG_NABATAEAN = KBTS_FOURCC('n', 'b', 'a', 't'), + KBTS_SCRIPT_TAG_NAG_MUNDARI = KBTS_FOURCC('n', 'a', 'g', 'm'), + KBTS_SCRIPT_TAG_NANDINAGARI = KBTS_FOURCC('n', 'a', 'n', 'd'), + KBTS_SCRIPT_TAG_NEWA = KBTS_FOURCC('n', 'e', 'w', 'a'), + KBTS_SCRIPT_TAG_NEW_TAI_LUE = KBTS_FOURCC('t', 'a', 'l', 'u'), + KBTS_SCRIPT_TAG_NKO = KBTS_FOURCC('n', 'k', 'o', ' '), + KBTS_SCRIPT_TAG_NUSHU = KBTS_FOURCC('n', 's', 'h', 'u'), + KBTS_SCRIPT_TAG_NYIAKENG_PUACHUE_HMONG = KBTS_FOURCC('h', 'm', 'n', 'p'), + KBTS_SCRIPT_TAG_OGHAM = KBTS_FOURCC('o', 'g', 'a', 'm'), + KBTS_SCRIPT_TAG_OL_CHIKI = KBTS_FOURCC('o', 'l', 'c', 'k'), + KBTS_SCRIPT_TAG_OL_ONAL = KBTS_FOURCC('o', 'n', 'a', 'o'), + KBTS_SCRIPT_TAG_OLD_ITALIC = KBTS_FOURCC('i', 't', 'a', 'l'), + KBTS_SCRIPT_TAG_OLD_HUNGARIAN = KBTS_FOURCC('h', 'u', 'n', 'g'), + KBTS_SCRIPT_TAG_OLD_NORTH_ARABIAN = KBTS_FOURCC('n', 'a', 'r', 'b'), + KBTS_SCRIPT_TAG_OLD_PERMIC = KBTS_FOURCC('p', 'e', 'r', 'm'), + KBTS_SCRIPT_TAG_OLD_PERSIAN_CUNEIFORM = KBTS_FOURCC('x', 'p', 'e', 'o'), + KBTS_SCRIPT_TAG_OLD_SOGDIAN = KBTS_FOURCC('s', 'o', 'g', 'o'), + KBTS_SCRIPT_TAG_OLD_SOUTH_ARABIAN = KBTS_FOURCC('s', 'a', 'r', 'b'), + KBTS_SCRIPT_TAG_OLD_TURKIC = KBTS_FOURCC('o', 'r', 'k', 'h'), + KBTS_SCRIPT_TAG_OLD_UYGHUR = KBTS_FOURCC('o', 'u', 'g', 'r'), + KBTS_SCRIPT_TAG_ODIA = KBTS_FOURCC('o', 'r', 'y', '2'), + KBTS_SCRIPT_TAG_OSAGE = KBTS_FOURCC('o', 's', 'g', 'e'), + KBTS_SCRIPT_TAG_OSMANYA = KBTS_FOURCC('o', 's', 'm', 'a'), + KBTS_SCRIPT_TAG_PAHAWH_HMONG = KBTS_FOURCC('h', 'm', 'n', 'g'), + KBTS_SCRIPT_TAG_PALMYRENE = KBTS_FOURCC('p', 'a', 'l', 'm'), + KBTS_SCRIPT_TAG_PAU_CIN_HAU = KBTS_FOURCC('p', 'a', 'u', 'c'), + KBTS_SCRIPT_TAG_PHAGS_PA = KBTS_FOURCC('p', 'h', 'a', 'g'), + KBTS_SCRIPT_TAG_PHOENICIAN = KBTS_FOURCC('p', 'h', 'n', 'x'), + KBTS_SCRIPT_TAG_PSALTER_PAHLAVI = KBTS_FOURCC('p', 'h', 'l', 'p'), + KBTS_SCRIPT_TAG_REJANG = KBTS_FOURCC('r', 'j', 'n', 'g'), + KBTS_SCRIPT_TAG_RUNIC = KBTS_FOURCC('r', 'u', 'n', 'r'), + KBTS_SCRIPT_TAG_SAMARITAN = KBTS_FOURCC('s', 'a', 'm', 'r'), + KBTS_SCRIPT_TAG_SAURASHTRA = KBTS_FOURCC('s', 'a', 'u', 'r'), + KBTS_SCRIPT_TAG_SHARADA = KBTS_FOURCC('s', 'h', 'r', 'd'), + KBTS_SCRIPT_TAG_SHAVIAN = KBTS_FOURCC('s', 'h', 'a', 'w'), + KBTS_SCRIPT_TAG_SIDDHAM = KBTS_FOURCC('s', 'i', 'd', 'd'), + KBTS_SCRIPT_TAG_SIGN_WRITING = KBTS_FOURCC('s', 'g', 'n', 'w'), + KBTS_SCRIPT_TAG_SOGDIAN = KBTS_FOURCC('s', 'o', 'g', 'd'), + KBTS_SCRIPT_TAG_SINHALA = KBTS_FOURCC('s', 'i', 'n', 'h'), + KBTS_SCRIPT_TAG_SORA_SOMPENG = KBTS_FOURCC('s', 'o', 'r', 'a'), + KBTS_SCRIPT_TAG_SOYOMBO = KBTS_FOURCC('s', 'o', 'y', 'o'), + KBTS_SCRIPT_TAG_SUMERO_AKKADIAN_CUNEIFORM = KBTS_FOURCC('x', 's', 'u', 'x'), + KBTS_SCRIPT_TAG_SUNDANESE = KBTS_FOURCC('s', 'u', 'n', 'd'), + KBTS_SCRIPT_TAG_SUNUWAR = KBTS_FOURCC('s', 'u', 'n', 'u'), + KBTS_SCRIPT_TAG_SYLOTI_NAGRI = KBTS_FOURCC('s', 'y', 'l', 'o'), + KBTS_SCRIPT_TAG_SYRIAC = KBTS_FOURCC('s', 'y', 'r', 'c'), + KBTS_SCRIPT_TAG_TAGALOG = KBTS_FOURCC('t', 'g', 'l', 'g'), + KBTS_SCRIPT_TAG_TAGBANWA = KBTS_FOURCC('t', 'a', 'g', 'b'), + KBTS_SCRIPT_TAG_TAI_LE = KBTS_FOURCC('t', 'a', 'l', 'e'), + KBTS_SCRIPT_TAG_TAI_THAM = KBTS_FOURCC('l', 'a', 'n', 'a'), + KBTS_SCRIPT_TAG_TAI_VIET = KBTS_FOURCC('t', 'a', 'v', 't'), + KBTS_SCRIPT_TAG_TAKRI = KBTS_FOURCC('t', 'a', 'k', 'r'), + KBTS_SCRIPT_TAG_TAMIL = KBTS_FOURCC('t', 'm', 'l', '2'), + KBTS_SCRIPT_TAG_TANGSA = KBTS_FOURCC('t', 'n', 's', 'a'), + KBTS_SCRIPT_TAG_TANGUT = KBTS_FOURCC('t', 'a', 'n', 'g'), + KBTS_SCRIPT_TAG_TELUGU = KBTS_FOURCC('t', 'e', 'l', '2'), + KBTS_SCRIPT_TAG_THAANA = KBTS_FOURCC('t', 'h', 'a', 'a'), + KBTS_SCRIPT_TAG_THAI = KBTS_FOURCC('t', 'h', 'a', 'i'), + KBTS_SCRIPT_TAG_TIBETAN = KBTS_FOURCC('t', 'i', 'b', 't'), + KBTS_SCRIPT_TAG_TIFINAGH = KBTS_FOURCC('t', 'f', 'n', 'g'), + KBTS_SCRIPT_TAG_TIRHUTA = KBTS_FOURCC('t', 'i', 'r', 'h'), + KBTS_SCRIPT_TAG_TODHRI = KBTS_FOURCC('t', 'o', 'd', 'r'), + KBTS_SCRIPT_TAG_TOTO = KBTS_FOURCC('t', 'o', 't', 'o'), + KBTS_SCRIPT_TAG_TULU_TIGALARI = KBTS_FOURCC('t', 'u', 't', 'g'), + KBTS_SCRIPT_TAG_UGARITIC_CUNEIFORM = KBTS_FOURCC('u', 'g', 'a', 'r'), + KBTS_SCRIPT_TAG_VAI = KBTS_FOURCC('v', 'a', 'i', ' '), + KBTS_SCRIPT_TAG_VITHKUQI = KBTS_FOURCC('v', 'i', 't', 'h'), + KBTS_SCRIPT_TAG_WANCHO = KBTS_FOURCC('w', 'c', 'h', 'o'), + KBTS_SCRIPT_TAG_WARANG_CITI = KBTS_FOURCC('w', 'a', 'r', 'a'), + KBTS_SCRIPT_TAG_YEZIDI = KBTS_FOURCC('y', 'e', 'z', 'i'), + KBTS_SCRIPT_TAG_YI = KBTS_FOURCC('y', 'i', ' ', ' '), + KBTS_SCRIPT_TAG_ZANABAZAR_SQUARE = KBTS_FOURCC('z', 'a', 'n', 'b'), +}; + +typedef kbts_u32 kbts_script; +enum kbts_script_enum +{ + KBTS_SCRIPT_DONT_KNOW, + KBTS_SCRIPT_ADLAM, + KBTS_SCRIPT_AHOM, + KBTS_SCRIPT_ANATOLIAN_HIEROGLYPHS, + KBTS_SCRIPT_ARABIC, + KBTS_SCRIPT_ARMENIAN, + KBTS_SCRIPT_AVESTAN, + KBTS_SCRIPT_BALINESE, + KBTS_SCRIPT_BAMUM, + KBTS_SCRIPT_BASSA_VAH, + KBTS_SCRIPT_BATAK, + KBTS_SCRIPT_BENGALI, + KBTS_SCRIPT_BHAIKSUKI, + KBTS_SCRIPT_BOPOMOFO, + KBTS_SCRIPT_BRAHMI, + KBTS_SCRIPT_BUGINESE, + KBTS_SCRIPT_BUHID, + KBTS_SCRIPT_CANADIAN_SYLLABICS, + KBTS_SCRIPT_CARIAN, + KBTS_SCRIPT_CAUCASIAN_ALBANIAN, + KBTS_SCRIPT_CHAKMA, + KBTS_SCRIPT_CHAM, + KBTS_SCRIPT_CHEROKEE, + KBTS_SCRIPT_CHORASMIAN, + KBTS_SCRIPT_CJK_IDEOGRAPHIC, + KBTS_SCRIPT_COPTIC, + KBTS_SCRIPT_CYPRIOT_SYLLABARY, + KBTS_SCRIPT_CYPRO_MINOAN, + KBTS_SCRIPT_CYRILLIC, + KBTS_SCRIPT_DEFAULT, + KBTS_SCRIPT_DEFAULT2, + KBTS_SCRIPT_DESERET, + KBTS_SCRIPT_DEVANAGARI, + KBTS_SCRIPT_DIVES_AKURU, + KBTS_SCRIPT_DOGRA, + KBTS_SCRIPT_DUPLOYAN, + KBTS_SCRIPT_EGYPTIAN_HIEROGLYPHS, + KBTS_SCRIPT_ELBASAN, + KBTS_SCRIPT_ELYMAIC, + KBTS_SCRIPT_ETHIOPIC, + KBTS_SCRIPT_GARAY, + KBTS_SCRIPT_GEORGIAN, + KBTS_SCRIPT_GLAGOLITIC, + KBTS_SCRIPT_GOTHIC, + KBTS_SCRIPT_GRANTHA, + KBTS_SCRIPT_GREEK, + KBTS_SCRIPT_GUJARATI, + KBTS_SCRIPT_GUNJALA_GONDI, + KBTS_SCRIPT_GURMUKHI, + KBTS_SCRIPT_GURUNG_KHEMA, + KBTS_SCRIPT_HANGUL, + KBTS_SCRIPT_HANIFI_ROHINGYA, + KBTS_SCRIPT_HANUNOO, + KBTS_SCRIPT_HATRAN, + KBTS_SCRIPT_HEBREW, + KBTS_SCRIPT_HIRAGANA, + KBTS_SCRIPT_IMPERIAL_ARAMAIC, + KBTS_SCRIPT_INSCRIPTIONAL_PAHLAVI, + KBTS_SCRIPT_INSCRIPTIONAL_PARTHIAN, + KBTS_SCRIPT_JAVANESE, + KBTS_SCRIPT_KAITHI, + KBTS_SCRIPT_KANNADA, + KBTS_SCRIPT_KATAKANA, + KBTS_SCRIPT_KAWI, + KBTS_SCRIPT_KAYAH_LI, + KBTS_SCRIPT_KHAROSHTHI, + KBTS_SCRIPT_KHITAN_SMALL_SCRIPT, + KBTS_SCRIPT_KHMER, + KBTS_SCRIPT_KHOJKI, + KBTS_SCRIPT_KHUDAWADI, + KBTS_SCRIPT_KIRAT_RAI, + KBTS_SCRIPT_LAO, + KBTS_SCRIPT_LATIN, + KBTS_SCRIPT_LEPCHA, + KBTS_SCRIPT_LIMBU, + KBTS_SCRIPT_LINEAR_A, + KBTS_SCRIPT_LINEAR_B, + KBTS_SCRIPT_LISU, + KBTS_SCRIPT_LYCIAN, + KBTS_SCRIPT_LYDIAN, + KBTS_SCRIPT_MAHAJANI, + KBTS_SCRIPT_MAKASAR, + KBTS_SCRIPT_MALAYALAM, + KBTS_SCRIPT_MANDAIC, + KBTS_SCRIPT_MANICHAEAN, + KBTS_SCRIPT_MARCHEN, + KBTS_SCRIPT_MASARAM_GONDI, + KBTS_SCRIPT_MEDEFAIDRIN, + KBTS_SCRIPT_MEETEI_MAYEK, + KBTS_SCRIPT_MENDE_KIKAKUI, + KBTS_SCRIPT_MEROITIC_CURSIVE, + KBTS_SCRIPT_MEROITIC_HIEROGLYPHS, + KBTS_SCRIPT_MIAO, + KBTS_SCRIPT_MODI, + KBTS_SCRIPT_MONGOLIAN, + KBTS_SCRIPT_MRO, + KBTS_SCRIPT_MULTANI, + KBTS_SCRIPT_MYANMAR, + KBTS_SCRIPT_NABATAEAN, + KBTS_SCRIPT_NAG_MUNDARI, + KBTS_SCRIPT_NANDINAGARI, + KBTS_SCRIPT_NEWA, + KBTS_SCRIPT_NEW_TAI_LUE, + KBTS_SCRIPT_NKO, + KBTS_SCRIPT_NUSHU, + KBTS_SCRIPT_NYIAKENG_PUACHUE_HMONG, + KBTS_SCRIPT_OGHAM, + KBTS_SCRIPT_OL_CHIKI, + KBTS_SCRIPT_OL_ONAL, + KBTS_SCRIPT_OLD_ITALIC, + KBTS_SCRIPT_OLD_HUNGARIAN, + KBTS_SCRIPT_OLD_NORTH_ARABIAN, + KBTS_SCRIPT_OLD_PERMIC, + KBTS_SCRIPT_OLD_PERSIAN_CUNEIFORM, + KBTS_SCRIPT_OLD_SOGDIAN, + KBTS_SCRIPT_OLD_SOUTH_ARABIAN, + KBTS_SCRIPT_OLD_TURKIC, + KBTS_SCRIPT_OLD_UYGHUR, + KBTS_SCRIPT_ODIA, + KBTS_SCRIPT_OSAGE, + KBTS_SCRIPT_OSMANYA, + KBTS_SCRIPT_PAHAWH_HMONG, + KBTS_SCRIPT_PALMYRENE, + KBTS_SCRIPT_PAU_CIN_HAU, + KBTS_SCRIPT_PHAGS_PA, + KBTS_SCRIPT_PHOENICIAN, + KBTS_SCRIPT_PSALTER_PAHLAVI, + KBTS_SCRIPT_REJANG, + KBTS_SCRIPT_RUNIC, + KBTS_SCRIPT_SAMARITAN, + KBTS_SCRIPT_SAURASHTRA, + KBTS_SCRIPT_SHARADA, + KBTS_SCRIPT_SHAVIAN, + KBTS_SCRIPT_SIDDHAM, + KBTS_SCRIPT_SIGN_WRITING, + KBTS_SCRIPT_SOGDIAN, + KBTS_SCRIPT_SINHALA, + KBTS_SCRIPT_SORA_SOMPENG, + KBTS_SCRIPT_SOYOMBO, + KBTS_SCRIPT_SUMERO_AKKADIAN_CUNEIFORM, + KBTS_SCRIPT_SUNDANESE, + KBTS_SCRIPT_SUNUWAR, + KBTS_SCRIPT_SYLOTI_NAGRI, + KBTS_SCRIPT_SYRIAC, + KBTS_SCRIPT_TAGALOG, + KBTS_SCRIPT_TAGBANWA, + KBTS_SCRIPT_TAI_LE, + KBTS_SCRIPT_TAI_THAM, + KBTS_SCRIPT_TAI_VIET, + KBTS_SCRIPT_TAKRI, + KBTS_SCRIPT_TAMIL, + KBTS_SCRIPT_TANGSA, + KBTS_SCRIPT_TANGUT, + KBTS_SCRIPT_TELUGU, + KBTS_SCRIPT_THAANA, + KBTS_SCRIPT_THAI, + KBTS_SCRIPT_TIBETAN, + KBTS_SCRIPT_TIFINAGH, + KBTS_SCRIPT_TIRHUTA, + KBTS_SCRIPT_TODHRI, + KBTS_SCRIPT_TOTO, + KBTS_SCRIPT_TULU_TIGALARI, + KBTS_SCRIPT_UGARITIC_CUNEIFORM, + KBTS_SCRIPT_VAI, + KBTS_SCRIPT_VITHKUQI, + KBTS_SCRIPT_WANCHO, + KBTS_SCRIPT_WARANG_CITI, + KBTS_SCRIPT_YEZIDI, + KBTS_SCRIPT_YI, + KBTS_SCRIPT_ZANABAZAR_SQUARE, + KBTS_SCRIPT_COUNT, +}; + +typedef kbts_u32 kbts_feature_tag; +enum kbts_feature_tag_enum +{ + KBTS_FEATURE_TAG_UNREGISTERED = KBTS_FOURCC(0, 0, 0, 0), // Features that aren't pre-defined in the OpenType spec + KBTS_FEATURE_TAG_isol = KBTS_FOURCC('i', 's', 'o', 'l'), // Isolated Forms + KBTS_FEATURE_TAG_fina = KBTS_FOURCC('f', 'i', 'n', 'a'), // Terminal Forms + KBTS_FEATURE_TAG_fin2 = KBTS_FOURCC('f', 'i', 'n', '2'), // Terminal Forms #2 + KBTS_FEATURE_TAG_fin3 = KBTS_FOURCC('f', 'i', 'n', '3'), // Terminal Forms #3 + KBTS_FEATURE_TAG_medi = KBTS_FOURCC('m', 'e', 'd', 'i'), // Medial Forms + KBTS_FEATURE_TAG_med2 = KBTS_FOURCC('m', 'e', 'd', '2'), // Medial Forms #2 + KBTS_FEATURE_TAG_init = KBTS_FOURCC('i', 'n', 'i', 't'), // Initial Forms + KBTS_FEATURE_TAG_ljmo = KBTS_FOURCC('l', 'j', 'm', 'o'), // Leading Jamo Forms + KBTS_FEATURE_TAG_vjmo = KBTS_FOURCC('v', 'j', 'm', 'o'), // Vowel Jamo Forms + KBTS_FEATURE_TAG_tjmo = KBTS_FOURCC('t', 'j', 'm', 'o'), // Trailing Jamo Forms + KBTS_FEATURE_TAG_rphf = KBTS_FOURCC('r', 'p', 'h', 'f'), // Reph Form + KBTS_FEATURE_TAG_blwf = KBTS_FOURCC('b', 'l', 'w', 'f'), // Below-base Forms + KBTS_FEATURE_TAG_half = KBTS_FOURCC('h', 'a', 'l', 'f'), // Half Forms + KBTS_FEATURE_TAG_pstf = KBTS_FOURCC('p', 's', 't', 'f'), // Post-base Forms + KBTS_FEATURE_TAG_abvf = KBTS_FOURCC('a', 'b', 'v', 'f'), // Above-base Forms + KBTS_FEATURE_TAG_pref = KBTS_FOURCC('p', 'r', 'e', 'f'), // Pre-base Forms + KBTS_FEATURE_TAG_numr = KBTS_FOURCC('n', 'u', 'm', 'r'), // Numerators + KBTS_FEATURE_TAG_frac = KBTS_FOURCC('f', 'r', 'a', 'c'), // Fractions + KBTS_FEATURE_TAG_dnom = KBTS_FOURCC('d', 'n', 'o', 'm'), // Denominators + KBTS_FEATURE_TAG_cfar = KBTS_FOURCC('c', 'f', 'a', 'r'), // Conjunct Form After Ro + KBTS_FEATURE_TAG_aalt = KBTS_FOURCC('a', 'a', 'l', 't'), // Access All Alternates + KBTS_FEATURE_TAG_abvm = KBTS_FOURCC('a', 'b', 'v', 'm'), // Above-base Mark Positioning + KBTS_FEATURE_TAG_abvs = KBTS_FOURCC('a', 'b', 'v', 's'), // Above-base Substitutions + KBTS_FEATURE_TAG_afrc = KBTS_FOURCC('a', 'f', 'r', 'c'), // Alternative Fractions + KBTS_FEATURE_TAG_akhn = KBTS_FOURCC('a', 'k', 'h', 'n'), // Akhand + KBTS_FEATURE_TAG_apkn = KBTS_FOURCC('a', 'p', 'k', 'n'), // Kerning for Alternate Proportional Widths + KBTS_FEATURE_TAG_blwm = KBTS_FOURCC('b', 'l', 'w', 'm'), // Below-base Mark Positioning + KBTS_FEATURE_TAG_blws = KBTS_FOURCC('b', 'l', 'w', 's'), // Below-base Substitutions + KBTS_FEATURE_TAG_calt = KBTS_FOURCC('c', 'a', 'l', 't'), // Contextual Alternates + KBTS_FEATURE_TAG_case = KBTS_FOURCC('c', 'a', 's', 'e'), // Case-sensitive Forms + KBTS_FEATURE_TAG_ccmp = KBTS_FOURCC('c', 'c', 'm', 'p'), // Glyph Composition / Decomposition + KBTS_FEATURE_TAG_chws = KBTS_FOURCC('c', 'h', 'w', 's'), // Contextual Half-width Spacing + KBTS_FEATURE_TAG_cjct = KBTS_FOURCC('c', 'j', 'c', 't'), // Conjunct Forms + KBTS_FEATURE_TAG_clig = KBTS_FOURCC('c', 'l', 'i', 'g'), // Contextual Ligatures + KBTS_FEATURE_TAG_cpct = KBTS_FOURCC('c', 'p', 'c', 't'), // Centered CJK Punctuation + KBTS_FEATURE_TAG_cpsp = KBTS_FOURCC('c', 'p', 's', 'p'), // Capital Spacing + KBTS_FEATURE_TAG_cswh = KBTS_FOURCC('c', 's', 'w', 'h'), // Contextual Swash + KBTS_FEATURE_TAG_curs = KBTS_FOURCC('c', 'u', 'r', 's'), // Cursive Positioning + KBTS_FEATURE_TAG_cv01 = KBTS_FOURCC('c', 'v', '0', '1'), // Character Variant 1 + KBTS_FEATURE_TAG_cv02 = KBTS_FOURCC('c', 'v', '0', '2'), // Character Variant 2 + KBTS_FEATURE_TAG_cv03 = KBTS_FOURCC('c', 'v', '0', '3'), // Character Variant 3 + KBTS_FEATURE_TAG_cv04 = KBTS_FOURCC('c', 'v', '0', '4'), // Character Variant 4 + KBTS_FEATURE_TAG_cv05 = KBTS_FOURCC('c', 'v', '0', '5'), // Character Variant 5 + KBTS_FEATURE_TAG_cv06 = KBTS_FOURCC('c', 'v', '0', '6'), // Character Variant 6 + KBTS_FEATURE_TAG_cv07 = KBTS_FOURCC('c', 'v', '0', '7'), // Character Variant 7 + KBTS_FEATURE_TAG_cv08 = KBTS_FOURCC('c', 'v', '0', '8'), // Character Variant 8 + KBTS_FEATURE_TAG_cv09 = KBTS_FOURCC('c', 'v', '0', '9'), // Character Variant 9 + KBTS_FEATURE_TAG_cv10 = KBTS_FOURCC('c', 'v', '1', '0'), // Character Variant 10 + KBTS_FEATURE_TAG_cv11 = KBTS_FOURCC('c', 'v', '1', '1'), // Character Variant 11 + KBTS_FEATURE_TAG_cv12 = KBTS_FOURCC('c', 'v', '1', '2'), // Character Variant 12 + KBTS_FEATURE_TAG_cv13 = KBTS_FOURCC('c', 'v', '1', '3'), // Character Variant 13 + KBTS_FEATURE_TAG_cv14 = KBTS_FOURCC('c', 'v', '1', '4'), // Character Variant 14 + KBTS_FEATURE_TAG_cv15 = KBTS_FOURCC('c', 'v', '1', '5'), // Character Variant 15 + KBTS_FEATURE_TAG_cv16 = KBTS_FOURCC('c', 'v', '1', '6'), // Character Variant 16 + KBTS_FEATURE_TAG_cv17 = KBTS_FOURCC('c', 'v', '1', '7'), // Character Variant 17 + KBTS_FEATURE_TAG_cv18 = KBTS_FOURCC('c', 'v', '1', '8'), // Character Variant 18 + KBTS_FEATURE_TAG_cv19 = KBTS_FOURCC('c', 'v', '1', '9'), // Character Variant 19 + KBTS_FEATURE_TAG_cv20 = KBTS_FOURCC('c', 'v', '2', '0'), // Character Variant 20 + KBTS_FEATURE_TAG_cv21 = KBTS_FOURCC('c', 'v', '2', '1'), // Character Variant 21 + KBTS_FEATURE_TAG_cv22 = KBTS_FOURCC('c', 'v', '2', '2'), // Character Variant 22 + KBTS_FEATURE_TAG_cv23 = KBTS_FOURCC('c', 'v', '2', '3'), // Character Variant 23 + KBTS_FEATURE_TAG_cv24 = KBTS_FOURCC('c', 'v', '2', '4'), // Character Variant 24 + KBTS_FEATURE_TAG_cv25 = KBTS_FOURCC('c', 'v', '2', '5'), // Character Variant 25 + KBTS_FEATURE_TAG_cv26 = KBTS_FOURCC('c', 'v', '2', '6'), // Character Variant 26 + KBTS_FEATURE_TAG_cv27 = KBTS_FOURCC('c', 'v', '2', '7'), // Character Variant 27 + KBTS_FEATURE_TAG_cv28 = KBTS_FOURCC('c', 'v', '2', '8'), // Character Variant 28 + KBTS_FEATURE_TAG_cv29 = KBTS_FOURCC('c', 'v', '2', '9'), // Character Variant 29 + KBTS_FEATURE_TAG_cv30 = KBTS_FOURCC('c', 'v', '3', '0'), // Character Variant 30 + KBTS_FEATURE_TAG_cv31 = KBTS_FOURCC('c', 'v', '3', '1'), // Character Variant 31 + KBTS_FEATURE_TAG_cv32 = KBTS_FOURCC('c', 'v', '3', '2'), // Character Variant 32 + KBTS_FEATURE_TAG_cv33 = KBTS_FOURCC('c', 'v', '3', '3'), // Character Variant 33 + KBTS_FEATURE_TAG_cv34 = KBTS_FOURCC('c', 'v', '3', '4'), // Character Variant 34 + KBTS_FEATURE_TAG_cv35 = KBTS_FOURCC('c', 'v', '3', '5'), // Character Variant 35 + KBTS_FEATURE_TAG_cv36 = KBTS_FOURCC('c', 'v', '3', '6'), // Character Variant 36 + KBTS_FEATURE_TAG_cv37 = KBTS_FOURCC('c', 'v', '3', '7'), // Character Variant 37 + KBTS_FEATURE_TAG_cv38 = KBTS_FOURCC('c', 'v', '3', '8'), // Character Variant 38 + KBTS_FEATURE_TAG_cv39 = KBTS_FOURCC('c', 'v', '3', '9'), // Character Variant 39 + KBTS_FEATURE_TAG_cv40 = KBTS_FOURCC('c', 'v', '4', '0'), // Character Variant 40 + KBTS_FEATURE_TAG_cv41 = KBTS_FOURCC('c', 'v', '4', '1'), // Character Variant 41 + KBTS_FEATURE_TAG_cv42 = KBTS_FOURCC('c', 'v', '4', '2'), // Character Variant 42 + KBTS_FEATURE_TAG_cv43 = KBTS_FOURCC('c', 'v', '4', '3'), // Character Variant 43 + KBTS_FEATURE_TAG_cv44 = KBTS_FOURCC('c', 'v', '4', '4'), // Character Variant 44 + KBTS_FEATURE_TAG_cv45 = KBTS_FOURCC('c', 'v', '4', '5'), // Character Variant 45 + KBTS_FEATURE_TAG_cv46 = KBTS_FOURCC('c', 'v', '4', '6'), // Character Variant 46 + KBTS_FEATURE_TAG_cv47 = KBTS_FOURCC('c', 'v', '4', '7'), // Character Variant 47 + KBTS_FEATURE_TAG_cv48 = KBTS_FOURCC('c', 'v', '4', '8'), // Character Variant 48 + KBTS_FEATURE_TAG_cv49 = KBTS_FOURCC('c', 'v', '4', '9'), // Character Variant 49 + KBTS_FEATURE_TAG_cv50 = KBTS_FOURCC('c', 'v', '5', '0'), // Character Variant 50 + KBTS_FEATURE_TAG_cv51 = KBTS_FOURCC('c', 'v', '5', '1'), // Character Variant 51 + KBTS_FEATURE_TAG_cv52 = KBTS_FOURCC('c', 'v', '5', '2'), // Character Variant 52 + KBTS_FEATURE_TAG_cv53 = KBTS_FOURCC('c', 'v', '5', '3'), // Character Variant 53 + KBTS_FEATURE_TAG_cv54 = KBTS_FOURCC('c', 'v', '5', '4'), // Character Variant 54 + KBTS_FEATURE_TAG_cv55 = KBTS_FOURCC('c', 'v', '5', '5'), // Character Variant 55 + KBTS_FEATURE_TAG_cv56 = KBTS_FOURCC('c', 'v', '5', '6'), // Character Variant 56 + KBTS_FEATURE_TAG_cv57 = KBTS_FOURCC('c', 'v', '5', '7'), // Character Variant 57 + KBTS_FEATURE_TAG_cv58 = KBTS_FOURCC('c', 'v', '5', '8'), // Character Variant 58 + KBTS_FEATURE_TAG_cv59 = KBTS_FOURCC('c', 'v', '5', '9'), // Character Variant 59 + KBTS_FEATURE_TAG_cv60 = KBTS_FOURCC('c', 'v', '6', '0'), // Character Variant 60 + KBTS_FEATURE_TAG_cv61 = KBTS_FOURCC('c', 'v', '6', '1'), // Character Variant 61 + KBTS_FEATURE_TAG_cv62 = KBTS_FOURCC('c', 'v', '6', '2'), // Character Variant 62 + KBTS_FEATURE_TAG_cv63 = KBTS_FOURCC('c', 'v', '6', '3'), // Character Variant 63 + KBTS_FEATURE_TAG_cv64 = KBTS_FOURCC('c', 'v', '6', '4'), // Character Variant 64 + KBTS_FEATURE_TAG_cv65 = KBTS_FOURCC('c', 'v', '6', '5'), // Character Variant 65 + KBTS_FEATURE_TAG_cv66 = KBTS_FOURCC('c', 'v', '6', '6'), // Character Variant 66 + KBTS_FEATURE_TAG_cv67 = KBTS_FOURCC('c', 'v', '6', '7'), // Character Variant 67 + KBTS_FEATURE_TAG_cv68 = KBTS_FOURCC('c', 'v', '6', '8'), // Character Variant 68 + KBTS_FEATURE_TAG_cv69 = KBTS_FOURCC('c', 'v', '6', '9'), // Character Variant 69 + KBTS_FEATURE_TAG_cv70 = KBTS_FOURCC('c', 'v', '7', '0'), // Character Variant 70 + KBTS_FEATURE_TAG_cv71 = KBTS_FOURCC('c', 'v', '7', '1'), // Character Variant 71 + KBTS_FEATURE_TAG_cv72 = KBTS_FOURCC('c', 'v', '7', '2'), // Character Variant 72 + KBTS_FEATURE_TAG_cv73 = KBTS_FOURCC('c', 'v', '7', '3'), // Character Variant 73 + KBTS_FEATURE_TAG_cv74 = KBTS_FOURCC('c', 'v', '7', '4'), // Character Variant 74 + KBTS_FEATURE_TAG_cv75 = KBTS_FOURCC('c', 'v', '7', '5'), // Character Variant 75 + KBTS_FEATURE_TAG_cv76 = KBTS_FOURCC('c', 'v', '7', '6'), // Character Variant 76 + KBTS_FEATURE_TAG_cv77 = KBTS_FOURCC('c', 'v', '7', '7'), // Character Variant 77 + KBTS_FEATURE_TAG_cv78 = KBTS_FOURCC('c', 'v', '7', '8'), // Character Variant 78 + KBTS_FEATURE_TAG_cv79 = KBTS_FOURCC('c', 'v', '7', '9'), // Character Variant 79 + KBTS_FEATURE_TAG_cv80 = KBTS_FOURCC('c', 'v', '8', '0'), // Character Variant 80 + KBTS_FEATURE_TAG_cv81 = KBTS_FOURCC('c', 'v', '8', '1'), // Character Variant 81 + KBTS_FEATURE_TAG_cv82 = KBTS_FOURCC('c', 'v', '8', '2'), // Character Variant 82 + KBTS_FEATURE_TAG_cv83 = KBTS_FOURCC('c', 'v', '8', '3'), // Character Variant 83 + KBTS_FEATURE_TAG_cv84 = KBTS_FOURCC('c', 'v', '8', '4'), // Character Variant 84 + KBTS_FEATURE_TAG_cv85 = KBTS_FOURCC('c', 'v', '8', '5'), // Character Variant 85 + KBTS_FEATURE_TAG_cv86 = KBTS_FOURCC('c', 'v', '8', '6'), // Character Variant 86 + KBTS_FEATURE_TAG_cv87 = KBTS_FOURCC('c', 'v', '8', '7'), // Character Variant 87 + KBTS_FEATURE_TAG_cv88 = KBTS_FOURCC('c', 'v', '8', '8'), // Character Variant 88 + KBTS_FEATURE_TAG_cv89 = KBTS_FOURCC('c', 'v', '8', '9'), // Character Variant 89 + KBTS_FEATURE_TAG_cv90 = KBTS_FOURCC('c', 'v', '9', '0'), // Character Variant 90 + KBTS_FEATURE_TAG_cv91 = KBTS_FOURCC('c', 'v', '9', '1'), // Character Variant 91 + KBTS_FEATURE_TAG_cv92 = KBTS_FOURCC('c', 'v', '9', '2'), // Character Variant 92 + KBTS_FEATURE_TAG_cv93 = KBTS_FOURCC('c', 'v', '9', '3'), // Character Variant 93 + KBTS_FEATURE_TAG_cv94 = KBTS_FOURCC('c', 'v', '9', '4'), // Character Variant 94 + KBTS_FEATURE_TAG_cv95 = KBTS_FOURCC('c', 'v', '9', '5'), // Character Variant 95 + KBTS_FEATURE_TAG_cv96 = KBTS_FOURCC('c', 'v', '9', '6'), // Character Variant 96 + KBTS_FEATURE_TAG_cv97 = KBTS_FOURCC('c', 'v', '9', '7'), // Character Variant 97 + KBTS_FEATURE_TAG_cv98 = KBTS_FOURCC('c', 'v', '9', '8'), // Character Variant 98 + KBTS_FEATURE_TAG_cv99 = KBTS_FOURCC('c', 'v', '9', '9'), // Character Variant 99 + KBTS_FEATURE_TAG_c2pc = KBTS_FOURCC('c', '2', 'p', 'c'), // Petite Capitals From Capitals + KBTS_FEATURE_TAG_c2sc = KBTS_FOURCC('c', '2', 's', 'c'), // Small Capitals From Capitals + KBTS_FEATURE_TAG_dist = KBTS_FOURCC('d', 'i', 's', 't'), // Distances + KBTS_FEATURE_TAG_dlig = KBTS_FOURCC('d', 'l', 'i', 'g'), // Discretionary Ligatures + KBTS_FEATURE_TAG_dtls = KBTS_FOURCC('d', 't', 'l', 's'), // Dotless Forms + KBTS_FEATURE_TAG_expt = KBTS_FOURCC('e', 'x', 'p', 't'), // Expert Forms + KBTS_FEATURE_TAG_falt = KBTS_FOURCC('f', 'a', 'l', 't'), // Final Glyph on Line Alternates + KBTS_FEATURE_TAG_flac = KBTS_FOURCC('f', 'l', 'a', 'c'), // Flattened Accent Forms + KBTS_FEATURE_TAG_fwid = KBTS_FOURCC('f', 'w', 'i', 'd'), // Full Widths + KBTS_FEATURE_TAG_haln = KBTS_FOURCC('h', 'a', 'l', 'n'), // Halant Forms + KBTS_FEATURE_TAG_halt = KBTS_FOURCC('h', 'a', 'l', 't'), // Alternate Half Widths + KBTS_FEATURE_TAG_hist = KBTS_FOURCC('h', 'i', 's', 't'), // Historical Forms + KBTS_FEATURE_TAG_hkna = KBTS_FOURCC('h', 'k', 'n', 'a'), // Horizontal Kana Alternates + KBTS_FEATURE_TAG_hlig = KBTS_FOURCC('h', 'l', 'i', 'g'), // Historical Ligatures + KBTS_FEATURE_TAG_hngl = KBTS_FOURCC('h', 'n', 'g', 'l'), // Hangul + KBTS_FEATURE_TAG_hojo = KBTS_FOURCC('h', 'o', 'j', 'o'), // Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms) + KBTS_FEATURE_TAG_hwid = KBTS_FOURCC('h', 'w', 'i', 'd'), // Half Widths + KBTS_FEATURE_TAG_ital = KBTS_FOURCC('i', 't', 'a', 'l'), // Italics + KBTS_FEATURE_TAG_jalt = KBTS_FOURCC('j', 'a', 'l', 't'), // Justification Alternates + KBTS_FEATURE_TAG_jp78 = KBTS_FOURCC('j', 'p', '7', '8'), // JIS78 Forms + KBTS_FEATURE_TAG_jp83 = KBTS_FOURCC('j', 'p', '8', '3'), // JIS83 Forms + KBTS_FEATURE_TAG_jp90 = KBTS_FOURCC('j', 'p', '9', '0'), // JIS90 Forms + KBTS_FEATURE_TAG_jp04 = KBTS_FOURCC('j', 'p', '0', '4'), // JIS2004 Forms + KBTS_FEATURE_TAG_kern = KBTS_FOURCC('k', 'e', 'r', 'n'), // Kerning + KBTS_FEATURE_TAG_lfbd = KBTS_FOURCC('l', 'f', 'b', 'd'), // Left Bounds + KBTS_FEATURE_TAG_liga = KBTS_FOURCC('l', 'i', 'g', 'a'), // Standard Ligatures + KBTS_FEATURE_TAG_lnum = KBTS_FOURCC('l', 'n', 'u', 'm'), // Lining Figures + KBTS_FEATURE_TAG_locl = KBTS_FOURCC('l', 'o', 'c', 'l'), // Localized Forms + KBTS_FEATURE_TAG_ltra = KBTS_FOURCC('l', 't', 'r', 'a'), // Left-to-right Alternates + KBTS_FEATURE_TAG_ltrm = KBTS_FOURCC('l', 't', 'r', 'm'), // Left-to-right Mirrored Forms + KBTS_FEATURE_TAG_mark = KBTS_FOURCC('m', 'a', 'r', 'k'), // Mark Positioning + KBTS_FEATURE_TAG_mgrk = KBTS_FOURCC('m', 'g', 'r', 'k'), // Mathematical Greek + KBTS_FEATURE_TAG_mkmk = KBTS_FOURCC('m', 'k', 'm', 'k'), // Mark to Mark Positioning + KBTS_FEATURE_TAG_mset = KBTS_FOURCC('m', 's', 'e', 't'), // Mark Positioning via Substitution + KBTS_FEATURE_TAG_nalt = KBTS_FOURCC('n', 'a', 'l', 't'), // Alternate Annotation Forms + KBTS_FEATURE_TAG_nlck = KBTS_FOURCC('n', 'l', 'c', 'k'), // NLC Kanji Forms + KBTS_FEATURE_TAG_nukt = KBTS_FOURCC('n', 'u', 'k', 't'), // Nukta Forms + KBTS_FEATURE_TAG_onum = KBTS_FOURCC('o', 'n', 'u', 'm'), // Oldstyle Figures + KBTS_FEATURE_TAG_opbd = KBTS_FOURCC('o', 'p', 'b', 'd'), // Optical Bounds + KBTS_FEATURE_TAG_ordn = KBTS_FOURCC('o', 'r', 'd', 'n'), // Ordinals + KBTS_FEATURE_TAG_ornm = KBTS_FOURCC('o', 'r', 'n', 'm'), // Ornaments + KBTS_FEATURE_TAG_palt = KBTS_FOURCC('p', 'a', 'l', 't'), // Proportional Alternate Widths + KBTS_FEATURE_TAG_pcap = KBTS_FOURCC('p', 'c', 'a', 'p'), // Petite Capitals + KBTS_FEATURE_TAG_pkna = KBTS_FOURCC('p', 'k', 'n', 'a'), // Proportional Kana + KBTS_FEATURE_TAG_pnum = KBTS_FOURCC('p', 'n', 'u', 'm'), // Proportional Figures + KBTS_FEATURE_TAG_pres = KBTS_FOURCC('p', 'r', 'e', 's'), // Pre-base Substitutions + KBTS_FEATURE_TAG_psts = KBTS_FOURCC('p', 's', 't', 's'), // Post-base Substitutions + KBTS_FEATURE_TAG_pwid = KBTS_FOURCC('p', 'w', 'i', 'd'), // Proportional Widths + KBTS_FEATURE_TAG_qwid = KBTS_FOURCC('q', 'w', 'i', 'd'), // Quarter Widths + KBTS_FEATURE_TAG_rand = KBTS_FOURCC('r', 'a', 'n', 'd'), // Randomize + KBTS_FEATURE_TAG_rclt = KBTS_FOURCC('r', 'c', 'l', 't'), // Required Contextual Alternates + KBTS_FEATURE_TAG_rkrf = KBTS_FOURCC('r', 'k', 'r', 'f'), // Rakar Forms + KBTS_FEATURE_TAG_rlig = KBTS_FOURCC('r', 'l', 'i', 'g'), // Required Ligatures + KBTS_FEATURE_TAG_rtbd = KBTS_FOURCC('r', 't', 'b', 'd'), // Right Bounds + KBTS_FEATURE_TAG_rtla = KBTS_FOURCC('r', 't', 'l', 'a'), // Right-to-left Alternates + KBTS_FEATURE_TAG_rtlm = KBTS_FOURCC('r', 't', 'l', 'm'), // Right-to-left Mirrored Forms + KBTS_FEATURE_TAG_ruby = KBTS_FOURCC('r', 'u', 'b', 'y'), // Ruby Notation Forms + KBTS_FEATURE_TAG_rvrn = KBTS_FOURCC('r', 'v', 'r', 'n'), // Required Variation Alternates + KBTS_FEATURE_TAG_salt = KBTS_FOURCC('s', 'a', 'l', 't'), // Stylistic Alternates + KBTS_FEATURE_TAG_sinf = KBTS_FOURCC('s', 'i', 'n', 'f'), // Scientific Inferiors + KBTS_FEATURE_TAG_size = KBTS_FOURCC('s', 'i', 'z', 'e'), // Optical size + KBTS_FEATURE_TAG_smcp = KBTS_FOURCC('s', 'm', 'c', 'p'), // Small Capitals + KBTS_FEATURE_TAG_smpl = KBTS_FOURCC('s', 'm', 'p', 'l'), // Simplified Forms + KBTS_FEATURE_TAG_ss01 = KBTS_FOURCC('s', 's', '0', '1'), // Stylistic Set 1 + KBTS_FEATURE_TAG_ss02 = KBTS_FOURCC('s', 's', '0', '2'), // Stylistic Set 2 + KBTS_FEATURE_TAG_ss03 = KBTS_FOURCC('s', 's', '0', '3'), // Stylistic Set 3 + KBTS_FEATURE_TAG_ss04 = KBTS_FOURCC('s', 's', '0', '4'), // Stylistic Set 4 + KBTS_FEATURE_TAG_ss05 = KBTS_FOURCC('s', 's', '0', '5'), // Stylistic Set 5 + KBTS_FEATURE_TAG_ss06 = KBTS_FOURCC('s', 's', '0', '6'), // Stylistic Set 6 + KBTS_FEATURE_TAG_ss07 = KBTS_FOURCC('s', 's', '0', '7'), // Stylistic Set 7 + KBTS_FEATURE_TAG_ss08 = KBTS_FOURCC('s', 's', '0', '8'), // Stylistic Set 8 + KBTS_FEATURE_TAG_ss09 = KBTS_FOURCC('s', 's', '0', '9'), // Stylistic Set 9 + KBTS_FEATURE_TAG_ss10 = KBTS_FOURCC('s', 's', '1', '0'), // Stylistic Set 10 + KBTS_FEATURE_TAG_ss11 = KBTS_FOURCC('s', 's', '1', '1'), // Stylistic Set 11 + KBTS_FEATURE_TAG_ss12 = KBTS_FOURCC('s', 's', '1', '2'), // Stylistic Set 12 + KBTS_FEATURE_TAG_ss13 = KBTS_FOURCC('s', 's', '1', '3'), // Stylistic Set 13 + KBTS_FEATURE_TAG_ss14 = KBTS_FOURCC('s', 's', '1', '4'), // Stylistic Set 14 + KBTS_FEATURE_TAG_ss15 = KBTS_FOURCC('s', 's', '1', '5'), // Stylistic Set 15 + KBTS_FEATURE_TAG_ss16 = KBTS_FOURCC('s', 's', '1', '6'), // Stylistic Set 16 + KBTS_FEATURE_TAG_ss17 = KBTS_FOURCC('s', 's', '1', '7'), // Stylistic Set 17 + KBTS_FEATURE_TAG_ss18 = KBTS_FOURCC('s', 's', '1', '8'), // Stylistic Set 18 + KBTS_FEATURE_TAG_ss19 = KBTS_FOURCC('s', 's', '1', '9'), // Stylistic Set 19 + KBTS_FEATURE_TAG_ss20 = KBTS_FOURCC('s', 's', '2', '0'), // Stylistic Set 20 + KBTS_FEATURE_TAG_ssty = KBTS_FOURCC('s', 's', 't', 'y'), // Math Script-style Alternates + KBTS_FEATURE_TAG_stch = KBTS_FOURCC('s', 't', 'c', 'h'), // Stretching Glyph Decomposition + KBTS_FEATURE_TAG_subs = KBTS_FOURCC('s', 'u', 'b', 's'), // Subscript + KBTS_FEATURE_TAG_sups = KBTS_FOURCC('s', 'u', 'p', 's'), // Superscript + KBTS_FEATURE_TAG_swsh = KBTS_FOURCC('s', 'w', 's', 'h'), // Swash + KBTS_FEATURE_TAG_test = KBTS_FOURCC('t', 'e', 's', 't'), // Test features, only for development + KBTS_FEATURE_TAG_titl = KBTS_FOURCC('t', 'i', 't', 'l'), // Titling + KBTS_FEATURE_TAG_tnam = KBTS_FOURCC('t', 'n', 'a', 'm'), // Traditional Name Forms + KBTS_FEATURE_TAG_tnum = KBTS_FOURCC('t', 'n', 'u', 'm'), // Tabular Figures + KBTS_FEATURE_TAG_trad = KBTS_FOURCC('t', 'r', 'a', 'd'), // Traditional Forms + KBTS_FEATURE_TAG_twid = KBTS_FOURCC('t', 'w', 'i', 'd'), // Third Widths + KBTS_FEATURE_TAG_unic = KBTS_FOURCC('u', 'n', 'i', 'c'), // Unicase + KBTS_FEATURE_TAG_valt = KBTS_FOURCC('v', 'a', 'l', 't'), // Alternate Vertical Metrics + KBTS_FEATURE_TAG_vapk = KBTS_FOURCC('v', 'a', 'p', 'k'), // Kerning for Alternate Proportional Vertical Metrics + KBTS_FEATURE_TAG_vatu = KBTS_FOURCC('v', 'a', 't', 'u'), // Vattu Variants + KBTS_FEATURE_TAG_vchw = KBTS_FOURCC('v', 'c', 'h', 'w'), // Vertical Contextual Half-width Spacing + KBTS_FEATURE_TAG_vert = KBTS_FOURCC('v', 'e', 'r', 't'), // Vertical Alternates + KBTS_FEATURE_TAG_vhal = KBTS_FOURCC('v', 'h', 'a', 'l'), // Alternate Vertical Half Metrics + KBTS_FEATURE_TAG_vkna = KBTS_FOURCC('v', 'k', 'n', 'a'), // Vertical Kana Alternates + KBTS_FEATURE_TAG_vkrn = KBTS_FOURCC('v', 'k', 'r', 'n'), // Vertical Kerning + KBTS_FEATURE_TAG_vpal = KBTS_FOURCC('v', 'p', 'a', 'l'), // Proportional Alternate Vertical Metrics + KBTS_FEATURE_TAG_vrt2 = KBTS_FOURCC('v', 'r', 't', '2'), // Vertical Alternates and Rotation + KBTS_FEATURE_TAG_vrtr = KBTS_FOURCC('v', 'r', 't', 'r'), // Vertical Alternates for Rotation + KBTS_FEATURE_TAG_zero = KBTS_FOURCC('z', 'e', 'r', 'o'), // Slashed Zero +}; + +typedef kbts_u32 kbts_feature_id; +enum kbts_feature_id_enum +{ + KBTS_FEATURE_ID_UNREGISTERED, // Features that aren't pre-defined in the OpenType spec + KBTS_FEATURE_ID_isol, // Isolated Forms + KBTS_FEATURE_ID_fina, // Terminal Forms + KBTS_FEATURE_ID_fin2, // Terminal Forms #2 + KBTS_FEATURE_ID_fin3, // Terminal Forms #3 + KBTS_FEATURE_ID_medi, // Medial Forms + KBTS_FEATURE_ID_med2, // Medial Forms #2 + KBTS_FEATURE_ID_init, // Initial Forms + KBTS_FEATURE_ID_ljmo, // Leading Jamo Forms + KBTS_FEATURE_ID_vjmo, // Vowel Jamo Forms + KBTS_FEATURE_ID_tjmo, // Trailing Jamo Forms + KBTS_FEATURE_ID_rphf, // Reph Form + KBTS_FEATURE_ID_blwf, // Below-base Forms + KBTS_FEATURE_ID_half, // Half Forms + KBTS_FEATURE_ID_pstf, // Post-base Forms + KBTS_FEATURE_ID_abvf, // Above-base Forms + KBTS_FEATURE_ID_pref, // Pre-base Forms + KBTS_FEATURE_ID_numr, // Numerators + KBTS_FEATURE_ID_frac, // Fractions + KBTS_FEATURE_ID_dnom, // Denominators + KBTS_FEATURE_ID_cfar, // Conjunct Form After Ro + KBTS_FEATURE_ID_aalt, // Access All Alternates + KBTS_FEATURE_ID_abvm, // Above-base Mark Positioning + KBTS_FEATURE_ID_abvs, // Above-base Substitutions + KBTS_FEATURE_ID_afrc, // Alternative Fractions + KBTS_FEATURE_ID_akhn, // Akhand + KBTS_FEATURE_ID_apkn, // Kerning for Alternate Proportional Widths + KBTS_FEATURE_ID_blwm, // Below-base Mark Positioning + KBTS_FEATURE_ID_blws, // Below-base Substitutions + KBTS_FEATURE_ID_calt, // Contextual Alternates + KBTS_FEATURE_ID_case, // Case-sensitive Forms + KBTS_FEATURE_ID_ccmp, // Glyph Composition / Decomposition + KBTS_FEATURE_ID_chws, // Contextual Half-width Spacing + KBTS_FEATURE_ID_cjct, // Conjunct Forms + KBTS_FEATURE_ID_clig, // Contextual Ligatures + KBTS_FEATURE_ID_cpct, // Centered CJK Punctuation + KBTS_FEATURE_ID_cpsp, // Capital Spacing + KBTS_FEATURE_ID_cswh, // Contextual Swash + KBTS_FEATURE_ID_curs, // Cursive Positioning + KBTS_FEATURE_ID_cv01, // Character Variant 1 + KBTS_FEATURE_ID_cv02, // Character Variant 2 + KBTS_FEATURE_ID_cv03, // Character Variant 3 + KBTS_FEATURE_ID_cv04, // Character Variant 4 + KBTS_FEATURE_ID_cv05, // Character Variant 5 + KBTS_FEATURE_ID_cv06, // Character Variant 6 + KBTS_FEATURE_ID_cv07, // Character Variant 7 + KBTS_FEATURE_ID_cv08, // Character Variant 8 + KBTS_FEATURE_ID_cv09, // Character Variant 9 + KBTS_FEATURE_ID_cv10, // Character Variant 10 + KBTS_FEATURE_ID_cv11, // Character Variant 11 + KBTS_FEATURE_ID_cv12, // Character Variant 12 + KBTS_FEATURE_ID_cv13, // Character Variant 13 + KBTS_FEATURE_ID_cv14, // Character Variant 14 + KBTS_FEATURE_ID_cv15, // Character Variant 15 + KBTS_FEATURE_ID_cv16, // Character Variant 16 + KBTS_FEATURE_ID_cv17, // Character Variant 17 + KBTS_FEATURE_ID_cv18, // Character Variant 18 + KBTS_FEATURE_ID_cv19, // Character Variant 19 + KBTS_FEATURE_ID_cv20, // Character Variant 20 + KBTS_FEATURE_ID_cv21, // Character Variant 21 + KBTS_FEATURE_ID_cv22, // Character Variant 22 + KBTS_FEATURE_ID_cv23, // Character Variant 23 + KBTS_FEATURE_ID_cv24, // Character Variant 24 + KBTS_FEATURE_ID_cv25, // Character Variant 25 + KBTS_FEATURE_ID_cv26, // Character Variant 26 + KBTS_FEATURE_ID_cv27, // Character Variant 27 + KBTS_FEATURE_ID_cv28, // Character Variant 28 + KBTS_FEATURE_ID_cv29, // Character Variant 29 + KBTS_FEATURE_ID_cv30, // Character Variant 30 + KBTS_FEATURE_ID_cv31, // Character Variant 31 + KBTS_FEATURE_ID_cv32, // Character Variant 32 + KBTS_FEATURE_ID_cv33, // Character Variant 33 + KBTS_FEATURE_ID_cv34, // Character Variant 34 + KBTS_FEATURE_ID_cv35, // Character Variant 35 + KBTS_FEATURE_ID_cv36, // Character Variant 36 + KBTS_FEATURE_ID_cv37, // Character Variant 37 + KBTS_FEATURE_ID_cv38, // Character Variant 38 + KBTS_FEATURE_ID_cv39, // Character Variant 39 + KBTS_FEATURE_ID_cv40, // Character Variant 40 + KBTS_FEATURE_ID_cv41, // Character Variant 41 + KBTS_FEATURE_ID_cv42, // Character Variant 42 + KBTS_FEATURE_ID_cv43, // Character Variant 43 + KBTS_FEATURE_ID_cv44, // Character Variant 44 + KBTS_FEATURE_ID_cv45, // Character Variant 45 + KBTS_FEATURE_ID_cv46, // Character Variant 46 + KBTS_FEATURE_ID_cv47, // Character Variant 47 + KBTS_FEATURE_ID_cv48, // Character Variant 48 + KBTS_FEATURE_ID_cv49, // Character Variant 49 + KBTS_FEATURE_ID_cv50, // Character Variant 50 + KBTS_FEATURE_ID_cv51, // Character Variant 51 + KBTS_FEATURE_ID_cv52, // Character Variant 52 + KBTS_FEATURE_ID_cv53, // Character Variant 53 + KBTS_FEATURE_ID_cv54, // Character Variant 54 + KBTS_FEATURE_ID_cv55, // Character Variant 55 + KBTS_FEATURE_ID_cv56, // Character Variant 56 + KBTS_FEATURE_ID_cv57, // Character Variant 57 + KBTS_FEATURE_ID_cv58, // Character Variant 58 + KBTS_FEATURE_ID_cv59, // Character Variant 59 + KBTS_FEATURE_ID_cv60, // Character Variant 60 + KBTS_FEATURE_ID_cv61, // Character Variant 61 + KBTS_FEATURE_ID_cv62, // Character Variant 62 + KBTS_FEATURE_ID_cv63, // Character Variant 63 + KBTS_FEATURE_ID_cv64, // Character Variant 64 + KBTS_FEATURE_ID_cv65, // Character Variant 65 + KBTS_FEATURE_ID_cv66, // Character Variant 66 + KBTS_FEATURE_ID_cv67, // Character Variant 67 + KBTS_FEATURE_ID_cv68, // Character Variant 68 + KBTS_FEATURE_ID_cv69, // Character Variant 69 + KBTS_FEATURE_ID_cv70, // Character Variant 70 + KBTS_FEATURE_ID_cv71, // Character Variant 71 + KBTS_FEATURE_ID_cv72, // Character Variant 72 + KBTS_FEATURE_ID_cv73, // Character Variant 73 + KBTS_FEATURE_ID_cv74, // Character Variant 74 + KBTS_FEATURE_ID_cv75, // Character Variant 75 + KBTS_FEATURE_ID_cv76, // Character Variant 76 + KBTS_FEATURE_ID_cv77, // Character Variant 77 + KBTS_FEATURE_ID_cv78, // Character Variant 78 + KBTS_FEATURE_ID_cv79, // Character Variant 79 + KBTS_FEATURE_ID_cv80, // Character Variant 80 + KBTS_FEATURE_ID_cv81, // Character Variant 81 + KBTS_FEATURE_ID_cv82, // Character Variant 82 + KBTS_FEATURE_ID_cv83, // Character Variant 83 + KBTS_FEATURE_ID_cv84, // Character Variant 84 + KBTS_FEATURE_ID_cv85, // Character Variant 85 + KBTS_FEATURE_ID_cv86, // Character Variant 86 + KBTS_FEATURE_ID_cv87, // Character Variant 87 + KBTS_FEATURE_ID_cv88, // Character Variant 88 + KBTS_FEATURE_ID_cv89, // Character Variant 89 + KBTS_FEATURE_ID_cv90, // Character Variant 90 + KBTS_FEATURE_ID_cv91, // Character Variant 91 + KBTS_FEATURE_ID_cv92, // Character Variant 92 + KBTS_FEATURE_ID_cv93, // Character Variant 93 + KBTS_FEATURE_ID_cv94, // Character Variant 94 + KBTS_FEATURE_ID_cv95, // Character Variant 95 + KBTS_FEATURE_ID_cv96, // Character Variant 96 + KBTS_FEATURE_ID_cv97, // Character Variant 97 + KBTS_FEATURE_ID_cv98, // Character Variant 98 + KBTS_FEATURE_ID_cv99, // Character Variant 99 + KBTS_FEATURE_ID_c2pc, // Petite Capitals From Capitals + KBTS_FEATURE_ID_c2sc, // Small Capitals From Capitals + KBTS_FEATURE_ID_dist, // Distances + KBTS_FEATURE_ID_dlig, // Discretionary Ligatures + KBTS_FEATURE_ID_dtls, // Dotless Forms + KBTS_FEATURE_ID_expt, // Expert Forms + KBTS_FEATURE_ID_falt, // Final Glyph on Line Alternates + KBTS_FEATURE_ID_flac, // Flattened Accent Forms + KBTS_FEATURE_ID_fwid, // Full Widths + KBTS_FEATURE_ID_haln, // Halant Forms + KBTS_FEATURE_ID_halt, // Alternate Half Widths + KBTS_FEATURE_ID_hist, // Historical Forms + KBTS_FEATURE_ID_hkna, // Horizontal Kana Alternates + KBTS_FEATURE_ID_hlig, // Historical Ligatures + KBTS_FEATURE_ID_hngl, // Hangul + KBTS_FEATURE_ID_hojo, // Hojo Kanji Forms (JIS X 0212-1990 Kanji Forms) + KBTS_FEATURE_ID_hwid, // Half Widths + KBTS_FEATURE_ID_ital, // Italics + KBTS_FEATURE_ID_jalt, // Justification Alternates + KBTS_FEATURE_ID_jp78, // JIS78 Forms + KBTS_FEATURE_ID_jp83, // JIS83 Forms + KBTS_FEATURE_ID_jp90, // JIS90 Forms + KBTS_FEATURE_ID_jp04, // JIS2004 Forms + KBTS_FEATURE_ID_kern, // Kerning + KBTS_FEATURE_ID_lfbd, // Left Bounds + KBTS_FEATURE_ID_liga, // Standard Ligatures + KBTS_FEATURE_ID_lnum, // Lining Figures + KBTS_FEATURE_ID_locl, // Localized Forms + KBTS_FEATURE_ID_ltra, // Left-to-right Alternates + KBTS_FEATURE_ID_ltrm, // Left-to-right Mirrored Forms + KBTS_FEATURE_ID_mark, // Mark Positioning + KBTS_FEATURE_ID_mgrk, // Mathematical Greek + KBTS_FEATURE_ID_mkmk, // Mark to Mark Positioning + KBTS_FEATURE_ID_mset, // Mark Positioning via Substitution + KBTS_FEATURE_ID_nalt, // Alternate Annotation Forms + KBTS_FEATURE_ID_nlck, // NLC Kanji Forms + KBTS_FEATURE_ID_nukt, // Nukta Forms + KBTS_FEATURE_ID_onum, // Oldstyle Figures + KBTS_FEATURE_ID_opbd, // Optical Bounds + KBTS_FEATURE_ID_ordn, // Ordinals + KBTS_FEATURE_ID_ornm, // Ornaments + KBTS_FEATURE_ID_palt, // Proportional Alternate Widths + KBTS_FEATURE_ID_pcap, // Petite Capitals + KBTS_FEATURE_ID_pkna, // Proportional Kana + KBTS_FEATURE_ID_pnum, // Proportional Figures + KBTS_FEATURE_ID_pres, // Pre-base Substitutions + KBTS_FEATURE_ID_psts, // Post-base Substitutions + KBTS_FEATURE_ID_pwid, // Proportional Widths + KBTS_FEATURE_ID_qwid, // Quarter Widths + KBTS_FEATURE_ID_rand, // Randomize + KBTS_FEATURE_ID_rclt, // Required Contextual Alternates + KBTS_FEATURE_ID_rkrf, // Rakar Forms + KBTS_FEATURE_ID_rlig, // Required Ligatures + KBTS_FEATURE_ID_rtbd, // Right Bounds + KBTS_FEATURE_ID_rtla, // Right-to-left Alternates + KBTS_FEATURE_ID_rtlm, // Right-to-left Mirrored Forms + KBTS_FEATURE_ID_ruby, // Ruby Notation Forms + KBTS_FEATURE_ID_rvrn, // Required Variation Alternates + KBTS_FEATURE_ID_salt, // Stylistic Alternates + KBTS_FEATURE_ID_sinf, // Scientific Inferiors + KBTS_FEATURE_ID_size, // Optical size + KBTS_FEATURE_ID_smcp, // Small Capitals + KBTS_FEATURE_ID_smpl, // Simplified Forms + KBTS_FEATURE_ID_ss01, // Stylistic Set 1 + KBTS_FEATURE_ID_ss02, // Stylistic Set 2 + KBTS_FEATURE_ID_ss03, // Stylistic Set 3 + KBTS_FEATURE_ID_ss04, // Stylistic Set 4 + KBTS_FEATURE_ID_ss05, // Stylistic Set 5 + KBTS_FEATURE_ID_ss06, // Stylistic Set 6 + KBTS_FEATURE_ID_ss07, // Stylistic Set 7 + KBTS_FEATURE_ID_ss08, // Stylistic Set 8 + KBTS_FEATURE_ID_ss09, // Stylistic Set 9 + KBTS_FEATURE_ID_ss10, // Stylistic Set 10 + KBTS_FEATURE_ID_ss11, // Stylistic Set 11 + KBTS_FEATURE_ID_ss12, // Stylistic Set 12 + KBTS_FEATURE_ID_ss13, // Stylistic Set 13 + KBTS_FEATURE_ID_ss14, // Stylistic Set 14 + KBTS_FEATURE_ID_ss15, // Stylistic Set 15 + KBTS_FEATURE_ID_ss16, // Stylistic Set 16 + KBTS_FEATURE_ID_ss17, // Stylistic Set 17 + KBTS_FEATURE_ID_ss18, // Stylistic Set 18 + KBTS_FEATURE_ID_ss19, // Stylistic Set 19 + KBTS_FEATURE_ID_ss20, // Stylistic Set 20 + KBTS_FEATURE_ID_ssty, // Math Script-style Alternates + KBTS_FEATURE_ID_stch, // Stretching Glyph Decomposition + KBTS_FEATURE_ID_subs, // Subscript + KBTS_FEATURE_ID_sups, // Superscript + KBTS_FEATURE_ID_swsh, // Swash + KBTS_FEATURE_ID_test, // Test features, only for development + KBTS_FEATURE_ID_titl, // Titling + KBTS_FEATURE_ID_tnam, // Traditional Name Forms + KBTS_FEATURE_ID_tnum, // Tabular Figures + KBTS_FEATURE_ID_trad, // Traditional Forms + KBTS_FEATURE_ID_twid, // Third Widths + KBTS_FEATURE_ID_unic, // Unicase + KBTS_FEATURE_ID_valt, // Alternate Vertical Metrics + KBTS_FEATURE_ID_vapk, // Kerning for Alternate Proportional Vertical Metrics + KBTS_FEATURE_ID_vatu, // Vattu Variants + KBTS_FEATURE_ID_vchw, // Vertical Contextual Half-width Spacing + KBTS_FEATURE_ID_vert, // Vertical Alternates + KBTS_FEATURE_ID_vhal, // Alternate Vertical Half Metrics + KBTS_FEATURE_ID_vkna, // Vertical Kana Alternates + KBTS_FEATURE_ID_vkrn, // Vertical Kerning + KBTS_FEATURE_ID_vpal, // Proportional Alternate Vertical Metrics + KBTS_FEATURE_ID_vrt2, // Vertical Alternates and Rotation + KBTS_FEATURE_ID_vrtr, // Vertical Alternates for Rotation + KBTS_FEATURE_ID_zero, // Slashed Zero + KBTS_FEATURE_ID_COUNT, +}; + +typedef kbts_u8 kbts_shaping_table; +enum kbts_shaping_table_enum +{ + KBTS_SHAPING_TABLE_GSUB, + KBTS_SHAPING_TABLE_GPOS, + KBTS_SHAPING_TABLE_COUNT, +}; + +typedef struct kbts_lookup_info +{ + kbts_u32 MaximumBacktrackWithoutSkippingGlyphs; + kbts_u32 MaximumLookaheadWithoutSkippingGlyphs; + kbts_u32 MaximumSubstitutionOutputSize; + kbts_u32 MaximumInputSequenceLength; + kbts_u32 MaximumLookupStackSize; +} kbts_lookup_info; + +typedef struct kbts_op_state kbts_op_state; +typedef struct kbts_gdef kbts_gdef; +typedef struct kbts_cmap_14 kbts_cmap_14; +typedef struct kbts_gsub_gpos kbts_gsub_gpos; +typedef struct kbts_maxp kbts_maxp; +typedef struct kbts_hea kbts_hea; +typedef struct kbts_iterate_features kbts_iterate_features; +typedef struct kbts_shape_state kbts_shape_state; +typedef struct kbts_shaper_properties kbts_shaper_properties; +typedef struct kbts_feature kbts_feature; +typedef struct kbts_head kbts_head; + +typedef struct kbts_lookup_subtable_info +{ + kbts_u32 MinimumBacktrackPlusOne; + kbts_u32 MinimumFollowupPlusOne; +} kbts_lookup_subtable_info; + +typedef struct kbts_font +{ + char *FileBase; + kbts_un FileSize; + kbts_head *Head; + kbts_u16 *Cmap; + kbts_gdef *Gdef; + kbts_cmap_14 *Cmap14; + kbts_gsub_gpos *ShapingTables[KBTS_SHAPING_TABLE_COUNT]; + void *Fvar; + kbts_maxp *Maxp; + + kbts_hea *Hea[KBTS_ORIENTATION_COUNT]; + kbts_u16 *Mtx[KBTS_ORIENTATION_COUNT]; + + kbts_lookup_info LookupInfo; + + kbts_u32 GlyphCount; + kbts_u32 LookupCount; + kbts_u32 SubtableCount; + + kbts_u32 *GlyphLookupMatrix; // [LookupCount * GlyphCount] bitmap + kbts_u32 *GlyphLookupSubtableMatrix; // [LookupSubtableCount * GlyphCount] bitmap + kbts_u32 *LookupSubtableIndexOffsets; // [LookupCount] + kbts_lookup_subtable_info *SubtableInfos; // [LookupSubtableCount] + kbts_u32 GposLookupIndexOffset; + + int Error; +} kbts_font; + +typedef struct kbts_glyph_classes +{ + kbts_u16 Class; + kbts_u16 MarkAttachmentClass; +} kbts_glyph_classes; + +typedef struct kbts_feature_set +{ + kbts_u64 Flags[(KBTS_FEATURE_ID_COUNT + 63) / 64]; +} kbts_feature_set; + +typedef struct kbts_feature_override +{ + kbts_feature_id Id; + kbts_feature_tag Tag; + kbts_u32 EnabledOrAlternatePlusOne; +} kbts_feature_override; + +typedef struct kbts_glyph_config +{ + kbts_feature_set EnabledFeatures; + kbts_feature_set DisabledFeatures; + kbts_u32 FeatureOverrideCount; + kbts_u32 FeatureOverrideCapacity; + kbts_u32 RequiredFeatureOverrideCapacity; + kbts_feature_override *FeatureOverrides; // [FeatureOverrideCount] +} kbts_glyph_config; + +typedef struct kbts_glyph +{ + kbts_u32 Codepoint; + kbts_u16 Id; // Glyph index. This is what you want to use to query outline data. + kbts_u16 Uid; + kbts_glyph_classes Classes; + + kbts_u64 Decomposition; + + kbts_glyph_config *Config; + + kbts_glyph_flags Flags; + + // These fields are the glyph's final positioning data. + // For normal usage, you should not have to use these directly yourself. + // In case you are curious or have a specific need, see kbts_PositionGlyph() to see how these are used. + kbts_s32 OffsetX; + kbts_s32 OffsetY; + kbts_s32 AdvanceX; + kbts_s32 AdvanceY; + + kbts_u32 ParentInfo; + + // This is set by GSUB and used by GPOS. + // A 0-index means that we should attach to the last component in the ligature. + // + // From the Microsoft docs: + // To correctly access the subtables, the client must keep track of the component associated with the mark. + // + // For a given mark assigned to a particular class, the appropriate base attachment point is determined by which + // ligature component the mark is associated with. This is dependent on the original character string and subsequent + // character- or glyph-sequence processing, not the font data alone. While a text-layout client is performing any + // character-based preprocessing or any glyph-substitution operations using the GSUB table, the text-layout client + // must keep track of associations of marks to particular ligature-glyph components. + kbts_u16 LigatureUid; + kbts_u16 LigatureComponentIndexPlusOne; + + // Earlier on, we used to assume that, if a glyph had no advance, or had the MARK glyph class, then + // it could be handled as a mark in layout operations. This is inaccurate. + // Unicode makes a distinction between attached marks and standalone marks. For our purposes, attached + // marks are marks that have found a valid base character to attach to. In practice, this means that the + // font contains a valid display position/configuration for it in the current context. + // In contrast, standalone marks are marks that aren't attached to anything. Fonts may still have glyphs + // for them, in which case we want to display those just like regular glyphs that take up horizontal space + // on the line. When fonts don't have glyphs for them, they simply stay around as zero-width glyphs. + // Standalone marks have notably different behavior compared to attached marks, and so, once we start + // applying positioning features, it becomes worthwhile to track exactly which glyph has attached to which. + kbts_u16 AttachGlyphIndexPlusOne; // Set by GPOS attachments. + + // Set in GSUB and used in GPOS, for STCH. + kbts_joining_feature JoiningFeature; + + // Unicode properties filled in by CodepointToGlyph. + kbts_unicode_joining_type JoiningType; + kbts_u8 Script; + kbts_u8 UnicodeFlags; + kbts_u8 SyllabicClass; + kbts_u8 SyllabicPosition; + kbts_u8 UseClass; + kbts_u8 CombiningClass; + + kbts_u8 MarkOrdering; // Only used temporarily in NORMALIZE for Arabic mark reordering. +} kbts_glyph; + +typedef struct kbts_glyph_array +{ + kbts_glyph *Glyphs; + kbts_u32 Count; + kbts_u32 TotalCount; + kbts_u32 Capacity; + kbts_u32 RequiredCapacity; +} kbts_glyph_array; + +typedef struct kbts_op_state_normalize +{ + kbts_un CodepointsToDecomposeCount; + kbts_un AboveBaseGlyphCount; +} kbts_op_state_normalize; + +typedef struct kbts_op_state_gsub +{ + kbts_feature_set LookupFeatures; + kbts_un LookupIndex; + kbts_u32 GlyphFilter; + kbts_u32 SkipFlags; +} kbts_op_state_gsub; + +typedef struct kbts_op_state_normalize_hangul +{ + kbts_glyph LvtGlyphs[4]; + kbts_un LvtGlyphCount; +} kbts_op_state_normalize_hangul; + +typedef union kbts_op_state_op_specific +{ + kbts_op_state_normalize Normalize; + kbts_op_state_gsub Gsub; + kbts_op_state_normalize_hangul NormalizeHangul; +} kbts_op_state_op_specific; + +typedef struct kbts_lookup_indices +{ + kbts_u32 FeatureTag; + kbts_u32 FeatureId; + kbts_u32 SkipFlags; + kbts_u32 GlyphFilter; + kbts_u32 Count; + kbts_u16 *Indices; +} kbts_lookup_indices; + +typedef struct kbts_op +{ + kbts_op_kind Kind; + kbts_feature_set Features; +} kbts_op; + +// This needs to be updated when we change the op lists! +#define KBTS_MAX_SIMULTANEOUS_FEATURES 16 +typedef struct kbts_op_state +{ + kbts_un WrittenCount; + kbts_un GlyphIndex; + kbts_u32 FrameCount; + kbts_u32 ResumePoint; + + kbts_u32 FeatureCount; + kbts_lookup_indices FeatureLookupIndices[KBTS_MAX_SIMULTANEOUS_FEATURES]; + kbts_u32 UnregisteredFeatureCount; + kbts_feature_tag UnregisteredFeatureTags[KBTS_MAX_SIMULTANEOUS_FEATURES]; + + kbts_op_state_op_specific OpSpecific; + + // Ops are free to use the following as they please: + // kbts_u8 LeftoverMemory[LeftoverMemorySize]; +} kbts_op_state; + +typedef struct kbts_op_list +{ + kbts_u8 *Ops; + kbts_un Length; +} kbts_op_list; + +typedef struct kbts_indic_script_properties +{ + kbts_u32 ViramaCodepoint; + kbts_u8 BlwfPostOnly; + kbts_reph_position RephPosition; + kbts_reph_encoding RephEncoding; + kbts_syllabic_position RightSideMatraPosition; + kbts_syllabic_position AboveBaseMatraPosition; + kbts_syllabic_position BelowBaseMatraPosition; +} kbts_indic_script_properties; + +typedef struct kbts_langsys kbts_langsys; +typedef struct kbts_shape_config +{ + kbts_font *Font; + kbts_script Script; + kbts_language Language; + kbts_langsys *Langsys[KBTS_SHAPING_TABLE_COUNT]; + kbts_op_list OpLists[4]; + + kbts_feature_set *Features; + + kbts_shaper Shaper; + kbts_shaper_properties *ShaperProperties; + + kbts_indic_script_properties IndicScriptProperties; + kbts_feature *Blwf; + kbts_feature *Pref; + kbts_feature *Pstf; + kbts_feature *Locl; + kbts_feature *Rphf; + kbts_feature *Half; + kbts_feature *Vatu; + + // Indic + kbts_glyph Virama; + + kbts_glyph DottedCircle; + kbts_glyph Whitespace; + + // Thai + kbts_glyph Nikhahit; + kbts_glyph SaraAa; +} kbts_shape_config; + +typedef struct kbts_shape_state +{ + kbts_op Op; + kbts_shape_config *Config; + kbts_direction MainDirection; + kbts_direction RunDirection; + + kbts_feature_set UserFeatures; + + kbts_glyph_array GlyphArray; + kbts_glyph_array ClusterGlyphArray; + + kbts_u32 DottedCircleInsertIndex; + + kbts_u32 GlyphCountStartingFromCurrentCluster; + + kbts_u32 At; + kbts_u32 ResumePoint; + kbts_u32 OpGlyphOffset; + kbts_u32 ClusterGlyphCount; + kbts_u32 Ip; + kbts_u32 NextGlyphUid; + + kbts_u32 RequiredGlyphCapacity; + + int RealCluster; + int ClusterAtStartOfWord; + int WordBreak; + + // This must always be the last member! + kbts_op_state OpState; +} kbts_shape_state; + +typedef struct kbts_cursor +{ + kbts_direction Direction; + kbts_s32 LastAdvanceX; + kbts_s32 X; + kbts_s32 Y; +} kbts_cursor; + +typedef struct kbts_break +{ + // The break code mostly works in relative positions, but we convert to absolute positions for the user. + // That way, breaks can be trivially stored and compared and such and it just works. + kbts_u32 Position; + kbts_break_flags Flags; + kbts_direction Direction; // Only valid if (Flags & KBTS_BREAK_FLAG_DIRECTION). + kbts_script Script; // Only valid if (Flags & KBTS_BREAK_FLAG_SCRIPT). +} kbts_break; + +typedef struct kbts_bracket +{ + kbts_u32 Codepoint; + kbts_u8 Direction; + kbts_u8 Script; +} kbts_bracket; + +typedef kbts_u32 kbts_break_state_flags; +enum kbts_break_state_flags_enum +{ + KBTS_BREAK_STATE_FLAG_STARTED = 1, + KBTS_BREAK_STATE_FLAG_END = 2, + KBTS_BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE = 4, + + // Bidirectional flags + KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L = 8, + KBTS_BREAK_STATE_FLAG_SAW_AL_AFTER_LR = 0x10, + KBTS_BREAK_STATE_FLAG_LAST_WAS_BRACKET = 0x20, +}; + +// In the worst case, a single call to BreakAddCodepoint would generate 4 breaks. +// We buffer breaks to reorder them before returning them to the user. +// This potentially requires infinite memory, which we don't have, so you may want to tweak this constant, +// although, really, if the defaults don't work, then you have likely found very strange/adversarial text. +#define KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD 4 +#define KBTS_BREAK_REORDER_BUFFER_SIZE (KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD * 2) +typedef struct kbts_break_state +{ + kbts_break Breaks[KBTS_BREAK_REORDER_BUFFER_SIZE]; + kbts_u32 BreakCount; + kbts_direction MainDirection; + + kbts_u32 LastFlushedBreakPosition; + kbts_u32 CurrentPosition; + + kbts_u8 LastScripts[2]; + + kbts_bracket Brackets[64]; + kbts_u32 BracketCount; + kbts_break_state_flags Flags; + + kbts_u32 FlagState; // u8(kbts_break_flags)x4 + kbts_s16 PositionOffset2; + kbts_s16 PositionOffset3; + + kbts_u32 WordBreakHistory; // u8x4 + kbts_u16 WordBreaks; // u4x4 + kbts_u16 WordUnbreaks; // u4x4 + kbts_s16 WordBreak2PositionOffset; + + kbts_u64 LineBreaks; // u16x4 + // Instead of staying synchronized with LineBreaks/LineUnbreaks, + // this advances every character always. + // (This is only needed because ZWJ can create an unbreak while simultaneously being ignored.) + kbts_u64 LineUnbreaksAsync; // u16x4 + kbts_u64 LineUnbreaks; // u16x4 + kbts_u32 LineBreakHistory; // u8(line_break_class)x4 + kbts_s16 LineBreak2PositionOffset; + kbts_s16 LineBreak3PositionOffset; + + kbts_u8 LastDirection; + kbts_u8 BidirectionalClass2; + kbts_u8 BidirectionalClass1; + + kbts_japanese_line_break_style JapaneseLineBreakStyle; + kbts_u8 GraphemeBreakState; + kbts_u8 LastLineBreakClass; + kbts_u8 LastWordBreakClass; + kbts_u8 LastWordBreakClassIncludingIgnored; +} kbts_break_state; + +typedef struct kbts_decode +{ + kbts_u32 Codepoint; + + kbts_u32 SourceCharactersConsumed; + kbts_u32 Valid; +} kbts_decode; + +#ifndef KB_TEXT_SHAPE_NO_CRT +KBTS_EXPORT kbts_font kbts_FontFromFile(const char *FileName); +KBTS_EXPORT void kbts_FreeFont(kbts_font *Font); +KBTS_EXPORT kbts_shape_state *kbts_CreateShapeState(kbts_font *Font); +KBTS_EXPORT void kbts_FreeShapeState(kbts_shape_state *State); +#endif +KBTS_EXPORT kbts_feature_id kbts_FeatureTagToId(kbts_feature_tag Tag); +KBTS_EXPORT kbts_feature_override kbts_FeatureOverride(kbts_feature_id Id, int Alternate, kbts_u32 Value); +KBTS_EXPORT kbts_feature_override kbts_FeatureOverrideFromTag(kbts_feature_tag Tag, int Alternate, kbts_u32 Value); +KBTS_EXPORT kbts_glyph_config kbts_GlyphConfig(kbts_feature_override *FeatureOverrides, kbts_u32 FeatureOverrideCount); +KBTS_EXPORT kbts_glyph_config kbts_EmptyGlyphConfig(kbts_feature_override *FeatureOverrides, kbts_u32 FeatureOverrideCapacity); +KBTS_EXPORT int kbts_GlyphConfigOverrideFeature(kbts_glyph_config *Config, kbts_feature_id Id, int Alternate, kbts_u32 Value); +KBTS_EXPORT int kbts_GlyphConfigOverrideFeatureFromTag(kbts_glyph_config *Config, kbts_feature_tag Tag, int Alternate, kbts_u32 Value); +KBTS_EXPORT int kbts_FontIsValid(kbts_font *Font); +KBTS_EXPORT kbts_un kbts_ReadFontHeader(kbts_font *Font, void *Data, kbts_un Size); +KBTS_EXPORT kbts_un kbts_ReadFontData(kbts_font *Font, void *Scratch, kbts_un ScratchSize); +KBTS_EXPORT int kbts_PostReadFontInitialize(kbts_font *Font, void *Memory, kbts_un MemorySize); +KBTS_EXPORT kbts_un kbts_SizeOfShapeState(kbts_font *Font); +KBTS_EXPORT kbts_shape_state *kbts_PlaceShapeState(void *Address, kbts_un Size); +KBTS_EXPORT void kbts_ResetShapeState(kbts_shape_state *State); +KBTS_EXPORT kbts_shape_config kbts_ShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language); +KBTS_EXPORT int kbts_ShaperIsComplex(kbts_shaper Shaper); +KBTS_EXPORT int kbts_Shape(kbts_shape_state *State, kbts_shape_config *Config, kbts_direction MainDirection, kbts_direction RunDirection, kbts_glyph *Glyphs, kbts_u32 *GlyphCount, kbts_u32 GlyphCapacity); +KBTS_EXPORT kbts_cursor kbts_Cursor(kbts_direction Direction); +KBTS_EXPORT void kbts_PositionGlyph(kbts_cursor *Cursor, kbts_glyph *Glyph, kbts_s32 *X, kbts_s32 *Y); +KBTS_EXPORT void kbts_BeginBreak(kbts_break_state *State, kbts_direction MainDirection, kbts_japanese_line_break_style JapaneseLineBreakStyle); +KBTS_EXPORT int kbts_BreakStateIsValid(kbts_break_state *State); +KBTS_EXPORT void kbts_BreakAddCodepoint(kbts_break_state *State, kbts_u32 Codepoint, kbts_u32 PositionIncrement, int EndOfText); +KBTS_EXPORT void kbts_BreakFlush(kbts_break_state *State); +KBTS_EXPORT int kbts_Break(kbts_break_state *State, kbts_break *Break); +KBTS_EXPORT kbts_decode kbts_DecodeUtf8(const char *Utf8, kbts_un Length); +KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint); +KBTS_EXPORT void kbts_InferScript(kbts_direction *Direction, kbts_script *Script, kbts_script GlyphScript); +KBTS_EXPORT int kbts_ScriptIsComplex(kbts_script Script); +KBTS_EXPORT kbts_script kbts_ScriptTagToScript(kbts_script_tag Tag); +#endif + +#ifdef KB_TEXT_SHAPE_IMPLEMENTATION +#ifdef _MSC_VER +#define KBTS_UNUSED(X) (void)sizeof((X)) +#else +#define KBTS_UNUSED(X) (void)(X) +#endif +# define KBTS_FOR(I, Start, End) for(kbts_un I = (Start); I < (End); ++I) +# ifdef __cplusplus +# define KBTS_ZERO {} +# define KBTS_ZERO_TYPE(T) T{} +# else +# define KBTS_ZERO {0} +# define KBTS_ZERO_TYPE(T) (T){0} +# endif +# define KBTS_MAX(A, B) (((A) < (B)) ? (B) : (A)) +# define KBTS_MIN(A, B) (((A) < (B)) ? (A) : (B)) +# define KBTS_ARRAY_LENGTH(A) (sizeof(A)/sizeof(*(A))) +# define KBTS_POINTER_AFTER(Type, X) ((Type *)((X) + 1)) +# define KBTS_POINTER_OFFSET(Type, Base, Offset) ((Type *)((char *)(Base) + (Offset))) +# define KBTS_POINTER_DIFF32(Pointer, Base) ((kbts_u32)((char *)(Pointer) - (char *)(Base))) +# define KBTS_PASTE_1(A, B) A##B +# define KBTS_PASTE_0(A, B) KBTS_PASTE_1(A, B) +# define KBTS_PASTE(A, B) KBTS_PASTE_0(A, B) +# define KBTS_IN_SET(X, Set) ((1u << (X)) & (Set)) +# define KBTS_SET32_0(Arg) | (1u << (Arg)) KBTS_SET32_1 +# define KBTS_SET32_1(Arg) | (1u << (Arg)) KBTS_SET32_0 +# define KBTS_SET32_0End +# define KBTS_SET32_1End +# define KBTS_SET32(Args) (0u KBTS_PASTE(KBTS_SET32_0 Args, End)) +# define KBTS_IN_SET64(X, Set) ((1ull << (X)) & (Set)) +# define KBTS_SET64_0(Arg) | (1ull << (Arg)) KBTS_SET64_1 +# define KBTS_SET64_1(Arg) | (1ull << (Arg)) KBTS_SET64_0 +# define KBTS_SET64_0End +# define KBTS_SET64_1End +# define KBTS_SET64(Args) (0u KBTS_PASTE(KBTS_SET64_0 Args, End)) + +# ifndef KBTS_ASSERT +#ifndef KB_TEXT_SHAPE_NO_CRT +# include +# define KBTS_ASSERT(Cond) assert(Cond) +#else +#define KBTS_ASSERT(Cond) +#endif +# endif + +#ifndef KB_TEXT_SHAPE_NO_CRT +#include +#endif + +#ifndef KBTS_MEMSET +#include +#define KBTS_MEMSET memset +#endif + +#ifndef kbts_ByteSwap16 +# if defined(_MSC_VER) && !defined(__clang__) +# define kbts_ByteSwap16(X) _byteswap_ushort(X) +# define kbts_ByteSwap32(X) _byteswap_ulong(X) +# define kbts_PopCount32(X) (kbts_un)__popcnt(X) +# elif defined(__clang__) || defined(__GNUC__) +# define kbts_ByteSwap16(X) __builtin_bswap16(X) +# define kbts_ByteSwap32(X) __builtin_bswap32(X) +# define kbts_PopCount32(X) (kbts_un)__builtin_popcount(X) +# else +# error Unsupported compiler! +# endif +#endif + +#define KBTS_FEATURE_FLAG0(Feature) (1ull << KBTS_FEATURE_ID_##Feature) +#define KBTS_FEATURE_FLAG1(Feature) (1ull << (KBTS_FEATURE_ID_##Feature - 64)) +#define KBTS_FEATURE_FLAG2(Feature) (1ull << (KBTS_FEATURE_ID_##Feature - 128)) +#define KBTS_FEATURE_FLAG3(Feature) (1ull << (KBTS_FEATURE_ID_##Feature - 192)) + +// # define KBTS_DUMP +# ifdef KBTS_DUMP +# define KBTS_DUMPF(...) printf(__VA_ARGS__), fflush(stdout) +# else +# define KBTS_DUMPF(...) +# endif + +# define KBTS_GROW_BUFFER_MARGIN 16 + +#ifndef KBTS_INSTRUMENT_BLOCK_BEGIN +#define KBTS_INSTRUMENT_BLOCK_BEGIN(Name) +#define KBTS_INSTRUMENT_FUNCTION_BEGIN +#define KBTS_INSTRUMENT_END +#endif + +#define KBTS_MAXIMUM_DECOMPOSITION_CODEPOINTS 6 +typedef struct kbts_script_properties { + kbts_u32 Tag; + kbts_shaper Shaper; +} kbts_script_properties; + +static kbts_script_properties kbts_ScriptProperties[KBTS_SCRIPT_COUNT] = { + {KBTS_FOURCC(' ', ' ', ' ', ' '), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('a', 'd', 'l', 'm'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('a', 'h', 'o', 'm'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('h', 'l', 'u', 'w'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('a', 'r', 'a', 'b'), KBTS_SHAPER_ARABIC}, + {KBTS_FOURCC('a', 'r', 'm', 'n'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('a', 'v', 's', 't'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('b', 'a', 'l', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('b', 'a', 'm', 'u'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('b', 'a', 's', 's'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('b', 'a', 't', 'k'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('b', 'n', 'g', '2'), KBTS_SHAPER_INDIC}, + {KBTS_FOURCC('b', 'h', 'k', 's'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('b', 'o', 'p', 'o'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('b', 'r', 'a', 'h'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('b', 'u', 'g', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('b', 'u', 'h', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('c', 'a', 'n', 's'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('c', 'a', 'r', 'i'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('a', 'g', 'h', 'b'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('c', 'a', 'k', 'm'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('c', 'h', 'a', 'm'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('c', 'h', 'e', 'r'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('c', 'h', 'r', 's'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('h', 'a', 'n', 'i'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('c', 'o', 'p', 't'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('c', 'p', 'r', 't'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('c', 'p', 'm', 'n'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('c', 'y', 'r', 'l'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('D', 'F', 'L', 'T'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('D', 'F', 'L', 'T'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('d', 's', 'r', 't'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('d', 'e', 'v', '2'), KBTS_SHAPER_INDIC}, + {KBTS_FOURCC('d', 'i', 'a', 'k'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('d', 'o', 'g', 'r'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('d', 'u', 'p', 'l'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('e', 'g', 'y', 'p'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('e', 'l', 'b', 'a'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('e', 'l', 'y', 'm'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('e', 't', 'h', 'i'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('g', 'a', 'r', 'a'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('g', 'e', 'o', 'r'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('g', 'l', 'a', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('g', 'o', 't', 'h'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('g', 'r', 'a', 'n'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('g', 'r', 'e', 'k'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('g', 'j', 'r', '2'), KBTS_SHAPER_INDIC}, + {KBTS_FOURCC('g', 'o', 'n', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('g', 'u', 'r', '2'), KBTS_SHAPER_INDIC}, + {KBTS_FOURCC('g', 'u', 'k', 'h'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('h', 'a', 'n', 'g'), KBTS_SHAPER_HANGUL}, + {KBTS_FOURCC('r', 'o', 'h', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('h', 'a', 'n', 'o'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('h', 'a', 't', 'r'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('h', 'e', 'b', 'r'), KBTS_SHAPER_HEBREW}, + {KBTS_FOURCC('k', 'a', 'n', 'a'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('a', 'r', 'm', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('p', 'h', 'l', 'i'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('p', 'r', 't', 'i'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('j', 'a', 'v', 'a'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('k', 't', 'h', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('k', 'n', 'd', '2'), KBTS_SHAPER_INDIC}, + {KBTS_FOURCC('k', 'a', 'n', 'a'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('k', 'a', 'w', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('k', 'a', 'l', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('k', 'h', 'a', 'r'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('k', 'i', 't', 's'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('k', 'h', 'm', 'r'), KBTS_SHAPER_KHMER}, + {KBTS_FOURCC('k', 'h', 'o', 'j'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'i', 'n', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('k', 'r', 'a', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('l', 'a', 'o', ' '), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('l', 'a', 't', 'n'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('l', 'e', 'p', 'c'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('l', 'i', 'm', 'b'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('l', 'i', 'n', 'a'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('l', 'i', 'n', 'b'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('l', 'i', 's', 'u'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('l', 'y', 'c', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('l', 'y', 'd', 'i'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('m', 'a', 'h', 'j'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'a', 'k', 'a'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'l', 'm', '2'), KBTS_SHAPER_INDIC}, + {KBTS_FOURCC('m', 'a', 'n', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'a', 'n', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'a', 'r', 'c'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('g', 'o', 'n', 'm'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'e', 'd', 'f'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 't', 'e', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'e', 'n', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'e', 'r', 'c'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'e', 'r', 'o'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('p', 'l', 'r', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'o', 'd', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'o', 'n', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'r', 'o', 'o'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('m', 'u', 'l', 't'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('m', 'y', 'm', '2'), KBTS_SHAPER_MYANMAR}, + {KBTS_FOURCC('n', 'b', 'a', 't'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('n', 'a', 'g', 'm'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('n', 'a', 'n', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('n', 'e', 'w', 'a'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'a', 'l', 'u'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('n', 'k', 'o', ' '), KBTS_SHAPER_USE}, + {KBTS_FOURCC('n', 's', 'h', 'u'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('h', 'm', 'n', 'p'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('o', 'g', 'a', 'm'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('o', 'l', 'c', 'k'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('o', 'n', 'a', 'o'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('i', 't', 'a', 'l'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('h', 'u', 'n', 'g'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('n', 'a', 'r', 'b'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('p', 'e', 'r', 'm'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('x', 'p', 'e', 'o'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'o', 'g', 'o'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'a', 'r', 'b'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('o', 'r', 'k', 'h'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('o', 'u', 'g', 'r'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('o', 'r', 'y', '2'), KBTS_SHAPER_INDIC}, + {KBTS_FOURCC('o', 's', 'g', 'e'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('o', 's', 'm', 'a'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('h', 'm', 'n', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('p', 'a', 'l', 'm'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('p', 'a', 'u', 'c'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('p', 'h', 'a', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('p', 'h', 'n', 'x'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('p', 'h', 'l', 'p'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('r', 'j', 'n', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('r', 'u', 'n', 'r'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('s', 'a', 'm', 'r'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('s', 'a', 'u', 'r'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'h', 'r', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'h', 'a', 'w'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('s', 'i', 'd', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'g', 'n', 'w'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'o', 'g', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'i', 'n', 'h'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'o', 'r', 'a'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'o', 'y', 'o'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('x', 's', 'u', 'x'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'u', 'n', 'd'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'u', 'n', 'u'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'y', 'l', 'o'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('s', 'y', 'r', 'c'), KBTS_SHAPER_ARABIC}, + {KBTS_FOURCC('t', 'g', 'l', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'a', 'g', 'b'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'a', 'l', 'e'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('l', 'a', 'n', 'a'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'a', 'v', 't'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'a', 'k', 'r'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'm', 'l', '2'), KBTS_SHAPER_INDIC}, + {KBTS_FOURCC('t', 'n', 's', 'a'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'a', 'n', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'e', 'l', '2'), KBTS_SHAPER_INDIC}, + {KBTS_FOURCC('t', 'h', 'a', 'a'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('t', 'h', 'a', 'i'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('t', 'i', 'b', 't'), KBTS_SHAPER_TIBETAN}, + {KBTS_FOURCC('t', 'f', 'n', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'i', 'r', 'h'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'o', 'd', 'r'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'o', 't', 'o'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('t', 'u', 't', 'g'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('u', 'g', 'a', 'r'), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('v', 'a', 'i', ' '), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('v', 'i', 't', 'h'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('w', 'c', 'h', 'o'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('w', 'a', 'r', 'a'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('y', 'e', 'z', 'i'), KBTS_SHAPER_USE}, + {KBTS_FOURCC('y', 'i', ' ', ' '), KBTS_SHAPER_DEFAULT}, + {KBTS_FOURCC('z', 'a', 'n', 'b'), KBTS_SHAPER_USE}, +}; + +KBTS_EXPORT kbts_script kbts_ScriptTagToScript(kbts_script_tag Tag) +{ + kbts_script Result = 0; + switch(Tag) + { + case KBTS_SCRIPT_TAG_DONT_KNOW: Result = KBTS_SCRIPT_DONT_KNOW; break; + case KBTS_SCRIPT_TAG_ADLAM: Result = KBTS_SCRIPT_ADLAM; break; + case KBTS_SCRIPT_TAG_AHOM: Result = KBTS_SCRIPT_AHOM; break; + case KBTS_SCRIPT_TAG_ANATOLIAN_HIEROGLYPHS: Result = KBTS_SCRIPT_ANATOLIAN_HIEROGLYPHS; break; + case KBTS_SCRIPT_TAG_ARABIC: Result = KBTS_SCRIPT_ARABIC; break; + case KBTS_SCRIPT_TAG_ARMENIAN: Result = KBTS_SCRIPT_ARMENIAN; break; + case KBTS_SCRIPT_TAG_AVESTAN: Result = KBTS_SCRIPT_AVESTAN; break; + case KBTS_SCRIPT_TAG_BALINESE: Result = KBTS_SCRIPT_BALINESE; break; + case KBTS_SCRIPT_TAG_BAMUM: Result = KBTS_SCRIPT_BAMUM; break; + case KBTS_SCRIPT_TAG_BASSA_VAH: Result = KBTS_SCRIPT_BASSA_VAH; break; + case KBTS_SCRIPT_TAG_BATAK: Result = KBTS_SCRIPT_BATAK; break; + case KBTS_SCRIPT_TAG_BENGALI: Result = KBTS_SCRIPT_BENGALI; break; + case KBTS_SCRIPT_TAG_BHAIKSUKI: Result = KBTS_SCRIPT_BHAIKSUKI; break; + case KBTS_SCRIPT_TAG_BOPOMOFO: Result = KBTS_SCRIPT_BOPOMOFO; break; + case KBTS_SCRIPT_TAG_BRAHMI: Result = KBTS_SCRIPT_BRAHMI; break; + case KBTS_SCRIPT_TAG_BUGINESE: Result = KBTS_SCRIPT_BUGINESE; break; + case KBTS_SCRIPT_TAG_BUHID: Result = KBTS_SCRIPT_BUHID; break; + case KBTS_SCRIPT_TAG_CANADIAN_SYLLABICS: Result = KBTS_SCRIPT_CANADIAN_SYLLABICS; break; + case KBTS_SCRIPT_TAG_CARIAN: Result = KBTS_SCRIPT_CARIAN; break; + case KBTS_SCRIPT_TAG_CAUCASIAN_ALBANIAN: Result = KBTS_SCRIPT_CAUCASIAN_ALBANIAN; break; + case KBTS_SCRIPT_TAG_CHAKMA: Result = KBTS_SCRIPT_CHAKMA; break; + case KBTS_SCRIPT_TAG_CHAM: Result = KBTS_SCRIPT_CHAM; break; + case KBTS_SCRIPT_TAG_CHEROKEE: Result = KBTS_SCRIPT_CHEROKEE; break; + case KBTS_SCRIPT_TAG_CHORASMIAN: Result = KBTS_SCRIPT_CHORASMIAN; break; + case KBTS_SCRIPT_TAG_CJK_IDEOGRAPHIC: Result = KBTS_SCRIPT_CJK_IDEOGRAPHIC; break; + case KBTS_SCRIPT_TAG_COPTIC: Result = KBTS_SCRIPT_COPTIC; break; + case KBTS_SCRIPT_TAG_CYPRIOT_SYLLABARY: Result = KBTS_SCRIPT_CYPRIOT_SYLLABARY; break; + case KBTS_SCRIPT_TAG_CYPRO_MINOAN: Result = KBTS_SCRIPT_CYPRO_MINOAN; break; + case KBTS_SCRIPT_TAG_CYRILLIC: Result = KBTS_SCRIPT_CYRILLIC; break; + case KBTS_SCRIPT_TAG_DEFAULT: Result = KBTS_SCRIPT_DEFAULT; break; + case KBTS_SCRIPT_TAG_DESERET: Result = KBTS_SCRIPT_DESERET; break; + case KBTS_SCRIPT_TAG_DEVANAGARI: Result = KBTS_SCRIPT_DEVANAGARI; break; + case KBTS_SCRIPT_TAG_DIVES_AKURU: Result = KBTS_SCRIPT_DIVES_AKURU; break; + case KBTS_SCRIPT_TAG_DOGRA: Result = KBTS_SCRIPT_DOGRA; break; + case KBTS_SCRIPT_TAG_DUPLOYAN: Result = KBTS_SCRIPT_DUPLOYAN; break; + case KBTS_SCRIPT_TAG_EGYPTIAN_HIEROGLYPHS: Result = KBTS_SCRIPT_EGYPTIAN_HIEROGLYPHS; break; + case KBTS_SCRIPT_TAG_ELBASAN: Result = KBTS_SCRIPT_ELBASAN; break; + case KBTS_SCRIPT_TAG_ELYMAIC: Result = KBTS_SCRIPT_ELYMAIC; break; + case KBTS_SCRIPT_TAG_ETHIOPIC: Result = KBTS_SCRIPT_ETHIOPIC; break; + case KBTS_SCRIPT_TAG_GARAY: Result = KBTS_SCRIPT_GARAY; break; + case KBTS_SCRIPT_TAG_GEORGIAN: Result = KBTS_SCRIPT_GEORGIAN; break; + case KBTS_SCRIPT_TAG_GLAGOLITIC: Result = KBTS_SCRIPT_GLAGOLITIC; break; + case KBTS_SCRIPT_TAG_GOTHIC: Result = KBTS_SCRIPT_GOTHIC; break; + case KBTS_SCRIPT_TAG_GRANTHA: Result = KBTS_SCRIPT_GRANTHA; break; + case KBTS_SCRIPT_TAG_GREEK: Result = KBTS_SCRIPT_GREEK; break; + case KBTS_SCRIPT_TAG_GUJARATI: Result = KBTS_SCRIPT_GUJARATI; break; + case KBTS_SCRIPT_TAG_GUNJALA_GONDI: Result = KBTS_SCRIPT_GUNJALA_GONDI; break; + case KBTS_SCRIPT_TAG_GURMUKHI: Result = KBTS_SCRIPT_GURMUKHI; break; + case KBTS_SCRIPT_TAG_GURUNG_KHEMA: Result = KBTS_SCRIPT_GURUNG_KHEMA; break; + case KBTS_SCRIPT_TAG_HANGUL: Result = KBTS_SCRIPT_HANGUL; break; + case KBTS_SCRIPT_TAG_HANIFI_ROHINGYA: Result = KBTS_SCRIPT_HANIFI_ROHINGYA; break; + case KBTS_SCRIPT_TAG_HANUNOO: Result = KBTS_SCRIPT_HANUNOO; break; + case KBTS_SCRIPT_TAG_HATRAN: Result = KBTS_SCRIPT_HATRAN; break; + case KBTS_SCRIPT_TAG_HEBREW: Result = KBTS_SCRIPT_HEBREW; break; + case KBTS_SCRIPT_TAG_HIRAGANA: Result = KBTS_SCRIPT_HIRAGANA; break; + case KBTS_SCRIPT_TAG_IMPERIAL_ARAMAIC: Result = KBTS_SCRIPT_IMPERIAL_ARAMAIC; break; + case KBTS_SCRIPT_TAG_INSCRIPTIONAL_PAHLAVI: Result = KBTS_SCRIPT_INSCRIPTIONAL_PAHLAVI; break; + case KBTS_SCRIPT_TAG_INSCRIPTIONAL_PARTHIAN: Result = KBTS_SCRIPT_INSCRIPTIONAL_PARTHIAN; break; + case KBTS_SCRIPT_TAG_JAVANESE: Result = KBTS_SCRIPT_JAVANESE; break; + case KBTS_SCRIPT_TAG_KAITHI: Result = KBTS_SCRIPT_KAITHI; break; + case KBTS_SCRIPT_TAG_KANNADA: Result = KBTS_SCRIPT_KANNADA; break; + case KBTS_SCRIPT_TAG_KAWI: Result = KBTS_SCRIPT_KAWI; break; + case KBTS_SCRIPT_TAG_KAYAH_LI: Result = KBTS_SCRIPT_KAYAH_LI; break; + case KBTS_SCRIPT_TAG_KHAROSHTHI: Result = KBTS_SCRIPT_KHAROSHTHI; break; + case KBTS_SCRIPT_TAG_KHITAN_SMALL_SCRIPT: Result = KBTS_SCRIPT_KHITAN_SMALL_SCRIPT; break; + case KBTS_SCRIPT_TAG_KHMER: Result = KBTS_SCRIPT_KHMER; break; + case KBTS_SCRIPT_TAG_KHOJKI: Result = KBTS_SCRIPT_KHOJKI; break; + case KBTS_SCRIPT_TAG_KHUDAWADI: Result = KBTS_SCRIPT_KHUDAWADI; break; + case KBTS_SCRIPT_TAG_KIRAT_RAI: Result = KBTS_SCRIPT_KIRAT_RAI; break; + case KBTS_SCRIPT_TAG_LAO: Result = KBTS_SCRIPT_LAO; break; + case KBTS_SCRIPT_TAG_LATIN: Result = KBTS_SCRIPT_LATIN; break; + case KBTS_SCRIPT_TAG_LEPCHA: Result = KBTS_SCRIPT_LEPCHA; break; + case KBTS_SCRIPT_TAG_LIMBU: Result = KBTS_SCRIPT_LIMBU; break; + case KBTS_SCRIPT_TAG_LINEAR_A: Result = KBTS_SCRIPT_LINEAR_A; break; + case KBTS_SCRIPT_TAG_LINEAR_B: Result = KBTS_SCRIPT_LINEAR_B; break; + case KBTS_SCRIPT_TAG_LISU: Result = KBTS_SCRIPT_LISU; break; + case KBTS_SCRIPT_TAG_LYCIAN: Result = KBTS_SCRIPT_LYCIAN; break; + case KBTS_SCRIPT_TAG_LYDIAN: Result = KBTS_SCRIPT_LYDIAN; break; + case KBTS_SCRIPT_TAG_MAHAJANI: Result = KBTS_SCRIPT_MAHAJANI; break; + case KBTS_SCRIPT_TAG_MAKASAR: Result = KBTS_SCRIPT_MAKASAR; break; + case KBTS_SCRIPT_TAG_MALAYALAM: Result = KBTS_SCRIPT_MALAYALAM; break; + case KBTS_SCRIPT_TAG_MANDAIC: Result = KBTS_SCRIPT_MANDAIC; break; + case KBTS_SCRIPT_TAG_MANICHAEAN: Result = KBTS_SCRIPT_MANICHAEAN; break; + case KBTS_SCRIPT_TAG_MARCHEN: Result = KBTS_SCRIPT_MARCHEN; break; + case KBTS_SCRIPT_TAG_MASARAM_GONDI: Result = KBTS_SCRIPT_MASARAM_GONDI; break; + case KBTS_SCRIPT_TAG_MEDEFAIDRIN: Result = KBTS_SCRIPT_MEDEFAIDRIN; break; + case KBTS_SCRIPT_TAG_MEETEI_MAYEK: Result = KBTS_SCRIPT_MEETEI_MAYEK; break; + case KBTS_SCRIPT_TAG_MENDE_KIKAKUI: Result = KBTS_SCRIPT_MENDE_KIKAKUI; break; + case KBTS_SCRIPT_TAG_MEROITIC_CURSIVE: Result = KBTS_SCRIPT_MEROITIC_CURSIVE; break; + case KBTS_SCRIPT_TAG_MEROITIC_HIEROGLYPHS: Result = KBTS_SCRIPT_MEROITIC_HIEROGLYPHS; break; + case KBTS_SCRIPT_TAG_MIAO: Result = KBTS_SCRIPT_MIAO; break; + case KBTS_SCRIPT_TAG_MODI: Result = KBTS_SCRIPT_MODI; break; + case KBTS_SCRIPT_TAG_MONGOLIAN: Result = KBTS_SCRIPT_MONGOLIAN; break; + case KBTS_SCRIPT_TAG_MRO: Result = KBTS_SCRIPT_MRO; break; + case KBTS_SCRIPT_TAG_MULTANI: Result = KBTS_SCRIPT_MULTANI; break; + case KBTS_SCRIPT_TAG_MYANMAR: Result = KBTS_SCRIPT_MYANMAR; break; + case KBTS_SCRIPT_TAG_NABATAEAN: Result = KBTS_SCRIPT_NABATAEAN; break; + case KBTS_SCRIPT_TAG_NAG_MUNDARI: Result = KBTS_SCRIPT_NAG_MUNDARI; break; + case KBTS_SCRIPT_TAG_NANDINAGARI: Result = KBTS_SCRIPT_NANDINAGARI; break; + case KBTS_SCRIPT_TAG_NEWA: Result = KBTS_SCRIPT_NEWA; break; + case KBTS_SCRIPT_TAG_NEW_TAI_LUE: Result = KBTS_SCRIPT_NEW_TAI_LUE; break; + case KBTS_SCRIPT_TAG_NKO: Result = KBTS_SCRIPT_NKO; break; + case KBTS_SCRIPT_TAG_NUSHU: Result = KBTS_SCRIPT_NUSHU; break; + case KBTS_SCRIPT_TAG_NYIAKENG_PUACHUE_HMONG: Result = KBTS_SCRIPT_NYIAKENG_PUACHUE_HMONG; break; + case KBTS_SCRIPT_TAG_OGHAM: Result = KBTS_SCRIPT_OGHAM; break; + case KBTS_SCRIPT_TAG_OL_CHIKI: Result = KBTS_SCRIPT_OL_CHIKI; break; + case KBTS_SCRIPT_TAG_OL_ONAL: Result = KBTS_SCRIPT_OL_ONAL; break; + case KBTS_SCRIPT_TAG_OLD_ITALIC: Result = KBTS_SCRIPT_OLD_ITALIC; break; + case KBTS_SCRIPT_TAG_OLD_HUNGARIAN: Result = KBTS_SCRIPT_OLD_HUNGARIAN; break; + case KBTS_SCRIPT_TAG_OLD_NORTH_ARABIAN: Result = KBTS_SCRIPT_OLD_NORTH_ARABIAN; break; + case KBTS_SCRIPT_TAG_OLD_PERMIC: Result = KBTS_SCRIPT_OLD_PERMIC; break; + case KBTS_SCRIPT_TAG_OLD_PERSIAN_CUNEIFORM: Result = KBTS_SCRIPT_OLD_PERSIAN_CUNEIFORM; break; + case KBTS_SCRIPT_TAG_OLD_SOGDIAN: Result = KBTS_SCRIPT_OLD_SOGDIAN; break; + case KBTS_SCRIPT_TAG_OLD_SOUTH_ARABIAN: Result = KBTS_SCRIPT_OLD_SOUTH_ARABIAN; break; + case KBTS_SCRIPT_TAG_OLD_TURKIC: Result = KBTS_SCRIPT_OLD_TURKIC; break; + case KBTS_SCRIPT_TAG_OLD_UYGHUR: Result = KBTS_SCRIPT_OLD_UYGHUR; break; + case KBTS_SCRIPT_TAG_ODIA: Result = KBTS_SCRIPT_ODIA; break; + case KBTS_SCRIPT_TAG_OSAGE: Result = KBTS_SCRIPT_OSAGE; break; + case KBTS_SCRIPT_TAG_OSMANYA: Result = KBTS_SCRIPT_OSMANYA; break; + case KBTS_SCRIPT_TAG_PAHAWH_HMONG: Result = KBTS_SCRIPT_PAHAWH_HMONG; break; + case KBTS_SCRIPT_TAG_PALMYRENE: Result = KBTS_SCRIPT_PALMYRENE; break; + case KBTS_SCRIPT_TAG_PAU_CIN_HAU: Result = KBTS_SCRIPT_PAU_CIN_HAU; break; + case KBTS_SCRIPT_TAG_PHAGS_PA: Result = KBTS_SCRIPT_PHAGS_PA; break; + case KBTS_SCRIPT_TAG_PHOENICIAN: Result = KBTS_SCRIPT_PHOENICIAN; break; + case KBTS_SCRIPT_TAG_PSALTER_PAHLAVI: Result = KBTS_SCRIPT_PSALTER_PAHLAVI; break; + case KBTS_SCRIPT_TAG_REJANG: Result = KBTS_SCRIPT_REJANG; break; + case KBTS_SCRIPT_TAG_RUNIC: Result = KBTS_SCRIPT_RUNIC; break; + case KBTS_SCRIPT_TAG_SAMARITAN: Result = KBTS_SCRIPT_SAMARITAN; break; + case KBTS_SCRIPT_TAG_SAURASHTRA: Result = KBTS_SCRIPT_SAURASHTRA; break; + case KBTS_SCRIPT_TAG_SHARADA: Result = KBTS_SCRIPT_SHARADA; break; + case KBTS_SCRIPT_TAG_SHAVIAN: Result = KBTS_SCRIPT_SHAVIAN; break; + case KBTS_SCRIPT_TAG_SIDDHAM: Result = KBTS_SCRIPT_SIDDHAM; break; + case KBTS_SCRIPT_TAG_SIGN_WRITING: Result = KBTS_SCRIPT_SIGN_WRITING; break; + case KBTS_SCRIPT_TAG_SOGDIAN: Result = KBTS_SCRIPT_SOGDIAN; break; + case KBTS_SCRIPT_TAG_SINHALA: Result = KBTS_SCRIPT_SINHALA; break; + case KBTS_SCRIPT_TAG_SORA_SOMPENG: Result = KBTS_SCRIPT_SORA_SOMPENG; break; + case KBTS_SCRIPT_TAG_SOYOMBO: Result = KBTS_SCRIPT_SOYOMBO; break; + case KBTS_SCRIPT_TAG_SUMERO_AKKADIAN_CUNEIFORM: Result = KBTS_SCRIPT_SUMERO_AKKADIAN_CUNEIFORM; break; + case KBTS_SCRIPT_TAG_SUNDANESE: Result = KBTS_SCRIPT_SUNDANESE; break; + case KBTS_SCRIPT_TAG_SUNUWAR: Result = KBTS_SCRIPT_SUNUWAR; break; + case KBTS_SCRIPT_TAG_SYLOTI_NAGRI: Result = KBTS_SCRIPT_SYLOTI_NAGRI; break; + case KBTS_SCRIPT_TAG_SYRIAC: Result = KBTS_SCRIPT_SYRIAC; break; + case KBTS_SCRIPT_TAG_TAGALOG: Result = KBTS_SCRIPT_TAGALOG; break; + case KBTS_SCRIPT_TAG_TAGBANWA: Result = KBTS_SCRIPT_TAGBANWA; break; + case KBTS_SCRIPT_TAG_TAI_LE: Result = KBTS_SCRIPT_TAI_LE; break; + case KBTS_SCRIPT_TAG_TAI_THAM: Result = KBTS_SCRIPT_TAI_THAM; break; + case KBTS_SCRIPT_TAG_TAI_VIET: Result = KBTS_SCRIPT_TAI_VIET; break; + case KBTS_SCRIPT_TAG_TAKRI: Result = KBTS_SCRIPT_TAKRI; break; + case KBTS_SCRIPT_TAG_TAMIL: Result = KBTS_SCRIPT_TAMIL; break; + case KBTS_SCRIPT_TAG_TANGSA: Result = KBTS_SCRIPT_TANGSA; break; + case KBTS_SCRIPT_TAG_TANGUT: Result = KBTS_SCRIPT_TANGUT; break; + case KBTS_SCRIPT_TAG_TELUGU: Result = KBTS_SCRIPT_TELUGU; break; + case KBTS_SCRIPT_TAG_THAANA: Result = KBTS_SCRIPT_THAANA; break; + case KBTS_SCRIPT_TAG_THAI: Result = KBTS_SCRIPT_THAI; break; + case KBTS_SCRIPT_TAG_TIBETAN: Result = KBTS_SCRIPT_TIBETAN; break; + case KBTS_SCRIPT_TAG_TIFINAGH: Result = KBTS_SCRIPT_TIFINAGH; break; + case KBTS_SCRIPT_TAG_TIRHUTA: Result = KBTS_SCRIPT_TIRHUTA; break; + case KBTS_SCRIPT_TAG_TODHRI: Result = KBTS_SCRIPT_TODHRI; break; + case KBTS_SCRIPT_TAG_TOTO: Result = KBTS_SCRIPT_TOTO; break; + case KBTS_SCRIPT_TAG_TULU_TIGALARI: Result = KBTS_SCRIPT_TULU_TIGALARI; break; + case KBTS_SCRIPT_TAG_UGARITIC_CUNEIFORM: Result = KBTS_SCRIPT_UGARITIC_CUNEIFORM; break; + case KBTS_SCRIPT_TAG_VAI: Result = KBTS_SCRIPT_VAI; break; + case KBTS_SCRIPT_TAG_VITHKUQI: Result = KBTS_SCRIPT_VITHKUQI; break; + case KBTS_SCRIPT_TAG_WANCHO: Result = KBTS_SCRIPT_WANCHO; break; + case KBTS_SCRIPT_TAG_WARANG_CITI: Result = KBTS_SCRIPT_WARANG_CITI; break; + case KBTS_SCRIPT_TAG_YEZIDI: Result = KBTS_SCRIPT_YEZIDI; break; + case KBTS_SCRIPT_TAG_YI: Result = KBTS_SCRIPT_YI; break; + case KBTS_SCRIPT_TAG_ZANABAZAR_SQUARE: Result = KBTS_SCRIPT_ZANABAZAR_SQUARE; break; + default: break; + } + return Result; +} + +KBTS_EXPORT kbts_feature_id kbts_FeatureTagToId(kbts_feature_tag Tag) +{ + kbts_feature_id Result = 0; + switch(Tag) + { + case KBTS_FEATURE_TAG_isol: Result = KBTS_FEATURE_ID_isol; break; + case KBTS_FEATURE_TAG_fina: Result = KBTS_FEATURE_ID_fina; break; + case KBTS_FEATURE_TAG_fin2: Result = KBTS_FEATURE_ID_fin2; break; + case KBTS_FEATURE_TAG_fin3: Result = KBTS_FEATURE_ID_fin3; break; + case KBTS_FEATURE_TAG_medi: Result = KBTS_FEATURE_ID_medi; break; + case KBTS_FEATURE_TAG_med2: Result = KBTS_FEATURE_ID_med2; break; + case KBTS_FEATURE_TAG_init: Result = KBTS_FEATURE_ID_init; break; + case KBTS_FEATURE_TAG_ljmo: Result = KBTS_FEATURE_ID_ljmo; break; + case KBTS_FEATURE_TAG_vjmo: Result = KBTS_FEATURE_ID_vjmo; break; + case KBTS_FEATURE_TAG_tjmo: Result = KBTS_FEATURE_ID_tjmo; break; + case KBTS_FEATURE_TAG_rphf: Result = KBTS_FEATURE_ID_rphf; break; + case KBTS_FEATURE_TAG_blwf: Result = KBTS_FEATURE_ID_blwf; break; + case KBTS_FEATURE_TAG_half: Result = KBTS_FEATURE_ID_half; break; + case KBTS_FEATURE_TAG_pstf: Result = KBTS_FEATURE_ID_pstf; break; + case KBTS_FEATURE_TAG_abvf: Result = KBTS_FEATURE_ID_abvf; break; + case KBTS_FEATURE_TAG_pref: Result = KBTS_FEATURE_ID_pref; break; + case KBTS_FEATURE_TAG_numr: Result = KBTS_FEATURE_ID_numr; break; + case KBTS_FEATURE_TAG_frac: Result = KBTS_FEATURE_ID_frac; break; + case KBTS_FEATURE_TAG_dnom: Result = KBTS_FEATURE_ID_dnom; break; + case KBTS_FEATURE_TAG_cfar: Result = KBTS_FEATURE_ID_cfar; break; + case KBTS_FEATURE_TAG_aalt: Result = KBTS_FEATURE_ID_aalt; break; + case KBTS_FEATURE_TAG_abvm: Result = KBTS_FEATURE_ID_abvm; break; + case KBTS_FEATURE_TAG_abvs: Result = KBTS_FEATURE_ID_abvs; break; + case KBTS_FEATURE_TAG_afrc: Result = KBTS_FEATURE_ID_afrc; break; + case KBTS_FEATURE_TAG_akhn: Result = KBTS_FEATURE_ID_akhn; break; + case KBTS_FEATURE_TAG_apkn: Result = KBTS_FEATURE_ID_apkn; break; + case KBTS_FEATURE_TAG_blwm: Result = KBTS_FEATURE_ID_blwm; break; + case KBTS_FEATURE_TAG_blws: Result = KBTS_FEATURE_ID_blws; break; + case KBTS_FEATURE_TAG_calt: Result = KBTS_FEATURE_ID_calt; break; + case KBTS_FEATURE_TAG_case: Result = KBTS_FEATURE_ID_case; break; + case KBTS_FEATURE_TAG_ccmp: Result = KBTS_FEATURE_ID_ccmp; break; + case KBTS_FEATURE_TAG_chws: Result = KBTS_FEATURE_ID_chws; break; + case KBTS_FEATURE_TAG_cjct: Result = KBTS_FEATURE_ID_cjct; break; + case KBTS_FEATURE_TAG_clig: Result = KBTS_FEATURE_ID_clig; break; + case KBTS_FEATURE_TAG_cpct: Result = KBTS_FEATURE_ID_cpct; break; + case KBTS_FEATURE_TAG_cpsp: Result = KBTS_FEATURE_ID_cpsp; break; + case KBTS_FEATURE_TAG_cswh: Result = KBTS_FEATURE_ID_cswh; break; + case KBTS_FEATURE_TAG_curs: Result = KBTS_FEATURE_ID_curs; break; + case KBTS_FEATURE_TAG_cv01: Result = KBTS_FEATURE_ID_cv01; break; + case KBTS_FEATURE_TAG_cv02: Result = KBTS_FEATURE_ID_cv02; break; + case KBTS_FEATURE_TAG_cv03: Result = KBTS_FEATURE_ID_cv03; break; + case KBTS_FEATURE_TAG_cv04: Result = KBTS_FEATURE_ID_cv04; break; + case KBTS_FEATURE_TAG_cv05: Result = KBTS_FEATURE_ID_cv05; break; + case KBTS_FEATURE_TAG_cv06: Result = KBTS_FEATURE_ID_cv06; break; + case KBTS_FEATURE_TAG_cv07: Result = KBTS_FEATURE_ID_cv07; break; + case KBTS_FEATURE_TAG_cv08: Result = KBTS_FEATURE_ID_cv08; break; + case KBTS_FEATURE_TAG_cv09: Result = KBTS_FEATURE_ID_cv09; break; + case KBTS_FEATURE_TAG_cv10: Result = KBTS_FEATURE_ID_cv10; break; + case KBTS_FEATURE_TAG_cv11: Result = KBTS_FEATURE_ID_cv11; break; + case KBTS_FEATURE_TAG_cv12: Result = KBTS_FEATURE_ID_cv12; break; + case KBTS_FEATURE_TAG_cv13: Result = KBTS_FEATURE_ID_cv13; break; + case KBTS_FEATURE_TAG_cv14: Result = KBTS_FEATURE_ID_cv14; break; + case KBTS_FEATURE_TAG_cv15: Result = KBTS_FEATURE_ID_cv15; break; + case KBTS_FEATURE_TAG_cv16: Result = KBTS_FEATURE_ID_cv16; break; + case KBTS_FEATURE_TAG_cv17: Result = KBTS_FEATURE_ID_cv17; break; + case KBTS_FEATURE_TAG_cv18: Result = KBTS_FEATURE_ID_cv18; break; + case KBTS_FEATURE_TAG_cv19: Result = KBTS_FEATURE_ID_cv19; break; + case KBTS_FEATURE_TAG_cv20: Result = KBTS_FEATURE_ID_cv20; break; + case KBTS_FEATURE_TAG_cv21: Result = KBTS_FEATURE_ID_cv21; break; + case KBTS_FEATURE_TAG_cv22: Result = KBTS_FEATURE_ID_cv22; break; + case KBTS_FEATURE_TAG_cv23: Result = KBTS_FEATURE_ID_cv23; break; + case KBTS_FEATURE_TAG_cv24: Result = KBTS_FEATURE_ID_cv24; break; + case KBTS_FEATURE_TAG_cv25: Result = KBTS_FEATURE_ID_cv25; break; + case KBTS_FEATURE_TAG_cv26: Result = KBTS_FEATURE_ID_cv26; break; + case KBTS_FEATURE_TAG_cv27: Result = KBTS_FEATURE_ID_cv27; break; + case KBTS_FEATURE_TAG_cv28: Result = KBTS_FEATURE_ID_cv28; break; + case KBTS_FEATURE_TAG_cv29: Result = KBTS_FEATURE_ID_cv29; break; + case KBTS_FEATURE_TAG_cv30: Result = KBTS_FEATURE_ID_cv30; break; + case KBTS_FEATURE_TAG_cv31: Result = KBTS_FEATURE_ID_cv31; break; + case KBTS_FEATURE_TAG_cv32: Result = KBTS_FEATURE_ID_cv32; break; + case KBTS_FEATURE_TAG_cv33: Result = KBTS_FEATURE_ID_cv33; break; + case KBTS_FEATURE_TAG_cv34: Result = KBTS_FEATURE_ID_cv34; break; + case KBTS_FEATURE_TAG_cv35: Result = KBTS_FEATURE_ID_cv35; break; + case KBTS_FEATURE_TAG_cv36: Result = KBTS_FEATURE_ID_cv36; break; + case KBTS_FEATURE_TAG_cv37: Result = KBTS_FEATURE_ID_cv37; break; + case KBTS_FEATURE_TAG_cv38: Result = KBTS_FEATURE_ID_cv38; break; + case KBTS_FEATURE_TAG_cv39: Result = KBTS_FEATURE_ID_cv39; break; + case KBTS_FEATURE_TAG_cv40: Result = KBTS_FEATURE_ID_cv40; break; + case KBTS_FEATURE_TAG_cv41: Result = KBTS_FEATURE_ID_cv41; break; + case KBTS_FEATURE_TAG_cv42: Result = KBTS_FEATURE_ID_cv42; break; + case KBTS_FEATURE_TAG_cv43: Result = KBTS_FEATURE_ID_cv43; break; + case KBTS_FEATURE_TAG_cv44: Result = KBTS_FEATURE_ID_cv44; break; + case KBTS_FEATURE_TAG_cv45: Result = KBTS_FEATURE_ID_cv45; break; + case KBTS_FEATURE_TAG_cv46: Result = KBTS_FEATURE_ID_cv46; break; + case KBTS_FEATURE_TAG_cv47: Result = KBTS_FEATURE_ID_cv47; break; + case KBTS_FEATURE_TAG_cv48: Result = KBTS_FEATURE_ID_cv48; break; + case KBTS_FEATURE_TAG_cv49: Result = KBTS_FEATURE_ID_cv49; break; + case KBTS_FEATURE_TAG_cv50: Result = KBTS_FEATURE_ID_cv50; break; + case KBTS_FEATURE_TAG_cv51: Result = KBTS_FEATURE_ID_cv51; break; + case KBTS_FEATURE_TAG_cv52: Result = KBTS_FEATURE_ID_cv52; break; + case KBTS_FEATURE_TAG_cv53: Result = KBTS_FEATURE_ID_cv53; break; + case KBTS_FEATURE_TAG_cv54: Result = KBTS_FEATURE_ID_cv54; break; + case KBTS_FEATURE_TAG_cv55: Result = KBTS_FEATURE_ID_cv55; break; + case KBTS_FEATURE_TAG_cv56: Result = KBTS_FEATURE_ID_cv56; break; + case KBTS_FEATURE_TAG_cv57: Result = KBTS_FEATURE_ID_cv57; break; + case KBTS_FEATURE_TAG_cv58: Result = KBTS_FEATURE_ID_cv58; break; + case KBTS_FEATURE_TAG_cv59: Result = KBTS_FEATURE_ID_cv59; break; + case KBTS_FEATURE_TAG_cv60: Result = KBTS_FEATURE_ID_cv60; break; + case KBTS_FEATURE_TAG_cv61: Result = KBTS_FEATURE_ID_cv61; break; + case KBTS_FEATURE_TAG_cv62: Result = KBTS_FEATURE_ID_cv62; break; + case KBTS_FEATURE_TAG_cv63: Result = KBTS_FEATURE_ID_cv63; break; + case KBTS_FEATURE_TAG_cv64: Result = KBTS_FEATURE_ID_cv64; break; + case KBTS_FEATURE_TAG_cv65: Result = KBTS_FEATURE_ID_cv65; break; + case KBTS_FEATURE_TAG_cv66: Result = KBTS_FEATURE_ID_cv66; break; + case KBTS_FEATURE_TAG_cv67: Result = KBTS_FEATURE_ID_cv67; break; + case KBTS_FEATURE_TAG_cv68: Result = KBTS_FEATURE_ID_cv68; break; + case KBTS_FEATURE_TAG_cv69: Result = KBTS_FEATURE_ID_cv69; break; + case KBTS_FEATURE_TAG_cv70: Result = KBTS_FEATURE_ID_cv70; break; + case KBTS_FEATURE_TAG_cv71: Result = KBTS_FEATURE_ID_cv71; break; + case KBTS_FEATURE_TAG_cv72: Result = KBTS_FEATURE_ID_cv72; break; + case KBTS_FEATURE_TAG_cv73: Result = KBTS_FEATURE_ID_cv73; break; + case KBTS_FEATURE_TAG_cv74: Result = KBTS_FEATURE_ID_cv74; break; + case KBTS_FEATURE_TAG_cv75: Result = KBTS_FEATURE_ID_cv75; break; + case KBTS_FEATURE_TAG_cv76: Result = KBTS_FEATURE_ID_cv76; break; + case KBTS_FEATURE_TAG_cv77: Result = KBTS_FEATURE_ID_cv77; break; + case KBTS_FEATURE_TAG_cv78: Result = KBTS_FEATURE_ID_cv78; break; + case KBTS_FEATURE_TAG_cv79: Result = KBTS_FEATURE_ID_cv79; break; + case KBTS_FEATURE_TAG_cv80: Result = KBTS_FEATURE_ID_cv80; break; + case KBTS_FEATURE_TAG_cv81: Result = KBTS_FEATURE_ID_cv81; break; + case KBTS_FEATURE_TAG_cv82: Result = KBTS_FEATURE_ID_cv82; break; + case KBTS_FEATURE_TAG_cv83: Result = KBTS_FEATURE_ID_cv83; break; + case KBTS_FEATURE_TAG_cv84: Result = KBTS_FEATURE_ID_cv84; break; + case KBTS_FEATURE_TAG_cv85: Result = KBTS_FEATURE_ID_cv85; break; + case KBTS_FEATURE_TAG_cv86: Result = KBTS_FEATURE_ID_cv86; break; + case KBTS_FEATURE_TAG_cv87: Result = KBTS_FEATURE_ID_cv87; break; + case KBTS_FEATURE_TAG_cv88: Result = KBTS_FEATURE_ID_cv88; break; + case KBTS_FEATURE_TAG_cv89: Result = KBTS_FEATURE_ID_cv89; break; + case KBTS_FEATURE_TAG_cv90: Result = KBTS_FEATURE_ID_cv90; break; + case KBTS_FEATURE_TAG_cv91: Result = KBTS_FEATURE_ID_cv91; break; + case KBTS_FEATURE_TAG_cv92: Result = KBTS_FEATURE_ID_cv92; break; + case KBTS_FEATURE_TAG_cv93: Result = KBTS_FEATURE_ID_cv93; break; + case KBTS_FEATURE_TAG_cv94: Result = KBTS_FEATURE_ID_cv94; break; + case KBTS_FEATURE_TAG_cv95: Result = KBTS_FEATURE_ID_cv95; break; + case KBTS_FEATURE_TAG_cv96: Result = KBTS_FEATURE_ID_cv96; break; + case KBTS_FEATURE_TAG_cv97: Result = KBTS_FEATURE_ID_cv97; break; + case KBTS_FEATURE_TAG_cv98: Result = KBTS_FEATURE_ID_cv98; break; + case KBTS_FEATURE_TAG_cv99: Result = KBTS_FEATURE_ID_cv99; break; + case KBTS_FEATURE_TAG_c2pc: Result = KBTS_FEATURE_ID_c2pc; break; + case KBTS_FEATURE_TAG_c2sc: Result = KBTS_FEATURE_ID_c2sc; break; + case KBTS_FEATURE_TAG_dist: Result = KBTS_FEATURE_ID_dist; break; + case KBTS_FEATURE_TAG_dlig: Result = KBTS_FEATURE_ID_dlig; break; + case KBTS_FEATURE_TAG_dtls: Result = KBTS_FEATURE_ID_dtls; break; + case KBTS_FEATURE_TAG_expt: Result = KBTS_FEATURE_ID_expt; break; + case KBTS_FEATURE_TAG_falt: Result = KBTS_FEATURE_ID_falt; break; + case KBTS_FEATURE_TAG_flac: Result = KBTS_FEATURE_ID_flac; break; + case KBTS_FEATURE_TAG_fwid: Result = KBTS_FEATURE_ID_fwid; break; + case KBTS_FEATURE_TAG_haln: Result = KBTS_FEATURE_ID_haln; break; + case KBTS_FEATURE_TAG_halt: Result = KBTS_FEATURE_ID_halt; break; + case KBTS_FEATURE_TAG_hist: Result = KBTS_FEATURE_ID_hist; break; + case KBTS_FEATURE_TAG_hkna: Result = KBTS_FEATURE_ID_hkna; break; + case KBTS_FEATURE_TAG_hlig: Result = KBTS_FEATURE_ID_hlig; break; + case KBTS_FEATURE_TAG_hngl: Result = KBTS_FEATURE_ID_hngl; break; + case KBTS_FEATURE_TAG_hojo: Result = KBTS_FEATURE_ID_hojo; break; + case KBTS_FEATURE_TAG_hwid: Result = KBTS_FEATURE_ID_hwid; break; + case KBTS_FEATURE_TAG_ital: Result = KBTS_FEATURE_ID_ital; break; + case KBTS_FEATURE_TAG_jalt: Result = KBTS_FEATURE_ID_jalt; break; + case KBTS_FEATURE_TAG_jp78: Result = KBTS_FEATURE_ID_jp78; break; + case KBTS_FEATURE_TAG_jp83: Result = KBTS_FEATURE_ID_jp83; break; + case KBTS_FEATURE_TAG_jp90: Result = KBTS_FEATURE_ID_jp90; break; + case KBTS_FEATURE_TAG_jp04: Result = KBTS_FEATURE_ID_jp04; break; + case KBTS_FEATURE_TAG_kern: Result = KBTS_FEATURE_ID_kern; break; + case KBTS_FEATURE_TAG_lfbd: Result = KBTS_FEATURE_ID_lfbd; break; + case KBTS_FEATURE_TAG_liga: Result = KBTS_FEATURE_ID_liga; break; + case KBTS_FEATURE_TAG_lnum: Result = KBTS_FEATURE_ID_lnum; break; + case KBTS_FEATURE_TAG_locl: Result = KBTS_FEATURE_ID_locl; break; + case KBTS_FEATURE_TAG_ltra: Result = KBTS_FEATURE_ID_ltra; break; + case KBTS_FEATURE_TAG_ltrm: Result = KBTS_FEATURE_ID_ltrm; break; + case KBTS_FEATURE_TAG_mark: Result = KBTS_FEATURE_ID_mark; break; + case KBTS_FEATURE_TAG_mgrk: Result = KBTS_FEATURE_ID_mgrk; break; + case KBTS_FEATURE_TAG_mkmk: Result = KBTS_FEATURE_ID_mkmk; break; + case KBTS_FEATURE_TAG_mset: Result = KBTS_FEATURE_ID_mset; break; + case KBTS_FEATURE_TAG_nalt: Result = KBTS_FEATURE_ID_nalt; break; + case KBTS_FEATURE_TAG_nlck: Result = KBTS_FEATURE_ID_nlck; break; + case KBTS_FEATURE_TAG_nukt: Result = KBTS_FEATURE_ID_nukt; break; + case KBTS_FEATURE_TAG_onum: Result = KBTS_FEATURE_ID_onum; break; + case KBTS_FEATURE_TAG_opbd: Result = KBTS_FEATURE_ID_opbd; break; + case KBTS_FEATURE_TAG_ordn: Result = KBTS_FEATURE_ID_ordn; break; + case KBTS_FEATURE_TAG_ornm: Result = KBTS_FEATURE_ID_ornm; break; + case KBTS_FEATURE_TAG_palt: Result = KBTS_FEATURE_ID_palt; break; + case KBTS_FEATURE_TAG_pcap: Result = KBTS_FEATURE_ID_pcap; break; + case KBTS_FEATURE_TAG_pkna: Result = KBTS_FEATURE_ID_pkna; break; + case KBTS_FEATURE_TAG_pnum: Result = KBTS_FEATURE_ID_pnum; break; + case KBTS_FEATURE_TAG_pres: Result = KBTS_FEATURE_ID_pres; break; + case KBTS_FEATURE_TAG_psts: Result = KBTS_FEATURE_ID_psts; break; + case KBTS_FEATURE_TAG_pwid: Result = KBTS_FEATURE_ID_pwid; break; + case KBTS_FEATURE_TAG_qwid: Result = KBTS_FEATURE_ID_qwid; break; + case KBTS_FEATURE_TAG_rand: Result = KBTS_FEATURE_ID_rand; break; + case KBTS_FEATURE_TAG_rclt: Result = KBTS_FEATURE_ID_rclt; break; + case KBTS_FEATURE_TAG_rkrf: Result = KBTS_FEATURE_ID_rkrf; break; + case KBTS_FEATURE_TAG_rlig: Result = KBTS_FEATURE_ID_rlig; break; + case KBTS_FEATURE_TAG_rtbd: Result = KBTS_FEATURE_ID_rtbd; break; + case KBTS_FEATURE_TAG_rtla: Result = KBTS_FEATURE_ID_rtla; break; + case KBTS_FEATURE_TAG_rtlm: Result = KBTS_FEATURE_ID_rtlm; break; + case KBTS_FEATURE_TAG_ruby: Result = KBTS_FEATURE_ID_ruby; break; + case KBTS_FEATURE_TAG_rvrn: Result = KBTS_FEATURE_ID_rvrn; break; + case KBTS_FEATURE_TAG_salt: Result = KBTS_FEATURE_ID_salt; break; + case KBTS_FEATURE_TAG_sinf: Result = KBTS_FEATURE_ID_sinf; break; + case KBTS_FEATURE_TAG_size: Result = KBTS_FEATURE_ID_size; break; + case KBTS_FEATURE_TAG_smcp: Result = KBTS_FEATURE_ID_smcp; break; + case KBTS_FEATURE_TAG_smpl: Result = KBTS_FEATURE_ID_smpl; break; + case KBTS_FEATURE_TAG_ss01: Result = KBTS_FEATURE_ID_ss01; break; + case KBTS_FEATURE_TAG_ss02: Result = KBTS_FEATURE_ID_ss02; break; + case KBTS_FEATURE_TAG_ss03: Result = KBTS_FEATURE_ID_ss03; break; + case KBTS_FEATURE_TAG_ss04: Result = KBTS_FEATURE_ID_ss04; break; + case KBTS_FEATURE_TAG_ss05: Result = KBTS_FEATURE_ID_ss05; break; + case KBTS_FEATURE_TAG_ss06: Result = KBTS_FEATURE_ID_ss06; break; + case KBTS_FEATURE_TAG_ss07: Result = KBTS_FEATURE_ID_ss07; break; + case KBTS_FEATURE_TAG_ss08: Result = KBTS_FEATURE_ID_ss08; break; + case KBTS_FEATURE_TAG_ss09: Result = KBTS_FEATURE_ID_ss09; break; + case KBTS_FEATURE_TAG_ss10: Result = KBTS_FEATURE_ID_ss10; break; + case KBTS_FEATURE_TAG_ss11: Result = KBTS_FEATURE_ID_ss11; break; + case KBTS_FEATURE_TAG_ss12: Result = KBTS_FEATURE_ID_ss12; break; + case KBTS_FEATURE_TAG_ss13: Result = KBTS_FEATURE_ID_ss13; break; + case KBTS_FEATURE_TAG_ss14: Result = KBTS_FEATURE_ID_ss14; break; + case KBTS_FEATURE_TAG_ss15: Result = KBTS_FEATURE_ID_ss15; break; + case KBTS_FEATURE_TAG_ss16: Result = KBTS_FEATURE_ID_ss16; break; + case KBTS_FEATURE_TAG_ss17: Result = KBTS_FEATURE_ID_ss17; break; + case KBTS_FEATURE_TAG_ss18: Result = KBTS_FEATURE_ID_ss18; break; + case KBTS_FEATURE_TAG_ss19: Result = KBTS_FEATURE_ID_ss19; break; + case KBTS_FEATURE_TAG_ss20: Result = KBTS_FEATURE_ID_ss20; break; + case KBTS_FEATURE_TAG_ssty: Result = KBTS_FEATURE_ID_ssty; break; + case KBTS_FEATURE_TAG_stch: Result = KBTS_FEATURE_ID_stch; break; + case KBTS_FEATURE_TAG_subs: Result = KBTS_FEATURE_ID_subs; break; + case KBTS_FEATURE_TAG_sups: Result = KBTS_FEATURE_ID_sups; break; + case KBTS_FEATURE_TAG_swsh: Result = KBTS_FEATURE_ID_swsh; break; + case KBTS_FEATURE_TAG_test: Result = KBTS_FEATURE_ID_test; break; + case KBTS_FEATURE_TAG_titl: Result = KBTS_FEATURE_ID_titl; break; + case KBTS_FEATURE_TAG_tnam: Result = KBTS_FEATURE_ID_tnam; break; + case KBTS_FEATURE_TAG_tnum: Result = KBTS_FEATURE_ID_tnum; break; + case KBTS_FEATURE_TAG_trad: Result = KBTS_FEATURE_ID_trad; break; + case KBTS_FEATURE_TAG_twid: Result = KBTS_FEATURE_ID_twid; break; + case KBTS_FEATURE_TAG_unic: Result = KBTS_FEATURE_ID_unic; break; + case KBTS_FEATURE_TAG_valt: Result = KBTS_FEATURE_ID_valt; break; + case KBTS_FEATURE_TAG_vapk: Result = KBTS_FEATURE_ID_vapk; break; + case KBTS_FEATURE_TAG_vatu: Result = KBTS_FEATURE_ID_vatu; break; + case KBTS_FEATURE_TAG_vchw: Result = KBTS_FEATURE_ID_vchw; break; + case KBTS_FEATURE_TAG_vert: Result = KBTS_FEATURE_ID_vert; break; + case KBTS_FEATURE_TAG_vhal: Result = KBTS_FEATURE_ID_vhal; break; + case KBTS_FEATURE_TAG_vkna: Result = KBTS_FEATURE_ID_vkna; break; + case KBTS_FEATURE_TAG_vkrn: Result = KBTS_FEATURE_ID_vkrn; break; + case KBTS_FEATURE_TAG_vpal: Result = KBTS_FEATURE_ID_vpal; break; + case KBTS_FEATURE_TAG_vrt2: Result = KBTS_FEATURE_ID_vrt2; break; + case KBTS_FEATURE_TAG_vrtr: Result = KBTS_FEATURE_ID_vrtr; break; + case KBTS_FEATURE_TAG_zero: Result = KBTS_FEATURE_ID_zero; break; + default: break; + } + return Result; +} + +static kbts_s32 kbts_UnicodeParentDeltas[1679] = { + 132,133,134,135,244,246,248,250,252,254,315,351,416,418,7678,7680,7682,7792,7794,132,133,134,135,275,277,279,281,283,285,346,382,447, + 449,7709,7711,7713,7823,7825,131,132,133,134,174,176,178,180,182,416,418,452,7604,7606,7764,7766,7768,131,132,133,134,205,207,209,211,213, + 447,449,483,7635,7637,7795,7797,7799,127,128,129,130,131,132,160,162,164,365,416,418,454,7584,7744,7746,127,128,129,130,131,132,191,193, + 195,396,447,449,485,7615,7775,7777,131,132,133,134,135,222,224,226,306,355,380,414,416,448,7774,7776,131,132,133,134,135,253,255,257, + 337,386,411,445,447,479,7805,7807,131,132,133,134,223,225,227,229,231,390,447,449,7651,7807,7809,131,132,133,134,192,194,196,198,359, + 416,418,7620,7776,7778,132,134,254,442,7702,7712,7802,7804,7806,7808,-10,17,7031,7032,7101,7173,7191,7192,7197,131,214,216,218,395,7639,7641,7643, + 7645,131,245,247,249,426,7670,7672,7674,7676,132,285,287,473,7733,7833,7835,7837,7839,227,229,231,415,417,7655,7657,7661,6,8,7051,7052,7093, + 7195,7196,7201,189,439,7611,7613,7615,7617,7619,7726,239,241,423,7671,7673,7675,7677,7715,-5,6991,6992,7103,7167,7168,7170,7173,258,260,262,446,448, + 7686,7688,7692,182,184,186,188,384,398,7610,213,215,217,219,415,429,7641,232,234,236,238,422,7662,7664,263,265,267,269,453,7693,7695,-15, + 17,7071,7072,7231,7232,7233,220,470,7642,7644,7646,7648,7650,-11,7031,7032,7207,7208,7209,7211,254,7690,7692,7694,7696,7698,7713,270,272,454,7702,7704, + 7706,7708,206,208,210,7627,7631,7633,-23,6,7092,7235,7236,7237,-26,7103,7104,7249,7251,7549,235,413,7653,7655,7657,8415,237,239,241,7658,7662,7664, + -9,7017,7018,7101,7180,7183,5,7063,7064,7091,7210,7213,256,258,260,7703,7705,7707,171,7591,7593,7595,7597,7599,287,289,291,7734,7736,7738,202,7622, + 7624,7626,7628,7630,285,7721,7723,7725,7727,7729,-3,-2,-1,3,4,1,2,3,4,5,132,164,166,168,170,-14,7057,7058,7219,7221,132,195, + 197,199,201,7481,7483,7485,7487,7489,7482,7484,7486,7488,7490,204,382,7622,7624,7626,2,4,6,64,3,4,5,7,-21,203,205,207,2,4, + 6,112,-11,1,202,204,2,4,6,128,1,37,171,173,-8,7003,7004,7101,-19,7081,7082,7257,27,172,174,176,-13,7043,7044,7219,218,220, + 222,224,249,251,253,255,13,7041,7042,7097,7596,7598,7600,7602,7619,7621,7623,7625,7637,7639,7641,7643,7645,7647,7649,7651,7650,7652,7654,7656,7668,7670, + 7672,7674,7676,7678,7680,7682,-33,-32,-31,-58,7176,7181,-27,7191,7196,-5,-4,-2,1,2,4,1,3,5,2,3,5,1,4,5,-21,-20, + 193,2,4,16,3,5,6,14,15,16,27,28,162,312,7512,7514,343,7543,7545,7585,7587,7589,733,7961,8005,7616,7618,7620,7634,7636,7638,7665, + 7667,7669,22891,22892,23346,31318,31405,162165,31650,31843,31932,35977,36182,166849,36278,36572,167227,36626,36698,36797,62785,62786,62816,25280,156147,156148,37394,37755,168385,38990,39065,169662, + 62814,62815,62816,39089,39163,169757,40312,40387,171144,173234,173235,173236,-29,-28,12,22,161,163,140,167,171,198,253,279,203,390,284,310,7109,7176,7111,7190, + 7087,7206,7203,7204,7426,7428,7428,7430,7684,7686,309,8294,7687,7689,7699,7701,7718,7720,7730,7732,25135,25233,25194,25291,25286,25458,25477,25572,27117,27183,27997,28089, + 28255,28607,28357,28407,28458,28550,28458,28610,28513,28603,28875,28962,30692,30693,24507,155384,32406,32493,27530,158375,28470,159303,33613,33756,28625,159459,29500,160322,34266,34388,34540,34678, + 29402,160600,30216,161096,35034,35118,30351,161459,32788,163609,32908,163783,35621,35704,37790,37917,32943,164035,33018,163837,40630,40631,41398,41506,42137,42203,33247,163972,54624,54625,33631,164350, + 33716,164428,33778,164808,34352,165055,34921,165612,35453,166134,35790,166464,62788,62816,62816,62826,36046,166794,62816,62834,62816,62838,37311,168029,37752,168382,37810,168510,62816,62843,161426,161674, + 38130,168825,38679,169659,39225,169818,39337,169999,39518,170436,40398,171018,42033,172614,42209,172718,164391,164392,169819,169821,42724,173276,42572,173332,42877,173358,42832,173379,170354,170355,42858,173405, + 42927,173406,43001,173641,43196,173670,43237,173761,171308,171309,43338,173859,172737,172738,43650,174167,47771,178448,178804,178805,48949,179530,-99324,-90618,-87924,-84098,-80132,-77179,-77172,-3295,-163,-70, + -60,-59,-36,-16,-6,9,10,26,32,34,41,48,51,55,56,59,60,63,66,67,78,81,100,118,169,187,200,278,282,294,340,720, + 835,7085,7086,7110,7112,7156,7234,7243,7261,7273,7276,7277,7434,7440,7452,7458,7519,7609,7640,8009,8079,8739,8753,8754,21533,21757,22403,22533,22797,22850,23095,23227, + 23233,23281,23298,23360,23371,23380,23445,23673,23963,24010,24281,24349,24361,24836,24879,24891,24946,24988,25094,25170,25195,25276,25316,25326,25344,25350,25352,25422,25430,25435,25464,25496, + 25532,25561,25674,25675,25959,26097,26171,26173,26193,26425,26493,26543,26589,26627,26653,26703,26718,26756,26801,26921,26923,26951,26960,26999,27073,27179,27192,27217,27250,27309,27312,27340, + 27464,27707,27770,27782,27832,28049,28122,28147,28267,28324,28331,28608,28656,28666,28698,28799,28894,28935,28936,28952,28977,29008,29015,29045,29116,29367,29393,29426,29487,29526,29684,29686, + 29710,29867,29894,29915,29989,30055,30069,30405,30408,30477,30542,30561,30734,30805,30831,30919,30920,31016,31027,31082,31114,31253,31329,31341,31401,31464,31513,31603,31641,31645,31768,31776, + 31816,31823,31892,31935,31972,32043,32045,32084,32095,32103,32104,32307,32472,32556,32570,32701,32715,32724,32763,32776,32859,32870,32873,32893,32949,32955,32965,32988,33012,33023,33028,33030, + 33038,33053,33123,33210,33356,33388,33445,33526,33630,33642,33663,33740,33795,33809,33908,33926,33927,34059,34105,34117,34135,34152,34204,34243,34270,34273,34299,34344,34351,34354,34532,34563, + 34594,34618,34800,34802,34846,34877,34890,35031,35039,35127,35170,35206,35327,35379,35391,35439,35457,35631,35634,35699,35773,35776,35820,35834,35882,35884,35898,35996,36049,36071,36074,36094, + 36206,36343,36373,36377,36443,36446,36636,36665,37113,37178,37315,37331,37334,37344,37389,37453,37469,37523,37573,37693,37694,37714,37822,37837,37846,37873,37925,37977,37984,37996,38049,38135, + 38202,38357,38441,38457,38461,38492,38514,38517,38540,38556,38590,38601,38700,38703,38730,38800,38820,38911,39000,39061,39126,39128,39210,39246,39296,39312,39342,39357,39397,39414,39487,39501, + 39574,39640,39641,39706,39707,39736,39771,39850,39856,39889,39921,40124,40165,40169,40314,40318,40374,40407,40575,40793,40888,40900,40928,40974,40990,41059,41074,41230,41259,41274,41362,41418, + 41465,41616,41648,41658,41772,41860,41936,42061,42273,42276,42288,42302,42407,42408,42447,42448,42577,42624,42634,42668,42735,42746,42814,42871,42872,42885,42889,42928,42932,42949,43023,43025, + 43050,43063,43086,43088,43108,43212,43233,43253,43257,43274,43311,43396,43418,43430,43431,43433,43562,43673,43716,43721,43731,43763,43813,43828,43837,43866,44106,44197,44287,45331,45553,45851, + 46452,46778,47491,47538,47676,47803,48104,48191,48639,48746,49225,49737,50294,50458,50655,50670,50678,50721,51392,52429,52652,53712,55046,55194,55959,56301,56665,56996,57719,57784,58229,60629, + 60936,61695,61907,61909,62155,62198,62454,62765,63201,154337,154373,154379,154388,154394,154398,154458,154792,154895,155083,155657,155716,155742,155867,155936,156119,156186,156370,156464,156729,156771,157143,157170, + 157457,157550,157615,157899,157907,157938,158030,158191,158474,158700,158735,158751,158816,158907,158996,159017,159101,159535,159951,159977,159983,160097,160099,160192,160223,160312,160338,160404,160427,160472,160526,160560, + 160589,160590,160611,160840,160916,160950,160951,161207,161223,161238,161239,161248,161262,161335,161357,161401,161404,161456,161496,161505,161506,161524,161534,161541,161672,161833,161863,161920,162000,162063,162077,162175, + 162275,162300,162603,162669,162727,162825,162922,162944,162950,162964,163226,163228,163441,163596,163600,163692,164096,164287,164650,164856,164880,164968,165036,165075,165095,165254,165278,165294,165520,165540,165586,165624, + 165762,165829,165847,165997,166043,166050,166093,166106,166138,166220,166305,166469,166555,166617,166677,166784,166796,166810,166850,166867,166889,166960,166973,167063,167084,167253,167297,167325,167374,167442,167491,167680, + 167750,167846,167890,168022,168079,168134,168165,168283,168317,168329,168377,168404,168505,168580,168680,168797,169000,169030,169039,169050,169117,169177,169211,169240,169273,169299,169319,169340,169406,169442,169476,169559, + 169624,169634,169681,169722,169727,169737,169776,169822,169950,170015,170150,170183,170192,170242,170273,170287,170295,170386,170455,170457,170459,170526,170569,170589,170631,170656,170756,170768,170772,170809,170937,170989, + 171031,171074,171091,171117,171123,171133,171158,171178,171361,171520,171581,171592,171638,171661,171729,171773,171836,171843,171862,171875,171876,171880,171948,172068,172070,172103,172127,172164,172234,172341,172342,172507, + 172541,172680,172694,172701,172769,172784,172850,172875,172958,173015,173046,173061,173109,173129,173134,173144,173164,173244,173268,173283,173348,173484,173488,173531,173541,173595,173608,173678,173684,173696,173704,173722, + 173740,173741,173755,173791,173884,173886,173888,173936,173966,174085,174155,174244,174413,174529,174531,174537,175296,175385,175393,175423,175674,175824,175946,176003,176010,176140,176218,176903,176911,177043,177097,177128, + 177223,177230,177233,177276,177406,177443,177529,177580,177691,177725,177772,177863,177981,178014,178217,178286,178358,178437,178487,178498,178712,178814,179072,179159,179364,179414,179605,179637,179656,179693,179803,179860, + 180071,180102,180152,180175,180238,180262,180308,180469,180588,180601,181007,181056,181082,181102,181519, +}; + +static kbts_u8 kbts_UnicodeDecomposition_PageIndices[17407] = { + 0,1,1,2,3,4,5,6,7,1,1,1,1,8,9,10,11,12,1,13,1,1,1,1,14,1,1,15,1,1,1,1, + 1,1,1,1,16,17,1,18,19,20,1,1,1,21,1,22,1,23,1,24,1,25,1,26,1,1,1,1,1,27,28,1, + 29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,30,31, + 1,1,1,1,1,1,1,1,1,1,1,1,32,33,1,1,1,1,1,1,1,1,1,1,34,35,36,37,38,39,40,41, + 42,1,1,1,43,1,44,45,46,47,48,49,50,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,51,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,52,53,54,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,55,56,57,58,59,60,61,62,63,64,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,65,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,66,1,67,1,1,1,1,1,1,1,1,68,69,70,1,1,71,1,1,1,72,1,1,1,1,1,1,1,1,1, + 1,1,1,1,73,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,74,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,75,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,76,77,78,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 79,80,81,82,83,84,85,86,87,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +}; + +static kbts_u64 kbts_UnicodeDecomposition_Data[5632] = { + 52776558133248ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,343932928ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 6442451206ull,6450839814ull,6459228422ull,6467617030ull,6509560070ull,6526337286ull,0ull,6769606926ull,6442451222ull,6450839830ull,6459228438ull,6509560086ull,6442451238ull,6450839846ull,6459228454ull,6509560102ull,0ull,6467617082ull,6442451262ull,6450839870ull,6459228478ull,6467617086ull,6509560126ull,0ull,0ull,6442451286ull,6450839894ull,6459228502ull,6509560150ull,6450839910ull,0ull,0ull, + 6442451334ull,6450839942ull,6459228550ull,6467617158ull,6509560198ull,6526337414ull,0ull,6769607054ull,6442451350ull,6450839958ull,6459228566ull,6509560214ull,6442451366ull,6450839974ull,6459228582ull,6509560230ull,0ull,6467617210ull,6442451390ull,6450839998ull,6459228606ull,6467617214ull,6509560254ull,0ull,0ull,6442451414ull,6450840022ull,6459228630ull,6509560278ull,6450840038ull,0ull,6509560294ull, + 6476005638ull,6476005766ull,6492782854ull,6492782982ull,6777995526ull,6777995654ull,6450839822ull,6450839950ull,6459228430ull,6459228558ull,6501171470ull,6501171598ull,6543114510ull,6543114638ull,6543114514ull,6543114642ull,0ull,0ull,6476005654ull,6476005782ull,6492782870ull,6492782998ull,6501171478ull,6501171606ull,6777995542ull,6777995670ull,6543114518ull,6543114646ull,6459228446ull,6459228574ull,6492782878ull,6492783006ull, + 6501171486ull,6501171614ull,6769606942ull,6769607070ull,6459228450ull,6459228578ull,0ull,0ull,6467617062ull,6467617190ull,6476005670ull,6476005798ull,6492782886ull,6492783014ull,6777995558ull,6777995686ull,6501171494ull,0ull,0ull,0ull,6459228458ull,6459228586ull,6769606958ull,6769607086ull,0ull,6450839858ull,6450839986ull,6769606962ull,6769607090ull,6543114546ull,6543114674ull,0ull, + 0ull,0ull,0ull,6450839866ull,6450839994ull,6769606970ull,6769607098ull,6543114554ull,6543114682ull,0ull,0ull,0ull,6476005694ull,6476005822ull,6492782910ull,6492783038ull,6534725950ull,6534726078ull,0ull,0ull,6450839882ull,6450840010ull,6769606986ull,6769607114ull,6543114570ull,6543114698ull,6450839886ull,6450840014ull,6459228494ull,6459228622ull,6769606990ull,6769607118ull, + 6543114574ull,6543114702ull,6769606994ull,6769607122ull,6543114578ull,6543114706ull,0ull,0ull,6467617110ull,6467617238ull,6476005718ull,6476005846ull,6492782934ull,6492783062ull,6526337366ull,6526337494ull,6534725974ull,6534726102ull,6777995606ull,6777995734ull,6459228510ull,6459228638ull,6459228518ull,6459228646ull,6509560166ull,6450839914ull,6450840042ull,6501171562ull,6501171690ull,6543114602ull,6543114730ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 6668943678ull,6668943806ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6668943702ull,6668943830ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6543114502ull,6543114630ull,6543114534ull,6543114662ull,6543114558ull,6543114686ull,6543114582ull,6543114710ull,6476006258ull,6476006386ull,6450840434ull,6450840562ull,6543115122ull,6543115250ull,6442451826ull,6442451954ull,0ull,6476006162ull,6476006290ull, + 6476007578ull,6476007582ull,6476006170ull,6476006298ull,0ull,0ull,6543114526ull,6543114654ull,6543114542ull,6543114670ull,6777995582ull,6777995710ull,6476007338ull,6476007342ull,6543115998ull,6543116874ull,6543114666ull,0ull,0ull,0ull,6450839838ull,6450839966ull,0ull,0ull,6442451258ull,6442451386ull,6450840342ull,6450840470ull,6450840346ull,6450840474ull,6450840418ull,6450840546ull, + 6568280326ull,6568280454ull,6585057542ull,6585057670ull,6568280342ull,6568280470ull,6585057558ull,6585057686ull,6568280358ull,6568280486ull,6585057574ull,6585057702ull,6568280382ull,6568280510ull,6585057598ull,6585057726ull,6568280394ull,6568280522ull,6585057610ull,6585057738ull,6568280406ull,6568280534ull,6585057622ull,6585057750ull,6761218382ull,6761218510ull,6761218386ull,6761218514ull,0ull,0ull,6543114530ull,6543114658ull, + 0ull,0ull,0ull,0ull,0ull,0ull,6501171462ull,6501171590ull,6769606934ull,6769607062ull,6476006234ull,6476006362ull,6476006230ull,6476006358ull,6501171518ull,6501171646ull,6476007610ull,6476007614ull,6476005734ull,6476005862ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 3073ull,3077ull,0ull,3149ull,6450842658ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,2789ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,237ull,0ull, + 0ull,0ull,0ull,0ull,0ull,6450840226ull,6450843206ull,733ull,6450843222ull,6450843230ull,6450843238ull,0ull,6450843262ull,0ull,6450843286ull,6450843302ull,6450843434ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6509563494ull,6509563542ull,6450843334ull,6450843350ull,6450843358ull,6450843366ull,6450843438ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6509563622ull,6509563670ull,6450843390ull,6450843414ull,6450843430ull,0ull,0ull,0ull,0ull,6450843466ull,6509563722ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 6442455126ull,6509563990ull,0ull,6450843726ull,0ull,0ull,0ull,6509563930ull,0ull,0ull,0ull,0ull,6450843754ull,6442455138ull,6492786830ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6492786786ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6492786914ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6442455254ull,6509564118ull,0ull,6450843854ull,0ull,0ull,0ull,6509564250ull,0ull,0ull,0ull,0ull,6450843882ull,6442455266ull,6492786958ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6568284626ull,6568284630ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,6492786778ull,6492786906ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6492786754ull,6492786882ull,6509563970ull,6509564098ull,0ull,0ull,6492786774ull,6492786902ull,0ull,0ull,6509564770ull,6509564774ull,6509563994ull,6509564122ull,6509563998ull,6509564126ull, + 0ull,0ull,6476009570ull,6476009698ull,6509564002ull,6509564130ull,6509564026ull,6509564154ull,0ull,0ull,6509564834ull,6509564838ull,6509564086ull,6509564214ull,6476009614ull,6476009742ull,6509564046ull,6509564174ull,6534729870ull,6534729998ull,6509564062ull,6509564190ull,0ull,0ull,6509564078ull,6509564206ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,13581162654ull,13589551262ull,13589551394ull,13597939870ull,13589551402ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 13589551958ull,0ull,13589551878ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,13589551946ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,19830678690ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,19830678734ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,19830678614ull,19830678618ull,19830678622ull,19830678642ull,19830678662ull,19830678666ull,19830678702ull,19830678718ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,20921198366ull,21130913566ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,20904421054ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,21978163402ull,0ull,0ull,21978163426ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,21978163290ull,21978163294ull,21978163314ull,0ull,0ull,21978163374ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,24343751966ull,0ull,0ull,24142425374ull,24352140574ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,24125648006ull,24125648010ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,25216167706ull,25216167710ull,25425882906ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,26491236634ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 27556590334ull,0ull,0ull,0ull,0ull,0ull,0ull,27556590362ull,27564978970ull,0ull,27397206810ull,27556590378ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,28437394714ull,28437394718ull,28647109914ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,29611800422ull,0ull,29653743462ull,29611800434ull,29787961190ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,33747385610ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,33747385650ull,0ull,0ull,0ull,0ull,33747385670ull,0ull,0ull,0ull,0ull,33747385690ull,0ull,0ull,0ull,0ull,33747385710ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,33730608386ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,33168571846ull,0ull,33185349062ull,33286012618ull,0ull,33286012622ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,33286012358ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,33747385930ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,33747385970ull,0ull,0ull, + 0ull,0ull,33747385990ull,0ull,0ull,0ull,0ull,33747386010ull,0ull,0ull,0ull,0ull,33747386030ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,33730608706ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,34745630870ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,35235358072582ull,35235366461190ull, + 35235374849798ull,0ull,0ull,0ull,35235408404230ull,35235416792838ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,58426682390ull,0ull,58426682398ull,0ull,58426682406ull,0ull,58426682414ull,0ull,58426682422ull,0ull,0ull,0ull,58426682438ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,58426682602ull,0ull,58426682610ull,0ull,0ull, + 58426682618ull,58426682622ull,0ull,58426682634ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 6752829702ull,6752829830ull,6501171466ull,6501171594ull,6736052490ull,6736052618ull,6853493002ull,6853493130ull,6450840350ull,6450840478ull,6501171474ull,6501171602ull,6736052498ull,6736052626ull,6853493010ull,6853493138ull,6769606930ull,6769607058ull,6819938578ull,6819938706ull,6442452042ull,6442452046ull,6450840650ull,6450840654ull,6819938582ull,6819938710ull,6845104406ull,6845104534ull,6492784802ull,6492784806ull,6501171482ull,6501171610ull, + 6476005662ull,6476005790ull,6501171490ull,6501171618ull,6736052514ull,6736052642ull,6509560098ull,6509560226ull,6769606946ull,6769607074ull,6828327202ull,6828327330ull,6845104422ull,6845104550ull,6450840382ull,6450840510ull,6450839854ull,6450839982ull,6736052526ull,6736052654ull,6853493038ull,6853493166ull,6736052530ull,6736052658ull,6476036314ull,6476036318ull,6853493042ull,6853493170ull,6819938610ull,6819938738ull,6450839862ull,6450839990ull, + 6501171510ull,6501171638ull,6736052534ull,6736052662ull,6501171514ull,6501171642ull,6736052538ull,6736052666ull,6853493050ull,6853493178ull,6819938618ull,6819938746ull,6450840406ull,6450840534ull,6509560662ull,6509560790ull,6442452274ull,6442452278ull,6450840882ull,6450840886ull,6450839874ull,6450840002ull,6501171522ull,6501171650ull,6501171530ull,6501171658ull,6736052554ull,6736052682ull,6476036458ull,6476036462ull,6853493066ull,6853493194ull, + 6501171534ull,6501171662ull,6736052558ull,6736052686ull,6501172586ull,6501172590ull,6501172610ull,6501172614ull,6501202314ull,6501202318ull,6501171538ull,6501171666ull,6736052562ull,6736052690ull,6853493074ull,6853493202ull,6819938642ull,6819938770ull,6744441174ull,6744441302ull,6845104470ull,6845104598ull,6819938646ull,6819938774ull,6450840994ull,6450840998ull,6509561258ull,6509561262ull,6467617114ull,6467617242ull,6736052570ull,6736052698ull, + 6442451294ull,6442451422ull,6450839902ull,6450840030ull,6509560158ull,6509560286ull,6501171550ull,6501171678ull,6736052574ull,6736052702ull,6501171554ull,6501171682ull,6509560162ull,6509560290ull,6501171558ull,6501171686ull,6459228522ull,6459228650ull,6736052586ull,6736052714ull,6853493098ull,6853493226ull,6853493154ull,6509560274ull,6526337502ull,6526337510ull,0ull,6501172734ull,0ull,0ull,0ull,0ull, + 6736052486ull,6736052614ull,6517948678ull,6517948806ull,6450840330ull,6450840458ull,6442451722ull,6442451850ull,6517949194ull,6517949322ull,6467617546ull,6467617674ull,6459259522ull,6459259526ull,6450840586ull,6450840590ull,6442451978ull,6442451982ull,6517949450ull,6517949454ull,6467617802ull,6467617806ull,6492813954ull,6492813958ull,6736052502ull,6736052630ull,6517948694ull,6517948822ull,6467617046ull,6467617174ull,6450840362ull,6450840490ull, + 6442451754ull,6442451882ull,6517949226ull,6517949354ull,6467617578ull,6467617706ull,6459259618ull,6459259622ull,6517948710ull,6517948838ull,6736052518ull,6736052646ull,6736052542ull,6736052670ull,6517948734ull,6517948862ull,6450840402ull,6450840530ull,6442451794ull,6442451922ull,6517949266ull,6517949394ull,6467617618ull,6467617746ull,6459259698ull,6459259702ull,6450841218ull,6450841222ull,6442452610ull,6442452614ull,6517950082ull,6517950086ull, + 6467618434ull,6467618438ull,6736053890ull,6736053894ull,6736052566ull,6736052694ull,6517948758ull,6517948886ull,6450841278ull,6450841282ull,6442452670ull,6442452674ull,6517950142ull,6517950146ull,6467618494ull,6467618498ull,6736053950ull,6736053954ull,6442451302ull,6442451430ull,6736052582ull,6736052710ull,6517948774ull,6517948902ull,6467617126ull,6467617254ull,0ull,0ull,0ull,0ull,0ull,0ull, + 6601838278ull,6610226886ull,6442482690ull,6442482694ull,6450871298ull,6450871302ull,6996130818ull,6996130822ull,6601838150ull,6610226758ull,6442482722ull,6442482726ull,6450871330ull,6450871334ull,6996130850ull,6996130854ull,6601838294ull,6610226902ull,6442482754ull,6442482758ull,6450871362ull,6450871366ull,0ull,0ull,6601838166ull,6610226774ull,6442482786ull,6442482790ull,6450871394ull,6450871398ull,0ull,0ull, + 6601838302ull,6610226910ull,6442482818ull,6442482822ull,6450871426ull,6450871430ull,6996130946ull,6996130950ull,6601838174ull,6610226782ull,6442482850ull,6442482854ull,6450871458ull,6450871462ull,6996130978ull,6996130982ull,6601838310ull,6610226918ull,6442482882ull,6442482886ull,6450871490ull,6450871494ull,6996131010ull,6996131014ull,6601838182ull,6610226790ull,6442482914ull,6442482918ull,6450871522ull,6450871526ull,6996131042ull,6996131046ull, + 6601838334ull,6610226942ull,6442482946ull,6442482950ull,6450871554ull,6450871558ull,0ull,0ull,6601838206ull,6610226814ull,6442482978ull,6442482982ull,6450871586ull,6450871590ull,0ull,0ull,6601838358ull,6610226966ull,6442483010ull,6442483014ull,6450871618ull,6450871622ull,6996131138ull,6996131142ull,0ull,6610226838ull,0ull,6442483046ull,0ull,6450871654ull,0ull,6996131174ull, + 6601838374ull,6610226982ull,6442483074ull,6442483078ull,6450871682ull,6450871686ull,6996131202ull,6996131206ull,6601838246ull,6610226854ull,6442483106ull,6442483110ull,6450871714ull,6450871718ull,6996131234ull,6996131238ull,6442454726ull,3761ull,6442454742ull,3765ull,6442454750ull,3769ull,6442454758ull,3773ull,6442454782ull,3889ull,6442454806ull,3893ull,6442454822ull,3897ull,0ull,0ull, + 7021296642ull,7021296646ull,7021296650ull,7021296654ull,7021296658ull,7021296662ull,7021296666ull,7021296670ull,7021296674ull,7021296678ull,7021296682ull,7021296686ull,7021296690ull,7021296694ull,7021296698ull,7021296702ull,7021296770ull,7021296774ull,7021296778ull,7021296782ull,7021296786ull,7021296790ull,7021296794ull,7021296798ull,7021296802ull,7021296806ull,7021296810ull,7021296814ull,7021296818ull,7021296822ull,7021296826ull,7021296830ull, + 7021297026ull,7021297030ull,7021297034ull,7021297038ull,7021297042ull,7021297046ull,7021297050ull,7021297054ull,7021297058ull,7021297062ull,7021297066ull,7021297070ull,7021297074ull,7021297078ull,7021297082ull,7021297086ull,6492786374ull,6476009158ull,7021297090ull,7021268678ull,7021268658ull,0ull,6996102854ull,7021297370ull,6492786246ull,6476009030ull,6442454598ull,3609ull,7021268550ull,0ull,3813ull,0ull, + 0ull,6996099746ull,7021297106ull,7021268702ull,7021268666ull,0ull,6996102878ull,7021297434ull,6442454614ull,3617ull,6442454622ull,3621ull,7021268574ull,6442483454ull,6450872062ull,6996131582ull,6492786406ull,6476009190ull,6442454826ull,3649ull,0ull,0ull,6996102886ull,6996102954ull,6492786278ull,6476009062ull,6442454630ull,3625ull,0ull,6442483706ull,6450872314ull,6996131834ull, + 6492786454ull,6476009238ull,6442454830ull,3777ull,6601838342ull,6610226950ull,6996102934ull,6996102958ull,6492786326ull,6476009110ull,6442454678ull,3641ull,6610226822ull,6442451618ull,3605ull,385ull,0ull,0ull,7021297138ull,7021268774ull,7021268794ull,0ull,6996102950ull,7021297626ull,6442454654ull,3633ull,6442454694ull,3645ull,7021268646ull,721ull,0ull,0ull, + 32777ull,32781ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,32833ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,3749ull,0ull,0ull,0ull,301ull,789ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6912247362ull,6912247370ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6912247378ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6912247618ull,6912247634ull,6912247626ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,6912247822ull,0ull,0ull,0ull,0ull,6912247842ull,0ull,0ull,6912247854ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,6912247950ull,0ull,6912247958ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,6912248050ull,0ull,0ull,6912248078ull,0ull,0ull,6912248086ull,0ull,6912248098ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 6912213238ull,0ull,6912248198ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6912248118ull,6912213234ull,6912213242ull,6912248210ull,6912248214ull,0ull,0ull,6912248266ull,6912248270ull,0ull,0ull,6912248282ull,6912248286ull,0ull,0ull,0ull,0ull,0ull,0ull, + 6912248298ull,6912248302ull,0ull,0ull,6912248330ull,6912248334ull,0ull,0ull,6912248346ull,6912248350ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6912248458ull,6912248482ull,6912248486ull,6912248494ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 6912248306ull,6912248310ull,6912248390ull,6912248394ull,0ull,0ull,0ull,0ull,0ull,0ull,6912248522ull,6912248526ull,6912248530ull,6912248534ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,49185ull,49189ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6912256886ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,104362721582ull,0ull,104362721590ull,0ull,104362721598ull,0ull,104362721606ull,0ull,104362721614ull,0ull,104362721622ull,0ull,104362721630ull,0ull,104362721638ull,0ull,104362721646ull,0ull,104362721654ull,0ull, + 104362721662ull,0ull,104362721670ull,0ull,0ull,104362721682ull,0ull,104362721690ull,0ull,104362721698ull,0ull,0ull,0ull,0ull,0ull,0ull,104362721726ull,104371110334ull,0ull,104362721738ull,104371110346ull,0ull,104362721750ull,104371110358ull,0ull,104362721762ull,104371110370ull,0ull,104362721774ull,104371110382ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,104362721562ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,104362721910ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,104362721966ull,0ull,104362721974ull,0ull,104362721982ull,0ull,104362721990ull,0ull,104362721998ull,0ull,104362722006ull,0ull,104362722014ull,0ull,104362722022ull,0ull,104362722030ull,0ull,104362722038ull,0ull, + 104362722046ull,0ull,104362722054ull,0ull,0ull,104362722066ull,0ull,104362722074ull,0ull,104362722082ull,0ull,0ull,0ull,0ull,0ull,0ull,104362722110ull,104371110718ull,0ull,104362722122ull,104371110730ull,0ull,104362722134ull,104371110742ull,0ull,104362722146ull,104371110754ull,0ull,104362722158ull,104371110766ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,104362721946ull,0ull,0ull,104362722238ull,104362722242ull,104362722246ull,104362722250ull,0ull,0ull,0ull,104362722294ull,0ull, + 143649ull,105425ull,146217ull,144161ull,113477ull,80073ull,85909ull,163441ull,163441ull,91461ull,149317ull,87581ull,91425ull,100313ull,121253ull,130581ull,137469ull,138985ull,140257ull,148029ull,108553ull,111725ull,115557ull,118649ull,135413ull,148905ull,157637ull,80393ull,85461ull,109585ull,116845ull,137397ull, + 161913ull,95553ull,114605ull,137013ull,140689ull,101157ull,132961ull,139389ull,97065ull,105565ull,112041ull,117745ull,148281ull,81433ull,83677ull,84857ull,103185ull,109389ull,116801ull,121757ull,131077ull,137241ull,137585ull,145341ull,154825ull,159165ull,161769ull,123441ull,124413ull,128641ull,134949ull,150545ull, + 162301ull,142169ull,91005ull,97297ull,127361ull,131577ull,117129ull,123689ull,144137ull,154589ull,90977ull,94601ull,108621ull,112489ull,113725ull,128189ull,129245ull,153901ull,84809ull,131629ull,83825ull,83761ull,125041ull,128761ull,135109ull,154069ull,142849ull,101181ull,108553ull,142329ull,80101ull,94109ull, + 98377ull,118301ull,120257ull,85085ull,123885ull,81661ull,97957ull,79925ull,111409ull,103905ull,128137ull,85773ull,90489ull,121861ull,135461ull,141993ull,110313ull,147137ull,111137ull,101369ull,134037ull,102017ull,120213ull,80569ull,83365ull,83749ull,107013ull,127901ull,133565ull,142153ull,149309ull,84949ull, + 86281ull,91597ull,97201ull,104213ull,114681ull,124073ull,153269ull,158121ull,162397ull,162617ull,84589ull,105241ull,110045ull,146825ull,96721ull,99905ull,100353ull,103017ull,113805ull,116005ull,119333ull,124713ull,128977ull,131517ull,146585ull,136121ull,147597ull,150825ull,84061ull,84621ull,86773ull,115489ull, + 140041ull,141993ull,97061ull,98261ull,101869ull,110265ull,127225ull,118229ull,80785ull,89061ull,94109ull,95977ull,98417ull,118473ull,119205ull,130665ull,131353ull,149713ull,154585ull,154913ull,155745ull,81453ull,124601ull,149201ull,154337ull,99205ull,80409ull,82793ull,94137ull,94461ull,104037ull,108553ull, + 116537ull,121097ull,136177ull,147953ull,163381ull,104993ull,153785ull,84517ull,105965ull,106445ull,111877ull,113265ull,118821ull,120165ull,123309ull,128065ull,156025ull,83381ull,100537ull,154081ull,82093ull,95333ull,112553ull,146601ull,97837ull,99601ull,106589ull,118301ull,154137ull,84133ull,86077ull,94613ull, + 104525ull,105785ull,107169ull,111509ull,118809ull,120713ull,130533ull,140093ull,140165ull,149297ull,154505ull,85245ull,113385ull,86133ull,116545ull,119393ull,137193ull,154253ull,160093ull,162429ull,106077ull,112429ull,133025ull,125741ull,126081ull,127561ull,117505ull,115301ull,142689ull,80641ull,134361ull,84201ull, + 83997ull,96921ull,101197ull,127833ull,93717ull,111737ull,105169ull,146669ull,139569ull,153909ull,140845ull,97101ull,83201ull,87809ull,0ull,0ull,90473ull,0ull,104913ull,0ull,0ull,83833ull,117929ull,121641ull,124145ull,124281ull,124309ull,124477ull,154969ull,127737ull,130805ull,0ull, + 137289ull,0ull,142305ull,0ull,0ull,147681ull,148469ull,0ull,0ull,0ull,156605ull,156657ull,156833ull,161489ull,148345ull,154333ull,81593ull,82845ull,83253ull,84773ull,84881ull,85317ull,87669ull,88089ull,88481ull,90369ull,90785ull,94609ull,94649ull,98897ull,99745ull,99897ull, + 100297ull,103741ull,104329ull,105029ull,107029ull,112093ull,112745ull,113801ull,116153ull,116909ull,118921ull,123461ull,124153ull,124197ull,124193ull,124225ull,124249ull,124277ull,124469ull,124473ull,125185ull,125445ull,126721ull,128977ull,129061ull,129285ull,130505ull,131093ull,133045ull,133605ull,133605ull,135517ull, + 140353ull,140889ull,142341ull,142565ull,144205ull,144417ull,147161ull,147681ull,154509ull,155645ull,155885ull,98773ull,592825ull,133217ull,0ull,0ull,80025ull,83669ull,83361ull,81409ull,83221ull,83457ull,84765ull,84969ull,87669ull,87381ull,87653ull,87945ull,90473ull,90829ull,91409ull,91473ull, + 92553ull,93345ull,97097ull,97125ull,97701ull,97973ull,99169ull,99641ull,99361ull,99897ull,99713ull,100297ull,100561ull,102161ull,102513ull,102729ull,103769ull,104913ull,105565ull,105581ull,105817ull,110053ull,110313ull,111877ull,113517ull,113453ull,113801ull,114809ull,116153ull,122525ull,116949ull,117437ull, + 117929ull,119237ull,119833ull,120045ull,120949ull,120957ull,121641ull,121709ull,121809ull,122153ull,122113ull,123697ull,125637ull,126721ull,127469ull,128365ull,128977ull,130297ull,131093ull,134473ull,135101ull,138725ull,140549ull,140825ull,140889ull,142077ull,142305ull,142125ull,142341ull,142329ull,142261ull,142565ull, + 142889ull,144417ull,146657ull,147913ull,149093ull,149977ull,154097ull,154509ull,154969ull,155501ull,155645ull,155693ull,155885ull,158793ull,163441ull,565545ull,565521ull,577365ull,61045ull,65633ull,65765ull,608549ull,619329ull,654157ull,163085ull,163385ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,12247373670ull,0ull,12272539594ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,12356425638ull,12364814246ull,12356676902ull,12365065510ull,12272539458ull,12280928066ull,12314482498ull,12314482502ull,12314482506ull,12314482510ull,12314482514ull,12314482518ull,12314482522ull,0ull,12314482530ull,12314482534ull,12314482538ull,12314482542ull,12314482546ull,0ull,12314482554ull,0ull, + 12314482562ull,12314482566ull,0ull,12314482574ull,12314482578ull,0ull,12314482586ull,12314482590ull,12314482594ull,12314482598ull,12314482602ull,12289316694ull,12339648326ull,12339648366ull,12339648402ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,6501439306ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,6501439338ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,585676112486ull,0ull,585676112494ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,585676112534ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,586590471366ull,586590471370ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,591078378782ull,591288093982ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,592244395530ull,0ull,592126955026ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,592185675310ull,0ull,0ull,592244395586ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,592185675530ull,0ull,592101789450ull,592244395786ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,594266051302ull,594182165222ull,0ull,594291217126ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,596321261282ull,596321261286ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,603845846230ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,758313747578ull,758406022266ull,758322136186ull,758322136230ull,758330524794ull,758322136198ull,758322136202ull,758330524806ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,784695932318ull,784695932302ull,784695932326ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,999427622238ull,999427622242ull, + 999503119742ull,999511508350ull,999519896958ull,999528285566ull,999536674174ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,999427622630ull,999427622634ull,999503120110ull,999503120114ull,999511508718ull, + 999511508722ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, + 80117ull,80097ull,80133ull,525449ull,81281ull,81593ull,81645ull,81929ull,82409ull,82533ull,82845ull,82749ull,53881ull,530665ull,83253ull,83281ull,83345ull,83421ull,529521ull,53989ull,83357ull,83509ull,529709ull,83549ull,83601ull,80689ull,83633ull,83669ull,673661ull,83925ull,83981ull,54141ull, + 84205ull,84249ull,84425ull,84445ull,54357ull,84765ull,84773ull,84881ull,84969ull,85013ull,85017ull,85085ull,85285ull,85317ull,85353ull,85453ull,85493ull,85501ull,85501ull,85501ull,534705ull,115137ull,85801ull,85885ull,535949ull,85933ull,85957ull,86041ull,86649ull,86241ull,86305ull,86433ull, + 86665ull,87001ull,87105ull,87373ull,87437ull,87569ull,87569ull,87653ull,87725ull,87757ull,87817ull,89177ull,88089ull,89181ull,88389ull,88529ull,83997ull,91065ull,89913ull,90065ull,90165ull,89645ull,90313ull,90309ull,90801ull,545681ull,91081ull,91101ull,91161ull,91241ull,91273ull,91529ull, + 547489ull,547753ull,92081ull,92269ull,92317ull,92001ull,92569ull,56249ull,56305ull,93217ull,93433ull,93433ull,550689ull,93965ull,94049ull,94109ull,94157ull,552033ull,94205ull,94233ull,97613ull,94345ull,56837ull,94593ull,94649ull,94977ull,94773ull,554897ull,95501ull,554905ull,95673ull,95661ull, + 95729ull,96133ull,96137ull,57533ull,96245ull,96417ull,96501ull,96677ull,57737ull,558605ull,57841ull,96961ull,96973ull,96985ull,97065ull,691785ull,97273ull,560325ull,560325ull,133125ull,97417ull,97417ull,58141ull,576225ull,624489ull,97673ull,97709ull,58253ull,97897ull,98101ull,98141ull,98277ull, + 98821ull,58601ull,58481ull,98897ull,564049ull,99101ull,99617ull,99633ull,99641ull,99633ull,99817ull,99897ull,100041ull,99985ull,100029ull,100217ull,100297ull,100313ull,100417ull,100461ull,100725ull,101061ull,101201ull,101697ull,568369ull,101621ull,101361ull,101793ull,101901ull,102289ull,569285ull,102537ull, + 102165ull,102053ull,59577ull,102821ull,102905ull,103029ull,102877ull,59825ull,103741ull,103857ull,573481ull,104333ull,105441ull,104741ull,60517ull,105029ull,60449ull,60305ull,83529ull,83541ull,105473ull,105073ull,131765ull,69477ull,105565ull,105581ull,105605ull,105849ull,105805ull,577293ull,60709ull,106473ull, + 106005ull,106825ull,107029ull,577973ull,107065ull,106621ull,107601ull,61045ull,107785ull,108173ull,108457ull,109217ull,580237ull,109421ull,61537ull,109701ull,582301ull,109905ull,61753ull,110025ull,110205ull,110313ull,110317ull,584245ull,554029ull,584681ull,110905ull,586481ull,111357ull,111413ull,111005ull,111705ull, + 111865ull,112093ull,111877ull,112037ull,112097ull,112149ull,586873ull,111825ull,112829ull,113081ull,62669ull,113453ull,113437ull,588613ull,112613ull,114105ull,589177ull,589369ull,114457ull,114917ull,114809ull,114797ull,63065ull,114985ull,115189ull,115165ull,115381ull,529557ull,115989ull,592269ull,116337ull,593581ull, + 116897ull,116949ull,117057ull,596001ull,117249ull,117333ull,597205ull,598097ull,118249ull,118317ull,64177ull,118421ull,64225ull,64225ull,119069ull,119153ull,119237ull,119317ull,119593ull,64621ull,119953ull,602329ull,120057ull,602697ull,120257ull,558717ull,120897ull,605829ull,605921ull,606481ull,65521ull,65569ull, + 121809ull,607181ull,607177ull,607333ull,607437ull,121977ull,121981ull,121981ull,122153ull,65765ull,122413ull,65817ull,66137ull,610421ull,123193ull,123441ull,123697ull,66445ull,612505ull,124249ull,612969ull,613141ull,124477ull,124845ull,66749ull,125185ull,125225ull,125245ull,615921ull,617117ull,617117ull,125881ull, + 67593ull,618157ull,126745ull,126757ull,67741ull,619009ull,127817ull,68225ull,127905ull,127885ull,128001ull,622105ull,128397ull,68613ull,128797ull,129033ull,129301ull,68817ull,624801ull,624925ull,68965ull,625509ull,130537ull,625913ull,130645ull,131049ull,131093ull,627561ull,627853ull,131457ull,628385ull,131521ull, + 576893ull,69461ull,131785ull,132109ull,69677ull,132345ull,92885ull,630429ull,630485ull,577101ull,577137ull,133125ull,133137ull,147065ull,70061ull,133701ull,133677ull,133749ull,84685ull,133829ull,133837ull,133877ull,134041ull,634097ull,134037ull,134261ull,134541ull,134837ull,134285ull,134901ull,135069ull,135517ull, + 134477ull,134953ull,134961ull,135025ull,635097ull,636333ull,635733ull,70829ull,136133ull,136141ull,136281ull,642857ull,136593ull,638129ull,71029ull,71045ull,638661ull,639817ull,71085ull,137537ull,137585ull,137629ull,137637ull,137893ull,137761ull,138297ull,138121ull,138725ull,138401ull,138669ull,138777ull,71517ull, + 139141ull,139269ull,71653ull,139649ull,139661ull,645533ull,140125ull,140153ull,71893ull,140265ull,53997ull,647865ull,648601ull,72441ull,72477ull,141953ull,142261ull,142889ull,143701ull,651937ull,144045ull,144133ull,144493ull,144861ull,654525ull,532497ull,145197ull,145137ull,145345ull,533369ull,146257ull,146657ull, + 661321ull,661429ull,148049ull,148421ull,148549ull,662713ull,148589ull,149729ull,150365ull,150369ull,150001ull,151525ull,151637ull,667625ull,153133ull,75349ull,153309ull,669149ull,75673ull,154381ull,95945ull,154765ull,673045ull,673897ull,76217ull,76249ull,155521ull,675881ull,76489ull,676441ull,155693ull,155693ull, + 155813ull,677593ull,156553ull,77005ull,156837ull,157341ull,157449ull,157689ull,77625ull,683201ull,158793ull,160001ull,160757ull,78649ull,78773ull,161181ull,688953ull,78817ull,689173ull,690233ull,690757ull,162541ull,79193ull,162789ull,162809ull,162837ull,162877ull,162905ull,163053ull,694273ull,0ull,0ull, + 0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull,0ull, +}; + +KBTS_INLINE kbts_u64 kbts_GetUnicodeDecomposition(kbts_u32 Codepoint) +{ + return kbts_UnicodeDecomposition_Data[((kbts_un)kbts_UnicodeDecomposition_PageIndices[Codepoint/64] * 64) | (Codepoint & 63)]; +} + +static kbts_u8 kbts_UnicodeWordBreakClass_PageIndices[8703] = { + 0,1,2,2,2,3,4,5,2,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,2,2,31,32,33,34,35,2,2,2,36,37,38,39,40,41,42,43,44,45,46,47,48,49,2,50,2,2,51,52, + 53,54,55,56,57,57,58,59,57,60,57,61,62,63,64,65,57,57,66,57,57,57,67,57,2,68,69,70,71,57,57,57, + 72,73,74,75,57,76,77,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 2,2,2,2,2,2,2,2,2,78,2,2,79,80,81,82,83,84,85,86,87,88,89,90,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,91,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,92,93,2,2,94,95,96,97,98,99, + 100,101,102,103,57,104,105,106,2,107,108,109,2,2,110,111,112,113,114,115,116,117,118,119,120,121,122,123,57,124,125,126, + 127,128,129,130,131,132,133,134,135,136,57,137,138,139,140,57,141,142,143,144,145,146,57,147,148,149,150,151,57,152,153,154, + 2,2,2,2,2,2,2,155,156,2,157,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,158, + 2,2,2,2,2,2,2,2,159,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,101,2,2,2,2,160,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,161,57,57,57,57,57,57,57,57,57,57,57,57,57,2,2,2,2,162,163,164,165,57,57,166,57,167,57,168,169, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,170, + 171,57,172,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,173,174,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,175,57,57,57,57,176,57, + 57,57,177,178,179,57,57,57,180,181,182,2,2,183,184,185,57,57,57,57,186,187,57,57,57,57,57,57,57,57,188,57, + 189,190,191,57,57,192,57,57,57,193,57,194,57,57,57,195,2,196,197,57,57,57,57,57,57,57,57,57,198,199,57,57, + 200,200,201,202,203,200,200,204,200,200,205,200,206,200,207,208,209,210,211,200,200,200,57,175,200,200,200,200,200,200,200,212, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 213,57,214,215,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +}; + +static kbts_u8 kbts_UnicodeWordBreakClass_Data[27648] = { + 0,0,0,0,0,0,0,0,0,0,3,4,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,14,0,0,0,0,13,0,0,0,0,17,0,15,0,18,18,18,18,18,18,18,18,18,18,16,17,0,0,0,0, + 0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,19,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0, + 0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,11,0,0,8,1,0,0,0,0,0,0,11,0,16,0,0,11,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,11,11,11,11,11,0,11,11,0,0,11,11,11,11,17,11, + 0,0,0,0,0,0,11,16,11,11,11,0,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11, + 11,11,0,5,5,5,5,5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,0,11,16,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,17,11,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5, + 0,5,5,0,5,5,0,5,0,0,0,0,0,0,0,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0,0,10,10,10,10,11,16,0,0,0,0,0,0,0,0,0,0,0, + 18,18,18,18,18,18,0,0,0,0,0,0,17,17,0,0,5,5,5,5,5,5,5,5,5,5,5,0,8,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,18,18,18,18,18,18,18,18,18,18,0,18,17,0,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,5,5,5,5,5,5,5,18,0,5,5,5,5,5,5,11,11,5,5,0,5,5,5,5,11,11,18,18,18,18,18,18,18,18,18,18,11,11,11,0,0,11, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 18,18,18,18,18,18,18,18,18,18,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,11,11,0,0,17,0,11,0,0,5,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,11,5,5,5,5,5,5,5,5,5,11,5,5,5,11,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,0,18,18,0,0,0,0,0,5,5,5,5,5,5,5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,18,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,11,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,11,5,5,5,5,5,5,5,11,11,11,11,11,11,11,11,11,11,5,5,0,0,18,18,18,18,18,18,18,18,18,18,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,5,5,5,0,11,11,11,11,11,11,11,11,0,0,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,0,0,0,11,11,11,11,0,0,5,11,5,5, + 5,5,5,5,5,0,0,5,5,0,0,5,5,5,11,0,0,0,0,0,0,0,0,5,0,0,0,0,11,11,0,11,11,11,5,5,0,0,18,18,18,18,18,18,18,18,18,18,11,11,0,0,0,0,0,0,0,0,0,0,11,0,5,0, + 0,5,5,5,0,11,11,11,11,11,11,0,0,0,0,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,0,11,11,0,11,11,0,0,5,0,5,5, + 5,5,5,0,0,0,0,5,5,0,0,5,5,5,0,0,0,5,0,0,0,0,0,0,0,11,11,11,11,0,11,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,5,5,11,11,11,5,0,0,0,0,0,0,0,0,0,0, + 0,5,5,5,0,11,11,11,11,11,11,11,11,11,0,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,0,11,11,11,11,11,0,0,5,11,5,5, + 5,5,5,5,5,5,0,5,5,5,0,5,5,5,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,5,5,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,11,5,5,5,5,5,5, + 0,5,5,5,0,11,11,11,11,11,11,11,11,0,0,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,0,11,11,11,11,11,0,0,5,11,5,5, + 5,5,5,5,5,0,0,5,5,0,0,5,5,5,0,0,0,0,0,0,0,5,5,5,0,0,0,0,11,11,0,11,11,11,5,5,0,0,18,18,18,18,18,18,18,18,18,18,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,5,11,0,11,11,11,11,11,11,0,0,0,11,11,11,0,11,11,11,11,0,0,0,11,11,0,11,0,11,11,0,0,0,11,11,0,0,0,11,11,11,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,5,5, + 5,5,5,0,0,0,5,5,5,0,5,5,5,5,0,0,11,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,11,11,11,11,11,11,11,11,0,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,5,11,5,5, + 5,5,5,5,5,0,5,5,5,0,5,5,5,5,0,0,0,0,0,0,0,5,5,0,11,11,11,0,0,11,0,0,11,11,5,5,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,5,5,5,0,11,11,11,11,11,11,11,11,0,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,0,0,5,11,5,5, + 5,5,5,5,5,0,5,5,5,0,5,5,5,5,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,11,11,0,11,11,5,5,0,0,18,18,18,18,18,18,18,18,18,18,0,11,11,5,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,11,11,11,11,11,11,11,11,11,0,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,11,5,5, + 5,5,5,5,5,0,5,5,5,0,5,5,5,5,11,0,0,0,0,0,11,11,11,5,0,0,0,0,0,0,0,11,11,11,5,5,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11, + 0,5,5,5,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,0,11,0,0, + 11,11,11,11,11,11,11,0,0,0,5,0,0,0,0,5,5,5,5,5,5,0,5,0,5,5,5,5,5,5,5,5,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5,5,5,5,5,5,5,0,0,0,0,0, + 0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5,5,5,5,5,5,5,5,5,0,0,0, + 0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,5,0,0,0,0,5,5, + 11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,0,5,5,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0, + 0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, + 18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,5,5,5,0,5,5,5,0,0,5,5,5,5,5,5,5,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0, + 0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,5,18,18,18,18,18,18,18,18,18,18,5,5,5,5,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,0,11,0,0,0,0,0,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,0,11,11,11,11,0,0,11,11,11,11,11,11,11,0,11,0,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,0,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,0,0,11,11,11,11,11,11,11,0, + 11,0,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,0,0, + 0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 20,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,5,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,5,5,5,8,5,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0, + 11,11,11,11,11,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0, + 0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,5, + 18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,11,11,11,11,11,11,11,11,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,11,11,18,18,18,18,18,18,18,18,18,18,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0, + 18,18,18,18,18,18,18,18,18,18,0,0,0,11,11,11,18,18,18,18,18,18,18,18,18,18,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0, + 11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,11,11,11,11,5,11,11,11,11,11,11,5,11,11,5,5,5,11,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,0,0,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,0,11,0,11,0,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,0, + 0,0,11,11,11,0,11,11,11,11,11,11,11,0,0,0,11,11,11,11,0,0,11,11,11,11,11,11,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,11,11,11,0,11,11,11,11,11,11,11,0,0,0, + 20,20,20,20,20,20,20,0,20,20,20,0,5,6,8,8,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,15,0,0,16,4,4,8,8,8,8,8,19,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,19, + 19,0,0,0,17,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,20,8,8,8,8,8,0,8,8,8,8,8,8,8,8,8,8,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,11, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,11,0,0,0,0,11,0,0,11,11,11,11,11,11,11,11,11,11,0,11,0,0,0,11,11,11,11,11,0,0,0,0,1,0,11,0,11,0,11,0,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,12,0,0,11,11,11,11, + 0,0,0,0,0,11,11,11,11,11,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,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,0,0,0,0,1,1,1,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11, + 11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0, + 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,11,11,11,11,5,5,5,11,11,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,0,0,0,0,0,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0, + 11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 20,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,1,9,9,9,9,9,0,0,0,0,0,11,11,1,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,9,9,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,9,9,9,9, + 0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,18,18,18,18,18,18,18,18,18,18,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,0,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,0,11,0,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,5,11,11,11,5,11,11,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,11,11,11,11,11,11,0,0,0,11,0,11,11,5, + 18,18,18,18,18,18,18,18,18,18,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0, + 5,5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0, + 11,11,11,5,11,11,11,11,11,11,11,11,5,5,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,5,5,0,0,5,5,0,0,0,0,0,5,5, + 0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,0,0,11,11,11,5,5,0,0,0,0,0,0,0,0,0, + 0,11,11,11,11,11,11,0,0,11,11,11,11,11,11,0,0,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,0,5,5,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0, + 11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,0,0,0,0,0,10,5,10,10,10,10,10,10,10,10,10,10,0,10,10,10,10,10,10,10,10,10,10,10,10,10,0,10,10,10,10,10,0,10,0, + 10,10,0,10,10,0,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,19,19,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,19,19,19,17,0,15,0,17,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,8, + 0,0,0,0,0,0,0,15,0,0,0,0,17,0,15,0,18,18,18,18,18,18,18,18,18,18,16,17,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,19, + 0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0, + 0,0,11,11,11,11,11,11,0,0,11,11,11,11,11,11,0,0,11,11,11,11,11,11,0,0,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,8,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,0,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,0,0,0,0,11,11,11,11,11,11,11,11,0,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,0,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,0,0,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,0,0,0,11,0,0,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,11,11, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,5,5,5,0,5,5,0,0,0,0,0,5,5,5,5,11,11,11,11,0,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,5,5,5,0,0,0,0,5, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 18,18,18,18,18,18,18,18,18,18,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,5,5,5,5,5,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,5,5,0,0,0,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0, + 5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,5,11,11,5,5,11,0,0,0,0,0,0,0,0,0,5, + 5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,0,0,18,0,0, + 0,0,5,0,0,0,0,0,0,0,0,0,0,18,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,18,18,18,18,18,18,18,18,18,18, + 0,0,0,0,11,5,5,11,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,0,0,11,0,0,0,0,0,0,0,0,0, + 5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,11,11,11,11,0,0,0,0,5,5,5,5,0,5,5,18,18,18,18,18,18,18,18,18,18,11,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,5,11, + 11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,0,11,0,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 5,5,5,5,0,11,11,11,11,11,11,11,11,0,0,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,0,11,11,11,11,11,0,5,5,11,5,5, + 5,5,5,5,5,0,0,5,5,0,0,5,5,5,0,0,11,0,0,0,0,0,0,5,0,0,0,0,0,11,11,11,11,11,5,5,0,0,5,5,5,5,5,5,5,0,0,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,0,11,0,0,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,5,5,5,5,5,5,5,5, + 5,0,5,0,0,5,0,5,5,5,5,0,5,5,5,5,5,11,5,11,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,11,11,11,11,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,5,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,11,11,0,11,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5, + 5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,11,0,0,0,0,0,0,0, + 18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11, + 11,11,11,11,11,11,11,0,0,11,0,0,11,11,11,11,11,11,11,11,0,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,0,5,5,0,0,5,5,5,5,11, + 5,11,5,5,0,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,11,0,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,5,5,5,5,5,5,5,5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,11,5,5,5,5,0, + 0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,11,5,5,5,5,5,5,5,5,5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5, + 11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,0,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,0,0,0,5,0,5,5,0,5, + 5,5,5,5,5,5,11,5,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,11,11,11,11,11,11,0,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,0,5,5,0,5,5,5,5,5,11,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,0,0,0,0,0,0,0,0,0, + 5,5,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,0,0,0,5,5, + 5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 5,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0, + 18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0, + 11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,5,11,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,5,5,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,0,11,5,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,9,0,9,9,9,9,9,9,9,0,9,9,0, + 9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0, + 11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,0,0,0,5,5,0,8,8,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,0,0,5,5,5,5,5,5,8,8,8,8,8,8,8,8,5,5,5,5,5, + 5,5,5,0,0,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,0,0,11,0,0,11,11,0,0,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,0,11,0,11,11,11, + 11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,0,11,11,11,11,0,0,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,0, + 11,11,11,11,11,0,11,0,0,0,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,0,11,11,11,11,11,11,11,11,0,0,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,0,5,5,0,5,5,5,5,5,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,5,5,5,5,5,5,5,11,11,11,11,11,11,11,0,0, + 18,18,18,18,18,18,18,18,18,18,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5,5,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,11,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,11,11,11,11,11,11,0,11,11,11,11,0,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,5,5,5,5,5,5,5,11,0,0,0,0,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,0,11,0,0,11,0,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,0,11,0,11,0,0,0,0, + 0,0,11,0,0,0,0,11,0,11,0,11,0,11,11,11,0,11,11,0,11,0,0,11,0,11,0,11,0,11,0,11,0,11,11,0,11,0,0,11,11,11,11,0,11,11,11,11,11,11,11,0,11,11,11,11,0,11,11,11,11,0,11,0, + 11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,11,11,11,0,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,0,0,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,1,1,1,1,12,12,11,11,11,11,11,11,11,11,11,11,11,11,12,12, + 11,11,11,11,11,11,11,11,11,11,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,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,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1, + 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,5,5,5,5,5, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, + 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1, + 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, + 0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +KBTS_INLINE kbts_u8 kbts_GetUnicodeWordBreakClass(kbts_u32 Codepoint) +{ + return kbts_UnicodeWordBreakClass_Data[((kbts_un)kbts_UnicodeWordBreakClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; +} + +static kbts_u8 kbts_UnicodeLineBreakClass_PageIndices[8703] = { + 0,1,2,2,2,3,4,2,2,5,2,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,2,2,31,2,32,2,2,2,2,33,34,35,36,37,38,39,40,41,42,43,44,45,2,46,2,2,2,47, + 48,49,50,2,51,52,53,54,2,2,2,55,56,57,58,59,2,2,2,60,2,2,61,2,2,62,63,64,65,66,67,68, + 69,70,71,72,73,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,74,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 75,67,67,67,67,67,67,67,67,76,2,2,77,78,2,2,79,80,81,82,83,84,2,85,86,87,88,89,90,91,92,86, + 87,88,89,90,91,92,86,87,88,89,90,91,92,86,87,88,89,90,91,92,86,87,88,89,90,91,92,86,87,88,89,90, + 91,92,86,87,88,89,90,91,92,86,87,88,89,90,91,92,86,87,88,89,90,91,92,86,87,88,89,90,91,92,86,87, + 88,89,90,91,92,86,87,88,89,90,91,92,86,87,88,93,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,67,67,67,67,95,2,2,2,96,97,98,99,100,101, + 2,2,102,103,2,104,105,106,2,107,2,2,2,2,2,2,108,2,109,2,110,111,112,2,2,2,113,2,2,114,115,116, + 117,118,119,120,121,122,123,124,125,126,2,127,128,129,130,2,131,132,133,134,135,136,137,138,139,140,141,142,2,143,144,145, + 2,2,2,2,2,2,2,2,146,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,147,148,149,2,150,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,151,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,152,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,153,154,155,2,2,2,156,2,2,157,158,159, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,160,67,67,67,67,67,67,161,161,161,162,163,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,164, + 67,67,165,67,67,166,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,167,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,138,2,2,2,2,168,2, + 2,2,169,170,171,2,172,2,2,2,2,2,2,2,2,173,2,2,2,2,174,175,2,2,2,2,2,2,2,2,2,2, + 176,177,178,2,2,179,2,2,2,180,2,181,2,2,2,2,2,182,183,2,2,2,2,2,2,184,2,2,2,2,2,2, + 185,186,2,187,188,189,190,191,192,193,194,195,196,197,198,199,2,2,200,201,202,203,2,138,189,189,189,189,189,189,189,204, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,205, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,205, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 206,2,207,208,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +}; + +static kbts_u8 kbts_UnicodeLineBreakClass_Data[26752] = { + 63,63,63,63,63,63,63,63,63,19,5,3,3,4,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,7,16,23,37,40,48,37,23,21,14,37,40,26,31,26,18,39,39,39,39,39,39,39,39,39,39,26,26,37,37,37,16, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,40,14,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,19,12,37,63, + 63,63,63,63,63,6,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,10,21,48,40,40,40,37,37,37,37,37,24,37,19,37,37,48,40,37,37,35,37,37,37,37,37,37,25,37,37,37,21, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,35,37,37,37,35,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,35,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,10,63,63,63,63,63,63,63,63,63,63,63,63,10,10,10,10,10,10,10,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,26,37, + 37,37,37,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,26,19,37,37,37,37,40,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,19,63, + 37,63,63,37,63,63,16,63,37,37,37,37,37,37,37,37,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,37,37,37,37,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37, + 39,39,39,39,39,39,37,37,37,48,48,48,26,26,37,37,63,63,63,63,63,63,63,63,63,63,63,16,63,16,16,16,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,39,39,39,39,39,39,39,39,39,39,48,39,39,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,16,37,63,63,63,63,63,63,63,39,37,63,63,63,63,63,63,37,37,63,63,37,63,63,63,63,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,37,37,37,37,26,16,37,37,37,63,40,40, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,37,63,63,63,63,63,63,63,63,63,37,63,63,63,37,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,37,37,37,37,37,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,39,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,37,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,63,63,19,19,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,63,63, + 63,63,63,63,63,37,37,63,63,37,37,63,63,63,37,37,37,37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,63,63,37,37,39,39,39,39,39,39,39,39,39,39,37,37,48,48,37,37,37,37,37,48,37,40,37,37,63,37, + 37,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,63,63, + 63,63,63,37,37,37,37,63,63,37,37,63,63,63,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,63,63,37,37,37,63,37,37,37,37,37,37,37,37,37,37, + 37,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,63,63, + 63,63,63,63,63,63,37,63,63,63,37,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,37,37,39,39,39,39,39,39,39,39,39,39,37,40,37,37,37,37,37,37,37,37,63,63,63,63,63,63, + 37,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,63,63, + 63,63,63,63,63,37,37,63,63,37,37,63,63,63,37,37,37,37,37,37,37,63,63,63,37,37,37,37,37,37,37,37,37,37,63,63,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63, + 63,63,63,37,37,37,63,63,63,37,63,63,63,63,37,37,37,37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,40,37,37,37,37,37,37, + 63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,63,63, + 63,63,63,63,63,37,63,63,63,37,63,63,63,63,37,37,37,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,63,63,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,35,37,37,37,37,37,37,37,37, + 37,63,63,63,35,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,63,63, + 63,63,63,63,63,37,63,63,63,37,63,63,63,63,37,37,37,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,63,63,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37, + 63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,37,63,63, + 63,63,63,63,63,37,63,63,63,37,63,63,63,63,37,37,37,37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,63,63,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,48,37,37,37,37,37,37, + 37,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,63,37,37,37,37,63,63,63,63,63,63,37,63,37,63,63,63,63,63,63,63,63,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,40, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,35,35,35,35,37,35,35,10,35,35,19,10,16,16,16,16,16,10,37,16,37,37,37,63,63,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,19,63,37,63,37,63,21,12,21,12,63,63, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,19, + 63,63,63,63,63,19,63,63,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,19,19, + 37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,35,35,19,35,37,37,37,37,37,10,10,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 39,39,39,39,39,39,39,39,39,39,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, + 51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, + 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,37,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,19,19,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,27,37,19,37,19,40,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,16,16,19,19,35,37,16,16,37,63,63,63,10,63,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37, + 37,37,37,37,16,16,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63, + 39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 63,63,63,63,63,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,60,56,56,56,56,56,56,56,56,37,19,19,58,58,58,58,58,58,58,58,58,58,19,19,42,19,19,19,19,42,42,42,42,42,42,42,42,42,42,63,63,63,63,63,63,63,63,63,42,42,42,42,42,42,42,42,42,19,19,19, + 63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,63,63,63,63,63,63,63,63,63,63,63,63,59,59,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,19,19,19,19,19, + 39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,63,37,37,37,37,37,37,63,37,37,63,63,63,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 63,63,63,63,63,63,63,63,63,63,63,63,63,10,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,10,63,63,63, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,35,37,37, + 19,19,19,19,19,19,19,10,19,19,19,8,63,64,63,63,32,10,19,19,29,37,37,37,24,25,21,24,24,25,21,24,37,37,37,37,33,33,33,19,3,3,63,63,63,63,63,10,48,48,48,48,48,48,48,48,37,24,25,37,27,27,37,37, + 37,37,37,37,26,21,12,27,27,27,37,37,37,37,37,37,37,37,37,37,37,37,19,48,19,19,19,19,37,19,19,19,9,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,21,12,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,21,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,40,40,40,40,40,40,40,48,40,41,40,40,40,40,40,40,40,40,40,40,40,40,48,40,40,40,40,48,40,40,48,40, + 48,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,48,37,37,37,37,37,48,37,37,37,37,37,37,37,37,37,37,37,37,40,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,40,40,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,33,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,21,12,21,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,43,43,37,37,37,37,37,37,37,37,37,37,37,37,37,22,13,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,38,38,38,37,37,37,43,42,42,43,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,57,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,38,37, + 42,42,42,42,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,43,43,37,37,42,37,42,42,42,45,42,42,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,37,42,42,42,37,37,37,37, + 37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,42,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,43, + 37,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,37,37,37,38,37,37,37,37,37,37,37,37,37,37,37,37,37,38,37,37,37,37,37,37,37,37,38,38,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,43,43,42, + 42,42,42,42,43,43,42,42,42,37,37,37,37,42,38,42,42,42,37,42,43,37,37,37,42,42,37,37,42,37,37,42,42,42,37,37,37,37,37,37,37,37,43,37,37,37,37,37,37,42,43,43,42,43,37,42,42,45,43,37,37,43,42,42, + 42,42,42,42,42,38,37,37,42,42,46,46,45,45,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,38,37,38,37,37,37,37,38,38,38,37,38,37,37,37,23,23,23,23,23,23,37,16,16,42,37,37,37,21,12,21,12,21,12,21,12,21,12,21,12,21,12,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,38,38,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38, + 37,37,37,37,37,21,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,12,21,12,21,12,21,12,21,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,21,12,21,12,21,12,21,12,21,12,21,12,21,12,21,12,21,12,21,12,21,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,12,21,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,12,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,38,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,37,37,37,37,38,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,37,37,37,37,37,37,37,16,19,19,19,37,16,19, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 23,23,24,25,24,25,23,23,23,24,25,23,24,25,19,19,19,19,19,19,19,19,37,19,21,19,37,37,24,25,37,37,24,25,21,12,21,12,21,12,21,12,19,19,19,19,16,37,19,19,37,19,19,37,37,37,37,37,29,29,19,19,19,37, + 19,19,21,19,19,19,19,19,19,19,19,37,19,37,19,19,37,37,37,16,16,21,14,21,14,21,14,21,14,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,37,37,37,37,37,37,37,37,37,37,37, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 20,13,13,43,43,28,43,43,22,13,22,13,22,13,22,13,22,13,43,43,22,13,22,13,22,13,22,13,28,22,13,13,43,43,43,43,43,43,43,43,43,43,63,63,63,63,63,63,43,43,43,43,43,63,43,43,43,43,43,28,28,43,43,42, + 37,65,43,65,43,65,43,65,43,65,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,65,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,65,43,65,43,65,43,43,43,43,43,43,65,43,43,43,43,43,43,65,65,37,37,63,63,28,28,28,28,43,28,65,43,65,43,65,43,65,43,65,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,65,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,65,43,65,43,65,43,43,43,43,43,43,65,43,43,43,43,43,43,65,65,43,43,43,43,28,65,28,28,43, + 37,37,37,37,37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,37,37,37,37,37,37,37,37,43,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,37,37,37,37,37,37,37,37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,28,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,37,37,37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19, + 37,37,37,37,37,37,37,37,37,37,37,37,37,19,16,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,37,63,63,63,63,63,63,63,63,63,63,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,37,19,19,19,19,19,37,37,37,37,37,37,37,37, + 37,37,63,37,37,37,63,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,48,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,35,35,16,16,37,37,37,37,37,37,37,37, + 63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,37,37,37,37,37,37,37,37,19,19,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,35,37,37,63, + 39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,37,37,37, + 63,63,63,63,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,63,63,63,63,63,63,63,63,63,63,63,63,63, + 60,42,42,42,42,42,42,19,19,19,42,42,42,42,37,19,58,58,58,58,58,58,58,58,58,58,37,37,37,37,42,42,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37, + 19,19,19,63,19,19,19,19,19,19,19,19,63,63,37,37,58,58,58,58,58,58,58,58,58,58,37,37,42,19,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,19,19,37,37,37,63,63,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,19,63,63,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,37,37,37,37,37,37,37,37,37,37,37,37,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, + 51,51,51,51,51,51,51,37,37,37,37,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,37,37,37,37, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,36,63,36,36,36,36,36,36,36,36,36,36,37,36,36,36,36,36,36,36,36,36,36,36,36,36,37,36,36,36,36,36,37,36,37, + 36,36,37,36,36,37,36,36,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,12,21, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,48,37,37,37, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,13,13,13,28,28,17,17,22,13,34,37,37,37,37,37,37,10,63,10,63,10,63,10,10,63,10,63,10,63,10,10,63,43,43,43,43,43,22,13,22,13,22,13,22,13,22,13,22, + 13,22,13,22,13,43,43,22,13,43,43,43,43,43,43,43,13,43,13,37,28,28,17,17,43,22,13,22,13,22,13,43,43,43,43,43,43,43,43,37,43,41,49,43,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,9, + 37,17,43,43,41,49,43,43,22,13,43,43,13,43,13,43,43,43,43,43,43,43,43,43,43,43,28,28,43,43,43,17,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,22,43,13,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,22,43,13,43,22,13,13,22,13,13,28,43,65,65,65,65,65,65,65,65,65,65,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,28,28,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37, + 37,37,43,43,43,43,43,43,37,37,43,43,43,43,43,43,37,37,43,43,43,43,43,43,37,37,43,43,43,37,37,37,49,41,43,43,43,41,41,37,38,38,38,38,38,38,38,37,37,37,37,37,37,37,37,37,37,63,63,63,30,37,37,37, + 19,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,63,63,63,37,63,63,37,37,37,37,37,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,37,37,37,37,63, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,19,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,19,19,19,19,19,19,33,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,19,19, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 63,63,63,55,55,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,60,19,19,42,42,42,42,42,37,37,37,37,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,58,58,58,58,58,58,58,58,58,58,63,56,56,63,63,56,37,37,37,37,37,37,37,37,37,10, + 63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,37,37,39,19,19, + 19,19,63,37,37,37,37,37,37,37,37,37,37,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,39,39,39,39,39,39,39,39,39,39, + 19,19,19,19,37,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,35,37,37,37,37,37,37,37,37,37,37, + 63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,37,37,37,37,19,19,37,19,63,63,63,63,37,63,63,39,39,39,39,39,39,39,39,39,39,37,35,37,19,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,19,19,37,19,19,37,63,37, + 37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 63,63,63,63,37,56,56,56,56,56,56,56,56,37,37,56,56,37,37,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,37,56,56,56,56,56,56,56,37,56,56,37,56,56,56,56,56,37,63,63,19,63,63, + 63,63,63,63,63,37,37,63,63,37,37,63,63,60,37,37,58,37,37,37,37,37,37,63,37,37,37,37,37,19,58,58,56,56,63,63,37,37,63,63,63,63,63,63,63,37,37,37,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37, + 58,58,58,58,58,58,58,58,58,58,37,58,37,37,58,37,58,58,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,37,42,63,63,63,63,63,63,63,63, + 63,37,63,37,37,63,37,63,63,63,63,37,63,63,63,63,60,55,63,42,42,42,37,42,42,37,37,37,37,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,37,37,37,37,19,19,19,19,37,39,39,39,39,39,39,39,39,39,39,19,19,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,37,37,63,63,63,63,63,63,63,63, + 63,35,19,19,16,16,37,37,37,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,35,35,35,35,35,35,35,35,35,35,35,35,35,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37, + 39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,19,19,19,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 56,56,56,56,56,56,56,37,37,56,37,37,56,56,56,56,56,56,56,56,37,56,56,37,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,63,63,63,63,63,63,37,63,63,37,37,63,63,63,60,55, + 63,55,63,63,19,19,19,37,37,37,37,37,37,37,37,37,58,58,58,58,58,58,58,58,58,58,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,37,37,63,63,63,63,63,63,63,37,35,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,37,63,63,63,63,35, + 37,19,19,19,19,35,37,63,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,19,19,19,37,35,35,35,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 35,35,35,35,35,35,35,35,35,35,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,37,63,63,63,63,63,63,63,63, + 37,19,19,19,19,19,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,35,16,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,37,37,37,63,37,63,63,37,63, + 63,63,63,63,63,63,37,63,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,37,63,63,37,63,63,63,63,63,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,19,63,63,63,63,19,19,37,37,37,37,37,37,37, + 63,63,55,63,56,56,56,56,56,56,56,56,56,56,56,56,56,37,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,63,63,63,63,63,63,63,37,37,37,63,63, + 63,63,60,19,19,42,42,42,42,42,42,42,42,42,42,42,58,58,58,58,58,58,58,58,58,58,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,48,48,48,48,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,19,19,19,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,21,21,12,12,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,12,37,37,37,21,12,21,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,12,12,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,10,10,10,10,10,10,10,21,12,10,10,10,21,12,21,12, + 63,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,21,12,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,58,58,58,58,58,58,58,58,58,58,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,19,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,19,19,19,37,37,37,37,37,37, + 37,37,37,37,19,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,28,28,28,28,11,37,37,37,37,37,37,37,37,37,37,37,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,37,37,37,37,37,37,37, + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38, + 43,43,43,43,43,43,43,43,43,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,38,38,38,37,38,38,38,38,38,38,38,37,38,38,37, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,65,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,65,65,65,37,37,65,37,37,37,37,37,37,37,37,37,37,37,37,37,37,65,65,65,65,37,37,37,37,37,37,37,37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,19,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,37,37,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,63,37,37,19,19,19,19,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 63,63,63,63,63,63,63,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,63,63,63,63,63,63,63,37,63,63,37,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37, + 39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,40, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,63,63,63,63,63,63,63,37,37,37,37,37,39,39,39,39,39,39,39,39,39,39,37,37,37,37,21,21,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,48,37,37,37,48,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 42,42,42,42,43,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,44,44,44,44,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42, + 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42, + 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,44,44,44,44,44,44,44,44,44,44,44,44,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,44,44,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42, + 44,42,42,42,42,42,42,42,42,42,42,42,42,42,42,43,44,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,44,44,44,44,44,44,44,44,44,44, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,37,37,38,38,38,38,38,38,38,38,38,38,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 43,43,43,44,44,44,44,44,44,44,44,44,44,44,44,44,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,44,44,44,44, + 43,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,43,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,43,43,43,43,43,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,42,42,42,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,43,42,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,43,43, + 43,43,43,43,43,46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,42,42,42,42,42,42,42,37,37,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,38,38,43,43,43,43,43,38,43,43,43, + 43,43,46,46,46,43,43,46,43,43,46,45,45,42,42,43,43,43,43,43,42,42,42,42,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,42,42,43,42,42,42,43,43,43,47,47,47,47,47, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42, + 43,42,46,46,43,43,46,46,46,46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,43,43,43,46,43,43,43, + 43,46,46,46,43,46,46,46,43,43,43,43,43,43,43,46,43,46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,38,43,38,43,38,43,43,43,43,43,46,43,43,43,43,38,43,38,38,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,42,43, + 38,38,38,38,38,38,38,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,38,38,38,38,38,38,38,38,38,38,38,38,38,38,43,43,43,43,43,43,43,43,43,43,43,43,43,38,38,38,38,38,38,38,38,38,38,38,38,37,37, + 37,37,37,37,37,37,37,37,37,37,42,43,43,43,43,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,42,42,42,42,42,42,42,42,42,42,42,42,45,45,42,42,42,42,46,42,42,42,42,42, + 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,45,42,42,42,42,46,46,42,42,42,42,42,42,42,42,42,42,42,42,42,43,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42, + 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,37,37,37,37,37,37,37,37,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,37,37,37,37,37,37,42,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,46,46,46,43,43,43,46,46,46,46,46,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,23,23,23,27,27,27,37,37,37,37, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46,46,46,43,43,43,43,43,43,43,43,43, + 46,43,43,43,43,43,42,42,42,42,42,42,46,42,42,42,43,43,43,42,42,43,43,43,44,44,44,44,43,43,43,43,42,42,42,42,42,42,42,42,42,42,42,43,43,44,44,44,42,42,42,42,43,43,43,43,43,43,43,43,43,44,44,44, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,42,42,42,44,44,44,44,42,42,42,42,42, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,42,42,42,42,42,44,44,44,44,44,44,43,43,43,43,43,43,43,43,43,43,43,43,44,44,44,44,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 37,37,37,37,37,37,37,37,37,37,37,37,46,43,43,46,43,43,43,43,43,43,43,43,46,46,46,46,46,46,46,46,43,43,43,43,43,43,46,43,43,43,43,43,43,43,43,43,46,46,46,46,46,46,46,46,46,46,43,42,46,46,46,43, + 43,43,43,43,43,43,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,46,46,43,46,46,43,46,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,46,46,46,43,46,46,46,46,46,46,46,46,46,46,46,46,46,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,44,44,44,44,44,44,44,44,44,44,44,44,42,42,42,42,42,42,42,42,42,42,42,42,42,42,44,44,43,43,43,43,43,43,43,43,43,43,43,43,43,44,44,44, + 43,43,43,43,43,43,43,43,43,43,44,44,44,44,44,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,46,46,46,43,44,44,44,44,44,44,44,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,44,44,43,43,43,43,43,43,43,43,43,43,43,44,44,44,44,44,44,46,46,46,46,46,46,46,46,46,44,44,44,44,44,44,44, + 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,37,37, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,37,37, + 37,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, +}; + +KBTS_INLINE kbts_u8 kbts_GetUnicodeLineBreakClass(kbts_u32 Codepoint) +{ + return kbts_UnicodeLineBreakClass_Data[((kbts_un)kbts_UnicodeLineBreakClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; +} + +static kbts_u8 kbts_UnicodeGraphemeBreakClass_PageIndices[8703] = { + 0,1,2,2,2,2,3,2,2,4,2,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,2,2,30,2,2,2,2,2,2,2,31,32,33,34,35,2,36,37,38,39,40,41,2,42,2,2,2,2, + 43,44,45,46,2,2,47,48,2,49,2,50,51,52,53,54,2,2,55,2,2,2,56,2,2,57,58,59,2,2,2,2, + 60,61,2,2,2,62,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,63,64,2,2,65,66,67,68,69,70,2,71,72,73,74,75,76,77,78,79, + 73,74,75,76,77,78,79,73,74,75,76,77,78,79,73,74,75,76,77,78,79,73,74,75,76,77,78,79,73,74,75,76, + 77,78,79,73,74,75,76,77,78,79,73,74,75,76,77,78,79,73,74,75,76,77,78,79,73,74,75,76,77,78,79,73, + 74,75,76,77,78,79,73,74,75,76,77,78,79,73,74,80,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,81,2,2,2,2,2,82,83,2,84, + 2,2,2,85,2,86,87,2,2,2,2,2,2,2,2,2,2,2,2,2,88,89,2,2,2,2,90,2,2,91,92,93, + 94,95,96,97,98,99,100,101,102,103,2,104,105,106,107,2,108,2,109,110,111,112,2,2,113,114,115,116,2,117,118,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,119,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,120,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,121,122,2,2,2,123,2,2,2,124,125, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,126,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,127,2, + 2,2,128,129,130,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,131,132,2,2,2,2,2,2,2,2,2,2, + 133,134,122,2,2,135,2,2,2,136,2,137,2,2,2,2,2,138,139,2,2,2,2,2,2,2,2,2,2,2,2,2, + 140,140,141,142,143,140,140,144,140,140,145,140,146,140,147,148,149,150,151,140,140,140,2,2,140,140,140,140,140,140,140,152, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 153,154,155,156,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +}; + +static kbts_u8 kbts_UnicodeGraphemeBreakClass_Data[20096] = { + 3,3,3,3,3,3,3,3,3,3,2,0,3,1,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,16,0,0,0,3,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,14, + 0,14,14,0,14,14,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 12,12,12,12,12,12,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,12,0,14,14,14,14,14,14,0,0,14,14,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,14,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,0,14,14,14,14,14,14,14,14,14,0,14,14,14,0,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,12,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,6,14,0,6,6, + 6,14,14,14,14,14,14,14,14,6,6,6,6,15,6,6,0,14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,13,13,13,13,13,13,13, + 0,14,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,0,13,13,13,13,13,13,13,0,13,0,0,0,13,13,13,13,0,0,14,0,14,6, + 6,14,14,14,14,0,0,6,6,0,0,6,6,15,0,0,0,0,0,0,0,0,0,14,0,0,0,0,13,13,0,13,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,13,13,0,0,0,0,0,0,0,0,0,0,0,0,14,0, + 0,14,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,6,6, + 6,14,14,0,0,0,0,14,14,0,0,14,14,14,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,14,0,0,0,0,0,0,0,0,0,0, + 0,14,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,0,13,13,13,13,13,13,13,0,13,13,0,13,13,13,13,13,0,0,14,0,6,6, + 6,14,14,14,14,14,0,14,14,6,0,6,6,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,14,14,14,14,14,14, + 0,14,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,0,13,13,13,13,13,13,13,0,13,13,0,13,13,13,13,13,0,0,14,0,14,14, + 6,14,14,14,14,0,0,6,6,0,0,6,6,15,0,0,0,0,0,0,0,14,14,14,0,0,0,0,13,13,0,13,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6, + 14,6,6,0,0,0,6,6,6,0,6,6,6,14,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,6,6,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,0,0,14,0,14,14, + 14,6,6,6,6,0,14,14,14,0,14,14,14,15,0,0,0,0,0,0,0,14,14,0,13,13,13,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,14,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,6,14, + 14,6,14,6,6,0,14,14,14,0,14,14,14,14,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,0,14,6, + 6,14,14,14,14,0,6,6,6,0,6,6,6,15,12,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,14,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,14,6,6,14,14,14,0,14,0,6,6,6,6,6,6,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,6,14,14,14,14,14,14,14,0,0,0,0,0, + 0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,6,14,14,14,14,14,14,14,14,14,0,0,0, + 0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,14,0,14,0,0,0,0,6,6, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,6, + 14,14,14,14,14,0,14,14,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0, + 0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,6,14,14,14,14,14,14,0,14,14,6,6,14,14,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,14,14,0,0,0,0,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0, + 0,0,14,0,6,14,14,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,6,14,14,14,14,14,14,14,6,6, + 6,6,6,6,6,6,14,6,6,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,14,14,14,3,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,6,6,6,6,14,14,6,6,6,0,0,0,0,6,6,14,6,6,6,6,6,6,14,14,14,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,6,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,14,6,14,14,14,14,14,14,14,0,14,0,14,0,0,14,14,14,14,14,14,14,14,6,6,6,6,6,6,14,14,14,14,14,14,14,14,14,14,0,0,14, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,14,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,6,6, + 6,6,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,14,14,14,14,6,6,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6,14,14,6,6,6,14,6,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,14,14,14,14,14,14,14,14,6,6,14,14,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,0,14,14,14,14,14,14,14,14,14,14,14,14,14,6,14,14,14,14,14,14,14,0,0,0,0,14,0,0,0,0,0,0,14,0,0,6,14,14,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 0,0,0,0,0,0,0,0,0,0,0,3,4,5,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0, + 0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0, + 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,0, + 16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,0,16,0,16,0,0,0,0,0,0,16,0,0,0,16,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,16,0,0,16,0,0,0,0,16,0,16,0,0,0,0,16,16,16,0,16,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,16,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,0,14,14,14,14,14,14,14,14,14,14,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,14,0,0,0,14,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,14,14,6,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,14, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,6,14,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0, + 14,14,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6,6,14,14,14,14,6,6,14,14,6,6, + 14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,6,6,14,14,6,6,14,14,0,0,0,0,0,0,0,0,0, + 0,0,0,14,0,0,0,0,0,0,0,0,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,14,14,14,0,0,14,14,0,0,0,0,0,14,14, + 0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,14,14,6,6,0,0,0,0,0,6,14,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,14,6,6,14,6,6,0,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,9,0,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0,0,0,0,0,0,0,0,0,0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,0,0,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,0,3,3,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,0,0,0,0,0, + 0,14,14,14,0,14,14,0,0,0,0,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,0,0,0,0,14, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 6,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,14,14,0,0,0,0,0,0,0,0,0,0,14, + 14,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,14,14,14,14,6,6,14,14,0,0,12,0,0, + 0,0,14,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,6,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,14,14,14,14,14,14,14,14,14,6, + 14,0,12,12,0,0,0,0,0,14,14,14,14,0,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,14,14,14,6,6,14,14,14,14,0,0,0,0,0,0,14,0, + 0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6,6,6,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,14,6, + 14,6,6,6,6,0,0,6,6,0,0,6,6,14,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,6,6,0,0,14,14,14,14,14,14,14,0,0,0,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6,6,14,14,14,14,14, + 14,0,14,0,0,14,0,14,14,14,6,0,6,6,14,14,14,12,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,14,14,14,14,14,14,14,14, + 6,6,14,14,14,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6,6,14,14,14,14,14,14,6,14,6,6,14,6,14, + 14,6,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6,6,14,14,14,14,0,0,6,6,6,6,14,14,6,14, + 14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,14,14,14,14,14,14,14,14,6,6,14,6,14, + 14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6,14,6,6,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6,14,0,0,14,14,14,14,6,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,14,14,14,14,14,14,14,14,14,6,14,14,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,6,6,6,6,6,0,6,6,0,0,14,14,14,14,12, + 6,12,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,14,14,14,14,0,0,14,14,6,6,6,6,14,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,6,12,14,14,14,14,0, + 0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,6,6,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,12,12,12,12,12,12,14,14,14,14,14,14,14,14,14,14,14,14,14,6,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,14,14,14,14,14,14,14,0,14,14,14,14,14,14,6,14, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,6,14,14,14,14,14,14,14,6,14,14,6,14,14,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,0,0,0,14,0,14,14,0,14, + 14,14,14,14,14,14,12,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,0,14,14,0,6,6,14,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,6,6,0,0,0,0,0,0,0,0,0, + 14,14,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,14,14,14,14,14,0,0,0,6,6, + 14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 14,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,6,6,6,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,8,8,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,0,0,0,0,0,0,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,0,0,0,14,14,14,14,14,14,3,3,3,3,3,3,3,3,14,14,14,14,14, + 14,14,14,0,0,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 14,14,14,14,14,14,14,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,14,14,14,14,14,14,14,0,14,14,0,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,16,16,16,16,16,16,16,16,16,0,16,16,16,16, + 0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,14,14,14,14,14, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0, + 0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16, + 16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0, + 3,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +}; + +KBTS_INLINE kbts_u8 kbts_GetUnicodeGraphemeBreakClass(kbts_u32 Codepoint) +{ + return kbts_UnicodeGraphemeBreakClass_Data[((kbts_un)kbts_UnicodeGraphemeBreakClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; +} + +static kbts_u8 kbts_UnicodeSyllabicInfo_PageIndices[8703] = { + 0,1,2,2,2,2,2,2,2,2,2,2,2,2,2,3,4,2,5,6,7,8,9,10,11,12,13,14,15,16,17,18, + 19,20,2,2,2,2,2,2,2,2,2,2,2,2,21,22,23,24,25,26,27,28,29,30,31,32,2,33,2,2,2,2, + 34,35,2,2,2,2,2,2,2,2,2,36,2,2,2,2,2,2,2,2,2,2,2,2,2,2,37,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,38,39,40,41,42,43,2,44,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,45,2,2,2, + 2,2,2,2,2,2,2,2,2,2,46,47,2,2,2,2,2,2,2,2,48,49,2,2,2,2,50,51,2,52,53,54, + 55,56,57,58,59,60,61,62,63,64,2,65,66,67,68,2,69,2,70,71,72,73,2,2,74,75,76,77,2,78,79,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,80,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,81,82,2,2,2,83,2,2,2,84,85, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,86,86,86,87,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,88,89,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,90,2,2,91,2,2,2,92,2,93,2,2,2,2,2,2,94,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +}; + +static kbts_u16 kbts_UnicodeSyllabicInfo_Data[12160] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,1034,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3592,3592,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1034,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,3,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3,3,3,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,3592,3592,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1039,1025,1025,1025,1025,1025,1025,1025,1025,1025,2311,2311,2307,3601,2311,519, + 2311,2311,2311,2311,2311,2311,2311,2311,2311,2311,2311,2311,2311,2308,519,2311,0,3593,3593,3592,3592,2311,2311,2311,1025,1025,1025,1025,1025,1025,1025,1025, + 1026,1026,2311,2311,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025, + 1034,3592,3592,3592,0,1026,1026,1026,1026,1026,1026,1026,1026,0,0,1026,1026,0,0,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1039,0,1025,0,0,0,1025,1025,1025,1025,0,0,2307,3601,3079,519, + 3079,2311,2311,2311,2311,0,0,519,519,0,0,3079,3079,2308,1025,0,0,0,0,0,0,0,0,3079,0,0,0,0,1025,1025,0,1025, + 1026,1026,2311,2311,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1025,1025,0,0,0,0,0,0,0,0,0,0,1034,0,3592,0, + 0,3592,3592,3592,0,1026,1026,1026,1026,1026,1026,0,0,0,0,1026,1026,0,0,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1039,0,1025,1025,0,1025,1025,0,1025,1025,0,0,3075,0,3079,519, + 3085,3079,3079,0,0,0,0,3079,3079,0,0,3079,3079,3076,0,0,0,2055,0,0,0,0,0,0,0,1025,1025,1025,1025,0,1025,0, + 0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,3592,3592,1025,1025,0,1040,0,0,0,0,0,0,0,0,0,0, + 0,3592,3592,3592,0,1026,1026,1026,1026,1026,1026,1026,1026,1026,0,1026,1026,1026,0,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1039,0,1025,1025,0,1025,1025,1025,1025,1025,0,0,3075,3601,3079,519, + 3079,3079,3079,3079,3079,2311,0,2311,2311,3079,0,3079,3079,3076,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,3079,3079,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,1025,3593,2307,3593,2307,2307,2307, + 0,1800,3592,3592,0,1026,1026,1026,1026,1026,1026,1026,1026,0,0,1026,1026,0,0,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1039,0,1025,1025,0,1025,1025,1025,1025,1025,0,0,2307,3601,3079,1287, + 3079,2311,2311,2311,2311,0,0,519,1287,0,0,3079,3079,2308,0,0,0,0,0,0,0,1283,1287,3079,0,0,0,0,1025,1025,0,1025, + 1026,1026,2311,2311,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,3592,0,0,1026,1026,1026,1026,1026,1026,0,0,0,1026,1026,1026,0,1026,1026,1026,1025,0,0,0,1025,1025,0,1025,0,1025,1025, + 0,0,0,1025,1025,0,0,0,1025,1025,1025,0,0,0,1025,1025,1039,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,3079,3079, + 2311,3079,3079,0,0,0,519,519,519,0,3079,3079,3079,2308,0,0,0,0,0,0,0,0,0,3079,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,3592,3592,3592,1026,1026,1026,1026,1026,1026,1026,1026,0,1026,1026,1026,0,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1039,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,1795,3601,1799,1799, + 1799,1799,1799,2311,2311,0,1799,1799,1799,0,1799,1799,1799,1796,0,0,0,0,0,0,0,1799,1799,0,1025,1025,1025,0,0,1025,0,0, + 1026,1026,1799,1799,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1034,3592,3592,3592,0,1026,1026,1026,1026,1026,1026,1026,1026,0,1026,1026,1026,0,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1039,1025,1025,1025,0,1025,1025,1025,1025,1025,0,0,1795,3601,1799,1799, + 1799,1799,1799,2311,2311,0,1799,2311,2311,0,2311,2311,1799,1796,0,0,0,0,0,0,0,2311,2311,0,0,0,0,0,0,1025,1025,0, + 1026,1026,1799,1799,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,1042,1042,3592,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,3592,3592,1034,1026,1026,1026,1026,1026,1026,1026,1026,0,1026,1026,1026,0,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1039,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,3601,3079,3079, + 3079,3079,3079,3079,3079,0,519,519,519,0,3079,3079,3079,4,14,0,0,0,0,0,1025,1025,1025,3079,0,0,0,0,0,0,0,1026, + 1026,1026,3079,3079,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025, + 0,3592,3592,3592,0,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,0,0,0,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,0,0, + 1025,1025,1025,1025,1025,1025,1025,0,0,0,2308,0,0,0,0,2311,2311,2311,2311,2311,2311,0,2311,0,2311,519,2311,519,2311,2311,2311,2311, + 0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,2311,2311,0,0,0,0,0,0,0,0,0,0,0,0, + 0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0, + 519,519,519,519,519,7,0,7,3,3,3,3,7,3592,7,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,1025,1025,0,1025,0,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,0,1025,0,1025,1025,1025,1025,1025,1025,1025,1025,0,7,7,7,7,7,7,7,7,7,7,7,7,1040,1040,0,0, + 519,519,519,519,519,0,0,0,3,3,3,3,0,3592,3592,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,1025,1025,1025,1025, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,0,0,1025,1025,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,3592,0,3592,0,3,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,3,7,7,7,7,7,7,7,7,7,7,7,7,3592,1025, + 7,7,3592,3592,7,3601,3,3,1025,1025,1025,1025,1025,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,0,1040,1040,1040,1040,1040,1040,1040, + 1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,0,0,0, + 0,0,0,0,0,0,3592,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1039,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1039,1025,1025,1025,1025, + 1025,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,23,23,20,20,21,21,22,3593,20,20,20,3593,3,1034,4,27,33,31,32,30,1025, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,1025,0,1025,1025,1026,1026,1026,1026,23,23,21,21,1039,1025,1025,1025,33,33, + 36,1025,23,34,34,1025,1025,23,23,34,34,34,34,34,1025,1025,1025,20,20,20,20,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,32,23,22,20,20,1034,1034,1034,1034,1034,1034,1034,1025,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,20,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,0,0,0,0,0,0,0,0,0,1025, + 1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1039,1025,1025,1025,1025,1025, + 1025,1025,1025,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,0,0,23,20,20,20,20,21,21,21,20,23, + 23,22,22,22,23,23,25,25,25,24,24,25,24,25,25,25,25,25,4,25,0,0,0,0,0,1034,0,0,3601,25,0,0, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,0,0,0,0,0,0,1025,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0, + 1034,1034,1034,1034,1034,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1034,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0, + 7,7,7,7,7,7,7,7,7,1040,1040,1040,0,0,0,0,1040,1040,3592,1040,1040,1040,1040,1040,1040,1040,3592,3592,0,0,0,0, + 0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,7,7,7,7,7,519,519,519,7,7,519,7,7,7,7,7, + 7,1025,1025,1025,1025,1025,1025,1025,3,3,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1026,1026,1026,1026,1026,1026,1025,1025,1040,1040,1040,1040,1040,1025,1040,1040,1040,1040,0, + 4,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3592,3,3,3,3,3,7,3,3,0,0,3, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,3592,1040,3592,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,4,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,1040,3592,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1040,1040,1040,7,7,7,7,7,7,7,4,1040,1040,1025,1025,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,3601,1025,1025,1025,1040,1040, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1026,1026,3,7,7,7,7,7,7,7,7,7,1040,1040,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1040,1040,7,7,7,7,7,7,7,1040,1040,1040,1040,1040,1040,1040,3592,3592,0,3,0,0,0,0,0,0,0,0, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,1025,1025,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3593,3593,3593,0,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593, + 3593,3593,3593,3593,3593,3593,3593,3593,3593,3601,3601,3601,3601,3593,3601,3601,3601,3601,1025,1025,3593,1025,1025,3593,3593,3593,1034,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3592,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,5,6,0,0,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0, + 0,0,1034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3592,0,0,0,0,0,0,0,0,0,0,0, + 0,0,3592,3592,3592,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3593,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,1035,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1034,1034,1034,1034,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, + 1026,1026,7,1026,1026,1026,4,1025,1025,1025,1025,3592,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,7,7,7,7,7,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1026,1026, + 1026,1026,1025,1025,1025,1025,1026,1040,1040,1025,1025,1025,1025,1025,1025,1025,1025,1040,1025,3592,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1040,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,4,3592,0,0,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3593,3601,3601,3601,3601,3601,3601,0,0,0,0,0,0,1026,2311, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1026,1026,1026,1026,1026,1026,1026,1026,1026,3,3,3,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,1040,1040,1040,1040,7,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,1040,3592,1026,1026,1026,1026,1026,1025,1025,1025,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3,7,7,7,7,7,7,7,7,7,1040,1040,1040, + 4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,20,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1025,1025,1025,1025,1025,0, + 1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,3592,7,7,7,7,7,7,7,7,7,1040,1040,1040,1040,0,0,0,0,0,0,0,0,0, + 1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1034,1034,1034,0,0,0,1025,34,3,3,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,1026,7,7,7,519,519,7,7,519,1026,519,519,1026,7,3, + 0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,0,0,0,0,0,3592,4,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1026,1026,1025,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1040,1040,1040,1040,1040, + 1040,1040,1040,7,7,7,7,7,7,7,7,0,3,7,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1287,7,7,0,7,1287,0,0,0,0,0,7,3592,3592,3592,1025,1025,1025,1025,0,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,3,3,3,0,0,0,0,4, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,3,3,3,3592,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,0,0,0,7,7,7,7,7,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,7,7,0,0,0,1025,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,3,3,3,3,3,3,3,3,3,3,3,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,3592,1042,1042,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,4,0,0,0,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,7,1026,1026,7,7,1025,0,0,0,0,0,0,0,0,0,1034, + 3592,3592,3592,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,7,4,3,0,0,0,0,0, + 0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,3592,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,7,7,7,7,4,3592,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034, + 0,0,0,0,1025,7,7,1025,0,0,0,0,0,0,0,0,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,3592,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,7,7,7,7,7, + 4,3601,0,0,0,0,0,0,0,3592,3,7,7,0,7,3592,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1025,0,0,0,0,0, + 0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,3592,4,3,3592,0,0,0,0,0,0,3593,1025, + 1026,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1025,1025,1025,0,1025,0,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3592, + 7,7,7,7,7,7,7,7,7,3,7,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 3592,3592,3592,3592,0,1026,1026,1026,1026,1026,1026,1026,1026,0,0,1026,1026,0,0,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,0,1025,1025,1025,1025,1025,0,3,3,3601,7,7, + 7,7,7,7,7,0,0,7,7,0,0,7,7,4,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,3592,3592, + 1026,1026,7,7,0,0,3593,3593,3593,3593,3593,3593,3593,0,0,0,3593,3593,3593,3593,3593,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,0,1026,0,0,1026,0,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,3601,7,7,7,7,7,7,7,7, + 7,0,7,0,0,7,0,7,7,7,3592,0,3592,3592,3592,3,4,14,3592,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,3593,3593,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,7,7,7, + 7,7,4,3592,3592,3592,3,3601,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,3592,3592, + 1042,1042,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,3592, + 3592,3592,4,3,3601,0,0,0,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,0,0,7,7,7,7,3592,3592,3592,4, + 3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1026,1026,1026,1026,7,7,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,7,7,7,7,7,3592,3592,4, + 7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3592,3592,7,7,7,7,7,7,7,7,7,4,3,1025,0,0,0,0,0,0,0, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034, + 1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,1040,1040,1040, + 7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,7,7,7,3592,3592,4,3,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,0,0,1026,0,0,1025,1025,1025,1025,1025,1025,1025,1025,0,1025,1025,0,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,0,7,7,0,0,3592,3592,7,4,0, + 1040,14,1040,3,0,0,0,0,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,1026,0,0,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,0,0,7,7,7,7,3592,3592, + 4,3601,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,7,7,7,7,7,7,7,7,7,7,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3592,7,3592,3592,3592,3592,3592,1042,1040,1040,1040,1040,1034, + 0,0,0,0,0,1034,0,4,0,0,0,0,0,0,0,0,1026,7,7,7,7,7,7,7,7,7,7,7,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,0,0,0,0,0,0,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,3592,3592,3592,4,0,0,0,3601,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,1026,1026,0,1026,1026,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,7,0,7,7,7,7,3592,3592,3592,4, + 3601,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040, + 1040,1040,1040,1040,1040,1040,1040,1040,0,1040,1040,1040,1040,1040,1040,1040,7,7,7,7,7,3592,3592,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,1026,0,1026,1026,0,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,0,0,0,7,0,7,7,0,7, + 3592,3592,3,7,7,4,14,1040,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 1026,1026,1026,1026,1026,1026,0,1026,1026,0,1026,1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,0,7,7,0,7,7,3592,3592,4,0,0,0,0,0,0,0,0, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1034,7,7,7,7,0,0,0,0,0,0,0,0,0, + 3592,3592,14,3592,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,7,7,7,0,0,0,7,7, + 7,7,4,0,0,0,0,0,0,0,0,0,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,3,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1026,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7, + 7,7,7,7,7,7,7,7,7,7,1040,1040,1040,3592,1040,7,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3592,3592,3592,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,7,7,7,7,7,7,7,7,7,7,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,3,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,1283,1283,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,0,0,0,3,3,3,3,3,3,3,1025,1025,1025,1025,1025,1025,1025,0,0, + 1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,1025,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,3,3,3,3,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,7,7,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,7,7,1025,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025, + 1025,1025,1025,1025,3,3,3,3,3,3,3,1025,0,0,0,0,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +KBTS_INLINE kbts_u16 kbts_GetUnicodeSyllabicInfo(kbts_u32 Codepoint) +{ + return kbts_UnicodeSyllabicInfo_Data[((kbts_un)kbts_UnicodeSyllabicInfo_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; +} + +static kbts_u8 kbts_UnicodeScript_PageIndices[8703] = { + 0,1,2,2,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,32,33,34,35,36,37,37,37,37,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,2,2,53,54, + 55,56,57,58,59,59,59,59,60,59,59,59,59,59,59,59,61,61,59,59,59,59,62,63,64,65,66,67,68,61,61,69, + 70,71,72,73,74,75,76,59,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,77,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 78,78,78,78,78,78,78,78,78,79,80,80,81,82,83,84,85,86,87,88,89,90,91,92,32,32,32,32,32,32,32,32, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,93,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,94,95,96,96,97,98,99,100,101,102, + 103,104,105,106,61,107,108,109,110,111,112,113,114,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132, + 133,134,135,136,137,138,139,140,141,142,61,143,144,145,146,61,147,148,149,150,151,152,153,154,155,156,157,158,61,159,160,161, + 162,162,162,162,162,162,162,163,164,162,165,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,166, + 167,167,167,167,167,167,167,167,168,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, + 167,167,167,167,167,167,167,169,170,170,170,170,171,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,172,61,61,61,61,61,61,61,61,61,61,61,61,61,173,173,173,173,174,175,176,177,61,61,178,61,179,180,181,182, + 183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, + 183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,184,183,183,183,183,183,183,185,185,185,186,187,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,188, + 189,190,191,192,192,193,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,194,195,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,59,196,59,59,59,197,198,199, + 59,200,201,202,203,204,205,61,206,207,208,59,59,209,59,210,211,211,211,211,211,212,61,61,61,61,61,61,61,61,213,61, + 214,215,216,61,61,217,61,61,61,218,61,219,61,61,61,220,221,222,223,61,61,61,61,61,224,225,226,61,227,228,61,61, + 229,230,59,231,232,61,59,59,59,59,59,59,59,233,234,235,236,237,59,59,238,239,59,240,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 241,61,242,243,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, +}; + +static kbts_u8 kbts_UnicodeScript_Data[31232] = { + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,29,29,29,29,29, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,72,72,72,72,29,29,29,29,29,13,13,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,45,45,45,45,29,45,45,45,0,0,45,45,45,45,29,45, + 0,0,0,0,45,29,45,29,45,45,45,0,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, + 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,25,25,25,25,25,25,25,25,25,25,25,25,25,25,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,30,30,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,0,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,0,0,0,0,0,0,0,0,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,0,0,0,0,54,54,54,54,54,54,0,0,0,0,0,0,0,0,0,0,0, + 4,4,4,4,4,29,4,4,4,4,4,4,29,4,4,4,4,4,4,4,4,4,4,4,4,4,4,29,4,4,4,29,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 29,4,4,4,4,4,4,4,4,4,4,30,30,30,30,30,30,30,30,30,30,30,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,30,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,29,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 143,143,143,143,143,143,143,143,143,143,143,143,143,143,0,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, + 143,143,143,143,143,143,143,143,143,143,143,0,0,143,143,143,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,0,0,103,103,103, + 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,0,0,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,0, + 83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,0,0,83,0,143,143,143,143,143,143,143,143,143,143,143,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,29,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,30,30,30,30,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,29,29,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 11,11,11,11,0,11,11,11,11,11,11,11,11,0,0,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,0,11,0,0,0,11,11,11,11,0,0,11,11,11,11, + 11,11,11,11,11,0,0,11,11,0,0,11,11,11,11,0,0,0,0,0,0,0,0,11,0,0,0,0,11,11,0,11,11,11,11,11,0,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0, + 0,48,48,48,0,48,48,48,48,48,48,0,0,0,0,48,48,0,0,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,0,48,48,48,48,48,48,48,0,48,48,0,48,48,0,48,48,0,0,48,0,48,48, + 48,48,48,0,0,0,0,48,48,0,0,48,48,48,0,0,0,48,0,0,0,0,0,0,0,48,48,48,48,0,48,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0, + 0,46,46,46,0,46,46,46,46,46,46,46,46,46,0,46,46,46,0,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,0,46,46,46,46,46,46,46,0,46,46,0,46,46,46,46,46,0,0,46,46,46,46, + 46,46,46,46,46,46,0,46,46,46,0,46,46,46,0,0,46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46,46,46,46,0,0,46,46,46,46,46,46,46,46,46,46,46,46,0,0,0,0,0,0,0,46,46,46,46,46,46,46, + 0,118,118,118,0,118,118,118,118,118,118,118,118,0,0,118,118,0,0,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,0,118,118,118,118,118,118,118,0,118,118,0,118,118,118,118,118,0,0,118,118,118,118, + 118,118,118,118,118,0,0,118,118,0,0,118,118,118,0,0,0,0,0,0,0,118,118,118,0,0,0,0,118,118,0,118,118,118,118,118,0,0,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,0,0,0,0,0,0,0,0, + 0,0,150,150,0,150,150,150,150,150,150,0,0,0,150,150,150,0,150,150,150,150,0,0,0,150,150,0,150,0,150,150,0,0,0,150,150,0,0,0,150,150,150,0,0,0,150,150,150,150,150,150,150,150,150,150,150,150,0,0,0,0,150,150, + 150,150,150,0,0,0,150,150,150,0,150,150,150,150,0,0,150,0,0,0,0,0,0,150,0,0,0,0,0,0,0,0,0,0,0,0,0,0,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,0,0,0,0,0, + 153,153,153,153,153,153,153,153,153,153,153,153,153,0,153,153,153,0,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,0,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,0,0,153,153,153,153, + 153,153,153,153,153,0,153,153,153,0,153,153,153,153,0,0,0,0,0,0,0,153,153,0,153,153,153,0,0,153,0,0,153,153,153,153,0,0,153,153,153,153,153,153,153,153,153,153,0,0,0,0,0,0,0,153,153,153,153,153,153,153,153,153, + 61,61,61,61,61,61,61,61,61,61,61,61,61,0,61,61,61,0,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,0,61,61,61,61,61,61,61,61,61,61,0,61,61,61,61,61,0,0,61,61,61,61, + 61,61,61,61,61,0,61,61,61,0,61,61,61,61,0,0,0,0,0,0,0,61,61,0,0,0,0,0,0,61,61,0,61,61,61,61,0,0,61,61,61,61,61,61,61,61,61,61,0,61,61,61,0,0,0,0,0,0,0,0,0,0,0,0, + 82,82,82,82,82,82,82,82,82,82,82,82,82,0,82,82,82,0,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, + 82,82,82,82,82,0,82,82,82,0,82,82,82,82,82,82,0,0,0,0,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,0,0,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, + 0,136,136,136,0,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,0,0,0,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,0,136,136,136,136,136,136,136,136,136,0,136,0,0, + 136,136,136,136,136,136,136,0,0,0,136,0,0,0,0,136,136,136,136,136,136,0,136,0,136,136,136,136,136,136,136,136,0,0,0,0,0,0,136,136,136,136,136,136,136,136,136,136,0,0,136,136,136,0,0,0,0,0,0,0,0,0,0,0, + 0,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,0,0,0,0,29, + 155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,71,71,0,71,0,71,71,71,71,71,0,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,0,71,0,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,0,0, + 71,71,71,71,71,0,71,0,71,71,71,71,71,71,71,0,71,71,71,71,71,71,71,71,71,71,0,0,71,71,71,71,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, + 156,156,156,156,156,156,156,156,0,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,0,0,0,0,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, + 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,0,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,0,156,156, + 156,156,156,156,156,156,156,156,156,156,156,156,156,0,156,156,156,156,156,156,156,29,29,29,29,156,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, + 41,41,41,41,41,41,0,41,0,0,0,0,0,41,0,0,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,29,41,41,41,41, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, + 39,39,39,39,39,39,39,39,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,0,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, + 39,39,39,39,39,39,39,39,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,0, + 39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, + 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, + 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,0,0, + 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,0,0,0,0,0,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,0,0,22,22,22,22,22,22,0,0, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,0,0,0,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,29,29,29,128,128,128,128,128,128,128,128,128,128,128,0,0,0,0,0,0,0, + 144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,0,0,0,0,0,0,0,0,0,144,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,29,29,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,145,145,145,145,145,145,145,145,145,145,145,145,145,0,145,145,145,0,145,145,0,0,0,0,0,0,0,0,0,0,0,0, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,0,0,67,67,67,67,67,67,67,67,67,67,0,0,0,0,0,0,67,67,67,67,67,67,67,67,67,67,0,0,0,0,0,0, + 94,94,29,29,94,29,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,0,0,0,0,0,0,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94, + 94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,0,0,0,0,0,0,0, + 94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,0,0,0,0,0,0,0,0,0,0, + 74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,0,74,74,74,74,74,74,74,74,74,74,74,74,0,0,0,0,74,74,74,74,74,74,74,74,74,74,74,74,0,0,0,0, + 74,0,0,0,74,74,74,74,74,74,74,74,74,74,74,74,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,0,0,146,146,146,146,146,0,0,0,0,0,0,0,0,0,0,0, + 102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,0,0,0,0,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, + 102,102,102,102,102,102,102,102,102,102,0,0,0,0,0,0,102,102,102,102,102,102,102,102,102,102,102,0,0,0,102,102,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,0,0,15,15,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, + 147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,0,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,0,0,147, + 147,147,147,147,147,147,147,147,147,147,0,0,0,0,0,0,147,147,147,147,147,147,147,147,147,147,0,0,0,0,0,0,147,147,147,147,147,147,147,147,147,147,147,147,147,147,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, + 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,0,0,0,0,0,0,0,0,10,10,10,10, + 73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,0,0,0,73,73,73,73,73, + 73,73,73,73,73,73,73,73,73,73,0,0,0,73,73,73,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, + 28,28,28,28,28,28,28,28,28,28,28,0,0,0,0,0,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,0,0,41,41,41, + 140,140,140,140,140,140,140,140,0,0,0,0,0,0,0,0,30,30,30,29,30,30,30,30,30,30,30,30,30,30,30,30,30,29,30,30,30,30,30,30,30,29,29,29,29,30,29,29,29,29,29,29,30,29,29,29,30,30,29,0,0,0,0,0, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,45,45,45,45,45,28,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,45,45,45,45,45,72,72,72,72,45,45,45,45,45,72,72,72,72,72,72,72,72,72,72,72,72,72,28,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,45, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, + 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,0,45,45,45,45,45,45,0,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, + 45,45,45,45,45,45,0,0,45,45,45,45,45,45,0,0,45,45,45,45,45,45,45,45,0,45,0,45,0,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,0, + 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,45,45,45,45,45,45,45,45,45,45, + 45,45,45,45,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,0,45,45,45,45,45,45,0,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,0,45,45,45,0,45,45,45,45,45,45,45,45,45,0, + 29,29,29,29,29,29,29,29,29,29,29,29,30,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,72,0,0,29,29,29,29,29,29,29,29,29,29,29,72, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,72,72,72,72,72,72,72,72,72,72,72,72,72,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,45,29,29,29,72,72,29,29,29,29,29,29,72,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42, + 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, + 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,0,0,0,0,0,25,25,25,25,25,25,25, + 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,0,41,0,0,0,0,0,41,0,0,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, + 157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,0,0,0,0,0,0,0,157,157,0,0,0,0,0,0,0,0,0,0,0,0,0,0,157, + 39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0,0,0,0,0,0,0,0,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0, + 39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,0,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,30,30,30,30,50,50,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29, + 0,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, + 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,0,0,30,30,29,29,55,55,55,29,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, + 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,29,29,62,62,62, + 0,0,0,0,0,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,0,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,29,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,29, + 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, + 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, + 168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, + 168,168,168,168,168,168,168,168,168,168,168,168,168,0,0,0,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, + 168,168,168,168,168,168,168,0,0,0,0,0,0,0,0,0,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, + 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, + 163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,0,0,72,72,0,72,0,72,72,72,72,72,72,72,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,0,0,0,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0, + 124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,0,0,0,0,0,0,0,0, + 130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, + 130,130,130,130,130,130,0,0,0,0,0,0,0,0,130,130,130,130,130,130,130,130,130,130,130,130,0,0,0,0,0,0,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,29,64,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, + 127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,0,0,0,0,0,0,0,0,0,0,0,127,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0, + 59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59, + 59,59,59,59,59,59,59,59,59,59,59,59,59,59,0,29,59,59,59,59,59,59,59,59,59,59,0,0,0,0,59,59,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,0, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,0,0,0,0,0,0,0,0,0, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,0,0,21,21,21,21,21,21,21,21,21,21,0,0,21,21,21,21,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, + 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, + 148,148,148,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,148,148,148,148,148,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,0,0,0,0,0,0,0,0,0, + 0,39,39,39,39,39,39,0,0,39,39,39,39,39,39,0,0,39,39,39,39,39,39,0,0,0,0,0,0,0,0,0,39,39,39,39,39,39,39,0,39,39,39,39,39,39,39,0,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,72,72,72,72,72,72,72,72,72,45,72,72,72,72,29,29,0,0,0,0,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,0,0,88,88,88,88,88,88,88,88,88,88,0,0,0,0,0,0, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0,0,0,0,0,0,0,0,0,0,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,0,0,0,0,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0,0,0,0, + 72,72,72,72,72,72,72,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,0,0,0,0,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,0,54,54,54,54,54,0,54,0, + 54,54,0,54,54,0,54,54,54,54,54,54,54,54,54,54,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,29,29, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,0,0,0,0,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,29, + 0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29, + 29,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,29,29,29,29,29,29,29,29,29,29,29,62,62,62,62,62,62,62,62,62,62,29,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, + 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,29,29,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,0, + 0,0,50,50,50,50,50,50,0,0,50,50,50,50,50,50,0,0,50,50,50,50,50,50,0,0,50,50,50,0,0,0,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,0,0, + 76,76,76,76,76,76,76,76,76,76,76,76,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,76,76,0,76, + 76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, + 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,0,0,0,0,0, + 29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,29,29,29,29,29,29,29,29,29, + 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, + 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,0,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,0,0, + 78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,0,0,0,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0, + 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,0,0,0,0,0,0,0,0,0,109,109,109,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,43,43,43,0,0,0,0,0,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,0,0,0,0,0, + 162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,0,162,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, + 113,113,113,113,0,0,0,0,113,113,113,113,113,113,113,113,113,113,113,113,113,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31, + 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, + 120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,0,0,120,120,120,120,120,120,120,120,120,120,0,0,0,0,0,0,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, + 119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,0,0,0,0,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,0,0,0,0, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,0,0,0,0,0,0,0,0,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,0,0,0,0,0,0,0,0,0,0,0,19,164,164,164,164,164,164,164,164,164,164,164,0,164,164,164,164, + 164,164,164,164,164,164,164,164,164,164,164,0,164,164,164,164,164,164,164,0,164,164,0,164,164,164,164,164,164,164,164,164,164,164,0,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,0,164,164,164,164,164,164,164,0,164,164,0,0,0, + 159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,0,0,0,0,0,0,0,0,0,0,0,0, + 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, + 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, + 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,0,0,0,0,0,0,0,0,0, + 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,0,0,0,0,0,0,0,0,0,0,75,75,75,75,75,75,75,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 72,72,72,72,72,72,0,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,0,72,72,72,72,72,72,72,72,72,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 26,26,26,26,26,26,0,0,26,0,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,0,26,26,0,0,0,26,0,0,26, + 56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,0,56,56,56,56,56,56,56,56,56,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, + 98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,0,0,0,0,0,0,0,0,98,98,98,98,98,98,98,98,98,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,0,53,53,0,0,0,0,0,53,53,53,53,53, + 125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,0,0,0,125,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,0,0,0,0,0,79, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,0,0,0,0,90,90,90,90, + 90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,0,0,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90, + 65,65,65,65,0,65,65,0,0,0,0,0,65,65,65,65,65,65,65,65,0,65,65,65,0,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,0,0,65,65,65,0,0,0,0,65, + 65,65,65,65,65,65,65,65,65,0,0,0,0,0,0,0,65,65,65,65,65,65,65,65,65,0,0,0,0,0,0,0,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,0,0,0,0,84,84,84,84,84,84,84,84,84,84,84,84,0,0,0,0,0,0,0,0,0, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,6,6,6,6,6,6,6, + 58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,0,0,58,58,58,58,58,58,58,58,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,0,0,0,0,0,57,57,57,57,57,57,57,57, + 126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,0,0,0,0,0,0,0,126,126,126,126,0,0,0,0,0,0,0,0,0,0,0,0,126,126,126,126,126,126,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, + 116,116,116,116,116,116,116,116,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,0,0,0,0,0,0,0,0,0,0,0,0,0, + 110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,0,0,0,0,0,0,0,110,110,110,110,110,110, + 51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,0,0,0,0,0,0,0,0,51,51,51,51,51,51,51,51,51,51,0,0,0,0,0,0, + 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,0,0,0,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, + 40,40,40,40,40,40,0,0,0,0,0,0,0,0,40,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0, + 167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,0,167,167,167,0,0,167,167,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4, + 114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,0,0,0,0,0,0,0,0,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, + 135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, + 117,117,117,117,117,117,117,117,117,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 23,23,23,23,23,23,23,23,23,23,23,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,0,0,0,0,0,0,0,0,0, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,0,0,0,0,0,0,0,0,0,14, + 60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, + 60,60,60,0,0,0,0,0,0,0,0,0,0,60,0,0,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,0,0,0,0,0,0,0,137,137,137,137,137,137,137,137,137,137,0,0,0,0,0,0, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,0,20,20,20,20,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0, + 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, + 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,0,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,0,0,0,0,0,0,0,0,0,0,0, + 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,0,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, + 68,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 96,96,96,96,96,96,96,0,96,0,96,96,96,96,0,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,0,96,96,96,96,96,96,96,96,96,96,96,0,0,0,0,0,0,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, + 69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,0,0,0,0,0,69,69,69,69,69,69,69,69,69,69,0,0,0,0,0,0, + 44,44,44,44,0,44,44,44,44,44,44,44,44,0,0,44,44,0,0,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,0,44,44,44,44,44,44,44,0,44,44,0,44,44,44,44,44,0,30,44,44,44,44, + 44,44,44,44,44,0,0,44,44,0,0,44,44,44,0,0,44,0,0,0,0,0,0,44,0,0,0,0,0,44,44,44,44,44,44,44,0,0,44,44,44,44,44,44,44,0,0,0,44,44,44,44,44,0,0,0,0,0,0,0,0,0,0,0, + 161,161,161,161,161,161,161,161,161,161,0,161,0,0,161,0,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,0,161,161,161,161,161,161,161,161,161, + 161,0,161,0,0,161,0,161,161,161,161,0,161,161,161,161,161,161,161,161,161,161,0,161,161,0,0,0,0,0,0,0,0,161,161,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, + 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,0,101,101,101,101,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, + 158,158,158,158,158,158,158,158,0,0,0,0,0,0,0,0,158,158,158,158,158,158,158,158,158,158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,0,0,133,133,133,133,133,133,133,133, + 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, + 93,93,93,93,93,0,0,0,0,0,0,0,0,0,0,0,93,93,93,93,93,93,93,93,93,93,0,0,0,0,0,0,94,94,94,94,94,94,94,94,94,94,94,94,94,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,0,0,0,0,0,0, + 149,149,149,149,149,149,149,149,149,149,0,0,0,0,0,0,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, + 166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,0,0,0,0,0,0,0,0,0,0,0,0,166, + 33,33,33,33,33,33,33,0,0,33,0,0,33,33,33,33,33,33,33,33,0,33,33,0,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,0,33,33,0,0,33,33,33,33,33, + 33,33,33,33,33,33,33,0,0,0,0,0,0,0,0,0,33,33,33,33,33,33,33,33,33,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,100,100,100,100,100,100,100,0,0,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,0,0,100,100,100,100,100,100,100,100,100,100,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, + 169,169,169,169,169,169,169,169,0,0,0,0,0,0,0,0,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, + 138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,0,0,0,0,0,0,0, + 32,32,32,32,32,32,32,32,32,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,0,0,0,0,0,0,0,0,0,0,0,0,0,0,141,141,141,141,141,141,141,141,141,141,0,0,0,0,0,0, + 12,12,12,12,12,12,12,12,12,0,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,0,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,0,0,0,0,0,0,0,0,0,0,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,0,0,0,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,0,0,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,0,85,85,85,85,85,85,85,85,85,85,85,85,85,85,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 86,86,86,86,86,86,86,0,86,86,0,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,0,0,0,86,0,86,86,0,86, + 86,86,86,86,86,86,86,86,0,0,0,0,0,0,0,0,86,86,86,86,86,86,86,86,86,86,0,0,0,0,0,0,47,47,47,47,47,47,0,47,47,0,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47, + 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,0,47,47,0,47,47,47,47,47,47,0,0,0,0,0,0,0,47,47,47,47,47,47,47,47,47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,0,0,0,0,0,0,0, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,0,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,0,0,0,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,0,0,0,0,0,0,0,0,0,0,0,0,0,150, + 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, + 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, + 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, + 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,0,139,139,139,139,139,0,0,0,0,0,0,0,0,0,0,0, + 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, + 139,139,139,139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27, + 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,0,0,0,0,0,0,0,0,0,0,0,0,0, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,0,0,0,0,0,0,0,0,0,0,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,0,0,0,0,0,0,0, + 95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,0,95,95,95,95,95,95,95,95,95,95,0,0,0,0,95,95,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, + 151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,0, + 151,151,151,151,151,151,151,151,151,151,0,0,0,0,0,0,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,0,0,9,9,9,9,9,9,0,0,0,0,0,0,0,0,0,0, + 121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, + 121,121,121,121,121,121,0,0,0,0,0,0,0,0,0,0,121,121,121,121,121,121,121,121,121,121,0,121,121,121,121,121,121,121,0,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,0,0,0,0,0,121,121,121, + 121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87, + 87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, + 92,92,92,92,92,92,92,92,92,92,92,0,0,0,0,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, + 92,92,92,92,92,92,92,92,0,0,0,0,0,0,0,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,152,104,0,0,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, + 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, + 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, + 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,0,0,0,0,0,0,0,0, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66, + 152,152,152,152,152,152,152,152,152,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,62,62,62,0,62,62,62,62,62,62,62,0,62,62,0, + 62,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, + 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, + 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, + 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, + 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,62,62,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,55,55,0,0,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,62,62,62,62,0,0,0,0,0,0,0,0,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, + 104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, + 104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, + 104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, + 104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,0,0,0,0, + 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35, + 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,0,0,0,0,0,35,35,35,35,35,35,35,35,35,35,35,35,35,0,0,0, + 35,35,35,35,35,35,35,35,35,0,0,0,0,0,0,0,35,35,35,35,35,35,35,35,35,35,0,0,35,35,35,35,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, + 30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,30,30, + 30,30,30,29,29,30,30,30,30,30,30,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,30,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, + 45,45,45,45,45,45,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,0,0,29,0,0,29,29,0,0,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,0,29,0,29,29,29, + 29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,0,29,29,29,29,0,0,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,0, + 29,29,29,29,29,0,29,0,0,0,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, + 134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, + 134,134,134,134,134,134,134,134,134,134,134,134,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,134,134,134,134,134,0,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,0,0,0,0,0,0,72,72,72,72,72,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 42,42,42,42,42,42,42,0,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,0,0,42,42,42,42,42,42,42,0,42,42,0,42,42,42,42,42,0,0,0,0,0,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,0,0,0,105,105,105,105,105,105,105,105,105,105,105,105,105,105,0,0, + 105,105,105,105,105,105,105,105,105,105,0,0,0,0,105,105,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,0,0,0,0,0,165, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,0,0,0,0,108, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,39,39,39,39,39,39,0,39,39,39,39,0,39,39,0,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,0, + 89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, + 89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, + 89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, + 89,89,89,89,89,0,0,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,0,4,0,0,4,0,4,4,4,4,4,4,4,4,4,4,0,4,4,4,4,0,4,0,4,0,0,0,0, + 0,0,4,0,0,0,0,4,0,4,0,4,0,4,4,4,0,4,4,0,4,0,0,4,0,4,0,4,0,4,0,4,0,4,4,0,4,0,0,4,4,4,4,0,4,4,4,4,4,4,4,0,4,4,4,4,0,4,4,4,4,0,4,0, + 4,4,4,4,4,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,0,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 55,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0, + 29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0, + 29,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0, + 29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,0, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0, + 0,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +KBTS_INLINE kbts_u8 kbts_GetUnicodeScript(kbts_u32 Codepoint) +{ + return kbts_UnicodeScript_Data[((kbts_un)kbts_UnicodeScript_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; +} + +static kbts_u8 kbts_UnicodeFlags_PageIndices[8703] = { + 0,1,2,3,2,4,5,6,2,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,33,33,33,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,2,2,2,55, + 56,57,58,59,33,33,60,33,61,33,33,33,33,33,62,63,33,33,33,64,33,33,65,66,67,68,69,70,71,72,33,73, + 74,75,76,77,78,33,33,33,79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,80,79,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,81, + 33,33,33,33,33,33,33,33,33,82,33,33,83,84,85,86,87,88,89,90,91,92,93,94,79,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,95,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,81,33,33,96,97,98,99,33,33,100,101,102,103,104,105, + 106,107,108,109,2,110,111,112,113,114,115,116,33,33,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134, + 135,136,137,138,139,140,141,142,143,144,2,145,146,147,148,2,149,150,151,152,153,154,2,155,156,157,158,159,2,160,161,162, + 33,33,33,33,33,33,33,37,163,33,164,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,165, + 33,33,33,33,33,33,33,33,166,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, + 33,33,33,33,33,33,33,107,33,33,33,33,167,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,168,2,2,2,2,2,2,2,2,2,2,2,2,2,33,33,33,33,169,170,171,172,2,2,173,2,2,174,175,176, + 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,177,33,33,33,33,33,33,33,33,33,178,179,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,180, + 33,33,181,33,33,182,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,183,184,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,33,185,33,33,33,186,187,164, + 33,188,189,190,191,192,193,2,2,2,2,2,2,194,195,196,33,33,33,33,197,198,2,2,2,2,2,2,2,2,199,2, + 200,201,202,2,2,203,2,2,2,204,2,205,2,2,2,206,33,207,208,2,2,2,2,2,209,210,211,2,212,213,2,2, + 214,215,33,216,217,2,33,33,33,33,33,33,33,218,219,220,221,222,33,33,223,224,33,225,2,2,2,2,2,2,2,2, + 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,226,79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,227,2,228,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,229,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,230,2,2,2,2,231,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,33,33,33,33,232,2,2,2,2,2,2,2,2,2,2,2, + 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,233,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,234,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 235,235,236,237,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,238, + 79,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, +}; + +static kbts_u8 kbts_UnicodeFlags_Data[30592] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,4,0,0,16,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,16,16,16,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,0,16,16,16,0,16,2,16,16,16,16,16,16,16,0,0,0,16,16,16,0,16,16,16,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0, + 16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,82,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,16,16,0,0,0,0,16,0,0,0,0,0, + 0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0, + 0,0,16,80,80,80,80,80,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,80, + 0,80,80,0,80,80,0,80,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,16,16,16,0,0,16,0,0,16,16,80,80,80,80,80,80,80,80,80,80,80,0,2,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,81,81,80,80,81,80,80,80,80,80,80,80,48,48,48,48,48,48,48,48,48,48,0,0,0,0,16,16,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,80,80,80,80,80,80,81,0,16,80,80,80,80,81,80,16,16,81,81,16,80,80,80,80,16,16,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, + 80,80,80,80,80,80,80,80,80,80,80,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,80,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,16,16,16,0,0,0,16,0,0,80,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,16,80,80,80,80,80,80,80,80,80,16,80,80,80,16,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,81,81,80,81,81,81,80,80,80,81,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,81,80,80,80,80,80,80,80,80,80,80,80,80, + 80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,80,16,16,16, + 16,80,80,80,80,80,80,80,80,16,16,16,16,80,16,16,16,80,80,80,80,80,80,80,16,16,16,16,16,16,16,16,16,16,80,80,0,0,48,48,48,48,48,48,48,48,48,48,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,80,16,16,0,16,16,16,16,16,16,16,16,0,0,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,0,0,0,16,16,16,16,0,0,80,16,16,16, + 16,80,80,80,80,0,0,16,16,0,0,16,16,80,16,0,0,0,0,0,0,0,0,16,0,0,0,0,16,16,0,16,16,16,80,80,0,0,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,16,16,0,80,0, + 0,80,80,16,0,16,16,16,16,16,16,0,0,0,0,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,0,16,16,0,16,16,0,0,80,0,16,16, + 16,80,80,0,0,0,0,80,80,0,0,80,80,80,0,0,0,80,0,0,0,0,0,0,0,16,16,16,16,0,16,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,80,80,16,16,16,80,0,0,0,0,0,0,0,0,0,0, + 0,80,80,16,0,16,16,16,16,16,16,16,16,16,0,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,0,16,16,16,16,16,0,0,80,16,16,16, + 16,80,80,80,80,80,0,80,80,16,0,16,16,80,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,80,80,0,0,48,48,48,48,48,48,48,48,48,48,0,16,0,0,0,0,0,0,0,16,80,80,80,80,80,80, + 0,80,16,16,0,16,16,16,16,16,16,16,16,0,0,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,0,16,16,16,16,16,0,0,80,16,16,80, + 16,80,80,80,80,0,0,16,16,0,0,16,16,80,0,0,0,0,0,0,0,80,80,16,0,0,0,0,16,16,0,16,16,16,80,80,0,0,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0, + 0,0,80,16,0,16,16,16,16,16,16,0,0,0,16,16,16,0,16,16,16,16,0,0,0,16,16,0,16,0,16,16,0,0,0,16,16,0,0,0,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16, + 80,16,16,0,0,0,16,16,16,0,16,16,16,80,0,0,16,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0, + 80,16,16,16,80,16,16,16,16,16,16,16,16,0,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,80,16,80,80, + 80,16,16,16,16,0,80,80,80,0,80,80,80,80,0,0,0,0,0,0,0,80,80,0,16,16,16,0,0,16,0,0,16,16,80,80,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16, + 16,80,16,16,0,16,16,16,16,16,16,16,16,0,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,0,0,80,16,16,80, + 16,16,16,16,16,0,80,16,16,0,16,16,80,80,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,16,16,0,16,16,80,80,0,0,48,48,48,48,48,48,48,48,48,48,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0, + 80,80,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,16,16,16, + 16,80,80,80,80,0,16,16,16,0,16,16,16,80,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,0,0,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,80,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,0,16,0,0, + 16,16,16,16,16,16,16,0,0,0,80,0,0,0,0,16,16,16,80,80,80,0,80,0,16,16,16,16,16,16,16,16,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,16,80,80,80,80,80,80,80,0,0,0,0,16, + 16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,16,16,0,16,0,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,0,16,16,16,16,16,16,16,16,16,16,80,16,16,80,80,80,80,80,80,80,80,80,16,0,0, + 16,16,16,16,16,0,16,0,80,80,80,80,80,80,80,0,48,48,48,48,48,48,48,48,48,48,0,0,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,16,16,80,80,16,16,16,16,16,16,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,80,16,80,16,80,0,0,0,0,16,16, + 16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,16, + 80,80,80,80,80,0,80,80,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,80,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,16,16, + 16,16,16,16,16,16,80,16,16,16,16,16,16,0,16,16,0,0,0,0,0,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,16,80,80,80,80,80,80,16,80,80,16,16,80,80,16, + 48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,16,16,16,16,16,16,16,16,80,80,16,16,16,16,80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,16,16,16,16,16,16,16,16,16,16,16, + 16,16,80,16,16,80,80,16,16,16,16,16,16,80,16,16,48,48,48,48,48,48,48,48,48,48,16,16,16,80,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,0,16,16,16,16,0,0,16,16,16,16,16,16,16,0,16,0,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,0,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,0,0,16,16,16,16,16,16,16,0, + 16,0,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,80,80,80,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,16,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,16,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,0,80,80,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,82,82,16,80,80,80,80,80,80,80,16,16, + 16,16,16,16,16,16,80,16,16,80,80,80,80,80,80,80,80,80,80,80,0,0,0,16,0,0,0,16,16,80,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,82,82,82,2,82,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0, + 16,16,16,16,16,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,80,80,80,16,16,16,16,80,80,16,16,16,0,0,0,0,16,16,80,16,16,16,16,16,16,80,80,80,0,0,0,0, + 16,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,16,16,80,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,80,80,80,80,80,80,80,0,80,16,80,16,16,80,80,80,80,80,80,80,80,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,0,0,80, + 48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,16,80, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 80,80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,80,80,80,80,80,16,80,16,16,16, + 16,16,80,16,16,16,16,16,16,16,16,16,16,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,16,16,16,16,16,16,16,16,16,0,0,0, + 80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,16,16,80,80,16,80,80,80,16,16,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,80,80,16,16,16,80,16,80,80,80,16,16,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,16,16,80,80,0,0,0,0,0,0,0,0, + 48,48,48,48,48,48,48,48,48,48,0,0,0,16,16,16,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,0,80,80,80,80,80,80,80,80,80,80,80,80,80,16,80,80,80,80,80,80,80,16,16,16,16,80,16,16,16,16,16,16,80,16,16,16,80,80,16,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16, + 16,16,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0, + 0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,16,16,0,0,16,16,16,16,16,16,16,16,16,0,0,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,16,16,16,16,80,16,16,16,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,0,16,16,16,16,0,16,16,0,0,0,0,0,0,0,0,0,0,16,0,16,16,16,0,0,0,0,0,16,16,16,16,16,16,0,16,0,16,0,16,0,0,0,0,16,0,0,0,0,0,0,16,16,16,16,0,16,16,0,0,0,0, + 16,16,16,16,16,0,0,0,0,0,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,0,0,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,0,0,0,0,80,80,80,0,0,0,0,0,0,0,0,0,0,0,16,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0, + 16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,16,16,16,16,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,80,80,80,80,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,80,80,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16, + 0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,48,48,48,48,48,48,48,48,48,48,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,80,16,16,16,0,80,80,80,80,80,80,80,80,80,80,0,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,16,16,16,0,16,16,16,16,16, + 16,16,80,16,16,16,80,16,16,16,16,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,16,16,16,16,16,80,0,0,0,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,80,80,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,16,16,16,16,16,16,0,0,0,16,0,16,16,80, + 48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,80,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0, + 80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,16,80,80,80,80,16,16,80,80,16,16, + 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,16,16,16,16,16,80,16,16,16,16,16,16,16,16,16,16,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,16,16,80,80,16,16,80,80,0,0,0,0,0,0,0,0,0, + 16,16,16,80,16,16,16,16,16,16,16,16,80,16,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,80,80,80,16,16,80,80,16,16,16,16,16,80,80, + 16,80,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,80,80,16,16,0,0,16,16,16,16,80,0,0,0,0,0,0,0,0,0, + 0,16,16,16,16,16,16,0,0,16,16,16,16,16,16,0,0,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,0,0,0,0,0,0,0,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,16,80,16,16,0,16,80,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,0,16,0, + 16,16,0,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,16,16,0,0,16,0,0,0,0,0,0,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,2, + 0,0,0,0,16,0,0,0,0,0,0,16,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0, + 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,16,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0, + 0,0,16,16,16,16,16,16,0,0,16,16,16,16,16,16,0,0,16,16,16,16,16,16,0,0,16,16,16,0,0,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,2,2,2,2,2,2,2,2,2,0,0,0,16,16,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,0,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0, + 0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,0,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,0,0,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,0,0,0,16,0,0,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,0,0,0,0,0,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,80,80,80,0,80,80,0,0,0,0,0,80,80,80,80,16,16,16,16,0,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,80,80,80,0,0,0,0,80, + 16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,0,0,0,0,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,80,80,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,80,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0, + 16,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80, + 80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,48,48,48,48,48,48,48,48,48,48,80,16,16,80,80,16,0,0,0,0,0,0,0,0,0,80, + 80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,16,16,80,80,0,0,0,0,0, + 0,0,80,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,16,80,80,80,80,80,80,80,80,0,48,48,48,48,48,48,48,48,48,48, + 0,0,0,0,16,16,16,16,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,0,0,16,0,0,0,0,0,0,0,0,0, + 80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,16, + 16,16,16,16,16,0,0,0,0,80,80,80,80,0,16,80,48,48,48,48,48,48,48,48,48,48,16,0,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,16,16,80,16,80,80,0,0,0,0,0,0,80,16, + 16,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,0,16,0,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,16,16,80,80,80,80,80,80,80,80,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 80,80,16,16,0,16,16,16,16,16,16,16,16,0,0,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,0,16,16,16,16,16,0,80,80,16,16,16, + 80,16,16,16,16,0,0,16,16,0,0,16,16,16,0,0,16,0,0,0,0,0,0,16,0,0,0,0,0,16,16,16,16,16,16,16,0,0,80,80,80,80,80,80,80,0,0,0,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,0,16,0,0,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,80,80,80,80,80, + 80,0,16,0,0,16,0,16,16,16,16,0,16,16,80,16,80,16,80,16,0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80, + 16,16,80,80,80,16,80,16,16,16,16,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,80,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,16,80,16,16,16,16,80, + 80,16,80,80,16,16,0,16,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,0,0,16,16,16,16,80,80,16,80, + 80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,16,16,80,16,80, + 80,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,16,80,16,16,80,80,80,80,80,80,16,80,16,0,0,0,0,0,0,0, + 48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,80,16,80,16,16,80,80,80,80,16,80,80,80,80,80,0,0,0,0,48,48,48,48,48,48,48,48,48,48,16,16,0,0,0,16, + 16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,16,80,80,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16, + 16,16,16,16,16,16,16,0,0,16,0,0,16,16,16,16,16,16,16,16,0,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,0,0,80,80,16,80,16, + 16,16,16,80,0,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,0,0,80,80,16,16,16,16,80,16,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,80,80,80,80,80,80,80,80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,16,16,80,80,80,80,0, + 0,0,0,0,0,0,0,80,0,0,0,0,0,0,0,0,16,80,80,80,80,80,80,16,16,80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,80,80,80,16,80,80,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,0,80,80,80,80,80,80,16,80, + 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,16,80,80,80,80,80,80,80,16,80,80,16,80,80,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,0,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,0,0,0,80,0,80,80,0,80, + 80,80,80,80,80,80,16,80,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,16,16,16,16,16,16,0,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,80,80,0,16,16,80,16,80,16,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,16,16,0,0,0,0,0,0,0,0,0, + 80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,0,0,0,16,16, + 80,16,80,0,0,0,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 80,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,80,80,80,80,80,16,16,16,80,80,80,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0, + 48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,0,0,0,0,0,16,16,16,16, + 16,16,16,16,0,16,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,80,80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,16,80,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16, + 16,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0, + 16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,0,0,16,80,80,0,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, + 80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,16,16,16,16,16,16,16,16,16,2,2,2,2,2,2,2,2,80,80,80,80,80, + 80,80,80,16,16,80,80,80,80,80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,80,80,80,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,16,0,0,0,0,0,0,0,0,0,0,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,16,16,16,16,80,80,80,80,80, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,16,16,16,16,16,16,16,16,80,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,80,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,80,80,80,80,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 80,80,80,80,80,80,80,0,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,0,0,80,80,80,80,80,80,80,0,80,80,0,80,80,80,80,80,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,80,80,80,80,80,80,80,16,16,16,16,16,16,16,0,0, + 48,48,48,48,48,48,48,48,48,48,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,16, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,80,80,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,80,80,16,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,0,16,16,16,16,0,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,80,80,80,80,80,80,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,80,80,80,80,80,80,80,16,0,0,0,0,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,0,16,0,0,16,0,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,0,16,0,16,0,0,0,0, + 0,0,16,0,0,0,0,16,0,16,0,16,0,16,16,16,0,16,16,0,16,0,0,16,0,16,0,16,0,16,0,16,0,16,16,0,16,0,0,16,16,16,16,0,16,16,16,16,16,16,16,0,16,16,16,16,0,16,16,16,16,0,16,0, + 16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,0,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0, + 16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0, + 16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0, + 16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,0,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,48,48,48,48,48,48,48,48,48,48,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0, + 16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, + 82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, + 82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, + 82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0, +}; + +KBTS_INLINE kbts_u8 kbts_GetUnicodeFlags(kbts_u32 Codepoint) +{ + return kbts_UnicodeFlags_Data[((kbts_un)kbts_UnicodeFlags_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; +} + +static kbts_u8 kbts_UnicodeBidirectionalClass_PageIndices[8703] = { + 0,1,2,2,2,3,4,5,2,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,2,2,31,32,33,34,35,2,2,2,2,36,37,38,39,40,41,42,43,44,45,46,47,48,2,49,2,2,50,51, + 52,53,54,55,56,57,58,59,57,60,57,57,57,61,57,57,2,2,57,57,57,57,57,57,2,62,63,64,57,57,57,57, + 65,66,67,68,69,70,71,72,73,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,74,73,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,75, + 2,2,2,2,2,2,2,2,2,76,2,2,77,78,79,80,81,82,83,84,85,86,87,88,73,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,89,73,57,57,57,57,57,75,90,73,57,57,57,57,57,57,75, + 73,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,75,2,2,91,92,93,94,95,95,96,97,98,99,100,101, + 102,103,104,105,57,106,107,108,2,109,110,111,2,2,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129, + 130,131,132,133,134,135,136,137,138,139,57,140,141,142,143,57,144,145,146,147,148,149,150,151,152,153,154,155,57,156,157,158, + 2,2,2,2,2,2,2,159,160,2,161,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,162, + 2,2,2,2,2,2,2,2,163,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,103,2,2,2,2,164,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,165,57,57,57,57,57,57,57,57,57,57,57,57,57,2,2,2,2,166,167,168,169,57,57,170,57,171,172,173,174, + 73,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,175,2,2,2,2,2,2,2,2,2,176,177,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,178, + 2,2,179,2,2,180,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,181,182,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,183,57,57,57,57,184,161, + 2,185,186,187,188,189,190,57,191,192,193,2,2,194,195,196,2,2,2,2,197,198,57,57,57,57,57,57,57,57,199,57, + 200,201,202,57,57,203,57,57,57,204,57,205,57,57,57,206,207,208,209,57,57,57,57,57,210,211,212,57,213,214,57,57, + 57,57,215,216,217,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,218,57,57,57,57,57,57,57,57, + 73,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,219,73,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,220,57,221,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,222,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,223,57,57,57,57,224,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,2,2,2,2,225,57,57,57,57,57,57,57,57,57,57,57, + 73,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,226,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,227,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,228,229,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 73,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,230, + 73,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +}; + +static kbts_u8 kbts_UnicodeBidirectionalClass_Data[29568] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,8,0,0,0,0,0,7,9,7,9,9,6,6,6,6,6,6,6,6,6,6,9,0,0,0,0,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,8,8,8,8,0,0,0,0,1,0,0,0,0,0,8,8,6,6,0,1,0,0,0,6,1,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1, + 1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,0,0,1,1,0,0,1,1,1,1,0,1, + 0,0,0,0,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1, + 1,1,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,8,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3, + 2,3,3,2,3,3,2,3,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,5,0,0,4,8,8,4,9,4,0,0,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,5,5,5,5,5,5,5,5,5,5,8,5,5,4,4,4,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,5,0,3,3,3,3,3,3,4,4,3,3,0,3,3,3,3,4,4,6,6,6,6,6,6,6,6,6,6,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,2,2,0,0,0,0,2,0,0,3,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,2,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,0,0,2,0,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,5,5,0,0,0,0,0,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,5,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1, + 1,3,3,3,3,3,3,3,3,1,1,1,1,3,1,1,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,3,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,0,3,1,1,1, + 1,3,3,3,3,0,0,1,1,0,0,1,1,3,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,1,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,1,1,8,8,1,1,1,1,1,1,1,8,1,1,3,0, + 0,3,3,1,0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,0,3,0,1,1, + 1,3,3,0,0,0,0,3,3,0,0,3,3,3,0,0,0,3,0,0,0,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,3,1,0,0,0,0,0,0,0,0,0, + 0,3,3,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,3,1,1,1, + 1,3,3,3,3,3,0,3,3,1,0,1,1,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,1,8,0,0,0,0,0,0,0,1,3,3,3,3,3,3, + 0,3,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,3,1,1,3, + 1,3,3,3,3,0,0,1,1,0,0,1,1,3,0,0,0,0,0,0,0,3,3,1,0,0,0,0,1,1,0,1,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, + 0,0,3,1,0,1,1,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1, + 3,1,1,0,0,0,1,1,1,0,1,1,1,3,0,0,1,0,0,0,0,0,0,1,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,0,0,0,0,0,0,8,0,0,0,0,0,0, + 3,1,1,1,3,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,1,3,3, + 3,1,1,1,1,0,3,3,3,0,3,3,3,3,0,0,0,0,0,0,0,3,3,0,1,1,1,0,0,1,0,0,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, + 1,3,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,3,1,1,1, + 1,1,1,1,1,0,1,1,1,0,1,1,3,3,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1, + 1,3,3,3,3,0,1,1,1,0,1,1,1,3,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,3,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,0, + 1,1,1,1,1,1,1,0,0,0,3,0,0,0,0,1,1,1,3,3,3,0,3,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,3,3,3,3,3,3,3,0,0,0,0,8, + 1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,3,1,1,3,3,3,3,3,3,3,3,3,1,0,0, + 1,1,1,1,1,0,1,0,3,3,3,3,3,3,3,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,3,0,0,0,0,1,1, + 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1, + 3,3,3,3,3,1,3,3,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,1,1, + 1,1,1,1,1,1,3,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,3,3,3,3,3,3,1,3,3,1,1,3,3,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1, + 1,1,3,1,1,3,3,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,0,1,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0, + 1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,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,1,1,1,3,3,1,1,1,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,1,1,3,3,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,0,1,1,1,0,3,3,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,3,3,3,3,3,3,3,1,1, + 1,1,1,1,1,1,3,1,1,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,8,1,3,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,3,3,3,0,3,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, + 1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,3,3,3,1,1,1,1,3,3,1,1,1,0,0,0,0,1,1,3,1,1,1,1,1,1,3,3,3,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,3,3,1,1,3,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,3,3,3,3,3,3,0,3,1,3,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,0,0,3, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,3,3,3,3,1,3,1,1,1, + 1,1,3,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1, + 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,3,3,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,3,1,1,1,3,1,3,3,3,1,1,0,0,0,0,0,0,0,0,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,3,3,0,0,0,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1, + 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,1,1,1,1,3,1,1,1,1,1,1,3,1,1,1,3,3,1,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0, + 0,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,8,8,8,8,8,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,1,0,0,6,6,6,6,6,6,7,7,0,0,0,1, + 6,6,6,6,6,6,6,6,6,6,7,7,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,1,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,1,0,1,0,1,0,1,1,1,1,8,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1, + 0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,3,3,3,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0, + 1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,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,3,3,3,3,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1, + 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,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,3,1,1,1,3,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,0,0,0,0,3,0,0,0,1,1,1,1,1,1,1,1,8,8,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,3,3,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0, + 3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,3,3,3,3,1,1,3,3,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,3,3,1,1,3,3,0,0,0,0,0,0,0,0,0, + 1,1,1,3,1,1,1,1,1,1,1,1,3,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,3,3,1,1,3,3,1,1,1,1,1,3,3, + 1,3,1,0,0,0,0,0,0,0,0,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,1,3,3,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0,0, + 0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,3,1,1,1,1,3,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,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, + 1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,2,3,2,2,2,2,2,2,2,2,2,2,7,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,0,2,0, + 2,2,0,2,2,0,2,2,2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,9,0,0,9,0,0,0,0,0,0,0,0,0,8,0,0,7,7,0,0,0,0,0,8,8,0,0,0,0,0,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0, + 0,0,0,8,8,8,0,0,0,0,0,7,9,7,9,9,6,6,6,6,6,6,6,6,6,6,9,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,0,0,0,8,8,0,0,0,8,8,0,0,0,0,0,0,0,0,0,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,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 1,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,0,0,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,2,0,0,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,3,3,3,0,3,3,0,0,0,0,0,3,3,3,3,2,2,2,2,0,2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,3,3,3,0,0,0,0,3, + 2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,3,3,3,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0, + 5,5,5,5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,3,3,3,3,3,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,3,3,2,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,3,3,3,3,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0, + 1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,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,3,1,1,3,3,1,0,0,0,0,0,0,0,0,0,3, + 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,3,3,1,1,1,1,1, + 1,1,3,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,1,3,3,3,3,3,3,3,3,0,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,0,0,0,0,0,0,0,0,0, + 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1, + 1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,1,3,1,3,3,1,1,1,1,1,1,3,1, + 1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,3,3,3,3,3,3,3,3,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 3,3,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,3,3,1,1,1, + 3,1,1,1,1,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,3,3,3,3,3,3,3,0,0,0,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,3,3,3,3,3, + 3,0,1,0,0,1,0,1,1,1,1,0,1,1,3,1,3,1,3,1,1,1,0,1,1,0,0,0,0,0,0,0,0,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3, + 1,1,3,3,3,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,3,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,1,3,1,1,1,1,3, + 3,1,3,3,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,0,0,1,1,1,1,3,3,1,3, + 3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,1,1,3,1,3, + 3,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,3,3,3,3,3,3,1,3,1,1,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,0,0,3,1,3,1,1,3,3,3,3,1,3,3,3,3,3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,1,3,3,1,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1, + 1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,3,3,1,3,1, + 1,1,1,3,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,0,0,3,3,1,1,1,1,3,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,3,3,3,3,3,3,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,1,1,3,3,3,3,1, + 1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0,1,3,3,3,3,3,3,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,1,1,1,1,1,1,1,1,1,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, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,0,3,3,3,3,3,3,1,1, + 1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,1,3,3,3,3,3,3,3,1,3,3,1,3,3,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,0,0,0,3,0,3,3,0,3, + 3,3,3,3,3,3,1,3,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,3,3,0,1,1,3,1,3,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,3,3,1,1,1,1,0,0,0,0,0,0,0, + 3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,0,0,0,1,1, + 3,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,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,1,1,1,1,1,0,0,0,0,0,0,0,0,8,8,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 3,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3,3,3,3,3,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,3,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, + 1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0, + 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,3,3,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,6,6,6,6,6,6,6,6,6,6,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,3,3,3,3,3, + 3,3,3,1,1,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,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,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1, + 1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0, + 1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,0,1,1,1,1,1,1,1,1,0,0,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,3,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,3,3,3,3,3,3,3,1,1,1,1,1,1,1,0,0, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,8, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 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,1,1,1,1,1,1,1,1,1,1,1,1,3,3,3,3,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,3,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,0,0,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,3,3,3,3,3,3,3,2,0,0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,4,4,0,4,0,0,4,0,4,4,4,4,4,4,4,4,4,4,0,4,4,4,4,0,4,0,4,0,0,0,0, + 0,0,4,0,0,0,0,4,0,4,0,4,0,4,4,4,0,4,4,0,4,0,0,4,0,4,0,4,0,4,0,4,0,4,4,0,4,0,0,4,4,4,4,0,4,4,4,4,4,4,4,0,4,4,4,4,0,4,4,4,4,0,4,0, + 4,4,4,4,4,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0,0,4,4,4,0,4,4,4,4,4,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 6,6,6,6,6,6,6,6,6,6,6,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1, + 1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, + 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6,6,6,6,6,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +}; + +KBTS_INLINE kbts_u8 kbts_GetUnicodeBidirectionalClass(kbts_u32 Codepoint) +{ + return kbts_UnicodeBidirectionalClass_Data[((kbts_un)kbts_UnicodeBidirectionalClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; +} + +static kbts_u8 kbts_UnicodeJoiningType_PageIndices[8703] = { + 0,1,0,0,0,0,2,0,0,3,0,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,0,0,0,0,27,0,0,0,0,0,0,0,28,29,30,31,32,0,33,34,35,36,37,38,0,39,0,0,0,0, + 40,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,43,44,0,0,0,0, + 45,46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,47,48,0,0,49,50,51,52,53,54,0,55,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,0,0,0,0,0,57,43,0,58, + 0,0,0,59,0,60,61,0,0,0,0,0,0,0,0,0,0,0,0,0,62,63,0,64,0,0,65,0,0,66,67,68, + 69,70,71,72,73,74,75,76,77,78,0,79,80,81,82,0,83,0,84,85,86,87,0,0,88,89,90,91,0,92,93,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,94,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,95,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,97,0,0,0,0,0,0,0,98,99, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,0, + 0,0,102,103,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,105,106,0,0,0,0,0,0,0,0,0,0, + 107,108,97,0,0,109,0,0,0,110,0,111,0,0,0,0,0,112,113,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 114,0,115,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +static kbts_u8 kbts_UnicodeJoiningType_Data[14848] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5, + 0,5,5,0,5,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,0,5,0,0,0,2,0,4,4,4,4,2,4,2,4,2,2,2,2,2,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,2,2,2,2,2,2,2,4,2,2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,5,4,4,4,0,4,4,4,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 4,2,2,4,4,4,4,4,4,4,4,4,2,4,2,4,2,2,4,4,0,4,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,0,0,5,5,0,5,5,5,5,4,4,0,0,0,0,0,0,0,0,0,0,2,2,2,0,0,2, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,4,5,2,2,2,4,4,4,4,4,2,2,2,2,4,2,2,2,2,2,2,2,2,2,4,2,4,2,4,2,2,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,0,0,4,2,2,2,2,2,2,2,2,2,2,2,4,4,4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,4,2,2,2,2,4,2,4,4,2,2,2,4,4,2,2,2,2,2,2, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,3,0,0,5,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,5,5,5,5,5,5,5,5,5,0,5,5,5,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 4,2,2,2,2,2,4,4,2,4,2,2,2,2,2,2,2,2,2,2,4,2,4,4,4,5,5,5,0,0,0,0,2,0,2,2,2,2,0,4,2,4,4,0,0,0,0,0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,3,3,3,2,0,0,2,2,2,2,2,4,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,2,2,2,2,2,2,2,2,2,2,4,4,4,0,4,2,2,4,4,2,2,2,2,2,2,4,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,0, + 0,5,5,5,5,5,5,5,5,0,0,0,0,5,0,0,0,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0, + 0,5,5,5,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0, + 0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0, + 0,5,5,0,0,0,0,5,5,0,0,5,5,5,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,5,0,0,0,0,0,0,0,0,0,0, + 0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0, + 0,5,5,5,5,5,0,5,5,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5, + 0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5, + 0,5,5,5,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,5, + 5,0,0,0,0,0,5,5,5,0,5,5,5,5,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5, + 0,0,0,0,0,0,5,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0, + 0,5,5,5,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,5,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5,5,5,5,5,5,5,0,0,0,0,0, + 0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5,5,5,5,5,5,5,5,5,0,0,0, + 0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,5,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0, + 5,5,5,5,5,0,5,5,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0, + 0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,5,5,5,5,5,5,0,5,5,0,0,5,5,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0, + 0,0,5,0,0,5,5,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,5,5,5,5,5,5,5,0,0, + 0,0,0,0,0,0,5,0,0,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,2,0,0,3,5,5,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0, + 0,0,0,0,0,5,5,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,5,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,5,5,5,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,5,5,5,5,5,5,0,5,0,5,0,0,5,5,5,5,5,5,5,5,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,0,0,5, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,5,5,5,5,0,5,0,0,0, + 0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,5,5,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,5,0,0,0,5,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,0,0,5,5,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,0,0,0,0,5,0,0,0,0,0,0,5,0,0,0,5,5,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 0,0,0,0,0,0,0,0,0,0,0,5,0,3,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,0,0,0,0,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,5,0,0,0,5,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5,5,5,5,0,0,5,5,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,5,5,0,0,5,5,0,0,0,0,0,0,0,0,0, + 0,0,0,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,5,5,0,0,5,5,0,0,0,0,0,5,5, + 0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,0,0,0,0, + 0,5,5,5,0,5,5,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,5, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,4,0,4,0,4,4,0,0,1,4,4,4,4,4,2,2,2,2,1,2,2,2,2,2,4,2,2,2,4,0,0,4,5,5,0,0,0,0,2,2,2,2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,4,2,4,4,4,2,2,2,4,2,2,4,2,4,4,2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,4,4,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,4,2,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,4,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,4,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,0,5,5,5,5,5,5,5,5,5,5,5,2,2,2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,4,4,2,2,2,2,2,2,2,2,2,2, + 2,2,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,2,4,4,4,0,2,4,4,2,2,4,2,2, + 0,2,4,4,2,0,0,0,0,4,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5,5,0,0,0,0,0,0,0,0,0,0,5, + 5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,5,5,0,0,0,0,0, + 0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,0, + 0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,5,0,5,5,0,0,0,0,0,0,5,0, + 0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0, + 5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,0,0,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5, + 5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5, + 0,0,5,5,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,0,5,0,0,0,0,5, + 5,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,5,5,0,5, + 5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,0,0,5,0,5, + 5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,5,5,5,5,5,5,0,5,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,5,5,5,5,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,0,5,5,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,5,0, + 0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,5,5,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,5,5,5,5,0, + 0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,0,5,5,5,5,5,5,0,5, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,0,5,5,0,5,5,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,0,0,0,5,0,5,5,0,5, + 5,5,5,5,5,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0, + 5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,0,0,0,0, + 5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,0,0,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 5,5,5,5,5,5,5,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,5,5,5,5,5,5,5,0,5,5,0,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, +}; + +KBTS_INLINE kbts_u8 kbts_GetUnicodeJoiningType(kbts_u32 Codepoint) +{ + return kbts_UnicodeJoiningType_Data[((kbts_un)kbts_UnicodeJoiningType_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; +} + +static kbts_u8 kbts_UnicodeCombiningClass_PageIndices[8703] = { + 0,0,0,0,0,0,1,0,0,2,0,3,4,5,6,7,8,9,10,11,12,12,12,13,14,12,15,16,17,18,19,20, + 21,22,0,0,0,0,23,0,0,0,0,0,0,0,24,25,0,26,27,0,28,29,30,31,32,33,0,34,0,0,0,0, + 0,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,37,38,0,0,0,0, + 39,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,41,42,0,0,43,44,45,46,0,47,0,48,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,0,0,0,0,0,50,0,0,0, + 0,0,0,51,0,52,53,0,0,0,0,0,0,0,0,0,0,0,0,0,54,55,0,0,0,0,56,0,0,57,58,59, + 60,61,62,63,64,65,66,67,68,69,0,70,71,72,73,0,61,0,74,75,76,77,0,0,71,0,78,79,0,0,80,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,81,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,82,83,0,0,0,0,0,0,0,0,84, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,86,87,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 89,90,83,0,0,91,0,0,0,92,0,93,0,0,0,0,0,94,95,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +static kbts_u8 kbts_UnicodeCombiningClass_Data[12288] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,220,220,220,220,220,220,220,220,1,1,1,1,1,220,220,220,220,230,230,230, + 230,230,230,230,230,240,230,220,220,220,230,230,230,220,220,0,230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233,234,234,233,230,230,230,230,230,230,230,230,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,230,230,230,230,220,230,230,230,222,220,230,230,230,230,230,230,220,220,220,220,220,220,230,230,220,230,230,222,228,230,22,15,16,17,23,18,19,20,21,14,14,24,12,25,0,13, + 0,10,11,0,230,220,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,230,31,32,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,28,29,30,31,32,33,27,34,230,230,220,220,230,230,230,230,230,220,230,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,230,230,230,230,220,230,0,0,230,230,0,220,230,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,230,230,220,230,230,220,220,220,230,220,220,230,220,230, + 230,230,220,230,220,230,220,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,220,230,0,0,0,0,0,0,0,0,0,220,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,230,230,230,230,230,230,230,230,230,0,230,230,230,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,220,220,220,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,220,220,220,220,220,230,230,230,230,230,230,230,230,230,230,230,230,230,230,0,220,230,230,220,230,230,220,230,230,230,220,220,220,28,29,30,230,230,230,220,230,230,220,220,230,230,230,230,230, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,230,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,4,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,9,0,0,0,0,0, + 0,0,0,0,0,0,0,0,107,107,107,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,118,118,9,0,0,0,0,0, + 0,0,0,0,0,0,0,0,122,122,122,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,220,0,127,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,132,0,131,0,0,0,0,0,132,132,132,132,0,0, + 132,0,230,230,9,0,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,9,9,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,228,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,222,230,220,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,230,0,0,220, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,220,220,220,220,220,220,230,230,220,0,220, + 220,230,230,220,220,230,230,230,230,230,220,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,230,230,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,0,1,220,220,220,220,220,230,230,220,220,220,220,230,0,1,1,1,1,1,1,1,0,0,0,0,220,0,0,0,0,0,0,230,0,0,0,230,230,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 230,230,220,230,230,230,230,230,230,230,220,230,230,234,214,220,202,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,232,228,228,220,218,230,233,220,230,220, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,1,1,230,230,230,230,1,1,1,230,230,0,0,0,0,230,0,0,0,1,1,230,220,230,1,1,220,220,220,220,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,218,228,232,222,224,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0,0,0,0,230,230,230,230,230,230,230,230,230,230,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0, + 9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0,230,230,220,0,0,230,230,0,0,0,0,0,230,230, + 0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,220,220,220,220,220,220,220,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,1,220,0,0,0,0,9, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,220,220,230,230,230,220,230,220,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,230,220,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 9,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,9,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9, + 7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,9,0, + 0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,7,0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,230,230,230,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,216,216,1,1,1,0,0,0,226,216,216,216,216,216,0,0,0,0,0,0,0,0,220,220,220,220,220, + 220,220,220,0,0,230,230,230,230,230,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 230,230,230,230,230,230,230,0,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,0,0,230,230,230,230,230,230,230,0,230,230,0,230,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,230,230,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,232,232,220,230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,220,220,220,220,220,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,230,230,230,230,230,230,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +KBTS_INLINE kbts_u8 kbts_GetUnicodeCombiningClass(kbts_u32 Codepoint) +{ + return kbts_UnicodeCombiningClass_Data[((kbts_un)kbts_UnicodeCombiningClass_PageIndices[Codepoint/128] * 128) | (Codepoint & 127)]; +} + +static kbts_u16 kbts_UnicodeParentInfo_PageIndices[34815] = { + 0,1,2,3,0,4,5,6,7,0,8,9,0,10,0,11,0,12,0,0,13,14,0,0,15,0,0,0,16,17,18,0, + 19,20,21,22,0,0,23,24,0,0,0,0,0,0,25,26,0,27,28,0,0,0,29,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,30,31,0,0,0,32,33,0,34,35,0,0,0,0,0,0,0,36,37,0,0,0,38,0, + 0,0,39,0,0,40,41,0,0,0,38,0,0,0,42,0,0,0,0,0,0,0,0,0,0,0,43,44,45,46,0,0, + 0,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,50,51,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,53,54,0,55,56,0,57,58,59,60,0,61,62,63, + 64,0,0,0,0,0,0,0,0,0,0,0,65,0,66,0,67,68,69,70,71,72,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 74,0,75,76,77,75,76,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,79,80,81,0,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,83,0,0,0,0,84,0,0,0, + 0,85,0,86,0,0,87,88,89,90,0,0,0,0,0,0,0,91,0,92,0,0,0,93,94,0,95,0,96,0,0,0, + 97,0,98,0,0,0,0,0,0,99,0,0,100,0,0,0,0,0,0,0,0,101,0,0,102,0,0,0,0,0,0,103, + 104,105,106,0,107,0,0,108,0,109,0,0,0,0,0,0,110,111,0,0,0,112,0,0,113,114,115,0,0,0,116,0, + 117,0,0,118,0,0,0,0,0,119,120,121,0,0,122,123,0,124,0,0,0,125,126,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,128,0,0,0,129,0,130,0,0,0,131,0,0,0,0,132,0, + 0,0,0,0,0,0,133,134,0,0,135,0,0,0,0,0,136,137,138,0,139,140,141,142,0,0,0,143,144,145,0,0, + 146,147,0,148,149,0,150,151,0,0,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,0,0,170,171, + 172,173,174,175,176,177,0,178,179,0,180,181,182,183,184,185,186,0,187,188,0,0,0,189,190,0,0,0,191,0,192,193, + 194,195,196,0,0,197,198,199,200,201,202,203,0,0,204,205,206,207,0,208,0,209,0,0,210,211,0,0,212,0,213,214, + 215,216,0,217,218,0,219,0,220,0,221,222,0,223,0,224,0,225,0,226,0,227,228,229,230,231,232,233,234,235,236,237, + 238,0,0,239,240,0,241,242,243,0,244,245,246,247,248,249,250,251,252,0,0,253,254,255,0,256,257,258,259,260,261,262, + 263,264,265,266,267,0,268,0,0,0,269,270,271,0,272,273,274,0,275,276,277,278,279,280,281,282,283,284,285,0,0,286, + 287,0,288,0,289,290,0,0,291,0,292,0,0,293,0,294,295,0,0,0,0,296,297,0,298,299,300,301,302,303,0,0, + 0,0,304,305,306,307,308,309,310,311,312,313,314,0,315,316,317,318,0,319,320,321,322,0,323,324,0,325,0,0,326,327, + 328,329,330,331,332,333,334,0,0,0,335,336,337,0,338,0,339,340,341,342,343,344,345,346,0,347,0,348,349,350,351,0, + 352,353,354,355,356,0,357,0,358,359,360,361,0,0,0,362,363,0,364,365,0,0,366,367,368,0,369,0,370,371,0,0, + 0,0,372,373,374,0,375,376,0,377,378,379,380,381,382,383,384,0,385,0,386,387,388,389,0,390,0,0,0,0,391,0, + 0,392,0,393,394,395,396,397,398,399,400,401,0,402,403,404,405,406,407,0,0,0,0,0,0,408,0,409,410,411,0,412, + 413,0,414,415,416,417,0,0,418,419,0,0,0,0,420,421,422,0,0,423,424,425,0,426,427,428,429,430,0,431,432,433, + 0,434,435,0,0,0,0,436,437,0,0,438,0,0,439,440,441,442,443,444,445,446,0,447,448,449,0,450,451,452,0,453, + 454,0,455,456,0,0,457,458,459,0,460,461,462,0,0,0,0,0,0,0,0,463,464,465,466,467,468,0,469,0,0,0, + 0,0,470,0,0,471,472,0,473,0,0,474,0,475,476,477,0,0,0,0,0,0,478,0,0,479,0,480,481,482,0,0, + 0,483,0,484,485,0,486,487,488,0,0,489,490,491,492,0,0,493,0,494,0,0,495,0,496,0,497,0,0,0,0,498, + 499,0,0,0,0,0,0,0,0,0,0,0,500,501,0,0,0,502,503,504,505,506,507,508,0,509,510,0,0,0,511,512, + 513,514,515,0,0,0,0,516,0,517,0,0,0,518,519,520,0,0,0,521,0,0,0,0,522,0,0,523,0,0,0,0, + 0,0,524,0,0,0,0,525,0,0,0,526,0,527,0,528,529,0,0,530,531,532,533,534,535,536,537,0,538,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,539,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,540,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,541,542,0,0,0,543,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,33,0,544,0,545,0, + 0,0,0,0,0,546,0,0,0,0,0,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,547,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,548,549,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,550,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,551,0,0,552,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,553,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,554,555,556,0,0,0,0,0,0,557,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 558,0,0,0,0,0,559,0,0,0,0,0,0,0,0,0,0,560,0,0,0,0,0,0,0,0,0,561,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,562,0,0,0,0,0,0,0,0,0,0,0,0,0,563,0,564,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,565,0,0,0,0,0,0,0,0,0,566,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,567,0,0,0,0,0,0,568,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,569,0,0,0,0,0,0,0,0,0,0,0,0,570,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,571,0,0,0,0,0,0,0,0,0, + 0,0,572,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,573,0,0,0,0,0,0,574, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 575,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,576,0,0,0,0,577,0,578,0,579,0, + 0,0,0,580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,581,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,582,0,0,0,0,0,0,0,0,0,0,0,0,0,0,583,0,0,584,0,0,0,0,0,0,0,0, + 0,0,0,0,0,585,0,0,586,0,0,0,0,0,0,0,0,0,0,0,0,0,587,0,0,0,588,0,589,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,590,0,0,0,591,0,0,0,0,0,592,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,593,0,0,0,0,0,0,0,0,594,0,0,0,0,0,0, + 595,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,596,0,0,597,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,598,0,0, + 0,0,599,0,0,0,0,600,601,602,0,0,0,0,0,0,0,0,603,0,0,0,0,0,0,0,0,0,0,0,0,0, + 604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,605,0,0,606,0,607,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,608,0,0,0,0,0,0,0,0,0,609,0,0,0,0,0,0,0,610,0,0, + 0,0,0,0,611,0,612,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,613,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,614,0,0,615,616,0,0,0,617,0,0,618,0,0,0,0,0,0, + 0,0,0,0,0,0,619,0,0,620,0,0,0,621,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,622,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,623,0,0,0,0,0,0, + 0,624,0,0,0,0,625,0,0,0,0,626,0,0,0,0,0,0,0,0,0,0,0,0,0,627,0,0,0,628,0,0, + 0,0,0,0,0,0,629,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,630,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,631,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,632,0,0,0,0,0,633,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,634,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,635,0,0,636,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,637,638,0,0,0,0,0,0,0,0,0,639,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,640, + 0,0,0,0,0,0,0,0,0,0,0,641,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,642,0,0,0,643,0,644,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 645,0,0,0,646,0,0,0,0,0,0,0,0,647,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,648,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,649,0,650,0,0,0,0,0,0,0,651,0,0,0,652,0,0,0,0,0,0,0,653,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,654,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +static kbts_u32 kbts_UnicodeParentInfo_Data[20960] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66400,66423,66421,66422,0, + 0,1048664,197177,328094,393598,1114167,66418,459018,459046,983176,65810,393556,393562,197183,590017,1048696,131720,0,524539,459032,459067,1245203,131728,393604,131730,590026,393592,0,0,0,0,0, + 66420,1048648,197171,328084,393586,1114150,66417,459011,524515,917655,131704,328109,393538,197180,590008,1048680,131414,0,524499,459025,524523,1245184,131724,459060,131726,655525,393580,0,0,0,0,0, + 0,0,0,0,0,0,0,0,197174,0,0,0,0,0,0,0,0,0,0,0,66419,0,0,66399,0,0,0,0,0,0,0,0, + 0,0,262650,0,66396,131722,131706,65959,0,0,262654,0,0,0,0,66416,0,0,0,0,262658,197168,66398,0,66397,0,0,0,262626,0,0,0, + 0,0,262638,0,66019,66395,131702,66415,0,0,262642,0,0,0,0,65963,0,0,0,0,262646,197165,66186,0,65816,0,0,0,262622,0,0,0, + 0,0,262634,262634,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131716,131716,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,131718,131718,0,0,0,0,0,0,0,0,0,0,0,0,66412,66412,0,0,0,0, + 66183,66183,0,0,0,0,0,0,66413,66413,66413,66413,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66414, + 328104,328104,0,0,0,0,0,0,0,0,0,0,0,0,0,328099,328099,0,0,0,0,0,0,66381,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,65936,65936,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66367,66367,66405,66405,0,0,0,0,65936,65936,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66366,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66393,0,0,0,0,0,0, + 65973,65973,0,0,0,0,0,0,66384,0,0,0,0,0,0,0,0,0,0,66379,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,66409,65949,0,65829,66406,65873,0,66411,0,66408,66410,65867,459053,0,0,0,262618,0,328089,0,459039,0,0,0,0,0,262610, + 0,66407,0,0,0,393544,0,0,0,393550,0,0,131708,66403,131710,66404,65948,524531,0,0,0,262606,0,393568,0,589999,0,0,0,0,0,262630, + 0,131714,0,0,0,524507,0,0,0,393574,197129,197132,66401,66402,131712,0,0,0,131471,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,65935,0,0,0,0,0,0,0,0,0,131227,0,0,66371,0,197150,131700,65953,262594,0,65945,0,0,0,66394,0, + 0,0,0,262586,0,0,0,65595,0,0,0,65595,0,65630,0,0,131696,0,0,66376,0,197162,131698,65943,262602,0,66377,0,0,0,66392,0, + 0,0,0,262614,0,0,0,65578,0,0,0,65578,0,65614,0,0,0,0,0,0,0,0,65935,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65936,65936,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65936,65936,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,65936,65936,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197216,131836,66134,66134,66134,131828,66134,0,66134,131820,66134,131826,66134,0,66134,0, + 66134,66134,0,66134,131822,0,66134,66134,66134,197204,66134,0,0,0,0,0,0,0,66855,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,197135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66370,0,66370,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65935,0,0,65978,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66387,66387,66387,0,0,0,0,66385,0,0,0, + 0,66383,66383,0,0,0,0,0,65935,0,0,66380,0,0,0,66379,0,0,0,65935,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66379,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,131474,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66387,66387,0,0,0,0,66385,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66380,0,0,0,0,0,0,65935,0,0,0,0,0,65931,0,0,0,0,0,0,0, + 0,66383,66383,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,197147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,131507,65934,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,65936,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65935, + 0,0,0,0,0,0,197138,0,0,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197141,0,0,65935,0,0,0, + 66378,0,65935,0,0,0,0,0,0,0,0,0,65935,0,0,0,0,65935,0,0,0,0,65935,0,0,0,0,65935,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197153,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66378,0,65935,0,0,0,0,0,0,0,0,0,65935,0,0,0, + 0,65935,0,0,0,0,65935,0,0,0,0,65935,0,0,0,0,0,0,66368,66369,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,328074,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,65935,0,65935,0,65935,0,65935,0,65935,0,0,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65935,0,65935,0,65936,65936, + 0,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65936,65936,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65936,65936,0,0,0,0, + 0,0,65755,65755,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 131694,131694,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66087,66087,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,66158,66158,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 262598,262598,65609,65609,65609,65609,65609,65609,262598,262598,65609,65609,65609,65609,65609,65609,131506,131506,0,0,0,0,0,0,131506,131506,0,0,0,0,0,0, + 262590,262590,65985,65985,65985,65985,65985,65985,262590,262590,65985,65985,65985,65985,65985,65985,197042,197042,0,0,0,0,0,0,197042,197042,0,0,0,0,0,0, + 131506,131506,0,0,0,0,0,0,131506,131506,0,0,0,0,0,0,197042,197042,0,0,0,0,0,0,0,197042,0,0,0,0,0,0, + 262578,262578,65973,65973,65973,65973,65973,65973,262578,262578,65973,65973,65973,65973,65973,65973,66386,0,0,0,66388,0,0,0,0,0,0,0,66391,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65935,0,0,0,0,0,0,0,0,197159, + 0,0,0,0,0,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65935,0,0,0,0,0,0,0,197126,0, + 0,0,65931,65931,0,0,0,0,0,0,0,0,0,0,0,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66374,0,66373,0,66375,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65930,0,65930,0,66372,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,65935,0,0,0,0,65935,0,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,65935,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65894,0,0,0, + 0,0,0,65935,0,65936,0,0,65935,0,0,0,0,66376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,65935,0,0,66158,66158,0,0,0,0,0,0,0,0,0,0,0,0,65936,65936,0,0,65936,65936,0,0,65755,65755,66390,66390,0,0, + 0,0,65936,65936,0,0,65936,65936,0,0,0,0,0,0,0,0,0,66389,66389,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66374,0,0,0,0,0,65894,65894,0,65934,0,0,0,0,0,0,66382,66382,66382,66382,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65932,0,0, + 0,0,0,0,0,0,0,0,66365,66365,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66388,0,0,0,0,65935,0,65935,0,65935,0,65935,0,65935,0,65935,0,65935,0,65935,0,65935,0,65935,0,65935, + 0,65935,0,0,65935,0,65935,0,65935,0,0,0,0,0,0,131471,0,0,131471,0,0,131471,0,0,131471,0,0,131471,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65935,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65756,65756,65756,65756,0,0,0,0,0,0,0,0,0,0,65935,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67213,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67212,0,67214,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67211, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67210,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,67209,0,0,0,0,0,0,0,0,0,0,0,0,0,67208,0,0,0, + 0,67207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,67205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67204,0,0,0, + 0,0,0,0,0,0,0,67203,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,67202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67201,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67200,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,67199,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,67198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,67197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,67196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67195,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,67194,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131892,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67193,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,67192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67191,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67190,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,67189,0,0,0,0,0,0,0,0,0,0,0,131890,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67188,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67187,0,0,0, + 0,0,0,0,0,0,0,0,67186,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66821,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131888,0,0,0,0,0,0, + 0,0,0,0,0,0,67185,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67184,0,0,0,0,0,0,0,0,0, + 0,0,0,67183,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67182,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,67181,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,67180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 67179,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,67178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67177,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67176,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67175,0,0,0,67172,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,67174,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,67173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,67171,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67170,0,0, + 0,67169,0,0,0,0,0,0,0,0,0,67168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67167,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67166,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67165,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67164,0, + 0,0,0,0,0,0,0,67163,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67162,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,67161,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,67160,0,0,0,0,0,0,0,67159,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67158,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67157,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,67156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,67155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,67154,0,0,0,0,0,0,0,0,0,0,67153,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67152,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66809,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66810,0,0,0,0,0,0,0,0,0,0,0,66804,0,0,0,0,0,67151,66806,0,0,0,67150,0,0, + 0,67149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66801,0,0,0,66807,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66803,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66808,0,0,0,0,0,0,0,0,0,0,0,67148,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66802,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 67147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66805,0,0,0,0,0,66798,0,0,0,0,66800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,131886,0,0,0,0,0,0,0,0,0,0,0,0,67146,0,0,0,66797, + 0,0,67145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66799,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67144,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67143,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67140,0,0,0,0,0,0,0,0,0,0,66790,0,0,0,0,0, + 0,0,0,0,0,0,0,131882,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66789,0,0,0,0,66794,0,0,0,0,0,0,0,131878,0,0,0,0,0,0,67138,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,67136,0,0,67137,66793,66782,0,0,0,66788,0,0,0,0,0,0,0,0,0,67135,0,0,0,0,0,0,0,0, + 66791,0,0,0,0,0,0,0,0,0,0,0,0,67134,0,0,0,0,67142,0,0,67141,0,67133,0,0,0,0,0,0,0,0, + 0,0,0,0,67132,0,0,0,0,0,0,0,67131,0,0,0,0,0,0,0,0,131876,0,66775,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66779,0,0,66778,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66776,0,66785,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67130,0,0,0,0,0,0,0,0,0,0, + 0,0,0,67129,0,0,0,131874,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66777,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66781,67128,0,0,0,0, + 0,0,0,0,0,0,67127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67126,0,0,0,0,67125,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66774,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66772,0,0,0,0, + 0,0,0,66773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67139,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,131872,0,131870,0,0,0,0,0,0,0,0,66769,0,0,0,0,0,0,0,0,0,0,0,66768,0, + 0,0,0,0,131866,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66770,0,0,0,0,131864,0,0,0,0,0, + 0,0,0,0,0,67124,67124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131862,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66771, + 0,0,0,0,0,0,0,0,0,67123,0,0,0,0,0,0,0,131860,0,0,0,0,0,0,0,0,67122,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67121,0,66764,0,0,0,0,0,0,0,66154,0,197225, + 0,0,0,66765,0,0,0,0,0,0,67120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67119, + 0,0,0,0,0,66760,0,0,0,0,0,67118,0,0,0,0,0,67117,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,67116,0,0,0,0,0,0,0,0,66766,0,0,0,0,0,0,0,0,0,0,0,0,0,66767,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67115,0,0,0,0,0,0,0, + 0,0,66763,0,0,0,0,0,67114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,67113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67112,0, + 0,0,67112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66318,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67111,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67109,0,66761,0,0,0,0,0,0,0,0,0,0, + 0,0,0,67108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,131884,0,0,66757,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131854,0,0,0,131800,0,0, + 0,0,0,0,0,0,0,0,0,0,0,67107,0,0,0,0,0,0,0,67106,0,0,0,0,0,0,0,0,0,0,0,0, + 66759,0,67105,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,131852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67104,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66758,0,0,0,0,0,0,0,0,0,0,0,67103,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66754,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67101,67102,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,67100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,67099,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67098,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,67097,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67096,67095,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66752,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131798,0,0,0,66747,0, + 0,0,0,0,0,0,0,0,66750,0,0,0,67094,0,0,0,0,0,0,66751,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66746,0,0,0,0,0,0,66745, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,67091,0,0,0,67093,0,0,0,0,67092,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,67090,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67089,0,0,0,0,0, + 0,0,67088,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66749,0,0,0,66741,0,0,0,0,0,0,0,0,66740,0,0,66748,0,0,0,0,0,0,0,0,0,0,0, + 0,0,67087,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66743,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67085,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,67084,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67083,0,0,0,0, + 0,0,0,0,0,0,0,67082,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66744,0,0,0,67081,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67086,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,67080,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66739,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131880,0, + 0,0,0,0,0,66738,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,67079,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67078,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,197222,0,0,0,0,0,0,66314,0,0,0,0,67077,0,0,0,0,0,0,0,0,0,0,0,67076, + 0,0,0,0,0,0,67075,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,67074,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66735, + 67072,0,66733,0,66737,66734,0,0,0,0,0,0,0,0,131850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,67071,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 67070,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66731,0,0,0,0,0,0, + 0,0,0,67069,0,0,0,0,0,0,0,0,0,0,0,0,66729,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,67068,0,0,67067,0,0,0,0,0,0,0,0,0,0,0,0,0,67066,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67073,0,0,0,0,0,0,0,66730,0,0,0,0,0, + 0,67065,67065,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67064,0,0, + 0,0,0,0,0,0,0,0,67063,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67062,0,0, + 0,0,0,0,0,0,0,0,0,67061,0,0,0,0,0,0,0,0,0,0,66723,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66726,0,0,0,0,0,0,0,0,0,67060,0,0,67059,0,0,67058,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66722,131848,0,0,0,0,0,0,0,66728,66725,0,0,0,0,0,66727,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,66720,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67057,0, + 0,0,0,0,66718,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,131868,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67054,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,67056,0,0,0,0,0,0,66724,0,67055,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66719,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67053,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66715,0,0,0,66721,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,67052,0,0,0,0,0,0,0,0,0,67051,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66714,0,0,0,67050,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66711,0,0,0,0,0,0,0,0,0,66713,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66717,0,0,0,0,0,0,0,0,0,0, + 0,67049,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131846,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,67048,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66714,0,0,0,0,0,0,0, + 0,66709,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66712,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66707,0,0,0,67047,0,0,0,131858,0,131844,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66710,0,0,0,0,0,0,0,66708,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67046,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,197219,0,66705,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,67045,0,0,0,0,0,0,0,0,0,0,67044,0,0,67043,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67042,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197213,0,0,0,131842,0,0,0,0,0,0,0,0,0, + 66703,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67041,0,0,0,0,0,0,0,0,0,0,67040,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66704,0,0,0,0,0,66706,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67039,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67038,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66693,0,0,0,0,0,66696,0,0,0,66701,67037,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67036,0,66695,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67035,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67034,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,67033,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66690,0,0,0,0, + 0,0,0,67032,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66689,0,0,0,0,0,0,0,0,67031,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66699,67030,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,67029,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66694,0,0,0, + 0,0,67028,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66692,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,67027,0,0,0,0,0,0,0,0,0,0,0,0,0,67026,0,0,0,0,0,0,67025,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66687,0,0,67024,0,0, + 0,0,0,0,66685,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131840,0,0,0,0,0,0,66688,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,67023,0,0,0,0,0,0,0,0,0,0,0,66681,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66682,0,0,0,0,0,0, + 0,0,0,0,0,66678,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66684,67022,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66679,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,67021,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131790,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66675,0,0,0,0,0,0,0,0,131834,0,0,0,0,0,0,0,0,0,0,67020,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66677,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66674,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66670,0,0,0,67019,0,0,0,0,0,0,0, + 67019,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197210,0,0,0,131832,0,0,0,0, + 0,67018,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66673,0,0,0,0,67017,0,0,66676,0,0,0,0,0,0,0,67016,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66671,0,0,0,0, + 0,0,0,0,0,67015,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66672,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66668,0,0,0,0,0,0,67014,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66666,0,0,0,0,0,0,0,67013, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67012,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,66664,0,0,0,131830,0,0,0,0,0,0,0,0,67011,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66665,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67010,0,0,0,0,0,0,0,0,0,0,0, + 0,0,67009,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,67008,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,67007,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,197201,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66663,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,67006,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66661,0,0,0,0,0,0,0,67005,0,0,0,0, + 0,0,0,0,66659,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,67004,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67003,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67002,0,0,0,0,66658,0,66662,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,67001, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66657,0,0,0,0,0,0,0,0,0,0,0,197198,66128,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,67000,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,66999,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66654,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66998, + 0,0,0,0,0,0,0,0,0,0,0,0,66651,66997,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,66655,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66996,0,0,0,0,66647,0,0,66653,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66995,0,0,0,0,0,0,0,0,0,66994,0, + 0,197195,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66993,66645,0,0,0,0,0,0,0,0,0,0,0,0,131824,66992,0,0,0,0,0,0,0, + 0,0,0,0,0,66991,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66648,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66643,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66646,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66990,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66649,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66989,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66988,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66641,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66642,0,0,0,0,0, + 0,0,0,0,0,0,0,66987,0,0,0,131818,0,0,0,0,0,66637,0,0,0,0,0,0,0,0,0,66644,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66638,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,131788,66639,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66986,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66985,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66633,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66635,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66984,0,0,131816,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66983,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66982,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66977,0,0,0,0,0,0,66981,0,0,0,0,0,66980,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66634,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66979,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66631,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66629,0,0,0,0,0,0, + 0,0,0,0,0,66978,0,0,0,66630,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,131780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66976,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66627,0,66628,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66624,0,0,0,0,0,0,0,0,0,0,66623,0,0,0,0, + 0,0,0,0,0,0,0,0,66975,0,0,66628,0,0,0,0,0,0,0,0,0,131814,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66974,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66622,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66973,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66972,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66626,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66625,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66620,0,0,0, + 0,0,0,0,0,0,0,0,0,0,131774,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66621,0,0,0,0,66971,0,0,0,0,0, + 0,0,0,0,0,0,0,131772,0,0,0,66970,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,66969,0,0,0,0,0,0,0,0,0,0,0,0,66618,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66610,0, + 0,0,0,0,0,0,66616,0,0,66615,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,66968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66967,0,0,0, + 0,0,0,0,0,0,0,0,0,66611,0,0,0,0,0,0,0,131812,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,66966,0,0,0,66609,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66612,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66965,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66614,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66964,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66613,0,0,66963,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66606,0,0,0,0,0,0, + 0,0,0,0,0,66605,0,0,0,0,0,0,0,0,0,0,131810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66604,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66962,0,0,0,0,0,0,0,0,0,0,0,0,66608,0,66607, + 0,0,66602,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66598,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,131766,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66603,0,0,0,0, + 0,0,0,0,0,0,0,66596,0,0,0,0,0,0,0,0,0,0,0,0,131808,0,0,0,0,0,0,0,0,0,0,0, + 0,66597,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66320,131856, + 66601,0,0,0,0,0,0,0,0,0,131806,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66961,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,66599,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66960,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66594,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,131792,0,0,0,0,66595,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66583,0,131802,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66582,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66587,0,66592,0, + 0,0,0,0,0,0,0,0,66591,66590,0,0,0,0,0,0,66589,0,0,0,0,0,131794,0,0,0,0,0,0,66588,66585,0, + 0,0,0,0,0,66584,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66575, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66586,66586,131786,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66579,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66576,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66959,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66574,0,0,0, + 131784,0,0,0,0,0,0,0,0,0,66958,0,0,0,0,66957,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,66577,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66578,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66573,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66956,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66572,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 131760,0,0,0,0,0,66955,0,0,66954,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66570,0, + 66564,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66571,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66569,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66568,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66953,0,0,0,66566,0,0,0,0,0,0,0,0,0, + 0,0,0,66952,0,0,0,66562,66951,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66563,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66560,0,0,0,0,0,0,0,0,0,0,0,0,66559,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66567,0,0,0,0, + 0,0,0,66949,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66557,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66556,0, + 0,0,0,0,0,0,0,66948,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197192,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66947,0,0,0,0,0,0,66561,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66554,0,0,0,0,0,0,0,0, + 0,66558,0,0,0,66946,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66555,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66553,0,0,0,0,0,0,66551,66945,0,0,0,0,0, + 0,0,0,0,0,66548,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66944,0,0,0,0,66549,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66550,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66943,0,0,0,0,0, + 0,66546,0,0,0,197189,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66547,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66942,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66545,66941,0,0,0,0,0,0,0,0,0,0,0,0,0,66543,0, + 0,0,0,0,0,0,0,0,0,0,0,66544,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66937,0,0,0,0,66940,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,66939,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66938,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66538,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66540,0,0,0,0,66542,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,131838,0,0,66936,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66541,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66537,0,0,0,0,0,0,0,0,0,131756,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66935,0,0,0,0,0,66934,0,0,0,0,0,0,0,0,0,0,0,66933,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66932,0,66931,0,0,0,0,0,0,0,0,0,66930,0,0, + 0,0,0,0,0,131782,66929,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66928,0,0, + 0,0,0,66927,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66536,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66539,66926,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,66925,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66924,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66923,0,0, + 0,0,0,0,0,0,0,0,0,66534,66922,0,66921,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66920,0,0,0, + 0,0,0,0,0,0,0,66919,0,0,0,0,0,0,0,66535,0,66533,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66531,0,0, + 0,0,0,0,0,0,0,0,0,66532,0,0,0,0,0,0,0,0,0,0,0,0,0,131778,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66529,0,0,66918,0,66917,0,0,0,0,0,0,0,0,66530,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66916,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66915,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66525,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66527,0,0,0,0,0, + 0,0,0,0,0,0,66524,0,0,0,0,0,0,0,0,0,0,0,66528,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66523,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66522, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66914,0,0,0,0,0,0,0,0,0,0,0,131776,0,0,0, + 0,0,0,0,0,0,0,66913,0,66912,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66911,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66909,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66908,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66907,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66906,0,0,0,0,0,0,0,0,0,0,0,0,0,131770,0,0,0,0,0,0, + 0,0,0,0,0,0,66905,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66518,0,0,0,0,0, + 0,66904,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,66903,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66514, + 0,0,0,0,0,0,0,0,0,0,0,0,66520,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66902,0,0,66901,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66512,0,0,0,0,0,0,0,0,0,0,0,0,66515,0,0,0,0,0,0,0,66900,0,0,0,0,0,0,66899,0, + 0,66513,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66510,0,66898,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66517,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,66519,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66507,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66516,0,0,0,0,66511,0,0,0,0,0,0,0,0,0,0,131754,0,0,0,0,0,0,0,0,0, + 66897,0,0,0,0,0,0,0,0,0,131746,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66509, + 0,0,0,0,0,0,0,0,0,0,0,66508,0,0,0,0,0,0,66506,0,0,0,66504,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,131768,0,0,0,0,0,0,0,0,0,0,131750,0,0,0,0,0,131744,0, + 0,131752,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131748,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66505,0,0,0,0,0,0,0, + 66502,0,0,0,0,0,0,0,0,0,131764,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66500,0,0,0,0,0,0,0,0,0,0,0,0,66896,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66895,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,66894,66499,0,0,0,0,0,66497,0,0,0,0,0,0,0,0,0,0,66501,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,131742,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66893,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66892,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66891,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66890,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66496,66889,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66490,0,0,0,0,0,0,0,0,0,66888,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66492,0,0,0,66493,0,0,0,0,0,0,0,0,0,0,0,0,0,131762,0,0,66495,0,0,0,0, + 0,0,66489,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66887,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66488,0,0,0,0,0,66494,0,0,0,0,0,0,0,0,0, + 0,0,0,66487,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131740,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66491,0,0,0,0,0,0,0,0,0,66485,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66481,0,0,0,0,66886,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66486,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66885,0,0,0,0,0,0,0,0,0,0,0,66483,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66884,0,0,0,0,0,0,0,0,0,66883,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66475,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66484,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66477,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,66478,0,0,66475,0,66473,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66474,0,0,0,66882,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66479,0,0,0,0,0,66881,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66880,66880,0,0,0,0,0,0,0, + 0,0,0,0,66470,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66472,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66879,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66878,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66877,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66465,0,0,0,0,0,0,0,0,0,66876,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66463,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66457,0,66464,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66454,0,0,66461,0,0,0,66466,0,0,0, + 0,0,0,0,0,0,66460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,66459,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66462,66456,0,0,0,0,0,0,0, + 0,0,0,66875,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66458,131738,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66453,66451,0,0,0,0,0,0,0,0, + 0,0,0,66874,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66450,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66452,0,0,0,0,0,0,0,0,0,0,0,0,0,131736,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66455,0,0,0,0, + 66873,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131734, + 0,0,0,0,0,0,0,0,0,0,0,197207,0,0,0,0,0,0,0,0,0,0,0,0,66449,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66872,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131732,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66448,0, + 0,0,66871,0,0,0,0,0,0,0,0,0,0,0,0,66447,0,0,0,0,0,0,0,0,0,0,0,0,66446,0,0,0, + 0,0,0,0,0,0,0,0,66445,66870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,66869,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,66868,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66444,0,0,0,0,0,0,0,0,0,0,0,0,66867,0, + 0,0,0,0,0,0,0,0,0,0,66443,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131758,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66441,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66866,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66440,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66865,0,0, + 0,0,0,0,0,0,0,66864,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66439,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66435,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66434,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66432, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66433,0,0,0,0,0,0,0,66437, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66863,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66431,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66862,0,0,0,0,66861,0, + 0,0,0,0,0,66860,0,0,0,0,0,0,0,0,0,66859,0,0,0,0,0,0,66858,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66857,0,0,0,0, + 0,0,0,66438,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66430,66436,0,0,0,0,0,0,0,0,0,0,0,0,0,197186,0,0,0, + 0,0,0,0,0,0,0,0,0,131692,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65888,0,0,0,0,0,0,0,66374,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65935,0,65935,0,0,0,0, + 0,0,0,0,0,65755,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65930,65930,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,65935,0,65935,0,0,0,0,0,0,65933,0,0,0,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,197156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197144,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65933,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,262582,0, + 0,131512,65894,0,0,0,0,0,0,65779,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,65755,0,0,0,65935,0,65935,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65977,65977,0,0,0,0,0,0,328079, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,65936,65936,131506,131506,0,0,0, + 0,0,66856,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66853,0,0,0, + 0,0,0,0,0,66854,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66850,0,0,0,0,0, + 0,0,0,0,66851,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66849,0, + 0,0,0,0,0,0,0,0,0,0,0,0,66848,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,66847,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66846,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66845,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66844,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66843,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66842,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66841,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66840,0,66840,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,66838,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66839, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,131804,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66837,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,66364,0,0,0,0,0,66363,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,66836,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66835,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66834,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66830,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66833, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66832,0,0,0,0,0,0,0,0,66831,0,0,0, + 0,0,0,66829,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66362,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66828,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,66827,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,66826,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66825,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66824,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66823,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66822,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66820,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66819,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66818,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,66817,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66361,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66816,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66815,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66814,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66813,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66812,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66811,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,66796,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66795,0,0,0,0,0,0,0, + 0,0,0,0,66792,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66787,66786,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66784,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66783,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,66360,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66762,0,0, + 0,0,0,0,0,0,66756,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66755,0,0,0,0,0, + 0,0,0,0,0,66753,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66742,0,0,0, + 0,0,0,0,0,0,0,131796,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66736,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66732,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66359,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66716,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66698,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66702,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,66700,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66697,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66691,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66686,0,0,0,0,0, + 0,0,0,66683,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,66669,0,0,0,0,0,0,0,0,0,0,0,0,0,66667,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66660,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66656,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66652,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,66650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,66640,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66636,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66632,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66617,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,66600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66593,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,66581,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,66565,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66358,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66552,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66528,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,66526,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66521,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66503,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66498,0,0,0,0,0,0,0,0, + 0,0,0,0,0,66482,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66471, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66476,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,66469,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66468,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66467,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66442,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66429,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,66428,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,66427,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66426,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66425,0,0,0,0,0,0,0,0,0,0,0,0,0, + 66424,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +KBTS_INLINE kbts_u32 kbts_GetUnicodeParentInfo(kbts_u32 Codepoint) +{ + return kbts_UnicodeParentInfo_Data[((kbts_un)kbts_UnicodeParentInfo_PageIndices[Codepoint/32] * 32) | (Codepoint & 31)]; +} + +static kbts_u8 kbts_UnicodeUseClass_PageIndices[4351] = { + 0,1,1,1,1,1,2,3,4,5,6,7,8,9,10,11,12,1,1,1,1,1,1,13,14,15,16,17,18,19,1,1, + 20,1,1,1,1,21,1,22,1,1,1,1,1,23,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,25,26,27,28,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,29,1,1,1,1,30,31,1,32,33,34,35,36,37,38,39,40,41,42,43,44,45,1,46,47,48,49, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,50,50,50,50,51,50,50,50,50,50,50,50,50,50,50,50, + 50,50,50,52,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,53,1,1,1,1,1,1,1,1,54,55,1,56,1,57,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,58,59,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,60,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,61,62,1,63,64,1,1,1,65,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +}; + +static kbts_u8 kbts_UnicodeUseClass_Data[16896] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,21,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,29,29,29,29,29,29,29,29,29,0,0,0,0,0,0,1,0,0,29,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,9,9,9,0,0,0,0,1,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,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,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,34,36,9,1,36,33, + 36,35,35,35,35,34,34,34,34,36,36,36,36,3,33,36,0,29,30,0,0,34,35,35,1,1,1,1,1,1,1,1,1,1,35,35,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,29,31,31,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,0,9,1,36,33, + 36,35,35,35,35,0,0,33,33,0,0,33,33,3,0,0,0,0,0,0,0,0,0,36,0,0,0,0,1,1,0,1,1,1,35,35,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,6,0, + 0,29,29,31,0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,0,9,0,36,33, + 36,35,35,0,0,0,0,34,34,0,0,34,34,3,0,0,0,30,0,0,0,0,0,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,29,8,2,2,0,12,0,0,0,0,0,0,0,0,0,0, + 0,29,29,31,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,9,1,36,33, + 36,35,35,35,35,34,0,34,34,34,0,36,36,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,35,35,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,29,8,29,8,8,8, + 0,29,31,31,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,9,1,36,34, + 36,35,35,35,35,0,0,33,33,0,0,33,33,3,0,0,0,0,0,0,0,34,34,34,0,0,0,0,1,1,0,1,1,1,35,35,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,29,0,0,1,1,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,36,36, + 34,36,36,0,0,0,33,33,33,0,33,33,33,3,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,31,31,31,29,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,9,1,34,34, + 34,36,36,36,36,0,34,34,34,0,34,34,34,3,0,0,0,0,0,0,0,34,35,0,1,1,1,0,0,0,0,0,1,1,35,35,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,29,31,31,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,9,1,36,34, + 34,36,36,36,36,0,34,34,34,0,34,34,34,3,0,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,1,0,1,1,35,35,0,0,1,1,1,1,1,1,1,1,1,1,0,37,37,31,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,31,31,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,34,34,1,36,36, + 36,35,35,35,35,0,33,33,33,0,33,33,33,3,38,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,1,1,1,35,35,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,29,31,31,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,0, + 1,1,1,1,1,1,1,0,0,0,4,0,0,0,0,36,36,36,34,34,35,0,35,0,36,33,33,33,33,33,33,36,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,36,36,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,34,1,1,34,34,34,34,35,35,35,0,0,0,0,0, + 1,1,1,1,1,1,0,34,29,29,29,29,8,29,34,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,34,1,1,34,34,34,34,35,35,35,34,12,1,0,0, + 1,1,1,1,1,0,0,0,29,29,29,29,0,29,6,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,0,6,0,6,0,8,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,9,35,34,34,35,34,34,34,34,35,35,35,35,29,0, + 35,34,29,29,35,0,29,29,1,1,1,1,1,7,7,7,7,7,7,7,7,7,7,7,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0, + 0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,36,34,34,35,35,33,34,34,34,34,29,30,31,6,34,13,10,12,12,1, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,36,36,35,35,1,1,1,1,12,12,12,1,36,31,31,1,1,36,36,31,31,31,31,31,1,1,1,34,34,34,34,1,1,1,1,1,1,1,1,1,1,1, + 1,1,12,36,33,34,34,31,31,31,31,31,31,30,1,31,1,1,1,1,1,1,1,1,1,1,31,31,36,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,34,35,35,36,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,1,1,1,34,35,36,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,1,1,34,35,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,0,1,1,1,0,34,35,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,36,34,34,34,34,35,35,35,33,33, + 33,33,33,33,33,33,29,31,36,29,29,6,14,8,6,29,6,34,6,6,0,0,0,0,0,0,0,0,1,6,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0, + 2,2,2,2,2,8,8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,34,34,35,36,36,34,34,34,34,7,7,7,0,0,0,0,16,16,30,16,16,16,16,16,16,15,29,6,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,31,31,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,34,34,33,36,34,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,12,7,14,14,11,7,7,7,7,0,5,36,34,36,36,34,34,34,34,35,35,34,35,36,33,33,33,33,33,34,29,29,29,29,29,29,34,29,29,0,0,30, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,14,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,8,36,34,34,35,35,35,35,34,34,33,33, + 33,33,34,34,3,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,14,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,7,7,7,34,35,33,36,34,34,36,6,7,7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,8,36,34,34,36,36,36,34,36,34,14,14,17,17,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,7,7,36,33,33,33,36,36,35,14,14,14,14,14,14,14,32,32,0,9,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,29,29,0,30,30,30,30,30,30,29,29,30,30,30,30,29,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,37,37,31,29,29,2,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,39,1,0,0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0, + 0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2,2,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,21,19,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,21,19,21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,34,1,1,1,3,1,1,1,1,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,36,35,34,36,0,0,0,0,35,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, + 31,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,13,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,3,29,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,1,1,0,0,0,0,0,0,0,0,0,0,1,34, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,34,34,34,34,34,30,30,30,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,35,35,35,34,35,35,35,35,14,14,14,16,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,14,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,8,36,36,34,34,35,35,33,33,34,12,13,12, + 3,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,0,0,0,0,0,0,1,1,1,1,1,34,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,29,34,34,34,35,34,33,33,34,35,13,10,11,12,0,0,0,0,0,0,0,0,0, + 1,1,1,14,1,1,1,1,1,1,1,1,14,16,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,2,2,2,0,0,0,1,31,29,31,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,35,1,35,35,34,1,1,35,35,1,1,1,1,1,35,29, + 1,29,1,0,0,0,0,0,0,0,0,0,0,0,0,0,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,33,35,34,33,36,0,0,0,0,0,31,6,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,36,34,36,36,35,36,36,0,31,35,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,35,35,35,0,34,35,0,0,0,0,0,36,30,30,29,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,9,9,9,0,0,0,0,6, + 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,29,29,29,8,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,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,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,34,34,34,34,34,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,34,34,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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, + 1,1,1,1,1,1,30,30,30,30,30,30,30,30,30,30,30,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,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, + 1,1,9,9,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1, + 0,1,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 31,29,31,37,37,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,34,34,34,34,35,35,35,35, + 35,35,34,34,34,34,3,0,0,0,0,0,0,0,0,0,0,0,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,1,1,1,1,1,1,1,1,1,1,34,1,1,34,34,1,0,0,0,0,0,0,0,0,0,40, + 29,29,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,33,36,35,35,34,34,36,36,3,9,0,0,0,0,0, + 0,0,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,29,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,35,35,35,34,34,33,35,34,34,35,34,34,6,8,0,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,1,36,36,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,0,0,0,0,0,0,0,0,0,0,0,0, + 29,29,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,33,36,35,35,35,35,35,35,34,34,34,34, + 3,1,38,38,0,0,0,0,0,6,9,34,35,0,33,29,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,36,36,35,34,34,34,34,29,3,8,8,0,0,0,0,0,0,29,1, + 1,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,29,36,33,36,35,35,34,34,34,34,9,35,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 29,29,31,31,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,9,9,1,36,36, + 34,36,36,36,36,0,0,33,33,0,0,33,33,3,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,1,1,1,1,36,36,0,0,29,29,29,29,29,29,29,0,0,0,29,29,29,29,29,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,36,34,34,35,35,35,35,35, + 35,0,33,0,0,33,0,33,33,36,31,0,31,31,29,9,6,38,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,30,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,33,36,35,35,35,35,35,35,34,34, + 36,36,3,29,29,31,9,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,6,1,37,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,33,36,35,35,35,35,35,35,33,34,33,33,36,33,29, + 29,31,3,9,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,33,36,35,35,35,35,0,0,33,33,33,33,29,29,31,3, + 9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,35,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,36,36,35,35,35,35,35,35,34,34,36,36,29,31,3, + 34,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,29,31,34,33,36,35,35,34,34,34,34,3,9,1,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,0,0,12,3,11,36,36,34,34,35,35,33,34,35,34,34,34,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, + 1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,33,36,35,35,35,35,34,34,34,34,29,31,3,9,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,36,36,36,36,33,0,33,33,0,0,29,29,36,6,38, + 13,38,13,9,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,33,36,35,35,35,35,0,0,34,34,36,36,31,31,3,1,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,34,35,35,34,34,34,34,34,34,35,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,6,35,29,29,29,29,31,37,7,7,7,7,0, + 0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,1,34,35,35,34,34,34,36,36,35,35,35,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,38,38,38,38,38,38,15,15,15,15,15,15,15,15,15,15,15,15,29,31,8,6,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,34,34,35,35,35,35,35,0,34,34,34,34,29,29,31,3, + 1,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,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,7,7,7,7,7,7,7,35,33,35,34,36,29,29,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,34,34,34,34,34,35,0,0,0,34,0,34,34,0,34, + 29,29,9,34,35,6,38,12,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,36,36,36,36,36,0,34,34,0,36,36,29,31,6,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,2,34,35,33,36,0,0,0,0,0,0,0,0,0, + 29,29,38,31,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,36,34,34,35,35,35,0,0,0,33,33, + 34,36,6,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,22,22,22,22,22,22,22,19,21,22,22,22,18,18,18,18, + 23,18,18,18,18,18,18,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,0,0,0,0,0,0,0,0,0,0,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,34,34,34,34,34,34,34,34,34,34,34,34,10,10,13,29,12,35,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,29,29,29,29,29,29,29,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 31,31,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,36,36,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,9,0,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35, + 35,35,35,35,35,35,35,35,0,0,0,0,0,0,0,30,30,30,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0, + 1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,29,29,29,29,29,29,29,1,1,1,1,1,1,1,0,0, + 1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,29,0,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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,29,29,29,29,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 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,1,1,1,1,1,1,1,1,1,1,1,1,34,34,34,34,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 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,1,1,1,1,1,1,1,1,1,1,1,1,1,1,35,35,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,8,8,8,8,8,8,8,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +KBTS_INLINE kbts_u8 kbts_GetUnicodeUseClass(kbts_u32 Codepoint) +{ + return kbts_UnicodeUseClass_Data[((kbts_un)kbts_UnicodeUseClass_PageIndices[Codepoint/256] * 256) | (Codepoint & 255)]; +} + +KBTS_INLINE kbts_u32 kbts_GetDecompositionSize(kbts_u64 Decomposition) +{ + return Decomposition & 3; +} + +KBTS_INLINE kbts_u32 kbts_GetDecompositionCodepoint(kbts_u64 Decomposition, kbts_un Index){ + return (Decomposition >> (Index ? 23 : 2)) & 0x1FFFFF; +} + +#define KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE0 (1ull << 44) +#define KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE1 (1ull << 45) + +KBTS_INLINE kbts_u32 kbts_GetMatchingBracket(kbts_u64 Decomposition) +{ + return (Decomposition >> 23) & 0x1FFFFF; +} + +KBTS_INLINE kbts_u32 kbts_GetUnicodeMatchingBracket(kbts_u32 Codepoint) +{ + kbts_u64 Decomposition = kbts_GetUnicodeDecomposition(Codepoint); return (Decomposition >> 23) & 0x1FFFFF; +} + +KBTS_INLINE kbts_u8 kbts_GetSyllabicClass(kbts_u16 SyllabicInfo) +{ + return SyllabicInfo & 0xFF; +} + +KBTS_INLINE kbts_u8 kbts_GetSyllabicPosition(kbts_u16 SyllabicInfo) +{ + return SyllabicInfo >> 8; +} + +KBTS_INLINE kbts_s32 *kbts_GetParentInfoDeltas(kbts_u32 ParentInfo) +{ + return kbts_UnicodeParentDeltas + (ParentInfo & 0xFFFF); +} + +KBTS_INLINE kbts_un kbts_GetParentInfoCount(kbts_u32 ParentInfo) +{ + return ParentInfo >> 16; +} + +typedef kbts_u8 kbts_grapheme_break_class; +enum kbts_grapheme_break_class_enum { + /* 0 */ KBTS_GRAPHEME_BREAK_CLASS_DEFAULT, + /* 1 */ KBTS_GRAPHEME_BREAK_CLASS_CR, + /* 2 */ KBTS_GRAPHEME_BREAK_CLASS_LF, + /* 3 */ KBTS_GRAPHEME_BREAK_CLASS_Control, + /* 4 */ KBTS_GRAPHEME_BREAK_CLASS_Extend, + /* 5 */ KBTS_GRAPHEME_BREAK_CLASS_ZWJ, + /* 6 */ KBTS_GRAPHEME_BREAK_CLASS_SpacingMark, + /* 7 */ KBTS_GRAPHEME_BREAK_CLASS_L, + /* 8 */ KBTS_GRAPHEME_BREAK_CLASS_V, + /* 9 */ KBTS_GRAPHEME_BREAK_CLASS_LV, + /* 10 */ KBTS_GRAPHEME_BREAK_CLASS_LVT, + /* 11 */ KBTS_GRAPHEME_BREAK_CLASS_T, + /* 12 */ KBTS_GRAPHEME_BREAK_CLASS_Prepend, + /* 13 */ KBTS_GRAPHEME_BREAK_CLASS_IndicConsonant, + /* 14 */ KBTS_GRAPHEME_BREAK_CLASS_IndicExtend, + /* 15 */ KBTS_GRAPHEME_BREAK_CLASS_IndicLinker, + /* 16 */ KBTS_GRAPHEME_BREAK_CLASS_ExtendedPictographic, + /* 17 */ KBTS_GRAPHEME_BREAK_CLASS_RI, + + KBTS_GRAPHEME_BREAK_CLASS_COUNT, +}; + +typedef kbts_u8 kbts_grapheme_break_state; +enum kbts_grapheme_break_state_enum { + /* 0 */ KBTS_GRAPHEME_BREAK_STATE_START, + /* 1 */ KBTS_GRAPHEME_BREAK_STATE_CR, + /* 2 */ KBTS_GRAPHEME_BREAK_STATE_L, + /* 3 */ KBTS_GRAPHEME_BREAK_STATE_LVxV, + /* 4 */ KBTS_GRAPHEME_BREAK_STATE_LVTxT, + /* 5 */ KBTS_GRAPHEME_BREAK_STATE_IndicConsonantxIndicLinker, + /* 6 */ KBTS_GRAPHEME_BREAK_STATE_IndicExtendr, + /* 7 */ KBTS_GRAPHEME_BREAK_STATE_IndicExtendLinkerr, + /* 8 */ KBTS_GRAPHEME_BREAK_STATE_ExtendedPictographic, + /* 9 */ KBTS_GRAPHEME_BREAK_STATE_ExtendR, + /* 10 */ KBTS_GRAPHEME_BREAK_STATE_ExtendR_ZWJ, + /* 11 */ KBTS_GRAPHEME_BREAK_STATE_RI, + /* 12 */ KBTS_GRAPHEME_BREAK_STATE_SKIP, + + /* 13 */ KBTS_GRAPHEME_BREAK_STATE_COUNT, + + /* 14 */ KBTS_GRAPHEME_BREAK_STATE_b0, + /* 15 */ KBTS_GRAPHEME_BREAK_STATE_b01, + // The values below have to be in the same order as their corresponding states. + /* 16 */ KBTS_GRAPHEME_BREAK_STATE_b1, + /* 17 */ KBTS_GRAPHEME_BREAK_STATE_b1toCR, + /* 18 */ KBTS_GRAPHEME_BREAK_STATE_b1toL, + /* 19 */ KBTS_GRAPHEME_BREAK_STATE_b1toLVxV, + /* 20 */ KBTS_GRAPHEME_BREAK_STATE_b1toLVTxT, + /* 21 */ KBTS_GRAPHEME_BREAK_STATE_b1toIndicConsonantxIndicLinker, + /* 22 */ KBTS_GRAPHEME_BREAK_STATE_PADDING0, + /* 23 */ KBTS_GRAPHEME_BREAK_STATE_PADDING1, + /* 24 */ KBTS_GRAPHEME_BREAK_STATE_b1toExtendedPictographic, + /* 25 */ KBTS_GRAPHEME_BREAK_STATE_PADDING2, + /* 26 */ KBTS_GRAPHEME_BREAK_STATE_PADDING3, + /* 27 */ KBTS_GRAPHEME_BREAK_STATE_b1toRI, + /* 28 */ KBTS_GRAPHEME_BREAK_STATE_b1toSKIP, +}; + +// In the SKIP column, CR, LF and Control all still break before the cursor +// because their rules have a higher priority. +// In Indic-related states, ZWJ should behave like an Indic Extend. +static kbts_grapheme_break_state kbts_GraphemeBreakTransition[KBTS_GRAPHEME_BREAK_CLASS_COUNT][KBTS_GRAPHEME_BREAK_STATE_COUNT] = { + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 */ + /* 0 */ {16,16,16,16,16,16,16,16,16,16,16,16, 0}, + /* 1 */ {17,17,17,17,17,17,17,17,17,17,17,17,17}, + /* 2 */ {15,14,15,15,15,15,15,15,15,15,15,15,15}, + /* 3 */ {15,15,15,15,15,15,15,15,15,15,15,15,15}, + /* 4 */ { 0,16, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0}, + /* 5 */ { 0,16, 0, 0, 0, 6, 6, 7,10,10, 0, 0, 0}, + /* 6 */ { 0,16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + /* 7 */ {18,18, 2,18,18,18,18,16,18,18,18,18, 2}, + /* 8 */ {19,19, 3, 3,19,19,19,16,19,19,19,19, 3}, + /* 9 */ {19,19, 3,19,19,19,19,16,19,19,19,19, 3}, + /* 10 */ {20,20, 4,20,20,20,20,16,20,20,20,20, 4}, + /* 11 */ {20,20,20, 4, 4,20,20,16,20,20,20,20, 4}, + /* 12 */ {28,28,28,28,28,28,28,28,28,28,28,28,12}, + /* 13 */ {21,21,21,21,21,21,21, 5,21,21,21,21, 5}, + /* 14 */ { 0,16, 0, 0, 0, 6, 6, 7, 9, 9, 0, 0, 0}, + /* 15 */ { 5,21, 5, 5, 5, 7, 7, 7, 5, 5, 5, 5, 5}, + /* 16 */ {24,24,24,24,24,24,24,16,24,24, 0,24, 8}, + /* 17 */ {27,27,27,27,27,27,27,27,27,27,27, 0,11}, +}; + +// These classes are for Indic, Myanmar and Khmer. +typedef kbts_u8 kbts_indic_syllabic_class; +enum kbts_indic_syllabic_class_enum { + /* 0 A */ KBTS_INDIC_SYLLABIC_CLASS_OTHER, + /* 1 B */ KBTS_INDIC_SYLLABIC_CLASS_CONSONANT, + /* 2 C */ KBTS_INDIC_SYLLABIC_CLASS_VOWEL, + /* 3 D */ KBTS_INDIC_SYLLABIC_CLASS_NUKTA, + /* 4 E */ KBTS_INDIC_SYLLABIC_CLASS_HALANT, + /* 5 F */ KBTS_INDIC_SYLLABIC_CLASS_ZWNJ, + /* 6 G */ KBTS_INDIC_SYLLABIC_CLASS_ZWJ, + /* 7 H */ KBTS_INDIC_SYLLABIC_CLASS_MATRA, + /* 8 I */ KBTS_INDIC_SYLLABIC_CLASS_SYLLABLE_MODIFIER, + /* 9 J */ KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN, + /* 10 K */ KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER, + /* 11 L */ KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE, + /* 12 M */ KBTS_INDIC_SYLLABIC_CLASS_REGISTER_SHIFTER, + /* 13 N */ KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST, + /* 14 O */ KBTS_INDIC_SYLLABIC_CLASS_REPHA, + /* 15 P */ KBTS_INDIC_SYLLABIC_CLASS_RA, + /* 16 Q */ KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL, + /* 17 R */ KBTS_INDIC_SYLLABIC_CLASS_SYMBOL, + /* 18 S */ KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER, + /* 19 T */ KBTS_INDIC_SYLLABIC_CLASS_SYLLABLE_MODIFIER_POST, + /* 20 U */ KBTS_INDIC_SYLLABIC_CLASS_VOWEL_ABOVE, + /* 21 V */ KBTS_INDIC_SYLLABIC_CLASS_VOWEL_BELOW, + /* 22 W */ KBTS_INDIC_SYLLABIC_CLASS_VOWEL_PRE, + /* 23 X */ KBTS_INDIC_SYLLABIC_CLASS_VOWEL_POST, + /* 24 Y */ KBTS_INDIC_SYLLABIC_CLASS_ROBATIC, + /* 25 Z */ KBTS_INDIC_SYLLABIC_CLASS_X_GROUP, + /* 26 a */ KBTS_INDIC_SYLLABIC_CLASS_Y_GROUP, + /* 27 b */ KBTS_INDIC_SYLLABIC_CLASS_ASAT, + /* 28 c */ KBTS_INDIC_SYLLABIC_CLASS_DOT_BELOW, + /* 29 d */ KBTS_INDIC_SYLLABIC_CLASS_SYLLABLE_MOD, + /* 30 e */ KBTS_INDIC_SYLLABIC_CLASS_MEDIAL_HA, + /* 31 f */ KBTS_INDIC_SYLLABIC_CLASS_MEDIAL_RA, + /* 32 g */ KBTS_INDIC_SYLLABIC_CLASS_MEDIAL_WA, + /* 33 h */ KBTS_INDIC_SYLLABIC_CLASS_MEDIAL_YA, + /* 34 i */ KBTS_INDIC_SYLLABIC_CLASS_PWO, + /* 35 j */ KBTS_INDIC_SYLLABIC_CLASS_VARIATION_SELECTOR, + /* 36 k */ KBTS_INDIC_SYLLABIC_CLASS_MEDIAL_MON_LA, + + KBTS_MYANMAR_SYLLABIC_CLASS_COUNT, + KBTS_INDIC_SYLLABIC_CLASS_COUNT = KBTS_INDIC_SYLLABIC_CLASS_SYLLABLE_MODIFIER_POST + 1, + KBTS_KHMER_SYLLABIC_CLASS_COUNT = KBTS_INDIC_SYLLABIC_CLASS_Y_GROUP + 1, +}; + +#define KBTS_INDIC_SYLLABIC_STATE_COUNT 41 +#define KBTS_MYANMAR_SYLLABIC_STATE_COUNT 31 +#define KBTS_KHMER_SYLLABIC_STATE_COUNT 23 + +// @Incomplete: Decrement every state by 1. +static kbts_u8 kbts_IndicSyllabicTransition[KBTS_INDIC_SYLLABIC_CLASS_COUNT][KBTS_INDIC_SYLLABIC_STATE_COUNT] = { + /* 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 */ + /* A */ {43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,}, + /* B */ {14,43,43,43,43,43,43,14,43,43,43,43,43,43,43,14,43,14,43,43,43,43,43,43,43,14,43,43,43,43,43,43,14,43,43,14,43,43,14,43,14,}, + /* C */ {30,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,30,43,43,43,43,43,43,43,43,43,43,43,43,30,43,43,}, + /* D */ {24,43,24,20,43,43,31,43,43,43, 7,43,43,24,43,33,43,43,43,43,43,43,43,12,43,24,43,43,43, 7,43,24,43,43,43,33,15,43,24,24,43,}, + /* E */ { 8,43, 8,21,27,43, 8,43,18,18, 8, 8,18, 8,43,43,43,43,43,21,43,43,43, 8,18, 8,43,38,43, 8, 8, 8,43,43,18,18,43,43, 8,26,43,}, + /* F */ {25,43,13,22,28, 2,13,15,19,19,13,13,19,25,29,29, 2,29,19,22,22,19, 2,13,19,35,15,19,43, 9,13,25,29,43,22,22,29,29,25,25,43,}, + /* G */ {13,43,13,22,28,43,10,16,19,19,10,13,19,32,29,29,43,16,19,22,22,19,43,13,19,36,37,19,43,10,10,13,29,43,22,22,29,37,13,32,43,}, + /* H */ { 4,43, 4, 4, 4,43, 4,43, 4, 4, 4, 4, 4, 4,43,43,43,43, 4, 4, 4, 4,43, 4, 4, 4,43, 4,43, 4, 4, 4,43,43, 4, 4,43,43, 4, 4,43,}, + /* I */ { 6,43, 6, 6, 6,23, 6,17, 6, 6, 6, 6, 6, 6,17,17,23,17,34, 6, 6, 6,43, 6, 6, 6,17, 6,17, 6, 6, 6,17,43, 6, 6,17,17, 6, 6,43,}, + /* J */ { 2, 2, 2, 2, 2, 2, 2, 2,43,43, 2, 2,43, 2, 2, 2, 2, 2,43, 2, 2,43, 2, 2,43, 2, 2,43,43, 2, 2, 2, 2,43, 2, 2, 2, 2, 2, 2,43,}, + /* K */ {32,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,32,43,32,}, + /* L */ {32,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,32,43,43,43,43,43,43,43,43,43,43,43,43,32,43,43,}, + /* M */ { 3,43,43,43,43,43,43,43,11,43,43,43,43, 3,43,43,43,43,43,43,43,43,43,43, 3, 3,43,43,43,11,43, 3,43,43, 3,43,43,43, 3, 3,43,}, + /* N */ { 4,43, 4, 4, 4, 4, 4,43, 4, 4, 4, 4, 4, 4,43,43,43,43, 4, 4, 4, 4,43, 4, 4, 4,43, 4,43, 4, 4, 4,43, 4, 4, 4,43,43, 4, 4,43,}, + /* O */ {39,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,}, + /* P */ {40,43,43,43,43,43,43,14,43,43,43,43,43,43,43,14,43,14,43,43,43,43,43,43,43,14,43,43,43,43,43,43,14,43,43,14,43,43,14,43,14,}, + /* Q */ { 5,43, 5,43,43,43, 5,43,43,43, 5, 5,43, 5,43,43,43,43,43,43,43,43,43, 5,43, 5,43,43,43, 5, 5, 5,43,43,43,43,43,43, 5, 5,43,}, + /* R */ {37,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,}, + /* S */ {41,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,}, + /* T */ { 6,43, 6, 6, 6,23, 6,17, 6, 6, 6, 6, 6, 6,17,17,23,17,34, 6, 6, 6,43, 6, 6, 6,17, 6,17, 6, 6, 6,17,43, 6, 6,17,17, 6, 6,43,}, +}; + +// @Incomplete: Decrement every state by 1. +static kbts_u8 kbts_MyanmarSyllabicTransition[KBTS_MYANMAR_SYLLABIC_CLASS_COUNT][KBTS_MYANMAR_SYLLABIC_STATE_COUNT] = { + /* 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 */ + /* A */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* B */ {18,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,18,33,33,33,33,33,33,33,33,18,18,33,18,}, + /* C */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* D */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* E */ {19,33,33,33,33,33,33,33,33,33,33,33,33,33,33,28,33,28,19,29,33,33,33,33,33,33,33,18,19,28,18,}, + /* F */ { 2,33, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,33, 2, 2,33,}, + /* G */ { 2,33, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,33, 2, 2,33,}, + /* H */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* I */ { 3,33, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,33, 3, 3,33,}, + /* J */ { 4,33,33, 4, 4, 4, 4, 4, 4,33, 4, 4, 4, 4,15, 4, 4, 4, 4, 4, 4, 4, 4, 4,33, 4,33,33, 4, 4, 4,}, + /* K */ {18,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,18,33,18,}, + /* L */ {18,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,18,33,18,}, + /* M */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* N */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* O */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* P */ {30,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,18,33,33,33,33,33,33,33,33,18,18,33,18,}, + /* Q */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* R */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* S */ {31,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* T */ { 3,33, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,33, 3, 3,33,}, + /* U */ { 5,33,33,33, 5,33, 5,22, 5,33, 5, 5, 5, 5,33, 5, 5, 5, 5, 5, 5,22,22,22,33, 5,33,33, 5, 5,33,}, + /* V */ { 6,33,33,33, 6, 6, 6,33, 6,33, 6, 6, 6, 6,33, 6, 6, 6, 6, 6, 6,33,33,33,33, 6,33,33, 6, 6,33,}, + /* W */ { 7,33,33,33,33,33, 7,33, 7,33, 7, 7, 7, 7,33, 7, 7, 7, 7, 7, 7,33,33,33,33, 7,33,33, 7, 7,33,}, + /* X */ { 8,33,33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,33,33, 8, 8,33,}, + /* Y */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* Z */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* a */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* b */ { 9,33,33,33,33,33,33,23, 9,25,21,33,21,26, 3, 9,21, 9, 9, 9,33,33,23,23,33,33, 3,33, 9,20,33,}, + /* c */ {10,33,33,10,10,10,10,10,10,33,10,10,10,10,27,10,10,10,10,10,10,10,10,10,33,10,33,33,10,10,33,}, + /* d */ {33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,}, + /* e */ {11,33,33,33,33,33,33,24,11,33,33,11,11,11,33,11,33,11,11,11,33,33,33,33,33,11,33,33,11,11,33,}, + /* f */ {12,33,33,33,33,33,33,33,12,33,33,33,33,12,33,12,33,12,12,12,33,33,33,33,33,12,33,33,12,12,33,}, + /* g */ {13,33,33,33,33,33,33,33,13,33,33,13,33,13,33,13,33,13,13,13,33,33,33,33,33,13,33,33,13,13,33,}, + /* h */ {14,33,33,33,33,33,33,33,14,33,33,33,33,33,33,14,33,14,14,14,33,33,33,33,33,33,33,33,14,14,33,}, + /* i */ {15,33,15,15,15,15,15,15,15,15,15,15,15,15,33,15,15,15,15,15,15,15,15,15,15,15,15,33,15,15,33,}, + /* j */ {16,33,33,33,33,33,21,33,33,33,33,33,33,33,33,33,33,16,16,33,33,33,33,33,33,33,33,33,16,16,33,}, + /* k */ {17,33,33,33,33,33,33,23,17,33,17,17,17,17,33,17,33,17,17,17,33,33,33,23,33,17,33,33,17,17,33,}, +}; + +// @Incomplete: Decrement every state by 1. +static kbts_u8 kbts_KhmerSyllabicTransition[KBTS_KHMER_SYLLABIC_CLASS_COUNT][KBTS_KHMER_SYLLABIC_STATE_COUNT] = { + /* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 */ + /* A */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* B */ {15,25,25,25,25,18,25,25,25,25,25,25,25,25,25,25,25,25,25,25, 2,25,25,}, + /* C */ {15,25,25,25,25,18,25,25,25,25,25,25,25,25,25,25,25,25,25,25, 2,25,25,}, + /* D */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* E */ {21,21,25,25,21,25,25, 6,25, 6,25, 6,25, 6,21,21,25,25,25,25,25, 6,25,}, + /* F */ { 4,17, 3, 3, 4,25, 7, 7,19, 9,20,11,13,13,23, 4, 3,25,19,20,25, 4, 3,}, + /* G */ { 4,17, 3, 3, 4,25, 7, 7,19, 9,20,11,13,13,23, 4, 3,25,19,20,25, 4, 3,}, + /* H */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* I */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* J */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* K */ {16,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* L */ {16,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* M */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* N */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* O */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* P */ {15,25,25,25,25,18,25,25,25,25,25,25,25,25,25,25,25,25,25,25, 2,25,25,}, + /* Q */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* R */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* S */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* T */ {25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,}, + /* U */ { 8, 8,25, 8, 8,25,25,25, 8, 8, 8, 8,25,25, 8, 8, 8,25,25,25,25, 8, 8,}, + /* V */ {10,10,25,25,10,25,25,25,25,25,25,10,25,25,10,10,25,25,25,25,25,10,25,}, + /* W */ {12,12,25,25,12,25,25,25,25,25,25,25,25,25,12,12,25,25,25,25,25,12,25,}, + /* X */ {14,14,25,25,14,25,25,14,25,14,25,14,25,25,14,14,25,25,25,25,25,14,25,}, + /* Y */ { 5, 5,25,25,25,25,25,25,25,25,25,25,25,25,16, 5, 5,25,25,25,25,25,16,}, + /* Z */ {22,22,22,22,22,25, 8, 8,10,10,12,12,14,14,22,22,22,25,10,12,25,22,22,}, + /* a */ {18,18,25,25,18,25,25,18,25,18,25,18,25,18,18,18,25,18,25,25,25,18,25,}, +}; + +typedef kbts_u8 kbts_use_syllabic_class; +enum kbts_use_syllabic_class_enum { + /* 0 */ KBTS_USE_SYLLABIC_CLASS_OTHER, + /* 1 */ KBTS_USE_SYLLABIC_CLASS_BASE, + /* 2 */ KBTS_USE_SYLLABIC_CLASS_BASE_OTHER, + /* 3 */ KBTS_USE_SYLLABIC_CLASS_HALANT, + /* 4 */ KBTS_USE_SYLLABIC_CLASS_HALANT_OR_VOWEL_MODIFIER, + /* 5 */ KBTS_USE_SYLLABIC_CLASS_SAKOT, + /* 6 */ KBTS_USE_SYLLABIC_CLASS_INVISIBLE_STACKER, + /* 7 */ KBTS_USE_SYLLABIC_CLASS_CONS_SUB, + /* 8 */ KBTS_USE_SYLLABIC_CLASS_CONS_MOD_ABOVE, + /* 9 */ KBTS_USE_SYLLABIC_CLASS_CONS_MOD_BELOW, + /* 10 */ KBTS_USE_SYLLABIC_CLASS_CONS_MED_PRE, + /* 11 */ KBTS_USE_SYLLABIC_CLASS_CONS_MED_ABOVE, + /* 12 */ KBTS_USE_SYLLABIC_CLASS_CONS_MED_BELOW, + /* 13 */ KBTS_USE_SYLLABIC_CLASS_CONS_MED_POST, + /* 14 */ KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_ABOVE, + /* 15 */ KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_BELOW, + /* 16 */ KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_POST, + /* 17 */ KBTS_USE_SYLLABIC_CLASS_REORDERING_KILLER, + /* 18 */ KBTS_USE_SYLLABIC_CLASS_HIEROGLYPH, + /* 19 */ KBTS_USE_SYLLABIC_CLASS_HIEROGLYPH_SEGMENT_BEGIN, + /* 20 */ KBTS_USE_SYLLABIC_CLASS_HIEROGLYPH_MOD, + /* 21 */ KBTS_USE_SYLLABIC_CLASS_HIEROGLYPH_SEGMENT_END, + /* 22 */ KBTS_USE_SYLLABIC_CLASS_HIEROGLYPH_JOINER, + /* 23 */ KBTS_USE_SYLLABIC_CLASS_HIEROGLYPH_MIRROR, + /* 24 */ KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_ABOVE, + /* 25 */ KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_BELOW, + /* 26 */ KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_POST, + /* 27 */ KBTS_USE_SYLLABIC_CLASS_SYMBOL_MOD_ABOVE, + /* 28 */ KBTS_USE_SYLLABIC_CLASS_SYMBOL_MOD_BELOW, + /* 29 */ KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_ABOVE, + /* 30 */ KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_BELOW, + /* 31 */ KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_POST, + /* 32 */ KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_PRE, + /* 33 */ KBTS_USE_SYLLABIC_CLASS_VOWEL_PRE, + /* 34 */ KBTS_USE_SYLLABIC_CLASS_VOWEL_ABOVE, + /* 35 */ KBTS_USE_SYLLABIC_CLASS_VOWEL_BELOW, + /* 36 */ KBTS_USE_SYLLABIC_CLASS_VOWEL_POST, + /* 37 */ KBTS_USE_SYLLABIC_CLASS_CONSONANT_WITH_STACKER, + /* 38 */ KBTS_USE_SYLLABIC_CLASS_REPHA, + /* 39 */ KBTS_USE_SYLLABIC_CLASS_ZWNJ, + /* 40 */ KBTS_USE_SYLLABIC_CLASS_HALANT_NUM, + /* 41 */ KBTS_USE_SYLLABIC_CLASS_BASE_NUM, + + KBTS_USE_SYLLABIC_CLASS_COUNT, +}; + +enum +{ + KBTS_USE_STATE_s0 = 42, +}; + +// @Incomplete: Decrement every state by 1. +static kbts_u8 kbts_UseTransition[KBTS_USE_SYLLABIC_CLASS_COUNT][KBTS_USE_STATE_s0] = { + /* 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 */ + /* A */ {24,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,}, + /* B */ {15,44,44,44,44,44,44,44,44,15,15,44,44,15,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,37,44,37,44,44,44,44,44,44,44,44,44,44,}, + /* C */ {24,44,44,44,44,44,44,44,44,15,15,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,}, + /* D */ {14,44,44,44,44,44,44,44,44,44,14,44,44,44,14,14,31,31,31,31,44,44,44,14,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,14,}, + /* E */ {14,44,44,44,44, 5, 5, 5, 5,44,14,44,44, 5,14,14,31,31,31,31,44,44,44,14,44,44,44,44,44,44, 5, 5,44,44,44,44,44,44,44,44,44,14,}, + /* F */ {14,30,30,30,30,30,30,30,30,44,14,44,44,30,14,14,32,32,32,32,44,44,44,14,44,44,44,44,44,44,30,30,44,44,44,44,30,44,44,44,44,14,}, + /* G */ {14,44,44,44,44,44,44,44,44,44,14,44,44,44,14,14,31,31,31,31,44,44,44,14,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,14,}, + /* H */ {15,44,44,44,44,44,44,44,44,44,15,44,44,44,15,15,44,44,44,44,44,44,44,15,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,15,}, + /* I */ {15,44,44,44,44,44,44,44,44,44,15,44,44,44,15,44,44,44,44,44,44,44,44,15,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,15,}, + /* J */ {16,44,44,44,44,44,44,44,44,44,16,44,44,44,16,16,44,44,44,44,44,44,44,16,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,16,}, + /* K */ {17,44,44,44,44,44,44,44,44,44,17,44,44,44,17,17,44,44,44,44,44,44,44,17,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,17,}, + /* L */ {18,44,44,44,44,44,44,44,44,44,18,44,44,44,18,18,18,44,44,44,44,44,44,18,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,18,}, + /* M */ {19,44,44,44,44,44,44,44,44,44,19,44,44,44,19,19,19,19,44,44,44,44,44,19,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,19,}, + /* N */ {20,44,44,44,44,44,44,44,44,44,20,44,44,44,20,20,20,20,20,44,44,44,44,20,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,20,}, + /* O */ {21,21,21,21,21,21,21,21,21,44,21,44,44,21,21,21,21,21,21,21,21,44,44,21,44,44,44,44,44,44,21,21,44,44,44,44,21,44,44,44,44,21,}, + /* P */ {22,22,22,22,22,22,22,22,22,44,22,44,44,22,22,22,22,22,22,22,22,22,44,22,44,44,44,44,44,44,22,22,44,44,44,44,22,44,44,44,44,22,}, + /* Q */ {23,23,23,23,23,23,23,23,23,44,23,44,44,23,23,23,23,23,23,23,23,23,23,23,44,44,44,44,44,44,23,23,44,44,44,44,23,44,44,44,44,23,}, + /* R */ {25,44,44,44,44,44,44,44,44,44,25,44,44,44,25,25,44,44,44,44,44,44,44,25,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,25,}, + /* S */ {41,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,38,44,41,44,44,44,44,44,41,}, + /* T */ {42,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,34,44,36,44,39,39,39,44,36,}, + /* U */ {44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,33,44,44,39,44,39,33,44,}, + /* V */ {44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,33,44,33,44,44,44,44,44,33,44,}, + /* W */ {44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,34,34,34,44,44,34,34,34,34,44,}, + /* X */ {44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,40,44,44,35,44,}, + /* Y */ {26,26,26,26,26,26,26,26,26,44,26,44,44,26,26,26,26,26,26,26,26,26,26,26,44,26,44,44,44,44,26,26,44,44,44,44,26,44,44,44,44,26,}, + /* Z */ {27,27,27,27,27,27,27,27,27,44,27,44,44,27,27,27,27,27,27,27,27,27,27,27,44,27,27,44,44,44,27,27,44,44,44,44,27,44,44,44,44,27,}, + /* a */ {25,25,25,25,25,25,25,25,25,44,25,44,44,25,25,25,25,25,25,25,25,25,25,25,44,44,44,44,44,44,25,25,44,44,44,44,25,44,44,44,44,25,}, + /* b */ {28,44,44,44,44,44,44,44,44,44,11,44,44,44,44,44,44,44,44,44,44,44,44,28,44,44,44,28,44,44,44,44,44,44,44,44,44,44,44,44,44,28,}, + /* c */ {29,44,44,44,44,44,44,44,44,44,29,44,44,44,44,44,44,44,44,44,44,44,44,29,44,44,44,29,29,44,44,44,44,44,44,44,44,44,44,44,44,29,}, + /* d */ { 2, 2,44,44, 2, 2, 2, 2, 2,44, 2,44,44, 2, 2, 2, 2, 2, 2, 2,44,44,44, 2,44,44,44,44,44,44, 2, 2,44,44,44,44,44,44,44,44,44, 2,}, + /* e */ { 3, 3, 3,44, 3, 3, 3, 3, 3,44, 3,44,44, 3, 3, 3, 3, 3, 3, 3,44,44,44, 3,44,44,44,44,44,44, 3, 3,44,44,44,44,44,44,44,44,44, 3,}, + /* f */ { 4, 4, 4,44, 4, 4, 4, 4, 4,44, 4,44,44, 4, 4, 4, 4, 4, 4, 4,44,44,44, 4,44,44,44,44,44,44, 4, 4,44,44,44,44,44,44,44,44,44, 4,}, + /* g */ { 5,44,44,44, 5, 5, 5, 5, 5,44, 5,44,44, 5, 5, 5, 5, 5, 5, 5,44,44,44, 5,44,44,44,44,44,44, 5, 5,44,44,44,44,44,44,44,44,44, 5,}, + /* h */ { 6,44,44,44,44, 6,44,44,44,44, 6,44,44,44, 6, 6, 6, 6, 6, 6,44,44,44, 6,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, 6,}, + /* i */ { 7,44,44,44,44, 7, 7,44,44,44, 7,44,44,44, 7, 7, 7, 7, 7, 7,44,44,44, 7,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, 7,}, + /* j */ { 8,44,44,44,44, 8, 8, 8,44,44, 8,44,44,44, 8, 8, 8, 8, 8, 8,44,44,44, 8,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, 8,}, + /* k */ { 9,44,44,44,44, 9, 9, 9, 9,44, 9,44,44,44, 9, 9, 9, 9, 9, 9,44,44,44, 9,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, 9,}, + /* l */ {10,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,}, + /* m */ {11,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,}, + /* n */ {44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,}, + /* o */ {12,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,}, + /* p */ {13,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,}, +}; + +static const kbts_u8 kbts_CmapFormatPrecedence[14] = {1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 3, 0, 4, 5}; + +static int kbts_ShaperClearsMarkAdvancesInPostGposFixup(kbts_u32 Shaper) +{ + int Result = (1 << Shaper) & ((1 << KBTS_SHAPER_ARABIC) | (1 << KBTS_SHAPER_DEFAULT) | (1 << KBTS_SHAPER_HEBREW)); + return Result; +} + +static kbts_indic_script_properties kbts_IndicScriptProperties(kbts_u32 Script) +{ + kbts_indic_script_properties Result = KBTS_ZERO; + + switch(Script) + { + case KBTS_SCRIPT_DEVANAGARI: + { + Result.ViramaCodepoint = 0x94D; + Result.RephPosition = KBTS_REPH_POSITION_BEFORE_POST; + Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + } + break; + + case KBTS_SCRIPT_BENGALI: + { + Result.ViramaCodepoint = 0x9CD; + Result.RephPosition = KBTS_REPH_POSITION_AFTER_SUBJOINED; + Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + } + break; + + case KBTS_SCRIPT_GUJARATI: + { + Result.ViramaCodepoint = 0xACD; + Result.RephPosition = KBTS_REPH_POSITION_BEFORE_POST; + Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + } + break; + + case KBTS_SCRIPT_GURMUKHI: + { + Result.ViramaCodepoint = 0xA4D; + Result.RephPosition = KBTS_REPH_POSITION_BEFORE_SUBJOINED; + Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + } + break; + + case KBTS_SCRIPT_KANNADA: + { + Result.ViramaCodepoint = 0xCCD; + Result.BlwfPostOnly = 1; + Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; + } + break; + + case KBTS_SCRIPT_MALAYALAM: + { + Result.ViramaCodepoint = 0xD4D; + Result.RephPosition = KBTS_REPH_POSITION_AFTER_MAIN; + Result.RephEncoding = KBTS_REPH_ENCODING_LOGICAL_REPHA; + Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + } + break; + + case KBTS_SCRIPT_ODIA: + { + Result.ViramaCodepoint = 0xB4D; + Result.RephPosition = KBTS_REPH_POSITION_AFTER_MAIN; + Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; + Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + } + break; + + case KBTS_SCRIPT_TAMIL: + { + Result.ViramaCodepoint = 0xBCD; + Result.RightSideMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_AFTER_POST; + } + break; + + case KBTS_SCRIPT_TELUGU: + { + Result.ViramaCodepoint = 0xC4D; + Result.RephEncoding = KBTS_REPH_ENCODING_EXPLICIT; + Result.BlwfPostOnly = 1; + Result.AboveBaseMatraPosition = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; + Result.BelowBaseMatraPosition = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; + } + break; + } + + return Result; +} + +static void kbts_ByteSwapArray16Unchecked(kbts_u16 *Array, kbts_un Count) +{ + KBTS_FOR(It, 0, Count) + { + Array[It] = kbts_ByteSwap16(Array[It]); + } +} + +static int kbts_ByteSwapArray16(kbts_u16 *Array, kbts_un Count, char *End) +{ + int Result = 0; + if((char *)(Array + Count) <= End) + { + kbts_ByteSwapArray16Unchecked(Array, Count); + Result = 1; + } + return Result; +} + +static void kbts_ByteSwapArray32Unchecked(kbts_u32 *Array, kbts_un Count) +{ + KBTS_FOR(It, 0, Count) + { + Array[It] = kbts_ByteSwap32(Array[It]); + } +} + +static int kbts_ByteSwapArray32(kbts_u32 *Array, kbts_un Count, char *End) +{ + int Result = 0; + if((char *)(Array + Count) <= End) + { + kbts_ByteSwapArray32Unchecked(Array, Count); + Result = 1; + } + return Result; +} + +static kbts_u64 kbts_ContainsFeature(kbts_feature_set *Set, kbts_feature_id Id) +{ + kbts_un WordIndex = Id / 64; + kbts_un BitIndex = Id % 64; + + kbts_u64 Result = Set->Flags[WordIndex] & (1ull << BitIndex); + return Result; +} + +static void kbts_AddFeature(kbts_feature_set *Set, kbts_feature_id Id) +{ + kbts_un WordIndex = Id / 64; + kbts_un BitIndex = Id % 64; + + Set->Flags[WordIndex] |= 1ull << BitIndex; +} + +static kbts_feature_override kbts_FeatureOverrideBase(kbts_feature_id Id, kbts_feature_tag Tag, int Alternate, kbts_u32 Value) +{ + kbts_feature_override Result = KBTS_ZERO; + Result.Id = Id; + Result.Tag = Tag; + + if(Alternate) + { + Result.EnabledOrAlternatePlusOne = Value + 1; + } + else + { + Result.EnabledOrAlternatePlusOne = Value; + } + + return Result; +} +KBTS_EXPORT kbts_feature_override kbts_FeatureOverrideFromTag(kbts_feature_tag Tag, int Alternate, kbts_u32 Value) +{ + kbts_feature_override Result = kbts_FeatureOverrideBase(kbts_FeatureTagToId(Tag), Tag, Alternate, Value); + return Result; +} +KBTS_EXPORT kbts_feature_override kbts_FeatureOverride(kbts_feature_id Id, int Alternate, kbts_u32 Value) +{ + kbts_feature_override Result = kbts_FeatureOverrideBase(Id, 0, Alternate, Value); + return Result; +} + +KBTS_EXPORT kbts_glyph_config kbts_GlyphConfig(kbts_feature_override *FeatureOverrides, kbts_u32 FeatureOverrideCount) +{ + kbts_glyph_config Result = KBTS_ZERO; + Result.FeatureOverrides = FeatureOverrides; + Result.FeatureOverrideCount = FeatureOverrideCount; + + KBTS_FOR(FeatureOverrideIndex, 0, FeatureOverrideCount) + { + kbts_feature_override *Override = &FeatureOverrides[FeatureOverrideIndex]; + if(Override->EnabledOrAlternatePlusOne) + { + kbts_AddFeature(&Result.EnabledFeatures, FeatureOverrides[FeatureOverrideIndex].Id); + } + else + { + kbts_AddFeature(&Result.DisabledFeatures, FeatureOverrides[FeatureOverrideIndex].Id); + } + } + + return Result; +} + +KBTS_EXPORT kbts_glyph_config kbts_EmptyGlyphConfig(kbts_feature_override *FeatureOverrides, kbts_u32 FeatureOverrideCapacity) +{ + kbts_glyph_config Result = KBTS_ZERO; + Result.FeatureOverrides = FeatureOverrides; + Result.FeatureOverrideCapacity = FeatureOverrideCapacity; + return Result; +} + +static int kbts_GlyphConfigOverrideFeatureBase(kbts_glyph_config *Config, kbts_feature_id Id, kbts_feature_tag Tag, int Alternate, kbts_u32 Value) +{ + kbts_feature_set *Set = &Config->EnabledFeatures; + if(!Value) + { + Set = &Config->DisabledFeatures; + } + kbts_AddFeature(Set, Id); + + if(!Id || Alternate) + { + if(Config->FeatureOverrideCount < Config->FeatureOverrideCapacity) + { + kbts_feature_override Override = kbts_FeatureOverrideFromTag(Tag, Alternate, Value); + Config->FeatureOverrides[Config->FeatureOverrideCount++] = Override; + } + Config->RequiredFeatureOverrideCapacity += 1; + } + + int Result = Config->RequiredFeatureOverrideCapacity <= Config->FeatureOverrideCapacity; + return Result; +} +KBTS_EXPORT int kbts_GlyphConfigOverrideFeature(kbts_glyph_config *Config, kbts_feature_id Id, int Alternate, kbts_u32 Value) +{ + int Result = kbts_GlyphConfigOverrideFeatureBase(Config, Id, 0, Alternate, Value); + return Result; +} +KBTS_EXPORT int kbts_GlyphConfigOverrideFeatureFromTag(kbts_glyph_config *Config, kbts_feature_tag Tag, int Alternate, kbts_u32 Value) +{ + int Result = kbts_GlyphConfigOverrideFeatureBase(Config, kbts_FeatureTagToId(Tag), Tag, Alternate, Value); + return Result; +} + +// +// TTF struct definitions. +// + +enum +{ + KBTS_GLYPH_CLASS_BASE = 1, + KBTS_GLYPH_CLASS_LIGATURE = 2, + KBTS_GLYPH_CLASS_MARK = 3, + KBTS_GLYPH_CLASS_COMPONENT = 4, +}; + +enum +{ + KBTS_LOOKUP_FLAG_RIGHT_TO_LEFT = 1 << 0, + KBTS_LOOKUP_FLAG_IGNORE_BASE_GLYPHS = 1 << 1, + KBTS_LOOKUP_FLAG_IGNORE_LIGATURES = 1 << 2, + KBTS_LOOKUP_FLAG_IGNORE_MARKS = 1 << 3, + KBTS_LOOKUP_FLAG_USE_MARK_FILTERING_SET = 1 << 4, + + KBTS_LOOKUP_FLAG_MARK_ATTACHMENT_CLASS_FILTER = 0xFF00, +}; + +enum +{ + KBTS_VALUE_FORMAT_X_PLACEMENT = 1 << 0, + KBTS_VALUE_FORMAT_Y_PLACEMENT = 1 << 1, + KBTS_VALUE_FORMAT_X_ADVANCE = 1 << 2, + KBTS_VALUE_FORMAT_Y_ADVANCE = 1 << 3, + KBTS_VALUE_FORMAT_X_PLACEMENT_DEVICE = 1 << 4, + KBTS_VALUE_FORMAT_Y_PLACEMENT_DEVICE = 1 << 5, + KBTS_VALUE_FORMAT_X_ADVANCE_DEVICE = 1 << 6, + KBTS_VALUE_FORMAT_Y_ADVANCE_DEVICE = 1 << 7, +}; + +enum +{ + KBTS_DELTA_FORMAT_2_BIT = 1, + KBTS_DELTA_FORMAT_4_BIT = 2, + KBTS_DELTA_FORMAT_8_BIT = 3, + KBTS_DELTA_FORMAT_VARIATION_INDEX = 0x8000, +}; + +# pragma pack(push, 1) + +typedef struct kbts_glyph_header +{ + kbts_s16 ContourCount; + kbts_s16 MinX; + kbts_s16 MinY; + kbts_s16 MaxX; + kbts_s16 MaxY; +} kbts_glyph_header; + +typedef struct kbts_script_record +{ + kbts_u32 Tag; + kbts_u16 Offset; +} kbts_script_record; + +typedef struct kbts_script_list +{ + kbts_u16 Count; + // kbts_script_record Records[Count]; +} kbts_script_list; + +typedef struct kbts_ot_script +{ + kbts_u16 DefaultLangsysOffset; + kbts_u16 Count; + // kbts_langsys_record Records[Count]; +} kbts_ot_script; + +typedef struct kbts_langsys_record +{ + kbts_u32 Tag; + kbts_u16 Offset; +} kbts_langsys_record; + +typedef struct kbts_langsys +{ + kbts_u16 LookupOrderOffset; // reserved + kbts_u16 RequiredFeatureIndex; + kbts_u16 FeatureIndexCount; + // kbts_u16 FeatureIndices[FeatureIndexCount]; +} kbts_langsys; + +typedef struct kbts_feature_list +{ + kbts_u16 Count; + // kbts_feature_record Records[Count]; +} kbts_feature_list; + +typedef struct kbts_feature_record +{ + kbts_u32 Tag; + kbts_u16 Offset; +} kbts_feature_record; + +typedef struct kbts_feature +{ + kbts_u16 FeatureParamsOffset; + kbts_u16 LookupIndexCount; + // kbts_u16 LookupIndices[LookupIndexCount]; +} kbts_feature; + +typedef struct kbts_lookup_list +{ + kbts_u16 Count; + // kbts_u16 Offsets[Count]; +} kbts_lookup_list; + +// Lookups are used both in GSUB and GPOS. +// Type means either GSUB Lookup Type, or GPOS Lookup Type, depending on the table we are parsing. +typedef struct kbts_lookup +{ + kbts_u16 Type; + kbts_u16 Flag; + kbts_u16 SubtableCount; + // kbts_u16 SubtableOffsets[SubtableCount]; + // If USE_MARK_FILTERING_SET: + // kbts_u16 MarkFilteringSet; +} kbts_lookup; + +typedef struct kbts_coverage +{ + kbts_u16 Format; + kbts_u16 Count; + // If Format == 1: + // kbts_u16 GlyphArray[Count]; + // If Format == 2: + // kbts_range_record Ranges[Count]; +} kbts_coverage; + +typedef struct kbts_range_record +{ + kbts_u16 StartGlyphId; + kbts_u16 EndGlyphId; + kbts_u16 StartCoverageIndex; +} kbts_range_record; + +typedef struct kbts_class_definition_1 +{ + kbts_u16 Format; + kbts_u16 StartGlyphId; + kbts_u16 GlyphCount; + // kbts_u16 ClassValues[GlyphCount]; +} kbts_class_definition_1; + +typedef struct kbts_class_definition_2 +{ + kbts_u16 Format; + kbts_u16 Count; + // kbts_class_range_record Ranges[Count]; +} kbts_class_definition_2; + +typedef struct kbts_class_range_record +{ + kbts_u16 StartGlyphId; + kbts_u16 EndGlyphId; + kbts_u16 Class; +} kbts_class_range_record; + +typedef struct kbts_sequence_lookup_record +{ + kbts_u16 SequenceIndex; + kbts_u16 LookupListIndex; +} kbts_sequence_lookup_record; + +typedef struct kbts_sequence_rule +{ + kbts_u16 GlyphCount; + kbts_u16 SequenceLookupCount; + // kbts_u16 InputSequence[GlyphCount - 1]; + // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts_sequence_rule; + +typedef struct kbts_sequence_rule_set +{ + kbts_u16 Count; + // kbts_u16 Offsets[Count]; +} kbts_sequence_rule_set; + +typedef struct kbts_sequence_context_1 +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 SeqRuleSetCount; + // kbts_u16 SeqRuleSetOffsets[]; +} kbts_sequence_context_1; + +typedef struct kbts_sequence_context_2 +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 ClassDefOffset; + kbts_u16 ClassSequenceRuleSetCount; + // kbts_u16 ClassSequenceRuleSetOffsets[ClassSequenceRuleSetCount]; May be NULL! +} kbts_sequence_context_2; + +typedef struct kbts_class_sequence_rule_set +{ + kbts_u16 Count; + // kbts_u16 ClassSequenceRuleOffsets[Count]; +} kbts_class_sequence_rule_set; + +typedef struct kbts_class_sequence_rule +{ + kbts_u16 GlyphCount; + kbts_u16 SequenceLookupCount; + // kbts_u16 InputSequence[GlyphCount-1]; + // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts_class_sequence_rule; + +typedef struct kbts_sequence_context_3 +{ + kbts_u16 Format; + kbts_u16 GlyphCount; + kbts_u16 SequenceLookupCount; + // kbts_u16 CoverageOffsets[GlyphCount]; + // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts_sequence_context_3; + +typedef struct kbts_chained_sequence_context_1 +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 ChainedSequenceRuleSetCount; + // kbts_u16 ChainedSequenceRuleSetOffsets[ChainedSequenceRuleSetCount]; +} kbts_chained_sequence_context_1; + +typedef struct kbts_chained_sequence_rule_set +{ + kbts_u16 Count; + // kbts_u16 Offsets[Count]; +} kbts_chained_sequence_rule_set; + +typedef struct kbts_chained_sequence_rule +{ + kbts_u16 BacktrackGlyphCount; + // kbts_u16 BacktrackSequence[BacktrackCount]; + // kbts_u16 InputGlyphCount; + // kbts_u16 InputSequence[InputGlyphCount - 1]; + // kbts_u16 LookaheadGlyphCount; + // kbts_u16 LookaheadSequence[LookaheadGlyphCount]; + // kbts_u16 SequenceLookupCount; + // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts_chained_sequence_rule; + +typedef struct kbts_chained_sequence_context_2 +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 BacktrackClassDefOffset; + kbts_u16 InputClassDefOffset; + kbts_u16 LookaheadClassDefOffset; + kbts_u16 ChainedClassSequenceRuleSetCount; + // kbts_u16 ChainedClassSequenceRuleSetOffsets[ChainedClassSequenceRuleSetCount]; +} kbts_chained_sequence_context_2; + +typedef struct kbts_chained_sequence_context_3 +{ + kbts_u16 Format; + kbts_u16 BacktrackGlyphCount; + // kbts_u16 BacktrackCoverageOffsets[BacktrackGlyphCount]; + // kbts_u16 InputGlyphCount; + // kbts_u16 InputCoverageOffsets[InputGlyphCount]; + // kbts_u16 LookaheadGlyphCount; + // kbts_u16 LookaheadCoverageOffsets[LookaheadGlyphCount]; + // kbts_u16 SequenceLookupCount; + // kbts_sequence_lookup_record SequenceLookupRecords[SequenceLookupCount]; +} kbts_chained_sequence_context_3; + +typedef struct kbts_device +{ + union + { + struct + { + kbts_u16 StartSize; + kbts_u16 EndSize; + } Device; + + struct + { + kbts_u16 DeltaSetOuterIndex; + kbts_u16 DeltaSetInnerIndex; + } VariationIndex; + } U; + kbts_u16 DeltaFormat; + // kbts_u16 DeltaValue[]; +} kbts_device; + +typedef struct kbts_feature_variations +{ + kbts_u16 Major; + kbts_u16 Minor; + kbts_u32 RecordCount; + // kbts_feature_variation_record Records[RecordCount]; +} kbts_feature_variations; + +typedef struct kbts_feature_variation_record +{ + kbts_u32 ConditionSetOffset; + kbts_u32 FeatureTableSubstitutionOffset; +} kbts_feature_variation_record; + +typedef struct kbts_condition_set +{ + kbts_u16 Count; + // kbts_u32 Offsets[Count]; +} kbts_condition_set; + +typedef struct kbts_condition_1 +{ + kbts_u16 Format; + kbts_u16 AxisIndex; + kbts_u16 FilterRangeMinValue; + kbts_u16 FilterRangeMaxValue; +} kbts_condition_1; + +typedef struct kbts_feature_table_substitution +{ + kbts_u16 Major; + kbts_u16 Minor; + kbts_u16 Count; + // kbts_feature_table_substitution_record Records[Count]; +} kbts_feature_table_substitution; + +typedef struct kbts_feature_table_substitution_record +{ + kbts_u16 FeatureIndex; + kbts_u32 AlternateFeatureOffset; +} kbts_feature_table_substitution_record; + +typedef struct kbts_table_directory +{ + kbts_u32 Version; + kbts_u16 TableCount; + kbts_u16 SearchRange; + kbts_u16 EntrySelector; + kbts_u16 RangeShift; + // kbts_table_record Records[TableCount]; +} kbts_table_directory; + +typedef struct kbts_table_record +{ + kbts_u32 Tag; + kbts_u32 Checksum; + kbts_u32 Offset; + kbts_u32 Length; +} kbts_table_record; + +typedef struct kbts_cmap +{ + kbts_u16 Version; + kbts_u16 TableCount; + // kbts_encoding_record Records[TableCount]; +} kbts_cmap; + +typedef struct kbts_encoding_record +{ + kbts_u16 PlatformId; + kbts_u16 EncodingId; + kbts_u32 SubtableOffset; +} kbts_encoding_record; + +/* Precedence rules for cmap tables: + - Tables are mutually exclusive, except for format 14 which completes the others. + - 8, 10, 12 > 0, 2, 4, 6 + - Formats 4, 12, 13, 14 are used today. + - Formats 4 and 12 are basic cmap tables. + - Format 13 is for fallback fonts that want to map lots of codepoints to a few fallback glyphs. + - Format 14 is for Unicode Variation Sequences. + - There can be Unicode and Windows tables with the same formats. In that case, we prefer the Windows tables. +*/ + +typedef struct kbts_cmap_0 +{ + kbts_u16 Format; + kbts_u16 Length; + kbts_u16 Language; + kbts_u8 GlyphIdArray[256]; +} kbts_cmap_0; + +typedef struct kbts_cmap_2 +{ + kbts_u16 Format; + kbts_u16 Length; + kbts_u16 Language; + kbts_u16 SubHeaderKeys[256]; + // kbts_sub_header SubHeaders[]; + // kbts_u16 GlyphIdArray[]; +} kbts_cmap_2; + +typedef struct kbts_sub_header +{ + kbts_u16 FirstCode; + kbts_u16 EntryCount; + kbts_s16 IdDelta; + kbts_u16 IdRangeOffset; +} kbts_sub_header; + +typedef struct kbts_cmap_4 +{ + kbts_u16 Format; + kbts_u16 Length; + kbts_u16 Language; + kbts_u16 SegmentCountTimesTwo; + kbts_u16 SearchRange; + kbts_u16 EntrySelector; + kbts_u16 RangeShift; + // kbts_u16 EndCode[SegmentCount]; + // kbts_u16 Reserved; + // kbts_u16 StartCode[SegmentCount]; + // kbts_s16 IdDelta[SegmentCount]; + // kbts_u16 IdRangeOffsets[SegmentCount]; + // kbts_u16 GlyphIdArray[]; +} kbts_cmap_4; + +typedef struct kbts_cmap_6 +{ + kbts_u16 Format; + kbts_u16 Length; + kbts_u16 Language; + kbts_u16 FirstCode; + kbts_u16 EntryCount; + // kbts_u16 GlyphIdArray[EntryCount]; +} kbts_cmap_6; + +typedef struct kbts_cmap_12_13 +{ + kbts_u16 Format; + kbts_u16 Reserved; + kbts_u32 Length; + kbts_u32 Language; + kbts_u32 GroupCount; + // kbts_sequential_map_group Groups[GroupCount]; +} kbts_cmap_12_13; + +typedef struct kbts_sequential_map_group +{ + kbts_u32 StartCharacterCode; + kbts_u32 EndCharacterCode; + kbts_u32 StartGlyphId; +} kbts_sequential_map_group; + +typedef struct kbts_cmap_14 +{ + kbts_u16 Format; + kbts_u32 Length; + kbts_u32 SelectorCount; + // kbts_variation_selector Selectors[SelectorCount]; +} kbts_cmap_14; + +typedef struct kbts_variation_selector +{ + kbts_u8 Selector[3]; + kbts_u32 DefaultUvsOffset; + kbts_u32 NonDefaultUvsOffset; +} kbts_variation_selector; + +typedef struct kbts_default_uvs +{ + kbts_u32 RangeCount; + // kbts_unicode_range Ranges[RangeCount]; +} kbts_default_uvs; + +typedef struct kbts_unicode_range +{ + kbts_u8 Start[3]; + kbts_u8 Count; +} kbts_unicode_range; + +typedef struct kbts_non_default_uvs +{ + kbts_u32 MappingCount; + // kbts_uvs_mapping Mappings[MappingCount]; +} kbts_non_default_uvs; + +typedef struct kbts_uvs_mapping +{ + kbts_u8 UnicodeValue[3]; + kbts_u16 GlyphId; +} kbts_uvs_mapping; + +typedef struct kbts_gsub_gpos +{ + kbts_u16 Major; + kbts_u16 Minor; + kbts_u16 ScriptListOffset; + kbts_u16 FeatureListOffset; + kbts_u16 LookupListOffset; + kbts_u32 FeatureVariationsOffset; // Only present in v1.1 +} kbts_gsub_gpos; + +typedef struct kbts_single_substitution +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + union + { + kbts_s16 DeltaGlyphId; // Format == 1 + kbts_u16 GlyphCount; // Format == 2 + } DeltaOrCount; + // If Format == 2: + // kbts_u16 SubstituteGlyphIds[GlyphCount]; +} kbts_single_substitution; + +typedef struct kbts_multiple_substitution +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 SequenceCount; + // kbts_u16 SequenceOffsets[SequenceCount]; +} kbts_multiple_substitution; + +typedef struct kbts_sequence +{ + kbts_u16 GlyphCount; + // kbts_u16 SubstituteGlyphIds[GlyphCount]; +} kbts_sequence; + +typedef struct kbts_alternate_substitution +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 AlternateSetCount; + // kbts_u16 AlternateSetOffsets[AlternateSetCount]; +} kbts_alternate_substitution; + +typedef struct kbts_alternate_set +{ + kbts_u16 GlyphCount; + // kbts_u16 AlternateGlyphIds[GlyphCount]; +} kbts_alternate_set; + +typedef struct kbts_ligature_substitution +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 LigatureSetCount; + // kbts_u16 LigatureSetOffsets[LigatureSetCount]; +} kbts_ligature_substitution; + +typedef struct kbts_ligature_set +{ + kbts_u16 Count; + // kbts_u16 Offsets[Count]; +} kbts_ligature_set; + +typedef struct kbts_ligature +{ + kbts_u16 Glyph; + kbts_u16 ComponentCount; + // kbts_u16 ComponentGlyphIds[ComponentCount - 1]; +} kbts_ligature; + +typedef struct kbts_extension +{ + kbts_u16 Format; + kbts_u16 LookupType; + kbts_u32 Offset; +} kbts_extension; + +typedef struct kbts_reverse_chain_substitution +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 BacktrackGlyphCount; + // kbts_u16 BacktrackCoverageOffsets[BacktrackGlyphCount]; + // kbts_u16 LookaheadGlyphCount; + // kbts_u16 LookaheadCoverageOffsets[LookaheadGlyphCount]; + // kbts_u16 GlyphCount; + // kbts_u16 SubstituteGlyphIds[GlyphCount]; +} kbts_reverse_chain_substitution; + +typedef struct kbts_mark_glyph_sets +{ + kbts_u16 Format; + kbts_u16 MarkGlyphSetCount; + // kbts_u32 CoverageOffsets[MarkGlyphSetCount]; +} kbts_mark_glyph_sets; + +typedef struct kbts_gdef +{ + kbts_u16 Major; + kbts_u16 Minor; + kbts_u16 ClassDefinitionOffset; // May be 0 + kbts_u16 AttachListOffset; // May be 0 + kbts_u16 LigatureCaretListOffset; // May be 0 + kbts_u16 MarkAttachmentClassDefinitionOffset; // May be 0 + kbts_u16 MarkGlyphSetsDefinitionOffset; // v1.2 and up; may be 0 + kbts_u32 ItemVariationStoreOffset; // v1.3 and up; may be 0 +} kbts_gdef; + +typedef struct kbts_anchor +{ + kbts_u16 Format; + kbts_s16 X; + kbts_s16 Y; + union + { + kbts_u16 AnchorPoint; // If Format == 2 + kbts_u16 XDeviceOffset; // If Format == 3 + } U; + kbts_u16 YDeviceOffset; // If Format == 3 +} kbts_anchor; + +typedef struct kbts_mark_record +{ + kbts_u16 Class; + kbts_u16 AnchorOffset; +} kbts_mark_record; + +typedef struct kbts_mark_array +{ + kbts_u16 Count; + // kbts_mark_record Records[Count]; +} kbts_mark_array; + +typedef struct kbts_single_adjustment_1 +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 ValueFormat; + // ValueRecord; +} kbts_single_adjustment_1; + +typedef struct kbts_single_adjustment_2 +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 ValueFormat; + kbts_u16 RecordCount; + // ValueRecord Records[RecordCount]; +} kbts_single_adjustment_2; + +typedef struct kbts_pair_value_record +{ + kbts_u16 SecondGlyph; + // ValueRecord Record1; + // ValueRecord Record2; +} kbts_pair_value_record; + +typedef struct kbts_pair_set +{ + kbts_u16 Count; + // kbts_pair_value_record PairValueRecords[Count]; +} kbts_pair_set; + +typedef struct kbts_pair_adjustment_1 +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 ValueFormat1; // May be 0 + kbts_u16 ValueFormat2; // May be 0 + kbts_u16 SetCount; + // kbts_u16 SetOffsets[PairSetCount]; +} kbts_pair_adjustment_1; + +typedef struct kbts_pair_adjustment_2 +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 ValueFormat1; // May be 0 + kbts_u16 ValueFormat2; // May be 0 + kbts_u16 ClassDefinition1Offset; + kbts_u16 ClassDefinition2Offset; + kbts_u16 Class1Count; + kbts_u16 Class2Count; + // ValueRecord ValueRecords[Class1Count][Class2Count][2]; +} kbts_pair_adjustment_2; + +typedef struct kbts_entry_exit +{ + kbts_u16 EntryAnchorOffset; + kbts_u16 ExitAnchorOffset; +} kbts_entry_exit; + +typedef struct kbts_cursive_attachment +{ + kbts_u16 Format; + kbts_u16 CoverageOffset; + kbts_u16 EntryExitCount; + // kbts_entry_exit Records[EntryExitCount]; +} kbts_cursive_attachment; + +typedef struct kbts_base_array +{ + kbts_u16 BaseCount; + // kbts_u16 BaseAnchorOffsets[BaseCount][MarkClassCount]; // May be NULL +} kbts_base_array; + +typedef struct kbts_mark_to_base_attachment +{ + kbts_u16 Format; + kbts_u16 MarkCoverageOffset; + kbts_u16 BaseCoverageOffset; + kbts_u16 MarkClassCount; + kbts_u16 MarkArrayOffset; + kbts_u16 BaseArrayOffset; +} kbts_mark_to_base_attachment; + +typedef struct kbts_ligature_attach +{ + kbts_u16 Count; + // kbts_u16 LigatureAnchorOffsets[Count][MarkClassCount]; // May be NULL +} kbts_ligature_attach; + +typedef struct kbts_ligature_array +{ + kbts_u16 Count; + // kbts_u16 LigatureAttachOffsets[Count]; +} kbts_ligature_array; + +typedef struct kbts_mark_to_ligature_attachment +{ + kbts_u16 Format; + kbts_u16 MarkCoverageOffset; + kbts_u16 LigatureCoverageOffset; + kbts_u16 MarkClassCount; + kbts_u16 MarkArrayOffset; + kbts_u16 LigatureArrayOffset; +} kbts_mark_to_ligature_attachment; + +typedef struct kbts_long_mtx +{ + kbts_u16 Advance; + kbts_s16 PreviousSideBearing; +} kbts_long_mtx; + +struct kbts_head +{ + kbts_u16 Major; + kbts_u16 Minor; + kbts_u32 Revision; + kbts_u32 ChecksumAdjustment; + kbts_u32 MagicNumber; + kbts_u16 Flags; + kbts_u16 UnitsPerEm; + kbts_s64 CreatedTime; + kbts_s64 LastModifiedTime; + kbts_s16 XMin; + kbts_s16 YMin; + kbts_s16 XMax; + kbts_s16 YMax; + kbts_u16 MacStyle; // OS/2 style takes priority on Windows. + kbts_u16 LowestRecommendedPpem; + kbts_s16 DirectionHint; // Deprecated. Should ~always be 2. + kbts_s16 IndexToLocFormat; + kbts_s16 GlyphDataFormat; // Only 0 is defined. +}; + +typedef struct kbts_hea +{ + kbts_u16 Major; + kbts_u16 Minor; + + // According to Microsoft, these metrics are deprecated. + // The OS/2 table is the preferred way to get these, now. + kbts_s16 Ascent; + kbts_s16 Descent; + kbts_s16 LineGap; + + kbts_u16 MaxAdvance; + kbts_s16 MinPreviousSideBearing; + kbts_s16 MinNextSideBearing; + kbts_s16 MaxExtent; + + kbts_s16 CaretSlopeRise; + kbts_s16 CaretSlopeRun; + kbts_s16 CaretOffset; + + kbts_u16 Reserved[4]; + + kbts_s16 MetricDataFormat; + kbts_u16 MetricCount; +} kbts_hea; + +typedef struct kbts_maxp +{ + kbts_u16 Major; + kbts_u16 Minor; + kbts_u16 GlyphCount; + + // If Major == 1: + kbts_u16 MaxPointCount; + kbts_u16 MaxContourCount; + kbts_u16 MaxCompositePointCount; + kbts_u16 MaxCompositeContourCount; + kbts_u16 MaxZoneCount; + kbts_u16 MaxTwilightPointCount; + kbts_u16 StorageAreaCount; + kbts_u16 FunctionDefinitionCount; + kbts_u16 InstructionDefinitionCount; + kbts_u16 MaximumStackDepth; + kbts_u16 MaximumInstructionSize; + kbts_u16 MaximumTopLevelComponentCount; + kbts_u16 MaximumComponentDepth; +} kbts_maxp; + +# pragma pack(pop) + +// +// Unpack functions for TTF structs. +// + +typedef struct kbts_script_pointer +{ + kbts_u32 Tag; + kbts_ot_script *Script; +} kbts_script_pointer; + +typedef struct kbts_langsys_pointer +{ + kbts_u32 Tag; + kbts_langsys *Langsys; +} kbts_langsys_pointer; + +typedef struct kbts_feature_pointer +{ + kbts_u32 Tag; + kbts_feature *Feature; +} kbts_feature_pointer; + +typedef struct kbts_feature_variation_pointer +{ + kbts_condition_set *ConditionSet; + kbts_feature_table_substitution *FeatureTableSubstitution; +} kbts_feature_variation_pointer; + +typedef struct kbts_feature_substitution_pointer +{ + kbts_u16 SubstitutedFeatureIndex; + kbts_feature *AlternateFeature; +} kbts_feature_substitution_pointer; + +typedef struct kbts_cmap_subtable_pointer +{ + kbts_u16 PlatformId; + kbts_u16 EncodingId; + kbts_u16 *Subtable; +} kbts_cmap_subtable_pointer; + +typedef struct kbts_unpacked_chained_sequence_rule +{ + kbts_u16 *Input; + kbts_u16 *Backtrack; + kbts_u16 *Lookahead; + kbts_sequence_lookup_record *Records; + + kbts_u16 BacktrackCount; + kbts_u16 InputCount; + kbts_u16 LookaheadCount; + kbts_u16 RecordCount; +} kbts_unpacked_chained_sequence_rule; + +typedef struct kbts_unpacked_chained_sequence_context_3 +{ + kbts_u16 *BacktrackCoverageOffsets; + kbts_u16 *InputCoverageOffsets; + kbts_u16 *LookaheadCoverageOffsets; + kbts_sequence_lookup_record *Records; + + kbts_u16 BacktrackCount; + kbts_u16 InputCount; + kbts_u16 LookaheadCount; + kbts_u16 RecordCount; +} kbts_unpacked_chained_sequence_context_3; + +typedef struct kbts_unpacked_reverse_chain_substitution +{ + kbts_u16 *BacktrackCoverageOffsets; + kbts_u16 *LookaheadCoverageOffsets; + kbts_u16 *SubstituteGlyphIds; + + kbts_u16 BacktrackCount; + kbts_u16 LookaheadCount; + kbts_u16 GlyphCount; +} kbts_unpacked_reverse_chain_substitution; + +typedef struct kbts_unpacked_value_record +{ + kbts_u16 Size; + + kbts_s16 PlacementX; + kbts_s16 PlacementY; + kbts_s16 AdvanceX; + kbts_s16 AdvanceY; + kbts_device *PlacementXDevice; + kbts_device *PlacementYDevice; + kbts_device *AdvanceXDevice; + kbts_device *AdvanceYDevice; +} kbts_unpacked_value_record; + +static kbts_unpacked_value_record kbts_UnpackValueRecord(void *Parent, kbts_u16 Format, kbts_u16 *Record) +{ + kbts_unpacked_value_record Result = KBTS_ZERO; + + kbts_u16 *At = Record; + + if(Format & KBTS_VALUE_FORMAT_X_PLACEMENT) + { + Result.PlacementX = (kbts_s16)*At++; + } + if(Format & KBTS_VALUE_FORMAT_Y_PLACEMENT) + { + Result.PlacementY = (kbts_s16)*At++; + } + if(Format & KBTS_VALUE_FORMAT_X_ADVANCE) + { + Result.AdvanceX = (kbts_s16)*At++; + } + if(Format & KBTS_VALUE_FORMAT_Y_ADVANCE) + { + Result.AdvanceY = (kbts_s16)*At++; + } + if(Format & KBTS_VALUE_FORMAT_X_PLACEMENT_DEVICE) + { + kbts_u16 Offset = *At++; + + if(Offset) + { + Result.PlacementXDevice = KBTS_POINTER_OFFSET(kbts_device, Parent, Offset); + } + } + if(Format & KBTS_VALUE_FORMAT_Y_PLACEMENT_DEVICE) + { + kbts_u16 Offset = *At++; + + if(Offset) + { + Result.PlacementYDevice = KBTS_POINTER_OFFSET(kbts_device, Parent, Offset); + } + } + if(Format & KBTS_VALUE_FORMAT_X_ADVANCE_DEVICE) + { + kbts_u16 Offset = *At++; + + if(Offset) + { + Result.AdvanceXDevice = KBTS_POINTER_OFFSET(kbts_device, Parent, Offset); + } + } + if(Format & KBTS_VALUE_FORMAT_Y_ADVANCE_DEVICE) + { + kbts_u16 Offset = *At++; + + if(Offset) + { + Result.AdvanceYDevice = KBTS_POINTER_OFFSET(kbts_device, Parent, Offset); + } + } + + Result.Size = (kbts_u16)(At - Record); + + return Result; +} + +static kbts_unpacked_reverse_chain_substitution kbts_UnpackReverseChainSubstitution(kbts_reverse_chain_substitution *Subst, int ByteSwap) +{ + kbts_unpacked_reverse_chain_substitution Result; + + Result.BacktrackCoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + Result.BacktrackCount = Subst->BacktrackGlyphCount; + if(ByteSwap) + { + Result.BacktrackCount = kbts_ByteSwap16(Result.BacktrackCount); + } + + Result.LookaheadCoverageOffsets = Result.BacktrackCoverageOffsets + Result.BacktrackCount + 1; + Result.LookaheadCount = Result.BacktrackCoverageOffsets[Result.BacktrackCount]; + if(ByteSwap) + { + Result.LookaheadCount = kbts_ByteSwap16(Result.LookaheadCount); + } + + Result.SubstituteGlyphIds = Result.LookaheadCoverageOffsets + Result.LookaheadCount + 1; + Result.GlyphCount = Result.LookaheadCoverageOffsets[Result.LookaheadCount]; + if(ByteSwap) + { + Result.GlyphCount = kbts_ByteSwap16(Result.GlyphCount); + } + + return Result; +} + +static kbts_unpacked_chained_sequence_rule kbts_UnpackChainedSequenceRule(kbts_chained_sequence_rule *Rule, int ByteSwap) +{ + kbts_unpacked_chained_sequence_rule Result; + + Result.Backtrack = KBTS_POINTER_AFTER(kbts_u16, Rule); + Result.BacktrackCount = Rule->BacktrackGlyphCount; + if(ByteSwap) + { + Result.BacktrackCount = kbts_ByteSwap16(Result.BacktrackCount); + } + + Result.Input = Result.Backtrack + Result.BacktrackCount + 1; + Result.InputCount = Result.Backtrack[Result.BacktrackCount]; + if(ByteSwap) + { + Result.InputCount = kbts_ByteSwap16(Result.InputCount); + } + + Result.Lookahead = Result.Input + Result.InputCount; + Result.LookaheadCount = Result.Input[Result.InputCount - 1]; + if(ByteSwap) + { + Result.LookaheadCount = kbts_ByteSwap16(Result.LookaheadCount); + } + + Result.Records = (kbts_sequence_lookup_record *)(Result.Lookahead + Result.LookaheadCount + 1); + Result.RecordCount = Result.Lookahead[Result.LookaheadCount]; + if(ByteSwap) + { + Result.RecordCount = kbts_ByteSwap16(Result.RecordCount); + } + + return Result; +} + +static kbts_unpacked_chained_sequence_context_3 kbts_UnpackChainedSequenceContext3(kbts_chained_sequence_context_3 *Subst, int ByteSwap) +{ + kbts_unpacked_chained_sequence_context_3 Result; + + Result.BacktrackCoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + Result.BacktrackCount = Subst->BacktrackGlyphCount; + if(ByteSwap) + { + Result.BacktrackCount = kbts_ByteSwap16(Result.BacktrackCount); + } + + Result.InputCoverageOffsets = Result.BacktrackCoverageOffsets + Result.BacktrackCount + 1; + Result.InputCount = Result.BacktrackCoverageOffsets[Result.BacktrackCount]; + if(ByteSwap) + { + Result.InputCount = kbts_ByteSwap16(Result.InputCount); + } + + Result.LookaheadCoverageOffsets = Result.InputCoverageOffsets + Result.InputCount + 1; + Result.LookaheadCount = Result.InputCoverageOffsets[Result.InputCount]; + if(ByteSwap) + { + Result.LookaheadCount = kbts_ByteSwap16(Result.LookaheadCount); + } + + Result.Records = (kbts_sequence_lookup_record *)(Result.LookaheadCoverageOffsets + Result.LookaheadCount + 1); + Result.RecordCount = Result.LookaheadCoverageOffsets[Result.LookaheadCount]; + if(ByteSwap) + { + Result.RecordCount = kbts_ByteSwap16(Result.RecordCount); + } + + return Result; +} + +typedef struct kbts_unpacked_lookup +{ + kbts_u16 *SubtableOffsets; + kbts_coverage *MarkFilteringSet; + kbts_u16 Type; + kbts_u16 Flags; + kbts_u16 SubtableCount; +} kbts_unpacked_lookup; + +static kbts_unpacked_lookup kbts_UnpackLookup(kbts_gdef *Gdef, kbts_lookup *Lookup) +{ + kbts_unpacked_lookup Result = KBTS_ZERO; + + Result.Type = Lookup->Type; + Result.Flags = Lookup->Flag; + Result.SubtableCount = Lookup->SubtableCount; + Result.SubtableOffsets = KBTS_POINTER_AFTER(kbts_u16, Lookup); + if(Result.Flags & KBTS_LOOKUP_FLAG_USE_MARK_FILTERING_SET) + { + kbts_u16 MarkFilteringSetIndex = Result.SubtableOffsets[Result.SubtableCount]; + if(Gdef && Gdef->MarkGlyphSetsDefinitionOffset) + { + kbts_mark_glyph_sets *MarkGlyphSets = KBTS_POINTER_OFFSET(kbts_mark_glyph_sets, Gdef, Gdef->MarkGlyphSetsDefinitionOffset); + if(MarkGlyphSets->MarkGlyphSetCount > MarkFilteringSetIndex) + { + kbts_u32 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u32, MarkGlyphSets); + Result.MarkFilteringSet = KBTS_POINTER_OFFSET(kbts_coverage, MarkGlyphSets, CoverageOffsets[MarkFilteringSetIndex]); + } + } + } + + return Result; +} + +static kbts_script_pointer kbts_GetScript(kbts_script_list *List, kbts_un Index) +{ + kbts_script_record *Records = (kbts_script_record *)(List + 1); + kbts_script_record *Record = &Records[Index]; + + kbts_script_pointer Result; + Result.Tag = Record->Tag; + Result.Script = (kbts_ot_script *)((char *)List + Record->Offset); + + return Result; +} + +static kbts_langsys *kbts_GetDefaultLangsys(kbts_ot_script *Script) +{ + kbts_langsys *Result = Script->DefaultLangsysOffset ? KBTS_POINTER_OFFSET(kbts_langsys, Script, Script->DefaultLangsysOffset) : 0; + return Result; +} + +static kbts_langsys_pointer kbts_GetLangsys(kbts_ot_script *Script, kbts_un Index) +{ + kbts_langsys_record *Records = (kbts_langsys_record *)(Script + 1); + kbts_langsys_record *Record = &Records[Index]; + + kbts_langsys_pointer Result; + Result.Tag = Record->Tag; + Result.Langsys = KBTS_POINTER_OFFSET(kbts_langsys, Script, Record->Offset); + return Result; +} + +static kbts_feature_pointer kbts_GetFeature(kbts_feature_list *List, kbts_un Index) +{ + kbts_feature_record *Records = (kbts_feature_record *)(List + 1); + kbts_feature_record *Record = &Records[Index]; + + kbts_feature_pointer Result; + Result.Tag = Record->Tag; + Result.Feature = KBTS_POINTER_OFFSET(kbts_feature, List, Record->Offset); + return Result; +} + +static kbts_lookup_list *kbts_GetLookupList(kbts_gsub_gpos *GsubGpos) +{ + kbts_lookup_list *Result = 0; + + if(GsubGpos) + { + Result = KBTS_POINTER_OFFSET(kbts_lookup_list, GsubGpos, GsubGpos->LookupListOffset); + } + + return Result; +} + +static kbts_lookup *kbts_GetLookup(kbts_lookup_list *List, kbts_un Index) +{ + KBTS_ASSERT(Index < List->Count); + kbts_u16 *Offsets = (kbts_u16 *)(List + 1); + kbts_lookup *Result = KBTS_POINTER_OFFSET(kbts_lookup, List, Offsets[Index]); + return Result; +} + +static kbts_sequence_rule_set *kbts_GetSequenceRuleSet(kbts_sequence_context_1 *Context, kbts_un Index) +{ + KBTS_ASSERT(Index < Context->SeqRuleSetCount); + kbts_u16 *Offsets = (kbts_u16 *)(Context + 1); + kbts_u16 Offset = Offsets[Index]; + + kbts_sequence_rule_set *Result = Offset ? KBTS_POINTER_OFFSET(kbts_sequence_rule_set, Context, Offsets[Index]) : 0; + return Result; +} + +static kbts_sequence_rule *kbts_GetSequenceRule(kbts_sequence_rule_set *Set, kbts_un Index) +{ + KBTS_ASSERT(Index < Set->Count); + kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); + kbts_sequence_rule *Result = KBTS_POINTER_OFFSET(kbts_sequence_rule, Set, Offsets[Index]); + return Result; +} + +// A single class definition table can be used by multiple lookups, so it is possible +// (and valid) to get an out-of-bounds glyph class. +static kbts_class_sequence_rule_set *kbts_GetClassSequenceRuleSet(kbts_sequence_context_2 *Context, kbts_un Index) +{ + kbts_class_sequence_rule_set *Result = 0; + if(Index < Context->ClassSequenceRuleSetCount) + { + kbts_u16 *Offsets = (kbts_u16 *)(Context + 1); + Result = Offsets[Index] ? KBTS_POINTER_OFFSET(kbts_class_sequence_rule_set, Context, Offsets[Index]) : 0; + } + return Result; +} + +static kbts_class_sequence_rule *kbts_GetClassSequenceRule(kbts_class_sequence_rule_set *Set, kbts_un Index) +{ + KBTS_ASSERT(Index < Set->Count); + kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); + kbts_class_sequence_rule *Result = KBTS_POINTER_OFFSET(kbts_class_sequence_rule, Set, Offsets[Index]); + return Result; +} + +static kbts_chained_sequence_rule_set *kbts_GetChainedSequenceRuleSet(kbts_chained_sequence_context_1 *Context, kbts_un Index) +{ + kbts_u16 *Offsets = (kbts_u16 *)(Context + 1); + kbts_chained_sequence_rule_set *Result = Offsets[Index] ? KBTS_POINTER_OFFSET(kbts_chained_sequence_rule_set, Context, Offsets[Index]) : 0; + return Result; +} + +static kbts_chained_sequence_rule *kbts_GetChainedSequenceRule(kbts_chained_sequence_rule_set *Set, kbts_un Index) +{ + kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); + kbts_chained_sequence_rule *Result = KBTS_POINTER_OFFSET(kbts_chained_sequence_rule, Set, Offsets[Index]); + return Result; +} + +static kbts_chained_sequence_rule_set *kbts_GetChainedClassSequenceRuleSet(kbts_chained_sequence_context_2 *Context, kbts_un Index) +{ + kbts_u16 *Offsets = (kbts_u16 *)(Context + 1); + kbts_u16 Offset = Offsets[Index]; + kbts_chained_sequence_rule_set *Result = Offset ? KBTS_POINTER_OFFSET(kbts_chained_sequence_rule_set, Context, Offset) : NULL; + return Result; +} + +static kbts_chained_sequence_rule *kbts_GetChainedClassSequenceRule(kbts_chained_sequence_rule_set *Set, kbts_un Index) +{ + kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); + kbts_chained_sequence_rule *Result = KBTS_POINTER_OFFSET(kbts_chained_sequence_rule, Set, Offsets[Index]); + return Result; +} + +#if 0 // @Incomplete +static kbts_feature_variation_pointer kbts_GetFeatureVariation(kbts_feature_variations *Variations, kbts_un Index) +{ + kbts_feature_variation_record *Records = (kbts_feature_variation_record *)(Variations + 1); + kbts_feature_variation_record *Record = &Records[Index]; + + kbts_feature_variation_pointer Result; + Result.ConditionSet = KBTS_POINTER_OFFSET(kbts_condition_set, Variations, Record->ConditionSetOffset); + Result.FeatureTableSubstitution = KBTS_POINTER_OFFSET(kbts_feature_table_substitution, Variations, Record->FeatureTableSubstitutionOffset); + return Result; +} + +static kbts_condition_1 *kbts_GetCondition(kbts_condition_set *Set, kbts_un Index) +{ + kbts_u32 *Offsets = (kbts_u32 *)(Set + 1); + kbts_condition_1 *Result = KBTS_POINTER_OFFSET(kbts_condition_1, Set, Offsets[Index]); + return Result; +} + +static kbts_feature_substitution_pointer kbts_GetFeatureSubstitution(kbts_feature_table_substitution *Table, kbts_un Index) +{ + kbts_feature_table_substitution_record *Records = (kbts_feature_table_substitution_record *)(Table + 1); + kbts_feature_table_substitution_record *Record = &Records[Index]; + + kbts_feature_substitution_pointer Result; + Result.SubstitutedFeatureIndex = Record->FeatureIndex; + Result.AlternateFeature = KBTS_POINTER_OFFSET(kbts_feature, Table, Record->AlternateFeatureOffset); + return Result; +} +#endif + +static kbts_cmap_subtable_pointer kbts_GetCmapSubtable(kbts_cmap *Cmap, kbts_un Index) +{ + kbts_encoding_record *Records = (kbts_encoding_record *)(Cmap + 1); + kbts_encoding_record *Record = &Records[Index]; + + kbts_cmap_subtable_pointer Result; + Result.PlatformId = Record->PlatformId; + Result.EncodingId = Record->EncodingId; + Result.Subtable = KBTS_POINTER_OFFSET(kbts_u16, Cmap, Record->SubtableOffset); + + return Result; +} + +static kbts_sequence *kbts_GetSequence(kbts_multiple_substitution *Subst, kbts_un Index) +{ + kbts_u16 *Offsets = (kbts_u16 *)(Subst + 1); + kbts_sequence *Result = KBTS_POINTER_OFFSET(kbts_sequence, Subst, Offsets[Index]); + return Result; +} + +static kbts_alternate_set *kbts_GetAlternateSet(kbts_alternate_substitution *Subst, kbts_un Index) +{ + kbts_u16 *Offsets = (kbts_u16 *)(Subst + 1); + kbts_alternate_set *Result = KBTS_POINTER_OFFSET(kbts_alternate_set, Subst, Offsets[Index]); + return Result; +} + +static kbts_ligature_set *kbts_GetLigatureSet(kbts_ligature_substitution *Subst, kbts_un Index) +{ + kbts_u16 *Offsets = (kbts_u16 *)(Subst + 1); + kbts_ligature_set *Result = KBTS_POINTER_OFFSET(kbts_ligature_set, Subst, Offsets[Index]); + return Result; +} + +static kbts_ligature *kbts_GetLigature(kbts_ligature_set *Set, kbts_un Index) +{ + kbts_u16 *Offsets = (kbts_u16 *)(Set + 1); + kbts_ligature *Result = KBTS_POINTER_OFFSET(kbts_ligature, Set, Offsets[Index]); + return Result; +} + +static kbts_mark_record *kbts_GetMarkRecord(kbts_mark_array *Array, kbts_un Index) +{ + kbts_mark_record *Records = KBTS_POINTER_AFTER(kbts_mark_record, Array); + kbts_mark_record *Result = &Records[Index]; + return Result; +} + +static kbts_ligature_attach *kbts_GetLigatureAttach(kbts_ligature_array *Array, kbts_un Index) +{ + kbts_u16 *Offsets = KBTS_POINTER_AFTER(kbts_u16, Array); + kbts_ligature_attach *Result = KBTS_POINTER_OFFSET(kbts_ligature_attach, Array, Offsets[Index]); + return Result; +} + +static kbts_anchor *kbts_GetLigatureAttachAnchor(kbts_mark_to_ligature_attachment *Adjust, kbts_ligature_attach *Attach, kbts_u16 MarkClass, kbts_un ComponentIndex) +{ + kbts_u16 *Offsets = KBTS_POINTER_AFTER(kbts_u16, Attach); + kbts_u16 Offset = Offsets[ComponentIndex * Adjust->MarkClassCount + MarkClass]; + + kbts_anchor *Result = 0; + if(Offset) + { + Result = KBTS_POINTER_OFFSET(kbts_anchor, Attach, Offset); + } + + return Result; +} + +typedef struct kbts_mark_info +{ + kbts_mark_array *Array; + kbts_mark_record *Record; + kbts_anchor *Anchor; +} kbts_mark_info; + +static kbts_mark_info kbts_GetMarkInfo(void *Subtable, kbts_un SubtableOffsetToMarkArray, kbts_un CoverageIndex) +{ + kbts_mark_info Result = KBTS_ZERO; + + Result.Array = KBTS_POINTER_OFFSET(kbts_mark_array, Subtable, SubtableOffsetToMarkArray); + Result.Record = kbts_GetMarkRecord(Result.Array, CoverageIndex); + Result.Anchor = KBTS_POINTER_OFFSET(kbts_anchor, Result.Array, Result.Record->AnchorOffset); + + return Result; +} + +// +// +// + +typedef struct kbts_byteswap_context +{ + char *FileBase; + char *FileEnd; + kbts_u32 *Pointers; + kbts_un PointerCapacity; + kbts_un PointerCount; + + int Error; +} kbts_byteswap_context; + +static int kbts_ByteSwapArray16Context(kbts_u16 *Array, kbts_un Count, kbts_byteswap_context *Context) +{ + int Result = kbts_ByteSwapArray16(Array, Count, Context->FileEnd); + Context->Error |= !Result; + return Result; +} + +static int kbts_ByteSwapArray32Context(kbts_u32 *Array, kbts_un Count, kbts_byteswap_context *Context) +{ + int Result = kbts_ByteSwapArray32(Array, Count, Context->FileEnd); + Context->Error |= !Result; + return Result; +} + +typedef struct kbts_cover_glyph_result +{ + kbts_u32 Valid; + kbts_u32 Index; +} kbts_cover_glyph_result; + +static int kbts_LookupBeginsWithCoverage(kbts_shaping_table ShapingTable, kbts_u16 LookupType, kbts_u16 Format) +{ + int Result = 0; + if(ShapingTable == KBTS_SHAPING_TABLE_GSUB) + { + Result = (LookupType != 7) && (Format != 3); + } + else + { + Result = (LookupType != 9) && (Format != 3); + } + return Result; +} + +// Except for lookup tables 5.3, 6.3 and 7, all tables begin with (kbts_u16 Format, kbts_u16 CoverageOffset). +KBTS_INLINE int kbts_GsubLookupBeginsWithCoverage(kbts_u16 LookupType, kbts_u16 Format) +{ + int Result = kbts_LookupBeginsWithCoverage(KBTS_SHAPING_TABLE_GSUB, LookupType, Format); + return Result; +} + +KBTS_INLINE int kbts_GposLookupBeginsWithCoverage(kbts_u16 LookupType, kbts_u16 Format) +{ + int Result = kbts_LookupBeginsWithCoverage(KBTS_SHAPING_TABLE_GPOS, LookupType, Format); + return Result; +} + +typedef struct kbts_lookup_info_frame +{ + kbts_u16 *Base; + kbts_u16 LookupType; + kbts_u32 LookaheadOffset; + kbts_u32 StackSize; +} kbts_lookup_info_frame; + +static int kbts_PushLookup(kbts_gdef *Gdef, kbts_lookup_info_frame *Frames, kbts_un *FrameCount, kbts_un FrameCapacity, kbts_lookup *PackedLookup, kbts_u32 LookaheadOffset, kbts_un StackSize) +{ + int Result = 0; + kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Gdef, PackedLookup); + + if((*FrameCount + Lookup.SubtableCount) <= FrameCapacity) + { + KBTS_FOR(SubtableIndex, 0, Lookup.SubtableCount) + { + kbts_lookup_info_frame *Frame = &Frames[(*FrameCount)++]; + Frame->Base = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubtableIndex]); + Frame->LookupType = Lookup.Type; + Frame->LookaheadOffset = LookaheadOffset; + Frame->StackSize = (kbts_u32)StackSize; + } + + Result = 1; + } + + return Result; +} + +static int kbts_AlreadyVisited(kbts_byteswap_context *Context, void *Pointer) +{ + int Result = !Pointer || Context->Error; + + if(!Result) + { + kbts_u32 *Pointers = Context->Pointers; + kbts_u32 Pointer32 = KBTS_POINTER_DIFF32(Pointer, Context->FileBase); + + kbts_un Index = 0; + if(Context->PointerCount) + { + kbts_un PointerCount = Context->PointerCount; + if(PointerCount) + { + while(PointerCount > 1) + { + kbts_un HalfCount = PointerCount / 2; + Index = (Pointers[Index + HalfCount - 1] < Pointer32) ? (Index + HalfCount) : Index; + PointerCount -= HalfCount; + } + Result = (Pointer32 == Pointers[Index]); + } + } + + if(!Result && (Context->PointerCount < Context->PointerCapacity)) + { + while((Index < Context->PointerCount) && (Pointers[Index] < Pointer32)) ++Index; + + for(kbts_un GrowIndex = Context->PointerCount; GrowIndex > Index; --GrowIndex) + { + Pointers[GrowIndex] = Pointers[GrowIndex - 1]; + } + Pointers[Index] = Pointer32; + Context->PointerCount += 1; + } + } + + return Result; +} + +static void kbts_ByteSwapFeature(kbts_byteswap_context *Context, kbts_feature *Feature) +{ + if(!kbts_AlreadyVisited(Context, Feature)) + { + kbts_u16 *LookupIndices = KBTS_POINTER_AFTER(kbts_u16, Feature); + Context->Error |= !kbts_ByteSwapArray16(&Feature->FeatureParamsOffset, 2, Context->FileEnd); + Context->Error |= !kbts_ByteSwapArray16(LookupIndices, Feature->LookupIndexCount, Context->FileEnd); + + // We require lookup indices to be sorted per feature for the lookup application order to match Harfbuzz. + // Lookup indices are _typically_ sorted per feature, but we can't assume it is always the case. + kbts_un LookupIndexCount = Feature->LookupIndexCount; + KBTS_FOR(Iter, 0, LookupIndexCount) + { + KBTS_FOR(IndexIndex, 1, LookupIndexCount) + { + kbts_u16 Left = LookupIndices[IndexIndex - 1]; + kbts_u16 Right = LookupIndices[IndexIndex]; + + if(Left > Right) + { + LookupIndices[IndexIndex - 1] = Right; + LookupIndices[IndexIndex] = Left; + } + } + } + } + +# ifdef KBTS_DUMP + kbts_u16 *LookupIndices = KBTS_POINTER_AFTER(kbts_u16, Feature); + KBTS_FOR(LookupIndexIndex, 0, Feature->LookupIndexCount) + { + KBTS_DUMPF(" Lookup index %u\n", LookupIndices[LookupIndexIndex]); + } +# endif +} + +static void kbts_ByteSwapGsubGposCommon(kbts_byteswap_context *Context, kbts_gsub_gpos *Header) +{ + kbts_ByteSwapArray16Context(&Header->Major, 5, Context); + + if(Header->Minor == 1) + { + Header->FeatureVariationsOffset = kbts_ByteSwap32(Header->FeatureVariationsOffset); + } + + kbts_script_list *ScriptList = KBTS_POINTER_OFFSET(kbts_script_list, Header, Header->ScriptListOffset); + if(!kbts_AlreadyVisited(Context, ScriptList)) + { + ScriptList->Count = kbts_ByteSwap16(ScriptList->Count); + + kbts_script_record *ScriptRecords = KBTS_POINTER_AFTER(kbts_script_record, ScriptList); + KBTS_FOR(It, 0, ScriptList->Count) + { + kbts_script_record *Record = &ScriptRecords[It]; + + Record->Offset = kbts_ByteSwap16(Record->Offset); + + KBTS_DUMPF("Script %.4s\n", (char *)&Record->Tag); + + kbts_ot_script *Script = KBTS_POINTER_OFFSET(kbts_ot_script, ScriptList, Record->Offset); + if(!kbts_AlreadyVisited(Context, Script)) + { + Script->DefaultLangsysOffset = kbts_ByteSwap16(Script->DefaultLangsysOffset); + Script->Count = kbts_ByteSwap16(Script->Count); + + kbts_langsys *DefaultLangsys = kbts_GetDefaultLangsys(Script); + + if(DefaultLangsys && !kbts_AlreadyVisited(Context, DefaultLangsys)) + { + kbts_ByteSwapArray16Context(&DefaultLangsys->LookupOrderOffset, 3, Context); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, DefaultLangsys), DefaultLangsys->FeatureIndexCount, Context); + } + + kbts_langsys_record *LangsysRecords = KBTS_POINTER_AFTER(kbts_langsys_record, Script); + KBTS_FOR(LangsysIndex, 0, Script->Count) + { + kbts_langsys_record *LangsysRecord = &LangsysRecords[LangsysIndex]; + + LangsysRecord->Offset = kbts_ByteSwap16(LangsysRecord->Offset); + + kbts_langsys *Langsys = KBTS_POINTER_OFFSET(kbts_langsys, Script, LangsysRecord->Offset); + if(!kbts_AlreadyVisited(Context, Langsys)) + { + kbts_ByteSwapArray16Context(&Langsys->LookupOrderOffset, 3, Context); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Langsys), Langsys->FeatureIndexCount, Context); + } + } + +# ifdef KBTS_DUMP + if(DefaultLangsys) + { + KBTS_DUMPF(" Default langsys @ %zu\n", (char *)DefaultLangsys - Context->FileBase); + KBTS_DUMPF(" Lookup order offset %u\n", DefaultLangsys->LookupOrderOffset); + KBTS_DUMPF(" Required feature %u\n", DefaultLangsys->RequiredFeatureIndex); + kbts_u16 *FeatureIndices = KBTS_POINTER_AFTER(kbts_u16, DefaultLangsys); + KBTS_FOR(FeatureIndexIndex, 0, DefaultLangsys->FeatureIndexCount) + { + KBTS_DUMPF(" Feature %u\n", FeatureIndices[FeatureIndexIndex]); + } + } + + KBTS_FOR(LangsysIndex, 0, Script->Count) + { + kbts_langsys_record *LangsysRecord = &LangsysRecords[LangsysIndex]; + kbts_langsys *Langsys = KBTS_POINTER_OFFSET(kbts_langsys, Script, LangsysRecord->Offset); + KBTS_DUMPF(" Langsys %.4s @ %zu\n", (char *)&LangsysRecord->Tag, (char *)Script + LangsysRecord->Offset - Context->FileBase); + KBTS_DUMPF(" Lookup order offset %u\n" + " Required feature %u\n", + Langsys->LookupOrderOffset, Langsys->RequiredFeatureIndex); + kbts_u16 *FeatureIndices = KBTS_POINTER_AFTER(kbts_u16, Langsys); + KBTS_FOR(FeatureIndexIndex, 0, Langsys->FeatureIndexCount) + { + KBTS_DUMPF(" Feature %u\n", FeatureIndices[FeatureIndexIndex]); + } + } +# endif + } + } + + if((Header->Minor == 1) && Header->FeatureVariationsOffset) + { + kbts_feature_variations *FeatureVariations = KBTS_POINTER_OFFSET(kbts_feature_variations, Header, Header->FeatureVariationsOffset); + + if(!kbts_AlreadyVisited(Context, FeatureVariations)) + { + kbts_ByteSwapArray16Context(&FeatureVariations->Major, 2, Context); + FeatureVariations->RecordCount = kbts_ByteSwap32(FeatureVariations->RecordCount); + + kbts_feature_variation_record *Records = KBTS_POINTER_AFTER(kbts_feature_variation_record, FeatureVariations); + KBTS_FOR(VariationIndex, 0, FeatureVariations->RecordCount) + { + kbts_feature_variation_record *Record = &Records[VariationIndex]; + + kbts_ByteSwapArray32Context(&Record->ConditionSetOffset, 2, Context); + + kbts_condition_set *Set = KBTS_POINTER_OFFSET(kbts_condition_set, FeatureVariations, Record->ConditionSetOffset); + + if(!kbts_AlreadyVisited(Context, Set)) + { + Set->Count = kbts_ByteSwap16(Set->Count); + + kbts_u32 *ConditionOffsets = KBTS_POINTER_AFTER(kbts_u32, Set); + kbts_ByteSwapArray32Context(ConditionOffsets, Set->Count, Context); + + KBTS_FOR(ConditionIndex, 0, Set->Count) + { + kbts_condition_1 *Condition = KBTS_POINTER_OFFSET(kbts_condition_1, Set, ConditionOffsets[ConditionIndex]); + + if(!kbts_AlreadyVisited(Context, Condition)) + { + kbts_ByteSwapArray16Context(&Condition->Format, 4, Context); + } + } + + kbts_feature_table_substitution *FeatureSubst = KBTS_POINTER_OFFSET(kbts_feature_table_substitution, FeatureVariations, Record->FeatureTableSubstitutionOffset); + + if(!kbts_AlreadyVisited(Context, FeatureSubst)) + { + kbts_ByteSwapArray16Context(&FeatureSubst->Major, 3, Context); + + kbts_feature_table_substitution_record *SubstRecords = KBTS_POINTER_AFTER(kbts_feature_table_substitution_record, FeatureSubst); + KBTS_FOR(SubstRecordIndex, 0, FeatureSubst->Count) + { + kbts_feature_table_substitution_record *SubstRecord = &SubstRecords[SubstRecordIndex]; + SubstRecord->FeatureIndex = kbts_ByteSwap16(SubstRecord->FeatureIndex); + + kbts_feature *Feature = KBTS_POINTER_OFFSET(kbts_feature, FeatureSubst, SubstRecord->AlternateFeatureOffset); + kbts_ByteSwapFeature(Context, Feature); + } + } + } + } + } + } + } + + kbts_feature_list *FeatureList = KBTS_POINTER_OFFSET(kbts_feature_list, Header, Header->FeatureListOffset); + if(!kbts_AlreadyVisited(Context, FeatureList)) + { + FeatureList->Count = kbts_ByteSwap16(FeatureList->Count); + kbts_feature_record *FeatureRecords = KBTS_POINTER_AFTER(kbts_feature_record, FeatureList); + KBTS_FOR(FeatureRecordIndex, 0, FeatureList->Count) + { + kbts_feature_record *FeatureRecord = &FeatureRecords[FeatureRecordIndex]; + + KBTS_DUMPF("Feature %llu %.4s\n", FeatureRecordIndex, (char *)&FeatureRecord->Tag); + + if(!kbts_AlreadyVisited(Context, FeatureRecord)) + { + FeatureRecord->Offset = kbts_ByteSwap16(FeatureRecord->Offset); + + kbts_feature *Feature = KBTS_POINTER_OFFSET(kbts_feature, FeatureList, FeatureRecord->Offset); + kbts_ByteSwapFeature(Context, Feature); + } + } + } +} + +static int kbts_ByteSwapLookup(kbts_byteswap_context *Context, kbts_lookup *Lookup) +{ + int Result = 0; + + if(!kbts_AlreadyVisited(Context, Lookup)) + { + Result = 1; + + kbts_ByteSwapArray16Context(&Lookup->Type, 3, Context); + kbts_u16 *SubtableOffsets = KBTS_POINTER_AFTER(kbts_u16, Lookup); + + kbts_un U16Count = Lookup->SubtableCount; + if(Lookup->Flag & KBTS_LOOKUP_FLAG_USE_MARK_FILTERING_SET) + { + U16Count += 1; + } + kbts_ByteSwapArray16Context(SubtableOffsets, U16Count, Context); + } + + return Result; +} + +static void kbts_ByteSwapCoverage(kbts_byteswap_context *Context, kbts_coverage *Coverage) +{ + if(!kbts_AlreadyVisited(Context, Coverage)) + { + kbts_ByteSwapArray16Context(&Coverage->Format, 2, Context); + + kbts_un U16Count = 0; + if(Coverage->Format == 1) + { + U16Count = Coverage->Count; + } + else if(Coverage->Format == 2) + { + U16Count = Coverage->Count * 3; + } + + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Coverage), U16Count, Context); + } +} + +static void kbts_ByteSwapAnchor(kbts_byteswap_context *Context, kbts_anchor *Anchor) +{ + if(!kbts_AlreadyVisited(Context, Anchor)) + { + Anchor->Format = kbts_ByteSwap16(Anchor->Format); + + kbts_un U16Count = 2; + if(Anchor->Format == 2) + { + U16Count = 3; + } + else if(Anchor->Format == 3) + { + U16Count = 4; + } + + kbts_ByteSwapArray16Context((kbts_u16 *)&Anchor->X, U16Count, Context); + } +} + +static void kbts_ByteSwapBaseArray(kbts_byteswap_context *Context, kbts_u16 MarkClassCount, kbts_base_array *Array) +{ + if(!kbts_AlreadyVisited(Context, Array)) + { + Array->BaseCount = kbts_ByteSwap16(Array->BaseCount); + + kbts_u16 *BaseAnchorOffsets = KBTS_POINTER_AFTER(kbts_u16, Array); + kbts_ByteSwapArray16Context(BaseAnchorOffsets, Array->BaseCount * MarkClassCount, Context); + + KBTS_FOR(OffsetIndex, 0, (kbts_un)Array->BaseCount * MarkClassCount) + { + kbts_u16 Offset = BaseAnchorOffsets[OffsetIndex]; + + if(Offset) + { + kbts_ByteSwapAnchor(Context, KBTS_POINTER_OFFSET(kbts_anchor, Array, Offset)); + } + } + } +} + +static void kbts_ByteSwapDevice(kbts_byteswap_context *Context, kbts_device *Device) +{ + if(!kbts_AlreadyVisited(Context, Device)) + { + kbts_ByteSwapArray16Context(&Device->U.Device.StartSize, 3, Context); + + if(Device->DeltaFormat <= 3) + { + // @Incomplete + } + } +} + +static kbts_unpacked_value_record kbts_ByteSwapValueRecord(kbts_byteswap_context *Context, void *Parent, kbts_u16 ValueFormat, kbts_u16 *Record) +{ + kbts_unpacked_value_record Result = KBTS_ZERO; + + if(ValueFormat) + { + kbts_un U16Count = kbts_PopCount32(ValueFormat); + + kbts_ByteSwapArray16Context(Record, U16Count, Context); + + Result = kbts_UnpackValueRecord(Parent, ValueFormat, Record); + + kbts_ByteSwapDevice(Context, Result.PlacementXDevice); + kbts_ByteSwapDevice(Context, Result.PlacementYDevice); + kbts_ByteSwapDevice(Context, Result.AdvanceXDevice); + kbts_ByteSwapDevice(Context, Result.AdvanceYDevice); + } + + return Result; +} + +static void kbts_ByteSwapMarkArray(kbts_byteswap_context *Context, kbts_mark_array *MarkArray) +{ + if(!kbts_AlreadyVisited(Context, MarkArray)) + { + MarkArray->Count = kbts_ByteSwap16(MarkArray->Count); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, MarkArray), MarkArray->Count * 2, Context); + + kbts_mark_record *MarkRecords = KBTS_POINTER_AFTER(kbts_mark_record, MarkArray); + KBTS_FOR(MarkRecordIndex, 0, MarkArray->Count) + { + kbts_mark_record *MarkRecord = &MarkRecords[MarkRecordIndex]; + + kbts_ByteSwapAnchor(Context, KBTS_POINTER_OFFSET(kbts_anchor, MarkArray, MarkRecord->AnchorOffset)); + } + } +} + +static void kbts_ByteSwapChainedSequenceRuleSet(kbts_byteswap_context *Context, kbts_chained_sequence_rule_set *Set) +{ + if(Set && !kbts_AlreadyVisited(Context, Set)) + { + Set->Count = kbts_ByteSwap16(Set->Count); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->Count, Context); + + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); + + if(!kbts_AlreadyVisited(Context, Rule)) + { + kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 1); + + kbts_un U16Count = Unpacked.BacktrackCount + Unpacked.InputCount + Unpacked.LookaheadCount + Unpacked.RecordCount * 2 + 3; + kbts_ByteSwapArray16Context(&Rule->BacktrackGlyphCount, U16Count, Context); + } + } + } +} + +#ifdef KBTS_DUMP +static void kbts_DumpClassDefinition(kbts_u16 *Base) +{ + if(*Base == 1) + { + kbts_class_definition_1 *ClassDef = (kbts_class_definition_1 *)Base; + kbts_u16 *ClassValues = KBTS_POINTER_AFTER(kbts_u16, ClassDef); + KBTS_FOR(GlyphIndex, 0, ClassDef->GlyphCount) + { + KBTS_DUMPF("%llx -> %u\n", ClassDef->StartGlyphId + GlyphIndex, ClassValues[GlyphIndex]); + } + } + else if(*Base == 2) + { + kbts_class_definition_2 *ClassDef = (kbts_class_definition_2 *)Base; + kbts_class_range_record *Ranges = KBTS_POINTER_AFTER(kbts_class_range_record, ClassDef); + KBTS_FOR(RangeIndex, 0, ClassDef->Count) + { + kbts_class_range_record *Range = &Ranges[RangeIndex]; + + KBTS_DUMPF("[%x..%x] -> %u\n", Range->StartGlyphId, Range->EndGlyphId, Range->Class); + } + } +} +#endif + +static void kbts_ByteSwapClassDefinition(kbts_byteswap_context *Context, kbts_u16 *Base) +{ + if(!kbts_AlreadyVisited(Context, Base)) + { + *Base = kbts_ByteSwap16(*Base); + + if(*Base == 1) + { + kbts_class_definition_1 *ClassDef = (kbts_class_definition_1 *)Base; + kbts_ByteSwapArray16Context(&ClassDef->StartGlyphId, 2, Context); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, ClassDef), ClassDef->GlyphCount, Context); + } + else if(*Base == 2) + { + kbts_class_definition_2 *ClassDef = (kbts_class_definition_2 *)Base; + ClassDef->Count = kbts_ByteSwap16(ClassDef->Count); + + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, ClassDef), ClassDef->Count * 3, Context); + } + } +} + +typedef struct kbts_glyph_class_from_table_result +{ + int Found; + kbts_u16 Class; +} kbts_glyph_class_from_table_result; + +static kbts_glyph_class_from_table_result kbts_GlyphClassFromTable(kbts_u16 *ClassDefinitionBase, kbts_un Id) +{ + kbts_glyph_class_from_table_result Result = KBTS_ZERO; + + // From the Microsoft docs: + // There is one offset to a ChainedClassSequenceRuleSet subtable for each class defined in the input sequence + // class definition table. The offsets are listed in class value order. + // This means that we do not actually care what the class _values_ are. We only care about the classes' relative + // values. + // Also from the Microsoft docs, about class definition tables: + // A class definition table (ClassDef) assigns glyphs into classes, beginning with Class 1, then Class 2, and so + // on. All glyphs not assigned to a class fall into Class 0. + // So, we should be able to pretty reliably just subtract 1 from the class to get. + + if(*ClassDefinitionBase == 1) + { + kbts_class_definition_1 *ClassDef = (kbts_class_definition_1 *)ClassDefinitionBase; + kbts_u16 *GlyphClasses = KBTS_POINTER_AFTER(kbts_u16, ClassDef); + + kbts_un Offset = Id - ClassDef->StartGlyphId; + if(Offset < ClassDef->GlyphCount) + { + Result.Class = GlyphClasses[Offset]; + Result.Found = 1; + } + } + else if(*ClassDefinitionBase == 2) + { + kbts_class_definition_2 *ClassDef = (kbts_class_definition_2 *)ClassDefinitionBase; + kbts_class_range_record *Ranges = KBTS_POINTER_AFTER(kbts_class_range_record, ClassDef); + + kbts_un RangeCount = ClassDef->Count; + if(RangeCount) + { + while(RangeCount > 1) + { + kbts_un HalfCount = RangeCount / 2; + Ranges = (Ranges[HalfCount - 1].EndGlyphId < Id) ? (Ranges + HalfCount) : Ranges; + RangeCount -= HalfCount; + } + if((Id >= Ranges->StartGlyphId) && (Id <= Ranges->EndGlyphId)) + { + Result.Class = Ranges->Class; + Result.Found = 1; + } + } + } + + return Result; +} + +static kbts_cover_glyph_result kbts_CoverGlyph(kbts_coverage *Coverage, kbts_u32 GlyphId) +{ + KBTS_INSTRUMENT_FUNCTION_BEGIN + kbts_cover_glyph_result Result = KBTS_ZERO; + kbts_un Count = Coverage->Count; + + if(Count) + { + if(Coverage->Format == 1) + { + kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Coverage); + + while(Count > 1) + { + kbts_un HalfCount = Count / 2; + GlyphIds = (GlyphIds[HalfCount - 1] < GlyphId) ? (GlyphIds + HalfCount) : GlyphIds; + Count -= HalfCount; + } + + if(GlyphId == *GlyphIds) + { + Result.Valid = 1; + Result.Index = (kbts_u32)(GlyphIds - KBTS_POINTER_AFTER(kbts_u16, Coverage)); + } + } + else if(Coverage->Format == 2) + { + kbts_range_record *Ranges = KBTS_POINTER_AFTER(kbts_range_record, Coverage); + + while(Count > 1) + { + kbts_un HalfCount = Count / 2; + Ranges = (Ranges[HalfCount - 1].EndGlyphId < GlyphId) ? (Ranges + HalfCount) : Ranges; + Count -= HalfCount; + } + if((GlyphId >= Ranges->StartGlyphId) && (GlyphId <= Ranges->EndGlyphId)) + { + Result.Valid = 1; + Result.Index = Ranges->StartCoverageIndex + GlyphId - Ranges->StartGlyphId; + } + } + } + + KBTS_INSTRUMENT_END + return Result; +} + +static void kbts_ByteSwapSequenceContextSubtable(kbts_byteswap_context *Context, kbts_u16 *Base) +{ + if(Base[0] == 1) + { + kbts_sequence_context_1 *Subst = (kbts_sequence_context_1 *)Base; + Subst->SeqRuleSetCount = kbts_ByteSwap16(Subst->SeqRuleSetCount); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->SeqRuleSetCount, Context); + + KBTS_FOR(SetIndex, 0, Subst->SeqRuleSetCount) + { + kbts_sequence_rule_set *Set = kbts_GetSequenceRuleSet(Subst, SetIndex); + + if(Set && !kbts_AlreadyVisited(Context, Set)) + { + Set->Count = kbts_ByteSwap16(Set->Count); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->Count, Context); + + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_sequence_rule *Rule = kbts_GetSequenceRule(Set, RuleIndex); + + if(!kbts_AlreadyVisited(Context, Rule)) + { + kbts_ByteSwapArray16Context(&Rule->GlyphCount, 2, Context); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Rule), (kbts_un)Rule->GlyphCount - 1 + (kbts_un)Rule->SequenceLookupCount * 2, Context); + } + } + } + } + } + else if(Base[0] == 2) + { + kbts_sequence_context_2 *Subst = (kbts_sequence_context_2 *)Base; + kbts_ByteSwapArray16Context(&Subst->ClassDefOffset, 2, Context); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->ClassSequenceRuleSetCount, Context); + + kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->ClassDefOffset); + kbts_ByteSwapClassDefinition(Context, ClassDefBase); + + KBTS_FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) + { + kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, SetIndex); + + if(Set && !kbts_AlreadyVisited(Context, Set)) + { + Set->Count = kbts_ByteSwap16(Set->Count); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->Count, Context); + + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); + + if(!kbts_AlreadyVisited(Context, Rule)) + { + kbts_ByteSwapArray16Context(&Rule->GlyphCount, 2, Context); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Rule), Rule->GlyphCount - 1 + 2 * Rule->SequenceLookupCount, Context); + } + } + } + } + + #ifdef KBTS_DUMP + kbts_DumpClassDefinition(ClassDefBase); + KBTS_FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) + { + kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, SetIndex); + + if(Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); + kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); + kbts_sequence_lookup_record *Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); + KBTS_DUMPF("Input: ["); + KBTS_FOR(GlyphIndex, 1, Rule->GlyphCount) + { + KBTS_DUMPF(", %x", InputSequence[GlyphIndex - 1]); + } + KBTS_DUMPF("]\nRecords: ["); + KBTS_FOR(RecordIndex, 0, Rule->SequenceLookupCount) + { + kbts_sequence_lookup_record *Record = &Records[RecordIndex]; + if(RecordIndex) KBTS_DUMPF(", "); + KBTS_DUMPF("%u@%u", Record->LookupListIndex, Record->SequenceIndex); + } + KBTS_DUMPF("]\n"); + } + } + } + #endif + } + else if(Base[0] == 3) + { + kbts_sequence_context_3 *Subst = (kbts_sequence_context_3 *)Base; + kbts_ByteSwapArray16Context(&Subst->GlyphCount, 2, Context); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->GlyphCount + 2 * Subst->SequenceLookupCount, Context); + + kbts_u16 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + KBTS_FOR(CoverageIndex, 0, Subst->GlyphCount) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, CoverageOffsets[CoverageIndex]); + + kbts_ByteSwapCoverage(Context, Coverage); + } + } +} + +typedef kbts_u32 kbts_skip_flags; +enum kbts_skip_flags_enum +{ + KBTS_SKIP_FLAG_NONE, + KBTS_SKIP_FLAG_ZWNJ = (1 << 0), + KBTS_SKIP_FLAG_ZWJ = (1 << 1), +}; +// The Harfbuzz behavior is: +// - GPOS lookups always skip ZWNJ. +// - Sequence lookups always skip ZWJ. +// - GSUB sequence lookups skip ZWNJ when requested. +// - Regular lookups skip ZWJ when requested. +#define KBTS_SKIP_FLAGS_GSUB_REGULAR(RequestedFlags) ((RequestedFlags) & KBTS_SKIP_FLAG_ZWJ) +#define KBTS_SKIP_FLAGS_GSUB_SEQUENCE(RequestedFlags) (KBTS_SKIP_FLAG_ZWJ | ((RequestedFlags) & KBTS_SKIP_FLAG_ZWNJ)) +#define KBTS_SKIP_FLAGS_GPOS_REGULAR(RequestedFlags) (((RequestedFlags) & KBTS_SKIP_FLAG_ZWJ) | KBTS_SKIP_FLAG_ZWNJ) +#define KBTS_SKIP_FLAGS_GPOS_SEQUENCE(RequestedFlags) (KBTS_SKIP_FLAG_ZWJ | KBTS_SKIP_FLAG_ZWNJ) + +static kbts_skip_flags kbts_SkipFlags(kbts_feature_id FeatureId, kbts_shaper Shaper) +{ + kbts_skip_flags Result = 0; + switch(FeatureId) + { + case KBTS_FEATURE_ID_nukt: + case KBTS_FEATURE_ID_akhn: + case KBTS_FEATURE_ID_rphf: + case KBTS_FEATURE_ID_rkrf: + case KBTS_FEATURE_ID_pref: + case KBTS_FEATURE_ID_blwf: + case KBTS_FEATURE_ID_abvf: + case KBTS_FEATURE_ID_half: + case KBTS_FEATURE_ID_pstf: + case KBTS_FEATURE_ID_vatu: + case KBTS_FEATURE_ID_cjct: + case KBTS_FEATURE_ID_pres: + case KBTS_FEATURE_ID_abvs: + case KBTS_FEATURE_ID_blws: + case KBTS_FEATURE_ID_psts: + case KBTS_FEATURE_ID_haln: + Result = (Shaper == KBTS_SHAPER_INDIC) ? 0 : KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ; + break; + + case KBTS_FEATURE_ID_init: + if (Shaper == KBTS_SHAPER_INDIC) {Result = 0;} + else if(Shaper == KBTS_SHAPER_ARABIC) {Result = KBTS_SKIP_FLAG_ZWNJ;} + else {Result = KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ;} + break; + + case KBTS_FEATURE_ID_ccmp: + case KBTS_FEATURE_ID_locl: + case KBTS_FEATURE_ID_isol: + case KBTS_FEATURE_ID_fina: + case KBTS_FEATURE_ID_fin2: + case KBTS_FEATURE_ID_fin3: + case KBTS_FEATURE_ID_medi: + case KBTS_FEATURE_ID_med2: + case KBTS_FEATURE_ID_calt: + case KBTS_FEATURE_ID_liga: + case KBTS_FEATURE_ID_clig: + case KBTS_FEATURE_ID_rlig: + case KBTS_FEATURE_ID_mset: + Result = (Shaper == KBTS_SHAPER_ARABIC) ? KBTS_SKIP_FLAG_ZWNJ : KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ; + break; + + case KBTS_FEATURE_ID_mark: + case KBTS_FEATURE_ID_mkmk: + Result = 0; + break; + + default: + Result = KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ; + break; + } + return Result; +} + +static kbts_u32 kbts_GlyphIncludedInLookup(kbts_font *Font, int Gpos, kbts_un LookupIndex, kbts_u32 Id) +{ + kbts_u32 Result = 1; + if(Font->GlyphLookupMatrix && (Id < Font->GlyphCount)) + { + kbts_un FlatLookupIndex = (Gpos ? Font->GposLookupIndexOffset : 0) + LookupIndex; + kbts_un FlatIndex = FlatLookupIndex * Font->Maxp->GlyphCount + Id; + kbts_un WordIndex = FlatIndex / 32; + kbts_un BitIndex = FlatIndex % 32; + + Result = Font->GlyphLookupMatrix[WordIndex] & (1 << BitIndex); + } + return Result; +} + +static int kbts_GlyphPassesLookupFilter(kbts_glyph *Glyph, kbts_unpacked_lookup *Lookup) +{ + int Result = 1; + kbts_u16 Class = Glyph->Classes.Class; + + if(Class && (Lookup->Flags & (1 << Class))) + { + Result = 0; + } + + if(Result && (Class == KBTS_GLYPH_CLASS_MARK)) + { + if(Lookup->Flags & KBTS_LOOKUP_FLAG_MARK_ATTACHMENT_CLASS_FILTER) + { + kbts_u32 DesiredMarkAttachmentClass = Lookup->Flags >> 8; + + if(Glyph->Classes.MarkAttachmentClass != DesiredMarkAttachmentClass) + { + Result = 0; + } + } + + if(Result && Lookup->MarkFilteringSet) + { + // @Speed: We may want to save the result of the last mark filtering test on the glyph itself. + kbts_cover_glyph_result Cover = kbts_CoverGlyph(Lookup->MarkFilteringSet, Glyph->Id); + if(!Cover.Valid) + { + Result = 0; + } + } + } + + return Result; +} + +static int kbts_SkipGlyph(kbts_glyph *Glyph, kbts_unpacked_lookup *Lookup, kbts_skip_flags SkipFlags, kbts_u32 SkipUnicodeFlags) +{ + int Result = (Glyph->UnicodeFlags & SkipUnicodeFlags) || + ((SkipFlags & KBTS_SKIP_FLAG_ZWNJ) && (Glyph->Codepoint == 0x200C)) || + ((SkipFlags & KBTS_SKIP_FLAG_ZWJ) && (Glyph->Codepoint == 0x200D)) || + !kbts_GlyphPassesLookupFilter(Glyph, Lookup); + return Result; +} + +static int kbts_GlyphsIncludedInLookupSubtable(kbts_font *Font, int Gpos, kbts_unpacked_lookup *Lookup, kbts_un LookupIndex, kbts_un SubtableIndex, kbts_glyph_array *Array, kbts_un CurrentGlyphIndex, kbts_skip_flags SkipFlags, kbts_unicode_flags SkipUnicodeFlags) +{ + if(Font->GlyphLookupSubtableMatrix) + { + kbts_un FlatLookupIndex = (Gpos ? Font->GposLookupIndexOffset : 0) + LookupIndex; + kbts_un FlatSubtableIndex = Font->LookupSubtableIndexOffsets[FlatLookupIndex] + SubtableIndex; + kbts_un MatrixRowOffset = FlatSubtableIndex * Font->Maxp->GlyphCount; + kbts_lookup_subtable_info *Info = &Font->SubtableInfos[FlatSubtableIndex]; + kbts_un MinimumBacktrack = (Info->MinimumBacktrackPlusOne) ? Info->MinimumBacktrackPlusOne - 1 : 0; + kbts_un MinimumFollowup = (Info->MinimumFollowupPlusOne) ? Info->MinimumFollowupPlusOne - 1 : 0; + kbts_un GlyphCount = Font->GlyphCount; + + if((MinimumBacktrack <= CurrentGlyphIndex) && (MinimumFollowup <= (Array->Count - CurrentGlyphIndex))) + { + { // Check the current glyph. + kbts_un Id = Array->Glyphs[CurrentGlyphIndex].Id; + kbts_un FlatIndex = MatrixRowOffset + Id; + kbts_un WordIndex = FlatIndex / 32; + kbts_un BitIndex = FlatIndex % 32; + if(Id >= GlyphCount) + { + return 1; + } + else if(!(Font->GlyphLookupSubtableMatrix[WordIndex] & (1 << BitIndex))) + { + return 0; + } + } + + { + kbts_un BacktrackCounter = 0; + kbts_glyph *BacktrackGlyph = &Array->Glyphs[CurrentGlyphIndex - 1]; + while((BacktrackGlyph >= Array->Glyphs) && (BacktrackCounter < MinimumBacktrack)) + { + kbts_un FlatIndex = MatrixRowOffset + BacktrackGlyph->Id; + kbts_un WordIndex = FlatIndex / 32; + kbts_un BitIndex = FlatIndex % 32; + if(BacktrackGlyph->Id >= GlyphCount) + { + return 1; + } + else if(Font->GlyphLookupSubtableMatrix[WordIndex] & (1 << BitIndex)) + { + BacktrackCounter += 1; + } + else if(!kbts_SkipGlyph(BacktrackGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + return 0; + } + + BacktrackGlyph -= 1; + } + + if(BacktrackCounter < MinimumBacktrack) + { + return 0; + } + } + + { + kbts_un LookaheadCounter = 0; + kbts_glyph *LookaheadGlyph = &Array->Glyphs[CurrentGlyphIndex + 1]; + kbts_glyph *OnePastLastGlyph = Array->Glyphs + Array->Count; + while((LookaheadGlyph < OnePastLastGlyph) && (LookaheadCounter < MinimumFollowup)) + { + kbts_un FlatIndex = MatrixRowOffset + LookaheadGlyph->Id; + kbts_un WordIndex = FlatIndex / 32; + kbts_un BitIndex = FlatIndex % 32; + if(LookaheadGlyph->Id >= GlyphCount) + { + return 1; + } + else if(Font->GlyphLookupSubtableMatrix[WordIndex] & (1 << BitIndex)) + { + LookaheadCounter += 1; + } + else if(!kbts_SkipGlyph(LookaheadGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + return 0; + } + + LookaheadGlyph += 1; + } + + if(LookaheadCounter < MinimumFollowup) + { + return 0; + } + } + } + else + { + return 0; + } + } + + return 1; +} + +# ifdef KBTS_DUMP +static void kbts_DumpCoverage(kbts_coverage *Coverage) +{ + KBTS_DUMPF("["); + if(Coverage->Format == 1) + { + kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Coverage); + KBTS_FOR(GlyphIndex, 0, Coverage->Count) + { + KBTS_DUMPF("%x,", GlyphIds[GlyphIndex]); + } + } + else if(Coverage->Format == 2) + { + kbts_range_record *Ranges = KBTS_POINTER_AFTER(kbts_range_record, Coverage); + KBTS_FOR(RangeIndex, 0, Coverage->Count) + { + kbts_range_record *Range = &Ranges[RangeIndex]; + KBTS_DUMPF("%x..%x @ %u,", Range->StartGlyphId, Range->EndGlyphId, Range->StartCoverageIndex); + } + } + KBTS_DUMPF("]"); +} +# endif + +static void kbts_ByteSwapChainedSequenceContextSubtable(kbts_byteswap_context *Context, kbts_u16 *Base) +{ + if(Base[0] == 1) + { + kbts_chained_sequence_context_1 *Subst = (kbts_chained_sequence_context_1 *)Base; + Subst->ChainedSequenceRuleSetCount = kbts_ByteSwap16(Subst->ChainedSequenceRuleSetCount); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->ChainedSequenceRuleSetCount, Context); + + KBTS_FOR(SetIndex, 0, Subst->ChainedSequenceRuleSetCount) + { + kbts_ByteSwapChainedSequenceRuleSet(Context, kbts_GetChainedSequenceRuleSet(Subst, SetIndex)); + } + } + else if(Base[0] == 2) + { + kbts_chained_sequence_context_2 *Subst = (kbts_chained_sequence_context_2 *)Base; + kbts_ByteSwapArray16Context(&Subst->BacktrackClassDefOffset, 4, Context); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->ChainedClassSequenceRuleSetCount, Context); + + kbts_u16 *BacktrackClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->BacktrackClassDefOffset); + kbts_ByteSwapClassDefinition(Context, BacktrackClassDefinition); + + kbts_u16 *InputClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->InputClassDefOffset); + kbts_ByteSwapClassDefinition(Context, InputClassDefinition); + + kbts_u16 *LookaheadClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->LookaheadClassDefOffset); + kbts_ByteSwapClassDefinition(Context, LookaheadClassDefinition); + + #ifdef KBTS_DUMP + KBTS_DUMPF("Backtrack classes:\n"); + // kbts_DumpClassDefinition(BacktrackClassDefinition); + KBTS_DUMPF("Input classes:\n"); + // kbts_DumpClassDefinition(InputClassDefinition); + KBTS_DUMPF("Lookahead classes:\n"); + // kbts_DumpClassDefinition(LookaheadClassDefinition); + #endif + + KBTS_FOR(SetIndex, 0, Subst->ChainedClassSequenceRuleSetCount) + { + kbts_chained_sequence_rule_set *Set = kbts_GetChainedClassSequenceRuleSet(Subst, SetIndex); + kbts_ByteSwapChainedSequenceRuleSet(Context, Set); + + #ifdef KBTS_DUMP + if(Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_chained_sequence_rule *Rule = kbts_GetChainedClassSequenceRule(Set, RuleIndex); + kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + + KBTS_DUMPF("Backtrack: ["); + KBTS_FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) + { + if(BacktrackIndex) KBTS_DUMPF(", "); + KBTS_DUMPF("%u", Unpacked.Backtrack[BacktrackIndex]); + } + KBTS_DUMPF("]\n" + "Input: ["); + KBTS_FOR(InputIndex, 1, Unpacked.InputCount) + { + if(InputIndex) KBTS_DUMPF(", "); + KBTS_DUMPF("%u", Unpacked.Input[InputIndex - 1]); + } + KBTS_DUMPF("]\n" + "Lookahead: ["); + KBTS_FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) + { + if(LookaheadIndex) KBTS_DUMPF(", "); + KBTS_DUMPF("%u", Unpacked.Lookahead[LookaheadIndex]); + } + KBTS_DUMPF("]\n" + "Records: ["); + KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) + { + kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; + if(RecordIndex) KBTS_DUMPF(", "); + KBTS_DUMPF("%u@%u", Record->LookupListIndex, Record->SequenceIndex); + } + KBTS_DUMPF("]\n"); + } + } + #endif + } + } + else if(Base[0] == 3) + { + kbts_chained_sequence_context_3 *Subst = (kbts_chained_sequence_context_3 *)Base; + kbts_unpacked_chained_sequence_context_3 Unpacked = kbts_UnpackChainedSequenceContext3(Subst, 1); + + kbts_un U16Count = Unpacked.BacktrackCount + Unpacked.InputCount + Unpacked.LookaheadCount + Unpacked.RecordCount * 2 + 4; + kbts_ByteSwapArray16Context(&Subst->BacktrackGlyphCount, U16Count, Context); + + KBTS_FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex]); + + kbts_ByteSwapCoverage(Context, Coverage); + } + + KBTS_FOR(InputCoverageIndex, 0, Unpacked.InputCount) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.InputCoverageOffsets[InputCoverageIndex]); + + kbts_ByteSwapCoverage(Context, Coverage); + } + + KBTS_FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex]); + + kbts_ByteSwapCoverage(Context, Coverage); + } + +# ifdef KBTS_DUMP + KBTS_DUMPF(" Backtrack: "); + KBTS_FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) + { + kbts_DumpCoverage(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex])); + } + KBTS_DUMPF("\n Input: "); + KBTS_FOR(InputCoverageIndex, 0, Unpacked.InputCount) + { + kbts_DumpCoverage(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.InputCoverageOffsets[InputCoverageIndex])); + } + KBTS_DUMPF("\n Lookahead: "); + KBTS_FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) + { + kbts_DumpCoverage(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex])); + } + KBTS_DUMPF("\n Lookups: ["); + KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) + { + kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; + + KBTS_DUMPF("%u@%u,", Record->LookupListIndex, Record->SequenceIndex); + } + KBTS_DUMPF("]\n"); +# endif + } +} + +static void kbts_ByteSwapGsubLookupSubtable(kbts_byteswap_context *Context, kbts_u16 LookupType, kbts_u16 *Base) +{ + int Swap = !kbts_AlreadyVisited(Context, Base); + while(Swap && (LookupType == 7)) + { + kbts_extension *Subst = (kbts_extension *)Base; + Subst->Format = kbts_ByteSwap16(Subst->Format); + Subst->LookupType = kbts_ByteSwap16(Subst->LookupType); + Subst->Offset = kbts_ByteSwap32(Subst->Offset); + + KBTS_DUMPF(" Type 7.1\n" + " Offset %zu\n" + " -> %zu\n", + (char *)Base - Context->FileBase, (char *)Subst + Subst->Offset - Context->FileBase); + + Base = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->Offset); + LookupType = Subst->LookupType; + + Swap = !kbts_AlreadyVisited(Context, Base); + } + + if(Swap) + { + *Base = kbts_ByteSwap16(*Base); + + KBTS_DUMPF(" Type %u.%u\n" + " Offset %zu\n", + LookupType, *Base, (char *)Base - Context->FileBase); + + if(kbts_GsubLookupBeginsWithCoverage(LookupType, Base[0])) + { + Base[1] = kbts_ByteSwap16(Base[1]); + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, Base[1]); + + kbts_ByteSwapCoverage(Context, Coverage); + +# ifdef KBTS_DUMP + KBTS_DUMPF(" Coverage %u\n", Coverage->Format); + if(Coverage->Format == 1) + { + kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Coverage); + KBTS_FOR(GlyphIndex, 0, Coverage->Count) + { + KBTS_DUMPF(" %x\n", GlyphIds[GlyphIndex]); + } + } + else if(Coverage->Format == 2) + { + kbts_range_record *Ranges = KBTS_POINTER_AFTER(kbts_range_record, Coverage); + KBTS_FOR(RangeIndex, 0, Coverage->Count) + { + kbts_range_record Range = Ranges[RangeIndex]; + KBTS_DUMPF(" %x..%x@%u..%u\n", Range.StartGlyphId, Range.EndGlyphId, Range.StartCoverageIndex, Range.StartCoverageIndex + (Range.EndGlyphId - Range.StartGlyphId)); + } + } +# endif + } + + switch(LookupType) + { + case 1: + { + kbts_single_substitution *Subst = (kbts_single_substitution *)Base; + Subst->DeltaOrCount.GlyphCount = kbts_ByteSwap16(Subst->DeltaOrCount.GlyphCount); + +# ifdef KBTS_DUMP + if(Subst->Format == 1) + { + KBTS_DUMPF(" += %d\n", Subst->DeltaOrCount.DeltaGlyphId); + } +# endif + + if(Subst->Format == 2) + { + kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Subst); + kbts_ByteSwapArray16Context(GlyphIds, Subst->DeltaOrCount.GlyphCount, Context); + + #ifdef KBTS_DUMP + KBTS_DUMPF(" ["); + KBTS_FOR(IdIndex, 0, Subst->DeltaOrCount.GlyphCount) + { + if(IdIndex) KBTS_DUMPF(" "); + KBTS_DUMPF("%x", GlyphIds[IdIndex]); + } + KBTS_DUMPF("]\n"); + #endif + } + } + break; + + case 2: + { + kbts_multiple_substitution *Subst = (kbts_multiple_substitution *)Base; + Subst->SequenceCount = kbts_ByteSwap16(Subst->SequenceCount); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->SequenceCount, Context); + + KBTS_FOR(SequenceIndex, 0, Subst->SequenceCount) + { + kbts_sequence *Sequence = kbts_GetSequence(Subst, SequenceIndex); + + if(!kbts_AlreadyVisited(Context, Sequence)) + { + Sequence->GlyphCount = kbts_ByteSwap16(Sequence->GlyphCount); + + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Sequence), Sequence->GlyphCount, Context); + } + + #ifdef KBTS_DUMP + KBTS_DUMPF(" ["); + kbts_u16 *SequenceGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Sequence); + KBTS_FOR(SequenceGlyphIndex, 0, Sequence->GlyphCount) + { + if(SequenceGlyphIndex) KBTS_DUMPF(" "); + KBTS_DUMPF("%x", SequenceGlyphIds[SequenceGlyphIndex]); + } + KBTS_DUMPF("]\n"); + #endif + } + } + break; + + case 3: + { + kbts_alternate_substitution *Subst = (kbts_alternate_substitution *)Base; + Subst->AlternateSetCount = kbts_ByteSwap16(Subst->AlternateSetCount); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->AlternateSetCount, Context); + + KBTS_FOR(SetIndex, 0, Subst->AlternateSetCount) + { + kbts_alternate_set *Set = kbts_GetAlternateSet(Subst, SetIndex); + + if(!kbts_AlreadyVisited(Context, Set)) + { + Set->GlyphCount = kbts_ByteSwap16(Set->GlyphCount); + + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->GlyphCount, Context); + } + + #ifdef KBTS_DUMP + KBTS_DUMPF(" ["); + kbts_u16 *SetGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Set); + KBTS_FOR(SetGlyphIndex, 0, Set->GlyphCount) + { + if(SetGlyphIndex) KBTS_DUMPF(" "); + KBTS_DUMPF("%x", SetGlyphIds[SetGlyphIndex]); + } + KBTS_DUMPF("]\n"); + #endif + } + } + break; + + case 4: + { + kbts_ligature_substitution *Subst = (kbts_ligature_substitution *)Base; + Subst->LigatureSetCount = kbts_ByteSwap16(Subst->LigatureSetCount); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Subst), Subst->LigatureSetCount, Context); + + KBTS_FOR(SetIndex, 0, Subst->LigatureSetCount) + { + kbts_ligature_set *Set = kbts_GetLigatureSet(Subst, SetIndex); + + if(!kbts_AlreadyVisited(Context, Set)) + { + Set->Count = kbts_ByteSwap16(Set->Count); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Set), Set->Count, Context); + + KBTS_FOR(LigatureIndex, 0, Set->Count) + { + kbts_ligature *Ligature = kbts_GetLigature(Set, LigatureIndex); + + if(!kbts_AlreadyVisited(Context, Ligature)) + { + kbts_ByteSwapArray16Context(&Ligature->Glyph, 2, Context); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Ligature), Ligature->ComponentCount - 1, Context); + +# ifdef KBTS_DUMP + KBTS_DUMPF("ligature: ["); + kbts_u16 *ComponentIds = KBTS_POINTER_AFTER(kbts_u16, Ligature); + KBTS_FOR(ComponentIndex, 1, Ligature->ComponentCount) + { + KBTS_DUMPF("%x,", ComponentIds[ComponentIndex - 1]); + } + KBTS_DUMPF("] -> %x\n", Ligature->Glyph); +# endif + } + } + } + } + +# ifdef KBTS_DUMP + +# endif + } + break; + + case 5: + { + kbts_ByteSwapSequenceContextSubtable(Context, Base); + } + break; + + case 6: + { + kbts_ByteSwapChainedSequenceContextSubtable(Context, Base); + } + break; + + case 8: + { + kbts_reverse_chain_substitution *Subst = (kbts_reverse_chain_substitution *)Base; + kbts_unpacked_reverse_chain_substitution Unpacked = kbts_UnpackReverseChainSubstitution(Subst, 1); + + kbts_un U16Count = Unpacked.BacktrackCount + Unpacked.GlyphCount + Unpacked.LookaheadCount + 3; + kbts_ByteSwapArray16Context(&Subst->BacktrackGlyphCount, U16Count, Context); + + KBTS_FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) + { + kbts_ByteSwapCoverage(Context, KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex])); + } + KBTS_FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) + { + kbts_ByteSwapCoverage(Context, KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex])); + } + } + break; + } + } +} + +static void kbts_ByteSwapGposLookupSubtable(kbts_byteswap_context *Context, kbts_lookup_list *LookupList, kbts_u16 LookupType, kbts_u16 *Base) +{ + if(!kbts_AlreadyVisited(Context, Base)) + { + *Base = kbts_ByteSwap16(*Base); + + KBTS_DUMPF(" GPOS subtable %u.%u\n", LookupType, *Base); + + if(kbts_GposLookupBeginsWithCoverage(LookupType, *Base)) + { + kbts_u16 *CoverageOffset = &Base[1]; + *CoverageOffset = kbts_ByteSwap16(*CoverageOffset); + + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, *CoverageOffset); + kbts_ByteSwapCoverage(Context, Coverage); + } + + switch(LookupType) + { + case 1: + { + kbts_single_adjustment_1 *Adjust = (kbts_single_adjustment_1 *)Base; + Adjust->ValueFormat = kbts_ByteSwap16(Adjust->ValueFormat); + + if(Adjust->Format == 1) + { + kbts_ByteSwapValueRecord(Context, Adjust, Adjust->ValueFormat, KBTS_POINTER_AFTER(kbts_u16, Adjust)); + } + else if(Adjust->Format == 2) + { + kbts_single_adjustment_2 *Adjust2 = (kbts_single_adjustment_2 *)Base; + Adjust2->RecordCount = kbts_ByteSwap16(Adjust2->RecordCount); + + kbts_u16 *At = KBTS_POINTER_AFTER(kbts_u16, Adjust2); + KBTS_FOR(RecordIndex, 0, Adjust2->RecordCount) + { + kbts_unpacked_value_record Unpacked = kbts_ByteSwapValueRecord(Context, Adjust2, Adjust2->ValueFormat, At); + + At += Unpacked.Size; + } + } + } + break; + + case 2: + { + if(*Base == 1) + { + kbts_pair_adjustment_1 *Adjust = (kbts_pair_adjustment_1 *)Base; + kbts_ByteSwapArray16Context(&Adjust->ValueFormat1, 3, Context); + + kbts_u16 *SetOffsets = KBTS_POINTER_AFTER(kbts_u16, Adjust); + kbts_ByteSwapArray16Context(SetOffsets, Adjust->SetCount, Context); + + kbts_un Size1 = kbts_PopCount32(Adjust->ValueFormat1); + kbts_un Size2 = kbts_PopCount32(Adjust->ValueFormat2); + kbts_un PairRecordSize = Size1 + Size2 + 1; + + KBTS_FOR(SetIndex, 0, Adjust->SetCount) + { + kbts_pair_set *Set = KBTS_POINTER_OFFSET(kbts_pair_set, Adjust, SetOffsets[SetIndex]); + + if(!kbts_AlreadyVisited(Context, Set)) + { + Set->Count = kbts_ByteSwap16(Set->Count); + + kbts_u16 *At = KBTS_POINTER_AFTER(kbts_u16, Set); + + KBTS_FOR(RecordIndex, 0, Set->Count) + { + kbts_pair_value_record *PairRecord = (kbts_pair_value_record *)(At + RecordIndex * PairRecordSize); + + PairRecord->SecondGlyph = kbts_ByteSwap16(PairRecord->SecondGlyph); + kbts_u16 *Record = KBTS_POINTER_AFTER(kbts_u16, PairRecord); + + kbts_unpacked_value_record Unpacked1 = kbts_ByteSwapValueRecord(Context, Record, Adjust->ValueFormat1, Record); + Record += Unpacked1.Size; + kbts_ByteSwapValueRecord(Context, Record, Adjust->ValueFormat2, Record); + } + } + } + } + else if(*Base == 2) + { + kbts_pair_adjustment_2 *Adjust = (kbts_pair_adjustment_2 *)Base; + kbts_ByteSwapArray16Context(&Adjust->ValueFormat1, 6, Context); + + kbts_ByteSwapClassDefinition(Context, KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition1Offset)); + kbts_ByteSwapClassDefinition(Context, KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition2Offset)); + + kbts_u16 *Records = KBTS_POINTER_AFTER(kbts_u16, Adjust); + + kbts_un Size1 = kbts_PopCount32(Adjust->ValueFormat1); + kbts_un Size2 = kbts_PopCount32(Adjust->ValueFormat2); + + kbts_u16 *RecordPair = Records; + KBTS_FOR(RecordIndex, 0, (kbts_un)Adjust->Class1Count * (kbts_un)Adjust->Class2Count) + { + kbts_ByteSwapValueRecord(Context, Adjust, Adjust->ValueFormat1, RecordPair); + RecordPair += Size1; + + kbts_ByteSwapValueRecord(Context, Adjust, Adjust->ValueFormat2, RecordPair); + RecordPair += Size2; + } + } + } + break; + + case 3: + { + kbts_cursive_attachment *Adjust = (kbts_cursive_attachment *)Base; + Adjust->EntryExitCount = kbts_ByteSwap16(Adjust->EntryExitCount); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, Adjust), Adjust->EntryExitCount * 2, Context); + + kbts_entry_exit *EntryExits = KBTS_POINTER_AFTER(kbts_entry_exit, Adjust); + KBTS_FOR(EntryExitIndex, 0, Adjust->EntryExitCount) + { + kbts_entry_exit *EntryExit = &EntryExits[EntryExitIndex]; + + if(EntryExit->EntryAnchorOffset) + { + kbts_ByteSwapAnchor(Context, KBTS_POINTER_OFFSET(kbts_anchor, Adjust, EntryExit->EntryAnchorOffset)); + } + + if(EntryExit->ExitAnchorOffset) + { + kbts_ByteSwapAnchor(Context, KBTS_POINTER_OFFSET(kbts_anchor, Adjust, EntryExit->ExitAnchorOffset)); + } + } + } + break; + + case 4: + case 6: + { + kbts_mark_to_base_attachment *Adjust = (kbts_mark_to_base_attachment *)Base; + kbts_ByteSwapArray16Context(&Adjust->BaseCoverageOffset, 4, Context); + + kbts_ByteSwapCoverage(Context, KBTS_POINTER_OFFSET(kbts_coverage, Adjust, Adjust->BaseCoverageOffset)); + kbts_ByteSwapMarkArray(Context, KBTS_POINTER_OFFSET(kbts_mark_array, Adjust, Adjust->MarkArrayOffset)); + kbts_ByteSwapBaseArray(Context, Adjust->MarkClassCount, KBTS_POINTER_OFFSET(kbts_base_array, Adjust, Adjust->BaseArrayOffset)); + } + break; + + case 5: + { + kbts_mark_to_ligature_attachment *Adjust = (kbts_mark_to_ligature_attachment *)Base; + kbts_ByteSwapArray16Context(&Adjust->LigatureCoverageOffset, 4, Context); + + kbts_ByteSwapCoverage(Context, KBTS_POINTER_OFFSET(kbts_coverage, Adjust, Adjust->LigatureCoverageOffset)); + kbts_ByteSwapMarkArray(Context, KBTS_POINTER_OFFSET(kbts_mark_array, Adjust, Adjust->MarkArrayOffset)); + + kbts_ligature_array *LigatureArray = KBTS_POINTER_OFFSET(kbts_ligature_array, Adjust, Adjust->LigatureArrayOffset); + if(!kbts_AlreadyVisited(Context, LigatureArray)) + { + LigatureArray->Count = kbts_ByteSwap16(LigatureArray->Count); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, LigatureArray), LigatureArray->Count, Context); + + KBTS_FOR(AttachIndex, 0, LigatureArray->Count) + { + kbts_ligature_attach *Attach = kbts_GetLigatureAttach(LigatureArray, AttachIndex); + + if(!kbts_AlreadyVisited(Context, Attach)) + { + Attach->Count = kbts_ByteSwap16(Attach->Count); + + kbts_u16 *AttachAnchorOffsets = KBTS_POINTER_AFTER(kbts_u16, Attach); + kbts_ByteSwapArray16Context(AttachAnchorOffsets, Attach->Count * Adjust->MarkClassCount, Context); + + KBTS_FOR(ComponentIndex, 0, Attach->Count) + { + KBTS_FOR(MarkClass, 0, Adjust->MarkClassCount) + { + kbts_anchor *Anchor = kbts_GetLigatureAttachAnchor(Adjust, Attach, (kbts_u16)MarkClass, ComponentIndex); + + kbts_ByteSwapAnchor(Context, Anchor); + } + } + } + } + } + } + break; + + case 7: + { + kbts_ByteSwapSequenceContextSubtable(Context, Base); + } + break; + + case 8: + { + kbts_ByteSwapChainedSequenceContextSubtable(Context, Base); + } + break; + + case 9: + { + // @Cleanup: Replace recursion with a loop at the start of this function! + kbts_extension *Adjust = (kbts_extension *)Base; + + Adjust->LookupType = kbts_ByteSwap16(Adjust->LookupType); + Adjust->Offset = kbts_ByteSwap32(Adjust->Offset); + + kbts_ByteSwapGposLookupSubtable(Context, LookupList, Adjust->LookupType, KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->Offset)); + } + break; + } + } +} + +static kbts_glyph_classes kbts_GlyphClasses(kbts_font *Font, kbts_u32 Id) +{ + kbts_glyph_classes Result = KBTS_ZERO; + + // Look up all glyph classes. + kbts_gdef *Gdef = Font->Gdef; + if(Gdef) + { + if(Gdef->ClassDefinitionOffset) + { + kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Gdef, Gdef->ClassDefinitionOffset); + Result.Class = kbts_GlyphClassFromTable(ClassDefBase, Id).Class; + } + + if(Gdef->MarkAttachmentClassDefinitionOffset && (Result.Class == KBTS_GLYPH_CLASS_MARK)) + { + kbts_u16 *MarkAttachmentClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Gdef, Gdef->MarkAttachmentClassDefinitionOffset); + Result.MarkAttachmentClass = kbts_GlyphClassFromTable(MarkAttachmentClassDefBase, Id).Class; + } + } + + return Result; +} + +static int kbts_ScriptIsWeak(kbts_script Script) +{ + int Result = (Script == KBTS_SCRIPT_DONT_KNOW) || (Script == KBTS_SCRIPT_DEFAULT) || (Script == KBTS_SCRIPT_DEFAULT2); + return Result; +} + +static int kbts_ShaperRtl(kbts_shaper Shaper) +{ + int Result = (Shaper == KBTS_SHAPER_ARABIC) || (Shaper == KBTS_SHAPER_HEBREW); + return Result; +} + +// Easy shorthand for determining scripts in simple cases. +// Do not ship this! You should use script breaks instead. +KBTS_EXPORT void kbts_InferScript(kbts_direction *Direction, kbts_script *Script, kbts_script GlyphScript) +{ + if(Script) + { + if(kbts_ScriptIsWeak(*Script) && !kbts_ScriptIsWeak(GlyphScript)) + { + *Script = GlyphScript; + if(Direction && (!*Direction)) + { + kbts_script_properties *Properties = &kbts_ScriptProperties[GlyphScript]; + *Direction = kbts_ShaperRtl(Properties->Shaper) ? KBTS_DIRECTION_RTL : KBTS_DIRECTION_LTR; + } + } + } +} + +KBTS_EXPORT kbts_glyph kbts_CodepointToGlyph(kbts_font *Font, kbts_u32 Codepoint) +{ + kbts_glyph Result = KBTS_ZERO; + Result.Codepoint = Codepoint; + + // Look up Unicode properties. + Result.Decomposition = kbts_GetUnicodeDecomposition(Codepoint); + Result.JoiningType = kbts_GetUnicodeJoiningType(Codepoint); + Result.UnicodeFlags = kbts_GetUnicodeFlags(Codepoint); + kbts_u16 SyllabicInfo = kbts_GetUnicodeSyllabicInfo(Codepoint); + Result.SyllabicClass = kbts_GetSyllabicClass(SyllabicInfo); + Result.SyllabicPosition = kbts_GetSyllabicPosition(SyllabicInfo); + Result.CombiningClass = kbts_GetUnicodeCombiningClass(Codepoint); + Result.UseClass = kbts_GetUnicodeUseClass(Codepoint); + Result.Script = kbts_GetUnicodeScript(Codepoint); + Result.ParentInfo = kbts_GetUnicodeParentInfo(Codepoint); + + kbts_u16 *CmapBase = Font->Cmap; + if(CmapBase) + { + switch(*CmapBase) + { + case 0: + { + kbts_cmap_0 *Cmap0 = (kbts_cmap_0 *)CmapBase; + + if((kbts_un)Codepoint < KBTS_ARRAY_LENGTH(Cmap0->GlyphIdArray)) + { + Result.Id = Cmap0->GlyphIdArray[Codepoint]; + } + } break; + + case 2: + { + kbts_cmap_2 *Cmap2 = (kbts_cmap_2 *)CmapBase; + kbts_sub_header *SubHeaders = KBTS_POINTER_AFTER(kbts_sub_header, Cmap2); + + kbts_u32 High = (Codepoint >> 8) & 0xFF; + + if(!(Codepoint & 0xFF00)) + { + High = Codepoint & 0xFF; + } + + // The Microsoft documentation doesn't mention that the SubHeaderKeys are indices multiplied by 8, for some + // reason..! The Apple documentation does. + kbts_u16 SubHeaderIndex = Cmap2->SubHeaderKeys[High] / 8; + kbts_sub_header *SubHeader = &SubHeaders[SubHeaderIndex]; + + if(!SubHeaderIndex) + { + // With SubHeader 0, we only use the first byte. + Codepoint = High; + } + else + { + Codepoint = Codepoint & 0xFF; + } + + kbts_u32 Offset = Codepoint - SubHeader->FirstCode; + if(Offset < SubHeader->EntryCount) + { + kbts_u16 *GlyphIds = KBTS_POINTER_OFFSET(kbts_u16, &SubHeader->IdRangeOffset, SubHeader->IdRangeOffset); + kbts_u16 GlyphId = GlyphIds[Offset]; + if(GlyphId) + { + GlyphId += SubHeader->IdDelta; + } + + Result.Id = GlyphId; + } + } break; + + case 4: + { + kbts_cmap_4 *Cmap4 = (kbts_cmap_4 *)CmapBase; + kbts_un SegmentCount = Cmap4->SegmentCountTimesTwo / 2; + kbts_u16 *EndCodes = KBTS_POINTER_AFTER(kbts_u16, Cmap4); + kbts_u16 *StartCodes = EndCodes + SegmentCount + 1; + kbts_s16 *IdDeltas = (kbts_s16 *)(StartCodes + SegmentCount); + kbts_u16 *IdRangeOffsets = (kbts_u16 *)(IdDeltas + SegmentCount); + kbts_un SegmentIndexOffset = 0; + + if(SegmentCount) + { + while(SegmentCount > 1) + { + kbts_un HalfCount = SegmentCount / 2; + SegmentIndexOffset = (EndCodes[SegmentIndexOffset + HalfCount - 1] < Codepoint) ? (SegmentIndexOffset + HalfCount) : SegmentIndexOffset; + SegmentCount -= HalfCount; + } + } + + kbts_u16 Start = StartCodes[SegmentIndexOffset]; + if((Codepoint >= Start) && (Codepoint <= EndCodes[SegmentIndexOffset])) + { + kbts_s16 Delta = IdDeltas[SegmentIndexOffset]; + kbts_u16 RangeOffset = IdRangeOffsets[SegmentIndexOffset]; + + kbts_u16 GlyphId = (kbts_u16)Delta; + if(RangeOffset) + { + GlyphId += *(&IdRangeOffsets[SegmentIndexOffset] + (Codepoint - Start) + RangeOffset / 2); + } + else + { + GlyphId += (kbts_u16)(Codepoint); + } + Result.Id = GlyphId; + } + } break; + + case 6: + { + kbts_cmap_6 *Cmap6 = (kbts_cmap_6 *)CmapBase; + kbts_u16 *GlyphIds = KBTS_POINTER_AFTER(kbts_u16, Cmap6); + + kbts_un Offset = Codepoint - Cmap6->FirstCode; + if(Offset < Cmap6->EntryCount) + { + Result.Id = GlyphIds[Offset]; + } + } break; + + case 12: + { + kbts_cmap_12_13 *Cmap12 = (kbts_cmap_12_13 *)CmapBase; + kbts_sequential_map_group *Groups = KBTS_POINTER_AFTER(kbts_sequential_map_group, Cmap12); + + kbts_un GlyphId = 0; + kbts_un GroupCount = Cmap12->GroupCount; + if(GroupCount) + { + while(GroupCount > 1) + { + kbts_un HalfCount = GroupCount / 2; + Groups = (Groups[HalfCount - 1].EndCharacterCode < Codepoint) ? (Groups + HalfCount) : Groups; + GroupCount -= HalfCount; + } + } + + if((Codepoint >= Groups->StartCharacterCode) && (Codepoint <= Groups->EndCharacterCode)) + { + kbts_un Offset = Codepoint - Groups->StartCharacterCode; + GlyphId = Groups->StartGlyphId + Offset; + } + + Result.Id = (kbts_u16)GlyphId; + } break; + } + } + + if(Font->Gdef) + { + Result.Classes = kbts_GlyphClasses(Font, Result.Id); + } + else + { + // @Cleanup: This is garbage compatibility-with-broken-fonts code. I would very much like to get rid of it. + if((Result.UnicodeFlags & KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE) || !(Result.UnicodeFlags & KBTS_UNICODE_FLAG_NON_SPACING_MARK)) + { + Result.Classes.Class = KBTS_GLYPH_CLASS_BASE; + } + else + { + Result.Classes.Class = KBTS_GLYPH_CLASS_MARK; + } + } + + return Result; +} + +typedef struct kbts_iterate_features +{ + kbts_gsub_gpos *Header; + kbts_feature_list *FeatureList; + // @Incomplete + // kbts_feature_variations *FeatureVariations; + kbts_langsys *Langsys; + + kbts_feature_set EnabledFeatures; + + kbts_u32 CurrentFeatureTag; + kbts_u32 CurrentFeatureFlag; + + kbts_u32 FeatureIndex; + kbts_feature *Feature; +} kbts_iterate_features; + +static kbts_iterate_features kbts_IterateFeatures(kbts_shape_config *Config, kbts_shaping_table ShapingTable, kbts_feature_set EnabledFeatures) +{ + kbts_iterate_features Result = KBTS_ZERO; + + kbts_gsub_gpos *Header = Config->Font->ShapingTables[ShapingTable]; + if(Header) + { + // @Incomplete + // if(Header->Minor == 1) + // { + // Result.FeatureVariations = KBTS_POINTER_OFFSET(kbts_feature_variations, Header, Header->FeatureVariationsOffset); + // } + + Result.FeatureList = KBTS_POINTER_OFFSET(kbts_feature_list, Header, Header->FeatureListOffset); + Result.Header = Header; + Result.Langsys = Config->Langsys[ShapingTable]; + Result.EnabledFeatures = EnabledFeatures; + } + + return Result; +} + +static kbts_u32 kbts_IsValidFeatureIteration(kbts_iterate_features *It) +{ + kbts_u32 Result = It->Langsys != 0; + return Result; +} + +static kbts_u32 kbts_NextFeature(kbts_iterate_features *It) +{ + kbts_u32 Result = 0; + It->Feature = 0; + + if(kbts_IsValidFeatureIteration(It)) + { + kbts_u16 *FeatureIndices = KBTS_POINTER_AFTER(kbts_u16, It->Langsys); + // @Incomplete + // kbts_feature_variations *FeatureVariations = It->FeatureVariations; + while(It->FeatureIndex < It->Langsys->FeatureIndexCount) + { + kbts_feature_pointer Feature = kbts_GetFeature(It->FeatureList, FeatureIndices[It->FeatureIndex]); + + // We might need to swap out this feature with another. + // Check for variations. + // @Incomplete + //if(FeatureVariations) + //{ + // KBTS_FOR(VariationIndex, 0, FeatureVariations->RecordCount) + // { + // kbts_feature_variation_pointer Variation = kbts_GetFeatureVariation(FeatureVariations, VariationIndex); + // KBTS_FOR(ConditionIndex, 0, Variation.ConditionSet->Count) + // { + // kbts_condition_1 *Condition = kbts_GetCondition(Variation.ConditionSet, ConditionIndex); + // KBTS_ASSERT(0); + // } + // } + //} + + It->FeatureIndex += 1; + + kbts_u32 FeatureId = kbts_FeatureTagToId(Feature.Tag); + if(kbts_ContainsFeature(&It->EnabledFeatures, FeatureId)) + { + It->Feature = Feature.Feature; + It->CurrentFeatureTag = Feature.Tag; + if(FeatureId && (FeatureId <= 32)) + { + It->CurrentFeatureFlag = (1 << (FeatureId - 1)) & KBTS_GLYPH_FEATURE_MASK; + } + Result = 1; + + break; + } + } + } + + return Result; +} + +typedef struct kbts_iterate_lookups +{ + kbts_lookup_list *LookupList; + kbts_feature *Feature; + + kbts_lookup *Lookup; + kbts_u16 LookupIndex; + + kbts_u32 LookupIndexIndex; +} kbts_iterate_lookups; + +static kbts_iterate_lookups kbts_IterateLookups(kbts_lookup_list *List, kbts_feature *Feature) +{ + kbts_iterate_lookups Result = KBTS_ZERO; + Result.LookupList = List; + Result.Feature = Feature; + + return Result; +} + +static kbts_u32 kbts_NextLookup(kbts_iterate_lookups *It) +{ + kbts_u32 Result = 0; + kbts_feature *Feature = It->Feature; + + if(It->LookupList && Feature && (It->LookupIndexIndex < Feature->LookupIndexCount)) + { + kbts_u16 *LookupIndices = KBTS_POINTER_AFTER(kbts_u16, Feature); + + It->LookupIndex = LookupIndices[It->LookupIndexIndex]; + It->Lookup = kbts_GetLookup(It->LookupList, It->LookupIndex); + + Result = 1; + It->LookupIndexIndex += 1; + } + + return Result; +} + +KBTS_INLINE void kbts_GsubMutate(kbts_font *Font, kbts_glyph *Glyph, kbts_u16 NewId, kbts_u32 Flags) +{ + Glyph->Id = NewId; + Glyph->Classes = kbts_GlyphClasses(Font, NewId); + Glyph->Flags = (Glyph->Flags & ~KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION) | Flags; +} + +typedef struct kbts_do_single_substitution_result +{ + kbts_u32 ConsumedGlyphCount; + kbts_u32 WrittenGlyphCount; + kbts_u32 PerformedSubstitution; +} kbts_do_single_substitution_result; + +static kbts_feature_set kbts_ShaperFeatures[] = { + /* KBTS_SHAPER_DEFAULT */ {{KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs) | + KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | + KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG0(calt), + 0, + KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(liga) | + KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | + KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk), + KBTS_FEATURE_FLAG3(rvrn)}}, + /* KBTS_SHAPER_ARABIC */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | + KBTS_FEATURE_FLAG0(isol) | KBTS_FEATURE_FLAG0(fina) | KBTS_FEATURE_FLAG0(fin2) | KBTS_FEATURE_FLAG0(fin3) | + KBTS_FEATURE_FLAG0(medi) | KBTS_FEATURE_FLAG0(med2) | KBTS_FEATURE_FLAG0(init) | KBTS_FEATURE_FLAG0(calt) | + KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG2(mset) | KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | + KBTS_FEATURE_FLAG0(curs), + 0, + KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(liga) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(mark) | + KBTS_FEATURE_FLAG2(mkmk) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | KBTS_FEATURE_FLAG2(locl), + KBTS_FEATURE_FLAG3(rvrn) | KBTS_FEATURE_FLAG3(rtlm) | KBTS_FEATURE_FLAG3(stch) | KBTS_FEATURE_FLAG3(rtla)}}, + /* KBTS_SHAPER_HANGUL */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ljmo) | + KBTS_FEATURE_FLAG0(vjmo) | KBTS_FEATURE_FLAG0(tjmo) | KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | + KBTS_FEATURE_FLAG0(ccmp) | KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG0(curs), + 0, + KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | + KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk) | + KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(liga), + KBTS_FEATURE_FLAG3(rvrn)}}, + /* KBTS_SHAPER_HEBREW */ {{KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs) | + KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | + KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG0(calt), + 0, + KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(liga) | + KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | + KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk), + KBTS_FEATURE_FLAG3(rvrn)}}, // (Same as DEFAULT) + /* KBTS_SHAPER_INDIC */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(akhn) | + KBTS_FEATURE_FLAG0(rphf) | KBTS_FEATURE_FLAG0(pref) | KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(abvf) | + KBTS_FEATURE_FLAG0(half) | KBTS_FEATURE_FLAG0(pstf) | KBTS_FEATURE_FLAG0(cjct) | KBTS_FEATURE_FLAG0(abvs) | + KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(init) | KBTS_FEATURE_FLAG0(calt) | KBTS_FEATURE_FLAG0(clig) | + KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs), + 0, + KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(nukt) | KBTS_FEATURE_FLAG2(rkrf) | + KBTS_FEATURE_FLAG2(pres) | KBTS_FEATURE_FLAG2(psts) | KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(rlig) | + KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(haln) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(mark) | + KBTS_FEATURE_FLAG2(mkmk) | KBTS_FEATURE_FLAG2(kern), + KBTS_FEATURE_FLAG3(rvrn) | KBTS_FEATURE_FLAG3(vatu),}}, + /* KBTS_SHAPER_KHMER */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | + KBTS_FEATURE_FLAG0(pref) | KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(abvf) | KBTS_FEATURE_FLAG0(pstf) | + KBTS_FEATURE_FLAG0(cfar) | KBTS_FEATURE_FLAG0(abvs) | KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(calt) | + KBTS_FEATURE_FLAG0(clig) | KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs), + 0, + KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk) | + KBTS_FEATURE_FLAG2(pres) | KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(locl) | + KBTS_FEATURE_FLAG2(psts) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(rlig), + KBTS_FEATURE_FLAG3(rvrn)}}, + /* KBTS_SHAPER_MYANMAR */ {{KBTS_FEATURE_FLAG0(rphf) | KBTS_FEATURE_FLAG0(pref) | KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(pstf) | + KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | + KBTS_FEATURE_FLAG0(abvs) | KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(calt) | KBTS_FEATURE_FLAG0(clig) | + KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs), + 0, + KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk) | KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | + KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(psts) | KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(pres) | + KBTS_FEATURE_FLAG2(liga) | KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern), + KBTS_FEATURE_FLAG3(rvrn)}}, + /* KBTS_SHAPER_TIBETAN */ {{KBTS_FEATURE_FLAG0(ccmp) | KBTS_FEATURE_FLAG0(abvs) | KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(calt) | + KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm), + 0, + KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(liga) | KBTS_FEATURE_FLAG2(kern) | KBTS_FEATURE_FLAG2(mkmk), + 0}}, + /* KBTS_SHAPER_USE */ {{KBTS_FEATURE_FLAG0(frac) | KBTS_FEATURE_FLAG0(numr) | KBTS_FEATURE_FLAG0(dnom) | KBTS_FEATURE_FLAG0(ccmp) | + KBTS_FEATURE_FLAG0(akhn) | KBTS_FEATURE_FLAG0(rphf) | KBTS_FEATURE_FLAG0(pref) | KBTS_FEATURE_FLAG0(abvf) | + KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(cjct) | KBTS_FEATURE_FLAG0(half) | KBTS_FEATURE_FLAG0(pstf) | + KBTS_FEATURE_FLAG0(fina) | KBTS_FEATURE_FLAG0(init) | KBTS_FEATURE_FLAG0(isol) | KBTS_FEATURE_FLAG0(medi) | + KBTS_FEATURE_FLAG0(abvs) | KBTS_FEATURE_FLAG0(blws) | KBTS_FEATURE_FLAG0(calt) | KBTS_FEATURE_FLAG0(clig) | + KBTS_FEATURE_FLAG0(abvm) | KBTS_FEATURE_FLAG0(blwm) | KBTS_FEATURE_FLAG0(curs), + 0, + KBTS_FEATURE_FLAG2(ltra) | KBTS_FEATURE_FLAG2(ltrm) | KBTS_FEATURE_FLAG2(locl) | KBTS_FEATURE_FLAG2(nukt) | + KBTS_FEATURE_FLAG2(rkrf) | KBTS_FEATURE_FLAG2(rlig) | KBTS_FEATURE_FLAG2(dist) | KBTS_FEATURE_FLAG2(kern) | + KBTS_FEATURE_FLAG2(mark) | KBTS_FEATURE_FLAG2(mkmk) | KBTS_FEATURE_FLAG2(haln) | KBTS_FEATURE_FLAG2(liga) | + KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(pres) | KBTS_FEATURE_FLAG2(psts), + KBTS_FEATURE_FLAG3(rvrn) | KBTS_FEATURE_FLAG3(vatu)}}, +}; + +// Make sure that these fit KBTS_MAX_SIMULTANEOUS_FEATURES! +static kbts_u8 kbts_Ops_Default[] = { + KBTS_OP_KIND_NORMALIZE, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, + KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 12, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, + KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_clig, + KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_rclt, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_curs, + KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; + +/* @Incomplete: Vertical text. +static kbts_u8 kbts_Ops_DefaultTtbBtt[] = { + KBTS_OP_KIND_NORMALIZE, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, + KBTS_OP_KIND_GSUB_FEATURES, 3, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 10, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_mark, + KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_vert, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; +*/ +static kbts_u8 kbts_Ops_Hangul[] = { + KBTS_OP_KIND_NORMALIZE, KBTS_OP_KIND_NORMALIZE_HANGUL, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, + KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 8, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, + KBTS_FEATURE_ID_ljmo, KBTS_FEATURE_ID_vjmo, KBTS_FEATURE_ID_tjmo, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 13, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_mark, + KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_curs, + KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, KBTS_FEATURE_ID_rclt, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; +static kbts_u8 kbts_Ops_ArabicRclt[] = { + KBTS_OP_KIND_NORMALIZE, KBTS_OP_KIND_FLAG_JOINING_LETTERS, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, + KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_rtla, KBTS_FEATURE_ID_rtlm, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_stch, + KBTS_OP_KIND_GSUB_FEATURES, 2, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_isol, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fina, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fin2, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fin3, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_medi, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_med2, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_init, + // @Incomplete: In Arabic rlig, ZWJ should not be skipped in lookups (i.e. it should block ligatures). + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rlig, + // @Incomplete: In non-Arabic scripts, e.g. Syriac, Harfbuzz does not pause here. + KBTS_OP_KIND_GSUB_FEATURES, 5, KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_mset, KBTS_FEATURE_ID_rclt, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_curs, + KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, + KBTS_OP_KIND_STCH_POSTPASS, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; +static kbts_u8 kbts_Ops_ArabicNoRclt[] = { + KBTS_OP_KIND_NORMALIZE, KBTS_OP_KIND_FLAG_JOINING_LETTERS, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, + KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_rtla, KBTS_FEATURE_ID_rtlm, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_stch, + KBTS_OP_KIND_GSUB_FEATURES, 2, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_locl, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_isol, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fina, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fin2, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_fin3, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_medi, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_med2, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_init, + // @Incomplete: In Arabic rlig, ZWJ should not be skipped in lookups (i.e. it should block ligatures). + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rlig, + // @Incomplete: In non-Arabic scripts, e.g. Syriac, Harfbuzz does not pause here. + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_calt, + // When the font does not contain rclt, Uniscribe puts calt in its own pass, and so we pause here. + KBTS_OP_KIND_GSUB_FEATURES, 4, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_mset, KBTS_FEATURE_ID_rclt, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_curs, + KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, + KBTS_OP_KIND_STCH_POSTPASS, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; +static kbts_u8 kbts_Ops_Indic0[] = { + KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, KBTS_OP_KIND_NORMALIZE, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, + KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, +}; +// After BeginCluster. +static kbts_u8 kbts_Ops_Indic1[] = { + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_nukt, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_akhn, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rphf, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rkrf, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pref, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_blwf, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_abvf, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_half, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pstf, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_vatu, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_cjct, +}; +// After EndCluster. +static kbts_u8 kbts_Ops_Indic2[] = { + KBTS_OP_KIND_GSUB_FEATURES, 6, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_haln, KBTS_FEATURE_ID_init, KBTS_FEATURE_ID_pres, + KBTS_FEATURE_ID_psts, +}; +// After syllable processing. +static kbts_u8 kbts_Ops_Indic3[] = { + KBTS_OP_KIND_GSUB_FEATURES, 5, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_rclt, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, KBTS_FEATURE_ID_curs, + KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; +static kbts_u8 kbts_Ops_Use0[] = { + KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, KBTS_OP_KIND_NORMALIZE, KBTS_OP_KIND_FLAG_JOINING_LETTERS, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, + KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, +}; +static kbts_u8 kbts_Ops_Use1[] = { + KBTS_OP_KIND_GSUB_FEATURES, 4, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_nukt, KBTS_FEATURE_ID_akhn, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rphf, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pref, + KBTS_OP_KIND_GSUB_FEATURES, 7, KBTS_FEATURE_ID_abvf, KBTS_FEATURE_ID_blwf, KBTS_FEATURE_ID_cjct, KBTS_FEATURE_ID_half, KBTS_FEATURE_ID_pstf, + KBTS_FEATURE_ID_rkrf, KBTS_FEATURE_ID_vatu, +}; +// There is no kbts_Ops_Use2, because there are no features that apply per syllable after reordering. +static kbts_u8 kbts_Ops_Use3[] = { + KBTS_OP_KIND_GSUB_FEATURES, 4, KBTS_FEATURE_ID_fina, KBTS_FEATURE_ID_init, KBTS_FEATURE_ID_isol, KBTS_FEATURE_ID_medi, + KBTS_OP_KIND_GSUB_FEATURES,10, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_haln, KBTS_FEATURE_ID_pres, KBTS_FEATURE_ID_psts, + KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_rclt, KBTS_FEATURE_ID_rlig, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_curs, KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, + KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; +static kbts_u8 kbts_Ops_Tibetan[] = { + KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 1, KBTS_FEATURE_ID_locl, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_ccmp, + KBTS_OP_KIND_GSUB_FEATURES, 4, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_liga, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 4, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_kern, KBTS_FEATURE_ID_mkmk, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; +static kbts_u8 kbts_Ops_Khmer0[] = { + KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES, KBTS_OP_KIND_NORMALIZE, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rvrn, + KBTS_OP_KIND_GSUB_FEATURES_WITH_USER, 5, KBTS_FEATURE_ID_frac, KBTS_FEATURE_ID_numr, KBTS_FEATURE_ID_dnom, KBTS_FEATURE_ID_ltra, KBTS_FEATURE_ID_ltrm, +}; +static kbts_u8 kbts_Ops_Khmer1[] = { + KBTS_OP_KIND_GSUB_FEATURES, 7, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_ccmp, KBTS_FEATURE_ID_pref, KBTS_FEATURE_ID_blwf, KBTS_FEATURE_ID_abvf, + KBTS_FEATURE_ID_pstf, KBTS_FEATURE_ID_cfar, +}; +static kbts_u8 kbts_Ops_Khmer3[] = { + KBTS_OP_KIND_GSUB_FEATURES, 8, KBTS_FEATURE_ID_pres, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_psts, KBTS_FEATURE_ID_calt, + KBTS_FEATURE_ID_rclt, KBTS_FEATURE_ID_rlig, KBTS_FEATURE_ID_clig, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_curs, KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, + KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; +#define kbts_Ops_Myanmar0 kbts_Ops_Khmer0 +static kbts_u8 kbts_Ops_Myanmar1[] = { + KBTS_OP_KIND_GSUB_FEATURES, 2, KBTS_FEATURE_ID_locl, KBTS_FEATURE_ID_ccmp, +}; +static kbts_u8 kbts_Ops_Myanmar2[] = { + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_rphf, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pref, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_blwf, + KBTS_OP_KIND_GSUB_FEATURES, 1, KBTS_FEATURE_ID_pstf, +}; +static kbts_u8 kbts_Ops_Myanmar3[] = { + KBTS_OP_KIND_GSUB_FEATURES, 9, KBTS_FEATURE_ID_pres, KBTS_FEATURE_ID_abvs, KBTS_FEATURE_ID_blws, KBTS_FEATURE_ID_psts, KBTS_FEATURE_ID_rlig, + KBTS_FEATURE_ID_calt, KBTS_FEATURE_ID_clig, KBTS_FEATURE_ID_liga, KBTS_FEATURE_ID_rclt, + KBTS_OP_KIND_GPOS_METRICS, + KBTS_OP_KIND_GPOS_FEATURES, 7, KBTS_FEATURE_ID_abvm, KBTS_FEATURE_ID_blwm, KBTS_FEATURE_ID_curs, KBTS_FEATURE_ID_dist, KBTS_FEATURE_ID_kern, + KBTS_FEATURE_ID_mark, KBTS_FEATURE_ID_mkmk, + KBTS_OP_KIND_POST_GPOS_FIXUP, +}; + +static kbts_op_list kbts_ShaperOpLists[KBTS_SHAPER_COUNT] = { + /* DEFAULT, */ {kbts_Ops_Default, KBTS_ARRAY_LENGTH(kbts_Ops_Default)}, + /* ARABIC, */ {kbts_Ops_ArabicRclt, KBTS_ARRAY_LENGTH(kbts_Ops_ArabicRclt)}, + /* HANGUL, */ {kbts_Ops_Hangul, KBTS_ARRAY_LENGTH(kbts_Ops_Hangul)}, + /* HEBREW, */ {kbts_Ops_Default, KBTS_ARRAY_LENGTH(kbts_Ops_Default)}, + /* INDIC, */ {kbts_Ops_Indic0, KBTS_ARRAY_LENGTH(kbts_Ops_Indic0)}, + /* KHMER, */ {kbts_Ops_Khmer0, KBTS_ARRAY_LENGTH(kbts_Ops_Khmer0)}, + /* MYANMAR, */ {kbts_Ops_Myanmar0, KBTS_ARRAY_LENGTH(kbts_Ops_Myanmar0)}, + /* TIBETAN, */ {kbts_Ops_Tibetan, KBTS_ARRAY_LENGTH(kbts_Ops_Tibetan)}, + /* USE, */ {kbts_Ops_Use0, KBTS_ARRAY_LENGTH(kbts_Ops_Use0)}, +}; + +typedef struct kbts_gsub_frame +{ + kbts_u16 LookupIndex; + kbts_u16 SubtableIndex; + + kbts_u16 InputGlyphIndex; + kbts_u16 InputGlyphCount; + + // Defined for nested lookups. + kbts_sequence_lookup_record *Records; + kbts_u16 RecordCount; + kbts_u16 RecordIndex; +} kbts_gsub_frame; + +KBTS_EXPORT kbts_un kbts_SizeOfShapeState(kbts_font *Font) +{ + kbts_un GsubMemorySize = Font->LookupInfo.MaximumLookupStackSize * sizeof(kbts_gsub_frame); + kbts_un NormalizationMemorySize = KBTS_MAXIMUM_DECOMPOSITION_CODEPOINTS * sizeof(kbts_glyph); + kbts_un LeftoverMemorySize = KBTS_MAX(GsubMemorySize, NormalizationMemorySize); + + kbts_un Result = sizeof(kbts_shape_state) + LeftoverMemorySize; + return Result; +} + +KBTS_EXPORT kbts_shape_state *kbts_PlaceShapeState(void *Address, kbts_un Size) +{ + kbts_shape_state *State = (kbts_shape_state *)Address; + KBTS_MEMSET(State, 0, Size); + + return State; +} + +#ifndef KB_TEXT_SHAPE_NO_CRT +KBTS_EXPORT kbts_shape_state *kbts_CreateShapeState(kbts_font *Font) +{ + kbts_un Size = kbts_SizeOfShapeState(Font); + void *Memory = malloc(Size); + kbts_shape_state *Result = kbts_PlaceShapeState(Memory, Size); + + return Result; +} + +KBTS_EXPORT void kbts_FreeShapeState(kbts_shape_state *State) +{ + if(State) + { + free(State); + } +} +#endif + +KBTS_EXPORT void kbts_ResetShapeState(kbts_shape_state *State) +{ + State->ResumePoint = 0; +} + +static kbts_glyph_array kbts_ClipGlyphArray(kbts_glyph_array *Source, kbts_un Count) +{ + kbts_glyph_array Result = KBTS_ZERO; + Result.Glyphs = Source->Glyphs; + Result.Count = (kbts_u32)Count; + Result.TotalCount = (kbts_u32)Count; + Result.Capacity = (kbts_u32)Count; + return Result; +} + +static void kbts_TransferGrowRequest(kbts_glyph_array *From, kbts_glyph_array *To) +{ + if(From->RequiredCapacity > From->Capacity) + { + To->RequiredCapacity = To->Capacity + From->RequiredCapacity - From->Capacity; + } +} + +static kbts_glyph_array kbts_GlyphSubArray(kbts_glyph_array *Source, kbts_un FromIndex) +{ + kbts_glyph_array Result = KBTS_ZERO; + Result.Glyphs = Source->Glyphs + FromIndex; + Result.Count = (kbts_u32)(Source->Count - FromIndex); + Result.TotalCount = (kbts_u32)(Source->TotalCount - FromIndex); + Result.Capacity = (kbts_u32)(Source->Capacity - FromIndex); + return Result; +} + +static kbts_glyph_array kbts_GlyphArray(kbts_glyph *Glyphs, kbts_un Count, kbts_un TotalCount, kbts_un Capacity) +{ + kbts_glyph_array Result = KBTS_ZERO; + Result.Glyphs = Glyphs; + Result.Count = (kbts_u32)Count; + Result.TotalCount = (kbts_u32)TotalCount; + Result.Capacity = (kbts_u32)Capacity; + return Result; +} + +static int kbts_GrowGlyphArray(kbts_u32 *ResumePoint_, kbts_glyph_array *Array, kbts_un InsertIndex, kbts_un GrowCount, kbts_u32 ResumePoint, int DoNotModifyGlyphCounts) +{ + int Result = 0; + kbts_un TotalCount = Array->TotalCount; + kbts_un NewTotalCount = TotalCount + GrowCount; + + if(NewTotalCount <= Array->Capacity) + { + if(NewTotalCount > TotalCount) + { + for(kbts_un ToIndex = NewTotalCount; ToIndex > InsertIndex + GrowCount; --ToIndex) + { + Array->Glyphs[ToIndex - 1] = Array->Glyphs[ToIndex - 1 - GrowCount]; + } + } + else if(NewTotalCount < TotalCount) + { + // Multiple substitutions that generate 0 glyphs exist. In that case, GrowCount will be negative. + KBTS_FOR(ToIndex, InsertIndex, NewTotalCount) + { + Array->Glyphs[ToIndex] = Array->Glyphs[ToIndex - GrowCount]; + } + } + + if(!DoNotModifyGlyphCounts) + { + Array->Count += GrowCount; + Array->TotalCount = (kbts_u32)NewTotalCount; + } + Result = 1; + } + else + { + Array->RequiredCapacity = (kbts_u32)(NewTotalCount + KBTS_GROW_BUFFER_MARGIN); + if(ResumePoint_) *ResumePoint_ = ResumePoint; + } + + return Result; +} + +static void kbts_BeginFeatures(kbts_op_state *State, kbts_shape_config *Config, kbts_shaping_table ShapingTable, kbts_feature_set EnabledFeatures) +{ + kbts_un FeatureCount = 0; + kbts_gsub_gpos *Header = Config->Font->ShapingTables[ShapingTable]; + kbts_langsys *Langsys = Config->Langsys[ShapingTable]; + if(Header && Langsys) + { + kbts_feature_list *FeatureList = KBTS_POINTER_OFFSET(kbts_feature_list, Header, Header->FeatureListOffset); + kbts_u16 *FeatureIndices = KBTS_POINTER_AFTER(kbts_u16, Langsys); + // @Incomplete + // if(Header->Minor == 1) + // { + // kbts_feature_variations *FeatureVariations = KBTS_POINTER_OFFSET(kbts_feature_variations, Header, Header->FeatureVariationsOffset); + // } + + KBTS_FOR(FeatureIndexIndex, 0, Langsys->FeatureIndexCount) + { + kbts_un FeatureIndex = FeatureIndices[FeatureIndexIndex]; + kbts_feature_pointer Feature = kbts_GetFeature(FeatureList, FeatureIndex); + // @Incomplete + //if(FeatureVariations) + //{ + // KBTS_FOR(VariationIndex, 0, FeatureVariations->RecordCount) + // { + // kbts_feature_variation_pointer Variation = kbts_GetFeatureVariation(FeatureVariations, VariationIndex); + // KBTS_FOR(ConditionIndex, 0, Variation.ConditionSet->Count) + // { + // kbts_condition_1 *Condition = kbts_GetCondition(Variation.ConditionSet, ConditionIndex); + // KBTS_ASSERT(0); + // } + // } + //} + + kbts_u32 FeatureId = kbts_FeatureTagToId(Feature.Tag); + if(Feature.Feature->LookupIndexCount && kbts_ContainsFeature(&EnabledFeatures, FeatureId)) + { + kbts_lookup_indices LookupIndices = KBTS_ZERO; + LookupIndices.FeatureTag = Feature.Tag; + LookupIndices.FeatureId = FeatureId; + LookupIndices.SkipFlags = kbts_SkipFlags(FeatureId, Config->Shaper); + // For Myanmar, we could try and tag glyphs depending on their Indic properties in BeginCluster, just like we do for + // Indic scripts. + // However, Harfbuzz does _not_ do this, so it seems like a bunch of work that would, at best, make us diverge from + // Harfbuzz more often. + if((Config->Shaper != KBTS_SHAPER_MYANMAR) && (FeatureId >= 1) && (FeatureId <= 32)) + { + // These must properly map KBTS_FEATURE_ID to kbts_glyph_flags! + LookupIndices.GlyphFilter = (1 << (FeatureId - 1)) & KBTS_GLYPH_FEATURE_MASK; + } + LookupIndices.Count = Feature.Feature->LookupIndexCount; + LookupIndices.Indices = KBTS_POINTER_AFTER(kbts_u16, Feature.Feature); + State->FeatureLookupIndices[FeatureCount++] = LookupIndices; + } + } + } + State->FeatureCount = (kbts_u32)FeatureCount; +} + +typedef struct kbts_sequence_lookup_result +{ + kbts_sequence_lookup_record *Records; + kbts_un RecordCount; + kbts_un InputSequenceCountIncludingSkippedGlyphs; + + // This is specified _nowhere_ in the docs, BUT some sequence lookups have 0 records, and exist just to prevent the + // next lookups from executing. + // So, checking if we got any records is not enough to figure out whether we need to "apply" this lookup. + // We need to have an explicit bool as well. + // Sigh. + int Matched; +} kbts_sequence_lookup_result; + +typedef struct kbts_sequence_match +{ + kbts_un MatchCount; + kbts_un MatchOrSkipCount; +} kbts_sequence_match; + +static kbts_sequence_match kbts_MatchCoverageSequence(kbts_unpacked_lookup *Lookup, kbts_u32 SkipFlags, kbts_u32 SkipUnicodeFlags, + void *Base, kbts_u16 *CoverageOffsets, kbts_un CoverageCount, + kbts_glyph_array *GlyphArray, kbts_un GlyphStartIndex, kbts_un GlyphIndexIncrement) +{ + kbts_un CoverageIndex = 0; + kbts_un GlyphCounter = 0; + kbts_un GlyphIndex = GlyphStartIndex; + while((GlyphCounter < GlyphArray->Count) && (CoverageIndex < CoverageCount)) + { + kbts_glyph *Glyph = &GlyphArray->Glyphs[GlyphIndex]; + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, CoverageOffsets[CoverageIndex]); + + if(!kbts_SkipGlyph(Glyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + kbts_cover_glyph_result Cover = kbts_CoverGlyph(Coverage, Glyph->Id); + + if(Cover.Valid) + { + CoverageIndex += 1; + } + else + { + break; + } + } + + GlyphIndex += GlyphIndexIncrement; + GlyphCounter += 1; + } + + kbts_sequence_match Result = KBTS_ZERO; + Result.MatchCount = CoverageIndex; + Result.MatchOrSkipCount = GlyphCounter; + return Result; +} + +static int kbts_BranchlessCompareArray16(kbts_u16 *A, kbts_u16 *B, kbts_un Count) +{ + kbts_u16 DifferenceMask = 0; + KBTS_FOR(Index, 0, Count) + { + DifferenceMask |= A[Index] ^ B[Index]; + } + return (int)DifferenceMask; +} + +static kbts_sequence_lookup_result kbts_DoSequenceLookup(kbts_unpacked_lookup *Lookup, kbts_u16 *Base, kbts_cover_glyph_result Cover, + kbts_glyph_array *GlyphArray, kbts_un InputGlyphOffset, kbts_skip_flags SkipFlags, kbts_u32 SkipUnicodeFlags) +{ + KBTS_INSTRUMENT_FUNCTION_BEGIN + kbts_sequence_lookup_result Result = KBTS_ZERO; + + kbts_glyph_array BacktrackGlyphs = kbts_ClipGlyphArray(GlyphArray, InputGlyphOffset); + kbts_glyph_array InputGlyphs = kbts_GlyphSubArray(GlyphArray, InputGlyphOffset); + kbts_glyph_array FollowupGlyphs = kbts_GlyphSubArray(&InputGlyphs, 1); + + kbts_glyph *FirstGlyph = &GlyphArray->Glyphs[0]; + kbts_glyph *CurrentGlyph = &GlyphArray->Glyphs[InputGlyphOffset]; + kbts_glyph *InputGlyph = &GlyphArray->Glyphs[InputGlyphOffset + 1]; + kbts_glyph *OnePastLastGlyph = &GlyphArray->Glyphs[GlyphArray->Count]; + kbts_glyph *BacktrackGlyph = &GlyphArray->Glyphs[InputGlyphOffset - 1]; + + // Lookup types 7 and 8 are dispatch mechanisms. They do not substitute anything by themselves, they only point to + // other rules. + // Some formats have multiple rules; when that happens, we only ever match on the first one that fits. + + // We want to go to the right LookupType/SubtableFormat combination in a single jump, so we concatenate them here. + // GSUB format 5 == GPOS format 7. + // GSUB format 6 == GPOS format 8. + switch(((kbts_u32)Lookup->Type << 16) | (kbts_u32)Base[0]) + { + case 0x50001: + case 0x70001: + { + kbts_sequence_context_1 *Subst = (kbts_sequence_context_1 *)Base; + kbts_sequence_rule_set *Set = kbts_GetSequenceRuleSet(Subst, Cover.Index); + + if(Set) + { + kbts_u16 Ids[64]; // @Hardcoded + kbts_u16 GlyphOffsets[64]; + kbts_un IdCount = 0; + + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_sequence_rule *Rule = kbts_GetSequenceRule(Set, RuleIndex); + kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); + + // @Hardcoded! + KBTS_ASSERT(Rule->GlyphCount <= 64); + + while((InputGlyph < OnePastLastGlyph) && ((IdCount + 1) < Rule->GlyphCount)) + { + if(!kbts_SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + GlyphOffsets[IdCount] = (kbts_u16)(InputGlyph - CurrentGlyph); + Ids[IdCount++] = InputGlyph->Id; + } + + InputGlyph += 1; + } + + if(((IdCount + 1) >= Rule->GlyphCount) && + !kbts_BranchlessCompareArray16(Ids, InputSequence, Rule->GlyphCount - 1)) + { + Result.Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); + Result.RecordCount = Rule->SequenceLookupCount; + Result.InputSequenceCountIncludingSkippedGlyphs = 1; + if(Rule->GlyphCount > 1) + { + Result.InputSequenceCountIncludingSkippedGlyphs = GlyphOffsets[Rule->GlyphCount - 2] + 1; + } + Result.Matched = 1; + + break; + } + } + } + } + break; + + case 0x50002: + case 0x70002: + { + kbts_sequence_context_2 *Subst = (kbts_sequence_context_2 *)Base; + kbts_u16 *ClassDefinitionBase = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->ClassDefOffset); + + // @Hardcoded! + kbts_u16 InputClasses[64]; + kbts_u16 InputOffsets[64]; + kbts_un InputCount = 0; + + // For class-based contexts, the coverage index is not used. + // Instead, we know which set to use based on the current glyph's class. + // From the Microsoft docs: + // The class value is used as the index into an array of offsets to ClassSequenceRuleSet tables. + kbts_glyph_class_from_table_result CurrentGlyphClass = kbts_GlyphClassFromTable(ClassDefinitionBase, CurrentGlyph->Id); + kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, CurrentGlyphClass.Class); + + if((CurrentGlyphClass.Class < Subst->ClassSequenceRuleSetCount) && Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); + kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); + + while((InputGlyph < OnePastLastGlyph) && ((InputCount + 1) < Rule->GlyphCount)) + { + if(!kbts_SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + InputOffsets[InputCount] = (kbts_u16)(InputGlyph - CurrentGlyph); + InputClasses[InputCount++] = kbts_GlyphClassFromTable(ClassDefinitionBase, InputGlyph->Id).Class; + } + + InputGlyph += 1; + } + + if(((InputCount + 1) >= Rule->GlyphCount) && + !kbts_BranchlessCompareArray16(InputClasses, InputSequence, Rule->GlyphCount - 1)) + { + Result.Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); + Result.RecordCount = Rule->SequenceLookupCount; + Result.InputSequenceCountIncludingSkippedGlyphs = 1; + if(Rule->GlyphCount > 1) + { + Result.InputSequenceCountIncludingSkippedGlyphs = InputOffsets[Rule->GlyphCount - 2] + 1; + } + Result.Matched = 1; + + break; + } + } + } + } + break; + + case 0x50003: + case 0x70003: + { + kbts_sequence_context_3 *Subst = (kbts_sequence_context_3 *)Base; + kbts_u16 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + + kbts_sequence_match InputMatch = kbts_MatchCoverageSequence(Lookup, SkipFlags, SkipUnicodeFlags, Subst, CoverageOffsets, Subst->GlyphCount, &InputGlyphs, 0, 1); + + if(InputMatch.MatchCount == Subst->GlyphCount) + { + Result.Records = (kbts_sequence_lookup_record *)(CoverageOffsets + Subst->GlyphCount); + Result.RecordCount = Subst->SequenceLookupCount; + Result.InputSequenceCountIncludingSkippedGlyphs = InputMatch.MatchOrSkipCount; + Result.Matched = 1; + } + } + break; + + case 0x60001: + case 0x80001: + { + kbts_chained_sequence_context_1 *Subst = (kbts_chained_sequence_context_1 *)Base; + kbts_chained_sequence_rule_set *Set = kbts_GetChainedSequenceRuleSet(Subst, Cover.Index); + + if(Set) + { + // @Hardcoded! + kbts_u16 BacktrackIds[64]; + kbts_u16 InputIds[64]; + kbts_u16 InputOffsets[64]; + kbts_un BacktrackCount = 0; + kbts_un InputCount = 0; + + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); + kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + + while((BacktrackGlyph >= FirstGlyph) && (BacktrackCount < Unpacked.BacktrackCount)) + { + if(!kbts_SkipGlyph(BacktrackGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + BacktrackIds[BacktrackCount++] = BacktrackGlyph->Id; + } + BacktrackGlyph -= 1; + } + + kbts_un TotalInputGlyphsRequired = Unpacked.InputCount - 1 + Unpacked.LookaheadCount; + while((InputGlyph < OnePastLastGlyph) && (InputCount < TotalInputGlyphsRequired)) + { + if(!kbts_SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + InputOffsets[InputCount] = (kbts_u16)(InputGlyph - CurrentGlyph); + InputIds[InputCount++] = InputGlyph->Id; + } + InputGlyph += 1; + } + + if((BacktrackCount >= Unpacked.BacktrackCount) && (InputCount >= TotalInputGlyphsRequired) && + !kbts_BranchlessCompareArray16(BacktrackIds, Unpacked.Backtrack, Unpacked.BacktrackCount) && + !kbts_BranchlessCompareArray16(InputIds, Unpacked.Input, Unpacked.InputCount - 1) && + !kbts_BranchlessCompareArray16(InputIds + Unpacked.InputCount - 1, Unpacked.Lookahead, Unpacked.LookaheadCount)) + { + Result.Records = Unpacked.Records; + Result.RecordCount = Unpacked.RecordCount; + Result.InputSequenceCountIncludingSkippedGlyphs = 1; + if(Unpacked.InputCount > 1) + { + Result.InputSequenceCountIncludingSkippedGlyphs = InputOffsets[Unpacked.InputCount - 2] + 1; + } + Result.Matched = 1; + + break; + } + } + } + } + break; + + case 0x60002: + case 0x80002: + { + kbts_chained_sequence_context_2 *Subst = (kbts_chained_sequence_context_2 *)Base; + kbts_u16 *BacktrackClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->BacktrackClassDefOffset); + kbts_u16 *InputClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->InputClassDefOffset); + kbts_u16 *LookaheadClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->LookaheadClassDefOffset); + + // @Incomplete: Do this with all sequence types! + + // @Hardcoded: Pre-alloc this using LookupInfo! + kbts_u16 BacktrackClasses[64]; + kbts_u16 InputClasses[64]; + kbts_u16 InputClassOffsets[64]; + kbts_u16 LookaheadClasses[64]; + kbts_un BacktrackClassCount = 0; + kbts_un InputClassCount = 0; + + // Just like lookup 5.2, we use the current glyph class to figure out which set to look up. + // From the Microsoft docs: + // If found, the client then searches in the class definition table to find the class value assigned to the + // current glyph. The class value is used as the index into an array of offsets to ChainedClassSequenceRuleSet + // tables. + // + kbts_u16 CurrentGlyphClass = kbts_GlyphClassFromTable(InputClassDefinition, CurrentGlyph->Id).Class; + kbts_chained_sequence_rule_set *Set = kbts_GetChainedClassSequenceRuleSet(Subst, CurrentGlyphClass); + // If the glyph was contained in the coverage table, then it should have a valid class. + // Nevertheless, one Harfbuzz test font did not remove out-of-bounds glyph classes from the class definition + // table here, so we double-check it here. + // (It is also possible for a font to want to reuse the same class definition table across multiple lookups, + // in which case ignoring these classes becomes a feature.) + if((CurrentGlyphClass < Subst->ChainedClassSequenceRuleSetCount) && Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_chained_sequence_rule *Rule = kbts_GetChainedClassSequenceRule(Set, RuleIndex); + kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + + // @Hardcoded + KBTS_ASSERT(Unpacked.BacktrackCount <= 64); + KBTS_ASSERT(Unpacked.InputCount <= 64); + KBTS_ASSERT(Unpacked.LookaheadCount <= 64); + + while((BacktrackGlyph >= FirstGlyph) && (BacktrackClassCount < Unpacked.BacktrackCount)) + { + if(!kbts_SkipGlyph(BacktrackGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + // @Robustness: Do we want to break if we don't find a class? + kbts_glyph_class_from_table_result Class = kbts_GlyphClassFromTable(BacktrackClassDefinition, BacktrackGlyph->Id); + BacktrackClasses[BacktrackClassCount++] = Class.Class; + } + + BacktrackGlyph -= 1; + } + + kbts_un InputClassCountRequired = Unpacked.InputCount - 1 + Unpacked.LookaheadCount; + while((InputGlyph < OnePastLastGlyph) && (InputClassCount < InputClassCountRequired)) + { + if(!kbts_SkipGlyph(InputGlyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + kbts_glyph_class_from_table_result InputClass = kbts_GlyphClassFromTable(InputClassDefinition, InputGlyph->Id); + // In many cases, the font designer just wants to match "a set of glyphs" forward, + // and it doesn't matter whether those glyphs are in the input sequence or part of the lookahead. + // This happens often enough that we care to special-case it. + kbts_glyph_class_from_table_result LookaheadClass = InputClass; + if(LookaheadClassDefinition != InputClassDefinition) + { + LookaheadClass = kbts_GlyphClassFromTable(LookaheadClassDefinition, InputGlyph->Id); + } + + // @Robustness: Do we want to break if we don't find a class? + InputClassOffsets[InputClassCount] = (kbts_u16)(InputGlyph - CurrentGlyph); + InputClasses[InputClassCount] = InputClass.Class; + LookaheadClasses[InputClassCount] = LookaheadClass.Class; + + InputClassCount += 1; + } + + InputGlyph += 1; + } + + if((BacktrackClassCount >= Unpacked.BacktrackCount) && + (InputClassCount >= InputClassCountRequired) && + !kbts_BranchlessCompareArray16(BacktrackClasses, Unpacked.Backtrack, Unpacked.BacktrackCount) && + !kbts_BranchlessCompareArray16(InputClasses, Unpacked.Input, Unpacked.InputCount - 1) && + !kbts_BranchlessCompareArray16(LookaheadClasses + Unpacked.InputCount - 1, Unpacked.Lookahead, Unpacked.LookaheadCount)) + { + Result.Records = Unpacked.Records; + Result.RecordCount = Unpacked.RecordCount; + Result.InputSequenceCountIncludingSkippedGlyphs = 1; + if(Unpacked.InputCount > 1) + { + Result.InputSequenceCountIncludingSkippedGlyphs = InputClassOffsets[Unpacked.InputCount - 2] + 1; + } + Result.Matched = 1; + + break; + } + } + } + } + break; + + case 0x60003: + case 0x80003: + { + kbts_chained_sequence_context_3 *Subst = (kbts_chained_sequence_context_3 *)Base; + kbts_unpacked_chained_sequence_context_3 Unpacked = kbts_UnpackChainedSequenceContext3(Subst, 0); + + // Since chained sequence contexts roll the coverage for the first glyph into an array, you'd think that + // the matching logic for the first glyph would be the same as for any other glyph in that array. + // You'd be wrong! + // The first glyph does _not_ have to pass glyph filtering logic. It just has to pass the coverage test. + // Every other input glyph still does, though. + kbts_cover_glyph_result CurrentCover = KBTS_ZERO; + CurrentCover.Valid = !Unpacked.InputCount || kbts_GlyphPassesLookupFilter(InputGlyphs.Glyphs, Lookup); + if(Unpacked.InputCount) + { + kbts_coverage *CurrentCoverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.InputCoverageOffsets[0]); + CurrentCover = kbts_CoverGlyph(CurrentCoverage, InputGlyphs.Glyphs[0].Id); + } + + if(CurrentCover.Valid) + { + kbts_sequence_match BacktrackMatch = kbts_MatchCoverageSequence(Lookup, SkipFlags, SkipUnicodeFlags, Subst, Unpacked.BacktrackCoverageOffsets, Unpacked.BacktrackCount, &BacktrackGlyphs, BacktrackGlyphs.Count - 1, -1); + kbts_sequence_match InputMatch = kbts_MatchCoverageSequence(Lookup, SkipFlags, SkipUnicodeFlags, Subst, Unpacked.InputCoverageOffsets + 1, Unpacked.InputCount - 1, &FollowupGlyphs, 0, 1); + kbts_un MatchingInputGlyphCount = 1 + InputMatch.MatchCount; + kbts_un MatchedOrSkippedInputGlyphCount = 1 + InputMatch.MatchOrSkipCount; + kbts_glyph_array LookaheadGlyphs = kbts_GlyphSubArray(&InputGlyphs, MatchedOrSkippedInputGlyphCount); + kbts_sequence_match LookaheadMatch = kbts_MatchCoverageSequence(Lookup, SkipFlags, SkipUnicodeFlags, Subst, Unpacked.LookaheadCoverageOffsets, Unpacked.LookaheadCount, &LookaheadGlyphs, 0, 1); + + if((BacktrackMatch.MatchCount == Unpacked.BacktrackCount) && ((MatchingInputGlyphCount) == Unpacked.InputCount) && (LookaheadMatch.MatchCount == Unpacked.LookaheadCount)) + { + Result.Records = Unpacked.Records; + Result.RecordCount = Unpacked.RecordCount; + Result.InputSequenceCountIncludingSkippedGlyphs = MatchedOrSkippedInputGlyphCount; + Result.Matched = 1; + + break; + } + } + } + break; + } + + KBTS_INSTRUMENT_END + return Result; +} + +static void kbts_ApplyValueRecord(kbts_glyph *Glyph, kbts_unpacked_value_record *Unpacked) +{ + Glyph->OffsetX += Unpacked->PlacementX; + Glyph->OffsetY += Unpacked->PlacementY; + + Glyph->AdvanceX += Unpacked->AdvanceX; + Glyph->AdvanceY += Unpacked->AdvanceY; +} + +typedef struct kbts_indexed_glyph +{ + kbts_glyph *Glyph; + kbts_un Index; +} kbts_indexed_glyph; + +static int kbts_NextGlyph(kbts_unpacked_lookup *Lookup, kbts_glyph *InputGlyphs, kbts_un CurrentIndex, kbts_un InputGlyphCount, kbts_skip_flags SkipFlags, kbts_u32 SkipUnicodeFlags, kbts_indexed_glyph *IndexedGlyph) +{ + kbts_glyph *MatchingGlyph = 0; + kbts_un GlyphIndex = CurrentIndex; + + while(GlyphIndex < InputGlyphCount) + { + kbts_glyph *Glyph = &InputGlyphs[GlyphIndex]; + + if(!kbts_SkipGlyph(Glyph, Lookup, SkipFlags, SkipUnicodeFlags)) + { + MatchingGlyph = Glyph; + break; + } + else + { + GlyphIndex += 1; + } + } + + IndexedGlyph->Glyph = MatchingGlyph; + IndexedGlyph->Index = GlyphIndex; + return MatchingGlyph != 0; +} + +static void kbts_AttachGlyph(kbts_glyph_array *GlyphArray, kbts_glyph *Parent, kbts_glyph *Child, kbts_s32 X, kbts_s32 Y) +{ + kbts_s32 DeltaOffsetX = X - Child->OffsetX; + kbts_s32 DeltaOffsetY = Y - Child->OffsetY; + + Child->OffsetX = X; + Child->OffsetY = Y; + Child->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; + Child->AttachGlyphIndexPlusOne = (kbts_u16)(Parent - GlyphArray->Glyphs + 1); + + Parent->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; + + for(kbts_glyph *MiddleGlyph = Parent + 1; MiddleGlyph < Child; ++MiddleGlyph) + { + MiddleGlyph->Flags |= KBTS_GLYPH_FLAG_NO_BREAK; + } + + // @Speed: Fuck this. + // Attachments can happen in anti-topological order, so we have to fix them up here. + // We should store glyph parent/child indices instead of traversing all glyphs. + kbts_un ChildIndex = (kbts_un)(Child - GlyphArray->Glyphs); + KBTS_FOR(PostGlyphIndex, ChildIndex + 1, GlyphArray->Count) + { + kbts_glyph *Glyph = &GlyphArray->Glyphs[PostGlyphIndex]; + + if(Glyph->AttachGlyphIndexPlusOne == (ChildIndex + 1)) + { + Glyph->OffsetX += DeltaOffsetX; + Glyph->OffsetY += DeltaOffsetY; + } + } +} + +typedef struct kbts_do_single_adjustment_result +{ + kbts_un PositionedGlyphCount; + kbts_u32 PerformedAdjustment; +} kbts_do_single_adjustment_result; +static kbts_do_single_adjustment_result kbts_DoSingleAdjustment(kbts_shape_config *Config, kbts_lookup_list *LookupList, kbts_un LookupIndex, kbts_un SubtableIndex, kbts_unpacked_lookup *Lookup, kbts_u16 *Base, + kbts_glyph_array *GlyphArray, kbts_un CurrentGlyphIndex, kbts_skip_flags RequestedSkipFlags) +{ + KBTS_INSTRUMENT_FUNCTION_BEGIN + kbts_unicode_flags SkipUnicodeFlags = KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE; + kbts_skip_flags RegularSkipFlags = KBTS_SKIP_FLAGS_GPOS_REGULAR(RequestedSkipFlags); + kbts_skip_flags SequenceSkipFlags = KBTS_SKIP_FLAGS_GPOS_SEQUENCE(RequestedSkipFlags); + kbts_do_single_adjustment_result Result = KBTS_ZERO; + kbts_glyph *CurrentGlyph = &GlyphArray->Glyphs[CurrentGlyphIndex]; + + if(kbts_GlyphsIncludedInLookupSubtable(Config->Font, 1, Lookup, LookupIndex, SubtableIndex, GlyphArray, CurrentGlyphIndex, SequenceSkipFlags, SkipUnicodeFlags)) + { + Result.PerformedAdjustment = 1; + + // CAREFUL: We want kbts_unpacked_lookup to be a useful bag-of-arguments type, but, for extension + // lookups, each subtable may specify its own lookup type, so we save it here and restore it at + // the end of this function. + kbts_u16 OriginalLookupType = Lookup->Type; + + while(Lookup->Type == 9) + { + kbts_extension *Extension = (kbts_extension *)Base; + + Lookup->Type = Extension->LookupType; + Base = KBTS_POINTER_OFFSET(kbts_u16, Extension, Extension->Offset); + } + + kbts_glyph *InputGlyphs = GlyphArray->Glyphs + CurrentGlyphIndex; + kbts_un InputGlyphCount = GlyphArray->Count - CurrentGlyphIndex; + + kbts_cover_glyph_result Cover = KBTS_ZERO; + Cover.Valid = kbts_GlyphPassesLookupFilter(CurrentGlyph, Lookup); + kbts_coverage *Coverage = 0; + if(Cover.Valid && kbts_GposLookupBeginsWithCoverage(Lookup->Type, Base[0])) + { + kbts_u16 *CoverageOffset = Base + 1; + Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, *CoverageOffset); + Cover = kbts_CoverGlyph(Coverage, CurrentGlyph->Id); + } + + if(Cover.Valid) + { + switch(Lookup->Type) + { + case 1: + { + kbts_unpacked_value_record Unpacked = KBTS_ZERO; + + if(Base[0] == 1) + { + kbts_single_adjustment_1 *Adjust = (kbts_single_adjustment_1 *)Base; + + Unpacked = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat, KBTS_POINTER_AFTER(kbts_u16, Adjust)); + } + else if(Base[0] == 2) + { + kbts_single_adjustment_2 *Adjust = (kbts_single_adjustment_2 *)Base; + + kbts_un RecordSize = kbts_PopCount32(Adjust->ValueFormat); + kbts_u16 *Records = KBTS_POINTER_AFTER(kbts_u16, Adjust); + kbts_u16 *Record = Records + RecordSize * Cover.Index; + + Unpacked = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat, Record); + } + + kbts_ApplyValueRecord(CurrentGlyph, &Unpacked); + CurrentGlyph->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; + + Result.PositionedGlyphCount = 1; + } + break; + + case 2: + { + kbts_indexed_glyph NextGlyph; + if(kbts_NextGlyph(Lookup, InputGlyphs, 1, InputGlyphCount, RegularSkipFlags, SkipUnicodeFlags, &NextGlyph)) + { + kbts_u32 NextGlyphId = NextGlyph.Glyph->Id; + + kbts_unpacked_value_record Unpacked1 = KBTS_ZERO; + kbts_unpacked_value_record Unpacked2 = KBTS_ZERO; + int Valid = 0; + + if(Base[0] == 1) + { + kbts_pair_adjustment_1 *Adjust = (kbts_pair_adjustment_1 *)Base; + + kbts_un Size1 = kbts_PopCount32(Adjust->ValueFormat1); + kbts_un Size2 = kbts_PopCount32(Adjust->ValueFormat2); + + kbts_u16 *SetOffsets = KBTS_POINTER_AFTER(kbts_u16, Adjust); + kbts_pair_set *Set = KBTS_POINTER_OFFSET(kbts_pair_set, Adjust, SetOffsets[Cover.Index]); + + kbts_un PairRecordSize = Size1 + Size2 + 1; // + 1 because each pair stores the next glyph ID. + kbts_pair_value_record *PairRecords = KBTS_POINTER_AFTER(kbts_pair_value_record, Set); + KBTS_FOR(PairIndex, 0, Set->Count) + { + kbts_pair_value_record *PairRecord = PairRecords + PairRecordSize * PairIndex; + + if(PairRecord->SecondGlyph == NextGlyphId) + { + kbts_u16 *Records = KBTS_POINTER_AFTER(kbts_u16, PairRecord); + + Unpacked1 = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat1, Records); + Records += Unpacked1.Size; + Unpacked2 = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat2, Records); + Valid = 1; + } + } + } + else if(Base[0] == 2) + { + kbts_pair_adjustment_2 *Adjust = (kbts_pair_adjustment_2 *)Base; + kbts_u16 *ClassDef1 = KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition1Offset); + kbts_u16 *ClassDef2 = KBTS_POINTER_OFFSET(kbts_u16, Adjust, Adjust->ClassDefinition2Offset); + + kbts_un Size1 = kbts_PopCount32(Adjust->ValueFormat1); + kbts_un Size2 = kbts_PopCount32(Adjust->ValueFormat2); + kbts_un PairRecordSize = Size1 + Size2; + kbts_u16 *PairRecords = KBTS_POINTER_AFTER(kbts_u16, Adjust); + + // From the Microsoft docs: + // PairPosFormat2 requires that each glyph in all pairs be assigned to a class, which is + // identified by an integer called a class value. + // This _seems_ like it would mean that, if either glyph is not specified in its respective + // class definition table, then we should skip the lookup. + // However, this seems wrong in practice. Undefined classes seem to just default to 0, and then + // the bounds check takes care of deciding whether the lookup is okay to apply or not. + kbts_glyph_class_from_table_result Class1 = kbts_GlyphClassFromTable(ClassDef1, CurrentGlyph->Id); + kbts_glyph_class_from_table_result Class2 = kbts_GlyphClassFromTable(ClassDef2, NextGlyphId); + if((Class1.Class < Adjust->Class1Count) && (Class2.Class < Adjust->Class2Count)) + { + kbts_u16 *PairRecord = PairRecords + Class1.Class * PairRecordSize * Adjust->Class2Count + Class2.Class * PairRecordSize; + + Unpacked1 = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat1, PairRecord); + PairRecord += Size1; + + Unpacked2 = kbts_UnpackValueRecord(Adjust, Adjust->ValueFormat2, PairRecord); + PairRecord += Size2; + Valid = 1; + } + } + + if(Valid) + { + kbts_ApplyValueRecord(CurrentGlyph, &Unpacked1); + CurrentGlyph->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; + + kbts_ApplyValueRecord(&InputGlyphs[NextGlyph.Index], &Unpacked2); + NextGlyph.Glyph->Flags |= KBTS_GLYPH_FLAG_USED_IN_GPOS; + + Result.PositionedGlyphCount = 2; + if(!Unpacked2.Size) + { + Result.PositionedGlyphCount = 1; + } + } + } + } + break; + + // All three types of attachment (cursive, mark-to-base, mark-to-ligature) look backward instead of forward. + case 3: + { + kbts_cursive_attachment *Adjust = (kbts_cursive_attachment *)Base; + kbts_entry_exit *EntryExits = KBTS_POINTER_AFTER(kbts_entry_exit, Adjust); + + kbts_glyph *Prev = 0; + for(kbts_un PrevIndex = CurrentGlyphIndex; PrevIndex > 0; --PrevIndex) + { + kbts_glyph *PrevGlyph = &GlyphArray->Glyphs[PrevIndex - 1]; + if(!kbts_SkipGlyph(PrevGlyph, Lookup, RegularSkipFlags, SkipUnicodeFlags)) + { + Prev = PrevGlyph; + break; + } + } + + if(Prev) + { + // For two cursive glyphs to be aligned, they both need to be defined by the same cursive attachment table. + kbts_cover_glyph_result PrevCover = kbts_CoverGlyph(Coverage, Prev->Id); + + if(PrevCover.Valid) + { + // Get anchor points for both glyphs. + kbts_entry_exit *PrevEntryExit = &EntryExits[PrevCover.Index]; + kbts_entry_exit *EntryExit = &EntryExits[Cover.Index]; + + if(PrevEntryExit->ExitAnchorOffset && EntryExit->EntryAnchorOffset) + { + kbts_anchor *PrevExitAnchor = KBTS_POINTER_OFFSET(kbts_anchor, Adjust, PrevEntryExit->ExitAnchorOffset); + kbts_anchor *EntryAnchor = KBTS_POINTER_OFFSET(kbts_anchor, Adjust, EntryExit->EntryAnchorOffset); + kbts_s32 Anchor0X = PrevExitAnchor->X; + kbts_s32 Anchor0Y = PrevExitAnchor->Y; + kbts_s32 Anchor1X = EntryAnchor->X; + kbts_s32 Anchor1Y = EntryAnchor->Y; + kbts_s32 Advance0X = Prev->AdvanceX; + kbts_s32 Advance1X = CurrentGlyph->AdvanceX; + kbts_s32 Offset0X = Prev->OffsetX; + kbts_s32 Offset0Y = Prev->OffsetY; + kbts_s32 Offset1X = CurrentGlyph->OffsetX; + kbts_s32 Offset1Y = CurrentGlyph->OffsetY; + + // Cursive positioning is made up of two parts. + // The first part is glyph-to-glyph alignment, which depends on the text direction. + // Here, we are only concerned with making the relative placements of the glyphs correct, + // insofar as they follow the specified anchor positions. + // + // The OpenType spec makes no attempt to describe how the two glyphs should be aligned, mathematically + // speaking. + // + // This is all we get: + // + // "To position glyphs using the CursivePosFormat1 subtable, a text-processing client aligns the exit + // anchor point of a glyph with the entry anchor point of the following glyph." + // + // In practice, we reproduce harfbuzz's behavior here, which is: + // - Glyph1.Offset.X is unaffected + // - Glyph1.Advance.X = Glyph1.Offset.X + Glyph1.Anchor.X, aka. the _actual position of its anchor_ + // - Glyph2.Offset.X = -Glyph2.Anchor.X + // - Glyph2.Offset.Y = Glyph1.Anchor.Y - Glyph2.Anchor.Y + // - Glyph2.Advance.X -= Glyph2.Anchor.X + // + // (...where "X" here just means "the main direction". In top-to-bottom or bottom-to-top contexts, that + // would be the Y coordinate, but we do not support those yet.) + // + // So, instead of aligning everything with offsets, we use Advance to align _the rest of the string_ + // horizontally with the first glyph, and not just the next glyph. + // + // It might seem dumb to modify both Glyph2.Offset _and_ Glyph2.Advance, because, when the glyphs are next + // to one another, this is equivalent to modifying Glyph1.Advance. However, due to lookup flag nonsense, + // there may be some glyphs between Glyph1 and Glyph2, and, _apparently_, it is fine to adjust them by the + // position of Glyph1's anchor point, and it is not fine to adjust them by the position of Glyph2's anchor + // point. + // + // This Advance tweak seems like it would be wrong, because any marks attached to Glyph1 will then have + // invalid positions. The hope is that this does not matter in practice, because 'mark' is applied after + // 'curs', and font designers are expected to know that and to know never to apply mark attachments + // before cursive positioning, I guess. + if(!kbts_ShaperRtl(Config->Shaper)) + { + Advance0X = Offset0X + Anchor0X; + kbts_s32 Dx = -Anchor1X - Offset1X; + Advance1X += Dx; + Offset1X += Dx; + } + else + { + kbts_s32 Dx = -Anchor0X - Offset0X; + Advance0X += Dx; + Offset0X += Dx; + Advance1X = Offset1X + Anchor1X; + } + + Prev->AdvanceX = Advance0X; + Prev->OffsetX = Offset0X; + Prev->Flags |= (KBTS_GLYPH_FLAG_CURSIVE | KBTS_GLYPH_FLAG_USED_IN_GPOS | KBTS_GLYPH_FLAG_NO_BREAK); + CurrentGlyph->AdvanceX = Advance1X; + CurrentGlyph->OffsetX = Offset1X; + CurrentGlyph->Flags |= (KBTS_GLYPH_FLAG_CURSIVE | KBTS_GLYPH_FLAG_USED_IN_GPOS); + + for(kbts_glyph *CursiveGlyph = Prev + 1; CursiveGlyph < CurrentGlyph; ++CursiveGlyph) + { + CursiveGlyph->Flags |= KBTS_GLYPH_FLAG_NO_BREAK; + } + + // The second part is aligning the newly-formed cursive cluster to the "baseline". It is trickier than you'd expect. + // + // When applying cursive attachments, Glyph1 (RIGHT_TO_LEFT=0) or Glyph2 (RIGHT_TO_LEFT=1) is treated as being + // "on the baseline" and its Y coordinate is used as the reference Y coordinate for the entire cursive glyph + // cluster that has been formed so far. + // This means that, anytime we apply a cursive attachment, we have to offset _all_ of the cursive glyphs to the + // left (RIGHT_TO_LEFT=0) or to the right (RIGHT_TO_LEFT=1) of it. + // This is obviously O(n^2), and @Speed: it might be worthwhile to record cursive offsets as we go, and only resolve + // them when we actually need them, i.e. when applying a non-cursive lookup or, at the latest, when we are done with + // positioning. + // + // The glyph being attached is set at a hard relative offset from the reference glyph. Its previous Y coordinate only + // matters insofar as we need to align every other cursive glyph in its direction. + + kbts_s32 CursiveDy = 0; + kbts_un CursiveStartIndex = CurrentGlyphIndex; + kbts_un DIndex = 1; + + if(!(Lookup->Flags & KBTS_LOOKUP_FLAG_RIGHT_TO_LEFT)) + { + kbts_s32 NewOffset1Y = Offset0Y + Anchor0Y - Anchor1Y; + CursiveDy = NewOffset1Y - Offset1Y; + } + else + { + kbts_s32 NewOffset0Y = Offset1Y + Anchor1Y - Anchor0Y; + CursiveDy = NewOffset0Y - Offset0Y; + DIndex = -1; + CursiveStartIndex = (kbts_un)(Prev - GlyphArray->Glyphs); + } + + for(kbts_un CursiveGlyphIndex = CursiveStartIndex; CursiveGlyphIndex < GlyphArray->Count; CursiveGlyphIndex += DIndex) + { + kbts_glyph *CursiveGlyph = &GlyphArray->Glyphs[CursiveGlyphIndex]; + + if(CursiveGlyph->Flags & KBTS_GLYPH_FLAG_CURSIVE) + { + CursiveGlyph->OffsetY += CursiveDy; + } + else if(CursiveGlyph->AdvanceX | CursiveGlyph->AdvanceY) // Ignore marks. + { + break; + } + } + + Result.PositionedGlyphCount = 1; + } + } + } + } + break; + + case 4: + case 6: + { + kbts_mark_to_base_attachment *Adjust = (kbts_mark_to_base_attachment *)Base; + + // We want to know which glyph to attach to, and how far that glyph is from us. + // To do that, we add up all advances between it and us. + // There is a slight wrinkle here: most shapers end up zeroing mark advances at the _end_ + // of the shaping process, which would retroactively make a naive advance accumulation wrong. + // We have to take that into account here, and only accumulate mark advances for shapers that + // don't do that zeroing at the end (either because they do it at the beginning of GPOS, or + // because they don't do it at all). + int CountMarkAdvances = !kbts_ShaperClearsMarkAdvancesInPostGposFixup(Config->Shaper); + kbts_s32 AdvanceSinceBaseX = 0; + kbts_s32 AdvanceSinceBaseY = 0; + kbts_u32 BaseClasses = Lookup->Type == 6 ? (1 << KBTS_GLYPH_CLASS_MARK) : (1 | (1 << KBTS_GLYPH_CLASS_BASE) | (1 << KBTS_GLYPH_CLASS_LIGATURE) | (1 << KBTS_GLYPH_CLASS_COMPONENT)); + kbts_glyph *BaseGlyph = 0; + for(kbts_un PrevGlyphIndex = CurrentGlyphIndex; PrevGlyphIndex; --PrevGlyphIndex) + { + kbts_glyph *PrevGlyph = &GlyphArray->Glyphs[PrevGlyphIndex - 1]; + + if(CountMarkAdvances || (PrevGlyph->Classes.Class != KBTS_GLYPH_CLASS_MARK)) + { + AdvanceSinceBaseX += PrevGlyph->AdvanceX; + AdvanceSinceBaseY += PrevGlyph->AdvanceY; + } + + if(!kbts_SkipGlyph(PrevGlyph, Lookup, RegularSkipFlags, SkipUnicodeFlags)) + { + if((1 << PrevGlyph->Classes.Class) & BaseClasses) + { + BaseGlyph = PrevGlyph; + break; + } + else if(Lookup->Type == 6) + { + // Unskipped non-marks block mark attachments. + break; + } + } + } + + if(BaseGlyph) + { + int Ok = (Lookup->Type == 4) || // This is a mark-to-base attachment + ((BaseGlyph->LigatureUid == CurrentGlyph->LigatureUid) && (BaseGlyph->LigatureComponentIndexPlusOne == CurrentGlyph->LigatureComponentIndexPlusOne)) || // This is a mark-to-mark attachment, and both marks belong to the same ligature component + ((BaseGlyph->Flags | CurrentGlyph->Flags) & KBTS_GLYPH_FLAG_LIGATURE); // This is a mark-to-mark attachment, and either mark was created by a ligature substitution + if(Ok) + { + kbts_cover_glyph_result BaseCover = kbts_CoverGlyph(KBTS_POINTER_OFFSET(kbts_coverage, Adjust, Adjust->BaseCoverageOffset), BaseGlyph->Id); + + if(BaseCover.Valid) + { + kbts_base_array *BaseArray = KBTS_POINTER_OFFSET(kbts_base_array, Adjust, Adjust->BaseArrayOffset); + kbts_u16 *BaseAnchorOffsets = KBTS_POINTER_AFTER(kbts_u16, BaseArray) + BaseCover.Index * Adjust->MarkClassCount; + kbts_mark_info MarkInfo = kbts_GetMarkInfo(Adjust, Adjust->MarkArrayOffset, Cover.Index); + + kbts_u16 BaseAnchorOffset = BaseAnchorOffsets[MarkInfo.Record->Class]; + if(BaseAnchorOffset) + { + kbts_anchor *BaseAnchor = KBTS_POINTER_OFFSET(kbts_anchor, BaseArray, BaseAnchorOffset); + + /* From the Microsoft docs: + When a mark is combined with a given base, the mark placement is adjusted so that the mark anchor is + aligned with the base anchor for the applicable mark class. Placement of the base glyph and advances of + both glyphs are not affected. + */ + + kbts_s32 NewOffsetX = BaseGlyph->OffsetX - AdvanceSinceBaseX + (BaseAnchor->X - MarkInfo.Anchor->X); + kbts_s32 NewOffsetY = BaseGlyph->OffsetY - AdvanceSinceBaseY + (BaseAnchor->Y - MarkInfo.Anchor->Y); + + kbts_AttachGlyph(GlyphArray, BaseGlyph, CurrentGlyph, NewOffsetX, NewOffsetY); + + Result.PositionedGlyphCount = 1; + } + } + } + } + } + break; + + case 5: + { + kbts_mark_to_ligature_attachment *Adjust = (kbts_mark_to_ligature_attachment *)Base; + + kbts_s32 AdvanceSinceBaseX = 0; + kbts_s32 AdvanceSinceBaseY = 0; + kbts_u32 BaseClasses = (1 | (1 << KBTS_GLYPH_CLASS_BASE) | (1 << KBTS_GLYPH_CLASS_LIGATURE) | (1 << KBTS_GLYPH_CLASS_COMPONENT)); + kbts_glyph *LigatureGlyph = 0; + for(kbts_un PrevGlyphIndex = CurrentGlyphIndex; PrevGlyphIndex; --PrevGlyphIndex) + { + kbts_glyph *PrevGlyph = &GlyphArray->Glyphs[PrevGlyphIndex - 1]; + AdvanceSinceBaseX += PrevGlyph->AdvanceX; + AdvanceSinceBaseY += PrevGlyph->AdvanceY; + if(!kbts_SkipGlyph(PrevGlyph, Lookup, RegularSkipFlags, SkipUnicodeFlags) && ((1 << PrevGlyph->Classes.Class) & BaseClasses)) + { + LigatureGlyph = PrevGlyph; + break; + } + } + + if(LigatureGlyph) + { + kbts_cover_glyph_result LigatureCover = kbts_CoverGlyph(KBTS_POINTER_OFFSET(kbts_coverage, Adjust, Adjust->LigatureCoverageOffset), + LigatureGlyph->Id); + if(LigatureCover.Valid) + { + kbts_ligature_array *LigatureArray = KBTS_POINTER_OFFSET(kbts_ligature_array, Adjust, Adjust->LigatureArrayOffset); + kbts_ligature_attach *LigatureAttach = kbts_GetLigatureAttach(LigatureArray, LigatureCover.Index); + kbts_mark_info MarkInfo = kbts_GetMarkInfo(Adjust, Adjust->MarkArrayOffset, Cover.Index); + kbts_un LigatureComponentIndex = CurrentGlyph->LigatureComponentIndexPlusOne; + + if(CurrentGlyph->LigatureUid != LigatureGlyph->Uid) + { + // If the mark is not yet attached to the ligature, attach it now. + // Apparently, in this case, the mark should be considered part of the _last_ component of the ligature. + LigatureComponentIndex = LigatureAttach->Count; + } + + if(CurrentGlyph->LigatureComponentIndexPlusOne <= LigatureAttach->Count) + { + kbts_un AnchorIndex = LigatureComponentIndex; + if(AnchorIndex) + { + AnchorIndex -= 1; + } + else + { + AnchorIndex = LigatureAttach->Count - 1; + } + + kbts_anchor *LigatureAnchor = kbts_GetLigatureAttachAnchor(Adjust, LigatureAttach, MarkInfo.Record->Class, AnchorIndex); + + kbts_s32 NewOffsetX = LigatureGlyph->OffsetX - AdvanceSinceBaseX + (LigatureAnchor->X - MarkInfo.Anchor->X); + kbts_s32 NewOffsetY = LigatureGlyph->OffsetY - AdvanceSinceBaseY + (LigatureAnchor->Y - MarkInfo.Anchor->Y); + + kbts_AttachGlyph(GlyphArray, LigatureGlyph, CurrentGlyph, NewOffsetX, NewOffsetY); + + CurrentGlyph->LigatureComponentIndexPlusOne = (kbts_u16)LigatureComponentIndex; + CurrentGlyph->LigatureUid = LigatureGlyph->Uid; + // I'm not sure why, but Harfbuzz only clears this in mark-to-ligature substitutions, and not in mark-to-base or + // mark-to-mark. + CurrentGlyph->AdvanceX = 0; + CurrentGlyph->AdvanceY = 0; + + for(kbts_glyph *MiddleGlyph = LigatureGlyph + 1; MiddleGlyph < CurrentGlyph; ++MiddleGlyph) + { + MiddleGlyph->Flags |= KBTS_GLYPH_FLAG_NO_BREAK; + } + + Result.PositionedGlyphCount = 1; + } + } + } + } + break; + + case 7: + case 8: + { + kbts_sequence_lookup_result SequenceLookup = kbts_DoSequenceLookup(Lookup, Base, Cover, GlyphArray, CurrentGlyphIndex, SequenceSkipFlags, SkipUnicodeFlags); + if(SequenceLookup.RecordCount) + { + KBTS_FOR(RecordIndex, 0, SequenceLookup.RecordCount) + { + kbts_sequence_lookup_record *Record = &SequenceLookup.Records[RecordIndex]; + kbts_lookup *PackedRecordLookup = kbts_GetLookup(LookupList, Record->LookupListIndex); + kbts_unpacked_lookup RecordLookup = kbts_UnpackLookup(Config->Font->Gdef, PackedRecordLookup); + + kbts_un NestedCurrentGlyphIndex = CurrentGlyphIndex; + { // Figure out where in the input sequence we need to apply the lookup. + kbts_un SequenceIndex = 0; + KBTS_FOR(InputGlyphIndex, 0, InputGlyphCount) + { + kbts_un NestedIndex = CurrentGlyphIndex + InputGlyphIndex; + kbts_glyph *Glyph = &GlyphArray->Glyphs[NestedIndex]; + + if(!kbts_SkipGlyph(Glyph, Lookup, SequenceSkipFlags, SkipUnicodeFlags)) + { + if(SequenceIndex == Record->SequenceIndex) + { + NestedCurrentGlyphIndex = NestedIndex; + + break; + } + + SequenceIndex += 1; + } + } + } + + KBTS_FOR(NestedSubtableIndex, 0, RecordLookup.SubtableCount) + { + kbts_u16 *NestedBase = KBTS_POINTER_OFFSET(kbts_u16, PackedRecordLookup, RecordLookup.SubtableOffsets[NestedSubtableIndex]); + + kbts_DoSingleAdjustment(Config, LookupList, Record->LookupListIndex, NestedSubtableIndex, &RecordLookup, NestedBase, GlyphArray, NestedCurrentGlyphIndex, RequestedSkipFlags); + } + } + + Result.PositionedGlyphCount = SequenceLookup.InputSequenceCountIncludingSkippedGlyphs; + } + } + break; + } + } + + Lookup->Type = OriginalLookupType; + } + + if(!Result.PositionedGlyphCount) + { + Result.PositionedGlyphCount = 1; + Result.PerformedAdjustment = 0; + } + + KBTS_INSTRUMENT_END + return Result; +} + +typedef kbts_u32 kbts_mcm_sequence_state; +enum kbts_mcm_sequence_state_enum +{ + KBTS_MCM_SEQUENCE_STATE_NONE, + KBTS_MCM_SEQUENCE_STATE_OUT, + KBTS_MCM_SEQUENCE_STATE_IN, +}; + +typedef kbts_u32 kbts_hangul_syllable_type; +enum kbts_hangul_syllable_type_enum +{ + KBTS_HANGUL_SYLLABLE_TYPE_NONE, + + KBTS_HANGUL_SYLLABLE_TYPE_L, + KBTS_HANGUL_SYLLABLE_TYPE_V, + KBTS_HANGUL_SYLLABLE_TYPE_T, + KBTS_HANGUL_SYLLABLE_TYPE_LV, + KBTS_HANGUL_SYLLABLE_TYPE_LVT, + + KBTS_HANGUL_SYLLABLE_TYPE_COUNT, +}; + +typedef struct kbts_hangul_syllable_info +{ + kbts_hangul_syllable_type Type; + kbts_u32 Composable; +} kbts_hangul_syllable_info; + +static kbts_hangul_syllable_info kbts_HangulSyllableInfo(kbts_u32 Codepoint) +{ + kbts_hangul_syllable_info Result = KBTS_ZERO; + + if((Codepoint >= 0x1100) && (Codepoint <= 0x115F)) + { + Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_L; + Result.Composable = (Codepoint < 0x1113); + } + else if((Codepoint >= 0x1160) && (Codepoint <= 0x11A7)) + { + Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_V; + Result.Composable = ((Codepoint >= 0x1161) & (Codepoint <= 0x1175)); + } + else if((Codepoint >= 0x11A8) && (Codepoint <= 0x11FF)) + { + Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_T; + Result.Composable = (Codepoint < 0x11C3); + } + else if((Codepoint >= 0xA960) && (Codepoint <= 0xA97C)) + { + Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_L; + } + else if((Codepoint == 0xAC00) && (Codepoint <= 0xD7A3)) + { + Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_LVT; + + if(!((Codepoint - 0xAC00) % 28)) + { + Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_LV; + } + } + else if((Codepoint >= 0xD7B0) && (Codepoint <= 0xD7C6)) + { + Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_V; + } + else if((Codepoint >= 0xD7CB) && (Codepoint <= 0xD7FB)) + { + Result.Type = KBTS_HANGUL_SYLLABLE_TYPE_T; + } + + return Result; +} + +KBTS_INLINE kbts_u32 kbts_SyllabicClassIsConsonant(kbts_indic_syllabic_class Class) +{ + kbts_u32 Result = + KBTS_IN_SET(Class, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_CONSONANT)(KBTS_INDIC_SYLLABIC_CLASS_RA)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL))); + return Result; +} + +enum +{ + KBTS_FEATURE_MATCH_FLAG_KA_JA = (1 << 0), + KBTS_FEATURE_MATCH_FLAG_SSA_NYA = (1 << 1), + KBTS_FEATURE_MATCH_FLAG_RA_HA_VA = (1 << 2), + KBTS_FEATURE_MATCH_FLAG_YA = (1 << 3), + KBTS_FEATURE_MATCH_FLAG_CONSONANT = (1 << 4), + KBTS_FEATURE_MATCH_FLAG_NUKTA = (1 << 5), + KBTS_FEATURE_MATCH_FLAG_HALANT = (1 << 6), + KBTS_FEATURE_MATCH_FLAG_ZWJ = (1 << 7), + KBTS_FEATURE_MATCH_FLAG_ZWNJ = (1 << 8), + KBTS_FEATURE_MATCH_FLAG_INITIAL = (1 << 10), + KBTS_FEATURE_MATCH_FLAG_POST_BASE = (1 << 11), + + KBTS_FEATURE_MATCH_FLAG_RPHF = KBTS_FEATURE_FLAG0(rphf), +}; +# define KBTS_FEATURE_MATCH_MASK(W0, W1, W2, W3) (((kbts_u64)(W0) << 48) | ((kbts_u64)(W1) << 32) | ((kbts_u64)(W0) << 16) | (kbts_u64)(W0)) +# define KBTS_FEATURE_MATCH_MASK_AKHN KBTS_FEATURE_MATCH_MASK(0, KBTS_FEATURE_MATCH_FLAG_KA_JA, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_SSA_NYA) +# define KBTS_FEATURE_MATCH_MASK_BLWF_PRE KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_RA_HA_VA | KBTS_FEATURE_MATCH_FLAG_INITIAL, KBTS_FEATURE_MATCH_FLAG_HALANT) +# define KBTS_FEATURE_MATCH_MASK_BLWF_PRE_OK KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_RA_HA_VA, KBTS_FEATURE_MATCH_FLAG_HALANT) +# define KBTS_FEATURE_MATCH_MASK_BLWF_POST KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_RA_HA_VA) +# define KBTS_FEATURE_MATCH_MASK_CJCT KBTS_FEATURE_MATCH_MASK(0, KBTS_FEATURE_MATCH_FLAG_CONSONANT, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_CONSONANT) +# define KBTS_FEATURE_MATCH_MASK_HALF KBTS_FEATURE_MATCH_MASK(KBTS_FEATURE_MATCH_FLAG_CONSONANT | KBTS_FEATURE_MATCH_FLAG_RPHF | KBTS_FEATURE_MATCH_FLAG_POST_BASE, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_ZWNJ, KBTS_FEATURE_MATCH_FLAG_CONSONANT) +# define KBTS_FEATURE_MATCH_MASK_HALF_OK KBTS_FEATURE_MATCH_MASK(KBTS_FEATURE_MATCH_FLAG_CONSONANT, KBTS_FEATURE_MATCH_FLAG_HALANT, 0, 0) +# define KBTS_FEATURE_MATCH_MASK_NUKT KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_CONSONANT, KBTS_FEATURE_MATCH_FLAG_HALANT) +# define KBTS_FEATURE_MATCH_MASK_PSTF KBTS_FEATURE_MATCH_MASK(0, 0, KBTS_FEATURE_MATCH_FLAG_HALANT | KBTS_FEATURE_MATCH_FLAG_INITIAL, KBTS_FEATURE_MATCH_FLAG_YA) +# define KBTS_FEATURE_MATCH_MASK_VATU KBTS_FEATURE_MATCH_MASK(0, KBTS_FEATURE_MATCH_FLAG_CONSONANT, KBTS_FEATURE_MATCH_FLAG_HALANT, KBTS_FEATURE_MATCH_FLAG_RA_HA_VA) + +typedef kbts_u32 kbts_substitution_result_flags; +enum kbts_substitution_result_flags_enum +{ + KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION = (1 << 0), + KBTS_SUBSTITUTION_RESULT_FLAG_GROW_BUFFER = (1 << 1), +}; + +static kbts_substitution_result_flags kbts_DoSubstitution(kbts_shape_state *ShapeState, kbts_lookup_list *LookupList, kbts_gsub_frame *Frames, kbts_u32 *FrameCount_, + kbts_glyph_array *GlyphArray, kbts_u32 CheckOnly, kbts_skip_flags RequestedSkipFlags, kbts_u32 GeneratedGlyphFlags) +{ + kbts_substitution_result_flags Result = 0; + kbts_font *Font = ShapeState->Config->Font; + kbts_glyph *Glyphs = GlyphArray->Glyphs; + kbts_unicode_flags SkipUnicodeFlags = 0; // @Incomplete + kbts_skip_flags RegularSkipFlags = KBTS_SKIP_FLAGS_GSUB_REGULAR(RequestedSkipFlags); + kbts_skip_flags SequenceSkipFlags = KBTS_SKIP_FLAGS_GSUB_SEQUENCE(RequestedSkipFlags); + GeneratedGlyphFlags |= KBTS_GLYPH_FLAG_GENERATED_BY_GSUB; + + kbts_un FrameCount = *FrameCount_; + kbts_gsub_frame *Frame = &Frames[FrameCount - 1]; + + kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, Frame->LookupIndex); + kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); + kbts_u16 BaseLookupType = Lookup.Type; + + while(Frame->SubtableIndex < Lookup.SubtableCount) + { + kbts_u16 *Subtable = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[Frame->SubtableIndex]); + // In a type-7 lookup, each subtable can specify a different lookup type. + // We still want to pass kbts_unpacked_lookup around as a useful bag of arguments, though. + // So, we restore the original lookup's type here before resolving each subtable. + Lookup.Type = BaseLookupType; + + while(Lookup.Type == 7) + { + kbts_extension *Extension = (kbts_extension *)Subtable; + Lookup.Type = Extension->LookupType; + Subtable = KBTS_POINTER_OFFSET(kbts_u16, Extension, Extension->Offset); + } + + // :ReverseChaining + // From the Microsoft docs: + // In processing a reverse chaining substitution, i begins at the logical end of the string and moves to the beginning. + // This comment only makes sense when the reverse chaining substitution happens at the top level. + // When it _is_ at the top level, we know we are just doing a linear scan through the string, and since this is a single + // substitution (i.e. one glyph -> one glyph), we know the size of the buffer won't change throughout the scan. + // Given all of this, handling the reverse-scanning nature of this lookup actually becomes very easy: + if((Lookup.Type == 8) && (FrameCount == 1)) + { + Frame->InputGlyphIndex = (kbts_u16)(GlyphArray->Count - 1 - Frame->InputGlyphIndex); + } + + kbts_glyph *CurrentGlyph = &Glyphs[Frame->InputGlyphIndex]; + kbts_glyph_array InputGlyphs = kbts_GlyphSubArray(GlyphArray, Frame->InputGlyphIndex); + + kbts_skip_flags SkipFlags = (Lookup.Type >= 5) ? SequenceSkipFlags : RegularSkipFlags; + if(kbts_GlyphsIncludedInLookupSubtable(Font, 0, &Lookup, Frame->LookupIndex, Frame->SubtableIndex, GlyphArray, Frame->InputGlyphIndex, SkipFlags, SkipUnicodeFlags)) + { + kbts_cover_glyph_result Cover = KBTS_ZERO; + Cover.Valid = kbts_GlyphPassesLookupFilter(CurrentGlyph, &Lookup); + if(Cover.Valid && kbts_GsubLookupBeginsWithCoverage(Lookup.Type, Subtable[0])) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subtable, Subtable[1]); + Cover = kbts_CoverGlyph(Coverage, CurrentGlyph->Id); + } + + if(Cover.Valid) + { + kbts_un DeltaGlyphCount = 0; + + if((Lookup.Type == 5) || (Lookup.Type == 6)) + { + kbts_sequence_lookup_result SequenceLookup = kbts_DoSequenceLookup(&Lookup, Subtable, Cover, GlyphArray, Frame->InputGlyphIndex, SequenceSkipFlags, SkipUnicodeFlags); + + if(SequenceLookup.Matched) + { + KBTS_FOR(FrameIndex, 0, FrameCount - 1) + { + kbts_gsub_frame *ParentFrame = &Frames[FrameIndex]; + + if((ParentFrame->InputGlyphIndex < (Frame->InputGlyphIndex + SequenceLookup.InputSequenceCountIncludingSkippedGlyphs)) && + ((ParentFrame->InputGlyphIndex + ParentFrame->InputGlyphCount) > Frame->InputGlyphIndex)) + { + ParentFrame->InputGlyphCount += (kbts_u16)(SequenceLookup.InputSequenceCountIncludingSkippedGlyphs - Frame->InputGlyphCount); + } + } + + Frame->InputGlyphCount = (kbts_u16)SequenceLookup.InputSequenceCountIncludingSkippedGlyphs; + Frame->Records = SequenceLookup.Records; + Frame->RecordCount = (kbts_u16)SequenceLookup.RecordCount; + Frame->RecordIndex = 0; + + Frame->SubtableIndex = 0xFFFE; + } + } + else + { + // Do single substitution. + + switch(Lookup.Type) + { + case 1: + { + Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + + if(!CheckOnly) + { + kbts_single_substitution *Subst = (kbts_single_substitution *)Subtable; + + kbts_u16 NewId = 0; + if(Subst->Format == 1) + { + // From the Microsoft docs: + // "Addition of deltaGlyphID is modulo 65536." + NewId = (CurrentGlyph->Id + (kbts_u32)Subst->DeltaOrCount.DeltaGlyphId) & 0xFFFF; + } + else if(Subst->Format == 2) + { + kbts_u16 *SubstituteGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Subst); + NewId = SubstituteGlyphIds[Cover.Index]; + } + + kbts_GsubMutate(Font, CurrentGlyph, NewId, GeneratedGlyphFlags); + } + } break; + + case 2: + { + Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + + if(!CheckOnly) + { + kbts_multiple_substitution *Subst = (kbts_multiple_substitution *)Subtable; + kbts_sequence *Sequence = kbts_GetSequence(Subst, Cover.Index); + kbts_u16 *SubstGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Sequence); + + kbts_un GrowCount = Sequence->GlyphCount - 1; + if(!kbts_GrowGlyphArray(0, &InputGlyphs, 0, GrowCount, 0, 0)) + { + Result |= KBTS_SUBSTITUTION_RESULT_FLAG_GROW_BUFFER; + kbts_TransferGrowRequest(&InputGlyphs, GlyphArray); + + goto Cleanup; + } + DeltaGlyphCount += GrowCount; + + kbts_glyph OriginalGlyph = *CurrentGlyph; + KBTS_FOR(SubstGlyphIndex, 0, Sequence->GlyphCount) + { + kbts_glyph NewGlyph = OriginalGlyph; + kbts_GsubMutate(Font, &NewGlyph, SubstGlyphIds[SubstGlyphIndex], GeneratedGlyphFlags | KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION); + if(SubstGlyphIndex) + { + NewGlyph.Uid = (kbts_u16)++ShapeState->NextGlyphUid; + } + else + { + NewGlyph.Flags |= KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION; + } + Glyphs[Frame->InputGlyphIndex + SubstGlyphIndex] = NewGlyph; + } + + Frame->InputGlyphCount = Sequence->GlyphCount; + + // Shift other frames' input cursors. + KBTS_FOR(FrameIndex, 0, FrameCount - 1) + { + kbts_gsub_frame *OtherFrame = &Frames[FrameIndex]; + + if(OtherFrame->InputGlyphIndex > Frame->InputGlyphIndex) + { + OtherFrame->InputGlyphIndex = (kbts_u16)(OtherFrame->InputGlyphIndex + GrowCount); + } + else if((OtherFrame->InputGlyphIndex + OtherFrame->InputGlyphCount) > Frame->InputGlyphIndex) + { + OtherFrame->InputGlyphCount = (kbts_u16)(OtherFrame->InputGlyphCount + GrowCount); + } + } + } + } break; + + case 3: + { + Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + + if(!CheckOnly) + { + kbts_alternate_substitution *Subst = (kbts_alternate_substitution *)Subtable; + kbts_alternate_set *Set = kbts_GetAlternateSet(Subst, Cover.Index); + kbts_u16 *AltGlyphIds = KBTS_POINTER_AFTER(kbts_u16, Set); + + kbts_un AlternateIndex = 0; + + { + kbts_feature_set *ShaperFeatures = ShapeState->Config->Features; + kbts_glyph_config *GlyphConfig = CurrentGlyph->Config; + if(GlyphConfig) + { + int HasOverride = 0; + KBTS_FOR(WordIndex, 0, KBTS_ARRAY_LENGTH(GlyphConfig->EnabledFeatures.Flags)) + { + kbts_u64 Flags = GlyphConfig->EnabledFeatures.Flags[WordIndex] & ShaperFeatures->Flags[WordIndex]; + if(Flags) + { + HasOverride = 1; + break; + } + } + + if(HasOverride) + { + kbts_op_state_gsub *Gsub = &ShapeState->OpState.OpSpecific.Gsub; + KBTS_FOR(OverrideIndex, 0, GlyphConfig->FeatureOverrideCount) + { + kbts_feature_override *Override = &GlyphConfig->FeatureOverrides[OverrideIndex]; + kbts_u32 EnabledOrAlternatePlusOne = Override->EnabledOrAlternatePlusOne; + + if(EnabledOrAlternatePlusOne && kbts_ContainsFeature(&Gsub->LookupFeatures, Override->Id)) + { + int Match = 1; + if(!Override->Id) + { + // Slow path for unregistered features. + Match = 0; + KBTS_FOR(UnregisteredFeatureIndex, 0, ShapeState->OpState.UnregisteredFeatureCount) + { + if(Override->Tag == ShapeState->OpState.UnregisteredFeatureTags[UnregisteredFeatureIndex]) + { + Match = 1; + break; + } + } + } + + if(Match) + { + AlternateIndex = EnabledOrAlternatePlusOne - 1; + break; + } + } + } + } + } + } + + if(AlternateIndex >= Set->GlyphCount) + { + AlternateIndex = 0; + } + + kbts_u16 NewId = AltGlyphIds[AlternateIndex]; + kbts_GsubMutate(Font, CurrentGlyph, NewId, GeneratedGlyphFlags); + } + } break; + + case 4: + { + kbts_ligature_substitution *Subst = (kbts_ligature_substitution *)Subtable; + kbts_ligature_set *Set = kbts_GetLigatureSet(Subst, Cover.Index); + + KBTS_FOR(LigatureIndex, 0, Set->Count) + { + kbts_ligature *Ligature = kbts_GetLigature(Set, LigatureIndex); + kbts_u16 *ComponentIds = KBTS_POINTER_AFTER(kbts_u16, Ligature); + + if(Ligature->ComponentCount <= InputGlyphs.Count) + { + kbts_un MatchingGlyphCount = 1; + + { + kbts_un InputIndex = 1; + while((InputIndex < InputGlyphs.Count) && (MatchingGlyphCount < Ligature->ComponentCount)) + { + kbts_glyph *Glyph = &InputGlyphs.Glyphs[InputIndex]; + // A ligature may contain an explicit ZWJ, which SkipGlyph() would probably skip. + // The expected behavior in that case is to assume the font designer knows what they are doing + // and match the ZWJ. + if(Glyph->Id == ComponentIds[MatchingGlyphCount - 1]) + { + MatchingGlyphCount += 1; + } + else if(!kbts_SkipGlyph(Glyph, &Lookup, RegularSkipFlags, SkipUnicodeFlags)) + { + break; + } + InputIndex += 1; + } + } + + if(MatchingGlyphCount == Ligature->ComponentCount) + { + Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + + if(!CheckOnly) + { + kbts_u32 LigatureUid = ++ShapeState->NextGlyphUid; + + { // For glyphs that aren't part of the ligature, store which component it is attached to. + // For glyphs that _are_, eat them. + kbts_un LigatureGlyphCount = 1; + kbts_un ReadCursor = 1; + kbts_un WriteCursor = 1; + + while((LigatureGlyphCount < InputGlyphs.Count) && (LigatureGlyphCount < Ligature->ComponentCount) && (ReadCursor < InputGlyphs.Count)) + { + kbts_glyph *Glyph = &InputGlyphs.Glyphs[ReadCursor]; + + if(Glyph->Id == ComponentIds[LigatureGlyphCount - 1]) + { + LigatureGlyphCount += 1; + ReadCursor += 1; + } + else if(kbts_SkipGlyph(Glyph, &Lookup, RegularSkipFlags, SkipUnicodeFlags)) + { + Glyph->LigatureComponentIndexPlusOne = (kbts_u16)LigatureGlyphCount; + Glyph->LigatureUid = (kbts_u16)LigatureUid; + + InputGlyphs.Glyphs[WriteCursor++] = InputGlyphs.Glyphs[ReadCursor++]; + } + else + { + break; + } + } + + // Finish moving all non-ligature glyphs in their place. + // We are effectively shrinking the whole buffer here, so we have to touch + // glyphs outside of our own cluster. + kbts_un GrowCount = WriteCursor - ReadCursor; // Negative + kbts_GrowGlyphArray(0, &InputGlyphs, WriteCursor, GrowCount, 0, 0); + DeltaGlyphCount += GrowCount; + + // Update frame input cursors. + KBTS_FOR(FrameIndex, 0, FrameCount - 1) + { + kbts_gsub_frame *OtherFrame = &Frames[FrameIndex]; + + if(OtherFrame->InputGlyphIndex >= Frame->InputGlyphIndex) + { + kbts_un OtherInputIndex = OtherFrame->InputGlyphIndex + GrowCount; + OtherInputIndex = KBTS_MAX(OtherInputIndex, Frame->InputGlyphIndex); + OtherFrame->InputGlyphIndex = (kbts_u16)OtherInputIndex; + } + else + { + kbts_un End = OtherFrame->InputGlyphIndex + OtherFrame->InputGlyphCount; + End = KBTS_MIN(End, GlyphArray->TotalCount); + OtherFrame->InputGlyphCount = (kbts_u16)(End - OtherFrame->InputGlyphIndex); + } + } + } + + // Currently, we only take the main glyph's config into account while making the ligature's config. + // Maybe we should merge all of the components' configs into one instead? + kbts_GsubMutate(Font, CurrentGlyph, Ligature->Glyph, GeneratedGlyphFlags | KBTS_GLYPH_FLAG_LIGATURE); + CurrentGlyph->Uid = (kbts_u16)LigatureUid; + // Harfbuzz does this, because Uniscribe does this, and so we do the same. Sigh. + CurrentGlyph->Flags &= ~KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION; + } + + break; + } + } + } + } break; + + case 8: + { + kbts_reverse_chain_substitution *Subst = (kbts_reverse_chain_substitution *)Subtable; + kbts_unpacked_reverse_chain_substitution Unpacked = kbts_UnpackReverseChainSubstitution(Subst, 0); + + // :BoundsChecking + if(Cover.Index < Unpacked.GlyphCount) + { + // Should we use regular or sequence skip flags here? + kbts_glyph_array BacktrackGlyphs = kbts_ClipGlyphArray(GlyphArray, Frame->InputGlyphIndex); + kbts_sequence_match BacktrackMatch = kbts_MatchCoverageSequence(&Lookup, RegularSkipFlags, SkipUnicodeFlags, Subst, Unpacked.BacktrackCoverageOffsets, Unpacked.BacktrackCount, + &BacktrackGlyphs, (kbts_un)Frame->InputGlyphIndex - 1, -1); + kbts_glyph_array FollowupGlyphs = kbts_GlyphSubArray(&InputGlyphs, 1); + kbts_sequence_match LookaheadMatch = kbts_MatchCoverageSequence(&Lookup, RegularSkipFlags, SkipUnicodeFlags, Subst, Unpacked.LookaheadCoverageOffsets, Unpacked.LookaheadCount, + &FollowupGlyphs, 0, 1); + if((BacktrackMatch.MatchCount == Unpacked.BacktrackCount) && (LookaheadMatch.MatchCount == Unpacked.LookaheadCount)) + { + Result |= KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION; + kbts_GsubMutate(Font, CurrentGlyph, Unpacked.SubstituteGlyphIds[Cover.Index], GeneratedGlyphFlags); + } + } + } break; + } + + if(Result & KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION) + { + Frame->SubtableIndex = 0xFFFE; + + // From the Microsoft docs: + // To move to the “next” glyph, the client skips all the glyphs that participated in the lookup operation: + // glyphs that were substituted/positioned as well as any other glyphs in the matched input sequence. + + GlyphArray->Count += DeltaGlyphCount; + GlyphArray->TotalCount += DeltaGlyphCount; + } + } + } + } + + Frame->SubtableIndex += 1; + } + + if(Frame->RecordIndex < Frame->RecordCount) + { + kbts_sequence_lookup_record *SequenceRecord = &Frame->Records[Frame->RecordIndex++]; + + kbts_gsub_frame NewFrame = KBTS_ZERO; + NewFrame.LookupIndex = SequenceRecord->LookupListIndex; + NewFrame.SubtableIndex = 0; + NewFrame.InputGlyphIndex = Frame->InputGlyphIndex; + + if(SequenceRecord->SequenceIndex) + { + // @Speed: Re-scan the sequence to find where we are in the _filtered_ sequence. + kbts_un SequenceInputIndex = 0; + KBTS_FOR(FilterAt, Frame->InputGlyphIndex + 1, GlyphArray->Count) + { + kbts_glyph *FilterGlyph = &Glyphs[FilterAt]; + + // @Incomplete: SequenceSkipFlags? 0? + // What do we use here? + if(!kbts_SkipGlyph(FilterGlyph, &Lookup, 0, SkipUnicodeFlags)) + { + SequenceInputIndex += 1; + + if(SequenceInputIndex == SequenceRecord->SequenceIndex) + { + NewFrame.InputGlyphIndex = (kbts_u16)FilterAt; + + break; + } + } + } + } + + NewFrame.InputGlyphCount = 1; + Frames[FrameCount++] = NewFrame; + } + + // Only actually pop the frame if we haven't pushed anything else in the meantime. + if(Frame == &Frames[FrameCount - 1]) + { + FrameCount -= 1; + } + +Cleanup:; + *FrameCount_ = (kbts_u32)FrameCount; + + return Result; +} + +static kbts_u32 kbts_WouldSubstitute(kbts_shape_state *ShapeState, kbts_lookup_list *LookupList, kbts_gsub_frame *Frames, kbts_feature *Feature, kbts_skip_flags SkipFlags, kbts_glyph *Glyphs, kbts_un GlyphCount) +{ + kbts_u32 Result = 0; + kbts_glyph_array GlyphArray = kbts_GlyphArray(Glyphs, GlyphCount, GlyphCount, GlyphCount); + + kbts_iterate_lookups IterateLookups = kbts_IterateLookups(LookupList, Feature); + while(kbts_NextLookup(&IterateLookups)) + { + kbts_un GlyphIndex = 0; + + while(GlyphIndex < GlyphCount) + { + kbts_gsub_frame *Frame = &Frames[0]; + Frame->LookupIndex = IterateLookups.LookupIndex; + Frame->SubtableIndex = 0; + Frame->InputGlyphIndex = 0; + Frame->InputGlyphCount = 1; + kbts_u32 FrameCount = 1; + + while(FrameCount) + { + kbts_substitution_result_flags SubstitutionResult = kbts_DoSubstitution(ShapeState, LookupList, Frames, &FrameCount, &GlyphArray, 1, SkipFlags, 0); + + if(SubstitutionResult & KBTS_SUBSTITUTION_RESULT_FLAG_MATCHED_SUBSTITUTION) + { + Result = 1; + goto Done; + } + } + + GlyphIndex += Frames[0].InputGlyphCount; + } + } + +Done:; + return Result; +} + +static int kbts_NextLookupIndex(kbts_op_state *S, kbts_un *LookupIndex, kbts_u32 *SkipFlags_, kbts_u32 *GlyphFilter_, kbts_feature_set *FeatureSet_) +{ + kbts_un LowestIndex = 0xFFFFFFFF; + KBTS_FOR(FeatureIndex, 0, S->FeatureCount) + { + kbts_lookup_indices *Indices = &S->FeatureLookupIndices[FeatureIndex]; + kbts_un Index = Indices->Indices[0]; + if(Index < LowestIndex) + { + LowestIndex = Index; + } + } + + kbts_feature_set FeatureSet = KBTS_ZERO; + kbts_skip_flags SkipFlags = 0; + kbts_u32 GlyphFilter = 0; + kbts_un UnregisteredFeatureCount = 0; + KBTS_FOR(FeatureIndex, 0, S->FeatureCount) + { + kbts_lookup_indices *Indices = &S->FeatureLookupIndices[FeatureIndex]; + kbts_un Index = Indices->Indices[0]; + if(Index == LowestIndex) + { + SkipFlags |= Indices->SkipFlags; + GlyphFilter |= Indices->GlyphFilter; + kbts_AddFeature(&FeatureSet, Indices->FeatureId); + + if(!Indices->FeatureId && (UnregisteredFeatureCount < KBTS_MAX_SIMULTANEOUS_FEATURES)) + { + S->UnregisteredFeatureTags[UnregisteredFeatureCount++] = Indices->FeatureTag; + } + + ++Indices->Indices; --Indices->Count; + if(!Indices->Count) + { + S->FeatureLookupIndices[FeatureIndex--] = S->FeatureLookupIndices[--S->FeatureCount]; + } + } + } + + S->UnregisteredFeatureCount = (kbts_u32)UnregisteredFeatureCount; + *LookupIndex = LowestIndex; + *SkipFlags_ = SkipFlags; + *GlyphFilter_ = GlyphFilter; + *FeatureSet_ = FeatureSet; + return LowestIndex != 0xFFFFFFFF; +} + +static int kbts_ConfigAllowsFeatures(kbts_op_state *S, kbts_shape_config *Config, kbts_glyph_config *GlyphConfig, kbts_feature_set *Features) +{ + kbts_glyph_config DummyGlyphConfig = KBTS_ZERO; + kbts_u64 UserEnabled = 0; // Whether the user enabled _any_ feature corresponding to this lookup. + kbts_u64 UserDisabled = 1; // Whether the user disabled _all_ features corresponding to this lookup. + kbts_u64 DefaultEnabled = 0; // Whether any feature is non-user. + + if(!GlyphConfig) + { + GlyphConfig = &DummyGlyphConfig; + } + + kbts_u64 Mask = 1; // Ignore unregistered features in the broad pass. + KBTS_FOR(WordIndex, 0, KBTS_ARRAY_LENGTH(GlyphConfig->EnabledFeatures.Flags)) + { + kbts_u64 LookupFeatureFlags = Features->Flags[WordIndex] & ~Mask; + Mask = 0; + + UserEnabled |= GlyphConfig->EnabledFeatures.Flags[WordIndex] & LookupFeatureFlags; + UserDisabled &= (GlyphConfig->DisabledFeatures.Flags[WordIndex] & LookupFeatureFlags) == LookupFeatureFlags; + DefaultEnabled |= Features->Flags[WordIndex] & Config->Features->Flags[WordIndex]; + } + + if(Features->Flags[0] & (GlyphConfig->EnabledFeatures.Flags[0] | GlyphConfig->DisabledFeatures.Flags[0]) & KBTS_FEATURE_FLAG0(UNREGISTERED)) + { + // Slow path for unregistered features. + KBTS_FOR(FeatureOverrideIndex, 0, GlyphConfig->FeatureOverrideCount) + { + kbts_feature_override *Override = &GlyphConfig->FeatureOverrides[FeatureOverrideIndex]; + if(Override->Id == KBTS_FEATURE_ID_UNREGISTERED) + { + kbts_feature_tag OverrideTag = Override->Tag; + KBTS_FOR(UnregisteredFeatureIndex, 0, S->UnregisteredFeatureCount) + { + if(OverrideTag == S->UnregisteredFeatureTags[UnregisteredFeatureIndex]) + { + UserEnabled |= Override->EnabledOrAlternatePlusOne; + UserDisabled &= !Override->EnabledOrAlternatePlusOne; + break; + } + } + } + } + } + int Result = (!UserDisabled && (DefaultEnabled || UserEnabled)); + return Result; +} + +static kbts_u32 kbts_ExecuteOp(kbts_shape_state *ShapeState, kbts_glyph_array *GlyphArray) +{ + KBTS_INSTRUMENT_FUNCTION_BEGIN + kbts_shape_config *Config = ShapeState->Config; + kbts_font *Font = Config->Font; + kbts_op *Op = &ShapeState->Op; + kbts_op_state *S = &ShapeState->OpState; + kbts_glyph *Glyphs = GlyphArray->Glyphs; + + kbts_u32 ResumePoint = S->ResumePoint; + S->ResumePoint = 0; + switch(ResumePoint) + { + case 1: goto ResumePoint1; break; + case 2: goto ResumePoint2; break; + case 3: goto ResumePoint3; break; + case 4: goto ResumePoint4; break; + case 5: goto ResumePoint5; break; + } + + S->WrittenCount = 0; + + switch(Op->Kind) + { + case KBTS_OP_KIND_PRE_NORMALIZE_DOTTED_CIRCLES: + { + KBTS_INSTRUMENT_BLOCK_BEGIN("PRE_NORMALIZE_DOTTED_CIRCLES") + // Before even trying to normalize anything, there are some _exceptions_ we have to take care of. + // The USE spec gives us a list of codepoint sequences which necessitate insertion of a dotted circle. + // These sequences are from IndicShapingInvalidClusters.txt. + S->GlyphIndex = 0; + kbts_u64 Codepoints; Codepoints = 0; // 0xABBBBBCCCCCDDDDD + for(; S->GlyphIndex < GlyphArray->Count; ++S->GlyphIndex) + { + kbts_u32 NewCodepoint; NewCodepoint = Glyphs[S->GlyphIndex].Codepoint & 0x1FFFFF; + Codepoints = (Codepoints << 21) | NewCodepoint; + + // This switch is faster than any table lookup I could come up with in my tests. + #define KBTS_C2(A, B) case (((kbts_u64)(A) << 21) | (kbts_u64)(B)): + switch(Codepoints & (((kbts_u64)1 << 42) - 1)) + { + default: + if((Codepoints & (((kbts_u64)1 << 63) - 1)) == (((kbts_u64)0x930 << 42) | ((kbts_u64)0x94D << 21) | ((kbts_u64)0x907))) + { + if(0) + { + ResumePoint4:; + Codepoints = 0; + } + KBTS_C2(0x905, 0x93A) + KBTS_C2(0x905, 0x93B) + KBTS_C2(0x905, 0x93E) + KBTS_C2(0x905, 0x945) + KBTS_C2(0x905, 0x946) + KBTS_C2(0x905, 0x949) + KBTS_C2(0x905, 0x94A) + KBTS_C2(0x905, 0x94B) + KBTS_C2(0x905, 0x94C) + KBTS_C2(0x905, 0x94F) + KBTS_C2(0x905, 0x956) + KBTS_C2(0x905, 0x957) + KBTS_C2(0x906, 0x93A) + KBTS_C2(0x906, 0x945) + KBTS_C2(0x906, 0x946) + KBTS_C2(0x906, 0x947) + KBTS_C2(0x906, 0x948) + KBTS_C2(0x909, 0x941) + KBTS_C2(0x90F, 0x945) + KBTS_C2(0x90F, 0x946) + KBTS_C2(0x90F, 0x947) + KBTS_C2(0x985, 0x9BE) + KBTS_C2(0x98B, 0x9C3) + KBTS_C2(0x98C, 0x9E2) + KBTS_C2(0xA05, 0xA3E) + KBTS_C2(0xA05, 0xA48) + KBTS_C2(0xA05, 0xA4C) + KBTS_C2(0xA72, 0xA3F) + KBTS_C2(0xA72, 0xA40) + KBTS_C2(0xA72, 0xA47) + KBTS_C2(0xA73, 0xA41) + KBTS_C2(0xA73, 0xA42) + KBTS_C2(0xA73, 0xA4B) + KBTS_C2(0xA85, 0xABE) + KBTS_C2(0xA85, 0xAC5) + KBTS_C2(0xA85, 0xAC7) + KBTS_C2(0xA85, 0xAC8) + KBTS_C2(0xA85, 0xAC9) + KBTS_C2(0xA85, 0xACB) + KBTS_C2(0xA85, 0xACC) + KBTS_C2(0xAC5, 0xABE) + KBTS_C2(0xB05, 0xB3E) + KBTS_C2(0xB0F, 0xB57) + KBTS_C2(0xB13, 0xB57) + KBTS_C2(0xB85, 0xBC2) + KBTS_C2(0xC12, 0xC4C) + KBTS_C2(0xC12, 0xC55) + KBTS_C2(0xC3F, 0xC55) + KBTS_C2(0xC46, 0xC55) + KBTS_C2(0xC4A, 0xC55) + KBTS_C2(0xC89, 0xCBE) + KBTS_C2(0xC8B, 0xCBE) + KBTS_C2(0xC92, 0xCCC) + KBTS_C2(0xD07, 0xD57) + KBTS_C2(0xD09, 0xD57) + KBTS_C2(0xD0E, 0xD46) + KBTS_C2(0xD12, 0xD3E) + KBTS_C2(0xD12, 0xD57) + KBTS_C2(0xD85, 0xDCF) + KBTS_C2(0xD85, 0xDD0) + KBTS_C2(0xD85, 0xDD1) + KBTS_C2(0xD8B, 0xDDF) + KBTS_C2(0xD8D, 0xDD8) + KBTS_C2(0xD8F, 0xDDF) + KBTS_C2(0xD91, 0xDCA) + KBTS_C2(0xD91, 0xDD9) + KBTS_C2(0xD91, 0xDDA) + KBTS_C2(0xD91, 0xDDC) + KBTS_C2(0xD91, 0xDDD) + KBTS_C2(0xD91, 0xDDE) + KBTS_C2(0xD94, 0xDDF) + KBTS_C2(0x11005, 0x11038) + KBTS_C2(0x1100B, 0x1103E) + KBTS_C2(0x1100F, 0x11042) + KBTS_C2(0x11200, 0x1122C) + KBTS_C2(0x11200, 0x11231) + KBTS_C2(0x11200, 0x11233) + KBTS_C2(0x11206, 0x1122C) + KBTS_C2(0x1122C, 0x11230) + KBTS_C2(0x1122C, 0x11231) + KBTS_C2(0x11240, 0x1122E) + KBTS_C2(0x112B0, 0x112E0) + KBTS_C2(0x112B0, 0x112E5) + KBTS_C2(0x112B0, 0x112E6) + KBTS_C2(0x112B0, 0x112E7) + KBTS_C2(0x112B0, 0x112E8) + KBTS_C2(0x11481, 0x114B0) + KBTS_C2(0x1148B, 0x114BA) + KBTS_C2(0x1148D, 0x114BA) + KBTS_C2(0x114AA, 0x114B5) + KBTS_C2(0x114AA, 0x114B6) + KBTS_C2(0x11600, 0x11639) + KBTS_C2(0x11600, 0x1163A) + KBTS_C2(0x11601, 0x11639) + KBTS_C2(0x11601, 0x1163A) + KBTS_C2(0x11680, 0x116AD) + KBTS_C2(0x11680, 0x116B4) + KBTS_C2(0x11680, 0x116B5) + KBTS_C2(0x11686, 0x116B2) + if(!kbts_GrowGlyphArray(&S->ResumePoint, GlyphArray, S->GlyphIndex, 1, 4, 0)) + { + KBTS_INSTRUMENT_END + return 1; + } + GlyphArray->Glyphs[S->GlyphIndex] = Config->DottedCircle; + } + } + #undef KBTS_C2 + } + + S->WrittenCount = GlyphArray->TotalCount; + KBTS_INSTRUMENT_END + } break; + + case KBTS_OP_KIND_NORMALIZE: + { + KBTS_INSTRUMENT_BLOCK_BEGIN("NORMALIZE") + // @Incomplete: We need to honor this. + // HB_OT_SHAPE_NORMALIZATION_MODE_NONE, + // HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* Always fully decomposes and then recompose back */ + // + // hangul: HB_OT_SHAPE_NORMALIZATION_MODE_NONE, + // arabic: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // default: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // hebrew: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // thai: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO, + // indic: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + // khmer: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + // myanmar: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + // use: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, + + { // Full NFD decomposition + kbts_glyph *DecompositionGlyphs; DecompositionGlyphs = KBTS_POINTER_AFTER(kbts_glyph, S); + for(S->GlyphIndex = 0; S->GlyphIndex < GlyphArray->Count; ++S->GlyphIndex) + { + DecompositionGlyphs[0] = Glyphs[S->GlyphIndex]; + S->OpSpecific.Normalize.CodepointsToDecomposeCount = 1; + + while(S->OpSpecific.Normalize.CodepointsToDecomposeCount) + { + if(0) + { + ResumePoint1:; + DecompositionGlyphs = KBTS_POINTER_AFTER(kbts_glyph, S); + } + + kbts_glyph GlyphToDecompose = DecompositionGlyphs[--S->OpSpecific.Normalize.CodepointsToDecomposeCount]; + kbts_u64 Decomposition = 0; + kbts_u32 DecompositionSize = 0; + kbts_u32 AnyUnsupported = 0; + kbts_glyph Decomposed[2]; + + if(!(GlyphToDecompose.Flags & KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE)) + { + Decomposition = GlyphToDecompose.Decomposition; + DecompositionSize = kbts_GetDecompositionSize(Decomposition); + + // Only decompose when the font supports the decomposed form. + KBTS_FOR(DecompositionIndex, 0, DecompositionSize) + { + kbts_glyph DecompositionGlyph = kbts_CodepointToGlyph(Font, kbts_GetDecompositionCodepoint(Decomposition, DecompositionIndex)); + DecompositionGlyph.Config = GlyphToDecompose.Config; + + AnyUnsupported |= !DecompositionGlyph.Id; + Decomposed[DecompositionIndex] = DecompositionGlyph; + } + } + + if(AnyUnsupported | !DecompositionSize) + { + if(S->WrittenCount > S->GlyphIndex) + { + if(!kbts_GrowGlyphArray(&S->ResumePoint, GlyphArray, S->WrittenCount, 1, 1, 0)) + { + S->OpSpecific.Normalize.CodepointsToDecomposeCount += 1; // Push the codepoint back on the stack. + + KBTS_INSTRUMENT_END + return 1; + } + + S->GlyphIndex += 1; + } + + Glyphs[S->WrittenCount++] = GlyphToDecompose; + } + else + { + KBTS_ASSERT((S->OpSpecific.Normalize.CodepointsToDecomposeCount + DecompositionSize) <= KBTS_MAXIMUM_DECOMPOSITION_CODEPOINTS); + + if(Decomposition & KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE0) + { + Decomposed[0].Flags |= KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE; + } + if(Decomposition & KBTS_UNICODE_DECOMPOSITION_DO_NOT_RECURSE1) + { + Decomposed[1].Flags |= KBTS_GLYPH_FLAG_DO_NOT_DECOMPOSE; + } + + KBTS_FOR(DecompositionIndex, 0, DecompositionSize) + { + // We reverse the glyphs here because we use a stack. + DecompositionGlyphs[S->OpSpecific.Normalize.CodepointsToDecomposeCount++] = Decomposed[DecompositionSize - 1 - DecompositionIndex]; + } + } + } + } + } + + { // Selective recomposition. + // The OpenType shaping documents say that Hebrew Alphabetic Presentation Form compositions aren't canonical, + // but looking at UnicodeData.txt, it seems like they totally are, so they are handled here. + kbts_glyph *LastBase = 0; + kbts_un LastBaseParentCount = 0; + kbts_s32 *LastBaseParentDeltas = 0; + kbts_un PreSlashDecimalDigitCount = 0; + kbts_un DecimalDigitCount = 0; + int InFraction = 0; + + kbts_u32 BeforeFractionSlashGlyphFlags = KBTS_GLYPH_FLAG_NUMR | KBTS_GLYPH_FLAG_FRAC; + kbts_u32 AfterFractionSlashGlyphFlags = KBTS_GLYPH_FLAG_DNOM | KBTS_GLYPH_FLAG_FRAC; + if(kbts_ShaperRtl(Config->Shaper)) + { + // RTL needs to invert NUMR and DNOM. + kbts_u32 Swap = BeforeFractionSlashGlyphFlags; + BeforeFractionSlashGlyphFlags = AfterFractionSlashGlyphFlags; + AfterFractionSlashGlyphFlags = Swap; + } + + // We also collate user features here. + kbts_feature_set UserFeatures = KBTS_ZERO; + kbts_feature_set *DefaultFeatures = Config->Features; + + KBTS_FOR(GlyphIndex, 0, S->WrittenCount) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + Glyph->Uid = (kbts_u16)++ShapeState->NextGlyphUid; + + if(Glyph->Config) + { + kbts_glyph_config *GlyphConfig = Glyph->Config; + KBTS_FOR(WordIndex, 0, KBTS_ARRAY_LENGTH(UserFeatures.Flags)) + { + UserFeatures.Flags[WordIndex] |= GlyphConfig->EnabledFeatures.Flags[WordIndex] & ~DefaultFeatures->Flags[WordIndex]; + } + } + + kbts_un AvailableGlyphCount = 0; + if(!Glyph->CombiningClass) + { + LastBase = Glyph; + // From the Microsoft docs: + // USE decomposes split vowel characters belonging to UISC = Vowel_Dependent according to character + // decomposition mappings defined in UnicodeData.txt + // Cluster validation, is done based on the decomposed state of a split vowel. + // + // (Note: our Matra corresponds to Vowel_Dependent + Pure_Killer.) + if((Config->Shaper != KBTS_SHAPER_USE) || (Glyph->SyllabicClass != KBTS_INDIC_SYLLABIC_CLASS_MATRA)) + { + LastBaseParentDeltas = kbts_GetParentInfoDeltas(Glyph->ParentInfo); + LastBaseParentCount = kbts_GetParentInfoCount(Glyph->ParentInfo); + AvailableGlyphCount = 1; + } + else + { + LastBaseParentDeltas = 0; + LastBaseParentCount = 0; + } + } + else + { + if(LastBase) + { + AvailableGlyphCount = 2; + } + } + + KBTS_FOR(ParentIndex, 0, LastBaseParentCount) + { + kbts_u32 ParentCodepoint = LastBase->Codepoint + (kbts_u32)LastBaseParentDeltas[ParentIndex]; + kbts_glyph ParentGlyph = kbts_CodepointToGlyph(Font, ParentCodepoint); + kbts_u32 DecompositionSize = kbts_GetDecompositionSize(ParentGlyph.Decomposition); + + ParentGlyph.Uid = LastBase->Uid; + ParentGlyph.Config = LastBase->Config; + if((DecompositionSize == AvailableGlyphCount) && ParentGlyph.Id) + { + if(DecompositionSize == 2) + { + if(kbts_GetDecompositionCodepoint(ParentGlyph.Decomposition, 1) == Glyph->Codepoint) + { + // Both match. Reclaim space. + // @Speed: We should use separate read and write cursors instead. + KBTS_FOR(ShrinkIndex, GlyphIndex + 1, S->WrittenCount) + { + Glyphs[ShrinkIndex - 1] = Glyphs[ShrinkIndex]; + } + S->WrittenCount -= 1; + } + else + { + continue; + } + } + + *LastBase = ParentGlyph; + GlyphIndex = (kbts_un)((LastBase - Glyphs) - 1); // Handle recursive recomposition. + break; + } + } + + // It is safe to look for fractions here, because decimal digits/the fraction slash are not marks or + // jamos, so they should not get reordered after this pass. + if(Glyph->UnicodeFlags & KBTS_UNICODE_FLAG_DECIMAL_DIGIT) + { + if(InFraction) + { + // We are in the post-slash part of the fraction. + Glyph->Flags |= AfterFractionSlashGlyphFlags; + // Only flag the pre-slash part of the fraction if there is a post-slash part. + KBTS_FOR(DecimalDigitIndex, 0, PreSlashDecimalDigitCount) + { + Glyphs[GlyphIndex - PreSlashDecimalDigitCount - 1 + DecimalDigitIndex].Flags |= BeforeFractionSlashGlyphFlags; + } + PreSlashDecimalDigitCount = 0; + } + DecimalDigitCount += 1; + } + else if((Glyph->Codepoint == 0x2044) && (!InFraction || DecimalDigitCount)) + { + // Fraction slash. + Glyph->Flags |= KBTS_GLYPH_FLAG_FRAC; + PreSlashDecimalDigitCount = DecimalDigitCount; + InFraction = DecimalDigitCount != 0; + DecimalDigitCount = 0; + } + else + { + InFraction = 0; + } + } + + // Ignore added features that are already part of the shaper. + kbts_feature_set *ShaperFeatures = Config->Features; + KBTS_FOR(WordIndex, 0, KBTS_ARRAY_LENGTH(UserFeatures.Flags)) + { + UserFeatures.Flags[WordIndex] &= ~ShaperFeatures->Flags[WordIndex]; + } + + ShapeState->UserFeatures = UserFeatures; + } + + { // Unicode mark reordering. + S->GlyphIndex = 0; + while(S->GlyphIndex < S->WrittenCount) + { + kbts_glyph *Glyph = &Glyphs[S->GlyphIndex]; + kbts_u8 CombiningClass = Glyph->CombiningClass; + + kbts_un IndexIncrement = 1; + + if(CombiningClass) + { + Glyph->MarkOrdering = CombiningClass; + kbts_un MarkSequenceLength = 1; + while((S->GlyphIndex + MarkSequenceLength) < S->WrittenCount) + { + kbts_glyph *SequenceGlyph = &Glyphs[S->GlyphIndex + MarkSequenceLength]; + kbts_u8 SequenceGlyphCombiningClass = SequenceGlyph->CombiningClass; + if(SequenceGlyphCombiningClass) + { + SequenceGlyph->MarkOrdering = SequenceGlyphCombiningClass; + MarkSequenceLength += 1; + } + else + { + break; + } + } + + KBTS_FOR(Iter, 0, MarkSequenceLength) + { + KBTS_FOR(SequenceIndex, 1, MarkSequenceLength) + { + kbts_glyph *Glyph0 = &Glyphs[S->GlyphIndex + SequenceIndex - 1]; + kbts_glyph *Glyph1 = &Glyphs[S->GlyphIndex + SequenceIndex]; + + if(Glyph0->MarkOrdering > Glyph1->MarkOrdering) + { + kbts_glyph Swap = *Glyph0; + *Glyph0 = *Glyph1; + *Glyph1 = Swap; + } + } + } + + IndexIncrement = MarkSequenceLength; + } + + S->GlyphIndex += IndexIncrement; + } + } + + if(Config->Script == KBTS_SCRIPT_ARABIC) + { + S->GlyphIndex = 0; + while(S->GlyphIndex < S->WrittenCount) + { + // Find a mark sequence. + kbts_glyph *Glyph = &Glyphs[S->GlyphIndex]; + kbts_u8 CombiningClass = Glyph->CombiningClass; + + if(CombiningClass) + { + // Arabic: Reorder sequences of mark glyphs. + // + // From the Unicode standard: + // - Move any shadda characters (ccc=33) to the beginning of S. + // - If a sequence of ccc=230 characters begins with any MCM characters, move the sequence of such MCM + // characters + // to the beginning of S (before any characters with ccc=33). + // - If a sequence of ccc=220 characters begins with any MCM characters, move the sequence of such MCM + // characters + // to the beginning of S (before any MCM with ccc=230 or ccc=33). + // + // Final ordering: 220 230 shadda other + + kbts_mcm_sequence_state Mcm220SequenceState = 0; + kbts_mcm_sequence_state Mcm230SequenceState = 0; + + kbts_un SequenceStart = S->GlyphIndex; + +# define KBTS_REMAPPED_CCC_33 27 + + while(S->GlyphIndex < S->WrittenCount) + { + kbts_glyph *SequenceGlyph = &Glyphs[S->GlyphIndex]; + kbts_u16 SequenceGlyphCombiningClass = SequenceGlyph->CombiningClass; + kbts_u16 SequenceGlyphFlags = SequenceGlyph->UnicodeFlags; + + kbts_u8 MarkOrdering = 3; + + if(SequenceGlyphCombiningClass == KBTS_REMAPPED_CCC_33) + { + MarkOrdering = 2; + } + else if(SequenceGlyphCombiningClass == 220) + { + if(SequenceGlyphFlags & KBTS_UNICODE_FLAG_MODIFIER_COMBINING_MARK) + { + if(Mcm220SequenceState != KBTS_MCM_SEQUENCE_STATE_OUT) + { + Mcm220SequenceState = KBTS_MCM_SEQUENCE_STATE_IN; + } + } + else + { + Mcm220SequenceState = KBTS_MCM_SEQUENCE_STATE_OUT; + } + + if(Mcm220SequenceState == KBTS_MCM_SEQUENCE_STATE_IN) + { + MarkOrdering = 0; + } + + Mcm230SequenceState = KBTS_MCM_SEQUENCE_STATE_NONE; + } + else if(SequenceGlyphCombiningClass == 230) + { + if(SequenceGlyphFlags & KBTS_UNICODE_FLAG_MODIFIER_COMBINING_MARK) + { + if(Mcm230SequenceState != KBTS_MCM_SEQUENCE_STATE_OUT) + { + Mcm230SequenceState = KBTS_MCM_SEQUENCE_STATE_IN; + } + } + else + { + Mcm230SequenceState = KBTS_MCM_SEQUENCE_STATE_OUT; + } + + if(Mcm230SequenceState == KBTS_MCM_SEQUENCE_STATE_IN) + { + MarkOrdering = 1; + } + } + else if(SequenceGlyphCombiningClass) + { + Mcm220SequenceState = KBTS_MCM_SEQUENCE_STATE_NONE; + Mcm230SequenceState = KBTS_MCM_SEQUENCE_STATE_NONE; + } + else + { + break; + } + + SequenceGlyph->MarkOrdering = MarkOrdering; + S->GlyphIndex += 1; + } + + KBTS_FOR(Iter, SequenceStart, S->GlyphIndex) + { + KBTS_FOR(SortIndex, SequenceStart + 1, S->GlyphIndex) + { + kbts_glyph *Left = &Glyphs[SortIndex - 1]; + kbts_glyph *Right = &Glyphs[SortIndex]; + + if(Left->MarkOrdering > Right->MarkOrdering) + { + kbts_glyph Swap = *Left; + *Left = *Right; + *Right = Swap; + } + } + } + } + else + { + S->GlyphIndex += 1; + } + } + } + else if((Config->Script == KBTS_SCRIPT_THAI) || (Config->Script == KBTS_SCRIPT_LAO)) + { + // Decompose sara/sala ams. + kbts_un AboveBaseGlyphCount; AboveBaseGlyphCount = 0; + for(S->GlyphIndex = 0; S->GlyphIndex < S->WrittenCount; ++S->GlyphIndex) + { + if(0) + { + ResumePoint5:; + AboveBaseGlyphCount = S->OpSpecific.Normalize.AboveBaseGlyphCount; + } + kbts_glyph *Glyph = &Glyphs[S->GlyphIndex]; + kbts_u32 Codepoint = Glyph->Codepoint; + + switch(Codepoint) + { + // Sara am/sala am. + // We match both because storing the sara am codepoint that corresponds to the current script + // doesn't seem that worthwhile, given that this is already a pretty big switch case. + // If we choose to use a unicode flag or indic syllabic category to notate above-base marks, + // then this loops gets a lot tighter and it would probably become the right call to pre-determine + // the sara am codepoint. + case 0xE33: case 0xEB3: // Sara am + { + if(!kbts_GrowGlyphArray(&S->ResumePoint, GlyphArray, S->GlyphIndex, 1, 5, 0)) + { + S->OpSpecific.Normalize.AboveBaseGlyphCount = AboveBaseGlyphCount; + KBTS_INSTRUMENT_END + return 1; + } + + AboveBaseGlyphCount = S->OpSpecific.Normalize.AboveBaseGlyphCount; + for(kbts_un AboveBaseIndex = 0; AboveBaseIndex < AboveBaseGlyphCount; ++AboveBaseIndex) + { + Glyphs[S->GlyphIndex - AboveBaseIndex] = Glyphs[S->GlyphIndex - AboveBaseIndex - 1]; + } + Glyphs[S->GlyphIndex - AboveBaseGlyphCount] = Config->Nikhahit; + Glyphs[S->GlyphIndex + 1] = Config->SaraAa; + S->WrittenCount += 1; + } break; + + case 0xE31: case 0xE34: case 0xE35: case 0xE36: case 0xE37: case 0xE3B: + case 0xE47: case 0xE48: case 0xE49: case 0xE4A: case 0xE4B: case 0xE4C: case 0xE4D: case 0xE4E: + case 0xEB1: case 0xEB4: case 0xEB5: case 0xEB6: case 0xEB7: case 0xEBB: + case 0xEC7: case 0xEC8: case 0xEC9: case 0xECA: case 0xECB: case 0xECC: case 0xECD: case 0xECE: + AboveBaseGlyphCount += 1; + break; + + default: + AboveBaseGlyphCount = 0; + break; + } + } + } + + KBTS_INSTRUMENT_END + } + break; + + case KBTS_OP_KIND_NORMALIZE_HANGUL: + { + KBTS_INSTRUMENT_BLOCK_BEGIN("NORMALIZE_HANGUL") + kbts_op_state_normalize_hangul *NormalizeHangul; NormalizeHangul = &S->OpSpecific.NormalizeHangul; + S->GlyphIndex = 0; + while(S->GlyphIndex < GlyphArray->Count) + { + { + kbts_glyph *Glyph = &Glyphs[S->GlyphIndex]; + kbts_un L = 0; + kbts_un V = 0; + kbts_un T = 0; + + kbts_hangul_syllable_info LInfo = kbts_HangulSyllableInfo(Glyph->Codepoint); + if(LInfo.Type >= KBTS_HANGUL_SYLLABLE_TYPE_LV) + { + kbts_un SIndex = (Glyph->Codepoint - 0xAC00); + + L = 0x1100 + SIndex / 588; + V = 0x1161 + (SIndex % 588) / 28; + + kbts_un TIndex = SIndex % 28; + if(TIndex) + { + T = 0x11A7 + TIndex; + } + } + else if(LInfo.Type == KBTS_HANGUL_SYLLABLE_TYPE_L) + { + L = Glyph->Codepoint; + } + + S->GlyphIndex += 1; + + if(L) + { + kbts_hangul_syllable_info VInfo = KBTS_ZERO; + + if(!V && (S->GlyphIndex < GlyphArray->Count)) + { + kbts_u32 VCodepoint = Glyphs[S->GlyphIndex].Codepoint; + + VInfo = kbts_HangulSyllableInfo(VCodepoint); + + if(VInfo.Type == KBTS_HANGUL_SYLLABLE_TYPE_V) + { + V = VCodepoint; + + S->GlyphIndex += 1; + } + } + + if(V) + { + kbts_hangul_syllable_info TInfo = KBTS_ZERO; + + if(!T && (S->GlyphIndex < GlyphArray->Count)) + { + kbts_u32 TCodepoint = Glyphs[S->GlyphIndex].Codepoint; + + TInfo = kbts_HangulSyllableInfo(TCodepoint); + + if(TInfo.Type == KBTS_HANGUL_SYLLABLE_TYPE_T) + { + T = TCodepoint; + + S->GlyphIndex += 1; + } + } + + NormalizeHangul->LvtGlyphCount = 0; + + // Check for any tone marks that we need to swap to the front of the syllable. + // The OpenType shaping documents say that we need to do this after applying GSUB features, but + // harfbuzz does it before, so it's probably fine to do it here? + // It's also basically free to do here, which is nice. + if(S->GlyphIndex < GlyphArray->Count) + { + kbts_u32 ToneMarkCodepoint = Glyphs[S->GlyphIndex].Codepoint; + + if((ToneMarkCodepoint >= 0x302E) && (ToneMarkCodepoint <= 0x302F)) + { + NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = kbts_CodepointToGlyph(Font, ToneMarkCodepoint); + + S->GlyphIndex += 1; + } + } + + if(LInfo.Composable & VInfo.Composable & TInfo.Composable) + { + // Try LVT. + kbts_un LvtCodepoint = 0xAC00 + (L - 0x1100) * 588 + (V - 0x1161) * 28 + (T - 0x11A7); + + kbts_glyph LvtGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)LvtCodepoint); + if(LvtGlyph.Id) + { + NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = LvtGlyph; + } + } + + if(!NormalizeHangul->LvtGlyphCount) + { + kbts_glyph LvGlyph = KBTS_ZERO; + if(LInfo.Composable & VInfo.Composable) + { + // Try LV. + kbts_un LvCodepoint = 0xAC00 + (L - 0x1100) * 588 + (V - 0x1161) * 28; + + LvGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)LvCodepoint); + } + + if(LvGlyph.Id) + { + NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = LvGlyph; + } + else + { + // Do L-V. + kbts_glyph LGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)L); + LGlyph.Flags |= KBTS_GLYPH_FLAG_LJMO; + + kbts_glyph VGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)V); + VGlyph.Flags |= KBTS_GLYPH_FLAG_VJMO; + + NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = LGlyph; + NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = VGlyph; + } + + if(T) + { + kbts_glyph TGlyph = kbts_CodepointToGlyph(Font, (kbts_u32)T); + TGlyph.Flags |= KBTS_GLYPH_FLAG_TJMO; + + NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = TGlyph; + } + } + } + } + + if(!NormalizeHangul->LvtGlyphCount) + { + kbts_glyph NewGlyph = kbts_CodepointToGlyph(Font, Glyph->Codepoint); + + NormalizeHangul->LvtGlyphs[NormalizeHangul->LvtGlyphCount++] = NewGlyph; + } + } + + { // Insert the LVT glyphs. + ResumePoint3:; + NormalizeHangul = &S->OpSpecific.NormalizeHangul; + + kbts_un NewWrittenCount = S->WrittenCount + NormalizeHangul->LvtGlyphCount; + if(NewWrittenCount > S->GlyphIndex) + { + if(!kbts_GrowGlyphArray(&S->ResumePoint, GlyphArray, S->WrittenCount, NormalizeHangul->LvtGlyphCount, 3, 0)) + { + KBTS_INSTRUMENT_END + return 1; + } + + S->GlyphIndex += NormalizeHangul->LvtGlyphCount; + } + + KBTS_FOR(LvtGlyphIndex, 0, NormalizeHangul->LvtGlyphCount) + { + Glyphs[S->WrittenCount++] = NormalizeHangul->LvtGlyphs[LvtGlyphIndex]; + } + } + } + KBTS_INSTRUMENT_END + } + break; + + case KBTS_OP_KIND_GSUB_FEATURES: + { + KBTS_INSTRUMENT_BLOCK_BEGIN("GSUB_FEATURES") + + kbts_gsub_gpos *FontGsub; FontGsub = Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]; + kbts_lookup_list *LookupList; LookupList = kbts_GetLookupList(FontGsub); + kbts_gsub_frame *Frames; Frames = KBTS_POINTER_AFTER(kbts_gsub_frame, S); + kbts_op_state_gsub *Gsub; Gsub = &S->OpSpecific.Gsub; + kbts_u32 GlyphFilter; + kbts_skip_flags SkipFlags; + kbts_feature_set LookupFeatures; + + kbts_BeginFeatures(S, Config, KBTS_SHAPING_TABLE_GSUB, Op->Features); + while(kbts_NextLookupIndex(S, &Gsub->LookupIndex, &SkipFlags, &GlyphFilter, &LookupFeatures)) + { + Gsub->LookupFeatures = LookupFeatures; + S->GlyphIndex = 0; + + // From the Microsoft docs: + // If a Lookup table has multiple subtables, the subtables are processed in order, testing the glyph sequence + // at the current glyph position for a match with the input sequence patterns specified by each subtable in + // turn. + // + // This means the subtable loop is _inside_ of the loop over our glyphs. + while(S->GlyphIndex < GlyphArray->Count) + { + Frames[0].InputGlyphCount = 1; + + { + kbts_u32 FilterMask = Config->Shaper == KBTS_SHAPER_USE ? KBTS_USE_GLYPH_FEATURE_MASK : KBTS_GLYPH_FEATURE_MASK; + kbts_u32 EffectiveGlyphFilter = GlyphFilter & FilterMask; + + // Reverse chaining substitutions are tricky. + // See the comment at :ReverseChaining. + // @Duplication: We just copy the top-level mirroring logic from DoSubstitution here for now. + kbts_lookup *Lookup = kbts_GetLookup(LookupList, Gsub->LookupIndex); + kbts_un CurrentGlyphIndex = (Lookup->Type == 8) ? GlyphArray->Count - 1 - S->GlyphIndex : S->GlyphIndex; + kbts_glyph *CurrentGlyph = &Glyphs[CurrentGlyphIndex]; + + if(kbts_GlyphIncludedInLookup(Config->Font, 0, Gsub->LookupIndex, CurrentGlyph->Id) && + ((CurrentGlyph->Flags & EffectiveGlyphFilter) == EffectiveGlyphFilter) && + kbts_ConfigAllowsFeatures(S, Config, CurrentGlyph->Config, &LookupFeatures)) + { + kbts_gsub_frame *Frame = &Frames[0]; + + Frame->LookupIndex = (kbts_u16)Gsub->LookupIndex; + Frame->SubtableIndex = 0; + Frame->InputGlyphIndex = (kbts_u16)S->GlyphIndex; + S->FrameCount = 1; + } + } + + while(S->FrameCount) + { + if(0) + { + ResumePoint2:; + FontGsub = Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]; + Gsub = &S->OpSpecific.Gsub; + LookupList = kbts_GetLookupList(FontGsub); + Frames = KBTS_POINTER_AFTER(kbts_gsub_frame, S); + LookupFeatures = Gsub->LookupFeatures; + GlyphFilter = Gsub->GlyphFilter; + SkipFlags = Gsub->SkipFlags; + } + + // These flags are used by USE. + kbts_u32 GeneratedGlyphFlags = GlyphFilter & (KBTS_GLYPH_FLAG_RPHF | KBTS_GLYPH_FLAG_PREF); + kbts_substitution_result_flags SubstitutionFlags = kbts_DoSubstitution(ShapeState, LookupList, Frames, &S->FrameCount, GlyphArray, 0, SkipFlags, GeneratedGlyphFlags); + if(SubstitutionFlags & KBTS_SUBSTITUTION_RESULT_FLAG_GROW_BUFFER) + { + Gsub->GlyphFilter = GlyphFilter; + Gsub->SkipFlags = SkipFlags; + S->ResumePoint = 2; + + KBTS_INSTRUMENT_END + return 1; + } + } + + S->GlyphIndex += Frames[0].InputGlyphCount; + } + } + + S->WrittenCount = GlyphArray->Count; + KBTS_INSTRUMENT_END + } + break; + + case KBTS_OP_KIND_FLAG_JOINING_LETTERS: + { + KBTS_INSTRUMENT_BLOCK_BEGIN("FLAG_JOINING_LETTERS") + kbts_u64 JoiningTypesMatchLookup = + (((1ull << KBTS_UNICODE_JOINING_TYPE_RIGHT) | (1ull << KBTS_UNICODE_JOINING_TYPE_DUAL) | (1ull << KBTS_UNICODE_JOINING_TYPE_FORCE)) << (8 * KBTS_UNICODE_JOINING_TYPE_LEFT)) | + (((1ull << KBTS_UNICODE_JOINING_TYPE_RIGHT) | (1ull << KBTS_UNICODE_JOINING_TYPE_DUAL) | (1ull << KBTS_UNICODE_JOINING_TYPE_FORCE)) << (8 * KBTS_UNICODE_JOINING_TYPE_DUAL)) | + (((1ull << KBTS_UNICODE_JOINING_TYPE_RIGHT) | (1ull << KBTS_UNICODE_JOINING_TYPE_DUAL) | (1ull << KBTS_UNICODE_JOINING_TYPE_FORCE)) << (8 * KBTS_UNICODE_JOINING_TYPE_FORCE)); + + kbts_u64 JoiningFeatureTransition = ((kbts_u64)KBTS_JOINING_FEATURE_INIT << (8 * KBTS_JOINING_FEATURE_ISOL)) | ((kbts_u64)KBTS_JOINING_FEATURE_MEDI << (8 * KBTS_JOINING_FEATURE_FINA)) | + ((kbts_u64)KBTS_JOINING_FEATURE_MEDI << (8 * KBTS_JOINING_FEATURE_MEDI)) | ((kbts_u64)KBTS_JOINING_FEATURE_MED2 << (8 * KBTS_JOINING_FEATURE_MED2)); + + // Tag letters for joining features. + kbts_glyph PreviousGlyph_ = KBTS_ZERO; + kbts_glyph *PreviousGlyph = &PreviousGlyph_; + KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + if(Glyph->JoiningType != KBTS_UNICODE_JOINING_TYPE_TRANSPARENT) + { + Glyph->JoiningFeature = !PreviousGlyph->JoiningType ? KBTS_JOINING_FEATURE_INIT : KBTS_JOINING_FEATURE_FINA; + + if(JoiningTypesMatchLookup & (1ull << (Glyph->JoiningType + 8 * PreviousGlyph->JoiningType))) + { + PreviousGlyph->JoiningFeature = (JoiningFeatureTransition >> (8 * PreviousGlyph->JoiningFeature)) & 0xFF; + PreviousGlyph->Flags = (PreviousGlyph->Flags & ~KBTS_JOINING_FEATURE_MASK) | KBTS_JOINING_FEATURE_TO_GLYPH_FLAG(PreviousGlyph->JoiningFeature); + + Glyph->JoiningFeature = KBTS_JOINING_FEATURE_FINA; + } + else + { + Glyph->JoiningFeature = KBTS_JOINING_FEATURE_ISOL; + } + + if(Glyph->JoiningFeature) + { + // Be careful that this properly maps kbts_joining_feature to KBTS_GLYPH_FLAG! + Glyph->Flags = (Glyph->Flags & ~KBTS_JOINING_FEATURE_MASK) | KBTS_JOINING_FEATURE_TO_GLYPH_FLAG(Glyph->JoiningFeature); + } + + PreviousGlyph = Glyph; + } + } + + S->WrittenCount = GlyphArray->Count; + KBTS_INSTRUMENT_END + } + break; + + case KBTS_OP_KIND_GPOS_METRICS: + { + KBTS_INSTRUMENT_BLOCK_BEGIN("GPOS_METRICS") + // hmtx/vmtx pass. + int ClearMarkAdvances = (Config->Shaper == KBTS_SHAPER_MYANMAR) || (Config->Shaper == KBTS_SHAPER_USE); + kbts_u32 Orientation = KBTS_ORIENTATION_HORIZONTAL; // @Hardcoded + kbts_hea *Hea = Font->Hea[Orientation]; + kbts_u16 *Mtx = Font->Mtx[Orientation]; + + kbts_long_mtx *LongMetrics = 0; + kbts_s16 *ShortMetrics = 0; + if(Hea && Mtx) + { + LongMetrics = (kbts_long_mtx *)Mtx; + ShortMetrics = (kbts_s16 *)(LongMetrics + Hea->MetricCount); + } + + kbts_long_mtx DefaultMetric = {1024, 0}; + if(Font->Head) + { + DefaultMetric.Advance = Font->Head->UnitsPerEm; + if(Orientation == KBTS_ORIENTATION_HORIZONTAL) + { + DefaultMetric.Advance /= 2; + } + } + + KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + kbts_long_mtx Metric = DefaultMetric; + if(LongMetrics) + { + kbts_u32 Id = Glyph->Id; + + // At the end of shaping, default ignorable glyphs that are not generated by GSUB are replaced with zero-width + // whitespace glyphs (or a zero-width empty glyph if no whitespace glyph is present). + // (By the way, we do this because Harfbuzz does it, and Harfbuzz does it probably because Uniscribe does it.) + // We handle this in two steps: + // - The first is here. We want cursive attachments, and mark-to-base attachments, and other relative placements + // to take the zero width into account, and zeroing the width right at the beginning of GPOS is the most + // straighforward way to accomplish this. + // (@Incomplete: It is likely that we also need to take the default ignorable case into account when accumulating + // cursive offsets.) + // - In POST_GPOS_FIXUP, we perform the glyph ID substitution. We have to wait until all GPOS features have been + // executed to do this because they might possibly match the original ID. + if(!(Glyph->Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) && (Glyph->UnicodeFlags & KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE)) + { + Metric.Advance = 0; + Metric.PreviousSideBearing = 0; + } + else if(Id < Hea->MetricCount) + { + Metric = LongMetrics[Id]; + } + else + { + Metric.Advance = LongMetrics[Hea->MetricCount - 1].Advance; + Metric.PreviousSideBearing = ShortMetrics[Id - Hea->MetricCount]; + } + } + + if(!ClearMarkAdvances | (Glyph->Classes.Class != KBTS_GLYPH_CLASS_MARK)) + { + if(Orientation == KBTS_ORIENTATION_HORIZONTAL) + { + // @Cleanup: Why does harfbuzz not take bearings into account in these tests? + // P.X += Metric.PreviousSideBearing; + Glyph->AdvanceX = Metric.Advance; + } + else + { + // @Cleanup: Why does harfbuzz not take bearings into account in these tests? + // P.Y += Metric.PreviousSideBearing; + Glyph->AdvanceY = Metric.Advance; + } + } + } + KBTS_INSTRUMENT_END + } + break; + + case KBTS_OP_KIND_GPOS_FEATURES: + { + KBTS_INSTRUMENT_BLOCK_BEGIN("GPOS_FEATURES") + kbts_gsub_gpos *Gpos = Font->ShapingTables[KBTS_SHAPING_TABLE_GPOS]; + kbts_BeginFeatures(S, Config, KBTS_SHAPING_TABLE_GPOS, Op->Features); + kbts_lookup_list *LookupList = kbts_GetLookupList(Gpos); + kbts_un LookupIndex; + kbts_skip_flags SkipFlags; + kbts_u32 GlyphFilter; + kbts_feature_set LookupFeatures; + while(kbts_NextLookupIndex(S, &LookupIndex, &SkipFlags, &GlyphFilter, &LookupFeatures)) + { + kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, LookupIndex); + kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); + + kbts_un PositionedGlyphCount = 0; + while(PositionedGlyphCount < GlyphArray->Count) + { + kbts_un DeltaGlyphIndex = 1; + + if(kbts_GlyphIncludedInLookup(Config->Font, 1, LookupIndex, GlyphArray->Glyphs[PositionedGlyphCount].Id) && + kbts_ConfigAllowsFeatures(S, Config, Glyphs[PositionedGlyphCount].Config, &LookupFeatures)) + { + KBTS_FOR(SubtableIndex, 0, Lookup.SubtableCount) + { + kbts_u16 *Subtable = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubtableIndex]); + kbts_do_single_adjustment_result Adjustment = kbts_DoSingleAdjustment(Config, LookupList, LookupIndex, SubtableIndex, &Lookup, Subtable, GlyphArray, PositionedGlyphCount, SkipFlags); + if(Adjustment.PerformedAdjustment) + { + DeltaGlyphIndex = Adjustment.PositionedGlyphCount; + break; + } + } + } + + PositionedGlyphCount += DeltaGlyphIndex; + } + } + KBTS_INSTRUMENT_END + } + break; + + case KBTS_OP_KIND_POST_GPOS_FIXUP: + { + KBTS_INSTRUMENT_BLOCK_BEGIN("POST_GPOS_FIXUP") + kbts_un WriteAt = 0; + kbts_glyph WhitespaceGlyph = Config->Whitespace; + int ClearMarkAdvances = kbts_ShaperClearsMarkAdvancesInPostGposFixup(Config->Shaper); + + if(ShapeState->MainDirection != ShapeState->RunDirection) + { + // Flip direction. + // This might seem like a totally superfluous thing to do, because we have to do a bunch + // of work to reverse glyph order while still preserving their relative positions. + // However, for mainly LTR documents, the anchor position will naturally be left-aligned, + // while, in RTL documents, it will naturally right-align. + // As such, going through the glyph sequence and reversing it is needed _anyway_ at some point, + // and we might as well do it here, because this is where we can take resolve attachments + // for relatively cheap, since they are always back-looking. (The next paragraph explains this + // in more detail.) + + // The unintuitive part about this pass is the glyph advances. + // Normally, when iterating over a sequence of glyphs, we see base glyphs before marks. Obviously. + // However, when flipping the sequence, we see the marks before seeing the bases, which means we + // won't have accumulated the base glyph's advance yet! So we have to go through the sequence here + // and compensate for missing advances by precomputing them and baking them into the marks. + // Another way to reach the same result would be to keep marks on the same side as their bases when + // flipping, but that is not what Harfbuzz does, and, the day we decide we want to diverge from Harfbuzz, + // we will very likely be better off not flipping the sequence at all and deleting all of this garbage code. + kbts_s32 MarkAttachAdvanceX = 0; + kbts_s32 MarkAttachAdvanceY = 0; + KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + if(Glyph->AttachGlyphIndexPlusOne) + { + kbts_glyph *Attach = &Glyphs[Glyph->AttachGlyphIndexPlusOne - 1]; + kbts_s32 AttachAdvanceX = MarkAttachAdvanceX; + kbts_s32 AttachAdvanceY = MarkAttachAdvanceY; + if(Attach->Classes.Class != KBTS_GLYPH_CLASS_MARK) + { + AttachAdvanceX = Attach->AdvanceX; + AttachAdvanceY = Attach->AdvanceY; + } + Glyph->OffsetX += AttachAdvanceX; + Glyph->OffsetY += AttachAdvanceY; + MarkAttachAdvanceX = AttachAdvanceX; + MarkAttachAdvanceY = AttachAdvanceY; + } + } + + kbts_un SwapCount = GlyphArray->Count / 2; + KBTS_FOR(LeftIndex, 0, SwapCount) + { + kbts_un RightIndex = GlyphArray->Count - 1 - LeftIndex; + + kbts_glyph SwapGlyph = Glyphs[LeftIndex]; + Glyphs[LeftIndex] = Glyphs[RightIndex]; + Glyphs[RightIndex] = SwapGlyph; + } + } + + // Make default ignorables that weren't explicitly created by the font invisible. + // + // It is tempting to put this loop inside of an if(WhitespaceGlyph.Id), just like we do + // for dotted circle insertion. However, Harfbuzz does not do this! + // When the font does not contain a dotted circle, nothing is inserted, but when the font + // does not contain a whitespace glyph, _we still insert an empty glyph_. + KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) + { + kbts_glyph Glyph = Glyphs[GlyphIndex]; + int Write = 0; + + // It might be tempting to keep glyphs that were used in GPOS, but Harfbuzz doesn't care. + if(!(Glyph.Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) && (Glyph.UnicodeFlags & KBTS_UNICODE_FLAG_DEFAULT_IGNORABLE)) + { + // This glyph is default ignorable and should be ignored. + if(WhitespaceGlyph.Id) + { + Write = 1; + Glyph = WhitespaceGlyph; + } + } + else + { + if(ClearMarkAdvances && (Glyph.Classes.Class == KBTS_GLYPH_CLASS_MARK)) + { + Glyph.AdvanceX = Glyph.AdvanceY = 0; + } + Write = 1; + } + + if(Write) + { + Glyphs[WriteAt++] = Glyph; + } + } + + GlyphArray->Count = (kbts_u32)WriteAt; + GlyphArray->TotalCount = GlyphArray->Count; + KBTS_INSTRUMENT_END + } + break; + + case KBTS_OP_KIND_STCH_POSTPASS: + { + KBTS_FOR(GlyphIndex, 0, GlyphArray->Count) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + if(Glyph->Flags & (KBTS_GLYPH_FLAG_STCH_ENDPOINT | KBTS_GLYPH_FLAG_STCH_EXTENSION)) + { + kbts_un At = GlyphIndex; + + kbts_un ExtensionIndex = At; + kbts_u32 SawExtension = 0; + + kbts_s32 EndpointWidth = 0; + kbts_s32 ExtensionWidth = 0; + + while(At < GlyphArray->Count) + { + kbts_glyph *AtGlyph = &Glyphs[At]; + + if(AtGlyph->Flags & KBTS_GLYPH_FLAG_STCH_ENDPOINT) + { + EndpointWidth += AtGlyph->AdvanceX; + + At += 1; + } + else if(AtGlyph->Flags & KBTS_GLYPH_FLAG_STCH_EXTENSION) + { + ExtensionIndex = At; + ExtensionWidth += AtGlyph->AdvanceX; + SawExtension = 1; + + At += 1; + } + else + { + break; + } + } + + kbts_sn WordWidth = 0; + + while(At < GlyphArray->Count) + { + kbts_glyph *AtGlyph = &Glyphs[At]; + + int Ok = 0; + + if(!(AtGlyph->Flags & (KBTS_GLYPH_FLAG_STCH_ENDPOINT | KBTS_GLYPH_FLAG_STCH_EXTENSION)) && (AtGlyph->UnicodeFlags & KBTS_UNICODE_FLAG_PART_OF_WORD)) + { + Ok = 1; + } + + if(Ok) + { + WordWidth += AtGlyph->AdvanceX; + + At += 1; + } + else + { + break; + } + } + + if(WordWidth > EndpointWidth) + { + kbts_sn ExtensionCount = (WordWidth - EndpointWidth) / ExtensionWidth; + if((ExtensionWidth * ExtensionCount) < (WordWidth - EndpointWidth)) + { + ExtensionCount += 1; + } + + (void)ExtensionCount; + (void)ExtensionIndex; + (void)SawExtension; + /* @Incomplete + kbts_glyph_adjustment *ExtensionAdjustment = &Positions[ExtensionIndex]; + ExtensionAdjustment->LastRepeatIndex = ExtensionCount - 1; + ExtensionAdjustment->RepeatOffsetX = (WordWidth - EndpointWidth - ExtensionWidth) / ExtensionCount; + */ + } + + GlyphIndex = At; + } + } + } + break; + } + + if(Op->Kind < KBTS_OP_KIND_GPOS_METRICS) + { + kbts_un DeltaCount = S->WrittenCount - GlyphArray->Count; + GlyphArray->Count += (kbts_u32)DeltaCount; + GlyphArray->TotalCount += (kbts_u32)DeltaCount; + } + + KBTS_INSTRUMENT_END + return 0; +} + +static kbts_glyph kbts_Substitute1(kbts_shape_state *ShapeState, kbts_lookup_list *LookupList, kbts_feature *Feature, kbts_skip_flags SkipFlags, kbts_glyph *Glyph) +{ + kbts_glyph Result = *Glyph; + + kbts_glyph_array GlyphArray = kbts_GlyphArray(Glyph, 1, 1, 1); + + kbts_iterate_lookups IterateLookups = kbts_IterateLookups(LookupList, Feature); + while(kbts_NextLookup(&IterateLookups)) + { + kbts_gsub_frame Frames[8]; + Frames[0].InputGlyphCount = 1; + kbts_u32 FrameCount = 1; + + while(FrameCount) + { + kbts_substitution_result_flags SubstitutionResult = kbts_DoSubstitution(ShapeState, LookupList, Frames, &FrameCount, &GlyphArray, 0, SkipFlags, 0); + if(SubstitutionResult & KBTS_SUBSTITUTION_RESULT_FLAG_GROW_BUFFER) + { + goto Done; + } + } + } + +Done:; + return Result; +} + +typedef struct kbts_attach_state +{ + kbts_syllabic_position CurrentPosition; + kbts_syllabic_position LastPositionThatWasNotPreBaseMatra; + kbts_indic_syllabic_class LastClass; + kbts_un Start; + kbts_un OnePastLast; +} kbts_attach_state; + +typedef struct kbts_begin_cluster_result +{ + kbts_un ClusterGlyphCount; + kbts_un InsertedGlyphCount; +} kbts_begin_cluster_result; + +static kbts_begin_cluster_result kbts_BeginCluster(kbts_shape_state *ShapeState, kbts_glyph *Glyphs, kbts_un GlyphCount) +{ + kbts_begin_cluster_result Result = KBTS_ZERO; + Result.ClusterGlyphCount = GlyphCount; + kbts_op_state *OpState = &ShapeState->OpState; + kbts_shape_config *Config = ShapeState->Config; + kbts_font *Font = Config->Font; + ShapeState->RealCluster = 0; + + switch(Config->Shaper) + { + case KBTS_SHAPER_INDIC: + { + kbts_lookup_list *LookupList = kbts_GetLookupList(Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]); + + kbts_un OtherCount = 0; + while((OtherCount < GlyphCount) && ((Glyphs[OtherCount].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_OTHER) || (Glyphs[OtherCount].SyllabicClass >= KBTS_INDIC_SYLLABIC_CLASS_COUNT))) + { + ++OtherCount; + } + + if(OtherCount) + { + // Not an Indic syllable. + // Just pass it along. + Result.ClusterGlyphCount = OtherCount; + } + else + { + kbts_un ScanGlyphIndex = 0; + kbts_un State = 0; + kbts_un Broken = 1; + kbts_un BrokenState = 0; + + while((ScanGlyphIndex < GlyphCount) && (State < KBTS_INDIC_SYLLABIC_STATE_COUNT)) + { + kbts_glyph *Glyph = &Glyphs[ScanGlyphIndex]; + kbts_un Class = Glyph->SyllabicClass; + + if(KBTS_IN_SET(Class, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_RA)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT) + (KBTS_INDIC_SYLLABIC_CLASS_VOWEL)(KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE) + (KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER)(KBTS_INDIC_SYLLABIC_CLASS_SYMBOL)))) + { + Broken = 0; + } + BrokenState = (BrokenState << 1) | Broken; + + State = kbts_IndicSyllabicTransition[Class][State]; + State -= 1; // @Incomplete @Cleanup: Decrement every state by 1 in the transition table. + ScanGlyphIndex += 1; + } + + if(State > KBTS_INDIC_SYLLABIC_STATE_COUNT) + { + ScanGlyphIndex -= State - KBTS_INDIC_SYLLABIC_STATE_COUNT; + BrokenState >>= State - KBTS_INDIC_SYLLABIC_STATE_COUNT; + + if(!ScanGlyphIndex) + { + // If we backtrack all the way to the beginning, still eat a character. + ScanGlyphIndex = 1; + } + } + + // NOTE: Symbols, vedics, modifiers, matras have their syllabic positions tagged at build time. + // It is tempting to use Unicode's positional information for consonants, too, but OpenType + // _strongly_ recommends that shapers use the font's tables instead, ie. doing tentative lookups + // with specific features. + + kbts_gsub_frame *Frames = KBTS_POINTER_AFTER(kbts_gsub_frame, OpState); + kbts_glyph *OnePastLastSyllableGlyph = Glyphs + ScanGlyphIndex; + + if((Config->Script == KBTS_SCRIPT_KANNADA) && (ScanGlyphIndex >= 3) && (Glyphs[0].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_RA) && + (Glyphs[1].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && (Glyphs[2].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) + { + // In older versions of Unicode (~4.x, pre-2004), Ra-Virama-Zwj was recommended in Kannada + // to communicate the intent of displaying (Ra + (next consonant as below-base form)). + // This was changed in Unicode 5. Now, the recommended sequence to display (Ra + + // (next consonant as below-base form)) is Ra-Zwj-Virama. + // Since Ra-Virama-Zwj is not a useful sequence that happens organically in Kannada, + // we are free to transform it into Ra-Zwj-Virama here without losing information. + kbts_glyph Swap = Glyphs[1]; + Glyphs[1] = Glyphs[2]; + Glyphs[2] = Swap; + } + + kbts_glyph_flags RephFlags = KBTS_GLYPH_FLAG_RPHF; + kbts_un OnePastRephIndex = 0; + { // Reph tagging. + // This first pass only figures out where the reph ends. + // We delay updating glyph properties until we know whether the reph is the base or not. + kbts_glyph *First = &Glyphs[0]; + kbts_glyph *Second = &Glyphs[1]; + kbts_feature *Rphf = Config->Rphf; + + switch(Config->IndicScriptProperties.RephEncoding) + { + case KBTS_REPH_ENCODING_LOGICAL_REPHA: + if(First->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_REPHA) + { + RephFlags = 0; + OnePastRephIndex = 1; + } + break; + + case KBTS_REPH_ENCODING_IMPLICIT: + if((ScanGlyphIndex >= 2) && (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && kbts_WouldSubstitute(ShapeState, LookupList, Frames, Rphf, 0, Glyphs, 2)) + { + OnePastRephIndex = 2; + } + break; + + case KBTS_REPH_ENCODING_EXPLICIT: + if((ScanGlyphIndex >= 3) && (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && (Glyphs[2].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ) && + kbts_WouldSubstitute(ShapeState, LookupList, Frames, Rphf, 0, Glyphs, 3)) + { + OnePastRephIndex = 3; + } + break; + } + + // Extend the reph with suffixed joiners. + if(OnePastRephIndex) + { + while((OnePastRephIndex < ScanGlyphIndex) && KBTS_IN_SET(Glyphs[OnePastRephIndex].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ)(KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) + { + OnePastRephIndex += 1; + } + } + } + + kbts_feature *Pref = Config->Pref; + kbts_un BaseIndex = ScanGlyphIndex; + kbts_un LastConsonantIndex = 0; + kbts_syllabic_position LastConsonantPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + if(Config->DottedCircle.Id && (BrokenState & 1)) + { + // Insert a dotted circle after Reph. + for(kbts_un GlyphIndex = GlyphCount; GlyphIndex > OnePastRephIndex; --GlyphIndex) + { + Glyphs[GlyphIndex] = Glyphs[GlyphIndex - 1]; + } + ScanGlyphIndex += 1; + Result.InsertedGlyphCount = 1; + + Glyphs[OnePastRephIndex] = Config->DottedCircle; + BaseIndex = OnePastRephIndex; + } + else + { + // Going backwards, tag blwf and pstf consonants until we get to the base. + kbts_glyph Scratch[3]; + Scratch[0] = Config->Virama; + Scratch[2] = Config->Virama; + + kbts_feature *Locl = Config->Locl; + kbts_feature *Vatu = Config->Vatu; + + // pstf forms come last, then blwf. + kbts_feature *SectionFeature = Config->Pstf; + kbts_syllabic_position SectionPosition = KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT; + // If we see no consonant/matra, then surely we want to attach to the base. + kbts_syllabic_position SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + kbts_indic_syllabic_class LastClass = KBTS_INDIC_SYLLABIC_CLASS_COUNT; + + for(kbts_un GlyphIndex = ScanGlyphIndex; GlyphIndex > OnePastRephIndex; --GlyphIndex) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; + kbts_indic_syllabic_class Class = Glyph->SyllabicClass; + + switch(Class) + { + case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT: + case KBTS_INDIC_SYLLABIC_CLASS_RA: + case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER: + case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL: + // Apply locl first. + Scratch[1] = kbts_Substitute1(ShapeState, LookupList, Locl, KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ, Glyph); + + // Microsoft says to "move backwards until a consonant is found that does not have a below-base + // or post-base form". + // As with everything else the spec says, it is wrong. There are cases in which the only consonant + // in a syllable has a below-base or post-base form. In those cases, we still want them to be the + // syllable base. + // So, as we sweep backward, set the base index on consonants unconditionally. + // @Robustness: Do we want to update Base only if we do not match Pref/Vatu? + BaseIndex = GlyphIndex - 1; + + if(kbts_WouldSubstitute(ShapeState, LookupList, Frames, Pref, 0, Scratch, 2) || kbts_WouldSubstitute(ShapeState, LookupList, Frames, Pref, 0, Scratch + 1, 2) || + kbts_WouldSubstitute(ShapeState, LookupList, Frames, Vatu, 0, Scratch, 2) || kbts_WouldSubstitute(ShapeState, LookupList, Frames, Vatu, 0, Scratch + 1, 2)) + { + SyllabicPosition = KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT; + } + else + { + for(;;) + { + if(kbts_WouldSubstitute(ShapeState, LookupList, Frames, SectionFeature, 0, Scratch, 2) || kbts_WouldSubstitute(ShapeState, LookupList, Frames, SectionFeature, 0, Scratch + 1, 2)) + { + SyllabicPosition = SectionPosition; + break; + } + else if(SectionPosition == KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT) + { + SectionFeature = Config->Blwf; + SectionPosition = KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT; + // Retry with Blwf. + } + else + { + goto DoneScanningForBase; + } + } + } + + if(!LastConsonantIndex) + { + LastConsonantIndex = GlyphIndex - 1; + LastConsonantPosition = SyllabicPosition; + } + + Glyph->SyllabicPosition = SyllabicPosition; + break; + + case KBTS_INDIC_SYLLABIC_CLASS_VOWEL: + case KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER: + case KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE: + BaseIndex = GlyphIndex - 1; + goto DoneScanningForBase; + break; + + case KBTS_INDIC_SYLLABIC_CLASS_HALANT: + if(LastClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ) + { + // Explicit half form. + // Since half forms are always before the base, we can safely stop here. + goto DoneScanningForBase; + } + case KBTS_INDIC_SYLLABIC_CLASS_NUKTA: + case KBTS_INDIC_SYLLABIC_CLASS_ZWJ: + case KBTS_INDIC_SYLLABIC_CLASS_ZWNJ: + // @Incomplete: Register Shifter + Glyph->SyllabicPosition = SyllabicPosition; + break; + } + + LastClass = Class; + } + DoneScanningForBase:; + } + + // Fix reph position now. + if(OnePastRephIndex) + { + kbts_syllabic_position RephPosition = KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH; + kbts_glyph_flags Flags = RephFlags; + kbts_un OnePastLast = OnePastRephIndex; + if(BaseIndex == ScanGlyphIndex) + { + RephPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + Flags = 0; + + BaseIndex = 0; + OnePastRephIndex = 0; + } + + KBTS_FOR(GlyphIndex, 0, OnePastLast) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + Glyph->SyllabicPosition = RephPosition; + Glyph->Flags |= Flags; + } + } + + if(BaseIndex < ScanGlyphIndex) + { + Glyphs[BaseIndex].SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + + if(!LastConsonantIndex) + { + LastConsonantIndex = BaseIndex; + // LastConsonantPosition is already set to SYLLABLE_BASE. + } + } + + { // Reorder marks. + // @Cleanup @Speed: Supposedly, NORMALIZE already does this... + kbts_glyph *ReorderGlyph = Glyphs + ScanGlyphIndex - 1; + while(ReorderGlyph >= Glyphs) + { + if(ReorderGlyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_NUKTA) + { + kbts_glyph *Prev = ReorderGlyph - 1; + + while((Prev >= Glyphs) && KBTS_IN_SET(Prev->SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_HALANT)(KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN)))) + { + kbts_glyph Swap = *Prev; + *Prev = Prev[1]; + Prev[1] = Swap; + + Prev -= 1; + } + + ReorderGlyph = Prev; + } + else + { + ReorderGlyph -= 1; + } + } + } + + { // @Temporary @Cleanup + // Left matras should be ordered backwards. + // We want to bake this ordering into our sort, so we increase our syllabic position bits + // and sub-order matras with the low nibble. (There should only be 4 matras tops, anyway.) + kbts_un LeftMatraCount = 0; + KBTS_FOR(GlyphIndex, 0, ScanGlyphIndex) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + Glyph->SyllabicPosition <<= 4; + + if(Glyph->SyllabicPosition == (KBTS_SYLLABIC_POSITION_PREBASE_MATRA << 4)) + { + Glyph->SyllabicPosition += (15 - LeftMatraCount++) & 0xF; + } + } + } + + { // Attach stuff to the right of consonants/matras. + // Pre-base consonants, the base consonant, and matras all have right attachments, + // while post-base consonants have left attachments. + // Since matras always come after all consonants, we try to separate the buffer into three parts: + // a pre-base+base part (right attachments), a post-base consonant part (left attachments), and + // a post-consonant part (right attachments again). + // This part handles right attachments. Left attachments were handled in the base syllable search. + kbts_attach_state States[2] = { + {KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH << 4, KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH << 4, KBTS_INDIC_SYLLABIC_CLASS_COUNT, OnePastRephIndex, BaseIndex}, + {(kbts_u8)(LastConsonantPosition << 4), (kbts_u8)(LastConsonantPosition << 4), KBTS_INDIC_SYLLABIC_CLASS_COUNT, LastConsonantIndex + 1, ScanGlyphIndex}, + }; + kbts_un Iterations = KBTS_MAX(States[0].OnePastLast - States[0].Start, States[1].OnePastLast - States[1].Start); + KBTS_FOR(GlyphIndex, 0, Iterations) + { + KBTS_FOR(StateIndex, 0, KBTS_ARRAY_LENGTH(States)) + { + kbts_attach_state *Attach = &States[StateIndex]; + + if((Attach->Start + GlyphIndex) < Attach->OnePastLast) + { + kbts_glyph *Glyph = &Glyphs[Attach->Start + GlyphIndex]; + kbts_indic_syllabic_class Class = Glyph->SyllabicClass; + switch(Class) + { + case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT: + case KBTS_INDIC_SYLLABIC_CLASS_RA: + case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER: + case KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL: + // This only happens in the pre-base state. + Glyph->SyllabicPosition = (KBTS_SYLLABIC_POSITION_PREBASE_CONSONANT << 4); + Attach->CurrentPosition = (KBTS_SYLLABIC_POSITION_PREBASE_CONSONANT << 4); + break; + + case KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST: + // This specific category (which is composed of a single character) may come after + // a syllable modifier in a sequence like Consonant-SyllableModifier-MatraPost. + // In this very particular case (!), the syllable modifier is attached _to the matra_, + // and not to the consonant. + if(Attach->LastClass == KBTS_INDIC_SYLLABIC_CLASS_SYLLABLE_MODIFIER) + { + Glyph[-1].SyllabicPosition = Glyph->SyllabicPosition; + } + case KBTS_INDIC_SYLLABIC_CLASS_MATRA: + Attach->CurrentPosition = Glyph->SyllabicPosition; + if((Attach->CurrentPosition >> 4) != KBTS_SYLLABIC_POSITION_PREBASE_MATRA) + { + Attach->LastPositionThatWasNotPreBaseMatra = Attach->CurrentPosition; + } + break; + + case KBTS_INDIC_SYLLABIC_CLASS_HALANT: + if((Attach->CurrentPosition >> 4) == KBTS_SYLLABIC_POSITION_PREBASE_MATRA) + { + // Uniscribe does not reorder halants with pre-base matras. Not sure why. + Glyph->SyllabicPosition = Attach->LastPositionThatWasNotPreBaseMatra; + break; + } + case KBTS_INDIC_SYLLABIC_CLASS_NUKTA: + case KBTS_INDIC_SYLLABIC_CLASS_ZWJ: + case KBTS_INDIC_SYLLABIC_CLASS_ZWNJ: + // @Incomplete: Register Shifter + Glyph->SyllabicPosition = Attach->CurrentPosition; + break; + } + Attach->LastClass = Class; + } + } + } + } + + { // Do the sort! + // NOTE: It is important that we sort _now_, because some characters will be reordered across the base from + // where they started, which can change which features will apply to them. + KBTS_FOR(Iteration, 0, ScanGlyphIndex) + { + KBTS_FOR(GlyphIndex, 1, ScanGlyphIndex) + { + kbts_glyph *Left = &Glyphs[GlyphIndex - 1]; + kbts_glyph *Right = &Glyphs[GlyphIndex]; + + if(Left->SyllabicPosition > Right->SyllabicPosition) + { + kbts_glyph Swap = *Left; + *Left = *Right; + *Right = Swap; + + // Make sure we don't lose track of the base... + if(GlyphIndex == BaseIndex) + { + BaseIndex = GlyphIndex - 1; + } + else if((GlyphIndex - 1) == BaseIndex) + { + BaseIndex = GlyphIndex; + } + } + } + } + } + + { // @Temporary @Cleanup + // Revert our syllabic position shift for now. + KBTS_FOR(GlyphIndex, 0, ScanGlyphIndex) + { + Glyphs[GlyphIndex].SyllabicPosition >>= 4; + } + } + + // This is what Harfbuzz does: + + // - NUKT, AKHN, RKRF, VATU, CJCT are active for all characters, but they count ZWJ/ZWNJ in their sequence + // lookups. + // - Note that, by default, Harfbuzz skips ZWJ/ZWNJ in sequence lookups, and selectively disables it for CJCT. + // - Anyway, since these are active for all characters, we don't need flags for them. + + // (RPHF was already handled before sorting.) + + { // All pre-base glyphs get HALF, which is then selectively disabled in front of ZWNJs. + kbts_glyph_flags BaseFlags = 0; + if(!Config->IndicScriptProperties.BlwfPostOnly) + { + BaseFlags = KBTS_GLYPH_FLAG_BLWF; + } + + kbts_indic_syllabic_class LastClass = 0; + for(kbts_un GlyphIndex = BaseIndex; GlyphIndex > 0; --GlyphIndex) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; + kbts_glyph_flags Flags = BaseFlags; + + if(LastClass != KBTS_INDIC_SYLLABIC_CLASS_ZWNJ) + { + Flags |= KBTS_GLYPH_FLAG_HALF; + } + + Glyph->Flags |= Flags; + LastClass = Glyph->SyllabicClass; + } + } + + // All post-base glyphs get BLWF, ABVF, PSTF. Some get PREF. + kbts_glyph Scratch[2]; Scratch[0] = Scratch[1] = KBTS_ZERO_TYPE(kbts_glyph); + kbts_glyph *LastGlyph; LastGlyph = 0; + KBTS_FOR(GlyphIndex, BaseIndex + 1, ScanGlyphIndex) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + // It is tempting to apply PREF to every glyph after the base. + // However, the PREF flag is also used to find the syllable base again in EndCluster, + // so we have to be precise with it. + Scratch[1] = *Glyph; + if(kbts_WouldSubstitute(ShapeState, LookupList, Frames, Pref, 0, Scratch, 2)) + { + LastGlyph->Flags |= KBTS_GLYPH_FLAG_PREF; + Glyph->Flags |= KBTS_GLYPH_FLAG_PREF; + } + + Glyph->Flags |= (KBTS_GLYPH_FLAG_BLWF | KBTS_GLYPH_FLAG_ABVF | KBTS_GLYPH_FLAG_PSTF); + Scratch[0] = Scratch[1]; + LastGlyph = Glyph; + } + + // The base only inherits stuff after it, up to whatever and not including what was grabbed by + // post-base consonants. + if(BaseIndex < ScanGlyphIndex) + { + Glyphs[BaseIndex].SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + + kbts_u64 Classes = (1ull << KBTS_INDIC_SYLLABIC_CLASS_HALANT) | (1ull << KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN) | (1ull << KBTS_INDIC_SYLLABIC_CLASS_NUKTA) | + (1ull << KBTS_INDIC_SYLLABIC_CLASS_ZWJ) | (1ull << KBTS_INDIC_SYLLABIC_CLASS_ZWNJ); + kbts_glyph *Next = &Glyphs[BaseIndex + 1]; + while((Next < OnePastLastSyllableGlyph) && (Next->SyllabicPosition < KBTS_SYLLABIC_POSITION_SYLLABLE_BASE) && ((1ull << Next->SyllabicClass) & Classes)) + { + Next->SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + + Next += 1; + } + } + + Result.ClusterGlyphCount = ScanGlyphIndex; + ShapeState->RealCluster = 1; + } + } + break; + + case KBTS_SHAPER_USE: + { + kbts_un OtherCount = 0; + while((OtherCount < GlyphCount) && ((Glyphs[OtherCount].UseClass == KBTS_USE_SYLLABIC_CLASS_OTHER) || + (Glyphs[OtherCount].UseClass == KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_POST))) + { + OtherCount += 1; + } + + if(OtherCount) + { + Result.ClusterGlyphCount = OtherCount; + } + else + { + // Parse a real cluster. + kbts_u8 State = 0; + kbts_un ScanGlyphIndex = 0; + + while((ScanGlyphIndex < GlyphCount) && (State < KBTS_USE_STATE_s0)) + { + kbts_glyph *Glyph = &Glyphs[ScanGlyphIndex++]; + State = kbts_UseTransition[Glyph->UseClass][State]; + // @Incomplete: Remove this!!! + State -= 1; + } + + if(State >= KBTS_USE_STATE_s0) + { + ScanGlyphIndex -= 1; + } + if((ScanGlyphIndex < GlyphCount) && (Glyphs[ScanGlyphIndex].UseClass == KBTS_USE_SYLLABIC_CLASS_ZWNJ)) + { + ScanGlyphIndex += 1; + } + if(!ScanGlyphIndex) ScanGlyphIndex = 1; + + Result.ClusterGlyphCount = ScanGlyphIndex; + ShapeState->RealCluster = 1; + } + } break; + + case KBTS_SHAPER_KHMER: + { + kbts_un OtherCount = 0; + while((OtherCount < GlyphCount) && ((Glyphs[OtherCount].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_OTHER) || + (Glyphs[OtherCount].SyllabicClass >= KBTS_KHMER_SYLLABIC_CLASS_COUNT))) + { + OtherCount += 1; + } + + if(OtherCount) + { + Result.ClusterGlyphCount = OtherCount; + } + else + { + kbts_u8 State = 0; + kbts_un ScanGlyphIndex = 0; + while((ScanGlyphIndex < GlyphCount) && (State < KBTS_KHMER_SYLLABIC_STATE_COUNT)) + { + kbts_glyph *Glyph = &Glyphs[ScanGlyphIndex++]; + kbts_indic_syllabic_class Class = Glyph->SyllabicClass; + + State = kbts_KhmerSyllabicTransition[Class][State]; + // @Incomplete: Remove this! + State -= 1; + } + + if(State >= KBTS_KHMER_SYLLABIC_STATE_COUNT) + { + ScanGlyphIndex -= 1; + } + if(!ScanGlyphIndex) ScanGlyphIndex = 1; + + if(Config->DottedCircle.Id && + !KBTS_IN_SET64(Glyphs->SyllabicClass, KBTS_SET64((KBTS_INDIC_SYLLABIC_CLASS_CONSONANT)(KBTS_INDIC_SYLLABIC_CLASS_RA) + (KBTS_INDIC_SYLLABIC_CLASS_VOWEL)(KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE) + (KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER)))) + { + // Broken cluster. + // Insert a dotted circle. + for(kbts_un GlyphIndex = GlyphCount; GlyphIndex; --GlyphIndex) + { + Glyphs[GlyphIndex] = Glyphs[GlyphIndex - 1]; + } + ScanGlyphIndex += 1; + Result.InsertedGlyphCount = 1; + Glyphs[0] = Config->DottedCircle; + } + + // In Khmer, the first glyph is always the base. + + kbts_glyph PreBaseGlyphs[3]; + int SawHalantRa = 0; + kbts_un PreBaseGlyphCount = 0; + kbts_un Classes = 0; + kbts_un WriteCursor = ScanGlyphIndex - 1; + for(kbts_un GlyphIndex = ScanGlyphIndex; GlyphIndex; --GlyphIndex) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; + kbts_indic_syllabic_class Class = Glyph->SyllabicClass; + + if(GlyphIndex > 1) {Glyph->Flags |= KBTS_GLYPH_FLAG_ABVF | KBTS_GLYPH_FLAG_BLWF | KBTS_GLYPH_FLAG_PSTF;} + + Classes = ((Classes << 8) | Class) & 0xFFFF; + + if(Class == KBTS_INDIC_SYLLABIC_CLASS_VOWEL_PRE) + { + PreBaseGlyphs[PreBaseGlyphCount++] = *Glyph; + } + else if(!SawHalantRa && (Classes == (KBTS_INDIC_SYLLABIC_CLASS_HALANT | (KBTS_INDIC_SYLLABIC_CLASS_RA << 8)))) + { + kbts_glyph *Ra = &Glyphs[GlyphIndex]; + Glyph->Flags |= KBTS_GLYPH_FLAG_PREF; + Ra->Flags |= KBTS_GLYPH_FLAG_PREF; + + PreBaseGlyphs[PreBaseGlyphCount++] = *Glyph; + PreBaseGlyphs[PreBaseGlyphCount++] = *Ra; + WriteCursor += 1; // Cancel the Ra write. + // All of the glyphs written so far need to be flagged with cfar. + KBTS_FOR(CfarGlyphIndex, WriteCursor, ScanGlyphIndex) + { + Glyphs[CfarGlyphIndex].Flags |= KBTS_GLYPH_FLAG_CFAR; + } + SawHalantRa = 1; + } + else + { + Glyphs[WriteCursor--] = *Glyph; + } + } + + KBTS_FOR(PreBaseGlyphIndex, 0, PreBaseGlyphCount) + { + Glyphs[PreBaseGlyphIndex] = PreBaseGlyphs[PreBaseGlyphIndex]; + } + + Result.ClusterGlyphCount = ScanGlyphIndex; + } + } break; + + case KBTS_SHAPER_MYANMAR: + { + kbts_un OtherCount = 0; + while((OtherCount < GlyphCount) && ((Glyphs[OtherCount].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_OTHER) || + (Glyphs[OtherCount].SyllabicClass >= KBTS_MYANMAR_SYLLABIC_CLASS_COUNT))) + { + OtherCount += 1; + } + + if(OtherCount) + { + Result.ClusterGlyphCount = OtherCount; + } + else + { + kbts_u8 State = 0; + kbts_un ScanGlyphIndex = 0; + while((ScanGlyphIndex < GlyphCount) && (State < KBTS_MYANMAR_SYLLABIC_STATE_COUNT)) + { + kbts_glyph *Glyph = &Glyphs[ScanGlyphIndex++]; + kbts_indic_syllabic_class Class = Glyph->SyllabicClass; + + State = kbts_MyanmarSyllabicTransition[Class][State]; + // @Incomplete: Remove this! + State -= 1; + } + + if(State >= KBTS_MYANMAR_SYLLABIC_STATE_COUNT) + { + ScanGlyphIndex -= 1; + } + if(!ScanGlyphIndex) ScanGlyphIndex = 1; + + ShapeState->RealCluster = 1; + Result.ClusterGlyphCount = ScanGlyphIndex; + } + } break; + } + + return Result; +} + +typedef struct kbts_end_cluster_result +{ + int InsertDottedCircle; + kbts_un DottedCircleIndex; +} kbts_end_cluster_result; + +static kbts_end_cluster_result kbts_EndCluster(kbts_shape_state *ShapeState, kbts_glyph_array *Cluster) +{ + kbts_end_cluster_result Result = KBTS_ZERO; + kbts_shape_config *Config = ShapeState->Config; + kbts_glyph *Glyphs = Cluster->Glyphs; + kbts_un GlyphCount = Cluster->Count; + + switch(Config->Shaper) + { + case KBTS_SHAPER_INDIC: + if(GlyphCount > 1) + { + // Final syllable reordering. + // We are just copying Harfbuzz here, because I've read all the documentation I can and, frankly, I have no idea. + kbts_feature *Pref = Config->Pref; + + kbts_u32 ViramaId = Config->Virama.Id; + KBTS_FOR(GlyphIndex, 0, GlyphCount) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + // Harfbuzz tests for (ligated | multiplied) here. + // I don't really get why, because, supposedly, all viramas should be + // classified as halants regardless. + if(ViramaId && (Glyph->Id == ViramaId)) + { + Glyph->SyllabicClass = KBTS_INDIC_SYLLABIC_CLASS_HALANT; + Glyph->Flags &= ~(KBTS_GLYPH_FLAG_LIGATURE | KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION); + } + else if(Glyph->Flags & KBTS_GLYPH_FLAG_LIGATURE) + { + // We can't know the syllabic classes of ligatures for sure. + Glyph->SyllabicClass = KBTS_INDIC_SYLLABIC_CLASS_COUNT; + } + } + + // Locate the syllable base. + kbts_un BaseIndex = GlyphCount; + { + kbts_un AfterPreBaseIndex = 0; + while((AfterPreBaseIndex < GlyphCount) && (Glyphs[AfterPreBaseIndex].SyllabicPosition < KBTS_SYLLABIC_POSITION_SYLLABLE_BASE)) + { + ++AfterPreBaseIndex; + } + + if(AfterPreBaseIndex < GlyphCount) + { + BaseIndex = AfterPreBaseIndex; + + if(Pref && ((AfterPreBaseIndex + 1) < GlyphCount)) + { + // If we find a pre-base-reordering ra, then the base is probably right after it! + kbts_un At = AfterPreBaseIndex + 1; + while((At < GlyphCount) && !(Glyphs[At].Flags & KBTS_GLYPH_FLAG_PREF)) + { + ++At; + } + + // If we are not a consonant, then we are attached to a consonant. + // If we are a pref-able consonant, but we did not form a pref, then we should be right after the base. + // Either way, we are very close to the base. + kbts_glyph *Prefable = &Glyphs[At]; + if((At < GlyphCount) && + (!(Prefable->Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) || !(Prefable->Flags & KBTS_GLYPH_FLAG_LIGATURE) || (Prefable->Flags & KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION))) + { + while((At < GlyphCount) && (Prefable->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) + { + ++At; + ++Prefable; + } + + if(At < GlyphCount) + { + Prefable->SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + BaseIndex = At; + // Fall through to the Malayalam test. + } + } + } + + if(Config->Script == KBTS_SCRIPT_MALAYALAM) + { + // In Malayalam, the base is after below-base forms. + // (We actually just give all below-base forms the base pos.) + // @Speed: This would be way simpler with a null sentinel at the end of Glyphs! + kbts_un At = BaseIndex + 1; + while(At < GlyphCount) + { + while((At < GlyphCount) && KBTS_IN_SET(Glyphs[At].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ)(KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) + { + ++At; + } + + if((At < GlyphCount) && (Glyphs[At].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) + { + ++At; + } + else + { + break; + } + + while((At < GlyphCount) && KBTS_IN_SET(Glyphs[At].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ)(KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) + { + ++At; + } + + if(At < GlyphCount) + { + kbts_glyph *Glyph = &Glyphs[At]; + if(kbts_SyllabicClassIsConsonant(Glyph->SyllabicClass) && (Glyph->SyllabicPosition == KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT)) + { + Glyph->SyllabicPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + BaseIndex = At; + // Do not break; keep matching below-base forms. + } + } + } + } + } + + if(BaseIndex && (BaseIndex < GlyphCount) && (Glyphs[BaseIndex].SyllabicPosition > KBTS_SYLLABIC_POSITION_SYLLABLE_BASE)) + { + BaseIndex -= 1; + } + + if((BaseIndex == GlyphCount) && (Glyphs[GlyphCount - 1].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) + { + BaseIndex = GlyphCount - 1; + } + + if(BaseIndex < GlyphCount) + { + while(BaseIndex && KBTS_IN_SET(Glyphs[BaseIndex].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_NUKTA)(KBTS_INDIC_SYLLABIC_CLASS_HALANT)))) + { + BaseIndex -= 1; + } + } + } + + // Reorder matras. + if(BaseIndex && (GlyphCount > 1)) + { + kbts_un ToIndex = BaseIndex - 1; + if(BaseIndex == GlyphCount) + { + ToIndex = GlyphCount - 2; + } + + if((Config->Script != KBTS_SCRIPT_MALAYALAM) && (Config->Script != KBTS_SCRIPT_TAMIL)) + { + for(;;) + { + while(ToIndex && !KBTS_IN_SET(Glyphs[ToIndex].SyllabicClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_MATRA)(KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST)(KBTS_INDIC_SYLLABIC_CLASS_HALANT)))) + { + --ToIndex; + } + + kbts_glyph *Glyph = &Glyphs[ToIndex]; + if((Glyph->SyllabicClass != KBTS_INDIC_SYLLABIC_CLASS_HALANT) || (Glyph->SyllabicPosition == KBTS_SYLLABIC_POSITION_PREBASE_MATRA)) + { + // We have nothing to move. + ToIndex = 0; + + break; + } + else if(ToIndex && ((ToIndex + 1) < GlyphCount) && (Glyphs[ToIndex + 1].SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ)) + { + // Zwj+Halant cancels matra movement when the Halant is not attached to the matra. + --ToIndex; + } + else + { + break; + } + } + } + + if(ToIndex && (Glyphs[ToIndex].SyllabicPosition != KBTS_SYLLABIC_POSITION_PREBASE_MATRA)) + { + for(kbts_un MatraIndex = ToIndex; MatraIndex; --MatraIndex) + { + kbts_glyph *Matra = &Glyphs[MatraIndex - 1]; + + if(Matra->SyllabicPosition == KBTS_SYLLABIC_POSITION_PREBASE_MATRA) + { + kbts_glyph MatraToReorder = *Matra; + + KBTS_FOR(GlyphIndex, MatraIndex, ToIndex + 1) + { + Glyphs[GlyphIndex - 1] = Glyphs[GlyphIndex]; + } + + Glyphs[ToIndex] = MatraToReorder; + ToIndex -= 1; + } + } + } + } + + // Reorder reph. + // We should only reorder reph when it is a single Repha glyph, and not a Ra sequence. + if((Glyphs[0].SyllabicPosition == KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH) && (Glyphs[1].SyllabicPosition != KBTS_SYLLABIC_POSITION_RA_TO_BECOME_REPH)) + { + kbts_reph_position RephPosition = Config->IndicScriptProperties.RephPosition; + + kbts_un ToIndex = 0; + + KBTS_FOR(GlyphIndex, 0, BaseIndex) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + if(Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) + { + ToIndex = GlyphIndex; + + if((GlyphIndex + 1) < BaseIndex) + { + kbts_u8 NextClass = Glyphs[GlyphIndex + 1].SyllabicClass; + + if((NextClass == KBTS_INDIC_SYLLABIC_CLASS_ZWJ) || (NextClass == KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)) + { + ToIndex = GlyphIndex + 1; + } + } + + break; + } + } + + if(!ToIndex) + { + if(RephPosition == KBTS_REPH_POSITION_AFTER_SUBJOINED) + { + KBTS_FOR(GlyphIndex, BaseIndex, GlyphCount) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + kbts_u8 SyllabicPosition = Glyph->SyllabicPosition; + + if(KBTS_IN_SET(SyllabicPosition, KBTS_SET32((KBTS_SYLLABIC_POSITION_POSTBASE_CONSONANT)(KBTS_SYLLABIC_POSITION_AFTER_POST)(KBTS_SYLLABIC_POSITION_SMVD)))) + { + ToIndex = GlyphIndex - 1; + + break; + } + } + } + else if(RephPosition == KBTS_REPH_POSITION_AFTER_MAIN) + { + KBTS_FOR(GlyphIndex, BaseIndex, GlyphCount) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + if(Glyph->SyllabicPosition > KBTS_SYLLABIC_POSITION_AFTER_MAIN) + { + ToIndex = GlyphIndex - 1; + + break; + } + } + } + } + + if(!ToIndex) + { + // As a fallback, move reph to the end of the syllable. + for(kbts_un GlyphIndex = GlyphCount; GlyphIndex; --GlyphIndex) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; + + if(Glyph->SyllabicPosition != KBTS_SYLLABIC_POSITION_SMVD) + { + ToIndex = GlyphIndex - 1; + + break; + } + } + + // Matras will still come after reph. + kbts_glyph *Glyph = &Glyphs[ToIndex]; + if(Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) + { + KBTS_FOR(MatraIndex, BaseIndex + 1, ToIndex) + { + kbts_glyph *Matra = &Glyphs[MatraIndex]; + kbts_u8 Class = Matra->SyllabicClass; + + if(KBTS_IN_SET(Class, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_MATRA)(KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL)))) + { + ToIndex -= 1; + } + } + } + } + + if(ToIndex) + { + // Do the reorder! + kbts_glyph Reph = Glyphs[0]; + + KBTS_FOR(GlyphIndex, 0, ToIndex) + { + Glyphs[GlyphIndex] = Glyphs[GlyphIndex + 1]; + } + + Glyphs[ToIndex] = Reph; + + if(BaseIndex && (BaseIndex <= ToIndex)) + { + BaseIndex -= 1; + } + } + } + + // Reorder pre-base-reordering consonants. + if(Pref) + { + kbts_un PrefIndex = 0; + + KBTS_FOR(GlyphIndex, BaseIndex + 1, GlyphCount) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + if(Glyph->Flags & KBTS_GLYPH_FLAG_PREF) + { + PrefIndex = GlyphIndex; + + break; + } + } + + if(PrefIndex) + { + kbts_glyph PrefGlyph = Glyphs[PrefIndex]; + + // Harfbuzz says the ideal is to check that this glyph was generated by the pref feature specifically, + // but then just uses a generic flag like this. + // The ideal solution would not be very difficult to implement! + if(PrefGlyph.Flags & KBTS_GLYPH_FLAG_GENERATED_BY_GSUB) + { + kbts_un ToIndex = 0; + + for(kbts_un GlyphIndex = BaseIndex; GlyphIndex; --GlyphIndex) + { + kbts_u8 Class = Glyphs[GlyphIndex - 1].SyllabicClass; + + if(KBTS_IN_SET(Class, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_MATRA)(KBTS_INDIC_SYLLABIC_CLASS_MATRA_POST)(KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_MEDIAL)(KBTS_INDIC_SYLLABIC_CLASS_HALANT)))) + { + ToIndex = GlyphIndex; + + break; + } + } + + if(ToIndex && (ToIndex < GlyphCount)) + { + kbts_glyph *Prev = &Glyphs[ToIndex - 1]; + kbts_u8 CurrentClass = Glyphs[ToIndex].SyllabicClass; + + if((Prev->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT) && KBTS_IN_SET(CurrentClass, KBTS_SET32((KBTS_INDIC_SYLLABIC_CLASS_ZWJ)(KBTS_INDIC_SYLLABIC_CLASS_ZWNJ)))) + { + ToIndex += 1; + } + } + + // Do the reorder! + for(kbts_un GlyphIndex = PrefIndex; GlyphIndex > ToIndex; --GlyphIndex) + { + Glyphs[GlyphIndex] = Glyphs[GlyphIndex - 1]; + } + + Glyphs[ToIndex] = PrefGlyph; + + // @Cleanup: This is probably always true? + if((BaseIndex >= ToIndex) && (BaseIndex < PrefIndex)) + { + BaseIndex += 1; + } + } + } + } + + { // Mark matras at the beginning of a word for init application. + // It is tempting to check for this at the same time as the reph reordering, but glyphs could have been + // reordered since then and the reordering procedure is clearly defined to happen in sequential steps. + kbts_glyph *First = &Glyphs[0]; + + if((First->SyllabicPosition == KBTS_SYLLABIC_POSITION_PREBASE_MATRA) && ShapeState->ClusterAtStartOfWord) + { + First->Flags |= KBTS_GLYPH_FLAG_INIT; + } + } + } + break; + + case KBTS_SHAPER_USE: + { + kbts_u64 PostBaseSet = KBTS_SET64((KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_ABOVE)(KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_BELOW) + (KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_ABOVE)(KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_BELOW) + (KBTS_USE_SYLLABIC_CLASS_CONS_FINAL_MOD_POST)(KBTS_USE_SYLLABIC_CLASS_CONS_MED_ABOVE) + (KBTS_USE_SYLLABIC_CLASS_CONS_MED_BELOW)(KBTS_USE_SYLLABIC_CLASS_CONS_MED_POST) + (KBTS_USE_SYLLABIC_CLASS_CONS_MED_PRE)(KBTS_USE_SYLLABIC_CLASS_VOWEL_ABOVE) + (KBTS_USE_SYLLABIC_CLASS_VOWEL_BELOW)(KBTS_USE_SYLLABIC_CLASS_VOWEL_POST) + (KBTS_USE_SYLLABIC_CLASS_VOWEL_PRE)(KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_ABOVE) + (KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_BELOW)(KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_POST) + (KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_PRE)); + kbts_u64 HalantSet = KBTS_SET64((KBTS_USE_SYLLABIC_CLASS_HALANT)(KBTS_USE_SYLLABIC_CLASS_HALANT_OR_VOWEL_MODIFIER)(KBTS_USE_SYLLABIC_CLASS_INVISIBLE_STACKER)); + + // In the reorderings below, we check for halants because that's what Harfbuzz does. + // Nowhere does Microsoft mention that halants should block reorderings! + kbts_glyph Repha = Glyphs[0]; + if((Repha.UseClass == KBTS_USE_SYLLABIC_CLASS_REPHA) || (Repha.Flags & KBTS_GLYPH_FLAG_RPHF)) + { + kbts_un GlyphIndex = 1; + for(; GlyphIndex < GlyphCount; ++GlyphIndex) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + + // Microsoft says that rephas are reordered "after a following full base", which is needlessly vague. + // Harfbuzz reorders them in front of the first post-base glyph. + if(KBTS_IN_SET64(Glyph->UseClass, PostBaseSet) || (!(Glyph->Flags & KBTS_GLYPH_FLAG_LIGATURE) && KBTS_IN_SET64(Glyph->UseClass, HalantSet))) + { + break; + } + + Glyphs[GlyphIndex - 1] = *Glyph; + } + + Glyphs[GlyphIndex - 1] = Repha; + } + + { + // Microsoft says that pre-base vowels and vowel modifiers should be reordered "before the base glyph + // and, if present, before a pre-base glyph reordered via the 'pref' feature". + // In practice, we tag 'pref'-generated glyphs with the VOWEL_PRE class so that they get reordered here. + // Note that the final reordered glyphs end up backwards from their original order. + kbts_glyph PreBaseVowels[16]; // @Robustness: How many vowels can there realistically be in a single cluster? + kbts_un PreBaseVowelCount = 0; + kbts_u64 SawBase = 0; + for(kbts_un GlyphIndex = GlyphCount; GlyphIndex; --GlyphIndex) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex - 1]; + SawBase |= KBTS_IN_SET64(Glyph->UseClass, KBTS_SET64((KBTS_USE_SYLLABIC_CLASS_BASE)(KBTS_USE_SYLLABIC_CLASS_BASE_OTHER)(KBTS_USE_SYLLABIC_CLASS_BASE_NUM))); + + kbts_u32 Flags = Glyph->Flags; + // Only accept the first glyphs produced by multiple substitutions. + if(((Flags & KBTS_GLYPH_FLAG_FIRST_IN_MULTIPLE_SUBSTITUTION) || !(Flags & KBTS_GLYPH_FLAG_MULTIPLE_SUBSTITUTION)) && + (KBTS_IN_SET64(Glyph->UseClass, KBTS_SET64((KBTS_USE_SYLLABIC_CLASS_VOWEL_PRE)(KBTS_USE_SYLLABIC_CLASS_VOWEL_MOD_PRE))) || + (Flags & KBTS_GLYPH_FLAG_PREF))) + { + if(PreBaseVowelCount < KBTS_ARRAY_LENGTH(PreBaseVowels)) + { + PreBaseVowels[PreBaseVowelCount++] = *Glyph; + } + } + else if(!(Glyph->Flags & KBTS_GLYPH_FLAG_LIGATURE) && KBTS_IN_SET64(Glyph->UseClass, HalantSet)) + { + // Reordering stops at halants, apparently. + // We want to write the vowels in the reverse order they appear in the glyph sequence. + // Since we are iterating backwards, they already _are_ backwards in the PreBaseVowels array, + // so there's no need to do anything. + KBTS_FOR(PreBaseVowelIndex, 0, PreBaseVowelCount) + { + Glyphs[GlyphIndex + PreBaseVowelIndex] = PreBaseVowels[PreBaseVowelIndex]; + } + PreBaseVowelCount = 0; + + // Valid bases only show up before halants. + SawBase = 0; + } + else + { + Glyphs[GlyphIndex - 1 + PreBaseVowelCount] = *Glyph; + } + } + + // Flush the rest of the vowels. + KBTS_FOR(PreBaseVowelIndex, 0, PreBaseVowelCount) + { + Glyphs[PreBaseVowelIndex] = PreBaseVowels[PreBaseVowelIndex]; + } + + // We are supposed to insert a dotted circle after repha when a base is missing. + // The issue is that we have no idea whether the first glyph is a repha or not before we apply + // RPHF. + // So, this is really sucky, but I haven't found a way to merge this logic into any already- + // existing loop, so we have to eat the extra traversal for now. + if(ShapeState->RealCluster && !SawBase) + { + Result.InsertDottedCircle = 1; + Result.DottedCircleIndex = PreBaseVowelCount; + } + } + } break; + + case KBTS_SHAPER_MYANMAR: + if(ShapeState->RealCluster) + { + kbts_un OnePastRephIndex = 0; + kbts_un BaseIndex = GlyphCount; + if(GlyphCount >= 3) + { + kbts_glyph *First = &Glyphs[0]; + kbts_glyph *Second = &Glyphs[1]; + kbts_glyph *Third = &Glyphs[2]; + + if((First->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_RA) && + (Second->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_ASAT) && + (Third->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_HALANT)) + { + First->SyllabicPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; + Second->SyllabicPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; + Third->SyllabicPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; + + OnePastRephIndex = 3; + BaseIndex = 0; + } + } + + kbts_u64 BaseSet = KBTS_SET64((KBTS_INDIC_SYLLABIC_CLASS_CONSONANT) + (KBTS_INDIC_SYLLABIC_CLASS_CONSONANT_WITH_STACKER) + (KBTS_INDIC_SYLLABIC_CLASS_RA) + (KBTS_INDIC_SYLLABIC_CLASS_VOWEL) + (KBTS_INDIC_SYLLABIC_CLASS_PLACEHOLDER) + (KBTS_INDIC_SYLLABIC_CLASS_DOTTED_CIRCLE)); + KBTS_FOR(GlyphIndex, OnePastRephIndex, GlyphCount) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + kbts_indic_syllabic_class Class = Glyph->SyllabicClass; + + if((BaseIndex == GlyphCount) && KBTS_IN_SET64(Class, BaseSet)) + { + BaseIndex = GlyphIndex; + break; + } + } + + if((BaseIndex == GlyphCount) && OnePastRephIndex) + { + BaseIndex = 0; + } + + kbts_syllabic_position LastPosition = KBTS_SYLLABIC_POSITION_SYLLABLE_BASE; + kbts_syllabic_position SectionPosition = KBTS_SYLLABIC_POSITION_AFTER_MAIN; + kbts_un LastPreBaseMatraIndex = GlyphCount; + KBTS_FOR(GlyphIndex, BaseIndex + 1, GlyphCount) + { + kbts_glyph *Glyph = &Glyphs[GlyphIndex]; + kbts_syllabic_position Position = SectionPosition; + + switch(Glyph->SyllabicClass) + { + case KBTS_INDIC_SYLLABIC_CLASS_MEDIAL_RA: + Position = KBTS_SYLLABIC_POSITION_PREBASE_CONSONANT; + break; + + case KBTS_INDIC_SYLLABIC_CLASS_VOWEL_PRE: + { + Position = KBTS_SYLLABIC_POSITION_PREBASE_MATRA; + + // According to Unicode 15.0: + // For combining characters placed to the left of a base character, the combining characters start from the base + // character and are arranged leftward. + // Since these guys will get reordered into being pre-base, we need to flip them. + if(GlyphIndex > LastPreBaseMatraIndex) + { + kbts_un FlipCount = GlyphIndex - LastPreBaseMatraIndex + 1; + KBTS_FOR(FlipIndex, 0, FlipCount / 2) + { + kbts_un LeftIndex = LastPreBaseMatraIndex + FlipIndex; + kbts_un RightIndex = LastPreBaseMatraIndex + FlipCount - 1 - FlipIndex; + kbts_glyph Swap = Glyphs[LeftIndex]; + Glyphs[LeftIndex] = Glyphs[RightIndex]; + Glyphs[RightIndex] = Swap; + } + + // Readjust Glyph to compensate for the flip. + Glyph = &Glyphs[LastPreBaseMatraIndex]; + } + + LastPreBaseMatraIndex = GlyphIndex; + } break; + + case KBTS_INDIC_SYLLABIC_CLASS_VARIATION_SELECTOR: + Position = LastPosition; + break; + + case KBTS_INDIC_SYLLABIC_CLASS_VOWEL_BELOW: + if(Position == KBTS_SYLLABIC_POSITION_AFTER_MAIN) + { + Position = KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT; + } + else if(Position == KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT) + { + Position = SectionPosition; + } + break; + + case KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN: + if(Position == KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT) + { + Position = KBTS_SYLLABIC_POSITION_BEFORE_SUBJOINED; + } + break; + } + + if((SectionPosition == KBTS_SYLLABIC_POSITION_BELOWBASE_CONSONANT) && (Glyph->SyllabicClass == KBTS_INDIC_SYLLABIC_CLASS_VEDIC_SIGN)) + { + SectionPosition = KBTS_SYLLABIC_POSITION_AFTER_SUBJOINED; + Position = SectionPosition; + } + + Glyph->SyllabicPosition = Position; + LastPosition = Position; + } + + KBTS_FOR(Iter, 1, GlyphCount) + { + KBTS_FOR(GlyphIndex, 1, GlyphCount) + { + kbts_glyph *A = &Glyphs[GlyphIndex - 1]; + kbts_glyph *B = &Glyphs[GlyphIndex]; + + if(A->SyllabicPosition > B->SyllabicPosition) + { + kbts_glyph Swap = *A; + *A = *B; + *B = Swap; + } + } + } + } break; + } + + return Result; +} + +static kbts_op_list kbts_OpList(kbts_u8 *Ops, kbts_un Size) +{ + kbts_op_list Result = KBTS_ZERO; + Result.Ops = Ops; + Result.Length = Size; + return Result; +} +#define KBTS_OP_LIST(OpList) kbts_OpList((kbts_Ops_##OpList), KBTS_ARRAY_LENGTH(kbts_Ops_##OpList)) + +KBTS_EXPORT kbts_shape_config kbts_ShapeConfig(kbts_font *Font, kbts_script Script, kbts_language Language) +{ + kbts_shape_config Result = KBTS_ZERO; + + Result.Font = Font; + Result.Script = Script; + Result.Language = Language; + + kbts_gsub_gpos *Gsub = Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]; + + // Find the appropriate language system in GSUB/GPOS. + kbts_script_properties *ScriptProperties = &kbts_ScriptProperties[Script]; + int FoundScriptIsIndic3 = 0; + + KBTS_FOR(ShapingTableIndex, 0, KBTS_SHAPING_TABLE_COUNT) + { + kbts_gsub_gpos *ShapingTable = Font->ShapingTables[ShapingTableIndex]; + if(ShapingTable) + { + kbts_script_list *ScriptList = KBTS_POINTER_OFFSET(kbts_script_list, ShapingTable, ShapingTable->ScriptListOffset); + + kbts_langsys *ChosenLangsys = 0; + kbts_u32 DesiredTag = ScriptProperties->Tag; + + KBTS_FOR(ScriptIndex, 0, ScriptList->Count) + { + kbts_script_pointer ThisScript = kbts_GetScript(ScriptList, ScriptIndex); + kbts_u32 Tag = ThisScript.Tag; + + // The OpenType spec does not define or even mention "Indic3" scripts at all. + // Nevertheless, Harfbuzz at least checks for '3' at the end of script tags, and, if one exists, they choose USE. + int Indic3 = (ThisScript.Tag >> 24) == '3'; + kbts_u32 MatchMask = Indic3 ? 0xFFFFFF : 0xFFFFFFFF; + int PerfectMatch = !((Tag ^ DesiredTag) & MatchMask); + if(!ScriptIndex || PerfectMatch || (Tag == KBTS_FOURCC('D', 'F', 'L', 'T'))) + { + kbts_langsys *Langsys = kbts_GetDefaultLangsys(ThisScript.Script); + KBTS_FOR(LangsysIndex, 0, ThisScript.Script->Count) + { + kbts_langsys_pointer LangsysPointer = kbts_GetLangsys(ThisScript.Script, LangsysIndex); + + if(LangsysPointer.Tag == Language) + { + Langsys = LangsysPointer.Langsys; + break; + } + } + + // It is tempting to try to look for another script if the one we want has no langsys. + // However, it is possible for a script to purposefully have no langsys at all. In that case, + // the shaper should not apply any GSUB features. + // In that case, the shaper should not apply any GSUB features. + // So, store the result _regardless_ of whether Langsys is null or not. + ChosenLangsys = Langsys; + if(ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) + { + // Apparently, it is allowed to have script-specific GSUB tables, and a huge DFLT GPOS table. + FoundScriptIsIndic3 = Indic3; + } + // And then get out if we found the appropriate script, even if the langsys is null! + if(PerfectMatch) + { + break; + } + } + } + + Result.Langsys[ShapingTableIndex] = ChosenLangsys; + } + } + + Result.IndicScriptProperties = kbts_IndicScriptProperties(Script); + Result.Shaper = FoundScriptIsIndic3 ? KBTS_SHAPER_USE : ScriptProperties->Shaper; + Result.OpLists[0] = kbts_ShaperOpLists[Result.Shaper]; + + switch(Result.Shaper) + { + case KBTS_SHAPER_INDIC: + Result.OpLists[1] = KBTS_OP_LIST(Indic1); + Result.OpLists[2] = KBTS_OP_LIST(Indic2); + Result.OpLists[3] = KBTS_OP_LIST(Indic3); + break; + case KBTS_SHAPER_USE: + Result.OpLists[1] = KBTS_OP_LIST(Use1); + Result.OpLists[3] = KBTS_OP_LIST(Use3); + break; + case KBTS_SHAPER_KHMER: + Result.OpLists[1] = KBTS_OP_LIST(Khmer1); + Result.OpLists[3] = KBTS_OP_LIST(Khmer3); + break; + case KBTS_SHAPER_MYANMAR: + Result.OpLists[1] = KBTS_OP_LIST(Myanmar1); + Result.OpLists[2] = KBTS_OP_LIST(Myanmar2); + Result.OpLists[3] = KBTS_OP_LIST(Myanmar3); + break; + } + + Result.Features = &kbts_ShaperFeatures[Result.Shaper]; + + kbts_feature *Rclt = 0; + kbts_feature_set SyllableFeatureSet = {{KBTS_FEATURE_FLAG0(rphf) | KBTS_FEATURE_FLAG0(blwf) | KBTS_FEATURE_FLAG0(half) | KBTS_FEATURE_FLAG0(pstf) | KBTS_FEATURE_FLAG0(pref), + 0, KBTS_FEATURE_FLAG2(rclt) | KBTS_FEATURE_FLAG2(locl), KBTS_FEATURE_FLAG3(vatu)}}; + kbts_iterate_features IterateFeatures = kbts_IterateFeatures(&Result, KBTS_SHAPING_TABLE_GSUB, SyllableFeatureSet); + while(kbts_NextFeature(&IterateFeatures)) + { + switch(IterateFeatures.CurrentFeatureTag) + { + case KBTS_FEATURE_TAG_blwf: Result.Blwf = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_pref: Result.Pref = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_pstf: Result.Pstf = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_locl: Result.Locl = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_rphf: Result.Rphf = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_half: Result.Half = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_vatu: Result.Vatu = IterateFeatures.Feature; break; + case KBTS_FEATURE_TAG_rclt: Rclt = IterateFeatures.Feature; break; + } + } + + if((Result.Shaper == KBTS_SHAPER_ARABIC) && !Rclt) + { + Result.OpLists[0] = KBTS_OP_LIST(ArabicNoRclt); + } + + kbts_shape_state DummyState = KBTS_ZERO; + DummyState.Config = &Result; + + if(Result.IndicScriptProperties.ViramaCodepoint) + { + // Bake the locl-ized virama. + kbts_glyph Virama = kbts_CodepointToGlyph(Font, Result.IndicScriptProperties.ViramaCodepoint); + Result.Virama = kbts_Substitute1(&DummyState, kbts_GetLookupList(Gsub), Result.Locl, KBTS_SKIP_FLAG_ZWNJ | KBTS_SKIP_FLAG_ZWJ, &Virama); + } + + if((Result.Script == KBTS_SCRIPT_THAI) || (Result.Script == KBTS_SCRIPT_LAO)) + { + kbts_u32 NikhahitCodepoint = (Result.Script == KBTS_SCRIPT_THAI) ? 0xE4D : 0xECD; + kbts_u32 SaraAaCodepoint = (Result.Script == KBTS_SCRIPT_THAI) ? 0xE32 : 0xEB2; + Result.Nikhahit = kbts_CodepointToGlyph(Font, NikhahitCodepoint); + Result.SaraAa = kbts_CodepointToGlyph(Font, SaraAaCodepoint); + } + + Result.DottedCircle = kbts_CodepointToGlyph(Font, 0x25CC); + Result.Whitespace = kbts_CodepointToGlyph(Font, ' '); + + return Result; +} + +static kbts_op kbts_ReadOp(kbts_shape_state *State, kbts_u8 *Ops) +{ + kbts_op Result = KBTS_ZERO; + Result.Kind = Ops[State->Ip++]; + + if(Result.Kind == KBTS_OP_KIND_GSUB_FEATURES_WITH_USER) + { + Result.Kind = KBTS_OP_KIND_GSUB_FEATURES; + Result.Features = State->UserFeatures; + } + + if((Result.Kind == KBTS_OP_KIND_GSUB_FEATURES) || (Result.Kind == KBTS_OP_KIND_GPOS_FEATURES)) + { + kbts_un FeatureCount = Ops[State->Ip++]; + int Rtl = (State->RunDirection == KBTS_DIRECTION_RTL); + KBTS_FOR(FeatureIndex, 0, FeatureCount) + { + kbts_u32 FeatureId = Ops[State->Ip++]; + + if((FeatureId == KBTS_FEATURE_ID_ltra) && Rtl) + { + FeatureId = KBTS_FEATURE_ID_rtla; + } + else if((FeatureId == KBTS_FEATURE_ID_ltrm) && Rtl) + { + FeatureId = KBTS_FEATURE_ID_rtlm; + } + + kbts_AddFeature(&Result.Features, FeatureId); + } + } + return Result; +} + +KBTS_EXPORT int kbts_Shape(kbts_shape_state *State, kbts_shape_config *Config, kbts_direction MainDirection, kbts_direction RunDirection, kbts_glyph *Glyphs, kbts_u32 *GlyphCount, kbts_u32 GlyphCapacity) +{ + KBTS_INSTRUMENT_FUNCTION_BEGIN + State->Config = Config; + State->MainDirection = MainDirection; + State->RunDirection = RunDirection; + + kbts_glyph_array *GlyphArray = &State->GlyphArray; + // The Glyphs array might move after a grow, so update the pointers here. + // We preserve Count information, though, because it makes it simpler not to touch anything + // when we are dealing with sub-arrays like Cluster. + GlyphArray->Glyphs = Glyphs; + GlyphArray->Capacity = GlyphCapacity; + kbts_glyph_array *Cluster = &State->ClusterGlyphArray; + Cluster->Glyphs = Glyphs + State->At; + Cluster->Capacity = GlyphCapacity - State->At; + + kbts_u32 ResumePoint = State->ResumePoint; + State->ResumePoint = 0; + switch(ResumePoint) + { + case 1: goto ResumePoint1; break; + case 2: goto ResumePoint2; break; + case 3: goto ResumePoint3; break; + case 4: goto ResumePoint4; break; + case 5: goto ResumePoint5; break; + case 6: goto ResumePoint6; break; + } + + *GlyphArray = kbts_GlyphArray(Glyphs, *GlyphCount, *GlyphCount, GlyphCapacity); + + // For simple shapers, all of the shaping happens in this single loop. + // For complex shapers, this loop is preparing the text for clustering logic, which happens below. + for(State->Ip = 0; State->Ip < Config->OpLists[0].Length;) + { + State->Op = kbts_ReadOp(State, Config->OpLists[0].Ops); + ResumePoint1:; + if(kbts_ExecuteOp(State, GlyphArray)) + { + State->ResumePoint = 1; + goto GrowRequest; + } + } + + if(KBTS_IN_SET(Config->Shaper, KBTS_SET32((KBTS_SHAPER_INDIC)(KBTS_SHAPER_USE)(KBTS_SHAPER_KHMER)(KBTS_SHAPER_MYANMAR)))) + { + State->ClusterAtStartOfWord = 1; + State->At = 0; + while(State->At < GlyphArray->Count) + { + if(KBTS_IN_SET(Config->Shaper, KBTS_SET32((KBTS_SHAPER_INDIC)(KBTS_SHAPER_KHMER)))) + { + // Reserve a slot in case we need to insert a dotted circle into a broken syllable. + ResumePoint2:; + if(!kbts_GrowGlyphArray(&State->ResumePoint, GlyphArray, GlyphArray->Count, 1, 2, 1)) + { + goto GrowRequest; + } + } + + { + kbts_begin_cluster_result BeginClusterResult = kbts_BeginCluster(State, Glyphs + State->At, GlyphArray->Count - State->At); + GlyphArray->Count += BeginClusterResult.InsertedGlyphCount; + GlyphArray->TotalCount += BeginClusterResult.InsertedGlyphCount; + State->ClusterGlyphCount = (kbts_u32)BeginClusterResult.ClusterGlyphCount; + *Cluster = kbts_GlyphArray(Glyphs + State->At, BeginClusterResult.ClusterGlyphCount, GlyphArray->Count - State->At, GlyphCapacity - State->At); + } + + kbts_glyph *LastGlyphInCluster; LastGlyphInCluster = &Glyphs[State->At + Cluster->Count - 1]; + State->WordBreak = !(LastGlyphInCluster->UnicodeFlags & KBTS_UNICODE_FLAG_PART_OF_WORD); + + for(State->Ip = 0; State->Ip < Config->OpLists[1].Length;) + { + State->Op = kbts_ReadOp(State, Config->OpLists[1].Ops); + ResumePoint3:; + if(kbts_ExecuteOp(State, Cluster)) + { + State->ResumePoint = 3; + goto GrowRequest; + } + } + + kbts_end_cluster_result EndClusterResult; EndClusterResult = kbts_EndCluster(State, Cluster); + if(EndClusterResult.InsertDottedCircle) + { + State->DottedCircleInsertIndex = (kbts_u32)EndClusterResult.DottedCircleIndex; + ResumePoint6:; + if(!kbts_GrowGlyphArray(&State->ResumePoint, Cluster, State->DottedCircleInsertIndex, 1, 6, 0)) + { + State->RequiredGlyphCapacity = Cluster->RequiredCapacity + State->At; + goto GrowRequest; + } + Glyphs[State->At + State->DottedCircleInsertIndex] = Config->DottedCircle; + } + + for(State->Ip = 0; State->Ip < Config->OpLists[2].Length;) + { + State->Op = kbts_ReadOp(State, Config->OpLists[2].Ops); + ResumePoint4:; + if(kbts_ExecuteOp(State, Cluster)) + { + State->ResumePoint = 4; + goto GrowRequest; + } + } + + State->At += Cluster->Count; + kbts_un DeltaClusterGlyphCount = Cluster->Count - State->ClusterGlyphCount; + GlyphArray->Count += DeltaClusterGlyphCount; + GlyphArray->TotalCount += DeltaClusterGlyphCount; + State->ClusterAtStartOfWord = State->WordBreak; + } + + // Post-clustering ops work across clusters. + // This is where Indic GPOS + post-passes happen. + for(State->Ip = 0; State->Ip < Config->OpLists[3].Length;) + { + State->Op = kbts_ReadOp(State, Config->OpLists[3].Ops); + ResumePoint5:; + if(kbts_ExecuteOp(State, GlyphArray)) + { + State->ResumePoint = 5; + goto GrowRequest; + } + } + } + + if(0) + { + GrowRequest:; + kbts_TransferGrowRequest(Cluster, GlyphArray); + State->RequiredGlyphCapacity = GlyphArray->RequiredCapacity; + KBTS_INSTRUMENT_END + return 1; + } + + *GlyphCount = GlyphArray->Count; + KBTS_INSTRUMENT_END + return 0; +} + +KBTS_EXPORT kbts_cursor kbts_Cursor(kbts_direction Direction) +{ + kbts_cursor Result = KBTS_ZERO; + Result.Direction = Direction; + return Result; +} + +KBTS_EXPORT void kbts_PositionGlyph(kbts_cursor *Cursor, kbts_glyph *Glyph, kbts_s32 *X, kbts_s32 *Y) +{ + kbts_s32 AdvanceX = Glyph->AdvanceX; + kbts_s32 AdvanceY = Glyph->AdvanceY; + kbts_s32 OffsetX = Glyph->OffsetX; + kbts_s32 OffsetY = Glyph->OffsetY; + if(Cursor->Direction != KBTS_DIRECTION_RTL) + { + *X = Cursor->X + OffsetX; + *Y = Cursor->Y + OffsetY; + + Cursor->X += AdvanceX; + Cursor->Y += AdvanceY; + } + else + { + // Right-to-left should, in theory, work almost identically to left-to-right: just right-align everything. + // However, the convention for glyph bounding boxes, etc., is that they are left-aligned. + // To compensate for this, we add base glyphs' advances to their positions, which should left-align them. + // We can't accumulate the advances immediately into the cursor, though, because then mark offsets will be wrong. + // + // By the way, Harfbuzz just reverses glyphs to always be left-to-right for the sake of layout. + // The reason we try to handle right-to-left somewhat properly here is that it allows the user to position one + // glyph at a time by just going through the glyph sequence, no matter the text direction. + // This should hopefully save the user from having to allocate a buffer of glyph positions and/or doing a pre-pass + // just to get the total string width, in the case of cross-direction text. + // + // The classic Harfbuzz behavior can be obtained by passing MainDirection = LTR to Shape, even for RTL text. + // (Cursor.Direction also needs to be NONE or LTR, of course, which is the default.) + if(AdvanceX) + { + Cursor->X -= Cursor->LastAdvanceX; + Cursor->LastAdvanceX = AdvanceX; + } + + *X = Cursor->X - AdvanceX + OffsetX; + *Y = Cursor->Y + OffsetY; + + Cursor->Y += AdvanceY; + } +} + +KBTS_EXPORT kbts_un kbts_ReadFontHeader(kbts_font *Font, void *Data, kbts_un Size) +{ + KBTS_UNUSED(Size); + kbts_un Result = 0; + if(Size >= sizeof(kbts_table_directory)) + { + char *FileEnd = (char *)Data + Size; + Font->FileBase = (char *)Data; + Font->FileSize = Size; + kbts_table_directory *Directory = (kbts_table_directory *)Font->FileBase; + + Directory->TableCount = kbts_ByteSwap16(Directory->TableCount); + Directory->SearchRange = kbts_ByteSwap16(Directory->SearchRange); + Directory->EntrySelector = kbts_ByteSwap16(Directory->EntrySelector); + Directory->RangeShift = kbts_ByteSwap16(Directory->RangeShift); + + kbts_table_record *Tables = KBTS_POINTER_AFTER(kbts_table_record, Directory); + + kbts_un ShapingTableSizes[KBTS_SHAPING_TABLE_COUNT] = {0}; + kbts_u32 GdefSize = 0; + kbts_un DirectoryTableCapacity = (FileEnd - (char *)Tables) / sizeof(kbts_table_record); + if(Directory->TableCount <= DirectoryTableCapacity) + { + for(kbts_un TableIndex = 0; TableIndex < Directory->TableCount; ++TableIndex) + { + kbts_table_record *Table = &Tables[TableIndex]; + Table->Checksum = kbts_ByteSwap32(Table->Checksum); + Table->Offset = kbts_ByteSwap32(Table->Offset); + Table->Length = kbts_ByteSwap32(Table->Length); + int TableValid = 0; + + void *TableBase = KBTS_POINTER_OFFSET(void, Font->FileBase, Table->Offset); + char *TableEnd = (char *)TableBase + Table->Length; + if(((char *)TableBase >= (char *)(Tables + Directory->TableCount)) && (TableEnd <= FileEnd)) + { + switch(Table->Tag) + { + case KBTS_FOURCC('h', 'e', 'a', 'd'): + { + if(Table->Length >= sizeof(kbts_head)) + { + kbts_head *Head = (kbts_head *)TableBase; + kbts_ByteSwapArray16Unchecked(&Head->Major, 2); + kbts_ByteSwapArray32Unchecked(&Head->Revision, 2); + // We do not swap the magic number. + kbts_ByteSwapArray16Unchecked(&Head->Flags, 2); + // We do not swap file times. + kbts_ByteSwapArray16Unchecked((kbts_u16 *)&Head->XMin, 9); + + Font->Head = Head; + TableValid = 1; + } + } break; + + case KBTS_FOURCC('c', 'm', 'a', 'p'): + { + if(Table->Length >= sizeof(kbts_cmap)) + { + kbts_cmap *Cmap = (kbts_cmap *)TableBase; + Cmap->Version = kbts_ByteSwap16(Cmap->Version); + Cmap->TableCount = kbts_ByteSwap16(Cmap->TableCount); + + kbts_encoding_record *Records = KBTS_POINTER_AFTER(kbts_encoding_record, Cmap); + + if((char *)(Records + Cmap->TableCount) <= TableEnd) + { + KBTS_FOR(It, 0, Cmap->TableCount) + { + kbts_encoding_record *Record = &Records[It]; + Record->EncodingId = kbts_ByteSwap16(Record->EncodingId); + Record->PlatformId = kbts_ByteSwap16(Record->PlatformId); + Record->SubtableOffset = kbts_ByteSwap32(Record->SubtableOffset); + } + + kbts_cmap_subtable_pointer PreferredSubtable = KBTS_ZERO; + kbts_u16 PreferredFormat = 1; + KBTS_FOR(It, 0, Cmap->TableCount) + { + kbts_cmap_subtable_pointer Subtable = kbts_GetCmapSubtable(Cmap, It); + if((char *)(Subtable.Subtable + 1) <= TableEnd) + { + kbts_u16 Format = kbts_ByteSwap16(*Subtable.Subtable); + + if(Format == 14) + { + if((char *)(Subtable.Subtable + sizeof(kbts_cmap_14)) <= TableEnd) + { + Font->Cmap14 = (kbts_cmap_14 *)Subtable.Subtable; + } + } + else if(!PreferredSubtable.Subtable) + { + PreferredSubtable = Subtable; + } + else if(Format < KBTS_ARRAY_LENGTH(kbts_CmapFormatPrecedence)) + { + kbts_u16 Precedence = kbts_CmapFormatPrecedence[Format]; + kbts_u16 PreferredPrecedence = kbts_CmapFormatPrecedence[PreferredFormat]; + + if((Precedence > PreferredPrecedence) || ((Precedence == PreferredPrecedence) && (Subtable.PlatformId == 3))) + { + PreferredSubtable = Subtable; + PreferredFormat = Format; + } + } + } + } + + if(PreferredSubtable.Subtable) + { + *PreferredSubtable.Subtable = kbts_ByteSwap16(*PreferredSubtable.Subtable); + switch(*PreferredSubtable.Subtable) + { + case 0: + { + kbts_cmap_0 *Cmap0 = (kbts_cmap_0 *)PreferredSubtable.Subtable; + if((char *)(Cmap0 + 1) <= TableEnd) + { + Cmap0->Length = kbts_ByteSwap16(Cmap0->Length); + Cmap0->Language = kbts_ByteSwap16(Cmap0->Language); + TableValid = 1; + } + } + break; + + case 2: + { + kbts_cmap_2 *Cmap2 = (kbts_cmap_2 *)PreferredSubtable.Subtable; + if(kbts_ByteSwapArray16(&Cmap2->Length, 258, TableEnd)) + { + kbts_un SubHeaderCount = 0; + KBTS_FOR(It, 0, 256) + { + kbts_un SubHeaderIndex = Cmap2->SubHeaderKeys[It]; + SubHeaderCount = KBTS_MAX(SubHeaderCount, SubHeaderIndex + 1); + } + + kbts_sub_header *SubHeaders = KBTS_POINTER_AFTER(kbts_sub_header, Cmap2); + if(kbts_ByteSwapArray16(&SubHeaders->FirstCode, 4 * SubHeaderCount, TableEnd)) + { + kbts_u16 *GlyphIds = (kbts_u16 *)(SubHeaders + SubHeaderCount); + + kbts_sn GlyphIdCount = 0; + KBTS_FOR(It, 0, SubHeaderCount) + { + kbts_sub_header *SubHeader = &SubHeaders[It]; + + kbts_u16 *OnePastLastGlyphId = &SubHeader->IdRangeOffset + SubHeader->IdRangeOffset / 2 + SubHeader->EntryCount; + GlyphIdCount = KBTS_MAX(GlyphIdCount, OnePastLastGlyphId - GlyphIds); + } + + if(kbts_ByteSwapArray16(GlyphIds, (kbts_un)GlyphIdCount, TableEnd)) + { + TableValid = 1; + } + } + } + } + break; + + case 4: + { + kbts_cmap_4 *Cmap4 = (kbts_cmap_4 *)PreferredSubtable.Subtable; + if(kbts_ByteSwapArray16(&Cmap4->Length, 5, TableEnd) && + kbts_ByteSwapArray16(KBTS_POINTER_AFTER(kbts_u16, Cmap4), Cmap4->SegmentCountTimesTwo * 2 + 1, TableEnd)) + { + kbts_un SegmentCount = Cmap4->SegmentCountTimesTwo / 2; + kbts_u16 *EndCodes = KBTS_POINTER_AFTER(kbts_u16, Cmap4); + kbts_u16 *StartCodes = EndCodes + SegmentCount + 1; + kbts_s16 *IdDeltas = (kbts_s16 *)(StartCodes + SegmentCount); + kbts_u16 *IdRangeOffsets = (kbts_u16 *)(IdDeltas + SegmentCount); + kbts_u16 *GlyphIds = IdRangeOffsets + SegmentCount; + + kbts_sn GlyphIdCount = 0; + + KBTS_FOR(SegmentIndex, 0, SegmentCount) + { + kbts_u16 Offset = IdRangeOffsets[SegmentIndex]; + + if(Offset) + { + kbts_u16 *IdLookup = &IdRangeOffsets[SegmentIndex] + (EndCodes[SegmentIndex] - StartCodes[SegmentIndex] + 1) + Offset / 2; + + GlyphIdCount = KBTS_MAX(GlyphIdCount, (IdLookup - GlyphIds)); + } + } + + if(kbts_ByteSwapArray16(GlyphIds, (kbts_un)GlyphIdCount, TableEnd)) + { + TableValid = 1; + } + } + } + break; + + case 6: + { + kbts_cmap_6 *Cmap6 = (kbts_cmap_6 *)PreferredSubtable.Subtable; + if(kbts_ByteSwapArray16(&Cmap6->Length, 4, TableEnd) && + kbts_ByteSwapArray16(KBTS_POINTER_AFTER(kbts_u16, Cmap6), Cmap6->EntryCount, TableEnd)) + { + TableValid = 1; + } + } + break; + + case 12: + { + kbts_cmap_12_13 *Cmap12 = (kbts_cmap_12_13 *)PreferredSubtable.Subtable; + if(kbts_ByteSwapArray32(&Cmap12->Length, 3, TableEnd) && + kbts_ByteSwapArray32(KBTS_POINTER_AFTER(kbts_u32, Cmap12), Cmap12->GroupCount * 3, TableEnd)) + { + TableValid = 1; + } + } + break; + } + + Font->Cmap = PreferredSubtable.Subtable; + } + } + } + } + break; + + case KBTS_FOURCC('G', 'D', 'E', 'F'): + { + kbts_gdef *Gdef = (kbts_gdef *)TableBase; + GdefSize = Table->Length; + + if(kbts_ByteSwapArray16(&Gdef->Major, 6, TableEnd)) + { + if(Gdef->Minor >= 2) + { + if(Table->Length >= 14) + { + Gdef->MarkGlyphSetsDefinitionOffset = kbts_ByteSwap16(Gdef->MarkGlyphSetsDefinitionOffset); + + if(Gdef->Minor == 3) + { + if(Table->Length >= sizeof(kbts_gdef)) + { + // @Incomplete + Gdef->ItemVariationStoreOffset = kbts_ByteSwap32(Gdef->ItemVariationStoreOffset); + TableValid = 1; + } + } + else + { + TableValid = 1; + } + } + } + else + { + TableValid = 1; + } + } + + Font->Gdef = Gdef; + } + break; + + case KBTS_FOURCC('G', 'S', 'U', 'B'): + case KBTS_FOURCC('G', 'P', 'O', 'S'): + { + // We do not do any bounds checking here because Gsub/Gpos tables get byteswapped later on, + // in ByteSwapGsubGposCommon. + kbts_un Index = (Table->Tag == KBTS_FOURCC('G', 'S', 'U', 'B')) ? KBTS_SHAPING_TABLE_GSUB : KBTS_SHAPING_TABLE_GPOS; + Font->ShapingTables[Index] = (kbts_gsub_gpos *)TableBase; + ShapingTableSizes[Index] = Table->Length; + TableValid = 1; + } break; + + case KBTS_FOURCC('h', 'h', 'e', 'a'): + case KBTS_FOURCC('v', 'h', 'e', 'a'): + { + kbts_un Orientation = Table->Tag == KBTS_FOURCC('h', 'h', 'e', 'a') ? KBTS_ORIENTATION_HORIZONTAL : KBTS_ORIENTATION_VERTICAL; + kbts_hea *Hea = (kbts_hea *)TableBase; + if(kbts_ByteSwapArray16((kbts_u16 *)Hea, sizeof(kbts_hea) / sizeof(kbts_u16), TableEnd)) + { + Font->Hea[Orientation] = Hea; + TableValid = 1; + } + } break; + + case KBTS_FOURCC('h', 'm', 't', 'x'): + case KBTS_FOURCC('v', 'm', 't', 'x'): + { + kbts_un Orientation = Table->Tag == KBTS_FOURCC('h', 'm', 't', 'x') ? KBTS_ORIENTATION_HORIZONTAL : KBTS_ORIENTATION_VERTICAL; + kbts_u16 *Mtx = (kbts_u16 *)TableBase; + kbts_ByteSwapArray16Unchecked(Mtx, Table->Length / sizeof(kbts_u16)); + Font->Mtx[Orientation] = Mtx; + TableValid = 1; + } break; + + case KBTS_FOURCC('m', 'a', 'x', 'p'): + { + if(Table->Length >= 6) + { + Font->Maxp = (kbts_maxp *)TableBase; + Font->Maxp->Major = kbts_ByteSwap16(Font->Maxp->Major); + Font->Maxp->Minor = kbts_ByteSwap16(Font->Maxp->Minor); + + kbts_un U16Count = 0; + if(!Font->Maxp->Major && (Font->Maxp->Minor == 0x5000)) + { + U16Count = 1; + } + else if((Font->Maxp->Major == 1) && !Font->Maxp->Minor) + { + U16Count = 14; + } + + if(kbts_ByteSwapArray16(&Font->Maxp->GlyphCount, U16Count, TableEnd)) + { + Font->GlyphCount = Font->Maxp->GlyphCount; + TableValid = 1; + } + } + } break; + + default: + { + TableValid = 1; + } break; + } + } + + if(!TableValid) + { + goto Error; + } + } + } + else + { + goto Error; + } + + if(kbts_FontIsValid(Font)) + { + Result = sizeof(kbts_u32) * ((ShapingTableSizes[KBTS_SHAPING_TABLE_GSUB] + ShapingTableSizes[KBTS_SHAPING_TABLE_GPOS] + GdefSize) / 2); + } + } + else + { + goto Error; + } + + if(0) + { + Error:; + Font->Error = 1; + } + + return (kbts_u32)Result; +} + +KBTS_EXPORT kbts_un kbts_ReadFontData(kbts_font *Font, void *Scratch, kbts_un ScratchSize) +{ + kbts_un Result = 0; + if(kbts_FontIsValid(Font)) + { + kbts_byteswap_context ByteSwapContext = KBTS_ZERO; + ByteSwapContext.FileBase = Font->FileBase; + ByteSwapContext.FileEnd = Font->FileBase + Font->FileSize; + ByteSwapContext.PointerCapacity = ScratchSize / sizeof(kbts_u32); + ByteSwapContext.Pointers = (kbts_u32 *)Scratch; + + kbts_un TotalLookupCount = 0; + kbts_un TotalSubtableCount = 0; + + kbts_gdef *Gdef = Font->Gdef; + if(Gdef) + { + if(Gdef->ClassDefinitionOffset) + { + kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Gdef, Gdef->ClassDefinitionOffset); + kbts_ByteSwapClassDefinition(&ByteSwapContext, ClassDefBase); + } + + if(Gdef->MarkAttachmentClassDefinitionOffset) + { + kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Gdef, Gdef->MarkAttachmentClassDefinitionOffset); + kbts_ByteSwapClassDefinition(&ByteSwapContext, ClassDefBase); + } + + if((Gdef->Minor >= 2) && Gdef->MarkGlyphSetsDefinitionOffset) + { + kbts_mark_glyph_sets *MarkGlyphSets = KBTS_POINTER_OFFSET(kbts_mark_glyph_sets, Gdef, Gdef->MarkGlyphSetsDefinitionOffset); + kbts_ByteSwapArray16Context(&MarkGlyphSets->Format, 2, &ByteSwapContext); + if(MarkGlyphSets->Format == 1) + { + kbts_u32 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u32, MarkGlyphSets); + kbts_ByteSwapArray32Context(CoverageOffsets, MarkGlyphSets->MarkGlyphSetCount, &ByteSwapContext); + + KBTS_FOR(MarkGlyphSetIndex, 0, MarkGlyphSets->MarkGlyphSetCount) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, MarkGlyphSets, CoverageOffsets[MarkGlyphSetIndex]); + kbts_ByteSwapCoverage(&ByteSwapContext, Coverage); + } + } + } + } + + kbts_gsub_gpos *Gsub = Font->ShapingTables[KBTS_SHAPING_TABLE_GSUB]; + if(Gsub) + { + kbts_ByteSwapGsubGposCommon(&ByteSwapContext, Gsub); + + kbts_lookup_list *LookupList = kbts_GetLookupList(Gsub); + LookupList->Count = kbts_ByteSwap16(LookupList->Count); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, LookupList), LookupList->Count, &ByteSwapContext); + + TotalLookupCount += LookupList->Count; + + KBTS_FOR(LookupIndex, 0, LookupList->Count) + { + kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, LookupIndex); + + KBTS_DUMPF("GSUB Lookup %llu:\n", LookupIndex); + + if(kbts_ByteSwapLookup(&ByteSwapContext, PackedLookup)) + { + kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); + KBTS_DUMPF(" Flags %u\n", Lookup.Flags); + + KBTS_FOR(SubstitutionIndex, 0, Lookup.SubtableCount) + { + kbts_u16 *Base = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubstitutionIndex]); + + KBTS_DUMPF(" Subtable %llu:\n", SubstitutionIndex); + + kbts_ByteSwapGsubLookupSubtable(&ByteSwapContext, Lookup.Type, Base); + } + } + + TotalSubtableCount += PackedLookup->SubtableCount; + } + } + + kbts_gsub_gpos *Gpos = Font->ShapingTables[KBTS_SHAPING_TABLE_GPOS]; + if(Gpos) + { + kbts_ByteSwapGsubGposCommon(&ByteSwapContext, Gpos); + + kbts_lookup_list *LookupList = kbts_GetLookupList(Gpos); + LookupList->Count = kbts_ByteSwap16(LookupList->Count); + kbts_ByteSwapArray16Context(KBTS_POINTER_AFTER(kbts_u16, LookupList), LookupList->Count, &ByteSwapContext); + + TotalLookupCount += LookupList->Count; + + KBTS_FOR(LookupIndex, 0, LookupList->Count) + { + kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, LookupIndex); + + KBTS_DUMPF("GPOS Lookup %llu:\n", LookupIndex); + + if(kbts_ByteSwapLookup(&ByteSwapContext, PackedLookup)) + { + kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); + + KBTS_DUMPF(" Flags %x\n", Lookup.Flags); + + KBTS_FOR(SubstitutionIndex, 0, Lookup.SubtableCount) + { + kbts_u16 *Base = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubstitutionIndex]); + + KBTS_DUMPF(" Subtable %llu:\n", (kbts_un)SubstitutionIndex); + + kbts_ByteSwapGposLookupSubtable(&ByteSwapContext, LookupList, Lookup.Type, Base); + } + } + + TotalSubtableCount += PackedLookup->SubtableCount; + } + } + + // At this point, we are done byteswapping the file, so we can start reusing the scratch memory. + + if(Gsub) + { + kbts_lookup_list *LookupList = kbts_GetLookupList(Gsub); + + // Figure out lookup recursion depth and other useful metrics. + // Most of these are not used yet, but would be useful for a streaming shaper and/or to inform GLYPH_BUFFER_GROW_MARGIN. + kbts_un MaximumBacktrackWithoutSkippingGlyphs = 0; + kbts_un MaximumLookaheadWithoutSkippingGlyphs = 0; + kbts_un MaximumLookupStackSize = 1; + kbts_un MaximumSubstitutionOutputSize = 1; + kbts_un MaximumInputSequenceLength = 1; + + // We are done byteswapping the file, so we can reclaim the scratch memory. + kbts_lookup_info_frame *Frames = (kbts_lookup_info_frame *)Scratch; + kbts_un FrameCapacity = ScratchSize / sizeof(kbts_lookup_info_frame); + + KBTS_FOR(RootLookupIndex, 0, LookupList->Count) + { + kbts_lookup *PackedRootLookup = kbts_GetLookup(LookupList, RootLookupIndex); + kbts_unpacked_lookup RootLookup = kbts_UnpackLookup(Gdef, PackedRootLookup); + + KBTS_FOR(RootSubtableIndex, 0, RootLookup.SubtableCount) + { + kbts_un FrameCount = 0; + { + kbts_lookup_info_frame First = KBTS_ZERO; + First.LookupType = RootLookup.Type; + First.Base = KBTS_POINTER_OFFSET(kbts_u16, PackedRootLookup, RootLookup.SubtableOffsets[RootSubtableIndex]); + First.StackSize = 1; + if(FrameCount < FrameCapacity) + { + Frames[FrameCount++] = First; + } + else + { + Font->Error = 1; + goto DoneGatheringLookupInfo; + } + } + + while(FrameCount) + { + kbts_lookup_info_frame Frame = Frames[--FrameCount]; + kbts_u16 LookupType = Frame.LookupType; + kbts_u16 *Base = Frame.Base; + kbts_u32 LookaheadOffset = Frame.LookaheadOffset; + kbts_u32 StackSize = Frame.StackSize; + + MaximumLookupStackSize = KBTS_MAX(MaximumLookupStackSize, StackSize); + + while(LookupType == 7) + { + kbts_extension *Subst = (kbts_extension *)Base; + + Base = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->Offset); + LookupType = Subst->LookupType; + } + + switch(LookupType) + { + case 2: + { + kbts_multiple_substitution *Subst = (kbts_multiple_substitution *)Base; + KBTS_FOR(SequenceIndex, 0, Subst->SequenceCount) + { + kbts_sequence *Sequence = kbts_GetSequence(Subst, SequenceIndex); + + MaximumSubstitutionOutputSize = KBTS_MAX(MaximumSubstitutionOutputSize, Sequence->GlyphCount); + } + } break; + + case 4: + { + kbts_ligature_substitution *Subst = (kbts_ligature_substitution *)Base; + + KBTS_FOR(SetIndex, 0, Subst->LigatureSetCount) + { + kbts_ligature_set *Set = kbts_GetLigatureSet(Subst, SetIndex); + + KBTS_FOR(LigatureIndex, 0, Set->Count) + { + kbts_ligature *Ligature = kbts_GetLigature(Set, LigatureIndex); + + MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Ligature->ComponentCount - 1); + } + } + } break; + + case 5: + { + if(Base[0] == 1) + { + kbts_sequence_context_1 *Subst = (kbts_sequence_context_1 *)Base; + + KBTS_FOR(SetIndex, 0, Subst->SeqRuleSetCount) + { + kbts_sequence_rule_set *Set = kbts_GetSequenceRuleSet(Subst, SetIndex); + + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_sequence_rule *Rule = kbts_GetSequenceRule(Set, RuleIndex); + + MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Rule->GlyphCount - 1); + MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Rule->GlyphCount); + + kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); + kbts_sequence_lookup_record *Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); + KBTS_FOR(RecordIndex, 0, Rule->SequenceLookupCount) + { + kbts_sequence_lookup_record *Record = &Records[RecordIndex]; + if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) + { + Font->Error = 1; + goto DoneGatheringLookupInfo; + } + } + } + } + } + else if(Base[0] == 2) + { + kbts_sequence_context_2 *Subst = (kbts_sequence_context_2 *)Base; + + KBTS_FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) + { + kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, SetIndex); + + if(Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); + + MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Rule->GlyphCount - 1); + MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Rule->GlyphCount); + + kbts_u16 *InputSequence = KBTS_POINTER_AFTER(kbts_u16, Rule); + kbts_sequence_lookup_record *Records = (kbts_sequence_lookup_record *)(InputSequence + Rule->GlyphCount - 1); + + KBTS_FOR(RecordIndex, 0, Rule->SequenceLookupCount) + { + kbts_sequence_lookup_record *Record = &Records[RecordIndex]; + if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) + { + Font->Error = 1; + goto DoneGatheringLookupInfo; + } + } + } + } + } + } + else if(Base[0] == 3) + { + kbts_sequence_context_3 *Subst = (kbts_sequence_context_3 *)Base; + + MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Subst->GlyphCount - 1); + MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Subst->GlyphCount); + + kbts_u16 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + kbts_sequence_lookup_record *Records = (kbts_sequence_lookup_record *)(CoverageOffsets + Subst->GlyphCount); + + KBTS_FOR(RecordIndex, 0, Subst->SequenceLookupCount) + { + kbts_sequence_lookup_record *Record = &Records[RecordIndex]; + if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) + { + Font->Error = 1; + goto DoneGatheringLookupInfo; + } + } + } + } break; + + case 6: + { + if(Base[0] == 1) + { + kbts_chained_sequence_context_1 *Subst = (kbts_chained_sequence_context_1 *)Base; + + KBTS_FOR(SetIndex, 0, Subst->ChainedSequenceRuleSetCount) + { + kbts_chained_sequence_rule_set *Set = kbts_GetChainedSequenceRuleSet(Subst, SetIndex); + + if(Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); + kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + + MaximumBacktrackWithoutSkippingGlyphs = KBTS_MAX(MaximumBacktrackWithoutSkippingGlyphs, Unpacked.BacktrackCount); + MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Unpacked.LookaheadCount); + MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Unpacked.InputCount); + + KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) + { + kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; + if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) + { + Font->Error = 1; + goto DoneGatheringLookupInfo; + } + } + } + } + } + } + else if(Base[0] == 2) + { + kbts_chained_sequence_context_2 *Subst = (kbts_chained_sequence_context_2 *)Base; + + KBTS_FOR(SetIndex, 0, Subst->ChainedClassSequenceRuleSetCount) + { + // @Duplication with 6.1. + kbts_chained_sequence_rule_set *Set = kbts_GetChainedClassSequenceRuleSet(Subst, SetIndex); + + if(Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); + kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + + MaximumBacktrackWithoutSkippingGlyphs = KBTS_MAX(MaximumBacktrackWithoutSkippingGlyphs, Unpacked.BacktrackCount); + MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Unpacked.LookaheadCount); + MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Unpacked.InputCount); + + KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) + { + kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; + if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) + { + Font->Error = 1; + goto DoneGatheringLookupInfo; + } + } + } + } + } + } + else if(Base[0] == 3) + { + kbts_chained_sequence_context_3 *Subst = (kbts_chained_sequence_context_3 *)Base; + kbts_unpacked_chained_sequence_context_3 Unpacked = kbts_UnpackChainedSequenceContext3(Subst, 0); + + MaximumBacktrackWithoutSkippingGlyphs = KBTS_MAX(MaximumBacktrackWithoutSkippingGlyphs, Unpacked.BacktrackCount); + MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Unpacked.LookaheadCount); + MaximumInputSequenceLength = KBTS_MAX(MaximumInputSequenceLength, Unpacked.InputCount); + + KBTS_FOR(RecordIndex, 0, Unpacked.RecordCount) + { + kbts_sequence_lookup_record *Record = &Unpacked.Records[RecordIndex]; + if(!kbts_PushLookup(Gdef, Frames, &FrameCount, FrameCapacity, kbts_GetLookup(LookupList, Record->LookupListIndex), LookaheadOffset + Record->SequenceIndex, StackSize + RecordIndex + 1)) + { + Font->Error = 1; + goto DoneGatheringLookupInfo; + } + } + } + } break; + + case 8: + { + kbts_reverse_chain_substitution *Subst = (kbts_reverse_chain_substitution *)Base; + kbts_unpacked_reverse_chain_substitution Unpacked = kbts_UnpackReverseChainSubstitution(Subst, 0); + + MaximumBacktrackWithoutSkippingGlyphs = KBTS_MAX(MaximumBacktrackWithoutSkippingGlyphs, Unpacked.BacktrackCount); + MaximumLookaheadWithoutSkippingGlyphs = KBTS_MAX(MaximumLookaheadWithoutSkippingGlyphs, LookaheadOffset + Unpacked.LookaheadCount); + } break; + } + } + } + } + + DoneGatheringLookupInfo:; + Font->LookupInfo.MaximumBacktrackWithoutSkippingGlyphs = (kbts_u32)MaximumBacktrackWithoutSkippingGlyphs; + Font->LookupInfo.MaximumLookaheadWithoutSkippingGlyphs = (kbts_u32)MaximumLookaheadWithoutSkippingGlyphs; + Font->LookupInfo.MaximumSubstitutionOutputSize = (kbts_u32)MaximumSubstitutionOutputSize; + Font->LookupInfo.MaximumInputSequenceLength = (kbts_u32)MaximumInputSequenceLength; + Font->LookupInfo.MaximumLookupStackSize = (kbts_u32)MaximumLookupStackSize; + } + + Font->LookupCount = (kbts_u32)TotalLookupCount; + Font->SubtableCount = (kbts_u32)TotalSubtableCount; + + kbts_un GlyphLookupMatrixSizeInBytes = ((((TotalLookupCount * Font->GlyphCount) + 7) / 8) + 3) & ~3; + kbts_un GlyphLookupSubtableMatrixSizeInBytes = ((((TotalSubtableCount * Font->GlyphCount) + 7) / 8) + 3) & ~3; + Result = GlyphLookupMatrixSizeInBytes + GlyphLookupSubtableMatrixSizeInBytes + sizeof(kbts_u32) * TotalLookupCount + sizeof(kbts_lookup_subtable_info) * TotalSubtableCount; + + Font->Error |= ByteSwapContext.Error; + } + return Result; +} + +KBTS_EXPORT int kbts_PostReadFontInitialize(kbts_font *Font, void *Memory, kbts_un MemorySize) +{ + if(kbts_FontIsValid(Font) && Font->Maxp) + { + // Bake table filters. + kbts_un GlyphCount = Font->GlyphCount; + + kbts_un GlyphLookupMatrixSizeInBits = Font->LookupCount * GlyphCount; + kbts_un GlyphLookupMatrixSizeInBytes = (GlyphLookupMatrixSizeInBits + 7) / 8; + GlyphLookupMatrixSizeInBytes = (GlyphLookupMatrixSizeInBytes + 3) & ~3; // Align to u32 + + kbts_un GlyphLookupSubtableMatrixSizeInBits = Font->SubtableCount * GlyphCount; + kbts_un GlyphLookupSubtableMatrixSizeInBytes = (GlyphLookupSubtableMatrixSizeInBits + 7) / 8; + GlyphLookupSubtableMatrixSizeInBytes = (GlyphLookupSubtableMatrixSizeInBytes + 3) & ~3; // Align to u32 + + KBTS_MEMSET(Memory, 0, MemorySize); + + kbts_u32 *GlyphLookupMatrix = (kbts_u32 *)Memory; + kbts_u32 *GlyphLookupSubtableMatrix = KBTS_POINTER_OFFSET(kbts_u32, GlyphLookupMatrix, GlyphLookupMatrixSizeInBytes); + kbts_u32 *LookupSubtableIndexOffsets = KBTS_POINTER_OFFSET(kbts_u32, GlyphLookupSubtableMatrix, GlyphLookupSubtableMatrixSizeInBytes); + kbts_lookup_subtable_info *SubtableInfos = KBTS_POINTER_OFFSET(kbts_lookup_subtable_info, LookupSubtableIndexOffsets, sizeof(kbts_u32) * Font->LookupCount); + kbts_un GposLookupIndexOffset = 0; + + kbts_un RunningLookupIndex = 0; + kbts_un RunningSubtableIndex = 0; + + KBTS_FOR(ShapingTableIndex, 0, KBTS_SHAPING_TABLE_COUNT) + { + kbts_gsub_gpos *ShapingTable = Font->ShapingTables[ShapingTableIndex]; + + if(ShapingTableIndex == KBTS_SHAPING_TABLE_GPOS) + { + GposLookupIndexOffset = RunningLookupIndex; + } + + if(ShapingTable) + { + kbts_lookup_list *LookupList = kbts_GetLookupList(ShapingTable); + KBTS_FOR(LookupIndex, 0, LookupList->Count) + { + kbts_lookup *PackedLookup = kbts_GetLookup(LookupList, LookupIndex); + kbts_unpacked_lookup Lookup = kbts_UnpackLookup(Font->Gdef, PackedLookup); + + LookupSubtableIndexOffsets[RunningLookupIndex] = (kbts_u32)RunningSubtableIndex; + + KBTS_FOR(SubtableIndex, 0, Lookup.SubtableCount) + { + kbts_lookup_subtable_info SubtableInfo = KBTS_ZERO; + kbts_u32 LookupType = Lookup.Type; + kbts_u16 *Base = KBTS_POINTER_OFFSET(kbts_u16, PackedLookup, Lookup.SubtableOffsets[SubtableIndex]); + + while(((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 7)) || + ((ShapingTableIndex == KBTS_SHAPING_TABLE_GPOS) && (LookupType == 9))) + { + kbts_extension *Extension = (kbts_extension *)Base; + LookupType = Extension->LookupType; + Base = KBTS_POINTER_OFFSET(kbts_u16, Extension, Extension->Offset); + } + + KBTS_FOR(GlyphIndex, 0, GlyphCount) + { + kbts_glyph Glyph = KBTS_ZERO; + Glyph.Id = (kbts_u16)GlyphIndex; + Glyph.Classes = kbts_GlyphClasses(Font, Glyph.Id); + + // @Duplication + kbts_cover_glyph_result Cover = KBTS_ZERO; + Cover.Valid = kbts_GlyphPassesLookupFilter(&Glyph, &Lookup); + if(Cover.Valid && kbts_LookupBeginsWithCoverage((kbts_shaping_table)ShapingTableIndex, Lookup.Type, Base[0])) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Base, Base[1]); + Cover = kbts_CoverGlyph(Coverage, Glyph.Id); + } + + // The "primary" slot here refers to the "current glyph" when matching. + // It is the first glyph in the input sequence, not counting backtrack. + // We use the primary slot for per-feature filtering. + int InPrimary = Cover.Valid; + // The secondary slot is anything else: input sequence, lookahead, backtrack, ligature components. + // They are used for subtable filtering. + int InSecondary = 0; + + if((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 4)) + { + kbts_ligature_substitution *Subst = (kbts_ligature_substitution *)Base; + KBTS_FOR(SetIndex, 0, Subst->LigatureSetCount) + { + kbts_ligature_set *Set = kbts_GetLigatureSet(Subst, SetIndex); + KBTS_FOR(LigatureIndex, 0, Set->Count) + { + kbts_ligature *Ligature = kbts_GetLigature(Set, LigatureIndex); + kbts_u16 *Ids = KBTS_POINTER_AFTER(kbts_u16, Ligature); + + SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Ligature->ComponentCount - 1) + 1; + + KBTS_FOR(IdIndex, 1, Ligature->ComponentCount) + { + kbts_u16 LigatureGlyphId = Ids[IdIndex - 1]; + if(LigatureGlyphId == Glyph.Id) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + } + } + } + else if(((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 5)) || + ((ShapingTableIndex == KBTS_SHAPING_TABLE_GPOS) && (LookupType == 7))) + { + if(Base[0] == 1) + { + kbts_sequence_context_1 *Subst = (kbts_sequence_context_1 *)Base; + + KBTS_FOR(SetIndex, 0, Subst->SeqRuleSetCount) + { + kbts_sequence_rule_set *Set = kbts_GetSequenceRuleSet(Subst, SetIndex); + + if(Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_sequence_rule *Rule = kbts_GetSequenceRule(Set, RuleIndex); + SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Rule->GlyphCount - 1) + 1; + + kbts_u16 *SequenceIds = KBTS_POINTER_AFTER(kbts_u16, Rule); + KBTS_FOR(InputIndex, 1, Rule->GlyphCount) + { + kbts_u16 SequenceId = SequenceIds[InputIndex - 1]; + if(SequenceId == Glyph.Id) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + } + } + } + } + else if(Base[0] == 2) + { + kbts_sequence_context_2 *Subst = (kbts_sequence_context_2 *)Base; + kbts_u16 *ClassDefBase = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->ClassDefOffset); + kbts_glyph_class_from_table_result Class = kbts_GlyphClassFromTable(ClassDefBase, Glyph.Id); + + KBTS_FOR(SetIndex, 0, Subst->ClassSequenceRuleSetCount) + { + kbts_class_sequence_rule_set *Set = kbts_GetClassSequenceRuleSet(Subst, SetIndex); + if(Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_class_sequence_rule *Rule = kbts_GetClassSequenceRule(Set, RuleIndex); + kbts_u16 *SequenceClasses = KBTS_POINTER_AFTER(kbts_u16, Rule); + + SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Rule->GlyphCount - 1) + 1; + + KBTS_FOR(SequenceIndex, 1, Rule->GlyphCount) + { + if(SequenceClasses[SequenceIndex - 1] == Class.Class) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + } + } + } + } + else if(Base[0] == 3) + { + kbts_sequence_context_3 *Subst = (kbts_sequence_context_3 *)Base; + kbts_u16 *CoverageOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + + SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Subst->GlyphCount - 1) + 1; + + InPrimary = 0; + KBTS_FOR(CoverageIndex, 0, Subst->GlyphCount) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, CoverageOffsets[CoverageIndex]); + kbts_cover_glyph_result SequenceCover = kbts_CoverGlyph(Coverage, Glyph.Id); + if(SequenceCover.Valid) + { + if(!CoverageIndex) + { + InPrimary = 1; + } + else + { + InSecondary = 1; + } + goto DoneCheckingForInclusion; + } + } + } + } + else if(((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 6)) || + ((ShapingTableIndex == KBTS_SHAPING_TABLE_GPOS) && (LookupType == 8))) + { + if(Base[0] == 1) + { + kbts_chained_sequence_context_1 *Subst = (kbts_chained_sequence_context_1 *)Base; + kbts_u16 *ChainedSequenceRuleSetOffsets = KBTS_POINTER_AFTER(kbts_u16, Subst); + + KBTS_FOR(SetIndex, 0, Subst->ChainedSequenceRuleSetCount) + { + kbts_chained_sequence_rule_set *Set = KBTS_POINTER_OFFSET(kbts_chained_sequence_rule_set, Subst, ChainedSequenceRuleSetOffsets[SetIndex]); + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_chained_sequence_rule *Rule = kbts_GetChainedClassSequenceRule(Set, RuleIndex); + kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + + SubtableInfo.MinimumBacktrackPlusOne = KBTS_MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; + SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.InputCount - 1 + Unpacked.LookaheadCount) + 1; + + KBTS_FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) + { + if(Unpacked.Backtrack[BacktrackIndex] == Glyph.Id) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + KBTS_FOR(InputIndex, 1, Unpacked.InputCount) + { + if(Unpacked.Input[InputIndex - 1] == Glyph.Id) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + KBTS_FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) + { + if(Unpacked.Lookahead[LookaheadIndex] == Glyph.Id) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + } + } + } + else if(Base[0] == 2) + { + kbts_chained_sequence_context_2 *Subst = (kbts_chained_sequence_context_2 *)Base; + kbts_u16 *BacktrackClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->BacktrackClassDefOffset); + kbts_u16 *InputClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->InputClassDefOffset); + kbts_u16 *LookaheadClassDefinition = KBTS_POINTER_OFFSET(kbts_u16, Subst, Subst->LookaheadClassDefOffset); + + kbts_u16 BacktrackClass = kbts_GlyphClassFromTable(BacktrackClassDefinition, Glyph.Id).Class; + kbts_u16 InputClass = kbts_GlyphClassFromTable(InputClassDefinition, Glyph.Id).Class; + kbts_u16 LookaheadClass = kbts_GlyphClassFromTable(LookaheadClassDefinition, Glyph.Id).Class; + + KBTS_FOR(SetIndex, 0, Subst->ChainedClassSequenceRuleSetCount) + { + kbts_chained_sequence_rule_set *Set = kbts_GetChainedClassSequenceRuleSet(Subst, SetIndex); + if(Set) + { + KBTS_FOR(RuleIndex, 0, Set->Count) + { + kbts_chained_sequence_rule *Rule = kbts_GetChainedSequenceRule(Set, RuleIndex); + kbts_unpacked_chained_sequence_rule Unpacked = kbts_UnpackChainedSequenceRule(Rule, 0); + + SubtableInfo.MinimumBacktrackPlusOne = KBTS_MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; + SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.InputCount - 1 + Unpacked.LookaheadCount) + 1; + + KBTS_FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) + { + if(Unpacked.Backtrack[BacktrackIndex] == BacktrackClass) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + KBTS_FOR(InputIndex, 1, Unpacked.InputCount) + { + if(Unpacked.Input[InputIndex - 1] == InputClass) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + KBTS_FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) + { + if(Unpacked.Lookahead[LookaheadIndex] == LookaheadClass) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + } + } + } + } + else if(Base[0] == 3) + { + kbts_chained_sequence_context_3 *Subst = (kbts_chained_sequence_context_3 *)Base; + kbts_unpacked_chained_sequence_context_3 Unpacked = kbts_UnpackChainedSequenceContext3(Subst, 0); + + SubtableInfo.MinimumBacktrackPlusOne = KBTS_MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; + SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.InputCount - 1 + Unpacked.LookaheadCount) + 1; + + KBTS_FOR(BacktrackCoverageIndex, 0, Unpacked.BacktrackCount) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackCoverageIndex]); + kbts_cover_glyph_result SequenceCover = kbts_CoverGlyph(Coverage, Glyph.Id); + if(SequenceCover.Valid) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + + InPrimary = 0; + KBTS_FOR(InputCoverageIndex, 0, Unpacked.InputCount) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.InputCoverageOffsets[InputCoverageIndex]); + kbts_cover_glyph_result SequenceCover = kbts_CoverGlyph(Coverage, Glyph.Id); + if(SequenceCover.Valid) + { + if(!InputCoverageIndex) + { + InPrimary = 1; + } + else + { + InSecondary = 1; + } + goto DoneCheckingForInclusion; + } + } + + KBTS_FOR(LookaheadCoverageIndex, 0, Unpacked.LookaheadCount) + { + kbts_coverage *Coverage = KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadCoverageIndex]); + kbts_cover_glyph_result SequenceCover = kbts_CoverGlyph(Coverage, Glyph.Id); + if(SequenceCover.Valid) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + } + } + else if((ShapingTableIndex == KBTS_SHAPING_TABLE_GSUB) && (LookupType == 8)) + { + kbts_reverse_chain_substitution *Subst = (kbts_reverse_chain_substitution *)Base; + kbts_unpacked_reverse_chain_substitution Unpacked = kbts_UnpackReverseChainSubstitution(Subst, 0); + + SubtableInfo.MinimumBacktrackPlusOne = KBTS_MIN(SubtableInfo.MinimumBacktrackPlusOne - 1, Unpacked.BacktrackCount) + 1; + SubtableInfo.MinimumFollowupPlusOne = KBTS_MIN(SubtableInfo.MinimumFollowupPlusOne - 1, Unpacked.LookaheadCount) + 1; + + KBTS_FOR(BacktrackIndex, 0, Unpacked.BacktrackCount) + { + kbts_cover_glyph_result BacktrackCover = kbts_CoverGlyph(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.BacktrackCoverageOffsets[BacktrackIndex]), Glyph.Id); + if(BacktrackCover.Valid) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + KBTS_FOR(LookaheadIndex, 0, Unpacked.LookaheadCount) + { + kbts_cover_glyph_result LookaheadCover = kbts_CoverGlyph(KBTS_POINTER_OFFSET(kbts_coverage, Subst, Unpacked.LookaheadCoverageOffsets[LookaheadIndex]), Glyph.Id); + if(LookaheadCover.Valid) + { + InSecondary = 1; + goto DoneCheckingForInclusion; + } + } + } + DoneCheckingForInclusion:; + + if(InPrimary) + { + kbts_un FlatIndex = RunningLookupIndex * GlyphCount + GlyphIndex; + kbts_un WordIndex = FlatIndex / 32; + kbts_un BitIndex = FlatIndex % 32; + GlyphLookupMatrix[WordIndex] |= (1 << BitIndex); + } + if(InPrimary || InSecondary) + { + kbts_un FlatIndex = RunningSubtableIndex * GlyphCount + GlyphIndex; + kbts_un WordIndex = FlatIndex / 32; + kbts_un BitIndex = FlatIndex % 32; + GlyphLookupSubtableMatrix[WordIndex] |= (1 << BitIndex); + } + } + + SubtableInfos[RunningSubtableIndex] = SubtableInfo; + RunningSubtableIndex += 1; + } + + RunningLookupIndex += 1; + } + } + } + + Font->SubtableInfos = SubtableInfos; + Font->GlyphLookupMatrix = GlyphLookupMatrix; + Font->GlyphLookupSubtableMatrix = GlyphLookupSubtableMatrix; + Font->LookupSubtableIndexOffsets = LookupSubtableIndexOffsets; + Font->GposLookupIndexOffset = (kbts_u32)GposLookupIndexOffset; + Font->GlyphCount = (kbts_u32)GlyphCount; + } + + return kbts_FontIsValid(Font); +} + +KBTS_EXPORT int kbts_FontIsValid(kbts_font *Font) +{ + int Result = !Font->Error; + return Result; +} + +#ifndef KB_TEXT_SHAPE_NO_CRT +KBTS_EXPORT kbts_font kbts_FontFromFile(const char *FileName) +{ + kbts_font Result = KBTS_ZERO; + + FILE *File; +# ifndef _MSC_VER + File = fopen(FileName, "rb"); +# else + fopen_s(&File, FileName, "rb"); +# endif + + if(File) + { + fseek(File, 0, SEEK_END); + long FileSize = ftell(File); + fseek(File, 0, SEEK_SET); + + void *Data = malloc((kbts_un)FileSize); + kbts_un Ok = fread(Data, (kbts_un)FileSize, 1, File); + fclose(File); + + if(Ok) + { + kbts_un ScratchSize = kbts_ReadFontHeader(&Result, Data, (kbts_un)FileSize); + + void *Scratch = malloc(ScratchSize); + kbts_un MemorySize = kbts_ReadFontData(&Result, Scratch, ScratchSize); + + void *Memory = Scratch; + if(MemorySize > ScratchSize) + { + free(Scratch); + Memory = malloc(MemorySize); + } + + kbts_PostReadFontInitialize(&Result, Memory, MemorySize); + } + } + + return Result; +} + +KBTS_EXPORT void kbts_FreeFont(kbts_font *Font) +{ + if(Font->FileBase) + { + free(Font->FileBase); + if(Font->GlyphLookupMatrix) + { + free(Font->GlyphLookupMatrix); // This frees everything else. + } + } +} +#endif + +KBTS_EXPORT int kbts_BreakStateIsValid(kbts_break_state *State) +{ + int Result = !(State->Flags & KBTS_BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE); + return Result; +} + +static void kbts_DoBreak(kbts_break_state *State, kbts_s32 Position, kbts_u8 Flags, kbts_direction Direction, kbts_script Script) +{ + if(kbts_BreakStateIsValid(State) && Flags && (State->BreakCount < KBTS_BREAK_REORDER_BUFFER_SIZE)) + { + if(State->BreakCount < KBTS_BREAK_REORDER_BUFFER_SIZE) + { + kbts_break Break = KBTS_ZERO; + Break.Position = State->CurrentPosition + (kbts_u32)Position; + Break.Flags = Flags; + Break.Direction = Direction; + Break.Script = Script; + + int Matched = 0; + KBTS_FOR(BreakIndex, 0, State->BreakCount) + { + kbts_break *Existing = &State->Breaks[BreakIndex]; + + if(Existing->Position == Break.Position) + { + Existing->Flags |= Break.Flags; + if(Break.Flags & KBTS_BREAK_FLAG_DIRECTION) Existing->Direction = Break.Direction; + if(Break.Flags & KBTS_BREAK_FLAG_SCRIPT) Existing->Script = Break.Script; + Matched = 1; + break; + } + else if(Existing->Position < Break.Position) + { + kbts_break Swap = *Existing; + *Existing = Break; + Break = Swap; + } + } + State->Breaks[State->BreakCount] = Break; + State->BreakCount += !Matched; + } + else + { + // This should never happen as long as we call Break() after every BreakAddCodepoint(). + State->Flags |= KBTS_BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE; + } + } +} + +// The line break state is a 4-character history. Each character is a bags of 12 bits (padded to 16 bits). +// Each character specifies allowed and required breaks on 6 levels of priority. +// A required break implies an allowed break. +// A priority N break implies priority 0..N-1 breaks. +enum { + KBTS_LINE_BREAK_ALLOWED0 = 1, + KBTS_LINE_BREAK_ALLOWED1 = 3, + KBTS_LINE_BREAK_ALLOWED2 = 7, + KBTS_LINE_BREAK_ALLOWED3 = 0xF, + KBTS_LINE_BREAK_ALLOWED4 = 0x1F, + KBTS_LINE_BREAK_ALLOWED5 = 0x3F, + KBTS_LINE_BREAK_REQUIRED0 = (1 << 6) | KBTS_LINE_BREAK_ALLOWED0, + KBTS_LINE_BREAK_REQUIRED1 = (3 << 6) | KBTS_LINE_BREAK_ALLOWED1, + KBTS_LINE_BREAK_REQUIRED2 = (7 << 6) | KBTS_LINE_BREAK_ALLOWED2, + KBTS_LINE_BREAK_REQUIRED3 = (0xF << 6) | KBTS_LINE_BREAK_ALLOWED3, + KBTS_LINE_BREAK_REQUIRED4 = (0x1F << 6) | KBTS_LINE_BREAK_ALLOWED4, + KBTS_LINE_BREAK_REQUIRED5 = (0x3F << 6) | KBTS_LINE_BREAK_ALLOWED5, + KBTS_LINE_BREAK_REQUIRED_MASK = 0x3F << 6, + KBTS_LINE_BREAK_ALLOWED_MASK = 0x3F, + KBTS_LINE_BREAK_MASK = KBTS_LINE_BREAK_REQUIRED_MASK | KBTS_LINE_BREAK_ALLOWED_MASK, +}; + +static void kbts_DoLineBreak(kbts_break_state *State, int Position, kbts_u64 EffectiveLineBreaks, int Rtl, kbts_script Script) +{ + if(EffectiveLineBreaks & KBTS_LINE_BREAK_MASK) + { + kbts_u8 Flags = 0; + if(EffectiveLineBreaks & KBTS_LINE_BREAK_ALLOWED_MASK) Flags |= KBTS_BREAK_FLAG_LINE_SOFT; + if(EffectiveLineBreaks & KBTS_LINE_BREAK_REQUIRED_MASK) Flags |= KBTS_BREAK_FLAG_LINE_HARD; + + kbts_DoBreak(State, Position, Flags, Rtl, Script); + } +} + +static void kbts_BreakAddCodepoint_(kbts_break_state *State, kbts_u32 Codepoint, kbts_u32 PositionIncrement, int MaybeEndOfText) +{ + // In these macros, and in FlagState, and in the way we buffer our state in general, + // index 0 means _after_ the codepoint currently being added, + // index 1 means _before_ the codepoint currently being added. +#define KBTS_BREAK(Flags, Position) do {FlagState |= ((Flags) << (8 * (Position)));} while(0) +#define KBTS_BREAK2(Flags, Position0, Position1) do {FlagState |= ((Flags) << (8 * (Position0))) | ((Flags) << (8 * (Position1)));} while(0) + if(!kbts_BreakStateIsValid(State)) return; + + kbts_u8 Script = kbts_GetUnicodeScript(Codepoint); + kbts_unicode_bidirectional_class BidirectionalClass = kbts_GetUnicodeBidirectionalClass(Codepoint); + kbts_u8 UnicodeFlags = kbts_GetUnicodeFlags(Codepoint); + kbts_u32 MatchingBracket = kbts_GetUnicodeMatchingBracket(Codepoint); + kbts_u8 GraphemeBreakClass = kbts_GetUnicodeGraphemeBreakClass(Codepoint); + kbts_u8 LineBreakClass = kbts_GetUnicodeLineBreakClass(Codepoint); + kbts_u8 WordBreakClass = kbts_GetUnicodeWordBreakClass(Codepoint); + kbts_u8 LastScript = State->LastScripts[0]; + kbts_u32 FlagState = State->FlagState << 8; + kbts_u8 LastLineBreakClass = State->LastLineBreakClass; + // Super secret cheat code for signaling end-of-text + int EndOfText = (Codepoint == 3) && MaybeEndOfText; + int StartOfText = !(State->Flags & KBTS_BREAK_STATE_FLAG_STARTED); + kbts_u32 LineBreakHistory = State->LineBreakHistory; + kbts_u32 WordBreakHistory = State->WordBreakHistory; + kbts_u8 LastWordBreakClass = State->LastWordBreakClass; + kbts_s16 WordBreak2PositionOffset = State->WordBreak2PositionOffset; + kbts_u8 LastWordBreakClassIncludingIgnored = State->LastWordBreakClassIncludingIgnored; + kbts_s16 PositionOffset2 = State->PositionOffset2; + kbts_s16 PositionOffset3 = State->PositionOffset3; + kbts_u32 Flags = State->Flags; + kbts_direction LastDirection = State->LastDirection; + + if(StartOfText) + { + LineBreakHistory = LastLineBreakClass = KBTS_LINE_BREAK_CLASS_SOT; + WordBreakHistory = LastWordBreakClass = KBTS_WORD_BREAK_CLASS_SOT; + } + + + if((Script == KBTS_SCRIPT_DEFAULT) || (Script == KBTS_SCRIPT_DEFAULT2)) + { + Script = LastScript; + } + + // Bracket pairing overrides default directions/scripts. + if(UnicodeFlags & KBTS_UNICODE_FLAG_OPEN_BRACKET) + { + if(State->BracketCount < KBTS_ARRAY_LENGTH(State->Brackets)) + { + kbts_bracket *Bracket = &State->Brackets[State->BracketCount++]; + + // @Incomplete: Canonicalize the bracket. + Bracket->Codepoint = Codepoint; + Bracket->Direction = KBTS_DIRECTION_NONE; + Bracket->Script = Script; + + State->Flags |= KBTS_BREAK_STATE_FLAG_LAST_WAS_BRACKET; + } + } + else if(UnicodeFlags & KBTS_UNICODE_FLAG_CLOSE_BRACKET) + { + if(State->BracketCount) + { + kbts_un FoundBracketIndex = 0; + kbts_bracket *FoundBracket = 0; + + // @Incomplete: Canonicalize the bracket. + KBTS_FOR(BracketIndex, 0, State->BracketCount) + { + kbts_bracket *Bracket = &State->Brackets[State->BracketCount - 1 - BracketIndex]; + + if(Bracket->Codepoint == MatchingBracket) + { + FoundBracket = Bracket; + FoundBracketIndex = State->BracketCount - 1 - BracketIndex; + + break; + } + } + + if(FoundBracket) + { + BidirectionalClass = FoundBracket->Direction; + Script = FoundBracket->Script; + + State->BracketCount = (kbts_u32)FoundBracketIndex; + } + } + } + + { // Direction breaking. + kbts_u8 Bidirectional2 = State->BidirectionalClass2; + kbts_u8 Bidirectional1 = State->BidirectionalClass1; + + switch(BidirectionalClass) + { + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_NSM: BidirectionalClass = Bidirectional1; break; + + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_L: + Flags &= ~(KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L | KBTS_BREAK_STATE_FLAG_SAW_AL_AFTER_LR); + break; + + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_R: + Flags |= KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L; + Flags &= ~KBTS_BREAK_STATE_FLAG_SAW_AL_AFTER_LR; + break; + + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_AL: + // Rule W3 occurs before W7, so we treat AL as R for the purposes of rule W7. + Flags |= (KBTS_BREAK_STATE_FLAG_SAW_AL_AFTER_LR | KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L); + BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_R; + break; + + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN: + if(Flags & KBTS_BREAK_STATE_FLAG_SAW_AL_AFTER_LR) + { + BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN; + goto CaseAn; + } + if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN) && ((Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_ES) || (Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS))) + { + Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN; + } + if(!(Flags & KBTS_BREAK_STATE_FLAG_SAW_R_AFTER_L)) + { + BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; + } + break; + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN: + CaseAn:; + if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN) && (Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS)) + { + Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN; + } + break; + case KBTS_UNICODE_BIDIRECTIONAL_CLASS_ET: + if(Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN) + { + BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN; + } + break; + } + + if(KBTS_IN_SET(BidirectionalClass, KBTS_SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_ET)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_ES)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_CS)))) + { + BidirectionalClass = KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI; + } + + if(Bidirectional1 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_NI) + { + if(KBTS_IN_SET(Bidirectional2, KBTS_SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_R)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN))) && + KBTS_IN_SET(BidirectionalClass, KBTS_SET32((KBTS_UNICODE_BIDIRECTIONAL_CLASS_R)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN)(KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN)))) + { + Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_R; + } + else if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_L) && (BidirectionalClass == KBTS_UNICODE_BIDIRECTIONAL_CLASS_L)) + { + Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; + } + else + { + if (State->MainDirection == KBTS_DIRECTION_LTR) Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; + else if(State->MainDirection == KBTS_DIRECTION_RTL) Bidirectional1 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_R; + } + } + + // These rules happen at the very end, so we wait until the last slot to apply them. + if((Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_AN) || (Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_EN)) + { + Bidirectional2 = KBTS_UNICODE_BIDIRECTIONAL_CLASS_L; + } + + // @Incomplete: ET+ EN -> EN+ EN + kbts_direction Direction = KBTS_DIRECTION_NONE; + if(Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_L) Direction = KBTS_DIRECTION_LTR; + else if(Bidirectional2 == KBTS_UNICODE_BIDIRECTIONAL_CLASS_R) Direction = KBTS_DIRECTION_RTL; + if(Direction && (Direction != LastDirection)) + { + LastDirection = Direction; + KBTS_BREAK(KBTS_BREAK_FLAG_DIRECTION, 3); + + if(!State->MainDirection) + { + State->MainDirection = (kbts_u8)Direction; + } + } + + State->BidirectionalClass2 = Bidirectional1; + State->BidirectionalClass1 = BidirectionalClass; + } + + if(Script != LastScript) + { + KBTS_BREAK(KBTS_BREAK_FLAG_SCRIPT, 1); + } + + { // Grapheme breaking. + if(EndOfText && !StartOfText) + { + KBTS_BREAK(KBTS_BREAK_FLAG_GRAPHEME, 1); + State->GraphemeBreakState = KBTS_GRAPHEME_BREAK_STATE_START; + } + else + { + kbts_u8 GraphemeBreakState = kbts_GraphemeBreakTransition[GraphemeBreakClass][State->GraphemeBreakState]; + switch(GraphemeBreakState) + { + case KBTS_GRAPHEME_BREAK_STATE_b01: KBTS_BREAK2(KBTS_BREAK_FLAG_GRAPHEME, 1, 0); GraphemeBreakState = KBTS_GRAPHEME_BREAK_STATE_START; break; + case KBTS_GRAPHEME_BREAK_STATE_b0: KBTS_BREAK(KBTS_BREAK_FLAG_GRAPHEME, 0); GraphemeBreakState = KBTS_GRAPHEME_BREAK_STATE_START; break; + + case KBTS_GRAPHEME_BREAK_STATE_b1: + case KBTS_GRAPHEME_BREAK_STATE_b1toCR: + case KBTS_GRAPHEME_BREAK_STATE_b1toL: + case KBTS_GRAPHEME_BREAK_STATE_b1toLVxV: + case KBTS_GRAPHEME_BREAK_STATE_b1toLVTxT: + case KBTS_GRAPHEME_BREAK_STATE_b1toIndicConsonantxIndicLinker: + case KBTS_GRAPHEME_BREAK_STATE_PADDING0: // Padding values are just here to help the compiler. + case KBTS_GRAPHEME_BREAK_STATE_PADDING1: + case KBTS_GRAPHEME_BREAK_STATE_b1toExtendedPictographic: + case KBTS_GRAPHEME_BREAK_STATE_PADDING2: + case KBTS_GRAPHEME_BREAK_STATE_PADDING3: + case KBTS_GRAPHEME_BREAK_STATE_b1toRI: + case KBTS_GRAPHEME_BREAK_STATE_b1toSKIP: + KBTS_BREAK(KBTS_BREAK_FLAG_GRAPHEME, 1); + GraphemeBreakState -= KBTS_GRAPHEME_BREAK_STATE_b1; + } + + State->GraphemeBreakState = GraphemeBreakState; + } + } + + // Word breaks. + // We buffer 3 characters for word breaks. + // Each character gets 3 bits (padded to 4) representing 3 levels of priority. + #define KBTS_WORD_BREAK_BITS(Priority, Position) (((1 << ((Priority) + 1)) - 1) << ((Position) * 4)) + #define KBTS_C2(A, B) case (KBTS_WORD_BREAK_CLASS_##A << 8) | (KBTS_WORD_BREAK_CLASS_##B) + #define KBTS_C3(A, B, C) case (KBTS_WORD_BREAK_CLASS_##A << 16) | (KBTS_WORD_BREAK_CLASS_##B << 8) | (KBTS_WORD_BREAK_CLASS_##C) + + // Ignore [EX FO ZWJ] after ^[_sot_ CR LF NL]. + // @Cleanup: This is the only time we explicitly use EX and FO. They can be merged. + if(KBTS_IN_SET(WordBreakClass, KBTS_SET32((KBTS_WORD_BREAK_CLASS_EX)(KBTS_WORD_BREAK_CLASS_FO)(KBTS_WORD_BREAK_CLASS_ZWJ))) && + !KBTS_IN_SET(LastWordBreakClass, KBTS_SET32((KBTS_WORD_BREAK_CLASS_SOT)(KBTS_WORD_BREAK_CLASS_CR)(KBTS_WORD_BREAK_CLASS_LF)(KBTS_WORD_BREAK_CLASS_NL)))) + { + WordBreak2PositionOffset -= PositionIncrement; + State->WordBreak2PositionOffset = WordBreak2PositionOffset; + } + else + { + kbts_u32 WordBreaks = State->WordBreaks << 4; + kbts_u32 WordUnbreaks = State->WordUnbreaks << 4; + WordBreakHistory = (WordBreakHistory << 8) | WordBreakClass; + + WordBreaks |= KBTS_WORD_BREAK_BITS(0, 1) | KBTS_WORD_BREAK_BITS(0, 0); + if(StartOfText) + { + WordBreaks |= KBTS_WORD_BREAK_BITS(2, 1); + } + + if(KBTS_IN_SET(WordBreakClass, KBTS_SET32((KBTS_WORD_BREAK_CLASS_CR)(KBTS_WORD_BREAK_CLASS_LF)(KBTS_WORD_BREAK_CLASS_NL)))) + { + WordBreaks |= KBTS_WORD_BREAK_BITS(1, 1) | KBTS_WORD_BREAK_BITS(1, 0); + } + else if(KBTS_IN_SET(WordBreakClass, KBTS_SET32((KBTS_WORD_BREAK_CLASS_Oep)(KBTS_WORD_BREAK_CLASS_ALep)))) + { + // ZWJ x {Extended_Pictographic} + if(LastWordBreakClassIncludingIgnored == KBTS_WORD_BREAK_CLASS_ZWJ) + { + WordUnbreaks |= KBTS_WORD_BREAK_BITS(0, 1); + } + } + + switch(WordBreakHistory & 0xFFFF) + { + KBTS_C2(CR, LF): WordUnbreaks |= KBTS_WORD_BREAK_BITS(1, 1); break; + + KBTS_C2(WSS, WSS): + // WSS x WSS is a special rule, because it is supposed to happen _before_ ignores. + if(WordBreak2PositionOffset >= 0) WordUnbreaks |= KBTS_WORD_BREAK_BITS(0, 1); + break; + + // (RI RI)* RI x RI + KBTS_C2(RI, RI): + WordBreakHistory = 0; + // fallthrough + KBTS_C2(HL, SQ): + KBTS_C2(ALnep, ALnep): KBTS_C2(ALnep, ALep): KBTS_C2(ALnep, HL): KBTS_C2(ALnep, NM): KBTS_C2(ALnep, ENL): + KBTS_C2(ALep, ALnep): KBTS_C2(ALep, ALep): KBTS_C2(ALep, HL): KBTS_C2(ALep, NM): KBTS_C2(ALep, ENL): + KBTS_C2(HL, ALnep): KBTS_C2(HL, ALep): KBTS_C2(HL, HL): KBTS_C2(HL, NM): KBTS_C2(HL, ENL): + KBTS_C2(NM, ALnep): KBTS_C2(NM, ALep): KBTS_C2(NM, HL): KBTS_C2(NM, NM): KBTS_C2(NM, ENL): + KBTS_C2(KA, KA): KBTS_C2(KA, ENL): + KBTS_C2(ENL, ALnep): KBTS_C2(ENL, ALep): KBTS_C2(ENL, HL): KBTS_C2(ENL, NM): KBTS_C2(ENL, KA): KBTS_C2(ENL, ENL): + WordUnbreaks |= KBTS_WORD_BREAK_BITS(0, 1); break; + } + + switch(WordBreakHistory & 0xFFFFFF) + { + KBTS_C3(ALnep, ML, ALnep): KBTS_C3(ALnep, ML, ALep): KBTS_C3(ALnep, ML, HL): + KBTS_C3(ALnep, MNL, ALnep): KBTS_C3(ALnep, MNL, ALep): KBTS_C3(ALnep, MNL, HL): + KBTS_C3(ALnep, SQ, ALnep): KBTS_C3(ALnep, SQ, ALep): KBTS_C3(ALnep, SQ, HL): + KBTS_C3(ALep, ML, ALnep): KBTS_C3(ALep, ML, ALep): KBTS_C3(ALep, ML, HL): + KBTS_C3(ALep, MNL, ALnep): KBTS_C3(ALep, MNL, ALep): KBTS_C3(ALep, MNL, HL): + KBTS_C3(ALep, SQ, ALnep): KBTS_C3(ALep, SQ, ALep): KBTS_C3(ALep, SQ, HL): + KBTS_C3(HL, ML, ALnep): KBTS_C3(HL, ML, ALep): KBTS_C3(HL, ML, HL): + KBTS_C3(HL, MNL, ALnep): KBTS_C3(HL, MNL, ALep): KBTS_C3(HL, MNL, HL): + KBTS_C3(HL, SQ, ALnep): KBTS_C3(HL, SQ, ALep): KBTS_C3(HL, SQ, HL): + KBTS_C3(HL, DQ, HL): + KBTS_C3(NM, MN, NM): KBTS_C3(NM, MNL, NM): KBTS_C3(NM, SQ, NM): + WordUnbreaks |= KBTS_WORD_BREAK_BITS(0, 1) | KBTS_WORD_BREAK_BITS(0, 2); break; + } + + kbts_u32 EffectiveWordBreaks = WordBreaks & ~WordUnbreaks; + if(EffectiveWordBreaks & KBTS_WORD_BREAK_BITS(2, 2)) + { + kbts_DoBreak(State, PositionOffset2 + WordBreak2PositionOffset, KBTS_BREAK_FLAG_WORD, 0, 0); + } + if(EndOfText) + { + // Always break at the end of the text. + KBTS_BREAK(KBTS_BREAK_FLAG_WORD, 1); + // Do not break after the end of the text. + } + + State->WordBreaks = (kbts_u16)WordBreaks; + State->WordUnbreaks = (kbts_u16)WordUnbreaks; + State->LastWordBreakClass = WordBreakClass; + State->WordBreak2PositionOffset = 0; + State->WordBreakHistory = WordBreakHistory; + } + State->LastWordBreakClassIncludingIgnored = WordBreakClass; + #undef KBTS_WORD_BREAK_BITS + #undef KBTS_C2 + #undef KBTS_C3 + + kbts_s16 LineBreak3PositionOffset = State->LineBreak3PositionOffset; + kbts_s16 LineBreak2PositionOffset = State->LineBreak2PositionOffset; + { // Line breaking. + kbts_u64 LineBreaks = State->LineBreaks << 16; + kbts_u64 LineUnbreaks = State->LineUnbreaks << 16; + kbts_u64 LineUnbreaksAsync = State->LineUnbreaksAsync << 16; + + #define KBTS_C1(A) case KBTS_LINE_BREAK_CLASS_##A + #define KBTS_C2(A, B) case (KBTS_LINE_BREAK_CLASS_##A << 8) | (KBTS_LINE_BREAK_CLASS_##B) + #define KBTS_C3(A, B, C) case (KBTS_LINE_BREAK_CLASS_##A << 16) | (KBTS_LINE_BREAK_CLASS_##B << 8) | KBTS_LINE_BREAK_CLASS_##C + #define KBTS_C4(A, B, C, D) case (KBTS_LINE_BREAK_CLASS_##A << 24) | (KBTS_LINE_BREAK_CLASS_##B << 16) | (KBTS_LINE_BREAK_CLASS_##C << 8) | KBTS_LINE_BREAK_CLASS_##D + #define KBTS_REQUIRED_LINE_BREAK(Priority, Position) do {LineBreaks |= (kbts_u64)KBTS_LINE_BREAK_REQUIRED##Priority << ((Position) * 16);} while(0) + #define KBTS_LINE_BREAK(Priority, Position) do {LineBreaks |= (kbts_u64)KBTS_LINE_BREAK_ALLOWED##Priority << ((Position) * 16);} while(0) + #define KBTS_LINE_UNBREAK(Priority, Position) do {LineUnbreaks |= (kbts_u64)KBTS_LINE_BREAK_REQUIRED##Priority << ((Position) * 16);} while(0) + #define KBTS_LINE_UNBREAK_ASYNC(Priority, Position) do {LineUnbreaksAsync |= (kbts_u64)KBTS_LINE_BREAK_REQUIRED##Priority << ((Position) * 16);} while(0) + + if(EndOfText) + { + // Depending on the current line break state, we might need very different breaks. + // For now, we copy the transitions from the first row of the transition table, but + // we might want to special-case these. + LineBreakClass = KBTS_LINE_BREAK_CLASS_Onea; + } + else if(LineBreakClass > KBTS_LINE_BREAK_CLASS_COUNT) + { + // These guys have special rules. + if((LineBreakClass == KBTS_LINE_BREAK_CLASS_CM) || (LineBreakClass == KBTS_LINE_BREAK_CLASS_ZWJ)) + { + if(LineBreakClass == KBTS_LINE_BREAK_CLASS_ZWJ) + { + KBTS_LINE_UNBREAK_ASYNC(3, 0); + } + + switch(LastLineBreakClass) + { + case KBTS_LINE_BREAK_CLASS_SOT: + case KBTS_LINE_BREAK_CLASS_BK: + case KBTS_LINE_BREAK_CLASS_CR: + case KBTS_LINE_BREAK_CLASS_LF: + case KBTS_LINE_BREAK_CLASS_NL: + case KBTS_LINE_BREAK_CLASS_SP: + case KBTS_LINE_BREAK_CLASS_ZW: + LineBreakClass = KBTS_LINE_BREAK_CLASS_ALnea; + break; + + default: + // The standard says to treat X [CM ZWJ]* as X. + // This means that we need to hoist [CM ZWJ] completely out of the line breaking logic. + // However, we give our results in index offsets relative to the current glyph, so we + // do have to acknowledge that we are skipping glyphs. + goto LineBreakAbsorbCharacter; + } + } + else if(LineBreakClass == KBTS_LINE_BREAK_CLASS_CJ) + { + LineBreakClass = State->JapaneseLineBreakStyle == KBTS_JAPANESE_LINE_BREAK_STYLE_STRICT ? KBTS_LINE_BREAK_CLASS_NSea : KBTS_LINE_BREAK_CLASS_IDea; + } + } + + if(LastLineBreakClass == LineBreakClass) + { + // @Incomplete: Handle repeats that aren't SP*. + if(LineBreakClass == KBTS_LINE_BREAK_CLASS_SP) + { + goto LineBreakAbsorbCharacter; + } + } + + LineBreakHistory = (LineBreakHistory << 8) | LineBreakClass; + + if(EndOfText) + { + // Always break at the end of text. + KBTS_REQUIRED_LINE_BREAK(5, 1); + + // x QUPf _eot_ + if((LineBreakHistory & 0xFF00) == (KBTS_LINE_BREAK_CLASS_QUPf << 8)) + { + KBTS_LINE_UNBREAK(3, 2); + } + } + + KBTS_LINE_BREAK(0, 0); + KBTS_LINE_BREAK(0, 1); + + switch(LineBreakClass) + { + KBTS_C1(BK): + KBTS_C1(CR): + KBTS_C1(LF): + KBTS_C1(NL): KBTS_LINE_UNBREAK(4, 1); KBTS_REQUIRED_LINE_BREAK(5, 0); break; + KBTS_C1(ZW): KBTS_LINE_BREAK(4, 0); KBTS_LINE_UNBREAK(4, 1); break; + KBTS_C1(BB): KBTS_LINE_UNBREAK(0, 0); break; + + KBTS_C1(GLea): + KBTS_C1(GLnea): + KBTS_C1(OPea): + KBTS_C1(OPnea): KBTS_LINE_UNBREAK(3, 0); break; + + KBTS_C1(WJ): KBTS_LINE_UNBREAK(3, 0); KBTS_LINE_UNBREAK(3, 1); break; + + KBTS_C1(CLea): + KBTS_C1(CLnea): + KBTS_C1(CPea): + KBTS_C1(CPnea): + KBTS_C1(EXea): + KBTS_C1(EXnea): + KBTS_C1(SY): KBTS_LINE_UNBREAK(3, 1); break; + + KBTS_C1(IS): KBTS_LINE_UNBREAK(2, 1); break; + + KBTS_C1(SP): KBTS_LINE_UNBREAK(4, 1); KBTS_LINE_BREAK(2, 0); break; + + KBTS_C1(QU): KBTS_LINE_UNBREAK(1, 1); KBTS_LINE_UNBREAK(1, 0); break; + KBTS_C1(QUPi): KBTS_LINE_UNBREAK(1, 0); break; + KBTS_C1(QUPf): KBTS_LINE_UNBREAK(1, 1); break; + KBTS_C1(CB): KBTS_LINE_BREAK(1, 0); KBTS_LINE_BREAK(1, 1); break; + + KBTS_C1(BAnea): + KBTS_C1(BAea): + KBTS_C1(HYPHEN): + KBTS_C1(HY): + KBTS_C1(NSnea): + KBTS_C1(NSea): + KBTS_C1(INnea): + KBTS_C1(INea): + KBTS_LINE_UNBREAK(0, 1); break; + } + + switch(LineBreakHistory & 0xFFFF) + { + KBTS_C2(CR, LF): KBTS_LINE_UNBREAK(5, 1); break; + KBTS_C2(ZW, SP): KBTS_LINE_BREAK(4, 0); break; + + + KBTS_C2(OPea, QUPi): + KBTS_C2(GLea, QUPi): + KBTS_C2(OPea, SP): + KBTS_C2(OPnea,SP): + KBTS_LINE_UNBREAK(3, 0); + break; + + KBTS_C2(SOT, QUPi): + KBTS_C2(BK, QUPi): + KBTS_C2(CR, QUPi): + KBTS_C2(LF, QUPi): + KBTS_C2(NL, QUPi): + KBTS_C2(SP, QUPi): + KBTS_C2(ZW, QUPi): + KBTS_C2(GLnea, QUPi): + KBTS_C2(QU, QUPi): + KBTS_C2(OPnea, QUPi): + KBTS_LINE_UNBREAK(1, 1); + KBTS_LINE_UNBREAK(1, 0); + KBTS_LINE_UNBREAK(3, 0); + break; + + KBTS_C2(QUPi, QUPi): + KBTS_LINE_UNBREAK(3, 0); + KBTS_LINE_UNBREAK(1, 2); + KBTS_LINE_UNBREAK(1, 1); + KBTS_LINE_UNBREAK(1, 0); + break; + + KBTS_C2(QUPf, QUPi): + KBTS_LINE_UNBREAK(1, 1); + KBTS_LINE_UNBREAK(1, 0); + KBTS_LINE_UNBREAK(3, 0); + KBTS_LINE_UNBREAK(3, 2); + KBTS_LINE_UNBREAK(1, 1); + break; + + KBTS_C2(QUPf, GLnea): + KBTS_LINE_UNBREAK(3, 2); + KBTS_LINE_UNBREAK(3, 1); + KBTS_LINE_UNBREAK(1, 1); + break; + + KBTS_C2(QUPf, BK): + KBTS_C2(QUPf, CR): + KBTS_C2(QUPf, LF): + KBTS_C2(QUPf, NL): + KBTS_C2(QUPf, ZW): + KBTS_C2(QUPf, WJ): + KBTS_C2(QUPf, CLnea): + KBTS_C2(QUPf, CPnea): + KBTS_C2(QUPf, EXnea): + KBTS_C2(QUPf, SY): + KBTS_C2(QUPf, IS): + KBTS_C2(QUPf, SP): + KBTS_LINE_UNBREAK(3, 2); + KBTS_LINE_UNBREAK(1, 1); + break; + + KBTS_C2(QUPf, QUPf): + KBTS_LINE_UNBREAK(3, 2); + KBTS_LINE_UNBREAK(1, 1); + KBTS_LINE_UNBREAK(1, 0); + break; + + KBTS_C2(QUPf, QU): + KBTS_LINE_UNBREAK(3, 2); + KBTS_LINE_UNBREAK(1, 1); + KBTS_LINE_UNBREAK(1, 0); + break; + + KBTS_C2(QUPf, GLea): + KBTS_LINE_UNBREAK(3, 2); + KBTS_LINE_UNBREAK(3, 1); + break; + + KBTS_C2(QUPf, CPea): + KBTS_C2(QUPf, CLea): + KBTS_C2(QUPf, EXea): + KBTS_LINE_UNBREAK(3, 2); + break; + + KBTS_C2(QUPi, QU): + KBTS_LINE_UNBREAK(1, 1); + KBTS_LINE_UNBREAK(1, 0); + KBTS_LINE_UNBREAK(1, 2); + break; + + KBTS_C2(QUPi, QUPf): + KBTS_LINE_UNBREAK(1, 1); + KBTS_LINE_UNBREAK(1, 0); + KBTS_LINE_UNBREAK(1, 2); + break; + + KBTS_C2(QUPi, GLnea): + KBTS_LINE_UNBREAK(1, 2); + KBTS_LINE_UNBREAK(3, 1); + break; + + KBTS_C2(QUPi, Onea): KBTS_C2(QUPi, Ope): KBTS_C2(QUPi, BK): KBTS_C2(QUPi, CR): KBTS_C2(QUPi, LF): KBTS_C2(QUPi, NL): KBTS_C2(QUPi, SP): KBTS_C2(QUPi, ZW): + KBTS_C2(QUPi, WJ): KBTS_C2(QUPi, CLnea): KBTS_C2(QUPi, CPnea): KBTS_C2(QUPi, EXnea): KBTS_C2(QUPi, SY): KBTS_C2(QUPi, BAnea): + KBTS_C2(QUPi, OPnea): KBTS_C2(QUPi, IS): KBTS_C2(QUPi, NSnea): KBTS_C2(QUPi, B2): KBTS_C2(QUPi, CB): + KBTS_C2(QUPi, HY): KBTS_C2(QUPi, HYPHEN): KBTS_C2(QUPi, INnea): KBTS_C2(QUPi, BB): KBTS_C2(QUPi, HL): KBTS_C2(QUPi, ALnea): KBTS_C2(QUPi, NU): KBTS_C2(QUPi, PRnea): + KBTS_C2(QUPi, IDnea): KBTS_C2(QUPi, IDpe): KBTS_C2(QUPi, EBnea): KBTS_C2(QUPi, POnea): KBTS_C2(QUPi, JV): KBTS_C2(QUPi, JT): KBTS_C2(QUPi, AP): KBTS_C2(QUPi, AK): + KBTS_C2(QUPi, DOTTED_CIRCLE): KBTS_C2(QUPi, AS): KBTS_C2(QUPi, VF): KBTS_C2(QUPi, VI): KBTS_C2(QUPi, RI): + KBTS_LINE_UNBREAK(1, 2); break; + + + KBTS_C2(QUPf, Onea): KBTS_C2(QUPf, Ope): + KBTS_C2(QUPf, BAnea): + KBTS_C2(QUPf, OPnea): KBTS_C2(QUPf, NSnea): KBTS_C2(QUPf, B2): KBTS_C2(QUPf, CB): + KBTS_C2(QUPf, HY): KBTS_C2(QUPf, HYPHEN): KBTS_C2(QUPf, INnea): KBTS_C2(QUPf, BB): KBTS_C2(QUPf, HL): KBTS_C2(QUPf, ALnea): KBTS_C2(QUPf, NU): KBTS_C2(QUPf, PRnea): + KBTS_C2(QUPf, IDnea): KBTS_C2(QUPf, IDpe): KBTS_C2(QUPf, EBnea): KBTS_C2(QUPf, POnea): KBTS_C2(QUPf, JV): KBTS_C2(QUPf, JT): KBTS_C2(QUPf, AP): KBTS_C2(QUPf, AK): + KBTS_C2(QUPf, DOTTED_CIRCLE): KBTS_C2(QUPf, AS): KBTS_C2(QUPf, VF): KBTS_C2(QUPf, VI): KBTS_C2(QUPf, RI): + KBTS_LINE_UNBREAK(1, 1); break; + + KBTS_C2(SOT, QU): KBTS_C2(SOT, QUPf): + KBTS_C2(Onea, QU): KBTS_C2(Ope, QU): KBTS_C2(BK, QU): KBTS_C2(CR, QU): KBTS_C2(LF, QU): KBTS_C2(NL, QU): KBTS_C2(SP, QU): KBTS_C2(ZW, QU): + KBTS_C2(WJ, QU): KBTS_C2(GLnea, QU): KBTS_C2(CLnea, QU): KBTS_C2(CPnea, QU): KBTS_C2(EXnea, QU): KBTS_C2(SY, QU): KBTS_C2(BAnea, QU): + KBTS_C2(OPnea, QU): KBTS_C2(QU, QU): KBTS_C2(IS, QU): KBTS_C2(NSnea, QU): KBTS_C2(B2, QU): KBTS_C2(CB, QU): + KBTS_C2(HY, QU): KBTS_C2(HYPHEN, QU): KBTS_C2(INnea, QU): KBTS_C2(BB, QU): KBTS_C2(HL, QU): KBTS_C2(ALnea, QU): KBTS_C2(NU, QU): KBTS_C2(PRnea, QU): + KBTS_C2(IDnea, QU): KBTS_C2(IDpe, QU): KBTS_C2(EBnea, QU): KBTS_C2(POnea, QU): KBTS_C2(JV, QU): KBTS_C2(JT, QU): KBTS_C2(AP, QU): KBTS_C2(AK, QU): + KBTS_C2(DOTTED_CIRCLE, QU): KBTS_C2(AS, QU): KBTS_C2(VF, QU): KBTS_C2(VI, QU): KBTS_C2(RI, QU): + KBTS_C2(Onea, QUPi): KBTS_C2(Ope, QUPi): + KBTS_C2(WJ, QUPi): KBTS_C2(CLnea, QUPi): KBTS_C2(CPnea, QUPi): KBTS_C2(EXnea, QUPi): KBTS_C2(SY, QUPi): KBTS_C2(BAnea, QUPi): + KBTS_C2(IS, QUPi): + KBTS_C2(NSnea, QUPi): + KBTS_C2(B2, QUPi): + KBTS_C2(CB, QUPi): + KBTS_C2(HY, QUPi): KBTS_C2(HYPHEN, QUPi): KBTS_C2(INnea, QUPi): KBTS_C2(BB, QUPi): KBTS_C2(HL, QUPi): KBTS_C2(ALnea, QUPi): KBTS_C2(NU, QUPi): KBTS_C2(PRnea, QUPi): + KBTS_C2(IDnea, QUPi): KBTS_C2(IDpe, QUPi): KBTS_C2(EBnea, QUPi): KBTS_C2(POnea, QUPi): KBTS_C2(JV, QUPi): KBTS_C2(JT, QUPi): KBTS_C2(AP, QUPi): KBTS_C2(AK, QUPi): + KBTS_C2(DOTTED_CIRCLE, QUPi): KBTS_C2(AS, QUPi): KBTS_C2(VF, QUPi): KBTS_C2(VI, QUPi): KBTS_C2(RI, QUPi): + KBTS_C2(Onea, QUPf): KBTS_C2(Ope, QUPf): KBTS_C2(BK, QUPf): KBTS_C2(CR, QUPf): KBTS_C2(LF, QUPf): KBTS_C2(NL, QUPf): KBTS_C2(SP, QUPf): KBTS_C2(ZW, QUPf): + KBTS_C2(WJ, QUPf): KBTS_C2(GLnea, QUPf): KBTS_C2(CLnea, QUPf): KBTS_C2(CPnea, QUPf): KBTS_C2(EXnea, QUPf): KBTS_C2(SY, QUPf): KBTS_C2(BAnea, QUPf): + KBTS_C2(OPnea, QUPf): KBTS_C2(QU, QUPf): KBTS_C2(IS, QUPf): KBTS_C2(NSnea, QUPf): KBTS_C2(B2, QUPf): KBTS_C2(CB, QUPf): + KBTS_C2(HY, QUPf): KBTS_C2(HYPHEN, QUPf): KBTS_C2(INnea, QUPf): KBTS_C2(BB, QUPf): KBTS_C2(HL, QUPf): KBTS_C2(ALnea, QUPf): KBTS_C2(NU, QUPf): KBTS_C2(PRnea, QUPf): + KBTS_C2(IDnea, QUPf): KBTS_C2(IDpe, QUPf): KBTS_C2(EBnea, QUPf): KBTS_C2(POnea, QUPf): KBTS_C2(JV, QUPf): KBTS_C2(JT, QUPf): KBTS_C2(AP, QUPf): KBTS_C2(AK, QUPf): + KBTS_C2(DOTTED_CIRCLE, QUPf): KBTS_C2(AS, QUPf): KBTS_C2(VF, QUPf): KBTS_C2(VI, QUPf): KBTS_C2(RI, QUPf): + KBTS_LINE_UNBREAK(1, 1); KBTS_LINE_UNBREAK(1, 0); break; + + KBTS_C2(HL, NU): KBTS_C2(ALnea, NU): KBTS_C2(ALea, NU): KBTS_C2(DOTTED_CIRCLE, NU): + KBTS_C2(NU, ALnea): KBTS_C2(NU, ALea): KBTS_C2(NU, DOTTED_CIRCLE): KBTS_C2(NU, HL): + KBTS_C2(PRnea, IDnea): KBTS_C2(PRnea, IDea): KBTS_C2(PRnea, IDpe): KBTS_C2(PRnea, EBea): KBTS_C2(PRnea, EBnea): KBTS_C2(PRnea, EM): + KBTS_C2(PRea, IDnea): KBTS_C2(PRea, IDea): KBTS_C2(PRea, IDpe): KBTS_C2(PRea, EBea): KBTS_C2(PRea, EBnea): KBTS_C2(PRea, EM): + KBTS_C2(IDnea, POea): KBTS_C2(IDnea, POnea): KBTS_C2(IDea, POea): KBTS_C2(IDea, POnea): KBTS_C2(IDpe, POea): KBTS_C2(IDpe, POnea): + KBTS_C2(EBnea, POea): KBTS_C2(EBnea, POnea): KBTS_C2(EBea, POea): KBTS_C2(EBea, POnea): KBTS_C2(EM, POea): KBTS_C2(EM, POnea): + KBTS_C2(PRea, ALea): KBTS_C2(PRea, ALnea): KBTS_C2(PRea, DOTTED_CIRCLE): KBTS_C2(PRea, HL): + KBTS_C2(PRnea, ALea): KBTS_C2(PRnea, ALnea): KBTS_C2(PRnea, DOTTED_CIRCLE): KBTS_C2(PRnea, HL): + KBTS_C2(POea, ALea): KBTS_C2(POea, ALnea): KBTS_C2(POea, DOTTED_CIRCLE): KBTS_C2(POea, HL): + KBTS_C2(POnea, ALea): KBTS_C2(POnea, ALnea): KBTS_C2(POnea, DOTTED_CIRCLE): KBTS_C2(POnea, HL): + KBTS_C2(ALea, PRea): KBTS_C2(ALea, PRnea): KBTS_C2(ALea, POea): KBTS_C2(ALea, POnea): + KBTS_C2(ALnea, PRea): KBTS_C2(ALnea, PRnea): KBTS_C2(ALnea, POea): KBTS_C2(ALnea, POnea): + KBTS_C2(DOTTED_CIRCLE, PRea): KBTS_C2(DOTTED_CIRCLE, PRnea): KBTS_C2(DOTTED_CIRCLE, POea): KBTS_C2(DOTTED_CIRCLE, POnea): + KBTS_C2(HL, PRea): KBTS_C2(HL, PRnea): KBTS_C2(HL, POea): KBTS_C2(HL, POnea): + KBTS_C2(NU, POea): KBTS_C2(NU, POnea): KBTS_C2(NU, PRea): KBTS_C2(NU, PRnea): KBTS_C2(NU, NU): + KBTS_C2(POea, NU): KBTS_C2(POnea, NU): KBTS_C2(PRea, NU): KBTS_C2(PRnea, NU): + KBTS_C2(SY, HL): + KBTS_C2(JL, JL): KBTS_C2(JL, JV): KBTS_C2(JL, H2): KBTS_C2(JL, H3): + KBTS_C2(JV, JV): KBTS_C2(JV, JT): KBTS_C2(H2, JV): KBTS_C2(H2, JT): + KBTS_C2(JT, JT): KBTS_C2(H3, JT): + KBTS_C2(JL, POea): KBTS_C2(JL, POnea): KBTS_C2(JV, POea): KBTS_C2(JV, POnea): KBTS_C2(JT, POea): KBTS_C2(JT, POnea): + KBTS_C2(H2, POea): KBTS_C2(H2, POnea): KBTS_C2(H3, POea): KBTS_C2(H3, POnea): + KBTS_C2(PRea, JL): KBTS_C2(PRea, JV): KBTS_C2(PRea, JT): KBTS_C2(PRea, H2): KBTS_C2(PRea, H3): + KBTS_C2(PRnea, JL): KBTS_C2(PRnea, JV): KBTS_C2(PRnea, JT): KBTS_C2(PRnea, H2): KBTS_C2(PRnea, H3): + KBTS_C2(ALea, ALea): KBTS_C2(ALea, ALnea): KBTS_C2(ALea, DOTTED_CIRCLE): KBTS_C2(ALea, HL): + KBTS_C2(ALnea, ALea): KBTS_C2(ALnea, ALnea): KBTS_C2(ALnea, DOTTED_CIRCLE): KBTS_C2(ALnea, HL): + KBTS_C2(DOTTED_CIRCLE, ALea): KBTS_C2(DOTTED_CIRCLE, ALnea): KBTS_C2(DOTTED_CIRCLE, DOTTED_CIRCLE): KBTS_C2(DOTTED_CIRCLE, HL): + KBTS_C2(HL, ALea): KBTS_C2(HL, ALnea): KBTS_C2(HL, DOTTED_CIRCLE): KBTS_C2(HL, HL): + KBTS_C2(AP, AK): KBTS_C2(AP, DOTTED_CIRCLE): KBTS_C2(AP, AS): + KBTS_C2(AK, VF): KBTS_C2(AK, VI): KBTS_C2(DOTTED_CIRCLE, VF): KBTS_C2(DOTTED_CIRCLE, VI): KBTS_C2(AS, VF): KBTS_C2(AS, VI): + KBTS_C2(IS, ALea): KBTS_C2(IS, ALnea): KBTS_C2(IS, DOTTED_CIRCLE): KBTS_C2(IS, HL): + KBTS_C2(ALea, OPnea): KBTS_C2(ALnea, OPnea): KBTS_C2(DOTTED_CIRCLE, OPnea): KBTS_C2(HL, OPnea): KBTS_C2(NU, OPnea): + KBTS_C2(CPnea, ALea): KBTS_C2(CPnea, ALnea): KBTS_C2(CPnea, DOTTED_CIRCLE): KBTS_C2(CPnea, HL): KBTS_C2(CPnea, NU): + KBTS_C2(EBea, EM): KBTS_C2(EBnea, EM): KBTS_C2(Ope, EM): KBTS_C2(IDpe, EM): + KBTS_C2(HY, NU): KBTS_C2(IS, NU): + KBTS_LINE_UNBREAK(0, 1); break; + + KBTS_C2(Oea, GLea):KBTS_C2(Oea, GLnea): + KBTS_C2(Onea, GLea):KBTS_C2(Onea, GLnea): + KBTS_C2(Ope, GLea):KBTS_C2(Ope, GLnea): + KBTS_C2(BK, GLea):KBTS_C2(BK, GLnea): + KBTS_C2(CR, GLea):KBTS_C2(CR, GLnea): + KBTS_C2(LF, GLea):KBTS_C2(LF, GLnea): + KBTS_C2(NL, GLea):KBTS_C2(NL, GLnea): + KBTS_C2(ZW, GLea):KBTS_C2(ZW, GLnea): + KBTS_C2(WJ, GLea):KBTS_C2(WJ, GLnea): + KBTS_C2(GLea, GLea):KBTS_C2(GLea, GLnea): + KBTS_C2(GLnea, GLea):KBTS_C2(GLnea, GLnea): + KBTS_C2(CLea, GLea):KBTS_C2(CLea, GLnea): + KBTS_C2(CLnea, GLea):KBTS_C2(CLnea, GLnea): + KBTS_C2(CPea, GLea):KBTS_C2(CPea, GLnea): + KBTS_C2(CPnea, GLea):KBTS_C2(CPnea, GLnea): + KBTS_C2(EXea, GLea):KBTS_C2(EXea, GLnea): + KBTS_C2(EXnea, GLea):KBTS_C2(EXnea, GLnea): + KBTS_C2(SY, GLea):KBTS_C2(SY, GLnea): + KBTS_C2(OPea, GLea):KBTS_C2(OPea, GLnea): + KBTS_C2(OPnea, GLea):KBTS_C2(OPnea, GLnea): + KBTS_C2(QU, GLea):KBTS_C2(QU, GLnea): + KBTS_C2(QUPi, GLea): + KBTS_C2(IS, GLea):KBTS_C2(IS, GLnea): + KBTS_C2(NSea, GLea):KBTS_C2(NSea, GLnea): + KBTS_C2(NSnea, GLea):KBTS_C2(NSnea, GLnea): + KBTS_C2(B2, GLea):KBTS_C2(B2, GLnea): + KBTS_C2(CB, GLea):KBTS_C2(CB, GLnea): + KBTS_C2(INea, GLea):KBTS_C2(INea, GLnea): + KBTS_C2(INnea, GLea):KBTS_C2(INnea, GLnea): + KBTS_C2(BB, GLea):KBTS_C2(BB, GLnea): + KBTS_C2(HL, GLea):KBTS_C2(HL, GLnea): + KBTS_C2(ALea, GLea):KBTS_C2(ALea, GLnea): + KBTS_C2(ALnea, GLea):KBTS_C2(ALnea, GLnea): + KBTS_C2(NU, GLea):KBTS_C2(NU, GLnea): + KBTS_C2(PRea, GLea):KBTS_C2(PRea, GLnea): + KBTS_C2(PRnea, GLea):KBTS_C2(PRnea, GLnea): + KBTS_C2(IDea, GLea):KBTS_C2(IDea, GLnea): + KBTS_C2(IDnea, GLea):KBTS_C2(IDnea, GLnea): + KBTS_C2(IDpe, GLea):KBTS_C2(IDpe, GLnea): + KBTS_C2(EBea, GLea):KBTS_C2(EBea, GLnea): + KBTS_C2(EBnea, GLea):KBTS_C2(EBnea, GLnea): + KBTS_C2(EM, GLea):KBTS_C2(EM, GLnea): + KBTS_C2(POea, GLea):KBTS_C2(POea, GLnea): + KBTS_C2(POnea, GLea):KBTS_C2(POnea, GLnea): + KBTS_C2(JL, GLea):KBTS_C2(JL, GLnea): + KBTS_C2(JV, GLea):KBTS_C2(JV, GLnea): + KBTS_C2(JT, GLea):KBTS_C2(JT, GLnea): + KBTS_C2(H2, GLea):KBTS_C2(H2, GLnea): + KBTS_C2(H3, GLea):KBTS_C2(H3, GLnea): + KBTS_C2(AP, GLea):KBTS_C2(AP, GLnea): + KBTS_C2(AK, GLea):KBTS_C2(AK, GLnea): + KBTS_C2(DOTTED_CIRCLE, GLea):KBTS_C2(DOTTED_CIRCLE, GLnea): + KBTS_C2(AS, GLea):KBTS_C2(AS, GLnea): + KBTS_C2(VF, GLea):KBTS_C2(VF, GLnea): + KBTS_C2(VI, GLea):KBTS_C2(VI, GLnea): + KBTS_C2(RI, GLea):KBTS_C2(RI, GLnea): + KBTS_LINE_UNBREAK(3, 1); break; + + + KBTS_C2(CLea, NSnea): KBTS_C2(CLea, NSea): KBTS_C2(CLnea, NSnea): KBTS_C2(CLnea, NSea): + KBTS_C2(CPea, NSnea): KBTS_C2(CPea, NSea): KBTS_C2(CPnea, NSnea): KBTS_C2(CPnea, NSea): + KBTS_C2(B2, B2): + KBTS_LINE_UNBREAK(2, 1); break; + + KBTS_C2(RI, RI): // (RI RI)* RI x RI + KBTS_LINE_UNBREAK(0, 1); + LineBreakHistory = 0; + break; + } + + switch(LineBreakHistory & 0xFFFFFF) + { + KBTS_C3(SOT, QUPi, SP): KBTS_C3(BK, QUPi, SP): KBTS_C3(CR, QUPi, SP): KBTS_C3(LF, QUPi, SP): KBTS_C3(NL, QUPi, SP): KBTS_C3(OPea, QUPi, SP): KBTS_C3(OPnea, QUPi, SP): + KBTS_C3(SP, QUPi, SP): KBTS_C3(ZW, QUPi, SP): KBTS_C3(QU, QUPi, SP): KBTS_C3(QUPi, QUPi, SP): KBTS_C3(QUPf, QUPi, SP): KBTS_C3(GLea, QUPi, SP): KBTS_C3(GLnea, QUPi, SP): + KBTS_LINE_UNBREAK(3, 0); break; + + KBTS_C3(SP, IS, NU): + KBTS_LINE_BREAK(3, 2); break; + + KBTS_C3(CLea, SP, NSnea): KBTS_C3(CLea, SP, NSea): KBTS_C3(CLnea, SP, NSnea): KBTS_C3(CLnea, SP, NSea): + KBTS_C3(CPea, SP, NSnea): KBTS_C3(CPea, SP, NSea): KBTS_C3(CPnea, SP, NSnea): KBTS_C3(CPnea, SP, NSea): + KBTS_C3(B2, SP, B2): + KBTS_LINE_UNBREAK(2, 1); break; + + KBTS_C3(SOT, HY, ALnea): KBTS_C3(SOT, HY, ALea): KBTS_C3(SOT, HY, DOTTED_CIRCLE): KBTS_C3(SOT, HYPHEN, ALnea): KBTS_C3(SOT, HYPHEN, ALea): KBTS_C3(SOT, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(BK, HY, ALnea): KBTS_C3(BK, HY, ALea): KBTS_C3(BK, HY, DOTTED_CIRCLE): KBTS_C3(BK, HYPHEN, ALnea): KBTS_C3(BK, HYPHEN, ALea): KBTS_C3(BK, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(LF, HY, ALnea): KBTS_C3(LF, HY, ALea): KBTS_C3(LF, HY, DOTTED_CIRCLE): KBTS_C3(LF, HYPHEN, ALnea): KBTS_C3(LF, HYPHEN, ALea): KBTS_C3(LF, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(NL, HY, ALnea): KBTS_C3(NL, HY, ALea): KBTS_C3(NL, HY, DOTTED_CIRCLE): KBTS_C3(NL, HYPHEN, ALnea): KBTS_C3(NL, HYPHEN, ALea): KBTS_C3(NL, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(CR, HY, ALnea): KBTS_C3(CR, HY, ALea): KBTS_C3(CR, HY, DOTTED_CIRCLE): KBTS_C3(CR, HYPHEN, ALnea): KBTS_C3(CR, HYPHEN, ALea): KBTS_C3(CR, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(SP, HY, ALnea): KBTS_C3(SP, HY, ALea): KBTS_C3(SP, HY, DOTTED_CIRCLE): KBTS_C3(SP, HYPHEN, ALnea): KBTS_C3(SP, HYPHEN, ALea): KBTS_C3(SP, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(ZW, HY, ALnea): KBTS_C3(ZW, HY, ALea): KBTS_C3(ZW, HY, DOTTED_CIRCLE): KBTS_C3(ZW, HYPHEN, ALnea): KBTS_C3(ZW, HYPHEN, ALea): KBTS_C3(ZW, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(CB, HY, ALnea): KBTS_C3(CB, HY, ALea): KBTS_C3(CB, HY, DOTTED_CIRCLE): KBTS_C3(CB, HYPHEN, ALnea): KBTS_C3(CB, HYPHEN, ALea): KBTS_C3(CB, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(GLnea, HY, ALnea): KBTS_C3(GLnea, HY, ALea): KBTS_C3(GLnea, HY, DOTTED_CIRCLE): KBTS_C3(GLnea, HYPHEN, ALnea): KBTS_C3(GLnea, HYPHEN, ALea): KBTS_C3(GLnea, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(GLea, HY, ALnea): KBTS_C3(GLea, HY, ALea): KBTS_C3(GLea, HY, DOTTED_CIRCLE): KBTS_C3(GLea, HYPHEN, ALnea): KBTS_C3(GLea, HYPHEN, ALea): KBTS_C3(GLea, HYPHEN, DOTTED_CIRCLE): + KBTS_C3(NU, SY, POea): KBTS_C3(NU, SY, POnea): KBTS_C3(NU, SY, PRea): KBTS_C3(NU, SY, PRnea): KBTS_C3(NU, SY, NU): + KBTS_C3(NU, IS, POea): KBTS_C3(NU, IS, POnea): KBTS_C3(NU, IS, PRea): KBTS_C3(NU, IS, PRnea): KBTS_C3(NU, IS, NU): + KBTS_C3(NU, CLea, POea): KBTS_C3(NU, CLea, POnea): KBTS_C3(NU, CLea, PRea): KBTS_C3(NU, CLea, PRnea): + KBTS_C3(NU, CLnea, POea): KBTS_C3(NU, CLnea, POnea): KBTS_C3(NU, CLnea, PRea): KBTS_C3(NU, CLnea, PRnea): + KBTS_C3(NU, CPea, POea): KBTS_C3(NU, CPea, POnea): KBTS_C3(NU, CPea, PRea): KBTS_C3(NU, CPea, PRnea): + KBTS_C3(NU, CPnea, POea): KBTS_C3(NU, CPnea, POnea): KBTS_C3(NU, CPnea, PRea): KBTS_C3(NU, CPnea, PRnea): + KBTS_C3(AK, VI, AK): KBTS_C3(AK, VI, DOTTED_CIRCLE): KBTS_C3(DOTTED_CIRCLE, VI, AK): KBTS_C3(DOTTED_CIRCLE, VI, DOTTED_CIRCLE): KBTS_C3(AS, VI, AK): KBTS_C3(AS, VI, DOTTED_CIRCLE): + KBTS_LINE_UNBREAK(0, 1); break; + + KBTS_C3(POea, OPea, NU): KBTS_C3(POea, OPnea, NU): KBTS_C3(POnea, OPea, NU): KBTS_C3(POnea, OPnea, NU): + KBTS_C3(PRea, OPea, NU): KBTS_C3(PRea, OPnea, NU): KBTS_C3(PRnea, OPea, NU): KBTS_C3(PRnea, OPnea, NU): + KBTS_LINE_UNBREAK(0, 2); break; + + KBTS_C3(AK, AK, VF): KBTS_C3(AK, DOTTED_CIRCLE, VF): KBTS_C3(AK, AS, VF): + KBTS_C3(DOTTED_CIRCLE, AK, VF): KBTS_C3(DOTTED_CIRCLE, DOTTED_CIRCLE, VF): KBTS_C3(DOTTED_CIRCLE, AS, VF): + KBTS_C3(AS, AK, VF): KBTS_C3(AS, DOTTED_CIRCLE, VF): KBTS_C3(AS, AS, VF): + KBTS_LINE_UNBREAK(0, 2); break; + + KBTS_C3(HL, BAnea, Oea): KBTS_C3(HL, BAnea, Onea): KBTS_C3(HL, BAnea, Ope): KBTS_C3(HL, BAnea, BK): KBTS_C3(HL, BAnea, CR): KBTS_C3(HL, BAnea, LF): + KBTS_C3(HL, BAnea, NL): KBTS_C3(HL, BAnea, SP): KBTS_C3(HL, BAnea, ZW): KBTS_C3(HL, BAnea, WJ): KBTS_C3(HL, BAnea, GLea): KBTS_C3(HL, BAnea, GLnea): + KBTS_C3(HL, BAnea, CLea): KBTS_C3(HL, BAnea, CLnea): KBTS_C3(HL, BAnea, CPea): KBTS_C3(HL, BAnea, CPnea): KBTS_C3(HL, BAnea, EXea): KBTS_C3(HL, BAnea, EXnea): + KBTS_C3(HL, BAnea, SY): KBTS_C3(HL, BAnea, BAea): KBTS_C3(HL, BAnea, BAnea): KBTS_C3(HL, BAnea, OPea): KBTS_C3(HL, BAnea, OPnea): KBTS_C3(HL, BAnea, QU): + KBTS_C3(HL, BAnea, QUPi): KBTS_C3(HL, BAnea, QUPf): KBTS_C3(HL, BAnea, IS): KBTS_C3(HL, BAnea, NSea): KBTS_C3(HL, BAnea, NSnea): KBTS_C3(HL, BAnea, B2): + KBTS_C3(HL, BAnea, CB): KBTS_C3(HL, BAnea, HY): KBTS_C3(HL, BAnea, HYPHEN): KBTS_C3(HL, BAnea, INea): KBTS_C3(HL, BAnea, INnea): KBTS_C3(HL, BAnea, BB): + KBTS_C3(HL, BAnea, ALea): KBTS_C3(HL, BAnea, ALnea): KBTS_C3(HL, BAnea, NU): KBTS_C3(HL, BAnea, PRea): KBTS_C3(HL, BAnea, PRnea): KBTS_C3(HL, BAnea, IDea): + KBTS_C3(HL, BAnea, IDnea): KBTS_C3(HL, BAnea, IDpe): KBTS_C3(HL, BAnea, EBea): KBTS_C3(HL, BAnea, EBnea): KBTS_C3(HL, BAnea, EM): KBTS_C3(HL, BAnea, POea): + KBTS_C3(HL, BAnea, POnea): KBTS_C3(HL, BAnea, JL): KBTS_C3(HL, BAnea, JV): KBTS_C3(HL, BAnea, JT): KBTS_C3(HL, BAnea, H2): KBTS_C3(HL, BAnea, H3): + KBTS_C3(HL, BAnea, AP): KBTS_C3(HL, BAnea, AK): KBTS_C3(HL, BAnea, DOTTED_CIRCLE): KBTS_C3(HL, BAnea, AS): KBTS_C3(HL, BAnea, VF): KBTS_C3(HL, BAnea, VI): KBTS_C3(HL, BAnea, RI): + KBTS_C3(HL, HYPHEN, Oea): KBTS_C3(HL, HYPHEN, Onea): KBTS_C3(HL, HYPHEN, Ope): KBTS_C3(HL, HYPHEN, BK): KBTS_C3(HL, HYPHEN, CR): KBTS_C3(HL, HYPHEN, LF): + KBTS_C3(HL, HYPHEN, NL): KBTS_C3(HL, HYPHEN, SP): KBTS_C3(HL, HYPHEN, ZW): KBTS_C3(HL, HYPHEN, WJ): KBTS_C3(HL, HYPHEN, GLea): KBTS_C3(HL, HYPHEN, GLnea): + KBTS_C3(HL, HYPHEN, CLea): KBTS_C3(HL, HYPHEN, CLnea): KBTS_C3(HL, HYPHEN, CPea): KBTS_C3(HL, HYPHEN, CPnea): KBTS_C3(HL, HYPHEN, EXea): KBTS_C3(HL, HYPHEN, EXnea): + KBTS_C3(HL, HYPHEN, SY): KBTS_C3(HL, HYPHEN, BAea): KBTS_C3(HL, HYPHEN, BAnea): KBTS_C3(HL, HYPHEN, OPea): KBTS_C3(HL, HYPHEN, OPnea): KBTS_C3(HL, HYPHEN, QU): + KBTS_C3(HL, HYPHEN, QUPi): KBTS_C3(HL, HYPHEN, QUPf): KBTS_C3(HL, HYPHEN, IS): KBTS_C3(HL, HYPHEN, NSea): KBTS_C3(HL, HYPHEN, NSnea): KBTS_C3(HL, HYPHEN, B2): + KBTS_C3(HL, HYPHEN, CB): KBTS_C3(HL, HYPHEN, HY): KBTS_C3(HL, HYPHEN, HYPHEN): KBTS_C3(HL, HYPHEN, INea): KBTS_C3(HL, HYPHEN, INnea): KBTS_C3(HL, HYPHEN, BB): + KBTS_C3(HL, HYPHEN, ALea): KBTS_C3(HL, HYPHEN, ALnea): KBTS_C3(HL, HYPHEN, NU): KBTS_C3(HL, HYPHEN, PRea): KBTS_C3(HL, HYPHEN, PRnea): KBTS_C3(HL, HYPHEN, IDea): + KBTS_C3(HL, HYPHEN, IDnea): KBTS_C3(HL, HYPHEN, IDpe): KBTS_C3(HL, HYPHEN, EBea): KBTS_C3(HL, HYPHEN, EBnea): KBTS_C3(HL, HYPHEN, EM): KBTS_C3(HL, HYPHEN, POea): + KBTS_C3(HL, HYPHEN, POnea): KBTS_C3(HL, HYPHEN, JL): KBTS_C3(HL, HYPHEN, JV): KBTS_C3(HL, HYPHEN, JT): KBTS_C3(HL, HYPHEN, H2): KBTS_C3(HL, HYPHEN, H3): + KBTS_C3(HL, HYPHEN, AP): KBTS_C3(HL, HYPHEN, AK): KBTS_C3(HL, HYPHEN, DOTTED_CIRCLE): KBTS_C3(HL, HYPHEN, AS): KBTS_C3(HL, HYPHEN, VF): KBTS_C3(HL, HYPHEN, VI): KBTS_C3(HL, HYPHEN, RI): + KBTS_C3(HL, HY, Oea): KBTS_C3(HL, HY, Onea): KBTS_C3(HL, HY, Ope): KBTS_C3(HL, HY, BK): KBTS_C3(HL, HY, CR): KBTS_C3(HL, HY, LF): + KBTS_C3(HL, HY, NL): KBTS_C3(HL, HY, SP): KBTS_C3(HL, HY, ZW): KBTS_C3(HL, HY, WJ): KBTS_C3(HL, HY, GLea): KBTS_C3(HL, HY, GLnea): + KBTS_C3(HL, HY, CLea): KBTS_C3(HL, HY, CLnea): KBTS_C3(HL, HY, CPea): KBTS_C3(HL, HY, CPnea): KBTS_C3(HL, HY, EXea): KBTS_C3(HL, HY, EXnea): + KBTS_C3(HL, HY, SY): KBTS_C3(HL, HY, BAea): KBTS_C3(HL, HY, BAnea): KBTS_C3(HL, HY, OPea): KBTS_C3(HL, HY, OPnea): KBTS_C3(HL, HY, QU): + KBTS_C3(HL, HY, QUPi): KBTS_C3(HL, HY, QUPf): KBTS_C3(HL, HY, IS): KBTS_C3(HL, HY, NSea): KBTS_C3(HL, HY, NSnea): KBTS_C3(HL, HY, B2): + KBTS_C3(HL, HY, CB): KBTS_C3(HL, HY, HY): KBTS_C3(HL, HY, HYPHEN): KBTS_C3(HL, HY, INea): KBTS_C3(HL, HY, INnea): KBTS_C3(HL, HY, BB): + KBTS_C3(HL, HY, ALea): KBTS_C3(HL, HY, ALnea): KBTS_C3(HL, HY, NU): KBTS_C3(HL, HY, PRea): KBTS_C3(HL, HY, PRnea): KBTS_C3(HL, HY, IDea): + KBTS_C3(HL, HY, IDnea): KBTS_C3(HL, HY, IDpe): KBTS_C3(HL, HY, EBea): KBTS_C3(HL, HY, EBnea): KBTS_C3(HL, HY, EM): KBTS_C3(HL, HY, POea): + KBTS_C3(HL, HY, POnea): KBTS_C3(HL, HY, JL): KBTS_C3(HL, HY, JV): KBTS_C3(HL, HY, JT): KBTS_C3(HL, HY, H2): KBTS_C3(HL, HY, H3): + KBTS_C3(HL, HY, AP): KBTS_C3(HL, HY, AK): KBTS_C3(HL, HY, DOTTED_CIRCLE): KBTS_C3(HL, HY, AS): KBTS_C3(HL, HY, VF): KBTS_C3(HL, HY, VI): KBTS_C3(HL, HY, RI): + KBTS_LINE_UNBREAK(0, 1); break; + } + + switch(LineBreakHistory) + { + KBTS_C4(NU, SY, CLnea, POnea): KBTS_C4(NU, SY, CLnea, POea): KBTS_C4(NU, SY, CLnea, PRnea): KBTS_C4(NU, SY, CLnea, PRea): + KBTS_C4(NU, SY, CLea, POnea): KBTS_C4(NU, SY, CLea, POea): KBTS_C4(NU, SY, CLea, PRnea): KBTS_C4(NU, SY, CLea, PRea): + KBTS_C4(NU, SY, CPnea, POnea): KBTS_C4(NU, SY, CPnea, POea): KBTS_C4(NU, SY, CPnea, PRnea): KBTS_C4(NU, SY, CPnea, PRea): + KBTS_C4(NU, SY, CPea, POnea): KBTS_C4(NU, SY, CPea, POea): KBTS_C4(NU, SY, CPea, PRnea): KBTS_C4(NU, SY, CPea, PRea): + KBTS_C4(NU, IS, CLnea, POnea): KBTS_C4(NU, IS, CLnea, POea): KBTS_C4(NU, IS, CLnea, PRnea): KBTS_C4(NU, IS, CLnea, PRea): + KBTS_C4(NU, IS, CLea, POnea): KBTS_C4(NU, IS, CLea, POea): KBTS_C4(NU, IS, CLea, PRnea): KBTS_C4(NU, IS, CLea, PRea): + KBTS_C4(NU, IS, CPnea, POnea): KBTS_C4(NU, IS, CPnea, POea): KBTS_C4(NU, IS, CPnea, PRnea): KBTS_C4(NU, IS, CPnea, PRea): + KBTS_C4(NU, IS, CPea, POnea): KBTS_C4(NU, IS, CPea, POea): KBTS_C4(NU, IS, CPea, PRnea): KBTS_C4(NU, IS, CPea, PRea): + KBTS_LINE_UNBREAK(0, 1); break; + + KBTS_C4(POea, OPea, IS, NU): KBTS_C4(POea, OPnea, IS, NU): KBTS_C4(POnea, OPea, IS, NU): KBTS_C4(POnea, OPnea, IS, NU): + KBTS_C4(PRea, OPea, IS, NU): KBTS_C4(PRea, OPnea, IS, NU): KBTS_C4(PRnea, OPea, IS, NU): KBTS_C4(PRnea, OPnea, IS, NU): + KBTS_LINE_UNBREAK(0, 3); break; + } + + if(StartOfText) + { + // Never break lines. + KBTS_LINE_UNBREAK(5, 1); + // Always break graphemes. + KBTS_BREAK(KBTS_BREAK_FLAG_GRAPHEME, 1); + } + + #undef KBTS_C1 + #undef KBTS_C2 + #undef KBTS_C3 + #undef KBTS_C4 + #undef KBTS_REQUIRED_LINE_BREAK + #undef KBTS_LINE_BREAK + #undef KBTS_LINE_UNBREAK + + { + kbts_u64 EffectiveLineBreaks = LineBreaks & ~(LineUnbreaks | LineUnbreaksAsync); + + kbts_DoLineBreak(State, PositionOffset3 + LineBreak3PositionOffset, EffectiveLineBreaks >> 48, 0, 0); + if(EndOfText) + { + kbts_DoLineBreak(State, PositionOffset2 + LineBreak2PositionOffset, EffectiveLineBreaks >> 32, 0, 0); + { // @Cleanup: This is the same flag code as DoLineBreak, but we want to use FlagState buffering for this. + // The only places where we want to manually call DoBreak is for asynchronous/buffered guys. + kbts_u8 FlushFlags = 0; + if((EffectiveLineBreaks >> 16) & KBTS_LINE_BREAK_ALLOWED_MASK) FlushFlags |= KBTS_BREAK_FLAG_LINE_SOFT; + if((EffectiveLineBreaks >> 16) & KBTS_LINE_BREAK_REQUIRED_MASK) FlushFlags |= KBTS_BREAK_FLAG_LINE_HARD; + KBTS_BREAK(FlushFlags, 1); + } + // Lines are never broken after the end of text. + } + } + + State->LineBreaks = LineBreaks; + State->LineUnbreaks = LineUnbreaks; + State->LineBreak2PositionOffset = 0; + State->LineBreak3PositionOffset = LineBreak2PositionOffset; + State->LastLineBreakClass = LineBreakClass; + State->LineBreakHistory = LineBreakHistory; + State->LastDirection = (kbts_u8)LastDirection; + + if(0) + { + LineBreakAbsorbCharacter:; + State->LineBreak2PositionOffset -= PositionIncrement; + State->LineBreak3PositionOffset -= PositionIncrement; + } + + // This always gets updated. + State->LineUnbreaksAsync = LineUnbreaksAsync; + } + + // This is where we flush the normal breaks that don't need any special position adjustment. + kbts_DoBreak(State, PositionOffset3, (FlagState >> 24) & 0xFF, LastDirection, State->LastScripts[1]); + if(EndOfText) + { + kbts_DoBreak(State, PositionOffset2, (FlagState >> 16) & 0xFF, 0, LastScript); + kbts_DoBreak(State, 0, (FlagState >> 8) & 0xFF, 0, Script); + kbts_DoBreak(State, PositionIncrement, FlagState & 0xFF, 0, Script); + } + + State->FlagState = FlagState; + State->Flags |= KBTS_BREAK_STATE_FLAG_STARTED; + if(EndOfText) State->Flags |= KBTS_BREAK_STATE_FLAG_END; + State->PositionOffset2 = (kbts_s16)-(int)PositionIncrement; + State->PositionOffset3 = (kbts_s16)(PositionOffset2 - (int)PositionIncrement); + State->CurrentPosition += PositionIncrement; + + State->LastScripts[1] = State->LastScripts[0]; + State->LastScripts[0] = Script; +#undef KBTS_BREAK +#undef KBTS_BREAK2 +} + +KBTS_EXPORT void kbts_BreakFlush(kbts_break_state *State) +{ + // We pass 3, aka. ASCII end-of-text, at the end of text. + kbts_BreakAddCodepoint_(State, 3, 0, 1); +} + +KBTS_EXPORT void kbts_BreakAddCodepoint(kbts_break_state *State, kbts_u32 Codepoint, kbts_u32 PositionIncrement, int EndOfText) +{ + kbts_BreakAddCodepoint_(State, Codepoint, PositionIncrement, 0); + if(EndOfText) kbts_BreakFlush(State); +} + +KBTS_EXPORT int kbts_Break(kbts_break_state *State, kbts_break *Break) +{ + int Result = 0; + kbts_un Threshold = State->Flags & KBTS_BREAK_STATE_FLAG_END ? 0 : KBTS_BREAK_REORDER_BUFFER_FLUSH_THRESHOLD; + + if(kbts_BreakStateIsValid(State) && (State->BreakCount > Threshold)) + { + kbts_break *ToFlush = &State->Breaks[State->BreakCount - 1]; + // @Incomplete: Handle wrapping. + if(ToFlush->Position >= State->LastFlushedBreakPosition) + { + *Break = *ToFlush; + State->LastFlushedBreakPosition = ToFlush->Position; + State->BreakCount -= 1; + Result = 1; + } + else + { + State->Flags |= KBTS_BREAK_STATE_FLAG_RAN_OUT_OF_REORDER_BUFFER_SPACE; + } + } + + return Result; +} + +KBTS_EXPORT void kbts_BeginBreak(kbts_break_state *State, kbts_direction MainDirection, kbts_japanese_line_break_style JapaneseLineBreakStyle) +{ + if(State) + { + KBTS_MEMSET(State, 0, sizeof(*State)); + State->MainDirection = (kbts_u8)MainDirection; + State->JapaneseLineBreakStyle = JapaneseLineBreakStyle; + } +} + +KBTS_EXPORT kbts_decode kbts_DecodeUtf8(const char *Utf8, kbts_un Length) +{ + kbts_decode Result = KBTS_ZERO; + const char *Utf8Start = Utf8; + + if(Length) + { + kbts_u8 First = (kbts_u8)*Utf8++; + kbts_un FollowupCharacterCount = 0; + + switch((First & 0xF0) >> 4) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + { + Result.Codepoint = First & 0x7F; + Result.Valid = 1; + } + break; + + case 0xC: + case 0xD: + { + FollowupCharacterCount = 1; + Result.Codepoint = First & 0x1F; + Result.Valid = 1; + } + break; + + case 0xE: + { + FollowupCharacterCount = 2; + Result.Codepoint = First & 0xF; + Result.Valid = 1; + } + break; + + case 0xF: + { + FollowupCharacterCount = 3; + Result.Codepoint = First & 7; + Result.Valid = 1; + } + break; + } + + if(Length > FollowupCharacterCount) + { + KBTS_FOR(FollowupCharacterIndex, 0, FollowupCharacterCount) + { + kbts_u8 C = (kbts_u8)*Utf8++; + + if((C & 0xC0) == 0x80) + { + Result.Codepoint = (Result.Codepoint << 6) | (C & 0x3F); + } + else + { + Result.Valid = 0; + + break; + } + } + } + else + { + Result.Valid = 0; + } + } + + Result.SourceCharactersConsumed = (kbts_u32)(Utf8 - Utf8Start); + + return Result; +} + +KBTS_EXPORT int kbts_ShaperIsComplex(kbts_shaper Shaper) +{ + int Result = Shaper != KBTS_SHAPER_DEFAULT; // @Incomplete? + + return Result; +} + +KBTS_EXPORT int kbts_ScriptIsComplex(kbts_script Script) +{ + kbts_script_properties *Properties = &kbts_ScriptProperties[Script]; + int Result = kbts_ShaperIsComplex(Properties->Shaper); + return Result; +} + +#endif +#undef KBTS_X_FEATURES \ No newline at end of file diff --git a/vendor/libc/ctype.odin b/vendor/libc/ctype.odin new file mode 100644 index 000000000..8813055d7 --- /dev/null +++ b/vendor/libc/ctype.odin @@ -0,0 +1,33 @@ +package odin_libc + +@(require, linkage="strong", link_name="isdigit") +isdigit :: proc "c" (c: i32) -> b32 { + switch c { + case '0'..='9': return true + case: return false + } +} + +@(require, linkage="strong", link_name="isblank") +isblank :: proc "c" (c: i32) -> b32 { + switch c { + case '\t', ' ': return true + case: return false + } +} + +@(require, linkage="strong", link_name="isspace") +isspace :: proc "c" (c: i32) -> b32 { + switch c { + case '\t', ' ', '\n', '\v', '\f', '\r': return true + case: return false + } +} + +@(require, linkage="strong", link_name="toupper") +toupper :: proc "c" (c: i32) -> i32 { + if c >= 'a' && c <= 'z' { + return c - ('a' - 'A') + } + return c +} diff --git a/vendor/libc/include/alloca.h b/vendor/libc/include/alloca.h new file mode 100644 index 000000000..8b4d19018 --- /dev/null +++ b/vendor/libc/include/alloca.h @@ -0,0 +1,21 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + +#include + +void *alloca(size_t); /* built-in for gcc */ + +#if defined(__GNUC__) && __GNUC__ >= 3 +/* built-in for gcc 3 */ +#undef alloca +#undef __alloca +#define alloca(size) __alloca(size) +#define __alloca(size) __builtin_alloca(size) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/assert.h b/vendor/libc/include/assert.h index a6fb6c696..4e8cd85a4 100644 --- a/vendor/libc/include/assert.h +++ b/vendor/libc/include/assert.h @@ -1,3 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + #ifdef NDEBUG #define assert(e) ((void)0) #else @@ -14,3 +20,9 @@ void __odin_libc_assert_fail(const char *, const char *, int, const char *); (__builtin_expect(!(e), 0) ? __odin_libc_assert_fail(__func__, __ASSERT_FILE_NAME, __LINE__, #e) : (void)0) #endif /* NDEBUG */ + +#define static_assert _Static_assert + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/ctype.h b/vendor/libc/include/ctype.h new file mode 100644 index 000000000..a579b5674 --- /dev/null +++ b/vendor/libc/include/ctype.h @@ -0,0 +1,15 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + +int isdigit(int c); +int isblank(int c); +int isspace(int c); + +int toupper(int c); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/inttypes.h b/vendor/libc/include/inttypes.h new file mode 100644 index 000000000..e69de29bb diff --git a/vendor/libc/include/math.h b/vendor/libc/include/math.h index 9d486da11..fba520e4a 100644 --- a/vendor/libc/include/math.h +++ b/vendor/libc/include/math.h @@ -1,21 +1,66 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + #include +#define INFINITY (1.0 / 0.0) +#define NAN (0.0 / 0.0) + float sqrtf(float); float cosf(float); float sinf(float); float atan2f(float, float); -bool isnan(float); -bool isinf(float); + +float floorf(float x); double floor(double x); +float ceilf(float x); double ceil(double x); double sqrt(double x); +float powf(float x, float y); double pow(double x, double y); +float fmodf(float x, float y); double fmod(double x, double y); double cos(double x); +float acosf(float x); double acos(double x); +float fabsf(float x); double fabs(double x); int abs(int); double ldexp(double, int); double exp(double); +float logf(float); double log(double); double sin(double); +double trunc(double); +double log2(double); +double log10(double); +double asin(double); +double atan(double); +double tan(double); +double atan2(double, double); +double modf(double, double*); + +bool __isnanf(float); +bool __isnand(double); +#define isnan(x) \ + ( sizeof(x) == sizeof(float) ? __isnanf((float)(x)) \ + : __isnand((double)(x))) + +bool __isinff(float); +bool __isinfd(double); +#define isinf(x) \ + ( sizeof(x) == sizeof(float) ? __isinff((float)(x)) \ + : __isinfd((double)(x))) + +bool __isfinitef(float); +bool __isfinited(double); +#define isfinite(x) \ + ( sizeof(x) == sizeof(float) ? __isfinitef((float)(x)) \ + : __isfinited((double)(x))) + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/sched.h b/vendor/libc/include/sched.h new file mode 100644 index 000000000..6e4397536 --- /dev/null +++ b/vendor/libc/include/sched.h @@ -0,0 +1,23 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + +#include + +#define CLOCK_MONOTONIC 1 + +struct timespec +{ + int64_t tv_sec; + int64_t tv_nsec; +}; + +int clock_gettime(int clockid, struct timespec *tp); + +int sched_yield(); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/stdio.h b/vendor/libc/include/stdio.h index 807437f3c..06339c1a3 100644 --- a/vendor/libc/include/stdio.h +++ b/vendor/libc/include/stdio.h @@ -1,8 +1,14 @@ -#include -#include +#ifdef __cplusplus +extern "C" { +#endif #pragma once +#include +#include +#include +#include + typedef struct {} FILE; #define SEEK_SET 0 @@ -12,6 +18,8 @@ typedef struct {} FILE; #define stdout ((FILE *)2) #define stderr ((FILE *)3) +#define EOF -1 + FILE *fopen(const char *, char *); int fclose(FILE *); int fseek(FILE *, long, int); @@ -21,6 +29,10 @@ size_t fwrite(const void *, size_t, size_t, FILE *); int vfprintf(FILE *, const char *, va_list); int vsnprintf(char *, size_t, const char *, va_list); +int vsprintf(char *, const char *, va_list); + +int putchar(int ch); +int getchar(); static inline int snprintf(char *buf, size_t size, const char *fmt, ...) { va_list args; @@ -30,6 +42,14 @@ static inline int snprintf(char *buf, size_t size, const char *fmt, ...) { return result; } +static inline int sprintf(char *buf, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int result = vsprintf(buf, fmt, args); + va_end(args); + return result; +} + static inline int fprintf(FILE *f, const char *fmt, ...) { va_list args; va_start(args, fmt); @@ -45,3 +65,37 @@ static inline int printf(const char *fmt, ...) { va_end(args); return result; } + +int __sscanf(const char *str, const char *format, void *ptrs); + +static inline int vsscanf(const char *str, const char *format, va_list ap) { + int count = 0; + for (int i = 0; format[i]; i++) { + if (format[i] == '%') { + if (format[i+1] == '%') { + i++; + continue; + } + count++; + } + } + + void **ptrs = (void **)(alloca(count*sizeof(void *))); + for (int i = 0; i < count; i++) { + ptrs[i] = va_arg(ap, void *); + } + + return __sscanf(str, format, ptrs); +} + +static inline int sscanf(const char *str, const char *format, ...) { + va_list args; + va_start(args, format); + int res = vsscanf(str, format, args); + va_end(args); + return res; +} + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/stdlib.h b/vendor/libc/include/stdlib.h index 22cfc528b..01c6ac6b2 100644 --- a/vendor/libc/include/stdlib.h +++ b/vendor/libc/include/stdlib.h @@ -1,3 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + #include void *malloc(size_t size); @@ -17,3 +23,22 @@ long long atoll(const char *); double atof(const char *); long strtol(const char *, char **, int); +double strtod(const char *, char **); + +void abort(); +void exit(int exit_code); + +#define ATEXIT_MAX 32 + +int atexit(typeof(void (void)) *); + +typedef struct { + long int quot; + long int rem; +} ldiv_t; + +ldiv_t ldiv(long int number, long int denom); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/string.h b/vendor/libc/include/string.h index 4571f9454..7e5e2b252 100644 --- a/vendor/libc/include/string.h +++ b/vendor/libc/include/string.h @@ -1,9 +1,16 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + #include void *memcpy(void *, const void *, size_t); void *memset(void *, int, size_t); void *memmove(void *, void *, size_t); int memcmp(const void *, const void *, size_t); +void *memchr(const void *, int, size_t); unsigned long strlen(const char *str); @@ -19,3 +26,7 @@ int strcmp(const char *, const char *); int strncmp(const char *, const char *, size_t); char *strstr(const char *, const char *); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/include/time.h b/vendor/libc/include/time.h new file mode 100644 index 000000000..369e25256 --- /dev/null +++ b/vendor/libc/include/time.h @@ -0,0 +1,16 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#pragma once + +#include + +typedef int64_t clock_t; +typedef clock_t time_t; + +clock_t clock(); + +#ifdef __cplusplus +} +#endif diff --git a/vendor/libc/libc.odin b/vendor/libc/libc.odin index 00d687109..a5508e14f 100644 --- a/vendor/libc/libc.odin +++ b/vendor/libc/libc.odin @@ -10,8 +10,9 @@ g_ctx: runtime.Context g_allocator: mem.Compat_Allocator @(init) -init_context :: proc() { - g_ctx = context +init_context :: proc "contextless" () { + g_ctx = runtime.default_context() + context = g_ctx // Wrapping the allocator with the mem.Compat_Allocator so we can // mimic the realloc semantics. diff --git a/vendor/libc/math.odin b/vendor/libc/math.odin index af319ac6d..93df1fea6 100644 --- a/vendor/libc/math.odin +++ b/vendor/libc/math.odin @@ -14,23 +14,28 @@ cosf :: proc "c" (v: f32) -> f32 { return math.cos(v) } -@(require, linkage="strong", link_name="sinf") -sinf :: proc "c" (v: f32) -> f32 { - return math.sin(v) -} - @(require, linkage="strong", link_name="atan2f") atan2f :: proc "c" (v: f32, v2: f32) -> f32 { return math.atan2(v, v2) } -@(require, linkage="strong", link_name="isnan") -isnan :: proc "c" (v: f32) -> bool { +@(require, linkage="strong", link_name="__isnanf") +isnanf :: proc "c" (v: f32) -> bool { return math.is_nan(v) } -@(require, linkage="strong", link_name="isinf") -isinf :: proc "c" (v: f32) -> bool { +@(require, linkage="strong", link_name="__isnand") +isnand :: proc "c" (v: f64) -> bool { + return math.is_nan(v) +} + +@(require, linkage="strong", link_name="__isinff") +isinff :: proc "c" (v: f32) -> bool { + return math.is_inf(v) +} + +@(require, linkage="strong", link_name="__isinfd") +isinfd :: proc "c" (v: f64) -> bool { return math.is_inf(v) } @@ -39,21 +44,41 @@ sqrt :: proc "c" (x: f64) -> f64 { return math.sqrt(x) } +@(require, linkage="strong", link_name="floorf") +floorf :: proc "c" (x: f32) -> f32 { + return math.floor(x) +} + @(require, linkage="strong", link_name="floor") floor :: proc "c" (x: f64) -> f64 { return math.floor(x) } +@(require, linkage="strong", link_name="ceilf") +ceilf :: proc "c" (x: f32) -> f32 { + return math.ceil(x) +} + @(require, linkage="strong", link_name="ceil") ceil :: proc "c" (x: f64) -> f64 { return math.ceil(x) } +@(require, linkage="strong", link_name="powf") +powf :: proc "c" (x, y: f32) -> f32 { + return math.pow(x, y) +} + @(require, linkage="strong", link_name="pow") pow :: proc "c" (x, y: f64) -> f64 { return math.pow(x, y) } +@(require, linkage="strong", link_name="fmodf") +fmodf :: proc "c" (x, y: f32) -> f32 { + return math.mod(x, y) +} + @(require, linkage="strong", link_name="fmod") fmod :: proc "c" (x, y: f64) -> f64 { return math.mod(x, y) @@ -64,11 +89,21 @@ cos :: proc "c" (x: f64) -> f64 { return math.cos(x) } +@(require, linkage="strong", link_name="acosf") +acosf :: proc "c" (x: f32) -> f32 { + return math.acos(x) +} + @(require, linkage="strong", link_name="acos") acos :: proc "c" (x: f64) -> f64 { return math.acos(x) } +@(require, linkage="strong", link_name="fabsf") +fabsf :: proc "c" (x: f32) -> f32 { + return math.abs(x) +} + @(require, linkage="strong", link_name="fabs") fabs :: proc "c" (x: f64) -> f64 { return math.abs(x) @@ -89,6 +124,11 @@ exp :: proc "c" (x: f64) -> f64 { return math.exp(x) } +@(require, linkage="strong", link_name="logf") +logf :: proc "c" (x: f32) -> f32 { + return math.ln(x) +} + @(require, linkage="strong", link_name="log") log :: proc "c" (x: f64) -> f64 { return math.ln(x) @@ -98,3 +138,69 @@ log :: proc "c" (x: f64) -> f64 { sin :: proc "c" (x: f64) -> f64 { return math.sin(x) } + +@(require, linkage="strong", link_name="sinf") +sinf :: proc "c" (v: f32) -> f32 { + return math.sin(v) +} + + +@(require, linkage="strong", link_name="trunc") +trunc :: proc "c" (x: f64) -> f64 { + return math.trunc(x) +} + +@(require, linkage="strong", link_name="__isfinitef") +isfinitef :: proc "c" (x: f32) -> bool { + switch math.classify(x) { + case .Normal, .Subnormal, .Zero, .Neg_Zero: return true + case .Inf, .Neg_Inf, .NaN: return false + case: unreachable() + } +} + +@(require, linkage="strong", link_name="__isfinited") +isfinited :: proc "c" (x: f64) -> bool { + switch math.classify(x) { + case .Normal, .Subnormal, .Zero, .Neg_Zero: return true + case .Inf, .Neg_Inf, .NaN: return false + case: unreachable() + } +} + +@(require, linkage="strong", link_name="log2") +log2 :: proc "c" (x: f64) -> f64 { + return math.log2(x) +} + +@(require, linkage="strong", link_name="log10") +log10 :: proc "c" (x: f64) -> f64 { + return math.log10(x) +} + +@(require, linkage="strong", link_name="asin") +asin :: proc "c" (x: f64) -> f64 { + return math.asin(x) +} + +@(require, linkage="strong", link_name="atan") +atan :: proc "c" (x: f64) -> f64 { + return math.atan(x) +} + +@(require, linkage="strong", link_name="tan") +tan :: proc "c" (x: f64) -> f64 { + return math.tan(x) +} + +@(require, linkage="strong", link_name="atan2") +atan2 :: proc "c" (y: f64, x: f64) -> f64 { + return math.atan2(y, x) +} + +@(require, linkage="strong", link_name="modf") +modf :: proc "c" (num: f64, iptr: ^f64) -> f64 { + integral, fractional := math.modf(num) + iptr^ = integral + return fractional +} diff --git a/vendor/libc/sched.odin b/vendor/libc/sched.odin new file mode 100644 index 000000000..85fad3c05 --- /dev/null +++ b/vendor/libc/sched.odin @@ -0,0 +1,35 @@ +package odin_libc + +import "core:time" +import "core:thread" + +Clock :: enum i32 { + Monotonic = 1, +} + +Time_Spec :: struct { + tv_sec: i64, + tv_nsec: i64, +} + +@(require, linkage="strong", link_name="clock_gettime") +clock_gettine :: proc "c" (clockid: Clock, tp: ^Time_Spec) -> i32 { + switch clockid { + case .Monotonic: + tick := time.tick_now() + tp.tv_sec = tick._nsec/1e9 + tp.tv_nsec = tick._nsec%1e9/1000 + return 0 + + case: return -1 + } +} + +@(require, linkage="strong", link_name="sched_yield") +sched_yield :: proc "c" () -> i32 { + when thread.IS_SUPPORTED { + context = g_ctx + thread.yield() + } + return 0 +} diff --git a/vendor/libc/stdio.odin b/vendor/libc/stdio.odin index 97667a5c8..d41f790ee 100644 --- a/vendor/libc/stdio.odin +++ b/vendor/libc/stdio.odin @@ -1,18 +1,23 @@ #+build !freestanding package odin_libc +import "base:runtime" + import "core:c" import "core:io" import "core:os" +import "core:strconv" import stb "vendor:stb/sprintf" FILE :: uintptr +EOF :: -1 + @(require, linkage="strong", link_name="fopen") fopen :: proc "c" (path: cstring, mode: cstring) -> FILE { context = g_ctx - unimplemented("odin_libc.fopen") + unimplemented("vendor/libc: fopen") } @(require, linkage="strong", link_name="fseek") @@ -63,6 +68,31 @@ fwrite :: proc "c" (buffer: [^]byte, size: uint, count: uint, file: FILE) -> uin return uint(max(0, n)) } +@(require, linkage="strong", link_name="putchar") +putchar :: proc "c" (char: c.int) -> c.int { + context = g_ctx + + n, err := os.write_byte(os.stdout, byte(char)) + if n == 0 || err != nil { + return EOF + } + return char +} + +@(require, linkage="strong", link_name="getchar") +getchar :: proc "c" () -> c.int { + when #defined(os.stdin) { + ret: [1]byte + n, err := os.read(os.stdin, ret[:]) + if n == 0 || err != nil { + return EOF + } + return c.int(ret[0]) + } else { + return EOF + } +} + @(require, linkage="strong", link_name="vsnprintf") vsnprintf :: proc "c" (buf: [^]byte, count: uint, fmt: cstring, args: ^c.va_list) -> i32 { i32_count := i32(count) @@ -70,6 +100,11 @@ vsnprintf :: proc "c" (buf: [^]byte, count: uint, fmt: cstring, args: ^c.va_list return stb.vsnprintf(buf, i32_count, fmt, args) } +@(require, linkage="strong", link_name="vsprintf") +vsprintf :: proc "c" (buf: [^]byte, fmt: cstring, args: ^c.va_list) -> i32 { + return stb.vsprintf(buf, fmt, args) +} + @(require, linkage="strong", link_name="vfprintf") vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 { context = g_ctx @@ -105,3 +140,379 @@ vfprintf :: proc "c" (file: FILE, fmt: cstring, args: ^c.va_list) -> i32 { return i32(len(buf)) } + +/* +Derived from musl libc - MIT licensed - Copyright © 2005-2020 Rich Felker, et al. +*/ +@(require, linkage="strong", link_name="__sscanf") +_sscanf :: proc "c" (str, fmt: [^]byte, orig_ptrs: [^]rawptr) -> i32 { + Size :: enum u8 { + None, + hh, + h, + l, + L, + ll, + } + + store_int :: proc(dest: rawptr, size: Size, i: u64) { + if dest == nil { return } + #partial switch size { + case .hh: + (^c.char)(dest)^ = c.char(i) + case .h: + (^c.short)(dest)^ = c.short(i) + case .None: + (^c.int)(dest)^ = c.int(i) + case .l: + (^c.long)(dest)^ = c.long(i) + case .ll: + (^c.longlong)(dest)^ = c.longlong(i) + } + } + + context = g_ctx + + str := str + ptrs := orig_ptrs + + // TODO: implement wide char variants + + pos: u64 + dest: rawptr + ch, t: byte + // wcs: [^]c.wchar_t + s: [^]byte + k, i, width: int + alloc: bool + scanset: [257]byte + invert: u8 + matches: i32 + size: Size + input_fail, match_fail, fmt_fail, alloc_fail: bool + + main_loop: for p := fmt; p[0] != 0; p = p[1:] { + alloc = false + + if isspace(i32(p[0])) { + for isspace(i32(p[0])) { + p = p[1:] + } + for isspace(i32(str[0])) { + str = str[1:] + pos += 1 + } + } + + if p[0] != '%' || p[1] == '%' { + if p[0] == '%' { + p = p[1:] + } + ch = str[0] + if ch != p[0] { + if ch == 0 { + input_fail = true + break + } + match_fail = true + break + } + pos += 1 + continue + } + + p = p[1:] + if p[0] == '*' { + dest = nil + p = p[1:] + } else if isdigit(i32(p[0])) && p[1] == '$' { + dest = orig_ptrs[p[0] - '0'] + p = p[2:] + } else { + dest = ptrs[0] + ptrs = ptrs[1:] + } + + for width = 0; isdigit(i32(p[0])); p = p[1:] { + width = 10 * width + int(p[0] - '0') + } + + if p[0] == 'm' { + // wcs = nil + s = nil + alloc = dest != nil + p = p[1:] + } else { + alloc = false + } + + size = .None + p = p[1:] + switch p[-1] { + case 'h': + size = .h + if p[0] == 'h' { + p = p[1:] + size = .hh + } + case 'l': + size = .l + if p[0] == 'l' { + p = p[1:] + size = .ll + } + case 'j': + size = .ll + case 'z', 't': + size = .l + case 'L': + size = .L + case 'd', 'i', 'o', 'u', 'x', + 'a', 'e', 'f', 'g', + 'A', 'E', 'F', 'G', 'X', + 's', 'c', '[', + 'S', 'C', 'p', 'n': + p = p[-1:] + case: + fmt_fail = true + break main_loop + } + + t = p[0] + + switch t { + case 'C': + t = 'c' + size = .l + case 'S': + t = 's' + size = .l + } + + switch t { + case 'c': + if width < 1 { + width = 1 + } + case '[': + case 'n': + store_int(dest, size, pos) + continue + case: + for isspace(i32(str[0])) { + str = str[1:] + pos += 1 + } + } + + if str[0] == 0 { + input_fail = true + break + } + + if width == 0 { + width = max(int) + } + + switch t { + case 's', 'c', '[': + if t == 'c' || t == 's' { + runtime.memset(&scanset, -1, size_of(scanset)) + scanset[0] = 0 + if t == 's' { + scanset['\t'] = 0 + scanset['\n'] = 0 + scanset['\v'] = 0 + scanset['\f'] = 0 + scanset['\r'] = 0 + scanset[' '] = 0 + } + } else { + p = p[1:] + invert = 0 + if p[0] == '^' { + p = p[1:] + invert = 1 + } + + runtime.memset(&scanset, i32(invert), size_of(scanset)) + scanset[0] = 0 + if p[0] == '-' { + p = p[1:] + scanset['-'] = 1 - invert + } else if p[0] == ']' { + p = p[1:] + scanset[']'] = 1 - invert + } + + for ; p[0] != ']'; p = p[1:] { + if p[0] == 0 { + fmt_fail = true + break main_loop + } + if p[0] == '-' && p[1] != ']' { + c := p + p = p[1:] + for ch = c[0]; c[0] < p[0]; c, ch = c[1:], c[0] { + scanset[ch] = 1 - invert + } + scanset[p[0]] = 1 - invert + } + } + } + + // wcs = nil + s = nil + i = 0 + k = t == 'c' ? width + 1 : 31 + if size == .l { + unimplemented("vendor/libc: sscanf wide character support") + } else if alloc { + s = make([^]byte, k) + if s == nil { + alloc_fail = true + break main_loop + } + + for ch = str[0]; scanset[ch] != 0 && i < width; { + s[i] = ch + i += 1 + if i == k { + old_size := k + k += k + 1 + tmp, _ := runtime.non_zero_mem_resize(s, old_size, k) + if tmp == nil { + alloc_fail = true + break main_loop + } + s = raw_data(tmp) + } + + str = str[1:] + ch = str[0] + } + } else { + s = cast([^]byte)dest + if s != nil { + for ch = str[0]; scanset[ch] != 0 && i < width; { + s[i] = ch + i += 1 + + str = str[1:] + ch = str[0] + } + } else { + for ; scanset[str[0]] != 0 && i < width; str = str[1:] {} + } + } + + if i == 0 { + match_fail = true + break main_loop + } + + str = str[-1:] + + if t == 'c' && i != width { + match_fail = true + break main_loop + } + + if alloc { + (^rawptr)(dest)^ = s + } + + if t != 'c' { + if s != nil {s[i] = 0} + } + case: + base := -1 + switch t { + case 'p', 'X', 'x': + base = 16 + if i + 2 < width && str[0] == '0' && str[1] == 'x' { + str = str[2:] + } + case 'o': + base = 8 + if i + 1 < width && str[0] == '0' { + str = str[1:] + } + case 'd', 'u': + base = 10 + case 'i': + base = 0 + } + + odin_str := string(cstring(str)) + odin_str = odin_str[:min(len(odin_str), width-i)] + cnt: int + if base >= 0 { + x: i64 + if base == 0 { + x, _ = strconv.parse_i64_maybe_prefixed(odin_str, &cnt) + } else { + x, _ = strconv.parse_i64_of_base(odin_str, base, &cnt) + } + + if cnt == 0 { + match_fail = true + break main_loop + } + + if t == 'p' && dest != nil { + (^rawptr)(dest)^ = rawptr(uintptr(x)) + } else { + store_int(dest, size, u64(x)) + } + } else { + // should be a guarantee bcs of validation above. + // switch t { + // case 'a', 'A', + // 'e', 'E', + // 'f', 'F', + // 'g', 'G': + // } + x, _ := strconv.parse_f64(odin_str, &cnt) + + if cnt == 0 { + match_fail = true + break main_loop + } + + if dest != nil { + #partial switch size { + case .None: + (^c.float)(dest)^ = c.float(x) + case .l: + (^c.double)(dest)^ = c.double(x) + case .L: + (^c.double)(dest)^ = c.double(x) // longdouble + } + } + } + + pos += u64(cnt) + str = str[cnt:] + } + + if dest != nil { + matches += 1 + } + } + + if fmt_fail || alloc_fail || input_fail { + if matches == 0 { + matches = -1 + } + } + + if match_fail { + if alloc { + free(s) + // free(wcs) + } + } + + return matches +} diff --git a/vendor/libc/stdlib.odin b/vendor/libc/stdlib.odin index 54590c1c9..bb9233a28 100644 --- a/vendor/libc/stdlib.odin +++ b/vendor/libc/stdlib.odin @@ -1,8 +1,10 @@ package odin_libc +import "base:intrinsics" import "base:runtime" import "core:c" +import "core:os" import "core:slice" import "core:sort" import "core:strconv" @@ -108,12 +110,81 @@ atof :: proc "c" (str: cstring) -> f64 { @(require, linkage="strong", link_name="strtol") strtol :: proc "c" (str: cstring, str_end: ^cstring, base: i32) -> c.long { context = g_ctx - sstr := string(str) sstr = strings.trim_left_space(sstr) n: int i, _ := strconv.parse_i64_of_base(sstr, int(base), &n) str_end ^= cstring(raw_data(sstr)[n:]) + if str_end != nil { + str_end ^= cstring(raw_data(sstr)[n:]) + } return c.long(clamp(i, i64(min(c.long)), i64(max(c.long)))) } + +@(require, linkage="strong", link_name="strtod") +strtod :: proc "c" (str: cstring, str_end: ^cstring) -> c.double { + context = g_ctx + + sstr := string(str) + sstr = strings.trim_left_space(sstr) + + n: int + val, _ := strconv.parse_f64(sstr, &n) + if str_end != nil { + str_end ^= cstring(raw_data(sstr)[n:]) + } + + return c.double(val) +} + +@(require, linkage="strong", link_name="abort") +abort :: proc "c" () -> ! { + intrinsics.trap() +} + +ATEXIT_MAX :: 32 + +@(private) +atexit_functions: [ATEXIT_MAX]proc "c" () +@(private) +atexit_functions_count: int + +@(require, linkage="strong", link_name="atexit") +atexit :: proc "c" (function: proc "c" ()) -> i32 { + entry := intrinsics.atomic_add(&atexit_functions_count, 1) + if entry >= ATEXIT_MAX { + return -1 + } + + atexit_functions[entry] = function + return 0 +} + + +@(require, linkage="strong", link_name="exit") +exit :: proc "c" (exit_code: c.int) -> ! { + finish_atexit() + os.exit(int(exit_code)) +} + +@(private, fini) +finish_atexit :: proc "contextless" () { + n := intrinsics.atomic_exchange(&atexit_functions_count, 0) + for function in atexit_functions[:n] { + function() + } +} + +ldiv_t :: struct { + quot: c.long, + rem: c.long, +} + +@(require, linkage="strong", link_name="ldiv") +ldiv :: proc "c" (number: c.long, denom: c.long) -> ldiv_t { + return { + quot = number / denom, + rem = number %% denom, + } +} diff --git a/vendor/libc/string.odin b/vendor/libc/string.odin index 1ab0803da..b8115ea88 100644 --- a/vendor/libc/string.odin +++ b/vendor/libc/string.odin @@ -5,6 +5,7 @@ import "base:intrinsics" import "core:c" import "core:strings" import "core:mem" +import "core:bytes" // NOTE: already defined by Odin. // void *memcpy(void *, const void *, size_t); @@ -109,3 +110,12 @@ strstr :: proc "c" (str: cstring, substr: cstring) -> cstring { return cstring(([^]byte)(str)[idx:]) } +@(require, linkage="strong", link_name="memchr") +memchr :: proc "c" (str: [^]byte, c: i32, n: uint) -> [^]byte { + idx := bytes.index_byte(str[:n], u8(c)) + if idx < 0 { + return nil + } + + return str[idx:] +} diff --git a/vendor/libc/time.odin b/vendor/libc/time.odin new file mode 100644 index 000000000..6d8b8f611 --- /dev/null +++ b/vendor/libc/time.odin @@ -0,0 +1,10 @@ +package odin_libc + +import "core:time" + +clock_t :: i64 + +@(require, linkage="strong", link_name="clock") +clock :: proc "c" () -> clock_t { + return time.tick_now()._nsec +} diff --git a/vendor/miniaudio/common.odin b/vendor/miniaudio/common.odin index d72c3f251..e675cb7f6 100644 --- a/vendor/miniaudio/common.odin +++ b/vendor/miniaudio/common.odin @@ -20,12 +20,12 @@ foreign import lib { LIB } BINDINGS_VERSION_MAJOR :: 0 BINDINGS_VERSION_MINOR :: 11 -BINDINGS_VERSION_REVISION :: 21 +BINDINGS_VERSION_REVISION :: 22 BINDINGS_VERSION :: [3]u32{BINDINGS_VERSION_MAJOR, BINDINGS_VERSION_MINOR, BINDINGS_VERSION_REVISION} -BINDINGS_VERSION_STRING :: "0.11.21" +BINDINGS_VERSION_STRING :: "0.11.22" @(init) -version_check :: proc() { +version_check :: proc "contextless" () { v: [3]u32 version(&v.x, &v.y, &v.z) if v != BINDINGS_VERSION { @@ -43,7 +43,7 @@ version_check :: proc() { n += copy(buf[n:], "and executing `make`") } - panic(string(buf[:n])) + panic_contextless(string(buf[:n])) } } diff --git a/vendor/miniaudio/data_conversion.odin b/vendor/miniaudio/data_conversion.odin index c33f54707..d95607dd9 100644 --- a/vendor/miniaudio/data_conversion.odin +++ b/vendor/miniaudio/data_conversion.odin @@ -194,7 +194,7 @@ foreign lib { resampler_get_expected_output_frame_count :: proc(pResampler: ^resampler, inputFrameCount: u64, pOutputFrameCount: ^u64) -> result --- /* - Resets the resampler's timer and clears it's internal cache. + Resets the resampler's timer and clears its internal cache. */ resampler_reset :: proc(pResampler: ^resampler) -> result --- } @@ -421,7 +421,7 @@ foreign lib { /* Copies a channel map. - Both input and output channel map buffers must have a capacity of at at least `channels`. + Both input and output channel map buffers must have a capacity of at least `channels`. */ channel_map_copy :: proc(pOut: [^]channel, pIn: [^]channel, channels: u32) --- diff --git a/vendor/miniaudio/decoding.odin b/vendor/miniaudio/decoding.odin index f1fa279ac..e2f33b8e7 100644 --- a/vendor/miniaudio/decoding.odin +++ b/vendor/miniaudio/decoding.odin @@ -71,7 +71,7 @@ decoder :: struct { pInputCache: rawptr, /* In input format. Can be null if it's not needed. */ inputCacheCap: u64, /* The capacity of the input cache. */ inputCacheConsumed: u64, /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */ - inputCacheRemaining: u64, /* The number of valid frames remaining in the cahce. */ + inputCacheRemaining: u64, /* The number of valid frames remaining in the cache. */ allocationCallbacks: allocation_callbacks, data: struct #raw_union { vfs: struct { @@ -111,7 +111,7 @@ foreign lib { decoder_read_pcm_frames :: proc(pDecoder: ^decoder, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- /* - Seeks to a PCM frame based on it's absolute index. + Seeks to a PCM frame based on its absolute index. This is not thread safe without your own synchronization. */ diff --git a/vendor/miniaudio/device_io_procs.odin b/vendor/miniaudio/device_io_procs.odin index 21ac1afd7..a14de807c 100644 --- a/vendor/miniaudio/device_io_procs.odin +++ b/vendor/miniaudio/device_io_procs.odin @@ -12,6 +12,8 @@ foreign lib { device_job_thread_uninit :: proc(pJobThread: ^device_job_thread, pAllocationCallbacks: ^allocation_callbacks) --- device_job_thread_post :: proc(pJobThread: ^device_job_thread, pJob: ^job) -> result --- device_job_thread_next :: proc(pJobThread: ^device_job_thread, pJob: ^job) -> result --- + + device_id_equal :: proc(pA: ^device_id, pB: ^device_id) -> b32 --- /* Initializes a `ma_context_config` object. @@ -370,6 +372,9 @@ foreign lib { This function will allocate memory internally for the device lists and return a pointer to them through the `ppPlaybackDeviceInfos` and `ppCaptureDeviceInfos` parameters. If you do not want to incur the overhead of these allocations consider using `ma_context_enumerate_devices()` which will instead use a callback. + Note that this only retrieves the ID and name/description of the device. The reason for only retrieving basic information is that it would otherwise require + opening the backend device in order to probe it for more detailed information which can be inefficient. Consider using `ma_context_get_device_info()` for this, + but don't call it from within the enumeration callback. Parameters ---------- @@ -411,7 +416,7 @@ foreign lib { See Also -------- - ma_context_get_devices() + ma_context_enumerate_devices() */ context_get_devices :: proc(pContext: ^context_type, ppPlaybackDeviceInfos: ^[^]device_info, pPlaybackDeviceCount: ^u32, ppCaptureDeviceInfos: ^[^]device_info, pCaptureDeviceCount: ^u32) -> result --- @@ -550,7 +555,7 @@ foreign lib { playback, capture, full-duplex or loopback. (Note that loopback mode is only supported on select backends.) Sending and receiving audio data to and from the device is done via a callback which is fired by miniaudio at periodic time intervals. - The frequency at which data is delivered to and from a device depends on the size of it's period. The size of the period can be defined in terms of PCM frames + The frequency at which data is delivered to and from a device depends on the size of its period. The size of the period can be defined in terms of PCM frames or milliseconds, whichever is more convenient. Generally speaking, the smaller the period, the lower the latency at the expense of higher CPU usage and increased risk of glitching due to the more frequent and granular data deliver intervals. The size of a period will depend on your requirements, but miniaudio's defaults should work fine for most scenarios. If you're building a game you should leave this fairly small, whereas if you're building a simple @@ -624,7 +629,7 @@ foreign lib { performanceProfile A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or - `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value. + `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at its default value. noPreSilencedOutputBuffer When set to true, the contents of the output buffer passed into the data callback will be left undefined. When set to false (default), the contents of @@ -664,7 +669,7 @@ foreign lib { A pointer that will passed to callbacks in pBackendVTable. resampling.linear.lpfOrder - The linear resampler applies a low-pass filter as part of it's processing for anti-aliasing. This setting controls the order of the filter. The higher + The linear resampler applies a low-pass filter as part of its processing for anti-aliasing. This setting controls the order of the filter. The higher the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`. @@ -741,6 +746,9 @@ foreign lib { pulse.pStreamNameCapture PulseAudio only. Sets the stream name for capture. + pulse.channelMap + PulseAudio only. Sets the channel map that is requested from PulseAudio. See MA_PA_CHANNEL_MAP_* constants. Defaults to MA_PA_CHANNEL_MAP_AIFF. + coreaudio.allowNominalSampleRateChange Core Audio only. Desktop only. When enabled, allows the sample rate of the device to be changed at the operating system level. This is disabled by default in order to prevent intrusive changes to the user's system. This is useful if you want to use a sample rate @@ -914,7 +922,7 @@ foreign lib { Remarks ------- - You only need to use this function if you want to configure the context differently to it's defaults. You should never use this function if you want to manage + You only need to use this function if you want to configure the context differently to its defaults. You should never use this function if you want to manage your own context. See the documentation for `ma_context_init()` for information on the different context configuration options. diff --git a/vendor/miniaudio/device_io_types.odin b/vendor/miniaudio/device_io_types.odin index b52a3f423..9d64602f8 100644 --- a/vendor/miniaudio/device_io_types.odin +++ b/vendor/miniaudio/device_io_types.odin @@ -427,6 +427,7 @@ device_config :: struct { pulse: struct { pStreamNamePlayback: cstring, pStreamNameCapture: cstring, + channelMap: i32, }, coreaudio: struct { allowNominalSampleRateChange: b32, /* Desktop only. When enabled, allows changing of the sample rate at the operating system level. */ @@ -443,6 +444,7 @@ device_config :: struct { allowedCapturePolicy: aaudio_allowed_capture_policy, noAutoStartAfterReroute: b32, enableCompatibilityWorkarounds: b32, + allowSetBufferCapacity: b32, }, } @@ -514,7 +516,7 @@ and on output returns detailed information about the device in `ma_device_info`. case when the device ID is NULL, in which case information about the default device needs to be retrieved. Once the context has been created and the device ID retrieved (if using anything other than the default device), the device can be created. -This is a little bit more complicated than initialization of the context due to it's more complicated configuration. When initializing a +This is a little bit more complicated than initialization of the context due to its more complicated configuration. When initializing a device, a duplex device may be requested. This means a separate data format needs to be specified for both playback and capture. On input, the data format is set to what the application wants. On output it's set to the native format which should match as closely as possible to the requested format. The conversion between the format requested by the application and the device's native format will be handled @@ -535,10 +537,10 @@ asynchronous reading and writing, `onDeviceStart()` and `onDeviceStop()` should The handling of data delivery between the application and the device is the most complicated part of the process. To make this a bit easier, some helper callbacks are available. If the backend uses a blocking read/write style of API, the `onDeviceRead()` and `onDeviceWrite()` callbacks can optionally be implemented. These are blocking and work just like reading and writing from a file. If the -backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within it's callback. +backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within its callback. This allows miniaudio to then process any necessary data conversion and then pass it to the miniaudio data callback. -If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceDataLoop()` callback +If the backend requires absolute flexibility with its data delivery, it can optionally implement the `onDeviceDataLoop()` callback which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional. The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been @@ -575,6 +577,9 @@ context_config :: struct { threadStackSize: c.size_t, pUserData: rawptr, allocationCallbacks: allocation_callbacks, + dsound: struct { + hWnd: handle, /* HWND. Optional window handle to pass into SetCooperativeLevel(). Will default to the foreground window, and if that fails, the desktop window. */ + }, alsa: struct { useVerboseDeviceEnumeration: b32, }, @@ -649,6 +654,7 @@ context_type :: struct { } when SUPPORT_WASAPI else struct {}), dsound: (struct { + hWnd: handle, /* Can be null. */ hDSoundDLL: handle, DirectSoundCreate: proc "system" (), DirectSoundEnumerateA: proc "system" (), @@ -1195,6 +1201,7 @@ device :: struct { aaudio: (struct { /*AAudioStream**/ pStreamPlayback: rawptr, /*AAudioStream**/ pStreamCapture: rawptr, + rerouteLock: mutex, usage: aaudio_usage, contentType: aaudio_content_type, inputPreset: aaudio_input_preset, diff --git a/vendor/miniaudio/doc.odin b/vendor/miniaudio/doc.odin index 33c613ae4..ff7924b89 100644 --- a/vendor/miniaudio/doc.odin +++ b/vendor/miniaudio/doc.odin @@ -295,7 +295,7 @@ avoids the same sound being loaded multiple times. The node graph is used for mixing and effect processing. The idea is that you connect a number of nodes into the graph by connecting each node's outputs to another node's inputs. Each node can -implement it's own effect. By chaining nodes together, advanced mixing and effect processing can +implement its own effect. By chaining nodes together, advanced mixing and effect processing can be achieved. The engine encapsulates both the resource manager and the node graph to create a simple, easy to @@ -400,7 +400,7 @@ the be started and/or stopped at a specific time. This can be done with the foll ``` The start/stop time needs to be specified based on the absolute timer which is controlled by the -engine. The current global time time in PCM frames can be retrieved with +engine. The current global time in PCM frames can be retrieved with `ma_engine_get_time_in_pcm_frames()`. The engine's global time can be changed with `ma_engine_set_time_in_pcm_frames()` for synchronization purposes if required. Note that scheduling a start time still requires an explicit call to `ma_sound_start()` before anything will play: @@ -432,11 +432,11 @@ Sounds and sound groups are nodes in the engine's node graph and can be plugged API. This makes it possible to connect sounds and sound groups to effect nodes to produce complex effect chains. -A sound can have it's volume changed with `ma_sound_set_volume()`. If you prefer decibel volume +A sound can have its volume changed with `ma_sound_set_volume()`. If you prefer decibel volume control you can use `ma_volume_db_to_linear()` to convert from decibel representation to linear. Panning and pitching is supported with `ma_sound_set_pan()` and `ma_sound_set_pitch()`. If you know -a sound will never have it's pitch changed with `ma_sound_set_pitch()` or via the doppler effect, +a sound will never have its pitch changed with `ma_sound_set_pitch()` or via the doppler effect, you can specify the `MA_SOUND_FLAG_NO_PITCH` flag when initializing the sound for an optimization. By default, sounds and sound groups have spatialization enabled. If you don't ever want to @@ -485,21 +485,12 @@ link the relevant frameworks but should compile cleanly out of the box with Xcod through the command line requires linking to `-lpthread` and `-lm`. Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's -notarization process. To fix this there are two options. The first is to use the -`MA_NO_RUNTIME_LINKING` option, like so: - - ```c - #ifdef __APPLE__ - #define MA_NO_RUNTIME_LINKING - #endif - #define MINIAUDIO_IMPLEMENTATION - #include "miniaudio.h" - ``` - -This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioToolbox`. -If you get errors about AudioToolbox, try with `-framework AudioUnit` instead. You may get this when -using older versions of iOS. Alternatively, if you would rather keep using runtime linking you can -add the following to your entitlements.xcent file: +notarization process. To fix this there are two options. The first is to compile with +`-DMA_NO_RUNTIME_LINKING` which in turn will require linking with +`-framework CoreFoundation -framework CoreAudio -framework AudioToolbox`. If you get errors about +AudioToolbox, try with `-framework AudioUnit` instead. You may get this when using older versions +of iOS. Alternatively, if you would rather keep using runtime linking you can add the following to +your entitlements.xcent file: ``` com.apple.security.cs.allow-dyld-environment-variables @@ -557,7 +548,7 @@ To run locally, you'll need to use emrun: 2.7. Build Options ------------------ -`#define` these options before including miniaudio.h. +`#define` these options before including miniaudio.c, or pass them as compiler flags: +----------------------------------+--------------------------------------------------------------------+ | Option | Description | @@ -588,6 +579,8 @@ To run locally, you'll need to use emrun: +----------------------------------+--------------------------------------------------------------------+ | MA_NO_WEBAUDIO | Disables the Web Audio backend. | +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_CUSTOM | Disables support for custom backends. | + +----------------------------------+--------------------------------------------------------------------+ | MA_NO_NULL | Disables the null backend. | +----------------------------------+--------------------------------------------------------------------+ | MA_ENABLE_ONLY_SPECIFIC_BACKENDS | Disables all backends by default and requires `MA_ENABLE_*` to | @@ -632,6 +625,9 @@ To run locally, you'll need to use emrun: | MA_ENABLE_WEBAUDIO | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | | | enable the Web Audio backend. | +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_CUSTOM | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable custom backends. | + +----------------------------------+--------------------------------------------------------------------+ | MA_ENABLE_NULL | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | | | enable the null backend. | +----------------------------------+--------------------------------------------------------------------+ @@ -695,11 +691,30 @@ To run locally, you'll need to use emrun: | | You may need to enable this if your target platform does not allow | | | runtime linking via `dlopen()`. | +----------------------------------+--------------------------------------------------------------------+ + | MA_USE_STDINT | (Pass this in a compiler flag. Do not #define this before | + | | miniaudio.c) Forces the use of stdint.h for sized types. | + +----------------------------------+--------------------------------------------------------------------+ | MA_DEBUG_OUTPUT | Enable `printf()` output of debug logs (`MA_LOG_LEVEL_DEBUG`). | +----------------------------------+--------------------------------------------------------------------+ | MA_COINIT_VALUE | Windows only. The value to pass to internal calls to | | | `CoInitializeEx()`. Defaults to `COINIT_MULTITHREADED`. | +----------------------------------+--------------------------------------------------------------------+ + | MA_FORCE_UWP | Windows only. Affects only the WASAPI backend. Will force the | + | | WASAPI backend to use the UWP code path instead of the regular | + | | desktop path. This is normally auto-detected and should rarely be | + | | needed to be used explicitly, but can be useful for debugging. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ON_THREAD_ENTRY | Defines some code that will be executed as soon as an internal | + | | miniaudio-managed thread is created. This will be the first thing | + | | to be executed by the thread entry point. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ON_THREAD_EXIT | Defines some code that will be executed from the entry point of an | + | | internal miniaudio-managed thread upon exit. This will be the last | + | | thing to be executed before the thread's entry point exits. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_THREAD_DEFAULT_STACK_SIZE | If set, specifies the default stack size used by miniaudio-managed | + | | threads. | + +----------------------------------+--------------------------------------------------------------------+ | MA_API | Controls how public APIs should be decorated. Default is `extern`. | +----------------------------------+--------------------------------------------------------------------+ @@ -1311,7 +1326,7 @@ only works for sounds that were initialized with `ma_sound_init_from_file()` and When you initialize a sound, if you specify a sound group the sound will be attached to that group automatically. If you set it to NULL, it will be automatically attached to the engine's endpoint. -If you would instead rather leave the sound unattached by default, you can can specify the +If you would instead rather leave the sound unattached by default, you can specify the `MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT` flag. This is useful if you want to set up a complex node graph. @@ -1688,6 +1703,7 @@ combination of the following flags: MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING ``` When no flags are specified (set to 0), the sound will be fully loaded into memory, but not @@ -1708,6 +1724,14 @@ can instead stream audio data which you can do by specifying the second pages. When a new page needs to be decoded, a job will be posted to the job queue and then subsequently processed in a job thread. +The `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING` flag can be used so that the sound will loop +when it reaches the end by default. It's recommended you use this flag when you want to have a +looping streaming sound. If you try loading a very short sound as a stream, you will get a glitch. +This is because the resource manager needs to pre-fill the initial buffer at initialization time, +and if you don't specify the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING` flag, the resource +manager will assume the sound is not looping and will stop filling the buffer when it reaches the +end, therefore resulting in a discontinuous buffer. + For in-memory sounds, reference counting is used to ensure the data is loaded only once. This means multiple calls to `ma_resource_manager_data_source_init()` with the same file path will result in the file data only being loaded once. Each call to `ma_resource_manager_data_source_init()` must be @@ -1722,7 +1746,7 @@ actual file paths. When `ma_resource_manager_data_source_init()` is called (with `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag), the resource manager will look for these explicitly registered data buffers and, if found, will use it as the backing data for the data source. Note that the resource manager does *not* make a copy of this data so it is up to the -caller to ensure the pointer stays valid for it's lifetime. Use +caller to ensure the pointer stays valid for its lifetime. Use `ma_resource_manager_unregister_data()` to unregister the self-managed data. You can also use `ma_resource_manager_register_file()` and `ma_resource_manager_unregister_file()` to register and unregister a file. It does not make sense to use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` @@ -2033,7 +2057,7 @@ In the above graph, it starts with two data sources whose outputs are attached t splitter node. It's at this point that the two data sources are mixed. After mixing, the splitter performs it's processing routine and produces two outputs which is simply a duplication of the input stream. One output is attached to a low pass filter, whereas the other output is attached to -a echo/delay. The outputs of the the low pass filter and the echo are attached to the endpoint, and +a echo/delay. The outputs of the low pass filter and the echo are attached to the endpoint, and since they're both connected to the same input bus, they'll be mixed. Each input bus must be configured to accept the same number of channels, but the number of channels @@ -2074,7 +2098,7 @@ data from the graph: ``` When you read audio data, miniaudio starts at the node graph's endpoint node which then pulls in -data from it's input attachments, which in turn recursively pull in data from their inputs, and so +data from its input attachments, which in turn recursively pull in data from their inputs, and so on. At the start of the graph there will be some kind of data source node which will have zero inputs and will instead read directly from a data source. The base nodes don't literally need to read from a `ma_data_source` object, but they will always have some kind of underlying object that @@ -2320,7 +2344,7 @@ You can start and stop a node with the following: By default the node is in a started state, but since it won't be connected to anything won't actually be invoked by the node graph until it's connected. When you stop a node, data will not be -read from any of it's input connections. You can use this property to stop a group of sounds +read from any of its input connections. You can use this property to stop a group of sounds atomically. You can configure the initial state of a node in it's config: @@ -2413,29 +2437,29 @@ audio thread is finished so that control is not handed back to the caller thereb chance to free the node's memory. When the audio thread is processing a node, it does so by reading from each of the output buses of -the node. In order for a node to process data for one of it's output buses, it needs to read from -each of it's input buses, and so on an so forth. It follows that once all output buses of a node +the node. In order for a node to process data for one of its output buses, it needs to read from +each of its input buses, and so on an so forth. It follows that once all output buses of a node are detached, the node as a whole will be disconnected and no further processing will occur unless it's output buses are reattached, which won't be happening when the node is being uninitialized. By having `ma_node_detach_output_bus()` wait until the audio thread is finished with it, we can simplify a few things, at the expense of making `ma_node_detach_output_bus()` a bit slower. By doing this, the implementation of `ma_node_uninit()` becomes trivial - just detach all output -nodes, followed by each of the attachments to each of it's input nodes, and then do any final clean +nodes, followed by each of the attachments to each of its input nodes, and then do any final clean up. With the above design, the worst-case scenario is `ma_node_detach_output_bus()` taking as long as it takes to process the output bus being detached. This will happen if it's called at just the wrong moment where the audio thread has just iterated it and has just started processing. The caller of `ma_node_detach_output_bus()` will stall until the audio thread is finished, which -includes the cost of recursively processing it's inputs. This is the biggest compromise made with -the approach taken by miniaudio for it's lock-free processing system. The cost of detaching nodes +includes the cost of recursively processing its inputs. This is the biggest compromise made with +the approach taken by miniaudio for its lock-free processing system. The cost of detaching nodes earlier in the pipeline (data sources, for example) will be cheaper than the cost of detaching higher level nodes, such as some kind of final post-processing endpoint. If you need to do mass detachments, detach starting from the lowest level nodes and work your way towards the final endpoint node (but don't try detaching the node graph's endpoint). If the audio thread is not running, detachment will be fast and detachment in any order will be the same. The reason nodes need to wait for their input attachments to complete is due to the potential for desyncs between -data sources. If the node was to terminate processing mid way through processing it's inputs, +data sources. If the node was to terminate processing mid way through processing its inputs, there's a chance that some of the underlying data sources will have been read, but then others not. That will then result in a potential desynchronization when detaching and reattaching higher-level nodes. A possible solution to this is to have an option when detaching to terminate processing @@ -2806,7 +2830,7 @@ weights. Custom weights can be passed in as the last parameter of `ma_channel_converter_config_init()`. Predefined channel maps can be retrieved with `ma_channel_map_init_standard()`. This takes a -`ma_standard_channel_map` enum as it's first parameter, which can be one of the following: +`ma_standard_channel_map` enum as its first parameter, which can be one of the following: +-----------------------------------+-----------------------------------------------------------+ | Name | Description | @@ -2892,7 +2916,7 @@ like the following: ma_resample_algorithm_linear); ma_resampler resampler; - ma_result result = ma_resampler_init(&config, &resampler); + ma_result result = ma_resampler_init(&config, NULL, &resampler); if (result != MA_SUCCESS) { // An error occurred... } @@ -3134,7 +3158,7 @@ Biquad filtering is achieved with the `ma_biquad` API. Example: ```c ma_biquad_config config = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2); - ma_result result = ma_biquad_init(&config, &biquad); + ma_result result = ma_biquad_init(&config, NULL, &biquad); if (result != MA_SUCCESS) { // Error. } diff --git a/vendor/miniaudio/engine.odin b/vendor/miniaudio/engine.odin index a06e6c62c..e5364d782 100644 --- a/vendor/miniaudio/engine.odin +++ b/vendor/miniaudio/engine.odin @@ -18,7 +18,8 @@ sound_flag :: enum c.int { ASYNC = 2, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */ WAIT_INIT = 3, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */ UNKNOWN_LENGTH = 4, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH */ - + LOOPING = 5, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING */ + /* ma_sound specific flags. */ NO_DEFAULT_ATTACHMENT = 12, /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */ NO_PITCH = 13, /* Disable pitch shifting with ma_sound_set_pitch() and ma_sound_group_set_pitch(). This is an optimization. */ @@ -51,7 +52,7 @@ engine_node_config :: struct { /* Base node object for both ma_sound and ma_sound_group. */ engine_node :: struct { - baseNode: node_base, /* Must be the first member for compatiblity with the ma_node API. */ + baseNode: node_base, /* Must be the first member for compatibility with the ma_node API. */ pEngine: ^engine, /* A pointer to the engine. Set based on the value from the config. */ sampleRate: u32, /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */ volumeSmoothTimeInPCMFrames: u32, @@ -113,7 +114,6 @@ sound_config :: struct { rangeEndInPCMFrames: u64, loopPointBegInPCMFrames: u64, loopPointEndInPCMFrames: u64, - isLooping: b32, endCallback: sound_end_proc, /* Fired when the sound reaches the end. Will be fired from the audio thread. Do not restart, uninitialize or otherwise change the state of the sound from here. Instead fire an event or set a variable to indicate to a different thread to change the start of the sound. Will not be fired in response to a scheduled stop with ma_sound_set_stop_time_*(). */ pEndCallbackUserData: rawptr, @@ -121,6 +121,8 @@ sound_config :: struct { initNotifications: resource_manager_pipeline_notifications, pDoneFence: ^fence, /* Deprecated. Use initNotifications instead. Released when the resource manager has finished decoding the entire sound. Not used with streams. */ + + isLooping: b32, /* Deprecated. Use the MA_SOUND_FLAG_LOOPING in `flags` instead. */ } sound :: struct { @@ -226,6 +228,7 @@ foreign lib { sound_is_looping :: proc(pSound: ^sound) -> b32 --- sound_at_end :: proc(pSound: ^sound) -> b32 --- sound_seek_to_pcm_frame :: proc(pSound: ^sound, frameIndex: u64) -> result --- /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */ + sound_seek_to_second :: proc(pSound: ^sound, seekPointInSeconds: f32) -> result --- /* Abstraction to ma_sound_seek_to_pcm_frame() */ sound_get_data_format :: proc(pSound: ^sound, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: ^channel, channelMapCap: c.size_t) -> result --- sound_get_cursor_in_pcm_frames :: proc(pSound: ^sound, pCursor: ^u64) -> result --- sound_get_length_in_pcm_frames :: proc(pSound: ^sound, pLength: ^u64) -> result --- @@ -323,6 +326,7 @@ engine_config :: struct { gainSmoothTimeInMilliseconds: u32, /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */ defaultVolumeSmoothTimeInPCMFrames: u32, /* Defaults to 0. Controls the default amount of smoothing to apply to volume changes to sounds. High values means more smoothing at the expense of high latency (will take longer to reach the new volume). */ + preMixStackSizeInBytes: u32, /* A stack is used for internal processing in the node graph. This allows you to configure the size of this stack. Smaller values will reduce the maximum depth of your node graph. You should rarely need to modify this. */ allocationCallbacks: allocation_callbacks, noAutoStart: b32, /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */ @@ -344,7 +348,7 @@ engine :: struct { allocationCallbacks: allocation_callbacks, ownsResourceManager: b8, ownsDevice: b8, - inlinedSoundLock: spinlock, /* For synchronizing access so the inlined sound list. */ + inlinedSoundLock: spinlock, /* For synchronizing access to the inlined sound list. */ pInlinedSoundHead: ^sound_inlined, /* The first inlined sound. Inlined sounds are tracked in a linked list. */ inlinedSoundCount: u32, /*atomic*/ /* The total number of allocated inlined sound objects. Used for debugging. */ gainSmoothTimeInFrames: u32, /* The number of frames to interpolate the gain of spatialized sounds across. */ diff --git a/vendor/miniaudio/lib/miniaudio.lib b/vendor/miniaudio/lib/miniaudio.lib index d339c746e..c9ee60979 100644 Binary files a/vendor/miniaudio/lib/miniaudio.lib and b/vendor/miniaudio/lib/miniaudio.lib differ diff --git a/vendor/miniaudio/node_graph.odin b/vendor/miniaudio/node_graph.odin index 610ada7a8..496d566f4 100644 --- a/vendor/miniaudio/node_graph.odin +++ b/vendor/miniaudio/node_graph.odin @@ -19,6 +19,13 @@ MAX_NODE_LOCAL_BUS_COUNT :: 2 /* Use this when the bus count is determined by the node instance rather than the vtable. */ NODE_BUS_COUNT_UNKNOWN :: 255 +/* For some internal memory management of ma_node_graph. */ +stack :: struct { + offset: uint, + sizeInBytes: uint, + _data: [1]byte, +} + node :: struct {} /* Node flags. */ @@ -53,7 +60,7 @@ node_vtable :: struct { onProcess: proc "c" (pNode: ^node, ppFramesIn: ^[^]f32, pFrameCountIn: ^u32, ppFramesOut: ^[^]f32, pFrameCountOut: ^u32), /* - A callback for retrieving the number of a input frames that are required to output the + A callback for retrieving the number of input frames that are required to output the specified number of output frames. You would only want to implement this when the node performs resampling. This is optional, even for nodes that perform resampling, but it does offer a small reduction in latency as it allows miniaudio to calculate the exact number of input frames @@ -134,8 +141,12 @@ node_input_bus :: struct { node_base :: struct { /* These variables are set once at startup. */ - pNodeGraph: ^node_graph, /* The graph this node belongs to. */ + pNodeGraph: ^node_graph, /* The graph this node belongs to. */ vtable: ^node_vtable, + inputBusCount: u32, + outputBusCount: u32, + pInputBuses: [^]node_input_bus `fmt:"v,inputBusCount"`, + pOutputBuses: [^]node_output_bus `fmt:"v,outputBusCount"`, pCachedData: [^]f32, /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */ cachedDataCapInFramesPerBus: u16, /* The capacity of the input data cache in frames, per bus. */ @@ -148,10 +159,6 @@ node_base :: struct { state: node_state, /*atomic*/ /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */ stateTimes: [2]u64, /*atomic*/ /* Indexed by ma_node_state. Specifies the time based on the global clock that a node should be considered to be in the relevant state. */ localTime: u64, /*atomic*/ /* The node's local clock. This is just a running sum of the number of output frames that have been processed. Can be modified by any thread with `ma_node_set_time()`. */ - inputBusCount: u32, - outputBusCount: u32, - pInputBuses: [^]node_input_bus, - pOutputBuses: [^]node_output_bus, /* Memory management. */ _inputBuses: [MAX_NODE_LOCAL_BUS_COUNT]node_input_bus, @@ -189,18 +196,25 @@ foreign lib { } node_graph_config :: struct { - channels: u32, - nodeCacheCapInFrames: u16, + channels: u32, + processingSizeInFrames: u32, /* This is the preferred processing size for node processing callbacks unless overridden by a node itself. Can be 0 in which case it will be based on the frame count passed into ma_node_graph_read_pcm_frames(), but will not be well defined. */ + preMixStackSizeInBytes: uint, /* Defaults to 512KB per channel. Reducing this will save memory, but the depth of your node graph will be more restricted. */ } node_graph :: struct { /* Immutable. */ base: node_base, /* The node graph itself is a node so it can be connected as an input to different node graph. This has zero inputs and calls ma_node_graph_read_pcm_frames() to generate it's output. */ endpoint: node_base, /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */ - nodeCacheCapInFrames: u16, + + pProcessingCache: [^]f32, /* This will be allocated when processingSizeInFrames is non-zero. This is needed because ma_node_graph_read_pcm_frames() can be called with a variable number of frames, and we may need to do some buffering in situations where the caller requests a frame count that's not a multiple of processingSizeInFrames. */ + processingCacheFramesRemaining: u32, + processingSizeInFrames: u32, /* Read and written by multiple threads. */ isReading: b32, /*atomic*/ + + /* Modified only by the audio thread. */ + pPreMixStack: ^stack, } @(default_calling_convention="c", link_prefix="ma_") diff --git a/vendor/miniaudio/resource_manager.odin b/vendor/miniaudio/resource_manager.odin index 495a02c5d..4ef5778a9 100644 --- a/vendor/miniaudio/resource_manager.odin +++ b/vendor/miniaudio/resource_manager.odin @@ -16,6 +16,7 @@ resource_manager_data_source_flag :: enum c.int { ASYNC = 2, /* When set, the resource manager will load the data source asynchronously. */ WAIT_INIT = 3, /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */ UNKNOWN_LENGTH = 4, /* Gives the resource manager a hint that the length of the data source is unknown and calling `ma_data_source_get_length_in_pcm_frames()` should be avoided. */ + LOOPING = 5, /* When set, configures the data source to loop by default. */ } resource_manager_data_source_flags :: bit_set[resource_manager_data_source_flag; u32] @@ -79,8 +80,8 @@ resource_manager_data_source_config :: struct { rangeEndInPCMFrames: u64, loopPointBegInPCMFrames: u64, loopPointEndInPCMFrames: u64, - isLooping: b32, flags: u32, + isLooping: b32, /* Deprecated. Use the MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING flag in `flags` instead. */ } resource_manager_data_supply_type :: enum c.int { diff --git a/vendor/miniaudio/src/miniaudio.h b/vendor/miniaudio/src/miniaudio.h index 47332e11a..c74bebeb3 100644 --- a/vendor/miniaudio/src/miniaudio.h +++ b/vendor/miniaudio/src/miniaudio.h @@ -1,6 +1,6 @@ /* Audio playback and capture library. Choice of public domain or MIT-0. See license statements at the end of this file. -miniaudio - v0.11.21 - 2023-11-15 +miniaudio - v0.11.22 - 2025-02-24 David Reid - mackron@gmail.com @@ -12,15 +12,18 @@ GitHub: https://github.com/mackron/miniaudio /* 1. Introduction =============== -miniaudio is a single file library for audio playback and capture. To use it, do the following in -one .c file: +To use miniaudio, include "miniaudio.h": ```c - #define MINIAUDIO_IMPLEMENTATION #include "miniaudio.h" ``` -You can do `#include "miniaudio.h"` in other parts of the program just like any other header. +The implementation is contained in "miniaudio.c". Just compile this like any other source file. You +can include miniaudio.c if you want to compile your project as a single translation unit: + + ```c + #include "miniaudio.c" + ``` miniaudio includes both low level and high level APIs. The low level API is good for those who want to do all of their mixing themselves and only require a light weight interface to the underlying @@ -293,7 +296,7 @@ avoids the same sound being loaded multiple times. The node graph is used for mixing and effect processing. The idea is that you connect a number of nodes into the graph by connecting each node's outputs to another node's inputs. Each node can -implement it's own effect. By chaining nodes together, advanced mixing and effect processing can +implement its own effect. By chaining nodes together, advanced mixing and effect processing can be achieved. The engine encapsulates both the resource manager and the node graph to create a simple, easy to @@ -398,7 +401,7 @@ the be started and/or stopped at a specific time. This can be done with the foll ``` The start/stop time needs to be specified based on the absolute timer which is controlled by the -engine. The current global time time in PCM frames can be retrieved with +engine. The current global time in PCM frames can be retrieved with `ma_engine_get_time_in_pcm_frames()`. The engine's global time can be changed with `ma_engine_set_time_in_pcm_frames()` for synchronization purposes if required. Note that scheduling a start time still requires an explicit call to `ma_sound_start()` before anything will play: @@ -430,11 +433,11 @@ Sounds and sound groups are nodes in the engine's node graph and can be plugged API. This makes it possible to connect sounds and sound groups to effect nodes to produce complex effect chains. -A sound can have it's volume changed with `ma_sound_set_volume()`. If you prefer decibel volume +A sound can have its volume changed with `ma_sound_set_volume()`. If you prefer decibel volume control you can use `ma_volume_db_to_linear()` to convert from decibel representation to linear. Panning and pitching is supported with `ma_sound_set_pan()` and `ma_sound_set_pitch()`. If you know -a sound will never have it's pitch changed with `ma_sound_set_pitch()` or via the doppler effect, +a sound will never have its pitch changed with `ma_sound_set_pitch()` or via the doppler effect, you can specify the `MA_SOUND_FLAG_NO_PITCH` flag when initializing the sound for an optimization. By default, sounds and sound groups have spatialization enabled. If you don't ever want to @@ -483,21 +486,12 @@ link the relevant frameworks but should compile cleanly out of the box with Xcod through the command line requires linking to `-lpthread` and `-lm`. Due to the way miniaudio links to frameworks at runtime, your application may not pass Apple's -notarization process. To fix this there are two options. The first is to use the -`MA_NO_RUNTIME_LINKING` option, like so: - - ```c - #ifdef __APPLE__ - #define MA_NO_RUNTIME_LINKING - #endif - #define MINIAUDIO_IMPLEMENTATION - #include "miniaudio.h" - ``` - -This will require linking with `-framework CoreFoundation -framework CoreAudio -framework AudioToolbox`. -If you get errors about AudioToolbox, try with `-framework AudioUnit` instead. You may get this when -using older versions of iOS. Alternatively, if you would rather keep using runtime linking you can -add the following to your entitlements.xcent file: +notarization process. To fix this there are two options. The first is to compile with +`-DMA_NO_RUNTIME_LINKING` which in turn will require linking with +`-framework CoreFoundation -framework CoreAudio -framework AudioToolbox`. If you get errors about +AudioToolbox, try with `-framework AudioUnit` instead. You may get this when using older versions +of iOS. Alternatively, if you would rather keep using runtime linking you can add the following to +your entitlements.xcent file: ``` com.apple.security.cs.allow-dyld-environment-variables @@ -555,7 +549,7 @@ To run locally, you'll need to use emrun: 2.7. Build Options ------------------ -`#define` these options before including miniaudio.h. +`#define` these options before including miniaudio.c, or pass them as compiler flags: +----------------------------------+--------------------------------------------------------------------+ | Option | Description | @@ -586,6 +580,8 @@ To run locally, you'll need to use emrun: +----------------------------------+--------------------------------------------------------------------+ | MA_NO_WEBAUDIO | Disables the Web Audio backend. | +----------------------------------+--------------------------------------------------------------------+ + | MA_NO_CUSTOM | Disables support for custom backends. | + +----------------------------------+--------------------------------------------------------------------+ | MA_NO_NULL | Disables the null backend. | +----------------------------------+--------------------------------------------------------------------+ | MA_ENABLE_ONLY_SPECIFIC_BACKENDS | Disables all backends by default and requires `MA_ENABLE_*` to | @@ -630,6 +626,9 @@ To run locally, you'll need to use emrun: | MA_ENABLE_WEBAUDIO | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | | | enable the Web Audio backend. | +----------------------------------+--------------------------------------------------------------------+ + | MA_ENABLE_CUSTOM | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | + | | enable custom backends. | + +----------------------------------+--------------------------------------------------------------------+ | MA_ENABLE_NULL | Used in conjunction with MA_ENABLE_ONLY_SPECIFIC_BACKENDS to | | | enable the null backend. | +----------------------------------+--------------------------------------------------------------------+ @@ -693,11 +692,30 @@ To run locally, you'll need to use emrun: | | You may need to enable this if your target platform does not allow | | | runtime linking via `dlopen()`. | +----------------------------------+--------------------------------------------------------------------+ + | MA_USE_STDINT | (Pass this in as a compiler flag. Do not `#define` this before | + | | miniaudio.c) Forces the use of stdint.h for sized types. | + +----------------------------------+--------------------------------------------------------------------+ | MA_DEBUG_OUTPUT | Enable `printf()` output of debug logs (`MA_LOG_LEVEL_DEBUG`). | +----------------------------------+--------------------------------------------------------------------+ | MA_COINIT_VALUE | Windows only. The value to pass to internal calls to | | | `CoInitializeEx()`. Defaults to `COINIT_MULTITHREADED`. | +----------------------------------+--------------------------------------------------------------------+ + | MA_FORCE_UWP | Windows only. Affects only the WASAPI backend. Will force the | + | | WASAPI backend to use the UWP code path instead of the regular | + | | desktop path. This is normally auto-detected and should rarely be | + | | needed to be used explicitly, but can be useful for debugging. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ON_THREAD_ENTRY | Defines some code that will be executed as soon as an internal | + | | miniaudio-managed thread is created. This will be the first thing | + | | to be executed by the thread entry point. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_ON_THREAD_EXIT | Defines some code that will be executed from the entry point of an | + | | internal miniaudio-managed thread upon exit. This will be the last | + | | thing to be executed before the thread's entry point exits. | + +----------------------------------+--------------------------------------------------------------------+ + | MA_THREAD_DEFAULT_STACK_SIZE | If set, specifies the default stack size used by miniaudio-managed | + | | threads. | + +----------------------------------+--------------------------------------------------------------------+ | MA_API | Controls how public APIs should be decorated. Default is `extern`. | +----------------------------------+--------------------------------------------------------------------+ @@ -1309,7 +1327,7 @@ only works for sounds that were initialized with `ma_sound_init_from_file()` and When you initialize a sound, if you specify a sound group the sound will be attached to that group automatically. If you set it to NULL, it will be automatically attached to the engine's endpoint. -If you would instead rather leave the sound unattached by default, you can can specify the +If you would instead rather leave the sound unattached by default, you can specify the `MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT` flag. This is useful if you want to set up a complex node graph. @@ -1686,6 +1704,7 @@ combination of the following flags: MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING ``` When no flags are specified (set to 0), the sound will be fully loaded into memory, but not @@ -1706,6 +1725,14 @@ can instead stream audio data which you can do by specifying the second pages. When a new page needs to be decoded, a job will be posted to the job queue and then subsequently processed in a job thread. +The `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING` flag can be used so that the sound will loop +when it reaches the end by default. It's recommended you use this flag when you want to have a +looping streaming sound. If you try loading a very short sound as a stream, you will get a glitch. +This is because the resource manager needs to pre-fill the initial buffer at initialization time, +and if you don't specify the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING` flag, the resource +manager will assume the sound is not looping and will stop filling the buffer when it reaches the +end, therefore resulting in a discontinuous buffer. + For in-memory sounds, reference counting is used to ensure the data is loaded only once. This means multiple calls to `ma_resource_manager_data_source_init()` with the same file path will result in the file data only being loaded once. Each call to `ma_resource_manager_data_source_init()` must be @@ -1720,7 +1747,7 @@ actual file paths. When `ma_resource_manager_data_source_init()` is called (with `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` flag), the resource manager will look for these explicitly registered data buffers and, if found, will use it as the backing data for the data source. Note that the resource manager does *not* make a copy of this data so it is up to the -caller to ensure the pointer stays valid for it's lifetime. Use +caller to ensure the pointer stays valid for its lifetime. Use `ma_resource_manager_unregister_data()` to unregister the self-managed data. You can also use `ma_resource_manager_register_file()` and `ma_resource_manager_unregister_file()` to register and unregister a file. It does not make sense to use the `MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_STREAM` @@ -2031,7 +2058,7 @@ In the above graph, it starts with two data sources whose outputs are attached t splitter node. It's at this point that the two data sources are mixed. After mixing, the splitter performs it's processing routine and produces two outputs which is simply a duplication of the input stream. One output is attached to a low pass filter, whereas the other output is attached to -a echo/delay. The outputs of the the low pass filter and the echo are attached to the endpoint, and +a echo/delay. The outputs of the low pass filter and the echo are attached to the endpoint, and since they're both connected to the same input bus, they'll be mixed. Each input bus must be configured to accept the same number of channels, but the number of channels @@ -2072,7 +2099,7 @@ data from the graph: ``` When you read audio data, miniaudio starts at the node graph's endpoint node which then pulls in -data from it's input attachments, which in turn recursively pull in data from their inputs, and so +data from its input attachments, which in turn recursively pull in data from their inputs, and so on. At the start of the graph there will be some kind of data source node which will have zero inputs and will instead read directly from a data source. The base nodes don't literally need to read from a `ma_data_source` object, but they will always have some kind of underlying object that @@ -2318,7 +2345,7 @@ You can start and stop a node with the following: By default the node is in a started state, but since it won't be connected to anything won't actually be invoked by the node graph until it's connected. When you stop a node, data will not be -read from any of it's input connections. You can use this property to stop a group of sounds +read from any of its input connections. You can use this property to stop a group of sounds atomically. You can configure the initial state of a node in it's config: @@ -2411,29 +2438,29 @@ audio thread is finished so that control is not handed back to the caller thereb chance to free the node's memory. When the audio thread is processing a node, it does so by reading from each of the output buses of -the node. In order for a node to process data for one of it's output buses, it needs to read from -each of it's input buses, and so on an so forth. It follows that once all output buses of a node +the node. In order for a node to process data for one of its output buses, it needs to read from +each of its input buses, and so on an so forth. It follows that once all output buses of a node are detached, the node as a whole will be disconnected and no further processing will occur unless it's output buses are reattached, which won't be happening when the node is being uninitialized. By having `ma_node_detach_output_bus()` wait until the audio thread is finished with it, we can simplify a few things, at the expense of making `ma_node_detach_output_bus()` a bit slower. By doing this, the implementation of `ma_node_uninit()` becomes trivial - just detach all output -nodes, followed by each of the attachments to each of it's input nodes, and then do any final clean +nodes, followed by each of the attachments to each of its input nodes, and then do any final clean up. With the above design, the worst-case scenario is `ma_node_detach_output_bus()` taking as long as it takes to process the output bus being detached. This will happen if it's called at just the wrong moment where the audio thread has just iterated it and has just started processing. The caller of `ma_node_detach_output_bus()` will stall until the audio thread is finished, which -includes the cost of recursively processing it's inputs. This is the biggest compromise made with -the approach taken by miniaudio for it's lock-free processing system. The cost of detaching nodes +includes the cost of recursively processing its inputs. This is the biggest compromise made with +the approach taken by miniaudio for its lock-free processing system. The cost of detaching nodes earlier in the pipeline (data sources, for example) will be cheaper than the cost of detaching higher level nodes, such as some kind of final post-processing endpoint. If you need to do mass detachments, detach starting from the lowest level nodes and work your way towards the final endpoint node (but don't try detaching the node graph's endpoint). If the audio thread is not running, detachment will be fast and detachment in any order will be the same. The reason nodes need to wait for their input attachments to complete is due to the potential for desyncs between -data sources. If the node was to terminate processing mid way through processing it's inputs, +data sources. If the node was to terminate processing mid way through processing its inputs, there's a chance that some of the underlying data sources will have been read, but then others not. That will then result in a potential desynchronization when detaching and reattaching higher-level nodes. A possible solution to this is to have an option when detaching to terminate processing @@ -2804,7 +2831,7 @@ weights. Custom weights can be passed in as the last parameter of `ma_channel_converter_config_init()`. Predefined channel maps can be retrieved with `ma_channel_map_init_standard()`. This takes a -`ma_standard_channel_map` enum as it's first parameter, which can be one of the following: +`ma_standard_channel_map` enum as its first parameter, which can be one of the following: +-----------------------------------+-----------------------------------------------------------+ | Name | Description | @@ -2890,7 +2917,7 @@ like the following: ma_resample_algorithm_linear); ma_resampler resampler; - ma_result result = ma_resampler_init(&config, &resampler); + ma_result result = ma_resampler_init(&config, NULL, &resampler); if (result != MA_SUCCESS) { // An error occurred... } @@ -3132,7 +3159,7 @@ Biquad filtering is achieved with the `ma_biquad` API. Example: ```c ma_biquad_config config = ma_biquad_config_init(ma_format_f32, channels, b0, b1, b2, a0, a1, a2); - ma_result result = ma_biquad_init(&config, &biquad); + ma_result result = ma_biquad_init(&config, NULL, &biquad); if (result != MA_SUCCESS) { // Error. } @@ -3723,7 +3750,7 @@ extern "C" { #define MA_VERSION_MAJOR 0 #define MA_VERSION_MINOR 11 -#define MA_VERSION_REVISION 21 +#define MA_VERSION_REVISION 22 #define MA_VERSION_STRING MA_XSTRINGIFY(MA_VERSION_MAJOR) "." MA_XSTRINGIFY(MA_VERSION_MINOR) "." MA_XSTRINGIFY(MA_VERSION_REVISION) #if defined(_MSC_VER) && !defined(__clang__) @@ -3740,8 +3767,7 @@ extern "C" { #endif - -#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) || defined(__ppc64__) #define MA_SIZEOF_PTR 8 #else #define MA_SIZEOF_PTR 4 @@ -3805,7 +3831,7 @@ typedef void* ma_handle; typedef void* ma_ptr; /* -ma_proc is annoying because when compiling with GCC we get pendantic warnings about converting +ma_proc is annoying because when compiling with GCC we get pedantic warnings about converting between `void*` and `void (*)()`. We can't use `void (*)()` with MSVC however, because we'll get warning C4191 about "type cast between incompatible function types". To work around this I'm going to use a different data type depending on the compiler. @@ -3999,7 +4025,7 @@ Special wchar_t type to ensure any structures in the public sections that refere consistent size across all platforms. On Windows, wchar_t is 2 bytes, whereas everywhere else it's 4 bytes. Since Windows likes to use -wchar_t for it's IDs, we need a special explicitly sized wchar type that is always 2 bytes on all +wchar_t for its IDs, we need a special explicitly sized wchar type that is always 2 bytes on all platforms. */ #if !defined(MA_POSIX) && defined(MA_WIN32) @@ -4025,7 +4051,7 @@ MA_LOG_LEVEL_INFO callback. MA_LOG_LEVEL_WARNING - Warnings. You should enable this in you development builds and action them when encounted. These + Warnings. You should enable this in you development builds and action them when encountered. These logs usually indicate a potential problem or misconfiguration, but still allow you to keep running. This will never be called from within the data callback. @@ -5457,7 +5483,7 @@ input frames. MA_API ma_result ma_resampler_get_expected_output_frame_count(const ma_resampler* pResampler, ma_uint64 inputFrameCount, ma_uint64* pOutputFrameCount); /* -Resets the resampler's timer and clears it's internal cache. +Resets the resampler's timer and clears its internal cache. */ MA_API ma_result ma_resampler_reset(ma_resampler* pResampler); @@ -5678,7 +5704,7 @@ MA_API void ma_channel_map_init_standard(ma_standard_channel_map standardChannel /* Copies a channel map. -Both input and output channel map buffers must have a capacity of at at least `channels`. +Both input and output channel map buffers must have a capacity of at least `channels`. */ MA_API void ma_channel_map_copy(ma_channel* pOut, const ma_channel* pIn, ma_uint32 channels); @@ -5817,6 +5843,8 @@ MA_API void ma_data_source_uninit(ma_data_source* pDataSource); MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ MA_API ma_result ma_data_source_seek_pcm_frames(ma_data_source* pDataSource, ma_uint64 frameCount, ma_uint64* pFramesSeeked); /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount, &framesRead); */ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, ma_uint64 frameIndex); +MA_API ma_result ma_data_source_seek_seconds(ma_data_source* pDataSource, float secondCount, float* pSecondsSeeked); /* Can only seek forward. Abstraction to ma_data_source_seek_pcm_frames() */ +MA_API ma_result ma_data_source_seek_to_second(ma_data_source* pDataSource, float seekPointInSeconds); /* Abstraction to ma_data_source_seek_to_pcm_frame() */ MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pCursor); MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSource, ma_uint64* pLength); /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */ @@ -6182,6 +6210,12 @@ MA_API ma_result ma_event_wait(ma_event* pEvent); Signals the specified auto-reset event. */ MA_API ma_result ma_event_signal(ma_event* pEvent); + + +MA_API ma_result ma_semaphore_init(int initialValue, ma_semaphore* pSemaphore); +MA_API void ma_semaphore_uninit(ma_semaphore* pSemaphore); +MA_API ma_result ma_semaphore_wait(ma_semaphore* pSemaphore); +MA_API ma_result ma_semaphore_release(ma_semaphore* pSemaphore); #endif /* MA_NO_THREADING */ @@ -6273,7 +6307,7 @@ Job Queue /* Slot Allocator -------------- -The idea of the slot allocator is for it to be used in conjunction with a fixed sized buffer. You use the slot allocator to allocator an index that can be used +The idea of the slot allocator is for it to be used in conjunction with a fixed sized buffer. You use the slot allocator to allocate an index that can be used as the insertion point for an object. Slots are reference counted to help mitigate the ABA problem in the lock-free queue we use for tracking jobs. @@ -7006,6 +7040,8 @@ typedef union int nullbackend; /* The null backend uses an integer for device IDs. */ } ma_device_id; +MA_API ma_bool32 ma_device_id_equal(const ma_device_id* pA, const ma_device_id* pB); + typedef struct ma_context_config ma_context_config; typedef struct ma_device_config ma_device_config; @@ -7093,6 +7129,7 @@ struct ma_device_config { const char* pStreamNamePlayback; const char* pStreamNameCapture; + int channelMap; } pulse; struct { @@ -7112,6 +7149,7 @@ struct ma_device_config ma_aaudio_allowed_capture_policy allowedCapturePolicy; ma_bool32 noAutoStartAfterReroute; ma_bool32 enableCompatibilityWorkarounds; + ma_bool32 allowSetBufferCapacity; } aaudio; }; @@ -7184,7 +7222,7 @@ and on output returns detailed information about the device in `ma_device_info`. case when the device ID is NULL, in which case information about the default device needs to be retrieved. Once the context has been created and the device ID retrieved (if using anything other than the default device), the device can be created. -This is a little bit more complicated than initialization of the context due to it's more complicated configuration. When initializing a +This is a little bit more complicated than initialization of the context due to its more complicated configuration. When initializing a device, a duplex device may be requested. This means a separate data format needs to be specified for both playback and capture. On input, the data format is set to what the application wants. On output it's set to the native format which should match as closely as possible to the requested format. The conversion between the format requested by the application and the device's native format will be handled @@ -7205,10 +7243,10 @@ asynchronous reading and writing, `onDeviceStart()` and `onDeviceStop()` should The handling of data delivery between the application and the device is the most complicated part of the process. To make this a bit easier, some helper callbacks are available. If the backend uses a blocking read/write style of API, the `onDeviceRead()` and `onDeviceWrite()` callbacks can optionally be implemented. These are blocking and work just like reading and writing from a file. If the -backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within it's callback. +backend uses a callback for data delivery, that callback must call `ma_device_handle_backend_data_callback()` from within its callback. This allows miniaudio to then process any necessary data conversion and then pass it to the miniaudio data callback. -If the backend requires absolute flexibility with it's data delivery, it can optionally implement the `onDeviceDataLoop()` callback +If the backend requires absolute flexibility with its data delivery, it can optionally implement the `onDeviceDataLoop()` callback which will allow it to implement the logic that will run on the audio thread. This is much more advanced and is completely optional. The audio thread should run data delivery logic in a loop while `ma_device_get_state() == ma_device_state_started` and no errors have been @@ -7248,6 +7286,10 @@ struct ma_context_config void* pUserData; ma_allocation_callbacks allocationCallbacks; struct + { + ma_handle hWnd; /* HWND. Optional window handle to pass into SetCooperativeLevel(). Will default to the foreground window, and if that fails, the desktop window. */ + } dsound; + struct { ma_bool32 useVerboseDeviceEnumeration; } alsa; @@ -7336,6 +7378,7 @@ struct ma_context #ifdef MA_SUPPORT_DSOUND struct { + ma_handle hWnd; /* Can be null. */ ma_handle hDSoundDLL; ma_proc DirectSoundCreate; ma_proc DirectSoundEnumerateA; @@ -7942,6 +7985,7 @@ struct ma_device { /*AAudioStream**/ ma_ptr pStreamPlayback; /*AAudioStream**/ ma_ptr pStreamCapture; + ma_mutex rerouteLock; ma_aaudio_usage usage; ma_aaudio_content_type contentType; ma_aaudio_input_preset inputPreset; @@ -8365,6 +8409,10 @@ Retrieves basic information about every active playback and/or capture device. This function will allocate memory internally for the device lists and return a pointer to them through the `ppPlaybackDeviceInfos` and `ppCaptureDeviceInfos` parameters. If you do not want to incur the overhead of these allocations consider using `ma_context_enumerate_devices()` which will instead use a callback. +Note that this only retrieves the ID and name/description of the device. The reason for only retrieving basic information is that it would otherwise require +opening the backend device in order to probe it for more detailed information which can be inefficient. Consider using `ma_context_get_device_info()` for this, +but don't call it from within the enumeration callback. + Parameters ---------- @@ -8406,7 +8454,7 @@ The returned pointers will become invalid upon the next call this this function, See Also -------- -ma_context_get_devices() +ma_context_enumerate_devices() */ MA_API ma_result ma_context_get_devices(ma_context* pContext, ma_device_info** ppPlaybackDeviceInfos, ma_uint32* pPlaybackDeviceCount, ma_device_info** ppCaptureDeviceInfos, ma_uint32* pCaptureDeviceCount); @@ -8545,7 +8593,7 @@ from a microphone. Whether or not you should send or receive data from the devic playback, capture, full-duplex or loopback. (Note that loopback mode is only supported on select backends.) Sending and receiving audio data to and from the device is done via a callback which is fired by miniaudio at periodic time intervals. -The frequency at which data is delivered to and from a device depends on the size of it's period. The size of the period can be defined in terms of PCM frames +The frequency at which data is delivered to and from a device depends on the size of its period. The size of the period can be defined in terms of PCM frames or milliseconds, whichever is more convenient. Generally speaking, the smaller the period, the lower the latency at the expense of higher CPU usage and increased risk of glitching due to the more frequent and granular data deliver intervals. The size of a period will depend on your requirements, but miniaudio's defaults should work fine for most scenarios. If you're building a game you should leave this fairly small, whereas if you're building a simple @@ -8619,7 +8667,7 @@ then be set directly on the structure. Below are the members of the `ma_device_c performanceProfile A hint to miniaudio as to the performance requirements of your program. Can be either `ma_performance_profile_low_latency` (default) or - `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at it's default value. + `ma_performance_profile_conservative`. This mainly affects the size of default buffers and can usually be left at its default value. noPreSilencedOutputBuffer When set to true, the contents of the output buffer passed into the data callback will be left undefined. When set to false (default), the contents of @@ -8659,7 +8707,7 @@ then be set directly on the structure. Below are the members of the `ma_device_c A pointer that will passed to callbacks in pBackendVTable. resampling.linear.lpfOrder - The linear resampler applies a low-pass filter as part of it's processing for anti-aliasing. This setting controls the order of the filter. The higher + The linear resampler applies a low-pass filter as part of its processing for anti-aliasing. This setting controls the order of the filter. The higher the value, the better the quality, in general. Setting this to 0 will disable low-pass filtering altogether. The maximum value is `MA_MAX_FILTER_ORDER`. The default value is `min(4, MA_MAX_FILTER_ORDER)`. @@ -8736,6 +8784,9 @@ then be set directly on the structure. Below are the members of the `ma_device_c pulse.pStreamNameCapture PulseAudio only. Sets the stream name for capture. + pulse.channelMap + PulseAudio only. Sets the channel map that is requested from PulseAudio. See MA_PA_CHANNEL_MAP_* constants. Defaults to MA_PA_CHANNEL_MAP_AIFF. + coreaudio.allowNominalSampleRateChange Core Audio only. Desktop only. When enabled, allows the sample rate of the device to be changed at the operating system level. This is disabled by default in order to prevent intrusive changes to the user's system. This is useful if you want to use a sample rate @@ -8909,7 +8960,7 @@ Unsafe. It is not safe to call this inside any callback. Remarks ------- -You only need to use this function if you want to configure the context differently to it's defaults. You should never use this function if you want to manage +You only need to use this function if you want to configure the context differently to its defaults. You should never use this function if you want to manage your own context. See the documentation for `ma_context_init()` for information on the different context configuration options. @@ -9674,7 +9725,7 @@ Utilities ************************************************************************************************************************************************************/ /* -Calculates a buffer size in milliseconds from the specified number of frames and sample rate. +Calculates a buffer size in milliseconds (rounded up) from the specified number of frames and sample rate. */ MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 bufferSizeInFrames, ma_uint32 sampleRate); @@ -9931,7 +9982,7 @@ struct ma_decoder void* pInputCache; /* In input format. Can be null if it's not needed. */ ma_uint64 inputCacheCap; /* The capacity of the input cache. */ ma_uint64 inputCacheConsumed; /* The number of frames that have been consumed in the cache. Used for determining the next valid frame. */ - ma_uint64 inputCacheRemaining; /* The number of valid frames remaining in the cahce. */ + ma_uint64 inputCacheRemaining; /* The number of valid frames remaining in the cache. */ ma_allocation_callbacks allocationCallbacks; union { @@ -9972,7 +10023,7 @@ This is not thread safe without your own synchronization. MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead); /* -Seeks to a PCM frame based on it's absolute index. +Seeks to a PCM frame based on its absolute index. This is not thread safe without your own synchronization. */ @@ -10235,7 +10286,8 @@ typedef enum MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_DECODE = 0x00000002, /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */ MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC = 0x00000004, /* When set, the resource manager will load the data source asynchronously. */ MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT = 0x00000008, /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */ - MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH = 0x00000010 /* Gives the resource manager a hint that the length of the data source is unknown and calling `ma_data_source_get_length_in_pcm_frames()` should be avoided. */ + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH = 0x00000010, /* Gives the resource manager a hint that the length of the data source is unknown and calling `ma_data_source_get_length_in_pcm_frames()` should be avoided. */ + MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING = 0x00000020 /* When set, configures the data source to loop by default. */ } ma_resource_manager_data_source_flags; @@ -10303,8 +10355,8 @@ typedef struct ma_uint64 rangeEndInPCMFrames; ma_uint64 loopPointBegInPCMFrames; ma_uint64 loopPointEndInPCMFrames; - ma_bool32 isLooping; ma_uint32 flags; + ma_bool32 isLooping; /* Deprecated. Use the MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING flag in `flags` instead. */ } ma_resource_manager_data_source_config; MA_API ma_resource_manager_data_source_config ma_resource_manager_data_source_config_init(void); @@ -10547,6 +10599,16 @@ Node Graph /* Use this when the bus count is determined by the node instance rather than the vtable. */ #define MA_NODE_BUS_COUNT_UNKNOWN 255 + +/* For some internal memory management of ma_node_graph. */ +typedef struct +{ + size_t offset; + size_t sizeInBytes; + unsigned char _data[1]; +} ma_stack; + + typedef struct ma_node_graph ma_node_graph; typedef void ma_node; @@ -10586,7 +10648,7 @@ typedef struct void (* onProcess)(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn, float** ppFramesOut, ma_uint32* pFrameCountOut); /* - A callback for retrieving the number of a input frames that are required to output the + A callback for retrieving the number of input frames that are required to output the specified number of output frames. You would only want to implement this when the node performs resampling. This is optional, even for nodes that perform resampling, but it does offer a small reduction in latency as it allows miniaudio to calculate the exact number of input frames @@ -10671,10 +10733,14 @@ typedef struct ma_node_base ma_node_base; struct ma_node_base { /* These variables are set once at startup. */ - ma_node_graph* pNodeGraph; /* The graph this node belongs to. */ + ma_node_graph* pNodeGraph; /* The graph this node belongs to. */ const ma_node_vtable* vtable; - float* pCachedData; /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */ - ma_uint16 cachedDataCapInFramesPerBus; /* The capacity of the input data cache in frames, per bus. */ + ma_uint32 inputBusCount; + ma_uint32 outputBusCount; + ma_node_input_bus* pInputBuses; + ma_node_output_bus* pOutputBuses; + float* pCachedData; /* Allocated on the heap. Fixed size. Needs to be stored on the heap because reading from output buses is done in separate function calls. */ + ma_uint16 cachedDataCapInFramesPerBus; /* The capacity of the input data cache in frames, per bus. */ /* These variables are read and written only from the audio thread. */ ma_uint16 cachedFrameCountOut; @@ -10682,13 +10748,9 @@ struct ma_node_base ma_uint16 consumedFrameCountIn; /* These variables are read and written between different threads. */ - MA_ATOMIC(4, ma_node_state) state; /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */ - MA_ATOMIC(8, ma_uint64) stateTimes[2]; /* Indexed by ma_node_state. Specifies the time based on the global clock that a node should be considered to be in the relevant state. */ - MA_ATOMIC(8, ma_uint64) localTime; /* The node's local clock. This is just a running sum of the number of output frames that have been processed. Can be modified by any thread with `ma_node_set_time()`. */ - ma_uint32 inputBusCount; - ma_uint32 outputBusCount; - ma_node_input_bus* pInputBuses; - ma_node_output_bus* pOutputBuses; + MA_ATOMIC(4, ma_node_state) state; /* When set to stopped, nothing will be read, regardless of the times in stateTimes. */ + MA_ATOMIC(8, ma_uint64) stateTimes[2]; /* Indexed by ma_node_state. Specifies the time based on the global clock that a node should be considered to be in the relevant state. */ + MA_ATOMIC(8, ma_uint64) localTime; /* The node's local clock. This is just a running sum of the number of output frames that have been processed. Can be modified by any thread with `ma_node_set_time()`. */ /* Memory management. */ ma_node_input_bus _inputBuses[MA_MAX_NODE_LOCAL_BUS_COUNT]; @@ -10724,7 +10786,8 @@ MA_API ma_result ma_node_set_time(ma_node* pNode, ma_uint64 localTime); typedef struct { ma_uint32 channels; - ma_uint16 nodeCacheCapInFrames; + ma_uint32 processingSizeInFrames; /* This is the preferred processing size for node processing callbacks unless overridden by a node itself. Can be 0 in which case it will be based on the frame count passed into ma_node_graph_read_pcm_frames(), but will not be well defined. */ + size_t preMixStackSizeInBytes; /* Defaults to 512KB per channel. Reducing this will save memory, but the depth of your node graph will be more restricted. */ } ma_node_graph_config; MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels); @@ -10735,10 +10798,15 @@ struct ma_node_graph /* Immutable. */ ma_node_base base; /* The node graph itself is a node so it can be connected as an input to different node graph. This has zero inputs and calls ma_node_graph_read_pcm_frames() to generate it's output. */ ma_node_base endpoint; /* Special node that all nodes eventually connect to. Data is read from this node in ma_node_graph_read_pcm_frames(). */ - ma_uint16 nodeCacheCapInFrames; + float* pProcessingCache; /* This will be allocated when processingSizeInFrames is non-zero. This is needed because ma_node_graph_read_pcm_frames() can be called with a variable number of frames, and we may need to do some buffering in situations where the caller requests a frame count that's not a multiple of processingSizeInFrames. */ + ma_uint32 processingCacheFramesRemaining; + ma_uint32 processingSizeInFrames; /* Read and written by multiple threads. */ MA_ATOMIC(4, ma_bool32) isReading; + + /* Modified only by the audio thread. */ + ma_stack* pPreMixStack; }; MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const ma_allocation_callbacks* pAllocationCallbacks, ma_node_graph* pNodeGraph); @@ -11023,6 +11091,7 @@ typedef enum MA_SOUND_FLAG_ASYNC = 0x00000004, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC */ MA_SOUND_FLAG_WAIT_INIT = 0x00000008, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT */ MA_SOUND_FLAG_UNKNOWN_LENGTH = 0x00000010, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_UNKNOWN_LENGTH */ + MA_SOUND_FLAG_LOOPING = 0x00000020, /* MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING */ /* ma_sound specific flags. */ MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT = 0x00001000, /* Do not attach to the endpoint by default. Useful for when setting up nodes in a complex graph system. */ @@ -11062,7 +11131,7 @@ MA_API ma_engine_node_config ma_engine_node_config_init(ma_engine* pEngine, ma_e /* Base node object for both ma_sound and ma_sound_group. */ typedef struct { - ma_node_base baseNode; /* Must be the first member for compatiblity with the ma_node API. */ + ma_node_base baseNode; /* Must be the first member for compatibility with the ma_node API. */ ma_engine* pEngine; /* A pointer to the engine. Set based on the value from the config. */ ma_uint32 sampleRate; /* The sample rate of the input data. For sounds backed by a data source, this will be the data source's sample rate. Otherwise it'll be the engine's sample rate. */ ma_uint32 volumeSmoothTimeInPCMFrames; @@ -11122,13 +11191,13 @@ typedef struct ma_uint64 rangeEndInPCMFrames; ma_uint64 loopPointBegInPCMFrames; ma_uint64 loopPointEndInPCMFrames; - ma_bool32 isLooping; ma_sound_end_proc endCallback; /* Fired when the sound reaches the end. Will be fired from the audio thread. Do not restart, uninitialize or otherwise change the state of the sound from here. Instead fire an event or set a variable to indicate to a different thread to change the start of the sound. Will not be fired in response to a scheduled stop with ma_sound_set_stop_time_*(). */ void* pEndCallbackUserData; #ifndef MA_NO_RESOURCE_MANAGER ma_resource_manager_pipeline_notifications initNotifications; #endif ma_fence* pDoneFence; /* Deprecated. Use initNotifications instead. Released when the resource manager has finished decoding the entire sound. Not used with streams. */ + ma_bool32 isLooping; /* Deprecated. Use the MA_SOUND_FLAG_LOOPING flag in `flags` instead. */ } ma_sound_config; MA_API ma_sound_config ma_sound_config_init(void); /* Deprecated. Will be removed in version 0.12. Use ma_sound_config_2() instead. */ @@ -11192,6 +11261,7 @@ typedef struct ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. If set to 0, will use gainSmoothTimeInMilliseconds. */ ma_uint32 gainSmoothTimeInMilliseconds; /* When set to 0, gainSmoothTimeInFrames will be used. If both are set to 0, a default value will be used. */ ma_uint32 defaultVolumeSmoothTimeInPCMFrames; /* Defaults to 0. Controls the default amount of smoothing to apply to volume changes to sounds. High values means more smoothing at the expense of high latency (will take longer to reach the new volume). */ + ma_uint32 preMixStackSizeInBytes; /* A stack is used for internal processing in the node graph. This allows you to configure the size of this stack. Smaller values will reduce the maximum depth of your node graph. You should rarely need to modify this. */ ma_allocation_callbacks allocationCallbacks; ma_bool32 noAutoStart; /* When set to true, requires an explicit call to ma_engine_start(). This is false by default, meaning the engine will be started automatically in ma_engine_init(). */ ma_bool32 noDevice; /* When set to true, don't create a default device. ma_engine_read_pcm_frames() can be called manually to read data. */ @@ -11206,12 +11276,12 @@ MA_API ma_engine_config ma_engine_config_init(void); struct ma_engine { - ma_node_graph nodeGraph; /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */ + ma_node_graph nodeGraph; /* An engine is a node graph. It should be able to be plugged into any ma_node_graph API (with a cast) which means this must be the first member of this struct. */ #if !defined(MA_NO_RESOURCE_MANAGER) ma_resource_manager* pResourceManager; #endif #if !defined(MA_NO_DEVICE_IO) - ma_device* pDevice; /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */ + ma_device* pDevice; /* Optionally set via the config, otherwise allocated by the engine in ma_engine_init(). */ #endif ma_log* pLog; ma_uint32 sampleRate; @@ -11220,10 +11290,10 @@ struct ma_engine ma_allocation_callbacks allocationCallbacks; ma_bool8 ownsResourceManager; ma_bool8 ownsDevice; - ma_spinlock inlinedSoundLock; /* For synchronizing access so the inlined sound list. */ - ma_sound_inlined* pInlinedSoundHead; /* The first inlined sound. Inlined sounds are tracked in a linked list. */ - MA_ATOMIC(4, ma_uint32) inlinedSoundCount; /* The total number of allocated inlined sound objects. Used for debugging. */ - ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. */ + ma_spinlock inlinedSoundLock; /* For synchronizing access to the inlined sound list. */ + ma_sound_inlined* pInlinedSoundHead; /* The first inlined sound. Inlined sounds are tracked in a linked list. */ + MA_ATOMIC(4, ma_uint32) inlinedSoundCount; /* The total number of allocated inlined sound objects. Used for debugging. */ + ma_uint32 gainSmoothTimeInFrames; /* The number of frames to interpolate the gain of spatialized sounds across. */ ma_uint32 defaultVolumeSmoothTimeInPCMFrames; ma_mono_expansion_mode monoExpansionMode; ma_engine_process_proc onProcess; @@ -11348,6 +11418,7 @@ MA_API void ma_sound_set_looping(ma_sound* pSound, ma_bool32 isLooping); MA_API ma_bool32 ma_sound_is_looping(const ma_sound* pSound); MA_API ma_bool32 ma_sound_at_end(const ma_sound* pSound); MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameIndex); /* Just a wrapper around ma_data_source_seek_to_pcm_frame(). */ +MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds); /* Abstraction to ma_sound_seek_to_pcm_frame() */ MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap); MA_API ma_result ma_sound_get_cursor_in_pcm_frames(ma_sound* pSound, ma_uint64* pCursor); MA_API ma_result ma_sound_get_length_in_pcm_frames(ma_sound* pSound, ma_uint64* pLength); @@ -13861,7 +13932,7 @@ static ma_uint32 ma_ffs_32(ma_uint32 x) /* Just a naive implementation just to get things working for now. Will optimize this later. */ for (i = 0; i < 32; i += 1) { - if ((x & (1 << i)) != 0) { + if ((x & (1U << i)) != 0) { return i; } } @@ -14024,7 +14095,7 @@ static MA_INLINE ma_int32 ma_dither_s32(ma_dither_mode ditherMode, ma_int32 dith Atomics **************************************************************************************************************************************************************/ -/* ma_atomic.h begin */ +/* c89atomic.h begin */ #ifndef ma_atomic_h #if defined(__cplusplus) extern "C" { @@ -14750,12 +14821,12 @@ typedef int ma_atomic_memory_order; typedef ma_uint8 ma_atomic_flag; #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define c89atoimc_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) + #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) #else typedef ma_uint32 ma_atomic_flag; #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_32(ptr, order) #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_32(ptr, order) - #define c89atoimc_flag_load_explicit(ptr, order) ma_atomic_load_explicit_32(ptr, order) + #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_32(ptr, order) #endif #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) #define MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE @@ -14836,15 +14907,24 @@ typedef int ma_atomic_memory_order; __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } + #if defined(__clang__) + #pragma clang diagnostic push + #if __clang_major__ >= 8 + #pragma clang diagnostic ignored "-Watomic-alignment" + #endif + #endif static MA_INLINE ma_uint64 ma_atomic_compare_and_swap_64(volatile ma_uint64* dst, ma_uint64 expected, ma_uint64 desired) { __atomic_compare_exchange_n(dst, &expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); return expected; } + #if defined(__clang__) + #pragma clang diagnostic pop + #endif typedef ma_uint8 ma_atomic_flag; #define ma_atomic_flag_test_and_set_explicit(dst, order) (ma_bool32)__atomic_test_and_set(dst, order) #define ma_atomic_flag_clear_explicit(dst, order) __atomic_clear(dst, order) - #define c89atoimc_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) + #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) #else #define ma_atomic_memory_order_relaxed 1 #define ma_atomic_memory_order_consume 2 @@ -15358,7 +15438,7 @@ typedef int ma_atomic_memory_order; typedef ma_uint8 ma_atomic_flag; #define ma_atomic_flag_test_and_set_explicit(ptr, order) (ma_bool32)ma_atomic_test_and_set_explicit_8(ptr, order) #define ma_atomic_flag_clear_explicit(ptr, order) ma_atomic_clear_explicit_8(ptr, order) - #define c89atoimc_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) + #define ma_atomic_flag_load_explicit(ptr, order) ma_atomic_load_explicit_8(ptr, order) #endif #if !defined(MA_ATOMIC_HAS_NATIVE_COMPARE_EXCHANGE) #if defined(MA_ATOMIC_HAS_8) @@ -15883,7 +15963,7 @@ static MA_INLINE void ma_atomic_spinlock_lock(volatile ma_atomic_spinlock* pSpin if (ma_atomic_flag_test_and_set_explicit(pSpinlock, ma_atomic_memory_order_acquire) == 0) { break; } - while (c89atoimc_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { + while (ma_atomic_flag_load_explicit(pSpinlock, ma_atomic_memory_order_relaxed) == 1) { } } } @@ -15898,7 +15978,7 @@ static MA_INLINE void ma_atomic_spinlock_unlock(volatile ma_atomic_spinlock* pSp } #endif #endif -/* ma_atomic.h end */ +/* c89atomic.h end */ #define MA_ATOMIC_SAFE_TYPE_IMPL(c89TypeExtension, type) \ static MA_INLINE ma_##type ma_atomic_##type##_get(ma_atomic_##type* x) \ @@ -16096,7 +16176,7 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority int result; pthread_attr_t* pAttr = NULL; -#if !defined(__EMSCRIPTEN__) +#if !defined(__EMSCRIPTEN__) && !defined(__3DS__) /* Try setting the thread priority. It's not critical if anything fails here. */ pthread_attr_t attr; if (pthread_attr_init(&attr) == 0) { @@ -16142,19 +16222,34 @@ static ma_result ma_thread_create__posix(ma_thread* pThread, ma_thread_priority if (priority == ma_thread_priority_idle) { sched.sched_priority = priorityMin; } else if (priority == ma_thread_priority_realtime) { - sched.sched_priority = priorityMax; - } else { - sched.sched_priority += ((int)priority + 5) * priorityStep; /* +5 because the lowest priority is -5. */ - if (sched.sched_priority < priorityMin) { - sched.sched_priority = priorityMin; + #if defined(MA_PTHREAD_REALTIME_THREAD_PRIORITY) + { + sched.sched_priority = MA_PTHREAD_REALTIME_THREAD_PRIORITY; } - if (sched.sched_priority > priorityMax) { + #else + { sched.sched_priority = priorityMax; } + #endif + } else { + sched.sched_priority += ((int)priority + 5) * priorityStep; /* +5 because the lowest priority is -5. */ } - /* I'm not treating a failure of setting the priority as a critical error so not checking the return value here. */ - pthread_attr_setschedparam(&attr, &sched); + if (sched.sched_priority < priorityMin) { + sched.sched_priority = priorityMin; + } + if (sched.sched_priority > priorityMax) { + sched.sched_priority = priorityMax; + } + + /* I'm not treating a failure of setting the priority as a critical error so not aborting on failure here. */ + if (pthread_attr_setschedparam(&attr, &sched) == 0) { + #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) + { + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + } + #endif + } } } } @@ -16187,7 +16282,7 @@ static void ma_thread_wait__posix(ma_thread* pThread) static ma_result ma_mutex_init__posix(ma_mutex* pMutex) { int result; - + if (pMutex == NULL) { return MA_INVALID_ARGS; } @@ -17406,7 +17501,7 @@ static ma_job_proc g_jobVTable[MA_JOB_TYPE_COUNT] = /* Device. */ #if !defined(MA_NO_DEVICE_IO) - ma_job_process__device__aaudio_reroute /*MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE*/ + ma_job_process__device__aaudio_reroute /* MA_JOB_TYPE_DEVICE_AAUDIO_REROUTE */ #endif }; @@ -17751,7 +17846,7 @@ MA_API ma_result ma_job_queue_next(ma_job_queue* pQueue, ma_job* pJob) is stored. One thread can fall through to the freeing of this item while another is still using "head" for the retrieval of the "next" variable. - The slot allocator might need to make use of some reference counting to ensure it's only truely freed when + The slot allocator might need to make use of some reference counting to ensure it's only truly freed when there are no more references to the item. This must be fixed before removing these locks. */ @@ -17859,7 +17954,16 @@ MA_API void ma_dlclose(ma_log* pLog, ma_handle handle) #ifdef MA_WIN32 FreeLibrary((HMODULE)handle); #else - dlclose((void*)handle); + /* Hack for Android bug (see https://github.com/android/ndk/issues/360). Calling dlclose() pre-API 28 may segfault. */ + #if !defined(MA_ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 28) + { + dlclose((void*)handle); + } + #else + { + (void)handle; + } + #endif #endif (void)pLog; @@ -17880,12 +17984,12 @@ MA_API ma_proc ma_dlsym(ma_log* pLog, ma_handle handle, const char* symbol) #ifdef _WIN32 proc = (ma_proc)GetProcAddress((HMODULE)handle, symbol); #else -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) +#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #endif proc = (ma_proc)dlsym((void*)handle, symbol); -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) +#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) || defined(__clang__) #pragma GCC diagnostic pop #endif #endif @@ -17923,9 +18027,13 @@ DEVICE I/O #endif #endif +#ifdef MA_APPLE + #include +#endif + #ifndef MA_NO_DEVICE_IO -#if defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200) +#if defined(MA_APPLE) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101200) #include /* For mach_absolute_time() */ #endif @@ -17939,6 +18047,10 @@ DEVICE I/O #endif #endif +/* This must be set to at least 26. */ +#ifndef MA_AAUDIO_MIN_ANDROID_SDK_VERSION +#define MA_AAUDIO_MIN_ANDROID_SDK_VERSION 27 +#endif MA_API void ma_device_info_add_native_data_format(ma_device_info* pDeviceInfo, ma_format format, ma_uint32 channels, ma_uint32 sampleRate, ma_uint32 flags) @@ -18085,7 +18197,7 @@ MA_API ma_bool32 ma_is_backend_enabled(ma_backend backend) #if defined(MA_HAS_AAUDIO) #if defined(MA_ANDROID) { - return ma_android_sdk_version() >= 26; + return ma_android_sdk_version() >= MA_AAUDIO_MIN_ANDROID_SDK_VERSION; } #else return MA_FALSE; @@ -18402,7 +18514,6 @@ typedef LONG (WINAPI * MA_PFN_RegCloseKey)(HKEY hKey); typedef LONG (WINAPI * MA_PFN_RegQueryValueExA)(HKEY hKey, const char* lpValueName, DWORD* lpReserved, DWORD* lpType, BYTE* lpData, DWORD* lpcbData); #endif /* MA_WIN32_DESKTOP */ - MA_API size_t ma_strlen_WCHAR(const WCHAR* str) { size_t len = 0; @@ -18487,7 +18598,7 @@ Timing return (double)(counter.QuadPart - pTimer->counter) / g_ma_TimerFrequency.QuadPart; } -#elif defined(MA_APPLE) && (__MAC_OS_X_VERSION_MIN_REQUIRED < 101200) +#elif defined(MA_APPLE) && (MAC_OS_X_VERSION_MIN_REQUIRED < 101200) static ma_uint64 g_ma_TimerFrequency = 0; static void ma_timer_init(ma_timer* pTimer) { @@ -18670,11 +18781,16 @@ static void ma_device__on_notification_rerouted(ma_device* pDevice) #endif #if defined(MA_EMSCRIPTEN) -EMSCRIPTEN_KEEPALIVE -void ma_device__on_notification_unlocked(ma_device* pDevice) +#ifdef __cplusplus +extern "C" { +#endif +void EMSCRIPTEN_KEEPALIVE ma_device__on_notification_unlocked(ma_device* pDevice) { ma_device__on_notification(ma_device_notification_init(pDevice, ma_device_notification_type_unlocked)); } +#ifdef __cplusplus +} +#endif #endif @@ -18802,7 +18918,7 @@ static void ma_device__handle_data_callback(ma_device* pDevice, void* pFramesOut unsigned int prevDenormalState = ma_device_disable_denormals(pDevice); { /* Volume control of input makes things a bit awkward because the input buffer is read-only. We'll need to use a temp buffer and loop in this case. */ - if (pFramesIn != NULL && masterVolumeFactor < 1) { + if (pFramesIn != NULL && masterVolumeFactor != 1) { ma_uint8 tempFramesIn[MA_DATA_CONVERTER_STACK_BUFFER_SIZE]; ma_uint32 bpfCapture = ma_get_bytes_per_frame(pDevice->capture.format, pDevice->capture.channels); ma_uint32 bpfPlayback = ma_get_bytes_per_frame(pDevice->playback.format, pDevice->playback.channels); @@ -18825,7 +18941,7 @@ static void ma_device__handle_data_callback(ma_device* pDevice, void* pFramesOut /* Volume control and clipping for playback devices. */ if (pFramesOut != NULL) { - if (masterVolumeFactor < 1) { + if (masterVolumeFactor != 1) { if (pFramesIn == NULL) { /* <-- In full-duplex situations, the volume will have been applied to the input samples before the data callback. Applying it again post-callback will incorrectly compound it. */ ma_apply_volume_factor_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels, masterVolumeFactor); } @@ -18837,6 +18953,11 @@ static void ma_device__handle_data_callback(ma_device* pDevice, void* pFramesOut } } ma_device_restore_denormals(pDevice, prevDenormalState); + } else { + /* No data callback. Just silence the output. */ + if (pFramesOut != NULL) { + ma_silence_pcm_frames(pFramesOut, frameCount, pDevice->playback.format, pDevice->playback.channels); + } } } @@ -18922,9 +19043,7 @@ static void ma_device__read_frames_from_client(ma_device* pDevice, ma_uint32 fra framesToReadThisIterationIn = requiredInputFrameCount; } - if (framesToReadThisIterationIn > 0) { - ma_device__handle_data_callback(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn); - } + ma_device__handle_data_callback(pDevice, pIntermediaryBuffer, NULL, (ma_uint32)framesToReadThisIterationIn); /* At this point we have our decoded data in input format and now we need to convert to output format. Note that even if we didn't read any @@ -18965,7 +19084,7 @@ static void ma_device__send_frames_to_client(ma_device* pDevice, ma_uint32 frame ma_uint64 totalClientFramesProcessed = 0; const void* pRunningFramesInDeviceFormat = pFramesInDeviceFormat; - /* We just keep going until we've exhaused all of our input frames and cannot generate any more output frames. */ + /* We just keep going until we've exhausted all of our input frames and cannot generate any more output frames. */ for (;;) { ma_uint64 deviceFramesProcessedThisIteration; ma_uint64 clientFramesProcessedThisIteration; @@ -19248,7 +19367,7 @@ static ma_result ma_device_audio_thread__default_read_write(ma_device* pDevice) } /* - If we weren't able to generate any output frames it must mean we've exhaused all of our input. The only time this would not be the case is if capturedClientData was too small + If we weren't able to generate any output frames it must mean we've exhausted all of our input. The only time this would not be the case is if capturedClientData was too small which should never be the case when it's of the size MA_DATA_CONVERTER_STACK_BUFFER_SIZE. */ if (capturedClientFramesToProcessThisIteration == 0) { @@ -19451,7 +19570,7 @@ static ma_result ma_device_do_operation__null(ma_device* pDevice, ma_uint32 oper /* The first thing to do is wait for an operation slot to become available. We only have a single slot for this, but we could extend this later - to support queing of operations. + to support queuing of operations. */ result = ma_semaphore_wait(&pDevice->null_device.operationSemaphore); if (result != MA_SUCCESS) { @@ -21268,7 +21387,7 @@ static ma_result ma_context_get_device_info_from_IAudioClient__wasapi(ma_context } /* - Exlcusive Mode. We repeatedly call IsFormatSupported() here. This is not currently supported on + Exclusive Mode. We repeatedly call IsFormatSupported() here. This is not currently supported on UWP. Failure to retrieve the exclusive mode format is not considered an error, so from here on out, MA_SUCCESS is guaranteed to be returned. */ @@ -21473,8 +21592,23 @@ static ma_result ma_context_get_MMDevice__wasapi(ma_context* pContext, ma_device MA_ASSERT(pContext != NULL); MA_ASSERT(ppMMDevice != NULL); - hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); - if (FAILED(hr)) { + /* + This weird COM init/uninit here is a hack to work around a crash when changing devices. What is happening is + WASAPI fires a callback from another thread when the device is changed. It's from that thread where this + function is getting called. What I'm suspecting is that the other thread is not initializing COM which in turn + results in CoCreateInstance() failing. + + The community has reported that this seems to fix the crash. There are future plans to move all WASAPI operation + over to a single thread to make everything safer, but in the meantime while we wait for that to come online I'm + happy enough to use this hack instead. + */ + ma_CoInitializeEx(pContext, NULL, MA_COINIT_VALUE); + { + hr = ma_CoCreateInstance(pContext, &MA_CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &MA_IID_IMMDeviceEnumerator, (void**)&pDeviceEnumerator); + } + ma_CoUninitialize(pContext); + + if (FAILED(hr)) { /* <-- This is checking the call above to ma_CoCreateInstance(). */ ma_log_postf(ma_context_get_log(pContext), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to create IMMDeviceEnumerator.\n"); return ma_result_from_HRESULT(hr); } @@ -21506,7 +21640,7 @@ static ma_result ma_context_get_device_id_from_MMDevice__wasapi(ma_context* pCon size_t idlen = ma_strlen_WCHAR(pDeviceIDString); if (idlen+1 > ma_countof(pDeviceID->wasapi)) { ma_CoTaskMemFree(pContext, pDeviceIDString); - MA_ASSERT(MA_FALSE); /* NOTE: If this is triggered, please report it. It means the format of the ID must haved change and is too long to fit in our fixed sized buffer. */ + MA_ASSERT(MA_FALSE); /* NOTE: If this is triggered, please report it. It means the format of the ID must have changed and is too long to fit in our fixed sized buffer. */ return MA_ERROR; } @@ -21950,12 +22084,16 @@ static ma_result ma_device_uninit__wasapi(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); -#if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) - if (pDevice->wasapi.pDeviceEnumerator) { - ((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator, &pDevice->wasapi.notificationClient); - ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator); + #if defined(MA_WIN32_DESKTOP) || defined(MA_WIN32_GDK) + { + if (pDevice->wasapi.pDeviceEnumerator) { + ((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator)->lpVtbl->UnregisterEndpointNotificationCallback((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator, &pDevice->wasapi.notificationClient); + ma_IMMDeviceEnumerator_Release((ma_IMMDeviceEnumerator*)pDevice->wasapi.pDeviceEnumerator); + } + + ma_mutex_uninit(&pDevice->wasapi.rerouteLock); } -#endif + #endif if (pDevice->wasapi.pRenderClient) { if (pDevice->wasapi.pMappedBufferPlayback != NULL) { @@ -22256,7 +22394,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device MA_REFERENCE_TIME bufferDuration = periodDurationInMicroseconds * pData->periodsOut * 10; /* - If the periodicy is too small, Initialize() will fail with AUDCLNT_E_INVALID_DEVICE_PERIOD. In this case we should just keep increasing + If the periodicity is too small, Initialize() will fail with AUDCLNT_E_INVALID_DEVICE_PERIOD. In this case we should just keep increasing it and trying it again. */ hr = E_FAIL; @@ -22266,7 +22404,7 @@ static ma_result ma_device_init_internal__wasapi(ma_context* pContext, ma_device if (bufferDuration > 500*10000) { break; } else { - if (bufferDuration == 0) { /* <-- Just a sanity check to prevent an infinit loop. Should never happen, but it makes me feel better. */ + if (bufferDuration == 0) { /* <-- Just a sanity check to prevent an infinite loop. Should never happen, but it makes me feel better. */ break; } @@ -23005,6 +23143,14 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) } if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { + /* If we have a mapped buffer we need to release it. */ + if (pDevice->wasapi.pMappedBufferCapture != NULL) { + ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); + pDevice->wasapi.pMappedBufferCapture = NULL; + pDevice->wasapi.mappedBufferCaptureCap = 0; + pDevice->wasapi.mappedBufferCaptureLen = 0; + } + hr = ma_IAudioClient_Stop((ma_IAudioClient*)pDevice->wasapi.pAudioClientCapture); if (FAILED(hr)) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to stop internal capture device."); @@ -23018,31 +23164,34 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) return ma_result_from_HRESULT(hr); } - /* If we have a mapped buffer we need to release it. */ - if (pDevice->wasapi.pMappedBufferCapture != NULL) { - ma_IAudioCaptureClient_ReleaseBuffer((ma_IAudioCaptureClient*)pDevice->wasapi.pCaptureClient, pDevice->wasapi.mappedBufferCaptureCap); - pDevice->wasapi.pMappedBufferCapture = NULL; - pDevice->wasapi.mappedBufferCaptureCap = 0; - pDevice->wasapi.mappedBufferCaptureLen = 0; - } - ma_atomic_bool32_set(&pDevice->wasapi.isStartedCapture, MA_FALSE); } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + if (pDevice->wasapi.pMappedBufferPlayback != NULL) { + ma_silence_pcm_frames( + ma_offset_pcm_frames_ptr(pDevice->wasapi.pMappedBufferPlayback, pDevice->wasapi.mappedBufferPlaybackLen, pDevice->playback.internalFormat, pDevice->playback.internalChannels), + pDevice->wasapi.mappedBufferPlaybackCap - pDevice->wasapi.mappedBufferPlaybackLen, + pDevice->playback.internalFormat, pDevice->playback.internalChannels + ); + ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); + pDevice->wasapi.pMappedBufferPlayback = NULL; + pDevice->wasapi.mappedBufferPlaybackCap = 0; + pDevice->wasapi.mappedBufferPlaybackLen = 0; + } + /* The buffer needs to be drained before stopping the device. Not doing this will result in the last few frames not getting output to the speakers. This is a problem for very short sounds because it'll result in a significant portion of it not getting played. */ if (ma_atomic_bool32_get(&pDevice->wasapi.isStartedPlayback)) { /* We need to make sure we put a timeout here or else we'll risk getting stuck in a deadlock in some cases. */ - DWORD waitTime = pDevice->wasapi.actualBufferSizeInFramesPlayback / pDevice->playback.internalSampleRate; + DWORD waitTime = (pDevice->wasapi.actualBufferSizeInFramesPlayback * 1000) / pDevice->playback.internalSampleRate; if (pDevice->playback.shareMode == ma_share_mode_exclusive) { WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, waitTime); - } - else { - ma_uint32 prevFramesAvaialablePlayback = (ma_uint32)-1; + } else { + ma_uint32 prevFramesAvailablePlayback = (ma_uint32)-1; ma_uint32 framesAvailablePlayback; for (;;) { result = ma_device__get_available_frames__wasapi(pDevice, (ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback, &framesAvailablePlayback); @@ -23058,13 +23207,13 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) Just a safety check to avoid an infinite loop. If this iteration results in a situation where the number of available frames has not changed, get out of the loop. I don't think this should ever happen, but I think it's nice to have just in case. */ - if (framesAvailablePlayback == prevFramesAvaialablePlayback) { + if (framesAvailablePlayback == prevFramesAvailablePlayback) { break; } - prevFramesAvaialablePlayback = framesAvailablePlayback; + prevFramesAvailablePlayback = framesAvailablePlayback; - WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, waitTime * 1000); ResetEvent((HANDLE)pDevice->wasapi.hEventPlayback); /* Manual reset. */ + WaitForSingleObject((HANDLE)pDevice->wasapi.hEventPlayback, waitTime); } } } @@ -23076,19 +23225,20 @@ static ma_result ma_device_stop__wasapi_nolock(ma_device* pDevice) } /* The audio client needs to be reset otherwise restarting will fail. */ - hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback); + { + ma_int32 retries = 5; + + while ((hr = ma_IAudioClient_Reset((ma_IAudioClient*)pDevice->wasapi.pAudioClientPlayback)) == MA_AUDCLNT_E_BUFFER_OPERATION_PENDING && retries > 0) { + ma_sleep(10); + retries -= 1; + } + } + if (FAILED(hr)) { ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[WASAPI] Failed to reset internal playback device."); return ma_result_from_HRESULT(hr); } - if (pDevice->wasapi.pMappedBufferPlayback != NULL) { - ma_IAudioRenderClient_ReleaseBuffer((ma_IAudioRenderClient*)pDevice->wasapi.pRenderClient, pDevice->wasapi.mappedBufferPlaybackCap, 0); - pDevice->wasapi.pMappedBufferPlayback = NULL; - pDevice->wasapi.mappedBufferPlaybackCap = 0; - pDevice->wasapi.mappedBufferPlaybackLen = 0; - } - ma_atomic_bool32_set(&pDevice->wasapi.isStartedPlayback, MA_FALSE); } @@ -23655,6 +23805,13 @@ DirectSound Backend #define MA_DSBPLAY_TERMINATEBY_DISTANCE 0x00000010 #define MA_DSBPLAY_TERMINATEBY_PRIORITY 0x00000020 +#define MA_DSBSTATUS_PLAYING 0x00000001 +#define MA_DSBSTATUS_BUFFERLOST 0x00000002 +#define MA_DSBSTATUS_LOOPING 0x00000004 +#define MA_DSBSTATUS_LOCHARDWARE 0x00000008 +#define MA_DSBSTATUS_LOCSOFTWARE 0x00000010 +#define MA_DSBSTATUS_TERMINATED 0x00000020 + #define MA_DSCBSTART_LOOPING 0x00000001 typedef struct @@ -24024,9 +24181,12 @@ static ma_result ma_context_create_IDirectSound__dsound(ma_context* pContext, ma } /* The cooperative level must be set before doing anything else. */ - hWnd = ((MA_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)(); + hWnd = (HWND)pContext->dsound.hWnd; if (hWnd == 0) { - hWnd = ((MA_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)(); + hWnd = ((MA_PFN_GetForegroundWindow)pContext->win32.GetForegroundWindow)(); + if (hWnd == 0) { + hWnd = ((MA_PFN_GetDesktopWindow)pContext->win32.GetDesktopWindow)(); + } } hr = ma_IDirectSound_SetCooperativeLevel(pDirectSound, hWnd, (shareMode == ma_share_mode_exclusive) ? MA_DSSCL_EXCLUSIVE : MA_DSSCL_PRIORITY); @@ -24530,8 +24690,8 @@ static ma_result ma_device_init__dsound(ma_device* pDevice, const ma_device_conf } /* - Unfortunately DirectSound uses different APIs and data structures for playback and catpure devices. We need to initialize - the capture device first because we'll want to match it's buffer size and period count on the playback side if we're using + Unfortunately DirectSound uses different APIs and data structures for playback and capture devices. We need to initialize + the capture device first because we'll want to match its buffer size and period count on the playback side if we're using full-duplex mode. */ if (pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) { @@ -24814,6 +24974,7 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) ma_bool32 isPlaybackDeviceStarted = MA_FALSE; ma_uint32 framesWrittenToPlaybackDevice = 0; /* For knowing whether or not the playback device needs to be started. */ ma_uint32 waitTimeInMilliseconds = 1; + DWORD playbackBufferStatus = 0; MA_ASSERT(pDevice != NULL); @@ -25142,6 +25303,20 @@ static ma_result ma_device_data_loop__dsound(ma_device* pDevice) break; } + hr = ma_IDirectSoundBuffer_GetStatus((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, &playbackBufferStatus); + if (SUCCEEDED(hr) && (playbackBufferStatus & MA_DSBSTATUS_PLAYING) == 0 && isPlaybackDeviceStarted) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[DirectSound] Attempting to resume audio due to state: %d.", (int)playbackBufferStatus); + hr = ma_IDirectSoundBuffer_Play((ma_IDirectSoundBuffer*)pDevice->dsound.pPlaybackBuffer, 0, 0, MA_DSBPLAY_LOOPING); + if (FAILED(hr)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[DirectSound] IDirectSoundBuffer_Play() failed after attempting to resume from state %d.", (int)playbackBufferStatus); + return ma_result_from_HRESULT(hr); + } + + isPlaybackDeviceStarted = MA_TRUE; + ma_sleep(waitTimeInMilliseconds); + continue; + } + if (physicalPlayCursorInBytes < prevPlayCursorInBytesPlayback) { physicalPlayCursorLoopFlagPlayback = !physicalPlayCursorLoopFlagPlayback; } @@ -25343,6 +25518,8 @@ static ma_result ma_context_init__dsound(ma_context* pContext, const ma_context_ return MA_API_NOT_FOUND; } + pContext->dsound.hWnd = pConfig->dsound.hWnd; + pCallbacks->onContextInit = ma_context_init__dsound; pCallbacks->onContextUninit = ma_context_uninit__dsound; pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__dsound; @@ -25665,7 +25842,7 @@ static ma_result ma_context_get_device_info_from_WAVECAPS(ma_context* pContext, - If the name GUID is not present in the registry we'll also need to stick to the original 31 characters. - I like consistency, so I want the returned device names to be consistent with those returned by WASAPI and DirectSound. The problem, however is that WASAPI and DirectSound use " ()" format (such as "Speakers (High Definition Audio)"), - but WinMM does not specificy the component name. From my admittedly limited testing, I've notice the component name seems to + but WinMM does not specify the component name. From my admittedly limited testing, I've notice the component name seems to usually fit within the 31 characters of the fixed sized buffer, so what I'm going to do is parse that string for the component name, and then concatenate the name from the registry. */ @@ -25933,7 +26110,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi return MA_DEVICE_TYPE_NOT_SUPPORTED; } - /* No exlusive mode with WinMM. */ + /* No exclusive mode with WinMM. */ if (((pConfig->deviceType == ma_device_type_playback || pConfig->deviceType == ma_device_type_duplex) && pDescriptorPlayback->shareMode == ma_share_mode_exclusive) || ((pConfig->deviceType == ma_device_type_capture || pConfig->deviceType == ma_device_type_duplex) && pDescriptorCapture->shareMode == ma_share_mode_exclusive)) { return MA_SHARE_MODE_NOT_SUPPORTED; @@ -25955,7 +26132,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi /* We use an event to know when a new fragment needs to be enqueued. */ pDevice->winmm.hEventCapture = (ma_handle)CreateEventA(NULL, TRUE, TRUE, NULL); if (pDevice->winmm.hEventCapture == NULL) { - errorMsg = "[WinMM] Failed to create event for fragment enqueing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError()); + errorMsg = "[WinMM] Failed to create event for fragment enqueuing for the capture device.", errorCode = ma_result_from_GetLastError(GetLastError()); goto on_error; } @@ -25993,7 +26170,7 @@ static ma_result ma_device_init__winmm(ma_device* pDevice, const ma_device_confi /* We use an event to know when a new fragment needs to be enqueued. */ pDevice->winmm.hEventPlayback = (ma_handle)CreateEventA(NULL, TRUE, TRUE, NULL); if (pDevice->winmm.hEventPlayback == NULL) { - errorMsg = "[WinMM] Failed to create event for fragment enqueing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError()); + errorMsg = "[WinMM] Failed to create event for fragment enqueuing for the playback device.", errorCode = ma_result_from_GetLastError(GetLastError()); goto on_error; } @@ -27115,7 +27292,7 @@ static ma_result ma_context_open_pcm__alsa(ma_context* pContext, ma_share_mode s /* We're trying to open a specific device. There's a few things to consider here: - miniaudio recongnizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When + miniaudio recognizes a special format of device id that excludes the "hw", "dmix", etc. prefix. It looks like this: ":0,0", ":0,1", etc. When an ID of this format is specified, it indicates to miniaudio that it can try different combinations of plugins ("hw", "dmix", etc.) until it finds an appropriate one that works. This comes in very handy when trying to open a device in shared mode ("dmix"), vs exclusive mode ("hw"). */ @@ -27214,7 +27391,7 @@ static ma_result ma_context_enumerate_devices__alsa(ma_context* pContext, ma_enu /* At this point, hwid looks like "hw:0,0". In simplified enumeration mode, we actually want to strip off the plugin name so it looks like ":0,0". The reason for this is that this special format is detected at device - initialization time and is used as an indicator to try and use the most appropriate plugin depending on the + initialization time and is used as an indicator to try to use the most appropriate plugin depending on the device type and sharing mode. */ char* dst = hwid; @@ -27393,7 +27570,7 @@ static void ma_context_iterate_rates_and_add_native_data_format__alsa(ma_context ((ma_snd_pcm_hw_params_get_rate_min_proc)pContext->alsa.snd_pcm_hw_params_get_rate_min)(pHWParams, &minSampleRate, &sampleRateDir); ((ma_snd_pcm_hw_params_get_rate_max_proc)pContext->alsa.snd_pcm_hw_params_get_rate_max)(pHWParams, &maxSampleRate, &sampleRateDir); - /* Make sure our sample rates are clamped to sane values. Stupid devices like "pulse" will reports rates like "1" which is ridiculus. */ + /* Make sure our sample rates are clamped to sane values. Stupid devices like "pulse" will reports rates like "1" which is ridiculous. */ minSampleRate = ma_clamp(minSampleRate, (unsigned int)ma_standard_sample_rate_min, (unsigned int)ma_standard_sample_rate_max); maxSampleRate = ma_clamp(maxSampleRate, (unsigned int)ma_standard_sample_rate_min, (unsigned int)ma_standard_sample_rate_max); @@ -27469,10 +27646,10 @@ static ma_result ma_context_get_device_info__alsa(ma_context* pContext, ma_devic /* Some ALSA devices can support many permutations of formats, channels and rates. We only support a fixed number of permutations which means we need to employ some strategies to ensure the best - combinations are returned. An example is the "pulse" device which can do it's own data conversion + combinations are returned. An example is the "pulse" device which can do its own data conversion in software and as a result can support any combination of format, channels and rate. - We want to ensure the the first data formats are the best. We have a list of favored sample + We want to ensure that the first data formats are the best. We have a list of favored sample formats and sample rates, so these will be the basis of our iteration. */ @@ -28050,7 +28227,21 @@ static ma_result ma_device_start__alsa(ma_device* pDevice) } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - /* Don't need to do anything for playback because it'll be started automatically when enough data has been written. */ + /* + When data is written to the device we wait for the device to get ready to receive data with poll(). In my testing + I have observed that poll() can sometimes block forever unless the device is started explicitly with snd_pcm_start() + or some data is written with snd_pcm_writei(). + + To resolve this I've decided to do an explicit start with snd_pcm_start(). The problem with this is that the device + is started without any data in the internal buffer which will result in an immediate underrun. If instead we were + to call into snd_pcm_writei() in an attempt to prevent the underrun, we would run the risk of a weird deadlock + issue as documented inside ma_device_write__alsa(). + */ + resultALSA = ((ma_snd_pcm_start_proc)pDevice->pContext->alsa.snd_pcm_start)((ma_snd_pcm_t*)pDevice->alsa.pPCMPlayback); + if (resultALSA < 0) { + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] Failed to start playback device."); + return ma_result_from_errno(-resultALSA); + } } return MA_SUCCESS; @@ -28063,6 +28254,7 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice) a small chance that our wakeupfd has not been cleared. We'll clear that out now if applicable. */ int resultPoll; + int resultRead; if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Dropping capture device...\n"); @@ -28077,12 +28269,15 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice) ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Preparing capture device successful.\n"); } - /* Clear the wakeupfd. */ - resultPoll = poll((struct pollfd*)pDevice->alsa.pPollDescriptorsCapture, 1, 0); - if (resultPoll > 0) { - ma_uint64 t; - read(((struct pollfd*)pDevice->alsa.pPollDescriptorsCapture)[0].fd, &t, sizeof(t)); - } + /* Clear the wakeupfd. */ + resultPoll = poll((struct pollfd*)pDevice->alsa.pPollDescriptorsCapture, 1, 0); + if (resultPoll > 0) { + ma_uint64 t; + resultRead = read(((struct pollfd*)pDevice->alsa.pPollDescriptorsCapture)[0].fd, &t, sizeof(t)); + if (resultRead != sizeof(t)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to read from capture wakeupfd. read() = %d\n", resultRead); + } + } } if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { @@ -28099,12 +28294,14 @@ static ma_result ma_device_stop__alsa(ma_device* pDevice) } /* Clear the wakeupfd. */ - resultPoll = poll((struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback, 1, 0); - if (resultPoll > 0) { - ma_uint64 t; - read(((struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback)[0].fd, &t, sizeof(t)); - } - + resultPoll = poll((struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback, 1, 0); + if (resultPoll > 0) { + ma_uint64 t; + resultRead = read(((struct pollfd*)pDevice->alsa.pPollDescriptorsPlayback)[0].fd, &t, sizeof(t)); + if (resultRead != sizeof(t)) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "[ALSA] Failed to read from playback wakeupfd. read() = %d\n", resultRead); + } + } } return MA_SUCCESS; @@ -28117,13 +28314,20 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st int resultALSA; int resultPoll = poll(pPollDescriptors, pollDescriptorCount, -1); if (resultPoll < 0) { - ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[ALSA] poll() failed.\n"); - return ma_result_from_errno(errno); + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[ALSA] poll() failed.\n"); + + /* + There have been reports that poll() is returning an error randomly and that instead of + returning an error, simply trying again will work. I'm experimenting with adopting this + advice. + */ + continue; + /*return ma_result_from_errno(errno);*/ } /* Before checking the ALSA poll descriptor flag we need to check if the wakeup descriptor - has had it's POLLIN flag set. If so, we need to actually read the data and then exit + has had it's POLLIN flag set. If so, we need to actually read the data and then exit the function. The wakeup descriptor will be the first item in the descriptors buffer. */ if ((pPollDescriptors[0].revents & POLLIN) != 0) { @@ -28152,7 +28356,7 @@ static ma_result ma_device_wait__alsa(ma_device* pDevice, ma_snd_pcm_t* pPCM, st ma_snd_pcm_state_t state = ((ma_snd_pcm_state_proc)pDevice->pContext->alsa.snd_pcm_state)(pPCM); if (state == MA_SND_PCM_STATE_XRUN) { /* The PCM is in a xrun state. This will be recovered from at a higher level. We can disregard this. */ - } else { + } else { ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[ALSA] POLLERR detected. status = %d\n", ((ma_snd_pcm_state_proc)pDevice->pContext->alsa.snd_pcm_state)(pPCM)); } } @@ -28585,7 +28789,7 @@ static ma_result ma_context_init__alsa(ma_context* pContext, const ma_context_co return MA_SUCCESS; } -#endif /* ALSA */ +#endif /* MA_HAS_ALSA */ @@ -28596,7 +28800,7 @@ PulseAudio Backend ******************************************************************************/ #ifdef MA_HAS_PULSEAUDIO /* -The PulseAudio API, along with Apple's Core Audio, is the worst of the maintream audio APIs. This is a brief description of what's going on +The PulseAudio API, along with Apple's Core Audio, is the worst of the mainstream audio APIs. This is a brief description of what's going on in the PulseAudio backend. I apologize if this gets a bit ranty for your liking - you might want to skip this discussion. PulseAudio has something they call the "Simple API", which unfortunately isn't suitable for miniaudio. I've not seen anywhere where it @@ -28611,7 +28815,7 @@ get fun, and I don't mean that in a good way... The problems start with the very name of the API - "asynchronous". Yes, this is an asynchronous oriented API which means your commands don't immediately take effect. You instead need to issue your commands, and then wait for them to complete. The waiting mechanism is -enabled through the use of a "main loop". In the asychronous API you cannot get away from the main loop, and the main loop is where almost +enabled through the use of a "main loop". In the asynchronous API you cannot get away from the main loop, and the main loop is where almost all of PulseAudio's problems stem from. When you first initialize PulseAudio you need an object referred to as "main loop". You can implement this yourself by defining your own @@ -28661,7 +28865,7 @@ because PulseAudio takes it literally, specifically the "can be". You would thin writing and reading data to and from the stream, and that would be right, except when it's not. When you initialize the stream, you can set a flag that tells PulseAudio to not start the stream automatically. This is required because miniaudio does not auto-start devices straight after initialization - you need to call `ma_device_start()` manually. The problem is that even when this flag is specified, -PulseAudio will immediately fire it's write or read callback. This is *technically* correct (based on the wording in the documentation) +PulseAudio will immediately fire its write or read callback. This is *technically* correct (based on the wording in the documentation) because indeed, data *can* be written at this point. The problem is that it's not *practical*. It makes sense that the write/read callback would be where a program will want to write or read data to or from the stream, but when it's called before the application has even requested that the stream be started, it's just not practical because the program probably isn't ready for any kind of data delivery at @@ -30039,16 +30243,18 @@ static ma_pa_buffer_attr ma_device__pa_buffer_attr_new(ma_uint32 periodSizeInFra static ma_pa_stream* ma_device__pa_stream_new__pulse(ma_device* pDevice, const char* pStreamName, const ma_pa_sample_spec* ss, const ma_pa_channel_map* cmap) { - static int g_StreamCounter = 0; + static ma_atomic_uint32 g_StreamCounter = { 0 }; char actualStreamName[256]; if (pStreamName != NULL) { ma_strncpy_s(actualStreamName, sizeof(actualStreamName), pStreamName, (size_t)-1); } else { - ma_strcpy_s(actualStreamName, sizeof(actualStreamName), "miniaudio:"); - ma_itoa_s(g_StreamCounter, actualStreamName + 8, sizeof(actualStreamName)-8, 10); /* 8 = strlen("miniaudio:") */ + const char* pBaseName = "miniaudio:"; + size_t baseNameLen = strlen(pBaseName); + ma_strcpy_s(actualStreamName, sizeof(actualStreamName), pBaseName); + ma_itoa_s((int)ma_atomic_uint32_get(&g_StreamCounter), actualStreamName + baseNameLen, sizeof(actualStreamName)-baseNameLen, 10); } - g_StreamCounter += 1; + ma_atomic_uint32_fetch_add(&g_StreamCounter, 1); return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pulse.pPulseContext, actualStreamName, ss, cmap); } @@ -30302,6 +30508,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi ma_pa_buffer_attr attr; const ma_pa_sample_spec* pActualSS = NULL; const ma_pa_buffer_attr* pActualAttr = NULL; + const ma_pa_channel_map* pActualChannelMap = NULL; ma_uint32 iChannel; ma_pa_stream_flags_t streamFlags; @@ -30362,7 +30569,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi } /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, MA_PA_CHANNEL_MAP_DEFAULT); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ if (pDescriptorCapture->sampleRate != 0) { @@ -30451,7 +30658,12 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi goto on_error4; } + /* Internal channel map. */ + pActualChannelMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamCapture); + if (pActualChannelMap == NULL) { + pActualChannelMap = &cmap; /* Fallback just in case. */ + } /* Bug in PipeWire. There have been reports that PipeWire is returning AUX channels when reporting @@ -30461,8 +30673,8 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi fixed sooner than later. I might remove this hack later. */ if (pDescriptorCapture->channels > 2) { - for (iChannel = 0; iChannel < pDescriptorCapture->channels; ++iChannel) { - pDescriptorCapture->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); + for (iChannel = 0; iChannel < pDescriptorCapture->channels; iChannel += 1) { + pDescriptorCapture->channelMap[iChannel] = ma_channel_position_from_pulse(pActualChannelMap->map[iChannel]); } } else { /* Hack for mono and stereo. */ @@ -30509,7 +30721,7 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi } /* Use a default channel map. */ - ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, MA_PA_CHANNEL_MAP_DEFAULT); + ((ma_pa_channel_map_init_extend_proc)pDevice->pContext->pulse.pa_channel_map_init_extend)(&cmap, ss.channels, pConfig->pulse.channelMap); /* Use the requested sample rate if one was specified. */ @@ -30603,7 +30815,12 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi goto on_error4; } + /* Internal channel map. */ + pActualChannelMap = ((ma_pa_stream_get_channel_map_proc)pDevice->pContext->pulse.pa_stream_get_channel_map)((ma_pa_stream*)pDevice->pulse.pStreamPlayback); + if (pActualChannelMap == NULL) { + pActualChannelMap = &cmap; /* Fallback just in case. */ + } /* Bug in PipeWire. There have been reports that PipeWire is returning AUX channels when reporting @@ -30613,8 +30830,8 @@ static ma_result ma_device_init__pulse(ma_device* pDevice, const ma_device_confi fixed sooner than later. I might remove this hack later. */ if (pDescriptorPlayback->channels > 2) { - for (iChannel = 0; iChannel < pDescriptorPlayback->channels; ++iChannel) { - pDescriptorPlayback->channelMap[iChannel] = ma_channel_position_from_pulse(cmap.map[iChannel]); + for (iChannel = 0; iChannel < pDescriptorPlayback->channels; iChannel += 1) { + pDescriptorPlayback->channelMap[iChannel] = ma_channel_position_from_pulse(pActualChannelMap->map[iChannel]); } } else { /* Hack for mono and stereo. */ @@ -31767,7 +31984,7 @@ static ma_result ma_context_init__jack(ma_context* pContext, const ma_context_co return MA_SUCCESS; } -#endif /* JACK */ +#endif /* MA_HAS_JACK */ @@ -31858,7 +32075,7 @@ that supports this level of detail. There was some public domain sample code I s and AudioUnit APIs, but I couldn't see anything that gave low-level control over device selection and capabilities (the distinction between playback and capture in particular). Therefore, miniaudio is using the AudioObject API. -Most (all?) functions in the AudioObject API take a AudioObjectID as it's input. This is the device identifier. When +Most (all?) functions in the AudioObject API take a AudioObjectID as its input. This is the device identifier. When retrieving global information, such as the device list, you use kAudioObjectSystemObject. When retrieving device-specific data, you pass in the ID for that device. In order to retrieve device-specific IDs you need to enumerate over each of the devices. This is done using the AudioObjectGetPropertyDataSize() and AudioObjectGetPropertyData() APIs which seem to be @@ -32193,6 +32410,12 @@ static ma_result ma_get_channel_map_from_AudioChannelLayout(AudioChannelLayout* #define AUDIO_OBJECT_PROPERTY_ELEMENT kAudioObjectPropertyElementMaster #endif +/* kAudioDevicePropertyScope* were renamed to kAudioObjectPropertyScope* in 10.8. */ +#if !defined(MAC_OS_X_VERSION_10_8) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8) +#define kAudioObjectPropertyScopeInput kAudioDevicePropertyScopeInput +#define kAudioObjectPropertyScopeOutput kAudioDevicePropertyScopeOutput +#endif + static ma_result ma_get_device_object_ids__coreaudio(ma_context* pContext, UInt32* pDeviceCount, AudioObjectID** ppDeviceObjectIDs) /* NOTE: Free the returned buffer with ma_free(). */ { AudioObjectPropertyAddress propAddressDevices; @@ -32782,7 +33005,7 @@ static ma_result ma_find_best_format__coreaudio(ma_context* pContext, AudioObjec desiredSampleRate = sampleRate; if (desiredSampleRate == 0) { - desiredSampleRate = pOrigFormat->mSampleRate; + desiredSampleRate = (ma_uint32)pOrigFormat->mSampleRate; } desiredChannelCount = channels; @@ -33425,7 +33648,7 @@ static OSStatus ma_on_output__coreaudio(void* pUserData, AudioUnitRenderActionFl } } else { /* This is the deinterleaved case. We need to update each buffer in groups of internalChannels. This assumes each buffer is the same size. */ - MA_ASSERT(pDevice->playback.internalChannels <= MA_MAX_CHANNELS); /* This should heve been validated at initialization time. */ + MA_ASSERT(pDevice->playback.internalChannels <= MA_MAX_CHANNELS); /* This should have been validated at initialization time. */ /* For safety we'll check that the internal channels is a multiple of the buffer count. If it's not it means something @@ -33516,11 +33739,12 @@ static OSStatus ma_on_input__coreaudio(void* pUserData, AudioUnitRenderActionFla */ for (iBuffer = 0; iBuffer < pRenderedBufferList->mNumberBuffers; ++iBuffer) { pRenderedBufferList->mBuffers[iBuffer].mDataByteSize = pDevice->coreaudio.audioBufferCapInFrames * ma_get_bytes_per_sample(pDevice->capture.internalFormat) * pRenderedBufferList->mBuffers[iBuffer].mNumberChannels; + /*printf("DEBUG: nDataByteSize = %d\n", (int)pRenderedBufferList->mBuffers[iBuffer].mDataByteSize);*/ } status = ((ma_AudioUnitRender_proc)pDevice->pContext->coreaudio.AudioUnitRender)((AudioUnit)pDevice->coreaudio.audioUnitCapture, pActionFlags, pTimeStamp, busNumber, frameCount, pRenderedBufferList); if (status != noErr) { - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, " ERROR: AudioUnitRender() failed with %d.\n", (int)status); + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_DEBUG, "ERROR: AudioUnitRender() failed with %d.\n", (int)status); return status; } @@ -33756,7 +33980,7 @@ static ma_result ma_context__init_device_tracking__coreaudio(ma_context* pContex ma_spinlock_lock(&g_DeviceTrackingInitLock_CoreAudio); { - /* Don't do anything if we've already initializd device tracking. */ + /* Don't do anything if we've already initialized device tracking. */ if (g_DeviceTrackingInitCounter_CoreAudio == 0) { AudioObjectPropertyAddress propAddress; propAddress.mScope = kAudioObjectPropertyScopeGlobal; @@ -34068,11 +34292,11 @@ typedef struct static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pDeviceID, ma_device_init_internal_data__coreaudio* pData, void* pDevice_DoNotReference) /* <-- pDevice is typed as void* intentionally so as to avoid accidentally referencing it. */ { - ma_result result; + ma_result result = MA_SUCCESS; OSStatus status; UInt32 enableIOFlag; AudioStreamBasicDescription bestFormat; - UInt32 actualPeriodSizeInFrames; + ma_uint32 actualPeriodSizeInFrames; AURenderCallbackStruct callbackInfo; #if defined(MA_APPLE_DESKTOP) AudioObjectID deviceObjectID; @@ -34224,7 +34448,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev returning a result code of -10863. I have also tried changing the format directly on the input scope on the input bus, but this just results in `ca_require: IsStreamFormatWritable(inScope, inElement) NotWritable` when trying to set the format. - Something that does seem to work, however, has been setting the nominal sample rate on the deivce object. The problem with + Something that does seem to work, however, has been setting the nominal sample rate on the device object. The problem with this, however, is that it actually changes the sample rate at the operating system level and not just the application. This could be intrusive to the user, however, so I don't think it's wise to make this the default. Instead I'm making this a configuration option. When the `coreaudio.allowNominalSampleRateChange` config option is set to true, changing the sample @@ -34275,15 +34499,28 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev /* I've had a report that the channel count returned by AudioUnitGetProperty above is inconsistent with AVAudioSession outputNumberOfChannels. I'm going to try using the AVAudioSession values instead. + + UPDATE 20/02/2025: + When testing on the simulator with an iPhone 15 and iOS 17 I get an error when initializing the audio + unit if set the input channels to pAudioSession.inputNumberOfChannels. What is happening is the channel + count returned from AudioUnitGetProperty() above is set to 2, but pAudioSession is reporting a channel + count of 1. When this happens, the call to AudioUnitSetProprty() below just down below will succeed, but + AudioUnitInitialize() further down will fail. The only solution I have come up with is to not set the + channel count to pAudioSession.inputNumberOfChannels. */ if (deviceType == ma_device_type_playback) { bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.outputNumberOfChannels; } + + #if 0 if (deviceType == ma_device_type_capture) { + /*printf("DEBUG: bestFormat.mChannelsPerFrame = %d; pAudioSession.inputNumberOfChannels = %d\n", (int)bestFormat.mChannelsPerFrame, (int)pAudioSession.inputNumberOfChannels);*/ bestFormat.mChannelsPerFrame = (UInt32)pAudioSession.inputNumberOfChannels; } + #endif } + status = ((ma_AudioUnitSetProperty_proc)pContext->coreaudio.AudioUnitSetProperty)(pData->audioUnit, kAudioUnitProperty_StreamFormat, formatScope, formatElement, &bestFormat, sizeof(bestFormat)); if (status != noErr) { ((ma_AudioComponentInstanceDispose_proc)pContext->coreaudio.AudioComponentInstanceDispose)(pData->audioUnit); @@ -34303,7 +34540,7 @@ static ma_result ma_device_init_internal__coreaudio(ma_context* pContext, ma_dev } pData->channelsOut = bestFormat.mChannelsPerFrame; - pData->sampleRateOut = bestFormat.mSampleRate; + pData->sampleRateOut = (ma_uint32)bestFormat.mSampleRate; } /* Clamp the channel count for safety. */ @@ -34610,7 +34847,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDCapture, sizeof(pDevice->capture.id.coreaudio), pDevice->capture.id.coreaudio); /* - If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly + If we are using the default device we'll need to listen for changes to the system's default device so we can seamlessly switch the device in the background. */ if (pConfig->capture.pDeviceID == NULL) { @@ -34674,7 +34911,7 @@ static ma_result ma_device_init__coreaudio(ma_device* pDevice, const ma_device_c ma_get_AudioObject_uid(pDevice->pContext, pDevice->coreaudio.deviceObjectIDPlayback, sizeof(pDevice->playback.id.coreaudio), pDevice->playback.id.coreaudio); /* - If we are using the default device we'll need to listen for changes to the system's default device so we can seemlessly + If we are using the default device we'll need to listen for changes to the system's default device so we can seamlessly switch the device in the background. */ if (pDescriptorPlayback->pDeviceID == NULL && (pConfig->deviceType != ma_device_type_duplex || pDescriptorCapture->pDeviceID != NULL)) { @@ -34992,7 +35229,7 @@ static ma_result ma_context_init__coreaudio(ma_context* pContext, const ma_conte return MA_SUCCESS; } -#endif /* Core Audio */ +#endif /* MA_HAS_COREAUDIO */ @@ -35484,7 +35721,7 @@ static ma_result ma_device_uninit__sndio(ma_device* pDevice) ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handleCapture); } - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { ((ma_sio_close_proc)pDevice->pContext->sndio.sio_close)((struct ma_sio_hdl*)pDevice->sndio.handlePlayback); } @@ -35839,7 +36076,7 @@ static ma_result ma_context_init__sndio(ma_context* pContext, const ma_context_c (void)pConfig; return MA_SUCCESS; } -#endif /* sndio */ +#endif /* MA_HAS_SNDIO */ @@ -35857,6 +36094,10 @@ audio(4) Backend #include #include +#ifdef __NetBSD__ +#include +#endif + #if defined(__OpenBSD__) #include #if defined(OpenBSD) && OpenBSD >= 201709 @@ -36076,9 +36317,15 @@ static ma_result ma_context_get_device_info_from_fd__audio4(ma_context* pContext ma_uint32 channels; ma_uint32 sampleRate; +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 900000000) + if (ioctl(fd, AUDIO_GETFORMAT, &fdInfo) < 0) { + return MA_ERROR; + } +#else if (ioctl(fd, AUDIO_GETINFO, &fdInfo) < 0) { return MA_ERROR; } +#endif if (deviceType == ma_device_type_playback) { channels = fdInfo.play.channels; @@ -36356,7 +36603,11 @@ static ma_result ma_device_init_fd__audio4(ma_device* pDevice, const ma_device_c /* We're using a default device. Get the info from the /dev/audioctl file instead of /dev/audio. */ int fdctl = open(pDefaultDeviceCtlNames[iDefaultDevice], fdFlags, 0); if (fdctl != -1) { +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 900000000) + fdInfoResult = ioctl(fdctl, AUDIO_GETFORMAT, &fdInfo); +#else fdInfoResult = ioctl(fdctl, AUDIO_GETINFO, &fdInfo); +#endif close(fdctl); } } @@ -36723,7 +36974,7 @@ static ma_result ma_context_init__audio4(ma_context* pContext, const ma_context_ return MA_SUCCESS; } -#endif /* audio4 */ +#endif /* MA_HAS_AUDIO4 */ /****************************************************************************** @@ -37086,7 +37337,7 @@ static ma_result ma_device_init_fd__oss(ma_device* pDevice, const ma_device_conf } /* - The OSS documantation is very clear about the order we should be initializing the device's properties: + The OSS documentation is very clear about the order we should be initializing the device's properties: 1) Format 2) Channels 3) Sample rate. @@ -37354,7 +37605,7 @@ static ma_result ma_context_init__oss(ma_context* pContext, const ma_context_con return MA_SUCCESS; } -#endif /* OSS */ +#endif /* MA_HAS_OSS */ @@ -37367,7 +37618,9 @@ AAudio Backend ******************************************************************************/ #ifdef MA_HAS_AAUDIO -/*#include */ +#ifdef MA_NO_RUNTIME_LINKING + #include +#endif typedef int32_t ma_aaudio_result_t; typedef int32_t ma_aaudio_direction_t; @@ -37580,9 +37833,7 @@ static void ma_stream_error_callback__aaudio(ma_AAudioStream* pStream, void* pUs MA_ASSERT(pDevice != NULL); (void)error; - ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] ERROR CALLBACK: error=%d, AAudioStream_getState()=%d\n", error, ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream)); - /* When we get an error, we'll assume that the stream is in an erroneous state and needs to be restarted. From the documentation, we cannot do this from the error callback. Therefore we are going to use an event thread for the AAudio backend to do this @@ -37610,7 +37861,9 @@ static ma_aaudio_data_callback_result_t ma_stream_data_callback_capture__aaudio( ma_device* pDevice = (ma_device*)pUserData; MA_ASSERT(pDevice != NULL); - ma_device_handle_backend_data_callback(pDevice, NULL, pAudioData, frameCount); + if (frameCount > 0) { + ma_device_handle_backend_data_callback(pDevice, NULL, pAudioData, (ma_uint32)frameCount); + } (void)pStream; return MA_AAUDIO_CALLBACK_RESULT_CONTINUE; @@ -37621,7 +37874,14 @@ static ma_aaudio_data_callback_result_t ma_stream_data_callback_playback__aaudio ma_device* pDevice = (ma_device*)pUserData; MA_ASSERT(pDevice != NULL); - ma_device_handle_backend_data_callback(pDevice, pAudioData, NULL, frameCount); + /* + I've had a report that AAudio can sometimes post a frame count of 0. We need to check for that here + so we don't get any errors at a deeper level. I'm doing the same with the capture side for safety, + though I've not yet had any reports about that one. + */ + if (frameCount > 0) { + ma_device_handle_backend_data_callback(pDevice, pAudioData, NULL, (ma_uint32)frameCount); + } (void)pStream; return MA_AAUDIO_CALLBACK_RESULT_CONTINUE; @@ -37656,32 +37916,25 @@ static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* ((MA_PFN_AAudioStreamBuilder_setSampleRate)pContext->aaudio.AAudioStreamBuilder_setSampleRate)(pBuilder, pDescriptor->sampleRate); } - if (deviceType == ma_device_type_capture) { - if (pDescriptor->channels != 0) { - ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels); - } - if (pDescriptor->format != ma_format_unknown) { - ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT); - } - } else { - if (pDescriptor->channels != 0) { - ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels); - } - if (pDescriptor->format != ma_format_unknown) { - ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT); - } + if (pDescriptor->channels != 0) { + ((MA_PFN_AAudioStreamBuilder_setChannelCount)pContext->aaudio.AAudioStreamBuilder_setChannelCount)(pBuilder, pDescriptor->channels); + } + + if (pDescriptor->format != ma_format_unknown) { + ((MA_PFN_AAudioStreamBuilder_setFormat)pContext->aaudio.AAudioStreamBuilder_setFormat)(pBuilder, (pDescriptor->format == ma_format_s16) ? MA_AAUDIO_FORMAT_PCM_I16 : MA_AAUDIO_FORMAT_PCM_FLOAT); } /* - There have been reports where setting the frames per data callback results in an error - later on from Android. To address this, I'm experimenting with simply not setting it on - anything from Android 11 and earlier. Suggestions welcome on how we might be able to make - this more targetted. + There have been reports where setting the frames per data callback results in an error. + In particular, re-routing may inadvertently switch from low-latency mode, resulting in a less stable + stream from the legacy path (AudioStreamLegacy). To address this, we simply don't set the value. It + can still be set if it's explicitly requested via the aaudio.allowSetBufferCapacity variable in the + device config. */ - if (!pConfig->aaudio.enableCompatibilityWorkarounds || ma_android_sdk_version() > 30) { + if ((!pConfig->aaudio.enableCompatibilityWorkarounds || ma_android_sdk_version() > 30) && pConfig->aaudio.allowSetBufferCapacity) { /* - AAudio is annoying when it comes to it's buffer calculation stuff because it doesn't let you + AAudio is annoying when it comes to its buffer calculation stuff because it doesn't let you retrieve the actual sample rate until after you've opened the stream. But you need to configure the buffer capacity before you open the stream... :/ @@ -37715,7 +37968,11 @@ static ma_result ma_create_and_configure_AAudioStreamBuilder__aaudio(ma_context* ((MA_PFN_AAudioStreamBuilder_setDataCallback)pContext->aaudio.AAudioStreamBuilder_setDataCallback)(pBuilder, ma_stream_data_callback_playback__aaudio, (void*)pDevice); } - /* Not sure how this affects things, but since there's a mapping between miniaudio's performance profiles and AAudio's performance modes, let go ahead and set it. */ + /* + If we set AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, we allow for MMAP (non-legacy path). + Since there's a mapping between miniaudio's performance profiles and AAudio's performance modes, let's use it. + Beware though, with a conservative performance profile, AAudio will indeed take the legacy path. + */ ((MA_PFN_AAudioStreamBuilder_setPerformanceMode)pContext->aaudio.AAudioStreamBuilder_setPerformanceMode)(pBuilder, (pConfig->performanceProfile == ma_performance_profile_low_latency) ? MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY : MA_AAUDIO_PERFORMANCE_MODE_NONE); /* We need to set an error callback to detect device changes. */ @@ -37751,6 +38008,9 @@ static ma_result ma_open_stream_basic__aaudio(ma_context* pContext, const ma_dev return result; } + /* Let's give AAudio a hint to avoid the legacy path (AudioStreamLegacy). */ + ((MA_PFN_AAudioStreamBuilder_setPerformanceMode)pContext->aaudio.AAudioStreamBuilder_setPerformanceMode)(pBuilder, MA_AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); + return ma_open_stream_and_close_builder__aaudio(pContext, pBuilder, ppStream); } @@ -37775,6 +38035,10 @@ static ma_result ma_open_stream__aaudio(ma_device* pDevice, const ma_device_conf static ma_result ma_close_stream__aaudio(ma_context* pContext, ma_AAudioStream* pStream) { + if (pStream == NULL) { + return MA_INVALID_ARGS; + } + return ma_result_from_aaudio(((MA_PFN_AAudioStream_close)pContext->aaudio.AAudioStream_close)(pStream)); } @@ -37901,20 +38165,36 @@ static ma_result ma_context_get_device_info__aaudio(ma_context* pContext, ma_dev return MA_SUCCESS; } +static ma_result ma_close_streams__aaudio(ma_device* pDevice) +{ + MA_ASSERT(pDevice != NULL); + + /* When re-routing, streams may have been closed and never re-opened. Hence the extra checks below. */ + if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { + ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); + pDevice->aaudio.pStreamCapture = NULL; + } + if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { + ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); + pDevice->aaudio.pStreamPlayback = NULL; + } + + return MA_SUCCESS; +} static ma_result ma_device_uninit__aaudio(ma_device* pDevice) { MA_ASSERT(pDevice != NULL); - if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex) { - ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); - pDevice->aaudio.pStreamCapture = NULL; + /* Wait for any rerouting to finish before attempting to close the streams. */ + ma_mutex_lock(&pDevice->aaudio.rerouteLock); + { + ma_close_streams__aaudio(pDevice); } + ma_mutex_unlock(&pDevice->aaudio.rerouteLock); - if (pDevice->type == ma_device_type_playback || pDevice->type == ma_device_type_duplex) { - ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); - pDevice->aaudio.pStreamPlayback = NULL; - } + /* Destroy re-routing lock. */ + ma_mutex_uninit(&pDevice->aaudio.rerouteLock); return MA_SUCCESS; } @@ -37966,7 +38246,7 @@ static ma_result ma_device_init_by_type__aaudio(ma_device* pDevice, const ma_dev return MA_SUCCESS; } -static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +static ma_result ma_device_init_streams__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) { ma_result result; @@ -37999,6 +38279,25 @@ static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_conf return MA_SUCCESS; } +static ma_result ma_device_init__aaudio(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) +{ + ma_result result; + + MA_ASSERT(pDevice != NULL); + + result = ma_device_init_streams__aaudio(pDevice, pConfig, pDescriptorPlayback, pDescriptorCapture); + if (result != MA_SUCCESS) { + return result; + } + + result = ma_mutex_init(&pDevice->aaudio.rerouteLock); + if (result != MA_SUCCESS) { + return result; + } + + return MA_SUCCESS; +} + static ma_result ma_device_start_stream__aaudio(ma_device* pDevice, ma_AAudioStream* pStream) { ma_aaudio_result_t resultAA; @@ -38006,12 +38305,16 @@ static ma_result ma_device_start_stream__aaudio(ma_device* pDevice, ma_AAudioStr MA_ASSERT(pDevice != NULL); + if (pStream == NULL) { + return MA_INVALID_ARGS; + } + resultAA = ((MA_PFN_AAudioStream_requestStart)pDevice->pContext->aaudio.AAudioStream_requestStart)(pStream); if (resultAA != MA_AAUDIO_OK) { return ma_result_from_aaudio(resultAA); } - /* Do we actually need to wait for the device to transition into it's started state? */ + /* Do we actually need to wait for the device to transition into its started state? */ /* The device should be in either a starting or started state. If it's not set to started we need to wait for it to transition. It should go from starting to started. */ currentState = ((MA_PFN_AAudioStream_getState)pDevice->pContext->aaudio.AAudioStream_getState)(pStream); @@ -38038,6 +38341,10 @@ static ma_result ma_device_stop_stream__aaudio(ma_device* pDevice, ma_AAudioStre MA_ASSERT(pDevice != NULL); + if (pStream == NULL) { + return MA_INVALID_ARGS; + } + /* From the AAudio documentation: @@ -38123,22 +38430,20 @@ static ma_result ma_device_stop__aaudio(ma_device* pDevice) static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type deviceType) { ma_result result; + int32_t retries = 0; MA_ASSERT(pDevice != NULL); - /* The first thing to do is close the streams. */ - if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex) { - ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamCapture); - pDevice->aaudio.pStreamCapture = NULL; - } - - if (deviceType == ma_device_type_playback || deviceType == ma_device_type_duplex) { - ma_close_stream__aaudio(pDevice->pContext, (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback); - pDevice->aaudio.pStreamPlayback = NULL; - } - - /* Now we need to reinitialize each streams. The hardest part with this is just filling output the config and descriptors. */ + /* + TODO: Stop retrying if main thread is about to uninit device. + */ + ma_mutex_lock(&pDevice->aaudio.rerouteLock); { +error_disconnected: + /* The first thing to do is close the streams. */ + ma_close_streams__aaudio(pDevice); + + /* Now we need to reinitialize each streams. The hardest part with this is just filling output the config and descriptors. */ ma_device_config deviceConfig; ma_device_descriptor descriptorPlayback; ma_device_descriptor descriptorCapture; @@ -38187,15 +38492,17 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev descriptorPlayback.periodCount = deviceConfig.periods; } - result = ma_device_init__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); + result = ma_device_init_streams__aaudio(pDevice, &deviceConfig, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { - return result; + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to create stream after route change."); + goto done; } result = ma_device_post_init(pDevice, deviceType, &descriptorPlayback, &descriptorCapture); if (result != MA_SUCCESS) { - ma_device_uninit__aaudio(pDevice); - return result; + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_WARNING, "[AAudio] Failed to initialize device after route change."); + ma_close_streams__aaudio(pDevice); + goto done; } /* We'll only ever do this in response to a reroute. */ @@ -38204,14 +38511,29 @@ static ma_result ma_device_reinit__aaudio(ma_device* pDevice, ma_device_type dev /* If the device is started, start the streams. Maybe make this configurable? */ if (ma_device_get_state(pDevice) == ma_device_state_started) { if (pDevice->aaudio.noAutoStartAfterReroute == MA_FALSE) { - ma_device_start__aaudio(pDevice); + result = ma_device_start__aaudio(pDevice); + if (result != MA_SUCCESS) { + /* We got disconnected! Retry a few times, until we find a connected device! */ + retries += 1; + if (retries <= 3) { + ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change, retrying(%d)", retries); + goto error_disconnected; + } + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[AAudio] Failed to start stream after route change."); + goto done; + } } else { ma_device_stop(pDevice); /* Do a full device stop so we set internal state correctly. */ } } - - return MA_SUCCESS; + + result = MA_SUCCESS; } +done: + /* Re-routing done */ + ma_mutex_unlock(&pDevice->aaudio.rerouteLock); + + return result; } static ma_result ma_device_get_info__aaudio(ma_device* pDevice, ma_device_type type, ma_device_info* pDeviceInfo) @@ -38222,12 +38544,12 @@ static ma_result ma_device_get_info__aaudio(ma_device* pDevice, ma_device_type t MA_ASSERT(type != ma_device_type_duplex); MA_ASSERT(pDeviceInfo != NULL); - if (type == ma_device_type_playback) { + if (type == ma_device_type_capture) { pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamCapture; pDeviceInfo->id.aaudio = pDevice->capture.id.aaudio; ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_CAPTURE_DEVICE_NAME, (size_t)-1); /* Only supporting default devices. */ } - if (type == ma_device_type_capture) { + if (type == ma_device_type_playback) { pStream = (ma_AAudioStream*)pDevice->aaudio.pStreamPlayback; pDeviceInfo->id.aaudio = pDevice->playback.id.aaudio; ma_strncpy_s(pDeviceInfo->name, sizeof(pDeviceInfo->name), MA_DEFAULT_PLAYBACK_DEVICE_NAME, (size_t)-1); /* Only supporting default devices. */ @@ -38260,6 +38582,7 @@ static ma_result ma_context_uninit__aaudio(ma_context* pContext) static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) { +#if !defined(MA_NO_RUNTIME_LINKING) size_t i; const char* libNames[] = { "libaaudio.so" @@ -38305,7 +38628,39 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_getFramesPerBurst"); pContext->aaudio.AAudioStream_requestStart = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_requestStart"); pContext->aaudio.AAudioStream_requestStop = (ma_proc)ma_dlsym(ma_context_get_log(pContext), pContext->aaudio.hAAudio, "AAudioStream_requestStop"); - +#else + pContext->aaudio.AAudio_createStreamBuilder = (ma_proc)AAudio_createStreamBuilder; + pContext->aaudio.AAudioStreamBuilder_delete = (ma_proc)AAudioStreamBuilder_delete; + pContext->aaudio.AAudioStreamBuilder_setDeviceId = (ma_proc)AAudioStreamBuilder_setDeviceId; + pContext->aaudio.AAudioStreamBuilder_setDirection = (ma_proc)AAudioStreamBuilder_setDirection; + pContext->aaudio.AAudioStreamBuilder_setSharingMode = (ma_proc)AAudioStreamBuilder_setSharingMode; + pContext->aaudio.AAudioStreamBuilder_setFormat = (ma_proc)AAudioStreamBuilder_setFormat; + pContext->aaudio.AAudioStreamBuilder_setChannelCount = (ma_proc)AAudioStreamBuilder_setChannelCount; + pContext->aaudio.AAudioStreamBuilder_setSampleRate = (ma_proc)AAudioStreamBuilder_setSampleRate; + pContext->aaudio.AAudioStreamBuilder_setBufferCapacityInFrames = (ma_proc)AAudioStreamBuilder_setBufferCapacityInFrames; + pContext->aaudio.AAudioStreamBuilder_setFramesPerDataCallback = (ma_proc)AAudioStreamBuilder_setFramesPerDataCallback; + pContext->aaudio.AAudioStreamBuilder_setDataCallback = (ma_proc)AAudioStreamBuilder_setDataCallback; + pContext->aaudio.AAudioStreamBuilder_setErrorCallback = (ma_proc)AAudioStreamBuilder_setErrorCallback; + pContext->aaudio.AAudioStreamBuilder_setPerformanceMode = (ma_proc)AAudioStreamBuilder_setPerformanceMode; + pContext->aaudio.AAudioStreamBuilder_setUsage = (ma_proc)AAudioStreamBuilder_setUsage; + pContext->aaudio.AAudioStreamBuilder_setContentType = (ma_proc)AAudioStreamBuilder_setContentType; + pContext->aaudio.AAudioStreamBuilder_setInputPreset = (ma_proc)AAudioStreamBuilder_setInputPreset; + #if defined(__ANDROID_API__) && __ANDROID_API__ >= 29 + pContext->aaudio.AAudioStreamBuilder_setAllowedCapturePolicy = (ma_proc)AAudioStreamBuilder_setAllowedCapturePolicy; + #endif + pContext->aaudio.AAudioStreamBuilder_openStream = (ma_proc)AAudioStreamBuilder_openStream; + pContext->aaudio.AAudioStream_close = (ma_proc)AAudioStream_close; + pContext->aaudio.AAudioStream_getState = (ma_proc)AAudioStream_getState; + pContext->aaudio.AAudioStream_waitForStateChange = (ma_proc)AAudioStream_waitForStateChange; + pContext->aaudio.AAudioStream_getFormat = (ma_proc)AAudioStream_getFormat; + pContext->aaudio.AAudioStream_getChannelCount = (ma_proc)AAudioStream_getChannelCount; + pContext->aaudio.AAudioStream_getSampleRate = (ma_proc)AAudioStream_getSampleRate; + pContext->aaudio.AAudioStream_getBufferCapacityInFrames = (ma_proc)AAudioStream_getBufferCapacityInFrames; + pContext->aaudio.AAudioStream_getFramesPerDataCallback = (ma_proc)AAudioStream_getFramesPerDataCallback; + pContext->aaudio.AAudioStream_getFramesPerBurst = (ma_proc)AAudioStream_getFramesPerBurst; + pContext->aaudio.AAudioStream_requestStart = (ma_proc)AAudioStream_requestStart; + pContext->aaudio.AAudioStream_requestStop = (ma_proc)AAudioStream_requestStop; +#endif pCallbacks->onContextInit = ma_context_init__aaudio; pCallbacks->onContextUninit = ma_context_uninit__aaudio; @@ -38343,6 +38698,7 @@ static ma_result ma_context_init__aaudio(ma_context* pContext, const ma_context_ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) { + ma_result result; ma_device* pDevice; MA_ASSERT(pJob != NULL); @@ -38351,7 +38707,18 @@ static ma_result ma_job_process__device__aaudio_reroute(ma_job* pJob) MA_ASSERT(pDevice != NULL); /* Here is where we need to reroute the device. To do this we need to uninitialize the stream and reinitialize it. */ - return ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); + result = ma_device_reinit__aaudio(pDevice, (ma_device_type)pJob->data.device.aaudio.reroute.deviceType); + if (result != MA_SUCCESS) { + /* + Getting here means we failed to reroute the device. The best thing I can think of here is to + just stop the device. + */ + ma_log_post(ma_device_get_log(pDevice), MA_LOG_LEVEL_ERROR, "[AAudio] Stopping device due to reroute failure."); + ma_device_stop(pDevice); + return result; + } + + return MA_SUCCESS; } #else /* Getting here means there is no AAudio backend so we need a no-op job implementation. */ @@ -39637,6 +40004,10 @@ Web Audio Backend #if (__EMSCRIPTEN_major__ > 3) || (__EMSCRIPTEN_major__ == 3 && (__EMSCRIPTEN_minor__ > 1 || (__EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ >= 32))) #include #define MA_SUPPORT_AUDIO_WORKLETS + + #if (__EMSCRIPTEN_major__ > 3) || (__EMSCRIPTEN_major__ == 3 && (__EMSCRIPTEN_minor__ > 1 || (__EMSCRIPTEN_minor__ == 1 && __EMSCRIPTEN_tiny__ >= 70))) + #define MA_SUPPORT_AUDIO_WORKLETS_VARIABLE_BUFFER_SIZE + #endif #endif /* @@ -39648,7 +40019,7 @@ TODO: Version 0.12: Swap this logic around so that AudioWorklets are used by def /* The thread stack size must be a multiple of 16. */ #ifndef MA_AUDIO_WORKLETS_THREAD_STACK_SIZE -#define MA_AUDIO_WORKLETS_THREAD_STACK_SIZE 16384 +#define MA_AUDIO_WORKLETS_THREAD_STACK_SIZE 131072 #endif #if defined(MA_USE_AUDIO_WORKLETS) @@ -39774,12 +40145,14 @@ static ma_result ma_device_uninit__webaudio(ma_device* pDevice) #if defined(MA_USE_AUDIO_WORKLETS) { EM_ASM({ - var device = miniaudio.get_device_by_index($0); + var device = window.miniaudio.get_device_by_index($0); if (device.streamNode !== undefined) { device.streamNode.disconnect(); device.streamNode = undefined; } + + device.pDevice = undefined; }, pDevice->webaudio.deviceIndex); emscripten_destroy_web_audio_node(pDevice->webaudio.audioWorklet); @@ -39789,7 +40162,7 @@ static ma_result ma_device_uninit__webaudio(ma_device* pDevice) #else { EM_ASM({ - var device = miniaudio.get_device_by_index($0); + var device = window.miniaudio.get_device_by_index($0); /* Make sure all nodes are disconnected and marked for collection. */ if (device.scriptNode !== undefined) { @@ -39816,7 +40189,7 @@ static ma_result ma_device_uninit__webaudio(ma_device* pDevice) /* Clean up the device on the JS side. */ EM_ASM({ - miniaudio.untrack_device_by_index($0); + window.miniaudio.untrack_device_by_index($0); }, pDevice->webaudio.deviceIndex); ma_free(pDevice->webaudio.pIntermediaryBuffer, &pDevice->pContext->allocationCallbacks); @@ -39882,10 +40255,6 @@ static EM_BOOL ma_audio_worklet_process_callback__webaudio(int inputCount, const (void)paramCount; (void)pParams; - if (ma_device_get_state(pDevice) != ma_device_state_started) { - return EM_TRUE; - } - /* The Emscripten documentation says that it'll always be 128 frames being passed in. Hard coding it like that feels like a very bad idea to me. Even if it's hard coded in the backend, the API and documentation should always refer @@ -39894,7 +40263,20 @@ static EM_BOOL ma_audio_worklet_process_callback__webaudio(int inputCount, const Unfortunately the audio data is not interleaved so we'll need to convert it before we give the data to miniaudio for further processing. */ - frameCount = 128; + if (pDevice->type == ma_device_type_playback) { + frameCount = pDevice->playback.internalPeriodSizeInFrames; + } else { + frameCount = pDevice->capture.internalPeriodSizeInFrames; + } + + if (ma_device_get_state(pDevice) != ma_device_state_started) { + /* Fill the output buffer with zero to avoid a noise sound */ + for (int i = 0; i < outputCount; i += 1) { + MA_ZERO_MEMORY(pOutputs[i].data, pOutputs[i].numberOfChannels * frameCount * sizeof(float)); + } + + return EM_TRUE; + } if (inputCount > 0) { /* Input data needs to be interleaved before we hand it to the client. */ @@ -39949,7 +40331,7 @@ static void ma_audio_worklet_processor_created__webaudio(EMSCRIPTEN_WEBAUDIO_T a count from MediaStreamAudioSourceNode (what we use for capture)? The only way to have control is to configure an output channel count on the capture side. This is slightly confusing for capture mode because intuitively you wouldn't actually connect an output to an input-only node, but this is what we'll have to do in order to have - proper control over the channel count. In the capture case, we'll have to output silence to it's output node. + proper control over the channel count. In the capture case, we'll have to output silence to its output node. */ if (pParameters->pConfig->deviceType == ma_device_type_capture) { channels = (int)((pParameters->pDescriptorCapture->channels > 0) ? pParameters->pDescriptorCapture->channels : MA_DEFAULT_CHANNELS); @@ -39972,7 +40354,15 @@ static void ma_audio_worklet_processor_created__webaudio(EMSCRIPTEN_WEBAUDIO_T a Now that we know the channel count to use we can allocate the intermediary buffer. The intermediary buffer is used for interleaving and deinterleaving. */ - intermediaryBufferSizeInFrames = 128; + #if defined(MA_SUPPORT_AUDIO_WORKLETS_VARIABLE_BUFFER_SIZE) + { + intermediaryBufferSizeInFrames = (size_t)emscripten_audio_context_quantum_size(audioContext); + } + #else + { + intermediaryBufferSizeInFrames = 128; + } + #endif pParameters->pDevice->webaudio.pIntermediaryBuffer = (float*)ma_malloc(intermediaryBufferSizeInFrames * (ma_uint32)channels * sizeof(float), &pParameters->pDevice->pContext->allocationCallbacks); if (pParameters->pDevice->webaudio.pIntermediaryBuffer == NULL) { @@ -39981,7 +40371,6 @@ static void ma_audio_worklet_processor_created__webaudio(EMSCRIPTEN_WEBAUDIO_T a return; } - pParameters->pDevice->webaudio.audioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "miniaudio", &audioWorkletOptions, &ma_audio_worklet_process_callback__webaudio, pParameters->pDevice); /* With the audio worklet initialized we can now attach it to the graph. */ @@ -40121,7 +40510,6 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co /* It's not clear if this can return an error. None of the tests in the Emscripten repository check for this, so neither am I for now. */ pDevice->webaudio.audioContext = emscripten_create_audio_context(&audioContextAttributes); - /* With the context created we can now create the worklet. We can only have a single worklet per audio context which means we'll need to craft this appropriately to handle duplex devices correctly. @@ -40170,11 +40558,12 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co /* We need to add an entry to the miniaudio.devices list on the JS side so we can do some JS/C interop. */ pDevice->webaudio.deviceIndex = EM_ASM_INT({ - return miniaudio.track_device({ + return window.miniaudio.track_device({ webaudio: emscriptenGetAudioObject($0), - state: 1 /* 1 = ma_device_state_stopped */ + state: 1, /* 1 = ma_device_state_stopped */ + pDevice: $1 }); - }, pDevice->webaudio.audioContext); + }, pDevice->webaudio.audioContext, pDevice); return MA_SUCCESS; } @@ -40186,7 +40575,7 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co ma_uint32 sampleRate; ma_uint32 periodSizeInFrames; - /* The channel count will depend on the device type. If it's a capture, use it's, otherwise use the playback side. */ + /* The channel count will depend on the device type. If it's a capture, use its, otherwise use the playback side. */ if (pConfig->deviceType == ma_device_type_capture) { channels = (pDescriptorCapture->channels > 0) ? pDescriptorCapture->channels : MA_DEFAULT_CHANNELS; } else { @@ -40255,11 +40644,11 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co /* The node processing callback. */ device.scriptNode.onaudioprocess = function(e) { if (device.intermediaryBufferView == null || device.intermediaryBufferView.length == 0) { - device.intermediaryBufferView = new Float32Array(Module.HEAPF32.buffer, pIntermediaryBuffer, bufferSize * channels); + device.intermediaryBufferView = new Float32Array(HEAPF32.buffer, pIntermediaryBuffer, bufferSize * channels); } /* Do the capture side first. */ - if (deviceType == miniaudio.device_type.capture || deviceType == miniaudio.device_type.duplex) { + if (deviceType == window.miniaudio.device_type.capture || deviceType == window.miniaudio.device_type.duplex) { /* The data must be interleaved before being processed miniaudio. */ for (var iChannel = 0; iChannel < channels; iChannel += 1) { var inputBuffer = e.inputBuffer.getChannelData(iChannel); @@ -40273,7 +40662,7 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co _ma_device_process_pcm_frames_capture__webaudio(pDevice, bufferSize, pIntermediaryBuffer); } - if (deviceType == miniaudio.device_type.playback || deviceType == miniaudio.device_type.duplex) { + if (deviceType == window.miniaudio.device_type.playback || deviceType == window.miniaudio.device_type.duplex) { _ma_device_process_pcm_frames_playback__webaudio(pDevice, bufferSize, pIntermediaryBuffer); for (var iChannel = 0; iChannel < e.outputBuffer.numberOfChannels; ++iChannel) { @@ -40293,7 +40682,7 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co }; /* Now we need to connect our node to the graph. */ - if (deviceType == miniaudio.device_type.capture || deviceType == miniaudio.device_type.duplex) { + if (deviceType == window.miniaudio.device_type.capture || deviceType == window.miniaudio.device_type.duplex) { navigator.mediaDevices.getUserMedia({audio:true, video:false}) .then(function(stream) { device.streamNode = device.webaudio.createMediaStreamSource(stream); @@ -40305,13 +40694,13 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co }); } - if (deviceType == miniaudio.device_type.playback) { + if (deviceType == window.miniaudio.device_type.playback) { device.scriptNode.connect(device.webaudio.destination); } device.pDevice = pDevice; - return miniaudio.track_device(device); + return window.miniaudio.track_device(device); }, pConfig->deviceType, channels, sampleRate, periodSizeInFrames, pDevice->webaudio.pIntermediaryBuffer, pDevice); if (deviceIndex < 0) { @@ -40321,7 +40710,7 @@ static ma_result ma_device_init__webaudio(ma_device* pDevice, const ma_device_co pDevice->webaudio.deviceIndex = deviceIndex; /* Grab the sample rate from the audio context directly. */ - sampleRate = (ma_uint32)EM_ASM_INT({ return miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); + sampleRate = (ma_uint32)EM_ASM_INT({ return window.miniaudio.get_device_by_index($0).webaudio.sampleRate; }, deviceIndex); if (pDescriptorCapture != NULL) { pDescriptorCapture->format = ma_format_f32; @@ -40351,9 +40740,9 @@ static ma_result ma_device_start__webaudio(ma_device* pDevice) MA_ASSERT(pDevice != NULL); EM_ASM({ - var device = miniaudio.get_device_by_index($0); + var device = window.miniaudio.get_device_by_index($0); device.webaudio.resume(); - device.state = miniaudio.device_state.started; + device.state = window.miniaudio.device_state.started; }, pDevice->webaudio.deviceIndex); return MA_SUCCESS; @@ -40373,9 +40762,9 @@ static ma_result ma_device_stop__webaudio(ma_device* pDevice) do any kind of explicit draining. */ EM_ASM({ - var device = miniaudio.get_device_by_index($0); + var device = window.miniaudio.get_device_by_index($0); device.webaudio.suspend(); - device.state = miniaudio.device_state.stopped; + device.state = window.miniaudio.device_state.stopped; }, pDevice->webaudio.deviceIndex); ma_device__on_notification_stopped(pDevice); @@ -40393,6 +40782,10 @@ static ma_result ma_context_uninit__webaudio(ma_context* pContext) /* Remove the global miniaudio object from window if there are no more references to it. */ EM_ASM({ if (typeof(window.miniaudio) !== 'undefined') { + miniaudio.unlock_event_types.map(function(event_type) { + document.removeEventListener(event_type, miniaudio.unlock, true); + }); + window.miniaudio.referenceCount -= 1; if (window.miniaudio.referenceCount === 0) { delete window.miniaudio; @@ -40434,6 +40827,7 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex window.miniaudio.device_state.started = $4; /* Device cache for mapping devices to indexes for JavaScript/C interop. */ + let miniaudio = window.miniaudio; miniaudio.devices = []; miniaudio.track_device = function(device) { @@ -40485,13 +40879,13 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex var device = miniaudio.devices[i]; if (device != null && device.webaudio != null && - device.state === window.miniaudio.device_state.started) { + device.state === miniaudio.device_state.started) { device.webaudio.resume().then(() => { - Module._ma_device__on_notification_unlocked(device.pDevice); - }, - (error) => {console.error("Failed to resume audiocontext", error); - }); + _ma_device__on_notification_unlocked(device.pDevice); + }, + (error) => {console.error("Failed to resume audiocontext", error); + }); } } miniaudio.unlock_event_types.map(function(event_type) { @@ -40527,7 +40921,7 @@ static ma_result ma_context_init__webaudio(ma_context* pContext, const ma_contex return MA_SUCCESS; } -#endif /* Web Audio */ +#endif /* MA_HAS_WEBAUDIO */ @@ -40806,7 +41200,7 @@ MA_API ma_result ma_device_post_init(ma_device* pDevice, ma_device_type deviceTy ma_device_info deviceInfo; if (deviceType == ma_device_type_capture || deviceType == ma_device_type_duplex || deviceType == ma_device_type_loopback) { - result = ma_device_get_info(pDevice, (deviceType == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, &deviceInfo); + result = ma_device_get_info(pDevice, ma_device_type_capture, &deviceInfo); if (result == MA_SUCCESS) { ma_strncpy_s(pDevice->capture.name, sizeof(pDevice->capture.name), deviceInfo.name, (size_t)-1); } else { @@ -40853,7 +41247,7 @@ static ma_thread_result MA_THREADCALL ma_worker_thread(void* pData) #endif /* - When the device is being initialized it's initial state is set to ma_device_state_uninitialized. Before returning from + When the device is being initialized its initial state is set to ma_device_state_uninitialized. Before returning from ma_device_init(), the state needs to be set to something valid. In miniaudio the device's default state immediately after initialization is stopped, so therefore we need to mark the device as such. miniaudio will wait on the worker thread to signal an event to know when the worker thread is ready for action. @@ -41198,6 +41592,24 @@ MA_API ma_result ma_device_job_thread_next(ma_device_job_thread* pJobThread, ma_ } +MA_API ma_bool32 ma_device_id_equal(const ma_device_id* pA, const ma_device_id* pB) +{ + size_t i; + + if (pA == NULL || pB == NULL) { + return MA_FALSE; + } + + for (i = 0; i < sizeof(ma_device_id); i += 1) { + if (((const char*)pA)[i] != ((const char*)pB)[i]) { + return MA_FALSE; + } + } + + return MA_TRUE; +} + + MA_API ma_context_config ma_context_config_init(void) { @@ -41971,7 +42383,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC return result; } - /* Wait for the worker thread to put the device into it's stopped state for real. */ + /* Wait for the worker thread to put the device into its stopped state for real. */ ma_event_wait(&pDevice->stopEvent); MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); } else { @@ -41997,7 +42409,7 @@ MA_API ma_result ma_device_init(ma_context* pContext, const ma_device_config* pC ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, "[%s]\n", ma_get_backend_name(pDevice->pContext->backend)); if (pDevice->type == ma_device_type_capture || pDevice->type == ma_device_type_duplex || pDevice->type == ma_device_type_loopback) { char name[MA_MAX_DEVICE_NAME_LENGTH + 1]; - ma_device_get_name(pDevice, (pDevice->type == ma_device_type_loopback) ? ma_device_type_playback : ma_device_type_capture, name, sizeof(name), NULL); + ma_device_get_name(pDevice, ma_device_type_capture, name, sizeof(name), NULL); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " %s (%s)\n", name, "Capture"); ma_log_postf(ma_device_get_log(pDevice), MA_LOG_LEVEL_INFO, " Format: %s -> %s\n", ma_get_format_name(pDevice->capture.internalFormat), ma_get_format_name(pDevice->capture.format)); @@ -42250,6 +42662,17 @@ MA_API ma_result ma_device_get_info(ma_device* pDevice, ma_device_type type, ma_ if (type == ma_device_type_playback) { return ma_context_get_device_info(pDevice->pContext, type, pDevice->playback.pID, pDeviceInfo); } else { + /* + Here we're getting the capture side, which is the branch we'll be entering for a loopback + device, since loopback is capturing. However, if the device is using the default device ID, + it won't get the correct information because it'll think we're asking for the default + capture device, where in fact for loopback we want the default *playback* device. We'll do + a bit of a hack here to make sure we get the correct info. + */ + if (pDevice->type == ma_device_type_loopback && pDevice->capture.pID == NULL) { + type = ma_device_type_playback; + } + return ma_context_get_device_info(pDevice->pContext, type, pDevice->capture.pID, pDeviceInfo); } } @@ -42311,6 +42734,15 @@ MA_API ma_result ma_device_start(ma_device* pDevice) ma_mutex_lock(&pDevice->startStopLock); { + /* + We need to check again if the device is in a started state because it's possible for one thread to have started the device + while another was waiting on the mutex. + */ + if (ma_device_get_state(pDevice) == ma_device_state_started) { + ma_mutex_unlock(&pDevice->startStopLock); + return MA_SUCCESS; /* Already started. */ + } + /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a stopped or paused state. */ MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_stopped); @@ -42371,6 +42803,15 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) ma_mutex_lock(&pDevice->startStopLock); { + /* + We need to check again if the device is in a stopped state because it's possible for one thread to have stopped the device + while another was waiting on the mutex. + */ + if (ma_device_get_state(pDevice) == ma_device_state_stopped) { + ma_mutex_unlock(&pDevice->startStopLock); + return MA_SUCCESS; /* Already stopped. */ + } + /* Starting and stopping are wrapped in a mutex which means we can assert that the device is in a started or paused state. */ MA_ASSERT(ma_device_get_state(pDevice) == ma_device_state_started); @@ -42389,7 +42830,7 @@ MA_API ma_result ma_device_stop(ma_device* pDevice) } else { /* Synchronous backends. The stop callback is always called from the worker thread. Do not call the stop callback here. If - the backend is implementing it's own audio thread loop we'll need to wake it up if required. Note that we need to make + the backend is implementing its own audio thread loop we'll need to wake it up if required. Note that we need to make sure the state of the device is *not* playing right now, which it shouldn't be since we set it above. This is super important though, so I'm asserting it here as well for extra safety in case we accidentally change something later. */ @@ -42506,6 +42947,15 @@ MA_API ma_result ma_device_handle_backend_data_callback(ma_device* pDevice, void return MA_INVALID_ARGS; } + /* + There is an assert deeper in the code that checks that frameCount > 0. Since this is a public facing + API we'll need to check for that here. I've had reports that AAudio can sometimes post a frame count + of 0. + */ + if (frameCount == 0) { + return MA_INVALID_ARGS; + } + if (pDevice->type == ma_device_type_duplex) { if (pInput != NULL) { ma_device__handle_duplex_callback_capture(pDevice, frameCount, pInput, &pDevice->duplexRB.rb); @@ -42580,7 +43030,7 @@ MA_API ma_uint32 ma_calculate_buffer_size_in_milliseconds_from_frames(ma_uint32 return 0; } - return bufferSizeInFrames*1000 / sampleRate; + return (bufferSizeInFrames*1000 + (sampleRate - 1)) / sampleRate; } MA_API ma_uint32 ma_calculate_buffer_size_in_frames_from_milliseconds(ma_uint32 bufferSizeInMilliseconds, ma_uint32 sampleRate) @@ -47408,7 +47858,7 @@ static ma_result ma_bpf_get_heap_layout(const ma_bpf_config* pConfig, ma_bpf_hea return MA_INVALID_ARGS; } - bpf2Count = pConfig->channels / 2; + bpf2Count = pConfig->order / 2; pHeapLayout->sizeInBytes = 0; @@ -49466,7 +49916,7 @@ MA_API float ma_fader_get_current_volume(const ma_fader* pFader) } else if ((ma_uint64)pFader->cursorInFrames >= pFader->lengthInFrames) { /* Safe case because the < 0 case was checked above. */ return pFader->volumeEnd; } else { - /* The cursor is somewhere inside the fading period. We can figure this out with a simple linear interpoluation between volumeBeg and volumeEnd based on our cursor position. */ + /* The cursor is somewhere inside the fading period. We can figure this out with a simple linear interpolation between volumeBeg and volumeEnd based on our cursor position. */ return ma_mix_f32_fast(pFader->volumeBeg, pFader->volumeEnd, (ma_uint32)pFader->cursorInFrames / (float)((ma_uint32)pFader->lengthInFrames)); /* Safe cast to uint32 because we clamp it in ma_fader_process_pcm_frames(). */ } } @@ -49689,9 +50139,9 @@ static float ma_attenuation_exponential(float distance, float minDistance, float /* -Dopper Effect calculation taken from the OpenAL spec, with two main differences: +Doppler Effect calculation taken from the OpenAL spec, with two main differences: - 1) The source to listener vector will have already been calcualted at an earlier step so we can + 1) The source to listener vector will have already been calculated at an earlier step so we can just use that directly. We need only the position of the source relative to the origin. 2) We don't scale by a frequency because we actually just want the ratio which we'll plug straight @@ -49730,7 +50180,7 @@ static void ma_get_default_channel_map_for_spatializer(ma_channel* pChannelMap, Special case for stereo. Want to default the left and right speakers to side left and side right so that they're facing directly down the X axis rather than slightly forward. Not doing this will result in sounds being quieter when behind the listener. This might - actually be good for some scenerios, but I don't think it's an appropriate default because + actually be good for some scenarios, but I don't think it's an appropriate default because it can be a bit unexpected. */ if (channelCount == 2) { @@ -50064,7 +50514,7 @@ MA_API ma_spatializer_config ma_spatializer_config_init(ma_uint32 channelsIn, ma config.maxDistance = MA_FLT_MAX; config.rolloff = 1; config.coneInnerAngleInRadians = 6.283185f; /* 360 degrees. */ - config.coneOuterAngleInRadians = 6.283185f; /* 360 degress. */ + config.coneOuterAngleInRadians = 6.283185f; /* 360 degrees. */ config.coneOuterGain = 0.0f; config.dopplerFactor = 1; config.directionalAttenuationFactor = 1; @@ -50298,7 +50748,7 @@ static float ma_calculate_angular_gain(ma_vec3f dirA, ma_vec3f dirB, float coneI To do cone attenuation, I'm just using the same math that we'd use to implement a basic spotlight in OpenGL. We just need to get the direction from the source to the listener and then do a dot product against that and the direction of the spotlight. Then we just compare that dot product against the cosine of the inner and outer - angles. If the dot product is greater than the the outer angle, we just use coneOuterGain. If it's less than + angles. If the dot product is greater than the outer angle, we just use coneOuterGain. If it's less than the inner angle, we just use a gain of 1. Otherwise we linearly interpolate between 1 and coneOuterGain. */ if (coneInnerAngleInRadians < 6.283185f) { @@ -50368,7 +50818,7 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, ma_vec3f relativePosNormalized; ma_vec3f relativePos; /* The position relative to the listener. */ ma_vec3f relativeDir; /* The direction of the sound, relative to the listener. */ - ma_vec3f listenerVel; /* The volocity of the listener. For doppler pitch calculation. */ + ma_vec3f listenerVel; /* The velocity of the listener. For doppler pitch calculation. */ float speedOfSound; float distance = 0; float gain = 1; @@ -50449,11 +50899,11 @@ MA_API ma_result ma_spatializer_process_pcm_frames(ma_spatializer* pSpatializer, To do cone attenuation, I'm just using the same math that we'd use to implement a basic spotlight in OpenGL. We just need to get the direction from the source to the listener and then do a dot product against that and the direction of the spotlight. Then we just compare that dot product against the cosine of the inner and outer - angles. If the dot product is greater than the the outer angle, we just use coneOuterGain. If it's less than + angles. If the dot product is greater than the outer angle, we just use coneOuterGain. If it's less than the inner angle, we just use a gain of 1. Otherwise we linearly interpolate between 1 and coneOuterGain. */ if (distance > 0) { - /* Source anglular gain. */ + /* Source angular gain. */ float spatializerConeInnerAngle; float spatializerConeOuterAngle; float spatializerConeOuterGain; @@ -50965,7 +51415,7 @@ MA_API void ma_spatializer_get_relative_position_and_direction(const ma_spatiali listenerDirection = ma_spatializer_listener_get_direction(pListener); /* - We need to calcualte the right vector from our forward and up vectors. This is done with + We need to calculate the right vector from our forward and up vectors. This is done with a cross product. */ axisZ = ma_vec3f_normalize(listenerDirection); /* Normalization required here because we can't trust the caller. */ @@ -51111,7 +51561,7 @@ static ma_result ma_linear_resampler_set_rate_internal(ma_linear_resampler* pRes lpfConfig = ma_lpf_config_init(pResampler->config.format, pResampler->config.channels, lpfSampleRate, lpfCutoffFrequency, pResampler->config.lpfOrder); /* - If the resampler is alreay initialized we don't want to do a fresh initialization of the low-pass filter because it will result in the cached frames + If the resampler is already initialized we don't want to do a fresh initialization of the low-pass filter because it will result in the cached frames getting cleared. Instead we re-initialize the filter which will maintain any cached frames. */ if (isResamplerAlreadyInitialized) { @@ -51806,7 +52256,7 @@ MA_API ma_result ma_linear_resampler_get_expected_output_frame_count(const ma_li preliminaryInputFrameCount = (pResampler->inTimeInt + outputFrameCount*pResampler->inAdvanceInt ) + preliminaryInputFrameCountFromFrac; /* - If the total number of *whole* input frames that would be required to generate our preliminary output frame count is greather than + If the total number of *whole* input frames that would be required to generate our preliminary output frame count is greater than the amount of whole input frames we have available as input we need to *not* add an extra output frame as there won't be enough data to actually process. Otherwise we need to add the extra output frame. */ @@ -51844,7 +52294,7 @@ MA_API ma_result ma_linear_resampler_reset(ma_linear_resampler* pResampler) } } - /* The low pass filter needs to have it's cache reset. */ + /* The low pass filter needs to have its cache reset. */ ma_lpf_clear_cache(&pResampler->lpf); return MA_SUCCESS; @@ -52361,19 +52811,19 @@ static float ma_calculate_channel_position_rectangular_weight(ma_channel channel of contribution to apply to the side/left and back/left speakers, however, is a bit more complicated. Imagine the front/left speaker as emitting audio from two planes - the front plane and the left plane. You can think of the front/left - speaker emitting half of it's total volume from the front, and the other half from the left. Since part of it's volume is being emitted + speaker emitting half of its total volume from the front, and the other half from the left. Since part of its volume is being emitted from the left side, and the side/left and back/left channels also emit audio from the left plane, one would expect that they would receive some amount of contribution from front/left speaker. The amount of contribution depends on how many planes are shared between the two speakers. Note that in the examples below I've added a top/front/left speaker as an example just to show how the math works across 3 spatial dimensions. The first thing to do is figure out how each speaker's volume is spread over each of plane: - - front/left: 2 planes (front and left) = 1/2 = half it's total volume on each plane + - front/left: 2 planes (front and left) = 1/2 = half its total volume on each plane - side/left: 1 plane (left only) = 1/1 = entire volume from left plane - - back/left: 2 planes (back and left) = 1/2 = half it's total volume on each plane - - top/front/left: 3 planes (top, front and left) = 1/3 = one third it's total volume on each plane + - back/left: 2 planes (back and left) = 1/2 = half its total volume on each plane + - top/front/left: 3 planes (top, front and left) = 1/3 = one third its total volume on each plane - The amount of volume each channel contributes to each of it's planes is what controls how much it is willing to given and take to other + The amount of volume each channel contributes to each of its planes is what controls how much it is willing to given and take to other channels on the same plane. The volume that is willing to the given by one channel is multiplied by the volume that is willing to be taken by the other to produce the final contribution. */ @@ -52484,12 +52934,7 @@ static ma_channel_conversion_path ma_channel_map_get_conversion_path(const ma_ch ma_uint32 iChannelIn; ma_bool32 areAllChannelPositionsPresent = MA_TRUE; for (iChannelIn = 0; iChannelIn < channelsIn; ++iChannelIn) { - ma_bool32 isInputChannelPositionInOutput = MA_FALSE; - if (ma_channel_map_contains_channel_position(channelsOut, pChannelMapOut, ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn))) { - isInputChannelPositionInOutput = MA_TRUE; - break; - } - + ma_bool32 isInputChannelPositionInOutput = ma_channel_map_contains_channel_position(channelsOut, pChannelMapOut, ma_channel_map_get_channel(pChannelMapIn, channelsIn, iChannelIn)); if (!isInputChannelPositionInOutput) { areAllChannelPositionsPresent = MA_FALSE; break; @@ -52516,8 +52961,8 @@ static ma_result ma_channel_map_build_shuffle_table(const ma_channel* pChannelMa } /* - When building the shuffle table we just do a 1:1 mapping based on the first occurance of a channel. If the - input channel has more than one occurance of a channel position, the second one will be ignored. + When building the shuffle table we just do a 1:1 mapping based on the first occurrence of a channel. If the + input channel has more than one occurrence of a channel position, the second one will be ignored. */ for (iChannelOut = 0; iChannelOut < channelCountOut; iChannelOut += 1) { ma_channel channelOut; @@ -54812,7 +55257,7 @@ static ma_result ma_data_converter_process_pcm_frames__channels_first(ma_data_co Before doing any processing we need to determine how many frames we should try processing this iteration, for both input and output. The resampler requires us to perform format and channel conversion before passing any data into it. If we get our input count wrong, we'll - end up peforming redundant pre-processing. This isn't the end of the world, but it does + end up performing redundant pre-processing. This isn't the end of the world, but it does result in some inefficiencies proportionate to how far our estimates are off. If the resampler has a means to calculate exactly how much we'll need, we'll use that. @@ -55982,7 +56427,7 @@ MA_API const char* ma_channel_position_to_string(ma_channel channel) case MA_CHANNEL_LFE : return "CHANNEL_LFE"; case MA_CHANNEL_BACK_LEFT : return "CHANNEL_BACK_LEFT"; case MA_CHANNEL_BACK_RIGHT : return "CHANNEL_BACK_RIGHT"; - case MA_CHANNEL_FRONT_LEFT_CENTER : return "CHANNEL_FRONT_LEFT_CENTER "; + case MA_CHANNEL_FRONT_LEFT_CENTER : return "CHANNEL_FRONT_LEFT_CENTER"; case MA_CHANNEL_FRONT_RIGHT_CENTER: return "CHANNEL_FRONT_RIGHT_CENTER"; case MA_CHANNEL_BACK_CENTER : return "CHANNEL_BACK_CENTER"; case MA_CHANNEL_SIDE_LEFT : return "CHANNEL_SIDE_LEFT"; @@ -56287,13 +56732,9 @@ MA_API ma_result ma_rb_commit_read(ma_rb* pRB, size_t sizeInBytes) newReadOffsetLoopFlag ^= 0x80000000; } - ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetLoopFlag, newReadOffsetInBytes)); + ma_atomic_exchange_32(&pRB->encodedReadOffset, ma_rb__construct_offset(newReadOffsetInBytes, newReadOffsetLoopFlag)); - if (ma_rb_pointer_distance(pRB) == 0) { - return MA_AT_END; - } else { - return MA_SUCCESS; - } + return MA_SUCCESS; } MA_API ma_result ma_rb_acquire_write(ma_rb* pRB, size_t* pSizeInBytes, void** ppBufferOut) @@ -56373,13 +56814,9 @@ MA_API ma_result ma_rb_commit_write(ma_rb* pRB, size_t sizeInBytes) newWriteOffsetLoopFlag ^= 0x80000000; } - ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetLoopFlag, newWriteOffsetInBytes)); + ma_atomic_exchange_32(&pRB->encodedWriteOffset, ma_rb__construct_offset(newWriteOffsetInBytes, newWriteOffsetLoopFlag)); - if (ma_rb_pointer_distance(pRB) == 0) { - return MA_AT_END; - } else { - return MA_SUCCESS; - } + return MA_SUCCESS; } MA_API ma_result ma_rb_seek_read(ma_rb* pRB, size_t offsetInBytes) @@ -56602,6 +57039,16 @@ static ma_result ma_pcm_rb_data_source__on_read(ma_data_source* pDataSource, voi totalFramesRead += mappedFrameCount; } + /* + There is no notion of an "end" in a ring buffer. If we didn't have enough data to fill the requested frame + count we'll need to pad with silence. If we don't do this, totalFramesRead might equal 0 which will result + in the data source layer at a higher level translating this to MA_AT_END which is incorrect for a ring buffer. + */ + if (totalFramesRead < frameCount) { + ma_silence_pcm_frames(ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, pRB->format, pRB->channels), (frameCount - totalFramesRead), pRB->format, pRB->channels); + totalFramesRead = frameCount; + } + *pFramesRead = totalFramesRead; return MA_SUCCESS; } @@ -57150,6 +57597,10 @@ MA_API ma_result ma_data_source_init(const ma_data_source_config* pConfig, ma_da return MA_INVALID_ARGS; } + if (pConfig->vtable == NULL) { + return MA_INVALID_ARGS; + } + pDataSourceBase->vtable = pConfig->vtable; pDataSourceBase->rangeBegInFrames = MA_DATA_SOURCE_DEFAULT_RANGE_BEG; pDataSourceBase->rangeEndInFrames = MA_DATA_SOURCE_DEFAULT_RANGE_END; @@ -57200,6 +57651,58 @@ static ma_result ma_data_source_resolve_current(ma_data_source* pDataSource, ma_ return MA_SUCCESS; } +static ma_result ma_data_source_read_pcm_frames_from_backend(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) +{ + ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; + + MA_ASSERT(pDataSourceBase != NULL); + MA_ASSERT(pDataSourceBase->vtable != NULL); + MA_ASSERT(pDataSourceBase->vtable->onRead != NULL); + MA_ASSERT(pFramesRead != NULL); + + if (pFramesOut != NULL) { + return pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, pFramesRead); + } else { + /* + No output buffer. Probably seeking forward. Read and discard. Can probably optimize this in terms of + onSeek and onGetCursor, but need to keep in mind that the data source may not implement these functions. + */ + ma_result result; + ma_uint64 framesRead; + ma_format format; + ma_uint32 channels; + ma_uint64 discardBufferCapInFrames; + ma_uint8 pDiscardBuffer[4096]; + + result = ma_data_source_get_data_format(pDataSource, &format, &channels, NULL, NULL, 0); + if (result != MA_SUCCESS) { + return result; + } + + discardBufferCapInFrames = sizeof(pDiscardBuffer) / ma_get_bytes_per_frame(format, channels); + + framesRead = 0; + while (framesRead < frameCount) { + ma_uint64 framesReadThisIteration = 0; + ma_uint64 framesToRead = frameCount - framesRead; + if (framesToRead > discardBufferCapInFrames) { + framesToRead = discardBufferCapInFrames; + } + + result = pDataSourceBase->vtable->onRead(pDataSourceBase, pDiscardBuffer, framesToRead, &framesReadThisIteration); + if (result != MA_SUCCESS) { + return result; + } + + framesRead += framesReadThisIteration; + } + + *pFramesRead = framesRead; + + return MA_SUCCESS; + } +} + static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDataSource, void* pFramesOut, ma_uint64 frameCount, ma_uint64* pFramesRead) { ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; @@ -57215,9 +57718,11 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa return MA_INVALID_ARGS; } + MA_ASSERT(pDataSourceBase->vtable != NULL); + if ((pDataSourceBase->vtable->flags & MA_DATA_SOURCE_SELF_MANAGED_RANGE_AND_LOOP_POINT) != 0 || (pDataSourceBase->rangeEndInFrames == ~((ma_uint64)0) && (pDataSourceBase->loopEndInFrames == ~((ma_uint64)0) || loop == MA_FALSE))) { /* Either the data source is self-managing the range, or no range is set - just read like normal. The data source itself will tell us when the end is reached. */ - result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); + result = ma_data_source_read_pcm_frames_from_backend(pDataSource, pFramesOut, frameCount, &framesRead); } else { /* Need to clamp to within the range. */ ma_uint64 relativeCursor; @@ -57226,7 +57731,7 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa result = ma_data_source_get_cursor_in_pcm_frames(pDataSourceBase, &relativeCursor); if (result != MA_SUCCESS) { /* Failed to retrieve the cursor. Cannot read within a range or loop points. Just read like normal - this may happen for things like noise data sources where it doesn't really matter. */ - result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); + result = ma_data_source_read_pcm_frames_from_backend(pDataSource, pFramesOut, frameCount, &framesRead); } else { ma_uint64 rangeBeg; ma_uint64 rangeEnd; @@ -57254,7 +57759,7 @@ static ma_result ma_data_source_read_pcm_frames_within_range(ma_data_source* pDa MA_AT_END so the higher level function can know about it. */ if (frameCount > 0) { - result = pDataSourceBase->vtable->onRead(pDataSourceBase, pFramesOut, frameCount, &framesRead); + result = ma_data_source_read_pcm_frames_from_backend(pDataSource, pFramesOut, frameCount, &framesRead); } else { result = MA_AT_END; /* The cursor is sitting on the end of the range which means we're at the end. */ } @@ -57336,7 +57841,7 @@ MA_API ma_result ma_data_source_read_pcm_frames(ma_data_source* pDataSource, voi totalFramesProcessed += framesProcessed; /* - If we encounted an error from the read callback, make sure it's propagated to the caller. The caller may need to know whether or not MA_BUSY is returned which is + If we encountered an error from the read callback, make sure it's propagated to the caller. The caller may need to know whether or not MA_BUSY is returned which is not necessarily considered an error. */ if (result != MA_SUCCESS && result != MA_AT_END) { @@ -57427,7 +57932,7 @@ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, m ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; if (pDataSourceBase == NULL) { - return MA_SUCCESS; + return MA_INVALID_ARGS; } if (pDataSourceBase->vtable->onSeek == NULL) { @@ -57435,12 +57940,61 @@ MA_API ma_result ma_data_source_seek_to_pcm_frame(ma_data_source* pDataSource, m } if (frameIndex > pDataSourceBase->rangeEndInFrames) { - return MA_INVALID_OPERATION; /* Trying to seek to far forward. */ + return MA_INVALID_OPERATION; /* Trying to seek too far forward. */ } + MA_ASSERT(pDataSourceBase->vtable != NULL); + return pDataSourceBase->vtable->onSeek(pDataSource, pDataSourceBase->rangeBegInFrames + frameIndex); } +MA_API ma_result ma_data_source_seek_seconds(ma_data_source* pDataSource, float secondCount, float* pSecondsSeeked) +{ + ma_uint64 frameCount; + ma_uint64 framesSeeked = 0; + ma_uint32 sampleRate; + ma_result result; + + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0); + if (result != MA_SUCCESS) { + return result; + } + + /* We need PCM frames instead of seconds */ + frameCount = (ma_uint64)(secondCount * sampleRate); + + result = ma_data_source_seek_pcm_frames(pDataSource, frameCount, &framesSeeked); + + /* VC6 doesn't support division between unsigned 64-bit integer and floating point number. Signed integer needed. This shouldn't affect anything in practice */ + *pSecondsSeeked = (ma_int64)framesSeeked / (float)sampleRate; + return result; +} + +MA_API ma_result ma_data_source_seek_to_second(ma_data_source* pDataSource, float seekPointInSeconds) +{ + ma_uint64 frameIndex; + ma_uint32 sampleRate; + ma_result result; + + if (pDataSource == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_data_source_get_data_format(pDataSource, NULL, NULL, &sampleRate, NULL, 0); + if (result != MA_SUCCESS) { + return result; + } + + /* We need PCM frames instead of seconds */ + frameIndex = (ma_uint64)(seekPointInSeconds * sampleRate); + + return ma_data_source_seek_to_pcm_frame(pDataSource, frameIndex); +} + MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { ma_data_source_base* pDataSourceBase = (ma_data_source_base*)pDataSource; @@ -57467,6 +58021,8 @@ MA_API ma_result ma_data_source_get_data_format(ma_data_source* pDataSource, ma_ return MA_INVALID_ARGS; } + MA_ASSERT(pDataSourceBase->vtable != NULL); + if (pDataSourceBase->vtable->onGetDataFormat == NULL) { return MA_NOT_IMPLEMENTED; } @@ -57507,6 +58063,8 @@ MA_API ma_result ma_data_source_get_cursor_in_pcm_frames(ma_data_source* pDataSo return MA_SUCCESS; } + MA_ASSERT(pDataSourceBase->vtable != NULL); + if (pDataSourceBase->vtable->onGetCursor == NULL) { return MA_NOT_IMPLEMENTED; } @@ -57540,6 +58098,8 @@ MA_API ma_result ma_data_source_get_length_in_pcm_frames(ma_data_source* pDataSo return MA_INVALID_ARGS; } + MA_ASSERT(pDataSourceBase->vtable != NULL); + /* If we have a range defined we'll use that to determine the length. This is one of rare times where we'll actually trust the caller. If they've set the range, I think it's mostly safe to @@ -57627,6 +58187,8 @@ MA_API ma_result ma_data_source_set_looping(ma_data_source* pDataSource, ma_bool ma_atomic_exchange_32(&pDataSourceBase->isLooping, isLooping); + MA_ASSERT(pDataSourceBase->vtable != NULL); + /* If there's no callback for this just treat it as a successful no-op. */ if (pDataSourceBase->vtable->onSetLooping == NULL) { return MA_SUCCESS; @@ -57664,7 +58226,7 @@ MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSou /* We may need to adjust the position of the cursor to ensure it's clamped to the range. Grab it now - so we can calculate it's absolute position before we change the range. + so we can calculate its absolute position before we change the range. */ result = ma_data_source_get_cursor_in_pcm_frames(pDataSource, &relativeCursor); if (result == MA_SUCCESS) { @@ -57698,7 +58260,7 @@ MA_API ma_result ma_data_source_set_range_in_pcm_frames(ma_data_source* pDataSou /* Seek to within range. Note that our seek positions here are relative to the new range. We don't want - do do this if we failed to retrieve the cursor earlier on because it probably means the data source + to do this if we failed to retrieve the cursor earlier on because it probably means the data source has no notion of a cursor. In practice the seek would probably fail (which we silently ignore), but I'm just not even going to attempt it. */ @@ -57717,6 +58279,13 @@ MA_API void ma_data_source_get_range_in_pcm_frames(const ma_data_source* pDataSo { const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; + if (pRangeBegInFrames != NULL) { + *pRangeBegInFrames = 0; + } + if (pRangeEndInFrames != NULL) { + *pRangeEndInFrames = 0; + } + if (pDataSource == NULL) { return; } @@ -57761,6 +58330,13 @@ MA_API void ma_data_source_get_loop_point_in_pcm_frames(const ma_data_source* pD { const ma_data_source_base* pDataSourceBase = (const ma_data_source_base*)pDataSource; + if (pLoopBegInFrames != NULL) { + *pLoopBegInFrames = 0; + } + if (pLoopEndInFrames != NULL) { + *pLoopEndInFrames = 0; + } + if (pDataSource == NULL) { return; } @@ -59155,7 +59731,7 @@ static ma_result ma_default_vfs_seek__win32(ma_vfs* pVFS, ma_vfs_file file, ma_i result = ma_SetFilePointerEx((HANDLE)file, liDistanceToMove, NULL, dwMoveMethod); } else if (ma_SetFilePointer != NULL) { /* No SetFilePointerEx() so restrict to 31 bits. */ - if (origin > 0x7FFFFFFF) { + if (offset > 0x7FFFFFFF) { return MA_OUT_OF_RANGE; } @@ -59365,7 +59941,7 @@ static ma_result ma_default_vfs_seek__stdio(ma_vfs* pVFS, ma_vfs_file file, ma_i result = _fseeki64((FILE*)file, offset, whence); #else /* No _fseeki64() so restrict to 31 bits. */ - if (origin > 0x7FFFFFFF) { + if (offset > 0x7FFFFFFF) { return MA_OUT_OF_RANGE; } @@ -59758,7 +60334,7 @@ extern "C" { #define MA_DR_WAV_XSTRINGIFY(x) MA_DR_WAV_STRINGIFY(x) #define MA_DR_WAV_VERSION_MAJOR 0 #define MA_DR_WAV_VERSION_MINOR 13 -#define MA_DR_WAV_VERSION_REVISION 13 +#define MA_DR_WAV_VERSION_REVISION 18 #define MA_DR_WAV_VERSION_STRING MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MAJOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_MINOR) "." MA_DR_WAV_XSTRINGIFY(MA_DR_WAV_VERSION_REVISION) #include #define MA_DR_WAVE_FORMAT_PCM 0x1 @@ -60178,7 +60754,7 @@ extern "C" { #define MA_DR_FLAC_XSTRINGIFY(x) MA_DR_FLAC_STRINGIFY(x) #define MA_DR_FLAC_VERSION_MAJOR 0 #define MA_DR_FLAC_VERSION_MINOR 12 -#define MA_DR_FLAC_VERSION_REVISION 42 +#define MA_DR_FLAC_VERSION_REVISION 43 #define MA_DR_FLAC_VERSION_STRING MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MAJOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_MINOR) "." MA_DR_FLAC_XSTRINGIFY(MA_DR_FLAC_VERSION_REVISION) #include #if defined(_MSC_VER) && _MSC_VER >= 1700 @@ -60465,7 +61041,7 @@ extern "C" { #define MA_DR_MP3_XSTRINGIFY(x) MA_DR_MP3_STRINGIFY(x) #define MA_DR_MP3_VERSION_MAJOR 0 #define MA_DR_MP3_VERSION_MINOR 6 -#define MA_DR_MP3_VERSION_REVISION 38 +#define MA_DR_MP3_VERSION_REVISION 40 #define MA_DR_MP3_VERSION_STRING MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MAJOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_MINOR) "." MA_DR_MP3_XSTRINGIFY(MA_DR_MP3_VERSION_REVISION) #include #define MA_DR_MP3_MAX_PCM_FRAMES_PER_MP3_FRAME 1152 @@ -60627,7 +61203,7 @@ MA_API ma_decoder_config ma_decoder_config_init(ma_format outputFormat, ma_uint3 return config; } -MA_API ma_decoder_config ma_decoder_config_init_default() +MA_API ma_decoder_config ma_decoder_config_init_default(void) { return ma_decoder_config_init(ma_format_unknown, 0, 0); } @@ -63220,7 +63796,7 @@ MA_API ma_result ma_stbvorbis_init(ma_read_proc onRead, ma_seek_proc onSeek, ma_ #if !defined(MA_NO_VORBIS) { /* - stb_vorbis lacks a callback based API for it's pulling API which means we're stuck with the + stb_vorbis lacks a callback based API for its pulling API which means we're stuck with the pushing API. In order for us to be able to successfully initialize the decoder we need to supply it with enough data. We need to keep loading data until we have enough. */ @@ -63301,7 +63877,7 @@ MA_API ma_result ma_stbvorbis_init_memory(const void* pData, size_t dataSize, co { (void)pAllocationCallbacks; - /* stb_vorbis uses an int as it's size specifier, restricting it to 32-bit even on 64-bit systems. *sigh*. */ + /* stb_vorbis uses an int as its size specifier, restricting it to 32-bit even on 64-bit systems. *sigh*. */ if (dataSize > INT_MAX) { return MA_TOO_BIG; } @@ -63391,7 +63967,7 @@ MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFram /* The first thing to do is read from any already-cached frames. */ ma_uint32 framesToReadFromCache = (ma_uint32)ma_min(pVorbis->push.framesRemaining, (frameCount - totalFramesRead)); /* Safe cast because pVorbis->framesRemaining is 32-bit. */ - /* The output pointer can be null in which case we just treate it as a seek. */ + /* The output pointer can be null in which case we just treat it as a seek. */ if (pFramesOut != NULL) { ma_uint64 iFrame; for (iFrame = 0; iFrame < framesToReadFromCache; iFrame += 1) { @@ -63465,7 +64041,7 @@ MA_API ma_result ma_stbvorbis_read_pcm_frames(ma_stbvorbis* pVorbis, void* pFram } } - /* If we don't have a success code at this point it means we've encounted an error or the end of the file has been reached (probably the latter). */ + /* If we don't have a success code at this point it means we've encountered an error or the end of the file has been reached (probably the latter). */ if (result != MA_SUCCESS) { break; } @@ -64279,8 +64855,7 @@ MA_API ma_result ma_decoder_init_memory(const void* pData, size_t dataSize, cons #if defined(MA_HAS_WAV) || \ defined(MA_HAS_MP3) || \ defined(MA_HAS_FLAC) || \ - defined(MA_HAS_VORBIS) || \ - defined(MA_HAS_OPUS) + defined(MA_HAS_VORBIS) #define MA_HAS_PATH_API #endif @@ -65095,7 +65670,7 @@ MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesO } else { /* Getting here means we need to do data conversion. If we're seeking forward and are _not_ doing resampling we can run this in a fast path. If we're doing resampling we - need to run through each sample because we need to ensure it's internal cache is updated. + need to run through each sample because we need to ensure its internal cache is updated. */ if (pFramesOut == NULL && pDecoder->converter.hasResampler == MA_FALSE) { result = ma_data_source_read_pcm_frames(pDecoder->pBackend, NULL, frameCount, &totalFramesReadOut); @@ -65185,8 +65760,17 @@ MA_API ma_result ma_decoder_read_pcm_frames(ma_decoder* pDecoder, void* pFramesO if (requiredInputFrameCount > 0) { result = ma_data_source_read_pcm_frames(pDecoder->pBackend, pIntermediaryBuffer, framesToReadThisIterationIn, &framesReadThisIterationIn); + + /* + Note here that even if we've reached the end, we don't want to abort because there might be more output frames needing to be + generated from cached input data, which might happen if resampling is being performed. + */ + if (result != MA_SUCCESS && result != MA_AT_END) { + break; + } } else { framesReadThisIterationIn = 0; + pIntermediaryBuffer[0] = 0; /* <-- This is just to silence a static analysis warning. */ } /* @@ -66667,7 +67251,7 @@ MA_API ma_result ma_noise_set_type(ma_noise* pNoise, ma_noise_type type) /* This function should never have been implemented in the first place. Changing the type dynamically is not - supported. Instead you need to uninitialize and reinitiailize a fresh `ma_noise` object. This function + supported. Instead you need to uninitialize and reinitialize a fresh `ma_noise` object. This function will be removed in version 0.12. */ MA_ASSERT(MA_FALSE); @@ -67713,7 +68297,7 @@ MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pCon pResourceManager->config.pVFS = &pResourceManager->defaultVFS; } - /* If threading has been disabled at compile time, enfore it at run time as well. */ + /* If threading has been disabled at compile time, enforce it at run time as well. */ #ifdef MA_NO_THREADING { pResourceManager->config.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING; @@ -67750,15 +68334,17 @@ MA_API ma_result ma_resource_manager_init(const ma_resource_manager_config* pCon /* Custom decoding backends. */ if (pConfig->ppCustomDecodingBackendVTables != NULL && pConfig->customDecodingBackendCount > 0) { size_t sizeInBytes = sizeof(*pResourceManager->config.ppCustomDecodingBackendVTables) * pConfig->customDecodingBackendCount; + ma_decoding_backend_vtable** ppCustomDecodingBackendVTables; - pResourceManager->config.ppCustomDecodingBackendVTables = (ma_decoding_backend_vtable**)ma_malloc(sizeInBytes, &pResourceManager->config.allocationCallbacks); + ppCustomDecodingBackendVTables = (ma_decoding_backend_vtable**)ma_malloc(sizeInBytes, &pResourceManager->config.allocationCallbacks); if (pResourceManager->config.ppCustomDecodingBackendVTables == NULL) { ma_job_queue_uninit(&pResourceManager->jobQueue, &pResourceManager->config.allocationCallbacks); return MA_OUT_OF_MEMORY; } - MA_COPY_MEMORY(pResourceManager->config.ppCustomDecodingBackendVTables, pConfig->ppCustomDecodingBackendVTables, sizeInBytes); + MA_COPY_MEMORY(ppCustomDecodingBackendVTables, pConfig->ppCustomDecodingBackendVTables, sizeInBytes); + pResourceManager->config.ppCustomDecodingBackendVTables = ppCustomDecodingBackendVTables; pResourceManager->config.customDecodingBackendCount = pConfig->customDecodingBackendCount; pResourceManager->config.pCustomDecodingBackendUserData = pConfig->pCustomDecodingBackendUserData; } @@ -67809,7 +68395,7 @@ static void ma_resource_manager_delete_all_data_buffer_nodes(ma_resource_manager ma_resource_manager_data_buffer_node* pDataBufferNode = pResourceManager->pRootDataBufferNode; ma_resource_manager_data_buffer_node_remove(pResourceManager, pDataBufferNode); - /* The data buffer has been removed from the BST, so now we need to free it's data. */ + /* The data buffer has been removed from the BST, so now we need to free its data. */ ma_resource_manager_data_buffer_node_free(pResourceManager, pDataBufferNode); } } @@ -67822,7 +68408,7 @@ MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager) /* Job threads need to be killed first. To do this we need to post a quit message to the message queue and then wait for the thread. The quit message will never be removed from the - queue which means it will never not be returned after being encounted for the first time which means all threads will eventually receive it. + queue which means it will never not be returned after being encountered for the first time which means all threads will eventually receive it. */ ma_resource_manager_post_job_quit(pResourceManager); @@ -67862,7 +68448,7 @@ MA_API void ma_resource_manager_uninit(ma_resource_manager* pResourceManager) #endif } - ma_free(pResourceManager->config.ppCustomDecodingBackendVTables, &pResourceManager->config.allocationCallbacks); + ma_free((ma_decoding_backend_vtable**)pResourceManager->config.ppCustomDecodingBackendVTables, &pResourceManager->config.allocationCallbacks); /* <-- Naughty const-cast, but this is safe. */ if (pResourceManager->config.pLog == &pResourceManager->log) { ma_log_uninit(&pResourceManager->log); @@ -68280,7 +68866,7 @@ static ma_result ma_resource_manager_data_buffer_node_decode_next_page(ma_resour } result = ma_decoder_read_pcm_frames(pDecoder, pPage->pAudioData, framesToTryReading, &framesRead); - if (framesRead > 0) { + if (result == MA_SUCCESS && framesRead > 0) { pPage->sizeInFrames = framesRead; result = ma_paged_audio_buffer_data_append_page(&pDataBufferNode->data.backend.decodedPaged.data, pPage); @@ -68433,7 +69019,7 @@ static ma_result ma_resource_manager_data_buffer_node_acquire_critical_section(m if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { ma_resource_manager_inline_notification_uninit(pInitNotification); } else { - /* These will have been freed by the job thread, but with WAIT_INIT they will already have happend sinced the job has already been handled. */ + /* These will have been freed by the job thread, but with WAIT_INIT they will already have happened since the job has already been handled. */ ma_free(pFilePathCopy, &pResourceManager->config.allocationCallbacks); ma_free(pFilePathWCopy, &pResourceManager->config.allocationCallbacks); } @@ -68798,6 +69384,10 @@ static ma_result ma_resource_manager_data_buffer_init_ex_internal(ma_resource_ma flags &= ~MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC; } + if (pConfig->isLooping) { + flags |= MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING; + } + async = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_ASYNC) != 0; /* @@ -68810,7 +69400,7 @@ static ma_result ma_resource_manager_data_buffer_init_ex_internal(ma_resource_ma These fences are always released at the "done" tag at the end of this function. They'll be acquired a second if loading asynchronously. This double acquisition system is just done to - simplify code maintanence. + simplify code maintenance. */ ma_resource_manager_pipeline_notifications_acquire_all_fences(¬ifications); { @@ -68855,7 +69445,7 @@ static ma_result ma_resource_manager_data_buffer_init_ex_internal(ma_resource_ma /* The status of the data buffer needs to be set to MA_BUSY before posting the job so that the - worker thread is aware of it's busy state. If the LOAD_DATA_BUFFER job sees a status other + worker thread is aware of its busy state. If the LOAD_DATA_BUFFER job sees a status other than MA_BUSY, it'll assume an error and fall through to an early exit. */ ma_atomic_exchange_i32(&pDataBuffer->result, MA_BUSY); @@ -68874,7 +69464,7 @@ static ma_result ma_resource_manager_data_buffer_init_ex_internal(ma_resource_ma job.data.resourceManager.loadDataBuffer.rangeEndInPCMFrames = pConfig->rangeEndInPCMFrames; job.data.resourceManager.loadDataBuffer.loopPointBegInPCMFrames = pConfig->loopPointBegInPCMFrames; job.data.resourceManager.loadDataBuffer.loopPointEndInPCMFrames = pConfig->loopPointEndInPCMFrames; - job.data.resourceManager.loadDataBuffer.isLooping = pConfig->isLooping; + job.data.resourceManager.loadDataBuffer.isLooping = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING) != 0; /* If we need to wait for initialization to complete we can just process the job in place. */ if ((flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT) != 0) { @@ -69095,22 +69685,29 @@ MA_API ma_result ma_resource_manager_data_buffer_read_pcm_frames(ma_resource_man isDecodedBufferBusy = (ma_resource_manager_data_buffer_node_result(pDataBuffer->pNode) == MA_BUSY); if (ma_resource_manager_data_buffer_get_available_frames(pDataBuffer, &availableFrames) == MA_SUCCESS) { - /* Don't try reading more than the available frame count. */ - if (frameCount > availableFrames) { - frameCount = availableFrames; + /* Don't try reading more than the available frame count if the data buffer node is still loading. */ + if (isDecodedBufferBusy) { + if (frameCount > availableFrames) { + frameCount = availableFrames; - /* - If there's no frames available we want to set the status to MA_AT_END. The logic below - will check if the node is busy, and if so, change it to MA_BUSY. The reason we do this - is because we don't want to call `ma_data_source_read_pcm_frames()` if the frame count - is 0 because that'll result in a situation where it's possible MA_AT_END won't get - returned. - */ - if (frameCount == 0) { - result = MA_AT_END; + /* + If there's no frames available we want to set the status to MA_AT_END. The logic below + will check if the node is busy, and if so, change it to MA_BUSY. The reason we do this + is because we don't want to call `ma_data_source_read_pcm_frames()` if the frame count + is 0 because that'll result in a situation where it's possible MA_AT_END won't get + returned. + */ + if (frameCount == 0) { + result = MA_AT_END; + } + } else { + isDecodedBufferBusy = MA_FALSE; /* We have enough frames available in the buffer to avoid a MA_BUSY status. */ } } else { - isDecodedBufferBusy = MA_FALSE; /* We have enough frames available in the buffer to avoid a MA_BUSY status. */ + /* + Getting here means the buffer has been fully loaded. We can just pass the frame count straight + into ma_data_source_read_pcm_frames() below and let ma_data_source handle it. + */ } } } @@ -69510,6 +70107,7 @@ MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pR ma_bool32 waitBeforeReturning = MA_FALSE; ma_resource_manager_inline_notification waitNotification; ma_resource_manager_pipeline_notifications notifications; + ma_uint32 flags; if (pDataStream == NULL) { if (pConfig != NULL && pConfig->pNotifications != NULL) { @@ -69540,13 +70138,18 @@ MA_API ma_result ma_resource_manager_data_stream_init_ex(ma_resource_manager* pR return result; } + flags = pConfig->flags; + if (pConfig->isLooping) { + flags |= MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING; + } + pDataStream->pResourceManager = pResourceManager; pDataStream->flags = pConfig->flags; pDataStream->result = MA_BUSY; ma_data_source_set_range_in_pcm_frames(pDataStream, pConfig->rangeBegInPCMFrames, pConfig->rangeEndInPCMFrames); ma_data_source_set_loop_point_in_pcm_frames(pDataStream, pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); - ma_data_source_set_looping(pDataStream, pConfig->isLooping); + ma_data_source_set_looping(pDataStream, (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING) != 0); if (pResourceManager == NULL || (pConfig->pFilePath == NULL && pConfig->pFilePathW == NULL)) { ma_resource_manager_pipeline_notifications_signal_all_notifications(¬ifications); @@ -70168,6 +70771,9 @@ static ma_result ma_resource_manager_data_source_preinit(ma_resource_manager* pR } pDataSource->flags = pConfig->flags; + if (pConfig->isLooping) { + pDataSource->flags |= MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING; + } return MA_SUCCESS; } @@ -70726,9 +71332,10 @@ static ma_result ma_job_process__resource_manager__load_data_buffer(ma_job* pJob */ result = ma_resource_manager_data_buffer_result(pDataBuffer); if (result != MA_BUSY) { - goto done; /* <-- This will ensure the exucution pointer is incremented. */ + goto done; /* <-- This will ensure the execution pointer is incremented. */ } else { result = MA_SUCCESS; /* <-- Make sure this is reset. */ + (void)result; /* <-- This is to suppress a static analysis diagnostic about "result" not being used. But for safety when I do future maintenance I don't want to delete that assignment. */ } /* Try initializing the connector if we haven't already. */ @@ -71075,11 +71682,74 @@ static ma_result ma_job_process__resource_manager__seek_data_stream(ma_job* pJob #ifndef MA_NO_NODE_GRAPH + +static ma_stack* ma_stack_init(size_t sizeInBytes, const ma_allocation_callbacks* pAllocationCallbacks) +{ + ma_stack* pStack; + + if (sizeInBytes == 0) { + return NULL; + } + + pStack = (ma_stack*)ma_malloc(sizeof(*pStack) - sizeof(pStack->_data) + sizeInBytes, pAllocationCallbacks); + if (pStack == NULL) { + return NULL; + } + + pStack->offset = 0; + pStack->sizeInBytes = sizeInBytes; + + return pStack; +} + +static void ma_stack_uninit(ma_stack* pStack, const ma_allocation_callbacks* pAllocationCallbacks) +{ + if (pStack == NULL) { + return; + } + + ma_free(pStack, pAllocationCallbacks); +} + +static void* ma_stack_alloc(ma_stack* pStack, size_t sz) +{ + /* The size of the allocation is stored in the memory directly before the pointer. This needs to include padding to keep it aligned to ma_uintptr */ + void* p = (void*)((char*)pStack->_data + pStack->offset); + size_t* pSize = (size_t*)p; + + sz = (sz + (sizeof(ma_uintptr) - 1)) & ~(sizeof(ma_uintptr) - 1); /* Padding. */ + if (pStack->offset + sz + sizeof(size_t) > pStack->sizeInBytes) { + return NULL; /* Out of memory. */ + } + + pStack->offset += sz + sizeof(size_t); + + *pSize = sz; + return (void*)((char*)p + sizeof(size_t)); +} + +static void ma_stack_free(ma_stack* pStack, void* p) +{ + size_t* pSize; + + if (p == NULL) { + return; + } + + pSize = (size_t*)p - 1; + pStack->offset -= *pSize + sizeof(size_t); +} + + + /* 10ms @ 48K = 480. Must never exceed 65535. */ #ifndef MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS #define MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS 480 #endif +#ifndef MA_DEFAULT_PREMIX_STACK_SIZE_PER_CHANNEL +#define MA_DEFAULT_PREMIX_STACK_SIZE_PER_CHANNEL 524288 +#endif static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusIndex, float* pFramesOut, ma_uint32 frameCount, ma_uint32* pFramesRead, ma_uint64 globalTime); @@ -71119,8 +71789,8 @@ MA_API ma_node_graph_config ma_node_graph_config_init(ma_uint32 channels) ma_node_graph_config config; MA_ZERO_OBJECT(&config); - config.channels = channels; - config.nodeCacheCapInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS; + config.channels = channels; + config.processingSizeInFrames = 0; return config; } @@ -71207,11 +71877,7 @@ MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const m } MA_ZERO_OBJECT(pNodeGraph); - pNodeGraph->nodeCacheCapInFrames = pConfig->nodeCacheCapInFrames; - if (pNodeGraph->nodeCacheCapInFrames == 0) { - pNodeGraph->nodeCacheCapInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS; - } - + pNodeGraph->processingSizeInFrames = pConfig->processingSizeInFrames; /* Base node so we can use the node graph as a node into another graph. */ baseConfig = ma_node_config_init(); @@ -71236,6 +71902,40 @@ MA_API ma_result ma_node_graph_init(const ma_node_graph_config* pConfig, const m return result; } + + /* Processing cache. */ + if (pConfig->processingSizeInFrames > 0) { + pNodeGraph->pProcessingCache = (float*)ma_malloc(pConfig->processingSizeInFrames * pConfig->channels * sizeof(float), pAllocationCallbacks); + if (pNodeGraph->pProcessingCache == NULL) { + ma_node_uninit(&pNodeGraph->endpoint, pAllocationCallbacks); + ma_node_uninit(&pNodeGraph->base, pAllocationCallbacks); + return MA_OUT_OF_MEMORY; + } + } + + + /* + We need a pre-mix stack. The size of this stack is configurable via the config. The default value depends on the channel count. + */ + { + size_t preMixStackSizeInBytes = pConfig->preMixStackSizeInBytes; + if (preMixStackSizeInBytes == 0) { + preMixStackSizeInBytes = pConfig->channels * MA_DEFAULT_PREMIX_STACK_SIZE_PER_CHANNEL; + } + + pNodeGraph->pPreMixStack = ma_stack_init(preMixStackSizeInBytes, pAllocationCallbacks); + if (pNodeGraph->pPreMixStack == NULL) { + ma_node_uninit(&pNodeGraph->endpoint, pAllocationCallbacks); + ma_node_uninit(&pNodeGraph->base, pAllocationCallbacks); + if (pNodeGraph->pProcessingCache != NULL) { + ma_free(pNodeGraph->pProcessingCache, pAllocationCallbacks); + } + + return MA_OUT_OF_MEMORY; + } + } + + return MA_SUCCESS; } @@ -71246,6 +71946,17 @@ MA_API void ma_node_graph_uninit(ma_node_graph* pNodeGraph, const ma_allocation_ } ma_node_uninit(&pNodeGraph->endpoint, pAllocationCallbacks); + ma_node_uninit(&pNodeGraph->base, pAllocationCallbacks); + + if (pNodeGraph->pProcessingCache != NULL) { + ma_free(pNodeGraph->pProcessingCache, pAllocationCallbacks); + pNodeGraph->pProcessingCache = NULL; + } + + if (pNodeGraph->pPreMixStack != NULL) { + ma_stack_uninit(pNodeGraph->pPreMixStack, pAllocationCallbacks); + pNodeGraph->pPreMixStack = NULL; + } } MA_API ma_node* ma_node_graph_get_endpoint(ma_node_graph* pNodeGraph) @@ -71278,27 +71989,72 @@ MA_API ma_result ma_node_graph_read_pcm_frames(ma_node_graph* pNodeGraph, void* totalFramesRead = 0; while (totalFramesRead < frameCount) { ma_uint32 framesJustRead; - ma_uint64 framesToRead = frameCount - totalFramesRead; + ma_uint64 framesToRead; + float* pRunningFramesOut; + framesToRead = frameCount - totalFramesRead; if (framesToRead > 0xFFFFFFFF) { framesToRead = 0xFFFFFFFF; } - ma_node_graph_set_is_reading(pNodeGraph, MA_TRUE); - { - result = ma_node_read_pcm_frames(&pNodeGraph->endpoint, 0, (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels), (ma_uint32)framesToRead, &framesJustRead, ma_node_get_time(&pNodeGraph->endpoint)); - } - ma_node_graph_set_is_reading(pNodeGraph, MA_FALSE); + pRunningFramesOut = (float*)ma_offset_pcm_frames_ptr(pFramesOut, totalFramesRead, ma_format_f32, channels); - totalFramesRead += framesJustRead; + /* If there's anything in the cache, consume that first. */ + if (pNodeGraph->processingCacheFramesRemaining > 0) { + ma_uint32 framesToReadFromCache; - if (result != MA_SUCCESS) { - break; - } + framesToReadFromCache = (ma_uint32)framesToRead; + if (framesToReadFromCache > pNodeGraph->processingCacheFramesRemaining) { + framesToReadFromCache = pNodeGraph->processingCacheFramesRemaining; + } - /* Abort if we weren't able to read any frames or else we risk getting stuck in a loop. */ - if (framesJustRead == 0) { - break; + MA_COPY_MEMORY(pRunningFramesOut, pNodeGraph->pProcessingCache, framesToReadFromCache * channels * sizeof(float)); + MA_MOVE_MEMORY(pNodeGraph->pProcessingCache, pNodeGraph->pProcessingCache + (framesToReadFromCache * channels), (pNodeGraph->processingCacheFramesRemaining - framesToReadFromCache) * channels * sizeof(float)); + pNodeGraph->processingCacheFramesRemaining -= framesToReadFromCache; + + totalFramesRead += framesToReadFromCache; + continue; + } else { + /* + If processingSizeInFrames is non-zero, we need to make sure we always read in chunks of that size. If the frame count is less than + that, we need to read into the cache and then continue on. + */ + float* pReadDst = pRunningFramesOut; + + if (pNodeGraph->processingSizeInFrames > 0) { + if (framesToRead < pNodeGraph->processingSizeInFrames) { + pReadDst = pNodeGraph->pProcessingCache; /* We need to read into the cache because otherwise we'll overflow the output buffer. */ + } + + framesToRead = pNodeGraph->processingSizeInFrames; + } + + ma_node_graph_set_is_reading(pNodeGraph, MA_TRUE); + { + result = ma_node_read_pcm_frames(&pNodeGraph->endpoint, 0, pReadDst, (ma_uint32)framesToRead, &framesJustRead, ma_node_get_time(&pNodeGraph->endpoint)); + } + ma_node_graph_set_is_reading(pNodeGraph, MA_FALSE); + + /* + Do not increment the total frames read counter if we read into the cache. We use this to determine how many frames have + been written to the final output buffer. + */ + if (pReadDst == pNodeGraph->pProcessingCache) { + /* We read into the cache. */ + pNodeGraph->processingCacheFramesRemaining = framesJustRead; + } else { + /* We read straight into the output buffer. */ + totalFramesRead += framesJustRead; + } + + if (result != MA_SUCCESS) { + break; + } + + /* Abort if we weren't able to read any frames or else we risk getting stuck in a loop. */ + if (framesJustRead == 0) { + break; + } } } @@ -71499,7 +72255,7 @@ static void ma_node_input_bus_detach__no_output_bus_lock(ma_node_input_bus* pInp *not* using a lock when iterating over the list in the audio thread. We therefore need to craft this in a way such that the iteration on the audio thread doesn't break. - The the first thing to do is swap out the "next" pointer of the previous output bus with the + The first thing to do is swap out the "next" pointer of the previous output bus with the new "next" output bus. This is the operation that matters for iteration on the audio thread. After that, the previous pointer on the new "next" pointer needs to be updated, after which point the linked list will be in a good state. @@ -71592,7 +72348,7 @@ static void ma_node_input_bus_attach(ma_node_input_bus* pInputBus, ma_node_outpu /* Now we need to attach the output bus to the linked list. This involves updating two pointers on two different output buses so I'm going to go ahead and keep this simple and just use a lock. - There are ways to do this without a lock, but it's just too hard to maintain for it's value. + There are ways to do this without a lock, but it's just too hard to maintain for its value. Although we're locking here, it's important to remember that we're *not* locking when iterating and reading audio data since that'll be running on the audio thread. As a result we need to be @@ -71685,11 +72441,9 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ ma_uint32 inputChannels; ma_bool32 doesOutputBufferHaveContent = MA_FALSE; - (void)pInputNode; /* Not currently used. */ - /* This will be called from the audio thread which means we can't be doing any locking. Basically, - this function will not perfom any locking, whereas attaching and detaching will, but crafted in + this function will not perform any locking, whereas attaching and detaching will, but crafted in such a way that we don't need to perform any locking here. The important thing to remember is to always iterate in a forward direction. @@ -71735,19 +72489,12 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ if (pFramesOut != NULL) { /* Read. */ - float temp[MA_DATA_CONVERTER_STACK_BUFFER_SIZE / sizeof(float)]; - ma_uint32 tempCapInFrames = ma_countof(temp) / inputChannels; - while (framesProcessed < frameCount) { float* pRunningFramesOut; ma_uint32 framesToRead; - ma_uint32 framesJustRead; + ma_uint32 framesJustRead = 0; framesToRead = frameCount - framesProcessed; - if (framesToRead > tempCapInFrames) { - framesToRead = tempCapInFrames; - } - pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(pFramesOut, framesProcessed, inputChannels); if (doesOutputBufferHaveContent == MA_FALSE) { @@ -71755,11 +72502,32 @@ static ma_result ma_node_input_bus_read_pcm_frames(ma_node* pInputNode, ma_node_ result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, pRunningFramesOut, framesToRead, &framesJustRead, globalTime + framesProcessed); } else { /* Slow path. Not the first attachment. Mixing required. */ - result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, temp, framesToRead, &framesJustRead, globalTime + framesProcessed); - if (result == MA_SUCCESS || result == MA_AT_END) { - if (isSilentOutput == MA_FALSE) { /* Don't mix if the node outputs silence. */ - ma_mix_pcm_frames_f32(pRunningFramesOut, temp, framesJustRead, inputChannels, /*volume*/1); + ma_uint32 preMixBufferCapInFrames = ((ma_node_base*)pInputNode)->cachedDataCapInFramesPerBus; + float* pPreMixBuffer = (float*)ma_stack_alloc(((ma_node_base*)pInputNode)->pNodeGraph->pPreMixStack, preMixBufferCapInFrames * inputChannels * sizeof(float)); + + if (pPreMixBuffer == NULL) { + /* + If you're hitting this assert it means you've got an unusually deep chain of nodes, you've got an excessively large processing + size, or you have a combination of both, and as a result have run out of stack space. You can increase this using the + preMixStackSizeInBytes variable in ma_node_graph_config. If you're using ma_engine, you can do it via the preMixStackSizeInBytes + variable in ma_engine_config. It defaults to 512KB per output channel. + */ + MA_ASSERT(MA_FALSE); + } else { + if (framesToRead > preMixBufferCapInFrames) { + framesToRead = preMixBufferCapInFrames; } + + result = ma_node_read_pcm_frames(pOutputBus->pNode, pOutputBus->outputBusIndex, pPreMixBuffer, framesToRead, &framesJustRead, globalTime + framesProcessed); + if (result == MA_SUCCESS || result == MA_AT_END) { + if (isSilentOutput == MA_FALSE) { /* Don't mix if the node outputs silence. */ + ma_mix_pcm_frames_f32(pRunningFramesOut, pPreMixBuffer, framesJustRead, inputChannels, /*volume*/1); + } + } + + /* The pre-mix buffer is no longer required. */ + ma_stack_free(((ma_node_base*)pInputNode)->pNodeGraph->pPreMixStack, pPreMixBuffer); + pPreMixBuffer = NULL; } } @@ -71814,6 +72582,25 @@ MA_API ma_node_config ma_node_config_init(void) return config; } +static ma_uint16 ma_node_config_get_cache_size_in_frames(const ma_node_config* pConfig, const ma_node_graph* pNodeGraph) +{ + ma_uint32 cacheSizeInFrames; + + (void)pConfig; + + if (pNodeGraph->processingSizeInFrames > 0) { + cacheSizeInFrames = pNodeGraph->processingSizeInFrames; + } else { + cacheSizeInFrames = MA_DEFAULT_NODE_CACHE_CAP_IN_FRAMES_PER_BUS; + } + + if (cacheSizeInFrames > 0xFFFF) { + cacheSizeInFrames = 0xFFFF; + } + + return (ma_uint16)cacheSizeInFrames; +} + static ma_result ma_node_detach_full(ma_node* pNode); @@ -71968,7 +72755,7 @@ static ma_result ma_node_get_heap_layout(ma_node_graph* pNodeGraph, const ma_nod /* Cached audio data. - We need to allocate memory for a caching both input and output data. We have an optimization + We need to allocate memory for caching both input and output data. We have an optimization where no caching is necessary for specific conditions: - The node has 0 inputs and 1 output. @@ -71987,14 +72774,18 @@ static ma_result ma_node_get_heap_layout(ma_node_graph* pNodeGraph, const ma_nod } else { /* Slow path. Cache needed. */ size_t cachedDataSizeInBytes = 0; + ma_uint32 cacheCapInFrames; ma_uint32 iBus; + /* The capacity of the cache is based on our callback processing size. */ + cacheCapInFrames = ma_node_config_get_cache_size_in_frames(pConfig, pNodeGraph); + for (iBus = 0; iBus < inputBusCount; iBus += 1) { - cachedDataSizeInBytes += pNodeGraph->nodeCacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pInputChannels[iBus]); + cachedDataSizeInBytes += cacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pInputChannels[iBus]); } for (iBus = 0; iBus < outputBusCount; iBus += 1) { - cachedDataSizeInBytes += pNodeGraph->nodeCacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pOutputChannels[iBus]); + cachedDataSizeInBytes += cacheCapInFrames * ma_get_bytes_per_frame(ma_format_f32, pConfig->pOutputChannels[iBus]); } pHeapLayout->cachedDataOffset = pHeapLayout->sizeInBytes; @@ -72080,13 +72871,12 @@ MA_API ma_result ma_node_init_preallocated(ma_node_graph* pNodeGraph, const ma_n if (heapLayout.cachedDataOffset != MA_SIZE_MAX) { pNodeBase->pCachedData = (float*)ma_offset_ptr(pHeap, heapLayout.cachedDataOffset); - pNodeBase->cachedDataCapInFramesPerBus = pNodeGraph->nodeCacheCapInFrames; + pNodeBase->cachedDataCapInFramesPerBus = ma_node_config_get_cache_size_in_frames(pConfig, pNodeGraph); } else { pNodeBase->pCachedData = NULL; } - /* We need to run an initialization step for each input and output bus. */ for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNodeBase); iInputBus += 1) { result = ma_node_input_bus_init(pConfig->pInputChannels[iInputBus], &pNodeBase->pInputBuses[iInputBus]); @@ -72260,7 +73050,7 @@ static ma_result ma_node_detach_full(ma_node* pNode) /* At this point all output buses will have been detached from the graph and we can be guaranteed - that none of it's input nodes will be getting processed by the graph. We can detach these + that none of its input nodes will be getting processed by the graph. We can detach these without needing to worry about the audio thread touching them. */ for (iInputBus = 0; iInputBus < ma_node_get_input_bus_count(pNode); iInputBus += 1) { @@ -72275,7 +73065,7 @@ static ma_result ma_node_detach_full(ma_node* pNode) linked list logic. We don't need to worry about the audio thread referencing these because the step above severed the connection to the graph. */ - for (pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pInputBus->head.pNext); pOutputBus != NULL; pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pOutputBus->pNext)) { + for (pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pInputBus->head.pNext); pOutputBus != NULL; pOutputBus = (ma_node_output_bus*)ma_atomic_load_ptr(&pInputBus->head.pNext)) { ma_node_detach_output_bus(pOutputBus->pNode, pOutputBus->outputBusIndex); /* This won't do any waiting in practice and should be efficient. */ } } @@ -72297,7 +73087,7 @@ MA_API ma_result ma_node_detach_output_bus(ma_node* pNode, ma_uint32 outputBusIn return MA_INVALID_ARGS; /* Invalid output bus index. */ } - /* We need to lock the output bus because we need to inspect the input node and grab it's input bus. */ + /* We need to lock the output bus because we need to inspect the input node and grab its input bus. */ ma_node_output_bus_lock(&pNodeBase->pOutputBuses[outputBusIndex]); { pInputNodeBase = (ma_node_base*)pNodeBase->pOutputBuses[outputBusIndex].pInputNode; @@ -72463,7 +73253,7 @@ MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_ui /* Getting here means the node is marked as started, but it may still not be truly started due to - it's start time not having been reached yet. Also, the stop time may have also been reached in + its start time not having been reached yet. Also, the stop time may have also been reached in which case it'll be considered stopped. */ if (ma_node_get_state_time(pNode, ma_node_state_started) > globalTimeBeg) { @@ -72474,7 +73264,7 @@ MA_API ma_node_state ma_node_get_state_by_time_range(const ma_node* pNode, ma_ui return ma_node_state_stopped; /* Stop time has been reached. */ } - /* Getting here means the node is marked as started and is within it's start/stop times. */ + /* Getting here means the node is marked as started and is within its start/stop times. */ return ma_node_state_started; } @@ -72636,12 +73426,12 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde frameCountOut = totalFramesRead; if (totalFramesRead > 0) { - ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */ + ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Explicit cast to silence the warning. */ } /* A passthrough should never have modified the input and output frame counts. If you're - triggering these assers you need to fix your processing callback. + triggering these asserts you need to fix your processing callback. */ MA_ASSERT(frameCountIn == totalFramesRead); MA_ASSERT(frameCountOut == totalFramesRead); @@ -72819,7 +73609,7 @@ static ma_result ma_node_read_pcm_frames(ma_node* pNode, ma_uint32 outputBusInde frames available right now. */ if (frameCountIn > 0 || (pNodeBase->vtable->flags & MA_NODE_FLAG_DIFFERENT_PROCESSING_RATES) != 0) { - ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Excplicit cast to silence the warning. */ + ma_node_process_pcm_frames_internal(pNode, (const float**)ppFramesIn, &frameCountIn, ppFramesOut, &frameCountOut); /* From GCC: expected 'const float **' but argument is of type 'float **'. Shouldn't this be implicit? Explicit cast to silence the warning. */ } else { frameCountOut = 0; /* No data was processed. */ } @@ -74056,7 +74846,7 @@ static ma_bool32 ma_engine_node_is_pitching_enabled(const ma_engine_node* pEngin { MA_ASSERT(pEngineNode != NULL); - /* Don't try to be clever by skiping resampling in the pitch=1 case or else you'll glitch when moving away from 1. */ + /* Don't try to be clever by skipping resampling in the pitch=1 case or else you'll glitch when moving away from 1. */ return !ma_atomic_load_explicit_32(&pEngineNode->isPitchDisabled, ma_atomic_memory_order_acquire); } @@ -74093,7 +74883,7 @@ static ma_result ma_engine_node_set_volume(ma_engine_node* pEngineNode, float vo /* If we're not smoothing we should bypass the volume gainer entirely. */ if (pEngineNode->volumeSmoothTimeInPCMFrames == 0) { - /* We should always have an active spatializer because it can be enabled and disabled dynamically. We can just use that for hodling our volume. */ + /* We should always have an active spatializer because it can be enabled and disabled dynamically. We can just use that for holding our volume. */ ma_spatializer_set_master_volume(&pEngineNode->spatializer, volume); } else { /* We're using volume smoothing, so apply the master volume to the gainer. */ @@ -74408,7 +75198,7 @@ static void ma_engine_node_process_pcm_frames__sound(ma_node* pNode, const float ma_sound_set_at_end(pSound, MA_TRUE); /* This will be set to false in ma_sound_start(). */ } - pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesRead, ma_engine_get_channels(ma_sound_get_engine(pSound))); + pRunningFramesOut = ma_offset_pcm_frames_ptr_f32(ppFramesOut[0], totalFramesRead, ma_node_get_output_channels(pNode, 0)); frameCountIn = (ma_uint32)framesJustRead; frameCountOut = framesRemaining; @@ -74739,7 +75529,7 @@ MA_API ma_result ma_engine_node_init_preallocated(const ma_engine_node_config* p /* - Spatialization comes next. We spatialize based ont he node's output channel count. It's up the caller to + Spatialization comes next. We spatialize based on the node's output channel count. It's up the caller to ensure channels counts link up correctly in the node graph. */ spatializerConfig = ma_engine_node_spatializer_config_init(&baseNodeConfig); @@ -74929,6 +75719,21 @@ static void ma_engine_data_callback_internal(ma_device* pDevice, void* pFramesOu ma_engine_read_pcm_frames(pEngine, pFramesOut, frameCount, NULL); } + +static ma_uint32 ma_device__get_processing_size_in_frames(ma_device* pDevice) +{ + /* + The processing size is the period size. The device can have a fixed sized processing size, or + it can be decided by the backend in which case it can be variable. + */ + if (pDevice->playback.intermediaryBufferCap > 0) { + /* Using a fixed sized processing callback. */ + return pDevice->playback.intermediaryBufferCap; + } else { + /* Not using a fixed sized processing callback. Need to estimate the processing size based on the backend. */ + return pDevice->playback.internalPeriodSizeInFrames; + } +} #endif MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEngine) @@ -75022,6 +75827,14 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng if (pEngine->pDevice != NULL) { engineConfig.channels = pEngine->pDevice->playback.channels; engineConfig.sampleRate = pEngine->pDevice->sampleRate; + + /* + The processing size used by the engine is determined by engineConfig.periodSizeInFrames. We want + to make this equal to what the device is using for it's period size. If we don't do that, it's + possible that the node graph will split it's processing into multiple passes which can introduce + glitching. + */ + engineConfig.periodSizeInFrames = ma_device__get_processing_size_in_frames(pEngine->pDevice); } } #endif @@ -75048,9 +75861,10 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng } - /* The engine is a node graph. This needs to be initialized after we have the device so we can can determine the channel count. */ + /* The engine is a node graph. This needs to be initialized after we have the device so we can determine the channel count. */ nodeGraphConfig = ma_node_graph_config_init(engineConfig.channels); - nodeGraphConfig.nodeCacheCapInFrames = (engineConfig.periodSizeInFrames > 0xFFFF) ? 0xFFFF : (ma_uint16)engineConfig.periodSizeInFrames; + nodeGraphConfig.processingSizeInFrames = engineConfig.periodSizeInFrames; + nodeGraphConfig.preMixStackSizeInBytes = engineConfig.preMixStackSizeInBytes; result = ma_node_graph_init(&nodeGraphConfig, &pEngine->allocationCallbacks, &pEngine->nodeGraph); if (result != MA_SUCCESS) { @@ -75130,8 +75944,8 @@ MA_API ma_result ma_engine_init(const ma_engine_config* pConfig, ma_engine* pEng ma_allocation_callbacks_init_copy(&resourceManagerConfig.allocationCallbacks, &pEngine->allocationCallbacks); resourceManagerConfig.pVFS = engineConfig.pResourceManagerVFS; - /* The Emscripten build cannot use threads. */ - #if defined(MA_EMSCRIPTEN) + /* The Emscripten build cannot use threads unless it's targeting pthreads. */ + #if defined(MA_EMSCRIPTEN) && !defined(__EMSCRIPTEN_PTHREADS__) { resourceManagerConfig.jobThreadCount = 0; resourceManagerConfig.flags |= MA_RESOURCE_MANAGER_FLAG_NO_THREADING; @@ -75646,7 +76460,7 @@ MA_API ma_result ma_engine_play_sound_ex(ma_engine* pEngine, const char* pFilePa return MA_INVALID_ARGS; } - /* Attach to the endpoint node if nothing is specicied. */ + /* Attach to the endpoint node if nothing is specified. */ if (pNode == NULL) { pNode = ma_node_graph_get_endpoint(&pEngine->nodeGraph); nodeInputBusIndex = 0; @@ -75863,7 +76677,7 @@ static ma_result ma_sound_init_from_data_source_internal(ma_engine* pEngine, con ma_data_source_set_range_in_pcm_frames(ma_sound_get_data_source(pSound), pConfig->loopPointBegInPCMFrames, pConfig->loopPointEndInPCMFrames); } - ma_sound_set_looping(pSound, pConfig->isLooping); + ma_sound_set_looping(pSound, pConfig->isLooping || ((pConfig->flags & MA_SOUND_FLAG_LOOPING) != 0)); return MA_SUCCESS; } @@ -75887,6 +76701,9 @@ MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_s it and can avoid accessing the sound from within the notification. */ flags = pConfig->flags | MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_WAIT_INIT; + if (pConfig->isLooping) { + flags |= MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING; + } pSound->pResourceManagerDataSource = (ma_resource_manager_data_source*)ma_malloc(sizeof(*pSound->pResourceManagerDataSource), &pEngine->allocationCallbacks); if (pSound->pResourceManagerDataSource == NULL) { @@ -75915,7 +76732,7 @@ MA_API ma_result ma_sound_init_from_file_internal(ma_engine* pEngine, const ma_s resourceManagerDataSourceConfig.rangeEndInPCMFrames = pConfig->rangeEndInPCMFrames; resourceManagerDataSourceConfig.loopPointBegInPCMFrames = pConfig->loopPointBegInPCMFrames; resourceManagerDataSourceConfig.loopPointEndInPCMFrames = pConfig->loopPointEndInPCMFrames; - resourceManagerDataSourceConfig.isLooping = pConfig->isLooping; + resourceManagerDataSourceConfig.isLooping = (flags & MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING) != 0; result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource); if (result != MA_SUCCESS) { @@ -76067,7 +76884,7 @@ MA_API ma_result ma_sound_init_ex(ma_engine* pEngine, const ma_sound_config* pCo { /* Getting here means we're not loading from a file. We may be loading from an already-initialized - data source, or none at all. If we aren't specifying any data source, we'll be initializing the + data source, or none at all. If we aren't specifying any data source, we'll be initializing the equivalent to a group. ma_data_source_init_from_data_source_internal() will deal with this for us, so no special treatment required here. */ @@ -76787,6 +77604,27 @@ MA_API ma_result ma_sound_seek_to_pcm_frame(ma_sound* pSound, ma_uint64 frameInd return MA_SUCCESS; } +MA_API ma_result ma_sound_seek_to_second(ma_sound* pSound, float seekPointInSeconds) +{ + ma_uint64 frameIndex; + ma_uint32 sampleRate; + ma_result result; + + if (pSound == NULL) { + return MA_INVALID_ARGS; + } + + result = ma_sound_get_data_format(pSound, NULL, NULL, &sampleRate, NULL, 0); + if (result != MA_SUCCESS) { + return result; + } + + /* We need PCM frames. We need to convert first */ + frameIndex = (ma_uint64)(seekPointInSeconds * sampleRate); + + return ma_sound_seek_to_pcm_frame(pSound, frameIndex); +} + MA_API ma_result ma_sound_get_data_format(ma_sound* pSound, ma_format* pFormat, ma_uint32* pChannels, ma_uint32* pSampleRate, ma_channel* pChannelMap, size_t channelMapCap) { if (pSound == NULL) { @@ -77233,7 +78071,7 @@ code below please report the bug to the respective repository for the relevant p *************************************************************************************************************************************************************** **************************************************************************************************************************************************************/ #if !defined(MA_NO_WAV) && (!defined(MA_NO_DECODING) || !defined(MA_NO_ENCODING)) -#if !defined(MA_DR_WAV_IMPLEMENTATION) && !defined(MA_DR_WAV_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */ +#if !defined(MA_DR_WAV_IMPLEMENTATION) /* dr_wav_c begin */ #ifndef ma_dr_wav_c #define ma_dr_wav_c @@ -78555,7 +79393,6 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p } if (pWav->container == ma_dr_wav_container_riff || pWav->container == ma_dr_wav_container_rifx) { if (ma_dr_wav_bytes_to_u32_ex(chunkSizeBytes, pWav->container) < 36) { - return MA_FALSE; } } else if (pWav->container == ma_dr_wav_container_rf64) { if (ma_dr_wav_bytes_to_u32_le(chunkSizeBytes) != 0xFFFFFFFF) { @@ -78824,7 +79661,9 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p compressionFormat = MA_DR_WAVE_FORMAT_MULAW; } else if (ma_dr_wav_fourcc_equal(type, "ima4")) { compressionFormat = MA_DR_WAVE_FORMAT_DVI_ADPCM; - sampleSizeInBits = 4; + sampleSizeInBits = 4; + (void)compressionFormat; + (void)sampleSizeInBits; return MA_FALSE; } else { return MA_FALSE; @@ -78882,9 +79721,7 @@ MA_PRIVATE ma_bool32 ma_dr_wav_init__internal(ma_dr_wav* pWav, ma_dr_wav_chunk_p } } if (isProcessingMetadata) { - ma_uint64 metadataBytesRead; - metadataBytesRead = ma_dr_wav__metadata_process_chunk(&metadataParser, &header, ma_dr_wav_metadata_type_all_including_unknown); - MA_DR_WAV_ASSERT(metadataBytesRead <= header.sizeInBytes); + ma_dr_wav__metadata_process_chunk(&metadataParser, &header, ma_dr_wav_metadata_type_all_including_unknown); if (ma_dr_wav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData) == MA_FALSE) { break; } @@ -80332,6 +81169,12 @@ MA_API ma_uint64 ma_dr_wav_write_pcm_frames(ma_dr_wav* pWav, ma_uint64 framesToW MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_uint64 framesToRead, ma_int16* pBufferOut) { ma_uint64 totalFramesRead = 0; + static ma_int32 adaptationTable[] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 + }; + static ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; + static ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; MA_DR_WAV_ASSERT(pWav != NULL); MA_DR_WAV_ASSERT(framesToRead > 0); while (pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { @@ -80350,6 +81193,9 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0]; pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1]; pWav->msadpcm.cachedFrameCount = 2; + if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table)) { + return totalFramesRead; + } } else { ma_uint8 header[14]; if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { @@ -80369,6 +81215,9 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1]; pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1]; pWav->msadpcm.cachedFrameCount = 2; + if (pWav->msadpcm.predictor[0] >= ma_dr_wav_countof(coeff1Table) || pWav->msadpcm.predictor[1] >= ma_dr_wav_countof(coeff2Table)) { + return totalFramesRead; + } } } while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->readCursorInPCMFrames < pWav->totalPCMFrameCount) { @@ -80391,12 +81240,6 @@ MA_PRIVATE ma_uint64 ma_dr_wav_read_pcm_frames_s16__msadpcm(ma_dr_wav* pWav, ma_ if (pWav->msadpcm.bytesRemainingInBlock == 0) { continue; } else { - static ma_int32 adaptationTable[] = { - 230, 230, 230, 230, 307, 409, 512, 614, - 768, 614, 512, 409, 307, 230, 230, 230 - }; - static ma_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; - static ma_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; ma_uint8 nibbles; ma_int32 nibble0; ma_int32 nibble1; @@ -81647,7 +82490,7 @@ MA_API void ma_dr_wav_f32_to_s32(ma_int32* pOut, const float* pIn, size_t sample return; } for (i = 0; i < sampleCount; ++i) { - *pOut++ = (ma_int32)(2147483648.0 * pIn[i]); + *pOut++ = (ma_int32)(2147483648.0f * pIn[i]); } } MA_API void ma_dr_wav_f64_to_s32(ma_int32* pOut, const double* pIn, size_t sampleCount) @@ -82061,7 +82904,7 @@ MA_API ma_bool32 ma_dr_wav_fourcc_equal(const ma_uint8* a, const char* b) #endif /* MA_NO_WAV */ #if !defined(MA_NO_FLAC) && !defined(MA_NO_DECODING) -#if !defined(MA_DR_FLAC_IMPLEMENTATION) && !defined(MA_DR_FLAC_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */ +#if !defined(MA_DR_FLAC_IMPLEMENTATION) /* dr_flac_c begin */ #ifndef ma_dr_flac_c #define ma_dr_flac_c @@ -85093,6 +85936,7 @@ static ma_bool32 ma_dr_flac__read_subframe_header(ma_dr_flac_bs* bs, ma_dr_flac_ if ((header & 0x80) != 0) { return MA_FALSE; } + pSubframe->lpcOrder = 0; type = (header & 0x7E) >> 1; if (type == 0) { pSubframe->subframeType = MA_DR_FLAC_SUBFRAME_CONSTANT; @@ -85150,6 +85994,9 @@ static ma_bool32 ma_dr_flac__decode_subframe(ma_dr_flac_bs* bs, ma_dr_flac_frame } subframeBitsPerSample -= pSubframe->wastedBitsPerSample; pSubframe->pSamplesS32 = pDecodedSamplesOut; + if (frame->header.blockSizeInPCMFrames < pSubframe->lpcOrder) { + return MA_FALSE; + } switch (pSubframe->subframeType) { case MA_DR_FLAC_SUBFRAME_CONSTANT: @@ -89806,7 +90653,7 @@ MA_API ma_bool32 ma_dr_flac_next_cuesheet_track(ma_dr_flac_cuesheet_track_iterat #endif /* MA_NO_FLAC */ #if !defined(MA_NO_MP3) && !defined(MA_NO_DECODING) -#if !defined(MA_DR_MP3_IMPLEMENTATION) && !defined(MA_DR_MP3_IMPLEMENTATION) /* For backwards compatibility. Will be removed in version 0.11 for cleanliness. */ +#if !defined(MA_DR_MP3_IMPLEMENTATION) /* dr_mp3_c begin */ #ifndef ma_dr_mp3_c #define ma_dr_mp3_c @@ -89867,7 +90714,7 @@ MA_API const char* ma_dr_mp3_version_string(void) #define MA_DR_MP3_MIN(a, b) ((a) > (b) ? (b) : (a)) #define MA_DR_MP3_MAX(a, b) ((a) < (b) ? (b) : (a)) #if !defined(MA_DR_MP3_NO_SIMD) -#if !defined(MA_DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64)) +#if !defined(MA_DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) #define MA_DR_MP3_ONLY_SIMD #endif #if ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__))) @@ -89940,7 +90787,7 @@ end: return g_have_simd - 1; #endif } -#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) +#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) #include #define MA_DR_MP3_HAVE_SSE 0 #define MA_DR_MP3_HAVE_SIMD 1 @@ -89969,7 +90816,7 @@ static int ma_dr_mp3_have_simd(void) #else #define MA_DR_MP3_HAVE_SIMD 0 #endif -#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(__ARM_ARCH_6M__) +#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) && !defined(_M_ARM64EC) && !defined(__ARM_ARCH_6M__) #define MA_DR_MP3_HAVE_ARMV6 1 static __inline__ __attribute__((always_inline)) ma_int32 ma_dr_mp3_clip_int16_arm(ma_int32 a) { @@ -91135,8 +91982,8 @@ static ma_int16 ma_dr_mp3d_scale_pcm(float sample) s32 -= (s32 < 0); s = (ma_int16)ma_dr_mp3_clip_int16_arm(s32); #else - if (sample >= 32766.5) return (ma_int16) 32767; - if (sample <= -32767.5) return (ma_int16)-32768; + if (sample >= 32766.5f) return (ma_int16) 32767; + if (sample <= -32767.5f) return (ma_int16)-32768; s = (ma_int16)(sample + .5f); s -= (s < 0); #endif @@ -91522,9 +92369,9 @@ MA_API void ma_dr_mp3dec_f32_to_s16(const float *in, ma_int16 *out, size_t num_s for(; i < num_samples; i++) { float sample = in[i] * 32768.0f; - if (sample >= 32766.5) + if (sample >= 32766.5f) out[i] = (ma_int16) 32767; - else if (sample <= -32767.5) + else if (sample <= -32767.5f) out[i] = (ma_int16)-32768; else { @@ -92602,7 +93449,7 @@ For more information, please refer to =============================================================================== ALTERNATIVE 2 - MIT No Attribution =============================================================================== -Copyright 2023 David Reid +Copyright 2025 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 diff --git a/vendor/miniaudio/synchronization.odin b/vendor/miniaudio/synchronization.odin index 012f52c2c..08182c32b 100644 --- a/vendor/miniaudio/synchronization.odin +++ b/vendor/miniaudio/synchronization.odin @@ -62,6 +62,11 @@ when !NO_THREADING { Signals the specified auto-reset event. */ event_signal :: proc(pEvent: ^event) -> result --- + + semaphore_init :: proc(initialValue: i32, pSemaphore: ^semaphore) -> result --- + semaphore_uninit :: proc(pSemaphore: ^semaphore) --- + semaphore_wait :: proc(pSemaphore: ^semaphore) -> result --- + semaphore_release :: proc(pSemaphore: ^semaphore) -> result --- } /* NO_THREADING */ } diff --git a/vendor/miniaudio/utilities.odin b/vendor/miniaudio/utilities.odin index 9285874b6..d59bb75a4 100644 --- a/vendor/miniaudio/utilities.odin +++ b/vendor/miniaudio/utilities.odin @@ -7,7 +7,7 @@ foreign import lib { LIB } @(default_calling_convention="c", link_prefix="ma_") foreign lib { /* - Calculates a buffer size in milliseconds from the specified number of frames and sample rate. + Calculates a buffer size in milliseconds (rounded up) from the specified number of frames and sample rate. */ calculate_buffer_size_in_milliseconds_from_frames :: proc(bufferSizeInFrames: u32, sampleRate: u32) -> u32 --- @@ -163,6 +163,8 @@ foreign lib { data_source_read_pcm_frames :: proc(pDataSource: ^data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result --- /* Must support pFramesOut = NULL in which case a forward seek should be performed. */ data_source_seek_pcm_frames :: proc(pDataSource: ^data_source, frameCount: u64, pFramesSeeked: ^u64) -> result --- /* Can only seek forward. Equivalent to ma_data_source_read_pcm_frames(pDataSource, NULL, frameCount); */ data_source_seek_to_pcm_frame :: proc(pDataSource: ^data_source, frameIndex: u64) -> result --- + data_source_seek_seconds :: proc(pDataSource: ^data_source, secondCount: f32, pSecondsSeeked: ^f32) -> result --- /* Can only seek forward. Abstraction to ma_data_source_seek_pcm_frames() */ + data_source_seek_to_seconds :: proc(pDataSource: ^data_source, seekPointInSeconds: f32) -> result --- /* Abstraction to ma_data_source_seek_to_pcm_frame() */ data_source_get_data_format :: proc(pDataSource: ^data_source, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result --- data_source_get_cursor_in_pcm_frames :: proc(pDataSource: ^data_source, pCursor: ^u64) -> result --- data_source_get_length_in_pcm_frames :: proc(pDataSource: ^data_source, pLength: ^u64) -> result --- /* Returns MA_NOT_IMPLEMENTED if the length is unknown or cannot be determined. Decoders can return this. */ diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index 02bb6deea..bb8f0e894 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -274,7 +274,7 @@ Camera3D :: struct { target: Vector3, // Camera target it looks-at up: Vector3, // Camera up vector (rotation over its axis) fovy: f32, // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic - projection: CameraProjection, // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + projection: CameraProjection, // Camera projection: `.PERSPECTIVE` or `.ORTHOGRAPHIC` } Camera :: Camera3D // Camera type fallback, defaults to Camera3D diff --git a/vendor/raylib/raymath.odin b/vendor/raylib/raymath.odin index c8420d60a..9874d5086 100644 --- a/vendor/raylib/raymath.odin +++ b/vendor/raylib/raymath.odin @@ -831,8 +831,8 @@ fmaxf :: proc "contextless" (x, y: f32) -> f32 { return x } - if math.signbit(x) != math.signbit(y) { - return y if math.signbit(x) else x + if math.sign_bit(x) != math.sign_bit(y) { + return y if math.sign_bit(x) else x } return y if x < y else x diff --git a/vendor/raylib/rlgl/rlgl.odin b/vendor/raylib/rlgl/rlgl.odin index 6ac19695d..14a7cf5b0 100644 --- a/vendor/raylib/rlgl/rlgl.odin +++ b/vendor/raylib/rlgl/rlgl.odin @@ -375,17 +375,20 @@ foreign lib { //------------------------------------------------------------------------------------ // Functions Declaration - Matrix operations //------------------------------------------------------------------------------------ - MatrixMode :: proc(mode: c.int) --- // Choose the current matrix to be transformed - PushMatrix :: proc() --- // Push the current matrix to stack - PopMatrix :: proc() --- // Pop lattest inserted matrix from stack - LoadIdentity :: proc() --- // Reset current matrix to identity matrix - Translatef :: proc(x, y, z: f32) --- // Multiply the current matrix by a translation matrix - Rotatef :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix - Scalef :: proc(x, y, z: f32) --- // Multiply the current matrix by a scaling matrix - MultMatrixf :: proc(matf: [^]f32) --- // Multiply the current matrix by another matrix - Frustum :: proc(left, right, bottom, top, znear, zfar: f64) --- - Ortho :: proc(left, right, bottom, top, znear, zfar: f64) --- - Viewport :: proc(x, y, width, height: c.int) --- // Set the viewport area + MatrixMode :: proc(mode: c.int) --- // Choose the current matrix to be transformed + PushMatrix :: proc() --- // Push the current matrix to stack + PopMatrix :: proc() --- // Pop lattest inserted matrix from stack + LoadIdentity :: proc() --- // Reset current matrix to identity matrix + Translatef :: proc(x, y, z: f32) --- // Multiply the current matrix by a translation matrix + Rotatef :: proc(angleDeg: f32, x, y, z: f32) --- // Multiply the current matrix by a rotation matrix + Scalef :: proc(x, y, z: f32) --- // Multiply the current matrix by a scaling matrix + MultMatrixf :: proc(matf: [^]f32) --- // Multiply the current matrix by another matrix + Frustum :: proc(left, right, bottom, top, znear, zfar: f64) --- + Ortho :: proc(left, right, bottom, top, znear, zfar: f64) --- + Viewport :: proc(x, y, width, height: c.int) --- // Set the viewport area + SetClipPlanes :: proc(near, far: f64) --- // Set clip planes distances + GetCullDistanceNear :: proc() -> f64 --- // Get cull plane distance near + GetCullDistanceFar :: proc() -> f64 --- // Get cull plane distance far //------------------------------------------------------------------------------------ // Functions Declaration - Vertex level operations @@ -535,7 +538,7 @@ foreign lib { ReadScreenPixels :: proc(width, height: c.int) -> [^]byte --- // Read screen pixel data (color buffer) // Framebuffer management (fbo) - LoadFramebuffer :: proc(width, height: c.int) -> c.uint --- // Load an empty framebuffer + LoadFramebuffer :: proc() -> c.uint --- // Load an empty framebuffer FramebufferAttach :: proc(fboId, texId: c.uint, attachType: c.int, texType: c.int, mipLevel: c.int) --- // Attach texture/renderbuffer to a framebuffer FramebufferComplete :: proc(id: c.uint) -> bool --- // Verify framebuffer is complete UnloadFramebuffer :: proc(id: c.uint) --- // Delete framebuffer from GPU diff --git a/vendor/sdl2/sdl_audio.odin b/vendor/sdl2/sdl_audio.odin index 6ff9e93f4..296a773c4 100644 --- a/vendor/sdl2/sdl_audio.odin +++ b/vendor/sdl2/sdl_audio.odin @@ -74,12 +74,14 @@ when ODIN_ENDIAN == .Little { AUDIO_F32SYS :: AUDIO_F32MSB } - -AUDIO_ALLOW_FREQUENCY_CHANGE :: 0x00000001 -AUDIO_ALLOW_FORMAT_CHANGE :: 0x00000002 -AUDIO_ALLOW_CHANNELS_CHANGE :: 0x00000004 -AUDIO_ALLOW_SAMPLES_CHANGE :: 0x00000008 -AUDIO_ALLOW_ANY_CHANGE :: AUDIO_ALLOW_FREQUENCY_CHANGE|AUDIO_ALLOW_FORMAT_CHANGE|AUDIO_ALLOW_CHANNELS_CHANGE|AUDIO_ALLOW_SAMPLES_CHANGE +AudioAllowChangeFlags :: distinct bit_set[AudioAllowChangeFlag; c.int] +AudioAllowChangeFlag :: enum c.int { + FREQUENCY = 0, + FORMAT = 1, + CHANNELS = 2, + SAMPLES = 3, +} +AUDIO_ALLOW_ANY_CHANGE :: AudioAllowChangeFlags{.FREQUENCY, .FORMAT, .CHANNELS, .SAMPLES} AudioCallback :: proc "c" (userdata: rawptr, stream: [^]u8, len: c.int) @@ -151,7 +153,7 @@ foreign lib { iscapture: bool, desired: ^AudioSpec, obtained: ^AudioSpec, - allowed_changes: bool) -> AudioDeviceID --- + allowed_changes: AudioAllowChangeFlags) -> AudioDeviceID --- } diff --git a/vendor/sdl2/sdl_rwops.odin b/vendor/sdl2/sdl_rwops.odin index ca7fa0bea..d3986f4b3 100644 --- a/vendor/sdl2/sdl_rwops.odin +++ b/vendor/sdl2/sdl_rwops.odin @@ -87,7 +87,7 @@ foreign lib { RWseek :: proc(ctx: ^RWops, offset: i64, whence: c.int) -> i64 --- RWtell :: proc(ctx: ^RWops) -> i64 --- RWread :: proc(ctx: ^RWops, ptr: rawptr, size: c.size_t, maxnum: c.size_t) -> c.size_t --- - RWwrite :: proc(ctx: ^RWops, size: c.size_t, num: c.size_t) -> c.size_t --- + RWwrite :: proc(ctx: ^RWops, ptr: rawptr, size: c.size_t, num: c.size_t) -> c.size_t --- RWclose :: proc(ctx: ^RWops) -> c.int --- LoadFile_RW :: proc(src: ^RWops, datasize: ^c.size_t, freesrc: bool) -> rawptr --- diff --git a/vendor/sdl3/SDL3.dll b/vendor/sdl3/SDL3.dll index 6c9d438f9..63f5b22ec 100644 Binary files a/vendor/sdl3/SDL3.dll and b/vendor/sdl3/SDL3.dll differ diff --git a/vendor/sdl3/SDL3.lib b/vendor/sdl3/SDL3.lib index aec791196..164aeb9f1 100644 Binary files a/vendor/sdl3/SDL3.lib and b/vendor/sdl3/SDL3.lib differ diff --git a/vendor/sdl3/gamecontrollerdb.txt b/vendor/sdl3/gamecontrollerdb.txt index c57935b14..56e8c75b7 100644 --- a/vendor/sdl3/gamecontrollerdb.txt +++ b/vendor/sdl3/gamecontrollerdb.txt @@ -20,7 +20,7 @@ 03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, -05000000c82d00006a28000000000000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Windows, +03000000c82d00006a28000000000000,8BitDo GameCube,a:b0,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b9,paddle2:b8,rightshoulder:b10,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b1,y:b4,platform:Windows, 03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, 03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows, @@ -154,6 +154,7 @@ 03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, 03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows, +030000005a1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, 030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, 030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, 030000006d04000042c2000000000000,ChillStream,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, @@ -182,6 +183,9 @@ 030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows, 03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, 03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +03000095090000010000000000000000,Elecom JC-U609,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows, +0300004112000000e500000000000000,Elecom JC-U909Z,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows, +03000041120000001050000000000000,Elecom JC-U911,a:b1,b:b2,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b0,x:b4,y:b5,platform:Windows, 030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, 03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, 030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, @@ -193,6 +197,7 @@ 030000007d0400000640000000000000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Windows, 03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 03000000430b00000300000000000000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000062000001801000000000000,EMS TrioLinker Plus II,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Windows, 03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows, 03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, @@ -332,6 +337,7 @@ 03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows, 03000000242e00006a48000000000000,Hyperkin RetroN Sq,a:b3,b:b7,back:b5,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b0,rightshoulder:b1,start:b4,x:b2,y:b6,platform:Windows, 03000000242f00000a20000000000000,Hyperkin Scout,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +03000000242e00000a20000000000000,Hyperkin Scout Premium SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, 03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows, 03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows, 03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, @@ -387,7 +393,7 @@ 03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, -03000000380700008031000000000000,Mad Catz FightStick Alpha PS3 ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008031000000000000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, 03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, @@ -414,7 +420,7 @@ 03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, 0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000242e0000f500000000000000,Mayflash N64 Adapter,a:b2,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows, +03000000242f0000f500000000000000,Mayflash N64 Adapter,a:b2,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows, 03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows, 03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows, 030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, @@ -446,7 +452,6 @@ 03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, 03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows, 03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows, -030000006f0e00001311000000000000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Windows, 030000006b140000010c000000000000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, @@ -464,8 +469,10 @@ 030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows, 03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows, 03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +030000007e0500006920000000000000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Windows, 030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, 030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows, +030000007e0500007320000000000000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Windows, 030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows, 030000007e0500001720000000000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Windows, 03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows, @@ -481,6 +488,7 @@ 030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, 03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows, 03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, 03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, @@ -576,8 +584,10 @@ 030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, 030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, 030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows, +030000009b2800003c00000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, 030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, 030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, +030000009b2800006400000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, 030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows, 030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows, 030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, @@ -610,6 +620,7 @@ 03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows, 03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, 03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000632500007805000000000000,Retro Fighters Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, 03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows, 03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, @@ -627,6 +638,7 @@ 030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000830500007030000000000000,Rockfire Space Ranger,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b9,righttrigger:b8,start:b2,x:b3,y:b4,platform:Windows, 03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, 03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, 03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, @@ -637,6 +649,7 @@ 030000000d0f0000ad00000000000000,RX Gamepad,a:b0,b:b4,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b6,start:b9,x:b2,y:b1,platform:Windows, 030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, 03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00001311000000000000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Windows, 03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000a306000023f6000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, 03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, @@ -665,7 +678,7 @@ 03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows, 03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, -03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, 0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, 0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows, 03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, @@ -682,6 +695,7 @@ 03000000317300000100000000000000,Sony DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, 03000000666600006706000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows, 03000000e30500009605000000000000,Sony PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000fe1400002a23000000000000,Sony PlayStation Adapter,a:b0,b:b1,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,x:b2,y:b3,platform:Windows, 030000004c050000da0c000000000000,Sony PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, 03000000632500002306000000000000,Sony PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, 03000000f0250000c183000000000000,Sony PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, @@ -756,8 +770,8 @@ 03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, 03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, 03000000882800000305000000000000,V5 Game Pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,x:b2,y:b3,platform:Windows, -03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, -03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000790000001a18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000001b18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, 030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, 0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows, @@ -967,6 +981,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, 03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +0300000049190000020400001b010000,Manba One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, 030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X, 03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X, @@ -987,18 +1002,21 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, 03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000853200008906000000010000,Nacon Revolution X Unlimited,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X, 03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X, 030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X, +030000007e0500006920000001010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Mac OS X, 030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, 030000007e0500000920000010020000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X, 050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:Mac OS X, +030000007e0500007320000001010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Mac OS X, 030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X, 030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X, 03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X, 030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X, -03000000790000001c18000000010000,PB Tails Choc,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +0300000009120000072f000000010000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a2,leftx:a0,lefty:a1,righttrigger:a5,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Mac OS X, 030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, @@ -1032,6 +1050,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, 0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000632500008005000000010000,Redgear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000632500002305000000010000,Redragon Saturn,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, 03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X, 03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X, @@ -1070,6 +1089,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X, 03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X, +03000000790000001c18000000010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, 03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X, 03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X, @@ -1089,6 +1109,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X, 050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X, 030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4~,start:b8,x:b2,y:b3,platform:Mac OS X, 030000006f0e00000104000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 03000000c6240000045d000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, 030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, @@ -1244,9 +1265,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000bc2000000055000001000000,Betop AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000300e000011010000,Brook Audio Fighting Board PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000310e000011010000,Brook Audio Fighting Board PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000d81d00000b00000010010000,Buffalo BSGP1601,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Linux, 03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux, 030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux, @@ -1264,7 +1288,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e00008401000011010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, -03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000852100000201000010010000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, @@ -1276,15 +1300,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000373500009710000001020000,GameSir Kaleid Flux,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, 03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000f0250000c283000010010000,Gioteck VX2 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,platform:Linux, 190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux, -190000004b4800000011000000010000,GO-Super Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b2,y:b3,platform:Linux, +190000004b4800000011000000010000,GO-Super Gamepad,a:b0,b:b1,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b3,y:b2,platform:Linux, 03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, @@ -1380,6 +1406,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000380700008031000011010000,Mad Catz FightStick Alpha PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008081000011010000,Mad Catz FightStick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1419,6 +1447,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea0200000f050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -1426,7 +1455,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -060000005e040000120b000001050000,Microsoft Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000016050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000017050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b000001050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, 03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, @@ -1441,10 +1472,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, 030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000f70600000100000000010000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Linux, -030000006f0e00001311000011010000,N64 Controller,+rightx:b10,+righty:b3,-rightx:b0,-righty:b11,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,platform:Linux, 030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +05000000853200000503000000010000,Nacon MG-X Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1455,6 +1486,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, 030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux, 03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux, +030000007e0500006920000011010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Linux, 060000004e696e74656e646f20537700,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, 060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, 060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, @@ -1467,13 +1499,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux, 05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +050000005a1d00000218000003000000,Nokia GC 5000,a:b9,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux, -030000007e0500001920000011810000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux, +030000007e0500007320000011010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Linux, +030000007e0500001920000011810000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux, 050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux, -050000007e0500001920000001800000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux, -030000007e0500001720000011810000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +050000007e0500001920000001800000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,platform:Linux, +030000007e0500001e20000011810000,NSO Sega Genesis Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,misc1:b3,rightshoulder:b2,righttrigger:b4,start:b5,platform:Linux, +030000007e0500001720000011810000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, 050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux, -050000007e0500001720000001800000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +050000007e0500001720000001800000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, 03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, 03000000550900001472000011010000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, 05000000550900001472000001000000,NVIDIA Controller,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, @@ -1489,7 +1524,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00008501000011010000,PDP Fightpad Pro Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, @@ -1497,14 +1532,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000f102000000000000,PDP Xbox Atomic,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, 030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000006f0e0000f102000000000000,PDP Xbox Atomic,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, 03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000d62000000540000001010000,PowerA Advantage Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000540000001010000,PowerA Advantage Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1519,8 +1554,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000520000050010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000b20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -03000000d62000000b20000001010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux, 03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, @@ -1577,7 +1613,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 0300132d9b2800006500000001010000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, 030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, 030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800006100000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux, +030000009b2800006400000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux, 030000009b2800008000000020020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux, +030000009b2800008000000001010000,Raphnet Wii Classic Adapter V3,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux, 03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, @@ -1611,6 +1650,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00001311000011010000,Saffun Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Linux, 03000000a306000023f6000011010000,Saitek Cyborg PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, 03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux, 03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux, @@ -1711,6 +1751,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, 03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, 03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, +03000000790000001a18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000790000001b18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, 030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, 05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, @@ -1738,6 +1780,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000dd02000003020000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, @@ -1752,6 +1795,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000011050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000014050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000120b000015050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, @@ -1761,13 +1806,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 050000005e040000130b000011050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000017050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -030000005e040000120b000014050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, -050000005e040000130b000017050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, -060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000130b000022050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, @@ -1789,7 +1833,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android, 34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android, -38426974446f204e4743204d6f646b69,8BitDo GameCube,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b18,paddle2:b17,rightshoulder:b15,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b1,y:b3,platform:Android, +38426974446f204e4743204d6f646b69,8BitDo GameCube,a:b0,b:b2,back:b4,dpdown:b12,dpleft:b13,dpright:b14,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b18,paddle2:b17,rightshoulder:b15,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b1,y:b3,platform:Android, 38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, @@ -1903,6 +1947,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, 38383665633039363066383334653465,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, 39363561613936303237333537383931,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +39373064396565646338333134303131,Joy-Con (R),a:b1,b:b2,back:b5,leftstick:b8,leftx:a1~,lefty:a0,start:b6,x:b0,y:b3,platform:Android, 4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, 39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, 63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android, @@ -1910,7 +1955,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -39653365373864633935383236363438,Logitech G Butt,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39653365373864633935383236363438,Logitech G Cloud,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, 4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, @@ -1936,6 +1981,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android, 050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android, +31316661666466633938376335383661,Nintendo Switch Pro Controller,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,start:b6,x:b3,y:b2,platform:Android, 34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android, 36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android, @@ -1999,6 +2045,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android, 526574726f696420506f636b65742043,Retroid Pocket,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 582d426f7820436f6e74726f6c6c6572,Retroid Pocket,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +64633735616665613536653363336132,Retroid Pocket,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b19,paddle2:b20,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, 38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,start:b6,platform:Android, 37393234373533633333323633646531,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android, @@ -2059,8 +2106,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, 35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, -36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65316262316265373335666131623538,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, 050000005e040000000b000000783f80,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, 050000005e040000050b0000ffff3f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, @@ -2081,17 +2129,22 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, 05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, 05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, +05000000ac05000004000000a8986d04,8BitDo Micro gamepad,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,lefttrigger:b12,rightshoulder:b13,righttrigger:b14,start:b3,x:b6,y:b5,platform:iOS, +05000000ac05000004000000fd216d04,8BitDo Pro 2,a:b3,b:b2,back:b6,dpdown:b9,dpleft:b10,dpright:b11,dpup:b12,guide:b4,leftshoulder:b13,leftstick:b14,lefttrigger:+a2,leftx:a0,lefty:a1~,paddle1:b1,paddle2:b0,rightshoulder:b16,rightstick:b17,righttrigger:+a5,rightx:a3,righty:a4~,start:b5,x:b8,y:b7,platform:iOS, +05000000ac05000004000000209f6d04,8Bitdo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,platform:iOS, +05000000ac050000040000003b8a6d04,8BitDo SN30 Pro+,a:b1,b:b0,back:b4,dpdown:b7,dpleft:b8,dpright:b9,dpup:b10,guide:b2,leftshoulder:b11,leftstick:b12,lefttrigger:b13,leftx:a0,lefty:a1~,rightshoulder:b14,rightstick:b15,righttrigger:b16,rightx:a2,righty:a3~,start:b3,x:b6,y:b5,platform:iOS, 050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, 050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, 4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS, 4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS, 050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS, 050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,platform:iOS, -050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, 050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, -050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,platform:iOS, +050000007e050000072000000f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS, +050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS, 050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, -050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,platform:iOS, 050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, 050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, 050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, @@ -2103,9 +2156,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS, 05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, 05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, -050000005e040000050b0000df070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, -050000005e040000050b0000ff070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, -050000005e040000e0020000df070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, -050000005e040000e0020000ff070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000050b0000df070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000050b0000ff070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, 050000005e040000130b0000df870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, -050000005e040000130b0000ff870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, \ No newline at end of file +050000005e040000130b0000ff870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000e0020000df070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, \ No newline at end of file diff --git a/vendor/sdl3/image/SDL3_image.dll b/vendor/sdl3/image/SDL3_image.dll index a45e44530..2ba20a7cf 100644 Binary files a/vendor/sdl3/image/SDL3_image.dll and b/vendor/sdl3/image/SDL3_image.dll differ diff --git a/vendor/sdl3/image/include/SDL_image.h b/vendor/sdl3/image/include/SDL_image.h index 9775ee616..60d041fe6 100644 --- a/vendor/sdl3/image/include/SDL_image.h +++ b/vendor/sdl3/image/include/SDL_image.h @@ -45,7 +45,7 @@ extern "C" { */ #define SDL_IMAGE_MAJOR_VERSION 3 #define SDL_IMAGE_MINOR_VERSION 2 -#define SDL_IMAGE_MICRO_VERSION 0 +#define SDL_IMAGE_MICRO_VERSION 4 /** * This is the version number macro for the current SDL_image version. diff --git a/vendor/sdl3/image/sdl_image.odin b/vendor/sdl3/image/sdl_image.odin index 4712c7f3c..d2c628a86 100644 --- a/vendor/sdl3/image/sdl_image.odin +++ b/vendor/sdl3/image/sdl_image.odin @@ -11,7 +11,7 @@ when ODIN_OS == .Windows { MAJOR_VERSION :: 3 MINOR_VERSION :: 2 -PATCHLEVEL :: 0 +PATCHLEVEL :: 4 Animation :: struct { w, h: c.int, @@ -89,12 +89,12 @@ foreign lib { ReadXPMFromArrayToRGB888 :: proc(xpm: [^]cstring) -> ^SDL.Surface --- /* Individual saving functions */ - SaveAVIF :: proc(surface: ^SDL.Surface, file: cstring, quality: c.int) -> c.int --- - SaveAVIF_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.int --- - SavePNG :: proc(surface: ^SDL.Surface, file: cstring) -> c.int --- - SavePNG_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool) -> c.int --- - SaveJPG :: proc(surface: ^SDL.Surface, file: cstring, quality: c.int) -> c.int --- - SaveJPG_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.int --- + SaveAVIF :: proc(surface: ^SDL.Surface, file: cstring, quality: c.int) -> c.bool --- + SaveAVIF_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.bool --- + SavePNG :: proc(surface: ^SDL.Surface, file: cstring) -> c.bool --- + SavePNG_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool) -> c.bool --- + SaveJPG :: proc(surface: ^SDL.Surface, file: cstring, quality: c.int) -> c.bool --- + SaveJPG_IO :: proc(surface: ^SDL.Surface, dst: ^SDL.IOStream, closeio: bool, quality: c.int) -> c.bool --- LoadAnimation :: proc(file: cstring) -> ^Animation --- LoadAnimation_IO :: proc(src: ^SDL.IOStream, closeio: bool) -> ^Animation --- diff --git a/vendor/sdl3/include/SDL.h b/vendor/sdl3/include/SDL.h index 861c404f5..ed1b32483 100644 --- a/vendor/sdl3/include/SDL.h +++ b/vendor/sdl3/include/SDL.h @@ -20,7 +20,7 @@ */ /** - * Main include header for the SDL library, version 3.2.0 + * Main include header for the SDL library, version 3.2.16 * * It is almost always best to include just this one header instead of * picking out individual headers included here. There are exceptions to diff --git a/vendor/sdl3/include/SDL_assert.h b/vendor/sdl3/include/SDL_assert.h index 09b3b478f..6c90acc02 100644 --- a/vendor/sdl3/include/SDL_assert.h +++ b/vendor/sdl3/include/SDL_assert.h @@ -149,6 +149,8 @@ extern "C" { #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "bkpt #22\n\t" ) #elif defined(_WIN32) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__arm64__) || defined(__aarch64__)) ) #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "brk #0xF000\n\t" ) +#elif defined(__GNUC__) || defined(__clang__) + #define SDL_TriggerBreakpoint() __builtin_trap() /* older gcc may not support SDL_HAS_BUILTIN(__builtin_trap) above */ #elif defined(__386__) && defined(__WATCOMC__) #define SDL_TriggerBreakpoint() { _asm { int 0x03 } } #elif defined(HAVE_SIGNAL_H) && !defined(__WATCOMC__) diff --git a/vendor/sdl3/include/SDL_atomic.h b/vendor/sdl3/include/SDL_atomic.h index 03e3fb134..78b5e0fa5 100644 --- a/vendor/sdl3/include/SDL_atomic.h +++ b/vendor/sdl3/include/SDL_atomic.h @@ -498,7 +498,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_AddAtomicInt(SDL_AtomicInt *a, int v); * * ***Note: If you don't know what this macro is for, you shouldn't use it!*** * - * \param a a pointer to an SDL_AtomicInt to increment. + * \param a a pointer to an SDL_AtomicInt to decrement. * \returns true if the variable reached zero after decrementing, false * otherwise. * diff --git a/vendor/sdl3/include/SDL_audio.h b/vendor/sdl3/include/SDL_audio.h index 956938215..c6acf885f 100644 --- a/vendor/sdl3/include/SDL_audio.h +++ b/vendor/sdl3/include/SDL_audio.h @@ -781,7 +781,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsAudioDevicePlayback(SDL_AudioDeviceID dev * Physical devices can not be paused or unpaused, only logical devices * created through SDL_OpenAudioDevice() can be. * - * \param dev a device opened by SDL_OpenAudioDevice(). + * \param devid a device opened by SDL_OpenAudioDevice(). * \returns true on success or false on failure; call SDL_GetError() for more * information. * @@ -792,7 +792,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsAudioDevicePlayback(SDL_AudioDeviceID dev * \sa SDL_ResumeAudioDevice * \sa SDL_AudioDevicePaused */ -extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev); +extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID devid); /** * Use this function to unpause audio playback on a specified device. @@ -809,7 +809,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev); * Physical devices can not be paused or unpaused, only logical devices * created through SDL_OpenAudioDevice() can be. * - * \param dev a device opened by SDL_OpenAudioDevice(). + * \param devid a device opened by SDL_OpenAudioDevice(). * \returns true on success or false on failure; call SDL_GetError() for more * information. * @@ -820,7 +820,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev); * \sa SDL_AudioDevicePaused * \sa SDL_PauseAudioDevice */ -extern SDL_DECLSPEC bool SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID dev); +extern SDL_DECLSPEC bool SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID devid); /** * Use this function to query if an audio device is paused. @@ -832,7 +832,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID dev); * created through SDL_OpenAudioDevice() can be. Physical and invalid device * IDs will report themselves as unpaused here. * - * \param dev a device opened by SDL_OpenAudioDevice(). + * \param devid a device opened by SDL_OpenAudioDevice(). * \returns true if device is valid and paused, false otherwise. * * \threadsafety It is safe to call this function from any thread. @@ -842,7 +842,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID dev); * \sa SDL_PauseAudioDevice * \sa SDL_ResumeAudioDevice */ -extern SDL_DECLSPEC bool SDLCALL SDL_AudioDevicePaused(SDL_AudioDeviceID dev); +extern SDL_DECLSPEC bool SDLCALL SDL_AudioDevicePaused(SDL_AudioDeviceID devid); /** * Get the gain of an audio device. @@ -1583,6 +1583,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioStreamDevice(SDL_AudioStream *str * previously been paused. Once unpaused, any bound audio streams will begin * to progress again, and audio can be generated. * + * Remember, SDL_OpenAudioDeviceStream opens device in a paused state, so this + * function call is required for audio playback to begin on such device. + * * \param stream the audio stream associated with the audio device to resume. * \returns true on success or false on failure; call SDL_GetError() for more * information. @@ -1714,7 +1717,7 @@ typedef void (SDLCALL *SDL_AudioStreamCallback)(void *userdata, SDL_AudioStream * audio to the stream during this call; if needed, the request that triggered * this callback will obtain the new data immediately. * - * The callback's `approx_request` argument is roughly how many bytes of + * The callback's `additional_amount` argument is roughly how many bytes of * _unconverted_ data (in the stream's input format) is needed by the caller, * although this may overestimate a little for safety. This takes into account * how much is already in the stream and only asks for any extra necessary to @@ -1759,13 +1762,13 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioStreamGetCallback(SDL_AudioStream * * The callback can (optionally) call SDL_GetAudioStreamData() to obtain audio * from the stream during this call. * - * The callback's `approx_request` argument is how many bytes of _converted_ - * data (in the stream's output format) was provided by the caller, although - * this may underestimate a little for safety. This value might be less than - * what is currently available in the stream, if data was already there, and - * might be less than the caller provided if the stream needs to keep a buffer - * to aid in resampling. Which means the callback may be provided with zero - * bytes, and a different amount on each call. + * The callback's `additional_amount` argument is how many bytes of + * _converted_ data (in the stream's output format) was provided by the + * caller, although this may underestimate a little for safety. This value + * might be less than what is currently available in the stream, if data was + * already there, and might be less than the caller provided if the stream + * needs to keep a buffer to aid in resampling. Which means the callback may + * be provided with zero bytes, and a different amount on each call. * * The callback may call SDL_GetAudioStreamAvailable to see the total amount * currently available to read from the stream, instead of the total provided diff --git a/vendor/sdl3/include/SDL_camera.h b/vendor/sdl3/include/SDL_camera.h index c4d05962b..5f3911fdf 100644 --- a/vendor/sdl3/include/SDL_camera.h +++ b/vendor/sdl3/include/SDL_camera.h @@ -239,7 +239,7 @@ extern SDL_DECLSPEC SDL_CameraID * SDLCALL SDL_GetCameras(int *count); * there _is_ a camera until the user has given you permission to check * through a scary warning popup. * - * \param devid the camera device instance ID to query. + * \param instance_id the camera device instance ID. * \param count a pointer filled in with the number of elements in the list, * may be NULL. * \returns a NULL terminated array of pointers to SDL_CameraSpec or NULL on @@ -254,7 +254,7 @@ extern SDL_DECLSPEC SDL_CameraID * SDLCALL SDL_GetCameras(int *count); * \sa SDL_GetCameras * \sa SDL_OpenCamera */ -extern SDL_DECLSPEC SDL_CameraSpec ** SDLCALL SDL_GetCameraSupportedFormats(SDL_CameraID devid, int *count); +extern SDL_DECLSPEC SDL_CameraSpec ** SDLCALL SDL_GetCameraSupportedFormats(SDL_CameraID instance_id, int *count); /** * Get the human-readable device name for a camera. diff --git a/vendor/sdl3/include/SDL_dialog.h b/vendor/sdl3/include/SDL_dialog.h index 460038ff2..ddb9e24d5 100644 --- a/vendor/sdl3/include/SDL_dialog.h +++ b/vendor/sdl3/include/SDL_dialog.h @@ -84,8 +84,8 @@ typedef struct SDL_DialogFileFilter * - A pointer to NULL, the user either didn't choose any file or canceled the * dialog. * - A pointer to non-`NULL`, the user chose one or more files. The argument - * is a null-terminated list of pointers to C strings, each containing a - * path. + * is a null-terminated array of pointers to UTF-8 encoded strings, each + * containing a path. * * The filelist argument should not be freed; it will automatically be freed * when the callback returns. diff --git a/vendor/sdl3/include/SDL_events.h b/vendor/sdl3/include/SDL_events.h index 1323e9f0b..d267f051f 100644 --- a/vendor/sdl3/include/SDL_events.h +++ b/vendor/sdl3/include/SDL_events.h @@ -132,7 +132,7 @@ typedef enum SDL_EventType /* Window events */ /* 0x200 was SDL_WINDOWEVENT, reserve the number for sdl2-compat */ - /* 0x201 was SDL_EVENT_SYSWM, reserve the number for sdl2-compat */ + /* 0x201 was SDL_SYSWMEVENT, reserve the number for sdl2-compat */ SDL_EVENT_WINDOW_SHOWN = 0x202, /**< Window has been shown */ SDL_EVENT_WINDOW_HIDDEN, /**< Window has been hidden */ SDL_EVENT_WINDOW_EXPOSED, /**< Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event */ @@ -492,6 +492,8 @@ typedef struct SDL_MouseWheelEvent SDL_MouseWheelDirection direction; /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */ float mouse_x; /**< X coordinate, relative to window */ float mouse_y; /**< Y coordinate, relative to window */ + Sint32 integer_x; /**< The amount scrolled horizontally, accumulated to whole scroll "ticks" (added in 3.2.12) */ + Sint32 integer_y; /**< The amount scrolled vertically, accumulated to whole scroll "ticks" (added in 3.2.12) */ } SDL_MouseWheelEvent; /** @@ -1108,7 +1110,7 @@ typedef enum SDL_EventAction * \param numevents if action is SDL_ADDEVENT, the number of events to add * back to the event queue; if action is SDL_PEEKEVENT or * SDL_GETEVENT, the maximum number of events to retrieve. - * \param action action to take; see [[#action|Remarks]] for details. + * \param action action to take; see [Remarks](#remarks) for details. * \param minType minimum value of the event type to be considered; * SDL_EVENT_FIRST is a safe choice. * \param maxType maximum value of the event type to be considered; diff --git a/vendor/sdl3/include/SDL_gamepad.h b/vendor/sdl3/include/SDL_gamepad.h index 264f763b2..99f8b6593 100644 --- a/vendor/sdl3/include/SDL_gamepad.h +++ b/vendor/sdl3/include/SDL_gamepad.h @@ -29,7 +29,7 @@ * "joysticks" now are actually console-style gamepads. So SDL provides the * gamepad API on top of the lower-level joystick functionality. * - * The difference betweena joystick and a gamepad is that a gamepad tells you + * The difference between a joystick and a gamepad is that a gamepad tells you * _where_ a button or axis is on the device. You don't speak to gamepads in * terms of arbitrary numbers like "button 3" or "axis 2" but in standard * locations: the d-pad, the shoulder buttons, triggers, A/B/X/Y (or diff --git a/vendor/sdl3/include/SDL_gpu.h b/vendor/sdl3/include/SDL_gpu.h index fa870a579..b61661909 100644 --- a/vendor/sdl3/include/SDL_gpu.h +++ b/vendor/sdl3/include/SDL_gpu.h @@ -35,13 +35,14 @@ * can render offscreen entirely, perhaps for image processing, and not use a * window at all. * - * Next the app prepares static data (things that are created once and used + * Next, the app prepares static data (things that are created once and used * over and over). For example: * * - Shaders (programs that run on the GPU): use SDL_CreateGPUShader(). - * - Vertex buffers (arrays of geometry data) and other data rendering will - * need: use SDL_UploadToGPUBuffer(). - * - Textures (images): use SDL_UploadToGPUTexture(). + * - Vertex buffers (arrays of geometry data) and other rendering data: use + * SDL_CreateGPUBuffer() and SDL_UploadToGPUBuffer(). + * - Textures (images): use SDL_CreateGPUTexture() and + * SDL_UploadToGPUTexture(). * - Samplers (how textures should be read from): use SDL_CreateGPUSampler(). * - Render pipelines (precalculated rendering state): use * SDL_CreateGPUGraphicsPipeline() @@ -130,7 +131,8 @@ * It is optimal for apps to pre-compile the shader formats they might use, * but for ease of use SDL provides a separate project, * [SDL_shadercross](https://github.com/libsdl-org/SDL_shadercross) - * , for performing runtime shader cross-compilation. + * , for performing runtime shader cross-compilation. It also has a CLI + * interface for offline precompilation as well. * * This is an extremely quick overview that leaves out several important * details. Already, though, one can see that GPU programming can be quite @@ -888,6 +890,10 @@ typedef enum SDL_GPUCubeMapFace * Unlike textures, READ | WRITE can be used for simultaneous read-write * usage. The same data synchronization concerns as textures apply. * + * If you use a STORAGE flag, the data in the buffer must respect std140 + * layout conventions. In practical terms this means you must ensure that vec3 + * and vec4 fields are 16-byte aligned. + * * \since This datatype is available since SDL 3.2.0. * * \sa SDL_CreateGPUBuffer @@ -1361,6 +1367,7 @@ typedef struct SDL_GPUTextureLocation * * \sa SDL_UploadToGPUTexture * \sa SDL_DownloadFromGPUTexture + * \sa SDL_CreateGPUTexture */ typedef struct SDL_GPUTextureRegion { @@ -1489,9 +1496,16 @@ typedef struct SDL_GPUIndirectDispatchCommand /** * A structure specifying the parameters of a sampler. * + * Note that mip_lod_bias is a no-op for the Metal driver. For Metal, LOD bias + * must be applied via shader instead. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateGPUSampler + * \sa SDL_GPUFilter + * \sa SDL_GPUSamplerMipmapMode + * \sa SDL_GPUSamplerAddressMode + * \sa SDL_GPUCompareOp */ typedef struct SDL_GPUSamplerCreateInfo { @@ -1530,14 +1544,14 @@ typedef struct SDL_GPUSamplerCreateInfo * \since This struct is available since SDL 3.2.0. * * \sa SDL_GPUVertexAttribute - * \sa SDL_GPUVertexInputState + * \sa SDL_GPUVertexInputRate */ typedef struct SDL_GPUVertexBufferDescription { Uint32 slot; /**< The binding slot of the vertex buffer. */ Uint32 pitch; /**< The byte pitch between consecutive elements of the vertex buffer. */ SDL_GPUVertexInputRate input_rate; /**< Whether attribute addressing is a function of the vertex index or instance index. */ - Uint32 instance_step_rate; /**< The number of instances to draw using the same per-instance data before advancing in the instance buffer by one element. Ignored unless input_rate is SDL_GPU_VERTEXINPUTRATE_INSTANCE */ + Uint32 instance_step_rate; /**< Reserved for future use. Must be set to 0. */ } SDL_GPUVertexBufferDescription; /** @@ -1550,6 +1564,7 @@ typedef struct SDL_GPUVertexBufferDescription * * \sa SDL_GPUVertexBufferDescription * \sa SDL_GPUVertexInputState + * \sa SDL_GPUVertexElementFormat */ typedef struct SDL_GPUVertexAttribute { @@ -1706,10 +1721,13 @@ typedef struct SDL_GPUTransferBufferCreateInfo * A structure specifying the parameters of the graphics pipeline rasterizer * state. * - * NOTE: Some backend APIs (D3D11/12) will enable depth clamping even if - * enable_depth_clip is true. If you rely on this clamp+clip behavior, - * consider enabling depth clip and then manually clamping depth in your - * fragment shaders on Metal and Vulkan. + * Note that SDL_GPU_FILLMODE_LINE is not supported on many Android devices. + * For those devices, the fill mode will automatically fall back to FILL. + * + * Also note that the D3D12 driver will enable depth clamping even if + * enable_depth_clip is true. If you need this clamp+clip behavior, consider + * enabling depth clip and then manually clamping depth in your fragment + * shaders on Metal and Vulkan. * * \since This struct is available since SDL 3.2.0. * @@ -1740,8 +1758,8 @@ typedef struct SDL_GPURasterizerState typedef struct SDL_GPUMultisampleState { SDL_GPUSampleCount sample_count; /**< The number of samples to be used in rasterization. */ - Uint32 sample_mask; /**< Determines which samples get updated in the render targets. Treated as 0xFFFFFFFF if enable_mask is false. */ - bool enable_mask; /**< Enables sample masking. */ + Uint32 sample_mask; /**< Reserved for future use. Must be set to 0. */ + bool enable_mask; /**< Reserved for future use. Must be set to false. */ Uint8 padding1; Uint8 padding2; Uint8 padding3; @@ -1791,6 +1809,8 @@ typedef struct SDL_GPUColorTargetDescription * \since This struct is available since SDL 3.2.0. * * \sa SDL_GPUGraphicsPipelineCreateInfo + * \sa SDL_GPUColorTargetDescription + * \sa SDL_GPUTextureFormat */ typedef struct SDL_GPUGraphicsPipelineTargetInfo { @@ -1809,6 +1829,7 @@ typedef struct SDL_GPUGraphicsPipelineTargetInfo * \since This struct is available since SDL 3.2.0. * * \sa SDL_CreateGPUGraphicsPipeline + * \sa SDL_GPUShader * \sa SDL_GPUVertexInputState * \sa SDL_GPUPrimitiveType * \sa SDL_GPURasterizerState @@ -1836,6 +1857,7 @@ typedef struct SDL_GPUGraphicsPipelineCreateInfo * \since This struct is available since SDL 3.2.0. * * \sa SDL_CreateGPUComputePipeline + * \sa SDL_GPUShaderFormat */ typedef struct SDL_GPUComputePipelineCreateInfo { @@ -2104,7 +2126,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUSupportsProperties( * \sa SDL_DestroyGPUDevice * \sa SDL_GPUSupportsShaderFormats */ -extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDevice( +extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice( SDL_GPUShaderFormat format_flags, bool debug_mode, const char *name); @@ -2152,7 +2174,7 @@ extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDevice( * \sa SDL_DestroyGPUDevice * \sa SDL_GPUSupportsProperties */ -extern SDL_DECLSPEC SDL_GPUDevice *SDLCALL SDL_CreateGPUDeviceWithProperties( +extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties( SDL_PropertiesID props); #define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN "SDL.gpu.device.create.debugmode" @@ -2275,7 +2297,7 @@ extern SDL_DECLSPEC SDL_GPUShaderFormat SDLCALL SDL_GetGPUShaderFormats(SDL_GPUD * \sa SDL_BindGPUComputePipeline * \sa SDL_ReleaseGPUComputePipeline */ -extern SDL_DECLSPEC SDL_GPUComputePipeline *SDLCALL SDL_CreateGPUComputePipeline( +extern SDL_DECLSPEC SDL_GPUComputePipeline * SDLCALL SDL_CreateGPUComputePipeline( SDL_GPUDevice *device, const SDL_GPUComputePipelineCreateInfo *createinfo); @@ -2302,7 +2324,7 @@ extern SDL_DECLSPEC SDL_GPUComputePipeline *SDLCALL SDL_CreateGPUComputePipeline * \sa SDL_BindGPUGraphicsPipeline * \sa SDL_ReleaseGPUGraphicsPipeline */ -extern SDL_DECLSPEC SDL_GPUGraphicsPipeline *SDLCALL SDL_CreateGPUGraphicsPipeline( +extern SDL_DECLSPEC SDL_GPUGraphicsPipeline * SDLCALL SDL_CreateGPUGraphicsPipeline( SDL_GPUDevice *device, const SDL_GPUGraphicsPipelineCreateInfo *createinfo); @@ -2329,7 +2351,7 @@ extern SDL_DECLSPEC SDL_GPUGraphicsPipeline *SDLCALL SDL_CreateGPUGraphicsPipeli * \sa SDL_BindGPUFragmentSamplers * \sa SDL_ReleaseGPUSampler */ -extern SDL_DECLSPEC SDL_GPUSampler *SDLCALL SDL_CreateGPUSampler( +extern SDL_DECLSPEC SDL_GPUSampler * SDLCALL SDL_CreateGPUSampler( SDL_GPUDevice *device, const SDL_GPUSamplerCreateInfo *createinfo); @@ -2408,7 +2430,7 @@ extern SDL_DECLSPEC SDL_GPUSampler *SDLCALL SDL_CreateGPUSampler( * \sa SDL_CreateGPUGraphicsPipeline * \sa SDL_ReleaseGPUShader */ -extern SDL_DECLSPEC SDL_GPUShader *SDLCALL SDL_CreateGPUShader( +extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_CreateGPUShader( SDL_GPUDevice *device, const SDL_GPUShaderCreateInfo *createinfo); @@ -2445,9 +2467,9 @@ extern SDL_DECLSPEC SDL_GPUShader *SDLCALL SDL_CreateGPUShader( * - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT`: (Direct3D 12 only) * if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, clear * the texture to a depth of this value. Defaults to zero. - * - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8`: (Direct3D 12 + * - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER`: (Direct3D 12 * only) if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, - * clear the texture to a stencil of this value. Defaults to zero. + * clear the texture to a stencil of this Uint8 value. Defaults to zero. * - `SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING`: a name that can be displayed * in debugging tools. * @@ -2469,17 +2491,17 @@ extern SDL_DECLSPEC SDL_GPUShader *SDLCALL SDL_CreateGPUShader( * \sa SDL_ReleaseGPUTexture * \sa SDL_GPUTextureSupportsFormat */ -extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_CreateGPUTexture( +extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL SDL_CreateGPUTexture( SDL_GPUDevice *device, const SDL_GPUTextureCreateInfo *createinfo); -#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r" -#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g" -#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b" -#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a" -#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth" -#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8 "SDL.gpu.texture.create.d3d12.clear.stencil" -#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name" +#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT "SDL.gpu.texture.create.d3d12.clear.r" +#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT "SDL.gpu.texture.create.d3d12.clear.g" +#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT "SDL.gpu.texture.create.d3d12.clear.b" +#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT "SDL.gpu.texture.create.d3d12.clear.a" +#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT "SDL.gpu.texture.create.d3d12.clear.depth" +#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER "SDL.gpu.texture.create.d3d12.clear.stencil" +#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING "SDL.gpu.texture.create.name" /** * Creates a buffer object to be used in graphics or compute workflows. @@ -2490,6 +2512,10 @@ extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_CreateGPUTexture( * Note that certain combinations of usage flags are invalid. For example, a * buffer cannot have both the VERTEX and INDEX flags. * + * If you use a STORAGE flag, the data in the buffer must respect std140 + * layout conventions. In practical terms this means you must ensure that vec3 + * and vec4 fields are 16-byte aligned. + * * For better understanding of underlying concepts and memory management with * SDL GPU API, you may refer * [this blog post](https://moonside.games/posts/sdl-gpu-concepts-cycling/) @@ -2521,7 +2547,7 @@ extern SDL_DECLSPEC SDL_GPUTexture *SDLCALL SDL_CreateGPUTexture( * \sa SDL_DispatchGPUComputeIndirect * \sa SDL_ReleaseGPUBuffer */ -extern SDL_DECLSPEC SDL_GPUBuffer *SDLCALL SDL_CreateGPUBuffer( +extern SDL_DECLSPEC SDL_GPUBuffer * SDLCALL SDL_CreateGPUBuffer( SDL_GPUDevice *device, const SDL_GPUBufferCreateInfo *createinfo); @@ -2554,7 +2580,7 @@ extern SDL_DECLSPEC SDL_GPUBuffer *SDLCALL SDL_CreateGPUBuffer( * \sa SDL_DownloadFromGPUTexture * \sa SDL_ReleaseGPUTransferBuffer */ -extern SDL_DECLSPEC SDL_GPUTransferBuffer *SDLCALL SDL_CreateGPUTransferBuffer( +extern SDL_DECLSPEC SDL_GPUTransferBuffer * SDLCALL SDL_CreateGPUTransferBuffer( SDL_GPUDevice *device, const SDL_GPUTransferBufferCreateInfo *createinfo); @@ -2782,7 +2808,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseGPUGraphicsPipeline( * \sa SDL_SubmitGPUCommandBuffer * \sa SDL_SubmitGPUCommandBufferAndAcquireFence */ -extern SDL_DECLSPEC SDL_GPUCommandBuffer *SDLCALL SDL_AcquireGPUCommandBuffer( +extern SDL_DECLSPEC SDL_GPUCommandBuffer * SDLCALL SDL_AcquireGPUCommandBuffer( SDL_GPUDevice *device); /* Uniform Data */ @@ -2792,6 +2818,10 @@ extern SDL_DECLSPEC SDL_GPUCommandBuffer *SDLCALL SDL_AcquireGPUCommandBuffer( * * Subsequent draw calls will use this uniform data. * + * The data being pushed must respect std140 layout conventions. In practical + * terms this means you must ensure that vec3 and vec4 fields are 16-byte + * aligned. + * * \param command_buffer a command buffer. * \param slot_index the vertex uniform slot to push data to. * \param data client data to write. @@ -2810,6 +2840,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUVertexUniformData( * * Subsequent draw calls will use this uniform data. * + * The data being pushed must respect std140 layout conventions. In practical + * terms this means you must ensure that vec3 and vec4 fields are 16-byte + * aligned. + * * \param command_buffer a command buffer. * \param slot_index the fragment uniform slot to push data to. * \param data client data to write. @@ -2828,6 +2862,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUFragmentUniformData( * * Subsequent draw calls will use this uniform data. * + * The data being pushed must respect std140 layout conventions. In practical + * terms this means you must ensure that vec3 and vec4 fields are 16-byte + * aligned. + * * \param command_buffer a command buffer. * \param slot_index the uniform slot to push data to. * \param data client data to write. @@ -2868,7 +2906,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_PushGPUComputeUniformData( * * \sa SDL_EndGPURenderPass */ -extern SDL_DECLSPEC SDL_GPURenderPass *SDLCALL SDL_BeginGPURenderPass( +extern SDL_DECLSPEC SDL_GPURenderPass * SDLCALL SDL_BeginGPURenderPass( SDL_GPUCommandBuffer *command_buffer, const SDL_GPUColorTargetInfo *color_target_infos, Uint32 num_color_targets, @@ -2978,6 +3016,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUIndexBuffer( * * The textures must have been created with SDL_GPU_TEXTUREUSAGE_SAMPLER. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the vertex sampler slot to begin binding from. * \param texture_sampler_bindings an array of texture-sampler binding @@ -2986,6 +3027,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUIndexBuffer( * array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexSamplers( SDL_GPURenderPass *render_pass, @@ -2999,12 +3042,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexSamplers( * These textures must have been created with * SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the vertex storage texture slot to begin binding from. * \param storage_textures an array of storage textures. * \param num_bindings the number of storage texture to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageTextures( SDL_GPURenderPass *render_pass, @@ -3018,12 +3066,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageTextures( * These buffers must have been created with * SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the vertex storage buffer slot to begin binding from. * \param storage_buffers an array of buffers. * \param num_bindings the number of buffers to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageBuffers( SDL_GPURenderPass *render_pass, @@ -3036,6 +3089,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageBuffers( * * The textures must have been created with SDL_GPU_TEXTUREUSAGE_SAMPLER. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the fragment sampler slot to begin binding from. * \param texture_sampler_bindings an array of texture-sampler binding @@ -3044,6 +3100,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUVertexStorageBuffers( * array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentSamplers( SDL_GPURenderPass *render_pass, @@ -3057,12 +3115,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentSamplers( * These textures must have been created with * SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the fragment storage texture slot to begin binding from. * \param storage_textures an array of storage textures. * \param num_bindings the number of storage textures to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentStorageTextures( SDL_GPURenderPass *render_pass, @@ -3076,12 +3139,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentStorageTextures( * These buffers must have been created with * SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param render_pass a render pass handle. * \param first_slot the fragment storage buffer slot to begin binding from. * \param storage_buffers an array of storage buffers. * \param num_bindings the number of storage buffers to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUFragmentStorageBuffers( SDL_GPURenderPass *render_pass, @@ -3245,7 +3313,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_EndGPURenderPass( * * \sa SDL_EndGPUComputePass */ -extern SDL_DECLSPEC SDL_GPUComputePass *SDLCALL SDL_BeginGPUComputePass( +extern SDL_DECLSPEC SDL_GPUComputePass * SDLCALL SDL_BeginGPUComputePass( SDL_GPUCommandBuffer *command_buffer, const SDL_GPUStorageTextureReadWriteBinding *storage_texture_bindings, Uint32 num_storage_texture_bindings, @@ -3269,6 +3337,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputePipeline( * * The textures must have been created with SDL_GPU_TEXTUREUSAGE_SAMPLER. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param compute_pass a compute pass handle. * \param first_slot the compute sampler slot to begin binding from. * \param texture_sampler_bindings an array of texture-sampler binding @@ -3277,6 +3348,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputePipeline( * array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeSamplers( SDL_GPUComputePass *compute_pass, @@ -3290,12 +3363,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeSamplers( * These textures must have been created with * SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param compute_pass a compute pass handle. * \param first_slot the compute storage texture slot to begin binding from. * \param storage_textures an array of storage textures. * \param num_bindings the number of storage textures to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageTextures( SDL_GPUComputePass *compute_pass, @@ -3309,12 +3387,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageTextures( * These buffers must have been created with * SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ. * + * Be sure your shader is set up according to the requirements documented in + * SDL_CreateGPUShader(). + * * \param compute_pass a compute pass handle. * \param first_slot the compute storage buffer slot to begin binding from. * \param storage_buffers an array of storage buffer binding structs. * \param num_bindings the number of storage buffers to bind from the array. * * \since This function is available since SDL 3.2.0. + * + * \sa SDL_CreateGPUShader */ extern SDL_DECLSPEC void SDLCALL SDL_BindGPUComputeStorageBuffers( SDL_GPUComputePass *compute_pass, @@ -3389,7 +3472,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_EndGPUComputePass( /** * Maps a transfer buffer into application address space. * - * You must unmap the transfer buffer before encoding upload commands. + * You must unmap the transfer buffer before encoding upload commands. The + * memory is owned by the graphics driver - do NOT call SDL_free() on the + * returned pointer. * * \param device a GPU context. * \param transfer_buffer a transfer buffer. @@ -3399,7 +3484,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_EndGPUComputePass( * * \since This function is available since SDL 3.2.0. */ -extern SDL_DECLSPEC void *SDLCALL SDL_MapGPUTransferBuffer( +extern SDL_DECLSPEC void * SDLCALL SDL_MapGPUTransferBuffer( SDL_GPUDevice *device, SDL_GPUTransferBuffer *transfer_buffer, bool cycle); @@ -3430,7 +3515,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnmapGPUTransferBuffer( * * \since This function is available since SDL 3.2.0. */ -extern SDL_DECLSPEC SDL_GPUCopyPass *SDLCALL SDL_BeginGPUCopyPass( +extern SDL_DECLSPEC SDL_GPUCopyPass * SDLCALL SDL_BeginGPUCopyPass( SDL_GPUCommandBuffer *command_buffer); /** @@ -3690,7 +3775,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseWindowFromGPUDevice( * supported via SDL_WindowSupportsGPUPresentMode / * SDL_WindowSupportsGPUSwapchainComposition prior to calling this function. * - * SDL_GPU_PRESENTMODE_VSYNC and SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always + * SDL_GPU_PRESENTMODE_VSYNC with SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always * supported. * * \param device a GPU context. @@ -3848,6 +3933,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain( * freed by the user. You MUST NOT call this function from any thread other * than the one that created the window. * + * The swapchain texture is write-only and cannot be used as a sampler or for + * another reading operation. + * * \param command_buffer a command buffer. * \param window a window that has been claimed. * \param swapchain_texture a pointer filled in with a swapchain texture @@ -3866,6 +3954,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WaitForGPUSwapchain( * * \sa SDL_SubmitGPUCommandBuffer * \sa SDL_SubmitGPUCommandBufferAndAcquireFence + * \sa SDL_AcquireGPUSwapchainTexture */ extern SDL_DECLSPEC bool SDLCALL SDL_WaitAndAcquireGPUSwapchainTexture( SDL_GPUCommandBuffer *command_buffer, @@ -3922,7 +4011,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SubmitGPUCommandBuffer( * \sa SDL_SubmitGPUCommandBuffer * \sa SDL_ReleaseGPUFence */ -extern SDL_DECLSPEC SDL_GPUFence *SDLCALL SDL_SubmitGPUCommandBufferAndAcquireFence( +extern SDL_DECLSPEC SDL_GPUFence * SDLCALL SDL_SubmitGPUCommandBufferAndAcquireFence( SDL_GPUCommandBuffer *command_buffer); /** @@ -4004,6 +4093,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_QueryGPUFence( /** * Releases a fence obtained from SDL_SubmitGPUCommandBufferAndAcquireFence. * + * You must not reference the fence after calling this function. + * * \param device a GPU context. * \param fence a fence. * @@ -4054,7 +4145,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUTextureSupportsFormat( * \param device a GPU context. * \param format the texture format to check. * \param sample_count the sample count to check. - * \returns a hardware-specific version of min(preferred, possible). + * \returns whether the sample count is supported for this texture format. * * \since This function is available since SDL 3.2.0. */ diff --git a/vendor/sdl3/include/SDL_guid.h b/vendor/sdl3/include/SDL_guid.h index e2f32ffc9..312c42c03 100644 --- a/vendor/sdl3/include/SDL_guid.h +++ b/vendor/sdl3/include/SDL_guid.h @@ -71,6 +71,8 @@ typedef struct SDL_GUID { * \param pszGUID buffer in which to write the ASCII string. * \param cbGUID the size of pszGUID, should be at least 33 bytes. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_StringToGUID @@ -87,6 +89,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_GUIDToString(SDL_GUID guid, char *pszGUID, * \param pchGUID string containing an ASCII representation of a GUID. * \returns a SDL_GUID structure. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GUIDToString diff --git a/vendor/sdl3/include/SDL_hints.h b/vendor/sdl3/include/SDL_hints.h index 8f2d074d1..a08153571 100644 --- a/vendor/sdl3/include/SDL_hints.h +++ b/vendor/sdl3/include/SDL_hints.h @@ -1074,8 +1074,8 @@ extern "C" { * * By default, SDL will try all available GPU backends in a reasonable order * until it finds one that can work, but this hint allows the app or user to - * force a specific target, such as "direct3d11" if, say, your hardware - * supports D3D12 but want to try using D3D11 instead. + * force a specific target, such as "direct3d12" if, say, your hardware + * supports Vulkan but you want to try using D3D12 instead. * * This hint should be set before any GPU functions are called. * @@ -2026,8 +2026,8 @@ extern "C" { * * The variable can be set to the following values: * - * - "0": RAWINPUT drivers are not used. - * - "1": RAWINPUT drivers are used. (default) + * - "0": RAWINPUT drivers are not used. (default) + * - "1": RAWINPUT drivers are used. * * This hint should be set before SDL is initialized. * @@ -2191,6 +2191,28 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_ZERO_CENTERED_DEVICES "SDL_JOYSTICK_ZERO_CENTERED_DEVICES" +/** + * A variable containing a list of devices and their desired number of haptic + * (force feedback) enabled axis. + * + * The format of the string is a comma separated list of USB VID/PID pairs in + * hexadecimal form plus the number of desired axes, e.g. + * + * `0xAAAA/0xBBBB/1,0xCCCC/0xDDDD/3` + * + * This hint supports a "wildcard" device that will set the number of haptic + * axes on all initialized haptic devices which were not defined explicitly in + * this hint. + * + * `0xFFFF/0xFFFF/1` + * + * This hint should be set before a controller is opened. The number of haptic + * axes won't exceed the number of real axes found on the device. + * + * \since This hint is available since SDL 3.2.5. + */ +#define SDL_HINT_JOYSTICK_HAPTIC_AXES "SDL_JOYSTICK_HAPTIC_AXES" + /** * A variable that controls keycode representation in keyboard events. * @@ -2349,8 +2371,8 @@ extern "C" { #define SDL_HINT_MAC_OPENGL_ASYNC_DISPATCH "SDL_MAC_OPENGL_ASYNC_DISPATCH" /** - * A variable controlling whether the Option (⌥) key on macOS should be - * remapped to act as the Alt key. + * A variable controlling whether the Option key on macOS should be remapped + * to act as the Alt key. * * The variable can be set to the following values: * @@ -3585,6 +3607,22 @@ extern "C" { */ #define SDL_HINT_VIDEO_WIN_D3DCOMPILER "SDL_VIDEO_WIN_D3DCOMPILER" +/** + * A variable controlling whether SDL should call XSelectInput() to enable + * input events on X11 windows wrapped by SDL windows. + * + * The variable can be set to the following values: + * + * - "0": Don't call XSelectInput(), assuming the native window code has done + * it already. + * - "1": Call XSelectInput() to enable input events. (default) + * + * This hint should be set before creating a window. + * + * \since This hint is available since SDL 3.2.10. + */ +#define SDL_HINT_VIDEO_X11_EXTERNAL_WINDOW_INPUT "SDL_VIDEO_X11_EXTERNAL_WINDOW_INPUT" + /** * A variable controlling whether the X11 _NET_WM_BYPASS_COMPOSITOR hint * should be used. @@ -4360,7 +4398,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ResetHints(void); * \sa SDL_SetHint * \sa SDL_SetHintWithPriority */ -extern SDL_DECLSPEC const char *SDLCALL SDL_GetHint(const char *name); +extern SDL_DECLSPEC const char * SDLCALL SDL_GetHint(const char *name); /** * Get the boolean value of a hint variable. diff --git a/vendor/sdl3/include/SDL_init.h b/vendor/sdl3/include/SDL_init.h index adf0de8a2..27ebe4b0e 100644 --- a/vendor/sdl3/include/SDL_init.h +++ b/vendor/sdl3/include/SDL_init.h @@ -79,7 +79,7 @@ typedef Uint32 SDL_InitFlags; #define SDL_INIT_AUDIO 0x00000010u /**< `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` */ #define SDL_INIT_VIDEO 0x00000020u /**< `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread */ -#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD */ +#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS` */ #define SDL_INIT_HAPTIC 0x00001000u #define SDL_INIT_GAMEPAD 0x00002000u /**< `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` */ #define SDL_INIT_EVENTS 0x00004000u diff --git a/vendor/sdl3/include/SDL_log.h b/vendor/sdl3/include/SDL_log.h index a56476c6d..3fd7ec2ed 100644 --- a/vendor/sdl3/include/SDL_log.h +++ b/vendor/sdl3/include/SDL_log.h @@ -41,8 +41,8 @@ * "system", "audio", "video", "render", "input", "test", or `*` for any * unspecified category. * - * The level can be a numeric level, one of "verbose", "debug", "info", - * "warn", "error", "critical", or "quiet" to disable that category. + * The level can be a numeric level, one of "trace", "verbose", "debug", + * "info", "warn", "error", "critical", or "quiet" to disable that category. * * You can omit the category if you want to set the logging level for all * categories. @@ -56,6 +56,15 @@ * - Windows: debug output stream * - Android: log output * - Others: standard error output (stderr) + * + * You don't need to have a newline (`\n`) on the end of messages, the + * functions will do that for you. For consistent behavior cross-platform, you + * shouldn't have any newlines in messages, such as to log multiple lines in + * one call; unusual platform-specific behavior can be observed in such usage. + * Do one log call per line instead, with no newlines in messages. + * + * Each log call is atomic, so you won't see log messages cut off one another + * when logging from multiple threads. */ #ifndef SDL_log_h_ diff --git a/vendor/sdl3/include/SDL_main.h b/vendor/sdl3/include/SDL_main.h index 2e7a2ebb6..905d78e96 100644 --- a/vendor/sdl3/include/SDL_main.h +++ b/vendor/sdl3/include/SDL_main.h @@ -28,6 +28,9 @@ * should look like this: * * ```c + * #include + * #include + * * int main(int argc, char *argv[]) * { * } @@ -38,9 +41,9 @@ * This is also where an app can be configured to use the main callbacks, via * the SDL_MAIN_USE_CALLBACKS macro. * - * This is a "single-header library," which is to say that including this - * header inserts code into your program, and you should only include it once - * in most cases. SDL.h does not include this header automatically. + * SDL_main.h is a "single-header library," which is to say that including + * this header inserts code into your program, and you should only include it + * once in most cases. SDL.h does not include this header automatically. * * For more information, see: * diff --git a/vendor/sdl3/include/SDL_mouse.h b/vendor/sdl3/include/SDL_mouse.h index 18856e20e..864135d2b 100644 --- a/vendor/sdl3/include/SDL_mouse.h +++ b/vendor/sdl3/include/SDL_mouse.h @@ -353,7 +353,7 @@ extern SDL_DECLSPEC SDL_MouseButtonFlags SDLCALL SDL_GetRelativeMouseState(float * * \sa SDL_WarpMouseGlobal */ -extern SDL_DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window * window, +extern SDL_DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window *window, float x, float y); /** @@ -514,8 +514,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CaptureMouse(bool enabled); * \sa SDL_DestroyCursor * \sa SDL_SetCursor */ -extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 * data, - const Uint8 * mask, +extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 *data, + const Uint8 *mask, int w, int h, int hot_x, int hot_y); diff --git a/vendor/sdl3/include/SDL_pixels.h b/vendor/sdl3/include/SDL_pixels.h index b6f38acbe..39596c1c9 100644 --- a/vendor/sdl3/include/SDL_pixels.h +++ b/vendor/sdl3/include/SDL_pixels.h @@ -517,7 +517,7 @@ typedef enum SDL_PackedLayout * ABGR32, define a platform-independent encoding into bytes in the order * specified. For example, in RGB24 data, each pixel is encoded in 3 bytes * (red, green, blue) in that order, and in ABGR32 data, each pixel is - * encoded in 4 bytes alpha, blue, green, red) in that order. Use these + * encoded in 4 bytes (alpha, blue, green, red) in that order. Use these * names if the property of a format that is important to you is the order * of the bytes in memory or on disk. * - Names with a bit count per component, such as ARGB8888 and XRGB1555, are @@ -676,6 +676,9 @@ typedef enum SDL_PixelFormat SDL_PIXELFORMAT_EXTERNAL_OES = 0x2053454fu, /**< Android video texture format */ /* SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ') */ + SDL_PIXELFORMAT_MJPG = 0x47504a4du, /**< Motion JPEG */ + /* SDL_DEFINE_PIXELFOURCC('M', 'J', 'P', 'G') */ + /* Aliases for RGBA byte arrays of color data, for the current platform */ #if SDL_BYTEORDER == SDL_BIG_ENDIAN SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_RGBA8888, diff --git a/vendor/sdl3/include/SDL_platform_defines.h b/vendor/sdl3/include/SDL_platform_defines.h index 7e9a0a92a..6b240a8be 100644 --- a/vendor/sdl3/include/SDL_platform_defines.h +++ b/vendor/sdl3/include/SDL_platform_defines.h @@ -471,8 +471,6 @@ * \since This macro is available since SDL 3.2.0. */ #define SDL_PLATFORM_3DS 1 - -#undef __3DS__ #endif #endif /* SDL_platform_defines_h_ */ diff --git a/vendor/sdl3/include/SDL_power.h b/vendor/sdl3/include/SDL_power.h index 4056ce3c8..694fb0924 100644 --- a/vendor/sdl3/include/SDL_power.h +++ b/vendor/sdl3/include/SDL_power.h @@ -79,6 +79,10 @@ typedef enum SDL_PowerState * It's possible a platform can only report battery percentage or time left * but not both. * + * On some platforms, retrieving power supply details might be expensive. If + * you want to display continuous status you could call this function every + * minute or so. + * * \param seconds a pointer filled in with the seconds of battery life left, * or NULL to ignore. This will be filled in with -1 if we * can't determine a value or there is no battery. diff --git a/vendor/sdl3/include/SDL_process.h b/vendor/sdl3/include/SDL_process.h index 2cc77395b..511b2f9c5 100644 --- a/vendor/sdl3/include/SDL_process.h +++ b/vendor/sdl3/include/SDL_process.h @@ -103,7 +103,7 @@ typedef struct SDL_Process SDL_Process; * \sa SDL_WaitProcess * \sa SDL_DestroyProcess */ -extern SDL_DECLSPEC SDL_Process *SDLCALL SDL_CreateProcess(const char * const *args, bool pipe_stdio); +extern SDL_DECLSPEC SDL_Process * SDLCALL SDL_CreateProcess(const char * const *args, bool pipe_stdio); /** * Description of where standard I/O should be directed when creating a @@ -173,13 +173,13 @@ typedef enum SDL_ProcessIO * standard input when `SDL_PROP_PROCESS_CREATE_STDIN_NUMBER` is set to * `SDL_PROCESS_STDIO_REDIRECT`. * - `SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER`: an SDL_ProcessIO value - * describing where standard output for the process goes go, defaults to + * describing where standard output for the process goes to, defaults to * `SDL_PROCESS_STDIO_INHERITED`. * - `SDL_PROP_PROCESS_CREATE_STDOUT_POINTER`: an SDL_IOStream pointer used * for standard output when `SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER` is set * to `SDL_PROCESS_STDIO_REDIRECT`. * - `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER`: an SDL_ProcessIO value - * describing where standard error for the process goes go, defaults to + * describing where standard error for the process goes to, defaults to * `SDL_PROCESS_STDIO_INHERITED`. * - `SDL_PROP_PROCESS_CREATE_STDERR_POINTER`: an SDL_IOStream pointer used * for standard error when `SDL_PROP_PROCESS_CREATE_STDERR_NUMBER` is set to @@ -215,7 +215,7 @@ typedef enum SDL_ProcessIO * \sa SDL_WaitProcess * \sa SDL_DestroyProcess */ -extern SDL_DECLSPEC SDL_Process *SDLCALL SDL_CreateProcessWithProperties(SDL_PropertiesID props); +extern SDL_DECLSPEC SDL_Process * SDLCALL SDL_CreateProcessWithProperties(SDL_PropertiesID props); #define SDL_PROP_PROCESS_CREATE_ARGS_POINTER "SDL.process.create.args" #define SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER "SDL.process.create.environment" @@ -320,7 +320,7 @@ extern SDL_DECLSPEC void * SDLCALL SDL_ReadProcess(SDL_Process *process, size_t * \sa SDL_CreateProcessWithProperties * \sa SDL_GetProcessOutput */ -extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessInput(SDL_Process *process); +extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_GetProcessInput(SDL_Process *process); /** * Get the SDL_IOStream associated with process standard output. @@ -344,7 +344,7 @@ extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessInput(SDL_Process *proce * \sa SDL_CreateProcessWithProperties * \sa SDL_GetProcessInput */ -extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessOutput(SDL_Process *process); +extern SDL_DECLSPEC SDL_IOStream * SDLCALL SDL_GetProcessOutput(SDL_Process *process); /** * Stop a process. diff --git a/vendor/sdl3/include/SDL_rect.h b/vendor/sdl3/include/SDL_rect.h index 8998de6f4..eb2d34a69 100644 --- a/vendor/sdl3/include/SDL_rect.h +++ b/vendor/sdl3/include/SDL_rect.h @@ -371,7 +371,7 @@ SDL_FORCE_INLINE bool SDL_RectEmptyFloat(const SDL_FRect *r) * * \sa SDL_RectsEqualFloat */ -SDL_FORCE_INLINE bool SDL_RectsEqualEpsilon(const SDL_FRect *a, const SDL_FRect *b, const float epsilon) +SDL_FORCE_INLINE bool SDL_RectsEqualEpsilon(const SDL_FRect *a, const SDL_FRect *b, float epsilon) { return (a && b && ((a == b) || ((SDL_fabsf(a->x - b->x) <= epsilon) && diff --git a/vendor/sdl3/include/SDL_render.h b/vendor/sdl3/include/SDL_render.h index 891e99452..c9d184cc0 100644 --- a/vendor/sdl3/include/SDL_render.h +++ b/vendor/sdl3/include/SDL_render.h @@ -490,6 +490,9 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetRendererProperties(SDL_Rende * This returns the true output size in pixels, ignoring any render targets or * logical size and presentation. * + * For the output size of the current rendering target, with logical size + * adjustments, use SDL_GetCurrentRenderOutputSize() instead. + * * \param renderer the rendering context. * \param w a pointer filled in with the width in pixels. * \param h a pointer filled in with the height in pixels. @@ -508,9 +511,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderOutputSize(SDL_Renderer *renderer, * Get the current output size in pixels of a rendering context. * * If a rendering target is active, this will return the size of the rendering - * target in pixels, otherwise if a logical size is set, it will return the - * logical size, otherwise it will return the value of - * SDL_GetRenderOutputSize(). + * target in pixels, otherwise return the value of SDL_GetRenderOutputSize(). + * + * Rendering target or not, the output will be adjusted by the current logical + * presentation state, dictated by SDL_SetRenderLogicalPresentation(). * * \param renderer the rendering context. * \param w a pointer filled in with the current width. @@ -1318,6 +1322,11 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockTexture(SDL_Texture *texture); * To stop rendering to a texture and render to the window again, call this * function with a NULL `texture`. * + * Viewport, cliprect, scale, and logical presentation are unique to each + * render target. Get and set functions for these states apply to the current + * render target set by this function, and those states persist on each target + * when the current render target changes. + * * \param renderer the rendering context. * \param texture the targeted texture, which must be created with the * `SDL_TEXTUREACCESS_TARGET` flag, or NULL to render to the @@ -1351,25 +1360,39 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderTarget(SDL_Renderer *renderer, SDL extern SDL_DECLSPEC SDL_Texture * SDLCALL SDL_GetRenderTarget(SDL_Renderer *renderer); /** - * Set a device independent resolution and presentation mode for rendering. + * Set a device-independent resolution and presentation mode for rendering. * * This function sets the width and height of the logical rendering output. - * The renderer will act as if the window is always the requested dimensions, - * scaling to the actual window resolution as necessary. + * The renderer will act as if the current render target is always the + * requested dimensions, scaling to the actual resolution as necessary. * * This can be useful for games that expect a fixed size, but would like to * scale the output to whatever is available, regardless of how a user resizes * a window, or if the display is high DPI. * + * Logical presentation can be used with both render target textures and the + * renderer's window; the state is unique to each render target, and this + * function sets the state for the current render target. It might be useful + * to draw to a texture that matches the window dimensions with logical + * presentation enabled, and then draw that texture across the entire window + * with logical presentation disabled. Be careful not to render both with + * logical presentation enabled, however, as this could produce + * double-letterboxing, etc. + * * You can disable logical coordinates by setting the mode to * SDL_LOGICAL_PRESENTATION_DISABLED, and in that case you get the full pixel - * resolution of the output window; it is safe to toggle logical presentation + * resolution of the render target; it is safe to toggle logical presentation * during the rendering of a frame: perhaps most of the rendering is done to * specific dimensions but to make fonts look sharp, the app turns off logical - * presentation while drawing text. + * presentation while drawing text, for example. * - * Letterboxing will only happen if logical presentation is enabled during - * SDL_RenderPresent; be sure to reenable it first if you were using it. + * For the renderer's window, letterboxing is drawn into the framebuffer if + * logical presentation is enabled during SDL_RenderPresent; be sure to + * reenable it before presenting if you were toggling it, otherwise the + * letterbox areas might have artifacts from previous frames (or artifacts + * from external overlays, etc). Letterboxing is never drawn into texture + * render targets; be sure to call SDL_RenderClear() before drawing into the + * texture so the letterboxing areas are cleared, if appropriate. * * You can convert coordinates in an event into rendering coordinates using * SDL_ConvertEventToRenderCoordinates(). @@ -1397,6 +1420,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderLogicalPresentation(SDL_Renderer * * This function gets the width and height of the logical rendering output, or * the output size in pixels if a logical resolution is not enabled. * + * Each render target has its own logical presentation state. This function + * gets the state for the current render target. + * * \param renderer the rendering context. * \param w an int to be filled with the width. * \param h an int to be filled with the height. @@ -1420,6 +1446,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderLogicalPresentation(SDL_Renderer * * presentation is disabled, it will fill the rectangle with the output size, * in pixels. * + * Each render target has its own logical presentation state. This function + * gets the rectangle for the current render target. + * * \param renderer the rendering context. * \param rect a pointer filled in with the final presentation rectangle, may * be NULL. @@ -1536,6 +1565,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertEventToRenderCoordinates(SDL_Rendere * * The area's width and height must be >= 0. * + * Each render target has its own viewport. This function sets the viewport + * for the current render target. + * * \param renderer the rendering context. * \param rect the SDL_Rect structure representing the drawing area, or NULL * to set the viewport to the entire target. @@ -1554,6 +1586,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderViewport(SDL_Renderer *renderer, c /** * Get the drawing area for the current target. * + * Each render target has its own viewport. This function gets the viewport + * for the current render target. + * * \param renderer the rendering context. * \param rect an SDL_Rect structure filled in with the current drawing area. * \returns true on success or false on failure; call SDL_GetError() for more @@ -1572,8 +1607,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, S * Return whether an explicit rectangle was set as the viewport. * * This is useful if you're saving and restoring the viewport and want to know - * whether you should restore a specific rectangle or NULL. Note that the - * viewport is always reset when changing rendering targets. + * whether you should restore a specific rectangle or NULL. + * + * Each render target has its own viewport. This function checks the viewport + * for the current render target. * * \param renderer the rendering context. * \returns true if the viewport was set to a specific rectangle, or false if @@ -1613,6 +1650,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderSafeArea(SDL_Renderer *renderer, S /** * Set the clip rectangle for rendering on the specified target. * + * Each render target has its own clip rectangle. This function sets the + * cliprect for the current render target. + * * \param renderer the rendering context. * \param rect an SDL_Rect structure representing the clip area, relative to * the viewport, or NULL to disable clipping. @@ -1631,6 +1671,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, c /** * Get the clip rectangle for the current target. * + * Each render target has its own clip rectangle. This function gets the + * cliprect for the current render target. + * * \param renderer the rendering context. * \param rect an SDL_Rect structure filled in with the current clipping area * or an empty rectangle if clipping is disabled. @@ -1647,7 +1690,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderClipRect(SDL_Renderer *renderer, c extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderClipRect(SDL_Renderer *renderer, SDL_Rect *rect); /** - * Get whether clipping is enabled on the given renderer. + * Get whether clipping is enabled on the given render target. + * + * Each render target has its own clip rectangle. This function checks the + * cliprect for the current render target. * * \param renderer the rendering context. * \returns true if clipping is enabled or false if not; call SDL_GetError() @@ -1673,6 +1719,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderClipEnabled(SDL_Renderer *renderer); * will be handled using the appropriate quality hints. For best results use * integer scaling factors. * + * Each render target has its own scale. This function sets the scale for the + * current render target. + * * \param renderer the rendering context. * \param scaleX the horizontal scaling factor. * \param scaleY the vertical scaling factor. @@ -1690,6 +1739,9 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderScale(SDL_Renderer *renderer, floa /** * Get the drawing scale for the current target. * + * Each render target has its own scale. This function gets the scale for the + * current render target. + * * \param renderer the rendering context. * \param scaleX a pointer filled in with the horizontal scaling factor. * \param scaleY a pointer filled in with the vertical scaling factor. @@ -2247,15 +2299,21 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer, /** * Read pixels from the current rendering target. * - * The returned surface should be freed with SDL_DestroySurface() + * The returned surface contains pixels inside the desired area clipped to the + * current viewport, and should be freed with SDL_DestroySurface(). + * + * Note that this returns the actual pixels on the screen, so if you are using + * logical presentation you should use SDL_GetRenderLogicalPresentationRect() + * to get the area containing your content. * * **WARNING**: This is a very slow operation, and should not be used * frequently. If you're using this on the main rendering target, it should be * called after rendering and before SDL_RenderPresent(). * * \param renderer the rendering context. - * \param rect an SDL_Rect structure representing the area in pixels relative - * to the to current viewport, or NULL for the entire viewport. + * \param rect an SDL_Rect structure representing the area to read, which will + * be clipped to the current viewport, or NULL for the entire + * viewport. * \returns a new SDL_Surface on success or NULL on failure; call * SDL_GetError() for more information. * diff --git a/vendor/sdl3/include/SDL_revision.h b/vendor/sdl3/include/SDL_revision.h index 18f7c4d6c..9fb9937d9 100644 --- a/vendor/sdl3/include/SDL_revision.h +++ b/vendor/sdl3/include/SDL_revision.h @@ -48,9 +48,9 @@ */ #define SDL_REVISION "Some arbitrary string decided at SDL build time" #elif defined(SDL_VENDOR_INFO) -#define SDL_REVISION "release-3.2.0-0-g535d80bad (" SDL_VENDOR_INFO ")" +#define SDL_REVISION "release-3.2.16-0-gc9a6709bd (" SDL_VENDOR_INFO ")" #else -#define SDL_REVISION "release-3.2.0-0-g535d80bad" +#define SDL_REVISION "release-3.2.16-0-gc9a6709bd" #endif #endif /* SDL_revision_h_ */ diff --git a/vendor/sdl3/include/SDL_stdinc.h b/vendor/sdl3/include/SDL_stdinc.h index 4e15a3c64..7df253fec 100644 --- a/vendor/sdl3/include/SDL_stdinc.h +++ b/vendor/sdl3/include/SDL_stdinc.h @@ -1299,8 +1299,11 @@ extern "C" { * * If `size` is 0, it will be set to 1. * - * If you want to allocate memory aligned to a specific alignment, consider - * using SDL_aligned_alloc(). + * If the allocation is successful, the returned pointer is guaranteed to be + * aligned to either the *fundamental alignment* (`alignof(max_align_t)` in + * C11 and later) or `2 * sizeof(void *)`, whichever is smaller. Use + * SDL_aligned_alloc() if you need to allocate memory aligned to an alignment + * greater than this guarantee. * * \param size the size to allocate. * \returns a pointer to the allocated memory, or NULL if allocation failed. @@ -1323,6 +1326,10 @@ extern SDL_DECLSPEC SDL_MALLOC void * SDLCALL SDL_malloc(size_t size); * * If either of `nmemb` or `size` is 0, they will both be set to 1. * + * If the allocation is successful, the returned pointer is guaranteed to be + * aligned to either the *fundamental alignment* (`alignof(max_align_t)` in + * C11 and later) or `2 * sizeof(void *)`, whichever is smaller. + * * \param nmemb the number of elements in the array. * \param size the size of each element of the array. * \returns a pointer to the allocated array, or NULL if allocation failed. @@ -1357,6 +1364,11 @@ extern SDL_DECLSPEC SDL_MALLOC SDL_ALLOC_SIZE2(1, 2) void * SDLCALL SDL_calloc(s * - If it returns NULL (indicating failure), then `mem` will remain valid and * must still be freed with SDL_free(). * + * If the allocation is successfully resized, the returned pointer is + * guaranteed to be aligned to either the *fundamental alignment* + * (`alignof(max_align_t)` in C11 and later) or `2 * sizeof(void *)`, + * whichever is smaller. + * * \param mem a pointer to allocated memory to reallocate, or NULL. * \param size the new size of the memory. * \returns a pointer to the newly allocated memory, or NULL if allocation @@ -4243,14 +4255,14 @@ extern SDL_DECLSPEC int SDLCALL SDL_vasprintf(char **strp, SDL_PRINTF_FORMAT_STR /** * Seeds the pseudo-random number generator. * - * Reusing the seed number will cause SDL_rand_*() to repeat the same stream - * of 'random' numbers. + * Reusing the seed number will cause SDL_rand() to repeat the same stream of + * 'random' numbers. * * \param seed the value to use as a random number seed, or 0 to use * SDL_GetPerformanceCounter(). * * \threadsafety This should be called on the same thread that calls - * SDL_rand*() + * SDL_rand() * * \since This function is available since SDL 3.2.0. * @@ -4644,7 +4656,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_atanf(float x); * * Domain: `-INF <= x <= INF`, `-INF <= y <= INF` * - * Range: `-Pi/2 <= y <= Pi/2` + * Range: `-Pi <= y <= Pi` * * This function operates on double-precision floating point values, use * SDL_atan2f for single-precision floats. @@ -4680,7 +4692,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_atan2(double y, double x); * * Domain: `-INF <= x <= INF`, `-INF <= y <= INF` * - * Range: `-Pi/2 <= y <= Pi/2` + * Range: `-Pi <= y <= Pi` * * This function operates on single-precision floating point values, use * SDL_atan2 for double-precision floats. @@ -4701,7 +4713,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_atan2(double y, double x); * * \since This function is available since SDL 3.2.0. * - * \sa SDL_atan2f + * \sa SDL_atan2 * \sa SDL_atan * \sa SDL_tan */ @@ -4810,7 +4822,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_copysign(double x, double y); * * \since This function is available since SDL 3.2.0. * - * \sa SDL_copysignf + * \sa SDL_copysign * \sa SDL_fabsf */ extern SDL_DECLSPEC float SDLCALL SDL_copysignf(float x, float y); @@ -4943,7 +4955,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_expf(float x); * Range: `0 <= y <= INF` * * This function operates on double-precision floating point values, use - * SDL_copysignf for single-precision floats. + * SDL_fabsf for single-precision floats. * * \param x floating point value to use as the magnitude. * \returns the absolute value of `x`. @@ -4964,7 +4976,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_fabs(double x); * Range: `0 <= y <= INF` * * This function operates on single-precision floating point values, use - * SDL_copysignf for double-precision floats. + * SDL_fabs for double-precision floats. * * \param x floating point value to use as the magnitude. * \returns the absolute value of `x`. @@ -5016,7 +5028,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_floor(double x); * Range: `-INF <= y <= INF`, y integer * * This function operates on single-precision floating point values, use - * SDL_floorf for double-precision floats. + * SDL_floor for double-precision floats. * * \param x floating point value. * \returns the floor of `x`. @@ -5073,7 +5085,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_trunc(double x); * Range: `-INF <= y <= INF`, y integer * * This function operates on single-precision floating point values, use - * SDL_truncf for double-precision floats. + * SDL_trunc for double-precision floats. * * \param x floating point value. * \returns `x` truncated to an integer. @@ -5131,7 +5143,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_fmod(double x, double y); * Range: `-y <= z <= y` * * This function operates on single-precision floating point values, use - * SDL_fmod for single-precision floats. + * SDL_fmod for double-precision floats. * * \param x the numerator. * \param y the denominator. Must not be 0. @@ -5409,7 +5421,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_pow(double x, double y); * instead. * * This function operates on single-precision floating point values, use - * SDL_powf for double-precision floats. + * SDL_pow for double-precision floats. * * This function may use a different approximation across different versions, * platforms and configurations. i.e, it can return a different value given @@ -5469,8 +5481,8 @@ extern SDL_DECLSPEC double SDLCALL SDL_round(double x); * * Range: `-INF <= y <= INF`, y integer * - * This function operates on double-precision floating point values, use - * SDL_roundf for single-precision floats. To get the result as an integer + * This function operates on single-precision floating point values, use + * SDL_round for double-precision floats. To get the result as an integer * type, use SDL_lroundf. * * \param x floating point value. @@ -5499,7 +5511,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_roundf(float x); * Range: `MIN_LONG <= y <= MAX_LONG` * * This function operates on double-precision floating point values, use - * SDL_lround for single-precision floats. To get the result as a + * SDL_lroundf for single-precision floats. To get the result as a * floating-point type, use SDL_round. * * \param x floating point value. @@ -5528,8 +5540,8 @@ extern SDL_DECLSPEC long SDLCALL SDL_lround(double x); * Range: `MIN_LONG <= y <= MAX_LONG` * * This function operates on single-precision floating point values, use - * SDL_lroundf for double-precision floats. To get the result as a - * floating-point type, use SDL_roundf, + * SDL_lround for double-precision floats. To get the result as a + * floating-point type, use SDL_roundf. * * \param x floating point value. * \returns the nearest integer to `x`. @@ -5742,7 +5754,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_tan(double x); * Range: `-INF <= y <= INF` * * This function operates on single-precision floating point values, use - * SDL_tanf for double-precision floats. + * SDL_tan for double-precision floats. * * This function may use a different approximation across different versions, * platforms and configurations. i.e, it can return a different value given @@ -5962,14 +5974,17 @@ size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t size); size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t size); #endif +#ifndef _WIN32 /* strdup is not ANSI but POSIX, and its prototype might be hidden... */ +/* not for windows: might conflict with string.h where strdup may have + * dllimport attribute: https://github.com/libsdl-org/SDL/issues/12948 */ char *strdup(const char *str); +#endif /* Starting LLVM 16, the analyser errors out if these functions do not have their prototype defined (clang-diagnostic-implicit-function-declaration) */ #include #include -#include #define SDL_malloc malloc #define SDL_calloc calloc diff --git a/vendor/sdl3/include/SDL_storage.h b/vendor/sdl3/include/SDL_storage.h index 8b89ace18..6837ebaac 100644 --- a/vendor/sdl3/include/SDL_storage.h +++ b/vendor/sdl3/include/SDL_storage.h @@ -450,7 +450,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_CloseStorage(SDL_Storage *storage); * * This function should be called in regular intervals until it returns true - * however, it is not recommended to spinwait on this call, as the backend may - * depend on a synchronous message loop. + * depend on a synchronous message loop. You might instead poll this in your + * game's main loop while processing events and drawing a loading screen. * * \param storage a storage container to query. * \returns true if the container is ready, false otherwise. @@ -636,10 +637,10 @@ extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetStorageSpaceRemaining(SDL_Storage *sto * Enumerate a directory tree, filtered by pattern, and return a list. * * Files are filtered out if they don't match the string in `pattern`, which - * may contain wildcard characters '*' (match everything) and '?' (match one + * may contain wildcard characters `*` (match everything) and `?` (match one * character). If pattern is NULL, no filtering is done and all results are * returned. Subdirectories are permitted, and are specified with a path - * separator of '/'. Wildcard characters '*' and '?' never match a path + * separator of '/'. Wildcard characters `*` and `?` never match a path * separator. * * `flags` may be set to SDL_GLOB_CASEINSENSITIVE to make the pattern matching diff --git a/vendor/sdl3/include/SDL_surface.h b/vendor/sdl3/include/SDL_surface.h index 0752f5307..15fce042f 100644 --- a/vendor/sdl3/include/SDL_surface.h +++ b/vendor/sdl3/include/SDL_surface.h @@ -73,7 +73,7 @@ typedef Uint32 SDL_SurfaceFlags; * * \since This macro is available since SDL 3.2.0. */ -#define SDL_MUSTLOCK(S) ((((S)->flags & SDL_SURFACE_LOCK_NEEDED)) == SDL_SURFACE_LOCK_NEEDED) +#define SDL_MUSTLOCK(S) (((S)->flags & SDL_SURFACE_LOCK_NEEDED) == SDL_SURFACE_LOCK_NEEDED) /** * The scaling mode. @@ -82,6 +82,7 @@ typedef Uint32 SDL_SurfaceFlags; */ typedef enum SDL_ScaleMode { + SDL_SCALEMODE_INVALID = -1, SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */ SDL_SCALEMODE_LINEAR /**< linear filtering */ } SDL_ScaleMode; @@ -120,6 +121,9 @@ typedef enum SDL_FlipMode * format with a pitch of 32 would consist of 32x32 bytes of Y plane followed * by 32x16 bytes of UV plane. * + * When a surface holds MJPG format data, pixels points at the compressed JPEG + * image and pitch is the length of that data. + * * \since This struct is available since SDL 3.2.0. * * \sa SDL_CreateSurface @@ -153,6 +157,8 @@ typedef struct SDL_Surface SDL_Surface; * \returns the new SDL_Surface structure that is created or NULL on failure; * call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateSurfaceFrom @@ -181,6 +187,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_CreateSurface(int width, int heigh * \returns the new SDL_Surface structure that is created or NULL on failure; * call SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateSurface @@ -195,6 +203,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_CreateSurfaceFrom(int width, int h * * \param surface the SDL_Surface to free. * + * \threadsafety No other thread should be using the surface when it is freed. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreateSurface @@ -221,11 +231,17 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface); * the same tone mapping that Chrome uses for HDR content, the form "*=N", * where N is a floating point scale factor applied in linear space, and * "none", which disables tone mapping. This defaults to "chrome". + * - `SDL_PROP_SURFACE_HOTSPOT_X_NUMBER`: the hotspot pixel offset from the + * left edge of the image, if this surface is being used as a cursor. + * - `SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER`: the hotspot pixel offset from the + * top edge of the image, if this surface is being used as a cursor. * * \param surface the SDL_Surface structure to query. * \returns a valid property ID on success or 0 on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *surface); @@ -233,6 +249,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac #define SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT "SDL.surface.SDR_white_point" #define SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT "SDL.surface.HDR_headroom" #define SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap" +#define SDL_PROP_SURFACE_HOTSPOT_X_NUMBER "SDL.surface.hotspot.x" +#define SDL_PROP_SURFACE_HOTSPOT_Y_NUMBER "SDL.surface.hotspot.y" /** * Set the colorspace used by a surface. @@ -246,6 +264,8 @@ extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surfac * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetSurfaceColorspace @@ -263,6 +283,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorspace(SDL_Surface *surface, * \returns the colorspace used by the surface, or SDL_COLORSPACE_UNKNOWN if * the surface is NULL. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetSurfaceColorspace @@ -291,6 +313,8 @@ extern SDL_DECLSPEC SDL_Colorspace SDLCALL SDL_GetSurfaceColorspace(SDL_Surface * the surface didn't have an index format); call SDL_GetError() for * more information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetPaletteColors @@ -307,6 +331,8 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_CreateSurfacePalette(SDL_Surface * * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_CreatePalette @@ -321,6 +347,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfacePalette(SDL_Surface *surface, SDL * \returns a pointer to the palette used by the surface, or NULL if there is * no palette used. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetSurfacePalette @@ -344,6 +372,8 @@ extern SDL_DECLSPEC SDL_Palette * SDLCALL SDL_GetSurfacePalette(SDL_Surface *sur * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_RemoveSurfaceAlternateImages @@ -358,6 +388,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_AddSurfaceAlternateImage(SDL_Surface *surfa * \param surface the SDL_Surface structure to query. * \returns true if alternate versions are available or false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_AddSurfaceAlternateImage @@ -383,6 +415,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasAlternateImages(SDL_Surface *surf * failure; call SDL_GetError() for more information. This should be * freed with SDL_free() when it is no longer needed. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_AddSurfaceAlternateImage @@ -399,6 +433,8 @@ extern SDL_DECLSPEC SDL_Surface ** SDLCALL SDL_GetSurfaceImages(SDL_Surface *sur * * \param surface the SDL_Surface structure to update. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_AddSurfaceAlternateImage @@ -423,6 +459,10 @@ extern SDL_DECLSPEC void SDLCALL SDL_RemoveSurfaceAlternateImages(SDL_Surface *s * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. The locking referred to by + * this function is making the pixels available for direct + * access, not thread-safe locking. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_MUSTLOCK @@ -435,6 +475,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_LockSurface(SDL_Surface *surface); * * \param surface the SDL_Surface structure to be unlocked. * + * \threadsafety This function is not thread safe. The locking referred to by + * this function is making the pixels available for direct + * access, not thread-safe locking. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LockSurface @@ -453,6 +497,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnlockSurface(SDL_Surface *surface); * \returns a pointer to a new SDL_Surface structure or NULL on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_DestroySurface @@ -471,6 +517,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadBMP_IO(SDL_IOStream *src, bool * \returns a pointer to a new SDL_Surface structure or NULL on failure; call * SDL_GetError() for more information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_DestroySurface @@ -495,6 +543,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_LoadBMP(const char *file); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LoadBMP_IO @@ -516,6 +566,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP_IO(SDL_Surface *surface, SDL_IOStre * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_LoadBMP @@ -534,6 +586,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SaveBMP(SDL_Surface *surface, const char *f * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_BlitSurface @@ -550,6 +604,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceRLE(SDL_Surface *surface, bool en * \param surface the SDL_Surface structure to query. * \returns true if the surface is RLE enabled, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetSurfaceRLE @@ -572,6 +628,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasRLE(SDL_Surface *surface); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetSurfaceColorKey @@ -588,6 +646,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorKey(SDL_Surface *surface, bo * \param surface the SDL_Surface structure to query. * \returns true if the surface has a color key, false otherwise. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetSurfaceColorKey @@ -608,6 +668,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SurfaceHasColorKey(SDL_Surface *surface); * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetSurfaceColorKey @@ -631,6 +693,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceColorKey(SDL_Surface *surface, Ui * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetSurfaceColorMod @@ -649,6 +713,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceColorMod(SDL_Surface *surface, Ui * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetSurfaceAlphaMod @@ -669,6 +735,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceColorMod(SDL_Surface *surface, Ui * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetSurfaceAlphaMod @@ -684,6 +752,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceAlphaMod(SDL_Surface *surface, Ui * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetSurfaceColorMod @@ -703,6 +773,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceAlphaMod(SDL_Surface *surface, Ui * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetSurfaceBlendMode @@ -717,6 +789,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceBlendMode(SDL_Surface *surface, S * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetSurfaceBlendMode @@ -738,6 +812,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceBlendMode(SDL_Surface *surface, S * \returns true if the rectangle intersects the surface, otherwise false and * blits will be completely clipped. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_GetSurfaceClipRect @@ -757,6 +833,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetSurfaceClipRect(SDL_Surface *surface, co * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_SetSurfaceClipRect @@ -771,6 +849,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetSurfaceClipRect(SDL_Surface *surface, SD * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipMode flip); @@ -787,6 +867,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FlipSurface(SDL_Surface *surface, SDL_FlipM * \returns a copy of the surface or NULL on failure; call SDL_GetError() for * more information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_DestroySurface @@ -806,6 +888,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_DuplicateSurface(SDL_Surface *surf * \returns a copy of the surface or NULL on failure; call SDL_GetError() for * more information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_DestroySurface @@ -831,6 +915,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ScaleSurface(SDL_Surface *surface, * \returns the new SDL_Surface structure that is created or NULL on failure; * call SDL_GetError() for more information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_ConvertSurfaceAndColorspace @@ -857,6 +943,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ConvertSurface(SDL_Surface *surfac * \returns the new SDL_Surface structure that is created or NULL on failure; * call SDL_GetError() for more information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_ConvertSurface @@ -878,6 +966,10 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_ConvertSurfaceAndColorspace(SDL_Su * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety The same destination pixels should not be used from two + * threads at once. It is safe to use the same source pixels + * from multiple threads. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_ConvertPixelsAndColorspace @@ -907,6 +999,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertPixels(int width, int height, SDL_Pi * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety The same destination pixels should not be used from two + * threads at once. It is safe to use the same source pixels + * from multiple threads. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_ConvertPixels @@ -931,6 +1027,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ConvertPixelsAndColorspace(int width, int h * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety The same destination pixels should not be used from two + * threads at once. It is safe to use the same source pixels + * from multiple threads. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplyAlpha(int width, int height, SDL_PixelFormat src_format, const void *src, int src_pitch, SDL_PixelFormat dst_format, void *dst, int dst_pitch, bool linear); @@ -946,6 +1046,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplyAlpha(int width, int height, SDL * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplySurfaceAlpha(SDL_Surface *surface, bool linear); @@ -966,6 +1068,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PremultiplySurfaceAlpha(SDL_Surface *surfac * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_ClearSurface(SDL_Surface *surface, float r, float g, float b, float a); @@ -989,6 +1093,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ClearSurface(SDL_Surface *surface, float r, * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_FillSurfaceRects @@ -1014,6 +1120,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRect(SDL_Surface *dst, const SDL * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_FillSurfaceRect @@ -1027,9 +1135,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SD * If either `srcrect` or `dstrect` are NULL, the entire surface (`src` or * `dst`) is copied while ensuring clipping to `dst->clip_rect`. * - * The final blit rectangles are saved in `srcrect` and `dstrect` after all - * clipping is performed. - * * The blit function should not be called on a locked surface. * * The blit semantics for surfaces with and without blending and colorkey are @@ -1087,9 +1192,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SD * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety The same destination surface should not be used from two - * threads at once. It is safe to use the same source surface - * from multiple threads. + * \threadsafety Only one thread should be using the `src` and `dst` surfaces + * at any given time. * * \since This function is available since SDL 3.2.0. * @@ -1112,9 +1216,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurface(SDL_Surface *src, const SDL_Rec * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety The same destination surface should not be used from two - * threads at once. It is safe to use the same source surface - * from multiple threads. + * \threadsafety Only one thread should be using the `src` and `dst` surfaces + * at any given time. * * \since This function is available since SDL 3.2.0. * @@ -1137,9 +1240,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUnchecked(SDL_Surface *src, cons * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety The same destination surface should not be used from two - * threads at once. It is safe to use the same source surface - * from multiple threads. + * \threadsafety Only one thread should be using the `src` and `dst` surfaces + * at any given time. * * \since This function is available since SDL 3.2.0. * @@ -1163,9 +1265,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceScaled(SDL_Surface *src, const S * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety The same destination surface should not be used from two - * threads at once. It is safe to use the same source surface - * from multiple threads. + * \threadsafety Only one thread should be using the `src` and `dst` surfaces + * at any given time. * * \since This function is available since SDL 3.2.0. * @@ -1173,6 +1274,29 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceScaled(SDL_Surface *src, const S */ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode); +/** + * Perform a stretched pixel copy from one surface to another. + * + * \param src the SDL_Surface structure to be copied from. + * \param srcrect the SDL_Rect structure representing the rectangle to be + * copied, or NULL to copy the entire surface. + * \param dst the SDL_Surface structure that is the blit target. + * \param dstrect the SDL_Rect structure representing the target rectangle in + * the destination surface, or NULL to fill the entire + * destination surface. + * \param scaleMode the SDL_ScaleMode to be used. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety Only one thread should be using the `src` and `dst` surfaces + * at any given time. + * + * \since This function is available since SDL 3.4.0. + * + * \sa SDL_BlitSurfaceScaled + */ +extern SDL_DECLSPEC bool SDLCALL SDL_StretchSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode); + /** * Perform a tiled blit to a destination surface, which may be of a different * format. @@ -1189,9 +1313,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety The same destination surface should not be used from two - * threads at once. It is safe to use the same source surface - * from multiple threads. + * \threadsafety Only one thread should be using the `src` and `dst` surfaces + * at any given time. * * \since This function is available since SDL 3.2.0. * @@ -1219,9 +1342,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceTiled(SDL_Surface *src, const SD * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety The same destination surface should not be used from two - * threads at once. It is safe to use the same source surface - * from multiple threads. + * \threadsafety Only one thread should be using the `src` and `dst` surfaces + * at any given time. * * \since This function is available since SDL 3.2.0. * @@ -1256,9 +1378,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceTiledWithScale(SDL_Surface *src, * \returns true on success or false on failure; call SDL_GetError() for more * information. * - * \threadsafety The same destination surface should not be used from two - * threads at once. It is safe to use the same source surface - * from multiple threads. + * \threadsafety Only one thread should be using the `src` and `dst` surfaces + * at any given time. * * \since This function is available since SDL 3.2.0. * @@ -1290,6 +1411,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurface9Grid(SDL_Surface *src, const SD * \param b the blue component of the pixel in the range 0-255. * \returns a pixel value. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_MapSurfaceRGBA @@ -1321,6 +1444,8 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGB(SDL_Surface *surface, Uint8 * \param a the alpha component of the pixel in the range 0-255. * \returns a pixel value. * + * \threadsafety It is safe to call this function from any thread. + * * \since This function is available since SDL 3.2.0. * * \sa SDL_MapSurfaceRGB @@ -1350,6 +1475,8 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapSurfaceRGBA(SDL_Surface *surface, Uint * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a); @@ -1374,6 +1501,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixelFloat(SDL_Surface *surface, int x, int y, float *r, float *g, float *b, float *a); @@ -1397,6 +1526,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadSurfacePixelFloat(SDL_Surface *surface, * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 r, Uint8 g, Uint8 b, Uint8 a); @@ -1417,6 +1548,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixel(SDL_Surface *surface, int * \returns true on success or false on failure; call SDL_GetError() for more * information. * + * \threadsafety This function is not thread safe. + * * \since This function is available since SDL 3.2.0. */ extern SDL_DECLSPEC bool SDLCALL SDL_WriteSurfacePixelFloat(SDL_Surface *surface, int x, int y, float r, float g, float b, float a); diff --git a/vendor/sdl3/include/SDL_test_common.h b/vendor/sdl3/include/SDL_test_common.h index 3ab1ad01c..91efe8ac3 100644 --- a/vendor/sdl3/include/SDL_test_common.h +++ b/vendor/sdl3/include/SDL_test_common.h @@ -177,7 +177,7 @@ extern "C" { * * \returns a newly allocated common state object. */ -SDLTest_CommonState *SDLCALL SDLTest_CommonCreateState(char **argv, SDL_InitFlags flags); +SDLTest_CommonState * SDLCALL SDLTest_CommonCreateState(char **argv, SDL_InitFlags flags); /** * Free the common state object. diff --git a/vendor/sdl3/include/SDL_thread.h b/vendor/sdl3/include/SDL_thread.h index 277535fcb..e981b5429 100644 --- a/vendor/sdl3/include/SDL_thread.h +++ b/vendor/sdl3/include/SDL_thread.h @@ -139,7 +139,7 @@ typedef enum SDL_ThreadState * * \since This datatype is available since SDL 3.2.0. */ -typedef int (SDLCALL * SDL_ThreadFunction) (void *data); +typedef int (SDLCALL *SDL_ThreadFunction) (void *data); #ifdef SDL_WIKI_DOCUMENTATION_SECTION diff --git a/vendor/sdl3/include/SDL_tray.h b/vendor/sdl3/include/SDL_tray.h index 0b05db25b..1780b0ba5 100644 --- a/vendor/sdl3/include/SDL_tray.h +++ b/vendor/sdl3/include/SDL_tray.h @@ -118,7 +118,7 @@ typedef void (SDLCALL *SDL_TrayCallback)(void *userdata, SDL_TrayEntry *entry); * \sa SDL_GetTrayMenu * \sa SDL_DestroyTray */ -extern SDL_DECLSPEC SDL_Tray *SDLCALL SDL_CreateTray(SDL_Surface *icon, const char *tooltip); +extern SDL_DECLSPEC SDL_Tray * SDLCALL SDL_CreateTray(SDL_Surface *icon, const char *tooltip); /** * Updates the system tray icon's icon. @@ -172,7 +172,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayTooltip(SDL_Tray *tray, const char * * \sa SDL_GetTrayMenu * \sa SDL_GetTrayMenuParentTray */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTrayMenu(SDL_Tray *tray); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_CreateTrayMenu(SDL_Tray *tray); /** * Create a submenu for a system tray entry. @@ -196,7 +196,7 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTrayMenu(SDL_Tray *tray); * \sa SDL_GetTraySubmenu * \sa SDL_GetTrayMenuParentEntry */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTraySubmenu(SDL_TrayEntry *entry); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_CreateTraySubmenu(SDL_TrayEntry *entry); /** * Gets a previously created tray menu. @@ -220,7 +220,7 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_CreateTraySubmenu(SDL_TrayEntry *e * \sa SDL_CreateTray * \sa SDL_CreateTrayMenu */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayMenu(SDL_Tray *tray); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_GetTrayMenu(SDL_Tray *tray); /** * Gets a previously created tray entry submenu. @@ -244,14 +244,14 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayMenu(SDL_Tray *tray); * \sa SDL_InsertTrayEntryAt * \sa SDL_CreateTraySubmenu */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTraySubmenu(SDL_TrayEntry *entry); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_GetTraySubmenu(SDL_TrayEntry *entry); /** * Returns a list of entries in the menu, in order. * * \param menu The menu to get entries from. - * \param size An optional pointer to obtain the number of entries in the - * menu. + * \param count An optional pointer to obtain the number of entries in the + * menu. * \returns a NULL-terminated list of entries within the given menu. The * pointer becomes invalid when any function that inserts or deletes * entries in the menu is called. @@ -264,7 +264,7 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTraySubmenu(SDL_TrayEntry *entr * \sa SDL_RemoveTrayEntry * \sa SDL_InsertTrayEntryAt */ -extern SDL_DECLSPEC const SDL_TrayEntry **SDLCALL SDL_GetTrayEntries(SDL_TrayMenu *menu, int *size); +extern SDL_DECLSPEC const SDL_TrayEntry ** SDLCALL SDL_GetTrayEntries(SDL_TrayMenu *menu, int *count); /** * Removes a tray entry. @@ -307,7 +307,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_RemoveTrayEntry(SDL_TrayEntry *entry); * \sa SDL_RemoveTrayEntry * \sa SDL_GetTrayEntryParent */ -extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags); +extern SDL_DECLSPEC SDL_TrayEntry * SDLCALL SDL_InsertTrayEntryAt(SDL_TrayMenu *menu, int pos, const char *label, SDL_TrayEntryFlags flags); /** * Sets the label of an entry. @@ -348,7 +348,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_SetTrayEntryLabel(SDL_TrayEntry *entry, con * \sa SDL_InsertTrayEntryAt * \sa SDL_SetTrayEntryLabel */ -extern SDL_DECLSPEC const char *SDLCALL SDL_GetTrayEntryLabel(SDL_TrayEntry *entry); +extern SDL_DECLSPEC const char * SDLCALL SDL_GetTrayEntryLabel(SDL_TrayEntry *entry); /** * Sets whether or not an entry is checked. @@ -481,7 +481,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyTray(SDL_Tray *tray); * * \sa SDL_InsertTrayEntryAt */ -extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayEntryParent(SDL_TrayEntry *entry); +extern SDL_DECLSPEC SDL_TrayMenu * SDLCALL SDL_GetTrayEntryParent(SDL_TrayEntry *entry); /** * Gets the entry for which the menu is a submenu, if the current menu is a @@ -501,7 +501,7 @@ extern SDL_DECLSPEC SDL_TrayMenu *SDLCALL SDL_GetTrayEntryParent(SDL_TrayEntry * * \sa SDL_CreateTraySubmenu * \sa SDL_GetTrayMenuParentTray */ -extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu); +extern SDL_DECLSPEC SDL_TrayEntry * SDLCALL SDL_GetTrayMenuParentEntry(SDL_TrayMenu *menu); /** * Gets the tray for which this menu is the first-level menu, if the current @@ -521,7 +521,7 @@ extern SDL_DECLSPEC SDL_TrayEntry *SDLCALL SDL_GetTrayMenuParentEntry(SDL_TrayMe * \sa SDL_CreateTrayMenu * \sa SDL_GetTrayMenuParentEntry */ -extern SDL_DECLSPEC SDL_Tray *SDLCALL SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu); +extern SDL_DECLSPEC SDL_Tray * SDLCALL SDL_GetTrayMenuParentTray(SDL_TrayMenu *menu); /** * Update the trays. diff --git a/vendor/sdl3/include/SDL_version.h b/vendor/sdl3/include/SDL_version.h index 55014e3c1..435b3f95f 100644 --- a/vendor/sdl3/include/SDL_version.h +++ b/vendor/sdl3/include/SDL_version.h @@ -62,7 +62,7 @@ extern "C" { * * \since This macro is available since SDL 3.2.0. */ -#define SDL_MICRO_VERSION 0 +#define SDL_MICRO_VERSION 16 /** * This macro turns the version numbers into a numeric value. diff --git a/vendor/sdl3/include/SDL_video.h b/vendor/sdl3/include/SDL_video.h index a7afc3267..877b9adde 100644 --- a/vendor/sdl3/include/SDL_video.h +++ b/vendor/sdl3/include/SDL_video.h @@ -426,10 +426,10 @@ typedef SDL_EGLint *(SDLCALL *SDL_EGLIntArrayCallback)(void *userdata, SDL_EGLDi */ typedef enum SDL_GLAttr { - SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 3. */ - SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 3. */ - SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 2. */ - SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 0. */ + SDL_GL_RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 8. */ + SDL_GL_GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 8. */ + SDL_GL_BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 8. */ + SDL_GL_ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 8. */ SDL_GL_BUFFER_SIZE, /**< the minimum number of bits for frame buffer size; defaults to 0. */ SDL_GL_DOUBLEBUFFER, /**< whether the output is single or double buffered; defaults to double buffering on. */ SDL_GL_DEPTH_SIZE, /**< the minimum number of bits in the depth buffer; defaults to 16. */ @@ -1041,6 +1041,10 @@ extern SDL_DECLSPEC SDL_Window ** SDLCALL SDL_GetWindows(int *count); /** * Create a window with the specified dimensions and flags. * + * The window size is a request and may be different than expected based on + * the desktop layout and window manager policies. Your application should be + * prepared to handle a window of any size. + * * `flags` may be any of the following OR'd together: * * - `SDL_WINDOW_FULLSCREEN`: fullscreen window at desktop resolution @@ -1127,6 +1131,10 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreateWindow(const char *title, int /** * Create a child popup window of the specified parent window. * + * The window size is a request and may be different than expected based on + * the desktop layout and window manager policies. Your application should be + * prepared to handle a window of any size. + * * The flags parameter **must** contain at least one of the following: * * - `SDL_WINDOW_TOOLTIP`: The popup window is a tooltip and will not pass any @@ -1189,6 +1197,10 @@ extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_CreatePopupWindow(SDL_Window *paren /** * Create a window with the specified properties. * + * The window size is a request and may be different than expected based on + * the desktop layout and window manager policies. Your application should be + * prepared to handle a window of any size. + * * These are the supported properties: * * - `SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN`: true if the window should diff --git a/vendor/sdl3/include/SDL_vulkan.h b/vendor/sdl3/include/SDL_vulkan.h index 5a487561a..710afbe63 100644 --- a/vendor/sdl3/include/SDL_vulkan.h +++ b/vendor/sdl3/include/SDL_vulkan.h @@ -226,7 +226,7 @@ extern SDL_DECLSPEC char const * const * SDLCALL SDL_Vulkan_GetInstanceExtension extern SDL_DECLSPEC bool SDLCALL SDL_Vulkan_CreateSurface(SDL_Window *window, VkInstance instance, const struct VkAllocationCallbacks *allocator, - VkSurfaceKHR* surface); + VkSurfaceKHR *surface); /** * Destroy the Vulkan rendering surface of a window. diff --git a/vendor/sdl3/sdl3_audio.odin b/vendor/sdl3/sdl3_audio.odin index 43a8a34d2..045f4780e 100644 --- a/vendor/sdl3/sdl3_audio.odin +++ b/vendor/sdl3/sdl3_audio.odin @@ -83,9 +83,9 @@ foreign lib { OpenAudioDevice :: proc(devid: AudioDeviceID, spec: ^AudioSpec) -> AudioDeviceID --- IsAudioDevicePhysical :: proc(devid: AudioDeviceID) -> bool --- IsAudioDevicePlayback :: proc(devid: AudioDeviceID) -> bool --- - PauseAudioDevice :: proc(dev: AudioDeviceID) -> bool --- - ResumeAudioDevice :: proc(dev: AudioDeviceID) -> bool --- - AudioDevicePaused :: proc(dev: AudioDeviceID) -> bool --- + PauseAudioDevice :: proc(devid: AudioDeviceID) -> bool --- + ResumeAudioDevice :: proc(devid: AudioDeviceID) -> bool --- + AudioDevicePaused :: proc(devid: AudioDeviceID) -> bool --- GetAudioDeviceGain :: proc(devid: AudioDeviceID) -> f32 --- SetAudioDeviceGain :: proc(devid: AudioDeviceID, gain: f32) -> bool --- CloseAudioDevice :: proc(devid: AudioDeviceID) --- diff --git a/vendor/sdl3/sdl3_camera.odin b/vendor/sdl3/sdl3_camera.odin index d86d98746..7d46bd2bd 100644 --- a/vendor/sdl3/sdl3_camera.odin +++ b/vendor/sdl3/sdl3_camera.odin @@ -27,7 +27,7 @@ foreign lib { GetCameraDriver :: proc(index: c.int) -> cstring --- GetCurrentCameraDriver :: proc() -> cstring --- GetCameras :: proc(count: ^c.int) -> [^]CameraID --- - GetCameraSupportedFormats :: proc(devid: CameraID, count: ^c.int) -> [^]^CameraSpec --- + GetCameraSupportedFormats :: proc(instance_id: CameraID, count: ^c.int) -> [^]^CameraSpec --- GetCameraName :: proc(instance_id: CameraID) -> cstring --- GetCameraPosition :: proc(instance_id: CameraID) -> CameraPosition --- OpenCamera :: proc(instance_id: CameraID, spec: ^CameraSpec) -> ^Camera --- diff --git a/vendor/sdl3/sdl3_events.odin b/vendor/sdl3/sdl3_events.odin index 2eb2a4505..3f64f85fa 100644 --- a/vendor/sdl3/sdl3_events.odin +++ b/vendor/sdl3/sdl3_events.odin @@ -295,6 +295,8 @@ MouseWheelEvent :: struct { direction: MouseWheelDirection, /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */ mouse_x: f32, /**< X coordinate, relative to window */ mouse_y: f32, /**< Y coordinate, relative to window */ + integer_x: i32, /**< The amount scrolled horizontally, accumulated to whole scroll "ticks" (added in 3.2.12) */ + integer_y: i32, /**< The amount scrolled vertically, accumulated to whole scroll "ticks" (added in 3.2.12) */ } JoyAxisEvent :: struct { diff --git a/vendor/sdl3/sdl3_gpu.odin b/vendor/sdl3/sdl3_gpu.odin index da561b62b..def222739 100644 --- a/vendor/sdl3/sdl3_gpu.odin +++ b/vendor/sdl3/sdl3_gpu.odin @@ -46,7 +46,7 @@ GPUIndexElementSize :: enum c.int { GPUTextureFormat :: enum c.int { INVALID, - /* Unsigned Normalized Float Color Formats */ + /* Unsigned Normalized Float Color Formats */ A8_UNORM, R8_UNORM, R8G8_UNORM, @@ -59,34 +59,41 @@ GPUTextureFormat :: enum c.int { B5G5R5A1_UNORM, B4G4R4A4_UNORM, B8G8R8A8_UNORM, - /* Compressed Unsigned Normalized Float Color Formats */ + + /* Compressed Unsigned Normalized Float Color Formats */ BC1_RGBA_UNORM, BC2_RGBA_UNORM, BC3_RGBA_UNORM, BC4_R_UNORM, BC5_RG_UNORM, BC7_RGBA_UNORM, - /* Compressed Signed Float Color Formats */ + + /* Compressed Signed Float Color Formats */ BC6H_RGB_FLOAT, - /* Compressed Unsigned Float Color Formats */ + + /* Compressed Unsigned Float Color Formats */ BC6H_RGB_UFLOAT, - /* Signed Normalized Float Color Formats */ + + /* Signed Normalized Float Color Formats */ R8_SNORM, R8G8_SNORM, R8G8B8A8_SNORM, R16_SNORM, R16G16_SNORM, R16G16B16A16_SNORM, - /* Signed Float Color Formats */ + + /* Signed Float Color Formats */ R16_FLOAT, R16G16_FLOAT, R16G16B16A16_FLOAT, R32_FLOAT, R32G32_FLOAT, R32G32B32A32_FLOAT, - /* Unsigned Float Color Formats */ + + /* Unsigned Float Color Formats */ R11G11B10_UFLOAT, - /* Unsigned Integer Color Formats */ + + /* Unsigned Integer Color Formats */ R8_UINT, R8G8_UINT, R8G8B8A8_UINT, @@ -96,7 +103,8 @@ GPUTextureFormat :: enum c.int { R32_UINT, R32G32_UINT, R32G32B32A32_UINT, - /* Signed Integer Color Formats */ + + /* Signed Integer Color Formats */ R8_INT, R8G8_INT, R8G8B8A8_INT, @@ -106,21 +114,25 @@ GPUTextureFormat :: enum c.int { R32_INT, R32G32_INT, R32G32B32A32_INT, - /* SRGB Unsigned Normalized Color Formats */ + + /* SRGB Unsigned Normalized Color Formats */ R8G8B8A8_UNORM_SRGB, B8G8R8A8_UNORM_SRGB, - /* Compressed SRGB Unsigned Normalized Color Formats */ + + /* Compressed SRGB Unsigned Normalized Color Formats */ BC1_RGBA_UNORM_SRGB, BC2_RGBA_UNORM_SRGB, BC3_RGBA_UNORM_SRGB, BC7_RGBA_UNORM_SRGB, - /* Depth Formats */ + + /* Depth Formats */ D16_UNORM, D24_UNORM, D32_FLOAT, D24_UNORM_S8_UINT, D32_FLOAT_S8_UINT, - /* Compressed ASTC Normalized Float Color Formats*/ + + /* Compressed ASTC Normalized Float Color Formats*/ ASTC_4x4_UNORM, ASTC_5x4_UNORM, ASTC_5x5_UNORM, @@ -135,7 +147,8 @@ GPUTextureFormat :: enum c.int { ASTC_10x10_UNORM, ASTC_12x10_UNORM, ASTC_12x12_UNORM, - /* Compressed SRGB ASTC Normalized Float Color Formats*/ + + /* Compressed SRGB ASTC Normalized Float Color Formats*/ ASTC_4x4_UNORM_SRGB, ASTC_5x4_UNORM_SRGB, ASTC_5x5_UNORM_SRGB, @@ -150,7 +163,8 @@ GPUTextureFormat :: enum c.int { ASTC_10x10_UNORM_SRGB, ASTC_12x10_UNORM_SRGB, ASTC_12x12_UNORM_SRGB, - /* Compressed ASTC Signed Float Color Formats*/ + + /* Compressed ASTC Signed Float Color Formats*/ ASTC_4x4_FLOAT, ASTC_5x4_FLOAT, ASTC_5x5_FLOAT, @@ -516,7 +530,7 @@ GPUVertexBufferDescription :: struct { slot: Uint32, /**< The binding slot of the vertex buffer. */ pitch: Uint32, /**< The byte pitch between consecutive elements of the vertex buffer. */ input_rate: GPUVertexInputRate, /**< Whether attribute addressing is a function of the vertex index or instance index. */ - instance_step_rate: Uint32, /**< The number of instances to draw using the same per-instance data before advancing in the instance buffer by one element. Ignored unless input_rate is GPU_VERTEXINPUTRATE_INSTANCE */ + instance_step_rate: Uint32, /**< Reserved for future use. Must be set to 0. */ } GPUVertexAttribute :: struct { @@ -611,8 +625,8 @@ GPURasterizerState :: struct { GPUMultisampleState :: struct { sample_count: GPUSampleCount, /**< The number of samples to be used in rasterization. */ - sample_mask: Uint32, /**< Determines which samples get updated in the render targets. Treated as 0xFFFFFFFF if enable_mask is false. */ - enable_mask: bool, /**< Enables sample masking. */ + sample_mask: Uint32, /**< Reserved for future use. Must be set to 0. */ + enable_mask: bool, /**< Reserved for future use. Must be set to false. */ _: Uint8, _: Uint8, _: Uint8, @@ -751,30 +765,30 @@ GPUStorageTextureReadWriteBinding :: struct { } -PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN :: "SDL.gpu.device.create.debugmode" -PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN :: "SDL.gpu.device.create.preferlowpower" -PROP_GPU_DEVICE_CREATE_NAME_STRING :: "SDL.gpu.device.create.name" -PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN :: "SDL.gpu.device.create.shaders.private" -PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN :: "SDL.gpu.device.create.shaders.spirv" -PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN :: "SDL.gpu.device.create.shaders.dxbc" -PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN :: "SDL.gpu.device.create.shaders.dxil" -PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN :: "SDL.gpu.device.create.shaders.msl" -PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN :: "SDL.gpu.device.create.shaders.metallib" -PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING :: "SDL.gpu.device.create.d3d12.semantic" +PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN :: "SDL.gpu.device.create.debugmode" +PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN :: "SDL.gpu.device.create.preferlowpower" +PROP_GPU_DEVICE_CREATE_NAME_STRING :: "SDL.gpu.device.create.name" +PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN :: "SDL.gpu.device.create.shaders.private" +PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN :: "SDL.gpu.device.create.shaders.spirv" +PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN :: "SDL.gpu.device.create.shaders.dxbc" +PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN :: "SDL.gpu.device.create.shaders.dxil" +PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN :: "SDL.gpu.device.create.shaders.msl" +PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN :: "SDL.gpu.device.create.shaders.metallib" +PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING :: "SDL.gpu.device.create.d3d12.semantic" -PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING :: "SDL.gpu.computepipeline.create.name" -PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING :: "SDL.gpu.graphicspipeline.create.name" -PROP_GPU_SAMPLER_CREATE_NAME_STRING :: "SDL.gpu.sampler.create.name" -PROP_GPU_SHADER_CREATE_NAME_STRING :: "SDL.gpu.shader.create.name" -PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.r" -PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.g" -PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.b" -PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.a" -PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.depth" -PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8 :: "SDL.gpu.texture.create.d3d12.clear.stencil" -PROP_GPU_TEXTURE_CREATE_NAME_STRING :: "SDL.gpu.texture.create.name" -PROP_GPU_BUFFER_CREATE_NAME_STRING :: "SDL.gpu.buffer.create.name" -PROP_GPU_TRANSFERBUFFER_CREATE_NAME_STRING :: "SDL.gpu.transferbuffer.create.name" +PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING :: "SDL.gpu.computepipeline.create.name" +PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING :: "SDL.gpu.graphicspipeline.create.name" +PROP_GPU_SAMPLER_CREATE_NAME_STRING :: "SDL.gpu.sampler.create.name" +PROP_GPU_SHADER_CREATE_NAME_STRING :: "SDL.gpu.shader.create.name" +PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.r" +PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.g" +PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.b" +PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.a" +PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT :: "SDL.gpu.texture.create.d3d12.clear.depth" +PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER :: "SDL.gpu.texture.create.d3d12.clear.stencil" +PROP_GPU_TEXTURE_CREATE_NAME_STRING :: "SDL.gpu.texture.create.name" +PROP_GPU_BUFFER_CREATE_NAME_STRING :: "SDL.gpu.buffer.create.name" +PROP_GPU_TRANSFERBUFFER_CREATE_NAME_STRING :: "SDL.gpu.transferbuffer.create.name" @(default_calling_convention="c", link_prefix="SDL_", require_results) foreign lib { diff --git a/vendor/sdl3/sdl3_hints.odin b/vendor/sdl3/sdl3_hints.odin index a7398a124..987010c57 100644 --- a/vendor/sdl3/sdl3_hints.odin +++ b/vendor/sdl3/sdl3_hints.odin @@ -123,6 +123,7 @@ HINT_JOYSTICK_WGI :: "SDL_JOYSTICK_WGI" HINT_JOYSTICK_WHEEL_DEVICES :: "SDL_JOYSTICK_WHEEL_DEVICES" HINT_JOYSTICK_WHEEL_DEVICES_EXCLUDED :: "SDL_JOYSTICK_WHEEL_DEVICES_EXCLUDED" HINT_JOYSTICK_ZERO_CENTERED_DEVICES :: "SDL_JOYSTICK_ZERO_CENTERED_DEVICES" +HINT_JOYSTICK_HAPTIC_AXES :: "SDL_JOYSTICK_HAPTIC_AXES" HINT_KEYCODE_OPTIONS :: "SDL_KEYCODE_OPTIONS" HINT_KMSDRM_DEVICE_INDEX :: "SDL_KMSDRM_DEVICE_INDEX" HINT_KMSDRM_REQUIRE_DRM_MASTER :: "SDL_KMSDRM_REQUIRE_DRM_MASTER" @@ -197,6 +198,7 @@ HINT_VIDEO_WAYLAND_MODE_SCALING :: "SDL_VIDEO_WAYLAND_MODE_SCALING" HINT_VIDEO_WAYLAND_PREFER_LIBDECOR :: "SDL_VIDEO_WAYLAND_PREFER_LIBDECOR" HINT_VIDEO_WAYLAND_SCALE_TO_DISPLAY :: "SDL_VIDEO_WAYLAND_SCALE_TO_DISPLAY" HINT_VIDEO_WIN_D3DCOMPILER :: "SDL_VIDEO_WIN_D3DCOMPILER" +HINT_VIDEO_X11_EXTERNAL_WINDOW_INPUT :: "SDL_VIDEO_X11_EXTERNAL_WINDOW_INPUT" HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR :: "SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR" HINT_VIDEO_X11_NET_WM_PING :: "SDL_VIDEO_X11_NET_WM_PING" HINT_VIDEO_X11_NODIRECTCOLOR :: "SDL_VIDEO_X11_NODIRECTCOLOR" diff --git a/vendor/sdl3/sdl3_init.odin b/vendor/sdl3/sdl3_init.odin index 0d10ad357..97daebf03 100644 --- a/vendor/sdl3/sdl3_init.odin +++ b/vendor/sdl3/sdl3_init.odin @@ -6,7 +6,7 @@ InitFlags :: distinct bit_set[InitFlag; Uint32] InitFlag :: enum Uint32 { AUDIO = 4, /**< `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` */ VIDEO = 5, /**< `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread */ - JOYSTICK = 9, /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD */ + JOYSTICK = 9, /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS` */ HAPTIC = 12, GAMEPAD = 13, /**< `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` */ EVENTS = 14, diff --git a/vendor/sdl3/sdl3_mutex.odin b/vendor/sdl3/sdl3_mutex.odin index ada8006bc..8067473f3 100644 --- a/vendor/sdl3/sdl3_mutex.odin +++ b/vendor/sdl3/sdl3_mutex.odin @@ -1,8 +1,8 @@ package sdl3 -Mutex :: struct {} -RWLock :: struct {} - +Mutex :: struct {} +RWLock :: struct {} +Semaphore :: struct {} @(default_calling_convention="c", link_prefix="SDL_", require_results) foreign lib { @@ -19,4 +19,12 @@ foreign lib { TryLockRWLockForWriting :: proc(rwlock: ^RWLock) -> bool --- UnlockRWLock :: proc(rwlock: ^RWLock) --- DestroyRWLock :: proc(rwlock: ^RWLock) --- -} \ No newline at end of file + + CreateSemaphore :: proc(initial_value: Uint32) -> ^Semaphore --- + DestroySemaphore :: proc(sem: ^Semaphore) --- + GetSemaphoreValue :: proc(sem: ^Semaphore) -> Uint32 --- + SignalSemaphore :: proc(sem: ^Semaphore) --- + TryWaitSemaphore :: proc(sem: ^Semaphore) -> bool --- + WaitSemaphore :: proc(sem: ^Semaphore) --- + WaitSemaphoreTimeout :: proc(sem: ^Semaphore, timeout_ms: Sint32) --- +} diff --git a/vendor/sdl3/sdl3_pixels.odin b/vendor/sdl3/sdl3_pixels.odin index 0bea733f8..a636d13ff 100644 --- a/vendor/sdl3/sdl3_pixels.odin +++ b/vendor/sdl3/sdl3_pixels.odin @@ -277,6 +277,8 @@ PixelFormat :: enum c.int { /* SDL_DEFINE_PIXELFOURCC('P', '0', '1', '0'), */ EXTERNAL_OES = 0x2053454f, /**< Android video texture format */ /* SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ') */ + MJPG = 0x47504a4d, /**< Motion JPEG */ + /* SDL_DEFINE_PIXELFOURCC('M', 'J', 'P', 'G') */ /* Aliases for RGBA byte arrays of color data, for the current platform */ RGBA32 = RGBA8888 when BYTEORDER == BIG_ENDIAN else ABGR8888, @@ -550,7 +552,7 @@ PixelFormatDetails :: struct { @(default_calling_convention="c", link_prefix="SDL_") foreign lib { - GetPixelFormatName :: proc(format: PixelFormat) -> rawptr --- + GetPixelFormatName :: proc(format: PixelFormat) -> cstring --- GetMasksForPixelFormat :: proc(format: PixelFormat, bpp: ^c.int, Rmask, Gmask, Bmask, Amask: ^Uint32) -> bool --- GetPixelFormatForMasks :: proc(bpp: c.int, Rmask, Gmask, Bmask, Amask: Uint32) -> PixelFormat --- GetPixelFormatDetails :: proc(format: PixelFormat) -> ^PixelFormatDetails --- @@ -561,4 +563,4 @@ foreign lib { MapRGBA :: proc(format: ^PixelFormatDetails, palette: ^Palette, r, g, b, a: Uint8) -> Uint32 --- GetRGB :: proc(pixel: Uint32, format: ^PixelFormatDetails, palette: ^Palette, r, g, b: ^Uint8) --- GetRGBA :: proc(pixel: Uint32, format: ^PixelFormatDetails, palette: ^Palette, r, g, b, a: ^Uint8) --- -} \ No newline at end of file +} diff --git a/vendor/sdl3/sdl3_surface.odin b/vendor/sdl3/sdl3_surface.odin index 7abbd4ab5..526940147 100644 --- a/vendor/sdl3/sdl3_surface.odin +++ b/vendor/sdl3/sdl3_surface.odin @@ -22,6 +22,7 @@ MUSTLOCK :: proc "c" (S: ^Surface) -> bool { } ScaleMode :: enum c.int { + INVALID = -1, NEAREST, /**< nearest pixel sampling */ LINEAR, /**< linear filtering */ } @@ -45,6 +46,11 @@ Surface :: struct { reserved: rawptr, /**< Reserved for internal use */ } +PROP_SURFACE_SDR_WHITE_POINT_FLOAT :: "SDL.surface.SDR_white_point" +PROP_SURFACE_HDR_HEADROOM_FLOAT :: "SDL.surface.HDR_headroom" +PROP_SURFACE_TONEMAP_OPERATOR_STRING :: "SDL.surface.tonemap" +PROP_SURFACE_HOTSPOT_X_NUMBER :: "SDL.surface.hotspot.x" +PROP_SURFACE_HOTSPOT_Y_NUMBER :: "SDL.surface.hotspot.y" @(default_calling_convention="c", link_prefix="SDL_") foreign lib { @@ -96,6 +102,7 @@ foreign lib { BlitSurfaceUnchecked :: proc(src: ^Surface, srcrect: Maybe(^Rect), dst: ^Surface, dstrect: Maybe(^Rect)) -> bool --- BlitSurfaceScaled :: proc(src: ^Surface, srcrect: Maybe(^Rect), dst: ^Surface, dstrect: Maybe(^Rect), scaleMode: ScaleMode) -> bool --- BlitSurfaceUncheckedScaled :: proc(src: ^Surface, srcrect: Maybe(^Rect), dst: ^Surface, dstrect: Maybe(^Rect), scaleMode: ScaleMode) -> bool --- + StretchSurface :: proc(src: ^Surface, srcrect: Maybe(^Rect), dst: ^Surface, dstrect: Maybe(^Rect), scaleMode: ScaleMode) -> bool --- BlitSurfaceTiled :: proc(src: ^Surface, srcrect: Maybe(^Rect), dst: ^Surface, dstrect: Maybe(^Rect)) -> bool --- BlitSurfaceTiledWithScale :: proc(src: ^Surface, srcrect: Maybe(^Rect), scale: f32, scaleMode: ScaleMode, dst: ^Surface, dstrect: Maybe(^Rect)) -> bool --- BlitSurface9Grid :: proc(src: ^Surface, srcrect: Maybe(^Rect), left_width, right_width, top_height, bottom_height: c.int, scale: f32, scaleMode: ScaleMode, dst: ^Surface, dstrect: Maybe(^Rect)) -> bool --- diff --git a/vendor/sdl3/sdl3_thread.odin b/vendor/sdl3/sdl3_thread.odin index 9b2d068d9..e6bbf7d16 100644 --- a/vendor/sdl3/sdl3_thread.odin +++ b/vendor/sdl3/sdl3_thread.odin @@ -49,7 +49,7 @@ PROP_THREAD_CREATE_STACKSIZE_NUMBER :: "SDL.thread.create.stacksize" BeginThreadFunction :: proc "c" () -> FunctionPointer { when ODIN_OS == .Windows { foreign { - _beginthreadx :: proc "c" ( + _beginthreadex :: proc "c" ( security: rawptr, stack_size: c.uint, start_address: proc "c" (rawptr), @@ -58,7 +58,7 @@ BeginThreadFunction :: proc "c" () -> FunctionPointer { thraddr: ^c.uint, ) -> uintptr --- } - return FunctionPointer(_beginthreadx) + return FunctionPointer(_beginthreadex) } else { return nil } diff --git a/vendor/sdl3/sdl3_version.odin b/vendor/sdl3/sdl3_version.odin index 9a1f21add..fbc90e220 100644 --- a/vendor/sdl3/sdl3_version.odin +++ b/vendor/sdl3/sdl3_version.odin @@ -4,7 +4,7 @@ import "core:c" MAJOR_VERSION :: 3 MINOR_VERSION :: 2 -MICRO_VERSION :: 2 +MICRO_VERSION :: 16 @(require_results) VERSIONNUM :: #force_inline proc "c" (major, minor, patch: c.int) -> c.int { return (major * 1000000) + (minor * 1000) + patch } @(require_results) VERSIONNUM_MAJOR :: #force_inline proc "c" (version: c.int) -> c.int { return version / 1000000 } diff --git a/vendor/sdl3/sdl3_video.odin b/vendor/sdl3/sdl3_video.odin index 3be912d15..6761bee56 100644 --- a/vendor/sdl3/sdl3_video.odin +++ b/vendor/sdl3/sdl3_video.odin @@ -145,10 +145,10 @@ EGLAttribArrayCallback :: #type proc "c" (userdata: rawptr) -> ^EGLint EGLIntArrayCallback :: #type proc "c" (userdata: rawptr, display: EGLDisplay, config: EGLConfig) -> [^]EGLint GLAttr :: enum c.int { - RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 3. */ - GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 3. */ - BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 2. */ - ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 0. */ + RED_SIZE, /**< the minimum number of bits for the red channel of the color buffer; defaults to 8. */ + GREEN_SIZE, /**< the minimum number of bits for the green channel of the color buffer; defaults to 8. */ + BLUE_SIZE, /**< the minimum number of bits for the blue channel of the color buffer; defaults to 8. */ + ALPHA_SIZE, /**< the minimum number of bits for the alpha channel of the color buffer; defaults to 8. */ BUFFER_SIZE, /**< the minimum number of bits for frame buffer size; defaults to 0. */ DOUBLEBUFFER, /**< whether the output is single or double buffered; defaults to double buffering on. */ DEPTH_SIZE, /**< the minimum number of bits in the depth buffer; defaults to 16. */ @@ -336,7 +336,7 @@ foreign lib { GetNaturalDisplayOrientation :: proc(displayID: DisplayID) -> DisplayOrientation --- GetCurrentDisplayOrientation :: proc(displayID: DisplayID) -> DisplayOrientation --- GetDisplayContentScale :: proc(displayID: DisplayID) -> f32 --- - GetFullscreenDisplayModes :: proc(displayID: DisplayID, count: c.int) -> [^]^DisplayMode --- + GetFullscreenDisplayModes :: proc(displayID: DisplayID, count: ^c.int) -> [^]^DisplayMode --- GetClosestFullscreenDisplayMode :: proc(displayID: DisplayID, w, h: c.int, refresh_rate: f32, include_high_density_modes: bool, closest: ^DisplayMode) -> bool --- GetDesktopDisplayMode :: proc(displayID: DisplayID) -> ^DisplayMode --- GetCurrentDisplayMode :: proc(displayID: DisplayID) -> ^DisplayMode --- @@ -397,7 +397,7 @@ foreign lib { GetWindowKeyboardGrab :: proc(window: ^Window) -> bool --- GetWindowMouseGrab :: proc(window: ^Window) -> bool --- GetGrabbedWindow :: proc() -> ^Window --- - SetWindowMouseRect :: proc(window: ^Window, #by_ptr rect: Rect) -> bool --- + SetWindowMouseRect :: proc(window: ^Window, rect: ^Rect) -> bool --- GetWindowMouseRect :: proc(window: ^Window) -> ^Rect --- SetWindowOpacity :: proc(window: ^Window, opacity: f32) -> bool --- GetWindowOpacity :: proc(window: ^Window) -> f32 --- diff --git a/vendor/sdl3/ttf/LICENSE.freetype.txt b/vendor/sdl3/ttf/LICENSE.freetype.txt new file mode 100644 index 000000000..c406d150f --- /dev/null +++ b/vendor/sdl3/ttf/LICENSE.freetype.txt @@ -0,0 +1,169 @@ + The FreeType Project LICENSE + ---------------------------- + + 2006-Jan-27 + + Copyright 1996-2002, 2006 by + David Turner, Robert Wilhelm, and Werner Lemberg + + + +Introduction +============ + + The FreeType Project is distributed in several archive packages; + some of them may contain, in addition to the FreeType font engine, + various tools and contributions which rely on, or relate to, the + FreeType Project. + + This license applies to all files found in such packages, and + which do not fall under their own explicit license. The license + affects thus the FreeType font engine, the test programs, + documentation and makefiles, at the very least. + + This license was inspired by the BSD, Artistic, and IJG + (Independent JPEG Group) licenses, which all encourage inclusion + and use of free software in commercial and freeware products + alike. As a consequence, its main points are that: + + o We don't promise that this software works. However, we will be + interested in any kind of bug reports. (`as is' distribution) + + o You can use this software for whatever you want, in parts or + full form, without having to pay us. (`royalty-free' usage) + + o You may not pretend that you wrote this software. If you use + it, or only parts of it, in a program, you must acknowledge + somewhere in your documentation that you have used the + FreeType code. (`credits') + + We specifically permit and encourage the inclusion of this + software, with or without modifications, in commercial products. + We disclaim all warranties covering The FreeType Project and + assume no liability related to The FreeType Project. + + + Finally, many people asked us for a preferred form for a + credit/disclaimer to use in compliance with this license. We thus + encourage you to use the following text: + + """ + Portions of this software are copyright © The FreeType + Project (www.freetype.org). All rights reserved. + """ + + Please replace with the value from the FreeType version you + actually use. + + +Legal Terms +=========== + +0. Definitions +-------------- + + Throughout this license, the terms `package', `FreeType Project', + and `FreeType archive' refer to the set of files originally + distributed by the authors (David Turner, Robert Wilhelm, and + Werner Lemberg) as the `FreeType Project', be they named as alpha, + beta or final release. + + `You' refers to the licensee, or person using the project, where + `using' is a generic term including compiling the project's source + code as well as linking it to form a `program' or `executable'. + This program is referred to as `a program using the FreeType + engine'. + + This license applies to all files distributed in the original + FreeType Project, including all source code, binaries and + documentation, unless otherwise stated in the file in its + original, unmodified form as distributed in the original archive. + If you are unsure whether or not a particular file is covered by + this license, you must contact us to verify this. + + The FreeType Project is copyright (C) 1996-2000 by David Turner, + Robert Wilhelm, and Werner Lemberg. All rights reserved except as + specified below. + +1. No Warranty +-------------- + + THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO + USE, OF THE FREETYPE PROJECT. + +2. Redistribution +----------------- + + This license grants a worldwide, royalty-free, perpetual and + irrevocable right and license to use, execute, perform, compile, + display, copy, create derivative works of, distribute and + sublicense the FreeType Project (in both source and object code + forms) and derivative works thereof for any purpose; and to + authorize others to exercise some or all of the rights granted + herein, subject to the following conditions: + + o Redistribution of source code must retain this license file + (`FTL.TXT') unaltered; any additions, deletions or changes to + the original files must be clearly indicated in accompanying + documentation. The copyright notices of the unaltered, + original files must be preserved in all copies of source + files. + + o Redistribution in binary form must provide a disclaimer that + states that the software is based in part of the work of the + FreeType Team, in the distribution documentation. We also + encourage you to put an URL to the FreeType web page in your + documentation, though this isn't mandatory. + + These conditions apply to any software derived from or based on + the FreeType Project, not just the unmodified files. If you use + our work, you must acknowledge us. However, no fee need be paid + to us. + +3. Advertising +-------------- + + Neither the FreeType authors and contributors nor you shall use + the name of the other for commercial, advertising, or promotional + purposes without specific prior written permission. + + We suggest, but do not require, that you use one or more of the + following phrases to refer to this software in your documentation + or advertising materials: `FreeType Project', `FreeType Engine', + `FreeType library', or `FreeType Distribution'. + + As you have not signed this license, you are not required to + accept it. However, as the FreeType Project is copyrighted + material, only this license, or another one contracted with the + authors, grants you the right to use, distribute, and modify it. + Therefore, by using, distributing, or modifying the FreeType + Project, you indicate that you understand and accept all the terms + of this license. + +4. Contacts +----------- + + There are two mailing lists related to FreeType: + + o freetype@nongnu.org + + Discusses general use and applications of FreeType, as well as + future and wanted additions to the library and distribution. + If you are looking for support, start in this list if you + haven't found anything to help you in the documentation. + + o freetype-devel@nongnu.org + + Discusses bugs, as well as engine internals, design issues, + specific licenses, porting, etc. + + Our home page can be found at + + https://www.freetype.org + + +--- end of FTL.TXT --- diff --git a/vendor/sdl3/ttf/LICENSE.harfbuzz.txt b/vendor/sdl3/ttf/LICENSE.harfbuzz.txt new file mode 100644 index 000000000..1dd917e9f --- /dev/null +++ b/vendor/sdl3/ttf/LICENSE.harfbuzz.txt @@ -0,0 +1,42 @@ +HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. +For parts of HarfBuzz that are licensed under different licenses see individual +files names COPYING in subdirectories where applicable. + +Copyright © 2010-2022 Google, Inc. +Copyright © 2015-2020 Ebrahim Byagowi +Copyright © 2019,2020 Facebook, Inc. +Copyright © 2012,2015 Mozilla Foundation +Copyright © 2011 Codethink Limited +Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) +Copyright © 2009 Keith Stribley +Copyright © 2011 Martin Hosken and SIL International +Copyright © 2007 Chris Wilson +Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod +Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc. +Copyright © 1998-2005 David Turner and Werner Lemberg +Copyright © 2016 Igalia S.L. +Copyright © 2022 Matthias Clasen +Copyright © 2018,2021 Khaled Hosny +Copyright © 2018,2019,2020 Adobe, Inc +Copyright © 2013-2015 Alexei Podtelezhnikov + +For full copyright notices consult the individual files in the package. + + +Permission is hereby granted, without written agreement and without +license or royalty fees, to use, copy, modify, and distribute this +software and its documentation for any purpose, provided that the +above copyright notice and the following two paragraphs appear in +all copies of this software. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN +IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/vendor/sdl3/ttf/LICENSE.plutosvg.txt b/vendor/sdl3/ttf/LICENSE.plutosvg.txt new file mode 100644 index 000000000..62a964e73 --- /dev/null +++ b/vendor/sdl3/ttf/LICENSE.plutosvg.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2025 Samuel Ugochukwu + +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/vendor/sdl3/ttf/LICENSE.plutovg.txt b/vendor/sdl3/ttf/LICENSE.plutovg.txt new file mode 100644 index 000000000..62a964e73 --- /dev/null +++ b/vendor/sdl3/ttf/LICENSE.plutovg.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2025 Samuel Ugochukwu + +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/vendor/sdl3/ttf/LICENSE.txt b/vendor/sdl3/ttf/LICENSE.txt new file mode 100644 index 000000000..52d0ed38b --- /dev/null +++ b/vendor/sdl3/ttf/LICENSE.txt @@ -0,0 +1,17 @@ +Copyright (C) 1997-2025 Sam Lantinga + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/vendor/sdl3/ttf/SDL3_ttf.dll b/vendor/sdl3/ttf/SDL3_ttf.dll new file mode 100644 index 000000000..b1616f966 Binary files /dev/null and b/vendor/sdl3/ttf/SDL3_ttf.dll differ diff --git a/vendor/sdl3/ttf/SDL3_ttf.lib b/vendor/sdl3/ttf/SDL3_ttf.lib new file mode 100644 index 000000000..5716c5661 Binary files /dev/null and b/vendor/sdl3/ttf/SDL3_ttf.lib differ diff --git a/vendor/sdl3/ttf/include/SDL_textengine.h b/vendor/sdl3/ttf/include/SDL_textengine.h new file mode 100644 index 000000000..9f5f1f0c3 --- /dev/null +++ b/vendor/sdl3/ttf/include/SDL_textengine.h @@ -0,0 +1,181 @@ +/* + SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts + Copyright (C) 2001-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + + +/** + * \file SDL_textengine.h + * + * Definitions for implementations of the TTF_TextEngine interface. + */ +#ifndef SDL_TTF_TEXTENGINE_H_ +#define SDL_TTF_TEXTENGINE_H_ + +#include +#include + +#include + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A font atlas draw command. + * + * \since This enum is available since SDL_ttf 3.0.0. + */ +typedef enum TTF_DrawCommand +{ + TTF_DRAW_COMMAND_NOOP, + TTF_DRAW_COMMAND_FILL, + TTF_DRAW_COMMAND_COPY +} TTF_DrawCommand; + +/** + * A filled rectangle draw operation. + * + * \since This struct is available since SDL_ttf 3.0.0. + * + * \sa TTF_DrawOperation + */ +typedef struct TTF_FillOperation +{ + TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_FILL */ + SDL_Rect rect; /**< The rectangle to fill, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */ +} TTF_FillOperation; + +/** + * A texture copy draw operation. + * + * \since This struct is available since SDL_ttf 3.0.0. + * + * \sa TTF_DrawOperation + */ +typedef struct TTF_CopyOperation +{ + TTF_DrawCommand cmd; /**< TTF_DRAW_COMMAND_COPY */ + int text_offset; /**< The offset in the text corresponding to this glyph. + There may be multiple glyphs with the same text offset + and the next text offset might be several Unicode codepoints + later. In this case the glyphs and codepoints are grouped + together and the group bounding box is the union of the dst + rectangles for the corresponding glyphs. */ + TTF_Font *glyph_font; /**< The font containing the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */ + Uint32 glyph_index; /**< The glyph index of the glyph to be drawn, can be passed to TTF_GetGlyphImageForIndex() */ + SDL_Rect src; /**< The area within the glyph to be drawn */ + SDL_Rect dst; /**< The drawing coordinates of the glyph, in pixels. The x coordinate is relative to the left side of the text area, going right, and the y coordinate is relative to the top side of the text area, going down. */ + void *reserved; +} TTF_CopyOperation; + +/** + * A text engine draw operation. + * + * \since This struct is available since SDL_ttf 3.0.0. + */ +typedef union TTF_DrawOperation +{ + TTF_DrawCommand cmd; + TTF_FillOperation fill; + TTF_CopyOperation copy; +} TTF_DrawOperation; + + +/* Private data in TTF_Text, to assist in text measurement and layout */ +typedef struct TTF_TextLayout TTF_TextLayout; + + +/* Private data in TTF_Text, available to implementations */ +struct TTF_TextData +{ + TTF_Font *font; /**< The font used by this text, read-only. */ + SDL_FColor color; /**< The color of the text, read-only. */ + + bool needs_layout_update; /**< True if the layout needs to be updated */ + TTF_TextLayout *layout; /**< Cached layout information, read-only. */ + int x; /**< The x offset of the upper left corner of this text, in pixels, read-only. */ + int y; /**< The y offset of the upper left corner of this text, in pixels, read-only. */ + int w; /**< The width of this text, in pixels, read-only. */ + int h; /**< The height of this text, in pixels, read-only. */ + int num_ops; /**< The number of drawing operations to render this text, read-only. */ + TTF_DrawOperation *ops; /**< The drawing operations used to render this text, read-only. */ + int num_clusters; /**< The number of substrings representing clusters of glyphs in the string, read-only */ + TTF_SubString *clusters; /**< Substrings representing clusters of glyphs in the string, read-only */ + + SDL_PropertiesID props; /**< Custom properties associated with this text, read-only. This field is created as-needed using TTF_GetTextProperties() and the properties may be then set and read normally */ + + bool needs_engine_update; /**< True if the engine text needs to be updated */ + TTF_TextEngine *engine; /**< The engine used to render this text, read-only. */ + void *engine_text; /**< The implementation-specific representation of this text */ +}; + +/** + * A text engine interface. + * + * This structure should be initialized using SDL_INIT_INTERFACE() + * + * \since This struct is available since SDL_ttf 3.0.0. + * + * \sa SDL_INIT_INTERFACE + */ +struct TTF_TextEngine +{ + Uint32 version; /**< The version of this interface */ + + void *userdata; /**< User data pointer passed to callbacks */ + + /* Create a text representation from draw instructions. + * + * All fields of `text` except `internal->engine_text` will already be filled out. + * + * This function should set the `internal->engine_text` field to a non-NULL value. + * + * \param userdata the userdata pointer in this interface. + * \param text the text object being created. + */ + bool (SDLCALL *CreateText)(void *userdata, TTF_Text *text); + + /** + * Destroy a text representation. + */ + void (SDLCALL *DestroyText)(void *userdata, TTF_Text *text); + +}; + +/* Check the size of TTF_TextEngine + * + * If this assert fails, either the compiler is padding to an unexpected size, + * or the interface has been updated and this should be updated to match and + * the code using this interface should be updated to handle the old version. + */ +SDL_COMPILE_TIME_ASSERT(TTF_TextEngine_SIZE, + (sizeof(void *) == 4 && sizeof(TTF_TextEngine) == 16) || + (sizeof(void *) == 8 && sizeof(TTF_TextEngine) == 32)); + + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include + +#endif /* SDL_TTF_TEXTENGINE_H_ */ + diff --git a/vendor/sdl3/ttf/include/SDL_ttf.h b/vendor/sdl3/ttf/include/SDL_ttf.h new file mode 100644 index 000000000..b723bc74e --- /dev/null +++ b/vendor/sdl3/ttf/include/SDL_ttf.h @@ -0,0 +1,2833 @@ +/* + SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts + Copyright (C) 2001-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* WIKI CATEGORY: SDLTTF */ + +/** + * # CategorySDLTTF + * + * Header file for SDL_ttf library + * + * This library is a wrapper around the excellent FreeType 2.0 library, + * available at: https://www.freetype.org/ + */ + +#ifndef SDL_TTF_H_ +#define SDL_TTF_H_ + +#include +#include + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Printable format: "%d.%d.%d", MAJOR, MINOR, MICRO + */ +#define SDL_TTF_MAJOR_VERSION 3 +#define SDL_TTF_MINOR_VERSION 2 +#define SDL_TTF_MICRO_VERSION 2 + +/** + * This is the version number macro for the current SDL_ttf version. + */ +#define SDL_TTF_VERSION \ + SDL_VERSIONNUM(SDL_TTF_MAJOR_VERSION, SDL_TTF_MINOR_VERSION, SDL_TTF_MICRO_VERSION) + +/** + * This macro will evaluate to true if compiled with SDL_ttf at least X.Y.Z. + */ +#define SDL_TTF_VERSION_ATLEAST(X, Y, Z) \ + ((SDL_TTF_MAJOR_VERSION >= X) && \ + (SDL_TTF_MAJOR_VERSION > X || SDL_TTF_MINOR_VERSION >= Y) && \ + (SDL_TTF_MAJOR_VERSION > X || SDL_TTF_MINOR_VERSION > Y || SDL_TTF_MICRO_VERSION >= Z)) + +/** + * This function gets the version of the dynamically linked SDL_ttf library. + * + * \returns SDL_ttf version. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC int SDLCALL TTF_Version(void); + +/** + * Query the version of the FreeType library in use. + * + * TTF_Init() should be called before calling this function. + * + * \param major to be filled in with the major version number. Can be NULL. + * \param minor to be filled in with the minor version number. Can be NULL. + * \param patch to be filled in with the param version number. Can be NULL. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_Init + */ +extern SDL_DECLSPEC void SDLCALL TTF_GetFreeTypeVersion(int *major, int *minor, int *patch); + +/** + * Query the version of the HarfBuzz library in use. + * + * If HarfBuzz is not available, the version reported is 0.0.0. + * + * \param major to be filled in with the major version number. Can be NULL. + * \param minor to be filled in with the minor version number. Can be NULL. + * \param patch to be filled in with the param version number. Can be NULL. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC void SDLCALL TTF_GetHarfBuzzVersion(int *major, int *minor, int *patch); + +/** + * The internal structure containing font information. + * + * Opaque data! + */ +typedef struct TTF_Font TTF_Font; + +/** + * Initialize SDL_ttf. + * + * You must successfully call this function before it is safe to call any + * other function in this library. + * + * It is safe to call this more than once, and each successful TTF_Init() call + * should be paired with a matching TTF_Quit() call. + * + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_Quit + */ +extern SDL_DECLSPEC bool SDLCALL TTF_Init(void); + +/** + * Create a font from a file, using a specified point size. + * + * Some .fon fonts will have several sizes embedded in the file, so the point + * size becomes the index of choosing which size. If the value is too high, + * the last indexed size will be the default. + * + * When done with the returned TTF_Font, use TTF_CloseFont() to dispose of it. + * + * \param file path to font file. + * \param ptsize point size to use for the newly-opened font. + * \returns a valid TTF_Font, or NULL on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CloseFont + */ +extern SDL_DECLSPEC TTF_Font * SDLCALL TTF_OpenFont(const char *file, float ptsize); + +/** + * Create a font from an SDL_IOStream, using a specified point size. + * + * Some .fon fonts will have several sizes embedded in the file, so the point + * size becomes the index of choosing which size. If the value is too high, + * the last indexed size will be the default. + * + * If `closeio` is true, `src` will be automatically closed once the font is + * closed. Otherwise you should close `src` yourself after closing the font. + * + * When done with the returned TTF_Font, use TTF_CloseFont() to dispose of it. + * + * \param src an SDL_IOStream to provide a font file's data. + * \param closeio true to close `src` when the font is closed, false to leave + * it open. + * \param ptsize point size to use for the newly-opened font. + * \returns a valid TTF_Font, or NULL on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CloseFont + */ +extern SDL_DECLSPEC TTF_Font * SDLCALL TTF_OpenFontIO(SDL_IOStream *src, bool closeio, float ptsize); + +/** + * Create a font with the specified properties. + * + * These are the supported properties: + * + * - `TTF_PROP_FONT_CREATE_FILENAME_STRING`: the font file to open, if an + * SDL_IOStream isn't being used. This is required if + * `TTF_PROP_FONT_CREATE_IOSTREAM_POINTER` and + * `TTF_PROP_FONT_CREATE_EXISTING_FONT` aren't set. + * - `TTF_PROP_FONT_CREATE_IOSTREAM_POINTER`: an SDL_IOStream containing the + * font to be opened. This should not be closed until the font is closed. + * This is required if `TTF_PROP_FONT_CREATE_FILENAME_STRING` and + * `TTF_PROP_FONT_CREATE_EXISTING_FONT` aren't set. + * - `TTF_PROP_FONT_CREATE_IOSTREAM_OFFSET_NUMBER`: the offset in the iostream + * for the beginning of the font, defaults to 0. + * - `TTF_PROP_FONT_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN`: true if closing the + * font should also close the associated SDL_IOStream. + * - `TTF_PROP_FONT_CREATE_SIZE_FLOAT`: the point size of the font. Some .fon + * fonts will have several sizes embedded in the file, so the point size + * becomes the index of choosing which size. If the value is too high, the + * last indexed size will be the default. + * - `TTF_PROP_FONT_CREATE_FACE_NUMBER`: the face index of the font, if the + * font contains multiple font faces. + * - `TTF_PROP_FONT_CREATE_HORIZONTAL_DPI_NUMBER`: the horizontal DPI to use + * for font rendering, defaults to + * `TTF_PROP_FONT_CREATE_VERTICAL_DPI_NUMBER` if set, or 72 otherwise. + * - `TTF_PROP_FONT_CREATE_VERTICAL_DPI_NUMBER`: the vertical DPI to use for + * font rendering, defaults to `TTF_PROP_FONT_CREATE_HORIZONTAL_DPI_NUMBER` + * if set, or 72 otherwise. + * - `TTF_PROP_FONT_CREATE_EXISTING_FONT`: an optional TTF_Font that, if set, + * will be used as the font data source and the initial size and style of + * the new font. + * + * \param props the properties to use. + * \returns a valid TTF_Font, or NULL on failure; call SDL_GetError() for more + * information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CloseFont + */ +extern SDL_DECLSPEC TTF_Font * SDLCALL TTF_OpenFontWithProperties(SDL_PropertiesID props); + +#define TTF_PROP_FONT_CREATE_FILENAME_STRING "SDL_ttf.font.create.filename" +#define TTF_PROP_FONT_CREATE_IOSTREAM_POINTER "SDL_ttf.font.create.iostream" +#define TTF_PROP_FONT_CREATE_IOSTREAM_OFFSET_NUMBER "SDL_ttf.font.create.iostream.offset" +#define TTF_PROP_FONT_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN "SDL_ttf.font.create.iostream.autoclose" +#define TTF_PROP_FONT_CREATE_SIZE_FLOAT "SDL_ttf.font.create.size" +#define TTF_PROP_FONT_CREATE_FACE_NUMBER "SDL_ttf.font.create.face" +#define TTF_PROP_FONT_CREATE_HORIZONTAL_DPI_NUMBER "SDL_ttf.font.create.hdpi" +#define TTF_PROP_FONT_CREATE_VERTICAL_DPI_NUMBER "SDL_ttf.font.create.vdpi" +#define TTF_PROP_FONT_CREATE_EXISTING_FONT "SDL_ttf.font.create.existing_font" + +/** + * Create a copy of an existing font. + * + * The copy will be distinct from the original, but will share the font file + * and have the same size and style as the original. + * + * When done with the returned TTF_Font, use TTF_CloseFont() to dispose of it. + * + * \param existing_font the font to copy. + * \returns a valid TTF_Font, or NULL on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * original font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CloseFont + */ +extern SDL_DECLSPEC TTF_Font * SDLCALL TTF_CopyFont(TTF_Font *existing_font); + +/** + * Get the properties associated with a font. + * + * The following read-write properties are provided by SDL: + * + * - `TTF_PROP_FONT_OUTLINE_LINE_CAP_NUMBER`: The FT_Stroker_LineCap value + * used when setting the font outline, defaults to + * `FT_STROKER_LINECAP_ROUND`. + * - `TTF_PROP_FONT_OUTLINE_LINE_JOIN_NUMBER`: The FT_Stroker_LineJoin value + * used when setting the font outline, defaults to + * `FT_STROKER_LINEJOIN_ROUND`. + * - `TTF_PROP_FONT_OUTLINE_MITER_LIMIT_NUMBER`: The FT_Fixed miter limit used + * when setting the font outline, defaults to 0. + * + * \param font the font to query. + * \returns a valid property ID on success or 0 on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL TTF_GetFontProperties(TTF_Font *font); + +#define TTF_PROP_FONT_OUTLINE_LINE_CAP_NUMBER "SDL_ttf.font.outline.line_cap" +#define TTF_PROP_FONT_OUTLINE_LINE_JOIN_NUMBER "SDL_ttf.font.outline.line_join" +#define TTF_PROP_FONT_OUTLINE_MITER_LIMIT_NUMBER "SDL_ttf.font.outline.miter_limit" + +/** + * Get the font generation. + * + * The generation is incremented each time font properties change that require + * rebuilding glyphs, such as style, size, etc. + * + * \param font the font to query. + * \returns the font generation or 0 on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC Uint32 SDLCALL TTF_GetFontGeneration(TTF_Font *font); + +/** + * Add a fallback font. + * + * Add a font that will be used for glyphs that are not in the current font. + * The fallback font should have the same size and style as the current font. + * + * If there are multiple fallback fonts, they are used in the order added. + * + * This updates any TTF_Text objects using this font. + * + * \param font the font to modify. + * \param fallback the font to add as a fallback. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created + * both fonts. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_ClearFallbackFonts + * \sa TTF_RemoveFallbackFont + */ +extern SDL_DECLSPEC bool SDLCALL TTF_AddFallbackFont(TTF_Font *font, TTF_Font *fallback); + +/** + * Remove a fallback font. + * + * This updates any TTF_Text objects using this font. + * + * \param font the font to modify. + * \param fallback the font to remove as a fallback. + * + * \threadsafety This function should be called on the thread that created + * both fonts. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_AddFallbackFont + * \sa TTF_ClearFallbackFonts + */ +extern SDL_DECLSPEC void SDLCALL TTF_RemoveFallbackFont(TTF_Font *font, TTF_Font *fallback); + +/** + * Remove all fallback fonts. + * + * This updates any TTF_Text objects using this font. + * + * \param font the font to modify. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_AddFallbackFont + * \sa TTF_RemoveFallbackFont + */ +extern SDL_DECLSPEC void SDLCALL TTF_ClearFallbackFonts(TTF_Font *font); + +/** + * Set a font's size dynamically. + * + * This updates any TTF_Text objects using this font, and clears + * already-generated glyphs, if any, from the cache. + * + * \param font the font to resize. + * \param ptsize the new point size. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetFontSize + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetFontSize(TTF_Font *font, float ptsize); + +/** + * Set font size dynamically with target resolutions, in dots per inch. + * + * This updates any TTF_Text objects using this font, and clears + * already-generated glyphs, if any, from the cache. + * + * \param font the font to resize. + * \param ptsize the new point size. + * \param hdpi the target horizontal DPI. + * \param vdpi the target vertical DPI. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetFontSize + * \sa TTF_GetFontSizeDPI + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetFontSizeDPI(TTF_Font *font, float ptsize, int hdpi, int vdpi); + +/** + * Get the size of a font. + * + * \param font the font to query. + * \returns the size of the font, or 0.0f on failure; call SDL_GetError() for + * more information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontSize + * \sa TTF_SetFontSizeDPI + */ +extern SDL_DECLSPEC float SDLCALL TTF_GetFontSize(TTF_Font *font); + +/** + * Get font target resolutions, in dots per inch. + * + * \param font the font to query. + * \param hdpi a pointer filled in with the target horizontal DPI. + * \param vdpi a pointer filled in with the target vertical DPI. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontSizeDPI + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetFontDPI(TTF_Font *font, int *hdpi, int *vdpi); + +/** + * Font style flags for TTF_Font + * + * These are the flags which can be used to set the style of a font in + * SDL_ttf. A combination of these flags can be used with functions that set + * or query font style, such as TTF_SetFontStyle or TTF_GetFontStyle. + * + * \since This datatype is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontStyle + * \sa TTF_GetFontStyle + */ +typedef Uint32 TTF_FontStyleFlags; + +#define TTF_STYLE_NORMAL 0x00 /**< No special style */ +#define TTF_STYLE_BOLD 0x01 /**< Bold style */ +#define TTF_STYLE_ITALIC 0x02 /**< Italic style */ +#define TTF_STYLE_UNDERLINE 0x04 /**< Underlined text */ +#define TTF_STYLE_STRIKETHROUGH 0x08 /**< Strikethrough text */ + +/** + * Set a font's current style. + * + * This updates any TTF_Text objects using this font, and clears + * already-generated glyphs, if any, from the cache. + * + * The font styles are a set of bit flags, OR'd together: + * + * - `TTF_STYLE_NORMAL` (is zero) + * - `TTF_STYLE_BOLD` + * - `TTF_STYLE_ITALIC` + * - `TTF_STYLE_UNDERLINE` + * - `TTF_STYLE_STRIKETHROUGH` + * + * \param font the font to set a new style on. + * \param style the new style values to set, OR'd together. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetFontStyle + */ +extern SDL_DECLSPEC void SDLCALL TTF_SetFontStyle(TTF_Font *font, TTF_FontStyleFlags style); + +/** + * Query a font's current style. + * + * The font styles are a set of bit flags, OR'd together: + * + * - `TTF_STYLE_NORMAL` (is zero) + * - `TTF_STYLE_BOLD` + * - `TTF_STYLE_ITALIC` + * - `TTF_STYLE_UNDERLINE` + * - `TTF_STYLE_STRIKETHROUGH` + * + * \param font the font to query. + * \returns the current font style, as a set of bit flags. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontStyle + */ +extern SDL_DECLSPEC TTF_FontStyleFlags SDLCALL TTF_GetFontStyle(const TTF_Font *font); + +/** + * Set a font's current outline. + * + * This uses the font properties `TTF_PROP_FONT_OUTLINE_LINE_CAP_NUMBER`, + * `TTF_PROP_FONT_OUTLINE_LINE_JOIN_NUMBER`, and + * `TTF_PROP_FONT_OUTLINE_MITER_LIMIT_NUMBER` when setting the font outline. + * + * This updates any TTF_Text objects using this font, and clears + * already-generated glyphs, if any, from the cache. + * + * \param font the font to set a new outline on. + * \param outline positive outline value, 0 to default. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetFontOutline + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetFontOutline(TTF_Font *font, int outline); + +/** + * Query a font's current outline. + * + * \param font the font to query. + * \returns the font's current outline value. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontOutline + */ +extern SDL_DECLSPEC int SDLCALL TTF_GetFontOutline(const TTF_Font *font); + +/** + * Hinting flags for TTF (TrueType Fonts) + * + * This enum specifies the level of hinting to be applied to the font + * rendering. The hinting level determines how much the font's outlines are + * adjusted for better alignment on the pixel grid. + * + * \since This enum is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontHinting + * \sa TTF_GetFontHinting + */ +typedef enum TTF_HintingFlags +{ + TTF_HINTING_INVALID = -1, + TTF_HINTING_NORMAL, /**< Normal hinting applies standard grid-fitting. */ + TTF_HINTING_LIGHT, /**< Light hinting applies subtle adjustments to improve rendering. */ + TTF_HINTING_MONO, /**< Monochrome hinting adjusts the font for better rendering at lower resolutions. */ + TTF_HINTING_NONE, /**< No hinting, the font is rendered without any grid-fitting. */ + TTF_HINTING_LIGHT_SUBPIXEL /**< Light hinting with subpixel rendering for more precise font edges. */ +} TTF_HintingFlags; + +/** + * Set a font's current hinter setting. + * + * This updates any TTF_Text objects using this font, and clears + * already-generated glyphs, if any, from the cache. + * + * The hinter setting is a single value: + * + * - `TTF_HINTING_NORMAL` + * - `TTF_HINTING_LIGHT` + * - `TTF_HINTING_MONO` + * - `TTF_HINTING_NONE` + * - `TTF_HINTING_LIGHT_SUBPIXEL` (available in SDL_ttf 3.0.0 and later) + * + * \param font the font to set a new hinter setting on. + * \param hinting the new hinter setting. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetFontHinting + */ +extern SDL_DECLSPEC void SDLCALL TTF_SetFontHinting(TTF_Font *font, TTF_HintingFlags hinting); + +/** + * Query the number of faces of a font. + * + * \param font the font to query. + * \returns the number of FreeType font faces. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC int SDLCALL TTF_GetNumFontFaces(const TTF_Font *font); + +/** + * Query a font's current FreeType hinter setting. + * + * The hinter setting is a single value: + * + * - `TTF_HINTING_NORMAL` + * - `TTF_HINTING_LIGHT` + * - `TTF_HINTING_MONO` + * - `TTF_HINTING_NONE` + * - `TTF_HINTING_LIGHT_SUBPIXEL` (available in SDL_ttf 3.0.0 and later) + * + * \param font the font to query. + * \returns the font's current hinter value, or TTF_HINTING_INVALID if the + * font is invalid. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontHinting + */ +extern SDL_DECLSPEC TTF_HintingFlags SDLCALL TTF_GetFontHinting(const TTF_Font *font); + +/** + * Enable Signed Distance Field rendering for a font. + * + * SDF is a technique that helps fonts look sharp even when scaling and + * rotating, and requires special shader support for display. + * + * This works with Blended APIs, and generates the raw signed distance values + * in the alpha channel of the resulting texture. + * + * This updates any TTF_Text objects using this font, and clears + * already-generated glyphs, if any, from the cache. + * + * \param font the font to set SDF support on. + * \param enabled true to enable SDF, false to disable. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetFontSDF + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetFontSDF(TTF_Font *font, bool enabled); + +/** + * Query whether Signed Distance Field rendering is enabled for a font. + * + * \param font the font to query. + * \returns true if enabled, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontSDF + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetFontSDF(const TTF_Font *font); + +/** + * Query a font's weight, in terms of the lightness/heaviness of the strokes. + * + * \param font the font to query. + * \returns the font's current weight. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.4.0. + */ +extern SDL_DECLSPEC int SDLCALL TTF_GetFontWeight(const TTF_Font *font); + +#define TTF_FONT_WEIGHT_THIN 100 /**< Thin (100) named font weight value */ +#define TTF_FONT_WEIGHT_EXTRA_LIGHT 200 /**< ExtraLight (200) named font weight value */ +#define TTF_FONT_WEIGHT_LIGHT 300 /**< Light (300) named font weight value */ +#define TTF_FONT_WEIGHT_NORMAL 400 /**< Normal (400) named font weight value */ +#define TTF_FONT_WEIGHT_MEDIUM 500 /**< Medium (500) named font weight value */ +#define TTF_FONT_WEIGHT_SEMI_BOLD 600 /**< SemiBold (600) named font weight value */ +#define TTF_FONT_WEIGHT_BOLD 700 /**< Bold (700) named font weight value */ +#define TTF_FONT_WEIGHT_EXTRA_BOLD 800 /**< ExtraBold (800) named font weight value */ +#define TTF_FONT_WEIGHT_BLACK 900 /**< Black (900) named font weight value */ +#define TTF_FONT_WEIGHT_EXTRA_BLACK 950 /**< ExtraBlack (950) named font weight value */ + +/** + * The horizontal alignment used when rendering wrapped text. + * + * \since This enum is available since SDL_ttf 3.0.0. + */ +typedef enum TTF_HorizontalAlignment +{ + TTF_HORIZONTAL_ALIGN_INVALID = -1, + TTF_HORIZONTAL_ALIGN_LEFT, + TTF_HORIZONTAL_ALIGN_CENTER, + TTF_HORIZONTAL_ALIGN_RIGHT +} TTF_HorizontalAlignment; + +/** + * Set a font's current wrap alignment option. + * + * This updates any TTF_Text objects using this font. + * + * \param font the font to set a new wrap alignment option on. + * \param align the new wrap alignment option. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetFontWrapAlignment + */ +extern SDL_DECLSPEC void SDLCALL TTF_SetFontWrapAlignment(TTF_Font *font, TTF_HorizontalAlignment align); + +/** + * Query a font's current wrap alignment option. + * + * \param font the font to query. + * \returns the font's current wrap alignment option. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontWrapAlignment + */ +extern SDL_DECLSPEC TTF_HorizontalAlignment SDLCALL TTF_GetFontWrapAlignment(const TTF_Font *font); + +/** + * Query the total height of a font. + * + * This is usually equal to point size. + * + * \param font the font to query. + * \returns the font's height. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC int SDLCALL TTF_GetFontHeight(const TTF_Font *font); + +/** + * Query the offset from the baseline to the top of a font. + * + * This is a positive value, relative to the baseline. + * + * \param font the font to query. + * \returns the font's ascent. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC int SDLCALL TTF_GetFontAscent(const TTF_Font *font); + +/** + * Query the offset from the baseline to the bottom of a font. + * + * This is a negative value, relative to the baseline. + * + * \param font the font to query. + * \returns the font's descent. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC int SDLCALL TTF_GetFontDescent(const TTF_Font *font); + +/** + * Set the spacing between lines of text for a font. + * + * This updates any TTF_Text objects using this font. + * + * \param font the font to modify. + * \param lineskip the new line spacing for the font. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetFontLineSkip + */ +extern SDL_DECLSPEC void SDLCALL TTF_SetFontLineSkip(TTF_Font *font, int lineskip); + +/** + * Query the spacing between lines of text for a font. + * + * \param font the font to query. + * \returns the font's recommended spacing. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontLineSkip + */ +extern SDL_DECLSPEC int SDLCALL TTF_GetFontLineSkip(const TTF_Font *font); + +/** + * Set if kerning is enabled for a font. + * + * Newly-opened fonts default to allowing kerning. This is generally a good + * policy unless you have a strong reason to disable it, as it tends to + * produce better rendering (with kerning disabled, some fonts might render + * the word `kerning` as something that looks like `keming` for example). + * + * This updates any TTF_Text objects using this font. + * + * \param font the font to set kerning on. + * \param enabled true to enable kerning, false to disable. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetFontKerning + */ +extern SDL_DECLSPEC void SDLCALL TTF_SetFontKerning(TTF_Font *font, bool enabled); + +/** + * Query whether or not kerning is enabled for a font. + * + * \param font the font to query. + * \returns true if kerning is enabled, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontKerning + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetFontKerning(const TTF_Font *font); + +/** + * Query whether a font is fixed-width. + * + * A "fixed-width" font means all glyphs are the same width across; a + * lowercase 'i' will be the same size across as a capital 'W', for example. + * This is common for terminals and text editors, and other apps that treat + * text as a grid. Most other things (WYSIWYG word processors, web pages, etc) + * are more likely to not be fixed-width in most cases. + * + * \param font the font to query. + * \returns true if the font is fixed-width, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_FontIsFixedWidth(const TTF_Font *font); + +/** + * Query whether a font is scalable or not. + * + * Scalability lets us distinguish between outline and bitmap fonts. + * + * \param font the font to query. + * \returns true if the font is scalable, false otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontSDF + */ +extern SDL_DECLSPEC bool SDLCALL TTF_FontIsScalable(const TTF_Font *font); + +/** + * Query a font's family name. + * + * This string is dictated by the contents of the font file. + * + * Note that the returned string is to internal storage, and should not be + * modified or free'd by the caller. The string becomes invalid, with the rest + * of the font, when `font` is handed to TTF_CloseFont(). + * + * \param font the font to query. + * \returns the font's family name. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC const char * SDLCALL TTF_GetFontFamilyName(const TTF_Font *font); + +/** + * Query a font's style name. + * + * This string is dictated by the contents of the font file. + * + * Note that the returned string is to internal storage, and should not be + * modified or free'd by the caller. The string becomes invalid, with the rest + * of the font, when `font` is handed to TTF_CloseFont(). + * + * \param font the font to query. + * \returns the font's style name. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC const char * SDLCALL TTF_GetFontStyleName(const TTF_Font *font); + +/** + * Direction flags + * + * The values here are chosen to match + * [hb_direction_t](https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-direction-t) + * . + * + * \since This enum is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetFontDirection + */ +typedef enum TTF_Direction +{ + TTF_DIRECTION_INVALID = 0, + TTF_DIRECTION_LTR = 4, /**< Left to Right */ + TTF_DIRECTION_RTL, /**< Right to Left */ + TTF_DIRECTION_TTB, /**< Top to Bottom */ + TTF_DIRECTION_BTT /**< Bottom to Top */ +} TTF_Direction; + +/** + * Set the direction to be used for text shaping by a font. + * + * This function only supports left-to-right text shaping if SDL_ttf was not + * built with HarfBuzz support. + * + * This updates any TTF_Text objects using this font. + * + * \param font the font to modify. + * \param direction the new direction for text to flow. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetFontDirection(TTF_Font *font, TTF_Direction direction); + +/** + * Get the direction to be used for text shaping by a font. + * + * This defaults to TTF_DIRECTION_INVALID if it hasn't been set. + * + * \param font the font to query. + * \returns the direction to be used for text shaping. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC TTF_Direction SDLCALL TTF_GetFontDirection(TTF_Font *font); + +/** + * Convert from a 4 character string to a 32-bit tag. + * + * \param string the 4 character string to convert. + * \returns the 32-bit representation of the string. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_TagToString + */ +extern SDL_DECLSPEC Uint32 SDLCALL TTF_StringToTag(const char *string); + +/** + * Convert from a 32-bit tag to a 4 character string. + * + * \param tag the 32-bit tag to convert. + * \param string a pointer filled in with the 4 character representation of + * the tag. + * \param size the size of the buffer pointed at by string, should be at least + * 4. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_TagToString + */ +extern SDL_DECLSPEC void SDLCALL TTF_TagToString(Uint32 tag, char *string, size_t size); + +/** + * Set the script to be used for text shaping by a font. + * + * This returns false if SDL_ttf isn't built with HarfBuzz support. + * + * This updates any TTF_Text objects using this font. + * + * \param font the font to modify. + * \param script an + * [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html) + * . + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_StringToTag + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetFontScript(TTF_Font *font, Uint32 script); + +/** + * Get the script used for text shaping a font. + * + * \param font the font to query. + * \returns an + * [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html) + * or 0 if a script hasn't been set. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_TagToString + */ +extern SDL_DECLSPEC Uint32 SDLCALL TTF_GetFontScript(TTF_Font *font); + +/** + * Get the script used by a 32-bit codepoint. + * + * \param ch the character code to check. + * \returns an + * [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html) + * on success, or 0 on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function is thread-safe. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_TagToString + */ +extern SDL_DECLSPEC Uint32 SDLCALL TTF_GetGlyphScript(Uint32 ch); + +/** + * Set language to be used for text shaping by a font. + * + * If SDL_ttf was not built with HarfBuzz support, this function returns + * false. + * + * This updates any TTF_Text objects using this font. + * + * \param font the font to specify a language for. + * \param language_bcp47 a null-terminated string containing the desired + * language's BCP47 code. Or null to reset the value. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetFontLanguage(TTF_Font *font, const char *language_bcp47); + +/** + * Check whether a glyph is provided by the font for a UNICODE codepoint. + * + * \param font the font to query. + * \param ch the codepoint to check. + * \returns true if font provides a glyph for this character, false if not. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_FontHasGlyph(TTF_Font *font, Uint32 ch); + +/** + * The type of data in a glyph image + * + * \since This enum is available since SDL_ttf 3.0.0. + */ +typedef enum TTF_ImageType +{ + TTF_IMAGE_INVALID, + TTF_IMAGE_ALPHA, /**< The color channels are white */ + TTF_IMAGE_COLOR, /**< The color channels have image data */ + TTF_IMAGE_SDF, /**< The alpha channel has signed distance field information */ +} TTF_ImageType; + +/** + * Get the pixel image for a UNICODE codepoint. + * + * \param font the font to query. + * \param ch the codepoint to check. + * \param image_type a pointer filled in with the glyph image type, may be + * NULL. + * \returns an SDL_Surface containing the glyph, or NULL on failure; call + * SDL_GetError() for more information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_GetGlyphImage(TTF_Font *font, Uint32 ch, TTF_ImageType *image_type); + +/** + * Get the pixel image for a character index. + * + * This is useful for text engine implementations, which can call this with + * the `glyph_index` in a TTF_CopyOperation + * + * \param font the font to query. + * \param glyph_index the index of the glyph to return. + * \param image_type a pointer filled in with the glyph image type, may be + * NULL. + * \returns an SDL_Surface containing the glyph, or NULL on failure; call + * SDL_GetError() for more information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_GetGlyphImageForIndex(TTF_Font *font, Uint32 glyph_index, TTF_ImageType *image_type); + +/** + * Query the metrics (dimensions) of a font's glyph for a UNICODE codepoint. + * + * To understand what these metrics mean, here is a useful link: + * + * https://freetype.sourceforge.net/freetype2/docs/tutorial/step2.html + * + * \param font the font to query. + * \param ch the codepoint to check. + * \param minx a pointer filled in with the minimum x coordinate of the glyph + * from the left edge of its bounding box. This value may be + * negative. + * \param maxx a pointer filled in with the maximum x coordinate of the glyph + * from the left edge of its bounding box. + * \param miny a pointer filled in with the minimum y coordinate of the glyph + * from the bottom edge of its bounding box. This value may be + * negative. + * \param maxy a pointer filled in with the maximum y coordinate of the glyph + * from the bottom edge of its bounding box. + * \param advance a pointer filled in with the distance to the next glyph from + * the left edge of this glyph's bounding box. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetGlyphMetrics(TTF_Font *font, Uint32 ch, int *minx, int *maxx, int *miny, int *maxy, int *advance); + +/** + * Query the kerning size between the glyphs of two UNICODE codepoints. + * + * \param font the font to query. + * \param previous_ch the previous codepoint. + * \param ch the current codepoint. + * \param kerning a pointer filled in with the kerning size between the two + * glyphs, in pixels, may be NULL. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetGlyphKerning(TTF_Font *font, Uint32 previous_ch, Uint32 ch, int *kerning); + +/** + * Calculate the dimensions of a rendered string of UTF-8 text. + * + * This will report the width and height, in pixels, of the space that the + * specified string will take to fully render. + * + * \param font the font to query. + * \param text text to calculate, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param w will be filled with width, in pixels, on return. + * \param h will be filled with height, in pixels, on return. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetStringSize(TTF_Font *font, const char *text, size_t length, int *w, int *h); + +/** + * Calculate the dimensions of a rendered string of UTF-8 text. + * + * This will report the width and height, in pixels, of the space that the + * specified string will take to fully render. + * + * Text is wrapped to multiple lines on line endings and on word boundaries if + * it extends beyond `wrap_width` in pixels. + * + * If wrap_width is 0, this function will only wrap on newline characters. + * + * \param font the font to query. + * \param text text to calculate, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param wrap_width the maximum width or 0 to wrap on newline characters. + * \param w will be filled with width, in pixels, on return. + * \param h will be filled with height, in pixels, on return. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetStringSizeWrapped(TTF_Font *font, const char *text, size_t length, int wrap_width, int *w, int *h); + +/** + * Calculate how much of a UTF-8 string will fit in a given width. + * + * This reports the number of characters that can be rendered before reaching + * `max_width`. + * + * This does not need to render the string to do this calculation. + * + * \param font the font to query. + * \param text text to calculate, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param max_width maximum width, in pixels, available for the string, or 0 + * for unbounded width. + * \param measured_width a pointer filled in with the width, in pixels, of the + * string that will fit, may be NULL. + * \param measured_length a pointer filled in with the length, in bytes, of + * the string that will fit, may be NULL. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_MeasureString(TTF_Font *font, const char *text, size_t length, int max_width, int *measured_width, size_t *measured_length); + +/** + * Render UTF-8 text at fast quality to a new 8-bit surface. + * + * This function will allocate a new 8-bit, palettized surface. The surface's + * 0 pixel will be the colorkey, giving a transparent background. The 1 pixel + * will be set to the text color. + * + * This will not word-wrap the string; you'll get a surface with a single line + * of text, as long as the string requires. You can use + * TTF_RenderText_Solid_Wrapped() instead if you need to wrap the output to + * multiple lines. + * + * This will not wrap on newline characters. + * + * You can render at other quality levels with TTF_RenderText_Shaded, + * TTF_RenderText_Blended, and TTF_RenderText_LCD. + * + * \param font the font to render with. + * \param text text to render, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param fg the foreground color for the text. + * \returns a new 8-bit, palettized surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderText_Blended + * \sa TTF_RenderText_LCD + * \sa TTF_RenderText_Shaded + * \sa TTF_RenderText_Solid + * \sa TTF_RenderText_Solid_Wrapped + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Solid(TTF_Font *font, const char *text, size_t length, SDL_Color fg); + +/** + * Render word-wrapped UTF-8 text at fast quality to a new 8-bit surface. + * + * This function will allocate a new 8-bit, palettized surface. The surface's + * 0 pixel will be the colorkey, giving a transparent background. The 1 pixel + * will be set to the text color. + * + * Text is wrapped to multiple lines on line endings and on word boundaries if + * it extends beyond `wrapLength` in pixels. + * + * If wrapLength is 0, this function will only wrap on newline characters. + * + * You can render at other quality levels with TTF_RenderText_Shaded_Wrapped, + * TTF_RenderText_Blended_Wrapped, and TTF_RenderText_LCD_Wrapped. + * + * \param font the font to render with. + * \param text text to render, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param fg the foreground color for the text. + * \param wrapLength the maximum width of the text surface or 0 to wrap on + * newline characters. + * \returns a new 8-bit, palettized surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderText_Blended_Wrapped + * \sa TTF_RenderText_LCD_Wrapped + * \sa TTF_RenderText_Shaded_Wrapped + * \sa TTF_RenderText_Solid + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Solid_Wrapped(TTF_Font *font, const char *text, size_t length, SDL_Color fg, int wrapLength); + +/** + * Render a single 32-bit glyph at fast quality to a new 8-bit surface. + * + * This function will allocate a new 8-bit, palettized surface. The surface's + * 0 pixel will be the colorkey, giving a transparent background. The 1 pixel + * will be set to the text color. + * + * The glyph is rendered without any padding or centering in the X direction, + * and aligned normally in the Y direction. + * + * You can render at other quality levels with TTF_RenderGlyph_Shaded, + * TTF_RenderGlyph_Blended, and TTF_RenderGlyph_LCD. + * + * \param font the font to render with. + * \param ch the character to render. + * \param fg the foreground color for the text. + * \returns a new 8-bit, palettized surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderGlyph_Blended + * \sa TTF_RenderGlyph_LCD + * \sa TTF_RenderGlyph_Shaded + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Solid(TTF_Font *font, Uint32 ch, SDL_Color fg); + +/** + * Render UTF-8 text at high quality to a new 8-bit surface. + * + * This function will allocate a new 8-bit, palettized surface. The surface's + * 0 pixel will be the specified background color, while other pixels have + * varying degrees of the foreground color. This function returns the new + * surface, or NULL if there was an error. + * + * This will not word-wrap the string; you'll get a surface with a single line + * of text, as long as the string requires. You can use + * TTF_RenderText_Shaded_Wrapped() instead if you need to wrap the output to + * multiple lines. + * + * This will not wrap on newline characters. + * + * You can render at other quality levels with TTF_RenderText_Solid, + * TTF_RenderText_Blended, and TTF_RenderText_LCD. + * + * \param font the font to render with. + * \param text text to render, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param fg the foreground color for the text. + * \param bg the background color for the text. + * \returns a new 8-bit, palettized surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderText_Blended + * \sa TTF_RenderText_LCD + * \sa TTF_RenderText_Shaded_Wrapped + * \sa TTF_RenderText_Solid + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded(TTF_Font *font, const char *text, size_t length, SDL_Color fg, SDL_Color bg); + +/** + * Render word-wrapped UTF-8 text at high quality to a new 8-bit surface. + * + * This function will allocate a new 8-bit, palettized surface. The surface's + * 0 pixel will be the specified background color, while other pixels have + * varying degrees of the foreground color. This function returns the new + * surface, or NULL if there was an error. + * + * Text is wrapped to multiple lines on line endings and on word boundaries if + * it extends beyond `wrap_width` in pixels. + * + * If wrap_width is 0, this function will only wrap on newline characters. + * + * You can render at other quality levels with TTF_RenderText_Solid_Wrapped, + * TTF_RenderText_Blended_Wrapped, and TTF_RenderText_LCD_Wrapped. + * + * \param font the font to render with. + * \param text text to render, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param fg the foreground color for the text. + * \param bg the background color for the text. + * \param wrap_width the maximum width of the text surface or 0 to wrap on + * newline characters. + * \returns a new 8-bit, palettized surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderText_Blended_Wrapped + * \sa TTF_RenderText_LCD_Wrapped + * \sa TTF_RenderText_Shaded + * \sa TTF_RenderText_Solid_Wrapped + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded_Wrapped(TTF_Font *font, const char *text, size_t length, SDL_Color fg, SDL_Color bg, int wrap_width); + +/** + * Render a single UNICODE codepoint at high quality to a new 8-bit surface. + * + * This function will allocate a new 8-bit, palettized surface. The surface's + * 0 pixel will be the specified background color, while other pixels have + * varying degrees of the foreground color. This function returns the new + * surface, or NULL if there was an error. + * + * The glyph is rendered without any padding or centering in the X direction, + * and aligned normally in the Y direction. + * + * You can render at other quality levels with TTF_RenderGlyph_Solid, + * TTF_RenderGlyph_Blended, and TTF_RenderGlyph_LCD. + * + * \param font the font to render with. + * \param ch the codepoint to render. + * \param fg the foreground color for the text. + * \param bg the background color for the text. + * \returns a new 8-bit, palettized surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderGlyph_Blended + * \sa TTF_RenderGlyph_LCD + * \sa TTF_RenderGlyph_Solid + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Shaded(TTF_Font *font, Uint32 ch, SDL_Color fg, SDL_Color bg); + +/** + * Render UTF-8 text at high quality to a new ARGB surface. + * + * This function will allocate a new 32-bit, ARGB surface, using alpha + * blending to dither the font with the given color. This function returns the + * new surface, or NULL if there was an error. + * + * This will not word-wrap the string; you'll get a surface with a single line + * of text, as long as the string requires. You can use + * TTF_RenderText_Blended_Wrapped() instead if you need to wrap the output to + * multiple lines. + * + * This will not wrap on newline characters. + * + * You can render at other quality levels with TTF_RenderText_Solid, + * TTF_RenderText_Shaded, and TTF_RenderText_LCD. + * + * \param font the font to render with. + * \param text text to render, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param fg the foreground color for the text. + * \returns a new 32-bit, ARGB surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderText_Blended_Wrapped + * \sa TTF_RenderText_LCD + * \sa TTF_RenderText_Shaded + * \sa TTF_RenderText_Solid + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended(TTF_Font *font, const char *text, size_t length, SDL_Color fg); + +/** + * Render word-wrapped UTF-8 text at high quality to a new ARGB surface. + * + * This function will allocate a new 32-bit, ARGB surface, using alpha + * blending to dither the font with the given color. This function returns the + * new surface, or NULL if there was an error. + * + * Text is wrapped to multiple lines on line endings and on word boundaries if + * it extends beyond `wrap_width` in pixels. + * + * If wrap_width is 0, this function will only wrap on newline characters. + * + * You can render at other quality levels with TTF_RenderText_Solid_Wrapped, + * TTF_RenderText_Shaded_Wrapped, and TTF_RenderText_LCD_Wrapped. + * + * \param font the font to render with. + * \param text text to render, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param fg the foreground color for the text. + * \param wrap_width the maximum width of the text surface or 0 to wrap on + * newline characters. + * \returns a new 32-bit, ARGB surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderText_Blended + * \sa TTF_RenderText_LCD_Wrapped + * \sa TTF_RenderText_Shaded_Wrapped + * \sa TTF_RenderText_Solid_Wrapped + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended_Wrapped(TTF_Font *font, const char *text, size_t length, SDL_Color fg, int wrap_width); + +/** + * Render a single UNICODE codepoint at high quality to a new ARGB surface. + * + * This function will allocate a new 32-bit, ARGB surface, using alpha + * blending to dither the font with the given color. This function returns the + * new surface, or NULL if there was an error. + * + * The glyph is rendered without any padding or centering in the X direction, + * and aligned normally in the Y direction. + * + * You can render at other quality levels with TTF_RenderGlyph_Solid, + * TTF_RenderGlyph_Shaded, and TTF_RenderGlyph_LCD. + * + * \param font the font to render with. + * \param ch the codepoint to render. + * \param fg the foreground color for the text. + * \returns a new 32-bit, ARGB surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderGlyph_LCD + * \sa TTF_RenderGlyph_Shaded + * \sa TTF_RenderGlyph_Solid + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Blended(TTF_Font *font, Uint32 ch, SDL_Color fg); + +/** + * Render UTF-8 text at LCD subpixel quality to a new ARGB surface. + * + * This function will allocate a new 32-bit, ARGB surface, and render + * alpha-blended text using FreeType's LCD subpixel rendering. This function + * returns the new surface, or NULL if there was an error. + * + * This will not word-wrap the string; you'll get a surface with a single line + * of text, as long as the string requires. You can use + * TTF_RenderText_LCD_Wrapped() instead if you need to wrap the output to + * multiple lines. + * + * This will not wrap on newline characters. + * + * You can render at other quality levels with TTF_RenderText_Solid, + * TTF_RenderText_Shaded, and TTF_RenderText_Blended. + * + * \param font the font to render with. + * \param text text to render, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param fg the foreground color for the text. + * \param bg the background color for the text. + * \returns a new 32-bit, ARGB surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderText_Blended + * \sa TTF_RenderText_LCD_Wrapped + * \sa TTF_RenderText_Shaded + * \sa TTF_RenderText_Solid + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD(TTF_Font *font, const char *text, size_t length, SDL_Color fg, SDL_Color bg); + +/** + * Render word-wrapped UTF-8 text at LCD subpixel quality to a new ARGB + * surface. + * + * This function will allocate a new 32-bit, ARGB surface, and render + * alpha-blended text using FreeType's LCD subpixel rendering. This function + * returns the new surface, or NULL if there was an error. + * + * Text is wrapped to multiple lines on line endings and on word boundaries if + * it extends beyond `wrap_width` in pixels. + * + * If wrap_width is 0, this function will only wrap on newline characters. + * + * You can render at other quality levels with TTF_RenderText_Solid_Wrapped, + * TTF_RenderText_Shaded_Wrapped, and TTF_RenderText_Blended_Wrapped. + * + * \param font the font to render with. + * \param text text to render, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \param fg the foreground color for the text. + * \param bg the background color for the text. + * \param wrap_width the maximum width of the text surface or 0 to wrap on + * newline characters. + * \returns a new 32-bit, ARGB surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderText_Blended_Wrapped + * \sa TTF_RenderText_LCD + * \sa TTF_RenderText_Shaded_Wrapped + * \sa TTF_RenderText_Solid_Wrapped + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD_Wrapped(TTF_Font *font, const char *text, size_t length, SDL_Color fg, SDL_Color bg, int wrap_width); + +/** + * Render a single UNICODE codepoint at LCD subpixel quality to a new ARGB + * surface. + * + * This function will allocate a new 32-bit, ARGB surface, and render + * alpha-blended text using FreeType's LCD subpixel rendering. This function + * returns the new surface, or NULL if there was an error. + * + * The glyph is rendered without any padding or centering in the X direction, + * and aligned normally in the Y direction. + * + * You can render at other quality levels with TTF_RenderGlyph_Solid, + * TTF_RenderGlyph_Shaded, and TTF_RenderGlyph_Blended. + * + * \param font the font to render with. + * \param ch the codepoint to render. + * \param fg the foreground color for the text. + * \param bg the background color for the text. + * \returns a new 32-bit, ARGB surface, or NULL if there was an error. + * + * \threadsafety This function should be called on the thread that created the + * font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_RenderGlyph_Blended + * \sa TTF_RenderGlyph_Shaded + * \sa TTF_RenderGlyph_Solid + */ +extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_LCD(TTF_Font *font, Uint32 ch, SDL_Color fg, SDL_Color bg); + + +/** + * A text engine used to create text objects. + * + * This is a public interface that can be used by applications and libraries + * to perform customize rendering with text objects. See + * for details. + * + * There are three text engines provided with the library: + * + * - Drawing to an SDL_Surface, created with TTF_CreateSurfaceTextEngine() + * - Drawing with an SDL 2D renderer, created with + * TTF_CreateRendererTextEngine() + * - Drawing with the SDL GPU API, created with TTF_CreateGPUTextEngine() + * + * \since This struct is available since SDL_ttf 3.0.0. + */ +typedef struct TTF_TextEngine TTF_TextEngine; + +/** + * Internal data for TTF_Text + * + * \since This struct is available since SDL_ttf 3.0.0. + */ +typedef struct TTF_TextData TTF_TextData; + +/** + * Text created with TTF_CreateText() + * + * \since This struct is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateText + * \sa TTF_GetTextProperties + * \sa TTF_DestroyText + */ +typedef struct TTF_Text +{ + char *text; /**< A copy of the UTF-8 string that this text object represents, useful for layout, debugging and retrieving substring text. This is updated when the text object is modified and will be freed automatically when the object is destroyed. */ + int num_lines; /**< The number of lines in the text, 0 if it's empty */ + + int refcount; /**< Application reference count, used when freeing surface */ + + TTF_TextData *internal; /**< Private */ + +} TTF_Text; + +/** + * Create a text engine for drawing text on SDL surfaces. + * + * \returns a TTF_TextEngine object or NULL on failure; call SDL_GetError() + * for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_DestroySurfaceTextEngine + * \sa TTF_DrawSurfaceText + */ +extern SDL_DECLSPEC TTF_TextEngine * SDLCALL TTF_CreateSurfaceTextEngine(void); + +/** + * Draw text to an SDL surface. + * + * `text` must have been created using a TTF_TextEngine from + * TTF_CreateSurfaceTextEngine(). + * + * \param text the text to draw. + * \param x the x coordinate in pixels, positive from the left edge towards + * the right. + * \param y the y coordinate in pixels, positive from the top edge towards the + * bottom. + * \param surface the surface to draw on. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateSurfaceTextEngine + * \sa TTF_CreateText + */ +extern SDL_DECLSPEC bool SDLCALL TTF_DrawSurfaceText(TTF_Text *text, int x, int y, SDL_Surface *surface); + +/** + * Destroy a text engine created for drawing text on SDL surfaces. + * + * All text created by this engine should be destroyed before calling this + * function. + * + * \param engine a TTF_TextEngine object created with + * TTF_CreateSurfaceTextEngine(). + * + * \threadsafety This function should be called on the thread that created the + * engine. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateSurfaceTextEngine + */ +extern SDL_DECLSPEC void SDLCALL TTF_DestroySurfaceTextEngine(TTF_TextEngine *engine); + +/** + * Create a text engine for drawing text on an SDL renderer. + * + * \param renderer the renderer to use for creating textures and drawing text. + * \returns a TTF_TextEngine object or NULL on failure; call SDL_GetError() + * for more information. + * + * \threadsafety This function should be called on the thread that created the + * renderer. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_DestroyRendererTextEngine + * \sa TTF_DrawRendererText + * \sa TTF_CreateRendererTextEngineWithProperties + */ +extern SDL_DECLSPEC TTF_TextEngine * SDLCALL TTF_CreateRendererTextEngine(SDL_Renderer *renderer); + +/** + * Create a text engine for drawing text on an SDL renderer, with the + * specified properties. + * + * These are the supported properties: + * + * - `TTF_PROP_RENDERER_TEXT_ENGINE_RENDERER`: the renderer to use for + * creating textures and drawing text + * - `TTF_PROP_RENDERER_TEXT_ENGINE_ATLAS_TEXTURE_SIZE`: the size of the + * texture atlas + * + * \param props the properties to use. + * \returns a TTF_TextEngine object or NULL on failure; call SDL_GetError() + * for more information. + * + * \threadsafety This function should be called on the thread that created the + * renderer. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateRendererTextEngine + * \sa TTF_DestroyRendererTextEngine + * \sa TTF_DrawRendererText + */ +extern SDL_DECLSPEC TTF_TextEngine * SDLCALL TTF_CreateRendererTextEngineWithProperties(SDL_PropertiesID props); + +#define TTF_PROP_RENDERER_TEXT_ENGINE_RENDERER "SDL_ttf.renderer_text_engine.create.renderer" +#define TTF_PROP_RENDERER_TEXT_ENGINE_ATLAS_TEXTURE_SIZE "SDL_ttf.renderer_text_engine.create.atlas_texture_size" + +/** + * Draw text to an SDL renderer. + * + * `text` must have been created using a TTF_TextEngine from + * TTF_CreateRendererTextEngine(), and will draw using the renderer passed to + * that function. + * + * \param text the text to draw. + * \param x the x coordinate in pixels, positive from the left edge towards + * the right. + * \param y the y coordinate in pixels, positive from the top edge towards the + * bottom. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateRendererTextEngine + * \sa TTF_CreateText + */ +extern SDL_DECLSPEC bool SDLCALL TTF_DrawRendererText(TTF_Text *text, float x, float y); + +/** + * Destroy a text engine created for drawing text on an SDL renderer. + * + * All text created by this engine should be destroyed before calling this + * function. + * + * \param engine a TTF_TextEngine object created with + * TTF_CreateRendererTextEngine(). + * + * \threadsafety This function should be called on the thread that created the + * engine. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateRendererTextEngine + */ +extern SDL_DECLSPEC void SDLCALL TTF_DestroyRendererTextEngine(TTF_TextEngine *engine); + +/** + * Create a text engine for drawing text with the SDL GPU API. + * + * \param device the SDL_GPUDevice to use for creating textures and drawing + * text. + * \returns a TTF_TextEngine object or NULL on failure; call SDL_GetError() + * for more information. + * + * \threadsafety This function should be called on the thread that created the + * device. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateGPUTextEngineWithProperties + * \sa TTF_DestroyGPUTextEngine + * \sa TTF_GetGPUTextDrawData + */ +extern SDL_DECLSPEC TTF_TextEngine * SDLCALL TTF_CreateGPUTextEngine(SDL_GPUDevice *device); + +/** + * Create a text engine for drawing text with the SDL GPU API, with the + * specified properties. + * + * These are the supported properties: + * + * - `TTF_PROP_GPU_TEXT_ENGINE_DEVICE`: the SDL_GPUDevice to use for creating + * textures and drawing text. + * - `TTF_PROP_GPU_TEXT_ENGINE_ATLAS_TEXTURE_SIZE`: the size of the texture + * atlas + * + * \param props the properties to use. + * \returns a TTF_TextEngine object or NULL on failure; call SDL_GetError() + * for more information. + * + * \threadsafety This function should be called on the thread that created the + * device. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateGPUTextEngine + * \sa TTF_DestroyGPUTextEngine + * \sa TTF_GetGPUTextDrawData + */ +extern SDL_DECLSPEC TTF_TextEngine * SDLCALL TTF_CreateGPUTextEngineWithProperties(SDL_PropertiesID props); + +#define TTF_PROP_GPU_TEXT_ENGINE_DEVICE "SDL_ttf.gpu_text_engine.create.device" +#define TTF_PROP_GPU_TEXT_ENGINE_ATLAS_TEXTURE_SIZE "SDL_ttf.gpu_text_engine.create.atlas_texture_size" + +/** + * Draw sequence returned by TTF_GetGPUTextDrawData + * + * \since This struct is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetGPUTextDrawData + */ +typedef struct TTF_GPUAtlasDrawSequence +{ + SDL_GPUTexture *atlas_texture; /**< Texture atlas that stores the glyphs */ + SDL_FPoint *xy; /**< An array of vertex positions */ + SDL_FPoint *uv; /**< An array of normalized texture coordinates for each vertex */ + int num_vertices; /**< Number of vertices */ + int *indices; /**< An array of indices into the 'vertices' arrays */ + int num_indices; /**< Number of indices */ + TTF_ImageType image_type; /**< The image type of this draw sequence */ + + struct TTF_GPUAtlasDrawSequence *next; /**< The next sequence (will be NULL in case of the last sequence) */ +} TTF_GPUAtlasDrawSequence; + +/** + * Get the geometry data needed for drawing the text. + * + * `text` must have been created using a TTF_TextEngine from + * TTF_CreateGPUTextEngine(). + * + * The positive X-axis is taken towards the right and the positive Y-axis is + * taken upwards for both the vertex and the texture coordinates, i.e, it + * follows the same convention used by the SDL_GPU API. If you want to use a + * different coordinate system you will need to transform the vertices + * yourself. + * + * If the text looks blocky use linear filtering. + * + * \param text the text to draw. + * \returns a NULL terminated linked list of TTF_GPUAtlasDrawSequence objects + * or NULL if the passed text is empty or in case of failure; call + * SDL_GetError() for more information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateGPUTextEngine + * \sa TTF_CreateText + */ +extern SDL_DECLSPEC TTF_GPUAtlasDrawSequence * SDLCALL TTF_GetGPUTextDrawData(TTF_Text *text); + +/** + * Destroy a text engine created for drawing text with the SDL GPU API. + * + * All text created by this engine should be destroyed before calling this + * function. + * + * \param engine a TTF_TextEngine object created with + * TTF_CreateGPUTextEngine(). + * + * \threadsafety This function should be called on the thread that created the + * engine. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateGPUTextEngine + */ +extern SDL_DECLSPEC void SDLCALL TTF_DestroyGPUTextEngine(TTF_TextEngine *engine); + +/** + * The winding order of the vertices returned by TTF_GetGPUTextDrawData + * + * \since This enum is available since SDL_ttf 3.0.0. + */ +typedef enum TTF_GPUTextEngineWinding +{ + TTF_GPU_TEXTENGINE_WINDING_INVALID = -1, + TTF_GPU_TEXTENGINE_WINDING_CLOCKWISE, + TTF_GPU_TEXTENGINE_WINDING_COUNTER_CLOCKWISE +} TTF_GPUTextEngineWinding; + +/** + * Sets the winding order of the vertices returned by TTF_GetGPUTextDrawData + * for a particular GPU text engine. + * + * \param engine a TTF_TextEngine object created with + * TTF_CreateGPUTextEngine(). + * \param winding the new winding order option. + * + * \threadsafety This function should be called on the thread that created the + * engine. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetGPUTextEngineWinding + */ +extern SDL_DECLSPEC void SDLCALL TTF_SetGPUTextEngineWinding(TTF_TextEngine *engine, TTF_GPUTextEngineWinding winding); + +/** + * Get the winding order of the vertices returned by TTF_GetGPUTextDrawData + * for a particular GPU text engine + * + * \param engine a TTF_TextEngine object created with + * TTF_CreateGPUTextEngine(). + * \returns the winding order used by the GPU text engine or + * TTF_GPU_TEXTENGINE_WINDING_INVALID in case of error. + * + * \threadsafety This function should be called on the thread that created the + * engine. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetGPUTextEngineWinding + */ +extern SDL_DECLSPEC TTF_GPUTextEngineWinding SDLCALL TTF_GetGPUTextEngineWinding(const TTF_TextEngine *engine); + +/** + * Create a text object from UTF-8 text and a text engine. + * + * \param engine the text engine to use when creating the text object, may be + * NULL. + * \param font the font to render with. + * \param text the text to use, in UTF-8 encoding. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \returns a TTF_Text object or NULL on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * font and text engine. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_DestroyText + */ +extern SDL_DECLSPEC TTF_Text * SDLCALL TTF_CreateText(TTF_TextEngine *engine, TTF_Font *font, const char *text, size_t length); + +/** + * Get the properties associated with a text object. + * + * \param text the TTF_Text to query. + * \returns a valid property ID on success or 0 on failure; call + * SDL_GetError() for more information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC SDL_PropertiesID SDLCALL TTF_GetTextProperties(TTF_Text *text); + +/** + * Set the text engine used by a text object. + * + * This function may cause the internal text representation to be rebuilt. + * + * \param text the TTF_Text to modify. + * \param engine the text engine to use for drawing. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetTextEngine + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextEngine(TTF_Text *text, TTF_TextEngine *engine); + +/** + * Get the text engine used by a text object. + * + * \param text the TTF_Text to query. + * \returns the TTF_TextEngine used by the text on success or NULL on failure; + * call SDL_GetError() for more information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetTextEngine + */ +extern SDL_DECLSPEC TTF_TextEngine * SDLCALL TTF_GetTextEngine(TTF_Text *text); + +/** + * Set the font used by a text object. + * + * When a text object has a font, any changes to the font will automatically + * regenerate the text. If you set the font to NULL, the text will continue to + * render but changes to the font will no longer affect the text. + * + * This function may cause the internal text representation to be rebuilt. + * + * \param text the TTF_Text to modify. + * \param font the font to use, may be NULL. + * \returns false if the text pointer is null; otherwise, true. call + * SDL_GetError() for more information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetTextFont + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextFont(TTF_Text *text, TTF_Font *font); + +/** + * Get the font used by a text object. + * + * \param text the TTF_Text to query. + * \returns the TTF_Font used by the text on success or NULL on failure; call + * SDL_GetError() for more information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetTextFont + */ +extern SDL_DECLSPEC TTF_Font * SDLCALL TTF_GetTextFont(TTF_Text *text); + +/** + * Set the direction to be used for text shaping a text object. + * + * This function only supports left-to-right text shaping if SDL_ttf was not + * built with HarfBuzz support. + * + * \param text the text to modify. + * \param direction the new direction for text to flow. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextDirection(TTF_Text *text, TTF_Direction direction); + +/** + * Get the direction to be used for text shaping a text object. + * + * This defaults to the direction of the font used by the text object. + * + * \param text the text to query. + * \returns the direction to be used for text shaping. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC TTF_Direction SDLCALL TTF_GetTextDirection(TTF_Text *text); + +/** + * Set the script to be used for text shaping a text object. + * + * This returns false if SDL_ttf isn't built with HarfBuzz support. + * + * \param text the text to modify. + * \param script an + * [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html) + * . + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_StringToTag + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextScript(TTF_Text *text, Uint32 script); + +/** + * Get the script used for text shaping a text object. + * + * This defaults to the script of the font used by the text object. + * + * \param text the text to query. + * \returns an + * [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html) + * or 0 if a script hasn't been set on either the text object or the + * font. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_TagToString + */ +extern SDL_DECLSPEC Uint32 SDLCALL TTF_GetTextScript(TTF_Text *text); + +/** + * Set the color of a text object. + * + * The default text color is white (255, 255, 255, 255). + * + * \param text the TTF_Text to modify. + * \param r the red color value in the range of 0-255. + * \param g the green color value in the range of 0-255. + * \param b the blue color value in the range of 0-255. + * \param a the alpha value in the range of 0-255. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetTextColor + * \sa TTF_SetTextColorFloat + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextColor(TTF_Text *text, Uint8 r, Uint8 g, Uint8 b, Uint8 a); + +/** + * Set the color of a text object. + * + * The default text color is white (1.0f, 1.0f, 1.0f, 1.0f). + * + * \param text the TTF_Text to modify. + * \param r the red color value, normally in the range of 0-1. + * \param g the green color value, normally in the range of 0-1. + * \param b the blue color value, normally in the range of 0-1. + * \param a the alpha value in the range of 0-1. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetTextColorFloat + * \sa TTF_SetTextColor + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextColorFloat(TTF_Text *text, float r, float g, float b, float a); + +/** + * Get the color of a text object. + * + * \param text the TTF_Text to query. + * \param r a pointer filled in with the red color value in the range of + * 0-255, may be NULL. + * \param g a pointer filled in with the green color value in the range of + * 0-255, may be NULL. + * \param b a pointer filled in with the blue color value in the range of + * 0-255, may be NULL. + * \param a a pointer filled in with the alpha value in the range of 0-255, + * may be NULL. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetTextColorFloat + * \sa TTF_SetTextColor + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetTextColor(TTF_Text *text, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a); + +/** + * Get the color of a text object. + * + * \param text the TTF_Text to query. + * \param r a pointer filled in with the red color value, normally in the + * range of 0-1, may be NULL. + * \param g a pointer filled in with the green color value, normally in the + * range of 0-1, may be NULL. + * \param b a pointer filled in with the blue color value, normally in the + * range of 0-1, may be NULL. + * \param a a pointer filled in with the alpha value in the range of 0-1, may + * be NULL. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetTextColor + * \sa TTF_SetTextColorFloat + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetTextColorFloat(TTF_Text *text, float *r, float *g, float *b, float *a); + +/** + * Set the position of a text object. + * + * This can be used to position multiple text objects within a single wrapping + * text area. + * + * This function may cause the internal text representation to be rebuilt. + * + * \param text the TTF_Text to modify. + * \param x the x offset of the upper left corner of this text in pixels. + * \param y the y offset of the upper left corner of this text in pixels. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetTextPosition + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextPosition(TTF_Text *text, int x, int y); + +/** + * Get the position of a text object. + * + * \param text the TTF_Text to query. + * \param x a pointer filled in with the x offset of the upper left corner of + * this text in pixels, may be NULL. + * \param y a pointer filled in with the y offset of the upper left corner of + * this text in pixels, may be NULL. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetTextPosition + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetTextPosition(TTF_Text *text, int *x, int *y); + +/** + * Set whether wrapping is enabled on a text object. + * + * This function may cause the internal text representation to be rebuilt. + * + * \param text the TTF_Text to modify. + * \param wrap_width the maximum width in pixels, 0 to wrap on newline + * characters. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetTextWrapWidth + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextWrapWidth(TTF_Text *text, int wrap_width); + +/** + * Get whether wrapping is enabled on a text object. + * + * \param text the TTF_Text to query. + * \param wrap_width a pointer filled in with the maximum width in pixels or 0 + * if the text is being wrapped on newline characters. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetTextWrapWidth + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetTextWrapWidth(TTF_Text *text, int *wrap_width); + +/** + * Set whether whitespace should be visible when wrapping a text object. + * + * If the whitespace is visible, it will take up space for purposes of + * alignment and wrapping. This is good for editing, but looks better when + * centered or aligned if whitespace around line wrapping is hidden. This + * defaults false. + * + * This function may cause the internal text representation to be rebuilt. + * + * \param text the TTF_Text to modify. + * \param visible true to show whitespace when wrapping text, false to hide + * it. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_TextWrapWhitespaceVisible + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextWrapWhitespaceVisible(TTF_Text *text, bool visible); + +/** + * Return whether whitespace is shown when wrapping a text object. + * + * \param text the TTF_Text to query. + * \returns true if whitespace is shown when wrapping text, or false + * otherwise. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_SetTextWrapWhitespaceVisible + */ +extern SDL_DECLSPEC bool SDLCALL TTF_TextWrapWhitespaceVisible(TTF_Text *text); + +/** + * Set the UTF-8 text used by a text object. + * + * This function may cause the internal text representation to be rebuilt. + * + * \param text the TTF_Text to modify. + * \param string the UTF-8 text to use, may be NULL. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_AppendTextString + * \sa TTF_DeleteTextString + * \sa TTF_InsertTextString + */ +extern SDL_DECLSPEC bool SDLCALL TTF_SetTextString(TTF_Text *text, const char *string, size_t length); + +/** + * Insert UTF-8 text into a text object. + * + * This function may cause the internal text representation to be rebuilt. + * + * \param text the TTF_Text to modify. + * \param offset the offset, in bytes, from the beginning of the string if >= + * 0, the offset from the end of the string if < 0. Note that + * this does not do UTF-8 validation, so you should only insert + * at UTF-8 sequence boundaries. + * \param string the UTF-8 text to insert. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_AppendTextString + * \sa TTF_DeleteTextString + * \sa TTF_SetTextString + */ +extern SDL_DECLSPEC bool SDLCALL TTF_InsertTextString(TTF_Text *text, int offset, const char *string, size_t length); + +/** + * Append UTF-8 text to a text object. + * + * This function may cause the internal text representation to be rebuilt. + * + * \param text the TTF_Text to modify. + * \param string the UTF-8 text to insert. + * \param length the length of the text, in bytes, or 0 for null terminated + * text. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_DeleteTextString + * \sa TTF_InsertTextString + * \sa TTF_SetTextString + */ +extern SDL_DECLSPEC bool SDLCALL TTF_AppendTextString(TTF_Text *text, const char *string, size_t length); + +/** + * Delete UTF-8 text from a text object. + * + * This function may cause the internal text representation to be rebuilt. + * + * \param text the TTF_Text to modify. + * \param offset the offset, in bytes, from the beginning of the string if >= + * 0, the offset from the end of the string if < 0. Note that + * this does not do UTF-8 validation, so you should only delete + * at UTF-8 sequence boundaries. + * \param length the length of text to delete, in bytes, or -1 for the + * remainder of the string. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_AppendTextString + * \sa TTF_InsertTextString + * \sa TTF_SetTextString + */ +extern SDL_DECLSPEC bool SDLCALL TTF_DeleteTextString(TTF_Text *text, int offset, int length); + +/** + * Get the size of a text object. + * + * The size of the text may change when the font or font style and size + * change. + * + * \param text the TTF_Text to query. + * \param w a pointer filled in with the width of the text, in pixels, may be + * NULL. + * \param h a pointer filled in with the height of the text, in pixels, may be + * NULL. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetTextSize(TTF_Text *text, int *w, int *h); + +/** + * Flags for TTF_SubString + * + * \since This datatype is available since SDL_ttf 3.0.0. + * + * \sa TTF_SubString + */ +typedef Uint32 TTF_SubStringFlags; + +#define TTF_SUBSTRING_DIRECTION_MASK 0x000000FF /**< The mask for the flow direction for this substring */ +#define TTF_SUBSTRING_TEXT_START 0x00000100 /**< This substring contains the beginning of the text */ +#define TTF_SUBSTRING_LINE_START 0x00000200 /**< This substring contains the beginning of line `line_index` */ +#define TTF_SUBSTRING_LINE_END 0x00000400 /**< This substring contains the end of line `line_index` */ +#define TTF_SUBSTRING_TEXT_END 0x00000800 /**< This substring contains the end of the text */ + +/** + * The representation of a substring within text. + * + * \since This struct is available since SDL_ttf 3.0.0. + * + * \sa TTF_GetNextTextSubString + * \sa TTF_GetPreviousTextSubString + * \sa TTF_GetTextSubString + * \sa TTF_GetTextSubStringForLine + * \sa TTF_GetTextSubStringForPoint + * \sa TTF_GetTextSubStringsForRange + */ +typedef struct TTF_SubString +{ + TTF_SubStringFlags flags; /**< The flags for this substring */ + int offset; /**< The byte offset from the beginning of the text */ + int length; /**< The byte length starting at the offset */ + int line_index; /**< The index of the line that contains this substring */ + int cluster_index; /**< The internal cluster index, used for quickly iterating */ + SDL_Rect rect; /**< The rectangle, relative to the top left of the text, containing the substring */ +} TTF_SubString; + +/** + * Get the substring of a text object that surrounds a text offset. + * + * If `offset` is less than 0, this will return a zero length substring at the + * beginning of the text with the TTF_SUBSTRING_TEXT_START flag set. If + * `offset` is greater than or equal to the length of the text string, this + * will return a zero length substring at the end of the text with the + * TTF_SUBSTRING_TEXT_END flag set. + * + * \param text the TTF_Text to query. + * \param offset a byte offset into the text string. + * \param substring a pointer filled in with the substring containing the + * offset. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetTextSubString(TTF_Text *text, int offset, TTF_SubString *substring); + +/** + * Get the substring of a text object that contains the given line. + * + * If `line` is less than 0, this will return a zero length substring at the + * beginning of the text with the TTF_SUBSTRING_TEXT_START flag set. If `line` + * is greater than or equal to `text->num_lines` this will return a zero + * length substring at the end of the text with the TTF_SUBSTRING_TEXT_END + * flag set. + * + * \param text the TTF_Text to query. + * \param line a zero-based line index, in the range [0 .. text->num_lines-1]. + * \param substring a pointer filled in with the substring containing the + * offset. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetTextSubStringForLine(TTF_Text *text, int line, TTF_SubString *substring); + +/** + * Get the substrings of a text object that contain a range of text. + * + * \param text the TTF_Text to query. + * \param offset a byte offset into the text string. + * \param length the length of the range being queried, in bytes, or -1 for + * the remainder of the string. + * \param count a pointer filled in with the number of substrings returned, + * may be NULL. + * \returns a NULL terminated array of substring pointers or NULL on failure; + * call SDL_GetError() for more information. This is a single + * allocation that should be freed with SDL_free() when it is no + * longer needed. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC TTF_SubString ** SDLCALL TTF_GetTextSubStringsForRange(TTF_Text *text, int offset, int length, int *count); + +/** + * Get the portion of a text string that is closest to a point. + * + * This will return the closest substring of text to the given point. + * + * \param text the TTF_Text to query. + * \param x the x coordinate relative to the left side of the text, may be + * outside the bounds of the text area. + * \param y the y coordinate relative to the top side of the text, may be + * outside the bounds of the text area. + * \param substring a pointer filled in with the closest substring of text to + * the given point. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetTextSubStringForPoint(TTF_Text *text, int x, int y, TTF_SubString *substring); + +/** + * Get the previous substring in a text object + * + * If called at the start of the text, this will return a zero length + * substring with the TTF_SUBSTRING_TEXT_START flag set. + * + * \param text the TTF_Text to query. + * \param substring the TTF_SubString to query. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetPreviousTextSubString(TTF_Text *text, const TTF_SubString *substring, TTF_SubString *previous); + +/** + * Get the next substring in a text object + * + * If called at the end of the text, this will return a zero length substring + * with the TTF_SUBSTRING_TEXT_END flag set. + * + * \param text the TTF_Text to query. + * \param substring the TTF_SubString to query. + * \param next a pointer filled in with the next substring. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_GetNextTextSubString(TTF_Text *text, const TTF_SubString *substring, TTF_SubString *next); + +/** + * Update the layout of a text object. + * + * This is automatically done when the layout is requested or the text is + * rendered, but you can call this if you need more control over the timing of + * when the layout and text engine representation are updated. + * + * \param text the TTF_Text to update. + * \returns true on success or false on failure; call SDL_GetError() for more + * information. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC bool SDLCALL TTF_UpdateText(TTF_Text *text); + +/** + * Destroy a text object created by a text engine. + * + * \param text the text to destroy. + * + * \threadsafety This function should be called on the thread that created the + * text. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_CreateText + */ +extern SDL_DECLSPEC void SDLCALL TTF_DestroyText(TTF_Text *text); + +/** + * Dispose of a previously-created font. + * + * Call this when done with a font. This function will free any resources + * associated with it. It is safe to call this function on NULL, for example + * on the result of a failed call to TTF_OpenFont(). + * + * The font is not valid after being passed to this function. String pointers + * from functions that return information on this font, such as + * TTF_GetFontFamilyName() and TTF_GetFontStyleName(), are no longer valid + * after this call, as well. + * + * \param font the font to dispose of. + * + * \threadsafety This function should not be called while any other thread is + * using the font. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_OpenFont + * \sa TTF_OpenFontIO + */ +extern SDL_DECLSPEC void SDLCALL TTF_CloseFont(TTF_Font *font); + +/** + * Deinitialize SDL_ttf. + * + * You must call this when done with the library, to free internal resources. + * It is safe to call this when the library isn't initialized, as it will just + * return immediately. + * + * Once you have as many quit calls as you have had successful calls to + * TTF_Init, the library will actually deinitialize. + * + * Please note that this does not automatically close any fonts that are still + * open at the time of deinitialization, and it is possibly not safe to close + * them afterwards, as parts of the library will no longer be initialized to + * deal with it. A well-written program should call TTF_CloseFont() on any + * open fonts before calling this function! + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + */ +extern SDL_DECLSPEC void SDLCALL TTF_Quit(void); + +/** + * Check if SDL_ttf is initialized. + * + * This reports the number of times the library has been initialized by a call + * to TTF_Init(), without a paired deinitialization request from TTF_Quit(). + * + * In short: if it's greater than zero, the library is currently initialized + * and ready to work. If zero, it is not initialized. + * + * Despite the return value being a signed integer, this function should not + * return a negative number. + * + * \returns the current number of initialization calls, that need to + * eventually be paired with this many calls to TTF_Quit(). + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL_ttf 3.0.0. + * + * \sa TTF_Init + * \sa TTF_Quit + */ +extern SDL_DECLSPEC int SDLCALL TTF_WasInit(void); + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +} +#endif +#include + +#endif /* SDL_TTF_H_ */ + diff --git a/vendor/sdl3/ttf/sdl3_textengine.odin b/vendor/sdl3/ttf/sdl3_textengine.odin new file mode 100644 index 000000000..00bf881dd --- /dev/null +++ b/vendor/sdl3/ttf/sdl3_textengine.odin @@ -0,0 +1,62 @@ +package sdl3_ttf + +import "core:c" +import SDL "vendor:sdl3" + +DrawCommand :: enum c.int { + NOOP, + FILL, + COPY, +} + +FillOperation :: struct { + cmd: DrawCommand, + rect: SDL.Rect, +} + +CopyOperation :: struct { + cmd: DrawCommand, + text_offset: c.int, + glyph_font: ^Font, + glyph_index: u32, + src: SDL.Rect, + dst: SDL.Rect, + reserved: rawptr, +} + +DrawOperation :: struct #raw_union { + cmd: DrawCommand, + fill: FillOperation, + copy: CopyOperation, +} + +TextLayout :: struct {} + +TextData :: struct { + font: ^Font, + color: SDL.FColor, + needs_layout_update: bool, + layout: ^TextLayout, + x, y: c.int, + w, h: c.int, + num_ops: c.int, + ops: [^]DrawOperation `fmt:"v,num_ops"`, + num_clusters: c.int, + clusters: [^]SubString `fmt:"v,num_clusters"`, + props: SDL.PropertiesID, + needs_engine_update: bool, + engine: ^TextEngine, + engine_text: rawptr, +} + +TextEngine :: struct { + version: u32, + userdata: rawptr, + CreateText: proc "c" (userdata: rawptr, text: ^Text) -> bool, + DestroyText: proc "c" (userdata: rawptr, Textext: ^Text), +} + +#assert( + (size_of(TextEngine) == 16 && size_of(rawptr) == 4) || + (size_of(TextEngine) == 32 && size_of(rawptr) == 8), +) diff --git a/vendor/sdl3/ttf/sdl3_ttf.odin b/vendor/sdl3/ttf/sdl3_ttf.odin new file mode 100644 index 000000000..ada1de833 --- /dev/null +++ b/vendor/sdl3/ttf/sdl3_ttf.odin @@ -0,0 +1,292 @@ +package sdl3_ttf + +import "core:c" +import SDL "vendor:sdl3" + +when ODIN_OS == .Windows { + foreign import lib "SDL3_ttf.lib" +} else { + foreign import lib "system:SDL3_ttf" +} + + +PROP_FONT_CREATE_FILENAME_STRING :: "SDL_ttf.font.create.filename" +PROP_FONT_CREATE_IOSTREAM_POINTER :: "SDL_ttf.font.create.iostream" +PROP_FONT_CREATE_IOSTREAM_OFFSET_NUMBER :: "SDL_ttf.font.create.iostream.offset" +PROP_FONT_CREATE_IOSTREAM_AUTOCLOSE_BOOLEAN :: "SDL_ttf.font.create.iostream.autoclose" +PROP_FONT_CREATE_SIZE_FLOAT :: "SDL_ttf.font.create.size" +PROP_FONT_CREATE_FACE_NUMBER :: "SDL_ttf.font.create.face" +PROP_FONT_CREATE_HORIZONTAL_DPI_NUMBER :: "SDL_ttf.font.create.hdpi" +PROP_FONT_CREATE_VERTICAL_DPI_NUMBER :: "SDL_ttf.font.create.vdpi" +PROP_FONT_CREATE_EXISTING_FONT :: "SDL_ttf.font.create.existing_font" + +FONT_WEIGHT_THIN :: 100 /**< Thin (100) named font weight value */ +FONT_WEIGHT_EXTRA_LIGHT :: 200 /**< ExtraLight (200) named font weight value */ +FONT_WEIGHT_LIGHT :: 300 /**< Light (300) named font weight value */ +FONT_WEIGHT_NORMAL :: 400 /**< Normal (400) named font weight value */ +FONT_WEIGHT_MEDIUM :: 500 /**< Medium (500) named font weight value */ +FONT_WEIGHT_SEMI_BOLD :: 600 /**< SemiBold (600) named font weight value */ +FONT_WEIGHT_BOLD :: 700 /**< Bold (700) named font weight value */ +FONT_WEIGHT_EXTRA_BOLD :: 800 /**< ExtraBold (800) named font weight value */ +FONT_WEIGHT_BLACK :: 900 /**< Black (900) named font weight value */ +FONT_WEIGHT_EXTRA_BLACK :: 950 /**< ExtraBlack (950) named font weight value */ + +PROP_RENDERER_TEXT_ENGINE_RENDERER :: "SDL_ttf.renderer_text_engine.create.renderer" +PROP_RENDERER_TEXT_ENGINE_ATLAS_TEXTURE_SIZE :: "SDL_ttf.renderer_text_engine.create.atlas_texture_size" + +PROP_GPU_TEXT_ENGINE_DEVICE :: "SDL_ttf.gpu_text_engine.create.device" +PROP_GPU_TEXT_ENGINE_ATLAS_TEXTURE_SIZE :: "SDL_ttf.gpu_text_engine.create.atlas_texture_size" + +MAJOR_VERSION :: 3 +MINOR_VERSION :: 2 +PATCHLEVEL :: 2 + +Font :: struct {} + +Text :: struct { + text: [^]u8, + num_lines: c.int, + refcount: c.int, + internal: ^TextData, +} + +FontStyle :: enum u32 { + BOLD, + ITALIC, + UNDERLINE, + STRIKETHROUGH, +} + +FontStyleFlags :: distinct bit_set[FontStyle; u32] + +// NOTE: This is called TTF_HintingFlags but its not a bit_set so +// the "flags" doesn't really make sense, its just the hinting. +Hinting :: enum c.int { + INVALID = -1, + NORMAL, + LIGHT, + MONO, + NONE, + LIGHT_SUBPIXEL, +} + +HorizontalAlignment :: enum c.int { + INVALID = -1, + LEFT, + CENTER, + RIGHT, +} + +Direction :: enum c.int { + INVALID, + LTR = 4, + RTL, + TTB, + BTT, +} + +ImageType :: enum c.int { + INVALID, + ALPHA, + COLOR, + SDF, +} + +GPUAtlasDrawSequence :: struct { + atlas_texture: ^SDL.GPUTexture, + xy, uv: [^]SDL.FPoint `fmt:"v,num_vertices"`, + num_vertices: c.int, + indices: [^]c.int `fmt:"v,num_indices"`, + num_indices: c.int, + image_type: ImageType, + next: ^GPUAtlasDrawSequence, +} + +GPUTextEngineWinding :: enum c.int { + INVALID = -1, + CLOCKWISE = 0, + COUNTER_CLOCKWISE = +1, +} + +SubStringFlags :: bit_field u32 { + direction: u8 | 8, + text_start: bool | 1, + line_start: bool | 1, + line_end: bool | 1, + text_end: bool | 1, +} + +SubString :: struct { + flags: SubStringFlags, + offset, length: c.int, + line_index, cluster_index: c.int, + rect: SDL.Rect, +} + +@(default_calling_convention="c", link_prefix="TTF_", require_results) +foreign lib { + Version :: proc() -> c.int --- + WasInit :: proc() -> c.int --- + + OpenFont :: proc(file: cstring, ptsize: f32) -> ^Font --- + OpenFontIO :: proc(src: ^SDL.IOStream, closeio: bool, ptsize: f32) -> ^Font --- + OpenFontWithProperties :: proc(props: SDL.PropertiesID) -> ^Font --- + + CopyFont :: proc(existing_font: ^Font) -> ^Font --- + + GetFontProperties :: proc(font: ^Font) -> SDL.PropertiesID --- + GetFontGeneration :: proc(font: ^Font) -> u32 --- + + GetFontSize :: proc(font: ^Font) -> f32 --- + + SetFontStyle :: proc(font: ^Font, style: FontStyleFlags) --- + GetFontStyle :: proc(font: ^Font) -> FontStyleFlags --- + + SetFontOutline :: proc(font: ^Font, outline: c.int) -> bool --- + GetFontOutline :: proc(font: ^Font) -> c.int --- + + SetFontHinting :: proc(font: ^Font, hinting: Hinting) --- + GetFontHinting :: proc(font: ^Font) -> Hinting --- + + GetNumFontFaces :: proc(font: ^Font) -> c.int --- + + SetFontSDF :: proc(font: ^Font, enabled: bool) -> bool --- + GetFontSDF :: proc(font: ^Font) -> bool --- + + GetFontWeight :: proc(font: ^Font) -> c.int --- + + SetFontWrapAlignment :: proc(font: ^Font, align: HorizontalAlignment) --- + GetFontWrapAlignment :: proc(font: ^Font) -> HorizontalAlignment --- + + GetFontHeight :: proc(font: ^Font) -> c.int --- + GetFontAscent :: proc(font: ^Font) -> c.int --- + GetFontDescent :: proc(font: ^Font) -> c.int --- + + SetFontLineSkip :: proc(font: ^Font, lineskip: c.int) --- + GetFontLineSkip :: proc(font: ^Font) -> c.int --- + + SetFontKerning :: proc(font: ^Font, enabled: bool) --- + GetFontKerning :: proc(font: ^Font) -> bool --- + + FontIsFixedWidth :: proc(font: ^Font) -> bool --- + FontIsScalable :: proc(font: ^Font) -> bool --- + + GetFontFamilyName :: proc(font: ^Font) -> cstring --- + GetFontStyleName :: proc(font: ^Font) -> cstring --- + + GetFontDirection :: proc(font: ^Font) -> Direction --- + + StringToTag :: proc(string: cstring) -> u32 --- + + GetFontScript :: proc(font: ^Font) -> u32 --- + + GetGlyphScript :: proc(ch: u32) -> u32 --- + FontHasGlyph :: proc(font: ^Font, ch: u32) -> bool --- + GetGlyphImage :: proc(font: ^Font, ch: u32, image_type: ^ImageType) -> ^SDL.Surface --- + GetGlyphImageForIndex :: proc(font: ^Font, glyph_index: u32, image_type: ^ImageType) -> ^SDL.Surface --- + + RenderText_Solid :: proc(font: ^Font, text: cstring, length: c.size_t, fg: SDL.Color) -> ^SDL.Surface --- + RenderText_Solid_Wrapped :: proc(font: ^Font, text: cstring, length: c.size_t, fg: SDL.Color, wrap_Length: c.int) -> ^SDL.Surface --- + RenderGlyph_Solid :: proc(font: ^Font, ch: u32, fg: SDL.Color) -> ^SDL.Surface --- + RenderText_Shaded :: proc(font: ^Font, text: cstring, length: c.size_t, fg, bg: SDL.Color) -> ^SDL.Surface --- + RenderText_Shaded_Wrapped :: proc(font: ^Font, text: cstring, length: c.size_t, fg, bg: SDL.Color, wrap_width: c.int) -> ^SDL.Surface --- + RenderGlyph_Shaded :: proc(font: ^Font, ch: u32, fg, bg: SDL.Color) -> ^SDL.Surface --- + RenderText_Blended :: proc(font: ^Font, text: cstring, length: c.size_t, fg: SDL.Color) -> ^SDL.Surface --- + RenderText_Blended_Wrapped :: proc(font: ^Font, text: cstring, length: c.size_t, fg: SDL.Color, wrap_width: c.int) -> ^SDL.Surface --- + RenderGlyph_Blended :: proc(font: ^Font, ch: u32, fg: SDL.Color) -> ^SDL.Surface --- + RenderText_LCD :: proc(font: ^Font, text: cstring, length: c.size_t, fg, bg: SDL.Color) -> ^SDL.Surface --- + RenderText_LCD_Wrapped :: proc(font: ^Font, text: cstring, length: c.size_t, fg, bg: SDL.Color, wrap_width: c.int) -> ^SDL.Surface --- + RenderGlyph_LCD :: proc(font: ^Font, ch: u32, fg, bg: SDL.Color) -> ^SDL.Surface --- + + CreateSurfaceTextEngine :: proc() -> ^TextEngine --- + + CreateRendererTextEngine :: proc(renderer: ^SDL.Renderer) -> ^TextEngine --- + CreateRendererTextEngineWithProperties :: proc(props: SDL.PropertiesID) -> ^TextEngine --- + + CreateGPUTextEngine :: proc(device: ^SDL.GPUDevice) -> ^TextEngine --- + CreateGPUTextEngineWithProperties :: proc(props: SDL.PropertiesID) -> ^TextEngine --- + GetGPUTextDrawData :: proc(text: ^Text) -> ^GPUAtlasDrawSequence --- + SetGPUTextEngineWinding :: proc(engine: ^TextEngine, winding: GPUTextEngineWinding) --- + GetGPUTextEngineWinding :: proc(#by_ptr engine: TextEngine) -> GPUTextEngineWinding --- + + CreateText :: proc(engine: ^TextEngine, font: ^Font, text: cstring, length: c.size_t) -> ^Text --- + GetTextProperties :: proc(text: ^Text) -> SDL.PropertiesID --- + GetTextEngine :: proc(text: ^Text) -> ^TextEngine --- + GetTextFont :: proc(text: ^Text) -> ^Font --- + GetTextDirection :: proc(text: ^Text) -> Direction --- + GetTextScript :: proc(text: ^Text) -> u32 --- + TextWrapWhitespaceVisible :: proc(text: ^Text) -> bool --- + + GetTextSubStringsForRange :: proc(text: ^Text, offset, length: c.int, count: ^c.int) -> [^]^SubString --- +} + +@(default_calling_convention="c", link_prefix="TTF_") +foreign lib { + GetFreeTypeVersion :: proc(major, minor, patch: ^c.int) --- + GetHarfBuzzVersion :: proc(major, minor, patch: ^c.int) --- + + Init :: proc() -> bool --- + + AddFallbackFont :: proc(font: ^Font, fallback: ^Font) -> bool --- + RemoveFallbackFont :: proc(font: ^Font, fallback: ^Font) --- + ClearFallbackFonts :: proc(font: ^Font) --- + + SetFontSize :: proc(font: ^Font, ptsize: f32) -> bool --- + SetFontSizeDPI :: proc(font: ^Font, ptsize: f32, hdpi: c.int, vdpi: c.int) -> bool --- + GetFontDPI :: proc(font: ^Font, hdpi: ^c.int, vdpi: ^c.int) -> bool --- + + SetFontDirection :: proc(font: ^Font, direction: Direction) -> bool --- + + TagToString :: proc(tag: u32, string: [^]c.char, size: c.size_t) --- + + SetFontScript :: proc(font: ^Font, script: u32) -> bool --- + + SetFontLanguage :: proc(font: ^Font, language_bcp47: cstring) -> bool --- + + GetGlyphMetrics :: proc(font: ^Font, ch: u32, minx, maxx, miny, maxy, advance: ^c.int) -> bool --- + GetGlyphKerning :: proc(font: ^Font, previous_ch: u32, ch: u32, kerning: ^c.int) -> bool --- + + GetStringSize :: proc(font: ^Font, text: cstring, length: c.size_t, w, h: ^c.int) -> bool --- + GetStringSizeWrapped :: proc(font: ^Font, text: cstring, length: c.size_t, wrap_width: c.int, w, h: ^c.int) -> bool --- + MeasureString :: proc(font: ^Font, text: cstring, length: c.size_t, max_width: c.int, measured_width: ^c.int, measured_length: ^c.size_t) -> bool --- + + DrawSurfaceText :: proc(text: ^Text, x, y: c.int, surface: ^SDL.Surface) -> bool --- + DestroySurfaceTextEngine :: proc(engine: ^TextEngine) --- + + DrawRendererText :: proc(text: ^Text, x, y: f32) -> bool --- + DestroyRendererTextEngine :: proc(engine: ^TextEngine) --- + + DestroyGPUTextEngine :: proc(engine: ^TextEngine) --- + + SetTextEngine :: proc(text: ^Text, engine: ^TextEngine) -> bool --- + SetTextFont :: proc(text: ^Text, font: ^Font) -> bool --- + SetTextDirection :: proc(text: ^Text, direction: Direction) -> bool --- + SetTextScript :: proc(text: ^Text, script: u32) -> bool --- + SetTextColor :: proc(text: ^Text, r, g, b, a: u8) -> bool --- + SetTextColorFloat :: proc(text: ^Text, r, g, b, a: f32) -> bool --- + GetTextColor :: proc(text: ^Text, r, g, b, a: ^u8) -> bool --- + GetTextColorFloat :: proc(text: ^Text, r, g, b, a: ^f32) -> bool --- + SetTextPosition :: proc(text: ^Text, x, y: c.int) -> bool --- + GetTextPosition :: proc(text: ^Text, x, y: ^c.int) -> bool --- + SetTextWrapWidth :: proc(text: ^Text, wrap_width: c.int) -> bool --- + GetTextWrapWidth :: proc(text: ^Text, wrap_width: ^c.int) -> bool --- + SetTextWrapWhitespaceVisible :: proc(text: ^Text, visible: bool) -> bool --- + + SetTextString :: proc(text: ^Text, string: cstring, length: c.size_t) -> bool --- + InsertTextString :: proc(text: ^Text, offset: c.int, string: cstring, length: c.size_t) -> bool --- + AppendTextString :: proc(text: ^Text, string: cstring, length: c.size_t) -> bool --- + DeleteTextString :: proc(text: ^Text, offset, length: c.int) -> bool --- + + GetTextSize :: proc(text: ^Text, w, h: ^c.int) -> bool --- + + GetTextSubString :: proc(text: ^Text, offset: c.int, substring: ^SubString) -> bool --- + GetTextSubStringForLine :: proc(text: ^Text, line: c.int, substring: ^SubString) -> bool --- + GetTextSubStringForPoint :: proc(text: ^Text, x, y: c.int, substring: ^SubString) -> bool --- + GetPreviousTextSubString :: proc(text: ^Text, #by_ptr substring: SubString, previous: ^SubString) -> bool --- + GetNextTextSubString :: proc(text: ^Text, #by_ptr substring: SubString, next: ^SubString) -> bool --- + + UpdateText :: proc(text: ^Text) -> bool --- + DestroyText :: proc(text: ^Text) --- + CloseFont :: proc(font: ^Font) --- + Quit :: proc() --- +} diff --git a/vendor/stb/lib/stb_image.lib b/vendor/stb/lib/stb_image.lib index f0cffb1fc..b36fef6dc 100644 Binary files a/vendor/stb/lib/stb_image.lib and b/vendor/stb/lib/stb_image.lib differ diff --git a/vendor/stb/lib/stb_image_resize.lib b/vendor/stb/lib/stb_image_resize.lib index 30f6bd943..9d4315b1f 100644 Binary files a/vendor/stb/lib/stb_image_resize.lib and b/vendor/stb/lib/stb_image_resize.lib differ diff --git a/vendor/stb/lib/stb_image_write.lib b/vendor/stb/lib/stb_image_write.lib index 415a62996..34e724fc8 100644 Binary files a/vendor/stb/lib/stb_image_write.lib and b/vendor/stb/lib/stb_image_write.lib differ diff --git a/vendor/stb/lib/stb_rect_pack.lib b/vendor/stb/lib/stb_rect_pack.lib index a0a139ace..47344b366 100644 Binary files a/vendor/stb/lib/stb_rect_pack.lib and b/vendor/stb/lib/stb_rect_pack.lib differ diff --git a/vendor/stb/lib/stb_sprintf.lib b/vendor/stb/lib/stb_sprintf.lib index 35c2cecc9..892e56c42 100644 Binary files a/vendor/stb/lib/stb_sprintf.lib and b/vendor/stb/lib/stb_sprintf.lib differ diff --git a/vendor/stb/lib/stb_truetype.lib b/vendor/stb/lib/stb_truetype.lib index 16ecf944d..f86ddcc5e 100644 Binary files a/vendor/stb/lib/stb_truetype.lib and b/vendor/stb/lib/stb_truetype.lib differ diff --git a/vendor/stb/lib/stb_vorbis.lib b/vendor/stb/lib/stb_vorbis.lib index bf47eda26..6d6bccb44 100644 Binary files a/vendor/stb/lib/stb_vorbis.lib and b/vendor/stb/lib/stb_vorbis.lib differ diff --git a/vendor/stb/src/stb_truetype.c b/vendor/stb/src/stb_truetype.c index 05c23f583..974a0bdce 100644 --- a/vendor/stb/src/stb_truetype.c +++ b/vendor/stb/src/stb_truetype.c @@ -1,2 +1,6 @@ +#define STBRP_STATIC +#define STB_RECT_PACK_IMPLEMENTATION +#include "stb_rect_pack.h" + #define STB_TRUETYPE_IMPLEMENTATION #include "stb_truetype.h" \ No newline at end of file diff --git a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py index 9da3ee239..2d78179e7 100644 --- a/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py +++ b/vendor/vulkan/_gen/create_vulkan_odin_wrapper.py @@ -905,7 +905,7 @@ API_VERSION_1_2 :: (1<<22) | (2<<12) | (0) API_VERSION_1_3 :: (1<<22) | (3<<12) | (0) API_VERSION_1_4 :: (1<<22) | (4<<12) | (0) -MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 { +MAKE_VERSION :: proc "contextless" (major, minor, patch: u32) -> u32 { \treturn (major<<22) | (minor<<12) | (patch) } diff --git a/vendor/vulkan/core.odin b/vendor/vulkan/core.odin index b258bc85a..a80bdc73b 100644 --- a/vendor/vulkan/core.odin +++ b/vendor/vulkan/core.odin @@ -9,7 +9,7 @@ API_VERSION_1_2 :: (1<<22) | (2<<12) | (0) API_VERSION_1_3 :: (1<<22) | (3<<12) | (0) API_VERSION_1_4 :: (1<<22) | (4<<12) | (0) -MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 { +MAKE_VERSION :: proc "contextless" (major, minor, patch: u32) -> u32 { return (major<<22) | (minor<<12) | (patch) } diff --git a/vendor/wasm/WebGL/webgl.odin b/vendor/wasm/WebGL/webgl.odin index 389e729de..5616f3660 100644 --- a/vendor/wasm/WebGL/webgl.odin +++ b/vendor/wasm/WebGL/webgl.odin @@ -46,24 +46,26 @@ foreign webgl { IsExtensionSupported :: proc(name: string) -> bool --- - ActiveTexture :: proc(x: Enum) --- - AttachShader :: proc(program: Program, shader: Shader) --- - BindAttribLocation :: proc(program: Program, index: i32, name: string) --- - BindBuffer :: proc(target: Enum, buffer: Buffer) --- - BindFramebuffer :: proc(target: Enum, framebuffer: Framebuffer) --- - BindTexture :: proc(target: Enum, texture: Texture) --- - BlendColor :: proc(red, green, blue, alpha: f32) --- - BlendEquation :: proc(mode: Enum) --- - BlendFunc :: proc(sfactor, dfactor: Enum) --- - BlendFuncSeparate :: proc(srcRGB, dstRGB, srcAlpha, dstAlpha: Enum) --- + ActiveTexture :: proc(x: Enum) --- + AttachShader :: proc(program: Program, shader: Shader) --- + BindAttribLocation :: proc(program: Program, index: i32, name: string) --- + BindBuffer :: proc(target: Enum, buffer: Buffer) --- + BindFramebuffer :: proc(target: Enum, framebuffer: Framebuffer) --- + BindTexture :: proc(target: Enum, texture: Texture) --- + BindRenderbuffer :: proc(target: Enum, renderbuffer: Renderbuffer) --- + BlendColor :: proc(red, green, blue, alpha: f32) --- + BlendEquation :: proc(mode: Enum) --- + BlendEquationSeparate :: proc(modeRGB: Enum, modeAlpha: Enum) --- + BlendFunc :: proc(sfactor, dfactor: Enum) --- + BlendFuncSeparate :: proc(srcRGB, dstRGB, srcAlpha, dstAlpha: Enum) --- BufferData :: proc(target: Enum, size: int, data: rawptr, usage: Enum) --- BufferSubData :: proc(target: Enum, offset: uintptr, size: int, data: rawptr) --- - Clear :: proc(bits: Enum) --- + Clear :: proc(bits: u32) --- ClearColor :: proc(r, g, b, a: f32) --- - ClearDepth :: proc(x: Enum) --- - ClearStencil :: proc(x: Enum) --- + ClearDepth :: proc(x: f32) --- + ClearStencil :: proc(x: i32) --- ColorMask :: proc(r, g, b, a: bool) --- CompileShader :: proc(shader: Shader) --- @@ -113,6 +115,7 @@ foreign webgl { GetVertexAttribOffset :: proc(index: i32, pname: Enum) -> uintptr --- GetProgramParameter :: proc(program: Program, pname: Enum) -> i32 --- GetParameter :: proc(pname: Enum) -> i32 --- + GetParameter4i :: proc(pname: Enum, v0, v1, v2, v4: ^i32) --- Hint :: proc(target: Enum, mode: Enum) --- @@ -170,14 +173,63 @@ foreign webgl { Viewport :: proc(x, y, w, h: i32) --- } -Uniform1fv :: proc "contextless" (location: i32, v: f32) { Uniform1f(location, v) } -Uniform2fv :: proc "contextless" (location: i32, v: glm.vec2) { Uniform2f(location, v.x, v.y) } -Uniform3fv :: proc "contextless" (location: i32, v: glm.vec3) { Uniform3f(location, v.x, v.y, v.z) } -Uniform4fv :: proc "contextless" (location: i32, v: glm.vec4) { Uniform4f(location, v.x, v.y, v.z, v.w) } -Uniform1iv :: proc "contextless" (location: i32, v: i32) { Uniform1i(location, v) } -Uniform2iv :: proc "contextless" (location: i32, v: glm.ivec2) { Uniform2i(location, v.x, v.y) } -Uniform3iv :: proc "contextless" (location: i32, v: glm.ivec3) { Uniform3i(location, v.x, v.y, v.z) } -Uniform4iv :: proc "contextless" (location: i32, v: glm.ivec4) { Uniform4i(location, v.x, v.y, v.z, v.w) } +Uniform1fv :: proc "contextless" (location: i32, v: []f32) { + foreign webgl { + @(link_name="Uniform1fv") + _Uniform1fv :: proc "contextless" (location: i32, count: int, value: [^]f32) --- + } + _Uniform1fv(location, len(v), &v[0]) +} +Uniform2fv :: proc "contextless" (location: i32, v: []glm.vec2) { + foreign webgl { + @(link_name="Uniform2fv") + _Uniform2fv :: proc "contextless" (location: i32, count: int, value: [^]f32) --- + } + _Uniform2fv(location, len(v), &v[0].x) +} +Uniform3fv :: proc "contextless" (location: i32, v: []glm.vec3) { + foreign webgl { + @(link_name="Uniform3fv") + _Uniform3fv :: proc "contextless" (location: i32, count: int, value: [^]f32) --- + } + _Uniform3fv(location, len(v), &v[0].x) +} +Uniform4fv :: proc "contextless" (location: i32, v: []glm.vec4) { + foreign webgl { + @(link_name="Uniform4fv") + _Uniform4fv :: proc "contextless" (location: i32, count: int, value: [^]f32) --- + } + _Uniform4fv(location, len(v), &v[0].x) +} + +Uniform1iv :: proc "contextless" (location: i32, v: []i32) { + foreign webgl { + @(link_name="Uniform1iv") + _Uniform1iv :: proc "contextless" (location: i32, count: int, value: [^]i32) --- + } + _Uniform1iv(location, len(v), &v[0]) +} +Uniform2iv :: proc "contextless" (location: i32, v: []glm.ivec2) { + foreign webgl { + @(link_name="Uniform2iv") + _Uniform2iv :: proc "contextless" (location: i32, count: int, value: [^]i32) --- + } + _Uniform2iv(location, len(v), &v[0].x) +} +Uniform3iv :: proc "contextless" (location: i32, v: []glm.ivec3) { + foreign webgl { + @(link_name="Uniform3iv") + _Uniform3iv :: proc "contextless" (location: i32, count: int, value: [^]i32) --- + } + _Uniform3iv(location, len(v), &v[0].x) +} +Uniform4iv :: proc "contextless" (location: i32, v: []glm.ivec4) { + foreign webgl { + @(link_name="Uniform4iv") + _Uniform4iv :: proc "contextless" (location: i32, count: int, value: [^]i32) --- + } + _Uniform4iv(location, len(v), &v[0].x) +} VertexAttrib1fv :: proc "contextless" (index: i32, v: f32) { VertexAttrib1f(index, v) } VertexAttrib2fv :: proc "contextless" (index: i32, v: glm.vec2){ VertexAttrib2f(index, v.x, v.y) } diff --git a/vendor/wasm/WebGL/webgl2.odin b/vendor/wasm/WebGL/webgl2.odin index 74f0534d7..66a739303 100644 --- a/vendor/wasm/WebGL/webgl2.odin +++ b/vendor/wasm/WebGL/webgl2.odin @@ -36,7 +36,7 @@ foreign webgl2 { /* Texture objects */ TexStorage3D :: proc(target: Enum, levels: i32, internalformat: Enum, width, height, depth: i32) --- TexImage3D :: proc(target: Enum, level: i32, internalformat: Enum, width, height, depth: i32, border: i32, format, type: Enum, size: int, data: rawptr) --- - TexSubImage3D :: proc(target: Enum, level: i32, xoffset, yoffset, width, height, depth: i32, format, type: Enum, size: int, data: rawptr) --- + TexSubImage3D :: proc(target: Enum, level: i32, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: Enum, size: int, data: rawptr) --- CompressedTexImage3D :: proc(target: Enum, level: i32, internalformat: Enum, width, height, depth: i32, border: i32, imageSize: int, data: rawptr) --- CompressedTexSubImage3D :: proc(target: Enum, level: i32, xoffset, yoffset: i32, width, height, depth: i32, format: Enum, imageSize: int, data: rawptr) --- CopyTexSubImage3D :: proc(target: Enum, level: i32, xoffset, yoffset, zoffset: i32, x, y, width, height: i32) --- diff --git a/vendor/wasm/WebGL/webgl_helpers.odin b/vendor/wasm/WebGL/webgl_helpers.odin index 585706fbc..920734e99 100644 --- a/vendor/wasm/WebGL/webgl_helpers.odin +++ b/vendor/wasm/WebGL/webgl_helpers.odin @@ -29,7 +29,7 @@ CreateProgramFromStrings :: proc(vs_sources, fs_sources: []string) -> (program: } program = CreateProgram() - defer if !ok do DeleteProgram(program) + defer if !ok { DeleteProgram(program) } AttachShader(program, vs) AttachShader(program, fs) diff --git a/vendor/wgpu/README.md b/vendor/wgpu/doc.odin similarity index 68% rename from vendor/wgpu/README.md rename to vendor/wgpu/doc.odin index 8564244be..23f5dfc39 100644 --- a/vendor/wgpu/README.md +++ b/vendor/wgpu/doc.odin @@ -1,25 +1,26 @@ -# WGPU - +/* A cross-platform (and WASM) GPU API. WASM support is achieved by providing wrappers around the browser native WebGPU API -that are called instead of the [wgpu-native](https://github.com/gfx-rs/wgpu-native) library, +that are called instead of the [[wgpu-native; https://github.com/gfx-rs/wgpu-native]] library, the wgpu-native library provides support for all other targets. -Have a look at the `example/` directory for the rendering of a basic triangle. +**Examples** -## Getting the wgpu-native libraries +You can find a number of examples on [[Odin's official examples repository; https://github.com/odin-lang/examples/tree/master/wgpu]]. + +**Getting the wgpu-native libraries** For native support (not the browser), some libraries are required. Fortunately this is -extremely easy, just download them from the [releases on GitHub](https://github.com/gfx-rs/wgpu-native/releases/tag/v24.0.0.2), -the bindings are for v24.0.0.2 at the moment. +extremely easy, just download them from the [[releases on GitHub; https://github.com/gfx-rs/wgpu-native/releases/tag/v25.0.2.1]]. +the bindings are for v25.0.2.1 at the moment. These are expected in the `lib` folder under the same name as they are released (just unzipped). By default it will look for a static release version (`wgpu-OS-ARCH-release.a|lib`), you can set `-define:WGPU_DEBUG=true` for it to look for a debug version, and use `-define:WGPU_SHARED=true` to look for the shared libraries. -## WASM +**WASM** For WASM, the module has to be built with a function table to enable callbacks. You can do so using `-extra-linker-flags:"--export-table"`. @@ -29,12 +30,20 @@ Being able to allocate is also required (for some auxiliary APIs but also for ma You can set the context that is used for allocations by setting the global variable `wpgu.g_context`. It will default to the `runtime.default_context`. -Again, have a look at the `example/` and how it is set up, doing the `--import-memory` and the likes +Have a look at the [[example build file; https://github.com/odin-lang/examples/blob/master/wgpu/glfw-triangle/build_web.sh]] and [[html file; https://github.com/odin-lang/examples/blob/master/wgpu/glfw-triangle/web/index.html]] +to see how it looks when set up, doing the `--import-memory` and the likes is not strictly necessary but allows your app more memory than the minimal default. The bindings work on both `-target:js_wasm32` and `-target:js_wasm64p32`. -## GLFW Glue +**SDL Glue** + +There is an inner package `sdl2glue` (and `sdl3glue`) that can be used to glue together WGPU and SDL. +It exports one procedure `GetSurface(wgpu.Instance, ^SDL.Window) -> wgpu.Surface`. +The procedure will call the needed target specific procedures and return a surface configured +for the given window. + +**GLFW Glue** There is an inner package `glfwglue` that can be used to glue together WGPU and GLFW. It exports one procedure `GetSurface(wgpu.Instance, glfw.WindowHandle) -> wgpu.Surface`. @@ -44,14 +53,7 @@ for the given window. Do note that wgpu does not require GLFW, you can use native windows or another windowing library too. For that you can take inspiration from `glfwglue` on glueing them together. -## SDL2 Glue - -There is an inner package `sdl2glue` that can be used to glue together WGPU and SDL2. -It exports one procedure `GetSurface(wgpu.Instance, ^sdl2.Window) -> wgpu.Surface`. -The procedure will call the needed target specific procedures and return a surface configured -for the given window. - -### Wayland +**GLFW and Wayland** GLFW supports Wayland from version 3.4 onwards and only if it is compiled with `-DGLFW_EXPOSE_NATIVE_WAYLAND`. @@ -59,3 +61,5 @@ Odin links against your system's glfw library (probably installed through a pack If that version is lower than 3.4 or hasn't been compiled with the previously mentioned define, you will have to compile glfw from source yourself and adjust the `foreign import` declarations in `vendor:glfw/bindings` to point to it. +*/ +package wgpu diff --git a/vendor/wgpu/examples/glfw/Makefile b/vendor/wgpu/examples/glfw/Makefile deleted file mode 100644 index 022bfcbbc..000000000 --- a/vendor/wgpu/examples/glfw/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -FILES := $(wildcard *) - -# NOTE: changing this requires changing the same values in the `web/index.html`. -INITIAL_MEMORY_PAGES := 2000 -MAX_MEMORY_PAGES := 65536 - -PAGE_SIZE := 65536 -INITIAL_MEMORY_BYTES := $(shell expr $(INITIAL_MEMORY_PAGES) \* $(PAGE_SIZE)) -MAX_MEMORY_BYTES := $(shell expr $(MAX_MEMORY_PAGES) \* $(PAGE_SIZE)) - -web/triangle.wasm: $(FILES) ../../wgpu.js ../../../../core/sys/wasm/js/odin.js - odin build . \ - -target:js_wasm32 -out:web/triangle.wasm -o:size \ - -extra-linker-flags:"--export-table --import-memory --initial-memory=$(INITIAL_MEMORY_BYTES) --max-memory=$(MAX_MEMORY_BYTES)" - - cp ../../wgpu.js web/wgpu.js - cp ../../../../core/sys/wasm/js/odin.js web/odin.js diff --git a/vendor/wgpu/examples/glfw/build.bat b/vendor/wgpu/examples/glfw/build.bat deleted file mode 100644 index b71d4344a..000000000 --- a/vendor/wgpu/examples/glfw/build.bat +++ /dev/null @@ -1,12 +0,0 @@ -REM NOTE: changing this requires changing the same values in the `web/index.html`. -set INITIAL_MEMORY_PAGES=2000 -set MAX_MEMORY_PAGES=65536 - -set PAGE_SIZE=65536 -set /a INITIAL_MEMORY_BYTES=%INITIAL_MEMORY_PAGES% * %PAGE_SIZE% -set /a MAX_MEMORY_BYTES=%MAX_MEMORY_PAGES% * %PAGE_SIZE% - -call odin.exe build . -target:js_wasm32 -out:web/triangle.wasm -o:size -extra-linker-flags:"--export-table --import-memory --initial-memory=%INITIAL_MEMORY_BYTES% --max-memory=%MAX_MEMORY_BYTES%" - -copy "..\..\wgpu.js" "web\wgpu.js" -copy "..\..\..\..\core\sys\wasm\js\odin.js" "web\odin.js" diff --git a/vendor/wgpu/examples/glfw/main.odin b/vendor/wgpu/examples/glfw/main.odin deleted file mode 100644 index b6438bbc5..000000000 --- a/vendor/wgpu/examples/glfw/main.odin +++ /dev/null @@ -1,189 +0,0 @@ -package vendor_wgpu_example_triangle - -import "base:runtime" - -import "core:fmt" - -import "vendor:wgpu" - -State :: struct { - ctx: runtime.Context, - os: OS, - - instance: wgpu.Instance, - surface: wgpu.Surface, - adapter: wgpu.Adapter, - device: wgpu.Device, - config: wgpu.SurfaceConfiguration, - queue: wgpu.Queue, - module: wgpu.ShaderModule, - pipeline_layout: wgpu.PipelineLayout, - pipeline: wgpu.RenderPipeline, -} - -@(private="file") -state: State - -main :: proc() { - state.ctx = context - - os_init(&state.os) - - state.instance = wgpu.CreateInstance(nil) - if state.instance == nil { - panic("WebGPU is not supported") - } - state.surface = os_get_surface(&state.os, state.instance) - - wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, { callback = on_adapter }) - - on_adapter :: proc "c" (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: string, userdata1: rawptr, userdata2: rawptr) { - context = state.ctx - if status != .Success || adapter == nil { - fmt.panicf("request adapter failure: [%v] %s", status, message) - } - state.adapter = adapter - wgpu.AdapterRequestDevice(adapter, nil, { callback = on_device }) - } - - on_device :: proc "c" (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: string, userdata1: rawptr, userdata2: rawptr) { - context = state.ctx - if status != .Success || device == nil { - fmt.panicf("request device failure: [%v] %s", status, message) - } - state.device = device - - width, height := os_get_render_bounds(&state.os) - - state.config = wgpu.SurfaceConfiguration { - device = state.device, - usage = { .RenderAttachment }, - format = .BGRA8Unorm, - width = width, - height = height, - presentMode = .Fifo, - alphaMode = .Opaque, - } - wgpu.SurfaceConfigure(state.surface, &state.config) - - state.queue = wgpu.DeviceGetQueue(state.device) - - shader :: ` - @vertex - fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4 { - let x = f32(i32(in_vertex_index) - 1); - let y = f32(i32(in_vertex_index & 1u) * 2 - 1); - return vec4(x, y, 0.0, 1.0); - } - - @fragment - fn fs_main() -> @location(0) vec4 { - return vec4(1.0, 0.0, 0.0, 1.0); - }` - - state.module = wgpu.DeviceCreateShaderModule(state.device, &{ - nextInChain = &wgpu.ShaderSourceWGSL{ - sType = .ShaderSourceWGSL, - code = shader, - }, - }) - - state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(state.device, &{}) - state.pipeline = wgpu.DeviceCreateRenderPipeline(state.device, &{ - layout = state.pipeline_layout, - vertex = { - module = state.module, - entryPoint = "vs_main", - }, - fragment = &{ - module = state.module, - entryPoint = "fs_main", - targetCount = 1, - targets = &wgpu.ColorTargetState{ - format = .BGRA8Unorm, - writeMask = wgpu.ColorWriteMaskFlags_All, - }, - }, - primitive = { - topology = .TriangleList, - - }, - multisample = { - count = 1, - mask = 0xFFFFFFFF, - }, - }) - - os_run(&state.os) - } -} - -resize :: proc "c" () { - context = state.ctx - - state.config.width, state.config.height = os_get_render_bounds(&state.os) - wgpu.SurfaceConfigure(state.surface, &state.config) -} - -frame :: proc "c" (dt: f32) { - context = state.ctx - - surface_texture := wgpu.SurfaceGetCurrentTexture(state.surface) - switch surface_texture.status { - case .SuccessOptimal, .SuccessSuboptimal: - // All good, could handle suboptimal here. - case .Timeout, .Outdated, .Lost: - // Skip this frame, and re-configure surface. - if surface_texture.texture != nil { - wgpu.TextureRelease(surface_texture.texture) - } - resize() - return - case .OutOfMemory, .DeviceLost, .Error: - // Fatal error - fmt.panicf("[triangle] get_current_texture status=%v", surface_texture.status) - } - defer wgpu.TextureRelease(surface_texture.texture) - - frame := wgpu.TextureCreateView(surface_texture.texture, nil) - defer wgpu.TextureViewRelease(frame) - - command_encoder := wgpu.DeviceCreateCommandEncoder(state.device, nil) - defer wgpu.CommandEncoderRelease(command_encoder) - - render_pass_encoder := wgpu.CommandEncoderBeginRenderPass( - command_encoder, &{ - colorAttachmentCount = 1, - colorAttachments = &wgpu.RenderPassColorAttachment{ - view = frame, - loadOp = .Clear, - storeOp = .Store, - depthSlice = wgpu.DEPTH_SLICE_UNDEFINED, - clearValue = { 0, 1, 0, 1 }, - }, - }, - ) - - wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline) - wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) - - wgpu.RenderPassEncoderEnd(render_pass_encoder) - wgpu.RenderPassEncoderRelease(render_pass_encoder) - - command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil) - defer wgpu.CommandBufferRelease(command_buffer) - - wgpu.QueueSubmit(state.queue, { command_buffer }) - wgpu.SurfacePresent(state.surface) -} - -finish :: proc() { - wgpu.RenderPipelineRelease(state.pipeline) - wgpu.PipelineLayoutRelease(state.pipeline_layout) - wgpu.ShaderModuleRelease(state.module) - wgpu.QueueRelease(state.queue) - wgpu.DeviceRelease(state.device) - wgpu.AdapterRelease(state.adapter) - wgpu.SurfaceRelease(state.surface) - wgpu.InstanceRelease(state.instance) -} diff --git a/vendor/wgpu/examples/glfw/os_glfw.odin b/vendor/wgpu/examples/glfw/os_glfw.odin deleted file mode 100644 index 98407b5e2..000000000 --- a/vendor/wgpu/examples/glfw/os_glfw.odin +++ /dev/null @@ -1,55 +0,0 @@ -#+build !js -package vendor_wgpu_example_triangle - -import "core:time" - -import "vendor:glfw" -import "vendor:wgpu" -import "vendor:wgpu/glfwglue" - -OS :: struct { - window: glfw.WindowHandle, -} - -os_init :: proc(os: ^OS) { - if !glfw.Init() { - panic("[glfw] init failure") - } - - glfw.WindowHint(glfw.CLIENT_API, glfw.NO_API) - os.window = glfw.CreateWindow(960, 540, "WGPU Native Triangle", nil, nil) - - glfw.SetFramebufferSizeCallback(os.window, size_callback) -} - -os_run :: proc(os: ^OS) { - dt: f32 - - for !glfw.WindowShouldClose(os.window) { - start := time.tick_now() - - glfw.PollEvents() - frame(dt) - - dt = f32(time.duration_seconds(time.tick_since(start))) - } - - finish() - - glfw.DestroyWindow(os.window) - glfw.Terminate() -} - -os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) { - iw, ih := glfw.GetWindowSize(os.window) - return u32(iw), u32(ih) -} - -os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { - return glfwglue.GetSurface(instance, os.window) -} - -@(private="file") -size_callback :: proc "c" (window: glfw.WindowHandle, width, height: i32) { - resize() -} diff --git a/vendor/wgpu/examples/glfw/os_js.odin b/vendor/wgpu/examples/glfw/os_js.odin deleted file mode 100644 index 71c3aaeb5..000000000 --- a/vendor/wgpu/examples/glfw/os_js.odin +++ /dev/null @@ -1,61 +0,0 @@ -package vendor_wgpu_example_triangle - -import "core:sys/wasm/js" - -import "vendor:wgpu" - -OS :: struct { - initialized: bool, -} - -@(private="file") -g_os: ^OS - -os_init :: proc(os: ^OS) { - g_os = os - assert(js.add_window_event_listener(.Resize, nil, size_callback)) -} - -// NOTE: frame loop is done by the runtime.js repeatedly calling `step`. -os_run :: proc(os: ^OS) { - os.initialized = true -} - -os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) { - rect := js.get_bounding_client_rect("body") - return u32(rect.width), u32(rect.height) -} - -os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ - nextInChain = &wgpu.SurfaceSourceCanvasHTMLSelector{ - sType = .SurfaceSourceCanvasHTMLSelector, - selector = "#wgpu-canvas", - }, - }, - ) -} - -@(private="file", export) -step :: proc(dt: f32) -> bool { - if !g_os.initialized { - return true - } - - frame(dt) - return true -} - -@(private="file", fini) -os_fini :: proc() { - js.remove_window_event_listener(.Resize, nil, size_callback) - - finish() -} - -@(private="file") -size_callback :: proc(e: js.Event) { - resize() -} diff --git a/vendor/wgpu/examples/glfw/web/index.html b/vendor/wgpu/examples/glfw/web/index.html deleted file mode 100644 index a509cafbd..000000000 --- a/vendor/wgpu/examples/glfw/web/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - WGPU WASM Triangle - - - - - - - - - diff --git a/vendor/wgpu/examples/sdl2/Makefile b/vendor/wgpu/examples/sdl2/Makefile deleted file mode 100644 index 022bfcbbc..000000000 --- a/vendor/wgpu/examples/sdl2/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -FILES := $(wildcard *) - -# NOTE: changing this requires changing the same values in the `web/index.html`. -INITIAL_MEMORY_PAGES := 2000 -MAX_MEMORY_PAGES := 65536 - -PAGE_SIZE := 65536 -INITIAL_MEMORY_BYTES := $(shell expr $(INITIAL_MEMORY_PAGES) \* $(PAGE_SIZE)) -MAX_MEMORY_BYTES := $(shell expr $(MAX_MEMORY_PAGES) \* $(PAGE_SIZE)) - -web/triangle.wasm: $(FILES) ../../wgpu.js ../../../../core/sys/wasm/js/odin.js - odin build . \ - -target:js_wasm32 -out:web/triangle.wasm -o:size \ - -extra-linker-flags:"--export-table --import-memory --initial-memory=$(INITIAL_MEMORY_BYTES) --max-memory=$(MAX_MEMORY_BYTES)" - - cp ../../wgpu.js web/wgpu.js - cp ../../../../core/sys/wasm/js/odin.js web/odin.js diff --git a/vendor/wgpu/examples/sdl2/build.bat b/vendor/wgpu/examples/sdl2/build.bat deleted file mode 100644 index b71d4344a..000000000 --- a/vendor/wgpu/examples/sdl2/build.bat +++ /dev/null @@ -1,12 +0,0 @@ -REM NOTE: changing this requires changing the same values in the `web/index.html`. -set INITIAL_MEMORY_PAGES=2000 -set MAX_MEMORY_PAGES=65536 - -set PAGE_SIZE=65536 -set /a INITIAL_MEMORY_BYTES=%INITIAL_MEMORY_PAGES% * %PAGE_SIZE% -set /a MAX_MEMORY_BYTES=%MAX_MEMORY_PAGES% * %PAGE_SIZE% - -call odin.exe build . -target:js_wasm32 -out:web/triangle.wasm -o:size -extra-linker-flags:"--export-table --import-memory --initial-memory=%INITIAL_MEMORY_BYTES% --max-memory=%MAX_MEMORY_BYTES%" - -copy "..\..\wgpu.js" "web\wgpu.js" -copy "..\..\..\..\core\sys\wasm\js\odin.js" "web\odin.js" diff --git a/vendor/wgpu/examples/sdl2/main.odin b/vendor/wgpu/examples/sdl2/main.odin deleted file mode 100644 index 2dbfc9903..000000000 --- a/vendor/wgpu/examples/sdl2/main.odin +++ /dev/null @@ -1,189 +0,0 @@ -package vendor_wgpu_example_triangle - -import "base:runtime" - -import "core:fmt" - -import "vendor:wgpu" - -State :: struct { - ctx: runtime.Context, - os: OS, - - instance: wgpu.Instance, - surface: wgpu.Surface, - adapter: wgpu.Adapter, - device: wgpu.Device, - config: wgpu.SurfaceConfiguration, - queue: wgpu.Queue, - module: wgpu.ShaderModule, - pipeline_layout: wgpu.PipelineLayout, - pipeline: wgpu.RenderPipeline, -} - -@(private="file") -state: State - -main :: proc() { - state.ctx = context - - os_init(&state.os) - - state.instance = wgpu.CreateInstance(nil) - if state.instance == nil { - panic("WebGPU is not supported") - } - state.surface = os_get_surface(&state.os, state.instance) - - wgpu.InstanceRequestAdapter(state.instance, &{ compatibleSurface = state.surface }, { callback = on_adapter }) - - on_adapter :: proc "c" (status: wgpu.RequestAdapterStatus, adapter: wgpu.Adapter, message: string, userdata1, userdata2: rawptr) { - context = state.ctx - if status != .Success || adapter == nil { - fmt.panicf("request adapter failure: [%v] %s", status, message) - } - state.adapter = adapter - wgpu.AdapterRequestDevice(adapter, nil, { callback = on_device }) - } - - on_device :: proc "c" (status: wgpu.RequestDeviceStatus, device: wgpu.Device, message: string, userdata1, userdata2: rawptr) { - context = state.ctx - if status != .Success || device == nil { - fmt.panicf("request device failure: [%v] %s", status, message) - } - state.device = device - - width, height := os_get_render_bounds(&state.os) - - state.config = wgpu.SurfaceConfiguration { - device = state.device, - usage = { .RenderAttachment }, - format = .BGRA8Unorm, - width = width, - height = height, - presentMode = .Fifo, - alphaMode = .Opaque, - } - wgpu.SurfaceConfigure(state.surface, &state.config) - - state.queue = wgpu.DeviceGetQueue(state.device) - - shader :: ` - @vertex - fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) vec4 { - let x = f32(i32(in_vertex_index) - 1); - let y = f32(i32(in_vertex_index & 1u) * 2 - 1); - return vec4(x, y, 0.0, 1.0); - } - - @fragment - fn fs_main() -> @location(0) vec4 { - return vec4(1.0, 0.0, 0.0, 1.0); - }` - - state.module = wgpu.DeviceCreateShaderModule(state.device, &{ - nextInChain = &wgpu.ShaderSourceWGSL{ - sType = .ShaderSourceWGSL, - code = shader, - }, - }) - - state.pipeline_layout = wgpu.DeviceCreatePipelineLayout(state.device, &{}) - state.pipeline = wgpu.DeviceCreateRenderPipeline(state.device, &{ - layout = state.pipeline_layout, - vertex = { - module = state.module, - entryPoint = "vs_main", - }, - fragment = &{ - module = state.module, - entryPoint = "fs_main", - targetCount = 1, - targets = &wgpu.ColorTargetState{ - format = .BGRA8Unorm, - writeMask = wgpu.ColorWriteMaskFlags_All, - }, - }, - primitive = { - topology = .TriangleList, - - }, - multisample = { - count = 1, - mask = 0xFFFFFFFF, - }, - }) - - os_run(&state.os) - } -} - -resize :: proc "c" () { - context = state.ctx - - state.config.width, state.config.height = os_get_render_bounds(&state.os) - wgpu.SurfaceConfigure(state.surface, &state.config) -} - -frame :: proc "c" (dt: f32) { - context = state.ctx - - surface_texture := wgpu.SurfaceGetCurrentTexture(state.surface) - switch surface_texture.status { - case .SuccessOptimal, .SuccessSuboptimal: - // All good, could handle suboptimal here. - case .Timeout, .Outdated, .Lost: - // Skip this frame, and re-configure surface. - if surface_texture.texture != nil { - wgpu.TextureRelease(surface_texture.texture) - } - resize() - return - case .OutOfMemory, .DeviceLost, .Error: - // Fatal error - fmt.panicf("[triangle] get_current_texture status=%v", surface_texture.status) - } - defer wgpu.TextureRelease(surface_texture.texture) - - frame := wgpu.TextureCreateView(surface_texture.texture, nil) - defer wgpu.TextureViewRelease(frame) - - command_encoder := wgpu.DeviceCreateCommandEncoder(state.device, nil) - defer wgpu.CommandEncoderRelease(command_encoder) - - render_pass_encoder := wgpu.CommandEncoderBeginRenderPass( - command_encoder, &{ - colorAttachmentCount = 1, - colorAttachments = &wgpu.RenderPassColorAttachment{ - view = frame, - loadOp = .Clear, - storeOp = .Store, - depthSlice = wgpu.DEPTH_SLICE_UNDEFINED, - clearValue = { 0, 1, 0, 1 }, - }, - }, - ) - - wgpu.RenderPassEncoderSetPipeline(render_pass_encoder, state.pipeline) - wgpu.RenderPassEncoderDraw(render_pass_encoder, vertexCount=3, instanceCount=1, firstVertex=0, firstInstance=0) - - wgpu.RenderPassEncoderEnd(render_pass_encoder) - wgpu.RenderPassEncoderRelease(render_pass_encoder) - - command_buffer := wgpu.CommandEncoderFinish(command_encoder, nil) - defer wgpu.CommandBufferRelease(command_buffer) - - wgpu.QueueSubmit(state.queue, { command_buffer }) - wgpu.SurfacePresent(state.surface) -} - -finish :: proc() { - wgpu.RenderPipelineRelease(state.pipeline) - wgpu.PipelineLayoutRelease(state.pipeline_layout) - wgpu.ShaderModuleRelease(state.module) - wgpu.QueueRelease(state.queue) - wgpu.DeviceRelease(state.device) - wgpu.AdapterRelease(state.adapter) - wgpu.SurfaceRelease(state.surface) - wgpu.InstanceRelease(state.instance) -} diff --git a/vendor/wgpu/examples/sdl2/os_js.odin b/vendor/wgpu/examples/sdl2/os_js.odin deleted file mode 100644 index 71c3aaeb5..000000000 --- a/vendor/wgpu/examples/sdl2/os_js.odin +++ /dev/null @@ -1,61 +0,0 @@ -package vendor_wgpu_example_triangle - -import "core:sys/wasm/js" - -import "vendor:wgpu" - -OS :: struct { - initialized: bool, -} - -@(private="file") -g_os: ^OS - -os_init :: proc(os: ^OS) { - g_os = os - assert(js.add_window_event_listener(.Resize, nil, size_callback)) -} - -// NOTE: frame loop is done by the runtime.js repeatedly calling `step`. -os_run :: proc(os: ^OS) { - os.initialized = true -} - -os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) { - rect := js.get_bounding_client_rect("body") - return u32(rect.width), u32(rect.height) -} - -os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { - return wgpu.InstanceCreateSurface( - instance, - &wgpu.SurfaceDescriptor{ - nextInChain = &wgpu.SurfaceSourceCanvasHTMLSelector{ - sType = .SurfaceSourceCanvasHTMLSelector, - selector = "#wgpu-canvas", - }, - }, - ) -} - -@(private="file", export) -step :: proc(dt: f32) -> bool { - if !g_os.initialized { - return true - } - - frame(dt) - return true -} - -@(private="file", fini) -os_fini :: proc() { - js.remove_window_event_listener(.Resize, nil, size_callback) - - finish() -} - -@(private="file") -size_callback :: proc(e: js.Event) { - resize() -} diff --git a/vendor/wgpu/examples/sdl2/os_sdl2.odin b/vendor/wgpu/examples/sdl2/os_sdl2.odin deleted file mode 100644 index 6ed70452f..000000000 --- a/vendor/wgpu/examples/sdl2/os_sdl2.odin +++ /dev/null @@ -1,85 +0,0 @@ -#+build !js -package vendor_wgpu_example_triangle - -import "core:c" -import "core:fmt" - -import "vendor:sdl2" -import "vendor:wgpu" -import "vendor:wgpu/sdl2glue" - -OS :: struct { - window: ^sdl2.Window, -} - -os_init :: proc(os: ^OS) { - sdl_flags := sdl2.InitFlags{.VIDEO, .JOYSTICK, .GAMECONTROLLER, .EVENTS} - if res := sdl2.Init(sdl_flags); res != 0 { - fmt.eprintfln("ERROR: Failed to initialize SDL: [%s]", sdl2.GetError()) - return - } - - window_flags: sdl2.WindowFlags = {.SHOWN, .ALLOW_HIGHDPI, .RESIZABLE} - os.window = sdl2.CreateWindow( - "WGPU Native Triangle", - sdl2.WINDOWPOS_CENTERED, - sdl2.WINDOWPOS_CENTERED, - 960, - 540, - window_flags, - ) - if os.window == nil { - fmt.eprintfln("ERROR: Failed to create the SDL Window: [%s]", sdl2.GetError()) - return - } - - sdl2.AddEventWatch(size_callback, nil) -} - -os_run :: proc(os: ^OS) { - now := sdl2.GetPerformanceCounter() - last : u64 - dt: f32 - main_loop: for { - last = now - now = sdl2.GetPerformanceCounter() - dt = f32((now - last) * 1000) / f32(sdl2.GetPerformanceFrequency()) - - e: sdl2.Event - - for sdl2.PollEvent(&e) { - #partial switch (e.type) { - case .QUIT: - break main_loop - } - } - - frame(dt) - } - - sdl2.DestroyWindow(os.window) - sdl2.Quit() - - finish() -} - - -os_get_render_bounds :: proc(os: ^OS) -> (width, height: u32) { - iw, ih: c.int - sdl2.GetWindowSize(os.window, &iw, &ih) - return u32(iw), u32(ih) -} - -os_get_surface :: proc(os: ^OS, instance: wgpu.Instance) -> wgpu.Surface { - return sdl2glue.GetSurface(instance, os.window) -} - -@(private="file") -size_callback :: proc "c" (userdata: rawptr, event: ^sdl2.Event) -> c.int { - if event.type == .WINDOWEVENT { - if event.window.event == .SIZE_CHANGED || event.window.event == .RESIZED { - resize() - } - } - return 0 -} diff --git a/vendor/wgpu/examples/sdl2/web/index.html b/vendor/wgpu/examples/sdl2/web/index.html deleted file mode 100644 index a509cafbd..000000000 --- a/vendor/wgpu/examples/sdl2/web/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - WGPU WASM Triangle - - - - - - - - - diff --git a/vendor/wgpu/lib/wgpu-windows-x86_64-msvc-release/lib/wgpu_native.dll b/vendor/wgpu/lib/wgpu-windows-x86_64-msvc-release/lib/wgpu_native.dll index 7fa1c8398..3c4e1b5a6 100644 Binary files a/vendor/wgpu/lib/wgpu-windows-x86_64-msvc-release/lib/wgpu_native.dll and b/vendor/wgpu/lib/wgpu-windows-x86_64-msvc-release/lib/wgpu_native.dll differ diff --git a/vendor/wgpu/lib/wgpu-windows-x86_64-msvc-release/lib/wgpu_native.lib b/vendor/wgpu/lib/wgpu-windows-x86_64-msvc-release/lib/wgpu_native.lib index 787feaede..3ea8453f9 100644 Binary files a/vendor/wgpu/lib/wgpu-windows-x86_64-msvc-release/lib/wgpu_native.lib and b/vendor/wgpu/lib/wgpu-windows-x86_64-msvc-release/lib/wgpu_native.lib differ diff --git a/vendor/wgpu/wgpu.js b/vendor/wgpu/wgpu.js index 4816659f9..6104417df 100644 --- a/vendor/wgpu/wgpu.js +++ b/vendor/wgpu/wgpu.js @@ -340,8 +340,8 @@ class WebGPUInterface { return STATUS_SUCCESS; } - - genericAdapterInfo(infoPtr) { + + genericGetAdapterInfo(infoPtr) { this.assert(infoPtr != 0); const off = this.struct(infoPtr); @@ -528,7 +528,7 @@ class WebGPUInterface { return undefined; } - const off = this.struct(ptr); + const off = this.struct(start); return { view: this.textureViews.get(this.mem.loadPtr(off(4))), @@ -1217,17 +1217,22 @@ class WebGPUInterface { .then((device) => { const deviceIdx = this.devices.create(device); - const deviceLostCallbackInfo = off(this.sizes.CallbackInfo); - if (descriptorPtr !== 0 && deviceLostCallbackInfo !== null) { + if (deviceLostCallbackInfo.callback !== null) { device.lost.then((info) => { const reason = ENUMS.DeviceLostReason.indexOf(info.reason); + + const devicePtr = this.mem.exports.wgpu_alloc(4); + this.mem.storeI32(devicePtr, deviceIdx); + const messageAddr = this.makeMessageArg(info.message); - this.callCallback(deviceLostCallbackInfo, [deviceIdx, reason, messageAddr]); + this.callCallback(deviceLostCallbackInfo, [devicePtr, reason, messageAddr]); + + this.mem.exports.wgpu_free(devicePtr); this.mem.exports.wgpu_free(messageAddr); }); } - if (descriptorPtr !== 0 && uncapturedErrorCallbackInfo !== null) { + if (uncapturedErrorCallbackInfo.callback !== null) { device.onuncapturederror = (ev) => { let status; if (ev.error instanceof GPUValidationError) { @@ -2028,7 +2033,7 @@ class WebGPUInterface { addressModeW: this.enumeration("AddressMode", off(4)), magFilter: this.enumeration("FilterMode", off(4)), minFilter: this.enumeration("FilterMode", off(4)), - mipMapFilter: this.enumeration("MipmapFilterMode", off(4)), + mipmapFilter: this.enumeration("MipmapFilterMode", off(4)), lodMinClamp: this.mem.loadF32(off(4)), lodMaxClamp: this.mem.loadF32(off(4)), compare: this.enumeration("CompareFunction", off(4)), @@ -2583,7 +2588,12 @@ class WebGPUInterface { } dynamicOffsetCount = this.unwrapBigInt(dynamicOffsetCount); - const dynamicOffsets = this.array(dynamicOffsetCount, dynamicOffsetsPtr, this.mem.loadU32, 4); + const dynamicOffsets = this.array( + dynamicOffsetCount, + dynamicOffsetsPtr, + (ptr) => this.mem.loadU32(ptr), + 4 + ); renderBundleEncoder.setBindGroup(groupIndex, group, dynamicOffsets); }, @@ -2775,7 +2785,12 @@ class WebGPUInterface { } dynamicOffsetCount = this.unwrapBigInt(dynamicOffsetCount); - const dynamicOffsets = this.array(dynamicOffsetCount, dynamicOffsetsPtr, this.mem.loadU32, 4); + const dynamicOffsets = this.array( + dynamicOffsetCount, + dynamicOffsetsPtr, + (ptr) => this.mem.loadU32(ptr), + 4 + ); renderPassEncoder.setBindGroup(groupIndex, group, dynamicOffsets); }, @@ -3082,7 +3097,7 @@ class WebGPUInterface { * @param {number} surfaceCapabilitiesPtr */ wgpuSurfaceCapabilitiesFreeMembers: (surfaceCapabilitiesPtr) => { - const off = this.struct(capabilitiesPtr); + const off = this.struct(surfaceCapabilitiesPtr); off(4); // nextInChain off(8); // usages off(this.mem.intSize); // formatCount diff --git a/vendor/wgpu/wgpu.odin b/vendor/wgpu/wgpu.odin index fa72dc37a..c44bb2cbb 100644 --- a/vendor/wgpu/wgpu.odin +++ b/vendor/wgpu/wgpu.odin @@ -13,7 +13,7 @@ when ODIN_OS == .Windows { @(private) LIB :: "lib/wgpu-windows-" + ARCH + "-msvc-" + TYPE + "/lib/wgpu_native" + EXT when !#exists(LIB) { - #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v24.0.0.2, make sure to read the README at '" + #directory + "README.md'") + #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v25.0.2.1, make sure to read the README at '" + #directory + "README.md'") } @(export) @@ -39,12 +39,13 @@ when ODIN_OS == .Windows { @(private) LIB :: "lib/wgpu-macos-" + ARCH + "-" + TYPE + "/lib/libwgpu_native" + EXT when !#exists(LIB) { - #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v24.0.0.2, make sure to read the README at '" + #directory + "README.md'") + #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v25.0.2.1, make sure to read the README at '" + #directory + "README.md'") } @(export) foreign import libwgpu { LIB, + "system:Foundation.framework", "system:CoreFoundation.framework", "system:QuartzCore.framework", "system:Metal.framework", @@ -55,7 +56,7 @@ when ODIN_OS == .Windows { @(private) LIB :: "lib/wgpu-linux-" + ARCH + "-" + TYPE + "/lib/libwgpu_native" + EXT when !#exists(LIB) { - #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v24.0.0.2, make sure to read the README at '" + #directory + "README.md'") + #panic("Could not find the compiled WGPU Native library at '" + #directory + LIB + "', these can be downloaded from https://github.com/gfx-rs/wgpu-native/releases/tag/v25.0.2.1, make sure to read the README at '" + #directory + "README.md'") } @(export) @@ -301,7 +302,7 @@ FeatureName :: enum i32 { // PolygonModePoint, // ConservativeRasterization, // ClearTexture, - SprivShaderPassThrough = 0x00030017, + SpirvShaderPassthrough = 0x00030017, // MultiView, VertexAttribute64bit = 0x00030019, TextureFormatNv12, @@ -438,7 +439,7 @@ SType :: enum i32 { DeviceExtras = 0x00030001, NativeLimits, PipelineLayoutExtras, - ShaderModuleGLSLDescriptor, + ShaderSourceGLSL, SupportedLimitsExtras, InstanceExtras, BindGroupEntryExtras, @@ -762,100 +763,100 @@ BufferMapCallback :: #type proc "c" (status: MapAsyncStatus, message: StringView CompilationInfoCallback :: #type proc "c" (status: CompilationInfoRequestStatus, compilationInfo: ^CompilationInfo, userdata1: rawptr, userdata2: rawptr) CreateComputePipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: ComputePipeline, message: StringView, userdata1: rawptr, userdata2: rawptr) CreateRenderPipelineAsyncCallback :: #type proc "c" (status: CreatePipelineAsyncStatus, pipeline: RenderPipeline, message: StringView, userdata1: rawptr, userdata2: rawptr) -DeviceLostCallback :: #type proc "c" (device: Device, reason: DeviceLostReason, message: StringView, userdata1: rawptr, userdata2: rawptr) +DeviceLostCallback :: #type proc "c" (device: ^Device, reason: DeviceLostReason, message: StringView, userdata1: rawptr, userdata2: rawptr) PopErrorScopeCallback :: #type proc "c" (status: PopErrorScopeStatus, type: ErrorType, message: StringView, userdata1: rawptr, userdata2: rawptr) QueueWorkDoneCallback :: #type proc "c" (status: QueueWorkDoneStatus, userdata1: rawptr, userdata2: rawptr) RequestAdapterCallback :: #type proc "c" (status: RequestAdapterStatus, adapter: Adapter, message: StringView, userdata1: rawptr, userdata2: rawptr) RequestDeviceCallback :: #type proc "c" (status: RequestDeviceStatus, adapter: Device, message: StringView, userdata1: rawptr, userdata2: rawptr) -UncapturedErrorCallback :: #type proc "c" (device: Device, type: ErrorType, message: StringView, userdata1: rawptr, userdata2: rawptr) +UncapturedErrorCallback :: #type proc "c" (device: ^Device, type: ErrorType, message: StringView, userdata1: rawptr, userdata2: rawptr) ChainedStruct :: struct { - next: ^ChainedStruct, + next: ^ChainedStruct, sType: SType, } ChainedStructOut :: struct { - next: ^ChainedStructOut, + next: ^ChainedStructOut, sType: SType, } BufferMapCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, mode: CallbackMode, callback: BufferMapCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } CompilationInfoCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, mode: CallbackMode, callback: CompilationInfoCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } CreateComputePipelineAsyncCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, mode: CallbackMode, callback: CreateComputePipelineAsyncCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } CreateRenderPipelineAsyncCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, mode: CallbackMode, callback: CreateRenderPipelineAsyncCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } DeviceLostCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, mode: CallbackMode, callback: DeviceLostCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } PopErrorScopeCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, mode: CallbackMode, callback: PopErrorScopeCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } QueueWorkDoneCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, mode: CallbackMode, callback: QueueWorkDoneCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } RequestAdapterCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, mode: CallbackMode, callback: RequestAdapterCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } RequestDeviceCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, mode: CallbackMode, callback: RequestDeviceCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } UncapturedErrorCallbackInfo :: struct { - nextInChain: ^ChainedStructOut, + nextInChain: /* const */ ^ChainedStruct, callback: UncapturedErrorCallback, - userdata1: rawptr, - userdata2: rawptr, + userdata1: /* NULLABLE */ rawptr, + userdata2: /* NULLABLE */ rawptr, } AdapterInfo :: struct { @@ -894,7 +895,7 @@ BufferBindingLayout :: struct { } BufferDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, usage: BufferUsageFlags, size: u64, @@ -904,12 +905,12 @@ BufferDescriptor :: struct { Color :: [4]f64 CommandBufferDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, } CommandEncoderDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, } @@ -930,7 +931,7 @@ ComputePassTimestampWrites :: struct { } ConstantEntry :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, key: StringView, value: f64, } @@ -987,7 +988,7 @@ Limits :: struct { } MultisampleState :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, count: u32, mask: u32, alphaToCoverageEnabled: b32, @@ -1000,14 +1001,14 @@ Origin3D :: struct { } PipelineLayoutDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, bindGroupLayoutCount: uint, bindGroupLayouts: [^]BindGroupLayout `fmt:"v,bindGroupLayoutCount"`, } PrimitiveState :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, topology: PrimitiveTopology, stripIndexFormat: IndexFormat, frontFace: FrontFace, @@ -1016,27 +1017,27 @@ PrimitiveState :: struct { } QuerySetDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, type: QueryType, count: u32, } QueueDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, } RenderBundleDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, } RenderBundleEncoderDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, colorFormatCount: uint, - colorFormats: [^]TextureFormat `fmt:"v,colorFormatCount"`, + colorFormats: /* const */ [^]TextureFormat `fmt:"v,colorFormatCount"`, depthStencilFormat: TextureFormat, sampleCount: u32, depthReadOnly: b32, @@ -1067,7 +1068,7 @@ RenderPassTimestampWrites :: struct { } RequestAdapterOptions :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, featureLevel: FeatureLevel, powerPreference: PowerPreference, forceFallbackAdapter: b32, @@ -1076,12 +1077,12 @@ RequestAdapterOptions :: struct { } SamplerBindingLayout :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, type: SamplerBindingType, } SamplerDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, addressModeU: AddressMode, addressModeV: AddressMode, @@ -1096,7 +1097,7 @@ SamplerDescriptor :: struct { } ShaderModuleDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, } @@ -1119,7 +1120,7 @@ StencilFaceState :: struct { } StorageTextureBindingLayout :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, access: StorageTextureAccess, format: TextureFormat, viewDimension: TextureViewDimension, @@ -1127,12 +1128,12 @@ StorageTextureBindingLayout :: struct { SupportedFeatures :: struct { featureCount: uint, - features: [^]FeatureName `fmt:"v,featureCount"`, + features: /* const */ [^]FeatureName `fmt:"v,featureCount"`, } SupportedWGSLLanguageFeatures :: struct { featureCount: uint, - features: [^]WGSLLanguageFeatureName `fmt:"v,featureCount"`, + features: /* const */ [^]WGSLLanguageFeatureName `fmt:"v,featureCount"`, } SurfaceCapabilities :: struct { @@ -1147,20 +1148,20 @@ SurfaceCapabilities :: struct { } SurfaceConfiguration :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, device: Device, format: TextureFormat, usage: TextureUsageFlags, width: u32, height: u32, viewFormatCount: uint, - viewFormats: [^]TextureFormat `fmt:"v,viewFormatCount"`, + viewFormats: /* const */ [^]TextureFormat `fmt:"v,viewFormatCount"`, alphaMode: CompositeAlphaMode, presentMode: PresentMode, } SurfaceDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, } @@ -1204,7 +1205,7 @@ SurfaceSourceXlibWindow :: struct { } SurfaceTexture :: struct { - nextInChain: ^ChainedStruct, + nextInChain: ^ChainedStructOut, texture: Texture, status: SurfaceGetCurrentTextureStatus, } @@ -1216,14 +1217,14 @@ TexelCopyBufferLayout :: struct { } TextureBindingLayout :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, sampleType: TextureSampleType, viewDimension: TextureViewDimension, multisampled: b32, } TextureViewDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, format: TextureFormat, dimension: TextureViewDimension, @@ -1242,15 +1243,15 @@ VertexAttribute :: struct { } BindGroupDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, layout: BindGroupLayout, entryCount: uint, - entries: [^]BindGroupEntry `fmt:"v,entryCount"`, + entries: /* const */ [^]BindGroupEntry `fmt:"v,entryCount"`, } BindGroupLayoutEntry :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, binding: u32, visibility: ShaderStageFlags, buffer: BufferBindingLayout, @@ -1265,19 +1266,19 @@ BlendState :: struct { } CompilationInfo :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, messageCount: uint, - messages: [^]CompilationMessage `fmt:"v,messageCount"`, + messages: /* const */ [^]CompilationMessage `fmt:"v,messageCount"`, } ComputePassDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, /* NULLABLE */ timestampWrites: /* const */ ^ComputePassTimestampWrites, } DepthStencilState :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, format: TextureFormat, depthWriteEnabled: OptionalBool, depthCompare: CompareFunction, @@ -1291,10 +1292,10 @@ DepthStencilState :: struct { } DeviceDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, requiredFeatureCount: uint, - requiredFeatures: [^]FeatureName `fmt:"v,requiredFeatureCount"`, + requiredFeatures: /* const */ [^]FeatureName `fmt:"v,requiredFeatureCount"`, /* NULLABLE */ requiredLimits: /* const */ ^Limits, defaultQueue: QueueDescriptor, deviceLostCallbackInfo: DeviceLostCallbackInfo, @@ -1307,12 +1308,12 @@ FutureWaitInfo :: struct { } InstanceDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, features: InstanceCapabilities, } ProgrammableStageDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, module: ShaderModule, entryPoint: StringView, constantCount: uint, @@ -1320,7 +1321,7 @@ ProgrammableStageDescriptor :: struct { } RenderPassColorAttachment :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, /* NULLABLE */ view: TextureView, depthSlice: u32, /* NULLABLE */ resolveTarget: TextureView, @@ -1342,7 +1343,7 @@ TexelCopyTextureInfo :: struct { } TextureDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, usage: TextureUsageFlags, dimension: TextureDimension, @@ -1351,21 +1352,21 @@ TextureDescriptor :: struct { mipLevelCount: u32, sampleCount: u32, viewFormatCount: uint, - viewFormats: [^]TextureFormat `fmt:"v,viewFormatCount"`, + viewFormats: /* const */ [^]TextureFormat `fmt:"v,viewFormatCount"`, } VertexBufferLayout :: struct { stepMode: VertexStepMode, arrayStride: u64, attributeCount: uint, - attributes: [^]VertexAttribute `fmt:"v,attributeCount"`, + attributes: /* const */ [^]VertexAttribute `fmt:"v,attributeCount"`, } BindGroupLayoutDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, entryCount: uint, - entries: [^]BindGroupLayoutEntry `fmt:"v,entryCount"`, + entries: /* const */ [^]BindGroupLayoutEntry `fmt:"v,entryCount"`, } ColorTargetState :: struct { @@ -1376,44 +1377,44 @@ ColorTargetState :: struct { } ComputePipelineDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, /* NULLABLE */ layout: PipelineLayout, compute: ProgrammableStageDescriptor, } RenderPassDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, colorAttachmentCount: uint, - colorAttachments: [^]RenderPassColorAttachment `fmt:"v,colorAttachmentCount"`, + colorAttachments: /* const */ [^]RenderPassColorAttachment `fmt:"v,colorAttachmentCount"`, /* NULLABLE */ depthStencilAttachment: /* const */ ^RenderPassDepthStencilAttachment, /* NULLABLE */ occlusionQuerySet: QuerySet, /* NULLABLE */ timestampWrites: /* const */ ^RenderPassTimestampWrites, } VertexState :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, module: ShaderModule, entryPoint: StringView, constantCount: uint, - constants: [^]ConstantEntry `fmt:"v,constantCount"`, + constants: /* const */ [^]ConstantEntry `fmt:"v,constantCount"`, bufferCount: uint, - buffers: [^]VertexBufferLayout `fmt:"v,bufferCount"`, + buffers: /* const */ [^]VertexBufferLayout `fmt:"v,bufferCount"`, } FragmentState :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, module: ShaderModule, entryPoint: StringView, constantCount: uint, - constants: [^]ConstantEntry `fmt:"v,constantCount"`, + constants: /* const */ [^]ConstantEntry `fmt:"v,constantCount"`, targetCount: uint, - targets: [^]ColorTargetState `fmt:"v,targetCount"`, + targets: /* const */ [^]ColorTargetState `fmt:"v,targetCount"`, } RenderPipelineDescriptor :: struct { - nextInChain: ^ChainedStruct, + nextInChain: /* const */ ^ChainedStruct, label: StringView, /* NULLABLE */ layout: PipelineLayout, vertex: VertexState, @@ -1453,7 +1454,7 @@ foreign libwgpu { // Methods of BindGroupLayout BindGroupLayoutSetLabel :: proc(bindGroupLayout: BindGroupLayout, label: cstring) --- - BindGroupLayoutReference :: proc(bindGroupLayout: BindGroupLayout) --- + BindGroupLayoutAddRef :: proc(bindGroupLayout: BindGroupLayout) --- BindGroupLayoutRelease :: proc(bindGroupLayout: BindGroupLayout) --- // Methods of Buffer @@ -1465,7 +1466,7 @@ foreign libwgpu { RawBufferGetMappedRange :: proc(buffer: Buffer, offset: uint, size: uint) -> rawptr --- BufferGetSize :: proc(buffer: Buffer) -> u64 --- BufferGetUsage :: proc(buffer: Buffer) -> BufferUsageFlags --- - BufferMapAsync :: proc(buffer: Buffer, mode: MapModeFlags, offset: uint, size: uint, callback: BufferMapCallbackInfo) -> Future --- + BufferMapAsync :: proc(buffer: Buffer, mode: MapModeFlags, offset: uint, size: uint, callbackInfo: BufferMapCallbackInfo) -> Future --- BufferSetLabel :: proc(buffer: Buffer, label: StringView) --- BufferUnmap :: proc(buffer: Buffer) --- BufferAddRef :: proc(buffer: Buffer) --- @@ -1502,7 +1503,7 @@ foreign libwgpu { ComputePassEncoderPopDebugGroup :: proc(computePassEncoder: ComputePassEncoder) --- ComputePassEncoderPushDebugGroup :: proc(computePassEncoder: ComputePassEncoder, groupLabel: StringView) --- @(link_name="wgpuComputePassEncoderSetBindGroup") - RawComputePassEncoderSetBindGroup :: proc(computePassEncoder: ComputePassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: [^]u32) --- + RawComputePassEncoderSetBindGroup :: proc(computePassEncoder: ComputePassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: /* const */ [^]u32) --- ComputePassEncoderSetLabel :: proc(computePassEncoder: ComputePassEncoder, label: StringView) --- ComputePassEncoderSetPipeline :: proc(computePassEncoder: ComputePassEncoder, pipeline: ComputePipeline) --- ComputePassEncoderAddRef :: proc(computePassEncoder: ComputePassEncoder) --- @@ -1573,7 +1574,7 @@ foreign libwgpu { QueueOnSubmittedWorkDone :: proc(queue: Queue, callbackInfo: QueueWorkDoneCallbackInfo) -> Future --- QueueSetLabel :: proc(queue: Queue, label: StringView) --- @(link_name="wgpuQueueSubmit") - RawQueueSubmit :: proc(queue: Queue, commandCount: uint, commands: [^]CommandBuffer) --- + RawQueueSubmit :: proc(queue: Queue, commandCount: uint, commands: /* const */ [^]CommandBuffer) --- QueueWriteBuffer :: proc(queue: Queue, buffer: Buffer, bufferOffset: u64, data: /* const */ rawptr, size: uint) --- QueueWriteTexture :: proc(queue: Queue, destination: /* const */ ^TexelCopyTextureInfo, data: /* const */ rawptr, dataSize: uint, dataLayout: /* const */ ^TexelCopyBufferLayout, writeSize: /* const */ ^Extent3D) --- QueueAddRef :: proc(queue: Queue) --- @@ -1594,7 +1595,7 @@ foreign libwgpu { RenderBundleEncoderPopDebugGroup :: proc(renderBundleEncoder: RenderBundleEncoder) --- RenderBundleEncoderPushDebugGroup :: proc(renderBundleEncoder: RenderBundleEncoder, groupLabel: StringView) --- @(link_name="wgpuRenderBundleEncoderSetBindGroup") - RawRenderBundleEncoderSetBindGroup :: proc(renderBundleEncoder: RenderBundleEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: [^]u32) --- + RawRenderBundleEncoderSetBindGroup :: proc(renderBundleEncoder: RenderBundleEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: /* const */ [^]u32) --- RenderBundleEncoderSetIndexBuffer :: proc(renderBundleEncoder: RenderBundleEncoder, buffer: Buffer, format: IndexFormat, offset: u64, size: u64) --- RenderBundleEncoderSetLabel :: proc(renderBundleEncoder: RenderBundleEncoder, label: StringView) --- RenderBundleEncoderSetPipeline :: proc(renderBundleEncoder: RenderBundleEncoder, pipeline: RenderPipeline) --- @@ -1611,12 +1612,12 @@ foreign libwgpu { RenderPassEncoderEnd :: proc(renderPassEncoder: RenderPassEncoder) --- RenderPassEncoderEndOcclusionQuery :: proc(renderPassEncoder: RenderPassEncoder) --- @(link_name="wgpuRenderPassEncoderExecuteBundles") - RawRenderPassEncoderExecuteBundles :: proc(renderPassEncoder: RenderPassEncoder, bundleCount: uint, bundles: [^]RenderBundle) --- + RawRenderPassEncoderExecuteBundles :: proc(renderPassEncoder: RenderPassEncoder, bundleCount: uint, bundles: /* const */ [^]RenderBundle) --- RenderPassEncoderInsertDebugMarker :: proc(renderPassEncoder: RenderPassEncoder, markerLabel: StringView) --- RenderPassEncoderPopDebugGroup :: proc(renderPassEncoder: RenderPassEncoder) --- RenderPassEncoderPushDebugGroup :: proc(renderPassEncoder: RenderPassEncoder, groupLabel: StringView) --- @(link_name="wgpuRenderPassEncoderSetBindGroup") - RawRenderPassEncoderSetBindGroup :: proc(renderPassEncoder: RenderPassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: [^]u32) --- + RawRenderPassEncoderSetBindGroup :: proc(renderPassEncoder: RenderPassEncoder, groupIndex: u32, /* NULLABLE */ group: BindGroup, dynamicOffsetCount: uint, dynamicOffsets: /* const */ [^]u32) --- RenderPassEncoderSetBlendConstant :: proc(renderPassEncoder: RenderPassEncoder, color: /* const */ ^Color) --- RenderPassEncoderSetIndexBuffer :: proc(renderPassEncoder: RenderPassEncoder, buffer: Buffer, format: IndexFormat, offset: u64, size: u64) --- RenderPassEncoderSetLabel :: proc(renderPassEncoder: RenderPassEncoder, label: StringView) --- @@ -1853,8 +1854,8 @@ RenderPassEncoderSetBindGroup :: proc "c" (renderPassEncoder: RenderPassEncoder, // Wrappers of Surface -SurfaceGetCapabilities :: proc "c" (surface: Surface, adapter: Adapter) -> (capabilities: SurfaceCapabilities) { - RawSurfaceGetCapabilities(surface, adapter, &capabilities) +SurfaceGetCapabilities :: proc "c" (surface: Surface, adapter: Adapter) -> (capabilities: SurfaceCapabilities, status: Status) { + status = RawSurfaceGetCapabilities(surface, adapter, &capabilities) return } diff --git a/vendor/wgpu/wgpu_js.odin b/vendor/wgpu/wgpu_js.odin index 3c8375adb..3217a97dc 100644 --- a/vendor/wgpu/wgpu_js.odin +++ b/vendor/wgpu/wgpu_js.odin @@ -5,7 +5,7 @@ import "base:runtime" g_context: runtime.Context @(private="file", init) -wgpu_init_allocator :: proc() { +wgpu_init_allocator :: proc "contextless" () { if g_context.allocator.procedure == nil { g_context = runtime.default_context() } diff --git a/vendor/wgpu/wgpu_native.odin b/vendor/wgpu/wgpu_native.odin index def095e07..c58a8c90e 100644 --- a/vendor/wgpu/wgpu_native.odin +++ b/vendor/wgpu/wgpu_native.odin @@ -12,7 +12,7 @@ foreign libwgpu { RawQueueSubmitForIndex :: proc(queue: Queue, commandCount: uint, commands: [^]CommandBuffer) -> SubmissionIndex --- // Returns true if the queue is empty, or false if there are more queue submissions still in flight. - DevicePoll :: proc(device: Device, wait: b32, /* NULLABLE */ wrappedSubmissionIndex: /* const */ ^SubmissionIndex = nil) -> b32 --- + DevicePoll :: proc(device: Device, wait: b32, /* NULLABLE */ submissionIndex: /* const */ ^SubmissionIndex = nil) -> b32 --- DeviceCreateShaderModuleSpirV :: proc(device: Device, descriptor: ^ShaderModuleDescriptorSpirV) -> ShaderModule --- SetLogCallback :: proc(callback: LogCallback, userdata: rawptr) --- diff --git a/vendor/wgpu/wgpu_native_types.odin b/vendor/wgpu/wgpu_native_types.odin index 378b6591c..a9340affe 100644 --- a/vendor/wgpu/wgpu_native_types.odin +++ b/vendor/wgpu/wgpu_native_types.odin @@ -2,8 +2,8 @@ package wgpu import "base:runtime" -BINDINGS_VERSION :: [4]u8{24, 0, 0, 2} -BINDINGS_VERSION_STRING :: "24.0.0.2" +BINDINGS_VERSION :: [4]u8{25, 0, 2, 1} +BINDINGS_VERSION_STRING :: "25.0.2.1" LogLevel :: enum i32 { Off, @@ -56,14 +56,32 @@ PipelineStatisticName :: enum i32 { ComputeShaderInvocations, } +DxcMaxShaderModel :: enum i32 { + V6_0, + V6_1, + V6_2, + V6_3, + V6_4, + V6_5, + V6_6, + V6_7, +} + +GLFenceBehaviour :: enum i32 { + Normal, + AutoFinish, +} + InstanceExtras :: struct { using chain: ChainedStruct, backends: InstanceBackendFlags, flags: InstanceFlags, dx12ShaderCompiler: Dx12Compiler, gles3MinorVersion: Gles3MinorVersion, + glFenceBehaviour: GLFenceBehaviour, dxilPath: StringView, dxcPath: StringView, + dcxMaxShaderModel: DxcMaxShaderModel, } DeviceExtras :: struct { @@ -72,7 +90,7 @@ DeviceExtras :: struct { } NativeLimits :: struct { - chain: ChainedStructOut, + using chain: ChainedStructOut, maxPushConstantSize: u32, maxNonSamplerBindings: u32, } @@ -96,18 +114,18 @@ ShaderDefine :: struct { value: StringView, } -ShaderModuleGLSLDescriptor :: struct { +ShaderSourceGLSL :: struct { using chain: ChainedStruct, stage: ShaderStage, code: StringView, defineCount: uint, - defines: [^]ShaderDefine `fmt:"v,defineCount"`, + defines: /* const */ [^]ShaderDefine `fmt:"v,defineCount"`, } ShaderModuleDescriptorSpirV :: struct { label: StringView, sourceSize: u32, - source: [^]u32 `fmt:"v,sourceSize"`, + source: /* const */ [^]u32 `fmt:"v,sourceSize"`, } RegistryReport :: struct { @@ -170,7 +188,7 @@ QuerySetDescriptorExtras :: struct { SurfaceConfigurationExtras :: struct { using chain: ChainedStruct, - desiredMaximumFrameLatency: i32, + desiredMaximumFrameLatency: u32, } LogCallback :: #type proc "c" (level: LogLevel, message: StringView, userdata: rawptr) diff --git a/vendor/windows/GameInput/windows_game_input.odin b/vendor/windows/GameInput/windows_game_input.odin index f4e7a4e3c..5a47d47ef 100644 --- a/vendor/windows/GameInput/windows_game_input.odin +++ b/vendor/windows/GameInput/windows_game_input.odin @@ -7,15 +7,115 @@ */ package windows_game_input -foreign import wgi { - "system:gameinput.lib", +foreign import wgi "system:gameinput.lib" + +import win "core:sys/windows" + +HRESULT :: win.HRESULT +HANDLE :: win.HANDLE +IUnknown :: win.IUnknown +IUnknown_VTable :: win.IUnknown_VTable +IID :: win.IID + +APP_LOCAL_DEVICE_ID :: distinct [32]byte + +Kind :: distinct bit_set[KindFlag; u32] +KindFlag :: enum u32 { + RawDeviceReport = 0, + ControllerAxis = 1, + ControllerButton = 2, + ControllerSwitch = 3, + Keyboard = 4, + Mouse = 5, + Touch = 8, + Motion = 12, + ArcadeStick = 16, + FlightStick = 17, + Gamepad = 18, + RacingWheel = 19, + UiNavigation = 20, +} +KindUnknown :: Kind{} +KindController :: Kind{ .ControllerAxis, .ControllerButton, .ControllerSwitch } + +EnumerationKind :: enum i32 { + NoEnumeration = 0, + AsyncEnumeration = 1, + BlockingEnumeration = 2, } -import "core:c" -import "core:sys/windows" +FocusPolicy :: distinct bit_set[FocusPolicyFlag; u32] +FocusPolicyFlag :: enum u32 { + DisableBackgroundInput = 0, + ExclusiveForegroundInput = 1, + DisableBackgroundGuideButton = 2, + ExclusiveForegroundGuideButton = 3, + DisableBackgroundShareButton = 4, + ExclusiveForegroundShareButton = 5, +} +DefaultFocusPolicy :: FocusPolicy{} -// Enums -ArcadeStickButtonsFlag :: enum c.int { +SwitchKind :: enum i32 { + UnknownSwitchKind = -1, + TwoWaySwitch = 0, + FourWaySwitch = 1, + EightWaySwitch = 2, +} + +SwitchPosition :: enum i32 { + Center = 0, + Up = 1, + UpRight = 2, + Right = 3, + DownRight = 4, + Down = 5, + DownLeft = 6, + Left = 7, + UpLeft = 8, +} + +KeyboardKind :: enum i32 { + UnknownKeyboard = -1, + AnsiKeyboard = 0, + IsoKeyboard = 1, + KsKeyboard = 2, + AbntKeyboard = 3, + JisKeyboard = 4, +} + +MouseButtons :: distinct bit_set[MouseButtonsFlag; u32] +MouseButtonsFlag :: enum u32 { + LeftButton = 0, + RightButton = 1, + MiddleButton = 2, + Button4 = 3, + Button5 = 4, + WheelTiltLeft = 5, + WheelTiltRight = 6, +} +MouseNone :: MouseButtons{} + +TouchShape :: enum i32 { + Unknown = -1, + Point = 0, + Linear1D = 1, + Radial1D = 2, + Irregular1D = 3, + Rectangular2D = 4, + Elliptical2D = 5, + Irregular2D = 6, +} + +MotionAccuracy :: enum i32 { + AccuracyUnknown = -1, + Unavailable = 0, + Unreliable = 1, + Approximate = 2, + Accurate = 3, +} + +ArcadeStickButtons :: distinct bit_set[ArcadeStickButtonsFlag; u32] +ArcadeStickButtonsFlag :: enum u32 { Menu = 0, View = 1, Up = 2, @@ -31,104 +131,19 @@ ArcadeStickButtonsFlag :: enum c.int { Special1 = 12, Special2 = 13, } -ArcadeStickButtons :: distinct bit_set[ArcadeStickButtonsFlag; c.int] +ArcadeStickNone :: ArcadeStickButtons{} -BatteryStatus :: enum c.int { - Unknown = -1, - NotPresent = 0, - Discharging = 1, - Idle = 2, - Charging = 3, +FlightStickButtons :: distinct bit_set[FlightStickButtonsFlag; u32] +FlightStickButtonsFlag :: enum u32 { + Menu = 0, + View = 1, + FirePrimary = 2, + FireSecondary = 3, } +FlightStickNone :: FlightStickButtons{} -DeviceCapabilitiesFlag :: enum c.int { - Audio = 0, - PluginModule = 1, - PowerOff = 2, - Synchronization = 3, - Wireless = 4, -} -DeviceCapabilities :: distinct bit_set[DeviceCapabilitiesFlag; c.int] - -DeviceFamily :: enum c.int { - Virtual = -1, - Aggregate = 0, - XboxOne = 1, - Xbox360 = 2, - Hid = 3, - I8042 = 4, -} - -DeviceStatusFlag :: enum c.int { - Connected = 0, - InputEnabled = 1, - OutputEnabled = 2, - RawIoEnabled = 3, - AudioCapture = 4, - AudioRender = 5, - Synchronized = 6, - Wireless = 7, - UserIdle = 20, -} -DeviceStatus :: distinct bit_set[DeviceStatusFlag; c.int] - -EnumerationKind :: enum c.int { - NoEnumeration = 0, - AsyncEnumeration = 1, - BlockingEnumeration = 2, -} - -FeedbackAxesFlag :: enum c.int { - LinearX = 0, - LinearY = 1, - LinearZ = 2, - AngularX = 3, - AngularY = 4, - AngularZ = 5, - Normal = 6, -} -FeedbackAxes :: distinct bit_set[FeedbackAxesFlag; c.int] - -FeedbackEffectState :: enum c.int { - Stopped = 0, - Running = 1, - Paused = 2, -} - -FlightStickButtonsFlag :: enum c.int { - None = 0, - Menu = 1, - View = 2, - FirePrimary = 3, - FireSecondary = 4, -} -FlightStickButtons :: distinct bit_set[FlightStickButtonsFlag; c.int] - -FocusPolicyFlag :: enum c.int { - DisableBackgroundInput = 0, - ExclusiveForegroundInput = 1, - DisableBackgroundGuideButton = 2, - ExclusiveForegroundGuideButton = 3, - DisableBackgroundShareButton = 4, - ExclusiveForegroundShareButton = 5, -} -FocusPolicy :: distinct bit_set[FocusPolicyFlag; c.int] - -ForceFeedbackEffectKind :: enum c.int { - Constant = 0, - Ramp = 1, - SineWave = 2, - SquareWave = 3, - TriangleWave = 4, - SawtoothUpWave = 5, - SawtoothDownWave = 6, - Spring = 7, - Friction = 8, - Damper = 9, - Inertia = 10, -} - -GamepadButtonsFlag :: enum c.int { +GamepadButtons :: distinct bit_set[GamepadButtonsFlag; u32] +GamepadButtonsFlag :: enum u32 { Menu = 0, View = 1, A = 2, @@ -144,36 +159,156 @@ GamepadButtonsFlag :: enum c.int { LeftThumbstick = 12, RightThumbstick = 13, } -GamepadButtons :: distinct bit_set[GamepadButtonsFlag; c.int] +GamepadNone :: GamepadButtons{} -KeyboardKind :: enum c.int { - UnknownKeyboard = -1, - AnsiKeyboard = 0, - IsoKeyboard = 1, - KsKeyboard = 2, - AbntKeyboard = 3, - JisKeyboard = 4, +RacingWheelButtons :: distinct bit_set[RacingWheelButtonsFlag; u32] +RacingWheelButtonsFlag :: enum u32 { + Menu = 0, + View = 1, + PreviousGear = 2, + NextGear = 3, + DpadUp = 4, + DpadDown = 5, + DpadLeft = 6, + DpadRight = 7, +} +RacingWheelNone :: RacingWheelButtons{} + +UiNavigationButtons :: distinct bit_set[UiNavigationButtonsFlag; u32] +UiNavigationButtonsFlag :: enum u32 { + Menu = 0, + View = 1, + Accept = 2, + Cancel = 3, + Up = 4, + Down = 5, + Left = 6, + Right = 7, + Context1 = 8, + Context2 = 9, + Context3 = 10, + Context4 = 11, + PageUp = 12, + PageDown = 13, + PageLeft = 14, + PageRight = 15, + ScrollUp = 16, + ScrollDown = 17, + ScrollLeft = 18, + ScrollRight = 19, +} +UiNavigationNone :: UiNavigationButtons{} + +SystemButtons :: distinct bit_set[SystemButtonsFlag; u32] +SystemButtonsFlag :: enum u32 { + Guide = 0, + Share = 1, +} +SystemButtonNone :: SystemButtons{} + +DeviceStatus :: distinct bit_set[DeviceStatusFlag; u32] +DeviceStatusFlag :: enum u32 { + Connected = 0, + InputEnabled = 1, + OutputEnabled = 2, + RawIoEnabled = 3, + AudioCapture = 4, + AudioRender = 5, + Synchronized = 6, + Wireless = 7, + UserIdle = 20, +} +DeviceNoStatus :: DeviceStatus{} +//DeviceAnyStatus :: 0x00FFFFFF + +BatteryStatus :: enum i32 { + Unknown = -1, + NotPresent = 0, + Discharging = 1, + Idle = 2, + Charging = 3, } -KindFlag :: enum c.int { - RawDeviceReport = 0, - ControllerAxis = 1, - ControllerButton = 2, - ControllerSwitch = 3, - Keyboard = 4, - Mouse = 5, - Touch = 8, - Motion = 12, - ArcadeStick = 16, - FlightStick = 17, - Gamepad = 18, - RacingWheel = 19, - UiNavigation = 20, +DeviceFamily :: enum i32 { + Virtual = -1, + Aggregate = 0, + XboxOne = 1, + Xbox360 = 2, + Hid = 3, + I8042 = 4, } -Kind :: distinct bit_set[KindFlag; c.int] -Kind_Controller : Kind : { .ControllerAxis, .ControllerButton, .ControllerSwitch } -Label :: enum c.int { +DeviceCapabilities :: distinct bit_set[DeviceCapabilitiesFlag; u32] +DeviceCapabilitiesFlag :: enum u32 { + Audio = 0, + PluginModule = 1, + PowerOff = 2, + Synchronization = 3, + Wireless = 4, +} +DeviceCapabilityNone :: DeviceCapabilities{} + +RawDeviceReportKind :: enum i32 { + InputReport = 0, + OutputReport = 1, + FeatureReport = 2, +} + +RawDeviceReportItemFlags :: distinct bit_set[RawDeviceReportItemFlag; u32] +RawDeviceReportItemFlag :: enum u32 { + ConstantItem = 0, + ArrayItem = 1, + RelativeItem = 2, + WraparoundItem = 3, + NonlinearItem = 4, + StableItem = 5, + NullableItem = 6, + VolatileItem = 7, + BufferedItem = 8, +} +RawDeviceDefaultItem :: RawDeviceReportItemFlags{} + +RawDeviceItemCollectionKind :: enum i32 { + UnknownItemCollection = -1, + PhysicalItemCollection = 0, + ApplicationItemCollection = 1, + LogicalItemCollection = 2, + ReportItemCollection = 3, + NamedArrayItemCollection = 4, + UsageSwitchItemCollection = 5, + UsageModifierItemCollection = 6, +} + +RawDevicePhysicalUnitKind :: enum i32 { + Unknown = -1, + None = 0, + Time = 1, + Frequency = 2, + Length = 3, + Velocity = 4, + Acceleration = 5, + Mass = 6, + Momentum = 7, + Force = 8, + Pressure = 9, + Angle = 10, + AngularVelocity = 11, + AngularAcceleration = 12, + AngularMass = 13, + AngularMomentum = 14, + AngularTorque = 15, + ElectricCurrent = 16, + ElectricCharge = 17, + ElectricPotential = 18, + Energy = 19, + Power = 20, + Temperature = 21, + LuminousIntensity = 22, + LuminousFlux = 23, + Illuminance = 24, +} + +Label :: enum i32 { Unknown = -1, None = 0, XboxGuide = 1, @@ -301,7 +436,7 @@ Label :: enum c.int { P4 = 124, } -Location :: enum c.int { +Location :: enum i32 { Unknown = -1, Chassis = 0, Display = 1, @@ -312,189 +447,142 @@ Location :: enum c.int { TouchPad = 6, } -MotionAccuracy :: enum c.int { - AccuracyUnknown = -1, - Unavailable = 0, - Unreliable = 1, - Approximate = 2, - Accurate = 3, +FeedbackAxes :: distinct bit_set[FeedbackAxesFlag; u32] +FeedbackAxesFlag :: enum u32 { + LinearX = 0, + LinearY = 1, + LinearZ = 2, + AngularX = 3, + AngularY = 4, + AngularZ = 5, + Normal = 6, +} +FeedbackAxisNone :: FeedbackAxes{} + +FeedbackEffectState :: enum i32 { + Stopped = 0, + Running = 1, + Paused = 2, } -MouseButtonsFlag :: enum c.int { - LeftButton = 0, - RightButton = 1, - MiddleButton = 2, - Button4 = 3, - Button5 = 4, - WheelTiltLeft = 5, - WheelTiltRight = 6, -} -MouseButtons :: distinct bit_set[MouseButtonsFlag; c.int] - -RacingWheelButtonsFlag :: enum c.int { - Menu = 0, - View = 1, - PreviousGear = 2, - NextGear = 3, - DpadUp = 4, - DpadDown = 5, - DpadLeft = 6, - DpadRight = 7, -} -RacingWheelButtons :: distinct bit_set[RacingWheelButtonsFlag; c.int] - -RawDeviceItemCollectionKind :: enum c.int { - UnknownItemCollection = -1, - PhysicalItemCollection = 0, - ApplicationItemCollection = 1, - LogicalItemCollection = 2, - ReportItemCollection = 3, - NamedArrayItemCollection = 4, - UsageSwitchItemCollection = 5, - UsageModifierItemCollection = 6, +ForceFeedbackEffectKind :: enum i32 { + Constant = 0, + Ramp = 1, + SineWave = 2, + SquareWave = 3, + TriangleWave = 4, + SawtoothUpWave = 5, + SawtoothDownWave = 6, + Spring = 7, + Friction = 8, + Damper = 9, + Inertia = 10, } -RawDevicePhysicalUnitKind :: enum c.int { - Unknown = -1, - None = 0, - Time = 1, - Frequency = 2, - Length = 3, - Velocity = 4, - Acceleration = 5, - Mass = 6, - Momentum = 7, - Force = 8, - Pressure = 9, - Angle = 10, - AngularVelocity = 11, - AngularAcceleration = 12, - AngularMass = 13, - AngularMomentum = 14, - AngularTorque = 15, - ElectricCurrent = 16, - ElectricCharge = 17, - ElectricPotential = 18, - Energy = 19, - Power = 20, - Temperature = 21, - LuminousIntensity = 22, - LuminousFlux = 23, - Illuminance = 24, -} - -RawDeviceReportItemFlag :: enum c.int { - ConstantItem = 0, - ArrayItem = 1, - RelativeItem = 2, - WraparoundItem = 3, - NonlinearItem = 4, - StableItem = 5, - NullableItem = 6, - VolatileItem = 7, - BufferedItem = 8, -} -RawDeviceReportItemFlags :: distinct bit_set[RawDeviceReportItemFlag; c.int] - -RawDeviceReportKind :: enum c.int { - InputReport = 0, - OutputReport = 1, - FeatureReport = 2, -} - -RumbleMotorsFlag :: enum c.int { +RumbleMotors :: distinct bit_set[RumbleMotorsFlag; u32] +RumbleMotorsFlag :: enum u32 { LowFrequency = 0, HighFrequency = 1, LeftTrigger = 2, RightTrigger = 3, } -RumbleMotors :: distinct bit_set[RumbleMotorsFlag; c.int] +RumbleNone :: RumbleMotors{} -SwitchKind :: enum c.int { - UnknownSwitchKind = -1, - TwoWaySwitch = 0, - FourWaySwitch = 1, - EightWaySwitch = 2, +CallbackToken :: distinct u64 + +CURRENT_CALLBACK_TOKEN_VALUE :: CallbackToken(0xFFFFFFFFFFFFFFFF) +INVALID_CALLBACK_TOKEN_VALUE :: CallbackToken(0x0000000000000000) + +ReadingCallback :: #type proc "stdcall" (callbackToken: CallbackToken, ctx: rawptr, reading: ^IGameInputReading, hasOverrunOccured: bool) +DeviceCallback :: #type proc "stdcall" (callbackToken: CallbackToken, ctx: rawptr, device: ^IGameInputDevice, timestamp: u64, currentStatus: DeviceStatus, previousStatus: DeviceStatus) +SystemButtonCallback :: #type proc "stdcall" (callbackToken: CallbackToken, ctx: rawptr, device: ^IGameInputDevice, timestamp: u64, currentButtons: SystemButtons, previousButtons: SystemButtons) +KeyboardLayoutCallback :: #type proc "stdcall" (callbackToken: CallbackToken, ctx: rawptr, device: ^IGameInputDevice, timestamp: u64, currentLayout: u32, previousLayout: u32) + +KeyState :: struct { + scanCode: u32, + codePoint: u32, + virtualKey: u8, + isDeadKey: bool, } -SwitchPosition :: enum c.int { - Center = 0, - Up = 1, - UpRight = 2, - Right = 3, - DownRight = 4, - Down = 5, - DownLeft = 6, - Left = 7, - UpLeft = 8, +MouseState :: struct { + buttons: MouseButtons, + positionX: i64, + positionY: i64, + wheelX: i64, + wheelY: i64, } -SystemButtonsFlag :: enum c.int { - Guide = 0, - Share = 1 , -} -SystemButtons :: distinct bit_set[SystemButtonsFlag; c.int] - -TouchShape :: enum c.int { - Unknown = -1, - Point = 0, - Shape1DLinear = 1, - Shape1DRadial = 2, - Shape1DIrregular = 3, - Shape2DRectangular = 4, - Shape2DElliptical = 5, - Shape2DIrregular = 6, +TouchState :: struct { + touchId: u64, + sensorIndex: u32, + positionX: f32, + positionY: f32, + pressure: f32, + proximity: f32, + contactRectTop: f32, + contactRectLeft: f32, + contactRectRight: f32, + contactRectBottom: f32, } -UiNavigationButtonsFlag :: enum c.int { - Menu = 0, - View = 1, - Accept = 2, - Cancel = 3, - Up = 4, - Down = 5, - Left = 6, - Right = 7, - Context1 = 8, - Context2 = 9, - Context3 = 10, - Context4 = 11, - PageUp = 12, - PageDown = 13, - PageLeft = 14, - PageRight = 15, - ScrollUp = 16, - ScrollDown = 17, - ScrollLeft = 18, - ScrollRight = 19, -} -UiNavigationButtons :: distinct bit_set[UiNavigationButtonsFlag; c.int] - -// Structs - -APP_LOCAL_DEVICE_ID :: distinct [32]byte - -ArcadeStickInfo :: struct { - menuButtonLabel: Label, - viewButtonLabel: Label, - stickUpLabel: Label, - stickDownLabel: Label, - stickLeftLabel: Label, - stickRightLabel: Label, - actionButton1Label: Label, - actionButton2Label: Label, - actionButton3Label: Label, - actionButton4Label: Label, - actionButton5Label: Label, - actionButton6Label: Label, - specialButton1Label: Label, - specialButton2Label: Label, +MotionState :: struct { + accelerationX: f32, + accelerationY: f32, + accelerationZ: f32, + angularVelocityX: f32, + angularVelocityY: f32, + angularVelocityZ: f32, + magneticFieldX: f32, + magneticFieldY: f32, + magneticFieldZ: f32, + orientationW: f32, + orientationX: f32, + orientationY: f32, + orientationZ: f32, + accelerometerAccuracy: MotionAccuracy, + gyroscopeAccuracy: MotionAccuracy, + magnetometerAccuracy: MotionAccuracy, + orientationAccuracy: MotionAccuracy, } ArcadeStickState :: struct { buttons: ArcadeStickButtons, } +FlightStickState :: struct { + buttons: FlightStickButtons, + hatSwitch: SwitchPosition, + roll: f32, + pitch: f32, + yaw: f32, + throttle: f32, +} + +GamepadState :: struct { + buttons: GamepadButtons, + leftTrigger: f32, + rightTrigger: f32, + leftThumbstickX: f32, + leftThumbstickY: f32, + rightThumbstickX: f32, + rightThumbstickY: f32, +} + +RacingWheelState :: struct { + buttons: RacingWheelButtons, + patternShifterGear: i32, + wheel: f32, + throttle: f32, + brake: f32, + clutch: f32, + handbrake: f32, +} + +UiNavigationState :: struct { + buttons: UiNavigationButtons, +} + BatteryState :: struct { chargeRate: f32, maxChargeRate: f32, @@ -503,6 +591,64 @@ BatteryState :: struct { status: BatteryStatus, } +String :: struct { + sizeInBytes: u32, + codePointCount: u32, + data: [^]byte, +} + +Usage :: struct { + page: u16, + id: u16, +} + +Version :: struct { + major: u16, + minor: u16, + build: u16, + revision: u16, +} + +RawDeviceItemCollectionInfo :: struct { + kind: RawDeviceItemCollectionKind, + childCount: u32, + siblingCount: u32, + usageCount: u32, + usages: [^]Usage `fmt:"v,usageCount"`, + parent: ^RawDeviceItemCollectionInfo, + firstSibling: ^RawDeviceItemCollectionInfo, + previousSibling: ^RawDeviceItemCollectionInfo, + nextSibling: ^RawDeviceItemCollectionInfo, + lastSibling: ^RawDeviceItemCollectionInfo, + firstChild: ^RawDeviceItemCollectionInfo, + lastChild: ^RawDeviceItemCollectionInfo, +} + +RawDeviceReportItemInfo :: struct { + bitOffset: u32, + bitSize: u32, + logicalMin: i64, + logicalMax: i64, + physicalMin: f64, + physicalMax: f64, + physicalUnits: RawDevicePhysicalUnitKind, + rawPhysicalUnits: u32, + rawPhysicalUnitsExponent: i32, + flags: RawDeviceReportItemFlags, + usageCount: u32, + usages: [^]Usage `fmt:"v,usageCount"`, + collection: ^RawDeviceItemCollectionInfo, + itemString: ^String, +} + +RawDeviceReportInfo :: struct { + kind: RawDeviceReportKind, + id: u32, + size: u32, + itemCount: u32, + items: [^]RawDeviceReportItemInfo `fmt:"v,itemCount"`, +} + ControllerAxisInfo :: struct { mappedInputKinds: Kind, label: Label, @@ -541,6 +687,166 @@ ControllerSwitchInfo :: struct { inputReportItem: ^RawDeviceReportItemInfo, } +KeyboardInfo :: struct { + kind: KeyboardKind, + layout: u32, + keyCount: u32, + functionKeyCount: u32, + maxSimultaneousKeys: u32, + platformType: u32, + platformSubtype: u32, + nativeLanguage: ^String, +} + +MouseInfo :: struct { + supportedButtons: MouseButtons, + sampleRate: u32, + sensorDpi: u32, + hasWheelX: bool, + hasWheelY: bool, +} + +TouchSensorInfo :: struct { + mappedInputKinds: Kind, + label: Label, + location: Location, + locationId: u32, + resolutionX: u64, + resolutionY: u64, + shape: TouchShape, + aspectRatio: f32, + orientation: f32, + physicalWidth: f32, + physicalHeight: f32, + maxPressure: f32, + maxProximity: f32, + maxTouchPoints: u32, +} + +MotionInfo :: struct { + maxAcceleration: f32, + maxAngularVelocity: f32, + maxMagneticFieldStrength: f32, +} + +ArcadeStickInfo :: struct { + menuButtonLabel: Label, + viewButtonLabel: Label, + stickUpLabel: Label, + stickDownLabel: Label, + stickLeftLabel: Label, + stickRightLabel: Label, + actionButton1Label: Label, + actionButton2Label: Label, + actionButton3Label: Label, + actionButton4Label: Label, + actionButton5Label: Label, + actionButton6Label: Label, + specialButton1Label: Label, + specialButton2Label: Label, +} + +FlightStickInfo :: struct { + menuButtonLabel: Label, + viewButtonLabel: Label, + firePrimaryButtonLabel: Label, + fireSecondaryButtonLabel: Label, + hatSwitchKind: SwitchKind, +} + +GamepadInfo :: struct { + menuButtonLabel: Label, + viewButtonLabel: Label, + aButtonLabel: Label, + bButtonLabel: Label, + xButtonLabel: Label, + yButtonLabel: Label, + dpadUpLabel: Label, + dpadDownLabel: Label, + dpadLeftLabel: Label, + dpadRightLabel: Label, + leftShoulderButtonLabel: Label, + rightShoulderButtonLabel: Label, + leftThumbstickButtonLabel: Label, + rightThumbstickButtonLabel: Label, +} + +RacingWheelInfo :: struct { + menuButtonLabel: Label, + viewButtonLabel: Label, + previousGearButtonLabel: Label, + nextGearButtonLabel: Label, + dpadUpLabel: Label, + dpadDownLabel: Label, + dpadLeftLabel: Label, + dpadRightLabel: Label, + hasClutch: bool, + hasHandbrake: bool, + hasPatternShifter: bool, + minPatternShifterGear: i32, + maxPatternShifterGear: i32, + maxWheelAngle: f32, +} + +UiNavigationInfo :: struct { + menuButtonLabel: Label, + viewButtonLabel: Label, + acceptButtonLabel: Label, + cancelButtonLabel: Label, + upButtonLabel: Label, + downButtonLabel: Label, + leftButtonLabel: Label, + rightButtonLabel: Label, + contextButton1Label: Label, + contextButton2Label: Label, + contextButton3Label: Label, + contextButton4Label: Label, + pageUpButtonLabel: Label, + pageDownButtonLabel: Label, + pageLeftButtonLabel: Label, + pageRightButtonLabel: Label, + scrollUpButtonLabel: Label, + scrollDownButtonLabel: Label, + scrollLeftButtonLabel: Label, + scrollRightButtonLabel: Label, + guideButtonLabel: Label, +} + +ForceFeedbackMotorInfo :: struct { + supportedAxes: FeedbackAxes, + location: Location, + locationId: u32, + maxSimultaneousEffects: u32, + isConstantEffectSupported: bool, + isRampEffectSupported: bool, + isSineWaveEffectSupported: bool, + isSquareWaveEffectSupported: bool, + isTriangleWaveEffectSupported: bool, + isSawtoothUpWaveEffectSupported: bool, + isSawtoothDownWaveEffectSupported: bool, + isSpringEffectSupported: bool, + isFrictionEffectSupported: bool, + isDamperEffectSupported: bool, + isInertiaEffectSupported: bool, +} + +HapticWaveformInfo :: struct { + usage: Usage, + isDurationSupported: bool, + isIntensitySupported: bool, + isRepeatSupported: bool, + isRepeatDelaySupported: bool, + defaultDuration: u64, +} + +HapticFeedbackMotorInfo :: struct { + mappedRumbleMotor: RumbleMotors, + location: Location, + locationId: u32, + waveformCount: u32, + waveformInfo: [^]HapticWaveformInfo `fmt:"v,waveformCount"`, +} + DeviceInfo :: struct { infoSize: u32, vendorId: u16, @@ -569,60 +875,28 @@ DeviceInfo :: struct { hapticFeedbackMotorCount: u32, deviceStringCount: u32, deviceDescriptorSize: u32, - inputReportInfo: ^RawDeviceReportInfo, - outputReportInfo: ^RawDeviceReportInfo, - featureReportInfo: ^RawDeviceReportInfo, - controllerAxisInfo: ^ControllerAxisInfo, - controllerButtonInfo: ^ControllerButtonInfo, - controllerSwitchInfo: ^ControllerSwitchInfo, + inputReportInfo: [^]RawDeviceReportInfo `fmt:"v,inputReportCount"`, + outputReportInfo: [^]RawDeviceReportInfo `fmt:"v,outputReportCount"`, + featureReportInfo: [^]RawDeviceReportInfo `fmt:"v,featureReportCount"`, + controllerAxisInfo: [^]ControllerAxisInfo `fmt:"v,controllerAxisCount"`, + controllerButtonInfo: [^]ControllerButtonInfo `fmt:"v,controllerButtonCount"`, + controllerSwitchInfo: [^]ControllerSwitchInfo `fmt:"v,controllerSwitchCount"`, keyboardInfo: ^KeyboardInfo, mouseInfo: ^MouseInfo, - touchSensorInfo: ^TouchSensorInfo, + touchSensorInfo: [^]TouchSensorInfo `fmt:"v,touchSensorCount"`, motionInfo: ^MotionInfo, arcadeStickInfo: ^ArcadeStickInfo, flightStickInfo: ^FlightStickInfo, gamepadInfo: ^GamepadInfo, racingWheelInfo: ^RacingWheelInfo, uiNavigationInfo: ^UiNavigationInfo, - forceFeedbackMotorInfo: ^ForceFeedbackMotorInfo, - hapticFeedbackMotorInfo: ^HapticFeedbackMotorInfo, + forceFeedbackMotorInfo: [^]ForceFeedbackMotorInfo `fmt:"v,forceFeedbackMotorCount"`, + hapticFeedbackMotorInfo: [^]HapticFeedbackMotorInfo `fmt:"v,hapticFeedbackMotorCount"`, displayName: ^String, - deviceStrings: ^String, + deviceStrings: [^]String `fmt:"v,deviceStringCount"`, deviceDescriptorData: rawptr, } -FlightStickInfo :: struct { - menuButtonLabel: Label, - viewButtonLabel: Label, - firePrimaryButtonLabel: Label, - fireSecondaryButtonLabel: Label, - hatSwitchKind: SwitchKind, -} - -FlightStickState :: struct { - buttons: FlightStickButtons, - hatSwitch: SwitchPosition, - roll: f32, - pitch: f32, - yaw: f32, - throttle: f32, -} - -ForceFeedbackConditionParams :: struct { - magnitude: ForceFeedbackMagnitude, - positiveCoefficient: f32, - negativeCoefficient: f32, - maxPositiveMagnitude: f32, - maxNegativeMagnitude: f32, - deadZone: f32, - bias: f32, -} - -ForceFeedbackConstantParams :: struct { - envelope: ForceFeedbackEnvelope, - magnitude: ForceFeedbackMagnitude, -} - ForceFeedbackEnvelope :: struct { attackDuration: u64, sustainDuration: u64, @@ -644,39 +918,19 @@ ForceFeedbackMagnitude :: struct { normal: f32, } -ForceFeedbackMotorInfo :: struct { - supportedAxes: FeedbackAxes, - location: Location, - locationId: u32, - maxSimultaneousEffects: u32, - isConstantEffectSupported: bool, - isRampEffectSupported: bool, - isSineWaveEffectSupported: bool, - isSquareWaveEffectSupported: bool, - isTriangleWaveEffectSupported: bool, - isSawtoothUpWaveEffectSupported: bool, - isSawtoothDownWaveEffectSupported: bool, - isSpringEffectSupported: bool, - isFrictionEffectSupported: bool, - isDamperEffectSupported: bool, - isInertiaEffectSupported: bool, +ForceFeedbackConditionParams :: struct { + magnitude: ForceFeedbackMagnitude, + positiveCoefficient: f32, + negativeCoefficient: f32, + maxPositiveMagnitude: f32, + maxNegativeMagnitude: f32, + deadZone: f32, + bias: f32, } -ForceFeedbackParams :: struct { - kind: ForceFeedbackEffectKind, - using _: struct #raw_union { - constant: ForceFeedbackConstantParams, - ramp: ForceFeedbackRampParams, - sineWave: ForceFeedbackPeriodicParams, - squareWave: ForceFeedbackPeriodicParams, - triangleWave: ForceFeedbackPeriodicParams, - sawtoothUpWave: ForceFeedbackPeriodicParams, - sawtoothDownWave: ForceFeedbackPeriodicParams, - spring: ForceFeedbackConditionParams, - friction: ForceFeedbackConditionParams, - damper: ForceFeedbackConditionParams, - inertia: ForceFeedbackConditionParams, - }, +ForceFeedbackConstantParams :: struct { + envelope: ForceFeedbackEnvelope, + magnitude: ForceFeedbackMagnitude, } ForceFeedbackPeriodicParams :: struct { @@ -693,39 +947,21 @@ ForceFeedbackRampParams :: struct { endMagnitude: ForceFeedbackMagnitude, } -GamepadInfo :: struct { - menuButtonLabel: Label, - viewButtonLabel: Label, - aButtonLabel: Label, - bButtonLabel: Label, - xButtonLabel: Label, - yButtonLabel: Label, - dpadUpLabel: Label, - dpadDownLabel: Label, - dpadLeftLabel: Label, - dpadRightLabel: Label, - leftShoulderButtonLabel: Label, - rightShoulderButtonLabel: Label, - leftThumbstickButtonLabel: Label, - rightThumbstickButtonLabel: Label, -} - -GamepadState :: struct { - buttons: GamepadButtons, - leftTrigger: f32, - rightTrigger: f32, - leftThumbstickX: f32, - leftThumbstickY: f32, - rightThumbstickX: f32, - rightThumbstickY: f32, -} - -HapticFeedbackMotorInfo :: struct { - mappedRumbleMotor: RumbleMotors, - location: Location, - locationId: u32, - waveformCount: u32, - waveformInfo: [^]HapticWaveformInfo `fmt:"v,waveformCount"`, +ForceFeedbackParams :: struct { + kind: ForceFeedbackEffectKind, + using data: struct #raw_union { + constant: ForceFeedbackConstantParams, + ramp: ForceFeedbackRampParams, + sineWave: ForceFeedbackPeriodicParams, + squareWave: ForceFeedbackPeriodicParams, + triangleWave: ForceFeedbackPeriodicParams, + sawtoothUpWave: ForceFeedbackPeriodicParams, + sawtoothDownWave: ForceFeedbackPeriodicParams, + spring: ForceFeedbackConditionParams, + friction: ForceFeedbackConditionParams, + damper: ForceFeedbackConditionParams, + inertia: ForceFeedbackConditionParams, + }, } HapticFeedbackParams :: struct { @@ -736,142 +972,6 @@ HapticFeedbackParams :: struct { repeatDelay: u64, } -HapticWaveformInfo :: struct { - usage: Usage, - isDurationSupported: bool, - isIntensitySupported: bool, - isRepeatSupported: bool, - isRepeatDelaySupported: bool, - defaultDuration: u64, -} - -KeyboardInfo :: struct { - kind: KeyboardKind, - layout: u32, - keyCount: u32, - functionKeyCount: u32, - maxSimultaneousKeys: u32, - platformType: u32, - platformSubtype: u32, - nativeLanguage: ^String, -} - -KeyState :: struct { - scanCode: u32, - codePoint: u32, - virtualKey: u8, - isDeadKey: bool, -} - -MotionInfo :: struct { - maxAcceleration: f32, - maxAngularVelocity: f32, - maxMagneticFieldStrength: f32, -} - -MotionState :: struct { - accelerationX: f32, - accelerationY: f32, - accelerationZ: f32, - angularVelocityX: f32, - angularVelocityY: f32, - angularVelocityZ: f32, - magneticFieldX: f32, - magneticFieldY: f32, - magneticFieldZ: f32, - orientationW: f32, - orientationX: f32, - orientationY: f32, - orientationZ: f32, - accelerometerAccuracy: MotionAccuracy, - gyroscopeAccuracy: MotionAccuracy, - magnetometerAccuracy: MotionAccuracy, - orientationAccuracy: MotionAccuracy, -} - -MouseInfo :: struct { - supportedButtons: MouseButtons, - sampleRate: u32, - sensorDpi: u32, - hasWheelX: bool, - hasWheelY: bool, -} - -MouseState :: struct { - buttons: MouseButtons, - positionX: i64, - positionY: i64, - wheelX: i64, - wheelY: i64, -} - -RacingWheelInfo :: struct { - menuButtonLabel: Label, - viewButtonLabel: Label, - previousGearButtonLabel: Label, - nextGearButtonLabel: Label, - dpadUpLabel: Label, - dpadDownLabel: Label, - dpadLeftLabel: Label, - dpadRightLabel: Label, - hasClutch: bool, - hasHandbrake: bool, - hasPatternShifter: bool, - minPatternShifterGear: i32, - maxPatternShifterGear: i32, - maxWheelAngle: f32, -} - -RacingWheelState :: struct { - buttons: RacingWheelButtons, - patternShifterGear: i32, - wheel: f32, - throttle: f32, - brake: f32, - clutch: f32, - handbrake: f32, -} - -RawDeviceItemCollectionInfo :: struct { - kind: RawDeviceItemCollectionKind, - childCount: u32, - siblingCount: u32, - usageCount: u32, - usages: [^]Usage `fmt:v,usageCount`, - parent: ^RawDeviceItemCollectionInfo, - firstSibling: ^RawDeviceItemCollectionInfo, - previousSibling: ^RawDeviceItemCollectionInfo, - nextSibling: ^RawDeviceItemCollectionInfo, - lastSibling: ^RawDeviceItemCollectionInfo, - firstChild: ^RawDeviceItemCollectionInfo, - lastChild: ^RawDeviceItemCollectionInfo, -} - -RawDeviceReportInfo :: struct { - kind: RawDeviceReportKind, - id: u32, - size: u32, - itemCount: u32, - items: [^]RawDeviceReportItemInfo `fmt:"v,itemCount"`, -} - -RawDeviceReportItemInfo :: struct { - bitOffset: u32, - bitSize: u32, - logicalMin: i64, - logicalMax: i64, - physicalMin: f64, - physicalMax: f64, - physicalUnits: RawDevicePhysicalUnitKind, - rawPhysicalUnits: u32, - rawPhysicalUnitsExponent: i32, - flags: RawDeviceReportItemFlags, - usageCount: u32, - usages: [^]Usage `fmt:"v,usageCount"`, - collection: ^RawDeviceItemCollectionInfo, - itemString: ^String, -} - RumbleParams :: struct { lowFrequency: f32, highFrequency: f32, @@ -879,88 +979,6 @@ RumbleParams :: struct { rightTrigger: f32, } -String :: struct { - sizeInBytes: u32, - codePointCount: u32, - data: [^]byte, -} - -TouchSensorInfo :: struct { - mappedInputKinds: Kind, - label: Label, - location: Location, - locationId: u32, - resolutionX: u64, - resolutionY: u64, - shape: TouchShape, - aspectRatio: f32, - orientation: f32, - physicalWidth: f32, - physicalHeight: f32, - maxPressure: f32, - maxProximity: f32, - maxTouchPoints: u32, -} - -TouchState :: struct { - touchId: u64, - sensorIndex: u32, - positionX: f32, - positionY: f32, - pressure: f32, - proximity: f32, - contactRectTop: f32, - contactRectLeft: f32, - contactRectRight: f32, - contactRectBottom: f32, -} - -UiNavigationInfo :: struct { - menuButtonLabel: Label, - viewButtonLabel: Label, - acceptButtonLabel: Label, - cancelButtonLabel: Label, - upButtonLabel: Label, - downButtonLabel: Label, - leftButtonLabel: Label, - rightButtonLabel: Label, - contextButton1Label: Label, - contextButton2Label: Label, - contextButton3Label: Label, - contextButton4Label: Label, - pageUpButtonLabel: Label, - pageDownButtonLabel: Label, - pageLeftButtonLabel: Label, - pageRightButtonLabel: Label, - scrollUpButtonLabel: Label, - scrollDownButtonLabel: Label, - scrollLeftButtonLabel: Label, - scrollRightButtonLabel: Label, - guideButtonLabel: Label, -} - -UiNavigationState :: struct { - buttons: UiNavigationButtons, -} - -Usage :: struct { - page: u16, - id: u16, -} - -Version :: struct { - major: u16, - minor: u16, - build: u16, - revision: u16, -} - -// COM Interfaces - -IUnknown :: windows.IUnknown -IUnknown_VTable :: windows.IUnknown_VTable -IID :: windows.GUID - IGameInput_UUID_STRING :: "11BE2A7E-4254-445A-9C09-FFC40F006918" IGameInput_UUID := &IID{0x11BE2A7E, 0x4254, 0x445A, {0x9C, 0x09, 0xFF, 0xC4, 0x0F, 0x00, 0x69, 0x18}} IGameInput :: struct #raw_union { @@ -985,7 +1003,7 @@ IGameInput_VTable :: struct { FindDeviceFromId: proc "system" (this: ^IGameInput, value: ^APP_LOCAL_DEVICE_ID, device: ^^IGameInputDevice) -> HRESULT, FindDeviceFromObject: proc "system" (this: ^IGameInput, value: ^IUnknown, device: ^^IGameInputDevice) -> HRESULT, FindDeviceFromPlatformHandle: proc "system" (this: ^IGameInput, value: HANDLE, device: ^^IGameInputDevice) -> HRESULT, - FindDeviceFromPlatformString: proc "system" (this: ^IGameInput, value: windows.LPCWSTR, device: ^^IGameInputDevice) -> HRESULT, + FindDeviceFromPlatformString: proc "system" (this: ^IGameInput, value: win.LPCWSTR, device: ^^IGameInputDevice) -> HRESULT, EnableOemDeviceSupport: proc "system" (this: ^IGameInput, vendorId: u16, productId: u16, interfaceNumber: u8, collectionNumber: u8) -> HRESULT, SetFocusPolicy: proc "system" (this: ^IGameInput, policy: FocusPolicy), } @@ -999,7 +1017,7 @@ IGameInputReading :: struct #raw_union { IGameInputReading_VTable :: struct { using iunknown_vtable: IUnknown_VTable, GetInputKind: proc "system" (this: ^IGameInputReading) -> Kind, - GetSequenceNumber: proc "system" (this: ^IGameInputReading) -> u64, + GetSequenceNumber: proc "system" (this: ^IGameInputReading, inputKind: Kind) -> u64, GetTimestamp: proc "system" (this: ^IGameInputReading) -> u64, GetDevice: proc "system" (this: ^IGameInputReading, device: ^^IGameInputDevice), GetRawReport: proc "system" (this: ^IGameInputReading, report: ^^IGameInputRawDeviceReport) -> bool, @@ -1046,7 +1064,7 @@ IGameInputDevice_Vtable :: struct { SetRawDeviceFeature: proc "system" (this: ^IGameInputDevice, report: ^IGameInputRawDeviceReport) -> HRESULT, SendRawDeviceOutput: proc "system" (this: ^IGameInputDevice, report: ^IGameInputRawDeviceReport) -> HRESULT, SendRawDeviceOutputWithResponse: proc "system" (this: ^IGameInputDevice, requestReport: ^IGameInputRawDeviceReport, responseReport: ^^IGameInputRawDeviceReport) -> HRESULT, - ExecuteRawDeviceIoControl: proc "system" (this: ^IGameInputDevice, controlCode: u32, inputBufferSize: c.size_t, inputBuffer: rawptr, outputBufferSize: c.size_t, outputBuffer: rawptr, outputSize: ^c.size_t) -> HRESULT, + ExecuteRawDeviceIoControl: proc "system" (this: ^IGameInputDevice, controlCode: u32, inputBufferSize: win.SIZE_T, inputBuffer: rawptr, outputBufferSize: win.SIZE_T, outputBuffer: rawptr, outputSize: ^win.SIZE_T) -> HRESULT, AcquireExclusiveRawDeviceAccess: proc "system" (this: ^IGameInputDevice, timeoutInMicroseconds: u64) -> bool, ReleaseExclusiveRawDeviceAccess: proc "system" (this: ^IGameInputDevice), } @@ -1091,18 +1109,19 @@ IGameInputRawDeviceReport_Vtable :: struct { using iunknown_vtable: IUnknown_VTable, GetDevice: proc "system" (this: ^IGameInputRawDeviceReport, device: ^^IGameInputDevice), GetReportInfo: proc "system" (this: ^IGameInputRawDeviceReport) -> ^RawDeviceReportInfo, - GetRawDataSize: proc "system" (this: ^IGameInputRawDeviceReport) -> c.size_t, - GetRawData: proc "system" (this: ^IGameInputRawDeviceReport, bufferSize: c.size_t, buffer: rawptr) -> c.size_t, - SetRawData: proc "system" (this: ^IGameInputRawDeviceReport, bufferSize: c.size_t, buffer: rawptr) -> bool, + GetRawDataSize: proc "system" (this: ^IGameInputRawDeviceReport) -> win.SIZE_T, + GetRawData: proc "system" (this: ^IGameInputRawDeviceReport, bufferSize: win.SIZE_T, buffer: rawptr) -> win.SIZE_T, + SetRawData: proc "system" (this: ^IGameInputRawDeviceReport, bufferSize: win.SIZE_T, buffer: rawptr) -> bool, GetItemValue: proc "system" (this: ^IGameInputRawDeviceReport, itemIndex: u32, value: ^u64) -> bool, SetItemValue: proc "system" (this: ^IGameInputRawDeviceReport, itemIndex: u32, value: u64) -> bool, ResetItemValue: proc "system" (this: ^IGameInputRawDeviceReport, itemIndex: u32) -> bool, ResetAllItems: proc "system" (this: ^IGameInputRawDeviceReport) -> bool, } -// Functions -HRESULT :: windows.HRESULT -HANDLE :: windows.HANDLE +@(default_calling_convention="system", link_prefix="GameInput") +foreign wgi { + Create :: proc(gameInput: ^^IGameInput) -> HRESULT --- +} DEVICE_DISCONNECTED :: HRESULT(-0x7C75FFFF) DEVICE_NOT_FOUND :: HRESULT(-0x7C75FFFE) @@ -1110,20 +1129,3 @@ READING_NOT_FOUND :: HRESULT(-0x7C75FFFD) REFERENCE_READING_TOO_OLD :: HRESULT(-0x7C75FFFC) TIMESTAMP_OUT_OF_RANGE :: HRESULT(-0x7C75FFFB) INSUFFICIENT_FORCE_FEEDBACK_RESOURCES :: HRESULT(-0x7C75FFFA) - -CallbackToken :: distinct u64 - -CURRENT_CALLBACK_TOKEN_VALUE :: CallbackToken(0xFFFFFFFFFFFFFFFF) -INVALID_CALLBACK_TOKEN_VALUE :: CallbackToken(0x0000000000000000) - -@(default_calling_convention="system", link_prefix="GameInput") -foreign wgi { - Create :: proc(gameInput: ^^IGameInput) -> HRESULT --- -} - -DeviceCallback :: #type proc "system" (callbackToken: CallbackToken, ctx: rawptr, device: ^IGameInputDevice, timestamp: u64, currentState: DeviceStatus, previousState: DeviceStatus) -GuideButtonCallback :: #type proc "system" (callbackToken: CallbackToken, ctx: rawptr, device: ^IGameInputDevice, timestamp: u64, isPressed: bool) -SystemButtonCallback :: #type proc "system" (callbackToken: CallbackToken, ctx: rawptr, device: ^IGameInputDevice, timestamp: u64, currentState: DeviceStatus, previousState: DeviceStatus) -ReadingCallback :: #type proc "system" (callbackToken: CallbackToken, ctx: rawptr, reading: ^IGameInputReading, hasOverrunOccured: bool) -KeyboardLayoutCallback :: #type proc "system" (callbackToken: CallbackToken, ctx: rawptr, device: ^IGameInputDevice, timestamp: u64, currentState: DeviceStatus, previousState: DeviceStatus) - diff --git a/vendor/windows/XAudio2/hrtfapoapi.odin b/vendor/windows/XAudio2/hrtfapoapi.odin new file mode 100644 index 000000000..45f1cdb42 --- /dev/null +++ b/vendor/windows/XAudio2/hrtfapoapi.odin @@ -0,0 +1,149 @@ +#+build windows + +package windows_xaudio2 + +import win "core:sys/windows" + +foreign import hrtf "system:hrtfapo.lib" + +HRTF_MAX_GAIN_LIMIT :: 12.0 +HRTF_MIN_GAIN_LIMIT :: -96.0 +HRTF_MIN_UNITY_GAIN_DISTANCE :: 0.05 +HRTF_DEFAULT_UNITY_GAIN_DISTANCE :: 1.0 +HRTF_DEFAULT_CUTOFF_DISTANCE :: 3.402823466e+38 + +//! Represents a position in 3D space, using a right-handed coordinate system. +HrtfPosition :: struct { + x: f32, + y: f32, + z: f32, +} + +//! Indicates the orientation of an HRTF directivity object. This is a row-major 3x3 rotation matrix. +HrtfOrientation :: struct { + element: [9]f32, +} + +//! Indicates one of several stock directivity patterns. +HrtfDirectivityType :: enum i32 { + //! The sound emission is in all directions. + OmniDirectional = 0, + //! The sound emission is a cardiod shape. + Cardioid, + //! The sound emission is a cone. + Cone, +} + +//! Indicates one of several stock environment types. +HrtfEnvironment :: enum i32 { + //! A small room. + Small = 0, + //! A medium-sized room. + Medium, + //! A large enclosed space. + Large, + //! An outdoor space. + Outdoors, +} + +//! Base directivity pattern descriptor. Describes the type of directivity applied to a sound. +//! The scaling parameter is used to interpolate between directivity behavior and omnidirectional, it determines how much attenuation is applied to the source outside of the directivity pattern and controls how directional the source is. +HrtfDirectivity :: struct { + //! Indicates the type of directivity. + type: HrtfDirectivityType, + //! A normalized value between zero and one. Specifies the amount of linear interpolation between omnidirectional sound and the full directivity pattern, where 0 is fully omnidirectional and 1 is fully directional. + scaling: f32, +} + +//! Describes a cardioid directivity pattern. +HrtfDirectivityCardioid :: struct { + //! Descriptor for the cardioid pattern. The type parameter must be set to HrtfDirectivityType.Cardioid. + directivity: HrtfDirectivity, + //! Order controls the shape of the cardioid. The higher order the shape, the narrower it is. Must be greater than 0 and less than or equal to 32. + order: f32, +} + +//! Describes a cone directivity. +//! Attenuation is 0 inside the inner cone. +//! Attenuation is linearly interpolated between the inner cone, which is defined by innerAngle, and the outer cone, which is defined by outerAngle. +HrtfDirectivityCone :: struct { + //! Descriptor for the cone pattern. The type parameter must be set to HrtfDirectivityType.Cone. + directivity: HrtfDirectivity, + //! Angle, in radians, that defines the inner cone. Must be between 0 and TAU. + innerAngle: f32, + //! Angle, in radians, that defines the outer cone. Must be between 0 and TAU. + outerAngle: f32, +} + +//! Indicates a distance-based decay type applied to a sound. +HrtfDistanceDecayType :: enum i32 { + //! Simulates natural decay with distance, as constrained by minimum and maximum gain distance limits. Drops to silence at rolloff distance. + NaturalDecay = 0, + //! Used to set up a custom gain curve, within the maximum and minimum gain limit. + CustomDecay, +} + +//! Describes a distance-based decay behavior. +HrtfDistanceDecay :: struct { + //! The type of decay behavior, natural or custom. + type: HrtfDistanceDecayType, + //! The maximum gain limit applied at any distance. Applies to both natural and custom decay. This value is specified in dB, with a range from -96 to 12 inclusive. The default value is 12 dB. + maxGain: f32, + //! The minimum gain limit applied at any distance. Applies to both natural and custom decay. This value is specified in dB, with a range from -96 to 12 inclusive. The default value is -96 dB. + minGain: f32, + //! The distance at which the gain is 0dB. Applies to natural decay only. This value is specified in meters, with a range from 0.05 to infinity (max(f32)). The default value is 1 meter. + unityGainDistance: f32, + //! The distance at which output is silent. Applies to natural decay only. This value is specified in meters, with a range from zero (non-inclusive) to infinity (max(f32)). The default value is infinity. + cutoffDistance: f32, +} + +//! Specifies parameters used to initialize HRTF. +//! Instances of the XAPO interface are created by using the CreateHrtfApo() API: +//! ```CreateHrtfApo :: proc(pInit: HrtfApoInit, ppXapo: ^^IXAPO) -> HRESULT``` +HrtfApoInit :: struct { + //! The decay type. If you pass in nil, the default value will be used. The default is natural decay. + distanceDecay: ^HrtfDistanceDecay, + //! The directivity type. If you pass in nil, the default value will be used. The default directivity is omni-directional. + directivity: ^HrtfDirectivity, +} + +//! Creates an instance of the XAPO object. +//! Format requirements: +//! * Input: mono, 48 kHz, 32-bit float PCM. +//! * Output: stereo, 48 kHz, 32-bit float PCM. +//! Audio is processed in blocks of 1024 samples. +//! Returns: +//! S_OK for success, any other value indicates failure. +//! Returns E_NOTIMPL on unsupported platforms. +@(default_calling_convention="system") +foreign hrtf { + CreateHrtfApo :: proc( + //! Pointer to an HrtfApoInit struct. Specifies parameters for XAPO interface initialization. + #by_ptr init: HrtfApoInit, + //! Returns the new instance of the XAPO interface. + xApo: ^^IXAPO, + ) -> HRESULT --- +} + +//! The interface used to set parameters that control how HRTF is applied to a sound. +IXAPOHrtfParameters_UUID_STRING :: "15B3CD66-E9DE-4464-B6E6-2BC3CF63D455" +IXAPOHrtfParameters_UUID := &win.IID{0x15B3CD66, 0xE9DE, 0x4464, {0xB6, 0xE6, 0x2B, 0xC3, 0xCF, 0x63, 0xD4, 0x55}} +IXAPOHrtfParameters :: struct #raw_union { + #subtype iunknown: IUnknown, + using ixapohrtfparameters_vtable: ^IXAPOHrtfParameters_VTable, +} +IXAPOHrtfParameters_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + + // HRTF params + //! The position of the sound relative to the listener. + SetSourcePosition: proc "system" (this: ^IXAPOHrtfParameters, position: ^HrtfPosition) -> HRESULT, + //! The rotation matrix for the source orientation, with respect to the listener's frame of reference (the listener's coordinate system). + SetSourceOrientation: proc "system" (this: ^IXAPOHrtfParameters, orientation: ^HrtfOrientation) -> HRESULT, + //! The custom direct path gain value for the current source position. Valid only for sounds played with the HrtfDistanceDecayType. Custom decay type. + SetSourceGain: proc "system" (this: ^IXAPOHrtfParameters, gain: f32) -> HRESULT, + + // Distance cue params + //! Selects the acoustic environment to simulate. + SetEnvironment: proc "system" (this: ^IXAPOHrtfParameters, environment: HrtfEnvironment) -> HRESULT, +} diff --git a/vendor/windows/XAudio2/x3daudio.odin b/vendor/windows/XAudio2/x3daudio.odin new file mode 100644 index 000000000..c24e627e2 --- /dev/null +++ b/vendor/windows/XAudio2/x3daudio.odin @@ -0,0 +1,210 @@ +#+build windows + +/* NOTES: + 1. Definition of terms: + LFE: Low Frequency Effect -- always omnidirectional. + LPF: Low Pass Filter, divided into two classifications: + Direct -- Applied to the direct signal path, + used for obstruction/occlusion effects. + Reverb -- Applied to the reverb signal path, + used for occlusion effects only. + + 2. Volume level is expressed as a linear amplitude scaler: + 1.0 represents no attenuation applied to the original signal, + 0.5 denotes an attenuation of 6dB, and 0.0 results in silence. + Amplification (volume > 1.0) is also allowed, and is not clamped. + + LPF values range from 1.0 representing all frequencies pass through, + to 0.0 which results in silence as all frequencies are filtered out. + + 3. X3DAudio uses a left-handed Cartesian coordinate system with values + on the x-axis increasing from left to right, on the y-axis from + bottom to top, and on the z-axis from near to far. + Azimuths are measured clockwise from a given reference direction. + + Distance measurement is with respect to user-defined world units. + Applications may provide coordinates using any system of measure + as all non-normalized calculations are scale invariant, with such + operations natively occurring in user-defined world unit space. + Metric constants are supplied only as a convenience. + Distance is calculated using the Euclidean norm formula. + + 4. Only real values are permissible with functions using 32-bit + float parameters -- NAN and infinite values are not accepted. + All computation occurs in 32-bit precision mode. */ + + +package windows_xaudio2 + +import "core:math" +import win "core:sys/windows" + +foreign import xa2 "system:xaudio2.lib" + +SPEAKER_FLAGS :: win.SPEAKER_FLAGS + +//---------------------------------------------------// + +// standard speaker geometry configurations, used with Initialize +SPEAKER_MONO :: SPEAKER_FLAGS{.FRONT_CENTER} +SPEAKER_STEREO :: SPEAKER_FLAGS{.FRONT_LEFT, .FRONT_RIGHT} +SPEAKER_2POINT1 :: SPEAKER_FLAGS{.FRONT_LEFT, .FRONT_RIGHT, .LOW_FREQUENCY} +SPEAKER_SURROUND :: SPEAKER_FLAGS{.FRONT_LEFT, .FRONT_RIGHT, .FRONT_CENTER, .BACK_CENTER} +SPEAKER_QUAD :: SPEAKER_FLAGS{.FRONT_LEFT, .FRONT_RIGHT, .BACK_LEFT, .BACK_RIGHT} +SPEAKER_4POINT1 :: SPEAKER_FLAGS{.FRONT_LEFT, .FRONT_RIGHT, .LOW_FREQUENCY, .BACK_LEFT, .BACK_RIGHT} +SPEAKER_5POINT1 :: SPEAKER_FLAGS{.FRONT_LEFT, .FRONT_RIGHT, .FRONT_CENTER, .LOW_FREQUENCY, .BACK_LEFT, .BACK_RIGHT} +SPEAKER_7POINT1 :: SPEAKER_FLAGS{.FRONT_LEFT, .FRONT_RIGHT, .FRONT_CENTER, .LOW_FREQUENCY, .BACK_LEFT, .BACK_RIGHT, .FRONT_LEFT_OF_CENTER, .FRONT_RIGHT_OF_CENTER} +SPEAKER_5POINT1_SURROUND :: SPEAKER_FLAGS{.FRONT_LEFT, .FRONT_RIGHT, .FRONT_CENTER, .LOW_FREQUENCY, .SIDE_LEFT, .SIDE_RIGHT} +SPEAKER_7POINT1_SURROUND :: SPEAKER_FLAGS{.FRONT_LEFT, .FRONT_RIGHT, .FRONT_CENTER, .LOW_FREQUENCY, .BACK_LEFT, .BACK_RIGHT, .SIDE_LEFT, .SIDE_RIGHT} + +// size of instance handle in bytes +HANDLE_BYTESIZE :: 20 + +// speed of sound in meters per second for dry air at approximately 20C, used with Initialize +SPEED_OF_SOUND :: 343.5 + +// calculation control flags, used with Calculate +CALCULATE_FLAGS :: distinct bit_set[CALCULATE_FLAG; u32] +CALCULATE_FLAG :: enum u32 { + MATRIX = 0, // enable matrix coefficient table calculation + DELAY = 1, // enable delay time array calculation (stereo final mix only) + LPF_DIRECT = 2, // enable LPF direct-path coefficient calculation + LPF_REVERB = 3, // enable LPF reverb-path coefficient calculation + REVERB = 4, // enable reverb send level calculation + DOPPLER = 5, // enable doppler shift factor calculation + EMITTER_ANGLE = 6, // enable emitter-to-listener interior angle calculation + + ZEROCENTER = 16, // do not position to front center speaker, signal positioned to remaining speakers instead, front center destination channel will be zero in returned matrix coefficient table, valid only for matrix calculations with final mix formats that have a front center channel + REDIRECT_TO_LFE = 17, // apply equal mix of all source channels to LFE destination channel, valid only for matrix calculations with sources that have no LFE channel and final mix formats that have an LFE channel +} + +//-----------------------------------------------------// +VECTOR :: distinct [3]f32 // float 3D vector + +// instance handle of precalculated constants +HANDLE :: distinct [HANDLE_BYTESIZE]byte + +// Distance curve point: +// Defines a DSP setting at a given normalized distance. +DISTANCE_CURVE_POINT :: struct #packed { + Distance: f32, // normalized distance, must be within [0.0, 1.0] + DSPSetting: f32, // DSP setting +} + +// Distance curve: +// A piecewise curve made up of linear segments used to define DSP behaviour with respect to normalized distance. +// +// Note that curve point distances are normalized within [0.0, 1.0]. +// EMITTER.CurveDistanceScaler must be used to scale the normalized distances to user-defined world units. +// For distances beyond CurveDistanceScaler * 1.0, pPoints[PointCount-1].DSPSetting is used as the DSP setting. +// +// All distance curve spans must be such that: +// pPoints[k-1].DSPSetting + ((pPoints[k].DSPSetting-pPoints[k-1].DSPSetting) / (pPoints[k].Distance-pPoints[k-1].Distance)) * (pPoints[k].Distance-pPoints[k-1].Distance) != NAN or infinite values +// For all points in the distance curve where 1 <= k < PointCount. +DISTANCE_CURVE :: struct #packed { + pPoints: [^]DISTANCE_CURVE_POINT `fmt:"v,PointCount"`, // distance curve point array, must have at least PointCount elements with no duplicates and be sorted in ascending order with respect to Distance + PointCount: u32, // number of distance curve points, must be >= 2 as all distance curves must have at least two endpoints, defining DSP settings at 0.0 and 1.0 normalized distance +} +Default_LinearCurvePoints := [2]DISTANCE_CURVE_POINT{{0.0, 1.0}, {1.0, 0.0}} +Default_LinearCurve := DISTANCE_CURVE{&Default_LinearCurvePoints[0], 2} + +// Cone: +// Specifies directionality for a listener or single-channel emitter by modifying DSP behaviour with respect to its front orientation. +// This is modeled using two sound cones: an inner cone and an outer cone. On/within the inner cone, DSP settings are scaled by the inner values. +// On/beyond the outer cone, DSP settings are scaled by the outer values. If on both the cones, DSP settings are scaled by the inner values only. +// Between the two cones, the scaler is linearly interpolated between the inner and outer values. Set both cone angles to 0 or TAU for omnidirectionality using only the outer or inner values respectively. +CONE :: struct #packed { + InnerAngle: f32, // inner cone angle in radians, must be within [0.0, TAU] + OuterAngle: f32, // outer cone angle in radians, must be within [InnerAngle, TAU] + + InnerVolume: f32, // volume level scaler on/within inner cone, used only for matrix calculations, must be within [0.0, 2.0] when used + OuterVolume: f32, // volume level scaler on/beyond outer cone, used only for matrix calculations, must be within [0.0, 2.0] when used + InnerLPF: f32, // LPF (both direct and reverb paths) coefficient subtrahend on/within inner cone, used only for LPF (both direct and reverb paths) calculations, must be within [0.0, 1.0] when used + OuterLPF: f32, // LPF (both direct and reverb paths) coefficient subtrahend on/beyond outer cone, used only for LPF (both direct and reverb paths) calculations, must be within [0.0, 1.0] when used + InnerReverb: f32, // reverb send level scaler on/within inner cone, used only for reverb calculations, must be within [0.0, 2.0] when used + OuterReverb: f32, // reverb send level scaler on/beyond outer cone, used only for reverb calculations, must be within [0.0, 2.0] when used +} +Default_DirectionalCone := CONE{math.PI / 2, math.PI, 1.0, 0.708, 0.0, 0.25, 0.708, 1.0} + +// Listener: +// Defines a point of 3D audio reception. +// The cone is directed by the listener's front orientation. +LISTENER :: struct #packed { + OrientFront: VECTOR, // orientation of front direction, used only for matrix and delay calculations or listeners with cones for matrix, LPF (both direct and reverb paths), and reverb calculations, must be normalized when used + OrientTop: VECTOR, // orientation of top direction, used only for matrix and delay calculations, must be orthonormal with OrientFront when used + + Position: VECTOR, // position in user-defined world units, does not affect Velocity + Velocity: VECTOR, // velocity vector in user-defined world units/second, used only for doppler calculations, does not affect Position + + pCone: ^CONE, // sound cone, used only for matrix, LPF (both direct and reverb paths), and reverb calculations, nil specifies omnidirectionality +} + +// Emitter: +// Defines a 3D audio source, divided into two classifications: +// Single-point -- For use with single-channel sounds. +// Positioned at the emitter base, i.e. the channel radius and azimuth are ignored if the number of channels == 1. +// May be omnidirectional or directional using a cone. +// The cone originates from the emitter base position, and is directed by the emitter's front orientation. +// Multi-point -- For use with multi-channel sounds. +// Each non-LFE channel is positioned using an azimuth along the channel radius with respect to the front orientation vector in the plane orthogonal to the top orientation vector. +// An azimuth of TAU specifies a channel is an LFE. Such channels are positioned at the emitter base and are calculated with respect to pLFECurve only, never pVolumeCurve. +// Multi-point emitters are always omnidirectional, i.e. the cone is ignored if the number of channels > 1. +// Note that many properties are shared among all channel points, locking certain behaviour with respect to the emitter base position. +// For example, doppler shift is always calculated with respect to the emitter base position and so is constant for all its channel points. +// Distance curve calculations are also with respect to the emitter base position, with the curves being calculated independently of each other. +// For instance, volume and LFE calculations do not affect one another. +EMITTER :: struct #packed { + pCone: ^CONE, // sound cone, used only with single-channel emitters for matrix, LPF (both direct and reverb paths), and reverb calculations, nil specifies omnidirectionality + + OrientFront: VECTOR, // orientation of front direction, used only for emitter angle calculations or with multi-channel emitters for matrix calculations or single-channel emitters with cones for matrix, LPF (both direct and reverb paths), and reverb calculations, must be normalized when used + OrientTop: VECTOR, // orientation of top direction, used only with multi-channel emitters for matrix calculations, must be orthonormal with OrientFront when used + + Position: VECTOR, // position in user-defined world units, does not affect Velocity + Velocity: VECTOR, // velocity vector in user-defined world units/second, used only for doppler calculations, does not affect Position + + InnerRadius: f32, // inner radius, must be within [0.0, max(f32)] + InnerRadiusAngle: f32, // inner radius angle, must be within [0.0, PI/4.0) + + ChannelCount: u32, // number of sound channels, must be > 0 + ChannelRadius: f32, // channel radius, used only with multi-channel emitters for matrix calculations, must be >= 0.0 when used + pChannelAzimuths: [^]f32 `fmt:"v,ChannelCount"`, // channel azimuth array, used only with multi-channel emitters for matrix calculations, contains positions of each channel expressed in radians along the channel radius with respect to the front orientation vector in the plane orthogonal to the top orientation vector, or TAU to specify an LFE channel, must have at least ChannelCount elements, all within [0.0, TAU] when used + + pVolumeCurve: ^DISTANCE_CURVE, // volume level distance curve, used only for matrix calculations, nil specifies a default curve that conforms to the inverse square law, calculated in user-defined world units with distances <= CurveDistanceScaler clamped to no attenuation + pLFECurve: ^DISTANCE_CURVE, // LFE level distance curve, used only for matrix calculations, nil specifies a default curve that conforms to the inverse square law, calculated in user-defined world units with distances <= CurveDistanceScaler clamped to no attenuation + pLPFDirectCurve: ^DISTANCE_CURVE, // LPF direct-path coefficient distance curve, used only for LPF direct-path calculations, nil specifies the default curve: [0.0,1.0], [1.0,0.75] + pLPFReverbCurve: ^DISTANCE_CURVE, // LPF reverb-path coefficient distance curve, used only for LPF reverb-path calculations, nil specifies the default curve: [0.0,0.75], [1.0,0.75] + pReverbCurve: ^DISTANCE_CURVE, // reverb send level distance curve, used only for reverb calculations, nil specifies the default curve: [0.0,1.0], [1.0,0.0] + + CurveDistanceScaler: f32, // curve distance scaler, used to scale normalized distance curves to user-defined world units and/or exaggerate their effect, used only for matrix, LPF (both direct and reverb paths), and reverb calculations, must be within [min(f32), max(f32)] when used + DopplerScaler: f32, // doppler shift scaler, used to exaggerate doppler shift effect, used only for doppler calculations, must be within [0.0, max(f32)] when used +} + +// DSP settings: +// Receives results from a call to Calculate to be sent to the low-level audio rendering API for 3D signal processing. +// The user is responsible for allocating the matrix coefficient table, delay time array, and initializing the channel counts when used. +DSP_SETTINGS :: struct #packed { + pMatrixCoefficients: [^]f32, // [inout] matrix coefficient table, receives an array representing the volume level used to send from source channel S to destination channel D, stored as pMatrixCoefficients[SrcChannelCount * D + S], must have at least SrcChannelCount*DstChannelCount elements + pDelayTimes: [^]f32, // [inout] delay time array, receives delays for each destination channel in milliseconds, must have at least DstChannelCount elements (stereo final mix only) + SrcChannelCount: u32, // [in] number of source channels, must equal number of channels in respective emitter + DstChannelCount: u32, // [in] number of destination channels, must equal number of channels of the final mix + + LPFDirectCoefficient: f32, // [out] LPF direct-path coefficient + LPFReverbCoefficient: f32, // [out] LPF reverb-path coefficient + ReverbLevel: f32, // [out] reverb send level + DopplerFactor: f32, // [out] doppler shift factor, scales resampler ratio for doppler shift effect, where the effective frequency = DopplerFactor * original frequency + EmitterToListenerAngle: f32, // [out] emitter-to-listener interior angle, expressed in radians with respect to the emitter's front orientation + + EmitterToListenerDistance: f32, // [out] distance in user-defined world units from the emitter base to listener position, always calculated + EmitterVelocityComponent: f32, // [out] component of emitter velocity vector projected onto emitter->listener vector in user-defined world units/second, calculated only for doppler + ListenerVelocityComponent: f32, // [out] component of listener velocity vector projected onto emitter->listener vector in user-defined world units/second, calculated only for doppler +} + +//-------------------------------------------------------// +@(default_calling_convention="cdecl", link_prefix="X3DAudio") +foreign xa2 { + // initializes instance handle + Initialize :: proc(SpeakerChannelMask: SPEAKER_FLAGS, SpeedOfSound: f32, Instance: HANDLE) -> HRESULT --- + + // calculates DSP settings with respect to 3D parameters + Calculate :: proc(Instance: HANDLE, #by_ptr pListener: LISTENER, #by_ptr pEmitter: EMITTER, Flags: CALCULATE_FLAGS, pDSPSettings: ^DSP_SETTINGS) --- +} diff --git a/vendor/windows/XAudio2/xapo.odin b/vendor/windows/XAudio2/xapo.odin new file mode 100644 index 000000000..510eeb514 --- /dev/null +++ b/vendor/windows/XAudio2/xapo.odin @@ -0,0 +1,340 @@ +#+build windows + +/* NOTES: + 1. Definition of terms: + DSP: Digital Signal Processing. + + CBR: Constant BitRate -- DSP that consumes a constant number of input samples to produce an output sample. + For example, a 22kHz to 44kHz resampler is CBR DSP. Even though the number of input to output samples differ, the ratio between input to output rate remains constant. + All user-defined XAPOs are assumed to be CBR as XAudio2 only allows CBR DSP to be added to an effect chain. + + XAPO: Cross-platform Audio Processing Object -- + a thin wrapper that manages DSP code, allowing it to be easily plugged into an XAudio2 effect chain. + + Frame: A block of samples, one per channel, to be played simultaneously. + E.g. a mono stream has one sample per frame. + + In-Place: Processing such that the input buffer equals the output buffer (i.e. input data modified directly). + This form of processing is generally more efficient than using separate memory for input and output. + However, an XAPO may not perform format conversion when processing in-place. + + 2. XAPO member variables are divided into three classifications: + Immutable: Set once via IXAPO.Initialize and remain constant during the lifespan of the XAPO. + + Locked: May change before the XAPO is locked via + IXAPO.LockForProcess but remain constant until IXAPO.UnlockForProcess is called. + + Dynamic: May change from one processing pass to the next, usually via IXAPOParameters.SetParameters. + XAPOs should assign reasonable defaults to their dynamic variables during IXAPO.Initialize/LockForProcess so that calling IXAPOParameters.SetParameters is not required before processing begins. + + When implementing an XAPO, determine the type of each variable and initialize them in the appropriate method. Immutable variables are generally preferable over locked which are preferable over dynamic. + That is, one should strive to minimize XAPO state changes for best performance, maintainability, and ease of use. + + 3. To minimize glitches, the realtime audio processing thread must not block. XAPO methods called by the realtime thread are commented as non-blocking and therefore should not use blocking synchronization, allocate memory, access the disk, etc. + The XAPO interfaces were designed to allow an effect implementer to move such operations into other methods called on an application controlled thread. + + 4. Extending functionality is accomplished through the addition of new COM interfaces. For example, if a new member is added to a parameter structure, a new interface using the new structure should be added, leaving the original interface unchanged. + This ensures consistent communication between future versions of XAudio2 and various versions of XAPOs that may exist in an application. + + 5. All audio data is interleaved in XAudio2. + The default audio format for an effect chain is WAVE_FORMAT_IEEE_FLOAT. + + 6. User-defined XAPOs should assume all input and output buffers are 16-byte aligned. */ + +package windows_xaudio2 + +import win "core:sys/windows" + +//---------------------------------------------------// + +FORMAT_UNSUPPORTED := win.MAKE_HRESULT(win.SEVERITY.ERROR, win.FACILITY.XAPO, 0x01) // requested audio format unsupported + +// supported number of channels (samples per frame) range +XAPO_MIN_CHANNELS :: 1 +XAPO_MAX_CHANNELS :: 64 + +// supported framerate range +XAPO_MIN_FRAMERATE :: 1000 +XAPO_MAX_FRAMERATE :: 200000 + +// unicode string length, including terminator, used with XAPO_REGISTRATION_PROPERTIES +XAPO_REGISTRATION_STRING_LENGTH :: 256 + + +// XAPO property flags, used with XAPO_REGISTRATION_PROPERTIES.Flags: +XAPO_FLAGS :: distinct bit_set[XAPO_FLAG; u32] +XAPO_FLAG :: enum u32 { + // Number of channels of input and output buffers must match, applies to XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.pFormat. + CHANNELS_MUST_MATCH = 0, + + // Framerate of input and output buffers must match, applies to XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.pFormat. + FRAMERATE_MUST_MATCH = 1, + + // Bit depth of input and output buffers must match, applies to XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.pFormat. + // Container size of input and output buffers must also match if XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.pFormat is WAVEFORMATEXTENSIBLE. + BITSPERSAMPLE_MUST_MATCH = 2, + + // Number of input and output buffers must match, applies to XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS. + // Also, XAPO_REGISTRATION_PROPERTIES.MinInputBufferCount must equal XAPO_REGISTRATION_PROPERTIES.MinOutputBufferCount and XAPO_REGISTRATION_PROPERTIES.MaxInputBufferCount must equal XAPO_REGISTRATION_PROPERTIES.MaxOutputBufferCount when used. + BUFFERCOUNT_MUST_MATCH = 3, + + // XAPO must be run in-place. Use this flag only if your DSP implementation cannot process separate input and output buffers. + // If set, the following flags must also be set: + // CHANNELS_MUST_MATCH + // FRAMERATE_MUST_MATCH + // BITSPERSAMPLE_MUST_MATCH + // BUFFERCOUNT_MUST_MATCH + // INPLACE_SUPPORTED + // Multiple input and output buffers may be used with in-place XAPOs, though the input buffer count must equal the output buffer count. + // When multiple input/output buffers are used, the XAPO may assume input buffer [N] equals output buffer [N] for in-place processing. + INPLACE_REQUIRED = 5, + + // XAPO may be run in-place. If the XAPO is used in a chain such that the requirements for XAPO_FLAG_INPLACE_REQUIRED are met, XAudio2 will ensure the XAPO is run in-place. + // If not met, XAudio2 will still run the XAPO albeit with separate input and output buffers. + // For example, consider an effect which may be ran in stereo->5.1 mode or mono->mono mode. When set to stereo->5.1, it will be run with separate input and output buffers as format conversion is not permitted in-place. + // However, if configured to run mono->mono, the same XAPO can be run in-place. Thus the same implementation may be conveniently reused for various input/output configurations, while taking advantage of in-place processing when possible. + INPLACE_SUPPORTED = 4, +} + +//-----------------------------------------------------// + +// XAPO registration properties, describes general XAPO characteristics, used with IXAPO.GetRegistrationProperties +XAPO_REGISTRATION_PROPERTIES :: struct #packed { + clsid: win.CLSID, // COM class ID, used with CoCreate + FriendlyName: [XAPO_REGISTRATION_STRING_LENGTH]u16, // friendly name unicode string + CopyrightInfo: [XAPO_REGISTRATION_STRING_LENGTH]u16, // copyright information unicode string + MajorVersion: u32, // major version + MinorVersion: u32, // minor version + Flags: XAPO_FLAGS, // XAPO property flags, describes supported input/output configuration + MinInputBufferCount: u32, // minimum number of input buffers required for processing, can be 0 + MaxInputBufferCount: u32, // maximum number of input buffers supported for processing, must be >= MinInputBufferCount + MinOutputBufferCount: u32, // minimum number of output buffers required for processing, can be 0, must match MinInputBufferCount when XAPO_FLAG.BUFFERCOUNT_MUST_MATCH used + MaxOutputBufferCount: u32, // maximum number of output buffers supported for processing, must be >= MinOutputBufferCount, must match MaxInputBufferCount when XAPO_FLAG.BUFFERCOUNT_MUST_MATCH used +} + +// LockForProcess buffer parameters: +// Defines buffer parameters that remain constant while an XAPO is locked. +// Used with IXAPO.LockForProcess. +// For CBR XAPOs, MaxFrameCount is the only number of frames +// IXAPO.Process would have to handle for the respective buffer. +XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS :: struct #packed { + pFormat: ^WAVEFORMATEX, // buffer audio format + MaxFrameCount: u32, // maximum number of frames in respective buffer that IXAPO.Process would have to handle, irrespective of dynamic variable settings, can be 0 +} + +// Buffer flags: +// Describes assumed content of the respective buffer. +// Used with XAPO_PROCESS_BUFFER_PARAMETERS.BufferFlags. +// This meta-data can be used by an XAPO to implement optimizations that require knowledge of a buffer's content. +// For example, XAPOs that always produce silent output from silent input can check the flag on the input buffer to determine if any signal processing is necessary. +// If silent, the XAPO may simply set the flag on the output buffer to silent and return, optimizing out the work of processing silent data: XAPOs that generate silence for any reason may set the buffer's flag accordingly rather than writing out silent frames to the buffer itself. +// The flags represent what should be assumed is in the respective buffer. The flags may not reflect what is actually stored in memory. +XAPO_BUFFER_FLAGS :: enum i32 { + SILENT, // silent data should be assumed, respective memory may be uninitialized + VALID, // arbitrary data should be assumed (may or may not be silent frames), respective memory initialized +} + +// Process buffer parameters: +// Defines buffer parameters that may change from one processing pass to the next. Used with IXAPO.Process. +// Note the byte size of the respective buffer must be at least: +// XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount * XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.pFormat.nBlockAlign +// Although the audio format and maximum size of the respective buffer is locked (defined by XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS), the actual memory address of the buffer given is permitted to change from one processing pass to the next. +// For CBR XAPOs, ValidFrameCount is constant while locked and equals the respective XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount. +XAPO_PROCESS_BUFFER_PARAMETERS :: struct #packed { + pBuffer: rawptr, // audio data buffer, must be non-nil + BufferFlags: XAPO_BUFFER_FLAGS, // describes assumed content of pBuffer, does not affect ValidFrameCount + ValidFrameCount: u32, // number of frames of valid data, must be within respective [0, XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount], always XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount for CBR/user-defined XAPOs, does not affect BufferFlags +} + +// Used by IXAPO methods that must allocate arbitrary sized structures such as WAVEFORMATEX that are subsequently returned to the application. +XAPOAlloc :: win.CoTaskMemAlloc +XAPOFree :: win.CoTaskMemFree + +IXAPO_UUID_STRING :: "A410B984-9839-4819-A0BE-2856AE6B3ADB" +IXAPO_UUID := &win.IID{0xA410B984, 0x9839, 0x4819, {0xA0, 0xBE, 0x28, 0x56, 0xAE, 0x6B, 0x3A, 0xDB}} +IXAPO :: struct #raw_union { + #subtype iunknown: IUnknown, + using ixapo_vtable: ^IXAPO_VTable, +} +IXAPO_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + + // DESCRIPTION: + // Allocates a copy of the registration properties of the XAPO. + // PARAMETERS: + // ppRegistrationProperties - [out] receives pointer to copy of registration properties, use XAPOFree to free structure, left untouched on failure + // RETURN VALUE: + // COM error code + GetRegistrationProperties: proc "system" (this: ^IXAPO, ppRegistrationProperties: ^^XAPO_REGISTRATION_PROPERTIES) -> HRESULT, + + // DESCRIPTION: + // Queries if an input/output configuration is supported. + // REMARKS: + // This method allows XAPOs to express dependency of input format with respect to output format. + // If the input/output format pair configuration is unsupported, this method also determines the nearest input format supported. + // Nearest meaning closest bit depth, framerate, and channel count, in that order of importance. + // The behaviour of this method should remain constant after the XAPO has been initialized. + // PARAMETERS: + // pOutputFormat - [in] output format known to be supported + // pRequestedInputFormat - [in] input format to examine + // ppSupportedInputFormat - [out] receives pointer to nearest input format supported if not nil and input/output configuration unsupported, use XAPOFree to free structure, left untouched on any failure except FORMAT_UNSUPPORTED + // RETURN VALUE: + // COM error code, including: + // S_OK - input/output configuration supported, ppSupportedInputFormat left untouched + // FORMAT_UNSUPPORTED - input/output configuration unsupported, ppSupportedInputFormat receives pointer to nearest input format supported if not nil + // E_INVALIDARG - either audio format invalid, ppSupportedInputFormat left untouched + IsInputFormatSupported: proc "system" (this: ^IXAPO, pOutputFormat: ^WAVEFORMATEX, pRequestedInputFormat: ^WAVEFORMATEX, ppSupportedInputFormat: ^^WAVEFORMATEX) -> HRESULT, + + // DESCRIPTION: + // Queries if an input/output configuration is supported. + // REMARKS: + // This method allows XAPOs to express dependency of output format with respect to input format. + // If the input/output format pair configuration is unsupported, this method also determines the nearest output format supported. + // Nearest meaning closest bit depth, framerate, and channel count, in that order of importance. + // The behaviour of this method should remain constant after the XAPO has been initialized. + // PARAMETERS: + // pInputFormat - [in] input format known to be supported + // pRequestedOutputFormat - [in] output format to examine + // ppSupportedOutputFormat - [out] receives pointer to nearest output format supported if not nil and input/output configuration unsupported, use XAPOFree to free structure, left untouched on any failure except FORMAT_UNSUPPORTED + // RETURN VALUE: + // COM error code, including: + // S_OK - input/output configuration supported, ppSupportedOutputFormat left untouched + // FORMAT_UNSUPPORTED - input/output configuration unsupported, ppSupportedOutputFormat receives pointer to nearest output format supported if not nil + // E_INVALIDARG - either audio format invalid, ppSupportedOutputFormat left untouched + IsOutputFormatSupported: proc "system" (this: ^IXAPO, pInputFormat: ^WAVEFORMATEX, pRequestedOutputFormat: ^WAVEFORMATEX, ppSupportedOutputFormat: ^^WAVEFORMATEX) -> HRESULT, + + // DESCRIPTION: + // Performs any effect-specific initialization if required. + // REMARKS: + // The contents of pData are defined by the XAPO. + // Immutable variables (constant during the lifespan of the XAPO) should be set once via this method. + // Once initialized, an XAPO cannot be initialized again. + // An XAPO should be initialized before passing it to XAudio2 as part of an effect chain. XAudio2 will not call this method; it exists for future content-driven initialization. + // PARAMETERS: + // pData - [in] effect-specific initialization parameters, may be nil if DataByteSize == 0 + // DataByteSize - [in] size of pData in bytes, may be 0 if pData is nil + // RETURN VALUE: + // COM error code + Initialize: proc "system" (this: ^IXAPO, pData: rawptr, DataByteSize: u32) -> HRESULT, + + // DESCRIPTION: + // Resets variables dependent on frame history. + // REMARKS: + // All other variables remain unchanged, including variables set by IXAPOParameters.SetParameters. + // For example, an effect with delay should zero out its delay line during this method, but should not reallocate anything as the + // XAPO remains locked with a constant input/output configuration. XAudio2 calls this method only if the XAPO is locked. + // This method should not block as it is called from the realtime thread. + // PARAMETERS: + // void + // RETURN VALUE: + // void + Reset: proc "system" (this: ^IXAPO), + + // DESCRIPTION: + // Locks the XAPO to a specific input/output configuration, + // allowing it to do any final initialization before Process + // is called on the realtime thread. + // REMARKS: + // Once locked, the input/output configuration and any other locked variables remain constant until UnlockForProcess is called. + // XAPOs should assert the input/output configuration is supported and that any required effect-specific initialization is complete. + // IsInputFormatSupported, IsOutputFormatSupported, and Initialize should be called as necessary before this method is called. + // All internal memory buffers required for Process should be allocated by the time this method returns successfully as Process is non-blocking and should not allocate memory. + // Once locked, an XAPO cannot be locked again until UnLockForProcess is called. + // PARAMETERS: + // InputLockedParameterCount - [in] number of input buffers, must be within [XAPO_REGISTRATION_PROPERTIES.MinInputBufferCount, XAPO_REGISTRATION_PROPERTIES.MaxInputBufferCount] + // pInputLockedParameters - [in] array of input locked buffer parameter structures, may be nil if InputLockedParameterCount == 0, otherwise must have InputLockedParameterCount elements + // OutputLockedParameterCount - [in] number of output buffers, must be within [XAPO_REGISTRATION_PROPERTIES.MinOutputBufferCount, XAPO_REGISTRATION_PROPERTIES.MaxOutputBufferCount], must match InputLockedParameterCount when XAPO_FLAG.BUFFERCOUNT_MUST_MATCH used + // pOutputLockedParameters - [in] array of output locked buffer parameter structures, may be nil if OutputLockedParameterCount == 0, otherwise must have OutputLockedParameterCount elements + // RETURN VALUE: + // COM error code + LockForProcess: proc "system" (this: ^IXAPO, InputLockedParameterCount: u32, pInputLockedParameters: [^]XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS, OutputLockedParameterCount: u32, pOutputLockedParameters: [^]XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS) -> HRESULT, + + // DESCRIPTION: + // Opposite of LockForProcess. Variables allocated during LockForProcess should be deallocated by this method. + // REMARKS: + // Unlocking an XAPO allows an XAPO instance to be reused with different input/output configurations. + // PARAMETERS: + // void + // RETURN VALUE: + // void + UnlockForProcess: proc "system" (this: ^IXAPO), + + // DESCRIPTION: + // Runs the XAPO's DSP code on the given input/output buffers. + // REMARKS: + // In addition to writing to the output buffers as appropriate, an XAPO must set the BufferFlags and ValidFrameCount members of all elements in pOutputProcessParameters accordingly. + // ppInputProcessParameters will not necessarily be the same as ppOutputProcessParameters for in-place processing, rather the pBuffer members of each will point to the same memory. + // Multiple input/output buffers may be used with in-place XAPOs, though the input buffer count must equal the output buffer count. + // When multiple input/output buffers are used with in-place XAPOs, the XAPO may assume input buffer [N] equals output buffer [N]. + // When IsEnabled is false, the XAPO should process thru. Thru processing means an XAPO should not apply its normal processing to the given input/output buffers during Process. + // It should instead pass data from input to output with as little modification possible. Effects that perform format conversion should continue to do so. + // The effect must ensure transitions between normal and thru processing do not introduce discontinuities into the signal. + // XAudio2 calls this method only if the XAPO is locked. This method should not block as it is called from the realtime thread. + // PARAMETERS: + // InputProcessParameterCount - [in] number of input buffers, matches respective InputLockedParameterCount parameter given to LockForProcess + // pInputProcessParameters - [in] array of input process buffer parameter structures, may be nil if InputProcessParameterCount == 0, otherwise must have InputProcessParameterCount elements + // OutputProcessParameterCount - [in] number of output buffers, matches respective OutputLockedParameterCount parameter given to LockForProcess + // pOutputProcessParameters - [in/out] array of output process buffer parameter structures, may be nil if OutputProcessParameterCount == 0, otherwise must have OutputProcessParameterCount elements + // IsEnabled - [in] true to process normally, false to process thru + // RETURN VALUE: + // void + Process: proc "system" (this: ^IXAPO, InputProcessParameterCount: u32, pInputProcessParameters: [^]XAPO_PROCESS_BUFFER_PARAMETERS, OutputProcessParameterCount: u32, pOutputProcessParameters: [^]XAPO_PROCESS_BUFFER_PARAMETERS, IsEnabled: b32), + + // DESCRIPTION: + // Returns the number of input frames required to generate the requested number of output frames. + // REMARKS: + // XAudio2 may call this method to determine how many input frames an XAPO requires. + // This is constant for locked CBR XAPOs; this method need only be called once while an XAPO is locked. + // XAudio2 calls this method only if the XAPO is locked. This method should not block as it is called from the realtime thread. + // PARAMETERS: + // OutputFrameCount - [in] requested number of output frames, must be within respective [0, XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount], always XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount for CBR/user-defined XAPOs + // RETURN VALUE: + // number of input frames required + CalcInputFrames: proc "system" (this: ^IXAPO, OutputFrameCount: u32) -> u32, + + // DESCRIPTION: + // Returns the number of output frames generated for the requested number of input frames. + // REMARKS: + // XAudio2 may call this method to determine how many output frames an XAPO will generate. This is constant for locked CBR XAPOs; this method need only be called once while an XAPO is locked. + // XAudio2 calls this method only if the XAPO is locked. This method should not block as it is called from the realtime thread. + // PARAMETERS: + // InputFrameCount - [in] requested number of input frames, must be within respective [0, XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount], always XAPO_LOCKFORPROCESS_BUFFER_PARAMETERS.MaxFrameCount for CBR/user-defined XAPOs + // RETURN VALUE: + // number of output frames generated + CalcOutputFrames: proc "system" (this: ^IXAPO, InputFrameCount: u32) -> u32, +} + +// IXAPOParameters: +// Optional XAPO COM interface that allows an XAPO to use effect-specific parameters. +IXAPOParameters_UUID_STRING :: "26D95C66-80F2-499A-AD54-5AE7F01C6D98" +IXAPOParameters_UUID := &win.IID{0x26D95C66, 0x80F2, 0x499A, {0xAD, 0x54, 0x5A, 0xE7, 0xF0, 0x1C, 0x6D, 0x98}} +IXAPOParameters :: struct #raw_union { + #subtype iunknown: IUnknown, + using ixapoparameters_vtable: ^IXAPOParameters_VTable, +} +IXAPOParameters_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + + // DESCRIPTION: + // Sets effect-specific parameters. + // REMARKS: + // This method may only be called on the realtime thread; no synchronization between it and IXAPO.Process is necessary. + // This method should not block as it is called from the realtime thread. + // PARAMETERS: + // pParameters - [in] effect-specific parameter block, must be != nil + // ParameterByteSize - [in] size of pParameters in bytes, must be > 0 + // RETURN VALUE: + // void + SetParameters: proc "system" (this: ^IXAPOParameters, pParameters: rawptr, ParameterByteSize: u32), + + // DESCRIPTION: + // Gets effect-specific parameters. + // REMARKS: + // Unlike SetParameters, XAudio2 does not call this method on the realtime thread. Thus, the XAPO must protect variables shared with SetParameters/Process using appropriate synchronization. + // PARAMETERS: + // pParameters - [out] receives effect-specific parameter block, must be != nil + // ParameterByteSize - [in] size of pParameters in bytes, must be > 0 + // RETURN VALUE: + // void + GetParameters: proc "system" (this: ^IXAPOParameters, pParameters: rawptr, ParameterByteSize: u32), +} diff --git a/vendor/windows/XAudio2/xapofx.odin b/vendor/windows/XAudio2/xapofx.odin new file mode 100644 index 000000000..5ab9d57a8 --- /dev/null +++ b/vendor/windows/XAudio2/xapofx.odin @@ -0,0 +1,138 @@ +#+build windows + +package windows_xaudio2 + +import win "core:sys/windows" + +foreign import xa2 "system:xaudio2.lib" + +//---------------------------------------------------// + +FXEQ_UUID_STRING :: "F5E01117-D6C4-485A-A3F5-695196F3DBFA" +FXEQ_UUID := &win.CLSID{0xF5E01117, 0xD6C4, 0x485A, {0xA3, 0xF5, 0x69, 0x51, 0x96, 0xF3, 0xDB, 0xFA}} + +FXMasteringLimiter_UUID_STRING :: "C4137916-2BE1-46FD-8599-441536F49856" +FXMasteringLimiter_UUID := &win.CLSID{0xC4137916, 0x2BE1, 0x46FD, {0x85, 0x99, 0x44, 0x15, 0x36, 0xF4, 0x98, 0x56}} + +FXReverb_UUID_STRING :: "7D9ACA56-CB68-4807-B632-B137352E8596" +FXReverb_UUID := &win.CLSID{0x7D9ACA56, 0xCB68, 0x4807, {0xB6, 0x32, 0xB1, 0x37, 0x35, 0x2E, 0x85, 0x96}} + +FXEcho_UUID_STRING :: "5039D740-F736-449A-84D3-A56202557B87" +FXEcho_UUID := &win.CLSID{0x5039D740, 0xF736, 0x449A, {0x84, 0xD3, 0xA5, 0x62, 0x02, 0x55, 0x7B, 0x87}} + +// EQ parameter bounds (inclusive), used with FXEQ: +FXEQ_MIN_FRAMERATE :: 22000 +FXEQ_MAX_FRAMERATE :: 48000 + +FXEQ_MIN_FREQUENCY_CENTER :: 20.0 +FXEQ_MAX_FREQUENCY_CENTER :: 20000.0 +FXEQ_DEFAULT_FREQUENCY_CENTER_0 :: 100.0 // band 0 +FXEQ_DEFAULT_FREQUENCY_CENTER_1 :: 800.0 // band 1 +FXEQ_DEFAULT_FREQUENCY_CENTER_2 :: 2000.0 // band 2 +FXEQ_DEFAULT_FREQUENCY_CENTER_3 :: 10000.0 // band 3 + +FXEQ_MIN_GAIN :: 0.126 // -18dB +FXEQ_MAX_GAIN :: 7.94 // +18dB +FXEQ_DEFAULT_GAIN :: 1.0 // 0dB change, all bands + +FXEQ_MIN_BANDWIDTH :: 0.1 +FXEQ_MAX_BANDWIDTH :: 2.0 +FXEQ_DEFAULT_BANDWIDTH :: 1.0 // all bands + + +// Mastering limiter parameter bounds (inclusive), used with FXMasteringLimiter: +FXMASTERINGLIMITER_MIN_RELEASE :: 1 +FXMASTERINGLIMITER_MAX_RELEASE :: 20 +FXMASTERINGLIMITER_DEFAULT_RELEASE :: 6 + +FXMASTERINGLIMITER_MIN_LOUDNESS :: 1 +FXMASTERINGLIMITER_MAX_LOUDNESS :: 1800 +FXMASTERINGLIMITER_DEFAULT_LOUDNESS :: 1000 + + +// Reverb parameter bounds (inclusive), used with FXReverb: +FXREVERB_MIN_DIFFUSION :: 0.0 +FXREVERB_MAX_DIFFUSION :: 1.0 +FXREVERB_DEFAULT_DIFFUSION :: 0.9 + +FXREVERB_MIN_ROOMSIZE :: 0.0001 +FXREVERB_MAX_ROOMSIZE :: 1.0 +FXREVERB_DEFAULT_ROOMSIZE :: 0.6 + +// Loudness defaults used with FXLoudness: +FXLOUDNESS_DEFAULT_MOMENTARY_MS :: 400 +FXLOUDNESS_DEFAULT_SHORTTERM_MS :: 3000 + +// Echo initialization data/parameter bounds (inclusive), used with FXEcho: +FXECHO_MIN_WETDRYMIX :: 0.0 +FXECHO_MAX_WETDRYMIX :: 1.0 +FXECHO_DEFAULT_WETDRYMIX :: 0.5 + +FXECHO_MIN_FEEDBACK :: 0.0 +FXECHO_MAX_FEEDBACK :: 1.0 +FXECHO_DEFAULT_FEEDBACK :: 0.5 + +FXECHO_MIN_DELAY :: 1.0 +FXECHO_MAX_DELAY :: 2000.0 +FXECHO_DEFAULT_DELAY :: 500.0 + +//-----------------------------------------------------// + +// EQ parameters (4 bands), used with IXAPOParameters.SetParameters: +// The EQ supports only f32 audio foramts. +// The framerate must be within [22000, 48000] Hz. +FXEQ_PARAMETERS :: struct #packed { + FrequencyCenter0: f32, // center frequency in Hz, band 0 + Gain0: f32, // boost/cut + Bandwidth0: f32, // bandwidth, region of EQ is center frequency +/- bandwidth/2 + FrequencyCenter1: f32, // band 1 + Gain1: f32, + Bandwidth1: f32, + FrequencyCenter2: f32, // band 2 + Gain2: f32, + Bandwidth2: f32, + FrequencyCenter3: f32, // band 3 + Gain3: f32, + Bandwidth3: f32, +} + +// Mastering limiter parameters, used with IXAPOParameters.SetParameters: +// The mastering limiter supports only f32 audio formats. +FXMASTERINGLIMITER_PARAMETERS :: struct #packed { + Release: u32, // release time (tuning factor with no specific units) + Loudness: u32, // loudness target (threshold) +} + +// Reverb parameters, used with IXAPOParameters.SetParameters: +// The reverb supports only f32 audio formats with the following channel configurations: +// Input: Mono Output: Mono +// Input: Stereo Output: Stereo +FXREVERB_PARAMETERS :: struct #packed { + Diffusion: f32, // diffusion + RoomSize: f32, // room size +} + + +// Echo initialization data, used with CreateFX: +// Use of this structure is optional, the default MaxDelay is FXECHO_DEFAULT_DELAY. +FXECHO_INITDATA :: struct #packed { + MaxDelay: f32, // maximum delay (all channels) in milliseconds, must be within [FXECHO_MIN_DELAY, FXECHO_MAX_DELAY] +} + +// Echo parameters, used with IXAPOParameters.SetParameters: +// The echo supports only f32 audio formats. +FXECHO_PARAMETERS :: struct #packed { + WetDryMix: f32, // ratio of wet (processed) signal to dry (original) signal + Feedback: f32, // amount of output fed back into input + Delay: f32, // delay (all channels) in milliseconds, must be within [FXECHO_MIN_DELAY, FXECHO_PARAMETERS.MaxDelay] +} + +//-------------------------------------------------------// + +@(default_calling_convention="cdecl") +foreign xa2 { + // creates instance of requested XAPO, use Release to free instance + // pInitData - [in] effect-specific initialization parameters, may be nil if InitDataByteSize == 0 + // InitDataByteSize - [in] size of pInitData in bytes, may be 0 if pInitData is nil + CreateFX :: proc(clsid: win.REFCLSID, pEffect: ^^IUnknown, pInitDat: rawptr = nil, InitDataByteSize: u32 = 0) -> HRESULT --- +} diff --git a/vendor/windows/XAudio2/xaudio2.odin b/vendor/windows/XAudio2/xaudio2.odin new file mode 100644 index 000000000..6187b63fe --- /dev/null +++ b/vendor/windows/XAudio2/xaudio2.odin @@ -0,0 +1,817 @@ +#+build windows +/* + Bindings for Windows XAudio2: + https://learn.microsoft.com/en-us/windows/win32/xaudio2/xaudio2-introduction + + Compiling for Windows 10 RS5 (1809) and later +*/ + +package windows_xaudio2 + +import win "core:sys/windows" +import "core:math" + +foreign import xa2 "system:xaudio2.lib" + +HRESULT :: win.HRESULT +IUnknown :: win.IUnknown +IUnknown_VTable :: win.IUnknown_VTable +WAVEFORMATEX :: win.WAVEFORMATEX + +/************************************************************************** + * + * XAudio2 constants, flags and error codes. + * + **************************************************************************/ + +// Numeric boundary values +MAX_BUFFER_BYTES :: 0x80000000 // Maximum bytes allowed in a source buffer +MAX_QUEUED_BUFFERS :: 64 // Maximum buffers allowed in a voice queue +MAX_BUFFERS_SYSTEM :: 2 // Maximum buffers allowed for system threads (Xbox 360 only) +MAX_AUDIO_CHANNELS :: 64 // Maximum channels in an audio stream +MIN_SAMPLE_RATE :: 1000 // Minimum audio sample rate supported +MAX_SAMPLE_RATE :: 200000 // Maximum audio sample rate supported +MAX_VOLUME_LEVEL :: 16777216.0 // Maximum acceptable volume level (2^24) +MIN_FREQ_RATIO :: (1.0 / 1024.0) // Minimum SetFrequencyRatio argument +MAX_FREQ_RATIO :: 1024.0 // Maximum MaxFrequencyRatio argument +DEFAULT_FREQ_RATIO :: 2.0 // Default MaxFrequencyRatio argument +MAX_FILTER_ONEOVERQ :: 1.5 // Maximum FILTER_PARAMETERS.OneOverQ +MAX_FILTER_FREQUENCY :: 1.0 // Maximum FILTER_PARAMETERS.Frequency +MAX_LOOP_COUNT :: 254 // Maximum non-infinite BUFFER.LoopCount +MAX_INSTANCES :: 8 // Maximum simultaneous XAudio2 objects on Xbox 360 + +// For XMA voices on Xbox 360 there is an additional restriction on the MaxFrequencyRatio argument and the voice's sample rate: the product of these numbers cannot exceed 600000 for one-channel voices or 300000 for voices with more than one channel. +MAX_RATIO_TIMES_RATE_XMA_MONO :: 600000 +MAX_RATIO_TIMES_RATE_XMA_MULTICHANNEL :: 300000 + +// Numeric values with special meanings +COMMIT_NOW :: 0 // Used as an OperationSet argument +COMMIT_ALL :: 0 // Used in IXAudio2.CommitChanges +INVALID_OPSET :: 0xffffffff // Not allowed for OperationSet arguments +NO_LOOP_REGION :: 0 // Used in BUFFER.LoopCount +LOOP_INFINITE :: 255 // Used in BUFFER.LoopCount +DEFAULT_CHANNELS :: 0 // Used in CreateMasteringVoice +DEFAULT_SAMPLERATE :: 0 // Used in CreateMasteringVoice + +// Flags +FLAGS :: distinct bit_set[FLAG; u32] +FLAG :: enum u32 { + DEBUG_ENGINE = 0, // Used in Create + VOICE_NOPITCH = 1, // Used in IXAudio2.CreateSourceVoice + VOICE_NOSRC = 2, // Used in IXAudio2.CreateSourceVoice + VOICE_USEFILTER = 3, // Used in IXAudio2.CreateSource/SubmixVoice + PLAY_TAILS = 5, // Used in IXAudio2SourceVoice.Stop + END_OF_STREAM = 6, // Used in BUFFER.Flags + SEND_USEFILTER = 7, // Used in SEND_DESCRIPTOR.Flags + VOICE_NOSAMPLESPLAYED = 8, // Used in IXAudio2SourceVoice.GetState + STOP_ENGINE_WHEN_IDLE = 13, // Used in Create to force the engine to Stop when no source voices are Started, and Start when a voice is Started + QUANTUM_1024 = 15, // Used in Create to specify nondefault processing quantum of 21.33 ms (1024 samples at 48KHz) + NO_VIRTUAL_AUDIO_CLIENT = 16, // Used in CreateMasteringVoice to create a virtual audio client +} + +// Default parameters for the built-in filter +DEFAULT_FILTER_TYPE :: FILTER_TYPE.LowPassFilter +DEFAULT_FILTER_FREQUENCY :: MAX_FILTER_FREQUENCY +DEFAULT_FILTER_ONEOVERQ :: 1.0 + +// Internal XAudio2 constants +// The audio frame quantum can be calculated by reducing the fraction: +// SamplesPerAudioFrame / SamplesPerSecond +QUANTUM_NUMERATOR :: 1 // On Windows, XAudio2 processes audio +QUANTUM_DENOMINATOR :: 100 // in 10ms chunks (= 1/100 seconds) +QUANTUM_MS :: (1000.0 * QUANTUM_NUMERATOR / QUANTUM_DENOMINATOR) + +// XAudio2 error codes +INVALID_CALL :: HRESULT(-2003435519) // 0x88960001 An API call or one of its arguments was illegal +XMA_DECODER_ERROR :: HRESULT(-2003435518) // 0x88960002 The XMA hardware suffered an unrecoverable error +XAPO_CREATION_FAILED :: HRESULT(-2003435517) // 0x88960003 XAudio2 failed to initialize an XAPO effect +DEVICE_INVALIDATED :: HRESULT(-2003435516) // 0x88960004 An audio device became unusable (unplugged, etc) + + +/************************************************************************** + * + * XAudio2 structures and enumerations. + * + **************************************************************************/ + +// Used in Create, specifies which CPU(s) to use. +PROCESSOR_FLAGS :: distinct bit_set[PROCESSOR_FLAG; u32] +PROCESSOR_FLAG :: enum u32 { + Processor1 = 0, + Processor2 = 1, + Processor3 = 2, + Processor4 = 3, + Processor5 = 4, + Processor6 = 5, + Processor7 = 6, + Processor8 = 7, + Processor9 = 8, + Processor10 = 9, + Processor11 = 10, + Processor12 = 11, + Processor13 = 12, + Processor14 = 13, + Processor15 = 14, + Processor16 = 15, + Processor17 = 16, + Processor18 = 17, + Processor19 = 18, + Processor20 = 19, + Processor21 = 20, + Processor22 = 21, + Processor23 = 22, + Processor24 = 23, + Processor25 = 24, + Processor26 = 25, + Processor27 = 26, + Processor28 = 27, + Processor29 = 28, + Processor30 = 29, + Processor31 = 30, + Processor32 = 31, +} +//ANY_PROCESSOR :: 0xffffffff +USE_DEFAULT_PROCESSOR :: PROCESSOR_FLAGS{} + +// Returned by IXAudio2Voice.GetVoiceDetails +VOICE_DETAILS :: struct #packed { + CreatingFlags: FLAGS, + ActiveFlags: FLAGS, + InputChannels: u32, + InputSampleRate: u32, +} + +// Used in VOICE_SENDS below +SEND_DESCRIPTOR :: struct #packed { + Flags: FLAGS, // Either 0 or SEND_USEFILTER. + pOutputVoice: ^IXAudio2Voice, // This send's destination voice. +} + +// Used in the voice creation functions and in IXAudio2Voice.SetOutputVoices +VOICE_SENDS :: struct #packed { + SendCount: u32, // Number of sends from this voice. + pSends: [^]SEND_DESCRIPTOR `fmt:"v,SendCount"`, // Array of SendCount send descriptors. +} + +// Used in EFFECT_CHAIN below +EFFECT_DESCRIPTOR :: struct #packed { + pEffect: ^IUnknown, // Pointer to the effect object's IUnknown interface. + InitialState: b32, // TRUE if the effect should begin in the enabled state. + OutputChannels: u32, // How many output channels the effect should produce. +} + +// Used in the voice creation functions and in IXAudio2Voice.SetEffectChain +EFFECT_CHAIN :: struct #packed { + EffectCount: u32, // Number of effects in this voice's effect chain. + pEffectDescriptors: [^]EFFECT_DESCRIPTOR `fmt:"v,EffectCount"`, // Array of effect descriptors. +} + +// Used in FILTER_PARAMETERS below +FILTER_TYPE :: enum i32 { + LowPassFilter, // Attenuates frequencies above the cutoff frequency (state-variable filter). + BandPassFilter, // Attenuates frequencies outside a given range (state-variable filter). + HighPassFilter, // Attenuates frequencies below the cutoff frequency (state-variable filter). + NotchFilter, // Attenuates frequencies inside a given range (state-variable filter). + LowPassOnePoleFilter, // Attenuates frequencies above the cutoff frequency (one-pole filter, FILTER_PARAMETERS.OneOverQ has no effect) + HighPassOnePoleFilter, // Attenuates frequencies below the cutoff frequency (one-pole filter, FILTER_PARAMETERS.OneOverQ has no effect) +} + +// Used in IXAudio2Voice.Set/GetFilterParameters and Set/GetOutputFilterParameters +FILTER_PARAMETERS :: struct #packed { + Type: FILTER_TYPE, // Filter type. + Frequency: f32, // Filter coefficient. Must be >= 0 and <= MAX_FILTER_FREQUENCY. See CutoffFrequencyToRadians() for state-variable filter types and CutoffFrequencyToOnePoleCoefficient() for one-pole filter types. + OneOverQ: f32, // Reciprocal of the filter's quality factor Q; must be > 0 and <= MAX_FILTER_ONEOVERQ. Has no effect for one-pole filters. +} + +// Used in IXAudio2SourceVoice.SubmitSourceBuffer +BUFFER :: struct #packed { + Flags: FLAGS, // Either 0 or END_OF_STREAM. + AudioBytes: u32, // Size of the audio data buffer in bytes. + pAudioData: [^]byte `fmt:"v,AudioBytes"`, // Pointer to the audio data buffer. + PlayBegin: u32, // First sample in this buffer to be played. + PlayLength: u32, // Length of the region to be played in samples, or 0 to play the whole buffer. + LoopBegin: u32, // First sample of the region to be looped. + LoopLength: u32, // Length of the desired loop region in samples, or 0 to loop the entire buffer. + LoopCount: u32, // Number of times to repeat the loop region, or LOOP_INFINITE to loop forever. + pContext: rawptr, // Context value to be passed back in callbacks. +} + +// Used in IXAudio2SourceVoice.SubmitSourceBuffer when submitting XWMA data. +// NOTE: If an XWMA sound is submitted in more than one buffer, each buffer's pDecodedPacketCumulativeBytes[PacketCount-1] value must be subtracted from all the entries in the next buffer's pDecodedPacketCumulativeBytes array. +// And whether a sound is submitted in more than one buffer or not, the final buffer of the sound should use the END_OF_STREAM flag, or else the client must call IXAudio2SourceVoice.Discontinuity after submitting it. +BUFFER_WMA :: struct #packed { + pDecodedPacketCumulativeBytes: [^]u32 `fmt:"v,PacketCount"`, // Decoded packet's cumulative size array. Each element is the number of bytes accumulated when the corresponding XWMA packet is decoded in order. The array must have PacketCount elements. + PacketCount: u32, // Number of XWMA packets submitted. Must be >= 1 and divide evenly into BUFFER.AudioBytes. +} + +// Returned by IXAudio2SourceVoice.GetState +VOICE_STATE :: struct #packed { + pCurrentBufferContext: rawptr, // The pContext value provided in the BUFFER that is currently being processed, or nil if there are no buffers in the queue. + BuffersQueued: u32, // Number of buffers currently queued on the voice (including the one that is being processed). + SamplesPlayed: u64, // Total number of samples produced by the voice since it began processing the current audio stream. If VOICE_NOSAMPLESPLAYED is specified in the call to IXAudio2SourceVoice.GetState, this member will not be calculated, saving CPU. +} + +// Returned by IXAudio2.GetPerformanceData +PERFORMANCE_DATA :: struct #packed { + // CPU usage information + AudioCyclesSinceLastQuery: u64, // CPU cycles spent on audio processing since the last call to StartEngine or GetPerformanceData. + TotalCyclesSinceLastQuery: u64, // Total CPU cycles elapsed since the last call (only counts the CPU XAudio2 is running on). + MinimumCyclesPerQuantum: u32, // Fewest CPU cycles spent processing any one audio quantum since the last call. + MaximumCyclesPerQuantum: u32, // Most CPU cycles spent processing any one audio quantum since the last call. + + // Memory usage information + MemoryUsageInBytes: u32, // Total heap space currently in use. + + // Audio latency and glitching information + CurrentLatencyInSamples: u32, // Minimum delay from when a sample is read from a source buffer to when it reaches the speakers. + GlitchesSinceEngineStarted: u32, // Audio dropouts since the engine was started. + + // Data about XAudio2's current workload + ActiveSourceVoiceCount: u32, // Source voices currently playing. + TotalSourceVoiceCount: u32, // Source voices currently existing. + ActiveSubmixVoiceCount: u32, // Submix voices currently playing/existing. + + ActiveResamplerCount: u32, // Resample xAPOs currently active. + ActiveMatrixMixCount: u32, // MatrixMix xAPOs currently active. + + // Usage of the hardware XMA decoder (Xbox 360 only) + ActiveXmaSourceVoices: u32, // Number of source voices decoding XMA data. + ActiveXmaStreams: u32, // A voice can use more than one XMA stream. +} + +// Used in IXAudio2.SetDebugConfiguration +DEBUG_CONFIGURATION :: struct #packed { + TraceMask: DEBUG_CONFIG_FLAGS, // Bitmap of enabled debug message types. + BreakMask: DEBUG_CONFIG_FLAGS, // Message types that will break into the debugger. + LogThreadID: b32, // Whether to log the thread ID with each message. + LogFileline: b32, // Whether to log the source file and line number. + LogFunctionName: b32, // Whether to log the function name. + LogTiming: b32, // Whether to log message timestamps. +} + +// Values for the TraceMask and BreakMask bitmaps. Only ERRORS and WARNINGS are valid in BreakMask. +// WARNINGS implies ERRORS, DETAIL implies INFO, and FUNC_CALLS implies API_CALLS. +// By default, TraceMask is ERRORS and WARNINGS and all the other settings are zero. +DEBUG_CONFIG_FLAGS :: distinct bit_set[DEBUG_CONFIG_FLAG; u32] +DEBUG_CONFIG_FLAG :: enum u32 { + ERRORS = 0, // For handled errors with serious effects. + WARNINGS = 1, // For handled errors that may be recoverable. + INFO = 2, // Informational chit-chat (e.g. state changes). + DETAIL = 3, // More detailed chit-chat. + API_CALLS = 4, // Public API function entries and exits. + FUNC_CALLS = 5, // Internal function entries and exits. + TIMING = 6, // Delays detected and other timing data. + LOCKS = 7, // Usage of critical sections and mutexes. + MEMORY = 8, // Memory heap usage information. + STREAMING = 12, // Audio streaming information. +} + +/************************************************************************** + * + * IXAudio2: Top-level XAudio2 COM interface. + * + **************************************************************************/ + +IXAudio2_UUID_STRING :: "2B02E3CF-2E0B-4ec3-BE45-1B2A3FE7210D" +IXAudio2_UUID := &win.IID{0x2B02E3CF, 0x2E0B, 0x4ec3, {0xBE, 0x45, 0x1B, 0x2A, 0x3F, 0xE7, 0x21, 0x0D}} +IXAudio2 :: struct #raw_union { + #subtype iunknown: IUnknown, + using ixaudio2_vtable: ^IXAudio2_VTable, +} +IXAudio2_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + + // NAME: IXAudio2.RegisterForCallbacks + // DESCRIPTION: Adds a new client to receive XAudio2's engine callbacks. + // ARGUMENTS: + // pCallback - Callback interface to be called during each processing pass. + RegisterForCallbacks: proc "system" (this: ^IXAudio2, pCallback: ^IXAudio2EngineCallback) -> HRESULT, + + // NAME: IXAudio2.UnregisterForCallbacks + // DESCRIPTION: Removes an existing receiver of XAudio2 engine callbacks. + // ARGUMENTS: + // pCallback - Previously registered callback interface to be removed. + UnregisterForCallbacks: proc "system" (this: ^IXAudio2, pCallback: ^IXAudio2EngineCallback), + + // NAME: IXAudio2.CreateSourceVoice + // DESCRIPTION: Creates and configures a source voice. + // ARGUMENTS: + // ppSourceVoice - Returns the new object's IXAudio2SourceVoice interface. + // pSourceFormat - Format of the audio that will be fed to the voice. + // Flags - VOICE flags specifying the source voice's behavior. + // MaxFrequencyRatio - Maximum SetFrequencyRatio argument to be allowed. + // pCallback - Optional pointer to a client-provided callback interface. + // pSendList - Optional list of voices this voice should send audio to. + // pEffectChain - Optional list of effects to apply to the audio data. + CreateSourceVoice: proc "system" (this: ^IXAudio2, ppSourceVoice: ^^IXAudio2SourceVoice, pSourceFormat: ^WAVEFORMATEX, Flags: FLAGS = {}, MaxFrequencyRatio: f32 = DEFAULT_FREQ_RATIO, pCallback: ^IXAudio2VoiceCallback = nil, pSendList: [^]VOICE_SENDS = nil, pEffectChain: [^]EFFECT_CHAIN = nil) -> HRESULT, + + // NAME: IXAudio2.CreateSubmixVoice + // DESCRIPTION: Creates and configures a submix voice. + // ARGUMENTS: + // ppSubmixVoice - Returns the new object's IXAudio2SubmixVoice interface. + // InputChannels - Number of channels in this voice's input audio data. + // InputSampleRate - Sample rate of this voice's input audio data. + // Flags - VOICE flags specifying the submix voice's behavior. + // ProcessingStage - Arbitrary number that determines the processing order. + // pSendList - Optional list of voices this voice should send audio to. + // pEffectChain - Optional list of effects to apply to the audio data. + CreateSubmixVoice: proc "system" (this: ^IXAudio2, ppSubmixVoice: ^^IXAudio2SubmixVoice, InputChannels: u32, InputSampleRate: u32, Flags: FLAGS = {}, ProcessingStage: u32 = 0, pSendList: [^]VOICE_SENDS = nil, pEffectChain: [^]EFFECT_CHAIN = nil) -> HRESULT, + + // NAME: IXAudio2.CreateMasteringVoice + // DESCRIPTION: Creates and configures a mastering voice. + // ARGUMENTS: + // ppMasteringVoice - Returns the new object's IXAudio2MasteringVoice interface. + // InputChannels - Number of channels in this voice's input audio data. + // InputSampleRate - Sample rate of this voice's input audio data. + // Flags - VOICE flags specifying the mastering voice's behavior. + // szDeviceId - Identifier of the device to receive the output audio. + // pEffectChain - Optional list of effects to apply to the audio data. + // StreamCategory - The audio stream category to use for this mastering voice + CreateMasteringVoice: proc "system" (this: ^IXAudio2, ppMasteringVoice: ^^IXAudio2MasteringVoice, InputChannels: u32 = DEFAULT_CHANNELS, InputSampleRate: u32 = DEFAULT_SAMPLERATE, Flags: FLAGS = {}, szDeviceId: win.LPCWSTR = nil, pEffectChain: [^]EFFECT_CHAIN = nil, StreamCategory: AUDIO_STREAM_CATEGORY = .GameEffects) -> HRESULT, + + // NAME: IXAudio2.:StartEngine + // DESCRIPTION: Creates and starts the audio processing thread. + StartEngine: proc "system" (this: ^IXAudio2) -> HRESULT, + + // NAME: IXAudio2.StopEngine + // DESCRIPTION: Stops and destroys the audio processing thread. + StopEngine: proc "system" (this: ^IXAudio2), + + // NAME: IXAudio2.CommitChanges + // DESCRIPTION: Atomically applies a set of operations previously tagged with a given identifier. + // ARGUMENTS: + // OperationSet - Identifier of the set of operations to be applied. + CommitChanges: proc "system" (this: ^IXAudio2, OperationSet: u32) -> HRESULT, + + // NAME: IXAudio2.GetPerformanceData + // DESCRIPTION: Returns current resource usage details: memory, CPU, etc. + // ARGUMENTS: + // pPerfData - Returns the performance data structure. + GetPerformanceData: proc "system" (this: ^IXAudio2, pPerfData: ^PERFORMANCE_DATA), + + // NAME: IXAudio2.SetDebugConfiguration + // DESCRIPTION: Configures XAudio2's debug output (in debug builds only). + // ARGUMENTS: + // pDebugConfiguration - Structure describing the debug output behavior. + // pReserved - Optional parameter; must be nil. + SetDebugConfiguration: proc "system" (this: ^IXAudio2, pDebugConfiguration: ^DEBUG_CONFIGURATION, pReserved: rawptr = nil), +} + +// This interface extends IXAudio2 with additional functionality. +// Use IXAudio2.QueryInterface to obtain a pointer to this interface. +IXAudio2Extension_UUID_STRING :: "84ac29bb-d619-44d2-b197-e4acf7df3ed6" +IXAudio2Extension_UUID := &win.IID{0x84ac29bb, 0xd619, 0x44d2, {0xb1, 0x97, 0xe4, 0xac, 0xf7, 0xdf, 0x3e, 0xd6}} +IXAudio2Extension :: struct #raw_union { + #subtype iunknown: IUnknown, + using ixaudio2extension_vtable: ^IXAudio2Extension_VTable, +} +IXAudio2Extension_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + + // NAME: IXAudio2Extension.GetProcessingQuantum + // DESCRIPTION: Returns the processing quantum + // quantumMilliseconds = (1000.0f * quantumNumerator / quantumDenominator) + // ARGUMENTS: + // quantumNumerator - Quantum numerator + // quantumDenominator - Quantum denominator + GetProcessingQuantum: proc "system" (this: ^IXAudio2Extension, quantumNumerator: ^u32, quantumDenominator: ^u32), + + // NAME: IXAudio2Extension.GetProcessor + // DESCRIPTION: Returns the number of the processor used by XAudio2 + // ARGUMENTS: + // processor - Non-zero Processor number + GetProcessor: proc "system" (this: ^IXAudio2Extension, processor: ^PROCESSOR_FLAGS), +} + +/************************************************************************** + * + * IXAudio2Voice: Base voice management interface. + * + **************************************************************************/ + +IXAudio2Voice :: struct { + using ixaudio2voice_vtable: ^IXAudio2Voice_VTable, +} +IXAudio2Voice_VTable :: struct { + // NAME: IXAudio2Voice.GetVoiceDetails + // DESCRIPTION: Returns the basic characteristics of this voice. + // ARGUMENTS: + // pVoiceDetails - Returns the voice's details. + GetVoiceDetails: proc "system" (this: ^IXAudio2Voice, pVoiceDetails: ^VOICE_DETAILS), + + // NAME: IXAudio2Voice.SetOutputVoices + // DESCRIPTION: Replaces the set of submix/mastering voices that receive this voice's output. + // ARGUMENTS: + // pSendList - Optional list of voices this voice should send audio to. + SetOutputVoices: proc "system" (this: ^IXAudio2Voice, pSendList: [^]VOICE_SENDS) -> HRESULT, + + // NAME: IXAudio2Voice.SetEffectChain + // DESCRIPTION: Replaces this voice's current effect chain with a new one. + // ARGUMENTS: + // pEffectChain - Structure describing the new effect chain to be used. + SetEffectChain: proc "system" (this: ^IXAudio2Voice, pEffectChain: ^EFFECT_CHAIN) -> HRESULT, + + // NAME: IXAudio2Voice.EnableEffect + // DESCRIPTION: Enables an effect in this voice's effect chain. + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // OperationSet - Used to identify this call as part of a deferred batch. + EnableEffect: proc "system" (this: ^IXAudio2Voice, EffectIndex: u32, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2Voice.DisableEffect + // DESCRIPTION: Disables an effect in this voice's effect chain. + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // OperationSet - Used to identify this call as part of a deferred batch. + DisableEffect: proc "system" (this: ^IXAudio2Voice, EffectIndex: u32, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2Voice.GetEffectState + // DESCRIPTION: Returns the running state of an effect. + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // pEnabled - Returns the enabled/disabled state of the given effect. + GetEffectState: proc "system" (this: ^IXAudio2Voice, EffectIndex: u32, pEnabled: ^b32), + + // NAME: IXAudio2Voice.SetEffectParameters + // DESCRIPTION: Sets effect-specific parameters. + // REMARKS: Unlike IXAPOParameters.SetParameters, this method may be called from any thread. XAudio2 implements appropriate synchronization to copy the parameters to the realtime audio processing thread. + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // pParameters - Pointer to an effect-specific parameters block. + // ParametersByteSize - Size of the pParameters array in bytes. + // OperationSet - Used to identify this call as part of a deferred batch. + SetEffectParameters: proc "system" (this: ^IXAudio2Voice, EffectIndex: u32, pParameters: rawptr, ParametersByteSize: u32, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2Voice.GetEffectParameters + // DESCRIPTION: Obtains the current effect-specific parameters. + // ARGUMENTS: + // EffectIndex - Index of an effect within this voice's effect chain. + // pParameters - Returns the current values of the effect-specific parameters. + // ParametersByteSize - Size of the pParameters array in bytes. + GetEffectParameters: proc "system" (this: ^IXAudio2Voice, EffectIndex: u32, pParameters: rawptr, ParametersByteSize: u32) -> HRESULT, + + // NAME: IXAudio2Voice.SetFilterParameters + // DESCRIPTION: Sets this voice's filter parameters. + // ARGUMENTS: + // pParameters - Pointer to the filter's parameter structure. + // OperationSet - Used to identify this call as part of a deferred batch. + SetFilterParameters: proc "system" (this: ^IXAudio2Voice, pParameters: ^FILTER_PARAMETERS, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2Voice.GetFilterParameters + // DESCRIPTION: Returns this voice's current filter parameters. + // ARGUMENTS: + // pParameters - Returns the filter parameters. + GetFilterParameters: proc "system" (this: ^IXAudio2Voice, pParameters: ^FILTER_PARAMETERS), + + // NAME: IXAudio2Voice.SetOutputFilterParameters + // DESCRIPTION: Sets the filter parameters on one of this voice's sends. + // ARGUMENTS: + // pDestinationVoice - Destination voice of the send whose filter parameters will be set. + // pParameters - Pointer to the filter's parameter structure. + // OperationSet - Used to identify this call as part of a deferred batch. + SetOutputFilterParameters: proc "system" (this: ^IXAudio2Voice, pDestinationVoice: ^IXAudio2Voice, pParameters: ^FILTER_PARAMETERS, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2Voice.GetOutputFilterParameters + // DESCRIPTION: Returns the filter parameters from one of this voice's sends. + // ARGUMENTS: + // pDestinationVoice - Destination voice of the send whose filter parameters will be read. + // pParameters - Returns the filter parameters. + GetOutputFilterParameters: proc "system" (this: ^IXAudio2Voice, pDestinationVoice: ^IXAudio2Voice, pParameters: ^FILTER_PARAMETERS), + + // NAME: IXAudio2Voice.SetVolume + // DESCRIPTION: Sets this voice's overall volume level. + // ARGUMENTS: + // Volume - New overall volume level to be used, as an amplitude factor. + // OperationSet - Used to identify this call as part of a deferred batch. + SetVolume: proc "system" (this: ^IXAudio2Voice, Volume: f32, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2Voice.GetVolume + // DESCRIPTION: Obtains this voice's current overall volume level. + // ARGUMENTS: + // pVolume: Returns the voice's current overall volume level. + GetVolume: proc "system" (this: ^IXAudio2Voice, pVolume: ^f32), + + // NAME: IXAudio2Voice.SetChannelVolumes + // DESCRIPTION: Sets this voice's per-channel volume levels. + // ARGUMENTS: + // Channels - Used to confirm the voice's channel count. + // pVolumes - Array of per-channel volume levels to be used. + // OperationSet - Used to identify this call as part of a deferred batch. + SetChannelVolumes: proc "system" (this: ^IXAudio2Voice, Channels: u32, pVolumes: [^]f32, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2Voice.GetChannelVolumes + // DESCRIPTION: Returns this voice's current per-channel volume levels. + // ARGUMENTS: + // Channels - Used to confirm the voice's channel count. + // pVolumes - Returns an array of the current per-channel volume levels. + GetChannelVolumes: proc "system" (this: ^IXAudio2Voice, Channels: u32, pVolumes: [^]f32), + + // NAME: IXAudio2Voice.SetOutputMatrix + // DESCRIPTION: Sets the volume levels used to mix from each channel of this voice's output audio to each channel of a given destination voice's input audio. + // ARGUMENTS: + // pDestinationVoice - The destination voice whose mix matrix to change. + // SourceChannels - Used to confirm this voice's output channel count (the number of channels produced by the last effect in the chain). + // DestinationChannels - Confirms the destination voice's input channels. + // pLevelMatrix - Array of [SourceChannels * DestinationChannels] send levels. The level used to send from source channel S to destination channel D should be in pLevelMatrix[S + SourceChannels * D]. + // OperationSet - Used to identify this call as part of a deferred batch. + SetOutputMatrix: proc "system" (this: ^IXAudio2Voice, pDestinationVoice: ^IXAudio2Voice, SourceChannels: u32, DestinationChannels: u32, pLevelMatrix: [^]f32, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2Voice.GetOutputMatrix + // DESCRIPTION: Obtains the volume levels used to send each channel of this voice's output audio to each channel of a given destination voice's input audio. + // ARGUMENTS: + // pDestinationVoice - The destination voice whose mix matrix to obtain. + // SourceChannels - Used to confirm this voice's output channel count (the number of channels produced by the last effect in the chain). + // DestinationChannels - Confirms the destination voice's input channels. + // pLevelMatrix - Array of send levels, as above. + GetOutputMatrix: proc "system" (this: ^IXAudio2Voice, pDestinationVoice: ^IXAudio2Voice, SourceChannels: u32, DestinationChannels: u32, pLevelMatrix: [^]f32), + + // NAME: IXAudio2Voice.DestroyVoice + // DESCRIPTION: Destroys this voice, stopping it if necessary and removing it from the XAudio2 graph. + DestroyVoice: proc "system" (this: ^IXAudio2Voice), +} + +/************************************************************************** + * + * IXAudio2SourceVoice: Source voice management interface. + * + **************************************************************************/ + +IXAudio2SourceVoice :: struct #raw_union { + #subtype ixaudio2voice: IXAudio2Voice, + using ixaudio2sourcevoice_vtable: ^IXAudio2SourceVoice_VTable, +} +IXAudio2SourceVoice_VTable :: struct { + using ixaudio2voice_vtable: IXAudio2Voice_VTable, + + // NAME: IXAudio2SourceVoice.Start + // DESCRIPTION: Makes this voice start consuming and processing audio. + // ARGUMENTS: + // Flags - Flags controlling how the voice should be started. + // OperationSet - Used to identify this call as part of a deferred batch. + Start: proc "system" (this: ^IXAudio2SourceVoice, Flags: FLAGS = {}, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2SourceVoice.Stop + // DESCRIPTION: Makes this voice stop consuming audio. + // ARGUMENTS: + // Flags - Flags controlling how the voice should be stopped. + // OperationSet - Used to identify this call as part of a deferred batch. + Stop: proc "system" (this: ^IXAudio2SourceVoice, Flags: FLAGS = {}, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2SourceVoice.SubmitSourceBuffer + // DESCRIPTION: Adds a new audio buffer to this voice's input queue. + // ARGUMENTS: + // pBuffer - Pointer to the buffer structure to be queued. + // pBufferWMA - Additional structure used only when submitting XWMA data. + SubmitSourceBuffer: proc "system" (this: ^IXAudio2SourceVoice, pBuffer: ^BUFFER, pBufferWMA: ^BUFFER_WMA = nil) -> HRESULT, + + // NAME: IXAudio2SourceVoice.FlushSourceBuffers + // DESCRIPTION: Removes all pending audio buffers from this voice's queue. + FlushSourceBuffers: proc "system" (this: ^IXAudio2SourceVoice) -> HRESULT, + + // NAME: IXAudio2SourceVoice.Discontinuity + // DESCRIPTION: Notifies the voice of an intentional break in the stream of audio buffers (e.g. the end of a sound), to prevent XAudio2 from interpreting an empty buffer queue as a glitch. + Discontinuity: proc "system" (this: ^IXAudio2SourceVoice) -> HRESULT, + + // NAME: IXAudio2SourceVoice.ExitLoop + // DESCRIPTION: Breaks out of the current loop when its end is reached. + // ARGUMENTS: + // OperationSet - Used to identify this call as part of a deferred batch. + ExitLoop: proc "system" (this: ^IXAudio2SourceVoice, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2SourceVoice.GetState + // DESCRIPTION: Returns the number of buffers currently queued on this voice, the pContext value associated with the currently processing buffer (if any), and other voice state information. + // ARGUMENTS: + // pVoiceState - Returns the state information. + // Flags - Flags controlling what voice state is returned. + GetState: proc "system" (this: ^IXAudio2SourceVoice, pVoiceState: ^VOICE_STATE, Flags: FLAGS = {}), + + // NAME: IXAudio2SourceVoice.SetFrequencyRatio + // DESCRIPTION: Sets this voice's frequency adjustment, i.e. its pitch. + // ARGUMENTS: + // Ratio - Frequency change, expressed as source frequency / target frequency. + // OperationSet - Used to identify this call as part of a deferred batch. + SetFrequencyRatio: proc "system" (this: ^IXAudio2SourceVoice, Ratio: f32, OperationSet: u32 = COMMIT_NOW) -> HRESULT, + + // NAME: IXAudio2SourceVoice.GetFrequencyRatio + // DESCRIPTION: Returns this voice's current frequency adjustment ratio. + // ARGUMENTS: + // pRatio - Returns the frequency adjustment. + GetFrequencyRatio: proc "system" (this: ^IXAudio2SourceVoice, pRatio: ^f32), + + // NAME: IXAudio2SourceVoice.SetSourceSampleRate + // DESCRIPTION: Reconfigures this voice to treat its source data as being at a different sample rate than the original one specified in CreateSourceVoice's pSourceFormat argument. + // ARGUMENTS: + // UINT32 - The intended sample rate of further submitted source data. + SetSourceSampleRate: proc "system" (this: ^IXAudio2SourceVoice, NewSourceSampleRate: u32) -> HRESULT, +} + +/************************************************************************** + * + * IXAudio2SubmixVoice: Submixing voice management interface. + * + **************************************************************************/ + +IXAudio2SubmixVoice :: struct #raw_union { + #subtype ixaudio2voice: IXAudio2Voice, + using ixaudio2submixvoice_vtable: ^IXAudio2SubmixVoice_VTable, +} +IXAudio2SubmixVoice_VTable :: struct { + using ixaudio2voice_vtable: IXAudio2Voice_VTable, + // There are currently no methods specific to submix voices. +} + + /************************************************************************** + * + * IXAudio2MasteringVoice: Mastering voice management interface. + * + **************************************************************************/ + +IXAudio2MasteringVoice :: struct #raw_union { + #subtype ixaudio2voice: IXAudio2Voice, + using ixaudio2masteringvoice_vtable: ^IXAudio2MasteringVoice_VTable, +} +IXAudio2MasteringVoice_VTable :: struct { + using ixaudio2voice_vtable: IXAudio2Voice_VTable, + + // NAME: IXAudio2MasteringVoice.GetChannelMask + // DESCRIPTION: Returns the channel mask for this voice + // ARGUMENTS: + // pChannelMask - returns the channel mask for this voice. This corresponds to the dwChannelMask member of WAVEFORMATEXTENSIBLE. + GetChannelMask: proc "system" (this: ^IXAudio2MasteringVoice, pChannelmask: ^win.DWORD) -> HRESULT, +} + +/************************************************************************** + * + * IXAudio2EngineCallback: Client notification interface for engine events. + * + * REMARKS: Contains methods to notify the client when certain events happen in the XAudio2 engine. This interface should be implemented by the client. + * XAudio2 will call these methods via the interface pointer provided by the client when it calls IXAudio2.RegisterForCallbacks. + * + **************************************************************************/ + +IXAudio2EngineCallback :: struct { + using ixaudio2enginecallback_vtable: ^IXAudio2EngineCallback_VTable, +} +IXAudio2EngineCallback_VTable :: struct { + // Called by XAudio2 just before an audio processing pass begins. + OnProcessingPassStart: proc "system" (this: ^IXAudio2EngineCallback), + + // Called just after an audio processing pass ends. + OnProcessingPassEnd: proc "system" (this: ^IXAudio2EngineCallback), + + // Called in the event of a critical system error which requires XAudio2 to be closed down and restarted. The error code is given in Error. + OnCriticalError: proc "system" (this: ^IXAudio2EngineCallback, Error: HRESULT), +} + + /************************************************************************** + * + * IXAudio2VoiceCallback: Client notification interface for voice events. + * + * REMARKS: Contains methods to notify the client when certain events happen in an XAudio2 voice. This interface should be implemented by the client. + * XAudio2 will call these methods via an interface pointer provided by the client in the IXAudio2.CreateSourceVoice call. + * + **************************************************************************/ + +IXAudio2VoiceCallback :: struct { + using ixaudio2voicecallback_vtable: ^IXAudio2VoiceCallback_VTable, +} +IXAudio2VoiceCallback_VTable :: struct { + // Called just before this voice's processing pass begins. + OnVoiceProcessingPassStart: proc "system" (this: ^IXAudio2VoiceCallback, BytesRequired: u32), + + // Called just after this voice's processing pass ends. + OnVoiceProcessingPassEnd: proc "system" (this: ^IXAudio2VoiceCallback), + + // Called when this voice has just finished playing a buffer stream (as marked with the END_OF_STREAM flag on the last buffer). + OnStreamEnd: proc "system" (this: ^IXAudio2VoiceCallback), + + // Called when this voice is about to start processing a new buffer. + OnBufferStart: proc "system" (this: ^IXAudio2VoiceCallback, pBufferContext: rawptr), + + // Called when this voice has just finished processing a buffer. + // The buffer can now be reused or destroyed. + OnBufferEnd: proc "system" (this: ^IXAudio2VoiceCallback, pBufferContext: rawptr), + + // Called when this voice has just reached the end position of a loop. + OnLoopEnd: proc "system" (this: ^IXAudio2VoiceCallback, pBufferContext: rawptr), + + // Called in the event of a critical error during voice processing, such as a failing xAPO or an error from the hardware XMA decoder. + // The voice may have to be destroyed and re-created to recover from the error. + // The callback arguments report which buffer was being processed when the error occurred, and its HRESULT code. + OnVoiceError: proc "system" (this: ^IXAudio2VoiceCallback, pBufferContext: rawptr, Error: HRESULT), +} + +/************************************************************************** + * + * XAudio2Create: Top-level function that creates an XAudio2 instance. + * + * ARGUMENTS: + * + * Flags - Flags specifying the XAudio2 object's behavior. + * + * Processor - A PROCESSOR_FLAGS value that specifies the hardware threads (Xbox) or processors (Windows) that XAudio2 will use. + * Note that XAudio2 supports concurrent processing on multiple threads, using any combination of PROCESSOR_FLAGS flags. + * The values are platform-specific; platform-independent code can use USE_DEFAULT_PROCESSOR to use the default on each platform. + * + **************************************************************************/ + +@(default_calling_convention="system", link_prefix="XAudio2") +foreign xa2 { + Create :: proc(ppXaudio2: ^^IXAudio2, Flags: FLAGS = {}, Processor: PROCESSOR_FLAGS = {.Processor1}) -> HRESULT --- +} + +/************************************************************************** + * + * Utility functions used to convert from pitch in semitones and volume in decibels to the frequency and amplitude ratio units used by XAudio2. + * + **************************************************************************/ + +// Calculate the argument to SetVolume from a decibel value +DecibelsToAmplitudeRatio :: #force_inline proc "contextless" (Decibels: f32) -> f32 { + return math.pow_f32(10.0, Decibels / 20.0) +} + +// Recover a volume in decibels from an amplitude factor +AmplitudeRatioToDecibels :: #force_inline proc "contextless" (Volume: f32) -> f32 { + if Volume == 0 { + return min(f32) + } + return 20.0 * math.log10_f32(Volume) +} + +// Calculate the argument to SetFrequencyRatio from a semitone value +SemitonesToFrequencyRatio :: #force_inline proc "contextless" (Semitones: f32) -> f32 { + // FrequencyRatio = 2 ^ Octaves + // = 2 ^ (Semitones / 12) + return math.pow_f32(2.0, Semitones / 12.0) +} + +// Recover a pitch in semitones from a frequency ratio +FrequencyRatioToSemitones :: #force_inline proc "contextless" (FrequencyRatio: f32) -> f32 { + // Semitones = 12 * log2(FrequencyRatio) + // = 12 * log2(10) * log10(FrequencyRatio) + return 12.0 * math.log2_f32(FrequencyRatio) +} + +// Convert from filter cutoff frequencies expressed in Hertz to the radian frequency values used in FILTER_PARAMETERS.Frequency, state-variable filter types only. +// Use CutoffFrequencyToOnePoleCoefficient() for one-pole filter types. +// Note that the highest CutoffFrequency supported is SampleRate/6. +// Higher values of CutoffFrequency will return MAX_FILTER_FREQUENCY. +CutoffFrequencyToRadians :: #force_inline proc "contextless" (CutoffFrequency: f32, SampleRate: u32) -> f32 { + if u32(CutoffFrequency * 6.0) >= SampleRate { + return MAX_FILTER_FREQUENCY + } + return 2.0 * math.sin_f32(math.PI * CutoffFrequency / f32(SampleRate)) +} + +// Convert from radian frequencies back to absolute frequencies in Hertz +RadiansToCutoffFrequency :: #force_inline proc "contextless" (Radians: f32, SampleRate: f32) -> f32 { + return SampleRate * math.asin_f32(Radians / 2.0) / math.PI +} + +// Convert from filter cutoff frequencies expressed in Hertz to the filter coefficients used with FILTER_PARAMETERS.Frequency, +// LowPassOnePoleFilter and HighPassOnePoleFilter filter types only. +// Use CutoffFrequencyToRadians() for state-variable filter types. +CutoffFrequencyToOnePoleCoefficient :: #force_inline proc "contextless" (CutoffFrequency: f32, SampleRate: u32) -> f32 { + if u32(CutoffFrequency) >= SampleRate { + return MAX_FILTER_FREQUENCY + } + return 1.0 - math.pow_f32(1.0 - 2.0 * CutoffFrequency / f32(SampleRate), 2.0) +} + +//------------------------------------------------------------------------- +// Description: Audio stream categories +// +// Other - All other streams (default) +// ForegroundOnlyMedia - (deprecated for Win10) Music, Streaming audio +// BackgroundCapableMedia - (deprecated for Win10) Video with audio +// Communications - VOIP, chat, phone call +// Alerts - Alarm, Ring tones +// SoundEffects - Sound effects, clicks, dings +// GameEffects - Game sound effects +// GameMedia - Background audio for games +// GameChat - In game player chat +// Speech - Speech recognition +// Media - Music, Streaming audio +// Movie - Video with audio +// FarFieldSpeech - Capture of far field speech +// UniformSpeech - Uniform, device agnostic speech processing +// VoiceTyping - Dictation, typing by voice +// +AUDIO_STREAM_CATEGORY :: enum i32 { + Other = 0, + //ForegroundOnlyMedia = 1, + //BackgroundCapableMedia = 2, + Communications = 3, + Alerts = 4, + SoundEffects = 5, + GameEffects = 6, + GameMedia = 7, + GameChat = 8, + Speech = 9, + Movie = 10, + Media = 11, + FarFieldSpeech = 12, + UniformSpeech = 13, + VoiceTyping = 14, +} diff --git a/vendor/windows/XAudio2/xaudio2fx.odin b/vendor/windows/XAudio2/xaudio2fx.odin new file mode 100644 index 000000000..90bd9745b --- /dev/null +++ b/vendor/windows/XAudio2/xaudio2fx.odin @@ -0,0 +1,281 @@ +#+build windows + +package windows_xaudio2 + +import "core:math" + +foreign import xa2 "system:xaudio2.lib" + +/************************************************************************** + * + * Effect creation functions. + * + * On Xbox the application can link with the debug library to use the debug functionality. + * + **************************************************************************/ + +@(default_calling_convention="system") +foreign xa2 { + CreateAudioVolumeMeter :: proc(ppApo: ^^IUnknown) -> HRESULT --- + CreateAudioReverb :: proc(ppApo: ^^IUnknown) -> HRESULT --- +} + +/************************************************************************** + * + * Volume meter parameters. + * The volume meter supports f32 audio formats and must be used in-place. + * + **************************************************************************/ + +// VOLUMEMETER_LEVELS: Receives results from GetEffectParameters(). +// The user is responsible for allocating pPeakLevels, pRMSLevels, and initializing ChannelCount accordingly. +// The volume meter does not support SetEffectParameters(). +VOLUMEMETER_LEVELS :: struct #packed { + pPeakLevels: [^]f32 `fmt:"v,ChannelCount"`, // Peak levels table: receives maximum absolute level for each channel over a processing pass, may be nil if pRMSLevls != nil, otherwise must have at least ChannelCount elements. + pRMSLevels: [^]f32 `fmt:"v,ChannelCount"`, // Root mean square levels table: receives RMS level for each channel over a processing pass, may be nil if pPeakLevels != nil, otherwise must have at least ChannelCount elements. + ChannelCount: u32, // Number of channels being processed by the volume meter APO +} + +/************************************************************************** + * + * Reverb parameters. + * The reverb supports only f32 audio with the following channel configurations: + * Input: Mono Output: Mono + * Input: Mono Output: 5.1 + * Input: Stereo Output: Stereo + * Input: Stereo Output: 5.1 + * The framerate must be within [20000, 48000] Hz. + * + * When using mono input, delay filters associated with the right channel are not executed. + * In this case, parameters such as PositionRight and PositionMatrixRight have no effect. + * This also means the reverb uses less CPU when hosted in a mono submix. + * + **************************************************************************/ + +REVERB_MIN_FRAMERATE :: 20000 +REVERB_MAX_FRAMERATE :: 48000 + +// REVERB_PARAMETERS: Native parameter set for the reverb effect + +REVERB_PARAMETERS :: struct #packed { + // ratio of wet (processed) signal to dry (original) signal + WetDryMix: f32, // [0, 100] (percentage) + // Delay times + ReflectionsDelay: u32, // [0, 300] in ms + ReverbDelay: byte, // [0, 85] in ms + RearDelay: byte, // 7.1: [0, 20] in ms, all other: [0, 5] in ms + SideDelay: byte, // 7.1: [0, 5] in ms, all other: not used, but still validated + // Indexed parameters + PositionLeft: byte, // [0, 30] no units + PositionRight: byte, // [0, 30] no units, ignored when configured to mono + PositionMatrixLeft: byte, // [0, 30] no units + PositionMatrixRight: byte, // [0, 30] no units, ignored when configured to mono + EarlyDiffusion: byte, // [0, 15] no units + LateDiffusion: byte, // [0, 15] no units + LowEQGain: byte, // [0, 12] no units + LowEQCutoff: byte, // [0, 9] no units + HighEQGain: byte, // [0, 8] no units + HighEQCutoff: byte, // [0, 14] no units + // Direct parameters + RoomFilterFreq: f32, // [20, 20000] in Hz + RoomFilterMain: f32, // [-100, 0] in dB + RoomFilterHF: f32, // [-100, 0] in dB + ReflectionsGain: f32, // [-100, 20] in dB + ReverbGain: f32, // [-100, 20] in dB + DecayTime: f32, // [0.1, inf] in seconds + Density: f32, // [0, 100] (percentage) + RoomSize: f32, // [1, 100] in feet + // component control + DisableLateField: b32, // true to disable late field reflections +} + +// Maximum, minimum and default values for the parameters above +REVERB_MIN_WET_DRY_MIX :: 0.0 +REVERB_MIN_REFLECTIONS_DELAY :: 0 +REVERB_MIN_REVERB_DELAY :: 0 +REVERB_MIN_REAR_DELAY :: 0 +REVERB_MIN_7POINT1_SIDE_DELAY :: 0 +REVERB_MIN_7POINT1_REAR_DELAY :: 0 +REVERB_MIN_POSITION :: 0 +REVERB_MIN_DIFFUSION :: 0 +REVERB_MIN_LOW_EQ_GAIN :: 0 +REVERB_MIN_LOW_EQ_CUTOFF :: 0 +REVERB_MIN_HIGH_EQ_GAIN :: 0 +REVERB_MIN_HIGH_EQ_CUTOFF :: 0 +REVERB_MIN_ROOM_FILTER_FREQ :: 20.0 +REVERB_MIN_ROOM_FILTER_MAIN :: -100.0 +REVERB_MIN_ROOM_FILTER_HF :: -100.0 +REVERB_MIN_REFLECTIONS_GAIN :: -100.0 +REVERB_MIN_REVERB_GAIN :: -100.0 +REVERB_MIN_DECAY_TIME :: 0.1 +REVERB_MIN_DENSITY :: 0.0 +REVERB_MIN_ROOM_SIZE :: 0.0 + +REVERB_MAX_WET_DRY_MIX :: 100.0 +REVERB_MAX_REFLECTIONS_DELAY :: 300 +REVERB_MAX_REVERB_DELAY :: 85 +REVERB_MAX_REAR_DELAY :: 5 +REVERB_MAX_7POINT1_SIDE_DELAY :: 5 +REVERB_MAX_7POINT1_REAR_DELAY :: 20 +REVERB_MAX_POSITION :: 30 +REVERB_MAX_DIFFUSION :: 15 +REVERB_MAX_LOW_EQ_GAIN :: 12 +REVERB_MAX_LOW_EQ_CUTOFF :: 9 +REVERB_MAX_HIGH_EQ_GAIN :: 8 +REVERB_MAX_HIGH_EQ_CUTOFF :: 14 +REVERB_MAX_ROOM_FILTER_FREQ :: 20000.0 +REVERB_MAX_ROOM_FILTER_MAIN :: 0.0 +REVERB_MAX_ROOM_FILTER_HF :: 0.0 +REVERB_MAX_REFLECTIONS_GAIN :: 20.0 +REVERB_MAX_REVERB_GAIN :: 20.0 +REVERB_MAX_DENSITY :: 100.0 +REVERB_MAX_ROOM_SIZE :: 100.0 + +REVERB_DEFAULT_WET_DRY_MIX :: 100.0 +REVERB_DEFAULT_REFLECTIONS_DELAY :: 5 +REVERB_DEFAULT_REVERB_DELAY :: 5 +REVERB_DEFAULT_REAR_DELAY :: 5 +REVERB_DEFAULT_7POINT1_SIDE_DELAY :: 5 +REVERB_DEFAULT_7POINT1_REAR_DELAY :: 20 +REVERB_DEFAULT_POSITION :: 6 +REVERB_DEFAULT_POSITION_MATRIX :: 27 +REVERB_DEFAULT_EARLY_DIFFUSION :: 8 +REVERB_DEFAULT_LATE_DIFFUSION :: 8 +REVERB_DEFAULT_LOW_EQ_GAIN :: 8 +REVERB_DEFAULT_LOW_EQ_CUTOFF :: 4 +REVERB_DEFAULT_HIGH_EQ_GAIN :: 8 +REVERB_DEFAULT_HIGH_EQ_CUTOFF :: 4 +REVERB_DEFAULT_ROOM_FILTER_FREQ :: 5000.0 +REVERB_DEFAULT_ROOM_FILTER_MAIN :: 0.0 +REVERB_DEFAULT_ROOM_FILTER_HF :: 0.0 +REVERB_DEFAULT_REFLECTIONS_GAIN :: 0.0 +REVERB_DEFAULT_REVERB_GAIN :: 0.0 +REVERB_DEFAULT_DECAY_TIME :: 1.0 +REVERB_DEFAULT_DENSITY :: 100.0 +REVERB_DEFAULT_ROOM_SIZE :: 100.0 + +REVERB_DEFAULT_DISABLE_LATE_FIELD: b32 : false + +// REVERB_I3DL2_PARAMETERS: Parameter set compliant with the I3DL2 standard + +REVERB_I3DL2_PARAMETERS :: struct #packed { + // ratio of wet (processed) signal to dry (original) signal + WetDryMix: f32, // [0, 100] (percentage) + + // Standard I3DL2 parameters + Room: i32, // [-10000, 0] in mB (hundredths of decibels) + RoomHF: i32, // [-10000, 0] in mB (hundredths of decibels) + RoomRolloffFactor: f32, // [0.0, 10.0] + DecayTime: f32, // [0.1, 20.0] in seconds + DecayHFRatio: f32, // [0.1, 2.0] + Reflections: i32, // [-10000, 1000] in mB (hundredths of decibels) + ReflectionsDelay: f32, // [0.0, 0.3] in seconds + Reverb: i32, // [-10000, 2000] in mB (hundredths of decibels) + ReverbDelay: f32, // [0.0, 0.1] in seconds + Diffusion: f32, // [0.0, 100.0] (percentage) + Density: f32, // [0.0, 100.0] (percentage) + HFReference: f32, // [20.0, 20000.0] in Hz +} + +/************************************************************************** + * + * Standard I3DL2 reverb presets (100% wet). + * + **************************************************************************/ + +I3DL2_PRESET_DEFAULT := REVERB_I3DL2_PARAMETERS{100.0,-10000, 0,0.0, 1.00,0.50,-10000,0.020,-10000,0.040,100.0,100.0,5000.0} +I3DL2_PRESET_GENERIC := REVERB_I3DL2_PARAMETERS{100.0, -1000, -100,0.0, 1.49,0.83, -2602,0.007, 200,0.011,100.0,100.0,5000.0} +I3DL2_PRESET_PADDEDCELL := REVERB_I3DL2_PARAMETERS{100.0, -1000,-6000,0.0, 0.17,0.10, -1204,0.001, 207,0.002,100.0,100.0,5000.0} +I3DL2_PRESET_ROOM := REVERB_I3DL2_PARAMETERS{100.0, -1000, -454,0.0, 0.40,0.83, -1646,0.002, 53,0.003,100.0,100.0,5000.0} +I3DL2_PRESET_BATHROOM := REVERB_I3DL2_PARAMETERS{100.0, -1000,-1200,0.0, 1.49,0.54, -370,0.007, 1030,0.011,100.0, 60.0,5000.0} +I3DL2_PRESET_LIVINGROOM := REVERB_I3DL2_PARAMETERS{100.0, -1000,-6000,0.0, 0.50,0.10, -1376,0.003, -1104,0.004,100.0,100.0,5000.0} +I3DL2_PRESET_STONEROOM := REVERB_I3DL2_PARAMETERS{100.0, -1000, -300,0.0, 2.31,0.64, -711,0.012, 83,0.017,100.0,100.0,5000.0} +I3DL2_PRESET_AUDITORIUM := REVERB_I3DL2_PARAMETERS{100.0, -1000, -476,0.0, 4.32,0.59, -789,0.020, -289,0.030,100.0,100.0,5000.0} +I3DL2_PRESET_CONCERTHALL := REVERB_I3DL2_PARAMETERS{100.0, -1000, -500,0.0, 3.92,0.70, -1230,0.020, -2,0.029,100.0,100.0,5000.0} +I3DL2_PRESET_CAVE := REVERB_I3DL2_PARAMETERS{100.0, -1000, 0,0.0, 2.91,1.30, -602,0.015, -302,0.022,100.0,100.0,5000.0} +I3DL2_PRESET_ARENA := REVERB_I3DL2_PARAMETERS{100.0, -1000, -698,0.0, 7.24,0.33, -1166,0.020, 16,0.030,100.0,100.0,5000.0} +I3DL2_PRESET_HANGAR := REVERB_I3DL2_PARAMETERS{100.0, -1000,-1000,0.0,10.05,0.23, -602,0.020, 198,0.030,100.0,100.0,5000.0} +I3DL2_PRESET_CARPETEDHALLWAY := REVERB_I3DL2_PARAMETERS{100.0, -1000,-4000,0.0, 0.30,0.10, -1831,0.002, -1630,0.030,100.0,100.0,5000.0} +I3DL2_PRESET_HALLWAY := REVERB_I3DL2_PARAMETERS{100.0, -1000, -300,0.0, 1.49,0.59, -1219,0.007, 441,0.011,100.0,100.0,5000.0} +I3DL2_PRESET_STONECORRIDOR := REVERB_I3DL2_PARAMETERS{100.0, -1000, -237,0.0, 2.70,0.79, -1214,0.013, 395,0.020,100.0,100.0,5000.0} +I3DL2_PRESET_ALLEY := REVERB_I3DL2_PARAMETERS{100.0, -1000, -270,0.0, 1.49,0.86, -1204,0.007, -4,0.011,100.0,100.0,5000.0} +I3DL2_PRESET_FOREST := REVERB_I3DL2_PARAMETERS{100.0, -1000,-3300,0.0, 1.49,0.54, -2560,0.162, -613,0.088, 79.0,100.0,5000.0} +I3DL2_PRESET_CITY := REVERB_I3DL2_PARAMETERS{100.0, -1000, -800,0.0, 1.49,0.67, -2273,0.007, -2217,0.011, 50.0,100.0,5000.0} +I3DL2_PRESET_MOUNTAINS := REVERB_I3DL2_PARAMETERS{100.0, -1000,-2500,0.0, 1.49,0.21, -2780,0.300, -2014,0.100, 27.0,100.0,5000.0} +I3DL2_PRESET_QUARRY := REVERB_I3DL2_PARAMETERS{100.0, -1000,-1000,0.0, 1.49,0.83,-10000,0.061, 500,0.025,100.0,100.0,5000.0} +I3DL2_PRESET_PLAIN := REVERB_I3DL2_PARAMETERS{100.0, -1000,-2000,0.0, 1.49,0.50, -2466,0.179, -2514,0.100, 21.0,100.0,5000.0} +I3DL2_PRESET_PARKINGLOT := REVERB_I3DL2_PARAMETERS{100.0, -1000, 0,0.0, 1.65,1.50, -1363,0.008, -1153,0.012,100.0,100.0,5000.0} +I3DL2_PRESET_SEWERPIPE := REVERB_I3DL2_PARAMETERS{100.0, -1000,-1000,0.0, 2.81,0.14, 429,0.014, 648,0.021, 80.0, 60.0,5000.0} +I3DL2_PRESET_UNDERWATER := REVERB_I3DL2_PARAMETERS{100.0, -1000,-4000,0.0, 1.49,0.10, -449,0.007, 1700,0.011,100.0,100.0,5000.0} +I3DL2_PRESET_SMALLROOM := REVERB_I3DL2_PARAMETERS{100.0, -1000, -600,0.0, 1.10,0.83, -400,0.005, 500,0.010,100.0,100.0,5000.0} +I3DL2_PRESET_MEDIUMROOM := REVERB_I3DL2_PARAMETERS{100.0, -1000, -600,0.0, 1.30,0.83, -1000,0.010, -200,0.020,100.0,100.0,5000.0} +I3DL2_PRESET_LARGEROOM := REVERB_I3DL2_PARAMETERS{100.0, -1000, -600,0.0, 1.50,0.83, -1600,0.020, -1000,0.040,100.0,100.0,5000.0} +I3DL2_PRESET_MEDIUMHALL := REVERB_I3DL2_PARAMETERS{100.0, -1000, -600,0.0, 1.80,0.70, -1300,0.015, -800,0.030,100.0,100.0,5000.0} +I3DL2_PRESET_LARGEHALL := REVERB_I3DL2_PARAMETERS{100.0, -1000, -600,0.0, 1.80,0.70, -2000,0.030, -1400,0.060,100.0,100.0,5000.0} +I3DL2_PRESET_PLATE := REVERB_I3DL2_PARAMETERS{100.0, -1000, -200,0.0, 1.30,0.90, 0,0.002, 0,0.010,100.0, 75.0,5000.0} + +// ReverbConvertI3DL2ToNative: Utility function to map from I3DL2 to native parameters + +ReverbConvertI3DL2ToNative :: proc "contextless" (pI3DL2: ^REVERB_I3DL2_PARAMETERS, pNative: ^REVERB_PARAMETERS, sevenDotOneReverb: b32 = true) { + reflectionsDelay: f32 + reverbDelay: f32 + + // RoomRolloffFactor is ignored + + // These parameters have no equivalent in I3DL2 + if sevenDotOneReverb { + pNative.RearDelay = REVERB_DEFAULT_7POINT1_REAR_DELAY // 20 + } else { + pNative.RearDelay = REVERB_DEFAULT_REAR_DELAY // 5 + } + pNative.SideDelay = REVERB_DEFAULT_7POINT1_SIDE_DELAY // 5 + pNative.PositionLeft = REVERB_DEFAULT_POSITION // 6 + pNative.PositionRight = REVERB_DEFAULT_POSITION // 6 + pNative.PositionMatrixLeft = REVERB_DEFAULT_POSITION_MATRIX // 27 + pNative.PositionMatrixRight = REVERB_DEFAULT_POSITION_MATRIX // 27 + pNative.RoomSize = REVERB_DEFAULT_ROOM_SIZE // 100 + pNative.LowEQCutoff = 4 + pNative.HighEQCutoff = 6 + + // The rest of the I3DL2 parameters map to the native property set + pNative.RoomFilterMain = f32(pI3DL2.Room) / 100.0 + pNative.RoomFilterHF = f32(pI3DL2.RoomHF) / 100.0 + + if pI3DL2.DecayHFRatio >= 1.0 { + index := i32(-4.0 * math.log10_f32(pI3DL2.DecayHFRatio)) + if index < -8 {index = -8} + pNative.LowEQGain = byte((index < 0) ? index + 8 : 8) + pNative.HighEQGain = 8 + pNative.DecayTime = pI3DL2.DecayTime * pI3DL2.DecayHFRatio + } else { + index := i32(4.0 * math.log10_f32(pI3DL2.DecayHFRatio)) + if index < -8 {index = -8} + pNative.LowEQGain = 8 + pNative.HighEQGain = byte((index < 0) ? index + 8 : 8) + pNative.DecayTime = pI3DL2.DecayTime + } + + reflectionsDelay = pI3DL2.ReflectionsDelay * 1000.0 + if reflectionsDelay >= REVERB_MAX_REFLECTIONS_DELAY { // 300 + reflectionsDelay = f32(REVERB_MAX_REFLECTIONS_DELAY - 1) + } else if reflectionsDelay <= 1 { + reflectionsDelay = 1 + } + pNative.ReflectionsDelay = u32(reflectionsDelay) + + reverbDelay = pI3DL2.ReverbDelay * 1000.0 + if reverbDelay >= REVERB_MAX_REVERB_DELAY { // 85 + reverbDelay = f32(REVERB_MAX_REVERB_DELAY - 1) + } + pNative.ReverbDelay = byte(reverbDelay) + + pNative.ReflectionsGain = f32(pI3DL2.Reflections) / 100.0 + pNative.ReverbGain = f32(pI3DL2.Reverb) / 100.0 + pNative.EarlyDiffusion = byte(15.0 * pI3DL2.Diffusion / 100.0) + pNative.LateDiffusion = pNative.EarlyDiffusion + pNative.Density = pI3DL2.Density + pNative.RoomFilterFreq = pI3DL2.HFReference + + pNative.WetDryMix = pI3DL2.WetDryMix + pNative.DisableLateField = false +} diff --git a/vendor/x11/xlib/xlib_procs.odin b/vendor/x11/xlib/xlib_procs.odin index 2d35ab179..f5ac373ae 100644 --- a/vendor/x11/xlib/xlib_procs.odin +++ b/vendor/x11/xlib/xlib_procs.odin @@ -190,8 +190,8 @@ foreign xlib { display: ^Display, window: Window, mask: WindowChangesMask, - values: XWindowChanges, - ) --- + changes: ^XWindowChanges, + ) -> i32 --- MoveWindow :: proc( display: ^Display, window: Window, @@ -217,6 +217,11 @@ foreign xlib { window: Window, width: u32, ) --- + SetWindowBorder :: proc( + display: ^Display, + window: Window, + pixel: uint, + ) --- // Window: changing stacking order RaiseWindow :: proc(display: ^Display, window: Window) --- LowerWindow :: proc(display: ^Display, window: Window) --- @@ -229,7 +234,7 @@ foreign xlib { display: ^Display, window: Window, attr_mask: WindowAttributeMask, - attr: XWindowAttributes, + attr: ^XWindowAttributes, ) --- SetWindowBackground :: proc( display: ^Display, @@ -250,11 +255,11 @@ foreign xlib { display: ^Display, window: Window, cursor: Cursor, - ) --- + ) -> i32 --- UndefineCursor :: proc( display: ^Display, window: Window, - ) --- + ) -> i32 --- // Windows: querying information QueryTree :: proc( display: ^Display, @@ -268,7 +273,7 @@ foreign xlib { display: ^Display, window: Window, attr: ^XWindowAttributes, - ) --- + ) -> i32 --- GetGeometry :: proc( display: ^Display, drawable: Drawable, @@ -352,19 +357,19 @@ foreign xlib { mode: i32, data: rawptr, count: i32, - ) --- + ) -> i32 --- RotateWindowProperties :: proc( display: ^Display, window: Window, props: [^]Atom, nprops: i32, npos: i32, - ) --- + ) -> i32 --- DeleteProperty :: proc( display: ^Display, window: Window, prop: Atom, - ) --- + ) -> i32 --- // Selections SetSelectionOwner :: proc( display: ^Display, @@ -384,6 +389,18 @@ foreign xlib { requestor: Window, time: Time, ) --- + GetTextProperty :: proc( + display: ^Display, + window: Window, + text_prop_return: ^XTextProperty, + property: Atom, + ) -> Status --- + SetTextProperty :: proc( + display: ^Display, + window: Window, + text_prop: ^XTextProperty, + property: Atom, + ) --- // Creating and freeing pixmaps CreatePixmap :: proc( display: ^Display, @@ -1007,8 +1024,8 @@ foreign xlib { DisableAccessControl :: proc(display: ^Display) --- // Events SelectInput :: proc(display: ^Display, window: Window, mask: EventMask) --- - Flush :: proc(display: ^Display) --- - Sync :: proc(display: ^Display) --- + Flush :: proc(display: ^Display) -> i32 --- + Sync :: proc(display: ^Display, discard: bool) -> i32 --- EventsQueued :: proc(display: ^Display, mode: EventQueueMode) -> i32 --- Pending :: proc(display: ^Display) -> i32 --- NextEvent :: proc(display: ^Display, event: ^XEvent) ---